From f88cefad27a1737c76e09d99c9fb43e173506081 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Sun, 13 Sep 2015 08:41:44 +0200 Subject: Move all devices into separate part of src tree (nw) --- src/devices/bus/a1bus/a1bus.c | 204 + src/devices/bus/a1bus/a1bus.h | 145 + src/devices/bus/a1bus/a1cassette.c | 201 + src/devices/bus/a1bus/a1cassette.h | 53 + src/devices/bus/a1bus/a1cffa.c | 156 + src/devices/bus/a1bus/a1cffa.h | 53 + src/devices/bus/a2bus/a2alfam2.c | 181 + src/devices/bus/a2bus/a2alfam2.h | 72 + src/devices/bus/a2bus/a2applicard.c | 286 + src/devices/bus/a2bus/a2applicard.h | 61 + src/devices/bus/a2bus/a2arcadebd.c | 149 + src/devices/bus/a2bus/a2arcadebd.h | 54 + src/devices/bus/a2bus/a2bus.c | 334 + src/devices/bus/a2bus/a2bus.h | 197 + src/devices/bus/a2bus/a2cffa.c | 278 + src/devices/bus/a2bus/a2cffa.h | 86 + src/devices/bus/a2bus/a2corvus.c | 187 + src/devices/bus/a2bus/a2corvus.h | 55 + src/devices/bus/a2bus/a2diskii.c | 153 + src/devices/bus/a2bus/a2diskii.h | 67 + src/devices/bus/a2bus/a2diskiing.c | 123 + src/devices/bus/a2bus/a2diskiing.h | 59 + src/devices/bus/a2bus/a2dx1.c | 119 + src/devices/bus/a2bus/a2dx1.h | 52 + src/devices/bus/a2bus/a2eauxslot.c | 180 + src/devices/bus/a2bus/a2eauxslot.h | 146 + src/devices/bus/a2bus/a2echoii.c | 103 + src/devices/bus/a2bus/a2echoii.h | 49 + src/devices/bus/a2bus/a2eext80col.c | 75 + src/devices/bus/a2bus/a2eext80col.h | 47 + src/devices/bus/a2bus/a2eramworks3.c | 99 + src/devices/bus/a2bus/a2eramworks3.h | 49 + src/devices/bus/a2bus/a2estd80col.c | 82 + src/devices/bus/a2bus/a2estd80col.h | 47 + src/devices/bus/a2bus/a2hsscsi.c | 323 + src/devices/bus/a2bus/a2hsscsi.h | 65 + src/devices/bus/a2bus/a2lang.c | 145 + src/devices/bus/a2bus/a2lang.h | 46 + src/devices/bus/a2bus/a2mcms.c | 382 + src/devices/bus/a2bus/a2mcms.h | 121 + src/devices/bus/a2bus/a2memexp.c | 230 + src/devices/bus/a2bus/a2memexp.h | 72 + src/devices/bus/a2bus/a2midi.c | 172 + src/devices/bus/a2bus/a2midi.h | 55 + src/devices/bus/a2bus/a2mockingboard.c | 528 + src/devices/bus/a2bus/a2mockingboard.h | 97 + src/devices/bus/a2bus/a2pic.c | 290 + src/devices/bus/a2bus/a2pic.h | 67 + src/devices/bus/a2bus/a2sam.c | 87 + src/devices/bus/a2bus/a2sam.h | 48 + src/devices/bus/a2bus/a2scsi.c | 323 + src/devices/bus/a2bus/a2scsi.h | 64 + src/devices/bus/a2bus/a2softcard.c | 184 + src/devices/bus/a2bus/a2softcard.h | 54 + src/devices/bus/a2bus/a2ssc.c | 244 + src/devices/bus/a2bus/a2ssc.h | 58 + src/devices/bus/a2bus/a2swyft.c | 149 + src/devices/bus/a2bus/a2swyft.h | 52 + src/devices/bus/a2bus/a2themill.c | 333 + src/devices/bus/a2bus/a2themill.h | 57 + src/devices/bus/a2bus/a2thunderclock.c | 179 + src/devices/bus/a2bus/a2thunderclock.h | 57 + src/devices/bus/a2bus/a2ultraterm.c | 399 + src/devices/bus/a2bus/a2ultraterm.h | 79 + src/devices/bus/a2bus/a2videoterm.c | 377 + src/devices/bus/a2bus/a2videoterm.h | 121 + src/devices/bus/a2bus/a2vulcan.c | 302 + src/devices/bus/a2bus/a2vulcan.h | 80 + src/devices/bus/a2bus/a2zipdrive.c | 198 + src/devices/bus/a2bus/a2zipdrive.h | 65 + src/devices/bus/a2bus/corvfdc01.c | 281 + src/devices/bus/a2bus/corvfdc01.h | 65 + src/devices/bus/a2bus/corvfdc02.c | 299 + src/devices/bus/a2bus/corvfdc02.h | 70 + src/devices/bus/a2bus/ezcgi.c | 315 + src/devices/bus/a2bus/ezcgi.h | 111 + src/devices/bus/a2bus/laser128.c | 146 + src/devices/bus/a2bus/laser128.h | 54 + src/devices/bus/a2bus/mouse.c | 531 + src/devices/bus/a2bus/mouse.h | 93 + src/devices/bus/a2bus/ramcard128k.c | 190 + src/devices/bus/a2bus/ramcard128k.h | 56 + src/devices/bus/a2bus/ramcard16k.c | 170 + src/devices/bus/a2bus/ramcard16k.h | 55 + src/devices/bus/a2bus/timemasterho.c | 280 + src/devices/bus/a2bus/timemasterho.h | 67 + src/devices/bus/a7800/a78_carts.h | 39 + src/devices/bus/a7800/a78_slot.c | 831 + src/devices/bus/a7800/a78_slot.h | 155 + src/devices/bus/a7800/cpuwiz.c | 132 + src/devices/bus/a7800/cpuwiz.h | 74 + src/devices/bus/a7800/hiscore.c | 77 + src/devices/bus/a7800/hiscore.h | 40 + src/devices/bus/a7800/rom.c | 497 + src/devices/bus/a7800/rom.h | 261 + src/devices/bus/a7800/xboard.c | 239 + src/devices/bus/a7800/xboard.h | 71 + src/devices/bus/a800/a800_carts.h | 50 + src/devices/bus/a800/a800_slot.c | 549 + src/devices/bus/a800/a800_slot.h | 188 + src/devices/bus/a800/oss.c | 252 + src/devices/bus/a800/oss.h | 97 + src/devices/bus/a800/rom.c | 447 + src/devices/bus/a800/rom.h | 224 + src/devices/bus/a800/sparta.c | 71 + src/devices/bus/a800/sparta.h | 34 + src/devices/bus/a8sio/a8sio.c | 219 + src/devices/bus/a8sio/a8sio.h | 144 + src/devices/bus/a8sio/cassette.c | 117 + src/devices/bus/a8sio/cassette.h | 54 + src/devices/bus/abcbus/abc890.c | 408 + src/devices/bus/abcbus/abc890.h | 130 + src/devices/bus/abcbus/abcbus.c | 144 + src/devices/bus/abcbus/abcbus.h | 319 + src/devices/bus/abcbus/fd2.c | 432 + src/devices/bus/abcbus/fd2.h | 83 + src/devices/bus/abcbus/hdc.c | 151 + src/devices/bus/abcbus/hdc.h | 57 + src/devices/bus/abcbus/lux10828.c | 678 + src/devices/bus/abcbus/lux10828.h | 115 + src/devices/bus/abcbus/lux21046.c | 1163 + src/devices/bus/abcbus/lux21046.h | 200 + src/devices/bus/abcbus/lux21056.c | 673 + src/devices/bus/abcbus/lux21056.h | 108 + src/devices/bus/abcbus/lux4105.c | 393 + src/devices/bus/abcbus/lux4105.h | 92 + src/devices/bus/abcbus/memcard.c | 163 + src/devices/bus/abcbus/memcard.h | 56 + src/devices/bus/abcbus/ram.c | 79 + src/devices/bus/abcbus/ram.h | 51 + src/devices/bus/abcbus/sio.c | 160 + src/devices/bus/abcbus/sio.h | 53 + src/devices/bus/abcbus/slutprov.c | 79 + src/devices/bus/abcbus/slutprov.h | 44 + src/devices/bus/abcbus/turbo.c | 149 + src/devices/bus/abcbus/turbo.h | 56 + src/devices/bus/abcbus/uni800.c | 110 + src/devices/bus/abcbus/uni800.h | 44 + src/devices/bus/abckb/abc77.c | 658 + src/devices/bus/abckb/abc77.h | 116 + src/devices/bus/abckb/abc800kb.c | 507 + src/devices/bus/abckb/abc800kb.h | 90 + src/devices/bus/abckb/abc99.c | 782 + src/devices/bus/abckb/abc99.h | 114 + src/devices/bus/abckb/abckb.c | 136 + src/devices/bus/abckb/abckb.h | 97 + src/devices/bus/adam/adamlink.c | 84 + src/devices/bus/adam/adamlink.h | 47 + src/devices/bus/adam/exp.c | 190 + src/devices/bus/adam/exp.h | 130 + src/devices/bus/adam/ide.c | 209 + src/devices/bus/adam/ide.h | 59 + src/devices/bus/adam/ram.c | 72 + src/devices/bus/adam/ram.h | 50 + src/devices/bus/adamnet/adamnet.c | 264 + src/devices/bus/adamnet/adamnet.h | 131 + src/devices/bus/adamnet/ddp.c | 308 + src/devices/bus/adamnet/ddp.h | 67 + src/devices/bus/adamnet/fdc.c | 352 + src/devices/bus/adamnet/fdc.h | 69 + src/devices/bus/adamnet/kb.c | 425 + src/devices/bus/adamnet/kb.h | 78 + src/devices/bus/adamnet/printer.c | 257 + src/devices/bus/adamnet/printer.h | 61 + src/devices/bus/adamnet/spi.c | 185 + src/devices/bus/adamnet/spi.h | 60 + src/devices/bus/amiga/zorro/a2052.c | 134 + src/devices/bus/amiga/zorro/a2052.h | 51 + src/devices/bus/amiga/zorro/a2232.c | 651 + src/devices/bus/amiga/zorro/a2232.h | 151 + src/devices/bus/amiga/zorro/a590.c | 349 + src/devices/bus/amiga/zorro/a590.h | 134 + src/devices/bus/amiga/zorro/action_replay.c | 149 + src/devices/bus/amiga/zorro/action_replay.h | 82 + src/devices/bus/amiga/zorro/buddha.c | 350 + src/devices/bus/amiga/zorro/buddha.h | 82 + src/devices/bus/amiga/zorro/cards.c | 39 + src/devices/bus/amiga/zorro/cards.h | 44 + src/devices/bus/amiga/zorro/zorro.c | 378 + src/devices/bus/amiga/zorro/zorro.h | 449 + src/devices/bus/apf/rom.c | 78 + src/devices/bus/apf/rom.h | 62 + src/devices/bus/apf/slot.c | 294 + src/devices/bus/apf/slot.h | 116 + src/devices/bus/apricot/cards.c | 15 + src/devices/bus/apricot/cards.h | 19 + src/devices/bus/apricot/expansion.c | 192 + src/devices/bus/apricot/expansion.h | 208 + src/devices/bus/apricot/ram.c | 177 + src/devices/bus/apricot/ram.h | 89 + src/devices/bus/arcadia/rom.c | 62 + src/devices/bus/arcadia/rom.h | 44 + src/devices/bus/arcadia/slot.c | 260 + src/devices/bus/arcadia/slot.h | 103 + src/devices/bus/astrocde/exp.c | 85 + src/devices/bus/astrocde/exp.h | 57 + src/devices/bus/astrocde/ram.c | 211 + src/devices/bus/astrocde/ram.h | 135 + src/devices/bus/astrocde/rom.c | 99 + src/devices/bus/astrocde/rom.h | 73 + src/devices/bus/astrocde/slot.c | 236 + src/devices/bus/astrocde/slot.h | 103 + src/devices/bus/bml3/bml3bus.c | 241 + src/devices/bus/bml3/bml3bus.h | 153 + src/devices/bus/bml3/bml3kanji.c | 101 + src/devices/bus/bml3/bml3kanji.h | 49 + src/devices/bus/bml3/bml3mp1802.c | 143 + src/devices/bus/bml3/bml3mp1802.h | 58 + src/devices/bus/bml3/bml3mp1805.c | 170 + src/devices/bus/bml3/bml3mp1805.h | 54 + src/devices/bus/bw2/exp.c | 191 + src/devices/bus/bw2/exp.h | 131 + src/devices/bus/bw2/ramcard.c | 126 + src/devices/bus/bw2/ramcard.h | 59 + src/devices/bus/c64/16kb.c | 124 + src/devices/bus/c64/16kb.h | 59 + src/devices/bus/c64/4dxh.c | 77 + src/devices/bus/c64/4dxh.h | 50 + src/devices/bus/c64/4ksa.c | 77 + src/devices/bus/c64/4ksa.h | 50 + src/devices/bus/c64/4tba.c | 77 + src/devices/bus/c64/4tba.h | 50 + src/devices/bus/c64/bn1541.c | 154 + src/devices/bus/c64/bn1541.h | 82 + src/devices/bus/c64/c128_comal80.c | 103 + src/devices/bus/c64/c128_comal80.h | 51 + src/devices/bus/c64/c128_partner.c | 250 + src/devices/bus/c64/c128_partner.h | 68 + src/devices/bus/c64/comal80.c | 86 + src/devices/bus/c64/comal80.h | 51 + src/devices/bus/c64/cpm.c | 230 + src/devices/bus/c64/cpm.h | 65 + src/devices/bus/c64/currah_speech.c | 255 + src/devices/bus/c64/currah_speech.h | 58 + src/devices/bus/c64/dela_ep256.c | 156 + src/devices/bus/c64/dela_ep256.h | 60 + src/devices/bus/c64/dela_ep64.c | 146 + src/devices/bus/c64/dela_ep64.h | 64 + src/devices/bus/c64/dela_ep7x8.c | 133 + src/devices/bus/c64/dela_ep7x8.h | 65 + src/devices/bus/c64/dinamic.c | 74 + src/devices/bus/c64/dinamic.h | 50 + src/devices/bus/c64/dqbb.c | 121 + src/devices/bus/c64/dqbb.h | 59 + src/devices/bus/c64/easy_calc_result.c | 107 + src/devices/bus/c64/easy_calc_result.h | 51 + src/devices/bus/c64/easyflash.c | 228 + src/devices/bus/c64/easyflash.h | 64 + src/devices/bus/c64/epyx_fast_load.c | 116 + src/devices/bus/c64/epyx_fast_load.h | 52 + src/devices/bus/c64/exos.c | 67 + src/devices/bus/c64/exos.h | 47 + src/devices/bus/c64/exp.c | 445 + src/devices/bus/c64/exp.h | 202 + src/devices/bus/c64/fcc.c | 255 + src/devices/bus/c64/fcc.h | 69 + src/devices/bus/c64/final.c | 134 + src/devices/bus/c64/final.h | 53 + src/devices/bus/c64/final3.c | 150 + src/devices/bus/c64/final3.h | 57 + src/devices/bus/c64/fun_play.c | 98 + src/devices/bus/c64/fun_play.h | 51 + src/devices/bus/c64/geocable.c | 72 + src/devices/bus/c64/geocable.h | 63 + src/devices/bus/c64/georam.c | 99 + src/devices/bus/c64/georam.h | 53 + src/devices/bus/c64/ide64.c | 357 + src/devices/bus/c64/ide64.h | 70 + src/devices/bus/c64/ieee488.c | 249 + src/devices/bus/c64/ieee488.h | 67 + src/devices/bus/c64/kingsoft.c | 98 + src/devices/bus/c64/kingsoft.h | 49 + src/devices/bus/c64/mach5.c | 118 + src/devices/bus/c64/mach5.h | 55 + src/devices/bus/c64/magic_desk.c | 85 + src/devices/bus/c64/magic_desk.h | 51 + src/devices/bus/c64/magic_formel.c | 267 + src/devices/bus/c64/magic_formel.h | 71 + src/devices/bus/c64/magic_voice.c | 372 + src/devices/bus/c64/magic_voice.h | 82 + src/devices/bus/c64/midi_maplin.c | 152 + src/devices/bus/c64/midi_maplin.h | 56 + src/devices/bus/c64/midi_namesoft.c | 150 + src/devices/bus/c64/midi_namesoft.h | 56 + src/devices/bus/c64/midi_passport.c | 195 + src/devices/bus/c64/midi_passport.h | 62 + src/devices/bus/c64/midi_sci.c | 151 + src/devices/bus/c64/midi_sci.h | 56 + src/devices/bus/c64/midi_siel.c | 152 + src/devices/bus/c64/midi_siel.h | 56 + src/devices/bus/c64/mikro_assembler.c | 57 + src/devices/bus/c64/mikro_assembler.h | 46 + src/devices/bus/c64/multiscreen.c | 226 + src/devices/bus/c64/multiscreen.h | 57 + src/devices/bus/c64/music64.c | 238 + src/devices/bus/c64/music64.h | 63 + src/devices/bus/c64/neoram.c | 99 + src/devices/bus/c64/neoram.h | 57 + src/devices/bus/c64/ocean.c | 115 + src/devices/bus/c64/ocean.h | 51 + src/devices/bus/c64/pagefox.c | 137 + src/devices/bus/c64/pagefox.h | 53 + src/devices/bus/c64/partner.c | 208 + src/devices/bus/c64/partner.h | 60 + src/devices/bus/c64/prophet64.c | 86 + src/devices/bus/c64/prophet64.h | 51 + src/devices/bus/c64/ps64.c | 157 + src/devices/bus/c64/ps64.h | 52 + src/devices/bus/c64/reu.c | 137 + src/devices/bus/c64/reu.h | 101 + src/devices/bus/c64/rex.c | 78 + src/devices/bus/c64/rex.h | 47 + src/devices/bus/c64/rex_ep256.c | 165 + src/devices/bus/c64/rex_ep256.h | 60 + src/devices/bus/c64/ross.c | 92 + src/devices/bus/c64/ross.h | 52 + src/devices/bus/c64/sfx_sound_expander.c | 286 + src/devices/bus/c64/sfx_sound_expander.h | 71 + src/devices/bus/c64/silverrock.c | 132 + src/devices/bus/c64/silverrock.h | 51 + src/devices/bus/c64/simons_basic.c | 84 + src/devices/bus/c64/simons_basic.h | 48 + src/devices/bus/c64/stardos.c | 194 + src/devices/bus/c64/stardos.h | 60 + src/devices/bus/c64/std.c | 68 + src/devices/bus/c64/std.h | 46 + src/devices/bus/c64/structured_basic.c | 103 + src/devices/bus/c64/structured_basic.h | 52 + src/devices/bus/c64/super_explode.c | 125 + src/devices/bus/c64/super_explode.h | 54 + src/devices/bus/c64/super_games.c | 102 + src/devices/bus/c64/super_games.h | 51 + src/devices/bus/c64/supercpu.c | 306 + src/devices/bus/c64/supercpu.h | 63 + src/devices/bus/c64/sw8k.c | 114 + src/devices/bus/c64/sw8k.h | 55 + src/devices/bus/c64/swiftlink.c | 175 + src/devices/bus/c64/swiftlink.h | 76 + src/devices/bus/c64/system3.c | 90 + src/devices/bus/c64/system3.h | 51 + src/devices/bus/c64/tdos.c | 341 + src/devices/bus/c64/tdos.h | 61 + src/devices/bus/c64/turbo232.c | 219 + src/devices/bus/c64/turbo232.h | 89 + src/devices/bus/c64/user.c | 32 + src/devices/bus/c64/user.h | 33 + src/devices/bus/c64/vizastar.c | 89 + src/devices/bus/c64/vizastar.h | 46 + src/devices/bus/c64/vw64.c | 127 + src/devices/bus/c64/vw64.h | 52 + src/devices/bus/c64/warp_speed.c | 147 + src/devices/bus/c64/warp_speed.h | 54 + src/devices/bus/c64/westermann.c | 82 + src/devices/bus/c64/westermann.h | 47 + src/devices/bus/c64/xl80.c | 239 + src/devices/bus/c64/xl80.h | 64 + src/devices/bus/c64/zaxxon.c | 66 + src/devices/bus/c64/zaxxon.h | 49 + src/devices/bus/cbm2/24k.c | 88 + src/devices/bus/cbm2/24k.h | 48 + src/devices/bus/cbm2/exp.c | 206 + src/devices/bus/cbm2/exp.h | 136 + src/devices/bus/cbm2/hrg.c | 231 + src/devices/bus/cbm2/hrg.h | 83 + src/devices/bus/cbm2/std.c | 65 + src/devices/bus/cbm2/std.h | 45 + src/devices/bus/cbm2/user.c | 77 + src/devices/bus/cbm2/user.h | 157 + src/devices/bus/cbmiec/c1526.c | 269 + src/devices/bus/cbmiec/c1526.h | 90 + src/devices/bus/cbmiec/c1541.c | 1211 + src/devices/bus/cbmiec/c1541.h | 300 + src/devices/bus/cbmiec/c1571.c | 1040 + src/devices/bus/cbmiec/c1571.h | 187 + src/devices/bus/cbmiec/c1581.c | 470 + src/devices/bus/cbmiec/c1581.h | 112 + src/devices/bus/cbmiec/c64_nl10.c | 102 + src/devices/bus/cbmiec/c64_nl10.h | 52 + src/devices/bus/cbmiec/cbmiec.c | 526 + src/devices/bus/cbmiec/cbmiec.h | 210 + src/devices/bus/cbmiec/cmdhd.c | 198 + src/devices/bus/cbmiec/cmdhd.h | 72 + src/devices/bus/cbmiec/diag264_lb_iec.c | 52 + src/devices/bus/cbmiec/diag264_lb_iec.h | 46 + src/devices/bus/cbmiec/fd2000.c | 361 + src/devices/bus/cbmiec/fd2000.h | 97 + src/devices/bus/cbmiec/interpod.c | 182 + src/devices/bus/cbmiec/interpod.h | 76 + src/devices/bus/cbmiec/serialbox.c | 150 + src/devices/bus/cbmiec/serialbox.h | 65 + src/devices/bus/cbmiec/vic1515.c | 164 + src/devices/bus/cbmiec/vic1515.h | 55 + src/devices/bus/cbmiec/vic1520.c | 192 + src/devices/bus/cbmiec/vic1520.h | 55 + src/devices/bus/centronics/comxpl80.c | 328 + src/devices/bus/centronics/comxpl80.h | 81 + src/devices/bus/centronics/covox.c | 127 + src/devices/bus/centronics/covox.h | 94 + src/devices/bus/centronics/ctronics.c | 132 + src/devices/bus/centronics/ctronics.h | 222 + src/devices/bus/centronics/digiblst.c | 63 + src/devices/bus/centronics/digiblst.h | 60 + src/devices/bus/centronics/dsjoy.c | 48 + src/devices/bus/centronics/dsjoy.h | 47 + src/devices/bus/centronics/epson_ex800.c | 496 + src/devices/bus/centronics/epson_ex800.h | 76 + src/devices/bus/centronics/epson_lx800.c | 358 + src/devices/bus/centronics/epson_lx800.h | 73 + src/devices/bus/centronics/epson_lx810l.c | 632 + src/devices/bus/centronics/epson_lx810l.h | 141 + src/devices/bus/centronics/printer.c | 133 + src/devices/bus/centronics/printer.h | 58 + src/devices/bus/cgenie/expansion/carts.c | 13 + src/devices/bus/cgenie/expansion/carts.h | 20 + src/devices/bus/cgenie/expansion/expansion.c | 108 + src/devices/bus/cgenie/expansion/expansion.h | 128 + src/devices/bus/cgenie/expansion/floppy.c | 226 + src/devices/bus/cgenie/expansion/floppy.h | 76 + src/devices/bus/cgenie/parallel/carts.c | 14 + src/devices/bus/cgenie/parallel/carts.h | 21 + src/devices/bus/cgenie/parallel/joystick.c | 153 + src/devices/bus/cgenie/parallel/joystick.h | 48 + src/devices/bus/cgenie/parallel/parallel.c | 115 + src/devices/bus/cgenie/parallel/parallel.h | 94 + src/devices/bus/cgenie/parallel/printer.c | 132 + src/devices/bus/cgenie/parallel/printer.h | 58 + src/devices/bus/chanf/rom.c | 242 + src/devices/bus/chanf/rom.h | 144 + src/devices/bus/chanf/slot.c | 286 + src/devices/bus/chanf/slot.h | 119 + src/devices/bus/coco/coco_232.c | 92 + src/devices/bus/coco/coco_232.h | 42 + src/devices/bus/coco/coco_dwsock.c | 210 + src/devices/bus/coco/coco_dwsock.h | 73 + src/devices/bus/coco/coco_fdc.c | 713 + src/devices/bus/coco/coco_fdc.h | 180 + src/devices/bus/coco/coco_multi.c | 274 + src/devices/bus/coco/coco_multi.h | 69 + src/devices/bus/coco/coco_orch90.c | 85 + src/devices/bus/coco/coco_orch90.h | 42 + src/devices/bus/coco/coco_pak.c | 179 + src/devices/bus/coco/coco_pak.h | 65 + src/devices/bus/coco/cococart.c | 451 + src/devices/bus/coco/cococart.h | 183 + src/devices/bus/coleco/ctrl.c | 77 + src/devices/bus/coleco/ctrl.h | 105 + src/devices/bus/coleco/exp.c | 156 + src/devices/bus/coleco/exp.h | 132 + src/devices/bus/coleco/hand.c | 126 + src/devices/bus/coleco/hand.h | 55 + src/devices/bus/coleco/sac.c | 138 + src/devices/bus/coleco/sac.h | 56 + src/devices/bus/coleco/std.c | 60 + src/devices/bus/coleco/std.h | 44 + src/devices/bus/coleco/xin1.c | 71 + src/devices/bus/coleco/xin1.h | 48 + src/devices/bus/compucolor/floppy.c | 252 + src/devices/bus/compucolor/floppy.h | 123 + src/devices/bus/comx35/clm.c | 263 + src/devices/bus/comx35/clm.h | 63 + src/devices/bus/comx35/eprom.c | 121 + src/devices/bus/comx35/eprom.h | 56 + src/devices/bus/comx35/exp.c | 187 + src/devices/bus/comx35/exp.h | 145 + src/devices/bus/comx35/expbox.c | 306 + src/devices/bus/comx35/expbox.h | 77 + src/devices/bus/comx35/fdc.c | 286 + src/devices/bus/comx35/fdc.h | 70 + src/devices/bus/comx35/joycard.c | 114 + src/devices/bus/comx35/joycard.h | 53 + src/devices/bus/comx35/printer.c | 191 + src/devices/bus/comx35/printer.h | 60 + src/devices/bus/comx35/ram.c | 103 + src/devices/bus/comx35/ram.h | 53 + src/devices/bus/comx35/thermal.c | 127 + src/devices/bus/comx35/thermal.h | 54 + src/devices/bus/cpc/amdrum.c | 69 + src/devices/bus/cpc/amdrum.h | 48 + src/devices/bus/cpc/brunword4.c | 110 + src/devices/bus/cpc/brunword4.h | 38 + src/devices/bus/cpc/cpc_pds.c | 76 + src/devices/bus/cpc/cpc_pds.h | 58 + src/devices/bus/cpc/cpc_rom.c | 135 + src/devices/bus/cpc/cpc_rom.h | 90 + src/devices/bus/cpc/cpc_rs232.c | 164 + src/devices/bus/cpc/cpc_rs232.h | 65 + src/devices/bus/cpc/cpc_ssa1.c | 220 + src/devices/bus/cpc/cpc_ssa1.h | 128 + src/devices/bus/cpc/cpcexp.c | 89 + src/devices/bus/cpc/cpcexp.h | 154 + src/devices/bus/cpc/ddi1.c | 139 + src/devices/bus/cpc/ddi1.h | 47 + src/devices/bus/cpc/hd20.c | 131 + src/devices/bus/cpc/hd20.h | 50 + src/devices/bus/cpc/magicsound.c | 190 + src/devices/bus/cpc/magicsound.h | 91 + src/devices/bus/cpc/mface2.c | 343 + src/devices/bus/cpc/mface2.h | 71 + src/devices/bus/cpc/playcity.c | 162 + src/devices/bus/cpc/playcity.h | 68 + src/devices/bus/cpc/smartwatch.c | 91 + src/devices/bus/cpc/smartwatch.h | 48 + src/devices/bus/cpc/symbfac2.c | 295 + src/devices/bus/cpc/symbfac2.h | 85 + src/devices/bus/crvision/rom.c | 140 + src/devices/bus/crvision/rom.h | 116 + src/devices/bus/crvision/slot.c | 295 + src/devices/bus/crvision/slot.h | 108 + src/devices/bus/dmv/dmvbus.c | 381 + src/devices/bus/dmv/dmvbus.h | 122 + src/devices/bus/dmv/k210.c | 166 + src/devices/bus/dmv/k210.h | 71 + src/devices/bus/dmv/k220.c | 275 + src/devices/bus/dmv/k220.h | 60 + src/devices/bus/dmv/k230.c | 315 + src/devices/bus/dmv/k230.h | 146 + src/devices/bus/dmv/k233.c | 89 + src/devices/bus/dmv/k233.h | 44 + src/devices/bus/dmv/k801.c | 280 + src/devices/bus/dmv/k801.h | 106 + src/devices/bus/dmv/k803.c | 133 + src/devices/bus/dmv/k803.h | 54 + src/devices/bus/dmv/k806.c | 243 + src/devices/bus/dmv/k806.h | 72 + src/devices/bus/dmv/ram.c | 96 + src/devices/bus/dmv/ram.h | 71 + src/devices/bus/ecbbus/ecbbus.c | 211 + src/devices/bus/ecbbus/ecbbus.h | 187 + src/devices/bus/ecbbus/grip.c | 902 + src/devices/bus/ecbbus/grip.h | 131 + src/devices/bus/econet/e01.c | 716 + src/devices/bus/econet/e01.h | 135 + src/devices/bus/econet/econet.c | 313 + src/devices/bus/econet/econet.h | 165 + src/devices/bus/ep64/exdos.c | 243 + src/devices/bus/ep64/exdos.h | 64 + src/devices/bus/ep64/exp.c | 90 + src/devices/bus/ep64/exp.h | 151 + src/devices/bus/epson_sio/epson_sio.c | 115 + src/devices/bus/epson_sio/epson_sio.h | 96 + src/devices/bus/epson_sio/pf10.c | 241 + src/devices/bus/epson_sio/pf10.h | 101 + src/devices/bus/epson_sio/tf20.c | 320 + src/devices/bus/epson_sio/tf20.h | 91 + src/devices/bus/gameboy/gb_slot.c | 860 + src/devices/bus/gameboy/gb_slot.h | 211 + src/devices/bus/gameboy/mbc.c | 1274 + src/devices/bus/gameboy/mbc.h | 393 + src/devices/bus/gameboy/rom.c | 364 + src/devices/bus/gameboy/rom.h | 146 + src/devices/bus/gamegear/ggext.c | 120 + src/devices/bus/gamegear/ggext.h | 122 + src/devices/bus/gamegear/smsctrladp.c | 94 + src/devices/bus/gamegear/smsctrladp.h | 56 + src/devices/bus/gba/gba_slot.c | 465 + src/devices/bus/gba/gba_slot.h | 583 + src/devices/bus/gba/rom.c | 438 + src/devices/bus/gba/rom.h | 174 + src/devices/bus/generic/carts.c | 22 + src/devices/bus/generic/carts.h | 24 + src/devices/bus/generic/ram.c | 123 + src/devices/bus/generic/ram.h | 109 + src/devices/bus/generic/rom.c | 122 + src/devices/bus/generic/rom.h | 75 + src/devices/bus/generic/slot.c | 283 + src/devices/bus/generic/slot.h | 176 + src/devices/bus/ieee488/c2031.c | 482 + src/devices/bus/ieee488/c2031.h | 87 + src/devices/bus/ieee488/c2040.c | 802 + src/devices/bus/ieee488/c2040.h | 133 + src/devices/bus/ieee488/c2040fdc.c | 623 + src/devices/bus/ieee488/c2040fdc.h | 168 + src/devices/bus/ieee488/c8050.c | 950 + src/devices/bus/ieee488/c8050.h | 140 + src/devices/bus/ieee488/c8050fdc.c | 634 + src/devices/bus/ieee488/c8050fdc.h | 170 + src/devices/bus/ieee488/c8280.c | 527 + src/devices/bus/ieee488/c8280.h | 90 + src/devices/bus/ieee488/d9060.c | 578 + src/devices/bus/ieee488/d9060.h | 122 + src/devices/bus/ieee488/hardbox.c | 401 + src/devices/bus/ieee488/hardbox.h | 77 + src/devices/bus/ieee488/ieee488.c | 396 + src/devices/bus/ieee488/ieee488.h | 253 + src/devices/bus/ieee488/shark.c | 144 + src/devices/bus/ieee488/shark.h | 52 + src/devices/bus/ieee488/softbox.c | 393 + src/devices/bus/ieee488/softbox.h | 82 + src/devices/bus/imi7000/imi5000h.c | 478 + src/devices/bus/imi7000/imi5000h.h | 89 + src/devices/bus/imi7000/imi7000.c | 101 + src/devices/bus/imi7000/imi7000.h | 132 + src/devices/bus/intv/ecs.c | 589 + src/devices/bus/intv/ecs.h | 147 + src/devices/bus/intv/rom.c | 51 + src/devices/bus/intv/rom.h | 84 + src/devices/bus/intv/slot.c | 571 + src/devices/bus/intv/slot.h | 185 + src/devices/bus/intv/voice.c | 124 + src/devices/bus/intv/voice.h | 78 + src/devices/bus/iq151/disc2.c | 132 + src/devices/bus/iq151/disc2.h | 53 + src/devices/bus/iq151/grafik.c | 190 + src/devices/bus/iq151/grafik.h | 63 + src/devices/bus/iq151/iq151.c | 210 + src/devices/bus/iq151/iq151.h | 155 + src/devices/bus/iq151/minigraf.c | 167 + src/devices/bus/iq151/minigraf.h | 56 + src/devices/bus/iq151/ms151a.c | 167 + src/devices/bus/iq151/ms151a.h | 56 + src/devices/bus/iq151/rom.c | 229 + src/devices/bus/iq151/rom.h | 130 + src/devices/bus/iq151/staper.c | 144 + src/devices/bus/iq151/staper.h | 59 + src/devices/bus/iq151/video32.c | 170 + src/devices/bus/iq151/video32.h | 50 + src/devices/bus/iq151/video64.c | 177 + src/devices/bus/iq151/video64.h | 51 + src/devices/bus/isa/3c503.c | 304 + src/devices/bus/isa/3c503.h | 64 + src/devices/bus/isa/3c505.c | 1667 + src/devices/bus/isa/3c505.h | 283 + src/devices/bus/isa/adlib.c | 87 + src/devices/bus/isa/adlib.h | 44 + src/devices/bus/isa/aga.c | 1008 + src/devices/bus/isa/aga.h | 128 + src/devices/bus/isa/aha1542.c | 203 + src/devices/bus/isa/aha1542.h | 57 + src/devices/bus/isa/cga.c | 2011 ++ src/devices/bus/isa/cga.h | 286 + src/devices/bus/isa/com.c | 194 + src/devices/bus/isa/com.h | 58 + src/devices/bus/isa/dectalk.c | 220 + src/devices/bus/isa/dectalk.h | 56 + src/devices/bus/isa/ega.c | 1416 + src/devices/bus/isa/ega.h | 111 + src/devices/bus/isa/fdc.c | 167 + src/devices/bus/isa/fdc.h | 84 + src/devices/bus/isa/finalchs.c | 127 + src/devices/bus/isa/finalchs.h | 50 + src/devices/bus/isa/gblaster.c | 124 + src/devices/bus/isa/gblaster.h | 49 + src/devices/bus/isa/gus.c | 1724 + src/devices/bus/isa/gus.h | 323 + src/devices/bus/isa/hdc.c | 1050 + src/devices/bus/isa/hdc.h | 186 + src/devices/bus/isa/ibm_mfc.c | 484 + src/devices/bus/isa/ibm_mfc.h | 90 + src/devices/bus/isa/ide.c | 120 + src/devices/bus/isa/ide.h | 50 + src/devices/bus/isa/isa.c | 646 + src/devices/bus/isa/isa.h | 439 + src/devices/bus/isa/isa_cards.c | 103 + src/devices/bus/isa/isa_cards.h | 71 + src/devices/bus/isa/lpt.c | 67 + src/devices/bus/isa/lpt.h | 50 + src/devices/bus/isa/mach32.c | 156 + src/devices/bus/isa/mach32.h | 176 + src/devices/bus/isa/mc1502_fdc.c | 221 + src/devices/bus/isa/mc1502_fdc.h | 65 + src/devices/bus/isa/mc1502_rom.c | 71 + src/devices/bus/isa/mc1502_rom.h | 42 + src/devices/bus/isa/mda.c | 981 + src/devices/bus/isa/mda.h | 132 + src/devices/bus/isa/mpu401.c | 93 + src/devices/bus/isa/mpu401.h | 46 + src/devices/bus/isa/mufdc.c | 203 + src/devices/bus/isa/mufdc.h | 94 + src/devices/bus/isa/ne1000.c | 133 + src/devices/bus/isa/ne1000.h | 37 + src/devices/bus/isa/ne2000.c | 144 + src/devices/bus/isa/ne2000.h | 35 + src/devices/bus/isa/num9rev.c | 319 + src/devices/bus/isa/num9rev.h | 63 + src/devices/bus/isa/omti8621.c | 1382 + src/devices/bus/isa/omti8621.h | 135 + src/devices/bus/isa/p1_fdc.c | 203 + src/devices/bus/isa/p1_fdc.h | 58 + src/devices/bus/isa/p1_hdc.c | 146 + src/devices/bus/isa/p1_hdc.h | 55 + src/devices/bus/isa/p1_rom.c | 76 + src/devices/bus/isa/p1_rom.h | 42 + src/devices/bus/isa/pc1640_iga.c | 115 + src/devices/bus/isa/pc1640_iga.h | 46 + src/devices/bus/isa/pds.c | 65 + src/devices/bus/isa/pds.h | 40 + src/devices/bus/isa/pgc.c | 372 + src/devices/bus/isa/pgc.h | 67 + src/devices/bus/isa/s3virge.c | 776 + src/devices/bus/isa/s3virge.h | 82 + src/devices/bus/isa/sb16.c | 850 + src/devices/bus/isa/sb16.h | 120 + src/devices/bus/isa/sblaster.c | 1682 + src/devices/bus/isa/sblaster.h | 258 + src/devices/bus/isa/sc499.c | 1333 + src/devices/bus/isa/sc499.h | 159 + src/devices/bus/isa/side116.c | 190 + src/devices/bus/isa/side116.h | 59 + src/devices/bus/isa/ssi2001.c | 39 + src/devices/bus/isa/ssi2001.h | 40 + src/devices/bus/isa/stereo_fx.c | 233 + src/devices/bus/isa/stereo_fx.h | 81 + src/devices/bus/isa/svga_cirrus.c | 180 + src/devices/bus/isa/svga_cirrus.h | 63 + src/devices/bus/isa/svga_s3.c | 392 + src/devices/bus/isa/svga_s3.h | 111 + src/devices/bus/isa/svga_trident.c | 107 + src/devices/bus/isa/svga_trident.h | 49 + src/devices/bus/isa/svga_tseng.c | 94 + src/devices/bus/isa/svga_tseng.h | 43 + src/devices/bus/isa/trident.c | 1612 + src/devices/bus/isa/trident.h | 153 + src/devices/bus/isa/vga.c | 84 + src/devices/bus/isa/vga.h | 43 + src/devices/bus/isa/vga_ati.c | 351 + src/devices/bus/isa/vga_ati.h | 97 + src/devices/bus/isa/wd1002a_wx1.c | 70 + src/devices/bus/isa/wd1002a_wx1.h | 46 + src/devices/bus/isa/wdxt_gen.c | 376 + src/devices/bus/isa/wdxt_gen.h | 85 + src/devices/bus/isa/xsu_cards.c | 66 + src/devices/bus/isa/xsu_cards.h | 37 + src/devices/bus/isa/xtide.c | 333 + src/devices/bus/isa/xtide.h | 51 + src/devices/bus/isbx/compis_fdc.c | 181 + src/devices/bus/isbx/compis_fdc.h | 65 + src/devices/bus/isbx/isbc_218a.c | 208 + src/devices/bus/isbx/isbc_218a.h | 67 + src/devices/bus/isbx/isbx.c | 78 + src/devices/bus/isbx/isbx.h | 155 + src/devices/bus/kc/d002.c | 230 + src/devices/bus/kc/d002.h | 60 + src/devices/bus/kc/d004.c | 514 + src/devices/bus/kc/d004.h | 114 + src/devices/bus/kc/kc.c | 376 + src/devices/bus/kc/kc.h | 152 + src/devices/bus/kc/ram.c | 449 + src/devices/bus/kc/ram.h | 180 + src/devices/bus/kc/rom.c | 230 + src/devices/bus/kc/rom.h | 98 + src/devices/bus/lpci/cirrus.c | 164 + src/devices/bus/lpci/cirrus.h | 41 + src/devices/bus/lpci/i82371ab.c | 257 + src/devices/bus/lpci/i82371ab.h | 53 + src/devices/bus/lpci/i82371sb.c | 181 + src/devices/bus/lpci/i82371sb.h | 50 + src/devices/bus/lpci/i82439tx.c | 312 + src/devices/bus/lpci/i82439tx.h | 59 + src/devices/bus/lpci/mpc105.c | 233 + src/devices/bus/lpci/mpc105.h | 60 + src/devices/bus/lpci/northbridge.c | 48 + src/devices/bus/lpci/northbridge.h | 34 + src/devices/bus/lpci/pci.c | 334 + src/devices/bus/lpci/pci.h | 112 + src/devices/bus/lpci/southbridge.c | 490 + src/devices/bus/lpci/southbridge.h | 131 + src/devices/bus/macpds/macpds.c | 198 + src/devices/bus/macpds/macpds.h | 133 + src/devices/bus/macpds/pds_tpdfpd.c | 238 + src/devices/bus/macpds/pds_tpdfpd.h | 55 + src/devices/bus/megadrive/eeprom.c | 376 + src/devices/bus/megadrive/eeprom.h | 143 + src/devices/bus/megadrive/ggenie.c | 185 + src/devices/bus/megadrive/ggenie.h | 40 + src/devices/bus/megadrive/jcart.c | 257 + src/devices/bus/megadrive/jcart.h | 84 + src/devices/bus/megadrive/md_carts.c | 71 + src/devices/bus/megadrive/md_carts.h | 27 + src/devices/bus/megadrive/md_slot.c | 1099 + src/devices/bus/megadrive/md_slot.h | 262 + src/devices/bus/megadrive/rom.c | 1422 + src/devices/bus/megadrive/rom.h | 585 + src/devices/bus/megadrive/sk.c | 95 + src/devices/bus/megadrive/sk.h | 35 + src/devices/bus/megadrive/stm95.c | 265 + src/devices/bus/megadrive/stm95.h | 86 + src/devices/bus/megadrive/svp.c | 472 + src/devices/bus/megadrive/svp.h | 75 + src/devices/bus/midi/midi.c | 55 + src/devices/bus/midi/midi.h | 65 + src/devices/bus/midi/midiinport.c | 30 + src/devices/bus/midi/midiinport.h | 36 + src/devices/bus/midi/midioutport.c | 29 + src/devices/bus/midi/midioutport.h | 36 + src/devices/bus/msx_cart/arc.c | 64 + src/devices/bus/msx_cart/arc.h | 34 + src/devices/bus/msx_cart/ascii.c | 535 + src/devices/bus/msx_cart/ascii.h | 141 + src/devices/bus/msx_cart/bm_012.c | 112 + src/devices/bus/msx_cart/bm_012.h | 34 + src/devices/bus/msx_cart/cartridge.c | 109 + src/devices/bus/msx_cart/cartridge.h | 52 + src/devices/bus/msx_cart/crossblaim.c | 82 + src/devices/bus/msx_cart/crossblaim.h | 37 + src/devices/bus/msx_cart/disk.c | 628 + src/devices/bus/msx_cart/disk.h | 145 + src/devices/bus/msx_cart/dooly.c | 67 + src/devices/bus/msx_cart/dooly.h | 32 + src/devices/bus/msx_cart/fmpac.c | 173 + src/devices/bus/msx_cart/fmpac.h | 46 + src/devices/bus/msx_cart/fs_sr022.c | 71 + src/devices/bus/msx_cart/fs_sr022.h | 33 + src/devices/bus/msx_cart/halnote.c | 159 + src/devices/bus/msx_cart/halnote.h | 37 + src/devices/bus/msx_cart/hfox.c | 79 + src/devices/bus/msx_cart/hfox.h | 35 + src/devices/bus/msx_cart/holy_quran.c | 119 + src/devices/bus/msx_cart/holy_quran.h | 37 + src/devices/bus/msx_cart/konami.c | 937 + src/devices/bus/msx_cart/konami.h | 197 + src/devices/bus/msx_cart/korean.c | 298 + src/devices/bus/msx_cart/korean.h | 91 + src/devices/bus/msx_cart/majutsushi.c | 115 + src/devices/bus/msx_cart/majutsushi.h | 39 + src/devices/bus/msx_cart/moonsound.c | 126 + src/devices/bus/msx_cart/moonsound.h | 37 + src/devices/bus/msx_cart/msx_audio.c | 389 + src/devices/bus/msx_cart/msx_audio.h | 93 + src/devices/bus/msx_cart/msx_audio_kb.c | 313 + src/devices/bus/msx_cart/msx_audio_kb.h | 49 + src/devices/bus/msx_cart/msxdos2.c | 67 + src/devices/bus/msx_cart/msxdos2.h | 35 + src/devices/bus/msx_cart/nomapper.c | 94 + src/devices/bus/msx_cart/nomapper.h | 30 + src/devices/bus/msx_cart/rtype.c | 78 + src/devices/bus/msx_cart/rtype.h | 35 + src/devices/bus/msx_cart/super_swangi.c | 72 + src/devices/bus/msx_cart/super_swangi.h | 35 + src/devices/bus/msx_cart/superloderunner.c | 62 + src/devices/bus/msx_cart/superloderunner.h | 35 + src/devices/bus/msx_cart/yamaha.c | 205 + src/devices/bus/msx_cart/yamaha.h | 64 + src/devices/bus/msx_slot/bunsetsu.c | 78 + src/devices/bus/msx_slot/bunsetsu.h | 38 + src/devices/bus/msx_slot/cartridge.c | 382 + src/devices/bus/msx_slot/cartridge.h | 87 + src/devices/bus/msx_slot/disk.c | 813 + src/devices/bus/msx_slot/disk.h | 231 + src/devices/bus/msx_slot/fs4600.c | 163 + src/devices/bus/msx_slot/fs4600.h | 47 + src/devices/bus/msx_slot/music.c | 49 + src/devices/bus/msx_slot/music.h | 39 + src/devices/bus/msx_slot/panasonic08.c | 182 + src/devices/bus/msx_slot/panasonic08.h | 48 + src/devices/bus/msx_slot/ram.c | 36 + src/devices/bus/msx_slot/ram.h | 36 + src/devices/bus/msx_slot/ram_mm.c | 80 + src/devices/bus/msx_slot/ram_mm.h | 45 + src/devices/bus/msx_slot/rom.c | 66 + src/devices/bus/msx_slot/rom.h | 34 + src/devices/bus/msx_slot/slot.c | 36 + src/devices/bus/msx_slot/slot.h | 39 + src/devices/bus/msx_slot/sony08.c | 190 + src/devices/bus/msx_slot/sony08.h | 47 + src/devices/bus/nasbus/avc.c | 164 + src/devices/bus/nasbus/avc.h | 56 + src/devices/bus/nasbus/cards.c | 14 + src/devices/bus/nasbus/cards.h | 21 + src/devices/bus/nasbus/floppy.c | 209 + src/devices/bus/nasbus/floppy.h | 61 + src/devices/bus/nasbus/nasbus.c | 165 + src/devices/bus/nasbus/nasbus.h | 210 + src/devices/bus/neogeo/banked_cart.c | 107 + src/devices/bus/neogeo/banked_cart.h | 46 + src/devices/bus/neogeo/bootleg_cart.c | 378 + src/devices/bus/neogeo/bootleg_cart.h | 250 + src/devices/bus/neogeo/bootleg_hybrid_cart.c | 319 + src/devices/bus/neogeo/bootleg_hybrid_cart.h | 192 + src/devices/bus/neogeo/bootleg_prot.c | 1066 + src/devices/bus/neogeo/bootleg_prot.h | 98 + src/devices/bus/neogeo/cmc_cart.c | 223 + src/devices/bus/neogeo/cmc_cart.h | 191 + src/devices/bus/neogeo/cmc_prot.c | 789 + src/devices/bus/neogeo/cmc_prot.h | 87 + src/devices/bus/neogeo/fatfury2_cart.c | 75 + src/devices/bus/neogeo/fatfury2_cart.h | 41 + src/devices/bus/neogeo/fatfury2_prot.c | 110 + src/devices/bus/neogeo/fatfury2_prot.h | 42 + src/devices/bus/neogeo/kof2002_cart.c | 157 + src/devices/bus/neogeo/kof2002_cart.h | 111 + src/devices/bus/neogeo/kof2002_prot.c | 83 + src/devices/bus/neogeo/kof2002_prot.h | 38 + src/devices/bus/neogeo/kof98_cart.c | 80 + src/devices/bus/neogeo/kof98_cart.h | 41 + src/devices/bus/neogeo/kof98_prot.c | 141 + src/devices/bus/neogeo/kof98_prot.h | 40 + src/devices/bus/neogeo/kog_prot.c | 118 + src/devices/bus/neogeo/kog_prot.h | 40 + src/devices/bus/neogeo/mslugx_cart.c | 75 + src/devices/bus/neogeo/mslugx_cart.h | 41 + src/devices/bus/neogeo/mslugx_prot.c | 95 + src/devices/bus/neogeo/mslugx_prot.h | 41 + src/devices/bus/neogeo/neogeo_carts.c | 97 + src/devices/bus/neogeo/neogeo_carts.h | 30 + src/devices/bus/neogeo/neogeo_helper.c | 66 + src/devices/bus/neogeo/neogeo_helper.h | 4 + src/devices/bus/neogeo/neogeo_intf.c | 33 + src/devices/bus/neogeo/neogeo_intf.h | 78 + src/devices/bus/neogeo/neogeo_slot.c | 222 + src/devices/bus/neogeo/neogeo_slot.h | 87 + src/devices/bus/neogeo/pcm2_cart.c | 135 + src/devices/bus/neogeo/pcm2_cart.h | 98 + src/devices/bus/neogeo/pcm2_prot.c | 88 + src/devices/bus/neogeo/pcm2_prot.h | 36 + src/devices/bus/neogeo/pvc_cart.c | 139 + src/devices/bus/neogeo/pvc_cart.h | 108 + src/devices/bus/neogeo/pvc_prot.c | 316 + src/devices/bus/neogeo/pvc_prot.h | 50 + src/devices/bus/neogeo/rom.c | 70 + src/devices/bus/neogeo/rom.h | 38 + src/devices/bus/neogeo/sbp_prot.c | 86 + src/devices/bus/neogeo/sbp_prot.h | 40 + src/devices/bus/neogeo/sma_cart.c | 177 + src/devices/bus/neogeo/sma_cart.h | 112 + src/devices/bus/neogeo/sma_prot.c | 462 + src/devices/bus/neogeo/sma_prot.h | 58 + src/devices/bus/nes/2a03pur.c | 109 + src/devices/bus/nes/2a03pur.h | 33 + src/devices/bus/nes/act53.c | 206 + src/devices/bus/nes/act53.h | 38 + src/devices/bus/nes/aladdin.c | 339 + src/devices/bus/nes/aladdin.h | 167 + src/devices/bus/nes/ave.c | 214 + src/devices/bus/nes/ave.h | 69 + src/devices/bus/nes/bandai.c | 479 + src/devices/bus/nes/bandai.h | 141 + src/devices/bus/nes/benshieng.c | 105 + src/devices/bus/nes/benshieng.h | 34 + src/devices/bus/nes/bootleg.c | 1635 + src/devices/bus/nes/bootleg.h | 480 + src/devices/bus/nes/camerica.c | 225 + src/devices/bus/nes/camerica.h | 72 + src/devices/bus/nes/cne.c | 220 + src/devices/bus/nes/cne.h | 66 + src/devices/bus/nes/cony.c | 397 + src/devices/bus/nes/cony.h | 75 + src/devices/bus/nes/datach.c | 420 + src/devices/bus/nes/datach.h | 170 + src/devices/bus/nes/discrete.c | 209 + src/devices/bus/nes/discrete.h | 80 + src/devices/bus/nes/disksys.c | 431 + src/devices/bus/nes/disksys.h | 71 + src/devices/bus/nes/event.c | 239 + src/devices/bus/nes/event.h | 44 + src/devices/bus/nes/ggenie.c | 274 + src/devices/bus/nes/ggenie.h | 58 + src/devices/bus/nes/henggedianzi.c | 278 + src/devices/bus/nes/henggedianzi.h | 78 + src/devices/bus/nes/hes.c | 87 + src/devices/bus/nes/hes.h | 28 + src/devices/bus/nes/hosenkan.c | 155 + src/devices/bus/nes/hosenkan.h | 39 + src/devices/bus/nes/irem.c | 352 + src/devices/bus/nes/irem.h | 108 + src/devices/bus/nes/jaleco.c | 886 + src/devices/bus/nes/jaleco.h | 256 + src/devices/bus/nes/jy.c | 589 + src/devices/bus/nes/jy.h | 104 + src/devices/bus/nes/kaiser.c | 588 + src/devices/bus/nes/kaiser.h | 184 + src/devices/bus/nes/karastudio.c | 309 + src/devices/bus/nes/karastudio.h | 147 + src/devices/bus/nes/konami.c | 787 + src/devices/bus/nes/konami.h | 155 + src/devices/bus/nes/legacy.c | 311 + src/devices/bus/nes/legacy.h | 81 + src/devices/bus/nes/mmc1.c | 374 + src/devices/bus/nes/mmc1.h | 82 + src/devices/bus/nes/mmc2.c | 198 + src/devices/bus/nes/mmc2.h | 54 + src/devices/bus/nes/mmc3.c | 560 + src/devices/bus/nes/mmc3.h | 146 + src/devices/bus/nes/mmc3_clones.c | 2588 ++ src/devices/bus/nes/mmc3_clones.h | 697 + src/devices/bus/nes/mmc5.c | 679 + src/devices/bus/nes/mmc5.h | 94 + src/devices/bus/nes/multigame.c | 2602 ++ src/devices/bus/nes/multigame.h | 894 + src/devices/bus/nes/namcot.c | 688 + src/devices/bus/nes/namcot.h | 163 + src/devices/bus/nes/nanjing.c | 175 + src/devices/bus/nes/nanjing.h | 38 + src/devices/bus/nes/nes_carts.c | 366 + src/devices/bus/nes/nes_carts.h | 73 + src/devices/bus/nes/nes_ines.inc | 939 + src/devices/bus/nes/nes_pcb.inc | 609 + src/devices/bus/nes/nes_slot.c | 1053 + src/devices/bus/nes/nes_slot.h | 430 + src/devices/bus/nes/nes_unif.inc | 575 + src/devices/bus/nes/ntdec.c | 186 + src/devices/bus/nes/ntdec.h | 51 + src/devices/bus/nes/nxrom.c | 583 + src/devices/bus/nes/nxrom.h | 216 + src/devices/bus/nes/pirate.c | 1387 + src/devices/bus/nes/pirate.h | 399 + src/devices/bus/nes/pt554.c | 107 + src/devices/bus/nes/pt554.h | 31 + src/devices/bus/nes/racermate.c | 92 + src/devices/bus/nes/racermate.h | 35 + src/devices/bus/nes/rcm.c | 303 + src/devices/bus/nes/rcm.h | 105 + src/devices/bus/nes/rexsoft.c | 262 + src/devices/bus/nes/rexsoft.h | 61 + src/devices/bus/nes/sachen.c | 695 + src/devices/bus/nes/sachen.h | 261 + src/devices/bus/nes/somari.c | 421 + src/devices/bus/nes/somari.h | 54 + src/devices/bus/nes/sunsoft.c | 628 + src/devices/bus/nes/sunsoft.h | 147 + src/devices/bus/nes/sunsoft_dcs.c | 315 + src/devices/bus/nes/sunsoft_dcs.h | 150 + src/devices/bus/nes/taito.c | 470 + src/devices/bus/nes/taito.h | 104 + src/devices/bus/nes/tengen.c | 376 + src/devices/bus/nes/tengen.h | 88 + src/devices/bus/nes/txc.c | 268 + src/devices/bus/nes/txc.h | 99 + src/devices/bus/nes/waixing.c | 1244 + src/devices/bus/nes/waixing.h | 396 + src/devices/bus/nes_ctrl/4score.c | 189 + src/devices/bus/nes_ctrl/4score.h | 84 + src/devices/bus/nes_ctrl/arkpaddle.c | 130 + src/devices/bus/nes_ctrl/arkpaddle.h | 70 + src/devices/bus/nes_ctrl/bcbattle.c | 183 + src/devices/bus/nes_ctrl/bcbattle.h | 53 + src/devices/bus/nes_ctrl/ctrl.c | 207 + src/devices/bus/nes_ctrl/ctrl.h | 103 + src/devices/bus/nes_ctrl/fckeybrd.c | 231 + src/devices/bus/nes_ctrl/fckeybrd.h | 54 + src/devices/bus/nes_ctrl/ftrainer.c | 153 + src/devices/bus/nes_ctrl/ftrainer.h | 51 + src/devices/bus/nes_ctrl/hori.c | 168 + src/devices/bus/nes_ctrl/hori.h | 78 + src/devices/bus/nes_ctrl/joypad.c | 315 + src/devices/bus/nes_ctrl/joypad.h | 111 + src/devices/bus/nes_ctrl/konamihs.c | 101 + src/devices/bus/nes_ctrl/konamihs.h | 49 + src/devices/bus/nes_ctrl/miracle.c | 283 + src/devices/bus/nes_ctrl/miracle.h | 71 + src/devices/bus/nes_ctrl/mjpanel.c | 131 + src/devices/bus/nes_ctrl/mjpanel.h | 51 + src/devices/bus/nes_ctrl/pachinko.c | 107 + src/devices/bus/nes_ctrl/pachinko.h | 49 + src/devices/bus/nes_ctrl/partytap.c | 107 + src/devices/bus/nes_ctrl/partytap.h | 49 + src/devices/bus/nes_ctrl/powerpad.c | 135 + src/devices/bus/nes_ctrl/powerpad.h | 52 + src/devices/bus/nes_ctrl/suborkey.c | 229 + src/devices/bus/nes_ctrl/suborkey.h | 51 + src/devices/bus/nes_ctrl/zapper.c | 96 + src/devices/bus/nes_ctrl/zapper.h | 52 + src/devices/bus/nubus/nubus.c | 475 + src/devices/bus/nubus/nubus.h | 177 + src/devices/bus/nubus/nubus_48gc.c | 369 + src/devices/bus/nubus/nubus_48gc.h | 70 + src/devices/bus/nubus/nubus_asntmc3b.c | 210 + src/devices/bus/nubus/nubus_asntmc3b.h | 68 + src/devices/bus/nubus/nubus_cb264.c | 300 + src/devices/bus/nubus/nubus_cb264.h | 51 + src/devices/bus/nubus/nubus_image.c | 388 + src/devices/bus/nubus/nubus_image.h | 80 + src/devices/bus/nubus/nubus_m2hires.c | 314 + src/devices/bus/nubus/nubus_m2hires.h | 56 + src/devices/bus/nubus/nubus_m2video.c | 314 + src/devices/bus/nubus/nubus_m2video.h | 56 + src/devices/bus/nubus/nubus_radiustpd.c | 214 + src/devices/bus/nubus/nubus_radiustpd.h | 56 + src/devices/bus/nubus/nubus_spec8.c | 355 + src/devices/bus/nubus/nubus_spec8.h | 64 + src/devices/bus/nubus/nubus_specpdq.c | 490 + src/devices/bus/nubus/nubus_specpdq.h | 63 + src/devices/bus/nubus/nubus_vikbw.c | 174 + src/devices/bus/nubus/nubus_vikbw.h | 50 + src/devices/bus/nubus/nubus_wsportrait.c | 310 + src/devices/bus/nubus/nubus_wsportrait.h | 56 + src/devices/bus/nubus/pds30_30hr.c | 319 + src/devices/bus/nubus/pds30_30hr.h | 56 + src/devices/bus/nubus/pds30_cb264.c | 324 + src/devices/bus/nubus/pds30_cb264.h | 56 + src/devices/bus/nubus/pds30_mc30.c | 336 + src/devices/bus/nubus/pds30_mc30.h | 56 + src/devices/bus/nubus/pds30_procolor816.c | 350 + src/devices/bus/nubus/pds30_procolor816.h | 56 + src/devices/bus/nubus/pds30_sigmalview.c | 216 + src/devices/bus/nubus/pds30_sigmalview.h | 57 + src/devices/bus/odyssey2/chess.c | 60 + src/devices/bus/odyssey2/chess.h | 32 + src/devices/bus/odyssey2/rom.c | 96 + src/devices/bus/odyssey2/rom.h | 67 + src/devices/bus/odyssey2/slot.c | 278 + src/devices/bus/odyssey2/slot.h | 121 + src/devices/bus/odyssey2/voice.c | 103 + src/devices/bus/odyssey2/voice.h | 50 + src/devices/bus/oricext/jasmin.c | 174 + src/devices/bus/oricext/jasmin.h | 43 + src/devices/bus/oricext/microdisc.c | 152 + src/devices/bus/oricext/microdisc.h | 54 + src/devices/bus/oricext/oricext.c | 78 + src/devices/bus/oricext/oricext.h | 65 + src/devices/bus/pc_joy/pc_joy.c | 93 + src/devices/bus/pc_joy/pc_joy.h | 78 + src/devices/bus/pc_joy/pc_joy_sw.c | 177 + src/devices/bus/pc_joy/pc_joy_sw.h | 38 + src/devices/bus/pc_kbd/ec1841.c | 486 + src/devices/bus/pc_kbd/ec1841.h | 82 + src/devices/bus/pc_kbd/iskr1030.c | 500 + src/devices/bus/pc_kbd/iskr1030.h | 93 + src/devices/bus/pc_kbd/keyboards.c | 28 + src/devices/bus/pc_kbd/keyboards.h | 31 + src/devices/bus/pc_kbd/keytro.c | 629 + src/devices/bus/pc_kbd/keytro.h | 76 + src/devices/bus/pc_kbd/msnat.c | 451 + src/devices/bus/pc_kbd/msnat.h | 74 + src/devices/bus/pc_kbd/pc83.c | 424 + src/devices/bus/pc_kbd/pc83.h | 89 + src/devices/bus/pc_kbd/pc_kbdc.c | 235 + src/devices/bus/pc_kbd/pc_kbdc.h | 143 + src/devices/bus/pc_kbd/pcat84.c | 641 + src/devices/bus/pc_kbd/pcat84.h | 114 + src/devices/bus/pc_kbd/pcxt83.c | 451 + src/devices/bus/pc_kbd/pcxt83.h | 83 + src/devices/bus/pce/pce_rom.c | 126 + src/devices/bus/pce/pce_rom.h | 85 + src/devices/bus/pce/pce_slot.c | 395 + src/devices/bus/pce/pce_slot.h | 129 + src/devices/bus/pet/64k.c | 203 + src/devices/bus/pet/64k.h | 56 + src/devices/bus/pet/c2n.c | 160 + src/devices/bus/pet/c2n.h | 86 + src/devices/bus/pet/cass.c | 99 + src/devices/bus/pet/cass.h | 117 + src/devices/bus/pet/cb2snd.c | 64 + src/devices/bus/pet/cb2snd.h | 44 + src/devices/bus/pet/diag.c | 44 + src/devices/bus/pet/diag.h | 57 + src/devices/bus/pet/diag264_lb_tape.c | 83 + src/devices/bus/pet/diag264_lb_tape.h | 53 + src/devices/bus/pet/exp.c | 204 + src/devices/bus/pet/exp.h | 139 + src/devices/bus/pet/hsg.c | 258 + src/devices/bus/pet/hsg.h | 87 + src/devices/bus/pet/petuja.c | 105 + src/devices/bus/pet/petuja.h | 63 + src/devices/bus/pet/superpet.c | 436 + src/devices/bus/pet/superpet.h | 80 + src/devices/bus/pet/user.c | 130 + src/devices/bus/pet/user.h | 231 + src/devices/bus/plus4/c1551.c | 552 + src/devices/bus/plus4/c1551.h | 107 + src/devices/bus/plus4/diag264_lb_user.c | 42 + src/devices/bus/plus4/diag264_lb_user.h | 59 + src/devices/bus/plus4/exp.c | 209 + src/devices/bus/plus4/exp.h | 187 + src/devices/bus/plus4/sid.c | 165 + src/devices/bus/plus4/sid.h | 59 + src/devices/bus/plus4/std.c | 69 + src/devices/bus/plus4/std.h | 47 + src/devices/bus/plus4/user.c | 22 + src/devices/bus/plus4/user.h | 33 + src/devices/bus/psx/analogue.c | 264 + src/devices/bus/psx/analogue.h | 57 + src/devices/bus/psx/ctlrport.c | 231 + src/devices/bus/psx/ctlrport.h | 145 + src/devices/bus/psx/memcard.c | 365 + src/devices/bus/psx/memcard.h | 77 + src/devices/bus/psx/multitap.c | 275 + src/devices/bus/psx/multitap.h | 43 + src/devices/bus/ql/cst_q_plus4.c | 144 + src/devices/bus/ql/cst_q_plus4.h | 72 + src/devices/bus/ql/cst_qdisc.c | 85 + src/devices/bus/ql/cst_qdisc.h | 53 + src/devices/bus/ql/cumana_fdi.c | 85 + src/devices/bus/ql/cumana_fdi.h | 53 + src/devices/bus/ql/exp.c | 110 + src/devices/bus/ql/exp.h | 151 + src/devices/bus/ql/kempston_di.c | 83 + src/devices/bus/ql/kempston_di.h | 53 + src/devices/bus/ql/miracle_gold_card.c | 85 + src/devices/bus/ql/miracle_gold_card.h | 53 + src/devices/bus/ql/miracle_hd.c | 83 + src/devices/bus/ql/miracle_hd.h | 53 + src/devices/bus/ql/mp_fdi.c | 83 + src/devices/bus/ql/mp_fdi.h | 53 + src/devices/bus/ql/opd_basic_master.c | 81 + src/devices/bus/ql/opd_basic_master.h | 53 + src/devices/bus/ql/pcml_qdisk.c | 83 + src/devices/bus/ql/pcml_qdisk.h | 53 + src/devices/bus/ql/qubide.c | 286 + src/devices/bus/ql/qubide.h | 63 + src/devices/bus/ql/rom.c | 136 + src/devices/bus/ql/rom.h | 126 + src/devices/bus/ql/sandy_superdisk.c | 275 + src/devices/bus/ql/sandy_superdisk.h | 70 + src/devices/bus/ql/sandy_superqboard.c | 453 + src/devices/bus/ql/sandy_superqboard.h | 131 + src/devices/bus/ql/std.c | 57 + src/devices/bus/ql/std.h | 44 + src/devices/bus/ql/trumpcard.c | 291 + src/devices/bus/ql/trumpcard.h | 100 + src/devices/bus/rs232/keyboard.c | 115 + src/devices/bus/rs232/keyboard.h | 48 + src/devices/bus/rs232/loopback.c | 42 + src/devices/bus/rs232/loopback.h | 25 + src/devices/bus/rs232/null_modem.c | 131 + src/devices/bus/rs232/null_modem.h | 53 + src/devices/bus/rs232/printer.c | 85 + src/devices/bus/rs232/printer.h | 44 + src/devices/bus/rs232/rs232.c | 113 + src/devices/bus/rs232/rs232.h | 263 + src/devices/bus/rs232/ser_mouse.c | 265 + src/devices/bus/rs232/ser_mouse.h | 81 + src/devices/bus/rs232/terminal.c | 106 + src/devices/bus/rs232/terminal.h | 46 + src/devices/bus/rs232/xvd701.c | 150 + src/devices/bus/rs232/xvd701.h | 44 + src/devices/bus/s100/dj2db.c | 517 + src/devices/bus/s100/dj2db.h | 88 + src/devices/bus/s100/djdma.c | 127 + src/devices/bus/s100/djdma.h | 51 + src/devices/bus/s100/mm65k16s.c | 267 + src/devices/bus/s100/mm65k16s.h | 55 + src/devices/bus/s100/nsmdsa.c | 120 + src/devices/bus/s100/nsmdsa.h | 58 + src/devices/bus/s100/nsmdsad.c | 122 + src/devices/bus/s100/nsmdsad.h | 59 + src/devices/bus/s100/s100.c | 200 + src/devices/bus/s100/s100.h | 311 + src/devices/bus/s100/wunderbus.c | 528 + src/devices/bus/s100/wunderbus.h | 72 + src/devices/bus/saturn/bram.c | 110 + src/devices/bus/saturn/bram.h | 69 + src/devices/bus/saturn/dram.c | 96 + src/devices/bus/saturn/dram.h | 49 + src/devices/bus/saturn/rom.c | 55 + src/devices/bus/saturn/rom.h | 33 + src/devices/bus/saturn/sat_slot.c | 295 + src/devices/bus/saturn/sat_slot.h | 123 + src/devices/bus/scsi/acb4070.c | 63 + src/devices/bus/scsi/acb4070.h | 47 + src/devices/bus/scsi/cdu76s.c | 47 + src/devices/bus/scsi/cdu76s.h | 31 + src/devices/bus/scsi/d9060hd.c | 36 + src/devices/bus/scsi/d9060hd.h | 22 + src/devices/bus/scsi/omti5100.c | 94 + src/devices/bus/scsi/omti5100.h | 30 + src/devices/bus/scsi/pc9801_sasi.c | 28 + src/devices/bus/scsi/pc9801_sasi.h | 20 + src/devices/bus/scsi/s1410.c | 365 + src/devices/bus/scsi/s1410.h | 35 + src/devices/bus/scsi/sa1403d.c | 148 + src/devices/bus/scsi/sa1403d.h | 36 + src/devices/bus/scsi/scsi.c | 709 + src/devices/bus/scsi/scsi.h | 313 + src/devices/bus/scsi/scsicd.c | 41 + src/devices/bus/scsi/scsicd.h | 31 + src/devices/bus/scsi/scsihd.c | 39 + src/devices/bus/scsi/scsihd.h | 31 + src/devices/bus/scsi/scsihle.c | 591 + src/devices/bus/scsi/scsihle.h | 92 + src/devices/bus/scv/rom.c | 205 + src/devices/bus/scv/rom.h | 151 + src/devices/bus/scv/slot.c | 317 + src/devices/bus/scv/slot.h | 119 + src/devices/bus/sega8/ccatch.c | 63 + src/devices/bus/sega8/ccatch.h | 35 + src/devices/bus/sega8/mgear.c | 46 + src/devices/bus/sega8/mgear.h | 39 + src/devices/bus/sega8/rom.c | 940 + src/devices/bus/sega8/rom.h | 388 + src/devices/bus/sega8/sega8_slot.c | 872 + src/devices/bus/sega8/sega8_slot.h | 243 + src/devices/bus/sms_ctrl/graphic.c | 156 + src/devices/bus/sms_ctrl/graphic.h | 59 + src/devices/bus/sms_ctrl/joypad.c | 76 + src/devices/bus/sms_ctrl/joypad.h | 52 + src/devices/bus/sms_ctrl/lphaser.c | 291 + src/devices/bus/sms_ctrl/lphaser.h | 69 + src/devices/bus/sms_ctrl/multitap.c | 154 + src/devices/bus/sms_ctrl/multitap.h | 59 + src/devices/bus/sms_ctrl/paddle.c | 108 + src/devices/bus/sms_ctrl/paddle.h | 60 + src/devices/bus/sms_ctrl/rfu.c | 140 + src/devices/bus/sms_ctrl/rfu.h | 62 + src/devices/bus/sms_ctrl/smsctrl.c | 133 + src/devices/bus/sms_ctrl/smsctrl.h | 118 + src/devices/bus/sms_ctrl/sports.c | 158 + src/devices/bus/sms_ctrl/sports.h | 65 + src/devices/bus/sms_ctrl/sportsjp.c | 156 + src/devices/bus/sms_ctrl/sportsjp.h | 65 + src/devices/bus/sms_exp/gender.c | 103 + src/devices/bus/sms_exp/gender.h | 57 + src/devices/bus/sms_exp/smsexp.c | 137 + src/devices/bus/sms_exp/smsexp.h | 95 + src/devices/bus/snes/bsx.c | 546 + src/devices/bus/snes/bsx.h | 151 + src/devices/bus/snes/event.c | 285 + src/devices/bus/snes/event.h | 57 + src/devices/bus/snes/rom.c | 510 + src/devices/bus/snes/rom.h | 209 + src/devices/bus/snes/rom21.c | 258 + src/devices/bus/snes/rom21.h | 67 + src/devices/bus/snes/sa1.c | 1144 + src/devices/bus/snes/sa1.h | 113 + src/devices/bus/snes/sdd1.c | 617 + src/devices/bus/snes/sdd1.h | 187 + src/devices/bus/snes/sfx.c | 148 + src/devices/bus/snes/sfx.h | 50 + src/devices/bus/snes/sgb.c | 292 + src/devices/bus/snes/sgb.h | 78 + src/devices/bus/snes/snes_carts.c | 52 + src/devices/bus/snes/snes_carts.h | 31 + src/devices/bus/snes/snes_slot.c | 1374 + src/devices/bus/snes/snes_slot.h | 274 + src/devices/bus/snes/spc7110.c | 1677 + src/devices/bus/snes/spc7110.h | 226 + src/devices/bus/snes/sufami.c | 162 + src/devices/bus/snes/sufami.h | 53 + src/devices/bus/snes/upd.c | 566 + src/devices/bus/snes/upd.h | 223 + src/devices/bus/snes_ctrl/bcbattle.c | 212 + src/devices/bus/snes_ctrl/bcbattle.h | 60 + src/devices/bus/snes_ctrl/ctrl.c | 136 + src/devices/bus/snes_ctrl/ctrl.h | 100 + src/devices/bus/snes_ctrl/joypad.c | 125 + src/devices/bus/snes_ctrl/joypad.h | 55 + src/devices/bus/snes_ctrl/miracle.c | 278 + src/devices/bus/snes_ctrl/miracle.h | 72 + src/devices/bus/snes_ctrl/mouse.c | 239 + src/devices/bus/snes_ctrl/mouse.h | 63 + src/devices/bus/snes_ctrl/multitap.c | 154 + src/devices/bus/snes_ctrl/multitap.h | 61 + src/devices/bus/snes_ctrl/pachinko.c | 110 + src/devices/bus/snes_ctrl/pachinko.h | 56 + src/devices/bus/snes_ctrl/sscope.c | 185 + src/devices/bus/snes_ctrl/sscope.h | 60 + src/devices/bus/snes_ctrl/twintap.c | 113 + src/devices/bus/snes_ctrl/twintap.h | 55 + src/devices/bus/spc1000/exp.c | 82 + src/devices/bus/spc1000/exp.h | 50 + src/devices/bus/spc1000/fdd.c | 226 + src/devices/bus/spc1000/fdd.h | 65 + src/devices/bus/spc1000/vdp.c | 106 + src/devices/bus/spc1000/vdp.h | 45 + src/devices/bus/ti99_peb/bwg.c | 704 + src/devices/bus/ti99_peb/bwg.h | 142 + src/devices/bus/ti99_peb/evpc.c | 369 + src/devices/bus/ti99_peb/evpc.h | 62 + src/devices/bus/ti99_peb/hfdc.c | 1079 + src/devices/bus/ti99_peb/hfdc.h | 188 + src/devices/bus/ti99_peb/horizon.c | 450 + src/devices/bus/ti99_peb/horizon.h | 67 + src/devices/bus/ti99_peb/hsgpl.c | 680 + src/devices/bus/ti99_peb/hsgpl.h | 83 + src/devices/bus/ti99_peb/memex.c | 176 + src/devices/bus/ti99_peb/memex.h | 45 + src/devices/bus/ti99_peb/myarcmem.c | 209 + src/devices/bus/ti99_peb/myarcmem.h | 45 + src/devices/bus/ti99_peb/pcode.c | 331 + src/devices/bus/ti99_peb/pcode.h | 51 + src/devices/bus/ti99_peb/peribox.c | 722 + src/devices/bus/ti99_peb/peribox.h | 246 + src/devices/bus/ti99_peb/samsmem.c | 133 + src/devices/bus/ti99_peb/samsmem.h | 44 + src/devices/bus/ti99_peb/spchsyn.c | 188 + src/devices/bus/ti99_peb/spchsyn.h | 51 + src/devices/bus/ti99_peb/ti_32kmem.c | 118 + src/devices/bus/ti99_peb/ti_32kmem.h | 36 + src/devices/bus/ti99_peb/ti_fdc.c | 432 + src/devices/bus/ti99_peb/ti_fdc.h | 111 + src/devices/bus/ti99_peb/ti_rs232.c | 1135 + src/devices/bus/ti99_peb/ti_rs232.h | 168 + src/devices/bus/ti99_peb/tn_ide.c | 382 + src/devices/bus/ti99_peb/tn_ide.h | 64 + src/devices/bus/ti99_peb/tn_usbsm.c | 345 + src/devices/bus/ti99_peb/tn_usbsm.h | 60 + src/devices/bus/ti99x/990_dk.c | 893 + src/devices/bus/ti99x/990_dk.h | 74 + src/devices/bus/ti99x/990_hd.c | 1025 + src/devices/bus/ti99x/990_hd.h | 80 + src/devices/bus/ti99x/990_tap.c | 1021 + src/devices/bus/ti99x/990_tap.h | 63 + src/devices/bus/ti99x/998board.c | 1076 + src/devices/bus/ti99x/998board.h | 278 + src/devices/bus/ti99x/datamux.c | 489 + src/devices/bus/ti99x/datamux.h | 157 + src/devices/bus/ti99x/genboard.c | 1994 ++ src/devices/bus/ti99x/genboard.h | 220 + src/devices/bus/ti99x/grom.c | 269 + src/devices/bus/ti99x/grom.h | 108 + src/devices/bus/ti99x/gromport.c | 2509 ++ src/devices/bus/ti99x/gromport.h | 547 + src/devices/bus/ti99x/handset.c | 530 + src/devices/bus/ti99x/handset.h | 93 + src/devices/bus/ti99x/joyport.c | 115 + src/devices/bus/ti99x/joyport.h | 89 + src/devices/bus/ti99x/mecmouse.c | 209 + src/devices/bus/ti99x/mecmouse.h | 48 + src/devices/bus/ti99x/ti99defs.h | 116 + src/devices/bus/ti99x/videowrp.c | 258 + src/devices/bus/ti99x/videowrp.h | 187 + src/devices/bus/tvc/hbf.c | 178 + src/devices/bus/tvc/hbf.h | 59 + src/devices/bus/tvc/tvc.c | 167 + src/devices/bus/tvc/tvc.h | 128 + src/devices/bus/vboy/rom.c | 61 + src/devices/bus/vboy/rom.h | 47 + src/devices/bus/vboy/slot.c | 273 + src/devices/bus/vboy/slot.h | 115 + src/devices/bus/vc4000/rom.c | 269 + src/devices/bus/vc4000/rom.h | 74 + src/devices/bus/vc4000/slot.c | 295 + src/devices/bus/vc4000/slot.h | 117 + src/devices/bus/vcs/compumat.c | 53 + src/devices/bus/vcs/compumat.h | 35 + src/devices/bus/vcs/dpc.c | 300 + src/devices/bus/vcs/dpc.h | 95 + src/devices/bus/vcs/rom.c | 1050 + src/devices/bus/vcs/rom.h | 391 + src/devices/bus/vcs/scharger.c | 214 + src/devices/bus/vcs/scharger.h | 47 + src/devices/bus/vcs/vcs_slot.c | 853 + src/devices/bus/vcs/vcs_slot.h | 160 + src/devices/bus/vcs_ctrl/ctrl.c | 83 + src/devices/bus/vcs_ctrl/ctrl.h | 124 + src/devices/bus/vcs_ctrl/joybooster.c | 95 + src/devices/bus/vcs_ctrl/joybooster.h | 59 + src/devices/bus/vcs_ctrl/joystick.c | 74 + src/devices/bus/vcs_ctrl/joystick.h | 51 + src/devices/bus/vcs_ctrl/keypad.c | 139 + src/devices/bus/vcs_ctrl/keypad.h | 59 + src/devices/bus/vcs_ctrl/lightpen.c | 85 + src/devices/bus/vcs_ctrl/lightpen.h | 55 + src/devices/bus/vcs_ctrl/paddles.c | 99 + src/devices/bus/vcs_ctrl/paddles.h | 58 + src/devices/bus/vcs_ctrl/wheel.c | 76 + src/devices/bus/vcs_ctrl/wheel.h | 52 + src/devices/bus/vectrex/rom.c | 88 + src/devices/bus/vectrex/rom.h | 67 + src/devices/bus/vectrex/slot.c | 278 + src/devices/bus/vectrex/slot.h | 115 + src/devices/bus/vic10/exp.c | 243 + src/devices/bus/vic10/exp.h | 184 + src/devices/bus/vic10/std.c | 78 + src/devices/bus/vic10/std.h | 47 + src/devices/bus/vic20/4cga.c | 113 + src/devices/bus/vic20/4cga.h | 66 + src/devices/bus/vic20/exp.c | 229 + src/devices/bus/vic20/exp.h | 172 + src/devices/bus/vic20/fe3.c | 638 + src/devices/bus/vic20/fe3.h | 94 + src/devices/bus/vic20/megacart.c | 130 + src/devices/bus/vic20/megacart.h | 60 + src/devices/bus/vic20/std.c | 69 + src/devices/bus/vic20/std.h | 46 + src/devices/bus/vic20/user.c | 22 + src/devices/bus/vic20/user.h | 33 + src/devices/bus/vic20/vic1010.c | 126 + src/devices/bus/vic20/vic1010.h | 69 + src/devices/bus/vic20/vic1011.c | 101 + src/devices/bus/vic20/vic1011.h | 57 + src/devices/bus/vic20/vic1110.c | 117 + src/devices/bus/vic20/vic1110.h | 54 + src/devices/bus/vic20/vic1111.c | 81 + src/devices/bus/vic20/vic1111.h | 50 + src/devices/bus/vic20/vic1112.c | 216 + src/devices/bus/vic20/vic1112.h | 72 + src/devices/bus/vic20/vic1210.c | 78 + src/devices/bus/vic20/vic1210.h | 51 + src/devices/bus/vidbrain/exp.c | 206 + src/devices/bus/vidbrain/exp.h | 169 + src/devices/bus/vidbrain/money_minder.c | 76 + src/devices/bus/vidbrain/money_minder.h | 46 + src/devices/bus/vidbrain/std.c | 62 + src/devices/bus/vidbrain/std.h | 45 + src/devices/bus/vidbrain/timeshare.c | 75 + src/devices/bus/vidbrain/timeshare.h | 46 + src/devices/bus/vip/byteio.c | 88 + src/devices/bus/vip/byteio.h | 133 + src/devices/bus/vip/exp.c | 217 + src/devices/bus/vip/exp.h | 167 + src/devices/bus/vip/vp550.c | 249 + src/devices/bus/vip/vp550.h | 66 + src/devices/bus/vip/vp570.c | 120 + src/devices/bus/vip/vp570.h | 54 + src/devices/bus/vip/vp575.c | 317 + src/devices/bus/vip/vp575.h | 96 + src/devices/bus/vip/vp585.c | 132 + src/devices/bus/vip/vp585.h | 56 + src/devices/bus/vip/vp590.c | 261 + src/devices/bus/vip/vp590.h | 71 + src/devices/bus/vip/vp595.c | 100 + src/devices/bus/vip/vp595.h | 53 + src/devices/bus/vip/vp620.c | 103 + src/devices/bus/vip/vp620.h | 57 + src/devices/bus/vip/vp700.c | 81 + src/devices/bus/vip/vp700.h | 52 + src/devices/bus/vtech/ioexp/carts.c | 14 + src/devices/bus/vtech/ioexp/carts.h | 21 + src/devices/bus/vtech/ioexp/ioexp.c | 91 + src/devices/bus/vtech/ioexp/ioexp.h | 87 + src/devices/bus/vtech/ioexp/joystick.c | 109 + src/devices/bus/vtech/ioexp/joystick.h | 50 + src/devices/bus/vtech/ioexp/printer.c | 93 + src/devices/bus/vtech/ioexp/printer.h | 52 + src/devices/bus/vtech/memexp/carts.c | 19 + src/devices/bus/vtech/memexp/carts.h | 23 + src/devices/bus/vtech/memexp/floppy.c | 298 + src/devices/bus/vtech/memexp/floppy.h | 66 + src/devices/bus/vtech/memexp/memexp.c | 108 + src/devices/bus/vtech/memexp/memexp.h | 125 + src/devices/bus/vtech/memexp/memory.c | 166 + src/devices/bus/vtech/memexp/memory.h | 94 + src/devices/bus/vtech/memexp/rs232.c | 104 + src/devices/bus/vtech/memexp/rs232.h | 50 + src/devices/bus/vtech/memexp/wordpro.c | 65 + src/devices/bus/vtech/memexp/wordpro.h | 39 + src/devices/bus/wangpc/emb.c | 175 + src/devices/bus/wangpc/emb.h | 55 + src/devices/bus/wangpc/lic.c | 159 + src/devices/bus/wangpc/lic.h | 53 + src/devices/bus/wangpc/lvc.c | 340 + src/devices/bus/wangpc/lvc.h | 68 + src/devices/bus/wangpc/mcc.c | 265 + src/devices/bus/wangpc/mcc.h | 60 + src/devices/bus/wangpc/mvc.c | 333 + src/devices/bus/wangpc/mvc.h | 68 + src/devices/bus/wangpc/rtc.c | 278 + src/devices/bus/wangpc/rtc.h | 66 + src/devices/bus/wangpc/tig.c | 324 + src/devices/bus/wangpc/tig.h | 69 + src/devices/bus/wangpc/wangpc.c | 278 + src/devices/bus/wangpc/wangpc.h | 228 + src/devices/bus/wangpc/wdc.c | 342 + src/devices/bus/wangpc/wdc.h | 81 + src/devices/bus/wswan/rom.c | 524 + src/devices/bus/wswan/rom.h | 105 + src/devices/bus/wswan/slot.c | 457 + src/devices/bus/wswan/slot.h | 131 + src/devices/bus/x68k/x68k_neptunex.c | 149 + src/devices/bus/x68k/x68k_neptunex.h | 54 + src/devices/bus/x68k/x68k_scsiext.c | 101 + src/devices/bus/x68k/x68k_scsiext.h | 46 + src/devices/bus/x68k/x68kexp.c | 79 + src/devices/bus/x68k/x68kexp.h | 149 + src/devices/bus/z88/flash.c | 94 + src/devices/bus/z88/flash.h | 46 + src/devices/bus/z88/ram.c | 110 + src/devices/bus/z88/ram.h | 85 + src/devices/bus/z88/rom.c | 89 + src/devices/bus/z88/rom.h | 70 + src/devices/bus/z88/z88.c | 212 + src/devices/bus/z88/z88.h | 138 + src/devices/cpu/8x300/8x300.c | 559 + src/devices/cpu/8x300/8x300.h | 136 + src/devices/cpu/8x300/8x300dasm.c | 151 + src/devices/cpu/adsp2100/2100dasm.c | 553 + src/devices/cpu/adsp2100/2100ops.inc | 2232 ++ src/devices/cpu/adsp2100/adsp2100.c | 1908 + src/devices/cpu/adsp2100/adsp2100.h | 586 + src/devices/cpu/alph8201/8201dasm.c | 404 + src/devices/cpu/alph8201/alph8201.c | 649 + src/devices/cpu/alph8201/alph8201.h | 408 + src/devices/cpu/alto2/a2curt.c | 88 + src/devices/cpu/alto2/a2curt.h | 28 + src/devices/cpu/alto2/a2dht.c | 67 + src/devices/cpu/alto2/a2dht.h | 27 + src/devices/cpu/alto2/a2disk.c | 1895 + src/devices/cpu/alto2/a2disk.h | 107 + src/devices/cpu/alto2/a2disp.c | 874 + src/devices/cpu/alto2/a2disp.h | 301 + src/devices/cpu/alto2/a2dvt.c | 46 + src/devices/cpu/alto2/a2dvt.h | 25 + src/devices/cpu/alto2/a2dwt.c | 62 + src/devices/cpu/alto2/a2dwt.h | 25 + src/devices/cpu/alto2/a2emu.c | 688 + src/devices/cpu/alto2/a2emu.h | 69 + src/devices/cpu/alto2/a2ether.c | 1380 + src/devices/cpu/alto2/a2ether.h | 116 + src/devices/cpu/alto2/a2hw.c | 422 + src/devices/cpu/alto2/a2hw.h | 66 + src/devices/cpu/alto2/a2jkff.h | 192 + src/devices/cpu/alto2/a2kbd.c | 63 + src/devices/cpu/alto2/a2kbd.h | 109 + src/devices/cpu/alto2/a2ksec.c | 54 + src/devices/cpu/alto2/a2ksec.h | 48 + src/devices/cpu/alto2/a2kwd.c | 52 + src/devices/cpu/alto2/a2kwd.h | 49 + src/devices/cpu/alto2/a2mem.c | 877 + src/devices/cpu/alto2/a2mem.h | 138 + src/devices/cpu/alto2/a2mouse.c | 271 + src/devices/cpu/alto2/a2mouse.h | 71 + src/devices/cpu/alto2/a2mrt.c | 45 + src/devices/cpu/alto2/a2mrt.h | 19 + src/devices/cpu/alto2/a2part.c | 30 + src/devices/cpu/alto2/a2part.h | 18 + src/devices/cpu/alto2/a2ram.c | 438 + src/devices/cpu/alto2/a2ram.h | 78 + src/devices/cpu/alto2/a2roms.c | 196 + src/devices/cpu/alto2/a2roms.h | 43 + src/devices/cpu/alto2/alto2cpu.c | 2816 ++ src/devices/cpu/alto2/alto2cpu.h | 946 + src/devices/cpu/alto2/alto2dsm.c | 390 + src/devices/cpu/am29000/am29000.c | 679 + src/devices/cpu/am29000/am29000.h | 660 + src/devices/cpu/am29000/am29dasm.c | 259 + src/devices/cpu/am29000/am29ops.h | 1716 + src/devices/cpu/amis2000/amis2000.c | 324 + src/devices/cpu/amis2000/amis2000.h | 244 + src/devices/cpu/amis2000/amis2000d.c | 133 + src/devices/cpu/amis2000/amis2000op.c | 524 + src/devices/cpu/apexc/apexc.c | 866 + src/devices/cpu/apexc/apexc.h | 94 + src/devices/cpu/apexc/apexcdsm.c | 184 + src/devices/cpu/arc/arc.c | 123 + src/devices/cpu/arc/arc.h | 75 + src/devices/cpu/arc/arcdasm.c | 224 + src/devices/cpu/arcompact/arcompact.c | 194 + src/devices/cpu/arcompact/arcompact.h | 891 + src/devices/cpu/arcompact/arcompact_common.c | 527 + src/devices/cpu/arcompact/arcompact_common.h | 24 + src/devices/cpu/arcompact/arcompact_execute.c | 3697 ++ src/devices/cpu/arcompact/arcompact_make.py | 434 + src/devices/cpu/arcompact/arcompactdasm.c | 92 + src/devices/cpu/arcompact/arcompactdasm_dispatch.c | 990 + src/devices/cpu/arcompact/arcompactdasm_dispatch.h | 50 + src/devices/cpu/arcompact/arcompactdasm_ops.c | 2370 ++ src/devices/cpu/arcompact/arcompactdasm_ops.h | 642 + src/devices/cpu/arm/arm.c | 1519 + src/devices/cpu/arm/arm.h | 124 + src/devices/cpu/arm/armdasm.c | 408 + src/devices/cpu/arm7/arm7.c | 1214 + src/devices/cpu/arm7/arm7.h | 566 + src/devices/cpu/arm7/arm7core.h | 534 + src/devices/cpu/arm7/arm7core.inc | 220 + src/devices/cpu/arm7/arm7dasm.c | 1331 + src/devices/cpu/arm7/arm7drc.inc | 1834 + src/devices/cpu/arm7/arm7help.h | 168 + src/devices/cpu/arm7/arm7ops.c | 1851 + src/devices/cpu/arm7/arm7tdrc.inc | 1593 + src/devices/cpu/arm7/arm7thmb.c | 1587 + src/devices/cpu/asap/asap.c | 1685 + src/devices/cpu/asap/asap.h | 276 + src/devices/cpu/asap/asapdasm.c | 144 + src/devices/cpu/avr8/avr8.c | 3930 +++ src/devices/cpu/avr8/avr8.h | 868 + src/devices/cpu/avr8/avr8dasm.c | 674 + src/devices/cpu/ccpu/ccpu.c | 689 + src/devices/cpu/ccpu/ccpu.h | 131 + src/devices/cpu/ccpu/ccpudasm.c | 330 + src/devices/cpu/cop400/cop400.c | 1239 + src/devices/cpu/cop400/cop400.h | 499 + src/devices/cpu/cop400/cop400op.inc | 1319 + src/devices/cpu/cop400/cop410ds.c | 349 + src/devices/cpu/cop400/cop420ds.c | 398 + src/devices/cpu/cop400/cop440ds.c | 415 + src/devices/cpu/cosmac/cosdasm.c | 197 + src/devices/cpu/cosmac/cosmac.c | 1247 + src/devices/cpu/cosmac/cosmac.h | 486 + src/devices/cpu/cp1610/1610dasm.c | 1490 + src/devices/cpu/cp1610/cp1610.c | 3423 ++ src/devices/cpu/cp1610/cp1610.h | 216 + src/devices/cpu/cubeqcpu/cubedasm.c | 306 + src/devices/cpu/cubeqcpu/cubeqcpu.c | 1542 + src/devices/cpu/cubeqcpu/cubeqcpu.h | 384 + src/devices/cpu/drcbec.c | 2278 ++ src/devices/cpu/drcbec.h | 59 + src/devices/cpu/drcbeut.c | 577 + src/devices/cpu/drcbeut.h | 166 + src/devices/cpu/drcbex64.c | 6711 ++++ src/devices/cpu/drcbex64.h | 345 + src/devices/cpu/drcbex86.c | 6589 ++++ src/devices/cpu/drcbex86.h | 346 + src/devices/cpu/drccache.c | 252 + src/devices/cpu/drccache.h | 114 + src/devices/cpu/drcfe.c | 378 + src/devices/cpu/drcfe.h | 164 + src/devices/cpu/drcuml.c | 1142 + src/devices/cpu/drcuml.h | 238 + src/devices/cpu/drcumlsh.h | 184 + src/devices/cpu/dsp16/dsp16.c | 453 + src/devices/cpu/dsp16/dsp16.h | 191 + src/devices/cpu/dsp16/dsp16dis.c | 583 + src/devices/cpu/dsp16/dsp16ops.inc | 937 + src/devices/cpu/dsp32/dsp32.c | 874 + src/devices/cpu/dsp32/dsp32.h | 439 + src/devices/cpu/dsp32/dsp32dis.c | 704 + src/devices/cpu/dsp32/dsp32ops.inc | 2846 ++ src/devices/cpu/dsp56k/dsp56def.h | 56 + src/devices/cpu/dsp56k/dsp56dsm.c | 30 + src/devices/cpu/dsp56k/dsp56k.c | 499 + src/devices/cpu/dsp56k/dsp56k.h | 259 + src/devices/cpu/dsp56k/dsp56mem.c | 948 + src/devices/cpu/dsp56k/dsp56mem.h | 241 + src/devices/cpu/dsp56k/dsp56ops.inc | 4922 +++ src/devices/cpu/dsp56k/dsp56pcu.c | 488 + src/devices/cpu/dsp56k/dsp56pcu.h | 150 + src/devices/cpu/dsp56k/inst.c | 785 + src/devices/cpu/dsp56k/inst.h | 3777 ++ src/devices/cpu/dsp56k/opcode.c | 80 + src/devices/cpu/dsp56k/opcode.h | 47 + src/devices/cpu/dsp56k/pmove.c | 79 + src/devices/cpu/dsp56k/pmove.h | 338 + src/devices/cpu/dsp56k/tables.c | 899 + src/devices/cpu/dsp56k/tables.h | 94 + src/devices/cpu/e0c6200/e0c6200.c | 837 + src/devices/cpu/e0c6200/e0c6200.h | 113 + src/devices/cpu/e0c6200/e0c6200d.c | 708 + src/devices/cpu/e0c6200/e0c6200op.inc | 241 + src/devices/cpu/e0c6200/e0c6s46.c | 893 + src/devices/cpu/e0c6200/e0c6s46.h | 182 + src/devices/cpu/e132xs/32xsdasm.c | 2142 ++ src/devices/cpu/e132xs/e132xs.c | 4980 +++ src/devices/cpu/e132xs/e132xs.h | 699 + src/devices/cpu/e132xs/e132xsop.inc | 1925 + src/devices/cpu/es5510/es5510.c | 1226 + src/devices/cpu/es5510/es5510.h | 195 + src/devices/cpu/esrip/esrip.c | 1985 ++ src/devices/cpu/esrip/esrip.h | 283 + src/devices/cpu/esrip/esripdsm.c | 95 + src/devices/cpu/f8/f8.c | 2074 ++ src/devices/cpu/f8/f8.h | 217 + src/devices/cpu/f8/f8dasm.c | 534 + src/devices/cpu/g65816/g65816.c | 1136 + src/devices/cpu/g65816/g65816.h | 1570 + src/devices/cpu/g65816/g65816cm.h | 262 + src/devices/cpu/g65816/g65816ds.c | 349 + src/devices/cpu/g65816/g65816ds.h | 22 + src/devices/cpu/g65816/g65816o0.c | 8 + src/devices/cpu/g65816/g65816o1.c | 8 + src/devices/cpu/g65816/g65816o2.c | 8 + src/devices/cpu/g65816/g65816o3.c | 8 + src/devices/cpu/g65816/g65816o4.c | 8 + src/devices/cpu/g65816/g65816op.h | 1961 ++ src/devices/cpu/h6280/6280dasm.c | 254 + src/devices/cpu/h6280/h6280.c | 2581 ++ src/devices/cpu/h6280/h6280.h | 377 + src/devices/cpu/h8/h8.c | 1523 + src/devices/cpu/h8/h8.h | 475 + src/devices/cpu/h8/h8.lst | 2811 ++ src/devices/cpu/h8/h83002.c | 219 + src/devices/cpu/h8/h83002.h | 67 + src/devices/cpu/h8/h83006.c | 271 + src/devices/cpu/h8/h83006.h | 80 + src/devices/cpu/h8/h83008.c | 226 + src/devices/cpu/h8/h83008.h | 71 + src/devices/cpu/h8/h83048.c | 286 + src/devices/cpu/h8/h83048.h | 99 + src/devices/cpu/h8/h83337.c | 247 + src/devices/cpu/h8/h83337.h | 94 + src/devices/cpu/h8/h8_adc.c | 501 + src/devices/cpu/h8/h8_adc.h | 177 + src/devices/cpu/h8/h8_intc.c | 385 + src/devices/cpu/h8/h8_intc.h | 120 + src/devices/cpu/h8/h8_port.c | 102 + src/devices/cpu/h8/h8_port.h | 53 + src/devices/cpu/h8/h8_sci.c | 692 + src/devices/cpu/h8/h8_sci.h | 147 + src/devices/cpu/h8/h8_timer16.c | 755 + src/devices/cpu/h8/h8_timer16.h | 207 + src/devices/cpu/h8/h8_timer8.c | 373 + src/devices/cpu/h8/h8_timer8.h | 113 + src/devices/cpu/h8/h8h.c | 18 + src/devices/cpu/h8/h8h.h | 109 + src/devices/cpu/h8/h8make.py | 474 + src/devices/cpu/h8/h8s2000.c | 17 + src/devices/cpu/h8/h8s2000.h | 51 + src/devices/cpu/h8/h8s2245.c | 347 + src/devices/cpu/h8/h8s2245.h | 102 + src/devices/cpu/h8/h8s2320.c | 456 + src/devices/cpu/h8/h8s2320.h | 143 + src/devices/cpu/h8/h8s2357.c | 427 + src/devices/cpu/h8/h8s2357.h | 122 + src/devices/cpu/h8/h8s2600.c | 16 + src/devices/cpu/h8/h8s2600.h | 39 + src/devices/cpu/h8/h8s2655.c | 434 + src/devices/cpu/h8/h8s2655.h | 88 + src/devices/cpu/hcd62121/hcd62121.c | 530 + src/devices/cpu/hcd62121/hcd62121.h | 100 + src/devices/cpu/hcd62121/hcd62121_ops.h | 1023 + src/devices/cpu/hcd62121/hcd62121d.c | 356 + src/devices/cpu/hd61700/hd61700.c | 2992 ++ src/devices/cpu/hd61700/hd61700.h | 171 + src/devices/cpu/hd61700/hd61700d.c | 439 + src/devices/cpu/hmcs40/hmcs40.c | 827 + src/devices/cpu/hmcs40/hmcs40.h | 475 + src/devices/cpu/hmcs40/hmcs40d.c | 232 + src/devices/cpu/hmcs40/hmcs40op.c | 681 + src/devices/cpu/hphybrid/hphybrid.c | 961 + src/devices/cpu/hphybrid/hphybrid.h | 146 + src/devices/cpu/hphybrid/hphybrid_dasm.c | 281 + src/devices/cpu/i386/cycles.h | 677 + src/devices/cpu/i386/i386.c | 4525 +++ src/devices/cpu/i386/i386.h | 1536 + src/devices/cpu/i386/i386dasm.c | 3126 ++ src/devices/cpu/i386/i386op16.inc | 3783 ++ src/devices/cpu/i386/i386op32.inc | 3585 ++ src/devices/cpu/i386/i386ops.h | 876 + src/devices/cpu/i386/i386ops.inc | 2540 ++ src/devices/cpu/i386/i386priv.h | 1410 + src/devices/cpu/i386/i486ops.inc | 516 + src/devices/cpu/i386/pentops.inc | 6654 ++++ src/devices/cpu/i386/x87ops.inc | 5113 +++ src/devices/cpu/i4004/4004dasm.c | 133 + src/devices/cpu/i4004/i4004.c | 529 + src/devices/cpu/i4004/i4004.h | 110 + src/devices/cpu/i8008/8008dasm.c | 115 + src/devices/cpu/i8008/i8008.c | 700 + src/devices/cpu/i8008/i8008.h | 103 + src/devices/cpu/i8085/8085dasm.c | 545 + src/devices/cpu/i8085/i8085.c | 1097 + src/devices/cpu/i8085/i8085.h | 181 + src/devices/cpu/i8085/i8085cpu.h | 188 + src/devices/cpu/i8089/i8089.c | 380 + src/devices/cpu/i8089/i8089.h | 158 + src/devices/cpu/i8089/i8089_channel.c | 848 + src/devices/cpu/i8089/i8089_channel.h | 224 + src/devices/cpu/i8089/i8089_dasm.c | 447 + src/devices/cpu/i8089/i8089_ops.c | 415 + src/devices/cpu/i86/i186.c | 1710 + src/devices/cpu/i86/i186.h | 151 + src/devices/cpu/i86/i286.c | 1989 ++ src/devices/cpu/i86/i286.h | 164 + src/devices/cpu/i86/i86.c | 2403 ++ src/devices/cpu/i86/i86.h | 371 + src/devices/cpu/i86/i86.txt | 111 + src/devices/cpu/i86/i86inline.h | 980 + src/devices/cpu/i860/i860.c | 237 + src/devices/cpu/i860/i860.h | 318 + src/devices/cpu/i860/i860dasm.c | 378 + src/devices/cpu/i860/i860dec.inc | 4687 +++ src/devices/cpu/i860/i860dis.c | 697 + src/devices/cpu/i960/i960.c | 2122 ++ src/devices/cpu/i960/i960.h | 177 + src/devices/cpu/i960/i960dis.c | 306 + src/devices/cpu/i960/i960dis.h | 15 + src/devices/cpu/ie15/ie15.c | 469 + src/devices/cpu/ie15/ie15.h | 92 + src/devices/cpu/ie15/ie15dasm.c | 126 + src/devices/cpu/jaguar/jagdasm.c | 196 + src/devices/cpu/jaguar/jaguar.c | 1452 + src/devices/cpu/jaguar/jaguar.h | 278 + src/devices/cpu/lc8670/lc8670.c | 1777 + src/devices/cpu/lc8670/lc8670.h | 276 + src/devices/cpu/lc8670/lc8670dsm.c | 178 + src/devices/cpu/lh5801/5801dasm.c | 725 + src/devices/cpu/lh5801/5801tbl.inc | 689 + src/devices/cpu/lh5801/lh5801.c | 254 + src/devices/cpu/lh5801/lh5801.h | 188 + src/devices/cpu/lr35902/lr35902.c | 354 + src/devices/cpu/lr35902/lr35902.h | 128 + src/devices/cpu/lr35902/lr35902d.c | 277 + src/devices/cpu/lr35902/opc_cb.inc | 1539 + src/devices/cpu/lr35902/opc_main.inc | 1429 + src/devices/cpu/m37710/m37710.c | 1215 + src/devices/cpu/m37710/m37710.h | 2051 ++ src/devices/cpu/m37710/m37710cm.h | 410 + src/devices/cpu/m37710/m37710il.h | 208 + src/devices/cpu/m37710/m37710o0.c | 8 + src/devices/cpu/m37710/m37710o1.c | 8 + src/devices/cpu/m37710/m37710o2.c | 8 + src/devices/cpu/m37710/m37710o3.c | 8 + src/devices/cpu/m37710/m37710op.h | 2608 ++ src/devices/cpu/m37710/m7700ds.c | 617 + src/devices/cpu/m37710/m7700ds.h | 23 + src/devices/cpu/m6502/ddeco16.lst | 18 + src/devices/cpu/m6502/deco16.c | 53 + src/devices/cpu/m6502/deco16.h | 62 + src/devices/cpu/m6502/dm4510.lst | 18 + src/devices/cpu/m6502/dm6502.lst | 18 + src/devices/cpu/m6502/dm6509.lst | 18 + src/devices/cpu/m6502/dm6510.lst | 18 + src/devices/cpu/m6502/dm65c02.lst | 18 + src/devices/cpu/m6502/dm65ce02.lst | 18 + src/devices/cpu/m6502/dm740.lst | 34 + src/devices/cpu/m6502/dn2a03.lst | 18 + src/devices/cpu/m6502/dr65c02.lst | 18 + src/devices/cpu/m6502/m3745x.c | 503 + src/devices/cpu/m6502/m3745x.h | 157 + src/devices/cpu/m6502/m4510.c | 106 + src/devices/cpu/m6502/m4510.h | 82 + src/devices/cpu/m6502/m5074x.c | 507 + src/devices/cpu/m6502/m5074x.h | 147 + src/devices/cpu/m6502/m6502.c | 724 + src/devices/cpu/m6502/m6502.h | 335 + src/devices/cpu/m6502/m6502.txt | 163 + src/devices/cpu/m6502/m6502make.py | 280 + src/devices/cpu/m6502/m6504.c | 61 + src/devices/cpu/m6502/m6504.h | 49 + src/devices/cpu/m6502/m6509.c | 148 + src/devices/cpu/m6502/m6509.h | 87 + src/devices/cpu/m6502/m6510.c | 175 + src/devices/cpu/m6502/m6510.h | 99 + src/devices/cpu/m6502/m6510t.c | 19 + src/devices/cpu/m6502/m6510t.h | 34 + src/devices/cpu/m6502/m65c02.c | 32 + src/devices/cpu/m6502/m65c02.h | 76 + src/devices/cpu/m6502/m65ce02.c | 98 + src/devices/cpu/m6502/m65ce02.h | 153 + src/devices/cpu/m6502/m65sc02.c | 19 + src/devices/cpu/m6502/m65sc02.h | 29 + src/devices/cpu/m6502/m740.c | 243 + src/devices/cpu/m6502/m740.h | 105 + src/devices/cpu/m6502/m7501.c | 19 + src/devices/cpu/m6502/m7501.h | 34 + src/devices/cpu/m6502/m8502.c | 19 + src/devices/cpu/m6502/m8502.h | 34 + src/devices/cpu/m6502/n2a03.c | 76 + src/devices/cpu/m6502/n2a03.h | 70 + src/devices/cpu/m6502/odeco16.lst | 101 + src/devices/cpu/m6502/om4510.lst | 21 + src/devices/cpu/m6502/om6502.lst | 1964 ++ src/devices/cpu/m6502/om6509.lst | 20 + src/devices/cpu/m6502/om6510.lst | 46 + src/devices/cpu/m6502/om65c02.lst | 584 + src/devices/cpu/m6502/om65ce02.lst | 1533 + src/devices/cpu/m6502/om740.lst | 749 + src/devices/cpu/m6502/on2a03.lst | 297 + src/devices/cpu/m6502/r65c02.c | 31 + src/devices/cpu/m6502/r65c02.h | 36 + src/devices/cpu/m6800/6800dasm.c | 282 + src/devices/cpu/m6800/6800ops.inc | 2284 ++ src/devices/cpu/m6800/6800tbl.inc | 140 + src/devices/cpu/m6800/m6800.c | 1817 + src/devices/cpu/m6800/m6800.h | 545 + src/devices/cpu/m68000/m68000.h | 808 + src/devices/cpu/m68000/m68k_in.c | 10546 ++++++ src/devices/cpu/m68000/m68kcpu.c | 2815 ++ src/devices/cpu/m68000/m68kcpu.h | 1698 + src/devices/cpu/m68000/m68kdasm.c | 4157 +++ src/devices/cpu/m68000/m68kfpu.inc | 2204 ++ src/devices/cpu/m68000/m68kmake.c | 1423 + src/devices/cpu/m68000/m68kmmu.h | 1148 + src/devices/cpu/m68000/m68kops.c | 34886 +++++++++++++++++++ src/devices/cpu/m68000/m68kops.h | 1995 ++ src/devices/cpu/m68000/makefile | 31 + src/devices/cpu/m6805/6805dasm.c | 214 + src/devices/cpu/m6805/6805ops.inc | 1806 + src/devices/cpu/m6805/m6805.c | 1003 + src/devices/cpu/m6805/m6805.h | 418 + src/devices/cpu/m6809/6309dasm.c | 943 + src/devices/cpu/m6809/6809dasm.c | 616 + src/devices/cpu/m6809/base6x09.ops | 537 + src/devices/cpu/m6809/hd6309.c | 812 + src/devices/cpu/m6809/hd6309.h | 148 + src/devices/cpu/m6809/hd6309.ops | 1085 + src/devices/cpu/m6809/knmidasm.c | 1877 + src/devices/cpu/m6809/konami.c | 380 + src/devices/cpu/m6809/konami.h | 81 + src/devices/cpu/m6809/konami.ops | 605 + src/devices/cpu/m6809/m6809.c | 608 + src/devices/cpu/m6809/m6809.h | 318 + src/devices/cpu/m6809/m6809.ops | 581 + src/devices/cpu/m6809/m6809inl.h | 273 + src/devices/cpu/m6809/m6809make.py | 125 + src/devices/cpu/mb86233/mb86233.c | 1655 + src/devices/cpu/mb86233/mb86233.h | 145 + src/devices/cpu/mb86233/mb86233d.c | 784 + src/devices/cpu/mb86235/mb86235.c | 129 + src/devices/cpu/mb86235/mb86235.h | 70 + src/devices/cpu/mb86235/mb86235d.c | 144 + src/devices/cpu/mb88xx/mb88dasm.c | 224 + src/devices/cpu/mb88xx/mb88xx.c | 974 + src/devices/cpu/mb88xx/mb88xx.h | 217 + src/devices/cpu/mc68hc11/hc11dasm.c | 1299 + src/devices/cpu/mc68hc11/hc11ops.h | 319 + src/devices/cpu/mc68hc11/hc11ops.inc | 3592 ++ src/devices/cpu/mc68hc11/mc68hc11.c | 599 + src/devices/cpu/mc68hc11/mc68hc11.h | 443 + src/devices/cpu/mcs48/mcs48.c | 1334 + src/devices/cpu/mcs48/mcs48.h | 643 + src/devices/cpu/mcs48/mcs48dsm.c | 313 + src/devices/cpu/mcs51/mcs51.c | 2514 ++ src/devices/cpu/mcs51/mcs51.h | 518 + src/devices/cpu/mcs51/mcs51dasm.c | 1213 + src/devices/cpu/mcs51/mcs51ops.inc | 980 + src/devices/cpu/mcs96/i8x9x.c | 373 + src/devices/cpu/mcs96/i8x9x.h | 98 + src/devices/cpu/mcs96/i8xc196.c | 76 + src/devices/cpu/mcs96/i8xc196.h | 46 + src/devices/cpu/mcs96/mcs96.c | 751 + src/devices/cpu/mcs96/mcs96.h | 256 + src/devices/cpu/mcs96/mcs96make.py | 196 + src/devices/cpu/mcs96/mcs96ops.lst | 1852 + src/devices/cpu/melps4/m58846.c | 213 + src/devices/cpu/melps4/m58846.h | 46 + src/devices/cpu/melps4/melps4.c | 440 + src/devices/cpu/melps4/melps4.h | 366 + src/devices/cpu/melps4/melps4d.c | 141 + src/devices/cpu/melps4/melps4op.c | 699 + src/devices/cpu/minx/minx.c | 234 + src/devices/cpu/minx/minx.h | 121 + src/devices/cpu/minx/minxd.c | 465 + src/devices/cpu/minx/minxfunc.h | 364 + src/devices/cpu/minx/minxopce.h | 563 + src/devices/cpu/minx/minxopcf.h | 563 + src/devices/cpu/minx/minxops.h | 563 + src/devices/cpu/mips/mips3.c | 3079 ++ src/devices/cpu/mips/mips3.h | 781 + src/devices/cpu/mips/mips3com.c | 433 + src/devices/cpu/mips/mips3com.h | 191 + src/devices/cpu/mips/mips3drc.c | 3310 ++ src/devices/cpu/mips/mips3dsm.c | 548 + src/devices/cpu/mips/mips3fe.c | 741 + src/devices/cpu/mips/mips3fe.h | 33 + src/devices/cpu/mips/r3000.c | 1347 + src/devices/cpu/mips/r3000.h | 319 + src/devices/cpu/mips/r3kdasm.c | 389 + src/devices/cpu/mn10200/mn10200.c | 2230 ++ src/devices/cpu/mn10200/mn10200.h | 218 + src/devices/cpu/mn10200/mn102dis.c | 1038 + src/devices/cpu/nec/nec.c | 541 + src/devices/cpu/nec/nec.h | 433 + src/devices/cpu/nec/necdasm.c | 1603 + src/devices/cpu/nec/necea.h | 59 + src/devices/cpu/nec/necinstr.h | 262 + src/devices/cpu/nec/necinstr.inc | 673 + src/devices/cpu/nec/necmacro.h | 269 + src/devices/cpu/nec/necmodrm.h | 106 + src/devices/cpu/nec/necpriv.h | 131 + src/devices/cpu/nec/v25.c | 751 + src/devices/cpu/nec/v25.h | 458 + src/devices/cpu/nec/v25instr.h | 261 + src/devices/cpu/nec/v25instr.inc | 84 + src/devices/cpu/nec/v25priv.h | 192 + src/devices/cpu/nec/v25sfr.c | 403 + src/devices/cpu/nec/v53.c | 578 + src/devices/cpu/nec/v53.h | 309 + src/devices/cpu/pdp1/pdp1.c | 1818 + src/devices/cpu/pdp1/pdp1.h | 199 + src/devices/cpu/pdp1/pdp1dasm.c | 294 + src/devices/cpu/pdp1/tx0.c | 1080 + src/devices/cpu/pdp1/tx0.h | 179 + src/devices/cpu/pdp1/tx0dasm.c | 123 + src/devices/cpu/pdp8/pdp8.c | 249 + src/devices/cpu/pdp8/pdp8.h | 113 + src/devices/cpu/pdp8/pdp8dasm.c | 174 + src/devices/cpu/pic16c5x/16c5xdsm.c | 256 + src/devices/cpu/pic16c5x/dis16c5x.c | 136 + src/devices/cpu/pic16c5x/pic16c5x.c | 1123 + src/devices/cpu/pic16c5x/pic16c5x.h | 275 + src/devices/cpu/pic16c62x/16c62xdsm.c | 267 + src/devices/cpu/pic16c62x/dis16c62x.c | 138 + src/devices/cpu/pic16c62x/pic16c62x.c | 1189 + src/devices/cpu/pic16c62x/pic16c62x.h | 265 + src/devices/cpu/powerpc/drc_ops.c | 3800 ++ src/devices/cpu/powerpc/drc_ops.h | 145 + src/devices/cpu/powerpc/ppc.c | 2135 ++ src/devices/cpu/powerpc/ppc.h | 811 + src/devices/cpu/powerpc/ppc403.inc | 947 + src/devices/cpu/powerpc/ppc602.inc | 279 + src/devices/cpu/powerpc/ppc603.inc | 285 + src/devices/cpu/powerpc/ppc_dasm.c | 1177 + src/devices/cpu/powerpc/ppc_mem.inc | 421 + src/devices/cpu/powerpc/ppc_ops.h | 152 + src/devices/cpu/powerpc/ppc_ops.inc | 2810 ++ src/devices/cpu/powerpc/ppccom.c | 2879 ++ src/devices/cpu/powerpc/ppccom.h | 480 + src/devices/cpu/powerpc/ppcdrc.c | 3923 +++ src/devices/cpu/powerpc/ppcfe.c | 1393 + src/devices/cpu/powerpc/ppcfe.h | 77 + src/devices/cpu/pps4/pps4.c | 1587 + src/devices/cpu/pps4/pps4.h | 167 + src/devices/cpu/pps4/pps4dasm.c | 443 + src/devices/cpu/psx/dismips.c | 361 + src/devices/cpu/psx/dismips.mak | 2 + src/devices/cpu/psx/dma.c | 424 + src/devices/cpu/psx/dma.h | 76 + src/devices/cpu/psx/gte.c | 946 + src/devices/cpu/psx/gte.h | 110 + src/devices/cpu/psx/irq.c | 207 + src/devices/cpu/psx/irq.h | 60 + src/devices/cpu/psx/mdec.c | 572 + src/devices/cpu/psx/mdec.h | 76 + src/devices/cpu/psx/psx.c | 3417 ++ src/devices/cpu/psx/psx.h | 533 + src/devices/cpu/psx/psxdasm.c | 680 + src/devices/cpu/psx/rcnt.c | 261 + src/devices/cpu/psx/rcnt.h | 76 + src/devices/cpu/psx/sio.c | 360 + src/devices/cpu/psx/sio.h | 114 + src/devices/cpu/rsp/clamp.h | 37 + src/devices/cpu/rsp/rsp.c | 809 + src/devices/cpu/rsp/rsp.h | 333 + src/devices/cpu/rsp/rsp_dasm.c | 355 + src/devices/cpu/rsp/rspcp2.c | 4222 +++ src/devices/cpu/rsp/rspcp2.h | 396 + src/devices/cpu/rsp/rspcp2d.c | 3736 ++ src/devices/cpu/rsp/rspcp2d.h | 109 + src/devices/cpu/rsp/rspdiv.h | 1029 + src/devices/cpu/rsp/rspdrc.c | 1292 + src/devices/cpu/rsp/rspfe.c | 306 + src/devices/cpu/rsp/rspfe.h | 56 + src/devices/cpu/rsp/vabs.h | 15 + src/devices/cpu/rsp/vadd.h | 16 + src/devices/cpu/rsp/vaddc.h | 13 + src/devices/cpu/rsp/vand.h | 9 + src/devices/cpu/rsp/vch.h | 57 + src/devices/cpu/rsp/vcl.h | 65 + src/devices/cpu/rsp/vcmp.h | 49 + src/devices/cpu/rsp/vcr.h | 35 + src/devices/cpu/rsp/vdivh.h | 12 + src/devices/cpu/rsp/vldst.h | 69 + src/devices/cpu/rsp/vmac.h | 57 + src/devices/cpu/rsp/vmov.h | 9 + src/devices/cpu/rsp/vmrg.h | 13 + src/devices/cpu/rsp/vmudh.h | 10 + src/devices/cpu/rsp/vmul.h | 39 + src/devices/cpu/rsp/vmulh.h | 30 + src/devices/cpu/rsp/vmull.h | 44 + src/devices/cpu/rsp/vmulm.h | 56 + src/devices/cpu/rsp/vmuln.h | 55 + src/devices/cpu/rsp/vor.h | 10 + src/devices/cpu/rsp/vrcpsq.h | 58 + src/devices/cpu/rsp/vrsq.h | 66 + src/devices/cpu/rsp/vsub.h | 17 + src/devices/cpu/rsp/vsubc.h | 14 + src/devices/cpu/rsp/vxor.h | 10 + src/devices/cpu/s2650/2650dasm.c | 868 + src/devices/cpu/s2650/s2650.c | 1576 + src/devices/cpu/s2650/s2650.h | 111 + src/devices/cpu/s2650/s2650cpu.h | 33 + src/devices/cpu/saturn/satops.inc | 1151 + src/devices/cpu/saturn/sattable.inc | 1039 + src/devices/cpu/saturn/saturn.c | 410 + src/devices/cpu/saturn/saturn.h | 295 + src/devices/cpu/saturn/saturnds.c | 1470 + src/devices/cpu/sc61860/readpc.c | 196 + src/devices/cpu/sc61860/sc61860.c | 253 + src/devices/cpu/sc61860/sc61860.h | 236 + src/devices/cpu/sc61860/scdasm.c | 210 + src/devices/cpu/sc61860/scops.inc | 760 + src/devices/cpu/sc61860/sctable.inc | 145 + src/devices/cpu/scmp/scmp.c | 566 + src/devices/cpu/scmp/scmp.h | 120 + src/devices/cpu/scmp/scmpdasm.c | 153 + src/devices/cpu/score/score.c | 1351 + src/devices/cpu/score/score.h | 150 + src/devices/cpu/score/scoredsm.c | 294 + src/devices/cpu/score/scorem.h | 146 + src/devices/cpu/scudsp/scudsp.c | 1039 + src/devices/cpu/scudsp/scudsp.h | 164 + src/devices/cpu/scudsp/scudspdasm.c | 364 + src/devices/cpu/se3208/se3208.c | 1833 + src/devices/cpu/se3208/se3208.h | 169 + src/devices/cpu/se3208/se3208dis.c | 1413 + src/devices/cpu/sh2/sh2.c | 2685 ++ src/devices/cpu/sh2/sh2.h | 569 + src/devices/cpu/sh2/sh2comn.c | 1027 + src/devices/cpu/sh2/sh2comn.h | 85 + src/devices/cpu/sh2/sh2dasm.c | 610 + src/devices/cpu/sh2/sh2drc.c | 2983 ++ src/devices/cpu/sh2/sh2fe.c | 762 + src/devices/cpu/sh4/sh3comn.c | 681 + src/devices/cpu/sh4/sh3comn.h | 96 + src/devices/cpu/sh4/sh4.c | 4608 +++ src/devices/cpu/sh4/sh4.h | 803 + src/devices/cpu/sh4/sh4comn.c | 1238 + src/devices/cpu/sh4/sh4comn.h | 174 + src/devices/cpu/sh4/sh4dasm.c | 824 + src/devices/cpu/sh4/sh4dmac.c | 666 + src/devices/cpu/sh4/sh4dmac.h | 65 + src/devices/cpu/sh4/sh4regs.h | 183 + src/devices/cpu/sh4/sh4tmu.c | 324 + src/devices/cpu/sh4/sh4tmu.h | 3 + src/devices/cpu/sharc/compute.inc | 1400 + src/devices/cpu/sharc/sharc.c | 960 + src/devices/cpu/sharc/sharc.h | 358 + src/devices/cpu/sharc/sharcdma.inc | 246 + src/devices/cpu/sharc/sharcdsm.c | 1220 + src/devices/cpu/sharc/sharcdsm.h | 79 + src/devices/cpu/sharc/sharcmem.inc | 204 + src/devices/cpu/sharc/sharcops.h | 134 + src/devices/cpu/sharc/sharcops.inc | 2767 ++ src/devices/cpu/sm510/sm510.c | 376 + src/devices/cpu/sm510/sm510.h | 307 + src/devices/cpu/sm510/sm510core.c | 136 + src/devices/cpu/sm510/sm510d.c | 215 + src/devices/cpu/sm510/sm510op.c | 456 + src/devices/cpu/sm510/sm511core.c | 162 + src/devices/cpu/sm8500/sm8500.c | 428 + src/devices/cpu/sm8500/sm8500.h | 118 + src/devices/cpu/sm8500/sm8500d.c | 583 + src/devices/cpu/sm8500/sm85ops.h | 1691 + src/devices/cpu/spc700/spc700.c | 1692 + src/devices/cpu/spc700/spc700.h | 141 + src/devices/cpu/spc700/spc700ds.c | 437 + src/devices/cpu/spc700/spc700ds.h | 24 + src/devices/cpu/ssem/ssem.c | 316 + src/devices/cpu/ssem/ssem.h | 86 + src/devices/cpu/ssem/ssemdasm.c | 87 + src/devices/cpu/ssp1601/ssp1601.c | 781 + src/devices/cpu/ssp1601/ssp1601.h | 107 + src/devices/cpu/ssp1601/ssp1601d.c | 298 + src/devices/cpu/superfx/sfx_dasm.c | 425 + src/devices/cpu/superfx/superfx.c | 1447 + src/devices/cpu/superfx/superfx.h | 217 + src/devices/cpu/t11/t11.c | 426 + src/devices/cpu/t11/t11.h | 1156 + src/devices/cpu/t11/t11dasm.c | 518 + src/devices/cpu/t11/t11ops.inc | 1414 + src/devices/cpu/t11/t11table.inc | 1322 + src/devices/cpu/tlcs90/tlcs90.c | 2786 ++ src/devices/cpu/tlcs90/tlcs90.h | 181 + src/devices/cpu/tlcs900/900tbl.inc | 6036 ++++ src/devices/cpu/tlcs900/dasm900.c | 2258 ++ src/devices/cpu/tlcs900/tlcs900.c | 2202 ++ src/devices/cpu/tlcs900/tlcs900.h | 840 + src/devices/cpu/tms0980/tms0980.c | 1441 + src/devices/cpu/tms0980/tms0980.h | 472 + src/devices/cpu/tms0980/tms0980d.c | 343 + src/devices/cpu/tms32010/32010dsm.c | 338 + src/devices/cpu/tms32010/dis32010.c | 138 + src/devices/cpu/tms32010/tms32010.c | 987 + src/devices/cpu/tms32010/tms32010.h | 222 + src/devices/cpu/tms32025/32025dsm.c | 507 + src/devices/cpu/tms32025/dis32025.c | 137 + src/devices/cpu/tms32025/tms32025.c | 2282 ++ src/devices/cpu/tms32025/tms32025.h | 368 + src/devices/cpu/tms32031/32031ops.c | 6890 ++++ src/devices/cpu/tms32031/dis32031.c | 745 + src/devices/cpu/tms32031/tms32031.c | 849 + src/devices/cpu/tms32031/tms32031.h | 817 + src/devices/cpu/tms32051/32051ops.c | 1820 + src/devices/cpu/tms32051/32051ops.h | 253 + src/devices/cpu/tms32051/dis32051.c | 644 + src/devices/cpu/tms32051/tms32051.c | 531 + src/devices/cpu/tms32051/tms32051.h | 371 + src/devices/cpu/tms32082/dis_mp.c | 513 + src/devices/cpu/tms32082/dis_pp.c | 714 + src/devices/cpu/tms32082/mp_ops.c | 1821 + src/devices/cpu/tms32082/tms32082.c | 597 + src/devices/cpu/tms32082/tms32082.h | 214 + src/devices/cpu/tms34010/34010dsm.c | 1761 + src/devices/cpu/tms34010/34010fld.c | 681 + src/devices/cpu/tms34010/34010gfx.c | 1972 ++ src/devices/cpu/tms34010/34010ops.c | 2460 ++ src/devices/cpu/tms34010/34010ops.h | 154 + src/devices/cpu/tms34010/34010tbl.c | 782 + src/devices/cpu/tms34010/dis34010.c | 115 + src/devices/cpu/tms34010/makefile | 6 + src/devices/cpu/tms34010/tms34010.c | 1644 + src/devices/cpu/tms34010/tms34010.h | 1074 + src/devices/cpu/tms57002/57002dsm.c | 95 + src/devices/cpu/tms57002/tms57002.c | 917 + src/devices/cpu/tms57002/tms57002.h | 219 + src/devices/cpu/tms57002/tms57kdec.c | 151 + src/devices/cpu/tms57002/tmsinstr.lst | 536 + src/devices/cpu/tms57002/tmsmake.py | 435 + src/devices/cpu/tms7000/7000dasm.c | 448 + src/devices/cpu/tms7000/tms7000.c | 950 + src/devices/cpu/tms7000/tms7000.h | 366 + src/devices/cpu/tms7000/tms70op.inc | 716 + src/devices/cpu/tms9900/9900dasm.c | 812 + src/devices/cpu/tms9900/99xxcore.h | 5319 +++ src/devices/cpu/tms9900/ti990_10.c | 148 + src/devices/cpu/tms9900/ti990_10.h | 61 + src/devices/cpu/tms9900/tms9900.c | 2736 ++ src/devices/cpu/tms9900/tms9900.h | 403 + src/devices/cpu/tms9900/tms9980a.c | 300 + src/devices/cpu/tms9900/tms9980a.h | 56 + src/devices/cpu/tms9900/tms9995.c | 3466 ++ src/devices/cpu/tms9900/tms9995.h | 446 + src/devices/cpu/tms9900/tms99com.h | 93 + src/devices/cpu/ucom4/ucom4.c | 484 + src/devices/cpu/ucom4/ucom4.h | 354 + src/devices/cpu/ucom4/ucom4d.c | 153 + src/devices/cpu/ucom4/ucom4op.c | 719 + src/devices/cpu/uml.c | 1029 + src/devices/cpu/uml.h | 661 + src/devices/cpu/unsp/unsp.c | 867 + src/devices/cpu/unsp/unsp.h | 113 + src/devices/cpu/unsp/unspdasm.c | 272 + src/devices/cpu/upd7725/dasm7725.c | 234 + src/devices/cpu/upd7725/upd7725.c | 622 + src/devices/cpu/upd7725/upd7725.h | 264 + src/devices/cpu/upd7810/upd7810.c | 1984 ++ src/devices/cpu/upd7810/upd7810.h | 1430 + src/devices/cpu/upd7810/upd7810_dasm.c | 5465 +++ src/devices/cpu/upd7810/upd7810_macros.h | 148 + src/devices/cpu/upd7810/upd7810_opcodes.c | 9485 +++++ src/devices/cpu/upd7810/upd7810_table.c | 6252 ++++ src/devices/cpu/v30mz/v30mz.c | 3732 ++ src/devices/cpu/v30mz/v30mz.h | 226 + src/devices/cpu/v60/am.inc | 83 + src/devices/cpu/v60/am1.inc | 1385 + src/devices/cpu/v60/am2.inc | 1254 + src/devices/cpu/v60/am3.inc | 885 + src/devices/cpu/v60/op12.inc | 2393 ++ src/devices/cpu/v60/op2.inc | 354 + src/devices/cpu/v60/op3.inc | 641 + src/devices/cpu/v60/op4.inc | 354 + src/devices/cpu/v60/op5.inc | 87 + src/devices/cpu/v60/op6.inc | 254 + src/devices/cpu/v60/op7a.inc | 1212 + src/devices/cpu/v60/optable.inc | 261 + src/devices/cpu/v60/v60.c | 619 + src/devices/cpu/v60/v60.h | 794 + src/devices/cpu/v60/v60d.c | 1499 + src/devices/cpu/v810/v810.c | 1395 + src/devices/cpu/v810/v810.h | 204 + src/devices/cpu/v810/v810dasm.c | 177 + src/devices/cpu/vtlb.c | 310 + src/devices/cpu/vtlb.h | 88 + src/devices/cpu/x86emit.h | 3188 ++ src/devices/cpu/x86log.c | 300 + src/devices/cpu/x86log.h | 50 + src/devices/cpu/z180/z180.c | 2579 ++ src/devices/cpu/z180/z180.h | 1788 + src/devices/cpu/z180/z180cb.inc | 293 + src/devices/cpu/z180/z180dasm.c | 518 + src/devices/cpu/z180/z180dd.inc | 297 + src/devices/cpu/z180/z180ed.inc | 298 + src/devices/cpu/z180/z180fd.inc | 292 + src/devices/cpu/z180/z180op.inc | 382 + src/devices/cpu/z180/z180ops.h | 940 + src/devices/cpu/z180/z180tbl.h | 232 + src/devices/cpu/z180/z180xy.inc | 293 + src/devices/cpu/z8/z8.c | 845 + src/devices/cpu/z8/z8.h | 326 + src/devices/cpu/z8/z8dasm.c | 380 + src/devices/cpu/z8/z8ops.inc | 745 + src/devices/cpu/z80/kl5c80a12.c | 54 + src/devices/cpu/z80/kl5c80a12.h | 62 + src/devices/cpu/z80/tmpz84c011.c | 124 + src/devices/cpu/z80/tmpz84c011.h | 179 + src/devices/cpu/z80/tmpz84c015.c | 217 + src/devices/cpu/z80/tmpz84c015.h | 273 + src/devices/cpu/z80/z80.c | 3745 ++ src/devices/cpu/z80/z80.h | 310 + src/devices/cpu/z80/z80daisy.c | 179 + src/devices/cpu/z80/z80daisy.h | 89 + src/devices/cpu/z80/z80dasm.c | 532 + src/devices/cpu/z8000/8000dasm.c | 355 + src/devices/cpu/z8000/makedab.c | 89 + src/devices/cpu/z8000/z8000.c | 808 + src/devices/cpu/z8000/z8000.h | 678 + src/devices/cpu/z8000/z8000cpu.h | 203 + src/devices/cpu/z8000/z8000dab.h | 277 + src/devices/cpu/z8000/z8000ops.inc | 6811 ++++ src/devices/cpu/z8000/z8000tbl.inc | 579 + src/devices/imagedev/bitbngr.c | 103 + src/devices/imagedev/bitbngr.h | 46 + src/devices/imagedev/cassette.c | 429 + src/devices/imagedev/cassette.h | 142 + src/devices/imagedev/chd_cd.c | 143 + src/devices/imagedev/chd_cd.h | 77 + src/devices/imagedev/diablo.c | 274 + src/devices/imagedev/diablo.h | 90 + src/devices/imagedev/flopdrv.c | 898 + src/devices/imagedev/flopdrv.h | 266 + src/devices/imagedev/floppy.c | 2132 ++ src/devices/imagedev/floppy.h | 357 + src/devices/imagedev/harddriv.c | 298 + src/devices/imagedev/harddriv.h | 94 + src/devices/imagedev/mfmhd.c | 1176 + src/devices/imagedev/mfmhd.h | 250 + src/devices/imagedev/midiin.c | 176 + src/devices/imagedev/midiin.h | 79 + src/devices/imagedev/midiout.c | 104 + src/devices/imagedev/midiout.h | 74 + src/devices/imagedev/printer.c | 110 + src/devices/imagedev/printer.h | 65 + src/devices/imagedev/snapquik.c | 96 + src/devices/imagedev/snapquik.h | 103 + src/devices/machine/40105.c | 172 + src/devices/machine/40105.h | 80 + src/devices/machine/53c7xx.c | 1776 + src/devices/machine/53c7xx.h | 229 + src/devices/machine/53c810.c | 816 + src/devices/machine/53c810.h | 119 + src/devices/machine/64h156.c | 652 + src/devices/machine/64h156.h | 205 + src/devices/machine/6522via.c | 985 + src/devices/machine/6522via.h | 221 + src/devices/machine/6525tpi.c | 561 + src/devices/machine/6525tpi.h | 154 + src/devices/machine/6532riot.c | 483 + src/devices/machine/6532riot.h | 127 + src/devices/machine/6821pia.c | 1121 + src/devices/machine/6821pia.h | 233 + src/devices/machine/68230pit.c | 265 + src/devices/machine/68230pit.h | 131 + src/devices/machine/68307.c | 352 + src/devices/machine/68307.h | 132 + src/devices/machine/68307bus.c | 112 + src/devices/machine/68307bus.h | 22 + src/devices/machine/68307sim.c | 314 + src/devices/machine/68307sim.h | 74 + src/devices/machine/68307tmu.c | 245 + src/devices/machine/68307tmu.h | 41 + src/devices/machine/68340.c | 152 + src/devices/machine/68340.h | 75 + src/devices/machine/68340dma.c | 39 + src/devices/machine/68340dma.h | 10 + src/devices/machine/68340ser.c | 40 + src/devices/machine/68340ser.h | 10 + src/devices/machine/68340sim.c | 349 + src/devices/machine/68340sim.h | 60 + src/devices/machine/68340tmu.c | 39 + src/devices/machine/68340tmu.h | 10 + src/devices/machine/6840ptm.c | 755 + src/devices/machine/6840ptm.h | 148 + src/devices/machine/6850acia.c | 597 + src/devices/machine/6850acia.h | 145 + src/devices/machine/68561mpcc.c | 481 + src/devices/machine/68561mpcc.h | 102 + src/devices/machine/7200fifo.c | 138 + src/devices/machine/7200fifo.h | 132 + src/devices/machine/74123.c | 249 + src/devices/machine/74123.h | 147 + src/devices/machine/74145.c | 142 + src/devices/machine/74145.h | 96 + src/devices/machine/74148.c | 198 + src/devices/machine/74148.h | 99 + src/devices/machine/74153.c | 172 + src/devices/machine/74153.h | 92 + src/devices/machine/74181.c | 150 + src/devices/machine/74181.h | 80 + src/devices/machine/7474.c | 216 + src/devices/machine/7474.h | 121 + src/devices/machine/8042kbdc.c | 618 + src/devices/machine/8042kbdc.h | 127 + src/devices/machine/8530scc.c | 678 + src/devices/machine/8530scc.h | 103 + src/devices/machine/aakart.c | 195 + src/devices/machine/aakart.h | 100 + src/devices/machine/adc0808.c | 187 + src/devices/machine/adc0808.h | 140 + src/devices/machine/adc083x.c | 448 + src/devices/machine/adc083x.h | 126 + src/devices/machine/adc1038.c | 121 + src/devices/machine/adc1038.h | 69 + src/devices/machine/adc1213x.c | 338 + src/devices/machine/adc1213x.h | 89 + src/devices/machine/aicartc.c | 169 + src/devices/machine/aicartc.h | 67 + src/devices/machine/akiko.c | 927 + src/devices/machine/akiko.h | 155 + src/devices/machine/am53cf96.c | 194 + src/devices/machine/am53cf96.h | 76 + src/devices/machine/am9517a.c | 1279 + src/devices/machine/am9517a.h | 255 + src/devices/machine/amigafdc.c | 656 + src/devices/machine/amigafdc.h | 121 + src/devices/machine/at28c16.c | 273 + src/devices/machine/at28c16.h | 74 + src/devices/machine/at29x.c | 525 + src/devices/machine/at29x.h | 116 + src/devices/machine/at45dbxx.c | 388 + src/devices/machine/at45dbxx.h | 152 + src/devices/machine/at_keybc.c | 226 + src/devices/machine/at_keybc.h | 108 + src/devices/machine/atadev.c | 21 + src/devices/machine/atadev.h | 44 + src/devices/machine/ataflash.c | 209 + src/devices/machine/ataflash.h | 41 + src/devices/machine/atahle.c | 950 + src/devices/machine/atahle.h | 218 + src/devices/machine/ataintf.c | 323 + src/devices/machine/ataintf.h | 129 + src/devices/machine/atapicdr.c | 81 + src/devices/machine/atapicdr.h | 38 + src/devices/machine/atapihle.c | 277 + src/devices/machine/atapihle.h | 78 + src/devices/machine/autoconfig.c | 169 + src/devices/machine/autoconfig.h | 74 + src/devices/machine/ay31015.c | 753 + src/devices/machine/ay31015.h | 198 + src/devices/machine/bankdev.c | 90 + src/devices/machine/bankdev.h | 75 + src/devices/machine/bcreader.c | 330 + src/devices/machine/bcreader.h | 60 + src/devices/machine/buffer.c | 17 + src/devices/machine/buffer.h | 31 + src/devices/machine/cdp1852.c | 187 + src/devices/machine/cdp1852.h | 102 + src/devices/machine/cdp1871.c | 290 + src/devices/machine/cdp1871.h | 172 + src/devices/machine/clock.c | 68 + src/devices/machine/clock.h | 37 + src/devices/machine/com8116.c | 159 + src/devices/machine/com8116.h | 104 + src/devices/machine/corvushd.c | 1475 + src/devices/machine/corvushd.h | 530 + src/devices/machine/cr511b.c | 121 + src/devices/machine/cr511b.h | 150 + src/devices/machine/cr589.c | 196 + src/devices/machine/cr589.h | 48 + src/devices/machine/cs4031.c | 969 + src/devices/machine/cs4031.h | 290 + src/devices/machine/cs8221.c | 167 + src/devices/machine/cs8221.h | 88 + src/devices/machine/diablo_hd.c | 1464 + src/devices/machine/diablo_hd.h | 178 + src/devices/machine/dmac.c | 465 + src/devices/machine/dmac.h | 171 + src/devices/machine/dp8390.c | 479 + src/devices/machine/dp8390.h | 147 + src/devices/machine/ds1204.c | 375 + src/devices/machine/ds1204.h | 93 + src/devices/machine/ds128x.c | 16 + src/devices/machine/ds128x.h | 26 + src/devices/machine/ds1302.c | 413 + src/devices/machine/ds1302.h | 96 + src/devices/machine/ds1315.c | 277 + src/devices/machine/ds1315.h | 72 + src/devices/machine/ds2401.c | 270 + src/devices/machine/ds2401.h | 71 + src/devices/machine/ds2404.c | 405 + src/devices/machine/ds2404.h | 129 + src/devices/machine/ds75160a.c | 111 + src/devices/machine/ds75160a.h | 84 + src/devices/machine/ds75161a.c | 353 + src/devices/machine/ds75161a.h | 177 + src/devices/machine/e0516.c | 198 + src/devices/machine/e0516.h | 82 + src/devices/machine/e05a03.c | 188 + src/devices/machine/e05a03.h | 99 + src/devices/machine/e05a30.c | 224 + src/devices/machine/e05a30.h | 115 + src/devices/machine/eeprom.c | 376 + src/devices/machine/eeprom.h | 116 + src/devices/machine/eeprompar.c | 133 + src/devices/machine/eeprompar.h | 105 + src/devices/machine/eepromser.c | 1161 + src/devices/machine/eepromser.h | 295 + src/devices/machine/er2055.c | 177 + src/devices/machine/er2055.h | 83 + src/devices/machine/f3853.c | 211 + src/devices/machine/f3853.h | 110 + src/devices/machine/fdc37c665gt.c | 61 + src/devices/machine/fdc37c665gt.h | 37 + src/devices/machine/fdc_pll.c | 134 + src/devices/machine/fdc_pll.h | 33 + src/devices/machine/gayle.c | 210 + src/devices/machine/gayle.h | 110 + src/devices/machine/generic.c | 290 + src/devices/machine/generic.h | 69 + src/devices/machine/hd63450.c | 555 + src/devices/machine/hd63450.h | 155 + src/devices/machine/hd64610.c | 366 + src/devices/machine/hd64610.h | 105 + src/devices/machine/hdc92x4.c | 4456 +++ src/devices/machine/hdc92x4.h | 487 + src/devices/machine/i2cmem.c | 510 + src/devices/machine/i2cmem.h | 158 + src/devices/machine/i6300esb.c | 757 + src/devices/machine/i6300esb.h | 160 + src/devices/machine/i80130.c | 173 + src/devices/machine/i80130.h | 111 + src/devices/machine/i8155.c | 593 + src/devices/machine/i8155.h | 153 + src/devices/machine/i8212.c | 142 + src/devices/machine/i8212.h | 103 + src/devices/machine/i8214.c | 205 + src/devices/machine/i8214.h | 94 + src/devices/machine/i8243.c | 125 + src/devices/machine/i8243.h | 78 + src/devices/machine/i8251.c | 788 + src/devices/machine/i8251.h | 155 + src/devices/machine/i82541.c | 32 + src/devices/machine/i82541.h | 29 + src/devices/machine/i8255.c | 995 + src/devices/machine/i8255.h | 148 + src/devices/machine/i8257.c | 668 + src/devices/machine/i8257.h | 207 + src/devices/machine/i8271.c | 1510 + src/devices/machine/i8271.h | 165 + src/devices/machine/i8279.c | 489 + src/devices/machine/i8279.h | 145 + src/devices/machine/i82875p.c | 515 + src/devices/machine/i82875p.h | 139 + src/devices/machine/i8355.c | 210 + src/devices/machine/i8355.h | 120 + src/devices/machine/idectrl.c | 393 + src/devices/machine/idectrl.h | 121 + src/devices/machine/idehd.c | 836 + src/devices/machine/idehd.h | 122 + src/devices/machine/im6402.c | 412 + src/devices/machine/im6402.h | 170 + src/devices/machine/ins8154.c | 247 + src/devices/machine/ins8154.h | 115 + src/devices/machine/ins8250.c | 705 + src/devices/machine/ins8250.h | 174 + src/devices/machine/intelfsh.c | 1146 + src/devices/machine/intelfsh.h | 427 + src/devices/machine/jvsdev.c | 260 + src/devices/machine/jvsdev.h | 54 + src/devices/machine/jvshost.c | 157 + src/devices/machine/jvshost.h | 47 + src/devices/machine/k033906.c | 128 + src/devices/machine/k033906.h | 71 + src/devices/machine/k053252.c | 233 + src/devices/machine/k053252.h | 73 + src/devices/machine/k056230.c | 112 + src/devices/machine/k056230.h | 72 + src/devices/machine/kb3600.c | 201 + src/devices/machine/kb3600.h | 151 + src/devices/machine/keyboard.c | 395 + src/devices/machine/keyboard.h | 60 + src/devices/machine/kr2376.c | 350 + src/devices/machine/kr2376.h | 106 + src/devices/machine/laserdsc.c | 1229 + src/devices/machine/laserdsc.h | 413 + src/devices/machine/latch.c | 122 + src/devices/machine/latch.h | 74 + src/devices/machine/latch8.c | 247 + src/devices/machine/latch8.h | 228 + src/devices/machine/lc89510.c | 26 + src/devices/machine/lc89510.h | 23 + src/devices/machine/ldpr8210.c | 1107 + src/devices/machine/ldpr8210.h | 193 + src/devices/machine/ldstub.c | 22 + src/devices/machine/ldstub.h | 114 + src/devices/machine/ldv1000.c | 656 + src/devices/machine/ldv1000.h | 128 + src/devices/machine/ldvp931.c | 653 + src/devices/machine/ldvp931.h | 138 + src/devices/machine/legscsi.c | 152 + src/devices/machine/legscsi.h | 39 + src/devices/machine/lh5810.c | 171 + src/devices/machine/lh5810.h | 106 + src/devices/machine/linflash.c | 208 + src/devices/machine/linflash.h | 72 + src/devices/machine/lpc-acpi.c | 368 + src/devices/machine/lpc-acpi.h | 88 + src/devices/machine/lpc-pit.c | 47 + src/devices/machine/lpc-pit.h | 32 + src/devices/machine/lpc-rtc.c | 83 + src/devices/machine/lpc-rtc.h | 44 + src/devices/machine/lpc.c | 8 + src/devices/machine/lpc.h | 16 + src/devices/machine/lpci.c | 291 + src/devices/machine/lpci.h | 83 + src/devices/machine/m6m80011ap.c | 232 + src/devices/machine/m6m80011ap.h | 91 + src/devices/machine/matsucd.c | 757 + src/devices/machine/matsucd.h | 31 + src/devices/machine/mb14241.c | 73 + src/devices/machine/mb14241.h | 45 + src/devices/machine/mb3773.c | 76 + src/devices/machine/mb3773.h | 56 + src/devices/machine/mb8421.c | 94 + src/devices/machine/mb8421.h | 71 + src/devices/machine/mb87078.c | 247 + src/devices/machine/mb87078.h | 68 + src/devices/machine/mb8795.c | 335 + src/devices/machine/mb8795.h | 124 + src/devices/machine/mb89352.c | 619 + src/devices/machine/mb89352.h | 118 + src/devices/machine/mb89363b.c | 181 + src/devices/machine/mb89363b.h | 134 + src/devices/machine/mb89371.c | 31 + src/devices/machine/mb89371.h | 35 + src/devices/machine/mc146818.c | 593 + src/devices/machine/mc146818.h | 177 + src/devices/machine/mc2661.c | 499 + src/devices/machine/mc2661.h | 149 + src/devices/machine/mc68328.c | 2871 ++ src/devices/machine/mc68328.h | 784 + src/devices/machine/mc6843.c | 827 + src/devices/machine/mc6843.h | 88 + src/devices/machine/mc6846.c | 568 + src/devices/machine/mc6846.h | 125 + src/devices/machine/mc6852.c | 302 + src/devices/machine/mc6852.h | 132 + src/devices/machine/mc6854.c | 989 + src/devices/machine/mc6854.h | 161 + src/devices/machine/mc68681.c | 1152 + src/devices/machine/mc68681.h | 180 + src/devices/machine/mc68901.c | 1134 + src/devices/machine/mc68901.h | 311 + src/devices/machine/mccs1850.c | 584 + src/devices/machine/mccs1850.h | 123 + src/devices/machine/mcf5206e.c | 1118 + src/devices/machine/mcf5206e.h | 215 + src/devices/machine/microtch.c | 307 + src/devices/machine/microtch.h | 79 + src/devices/machine/mm58167.c | 261 + src/devices/machine/mm58167.h | 70 + src/devices/machine/mm58274c.c | 470 + src/devices/machine/mm58274c.h | 81 + src/devices/machine/mm74c922.c | 190 + src/devices/machine/mm74c922.h | 138 + src/devices/machine/mos6526.c | 1178 + src/devices/machine/mos6526.h | 296 + src/devices/machine/mos6529.c | 95 + src/devices/machine/mos6529.h | 113 + src/devices/machine/mos6530.c | 382 + src/devices/machine/mos6530.h | 124 + src/devices/machine/mos6530n.c | 844 + src/devices/machine/mos6530n.h | 415 + src/devices/machine/mos6551.c | 833 + src/devices/machine/mos6551.h | 212 + src/devices/machine/mos6702.c | 68 + src/devices/machine/mos6702.h | 66 + src/devices/machine/mos8706.c | 78 + src/devices/machine/mos8706.h | 70 + src/devices/machine/mos8722.c | 366 + src/devices/machine/mos8722.h | 154 + src/devices/machine/mos8726.c | 125 + src/devices/machine/mos8726.h | 98 + src/devices/machine/mpu401.c | 289 + src/devices/machine/mpu401.h | 72 + src/devices/machine/msm5832.c | 306 + src/devices/machine/msm5832.h | 99 + src/devices/machine/msm58321.c | 646 + src/devices/machine/msm58321.h | 146 + src/devices/machine/msm6242.c | 557 + src/devices/machine/msm6242.h | 83 + src/devices/machine/ncr5380.c | 424 + src/devices/machine/ncr5380.h | 70 + src/devices/machine/ncr5380n.c | 586 + src/devices/machine/ncr5380n.h | 227 + src/devices/machine/ncr5390.c | 862 + src/devices/machine/ncr5390.h | 232 + src/devices/machine/ncr539x.c | 831 + src/devices/machine/ncr539x.h | 90 + src/devices/machine/netlist.c | 660 + src/devices/machine/netlist.h | 725 + src/devices/machine/nmc9306.c | 322 + src/devices/machine/nmc9306.h | 93 + src/devices/machine/nsc810.c | 312 + src/devices/machine/nsc810.h | 135 + src/devices/machine/nscsi_bus.c | 741 + src/devices/machine/nscsi_bus.h | 428 + src/devices/machine/nscsi_cb.c | 57 + src/devices/machine/nscsi_cb.h | 97 + src/devices/machine/nscsi_cd.c | 251 + src/devices/machine/nscsi_cd.h | 33 + src/devices/machine/nscsi_hd.c | 369 + src/devices/machine/nscsi_hd.h | 33 + src/devices/machine/nscsi_s1410.c | 151 + src/devices/machine/nscsi_s1410.h | 76 + src/devices/machine/nvram.c | 181 + src/devices/machine/nvram.h | 115 + src/devices/machine/pc_fdc.c | 192 + src/devices/machine/pc_fdc.h | 83 + src/devices/machine/pc_lpt.c | 163 + src/devices/machine/pc_lpt.h | 87 + src/devices/machine/pccard.c | 76 + src/devices/machine/pccard.h | 43 + src/devices/machine/pcf8593.c | 285 + src/devices/machine/pcf8593.h | 79 + src/devices/machine/pci-apic.c | 20 + src/devices/machine/pci-apic.h | 22 + src/devices/machine/pci-sata.c | 46 + src/devices/machine/pci-sata.h | 30 + src/devices/machine/pci-smbus.c | 280 + src/devices/machine/pci-smbus.h | 67 + src/devices/machine/pci-usb.c | 44 + src/devices/machine/pci-usb.h | 41 + src/devices/machine/pci.c | 908 + src/devices/machine/pci.h | 282 + src/devices/machine/pci9050.c | 254 + src/devices/machine/pci9050.h | 76 + src/devices/machine/pckeybrd.c | 1305 + src/devices/machine/pckeybrd.h | 137 + src/devices/machine/pic8259.c | 439 + src/devices/machine/pic8259.h | 126 + src/devices/machine/pit8253.c | 1135 + src/devices/machine/pit8253.h | 172 + src/devices/machine/pla.c | 181 + src/devices/machine/pla.h | 137 + src/devices/machine/r10696.c | 185 + src/devices/machine/r10696.h | 58 + src/devices/machine/r10788.c | 226 + src/devices/machine/r10788.h | 76 + src/devices/machine/ra17xx.c | 131 + src/devices/machine/ra17xx.h | 58 + src/devices/machine/ram.c | 222 + src/devices/machine/ram.h | 95 + src/devices/machine/rescap.h | 29 + src/devices/machine/rf5c296.c | 113 + src/devices/machine/rf5c296.h | 42 + src/devices/machine/roc10937.c | 388 + src/devices/machine/roc10937.h | 128 + src/devices/machine/rp5c01.c | 428 + src/devices/machine/rp5c01.h | 112 + src/devices/machine/rp5c15.c | 447 + src/devices/machine/rp5c15.h | 106 + src/devices/machine/rp5h01.c | 201 + src/devices/machine/rp5h01.h | 77 + src/devices/machine/rtc4543.c | 206 + src/devices/machine/rtc4543.h | 82 + src/devices/machine/rtc65271.c | 697 + src/devices/machine/rtc65271.h | 76 + src/devices/machine/rtc9701.c | 469 + src/devices/machine/rtc9701.h | 111 + src/devices/machine/s2636.c | 367 + src/devices/machine/s2636.h | 84 + src/devices/machine/s3520cf.c | 265 + src/devices/machine/s3520cf.h | 91 + src/devices/machine/s3c2400.c | 140 + src/devices/machine/s3c2400.h | 894 + src/devices/machine/s3c2410.c | 170 + src/devices/machine/s3c2410.h | 1073 + src/devices/machine/s3c2440.c | 175 + src/devices/machine/s3c2440.h | 1157 + src/devices/machine/s3c24xx.inc | 3519 ++ src/devices/machine/s3c44b0.c | 2055 ++ src/devices/machine/s3c44b0.h | 814 + src/devices/machine/saturn.c | 1003 + src/devices/machine/serflash.c | 411 + src/devices/machine/serflash.h | 108 + src/devices/machine/smc91c9x.c | 531 + src/devices/machine/smc91c9x.h | 100 + src/devices/machine/smpc.c | 1084 + src/devices/machine/smpc.h | 7 + src/devices/machine/spchrom.c | 139 + src/devices/machine/spchrom.h | 41 + src/devices/machine/steppers.c | 450 + src/devices/machine/steppers.h | 179 + src/devices/machine/strata.c | 675 + src/devices/machine/strata.h | 75 + src/devices/machine/stvcd.c | 2702 ++ src/devices/machine/t10mmc.c | 765 + src/devices/machine/t10mmc.h | 63 + src/devices/machine/t10sbc.c | 268 + src/devices/machine/t10sbc.h | 36 + src/devices/machine/t10spc.c | 150 + src/devices/machine/t10spc.h | 136 + src/devices/machine/tc009xlvc.c | 417 + src/devices/machine/tc009xlvc.h | 98 + src/devices/machine/terminal.c | 411 + src/devices/machine/terminal.h | 63 + src/devices/machine/timekpr.c | 437 + src/devices/machine/timekpr.h | 144 + src/devices/machine/tmp68301.c | 337 + src/devices/machine/tmp68301.h | 90 + src/devices/machine/tms1024.c | 111 + src/devices/machine/tms1024.h | 110 + src/devices/machine/tms5501.c | 529 + src/devices/machine/tms5501.h | 195 + src/devices/machine/tms6100.c | 264 + src/devices/machine/tms6100.h | 60 + src/devices/machine/tms9901.c | 630 + src/devices/machine/tms9901.h | 224 + src/devices/machine/tms9902.c | 847 + src/devices/machine/tms9902.h | 203 + src/devices/machine/upd1990a.c | 499 + src/devices/machine/upd1990a.h | 161 + src/devices/machine/upd4701.c | 259 + src/devices/machine/upd4701.h | 66 + src/devices/machine/upd4992.c | 156 + src/devices/machine/upd4992.h | 73 + src/devices/machine/upd7002.c | 172 + src/devices/machine/upd7002.h | 106 + src/devices/machine/upd71071.c | 517 + src/devices/machine/upd71071.h | 146 + src/devices/machine/upd765.c | 2534 ++ src/devices/machine/upd765.h | 533 + src/devices/machine/v3021.c | 185 + src/devices/machine/v3021.h | 78 + src/devices/machine/vrc4373.c | 432 + src/devices/machine/vrc4373.h | 132 + src/devices/machine/vt83c461.c | 105 + src/devices/machine/vt83c461.h | 51 + src/devices/machine/wd11c00_17.c | 474 + src/devices/machine/wd11c00_17.h | 142 + src/devices/machine/wd2010.c | 989 + src/devices/machine/wd2010.h | 157 + src/devices/machine/wd33c93.c | 807 + src/devices/machine/wd33c93.h | 109 + src/devices/machine/wd7600.c | 557 + src/devices/machine/wd7600.h | 240 + src/devices/machine/wd_fdc.c | 2831 ++ src/devices/machine/wd_fdc.h | 683 + src/devices/machine/wozfdc.c | 587 + src/devices/machine/wozfdc.h | 122 + src/devices/machine/x2212.c | 261 + src/devices/machine/x2212.h | 113 + src/devices/machine/x76f041.c | 540 + src/devices/machine/x76f041.h | 127 + src/devices/machine/x76f100.c | 427 + src/devices/machine/x76f100.h | 90 + src/devices/machine/ym2148.c | 209 + src/devices/machine/ym2148.h | 93 + src/devices/machine/z80ctc.c | 525 + src/devices/machine/z80ctc.h | 140 + src/devices/machine/z80dart.c | 1357 + src/devices/machine/z80dart.h | 684 + src/devices/machine/z80dma.c | 881 + src/devices/machine/z80dma.h | 165 + src/devices/machine/z80pio.c | 809 + src/devices/machine/z80pio.h | 260 + src/devices/machine/z80sti.c | 720 + src/devices/machine/z80sti.h | 250 + src/devices/machine/z8536.c | 1123 + src/devices/machine/z8536.h | 353 + src/devices/sound/2151intf.c | 131 + src/devices/sound/2151intf.h | 84 + src/devices/sound/2203intf.c | 195 + src/devices/sound/2203intf.h | 56 + src/devices/sound/2413intf.c | 95 + src/devices/sound/2413intf.h | 42 + src/devices/sound/2608intf.c | 231 + src/devices/sound/2608intf.h | 53 + src/devices/sound/2610intf.c | 226 + src/devices/sound/2610intf.h | 65 + src/devices/sound/2612intf.c | 183 + src/devices/sound/2612intf.h | 64 + src/devices/sound/262intf.c | 155 + src/devices/sound/262intf.h | 51 + src/devices/sound/315-5641.c | 70 + src/devices/sound/315-5641.h | 30 + src/devices/sound/3526intf.c | 173 + src/devices/sound/3526intf.h | 57 + src/devices/sound/3812intf.c | 171 + src/devices/sound/3812intf.h | 56 + src/devices/sound/8950intf.c | 226 + src/devices/sound/8950intf.h | 81 + src/devices/sound/aica.c | 1662 + src/devices/sound/aica.h | 213 + src/devices/sound/aicadsp.c | 351 + src/devices/sound/aicadsp.h | 42 + src/devices/sound/amiga.c | 245 + src/devices/sound/amiga.h | 65 + src/devices/sound/asc.c | 597 + src/devices/sound/asc.h | 136 + src/devices/sound/astrocde.c | 285 + src/devices/sound/astrocde.h | 73 + src/devices/sound/awacs.c | 176 + src/devices/sound/awacs.h | 77 + src/devices/sound/ay8910.c | 1270 + src/devices/sound/ay8910.h | 273 + src/devices/sound/beep.c | 147 + src/devices/sound/beep.h | 44 + src/devices/sound/bsmt2000.c | 358 + src/devices/sound/bsmt2000.h | 112 + src/devices/sound/c140.c | 489 + src/devices/sound/c140.h | 124 + src/devices/sound/c352.c | 551 + src/devices/sound/c352.h | 121 + src/devices/sound/c6280.c | 302 + src/devices/sound/c6280.h | 61 + src/devices/sound/cdda.c | 271 + src/devices/sound/cdda.h | 58 + src/devices/sound/cdp1863.c | 198 + src/devices/sound/cdp1863.h | 89 + src/devices/sound/cdp1864.c | 467 + src/devices/sound/cdp1864.h | 208 + src/devices/sound/cdp1869.c | 1004 + src/devices/sound/cdp1869.h | 302 + src/devices/sound/cem3394.c | 552 + src/devices/sound/cem3394.h | 117 + src/devices/sound/dac.c | 92 + src/devices/sound/dac.h | 70 + src/devices/sound/digitalk.c | 692 + src/devices/sound/digitalk.h | 101 + src/devices/sound/disc_cls.h | 258 + src/devices/sound/disc_dev.h | 129 + src/devices/sound/disc_dev.inc | 1776 + src/devices/sound/disc_flt.h | 180 + src/devices/sound/disc_flt.inc | 1438 + src/devices/sound/disc_inp.inc | 325 + src/devices/sound/disc_mth.h | 240 + src/devices/sound/disc_mth.inc | 2773 ++ src/devices/sound/disc_sys.inc | 123 + src/devices/sound/disc_wav.h | 193 + src/devices/sound/disc_wav.inc | 1787 + src/devices/sound/discrete.c | 1148 + src/devices/sound/discrete.h | 4728 +++ src/devices/sound/dmadac.c | 238 + src/devices/sound/dmadac.h | 56 + src/devices/sound/es1373.c | 499 + src/devices/sound/es1373.h | 145 + src/devices/sound/es5503.c | 451 + src/devices/sound/es5503.h | 108 + src/devices/sound/es5506.c | 2274 ++ src/devices/sound/es5506.h | 248 + src/devices/sound/es8712.c | 349 + src/devices/sound/es8712.h | 78 + src/devices/sound/esqpump.c | 170 + src/devices/sound/esqpump.h | 124 + src/devices/sound/filter.c | 234 + src/devices/sound/filter.h | 133 + src/devices/sound/flt_rc.c | 139 + src/devices/sound/flt_rc.h | 104 + src/devices/sound/flt_vol.c | 52 + src/devices/sound/flt_vol.h | 50 + src/devices/sound/fm.c | 3908 +++ src/devices/sound/fm.h | 201 + src/devices/sound/fm2612.c | 2559 ++ src/devices/sound/fmopl.c | 2582 ++ src/devices/sound/fmopl.h | 115 + src/devices/sound/gaelco.c | 276 + src/devices/sound/gaelco.h | 98 + src/devices/sound/hc55516.c | 337 + src/devices/sound/hc55516.h | 95 + src/devices/sound/i5000.c | 303 + src/devices/sound/i5000.h | 89 + src/devices/sound/ics2115.c | 890 + src/devices/sound/ics2115.h | 158 + src/devices/sound/iremga20.c | 268 + src/devices/sound/iremga20.h | 78 + src/devices/sound/k005289.c | 242 + src/devices/sound/k005289.h | 65 + src/devices/sound/k007232.c | 424 + src/devices/sound/k007232.h | 74 + src/devices/sound/k051649.c | 288 + src/devices/sound/k051649.h | 95 + src/devices/sound/k053260.c | 474 + src/devices/sound/k053260.h | 113 + src/devices/sound/k054539.c | 534 + src/devices/sound/k054539.h | 124 + src/devices/sound/k056800.c | 178 + src/devices/sound/k056800.h | 61 + src/devices/sound/l7a1045_l6028_dsp_a.c | 348 + src/devices/sound/l7a1045_l6028_dsp_a.h | 69 + src/devices/sound/lmc1992.c | 232 + src/devices/sound/lmc1992.h | 113 + src/devices/sound/mas3507d.c | 262 + src/devices/sound/mas3507d.h | 68 + src/devices/sound/mos6560.c | 969 + src/devices/sound/mos6560.h | 260 + src/devices/sound/mos6581.c | 157 + src/devices/sound/mos6581.h | 109 + src/devices/sound/mos7360.c | 1206 + src/devices/sound/mos7360.h | 205 + src/devices/sound/mpeg_audio.c | 759 + src/devices/sound/mpeg_audio.h | 134 + src/devices/sound/msm5205.c | 340 + src/devices/sound/msm5205.h | 109 + src/devices/sound/msm5232.c | 802 + src/devices/sound/msm5232.h | 111 + src/devices/sound/multipcm.c | 658 + src/devices/sound/multipcm.h | 110 + src/devices/sound/n63701x.c | 153 + src/devices/sound/n63701x.h | 69 + src/devices/sound/namco.c | 850 + src/devices/sound/namco.h | 132 + src/devices/sound/nes_apu.c | 774 + src/devices/sound/nes_apu.h | 96 + src/devices/sound/nes_defs.h | 290 + src/devices/sound/nile.c | 228 + src/devices/sound/nile.h | 60 + src/devices/sound/okiadpcm.c | 192 + src/devices/sound/okiadpcm.h | 64 + src/devices/sound/okim6258.c | 337 + src/devices/sound/okim6258.h | 99 + src/devices/sound/okim6295.c | 421 + src/devices/sound/okim6295.h | 126 + src/devices/sound/okim6376.c | 581 + src/devices/sound/okim6376.h | 82 + src/devices/sound/okim9810.c | 585 + src/devices/sound/okim9810.h | 163 + src/devices/sound/pci-ac97.c | 36 + src/devices/sound/pci-ac97.h | 28 + src/devices/sound/pokey.c | 1453 + src/devices/sound/pokey.h | 381 + src/devices/sound/pokey.txt | 319 + src/devices/sound/qs1000.c | 646 + src/devices/sound/qs1000.h | 165 + src/devices/sound/qsound.c | 324 + src/devices/sound/qsound.h | 81 + src/devices/sound/rf5c400.c | 551 + src/devices/sound/rf5c400.h | 117 + src/devices/sound/rf5c68.c | 233 + src/devices/sound/rf5c68.h | 96 + src/devices/sound/s14001a.c | 651 + src/devices/sound/s14001a.h | 67 + src/devices/sound/saa1099.c | 452 + src/devices/sound/saa1099.h | 112 + src/devices/sound/samples.c | 642 + src/devices/sound/samples.h | 187 + src/devices/sound/sb0400.c | 24 + src/devices/sound/sb0400.h | 27 + src/devices/sound/scsp.c | 1574 + src/devices/sound/scsp.h | 214 + src/devices/sound/scspdsp.c | 355 + src/devices/sound/scspdsp.h | 42 + src/devices/sound/segapcm.c | 151 + src/devices/sound/segapcm.h | 70 + src/devices/sound/sid.c | 352 + src/devices/sound/sid.h | 66 + src/devices/sound/side6581.h | 128 + src/devices/sound/sidenvel.c | 588 + src/devices/sound/sidenvel.h | 39 + src/devices/sound/sidvoice.c | 810 + src/devices/sound/sidvoice.h | 120 + src/devices/sound/sidw6581.h | 1053 + src/devices/sound/sidw8580.h | 1399 + src/devices/sound/sn76477.c | 2308 ++ src/devices/sound/sn76477.h | 337 + src/devices/sound/sn76496.c | 441 + src/devices/sound/sn76496.h | 144 + src/devices/sound/snkwave.c | 153 + src/devices/sound/snkwave.h | 64 + src/devices/sound/sp0250.c | 247 + src/devices/sound/sp0250.h | 58 + src/devices/sound/sp0256.c | 1367 + src/devices/sound/sp0256.h | 136 + src/devices/sound/speaker.c | 409 + src/devices/sound/speaker.h | 93 + src/devices/sound/spu.c | 3081 ++ src/devices/sound/spu.h | 255 + src/devices/sound/spu_tables.c | 703 + src/devices/sound/spureverb.c | 343 + src/devices/sound/spureverb.h | 72 + src/devices/sound/st0016.c | 164 + src/devices/sound/st0016.h | 54 + src/devices/sound/t6721a.c | 112 + src/devices/sound/t6721a.h | 123 + src/devices/sound/t6w28.c | 356 + src/devices/sound/t6w28.h | 47 + src/devices/sound/tc8830f.c | 256 + src/devices/sound/tc8830f.h | 71 + src/devices/sound/tiaintf.c | 64 + src/devices/sound/tiaintf.h | 50 + src/devices/sound/tiasound.c | 612 + src/devices/sound/tiasound.h | 47 + src/devices/sound/tms3615.c | 109 + src/devices/sound/tms3615.h | 61 + src/devices/sound/tms36xx.c | 557 + src/devices/sound/tms36xx.h | 137 + src/devices/sound/tms5110.c | 1620 + src/devices/sound/tms5110.h | 397 + src/devices/sound/tms5110r.inc | 705 + src/devices/sound/tms5220.c | 1953 ++ src/devices/sound/tms5220.h | 254 + src/devices/sound/tms5220.txt | 86 + src/devices/sound/upd7752.c | 195 + src/devices/sound/upd7752.h | 78 + src/devices/sound/upd7759.c | 874 + src/devices/sound/upd7759.h | 151 + src/devices/sound/vlm5030.c | 655 + src/devices/sound/vlm5030.h | 100 + src/devices/sound/votrax.c | 1362 + src/devices/sound/votrax.h | 164 + src/devices/sound/vrc6.c | 320 + src/devices/sound/vrc6.h | 61 + src/devices/sound/vrender0.c | 250 + src/devices/sound/vrender0.h | 63 + src/devices/sound/wave.c | 110 + src/devices/sound/wave.h | 47 + src/devices/sound/wavwrite.c | 189 + src/devices/sound/wavwrite.h | 18 + src/devices/sound/x1_010.c | 276 + src/devices/sound/x1_010.h | 58 + src/devices/sound/ym2151.c | 2500 ++ src/devices/sound/ym2151.h | 88 + src/devices/sound/ym2151.txt | 162 + src/devices/sound/ym2413.c | 2176 ++ src/devices/sound/ym2413.h | 45 + src/devices/sound/ymdeltat.c | 650 + src/devices/sound/ymdeltat.h | 86 + src/devices/sound/ymf262.c | 2715 ++ src/devices/sound/ymf262.h | 50 + src/devices/sound/ymf271.c | 1777 + src/devices/sound/ymf271.h | 166 + src/devices/sound/ymf278b.c | 1051 + src/devices/sound/ymf278b.h | 147 + src/devices/sound/ymz280b.c | 968 + src/devices/sound/ymz280b.h | 133 + src/devices/sound/ymz770.c | 345 + src/devices/sound/ymz770.h | 99 + src/devices/sound/zsg2.c | 464 + src/devices/sound/zsg2.h | 92 + src/devices/video/315_5124.c | 1709 + src/devices/video/315_5124.h | 255 + src/devices/video/315_5313.c | 2776 ++ src/devices/video/315_5313.h | 358 + src/devices/video/bufsprite.c | 23 + src/devices/video/bufsprite.h | 143 + src/devices/video/cdp1861.c | 253 + src/devices/video/cdp1861.h | 145 + src/devices/video/cdp1862.c | 198 + src/devices/video/cdp1862.h | 123 + src/devices/video/cgapal.c | 433 + src/devices/video/cgapal.h | 5 + src/devices/video/clgd542x.c | 1512 + src/devices/video/clgd542x.h | 114 + src/devices/video/crt9007.c | 935 + src/devices/video/crt9007.h | 222 + src/devices/video/crt9021.c | 187 + src/devices/video/crt9021.h | 139 + src/devices/video/crt9212.c | 195 + src/devices/video/crt9212.h | 126 + src/devices/video/crtc_ega.c | 728 + src/devices/video/crtc_ega.h | 236 + src/devices/video/dl1416.c | 297 + src/devices/video/dl1416.h | 78 + src/devices/video/dm9368.c | 96 + src/devices/video/dm9368.h | 75 + src/devices/video/ef9340_1.c | 383 + src/devices/video/ef9340_1.h | 81 + src/devices/video/ef9341_chargen.h | 269 + src/devices/video/ef9345.c | 1021 + src/devices/video/ef9345.h | 118 + src/devices/video/epic12.c | 949 + src/devices/video/epic12.h | 840 + src/devices/video/epic12_blit0.c | 558 + src/devices/video/epic12_blit1.c | 558 + src/devices/video/epic12_blit2.c | 558 + src/devices/video/epic12_blit3.c | 558 + src/devices/video/epic12_blit4.c | 558 + src/devices/video/epic12_blit5.c | 558 + src/devices/video/epic12_blit6.c | 558 + src/devices/video/epic12_blit7.c | 558 + src/devices/video/epic12_blit8.c | 42 + src/devices/video/epic12in.inc | 166 + src/devices/video/epic12pixel.inc | 193 + src/devices/video/fixfreq.c | 304 + src/devices/video/fixfreq.h | 163 + src/devices/video/generic.c | 94 + src/devices/video/generic.h | 31 + src/devices/video/gf4500.c | 184 + src/devices/video/gf4500.h | 56 + src/devices/video/gf7600gs.c | 33 + src/devices/video/gf7600gs.h | 27 + src/devices/video/h63484.c | 2190 ++ src/devices/video/h63484.h | 189 + src/devices/video/hd44102.c | 292 + src/devices/video/hd44102.h | 86 + src/devices/video/hd44352.c | 439 + src/devices/video/hd44352.h | 81 + src/devices/video/hd44780.c | 569 + src/devices/video/hd44780.h | 146 + src/devices/video/hd61830.c | 535 + src/devices/video/hd61830.h | 125 + src/devices/video/hd63484.c | 1578 + src/devices/video/hd63484.h | 81 + src/devices/video/hd66421.c | 287 + src/devices/video/hd66421.h | 84 + src/devices/video/huc6202.c | 367 + src/devices/video/huc6202.h | 130 + src/devices/video/huc6260.c | 311 + src/devices/video/huc6260.h | 98 + src/devices/video/huc6261.c | 434 + src/devices/video/huc6261.h | 81 + src/devices/video/huc6270.c | 895 + src/devices/video/huc6270.h | 141 + src/devices/video/huc6272.c | 249 + src/devices/video/huc6272.h | 80 + src/devices/video/i8244.c | 799 + src/devices/video/i8244.h | 169 + src/devices/video/i82730.c | 527 + src/devices/video/i82730.h | 157 + src/devices/video/i8275.c | 691 + src/devices/video/i8275.h | 236 + src/devices/video/m50458.c | 449 + src/devices/video/m50458.h | 105 + src/devices/video/mb90082.c | 248 + src/devices/video/mb90082.h | 85 + src/devices/video/mb_vcu.c | 579 + src/devices/video/mb_vcu.h | 92 + src/devices/video/mc6845.c | 1601 + src/devices/video/mc6845.h | 503 + src/devices/video/mc6847.c | 1890 + src/devices/video/mc6847.h | 706 + src/devices/video/mos6566.c | 2839 ++ src/devices/video/mos6566.h | 455 + src/devices/video/msm6222b.c | 246 + src/devices/video/msm6222b.h | 63 + src/devices/video/msm6255.c | 437 + src/devices/video/msm6255.h | 95 + src/devices/video/pc_vga.c | 5559 +++ src/devices/video/pc_vga.h | 705 + src/devices/video/poly.h | 1175 + src/devices/video/polylgcy.c | 1359 + src/devices/video/polylgcy.h | 155 + src/devices/video/psx.c | 3822 ++ src/devices/video/psx.h | 361 + src/devices/video/ramdac.c | 204 + src/devices/video/ramdac.h | 87 + src/devices/video/resnet.c | 719 + src/devices/video/resnet.h | 199 + src/devices/video/rgbgen.c | 136 + src/devices/video/rgbgen.h | 507 + src/devices/video/rgbsse.c | 194 + src/devices/video/rgbsse.h | 534 + src/devices/video/rgbutil.h | 24 + src/devices/video/rgbvmx.c | 220 + src/devices/video/rgbvmx.h | 509 + src/devices/video/saa5050.c | 525 + src/devices/video/saa5050.h | 257 + src/devices/video/scn2674.c | 766 + src/devices/video/scn2674.h | 133 + src/devices/video/sed1200.c | 192 + src/devices/video/sed1200.h | 92 + src/devices/video/sed1330.c | 688 + src/devices/video/sed1330.h | 126 + src/devices/video/sed1520.c | 164 + src/devices/video/sed1520.h | 72 + src/devices/video/snes_ppu.c | 2949 ++ src/devices/video/snes_ppu.h | 295 + src/devices/video/stvvdp1.c | 2160 ++ src/devices/video/stvvdp2.c | 6968 ++++ src/devices/video/t6a04.c | 242 + src/devices/video/t6a04.h | 72 + src/devices/video/tea1002.c | 85 + src/devices/video/tea1002.h | 66 + src/devices/video/tlc34076.c | 263 + src/devices/video/tlc34076.h | 76 + src/devices/video/tms34061.c | 557 + src/devices/video/tms34061.h | 122 + src/devices/video/tms3556.c | 658 + src/devices/video/tms3556.h | 139 + src/devices/video/tms9927.c | 326 + src/devices/video/tms9927.h | 110 + src/devices/video/tms9928a.c | 731 + src/devices/video/tms9928a.h | 207 + src/devices/video/upd3301.c | 635 + src/devices/video/upd3301.h | 194 + src/devices/video/upd7220.c | 1683 + src/devices/video/upd7220.h | 234 + src/devices/video/upd7227.c | 162 + src/devices/video/upd7227.h | 95 + src/devices/video/v9938.c | 3012 ++ src/devices/video/v9938.h | 250 + src/devices/video/vector.c | 307 + src/devices/video/vector.h | 73 + src/devices/video/vic4567.c | 2055 ++ src/devices/video/vic4567.h | 273 + src/devices/video/vooddefs.h | 5099 +++ src/devices/video/voodoo.c | 6537 ++++ src/devices/video/voodoo.h | 168 + src/devices/video/voodoo_pci.c | 180 + src/devices/video/voodoo_pci.h | 59 + 3320 files changed, 1310847 insertions(+) create mode 100644 src/devices/bus/a1bus/a1bus.c create mode 100644 src/devices/bus/a1bus/a1bus.h create mode 100644 src/devices/bus/a1bus/a1cassette.c create mode 100644 src/devices/bus/a1bus/a1cassette.h create mode 100644 src/devices/bus/a1bus/a1cffa.c create mode 100644 src/devices/bus/a1bus/a1cffa.h create mode 100644 src/devices/bus/a2bus/a2alfam2.c create mode 100644 src/devices/bus/a2bus/a2alfam2.h create mode 100644 src/devices/bus/a2bus/a2applicard.c create mode 100644 src/devices/bus/a2bus/a2applicard.h create mode 100644 src/devices/bus/a2bus/a2arcadebd.c create mode 100644 src/devices/bus/a2bus/a2arcadebd.h create mode 100644 src/devices/bus/a2bus/a2bus.c create mode 100644 src/devices/bus/a2bus/a2bus.h create mode 100644 src/devices/bus/a2bus/a2cffa.c create mode 100644 src/devices/bus/a2bus/a2cffa.h create mode 100644 src/devices/bus/a2bus/a2corvus.c create mode 100644 src/devices/bus/a2bus/a2corvus.h create mode 100644 src/devices/bus/a2bus/a2diskii.c create mode 100644 src/devices/bus/a2bus/a2diskii.h create mode 100644 src/devices/bus/a2bus/a2diskiing.c create mode 100644 src/devices/bus/a2bus/a2diskiing.h create mode 100644 src/devices/bus/a2bus/a2dx1.c create mode 100644 src/devices/bus/a2bus/a2dx1.h create mode 100644 src/devices/bus/a2bus/a2eauxslot.c create mode 100644 src/devices/bus/a2bus/a2eauxslot.h create mode 100644 src/devices/bus/a2bus/a2echoii.c create mode 100644 src/devices/bus/a2bus/a2echoii.h create mode 100644 src/devices/bus/a2bus/a2eext80col.c create mode 100644 src/devices/bus/a2bus/a2eext80col.h create mode 100644 src/devices/bus/a2bus/a2eramworks3.c create mode 100644 src/devices/bus/a2bus/a2eramworks3.h create mode 100644 src/devices/bus/a2bus/a2estd80col.c create mode 100644 src/devices/bus/a2bus/a2estd80col.h create mode 100644 src/devices/bus/a2bus/a2hsscsi.c create mode 100644 src/devices/bus/a2bus/a2hsscsi.h create mode 100644 src/devices/bus/a2bus/a2lang.c create mode 100644 src/devices/bus/a2bus/a2lang.h create mode 100644 src/devices/bus/a2bus/a2mcms.c create mode 100644 src/devices/bus/a2bus/a2mcms.h create mode 100644 src/devices/bus/a2bus/a2memexp.c create mode 100644 src/devices/bus/a2bus/a2memexp.h create mode 100644 src/devices/bus/a2bus/a2midi.c create mode 100644 src/devices/bus/a2bus/a2midi.h create mode 100644 src/devices/bus/a2bus/a2mockingboard.c create mode 100644 src/devices/bus/a2bus/a2mockingboard.h create mode 100644 src/devices/bus/a2bus/a2pic.c create mode 100644 src/devices/bus/a2bus/a2pic.h create mode 100644 src/devices/bus/a2bus/a2sam.c create mode 100644 src/devices/bus/a2bus/a2sam.h create mode 100644 src/devices/bus/a2bus/a2scsi.c create mode 100644 src/devices/bus/a2bus/a2scsi.h create mode 100644 src/devices/bus/a2bus/a2softcard.c create mode 100644 src/devices/bus/a2bus/a2softcard.h create mode 100644 src/devices/bus/a2bus/a2ssc.c create mode 100644 src/devices/bus/a2bus/a2ssc.h create mode 100644 src/devices/bus/a2bus/a2swyft.c create mode 100644 src/devices/bus/a2bus/a2swyft.h create mode 100644 src/devices/bus/a2bus/a2themill.c create mode 100644 src/devices/bus/a2bus/a2themill.h create mode 100644 src/devices/bus/a2bus/a2thunderclock.c create mode 100644 src/devices/bus/a2bus/a2thunderclock.h create mode 100644 src/devices/bus/a2bus/a2ultraterm.c create mode 100644 src/devices/bus/a2bus/a2ultraterm.h create mode 100644 src/devices/bus/a2bus/a2videoterm.c create mode 100644 src/devices/bus/a2bus/a2videoterm.h create mode 100644 src/devices/bus/a2bus/a2vulcan.c create mode 100644 src/devices/bus/a2bus/a2vulcan.h create mode 100644 src/devices/bus/a2bus/a2zipdrive.c create mode 100644 src/devices/bus/a2bus/a2zipdrive.h create mode 100644 src/devices/bus/a2bus/corvfdc01.c create mode 100644 src/devices/bus/a2bus/corvfdc01.h create mode 100644 src/devices/bus/a2bus/corvfdc02.c create mode 100644 src/devices/bus/a2bus/corvfdc02.h create mode 100644 src/devices/bus/a2bus/ezcgi.c create mode 100644 src/devices/bus/a2bus/ezcgi.h create mode 100644 src/devices/bus/a2bus/laser128.c create mode 100644 src/devices/bus/a2bus/laser128.h create mode 100644 src/devices/bus/a2bus/mouse.c create mode 100644 src/devices/bus/a2bus/mouse.h create mode 100644 src/devices/bus/a2bus/ramcard128k.c create mode 100644 src/devices/bus/a2bus/ramcard128k.h create mode 100644 src/devices/bus/a2bus/ramcard16k.c create mode 100644 src/devices/bus/a2bus/ramcard16k.h create mode 100644 src/devices/bus/a2bus/timemasterho.c create mode 100644 src/devices/bus/a2bus/timemasterho.h create mode 100644 src/devices/bus/a7800/a78_carts.h create mode 100644 src/devices/bus/a7800/a78_slot.c create mode 100644 src/devices/bus/a7800/a78_slot.h create mode 100644 src/devices/bus/a7800/cpuwiz.c create mode 100644 src/devices/bus/a7800/cpuwiz.h create mode 100644 src/devices/bus/a7800/hiscore.c create mode 100644 src/devices/bus/a7800/hiscore.h create mode 100644 src/devices/bus/a7800/rom.c create mode 100644 src/devices/bus/a7800/rom.h create mode 100644 src/devices/bus/a7800/xboard.c create mode 100644 src/devices/bus/a7800/xboard.h create mode 100644 src/devices/bus/a800/a800_carts.h create mode 100644 src/devices/bus/a800/a800_slot.c create mode 100644 src/devices/bus/a800/a800_slot.h create mode 100644 src/devices/bus/a800/oss.c create mode 100644 src/devices/bus/a800/oss.h create mode 100644 src/devices/bus/a800/rom.c create mode 100644 src/devices/bus/a800/rom.h create mode 100644 src/devices/bus/a800/sparta.c create mode 100644 src/devices/bus/a800/sparta.h create mode 100644 src/devices/bus/a8sio/a8sio.c create mode 100644 src/devices/bus/a8sio/a8sio.h create mode 100644 src/devices/bus/a8sio/cassette.c create mode 100644 src/devices/bus/a8sio/cassette.h create mode 100644 src/devices/bus/abcbus/abc890.c create mode 100644 src/devices/bus/abcbus/abc890.h create mode 100644 src/devices/bus/abcbus/abcbus.c create mode 100644 src/devices/bus/abcbus/abcbus.h create mode 100644 src/devices/bus/abcbus/fd2.c create mode 100644 src/devices/bus/abcbus/fd2.h create mode 100644 src/devices/bus/abcbus/hdc.c create mode 100644 src/devices/bus/abcbus/hdc.h create mode 100644 src/devices/bus/abcbus/lux10828.c create mode 100644 src/devices/bus/abcbus/lux10828.h create mode 100644 src/devices/bus/abcbus/lux21046.c create mode 100644 src/devices/bus/abcbus/lux21046.h create mode 100644 src/devices/bus/abcbus/lux21056.c create mode 100644 src/devices/bus/abcbus/lux21056.h create mode 100644 src/devices/bus/abcbus/lux4105.c create mode 100644 src/devices/bus/abcbus/lux4105.h create mode 100644 src/devices/bus/abcbus/memcard.c create mode 100644 src/devices/bus/abcbus/memcard.h create mode 100644 src/devices/bus/abcbus/ram.c create mode 100644 src/devices/bus/abcbus/ram.h create mode 100644 src/devices/bus/abcbus/sio.c create mode 100644 src/devices/bus/abcbus/sio.h create mode 100644 src/devices/bus/abcbus/slutprov.c create mode 100644 src/devices/bus/abcbus/slutprov.h create mode 100644 src/devices/bus/abcbus/turbo.c create mode 100644 src/devices/bus/abcbus/turbo.h create mode 100644 src/devices/bus/abcbus/uni800.c create mode 100644 src/devices/bus/abcbus/uni800.h create mode 100644 src/devices/bus/abckb/abc77.c create mode 100644 src/devices/bus/abckb/abc77.h create mode 100644 src/devices/bus/abckb/abc800kb.c create mode 100644 src/devices/bus/abckb/abc800kb.h create mode 100644 src/devices/bus/abckb/abc99.c create mode 100644 src/devices/bus/abckb/abc99.h create mode 100644 src/devices/bus/abckb/abckb.c create mode 100644 src/devices/bus/abckb/abckb.h create mode 100644 src/devices/bus/adam/adamlink.c create mode 100644 src/devices/bus/adam/adamlink.h create mode 100644 src/devices/bus/adam/exp.c create mode 100644 src/devices/bus/adam/exp.h create mode 100644 src/devices/bus/adam/ide.c create mode 100644 src/devices/bus/adam/ide.h create mode 100644 src/devices/bus/adam/ram.c create mode 100644 src/devices/bus/adam/ram.h create mode 100644 src/devices/bus/adamnet/adamnet.c create mode 100644 src/devices/bus/adamnet/adamnet.h create mode 100644 src/devices/bus/adamnet/ddp.c create mode 100644 src/devices/bus/adamnet/ddp.h create mode 100644 src/devices/bus/adamnet/fdc.c create mode 100644 src/devices/bus/adamnet/fdc.h create mode 100644 src/devices/bus/adamnet/kb.c create mode 100644 src/devices/bus/adamnet/kb.h create mode 100644 src/devices/bus/adamnet/printer.c create mode 100644 src/devices/bus/adamnet/printer.h create mode 100644 src/devices/bus/adamnet/spi.c create mode 100644 src/devices/bus/adamnet/spi.h create mode 100644 src/devices/bus/amiga/zorro/a2052.c create mode 100644 src/devices/bus/amiga/zorro/a2052.h create mode 100644 src/devices/bus/amiga/zorro/a2232.c create mode 100644 src/devices/bus/amiga/zorro/a2232.h create mode 100644 src/devices/bus/amiga/zorro/a590.c create mode 100644 src/devices/bus/amiga/zorro/a590.h create mode 100644 src/devices/bus/amiga/zorro/action_replay.c create mode 100644 src/devices/bus/amiga/zorro/action_replay.h create mode 100644 src/devices/bus/amiga/zorro/buddha.c create mode 100644 src/devices/bus/amiga/zorro/buddha.h create mode 100644 src/devices/bus/amiga/zorro/cards.c create mode 100644 src/devices/bus/amiga/zorro/cards.h create mode 100644 src/devices/bus/amiga/zorro/zorro.c create mode 100644 src/devices/bus/amiga/zorro/zorro.h create mode 100644 src/devices/bus/apf/rom.c create mode 100644 src/devices/bus/apf/rom.h create mode 100644 src/devices/bus/apf/slot.c create mode 100644 src/devices/bus/apf/slot.h create mode 100644 src/devices/bus/apricot/cards.c create mode 100644 src/devices/bus/apricot/cards.h create mode 100644 src/devices/bus/apricot/expansion.c create mode 100644 src/devices/bus/apricot/expansion.h create mode 100644 src/devices/bus/apricot/ram.c create mode 100644 src/devices/bus/apricot/ram.h create mode 100644 src/devices/bus/arcadia/rom.c create mode 100644 src/devices/bus/arcadia/rom.h create mode 100644 src/devices/bus/arcadia/slot.c create mode 100644 src/devices/bus/arcadia/slot.h create mode 100644 src/devices/bus/astrocde/exp.c create mode 100644 src/devices/bus/astrocde/exp.h create mode 100644 src/devices/bus/astrocde/ram.c create mode 100644 src/devices/bus/astrocde/ram.h create mode 100644 src/devices/bus/astrocde/rom.c create mode 100644 src/devices/bus/astrocde/rom.h create mode 100644 src/devices/bus/astrocde/slot.c create mode 100644 src/devices/bus/astrocde/slot.h create mode 100644 src/devices/bus/bml3/bml3bus.c create mode 100644 src/devices/bus/bml3/bml3bus.h create mode 100644 src/devices/bus/bml3/bml3kanji.c create mode 100644 src/devices/bus/bml3/bml3kanji.h create mode 100644 src/devices/bus/bml3/bml3mp1802.c create mode 100644 src/devices/bus/bml3/bml3mp1802.h create mode 100644 src/devices/bus/bml3/bml3mp1805.c create mode 100644 src/devices/bus/bml3/bml3mp1805.h create mode 100644 src/devices/bus/bw2/exp.c create mode 100644 src/devices/bus/bw2/exp.h create mode 100644 src/devices/bus/bw2/ramcard.c create mode 100644 src/devices/bus/bw2/ramcard.h create mode 100644 src/devices/bus/c64/16kb.c create mode 100644 src/devices/bus/c64/16kb.h create mode 100644 src/devices/bus/c64/4dxh.c create mode 100644 src/devices/bus/c64/4dxh.h create mode 100644 src/devices/bus/c64/4ksa.c create mode 100644 src/devices/bus/c64/4ksa.h create mode 100644 src/devices/bus/c64/4tba.c create mode 100644 src/devices/bus/c64/4tba.h create mode 100644 src/devices/bus/c64/bn1541.c create mode 100644 src/devices/bus/c64/bn1541.h create mode 100644 src/devices/bus/c64/c128_comal80.c create mode 100644 src/devices/bus/c64/c128_comal80.h create mode 100644 src/devices/bus/c64/c128_partner.c create mode 100644 src/devices/bus/c64/c128_partner.h create mode 100644 src/devices/bus/c64/comal80.c create mode 100644 src/devices/bus/c64/comal80.h create mode 100644 src/devices/bus/c64/cpm.c create mode 100644 src/devices/bus/c64/cpm.h create mode 100644 src/devices/bus/c64/currah_speech.c create mode 100644 src/devices/bus/c64/currah_speech.h create mode 100644 src/devices/bus/c64/dela_ep256.c create mode 100644 src/devices/bus/c64/dela_ep256.h create mode 100644 src/devices/bus/c64/dela_ep64.c create mode 100644 src/devices/bus/c64/dela_ep64.h create mode 100644 src/devices/bus/c64/dela_ep7x8.c create mode 100644 src/devices/bus/c64/dela_ep7x8.h create mode 100644 src/devices/bus/c64/dinamic.c create mode 100644 src/devices/bus/c64/dinamic.h create mode 100644 src/devices/bus/c64/dqbb.c create mode 100644 src/devices/bus/c64/dqbb.h create mode 100644 src/devices/bus/c64/easy_calc_result.c create mode 100644 src/devices/bus/c64/easy_calc_result.h create mode 100644 src/devices/bus/c64/easyflash.c create mode 100644 src/devices/bus/c64/easyflash.h create mode 100644 src/devices/bus/c64/epyx_fast_load.c create mode 100644 src/devices/bus/c64/epyx_fast_load.h create mode 100644 src/devices/bus/c64/exos.c create mode 100644 src/devices/bus/c64/exos.h create mode 100644 src/devices/bus/c64/exp.c create mode 100644 src/devices/bus/c64/exp.h create mode 100644 src/devices/bus/c64/fcc.c create mode 100644 src/devices/bus/c64/fcc.h create mode 100644 src/devices/bus/c64/final.c create mode 100644 src/devices/bus/c64/final.h create mode 100644 src/devices/bus/c64/final3.c create mode 100644 src/devices/bus/c64/final3.h create mode 100644 src/devices/bus/c64/fun_play.c create mode 100644 src/devices/bus/c64/fun_play.h create mode 100644 src/devices/bus/c64/geocable.c create mode 100644 src/devices/bus/c64/geocable.h create mode 100644 src/devices/bus/c64/georam.c create mode 100644 src/devices/bus/c64/georam.h create mode 100644 src/devices/bus/c64/ide64.c create mode 100644 src/devices/bus/c64/ide64.h create mode 100644 src/devices/bus/c64/ieee488.c create mode 100644 src/devices/bus/c64/ieee488.h create mode 100644 src/devices/bus/c64/kingsoft.c create mode 100644 src/devices/bus/c64/kingsoft.h create mode 100644 src/devices/bus/c64/mach5.c create mode 100644 src/devices/bus/c64/mach5.h create mode 100644 src/devices/bus/c64/magic_desk.c create mode 100644 src/devices/bus/c64/magic_desk.h create mode 100644 src/devices/bus/c64/magic_formel.c create mode 100644 src/devices/bus/c64/magic_formel.h create mode 100644 src/devices/bus/c64/magic_voice.c create mode 100644 src/devices/bus/c64/magic_voice.h create mode 100644 src/devices/bus/c64/midi_maplin.c create mode 100644 src/devices/bus/c64/midi_maplin.h create mode 100644 src/devices/bus/c64/midi_namesoft.c create mode 100644 src/devices/bus/c64/midi_namesoft.h create mode 100644 src/devices/bus/c64/midi_passport.c create mode 100644 src/devices/bus/c64/midi_passport.h create mode 100644 src/devices/bus/c64/midi_sci.c create mode 100644 src/devices/bus/c64/midi_sci.h create mode 100644 src/devices/bus/c64/midi_siel.c create mode 100644 src/devices/bus/c64/midi_siel.h create mode 100644 src/devices/bus/c64/mikro_assembler.c create mode 100644 src/devices/bus/c64/mikro_assembler.h create mode 100644 src/devices/bus/c64/multiscreen.c create mode 100644 src/devices/bus/c64/multiscreen.h create mode 100644 src/devices/bus/c64/music64.c create mode 100644 src/devices/bus/c64/music64.h create mode 100644 src/devices/bus/c64/neoram.c create mode 100644 src/devices/bus/c64/neoram.h create mode 100644 src/devices/bus/c64/ocean.c create mode 100644 src/devices/bus/c64/ocean.h create mode 100644 src/devices/bus/c64/pagefox.c create mode 100644 src/devices/bus/c64/pagefox.h create mode 100644 src/devices/bus/c64/partner.c create mode 100644 src/devices/bus/c64/partner.h create mode 100644 src/devices/bus/c64/prophet64.c create mode 100644 src/devices/bus/c64/prophet64.h create mode 100644 src/devices/bus/c64/ps64.c create mode 100644 src/devices/bus/c64/ps64.h create mode 100644 src/devices/bus/c64/reu.c create mode 100644 src/devices/bus/c64/reu.h create mode 100644 src/devices/bus/c64/rex.c create mode 100644 src/devices/bus/c64/rex.h create mode 100644 src/devices/bus/c64/rex_ep256.c create mode 100644 src/devices/bus/c64/rex_ep256.h create mode 100644 src/devices/bus/c64/ross.c create mode 100644 src/devices/bus/c64/ross.h create mode 100644 src/devices/bus/c64/sfx_sound_expander.c create mode 100644 src/devices/bus/c64/sfx_sound_expander.h create mode 100644 src/devices/bus/c64/silverrock.c create mode 100644 src/devices/bus/c64/silverrock.h create mode 100644 src/devices/bus/c64/simons_basic.c create mode 100644 src/devices/bus/c64/simons_basic.h create mode 100644 src/devices/bus/c64/stardos.c create mode 100644 src/devices/bus/c64/stardos.h create mode 100644 src/devices/bus/c64/std.c create mode 100644 src/devices/bus/c64/std.h create mode 100644 src/devices/bus/c64/structured_basic.c create mode 100644 src/devices/bus/c64/structured_basic.h create mode 100644 src/devices/bus/c64/super_explode.c create mode 100644 src/devices/bus/c64/super_explode.h create mode 100644 src/devices/bus/c64/super_games.c create mode 100644 src/devices/bus/c64/super_games.h create mode 100644 src/devices/bus/c64/supercpu.c create mode 100644 src/devices/bus/c64/supercpu.h create mode 100644 src/devices/bus/c64/sw8k.c create mode 100644 src/devices/bus/c64/sw8k.h create mode 100644 src/devices/bus/c64/swiftlink.c create mode 100644 src/devices/bus/c64/swiftlink.h create mode 100644 src/devices/bus/c64/system3.c create mode 100644 src/devices/bus/c64/system3.h create mode 100644 src/devices/bus/c64/tdos.c create mode 100644 src/devices/bus/c64/tdos.h create mode 100644 src/devices/bus/c64/turbo232.c create mode 100644 src/devices/bus/c64/turbo232.h create mode 100644 src/devices/bus/c64/user.c create mode 100644 src/devices/bus/c64/user.h create mode 100644 src/devices/bus/c64/vizastar.c create mode 100644 src/devices/bus/c64/vizastar.h create mode 100644 src/devices/bus/c64/vw64.c create mode 100644 src/devices/bus/c64/vw64.h create mode 100644 src/devices/bus/c64/warp_speed.c create mode 100644 src/devices/bus/c64/warp_speed.h create mode 100644 src/devices/bus/c64/westermann.c create mode 100644 src/devices/bus/c64/westermann.h create mode 100644 src/devices/bus/c64/xl80.c create mode 100644 src/devices/bus/c64/xl80.h create mode 100644 src/devices/bus/c64/zaxxon.c create mode 100644 src/devices/bus/c64/zaxxon.h create mode 100644 src/devices/bus/cbm2/24k.c create mode 100644 src/devices/bus/cbm2/24k.h create mode 100644 src/devices/bus/cbm2/exp.c create mode 100644 src/devices/bus/cbm2/exp.h create mode 100644 src/devices/bus/cbm2/hrg.c create mode 100644 src/devices/bus/cbm2/hrg.h create mode 100644 src/devices/bus/cbm2/std.c create mode 100644 src/devices/bus/cbm2/std.h create mode 100644 src/devices/bus/cbm2/user.c create mode 100644 src/devices/bus/cbm2/user.h create mode 100644 src/devices/bus/cbmiec/c1526.c create mode 100644 src/devices/bus/cbmiec/c1526.h create mode 100644 src/devices/bus/cbmiec/c1541.c create mode 100644 src/devices/bus/cbmiec/c1541.h create mode 100644 src/devices/bus/cbmiec/c1571.c create mode 100644 src/devices/bus/cbmiec/c1571.h create mode 100644 src/devices/bus/cbmiec/c1581.c create mode 100644 src/devices/bus/cbmiec/c1581.h create mode 100644 src/devices/bus/cbmiec/c64_nl10.c create mode 100644 src/devices/bus/cbmiec/c64_nl10.h create mode 100644 src/devices/bus/cbmiec/cbmiec.c create mode 100644 src/devices/bus/cbmiec/cbmiec.h create mode 100644 src/devices/bus/cbmiec/cmdhd.c create mode 100644 src/devices/bus/cbmiec/cmdhd.h create mode 100644 src/devices/bus/cbmiec/diag264_lb_iec.c create mode 100644 src/devices/bus/cbmiec/diag264_lb_iec.h create mode 100644 src/devices/bus/cbmiec/fd2000.c create mode 100644 src/devices/bus/cbmiec/fd2000.h create mode 100644 src/devices/bus/cbmiec/interpod.c create mode 100644 src/devices/bus/cbmiec/interpod.h create mode 100644 src/devices/bus/cbmiec/serialbox.c create mode 100644 src/devices/bus/cbmiec/serialbox.h create mode 100644 src/devices/bus/cbmiec/vic1515.c create mode 100644 src/devices/bus/cbmiec/vic1515.h create mode 100644 src/devices/bus/cbmiec/vic1520.c create mode 100644 src/devices/bus/cbmiec/vic1520.h create mode 100644 src/devices/bus/centronics/comxpl80.c create mode 100644 src/devices/bus/centronics/comxpl80.h create mode 100644 src/devices/bus/centronics/covox.c create mode 100644 src/devices/bus/centronics/covox.h create mode 100644 src/devices/bus/centronics/ctronics.c create mode 100644 src/devices/bus/centronics/ctronics.h create mode 100644 src/devices/bus/centronics/digiblst.c create mode 100644 src/devices/bus/centronics/digiblst.h create mode 100644 src/devices/bus/centronics/dsjoy.c create mode 100644 src/devices/bus/centronics/dsjoy.h create mode 100644 src/devices/bus/centronics/epson_ex800.c create mode 100644 src/devices/bus/centronics/epson_ex800.h create mode 100644 src/devices/bus/centronics/epson_lx800.c create mode 100644 src/devices/bus/centronics/epson_lx800.h create mode 100644 src/devices/bus/centronics/epson_lx810l.c create mode 100644 src/devices/bus/centronics/epson_lx810l.h create mode 100644 src/devices/bus/centronics/printer.c create mode 100644 src/devices/bus/centronics/printer.h create mode 100644 src/devices/bus/cgenie/expansion/carts.c create mode 100644 src/devices/bus/cgenie/expansion/carts.h create mode 100644 src/devices/bus/cgenie/expansion/expansion.c create mode 100644 src/devices/bus/cgenie/expansion/expansion.h create mode 100644 src/devices/bus/cgenie/expansion/floppy.c create mode 100644 src/devices/bus/cgenie/expansion/floppy.h create mode 100644 src/devices/bus/cgenie/parallel/carts.c create mode 100644 src/devices/bus/cgenie/parallel/carts.h create mode 100644 src/devices/bus/cgenie/parallel/joystick.c create mode 100644 src/devices/bus/cgenie/parallel/joystick.h create mode 100644 src/devices/bus/cgenie/parallel/parallel.c create mode 100644 src/devices/bus/cgenie/parallel/parallel.h create mode 100644 src/devices/bus/cgenie/parallel/printer.c create mode 100644 src/devices/bus/cgenie/parallel/printer.h create mode 100644 src/devices/bus/chanf/rom.c create mode 100644 src/devices/bus/chanf/rom.h create mode 100644 src/devices/bus/chanf/slot.c create mode 100644 src/devices/bus/chanf/slot.h create mode 100644 src/devices/bus/coco/coco_232.c create mode 100644 src/devices/bus/coco/coco_232.h create mode 100644 src/devices/bus/coco/coco_dwsock.c create mode 100644 src/devices/bus/coco/coco_dwsock.h create mode 100644 src/devices/bus/coco/coco_fdc.c create mode 100644 src/devices/bus/coco/coco_fdc.h create mode 100644 src/devices/bus/coco/coco_multi.c create mode 100644 src/devices/bus/coco/coco_multi.h create mode 100644 src/devices/bus/coco/coco_orch90.c create mode 100644 src/devices/bus/coco/coco_orch90.h create mode 100644 src/devices/bus/coco/coco_pak.c create mode 100644 src/devices/bus/coco/coco_pak.h create mode 100644 src/devices/bus/coco/cococart.c create mode 100644 src/devices/bus/coco/cococart.h create mode 100644 src/devices/bus/coleco/ctrl.c create mode 100644 src/devices/bus/coleco/ctrl.h create mode 100644 src/devices/bus/coleco/exp.c create mode 100644 src/devices/bus/coleco/exp.h create mode 100644 src/devices/bus/coleco/hand.c create mode 100644 src/devices/bus/coleco/hand.h create mode 100644 src/devices/bus/coleco/sac.c create mode 100644 src/devices/bus/coleco/sac.h create mode 100644 src/devices/bus/coleco/std.c create mode 100644 src/devices/bus/coleco/std.h create mode 100644 src/devices/bus/coleco/xin1.c create mode 100644 src/devices/bus/coleco/xin1.h create mode 100644 src/devices/bus/compucolor/floppy.c create mode 100644 src/devices/bus/compucolor/floppy.h create mode 100644 src/devices/bus/comx35/clm.c create mode 100644 src/devices/bus/comx35/clm.h create mode 100644 src/devices/bus/comx35/eprom.c create mode 100644 src/devices/bus/comx35/eprom.h create mode 100644 src/devices/bus/comx35/exp.c create mode 100644 src/devices/bus/comx35/exp.h create mode 100644 src/devices/bus/comx35/expbox.c create mode 100644 src/devices/bus/comx35/expbox.h create mode 100644 src/devices/bus/comx35/fdc.c create mode 100644 src/devices/bus/comx35/fdc.h create mode 100644 src/devices/bus/comx35/joycard.c create mode 100644 src/devices/bus/comx35/joycard.h create mode 100644 src/devices/bus/comx35/printer.c create mode 100644 src/devices/bus/comx35/printer.h create mode 100644 src/devices/bus/comx35/ram.c create mode 100644 src/devices/bus/comx35/ram.h create mode 100644 src/devices/bus/comx35/thermal.c create mode 100644 src/devices/bus/comx35/thermal.h create mode 100644 src/devices/bus/cpc/amdrum.c create mode 100644 src/devices/bus/cpc/amdrum.h create mode 100644 src/devices/bus/cpc/brunword4.c create mode 100644 src/devices/bus/cpc/brunword4.h create mode 100644 src/devices/bus/cpc/cpc_pds.c create mode 100644 src/devices/bus/cpc/cpc_pds.h create mode 100644 src/devices/bus/cpc/cpc_rom.c create mode 100644 src/devices/bus/cpc/cpc_rom.h create mode 100644 src/devices/bus/cpc/cpc_rs232.c create mode 100644 src/devices/bus/cpc/cpc_rs232.h create mode 100644 src/devices/bus/cpc/cpc_ssa1.c create mode 100644 src/devices/bus/cpc/cpc_ssa1.h create mode 100644 src/devices/bus/cpc/cpcexp.c create mode 100644 src/devices/bus/cpc/cpcexp.h create mode 100644 src/devices/bus/cpc/ddi1.c create mode 100644 src/devices/bus/cpc/ddi1.h create mode 100644 src/devices/bus/cpc/hd20.c create mode 100644 src/devices/bus/cpc/hd20.h create mode 100644 src/devices/bus/cpc/magicsound.c create mode 100644 src/devices/bus/cpc/magicsound.h create mode 100644 src/devices/bus/cpc/mface2.c create mode 100644 src/devices/bus/cpc/mface2.h create mode 100644 src/devices/bus/cpc/playcity.c create mode 100644 src/devices/bus/cpc/playcity.h create mode 100644 src/devices/bus/cpc/smartwatch.c create mode 100644 src/devices/bus/cpc/smartwatch.h create mode 100644 src/devices/bus/cpc/symbfac2.c create mode 100644 src/devices/bus/cpc/symbfac2.h create mode 100644 src/devices/bus/crvision/rom.c create mode 100644 src/devices/bus/crvision/rom.h create mode 100644 src/devices/bus/crvision/slot.c create mode 100644 src/devices/bus/crvision/slot.h create mode 100644 src/devices/bus/dmv/dmvbus.c create mode 100644 src/devices/bus/dmv/dmvbus.h create mode 100644 src/devices/bus/dmv/k210.c create mode 100644 src/devices/bus/dmv/k210.h create mode 100644 src/devices/bus/dmv/k220.c create mode 100644 src/devices/bus/dmv/k220.h create mode 100644 src/devices/bus/dmv/k230.c create mode 100644 src/devices/bus/dmv/k230.h create mode 100644 src/devices/bus/dmv/k233.c create mode 100644 src/devices/bus/dmv/k233.h create mode 100644 src/devices/bus/dmv/k801.c create mode 100644 src/devices/bus/dmv/k801.h create mode 100644 src/devices/bus/dmv/k803.c create mode 100644 src/devices/bus/dmv/k803.h create mode 100644 src/devices/bus/dmv/k806.c create mode 100644 src/devices/bus/dmv/k806.h create mode 100644 src/devices/bus/dmv/ram.c create mode 100644 src/devices/bus/dmv/ram.h create mode 100644 src/devices/bus/ecbbus/ecbbus.c create mode 100644 src/devices/bus/ecbbus/ecbbus.h create mode 100644 src/devices/bus/ecbbus/grip.c create mode 100644 src/devices/bus/ecbbus/grip.h create mode 100644 src/devices/bus/econet/e01.c create mode 100644 src/devices/bus/econet/e01.h create mode 100644 src/devices/bus/econet/econet.c create mode 100644 src/devices/bus/econet/econet.h create mode 100644 src/devices/bus/ep64/exdos.c create mode 100644 src/devices/bus/ep64/exdos.h create mode 100644 src/devices/bus/ep64/exp.c create mode 100644 src/devices/bus/ep64/exp.h create mode 100644 src/devices/bus/epson_sio/epson_sio.c create mode 100644 src/devices/bus/epson_sio/epson_sio.h create mode 100644 src/devices/bus/epson_sio/pf10.c create mode 100644 src/devices/bus/epson_sio/pf10.h create mode 100644 src/devices/bus/epson_sio/tf20.c create mode 100644 src/devices/bus/epson_sio/tf20.h create mode 100644 src/devices/bus/gameboy/gb_slot.c create mode 100644 src/devices/bus/gameboy/gb_slot.h create mode 100644 src/devices/bus/gameboy/mbc.c create mode 100644 src/devices/bus/gameboy/mbc.h create mode 100644 src/devices/bus/gameboy/rom.c create mode 100644 src/devices/bus/gameboy/rom.h create mode 100644 src/devices/bus/gamegear/ggext.c create mode 100644 src/devices/bus/gamegear/ggext.h create mode 100644 src/devices/bus/gamegear/smsctrladp.c create mode 100644 src/devices/bus/gamegear/smsctrladp.h create mode 100644 src/devices/bus/gba/gba_slot.c create mode 100644 src/devices/bus/gba/gba_slot.h create mode 100644 src/devices/bus/gba/rom.c create mode 100644 src/devices/bus/gba/rom.h create mode 100644 src/devices/bus/generic/carts.c create mode 100644 src/devices/bus/generic/carts.h create mode 100644 src/devices/bus/generic/ram.c create mode 100644 src/devices/bus/generic/ram.h create mode 100644 src/devices/bus/generic/rom.c create mode 100644 src/devices/bus/generic/rom.h create mode 100644 src/devices/bus/generic/slot.c create mode 100644 src/devices/bus/generic/slot.h create mode 100644 src/devices/bus/ieee488/c2031.c create mode 100644 src/devices/bus/ieee488/c2031.h create mode 100644 src/devices/bus/ieee488/c2040.c create mode 100644 src/devices/bus/ieee488/c2040.h create mode 100644 src/devices/bus/ieee488/c2040fdc.c create mode 100644 src/devices/bus/ieee488/c2040fdc.h create mode 100644 src/devices/bus/ieee488/c8050.c create mode 100644 src/devices/bus/ieee488/c8050.h create mode 100644 src/devices/bus/ieee488/c8050fdc.c create mode 100644 src/devices/bus/ieee488/c8050fdc.h create mode 100644 src/devices/bus/ieee488/c8280.c create mode 100644 src/devices/bus/ieee488/c8280.h create mode 100644 src/devices/bus/ieee488/d9060.c create mode 100644 src/devices/bus/ieee488/d9060.h create mode 100644 src/devices/bus/ieee488/hardbox.c create mode 100644 src/devices/bus/ieee488/hardbox.h create mode 100644 src/devices/bus/ieee488/ieee488.c create mode 100644 src/devices/bus/ieee488/ieee488.h create mode 100644 src/devices/bus/ieee488/shark.c create mode 100644 src/devices/bus/ieee488/shark.h create mode 100644 src/devices/bus/ieee488/softbox.c create mode 100644 src/devices/bus/ieee488/softbox.h create mode 100644 src/devices/bus/imi7000/imi5000h.c create mode 100644 src/devices/bus/imi7000/imi5000h.h create mode 100644 src/devices/bus/imi7000/imi7000.c create mode 100644 src/devices/bus/imi7000/imi7000.h create mode 100644 src/devices/bus/intv/ecs.c create mode 100644 src/devices/bus/intv/ecs.h create mode 100644 src/devices/bus/intv/rom.c create mode 100644 src/devices/bus/intv/rom.h create mode 100644 src/devices/bus/intv/slot.c create mode 100644 src/devices/bus/intv/slot.h create mode 100644 src/devices/bus/intv/voice.c create mode 100644 src/devices/bus/intv/voice.h create mode 100644 src/devices/bus/iq151/disc2.c create mode 100644 src/devices/bus/iq151/disc2.h create mode 100644 src/devices/bus/iq151/grafik.c create mode 100644 src/devices/bus/iq151/grafik.h create mode 100644 src/devices/bus/iq151/iq151.c create mode 100644 src/devices/bus/iq151/iq151.h create mode 100644 src/devices/bus/iq151/minigraf.c create mode 100644 src/devices/bus/iq151/minigraf.h create mode 100644 src/devices/bus/iq151/ms151a.c create mode 100644 src/devices/bus/iq151/ms151a.h create mode 100644 src/devices/bus/iq151/rom.c create mode 100644 src/devices/bus/iq151/rom.h create mode 100644 src/devices/bus/iq151/staper.c create mode 100644 src/devices/bus/iq151/staper.h create mode 100644 src/devices/bus/iq151/video32.c create mode 100644 src/devices/bus/iq151/video32.h create mode 100644 src/devices/bus/iq151/video64.c create mode 100644 src/devices/bus/iq151/video64.h create mode 100644 src/devices/bus/isa/3c503.c create mode 100644 src/devices/bus/isa/3c503.h create mode 100644 src/devices/bus/isa/3c505.c create mode 100644 src/devices/bus/isa/3c505.h create mode 100644 src/devices/bus/isa/adlib.c create mode 100644 src/devices/bus/isa/adlib.h create mode 100644 src/devices/bus/isa/aga.c create mode 100644 src/devices/bus/isa/aga.h create mode 100644 src/devices/bus/isa/aha1542.c create mode 100644 src/devices/bus/isa/aha1542.h create mode 100644 src/devices/bus/isa/cga.c create mode 100644 src/devices/bus/isa/cga.h create mode 100644 src/devices/bus/isa/com.c create mode 100644 src/devices/bus/isa/com.h create mode 100644 src/devices/bus/isa/dectalk.c create mode 100644 src/devices/bus/isa/dectalk.h create mode 100644 src/devices/bus/isa/ega.c create mode 100644 src/devices/bus/isa/ega.h create mode 100644 src/devices/bus/isa/fdc.c create mode 100644 src/devices/bus/isa/fdc.h create mode 100644 src/devices/bus/isa/finalchs.c create mode 100644 src/devices/bus/isa/finalchs.h create mode 100644 src/devices/bus/isa/gblaster.c create mode 100644 src/devices/bus/isa/gblaster.h create mode 100644 src/devices/bus/isa/gus.c create mode 100644 src/devices/bus/isa/gus.h create mode 100644 src/devices/bus/isa/hdc.c create mode 100644 src/devices/bus/isa/hdc.h create mode 100644 src/devices/bus/isa/ibm_mfc.c create mode 100644 src/devices/bus/isa/ibm_mfc.h create mode 100644 src/devices/bus/isa/ide.c create mode 100644 src/devices/bus/isa/ide.h create mode 100644 src/devices/bus/isa/isa.c create mode 100644 src/devices/bus/isa/isa.h create mode 100644 src/devices/bus/isa/isa_cards.c create mode 100644 src/devices/bus/isa/isa_cards.h create mode 100644 src/devices/bus/isa/lpt.c create mode 100644 src/devices/bus/isa/lpt.h create mode 100644 src/devices/bus/isa/mach32.c create mode 100644 src/devices/bus/isa/mach32.h create mode 100644 src/devices/bus/isa/mc1502_fdc.c create mode 100644 src/devices/bus/isa/mc1502_fdc.h create mode 100644 src/devices/bus/isa/mc1502_rom.c create mode 100644 src/devices/bus/isa/mc1502_rom.h create mode 100644 src/devices/bus/isa/mda.c create mode 100644 src/devices/bus/isa/mda.h create mode 100644 src/devices/bus/isa/mpu401.c create mode 100644 src/devices/bus/isa/mpu401.h create mode 100644 src/devices/bus/isa/mufdc.c create mode 100644 src/devices/bus/isa/mufdc.h create mode 100644 src/devices/bus/isa/ne1000.c create mode 100644 src/devices/bus/isa/ne1000.h create mode 100644 src/devices/bus/isa/ne2000.c create mode 100644 src/devices/bus/isa/ne2000.h create mode 100644 src/devices/bus/isa/num9rev.c create mode 100644 src/devices/bus/isa/num9rev.h create mode 100644 src/devices/bus/isa/omti8621.c create mode 100644 src/devices/bus/isa/omti8621.h create mode 100644 src/devices/bus/isa/p1_fdc.c create mode 100644 src/devices/bus/isa/p1_fdc.h create mode 100644 src/devices/bus/isa/p1_hdc.c create mode 100644 src/devices/bus/isa/p1_hdc.h create mode 100644 src/devices/bus/isa/p1_rom.c create mode 100644 src/devices/bus/isa/p1_rom.h create mode 100644 src/devices/bus/isa/pc1640_iga.c create mode 100644 src/devices/bus/isa/pc1640_iga.h create mode 100644 src/devices/bus/isa/pds.c create mode 100644 src/devices/bus/isa/pds.h create mode 100644 src/devices/bus/isa/pgc.c create mode 100644 src/devices/bus/isa/pgc.h create mode 100644 src/devices/bus/isa/s3virge.c create mode 100644 src/devices/bus/isa/s3virge.h create mode 100644 src/devices/bus/isa/sb16.c create mode 100644 src/devices/bus/isa/sb16.h create mode 100644 src/devices/bus/isa/sblaster.c create mode 100644 src/devices/bus/isa/sblaster.h create mode 100644 src/devices/bus/isa/sc499.c create mode 100644 src/devices/bus/isa/sc499.h create mode 100644 src/devices/bus/isa/side116.c create mode 100644 src/devices/bus/isa/side116.h create mode 100644 src/devices/bus/isa/ssi2001.c create mode 100644 src/devices/bus/isa/ssi2001.h create mode 100644 src/devices/bus/isa/stereo_fx.c create mode 100644 src/devices/bus/isa/stereo_fx.h create mode 100644 src/devices/bus/isa/svga_cirrus.c create mode 100644 src/devices/bus/isa/svga_cirrus.h create mode 100644 src/devices/bus/isa/svga_s3.c create mode 100644 src/devices/bus/isa/svga_s3.h create mode 100644 src/devices/bus/isa/svga_trident.c create mode 100644 src/devices/bus/isa/svga_trident.h create mode 100644 src/devices/bus/isa/svga_tseng.c create mode 100644 src/devices/bus/isa/svga_tseng.h create mode 100644 src/devices/bus/isa/trident.c create mode 100644 src/devices/bus/isa/trident.h create mode 100644 src/devices/bus/isa/vga.c create mode 100644 src/devices/bus/isa/vga.h create mode 100644 src/devices/bus/isa/vga_ati.c create mode 100644 src/devices/bus/isa/vga_ati.h create mode 100644 src/devices/bus/isa/wd1002a_wx1.c create mode 100644 src/devices/bus/isa/wd1002a_wx1.h create mode 100644 src/devices/bus/isa/wdxt_gen.c create mode 100644 src/devices/bus/isa/wdxt_gen.h create mode 100644 src/devices/bus/isa/xsu_cards.c create mode 100644 src/devices/bus/isa/xsu_cards.h create mode 100644 src/devices/bus/isa/xtide.c create mode 100644 src/devices/bus/isa/xtide.h create mode 100644 src/devices/bus/isbx/compis_fdc.c create mode 100644 src/devices/bus/isbx/compis_fdc.h create mode 100644 src/devices/bus/isbx/isbc_218a.c create mode 100644 src/devices/bus/isbx/isbc_218a.h create mode 100644 src/devices/bus/isbx/isbx.c create mode 100644 src/devices/bus/isbx/isbx.h create mode 100644 src/devices/bus/kc/d002.c create mode 100644 src/devices/bus/kc/d002.h create mode 100644 src/devices/bus/kc/d004.c create mode 100644 src/devices/bus/kc/d004.h create mode 100644 src/devices/bus/kc/kc.c create mode 100644 src/devices/bus/kc/kc.h create mode 100644 src/devices/bus/kc/ram.c create mode 100644 src/devices/bus/kc/ram.h create mode 100644 src/devices/bus/kc/rom.c create mode 100644 src/devices/bus/kc/rom.h create mode 100644 src/devices/bus/lpci/cirrus.c create mode 100644 src/devices/bus/lpci/cirrus.h create mode 100644 src/devices/bus/lpci/i82371ab.c create mode 100644 src/devices/bus/lpci/i82371ab.h create mode 100644 src/devices/bus/lpci/i82371sb.c create mode 100644 src/devices/bus/lpci/i82371sb.h create mode 100644 src/devices/bus/lpci/i82439tx.c create mode 100644 src/devices/bus/lpci/i82439tx.h create mode 100644 src/devices/bus/lpci/mpc105.c create mode 100644 src/devices/bus/lpci/mpc105.h create mode 100644 src/devices/bus/lpci/northbridge.c create mode 100644 src/devices/bus/lpci/northbridge.h create mode 100644 src/devices/bus/lpci/pci.c create mode 100644 src/devices/bus/lpci/pci.h create mode 100644 src/devices/bus/lpci/southbridge.c create mode 100644 src/devices/bus/lpci/southbridge.h create mode 100644 src/devices/bus/macpds/macpds.c create mode 100644 src/devices/bus/macpds/macpds.h create mode 100644 src/devices/bus/macpds/pds_tpdfpd.c create mode 100644 src/devices/bus/macpds/pds_tpdfpd.h create mode 100644 src/devices/bus/megadrive/eeprom.c create mode 100644 src/devices/bus/megadrive/eeprom.h create mode 100644 src/devices/bus/megadrive/ggenie.c create mode 100644 src/devices/bus/megadrive/ggenie.h create mode 100644 src/devices/bus/megadrive/jcart.c create mode 100644 src/devices/bus/megadrive/jcart.h create mode 100644 src/devices/bus/megadrive/md_carts.c create mode 100644 src/devices/bus/megadrive/md_carts.h create mode 100644 src/devices/bus/megadrive/md_slot.c create mode 100644 src/devices/bus/megadrive/md_slot.h create mode 100644 src/devices/bus/megadrive/rom.c create mode 100644 src/devices/bus/megadrive/rom.h create mode 100644 src/devices/bus/megadrive/sk.c create mode 100644 src/devices/bus/megadrive/sk.h create mode 100644 src/devices/bus/megadrive/stm95.c create mode 100644 src/devices/bus/megadrive/stm95.h create mode 100644 src/devices/bus/megadrive/svp.c create mode 100644 src/devices/bus/megadrive/svp.h create mode 100644 src/devices/bus/midi/midi.c create mode 100644 src/devices/bus/midi/midi.h create mode 100644 src/devices/bus/midi/midiinport.c create mode 100644 src/devices/bus/midi/midiinport.h create mode 100644 src/devices/bus/midi/midioutport.c create mode 100644 src/devices/bus/midi/midioutport.h create mode 100644 src/devices/bus/msx_cart/arc.c create mode 100644 src/devices/bus/msx_cart/arc.h create mode 100644 src/devices/bus/msx_cart/ascii.c create mode 100644 src/devices/bus/msx_cart/ascii.h create mode 100644 src/devices/bus/msx_cart/bm_012.c create mode 100644 src/devices/bus/msx_cart/bm_012.h create mode 100644 src/devices/bus/msx_cart/cartridge.c create mode 100644 src/devices/bus/msx_cart/cartridge.h create mode 100644 src/devices/bus/msx_cart/crossblaim.c create mode 100644 src/devices/bus/msx_cart/crossblaim.h create mode 100644 src/devices/bus/msx_cart/disk.c create mode 100644 src/devices/bus/msx_cart/disk.h create mode 100644 src/devices/bus/msx_cart/dooly.c create mode 100644 src/devices/bus/msx_cart/dooly.h create mode 100644 src/devices/bus/msx_cart/fmpac.c create mode 100644 src/devices/bus/msx_cart/fmpac.h create mode 100644 src/devices/bus/msx_cart/fs_sr022.c create mode 100644 src/devices/bus/msx_cart/fs_sr022.h create mode 100644 src/devices/bus/msx_cart/halnote.c create mode 100644 src/devices/bus/msx_cart/halnote.h create mode 100644 src/devices/bus/msx_cart/hfox.c create mode 100644 src/devices/bus/msx_cart/hfox.h create mode 100644 src/devices/bus/msx_cart/holy_quran.c create mode 100644 src/devices/bus/msx_cart/holy_quran.h create mode 100644 src/devices/bus/msx_cart/konami.c create mode 100644 src/devices/bus/msx_cart/konami.h create mode 100644 src/devices/bus/msx_cart/korean.c create mode 100644 src/devices/bus/msx_cart/korean.h create mode 100644 src/devices/bus/msx_cart/majutsushi.c create mode 100644 src/devices/bus/msx_cart/majutsushi.h create mode 100644 src/devices/bus/msx_cart/moonsound.c create mode 100644 src/devices/bus/msx_cart/moonsound.h create mode 100644 src/devices/bus/msx_cart/msx_audio.c create mode 100644 src/devices/bus/msx_cart/msx_audio.h create mode 100644 src/devices/bus/msx_cart/msx_audio_kb.c create mode 100644 src/devices/bus/msx_cart/msx_audio_kb.h create mode 100644 src/devices/bus/msx_cart/msxdos2.c create mode 100644 src/devices/bus/msx_cart/msxdos2.h create mode 100644 src/devices/bus/msx_cart/nomapper.c create mode 100644 src/devices/bus/msx_cart/nomapper.h create mode 100644 src/devices/bus/msx_cart/rtype.c create mode 100644 src/devices/bus/msx_cart/rtype.h create mode 100644 src/devices/bus/msx_cart/super_swangi.c create mode 100644 src/devices/bus/msx_cart/super_swangi.h create mode 100644 src/devices/bus/msx_cart/superloderunner.c create mode 100644 src/devices/bus/msx_cart/superloderunner.h create mode 100644 src/devices/bus/msx_cart/yamaha.c create mode 100644 src/devices/bus/msx_cart/yamaha.h create mode 100644 src/devices/bus/msx_slot/bunsetsu.c create mode 100644 src/devices/bus/msx_slot/bunsetsu.h create mode 100644 src/devices/bus/msx_slot/cartridge.c create mode 100644 src/devices/bus/msx_slot/cartridge.h create mode 100644 src/devices/bus/msx_slot/disk.c create mode 100644 src/devices/bus/msx_slot/disk.h create mode 100644 src/devices/bus/msx_slot/fs4600.c create mode 100644 src/devices/bus/msx_slot/fs4600.h create mode 100644 src/devices/bus/msx_slot/music.c create mode 100644 src/devices/bus/msx_slot/music.h create mode 100644 src/devices/bus/msx_slot/panasonic08.c create mode 100644 src/devices/bus/msx_slot/panasonic08.h create mode 100644 src/devices/bus/msx_slot/ram.c create mode 100644 src/devices/bus/msx_slot/ram.h create mode 100644 src/devices/bus/msx_slot/ram_mm.c create mode 100644 src/devices/bus/msx_slot/ram_mm.h create mode 100644 src/devices/bus/msx_slot/rom.c create mode 100644 src/devices/bus/msx_slot/rom.h create mode 100644 src/devices/bus/msx_slot/slot.c create mode 100644 src/devices/bus/msx_slot/slot.h create mode 100644 src/devices/bus/msx_slot/sony08.c create mode 100644 src/devices/bus/msx_slot/sony08.h create mode 100644 src/devices/bus/nasbus/avc.c create mode 100644 src/devices/bus/nasbus/avc.h create mode 100644 src/devices/bus/nasbus/cards.c create mode 100644 src/devices/bus/nasbus/cards.h create mode 100644 src/devices/bus/nasbus/floppy.c create mode 100644 src/devices/bus/nasbus/floppy.h create mode 100644 src/devices/bus/nasbus/nasbus.c create mode 100644 src/devices/bus/nasbus/nasbus.h create mode 100644 src/devices/bus/neogeo/banked_cart.c create mode 100644 src/devices/bus/neogeo/banked_cart.h create mode 100644 src/devices/bus/neogeo/bootleg_cart.c create mode 100644 src/devices/bus/neogeo/bootleg_cart.h create mode 100644 src/devices/bus/neogeo/bootleg_hybrid_cart.c create mode 100644 src/devices/bus/neogeo/bootleg_hybrid_cart.h create mode 100644 src/devices/bus/neogeo/bootleg_prot.c create mode 100644 src/devices/bus/neogeo/bootleg_prot.h create mode 100644 src/devices/bus/neogeo/cmc_cart.c create mode 100644 src/devices/bus/neogeo/cmc_cart.h create mode 100644 src/devices/bus/neogeo/cmc_prot.c create mode 100644 src/devices/bus/neogeo/cmc_prot.h create mode 100644 src/devices/bus/neogeo/fatfury2_cart.c create mode 100644 src/devices/bus/neogeo/fatfury2_cart.h create mode 100644 src/devices/bus/neogeo/fatfury2_prot.c create mode 100644 src/devices/bus/neogeo/fatfury2_prot.h create mode 100644 src/devices/bus/neogeo/kof2002_cart.c create mode 100644 src/devices/bus/neogeo/kof2002_cart.h create mode 100644 src/devices/bus/neogeo/kof2002_prot.c create mode 100644 src/devices/bus/neogeo/kof2002_prot.h create mode 100644 src/devices/bus/neogeo/kof98_cart.c create mode 100644 src/devices/bus/neogeo/kof98_cart.h create mode 100644 src/devices/bus/neogeo/kof98_prot.c create mode 100644 src/devices/bus/neogeo/kof98_prot.h create mode 100644 src/devices/bus/neogeo/kog_prot.c create mode 100644 src/devices/bus/neogeo/kog_prot.h create mode 100644 src/devices/bus/neogeo/mslugx_cart.c create mode 100644 src/devices/bus/neogeo/mslugx_cart.h create mode 100644 src/devices/bus/neogeo/mslugx_prot.c create mode 100644 src/devices/bus/neogeo/mslugx_prot.h create mode 100644 src/devices/bus/neogeo/neogeo_carts.c create mode 100644 src/devices/bus/neogeo/neogeo_carts.h create mode 100644 src/devices/bus/neogeo/neogeo_helper.c create mode 100644 src/devices/bus/neogeo/neogeo_helper.h create mode 100644 src/devices/bus/neogeo/neogeo_intf.c create mode 100644 src/devices/bus/neogeo/neogeo_intf.h create mode 100644 src/devices/bus/neogeo/neogeo_slot.c create mode 100644 src/devices/bus/neogeo/neogeo_slot.h create mode 100644 src/devices/bus/neogeo/pcm2_cart.c create mode 100644 src/devices/bus/neogeo/pcm2_cart.h create mode 100644 src/devices/bus/neogeo/pcm2_prot.c create mode 100644 src/devices/bus/neogeo/pcm2_prot.h create mode 100644 src/devices/bus/neogeo/pvc_cart.c create mode 100644 src/devices/bus/neogeo/pvc_cart.h create mode 100644 src/devices/bus/neogeo/pvc_prot.c create mode 100644 src/devices/bus/neogeo/pvc_prot.h create mode 100644 src/devices/bus/neogeo/rom.c create mode 100644 src/devices/bus/neogeo/rom.h create mode 100644 src/devices/bus/neogeo/sbp_prot.c create mode 100644 src/devices/bus/neogeo/sbp_prot.h create mode 100644 src/devices/bus/neogeo/sma_cart.c create mode 100644 src/devices/bus/neogeo/sma_cart.h create mode 100644 src/devices/bus/neogeo/sma_prot.c create mode 100644 src/devices/bus/neogeo/sma_prot.h create mode 100644 src/devices/bus/nes/2a03pur.c create mode 100644 src/devices/bus/nes/2a03pur.h create mode 100644 src/devices/bus/nes/act53.c create mode 100644 src/devices/bus/nes/act53.h create mode 100644 src/devices/bus/nes/aladdin.c create mode 100644 src/devices/bus/nes/aladdin.h create mode 100644 src/devices/bus/nes/ave.c create mode 100644 src/devices/bus/nes/ave.h create mode 100644 src/devices/bus/nes/bandai.c create mode 100644 src/devices/bus/nes/bandai.h create mode 100644 src/devices/bus/nes/benshieng.c create mode 100644 src/devices/bus/nes/benshieng.h create mode 100644 src/devices/bus/nes/bootleg.c create mode 100644 src/devices/bus/nes/bootleg.h create mode 100644 src/devices/bus/nes/camerica.c create mode 100644 src/devices/bus/nes/camerica.h create mode 100644 src/devices/bus/nes/cne.c create mode 100644 src/devices/bus/nes/cne.h create mode 100644 src/devices/bus/nes/cony.c create mode 100644 src/devices/bus/nes/cony.h create mode 100644 src/devices/bus/nes/datach.c create mode 100644 src/devices/bus/nes/datach.h create mode 100644 src/devices/bus/nes/discrete.c create mode 100644 src/devices/bus/nes/discrete.h create mode 100644 src/devices/bus/nes/disksys.c create mode 100644 src/devices/bus/nes/disksys.h create mode 100644 src/devices/bus/nes/event.c create mode 100644 src/devices/bus/nes/event.h create mode 100644 src/devices/bus/nes/ggenie.c create mode 100644 src/devices/bus/nes/ggenie.h create mode 100644 src/devices/bus/nes/henggedianzi.c create mode 100644 src/devices/bus/nes/henggedianzi.h create mode 100644 src/devices/bus/nes/hes.c create mode 100644 src/devices/bus/nes/hes.h create mode 100644 src/devices/bus/nes/hosenkan.c create mode 100644 src/devices/bus/nes/hosenkan.h create mode 100644 src/devices/bus/nes/irem.c create mode 100644 src/devices/bus/nes/irem.h create mode 100644 src/devices/bus/nes/jaleco.c create mode 100644 src/devices/bus/nes/jaleco.h create mode 100644 src/devices/bus/nes/jy.c create mode 100644 src/devices/bus/nes/jy.h create mode 100644 src/devices/bus/nes/kaiser.c create mode 100644 src/devices/bus/nes/kaiser.h create mode 100644 src/devices/bus/nes/karastudio.c create mode 100644 src/devices/bus/nes/karastudio.h create mode 100644 src/devices/bus/nes/konami.c create mode 100644 src/devices/bus/nes/konami.h create mode 100644 src/devices/bus/nes/legacy.c create mode 100644 src/devices/bus/nes/legacy.h create mode 100644 src/devices/bus/nes/mmc1.c create mode 100644 src/devices/bus/nes/mmc1.h create mode 100644 src/devices/bus/nes/mmc2.c create mode 100644 src/devices/bus/nes/mmc2.h create mode 100644 src/devices/bus/nes/mmc3.c create mode 100644 src/devices/bus/nes/mmc3.h create mode 100644 src/devices/bus/nes/mmc3_clones.c create mode 100644 src/devices/bus/nes/mmc3_clones.h create mode 100644 src/devices/bus/nes/mmc5.c create mode 100644 src/devices/bus/nes/mmc5.h create mode 100644 src/devices/bus/nes/multigame.c create mode 100644 src/devices/bus/nes/multigame.h create mode 100644 src/devices/bus/nes/namcot.c create mode 100644 src/devices/bus/nes/namcot.h create mode 100644 src/devices/bus/nes/nanjing.c create mode 100644 src/devices/bus/nes/nanjing.h create mode 100644 src/devices/bus/nes/nes_carts.c create mode 100644 src/devices/bus/nes/nes_carts.h create mode 100644 src/devices/bus/nes/nes_ines.inc create mode 100644 src/devices/bus/nes/nes_pcb.inc create mode 100644 src/devices/bus/nes/nes_slot.c create mode 100644 src/devices/bus/nes/nes_slot.h create mode 100644 src/devices/bus/nes/nes_unif.inc create mode 100644 src/devices/bus/nes/ntdec.c create mode 100644 src/devices/bus/nes/ntdec.h create mode 100644 src/devices/bus/nes/nxrom.c create mode 100644 src/devices/bus/nes/nxrom.h create mode 100644 src/devices/bus/nes/pirate.c create mode 100644 src/devices/bus/nes/pirate.h create mode 100644 src/devices/bus/nes/pt554.c create mode 100644 src/devices/bus/nes/pt554.h create mode 100644 src/devices/bus/nes/racermate.c create mode 100644 src/devices/bus/nes/racermate.h create mode 100644 src/devices/bus/nes/rcm.c create mode 100644 src/devices/bus/nes/rcm.h create mode 100644 src/devices/bus/nes/rexsoft.c create mode 100644 src/devices/bus/nes/rexsoft.h create mode 100644 src/devices/bus/nes/sachen.c create mode 100644 src/devices/bus/nes/sachen.h create mode 100644 src/devices/bus/nes/somari.c create mode 100644 src/devices/bus/nes/somari.h create mode 100644 src/devices/bus/nes/sunsoft.c create mode 100644 src/devices/bus/nes/sunsoft.h create mode 100644 src/devices/bus/nes/sunsoft_dcs.c create mode 100644 src/devices/bus/nes/sunsoft_dcs.h create mode 100644 src/devices/bus/nes/taito.c create mode 100644 src/devices/bus/nes/taito.h create mode 100644 src/devices/bus/nes/tengen.c create mode 100644 src/devices/bus/nes/tengen.h create mode 100644 src/devices/bus/nes/txc.c create mode 100644 src/devices/bus/nes/txc.h create mode 100644 src/devices/bus/nes/waixing.c create mode 100644 src/devices/bus/nes/waixing.h create mode 100644 src/devices/bus/nes_ctrl/4score.c create mode 100644 src/devices/bus/nes_ctrl/4score.h create mode 100644 src/devices/bus/nes_ctrl/arkpaddle.c create mode 100644 src/devices/bus/nes_ctrl/arkpaddle.h create mode 100644 src/devices/bus/nes_ctrl/bcbattle.c create mode 100644 src/devices/bus/nes_ctrl/bcbattle.h create mode 100644 src/devices/bus/nes_ctrl/ctrl.c create mode 100644 src/devices/bus/nes_ctrl/ctrl.h create mode 100644 src/devices/bus/nes_ctrl/fckeybrd.c create mode 100644 src/devices/bus/nes_ctrl/fckeybrd.h create mode 100644 src/devices/bus/nes_ctrl/ftrainer.c create mode 100644 src/devices/bus/nes_ctrl/ftrainer.h create mode 100644 src/devices/bus/nes_ctrl/hori.c create mode 100644 src/devices/bus/nes_ctrl/hori.h create mode 100644 src/devices/bus/nes_ctrl/joypad.c create mode 100644 src/devices/bus/nes_ctrl/joypad.h create mode 100644 src/devices/bus/nes_ctrl/konamihs.c create mode 100644 src/devices/bus/nes_ctrl/konamihs.h create mode 100644 src/devices/bus/nes_ctrl/miracle.c create mode 100644 src/devices/bus/nes_ctrl/miracle.h create mode 100644 src/devices/bus/nes_ctrl/mjpanel.c create mode 100644 src/devices/bus/nes_ctrl/mjpanel.h create mode 100644 src/devices/bus/nes_ctrl/pachinko.c create mode 100644 src/devices/bus/nes_ctrl/pachinko.h create mode 100644 src/devices/bus/nes_ctrl/partytap.c create mode 100644 src/devices/bus/nes_ctrl/partytap.h create mode 100644 src/devices/bus/nes_ctrl/powerpad.c create mode 100644 src/devices/bus/nes_ctrl/powerpad.h create mode 100644 src/devices/bus/nes_ctrl/suborkey.c create mode 100644 src/devices/bus/nes_ctrl/suborkey.h create mode 100644 src/devices/bus/nes_ctrl/zapper.c create mode 100644 src/devices/bus/nes_ctrl/zapper.h create mode 100644 src/devices/bus/nubus/nubus.c create mode 100644 src/devices/bus/nubus/nubus.h create mode 100644 src/devices/bus/nubus/nubus_48gc.c create mode 100644 src/devices/bus/nubus/nubus_48gc.h create mode 100644 src/devices/bus/nubus/nubus_asntmc3b.c create mode 100644 src/devices/bus/nubus/nubus_asntmc3b.h create mode 100644 src/devices/bus/nubus/nubus_cb264.c create mode 100644 src/devices/bus/nubus/nubus_cb264.h create mode 100644 src/devices/bus/nubus/nubus_image.c create mode 100644 src/devices/bus/nubus/nubus_image.h create mode 100644 src/devices/bus/nubus/nubus_m2hires.c create mode 100644 src/devices/bus/nubus/nubus_m2hires.h create mode 100644 src/devices/bus/nubus/nubus_m2video.c create mode 100644 src/devices/bus/nubus/nubus_m2video.h create mode 100644 src/devices/bus/nubus/nubus_radiustpd.c create mode 100644 src/devices/bus/nubus/nubus_radiustpd.h create mode 100644 src/devices/bus/nubus/nubus_spec8.c create mode 100644 src/devices/bus/nubus/nubus_spec8.h create mode 100644 src/devices/bus/nubus/nubus_specpdq.c create mode 100644 src/devices/bus/nubus/nubus_specpdq.h create mode 100644 src/devices/bus/nubus/nubus_vikbw.c create mode 100644 src/devices/bus/nubus/nubus_vikbw.h create mode 100644 src/devices/bus/nubus/nubus_wsportrait.c create mode 100644 src/devices/bus/nubus/nubus_wsportrait.h create mode 100644 src/devices/bus/nubus/pds30_30hr.c create mode 100644 src/devices/bus/nubus/pds30_30hr.h create mode 100644 src/devices/bus/nubus/pds30_cb264.c create mode 100644 src/devices/bus/nubus/pds30_cb264.h create mode 100644 src/devices/bus/nubus/pds30_mc30.c create mode 100644 src/devices/bus/nubus/pds30_mc30.h create mode 100644 src/devices/bus/nubus/pds30_procolor816.c create mode 100644 src/devices/bus/nubus/pds30_procolor816.h create mode 100644 src/devices/bus/nubus/pds30_sigmalview.c create mode 100644 src/devices/bus/nubus/pds30_sigmalview.h create mode 100644 src/devices/bus/odyssey2/chess.c create mode 100644 src/devices/bus/odyssey2/chess.h create mode 100644 src/devices/bus/odyssey2/rom.c create mode 100644 src/devices/bus/odyssey2/rom.h create mode 100644 src/devices/bus/odyssey2/slot.c create mode 100644 src/devices/bus/odyssey2/slot.h create mode 100644 src/devices/bus/odyssey2/voice.c create mode 100644 src/devices/bus/odyssey2/voice.h create mode 100644 src/devices/bus/oricext/jasmin.c create mode 100644 src/devices/bus/oricext/jasmin.h create mode 100644 src/devices/bus/oricext/microdisc.c create mode 100644 src/devices/bus/oricext/microdisc.h create mode 100644 src/devices/bus/oricext/oricext.c create mode 100644 src/devices/bus/oricext/oricext.h create mode 100644 src/devices/bus/pc_joy/pc_joy.c create mode 100644 src/devices/bus/pc_joy/pc_joy.h create mode 100644 src/devices/bus/pc_joy/pc_joy_sw.c create mode 100644 src/devices/bus/pc_joy/pc_joy_sw.h create mode 100644 src/devices/bus/pc_kbd/ec1841.c create mode 100644 src/devices/bus/pc_kbd/ec1841.h create mode 100644 src/devices/bus/pc_kbd/iskr1030.c create mode 100644 src/devices/bus/pc_kbd/iskr1030.h create mode 100644 src/devices/bus/pc_kbd/keyboards.c create mode 100644 src/devices/bus/pc_kbd/keyboards.h create mode 100644 src/devices/bus/pc_kbd/keytro.c create mode 100644 src/devices/bus/pc_kbd/keytro.h create mode 100644 src/devices/bus/pc_kbd/msnat.c create mode 100644 src/devices/bus/pc_kbd/msnat.h create mode 100644 src/devices/bus/pc_kbd/pc83.c create mode 100644 src/devices/bus/pc_kbd/pc83.h create mode 100644 src/devices/bus/pc_kbd/pc_kbdc.c create mode 100644 src/devices/bus/pc_kbd/pc_kbdc.h create mode 100644 src/devices/bus/pc_kbd/pcat84.c create mode 100644 src/devices/bus/pc_kbd/pcat84.h create mode 100644 src/devices/bus/pc_kbd/pcxt83.c create mode 100644 src/devices/bus/pc_kbd/pcxt83.h create mode 100644 src/devices/bus/pce/pce_rom.c create mode 100644 src/devices/bus/pce/pce_rom.h create mode 100644 src/devices/bus/pce/pce_slot.c create mode 100644 src/devices/bus/pce/pce_slot.h create mode 100644 src/devices/bus/pet/64k.c create mode 100644 src/devices/bus/pet/64k.h create mode 100644 src/devices/bus/pet/c2n.c create mode 100644 src/devices/bus/pet/c2n.h create mode 100644 src/devices/bus/pet/cass.c create mode 100644 src/devices/bus/pet/cass.h create mode 100644 src/devices/bus/pet/cb2snd.c create mode 100644 src/devices/bus/pet/cb2snd.h create mode 100644 src/devices/bus/pet/diag.c create mode 100644 src/devices/bus/pet/diag.h create mode 100644 src/devices/bus/pet/diag264_lb_tape.c create mode 100644 src/devices/bus/pet/diag264_lb_tape.h create mode 100644 src/devices/bus/pet/exp.c create mode 100644 src/devices/bus/pet/exp.h create mode 100644 src/devices/bus/pet/hsg.c create mode 100644 src/devices/bus/pet/hsg.h create mode 100644 src/devices/bus/pet/petuja.c create mode 100644 src/devices/bus/pet/petuja.h create mode 100644 src/devices/bus/pet/superpet.c create mode 100644 src/devices/bus/pet/superpet.h create mode 100644 src/devices/bus/pet/user.c create mode 100644 src/devices/bus/pet/user.h create mode 100644 src/devices/bus/plus4/c1551.c create mode 100644 src/devices/bus/plus4/c1551.h create mode 100644 src/devices/bus/plus4/diag264_lb_user.c create mode 100644 src/devices/bus/plus4/diag264_lb_user.h create mode 100644 src/devices/bus/plus4/exp.c create mode 100644 src/devices/bus/plus4/exp.h create mode 100644 src/devices/bus/plus4/sid.c create mode 100644 src/devices/bus/plus4/sid.h create mode 100644 src/devices/bus/plus4/std.c create mode 100644 src/devices/bus/plus4/std.h create mode 100644 src/devices/bus/plus4/user.c create mode 100644 src/devices/bus/plus4/user.h create mode 100644 src/devices/bus/psx/analogue.c create mode 100644 src/devices/bus/psx/analogue.h create mode 100644 src/devices/bus/psx/ctlrport.c create mode 100644 src/devices/bus/psx/ctlrport.h create mode 100644 src/devices/bus/psx/memcard.c create mode 100644 src/devices/bus/psx/memcard.h create mode 100644 src/devices/bus/psx/multitap.c create mode 100644 src/devices/bus/psx/multitap.h create mode 100644 src/devices/bus/ql/cst_q_plus4.c create mode 100644 src/devices/bus/ql/cst_q_plus4.h create mode 100644 src/devices/bus/ql/cst_qdisc.c create mode 100644 src/devices/bus/ql/cst_qdisc.h create mode 100644 src/devices/bus/ql/cumana_fdi.c create mode 100644 src/devices/bus/ql/cumana_fdi.h create mode 100644 src/devices/bus/ql/exp.c create mode 100644 src/devices/bus/ql/exp.h create mode 100644 src/devices/bus/ql/kempston_di.c create mode 100644 src/devices/bus/ql/kempston_di.h create mode 100644 src/devices/bus/ql/miracle_gold_card.c create mode 100644 src/devices/bus/ql/miracle_gold_card.h create mode 100644 src/devices/bus/ql/miracle_hd.c create mode 100644 src/devices/bus/ql/miracle_hd.h create mode 100644 src/devices/bus/ql/mp_fdi.c create mode 100644 src/devices/bus/ql/mp_fdi.h create mode 100644 src/devices/bus/ql/opd_basic_master.c create mode 100644 src/devices/bus/ql/opd_basic_master.h create mode 100644 src/devices/bus/ql/pcml_qdisk.c create mode 100644 src/devices/bus/ql/pcml_qdisk.h create mode 100644 src/devices/bus/ql/qubide.c create mode 100644 src/devices/bus/ql/qubide.h create mode 100644 src/devices/bus/ql/rom.c create mode 100644 src/devices/bus/ql/rom.h create mode 100644 src/devices/bus/ql/sandy_superdisk.c create mode 100644 src/devices/bus/ql/sandy_superdisk.h create mode 100644 src/devices/bus/ql/sandy_superqboard.c create mode 100644 src/devices/bus/ql/sandy_superqboard.h create mode 100644 src/devices/bus/ql/std.c create mode 100644 src/devices/bus/ql/std.h create mode 100644 src/devices/bus/ql/trumpcard.c create mode 100644 src/devices/bus/ql/trumpcard.h create mode 100644 src/devices/bus/rs232/keyboard.c create mode 100644 src/devices/bus/rs232/keyboard.h create mode 100644 src/devices/bus/rs232/loopback.c create mode 100644 src/devices/bus/rs232/loopback.h create mode 100644 src/devices/bus/rs232/null_modem.c create mode 100644 src/devices/bus/rs232/null_modem.h create mode 100644 src/devices/bus/rs232/printer.c create mode 100644 src/devices/bus/rs232/printer.h create mode 100644 src/devices/bus/rs232/rs232.c create mode 100644 src/devices/bus/rs232/rs232.h create mode 100644 src/devices/bus/rs232/ser_mouse.c create mode 100644 src/devices/bus/rs232/ser_mouse.h create mode 100644 src/devices/bus/rs232/terminal.c create mode 100644 src/devices/bus/rs232/terminal.h create mode 100644 src/devices/bus/rs232/xvd701.c create mode 100644 src/devices/bus/rs232/xvd701.h create mode 100644 src/devices/bus/s100/dj2db.c create mode 100644 src/devices/bus/s100/dj2db.h create mode 100644 src/devices/bus/s100/djdma.c create mode 100644 src/devices/bus/s100/djdma.h create mode 100644 src/devices/bus/s100/mm65k16s.c create mode 100644 src/devices/bus/s100/mm65k16s.h create mode 100644 src/devices/bus/s100/nsmdsa.c create mode 100644 src/devices/bus/s100/nsmdsa.h create mode 100644 src/devices/bus/s100/nsmdsad.c create mode 100644 src/devices/bus/s100/nsmdsad.h create mode 100644 src/devices/bus/s100/s100.c create mode 100644 src/devices/bus/s100/s100.h create mode 100644 src/devices/bus/s100/wunderbus.c create mode 100644 src/devices/bus/s100/wunderbus.h create mode 100644 src/devices/bus/saturn/bram.c create mode 100644 src/devices/bus/saturn/bram.h create mode 100644 src/devices/bus/saturn/dram.c create mode 100644 src/devices/bus/saturn/dram.h create mode 100644 src/devices/bus/saturn/rom.c create mode 100644 src/devices/bus/saturn/rom.h create mode 100644 src/devices/bus/saturn/sat_slot.c create mode 100644 src/devices/bus/saturn/sat_slot.h create mode 100644 src/devices/bus/scsi/acb4070.c create mode 100644 src/devices/bus/scsi/acb4070.h create mode 100644 src/devices/bus/scsi/cdu76s.c create mode 100644 src/devices/bus/scsi/cdu76s.h create mode 100644 src/devices/bus/scsi/d9060hd.c create mode 100644 src/devices/bus/scsi/d9060hd.h create mode 100644 src/devices/bus/scsi/omti5100.c create mode 100644 src/devices/bus/scsi/omti5100.h create mode 100644 src/devices/bus/scsi/pc9801_sasi.c create mode 100644 src/devices/bus/scsi/pc9801_sasi.h create mode 100644 src/devices/bus/scsi/s1410.c create mode 100644 src/devices/bus/scsi/s1410.h create mode 100644 src/devices/bus/scsi/sa1403d.c create mode 100644 src/devices/bus/scsi/sa1403d.h create mode 100644 src/devices/bus/scsi/scsi.c create mode 100644 src/devices/bus/scsi/scsi.h create mode 100644 src/devices/bus/scsi/scsicd.c create mode 100644 src/devices/bus/scsi/scsicd.h create mode 100644 src/devices/bus/scsi/scsihd.c create mode 100644 src/devices/bus/scsi/scsihd.h create mode 100644 src/devices/bus/scsi/scsihle.c create mode 100644 src/devices/bus/scsi/scsihle.h create mode 100644 src/devices/bus/scv/rom.c create mode 100644 src/devices/bus/scv/rom.h create mode 100644 src/devices/bus/scv/slot.c create mode 100644 src/devices/bus/scv/slot.h create mode 100644 src/devices/bus/sega8/ccatch.c create mode 100644 src/devices/bus/sega8/ccatch.h create mode 100644 src/devices/bus/sega8/mgear.c create mode 100644 src/devices/bus/sega8/mgear.h create mode 100644 src/devices/bus/sega8/rom.c create mode 100644 src/devices/bus/sega8/rom.h create mode 100644 src/devices/bus/sega8/sega8_slot.c create mode 100644 src/devices/bus/sega8/sega8_slot.h create mode 100644 src/devices/bus/sms_ctrl/graphic.c create mode 100644 src/devices/bus/sms_ctrl/graphic.h create mode 100644 src/devices/bus/sms_ctrl/joypad.c create mode 100644 src/devices/bus/sms_ctrl/joypad.h create mode 100644 src/devices/bus/sms_ctrl/lphaser.c create mode 100644 src/devices/bus/sms_ctrl/lphaser.h create mode 100644 src/devices/bus/sms_ctrl/multitap.c create mode 100644 src/devices/bus/sms_ctrl/multitap.h create mode 100644 src/devices/bus/sms_ctrl/paddle.c create mode 100644 src/devices/bus/sms_ctrl/paddle.h create mode 100644 src/devices/bus/sms_ctrl/rfu.c create mode 100644 src/devices/bus/sms_ctrl/rfu.h create mode 100644 src/devices/bus/sms_ctrl/smsctrl.c create mode 100644 src/devices/bus/sms_ctrl/smsctrl.h create mode 100644 src/devices/bus/sms_ctrl/sports.c create mode 100644 src/devices/bus/sms_ctrl/sports.h create mode 100644 src/devices/bus/sms_ctrl/sportsjp.c create mode 100644 src/devices/bus/sms_ctrl/sportsjp.h create mode 100644 src/devices/bus/sms_exp/gender.c create mode 100644 src/devices/bus/sms_exp/gender.h create mode 100644 src/devices/bus/sms_exp/smsexp.c create mode 100644 src/devices/bus/sms_exp/smsexp.h create mode 100644 src/devices/bus/snes/bsx.c create mode 100644 src/devices/bus/snes/bsx.h create mode 100644 src/devices/bus/snes/event.c create mode 100644 src/devices/bus/snes/event.h create mode 100644 src/devices/bus/snes/rom.c create mode 100644 src/devices/bus/snes/rom.h create mode 100644 src/devices/bus/snes/rom21.c create mode 100644 src/devices/bus/snes/rom21.h create mode 100644 src/devices/bus/snes/sa1.c create mode 100644 src/devices/bus/snes/sa1.h create mode 100644 src/devices/bus/snes/sdd1.c create mode 100644 src/devices/bus/snes/sdd1.h create mode 100644 src/devices/bus/snes/sfx.c create mode 100644 src/devices/bus/snes/sfx.h create mode 100644 src/devices/bus/snes/sgb.c create mode 100644 src/devices/bus/snes/sgb.h create mode 100644 src/devices/bus/snes/snes_carts.c create mode 100644 src/devices/bus/snes/snes_carts.h create mode 100644 src/devices/bus/snes/snes_slot.c create mode 100644 src/devices/bus/snes/snes_slot.h create mode 100644 src/devices/bus/snes/spc7110.c create mode 100644 src/devices/bus/snes/spc7110.h create mode 100644 src/devices/bus/snes/sufami.c create mode 100644 src/devices/bus/snes/sufami.h create mode 100644 src/devices/bus/snes/upd.c create mode 100644 src/devices/bus/snes/upd.h create mode 100644 src/devices/bus/snes_ctrl/bcbattle.c create mode 100644 src/devices/bus/snes_ctrl/bcbattle.h create mode 100644 src/devices/bus/snes_ctrl/ctrl.c create mode 100644 src/devices/bus/snes_ctrl/ctrl.h create mode 100644 src/devices/bus/snes_ctrl/joypad.c create mode 100644 src/devices/bus/snes_ctrl/joypad.h create mode 100644 src/devices/bus/snes_ctrl/miracle.c create mode 100644 src/devices/bus/snes_ctrl/miracle.h create mode 100644 src/devices/bus/snes_ctrl/mouse.c create mode 100644 src/devices/bus/snes_ctrl/mouse.h create mode 100644 src/devices/bus/snes_ctrl/multitap.c create mode 100644 src/devices/bus/snes_ctrl/multitap.h create mode 100644 src/devices/bus/snes_ctrl/pachinko.c create mode 100644 src/devices/bus/snes_ctrl/pachinko.h create mode 100644 src/devices/bus/snes_ctrl/sscope.c create mode 100644 src/devices/bus/snes_ctrl/sscope.h create mode 100644 src/devices/bus/snes_ctrl/twintap.c create mode 100644 src/devices/bus/snes_ctrl/twintap.h create mode 100644 src/devices/bus/spc1000/exp.c create mode 100644 src/devices/bus/spc1000/exp.h create mode 100644 src/devices/bus/spc1000/fdd.c create mode 100644 src/devices/bus/spc1000/fdd.h create mode 100644 src/devices/bus/spc1000/vdp.c create mode 100644 src/devices/bus/spc1000/vdp.h create mode 100644 src/devices/bus/ti99_peb/bwg.c create mode 100644 src/devices/bus/ti99_peb/bwg.h create mode 100644 src/devices/bus/ti99_peb/evpc.c create mode 100644 src/devices/bus/ti99_peb/evpc.h create mode 100644 src/devices/bus/ti99_peb/hfdc.c create mode 100644 src/devices/bus/ti99_peb/hfdc.h create mode 100644 src/devices/bus/ti99_peb/horizon.c create mode 100644 src/devices/bus/ti99_peb/horizon.h create mode 100644 src/devices/bus/ti99_peb/hsgpl.c create mode 100644 src/devices/bus/ti99_peb/hsgpl.h create mode 100644 src/devices/bus/ti99_peb/memex.c create mode 100644 src/devices/bus/ti99_peb/memex.h create mode 100644 src/devices/bus/ti99_peb/myarcmem.c create mode 100644 src/devices/bus/ti99_peb/myarcmem.h create mode 100644 src/devices/bus/ti99_peb/pcode.c create mode 100644 src/devices/bus/ti99_peb/pcode.h create mode 100644 src/devices/bus/ti99_peb/peribox.c create mode 100644 src/devices/bus/ti99_peb/peribox.h create mode 100644 src/devices/bus/ti99_peb/samsmem.c create mode 100644 src/devices/bus/ti99_peb/samsmem.h create mode 100644 src/devices/bus/ti99_peb/spchsyn.c create mode 100644 src/devices/bus/ti99_peb/spchsyn.h create mode 100644 src/devices/bus/ti99_peb/ti_32kmem.c create mode 100644 src/devices/bus/ti99_peb/ti_32kmem.h create mode 100644 src/devices/bus/ti99_peb/ti_fdc.c create mode 100644 src/devices/bus/ti99_peb/ti_fdc.h create mode 100644 src/devices/bus/ti99_peb/ti_rs232.c create mode 100644 src/devices/bus/ti99_peb/ti_rs232.h create mode 100644 src/devices/bus/ti99_peb/tn_ide.c create mode 100644 src/devices/bus/ti99_peb/tn_ide.h create mode 100644 src/devices/bus/ti99_peb/tn_usbsm.c create mode 100644 src/devices/bus/ti99_peb/tn_usbsm.h create mode 100644 src/devices/bus/ti99x/990_dk.c create mode 100644 src/devices/bus/ti99x/990_dk.h create mode 100644 src/devices/bus/ti99x/990_hd.c create mode 100644 src/devices/bus/ti99x/990_hd.h create mode 100644 src/devices/bus/ti99x/990_tap.c create mode 100644 src/devices/bus/ti99x/990_tap.h create mode 100644 src/devices/bus/ti99x/998board.c create mode 100644 src/devices/bus/ti99x/998board.h create mode 100644 src/devices/bus/ti99x/datamux.c create mode 100644 src/devices/bus/ti99x/datamux.h create mode 100644 src/devices/bus/ti99x/genboard.c create mode 100644 src/devices/bus/ti99x/genboard.h create mode 100644 src/devices/bus/ti99x/grom.c create mode 100644 src/devices/bus/ti99x/grom.h create mode 100644 src/devices/bus/ti99x/gromport.c create mode 100644 src/devices/bus/ti99x/gromport.h create mode 100644 src/devices/bus/ti99x/handset.c create mode 100644 src/devices/bus/ti99x/handset.h create mode 100644 src/devices/bus/ti99x/joyport.c create mode 100644 src/devices/bus/ti99x/joyport.h create mode 100644 src/devices/bus/ti99x/mecmouse.c create mode 100644 src/devices/bus/ti99x/mecmouse.h create mode 100644 src/devices/bus/ti99x/ti99defs.h create mode 100644 src/devices/bus/ti99x/videowrp.c create mode 100644 src/devices/bus/ti99x/videowrp.h create mode 100644 src/devices/bus/tvc/hbf.c create mode 100644 src/devices/bus/tvc/hbf.h create mode 100644 src/devices/bus/tvc/tvc.c create mode 100644 src/devices/bus/tvc/tvc.h create mode 100644 src/devices/bus/vboy/rom.c create mode 100644 src/devices/bus/vboy/rom.h create mode 100644 src/devices/bus/vboy/slot.c create mode 100644 src/devices/bus/vboy/slot.h create mode 100644 src/devices/bus/vc4000/rom.c create mode 100644 src/devices/bus/vc4000/rom.h create mode 100644 src/devices/bus/vc4000/slot.c create mode 100644 src/devices/bus/vc4000/slot.h create mode 100644 src/devices/bus/vcs/compumat.c create mode 100644 src/devices/bus/vcs/compumat.h create mode 100644 src/devices/bus/vcs/dpc.c create mode 100644 src/devices/bus/vcs/dpc.h create mode 100755 src/devices/bus/vcs/rom.c create mode 100755 src/devices/bus/vcs/rom.h create mode 100644 src/devices/bus/vcs/scharger.c create mode 100644 src/devices/bus/vcs/scharger.h create mode 100755 src/devices/bus/vcs/vcs_slot.c create mode 100755 src/devices/bus/vcs/vcs_slot.h create mode 100644 src/devices/bus/vcs_ctrl/ctrl.c create mode 100644 src/devices/bus/vcs_ctrl/ctrl.h create mode 100644 src/devices/bus/vcs_ctrl/joybooster.c create mode 100644 src/devices/bus/vcs_ctrl/joybooster.h create mode 100644 src/devices/bus/vcs_ctrl/joystick.c create mode 100644 src/devices/bus/vcs_ctrl/joystick.h create mode 100644 src/devices/bus/vcs_ctrl/keypad.c create mode 100644 src/devices/bus/vcs_ctrl/keypad.h create mode 100644 src/devices/bus/vcs_ctrl/lightpen.c create mode 100644 src/devices/bus/vcs_ctrl/lightpen.h create mode 100644 src/devices/bus/vcs_ctrl/paddles.c create mode 100644 src/devices/bus/vcs_ctrl/paddles.h create mode 100644 src/devices/bus/vcs_ctrl/wheel.c create mode 100644 src/devices/bus/vcs_ctrl/wheel.h create mode 100644 src/devices/bus/vectrex/rom.c create mode 100644 src/devices/bus/vectrex/rom.h create mode 100644 src/devices/bus/vectrex/slot.c create mode 100644 src/devices/bus/vectrex/slot.h create mode 100644 src/devices/bus/vic10/exp.c create mode 100644 src/devices/bus/vic10/exp.h create mode 100644 src/devices/bus/vic10/std.c create mode 100644 src/devices/bus/vic10/std.h create mode 100644 src/devices/bus/vic20/4cga.c create mode 100644 src/devices/bus/vic20/4cga.h create mode 100644 src/devices/bus/vic20/exp.c create mode 100644 src/devices/bus/vic20/exp.h create mode 100644 src/devices/bus/vic20/fe3.c create mode 100644 src/devices/bus/vic20/fe3.h create mode 100644 src/devices/bus/vic20/megacart.c create mode 100644 src/devices/bus/vic20/megacart.h create mode 100644 src/devices/bus/vic20/std.c create mode 100644 src/devices/bus/vic20/std.h create mode 100644 src/devices/bus/vic20/user.c create mode 100644 src/devices/bus/vic20/user.h create mode 100644 src/devices/bus/vic20/vic1010.c create mode 100644 src/devices/bus/vic20/vic1010.h create mode 100644 src/devices/bus/vic20/vic1011.c create mode 100644 src/devices/bus/vic20/vic1011.h create mode 100644 src/devices/bus/vic20/vic1110.c create mode 100644 src/devices/bus/vic20/vic1110.h create mode 100644 src/devices/bus/vic20/vic1111.c create mode 100644 src/devices/bus/vic20/vic1111.h create mode 100644 src/devices/bus/vic20/vic1112.c create mode 100644 src/devices/bus/vic20/vic1112.h create mode 100644 src/devices/bus/vic20/vic1210.c create mode 100644 src/devices/bus/vic20/vic1210.h create mode 100644 src/devices/bus/vidbrain/exp.c create mode 100644 src/devices/bus/vidbrain/exp.h create mode 100644 src/devices/bus/vidbrain/money_minder.c create mode 100644 src/devices/bus/vidbrain/money_minder.h create mode 100644 src/devices/bus/vidbrain/std.c create mode 100644 src/devices/bus/vidbrain/std.h create mode 100644 src/devices/bus/vidbrain/timeshare.c create mode 100644 src/devices/bus/vidbrain/timeshare.h create mode 100644 src/devices/bus/vip/byteio.c create mode 100644 src/devices/bus/vip/byteio.h create mode 100644 src/devices/bus/vip/exp.c create mode 100644 src/devices/bus/vip/exp.h create mode 100644 src/devices/bus/vip/vp550.c create mode 100644 src/devices/bus/vip/vp550.h create mode 100644 src/devices/bus/vip/vp570.c create mode 100644 src/devices/bus/vip/vp570.h create mode 100644 src/devices/bus/vip/vp575.c create mode 100644 src/devices/bus/vip/vp575.h create mode 100644 src/devices/bus/vip/vp585.c create mode 100644 src/devices/bus/vip/vp585.h create mode 100644 src/devices/bus/vip/vp590.c create mode 100644 src/devices/bus/vip/vp590.h create mode 100644 src/devices/bus/vip/vp595.c create mode 100644 src/devices/bus/vip/vp595.h create mode 100644 src/devices/bus/vip/vp620.c create mode 100644 src/devices/bus/vip/vp620.h create mode 100644 src/devices/bus/vip/vp700.c create mode 100644 src/devices/bus/vip/vp700.h create mode 100644 src/devices/bus/vtech/ioexp/carts.c create mode 100644 src/devices/bus/vtech/ioexp/carts.h create mode 100644 src/devices/bus/vtech/ioexp/ioexp.c create mode 100644 src/devices/bus/vtech/ioexp/ioexp.h create mode 100644 src/devices/bus/vtech/ioexp/joystick.c create mode 100644 src/devices/bus/vtech/ioexp/joystick.h create mode 100644 src/devices/bus/vtech/ioexp/printer.c create mode 100644 src/devices/bus/vtech/ioexp/printer.h create mode 100644 src/devices/bus/vtech/memexp/carts.c create mode 100644 src/devices/bus/vtech/memexp/carts.h create mode 100644 src/devices/bus/vtech/memexp/floppy.c create mode 100644 src/devices/bus/vtech/memexp/floppy.h create mode 100644 src/devices/bus/vtech/memexp/memexp.c create mode 100644 src/devices/bus/vtech/memexp/memexp.h create mode 100644 src/devices/bus/vtech/memexp/memory.c create mode 100644 src/devices/bus/vtech/memexp/memory.h create mode 100644 src/devices/bus/vtech/memexp/rs232.c create mode 100644 src/devices/bus/vtech/memexp/rs232.h create mode 100644 src/devices/bus/vtech/memexp/wordpro.c create mode 100644 src/devices/bus/vtech/memexp/wordpro.h create mode 100644 src/devices/bus/wangpc/emb.c create mode 100644 src/devices/bus/wangpc/emb.h create mode 100644 src/devices/bus/wangpc/lic.c create mode 100644 src/devices/bus/wangpc/lic.h create mode 100644 src/devices/bus/wangpc/lvc.c create mode 100644 src/devices/bus/wangpc/lvc.h create mode 100644 src/devices/bus/wangpc/mcc.c create mode 100644 src/devices/bus/wangpc/mcc.h create mode 100644 src/devices/bus/wangpc/mvc.c create mode 100644 src/devices/bus/wangpc/mvc.h create mode 100644 src/devices/bus/wangpc/rtc.c create mode 100644 src/devices/bus/wangpc/rtc.h create mode 100644 src/devices/bus/wangpc/tig.c create mode 100644 src/devices/bus/wangpc/tig.h create mode 100644 src/devices/bus/wangpc/wangpc.c create mode 100644 src/devices/bus/wangpc/wangpc.h create mode 100644 src/devices/bus/wangpc/wdc.c create mode 100644 src/devices/bus/wangpc/wdc.h create mode 100644 src/devices/bus/wswan/rom.c create mode 100644 src/devices/bus/wswan/rom.h create mode 100644 src/devices/bus/wswan/slot.c create mode 100644 src/devices/bus/wswan/slot.h create mode 100644 src/devices/bus/x68k/x68k_neptunex.c create mode 100644 src/devices/bus/x68k/x68k_neptunex.h create mode 100644 src/devices/bus/x68k/x68k_scsiext.c create mode 100644 src/devices/bus/x68k/x68k_scsiext.h create mode 100644 src/devices/bus/x68k/x68kexp.c create mode 100644 src/devices/bus/x68k/x68kexp.h create mode 100644 src/devices/bus/z88/flash.c create mode 100644 src/devices/bus/z88/flash.h create mode 100644 src/devices/bus/z88/ram.c create mode 100644 src/devices/bus/z88/ram.h create mode 100644 src/devices/bus/z88/rom.c create mode 100644 src/devices/bus/z88/rom.h create mode 100644 src/devices/bus/z88/z88.c create mode 100644 src/devices/bus/z88/z88.h create mode 100644 src/devices/cpu/8x300/8x300.c create mode 100644 src/devices/cpu/8x300/8x300.h create mode 100644 src/devices/cpu/8x300/8x300dasm.c create mode 100644 src/devices/cpu/adsp2100/2100dasm.c create mode 100644 src/devices/cpu/adsp2100/2100ops.inc create mode 100644 src/devices/cpu/adsp2100/adsp2100.c create mode 100644 src/devices/cpu/adsp2100/adsp2100.h create mode 100644 src/devices/cpu/alph8201/8201dasm.c create mode 100644 src/devices/cpu/alph8201/alph8201.c create mode 100644 src/devices/cpu/alph8201/alph8201.h create mode 100644 src/devices/cpu/alto2/a2curt.c create mode 100644 src/devices/cpu/alto2/a2curt.h create mode 100644 src/devices/cpu/alto2/a2dht.c create mode 100644 src/devices/cpu/alto2/a2dht.h create mode 100644 src/devices/cpu/alto2/a2disk.c create mode 100644 src/devices/cpu/alto2/a2disk.h create mode 100644 src/devices/cpu/alto2/a2disp.c create mode 100644 src/devices/cpu/alto2/a2disp.h create mode 100644 src/devices/cpu/alto2/a2dvt.c create mode 100644 src/devices/cpu/alto2/a2dvt.h create mode 100644 src/devices/cpu/alto2/a2dwt.c create mode 100644 src/devices/cpu/alto2/a2dwt.h create mode 100644 src/devices/cpu/alto2/a2emu.c create mode 100644 src/devices/cpu/alto2/a2emu.h create mode 100644 src/devices/cpu/alto2/a2ether.c create mode 100644 src/devices/cpu/alto2/a2ether.h create mode 100644 src/devices/cpu/alto2/a2hw.c create mode 100644 src/devices/cpu/alto2/a2hw.h create mode 100644 src/devices/cpu/alto2/a2jkff.h create mode 100644 src/devices/cpu/alto2/a2kbd.c create mode 100644 src/devices/cpu/alto2/a2kbd.h create mode 100644 src/devices/cpu/alto2/a2ksec.c create mode 100644 src/devices/cpu/alto2/a2ksec.h create mode 100644 src/devices/cpu/alto2/a2kwd.c create mode 100644 src/devices/cpu/alto2/a2kwd.h create mode 100644 src/devices/cpu/alto2/a2mem.c create mode 100644 src/devices/cpu/alto2/a2mem.h create mode 100644 src/devices/cpu/alto2/a2mouse.c create mode 100644 src/devices/cpu/alto2/a2mouse.h create mode 100644 src/devices/cpu/alto2/a2mrt.c create mode 100644 src/devices/cpu/alto2/a2mrt.h create mode 100644 src/devices/cpu/alto2/a2part.c create mode 100644 src/devices/cpu/alto2/a2part.h create mode 100644 src/devices/cpu/alto2/a2ram.c create mode 100644 src/devices/cpu/alto2/a2ram.h create mode 100644 src/devices/cpu/alto2/a2roms.c create mode 100644 src/devices/cpu/alto2/a2roms.h create mode 100644 src/devices/cpu/alto2/alto2cpu.c create mode 100644 src/devices/cpu/alto2/alto2cpu.h create mode 100644 src/devices/cpu/alto2/alto2dsm.c create mode 100644 src/devices/cpu/am29000/am29000.c create mode 100644 src/devices/cpu/am29000/am29000.h create mode 100644 src/devices/cpu/am29000/am29dasm.c create mode 100644 src/devices/cpu/am29000/am29ops.h create mode 100644 src/devices/cpu/amis2000/amis2000.c create mode 100644 src/devices/cpu/amis2000/amis2000.h create mode 100644 src/devices/cpu/amis2000/amis2000d.c create mode 100644 src/devices/cpu/amis2000/amis2000op.c create mode 100644 src/devices/cpu/apexc/apexc.c create mode 100644 src/devices/cpu/apexc/apexc.h create mode 100644 src/devices/cpu/apexc/apexcdsm.c create mode 100644 src/devices/cpu/arc/arc.c create mode 100644 src/devices/cpu/arc/arc.h create mode 100644 src/devices/cpu/arc/arcdasm.c create mode 100644 src/devices/cpu/arcompact/arcompact.c create mode 100644 src/devices/cpu/arcompact/arcompact.h create mode 100644 src/devices/cpu/arcompact/arcompact_common.c create mode 100644 src/devices/cpu/arcompact/arcompact_common.h create mode 100644 src/devices/cpu/arcompact/arcompact_execute.c create mode 100644 src/devices/cpu/arcompact/arcompact_make.py create mode 100644 src/devices/cpu/arcompact/arcompactdasm.c create mode 100644 src/devices/cpu/arcompact/arcompactdasm_dispatch.c create mode 100644 src/devices/cpu/arcompact/arcompactdasm_dispatch.h create mode 100644 src/devices/cpu/arcompact/arcompactdasm_ops.c create mode 100644 src/devices/cpu/arcompact/arcompactdasm_ops.h create mode 100644 src/devices/cpu/arm/arm.c create mode 100644 src/devices/cpu/arm/arm.h create mode 100644 src/devices/cpu/arm/armdasm.c create mode 100644 src/devices/cpu/arm7/arm7.c create mode 100644 src/devices/cpu/arm7/arm7.h create mode 100644 src/devices/cpu/arm7/arm7core.h create mode 100644 src/devices/cpu/arm7/arm7core.inc create mode 100644 src/devices/cpu/arm7/arm7dasm.c create mode 100644 src/devices/cpu/arm7/arm7drc.inc create mode 100644 src/devices/cpu/arm7/arm7help.h create mode 100644 src/devices/cpu/arm7/arm7ops.c create mode 100644 src/devices/cpu/arm7/arm7tdrc.inc create mode 100644 src/devices/cpu/arm7/arm7thmb.c create mode 100644 src/devices/cpu/asap/asap.c create mode 100644 src/devices/cpu/asap/asap.h create mode 100644 src/devices/cpu/asap/asapdasm.c create mode 100644 src/devices/cpu/avr8/avr8.c create mode 100644 src/devices/cpu/avr8/avr8.h create mode 100644 src/devices/cpu/avr8/avr8dasm.c create mode 100644 src/devices/cpu/ccpu/ccpu.c create mode 100644 src/devices/cpu/ccpu/ccpu.h create mode 100644 src/devices/cpu/ccpu/ccpudasm.c create mode 100644 src/devices/cpu/cop400/cop400.c create mode 100644 src/devices/cpu/cop400/cop400.h create mode 100644 src/devices/cpu/cop400/cop400op.inc create mode 100644 src/devices/cpu/cop400/cop410ds.c create mode 100644 src/devices/cpu/cop400/cop420ds.c create mode 100644 src/devices/cpu/cop400/cop440ds.c create mode 100644 src/devices/cpu/cosmac/cosdasm.c create mode 100644 src/devices/cpu/cosmac/cosmac.c create mode 100644 src/devices/cpu/cosmac/cosmac.h create mode 100644 src/devices/cpu/cp1610/1610dasm.c create mode 100644 src/devices/cpu/cp1610/cp1610.c create mode 100644 src/devices/cpu/cp1610/cp1610.h create mode 100644 src/devices/cpu/cubeqcpu/cubedasm.c create mode 100644 src/devices/cpu/cubeqcpu/cubeqcpu.c create mode 100644 src/devices/cpu/cubeqcpu/cubeqcpu.h create mode 100644 src/devices/cpu/drcbec.c create mode 100644 src/devices/cpu/drcbec.h create mode 100644 src/devices/cpu/drcbeut.c create mode 100644 src/devices/cpu/drcbeut.h create mode 100644 src/devices/cpu/drcbex64.c create mode 100644 src/devices/cpu/drcbex64.h create mode 100644 src/devices/cpu/drcbex86.c create mode 100644 src/devices/cpu/drcbex86.h create mode 100644 src/devices/cpu/drccache.c create mode 100644 src/devices/cpu/drccache.h create mode 100644 src/devices/cpu/drcfe.c create mode 100644 src/devices/cpu/drcfe.h create mode 100644 src/devices/cpu/drcuml.c create mode 100644 src/devices/cpu/drcuml.h create mode 100644 src/devices/cpu/drcumlsh.h create mode 100644 src/devices/cpu/dsp16/dsp16.c create mode 100644 src/devices/cpu/dsp16/dsp16.h create mode 100644 src/devices/cpu/dsp16/dsp16dis.c create mode 100644 src/devices/cpu/dsp16/dsp16ops.inc create mode 100644 src/devices/cpu/dsp32/dsp32.c create mode 100644 src/devices/cpu/dsp32/dsp32.h create mode 100644 src/devices/cpu/dsp32/dsp32dis.c create mode 100644 src/devices/cpu/dsp32/dsp32ops.inc create mode 100644 src/devices/cpu/dsp56k/dsp56def.h create mode 100644 src/devices/cpu/dsp56k/dsp56dsm.c create mode 100644 src/devices/cpu/dsp56k/dsp56k.c create mode 100644 src/devices/cpu/dsp56k/dsp56k.h create mode 100644 src/devices/cpu/dsp56k/dsp56mem.c create mode 100644 src/devices/cpu/dsp56k/dsp56mem.h create mode 100644 src/devices/cpu/dsp56k/dsp56ops.inc create mode 100644 src/devices/cpu/dsp56k/dsp56pcu.c create mode 100644 src/devices/cpu/dsp56k/dsp56pcu.h create mode 100644 src/devices/cpu/dsp56k/inst.c create mode 100644 src/devices/cpu/dsp56k/inst.h create mode 100644 src/devices/cpu/dsp56k/opcode.c create mode 100644 src/devices/cpu/dsp56k/opcode.h create mode 100644 src/devices/cpu/dsp56k/pmove.c create mode 100644 src/devices/cpu/dsp56k/pmove.h create mode 100644 src/devices/cpu/dsp56k/tables.c create mode 100644 src/devices/cpu/dsp56k/tables.h create mode 100644 src/devices/cpu/e0c6200/e0c6200.c create mode 100644 src/devices/cpu/e0c6200/e0c6200.h create mode 100644 src/devices/cpu/e0c6200/e0c6200d.c create mode 100644 src/devices/cpu/e0c6200/e0c6200op.inc create mode 100644 src/devices/cpu/e0c6200/e0c6s46.c create mode 100644 src/devices/cpu/e0c6200/e0c6s46.h create mode 100644 src/devices/cpu/e132xs/32xsdasm.c create mode 100644 src/devices/cpu/e132xs/e132xs.c create mode 100644 src/devices/cpu/e132xs/e132xs.h create mode 100644 src/devices/cpu/e132xs/e132xsop.inc create mode 100644 src/devices/cpu/es5510/es5510.c create mode 100644 src/devices/cpu/es5510/es5510.h create mode 100644 src/devices/cpu/esrip/esrip.c create mode 100644 src/devices/cpu/esrip/esrip.h create mode 100644 src/devices/cpu/esrip/esripdsm.c create mode 100644 src/devices/cpu/f8/f8.c create mode 100644 src/devices/cpu/f8/f8.h create mode 100644 src/devices/cpu/f8/f8dasm.c create mode 100644 src/devices/cpu/g65816/g65816.c create mode 100644 src/devices/cpu/g65816/g65816.h create mode 100644 src/devices/cpu/g65816/g65816cm.h create mode 100644 src/devices/cpu/g65816/g65816ds.c create mode 100644 src/devices/cpu/g65816/g65816ds.h create mode 100644 src/devices/cpu/g65816/g65816o0.c create mode 100644 src/devices/cpu/g65816/g65816o1.c create mode 100644 src/devices/cpu/g65816/g65816o2.c create mode 100644 src/devices/cpu/g65816/g65816o3.c create mode 100644 src/devices/cpu/g65816/g65816o4.c create mode 100644 src/devices/cpu/g65816/g65816op.h create mode 100644 src/devices/cpu/h6280/6280dasm.c create mode 100644 src/devices/cpu/h6280/h6280.c create mode 100644 src/devices/cpu/h6280/h6280.h create mode 100644 src/devices/cpu/h8/h8.c create mode 100644 src/devices/cpu/h8/h8.h create mode 100644 src/devices/cpu/h8/h8.lst create mode 100644 src/devices/cpu/h8/h83002.c create mode 100644 src/devices/cpu/h8/h83002.h create mode 100644 src/devices/cpu/h8/h83006.c create mode 100644 src/devices/cpu/h8/h83006.h create mode 100644 src/devices/cpu/h8/h83008.c create mode 100644 src/devices/cpu/h8/h83008.h create mode 100644 src/devices/cpu/h8/h83048.c create mode 100644 src/devices/cpu/h8/h83048.h create mode 100644 src/devices/cpu/h8/h83337.c create mode 100644 src/devices/cpu/h8/h83337.h create mode 100644 src/devices/cpu/h8/h8_adc.c create mode 100644 src/devices/cpu/h8/h8_adc.h create mode 100644 src/devices/cpu/h8/h8_intc.c create mode 100644 src/devices/cpu/h8/h8_intc.h create mode 100644 src/devices/cpu/h8/h8_port.c create mode 100644 src/devices/cpu/h8/h8_port.h create mode 100644 src/devices/cpu/h8/h8_sci.c create mode 100644 src/devices/cpu/h8/h8_sci.h create mode 100644 src/devices/cpu/h8/h8_timer16.c create mode 100644 src/devices/cpu/h8/h8_timer16.h create mode 100644 src/devices/cpu/h8/h8_timer8.c create mode 100644 src/devices/cpu/h8/h8_timer8.h create mode 100644 src/devices/cpu/h8/h8h.c create mode 100644 src/devices/cpu/h8/h8h.h create mode 100644 src/devices/cpu/h8/h8make.py create mode 100644 src/devices/cpu/h8/h8s2000.c create mode 100644 src/devices/cpu/h8/h8s2000.h create mode 100644 src/devices/cpu/h8/h8s2245.c create mode 100644 src/devices/cpu/h8/h8s2245.h create mode 100644 src/devices/cpu/h8/h8s2320.c create mode 100644 src/devices/cpu/h8/h8s2320.h create mode 100644 src/devices/cpu/h8/h8s2357.c create mode 100644 src/devices/cpu/h8/h8s2357.h create mode 100644 src/devices/cpu/h8/h8s2600.c create mode 100644 src/devices/cpu/h8/h8s2600.h create mode 100644 src/devices/cpu/h8/h8s2655.c create mode 100644 src/devices/cpu/h8/h8s2655.h create mode 100644 src/devices/cpu/hcd62121/hcd62121.c create mode 100644 src/devices/cpu/hcd62121/hcd62121.h create mode 100644 src/devices/cpu/hcd62121/hcd62121_ops.h create mode 100644 src/devices/cpu/hcd62121/hcd62121d.c create mode 100644 src/devices/cpu/hd61700/hd61700.c create mode 100644 src/devices/cpu/hd61700/hd61700.h create mode 100644 src/devices/cpu/hd61700/hd61700d.c create mode 100644 src/devices/cpu/hmcs40/hmcs40.c create mode 100644 src/devices/cpu/hmcs40/hmcs40.h create mode 100644 src/devices/cpu/hmcs40/hmcs40d.c create mode 100644 src/devices/cpu/hmcs40/hmcs40op.c create mode 100644 src/devices/cpu/hphybrid/hphybrid.c create mode 100644 src/devices/cpu/hphybrid/hphybrid.h create mode 100644 src/devices/cpu/hphybrid/hphybrid_dasm.c create mode 100644 src/devices/cpu/i386/cycles.h create mode 100644 src/devices/cpu/i386/i386.c create mode 100644 src/devices/cpu/i386/i386.h create mode 100644 src/devices/cpu/i386/i386dasm.c create mode 100644 src/devices/cpu/i386/i386op16.inc create mode 100644 src/devices/cpu/i386/i386op32.inc create mode 100644 src/devices/cpu/i386/i386ops.h create mode 100644 src/devices/cpu/i386/i386ops.inc create mode 100644 src/devices/cpu/i386/i386priv.h create mode 100644 src/devices/cpu/i386/i486ops.inc create mode 100644 src/devices/cpu/i386/pentops.inc create mode 100644 src/devices/cpu/i386/x87ops.inc create mode 100644 src/devices/cpu/i4004/4004dasm.c create mode 100644 src/devices/cpu/i4004/i4004.c create mode 100644 src/devices/cpu/i4004/i4004.h create mode 100644 src/devices/cpu/i8008/8008dasm.c create mode 100644 src/devices/cpu/i8008/i8008.c create mode 100644 src/devices/cpu/i8008/i8008.h create mode 100644 src/devices/cpu/i8085/8085dasm.c create mode 100644 src/devices/cpu/i8085/i8085.c create mode 100644 src/devices/cpu/i8085/i8085.h create mode 100644 src/devices/cpu/i8085/i8085cpu.h create mode 100644 src/devices/cpu/i8089/i8089.c create mode 100644 src/devices/cpu/i8089/i8089.h create mode 100644 src/devices/cpu/i8089/i8089_channel.c create mode 100644 src/devices/cpu/i8089/i8089_channel.h create mode 100644 src/devices/cpu/i8089/i8089_dasm.c create mode 100644 src/devices/cpu/i8089/i8089_ops.c create mode 100644 src/devices/cpu/i86/i186.c create mode 100644 src/devices/cpu/i86/i186.h create mode 100644 src/devices/cpu/i86/i286.c create mode 100644 src/devices/cpu/i86/i286.h create mode 100644 src/devices/cpu/i86/i86.c create mode 100644 src/devices/cpu/i86/i86.h create mode 100644 src/devices/cpu/i86/i86.txt create mode 100644 src/devices/cpu/i86/i86inline.h create mode 100644 src/devices/cpu/i860/i860.c create mode 100644 src/devices/cpu/i860/i860.h create mode 100644 src/devices/cpu/i860/i860dasm.c create mode 100644 src/devices/cpu/i860/i860dec.inc create mode 100644 src/devices/cpu/i860/i860dis.c create mode 100644 src/devices/cpu/i960/i960.c create mode 100644 src/devices/cpu/i960/i960.h create mode 100644 src/devices/cpu/i960/i960dis.c create mode 100644 src/devices/cpu/i960/i960dis.h create mode 100644 src/devices/cpu/ie15/ie15.c create mode 100644 src/devices/cpu/ie15/ie15.h create mode 100644 src/devices/cpu/ie15/ie15dasm.c create mode 100644 src/devices/cpu/jaguar/jagdasm.c create mode 100644 src/devices/cpu/jaguar/jaguar.c create mode 100644 src/devices/cpu/jaguar/jaguar.h create mode 100644 src/devices/cpu/lc8670/lc8670.c create mode 100644 src/devices/cpu/lc8670/lc8670.h create mode 100644 src/devices/cpu/lc8670/lc8670dsm.c create mode 100644 src/devices/cpu/lh5801/5801dasm.c create mode 100644 src/devices/cpu/lh5801/5801tbl.inc create mode 100644 src/devices/cpu/lh5801/lh5801.c create mode 100644 src/devices/cpu/lh5801/lh5801.h create mode 100644 src/devices/cpu/lr35902/lr35902.c create mode 100644 src/devices/cpu/lr35902/lr35902.h create mode 100644 src/devices/cpu/lr35902/lr35902d.c create mode 100644 src/devices/cpu/lr35902/opc_cb.inc create mode 100644 src/devices/cpu/lr35902/opc_main.inc create mode 100644 src/devices/cpu/m37710/m37710.c create mode 100644 src/devices/cpu/m37710/m37710.h create mode 100644 src/devices/cpu/m37710/m37710cm.h create mode 100644 src/devices/cpu/m37710/m37710il.h create mode 100644 src/devices/cpu/m37710/m37710o0.c create mode 100644 src/devices/cpu/m37710/m37710o1.c create mode 100644 src/devices/cpu/m37710/m37710o2.c create mode 100644 src/devices/cpu/m37710/m37710o3.c create mode 100644 src/devices/cpu/m37710/m37710op.h create mode 100644 src/devices/cpu/m37710/m7700ds.c create mode 100644 src/devices/cpu/m37710/m7700ds.h create mode 100644 src/devices/cpu/m6502/ddeco16.lst create mode 100644 src/devices/cpu/m6502/deco16.c create mode 100644 src/devices/cpu/m6502/deco16.h create mode 100644 src/devices/cpu/m6502/dm4510.lst create mode 100644 src/devices/cpu/m6502/dm6502.lst create mode 100644 src/devices/cpu/m6502/dm6509.lst create mode 100644 src/devices/cpu/m6502/dm6510.lst create mode 100644 src/devices/cpu/m6502/dm65c02.lst create mode 100644 src/devices/cpu/m6502/dm65ce02.lst create mode 100644 src/devices/cpu/m6502/dm740.lst create mode 100644 src/devices/cpu/m6502/dn2a03.lst create mode 100644 src/devices/cpu/m6502/dr65c02.lst create mode 100644 src/devices/cpu/m6502/m3745x.c create mode 100644 src/devices/cpu/m6502/m3745x.h create mode 100644 src/devices/cpu/m6502/m4510.c create mode 100644 src/devices/cpu/m6502/m4510.h create mode 100644 src/devices/cpu/m6502/m5074x.c create mode 100644 src/devices/cpu/m6502/m5074x.h create mode 100644 src/devices/cpu/m6502/m6502.c create mode 100644 src/devices/cpu/m6502/m6502.h create mode 100644 src/devices/cpu/m6502/m6502.txt create mode 100755 src/devices/cpu/m6502/m6502make.py create mode 100644 src/devices/cpu/m6502/m6504.c create mode 100644 src/devices/cpu/m6502/m6504.h create mode 100644 src/devices/cpu/m6502/m6509.c create mode 100644 src/devices/cpu/m6502/m6509.h create mode 100644 src/devices/cpu/m6502/m6510.c create mode 100644 src/devices/cpu/m6502/m6510.h create mode 100644 src/devices/cpu/m6502/m6510t.c create mode 100644 src/devices/cpu/m6502/m6510t.h create mode 100644 src/devices/cpu/m6502/m65c02.c create mode 100644 src/devices/cpu/m6502/m65c02.h create mode 100644 src/devices/cpu/m6502/m65ce02.c create mode 100644 src/devices/cpu/m6502/m65ce02.h create mode 100644 src/devices/cpu/m6502/m65sc02.c create mode 100644 src/devices/cpu/m6502/m65sc02.h create mode 100644 src/devices/cpu/m6502/m740.c create mode 100644 src/devices/cpu/m6502/m740.h create mode 100644 src/devices/cpu/m6502/m7501.c create mode 100644 src/devices/cpu/m6502/m7501.h create mode 100644 src/devices/cpu/m6502/m8502.c create mode 100644 src/devices/cpu/m6502/m8502.h create mode 100644 src/devices/cpu/m6502/n2a03.c create mode 100644 src/devices/cpu/m6502/n2a03.h create mode 100644 src/devices/cpu/m6502/odeco16.lst create mode 100644 src/devices/cpu/m6502/om4510.lst create mode 100644 src/devices/cpu/m6502/om6502.lst create mode 100644 src/devices/cpu/m6502/om6509.lst create mode 100644 src/devices/cpu/m6502/om6510.lst create mode 100644 src/devices/cpu/m6502/om65c02.lst create mode 100644 src/devices/cpu/m6502/om65ce02.lst create mode 100644 src/devices/cpu/m6502/om740.lst create mode 100644 src/devices/cpu/m6502/on2a03.lst create mode 100644 src/devices/cpu/m6502/r65c02.c create mode 100644 src/devices/cpu/m6502/r65c02.h create mode 100644 src/devices/cpu/m6800/6800dasm.c create mode 100644 src/devices/cpu/m6800/6800ops.inc create mode 100644 src/devices/cpu/m6800/6800tbl.inc create mode 100644 src/devices/cpu/m6800/m6800.c create mode 100644 src/devices/cpu/m6800/m6800.h create mode 100644 src/devices/cpu/m68000/m68000.h create mode 100644 src/devices/cpu/m68000/m68k_in.c create mode 100644 src/devices/cpu/m68000/m68kcpu.c create mode 100644 src/devices/cpu/m68000/m68kcpu.h create mode 100644 src/devices/cpu/m68000/m68kdasm.c create mode 100644 src/devices/cpu/m68000/m68kfpu.inc create mode 100644 src/devices/cpu/m68000/m68kmake.c create mode 100644 src/devices/cpu/m68000/m68kmmu.h create mode 100644 src/devices/cpu/m68000/m68kops.c create mode 100644 src/devices/cpu/m68000/m68kops.h create mode 100644 src/devices/cpu/m68000/makefile create mode 100644 src/devices/cpu/m6805/6805dasm.c create mode 100644 src/devices/cpu/m6805/6805ops.inc create mode 100644 src/devices/cpu/m6805/m6805.c create mode 100644 src/devices/cpu/m6805/m6805.h create mode 100644 src/devices/cpu/m6809/6309dasm.c create mode 100644 src/devices/cpu/m6809/6809dasm.c create mode 100644 src/devices/cpu/m6809/base6x09.ops create mode 100644 src/devices/cpu/m6809/hd6309.c create mode 100644 src/devices/cpu/m6809/hd6309.h create mode 100644 src/devices/cpu/m6809/hd6309.ops create mode 100644 src/devices/cpu/m6809/knmidasm.c create mode 100644 src/devices/cpu/m6809/konami.c create mode 100644 src/devices/cpu/m6809/konami.h create mode 100644 src/devices/cpu/m6809/konami.ops create mode 100644 src/devices/cpu/m6809/m6809.c create mode 100644 src/devices/cpu/m6809/m6809.h create mode 100644 src/devices/cpu/m6809/m6809.ops create mode 100644 src/devices/cpu/m6809/m6809inl.h create mode 100644 src/devices/cpu/m6809/m6809make.py create mode 100644 src/devices/cpu/mb86233/mb86233.c create mode 100644 src/devices/cpu/mb86233/mb86233.h create mode 100644 src/devices/cpu/mb86233/mb86233d.c create mode 100644 src/devices/cpu/mb86235/mb86235.c create mode 100644 src/devices/cpu/mb86235/mb86235.h create mode 100644 src/devices/cpu/mb86235/mb86235d.c create mode 100644 src/devices/cpu/mb88xx/mb88dasm.c create mode 100644 src/devices/cpu/mb88xx/mb88xx.c create mode 100644 src/devices/cpu/mb88xx/mb88xx.h create mode 100644 src/devices/cpu/mc68hc11/hc11dasm.c create mode 100644 src/devices/cpu/mc68hc11/hc11ops.h create mode 100644 src/devices/cpu/mc68hc11/hc11ops.inc create mode 100644 src/devices/cpu/mc68hc11/mc68hc11.c create mode 100644 src/devices/cpu/mc68hc11/mc68hc11.h create mode 100644 src/devices/cpu/mcs48/mcs48.c create mode 100644 src/devices/cpu/mcs48/mcs48.h create mode 100644 src/devices/cpu/mcs48/mcs48dsm.c create mode 100644 src/devices/cpu/mcs51/mcs51.c create mode 100644 src/devices/cpu/mcs51/mcs51.h create mode 100644 src/devices/cpu/mcs51/mcs51dasm.c create mode 100644 src/devices/cpu/mcs51/mcs51ops.inc create mode 100644 src/devices/cpu/mcs96/i8x9x.c create mode 100644 src/devices/cpu/mcs96/i8x9x.h create mode 100644 src/devices/cpu/mcs96/i8xc196.c create mode 100644 src/devices/cpu/mcs96/i8xc196.h create mode 100644 src/devices/cpu/mcs96/mcs96.c create mode 100644 src/devices/cpu/mcs96/mcs96.h create mode 100644 src/devices/cpu/mcs96/mcs96make.py create mode 100644 src/devices/cpu/mcs96/mcs96ops.lst create mode 100644 src/devices/cpu/melps4/m58846.c create mode 100644 src/devices/cpu/melps4/m58846.h create mode 100644 src/devices/cpu/melps4/melps4.c create mode 100644 src/devices/cpu/melps4/melps4.h create mode 100644 src/devices/cpu/melps4/melps4d.c create mode 100644 src/devices/cpu/melps4/melps4op.c create mode 100644 src/devices/cpu/minx/minx.c create mode 100644 src/devices/cpu/minx/minx.h create mode 100644 src/devices/cpu/minx/minxd.c create mode 100644 src/devices/cpu/minx/minxfunc.h create mode 100644 src/devices/cpu/minx/minxopce.h create mode 100644 src/devices/cpu/minx/minxopcf.h create mode 100644 src/devices/cpu/minx/minxops.h create mode 100644 src/devices/cpu/mips/mips3.c create mode 100644 src/devices/cpu/mips/mips3.h create mode 100644 src/devices/cpu/mips/mips3com.c create mode 100644 src/devices/cpu/mips/mips3com.h create mode 100644 src/devices/cpu/mips/mips3drc.c create mode 100644 src/devices/cpu/mips/mips3dsm.c create mode 100644 src/devices/cpu/mips/mips3fe.c create mode 100644 src/devices/cpu/mips/mips3fe.h create mode 100644 src/devices/cpu/mips/r3000.c create mode 100644 src/devices/cpu/mips/r3000.h create mode 100644 src/devices/cpu/mips/r3kdasm.c create mode 100644 src/devices/cpu/mn10200/mn10200.c create mode 100644 src/devices/cpu/mn10200/mn10200.h create mode 100644 src/devices/cpu/mn10200/mn102dis.c create mode 100644 src/devices/cpu/nec/nec.c create mode 100644 src/devices/cpu/nec/nec.h create mode 100644 src/devices/cpu/nec/necdasm.c create mode 100644 src/devices/cpu/nec/necea.h create mode 100644 src/devices/cpu/nec/necinstr.h create mode 100644 src/devices/cpu/nec/necinstr.inc create mode 100644 src/devices/cpu/nec/necmacro.h create mode 100644 src/devices/cpu/nec/necmodrm.h create mode 100644 src/devices/cpu/nec/necpriv.h create mode 100644 src/devices/cpu/nec/v25.c create mode 100644 src/devices/cpu/nec/v25.h create mode 100644 src/devices/cpu/nec/v25instr.h create mode 100644 src/devices/cpu/nec/v25instr.inc create mode 100644 src/devices/cpu/nec/v25priv.h create mode 100644 src/devices/cpu/nec/v25sfr.c create mode 100644 src/devices/cpu/nec/v53.c create mode 100644 src/devices/cpu/nec/v53.h create mode 100644 src/devices/cpu/pdp1/pdp1.c create mode 100644 src/devices/cpu/pdp1/pdp1.h create mode 100644 src/devices/cpu/pdp1/pdp1dasm.c create mode 100644 src/devices/cpu/pdp1/tx0.c create mode 100644 src/devices/cpu/pdp1/tx0.h create mode 100644 src/devices/cpu/pdp1/tx0dasm.c create mode 100644 src/devices/cpu/pdp8/pdp8.c create mode 100644 src/devices/cpu/pdp8/pdp8.h create mode 100644 src/devices/cpu/pdp8/pdp8dasm.c create mode 100644 src/devices/cpu/pic16c5x/16c5xdsm.c create mode 100644 src/devices/cpu/pic16c5x/dis16c5x.c create mode 100644 src/devices/cpu/pic16c5x/pic16c5x.c create mode 100644 src/devices/cpu/pic16c5x/pic16c5x.h create mode 100644 src/devices/cpu/pic16c62x/16c62xdsm.c create mode 100644 src/devices/cpu/pic16c62x/dis16c62x.c create mode 100644 src/devices/cpu/pic16c62x/pic16c62x.c create mode 100644 src/devices/cpu/pic16c62x/pic16c62x.h create mode 100644 src/devices/cpu/powerpc/drc_ops.c create mode 100644 src/devices/cpu/powerpc/drc_ops.h create mode 100644 src/devices/cpu/powerpc/ppc.c create mode 100644 src/devices/cpu/powerpc/ppc.h create mode 100644 src/devices/cpu/powerpc/ppc403.inc create mode 100644 src/devices/cpu/powerpc/ppc602.inc create mode 100644 src/devices/cpu/powerpc/ppc603.inc create mode 100644 src/devices/cpu/powerpc/ppc_dasm.c create mode 100644 src/devices/cpu/powerpc/ppc_mem.inc create mode 100644 src/devices/cpu/powerpc/ppc_ops.h create mode 100644 src/devices/cpu/powerpc/ppc_ops.inc create mode 100644 src/devices/cpu/powerpc/ppccom.c create mode 100644 src/devices/cpu/powerpc/ppccom.h create mode 100644 src/devices/cpu/powerpc/ppcdrc.c create mode 100644 src/devices/cpu/powerpc/ppcfe.c create mode 100644 src/devices/cpu/powerpc/ppcfe.h create mode 100644 src/devices/cpu/pps4/pps4.c create mode 100644 src/devices/cpu/pps4/pps4.h create mode 100644 src/devices/cpu/pps4/pps4dasm.c create mode 100644 src/devices/cpu/psx/dismips.c create mode 100644 src/devices/cpu/psx/dismips.mak create mode 100644 src/devices/cpu/psx/dma.c create mode 100644 src/devices/cpu/psx/dma.h create mode 100644 src/devices/cpu/psx/gte.c create mode 100644 src/devices/cpu/psx/gte.h create mode 100644 src/devices/cpu/psx/irq.c create mode 100644 src/devices/cpu/psx/irq.h create mode 100644 src/devices/cpu/psx/mdec.c create mode 100644 src/devices/cpu/psx/mdec.h create mode 100644 src/devices/cpu/psx/psx.c create mode 100644 src/devices/cpu/psx/psx.h create mode 100644 src/devices/cpu/psx/psxdasm.c create mode 100644 src/devices/cpu/psx/rcnt.c create mode 100644 src/devices/cpu/psx/rcnt.h create mode 100644 src/devices/cpu/psx/sio.c create mode 100644 src/devices/cpu/psx/sio.h create mode 100644 src/devices/cpu/rsp/clamp.h create mode 100644 src/devices/cpu/rsp/rsp.c create mode 100644 src/devices/cpu/rsp/rsp.h create mode 100644 src/devices/cpu/rsp/rsp_dasm.c create mode 100644 src/devices/cpu/rsp/rspcp2.c create mode 100644 src/devices/cpu/rsp/rspcp2.h create mode 100644 src/devices/cpu/rsp/rspcp2d.c create mode 100644 src/devices/cpu/rsp/rspcp2d.h create mode 100644 src/devices/cpu/rsp/rspdiv.h create mode 100644 src/devices/cpu/rsp/rspdrc.c create mode 100644 src/devices/cpu/rsp/rspfe.c create mode 100644 src/devices/cpu/rsp/rspfe.h create mode 100644 src/devices/cpu/rsp/vabs.h create mode 100644 src/devices/cpu/rsp/vadd.h create mode 100644 src/devices/cpu/rsp/vaddc.h create mode 100644 src/devices/cpu/rsp/vand.h create mode 100644 src/devices/cpu/rsp/vch.h create mode 100644 src/devices/cpu/rsp/vcl.h create mode 100644 src/devices/cpu/rsp/vcmp.h create mode 100644 src/devices/cpu/rsp/vcr.h create mode 100644 src/devices/cpu/rsp/vdivh.h create mode 100644 src/devices/cpu/rsp/vldst.h create mode 100644 src/devices/cpu/rsp/vmac.h create mode 100644 src/devices/cpu/rsp/vmov.h create mode 100644 src/devices/cpu/rsp/vmrg.h create mode 100644 src/devices/cpu/rsp/vmudh.h create mode 100644 src/devices/cpu/rsp/vmul.h create mode 100644 src/devices/cpu/rsp/vmulh.h create mode 100644 src/devices/cpu/rsp/vmull.h create mode 100644 src/devices/cpu/rsp/vmulm.h create mode 100644 src/devices/cpu/rsp/vmuln.h create mode 100644 src/devices/cpu/rsp/vor.h create mode 100644 src/devices/cpu/rsp/vrcpsq.h create mode 100644 src/devices/cpu/rsp/vrsq.h create mode 100644 src/devices/cpu/rsp/vsub.h create mode 100644 src/devices/cpu/rsp/vsubc.h create mode 100644 src/devices/cpu/rsp/vxor.h create mode 100644 src/devices/cpu/s2650/2650dasm.c create mode 100644 src/devices/cpu/s2650/s2650.c create mode 100644 src/devices/cpu/s2650/s2650.h create mode 100644 src/devices/cpu/s2650/s2650cpu.h create mode 100644 src/devices/cpu/saturn/satops.inc create mode 100644 src/devices/cpu/saturn/sattable.inc create mode 100644 src/devices/cpu/saturn/saturn.c create mode 100644 src/devices/cpu/saturn/saturn.h create mode 100644 src/devices/cpu/saturn/saturnds.c create mode 100644 src/devices/cpu/sc61860/readpc.c create mode 100644 src/devices/cpu/sc61860/sc61860.c create mode 100644 src/devices/cpu/sc61860/sc61860.h create mode 100644 src/devices/cpu/sc61860/scdasm.c create mode 100644 src/devices/cpu/sc61860/scops.inc create mode 100644 src/devices/cpu/sc61860/sctable.inc create mode 100644 src/devices/cpu/scmp/scmp.c create mode 100644 src/devices/cpu/scmp/scmp.h create mode 100644 src/devices/cpu/scmp/scmpdasm.c create mode 100644 src/devices/cpu/score/score.c create mode 100644 src/devices/cpu/score/score.h create mode 100644 src/devices/cpu/score/scoredsm.c create mode 100644 src/devices/cpu/score/scorem.h create mode 100644 src/devices/cpu/scudsp/scudsp.c create mode 100644 src/devices/cpu/scudsp/scudsp.h create mode 100644 src/devices/cpu/scudsp/scudspdasm.c create mode 100644 src/devices/cpu/se3208/se3208.c create mode 100644 src/devices/cpu/se3208/se3208.h create mode 100644 src/devices/cpu/se3208/se3208dis.c create mode 100644 src/devices/cpu/sh2/sh2.c create mode 100644 src/devices/cpu/sh2/sh2.h create mode 100644 src/devices/cpu/sh2/sh2comn.c create mode 100644 src/devices/cpu/sh2/sh2comn.h create mode 100644 src/devices/cpu/sh2/sh2dasm.c create mode 100644 src/devices/cpu/sh2/sh2drc.c create mode 100644 src/devices/cpu/sh2/sh2fe.c create mode 100644 src/devices/cpu/sh4/sh3comn.c create mode 100644 src/devices/cpu/sh4/sh3comn.h create mode 100644 src/devices/cpu/sh4/sh4.c create mode 100644 src/devices/cpu/sh4/sh4.h create mode 100644 src/devices/cpu/sh4/sh4comn.c create mode 100644 src/devices/cpu/sh4/sh4comn.h create mode 100644 src/devices/cpu/sh4/sh4dasm.c create mode 100644 src/devices/cpu/sh4/sh4dmac.c create mode 100644 src/devices/cpu/sh4/sh4dmac.h create mode 100644 src/devices/cpu/sh4/sh4regs.h create mode 100644 src/devices/cpu/sh4/sh4tmu.c create mode 100644 src/devices/cpu/sh4/sh4tmu.h create mode 100644 src/devices/cpu/sharc/compute.inc create mode 100644 src/devices/cpu/sharc/sharc.c create mode 100644 src/devices/cpu/sharc/sharc.h create mode 100644 src/devices/cpu/sharc/sharcdma.inc create mode 100644 src/devices/cpu/sharc/sharcdsm.c create mode 100644 src/devices/cpu/sharc/sharcdsm.h create mode 100644 src/devices/cpu/sharc/sharcmem.inc create mode 100644 src/devices/cpu/sharc/sharcops.h create mode 100644 src/devices/cpu/sharc/sharcops.inc create mode 100644 src/devices/cpu/sm510/sm510.c create mode 100644 src/devices/cpu/sm510/sm510.h create mode 100644 src/devices/cpu/sm510/sm510core.c create mode 100644 src/devices/cpu/sm510/sm510d.c create mode 100644 src/devices/cpu/sm510/sm510op.c create mode 100644 src/devices/cpu/sm510/sm511core.c create mode 100644 src/devices/cpu/sm8500/sm8500.c create mode 100644 src/devices/cpu/sm8500/sm8500.h create mode 100644 src/devices/cpu/sm8500/sm8500d.c create mode 100644 src/devices/cpu/sm8500/sm85ops.h create mode 100644 src/devices/cpu/spc700/spc700.c create mode 100644 src/devices/cpu/spc700/spc700.h create mode 100644 src/devices/cpu/spc700/spc700ds.c create mode 100644 src/devices/cpu/spc700/spc700ds.h create mode 100644 src/devices/cpu/ssem/ssem.c create mode 100644 src/devices/cpu/ssem/ssem.h create mode 100644 src/devices/cpu/ssem/ssemdasm.c create mode 100644 src/devices/cpu/ssp1601/ssp1601.c create mode 100644 src/devices/cpu/ssp1601/ssp1601.h create mode 100644 src/devices/cpu/ssp1601/ssp1601d.c create mode 100644 src/devices/cpu/superfx/sfx_dasm.c create mode 100644 src/devices/cpu/superfx/superfx.c create mode 100644 src/devices/cpu/superfx/superfx.h create mode 100644 src/devices/cpu/t11/t11.c create mode 100644 src/devices/cpu/t11/t11.h create mode 100644 src/devices/cpu/t11/t11dasm.c create mode 100644 src/devices/cpu/t11/t11ops.inc create mode 100644 src/devices/cpu/t11/t11table.inc create mode 100644 src/devices/cpu/tlcs90/tlcs90.c create mode 100644 src/devices/cpu/tlcs90/tlcs90.h create mode 100644 src/devices/cpu/tlcs900/900tbl.inc create mode 100644 src/devices/cpu/tlcs900/dasm900.c create mode 100644 src/devices/cpu/tlcs900/tlcs900.c create mode 100644 src/devices/cpu/tlcs900/tlcs900.h create mode 100644 src/devices/cpu/tms0980/tms0980.c create mode 100644 src/devices/cpu/tms0980/tms0980.h create mode 100644 src/devices/cpu/tms0980/tms0980d.c create mode 100644 src/devices/cpu/tms32010/32010dsm.c create mode 100644 src/devices/cpu/tms32010/dis32010.c create mode 100644 src/devices/cpu/tms32010/tms32010.c create mode 100644 src/devices/cpu/tms32010/tms32010.h create mode 100644 src/devices/cpu/tms32025/32025dsm.c create mode 100644 src/devices/cpu/tms32025/dis32025.c create mode 100644 src/devices/cpu/tms32025/tms32025.c create mode 100644 src/devices/cpu/tms32025/tms32025.h create mode 100644 src/devices/cpu/tms32031/32031ops.c create mode 100644 src/devices/cpu/tms32031/dis32031.c create mode 100644 src/devices/cpu/tms32031/tms32031.c create mode 100644 src/devices/cpu/tms32031/tms32031.h create mode 100644 src/devices/cpu/tms32051/32051ops.c create mode 100644 src/devices/cpu/tms32051/32051ops.h create mode 100644 src/devices/cpu/tms32051/dis32051.c create mode 100644 src/devices/cpu/tms32051/tms32051.c create mode 100644 src/devices/cpu/tms32051/tms32051.h create mode 100644 src/devices/cpu/tms32082/dis_mp.c create mode 100644 src/devices/cpu/tms32082/dis_pp.c create mode 100644 src/devices/cpu/tms32082/mp_ops.c create mode 100644 src/devices/cpu/tms32082/tms32082.c create mode 100644 src/devices/cpu/tms32082/tms32082.h create mode 100644 src/devices/cpu/tms34010/34010dsm.c create mode 100644 src/devices/cpu/tms34010/34010fld.c create mode 100644 src/devices/cpu/tms34010/34010gfx.c create mode 100644 src/devices/cpu/tms34010/34010ops.c create mode 100644 src/devices/cpu/tms34010/34010ops.h create mode 100644 src/devices/cpu/tms34010/34010tbl.c create mode 100644 src/devices/cpu/tms34010/dis34010.c create mode 100644 src/devices/cpu/tms34010/makefile create mode 100644 src/devices/cpu/tms34010/tms34010.c create mode 100644 src/devices/cpu/tms34010/tms34010.h create mode 100644 src/devices/cpu/tms57002/57002dsm.c create mode 100644 src/devices/cpu/tms57002/tms57002.c create mode 100644 src/devices/cpu/tms57002/tms57002.h create mode 100644 src/devices/cpu/tms57002/tms57kdec.c create mode 100644 src/devices/cpu/tms57002/tmsinstr.lst create mode 100755 src/devices/cpu/tms57002/tmsmake.py create mode 100644 src/devices/cpu/tms7000/7000dasm.c create mode 100644 src/devices/cpu/tms7000/tms7000.c create mode 100644 src/devices/cpu/tms7000/tms7000.h create mode 100644 src/devices/cpu/tms7000/tms70op.inc create mode 100644 src/devices/cpu/tms9900/9900dasm.c create mode 100644 src/devices/cpu/tms9900/99xxcore.h create mode 100644 src/devices/cpu/tms9900/ti990_10.c create mode 100644 src/devices/cpu/tms9900/ti990_10.h create mode 100644 src/devices/cpu/tms9900/tms9900.c create mode 100644 src/devices/cpu/tms9900/tms9900.h create mode 100644 src/devices/cpu/tms9900/tms9980a.c create mode 100644 src/devices/cpu/tms9900/tms9980a.h create mode 100644 src/devices/cpu/tms9900/tms9995.c create mode 100644 src/devices/cpu/tms9900/tms9995.h create mode 100644 src/devices/cpu/tms9900/tms99com.h create mode 100644 src/devices/cpu/ucom4/ucom4.c create mode 100644 src/devices/cpu/ucom4/ucom4.h create mode 100644 src/devices/cpu/ucom4/ucom4d.c create mode 100644 src/devices/cpu/ucom4/ucom4op.c create mode 100644 src/devices/cpu/uml.c create mode 100644 src/devices/cpu/uml.h create mode 100644 src/devices/cpu/unsp/unsp.c create mode 100644 src/devices/cpu/unsp/unsp.h create mode 100644 src/devices/cpu/unsp/unspdasm.c create mode 100644 src/devices/cpu/upd7725/dasm7725.c create mode 100644 src/devices/cpu/upd7725/upd7725.c create mode 100644 src/devices/cpu/upd7725/upd7725.h create mode 100644 src/devices/cpu/upd7810/upd7810.c create mode 100644 src/devices/cpu/upd7810/upd7810.h create mode 100644 src/devices/cpu/upd7810/upd7810_dasm.c create mode 100644 src/devices/cpu/upd7810/upd7810_macros.h create mode 100644 src/devices/cpu/upd7810/upd7810_opcodes.c create mode 100644 src/devices/cpu/upd7810/upd7810_table.c create mode 100644 src/devices/cpu/v30mz/v30mz.c create mode 100644 src/devices/cpu/v30mz/v30mz.h create mode 100644 src/devices/cpu/v60/am.inc create mode 100644 src/devices/cpu/v60/am1.inc create mode 100644 src/devices/cpu/v60/am2.inc create mode 100644 src/devices/cpu/v60/am3.inc create mode 100644 src/devices/cpu/v60/op12.inc create mode 100644 src/devices/cpu/v60/op2.inc create mode 100644 src/devices/cpu/v60/op3.inc create mode 100644 src/devices/cpu/v60/op4.inc create mode 100644 src/devices/cpu/v60/op5.inc create mode 100644 src/devices/cpu/v60/op6.inc create mode 100644 src/devices/cpu/v60/op7a.inc create mode 100644 src/devices/cpu/v60/optable.inc create mode 100644 src/devices/cpu/v60/v60.c create mode 100644 src/devices/cpu/v60/v60.h create mode 100644 src/devices/cpu/v60/v60d.c create mode 100644 src/devices/cpu/v810/v810.c create mode 100644 src/devices/cpu/v810/v810.h create mode 100644 src/devices/cpu/v810/v810dasm.c create mode 100644 src/devices/cpu/vtlb.c create mode 100644 src/devices/cpu/vtlb.h create mode 100644 src/devices/cpu/x86emit.h create mode 100644 src/devices/cpu/x86log.c create mode 100644 src/devices/cpu/x86log.h create mode 100644 src/devices/cpu/z180/z180.c create mode 100644 src/devices/cpu/z180/z180.h create mode 100644 src/devices/cpu/z180/z180cb.inc create mode 100644 src/devices/cpu/z180/z180dasm.c create mode 100644 src/devices/cpu/z180/z180dd.inc create mode 100644 src/devices/cpu/z180/z180ed.inc create mode 100644 src/devices/cpu/z180/z180fd.inc create mode 100644 src/devices/cpu/z180/z180op.inc create mode 100644 src/devices/cpu/z180/z180ops.h create mode 100644 src/devices/cpu/z180/z180tbl.h create mode 100644 src/devices/cpu/z180/z180xy.inc create mode 100644 src/devices/cpu/z8/z8.c create mode 100644 src/devices/cpu/z8/z8.h create mode 100644 src/devices/cpu/z8/z8dasm.c create mode 100644 src/devices/cpu/z8/z8ops.inc create mode 100644 src/devices/cpu/z80/kl5c80a12.c create mode 100644 src/devices/cpu/z80/kl5c80a12.h create mode 100644 src/devices/cpu/z80/tmpz84c011.c create mode 100644 src/devices/cpu/z80/tmpz84c011.h create mode 100644 src/devices/cpu/z80/tmpz84c015.c create mode 100644 src/devices/cpu/z80/tmpz84c015.h create mode 100644 src/devices/cpu/z80/z80.c create mode 100644 src/devices/cpu/z80/z80.h create mode 100644 src/devices/cpu/z80/z80daisy.c create mode 100644 src/devices/cpu/z80/z80daisy.h create mode 100644 src/devices/cpu/z80/z80dasm.c create mode 100644 src/devices/cpu/z8000/8000dasm.c create mode 100644 src/devices/cpu/z8000/makedab.c create mode 100644 src/devices/cpu/z8000/z8000.c create mode 100644 src/devices/cpu/z8000/z8000.h create mode 100644 src/devices/cpu/z8000/z8000cpu.h create mode 100644 src/devices/cpu/z8000/z8000dab.h create mode 100644 src/devices/cpu/z8000/z8000ops.inc create mode 100644 src/devices/cpu/z8000/z8000tbl.inc create mode 100644 src/devices/imagedev/bitbngr.c create mode 100644 src/devices/imagedev/bitbngr.h create mode 100644 src/devices/imagedev/cassette.c create mode 100644 src/devices/imagedev/cassette.h create mode 100644 src/devices/imagedev/chd_cd.c create mode 100644 src/devices/imagedev/chd_cd.h create mode 100644 src/devices/imagedev/diablo.c create mode 100644 src/devices/imagedev/diablo.h create mode 100644 src/devices/imagedev/flopdrv.c create mode 100644 src/devices/imagedev/flopdrv.h create mode 100644 src/devices/imagedev/floppy.c create mode 100644 src/devices/imagedev/floppy.h create mode 100644 src/devices/imagedev/harddriv.c create mode 100644 src/devices/imagedev/harddriv.h create mode 100644 src/devices/imagedev/mfmhd.c create mode 100644 src/devices/imagedev/mfmhd.h create mode 100644 src/devices/imagedev/midiin.c create mode 100644 src/devices/imagedev/midiin.h create mode 100644 src/devices/imagedev/midiout.c create mode 100644 src/devices/imagedev/midiout.h create mode 100644 src/devices/imagedev/printer.c create mode 100644 src/devices/imagedev/printer.h create mode 100644 src/devices/imagedev/snapquik.c create mode 100644 src/devices/imagedev/snapquik.h create mode 100644 src/devices/machine/40105.c create mode 100644 src/devices/machine/40105.h create mode 100644 src/devices/machine/53c7xx.c create mode 100644 src/devices/machine/53c7xx.h create mode 100644 src/devices/machine/53c810.c create mode 100644 src/devices/machine/53c810.h create mode 100644 src/devices/machine/64h156.c create mode 100644 src/devices/machine/64h156.h create mode 100644 src/devices/machine/6522via.c create mode 100644 src/devices/machine/6522via.h create mode 100644 src/devices/machine/6525tpi.c create mode 100644 src/devices/machine/6525tpi.h create mode 100644 src/devices/machine/6532riot.c create mode 100644 src/devices/machine/6532riot.h create mode 100644 src/devices/machine/6821pia.c create mode 100644 src/devices/machine/6821pia.h create mode 100644 src/devices/machine/68230pit.c create mode 100644 src/devices/machine/68230pit.h create mode 100644 src/devices/machine/68307.c create mode 100644 src/devices/machine/68307.h create mode 100644 src/devices/machine/68307bus.c create mode 100644 src/devices/machine/68307bus.h create mode 100644 src/devices/machine/68307sim.c create mode 100644 src/devices/machine/68307sim.h create mode 100644 src/devices/machine/68307tmu.c create mode 100644 src/devices/machine/68307tmu.h create mode 100644 src/devices/machine/68340.c create mode 100644 src/devices/machine/68340.h create mode 100644 src/devices/machine/68340dma.c create mode 100644 src/devices/machine/68340dma.h create mode 100644 src/devices/machine/68340ser.c create mode 100644 src/devices/machine/68340ser.h create mode 100644 src/devices/machine/68340sim.c create mode 100644 src/devices/machine/68340sim.h create mode 100644 src/devices/machine/68340tmu.c create mode 100644 src/devices/machine/68340tmu.h create mode 100644 src/devices/machine/6840ptm.c create mode 100644 src/devices/machine/6840ptm.h create mode 100644 src/devices/machine/6850acia.c create mode 100644 src/devices/machine/6850acia.h create mode 100644 src/devices/machine/68561mpcc.c create mode 100644 src/devices/machine/68561mpcc.h create mode 100644 src/devices/machine/7200fifo.c create mode 100644 src/devices/machine/7200fifo.h create mode 100644 src/devices/machine/74123.c create mode 100644 src/devices/machine/74123.h create mode 100644 src/devices/machine/74145.c create mode 100644 src/devices/machine/74145.h create mode 100644 src/devices/machine/74148.c create mode 100644 src/devices/machine/74148.h create mode 100644 src/devices/machine/74153.c create mode 100644 src/devices/machine/74153.h create mode 100644 src/devices/machine/74181.c create mode 100644 src/devices/machine/74181.h create mode 100644 src/devices/machine/7474.c create mode 100644 src/devices/machine/7474.h create mode 100644 src/devices/machine/8042kbdc.c create mode 100644 src/devices/machine/8042kbdc.h create mode 100644 src/devices/machine/8530scc.c create mode 100644 src/devices/machine/8530scc.h create mode 100644 src/devices/machine/aakart.c create mode 100644 src/devices/machine/aakart.h create mode 100644 src/devices/machine/adc0808.c create mode 100644 src/devices/machine/adc0808.h create mode 100644 src/devices/machine/adc083x.c create mode 100644 src/devices/machine/adc083x.h create mode 100644 src/devices/machine/adc1038.c create mode 100644 src/devices/machine/adc1038.h create mode 100644 src/devices/machine/adc1213x.c create mode 100644 src/devices/machine/adc1213x.h create mode 100644 src/devices/machine/aicartc.c create mode 100644 src/devices/machine/aicartc.h create mode 100644 src/devices/machine/akiko.c create mode 100644 src/devices/machine/akiko.h create mode 100644 src/devices/machine/am53cf96.c create mode 100644 src/devices/machine/am53cf96.h create mode 100644 src/devices/machine/am9517a.c create mode 100644 src/devices/machine/am9517a.h create mode 100644 src/devices/machine/amigafdc.c create mode 100644 src/devices/machine/amigafdc.h create mode 100644 src/devices/machine/at28c16.c create mode 100644 src/devices/machine/at28c16.h create mode 100644 src/devices/machine/at29x.c create mode 100644 src/devices/machine/at29x.h create mode 100644 src/devices/machine/at45dbxx.c create mode 100644 src/devices/machine/at45dbxx.h create mode 100644 src/devices/machine/at_keybc.c create mode 100644 src/devices/machine/at_keybc.h create mode 100644 src/devices/machine/atadev.c create mode 100644 src/devices/machine/atadev.h create mode 100644 src/devices/machine/ataflash.c create mode 100644 src/devices/machine/ataflash.h create mode 100644 src/devices/machine/atahle.c create mode 100644 src/devices/machine/atahle.h create mode 100644 src/devices/machine/ataintf.c create mode 100644 src/devices/machine/ataintf.h create mode 100644 src/devices/machine/atapicdr.c create mode 100644 src/devices/machine/atapicdr.h create mode 100644 src/devices/machine/atapihle.c create mode 100644 src/devices/machine/atapihle.h create mode 100644 src/devices/machine/autoconfig.c create mode 100644 src/devices/machine/autoconfig.h create mode 100644 src/devices/machine/ay31015.c create mode 100644 src/devices/machine/ay31015.h create mode 100644 src/devices/machine/bankdev.c create mode 100644 src/devices/machine/bankdev.h create mode 100644 src/devices/machine/bcreader.c create mode 100644 src/devices/machine/bcreader.h create mode 100644 src/devices/machine/buffer.c create mode 100644 src/devices/machine/buffer.h create mode 100644 src/devices/machine/cdp1852.c create mode 100644 src/devices/machine/cdp1852.h create mode 100644 src/devices/machine/cdp1871.c create mode 100644 src/devices/machine/cdp1871.h create mode 100644 src/devices/machine/clock.c create mode 100644 src/devices/machine/clock.h create mode 100644 src/devices/machine/com8116.c create mode 100644 src/devices/machine/com8116.h create mode 100644 src/devices/machine/corvushd.c create mode 100644 src/devices/machine/corvushd.h create mode 100644 src/devices/machine/cr511b.c create mode 100644 src/devices/machine/cr511b.h create mode 100644 src/devices/machine/cr589.c create mode 100644 src/devices/machine/cr589.h create mode 100644 src/devices/machine/cs4031.c create mode 100644 src/devices/machine/cs4031.h create mode 100644 src/devices/machine/cs8221.c create mode 100644 src/devices/machine/cs8221.h create mode 100644 src/devices/machine/diablo_hd.c create mode 100644 src/devices/machine/diablo_hd.h create mode 100644 src/devices/machine/dmac.c create mode 100644 src/devices/machine/dmac.h create mode 100644 src/devices/machine/dp8390.c create mode 100644 src/devices/machine/dp8390.h create mode 100644 src/devices/machine/ds1204.c create mode 100644 src/devices/machine/ds1204.h create mode 100644 src/devices/machine/ds128x.c create mode 100644 src/devices/machine/ds128x.h create mode 100644 src/devices/machine/ds1302.c create mode 100644 src/devices/machine/ds1302.h create mode 100644 src/devices/machine/ds1315.c create mode 100644 src/devices/machine/ds1315.h create mode 100644 src/devices/machine/ds2401.c create mode 100644 src/devices/machine/ds2401.h create mode 100644 src/devices/machine/ds2404.c create mode 100644 src/devices/machine/ds2404.h create mode 100644 src/devices/machine/ds75160a.c create mode 100644 src/devices/machine/ds75160a.h create mode 100644 src/devices/machine/ds75161a.c create mode 100644 src/devices/machine/ds75161a.h create mode 100644 src/devices/machine/e0516.c create mode 100644 src/devices/machine/e0516.h create mode 100644 src/devices/machine/e05a03.c create mode 100644 src/devices/machine/e05a03.h create mode 100644 src/devices/machine/e05a30.c create mode 100644 src/devices/machine/e05a30.h create mode 100644 src/devices/machine/eeprom.c create mode 100644 src/devices/machine/eeprom.h create mode 100644 src/devices/machine/eeprompar.c create mode 100644 src/devices/machine/eeprompar.h create mode 100644 src/devices/machine/eepromser.c create mode 100644 src/devices/machine/eepromser.h create mode 100644 src/devices/machine/er2055.c create mode 100644 src/devices/machine/er2055.h create mode 100644 src/devices/machine/f3853.c create mode 100644 src/devices/machine/f3853.h create mode 100644 src/devices/machine/fdc37c665gt.c create mode 100644 src/devices/machine/fdc37c665gt.h create mode 100644 src/devices/machine/fdc_pll.c create mode 100644 src/devices/machine/fdc_pll.h create mode 100644 src/devices/machine/gayle.c create mode 100644 src/devices/machine/gayle.h create mode 100644 src/devices/machine/generic.c create mode 100644 src/devices/machine/generic.h create mode 100644 src/devices/machine/hd63450.c create mode 100644 src/devices/machine/hd63450.h create mode 100644 src/devices/machine/hd64610.c create mode 100644 src/devices/machine/hd64610.h create mode 100644 src/devices/machine/hdc92x4.c create mode 100644 src/devices/machine/hdc92x4.h create mode 100644 src/devices/machine/i2cmem.c create mode 100644 src/devices/machine/i2cmem.h create mode 100644 src/devices/machine/i6300esb.c create mode 100644 src/devices/machine/i6300esb.h create mode 100644 src/devices/machine/i80130.c create mode 100644 src/devices/machine/i80130.h create mode 100644 src/devices/machine/i8155.c create mode 100644 src/devices/machine/i8155.h create mode 100644 src/devices/machine/i8212.c create mode 100644 src/devices/machine/i8212.h create mode 100644 src/devices/machine/i8214.c create mode 100644 src/devices/machine/i8214.h create mode 100644 src/devices/machine/i8243.c create mode 100644 src/devices/machine/i8243.h create mode 100644 src/devices/machine/i8251.c create mode 100644 src/devices/machine/i8251.h create mode 100644 src/devices/machine/i82541.c create mode 100644 src/devices/machine/i82541.h create mode 100644 src/devices/machine/i8255.c create mode 100644 src/devices/machine/i8255.h create mode 100644 src/devices/machine/i8257.c create mode 100644 src/devices/machine/i8257.h create mode 100644 src/devices/machine/i8271.c create mode 100644 src/devices/machine/i8271.h create mode 100644 src/devices/machine/i8279.c create mode 100644 src/devices/machine/i8279.h create mode 100644 src/devices/machine/i82875p.c create mode 100644 src/devices/machine/i82875p.h create mode 100644 src/devices/machine/i8355.c create mode 100644 src/devices/machine/i8355.h create mode 100644 src/devices/machine/idectrl.c create mode 100644 src/devices/machine/idectrl.h create mode 100644 src/devices/machine/idehd.c create mode 100644 src/devices/machine/idehd.h create mode 100644 src/devices/machine/im6402.c create mode 100644 src/devices/machine/im6402.h create mode 100644 src/devices/machine/ins8154.c create mode 100644 src/devices/machine/ins8154.h create mode 100644 src/devices/machine/ins8250.c create mode 100644 src/devices/machine/ins8250.h create mode 100644 src/devices/machine/intelfsh.c create mode 100644 src/devices/machine/intelfsh.h create mode 100644 src/devices/machine/jvsdev.c create mode 100644 src/devices/machine/jvsdev.h create mode 100644 src/devices/machine/jvshost.c create mode 100644 src/devices/machine/jvshost.h create mode 100644 src/devices/machine/k033906.c create mode 100644 src/devices/machine/k033906.h create mode 100644 src/devices/machine/k053252.c create mode 100644 src/devices/machine/k053252.h create mode 100644 src/devices/machine/k056230.c create mode 100644 src/devices/machine/k056230.h create mode 100644 src/devices/machine/kb3600.c create mode 100644 src/devices/machine/kb3600.h create mode 100644 src/devices/machine/keyboard.c create mode 100644 src/devices/machine/keyboard.h create mode 100644 src/devices/machine/kr2376.c create mode 100644 src/devices/machine/kr2376.h create mode 100644 src/devices/machine/laserdsc.c create mode 100644 src/devices/machine/laserdsc.h create mode 100644 src/devices/machine/latch.c create mode 100644 src/devices/machine/latch.h create mode 100644 src/devices/machine/latch8.c create mode 100644 src/devices/machine/latch8.h create mode 100644 src/devices/machine/lc89510.c create mode 100644 src/devices/machine/lc89510.h create mode 100644 src/devices/machine/ldpr8210.c create mode 100644 src/devices/machine/ldpr8210.h create mode 100644 src/devices/machine/ldstub.c create mode 100644 src/devices/machine/ldstub.h create mode 100644 src/devices/machine/ldv1000.c create mode 100644 src/devices/machine/ldv1000.h create mode 100644 src/devices/machine/ldvp931.c create mode 100644 src/devices/machine/ldvp931.h create mode 100644 src/devices/machine/legscsi.c create mode 100644 src/devices/machine/legscsi.h create mode 100644 src/devices/machine/lh5810.c create mode 100644 src/devices/machine/lh5810.h create mode 100644 src/devices/machine/linflash.c create mode 100644 src/devices/machine/linflash.h create mode 100644 src/devices/machine/lpc-acpi.c create mode 100644 src/devices/machine/lpc-acpi.h create mode 100644 src/devices/machine/lpc-pit.c create mode 100644 src/devices/machine/lpc-pit.h create mode 100644 src/devices/machine/lpc-rtc.c create mode 100644 src/devices/machine/lpc-rtc.h create mode 100644 src/devices/machine/lpc.c create mode 100644 src/devices/machine/lpc.h create mode 100644 src/devices/machine/lpci.c create mode 100644 src/devices/machine/lpci.h create mode 100644 src/devices/machine/m6m80011ap.c create mode 100644 src/devices/machine/m6m80011ap.h create mode 100644 src/devices/machine/matsucd.c create mode 100644 src/devices/machine/matsucd.h create mode 100644 src/devices/machine/mb14241.c create mode 100644 src/devices/machine/mb14241.h create mode 100644 src/devices/machine/mb3773.c create mode 100644 src/devices/machine/mb3773.h create mode 100644 src/devices/machine/mb8421.c create mode 100644 src/devices/machine/mb8421.h create mode 100644 src/devices/machine/mb87078.c create mode 100644 src/devices/machine/mb87078.h create mode 100644 src/devices/machine/mb8795.c create mode 100644 src/devices/machine/mb8795.h create mode 100644 src/devices/machine/mb89352.c create mode 100644 src/devices/machine/mb89352.h create mode 100644 src/devices/machine/mb89363b.c create mode 100644 src/devices/machine/mb89363b.h create mode 100644 src/devices/machine/mb89371.c create mode 100644 src/devices/machine/mb89371.h create mode 100644 src/devices/machine/mc146818.c create mode 100644 src/devices/machine/mc146818.h create mode 100644 src/devices/machine/mc2661.c create mode 100644 src/devices/machine/mc2661.h create mode 100644 src/devices/machine/mc68328.c create mode 100644 src/devices/machine/mc68328.h create mode 100644 src/devices/machine/mc6843.c create mode 100644 src/devices/machine/mc6843.h create mode 100644 src/devices/machine/mc6846.c create mode 100644 src/devices/machine/mc6846.h create mode 100644 src/devices/machine/mc6852.c create mode 100644 src/devices/machine/mc6852.h create mode 100644 src/devices/machine/mc6854.c create mode 100644 src/devices/machine/mc6854.h create mode 100644 src/devices/machine/mc68681.c create mode 100644 src/devices/machine/mc68681.h create mode 100644 src/devices/machine/mc68901.c create mode 100644 src/devices/machine/mc68901.h create mode 100644 src/devices/machine/mccs1850.c create mode 100644 src/devices/machine/mccs1850.h create mode 100644 src/devices/machine/mcf5206e.c create mode 100644 src/devices/machine/mcf5206e.h create mode 100644 src/devices/machine/microtch.c create mode 100644 src/devices/machine/microtch.h create mode 100644 src/devices/machine/mm58167.c create mode 100644 src/devices/machine/mm58167.h create mode 100644 src/devices/machine/mm58274c.c create mode 100644 src/devices/machine/mm58274c.h create mode 100644 src/devices/machine/mm74c922.c create mode 100644 src/devices/machine/mm74c922.h create mode 100644 src/devices/machine/mos6526.c create mode 100644 src/devices/machine/mos6526.h create mode 100644 src/devices/machine/mos6529.c create mode 100644 src/devices/machine/mos6529.h create mode 100644 src/devices/machine/mos6530.c create mode 100644 src/devices/machine/mos6530.h create mode 100644 src/devices/machine/mos6530n.c create mode 100644 src/devices/machine/mos6530n.h create mode 100644 src/devices/machine/mos6551.c create mode 100644 src/devices/machine/mos6551.h create mode 100644 src/devices/machine/mos6702.c create mode 100644 src/devices/machine/mos6702.h create mode 100644 src/devices/machine/mos8706.c create mode 100644 src/devices/machine/mos8706.h create mode 100644 src/devices/machine/mos8722.c create mode 100644 src/devices/machine/mos8722.h create mode 100644 src/devices/machine/mos8726.c create mode 100644 src/devices/machine/mos8726.h create mode 100644 src/devices/machine/mpu401.c create mode 100644 src/devices/machine/mpu401.h create mode 100644 src/devices/machine/msm5832.c create mode 100644 src/devices/machine/msm5832.h create mode 100644 src/devices/machine/msm58321.c create mode 100644 src/devices/machine/msm58321.h create mode 100644 src/devices/machine/msm6242.c create mode 100644 src/devices/machine/msm6242.h create mode 100644 src/devices/machine/ncr5380.c create mode 100644 src/devices/machine/ncr5380.h create mode 100644 src/devices/machine/ncr5380n.c create mode 100644 src/devices/machine/ncr5380n.h create mode 100644 src/devices/machine/ncr5390.c create mode 100644 src/devices/machine/ncr5390.h create mode 100644 src/devices/machine/ncr539x.c create mode 100644 src/devices/machine/ncr539x.h create mode 100644 src/devices/machine/netlist.c create mode 100644 src/devices/machine/netlist.h create mode 100644 src/devices/machine/nmc9306.c create mode 100644 src/devices/machine/nmc9306.h create mode 100644 src/devices/machine/nsc810.c create mode 100644 src/devices/machine/nsc810.h create mode 100644 src/devices/machine/nscsi_bus.c create mode 100644 src/devices/machine/nscsi_bus.h create mode 100644 src/devices/machine/nscsi_cb.c create mode 100644 src/devices/machine/nscsi_cb.h create mode 100644 src/devices/machine/nscsi_cd.c create mode 100644 src/devices/machine/nscsi_cd.h create mode 100644 src/devices/machine/nscsi_hd.c create mode 100644 src/devices/machine/nscsi_hd.h create mode 100644 src/devices/machine/nscsi_s1410.c create mode 100644 src/devices/machine/nscsi_s1410.h create mode 100644 src/devices/machine/nvram.c create mode 100644 src/devices/machine/nvram.h create mode 100644 src/devices/machine/pc_fdc.c create mode 100644 src/devices/machine/pc_fdc.h create mode 100644 src/devices/machine/pc_lpt.c create mode 100644 src/devices/machine/pc_lpt.h create mode 100644 src/devices/machine/pccard.c create mode 100644 src/devices/machine/pccard.h create mode 100644 src/devices/machine/pcf8593.c create mode 100644 src/devices/machine/pcf8593.h create mode 100644 src/devices/machine/pci-apic.c create mode 100644 src/devices/machine/pci-apic.h create mode 100644 src/devices/machine/pci-sata.c create mode 100644 src/devices/machine/pci-sata.h create mode 100644 src/devices/machine/pci-smbus.c create mode 100644 src/devices/machine/pci-smbus.h create mode 100644 src/devices/machine/pci-usb.c create mode 100644 src/devices/machine/pci-usb.h create mode 100644 src/devices/machine/pci.c create mode 100644 src/devices/machine/pci.h create mode 100644 src/devices/machine/pci9050.c create mode 100644 src/devices/machine/pci9050.h create mode 100644 src/devices/machine/pckeybrd.c create mode 100644 src/devices/machine/pckeybrd.h create mode 100644 src/devices/machine/pic8259.c create mode 100644 src/devices/machine/pic8259.h create mode 100644 src/devices/machine/pit8253.c create mode 100644 src/devices/machine/pit8253.h create mode 100644 src/devices/machine/pla.c create mode 100644 src/devices/machine/pla.h create mode 100644 src/devices/machine/r10696.c create mode 100644 src/devices/machine/r10696.h create mode 100644 src/devices/machine/r10788.c create mode 100644 src/devices/machine/r10788.h create mode 100644 src/devices/machine/ra17xx.c create mode 100644 src/devices/machine/ra17xx.h create mode 100644 src/devices/machine/ram.c create mode 100644 src/devices/machine/ram.h create mode 100644 src/devices/machine/rescap.h create mode 100644 src/devices/machine/rf5c296.c create mode 100644 src/devices/machine/rf5c296.h create mode 100644 src/devices/machine/roc10937.c create mode 100644 src/devices/machine/roc10937.h create mode 100644 src/devices/machine/rp5c01.c create mode 100644 src/devices/machine/rp5c01.h create mode 100644 src/devices/machine/rp5c15.c create mode 100644 src/devices/machine/rp5c15.h create mode 100644 src/devices/machine/rp5h01.c create mode 100644 src/devices/machine/rp5h01.h create mode 100644 src/devices/machine/rtc4543.c create mode 100644 src/devices/machine/rtc4543.h create mode 100644 src/devices/machine/rtc65271.c create mode 100644 src/devices/machine/rtc65271.h create mode 100644 src/devices/machine/rtc9701.c create mode 100644 src/devices/machine/rtc9701.h create mode 100644 src/devices/machine/s2636.c create mode 100644 src/devices/machine/s2636.h create mode 100644 src/devices/machine/s3520cf.c create mode 100644 src/devices/machine/s3520cf.h create mode 100644 src/devices/machine/s3c2400.c create mode 100644 src/devices/machine/s3c2400.h create mode 100644 src/devices/machine/s3c2410.c create mode 100644 src/devices/machine/s3c2410.h create mode 100644 src/devices/machine/s3c2440.c create mode 100644 src/devices/machine/s3c2440.h create mode 100644 src/devices/machine/s3c24xx.inc create mode 100644 src/devices/machine/s3c44b0.c create mode 100644 src/devices/machine/s3c44b0.h create mode 100644 src/devices/machine/saturn.c create mode 100644 src/devices/machine/serflash.c create mode 100644 src/devices/machine/serflash.h create mode 100644 src/devices/machine/smc91c9x.c create mode 100644 src/devices/machine/smc91c9x.h create mode 100644 src/devices/machine/smpc.c create mode 100644 src/devices/machine/smpc.h create mode 100644 src/devices/machine/spchrom.c create mode 100644 src/devices/machine/spchrom.h create mode 100644 src/devices/machine/steppers.c create mode 100644 src/devices/machine/steppers.h create mode 100644 src/devices/machine/strata.c create mode 100644 src/devices/machine/strata.h create mode 100644 src/devices/machine/stvcd.c create mode 100644 src/devices/machine/t10mmc.c create mode 100644 src/devices/machine/t10mmc.h create mode 100644 src/devices/machine/t10sbc.c create mode 100644 src/devices/machine/t10sbc.h create mode 100644 src/devices/machine/t10spc.c create mode 100644 src/devices/machine/t10spc.h create mode 100644 src/devices/machine/tc009xlvc.c create mode 100644 src/devices/machine/tc009xlvc.h create mode 100644 src/devices/machine/terminal.c create mode 100644 src/devices/machine/terminal.h create mode 100644 src/devices/machine/timekpr.c create mode 100644 src/devices/machine/timekpr.h create mode 100644 src/devices/machine/tmp68301.c create mode 100644 src/devices/machine/tmp68301.h create mode 100644 src/devices/machine/tms1024.c create mode 100644 src/devices/machine/tms1024.h create mode 100644 src/devices/machine/tms5501.c create mode 100644 src/devices/machine/tms5501.h create mode 100644 src/devices/machine/tms6100.c create mode 100644 src/devices/machine/tms6100.h create mode 100644 src/devices/machine/tms9901.c create mode 100644 src/devices/machine/tms9901.h create mode 100644 src/devices/machine/tms9902.c create mode 100644 src/devices/machine/tms9902.h create mode 100644 src/devices/machine/upd1990a.c create mode 100644 src/devices/machine/upd1990a.h create mode 100644 src/devices/machine/upd4701.c create mode 100644 src/devices/machine/upd4701.h create mode 100644 src/devices/machine/upd4992.c create mode 100644 src/devices/machine/upd4992.h create mode 100644 src/devices/machine/upd7002.c create mode 100644 src/devices/machine/upd7002.h create mode 100644 src/devices/machine/upd71071.c create mode 100644 src/devices/machine/upd71071.h create mode 100644 src/devices/machine/upd765.c create mode 100644 src/devices/machine/upd765.h create mode 100644 src/devices/machine/v3021.c create mode 100644 src/devices/machine/v3021.h create mode 100644 src/devices/machine/vrc4373.c create mode 100644 src/devices/machine/vrc4373.h create mode 100644 src/devices/machine/vt83c461.c create mode 100644 src/devices/machine/vt83c461.h create mode 100644 src/devices/machine/wd11c00_17.c create mode 100644 src/devices/machine/wd11c00_17.h create mode 100644 src/devices/machine/wd2010.c create mode 100644 src/devices/machine/wd2010.h create mode 100644 src/devices/machine/wd33c93.c create mode 100644 src/devices/machine/wd33c93.h create mode 100644 src/devices/machine/wd7600.c create mode 100644 src/devices/machine/wd7600.h create mode 100644 src/devices/machine/wd_fdc.c create mode 100644 src/devices/machine/wd_fdc.h create mode 100644 src/devices/machine/wozfdc.c create mode 100644 src/devices/machine/wozfdc.h create mode 100644 src/devices/machine/x2212.c create mode 100644 src/devices/machine/x2212.h create mode 100644 src/devices/machine/x76f041.c create mode 100644 src/devices/machine/x76f041.h create mode 100644 src/devices/machine/x76f100.c create mode 100644 src/devices/machine/x76f100.h create mode 100644 src/devices/machine/ym2148.c create mode 100644 src/devices/machine/ym2148.h create mode 100644 src/devices/machine/z80ctc.c create mode 100644 src/devices/machine/z80ctc.h create mode 100644 src/devices/machine/z80dart.c create mode 100644 src/devices/machine/z80dart.h create mode 100644 src/devices/machine/z80dma.c create mode 100644 src/devices/machine/z80dma.h create mode 100644 src/devices/machine/z80pio.c create mode 100644 src/devices/machine/z80pio.h create mode 100644 src/devices/machine/z80sti.c create mode 100644 src/devices/machine/z80sti.h create mode 100644 src/devices/machine/z8536.c create mode 100644 src/devices/machine/z8536.h create mode 100644 src/devices/sound/2151intf.c create mode 100644 src/devices/sound/2151intf.h create mode 100644 src/devices/sound/2203intf.c create mode 100644 src/devices/sound/2203intf.h create mode 100644 src/devices/sound/2413intf.c create mode 100644 src/devices/sound/2413intf.h create mode 100644 src/devices/sound/2608intf.c create mode 100644 src/devices/sound/2608intf.h create mode 100644 src/devices/sound/2610intf.c create mode 100644 src/devices/sound/2610intf.h create mode 100644 src/devices/sound/2612intf.c create mode 100644 src/devices/sound/2612intf.h create mode 100644 src/devices/sound/262intf.c create mode 100644 src/devices/sound/262intf.h create mode 100644 src/devices/sound/315-5641.c create mode 100644 src/devices/sound/315-5641.h create mode 100644 src/devices/sound/3526intf.c create mode 100644 src/devices/sound/3526intf.h create mode 100644 src/devices/sound/3812intf.c create mode 100644 src/devices/sound/3812intf.h create mode 100644 src/devices/sound/8950intf.c create mode 100644 src/devices/sound/8950intf.h create mode 100644 src/devices/sound/aica.c create mode 100644 src/devices/sound/aica.h create mode 100644 src/devices/sound/aicadsp.c create mode 100644 src/devices/sound/aicadsp.h create mode 100644 src/devices/sound/amiga.c create mode 100644 src/devices/sound/amiga.h create mode 100644 src/devices/sound/asc.c create mode 100644 src/devices/sound/asc.h create mode 100644 src/devices/sound/astrocde.c create mode 100644 src/devices/sound/astrocde.h create mode 100644 src/devices/sound/awacs.c create mode 100644 src/devices/sound/awacs.h create mode 100644 src/devices/sound/ay8910.c create mode 100644 src/devices/sound/ay8910.h create mode 100644 src/devices/sound/beep.c create mode 100644 src/devices/sound/beep.h create mode 100644 src/devices/sound/bsmt2000.c create mode 100644 src/devices/sound/bsmt2000.h create mode 100644 src/devices/sound/c140.c create mode 100644 src/devices/sound/c140.h create mode 100644 src/devices/sound/c352.c create mode 100644 src/devices/sound/c352.h create mode 100644 src/devices/sound/c6280.c create mode 100644 src/devices/sound/c6280.h create mode 100644 src/devices/sound/cdda.c create mode 100644 src/devices/sound/cdda.h create mode 100644 src/devices/sound/cdp1863.c create mode 100644 src/devices/sound/cdp1863.h create mode 100644 src/devices/sound/cdp1864.c create mode 100644 src/devices/sound/cdp1864.h create mode 100644 src/devices/sound/cdp1869.c create mode 100644 src/devices/sound/cdp1869.h create mode 100644 src/devices/sound/cem3394.c create mode 100644 src/devices/sound/cem3394.h create mode 100644 src/devices/sound/dac.c create mode 100644 src/devices/sound/dac.h create mode 100644 src/devices/sound/digitalk.c create mode 100644 src/devices/sound/digitalk.h create mode 100644 src/devices/sound/disc_cls.h create mode 100644 src/devices/sound/disc_dev.h create mode 100644 src/devices/sound/disc_dev.inc create mode 100644 src/devices/sound/disc_flt.h create mode 100644 src/devices/sound/disc_flt.inc create mode 100644 src/devices/sound/disc_inp.inc create mode 100644 src/devices/sound/disc_mth.h create mode 100644 src/devices/sound/disc_mth.inc create mode 100644 src/devices/sound/disc_sys.inc create mode 100644 src/devices/sound/disc_wav.h create mode 100644 src/devices/sound/disc_wav.inc create mode 100644 src/devices/sound/discrete.c create mode 100644 src/devices/sound/discrete.h create mode 100644 src/devices/sound/dmadac.c create mode 100644 src/devices/sound/dmadac.h create mode 100644 src/devices/sound/es1373.c create mode 100644 src/devices/sound/es1373.h create mode 100644 src/devices/sound/es5503.c create mode 100644 src/devices/sound/es5503.h create mode 100644 src/devices/sound/es5506.c create mode 100644 src/devices/sound/es5506.h create mode 100644 src/devices/sound/es8712.c create mode 100644 src/devices/sound/es8712.h create mode 100644 src/devices/sound/esqpump.c create mode 100644 src/devices/sound/esqpump.h create mode 100644 src/devices/sound/filter.c create mode 100644 src/devices/sound/filter.h create mode 100644 src/devices/sound/flt_rc.c create mode 100644 src/devices/sound/flt_rc.h create mode 100644 src/devices/sound/flt_vol.c create mode 100644 src/devices/sound/flt_vol.h create mode 100644 src/devices/sound/fm.c create mode 100644 src/devices/sound/fm.h create mode 100644 src/devices/sound/fm2612.c create mode 100644 src/devices/sound/fmopl.c create mode 100644 src/devices/sound/fmopl.h create mode 100644 src/devices/sound/gaelco.c create mode 100644 src/devices/sound/gaelco.h create mode 100644 src/devices/sound/hc55516.c create mode 100644 src/devices/sound/hc55516.h create mode 100644 src/devices/sound/i5000.c create mode 100644 src/devices/sound/i5000.h create mode 100644 src/devices/sound/ics2115.c create mode 100644 src/devices/sound/ics2115.h create mode 100644 src/devices/sound/iremga20.c create mode 100644 src/devices/sound/iremga20.h create mode 100644 src/devices/sound/k005289.c create mode 100644 src/devices/sound/k005289.h create mode 100644 src/devices/sound/k007232.c create mode 100644 src/devices/sound/k007232.h create mode 100644 src/devices/sound/k051649.c create mode 100644 src/devices/sound/k051649.h create mode 100644 src/devices/sound/k053260.c create mode 100644 src/devices/sound/k053260.h create mode 100644 src/devices/sound/k054539.c create mode 100644 src/devices/sound/k054539.h create mode 100644 src/devices/sound/k056800.c create mode 100644 src/devices/sound/k056800.h create mode 100644 src/devices/sound/l7a1045_l6028_dsp_a.c create mode 100644 src/devices/sound/l7a1045_l6028_dsp_a.h create mode 100644 src/devices/sound/lmc1992.c create mode 100644 src/devices/sound/lmc1992.h create mode 100644 src/devices/sound/mas3507d.c create mode 100644 src/devices/sound/mas3507d.h create mode 100644 src/devices/sound/mos6560.c create mode 100644 src/devices/sound/mos6560.h create mode 100644 src/devices/sound/mos6581.c create mode 100644 src/devices/sound/mos6581.h create mode 100644 src/devices/sound/mos7360.c create mode 100644 src/devices/sound/mos7360.h create mode 100644 src/devices/sound/mpeg_audio.c create mode 100644 src/devices/sound/mpeg_audio.h create mode 100644 src/devices/sound/msm5205.c create mode 100644 src/devices/sound/msm5205.h create mode 100644 src/devices/sound/msm5232.c create mode 100644 src/devices/sound/msm5232.h create mode 100644 src/devices/sound/multipcm.c create mode 100644 src/devices/sound/multipcm.h create mode 100644 src/devices/sound/n63701x.c create mode 100644 src/devices/sound/n63701x.h create mode 100644 src/devices/sound/namco.c create mode 100644 src/devices/sound/namco.h create mode 100644 src/devices/sound/nes_apu.c create mode 100644 src/devices/sound/nes_apu.h create mode 100644 src/devices/sound/nes_defs.h create mode 100644 src/devices/sound/nile.c create mode 100644 src/devices/sound/nile.h create mode 100644 src/devices/sound/okiadpcm.c create mode 100644 src/devices/sound/okiadpcm.h create mode 100644 src/devices/sound/okim6258.c create mode 100644 src/devices/sound/okim6258.h create mode 100644 src/devices/sound/okim6295.c create mode 100644 src/devices/sound/okim6295.h create mode 100644 src/devices/sound/okim6376.c create mode 100644 src/devices/sound/okim6376.h create mode 100644 src/devices/sound/okim9810.c create mode 100644 src/devices/sound/okim9810.h create mode 100644 src/devices/sound/pci-ac97.c create mode 100644 src/devices/sound/pci-ac97.h create mode 100644 src/devices/sound/pokey.c create mode 100644 src/devices/sound/pokey.h create mode 100644 src/devices/sound/pokey.txt create mode 100644 src/devices/sound/qs1000.c create mode 100644 src/devices/sound/qs1000.h create mode 100644 src/devices/sound/qsound.c create mode 100644 src/devices/sound/qsound.h create mode 100644 src/devices/sound/rf5c400.c create mode 100644 src/devices/sound/rf5c400.h create mode 100644 src/devices/sound/rf5c68.c create mode 100644 src/devices/sound/rf5c68.h create mode 100644 src/devices/sound/s14001a.c create mode 100644 src/devices/sound/s14001a.h create mode 100644 src/devices/sound/saa1099.c create mode 100644 src/devices/sound/saa1099.h create mode 100644 src/devices/sound/samples.c create mode 100644 src/devices/sound/samples.h create mode 100644 src/devices/sound/sb0400.c create mode 100644 src/devices/sound/sb0400.h create mode 100644 src/devices/sound/scsp.c create mode 100644 src/devices/sound/scsp.h create mode 100644 src/devices/sound/scspdsp.c create mode 100644 src/devices/sound/scspdsp.h create mode 100644 src/devices/sound/segapcm.c create mode 100644 src/devices/sound/segapcm.h create mode 100644 src/devices/sound/sid.c create mode 100644 src/devices/sound/sid.h create mode 100644 src/devices/sound/side6581.h create mode 100644 src/devices/sound/sidenvel.c create mode 100644 src/devices/sound/sidenvel.h create mode 100644 src/devices/sound/sidvoice.c create mode 100644 src/devices/sound/sidvoice.h create mode 100644 src/devices/sound/sidw6581.h create mode 100644 src/devices/sound/sidw8580.h create mode 100644 src/devices/sound/sn76477.c create mode 100644 src/devices/sound/sn76477.h create mode 100644 src/devices/sound/sn76496.c create mode 100644 src/devices/sound/sn76496.h create mode 100644 src/devices/sound/snkwave.c create mode 100644 src/devices/sound/snkwave.h create mode 100644 src/devices/sound/sp0250.c create mode 100644 src/devices/sound/sp0250.h create mode 100644 src/devices/sound/sp0256.c create mode 100644 src/devices/sound/sp0256.h create mode 100644 src/devices/sound/speaker.c create mode 100644 src/devices/sound/speaker.h create mode 100644 src/devices/sound/spu.c create mode 100644 src/devices/sound/spu.h create mode 100644 src/devices/sound/spu_tables.c create mode 100644 src/devices/sound/spureverb.c create mode 100644 src/devices/sound/spureverb.h create mode 100644 src/devices/sound/st0016.c create mode 100644 src/devices/sound/st0016.h create mode 100644 src/devices/sound/t6721a.c create mode 100644 src/devices/sound/t6721a.h create mode 100644 src/devices/sound/t6w28.c create mode 100644 src/devices/sound/t6w28.h create mode 100644 src/devices/sound/tc8830f.c create mode 100644 src/devices/sound/tc8830f.h create mode 100644 src/devices/sound/tiaintf.c create mode 100644 src/devices/sound/tiaintf.h create mode 100644 src/devices/sound/tiasound.c create mode 100644 src/devices/sound/tiasound.h create mode 100644 src/devices/sound/tms3615.c create mode 100644 src/devices/sound/tms3615.h create mode 100644 src/devices/sound/tms36xx.c create mode 100644 src/devices/sound/tms36xx.h create mode 100644 src/devices/sound/tms5110.c create mode 100644 src/devices/sound/tms5110.h create mode 100644 src/devices/sound/tms5110r.inc create mode 100644 src/devices/sound/tms5220.c create mode 100644 src/devices/sound/tms5220.h create mode 100644 src/devices/sound/tms5220.txt create mode 100644 src/devices/sound/upd7752.c create mode 100644 src/devices/sound/upd7752.h create mode 100644 src/devices/sound/upd7759.c create mode 100644 src/devices/sound/upd7759.h create mode 100644 src/devices/sound/vlm5030.c create mode 100644 src/devices/sound/vlm5030.h create mode 100644 src/devices/sound/votrax.c create mode 100644 src/devices/sound/votrax.h create mode 100644 src/devices/sound/vrc6.c create mode 100644 src/devices/sound/vrc6.h create mode 100644 src/devices/sound/vrender0.c create mode 100644 src/devices/sound/vrender0.h create mode 100644 src/devices/sound/wave.c create mode 100644 src/devices/sound/wave.h create mode 100644 src/devices/sound/wavwrite.c create mode 100644 src/devices/sound/wavwrite.h create mode 100644 src/devices/sound/x1_010.c create mode 100644 src/devices/sound/x1_010.h create mode 100644 src/devices/sound/ym2151.c create mode 100644 src/devices/sound/ym2151.h create mode 100644 src/devices/sound/ym2151.txt create mode 100644 src/devices/sound/ym2413.c create mode 100644 src/devices/sound/ym2413.h create mode 100644 src/devices/sound/ymdeltat.c create mode 100644 src/devices/sound/ymdeltat.h create mode 100644 src/devices/sound/ymf262.c create mode 100644 src/devices/sound/ymf262.h create mode 100644 src/devices/sound/ymf271.c create mode 100644 src/devices/sound/ymf271.h create mode 100644 src/devices/sound/ymf278b.c create mode 100644 src/devices/sound/ymf278b.h create mode 100644 src/devices/sound/ymz280b.c create mode 100644 src/devices/sound/ymz280b.h create mode 100644 src/devices/sound/ymz770.c create mode 100644 src/devices/sound/ymz770.h create mode 100644 src/devices/sound/zsg2.c create mode 100644 src/devices/sound/zsg2.h create mode 100644 src/devices/video/315_5124.c create mode 100644 src/devices/video/315_5124.h create mode 100644 src/devices/video/315_5313.c create mode 100644 src/devices/video/315_5313.h create mode 100644 src/devices/video/bufsprite.c create mode 100644 src/devices/video/bufsprite.h create mode 100644 src/devices/video/cdp1861.c create mode 100644 src/devices/video/cdp1861.h create mode 100644 src/devices/video/cdp1862.c create mode 100644 src/devices/video/cdp1862.h create mode 100644 src/devices/video/cgapal.c create mode 100644 src/devices/video/cgapal.h create mode 100644 src/devices/video/clgd542x.c create mode 100644 src/devices/video/clgd542x.h create mode 100644 src/devices/video/crt9007.c create mode 100644 src/devices/video/crt9007.h create mode 100644 src/devices/video/crt9021.c create mode 100644 src/devices/video/crt9021.h create mode 100644 src/devices/video/crt9212.c create mode 100644 src/devices/video/crt9212.h create mode 100644 src/devices/video/crtc_ega.c create mode 100644 src/devices/video/crtc_ega.h create mode 100644 src/devices/video/dl1416.c create mode 100644 src/devices/video/dl1416.h create mode 100644 src/devices/video/dm9368.c create mode 100644 src/devices/video/dm9368.h create mode 100644 src/devices/video/ef9340_1.c create mode 100644 src/devices/video/ef9340_1.h create mode 100644 src/devices/video/ef9341_chargen.h create mode 100644 src/devices/video/ef9345.c create mode 100644 src/devices/video/ef9345.h create mode 100644 src/devices/video/epic12.c create mode 100644 src/devices/video/epic12.h create mode 100644 src/devices/video/epic12_blit0.c create mode 100644 src/devices/video/epic12_blit1.c create mode 100644 src/devices/video/epic12_blit2.c create mode 100644 src/devices/video/epic12_blit3.c create mode 100644 src/devices/video/epic12_blit4.c create mode 100644 src/devices/video/epic12_blit5.c create mode 100644 src/devices/video/epic12_blit6.c create mode 100644 src/devices/video/epic12_blit7.c create mode 100644 src/devices/video/epic12_blit8.c create mode 100644 src/devices/video/epic12in.inc create mode 100644 src/devices/video/epic12pixel.inc create mode 100644 src/devices/video/fixfreq.c create mode 100644 src/devices/video/fixfreq.h create mode 100644 src/devices/video/generic.c create mode 100644 src/devices/video/generic.h create mode 100644 src/devices/video/gf4500.c create mode 100644 src/devices/video/gf4500.h create mode 100644 src/devices/video/gf7600gs.c create mode 100644 src/devices/video/gf7600gs.h create mode 100644 src/devices/video/h63484.c create mode 100644 src/devices/video/h63484.h create mode 100644 src/devices/video/hd44102.c create mode 100644 src/devices/video/hd44102.h create mode 100644 src/devices/video/hd44352.c create mode 100644 src/devices/video/hd44352.h create mode 100644 src/devices/video/hd44780.c create mode 100644 src/devices/video/hd44780.h create mode 100644 src/devices/video/hd61830.c create mode 100644 src/devices/video/hd61830.h create mode 100644 src/devices/video/hd63484.c create mode 100644 src/devices/video/hd63484.h create mode 100644 src/devices/video/hd66421.c create mode 100644 src/devices/video/hd66421.h create mode 100644 src/devices/video/huc6202.c create mode 100644 src/devices/video/huc6202.h create mode 100644 src/devices/video/huc6260.c create mode 100644 src/devices/video/huc6260.h create mode 100644 src/devices/video/huc6261.c create mode 100644 src/devices/video/huc6261.h create mode 100644 src/devices/video/huc6270.c create mode 100644 src/devices/video/huc6270.h create mode 100644 src/devices/video/huc6272.c create mode 100644 src/devices/video/huc6272.h create mode 100644 src/devices/video/i8244.c create mode 100644 src/devices/video/i8244.h create mode 100644 src/devices/video/i82730.c create mode 100644 src/devices/video/i82730.h create mode 100644 src/devices/video/i8275.c create mode 100644 src/devices/video/i8275.h create mode 100644 src/devices/video/m50458.c create mode 100644 src/devices/video/m50458.h create mode 100644 src/devices/video/mb90082.c create mode 100644 src/devices/video/mb90082.h create mode 100644 src/devices/video/mb_vcu.c create mode 100644 src/devices/video/mb_vcu.h create mode 100644 src/devices/video/mc6845.c create mode 100644 src/devices/video/mc6845.h create mode 100644 src/devices/video/mc6847.c create mode 100644 src/devices/video/mc6847.h create mode 100644 src/devices/video/mos6566.c create mode 100644 src/devices/video/mos6566.h create mode 100644 src/devices/video/msm6222b.c create mode 100644 src/devices/video/msm6222b.h create mode 100644 src/devices/video/msm6255.c create mode 100644 src/devices/video/msm6255.h create mode 100644 src/devices/video/pc_vga.c create mode 100644 src/devices/video/pc_vga.h create mode 100644 src/devices/video/poly.h create mode 100644 src/devices/video/polylgcy.c create mode 100644 src/devices/video/polylgcy.h create mode 100644 src/devices/video/psx.c create mode 100644 src/devices/video/psx.h create mode 100644 src/devices/video/ramdac.c create mode 100644 src/devices/video/ramdac.h create mode 100644 src/devices/video/resnet.c create mode 100644 src/devices/video/resnet.h create mode 100644 src/devices/video/rgbgen.c create mode 100644 src/devices/video/rgbgen.h create mode 100644 src/devices/video/rgbsse.c create mode 100644 src/devices/video/rgbsse.h create mode 100644 src/devices/video/rgbutil.h create mode 100644 src/devices/video/rgbvmx.c create mode 100644 src/devices/video/rgbvmx.h create mode 100644 src/devices/video/saa5050.c create mode 100644 src/devices/video/saa5050.h create mode 100644 src/devices/video/scn2674.c create mode 100644 src/devices/video/scn2674.h create mode 100644 src/devices/video/sed1200.c create mode 100644 src/devices/video/sed1200.h create mode 100644 src/devices/video/sed1330.c create mode 100644 src/devices/video/sed1330.h create mode 100644 src/devices/video/sed1520.c create mode 100644 src/devices/video/sed1520.h create mode 100644 src/devices/video/snes_ppu.c create mode 100644 src/devices/video/snes_ppu.h create mode 100644 src/devices/video/stvvdp1.c create mode 100644 src/devices/video/stvvdp2.c create mode 100644 src/devices/video/t6a04.c create mode 100644 src/devices/video/t6a04.h create mode 100644 src/devices/video/tea1002.c create mode 100644 src/devices/video/tea1002.h create mode 100644 src/devices/video/tlc34076.c create mode 100644 src/devices/video/tlc34076.h create mode 100644 src/devices/video/tms34061.c create mode 100644 src/devices/video/tms34061.h create mode 100644 src/devices/video/tms3556.c create mode 100644 src/devices/video/tms3556.h create mode 100644 src/devices/video/tms9927.c create mode 100644 src/devices/video/tms9927.h create mode 100644 src/devices/video/tms9928a.c create mode 100644 src/devices/video/tms9928a.h create mode 100644 src/devices/video/upd3301.c create mode 100644 src/devices/video/upd3301.h create mode 100644 src/devices/video/upd7220.c create mode 100644 src/devices/video/upd7220.h create mode 100644 src/devices/video/upd7227.c create mode 100644 src/devices/video/upd7227.h create mode 100644 src/devices/video/v9938.c create mode 100644 src/devices/video/v9938.h create mode 100644 src/devices/video/vector.c create mode 100644 src/devices/video/vector.h create mode 100644 src/devices/video/vic4567.c create mode 100644 src/devices/video/vic4567.h create mode 100644 src/devices/video/vooddefs.h create mode 100644 src/devices/video/voodoo.c create mode 100644 src/devices/video/voodoo.h create mode 100644 src/devices/video/voodoo_pci.c create mode 100644 src/devices/video/voodoo_pci.h (limited to 'src/devices') diff --git a/src/devices/bus/a1bus/a1bus.c b/src/devices/bus/a1bus/a1bus.c new file mode 100644 index 00000000000..7012d11a81b --- /dev/null +++ b/src/devices/bus/a1bus/a1bus.c @@ -0,0 +1,204 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/*************************************************************************** + + a1bus.c - Apple I slot bus and card emulation + +***************************************************************************/ + +#include "emu.h" +#include "emuopts.h" +#include "a1bus.h" + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type A1BUS_SLOT = &device_creator; + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// a1bus_slot_device - constructor +//------------------------------------------------- +a1bus_slot_device::a1bus_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, A1BUS_SLOT, "Apple I Slot", tag, owner, clock, "a1bus_slot", __FILE__), + device_slot_interface(mconfig, *this) +{ +} + +a1bus_slot_device::a1bus_slot_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_slot_interface(mconfig, *this) +{ +} + +void a1bus_slot_device::static_set_a1bus_slot(device_t &device, const char *tag, const char *slottag) +{ + a1bus_slot_device &a1bus_card = dynamic_cast(device); + a1bus_card.m_a1bus_tag = tag; + a1bus_card.m_a1bus_slottag = slottag; +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void a1bus_slot_device::device_start() +{ + device_a1bus_card_interface *dev = dynamic_cast(get_card_device()); + + if (dev) device_a1bus_card_interface::static_set_a1bus_tag(*dev, m_a1bus_tag, m_a1bus_slottag); +} + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type A1BUS = &device_creator; + +void a1bus_device::static_set_cputag(device_t &device, const char *tag) +{ + a1bus_device &a1bus = downcast(device); + a1bus.m_cputag = tag; +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// a1bus_device - constructor +//------------------------------------------------- + +a1bus_device::a1bus_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, A1BUS, "Apple I Bus", tag, owner, clock, "a1bus", __FILE__), + m_out_irq_cb(*this), + m_out_nmi_cb(*this) +{ +} + +a1bus_device::a1bus_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + m_out_irq_cb(*this), + m_out_nmi_cb(*this) +{ +} +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void a1bus_device::device_start() +{ + m_maincpu = machine().device(m_cputag); + + // resolve callbacks + m_out_irq_cb.resolve_safe(); + m_out_nmi_cb.resolve_safe(); + + // clear slot + m_device = NULL; +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void a1bus_device::device_reset() +{ +} + +device_a1bus_card_interface *a1bus_device::get_a1bus_card() +{ + return m_device; +} + +void a1bus_device::add_a1bus_card(device_a1bus_card_interface *card) +{ + m_device = card; +} + +void a1bus_device::set_irq_line(int state) +{ + m_out_irq_cb(state); +} + +void a1bus_device::set_nmi_line(int state) +{ + m_out_nmi_cb(state); +} + +void a1bus_device::install_device(offs_t start, offs_t end, read8_delegate rhandler, write8_delegate whandler) +{ + m_maincpu = machine().device(m_cputag); + + m_maincpu->space(AS_PROGRAM).install_readwrite_handler(start, end, rhandler, whandler); +} + +void a1bus_device::install_bank(offs_t start, offs_t end, offs_t mask, offs_t mirror, const char *tag, UINT8 *data) +{ +// printf("install_bank: %s @ %x->%x mask %x mirror %x\n", tag, start, end, mask, mirror); + m_maincpu = machine().device(m_cputag); + address_space &space = m_maincpu->space(AS_PROGRAM); + space.install_readwrite_bank(start, end, mask, mirror, tag ); + machine().root_device().membank(tag)->set_base(data); +} + +// interrupt request from a1bus card +WRITE_LINE_MEMBER( a1bus_device::irq_w ) { m_out_irq_cb(state); } +WRITE_LINE_MEMBER( a1bus_device::nmi_w ) { m_out_nmi_cb(state); } + +//************************************************************************** +// DEVICE CONFIG A1BUS CARD INTERFACE +//************************************************************************** + + +//************************************************************************** +// DEVICE A1BUS CARD INTERFACE +//************************************************************************** + +//------------------------------------------------- +// device_a1bus_card_interface - constructor +//------------------------------------------------- + +device_a1bus_card_interface::device_a1bus_card_interface(const machine_config &mconfig, device_t &device) + : device_slot_card_interface(mconfig, device), + m_a1bus(NULL), + m_a1bus_tag(NULL) +{ +} + + +//------------------------------------------------- +// ~device_a1bus_card_interface - destructor +//------------------------------------------------- + +device_a1bus_card_interface::~device_a1bus_card_interface() +{ +} + +void device_a1bus_card_interface::static_set_a1bus_tag(device_t &device, const char *tag, const char *slottag) +{ + device_a1bus_card_interface &a1bus_card = dynamic_cast(device); + a1bus_card.m_a1bus_tag = tag; + a1bus_card.m_a1bus_slottag = slottag; +} + +void device_a1bus_card_interface::set_a1bus_device() +{ + m_a1bus = dynamic_cast(device().machine().device(m_a1bus_tag)); + m_a1bus->add_a1bus_card(this); +} + +void device_a1bus_card_interface::install_device(offs_t start, offs_t end, read8_delegate rhandler, write8_delegate whandler) +{ + m_a1bus->install_device(start, end, rhandler, whandler); +} + +void device_a1bus_card_interface::install_bank(offs_t start, offs_t end, offs_t mask, offs_t mirror, char *tag, UINT8 *data) +{ + m_a1bus->install_bank(start, end, mask, mirror, tag, data); +} diff --git a/src/devices/bus/a1bus/a1bus.h b/src/devices/bus/a1bus/a1bus.h new file mode 100644 index 00000000000..ecdb440f948 --- /dev/null +++ b/src/devices/bus/a1bus/a1bus.h @@ -0,0 +1,145 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/*************************************************************************** + + a1bus.h - Apple I expansion slot and card emulation + +***************************************************************************/ + +#pragma once + +#ifndef __A1BUS_H__ +#define __A1BUS_H__ + +#include "emu.h" + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_A1BUS_CPU(_cputag) \ + a1bus_device::static_set_cputag(*device, _cputag); + +#define MCFG_A1BUS_OUT_IRQ_CB(_devcb) \ + devcb = &a1bus_device::set_out_irq_callback(*device, DEVCB_##_devcb); + +#define MCFG_A1BUS_OUT_NMI_CB(_devcb) \ + devcb = &a1bus_device::set_out_nmi_callback(*device, DEVCB_##_devcb); + +#define MCFG_A1BUS_SLOT_ADD(_nbtag, _tag, _slot_intf, _def_slot) \ + MCFG_DEVICE_ADD(_tag, A1BUS_SLOT, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) \ + a1bus_slot_device::static_set_a1bus_slot(*device, _nbtag, _tag); +#define MCFG_A1BUS_SLOT_REMOVE(_tag) \ + MCFG_DEVICE_REMOVE(_tag) + +#define MCFG_A1BUS_ONBOARD_ADD(_nbtag, _tag, _dev_type, _def_inp) \ + MCFG_DEVICE_ADD(_tag, _dev_type, 0) \ + MCFG_DEVICE_INPUT_DEFAULTS(_def_inp) \ + device_a1bus_card_interface::static_set_a1bus_tag(*device, _nbtag, _tag); + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class a1bus_device; + +class a1bus_slot_device : public device_t, + public device_slot_interface +{ +public: + // construction/destruction + a1bus_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + a1bus_slot_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + // device-level overrides + virtual void device_start(); + + // inline configuration + static void static_set_a1bus_slot(device_t &device, const char *tag, const char *slottag); +protected: + // configuration + const char *m_a1bus_tag, *m_a1bus_slottag; +}; + +// device type definition +extern const device_type A1BUS_SLOT; + + +class device_a1bus_card_interface; +// ======================> a1bus_device +class a1bus_device : public device_t +{ +public: + // construction/destruction + a1bus_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + a1bus_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + // inline configuration + static void static_set_cputag(device_t &device, const char *tag); + template static devcb_base &set_out_irq_callback(device_t &device, _Object object) { return downcast(device).m_out_irq_cb.set_callback(object); } + template static devcb_base &set_out_nmi_callback(device_t &device, _Object object) { return downcast(device).m_out_nmi_cb.set_callback(object); } + + void add_a1bus_card(device_a1bus_card_interface *card); + device_a1bus_card_interface *get_a1bus_card(); + + void set_irq_line(int state); + void set_nmi_line(int state); + + void install_device(offs_t start, offs_t end, read8_delegate rhandler, write8_delegate whandler); + void install_bank(offs_t start, offs_t end, offs_t mask, offs_t mirror, const char *tag, UINT8 *data); + + DECLARE_WRITE_LINE_MEMBER( irq_w ); + DECLARE_WRITE_LINE_MEMBER( nmi_w ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // internal state + cpu_device *m_maincpu; + + devcb_write_line m_out_irq_cb; + devcb_write_line m_out_nmi_cb; + + device_a1bus_card_interface *m_device; + const char *m_cputag; +}; + + +// device type definition +extern const device_type A1BUS; + +// ======================> device_a1bus_card_interface + +// class representing interface-specific live a1bus card +class device_a1bus_card_interface : public device_slot_card_interface +{ + friend class a1bus_device; +public: + // construction/destruction + device_a1bus_card_interface(const machine_config &mconfig, device_t &device); + virtual ~device_a1bus_card_interface(); + + device_a1bus_card_interface *next() const { return m_next; } + + void set_a1bus_device(); + + void raise_slot_irq() { m_a1bus->set_irq_line(ASSERT_LINE); } + void lower_slot_irq() { m_a1bus->set_irq_line(CLEAR_LINE); } + void raise_slot_nmi() { m_a1bus->set_nmi_line(ASSERT_LINE); } + void lower_slot_nmi() { m_a1bus->set_nmi_line(CLEAR_LINE); } + + void install_device(offs_t start, offs_t end, read8_delegate rhandler, write8_delegate whandler); + void install_bank(offs_t start, offs_t end, offs_t mask, offs_t mirror, char *tag, UINT8 *data); + + // inline configuration + static void static_set_a1bus_tag(device_t &device, const char *tag, const char *slottag); +public: + a1bus_device *m_a1bus; + const char *m_a1bus_tag, *m_a1bus_slottag; + device_a1bus_card_interface *m_next; +}; + +#endif /* __A1BUS_H__ */ diff --git a/src/devices/bus/a1bus/a1cassette.c b/src/devices/bus/a1bus/a1cassette.c new file mode 100644 index 00000000000..daa79b15ce5 --- /dev/null +++ b/src/devices/bus/a1bus/a1cassette.c @@ -0,0 +1,201 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/********************************************************************* + + a1cassette.c + + Apple I Cassette Interface + +*********************************************************************/ + +#include "a1cassette.h" + +/*************************************************************************** + PARAMETERS +***************************************************************************/ + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +#define CASSETTE_ROM_REGION "casrom" + +const device_type A1BUS_CASSETTE = &device_creator; + +/* sound output */ + +MACHINE_CONFIG_FRAGMENT( cassette ) + MCFG_CASSETTE_ADD("cassette") + MCFG_CASSETTE_DEFAULT_STATE(CASSETTE_STOPPED) + MCFG_CASSETTE_INTERFACE("apple1_cass") +MACHINE_CONFIG_END + +ROM_START( cassette ) + /* 256-byte cassette interface ROM, in two 82s129 or mmi6301 256x4 proms at locations 3 and 4 on the cassette interface daughtercard (they are labeled "MMI 6301-IJ // 7623L // APPLE-A3" and "MMI 6301-IJ // 7623L // APPLE-A4") */ + ROM_REGION(0x100, CASSETTE_ROM_REGION, 0) + ROM_LOAD_NIB_HIGH( "apple-a3.3", 0x0000, 0x0100, CRC(6eae8f52) SHA1(71906932727ef70952ef6afe6b08708df15cd67d) ) + ROM_LOAD_NIB_LOW( "apple-a4.4", 0x0000, 0x0100, CRC(94efa977) SHA1(851f3bd6863859a1a6909179a5e5bf744b3d807e) ) +ROM_END + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor a1bus_cassette_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( cassette ); +} + +const rom_entry *a1bus_cassette_device::device_rom_region() const +{ + return ROM_NAME( cassette ); +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +a1bus_cassette_device::a1bus_cassette_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, A1BUS_CASSETTE, "Apple I cassette board", tag, owner, clock, "a1cass", __FILE__), + device_a1bus_card_interface(mconfig, *this), + m_cassette(*this, "cassette") +{ +} + +a1bus_cassette_device::a1bus_cassette_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_a1bus_card_interface(mconfig, *this), + m_cassette(*this, "cassette") +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void a1bus_cassette_device::device_start() +{ + set_a1bus_device(); + + m_rom = device().machine().root_device().memregion(this->subtag(CASSETTE_ROM_REGION).c_str())->base(); + + install_device(0xc000, 0xc0ff, read8_delegate(FUNC(a1bus_cassette_device::cassette_r), this), write8_delegate(FUNC(a1bus_cassette_device::cassette_w), this)); + install_bank(0xc100, 0xc1ff, 0, 0, (char *)"bank_a1cas", m_rom); + + save_item(NAME(m_cassette_output_flipflop)); +} + +void a1bus_cassette_device::device_reset() +{ + m_cassette_output_flipflop = 0; +} + +/***************************************************************************** +** Cassette interface I/O +** +** The Apple I's cassette interface was a small card that plugged +** into the expansion connector on the motherboard. (This was a +** slot-type connector, separate from the motherboard's edge +** connector, but with the same signals.) The cassette interface +** provided separate cassette input and output jacks, some very +** simple interface hardware, and 256 bytes of ROM containing the +** cassette I/O code. +** +** The interface was mostly software-controlled. The only hardware +** was an output flip-flop for generating the cassette output signal, +** a National Semiconductor LM311 voltage comparator for generating a +** digital signal from the analog cassette input, an input +** signal-level LED, and some gates to control the interface logic +** and address decoding. The cassette ROM code did most of the work +** of generating and interpreting tape signals. It also contained +** its own mini-monitor for issuing tape read and write commands. +** +** The cassette interface was assigned to the $C000-$CFFF block of +** addresses, although it did not use most of the space in that +** block. Addresses were mapped as follows: +** +** $C000-$C0FF: Cassette I/O space. +** Any access here toggles the output signal. +** $C000-$C07F: Cassette output only; input disabled. +** Mirrors $C100-$C17F on reads. +** $C080-$C0FF: Cassette input and output. +** When input low, mirrors $C180-$C1FF on reads. +** When input high, both odd and even addresses +** mirror even ROM addresses $C180-$C1FE. +** $C100-$C1FF: Cassette ROM code. +** +** Note the peculiar addressing scheme. Data was written simply +** through repeated accesses, rather than by writing to an address. +** Data was read by reading an odd input address and comparing the +** ROM byte returned to detect signal changes. +** +** The standard tape signal was a simple square wave, although this +** was often greatly distorted by the cassette recorder. A single +** tape record consisted of a 10-second 800-Hz leader, followed by a +** single short square-wave cycle used as a sync bit, followed by the +** tape data. The data was encoded using a single square-wave cycle +** for each bit; "1" bits were at 1000 Hz, "0" bits at 2000 Hz. (All +** of these frequencies are approximate and could vary due to +** differences in recorder speed.) Each byte was written starting +** from the most significant bit; bytes were written from low to high +** addresses. No error detection was provided. Multiple records +** could be placed on a single tape. +*****************************************************************************/ + +/* The cassette output signal for writing tapes is generated by a + flip-flop which is toggled to produce the output waveform. Any + access to the cassette I/O range, whether a read or a write, + toggles this flip-flop. */ +void a1bus_cassette_device::cassette_toggle_output() +{ + m_cassette_output_flipflop = !m_cassette_output_flipflop; + m_cassette->output(m_cassette_output_flipflop ? 1.0 : -1.0); +} + +READ8_MEMBER(a1bus_cassette_device::cassette_r) +{ + cassette_toggle_output(); + + if (offset <= 0x7f) + { + /* If the access is to address range $C000-$C07F, the cassette + input signal is ignored . In this case the value read + always comes from the corresponding cassette ROM location + in $C100-$C17F. */ + + return m_rom[offset]; + } + else + { + /* For accesses to address range $C080-$C0FF, the cassette + input signal is enabled. If the signal is low, the value + read comes from the corresponding cassette ROM location in + $C180-$C1FF. If the signal is high, the low bit of the + address is masked before the corresponding cassette ROM + location is accessed; e.g., a read from $C081 would return + the ROM byte at $C180. The cassette ROM routines detect + changes in the cassette input signal by repeatedly reading + from $C081 and comparing the values read. */ + + /* (Don't try putting a non-zero "noise threshhold" here, + because it can cause tape header bits on real cassette + images to be misread as data bits.) */ + if (m_cassette->input() > 0.0) + return m_rom[0xc100 + (offset & ~1)]; + else + return m_rom[0xc100 + offset]; + } +} + +WRITE8_MEMBER(a1bus_cassette_device::cassette_w) +{ + /* Writes toggle the output flip-flop in the same way that reads + do; other than that they have no effect. Any repeated accesses + to the cassette I/O address range can be used to write data to + cassette, and the cassette ROM always uses reads to do this. + However, we still have to handle writes, since they may be done + by user code. */ + + cassette_toggle_output(); +} diff --git a/src/devices/bus/a1bus/a1cassette.h b/src/devices/bus/a1bus/a1cassette.h new file mode 100644 index 00000000000..e8d656c1c3a --- /dev/null +++ b/src/devices/bus/a1bus/a1cassette.h @@ -0,0 +1,53 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/********************************************************************* + + a1cassette.h + + Apple I Cassette Interface + +*********************************************************************/ + +#ifndef __A1BUS_CASSETTE__ +#define __A1BUS_CASSETTE__ + +#include "a1bus.h" +#include "imagedev/cassette.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class a1bus_cassette_device: + public device_t, + public device_a1bus_card_interface +{ +public: + // construction/destruction + a1bus_cassette_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + a1bus_cassette_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual const rom_entry *device_rom_region() const; + + optional_device m_cassette; + + DECLARE_READ8_MEMBER(cassette_r); + DECLARE_WRITE8_MEMBER(cassette_w); + +protected: + virtual void device_start(); + virtual void device_reset(); + + void cassette_toggle_output(); + +private: + UINT8 *m_rom; + int m_cassette_output_flipflop; +}; + +// device type definition +extern const device_type A1BUS_CASSETTE; + +#endif /* __A1BUS_CASSETTE__ */ diff --git a/src/devices/bus/a1bus/a1cffa.c b/src/devices/bus/a1bus/a1cffa.c new file mode 100644 index 00000000000..f67470bb5db --- /dev/null +++ b/src/devices/bus/a1bus/a1cffa.c @@ -0,0 +1,156 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/********************************************************************* + + a1cffa.c + + Rich Dreher's Compact Flash for Apple I + +*********************************************************************/ + +#include "a1cffa.h" + +/*************************************************************************** + PARAMETERS +***************************************************************************/ + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +#define CFFA_ROM_REGION "cffa_rom" +#define CFFA_ATA_TAG "cffa_ata" + +const device_type A1BUS_CFFA = &device_creator; + +MACHINE_CONFIG_FRAGMENT( cffa ) + MCFG_ATA_INTERFACE_ADD(CFFA_ATA_TAG, ata_devices, "hdd", NULL, false) +MACHINE_CONFIG_END + +ROM_START( cffa ) + ROM_REGION(0x2000, CFFA_ROM_REGION, 0) + ROM_LOAD ("cffaromv1.1.bin", 0x0000, 0x1fe0, CRC(bf6b55ad) SHA1(6a290be18485a06f243a3561c4e01be5aafa4bfe) ) +ROM_END + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor a1bus_cffa_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( cffa ); +} + +const rom_entry *a1bus_cffa_device::device_rom_region() const +{ + return ROM_NAME( cffa ); +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +a1bus_cffa_device::a1bus_cffa_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, A1BUS_CFFA, "CFFA Compact Flash for Apple I", tag, owner, clock, "cffa1", __FILE__), + device_a1bus_card_interface(mconfig, *this), + m_ata(*this, CFFA_ATA_TAG) +{ +} + +a1bus_cffa_device::a1bus_cffa_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_a1bus_card_interface(mconfig, *this), + m_ata(*this, CFFA_ATA_TAG) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void a1bus_cffa_device::device_start() +{ + set_a1bus_device(); + + m_rom = device().machine().root_device().memregion(this->subtag(CFFA_ROM_REGION).c_str())->base(); + + install_device(0xafe0, 0xafff, read8_delegate(FUNC(a1bus_cffa_device::cffa_r), this), write8_delegate(FUNC(a1bus_cffa_device::cffa_w), this)); + install_bank(0x9000, 0xafdf, 0, 0, (char *)"bank_cffa1", m_rom); + + save_item(NAME(m_lastdata)); + save_item(NAME(m_writeprotect)); +} + +void a1bus_cffa_device::device_reset() +{ + m_writeprotect = false; + m_lastdata = 0; +} + +READ8_MEMBER(a1bus_cffa_device::cffa_r) +{ + switch (offset & 0xf) + { + case 0x0: + return m_lastdata>>8; + + case 0x3: + m_writeprotect = false; + break; + + case 0x4: + m_writeprotect = true; + break; + + case 0x8: + m_lastdata = m_ata->read_cs0(space, (offset & 0xf) - 8, 0xff); + return m_lastdata & 0x00ff; + + case 0x9: + case 0xa: + case 0xb: + case 0xc: + case 0xd: + case 0xe: + case 0xf: + return m_ata->read_cs0(space, (offset & 0xf) - 8, 0xff); + } + + return 0xff; +} + +WRITE8_MEMBER(a1bus_cffa_device::cffa_w) +{ + switch (offset & 0xf) + { + case 0x0: + m_lastdata &= 0x00ff; + m_lastdata |= data<<8; + break; + + case 0x3: + m_writeprotect = false; + break; + + case 0x4: + m_writeprotect = true; + break; + + + case 0x8: + m_ata->write_cs0(space, (offset & 0xf) - 8, data, 0xff); + break; + + case 0x9: + case 0xa: + case 0xb: + case 0xc: + case 0xd: + case 0xe: + case 0xf: + m_ata->write_cs0(space, (offset & 0xf) - 8, data, 0xff); + break; + + } +} diff --git a/src/devices/bus/a1bus/a1cffa.h b/src/devices/bus/a1bus/a1cffa.h new file mode 100644 index 00000000000..a1dc4258cbc --- /dev/null +++ b/src/devices/bus/a1bus/a1cffa.h @@ -0,0 +1,53 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/********************************************************************* + + a1cffa.h + + Rich Dreher's Compact Flash for Apple I + +*********************************************************************/ + +#ifndef __A1BUS_CFFA__ +#define __A1BUS_CFFA__ + +#include "emu.h" +#include "a1bus.h" +#include "machine/ataintf.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class a1bus_cffa_device: + public device_t, + public device_a1bus_card_interface +{ +public: + // construction/destruction + a1bus_cffa_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + a1bus_cffa_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual const rom_entry *device_rom_region() const; + + required_device m_ata; + + DECLARE_READ8_MEMBER(cffa_r); + DECLARE_WRITE8_MEMBER(cffa_w); + +protected: + virtual void device_start(); + virtual void device_reset(); + +private: + UINT8 *m_rom; + UINT16 m_lastdata; + bool m_writeprotect; +}; + +// device type definition +extern const device_type A1BUS_CFFA; + +#endif /* __A1BUS_CFFA__ */ diff --git a/src/devices/bus/a2bus/a2alfam2.c b/src/devices/bus/a2bus/a2alfam2.c new file mode 100644 index 00000000000..3a35c8ab253 --- /dev/null +++ b/src/devices/bus/a2bus/a2alfam2.c @@ -0,0 +1,181 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/********************************************************************* + + a2alfsm2.c + + Implementation of the ALF Apple Music II card (originally marketed as the "MC1") + The AE Super Music Synthesizer is a superset of this card (4x76489 instead of 3) + +*********************************************************************/ + +#include "a2alfam2.h" +#include "includes/apple2.h" +#include "sound/sn76496.h" + +/*************************************************************************** + PARAMETERS +***************************************************************************/ + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type A2BUS_ALFAM2 = &device_creator; +const device_type A2BUS_AESMS = &device_creator; + +#define SN1_TAG "sn76489_1" // left +#define SN2_TAG "sn76489_2" // center +#define SN3_TAG "sn76489_3" // right +#define SN4_TAG "sn76489_4" // center? + +MACHINE_CONFIG_FRAGMENT( a2alfam2 ) + MCFG_SPEAKER_STANDARD_STEREO("alf_l", "alf_r") + + MCFG_SOUND_ADD(SN1_TAG, SN76489, 1020484) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "alf_l", 0.50) + MCFG_SOUND_ADD(SN2_TAG, SN76489, 1020484) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "alf_l", 0.50) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "alf_r", 0.50) + MCFG_SOUND_ADD(SN3_TAG, SN76489, 1020484) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "alf_r", 0.50) +MACHINE_CONFIG_END + +MACHINE_CONFIG_FRAGMENT( a2aesms ) + MCFG_SPEAKER_STANDARD_STEREO("alf_l", "alf_r") + + MCFG_SOUND_ADD(SN1_TAG, SN76489, 1020484) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "alf_l", 0.50) + + MCFG_SOUND_ADD(SN2_TAG, SN76489, 1020484) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "alf_l", 0.50) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "alf_r", 0.50) + + MCFG_SOUND_ADD(SN3_TAG, SN76489, 1020484) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "alf_r", 0.50) + + MCFG_SOUND_ADD(SN4_TAG, SN76489, 1020484) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "alf_l", 0.50) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "alf_r", 0.50) +MACHINE_CONFIG_END + +/*************************************************************************** + FUNCTION PROTOTYPES +***************************************************************************/ + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor a2bus_sn76489_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( a2alfam2 ); +} + +machine_config_constructor a2bus_aesms_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( a2aesms ); +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +a2bus_sn76489_device::a2bus_sn76489_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_a2bus_card_interface(mconfig, *this), + m_sn1(*this, SN1_TAG), + m_sn2(*this, SN2_TAG), + m_sn3(*this, SN3_TAG), + m_sn4(*this, SN4_TAG) +{ +} + +a2bus_alfam2_device::a2bus_alfam2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + a2bus_sn76489_device(mconfig, A2BUS_ALFAM2, "ALF MC1 / Apple Music II", tag, owner, clock, "a2alfam2", __FILE__) +{ + m_has4thsn = false; +} + +a2bus_aesms_device::a2bus_aesms_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + a2bus_sn76489_device(mconfig, A2BUS_ALFAM2, "Applied Engineering Super Music Synthesizer", tag, owner, clock, "a2aesms", __FILE__) +{ + m_has4thsn = true; +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void a2bus_sn76489_device::device_start() +{ + // set_a2bus_device makes m_slot valid + set_a2bus_device(); + m_latch0 = m_latch1 = m_latch2 = m_latch3 = 0; + + save_item(NAME(m_latch0)); + save_item(NAME(m_latch1)); + save_item(NAME(m_latch2)); + save_item(NAME(m_latch3)); +} + +void a2bus_sn76489_device::device_reset() +{ + m_latch0 = m_latch1 = m_latch2 = m_latch3 = 0; +} + +UINT8 a2bus_sn76489_device::read_c0nx(address_space &space, UINT8 offset) +{ + // SN76489 can't be read, it appears from the schematics this is what happens + switch (offset) + { + case 0: + return m_latch0; + + case 1: + return m_latch1; + + case 2: + return m_latch2; + + case 3: + return m_latch3; + } + + return 0xff; +} + +void a2bus_sn76489_device::write_c0nx(address_space &space, UINT8 offset, UINT8 data) +{ + switch (offset) + { + case 0: + m_sn1->write(space, 0, data); + m_latch0 = data; + break; + + case 1: + m_sn2->write(space, 0, data); + m_latch1 = data; + break; + + case 2: + m_sn3->write(space, 0, data); + m_latch2 = data; + break; + + case 3: + if (m_has4thsn) + { + m_sn4->write(space, 0, data); + m_latch3 = data; + } + break; + } +} + +bool a2bus_sn76489_device::take_c800() +{ + return false; +} diff --git a/src/devices/bus/a2bus/a2alfam2.h b/src/devices/bus/a2bus/a2alfam2.h new file mode 100644 index 00000000000..ab2ee9e38a4 --- /dev/null +++ b/src/devices/bus/a2bus/a2alfam2.h @@ -0,0 +1,72 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/********************************************************************* + + a2alfam2.h + + Implementation of the ALF Apple Music II card and compatibles + +*********************************************************************/ + +#ifndef __A2BUS_ALFAM2__ +#define __A2BUS_ALFAM2__ + +#include "emu.h" +#include "a2bus.h" +#include "sound/sn76496.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class a2bus_sn76489_device: + public device_t, + public device_a2bus_card_interface +{ +public: + // construction/destruction + a2bus_sn76489_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + + required_device m_sn1; + required_device m_sn2; + required_device m_sn3; + optional_device m_sn4; + +protected: + virtual void device_start(); + virtual void device_reset(); + + // overrides of standard a2bus slot functions + virtual UINT8 read_c0nx(address_space &space, UINT8 offset); + virtual void write_c0nx(address_space &space, UINT8 offset, UINT8 data); + virtual bool take_c800(); + +private: + UINT8 m_latch0, m_latch1, m_latch2, m_latch3; + +protected: + bool m_has4thsn; +}; + +class a2bus_alfam2_device : public a2bus_sn76489_device +{ +public: + a2bus_alfam2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class a2bus_aesms_device : public a2bus_sn76489_device +{ +public: + a2bus_aesms_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual machine_config_constructor device_mconfig_additions() const; +}; + +// device type definition +extern const device_type A2BUS_ALFAM2; +extern const device_type A2BUS_AESMS; + +#endif /* __A2BUS_ALFAM2__ */ diff --git a/src/devices/bus/a2bus/a2applicard.c b/src/devices/bus/a2bus/a2applicard.c new file mode 100644 index 00000000000..6698ea4f68c --- /dev/null +++ b/src/devices/bus/a2bus/a2applicard.c @@ -0,0 +1,286 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/********************************************************************* + + a2applicard.c + + Implementation of the PCPI AppliCard Z-80 card + + Unlike the SoftCard and clones, this has its own 64k of RAM on board + and the Z80 runs completely independently of the host's 6502. + +*********************************************************************/ + +#include "a2applicard.h" +#include "includes/apple2.h" +#include "cpu/z80/z80.h" +#include "machine/z80ctc.h" + +/*************************************************************************** + PARAMETERS +***************************************************************************/ + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type A2BUS_APPLICARD = &device_creator; + +#define Z80_TAG "z80" +#define Z80_ROM_REGION "z80_rom" + +static ADDRESS_MAP_START( z80_mem, AS_PROGRAM, 8, a2bus_applicard_device ) + AM_RANGE(0x0000, 0xffff) AM_READWRITE(dma_r, dma_w) +ADDRESS_MAP_END + +static ADDRESS_MAP_START( z80_io, AS_IO, 8, a2bus_applicard_device ) + AM_RANGE(0x00, 0x60) AM_MIRROR(0xff00) AM_READWRITE(z80_io_r, z80_io_w) +ADDRESS_MAP_END + +MACHINE_CONFIG_FRAGMENT( a2applicard ) + MCFG_CPU_ADD(Z80_TAG, Z80, 6000000) // Z80 runs at 6 MHz + MCFG_CPU_PROGRAM_MAP(z80_mem) + MCFG_CPU_IO_MAP(z80_io) +MACHINE_CONFIG_END + +ROM_START( a2applicard ) + ROM_REGION(0x800, Z80_ROM_REGION, 0) + ROM_LOAD( "applicard-v9.bin", 0x000000, 0x000800, CRC(1d461000) SHA1(71d633be864b6084362e85108a4e600cbe6e44fe) ) +ROM_END + +/*************************************************************************** + FUNCTION PROTOTYPES +***************************************************************************/ + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor a2bus_applicard_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( a2applicard ); +} + +//------------------------------------------------- +// device_rom_region - device-specific ROMs +//------------------------------------------------- + +const rom_entry *a2bus_applicard_device::device_rom_region() const +{ + return ROM_NAME( a2applicard ); +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +a2bus_applicard_device::a2bus_applicard_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_a2bus_card_interface(mconfig, *this), + m_z80(*this, Z80_TAG) +{ +} + +a2bus_applicard_device::a2bus_applicard_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, A2BUS_APPLICARD, "PCPI Applicard", tag, owner, clock, "a2aplcrd", __FILE__), + device_a2bus_card_interface(mconfig, *this), + m_z80(*this, Z80_TAG) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void a2bus_applicard_device::device_start() +{ + // set_a2bus_device makes m_slot valid + set_a2bus_device(); + + // locate Z80 ROM + m_z80rom = device().machine().root_device().memregion(this->subtag(Z80_ROM_REGION).c_str())->base(); + + save_item(NAME(m_bROMAtZ80Zero)); + save_item(NAME(m_z80stat)); + save_item(NAME(m_6502stat)); + save_item(NAME(m_toz80)); + save_item(NAME(m_to6502)); + save_item(NAME(m_z80ram)); + + memset(m_z80ram, 0, 64*1024); +} + +void a2bus_applicard_device::device_reset() +{ + m_bROMAtZ80Zero = true; + m_z80stat = false; +} + +UINT8 a2bus_applicard_device::read_c0nx(address_space &space, UINT8 offset) +{ + switch (offset & 0xf) + { + case 0: + m_6502stat = false; + return m_to6502; + + case 1: + return m_toz80; + + case 2: + if (m_z80stat) + { + return 0x80; + } + return false; + + case 3: + if (m_6502stat) + { + return 0x80; + } + return false; + + case 5: + m_bROMAtZ80Zero = true; + m_toz80 = false; + m_to6502 = false; + m_z80->reset(); + break; + + case 6: // IRQ on Z80 via CTC channel 3 (CP/M doesn't use the CTC or IRQs) + fatalerror("Applicard: Z80 IRQ not supported yet\n"); + + case 7: // NMI on Z80 (direct) + m_z80->set_input_line(INPUT_LINE_NMI, PULSE_LINE); + break; + + } + return 0xff; +} + +void a2bus_applicard_device::write_c0nx(address_space &space, UINT8 offset, UINT8 data) +{ + switch (offset & 0xf) + { + case 0: // are these legal to write? + case 2: + case 3: + break; + + case 1: + m_z80stat = true; + m_toz80 = data; + break; + + case 5: + case 6: + case 7: + read_c0nx(space, offset); // let the read handler take care of these + break; + } +} + +READ8_MEMBER( a2bus_applicard_device::z80_io_r ) +{ + UINT8 tmp = 0; + + switch (offset) + { + case 0: + return m_to6502; + + case 0x20: + m_z80stat = false; + return m_toz80; + + case 0x40: + if (m_z80stat) + { + tmp |= 0x80; + } + if (m_6502stat) + { + tmp |= 1; + } + return tmp; + + case 0x60: + break; + } + return 0xff; +} + +WRITE8_MEMBER( a2bus_applicard_device::z80_io_w ) +{ + switch (offset) + { + case 0: + m_to6502 = data; + m_6502stat = true; + break; + + case 0x60: + if (data & 1) + { + m_bROMAtZ80Zero = true; + } + else + { + m_bROMAtZ80Zero = false; + } + break; + } +} + +//------------------------------------------------- +// dma_r - +//------------------------------------------------- + +READ8_MEMBER( a2bus_applicard_device::dma_r ) +{ + if (offset < 0x8000) + { + if (m_bROMAtZ80Zero) + { + return m_z80rom[offset & 0x7ff]; + } + else + { + return m_z80ram[offset]; + } + } + else + { + return m_z80ram[offset]; + } + // never executed + //return 0xff; +} + + +//------------------------------------------------- +// dma_w - +//------------------------------------------------- + +WRITE8_MEMBER( a2bus_applicard_device::dma_w ) +{ + if (offset < 0x8000) + { + // writing only works if ROM not mapped from 0-7fff + if (!m_bROMAtZ80Zero) + { + m_z80ram[offset] = data; + } + } + else + { + m_z80ram[offset] = data; + } +} + +bool a2bus_applicard_device::take_c800() +{ + return false; +} diff --git a/src/devices/bus/a2bus/a2applicard.h b/src/devices/bus/a2bus/a2applicard.h new file mode 100644 index 00000000000..b015d84fe6a --- /dev/null +++ b/src/devices/bus/a2bus/a2applicard.h @@ -0,0 +1,61 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/********************************************************************* + + a2applicard.h + + Implementation of the PCPI AppliCard Z-80 card + +*********************************************************************/ + +#ifndef __A2BUS_APPLICARD__ +#define __A2BUS_APPLICARD__ + +#include "emu.h" +#include "a2bus.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class a2bus_applicard_device: + public device_t, + public device_a2bus_card_interface +{ +public: + // construction/destruction + a2bus_applicard_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + a2bus_applicard_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + + DECLARE_READ8_MEMBER( dma_r ); + DECLARE_WRITE8_MEMBER( dma_w ); + DECLARE_READ8_MEMBER( z80_io_r ); + DECLARE_WRITE8_MEMBER( z80_io_w ); + +protected: + virtual void device_start(); + virtual void device_reset(); + virtual const rom_entry *device_rom_region() const; + + // overrides of standard a2bus slot functions + virtual UINT8 read_c0nx(address_space &space, UINT8 offset); + virtual void write_c0nx(address_space &space, UINT8 offset, UINT8 data); + virtual bool take_c800(); + + required_device m_z80; + +private: + bool m_bROMAtZ80Zero; + bool m_z80stat, m_6502stat; + UINT8 m_toz80, m_to6502; + UINT8 m_z80ram[64*1024]; + UINT8 *m_z80rom; +}; + +// device type definition +extern const device_type A2BUS_APPLICARD; + +#endif /* __A2BUS_APPLICARD__ */ diff --git a/src/devices/bus/a2bus/a2arcadebd.c b/src/devices/bus/a2bus/a2arcadebd.c new file mode 100644 index 00000000000..dcad400f8b1 --- /dev/null +++ b/src/devices/bus/a2bus/a2arcadebd.c @@ -0,0 +1,149 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/********************************************************************* + + a2arcadeboard.c + + Implementation of the Third Millenium Engineering Arcade Board + + TODO: + - VDPTEST program seems to want more than 16K of RAM, but docs/ads/press releases say 16k, period + - MLDEMO program needs vsync IRQ from the TMS but doesn't program the registers the way our emulation + wants to enable IRQs + +*********************************************************************/ + +#include "emu.h" +#include "a2arcadebd.h" + + +/*************************************************************************** + PARAMETERS +***************************************************************************/ + +#define TMS_TAG "arcbd_tms" +#define AY_TAG "arcbd_ay" +#define SCREEN_TAG "screen" + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type A2BUS_ARCADEBOARD = &device_creator; + +MACHINE_CONFIG_FRAGMENT( arcadeboard ) + MCFG_DEVICE_ADD( TMS_TAG, TMS9918A, XTAL_10_738635MHz / 2 ) + MCFG_TMS9928A_VRAM_SIZE(0x4000) // 16k of VRAM + MCFG_TMS9928A_OUT_INT_LINE_CB(WRITELINE(a2bus_arcboard_device, tms_irq_w)) + MCFG_TMS9928A_SCREEN_ADD_NTSC( SCREEN_TAG ) + MCFG_SCREEN_UPDATE_DEVICE( TMS_TAG, tms9918a_device, screen_update ) + + MCFG_SPEAKER_STANDARD_MONO("mono") + MCFG_SOUND_ADD(AY_TAG, AY8910, 1022727) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 1.0) +MACHINE_CONFIG_END + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor a2bus_arcboard_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( arcadeboard ); +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +a2bus_arcboard_device::a2bus_arcboard_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, A2BUS_ARCADEBOARD, "Third Millenium Engineering Arcade Board", tag, owner, clock, "a2arcbd", __FILE__), + device_a2bus_card_interface(mconfig, *this), + m_tms(*this, TMS_TAG), + m_ay(*this, AY_TAG) +{ +} + +a2bus_arcboard_device::a2bus_arcboard_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_a2bus_card_interface(mconfig, *this), + m_tms(*this, TMS_TAG), + m_ay(*this, AY_TAG) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void a2bus_arcboard_device::device_start() +{ + // set_a2bus_device makes m_slot valid + set_a2bus_device(); +} + +void a2bus_arcboard_device::device_reset() +{ +} + +/* + C0nx map: + 0 - TMS read vram + 1 - TMS read status + 2 - TMS write vram + 3 - TMS write register + 5 - AY register select + 6 - AY data +*/ + +UINT8 a2bus_arcboard_device::read_c0nx(address_space &space, UINT8 offset) +{ + switch (offset) + { + case 0: + return m_tms->vram_read(space, 0); + + case 1: + return m_tms->register_read(space, 0); + + case 6: + return m_ay->data_r(space, 0); + } + + return 0xff; +} + +void a2bus_arcboard_device::write_c0nx(address_space &space, UINT8 offset, UINT8 data) +{ + switch (offset) + { + case 2: + m_tms->vram_write(space, 0, data); + break; + + case 3: + m_tms->register_write(space, 0, data); + break; + + case 5: + m_ay->address_w(space, 0, data); + break; + + case 6: + m_ay->data_w(space, 0, data); + break; + } +} + +WRITE_LINE_MEMBER( a2bus_arcboard_device::tms_irq_w ) +{ + if (state) + { + raise_slot_irq(); + } + else + { + lower_slot_irq(); + } +} diff --git a/src/devices/bus/a2bus/a2arcadebd.h b/src/devices/bus/a2bus/a2arcadebd.h new file mode 100644 index 00000000000..ae39c51eac6 --- /dev/null +++ b/src/devices/bus/a2bus/a2arcadebd.h @@ -0,0 +1,54 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/********************************************************************* + + a2arcadebd.h + + Third Millenium Engineering Arcade Board + +*********************************************************************/ + +#ifndef __A2BUS_ARCADEBOARD__ +#define __A2BUS_ARCADEBOARD__ + +#include "emu.h" +#include "a2bus.h" +#include "video/tms9928a.h" +#include "sound/ay8910.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class a2bus_arcboard_device: + public device_t, + public device_a2bus_card_interface +{ +public: + // construction/destruction + a2bus_arcboard_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + a2bus_arcboard_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + + DECLARE_WRITE_LINE_MEMBER( tms_irq_w ); + +protected: + virtual void device_start(); + virtual void device_reset(); + + // overrides of standard a2bus slot functions + virtual UINT8 read_c0nx(address_space &space, UINT8 offset); + virtual void write_c0nx(address_space &space, UINT8 offset, UINT8 data); + + required_device m_tms; + required_device m_ay; + +private: +}; + +// device type definition +extern const device_type A2BUS_ARCADEBOARD; + +#endif /* __A2BUS_ARCADEBOARD__ */ diff --git a/src/devices/bus/a2bus/a2bus.c b/src/devices/bus/a2bus/a2bus.c new file mode 100644 index 00000000000..cd2eab4eea7 --- /dev/null +++ b/src/devices/bus/a2bus/a2bus.c @@ -0,0 +1,334 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/*************************************************************************** + + a2bus.c - Apple II slot bus and card emulation + + by R. Belmont + + Pinout (/ indicates an inverted signal, ie, one that would have a bar over it + on a schematic diagram) + + (rear of computer) + + GND 26 25 +5V + DMA IN 27 24 DMA OUT + INT IN 28 23 INT OUT + /NMI 29 22 /DMA + /IRQ 30 21 RDY + /RES 31 20 /IOSTB + /INH 32 19 N.C. + -12V 33 18 R/W + -5V 34 17 A15 + N.C. 35 16 A14 + 7M 36 15 A13 + Q3 37 14 A12 + PH1 38 13 A11 + USER 1 39 12 A10 + PH0 40 11 A9 + /DEVSEL 41 10 A8 + D7 42 9 A7 + D6 43 8 A6 + D5 44 7 A5 + D4 45 6 A4 + D3 46 5 A3 + D2 47 4 A2 + D1 48 3 A1 + D0 49 2 A0 + -12V 50 1 /IOSEL + + (front of computer) + + Signal descriptions: + GND - power supply ground + DMA IN - daisy chain of DMA signal from higher priority devices. usually connected to DMA OUT. + INT IN - similar to DMA IN but for INT instead of DMA. + /NMI - non-maskable interrupt input to the 6502 + /IRQ - maskable interrupt input to the 6502 + /RES - system reset signal + /INH - On the II and II+, inhibits the motherboard ROMs, allowing a card to replace them. + On the IIe, inhibits all motherboard RAM/ROM for both CPU and DMA accesses. + On the IIgs, works like the IIe except for the address range 0x6000 to 0x9FFF where + it will cause bus contention. + -12V - negative 12 volts DC power + -5V - negative 5 volts DC power + 7M - 7 MHz clock (1/4th of the master clock on the IIgs, 1/2 on 8-bit IIs) + Q3 - 2 MHz asymmetrical clock + PH1 - 6502 phase 1 clock + /DEVSEL - asserted on an access to C0nX, where n = the slot number plus 8. + D0-D7 - 8-bit data bus + +5V - 5 volts DC power + DMA OUT - see DMA IN + INT OUT - see INT IN + /DMA - pulling this low disconnects the 6502 from the bus and halts it + RDY - 6502 RDY input. Pulling this low when PH1 is active will halt the + 6502 and latch the current address bus value. + /IOSTB - asserted on an access between C800 and CFFF. + A0-A15 - 16-bit address bus + /IOSEL - asserted on accesses to CnXX where n is the slot number. + Not present on slot 0. + +***************************************************************************/ + +#include "emu.h" +#include "emuopts.h" +#include "a2bus.h" + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type A2BUS_SLOT = &device_creator; + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// a2bus_slot_device - constructor +//------------------------------------------------- +a2bus_slot_device::a2bus_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, A2BUS_SLOT, "Apple II Slot", tag, owner, clock, "a2bus_slot", __FILE__), + device_slot_interface(mconfig, *this) +{ +} + +a2bus_slot_device::a2bus_slot_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_slot_interface(mconfig, *this) +{ +} + +void a2bus_slot_device::static_set_a2bus_slot(device_t &device, const char *tag, const char *slottag) +{ + a2bus_slot_device &a2bus_card = dynamic_cast(device); + a2bus_card.m_a2bus_tag = tag; + a2bus_card.m_a2bus_slottag = slottag; +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void a2bus_slot_device::device_start() +{ + device_a2bus_card_interface *dev = dynamic_cast(get_card_device()); + + if (dev) device_a2bus_card_interface::static_set_a2bus_tag(*dev, m_a2bus_tag, m_a2bus_slottag); +} + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type A2BUS = &device_creator; + +void a2bus_device::static_set_cputag(device_t &device, const char *tag) +{ + a2bus_device &a2bus = downcast(device); + a2bus.m_cputag = tag; +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// a2bus_device - constructor +//------------------------------------------------- + +a2bus_device::a2bus_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, A2BUS, "Apple II Bus", tag, owner, clock, "a2bus", __FILE__), + m_out_irq_cb(*this), + m_out_nmi_cb(*this), + m_out_inh_cb(*this) +{ +} + +a2bus_device::a2bus_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + m_out_irq_cb(*this), + m_out_nmi_cb(*this), + m_out_inh_cb(*this) +{ +} +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void a2bus_device::device_start() +{ + m_maincpu = machine().device(m_cputag); + m_maincpu_space = &machine().device(m_cputag)->space(AS_PROGRAM); + + // resolve callbacks + m_out_irq_cb.resolve_safe(); + m_out_nmi_cb.resolve_safe(); + m_out_inh_cb.resolve_safe(); + + // clear slots + for (int i = 0; i < 8; i++) + { + m_device_list[i] = NULL; + } + + m_slot_irq_mask = m_slot_nmi_mask = 0; +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void a2bus_device::device_reset() +{ +} + +device_a2bus_card_interface *a2bus_device::get_a2bus_card(int slot) +{ + if (slot < 0) + { + return NULL; + } + + if (m_device_list[slot]) + { + return m_device_list[slot]; + } + + return NULL; +} + +void a2bus_device::add_a2bus_card(int slot, device_a2bus_card_interface *card) +{ + m_device_list[slot] = card; +} + +UINT8 a2bus_device::get_a2bus_irq_mask() +{ + return m_slot_irq_mask; +} + +UINT8 a2bus_device::get_a2bus_nmi_mask() +{ + return m_slot_nmi_mask; +} + +void a2bus_device::set_irq_line(int state, int slot) +{ + m_out_irq_cb(state); + + if (state == CLEAR_LINE) + { + m_slot_irq_mask &= ~(1<set_input_line(INPUT_LINE_HALT, state); +} + +UINT8 a2bus_device::dma_r(address_space &space, UINT16 offset) +{ + m_maincpu_space->set_debugger_access(space.debugger_access()); + + return m_maincpu_space->read_byte(offset); +} + +void a2bus_device::dma_w(address_space &space, UINT16 offset, UINT8 data) +{ + m_maincpu_space->set_debugger_access(space.debugger_access()); + + m_maincpu_space->write_byte(offset, data); +} + +UINT8 a2bus_device::dma_nospace_r(UINT16 offset) +{ + return m_maincpu_space->read_byte(offset); +} + +void a2bus_device::dma_nospace_w(UINT16 offset, UINT8 data) +{ + m_maincpu_space->write_byte(offset, data); +} + +void a2bus_device::recalc_inh(int slot) +{ + m_out_inh_cb(ASSERT_LINE); + m_out_inh_cb(CLEAR_LINE); +} + +// interrupt request from a2bus card +WRITE_LINE_MEMBER( a2bus_device::irq_w ) { m_out_irq_cb(state); } +WRITE_LINE_MEMBER( a2bus_device::nmi_w ) { m_out_nmi_cb(state); } + +//************************************************************************** +// DEVICE CONFIG A2BUS CARD INTERFACE +//************************************************************************** + + +//************************************************************************** +// DEVICE A2BUS CARD INTERFACE +//************************************************************************** + +//------------------------------------------------- +// device_a2bus_card_interface - constructor +//------------------------------------------------- + +device_a2bus_card_interface::device_a2bus_card_interface(const machine_config &mconfig, device_t &device) + : device_slot_card_interface(mconfig, device), + m_a2bus(NULL), + m_a2bus_tag(NULL) +{ +} + + +//------------------------------------------------- +// ~device_a2bus_card_interface - destructor +//------------------------------------------------- + +device_a2bus_card_interface::~device_a2bus_card_interface() +{ +} + +void device_a2bus_card_interface::static_set_a2bus_tag(device_t &device, const char *tag, const char *slottag) +{ + device_a2bus_card_interface &a2bus_card = dynamic_cast(device); + a2bus_card.m_a2bus_tag = tag; + a2bus_card.m_a2bus_slottag = slottag; +} + +void device_a2bus_card_interface::set_a2bus_device() +{ + // extract the slot number from the last digit of the slot tag + int tlen = strlen(m_a2bus_slottag); + + m_slot = (m_a2bus_slottag[tlen-1] - '0'); + + if (m_slot < 0 || m_slot > 7) + { + fatalerror("Slot %x out of range for Apple II Bus\n", m_slot); + } + + m_a2bus = dynamic_cast(device().machine().device(m_a2bus_tag)); + m_a2bus->add_a2bus_card(m_slot, this); +} diff --git a/src/devices/bus/a2bus/a2bus.h b/src/devices/bus/a2bus/a2bus.h new file mode 100644 index 00000000000..90ab602607d --- /dev/null +++ b/src/devices/bus/a2bus/a2bus.h @@ -0,0 +1,197 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/*************************************************************************** + + a2bus.h - Apple II slot bus and card emulation + + by R. Belmont + +***************************************************************************/ + +#pragma once + +#ifndef __A2BUS_H__ +#define __A2BUS_H__ + +#include "emu.h" + +// /INH special addresses +#define INH_START_INVALID 0xffff; +#define INH_END_INVALID 0x0000; + +// /INH types +#define INH_NONE 0x00 +#define INH_READ 0x01 +#define INH_WRITE 0x02 + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_A2BUS_CPU(_cputag) \ + a2bus_device::static_set_cputag(*device, _cputag); + +#define MCFG_A2BUS_OUT_IRQ_CB(_devcb) \ + devcb = &a2bus_device::set_out_irq_callback(*device, DEVCB_##_devcb); + +#define MCFG_A2BUS_OUT_NMI_CB(_devcb) \ + devcb = &a2bus_device::set_out_nmi_callback(*device, DEVCB_##_devcb); + +#define MCFG_A2BUS_OUT_INH_CB(_devcb) \ + devcb = &a2bus_device::set_out_inh_callback(*device, DEVCB_##_devcb); + +#define MCFG_A2BUS_SLOT_ADD(_nbtag, _tag, _slot_intf, _def_slot) \ + MCFG_DEVICE_ADD(_tag, A2BUS_SLOT, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) \ + a2bus_slot_device::static_set_a2bus_slot(*device, _nbtag, _tag); +#define MCFG_A2BUS_SLOT_REMOVE(_tag) \ + MCFG_DEVICE_REMOVE(_tag) + +#define MCFG_A2BUS_ONBOARD_ADD(_nbtag, _tag, _dev_type, _def_inp) \ + MCFG_DEVICE_ADD(_tag, _dev_type, 0) \ + MCFG_DEVICE_INPUT_DEFAULTS(_def_inp) \ + device_a2bus_card_interface::static_set_a2bus_tag(*device, _nbtag, _tag); + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class a2bus_device; + +class a2bus_slot_device : public device_t, + public device_slot_interface +{ +public: + // construction/destruction + a2bus_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + a2bus_slot_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + // device-level overrides + virtual void device_start(); + + // inline configuration + static void static_set_a2bus_slot(device_t &device, const char *tag, const char *slottag); +protected: + // configuration + const char *m_a2bus_tag, *m_a2bus_slottag; +}; + +// device type definition +extern const device_type A2BUS_SLOT; + + +class device_a2bus_card_interface; +// ======================> a2bus_device +class a2bus_device : public device_t +{ + // multi-card devices need to access m_device_list, so they get friend'ed here. + friend class a2bus_mcms2_device; +public: + // construction/destruction + a2bus_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + a2bus_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + // inline configuration + static void static_set_cputag(device_t &device, const char *tag); + template static devcb_base &set_out_irq_callback(device_t &device, _Object object) { return downcast(device).m_out_irq_cb.set_callback(object); } + template static devcb_base &set_out_nmi_callback(device_t &device, _Object object) { return downcast(device).m_out_nmi_cb.set_callback(object); } + template static devcb_base &set_out_inh_callback(device_t &device, _Object object) { return downcast(device).m_out_inh_cb.set_callback(object); } + + void add_a2bus_card(int slot, device_a2bus_card_interface *card); + device_a2bus_card_interface *get_a2bus_card(int slot); + UINT8 get_a2bus_irq_mask(); + UINT8 get_a2bus_nmi_mask(); + + void set_irq_line(int state, int slot); + void set_nmi_line(int state, int slot); + void set_maincpu_halt(int state); + void recalc_inh(int slot); + UINT8 dma_r(address_space &space, UINT16 offset); + void dma_w(address_space &space, UINT16 offset, UINT8 data); + UINT8 dma_nospace_r(UINT16 offset); + void dma_nospace_w(UINT16 offset, UINT8 data); + + DECLARE_WRITE_LINE_MEMBER( irq_w ); + DECLARE_WRITE_LINE_MEMBER( nmi_w ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // internal state + cpu_device *m_maincpu; + address_space *m_maincpu_space; + + devcb_write_line m_out_irq_cb; + devcb_write_line m_out_nmi_cb; + devcb_write8 m_out_inh_cb; + + device_a2bus_card_interface *m_device_list[8]; + const char *m_cputag; + + UINT8 m_slot_irq_mask; + UINT8 m_slot_nmi_mask; +}; + + +// device type definition +extern const device_type A2BUS; + +// ======================> device_a2bus_card_interface + +// class representing interface-specific live a2bus card +class device_a2bus_card_interface : public device_slot_card_interface +{ + friend class a2bus_device; +public: + // construction/destruction + device_a2bus_card_interface(const machine_config &mconfig, device_t &device); + virtual ~device_a2bus_card_interface(); + + virtual UINT8 read_c0nx(address_space &space, UINT8 offset) { logerror("a2bus: unhandled read at C0n%x\n", offset); return 0; } // C0nX - /DEVSEL + virtual void write_c0nx(address_space &space, UINT8 offset, UINT8 data) { logerror("a2bus: unhandled write %02x to C0n%x\n", data, offset); } + virtual UINT8 read_cnxx(address_space &space, UINT8 offset) { return 0; } // CnXX - /IOSEL + virtual void write_cnxx(address_space &space, UINT8 offset, UINT8 data) { logerror("a2bus: unhandled write %02x to Cn%02x\n", data, offset); } + virtual UINT8 read_c800(address_space &space, UINT16 offset) { return 0; } // C800 - /IOSTB + virtual void write_c800(address_space &space, UINT16 offset, UINT8 data) { logerror("a2bus: unhandled write %02x to %04x\n", data, offset + 0xc800); } + virtual bool take_c800() { return true; } // override and return false if your card doesn't take over the c800 space + virtual UINT8 read_inh_rom(address_space &space, UINT16 offset) { return 0; } + virtual void write_inh_rom(address_space &space, UINT16 offset, UINT8 data) { } + virtual UINT16 inh_start() { return INH_START_INVALID; } + virtual UINT16 inh_end() { return INH_END_INVALID; } + virtual int inh_type() { return INH_NONE; } + + device_a2bus_card_interface *next() const { return m_next; } + + void set_a2bus_device(); + + UINT32 get_slotromspace() { return 0xc000 | (m_slot<<8); } // return Cn00 address for this slot + UINT32 get_slotiospace() { return 0xc080 + (m_slot<<4); } // return C0n0 address for this slot + + void raise_slot_irq() { m_a2bus->set_irq_line(ASSERT_LINE, m_slot); } + void lower_slot_irq() { m_a2bus->set_irq_line(CLEAR_LINE, m_slot); } + void raise_slot_nmi() { m_a2bus->set_nmi_line(ASSERT_LINE, m_slot); } + void lower_slot_nmi() { m_a2bus->set_nmi_line(CLEAR_LINE, m_slot); } + void recalc_slot_inh() { m_a2bus->recalc_inh(m_slot); } + void set_maincpu_halt(int state) { m_a2bus->set_maincpu_halt(state); } + + // pass through the original address space if any for debugger protection + // when debugging e.g. coprocessor cards (Z80 SoftCard etc). + UINT8 slot_dma_read(address_space &space, UINT16 offset) { return m_a2bus->dma_r(space, offset); } + void slot_dma_write(address_space &space, UINT16 offset, UINT8 data) { m_a2bus->dma_w(space, offset, data); } + + // these versions forego that protection for when the DMA isn't coming from a debuggable CPU device + UINT8 slot_dma_read_no_space(UINT16 offset) { return m_a2bus->dma_nospace_r(offset); } + void slot_dma_write_no_space(UINT16 offset, UINT8 data) { m_a2bus->dma_nospace_w(offset, data); } + + // inline configuration + static void static_set_a2bus_tag(device_t &device, const char *tag, const char *slottag); +public: + a2bus_device *m_a2bus; + const char *m_a2bus_tag, *m_a2bus_slottag; + int m_slot; + device_a2bus_card_interface *m_next; +}; + +#endif /* __A2BUS_H__ */ diff --git a/src/devices/bus/a2bus/a2cffa.c b/src/devices/bus/a2bus/a2cffa.c new file mode 100644 index 00000000000..6bde1195ac7 --- /dev/null +++ b/src/devices/bus/a2bus/a2cffa.c @@ -0,0 +1,278 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/********************************************************************* + + a2cffa.c + + Implementation of Rich Dreher's IDE/CompactFlash card + for the Apple II. + + http://www.dreher.net/ + +*********************************************************************/ + +#include "a2cffa.h" +#include "includes/apple2.h" +#include "machine/ataintf.h" +#include "imagedev/harddriv.h" + + +/*************************************************************************** + PARAMETERS +***************************************************************************/ + +#define LOG_A2CFFA 1 + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type A2BUS_CFFA2 = &device_creator; +const device_type A2BUS_CFFA2_6502 = &device_creator; + +#define CFFA2_ROM_REGION "cffa2_rom" +#define CFFA2_ATA_TAG "cffa2_ata" + +MACHINE_CONFIG_FRAGMENT( cffa2 ) + MCFG_ATA_INTERFACE_ADD(CFFA2_ATA_TAG, ata_devices, "hdd", NULL, false) + +// not yet, the core explodes +// MCFG_SOFTWARE_LIST_ADD("hdd_list", "apple2gs_hdd") +MACHINE_CONFIG_END + +ROM_START( cffa2 ) + ROM_REGION(0x1000, CFFA2_ROM_REGION, 0) + ROM_LOAD( "cffa20eec02.bin", 0x000000, 0x001000, CRC(fb3726f8) SHA1(080ff88f19de22328e162954ee2b51ee65f9d5cd) ) +ROM_END + +ROM_START( cffa2_6502 ) + ROM_REGION(0x1000, CFFA2_ROM_REGION, 0) + ROM_LOAD( "cffa20ee02.bin", 0x000000, 0x001000, CRC(3ecafce5) SHA1(d600692ed9626668233a22a48236af639410cb7b) ) +ROM_END + +/*************************************************************************** + FUNCTION PROTOTYPES +***************************************************************************/ + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor a2bus_cffa2000_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( cffa2 ); +} + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *a2bus_cffa2000_device::device_rom_region() const +{ + return ROM_NAME( cffa2 ); +} + +const rom_entry *a2bus_cffa2_6502_device::device_rom_region() const +{ + return ROM_NAME( cffa2_6502 ); +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +a2bus_cffa2000_device::a2bus_cffa2000_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_a2bus_card_interface(mconfig, *this), + m_ata(*this, CFFA2_ATA_TAG) +{ +} + +a2bus_cffa2_device::a2bus_cffa2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + a2bus_cffa2000_device(mconfig, A2BUS_CFFA2, "CFFA2000 Compact Flash (65C02 firmware, www.dreher.net)", tag, owner, clock, "a2cffa2", __FILE__), + device_nvram_interface(mconfig, *this) +{ +} + +a2bus_cffa2_6502_device::a2bus_cffa2_6502_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + a2bus_cffa2000_device(mconfig, A2BUS_CFFA2, "CFFA2000 Compact Flash (6502 firmware, www.dreher.net)", tag, owner, clock, "a2cffa02", __FILE__), + device_nvram_interface(mconfig, *this) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void a2bus_cffa2000_device::device_start() +{ + // set_a2bus_device makes m_slot valid + set_a2bus_device(); + + m_rom = device().machine().root_device().memregion(this->subtag(CFFA2_ROM_REGION).c_str())->base(); + + // patch default setting so slave device is enabled and up to 13 devices on both connectors + m_rom[0x800] = 13; + m_rom[0x801] = 13; + + save_item(NAME(m_lastdata)); + save_item(NAME(m_lastreaddata)); + save_item(NAME(m_writeprotect)); + save_item(NAME(m_eeprom)); + save_item(NAME(m_inwritecycle)); +} + +void a2bus_cffa2000_device::device_reset() +{ + m_writeprotect = true; + m_inwritecycle = false; +} + + +/*------------------------------------------------- + read_c0nx - called for reads from this card's c0nx space +-------------------------------------------------*/ + +UINT8 a2bus_cffa2000_device::read_c0nx(address_space &space, UINT8 offset) +{ + switch (offset) + { + case 0: + return m_lastreaddata>>8; + + case 3: + m_writeprotect = false; + break; + + case 4: + m_writeprotect = true; + break; + + case 8: + // Apple /// driver uses sta $c080,x when writing, which causes spurious reads of c088 + if (!m_inwritecycle) + { + m_lastreaddata = m_ata->read_cs0(space, offset - 8, 0xffff); + } + return m_lastreaddata & 0xff; + + case 9: + case 0xa: + case 0xb: + case 0xc: + case 0xd: + case 0xe: + case 0xf: + return m_ata->read_cs0(space, offset-8, 0xff); + } + + return 0xff; +} + + +/*------------------------------------------------- + write_c0nx - called for writes to this card's c0nx space +-------------------------------------------------*/ + +void a2bus_cffa2000_device::write_c0nx(address_space &space, UINT8 offset, UINT8 data) +{ + m_inwritecycle = false; + + switch (offset) + { + case 0: + m_lastdata &= 0x00ff; + m_lastdata |= data<<8; +// printf("%02x to 0, m_lastdata = %x\n", data, m_lastdata); + m_inwritecycle = true; + break; + + case 3: + m_writeprotect = false; + break; + + case 4: + m_writeprotect = true; + break; + + case 8: + m_lastdata &= 0xff00; + m_lastdata |= data; +// printf("%02x to 8, m_lastdata = %x\n", data, m_lastdata); + m_ata->write_cs0(space, offset-8, m_lastdata, 0xffff); + break; + + case 9: + case 0xa: + case 0xb: + case 0xc: + case 0xd: + case 0xe: + case 0xf: + m_ata->write_cs0(space, offset-8, data, 0xff); + break; + } +} + +/*------------------------------------------------- + read_cnxx - called for reads from this card's cnxx space +-------------------------------------------------*/ + +UINT8 a2bus_cffa2000_device::read_cnxx(address_space &space, UINT8 offset) +{ + int slotimg = m_slot * 0x100; + + // ROM contains a CnXX image for each of slots 1-7 + return m_eeprom[offset+slotimg]; +} + +/*------------------------------------------------- + read_c800 - called for reads from this card's c800 space +-------------------------------------------------*/ + +UINT8 a2bus_cffa2000_device::read_c800(address_space &space, UINT16 offset) +{ + return m_eeprom[offset+0x800]; +} + +void a2bus_cffa2000_device::write_c800(address_space &space, UINT16 offset, UINT8 data) +{ + if (!m_writeprotect) + { +// printf("Write %02x to EEPROM at %x (PC=%x)\n", data, offset, space.device().safe_pc()); + m_eeprom[offset + 0x800] = data; + } +} + +// NVRAM device virtual overrides to provide saving/loading of settings changes +void a2bus_cffa2_device::nvram_default() +{ + memcpy(m_eeprom, m_rom, 0x1000); +} + +void a2bus_cffa2_device::nvram_read(emu_file &file) +{ + file.read(m_eeprom, 0x1000); +} + +void a2bus_cffa2_device::nvram_write(emu_file &file) +{ + file.write(m_eeprom, 0x1000); +} + +void a2bus_cffa2_6502_device::nvram_default() +{ + memcpy(m_eeprom, m_rom, 0x1000); +} + +void a2bus_cffa2_6502_device::nvram_read(emu_file &file) +{ + file.read(m_eeprom, 0x1000); +} + +void a2bus_cffa2_6502_device::nvram_write(emu_file &file) +{ + file.write(m_eeprom, 0x1000); +} diff --git a/src/devices/bus/a2bus/a2cffa.h b/src/devices/bus/a2bus/a2cffa.h new file mode 100644 index 00000000000..a719861efa9 --- /dev/null +++ b/src/devices/bus/a2bus/a2cffa.h @@ -0,0 +1,86 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/********************************************************************* + + a2cffa.h + + Implementation of Rich Dreher's IDE/CompactFlash board for + the Apple II + +*********************************************************************/ + +#ifndef __A2BUS_CFFA2__ +#define __A2BUS_CFFA2__ + +#include "emu.h" +#include "a2bus.h" +#include "machine/ataintf.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class a2bus_cffa2000_device: + public device_t, + public device_a2bus_card_interface +{ +public: + // construction/destruction + a2bus_cffa2000_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual const rom_entry *device_rom_region() const; + +protected: + virtual void device_start(); + virtual void device_reset(); + + // overrides of standard a2bus slot functions + virtual UINT8 read_c0nx(address_space &space, UINT8 offset); + virtual void write_c0nx(address_space &space, UINT8 offset, UINT8 data); + virtual UINT8 read_cnxx(address_space &space, UINT8 offset); + virtual UINT8 read_c800(address_space &space, UINT16 offset); + virtual void write_c800(address_space &space, UINT16 offset, UINT8 data); + + required_device m_ata; + + UINT8 *m_rom; + UINT8 m_eeprom[0x1000]; + +private: + UINT16 m_lastdata, m_lastreaddata; + bool m_writeprotect; + bool m_inwritecycle; +}; + +class a2bus_cffa2_device : public a2bus_cffa2000_device, public device_nvram_interface +{ +public: + a2bus_cffa2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // device_config_nvram_interface overrides + virtual void nvram_default(); + virtual void nvram_read(emu_file &file); + virtual void nvram_write(emu_file &file); +}; + +class a2bus_cffa2_6502_device : public a2bus_cffa2000_device, public device_nvram_interface +{ +public: + a2bus_cffa2_6502_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual const rom_entry *device_rom_region() const; + +protected: + // device_config_nvram_interface overrides + virtual void nvram_default(); + virtual void nvram_read(emu_file &file); + virtual void nvram_write(emu_file &file); +}; + +// device type definition +extern const device_type A2BUS_CFFA2; +extern const device_type A2BUS_CFFA2_6502; + +#endif /* __A2BUS_CFFA2__ */ diff --git a/src/devices/bus/a2bus/a2corvus.c b/src/devices/bus/a2bus/a2corvus.c new file mode 100644 index 00000000000..d3de7fdfee0 --- /dev/null +++ b/src/devices/bus/a2bus/a2corvus.c @@ -0,0 +1,187 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/********************************************************************* + + a2corvus.c + + Implementation of the Corvus flat-cable hard disk interface + for the Apple II. + + This same card was used in the Corvus Concept. + + C0n0 = drive read/write + C0n1 = read status (busy in bit 7, data direction in bit 6) + + Reads and writes to C0n2+ happen; the contents of the reads are thrown away + immediately by all the code I've examined, and sending the writes to the + drive's write port makes it not work so they're intended to be ignored too. + + 5 MB: -chs 144,4,20 -ss 512 + 10 MB: -chs 358,3,20 -ss 512 + 20 MB: -chs 388,5,20 -ss 512 + + To set up a disk from scratch on the Apple II: + 1) Create a disk of your desired capacity using CHDMAN -c none and the parameters + listed above for each of the possible sizes. + 2) Boot apple2p with the corvus in slot 2 and a diskii(ng) in slot 6 with the + "Corvus Hard Drive - Diagnostics.dsk" mounted. + 3) Press F to format. Accept all the default options from now on; + there is no "format switch" to worry about with the current emulation. + 4) Quit MESS. Restart with the corvus in slot 6 and a diskii(ng) in slot 7 + with the "Corvus Hard Drive - Utilities Disk 1.dsk" mounted. + 5) When you get the BASIC prompt, "RUN BSYSGEN" + 6) Choose drive 1 and press Y at "OK TO BSYSGEN?" + 7) When the format completes, type "RUN APPLESOFT BOOT PREP" and press Enter. + 8) Once it finishes, quit MESS. Remove the diskii(ng) from slot 7 and + the system will boot into DOS 3.3 from the Corvus HD. + + TODO: but there are no Corvus drivers present after that, only + Disk II? + +*********************************************************************/ + +#include "a2corvus.h" +#include "includes/apple2.h" +#include "imagedev/harddriv.h" + +/*************************************************************************** + PARAMETERS +***************************************************************************/ + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type A2BUS_CORVUS = &device_creator; + +#define CORVUS_ROM_REGION "corvus_rom" +#define CORVUS_HD_TAG "corvushd" + +static MACHINE_CONFIG_FRAGMENT(corvus) + MCFG_DEVICE_ADD(CORVUS_HD_TAG, CORVUS_HDC, 0) + MCFG_HARDDISK_ADD("harddisk1") + MCFG_HARDDISK_INTERFACE("corvus_hdd") + MCFG_HARDDISK_ADD("harddisk2") + MCFG_HARDDISK_INTERFACE("corvus_hdd") + MCFG_HARDDISK_ADD("harddisk3") + MCFG_HARDDISK_INTERFACE("corvus_hdd") + MCFG_HARDDISK_ADD("harddisk4") + MCFG_HARDDISK_INTERFACE("corvus_hdd") +MACHINE_CONFIG_END + +ROM_START( corvus ) + ROM_REGION(0x800, CORVUS_ROM_REGION, 0) + ROM_LOAD( "a4.7.u10", 0x0000, 0x0800, CRC(1cf6e32a) SHA1(dbd6efeb3b54c0523b8b4eda8b3d737413f6a91a) ) +ROM_END + +/*************************************************************************** + FUNCTION PROTOTYPES +***************************************************************************/ + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor a2bus_corvus_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( corvus ); +} + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *a2bus_corvus_device::device_rom_region() const +{ + return ROM_NAME( corvus ); +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +a2bus_corvus_device::a2bus_corvus_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_a2bus_card_interface(mconfig, *this), + m_corvushd(*this, CORVUS_HD_TAG) +{ +} + +a2bus_corvus_device::a2bus_corvus_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, A2BUS_CORVUS, "Corvus Flat Cable interface", tag, owner, clock, "a2corvus", __FILE__), + device_a2bus_card_interface(mconfig, *this), + m_corvushd(*this, CORVUS_HD_TAG) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void a2bus_corvus_device::device_start() +{ + // set_a2bus_device makes m_slot valid + set_a2bus_device(); + + m_rom = device().machine().root_device().memregion(this->subtag(CORVUS_ROM_REGION).c_str())->base(); +} + +void a2bus_corvus_device::device_reset() +{ +} + + +/*------------------------------------------------- + read_c0nx - called for reads from this card's c0nx space +-------------------------------------------------*/ + +UINT8 a2bus_corvus_device::read_c0nx(address_space &space, UINT8 offset) +{ + switch (offset) + { + case 0: + return m_corvushd->read(space, 0); + + case 1: + return m_corvushd->status_r(space, 0); + + default: + logerror("Corvus: read unhandled c0n%x (PC=%x)\n", offset, space.device().safe_pc()); + break; + } + + return 0xff; +} + + +/*------------------------------------------------- + write_c0nx - called for writes to this card's c0nx space +-------------------------------------------------*/ + +void a2bus_corvus_device::write_c0nx(address_space &space, UINT8 offset, UINT8 data) +{ + if (offset == 0) + { + m_corvushd->write(space, 0, data); + } +} + +/*------------------------------------------------- + read_cnxx - called for reads from this card's cnxx space +-------------------------------------------------*/ + +UINT8 a2bus_corvus_device::read_cnxx(address_space &space, UINT8 offset) +{ + // one slot image at the end of the ROM, it appears + return m_rom[offset+0x700]; +} + +/*------------------------------------------------- + read_c800 - called for reads from this card's c800 space +-------------------------------------------------*/ + +UINT8 a2bus_corvus_device::read_c800(address_space &space, UINT16 offset) +{ + return m_rom[offset & 0x7ff]; +} diff --git a/src/devices/bus/a2bus/a2corvus.h b/src/devices/bus/a2bus/a2corvus.h new file mode 100644 index 00000000000..4c9ade900ab --- /dev/null +++ b/src/devices/bus/a2bus/a2corvus.h @@ -0,0 +1,55 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/********************************************************************* + + a2corvus.h + + Implementation of the Corvus flat-cable hard disk interface + for the Apple II. + +*********************************************************************/ + +#ifndef __A2BUS_CORVUS__ +#define __A2BUS_CORVUS__ + +#include "emu.h" +#include "a2bus.h" +#include "machine/corvushd.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class a2bus_corvus_device: + public device_t, + public device_a2bus_card_interface +{ +public: + // construction/destruction + a2bus_corvus_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + a2bus_corvus_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual const rom_entry *device_rom_region() const; + + required_device m_corvushd; + +protected: + virtual void device_start(); + virtual void device_reset(); + + // overrides of standard a2bus slot functions + virtual UINT8 read_c0nx(address_space &space, UINT8 offset); + virtual void write_c0nx(address_space &space, UINT8 offset, UINT8 data); + virtual UINT8 read_cnxx(address_space &space, UINT8 offset); + virtual UINT8 read_c800(address_space &space, UINT16 offset); + +private: + UINT8 *m_rom; +}; + +// device type definition +extern const device_type A2BUS_CORVUS; + +#endif /* __A2BUS_CORVUS__ */ diff --git a/src/devices/bus/a2bus/a2diskii.c b/src/devices/bus/a2bus/a2diskii.c new file mode 100644 index 00000000000..ad8a860a69f --- /dev/null +++ b/src/devices/bus/a2bus/a2diskii.c @@ -0,0 +1,153 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/********************************************************************* + + a2diskii.c + + Implementation of the Apple II Disk II controller card + +*********************************************************************/ + +#include "emu.h" +#include "includes/apple2.h" +#include "imagedev/flopdrv.h" +#include "formats/ap2_dsk.h" +#include "machine/appldriv.h" +#include "a2diskii.h" + + +/*************************************************************************** + PARAMETERS +***************************************************************************/ + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type A2BUS_DISKII = &device_creator; +const device_type A2BUS_IWM_FDC = &device_creator; + +#define DISKII_ROM_REGION "diskii_rom" +#define FDC_TAG "diskii_fdc" + +const applefdc_interface fdc_interface = +{ + apple525_set_lines, /* set_lines */ + apple525_set_enable_lines, /* set_enable_lines */ + + apple525_read_data, /* read_data */ + apple525_write_data, /* write_data */ + apple525_read_status /* read_status */ +}; + +static const floppy_interface floppy_interface = +{ + FLOPPY_STANDARD_5_25_DSHD, + LEGACY_FLOPPY_OPTIONS_NAME(apple2), + "floppy_5_25" +}; + +MACHINE_CONFIG_FRAGMENT( diskii ) + MCFG_APPLEFDC_ADD(FDC_TAG, fdc_interface) + MCFG_LEGACY_FLOPPY_APPLE_2_DRIVES_ADD(floppy_interface,15,16) +MACHINE_CONFIG_END + +MACHINE_CONFIG_FRAGMENT( iwmflop ) + MCFG_IWM_ADD(FDC_TAG, fdc_interface) + MCFG_LEGACY_FLOPPY_APPLE_2_DRIVES_ADD(floppy_interface,15,16) +MACHINE_CONFIG_END + +ROM_START( diskii ) + ROM_REGION(0x100, DISKII_ROM_REGION, 0) + ROM_LOAD( "341-0027-a.p5", 0x000000, 0x000100, CRC(ce7144f6) SHA1(d4181c9f046aafc3fb326b381baac809d9e38d16) ) +ROM_END + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor a2bus_floppy_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( diskii ); +} + +machine_config_constructor a2bus_iwmflop_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( iwmflop ); +} + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *a2bus_floppy_device::device_rom_region() const +{ + return ROM_NAME( diskii ); +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +a2bus_floppy_device::a2bus_floppy_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_a2bus_card_interface(mconfig, *this), + m_fdc(*this, FDC_TAG) +{ +} + +a2bus_diskii_device::a2bus_diskii_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + a2bus_floppy_device(mconfig, A2BUS_DISKII, "Apple Disk II controller", tag, owner, clock, "a2diskii", __FILE__) +{ +} + +a2bus_iwmflop_device::a2bus_iwmflop_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + a2bus_floppy_device(mconfig, A2BUS_IWM_FDC, "Apple IWM floppy card", tag, owner, clock, "a2iwm_flop", __FILE__) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void a2bus_floppy_device::device_start() +{ + // set_a2bus_device makes m_slot valid + set_a2bus_device(); + + m_rom = device().machine().root_device().memregion(this->subtag(DISKII_ROM_REGION).c_str())->base(); +} + +void a2bus_floppy_device::device_reset() +{ +} + + +/*------------------------------------------------- + read_c0nx - called for reads from this card's c0nx space +-------------------------------------------------*/ + +UINT8 a2bus_floppy_device::read_c0nx(address_space &space, UINT8 offset) +{ + return m_fdc->read(offset); +} + + +/*------------------------------------------------- + write_c0nx - called for writes to this card's c0nx space +-------------------------------------------------*/ + +void a2bus_floppy_device::write_c0nx(address_space &space, UINT8 offset, UINT8 data) +{ + m_fdc->write(offset, data); +} + +/*------------------------------------------------- + read_cnxx - called for reads from this card's c0nx space +-------------------------------------------------*/ + +UINT8 a2bus_floppy_device::read_cnxx(address_space &space, UINT8 offset) +{ + return m_rom[offset]; +} diff --git a/src/devices/bus/a2bus/a2diskii.h b/src/devices/bus/a2bus/a2diskii.h new file mode 100644 index 00000000000..15e47316fe7 --- /dev/null +++ b/src/devices/bus/a2bus/a2diskii.h @@ -0,0 +1,67 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/********************************************************************* + + a2diskii.h + + Apple II Disk II Controller Card + +*********************************************************************/ + +#ifndef __A2BUS_DISKII__ +#define __A2BUS_DISKII__ + +#include "emu.h" +#include "a2bus.h" +#include "machine/applefdc.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class a2bus_floppy_device: + public device_t, + public device_a2bus_card_interface +{ +public: + // construction/destruction + a2bus_floppy_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual const rom_entry *device_rom_region() const; + +protected: + virtual void device_start(); + virtual void device_reset(); + + // overrides of standard a2bus slot functions + virtual UINT8 read_c0nx(address_space &space, UINT8 offset); + virtual void write_c0nx(address_space &space, UINT8 offset, UINT8 data); + virtual UINT8 read_cnxx(address_space &space, UINT8 offset); + + required_device m_fdc; + +private: + UINT8 *m_rom; +}; + +class a2bus_diskii_device: public a2bus_floppy_device +{ +public: + a2bus_diskii_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class a2bus_iwmflop_device: public a2bus_floppy_device +{ +public: + a2bus_iwmflop_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual machine_config_constructor device_mconfig_additions() const; +}; + +// device type definition +extern const device_type A2BUS_DISKII; +extern const device_type A2BUS_IWM_FDC; + +#endif /* __A2BUS_DISKII__ */ diff --git a/src/devices/bus/a2bus/a2diskiing.c b/src/devices/bus/a2bus/a2diskiing.c new file mode 100644 index 00000000000..de0f84c26db --- /dev/null +++ b/src/devices/bus/a2bus/a2diskiing.c @@ -0,0 +1,123 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/********************************************************************* + + a2diskii.c + + Implementation of the Apple II Disk II controller card + +*********************************************************************/ + +#include "emu.h" +#include "imagedev/floppy.h" +#include "formats/ap2_dsk.h" +#include "a2diskiing.h" + +/*************************************************************************** + PARAMETERS +***************************************************************************/ + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type A2BUS_DISKIING = &device_creator; + +#define WOZFDC_TAG "wozfdc" +#define DISKII_ROM_REGION "diskii_rom" + +static SLOT_INTERFACE_START( a2_floppies ) + SLOT_INTERFACE( "525", FLOPPY_525_SD ) +SLOT_INTERFACE_END + +static MACHINE_CONFIG_FRAGMENT( diskiing ) + MCFG_DEVICE_ADD(WOZFDC_TAG, DISKII_FDC, 1021800*2) + MCFG_FLOPPY_DRIVE_ADD("0", a2_floppies, "525", a2bus_diskiing_device::floppy_formats) + MCFG_FLOPPY_DRIVE_ADD("1", a2_floppies, "525", a2bus_diskiing_device::floppy_formats) +MACHINE_CONFIG_END + +ROM_START( diskiing ) + ROM_REGION(0x100, DISKII_ROM_REGION, 0) + ROM_LOAD( "341-0027-a.p5", 0x0000, 0x0100, CRC(ce7144f6) SHA1(d4181c9f046aafc3fb326b381baac809d9e38d16) ) /* 341-0027-a: 16-sector disk drive (older version), PROM P5 */ +ROM_END + +FLOPPY_FORMATS_MEMBER( a2bus_diskiing_device::floppy_formats ) + FLOPPY_A216S_FORMAT, FLOPPY_RWTS18_FORMAT, FLOPPY_EDD_FORMAT +FLOPPY_FORMATS_END + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor a2bus_diskiing_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( diskiing ); +} + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *a2bus_diskiing_device::device_rom_region() const +{ + return ROM_NAME( diskiing ); +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +a2bus_diskiing_device::a2bus_diskiing_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, A2BUS_DISKIING, "Apple Disk II NG controller", tag, owner, clock, "a2diskiing", __FILE__), + device_a2bus_card_interface(mconfig, *this), + m_wozfdc(*this, WOZFDC_TAG), + floppy0(*this, "0"), + floppy1(*this, "1") +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void a2bus_diskiing_device::device_start() +{ + // set_a2bus_device makes m_slot valid + set_a2bus_device(); + + m_rom = device().machine().root_device().memregion(this->subtag(DISKII_ROM_REGION).c_str())->base(); +} + +void a2bus_diskiing_device::device_reset() +{ + m_wozfdc->set_floppies(floppy0, floppy1); +} + +/*------------------------------------------------- + read_c0nx - called for reads from this card's c0nx space +-------------------------------------------------*/ + +UINT8 a2bus_diskiing_device::read_c0nx(address_space &space, UINT8 offset) +{ + return m_wozfdc->read(space, offset); +} + + +/*------------------------------------------------- + write_c0nx - called for writes to this card's c0nx space +-------------------------------------------------*/ + +void a2bus_diskiing_device::write_c0nx(address_space &space, UINT8 offset, UINT8 data) +{ + m_wozfdc->write(space, offset, data); +} + +/*------------------------------------------------- + read_cnxx - called for reads from this card's cnxx space +-------------------------------------------------*/ + +UINT8 a2bus_diskiing_device::read_cnxx(address_space &space, UINT8 offset) +{ + return m_rom[offset]; +} diff --git a/src/devices/bus/a2bus/a2diskiing.h b/src/devices/bus/a2bus/a2diskiing.h new file mode 100644 index 00000000000..462731449bb --- /dev/null +++ b/src/devices/bus/a2bus/a2diskiing.h @@ -0,0 +1,59 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/********************************************************************* + + a2diskiing.h + + Apple II Disk II Controller Card, new floppy + +*********************************************************************/ + +#ifndef __A2BUS_DISKIING__ +#define __A2BUS_DISKIING__ + +#include "emu.h" +#include "a2bus.h" +#include "imagedev/floppy.h" +#include "formats/flopimg.h" +#include "machine/wozfdc.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + + +class a2bus_diskiing_device: + public device_t, + public device_a2bus_card_interface +{ +public: + // construction/destruction + a2bus_diskiing_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual const rom_entry *device_rom_region() const; + + DECLARE_FLOPPY_FORMATS( floppy_formats ); + +protected: + virtual void device_start(); + virtual void device_reset(); + + // overrides of standard a2bus slot functions + virtual UINT8 read_c0nx(address_space &space, UINT8 offset); + virtual void write_c0nx(address_space &space, UINT8 offset, UINT8 data); + virtual UINT8 read_cnxx(address_space &space, UINT8 offset); + +private: + required_device m_wozfdc; + required_device floppy0; + required_device floppy1; + + const UINT8 *m_rom; +}; + +// device type definition +extern const device_type A2BUS_DISKIING; + +#endif /* __A2BUS_DISKIING__ */ diff --git a/src/devices/bus/a2bus/a2dx1.c b/src/devices/bus/a2bus/a2dx1.c new file mode 100644 index 00000000000..e3b4fcc3fc5 --- /dev/null +++ b/src/devices/bus/a2bus/a2dx1.c @@ -0,0 +1,119 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/********************************************************************* + + a2dx1.c + + Implementation of the Decillionix DX-1 sampler card + +*********************************************************************/ + +#include "a2dx1.h" +#include "includes/apple2.h" +#include "sound/dac.h" + +/*************************************************************************** + PARAMETERS +***************************************************************************/ + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type A2BUS_DX1 = &device_creator; + +#define DAC_TAG "dac" + +MACHINE_CONFIG_FRAGMENT( a2dx1 ) + MCFG_SPEAKER_STANDARD_MONO("dx1spkr") + MCFG_SOUND_ADD(DAC_TAG, DAC, 0) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "dx1spkr", 1.00) +MACHINE_CONFIG_END + +/*************************************************************************** + FUNCTION PROTOTYPES +***************************************************************************/ + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor a2bus_dx1_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( a2dx1 ); +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +a2bus_dx1_device::a2bus_dx1_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_a2bus_card_interface(mconfig, *this), + m_dac(*this, DAC_TAG) +{ +} + +a2bus_dx1_device::a2bus_dx1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, A2BUS_DX1, "Decillonix DX-1", tag, owner, clock, "a2dx1", __FILE__), + device_a2bus_card_interface(mconfig, *this), + m_dac(*this, DAC_TAG) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void a2bus_dx1_device::device_start() +{ + // set_a2bus_device makes m_slot valid + set_a2bus_device(); + + save_item(NAME(m_volume)); + save_item(NAME(m_lastdac)); +} + +void a2bus_dx1_device::device_reset() +{ + m_volume = m_lastdac = 0; +} + +UINT8 a2bus_dx1_device::read_c0nx(address_space &space, UINT8 offset) +{ + switch (offset) + { + case 1: // ADC input + return 0; + + case 3: // busy flag + return 0x80; // indicate not busy + + case 7: // 1-bit ADC input (bit 7 of c0n1, probably) + return 0; + } + + return 0xff; +} + +void a2bus_dx1_device::write_c0nx(address_space &space, UINT8 offset, UINT8 data) +{ + switch (offset) + { + case 5: // volume + m_volume = data; + m_dac->write_unsigned16(data*m_lastdac); + break; + + case 6: + m_lastdac = data; + m_dac->write_unsigned16(data*m_volume); + break; + } +} + +bool a2bus_dx1_device::take_c800() +{ + return false; +} diff --git a/src/devices/bus/a2bus/a2dx1.h b/src/devices/bus/a2bus/a2dx1.h new file mode 100644 index 00000000000..99b9d98193a --- /dev/null +++ b/src/devices/bus/a2bus/a2dx1.h @@ -0,0 +1,52 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/********************************************************************* + + a2dx1.h + + Implementation of the Decillionix DX-1 sampler card + +*********************************************************************/ + +#ifndef __A2BUS_DX1__ +#define __A2BUS_DX1__ + +#include "emu.h" +#include "a2bus.h" +#include "sound/dac.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class a2bus_dx1_device: + public device_t, + public device_a2bus_card_interface +{ +public: + // construction/destruction + a2bus_dx1_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + a2bus_dx1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + + required_device m_dac; + +protected: + virtual void device_start(); + virtual void device_reset(); + + // overrides of standard a2bus slot functions + virtual UINT8 read_c0nx(address_space &space, UINT8 offset); + virtual void write_c0nx(address_space &space, UINT8 offset, UINT8 data); + virtual bool take_c800(); + +private: + UINT8 m_volume, m_lastdac; +}; + +// device type definition +extern const device_type A2BUS_DX1; + +#endif /* __A2BUS_DX1__ */ diff --git a/src/devices/bus/a2bus/a2eauxslot.c b/src/devices/bus/a2bus/a2eauxslot.c new file mode 100644 index 00000000000..3f6d99ead9c --- /dev/null +++ b/src/devices/bus/a2bus/a2eauxslot.c @@ -0,0 +1,180 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/*************************************************************************** + + a2eauxslot.c - Apple IIe auxiliary slot and card emulation + + by R. Belmont + +***************************************************************************/ + +#include "emu.h" +#include "emuopts.h" +#include "a2eauxslot.h" + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type A2EAUXSLOT_SLOT = &device_creator; + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// a2eauxslot_slot_device - constructor +//------------------------------------------------- +a2eauxslot_slot_device::a2eauxslot_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, A2EAUXSLOT_SLOT, "Apple IIe AUX Slot", tag, owner, clock, "a2eauxslot_slot", __FILE__), + device_slot_interface(mconfig, *this) +{ +} + +a2eauxslot_slot_device::a2eauxslot_slot_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_slot_interface(mconfig, *this) +{ +} + +void a2eauxslot_slot_device::static_set_a2eauxslot_slot(device_t &device, const char *tag, const char *slottag) +{ + a2eauxslot_slot_device &a2eauxslot_card = dynamic_cast(device); + a2eauxslot_card.m_a2eauxslot_tag = tag; + a2eauxslot_card.m_a2eauxslot_slottag = slottag; +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void a2eauxslot_slot_device::device_start() +{ + device_a2eauxslot_card_interface *dev = dynamic_cast(get_card_device()); + + if (dev) device_a2eauxslot_card_interface::static_set_a2eauxslot_tag(*dev, m_a2eauxslot_tag, m_a2eauxslot_slottag); +} + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type A2EAUXSLOT = &device_creator; + +void a2eauxslot_device::static_set_cputag(device_t &device, const char *tag) +{ + a2eauxslot_device &a2eauxslot = downcast(device); + a2eauxslot.m_cputag = tag; +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// a2eauxslot_device - constructor +//------------------------------------------------- + +a2eauxslot_device::a2eauxslot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, A2EAUXSLOT, "Apple IIe AUX Bus", tag, owner, clock, "a2eauxslot", __FILE__), + m_out_irq_cb(*this), + m_out_nmi_cb(*this) +{ +} + +a2eauxslot_device::a2eauxslot_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + m_out_irq_cb(*this), + m_out_nmi_cb(*this) +{ +} +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void a2eauxslot_device::device_start() +{ + m_maincpu = machine().device(m_cputag); + + // resolve callbacks + m_out_irq_cb.resolve_safe(); + m_out_nmi_cb.resolve_safe(); + + // clear slot + m_device = NULL; +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void a2eauxslot_device::device_reset() +{ +} + +device_a2eauxslot_card_interface *a2eauxslot_device::get_a2eauxslot_card() +{ + return m_device; +} + +void a2eauxslot_device::add_a2eauxslot_card(device_a2eauxslot_card_interface *card) +{ + m_device = card; +} + +void a2eauxslot_device::set_irq_line(int state) +{ + m_out_irq_cb(state); +} + +void a2eauxslot_device::set_nmi_line(int state) +{ + m_out_nmi_cb(state); +} + +// interrupt request from a2eauxslot card +WRITE_LINE_MEMBER( a2eauxslot_device::irq_w ) { m_out_irq_cb(state); } +WRITE_LINE_MEMBER( a2eauxslot_device::nmi_w ) { m_out_nmi_cb(state); } + +//************************************************************************** +// DEVICE CONFIG A2EAUXSLOT CARD INTERFACE +//************************************************************************** + + +//************************************************************************** +// DEVICE A2EAUXSLOT CARD INTERFACE +//************************************************************************** + +//------------------------------------------------- +// device_a2eauxslot_card_interface - constructor +//------------------------------------------------- + +device_a2eauxslot_card_interface::device_a2eauxslot_card_interface(const machine_config &mconfig, device_t &device) + : device_slot_card_interface(mconfig, device), + m_a2eauxslot(NULL), + m_a2eauxslot_tag(NULL) +{ +} + + +//------------------------------------------------- +// ~device_a2eauxslot_card_interface - destructor +//------------------------------------------------- + +device_a2eauxslot_card_interface::~device_a2eauxslot_card_interface() +{ +} + +void device_a2eauxslot_card_interface::static_set_a2eauxslot_tag(device_t &device, const char *tag, const char *slottag) +{ + device_a2eauxslot_card_interface &a2eauxslot_card = dynamic_cast(device); + a2eauxslot_card.m_a2eauxslot_tag = tag; + a2eauxslot_card.m_a2eauxslot_slottag = slottag; +} + +void device_a2eauxslot_card_interface::set_a2eauxslot_device() +{ + m_a2eauxslot = dynamic_cast(device().machine().device(m_a2eauxslot_tag)); + m_a2eauxslot->add_a2eauxslot_card(this); +} diff --git a/src/devices/bus/a2bus/a2eauxslot.h b/src/devices/bus/a2bus/a2eauxslot.h new file mode 100644 index 00000000000..47babc64bab --- /dev/null +++ b/src/devices/bus/a2bus/a2eauxslot.h @@ -0,0 +1,146 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/*************************************************************************** + + a2eauxslot.h - Apple IIe auxiliary slot and card emulation + + by R. Belmont + +***************************************************************************/ + +#pragma once + +#ifndef __A2EAUXSLOT_H__ +#define __A2EAUXSLOT_H__ + +#include "emu.h" +#include "a2bus.h" + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_A2EAUXSLOT_CPU(_cputag) \ + a2eauxslot_device::static_set_cputag(*device, _cputag); + +#define MCFG_A2EAUXSLOT_OUT_IRQ_CB(_devcb) \ + devcb = &a2eauxslot_device::set_out_irq_callback(*device, DEVCB_##_devcb); + +#define MCFG_A2EAUXSLOT_OUT_NMI_CB(_devcb) \ + devcb = &a2eauxslot_device::set_out_nmi_callback(*device, DEVCB_##_devcb); + +#define MCFG_A2EAUXSLOT_SLOT_ADD(_nbtag, _tag, _slot_intf, _def_slot) \ + MCFG_DEVICE_ADD(_tag, A2EAUXSLOT_SLOT, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) \ + a2eauxslot_slot_device::static_set_a2eauxslot_slot(*device, _nbtag, _tag); +#define MCFG_A2EAUXSLOT_SLOT_REMOVE(_tag) \ + MCFG_DEVICE_REMOVE(_tag) + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class a2eauxslot_device; + +class a2eauxslot_slot_device : public device_t, + public device_slot_interface +{ +public: + // construction/destruction + a2eauxslot_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + a2eauxslot_slot_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + // device-level overrides + virtual void device_start(); + + // inline configuration + static void static_set_a2eauxslot_slot(device_t &device, const char *tag, const char *slottag); +protected: + // configuration + const char *m_a2eauxslot_tag, *m_a2eauxslot_slottag; +}; + +// device type definition +extern const device_type A2EAUXSLOT_SLOT; + + +class device_a2eauxslot_card_interface; + +// ======================> a2eauxslot_device +class a2eauxslot_device : public device_t +{ +public: + // construction/destruction + a2eauxslot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + a2eauxslot_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + // inline configuration + static void static_set_cputag(device_t &device, const char *tag); + template static devcb_base &set_out_irq_callback(device_t &device, _Object object) { return downcast(device).m_out_irq_cb.set_callback(object); } + template static devcb_base &set_out_nmi_callback(device_t &device, _Object object) { return downcast(device).m_out_nmi_cb.set_callback(object); } + + void add_a2eauxslot_card(device_a2eauxslot_card_interface *card); + device_a2eauxslot_card_interface *get_a2eauxslot_card(); + + void set_irq_line(int state); + void set_nmi_line(int state); + + DECLARE_WRITE_LINE_MEMBER( irq_w ); + DECLARE_WRITE_LINE_MEMBER( nmi_w ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // internal state + cpu_device *m_maincpu; + + devcb_write_line m_out_irq_cb; + devcb_write_line m_out_nmi_cb; + + device_a2eauxslot_card_interface *m_device; + const char *m_cputag; +}; + + +// device type definition +extern const device_type A2EAUXSLOT; + +// ======================> device_a2eauxslot_card_interface + +// class representing interface-specific live a2eauxslot card +class device_a2eauxslot_card_interface : public device_slot_card_interface +{ + friend class a2eauxslot_device; +public: + // construction/destruction + device_a2eauxslot_card_interface(const machine_config &mconfig, device_t &device); + virtual ~device_a2eauxslot_card_interface(); + + virtual UINT8 read_auxram(UINT16 offset) { printf("a2eauxslot: unhandled auxram read @ %04x\n", offset); return 0xff; } + virtual void write_auxram(UINT16 offset, UINT8 data) { printf("a2eauxslot: unhandled auxram write %02x @ %04x\n", data, offset); } + virtual void write_c07x(address_space &space, UINT8 offset, UINT8 data) {} + virtual UINT8 *get_vram_ptr() = 0; + virtual UINT8 *get_auxbank_ptr() = 0; + virtual bool allow_dhr() { return true; } + + device_a2eauxslot_card_interface *next() const { return m_next; } + + void set_a2eauxslot_device(); + + void raise_slot_irq() { m_a2eauxslot->set_irq_line(ASSERT_LINE); } + void lower_slot_irq() { m_a2eauxslot->set_irq_line(CLEAR_LINE); } + void raise_slot_nmi() { m_a2eauxslot->set_nmi_line(ASSERT_LINE); } + void lower_slot_nmi() { m_a2eauxslot->set_nmi_line(CLEAR_LINE); } + + // inline configuration + static void static_set_a2eauxslot_tag(device_t &device, const char *tag, const char *slottag); +public: + a2eauxslot_device *m_a2eauxslot; + const char *m_a2eauxslot_tag, *m_a2eauxslot_slottag; + int m_slot; + device_a2eauxslot_card_interface *m_next; +}; + +#endif /* __A2EAUXSLOT_H__ */ diff --git a/src/devices/bus/a2bus/a2echoii.c b/src/devices/bus/a2bus/a2echoii.c new file mode 100644 index 00000000000..e6be96b5d85 --- /dev/null +++ b/src/devices/bus/a2bus/a2echoii.c @@ -0,0 +1,103 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/********************************************************************* + + a2echoii.c + + Implementation of the Street Electronics Echo II speech card + +*********************************************************************/ + +#include "a2echoii.h" +#include "includes/apple2.h" +#include "sound/tms5220.h" + +/*************************************************************************** + PARAMETERS +***************************************************************************/ + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type A2BUS_ECHOII = &device_creator; + +#define TMS_TAG "tms5220" + +MACHINE_CONFIG_FRAGMENT( a2echoii ) + MCFG_SPEAKER_STANDARD_MONO("echoii") + MCFG_SOUND_ADD(TMS_TAG, TMS5220, 640000) // Note the Echo II card has a "FREQ" potentiometer which can be used to adjust the tms5220's clock frequency; 640khz is the '8khz' value according to the tms5220 datasheet + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "echoii", 1.0) +MACHINE_CONFIG_END + +/*************************************************************************** + FUNCTION PROTOTYPES +***************************************************************************/ + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor a2bus_echoii_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( a2echoii ); +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +a2bus_echoii_device::a2bus_echoii_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_a2bus_card_interface(mconfig, *this), + m_tms(*this, TMS_TAG) +{ +} + +a2bus_echoii_device::a2bus_echoii_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, A2BUS_ECHOII, "Street Electronics Echo II", tag, owner, clock, "a2echoii", __FILE__), + device_a2bus_card_interface(mconfig, *this), + m_tms(*this, TMS_TAG) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void a2bus_echoii_device::device_start() +{ + // set_a2bus_device makes m_slot valid + set_a2bus_device(); +} + +void a2bus_echoii_device::device_reset() +{ +} + +UINT8 a2bus_echoii_device::read_c0nx(address_space &space, UINT8 offset) +{ + switch (offset) + { + case 0: + return 0x1f | m_tms->status_r(space, 0); + } + + return 0; +} + +void a2bus_echoii_device::write_c0nx(address_space &space, UINT8 offset, UINT8 data) +{ + switch (offset) + { + case 0: + m_tms->data_w(space, offset, data); + break; + } +} + +bool a2bus_echoii_device::take_c800() +{ + return false; +} diff --git a/src/devices/bus/a2bus/a2echoii.h b/src/devices/bus/a2bus/a2echoii.h new file mode 100644 index 00000000000..9413ce3a900 --- /dev/null +++ b/src/devices/bus/a2bus/a2echoii.h @@ -0,0 +1,49 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/********************************************************************* + + a2echoii.h + + Implementation of the Street Electronics Echo II speech card + +*********************************************************************/ + +#ifndef __A2BUS_ECHOII__ +#define __A2BUS_ECHOII__ + +#include "emu.h" +#include "a2bus.h" +#include "sound/tms5220.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class a2bus_echoii_device: + public device_t, + public device_a2bus_card_interface +{ +public: + // construction/destruction + a2bus_echoii_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + a2bus_echoii_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + + required_device m_tms; + +protected: + virtual void device_start(); + virtual void device_reset(); + + // overrides of standard a2bus slot functions + virtual UINT8 read_c0nx(address_space &space, UINT8 offset); + virtual void write_c0nx(address_space &space, UINT8 offset, UINT8 data); + virtual bool take_c800(); +}; + +// device type definition +extern const device_type A2BUS_ECHOII; + +#endif /* __A2BUS_ECHOII__ */ diff --git a/src/devices/bus/a2bus/a2eext80col.c b/src/devices/bus/a2bus/a2eext80col.c new file mode 100644 index 00000000000..c3e9af48cac --- /dev/null +++ b/src/devices/bus/a2bus/a2eext80col.c @@ -0,0 +1,75 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/********************************************************************* + + a2eext80col.c + + Apple IIe Extended 80 Column Card (64K of RAM, double-hi-res) + +*********************************************************************/ + +#include "emu.h" +#include "includes/apple2.h" +#include "a2eext80col.h" + + +/*************************************************************************** + PARAMETERS +***************************************************************************/ + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type A2EAUX_EXT80COL = &device_creator; + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +a2eaux_ext80col_device::a2eaux_ext80col_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, A2EAUX_EXT80COL, "Apple IIe Extended 80-Column Card", tag, owner, clock, "a2eext80", __FILE__), + device_a2eauxslot_card_interface(mconfig, *this) +{ +} + +a2eaux_ext80col_device::a2eaux_ext80col_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_a2eauxslot_card_interface(mconfig, *this) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void a2eaux_ext80col_device::device_start() +{ + set_a2eauxslot_device(); + memset(m_ram, 0, sizeof(m_ram)); + save_item(NAME(m_ram)); +} + +void a2eaux_ext80col_device::device_reset() +{ +} + +UINT8 a2eaux_ext80col_device::read_auxram(UINT16 offset) +{ + return m_ram[offset]; +} + +void a2eaux_ext80col_device::write_auxram(UINT16 offset, UINT8 data) +{ + m_ram[offset] = data; +} + +UINT8 *a2eaux_ext80col_device::get_vram_ptr() +{ + return &m_ram[0]; +} + +UINT8 *a2eaux_ext80col_device::get_auxbank_ptr() +{ + return &m_ram[0]; +} diff --git a/src/devices/bus/a2bus/a2eext80col.h b/src/devices/bus/a2bus/a2eext80col.h new file mode 100644 index 00000000000..ba14f5f0ad3 --- /dev/null +++ b/src/devices/bus/a2bus/a2eext80col.h @@ -0,0 +1,47 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/********************************************************************* + + a2eext80col.c + + Apple IIe Extended 80 Column Card + +*********************************************************************/ + +#ifndef __A2EAUX_EXT80COL__ +#define __A2EAUX_EXT80COL__ + +#include "emu.h" +#include "a2eauxslot.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class a2eaux_ext80col_device: + public device_t, + public device_a2eauxslot_card_interface +{ +public: + // construction/destruction + a2eaux_ext80col_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + a2eaux_ext80col_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + +protected: + virtual void device_start(); + virtual void device_reset(); + + virtual UINT8 read_auxram(UINT16 offset); + virtual void write_auxram(UINT16 offset, UINT8 data); + virtual UINT8 *get_vram_ptr(); + virtual UINT8 *get_auxbank_ptr(); + virtual bool allow_dhr() { return true; } + +private: + UINT8 m_ram[64*1024]; +}; + +// device type definition +extern const device_type A2EAUX_EXT80COL; + +#endif /* __A2EAUX_EXT80COL__ */ diff --git a/src/devices/bus/a2bus/a2eramworks3.c b/src/devices/bus/a2bus/a2eramworks3.c new file mode 100644 index 00000000000..17b7b2ceb0e --- /dev/null +++ b/src/devices/bus/a2bus/a2eramworks3.c @@ -0,0 +1,99 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/********************************************************************* + + a2eramworks3.c + + Applied Engineering RamWorks III + + +*********************************************************************/ + +#include "emu.h" +#include "includes/apple2.h" +#include "a2eramworks3.h" + + +/*************************************************************************** + PARAMETERS +***************************************************************************/ + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type A2EAUX_RAMWORKS3 = &device_creator; + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +a2eaux_ramworks3_device::a2eaux_ramworks3_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, A2EAUX_RAMWORKS3, "Applied Engineering RamWorks III", tag, owner, clock, "a2erwks3", __FILE__), + device_a2eauxslot_card_interface(mconfig, *this) +{ +} + +a2eaux_ramworks3_device::a2eaux_ramworks3_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_a2eauxslot_card_interface(mconfig, *this) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void a2eaux_ramworks3_device::device_start() +{ + set_a2eauxslot_device(); + save_item(NAME(m_ram)); + save_item(NAME(m_bank)); +} + +void a2eaux_ramworks3_device::device_reset() +{ + m_bank = 0; +} + +UINT8 a2eaux_ramworks3_device::read_auxram(UINT16 offset) +{ + return m_ram[offset+m_bank]; +} + +void a2eaux_ramworks3_device::write_auxram(UINT16 offset, UINT8 data) +{ + m_ram[offset+m_bank] = data; +} + +UINT8 *a2eaux_ramworks3_device::get_vram_ptr() +{ + return &m_ram[0]; +} + +UINT8 *a2eaux_ramworks3_device::get_auxbank_ptr() +{ + return &m_ram[m_bank]; +} + +/* + These cards are split into 64k logical banks. + + On a RW3: + Banks 00-0F is the first MB + Banks 10-17 are the next 512K + Banks 30-37 are the next 512K + Banks 50-57 are the next 512K + Banks 70-77 are the next 512K + + However, the software will recognize and correctly use a configuration in which + all of banks 00-7F are populated for a total of 8 megabytes. So that's what we do. +*/ +void a2eaux_ramworks3_device::write_c07x(address_space &space, UINT8 offset, UINT8 data) +{ + // write to C073? + if (offset == 3) + { + m_bank = 0x10000 * (data & 0x7f); + } +} diff --git a/src/devices/bus/a2bus/a2eramworks3.h b/src/devices/bus/a2bus/a2eramworks3.h new file mode 100644 index 00000000000..93b120bb59d --- /dev/null +++ b/src/devices/bus/a2bus/a2eramworks3.h @@ -0,0 +1,49 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/********************************************************************* + + a2eramworks3.c + + Applied Engineering RamWorks III + +*********************************************************************/ + +#ifndef __A2EAUX_RAMWORKS3__ +#define __A2EAUX_RAMWORKS3__ + +#include "emu.h" +#include "a2eauxslot.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class a2eaux_ramworks3_device: + public device_t, + public device_a2eauxslot_card_interface +{ +public: + // construction/destruction + a2eaux_ramworks3_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + a2eaux_ramworks3_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + +protected: + virtual void device_start(); + virtual void device_reset(); + + virtual UINT8 read_auxram(UINT16 offset); + virtual void write_auxram(UINT16 offset, UINT8 data); + virtual UINT8 *get_vram_ptr(); + virtual UINT8 *get_auxbank_ptr(); + virtual bool allow_dhr() { return true; } + virtual void write_c07x(address_space &space, UINT8 offset, UINT8 data); + +private: + UINT8 m_ram[8*1024*1024]; + int m_bank; +}; + +// device type definition +extern const device_type A2EAUX_RAMWORKS3; + +#endif /* __A2EAUX_RAMWORKS3__ */ diff --git a/src/devices/bus/a2bus/a2estd80col.c b/src/devices/bus/a2bus/a2estd80col.c new file mode 100644 index 00000000000..706f32d6a55 --- /dev/null +++ b/src/devices/bus/a2bus/a2estd80col.c @@ -0,0 +1,82 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/********************************************************************* + + a2estd80col.c + + Apple IIe Standard 80 Column Card (2K of RAM, no double-hi-res) + +*********************************************************************/ + +#include "emu.h" +#include "includes/apple2.h" +#include "a2estd80col.h" + + +/*************************************************************************** + PARAMETERS +***************************************************************************/ + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type A2EAUX_STD80COL = &device_creator; + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +a2eaux_std80col_device::a2eaux_std80col_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, A2EAUX_STD80COL, "Apple IIe Standard 80-Column Card", tag, owner, clock, "a2estd80", __FILE__), + device_a2eauxslot_card_interface(mconfig, *this) +{ +} + +a2eaux_std80col_device::a2eaux_std80col_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_a2eauxslot_card_interface(mconfig, *this) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void a2eaux_std80col_device::device_start() +{ + set_a2eauxslot_device(); + save_item(NAME(m_ram)); +} + +void a2eaux_std80col_device::device_reset() +{ +} + +UINT8 a2eaux_std80col_device::read_auxram(UINT16 offset) +{ + if (offset < 0x800) + { + return m_ram[offset]; + } + + return 0xff; +} + +void a2eaux_std80col_device::write_auxram(UINT16 offset, UINT8 data) +{ + if (offset < 0x800) + { + m_ram[offset] = data; + } +} + +UINT8 *a2eaux_std80col_device::get_vram_ptr() +{ + return &m_ram[0]; +} + +UINT8 *a2eaux_std80col_device::get_auxbank_ptr() +{ + return &m_ram[0]; +} diff --git a/src/devices/bus/a2bus/a2estd80col.h b/src/devices/bus/a2bus/a2estd80col.h new file mode 100644 index 00000000000..bcab4bab704 --- /dev/null +++ b/src/devices/bus/a2bus/a2estd80col.h @@ -0,0 +1,47 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/********************************************************************* + + a2estd80col.c + + Apple IIe Standard 80 Column Card + +*********************************************************************/ + +#ifndef __A2EAUX_STD80COL__ +#define __A2EAUX_STD80COL__ + +#include "emu.h" +#include "a2eauxslot.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class a2eaux_std80col_device: + public device_t, + public device_a2eauxslot_card_interface +{ +public: + // construction/destruction + a2eaux_std80col_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + a2eaux_std80col_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + +protected: + virtual void device_start(); + virtual void device_reset(); + + virtual UINT8 read_auxram(UINT16 offset); + virtual void write_auxram(UINT16 offset, UINT8 data); + virtual UINT8 *get_vram_ptr(); + virtual UINT8 *get_auxbank_ptr(); + virtual bool allow_dhr() { return false; } // we don't allow DHR + +private: + UINT8 m_ram[2*1024]; +}; + +// device type definition +extern const device_type A2EAUX_STD80COL; + +#endif /* __A2EAUX_STD80COL__ */ diff --git a/src/devices/bus/a2bus/a2hsscsi.c b/src/devices/bus/a2bus/a2hsscsi.c new file mode 100644 index 00000000000..a292eba7410 --- /dev/null +++ b/src/devices/bus/a2bus/a2hsscsi.c @@ -0,0 +1,323 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/********************************************************************* + + a2hsscsi.c + + Implementation of the Apple II High Speed SCSI Card + + This uses an ASIC called "Sandwich II"; the card itself is + sometimes known as "Cocoon". + + Notes: + C0n0-C0n7 = NCR5380 registers in normal order + C0n8 = DMA address low + C0n9 = DMA address high + C0nA = DMA count low + C0nB = DMA count high + C0nC = DMA control + C0nD = Enable DMA / reset 5380 + C0nE = Priority (read bits 5-7) / Fire watchdog (write bit 7) / RAM bank (write bits 0-3) + C0nF = DMA speed (bit 7 = 0 for fast, 1 for slow) / ROM bank (write bits 0-4) + + DMA control register (C0nC): + 0x01 = pseudo-DMA enable + 0x02 = DMA enable + 0x04 = test mode + 0x08 = disable stop-DMA-on-IRQ + 0x10 = DMA direction (read only) + 0x20 = 5380 IRQ enable + 0x40 = system DMA status (read only) + 0x80 = DMA stopped due to IRQ + + Enable DMA / reset 5380 register (C0nD): + 0x01 = Resume DMA after rollover or IRQ + 0x02 = Reset the 5380 + 0x40 = Clear test mode + 0x80 = Set test mode + +*********************************************************************/ + +#include "a2hsscsi.h" +#include "includes/apple2.h" +#include "machine/nscsi_cd.h" +#include "machine/nscsi_hd.h" + +/*************************************************************************** + PARAMETERS +***************************************************************************/ + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type A2BUS_HSSCSI = &device_creator; + +#define SCSI_ROM_REGION "scsi_rom" +#define SCSI_BUS_TAG "scsibus" +#define SCSI_5380_TAG "scsibus:7:ncr5380" + +static MACHINE_CONFIG_FRAGMENT( ncr5380 ) + MCFG_DEVICE_CLOCK(10000000) + MCFG_NCR5380N_DRQ_HANDLER(DEVWRITELINE("^^", a2bus_hsscsi_device, drq_w)) +MACHINE_CONFIG_END + +static SLOT_INTERFACE_START( hsscsi_devices ) + SLOT_INTERFACE("cdrom", NSCSI_CDROM) + SLOT_INTERFACE("harddisk", NSCSI_HARDDISK) + SLOT_INTERFACE_INTERNAL("ncr5380", NCR5380N) +SLOT_INTERFACE_END + +static MACHINE_CONFIG_FRAGMENT( hsscsi ) + MCFG_NSCSI_BUS_ADD(SCSI_BUS_TAG) + MCFG_NSCSI_ADD("scsibus:0", hsscsi_devices, 0, false) + MCFG_NSCSI_ADD("scsibus:1", hsscsi_devices, 0, false) + MCFG_NSCSI_ADD("scsibus:2", hsscsi_devices, 0, false) + MCFG_NSCSI_ADD("scsibus:3", hsscsi_devices, 0, false) + MCFG_NSCSI_ADD("scsibus:4", hsscsi_devices, 0, false) + MCFG_NSCSI_ADD("scsibus:5", hsscsi_devices, 0, false) + MCFG_NSCSI_ADD("scsibus:6", hsscsi_devices, "harddisk", false) + MCFG_NSCSI_ADD("scsibus:7", hsscsi_devices, "ncr5380", true) + MCFG_DEVICE_CARD_MACHINE_CONFIG("ncr5380", ncr5380) +MACHINE_CONFIG_END + +ROM_START( hsscsi ) + ROM_REGION(0x8000, SCSI_ROM_REGION, 0) + ROM_LOAD( "341-0803.bin", 0x0000, 0x8000, CRC(2c15618b) SHA1(7d32227299933bfc1b7f8bc2062906fdfe530674) ) +ROM_END + +/*************************************************************************** + FUNCTION PROTOTYPES +***************************************************************************/ + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor a2bus_hsscsi_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( hsscsi ); +} + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *a2bus_hsscsi_device::device_rom_region() const +{ + return ROM_NAME( hsscsi ); +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +a2bus_hsscsi_device::a2bus_hsscsi_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_a2bus_card_interface(mconfig, *this), + m_ncr5380(*this, SCSI_5380_TAG), + m_scsibus(*this, SCSI_BUS_TAG) +{ +} + +a2bus_hsscsi_device::a2bus_hsscsi_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, A2BUS_HSSCSI, "Apple II High-Speed SCSI Card", tag, owner, clock, "a2hsscsi", __FILE__), + device_a2bus_card_interface(mconfig, *this), + m_ncr5380(*this, SCSI_5380_TAG), + m_scsibus(*this, SCSI_BUS_TAG) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void a2bus_hsscsi_device::device_start() +{ + // set_a2bus_device makes m_slot valid + set_a2bus_device(); + + m_rom = device().machine().root_device().memregion(this->subtag(SCSI_ROM_REGION).c_str())->base(); + + memset(m_ram, 0, 8192); + + save_item(NAME(m_ram)); + save_item(NAME(m_rambank)); + save_item(NAME(m_rombank)); + save_item(NAME(m_bank)); + save_item(NAME(m_drq)); + save_item(NAME(m_816block)); +} + +void a2bus_hsscsi_device::device_reset() +{ + m_rambank = 0; + m_rombank = 0; + m_c0ne = m_c0nf = 0; + m_816block = false; +} + + +/*------------------------------------------------- + read_c0nx - called for reads from this card's c0nx space +-------------------------------------------------*/ + +UINT8 a2bus_hsscsi_device::read_c0nx(address_space &space, UINT8 offset) +{ + switch (offset) + { + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: +// printf("Read 5380 @ %x\n", offset); + return m_ncr5380->read(space, offset); + + case 0xc: + return 0x00; // indicate watchdog? + + case 0xe: // code at cf32 wants to RMW this without killing the ROM bank + return m_c0ne; + + case 0xf: + return m_c0nf; + + default: + printf("Read c0n%x (PC=%x)\n", offset, space.device().safe_pc()); + break; + } + + return 0xff; +} + + +/*------------------------------------------------- + write_c0nx - called for writes to this card's c0nx space +-------------------------------------------------*/ + +void a2bus_hsscsi_device::write_c0nx(address_space &space, UINT8 offset, UINT8 data) +{ + switch (offset) + { + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: +// printf("%02x to 5380 reg %x\n", data, offset); + m_ncr5380->write(space, offset, data); + break; +#if 0 + case 8: // DMA address low + break; + + case 9: // DMA address high + break; + + case 0xa: // DMA count low + break; + + case 0xb: // DMA count high + break; + + case 0xc: // DMA control + break; +#endif + + case 0xd: // DMA enable / reset + printf("%02x to DMA enable/reset\n", data); + if (data & 0x2) + { + // printf("Resetting SCSI: %02x at %x\n", data, space.device().safe_pc()); + m_ncr5380->reset(); + } + break; + + case 0xe: + m_c0ne = data; + m_rombank = (data & 0x1f) * 0x400; + printf("c0ne to %x (ROM bank %x)\n", data & 0x1f, m_rombank); + break; + + case 0xf: + m_c0nf = data; + m_rambank = (data & 0x7) * 0x400; + printf("c0nf to %x (RAM bank %x)\n", data & 0x7, m_rambank); + break; + + default: + printf("Write %02x to c0n%x (PC=%x)\n", data, offset, space.device().safe_pc()); + break; + } +} + +/*------------------------------------------------- + read_cnxx - called for reads from this card's cnxx space +-------------------------------------------------*/ + +UINT8 a2bus_hsscsi_device::read_cnxx(address_space &space, UINT8 offset) +{ + // one slot image at the start of the ROM, it appears + return m_rom[offset]; +} + +void a2bus_hsscsi_device::write_cnxx(address_space &space, UINT8 offset, UINT8 data) +{ +// printf("Write %02x to cn%02x (PC=%x)\n", data, offset, space.device().safe_pc()); +} + +/*------------------------------------------------- + read_c800 - called for reads from this card's c800 space +-------------------------------------------------*/ + +UINT8 a2bus_hsscsi_device::read_c800(address_space &space, UINT16 offset) +{ + // bankswitched RAM at c800-cbff + // bankswitched ROM at cc00-cfff + if (offset < 0x400) + { +// printf("Read RAM at %x = %02x\n", offset+m_rambank, m_ram[offset + m_rambank]); + if (m_816block) + { + return m_ncr5380->dma_r(); + } + + return m_ram[offset + m_rambank]; + } + else + { + return m_rom[(offset-0x400) + m_rombank]; + } +} + +/*------------------------------------------------- + write_c800 - called for writes to this card's c800 space +-------------------------------------------------*/ +void a2bus_hsscsi_device::write_c800(address_space &space, UINT16 offset, UINT8 data) +{ + if (offset < 0x400) + { +// printf("%02x to RAM at %x\n", data, offset+m_rambank); + if (m_816block) + { + m_ncr5380->dma_w(data); + } + else + { + m_ram[offset + m_rambank] = data; + } + } +} + +WRITE_LINE_MEMBER( a2bus_hsscsi_device::drq_w ) +{ + m_drq = (state ? 0x80 : 0x00); +} diff --git a/src/devices/bus/a2bus/a2hsscsi.h b/src/devices/bus/a2bus/a2hsscsi.h new file mode 100644 index 00000000000..2deada2e051 --- /dev/null +++ b/src/devices/bus/a2bus/a2hsscsi.h @@ -0,0 +1,65 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/********************************************************************* + + a2hsscsi.h + + Implementation of the Apple II High Speed SCSI Card + +*********************************************************************/ + +#ifndef __A2BUS_HSSCSI__ +#define __A2BUS_HSSCSI__ + +#include "emu.h" +#include "a2bus.h" +#include "machine/ncr5380n.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class a2bus_hsscsi_device: + public device_t, + public device_a2bus_card_interface +{ +public: + // construction/destruction + a2bus_hsscsi_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + a2bus_hsscsi_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual const rom_entry *device_rom_region() const; + + required_device m_ncr5380; + required_device m_scsibus; + + DECLARE_WRITE_LINE_MEMBER( drq_w ); + +protected: + virtual void device_start(); + virtual void device_reset(); + + // overrides of standard a2bus slot functions + virtual UINT8 read_c0nx(address_space &space, UINT8 offset); + virtual void write_c0nx(address_space &space, UINT8 offset, UINT8 data); + virtual UINT8 read_cnxx(address_space &space, UINT8 offset); + virtual void write_cnxx(address_space &space, UINT8 offset, UINT8 data); + virtual UINT8 read_c800(address_space &space, UINT16 offset); + virtual void write_c800(address_space &space, UINT16 offset, UINT8 data); + +private: + UINT8 *m_rom; + UINT8 m_ram[8192]; // 8 banks of 1024 bytes + int m_rambank, m_rombank; + UINT8 m_drq; + UINT8 m_bank; + bool m_816block; + UINT8 m_c0ne, m_c0nf; +}; + +// device type definition +extern const device_type A2BUS_HSSCSI; + +#endif /* __A2BUS_HSSCSI__ */ diff --git a/src/devices/bus/a2bus/a2lang.c b/src/devices/bus/a2bus/a2lang.c new file mode 100644 index 00000000000..9a0b21dca36 --- /dev/null +++ b/src/devices/bus/a2bus/a2lang.c @@ -0,0 +1,145 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/********************************************************************* + + a2lang.c + + Implementation of the Apple II Language Card + + TODO: refactor machine/apple2.c so it's possible to have an Apple II + and II Plus without a language card (and to emulate other + slot 0 stuff like hack/freezer cards). + +*********************************************************************/ + +#include "emu.h" +#include "includes/apple2.h" +#include "a2lang.h" + + +/*************************************************************************** + PARAMETERS +***************************************************************************/ + +#define LOG_LANGCARD 0 + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type A2BUS_LANG = &device_creator; + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +a2bus_lang_device::a2bus_lang_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, A2BUS_LANG, "Apple II Language Card", tag, owner, clock, "a2lang", __FILE__), + device_a2bus_card_interface(mconfig, *this) +{ + last_offset = -1; +} + +a2bus_lang_device::a2bus_lang_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_a2bus_card_interface(mconfig, *this) +{ + last_offset = -1; +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void a2bus_lang_device::device_start() +{ + // set_a2bus_device makes m_slot valid + set_a2bus_device(); + + save_item(NAME(last_offset)); +} + +void a2bus_lang_device::device_reset() +{ +} + +/*------------------------------------------------- + apple2_langcard_touch - device read callback +-------------------------------------------------*/ + +void a2bus_lang_device::langcard_touch(offs_t offset) +{ + UINT32 val, mask; + + if (LOG_LANGCARD) + logerror("language card bankswitch read, offset: $c08%0x\n", offset); + + /* determine which flags to change */ + mask = VAR_LCWRITE | VAR_LCRAM | VAR_LCRAM2; + val = 0; + + if (offset & 0x01) + val |= VAR_LCWRITE; + + switch(offset & 0x03) + { + case 0x03: + case 0x00: + val |= VAR_LCRAM; + break; + } + + if ((offset & 0x08) == 0) + val |= VAR_LCRAM2; + + /* change the flags */ + apple2_state *state = machine().driver_data(); + state->apple2_setvar(val, mask); +} + + + +/*------------------------------------------------- + read_c0nx - called for reads from this card's c0nx space +-------------------------------------------------*/ + +UINT8 a2bus_lang_device::read_c0nx(address_space &space, UINT8 offset) +{ + apple2_state *state = machine().driver_data(); + + // enforce "read twice" for c081/3/9/B + // but only on the II/II+ with a discrete language card. + // later machines' ASICs dropped the double-read requirement, + // likely to be interrupt-safe. + if (state->m_machinetype == APPLE_II) + { + switch (offset & 0x03) + { + case 1: + case 3: + if (offset != last_offset) + { + last_offset = offset; + return 0; + } + break; + } + } + + langcard_touch(offset); + last_offset = offset; + return 0; +} + + + +/*------------------------------------------------- + write_c0nx - called for writes to this card's c0nx space +-------------------------------------------------*/ + +void a2bus_lang_device::write_c0nx(address_space &space, UINT8 offset, UINT8 data) +{ + langcard_touch(offset); + last_offset = -1; +} diff --git a/src/devices/bus/a2bus/a2lang.h b/src/devices/bus/a2bus/a2lang.h new file mode 100644 index 00000000000..b97ae92a5b1 --- /dev/null +++ b/src/devices/bus/a2bus/a2lang.h @@ -0,0 +1,46 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/********************************************************************* + + a2lang.h + + Apple II Language Card + +*********************************************************************/ + +#ifndef __A2BUS_LANG__ +#define __A2BUS_LANG__ + +#include "emu.h" +#include "a2bus.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class a2bus_lang_device: + public device_t, + public device_a2bus_card_interface +{ +public: + // construction/destruction + a2bus_lang_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + a2bus_lang_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + +protected: + virtual void device_start(); + virtual void device_reset(); + + virtual UINT8 read_c0nx(address_space &space, UINT8 offset); + virtual void write_c0nx(address_space &space, UINT8 offset, UINT8 data); + +private: + void langcard_touch(offs_t offset); + + int last_offset; +}; + +// device type definition +extern const device_type A2BUS_LANG; + +#endif /* __A2BUS_LANG__ */ diff --git a/src/devices/bus/a2bus/a2mcms.c b/src/devices/bus/a2bus/a2mcms.c new file mode 100644 index 00000000000..e9bb29d1243 --- /dev/null +++ b/src/devices/bus/a2bus/a2mcms.c @@ -0,0 +1,382 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/********************************************************************* + + a2mcms.c + + Implementation of the Mountain Computer Music System. + This was sold standalone and also used as part of the alphaSyntauri + and SoundChaser systems. + +*********************************************************************/ + +#include "a2mcms.h" +#include "includes/apple2.h" + +// the actual sound device (a slot device can't currently also be a sound device so we keep this private here) +enum +{ + CTRL_IRQS = 0, + CTRL_DMA, + CTRL_MASTERVOL +}; + + +const device_type MCMS = &device_creator; + +/*************************************************************************** + PARAMETERS +***************************************************************************/ + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type A2BUS_MCMS1 = &device_creator; +const device_type A2BUS_MCMS2 = &device_creator; + +#define ENGINE_TAG "engine" + +#define MCFG_MCMS_IRQ_CALLBACK(_cb) \ + devcb = &mcms_device::set_irq_cb(*device, DEVCB_##_cb); + +MACHINE_CONFIG_FRAGMENT( a2mcms ) + MCFG_SPEAKER_STANDARD_STEREO("mcms_l", "mcms_r") + + MCFG_DEVICE_ADD(ENGINE_TAG, MCMS, 1000000) + MCFG_MCMS_IRQ_CALLBACK(WRITELINE(a2bus_mcms1_device, irq_w)) + + MCFG_SOUND_ROUTE(0, "mcms_l", 1.0) + MCFG_SOUND_ROUTE(1, "mcms_r", 1.0) +MACHINE_CONFIG_END + +/*************************************************************************** + FUNCTION PROTOTYPES +***************************************************************************/ + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor a2bus_mcms1_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( a2mcms ); +} + +//************************************************************************** +// LIVE DEVICE - Card 1 +//************************************************************************** + +a2bus_mcms1_device::a2bus_mcms1_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_a2bus_card_interface(mconfig, *this), + m_mcms(*this, ENGINE_TAG) +{ +} + +a2bus_mcms1_device::a2bus_mcms1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, A2BUS_MCMS1, "Mountain Computer Music System (card 1)", tag, owner, clock, "a2mcms1", __FILE__), + device_a2bus_card_interface(mconfig, *this), + m_mcms(*this, ENGINE_TAG) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void a2bus_mcms1_device::device_start() +{ + // set_a2bus_device makes m_slot valid + set_a2bus_device(); +} + +void a2bus_mcms1_device::device_reset() +{ + m_mcms->set_bus_device(this); +} + +// read once at c0n0 to disable 125 Hz IRQs +// read once at c0n1 to enable 125 Hz IRQs +UINT8 a2bus_mcms1_device::read_c0nx(address_space &space, UINT8 offset) +{ + if (offset == 0) + { + m_mcms->control_w(space, CTRL_IRQS, 0); + } + else if (offset == 1) + { + m_mcms->control_w(space, CTRL_IRQS, 1); + } + + return 0xff; +} + +// read at Cn00: light gun in bit 7, bits 0-5 = 'random' number +UINT8 a2bus_mcms1_device::read_cnxx(address_space &space, UINT8 offset) +{ + return m_mcms->get_pen_rand(); +} + +// write 0-255 to Cn00 to set the master volume +void a2bus_mcms1_device::write_cnxx(address_space &space, UINT8 offset, UINT8 data) +{ + if (offset == 0) + { + m_mcms->control_w(space, CTRL_MASTERVOL, data); + } +} + +mcms_device *a2bus_mcms1_device::get_engine(void) +{ + return m_mcms; +} + +WRITE_LINE_MEMBER(a2bus_mcms1_device::irq_w) +{ + if (state == ASSERT_LINE) + { + raise_slot_irq(); + } + else + { + lower_slot_irq(); + } +} + +//************************************************************************** +// LIVE DEVICE - Card 2 +//************************************************************************** + +a2bus_mcms2_device::a2bus_mcms2_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_a2bus_card_interface(mconfig, *this) +{ +} + +a2bus_mcms2_device::a2bus_mcms2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, A2BUS_MCMS2, "Mountain Computer Music System (card 2)", tag, owner, clock, "a2mcms2", __FILE__), + device_a2bus_card_interface(mconfig, *this) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void a2bus_mcms2_device::device_start() +{ + // set_a2bus_device makes m_slot valid + set_a2bus_device(); + + if (m_slot < 2) + { + fatalerror("MCMS: Card 2 must be in slot 2 or greater\n"); + } +} + +void a2bus_mcms2_device::device_reset() +{ + m_card1 = static_cast(m_a2bus->m_device_list[m_slot-1]); + m_engine = m_card1->get_engine(); +} + +// here to soak up false reads from indexed accesses +UINT8 a2bus_mcms2_device::read_c0nx(address_space &space, UINT8 offset) +{ + return 0xff; +} + +// write once to c0n0 to disable the card (reset also disables) +// write twice to c0n1 to enable the card (value doesn't matter) +void a2bus_mcms2_device::write_c0nx(address_space &space, UINT8 offset, UINT8 data) +{ + if (offset == 0) + { + m_engine->control_w(space, CTRL_DMA, 0); + } + else if (offset == 1) + { + m_engine->control_w(space, CTRL_DMA, 1); + } +} + +void a2bus_mcms2_device::write_cnxx(address_space &space, UINT8 offset, UINT8 data) +{ + m_engine->voiceregs_w(space, offset, data); +} + + +/* + Sound device implementation +*/ + +mcms_device::mcms_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, MCMS, "Mountain Computer Music System engine", tag, owner, clock, "msmseng", __FILE__), + device_sound_interface(mconfig, *this), + m_write_irq(*this) +{ +} + +void mcms_device::device_start() +{ + m_write_irq.resolve(); + m_stream = machine().sound().stream_alloc(*this, 0, 2, 31250); + m_timer = timer_alloc(0, NULL); + m_clrtimer = timer_alloc(1, NULL); + m_enabled = false; + memset(m_vols, 0, sizeof(m_vols)); + memset(m_table, 0, sizeof(m_table)); + memset(m_freq, 0, sizeof(m_freq)); + memset(m_acc, 0, sizeof(m_acc)); + + // the card detect programs volumes and wavetable page but not freq and expects the accumulator to increment + for (int i = 0; i < 16; i++) + { + m_freq[i] = 0x0040; + } + + save_item(NAME(m_enabled)); + save_item(NAME(m_vols)); + save_item(NAME(m_table)); + save_item(NAME(m_freq)); + save_item(NAME(m_acc)); + save_item(NAME(m_mastervol)); + save_item(NAME(m_rand)); +} + +void mcms_device::device_reset() +{ + m_write_irq(CLEAR_LINE); + m_timer->adjust(attotime::never); + m_clrtimer->adjust(attotime::never); + m_enabled = false; +} + +void mcms_device::device_timer(emu_timer &timer, device_timer_id tid, int param, void *ptr) +{ + if (tid == 0) + { + m_write_irq(ASSERT_LINE); + // clear this IRQ in 10 cycles (?) + m_clrtimer->adjust(attotime::from_usec(10), 0); + } + else if (tid == 1) + { + m_write_irq(CLEAR_LINE); + } +} + +void mcms_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + stream_sample_t *outL, *outR; + int i, v; + UINT16 wptr; + INT8 sample; + INT32 mixL, mixR; + + outL = outputs[1]; + outR = outputs[0]; + + if (m_enabled) + { + for (i = 0; i < samples; i++) + { + mixL = mixR = 0; + + for (v = 0; v < 16; v++) + { + m_acc[v] += m_freq[v]; + wptr = (m_table[v]<<8) | (m_acc[v]>>8); + m_rand = (m_acc[v]>>8) & 0x1f; + + sample = (m_pBusDevice->slot_dma_read_no_space(wptr) ^ 0x80); + if (v & 1) + { + mixL += sample * m_vols[v]; + } + else + { + mixR += sample * m_vols[v]; + } + } + + outL[i] = (mixL * m_mastervol)>>9; + outR[i] = (mixR * m_mastervol)>>9; + } + } + else + { + for (i = 0; i < samples; i++) + { + outL[i] = outR[i] = 0; + } + } +} + +WRITE8_MEMBER(mcms_device::voiceregs_w) +{ + m_stream->update(); + if (offset >= 0x20) + { + if (offset & 1) // amp + { + m_vols[(offset-0x21)/2] = data; + } + else // wavetable page + { + m_table[(offset-0x20)/2] = data; + } + } + else + { + if (offset & 1) // freq L + { + if (offset == 0x1f) + { + m_freq[0] &= 0xff00; + m_freq[0] |= data; + } + else + { + int reg = (offset/2)+1; + m_freq[reg] &= 0xff00; + m_freq[reg] |= data; + } + } + else // freq H + { + int reg = (offset/2); + m_freq[reg] &= 0x00ff; + m_freq[reg] |= (data<<8); + } + } +} + +WRITE8_MEMBER(mcms_device::control_w) +{ + m_stream->update(); + + switch (offset) + { + case CTRL_IRQS: + if (data == 0) + { + m_timer->adjust(attotime::never); + } + else + { + m_timer->adjust(attotime::zero, 0, attotime::from_hz(125)); + } + break; + + case CTRL_DMA: + m_enabled = (data == 0) ? false : true; + break; + + case CTRL_MASTERVOL: + m_mastervol = data; + break; + } +} diff --git a/src/devices/bus/a2bus/a2mcms.h b/src/devices/bus/a2bus/a2mcms.h new file mode 100644 index 00000000000..283d13be62c --- /dev/null +++ b/src/devices/bus/a2bus/a2mcms.h @@ -0,0 +1,121 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/********************************************************************* + + a2mcms.h + + Implementation of the Mountain Computer Music System. + This was sold standalone and also used as part of the alphaSyntauri + and SoundChaser systems. + +*********************************************************************/ + +#ifndef __A2BUS_MCMS__ +#define __A2BUS_MCMS__ + +#include "emu.h" +#include "a2bus.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class a2bus_mcms1_device; + +class mcms_device : public device_t, public device_sound_interface +{ +public: + // construction/destruction + mcms_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + DECLARE_WRITE8_MEMBER(voiceregs_w); + DECLARE_WRITE8_MEMBER(control_w); + UINT8 get_pen_rand(void) { m_stream->update(); return m_rand; } + + void set_bus_device(a2bus_mcms1_device *pDev) { m_pBusDevice = pDev; } + + template static devcb_base &set_irq_cb(device_t &device, _Object wr) { return downcast(device).m_write_irq.set_callback(wr); } + devcb_write_line m_write_irq; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + +private: + sound_stream *m_stream; + emu_timer *m_timer, *m_clrtimer; + a2bus_mcms1_device *m_pBusDevice; + bool m_enabled; + UINT8 m_vols[16]; + UINT8 m_table[16]; + UINT16 m_freq[16]; + UINT16 m_acc[16]; + UINT8 m_mastervol; + UINT8 m_rand; +}; + +// card 1 +class a2bus_mcms1_device: + public device_t, + public device_a2bus_card_interface +{ +public: + // construction/destruction + a2bus_mcms1_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + a2bus_mcms1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + + // comms from card 2 (oscillator parameter writes) + mcms_device *get_engine(void); + + DECLARE_WRITE_LINE_MEMBER(irq_w); + + required_device m_mcms; + +protected: + virtual void device_start(); + virtual void device_reset(); + + // overrides of standard a2bus slot functions + virtual UINT8 read_c0nx(address_space &space, UINT8 offset); + virtual UINT8 read_cnxx(address_space &space, UINT8 offset); + virtual void write_cnxx(address_space &space, UINT8 offset, UINT8 data); + virtual bool take_c800() { return false; } +}; + +// card 2 +class a2bus_mcms2_device: + public device_t, + public device_a2bus_card_interface +{ +public: + // construction/destruction + a2bus_mcms2_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + a2bus_mcms2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual void device_start(); + virtual void device_reset(); + + // overrides of standard a2bus slot functions + virtual UINT8 read_c0nx(address_space &space, UINT8 offset); + virtual void write_c0nx(address_space &space, UINT8 offset, UINT8 data); + virtual void write_cnxx(address_space &space, UINT8 offset, UINT8 data); + virtual bool take_c800() { return false; } + +private: + a2bus_mcms1_device *m_card1; // card 1 for passthrough + mcms_device *m_engine; +}; + +// device type definition +extern const device_type A2BUS_MCMS1; +extern const device_type A2BUS_MCMS2; + +#endif /* __A2BUS_MCMS__ */ diff --git a/src/devices/bus/a2bus/a2memexp.c b/src/devices/bus/a2bus/a2memexp.c new file mode 100644 index 00000000000..210ba76a0d2 --- /dev/null +++ b/src/devices/bus/a2bus/a2memexp.c @@ -0,0 +1,230 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/********************************************************************* + + a2memexp.c + + Implementation of the Apple II Memory Expansion Card + +*********************************************************************/ + +#include "a2memexp.h" +#include "includes/apple2.h" + + +/*************************************************************************** + PARAMETERS +***************************************************************************/ + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type A2BUS_MEMEXP = &device_creator; +const device_type A2BUS_RAMFACTOR = &device_creator; + +#define MEMEXP_ROM_REGION "memexp_rom" + +MACHINE_CONFIG_FRAGMENT( memexp ) +MACHINE_CONFIG_END + +ROM_START( memexp ) + ROM_REGION(0x1000, MEMEXP_ROM_REGION, 0) + ROM_LOAD( "341-0344a.bin", 0x0000, 0x1000, CRC(1e994e17) SHA1(6e823a1fa40ed37eeddcef23f5df24da2ea1463e) ) +ROM_END + +ROM_START( ramfactor ) + ROM_REGION(0x8000, MEMEXP_ROM_REGION, 0) + ROM_LOAD( "ae ramfactor rom v1.4.bin", 0x0000, 0x2000, CRC(1c56d646) SHA1(32cb02a6a915dd3962bfa1f0184a94253e03ba6b) ) + ROM_LOAD( "ae ramfactor rom v1.3.bin", 0x2000, 0x2000, CRC(434f5c45) SHA1(cf31a370951bd9a10d5b77f179134b358683b8fa) ) + ROM_LOAD( "ae ramfactor rom v1.1.bin", 0x4000, 0x2000, CRC(328907a3) SHA1(dc25b4133a52609799098d8918a289fd973d28d9) ) + ROM_LOAD( "ae ramfactor rom v1.0.bin", 0x6000, 0x2000, CRC(39c2162a) SHA1(9286d35907939aadb1fffd3e1d75603fe3e846ad) ) +ROM_END + +/*************************************************************************** + FUNCTION PROTOTYPES +***************************************************************************/ + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor a2bus_memexp_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( memexp ); +} + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *a2bus_memexp_device::device_rom_region() const +{ + return ROM_NAME( memexp ); +} + +const rom_entry *a2bus_ramfactor_device::device_rom_region() const +{ + return ROM_NAME( ramfactor ); +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +a2bus_memexp_device::a2bus_memexp_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_a2bus_card_interface(mconfig, *this) +{ +} + +a2bus_memexpapple_device::a2bus_memexpapple_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + a2bus_memexp_device(mconfig, A2BUS_MEMEXP, "Apple II Memory Expansion Card", tag, owner, clock, "a2memexp", __FILE__) +{ + m_isramfactor = false; + m_bankhior = 0xf0; + m_addrmask = 0xfffff; +} + +a2bus_ramfactor_device::a2bus_ramfactor_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + a2bus_memexp_device(mconfig, A2BUS_RAMFACTOR, "Applied Engineering RamFactor", tag, owner, clock, "a2ramfac", __FILE__) +{ + m_isramfactor = true; + m_bankhior = 0x00; + m_addrmask = 0x7fffff; +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void a2bus_memexp_device::device_start() +{ + // set_a2bus_device makes m_slot valid + set_a2bus_device(); + + m_rom = device().machine().root_device().memregion(this->subtag(MEMEXP_ROM_REGION).c_str())->base(); + + memset(m_ram, 0xff, 1024*1024*sizeof(UINT8)); + + save_item(NAME(m_regs)); + save_item(NAME(m_ram)); + save_item(NAME(m_wptr)); + save_item(NAME(m_liveptr)); +} + +void a2bus_memexp_device::device_reset() +{ + memset(m_regs, 0, sizeof(UINT8) * 0x10); + m_wptr = m_liveptr = 0; +} + + +/*------------------------------------------------- + read_c0nx - called for reads from this card's c0nx space +-------------------------------------------------*/ + +UINT8 a2bus_memexp_device::read_c0nx(address_space &space, UINT8 offset) +{ + UINT8 retval = m_regs[offset]; + + if (offset == 3) + { + retval = m_ram[m_liveptr&m_addrmask]; +// printf("Read RAM[%x] = %02x\n", m_liveptr, retval); + m_liveptr++; + m_regs[0] = m_liveptr & 0xff; + m_regs[1] = (m_liveptr>>8) & 0xff; + m_regs[2] = ((m_liveptr>>16) & 0xff) | m_bankhior; + } + +// printf("Read c0n%x (PC=%x) = %02x\n", offset, space.device().safe_pc(), retval); + + return retval; +} + + +/*------------------------------------------------- + write_c0nx - called for writes to this card's c0nx space +-------------------------------------------------*/ + +void a2bus_memexp_device::write_c0nx(address_space &space, UINT8 offset, UINT8 data) +{ +// printf("Write %02x to c0n%x (PC=%x)\n", data, offset, space.device().safe_pc()); + + switch (offset) + { + case 0: + m_wptr &= ~0xff; + m_wptr |= data; + m_regs[0] = m_wptr & 0xff; + m_regs[1] = (m_wptr>>8) & 0xff; + m_regs[2] = ((m_wptr>>16) & 0xff) | m_bankhior; + m_liveptr = m_wptr; + break; + + case 1: + m_wptr &= ~0xff00; + m_wptr |= (data<<8); + m_regs[0] = m_wptr & 0xff; + m_regs[1] = (m_wptr>>8) & 0xff; + m_regs[2] = ((m_wptr>>16) & 0xff) | m_bankhior; + m_liveptr = m_wptr; + break; + + case 2: + m_wptr &= ~0xff0000; + m_wptr |= (data<<16); + m_regs[0] = m_wptr & 0xff; + m_regs[1] = (m_wptr>>8) & 0xff; + m_regs[2] = ((m_wptr>>16) & 0xff) | m_bankhior; + m_liveptr = m_wptr; + break; + + case 3: +// printf("Write %02x to RAM[%x]\n", data, m_liveptr); + m_ram[(m_liveptr&m_addrmask)] = data; + m_liveptr++; + m_regs[0] = m_liveptr & 0xff; + m_regs[1] = (m_liveptr>>8) & 0xff; + m_regs[2] = ((m_liveptr>>16) & 0xff) | m_bankhior; + break; + + default: + m_regs[offset] = data; + break; + } +} + +/*------------------------------------------------- + read_cnxx - called for reads from this card's cnxx space +-------------------------------------------------*/ + +UINT8 a2bus_memexp_device::read_cnxx(address_space &space, UINT8 offset) +{ + int slotimg = m_slot * 0x100; + + // first 0x400 of ROM contains a CnXX image for each of slots 1-7, last 0x400 is c800 image + if ((m_isramfactor) && (m_regs[0xf] & 0x01)) + { + return m_rom[offset+slotimg+0x1000]; + } + + return m_rom[offset+slotimg]; +} + +/*------------------------------------------------- + read_c800 - called for reads from this card's c800 space +-------------------------------------------------*/ + +UINT8 a2bus_memexp_device::read_c800(address_space &space, UINT16 offset) +{ + // c70a diags confirm: bit 1 of cn0F banks in the second half of the ROM + if ((m_isramfactor) && (m_regs[0xf] & 0x01)) + { + return m_rom[offset+0x1800]; + } + + return m_rom[offset+0x800]; +} diff --git a/src/devices/bus/a2bus/a2memexp.h b/src/devices/bus/a2bus/a2memexp.h new file mode 100644 index 00000000000..e7167569c67 --- /dev/null +++ b/src/devices/bus/a2bus/a2memexp.h @@ -0,0 +1,72 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/********************************************************************* + + a2memexp.h + + Implementation of the Apple II Memory Expansion Card + +*********************************************************************/ + +#ifndef __A2BUS_MEMEXP__ +#define __A2BUS_MEMEXP__ + +#include "emu.h" +#include "a2bus.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class a2bus_memexp_device: + public device_t, + public device_a2bus_card_interface +{ +public: + // construction/destruction + a2bus_memexp_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual const rom_entry *device_rom_region() const; + + bool m_isramfactor; + UINT8 m_bankhior; + int m_addrmask; + +protected: + virtual void device_start(); + virtual void device_reset(); + + // overrides of standard a2bus slot functions + virtual UINT8 read_c0nx(address_space &space, UINT8 offset); + virtual void write_c0nx(address_space &space, UINT8 offset, UINT8 data); + virtual UINT8 read_cnxx(address_space &space, UINT8 offset); + virtual UINT8 read_c800(address_space &space, UINT16 offset); + +private: + UINT8 *m_rom; + UINT8 m_regs[0x10]; + UINT8 m_ram[8*1024*1024]; + int m_wptr, m_liveptr; +}; + +class a2bus_memexpapple_device : public a2bus_memexp_device +{ +public: + a2bus_memexpapple_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class a2bus_ramfactor_device : public a2bus_memexp_device +{ +public: + a2bus_ramfactor_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual const rom_entry *device_rom_region() const; +}; + +// device type definition +extern const device_type A2BUS_MEMEXP; +extern const device_type A2BUS_RAMFACTOR; + +#endif /* __A2BUS_MEMEXP__ */ diff --git a/src/devices/bus/a2bus/a2midi.c b/src/devices/bus/a2bus/a2midi.c new file mode 100644 index 00000000000..92dbff70520 --- /dev/null +++ b/src/devices/bus/a2bus/a2midi.c @@ -0,0 +1,172 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/********************************************************************* + + a2midi.c + + Apple II 6850 MIDI card, as made by Passport, Yamaha, and others. + +*********************************************************************/ + +#include "a2midi.h" +#include "machine/clock.h" +#include "bus/midi/midi.h" + + +/*************************************************************************** + PARAMETERS +***************************************************************************/ + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type A2BUS_MIDI = &device_creator; + +#define MIDI_PTM_TAG "midi_ptm" +#define MIDI_ACIA_TAG "midi_acia" + +MACHINE_CONFIG_FRAGMENT( midi ) + MCFG_DEVICE_ADD(MIDI_PTM_TAG, PTM6840, 0) + MCFG_PTM6840_INTERNAL_CLOCK(1021800.0f) + MCFG_PTM6840_EXTERNAL_CLOCKS(1021800.0f, 1021800.0f, 1021800.0f) + MCFG_PTM6840_IRQ_CB(WRITELINE(a2bus_midi_device, ptm_irq_w)) + + MCFG_DEVICE_ADD(MIDI_ACIA_TAG, ACIA6850, 0) + MCFG_ACIA6850_TXD_HANDLER(DEVWRITELINE("mdout", midi_port_device, write_txd)) + MCFG_ACIA6850_IRQ_HANDLER(WRITELINE(a2bus_midi_device, acia_irq_w)) + + MCFG_MIDI_PORT_ADD("mdin", midiin_slot, "midiin") + MCFG_MIDI_RX_HANDLER(DEVWRITELINE(MIDI_ACIA_TAG, acia6850_device, write_rxd)) + + MCFG_MIDI_PORT_ADD("mdout", midiout_slot, "midiout") + + MCFG_DEVICE_ADD("acia_clock", CLOCK, 31250*16) + MCFG_CLOCK_SIGNAL_HANDLER(WRITELINE(a2bus_midi_device, write_acia_clock)) +MACHINE_CONFIG_END + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor a2bus_midi_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( midi ); +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +a2bus_midi_device::a2bus_midi_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, A2BUS_MIDI, "6850 MIDI card", tag, owner, clock, "a2midi", __FILE__), + device_a2bus_card_interface(mconfig, *this), + m_ptm(*this, MIDI_PTM_TAG), + m_acia(*this, MIDI_ACIA_TAG), + m_ptm_irq(false) +{ +} + +a2bus_midi_device::a2bus_midi_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_a2bus_card_interface(mconfig, *this), + m_ptm(*this, MIDI_PTM_TAG), + m_acia(*this, MIDI_ACIA_TAG), + m_ptm_irq(false) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void a2bus_midi_device::device_start() +{ + // set_a2bus_device makes m_slot valid + set_a2bus_device(); +} + +void a2bus_midi_device::device_reset() +{ + m_acia_irq = m_ptm_irq = false; +} + +/*------------------------------------------------- + read_c0nx - called for reads from this card's c0nx space +-------------------------------------------------*/ + +UINT8 a2bus_midi_device::read_c0nx(address_space &space, UINT8 offset) +{ + // PTM at C0n0-C0n7, ACIA at C0n8-C0n9, drum sync (?) at C0nA-C0nB + + if (offset < 8) + { + return m_ptm->read(space, offset & 7); + } + else if (offset == 8) + { + return m_acia->status_r(space, 0); + } + else if (offset == 9) + { + UINT8 ret = m_acia->data_r(space, 0); + return ret; + } + + return 0; +} + +/*------------------------------------------------- + write_c0nx - called for writes to this card's c0nx space +-------------------------------------------------*/ + +void a2bus_midi_device::write_c0nx(address_space &space, UINT8 offset, UINT8 data) +{ + if (offset < 8) + { + m_ptm->write(space, offset & 7, data); + } + else if (offset == 8) + { + m_acia->control_w(space, 0, data); + } + else if (offset == 9) + { + m_acia->data_w(space, 0, data); + } +} + +WRITE_LINE_MEMBER( a2bus_midi_device::acia_irq_w ) +{ + m_acia_irq = state ? true : false; + + if (m_acia_irq || m_ptm_irq) + { + raise_slot_irq(); + } + else + { + lower_slot_irq(); + } +} + +WRITE_LINE_MEMBER( a2bus_midi_device::ptm_irq_w ) +{ + m_acia_irq = state ? true : false; + + if (m_acia_irq || m_ptm_irq) + { + raise_slot_irq(); + } + else + { + lower_slot_irq(); + } +} + +WRITE_LINE_MEMBER( a2bus_midi_device::write_acia_clock ) +{ + m_acia->write_txc(state); + m_acia->write_rxc(state); +} diff --git a/src/devices/bus/a2bus/a2midi.h b/src/devices/bus/a2bus/a2midi.h new file mode 100644 index 00000000000..f7023eba570 --- /dev/null +++ b/src/devices/bus/a2bus/a2midi.h @@ -0,0 +1,55 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/********************************************************************* + + a2midi.h + + Apple II 6850 MIDI card, as made by Passport, Yamaha, and others. + +*********************************************************************/ + +#ifndef __A2BUS_MIDI__ +#define __A2BUS_MIDI__ + +#include "a2bus.h" +#include "machine/6840ptm.h" +#include "machine/6850acia.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class a2bus_midi_device: + public device_t, + public device_a2bus_card_interface +{ +public: + // construction/destruction + a2bus_midi_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + a2bus_midi_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + + DECLARE_WRITE_LINE_MEMBER( acia_irq_w ); + DECLARE_WRITE_LINE_MEMBER( ptm_irq_w ); + DECLARE_WRITE_LINE_MEMBER( write_acia_clock ); + +protected: + virtual void device_start(); + virtual void device_reset(); + + virtual UINT8 read_c0nx(address_space &space, UINT8 offset); + virtual void write_c0nx(address_space &space, UINT8 offset, UINT8 data); + + required_device m_ptm; + required_device m_acia; + +private: + bool m_acia_irq, m_ptm_irq; +}; + +// device type definition +extern const device_type A2BUS_MIDI; + +#endif /* __A2BUS_MIDI__ */ diff --git a/src/devices/bus/a2bus/a2mockingboard.c b/src/devices/bus/a2bus/a2mockingboard.c new file mode 100644 index 00000000000..9dd792f6e45 --- /dev/null +++ b/src/devices/bus/a2bus/a2mockingboard.c @@ -0,0 +1,528 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/********************************************************************* + + a2mockingboard.c + + Implementation of the Sweet Micro Systems Mockingboard card + and friends. + +*********************************************************************/ + +#include "emu.h" +#include "a2mockingboard.h" + + +/*************************************************************************** + PARAMETERS +***************************************************************************/ + +#define VIA1_TAG "mockbd_via1" +#define VIA2_TAG "mockbd_via2" +#define AY1_TAG "mockbd_ay1" +#define AY2_TAG "mockbd_ay2" +#define AY3_TAG "mockbd_ay3" +#define AY4_TAG "mockbd_ay4" +#define E2P_TMS_TAG "tms5220" + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type A2BUS_MOCKINGBOARD = &device_creator; +const device_type A2BUS_PHASOR = &device_creator; +const device_type A2BUS_ECHOPLUS = &device_creator; + +MACHINE_CONFIG_FRAGMENT( mockingboard ) + MCFG_DEVICE_ADD(VIA1_TAG, VIA6522, 1022727) + MCFG_VIA6522_WRITEPA_HANDLER(WRITE8(a2bus_ayboard_device, via1_out_a)) + MCFG_VIA6522_WRITEPB_HANDLER(WRITE8(a2bus_ayboard_device, via1_out_b)) + MCFG_VIA6522_IRQ_HANDLER(WRITELINE(a2bus_ayboard_device, via1_irq_w)) + + MCFG_DEVICE_ADD(VIA2_TAG, VIA6522, 1022727) + MCFG_VIA6522_WRITEPA_HANDLER(WRITE8(a2bus_ayboard_device, via2_out_a)) + MCFG_VIA6522_WRITEPB_HANDLER(WRITE8(a2bus_ayboard_device, via2_out_b)) + MCFG_VIA6522_IRQ_HANDLER(WRITELINE(a2bus_ayboard_device, via2_irq_w)) + + MCFG_SPEAKER_STANDARD_STEREO("lspeaker", "rspeaker") + MCFG_SOUND_ADD(AY1_TAG, AY8913, 1022727) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "lspeaker", 1.0) + MCFG_SOUND_ADD(AY2_TAG, AY8913, 1022727) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "rspeaker", 1.0) +MACHINE_CONFIG_END + +MACHINE_CONFIG_FRAGMENT( phasor ) + MCFG_DEVICE_ADD(VIA1_TAG, VIA6522, 1022727) + MCFG_VIA6522_WRITEPA_HANDLER(WRITE8(a2bus_ayboard_device, via1_out_a)) + MCFG_VIA6522_WRITEPB_HANDLER(WRITE8(a2bus_ayboard_device, via1_out_b)) + MCFG_VIA6522_IRQ_HANDLER(WRITELINE(a2bus_ayboard_device, via1_irq_w)) + + MCFG_DEVICE_ADD(VIA2_TAG, VIA6522, 1022727) + MCFG_VIA6522_WRITEPA_HANDLER(WRITE8(a2bus_ayboard_device, via2_out_a)) + MCFG_VIA6522_WRITEPB_HANDLER(WRITE8(a2bus_ayboard_device, via2_out_b)) + MCFG_VIA6522_IRQ_HANDLER(WRITELINE(a2bus_ayboard_device, via2_irq_w)) + + MCFG_SPEAKER_STANDARD_STEREO("lspeaker", "rspeaker") + MCFG_SPEAKER_STANDARD_STEREO("lspeaker2", "rspeaker2") + MCFG_SOUND_ADD(AY1_TAG, AY8913, 1022727) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "lspeaker", 1.0) + MCFG_SOUND_ADD(AY2_TAG, AY8913, 1022727) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "lspeaker2", 1.0) + MCFG_SOUND_ADD(AY3_TAG, AY8913, 1022727) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "rspeaker", 1.0) + MCFG_SOUND_ADD(AY4_TAG, AY8913, 1022727) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "rspeaker2", 1.0) +MACHINE_CONFIG_END + +MACHINE_CONFIG_FRAGMENT( echoplus ) + MCFG_DEVICE_ADD(VIA1_TAG, VIA6522, 1022727) + MCFG_VIA6522_WRITEPA_HANDLER(WRITE8(a2bus_ayboard_device, via1_out_a)) + MCFG_VIA6522_WRITEPB_HANDLER(WRITE8(a2bus_ayboard_device, via1_out_b)) + MCFG_VIA6522_IRQ_HANDLER(WRITELINE(a2bus_ayboard_device, via1_irq_w)) + + MCFG_DEVICE_ADD(VIA2_TAG, VIA6522, 1022727) + MCFG_VIA6522_WRITEPA_HANDLER(WRITE8(a2bus_ayboard_device, via2_out_a)) + MCFG_VIA6522_WRITEPB_HANDLER(WRITE8(a2bus_ayboard_device, via2_out_b)) + MCFG_VIA6522_IRQ_HANDLER(WRITELINE(a2bus_ayboard_device, via2_irq_w)) + + MCFG_SPEAKER_STANDARD_STEREO("lspeaker", "rspeaker") + MCFG_SOUND_ADD(AY1_TAG, AY8913, 1022727) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "lspeaker", 1.0) + MCFG_SOUND_ADD(AY2_TAG, AY8913, 1022727) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "rspeaker", 1.0) + + MCFG_SPEAKER_STANDARD_MONO("echosp") + MCFG_SOUND_ADD(E2P_TMS_TAG, TMS5220, 640000) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "echosp", 1.0) +MACHINE_CONFIG_END + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor a2bus_ayboard_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( mockingboard ); +} + +machine_config_constructor a2bus_phasor_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( phasor ); +} + +machine_config_constructor a2bus_echoplus_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( echoplus ); +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +a2bus_ayboard_device::a2bus_ayboard_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_a2bus_card_interface(mconfig, *this), + m_via1(*this, VIA1_TAG), + m_via2(*this, VIA2_TAG), + m_ay1(*this, AY1_TAG), + m_ay2(*this, AY2_TAG), + m_ay3(*this, AY3_TAG), + m_ay4(*this, AY4_TAG) +{ +} + +a2bus_mockingboard_device::a2bus_mockingboard_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + a2bus_ayboard_device(mconfig, A2BUS_MOCKINGBOARD, "Sweet Micro Systems Mockingboard", tag, owner, clock, "a2mockbd", __FILE__) +{ + m_isPhasor = false; + m_PhasorNative = false; +} + +a2bus_phasor_device::a2bus_phasor_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + a2bus_ayboard_device(mconfig, A2BUS_PHASOR, "Applied Engineering Phasor", tag, owner, clock, "a2phasor", __FILE__) +{ + m_isPhasor = true; + m_PhasorNative = false; +} + +a2bus_echoplus_device::a2bus_echoplus_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + a2bus_ayboard_device(mconfig, A2BUS_ECHOPLUS, "Street Electronics Echo Plus", tag, owner, clock, "a2echop", __FILE__), + m_tms(*this, E2P_TMS_TAG) +{ + m_isPhasor = false; + m_PhasorNative = false; +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void a2bus_ayboard_device::device_start() +{ + // set_a2bus_device makes m_slot valid + set_a2bus_device(); + + save_item(NAME(m_porta1)); + save_item(NAME(m_porta2)); +} + +void a2bus_ayboard_device::device_reset() +{ + m_porta1 = m_porta2 = 0; +} + +/*------------------------------------------------- + read_cnxx - called for reads from this card's cnxx space +-------------------------------------------------*/ + +UINT8 a2bus_ayboard_device::read_cnxx(address_space &space, UINT8 offset) +{ +// printf("Mockingboard(%d): read @ Cn%02X (PC=%x)\n", m_slot, offset, space.device().safe_pc()); + if (m_isPhasor) + { + UINT8 retVal = 0; + int viaSel; + + if (m_PhasorNative) + { + viaSel = ((offset & 0x80)>> 6) | ((offset & 0x10)>> 4); + } + else + { + viaSel = (offset & 0x80) ? 2 : 1; + } + + if ((offset <= 0x20) || (offset >= 0x80 && offset <= 0xa0)) + { + if (viaSel & 1) + { + retVal |= m_via1->read(space, offset & 0xf); + } + + if (viaSel & 2) + { + retVal |= m_via2->read(space, offset & 0xf); + } + } + + return retVal; + } + else + { + if (offset <= 0x10) + { + return m_via1->read(space, offset & 0xf); + } + else if (offset >= 0x80 && offset <= 0x90) + { + return m_via2->read(space, offset & 0xf); + } + } + + return 0; +} + +/*------------------------------------------------- + write_cnxx - called for writes to this card's c0nx space +-------------------------------------------------*/ + +void a2bus_ayboard_device::write_cnxx(address_space &space, UINT8 offset, UINT8 data) +{ + if (m_isPhasor) + { + if ((offset <= 0x20) || (offset >= 0x80 && offset <= 0xa0)) + { + int viaSel; + + if (m_PhasorNative) + { + viaSel = ((offset & 0x80)>> 6) | ((offset & 0x10)>> 4); + } + else + { + viaSel = (offset & 0x80) ? 2 : 1; + } + +// printf("Phasor(%d): write %02x to Cn%02X (PC=%x) (native %d viaSel %d)\n", m_slot, data, offset, space.device().safe_pc(), m_PhasorNative ? 1 : 0, viaSel); + + if (viaSel & 1) + { + m_via1->write(space, offset&0xf, data); + } + if (viaSel & 2) + { + m_via2->write(space, offset&0xf, data); + } + } + } + else + { + if (offset <= 0x10) + { + m_via1->write(space, offset & 0xf, data); + } + else if (offset >= 0x80 && offset <= 0x90) + { + m_via2->write(space, offset & 0xf, data); + } + else + { + printf("Mockingboard(%d): unk write %02x to Cn%02X (PC=%x)\n", m_slot, data, offset, space.device().safe_pc()); + } + } +} + + +WRITE_LINE_MEMBER( a2bus_ayboard_device::via1_irq_w ) +{ + if (state) + { + raise_slot_irq(); + } + else + { + lower_slot_irq(); + } +} + +WRITE_LINE_MEMBER( a2bus_ayboard_device::via2_irq_w ) +{ + if (state) + { + raise_slot_irq(); + } + else + { + lower_slot_irq(); + } +} + +WRITE8_MEMBER( a2bus_ayboard_device::via1_out_a ) +{ + m_porta1 = data; +} + +WRITE8_MEMBER( a2bus_ayboard_device::via1_out_b ) +{ + if (!(data & 4)) + { + m_ay1->reset_w(space, 0, 0); + if (m_isPhasor && m_PhasorNative) + { + m_ay2->reset_w(space, 0, 0); + } + } + else + { + if (!m_isPhasor) + { + switch (data & 3) + { + case 0: // BDIR=0, BC1=0 (inactive) + break; + + case 1: // BDIR=0, BC1=1 (read PSG) + m_porta1 = m_ay1->data_r(space, 0); + break; + + case 2: // BDIR=1, BC1=0 (write PSG) + m_ay1->data_w(space, 0, m_porta1); + break; + + case 3: // BDIR=1, BC1=1 (latch) + m_ay1->address_w(space, 0, m_porta1); + break; + } + } + else + { + int chipSel; + + if (m_PhasorNative) + { + chipSel = (~(data >> 3) & 3); + } + else + { + chipSel = 1; + } + +// printf("Phasor: %02x to AY1/2 CS %02x (BDIR/BC1 %02x, data %02x)\n", m_porta1, chipSel, data & 3, data); + switch (data & 3) + { + case 0: // BDIR=0, BC1=0 (inactive) + break; + + case 1: // BDIR=0, BC1=1 (read PSG) + if (chipSel & 1) + { + m_porta1 = m_ay1->data_r(space, 0); + } + if (chipSel & 2) + { + m_porta1 = m_ay2->data_r(space, 0); + } + break; + + case 2: // BDIR=1, BC1=0 (write PSG) + if (chipSel & 1) + { + m_ay1->data_w(space, 0, m_porta1); + } + if (chipSel & 2) + { + m_ay2->data_w(space, 0, m_porta1); + } + break; + + case 3: // BDIR=1, BC1=1 (latch) + if (chipSel & 1) + { + m_ay1->address_w(space, 0, m_porta1); + } + if (chipSel & 2) + { + m_ay2->address_w(space, 0, m_porta1); + } + break; + } + } + } +} + +WRITE8_MEMBER( a2bus_ayboard_device::via2_out_a ) +{ + m_porta2 = data; +} + +WRITE8_MEMBER( a2bus_ayboard_device::via2_out_b ) +{ + if (!(data & 4)) + { + if (m_isPhasor && m_PhasorNative) + { + m_ay3->reset_w(space, 0, 0); + m_ay4->reset_w(space, 0, 0); + } + else + { + m_ay2->reset_w(space, 0, 0); + } + } + else + { + if (!m_isPhasor) + { + switch (data & 3) + { + case 0: // BDIR=0, BC1=0 (inactive) + break; + + case 1: // BDIR=0, BC1=1 (read PSG) + m_porta2 = m_ay2->data_r(space, 0); + break; + + case 2: // BDIR=1, BC1=0 (write PSG) + m_ay2->data_w(space, 0, m_porta2); + break; + + case 3: // BDIR=1, BC1=1 (latch) + m_ay2->address_w(space, 0, m_porta2); + break; + } + } + else + { + int chipSel; + + if (m_PhasorNative) + { + chipSel = (~(data >> 3) & 3); + } + else + { + chipSel = 1; + } + +// printf("Phasor: %02x to AY3/4 CS %02x (BDIR/BC1 %02x, data %02x)\n", m_porta2, chipSel, data & 3, data); + switch (data & 3) + { + case 0: // BDIR=0, BC1=0 (inactive) + break; + + case 1: // BDIR=0, BC1=1 (read PSG) + if (chipSel & 1) + { + m_porta2 = m_ay3->data_r(space, 0); + } + if (chipSel & 2) + { + m_porta2 = m_ay4->data_r(space, 0); + } + break; + + case 2: // BDIR=1, BC1=0 (write PSG) + if (chipSel & 1) + { + m_ay3->data_w(space, 0, m_porta2); + } + if (chipSel & 2) + { + m_ay4->data_w(space, 0, m_porta2); + } + break; + + case 3: // BDIR=1, BC1=1 (latch) + if (chipSel & 1) + { + m_ay3->address_w(space, 0, m_porta2); + } + if (chipSel & 2) + { + m_ay4->address_w(space, 0, m_porta2); + } + break; + } + } + } +} + +UINT8 a2bus_ayboard_device::read_c0nx(address_space &space, UINT8 offset) +{ + if (m_isPhasor) + { + m_PhasorNative = (offset & 1) ? true : false; + } + + return 0xff; +} + +void a2bus_ayboard_device::write_c0nx(address_space &space, UINT8 offset, UINT8 data) +{ + if (m_isPhasor) + { + m_PhasorNative = (offset & 1) ? true : false; + } +} + +UINT8 a2bus_echoplus_device::read_c0nx(address_space &space, UINT8 offset) +{ + switch (offset) + { + case 0: + return 0x1f | m_tms->status_r(space, 0); + } + + return 0; +} + +void a2bus_echoplus_device::write_c0nx(address_space &space, UINT8 offset, UINT8 data) +{ + switch (offset) + { + case 0: + m_tms->data_w(space, offset, data); + break; + } +} diff --git a/src/devices/bus/a2bus/a2mockingboard.h b/src/devices/bus/a2bus/a2mockingboard.h new file mode 100644 index 00000000000..eb297bc9605 --- /dev/null +++ b/src/devices/bus/a2bus/a2mockingboard.h @@ -0,0 +1,97 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/********************************************************************* + + a2mockingboard.h + + Sweet Micro Systems Mockingboard and compatibles + +*********************************************************************/ + +#ifndef __A2BUS_MOCKINGBOARD__ +#define __A2BUS_MOCKINGBOARD__ + +#include "emu.h" +#include "a2bus.h" +#include "machine/6522via.h" +#include "sound/ay8910.h" +#include "sound/tms5220.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class a2bus_ayboard_device: + public device_t, + public device_a2bus_card_interface +{ +public: + // construction/destruction + a2bus_ayboard_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + + DECLARE_WRITE_LINE_MEMBER( via1_irq_w ); + DECLARE_WRITE_LINE_MEMBER( via2_irq_w ); + DECLARE_WRITE8_MEMBER(via1_out_a); + DECLARE_WRITE8_MEMBER(via1_out_b); + DECLARE_WRITE8_MEMBER(via2_out_a); + DECLARE_WRITE8_MEMBER(via2_out_b); + +protected: + virtual void device_start(); + virtual void device_reset(); + + // overrides of standard a2bus slot functions + virtual UINT8 read_c0nx(address_space &space, UINT8 offset); + virtual void write_c0nx(address_space &space, UINT8 offset, UINT8 data); + virtual UINT8 read_cnxx(address_space &space, UINT8 offset); + virtual void write_cnxx(address_space &space, UINT8 offset, UINT8 data); + + required_device m_via1; + required_device m_via2; + required_device m_ay1; + required_device m_ay2; + optional_device m_ay3; + optional_device m_ay4; + + bool m_isPhasor, m_PhasorNative; + +private: + UINT8 m_porta1, m_porta2; +}; + +class a2bus_mockingboard_device : public a2bus_ayboard_device +{ +public: + a2bus_mockingboard_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class a2bus_phasor_device : public a2bus_ayboard_device +{ +public: + a2bus_phasor_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual machine_config_constructor device_mconfig_additions() const; +}; + +class a2bus_echoplus_device : public a2bus_ayboard_device +{ +public: + a2bus_echoplus_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual UINT8 read_c0nx(address_space &space, UINT8 offset); + virtual void write_c0nx(address_space &space, UINT8 offset, UINT8 data); + + required_device m_tms; + + virtual machine_config_constructor device_mconfig_additions() const; +}; + +// device type definition +extern const device_type A2BUS_MOCKINGBOARD; +extern const device_type A2BUS_PHASOR; +extern const device_type A2BUS_ECHOPLUS; + +#endif /* __A2BUS_MOCKINGBOARD__ */ diff --git a/src/devices/bus/a2bus/a2pic.c b/src/devices/bus/a2bus/a2pic.c new file mode 100644 index 00000000000..daede92b119 --- /dev/null +++ b/src/devices/bus/a2bus/a2pic.c @@ -0,0 +1,290 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/********************************************************************* + + a2pic.c + + Apple II Parallel Interface Card (670-0021) + +*********************************************************************/ + +#include "a2pic.h" + +/*************************************************************************** + PARAMETERS +***************************************************************************/ + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type A2BUS_PIC = &device_creator; + +#define PIC_ROM_REGION "pic_rom" +#define PIC_CENTRONICS_TAG "pic_ctx" + +MACHINE_CONFIG_FRAGMENT( pic ) + MCFG_CENTRONICS_ADD(PIC_CENTRONICS_TAG, centronics_devices, "printer") + MCFG_CENTRONICS_DATA_INPUT_BUFFER("ctx_data_in") + MCFG_CENTRONICS_ACK_HANDLER(WRITELINE(a2bus_pic_device, ack_w)) + + MCFG_DEVICE_ADD("ctx_data_in", INPUT_BUFFER, 0) + MCFG_CENTRONICS_OUTPUT_LATCH_ADD("ctx_data_out", PIC_CENTRONICS_TAG) +MACHINE_CONFIG_END + +ROM_START( pic ) + ROM_REGION(0x000200, PIC_ROM_REGION, 0) + ROM_LOAD( "341-0057.bin", 0x000000, 0x000200, CRC(0d2d84ee) SHA1(bfc5b863d37e59875a6159528eb0f2b6082063b5) ) +ROM_END + +static INPUT_PORTS_START( pic ) + PORT_START("DSW1") + PORT_DIPNAME( 0x07, 0x00, "Strobe length (SW1-3)" ) + PORT_DIPSETTING( 0x00, "1 microsecond" ) + PORT_DIPSETTING( 0x01, "3 microseconds" ) + PORT_DIPSETTING( 0x02, "5 microseconds" ) + PORT_DIPSETTING( 0x03, "7 microseconds" ) + PORT_DIPSETTING( 0x04, "9 microseconds" ) + PORT_DIPSETTING( 0x05, "11 microseconds" ) + PORT_DIPSETTING( 0x06, "13 microseconds" ) + PORT_DIPSETTING( 0x07, "15 microseconds" ) + + PORT_DIPNAME( 0x08, 0x00, "Strobe polarity (SW4)" ) + PORT_DIPSETTING( 0x00, "Positive" ) + PORT_DIPSETTING( 0x08, "Negative" ) + + PORT_DIPNAME( 0x10, 0x00, "Acknowledge polarity (SW5)" ) + PORT_DIPSETTING( 0x00, "Positive" ) + PORT_DIPSETTING( 0x10, "Negative" ) + + PORT_DIPNAME( 0x20, 0x20, "Firmware (SW6)" ) + PORT_DIPSETTING( 0x00, "Parallel Printer (341-0005)" ) + PORT_DIPSETTING( 0x20, "Centronics (341-0019)" ) + + PORT_DIPNAME( 0x40, 0x00, "Use interrupts (SW7)" ) + PORT_DIPSETTING( 0x00, "Off" ) + PORT_DIPSETTING( 0x40, "On" ) +INPUT_PORTS_END + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor a2bus_pic_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( pic ); +} + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor a2bus_pic_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( pic ); +} + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *a2bus_pic_device::device_rom_region() const +{ + return ROM_NAME( pic ); +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +a2bus_pic_device::a2bus_pic_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, A2BUS_PIC, "Apple Parallel Interface Card", tag, owner, clock, "a2pic", __FILE__), + device_a2bus_card_interface(mconfig, *this), + m_dsw1(*this, "DSW1"), + m_ctx(*this, PIC_CENTRONICS_TAG), + m_ctx_data_in(*this, "ctx_data_in"), + m_ctx_data_out(*this, "ctx_data_out"), + m_started(false) +{ +} + +a2bus_pic_device::a2bus_pic_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_a2bus_card_interface(mconfig, *this), + m_dsw1(*this, "DSW1"), + m_ctx(*this, PIC_CENTRONICS_TAG), + m_ctx_data_in(*this, "ctx_data_in"), + m_ctx_data_out(*this, "ctx_data_out"), + m_started(false) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void a2bus_pic_device::device_start() +{ + // set_a2bus_device makes m_slot valid + set_a2bus_device(); + + m_rom = device().machine().root_device().memregion(this->subtag(PIC_ROM_REGION).c_str())->base(); + + m_timer = timer_alloc(0, NULL); + m_timer->adjust(attotime::never); + + save_item(NAME(m_ack)); + save_item(NAME(m_irqenable)); + save_item(NAME(m_autostrobe)); +} + +void a2bus_pic_device::device_reset() +{ + m_started = true; + m_ack = 0; + m_irqenable = false; + m_autostrobe = false; + lower_slot_irq(); + m_timer->adjust(attotime::never); + + // set initial state of the strobe line depending on the dipswitch + clear_strobe(); +} + +void a2bus_pic_device::device_timer(emu_timer &timer, device_timer_id tid, int param, void *ptr) +{ + clear_strobe(); + + m_timer->adjust(attotime::never); +} + +/*------------------------------------------------- + read_cnxx - called for reads from this card's cnxx space +-------------------------------------------------*/ + +UINT8 a2bus_pic_device::read_cnxx(address_space &space, UINT8 offset) +{ + m_autostrobe = true; + + if (m_dsw1->read() & 0x20) + { + return m_rom[(offset&0xff) | 0x100]; + } + + return m_rom[(offset&0xff)]; +} + +/*------------------------------------------------- + read_c0nx - called for reads from this card's c0nx space +-------------------------------------------------*/ + +UINT8 a2bus_pic_device::read_c0nx(address_space &space, UINT8 offset) +{ + switch (offset) + { + case 3: + return m_ctx_data_in->read(); + + case 4: + return m_ack; + + case 6: // does reading this really work? + m_irqenable = true; + break; + + case 7: + m_irqenable = false; + m_autostrobe = false; + lower_slot_irq(); + break; + + } + + return 0; +} + +/*------------------------------------------------- + write_c0nx - called for writes to this card's c0nx space +-------------------------------------------------*/ + +void a2bus_pic_device::write_c0nx(address_space &space, UINT8 offset, UINT8 data) +{ + switch (offset) + { + case 0: // set data out and send a strobe + m_ctx_data_out->write(data); + + if (m_autostrobe) + { + start_strobe(); + } + break; + + case 2: // send a strobe + start_strobe(); + break; + + case 6: // enable interrupt on ACK + m_irqenable = true; + break; + + case 7: // disable and acknowledge IRQ, reset ACK flip-flop, disable autostrobe + m_irqenable = false; + m_autostrobe = false; + lower_slot_irq(); + break; + } +} + +WRITE_LINE_MEMBER( a2bus_pic_device::ack_w ) +{ + if (m_started) + { + UINT8 dsw1 = m_dsw1->read(); + + if (dsw1 & 0x10) // negative polarity + { + m_ack = (state == ASSERT_LINE) ? 0x00 : 0x80; + } + else + { + m_ack = (state == ASSERT_LINE) ? 0x80 : 0x00; + } + + m_ack |= 0x40; // set ACK flip-flop + + if ((dsw1 & 0x40) && (m_irqenable)) + { + raise_slot_irq(); + } + } +} + +void a2bus_pic_device::start_strobe() +{ + int usec = ((m_dsw1->read() & 7) * 2) + 1; // strobe length in microseconds + + if (m_dsw1->read() & 0x8) // negative polarity + { + m_ctx->write_strobe(CLEAR_LINE); + } + else + { + m_ctx->write_strobe(ASSERT_LINE); + } + + m_timer->adjust(attotime::from_usec(usec), 0, attotime::never); +} + +void a2bus_pic_device::clear_strobe() +{ + if (m_dsw1->read() & 0x8) // negative polarity + { + m_ctx->write_strobe(ASSERT_LINE); + } + else + { + m_ctx->write_strobe(CLEAR_LINE); + } +} diff --git a/src/devices/bus/a2bus/a2pic.h b/src/devices/bus/a2bus/a2pic.h new file mode 100644 index 00000000000..172ec603502 --- /dev/null +++ b/src/devices/bus/a2bus/a2pic.h @@ -0,0 +1,67 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/********************************************************************* + + a2pic.h + + Apple II Parallel Interface Card + +*********************************************************************/ + +#ifndef __A2BUS_PIC__ +#define __A2BUS_PIC__ + +#include "a2bus.h" +#include "bus/centronics/ctronics.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class a2bus_pic_device: + public device_t, + public device_a2bus_card_interface +{ +public: + // construction/destruction + a2bus_pic_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + a2bus_pic_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual const rom_entry *device_rom_region() const; + virtual ioport_constructor device_input_ports() const; + + required_ioport m_dsw1; + + DECLARE_WRITE_LINE_MEMBER( ack_w ); + +protected: + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + virtual UINT8 read_c0nx(address_space &space, UINT8 offset); + virtual void write_c0nx(address_space &space, UINT8 offset, UINT8 data); + virtual UINT8 read_cnxx(address_space &space, UINT8 offset); + + required_device m_ctx; + required_device m_ctx_data_in; + required_device m_ctx_data_out; + + void start_strobe(); + void clear_strobe(); + +private: + UINT8 *m_rom; + bool m_started; + UINT8 m_ack; + bool m_irqenable; + bool m_autostrobe; + emu_timer *m_timer; +}; + +// device type definition +extern const device_type A2BUS_PIC; + +#endif /* __A2BUS_PIC__ */ diff --git a/src/devices/bus/a2bus/a2sam.c b/src/devices/bus/a2bus/a2sam.c new file mode 100644 index 00000000000..7cdabc64b74 --- /dev/null +++ b/src/devices/bus/a2bus/a2sam.c @@ -0,0 +1,87 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/********************************************************************* + + a2sam.c + + Implementation of the S.A.M. "Software Automated Mouth" card + +*********************************************************************/ + +#include "a2sam.h" +#include "includes/apple2.h" +#include "sound/dac.h" + +/*************************************************************************** + PARAMETERS +***************************************************************************/ + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type A2BUS_SAM = &device_creator; + +#define DAC_TAG "dac" + +MACHINE_CONFIG_FRAGMENT( a2sam ) + MCFG_SPEAKER_STANDARD_MONO("samspkr") + MCFG_SOUND_ADD(DAC_TAG, DAC, 0) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "samspkr", 1.00) +MACHINE_CONFIG_END + +/*************************************************************************** + FUNCTION PROTOTYPES +***************************************************************************/ + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor a2bus_sam_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( a2sam ); +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +a2bus_sam_device::a2bus_sam_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_a2bus_card_interface(mconfig, *this), + m_dac(*this, DAC_TAG) +{ +} + +a2bus_sam_device::a2bus_sam_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, A2BUS_SAM, "Don't Ask Software SAM", tag, owner, clock, "a2sam", __FILE__), + device_a2bus_card_interface(mconfig, *this), + m_dac(*this, DAC_TAG) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void a2bus_sam_device::device_start() +{ + // set_a2bus_device makes m_slot valid + set_a2bus_device(); +} + +void a2bus_sam_device::device_reset() +{ +} + +void a2bus_sam_device::write_c0nx(address_space &space, UINT8 offset, UINT8 data) +{ + m_dac->write_unsigned8(data); +} + +bool a2bus_sam_device::take_c800() +{ + return false; +} diff --git a/src/devices/bus/a2bus/a2sam.h b/src/devices/bus/a2bus/a2sam.h new file mode 100644 index 00000000000..3c2076921ef --- /dev/null +++ b/src/devices/bus/a2bus/a2sam.h @@ -0,0 +1,48 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/********************************************************************* + + a2sam.h + + Implementation of the S.A.M. "Software Automated Mouth" card + +*********************************************************************/ + +#ifndef __A2BUS_SAM__ +#define __A2BUS_SAM__ + +#include "emu.h" +#include "a2bus.h" +#include "sound/dac.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class a2bus_sam_device: + public device_t, + public device_a2bus_card_interface +{ +public: + // construction/destruction + a2bus_sam_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + a2bus_sam_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + + required_device m_dac; + +protected: + virtual void device_start(); + virtual void device_reset(); + + // overrides of standard a2bus slot functions + virtual void write_c0nx(address_space &space, UINT8 offset, UINT8 data); + virtual bool take_c800(); +}; + +// device type definition +extern const device_type A2BUS_SAM; + +#endif /* __A2BUS_SAM__ */ diff --git a/src/devices/bus/a2bus/a2scsi.c b/src/devices/bus/a2bus/a2scsi.c new file mode 100644 index 00000000000..5e9fc865718 --- /dev/null +++ b/src/devices/bus/a2bus/a2scsi.c @@ -0,0 +1,323 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/********************************************************************* + + a2scsi.c + + Implementation of the Apple II SCSI Card + + Schematic at: + http://mirrors.apple2.org.za/Apple%20II%20Documentation%20Project/Interface%20Cards/SCSI%20Controllers/Apple%20II%20SCSI%20Card/Schematics/Rev.%20C%20SCSI%20Schematic%20-%20Updated%202-23-6.jpg + + + Notes: + C0n0-C0n7 = NCR5380 registers in normal order + C0n8 = pseudo-DMA read/write and DACK + C0n9 = DIP switches + C0na = RAM and ROM bank switching + C0nb = reset 5380 + C0nc = set IIgs block mode + C0nd = set pseudo-DMA + C0ne = read DRQ status in bit 7 + + In IIgs block mode, any read from C800-CBFF window fetches + the next byte from the 5380's DMA port. This lets you use the + 65816 MVN/MVP operations to burst-transfer up to 1K at a time. + (Requires a cycle-by-cycle haltable 65816 core; don't install the + GS/OS driver right now to avoid this) + + Pseudo-DMA works similarly to the Mac implementation; use C0n8 + to read/write "DMA" bytes in that mode. + +*********************************************************************/ + +#include "a2scsi.h" +#include "includes/apple2.h" +#include "machine/nscsi_cd.h" +#include "machine/nscsi_hd.h" + +/*************************************************************************** + PARAMETERS +***************************************************************************/ + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type A2BUS_SCSI = &device_creator; + +#define SCSI_ROM_REGION "scsi_rom" +#define SCSI_BUS_TAG "scsibus" +#define SCSI_5380_TAG "scsibus:7:ncr5380" + +static MACHINE_CONFIG_FRAGMENT( ncr5380 ) + MCFG_DEVICE_CLOCK(10000000) + MCFG_NCR5380N_DRQ_HANDLER(DEVWRITELINE("^^", a2bus_scsi_device, drq_w)) +MACHINE_CONFIG_END + +static SLOT_INTERFACE_START( scsi_devices ) + SLOT_INTERFACE("cdrom", NSCSI_CDROM) + SLOT_INTERFACE("harddisk", NSCSI_HARDDISK) + SLOT_INTERFACE_INTERNAL("ncr5380", NCR5380N) +SLOT_INTERFACE_END + +MACHINE_CONFIG_FRAGMENT( scsi ) + MCFG_NSCSI_BUS_ADD(SCSI_BUS_TAG) + MCFG_NSCSI_ADD("scsibus:0", scsi_devices, 0, false) + MCFG_NSCSI_ADD("scsibus:1", scsi_devices, 0, false) + MCFG_NSCSI_ADD("scsibus:2", scsi_devices, 0, false) + MCFG_NSCSI_ADD("scsibus:3", scsi_devices, 0, false) + MCFG_NSCSI_ADD("scsibus:4", scsi_devices, 0, false) + MCFG_NSCSI_ADD("scsibus:5", scsi_devices, 0, false) + MCFG_NSCSI_ADD("scsibus:6", scsi_devices, "harddisk", false) + MCFG_NSCSI_ADD("scsibus:7", scsi_devices, "ncr5380", true) + MCFG_DEVICE_CARD_MACHINE_CONFIG("ncr5380", ncr5380) +MACHINE_CONFIG_END + +ROM_START( scsi ) + ROM_REGION(0x4000, SCSI_ROM_REGION, 0) // this is the Rev. C ROM + ROM_LOAD( "341-0437-a.bin", 0x0000, 0x4000, CRC(5aff85d3) SHA1(451c85c46b92e6ad2ad930f055ccf0fe3049936d) ) +ROM_END + +/*************************************************************************** + FUNCTION PROTOTYPES +***************************************************************************/ + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor a2bus_scsi_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( scsi ); +} + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *a2bus_scsi_device::device_rom_region() const +{ + return ROM_NAME( scsi ); +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +a2bus_scsi_device::a2bus_scsi_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_a2bus_card_interface(mconfig, *this), + m_ncr5380(*this, SCSI_5380_TAG), + m_scsibus(*this, SCSI_BUS_TAG) +{ +} + +a2bus_scsi_device::a2bus_scsi_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, A2BUS_SCSI, "Apple II SCSI Card", tag, owner, clock, "a2scsi", __FILE__), + device_a2bus_card_interface(mconfig, *this), + m_ncr5380(*this, SCSI_5380_TAG), + m_scsibus(*this, SCSI_BUS_TAG) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void a2bus_scsi_device::device_start() +{ + // set_a2bus_device makes m_slot valid + set_a2bus_device(); + + m_rom = device().machine().root_device().memregion(this->subtag(SCSI_ROM_REGION).c_str())->base(); + + memset(m_ram, 0, 8192); + + save_item(NAME(m_ram)); + save_item(NAME(m_rambank)); + save_item(NAME(m_rombank)); + save_item(NAME(m_bank)); + save_item(NAME(m_drq)); + save_item(NAME(m_816block)); +} + +void a2bus_scsi_device::device_reset() +{ + m_rambank = m_rombank = 0; // CLR on 74LS273 at U3E is connected to RES, so these clear on reset + m_816block = false; +} + + +/*------------------------------------------------- + read_c0nx - called for reads from this card's c0nx space +-------------------------------------------------*/ + +UINT8 a2bus_scsi_device::read_c0nx(address_space &space, UINT8 offset) +{ + switch (offset) + { + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: +// printf("Read 5380 @ %x\n", offset); + return m_ncr5380->read(space, offset); + + case 8: // read and DACK + return m_ncr5380->dma_r(); + + case 9: // our SCSI ID (normally 0x80 = 7) + return (1<<7); + + case 0xa: // RAM/ROM bank + return m_bank; + + case 0xe: // DRQ status in bit 7 + return m_drq; + + default: + printf("Read c0n%x (PC=%x)\n", offset, space.device().safe_pc()); + break; + } + + return 0xff; +} + + +/*------------------------------------------------- + write_c0nx - called for writes to this card's c0nx space +-------------------------------------------------*/ + +void a2bus_scsi_device::write_c0nx(address_space &space, UINT8 offset, UINT8 data) +{ + switch (offset) + { + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: +// printf("%02x to 5380 reg %x\n", data, offset); + m_ncr5380->write(space, offset, data); + break; + + case 8: // write and DACK + m_ncr5380->dma_w(data); + break; + + case 0xa: // ROM and RAM banking (74LS273 at U3E) + /* + ROM banking: + (bits EA8-EA13 are all zeroed when /IOSEL is asserted, so CnXX always gets the first page of the ROM) + EA10 = bit 0 + EA11 = bit 1 + EA12 = bit 2 + EA13 = bit 3 (N/C) + + RAM banking: + RA10 = bit 4 + RA11 = bit 5 + RA12 = bit 6 + */ + + m_rambank = ((data>>4) & 0x7) * 0x400; + m_rombank = (data & 0xf) * 0x400; + m_bank = data; +// printf("RAM bank to %x, ROM bank to %x\n", m_rambank, m_rombank); + m_816block = false; // does this reset block mode? + break; + + case 0xb: // reset 5380 +// printf("Resetting SCSI: %02x at %x\n", data, space.device().safe_pc()); + m_ncr5380->reset(); + m_816block = false; + break; + + case 0xc: // set IIgs block mode DMA + printf("%02x to block-mode DMA mode\n", data); + m_816block = true; + break; + + case 0xd: // set Mac-style pseudo-DMA +// printf("%02x to pseudo-DMA mode\n", data); + m_816block = false; + break; + + default: + printf("Write %02x to c0n%x (PC=%x)\n", data, offset, space.device().safe_pc()); + break; + } +} + +/*------------------------------------------------- + read_cnxx - called for reads from this card's cnxx space +-------------------------------------------------*/ + +UINT8 a2bus_scsi_device::read_cnxx(address_space &space, UINT8 offset) +{ + // one slot image at the start of the ROM, it appears + return m_rom[offset]; +} + +void a2bus_scsi_device::write_cnxx(address_space &space, UINT8 offset, UINT8 data) +{ + // there are writes to cn0A, possibly misguided C0nA (bank select?) writes? +// printf("Write %02x to cn%02x (PC=%x)\n", data, offset, space.device().safe_pc()); +} + +/*------------------------------------------------- + read_c800 - called for reads from this card's c800 space +-------------------------------------------------*/ + +UINT8 a2bus_scsi_device::read_c800(address_space &space, UINT16 offset) +{ + // bankswitched RAM at c800-cbff + // bankswitched ROM at cc00-cfff + if (offset < 0x400) + { +// printf("Read RAM at %x = %02x\n", offset+m_rambank, m_ram[offset + m_rambank]); + if (m_816block) + { + return m_ncr5380->dma_r(); + } + + return m_ram[offset + m_rambank]; + } + else + { + return m_rom[(offset-0x400) + m_rombank]; + } +} + +/*------------------------------------------------- + write_c800 - called for writes to this card's c800 space +-------------------------------------------------*/ +void a2bus_scsi_device::write_c800(address_space &space, UINT16 offset, UINT8 data) +{ + if (offset < 0x400) + { +// printf("%02x to RAM at %x\n", data, offset+m_rambank); + if (m_816block) + { + m_ncr5380->dma_w(data); + } + else + { + m_ram[offset + m_rambank] = data; + } + } +} + +WRITE_LINE_MEMBER( a2bus_scsi_device::drq_w ) +{ + m_drq = (state ? 0x80 : 0x00); +} diff --git a/src/devices/bus/a2bus/a2scsi.h b/src/devices/bus/a2bus/a2scsi.h new file mode 100644 index 00000000000..660a6d4c7b0 --- /dev/null +++ b/src/devices/bus/a2bus/a2scsi.h @@ -0,0 +1,64 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/********************************************************************* + + a2scsi.h + + Implementation of the Apple II SCSI Card + +*********************************************************************/ + +#ifndef __A2BUS_SCSI__ +#define __A2BUS_SCSI__ + +#include "emu.h" +#include "a2bus.h" +#include "machine/ncr5380n.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class a2bus_scsi_device: + public device_t, + public device_a2bus_card_interface +{ +public: + // construction/destruction + a2bus_scsi_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + a2bus_scsi_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual const rom_entry *device_rom_region() const; + + required_device m_ncr5380; + required_device m_scsibus; + + DECLARE_WRITE_LINE_MEMBER( drq_w ); + +protected: + virtual void device_start(); + virtual void device_reset(); + + // overrides of standard a2bus slot functions + virtual UINT8 read_c0nx(address_space &space, UINT8 offset); + virtual void write_c0nx(address_space &space, UINT8 offset, UINT8 data); + virtual UINT8 read_cnxx(address_space &space, UINT8 offset); + virtual void write_cnxx(address_space &space, UINT8 offset, UINT8 data); + virtual UINT8 read_c800(address_space &space, UINT16 offset); + virtual void write_c800(address_space &space, UINT16 offset, UINT8 data); + +private: + UINT8 *m_rom; + UINT8 m_ram[8192]; // 8 banks of 1024 bytes + int m_rambank, m_rombank; + UINT8 m_drq; + UINT8 m_bank; + bool m_816block; +}; + +// device type definition +extern const device_type A2BUS_SCSI; + +#endif /* __A2BUS_SCSI__ */ diff --git a/src/devices/bus/a2bus/a2softcard.c b/src/devices/bus/a2bus/a2softcard.c new file mode 100644 index 00000000000..e7fe5cdff95 --- /dev/null +++ b/src/devices/bus/a2bus/a2softcard.c @@ -0,0 +1,184 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/********************************************************************* + + a2softcard.c + + Implementation of the Microsoft SoftCard Z-80 card + +*********************************************************************/ + +#include "a2softcard.h" +#include "includes/apple2.h" +#include "cpu/z80/z80.h" + +/*************************************************************************** + PARAMETERS +***************************************************************************/ + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type A2BUS_SOFTCARD = &device_creator; + +#define Z80_TAG "z80" + +static ADDRESS_MAP_START( z80_mem, AS_PROGRAM, 8, a2bus_softcard_device ) + AM_RANGE(0x0000, 0xffff) AM_READWRITE(dma_r, dma_w) +ADDRESS_MAP_END + +MACHINE_CONFIG_FRAGMENT( a2softcard ) + MCFG_CPU_ADD(Z80_TAG, Z80, 1021800*2) // Z80 runs on double the Apple II's clock + MCFG_CPU_PROGRAM_MAP(z80_mem) +MACHINE_CONFIG_END + +/*************************************************************************** + FUNCTION PROTOTYPES +***************************************************************************/ + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor a2bus_softcard_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( a2softcard ); +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +a2bus_softcard_device::a2bus_softcard_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_a2bus_card_interface(mconfig, *this), + m_z80(*this, Z80_TAG) +{ +} + +a2bus_softcard_device::a2bus_softcard_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, A2BUS_SOFTCARD, "Microsoft SoftCard", tag, owner, clock, "a2softcard", __FILE__), + device_a2bus_card_interface(mconfig, *this), + m_z80(*this, Z80_TAG) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void a2bus_softcard_device::device_start() +{ + // set_a2bus_device makes m_slot valid + set_a2bus_device(); + + save_item(NAME(m_bEnabled)); + save_item(NAME(m_FirstZ80Boot)); +} + +void a2bus_softcard_device::device_reset() +{ + m_bEnabled = false; + + m_FirstZ80Boot = true; + m_z80->set_input_line(INPUT_LINE_HALT, ASSERT_LINE); +} + +void a2bus_softcard_device::write_cnxx(address_space &space, UINT8 offset, UINT8 data) +{ + if (!m_bEnabled) + { + m_z80->set_input_line(INPUT_LINE_HALT, CLEAR_LINE); + set_maincpu_halt(ASSERT_LINE); + + if (m_FirstZ80Boot) + { + m_FirstZ80Boot = false; + m_z80->reset(); + } + + m_bEnabled = true; + } + else + { + m_z80->set_input_line(INPUT_LINE_HALT, ASSERT_LINE); + set_maincpu_halt(CLEAR_LINE); + m_bEnabled = false; + } +} + +READ8_MEMBER( a2bus_softcard_device::dma_r ) +{ + if (m_bEnabled) + { + if (offset <= 0xafff) + { + return slot_dma_read(space, offset+0x1000); + } + else if (offset <= 0xbfff) // LC bank 2 d000-dfff + { + return slot_dma_read(space, (offset&0xfff) + 0xd000); + } + else if (offset <= 0xcfff) // LC e000-efff + { + return slot_dma_read(space, (offset&0xfff) + 0xe000); + } + else if (offset <= 0xdfff) // LC f000-ffff (or ROM?) + { + return slot_dma_read(space, (offset&0xfff) + 0xf000); + } + else if (offset <= 0xefff) // I/O space c000-cfff + { + return slot_dma_read(space, (offset&0xfff) + 0xc000); + } + else // zero page + { + return slot_dma_read(space, offset&0xfff); + } + } + + return 0xff; +} + + +//------------------------------------------------- +// dma_w - +//------------------------------------------------- + +WRITE8_MEMBER( a2bus_softcard_device::dma_w ) +{ + if (m_bEnabled) + { + if (offset <= 0xafff) + { + slot_dma_write(space, offset+0x1000, data); + } + else if (offset <= 0xbfff) // LC bank 2 d000-dfff + { + slot_dma_write(space, (offset&0xfff) + 0xd000, data); + } + else if (offset <= 0xcfff) // LC e000-efff + { + slot_dma_write(space, (offset&0xfff) + 0xe000, data); + } + else if (offset <= 0xdfff) // LC f000-ffff (or ROM?) + { + slot_dma_write(space, (offset&0xfff) + 0xf000, data); + } + else if (offset <= 0xefff) // I/O space c000-cfff + { + slot_dma_write(space, (offset&0xfff) + 0xc000, data); + } + else // zero page + { + slot_dma_write(space, offset&0xfff, data); + } + } +} + +bool a2bus_softcard_device::take_c800() +{ + return false; +} diff --git a/src/devices/bus/a2bus/a2softcard.h b/src/devices/bus/a2bus/a2softcard.h new file mode 100644 index 00000000000..5c1064479e2 --- /dev/null +++ b/src/devices/bus/a2bus/a2softcard.h @@ -0,0 +1,54 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/********************************************************************* + + a2softcard.h + + Implementation of the Microsoft SoftCard Z-80 card + +*********************************************************************/ + +#ifndef __A2BUS_SOFTCARD__ +#define __A2BUS_SOFTCARD__ + +#include "emu.h" +#include "a2bus.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class a2bus_softcard_device: + public device_t, + public device_a2bus_card_interface +{ +public: + // construction/destruction + a2bus_softcard_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + a2bus_softcard_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + + DECLARE_READ8_MEMBER( dma_r ); + DECLARE_WRITE8_MEMBER( dma_w ); + +protected: + virtual void device_start(); + virtual void device_reset(); + + // overrides of standard a2bus slot functions + virtual void write_cnxx(address_space &space, UINT8 offset, UINT8 data); + virtual bool take_c800(); + + required_device m_z80; + +private: + bool m_bEnabled; + bool m_FirstZ80Boot; +}; + +// device type definition +extern const device_type A2BUS_SOFTCARD; + +#endif /* __A2BUS_SOFTCARD__ */ diff --git a/src/devices/bus/a2bus/a2ssc.c b/src/devices/bus/a2bus/a2ssc.c new file mode 100644 index 00000000000..992ae8fa6c0 --- /dev/null +++ b/src/devices/bus/a2bus/a2ssc.c @@ -0,0 +1,244 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/********************************************************************* + + a2ssc.c + + Apple II Super Serial Card + +*********************************************************************/ + +#include "a2ssc.h" +#include "bus/rs232/rs232.h" + + +/*************************************************************************** + PARAMETERS +***************************************************************************/ + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type A2BUS_SSC = &device_creator; + +#define SSC_ROM_REGION "ssc_rom" +#define SSC_ACIA_TAG "ssc_acia" +#define SSC_RS232_TAG "ssc_rs232" + +MACHINE_CONFIG_FRAGMENT( ssc ) + MCFG_DEVICE_ADD(SSC_ACIA_TAG, MOS6551, 0) + MCFG_MOS6551_XTAL(XTAL_1_8432MHz) + MCFG_MOS6551_IRQ_HANDLER(WRITELINE(a2bus_ssc_device, acia_irq_w)) + MCFG_MOS6551_TXD_HANDLER(DEVWRITELINE(SSC_RS232_TAG, rs232_port_device, write_txd)) + + MCFG_RS232_PORT_ADD(SSC_RS232_TAG, default_rs232_devices, NULL) + MCFG_RS232_RXD_HANDLER(DEVWRITELINE(SSC_ACIA_TAG, mos6551_device, write_rxd)) + MCFG_RS232_DCD_HANDLER(DEVWRITELINE(SSC_ACIA_TAG, mos6551_device, write_dcd)) + MCFG_RS232_DSR_HANDLER(DEVWRITELINE(SSC_ACIA_TAG, mos6551_device, write_dsr)) + MCFG_RS232_CTS_HANDLER(DEVWRITELINE(SSC_ACIA_TAG, mos6551_device, write_cts)) +MACHINE_CONFIG_END + +ROM_START( ssc ) + ROM_REGION(0x000800, SSC_ROM_REGION, 0) + ROM_LOAD( "341-0065-a.bin", 0x000000, 0x000800, CRC(b7539d4c) SHA1(6dab633470c6bc4cb3e81d09fda46597caf8ee57) ) +ROM_END + +static INPUT_PORTS_START( ssc ) + PORT_START("DSW1") + PORT_DIPNAME( 0xf0, 0xf0, "Baud rate" ) + PORT_DIPSETTING( 0x00, "Undefined/115200" ) + PORT_DIPSETTING( 0x10, "50" ) + PORT_DIPSETTING( 0x20, "75" ) + PORT_DIPSETTING( 0x30, "110" ) + PORT_DIPSETTING( 0x40, "135" ) + PORT_DIPSETTING( 0x50, "150" ) + PORT_DIPSETTING( 0x60, "300" ) + PORT_DIPSETTING( 0x70, "600" ) + PORT_DIPSETTING( 0x80, "1200" ) + PORT_DIPSETTING( 0x90, "1800" ) + PORT_DIPSETTING( 0xa0, "2400" ) + PORT_DIPSETTING( 0xb0, "3600" ) + PORT_DIPSETTING( 0xc0, "4800" ) + PORT_DIPSETTING( 0xd0, "7200" ) + PORT_DIPSETTING( 0xe0, "9600" ) + PORT_DIPSETTING( 0xf0, "19200" ) + + PORT_DIPNAME( 0x0c, 0x00, "Mode" ) + PORT_DIPSETTING( 0x00, "Communications Mode" ) + PORT_DIPSETTING( 0x04, "SIC P8 Emulation Mode" ) + PORT_DIPSETTING( 0x08, "Printer Mode" ) + PORT_DIPSETTING( 0x0c, "SIC P8A Emulation Mode" ) + + PORT_DIPNAME( 0x01, 0x00, "Clear To Send" ) + PORT_DIPSETTING( 0x00, "Normal Clear To Send" ) + PORT_DIPSETTING( 0x01, "Secondary Clear To Send" ) + + PORT_START("DSW2") + PORT_DIPNAME( 0xc0, 0x00, "Format" ) + PORT_DIPSETTING( 0x00, "8 data, 1 stop") + PORT_DIPSETTING( 0x40, "7 data, 1 stop") + PORT_DIPSETTING( 0x80, "8 data, 2 stop") + PORT_DIPSETTING( 0xc0, "7 data, 2 stop") + + PORT_DIPNAME( 0x30, 0x00, "Parity" ) + PORT_DIPSETTING( 0x00, "None") + PORT_DIPSETTING( 0x10, "Odd") + PORT_DIPSETTING( 0x30, "Even") + + PORT_DIPNAME( 0x08, 0x08, "End of Line" ) + PORT_DIPSETTING( 0x00, "Add LF after CR") + PORT_DIPSETTING( 0x08, "Don't add LF after CR") + + PORT_DIPNAME( 0x04, 0x04, "Interrupts" ) + PORT_DIPSETTING( 0x00, "On") + PORT_DIPSETTING( 0x04, "Off") +INPUT_PORTS_END + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor a2bus_ssc_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( ssc ); +} + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor a2bus_ssc_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( ssc ); +} + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *a2bus_ssc_device::device_rom_region() const +{ + return ROM_NAME( ssc ); +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +a2bus_ssc_device::a2bus_ssc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, A2BUS_SSC, "Apple Super Serial Card", tag, owner, clock, "a2ssc", __FILE__), + device_a2bus_card_interface(mconfig, *this), + m_dsw1(*this, "DSW1"), + m_dsw2(*this, "DSW2"), + m_acia(*this, SSC_ACIA_TAG), + m_started(false) +{ +} + +a2bus_ssc_device::a2bus_ssc_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_a2bus_card_interface(mconfig, *this), + m_dsw1(*this, "DSW1"), + m_dsw2(*this, "DSW2"), + m_acia(*this, SSC_ACIA_TAG), + m_started(false) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void a2bus_ssc_device::device_start() +{ + // set_a2bus_device makes m_slot valid + set_a2bus_device(); + + m_rom = device().machine().root_device().memregion(this->subtag(SSC_ROM_REGION).c_str())->base(); +} + +void a2bus_ssc_device::device_reset() +{ + m_started = true; +} + +/*------------------------------------------------- + read_cnxx - called for reads from this card's cnxx space +-------------------------------------------------*/ + +UINT8 a2bus_ssc_device::read_cnxx(address_space &space, UINT8 offset) +{ + return m_rom[(offset&0xff)+0x700]; +} + +/*------------------------------------------------- + read_c800 - called for reads from this card's c800 space +-------------------------------------------------*/ + +UINT8 a2bus_ssc_device::read_c800(address_space &space, UINT16 offset) +{ + return m_rom[offset]; +} + +/*------------------------------------------------- + read_c0nx - called for reads from this card's c0nx space +-------------------------------------------------*/ + +UINT8 a2bus_ssc_device::read_c0nx(address_space &space, UINT8 offset) +{ + // dips at C0n1/C0n2, ACIA at C0n8/9/A/B + + switch (offset) + { + case 1: + return m_dsw1->read(); + case 2: + return m_dsw2->read(); + + case 8: + case 9: + case 0xa: + case 0xb: + return m_acia->read(space, offset-8); + + } + + return 0; +} + +/*------------------------------------------------- + write_c0nx - called for writes to this card's c0nx space +-------------------------------------------------*/ + +void a2bus_ssc_device::write_c0nx(address_space &space, UINT8 offset, UINT8 data) +{ + switch (offset) + { + case 8: + case 9: + case 0xa: + case 0xb: + m_acia->write(space, offset-8, data); + break; + } +} + +WRITE_LINE_MEMBER( a2bus_ssc_device::acia_irq_w ) +{ + if (m_started) + { + if (!(m_dsw2->read() & 4)) + { + if (state) + { + raise_slot_irq(); + } + else + { + lower_slot_irq(); + } + } + } +} diff --git a/src/devices/bus/a2bus/a2ssc.h b/src/devices/bus/a2bus/a2ssc.h new file mode 100644 index 00000000000..8a19b0f49d2 --- /dev/null +++ b/src/devices/bus/a2bus/a2ssc.h @@ -0,0 +1,58 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/********************************************************************* + + a2ssc.h + + Apple II Super Serial Card + +*********************************************************************/ + +#ifndef __A2BUS_SSC__ +#define __A2BUS_SSC__ + +#include "a2bus.h" +#include "machine/mos6551.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class a2bus_ssc_device: + public device_t, + public device_a2bus_card_interface +{ +public: + // construction/destruction + a2bus_ssc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + a2bus_ssc_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual const rom_entry *device_rom_region() const; + virtual ioport_constructor device_input_ports() const; + + required_ioport m_dsw1, m_dsw2; + + DECLARE_WRITE_LINE_MEMBER( acia_irq_w ); + +protected: + virtual void device_start(); + virtual void device_reset(); + + virtual UINT8 read_c0nx(address_space &space, UINT8 offset); + virtual void write_c0nx(address_space &space, UINT8 offset, UINT8 data); + virtual UINT8 read_cnxx(address_space &space, UINT8 offset); + virtual UINT8 read_c800(address_space &space, UINT16 offset); + + required_device m_acia; + +private: + UINT8 *m_rom; + bool m_started; +}; + +// device type definition +extern const device_type A2BUS_SSC; + +#endif /* __A2BUS_SSC__ */ diff --git a/src/devices/bus/a2bus/a2swyft.c b/src/devices/bus/a2bus/a2swyft.c new file mode 100644 index 00000000000..38be337e8ba --- /dev/null +++ b/src/devices/bus/a2bus/a2swyft.c @@ -0,0 +1,149 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/********************************************************************* + + a2swyft.c + + Implementation of the IAI SwyftCard + +*********************************************************************/ + +#include "emu.h" +#include "includes/apple2.h" +#include "a2swyft.h" + + +/*************************************************************************** + PARAMETERS +***************************************************************************/ + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type A2BUS_SWYFT = &device_creator; + +#define SWYFT_ROM_REGION "swyft_rom" + +ROM_START( swyft ) + ROM_REGION(0x4000, SWYFT_ROM_REGION, 0) + ROM_LOAD( "840-003a.bin", 0x000000, 0x004000, CRC(5d6673e9) SHA1(1554bd03c536789f0ff7d1ef6c992265e311935d) ) + ROM_REGION(0x1000, "pal16r4", 0) + ROM_LOAD( "swyft_pal16r4.jed", 0x0000, 0x08EF, CRC(462a6938) SHA1(38be885539cf91423a246378c411ac8b2f150ec6) ) // swyft3.pal derived by D. Elvey, works as a replacement pal (original is protected?) +ROM_END + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *a2bus_swyft_device::device_rom_region() const +{ + return ROM_NAME( swyft ); +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +a2bus_swyft_device::a2bus_swyft_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, A2BUS_SWYFT, "IAI SwyftCard", tag, owner, clock, "a2swyft", __FILE__), + device_a2bus_card_interface(mconfig, *this) +{ +} + +a2bus_swyft_device::a2bus_swyft_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_a2bus_card_interface(mconfig, *this) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void a2bus_swyft_device::device_start() +{ + // set_a2bus_device makes m_slot valid + set_a2bus_device(); + + m_rom = device().machine().root_device().memregion(this->subtag(SWYFT_ROM_REGION).c_str())->base(); + + save_item(NAME(m_rombank)); +} + +void a2bus_swyft_device::device_reset() +{ + m_rombank = 0; + + m_inh_state = INH_READ; // read-enable the ROM + recalc_slot_inh(); +} + +UINT8 a2bus_swyft_device::read_c0nx(address_space &space, UINT8 offset) +{ + switch (offset) + { + case 0: + m_rombank = 0; + m_inh_state = INH_READ; + recalc_slot_inh(); + break; + + case 1: + m_rombank = 0; + m_inh_state = INH_NONE; + recalc_slot_inh(); + break; + + case 2: + m_rombank = 0x1000; + m_inh_state = INH_READ; + recalc_slot_inh(); + break; + } + + return 0xff; +} + +void a2bus_swyft_device::write_c0nx(address_space &space, UINT8 offset, UINT8 data) +{ + switch (offset) + { + case 0: + m_rombank = 0; + m_inh_state = INH_READ; + recalc_slot_inh(); + break; + + case 1: + m_rombank = 0; + m_inh_state = INH_NONE; + recalc_slot_inh(); + break; + + case 2: + m_rombank = 0x1000; + m_inh_state = INH_READ; + recalc_slot_inh(); + break; + } +} + +UINT8 a2bus_swyft_device::read_inh_rom(address_space &space, UINT16 offset) +{ + offset -= 0xd000; + + if (offset < 0x1000) // banked area d000-dfff + { + return m_rom[offset + m_rombank]; + } + else // fixed area e000-ffff + { + return m_rom[offset - 0x1000 + 0x2000]; + } +} + +int a2bus_swyft_device::inh_type() +{ + return m_inh_state; +} diff --git a/src/devices/bus/a2bus/a2swyft.h b/src/devices/bus/a2bus/a2swyft.h new file mode 100644 index 00000000000..a7903f29de7 --- /dev/null +++ b/src/devices/bus/a2bus/a2swyft.h @@ -0,0 +1,52 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/********************************************************************* + + a2swyft.h + + IAI SwyftCard + +*********************************************************************/ + +#ifndef __A2BUS_SWYFT__ +#define __A2BUS_SWYFT__ + +#include "emu.h" +#include "a2bus.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class a2bus_swyft_device: + public device_t, + public device_a2bus_card_interface +{ +public: + // construction/destruction + a2bus_swyft_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + a2bus_swyft_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + virtual const rom_entry *device_rom_region() const; + +protected: + virtual void device_start(); + virtual void device_reset(); + + virtual UINT8 read_c0nx(address_space &space, UINT8 offset); + virtual void write_c0nx(address_space &space, UINT8 offset, UINT8 data); + virtual UINT8 read_inh_rom(address_space &space, UINT16 offset); + virtual UINT16 inh_start() { return 0xd000; } + virtual UINT16 inh_end() { return 0xffff; } + virtual int inh_type(); + +private: + UINT8 *m_rom; + int m_rombank; + int m_inh_state; +}; + +// device type definition +extern const device_type A2BUS_SWYFT; + +#endif /* __A2BUS_SWYFT__ */ diff --git a/src/devices/bus/a2bus/a2themill.c b/src/devices/bus/a2bus/a2themill.c new file mode 100644 index 00000000000..4ea020ae434 --- /dev/null +++ b/src/devices/bus/a2bus/a2themill.c @@ -0,0 +1,333 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/********************************************************************* + + a2themill.c + + Implementation of the Stellation Two The Mill 6809 card + + The OS9 add-on changes the address mapping as follows: + 6809 0x0000-0xafff -> 6502 0x1000-0xbfff + 6809 0xb000-0xdfff -> 6502 0xd000-0xffff + 6809 0xe000-0xefff -> 6502 0xc000-0xcfff + 6809 0xf000-0xffff -> 6502 0x0000-0x0fff + + (reference: http://mirrors.apple2.org.za/ground.icaen.uiowa.edu/MiscInfo/Hardware/mill.6809 ) + + ProDOS "Stellation The Mill Disk.po" requires Mill in slot 2; boot + the disc and type "-DEMO1" and press Enter to launch the simple demo. + + The OS9 disk image available around the internet seems to be bad - the + 6809 boot vector is 0x4144 which maps to 6502 0x5144 and there's all + zeros from 6502 1000-8fff. There is valid 6809 code from 9000-BFFF + at the point where it wants to boot the 6809, but I don't know what + is supposed to be the entry point. + +*********************************************************************/ + +#include "a2themill.h" +#include "includes/apple2.h" +#include "cpu/m6809/m6809.h" + +/*************************************************************************** + PARAMETERS +***************************************************************************/ + +#define MILL_VERBOSE (0) + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type A2BUS_THEMILL = &device_creator; + +#define M6809_TAG "m6809" + +static ADDRESS_MAP_START( m6809_mem, AS_PROGRAM, 8, a2bus_themill_device ) + AM_RANGE(0x0000, 0xffff) AM_READWRITE(dma_r, dma_w) +ADDRESS_MAP_END + +MACHINE_CONFIG_FRAGMENT( a2themill ) + MCFG_CPU_ADD(M6809_TAG, M6809, 1021800) // M6809 runs at ~1 MHz as per Stellation Two's print ads + MCFG_CPU_PROGRAM_MAP(m6809_mem) +MACHINE_CONFIG_END + +/*************************************************************************** + FUNCTION PROTOTYPES +***************************************************************************/ + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor a2bus_themill_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( a2themill ); +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +a2bus_themill_device::a2bus_themill_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_a2bus_card_interface(mconfig, *this), + m_6809(*this, M6809_TAG) +{ +} + +a2bus_themill_device::a2bus_themill_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, A2BUS_THEMILL, "Stellation Two The Mill", tag, owner, clock, "a2themill", __FILE__), + device_a2bus_card_interface(mconfig, *this), + m_6809(*this, M6809_TAG) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void a2bus_themill_device::device_start() +{ + // set_a2bus_device makes m_slot valid + set_a2bus_device(); + + save_item(NAME(m_bEnabled)); + save_item(NAME(m_flipAddrSpace)); + save_item(NAME(m_6809Mode)); + save_item(NAME(m_status)); +} + +void a2bus_themill_device::device_reset() +{ + m_bEnabled = false; + m_flipAddrSpace = false; + m_6809Mode = false; + m_status = 0xc0; // OS9 loader relies on this + m_6809->set_input_line(INPUT_LINE_HALT, ASSERT_LINE); + m_6809->set_input_line(INPUT_LINE_RESET, ASSERT_LINE); +} + +UINT8 a2bus_themill_device::read_c0nx(address_space &space, UINT8 offset) +{ + return m_status; +} + +void a2bus_themill_device::write_c0nx(address_space &space, UINT8 offset, UINT8 data) +{ + switch (offset) + { + case 0: // 6502 IRQ + if (data & 0x80) + { + m_status |= 0x01; + lower_slot_irq(); + } + else + { + m_status &= ~0x01; + raise_slot_irq(); + } + break; + + case 2: // 6809 reset + if (data & 0x80) + { + m_6809->reset(); + + m_6809->set_input_line(INPUT_LINE_HALT, CLEAR_LINE); + m_6809->set_input_line(INPUT_LINE_RESET, CLEAR_LINE); + + m_bEnabled = true; + m_status &= ~0x04; + } + else + { + m_6809->set_input_line(INPUT_LINE_HALT, ASSERT_LINE); + m_bEnabled = false; + m_status |= 0x04; + } + break; + + case 1: // 6809 halt + if (data & 0x80) // release reset + { + m_status |= 0x02; + } + else + { + m_6809->reset(); + m_status &= ~0x02; + } + break; + + case 3: // 6809 NMI + if (data & 0x80) + { + m_6809->set_input_line(INPUT_LINE_NMI, CLEAR_LINE); + m_status |= 0x08; + } + else + { + m_6809->set_input_line(INPUT_LINE_NMI, ASSERT_LINE); + m_status &= ~0x08; + } + break; + + case 4: // 6809 FIRQ + if (data & 0x80) + { + m_6809->set_input_line(M6809_FIRQ_LINE, CLEAR_LINE); + m_status |= 0x10; + } + else + { + m_6809->set_input_line(M6809_FIRQ_LINE, ASSERT_LINE); + m_status &= ~0x10; + } + break; + + case 5: // 6809 IRQ + if (data & 0x80) + { + m_6809->set_input_line(M6809_IRQ_LINE, CLEAR_LINE); + m_status |= 0x20; + } + else + { + m_6809->set_input_line(M6809_IRQ_LINE, ASSERT_LINE); + m_status &= ~0x20; + } + break; + + case 6: + if (data & 0x80) // enable ROM socket + { + m_status |= 0x40; + printf("The Mill: on-board ROM socket enabled; because none of these ROMs are dumped, the 6809 will not run!\n"); + } + else + { + m_status &= ~0x40; + } + break; + + case 7: // 6809 mapping + if (data & 0x80) + { + m_status |= 0x80; + m_flipAddrSpace = false; + } + else + { + m_status &= ~0x80; + m_flipAddrSpace = true; + } + break; + + case 0xa: // addresses >= 0x8 are direct status writes? "Excel Flex 9" disc seems to indicate so. + m_status = data; + break; + + default: + printf("The Mill: %02x to unhandled c0n%x\n", data, offset); + break; + } +} + +READ8_MEMBER( a2bus_themill_device::dma_r ) +{ + if (m_6809Mode) + { + if (offset <= 0xafff) + { + return slot_dma_read(space, offset+0x1000); + } + else if (offset <= 0xbfff) + { + return slot_dma_read(space, (offset&0xfff) + 0xd000); + } + else if (offset <= 0xcfff) + { + return slot_dma_read(space, (offset&0xfff) + 0xe000); + } + else if (offset <= 0xdfff) + { + return slot_dma_read(space, (offset&0xfff) + 0xf000); + } + else if (offset <= 0xefff) + { + return slot_dma_read(space, (offset&0xfff) + 0xc000); + } + else // 6809 Fxxx -> 6502 ZP + { + return slot_dma_read(space, offset&0xfff); + } + } + else + { + if (m_flipAddrSpace) + { + return slot_dma_read(space, offset^0x8000); + } + else + { + return slot_dma_read(space, offset); + } + } + + return 0xff; +} + + +//------------------------------------------------- +// dma_w - +//------------------------------------------------- + +WRITE8_MEMBER( a2bus_themill_device::dma_w ) +{ + if (m_6809Mode) + { + if (offset <= 0xafff) + { + slot_dma_write(space, offset+0x1000, data); + } + else if (offset <= 0xbfff) + { + slot_dma_write(space, (offset&0xfff) + 0xd000, data); + } + else if (offset <= 0xcfff) + { + slot_dma_write(space, (offset&0xfff) + 0xe000, data); + } + else if (offset <= 0xdfff) + { + slot_dma_write(space, (offset&0xfff) + 0xf000, data); + } + else if (offset <= 0xefff) + { + slot_dma_write(space, (offset&0xfff) + 0xc000, data); + } + else // 6809 Fxxx -> 6502 ZP + { + slot_dma_write(space, offset&0xfff, data); + } + } + else + { + if (m_flipAddrSpace) + { + slot_dma_write(space, offset^0x8000, data); + } + else + { + slot_dma_write(space, offset, data); + } + } +} + +bool a2bus_themill_device::take_c800() +{ + return false; +} diff --git a/src/devices/bus/a2bus/a2themill.h b/src/devices/bus/a2bus/a2themill.h new file mode 100644 index 00000000000..72ea1b47953 --- /dev/null +++ b/src/devices/bus/a2bus/a2themill.h @@ -0,0 +1,57 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/********************************************************************* + + a2themill.h + + Implementation of the Stellation Two The Mill 6809 card + +*********************************************************************/ + +#ifndef __A2BUS_THEMILL__ +#define __A2BUS_THEMILL__ + +#include "emu.h" +#include "a2bus.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class a2bus_themill_device: + public device_t, + public device_a2bus_card_interface +{ +public: + // construction/destruction + a2bus_themill_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + a2bus_themill_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + + DECLARE_READ8_MEMBER( dma_r ); + DECLARE_WRITE8_MEMBER( dma_w ); + +protected: + virtual void device_start(); + virtual void device_reset(); + + // overrides of standard a2bus slot functions + virtual UINT8 read_c0nx(address_space &space, UINT8 offset); + virtual void write_c0nx(address_space &space, UINT8 offset, UINT8 data); + virtual bool take_c800(); + + required_device m_6809; + +private: + bool m_bEnabled; + bool m_flipAddrSpace; + bool m_6809Mode; + UINT8 m_status; +}; + +// device type definition +extern const device_type A2BUS_THEMILL; + +#endif /* __A2BUS_THEMILL__ */ diff --git a/src/devices/bus/a2bus/a2thunderclock.c b/src/devices/bus/a2bus/a2thunderclock.c new file mode 100644 index 00000000000..d16feb82448 --- /dev/null +++ b/src/devices/bus/a2bus/a2thunderclock.c @@ -0,0 +1,179 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/********************************************************************* + + a2thunderclock.c + + Implemention of the Thunderware Thunderclock Plus. + + + PCB Layout: (B1/B2 are batteries) + _______________________________________________________________ + | | + | | | | | uPD1990 CD4050 74LS174 74LS132 | + | | | | | _ _ _ _ _ | + | | | | | | | | | | | | | | | | + | | | | | |_| |_| |_| |_| |_| | + | B1 B2 74LS08 | + | 74LS74 74LS109 74LS126 ____________ 74LS27 | + | _ _ _ | | _ | + | | | | | | | | 2716 | | | | + | |_| |_| |_| |____________| |_| | + |______________________________________ _| + | | + |______________________| + +*********************************************************************/ + +#include "a2thunderclock.h" + +/*************************************************************************** + PARAMETERS +***************************************************************************/ + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type A2BUS_THUNDERCLOCK = &device_creator; + +#define THUNDERCLOCK_ROM_REGION "thunclk_rom" +#define THUNDERCLOCK_UPD1990_TAG "thunclk_upd" + +MACHINE_CONFIG_FRAGMENT( thunderclock ) + MCFG_UPD1990A_ADD(THUNDERCLOCK_UPD1990_TAG, 1021800, DEVWRITELINE(DEVICE_SELF, a2bus_thunderclock_device, upd_dataout_w), NULL) +MACHINE_CONFIG_END + +ROM_START( thunderclock ) + ROM_REGION(0x800, THUNDERCLOCK_ROM_REGION, 0) + ROM_LOAD( "thunderclock plus rom.bin", 0x0000, 0x0800, CRC(1b99c4e3) SHA1(60f434f5325899d7ea257a6e56e6f53eae65146a) ) +ROM_END + +/*************************************************************************** + FUNCTION PROTOTYPES +***************************************************************************/ + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor a2bus_thunderclock_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( thunderclock ); +} + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *a2bus_thunderclock_device::device_rom_region() const +{ + return ROM_NAME( thunderclock ); +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +a2bus_thunderclock_device::a2bus_thunderclock_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_a2bus_card_interface(mconfig, *this), + m_upd1990ac(*this, THUNDERCLOCK_UPD1990_TAG) +{ +} + +a2bus_thunderclock_device::a2bus_thunderclock_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, A2BUS_THUNDERCLOCK, "ThunderWare ThunderClock Plus", tag, owner, clock, "a2thunpl", __FILE__), + device_a2bus_card_interface(mconfig, *this), + m_upd1990ac(*this, THUNDERCLOCK_UPD1990_TAG) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void a2bus_thunderclock_device::device_start() +{ + // set_a2bus_device makes m_slot valid + set_a2bus_device(); + + m_rom = device().machine().root_device().memregion(this->subtag(THUNDERCLOCK_ROM_REGION).c_str())->base(); + + save_item(NAME(m_dataout)); +} + +void a2bus_thunderclock_device::device_reset() +{ + m_dataout = 0; +} + + +/*------------------------------------------------- + read_c0nx - called for reads from this card's c0nx space +-------------------------------------------------*/ + +UINT8 a2bus_thunderclock_device::read_c0nx(address_space &space, UINT8 offset) +{ + return (m_dataout << 7); +} + + +/*------------------------------------------------- + write_c0nx - called for writes to this card's c0nx space +-------------------------------------------------*/ + +void a2bus_thunderclock_device::write_c0nx(address_space &space, UINT8 offset, UINT8 data) +{ + // uPD1990AC hookup: + // bit 0 = DATA IN? + // bit 1 = CLK + // bit 2 = STB + // bit 3 = C0 + // bit 4 = C1 + // bit 5 = C2 + // bit 7 = data out + if (offset == 0) + { + m_upd1990ac->cs_w(1); + m_upd1990ac->oe_w(1); + m_upd1990ac->data_in_w(data&0x01); + m_upd1990ac->c0_w((data&0x08) >> 3); + m_upd1990ac->c1_w((data&0x10) >> 4); + m_upd1990ac->c2_w((data&0x20) >> 5); + m_upd1990ac->stb_w((data&0x04) >> 2); + m_upd1990ac->clk_w((data&0x02) >> 1); + } +} + +/*------------------------------------------------- + read_cnxx - called for reads from this card's cnxx space +-------------------------------------------------*/ + +UINT8 a2bus_thunderclock_device::read_cnxx(address_space &space, UINT8 offset) +{ + // ROM is primarily a c800 image, but the first page is also the CnXX ROM + return m_rom[offset]; +} + +/*------------------------------------------------- + read_c800 - called for reads from this card's c800 space +-------------------------------------------------*/ + +UINT8 a2bus_thunderclock_device::read_c800(address_space &space, UINT16 offset) +{ + return m_rom[offset]; +} + +WRITE_LINE_MEMBER( a2bus_thunderclock_device::upd_dataout_w ) +{ + if (state) + { + m_dataout = 1; + } + else + { + m_dataout = 0; + } +} diff --git a/src/devices/bus/a2bus/a2thunderclock.h b/src/devices/bus/a2bus/a2thunderclock.h new file mode 100644 index 00000000000..23b9e66981c --- /dev/null +++ b/src/devices/bus/a2bus/a2thunderclock.h @@ -0,0 +1,57 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/********************************************************************* + + a2thunderclock.h + + Implemention of the Thunderware Thunderclock Plus. + +*********************************************************************/ + +#ifndef __A2BUS_THUNDERCLOCK__ +#define __A2BUS_THUNDERCLOCK__ + +#include "emu.h" +#include "a2bus.h" +#include "machine/upd1990a.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class a2bus_thunderclock_device: + public device_t, + public device_a2bus_card_interface +{ +public: + // construction/destruction + a2bus_thunderclock_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + a2bus_thunderclock_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual const rom_entry *device_rom_region() const; + + DECLARE_WRITE_LINE_MEMBER( upd_dataout_w ); + +protected: + virtual void device_start(); + virtual void device_reset(); + + // overrides of standard a2bus slot functions + virtual UINT8 read_c0nx(address_space &space, UINT8 offset); + virtual void write_c0nx(address_space &space, UINT8 offset, UINT8 data); + virtual UINT8 read_cnxx(address_space &space, UINT8 offset); + virtual UINT8 read_c800(address_space &space, UINT16 offset); + + required_device m_upd1990ac; + +private: + UINT8 *m_rom; + int m_dataout; +}; + +// device type definition +extern const device_type A2BUS_THUNDERCLOCK; + +#endif /* __A2BUS_THUNDERCLOCK__ */ diff --git a/src/devices/bus/a2bus/a2ultraterm.c b/src/devices/bus/a2bus/a2ultraterm.c new file mode 100644 index 00000000000..62969c36dee --- /dev/null +++ b/src/devices/bus/a2bus/a2ultraterm.c @@ -0,0 +1,399 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/********************************************************************* + + a2ultraterm.c + + Implementation of the Videx UltraTerm 80/132/160-column card + + Notes: + + C0nX: C0n0 is 6845 register address, + C0n1 is 6845 register data. + C0n2 is control 1: b7 = 0 to read RAM at cc00, 1 for ROM (writes always to RAM) + b6 = 0 for Apple II video, 1 for 6845 + b5 = 0 for 17.430 MHz 6845 clock, 1 for 28.7595 MHz 6845 clock + b4 = 0 for 512 byte RAM block addressing (VideoTerm emulation), 1 for 256-byte RAM page addressing + b3-b0 = page select + C0n3 is control 2: b7 = 0 for attributes software controllable, 1 for DIP switches control attributes + b5 = 0 for normal video if bit 7 set, 1 for inverse if bit 7 set + b4 = 0 for lowlight if bit 7 set, 1 for highlight if bit 7 set + b2 = 0 for high-density character set, 1 for low-density character set + b1 = same as b5 + b0 = same as b4 + + C800-CBFF: ROM page 1 + CC00-CFEF: VRAM window or ROM page 2 + +*********************************************************************/ + +#include "a2ultraterm.h" +#include "includes/apple2.h" + + +/*************************************************************************** + PARAMETERS +***************************************************************************/ + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type A2BUS_ULTRATERM = &device_creator; +const device_type A2BUS_ULTRATERMENH = &device_creator; + +#define ULTRATERM_ROM_REGION "uterm_rom" +#define ULTRATERM_GFX_REGION "uterm_gfx" +#define ULTRATERM_SCREEN_NAME "uterm_screen" +#define ULTRATERM_MC6845_NAME "mc6845_uterm" + +#define CLOCK_LOW 17430000 +#define CLOCK_HIGH 28759500 + +#define CT1_MEMSEL (0x80) // 0 for read RAM at cc00, 1 for read ROM +#define CT1_VIDSEL (0x40) // 0 for Apple video passthrough, 1 for 6845 video +#define CT1_CLKSEL (0x20) // 0 for Videoterm clock, 1 for faster clock +#define CT1_VTEMU (0x10) // Videoterm emulation mode if 0 +#define CT1_PAGEMASK (0x0f) + +#define CT2_USEDIPS (0x80) // 0 to use the rest of ctrl2's bits, 1 to use DIPs +#define CT2_INVBIT7H (0x20) +#define CT2_HLBIT7H (0x10) +#define CT2_HIDENSITY (0x04) +#define CT2_INVBIT7L (0x02) +#define CT2_HLBIT7L (0x01) + + +static const rgb_t ultraterm_palette[4] = +{ + rgb_t(0x00,0x00,0x00), + rgb_t(0x55,0x55,0x55), + rgb_t(0xaa,0xaa,0xaa), + rgb_t(0xff,0xff,0xff) +}; + +MACHINE_CONFIG_FRAGMENT( a2ultraterm ) + MCFG_SCREEN_ADD( ULTRATERM_SCREEN_NAME, RASTER) + MCFG_SCREEN_RAW_PARAMS(CLOCK_LOW, 882, 0, 720, 370, 0, 350 ) + MCFG_SCREEN_UPDATE_DEVICE( ULTRATERM_MC6845_NAME, mc6845_device, screen_update ) + + MCFG_MC6845_ADD(ULTRATERM_MC6845_NAME, MC6845, ULTRATERM_SCREEN_NAME, CLOCK_LOW/9) + MCFG_MC6845_SHOW_BORDER_AREA(false) + MCFG_MC6845_CHAR_WIDTH(8) + MCFG_MC6845_UPDATE_ROW_CB(a2bus_videx160_device, crtc_update_row) + MCFG_MC6845_OUT_VSYNC_CB(WRITELINE(a2bus_videx160_device, vsync_changed)) +MACHINE_CONFIG_END + +ROM_START( a2ultraterm ) + ROM_REGION(0x1000, ULTRATERM_ROM_REGION, 0) + ROM_LOAD( "frm_b537.bin", 0x000000, 0x001000, CRC(1e85a93e) SHA1(b4acd1775c08ae43996ab4edf6d8e28f4736346b) ) + + ROM_REGION(0x1000, ULTRATERM_GFX_REGION, 0) + ROM_LOAD( "chs_7859.bin", 0x000000, 0x001000, CRC(ebe8f333) SHA1(3517fa9e7a39573f1cb159b3161d6939dec199ba) ) + + ROM_REGION(0x400, "pal", 0) + ROM_LOAD( "ult_2a313.jed", 0x000000, 0x000305, CRC(dcd51dea) SHA1(0ad0c5e802e48495da27f7bd26ee3ab1c92d74dd) ) +ROM_END + +ROM_START( a2ultratermenh ) + ROM_REGION(0x1000, ULTRATERM_ROM_REGION, 0) + ROM_LOAD( "frm_b5c9.bin", 0x000000, 0x001000, CRC(b71e05e0) SHA1(092e3eda4644d4f465809864a7f023ac7d1d1542) ) + + ROM_REGION(0x1000, ULTRATERM_GFX_REGION, 0) + ROM_LOAD( "chs_5604.bin", 0x000000, 0x001000, CRC(3fb4e90a) SHA1(94ff75199232a9b613585c22f88470f73fb7dd09) ) + + ROM_REGION(0x400, "pal", 0) + ROM_LOAD( "ult_251c.jed", 0x000000, 0x000305, CRC(12fabb0d) SHA1(d4a36837cb98bb65f7ddef7455eb5a7f8e648a82) ) +ROM_END + +/*************************************************************************** + FUNCTION PROTOTYPES +***************************************************************************/ + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor a2bus_videx160_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( a2ultraterm ); +} + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *a2bus_ultraterm_device::device_rom_region() const +{ + return ROM_NAME( a2ultraterm ); +} + +const rom_entry *a2bus_ultratermenh_device::device_rom_region() const +{ + return ROM_NAME( a2ultratermenh ); +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +a2bus_videx160_device::a2bus_videx160_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_a2bus_card_interface(mconfig, *this), + m_crtc(*this, ULTRATERM_MC6845_NAME) +{ +} + +a2bus_ultraterm_device::a2bus_ultraterm_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + a2bus_videx160_device(mconfig, A2BUS_ULTRATERM, "Videx UltraTerm (original)", tag, owner, clock, "a2ulttrm", __FILE__) +{ +} + +a2bus_ultratermenh_device::a2bus_ultratermenh_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + a2bus_videx160_device(mconfig, A2BUS_ULTRATERMENH, "Videx UltraTerm (enhanced //e)", tag, owner, clock, "a2ultrme", __FILE__) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void a2bus_videx160_device::device_start() +{ + // set_a2bus_device makes m_slot valid + set_a2bus_device(); + + m_rom = device().machine().root_device().memregion(this->subtag(ULTRATERM_ROM_REGION).c_str())->base(); + + m_chrrom = device().machine().root_device().memregion(this->subtag(ULTRATERM_GFX_REGION).c_str())->base(); + + memset(m_ram, 0, 256*16); + + save_item(NAME(m_ram)); + save_item(NAME(m_framecnt)); + save_item(NAME(m_rambank)); + save_item(NAME(m_ctrl1)); + save_item(NAME(m_ctrl2)); +} + +void a2bus_videx160_device::device_reset() +{ + m_rambank = 0; + m_framecnt = 0; +} + + +/*------------------------------------------------- + read_c0nx - called for reads from this card's c0nx space +-------------------------------------------------*/ + +UINT8 a2bus_videx160_device::read_c0nx(address_space &space, UINT8 offset) +{ +// printf("Read c0n%x (PC=%x)\n", offset, space.device().safe_pc()); + + if (!(m_ctrl1 & CT1_VTEMU)) + { + m_rambank = ((offset>>2) & 3) * 512; + } + + switch (offset) + { + case 1: + return m_crtc->register_r(space, offset); // status_r? + + case 2: + return m_ctrl1; + + case 3: + return m_ctrl2; + } + + return 0xff; +} + + +/*------------------------------------------------- + write_c0nx - called for writes to this card's c0nx space +-------------------------------------------------*/ + +void a2bus_videx160_device::write_c0nx(address_space &space, UINT8 offset, UINT8 data) +{ +// printf("Write %02x to c0n%x (PC=%x)\n", data, offset, space.device().safe_pc()); + + switch (offset) + { + case 0: + m_crtc->address_w(space, offset, data); + break; + + case 1: + m_crtc->register_w(space, offset, data); + break; + + case 2: + m_ctrl1 = data; +// printf("%02x to ctrl1\n", data); + + // if disabling Videoterm emulation, change RAM banking + if (data & CT1_VTEMU) + { + m_rambank = (data & CT1_PAGEMASK) * 256; + } + break; + + case 3: + m_ctrl2 = data; +// printf("%02x to ctrl2\n", data); + break; + } + + if (!(m_ctrl1 & CT1_VTEMU)) + { + m_rambank = ((offset >> 2) & 3) * 512; + } +} + +/*------------------------------------------------- + read_cnxx - called for reads from this card's cnxx space +-------------------------------------------------*/ + +UINT8 a2bus_videx160_device::read_cnxx(address_space &space, UINT8 offset) +{ + return m_rom[offset+(m_slot * 0x100)]; +} + +/*------------------------------------------------- + write_cnxx - called for writes to this card's cnxx space + the firmware writes here to switch in our $C800 a lot +-------------------------------------------------*/ +void a2bus_videx160_device::write_cnxx(address_space &space, UINT8 offset, UINT8 data) +{ +} + +/*------------------------------------------------- + read_c800 - called for reads from this card's c800 space +-------------------------------------------------*/ + +UINT8 a2bus_videx160_device::read_c800(address_space &space, UINT16 offset) +{ + // ROM at c800-cbff + // bankswitched RAM at cc00-cdff + if (offset < 0x400) + { +// printf("Read VRAM at %x = %02x\n", offset+m_rambank, m_ram[offset + m_rambank]); + return m_rom[offset + 0x800]; + } + else + { + if (m_ctrl1 & CT1_MEMSEL) // read ROM? + { + return m_rom[offset + 0x800]; + } + + return m_ram[(offset - 0x400) + m_rambank]; + } +} + +/*------------------------------------------------- + write_c800 - called for writes to this card's c800 space +-------------------------------------------------*/ +void a2bus_videx160_device::write_c800(address_space &space, UINT16 offset, UINT8 data) +{ + if (offset >= 0x400) + { +// printf("%02x to VRAM at %x\n", data, offset-0x400+m_rambank); + m_ram[(offset-0x400) + m_rambank] = data; + } +} + +MC6845_UPDATE_ROW( a2bus_videx160_device::crtc_update_row ) +{ + UINT32 *p = &bitmap.pix32(y); + UINT16 chr_base = ra; + int i; + + for ( i = 0; i < x_count; i++ ) + { + UINT16 offset = ( ma + i ); + UINT8 chr = m_ram[ offset ]; + UINT8 data = m_chrrom[ chr_base + (chr * 16) ]; + UINT8 fg = 2; + UINT8 bg = 0; + UINT8 tmp; + + // apply attributes + if (!(m_ctrl2 & CT2_USEDIPS)) + { + // this set and bit 7 in char, highlight + if ((m_ctrl2 & CT2_HLBIT7H) && (chr & 0x80)) + { + fg = 3; + bg = 0; + } + + // this set and NOT bit 7 in char, highlight + if ((m_ctrl2 & CT2_HLBIT7L) && (!(chr & 0x80))) + { + fg = 3; + bg = 0; + } + + // this clear and bit 7 in char, lowlight + if (!(m_ctrl2 & CT2_HLBIT7H) && (chr & 0x80)) + { + fg = 1; + bg = 0; + } + + // this clear and NOT bit 7 in char, lowlight + if (!(m_ctrl2 & CT2_HLBIT7L) && (!(chr & 0x80))) + { + fg = 1; + bg = 0; + } + + // invert last so invert + hilight/invert + lowlight are possible + // invert if char bit 7 is set + if ((m_ctrl2 & CT2_INVBIT7H) && (chr & 0x80)) + { + tmp = fg; + fg = bg; + bg = tmp; + } + + // invert if char bit 7 is clear + if ((m_ctrl2 & CT2_INVBIT7L) && (!(chr & 0x80))) + { + tmp = fg; + fg = bg; + bg = tmp; + } + } + + if ( i == cursor_x ) + { + if ( m_framecnt & 0x08 ) + { + data = 0xFF; + } + } + + *p = ultraterm_palette[( data & 0x80 ) ? fg : bg]; p++; + *p = ultraterm_palette[( data & 0x40 ) ? fg : bg]; p++; + *p = ultraterm_palette[( data & 0x20 ) ? fg : bg]; p++; + *p = ultraterm_palette[( data & 0x10 ) ? fg : bg]; p++; + *p = ultraterm_palette[( data & 0x08 ) ? fg : bg]; p++; + *p = ultraterm_palette[( data & 0x04 ) ? fg : bg]; p++; + *p = ultraterm_palette[( data & 0x02 ) ? fg : bg]; p++; + *p = ultraterm_palette[( data & 0x01 ) ? fg : bg]; p++; + } +} + +WRITE_LINE_MEMBER( a2bus_videx160_device::vsync_changed ) +{ + if ( state ) + { + m_framecnt++; + } +} diff --git a/src/devices/bus/a2bus/a2ultraterm.h b/src/devices/bus/a2bus/a2ultraterm.h new file mode 100644 index 00000000000..a9f9745f2cc --- /dev/null +++ b/src/devices/bus/a2bus/a2ultraterm.h @@ -0,0 +1,79 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/********************************************************************* + + a2ultraterm.h + + Implementation of the Videx UltraTerm 80/132/160-column video card + +*********************************************************************/ + +#ifndef __A2BUS_ULTRATERM__ +#define __A2BUS_ULTRATERM__ + +#include "emu.h" +#include "a2bus.h" +#include "video/mc6845.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class a2bus_videx160_device: + public device_t, + public device_a2bus_card_interface +{ +public: + // construction/destruction + a2bus_videx160_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + + DECLARE_WRITE_LINE_MEMBER(vsync_changed); + MC6845_UPDATE_ROW(crtc_update_row); + + UINT8 *m_rom, *m_chrrom; + UINT8 m_ram[256*16]; + int m_framecnt; + UINT8 m_ctrl1, m_ctrl2; + +protected: + virtual void device_start(); + virtual void device_reset(); + + // overrides of standard a2bus slot functions + virtual UINT8 read_c0nx(address_space &space, UINT8 offset); + virtual void write_c0nx(address_space &space, UINT8 offset, UINT8 data); + virtual UINT8 read_cnxx(address_space &space, UINT8 offset); + virtual void write_cnxx(address_space &space, UINT8 offset, UINT8 data); + virtual UINT8 read_c800(address_space &space, UINT16 offset); + virtual void write_c800(address_space &space, UINT16 offset, UINT8 data); + + required_device m_crtc; + +private: + int m_rambank; +}; + +class a2bus_ultraterm_device : public a2bus_videx160_device +{ +public: + a2bus_ultraterm_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual const rom_entry *device_rom_region() const; +}; + +class a2bus_ultratermenh_device : public a2bus_videx160_device +{ +public: + a2bus_ultratermenh_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual const rom_entry *device_rom_region() const; +}; + +// device type definition +extern const device_type A2BUS_ULTRATERM; +extern const device_type A2BUS_ULTRATERMENH; + +#endif /* __A2BUS_ULTRATERM__ */ diff --git a/src/devices/bus/a2bus/a2videoterm.c b/src/devices/bus/a2bus/a2videoterm.c new file mode 100644 index 00000000000..d29c00d2006 --- /dev/null +++ b/src/devices/bus/a2bus/a2videoterm.c @@ -0,0 +1,377 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/********************************************************************* + + a2videoterm.c + + Implementation of the Videx VideoTerm 80-column card + + Notes (from Videoterm user's manual, which contains + schematics and firmware source listings). + + C0nX: C0n0 is 6845 register address, + C0n1 is 6845 register data. + + Bits 2 & 3 on any access to C0nX set the VRAM page at CC00. + + C800-CBFF: ROM + CC00-CDFF: VRAM window + + TODO: + Cursor is probably not completely right. + Add font ROM select. + +*********************************************************************/ + +#include "a2videoterm.h" +#include "includes/apple2.h" + + +/*************************************************************************** + PARAMETERS +***************************************************************************/ + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type A2BUS_VIDEOTERM = &device_creator; +const device_type A2BUS_IBSAP16 = &device_creator; +const device_type A2BUS_IBSAP16ALT = &device_creator; +const device_type A2BUS_VTC1 = &device_creator; +const device_type A2BUS_VTC2 = &device_creator; +const device_type A2BUS_AEVIEWMASTER80 = &device_creator; + +#define VIDEOTERM_ROM_REGION "vterm_rom" +#define VIDEOTERM_GFX_REGION "vterm_gfx" +#define VIDEOTERM_SCREEN_NAME "vterm_screen" +#define VIDEOTERM_MC6845_NAME "mc6845_vterm" + +#define MDA_CLOCK 16257000 + +MACHINE_CONFIG_FRAGMENT( a2videoterm ) + MCFG_SCREEN_ADD( VIDEOTERM_SCREEN_NAME, RASTER) // 560x216? (80x24 7x9 characters) + MCFG_SCREEN_RAW_PARAMS(MDA_CLOCK, 882, 0, 720, 370, 0, 350 ) + MCFG_SCREEN_UPDATE_DEVICE( VIDEOTERM_MC6845_NAME, mc6845_device, screen_update ) + + MCFG_MC6845_ADD(VIDEOTERM_MC6845_NAME, MC6845, VIDEOTERM_SCREEN_NAME, MDA_CLOCK/9) + MCFG_MC6845_SHOW_BORDER_AREA(false) + MCFG_MC6845_CHAR_WIDTH(8) + MCFG_MC6845_UPDATE_ROW_CB(a2bus_videx80_device, crtc_update_row) + MCFG_MC6845_OUT_VSYNC_CB(WRITELINE(a2bus_videx80_device, vsync_changed)) +MACHINE_CONFIG_END + +ROM_START( a2videoterm ) + ROM_REGION(0x400, VIDEOTERM_ROM_REGION, 0) + ROM_LOAD( "videx videoterm rom 2.4.bin", 0x000000, 0x000400, CRC(bbe3bb28) SHA1(bb653836e84850ce3197f461d4e19355f738cfbf) ) + + ROM_REGION(0x5000, VIDEOTERM_GFX_REGION, 0) + ROM_LOAD( "videx videoterm character rom normal.bin", 0x000000, 0x000800, CRC(87f89f08) SHA1(410b54f33d13c82e3857f1be906d93a8c5b8d321) ) + ROM_LOAD( "videx videoterm character rom normal uppercase.bin", 0x000800, 0x000800, CRC(3d94a7a4) SHA1(5518254f24bc945aab13bc71ecc9526d6dd8e033) ) + ROM_LOAD( "videx videoterm character rom apl.bin", 0x001000, 0x000800, CRC(1adb704e) SHA1(a95df910eca33188cacee333b1325aa47edbcc25) ) + ROM_LOAD( "videx videoterm character rom epson.bin", 0x001800, 0x000800, CRC(0c6ef8d0) SHA1(db72c0c120086f1aa4a87120c5d7993c4a9d3a18) ) + ROM_LOAD( "videx videoterm character rom french.bin", 0x002000, 0x000800, CRC(266aa837) SHA1(2c6b4e9d342dbb2de8e278740f11925a9d8c6616) ) + ROM_LOAD( "videx videoterm character rom german.bin", 0x002800, 0x000800, CRC(df7324fa) SHA1(0ce58d2ffadbebc8db9f85bbb9a08a4f142af682) ) + ROM_LOAD( "videx videoterm character rom katakana.bin", 0x003000, 0x000800, CRC(b728690e) SHA1(e018fa66b0ff560313bb35757c9ce7adecae0c3a) ) + ROM_LOAD( "videx videoterm character rom spanish.bin", 0x003800, 0x000800, CRC(439eac08) SHA1(d6f9f8eb7702440d9ae39129ea4f480b80fc4608) ) + ROM_LOAD( "videx videoterm character rom super and subscript.bin", 0x004000, 0x000800, CRC(08b7c538) SHA1(7f4029d97be05680fe695debe07cea07666419e0) ) + ROM_LOAD( "videx videoterm character rom symbol.bin", 0x004800, 0x000800, CRC(82bce582) SHA1(29dfa8c5257dbf25651c6bffa9cdb453482aa70e) ) +ROM_END + +ROM_START( a2ap16 ) + ROM_REGION(0x2000, VIDEOTERM_ROM_REGION, 0) + ROM_LOAD( "space 84 video ap16.bin", 0x000000, 0x002000, CRC(0e188da2) SHA1(9a29250b6cc7b576fdc67769944de35e6f54b9d5) ) + + ROM_REGION(0x4000, VIDEOTERM_GFX_REGION, 0) + ROM_LOAD( "space 84 video chargen ap16.bin", 0x000000, 0x002000, CRC(b9447088) SHA1(19c95f91a67b948fc00a14621d574d629479d451) ) +ROM_END + +ROM_START( a2ap16alt ) + ROM_REGION(0x1000, VIDEOTERM_ROM_REGION, 0) + ROM_LOAD( "unknown apple ii clone video 3.bin", 0x000000, 0x001000, CRC(af1226d2) SHA1(18a569f417a47f54a17bd9046d306a54b46ed049) ) + + ROM_REGION(0x4000, VIDEOTERM_GFX_REGION, 0) + ROM_LOAD( "unknown apple ii clone video 1.bin", 0x000000, 0x001000, CRC(cf84811c) SHA1(135f4f35607dd74941f0a3cae813227bf8a8a020) ) +ROM_END + +ROM_START( vtc1 ) + ROM_REGION(0x800, VIDEOTERM_ROM_REGION, 0) + ROM_LOAD( "10.ic10.bin", 0x000000, 0x000800, CRC(ddbbc2fb) SHA1(15d6142b177b47c016f2745e1d95767b440d77c7) ) + + ROM_REGION(0x1000, VIDEOTERM_GFX_REGION, 0) + ROM_LOAD( "9.ic9.bin", 0x000000, 0x000800, CRC(094670f1) SHA1(aefae76fb07740d042cf294f01424efa7cc7a199) ) + ROM_LOAD( "8.ic8.bin", 0x000800, 0x000800, CRC(fbd98d77) SHA1(0d9b1c3917e23ca35d5fbd405f05ff6e87122b92) ) +ROM_END + +ROM_START( vtc2 ) + ROM_REGION(0x800, VIDEOTERM_ROM_REGION, 0) + ROM_LOAD( "6.ic6.bin", 0x000000, 0x000800, CRC(5776fa24) SHA1(19f69011ed7d2551c39d5c1cac1f5a2defc8f8fb) ) + + ROM_REGION(0x1000, VIDEOTERM_GFX_REGION, 0) + ROM_LOAD( "5.ic5.bin", 0x000000, 0x000800, CRC(aafa7085) SHA1(54d7c358f1927ba8f3b61145215a806d8cb6b673) ) + ROM_LOAD( "4.ic4.bin", 0x000800, 0x000800, CRC(8a497a48) SHA1(50c3df528109c65491a001ec74e50351a652c1fd) ) +ROM_END + +ROM_START( a2aevm80 ) + ROM_REGION(0x800, VIDEOTERM_ROM_REGION, 0) + ROM_LOAD( "ae viewmaster 80 rom.bin", 0x000000, 0x000800, CRC(62a4b111) SHA1(159bf7c4add1435be215fddb648c0743fbcc49b5) ) + + ROM_REGION(0x1000, VIDEOTERM_GFX_REGION, 0) + ROM_LOAD( "ae viewmaster 80 video rom.bin", 0x000000, 0x000800, CRC(4801ab90) SHA1(f90658ffee7740f3cb30ecef2e151f7dc6098833) ) +ROM_END + +/*************************************************************************** + FUNCTION PROTOTYPES +***************************************************************************/ + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor a2bus_videx80_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( a2videoterm ); +} + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *a2bus_videoterm_device::device_rom_region() const +{ + return ROM_NAME( a2videoterm ); +} + +const rom_entry *a2bus_ap16_device::device_rom_region() const +{ + return ROM_NAME( a2ap16 ); +} + +const rom_entry *a2bus_ap16alt_device::device_rom_region() const +{ + return ROM_NAME( a2ap16alt ); +} + +const rom_entry *a2bus_vtc1_device::device_rom_region() const +{ + return ROM_NAME( vtc1 ); +} + +const rom_entry *a2bus_vtc2_device::device_rom_region() const +{ + return ROM_NAME( vtc2 ); +} + +const rom_entry *a2bus_aevm80_device::device_rom_region() const +{ + return ROM_NAME( a2aevm80 ); +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +a2bus_videx80_device::a2bus_videx80_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_a2bus_card_interface(mconfig, *this), + m_crtc(*this, VIDEOTERM_MC6845_NAME), + m_palette(*this, ":palette") +{ +} + +a2bus_videoterm_device::a2bus_videoterm_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + a2bus_videx80_device(mconfig, A2BUS_VIDEOTERM, "Videx VideoTerm", tag, owner, clock, "a2vidtrm", __FILE__) +{ +} + +a2bus_ap16_device::a2bus_ap16_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + a2bus_videx80_device(mconfig, A2BUS_IBSAP16, "IBS AP-16 80 column card", tag, owner, clock, "a2ap16", __FILE__) +{ +} + +a2bus_ap16alt_device::a2bus_ap16alt_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + a2bus_videx80_device(mconfig, A2BUS_IBSAP16ALT, "IBS AP-16 80 column card (alt. version)", tag, owner, clock, "a2ap16a", __FILE__) +{ +} + +a2bus_vtc1_device::a2bus_vtc1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + a2bus_videx80_device(mconfig, A2BUS_VTC1, "Unknown VideoTerm clone #1", tag, owner, clock, "a2vtc1", __FILE__) +{ +} + +a2bus_vtc2_device::a2bus_vtc2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + a2bus_videx80_device(mconfig, A2BUS_VTC2, "Unknown VideoTerm clone #2", tag, owner, clock, "a2vtc2", __FILE__) +{ +} + +a2bus_aevm80_device::a2bus_aevm80_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + a2bus_videx80_device(mconfig, A2BUS_AEVIEWMASTER80, "Applied Engineering Viewmaster 80", tag, owner, clock, "a2aevm80", __FILE__) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void a2bus_videx80_device::device_start() +{ + // set_a2bus_device makes m_slot valid + set_a2bus_device(); + + m_rom = device().machine().root_device().memregion(this->subtag(VIDEOTERM_ROM_REGION).c_str())->base(); + + m_chrrom = device().machine().root_device().memregion(this->subtag(VIDEOTERM_GFX_REGION).c_str())->base(); + + memset(m_ram, 0, 4*512); + + save_item(NAME(m_ram)); + save_item(NAME(m_framecnt)); + save_item(NAME(m_rambank)); +} + +void a2bus_videx80_device::device_reset() +{ + m_rambank = 0; + m_framecnt = 0; +} + + +/*------------------------------------------------- + read_c0nx - called for reads from this card's c0nx space +-------------------------------------------------*/ + +UINT8 a2bus_videx80_device::read_c0nx(address_space &space, UINT8 offset) +{ +// printf("Read c0n%x (PC=%x)\n", offset, space.device().safe_pc()); + + m_rambank = ((offset>>2) & 3) * 512; + + if (offset == 1) + { + return m_crtc->register_r(space, offset); // status_r? + } + + return 0xff; +} + + +/*------------------------------------------------- + write_c0nx - called for writes to this card's c0nx space +-------------------------------------------------*/ + +void a2bus_videx80_device::write_c0nx(address_space &space, UINT8 offset, UINT8 data) +{ +// printf("Write %02x to c0n%x (PC=%x)\n", data, offset, space.device().safe_pc()); + + if (offset == 0) + { + m_crtc->address_w(space, offset, data); + } + else if (offset == 1) + { + m_crtc->register_w(space, offset, data); + } + + m_rambank = ((offset>>2) & 3) * 512; +} + +/*------------------------------------------------- + read_cnxx - called for reads from this card's cnxx space +-------------------------------------------------*/ + +UINT8 a2bus_videx80_device::read_cnxx(address_space &space, UINT8 offset) +{ + return m_rom[offset+0x300]; +} + +UINT8 a2bus_ap16_device::read_cnxx(address_space &space, UINT8 offset) +{ + return m_rom[offset+0x1f00]; +} + +UINT8 a2bus_ap16alt_device::read_cnxx(address_space &space, UINT8 offset) +{ + return m_rom[offset+0xb00]; +} + +/*------------------------------------------------- + write_cnxx - called for writes to this card's cnxx space + the firmware writes here to switch in our $C800 a lot +-------------------------------------------------*/ +void a2bus_videx80_device::write_cnxx(address_space &space, UINT8 offset, UINT8 data) +{ +} + +/*------------------------------------------------- + read_c800 - called for reads from this card's c800 space +-------------------------------------------------*/ + +UINT8 a2bus_videx80_device::read_c800(address_space &space, UINT16 offset) +{ + // ROM at c800-cbff + // bankswitched RAM at cc00-cdff + if (offset < 0x400) + { +// printf("Read VRAM at %x = %02x\n", offset+m_rambank, m_ram[offset + m_rambank]); + return m_rom[offset]; + } + else + { + return m_ram[(offset-0x400) + m_rambank]; + } +} + +/*------------------------------------------------- + write_c800 - called for writes to this card's c800 space +-------------------------------------------------*/ +void a2bus_videx80_device::write_c800(address_space &space, UINT16 offset, UINT8 data) +{ + if (offset >= 0x400) + { +// printf("%02x to VRAM at %x\n", data, offset-0x400+m_rambank); + m_ram[(offset-0x400) + m_rambank] = data; + } +} + +MC6845_UPDATE_ROW( a2bus_videx80_device::crtc_update_row ) +{ + const rgb_t *palette = m_palette->palette()->entry_list_raw(); + UINT32 *p = &bitmap.pix32(y); + UINT16 chr_base = ra; //( ra & 0x08 ) ? 0x800 | ( ra & 0x07 ) : ra; + int i; + + for ( i = 0; i < x_count; i++ ) + { + UINT16 offset = ( ma + i ) & 0x7ff; + UINT8 chr = m_ram[ offset ]; + UINT8 data = m_chrrom[ chr_base + chr * 16 ]; + UINT8 fg = 15; + UINT8 bg = 0; + + if ( i == cursor_x ) + { + if ( m_framecnt & 0x08 ) + { + data = 0xFF; + } + } + + *p = palette[( data & 0x80 ) ? fg : bg]; p++; + *p = palette[( data & 0x40 ) ? fg : bg]; p++; + *p = palette[( data & 0x20 ) ? fg : bg]; p++; + *p = palette[( data & 0x10 ) ? fg : bg]; p++; + *p = palette[( data & 0x08 ) ? fg : bg]; p++; + *p = palette[( data & 0x04 ) ? fg : bg]; p++; + *p = palette[( data & 0x02 ) ? fg : bg]; p++; + *p = palette[( data & 0x01 ) ? fg : bg]; p++; + } +} + +WRITE_LINE_MEMBER( a2bus_videx80_device::vsync_changed ) +{ + if ( state ) + { + m_framecnt++; + } +} diff --git a/src/devices/bus/a2bus/a2videoterm.h b/src/devices/bus/a2bus/a2videoterm.h new file mode 100644 index 00000000000..3452430e4dc --- /dev/null +++ b/src/devices/bus/a2bus/a2videoterm.h @@ -0,0 +1,121 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/********************************************************************* + + a2videoterm.h + + Implementation of the Apple II Memory Expansion Card + +*********************************************************************/ + +#ifndef __A2BUS_VIDEOTERM__ +#define __A2BUS_VIDEOTERM__ + +#include "emu.h" +#include "a2bus.h" +#include "video/mc6845.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class a2bus_videx80_device: + public device_t, + public device_a2bus_card_interface +{ +public: + // construction/destruction + a2bus_videx80_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + + DECLARE_WRITE_LINE_MEMBER(vsync_changed); + MC6845_UPDATE_ROW(crtc_update_row); + + UINT8 *m_rom, *m_chrrom; + UINT8 m_ram[512*4]; + int m_framecnt; + +protected: + virtual void device_start(); + virtual void device_reset(); + + // overrides of standard a2bus slot functions + virtual UINT8 read_c0nx(address_space &space, UINT8 offset); + virtual void write_c0nx(address_space &space, UINT8 offset, UINT8 data); + virtual UINT8 read_cnxx(address_space &space, UINT8 offset); + virtual void write_cnxx(address_space &space, UINT8 offset, UINT8 data); + virtual UINT8 read_c800(address_space &space, UINT16 offset); + virtual void write_c800(address_space &space, UINT16 offset, UINT8 data); + + required_device m_crtc; + +private: + int m_rambank; +public: + required_device m_palette; +}; + +class a2bus_videoterm_device : public a2bus_videx80_device +{ +public: + a2bus_videoterm_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual const rom_entry *device_rom_region() const; +}; + +class a2bus_ap16_device : public a2bus_videx80_device +{ +public: + a2bus_ap16_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual const rom_entry *device_rom_region() const; + + virtual UINT8 read_cnxx(address_space &space, UINT8 offset); +}; + + +class a2bus_ap16alt_device : public a2bus_videx80_device +{ +public: + a2bus_ap16alt_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual const rom_entry *device_rom_region() const; + + virtual UINT8 read_cnxx(address_space &space, UINT8 offset); +}; + +class a2bus_vtc1_device : public a2bus_videx80_device +{ +public: + a2bus_vtc1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual const rom_entry *device_rom_region() const; +}; + +class a2bus_vtc2_device : public a2bus_videx80_device +{ +public: + a2bus_vtc2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual const rom_entry *device_rom_region() const; +}; + +class a2bus_aevm80_device : public a2bus_videx80_device +{ +public: + a2bus_aevm80_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual const rom_entry *device_rom_region() const; +}; + +// device type definition +extern const device_type A2BUS_VIDEOTERM; +extern const device_type A2BUS_IBSAP16; +extern const device_type A2BUS_IBSAP16ALT; +extern const device_type A2BUS_VTC1; +extern const device_type A2BUS_VTC2; +extern const device_type A2BUS_AEVIEWMASTER80; + +#endif /* __A2BUS_VIDEOTERM__ */ diff --git a/src/devices/bus/a2bus/a2vulcan.c b/src/devices/bus/a2bus/a2vulcan.c new file mode 100644 index 00000000000..ff155f25acd --- /dev/null +++ b/src/devices/bus/a2bus/a2vulcan.c @@ -0,0 +1,302 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/********************************************************************* + + a2vulcan.c + + Applied Engineering Vulcan IDE controller + + Our copy of ROM version 1.4 will refuse any drive > 40 megs (top 2 bytes of # blocks >= 0x15b). + Protection against field upgrades? + + Vulcan Gold ROMs omit this protection but don't work with the version of the partitioner program + we have. + + Recognized drives by IDE features parameters: + (# of cylinders is never checked, just heads, sectors, and the vendor specific at 0x0A) + + H S Vendor specific #5 + 8, 33 + 0x69 0x31d blocks (400K?!) + 2, 33 + 0x69 0xa208 blocks (20 megs, 21237760 bytes) + 4, 26 + 0x69 0x14500 blocks (40 megs, 42598400 bytes) + 5, 29 + (any) 0x25c5b blocks (80 megs, 79214080 bytes) (chs = 1067,5,29) + 7, 29 + 0x44 0x34e19 blocks (100 megs, 110899712 bytes) + 9, 29 + (any) 0x44068 blocks (140 megs, 142659584 bytes) (chs = 1068,9,29) + 9, 36 + 0x44 0x54888 blocks (180 megs, 177278976 bytes) + 9, 36 + 0xff 0x645a8 blocks (200 megs, 210456576 bytes) + 7, 34 + (any) 0x32252 blocks (100 megs, 105161728 bytes) (chs = 863,7,34) + 4, 17 + 0x55 0xa218 blocks (20 megs, 21245952 bytes) + 4, 26 + 0x55 0xa218 blocks (20 megs, 21245952 bytes) + 5, 17 + 0x55 0x15234 blocks (40 megs, 44328960 bytes) + 6, 26 + 0x55 0x15234 blocks (40 megs, 44328960 bytes) + 2, 28 + 0x36 0xa250 blocks (20 megs, 21274624 bytes) + 4, 28 + 0x36 0x143c0 blocks (40 megs, 42434450 bytes) + 4, 28 + 0x67 0x143c0 blocks (40 megs, 42434450 bytes) + 4, 27 + 0x43 0x147cc blocks (40 megs, 42964992 bytes) + 5, 17 + 0x26 0x13ec0 blocks (40 megs, 41779200 bytes) (chs = 960,5,17) + 15, 32 + 0x43 0x5f6e0 blocks (200 megs, 200130560 bytes) + 16, 38 + 0x94 0x6540c blocks (200 megs, 212342784 bytes) + 10, 17 + (any) 0x2792f blocks (80 megs, 82992640 bytes) (chs = 954,10,17) + + Partition block: + +0000: 0xAE 0xAE signature + +0002: bytesum of remaining 508 bytes of partition block + +0005: total # of blocks (3 bytes) + +000E: boot partition # (0 based) + +0100: partition records + + Partition record: + +02: partition number (seems to be only valud for non-CLEAR partitions) + +03: little-endian unsigned word: # of 512 byte blocks + +06: bit 6 set for ON, bits 0-2 = 0 CLEAR, 1 PRODOS, 2 DOS 3.3, 3 PASCAL, 4 CP/M + +07: Partition name (Apple high-ASCII, zero terminated unless full 10 chars) + +*********************************************************************/ + +#include "a2vulcan.h" +#include "includes/apple2.h" +#include "machine/ataintf.h" +#include "imagedev/harddriv.h" + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type A2BUS_VULCAN = &device_creator; +const device_type A2BUS_VULCANGOLD = &device_creator; + +#define VULCAN_ROM_REGION "vulcan_rom" +#define VULCAN_ATA_TAG "vulcan_ata" + +static MACHINE_CONFIG_FRAGMENT( vulcan ) + MCFG_ATA_INTERFACE_ADD(VULCAN_ATA_TAG, ata_devices, "hdd", NULL, false) +MACHINE_CONFIG_END + +ROM_START( vulcan ) + ROM_REGION(0x4000, VULCAN_ROM_REGION, 0) + ROM_LOAD( "ae vulcan rom v1.4.bin", 0x000000, 0x004000, CRC(798d5825) SHA1(1d668e856e33c6eeb10fe26975341afa8acb81f5) ) +ROM_END + +ROM_START( vulcangold ) + ROM_REGION(0x4000, VULCAN_ROM_REGION, 0) + ROM_LOAD( "ae vulcan gold rom v2.0.bin", 0x000000, 0x004000, CRC(19bc3958) SHA1(96a22c2540fa603648a4e638e176eee76523b4e1) ) +ROM_END + +/*************************************************************************** + FUNCTION PROTOTYPES +***************************************************************************/ + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor a2bus_vulcanbase_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( vulcan ); +} + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *a2bus_vulcan_device::device_rom_region() const +{ + return ROM_NAME( vulcan ); +} + +const rom_entry *a2bus_vulcangold_device::device_rom_region() const +{ + return ROM_NAME( vulcangold ); +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +a2bus_vulcanbase_device::a2bus_vulcanbase_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_a2bus_card_interface(mconfig, *this), + m_ata(*this, VULCAN_ATA_TAG) +{ +} + +a2bus_vulcan_device::a2bus_vulcan_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + a2bus_vulcanbase_device(mconfig, A2BUS_VULCAN, "Applied Engineering Vulcan IDE controller", tag, owner, clock, "a2vulcan", __FILE__) +{ +} + +a2bus_vulcangold_device::a2bus_vulcangold_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + a2bus_vulcanbase_device(mconfig, A2BUS_VULCAN, "Applied Engineering Vulcan Gold IDE controller", tag, owner, clock, "a2vulgld", __FILE__) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void a2bus_vulcanbase_device::device_start() +{ + // set_a2bus_device makes m_slot valid + set_a2bus_device(); + + m_rom = device().machine().root_device().memregion(this->subtag(VULCAN_ROM_REGION).c_str())->base(); + + save_item(NAME(m_lastdata)); + save_item(NAME(m_ram)); + save_item(NAME(m_rombank)); + save_item(NAME(m_rambank)); +} + +void a2bus_vulcan_device::device_start() +{ + // call base class + a2bus_vulcanbase_device::device_start(); + + // disable 40 meg partition size limit / protection in v1.4 ROMs + m_rom[0x59e] = 0xea; + m_rom[0x59f] = 0xea; +} + +void a2bus_vulcanbase_device::device_reset() +{ + m_rombank = m_rambank = 0; + m_last_read_was_0 = false; +} + + +/*------------------------------------------------- + read_c0nx - called for reads from this card's c0nx space +-------------------------------------------------*/ + +UINT8 a2bus_vulcanbase_device::read_c0nx(address_space &space, UINT8 offset) +{ + switch (offset) + { + case 0: + m_lastdata = m_ata->read_cs0(space, offset, 0xffff); +// printf("IDE: read %04x\n", m_lastdata); + m_last_read_was_0 = true; + return m_lastdata&0xff; + + case 1: + if (m_last_read_was_0) + { + m_last_read_was_0 = false; + return (m_lastdata>>8) & 0xff; + } + else + { + return m_ata->read_cs0(space, offset, 0xff); + } + + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + return m_ata->read_cs0(space, offset, 0xff); + + default: + logerror("a2vulcan: unknown read @ C0n%x\n", offset); + break; + + } + + return 0xff; +} + + +/*------------------------------------------------- + write_c0nx - called for writes to this card's c0nx space +-------------------------------------------------*/ + +void a2bus_vulcanbase_device::write_c0nx(address_space &space, UINT8 offset, UINT8 data) +{ + switch (offset) + { + case 0: + m_lastdata = data; + m_last_read_was_0 = true; + break; + + case 1: + if (m_last_read_was_0) + { + m_last_read_was_0 = false; + m_lastdata &= 0x00ff; + m_lastdata |= (data << 8); +// printf("IDE: write %04x\n", m_lastdata); + m_ata->write_cs0(space, 0, m_lastdata, 0xffff); + } + else + { + m_ata->write_cs0(space, offset, data, 0xff); + } + break; + + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: +// printf("%02x to IDE controller @ %x\n", data, offset); + m_ata->write_cs0(space, offset, data, 0xff); + break; + + case 9: // ROM bank +// printf("%x (%x) to ROM bank\n", data, (data & 0xf) * 0x400); + m_rombank = (data & 0xf) * 0x400; + break; + + case 0xa: // RAM bank +// printf("%x to RAM bank\n", data); + m_rambank = (data & 7) * 0x400; + break; + + default: + logerror("a2vulcan: write %02x @ unhandled C0n%x\n", data, offset); + break; + } +} + +/*------------------------------------------------- + read_cnxx - called for reads from this card's cnxx space +-------------------------------------------------*/ + +UINT8 a2bus_vulcanbase_device::read_cnxx(address_space &space, UINT8 offset) +{ + int slotimg = m_slot * 0x100; + + // ROM contains a CnXX image for each of slots 1-7 at 0x3400 + return m_rom[offset+slotimg+0x3400]; +} + +/*------------------------------------------------- + read_c800 - called for reads from this card's c800 space +-------------------------------------------------*/ + +UINT8 a2bus_vulcanbase_device::read_c800(address_space &space, UINT16 offset) +{ + offset &= 0x7ff; + if (offset < 0x400) // c800-cbff is banked RAM window, cc00-cfff is banked ROM window + { +// printf("read RAM @ %x (bank %x)\n", offset, m_rambank); + return m_ram[offset + m_rambank]; + } + + offset -= 0x400; + return m_rom[offset+m_rombank]; +} + +void a2bus_vulcanbase_device::write_c800(address_space &space, UINT16 offset, UINT8 data) +{ + offset &= 0x7ff; + if (offset < 0x400) + { +// printf("%02x to RAM @ %x (bank %x)\n", data, offset, m_rambank); + m_ram[offset + m_rambank] = data; + } +} diff --git a/src/devices/bus/a2bus/a2vulcan.h b/src/devices/bus/a2bus/a2vulcan.h new file mode 100644 index 00000000000..bcd9f6fa3b6 --- /dev/null +++ b/src/devices/bus/a2bus/a2vulcan.h @@ -0,0 +1,80 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/********************************************************************* + + a2vulcan.h + + Applied Engineering Vulcan and Vulcan Gold IDE controllers + +*********************************************************************/ + +#ifndef __A2BUS_VULCAN__ +#define __A2BUS_VULCAN__ + +#include "emu.h" +#include "a2bus.h" +#include "machine/ataintf.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class a2bus_vulcanbase_device: + public device_t, + public device_a2bus_card_interface +{ +public: + // construction/destruction + a2bus_vulcanbase_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + +protected: + virtual void device_start(); + virtual void device_reset(); + + // overrides of standard a2bus slot functions + virtual UINT8 read_c0nx(address_space &space, UINT8 offset); + virtual void write_c0nx(address_space &space, UINT8 offset, UINT8 data); + virtual UINT8 read_cnxx(address_space &space, UINT8 offset); + virtual UINT8 read_c800(address_space &space, UINT16 offset); + virtual void write_c800(address_space &space, UINT16 offset, UINT8 data); + + required_device m_ata; + + UINT8 *m_rom; + UINT8 m_ram[8*1024]; + +private: + UINT16 m_lastdata; + int m_rombank, m_rambank; + bool m_last_read_was_0; +}; + +class a2bus_vulcan_device : public a2bus_vulcanbase_device +{ +public: + a2bus_vulcan_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual const rom_entry *device_rom_region() const; + +protected: + virtual void device_start(); + +protected: +}; + +class a2bus_vulcangold_device : public a2bus_vulcanbase_device +{ +public: + a2bus_vulcangold_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual const rom_entry *device_rom_region() const; + +protected: +}; + +// device type definition +extern const device_type A2BUS_VULCAN; +extern const device_type A2BUS_VULCANGOLD; + +#endif /* __A2BUS_VULCAN__ */ diff --git a/src/devices/bus/a2bus/a2zipdrive.c b/src/devices/bus/a2bus/a2zipdrive.c new file mode 100644 index 00000000000..da958262e34 --- /dev/null +++ b/src/devices/bus/a2bus/a2zipdrive.c @@ -0,0 +1,198 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/********************************************************************* + + a2zipdrive.c + + ZIP Technologies ZipDrive IDE card + + NOTE: No known dump exists of the formatter utility and the + format of the custom partition record (block 0) that the card + expects has not yet been determined, so this is largely untested + and will work only with a drive dump from real h/w. + + PLEASE use it only on a backup copy of said dump and contact MESSdev + if you have one! + + Partition block format: + +0000: ASCII "Zip Technologies" + +*********************************************************************/ + +#include "a2zipdrive.h" +#include "includes/apple2.h" +#include "machine/ataintf.h" +#include "imagedev/harddriv.h" + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type A2BUS_ZIPDRIVE = &device_creator; + +#define ZIPDRIVE_ROM_REGION "zipdrive_rom" +#define ZIPDRIVE_ATA_TAG "zipdrive_ata" + +static MACHINE_CONFIG_FRAGMENT( zipdrive ) + MCFG_ATA_INTERFACE_ADD(ZIPDRIVE_ATA_TAG, ata_devices, "hdd", NULL, false) +MACHINE_CONFIG_END + +ROM_START( zipdrive ) + ROM_REGION(0x2000, ZIPDRIVE_ROM_REGION, 0) + ROM_LOAD( "zip drive - rom.bin", 0x000000, 0x002000, CRC(fd800a40) SHA1(46636bfed88c864139e3d2826661908a8c07c459) ) +ROM_END + +/*************************************************************************** + FUNCTION PROTOTYPES +***************************************************************************/ + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor a2bus_zipdrivebase_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( zipdrive ); +} + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *a2bus_zipdrivebase_device::device_rom_region() const +{ + return ROM_NAME( zipdrive ); +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +a2bus_zipdrivebase_device::a2bus_zipdrivebase_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_a2bus_card_interface(mconfig, *this), + m_ata(*this, ZIPDRIVE_ATA_TAG) +{ +} + +a2bus_zipdrive_device::a2bus_zipdrive_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + a2bus_zipdrivebase_device(mconfig, A2BUS_ZIPDRIVE, "Zip Technologies ZipDrive", tag, owner, clock, "a2zipdrv", __FILE__) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void a2bus_zipdrivebase_device::device_start() +{ + // set_a2bus_device makes m_slot valid + set_a2bus_device(); + + m_rom = device().machine().root_device().memregion(this->subtag(ZIPDRIVE_ROM_REGION).c_str())->base(); + + save_item(NAME(m_lastdata)); +} + +void a2bus_zipdrivebase_device::device_reset() +{ + popmessage("Zip Drive partition format unknown, contact MESSdev if you have the software or a drive dump!"); +} + + +/*------------------------------------------------- + read_c0nx - called for reads from this card's c0nx space +-------------------------------------------------*/ + +UINT8 a2bus_zipdrivebase_device::read_c0nx(address_space &space, UINT8 offset) +{ + switch (offset) + { + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + return m_ata->read_cs0(space, offset, 0xff); + + case 8: // data port + m_lastdata = m_ata->read_cs0(space, offset, 0xffff); +// printf("%04x @ IDE data\n", m_lastdata); + return m_lastdata&0xff; + + case 9: + return (m_lastdata>>8) & 0xff; + + default: + logerror("a2zipdrive: unhandled read @ C0n%x\n", offset); + break; + } + + return 0xff; +} + + +/*------------------------------------------------- + write_c0nx - called for writes to this card's c0nx space +-------------------------------------------------*/ + +void a2bus_zipdrivebase_device::write_c0nx(address_space &space, UINT8 offset, UINT8 data) +{ + switch (offset) + { + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: +// printf("%02x to IDE controller @ %x\n", data, offset); + m_ata->write_cs0(space, offset, data, 0xff); + break; + + case 8: +// printf("%02x to IDE data lo\n", data); + m_lastdata = data; + break; + + case 9: +// printf("%02x to IDE data hi\n", data); + m_lastdata &= 0x00ff; + m_lastdata |= (data << 8); + m_ata->write_cs0(space, 0, m_lastdata, 0xffff); + break; + + default: + logerror("a2zipdrive: write %02x @ unhandled C0n%x\n", data, offset); + break; + } +} + +/*------------------------------------------------- + read_cnxx - called for reads from this card's cnxx space +-------------------------------------------------*/ + +UINT8 a2bus_zipdrivebase_device::read_cnxx(address_space &space, UINT8 offset) +{ + int slotimg = m_slot * 0x100; + + // ROM contains CnXX images for each of slots 1-7 at 0x0 and 0x1000 + return m_rom[offset+slotimg+0x1000]; +} + +/*------------------------------------------------- + read_c800 - called for reads from this card's c800 space +-------------------------------------------------*/ + +UINT8 a2bus_zipdrivebase_device::read_c800(address_space &space, UINT16 offset) +{ + offset &= 0x7ff; + + return m_rom[offset+0x1800]; +} diff --git a/src/devices/bus/a2bus/a2zipdrive.h b/src/devices/bus/a2bus/a2zipdrive.h new file mode 100644 index 00000000000..195ad987f25 --- /dev/null +++ b/src/devices/bus/a2bus/a2zipdrive.h @@ -0,0 +1,65 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/********************************************************************* + + a2zipdrive.h + + ZIP Technologies ZipDrive IDE card + + See important NOTE at the top of a2zipdrive.c! + +*********************************************************************/ + +#ifndef __A2BUS_ZIPDRIVE__ +#define __A2BUS_ZIPDRIVE__ + +#include "emu.h" +#include "a2bus.h" +#include "machine/ataintf.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class a2bus_zipdrivebase_device: + public device_t, + public device_a2bus_card_interface +{ +public: + // construction/destruction + a2bus_zipdrivebase_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual const rom_entry *device_rom_region() const; + +protected: + virtual void device_start(); + virtual void device_reset(); + + // overrides of standard a2bus slot functions + virtual UINT8 read_c0nx(address_space &space, UINT8 offset); + virtual void write_c0nx(address_space &space, UINT8 offset, UINT8 data); + virtual UINT8 read_cnxx(address_space &space, UINT8 offset); + virtual UINT8 read_c800(address_space &space, UINT16 offset); + + required_device m_ata; + + UINT8 *m_rom; + +private: + UINT16 m_lastdata; +}; + +class a2bus_zipdrive_device : public a2bus_zipdrivebase_device +{ +public: + a2bus_zipdrive_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: +}; + +// device type definition +extern const device_type A2BUS_ZIPDRIVE; + +#endif /* __A2BUS_ZIPDRIVE__ */ diff --git a/src/devices/bus/a2bus/corvfdc01.c b/src/devices/bus/a2bus/corvfdc01.c new file mode 100644 index 00000000000..fc1adf2e269 --- /dev/null +++ b/src/devices/bus/a2bus/corvfdc01.c @@ -0,0 +1,281 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/********************************************************************* + + corvfdc01.c + + Implemention of the Corvus Systems CORVUS01 floppy controller + + Boot PROM 0.8 fixes this at: 8", 500 blocks total, 128 bytes/block, + 26 sectors/track, 77 tracks. + +*********************************************************************/ + +#include "corvfdc01.h" + +/*************************************************************************** + PARAMETERS +***************************************************************************/ + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type A2BUS_CORVFDC01 = &device_creator; + +#define FDC01_ROM_REGION "fdc01_rom" +#define FDC01_FDC_TAG "fdc01_fdc" + +FLOPPY_FORMATS_MEMBER( a2bus_corvfdc01_device::corv_floppy_formats ) + FLOPPY_IMD_FORMAT +FLOPPY_FORMATS_END + +static SLOT_INTERFACE_START( corv_floppies ) + SLOT_INTERFACE( "8sssd", FLOPPY_8_SSSD ) +SLOT_INTERFACE_END + +MACHINE_CONFIG_FRAGMENT( fdc01 ) + MCFG_FD1793_ADD(FDC01_FDC_TAG, XTAL_16MHz / 8) + MCFG_WD_FDC_INTRQ_CALLBACK(WRITELINE(a2bus_corvfdc01_device, intrq_w)) + MCFG_WD_FDC_DRQ_CALLBACK(WRITELINE(a2bus_corvfdc01_device, drq_w)) + MCFG_FLOPPY_DRIVE_ADD(FDC01_FDC_TAG":0", corv_floppies, "8sssd", a2bus_corvfdc01_device::corv_floppy_formats) + MCFG_FLOPPY_DRIVE_ADD(FDC01_FDC_TAG":1", corv_floppies, "8sssd", a2bus_corvfdc01_device::corv_floppy_formats) + MCFG_FLOPPY_DRIVE_ADD(FDC01_FDC_TAG":2", corv_floppies, "8sssd", a2bus_corvfdc01_device::corv_floppy_formats) + MCFG_FLOPPY_DRIVE_ADD(FDC01_FDC_TAG":3", corv_floppies, "8sssd", a2bus_corvfdc01_device::corv_floppy_formats) +MACHINE_CONFIG_END + +ROM_START( fdc01 ) + ROM_REGION(0x20, FDC01_ROM_REGION, 0) + ROM_LOAD( "ff01.bin", 0x000000, 0x000020, CRC(ad3c1136) SHA1(b1e1e8a10618588b1b44b3be5d88857497f30b33) ) +ROM_END + +enum +{ + LS_DRQ_bit = 0, // DRQ + LS_INT_bit = 1, // INT + LS_SS_bit = 4, // 1 if single-sided (floppy or drive?) + LS_8IN_bit = 5, // 1 if 8" floppy drive? + LS_DSKCHG_bit = 6, // 0 if disk changed, 1 if not + LS_SD_bit = 7, // 1 if single density + + LS_DRQ_mask = (1 << LS_DRQ_bit), + LS_INT_mask = (1 << LS_INT_bit), + LS_SS_mask = (1 << LS_SS_bit), + LS_8IN_mask = (1 << LS_8IN_bit), + LS_DSKCHG_mask = (1 << LS_DSKCHG_bit), + LS_SD_mask = (1 << LS_SD_bit) +}; + +enum +{ + LC_FLPSD1_bit = 0, // 0 if side 0 , 1 if side 1 + LC_DE0_bit = 1, // drive select bit 0 + LC_DE1_bit = 4, // drive select bit 1 + LC_MOTOROF_bit = 5, // 1 if motor to be turned off + LC_FLP8IN_bit = 6, // 1 to select 8", 0 for 5"1/4 (which I knew what it means) + LC_FMMFM_bit = 7, // 1 to select single density, 0 for double + + LC_FLPSD1_mask = (1 << LC_FLPSD1_bit), + LC_DE0_mask = (1 << LC_DE0_bit), + LC_DE1_mask = (1 << LC_DE1_bit), + LC_MOTOROF_mask = (1 << LC_MOTOROF_bit), + LC_FLP8IN_mask = (1 << LC_FLP8IN_bit), + LC_FMMFM_mask = (1 << LC_FMMFM_bit) +}; + +/*************************************************************************** + FUNCTION PROTOTYPES +***************************************************************************/ + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor a2bus_corvfdc01_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( fdc01 ); +} + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *a2bus_corvfdc01_device::device_rom_region() const +{ + return ROM_NAME( fdc01 ); +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +a2bus_corvfdc01_device::a2bus_corvfdc01_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_a2bus_card_interface(mconfig, *this), + m_wdfdc(*this, FDC01_FDC_TAG), + m_con1(*this, FDC01_FDC_TAG":0"), + m_con2(*this, FDC01_FDC_TAG":1"), + m_con3(*this, FDC01_FDC_TAG":2"), + m_con4(*this, FDC01_FDC_TAG":3") +{ +} + +a2bus_corvfdc01_device::a2bus_corvfdc01_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, A2BUS_CORVFDC01, "Corvus Systems Floppy Controller", tag, owner, clock, "crvfdc01", __FILE__), + device_a2bus_card_interface(mconfig, *this), + m_wdfdc(*this, FDC01_FDC_TAG), + m_con1(*this, FDC01_FDC_TAG":0"), + m_con2(*this, FDC01_FDC_TAG":1"), + m_con3(*this, FDC01_FDC_TAG":2"), + m_con4(*this, FDC01_FDC_TAG":3") +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void a2bus_corvfdc01_device::device_start() +{ + // set_a2bus_device makes m_slot valid + set_a2bus_device(); + + m_rom = device().machine().root_device().memregion(this->subtag(FDC01_ROM_REGION).c_str())->base(); + + save_item(NAME(m_fdc_local_status)); + save_item(NAME(m_fdc_local_command)); +} + +void a2bus_corvfdc01_device::device_reset() +{ + m_fdc_local_status = 0; + m_fdc_local_command = 0; + m_curfloppy = NULL; +} + +/*------------------------------------------------- + read_c0nx - called for reads from this card's c0nx space +-------------------------------------------------*/ + +UINT8 a2bus_corvfdc01_device::read_c0nx(address_space &space, UINT8 offset) +{ + switch (offset) + { + case 0: // local status + if (m_curfloppy) + { + m_fdc_local_status &= ~LS_DSKCHG_mask; + m_fdc_local_status |= m_curfloppy->dskchg_r() ? LS_DSKCHG_mask : 0; + } + return m_fdc_local_status | LS_8IN_mask; + + case 8: // WD1793 at 8-11 + return m_wdfdc->status_r(space, offset); + + case 9: + return m_wdfdc->track_r(space, offset); + + case 10: + return m_wdfdc->sector_r(space, offset); + + case 11: + return m_wdfdc->data_r(space, offset); + } + + return 0xff; +} + + +/*------------------------------------------------- + write_c0nx - called for writes to this card's c0nx space +-------------------------------------------------*/ + +void a2bus_corvfdc01_device::write_c0nx(address_space &space, UINT8 offset, UINT8 data) +{ + int current_drive; + floppy_image_device *floppy = 0; + + switch (offset) + { + case 0: // LOCAL COMMAND REG + m_fdc_local_command = data; + + current_drive = ((data >> LC_DE0_bit) & 1) | ((data >> (LC_DE1_bit-1)) & 2); + switch (current_drive) + { + case 0: + floppy = m_con1 ? m_con1->get_device() : 0; + break; + case 1: + floppy = m_con2 ? m_con2->get_device() : 0; + break; + case 2: + floppy = m_con3 ? m_con3->get_device() : 0; + break; + case 3: + floppy = m_con4 ? m_con4->get_device() : 0; + break; + } + + if (floppy != m_curfloppy) + { + m_wdfdc->set_floppy(floppy); + } + + if (m_curfloppy != NULL) + { + // side select + m_curfloppy->ss_w((data & LC_FLPSD1_mask) != 0); + + // motor control (active low) + m_curfloppy->mon_w((data & LC_MOTOROF_mask) ? 1 : 0); + } + + /*flp_8in = (data & LC_FLP8IN_mask) != 0;*/ + + m_wdfdc->dden_w(BIT(data, LC_FMMFM_bit)); + break; + + case 8: // FDC COMMAMD REG + m_wdfdc->cmd_w(space, offset, data); + break; + + case 9: // FDC TRACK REG + m_wdfdc->track_w(space, offset, data); + break; + + case 10: // FDC SECTOR REG + m_wdfdc->sector_w(space, offset, data); + break; + + case 11: // FDC DATA REG + m_wdfdc->data_w(space, offset, data); + break; + } +} + +/*------------------------------------------------- + read_cnxx - called for reads from this card's cnxx space +-------------------------------------------------*/ + +UINT8 a2bus_corvfdc01_device::read_cnxx(address_space &space, UINT8 offset) +{ + return m_rom[offset & 0x1f]; +} + +WRITE_LINE_MEMBER(a2bus_corvfdc01_device::intrq_w) +{ + if (state) + m_fdc_local_status |= LS_INT_mask; + else + m_fdc_local_status &= ~LS_INT_mask; +} + +WRITE_LINE_MEMBER(a2bus_corvfdc01_device::drq_w) +{ + if (state) + m_fdc_local_status |= LS_DRQ_mask; + else + m_fdc_local_status &= ~LS_DRQ_mask; +} diff --git a/src/devices/bus/a2bus/corvfdc01.h b/src/devices/bus/a2bus/corvfdc01.h new file mode 100644 index 00000000000..2299f77cbd7 --- /dev/null +++ b/src/devices/bus/a2bus/corvfdc01.h @@ -0,0 +1,65 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/********************************************************************* + + corvfdc01.h + + Implemention of the Corvus Systems CORVUS01 floppy controller + +*********************************************************************/ + +#ifndef __A2BUS_CORVFDC01__ +#define __A2BUS_CORVFDC01__ + +#include "emu.h" +#include "a2bus.h" +#include "machine/wd_fdc.h" +#include "formats/imd_dsk.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class a2bus_corvfdc01_device: + public device_t, + public device_a2bus_card_interface +{ +public: + // construction/destruction + a2bus_corvfdc01_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + a2bus_corvfdc01_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual const rom_entry *device_rom_region() const; + + DECLARE_WRITE_LINE_MEMBER(intrq_w); + DECLARE_WRITE_LINE_MEMBER(drq_w); + + DECLARE_FLOPPY_FORMATS(corv_floppy_formats); + +protected: + virtual void device_start(); + virtual void device_reset(); + + // overrides of standard a2bus slot functions + virtual UINT8 read_c0nx(address_space &space, UINT8 offset); + virtual void write_c0nx(address_space &space, UINT8 offset, UINT8 data); + virtual UINT8 read_cnxx(address_space &space, UINT8 offset); + + required_device m_wdfdc; + required_device m_con1; + required_device m_con2; + required_device m_con3; + required_device m_con4; + +private: + UINT8 *m_rom; + UINT8 m_fdc_local_status, m_fdc_local_command; + floppy_image_device *m_curfloppy; +}; + +// device type definition +extern const device_type A2BUS_CORVFDC01; + +#endif /* __A2BUS_CORVFDC01__ */ diff --git a/src/devices/bus/a2bus/corvfdc02.c b/src/devices/bus/a2bus/corvfdc02.c new file mode 100644 index 00000000000..eaad8725d1f --- /dev/null +++ b/src/devices/bus/a2bus/corvfdc02.c @@ -0,0 +1,299 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/********************************************************************* + + corvfdc02.c + + Implemention of the Corvus Systems CORVUS02 floppy controller + aka the "Buffered Floppy Controller" + + Boot PROM 0.8 says 8" SSDD or 5.25" DSDD; we stick with 5.25" here + and let the FDC01 handle 8". + +*********************************************************************/ + +#include "corvfdc02.h" +#include "formats/concept_dsk.h" + +/*************************************************************************** + PARAMETERS +***************************************************************************/ + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type A2BUS_CORVFDC02 = &device_creator; + +#define FDC02_ROM_REGION "fdc02_rom" +#define FDC02_FDC_TAG "fdc02_fdc" + +FLOPPY_FORMATS_MEMBER( a2bus_corvfdc02_device::corv_floppy_formats ) + FLOPPY_CONCEPT_525DSDD_FORMAT, + FLOPPY_IMD_FORMAT +FLOPPY_FORMATS_END + +static SLOT_INTERFACE_START( corv_floppies ) + SLOT_INTERFACE( "525dsqd", FLOPPY_525_QD ) +SLOT_INTERFACE_END + + +MACHINE_CONFIG_FRAGMENT( fdc02 ) + MCFG_UPD765A_ADD(FDC02_FDC_TAG, true, false) + MCFG_UPD765_INTRQ_CALLBACK(WRITELINE(a2bus_corvfdc02_device, intrq_w)) + MCFG_UPD765_DRQ_CALLBACK(WRITELINE(a2bus_corvfdc02_device, drq_w)) + MCFG_FLOPPY_DRIVE_ADD(FDC02_FDC_TAG":0", corv_floppies, "525dsqd", a2bus_corvfdc02_device::corv_floppy_formats) + MCFG_FLOPPY_DRIVE_ADD(FDC02_FDC_TAG":1", corv_floppies, "525dsqd", a2bus_corvfdc02_device::corv_floppy_formats) + MCFG_FLOPPY_DRIVE_ADD(FDC02_FDC_TAG":2", corv_floppies, "525dsqd", a2bus_corvfdc02_device::corv_floppy_formats) + MCFG_FLOPPY_DRIVE_ADD(FDC02_FDC_TAG":3", corv_floppies, "525dsqd", a2bus_corvfdc02_device::corv_floppy_formats) +MACHINE_CONFIG_END + +ROM_START( fdc02 ) + ROM_REGION(0x20, FDC02_ROM_REGION, 0) + ROM_LOAD( "bfc00.bin", 0x000000, 0x000020, CRC(98d1a765) SHA1(d27c3c6921e1bb3778a3f78decf106275bc0add1) ) +ROM_END + +/*************************************************************************** + FUNCTION PROTOTYPES +***************************************************************************/ + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor a2bus_corvfdc02_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( fdc02 ); +} + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *a2bus_corvfdc02_device::device_rom_region() const +{ + return ROM_NAME( fdc02 ); +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +a2bus_corvfdc02_device::a2bus_corvfdc02_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_a2bus_card_interface(mconfig, *this), + m_fdc(*this, FDC02_FDC_TAG), + m_con1(*this, FDC02_FDC_TAG":0"), + m_con2(*this, FDC02_FDC_TAG":1"), + m_con3(*this, FDC02_FDC_TAG":2"), + m_con4(*this, FDC02_FDC_TAG":3") +{ +} + +a2bus_corvfdc02_device::a2bus_corvfdc02_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, A2BUS_CORVFDC02, "Corvus Systems Buffered Floppy Controller", tag, owner, clock, "crvfdc02", __FILE__), + device_a2bus_card_interface(mconfig, *this), + m_fdc(*this, FDC02_FDC_TAG), + m_con1(*this, FDC02_FDC_TAG":0"), + m_con2(*this, FDC02_FDC_TAG":1"), + m_con3(*this, FDC02_FDC_TAG":2"), + m_con4(*this, FDC02_FDC_TAG":3") +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void a2bus_corvfdc02_device::device_start() +{ + // set_a2bus_device makes m_slot valid + set_a2bus_device(); + + m_rom = device().machine().root_device().memregion(this->subtag(FDC02_ROM_REGION).c_str())->base(); + + m_timer = timer_alloc(0); + + save_item(NAME(m_fdc_local_status)); + save_item(NAME(m_fdc_local_command)); + save_item(NAME(m_bufptr)); + save_item(NAME(m_buffer)); +} + +void a2bus_corvfdc02_device::device_reset() +{ + m_fdc_local_status = 2; + m_fdc_local_command = 0; + m_curfloppy = NULL; + m_in_drq = false; + m_timer->adjust(attotime::never); +} + +void a2bus_corvfdc02_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + m_fdc->tc_w(true); + m_fdc->tc_w(false); +} + +/*------------------------------------------------- + read_c0nx - called for reads from this card's c0nx space +-------------------------------------------------*/ + +UINT8 a2bus_corvfdc02_device::read_c0nx(address_space &space, UINT8 offset) +{ + switch (offset) + { + case 0: // 765 FIFO + return m_fdc->fifo_r(space, 0); + + case 1: // 765 MSR + return m_fdc->msr_r(space, 0); + + case 2: // buffer address + return (m_bufptr>>1) & 0xff; + + case 3: +// printf("Read buffer @ %x = %02x\n", m_bufptr, m_buffer[m_bufptr]); + return m_buffer[m_bufptr--]; + + case 4: // local status + if (m_curfloppy) + { + m_fdc_local_status &= ~(1 | 0x40); + m_fdc_local_status |= m_curfloppy->dskchg_r() ? 1 : 0; + m_fdc_local_status |= m_curfloppy->ready_r() ? 0x40 : 0; + } + return m_fdc_local_status; + break; + } + + return 0xff; +} + + +/*------------------------------------------------- + write_c0nx - called for writes to this card's c0nx space +-------------------------------------------------*/ + +void a2bus_corvfdc02_device::write_c0nx(address_space &space, UINT8 offset, UINT8 data) +{ + floppy_image_device *floppy = NULL; + + switch (offset) + { + case 0: // FDC FIFO write + m_fdc->fifo_w(space, offset, data); + break; + + case 1: // FDC ??? + break; + + case 2: // buffer address + m_bufptr = (data << 1) | (data & 1); +// printf("%02x to buffer address yields %x\n", data, m_bufptr); + break; + + case 3: // buffer write +// printf("%02x to buffer[%x]\n", data, m_bufptr); + m_buffer[m_bufptr--] = data; + break; + + case 4: // LOCAL COMMAND REG + m_fdc_local_command = data; + + // drive select enabled? + if (data & 4) + { + switch (data & 3) + { + case 0: + floppy = m_con1 ? m_con1->get_device() : 0; + break; + case 1: + floppy = m_con2 ? m_con2->get_device() : 0; + break; + case 2: + floppy = m_con3 ? m_con3->get_device() : 0; + break; + case 3: + floppy = m_con4 ? m_con4->get_device() : 0; + break; + } + + logerror("corvfdc02: selecting drive %d: %p\n", data & 3, (void *) floppy); + + if (floppy != m_curfloppy) + { + m_fdc->set_floppy(floppy); + m_curfloppy = floppy; + } + } + + if (m_curfloppy != NULL) + { + // motor control (active low) + m_curfloppy->mon_w((data & 8) ? 1 : 0); +// printf("Cur drive %p motor %s\n", m_curfloppy, (data & 8) ? "OFF" : "ON"); + } + + if (data & 0x80) + { +// printf("Reset NEC765\n"); + m_fdc->reset(); + } + break; + } +} + +/*------------------------------------------------- + read_cnxx - called for reads from this card's cnxx space +-------------------------------------------------*/ + +UINT8 a2bus_corvfdc02_device::read_cnxx(address_space &space, UINT8 offset) +{ + return m_rom[offset & 0x1f]; +} + +WRITE_LINE_MEMBER(a2bus_corvfdc02_device::intrq_w) +{ + if (state) + { + m_fdc_local_status &= ~2; // indicate IRQ occurred + if (m_fdc_local_command & 0x20) + { + raise_slot_irq(); + } + } + else + { + m_fdc_local_status |= 2; // clear IRQ + lower_slot_irq(); + } +} + +WRITE_LINE_MEMBER(a2bus_corvfdc02_device::drq_w) +{ + if (state) + { + // pseudo-DMA direction? + if (m_fdc_local_command & 0x40) + { + m_buffer[m_bufptr] = m_fdc->dma_r(); +// printf("DMA %02x to buffer[%x]\n", m_buffer[m_bufptr], m_bufptr); + + if (!m_bufptr) + { + m_timer->adjust(attotime::zero); + } + + m_bufptr--; + m_bufptr &= 0x1ff; + } + else + { + m_fdc->dma_w(m_buffer[m_bufptr++]); + m_bufptr &= 0x1ff; + } + } +} diff --git a/src/devices/bus/a2bus/corvfdc02.h b/src/devices/bus/a2bus/corvfdc02.h new file mode 100644 index 00000000000..982c0486160 --- /dev/null +++ b/src/devices/bus/a2bus/corvfdc02.h @@ -0,0 +1,70 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/********************************************************************* + + corvfdc02.h + + Implemention of the Corvus Systems CORVUS02 floppy controller + +*********************************************************************/ + +#ifndef __A2BUS_CORVFDC02__ +#define __A2BUS_CORVFDC02__ + +#include "emu.h" +#include "a2bus.h" +#include "machine/upd765.h" +#include "formats/imd_dsk.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class a2bus_corvfdc02_device: + public device_t, + public device_a2bus_card_interface +{ +public: + // construction/destruction + a2bus_corvfdc02_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + a2bus_corvfdc02_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual const rom_entry *device_rom_region() const; + + DECLARE_WRITE_LINE_MEMBER(intrq_w); + DECLARE_WRITE_LINE_MEMBER(drq_w); + + DECLARE_FLOPPY_FORMATS(corv_floppy_formats); + +protected: + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + // overrides of standard a2bus slot functions + virtual UINT8 read_c0nx(address_space &space, UINT8 offset); + virtual void write_c0nx(address_space &space, UINT8 offset, UINT8 data); + virtual UINT8 read_cnxx(address_space &space, UINT8 offset); + + required_device m_fdc; + required_device m_con1; + required_device m_con2; + required_device m_con3; + required_device m_con4; + +private: + UINT8 *m_rom; + UINT8 m_fdc_local_status, m_fdc_local_command; + UINT16 m_bufptr; + UINT8 m_buffer[2048]; // 1x6116 SRAM + floppy_image_device *m_curfloppy; + bool m_in_drq; + emu_timer *m_timer; +}; + +// device type definition +extern const device_type A2BUS_CORVFDC02; + +#endif /* __A2BUS_CORVFDC02__ */ diff --git a/src/devices/bus/a2bus/ezcgi.c b/src/devices/bus/a2bus/ezcgi.c new file mode 100644 index 00000000000..e85db228ad2 --- /dev/null +++ b/src/devices/bus/a2bus/ezcgi.c @@ -0,0 +1,315 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/********************************************************************* + + ezcgi.c + + "E-Z Color Graphics Interface" by Steve Ciarcia + from BYTE Magazine, August, 1982 + https://archive.org/details/byte-magazine-1982-08-rescan + +*********************************************************************/ + +#include "emu.h" +#include "ezcgi.h" + + +/*************************************************************************** + PARAMETERS +***************************************************************************/ + +#define TMS_TAG "ezcgi_tms" +#define SCREEN_TAG "screen" + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type A2BUS_EZCGI = &device_creator; +const device_type A2BUS_EZCGI_9938 = &device_creator; +const device_type A2BUS_EZCGI_9958 = &device_creator; + +MACHINE_CONFIG_FRAGMENT( ezcgi ) + MCFG_DEVICE_ADD( TMS_TAG, TMS9918A, XTAL_10_738635MHz / 2 ) + MCFG_TMS9928A_VRAM_SIZE(0x4000) // 16k of VRAM + MCFG_TMS9928A_OUT_INT_LINE_CB(WRITELINE(a2bus_ezcgi_device, tms_irq_w)) + MCFG_TMS9928A_SCREEN_ADD_NTSC( SCREEN_TAG ) + MCFG_SCREEN_UPDATE_DEVICE( TMS_TAG, tms9918a_device, screen_update ) +MACHINE_CONFIG_END + +#define MSX2_XBORDER_PIXELS 16 +#define MSX2_YBORDER_PIXELS 28 +#define MSX2_TOTAL_XRES_PIXELS 256 * 2 + (MSX2_XBORDER_PIXELS * 2) +#define MSX2_TOTAL_YRES_PIXELS 212 * 2 + (MSX2_YBORDER_PIXELS * 2) +#define MSX2_VISIBLE_XBORDER_PIXELS 8 * 2 +#define MSX2_VISIBLE_YBORDER_PIXELS 14 * 2 + +MACHINE_CONFIG_FRAGMENT( ezcgi9938 ) + MCFG_V9938_ADD(TMS_TAG, SCREEN_TAG, 0x30000, XTAL_21_4772MHz) // 192K of VRAM / typical 9938 clock, not verified + MCFG_V99X8_INTERRUPT_CALLBACK(WRITELINE(a2bus_ezcgi_9938_device, tms_irq_w)) + + MCFG_SCREEN_ADD(SCREEN_TAG, RASTER) + MCFG_SCREEN_VIDEO_ATTRIBUTES(VIDEO_UPDATE_BEFORE_VBLANK) + MCFG_SCREEN_REFRESH_RATE(60) + MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(2500)) /* not accurate */ + MCFG_SCREEN_UPDATE_DEVICE(TMS_TAG, v9938_device, screen_update) + MCFG_SCREEN_SIZE(MSX2_TOTAL_XRES_PIXELS, 262*2) + MCFG_SCREEN_VISIBLE_AREA(MSX2_XBORDER_PIXELS - MSX2_VISIBLE_XBORDER_PIXELS, MSX2_TOTAL_XRES_PIXELS - MSX2_XBORDER_PIXELS + MSX2_VISIBLE_XBORDER_PIXELS - 1, MSX2_YBORDER_PIXELS - MSX2_VISIBLE_YBORDER_PIXELS, MSX2_TOTAL_YRES_PIXELS - MSX2_YBORDER_PIXELS + MSX2_VISIBLE_YBORDER_PIXELS - 1) + MCFG_SCREEN_PALETTE("ezcgi_tms:palette") +MACHINE_CONFIG_END + +MACHINE_CONFIG_FRAGMENT( ezcgi9958 ) + MCFG_V9958_ADD(TMS_TAG, SCREEN_TAG, 0x30000, XTAL_21_4772MHz) // 192K of VRAM / typcial 9938/9958 clock, not verified + MCFG_V99X8_INTERRUPT_CALLBACK(WRITELINE(a2bus_ezcgi_9958_device, tms_irq_w)) + + MCFG_SCREEN_ADD(SCREEN_TAG, RASTER) + MCFG_SCREEN_VIDEO_ATTRIBUTES(VIDEO_UPDATE_BEFORE_VBLANK) + MCFG_SCREEN_REFRESH_RATE(60) + MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(2500)) /* not accurate */ + MCFG_SCREEN_UPDATE_DEVICE(TMS_TAG, v9938_device, screen_update) + MCFG_SCREEN_SIZE(MSX2_TOTAL_XRES_PIXELS, 262*2) + MCFG_SCREEN_VISIBLE_AREA(MSX2_XBORDER_PIXELS - MSX2_VISIBLE_XBORDER_PIXELS, MSX2_TOTAL_XRES_PIXELS - MSX2_XBORDER_PIXELS + MSX2_VISIBLE_XBORDER_PIXELS - 1, MSX2_YBORDER_PIXELS - MSX2_VISIBLE_YBORDER_PIXELS, MSX2_TOTAL_YRES_PIXELS - MSX2_YBORDER_PIXELS + MSX2_VISIBLE_YBORDER_PIXELS - 1) + MCFG_SCREEN_PALETTE("ezcgi_tms:palette") +MACHINE_CONFIG_END + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor a2bus_ezcgi_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( ezcgi ); +} + +machine_config_constructor a2bus_ezcgi_9938_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( ezcgi9938 ); +} + +machine_config_constructor a2bus_ezcgi_9958_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( ezcgi9958 ); +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +a2bus_ezcgi_device::a2bus_ezcgi_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, A2BUS_EZCGI, "E-Z Color Graphics Interface", tag, owner, clock, "a2ezcgi", __FILE__), + device_a2bus_card_interface(mconfig, *this), + m_tms(*this, TMS_TAG) +{ +} + +a2bus_ezcgi_device::a2bus_ezcgi_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_a2bus_card_interface(mconfig, *this), + m_tms(*this, TMS_TAG) +{ +} + +a2bus_ezcgi_9938_device::a2bus_ezcgi_9938_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, A2BUS_EZCGI_9938, "E-Z Color Graphics Interface (TMS9938)", tag, owner, clock, "a2ezcgi3", __FILE__), + device_a2bus_card_interface(mconfig, *this), + m_tms(*this, TMS_TAG) +{ +} + +a2bus_ezcgi_9938_device::a2bus_ezcgi_9938_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_a2bus_card_interface(mconfig, *this), + m_tms(*this, TMS_TAG) +{ +} + +a2bus_ezcgi_9958_device::a2bus_ezcgi_9958_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, A2BUS_EZCGI_9958, "E-Z Color Graphics Interface (TMS9958)", tag, owner, clock, "a2ezcgi5", __FILE__), + device_a2bus_card_interface(mconfig, *this), + m_tms(*this, TMS_TAG) +{ +} + +a2bus_ezcgi_9958_device::a2bus_ezcgi_9958_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_a2bus_card_interface(mconfig, *this), + m_tms(*this, TMS_TAG) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void a2bus_ezcgi_device::device_start() +{ + // set_a2bus_device makes m_slot valid + set_a2bus_device(); +} + +void a2bus_ezcgi_device::device_reset() +{ +} + +void a2bus_ezcgi_9938_device::device_start() +{ + // set_a2bus_device makes m_slot valid + set_a2bus_device(); +} + +void a2bus_ezcgi_9938_device::device_reset() +{ +} + +void a2bus_ezcgi_9958_device::device_start() +{ + // set_a2bus_device makes m_slot valid + set_a2bus_device(); +} + +void a2bus_ezcgi_9958_device::device_reset() +{ +} + +/* + C0nx map: + 0 - TMS read + 1 - TMS write +*/ + +UINT8 a2bus_ezcgi_device::read_c0nx(address_space &space, UINT8 offset) +{ + switch (offset) + { + case 0: + return m_tms->vram_read(space, 0); + + case 1: + return m_tms->register_read(space, 0); + } + + return 0xff; +} + +void a2bus_ezcgi_device::write_c0nx(address_space &space, UINT8 offset, UINT8 data) +{ + switch (offset) + { + case 0: + m_tms->vram_write(space, 0, data); + break; + + case 1: + m_tms->register_write(space, 0, data); + break; + } +} + +UINT8 a2bus_ezcgi_9938_device::read_c0nx(address_space &space, UINT8 offset) +{ + switch (offset) + { + case 0: + return m_tms->vram_r(); + + case 1: + return m_tms->status_r(); + } + + return 0xff; +} + +void a2bus_ezcgi_9938_device::write_c0nx(address_space &space, UINT8 offset, UINT8 data) +{ + switch (offset) + { + case 0: + m_tms->vram_w(data); + break; + + case 1: + m_tms->command_w(data); + break; + + case 2: + m_tms->palette_w(data); + break; + + case 3: + m_tms->register_w(data); + break; + } +} + +UINT8 a2bus_ezcgi_9958_device::read_c0nx(address_space &space, UINT8 offset) +{ + switch (offset) + { + case 0: + return m_tms->vram_r(); + + case 1: + return m_tms->status_r(); + } + + return 0xff; +} + +void a2bus_ezcgi_9958_device::write_c0nx(address_space &space, UINT8 offset, UINT8 data) +{ + switch (offset) + { + case 0: + m_tms->vram_w(data); + break; + + case 1: + m_tms->command_w(data); + break; + + case 2: + m_tms->palette_w(data); + break; + + case 3: + m_tms->register_w(data); + break; + } +} + +WRITE_LINE_MEMBER( a2bus_ezcgi_device::tms_irq_w ) +{ + if (state) + { + raise_slot_irq(); + } + else + { + lower_slot_irq(); + } +} + +WRITE_LINE_MEMBER( a2bus_ezcgi_9938_device::tms_irq_w ) +{ + if (state) + { + raise_slot_irq(); + } + else + { + lower_slot_irq(); + } +} + +WRITE_LINE_MEMBER( a2bus_ezcgi_9958_device::tms_irq_w ) +{ + if (state) + { + raise_slot_irq(); + } + else + { + lower_slot_irq(); + } +} diff --git a/src/devices/bus/a2bus/ezcgi.h b/src/devices/bus/a2bus/ezcgi.h new file mode 100644 index 00000000000..ef1e6e397de --- /dev/null +++ b/src/devices/bus/a2bus/ezcgi.h @@ -0,0 +1,111 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/********************************************************************* + + ezcgi.h + + "E-Z Color Graphics Interface" by Steve Ciarcia + from BYTE Magazine, August, 1982 + https://archive.org/details/byte-magazine-1982-08-rescan + +*********************************************************************/ + +#ifndef __A2BUS_EZCGI__ +#define __A2BUS_EZCGI__ + +#include "emu.h" +#include "a2bus.h" +#include "video/tms9928a.h" +#include "video/v9938.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class a2bus_ezcgi_device: + public device_t, + public device_a2bus_card_interface +{ +public: + // construction/destruction + a2bus_ezcgi_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + a2bus_ezcgi_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + + DECLARE_WRITE_LINE_MEMBER( tms_irq_w ); + +protected: + virtual void device_start(); + virtual void device_reset(); + + // overrides of standard a2bus slot functions + virtual UINT8 read_c0nx(address_space &space, UINT8 offset); + virtual void write_c0nx(address_space &space, UINT8 offset, UINT8 data); + + required_device m_tms; + +private: +}; + +class a2bus_ezcgi_9938_device: + public device_t, + public device_a2bus_card_interface +{ +public: + // construction/destruction + a2bus_ezcgi_9938_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + a2bus_ezcgi_9938_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + + DECLARE_WRITE_LINE_MEMBER( tms_irq_w ); + +protected: + virtual void device_start(); + virtual void device_reset(); + + // overrides of standard a2bus slot functions + virtual UINT8 read_c0nx(address_space &space, UINT8 offset); + virtual void write_c0nx(address_space &space, UINT8 offset, UINT8 data); + + required_device m_tms; + +private: +}; + +class a2bus_ezcgi_9958_device: + public device_t, + public device_a2bus_card_interface +{ +public: + // construction/destruction + a2bus_ezcgi_9958_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + a2bus_ezcgi_9958_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + + DECLARE_WRITE_LINE_MEMBER( tms_irq_w ); + +protected: + virtual void device_start(); + virtual void device_reset(); + + // overrides of standard a2bus slot functions + virtual UINT8 read_c0nx(address_space &space, UINT8 offset); + virtual void write_c0nx(address_space &space, UINT8 offset, UINT8 data); + + required_device m_tms; + +private: +}; + +// device type definition +extern const device_type A2BUS_EZCGI; +extern const device_type A2BUS_EZCGI_9938; +extern const device_type A2BUS_EZCGI_9958; + +#endif /* __A2BUS_EZCGI__ */ diff --git a/src/devices/bus/a2bus/laser128.c b/src/devices/bus/a2bus/laser128.c new file mode 100644 index 00000000000..c64719ba7e5 --- /dev/null +++ b/src/devices/bus/a2bus/laser128.c @@ -0,0 +1,146 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/********************************************************************* + + laser128.c + + Helper to implement the Laser 128's built-in slot peripherals + +*********************************************************************/ + +#include "laser128.h" +#include "includes/apple2.h" + +/*************************************************************************** + PARAMETERS +***************************************************************************/ + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type A2BUS_LASER128 = &device_creator; + +MACHINE_CONFIG_FRAGMENT( a2laser128 ) +MACHINE_CONFIG_END + +/*************************************************************************** + FUNCTION PROTOTYPES +***************************************************************************/ + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor a2bus_laser128_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( a2laser128 ); +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +a2bus_laser128_device::a2bus_laser128_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_a2bus_card_interface(mconfig, *this) + +{ +} + +a2bus_laser128_device::a2bus_laser128_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, A2BUS_LASER128, "VTech Laser 128 Internal Device", tag, owner, clock, "a2laser128", __FILE__), + device_a2bus_card_interface(mconfig, *this) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void a2bus_laser128_device::device_start() +{ + // set_a2bus_device makes m_slot valid + set_a2bus_device(); + + save_item(NAME(m_slot7_bank)); + save_item(NAME(m_slot7_ram_bank)); +} + +void a2bus_laser128_device::device_reset() +{ + m_rom = device().machine().root_device().memregion("maincpu")->base(); + m_slot7_bank = 0; + m_slot7_ram_bank = 0; +} + +UINT8 a2bus_laser128_device::read_c0nx(address_space &space, UINT8 offset) +{ + return 0x00; +} + +void a2bus_laser128_device::write_c0nx(address_space &space, UINT8 offset, UINT8 data) +{ +} + +UINT8 a2bus_laser128_device::read_cnxx(address_space &space, UINT8 offset) +{ + return m_rom[offset + (m_slot * 0x100) + 0x4000]; +} + +UINT8 a2bus_laser128_device::read_c800(address_space &space, UINT16 offset) +{ + switch (m_slot) + { + case 1: + return m_rom[(offset & 0x7ff) + 0x4800]; + + case 2: + return m_rom[(offset & 0x7ff) + 0x5800]; + + case 5: + return m_rom[(offset & 0x7ff) + 0x5000]; + + case 6: + return m_rom[(offset & 0x7ff) + 0x7800]; + + case 7: + if (offset < 0x400) + { + return m_slot7_ram[offset]; + } + return m_rom[(offset & 0x3ff) + 0x6000 + m_slot7_bank]; + } + + return 0xff; +} + +void a2bus_laser128_device::write_c800(address_space &space, UINT16 offset, UINT8 data) +{ + if ((m_slot == 7) && (offset < 0x400)) + { + m_slot7_ram[offset] = data; + } + + // UDCREG + if ((m_slot == 7) && (offset == 0x7f8)) + { +// printf("%02x to UDCREG\n", data); + + m_slot7_ram_bank = (data & 0x8) ? 0x400 : 0; + m_slot7_bank = (((data >> 4) & 0x7) * 0x400); + +// printf("\tRAM bank %x, ROM bank %x\n", m_slot7_ram_bank, m_slot7_bank); + } +} + +bool a2bus_laser128_device::take_c800() +{ + if ((m_slot == 1) || (m_slot == 2) || (m_slot == 5) || (m_slot == 6) || (m_slot == 7)) + { + return true; + } + + return false; +} diff --git a/src/devices/bus/a2bus/laser128.h b/src/devices/bus/a2bus/laser128.h new file mode 100644 index 00000000000..de754f3b368 --- /dev/null +++ b/src/devices/bus/a2bus/laser128.h @@ -0,0 +1,54 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/********************************************************************* + + laser128.h + + Helper to implement the Laser 128's built-in slot peripherals + +*********************************************************************/ + +#ifndef __A2BUS_LASER128__ +#define __A2BUS_LASER128__ + +#include "emu.h" +#include "a2bus.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class a2bus_laser128_device: + public device_t, + public device_a2bus_card_interface +{ +public: + // construction/destruction + a2bus_laser128_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + a2bus_laser128_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + +protected: + virtual void device_start(); + virtual void device_reset(); + + // overrides of standard a2bus slot functions + virtual UINT8 read_c0nx(address_space &space, UINT8 offset); + virtual void write_c0nx(address_space &space, UINT8 offset, UINT8 data); + virtual UINT8 read_cnxx(address_space &space, UINT8 offset); + virtual UINT8 read_c800(address_space &space, UINT16 offset); + virtual void write_c800(address_space &space, UINT16 offset, UINT8 data); + virtual bool take_c800(); + +private: + UINT8 *m_rom; + UINT8 m_slot7_ram[0x800]; + int m_slot7_bank, m_slot7_ram_bank; +}; + +// device type definition +extern const device_type A2BUS_LASER128; + +#endif /* __A2BUS_LASER128__ */ diff --git a/src/devices/bus/a2bus/mouse.c b/src/devices/bus/a2bus/mouse.c new file mode 100644 index 00000000000..d044fbcdad2 --- /dev/null +++ b/src/devices/bus/a2bus/mouse.c @@ -0,0 +1,531 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/********************************************************************* + + mouse.c + + Implemention of the Apple II Mouse Card + + Apple II Mouse Interface PCB + Apple 1983 + + This is a mouse interface for the Apple II + + PCB Layout + ---------- + apple computer + MOUSE INTERFACE + 670-0030-C (C) 1983 + Printed on back side - MOUSE INTERFACE 820-0104-B (C) 1983 APPLE COMPUTER + |-----------------------------------| + | PAL16R4 6821 | + | | + | J1 | + | 74SC245 | + | 68705P3 8516 | + | 74LS74 X1 X2 | + |-------------------| |-| + |-------------| + + Notes: + J1 - 9 pin flat cable with female DB9 connector + 68705P3 - Motorola MC68705P3 microcontroller (DIP28) labelled '341-0269 (C) APPLE' + PCB printed '(C) APPLE 1983 341-0269 or 342-0285' + 8516 - Fujitsu MB8516 2k x8-bit EPROM (DIP24) labelled '341-0270-C (C) APPLE 1983' + PCB printed '(C) APPLE 1983 342-0270' + PAL16R4 - MMI PAL16R4ACN (DIP20) marked '341-0268-A' + PCB printed '(C) APPLE 1983 342-0268' + 6821 - AMI 6821 Peripheral Interface Adapter (DIP40) + X1/X2 - Jumper pads. X1 is open, X2 is closed. + + + Hookup notes: + PIA port A connects to 68705 port A in its entirety (bi-directional) + PIA PB4-PB7 connects to 68705 PC0-3 (bi-directional) + PIA PB0 is 'sync latch' + PIA PB1 is A8 on the EPROM + PIA PB2 is A9 on the EPROM + PIA PB3 is A10 on the EPROM + + 68705 PB0 is mouse X1 + 68705 PB1 is mouse X0 + 68705 PB2 is mouse Y0 + 68705 PB3 is mouse Y1 + 68705 PB4 and 5 are N/C + 68705 PB6 is IRQ for the slot + 68705 PB7 is the mouse button + + 68705 is clocked at 2M + PIA is clocked at 1M + + See the schematic at: + http://mirrors.apple2.org.za/Apple%20II%20Documentation%20Project/Interface%20Cards/Digitizers/Apple%20Mouse%20Interface%20Card/Schematics/ + +*********************************************************************/ + +#include "mouse.h" + +/*************************************************************************** + PARAMETERS +***************************************************************************/ + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type A2BUS_MOUSE = &device_creator; + +#define MOUSE_ROM_REGION "a2mse_rom" +#define MOUSE_PIA_TAG "a2mse_pia" +#define MOUSE_MCU_TAG "a2mse_mcu" +#define MOUSE_MCU_ROM "a2mse_mcurom" + +#define MOUSE_BUTTON_TAG "a2mse_button" +#define MOUSE_XAXIS_TAG "a2mse_x" +#define MOUSE_YAXIS_TAG "a2mse_y" + +#define TIMER_68705 0 +#define TIMER_QUADRATURE 1 + +static ADDRESS_MAP_START( mcu_mem, AS_PROGRAM, 8, a2bus_mouse_device ) + ADDRESS_MAP_GLOBAL_MASK(0x7ff) + AM_RANGE(0x0000, 0x0000) AM_READWRITE(mcu_port_a_r, mcu_port_a_w) + AM_RANGE(0x0001, 0x0001) AM_READWRITE(mcu_port_b_r, mcu_port_b_w) + AM_RANGE(0x0002, 0x0002) AM_READWRITE(mcu_port_c_r, mcu_port_c_w) + AM_RANGE(0x0004, 0x0004) AM_WRITE(mcu_ddr_a_w) + AM_RANGE(0x0005, 0x0005) AM_WRITE(mcu_ddr_b_w) + AM_RANGE(0x0006, 0x0006) AM_WRITE(mcu_ddr_c_w) + AM_RANGE(0x0008, 0x0009) AM_READWRITE(mcu_timer_r, mcu_timer_w) + AM_RANGE(0x0010, 0x007f) AM_RAM + AM_RANGE(0x0080, 0x07ff) AM_ROM AM_REGION(MOUSE_MCU_ROM, 0x80) +ADDRESS_MAP_END + +MACHINE_CONFIG_FRAGMENT( mouse ) + MCFG_CPU_ADD(MOUSE_MCU_TAG, M68705, 2043600) + MCFG_CPU_PROGRAM_MAP(mcu_mem) + + MCFG_DEVICE_ADD(MOUSE_PIA_TAG, PIA6821, 1021800) + MCFG_PIA_READPA_HANDLER(READ8(a2bus_mouse_device, pia_in_a)) + MCFG_PIA_READPB_HANDLER(READ8(a2bus_mouse_device, pia_in_b)) + MCFG_PIA_WRITEPA_HANDLER(WRITE8(a2bus_mouse_device, pia_out_a)) + MCFG_PIA_WRITEPB_HANDLER(WRITE8(a2bus_mouse_device, pia_out_b)) + MCFG_PIA_IRQA_HANDLER(WRITELINE(a2bus_mouse_device, pia_irqa_w)) + MCFG_PIA_IRQB_HANDLER(WRITELINE(a2bus_mouse_device, pia_irqb_w)) +MACHINE_CONFIG_END + +ROM_START( mouse ) + ROM_REGION(0x800, MOUSE_ROM_REGION, 0) + ROM_LOAD( "341-0270-c.4b", 0x000000, 0x000800, CRC(0bcd1e8e) SHA1(3a9d881a8a8d30f55b9719aceebbcf717f829d6f) ) + + ROM_REGION(0x800, MOUSE_MCU_ROM, 0) + ROM_LOAD( "341-0269.2b", 0x000000, 0x000800, CRC(94067f16) SHA1(3a2baa6648efe4456d3ec3721216e57c64f7acfc) ) + + ROM_REGION(0xc00, "pal", 0) + ROM_LOAD( "mmi_pal16r4a(jedec).2a", 0x000000, 0x000b04, CRC(1d620ee5) SHA1(5aa9a515c919ff7a18878649cac5d44f0c2abf28) ) + ROM_LOAD( "mmi_pal16r4a(binary).2a", 0x000000, 0x000100, CRC(1da5c745) SHA1(ba267b69a2fda2a2348b140979ece562411bb37b) ) +ROM_END + +static INPUT_PORTS_START( mouse ) + PORT_START(MOUSE_BUTTON_TAG) /* Mouse - button */ + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_BUTTON1) PORT_NAME("Mouse Button") PORT_CODE(MOUSECODE_BUTTON1) + + PORT_START(MOUSE_XAXIS_TAG) /* Mouse - X AXIS */ + PORT_BIT( 0xff, 0x00, IPT_MOUSE_X) PORT_SENSITIVITY(40) PORT_KEYDELTA(0) PORT_PLAYER(1) + + PORT_START(MOUSE_YAXIS_TAG) /* Mouse - Y AXIS */ + PORT_BIT( 0xff, 0x00, IPT_MOUSE_Y) PORT_SENSITIVITY(40) PORT_KEYDELTA(0) PORT_PLAYER(1) +INPUT_PORTS_END + +/*************************************************************************** + FUNCTION PROTOTYPES +***************************************************************************/ + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor a2bus_mouse_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( mouse ); +} + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor a2bus_mouse_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( mouse ); +} + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *a2bus_mouse_device::device_rom_region() const +{ + return ROM_NAME( mouse ); +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +a2bus_mouse_device::a2bus_mouse_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_a2bus_card_interface(mconfig, *this), + m_pia(*this, MOUSE_PIA_TAG), + m_mcu(*this, MOUSE_MCU_TAG), + m_mouseb(*this, MOUSE_BUTTON_TAG), + m_mousex(*this, MOUSE_XAXIS_TAG), + m_mousey(*this, MOUSE_YAXIS_TAG) +{ + m_started = false; + m_rom_bank = 0; +} + +a2bus_mouse_device::a2bus_mouse_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, A2BUS_MOUSE, "Apple II Mouse Card", tag, owner, clock, "a2mouse", __FILE__), + device_a2bus_card_interface(mconfig, *this), + m_pia(*this, MOUSE_PIA_TAG), + m_mcu(*this, MOUSE_MCU_TAG), + m_mouseb(*this, MOUSE_BUTTON_TAG), + m_mousex(*this, MOUSE_XAXIS_TAG), + m_mousey(*this, MOUSE_YAXIS_TAG) +{ + m_started = false; + m_rom_bank = 0; +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void a2bus_mouse_device::device_start() +{ + // set_a2bus_device makes m_slot valid + set_a2bus_device(); + + m_rom = device().machine().root_device().memregion(this->subtag(MOUSE_ROM_REGION).c_str())->base(); + + // allocate two timers: one for the 68705, one for the quadrature magic + m_timer = timer_alloc(TIMER_68705, NULL); + m_read_timer = timer_alloc(TIMER_QUADRATURE, NULL); + m_timer->adjust(attotime::never, TIMER_68705); + m_read_timer->adjust(attotime::never, TIMER_QUADRATURE); + + // get 68705P3 mask option byte + m_mask_option = m_rom[0x784]; + + // register save state variables + save_item(NAME(m_ddr_a)); + save_item(NAME(m_ddr_b)); + save_item(NAME(m_ddr_c)); + save_item(NAME(m_port_a_out)); + save_item(NAME(m_port_b_out)); + save_item(NAME(m_port_c_out)); + save_item(NAME(m_port_a_in)); + save_item(NAME(m_port_b_in)); + save_item(NAME(m_port_c_in)); + save_item(NAME(m_timer_cnt)); + save_item(NAME(m_timer_ctl)); + save_item(NAME(last_mx)); + save_item(NAME(last_my)); + save_item(NAME(count_x)); + save_item(NAME(count_y)); +} + +void a2bus_mouse_device::device_reset() +{ + m_started = true; + m_rom_bank = 0; + last_mx = last_my = count_x = count_y = 0; + m_timer_cnt = 0xff; + m_timer_ctl = 0x40; // disable interrupt, everything else clear + m_port_a_in = 0; + m_port_b_in = 0x80; + m_port_c_in = 0; + + // are we emulating the mask part with a semi-programmable timer? + if (m_mask_option & 0x40) + { + m_timer_ctl |= m_mask_option & 0x17; + } + + m_read_timer->adjust(attotime::from_hz(600.0), TIMER_QUADRATURE, attotime::from_hz(600.0)); +} + +/*------------------------------------------------- + read_c0nx - called for reads from this card's c0nx space +-------------------------------------------------*/ + +UINT8 a2bus_mouse_device::read_c0nx(address_space &space, UINT8 offset) +{ + return m_pia->read(space, offset & 3); +} + + +/*------------------------------------------------- + write_c0nx - called for writes to this card's c0nx space +-------------------------------------------------*/ + +void a2bus_mouse_device::write_c0nx(address_space &space, UINT8 offset, UINT8 data) +{ + m_pia->write(space, offset & 3, data); +} + +/*------------------------------------------------- + read_cnxx - called for reads from this card's cnxx space +-------------------------------------------------*/ + +UINT8 a2bus_mouse_device::read_cnxx(address_space &space, UINT8 offset) +{ + return m_rom[offset+m_rom_bank]; +} + +READ8_MEMBER(a2bus_mouse_device::pia_in_a) +{ + return m_port_a_out; +} + +READ8_MEMBER(a2bus_mouse_device::pia_in_b) +{ + return (m_port_c_out << 4); +} + +WRITE8_MEMBER(a2bus_mouse_device::pia_out_a) +{ + m_port_a_in = data; +} + +WRITE8_MEMBER(a2bus_mouse_device::pia_out_b) +{ + m_port_c_in &= 0xf0; + m_port_c_in |= ((data >> 4) & 0xf); + + m_rom_bank = (data & 0xe) << 7; +} + +WRITE_LINE_MEMBER(a2bus_mouse_device::pia_irqa_w) +{ +} + +WRITE_LINE_MEMBER(a2bus_mouse_device::pia_irqb_w) +{ +} + +READ8_MEMBER(a2bus_mouse_device::mcu_port_a_r) +{ + return (m_port_a_out & m_ddr_a) | (m_port_a_in & ~m_ddr_a); +} + +WRITE8_MEMBER(a2bus_mouse_device::mcu_port_a_w) +{ + m_port_a_out = data; +} + +WRITE8_MEMBER(a2bus_mouse_device::mcu_ddr_a_w) +{ + m_ddr_a = data; +} + +READ8_MEMBER(a2bus_mouse_device::mcu_port_b_r) +{ + UINT8 b_in = m_port_b_in; + + // clear the gates, leave everything else alone between pulses + m_port_b_in &= 0x85; + + return (m_port_b_out & m_ddr_b) | (b_in & ~m_ddr_b); +} + +WRITE8_MEMBER(a2bus_mouse_device::mcu_port_b_w) +{ + m_port_b_out = data; + + if (!(data & 0x40)) + { + raise_slot_irq(); + } + else + { + lower_slot_irq(); + } +} + +WRITE8_MEMBER(a2bus_mouse_device::mcu_ddr_b_w) +{ + m_ddr_b = data; +} + +READ8_MEMBER(a2bus_mouse_device::mcu_port_c_r) +{ + return (m_port_c_out & m_ddr_c) | (m_port_c_in & ~m_ddr_c); +} + +WRITE8_MEMBER(a2bus_mouse_device::mcu_port_c_w) +{ + m_port_c_out = data; +} + +WRITE8_MEMBER(a2bus_mouse_device::mcu_ddr_c_w) +{ + m_ddr_c = data; +} + +READ8_MEMBER(a2bus_mouse_device::mcu_timer_r) +{ + if (offset == 1) + { + return m_timer_ctl; + } + + return m_timer_cnt; +} + +WRITE8_MEMBER(a2bus_mouse_device::mcu_timer_w) +{ + static const int prescale[8] = { 1, 2, 4, 8, 16, 32, 64, 128 }; + bool recalc = false; + + // offset 0 = timer data (counts down) + if (offset == 0) + { + m_timer_cnt = data; + recalc = true; + } + // offset 1 = timer control: b7 = IRQ, b6 = IRQ mask (1=suppress), + // b5 = input select (0=CPU clk, 1=ext), + // b4 = enable external timer input, + // b3 = clear, b2-b0 = scaler (1/2/4/8/16/32/64/128) + else + { + // clearing the interrupt? + if ((m_timer_ctl & 0x80) && !(data & 0x80)) + { + m_mcu->set_input_line(M68705_INT_TIMER, CLEAR_LINE); + } + + if (m_mask_option & 0x40) + { + m_timer_ctl &= 0x3f; + m_timer_ctl |= (data & 0xc0); + } + else + { + // if any parameters that affect the timer changed, recalc now + if ((data & 0x3f) != (m_timer_ctl & 0x3f)) + { + recalc = true; + } + + // if prescaler reset, recalc + if (data & 0x8) + { + recalc = true; + } + + m_timer_ctl = data; + } + + } + + if (recalc) + { + // recalculate the timer now + UINT32 m_ticks = 2043600 / 4; + m_ticks /= prescale[m_timer_ctl & 7]; + m_ticks /= (int)(m_timer_cnt + 1); + m_timer->adjust(attotime::from_hz((double)m_ticks), TIMER_68705, attotime::from_hz((double)m_ticks)); + } +} + +/* + X0 = direction, 0 = left, 1 = right + X1 = gate, must go 0/1 for each pixel moved + Y0 = direction, 0 = up, 1 = down + Y1 = gate, must go 0/1 for each pixel moved + + The direction must stay constant for a given train of gate pulses or the MCU will get confused. +*/ +void a2bus_mouse_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + if (id == TIMER_68705) // 68705's built-in timer + { + m_timer_ctl |= 0x80; // indicate timer expired + if (!(m_timer_ctl & 0x40)) // if interrupt not suppressed, fire! + { + m_mcu->set_input_line(M68705_INT_TIMER, ASSERT_LINE); + } + } + else if (id == TIMER_QUADRATURE) + { + int new_mx, new_my; + m_port_b_in = 0x80; + + // update button now + if (m_mouseb->read()) m_port_b_in &= ~0x80; + + // read the axes + new_mx = m_mousex->read(); + new_my = m_mousey->read(); + + // did X change? + if (new_mx != last_mx) + { + int diff = new_mx - last_mx; + + /* check for wrap */ + if (diff > 0x80) + diff = 0x100-diff; + if (diff < -0x80) + diff = -0x100-diff; + + count_x += diff; + last_mx = new_mx; + } + + // did Y change? + if (new_my != last_my) + { + int diff = new_my - last_my; + + /* check for wrap */ + if (diff > 0x80) + diff = 0x100-diff; + if (diff < -0x80) + diff = -0x100-diff; + + count_y += diff; + last_my = new_my; + } + + if (count_x) + { + if (count_x < 0) + { + count_x++; + } + else + { + count_x--; + m_port_b_in |= 0x01; // X1 + } + m_port_b_in |= 0x02; // X0 + } + else if (count_y) + { + if (count_y < 0) + { + count_y++; + } + else + { + count_y--; + m_port_b_in |= 0x04; // Y0 + } + m_port_b_in |= 0x08; // Y1 + } + } +} diff --git a/src/devices/bus/a2bus/mouse.h b/src/devices/bus/a2bus/mouse.h new file mode 100644 index 00000000000..b6065897731 --- /dev/null +++ b/src/devices/bus/a2bus/mouse.h @@ -0,0 +1,93 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/********************************************************************* + + mouse.h + + Implemention of the Apple II Mouse Card + +*********************************************************************/ + +#ifndef __A2BUS_MOUSE__ +#define __A2BUS_MOUSE__ + +#include "emu.h" +#include "a2bus.h" +#include "machine/6821pia.h" +#include "cpu/m6805/m6805.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class a2bus_mouse_device: + public device_t, + public device_a2bus_card_interface +{ +public: + // construction/destruction + a2bus_mouse_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + a2bus_mouse_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual const rom_entry *device_rom_region() const; + virtual ioport_constructor device_input_ports() const; + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + DECLARE_READ8_MEMBER(pia_in_a); + DECLARE_READ8_MEMBER(pia_in_b); + DECLARE_WRITE8_MEMBER(pia_out_a); + DECLARE_WRITE8_MEMBER(pia_out_b); + DECLARE_WRITE_LINE_MEMBER(pia_irqa_w); + DECLARE_WRITE_LINE_MEMBER(pia_irqb_w); + + DECLARE_READ8_MEMBER(mcu_port_a_r); + DECLARE_READ8_MEMBER(mcu_port_b_r); + DECLARE_READ8_MEMBER(mcu_port_c_r); + DECLARE_WRITE8_MEMBER(mcu_port_a_w); + DECLARE_WRITE8_MEMBER(mcu_port_b_w); + DECLARE_WRITE8_MEMBER(mcu_port_c_w); + DECLARE_WRITE8_MEMBER(mcu_ddr_a_w); + DECLARE_WRITE8_MEMBER(mcu_ddr_b_w); + DECLARE_WRITE8_MEMBER(mcu_ddr_c_w); + DECLARE_READ8_MEMBER(mcu_timer_r); + DECLARE_WRITE8_MEMBER(mcu_timer_w); + +protected: + virtual void device_start(); + virtual void device_reset(); + + // overrides of standard a2bus slot functions + virtual UINT8 read_c0nx(address_space &space, UINT8 offset); + virtual void write_c0nx(address_space &space, UINT8 offset, UINT8 data); + virtual UINT8 read_cnxx(address_space &space, UINT8 offset); + + required_device m_pia; + required_device m_mcu; + required_ioport m_mouseb, m_mousex, m_mousey; + +private: + UINT8 *m_rom; + bool m_started; + int m_rom_bank; + UINT8 m_ddr_a; + UINT8 m_ddr_b; + UINT8 m_ddr_c; + UINT8 m_port_a_out; + UINT8 m_port_b_out; + UINT8 m_port_c_out; + UINT8 m_port_a_in; + UINT8 m_port_b_in; + UINT8 m_port_c_in; + UINT8 m_timer_cnt; + UINT8 m_timer_ctl; + UINT8 m_mask_option; + int last_mx, last_my, count_x, count_y; + emu_timer *m_timer, *m_read_timer; +}; + +// device type definition +extern const device_type A2BUS_MOUSE; + +#endif /* __A2BUS_MOUSE__ */ diff --git a/src/devices/bus/a2bus/ramcard128k.c b/src/devices/bus/a2bus/ramcard128k.c new file mode 100644 index 00000000000..3b05128e186 --- /dev/null +++ b/src/devices/bus/a2bus/ramcard128k.c @@ -0,0 +1,190 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/********************************************************************* + + ramcard128k.c + + Implemention of the Saturn Systems 128K extended language card + +*********************************************************************/ + +#include "ramcard128k.h" + +/*************************************************************************** + PARAMETERS +***************************************************************************/ + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type A2BUS_RAMCARD128K = &device_creator; + +/*************************************************************************** + FUNCTION PROTOTYPES +***************************************************************************/ + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +a2bus_ssramcard_device::a2bus_ssramcard_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_a2bus_card_interface(mconfig, *this) +{ +} + +a2bus_ssramcard_device::a2bus_ssramcard_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, A2BUS_RAMCARD128K, "Saturn Systems 128K Extended Language Card", tag, owner, clock, "ssram128", __FILE__), + device_a2bus_card_interface(mconfig, *this) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void a2bus_ssramcard_device::device_start() +{ + // set_a2bus_device makes m_slot valid + set_a2bus_device(); + + memset(m_ram, 0, 128*1024); + + save_item(NAME(m_inh_state)); + save_item(NAME(m_ram)); + save_item(NAME(m_dxxx_bank)); + save_item(NAME(m_main_bank)); + save_item(NAME(m_last_offset)); +} + +void a2bus_ssramcard_device::device_reset() +{ + m_inh_state = INH_NONE; + m_dxxx_bank = 0; + m_main_bank = 0; + m_last_offset = -1; +} + +void a2bus_ssramcard_device::do_io(int offset) +{ + int old_inh_state = m_inh_state; + + switch (offset) + { + case 0x1: case 0x3: case 0x9: case 0xb: + if (offset != m_last_offset) + { + m_last_offset = offset; + return; + } + break; + } + m_last_offset = offset; + + if (offset & 4) + { + switch (offset) + { + case 0x4: m_main_bank = 0x00000; break; + case 0x5: m_main_bank = 0x04000; break; + case 0x6: m_main_bank = 0x08000; break; + case 0x7: m_main_bank = 0x0c000; break; + case 0xc: m_main_bank = 0x10000; break; + case 0xd: m_main_bank = 0x14000; break; + case 0xe: m_main_bank = 0x18000; break; + case 0xf: m_main_bank = 0x1c000; break; + } + } + else + { + m_inh_state = INH_NONE; + m_dxxx_bank = 0; + + if (offset & 0x1) + { + m_inh_state |= INH_WRITE; + } + + switch(offset & 0x03) + { + case 0x00: + case 0x03: + m_inh_state |= INH_READ; + break; + } + + if (!(offset & 8)) + { + m_dxxx_bank = 0x1000; + } + } + + if (m_inh_state != old_inh_state) + { + recalc_slot_inh(); + } + + #if 0 + printf("LC: (ofs %x) new state %c%c dxxx=%04x main=%05x\n", + offset, + (m_inh_state & INH_READ) ? 'R' : 'x', + (m_inh_state & INH_WRITE) ? 'W' : 'x', + m_dxxx_bank, m_main_bank); + #endif +} + + +/*------------------------------------------------- + read_c0nx - called for reads from this card's c0nx space +-------------------------------------------------*/ + +UINT8 a2bus_ssramcard_device::read_c0nx(address_space &space, UINT8 offset) +{ + do_io(offset & 0xf); + return 0xff; +} + + +/*------------------------------------------------- + write_c0nx - called for writes to this card's c0nx space +-------------------------------------------------*/ + +void a2bus_ssramcard_device::write_c0nx(address_space &space, UINT8 offset, UINT8 data) +{ + do_io(offset & 0xf); +} + +UINT8 a2bus_ssramcard_device::read_inh_rom(address_space &space, UINT16 offset) +{ + assert(m_inh_state & INH_READ); // this should never happen + + if (offset < 0xe000) + { + return m_ram[(offset & 0xfff) + m_dxxx_bank + m_main_bank]; + } + + return m_ram[(offset & 0x1fff) + 0x2000 + m_main_bank]; +} + +void a2bus_ssramcard_device::write_inh_rom(address_space &space, UINT16 offset, UINT8 data) +{ + // are writes enabled? + if (!(m_inh_state & INH_WRITE)) + { + return; + } + + if (offset < 0xe000) + { + m_ram[(offset & 0xfff) + m_dxxx_bank + m_main_bank] = data; + return; + } + + m_ram[(offset & 0x1fff) + 0x2000 + m_main_bank] = data; +} + +int a2bus_ssramcard_device::inh_type() +{ + return m_inh_state; +} diff --git a/src/devices/bus/a2bus/ramcard128k.h b/src/devices/bus/a2bus/ramcard128k.h new file mode 100644 index 00000000000..4d2eb0da497 --- /dev/null +++ b/src/devices/bus/a2bus/ramcard128k.h @@ -0,0 +1,56 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/********************************************************************* + + ramcard128k.h + + Implemention of the Saturn Systems 128K extended language card + +*********************************************************************/ + +#ifndef __A2BUS_RAMCARD128K__ +#define __A2BUS_RAMCARD128K__ + +#include "emu.h" +#include "a2bus.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class a2bus_ssramcard_device: + public device_t, + public device_a2bus_card_interface +{ +public: + // construction/destruction + a2bus_ssramcard_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + a2bus_ssramcard_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual void device_start(); + virtual void device_reset(); + + // overrides of standard a2bus slot functions + virtual UINT8 read_c0nx(address_space &space, UINT8 offset); + virtual void write_c0nx(address_space &space, UINT8 offset, UINT8 data); + virtual UINT8 read_inh_rom(address_space &space, UINT16 offset); + virtual void write_inh_rom(address_space &space, UINT16 offset, UINT8 data); + virtual UINT16 inh_start() { return 0xd000; } + virtual UINT16 inh_end() { return 0xffff; } + virtual int inh_type(); + +private: + void do_io(int offset); + + int m_inh_state; + int m_last_offset; + int m_dxxx_bank; + int m_main_bank; + UINT8 m_ram[128*1024]; +}; + +// device type definition +extern const device_type A2BUS_RAMCARD128K; + +#endif /* __A2BUS_RAMCARD128K__ */ diff --git a/src/devices/bus/a2bus/ramcard16k.c b/src/devices/bus/a2bus/ramcard16k.c new file mode 100644 index 00000000000..a25ba79423f --- /dev/null +++ b/src/devices/bus/a2bus/ramcard16k.c @@ -0,0 +1,170 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/********************************************************************* + + ramcard16k.c + + Implemention of the Apple II 16K RAM card (aka "language card") + +*********************************************************************/ + +#include "ramcard16k.h" + +/*************************************************************************** + PARAMETERS +***************************************************************************/ + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type A2BUS_RAMCARD16K = &device_creator; + +/*************************************************************************** + FUNCTION PROTOTYPES +***************************************************************************/ + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +a2bus_ramcard_device::a2bus_ramcard_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_a2bus_card_interface(mconfig, *this) +{ +} + +a2bus_ramcard_device::a2bus_ramcard_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, A2BUS_RAMCARD16K, "Apple II 16K Language Card", tag, owner, clock, "a2ram16k", __FILE__), + device_a2bus_card_interface(mconfig, *this) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void a2bus_ramcard_device::device_start() +{ + // set_a2bus_device makes m_slot valid + set_a2bus_device(); + + memset(m_ram, 0, 16*1024); + + save_item(NAME(m_inh_state)); + save_item(NAME(m_ram)); + save_item(NAME(m_dxxx_bank)); + save_item(NAME(m_last_offset)); +} + +void a2bus_ramcard_device::device_reset() +{ + m_inh_state = INH_NONE; + m_dxxx_bank = 0; + m_last_offset = -1; +} + +void a2bus_ramcard_device::do_io(int offset) +{ + int old_inh_state = m_inh_state; + + switch (offset) + { + case 0x1: case 0x3: case 0x9: case 0xb: + if (offset != m_last_offset) + { + m_last_offset = offset; + return; + } + break; + } + m_last_offset = offset; + + m_inh_state = INH_NONE; + m_dxxx_bank = 0; + + if (offset & 0x1) + { + m_inh_state |= INH_WRITE; + } + + switch(offset & 0x03) + { + case 0x00: + case 0x03: + m_inh_state |= INH_READ; + break; + } + + if (!(offset & 8)) + { + m_dxxx_bank = 0x1000; + } + + if (m_inh_state != old_inh_state) + { + recalc_slot_inh(); + } + + #if 0 + printf("LC: new state %c%c dxxx=%04x\n", + (m_inh_state & INH_READ) ? 'R' : 'x', + (m_inh_state & INH_WRITE) ? 'W' : 'x', + m_dxxx_bank); + #endif +} + + +/*------------------------------------------------- + read_c0nx - called for reads from this card's c0nx space +-------------------------------------------------*/ + +UINT8 a2bus_ramcard_device::read_c0nx(address_space &space, UINT8 offset) +{ + do_io(offset & 0xf); + return 0xff; +} + + +/*------------------------------------------------- + write_c0nx - called for writes to this card's c0nx space +-------------------------------------------------*/ + +void a2bus_ramcard_device::write_c0nx(address_space &space, UINT8 offset, UINT8 data) +{ + do_io(offset & 0xf); +} + +UINT8 a2bus_ramcard_device::read_inh_rom(address_space &space, UINT16 offset) +{ + assert(m_inh_state & INH_READ); // this should never happen + + if (offset < 0xe000) + { + return m_ram[(offset & 0xfff) + m_dxxx_bank]; + } + + return m_ram[(offset & 0x1fff) + 0x2000]; +} + +void a2bus_ramcard_device::write_inh_rom(address_space &space, UINT16 offset, UINT8 data) +{ + // are writes enabled? + if (!(m_inh_state & INH_WRITE)) + { + return; + } + + if (offset < 0xe000) + { + m_ram[(offset & 0xfff) + m_dxxx_bank] = data; + return; + } + + m_ram[(offset & 0x1fff) + 0x2000] = data; +} + +int a2bus_ramcard_device::inh_type() +{ + return m_inh_state; +} diff --git a/src/devices/bus/a2bus/ramcard16k.h b/src/devices/bus/a2bus/ramcard16k.h new file mode 100644 index 00000000000..1de1cdaa85c --- /dev/null +++ b/src/devices/bus/a2bus/ramcard16k.h @@ -0,0 +1,55 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/********************************************************************* + + ramcard16k.h + + Implemention of the Apple II 16K RAM card (aka "language card") + +*********************************************************************/ + +#ifndef __A2BUS_RAMCARD16K__ +#define __A2BUS_RAMCARD16K__ + +#include "emu.h" +#include "a2bus.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class a2bus_ramcard_device: + public device_t, + public device_a2bus_card_interface +{ +public: + // construction/destruction + a2bus_ramcard_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + a2bus_ramcard_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual void device_start(); + virtual void device_reset(); + + // overrides of standard a2bus slot functions + virtual UINT8 read_c0nx(address_space &space, UINT8 offset); + virtual void write_c0nx(address_space &space, UINT8 offset, UINT8 data); + virtual UINT8 read_inh_rom(address_space &space, UINT16 offset); + virtual void write_inh_rom(address_space &space, UINT16 offset, UINT8 data); + virtual UINT16 inh_start() { return 0xd000; } + virtual UINT16 inh_end() { return 0xffff; } + virtual int inh_type(); + +private: + void do_io(int offset); + + int m_inh_state; + int m_last_offset; + int m_dxxx_bank; + UINT8 m_ram[16*1024]; +}; + +// device type definition +extern const device_type A2BUS_RAMCARD16K; + +#endif /* __A2BUS_RAMCARD16K__ */ diff --git a/src/devices/bus/a2bus/timemasterho.c b/src/devices/bus/a2bus/timemasterho.c new file mode 100644 index 00000000000..9b33d8fd511 --- /dev/null +++ b/src/devices/bus/a2bus/timemasterho.c @@ -0,0 +1,280 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/********************************************************************* + + timemasterho.c + + Implemention of the Applied Engineering TimeMaster H.O. + + + PCB Layout: + _____________________________________________________ + | ___ _ _____________________ | + | | D | | |MSM5832 | |u3 | + | | I | u1| | | HD46821P | ___ | + | | P | |_| |_____________________|| B | | + | |_S_| _____ | A | | + | u2|_____| 74LS245| T | | + | |J1 74LS00 74LS08 ____________ | T | | + | | _ _ u4| | | E | | + | | u5| | u6| | | 2716 | | R | | + | | |_| |_| |____________| |_Y_| | + |____________________________ _| + | | + |______________________| + + + DIPS: 1:SET 2:MODE 3:NMI 4:IRQ + 1 & 4 are on by default. + + J1: 8 pins for X10 home control functions (top to bottom) + 1: ADJ 2: 5V 3: MODE 4: GND + 5: A 6: 5V 7: B 8: GND + + X10 functions not supported. + +*********************************************************************/ + +#include "timemasterho.h" + +/*************************************************************************** + PARAMETERS +***************************************************************************/ + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type A2BUS_TIMEMASTERHO = &device_creator; + +#define TIMEMASTER_ROM_REGION "timemst_rom" +#define TIMEMASTER_PIA_TAG "timemst_pia" +#define TIMEMASTER_M5832_TAG "timemst_msm" + +MACHINE_CONFIG_FRAGMENT( timemaster ) + MCFG_DEVICE_ADD(TIMEMASTER_PIA_TAG, PIA6821, 1021800) + MCFG_PIA_WRITEPA_HANDLER(WRITE8(a2bus_timemasterho_device, pia_out_a)) + MCFG_PIA_WRITEPB_HANDLER(WRITE8(a2bus_timemasterho_device, pia_out_b)) + MCFG_PIA_IRQA_HANDLER(WRITELINE(a2bus_timemasterho_device, pia_irqa_w)) + MCFG_PIA_IRQB_HANDLER(WRITELINE(a2bus_timemasterho_device, pia_irqb_w)) + + MCFG_DEVICE_ADD(TIMEMASTER_M5832_TAG, MSM5832, 32768) +MACHINE_CONFIG_END + +ROM_START( timemaster ) + ROM_REGION(0x1000, TIMEMASTER_ROM_REGION, 0) + ROM_LOAD( "ae timemaster ii h.o. rom rev. 5.bin", 0x000000, 0x001000, CRC(ff5bd644) SHA1(ae0173da61581a06188c1bee89e95a0aa536c411) ) +ROM_END + +static INPUT_PORTS_START( tmho ) + PORT_START("DSW1") + PORT_DIPNAME( 0x01, 0x01, "Set") + PORT_DIPSETTING( 0x00, "Apple can't set clock") + PORT_DIPSETTING( 0x01, "Apple can set clock") + + PORT_DIPNAME( 0x02, 0x00, "Mode") + PORT_DIPSETTING( 0x00, "TimeMaster") + PORT_DIPSETTING( 0x02, "Mountain AppleClock") + + PORT_DIPNAME( 0x04, 0x00, "NMI") + PORT_DIPSETTING( 0x00, DEF_STR(Off)) + PORT_DIPSETTING( 0x04, DEF_STR(On)) + + PORT_DIPNAME( 0x08, 0x08, "IRQ") + PORT_DIPSETTING( 0x00, DEF_STR(Off)) + PORT_DIPSETTING( 0x08, DEF_STR(On)) +INPUT_PORTS_END + +/*************************************************************************** + FUNCTION PROTOTYPES +***************************************************************************/ + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor a2bus_timemasterho_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( tmho ); +} + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor a2bus_timemasterho_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( timemaster ); +} + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *a2bus_timemasterho_device::device_rom_region() const +{ + return ROM_NAME( timemaster ); +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +a2bus_timemasterho_device::a2bus_timemasterho_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_a2bus_card_interface(mconfig, *this), + m_pia(*this, TIMEMASTER_PIA_TAG), + m_msm5832(*this, TIMEMASTER_M5832_TAG), + m_dsw1(*this, "DSW1") +{ + m_started = false; +} + +a2bus_timemasterho_device::a2bus_timemasterho_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, A2BUS_TIMEMASTERHO, "Applied Engineering TimeMaster H.O.", tag, owner, clock, "a2tmstho", __FILE__), + device_a2bus_card_interface(mconfig, *this), + m_pia(*this, TIMEMASTER_PIA_TAG), + m_msm5832(*this, TIMEMASTER_M5832_TAG), + m_dsw1(*this, "DSW1") +{ + m_started = false; +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void a2bus_timemasterho_device::device_start() +{ + // set_a2bus_device makes m_slot valid + set_a2bus_device(); + + m_rom = device().machine().root_device().memregion(this->subtag(TIMEMASTER_ROM_REGION).c_str())->base(); +} + +void a2bus_timemasterho_device::device_reset() +{ + m_msm5832->cs_w(ASSERT_LINE); // CS is tied to Vcc + m_started = true; +} + + +/*------------------------------------------------- + read_c0nx - called for reads from this card's c0nx space +-------------------------------------------------*/ + +UINT8 a2bus_timemasterho_device::read_c0nx(address_space &space, UINT8 offset) +{ + if (offset <= 3) + { + return m_pia->read(space, offset); + } + + return 0xff; +} + + +/*------------------------------------------------- + write_c0nx - called for writes to this card's c0nx space +-------------------------------------------------*/ + +void a2bus_timemasterho_device::write_c0nx(address_space &space, UINT8 offset, UINT8 data) +{ + if (offset <= 3) + { + m_pia->write(space, offset, data); + } +} + +/*------------------------------------------------- + read_cnxx - called for reads from this card's cnxx space +-------------------------------------------------*/ + +UINT8 a2bus_timemasterho_device::read_cnxx(address_space &space, UINT8 offset) +{ + if (m_started) + { + if (!(m_dsw1->read() & 2)) // TimeMaster native + { + return m_rom[offset+0xc00]; + } + } + + // Mountain Computer compatible + return m_rom[offset+0x800]; +} + +/*------------------------------------------------- + read_c800 - called for reads from this card's c800 space +-------------------------------------------------*/ + +UINT8 a2bus_timemasterho_device::read_c800(address_space &space, UINT16 offset) +{ + return m_rom[offset+0xc00]; +} + +WRITE8_MEMBER(a2bus_timemasterho_device::pia_out_a) +{ + // port A appears to be input only +} + +WRITE8_MEMBER(a2bus_timemasterho_device::pia_out_b) +{ + m_msm5832->address_w(data & 0xf); + m_msm5832->hold_w((data>>4) & 1 ? ASSERT_LINE : CLEAR_LINE); + m_msm5832->read_w((data>>5) & 1 ? ASSERT_LINE : CLEAR_LINE); + + if (m_started) + { + if (m_dsw1->read() & 1) + { + m_msm5832->write_w((data >> 6) & 1 ? ASSERT_LINE : CLEAR_LINE); + } + } + + // if it's a read, poke it into the PIA + if ((data>>5) & 1) + { + m_pia->porta_w(m_msm5832->data_r(space, 0)); + } +} + +void a2bus_timemasterho_device::update_irqs() +{ + UINT8 dip = 0; + + if (m_started) + { + dip = m_dsw1->read(); + } + + if ((m_irqa | m_irqb) == ASSERT_LINE) + { + if (dip & 4) + { + raise_slot_nmi(); + } + if (dip & 8) + { + raise_slot_irq(); + } + } + else + { + lower_slot_irq(); + lower_slot_nmi(); + } +} + +WRITE_LINE_MEMBER(a2bus_timemasterho_device::pia_irqa_w) +{ + m_irqa = state; + update_irqs(); +} + +WRITE_LINE_MEMBER(a2bus_timemasterho_device::pia_irqb_w) +{ + m_irqb = state; + update_irqs(); +} diff --git a/src/devices/bus/a2bus/timemasterho.h b/src/devices/bus/a2bus/timemasterho.h new file mode 100644 index 00000000000..cf26d3cded8 --- /dev/null +++ b/src/devices/bus/a2bus/timemasterho.h @@ -0,0 +1,67 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/********************************************************************* + + timemasterho.h + + Implemention of the Applied Engineering TimeMaster H.O. + +*********************************************************************/ + +#ifndef __A2BUS_TIMEMASTERHO__ +#define __A2BUS_TIMEMASTERHO__ + +#include "emu.h" +#include "a2bus.h" +#include "machine/6821pia.h" +#include "machine/msm5832.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class a2bus_timemasterho_device: + public device_t, + public device_a2bus_card_interface +{ +public: + // construction/destruction + a2bus_timemasterho_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + a2bus_timemasterho_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual const rom_entry *device_rom_region() const; + virtual ioport_constructor device_input_ports() const; + + DECLARE_WRITE8_MEMBER(pia_out_a); + DECLARE_WRITE8_MEMBER(pia_out_b); + DECLARE_WRITE_LINE_MEMBER(pia_irqa_w); + DECLARE_WRITE_LINE_MEMBER(pia_irqb_w); + +protected: + virtual void device_start(); + virtual void device_reset(); + + // overrides of standard a2bus slot functions + virtual UINT8 read_c0nx(address_space &space, UINT8 offset); + virtual void write_c0nx(address_space &space, UINT8 offset, UINT8 data); + virtual UINT8 read_cnxx(address_space &space, UINT8 offset); + virtual UINT8 read_c800(address_space &space, UINT16 offset); + + required_device m_pia; + required_device m_msm5832; + required_ioport m_dsw1; + +private: + void update_irqs(); + + UINT8 *m_rom; + bool m_irqa, m_irqb; + bool m_started; +}; + +// device type definition +extern const device_type A2BUS_TIMEMASTERHO; + +#endif /* __A2BUS_TIMEMASTERHO__ */ diff --git a/src/devices/bus/a7800/a78_carts.h b/src/devices/bus/a7800/a78_carts.h new file mode 100644 index 00000000000..ebf66de8218 --- /dev/null +++ b/src/devices/bus/a7800/a78_carts.h @@ -0,0 +1,39 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __A78_CARTS_H +#define __A78_CARTS_H + +#include "emu.h" + +#include "rom.h" +#include "xboard.h" +#include "hiscore.h" +#include "cpuwiz.h" + +static SLOT_INTERFACE_START(a7800_cart) + SLOT_INTERFACE_INTERNAL("a78_rom", A78_ROM) + SLOT_INTERFACE_INTERNAL("a78_pokey", A78_ROM_POKEY) + SLOT_INTERFACE_INTERNAL("a78_sg", A78_ROM_SG) + SLOT_INTERFACE_INTERNAL("a78_sg_pokey", A78_ROM_SG_POKEY) + SLOT_INTERFACE_INTERNAL("a78_sg_ram", A78_ROM_SG_RAM) + SLOT_INTERFACE_INTERNAL("a78_sg9", A78_ROM_SG9) + SLOT_INTERFACE_INTERNAL("a78_abs", A78_ROM_ABSOLUTE) + SLOT_INTERFACE_INTERNAL("a78_act", A78_ROM_ACTIVISION) + SLOT_INTERFACE_INTERNAL("a78_hsc", A78_HISCORE) + SLOT_INTERFACE_INTERNAL("a78_xboard", A78_XBOARD) // the actual XBoarD expansion (as passthru) + SLOT_INTERFACE_INTERNAL("a78_xm", A78_XM) // the actual XM expansion (as passthru) + SLOT_INTERFACE_INTERNAL("a78_megacart", A78_ROM_MEGACART) + SLOT_INTERFACE_INTERNAL("a78_versa", A78_ROM_VERSABOARD) + // cart variants with a POKEY at 0x0450 (typically a VersaBoard variant, or an homebrew pcb) + SLOT_INTERFACE_INTERNAL("a78_p450_t0", A78_ROM_P450) + SLOT_INTERFACE_INTERNAL("a78_p450_t1", A78_ROM_P450_POKEY) + SLOT_INTERFACE_INTERNAL("a78_p450_t6", A78_ROM_P450_SG_RAM) + SLOT_INTERFACE_INTERNAL("a78_p450_ta", A78_ROM_P450_SG9) + SLOT_INTERFACE_INTERNAL("a78_p450_vb", A78_ROM_P450_VB) +SLOT_INTERFACE_END + + +// supported devices +SLOT_INTERFACE_EXTERN(a78_cart); + +#endif diff --git a/src/devices/bus/a7800/a78_slot.c b/src/devices/bus/a7800/a78_slot.c new file mode 100644 index 00000000000..6332492a6c2 --- /dev/null +++ b/src/devices/bus/a7800/a78_slot.c @@ -0,0 +1,831 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + Atari 7800 cart emulation + (through slot devices) + + Emulation of the cartslot for Atari 7800 + + Quoting "ATARI 7800 BANKSWITCHING GUIDE" (by Eckhard Stolberg): + 7800 games can use the memory from $0400 to $047f, from $0500 + to $17ff and from $2800 to $ffff, but only the High-Score cart + uses anything below $4000. It has 4KB of ROM at $3000-$3fff + and 2KB of battery-backed RAM at $1000-$17ff. + + Accordingly, we use the following handlers: + - read_04xx/write_04xx for accesses in the $0400 to $047f range + - read_10xx/write_10xx for accesses in the $1000 to $17ff range + - read_30xx/write_30xx for accesses in the $3000 to $3fff range + - read_40xx/write_40xx for accesses in the $4000 to $ffff range + even if not all carts use all of them (in particular no cart type + seems to use access to the ranges $0500 to $0fff and $2800 to $2fff) + + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "a78_slot.h" + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type A78_CART_SLOT = &device_creator; + + +//------------------------------------------------- +// device_vcs_cart_interface - constructor +//------------------------------------------------- + +device_a78_cart_interface::device_a78_cart_interface (const machine_config &mconfig, device_t &device) + : device_slot_card_interface(mconfig, device), + m_rom(NULL), + m_rom_size(0), + m_base_rom(0x8000), + m_bank_mask(0) +{ +} + + +//------------------------------------------------- +// ~device_a78_cart_interface - destructor +//------------------------------------------------- + +device_a78_cart_interface::~device_a78_cart_interface () +{ +} + +//------------------------------------------------- +// rom_alloc - alloc the space for the cart +//------------------------------------------------- + +void device_a78_cart_interface::rom_alloc(UINT32 size, const char *tag) +{ + if (m_rom == NULL) + { + m_rom = device().machine().memory().region_alloc(std::string(tag).append(A78SLOT_ROM_REGION_TAG).c_str(), size, 1, ENDIANNESS_LITTLE)->base(); + m_rom_size = size; + + // setup other helpers + if ((size / 0x4000) & 1) // compensate for SuperGame carts with 9 x 16K banks (to my knowledge no other cart has m_bank_mask != power of 2) + m_bank_mask = (size / 0x4000) - 2; + else + m_bank_mask = (size / 0x4000) - 1; + + // the rom is mapped to the top of the memory area + // so we store the starting point of data to simplify + // the access handling + m_base_rom = 0x10000 - size; + } +} + +//------------------------------------------------- +// ram_alloc - alloc the space for the on-cart RAM +//------------------------------------------------- + +void device_a78_cart_interface::ram_alloc(UINT32 size) +{ + m_ram.resize(size); + device().save_item(NAME(m_ram)); +} + + +//------------------------------------------------- +// ram_alloc - alloc the space for the on-cart RAM +//------------------------------------------------- + +void device_a78_cart_interface::nvram_alloc(UINT32 size) +{ + m_nvram.resize(size); + device().save_item(NAME(m_nvram)); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// a78_cart_slot_device - constructor +//------------------------------------------------- +a78_cart_slot_device::a78_cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, A78_CART_SLOT, "Atari 7800 Cartridge Slot", tag, owner, clock, "a78_cart_slot", __FILE__), + device_image_interface(mconfig, *this), + device_slot_interface(mconfig, *this) +{ +} + + +//------------------------------------------------- +// a78_cart_slot_device - destructor +//------------------------------------------------- + +a78_cart_slot_device::~a78_cart_slot_device() +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void a78_cart_slot_device::device_start() +{ + m_cart = dynamic_cast(get_card_device()); +} + +//------------------------------------------------- +// device_config_complete - perform any +// operations now that the configuration is +// complete +//------------------------------------------------- + +void a78_cart_slot_device::device_config_complete() +{ + // set brief and instance name + update_names(); +} + + + +/*------------------------------------------------- + call load + -------------------------------------------------*/ + +int a78_cart_slot_device::validate_header(int head, bool log) +{ + switch (head & 0x3d) + { + case 0x05: + if (log) + { + osd_printf_info("POKEY + RAM at $4000 (Header 0x05)\n"); + osd_printf_info("Disabling POKEY\n"); + } + head &= ~0x01; + break; + case 0x09: + if (log) + { + osd_printf_info("POKEY + Bank 0 of 144K ROM at $4000 (Header 0x09)\n"); + osd_printf_info("Disabling POKEY\n"); + } + head &= ~0x01; + break; + case 0x11: + if (log) + { + osd_printf_info("POKEY + Bank 6 ROM at $4000 (Header 0x11)\n"); + osd_printf_info("Disabling POKEY\n"); + } + head &= ~0x01; + break; + case 0x21: + if (log) + { + osd_printf_info("POKEY + banked RAM at $4000 (Header 0x21)\n"); + osd_printf_info("Disabling POKEY\n"); + } + head &= ~0x01; + break; + case 0x0c: + if (log) + { + osd_printf_info("RAM + Bank 0 of 144K ROM at $4000 (Header 0x0c)\n"); + osd_printf_info("Disabling RAM\n"); + } + head &= ~0x04; + break; + case 0x14: + if (log) + { + osd_printf_info("RAM + Bank 6 ROM at $4000 (Header 0x14)\n"); + osd_printf_info("Disabling RAM\n"); + } + head &= ~0x04; + break; + case 0x24: + if (log) + { + osd_printf_info("RAM + Banked RAM at $4000 (Header 0x24)\n"); + osd_printf_info("Disabling RAM\n"); + } + head &= ~0x04; + break; + case 0x18: + if (log) + { + osd_printf_info("Bank 0 of 144K ROM + Bank 6 ROM at $4000 (Header 0x18)\n"); + osd_printf_info("Disabling Bank 0 ROM\n"); + } + head &= ~0x08; + break; + case 0x28: + if (log) + { + osd_printf_info("Bank 0 of 144K ROM + Banked RAM at $4000 (Header 0x28)\n"); + osd_printf_info("Disabling Bank 0 ROM\n"); + } + head &= ~0x08; + break; + case 0x30: + if (log) + { + osd_printf_info("Bank 6 ROM + banked RAM at $4000 (Header 0x30)\n"); + osd_printf_info("Disabling Bank 6 ROM\n"); + } + head &= ~0x10; + break; + } + + if ((head & 0x3c) && !(head & 0x02)) + { + if (log) + { + osd_printf_info("SuperCart bankswitch detected at $4000, with no SuperCart bit (Header 0x%X)\n", head); + osd_printf_info("Enablig SuperCart bankswitch\n"); + } + head |= 0x02; + } + + if ((head & 0xff00) == 0x100 && (head & 0xff)) + { + if (log) + { + osd_printf_info("Bankswitch detected for an Activision cart (Header 0x%X)\n", head); + osd_printf_info("Disabling bankswitch\n"); + } + head &= 0xff00; + } + + if ((head & 0xff00) == 0x200 && (head & 0xff)) + { + if (log) + { + osd_printf_info("Bankswitch detected for an Absolute cart (Header 0x%X)\n", head); + osd_printf_info("Disabling bankswitch\n"); + } + head &= 0xff00; + } + + if ((head & 0xff00) > 0x300) + { + if (log) + { + osd_printf_info("Unsupported mapper, please contact MESSdevs (Header 0x%X)\n", head); + osd_printf_info("Disabling special bits\n"); + } + head &= 0x00ff; + } + + return head; +} + + +//------------------------------------------------- +// A78 PCBs +//------------------------------------------------- + +struct a78_slot +{ + int pcb_id; + const char *slot_option; +}; + +#define A78_POKEY0450 0x20 + +// Here, we take the feature attribute from .xml (i.e. the PCB name) and we assign a unique ID to it +static const a78_slot slot_list[] = +{ + { A78_TYPE0, "a78_rom" }, + { A78_TYPE1, "a78_pokey" }, + { A78_TYPE2, "a78_sg" }, + { A78_TYPE3, "a78_sg_pokey" }, + { A78_TYPE6, "a78_sg_ram" }, + { A78_TYPEA, "a78_sg9" }, + { A78_ABSOLUTE, "a78_abs" }, + { A78_ACTIVISION, "a78_act" }, + { A78_HSC, "a78_hsc" }, + { A78_XB_BOARD, "a78_xboard" }, + { A78_XM_BOARD, "a78_xm" }, + { A78_MEGACART, "a78_megacart" }, + { A78_VERSABOARD, "a78_versa" }, + { A78_TYPE0_POK450, "a78_p450_t0" }, + { A78_TYPE1_POK450, "a78_p450_t1" }, + { A78_TYPE6_POK450, "a78_p450_t6" }, + { A78_TYPEA_POK450, "a78_p450_ta" }, + { A78_VERSA_POK450, "a78_p450_vb" } +}; + +static int a78_get_pcb_id(const char *slot) +{ + for (int i = 0; i < ARRAY_LENGTH(slot_list); i++) + { + if (!core_stricmp(slot_list[i].slot_option, slot)) + return slot_list[i].pcb_id; + } + + return 0; +} + +static const char *a78_get_slot(int type) +{ + for (int i = 0; i < ARRAY_LENGTH(slot_list); i++) + { + if (slot_list[i].pcb_id == type) + return slot_list[i].slot_option; + } + + return "a78_rom"; +} + +bool a78_cart_slot_device::call_load() +{ + if (m_cart) + { + UINT32 len; + + if (software_entry() != NULL) + { + const char *pcb_name; + bool has_ram = get_software_region("ram") ? TRUE : FALSE; + bool has_nvram = get_software_region("nvram") ? TRUE : FALSE; + len = get_software_region_length("rom"); + + m_cart->rom_alloc(len, tag()); + memcpy(m_cart->get_rom_base(), get_software_region("rom"), len); + + if ((pcb_name = get_feature("slot")) != NULL) + m_type = a78_get_pcb_id(pcb_name); + else + m_type = A78_TYPE0; + + if (has_ram) + m_cart->ram_alloc(get_software_region_length("ram")); + if (has_nvram) + { + m_cart->nvram_alloc(get_software_region_length("nvram")); + battery_load(m_cart->get_nvram_base(), get_software_region_length("nvram"), 0xff); + } + } + else + { + // Load and check the header + int mapper; + char head[128]; + fread(head, 128); + + if (verify_header((char *)head) == IMAGE_VERIFY_FAIL) + return IMAGE_INIT_FAIL; + + len = (head[49] << 24) | (head[50] << 16) | (head[51] << 8) | head[52]; + if (len + 128 > length()) + { + logerror("Invalid length in the header. The game might be corrupted.\n"); + len = length() - 128; + } + + // let's try to auto-fix some common errors in the header + mapper = validate_header((head[53] << 8) | head[54], TRUE); + + switch (mapper & 0x2e) + { + case 0x0000: + m_type = BIT(mapper, 0) ? A78_TYPE1 : A78_TYPE0; + break; + case 0x0002: + m_type = BIT(mapper, 0) ? A78_TYPE3 : A78_TYPE2; + break; + case 0x0006: + m_type = A78_TYPE6; + break; + case 0x000a: + m_type = A78_TYPEA; + break; + case 0x0022: + case 0x0026: + if (len > 0x40000) + m_type = A78_MEGACART; + else + m_type = A78_VERSABOARD; + break; + } + + // check if cart has a POKEY at $0450 (typically a VersaBoard variant)! + if (mapper & 0x40) + { + if (m_type != A78_TYPE2) + { + m_type &= ~0x02; + m_type += A78_POKEY0450; + } + } + + // check special bits, which override the previous + if ((mapper & 0xff00) == 0x0100) + m_type = A78_ACTIVISION; + else if ((mapper & 0xff00) == 0x0200) + m_type = A78_ABSOLUTE; + + logerror("Cart type: 0x%x\n", m_type); + + if (head[58] == 1) + { + osd_printf_info("This cart support external NVRAM savings, using HSC.\n"); + osd_printf_info("Run it with the High Score Cart mounted to exploit this feature.\n"); + } + else if (head[58] == 2) + { + osd_printf_info("This cart support external NVRAM savings, using SaveKey.\n"); + osd_printf_info("This is not supported in MESS currently.\n"); + } + + if (head[63]) + { + osd_printf_info("This cart requires XBoarD / XM expansion\n"); + osd_printf_info("Run it through the expansion to exploit this feature.\n"); + } + + internal_header_logging((UINT8 *)head, length()); + + m_cart->rom_alloc(len, tag()); + fread(m_cart->get_rom_base(), len); + + if (m_type == A78_TYPE6) + m_cart->ram_alloc(0x4000); + if (m_type == A78_MEGACART || (m_type >= A78_VERSABOARD && m_type <= A78_VERSA_POK450)) + m_cart->ram_alloc(0x8000); + if (m_type == A78_XB_BOARD || m_type == A78_XM_BOARD) + m_cart->ram_alloc(0x20000); + if (m_type == A78_HSC || m_type == A78_XM_BOARD) + { + m_cart->nvram_alloc(0x800); + battery_load(m_cart->get_nvram_base(), 0x800, 0xff); + } + } + + //printf("Type: %s\n", a78_get_slot(m_type)); + } + return IMAGE_INIT_PASS; +} + + +void a78_partialhash(hash_collection &dest, const unsigned char *data, + unsigned long length, const char *functions) +{ + if (length <= 128) + return; + dest.compute(&data[128], length - 128, functions); +} + + +/*------------------------------------------------- + call_unload + -------------------------------------------------*/ + +void a78_cart_slot_device::call_unload() +{ + if (m_cart && m_cart->get_nvram_base() && m_cart->get_nvram_size()) + battery_save(m_cart->get_nvram_base(), 0x800); +} + + + +/*------------------------------------------------- + call softlist load + -------------------------------------------------*/ + +bool a78_cart_slot_device::call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry) +{ + load_software_part_region(*this, swlist, swname, start_entry); + return TRUE; +} + +/*------------------------------------------------- + verify_header - check the image (from fullpath) + has an admissible header + -------------------------------------------------*/ + +int a78_cart_slot_device::verify_header(char *header) +{ + const char *magic = "ATARI7800"; + + if (strncmp(magic, header + 1, 9)) + { + logerror("Not a valid A7800 image\n"); + return IMAGE_VERIFY_FAIL; + } + + logerror("returning ID_OK\n"); + return IMAGE_VERIFY_PASS; +} + + +/*------------------------------------------------- + get default card software + -------------------------------------------------*/ + +void a78_cart_slot_device::get_default_card_software(std::string &result) +{ + if (open_image_file(mconfig().options())) + { + const char *slot_string = "a78_rom"; + dynamic_buffer head(128); + int type = A78_TYPE0, mapper; + + // Load and check the header + core_fread(m_file, &head[0], 128); + + // let's try to auto-fix some common errors in the header + mapper = validate_header((head[53] << 8) | head[54], FALSE); + + switch (mapper & 0x2e) + { + case 0x0000: + type = BIT(mapper, 0) ? A78_TYPE1 : A78_TYPE0; + break; + case 0x0002: + type = BIT(mapper, 0) ? A78_TYPE3 : A78_TYPE2; + break; + case 0x0006: + type = A78_TYPE6; + break; + case 0x000a: + type = A78_TYPEA; + break; + case 0x0022: + case 0x0026: + if (core_fsize(m_file) > 0x40000) + type = A78_MEGACART; + else + type = A78_VERSABOARD; + break; + } + + // check if cart has a POKEY at $0450 (typically a VersaBoard variant)! + if (mapper & 0x40) + { + if (type != A78_TYPE2) + { + type &= ~0x02; + type += A78_POKEY0450; + } + } + + // check special bits, which override the previous + if ((mapper & 0xff00) == 0x0100) + type = A78_ACTIVISION; + else if ((mapper & 0xff00) == 0x0200) + type = A78_ABSOLUTE; + + logerror("Cart type: %x\n", type); + slot_string = a78_get_slot(type); + + clear(); + + result.assign(slot_string); + } + else + software_get_default_slot(result, "a78_rom"); +} + + +/*------------------------------------------------- + read + -------------------------------------------------*/ + +READ8_MEMBER(a78_cart_slot_device::read_04xx) +{ + if (m_cart) + return m_cart->read_04xx(space, offset, mem_mask); + else + return 0xff; +} + +READ8_MEMBER(a78_cart_slot_device::read_10xx) +{ + if (m_cart) + return m_cart->read_10xx(space, offset, mem_mask); + else + return 0xff; +} + +READ8_MEMBER(a78_cart_slot_device::read_30xx) +{ + if (m_cart) + return m_cart->read_30xx(space, offset, mem_mask); + else + return 0xff; +} + +READ8_MEMBER(a78_cart_slot_device::read_40xx) +{ + if (m_cart) + return m_cart->read_40xx(space, offset, mem_mask); + else + return 0xff; +} + + +/*------------------------------------------------- + write + -------------------------------------------------*/ + +WRITE8_MEMBER(a78_cart_slot_device::write_04xx) +{ + if (m_cart) + m_cart->write_04xx(space, offset, data, mem_mask); +} + +WRITE8_MEMBER(a78_cart_slot_device::write_10xx) +{ + if (m_cart) + m_cart->write_10xx(space, offset, data, mem_mask); +} + +WRITE8_MEMBER(a78_cart_slot_device::write_30xx) +{ + if (m_cart) + m_cart->write_30xx(space, offset, data, mem_mask); +} + +WRITE8_MEMBER(a78_cart_slot_device::write_40xx) +{ + if (m_cart) + m_cart->write_40xx(space, offset, data, mem_mask); +} + + +/*------------------------------------------------- + A78 header logging + + A78 HEADER FORMAT + + Bytes | Content | Length + ======================================== + 0 | Header version | 1 byte + -------|-------------------|------------ + 1..16 | "ATARI7800 " | 16 bytes + -------|-------------------|------------ + 17..48 | Cart title | 32 bytes + -------|-------------------|------------ + 49..52 | Data length | 4 bytes + -------|-------------------|------------ + 53..54 | Cart type [*] | 2 bytes + -------|-------------------|------------ + 55 | Controller 1 type | 1 byte + | | + | 0 = None | + | 1 = Joystick | + | 2 = Light Gun | + -------|-------------------|------------ + 56 | Controller 2 type | 1 byte + | | + | As above | + -------|-------------------|------------ + 57 | TV System | 1 byte + | | + | 0 = NTSC/1 = PAL | + -------|-------------------|------------ + 58 | Save data | 1 byte + | | (only v2) + | 0 = None / Unk | + | 1 = High Score | + | 2 = Savekey | + -------|-------------------|----------- + 63 | Expansion module | 1 byte + | | + | 0 = No expansion | + | module | + | 1 = Expansion | + | required | + -------|-------------------|----------- + + + [*] Cart type: + + bit 0-7 - Hardware "flags" + bit 0 [0x01] - POKEY at $4000 + bit 1 [0x02] - SuperCart bank switched + bit 2 [0x04] - SuperCart RAM at $4000 + bit 3 [0x08] - bank 0 of 144K ROM at $4000 + bit 4 [0x10] - bank 6 at $4000 + bit 5 [0x20] - banked RAM at $4000 + + bit 8-15 - Special values + 0 = Normal cart + 1 = Absolute (F18 Hornet) + 2 = Activision (Double Dragon & Rampage) + 3 = POKEY at $0450 + + -------------------------------------------------*/ + +void a78_cart_slot_device::internal_header_logging(UINT8 *header, UINT32 len) +{ + char head_title[35]; + UINT32 head_length = (header[49] << 24) | (header[50] << 16) | (header[51] << 8) | header[52]; + UINT16 head_mapper = (header[53] << 8) | header[54]; + UINT8 head_ctrl1 = header[55]; + UINT8 head_ctrl2 = header[56]; + UINT8 head_ispal = header[57]; + std::string cart_mapper, ctrl1, ctrl2; + memcpy(head_title, header + 0x11, 0x20); + + switch (head_mapper) + { + case 0x0000: + cart_mapper.assign("No Bankswitch"); + break; + case 0x0001: + cart_mapper.assign("No Bankswitch + POKEY"); + break; + case 0x0002: + cart_mapper.assign("SuperCart Bankswitch"); + break; + case 0x0003: + cart_mapper.assign("SuperCart Bankswitch + POKEY"); + break; + case 0x0006: + cart_mapper.assign("SuperCart Bankswitch + RAM"); + break; + case 0x000a: + cart_mapper.assign("SuperCart 9Banks"); + break; + case 0x000b: + cart_mapper.assign("SuperCart XM Compatible"); + break; + case 0x0020: + cart_mapper.assign("SuperCart Bankswitch + 32K RAM"); + break; + case 0x0100: + cart_mapper.assign("Activision Bankswitch"); + break; + case 0x0200: + cart_mapper.assign("Absolute Bankswitch"); + break; + default: + cart_mapper.assign("Unknown mapper"); + break; + } + + switch (head_ctrl1) + { + case 0x00: + ctrl1.assign("None"); + break; + case 0x01: + ctrl1.assign("Joystick"); + break; + case 0x02: + ctrl1.assign("Light Gun"); + break; + default: + ctrl1.assign("Unknown controller"); + break; + } + + switch (head_ctrl2) + { + case 0x00: + ctrl2.assign("None"); + break; + case 0x01: + ctrl2.assign("Joystick"); + break; + case 0x02: + ctrl2.assign("Light Gun"); + break; + default: + ctrl2.assign("Unknown controller"); + break; + } + + logerror( "ROM DETAILS\n" ); + logerror( "===========\n\n" ); + logerror( "\tTotal length (with header): 0x%x (%dK + 128b header)\n\n", len, len/0x400); + logerror( "HEADER DETAILS\n" ); + logerror( "==============\n\n" ); + logerror( "\tTitle: %.32s\n", head_title); + logerror( "\tLength: 0x%X [real 0x%X]\n", head_length, len); + logerror( "\tMapper: %s [0x%X]\n", cart_mapper.c_str(), head_mapper); + logerror( "\t\tPOKEY: %s\n", BIT(head_mapper, 0) ? "Yes" : "No"); + logerror( "\t\tSC Bankswitch: %s\n", BIT(head_mapper, 1) ? "Yes" : "No"); + logerror( "\t\tRAM at $4000: %s\n", BIT(head_mapper, 2) ? "Yes" : "No"); + logerror( "\t\tbank0 at $4000: %s\n", BIT(head_mapper, 3) ? "Yes" : "No"); + logerror( "\t\tbank6 at $4000: %s\n", BIT(head_mapper, 4) ? "Yes" : "No"); + logerror( "\t\tbanked RAM: %s\n", BIT(head_mapper, 5) ? "Yes" : "No"); + logerror( "\t\tSpecial: %s ", (head_mapper & 0xff00) ? "Yes" : "No"); + if (head_mapper & 0xff00) + { + logerror( "[%s]\n", (head_mapper & 0xff00) == 0x100 ? "Absolute" : + (head_mapper & 0xff00) == 0x200 ? "Activision" : "Unknown" ); + } + else + logerror( "\n"); + logerror( "\tController 1: 0x%.2X [%s]\n", head_ctrl1, ctrl1.c_str()); + logerror( "\tController 2: 0x%.2X [%s]\n", head_ctrl2, ctrl2.c_str()); + logerror( "\tVideo: %s\n", (head_ispal) ? "PAL" : "NTSC"); +} diff --git a/src/devices/bus/a7800/a78_slot.h b/src/devices/bus/a7800/a78_slot.h new file mode 100644 index 00000000000..ff41ae8a608 --- /dev/null +++ b/src/devices/bus/a7800/a78_slot.h @@ -0,0 +1,155 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __A78_SLOT_H +#define __A78_SLOT_H + + +/*************************************************************************** + TYPE DEFINITIONS + ***************************************************************************/ + + +/* PCB */ +enum +{ + A78_TYPE0 = 0, // standard 8K/16K/32K games, no bankswitch + A78_TYPE1, // as TYPE0 + POKEY chip on the PCB + A78_TYPE2, // Atari SuperGame pcb (8x16K banks with bankswitch) + A78_TYPE3, // as TYPE1 + POKEY chip on the PCB + A78_TYPE6, // as TYPE1 + RAM IC on the PCB + A78_TYPEA, // Alien Brigade, Crossbow (9x16K banks with diff bankswitch) + A78_ABSOLUTE, // F18 Hornet + A78_ACTIVISION, // Double Dragon, Rampage + A78_HSC, // Atari HighScore cart + A78_XB_BOARD, // A7800 Expansion Board (it shall more or less apply to the Expansion Module too, but this is not officially released yet) + A78_XM_BOARD, // A7800 XM Expansion Module (theoretical specs only, since this is not officially released yet) + A78_MEGACART, // Homebrew by CPUWIZ, consists of SuperGame bank up to 512K + 32K RAM banked + A78_VERSABOARD = 0x10, // Homebrew by CPUWIZ, consists of SuperGame bank up to 256K + 32K RAM banked + // VersaBoard variants configured as Type 1/3/A or VersaBoard + POKEY at $0450 + A78_TYPE0_POK450 = 0x20, + A78_TYPE1_POK450 = 0x21, + A78_TYPE6_POK450 = 0x24, + A78_TYPEA_POK450 = 0x25, + A78_VERSA_POK450 = 0x30 +}; + + +// ======================> device_a78_cart_interface + +class device_a78_cart_interface : public device_slot_card_interface +{ +public: + // construction/destruction + device_a78_cart_interface(const machine_config &mconfig, device_t &device); + virtual ~device_a78_cart_interface(); + + // memory accessor + virtual DECLARE_READ8_MEMBER(read_04xx) { return 0xff; } + virtual DECLARE_READ8_MEMBER(read_10xx) { return 0xff; } + virtual DECLARE_READ8_MEMBER(read_30xx) { return 0xff; } + virtual DECLARE_READ8_MEMBER(read_40xx) { return 0xff; } + virtual DECLARE_WRITE8_MEMBER(write_04xx) {} + virtual DECLARE_WRITE8_MEMBER(write_10xx) {} + virtual DECLARE_WRITE8_MEMBER(write_30xx) {} + virtual DECLARE_WRITE8_MEMBER(write_40xx) {} + + void rom_alloc(UINT32 size, const char *tag); + void ram_alloc(UINT32 size); + void nvram_alloc(UINT32 size); + UINT8* get_rom_base() { return m_rom; } + UINT8* get_ram_base() { return &m_ram[0]; } + UINT8* get_nvram_base() { return &m_nvram[0]; } + UINT32 get_rom_size() { return m_rom_size; } + UINT32 get_ram_size() { return m_ram.size(); } + UINT32 get_nvram_size() { return m_nvram.size(); } + +protected: + // internal state + UINT8 *m_rom; + UINT32 m_rom_size; + dynamic_buffer m_ram; + dynamic_buffer m_nvram; // HiScore cart can save scores! + // helpers + UINT32 m_base_rom; + int m_bank_mask; +}; + + +void a78_partialhash(hash_collection &dest, const unsigned char *data, unsigned long length, const char *functions); + + +// ======================> a78_cart_slot_device + +class a78_cart_slot_device : public device_t, + public device_image_interface, + public device_slot_interface +{ +public: + // construction/destruction + a78_cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual ~a78_cart_slot_device(); + + // device-level overrides + virtual void device_start(); + virtual void device_config_complete(); + + // image-level overrides + virtual bool call_load(); + virtual void call_unload(); + virtual bool call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry); + + int get_cart_type() { return m_type; }; + int identify_cart_type(UINT8 *ROM, UINT32 len); + bool has_cart() { return m_cart != NULL; } + + virtual iodevice_t image_type() const { return IO_CARTSLOT; } + virtual bool is_readable() const { return 1; } + virtual bool is_writeable() const { return 0; } + virtual bool is_creatable() const { return 0; } + virtual bool must_be_loaded() const { return 0; } + virtual bool is_reset_on_load() const { return 1; } + virtual const option_guide *create_option_guide() const { return NULL; } + virtual const char *image_interface() const { return "a7800_cart"; } + virtual const char *file_extensions() const { return "bin,a78"; } + virtual device_image_partialhash_func get_partial_hash() const { return &a78_partialhash; } + + // slot interface overrides + virtual void get_default_card_software(std::string &result); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_04xx); + virtual DECLARE_READ8_MEMBER(read_10xx); + virtual DECLARE_READ8_MEMBER(read_30xx); + virtual DECLARE_READ8_MEMBER(read_40xx); + virtual DECLARE_WRITE8_MEMBER(write_04xx); + virtual DECLARE_WRITE8_MEMBER(write_10xx); + virtual DECLARE_WRITE8_MEMBER(write_30xx); + virtual DECLARE_WRITE8_MEMBER(write_40xx); + +private: + device_a78_cart_interface* m_cart; + int m_type; + int m_stick_type; + + int verify_header(char *header); + int validate_header(int head, bool log); + void internal_header_logging(UINT8 *header, UINT32 len); +}; + + +// device type definition +extern const device_type A78_CART_SLOT; + + +/*************************************************************************** + DEVICE CONFIGURATION MACROS + ***************************************************************************/ + +#define A78SLOT_ROM_REGION_TAG ":cart:rom" + +#define MCFG_A78_CARTRIDGE_ADD(_tag,_slot_intf,_def_slot) \ + MCFG_DEVICE_ADD(_tag, A78_CART_SLOT, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) + + +#endif diff --git a/src/devices/bus/a7800/cpuwiz.c b/src/devices/bus/a7800/cpuwiz.c new file mode 100644 index 00000000000..9185e49ac7c --- /dev/null +++ b/src/devices/bus/a7800/cpuwiz.c @@ -0,0 +1,132 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + A7800 CPUWIZ's homebrew boards (MegaCart+ and VersaBoard) + + Here we emulate the base configurations of these two boards: + + MegaCart+ = up to 512K (31 banks at $8000, 1 at $C000) of ROM and 2 x 16K RAM @ $4000 + VersaBoard = up to 256K of ROM and 2 x 16K RAM + + Plus, for the moment, a VersaBoard with POKEY mapped at 0x0450 and support for 144K ROM, + since a few demo homebrew programs seems to use this to combine compatibility with + XBoarD & XM expansions + + Note that the VersaBoard can be configured to work with different banking hardware + e.g. with SG 9bank games or with SG + RAM (so to allow reproduction of games which + could have worked on old carts without sacrifying original carts), but games running + on those "standard" variants can be emulated with the standard code from rom.c ;-) + + + TO DO: + - investigate whether the POKEY detection routines in homebrew do fail due to emulation + issues or not + +***********************************************************************************************************/ + + +#include "emu.h" +#include "cpuwiz.h" + + +//------------------------------------------------- +// constructor +//------------------------------------------------- + +const device_type A78_ROM_VERSABOARD = &device_creator; +const device_type A78_ROM_MEGACART = &device_creator; + +const device_type A78_ROM_P450_VB = &device_creator; + + +a78_versaboard_device::a78_versaboard_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : a78_rom_sg_device(mconfig, type, name, tag, owner, clock, shortname, source) +{ +} + +a78_versaboard_device::a78_versaboard_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : a78_rom_sg_device(mconfig, A78_ROM_VERSABOARD, "Atari 7800 VersaBoard Cart", tag, owner, clock, "a78_versaboard", __FILE__) +{ +} + + +a78_megacart_device::a78_megacart_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : a78_versaboard_device(mconfig, A78_ROM_MEGACART, "Atari 7800 MegaCart+", tag, owner, clock, "a78_megacart", __FILE__) +{ +} + + +a78_rom_p450_vb_device::a78_rom_p450_vb_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : a78_versaboard_device(mconfig, A78_ROM_P450_VB, "Atari 7800 VersaBoard + POKEY @ 0x0450 Cart", tag, owner, clock, "a78_versapokey", __FILE__), + m_pokey450(*this, "pokey450") +{ +} + + +void a78_versaboard_device::device_start() +{ + save_item(NAME(m_bank)); + save_item(NAME(m_ram_bank)); +} + +void a78_versaboard_device::device_reset() +{ + m_bank = 0; + m_ram_bank = 0; +} + + +// VersaBoard + +READ8_MEMBER(a78_versaboard_device::read_40xx) +{ + if (offset < 0x4000) + return m_ram[offset + (m_ram_bank * 0x4000)]; + else if (offset < 0x8000) + return m_rom[(offset & 0x3fff) + (m_bank * 0x4000)]; + else + return m_rom[(offset & 0x3fff) + (m_bank_mask * 0x4000)]; // last bank +} + +WRITE8_MEMBER(a78_versaboard_device::write_40xx) +{ + if (offset < 0x4000) + m_ram[offset + (m_ram_bank * 0x4000)] = data; + else if (offset < 0x8000) + { + // hardware allows up to 256K ROM + m_bank = (data & 0x0f) & m_bank_mask; + m_ram_bank = BIT(data, 5); + } +} + + +// MegaCart+ + +WRITE8_MEMBER(a78_megacart_device::write_40xx) +{ + if (offset < 0x4000) + m_ram[offset + (m_ram_bank * 0x4000)] = data; + else if (offset < 0x8000) + { + // hardware allows up to 512K ROM + m_bank = (data & 0x1f) & m_bank_mask; + m_ram_bank = BIT(data, 5); + } +} + + +// VersaBoard + POKEY @ 0x0450 + +static MACHINE_CONFIG_FRAGMENT( a78_pokeyvb ) + MCFG_SPEAKER_STANDARD_MONO("addon") + + MCFG_SOUND_ADD("pokey450", POKEY, XTAL_14_31818MHz/8) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "addon", 1.00) +MACHINE_CONFIG_END + +machine_config_constructor a78_rom_p450_vb_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( a78_pokeyvb ); +} diff --git a/src/devices/bus/a7800/cpuwiz.h b/src/devices/bus/a7800/cpuwiz.h new file mode 100644 index 00000000000..75f980fbffd --- /dev/null +++ b/src/devices/bus/a7800/cpuwiz.h @@ -0,0 +1,74 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __A78_CPUWIZ_H +#define __A78_CPUWIZ_H + +#include "a78_slot.h" +#include "rom.h" + + +// ======================> a78_versaboard_device + +class a78_versaboard_device : public a78_rom_sg_device +{ +public: + // construction/destruction + a78_versaboard_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + a78_versaboard_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_40xx); + virtual DECLARE_WRITE8_MEMBER(write_40xx); + +protected: + int m_ram_bank; +}; + + +// ======================> a78_megacart_device + +class a78_megacart_device : public a78_versaboard_device +{ +public: + // construction/destruction + a78_megacart_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // reading and writing + virtual DECLARE_WRITE8_MEMBER(write_40xx); +}; + + +// VersaBoard variants of the standard carts + POKEY at 0x0450! + +// ======================> a78_rom_p450_vb_device + +class a78_rom_p450_vb_device : public a78_versaboard_device +{ +public: + // construction/destruction + a78_rom_p450_vb_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual machine_config_constructor device_mconfig_additions() const; + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_04xx) { if (offset >= 0x50 && offset < 0x60) return m_pokey450->read(space, offset & 0x0f); else return 0xff; } + virtual DECLARE_WRITE8_MEMBER(write_04xx) { if (offset >= 0x50 && offset < 0x60) m_pokey450->write(space, offset & 0x0f, data); } + +protected: + required_device m_pokey450; +}; + + + +// device type definition +extern const device_type A78_ROM_VERSABOARD; +extern const device_type A78_ROM_MEGACART; + +extern const device_type A78_ROM_P450_VB; + +#endif diff --git a/src/devices/bus/a7800/hiscore.c b/src/devices/bus/a7800/hiscore.c new file mode 100644 index 00000000000..cbdab10f02d --- /dev/null +++ b/src/devices/bus/a7800/hiscore.c @@ -0,0 +1,77 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + A7800 HighScore passthrough cart emulation + + +***********************************************************************************************************/ + + +#include "emu.h" +#include "hiscore.h" +#include "a78_carts.h" + + +//------------------------------------------------- +// constructor +//------------------------------------------------- + +const device_type A78_HISCORE = &device_creator; + + +a78_hiscore_device::a78_hiscore_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : a78_rom_device(mconfig, A78_HISCORE, "Atari 7800 High Score Cart", tag, owner, clock, "a78_highscore", __FILE__), + m_hscslot(*this, "hsc_slot") +{ +} + + +static MACHINE_CONFIG_FRAGMENT( a78_highscore ) + MCFG_A78_CARTRIDGE_ADD("hsc_slot", a7800_cart, NULL) +MACHINE_CONFIG_END + +machine_config_constructor a78_hiscore_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( a78_highscore ); +} + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +READ8_MEMBER(a78_hiscore_device::read_10xx) +{ + return m_nvram[offset]; +} + +WRITE8_MEMBER(a78_hiscore_device::write_10xx) +{ + m_nvram[offset] = data; +} + +READ8_MEMBER(a78_hiscore_device::read_30xx) +{ + return m_rom[offset]; +} + +READ8_MEMBER(a78_hiscore_device::read_04xx) +{ + return m_hscslot->read_04xx(space, offset); +} + +WRITE8_MEMBER(a78_hiscore_device::write_04xx) +{ + m_hscslot->write_04xx(space, offset, data); +} + +READ8_MEMBER(a78_hiscore_device::read_40xx) +{ + return m_hscslot->read_40xx(space, offset); +} + +WRITE8_MEMBER(a78_hiscore_device::write_40xx) +{ + m_hscslot->write_40xx(space, offset, data); +} diff --git a/src/devices/bus/a7800/hiscore.h b/src/devices/bus/a7800/hiscore.h new file mode 100644 index 00000000000..9677e72cdb0 --- /dev/null +++ b/src/devices/bus/a7800/hiscore.h @@ -0,0 +1,40 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __A78_HISCORE_H +#define __A78_HISCORE_H + +#include "a78_slot.h" +#include "rom.h" + + +// ======================> a78_hiscore_device + +class a78_hiscore_device : public a78_rom_device +{ +public: + // construction/destruction + a78_hiscore_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual machine_config_constructor device_mconfig_additions() const; + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_04xx); + virtual DECLARE_WRITE8_MEMBER(write_04xx); + virtual DECLARE_READ8_MEMBER(read_10xx); + virtual DECLARE_WRITE8_MEMBER(write_10xx); + virtual DECLARE_READ8_MEMBER(read_30xx); + virtual DECLARE_READ8_MEMBER(read_40xx); + virtual DECLARE_WRITE8_MEMBER(write_40xx); + +protected: + required_device m_hscslot; +}; + + + +// device type definition +extern const device_type A78_HISCORE; + + +#endif diff --git a/src/devices/bus/a7800/rom.c b/src/devices/bus/a7800/rom.c new file mode 100644 index 00000000000..fa44813dba4 --- /dev/null +++ b/src/devices/bus/a7800/rom.c @@ -0,0 +1,497 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + A7800 ROM cart emulation + + For the moment we use separate devices for each combination of hardware + - bankswitch or not + - pokey or not + - 9 banks or not + etc... + But we might merge many of these if they become too many + + TODO: + - Are POKEY regs readable somewhere in SG 144K + POKEY homebrew? How do they detect + the POKEY otherwise?!? + +***********************************************************************************************************/ + + +#include "emu.h" +#include "rom.h" + + +//------------------------------------------------- +// constructor +//------------------------------------------------- + +const device_type A78_ROM = &device_creator; +const device_type A78_ROM_SG = &device_creator; +const device_type A78_ROM_POKEY = &device_creator; +const device_type A78_ROM_SG_POKEY = &device_creator; +const device_type A78_ROM_SG_RAM = &device_creator; +const device_type A78_ROM_SG9 = &device_creator; +const device_type A78_ROM_ABSOLUTE = &device_creator; +const device_type A78_ROM_ACTIVISION = &device_creator; + + +const device_type A78_ROM_P450 = &device_creator; +const device_type A78_ROM_P450_POKEY = &device_creator; +const device_type A78_ROM_P450_SG_RAM = &device_creator; +const device_type A78_ROM_P450_SG9 = &device_creator; + + +a78_rom_device::a78_rom_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_a78_cart_interface( mconfig, *this ) +{ +} + +a78_rom_device::a78_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, A78_ROM, "Atari 7800 ROM Carts w/no Bankswitch", tag, owner, clock, "a78_rom", __FILE__), + device_a78_cart_interface( mconfig, *this ) +{ +} + +a78_rom_pokey_device::a78_rom_pokey_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : a78_rom_device(mconfig, type, name, tag, owner, clock, shortname, source), + m_pokey(*this, "pokey") +{ +} + +a78_rom_pokey_device::a78_rom_pokey_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : a78_rom_device(mconfig, A78_ROM_POKEY, "Atari 7800 ROM Carts w/no Bankswitch + POKEY", tag, owner, clock, "a78_rom_pok", __FILE__), + m_pokey(*this, "pokey") +{ +} + + +a78_rom_sg_device::a78_rom_sg_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : a78_rom_device(mconfig, type, name, tag, owner, clock, shortname, source) +{ +} + +a78_rom_sg_device::a78_rom_sg_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : a78_rom_device(mconfig, A78_ROM_SG, "Atari 7800 ROM Carts w/SuperGame Bankswitch", tag, owner, clock, "a78_rom_sg", __FILE__) +{ +} + +a78_rom_sg_pokey_device::a78_rom_sg_pokey_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : a78_rom_sg_device(mconfig, A78_ROM_SG_POKEY, "Atari 7800 ROM Carts w/SuperGame Bankswitch + POKEY", tag, owner, clock, "a78_rom_sgp", __FILE__), + m_pokey(*this, "pokey") +{ +} + + +a78_rom_sg_ram_device::a78_rom_sg_ram_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : a78_rom_sg_device(mconfig, type, name, tag, owner, clock, shortname, source) +{ +} + +a78_rom_sg_ram_device::a78_rom_sg_ram_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : a78_rom_sg_device(mconfig, A78_ROM_SG_RAM, "Atari 7800 ROM Carts w/SuperGame Bankswitch + RAM", tag, owner, clock, "a78_rom_sgr", __FILE__) +{ +} + + +a78_rom_sg9_device::a78_rom_sg9_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : a78_rom_sg_device(mconfig, type, name, tag, owner, clock, shortname, source) +{ +} + +a78_rom_sg9_device::a78_rom_sg9_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : a78_rom_sg_device(mconfig, A78_ROM_SG9, "Atari 7800 ROM Carts w/SuperGame 9Banks", tag, owner, clock, "a78_rom_sg9", __FILE__) +{ +} + + +a78_rom_abs_device::a78_rom_abs_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : a78_rom_device(mconfig, A78_ROM_ABSOLUTE, "Atari 7800 ROM Carts w/Absolute Bankswitch", tag, owner, clock, "a78_rom_abs", __FILE__) +{ +} + + +a78_rom_act_device::a78_rom_act_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : a78_rom_device(mconfig, A78_ROM_ACTIVISION, "Atari 7800 ROM Carts w/Activision Bankswitch", tag, owner, clock, "a78_rom_act", __FILE__) +{ +} + + + +a78_rom_p450_device::a78_rom_p450_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : a78_rom_device(mconfig, A78_ROM_P450, "Atari 7800 ROM Carts w/POKEY @ 0x0450", tag, owner, clock, "a78_p450_t0", __FILE__), + m_pokey450(*this, "pokey450") +{ +} + +a78_rom_p450_pokey_device::a78_rom_p450_pokey_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : a78_rom_pokey_device(mconfig, A78_ROM_P450_POKEY, "Atari 7800 ROM Carts w/no Bankswitch + POKEY + POKEY @ 0x0450", tag, owner, clock, "a78_p450_t1", __FILE__), + m_pokey450(*this, "pokey450") +{ +} + +a78_rom_p450_sg_ram_device::a78_rom_p450_sg_ram_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : a78_rom_sg_ram_device(mconfig, A78_ROM_P450_SG_RAM, "Atari 7800 ROM Carts w/SuperGame Bankswitch + RAM + POKEY @ 0x0450", tag, owner, clock, "a78_p450_t6", __FILE__), + m_pokey450(*this, "pokey450") +{ +} + +a78_rom_p450_sg9_device::a78_rom_p450_sg9_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : a78_rom_sg9_device(mconfig, A78_ROM_P450_SG9, "Atari 7800 ROM Carts w/SuperGame 9Banks + POKEY @ 0x0450", tag, owner, clock, "a78_p450_ta", __FILE__), + m_pokey450(*this, "pokey450") +{ +} + + + +void a78_rom_device::device_start() +{ +} + +void a78_rom_device::device_reset() +{ +} + +void a78_rom_sg_device::device_start() +{ + save_item(NAME(m_bank)); +} + +void a78_rom_sg_device::device_reset() +{ + m_bank = 0; +} + +void a78_rom_abs_device::device_start() +{ + save_item(NAME(m_bank)); +} + +void a78_rom_abs_device::device_reset() +{ + m_bank = 0; +} + +void a78_rom_act_device::device_start() +{ + save_item(NAME(m_bank)); +} + +void a78_rom_act_device::device_reset() +{ + m_bank = 0; +} + +// TO DO: do we need a PAL variant?!? +static MACHINE_CONFIG_FRAGMENT( a78_pokey ) + MCFG_SPEAKER_STANDARD_MONO("addon") + + MCFG_SOUND_ADD("pokey", POKEY, XTAL_14_31818MHz/8) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "addon", 1.00) +MACHINE_CONFIG_END + +static MACHINE_CONFIG_FRAGMENT( a78_pokey450 ) + MCFG_SPEAKER_STANDARD_MONO("pokey_450") + + MCFG_SOUND_ADD("pokey450", POKEY, XTAL_14_31818MHz/8) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "pokey_450", 1.00) +MACHINE_CONFIG_END + +static MACHINE_CONFIG_FRAGMENT( a78_2pokeys ) + MCFG_SPEAKER_STANDARD_MONO("addon") + + MCFG_SOUND_ADD("pokey", POKEY, XTAL_14_31818MHz/8) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "addon", 1.00) + + MCFG_SOUND_ADD("pokey450", POKEY, XTAL_14_31818MHz/8) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "addon", 1.00) +MACHINE_CONFIG_END + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +/*------------------------------------------------- + + Carts with no bankswitch (8K to 48K) + + GAMES: Asteroids, Centipede, Dig Dug and many more + + -------------------------------------------------*/ + +READ8_MEMBER(a78_rom_device::read_40xx) +{ + if (offset + 0x4000 < m_base_rom) + return 0xff; + else + return m_rom[offset + 0x4000 - m_base_rom]; +} + +/*------------------------------------------------- + + Carts with no bankswitch + POKEY chip + The Pokey chips is accessed by writing at + 0x4000-0x7fff. + + GAMES: Ballblazer, Beef Drop (homebrew) + + -------------------------------------------------*/ + +READ8_MEMBER(a78_rom_pokey_device::read_40xx) +{ + if (offset < 0x4000) + return m_pokey->read(space, offset & 0x0f); + + if (offset + 0x4000 < m_base_rom) + return 0xff; + else + return m_rom[offset + 0x4000 - m_base_rom]; +} + +WRITE8_MEMBER(a78_rom_pokey_device::write_40xx) +{ + if (offset < 0x4000) + m_pokey->write(space, offset & 0x0f, data); +} + +machine_config_constructor a78_rom_pokey_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( a78_pokey ); +} + + +/*------------------------------------------------- + + Carts with SuperGame bankswitch: + 8 x 16K banks mappable in 0x8000-0xbfff + bank 7 is always mapped in 0xc000-0xffff + range 0x4000-0x7fff is not clear: some games + expect bank 6 to be mapped there, others + have open bus (we assume the former until + a game requires more precise behavior or + some test is run) + Note that the code is written so that also + homebrew games with larger ROMs work! + + GAMES: Crack'd, Fatal Run, Ikari Warriors... + + -------------------------------------------------*/ + +READ8_MEMBER(a78_rom_sg_device::read_40xx) +{ + if (offset < 0x4000) + return m_rom[(offset & 0x3fff) + ((m_bank_mask - 1) * 0x4000)]; // second to last bank (is this always ok?!?) + else if (offset < 0x8000) + return m_rom[(offset & 0x3fff) + (m_bank * 0x4000)]; + else + return m_rom[(offset & 0x3fff) + (m_bank_mask * 0x4000)]; // last bank +} + +WRITE8_MEMBER(a78_rom_sg_device::write_40xx) +{ + if (offset >= 0x4000 && offset < 0x8000) + m_bank = data & m_bank_mask; +} + + +/*------------------------------------------------- + + Carts with SuperGame bankswitch + POKEY chip + As above + Pokey chip access + + GAMES: Commando + + -------------------------------------------------*/ + +READ8_MEMBER(a78_rom_sg_pokey_device::read_40xx) +{ + if (offset < 0x4000) + return m_pokey->read(space, offset & 0x0f); + else if (offset < 0x8000) + return m_rom[(offset & 0x3fff) + (m_bank * 0x4000)]; + else + return m_rom[(offset & 0x3fff) + (m_bank_mask * 0x4000)]; // last bank +} + +WRITE8_MEMBER(a78_rom_sg_pokey_device::write_40xx) +{ + if (offset < 0x4000) + m_pokey->write(space, offset & 0x0f, data); + else if (offset < 0x8000) + m_bank = data & m_bank_mask; +} + +machine_config_constructor a78_rom_sg_pokey_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( a78_pokey ); +} + + +/*------------------------------------------------- + + Carts with SuperGame bankswitch + 16K RAM + FIXME: Some games contained only 8K of RAM, but + for the moment we treat all as 16K of RAM even if + from softlist we shall differentiate between them. + + GAMES: Impossible Mission, Jinks and some protos + + -------------------------------------------------*/ + +READ8_MEMBER(a78_rom_sg_ram_device::read_40xx) +{ + if (offset < 0x4000) + return m_ram[offset]; + else if (offset < 0x8000) + return m_rom[(offset & 0x3fff) + (m_bank * 0x4000)]; + else + return m_rom[(offset & 0x3fff) + (m_bank_mask * 0x4000)]; // last bank +} + +WRITE8_MEMBER(a78_rom_sg_ram_device::write_40xx) +{ + if (offset < 0x4000) + m_ram[offset] = data; + else if (offset < 0x8000) + m_bank = data & m_bank_mask; +} + + +/*------------------------------------------------- + + Carts with SuperGame bankswitch 9banks: + 9 x 16K banks mappable in 0x8000-0xbfff + bank 7 is always mapped in 0xc000-0xffff + + GAMES: Alien Brigade & Crossbow + some homebrew + like Donkey Kong XM demo, Bentley Bear's Crystal + Quest + + -------------------------------------------------*/ + +READ8_MEMBER(a78_rom_sg9_device::read_40xx) +{ + if (offset < 0x4000) + return m_rom[(offset & 0x3fff)]; + else if (offset < 0x8000) + return m_rom[(offset & 0x3fff) + (m_bank * 0x4000)]; + else + return m_rom[(offset & 0x3fff) + ((m_bank_mask + 1) * 0x4000)]; // last bank +} + +WRITE8_MEMBER(a78_rom_sg9_device::write_40xx) +{ + if (offset >= 0x4000 && offset < 0x8000) + m_bank = (data & m_bank_mask) + 1; +} + +/*------------------------------------------------- + + Carts with Absolute bankswitch: + 64K games. Lower 32K are 2 banks of 16K to be mapped + in 0x4000-0x7fff, depending on the value written + at 0x8000. Higher 32K are fixed in 0x8000-0xffff + + GAMES: F-18 Hornet + + -------------------------------------------------*/ + +READ8_MEMBER(a78_rom_abs_device::read_40xx) +{ + if (offset < 0x4000) + return m_rom[(offset & 0x3fff) + (m_bank * 0x4000)]; + else + { + offset -= 0x4000; + return m_rom[offset + 0x8000]; + } +} + +WRITE8_MEMBER(a78_rom_abs_device::write_40xx) +{ + if (offset == 0x4000) + { + if (data & 1) + m_bank = 0; + else if (data & 2) + m_bank = 1; + } +} + +/*------------------------------------------------- + + Carts with Activision bankswitch: + 128K games. 8 x 16K banks (0-7) to be mapped at + 0xa000-0xdfff. Bank is selected depending on the + address written in 0xff80-0xff87. + The rest of the memory is as follows: + 0x4000-0x5fff second 8kb of bank 6 + 0x6000-0x7fff first 8kb of bank 6 + 0x8000-0x9fff second 8kb of bank 7 + 0xe000-0xffff first 8kb of bank 7 + + GAMES: Double Dragon, Rampage. + + -------------------------------------------------*/ + +READ8_MEMBER(a78_rom_act_device::read_40xx) +{ + UINT8 data = 0xff; + UINT16 addr = offset & 0x1fff; + + // offset goes from 0 to 0xc000 + switch (offset & 0xe000) + { + case 0x0000: + data = m_rom[addr + 0x1a000]; + break; + case 0x2000: + data = m_rom[addr + 0x18000]; + break; + case 0x4000: + data = m_rom[addr + 0x1e000]; + break; + case 0x6000: + data = m_rom[addr + (m_bank * 0x4000)]; + break; + case 0x8000: + data = m_rom[addr + (m_bank * 0x4000) + 0x2000]; + break; + case 0xa000: + data = m_rom[addr + 0x1c000]; + break; + } + + return data; +} + +WRITE8_MEMBER(a78_rom_act_device::write_40xx) +{ + if (offset >= 0xbf80 && offset <= 0xbf87) + m_bank = offset & 7; +} + + +// Machine configs for PCB variants with a POKEY at $0450 + +machine_config_constructor a78_rom_p450_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( a78_pokey450 ); +} + +machine_config_constructor a78_rom_p450_pokey_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( a78_2pokeys ); +} + +machine_config_constructor a78_rom_p450_sg_ram_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( a78_pokey450 ); +} + +machine_config_constructor a78_rom_p450_sg9_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( a78_pokey450 ); +} diff --git a/src/devices/bus/a7800/rom.h b/src/devices/bus/a7800/rom.h new file mode 100644 index 00000000000..0de17b2a952 --- /dev/null +++ b/src/devices/bus/a7800/rom.h @@ -0,0 +1,261 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __A78_ROM_H +#define __A78_ROM_H + +#include "a78_slot.h" +#include "sound/pokey.h" + + +// ======================> a78_rom_device + +class a78_rom_device : public device_t, + public device_a78_cart_interface +{ +public: + // construction/destruction + a78_rom_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + a78_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_40xx); +}; + + +// ======================> a78_rom_pokey_device + +class a78_rom_pokey_device : public a78_rom_device +{ +public: + // construction/destruction + a78_rom_pokey_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + a78_rom_pokey_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual machine_config_constructor device_mconfig_additions() const; + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_40xx); + virtual DECLARE_WRITE8_MEMBER(write_40xx); + +protected: + required_device m_pokey; +}; + + +// ======================> a78_rom_sg_device + +class a78_rom_sg_device : public a78_rom_device +{ +public: + // construction/destruction + a78_rom_sg_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + a78_rom_sg_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_40xx); + virtual DECLARE_WRITE8_MEMBER(write_40xx); + +protected: + int m_bank; +}; + + +// ======================> a78_rom_sg_pokey_device + +class a78_rom_sg_pokey_device : public a78_rom_sg_device +{ +public: + // construction/destruction + a78_rom_sg_pokey_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual machine_config_constructor device_mconfig_additions() const; + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_40xx); + virtual DECLARE_WRITE8_MEMBER(write_40xx); + +protected: + required_device m_pokey; +}; + + +// ======================> a78_rom_sg_ram_device + +class a78_rom_sg_ram_device : public a78_rom_sg_device +{ +public: + // construction/destruction + a78_rom_sg_ram_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + a78_rom_sg_ram_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_40xx); + virtual DECLARE_WRITE8_MEMBER(write_40xx); +}; + + +// ======================> a78_rom_sg9_device + +class a78_rom_sg9_device : public a78_rom_sg_device +{ +public: + // construction/destruction + a78_rom_sg9_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + a78_rom_sg9_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_40xx); + virtual DECLARE_WRITE8_MEMBER(write_40xx); +}; + + +// ======================> a78_rom_abs_device + +class a78_rom_abs_device : public a78_rom_device +{ +public: + // construction/destruction + a78_rom_abs_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_40xx); + virtual DECLARE_WRITE8_MEMBER(write_40xx); + +protected: + int m_bank; +}; + + +// ======================> a78_rom_act_device + +class a78_rom_act_device : public a78_rom_device +{ +public: + // construction/destruction + a78_rom_act_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_40xx); + virtual DECLARE_WRITE8_MEMBER(write_40xx); + +protected: + int m_bank; +}; + + +// PCB variants with a POKEY at $0450 + +// ======================> a78_rom_p450_device + +class a78_rom_p450_device : public a78_rom_device +{ +public: + // construction/destruction + a78_rom_p450_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual machine_config_constructor device_mconfig_additions() const; + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_04xx) { if (offset >= 0x50 && offset < 0x60) return m_pokey450->read(space, offset & 0x0f); else return 0xff; } + virtual DECLARE_WRITE8_MEMBER(write_04xx) { if (offset >= 0x50 && offset < 0x60) m_pokey450->write(space, offset & 0x0f, data); } + +protected: + required_device m_pokey450; +}; + + +// ======================> a78_rom_p450_pokey_device + +class a78_rom_p450_pokey_device : public a78_rom_pokey_device +{ +public: + // construction/destruction + a78_rom_p450_pokey_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual machine_config_constructor device_mconfig_additions() const; + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_04xx) { if (offset >= 0x50 && offset < 0x60) return m_pokey450->read(space, offset & 0x0f); else return 0xff; } + virtual DECLARE_WRITE8_MEMBER(write_04xx) { if (offset >= 0x50 && offset < 0x60) m_pokey450->write(space, offset & 0x0f, data); } + +protected: + required_device m_pokey450; +}; + + +// ======================> a78_rom_p450_sg_ram_device + +class a78_rom_p450_sg_ram_device : public a78_rom_sg_ram_device +{ +public: + // construction/destruction + a78_rom_p450_sg_ram_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual machine_config_constructor device_mconfig_additions() const; + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_04xx) { if (offset >= 0x50 && offset < 0x60) return m_pokey450->read(space, offset & 0x0f); else return 0xff; } + virtual DECLARE_WRITE8_MEMBER(write_04xx) { if (offset >= 0x50 && offset < 0x60) m_pokey450->write(space, offset & 0x0f, data); } + +protected: + required_device m_pokey450; +}; + + +// ======================> a78_rom_p450_sg9_device + +class a78_rom_p450_sg9_device : public a78_rom_sg9_device +{ +public: + // construction/destruction + a78_rom_p450_sg9_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual machine_config_constructor device_mconfig_additions() const; + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_04xx) { if (offset >= 0x50 && offset < 0x60) return m_pokey450->read(space, offset & 0x0f); else return 0xff; } + virtual DECLARE_WRITE8_MEMBER(write_04xx) { if (offset >= 0x50 && offset < 0x60) m_pokey450->write(space, offset & 0x0f, data); } + +protected: + required_device m_pokey450; +}; + + + + + +// device type definition +extern const device_type A78_ROM; +extern const device_type A78_ROM_SG; +extern const device_type A78_ROM_POKEY; +extern const device_type A78_ROM_SG_POKEY; +extern const device_type A78_ROM_SG_RAM; +extern const device_type A78_ROM_SG9; +extern const device_type A78_ROM_ABSOLUTE; +extern const device_type A78_ROM_ACTIVISION; + +// PCB variants with a POKEY at $0450 +extern const device_type A78_ROM_P450; +extern const device_type A78_ROM_P450_POKEY; +extern const device_type A78_ROM_P450_SG_RAM; +extern const device_type A78_ROM_P450_SG9; + +#endif diff --git a/src/devices/bus/a7800/xboard.c b/src/devices/bus/a7800/xboard.c new file mode 100644 index 00000000000..3c5eb3d0f24 --- /dev/null +++ b/src/devices/bus/a7800/xboard.c @@ -0,0 +1,239 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + A7800 XBoarD & XM expansions emulation + + The XBoarD should be socketed in the A7800 pcb in place of the Maria chip. + It adds to the system additional 128K of RAM and an onboard pokey. + The XM seems to work the same as XBoarD, but it also features HighScore savings + (using the same ROM as Atari HighScore cart) + + + Currently, we emulate both of these as a passthru cart, even if not 100% accurate for the XBoarD + + + Memory map: + + POKEY1 $0450 $045F 16 bytes + POKEY2* $0460 $046F 16 bytes + XCTRL $0470 $047F 1 byte + RAM $4000 $7FFF 16384 bytes + + XCTRL Bit Description + + +-------------------------------+ + | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | + +-------------------------------+ + | | | | | | | | + | | | | | | | +-- Bank select bit 0 \ + | | | | | | +------ Bank select bit 1 | Totally 128 KByte in 16 KByte banks + | | | | | +---------- Bank select bit 2 / + | | | | +-------------- Enable memory bit (1 = Memory enabled, 0 after power on) + | | | +------------------ Enable POKEY bit** (1 = POKEY enabled, 0 after power on) + | | | + NA NA NA = Not Available or Not Used + + * = Can be mounted piggy back on the first POKEY. Description how to do this will come when i have tried it out. + ** This bit controls both POKEY chip select signals. + + TODO: + - verify what happens when 2 POKEYs are present + +***********************************************************************************************************/ + + +#include "emu.h" +#include "xboard.h" +#include "a78_carts.h" + + +//------------------------------------------------- +// constructor +//------------------------------------------------- + +const device_type A78_XBOARD = &device_creator; +const device_type A78_XM = &device_creator; + + +a78_xboard_device::a78_xboard_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : a78_rom_device(mconfig, type, name, tag, owner, clock, shortname, source), + m_xbslot(*this, "xb_slot"), + m_pokey(*this, "xb_pokey") +{ +} + + +a78_xboard_device::a78_xboard_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : a78_rom_device(mconfig, A78_XBOARD, "Atari 7800 XBoarD expansion", tag, owner, clock, "a78_xboard", __FILE__), + m_xbslot(*this, "xb_slot"), + m_pokey(*this, "xb_pokey") +{ +} + + +a78_xm_device::a78_xm_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : a78_xboard_device(mconfig, A78_XM, "Atari 7800 XM expansion module", tag, owner, clock, "a78_xm", __FILE__), + m_ym(*this, "xm_ym2151") +{ +} + + +void a78_xboard_device::device_start() +{ + save_item(NAME(m_reg)); + save_item(NAME(m_ram_bank)); +} + +void a78_xboard_device::device_reset() +{ + m_reg = 0; + m_ram_bank = 0; +} + +void a78_xm_device::device_start() +{ + save_item(NAME(m_reg)); + save_item(NAME(m_ram_bank)); + save_item(NAME(m_ym_enabled)); +} + +void a78_xm_device::device_reset() +{ + m_reg = 0; + m_ram_bank = 0; + m_ym_enabled = 0; +} + + +static MACHINE_CONFIG_FRAGMENT( a78_xb ) + MCFG_A78_CARTRIDGE_ADD("xb_slot", a7800_cart, NULL) + + MCFG_SPEAKER_STANDARD_MONO("xb_speaker") + + MCFG_SOUND_ADD("xb_pokey", POKEY, XTAL_14_31818MHz/8) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "xb_speaker", 1.00) +MACHINE_CONFIG_END + +static MACHINE_CONFIG_FRAGMENT( a78_xm ) + MCFG_A78_CARTRIDGE_ADD("xb_slot", a7800_cart, NULL) + + MCFG_SPEAKER_STANDARD_MONO("xb_speaker") + + MCFG_SOUND_ADD("xb_pokey", POKEY, XTAL_14_31818MHz/8) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "xb_speaker", 1.00) + + MCFG_SOUND_ADD("xm_ym2151", YM2151, XTAL_14_31818MHz/4) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "xb_speaker", 1.00) +MACHINE_CONFIG_END + +machine_config_constructor a78_xboard_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( a78_xb ); +} + +machine_config_constructor a78_xm_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( a78_xm ); +} + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +/*------------------------------------------------- + + XBoarD: passthru + 128K RAM + POKEY + + -------------------------------------------------*/ + +READ8_MEMBER(a78_xboard_device::read_40xx) +{ + if (BIT(m_reg, 3) && offset < 0x4000) + return m_ram[offset + (m_ram_bank * 0x4000)]; + else + return m_xbslot->read_40xx(space, offset); +} + +WRITE8_MEMBER(a78_xboard_device::write_40xx) +{ + if (BIT(m_reg, 3) && offset < 0x4000) + m_ram[offset + (m_ram_bank * 0x4000)] = data; + else + m_xbslot->write_40xx(space, offset, data); +} + +READ8_MEMBER(a78_xboard_device::read_04xx) +{ + if (BIT(m_reg, 4) && offset >= 0x50 && offset < 0x60) + return m_pokey->read(space, offset & 0x0f); + else if (BIT(m_reg, 4) && offset >= 0x60 && offset < 0x70) + return m_xbslot->read_04xx(space, offset - 0x10); // access second POKEY + else + return 0xff; +} + +WRITE8_MEMBER(a78_xboard_device::write_04xx) +{ + if (BIT(m_reg, 4) && offset >= 0x50 && offset < 0x60) + m_pokey->write(space, offset & 0x0f, data); + else if (BIT(m_reg, 4) && offset >= 0x60 && offset < 0x70) + m_xbslot->write_04xx(space, offset - 0x10, data); // access second POKEY + else if (offset >= 0x70 && offset < 0x80) + { + m_reg = data; + m_ram_bank = m_reg & 7; + } +} + + +/*------------------------------------------------- + + XM: Same as above but also featuring High Score savings + + -------------------------------------------------*/ + +READ8_MEMBER(a78_xm_device::read_10xx) +{ + return m_nvram[offset]; +} + +WRITE8_MEMBER(a78_xm_device::write_10xx) +{ + m_nvram[offset] = data; +} + +READ8_MEMBER(a78_xm_device::read_30xx) +{ + return m_rom[offset]; +} + +READ8_MEMBER(a78_xm_device::read_04xx) +{ + if (BIT(m_reg, 4) && offset >= 0x50 && offset < 0x60) + return m_pokey->read(space, offset & 0x0f); + else if (m_ym_enabled && offset >= 0x60 && offset <= 0x61) + return m_ym->read(space, offset & 1); + else if (BIT(m_reg, 4) && offset >= 0x60 && offset < 0x70) + return m_xbslot->read_04xx(space, offset - 0x10); // access second POKEY + else + return 0xff; +} + +WRITE8_MEMBER(a78_xm_device::write_04xx) +{ + if (BIT(m_reg, 4) && offset >= 0x50 && offset < 0x60) + m_pokey->write(space, offset & 0x0f, data); + else if (m_ym_enabled && offset >= 0x60 && offset <= 0x61) + m_ym->write(space, offset & 1, data); + else if (BIT(m_reg, 4) && offset >= 0x60 && offset < 0x70) + m_xbslot->write_04xx(space, offset - 0x10, data); // access second POKEY + else if (offset >= 0x70 && offset < 0x80) + { + //printf("regs 0x%X\n", data); + if (data == 0x84) + m_ym_enabled = 1; + m_reg = data; + m_ram_bank = m_reg & 7; + } +} diff --git a/src/devices/bus/a7800/xboard.h b/src/devices/bus/a7800/xboard.h new file mode 100644 index 00000000000..44173e70390 --- /dev/null +++ b/src/devices/bus/a7800/xboard.h @@ -0,0 +1,71 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __A78_XBOARD_H +#define __A78_XBOARD_H + +#include "a78_slot.h" +#include "rom.h" +#include "sound/pokey.h" +#include "sound/2151intf.h" + + +// ======================> a78_xboard_device + +class a78_xboard_device : public a78_rom_device +{ +public: + // construction/destruction + a78_xboard_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + a78_xboard_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual machine_config_constructor device_mconfig_additions() const; + virtual void device_reset(); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_04xx); + virtual DECLARE_WRITE8_MEMBER(write_04xx); + virtual DECLARE_READ8_MEMBER(read_40xx); + virtual DECLARE_WRITE8_MEMBER(write_40xx); + +protected: + required_device m_xbslot; + required_device m_pokey; + int m_reg, m_ram_bank; +}; + + +// ======================> a78_xm_device + +class a78_xm_device : public a78_xboard_device +{ +public: + // construction/destruction + a78_xm_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual machine_config_constructor device_mconfig_additions() const; + virtual void device_reset(); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_04xx); + virtual DECLARE_WRITE8_MEMBER(write_04xx); + virtual DECLARE_READ8_MEMBER(read_10xx); + virtual DECLARE_WRITE8_MEMBER(write_10xx); + virtual DECLARE_READ8_MEMBER(read_30xx); + +protected: + required_device m_ym; + int m_ym_enabled; +}; + + + +// device type definition +extern const device_type A78_XBOARD; +extern const device_type A78_XM; + + +#endif diff --git a/src/devices/bus/a800/a800_carts.h b/src/devices/bus/a800/a800_carts.h new file mode 100644 index 00000000000..720b5e7f4f8 --- /dev/null +++ b/src/devices/bus/a800/a800_carts.h @@ -0,0 +1,50 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __A800_CARTS_H +#define __A800_CARTS_H + + +#include "emu.h" + +#include "rom.h" +#include "oss.h" +#include "sparta.h" + +static SLOT_INTERFACE_START(a800_left) + SLOT_INTERFACE_INTERNAL("a800_8k", A800_ROM) + SLOT_INTERFACE_INTERNAL("a800_8k_right", A800_ROM) + SLOT_INTERFACE_INTERNAL("a800_16k", A800_ROM) + SLOT_INTERFACE_INTERNAL("a800_phoenix", A800_ROM) // not really emulated at this stage + SLOT_INTERFACE_INTERNAL("a800_bbsb", A800_ROM_BBSB) + SLOT_INTERFACE_INTERNAL("a800_oss8k", A800_ROM_OSS8K) + SLOT_INTERFACE_INTERNAL("a800_oss034m", A800_ROM_OSS34) + SLOT_INTERFACE_INTERNAL("a800_oss043m", A800_ROM_OSS43) + SLOT_INTERFACE_INTERNAL("a800_ossm091", A800_ROM_OSS91) + SLOT_INTERFACE_INTERNAL("a800_williams", A800_ROM_WILLIAMS) + SLOT_INTERFACE_INTERNAL("a800_diamond", A800_ROM_EXPRESS) + SLOT_INTERFACE_INTERNAL("a800_express", A800_ROM_EXPRESS) + SLOT_INTERFACE_INTERNAL("a800_sparta", A800_ROM_SPARTADOS) // this is a passthru cart with unemulated (atm) subslot + SLOT_INTERFACE_INTERNAL("a800_blizzard", A800_ROM) + SLOT_INTERFACE_INTERNAL("a800_turbo64", A800_ROM_TURBO) + SLOT_INTERFACE_INTERNAL("a800_turbo128", A800_ROM_TURBO) + SLOT_INTERFACE_INTERNAL("a800_tlink2", A800_ROM_TELELINK2) + SLOT_INTERFACE_INTERNAL("a800_sitsa", A800_ROM_MICROCALC) + SLOT_INTERFACE_INTERNAL("a800_corina", A800_ROM) // NOT SUPPORTED YET! + SLOT_INTERFACE_INTERNAL("xegs", XEGS_ROM) +SLOT_INTERFACE_END + +static SLOT_INTERFACE_START(a800_right) + SLOT_INTERFACE_INTERNAL("a800_8k_right", A800_ROM) +SLOT_INTERFACE_END + +static SLOT_INTERFACE_START(xegs_carts) + SLOT_INTERFACE_INTERNAL("xegs", XEGS_ROM) +SLOT_INTERFACE_END + +static SLOT_INTERFACE_START(a5200_carts) + SLOT_INTERFACE_INTERNAL("a5200", A800_ROM) + SLOT_INTERFACE_INTERNAL("a5200_2chips", A5200_ROM_2CHIPS) + SLOT_INTERFACE_INTERNAL("a5200_bbsb", A5200_ROM_BBSB) +SLOT_INTERFACE_END + +#endif diff --git a/src/devices/bus/a800/a800_slot.c b/src/devices/bus/a800/a800_slot.c new file mode 100644 index 00000000000..c378d869811 --- /dev/null +++ b/src/devices/bus/a800/a800_slot.c @@ -0,0 +1,549 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + Atari 8 bit cart emulation + (through slot devices) + + Emulation of the cartslot(s) for Atari 8bit series of home computers + + Accessors to ROM are typically given in the area 0xa000-0xbfff, but some + carts (and the right slot in A800) maps ROM to 0x8000-0x9fff too + Bankswitch typically happens by accessing addresses in 0xd500-0xd5ff + + Accordingly, this device offers the following handlers + - read_80xx/write_80xx + - read_d5xx/write_d5xx + Notice that these are installed in different ranges at machine start by + the drivers, so that it might well be that offs=0 for read_80xx is 0xa000! + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "hashfile.h" +#include "a800_slot.h" + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type A800_CART_SLOT = &device_creator; +const device_type A5200_CART_SLOT = &device_creator; +const device_type XEGS_CART_SLOT = &device_creator; + + +//------------------------------------------------- +// device_vcs_cart_interface - constructor +//------------------------------------------------- + +device_a800_cart_interface::device_a800_cart_interface (const machine_config &mconfig, device_t &device) + : device_slot_card_interface(mconfig, device), + m_rom(NULL), + m_rom_size(0), + m_bank_mask(0) +{ +} + + +//------------------------------------------------- +// ~device_a800_cart_interface - destructor +//------------------------------------------------- + +device_a800_cart_interface::~device_a800_cart_interface () +{ +} + +//------------------------------------------------- +// rom_alloc - alloc the space for the cart +//------------------------------------------------- + +void device_a800_cart_interface::rom_alloc(UINT32 size, const char *tag) +{ + if (m_rom == NULL) + { + m_rom = device().machine().memory().region_alloc(std::string(tag).append(A800SLOT_ROM_REGION_TAG).c_str(), size, 1, ENDIANNESS_LITTLE)->base(); + m_rom_size = size; + + // setup other helpers + m_bank_mask = (size / 0x2000) - 1; // code for XEGS carts makes use of this to simplify banking + } +} + +//------------------------------------------------- +// ram_alloc - alloc the space for the on-cart RAM +//------------------------------------------------- + +void device_a800_cart_interface::ram_alloc(UINT32 size) +{ + m_ram.resize(size); + device().save_item(NAME(m_ram)); +} + + +//------------------------------------------------- +// ram_alloc - alloc the space for the on-cart RAM +//------------------------------------------------- + +void device_a800_cart_interface::nvram_alloc(UINT32 size) +{ + m_nvram.resize(size); + device().save_item(NAME(m_nvram)); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// ****_cart_slot_device - constructor +//------------------------------------------------- +a800_cart_slot_device::a800_cart_slot_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, __FILE__), + device_image_interface(mconfig, *this), + device_slot_interface(mconfig, *this) +{ +} + +a800_cart_slot_device::a800_cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, A800_CART_SLOT, "Atari 8bit Cartridge Slot", tag, owner, clock, "a800_cart_slot", __FILE__), + device_image_interface(mconfig, *this), + device_slot_interface(mconfig, *this) +{ +} + + +a5200_cart_slot_device::a5200_cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + a800_cart_slot_device(mconfig, A5200_CART_SLOT, "Atari 5200 Cartridge Slot", tag, owner, clock, "a5200_cart_slot", __FILE__) +{ +} + + +xegs_cart_slot_device::xegs_cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + a800_cart_slot_device(mconfig, XEGS_CART_SLOT, "Atari XEGS Cartridge Slot", tag, owner, clock, "xegs_cart_slot", __FILE__) +{ +} + + +//------------------------------------------------- +// ****_cart_slot_device - destructor +//------------------------------------------------- + +a800_cart_slot_device::~a800_cart_slot_device() +{ +} + +a5200_cart_slot_device::~a5200_cart_slot_device() +{ +} + +xegs_cart_slot_device::~xegs_cart_slot_device() +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void a800_cart_slot_device::device_start() +{ + m_cart = dynamic_cast(get_card_device()); +} + +//------------------------------------------------- +// device_config_complete - perform any +// operations now that the configuration is +// complete +//------------------------------------------------- + +void a800_cart_slot_device::device_config_complete() +{ + // set brief and instance name + update_names(); +} + + + +/*------------------------------------------------- + call load + -------------------------------------------------*/ + +//------------------------------------------------- +// A800 PCBs +//------------------------------------------------- + +struct a800_slot +{ + int pcb_id; + const char *slot_option; +}; + +// Here, we take the feature attribute from .xml (i.e. the PCB name) and we assign a unique ID to it +static const a800_slot slot_list[] = +{ + { A800_8K, "a800_8k" }, + { A800_16K, "a800_16k" }, + { A800_OSS034M, "a800_oss034m" }, + { A800_OSS043M, "a800_oss043m" }, + { A800_OSSM091, "a800_ossm091" }, + { A800_OSS8K, "a800_oss8k" }, + { A800_PHOENIX, "a800_phoenix" }, + { A800_XEGS, "xegs" }, + { A800_BBSB, "a800_bbsb" }, + { A800_DIAMOND, "a800_diamond" }, + { A800_WILLIAMS, "a800_williams" }, + { A800_EXPRESS, "a800_express" }, + { A800_SPARTADOS, "a800_sparta" }, + { A800_TURBO64, "a800_turbo64" }, + { A800_TURBO128, "a800_turbo128" }, + { A800_BLIZZARD, "a800_blizzard" }, + { A800_TELELINK2, "a800_tlink2" }, + { A800_MICROCALC, "a800_sitsa" }, + { A800_CORINA, "a800_corina" }, + { A800_8K_RIGHT, "a800_8k_right" }, + { A5200_4K, "a5200" }, + { A5200_8K, "a5200" }, + { A5200_16K, "a5200" }, + { A5200_32K, "a5200" }, + { A5200_16K_2CHIPS, "a5200_2chips" }, + { A5200_32K, "a5200" }, + { A5200_BBSB, "a5200_bbsb" } +}; + + +static int a800_get_pcb_id(const char *slot) +{ + for (int i = 0; i < ARRAY_LENGTH(slot_list); i++) + { + if (!core_stricmp(slot_list[i].slot_option, slot)) + return slot_list[i].pcb_id; + } + + return 0; +} + +static const char *a800_get_slot(int type) +{ + for (int i = 0; i < ARRAY_LENGTH(slot_list); i++) + { + if (slot_list[i].pcb_id == type) + return slot_list[i].slot_option; + } + + return "a800_8k"; +} + +bool a800_cart_slot_device::call_load() +{ + if (m_cart) + { + UINT32 len; + + if (software_entry() != NULL) + { + const char *pcb_name; + len = get_software_region_length("rom"); + + m_cart->rom_alloc(len, tag()); + memcpy(m_cart->get_rom_base(), get_software_region("rom"), len); + + if ((pcb_name = get_feature("slot")) != NULL) + m_type = a800_get_pcb_id(pcb_name); + else + m_type = A800_8K; + } + else + { + len = length(); + + // check whether there is an header, to identify the cart type + if ((len % 0x1000) == 0x10) + { + UINT8 header[16]; + fread(header, 0x10); + m_type = identify_cart_type(header); + len -= 0x10; // in identify_cart_type the first 0x10 bytes are read, so we need to adjust here + } + else // otherwise try to guess based on size + { + if (len == 0x8000) + m_type = A5200_32K; + if (len == 0x4000) + m_type = A800_16K; + if (len == 0x2000) + m_type = A800_8K; + if (len == 0x1000) + m_type = A5200_4K; + } + + m_cart->rom_alloc(len, tag()); + fread(m_cart->get_rom_base(), len); + } + if (m_type == A800_TELELINK2) + m_cart->nvram_alloc(0x100); + + printf("%s loaded cartridge '%s' size %dK\n", machine().system().name, filename(), len/1024); + } + return IMAGE_INIT_PASS; +} + + +/*------------------------------------------------- + call_unload + -------------------------------------------------*/ + +void a800_cart_slot_device::call_unload() +{ +} + +/*------------------------------------------------- + call softlist load + -------------------------------------------------*/ + +bool a800_cart_slot_device::call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry) +{ + load_software_part_region(*this, swlist, swname, start_entry); + return TRUE; +} + +/*------------------------------------------------- + identify_cart_type - code to detect cart type from + fullpath + -------------------------------------------------*/ + +int a800_cart_slot_device::identify_cart_type(UINT8 *header) +{ + int type = A800_8K; + + // check CART format + if (strncmp((const char *)header, "CART", 4)) + fatalerror("Invalid header detected!\n"); + + switch ((header[4] << 24) + (header[5] << 16) + (header[6] << 8) + (header[7] << 0)) + { + case 1: + type = A800_8K; + break; + case 2: + type = A800_16K; + break; + case 3: + type = A800_OSS034M; + break; + case 8: + type = A800_WILLIAMS; + break; + case 9: + type = A800_DIAMOND; + break; + case 10: + type = A800_EXPRESS; + break; + case 11: + type = A800_SPARTADOS; + break; + case 12: + type = A800_XEGS; + break; + case 15: + type = A800_OSSM091; + break; + case 18: + type = A800_BBSB; + break; + case 21: + type = A800_8K_RIGHT; + break; + case 39: + type = A800_PHOENIX; + break; + case 40: + type = A800_BLIZZARD; + break; + case 44: + type = A800_OSS8K; + break; + case 50: + type = A800_TURBO64; + break; + case 51: + type = A800_TURBO128; + break; + case 52: + type = A800_MICROCALC; + break; + // Atari 5200 CART files + case 4: + type = A5200_32K; + break; + case 16: + type = A5200_16K; + break; + case 19: + type = A5200_8K; + break; + case 20: + type = A5200_4K; + break; + case 6: + type = A5200_16K_2CHIPS; + break; + case 7: + type = A5200_BBSB; + break; + default: + osd_printf_info("Cart type \"%d\" is currently unsupported.\n", (header[4] << 24) + (header[5] << 16) + (header[6] << 8) + (header[7] << 0)); + break; + } + + return type; +} + +/*------------------------------------------------- + get default card software + -------------------------------------------------*/ + +void a800_cart_slot_device::get_default_card_software(std::string &result) +{ + if (open_image_file(mconfig().options())) + { + const char *slot_string = "a800_8k"; + dynamic_buffer head(0x10); + UINT32 len = core_fsize(m_file); + int type = A800_8K; + + // check whether there is an header, to identify the cart type + if ((len % 0x1000) == 0x10) + { + core_fread(m_file, &head[0], 0x10); + type = identify_cart_type(&head[0]); + } + else // otherwise try to guess based on size + { + if (len == 0x4000) + type = A800_16K; + if (len == 0x2000) + type = A800_8K; + } + + if (type >= A5200_4K) + osd_printf_info("This game is not designed for A800. You might want to run it in A5200.\n"); + + slot_string = a800_get_slot(type); + + clear(); + + result.assign(slot_string); + } + else + software_get_default_slot(result, "a800_8k"); +} + + +void a5200_cart_slot_device::get_default_card_software(std::string &result) +{ + if (open_image_file(mconfig().options())) + { + const char *slot_string = "a5200"; + dynamic_buffer head(0x10); + UINT32 len = core_fsize(m_file); + int type = A5200_8K; + + // check whether there is an header, to identify the cart type + if ((len % 0x1000) == 0x10) + { + core_fread(m_file, &head[0], 0x10); + type = identify_cart_type(&head[0]); + + std::string info; + if (hashfile_extrainfo(*this, info) && info.compare("A13MIRRORING")==0) + type = A5200_16K_2CHIPS; + } + if (type < A5200_4K) + osd_printf_info("This game is not designed for A5200. You might want to run it in A800 or A800XL.\n"); + + slot_string = a800_get_slot(type); + + clear(); + + result.assign(slot_string); + } + else + software_get_default_slot(result, "a5200"); +} + + +void xegs_cart_slot_device::get_default_card_software(std::string &result) +{ + if (open_image_file(mconfig().options())) + { + const char *slot_string = "xegs"; + dynamic_buffer head(0x10); + UINT32 len = core_fsize(m_file); + int type = A800_8K; + + // check whether there is an header, to identify the cart type + if ((len % 0x1000) == 0x10) + { + core_fread(m_file, &head[0], 0x10); + type = identify_cart_type(&head[0]); + } + if (type != A800_XEGS) + { + osd_printf_info("This game is not designed for XEGS. "); + if (type >= A5200_4K) + osd_printf_info("You might want to run it in A5200.\n"); + else + osd_printf_info("You might want to run it in A800 or A800XL.\n"); + } + + slot_string = a800_get_slot(type); + + clear(); + + result.assign(slot_string); + } + else + software_get_default_slot(result, "xegs"); +} + + +/*------------------------------------------------- + read + -------------------------------------------------*/ + +READ8_MEMBER(a800_cart_slot_device::read_80xx) +{ + if (m_cart) + return m_cart->read_80xx(space, offset, mem_mask); + else + return 0xff; +} + +READ8_MEMBER(a800_cart_slot_device::read_d5xx) +{ + if (m_cart) + return m_cart->read_d5xx(space, offset, mem_mask); + else + return 0xff; +} + + +/*------------------------------------------------- + write + -------------------------------------------------*/ + +WRITE8_MEMBER(a800_cart_slot_device::write_80xx) +{ + if (m_cart) + m_cart->write_80xx(space, offset, data, mem_mask); +} + +WRITE8_MEMBER(a800_cart_slot_device::write_d5xx) +{ + if (m_cart) + m_cart->write_d5xx(space, offset, data, mem_mask); +} diff --git a/src/devices/bus/a800/a800_slot.h b/src/devices/bus/a800/a800_slot.h new file mode 100644 index 00000000000..8359b9c7178 --- /dev/null +++ b/src/devices/bus/a800/a800_slot.h @@ -0,0 +1,188 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __A800_SLOT_H +#define __A800_SLOT_H + + +/*************************************************************************** + TYPE DEFINITIONS + ***************************************************************************/ + + +/* PCB */ +enum +{ + A800_8K = 0, + A800_8K_RIGHT, + A800_16K, + A800_OSS034M, + A800_OSS043M, + A800_OSSM091, + A800_OSS8K, + A800_PHOENIX, + A800_XEGS, + A800_BBSB, + A800_DIAMOND, + A800_WILLIAMS, + A800_EXPRESS, + A800_SPARTADOS, + A800_BLIZZARD, + A800_TURBO64, + A800_TURBO128, + A800_TELELINK2, + A800_MICROCALC, + A800_CORINA, + A5200_4K, + A5200_8K, + A5200_16K, + A5200_32K, + A5200_16K_2CHIPS, + A5200_BBSB +}; + + +// ======================> device_a800_cart_interface + +class device_a800_cart_interface : public device_slot_card_interface +{ +public: + // construction/destruction + device_a800_cart_interface(const machine_config &mconfig, device_t &device); + virtual ~device_a800_cart_interface(); + + // memory accessor + virtual DECLARE_READ8_MEMBER(read_80xx) { return 0xff; } + virtual DECLARE_READ8_MEMBER(read_d5xx) { return 0xff; } + virtual DECLARE_WRITE8_MEMBER(write_80xx) {} + virtual DECLARE_WRITE8_MEMBER(write_d5xx) {} + + void rom_alloc(UINT32 size, const char *tag); + void ram_alloc(UINT32 size); + void nvram_alloc(UINT32 size); + UINT8* get_rom_base() { return m_rom; } + UINT8* get_ram_base() { return &m_ram[0]; } + UINT8* get_nvram_base() { return &m_nvram[0]; } + UINT32 get_rom_size() { return m_rom_size; } + UINT32 get_ram_size() { return m_ram.size(); } + UINT32 get_nvram_size() { return m_nvram.size(); } + +protected: + // internal state + UINT8 *m_rom; + UINT32 m_rom_size; + dynamic_buffer m_ram; + dynamic_buffer m_nvram; // HiScore cart can save scores! + // helpers + int m_bank_mask; +}; + + +// ======================> a800_cart_slot_device + +class a800_cart_slot_device : public device_t, + public device_image_interface, + public device_slot_interface +{ +public: + // construction/destruction + a800_cart_slot_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + a800_cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual ~a800_cart_slot_device(); + + // device-level overrides + virtual void device_start(); + virtual void device_config_complete(); + + // image-level overrides + virtual bool call_load(); + virtual void call_unload(); + virtual bool call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry); + + int get_cart_type() { return m_type; }; + int identify_cart_type(UINT8 *header); + bool has_cart() { return m_cart != NULL; } + + virtual iodevice_t image_type() const { return IO_CARTSLOT; } + virtual bool is_readable() const { return 1; } + virtual bool is_writeable() const { return 0; } + virtual bool is_creatable() const { return 0; } + virtual bool must_be_loaded() const { return 0; } + virtual bool is_reset_on_load() const { return 1; } + virtual const option_guide *create_option_guide() const { return NULL; } + virtual const char *image_interface() const { return "a8bit_cart"; } + virtual const char *file_extensions() const { return "bin,rom,car"; } + + // slot interface overrides + virtual void get_default_card_software(std::string &result); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_80xx); + virtual DECLARE_READ8_MEMBER(read_d5xx); + virtual DECLARE_WRITE8_MEMBER(write_80xx); + virtual DECLARE_WRITE8_MEMBER(write_d5xx); + +private: + device_a800_cart_interface* m_cart; + int m_type; +}; + + +// The variants below are added to handle the additional formats for a5200, and to give more +// clear error messages if you try to load an A5200 game into an A800 or a XEGS, etc. + +// ======================> a5200_cart_slot_device + +class a5200_cart_slot_device : public a800_cart_slot_device +{ +public: + // construction/destruction + a5200_cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual ~a5200_cart_slot_device(); + + virtual const char *file_extensions() const { return "bin,rom,car,a52"; } + + // slot interface overrides + virtual void get_default_card_software(std::string &result); +}; + +// ======================> xegs_cart_slot_device + +class xegs_cart_slot_device : public a800_cart_slot_device +{ +public: + // construction/destruction + xegs_cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual ~xegs_cart_slot_device(); + + virtual const char *file_extensions() const { return "bin,rom,car"; } + + // slot interface overrides + virtual void get_default_card_software(std::string &result); +}; + +// device type definition +extern const device_type A800_CART_SLOT; +extern const device_type A5200_CART_SLOT; +extern const device_type XEGS_CART_SLOT; + + +/*************************************************************************** + DEVICE CONFIGURATION MACROS + ***************************************************************************/ + +#define A800SLOT_ROM_REGION_TAG ":cart:rom" + +#define MCFG_A800_CARTRIDGE_ADD(_tag,_slot_intf,_def_slot) \ + MCFG_DEVICE_ADD(_tag, A800_CART_SLOT, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) + +#define MCFG_A5200_CARTRIDGE_ADD(_tag,_slot_intf,_def_slot) \ + MCFG_DEVICE_ADD(_tag, A5200_CART_SLOT, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) + +#define MCFG_XEGS_CARTRIDGE_ADD(_tag,_slot_intf,_def_slot) \ + MCFG_DEVICE_ADD(_tag, XEGS_CART_SLOT, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) + + +#endif diff --git a/src/devices/bus/a800/oss.c b/src/devices/bus/a800/oss.c new file mode 100644 index 00000000000..8f7ae76735f --- /dev/null +++ b/src/devices/bus/a800/oss.c @@ -0,0 +1,252 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + A800 ROM cart emulation + +***********************************************************************************************************/ + + +#include "emu.h" +#include "oss.h" + + +//------------------------------------------------- +// constructor +//------------------------------------------------- + +const device_type A800_ROM_OSS8K = &device_creator; +const device_type A800_ROM_OSS34 = &device_creator; +const device_type A800_ROM_OSS43 = &device_creator; +const device_type A800_ROM_OSS91 = &device_creator; + + +a800_rom_oss8k_device::a800_rom_oss8k_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : a800_rom_device(mconfig, A800_ROM_OSS8K, "Atari 800 ROM Carts OSS 8K", tag, owner, clock, "a800_oss8k", __FILE__) +{ +} + + +a800_rom_oss34_device::a800_rom_oss34_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : a800_rom_device(mconfig, A800_ROM_OSS34, "Atari 800 ROM Carts OSS-034M", tag, owner, clock, "a800_034m", __FILE__) +{ +} + + +a800_rom_oss43_device::a800_rom_oss43_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : a800_rom_device(mconfig, A800_ROM_OSS43, "Atari 800 ROM Carts OSS-043M", tag, owner, clock, "a800_043m", __FILE__) +{ +} + + +a800_rom_oss91_device::a800_rom_oss91_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : a800_rom_device(mconfig, A800_ROM_OSS91, "Atari 800 ROM Carts OSS-M091", tag, owner, clock, "a800_m091", __FILE__) +{ +} + + + +void a800_rom_oss8k_device::device_start() +{ + save_item(NAME(m_bank)); +} + +void a800_rom_oss8k_device::device_reset() +{ + m_bank = 0; +} + + +void a800_rom_oss34_device::device_start() +{ + save_item(NAME(m_bank)); +} + +void a800_rom_oss34_device::device_reset() +{ + m_bank = 1; +} + + +void a800_rom_oss43_device::device_start() +{ + save_item(NAME(m_bank)); +} + +void a800_rom_oss43_device::device_reset() +{ + m_bank = 0; +} + + +void a800_rom_oss91_device::device_start() +{ + save_item(NAME(m_bank)); +} + +void a800_rom_oss91_device::device_reset() +{ + m_bank = 0; +} + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +/*------------------------------------------------- + + OSS 8K + + This is used by The Writer's Tool only. + + -------------------------------------------------*/ + +READ8_MEMBER(a800_rom_oss8k_device::read_80xx) +{ + if (offset >= 0x1000) + return m_rom[offset & 0xfff]; + else + return m_rom[(offset & 0xfff) + (m_bank * 0x1000)]; +} + +WRITE8_MEMBER(a800_rom_oss8k_device::write_d5xx) +{ + switch (offset & 0x09) + { + case 0: + case 1: + m_bank = 1; + break; + case 9: + m_bank = 0; + break; + default: + break; + } +} + + +/*------------------------------------------------- + + OSS 034M + + This apparently comes from a dump with the wrong bank order... + investigate whether we should remove it! + + -------------------------------------------------*/ + +READ8_MEMBER(a800_rom_oss34_device::read_80xx) +{ + if (offset >= 0x1000) + return m_rom[(offset & 0xfff) + 0x3000]; + else if (m_bank == 3) + return 0xff; + else + return m_rom[(offset & 0xfff) + (m_bank * 0x1000)]; +} + +WRITE8_MEMBER(a800_rom_oss34_device::write_d5xx) +{ + switch (offset & 0x0f) + { + case 0: + case 1: + m_bank = 0; + break; + case 2: + case 6: + m_bank = 3; // in this case the ROM gets disabled and 0xff is returned in 0xa000-0xafff + break; + case 3: + case 7: + m_bank = 1; + break; + case 4: + case 5: + m_bank = 2; + break; + default: + break; + } +} + + +/*------------------------------------------------- + + OSS 043M + + Same as above but with correct bank order + + -------------------------------------------------*/ + +READ8_MEMBER(a800_rom_oss43_device::read_80xx) +{ + if (offset >= 0x1000) + return m_rom[(offset & 0xfff) + 0x3000]; + else if (m_bank == 3) + return 0xff; + else + return m_rom[(offset & 0xfff) + (m_bank * 0x1000)]; +} + +WRITE8_MEMBER(a800_rom_oss43_device::write_d5xx) +{ + switch (offset & 0x0f) + { + case 0: + case 1: + m_bank = 0; + break; + case 2: + case 6: + m_bank = 3; // in this case the ROM gets disabled and 0xff is returned in 0xa000-0xafff + break; + case 3: + case 7: + m_bank = 2; + break; + case 4: + case 5: + m_bank = 1; + break; + default: + break; + } +} + + +/*------------------------------------------------- + + OSS M091 + + Simplified banking system which only uses two + address lines (A0 & A3) + + -------------------------------------------------*/ + +READ8_MEMBER(a800_rom_oss91_device::read_80xx) +{ + if (offset >= 0x1000) + return m_rom[offset & 0xfff]; + else + return m_rom[(offset & 0xfff) + (m_bank * 0x1000)]; +} + +WRITE8_MEMBER(a800_rom_oss91_device::write_d5xx) +{ + switch (offset & 0x09) + { + case 0: + m_bank = 1; + break; + case 1: + m_bank = 3; + break; + case 9: + m_bank = 2; + break; + default: + break; + } +} diff --git a/src/devices/bus/a800/oss.h b/src/devices/bus/a800/oss.h new file mode 100644 index 00000000000..f781c8f5182 --- /dev/null +++ b/src/devices/bus/a800/oss.h @@ -0,0 +1,97 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __A800_OSS_H +#define __A800_OSS_H + +#include "rom.h" + + +// ======================> a800_rom_oss8k_device + +class a800_rom_oss8k_device : public a800_rom_device +{ +public: + // construction/destruction + a800_rom_oss8k_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + virtual DECLARE_READ8_MEMBER(read_80xx); + virtual DECLARE_WRITE8_MEMBER(write_d5xx); + +protected: + int m_bank; +}; + + +// ======================> a800_rom_oss34_device + +class a800_rom_oss34_device : public a800_rom_device +{ +public: + // construction/destruction + a800_rom_oss34_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + virtual DECLARE_READ8_MEMBER(read_80xx); + virtual DECLARE_WRITE8_MEMBER(write_d5xx); + +protected: + int m_bank; +}; + + +// ======================> a800_rom_oss43_device + +class a800_rom_oss43_device : public a800_rom_device +{ +public: + // construction/destruction + a800_rom_oss43_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + virtual DECLARE_READ8_MEMBER(read_80xx); + virtual DECLARE_WRITE8_MEMBER(write_d5xx); + +protected: + int m_bank; +}; + + +// ======================> a800_rom_oss91_device + +class a800_rom_oss91_device : public a800_rom_device +{ +public: + // construction/destruction + a800_rom_oss91_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + virtual DECLARE_READ8_MEMBER(read_80xx); + virtual DECLARE_WRITE8_MEMBER(write_d5xx); + +protected: + int m_bank; +}; + + + +// device type definition +extern const device_type A800_ROM_OSS8K; +extern const device_type A800_ROM_OSS34; +extern const device_type A800_ROM_OSS43; +extern const device_type A800_ROM_OSS91; + + +#endif diff --git a/src/devices/bus/a800/rom.c b/src/devices/bus/a800/rom.c new file mode 100644 index 00000000000..f52a489bcf0 --- /dev/null +++ b/src/devices/bus/a800/rom.c @@ -0,0 +1,447 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + A800/A5200/XEGS ROM cart emulation + + Basic carts work the same (in addition of being mostly compatible) for all these systems + and thus we deal with them in a single file + +***********************************************************************************************************/ + + +#include "emu.h" +#include "rom.h" + + +//------------------------------------------------- +// constructor +//------------------------------------------------- + +const device_type A800_ROM = &device_creator; +const device_type A800_ROM_BBSB = &device_creator; +const device_type A800_ROM_WILLIAMS = &device_creator; +const device_type A800_ROM_EXPRESS = &device_creator; +const device_type A800_ROM_TURBO = &device_creator; +const device_type A800_ROM_TELELINK2 = &device_creator; +const device_type A800_ROM_MICROCALC = &device_creator; +const device_type XEGS_ROM = &device_creator; +const device_type A5200_ROM_2CHIPS = &device_creator; +const device_type A5200_ROM_BBSB = &device_creator; + + +a800_rom_device::a800_rom_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_a800_cart_interface( mconfig, *this ) +{ +} + +a800_rom_device::a800_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, A800_ROM, "Atari 800 ROM Carts", tag, owner, clock, "a800_rom", __FILE__), + device_a800_cart_interface( mconfig, *this ) +{ +} + + +a800_rom_bbsb_device::a800_rom_bbsb_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : a800_rom_device(mconfig, A800_ROM_BBSB, "Atari 800 ROM Cart BBSB", tag, owner, clock, "a800_bbsb", __FILE__) +{ +} + + + +xegs_rom_device::xegs_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : a800_rom_device(mconfig, XEGS_ROM, "Atari XEGS 64K ROM Carts", tag, owner, clock, "a800_xegs", __FILE__) +{ +} + + +a800_rom_williams_device::a800_rom_williams_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : a800_rom_device(mconfig, A800_ROM_WILLIAMS, "Atari 800 64K ROM Carts Williams", tag, owner, clock, "a800_williams", __FILE__) +{ +} + + +a800_rom_express_device::a800_rom_express_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : a800_rom_device(mconfig, A800_ROM_EXPRESS, "Atari 800 64K ROM Carts Express/Diamond", tag, owner, clock, "a800_express", __FILE__) +{ +} + + +a800_rom_turbo_device::a800_rom_turbo_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : a800_rom_device(mconfig, A800_ROM_TURBO, "Atari 800 64K ROM Carts Turbosoft", tag, owner, clock, "a800_turbo", __FILE__) +{ +} + + +a800_rom_telelink2_device::a800_rom_telelink2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : a800_rom_device(mconfig, A800_ROM_TELELINK2, "Atari 800 64K ROM Cart Telelink II", tag, owner, clock, "a800_tlink2", __FILE__) +{ +} + + +a800_rom_microcalc_device::a800_rom_microcalc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : a800_rom_device(mconfig, A800_ROM_MICROCALC, "Atari 800 64K ROM Cart SITSA MicroCalc", tag, owner, clock, "a800_sitsa", __FILE__) +{ +} + + +a5200_rom_2chips_device::a5200_rom_2chips_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : a800_rom_device(mconfig, A5200_ROM_2CHIPS, "Atari 5200 ROM Cart 16K in 2 Chips", tag, owner, clock, "a5200_16k2c", __FILE__) +{ +} + + +a5200_rom_bbsb_device::a5200_rom_bbsb_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : a800_rom_device(mconfig, A5200_ROM_BBSB, "Atari 5200 ROM Cart BBSB", tag, owner, clock, "a5200_bbsb", __FILE__) +{ +} + + + + +void a800_rom_device::device_start() +{ +} + +void a800_rom_device::device_reset() +{ +} + + +void a800_rom_bbsb_device::device_start() +{ + save_item(NAME(m_banks)); +} + +void a800_rom_bbsb_device::device_reset() +{ + m_banks[0] = 0; + m_banks[1] = 0; +} + + +void xegs_rom_device::device_start() +{ + save_item(NAME(m_bank)); +} + +void xegs_rom_device::device_reset() +{ + m_bank = 0; +} + + +void a800_rom_williams_device::device_start() +{ + save_item(NAME(m_bank)); +} + +void a800_rom_williams_device::device_reset() +{ + m_bank = 0; +} + + +void a800_rom_express_device::device_start() +{ + save_item(NAME(m_bank)); +} + +void a800_rom_express_device::device_reset() +{ + m_bank = 0; +} + + +void a800_rom_turbo_device::device_start() +{ + save_item(NAME(m_bank)); +} + +void a800_rom_turbo_device::device_reset() +{ + m_bank = 0; +} + + +void a800_rom_microcalc_device::device_start() +{ + save_item(NAME(m_bank)); +} + +void a800_rom_microcalc_device::device_reset() +{ + m_bank = 0; +} + + +void a5200_rom_bbsb_device::device_start() +{ + save_item(NAME(m_banks)); +} + +void a5200_rom_bbsb_device::device_reset() +{ + m_banks[0] = 0; + m_banks[1] = 0; +} + + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +/*------------------------------------------------- + + Carts with no bankswitch (8K, 16K) + + The cart accessors are mapped in the correct + range at driver start + + -------------------------------------------------*/ + +READ8_MEMBER(a800_rom_device::read_80xx) +{ + return m_rom[offset & (m_rom_size - 1)]; +} + + + +/*------------------------------------------------- + + Bounty Bob Strikes Back! cart (40K) + + Area 0xa000-0xbfff always point to last 8K bank + Areas 0x8000-0x8fff and 0x9000-0x9fff are + separate banks of 4K mapped either in the first + 16K chunk or in the second 16K chunk + Bankswitch is controlled by data written in + 0x8000-0x8fff and 0x9000-0x9fff respectively + + -------------------------------------------------*/ + +READ8_MEMBER(a800_rom_bbsb_device::read_80xx) +{ + if (offset < 0x1000) + return m_rom[(offset & 0xfff) + (m_banks[0] * 0x1000) + 0]; + else if (offset < 0x2000) + return m_rom[(offset & 0xfff) + (m_banks[1] * 0x1000) + 0x4000]; + else + return m_rom[(offset & 0x1fff) + 0x8000]; +} + +WRITE8_MEMBER(a800_rom_bbsb_device::write_80xx) +{ + UINT16 addr = offset & 0xfff; + if (addr >= 0xff6 && addr <= 0xff9) + m_banks[BIT(offset, 12)] = (addr - 0xff6); +} + +/*------------------------------------------------- + + XEGS carts (32K, 64K or 128K) + + Bankswitch is controlled by data written in + 0xd500-0xd5ff + + -------------------------------------------------*/ + +READ8_MEMBER(xegs_rom_device::read_80xx) +{ + if (offset < 0x2000) + return m_rom[(offset & 0x1fff) + (m_bank * 0x2000)]; + else + return m_rom[(offset & 0x1fff) + (m_bank_mask * 0x2000)]; // always last 8K bank + +} + +WRITE8_MEMBER(xegs_rom_device::write_d5xx) +{ + m_bank = data & m_bank_mask; +} + + +/*------------------------------------------------- + + Williams 64K + + The rom is accessed in 8K chunks at 0xa000-0xbfff + Bankswitch is controlled by writing to 7 diff + offsets (their location varies with the cart type): + offs 0 points to bank 0, offs 1 points to bank 1, + and so on... the rom can be disabled by writing to + the offsets 0x8-0xf of the same range as the bankswitch + + -------------------------------------------------*/ + +READ8_MEMBER(a800_rom_williams_device::read_80xx) +{ + return m_rom[(offset & 0x1fff) + (m_bank * 0x2000)]; +} + +WRITE8_MEMBER(a800_rom_williams_device::write_d5xx) +{ + m_bank = (offset & 0x07); +} + +/*------------------------------------------------- + + Express 64K / Diamond 64K carts + + The rom is accessed in 8K chunks at 0xa000-0xbfff + Bankswitch is the same as above, but writes trigger + banks in reverse order: offs 7 points to bank 0, offs 6 + points to bank 1, and so on... the rom can be disabled + by writing to the offsets 0x8-0xf of the same range + as the bankswitch + + -------------------------------------------------*/ + +READ8_MEMBER(a800_rom_express_device::read_80xx) +{ + return m_rom[(offset & 0x1fff) + (m_bank * 0x2000)]; +} + +WRITE8_MEMBER(a800_rom_express_device::write_d5xx) +{ + m_bank = (offset ^ 0x07) & 0x0f; +} + + +/*------------------------------------------------- + + Turbosoft 64K / 128K + + + -------------------------------------------------*/ + +READ8_MEMBER(a800_rom_turbo_device::read_80xx) +{ + return m_rom[(offset & 0x1fff) + (m_bank * 0x2000)]; +} + +WRITE8_MEMBER(a800_rom_turbo_device::write_d5xx) +{ + m_bank = offset & m_bank_mask; +} + + +/*------------------------------------------------- + + Telelink II + + + -------------------------------------------------*/ + +READ8_MEMBER(a800_rom_telelink2_device::read_80xx) +{ + if (offset >= 0x2000) + return m_rom[offset & 0x1fff]; + if (offset >= 0x1000 && offset < 0x1100) + return m_nvram[offset & 0xff]; + + return 0xff; +} + +WRITE8_MEMBER(a800_rom_telelink2_device::write_80xx) +{ + m_nvram[offset & 0xff] = data | 0xf0; // low 4bits only +} + +READ8_MEMBER(a800_rom_telelink2_device::read_d5xx) +{ + // this should affect NVRAM enable / save + return 0xff; +} + +WRITE8_MEMBER(a800_rom_telelink2_device::write_d5xx) +{ + // this should affect NVRAM enable / save +} + + + +/*------------------------------------------------- + + SITSA Microcalc + + + -------------------------------------------------*/ + +READ8_MEMBER(a800_rom_microcalc_device::read_80xx) +{ + return m_rom[(offset & 0x1fff) + (m_bank * 0x2000)]; +} + +WRITE8_MEMBER(a800_rom_microcalc_device::write_d5xx) +{ + m_bank = data; +} + + + +// Atari 5200 + + +/*------------------------------------------------- + + Carts with no bankswitch (4K, 8K, 16K, 32K) + + Same as base carts above + + -------------------------------------------------*/ + +/*------------------------------------------------- + + Carts with 2x8K (16K) with A13 line not connected + + Range 0x4000-0x7fff contains two copies of the low + 8K, range 0x8000-0xbfff contains two copies of the + high 8K + + -------------------------------------------------*/ + +READ8_MEMBER(a5200_rom_2chips_device::read_80xx) +{ + if (offset < 0x4000) + return m_rom[offset & 0x1fff]; + else + return m_rom[(offset & 0x1fff) + 0x2000]; +} + + +/*------------------------------------------------- + + Bounty Bob Strikes Back! cart (40K) + + Similar to the A800 version, but: + Area 0x8000-0xbfff always point to last 8K bank + (repeated twice) + Areas 0x4000-0x4fff and 0x5000-0x5fff are + separate banks of 4K mapped either in the first + 16K chunk or in the second 16K chunk + Bankswitch is controlled by data written in + 0x4000-0x4fff and 0x5000-0x5fff respectively + + -------------------------------------------------*/ + +READ8_MEMBER(a5200_rom_bbsb_device::read_80xx) +{ + if (offset < 0x1000) + return m_rom[(offset & 0xfff) + (m_banks[0] * 0x1000) + 0]; + else if (offset < 0x2000) + return m_rom[(offset & 0xfff) + (m_banks[1] * 0x1000) + 0x4000]; + else if (offset >= 0x4000) + return m_rom[(offset & 0x1fff) + 0x8000]; + else + return 0; +} + +WRITE8_MEMBER(a5200_rom_bbsb_device::write_80xx) +{ + UINT16 addr = offset & 0xfff; + if (addr >= 0xff6 && addr <= 0xff9) + m_banks[BIT(offset, 12)] = (addr - 0xff6); +} diff --git a/src/devices/bus/a800/rom.h b/src/devices/bus/a800/rom.h new file mode 100644 index 00000000000..a1e6cde0925 --- /dev/null +++ b/src/devices/bus/a800/rom.h @@ -0,0 +1,224 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __A800_ROM_H +#define __A800_ROM_H + +#include "a800_slot.h" + + +// ======================> a800_rom_device + +class a800_rom_device : public device_t, + public device_a800_cart_interface +{ +public: + // construction/destruction + a800_rom_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + a800_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + virtual DECLARE_READ8_MEMBER(read_80xx); +}; + + +// ======================> a800_rom_bbsb_device + +class a800_rom_bbsb_device : public a800_rom_device +{ +public: + // construction/destruction + a800_rom_bbsb_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + virtual DECLARE_READ8_MEMBER(read_80xx); + virtual DECLARE_WRITE8_MEMBER(write_80xx); + +protected: + int m_banks[2]; +}; + + +// ======================> a800_rom_williams_device + +class a800_rom_williams_device : public a800_rom_device +{ +public: + // construction/destruction + a800_rom_williams_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + virtual DECLARE_READ8_MEMBER(read_80xx); + virtual DECLARE_WRITE8_MEMBER(write_d5xx); + +protected: + int m_bank; +}; + + +// ======================> a800_rom_express_device + +class a800_rom_express_device : public a800_rom_device +{ +public: + // construction/destruction + a800_rom_express_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + virtual DECLARE_READ8_MEMBER(read_80xx); + virtual DECLARE_WRITE8_MEMBER(write_d5xx); + +protected: + int m_bank; +}; + + +// ======================> a800_rom_blizzard_device + +class a800_rom_blizzard_device : public a800_rom_device +{ +public: + // construction/destruction + a800_rom_blizzard_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + virtual DECLARE_READ8_MEMBER(read_80xx); +}; + + +// ======================> a800_rom_turbo_device + +class a800_rom_turbo_device : public a800_rom_device +{ +public: + // construction/destruction + a800_rom_turbo_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + virtual DECLARE_READ8_MEMBER(read_80xx); + virtual DECLARE_WRITE8_MEMBER(write_d5xx); + +protected: + int m_bank; +}; + + +// ======================> a800_rom_telelink2_device + +class a800_rom_telelink2_device : public a800_rom_device +{ +public: + // construction/destruction + a800_rom_telelink2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual DECLARE_READ8_MEMBER(read_80xx); + virtual DECLARE_WRITE8_MEMBER(write_80xx); + virtual DECLARE_READ8_MEMBER(read_d5xx); + virtual DECLARE_WRITE8_MEMBER(write_d5xx); +}; + + +// ======================> a800_rom_microcalc_device + +class a800_rom_microcalc_device : public a800_rom_device +{ +public: + // construction/destruction + a800_rom_microcalc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + virtual DECLARE_READ8_MEMBER(read_80xx); + virtual DECLARE_WRITE8_MEMBER(write_d5xx); + +protected: + int m_bank; +}; + + +// ======================> xegs_rom_device + +class xegs_rom_device : public a800_rom_device +{ +public: + // construction/destruction + xegs_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + virtual DECLARE_READ8_MEMBER(read_80xx); + virtual DECLARE_WRITE8_MEMBER(write_d5xx); + +protected: + int m_bank; +}; + + +// ======================> a5200_rom_2chips_device + +class a5200_rom_2chips_device : public a800_rom_device +{ +public: + // construction/destruction + a5200_rom_2chips_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual DECLARE_READ8_MEMBER(read_80xx); +}; + + +// ======================> a5200_rom_bbsb_device + +class a5200_rom_bbsb_device : public a800_rom_device +{ +public: + // construction/destruction + a5200_rom_bbsb_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + virtual DECLARE_READ8_MEMBER(read_80xx); + virtual DECLARE_WRITE8_MEMBER(write_80xx); + +protected: + int m_banks[2]; +}; + + + +// device type definition +extern const device_type A800_ROM; +extern const device_type A800_ROM_BBSB; +extern const device_type A800_ROM_WILLIAMS; +extern const device_type A800_ROM_EXPRESS; +extern const device_type A800_ROM_TURBO; +extern const device_type A800_ROM_TELELINK2; +extern const device_type A800_ROM_MICROCALC; +extern const device_type XEGS_ROM; +extern const device_type A5200_ROM_2CHIPS; +extern const device_type A5200_ROM_BBSB; + + +#endif diff --git a/src/devices/bus/a800/sparta.c b/src/devices/bus/a800/sparta.c new file mode 100644 index 00000000000..8e6a439d669 --- /dev/null +++ b/src/devices/bus/a800/sparta.c @@ -0,0 +1,71 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + A800 SpartaDOS cart emulation + +***********************************************************************************************************/ + + +#include "emu.h" +#include "sparta.h" + + +//------------------------------------------------- +// constructor +//------------------------------------------------- + +const device_type A800_ROM_SPARTADOS = &device_creator; + + +a800_rom_spartados_device::a800_rom_spartados_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : a800_rom_device(mconfig, A800_ROM_SPARTADOS, "Atari 800 SpartaDOS ROM Carts", tag, owner, clock, "a800_sparta", __FILE__) +{ +} + + + +void a800_rom_spartados_device::device_start() +{ + save_item(NAME(m_bank)); + save_item(NAME(m_subslot_enabled)); +} + +void a800_rom_spartados_device::device_reset() +{ + m_bank = 0; + m_subslot_enabled = 0; +} + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +/*------------------------------------------------- + + SpartaDOS 64K carts + + Similar to Express / Diamond carts, because + bankswitch is controlled by writing to 7 diff + offsets in reverse order, but writes to offsets + 0x8-0xf also enable/disable subslot + + -------------------------------------------------*/ + +READ8_MEMBER(a800_rom_spartados_device::read_80xx) +{ + if (!m_subslot_enabled) + return m_rom[(offset & 0x1fff) + (m_bank * 0x2000)]; + else + return 0xff; // subslot, currently not implemented +} + +WRITE8_MEMBER(a800_rom_spartados_device::write_d5xx) +{ + if (offset & 0x08) + m_subslot_enabled = !BIT(offset, 2); + else + m_bank = (offset ^ 0x07) & 0x0f; + +} diff --git a/src/devices/bus/a800/sparta.h b/src/devices/bus/a800/sparta.h new file mode 100644 index 00000000000..6b6cf9eb932 --- /dev/null +++ b/src/devices/bus/a800/sparta.h @@ -0,0 +1,34 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __A800_SPARTA_H +#define __A800_SPARTA_H + +#include "rom.h" + + +// ======================> a800_rom_spartados_device + +class a800_rom_spartados_device : public a800_rom_device +{ +public: + // construction/destruction + a800_rom_spartados_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + virtual DECLARE_READ8_MEMBER(read_80xx); + virtual DECLARE_WRITE8_MEMBER(write_d5xx); + +protected: + int m_bank, m_subslot_enabled; +}; + + + +// device type definition +extern const device_type A800_ROM_SPARTADOS; + + +#endif diff --git a/src/devices/bus/a8sio/a8sio.c b/src/devices/bus/a8sio/a8sio.c new file mode 100644 index 00000000000..fd64d077b50 --- /dev/null +++ b/src/devices/bus/a8sio/a8sio.c @@ -0,0 +1,219 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +/*************************************************************************** + + a8sio.h - Atari 8 bit SIO bus interface + + + 1 1 + 2 4 6 8 0 2 + +-----------+ + / o o o o o o \ + / o o o o o o o \ + +-----------------+ + 1 3 5 7 9 1 1 + 1 3 + + 1 - clock in (to computer) + 2 - clock out + 3 - data in + 4 - GND + 5 - data out + 6 - GND + 7 - command (active low) + 8 - motor + 9 - proceed (active low) + 10 - +5V/ready + 11 - audio in + 12 - +12V (A400/A800) + 13 - interrupt (active low) + +***************************************************************************/ + +#include "emu.h" +#include "a8sio.h" +#include "cassette.h" + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type A8SIO_SLOT = &device_creator; + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// a8sio_slot_device - constructor +//------------------------------------------------- +a8sio_slot_device::a8sio_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, A8SIO_SLOT, "Atari 8 bit SIO Slot", tag, owner, clock, "a8sio_slot", __FILE__) + , device_slot_interface(mconfig, *this) +{ +} + +a8sio_slot_device::a8sio_slot_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_slot_interface(mconfig, *this) +{ +} + +void a8sio_slot_device::static_set_a8sio_slot(device_t &device, const char *tag, const char *slottag) +{ + a8sio_slot_device &a8sio_ext = dynamic_cast(device); + a8sio_ext.m_a8sio_tag = tag; + a8sio_ext.m_a8sio_slottag = slottag; +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void a8sio_slot_device::device_start() +{ + device_a8sio_card_interface *dev = dynamic_cast(get_card_device()); + + if (dev) + { + device_a8sio_card_interface::static_set_a8sio_tag(*dev, m_a8sio_tag, m_a8sio_slottag); + } +} + + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type A8SIO = &device_creator; + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// a8sio_device - constructor +//------------------------------------------------- + +a8sio_device::a8sio_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, A8SIO, "Atari 8 biot SIO", tag, owner, clock, "a8sio", __FILE__) + , m_out_clock_in_cb(*this) + , m_out_data_in_cb(*this) + , m_out_audio_in_cb(*this) +{ +} + +a8sio_device::a8sio_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source) + , m_out_clock_in_cb(*this) + , m_out_data_in_cb(*this) + , m_out_audio_in_cb(*this) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void a8sio_device::device_start() +{ + // resolve callbacks + m_out_clock_in_cb.resolve_safe(); + m_out_data_in_cb.resolve_safe(); + m_out_audio_in_cb.resolve_safe(); + + // clear slot + m_device = NULL; +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void a8sio_device::device_reset() +{ +} + +device_a8sio_card_interface *a8sio_device::get_a8sio_card() +{ + return m_device; +} + +void a8sio_device::add_a8sio_card(device_a8sio_card_interface *card) +{ + m_device = card; +} + +WRITE_LINE_MEMBER( a8sio_device::clock_in_w ) +{ + m_out_clock_in_cb(state); +} + +WRITE_LINE_MEMBER( a8sio_device::data_in_w ) +{ + m_out_data_in_cb(state); +} + +WRITE_LINE_MEMBER( a8sio_device::motor_w ) +{ + if (m_device) + { + m_device->motor_w(state); + } +} + +WRITE8_MEMBER( a8sio_device::audio_in_w ) +{ + m_out_audio_in_cb(data); +} + + +//************************************************************************** +// DEVICE A8SIO CARD INTERFACE +//************************************************************************** + +//------------------------------------------------- +// device_a8sio_card_interface - constructor +//------------------------------------------------- + +device_a8sio_card_interface::device_a8sio_card_interface(const machine_config &mconfig, device_t &device) + : device_slot_card_interface(mconfig, device) + , m_a8sio(NULL) + , m_a8sio_tag(NULL) +{ +} + + +//------------------------------------------------- +// ~device_a8sio_card_interface - destructor +//------------------------------------------------- + +device_a8sio_card_interface::~device_a8sio_card_interface() +{ +} + +void device_a8sio_card_interface::static_set_a8sio_tag(device_t &device, const char *tag, const char *slottag) +{ + device_a8sio_card_interface &a8sio_card = dynamic_cast(device); + a8sio_card.m_a8sio_tag = tag; + a8sio_card.m_a8sio_slottag = slottag; +} + +void device_a8sio_card_interface::set_a8sio_device() +{ + m_a8sio = dynamic_cast(device().machine().device(m_a8sio_tag)); + m_a8sio->add_a8sio_card(this); +} + +WRITE_LINE_MEMBER( device_a8sio_card_interface::motor_w ) +{ + //printf("device_a8sio_card_interface::motor_w %d\n", state); +} + + +SLOT_INTERFACE_START(a8sio_cards) + SLOT_INTERFACE("cassette", A8SIO_CASSETTE) +SLOT_INTERFACE_END diff --git a/src/devices/bus/a8sio/a8sio.h b/src/devices/bus/a8sio/a8sio.h new file mode 100644 index 00000000000..29e548946d4 --- /dev/null +++ b/src/devices/bus/a8sio/a8sio.h @@ -0,0 +1,144 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +/*************************************************************************** + + a8sio.h - Atari 8 bit SIO bus interface + + + 1 1 + 2 4 6 8 0 2 + +-----------+ + / o o o o o o \ + / o o o o o o o \ + +-----------------+ + 1 3 5 7 9 1 1 + 1 3 + + 1 - clock in (to computer) + 2 - clock out + 3 - data in + 4 - GND + 5 - data out + 6 - GND + 7 - command (active low) + 8 - motor + 9 - proceed (active low) + 10 - +5V/ready + 11 - audio in + 12 - +12V (A400/A800) + 13 - interrupt (active low) + +***************************************************************************/ + +#pragma once + +#ifndef __A8SIO_H_ +#define __A8SIO_H_ + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_A8SIO_SLOT_ADD(_nbtag, _tag, _def_slot) \ + MCFG_DEVICE_ADD(_tag, A8SIO_SLOT, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(a8sio_cards, _def_slot, false) \ + a8sio_slot_device::static_set_a8sio_slot(*device, _nbtag, _tag); + +#define MCFG_A8SIO_DATA_IN_CB(_devcb) \ + devcb = &a8sio_device::set_data_in_callback(*device, DEVCB_##_devcb); + + +class a8sio_slot_device : public device_t, + public device_slot_interface +{ +public: + // construction/destruction + a8sio_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + a8sio_slot_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + // device-level overrides + virtual void device_start(); + + // inline configuration + static void static_set_a8sio_slot(device_t &device, const char *tag, const char *slottag); + +protected: + // configuration + const char *m_a8sio_tag; + const char *m_a8sio_slottag; +}; + + +// device type definition +extern const device_type A8SIO_SLOT; + + +class device_a8sio_card_interface; + +class a8sio_device : public device_t +{ +public: + // construction/destruction + a8sio_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + a8sio_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + // inline configuration + template static devcb_base &set_clock_in_callback(device_t &device, _Object object) { return downcast(device).m_out_clock_in_cb.set_callback(object); } + template static devcb_base &set_data_in_callback(device_t &device, _Object object) { return downcast(device).m_out_data_in_cb.set_callback(object); } + template static devcb_base &set_audio_in_callback(device_t &device, _Object object) { return downcast(device).m_out_audio_in_cb.set_callback(object); } + + void add_a8sio_card(device_a8sio_card_interface *card); + device_a8sio_card_interface *get_a8sio_card(); + + DECLARE_WRITE_LINE_MEMBER( clock_in_w ); // pin 1 + //virtual DECLARE_WRITE_LINE_MEMBER( clock_out_w ); // pin 2 + DECLARE_WRITE_LINE_MEMBER( data_in_w ); // pin 3 + //DECLARE_WRITE_LINE_MEMBER( data_out_wi ); // pin 5 + //DECLARE_WRITE_LINE_MEMBER( command_w ); // pin 7 + DECLARE_WRITE_LINE_MEMBER( motor_w ); // pin 8 + //DECLARE_WRITE_LINE_MEMBER( proceed_w ); // pin 9 + DECLARE_WRITE8_MEMBER( audio_in_w ); // pin 11 + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + devcb_write_line m_out_clock_in_cb; // pin 1 + devcb_write_line m_out_data_in_cb; // pin 3 + devcb_write8 m_out_audio_in_cb; // pin 11 + + device_a8sio_card_interface *m_device; +}; + + +// device type definition +extern const device_type A8SIO; + + +class device_a8sio_card_interface : public device_slot_card_interface +{ + friend class a8sio_device; +public: + // construction/destruction + device_a8sio_card_interface(const machine_config &mconfig, device_t &device); + virtual ~device_a8sio_card_interface(); + + void set_a8sio_device(); + + // inline configuration + static void static_set_a8sio_tag(device_t &device, const char *tag, const char *slottag); + + virtual DECLARE_WRITE_LINE_MEMBER( motor_w ); + +public: + a8sio_device *m_a8sio; + const char *m_a8sio_tag; + const char *m_a8sio_slottag; +}; + + +SLOT_INTERFACE_EXTERN(a8sio_cards); + +#endif diff --git a/src/devices/bus/a8sio/cassette.c b/src/devices/bus/a8sio/cassette.c new file mode 100644 index 00000000000..45d33173bac --- /dev/null +++ b/src/devices/bus/a8sio/cassette.c @@ -0,0 +1,117 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +/*************************************************************************** + + cassette.h - Atari 8 bit cassette player(s) + + +Known cassette players: +- Atari XC11 +- Atari XC12 (no SIO connection for an additional device) + +TODO: +- Implement cassette reading +- Implement cassette writing +- Add audio support +- Add SIO connector for a next device + +***************************************************************************/ + +#include "emu.h" +#include "cassette.h" + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type A8SIO_CASSETTE = &device_creator; +const device_timer_id TIMER_CASSETTE_READ = 1; + +static MACHINE_CONFIG_FRAGMENT( cassette ) + MCFG_CASSETTE_ADD("cassette") + //MCFG_CASSETTE_DEFAULT_STATE(CASSETTE_STOPPED) + MCFG_CASSETTE_DEFAULT_STATE(CASSETTE_PLAY) + MCFG_CASSETTE_INTERFACE("atari8bit_cass") +MACHINE_CONFIG_END + +machine_config_constructor a8sio_cassette_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( cassette ); +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +a8sio_cassette_device::a8sio_cassette_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, A8SIO_CASSETTE, "Atari 8 bit cassette", tag, owner, clock, "a8sio_cass", __FILE__) + , device_a8sio_card_interface(mconfig, *this) + , m_cassette(*this, "cassette") + , m_old_cass_signal(0) + , m_signal_count(0) +{ +} + +a8sio_cassette_device::a8sio_cassette_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source) + , device_a8sio_card_interface(mconfig, *this) + , m_cassette(*this, "cassette") + , m_old_cass_signal(0) + , m_signal_count(0) +{ +} + +void a8sio_cassette_device::device_start() +{ + set_a8sio_device(); + + save_item(NAME(m_old_cass_signal)); + save_item(NAME(m_signal_count)); + + m_read_timer = timer_alloc(TIMER_CASSETTE_READ); +} + +void a8sio_cassette_device::device_reset() +{ +} + +WRITE_LINE_MEMBER( a8sio_cassette_device::motor_w ) +{ + //printf("a8sio_cassette::motor_w %d\n", state); + if (!state) + { + m_cassette->change_state(CASSETTE_MOTOR_ENABLED, CASSETTE_MASK_MOTOR); + m_read_timer->adjust(attotime::zero, 0, attotime::from_hz(44100)); + } + else + { + m_cassette->change_state(CASSETTE_MOTOR_DISABLED, CASSETTE_MASK_MOTOR); + m_read_timer->reset(); + } +} + +void a8sio_cassette_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch (id) + { + case TIMER_CASSETTE_READ: + UINT8 cass_signal = m_cassette->input() < 0 ? 0 : 1; + + if (m_signal_count < 20) + { + m_signal_count++; + } + + if (cass_signal != m_old_cass_signal) + { + //printf("cass_signal: %d, count: %d, data: %d\n", cass_signal, m_signal_count, m_signal_count < 5 ? 1 : 0); + // ~4 kHz -> 0 + // ~5 kHz -> 1 + m_a8sio->data_in_w((m_signal_count < 5) ? 1 : 0); + m_signal_count = 0; + m_old_cass_signal = cass_signal; + } + break; + } +} diff --git a/src/devices/bus/a8sio/cassette.h b/src/devices/bus/a8sio/cassette.h new file mode 100644 index 00000000000..d9b59568864 --- /dev/null +++ b/src/devices/bus/a8sio/cassette.h @@ -0,0 +1,54 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +/*************************************************************************** + + cassette.h - Atari 8 bit cassette player(s) + + +Known cassette players: +- Atari XC11 +- Atari XC12 (no SIO connection for an additional device) + +***************************************************************************/ + +#pragma once + +#ifndef __A8SIO_CASSETTE_H_ +#define __A8SIO_CASSETTE_H_ + + +#include "a8sio.h" +#include "imagedev/cassette.h" + + +class a8sio_cassette_device + : public device_t + , public device_a8sio_card_interface +{ +public: + // construction/destruction + a8sio_cassette_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + a8sio_cassette_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + + virtual DECLARE_WRITE_LINE_MEMBER( motor_w ); + +protected: + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + required_device m_cassette; + emu_timer *m_read_timer; + + UINT8 m_old_cass_signal; + UINT8 m_signal_count; +}; + +// device type definition +extern const device_type A8SIO_CASSETTE; + + +#endif diff --git a/src/devices/bus/abcbus/abc890.c b/src/devices/bus/abcbus/abc890.c new file mode 100644 index 00000000000..ecfc1abf4d2 --- /dev/null +++ b/src/devices/bus/abcbus/abc890.c @@ -0,0 +1,408 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Luxor ABC 890 bus expander emulation + +*********************************************************************/ + +#include "abc890.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type ABC890 = &device_creator; +const device_type ABC_EXPANSION_UNIT = &device_creator; +const device_type ABC894 = &device_creator; +const device_type ABC850 = &device_creator; +const device_type ABC852 = &device_creator; +const device_type ABC856 = &device_creator; + + +//------------------------------------------------- +// MACHINE_DRIVER( abc890 ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( abc890 ) + MCFG_ABCBUS_SLOT_ADD("io1", abcbus_cards, NULL) + MCFG_ABCBUS_SLOT_ADD("io2", abcbus_cards, NULL) + MCFG_ABCBUS_SLOT_ADD("io3", abcbus_cards, NULL) + MCFG_ABCBUS_SLOT_ADD("io4", abcbus_cards, NULL) + MCFG_ABCBUS_SLOT_ADD("mem1", abcbus_cards, NULL) + MCFG_ABCBUS_SLOT_ADD("mem2", abcbus_cards, NULL) + MCFG_ABCBUS_SLOT_ADD("mem3", abcbus_cards, NULL) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor abc890_t::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( abc890 ); +} + + +//------------------------------------------------- +// MACHINE_DRIVER( abc_expansion_unit ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( abc_expansion_unit ) + MCFG_ABCBUS_SLOT_ADD("io1", abc80_cards, "abc830") + MCFG_ABCBUS_SLOT_ADD("io2", abc80_cards, NULL) + MCFG_ABCBUS_SLOT_ADD("io3", abc80_cards, NULL) + MCFG_ABCBUS_SLOT_ADD("io4", abc80_cards, NULL) + MCFG_ABCBUS_SLOT_ADD("mem1", abc80_cards, "memcard") + MCFG_ABCBUS_SLOT_ADD("mem2", abc80_cards, "16k") + MCFG_ABCBUS_SLOT_ADD("mem3", abc80_cards, NULL) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor abc_expansion_unit_t::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( abc_expansion_unit ); +} + + +//------------------------------------------------- +// MACHINE_DRIVER( abc894 ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( abc894 ) + MCFG_ABCBUS_SLOT_ADD("io1", abcbus_cards, NULL) + MCFG_ABCBUS_SLOT_ADD("io2", abcbus_cards, NULL) + MCFG_ABCBUS_SLOT_ADD("io3", abcbus_cards, NULL) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor abc894_t::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( abc894 ); +} + + +//------------------------------------------------- +// MACHINE_DRIVER( abc850 ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( abc850 ) + MCFG_ABCBUS_SLOT_ADD("io1", abcbus_cards, "abc850fdd") + MCFG_ABCBUS_SLOT_ADD("io2", abcbus_cards, "xebec") + MCFG_DEVICE_CARD_DEFAULT_BIOS("xebec", "ro202") + MCFG_ABCBUS_SLOT_ADD("io3", abcbus_cards, NULL) + MCFG_ABCBUS_SLOT_ADD("io4", abcbus_cards, NULL) + MCFG_ABCBUS_SLOT_ADD("io5", abcbus_cards, NULL) + MCFG_ABCBUS_SLOT_ADD("io6", abcbus_cards, NULL) + MCFG_ABCBUS_SLOT_ADD("io7", abcbus_cards, NULL) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor abc850_t::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( abc850 ); +} + + +//------------------------------------------------- +// MACHINE_DRIVER( abc852 ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( abc852 ) + MCFG_ABCBUS_SLOT_ADD("io1", abcbus_cards, "abc850fdd") + MCFG_ABCBUS_SLOT_ADD("io2", abcbus_cards, "xebec") + MCFG_DEVICE_CARD_DEFAULT_BIOS("xebec", "basf6185") + MCFG_ABCBUS_SLOT_ADD("io3", abcbus_cards, NULL) + MCFG_ABCBUS_SLOT_ADD("io4", abcbus_cards, NULL) + MCFG_ABCBUS_SLOT_ADD("io5", abcbus_cards, NULL) + MCFG_ABCBUS_SLOT_ADD("io6", abcbus_cards, NULL) + MCFG_ABCBUS_SLOT_ADD("io7", abcbus_cards, NULL) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor abc852_t::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( abc852 ); +} + + +//------------------------------------------------- +// MACHINE_DRIVER( abc856 ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( abc856 ) + MCFG_ABCBUS_SLOT_ADD("io1", abcbus_cards, "abc850fdd") + MCFG_ABCBUS_SLOT_ADD("io2", abcbus_cards, "xebec") + MCFG_DEVICE_CARD_DEFAULT_BIOS("xebec", "micr1325") + MCFG_ABCBUS_SLOT_ADD("io3", abcbus_cards, NULL) + MCFG_ABCBUS_SLOT_ADD("io4", abcbus_cards, NULL) + MCFG_ABCBUS_SLOT_ADD("io5", abcbus_cards, NULL) + MCFG_ABCBUS_SLOT_ADD("io6", abcbus_cards, NULL) + MCFG_ABCBUS_SLOT_ADD("io7", abcbus_cards, NULL) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor abc856_t::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( abc856 ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// abc890_t - constructor +//------------------------------------------------- + +abc890_t::abc890_t(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_abcbus_card_interface(mconfig, *this) +{ +} + +abc890_t::abc890_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, ABC890, "ABC 890", tag, owner, clock, "abc890", __FILE__), + device_abcbus_card_interface(mconfig, *this) +{ +} + +abc_expansion_unit_t::abc_expansion_unit_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + abc890_t(mconfig, ABC_EXPANSION_UNIT, "ABC Expansion Unit", tag, owner, clock, "abcexp", __FILE__) +{ +} + +abc894_t::abc894_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + abc890_t(mconfig, ABC894, "ABC 894", tag, owner, clock, "abc894", __FILE__) +{ +} + +abc850_t::abc850_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + abc890_t(mconfig, ABC850, "ABC 850", tag, owner, clock, "abc850", __FILE__) +{ +} + +abc852_t::abc852_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + abc890_t(mconfig, ABC852, "ABC 852", tag, owner, clock, "abc852", __FILE__) +{ +} + +abc856_t::abc856_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + abc890_t(mconfig, ABC856, "ABC 856", tag, owner, clock, "abc856", __FILE__) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void abc890_t::device_start() +{ +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void abc890_t::device_reset() +{ + for (device_t *device = first_subdevice(); device != NULL; device = device->next()) + { + device->reset(); + } +} + + +//------------------------------------------------- +// abcbus_cs - card select +//------------------------------------------------- + +void abc890_t::abcbus_cs(UINT8 data) +{ + abcbus_slot_device_iterator iter(*this); + + for (abcbus_slot_t *slot = iter.first(); slot != NULL; slot = iter.next()) + { + slot->cs_w(data); + } +} + + +//------------------------------------------------- +// abcbus_inp - input +//------------------------------------------------- + +UINT8 abc890_t::abcbus_inp() +{ + UINT8 data = 0xff; + + abcbus_slot_device_iterator iter(*this); + + for (abcbus_slot_t *slot = iter.first(); slot != NULL; slot = iter.next()) + { + data &= slot->inp_r(); + } + + return data; +} + + +//------------------------------------------------- +// abcbus_out - output +//------------------------------------------------- + +void abc890_t::abcbus_out(UINT8 data) +{ + abcbus_slot_device_iterator iter(*this); + + for (abcbus_slot_t *slot = iter.first(); slot != NULL; slot = iter.next()) + { + slot->out_w(data); + } +} + + +//------------------------------------------------- +// abcbus_stat - status +//------------------------------------------------- + +UINT8 abc890_t::abcbus_stat() +{ + UINT8 data = 0xff; + + abcbus_slot_device_iterator iter(*this); + + for (abcbus_slot_t *slot = iter.first(); slot != NULL; slot = iter.next()) + { + data &= slot->stat_r(); + } + + return data; +} + + +//------------------------------------------------- +// abcbus_c1 - command 1 +//------------------------------------------------- + +void abc890_t::abcbus_c1(UINT8 data) +{ + abcbus_slot_device_iterator iter(*this); + + for (abcbus_slot_t *slot = iter.first(); slot != NULL; slot = iter.next()) + { + slot->c1_w(data); + } +} + + +//------------------------------------------------- +// abcbus_c2 - command 2 +//------------------------------------------------- + +void abc890_t::abcbus_c2(UINT8 data) +{ + abcbus_slot_device_iterator iter(*this); + + for (abcbus_slot_t *slot = iter.first(); slot != NULL; slot = iter.next()) + { + slot->c2_w(data); + } +} + + +//------------------------------------------------- +// abcbus_c3 - command 3 +//------------------------------------------------- + +void abc890_t::abcbus_c3(UINT8 data) +{ + abcbus_slot_device_iterator iter(*this); + + for (abcbus_slot_t *slot = iter.first(); slot != NULL; slot = iter.next()) + { + slot->c3_w(data); + } +} + + +//------------------------------------------------- +// abcbus_c4 - command 4 +//------------------------------------------------- + +void abc890_t::abcbus_c4(UINT8 data) +{ + abcbus_slot_device_iterator iter(*this); + + for (abcbus_slot_t *slot = iter.first(); slot != NULL; slot = iter.next()) + { + slot->c4_w(data); + } +} + + +//------------------------------------------------- +// abcbus_xmemfl - extended memory read +//------------------------------------------------- + +UINT8 abc890_t::abcbus_xmemfl(offs_t offset) +{ + UINT8 data = 0xff; + + abcbus_slot_device_iterator iter(*this); + + for (abcbus_slot_t *slot = iter.first(); slot != NULL; slot = iter.next()) + { + data &= slot->xmemfl_r(offset); + } + + return data; +} + + +//------------------------------------------------- +// abcbus_xmemw - extended memory write +//------------------------------------------------- + +void abc890_t::abcbus_xmemw(offs_t offset, UINT8 data) +{ + abcbus_slot_device_iterator iter(*this); + + for (abcbus_slot_t *slot = iter.first(); slot != NULL; slot = iter.next()) + { + slot->xmemw_w(offset, data); + } +} diff --git a/src/devices/bus/abcbus/abc890.h b/src/devices/bus/abcbus/abc890.h new file mode 100644 index 00000000000..3c878bfa95c --- /dev/null +++ b/src/devices/bus/abcbus/abc890.h @@ -0,0 +1,130 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Luxor ABC 890 bus expander emulation + +*********************************************************************/ + +#pragma once + +#ifndef __ABC890__ +#define __ABC890__ + +#include "emu.h" +#include "abcbus.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> abc890_t + +class abc890_t : public device_t, + public device_abcbus_card_interface +{ +public: + // construction/destruction + abc890_t(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + abc890_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_abcbus_interface overrides + virtual void abcbus_cs(UINT8 data); + virtual UINT8 abcbus_inp(); + virtual void abcbus_out(UINT8 data); + virtual UINT8 abcbus_stat(); + virtual void abcbus_c1(UINT8 data); + virtual void abcbus_c2(UINT8 data); + virtual void abcbus_c3(UINT8 data); + virtual void abcbus_c4(UINT8 data); + virtual UINT8 abcbus_xmemfl(offs_t offset); + virtual void abcbus_xmemw(offs_t offset, UINT8 data); +}; + + +// ======================> abc_expansion_unit_t + +class abc_expansion_unit_t : public abc890_t +{ +public: + // construction/destruction + abc_expansion_unit_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; +}; + + +// ======================> abc894_t + +class abc894_t : public abc890_t +{ +public: + // construction/destruction + abc894_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; +}; + + +// ======================> abc850_t + +class abc850_t : public abc890_t +{ +public: + // construction/destruction + abc850_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; +}; + + +// ======================> abc852_t + +class abc852_t : public abc890_t +{ +public: + // construction/destruction + abc852_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; +}; + + +// ======================> abc856_t + +class abc856_t : public abc890_t +{ +public: + // construction/destruction + abc856_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; +}; + + +// device type definition +extern const device_type ABC_EXPANSION_UNIT; +extern const device_type ABC890; +extern const device_type ABC894; +extern const device_type ABC850; +extern const device_type ABC852; +extern const device_type ABC856; + + + +#endif diff --git a/src/devices/bus/abcbus/abcbus.c b/src/devices/bus/abcbus/abcbus.c new file mode 100644 index 00000000000..b5491e4e101 --- /dev/null +++ b/src/devices/bus/abcbus/abcbus.c @@ -0,0 +1,144 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Luxor ABC (Databoard 4680) Bus emulation + +**********************************************************************/ + +#include "abcbus.h" + + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type ABCBUS_SLOT = &device_creator; + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// device_abcbus_card_interface - constructor +//------------------------------------------------- + +device_abcbus_card_interface::device_abcbus_card_interface(const machine_config &mconfig, device_t &device) + : device_slot_card_interface(mconfig, device) +{ + m_slot = dynamic_cast(device.owner()); +} + + +//------------------------------------------------- +// abcbus_slot_t - constructor +//------------------------------------------------- + +abcbus_slot_t::abcbus_slot_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, ABCBUS_SLOT, "ABCBUS slot", tag, owner, clock, "abcbus_slot", __FILE__), + device_slot_interface(mconfig, *this), + m_write_irq(*this), + m_write_nmi(*this), + m_write_rdy(*this), + m_write_resin(*this), + m_write_pren(*this), + m_write_trrq(*this), + m_write_xint2(*this), + m_write_xint3(*this), + m_write_xint4(*this), + m_write_xint5(*this), + m_trrq(0) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void abcbus_slot_t::device_start() +{ + m_card = dynamic_cast(get_card_device()); + + // resolve callbacks + m_write_irq.resolve_safe(); + m_write_nmi.resolve_safe(); + m_write_rdy.resolve_safe(); + m_write_resin.resolve_safe(); + m_write_pren.resolve_safe(); + m_write_trrq.resolve_safe(); + m_write_xint2.resolve_safe(); + m_write_xint3.resolve_safe(); + m_write_xint4.resolve_safe(); + m_write_xint5.resolve_safe(); +} + + +// slot devices +#include "abc890.h" +#include "fd2.h" +#include "hdc.h" +#include "lux10828.h" +#include "lux21046.h" +#include "lux21056.h" +#include "lux4105.h" +#include "memcard.h" +#include "ram.h" +#include "sio.h" +#include "slutprov.h" +#include "turbo.h" +#include "uni800.h" + + + +//------------------------------------------------- +// SLOT_INTERFACE( abc80_cards ) +//------------------------------------------------- + +SLOT_INTERFACE_START( abc80_cards ) + SLOT_INTERFACE("fd2", ABC_FD2) + SLOT_INTERFACE("memcard", ABC_MEMORY_CARD) + SLOT_INTERFACE("abcexp", ABC_EXPANSION_UNIT) + SLOT_INTERFACE("16k", ABC80_16KB_RAM_CARD) + SLOT_INTERFACE("slow", LUXOR_55_10828) + SLOT_INTERFACE("abc830", ABC830) +SLOT_INTERFACE_END + + +//------------------------------------------------- +// SLOT_INTERFACE( abcbus_cards ) +//------------------------------------------------- + +SLOT_INTERFACE_START( abcbus_cards ) + SLOT_INTERFACE("abc830", ABC830) + SLOT_INTERFACE("abc832", ABC832) + SLOT_INTERFACE("abc834", ABC834) + SLOT_INTERFACE("abc838", ABC838) + SLOT_INTERFACE("abc850", ABC850) + SLOT_INTERFACE_INTERNAL("abc850fdd", ABC850_FLOPPY) + SLOT_INTERFACE("abc852", ABC852) + SLOT_INTERFACE("abc856", ABC856) + SLOT_INTERFACE("abc890", ABC890) + SLOT_INTERFACE("abc894", ABC894) + SLOT_INTERFACE("hdc", ABC_HDC) + SLOT_INTERFACE("sio", ABC_SIO) + SLOT_INTERFACE("slow", LUXOR_55_10828) + SLOT_INTERFACE("uni800", ABC_UNI800) + SLOT_INTERFACE("slutprov", ABC_SLUTPROV) + SLOT_INTERFACE("turbo", TURBO_KONTROLLER) + SLOT_INTERFACE("xebec", LUXOR_55_21056) +SLOT_INTERFACE_END + + +//------------------------------------------------- +// SLOT_INTERFACE( abc1600bus_cards ) +//------------------------------------------------- + +SLOT_INTERFACE_START( abc1600bus_cards ) + SLOT_INTERFACE("4105", LUXOR_4105) // SASI interface +// SLOT_INTERFACE("4077", LUXOR_4077) // Winchester controller +// SLOT_INTERFACE("4004", LUXOR_4004) // ICOM I/O (Z80, Z80PIO, Z80SIO/2, Z80CTC, 2 Z80DMAs, 2 PROMs, 64KB RAM) +SLOT_INTERFACE_END diff --git a/src/devices/bus/abcbus/abcbus.h b/src/devices/bus/abcbus/abcbus.h new file mode 100644 index 00000000000..cdfd436495d --- /dev/null +++ b/src/devices/bus/abcbus/abcbus.h @@ -0,0 +1,319 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Luxor ABC (Databoard 4680) Bus emulation + +********************************************************************** + + ABC 80 + + A B + -12 V <-- * 1 * --> -12V + 0 V --- * 2 * --- 0 V + RESIN_ --> * 3 * --> XMEMWR_ + 0 V --- * 4 * --> XMEMFL_ + INT_ --> * 5 * --> phi + D7 <-> * 6 * --- 0 V + D6 <-> * 7 * --- 0 V + D5 <-> * 8 * --- 0 V + D4 <-> * 9 * --- 0 V + D3 <-> * 10 * --- 0 V + D2 <-> * 11 * --- 0 V + D1 <-> * 12 * --- 0 V + D0 <-> * 13 * --- 0 V + * 14 * --> A15 + RST_ <-- * 15 * --> A14 + IN1 <-- * 16 * --> A13 + IN0 <-- * 17 * --> A12 + OUT5 <-- * 18 * --> A11 + OUT4 <-- * 19 * --> A10 + OUT3 <-- * 20 * --> A9 + OUT2 <-- * 21 * --> A8 + OUT0 <-- * 22 * --> A7 + OUT1 <-- * 23 * --> A6 + NMI_ --> * 24 * --> A5 + INP2_ <-- * 25 * --> A4 + XINPSTB_ <-- * 26 * --> A3 + XOUTPSTB_ <-- * 27 * --> A2 + XM_ --> * 28 * --> A1 + RFSH_ <-- * 29 * --> A0 + RDY --> * 30 * --> MEMRQ_ + +5 V <-- * 31 * --> +5 V + +12 V <-- * 32 * --> +12 V + + OUT 0 _OUT data output + OUT 1 _CS card select + OUT 2 _C1 command 1 + OUT 3 _C2 command 2 + OUT 4 _C3 command 3 + OUT 5 _C4 command 4 + + IN 0 _INP data input + IN 1 _STAT status in + IN 7 RST reset + +********************************************************************** + + ABC 1600 + + A B + -12 V --- * 1 * --- -12V + 0 V --- * 2 * --- 0 V + BPCLK* --- * 3 * --- BPCLK + 0 V --- * 4 * --- 0 V + INT* --- * 5 * --- 0 V + D7 --- * 6 * --- 0 V + D6 --- * 7 * --- + D5 --- * 8 * --- + D4 --- * 9 * --- + D3 --- * 10 * --- XINT*5^ + D2 --- * 11 * --- XINT*4^ + D1 --- * 12 * --- XINT*3^ + D0 --- * 13 * --- XINT*2^ + CSB* --- * 14 * --- XCSB*2^ + BRST* --- * 15 * --- XCSB*3^ + STAT* --- * 16 * --- XCSB*4^ + INP* --- * 17 * --- XCSB*5^ + C4* --- * 18 * --- + C3* --- * 19 * --- + C2* --- * 20 * --- + C1* --- * 21 * --- EXP*^ + OUT* --- * 22 * --- BUSEN*^ + CS* --- * 23 * --- DSTB* + NMI*^ --- * 24 * --- 0 V + OPS* --- * 25 * --- A4 + R/W* --- * 26 * --- A3 + TREN* --- * 27 * --- A2 + TRRQ* --- * 28 * --- A1 + PRAC* --- * 29 * --- A0 + PREN* --- * 30 * --- DIRW/R* + +5 V --- * 31 * --- +5 V + +12 V --- * 32 * --- +12 V + + ^ only connected on BUS0X + +**********************************************************************/ + +#pragma once + +#ifndef __ABCBUS__ +#define __ABCBUS__ + +#include "emu.h" + + +//************************************************************************** +// CONSTANTS +//************************************************************************** + +#define ABCBUS_TAG "bus" + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_ABCBUS_SLOT_ADD(_tag, _slot_intf, _def_slot) \ + MCFG_DEVICE_ADD(_tag, ABCBUS_SLOT, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) + + +#define MCFG_ABCBUS_SLOT_IRQ_CALLBACK(_irq) \ + downcast(device)->set_irq_callback(DEVCB_##_irq); + +#define MCFG_ABCBUS_SLOT_NMI_CALLBACK(_nmi) \ + downcast(device)->set_nmi_callback(DEVCB_##_nmi); + +#define MCFG_ABCBUS_SLOT_RDY_CALLBACK(_rdy) \ + downcast(device)->set_rdy_callback(DEVCB_##_rdy); + +#define MCFG_ABCBUS_SLOT_RESIN_CALLBACK(_resin) \ + downcast(device)->set_resin_callback(DEVCB_##_resin); + +#define MCFG_ABCBUS_SLOT_PREN_CALLBACK(_pren) \ + downcast(device)->set_pren_callback(DEVCB_##_pren); + +#define MCFG_ABCBUS_SLOT_TRRQ_CALLBACK(_trrq) \ + downcast(device)->set_trrq_callback(DEVCB_##_trrq); + +#define MCFG_ABCBUS_SLOT_XINT2_CALLBACK(_xint2) \ + downcast(device)->set_xint2_callback(DEVCB_##_xint2); + +#define MCFG_ABCBUS_SLOT_XINT3_CALLBACK(_xint3) \ + downcast(device)->set_xint3_callback(DEVCB_##_xint3); + +#define MCFG_ABCBUS_SLOT_XINT4_CALLBACK(_xint4) \ + downcast(device)->set_xint4_callback(DEVCB_##_xint4); + +#define MCFG_ABCBUS_SLOT_XINT5_CALLBACK(_xint5) \ + downcast(device)->set_xint5_callback(DEVCB_##_xint5); + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> device_abcbus_card_interface + +class abcbus_slot_t; + +class device_abcbus_card_interface : public device_slot_card_interface +{ +public: + // construction/destruction + device_abcbus_card_interface(const machine_config &mconfig, device_t &device); + + // required operation overrides + virtual void abcbus_cs(UINT8 data) = 0; + + // optional operation overrides + virtual UINT8 abcbus_inp() { return 0xff; }; + virtual void abcbus_out(UINT8 data) { }; + virtual UINT8 abcbus_stat() { return 0xff; }; + virtual void abcbus_c1(UINT8 data) { }; + virtual void abcbus_c2(UINT8 data) { }; + virtual void abcbus_c3(UINT8 data) { }; + virtual void abcbus_c4(UINT8 data) { }; + + // optional operation overrides for ABC 80 + virtual UINT8 abcbus_xmemfl(offs_t offset) { return 0xff; }; + virtual void abcbus_xmemw(offs_t offset, UINT8 data) { }; + + // optional operation overrides for ABC 1600 + virtual int abcbus_csb() { return 1; } + virtual UINT8 abcbus_ops() { return 0xff; }; + virtual void abcbus_tren(int state) { }; + virtual void abcbus_prac(int state) { }; + virtual UINT8 abcbus_exp() { return 0xff; }; + virtual int abcbus_xcsb2() { return 1; }; + virtual int abcbus_xcsb3() { return 1; }; + virtual int abcbus_xcsb4() { return 1; }; + virtual int abcbus_xcsb5() { return 1; }; + +public: + abcbus_slot_t *m_slot; +}; + + +// ======================> abcbus_slot_t + +class abcbus_slot_t : public device_t, + public device_slot_interface +{ +public: + // construction/destruction + abcbus_slot_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + template void set_irq_callback(_irq irq) { m_write_irq.set_callback(irq); } + template void set_nmi_callback(_nmi nmi) { m_write_nmi.set_callback(nmi); } + template void set_rdy_callback(_rdy rdy) { m_write_rdy.set_callback(rdy); } + template void set_resin_callback(_resin resin) { m_write_resin.set_callback(resin); } + template void set_pren_callback(_pren pren) { m_write_pren.set_callback(pren); } + template void set_trrq_callback(_trrq trrq) { m_write_trrq.set_callback(trrq); } + template void set_xint2_callback(_xint2 xint2) { m_write_xint2.set_callback(xint2); } + template void set_xint3_callback(_xint3 xint3) { m_write_xint3.set_callback(xint3); } + template void set_xint4_callback(_xint4 xint4) { m_write_xint4.set_callback(xint4); } + template void set_xint5_callback(_xint5 xint5) { m_write_xint5.set_callback(xint5); } + + // computer interface + void cs_w(UINT8 data) { if (m_card) m_card->abcbus_cs(data); } + UINT8 rst_r() { device_reset(); return 0xff; } + UINT8 inp_r() { return m_card ? m_card->abcbus_inp() : 0xff; } + void out_w(UINT8 data) { if (m_card) m_card->abcbus_out(data); } + UINT8 stat_r() { return m_card ? m_card->abcbus_stat() : 0xff; } + void c1_w(UINT8 data) { if (m_card) m_card->abcbus_c1(data); } + void c2_w(UINT8 data) { if (m_card) m_card->abcbus_c2(data); } + void c3_w(UINT8 data) { if (m_card) m_card->abcbus_c3(data); } + void c4_w(UINT8 data) { if (m_card) m_card->abcbus_c4(data); } + UINT8 xmemfl_r(offs_t offset) { return m_card ? m_card->abcbus_xmemfl(offset) : 0xff; } + void xmemw_w(offs_t offset, UINT8 data) { if (m_card) m_card->abcbus_xmemw(offset, data); } + DECLARE_READ_LINE_MEMBER( csb_r ) { return m_card ? m_card->abcbus_csb() : 1; } + UINT8 ops_r() { return m_card ? m_card->abcbus_ops() : 0xff; } + UINT8 exp_r() { return m_card ? m_card->abcbus_exp() : 0xff; } + DECLARE_READ_LINE_MEMBER( xcsb2_r ) { return m_card ? m_card->abcbus_xcsb2() : 1; } + DECLARE_READ_LINE_MEMBER( xcsb3_r ) { return m_card ? m_card->abcbus_xcsb3() : 1; } + DECLARE_READ_LINE_MEMBER( xcsb4_r ) { return m_card ? m_card->abcbus_xcsb4() : 1; } + DECLARE_READ_LINE_MEMBER( xcsb5_r ) { return m_card ? m_card->abcbus_xcsb5() : 1; } + DECLARE_WRITE_LINE_MEMBER( tren_w ) { if (m_card) m_card->abcbus_tren(state); } + DECLARE_WRITE_LINE_MEMBER( prac_w ) { if (m_card) m_card->abcbus_prac(state); } + + DECLARE_WRITE8_MEMBER( cs_w ) { cs_w(data); } + DECLARE_READ8_MEMBER( rst_r ) { return rst_r(); } + DECLARE_READ8_MEMBER( inp_r ) { return inp_r(); } + DECLARE_WRITE8_MEMBER( out_w ) { out_w(data); } + DECLARE_READ8_MEMBER( stat_r ) { return stat_r(); } + DECLARE_WRITE8_MEMBER( c1_w ) { c1_w(data); } + DECLARE_WRITE8_MEMBER( c2_w ) { c2_w(data); } + DECLARE_WRITE8_MEMBER( c3_w ) { c3_w(data); } + DECLARE_WRITE8_MEMBER( c4_w ) { c4_w(data); } + DECLARE_READ8_MEMBER( xmemfl_r ) { return xmemfl_r(offset); } + DECLARE_WRITE8_MEMBER( xmemw_w ) { xmemw_w(offset, data); } + + DECLARE_READ_LINE_MEMBER( irq_r ) { return m_irq; } + DECLARE_READ_LINE_MEMBER( nmi_r ) { return m_nmi; } + DECLARE_READ_LINE_MEMBER( pren_r ) { return m_pren; } + DECLARE_READ_LINE_MEMBER( trrq_r ) { return m_trrq; } + DECLARE_READ_LINE_MEMBER( xint2_r ) { return m_xint2; } + DECLARE_READ_LINE_MEMBER( xint3_r ) { return m_xint3; } + DECLARE_READ_LINE_MEMBER( xint4_r ) { return m_xint4; } + DECLARE_READ_LINE_MEMBER( xint5_r ) { return m_xint5; } + + // card interface + DECLARE_WRITE_LINE_MEMBER( irq_w ) { m_irq = state; m_write_irq(state); } + DECLARE_WRITE_LINE_MEMBER( nmi_w ) { m_nmi = state; m_write_nmi(state); } + DECLARE_WRITE_LINE_MEMBER( rdy_w ) { m_write_rdy(state); } + DECLARE_WRITE_LINE_MEMBER( resin_w ) { m_write_resin(state); } + DECLARE_WRITE_LINE_MEMBER( pren_w ) { m_pren = state; m_write_pren(state); } + DECLARE_WRITE_LINE_MEMBER( trrq_w ) { m_trrq = state; m_write_trrq(state); } + DECLARE_WRITE_LINE_MEMBER( xint2_w ) { m_xint2 = state; m_write_xint2(state); } + DECLARE_WRITE_LINE_MEMBER( xint3_w ) { m_xint3 = state; m_write_xint3(state); } + DECLARE_WRITE_LINE_MEMBER( xint4_w ) { m_xint4 = state; m_write_xint4(state); } + DECLARE_WRITE_LINE_MEMBER( xint5_w ) { m_xint5 = state; m_write_xint5(state); } + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset() { if (m_card) get_card_device()->reset(); } + + devcb_write_line m_write_irq; + devcb_write_line m_write_nmi; + devcb_write_line m_write_rdy; + devcb_write_line m_write_resin; + devcb_write_line m_write_pren; + devcb_write_line m_write_trrq; + devcb_write_line m_write_xint2; + devcb_write_line m_write_xint3; + devcb_write_line m_write_xint4; + devcb_write_line m_write_xint5; + + device_abcbus_card_interface *m_card; + + int m_irq; + int m_nmi; + int m_pren; + int m_trrq; + int m_xint2; + int m_xint3; + int m_xint4; + int m_xint5; +}; + + +// device type definition +extern const device_type ABCBUS_SLOT; + + +SLOT_INTERFACE_EXTERN( abc80_cards ); +SLOT_INTERFACE_EXTERN( abcbus_cards ); +SLOT_INTERFACE_EXTERN( abc1600bus_cards ); + + +typedef device_type_iterator<&device_creator, abcbus_slot_t> abcbus_slot_device_iterator; + + + + +#endif diff --git a/src/devices/bus/abcbus/fd2.c b/src/devices/bus/abcbus/fd2.c new file mode 100644 index 00000000000..7faeefb97c4 --- /dev/null +++ b/src/devices/bus/abcbus/fd2.c @@ -0,0 +1,432 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Scandia Metric ABC FD2 floppy controller emulation + +*********************************************************************/ + +/* + +PCB Layout +---------- + + |-------------------------------------------| +|-| | +|-| ROM0 4MHz | +|-| | +|-| Z80PIO | +|-| CN1| +|-| FD1771 2114 | +|-| 2114 | +|-| Z80 ROM1 | +|-| | + |-------------------------------------------| + +Notes: + Relevant IC's shown. + + ROM0 - AMI 8005SAJ 1Kx8 EPROM + ROM1 - Motorola MCM2708C 1Kx8 EPROM + Z80 - Zilog Z-80 CPU + Z80PIO - Zilog Z-80A PIO + FD1771 - FD1771-B01 + 2114 - National Semiconductor MM2114N 1Kx4 Static RAM + CN1 - 2x17 pin PCB header + +*/ + +#include "fd2.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define Z80_TAG "2e" +#define Z80PIO_TAG "2c" +#define FD1771_TAG "2d" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type ABC_FD2 = &device_creator; + + +//------------------------------------------------- +// ROM( abc_fd2 ) +//------------------------------------------------- + +ROM_START( abc_fd2 ) + ROM_REGION( 0x1000, "dos", 0 ) + ROM_LOAD( "ami 8005saj.1a", 0x000, 0x800, CRC(d865213f) SHA1(ae7399ede74520ccb2dd5be2e6bb13c33ee81bd0) ) // what's this? + ROM_LOAD( "abcdos.3d", 0x0000, 0x1000, CRC(2cb2192f) SHA1(a6b3a9587714f8db807c05bee6c71c0684363744) ) + + ROM_REGION( 0x400, Z80_TAG, 0 ) + ROM_LOAD( "1.02.3f", 0x000, 0x400, CRC(a19fbdc2) SHA1(d500377c34ac6c679c155f4a5208e1c3e00cd920) ) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *abc_fd2_t::device_rom_region() const +{ + return ROM_NAME( abc_fd2 ); +} + + +//------------------------------------------------- +// status_w - +//------------------------------------------------- + +WRITE8_MEMBER( abc_fd2_t::status_w ) +{ + /* + + bit description + + 0 _INT to main Z80 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + + */ + + m_status = data & 0xfe; + + // interrupt + m_slot->irq_w(BIT(data, 0) ? ASSERT_LINE : CLEAR_LINE); +} + + +//------------------------------------------------- +// ADDRESS_MAP( abc_fd2_mem ) +//------------------------------------------------- + +static ADDRESS_MAP_START( abc_fd2_mem, AS_PROGRAM, 8, abc_fd2_t ) + AM_RANGE(0x0000, 0x03ff) AM_ROM AM_REGION(Z80_TAG, 0) + AM_RANGE(0x0800, 0x0bff) AM_RAM +ADDRESS_MAP_END + + +//------------------------------------------------- +// ADDRESS_MAP( abc_fd2_io ) +//------------------------------------------------- + +static ADDRESS_MAP_START( abc_fd2_io, AS_IO, 8, abc_fd2_t ) + ADDRESS_MAP_GLOBAL_MASK(0x73) + AM_RANGE(0x30, 0x33) AM_DEVREADWRITE(Z80PIO_TAG, z80pio_device, read_alt, write_alt) + AM_RANGE(0x50, 0x53) AM_DEVREADWRITE(FD1771_TAG, fd1771_t, read, write) + AM_RANGE(0x60, 0x60) AM_WRITE(status_w) +ADDRESS_MAP_END + + +//------------------------------------------------- +// Z80PIO +//------------------------------------------------- + +READ8_MEMBER( abc_fd2_t::pio_pa_r ) +{ + return m_data; +} + +WRITE8_MEMBER( abc_fd2_t::pio_pa_w ) +{ + m_data = data; +} + +READ8_MEMBER( abc_fd2_t::pio_pb_r ) +{ + /* + + bit description + + 0 + 1 + 2 + 3 + 4 + 5 DRQ + 6 HLD + 7 INTRQ + + */ + + UINT8 data = 0; + + data |= m_fdc->drq_r() << 5; + data |= m_fdc->hld_r() << 6; + data |= m_fdc->intrq_r() << 7; + + return data; +} + +WRITE8_MEMBER( abc_fd2_t::pio_pb_w ) +{ + /* + + bit description + + 0 SEL1 + 1 SEL2 + 2 TG43 + 3 MON + 4 HLT + 5 + 6 + 7 + + */ + + floppy_image_device *floppy = NULL; + + if (BIT(data, 0)) floppy = m_floppy0->get_device(); + if (BIT(data, 1)) floppy = m_floppy1->get_device(); + + m_fdc->set_floppy(floppy); + + if (floppy) + { + // motor enable + floppy->mon_w(BIT(data, 3)); + } + + m_fdc->hlt_w(BIT(data, 4)); +} + + +//------------------------------------------------- +// z80_daisy_config daisy_chain +//------------------------------------------------- + +static const z80_daisy_config daisy_chain[] = +{ + { Z80PIO_TAG }, + { NULL } +}; + + +//------------------------------------------------- +// SLOT_INTERFACE( abc_fd2_floppies ) +//------------------------------------------------- + +static SLOT_INTERFACE_START( abc_fd2_floppies ) + SLOT_INTERFACE( "525sssd", FLOPPY_525_SSSD ) +SLOT_INTERFACE_END + +FLOPPY_FORMATS_MEMBER( abc_fd2_t::floppy_formats ) + FLOPPY_ABC_FD2_FORMAT +FLOPPY_FORMATS_END + + +//------------------------------------------------- +// MACHINE_DRIVER( abc_fd2 ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( abc_fd2 ) + MCFG_CPU_ADD(Z80_TAG, Z80, XTAL_4MHz/2) + MCFG_CPU_PROGRAM_MAP(abc_fd2_mem) + MCFG_CPU_IO_MAP(abc_fd2_io) + MCFG_CPU_CONFIG(daisy_chain) + + MCFG_DEVICE_ADD(Z80PIO_TAG, Z80PIO, XTAL_4MHz/2) + MCFG_Z80PIO_OUT_INT_CB(INPUTLINE(Z80_TAG, INPUT_LINE_IRQ0)) + MCFG_Z80PIO_IN_PA_CB(READ8(abc_fd2_t, pio_pa_r)) + MCFG_Z80PIO_OUT_PA_CB(WRITE8(abc_fd2_t, pio_pa_w)) + MCFG_Z80PIO_IN_PB_CB(READ8(abc_fd2_t, pio_pb_r)) + MCFG_Z80PIO_OUT_PB_CB(WRITE8(abc_fd2_t, pio_pb_w)) + + MCFG_FD1771_ADD(FD1771_TAG, XTAL_4MHz/4) + MCFG_WD_FDC_INTRQ_CALLBACK(DEVWRITELINE(Z80PIO_TAG, z80pio_device, pb7_w)) + MCFG_WD_FDC_DRQ_CALLBACK(DEVWRITELINE(Z80PIO_TAG, z80pio_device, pb5_w)) + MCFG_WD_FDC_HLD_CALLBACK(DEVWRITELINE(Z80PIO_TAG, z80pio_device, pb6_w)) + + MCFG_FLOPPY_DRIVE_ADD(FD1771_TAG ":0", abc_fd2_floppies, "525sssd", abc_fd2_t::floppy_formats) + MCFG_FLOPPY_DRIVE_ADD(FD1771_TAG ":1", abc_fd2_floppies, "525sssd", abc_fd2_t::floppy_formats) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor abc_fd2_t::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( abc_fd2 ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// abc_fd2_t - constructor +//------------------------------------------------- + +abc_fd2_t::abc_fd2_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, ABC_FD2, "ABC FD2", tag, owner, clock, "abc_fd2", __FILE__), + device_abcbus_card_interface(mconfig, *this), + m_maincpu(*this, Z80_TAG), + m_pio(*this, Z80PIO_TAG), + m_fdc(*this, FD1771_TAG), + m_floppy0(*this, FD1771_TAG ":0"), + m_floppy1(*this, FD1771_TAG ":1"), + m_dos_rom(*this, "dos"), + m_cs(false) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void abc_fd2_t::device_start() +{ +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void abc_fd2_t::device_reset() +{ + m_cs = false; + + m_status = 0; + m_slot->irq_w(CLEAR_LINE); + + m_maincpu->reset(); + m_fdc->soft_reset(); +} + + + +//************************************************************************** +// ABC BUS INTERFACE +//************************************************************************** + +//------------------------------------------------- +// abcbus_cs - +//------------------------------------------------- + +void abc_fd2_t::abcbus_cs(UINT8 data) +{ + m_cs = (data == 0x2d); +} + + +//------------------------------------------------- +// abcbus_stat - +//------------------------------------------------- + +UINT8 abc_fd2_t::abcbus_stat() +{ + UINT8 data = 0xff; + + if (m_cs) + { + data = (m_status & 0xfe) | m_pio->rdy_a(); + } + + return data; +} + + +//------------------------------------------------- +// abcbus_inp - +//------------------------------------------------- + +UINT8 abc_fd2_t::abcbus_inp() +{ + UINT8 data = 0xff; + + if (m_cs) + { + if (!BIT(m_status, 6)) + { + data = m_data; + } + + m_pio->strobe_a(0); + m_pio->strobe_a(1); + } + + return data; +} + + +//------------------------------------------------- +// abcbus_out - +//------------------------------------------------- + +void abc_fd2_t::abcbus_out(UINT8 data) +{ + if (!m_cs) return; + + if (BIT(m_status, 6)) + { + m_data = data; + } + + m_pio->strobe_a(0); + m_pio->strobe_a(1); +} + + +//------------------------------------------------- +// abcbus_c1 - +//------------------------------------------------- + +void abc_fd2_t::abcbus_c1(UINT8 data) +{ + if (m_cs) + { + m_maincpu->set_input_line(INPUT_LINE_NMI, ASSERT_LINE); + m_maincpu->set_input_line(INPUT_LINE_NMI, CLEAR_LINE); + } +} + + +//------------------------------------------------- +// abcbus_c3 - +//------------------------------------------------- + +void abc_fd2_t::abcbus_c3(UINT8 data) +{ + if (m_cs) + { + device_reset(); + } +} + + +//------------------------------------------------- +// abcbus_xmemfl - +//------------------------------------------------- + +UINT8 abc_fd2_t::abcbus_xmemfl(offs_t offset) +{ + UINT8 data = 0xff; + + if ((offset & 0xf000) == 0x6000) + { + data = m_dos_rom->base()[offset & 0xfff]; + } + + return data; +} diff --git a/src/devices/bus/abcbus/fd2.h b/src/devices/bus/abcbus/fd2.h new file mode 100644 index 00000000000..ef183e92843 --- /dev/null +++ b/src/devices/bus/abcbus/fd2.h @@ -0,0 +1,83 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Scandia Metric ABC FD2 floppy controller emulation + +*********************************************************************/ + +#pragma once + +#ifndef __ABC_FD2__ +#define __ABC_FD2__ + +#include "emu.h" +#include "abcbus.h" +#include "cpu/z80/z80.h" +#include "cpu/z80/z80daisy.h" +#include "formats/abcfd2_dsk.h" +#include "machine/wd_fdc.h" +#include "machine/z80pio.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> abc_fd2_t + +class abc_fd2_t : public device_t, + public device_abcbus_card_interface +{ +public: + // construction/destruction + abc_fd2_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + + DECLARE_WRITE8_MEMBER( status_w ); + + DECLARE_READ8_MEMBER( pio_pa_r ); + DECLARE_WRITE8_MEMBER( pio_pa_w ); + DECLARE_READ8_MEMBER( pio_pb_r ); + DECLARE_WRITE8_MEMBER( pio_pb_w ); + + DECLARE_FLOPPY_FORMATS( floppy_formats ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_abcbus_interface overrides + virtual void abcbus_cs(UINT8 data); + virtual UINT8 abcbus_inp(); + virtual void abcbus_out(UINT8 data); + virtual UINT8 abcbus_stat(); + virtual void abcbus_c1(UINT8 data); + virtual void abcbus_c3(UINT8 data); + virtual UINT8 abcbus_xmemfl(offs_t offset); + +private: + required_device m_maincpu; + required_device m_pio; + required_device m_fdc; + required_device m_floppy0; + required_device m_floppy1; + required_memory_region m_dos_rom; + + bool m_cs; + UINT8 m_status; + UINT8 m_data; +}; + + +// device type definition +extern const device_type ABC_FD2; + + + +#endif diff --git a/src/devices/bus/abcbus/hdc.c b/src/devices/bus/abcbus/hdc.c new file mode 100644 index 00000000000..628fbcb2d7d --- /dev/null +++ b/src/devices/bus/abcbus/hdc.c @@ -0,0 +1,151 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Luxor XEBEC Winchester controller card emulation + +*********************************************************************/ + +#include "hdc.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define Z80_TAG "z80" +#define SASIBUS_TAG "sasi" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type ABC_HDC = &device_creator; + + +//------------------------------------------------- +// ROM( abc_hdc ) +//------------------------------------------------- + +ROM_START( abc_hdc ) + ROM_REGION( 0x800, Z80_TAG, 0 ) + ROM_SYSTEM_BIOS( 0, "st4038", "Seagate ST4038 (CHS: 733,5,17,512)" ) + ROMX_LOAD( "st4038.6c", 0x000, 0x800, CRC(4c803b87) SHA1(1141bb51ad9200fc32d92a749460843dc6af8953), ROM_BIOS(1) ) // Seagate ST4038 (http://stason.org/TULARC/pc/hard-drives-hdd/seagate/ST4038-1987-31MB-5-25-FH-MFM-ST412.html) + ROM_SYSTEM_BIOS( 1, "st225", "Seagate ST225 (CHS: 615,4,17,512)" ) + ROMX_LOAD( "st225.6c", 0x000, 0x800, CRC(c9f68f81) SHA1(7ff8b2a19f71fe0279ab3e5a0a5fffcb6030360c), ROM_BIOS(2) ) // Seagate ST225 (http://stason.org/TULARC/pc/hard-drives-hdd/seagate/ST225-21MB-5-25-HH-MFM-ST412.html) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *abc_hdc_device::device_rom_region() const +{ + return ROM_NAME( abc_hdc ); +} + + +//------------------------------------------------- +// ADDRESS_MAP( abc_hdc_mem ) +//------------------------------------------------- + +static ADDRESS_MAP_START( abc_hdc_mem, AS_PROGRAM, 8, abc_hdc_device ) + AM_RANGE(0x0000, 0x0ff) AM_ROM AM_REGION(Z80_TAG, 0) +ADDRESS_MAP_END + + +//------------------------------------------------- +// ADDRESS_MAP( abc_hdc_io ) +//------------------------------------------------- + +static ADDRESS_MAP_START( abc_hdc_io, AS_IO, 8, abc_hdc_device ) +ADDRESS_MAP_END + + +//------------------------------------------------- +// z80_daisy_config daisy_chain +//------------------------------------------------- + +static const z80_daisy_config daisy_chain[] = +{ + { NULL } +}; + + +//------------------------------------------------- +// MACHINE_DRIVER( abc_hdc ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( abc_hdc ) + MCFG_CPU_ADD(Z80_TAG, Z80, 4000000) + MCFG_CPU_PROGRAM_MAP(abc_hdc_mem) + MCFG_CPU_IO_MAP(abc_hdc_io) + MCFG_CPU_CONFIG(daisy_chain) + + MCFG_DEVICE_ADD(SASIBUS_TAG, SCSI_PORT, 0) + MCFG_SCSIDEV_ADD(SASIBUS_TAG ":" SCSI_PORT_DEVICE1, "harddisk", SCSIHD, SCSI_ID_0) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor abc_hdc_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( abc_hdc ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// abc_hdc_device - constructor +//------------------------------------------------- + +abc_hdc_device::abc_hdc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, ABC_HDC, "ABC HDC", tag, owner, clock, "abc_hdc", __FILE__), + device_abcbus_card_interface(mconfig, *this), + m_maincpu(*this, Z80_TAG) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void abc_hdc_device::device_start() +{ +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void abc_hdc_device::device_reset() +{ +} + + + +//************************************************************************** +// ABC BUS INTERFACE +//************************************************************************** + +//------------------------------------------------- +// abcbus_cs - +//------------------------------------------------- + +void abc_hdc_device::abcbus_cs(UINT8 data) +{ +} diff --git a/src/devices/bus/abcbus/hdc.h b/src/devices/bus/abcbus/hdc.h new file mode 100644 index 00000000000..cebe7619174 --- /dev/null +++ b/src/devices/bus/abcbus/hdc.h @@ -0,0 +1,57 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Luxor XEBEC Winchester controller card emulation + +*********************************************************************/ + +#pragma once + +#ifndef __ABC_HDC__ +#define __ABC_HDC__ + +#include "emu.h" +#include "abcbus.h" +#include "cpu/z80/z80.h" +#include "cpu/z80/z80daisy.h" +#include "bus/scsi/scsihd.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> abc_hdc_device + +class abc_hdc_device : public device_t, + public device_abcbus_card_interface +{ +public: + // construction/destruction + abc_hdc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_abcbus_interface overrides + virtual void abcbus_cs(UINT8 data); + +private: + required_device m_maincpu; +}; + + +// device type definition +extern const device_type ABC_HDC; + + + +#endif diff --git a/src/devices/bus/abcbus/lux10828.c b/src/devices/bus/abcbus/lux10828.c new file mode 100644 index 00000000000..705a9e8035b --- /dev/null +++ b/src/devices/bus/abcbus/lux10828.c @@ -0,0 +1,678 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Luxor 55-10828 "slow" floppy disk controller emulation + +*********************************************************************/ + +/* + +Luxor Conkort + +PCB Layout +---------- + +55 10900-01 + +|-----------------------------------| +| LD1 SW1 LS132 CON2 | +| S | +| 4MHz S240 N8T97N | +| S | +| 7404 MC1458 4024 | +| S | +| 74276 S | +| S S | +| LS32 S C140E LS273 | +| | +| | +| MB8876 ROM | +| | +| | +| S LS32 LS156 TC5514 | +| | +| TC5514 | +| Z80 | +| LS273 | +| | +| LS373 | +| Z80PIO | +| LS245 | +| S1 | +| LS125 LS124 S20 DM8131 | +| | +|--|-----------------------------|--| + |------------CON1-------------| + +Notes: + All IC's shown. + + ROM - Hitachi HN462716 2Kx8 EPROM "MPI02" + Z80 - Sharp LH0080A Z80A CPU + Z80PIO - SGS Z8420AB1 Z80A PIO + MB8876 - Mitsubishi MB8876 Floppy Disc Controller (FD1791 compatible) + TC5514 - Toshiba TC5514AP-2 1Kx4 bit Static RAM + DM8131 - National Semiconductor DM8131N 6-Bit Unified Bus Comparator + C140E - Ferranti 2C140E "copy protection device" + N8T97N - SA N8T97N ? + CON1 - ABC bus connector + CON2 - 25-pin D sub floppy connector (AMP4284) + SW1 - Disk drive type (SS/DS, SD/DD) + S1 - ABC bus card address bit 0 + S2 - + S3 - + S4 - + S5 - + S6 - + S7 - + S8 - + S9 - + LD1 - LED + +*/ + +/* + + TODO: + + - Z80 IN instruction needs to halt in mid air for this controller to ever work (the first data byte of disk sector is read too early) + + wd17xx_command_w $88 READ_SEC + wd17xx_data_r: (no new data) $00 (data_count 0) + WAIT + wd179x: Read Sector callback. + sector found! C:$00 H:$00 R:$0b N:$01 + wd17xx_data_r: $FF (data_count 256) + WAIT + + - copy protection device (sends sector header bytes to CPU? DDEN is serial clock? code checks for either $b6 or $f7) + + 06F8: ld a,$2F ; SEEK + 06FA: out ($BC),a + 06FC: push af + 06FD: push bc + 06FE: ld bc,$0724 + 0701: push bc + 0702: ld b,$07 + 0704: rr a + 0706: call $073F + 073F: DB 7E in a,($7E) ; PIO PORT B + 0741: EE 08 xor $08 ; DDEN + 0743: D3 7E out ($7E),a + 0745: EE 08 xor $08 + 0747: D3 7E out ($7E),a + 0749: DB 7E in a,($7E) + 074B: 1F rra + 074C: 1F rra + 074D: 1F rra + 074E: CB 11 rl c + 0750: 79 ld a,c + 0751: C9 ret + 0709: djnz $0703 <-- jumps to middle of instruction! + 0703: rlca + 0704: rr a + 0706: call $073F + + - S2-S5 jumpers + - ABC80 ERR 48 on boot + - side select makes controller go crazy and try to WRITE_TRK + +*/ + +#include "lux10828.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define Z80_TAG "5a" +#define Z80PIO_TAG "3a" +#define MB8876_TAG "7a" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type LUXOR_55_10828 = &device_creator; + + +//------------------------------------------------- +// ROM( luxor_55_10828 ) +//------------------------------------------------- + +ROM_START( luxor_55_10828 ) + ROM_REGION( 0x800, Z80_TAG, 0 ) + ROM_DEFAULT_BIOS("mpi02n") + // ABC 830 + ROM_SYSTEM_BIOS( 0, "basf6106", "BASF 6106/08" ) + ROMX_LOAD( "basf .02.7c", 0x000, 0x800, CRC(5daba200) SHA1(7881933760bed3b94f27585c0a6fc43e5d5153f5), ROM_BIOS(1) ) + ROM_SYSTEM_BIOS( 1, "mpi02", "MPI 51" ) + ROMX_LOAD( "mpi .02.7c", 0x000, 0x800, CRC(2aac9296) SHA1(c01a62e7933186bdf7068d2e9a5bc36590544349), ROM_BIOS(2) ) + ROM_SYSTEM_BIOS( 2, "mpi02n", "MPI 51 (newer)" ) + ROMX_LOAD( "new mpi .02.7c", 0x000, 0x800, CRC(ab788171) SHA1(c8e29965c04c85f2f2648496ea10c9c7ff95392f), ROM_BIOS(3) ) + // ABC 832 + ROM_SYSTEM_BIOS( 3, "micr1015", "Micropolis 1015 (v1.4)" ) + ROMX_LOAD( "micr 1.4.7c", 0x000, 0x800, CRC(a7bc05fa) SHA1(6ac3e202b7ce802c70d89728695f1cb52ac80307), ROM_BIOS(4) ) + ROM_SYSTEM_BIOS( 4, "micr1115", "Micropolis 1115 (v2.3)" ) + ROMX_LOAD( "micr 2.3.7c", 0x000, 0x800, CRC(f2fc5ccc) SHA1(86d6baadf6bf1d07d0577dc1e092850b5ff6dd1b), ROM_BIOS(5) ) + ROM_SYSTEM_BIOS( 5, "basf6118", "BASF 6118 (v1.2)" ) + ROMX_LOAD( "basf 1.2.7c", 0x000, 0x800, CRC(9ca1a1eb) SHA1(04973ad69de8da403739caaebe0b0f6757e4a6b1), ROM_BIOS(6) ) + // ABC 838 + ROM_SYSTEM_BIOS( 6, "basf6104", "BASF 6104, BASF 6115 (v1.0)" ) + ROMX_LOAD( "basf 8 1.0.7c", 0x000, 0x800, NO_DUMP, ROM_BIOS(7) ) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *luxor_55_10828_device::device_rom_region() const +{ + return ROM_NAME( luxor_55_10828 ); +} + + +//------------------------------------------------- +// ADDRESS_MAP( luxor_55_10828_mem ) +//------------------------------------------------- + +static ADDRESS_MAP_START( luxor_55_10828_mem, AS_PROGRAM, 8, luxor_55_10828_device ) + ADDRESS_MAP_GLOBAL_MASK(0x1fff) + AM_RANGE(0x0000, 0x07ff) AM_MIRROR(0x0800) AM_ROM AM_REGION(Z80_TAG, 0) + AM_RANGE(0x1000, 0x13ff) AM_MIRROR(0x0c00) AM_RAM +ADDRESS_MAP_END + + +//------------------------------------------------- +// ADDRESS_MAP( luxor_55_10828_io ) +//------------------------------------------------- + +static ADDRESS_MAP_START( luxor_55_10828_io, AS_IO, 8, luxor_55_10828_device ) + ADDRESS_MAP_GLOBAL_MASK(0xff) + AM_RANGE(0x70, 0x73) AM_MIRROR(0x0c) AM_DEVREADWRITE(Z80PIO_TAG, z80pio_device, read_alt, write_alt) + AM_RANGE(0xb0, 0xb3) AM_MIRROR(0x0c) AM_READWRITE(fdc_r, fdc_w) + AM_RANGE(0xd0, 0xd0) AM_MIRROR(0x0f) AM_WRITE(status_w) + AM_RANGE(0xe0, 0xe0) AM_MIRROR(0x0f) AM_WRITE(ctrl_w) +ADDRESS_MAP_END + + +//------------------------------------------------- +// Z80PIO +//------------------------------------------------- + +READ8_MEMBER( luxor_55_10828_device::pio_pa_r ) +{ + return m_data; +} + +WRITE8_MEMBER( luxor_55_10828_device::pio_pa_w ) +{ + m_data = data; +} + +READ8_MEMBER( luxor_55_10828_device::pio_pb_r ) +{ + /* + + bit description + + 0 !(_DS0 & _DS1) single/double sided (0=SS, 1=DS) + 1 !(_DD0 & _DD1) single/double density (0=DS, 1=DD) + 2 8B pin 10 + 3 FDC _DDEN double density enable + 4 _R/BS radial/binary drive select + 5 FDC HLT head load timing + 6 FDC _HDLD head loaded + 7 FDC IRQ interrupt request + + */ + + UINT8 data = 0x04; + + // single/double sided drive + UINT8 sw1 = m_sw1->read() & 0x0f; + int ds0 = m_sel0 ? BIT(sw1, 0) : 1; + int ds1 = m_sel1 ? BIT(sw1, 1) : 1; + data |= !(ds0 & ds1); + + // single/double density drive + int dd0 = m_sel0 ? BIT(sw1, 2) : 1; + int dd1 = m_sel1 ? BIT(sw1, 3) : 1; + data |= !(dd0 & dd1) << 1; + + // radial/binary drive select + data |= 0x10; + + // head load + data |= m_fdc->hld_r() << 6; + data |= 0x40; // TODO remove + + // FDC interrupt request + data |= m_fdc_irq << 7; + + return data; +} + +WRITE8_MEMBER( luxor_55_10828_device::pio_pb_w ) +{ + /* + + bit signal description + + 0 !(_DS0 & _DS1) single/double sided (0=SS, 1=DS) + 1 !(_DD0 & _DD1) single/double density (0=DS, 1=DD) + 2 8B pin 10 + 3 FDC _DDEN double density enable + 4 _R/BS radial/binary drive select + 5 FDC HLT head load timing + 6 FDC _HDLD head loaded + 7 FDC IRQ interrupt request + + */ + + // double density enable + m_fdc->dden_w(BIT(data, 3)); + + // head load timing + m_fdc->hlt_w(BIT(data, 5)); +} + +//------------------------------------------------- +// z80_daisy_config daisy_chain +//------------------------------------------------- + +static const z80_daisy_config daisy_chain[] = +{ + { Z80PIO_TAG }, + { NULL } +}; + +static SLOT_INTERFACE_START( abc_floppies ) + SLOT_INTERFACE( "525sssd", FLOPPY_525_SSSD ) + SLOT_INTERFACE( "525sd", FLOPPY_525_SD ) + SLOT_INTERFACE( "525ssdd", FLOPPY_525_SSDD ) + SLOT_INTERFACE( "525dd", FLOPPY_525_DD ) + SLOT_INTERFACE( "8dsdd", FLOPPY_8_DSDD ) +SLOT_INTERFACE_END + +FLOPPY_FORMATS_MEMBER( luxor_55_10828_device::floppy_formats ) + FLOPPY_ABC800_FORMAT +FLOPPY_FORMATS_END + +WRITE_LINE_MEMBER( luxor_55_10828_device::fdc_intrq_w ) +{ + m_fdc_irq = state; + m_pio->port_b_write(state << 7); + + if (state) m_maincpu->set_input_line(Z80_INPUT_LINE_WAIT, CLEAR_LINE); +} + +WRITE_LINE_MEMBER( luxor_55_10828_device::fdc_drq_w ) +{ + m_fdc_drq = state; + + if (state) m_maincpu->set_input_line(Z80_INPUT_LINE_WAIT, CLEAR_LINE); +} + + +//------------------------------------------------- +// MACHINE_DRIVER( luxor_55_10828 ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( luxor_55_10828 ) + MCFG_CPU_ADD(Z80_TAG, Z80, XTAL_4MHz/2) + MCFG_CPU_PROGRAM_MAP(luxor_55_10828_mem) + MCFG_CPU_IO_MAP(luxor_55_10828_io) + MCFG_CPU_CONFIG(daisy_chain) + + MCFG_DEVICE_ADD(Z80PIO_TAG, Z80PIO, XTAL_4MHz/2) + MCFG_Z80PIO_OUT_INT_CB(INPUTLINE(Z80_TAG, INPUT_LINE_IRQ0)) + MCFG_Z80PIO_IN_PA_CB(READ8(luxor_55_10828_device, pio_pa_r)) + MCFG_Z80PIO_OUT_PA_CB(WRITE8(luxor_55_10828_device, pio_pa_w)) + MCFG_Z80PIO_IN_PB_CB(READ8(luxor_55_10828_device, pio_pb_r)) + MCFG_Z80PIO_OUT_PB_CB(WRITE8(luxor_55_10828_device, pio_pb_w)) + + MCFG_MB8876_ADD(MB8876_TAG, XTAL_4MHz/2) + MCFG_WD_FDC_INTRQ_CALLBACK(WRITELINE(luxor_55_10828_device, fdc_intrq_w)) + MCFG_WD_FDC_DRQ_CALLBACK(WRITELINE(luxor_55_10828_device, fdc_drq_w)) + + MCFG_FLOPPY_DRIVE_ADD(MB8876_TAG":0", abc_floppies, "525dd", luxor_55_10828_device::floppy_formats) + MCFG_FLOPPY_DRIVE_ADD(MB8876_TAG":1", abc_floppies, "525dd", luxor_55_10828_device::floppy_formats) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor luxor_55_10828_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( luxor_55_10828 ); +} + + +//------------------------------------------------- +// INPUT_PORTS( luxor_55_10828 ) +//------------------------------------------------- + +INPUT_PORTS_START( luxor_55_10828 ) + PORT_START("SW1") + PORT_DIPNAME( 0x01, 0x01, "Drive 0 Sided" ) PORT_DIPLOCATION("SW1:1") + PORT_DIPSETTING( 0x01, DEF_STR( Single ) ) + PORT_DIPSETTING( 0x00, "Double" ) + PORT_DIPNAME( 0x02, 0x02, "Drive 1 Sided" ) PORT_DIPLOCATION("SW1:2") + PORT_DIPSETTING( 0x02, DEF_STR( Single ) ) + PORT_DIPSETTING( 0x00, "Double" ) + PORT_DIPNAME( 0x04, 0x00, "Drive 0 Density" ) PORT_DIPLOCATION("SW1:3") + PORT_DIPSETTING( 0x04, DEF_STR( Single ) ) + PORT_DIPSETTING( 0x00, "Double" ) + PORT_DIPNAME( 0x08, 0x00, "Drive 1 Density" ) PORT_DIPLOCATION("SW1:4") + PORT_DIPSETTING( 0x08, DEF_STR( Single ) ) + PORT_DIPSETTING( 0x00, "Double" ) + + PORT_START("S1") + PORT_DIPNAME( 0x01, 0x01, "Card Address" ) PORT_DIPLOCATION("S1:1") + PORT_DIPSETTING( 0x00, "44 (ABC 832/834/850)" ) + PORT_DIPSETTING( 0x01, "45 (ABC 830)" ) +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor luxor_55_10828_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( luxor_55_10828 ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// luxor_55_10828_device - constructor +//------------------------------------------------- + +luxor_55_10828_device::luxor_55_10828_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, LUXOR_55_10828, "Luxor 55 10828", tag, owner, clock, "lux10828", __FILE__), + device_abcbus_card_interface(mconfig, *this), + m_maincpu(*this, Z80_TAG), + m_pio(*this, Z80PIO_TAG), + m_fdc(*this, MB8876_TAG), + m_floppy0(*this, MB8876_TAG":0"), + m_floppy1(*this, MB8876_TAG":1"), + m_sw1(*this, "SW1"), + m_s1(*this, "S1"), + m_cs(false), + m_fdc_irq(0), + m_fdc_drq(0), + m_wait_enable(0), + m_sel0(0), + m_sel1(0) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void luxor_55_10828_device::device_start() +{ + // state saving + save_item(NAME(m_cs)); + save_item(NAME(m_status)); + save_item(NAME(m_data)); + save_item(NAME(m_fdc_irq)); + save_item(NAME(m_fdc_drq)); + save_item(NAME(m_wait_enable)); + save_item(NAME(m_sel0)); + save_item(NAME(m_sel1)); + + // patch out protection checks + UINT8 *rom = memregion(Z80_TAG)->base(); + rom[0x00fa] = 0xff; + rom[0x0336] = 0xff; + rom[0x0718] = 0xff; + rom[0x072c] = 0xff; + rom[0x0771] = 0xff; + rom[0x0788] = 0xff; +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void luxor_55_10828_device::device_reset() +{ + m_cs = false; +} + + + +//************************************************************************** +// ABC BUS INTERFACE +//************************************************************************** + +//------------------------------------------------- +// abcbus_cs - +//------------------------------------------------- + +void luxor_55_10828_device::abcbus_cs(UINT8 data) +{ + UINT8 address = 0x2c | BIT(m_s1->read(), 0); + + m_cs = (data == address); +} + + +//------------------------------------------------- +// abcbus_stat - +//------------------------------------------------- + +UINT8 luxor_55_10828_device::abcbus_stat() +{ + UINT8 data = 0xff; + + if (m_cs) + { + data = (m_status & 0xfe) | m_pio->rdy_a(); + } + + return data; +} + + +//------------------------------------------------- +// abcbus_inp - +//------------------------------------------------- + +UINT8 luxor_55_10828_device::abcbus_inp() +{ + UINT8 data = 0xff; + + if (m_cs) + { + if (!BIT(m_status, 6)) + { + data = m_data; + } + + m_pio->strobe_a(0); + m_pio->strobe_a(1); + } + + return data; +} + + +//------------------------------------------------- +// abcbus_out - +//------------------------------------------------- + +void luxor_55_10828_device::abcbus_out(UINT8 data) +{ + if (!m_cs) return; + + if (BIT(m_status, 6)) + { + m_data = data; + } + + m_pio->strobe_a(0); + m_pio->strobe_a(1); +} + + +//------------------------------------------------- +// abcbus_c1 - +//------------------------------------------------- + +void luxor_55_10828_device::abcbus_c1(UINT8 data) +{ + if (m_cs) + { + m_maincpu->set_input_line(INPUT_LINE_NMI, ASSERT_LINE); + m_maincpu->set_input_line(INPUT_LINE_NMI, CLEAR_LINE); + } +} + + +//------------------------------------------------- +// abcbus_c3 - +//------------------------------------------------- + +void luxor_55_10828_device::abcbus_c3(UINT8 data) +{ + if (m_cs) + { + m_maincpu->reset(); + } +} + + + +//************************************************************************** +// IMPLEMENTATION +//************************************************************************** + +//------------------------------------------------- +// ctrl_w - +//------------------------------------------------- + +WRITE8_MEMBER( luxor_55_10828_device::ctrl_w ) +{ + /* + + bit signal description + + 0 SEL 0 + 1 SEL 1 + 2 SEL 2 + 3 _MOT ON + 4 SIDE + 5 _PRECOMP ON + 6 _WAIT ENABLE + 7 FDC _MR + + */ + + // drive selection + m_sel0 = BIT(data, 0); + m_sel1 = BIT(data, 1); + + floppy_image_device *floppy = NULL; + + if (BIT(data, 0)) floppy = m_floppy0->get_device(); + if (BIT(data, 1)) floppy = m_floppy1->get_device(); + + m_fdc->set_floppy(floppy); + + if (floppy) + { + // motor enable + floppy->mon_w(BIT(data, 3)); + + // side select + floppy->ss_w(BIT(data, 4)); + } + + // wait enable + m_wait_enable = BIT(data, 6); + + // FDC master reset + if (!BIT(data, 7)) m_fdc->soft_reset(); +} + + +//------------------------------------------------- +// status_w - +//------------------------------------------------- + +WRITE8_MEMBER( luxor_55_10828_device::status_w ) +{ + /* + + bit description + + 0 _INT to main Z80 + 1 + 2 + 3 + 4 + 5 + 6 LS245 DIR + 7 + + */ + + m_status = data & 0xfe; + + // interrupt + m_slot->irq_w(BIT(data, 0) ? CLEAR_LINE : ASSERT_LINE); +} + + +//------------------------------------------------- +// fdc_r - +//------------------------------------------------- + +READ8_MEMBER( luxor_55_10828_device::fdc_r ) +{ + if (!m_wait_enable && !m_fdc_irq && !m_fdc_drq) + { + logerror("Z80 WAIT not supported by MAME core\n"); + + m_maincpu->set_input_line(Z80_INPUT_LINE_WAIT, ASSERT_LINE); + } + + return m_fdc->gen_r(offset); +} + + +//------------------------------------------------- +// fdc_w - +//------------------------------------------------- + +WRITE8_MEMBER( luxor_55_10828_device::fdc_w ) +{ + if (!m_wait_enable && !m_fdc_irq && !m_fdc_drq) + { + logerror("Z80 WAIT not supported by MAME core\n"); + + m_maincpu->set_input_line(Z80_INPUT_LINE_WAIT, ASSERT_LINE); + } + + m_fdc->gen_w(offset, data); +} diff --git a/src/devices/bus/abcbus/lux10828.h b/src/devices/bus/abcbus/lux10828.h new file mode 100644 index 00000000000..3ffa18e9122 --- /dev/null +++ b/src/devices/bus/abcbus/lux10828.h @@ -0,0 +1,115 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Luxor 55-10828 "slow" floppy disk controller emulation + +*********************************************************************/ + +#pragma once + +#ifndef __LUXOR_55_10828__ +#define __LUXOR_55_10828__ + +#include "emu.h" +#include "abcbus.h" +#include "cpu/z80/z80.h" +#include "cpu/z80/z80daisy.h" +#include "formats/abc800_dsk.h" +#include "machine/wd_fdc.h" +#include "machine/z80pio.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define ADDRESS_ABC830 45 +#define ADDRESS_ABC832 44 +#define ADDRESS_ABC834 44 +#define ADDRESS_ABC850 44 + + +#define DRIVE_TEAC_FD55F 0x01 +#define DRIVE_BASF_6138 0x02 +#define DRIVE_MICROPOLIS_1015F 0x03 +#define DRIVE_BASF_6118 0x04 +#define DRIVE_MICROPOLIS_1115F 0x05 +#define DRIVE_BASF_6106_08 0x08 +#define DRIVE_MPI_51 0x09 +#define DRIVE_BASF_6105 0x0e +#define DRIVE_BASF_6106 0x0f + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> luxor_55_10828_device + +class luxor_55_10828_device : public device_t, + public device_abcbus_card_interface +{ +public: + // construction/destruction + luxor_55_10828_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + DECLARE_WRITE8_MEMBER( ctrl_w ); + DECLARE_WRITE8_MEMBER( status_w ); + DECLARE_READ8_MEMBER( fdc_r ); + DECLARE_WRITE8_MEMBER( fdc_w ); + + DECLARE_READ8_MEMBER( pio_pa_r ); + DECLARE_WRITE8_MEMBER( pio_pa_w ); + DECLARE_READ8_MEMBER( pio_pb_r ); + DECLARE_WRITE8_MEMBER( pio_pb_w ); + + DECLARE_WRITE_LINE_MEMBER( fdc_intrq_w ); + DECLARE_WRITE_LINE_MEMBER( fdc_drq_w ); + + DECLARE_FLOPPY_FORMATS( floppy_formats ); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + virtual ioport_constructor device_input_ports() const; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_abcbus_interface overrides + virtual void abcbus_cs(UINT8 data); + virtual UINT8 abcbus_inp(); + virtual void abcbus_out(UINT8 data); + virtual UINT8 abcbus_stat(); + virtual void abcbus_c1(UINT8 data); + virtual void abcbus_c3(UINT8 data); + +private: + required_device m_maincpu; + required_device m_pio; + required_device m_fdc; + required_device m_floppy0; + required_device m_floppy1; + required_ioport m_sw1; + required_ioport m_s1; + + bool m_cs; // card selected + UINT8 m_status; // ABC BUS status + UINT8 m_data; // ABC BUS data + bool m_fdc_irq; // floppy interrupt + bool m_fdc_drq; // floppy data request + int m_wait_enable; // wait enable + int m_sel0; // drive select 0 + int m_sel1; // drive select 1 +}; + + +// device type definition +extern const device_type LUXOR_55_10828; + +#endif diff --git a/src/devices/bus/abcbus/lux21046.c b/src/devices/bus/abcbus/lux21046.c new file mode 100644 index 00000000000..67396d81139 --- /dev/null +++ b/src/devices/bus/abcbus/lux21046.c @@ -0,0 +1,1163 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Luxor 55 21046-11/-21/-41 5.25"/8" Controller Card emulation + +*********************************************************************/ + +/* + +Luxor Conkort + +PCB Layout +---------- + +55 11046-03 + +|-----------------------------------| +| LD1 SW1 CON2 | +| | +| CON3 S8 | +| S9 | +| LS240 LS174 7406 7406 | +| | +| LS174 FDC9229 LS107 LS266 | +| | +| | +| SAB1793 | +| LS368 16MHz | +| S6 | +| Z80DMA ROM | +| | +| | +| Z80 TC5565 | +| | +| | +| LS138 LS174 SW2 74374 | +| | +| LS10 LS266 S5 LS374 | +| S3 | +| PAL* S1 LS240 | +| | +| LS125* LS244 SW3 DM8131 | +| | +| | +|--|-----------------------------|--| + |------------CON1-------------| + +Notes: + All IC's shown. (* only stocked when used with the ABC 1600 computer) + + ROM - Toshiba TMM27128D-20 16Kx8 EPROM "CNTR 1.07 6490318-07" + PAL - PAL16R4 + TC5565 - Toshiba TC5565PL-15 8Kx8 bit Static RAM + Z80 - Zilog Z8400APS Z80A CPU + Z80DMA - Zilog Z8410APS Z80A DMA + SAB1793 - Siemens SAB1793-02P Floppy Disc Controller + FDC9229 - SMC FDC9229BT Floppy Disc Interface Circuit + DM8131 - National Semiconductor DM8131N 6-Bit Unified Bus Comparator + CON1 - ABC bus connector + CON2 - 25-pin D sub floppy connector (AMP4284) + CON3 - 34-pin header floppy connector + SW1 - Disk drive type (SS/DS, SD/DD) + SW2 - Disk drive model + SW3 - ABC bus address + S1 - Interface type (A:ABC1600 B:ABCBUS) + S3 - Interface type (A:ABC1600 B:ABCBUS) + S5 - Interface type (A:ABC1600 B:ABCBUS) + S6 - Amount of RAM installed (A:2KB, B:8KB) + S7 - Number of drives connected (0:3, 1:2) *located on solder side + S8 - Disk drive type (0:8", 1:5.25") + S9 - Location of RDY signal (A:8" P2-6, B:5.25" P2-34) + LD1 - LED + +*/ + +#include "lux21046.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define Z80_TAG "5ab" +#define Z80DMA_TAG "6ab" +#define SAB1793_TAG "7ab" +#define FDC9229_TAG "8b" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type LUXOR_55_21046 = &device_creator; +const device_type ABC830 = &device_creator; +const device_type ABC832 = &device_creator; +const device_type ABC834 = &device_creator; +const device_type ABC838 = &device_creator; +const device_type ABC850_FLOPPY = &device_creator; + + +//------------------------------------------------- +// ROM( luxor_55_21046 ) +//------------------------------------------------- + +ROM_START( luxor_55_21046 ) + ROM_REGION( 0x4000, Z80_TAG, 0 ) + ROM_DEFAULT_BIOS( "v107" ) + ROM_SYSTEM_BIOS( 0, "v107", "Luxor v1.07 (1985-07-03)" ) + ROMX_LOAD( "cntr 1.07 6490318-07.6cd", 0x0000, 0x4000, CRC(db8c1c0e) SHA1(8bccd5bc72124984de529ee058df779f06d2c1d5), ROM_BIOS(1) ) + ROM_SYSTEM_BIOS( 1, "v108", "Luxor v1.08 (1986-03-12)" ) + ROMX_LOAD( "cntr 108.6cd", 0x2000, 0x2000, CRC(229764cb) SHA1(a2e2f6f49c31b827efc62f894de9a770b65d109d), ROM_BIOS(2) ) + ROM_SYSTEM_BIOS( 2, "v207", "DiAB v2.07 (1987-06-24)" ) + ROMX_LOAD( "diab 207.6cd", 0x2000, 0x2000, CRC(86622f52) SHA1(61ad271de53152c1640c0b364fce46d1b0b4c7e2), ROM_BIOS(3) ) + + ROM_REGION( 0x104, "plds", 0 ) + ROM_LOAD( "pal16r4.2a", 0x000, 0x104, NO_DUMP) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *luxor_55_21046_device::device_rom_region() const +{ + return ROM_NAME( luxor_55_21046 ); +} + + +//------------------------------------------------- +// ADDRESS_MAP( luxor_55_21046_mem ) +//------------------------------------------------- + +static ADDRESS_MAP_START( luxor_55_21046_mem, AS_PROGRAM, 8, luxor_55_21046_device ) + ADDRESS_MAP_UNMAP_HIGH + ADDRESS_MAP_GLOBAL_MASK(0x3fff) + AM_RANGE(0x0000, 0x1fff) AM_ROM AM_REGION(Z80_TAG, 0x2000) // A13 pull-up + AM_RANGE(0x2000, 0x3fff) AM_RAM +ADDRESS_MAP_END + + +//------------------------------------------------- +// ADDRESS_MAP( luxor_55_21046_io ) +//------------------------------------------------- + +static ADDRESS_MAP_START( luxor_55_21046_io, AS_IO, 8, luxor_55_21046_device ) + ADDRESS_MAP_UNMAP_HIGH + AM_RANGE(0x0c, 0x0c) AM_MIRROR(0xff03) AM_READ(out_r) + AM_RANGE(0x1c, 0x1c) AM_MIRROR(0xff03) AM_WRITE(inp_w) + AM_RANGE(0x2c, 0x2c) AM_MIRROR(0xff03) AM_WRITE(_4b_w) + AM_RANGE(0x3c, 0x3c) AM_MIRROR(0xff03) AM_WRITE(_9b_w) + AM_RANGE(0x4c, 0x4c) AM_MIRROR(0xff03) AM_WRITE(_8a_w) + AM_RANGE(0x5c, 0x5c) AM_MIRROR(0xff07) AM_MASK(0xff00) AM_READ(_9a_r) + AM_RANGE(0x68, 0x6b) AM_MIRROR(0xff00) AM_DEVREAD(SAB1793_TAG, fd1793_t, read) + AM_RANGE(0x78, 0x7b) AM_MIRROR(0xff00) AM_DEVWRITE(SAB1793_TAG, fd1793_t, write) + AM_RANGE(0x80, 0x80) AM_MIRROR(0xff77) AM_DEVREADWRITE(Z80DMA_TAG, z80dma_device, read, write) +ADDRESS_MAP_END + + +//------------------------------------------------- +// Z80DMA +//------------------------------------------------- + +/* + + DMA Transfer Programs + + READ DAM + -------- + 7D 45 21 05 00 C3 14 28 95 6B 02 8A CF 01 AF CF 87 + + 7D transfer mode, port A -> port B, port A starting address follows, block length follows + 45 port A starting address low byte = 45 + 21 port A starting address high byte = 21 + 05 block length low byte = 05 + 00 block length high byte = 00 + C3 reset + 14 port A is memory, port A address increments + 28 port B is I/O, port B address fixed + 95 byte mode, port B starting address low byte follows, interrupt control byte follows + 6B port B starting address low byte = 6B (FDC DATA read) + 02 interrupt at end of block + 8A ready active high + CF load + 01 transfer B->A + AF disable interrupts + CF load + 87 enable DMA + + WRITE TO DISK + ------------- + C3 14 28 95 7B 02 8A CF 05 AF CF 87 + + C3 reset + 14 port A is memory, port A address increments + 28 port B is I/O, port B address fixed + 95 byte mode, port B starting address low follows, interrupt control byte follows + 7B port B starting address 0x007B (FDC DATA write) + 02 interrupt at end of block + 8A ready active high + CF load + 05 transfer A->B + AF disable interrupts + CF load + 87 enable DMA + + ?? + -- + C3 91 40 8A AB + + C3 reset + 91 byte mode, interrupt control byte follows + 40 interrupt on RDY + 8A _CE only, ready active high, stop on end of block + AB enable interrupts + +*/ + +WRITE_LINE_MEMBER( luxor_55_21046_device::dma_int_w ) +{ + m_dma_irq = state; + + // FDC and DMA interrupts are wire-ORed to the Z80 + m_maincpu->set_input_line(INPUT_LINE_IRQ0, m_fdc_irq || m_dma_irq); +} + +READ8_MEMBER( luxor_55_21046_device::memory_read_byte ) +{ + return m_maincpu->space(AS_PROGRAM).read_byte(offset); +} + +WRITE8_MEMBER( luxor_55_21046_device::memory_write_byte ) +{ + return m_maincpu->space(AS_PROGRAM).write_byte(offset, data); +} + +READ8_MEMBER( luxor_55_21046_device::io_read_byte ) +{ + return m_maincpu->space(AS_IO).read_byte(offset); +} + +WRITE8_MEMBER( luxor_55_21046_device::io_write_byte ) +{ + return m_maincpu->space(AS_IO).write_byte(offset, data); +} + +FLOPPY_FORMATS_MEMBER( luxor_55_21046_device::floppy_formats ) + FLOPPY_ABC800_FORMAT +FLOPPY_FORMATS_END + +static SLOT_INTERFACE_START( abc_floppies ) + SLOT_INTERFACE( "525sssd", FLOPPY_525_SSSD ) + SLOT_INTERFACE( "525sd", FLOPPY_525_SD ) + SLOT_INTERFACE( "525ssdd", FLOPPY_525_SSDD ) + SLOT_INTERFACE( "525dd", FLOPPY_525_DD ) + SLOT_INTERFACE( "525qd", FLOPPY_525_QD ) + SLOT_INTERFACE( "8dsdd", FLOPPY_8_DSDD ) +SLOT_INTERFACE_END + +WRITE_LINE_MEMBER( luxor_55_21046_device::fdc_intrq_w ) +{ + m_fdc_irq = state; + + // FDC and DMA interrupts are wire-ORed to the Z80 + m_maincpu->set_input_line(INPUT_LINE_IRQ0, m_fdc_irq || m_dma_irq); +} + + +//------------------------------------------------- +// z80_daisy_config z80_daisy_chain +//------------------------------------------------- + +static const z80_daisy_config z80_daisy_chain[] = +{ + { Z80DMA_TAG }, + { NULL } +}; + + +//------------------------------------------------- +// MACHINE_CONFIG( luxor_55_21046 ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( luxor_55_21046 ) + MCFG_CPU_ADD(Z80_TAG, Z80, XTAL_16MHz/4) + MCFG_CPU_CONFIG(z80_daisy_chain) + MCFG_CPU_PROGRAM_MAP(luxor_55_21046_mem) + MCFG_CPU_IO_MAP(luxor_55_21046_io) + + MCFG_DEVICE_ADD(Z80DMA_TAG, Z80DMA, XTAL_16MHz/4) + MCFG_Z80DMA_OUT_BUSREQ_CB(INPUTLINE(Z80_TAG, INPUT_LINE_HALT)) + MCFG_Z80DMA_OUT_INT_CB(WRITELINE(luxor_55_21046_device, dma_int_w)) + MCFG_Z80DMA_IN_MREQ_CB(READ8(luxor_55_21046_device, memory_read_byte)) + MCFG_Z80DMA_OUT_MREQ_CB(WRITE8(luxor_55_21046_device, memory_write_byte)) + MCFG_Z80DMA_IN_IORQ_CB(READ8(luxor_55_21046_device, io_read_byte)) + MCFG_Z80DMA_OUT_IORQ_CB(WRITE8(luxor_55_21046_device, io_write_byte)) + + MCFG_FD1793_ADD(SAB1793_TAG, XTAL_16MHz/16) + MCFG_WD_FDC_INTRQ_CALLBACK(WRITELINE(luxor_55_21046_device, fdc_intrq_w)) + MCFG_WD_FDC_DRQ_CALLBACK(DEVWRITELINE(Z80DMA_TAG, z80dma_device, rdy_w)) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// MACHINE_CONFIG( abc830 ) +//------------------------------------------------- + +static MACHINE_CONFIG_DERIVED( abc830, luxor_55_21046 ) + MCFG_FLOPPY_DRIVE_ADD(SAB1793_TAG":0", abc_floppies, "525ssdd", luxor_55_21046_device::floppy_formats) + MCFG_FLOPPY_DRIVE_ADD(SAB1793_TAG":1", abc_floppies, "525ssdd", luxor_55_21046_device::floppy_formats) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// MACHINE_CONFIG( abc832 ) +//------------------------------------------------- + +static MACHINE_CONFIG_DERIVED( abc832, luxor_55_21046 ) + MCFG_FLOPPY_DRIVE_ADD(SAB1793_TAG":0", abc_floppies, "525qd", luxor_55_21046_device::floppy_formats) + MCFG_FLOPPY_DRIVE_ADD(SAB1793_TAG":1", abc_floppies, "525qd", luxor_55_21046_device::floppy_formats) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// MACHINE_CONFIG( abc838 ) +//------------------------------------------------- + +static MACHINE_CONFIG_DERIVED( abc838, luxor_55_21046 ) + MCFG_FLOPPY_DRIVE_ADD(SAB1793_TAG":0", abc_floppies, "8dsdd", luxor_55_21046_device::floppy_formats) + MCFG_FLOPPY_DRIVE_ADD(SAB1793_TAG":1", abc_floppies, "8dsdd", luxor_55_21046_device::floppy_formats) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// MACHINE_CONFIG( abc850 ) +//------------------------------------------------- + +static MACHINE_CONFIG_DERIVED( abc850, luxor_55_21046 ) + MCFG_FLOPPY_DRIVE_ADD(SAB1793_TAG":0", abc_floppies, "525qd", luxor_55_21046_device::floppy_formats) + MCFG_FLOPPY_DRIVE_ADD(SAB1793_TAG":1", abc_floppies, NULL, luxor_55_21046_device::floppy_formats) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor luxor_55_21046_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( luxor_55_21046 ); +} + +machine_config_constructor abc830_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( abc830 ); +} + +machine_config_constructor abc832_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( abc832 ); +} + +machine_config_constructor abc834_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( abc832 ); +} + +machine_config_constructor abc838_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( abc838 ); +} + +machine_config_constructor abc850_floppy_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( abc850 ); +} + + +//------------------------------------------------- +// INPUT_PORTS( luxor_55_21046 ) +//------------------------------------------------- + +INPUT_PORTS_START( luxor_55_21046 ) + PORT_START("SW1") + // ABC 838 + PORT_DIPNAME( 0x0f, 0x00, DEF_STR( Unused ) ) PORT_DIPLOCATION("SW1:1,2,3,4") PORT_CONDITION("SW3", 0x7f, EQUALS, 0x2e) + PORT_DIPSETTING( 0x00, DEF_STR( Unused ) ) PORT_CONDITION("SW3", 0x7f, EQUALS, 0x2e) + // ABC 830 + PORT_DIPNAME( 0x01, 0x01, "Drive 0 Sides" ) PORT_DIPLOCATION("SW1:1") PORT_CONDITION("SW3", 0x7f, EQUALS, 0x2d) + PORT_DIPSETTING( 0x01, DEF_STR( Single ) ) + PORT_DIPSETTING( 0x00, "Double" ) + PORT_DIPNAME( 0x02, 0x02, "Drive 1 Sides" ) PORT_DIPLOCATION("SW1:2") PORT_CONDITION("SW3", 0x7f, EQUALS, 0x2d) + PORT_DIPSETTING( 0x02, DEF_STR( Single ) ) + PORT_DIPSETTING( 0x00, "Double" ) + PORT_DIPNAME( 0x04, 0x00, "Drive 0 Density" ) PORT_DIPLOCATION("SW1:3") PORT_CONDITION("SW3", 0x7f, EQUALS, 0x2d) + PORT_DIPSETTING( 0x04, DEF_STR( Single ) ) + PORT_DIPSETTING( 0x00, "Double" ) + PORT_DIPNAME( 0x08, 0x00, "Drive 1 Density" ) PORT_DIPLOCATION("SW1:4") PORT_CONDITION("SW3", 0x7f, EQUALS, 0x2d) + PORT_DIPSETTING( 0x08, DEF_STR( Single ) ) + PORT_DIPSETTING( 0x00, "Double" ) + // ABC 832/834/850 + PORT_DIPNAME( 0x01, 0x00, "Drive 0 Sides" ) PORT_DIPLOCATION("SW1:1") PORT_CONDITION("SW3", 0x7f, EQUALS, 0x2c) + PORT_DIPSETTING( 0x01, DEF_STR( Single ) ) + PORT_DIPSETTING( 0x00, "Double" ) + PORT_DIPNAME( 0x02, 0x00, "Drive 1 Sides" ) PORT_DIPLOCATION("SW1:2") PORT_CONDITION("SW3", 0x7f, EQUALS, 0x2c) + PORT_DIPSETTING( 0x02, DEF_STR( Single ) ) + PORT_DIPSETTING( 0x00, "Double" ) + PORT_DIPNAME( 0x04, 0x04, "Drive 0 Tracks" ) PORT_DIPLOCATION("SW1:3") PORT_CONDITION("SW3", 0x7f, EQUALS, 0x2c) + PORT_DIPSETTING( 0x00, "40" ) + PORT_DIPSETTING( 0x04, "80" ) + PORT_DIPNAME( 0x08, 0x08, "Drive 1 Tracks" ) PORT_DIPLOCATION("SW1:4") PORT_CONDITION("SW3", 0x7f, EQUALS, 0x2c) + PORT_DIPSETTING( 0x00, "40" ) + PORT_DIPSETTING( 0x08, "80" ) + + PORT_START("SW2") + PORT_DIPNAME( 0x0f, 0x01, "Drive Type" ) PORT_DIPLOCATION("SW2:1,2,3,4") + PORT_DIPSETTING( 0x01, "TEAC FD55F (ABC 834)" ) PORT_CONDITION("SW3", 0x7f, EQUALS, 0x2c) // 230 7802-01 + PORT_DIPSETTING( 0x02, "BASF 6138 (ABC 850)" ) PORT_CONDITION("SW3", 0x7f, EQUALS, 0x2c) // 230 8440-15 + PORT_DIPSETTING( 0x03, "Micropolis 1015F (ABC 832)" ) PORT_CONDITION("SW3", 0x7f, EQUALS, 0x2c) // 190 9711-15 + PORT_DIPSETTING( 0x04, "BASF 6118 (ABC 832)" ) PORT_CONDITION("SW3", 0x7f, EQUALS, 0x2c) // 190 9711-16 + PORT_DIPSETTING( 0x05, "Micropolis 1115F (ABC 832)" ) PORT_CONDITION("SW3", 0x7f, EQUALS, 0x2c) // 190 9711-17 + PORT_DIPSETTING( 0x08, "BASF 6106/08 (ABC 830)" ) PORT_CONDITION("SW3", 0x7f, EQUALS, 0x2d) // 190 9206-16 + PORT_DIPSETTING( 0x09, "MPI 51 (ABC 830)" ) PORT_CONDITION("SW3", 0x7f, EQUALS, 0x2d) // 190 9206-16 + PORT_DIPSETTING( 0x0e, "BASF 6105 (ABC 838)" ) PORT_CONDITION("SW3", 0x7f, EQUALS, 0x2e) + PORT_DIPSETTING( 0x0f, "BASF 6106 (ABC 838)" ) PORT_CONDITION("SW3", 0x7f, EQUALS, 0x2e) // 230 8838-15 + + PORT_START("SW3") + PORT_DIPNAME( 0x7f, 0x2c, "Card Address" ) PORT_DIPLOCATION("SW3:1,2,3,4,5,6,7") + PORT_DIPSETTING( 0x2c, "44 (ABC 832/834/850)" ) // MF0: MF1: + PORT_DIPSETTING( 0x2d, "45 (ABC 830)" ) // MO0: MO1: + PORT_DIPSETTING( 0x2e, "46 (ABC 838)" ) // SF0: SF1: + + PORT_START("S1") // also S3,S5 + PORT_DIPNAME( 0x01, 0x01, "Interface Type" ) + PORT_DIPSETTING( 0x00, "ABC 1600" ) + PORT_DIPSETTING( 0x01, "ABC 80/800/802/806" ) + + PORT_START("S6") + PORT_DIPNAME( 0x01, 0x01, "RAM Size" ) + PORT_DIPSETTING( 0x00, "2 KB" ) + PORT_DIPSETTING( 0x01, "8 KB" ) + + PORT_START("S8") + PORT_DIPNAME( 0x01, 0x01, "Drive Type" ) + PORT_DIPSETTING( 0x00, "8\"" ) + PORT_DIPSETTING( 0x01, "5.25\"" ) + + PORT_START("S9") + PORT_DIPNAME( 0x01, 0x01, "RDY Pin" ) + PORT_DIPSETTING( 0x00, "P2-6 (8\")" ) + PORT_DIPSETTING( 0x01, "P2-34 (5.25\")" ) +INPUT_PORTS_END + + +//------------------------------------------------- +// INPUT_PORTS( abc830 ) +//------------------------------------------------- + +INPUT_PORTS_START( abc830 ) + PORT_START("SW1") + PORT_DIPNAME( 0x01, 0x01, "Drive 0 Sides" ) PORT_DIPLOCATION("SW1:1") + PORT_DIPSETTING( 0x01, DEF_STR( Single ) ) + PORT_DIPSETTING( 0x00, "Double" ) + PORT_DIPNAME( 0x02, 0x02, "Drive 1 Sides" ) PORT_DIPLOCATION("SW1:2") + PORT_DIPSETTING( 0x02, DEF_STR( Single ) ) + PORT_DIPSETTING( 0x00, "Double" ) + PORT_DIPNAME( 0x04, 0x00, "Drive 0 Density" ) PORT_DIPLOCATION("SW1:3") + PORT_DIPSETTING( 0x04, DEF_STR( Single ) ) + PORT_DIPSETTING( 0x00, "Double" ) + PORT_DIPNAME( 0x08, 0x00, "Drive 1 Density" ) PORT_DIPLOCATION("SW1:4") + PORT_DIPSETTING( 0x08, DEF_STR( Single ) ) + PORT_DIPSETTING( 0x00, "Double" ) + + PORT_START("SW2") + PORT_DIPNAME( 0x0f, 0x08, "Drive Type" ) PORT_DIPLOCATION("SW2:1,2,3,4") + PORT_DIPSETTING( 0x08, "BASF 6106/08" ) + PORT_DIPSETTING( 0x09, "MPI 51" ) + + PORT_START("SW3") + PORT_DIPNAME( 0x7f, 0x2d, "Card Address" ) PORT_DIPLOCATION("SW3:1,2,3,4,5,6,7") + PORT_DIPSETTING( 0x2d, "45" ) + + PORT_START("S1") // also S3,S5 + PORT_DIPNAME( 0x01, 0x01, "Interface Type" ) + PORT_DIPSETTING( 0x00, "ABC 1600" ) + PORT_DIPSETTING( 0x01, "ABC 80/800/802/806" ) + + PORT_START("S6") + PORT_DIPNAME( 0x01, 0x01, "RAM Size" ) + PORT_DIPSETTING( 0x00, "2 KB" ) + PORT_DIPSETTING( 0x01, "8 KB" ) + + PORT_START("S8") + PORT_DIPNAME( 0x01, 0x01, "Drive Type" ) + PORT_DIPSETTING( 0x00, "8\"" ) + PORT_DIPSETTING( 0x01, "5.25\"" ) + + PORT_START("S9") + PORT_DIPNAME( 0x01, 0x01, "RDY Pin" ) + PORT_DIPSETTING( 0x00, "P2-6 (8\")" ) + PORT_DIPSETTING( 0x01, "P2-34 (5.25\")" ) +INPUT_PORTS_END + + +//------------------------------------------------- +// INPUT_PORTS( abc832 ) +//------------------------------------------------- + +INPUT_PORTS_START( abc832 ) + PORT_START("SW1") + PORT_DIPNAME( 0x01, 0x00, "Drive 0 Sides" ) PORT_DIPLOCATION("SW1:1") + PORT_DIPSETTING( 0x01, DEF_STR( Single ) ) + PORT_DIPSETTING( 0x00, "Double" ) + PORT_DIPNAME( 0x02, 0x00, "Drive 1 Sides" ) PORT_DIPLOCATION("SW1:2") + PORT_DIPSETTING( 0x02, DEF_STR( Single ) ) + PORT_DIPSETTING( 0x00, "Double" ) + PORT_DIPNAME( 0x04, 0x04, "Drive 0 Tracks" ) PORT_DIPLOCATION("SW1:3") + PORT_DIPSETTING( 0x00, "40" ) + PORT_DIPSETTING( 0x04, "80" ) + PORT_DIPNAME( 0x08, 0x08, "Drive 1 Tracks" ) PORT_DIPLOCATION("SW1:4") + PORT_DIPSETTING( 0x00, "40" ) + PORT_DIPSETTING( 0x08, "80" ) + + PORT_START("SW2") + PORT_DIPNAME( 0x0f, 0x04, "Drive Type" ) PORT_DIPLOCATION("SW2:1,2,3,4") + PORT_DIPSETTING( 0x03, "Micropolis 1015F" ) + PORT_DIPSETTING( 0x04, "BASF 6118" ) + PORT_DIPSETTING( 0x05, "Micropolis 1115F" ) + + PORT_START("SW3") + PORT_DIPNAME( 0x7f, 0x2c, "Card Address" ) PORT_DIPLOCATION("SW3:1,2,3,4,5,6,7") + PORT_DIPSETTING( 0x2c, "44" ) + + PORT_START("S1") // also S3,S5 + PORT_DIPNAME( 0x01, 0x01, "Interface Type" ) + PORT_DIPSETTING( 0x00, "ABC 1600" ) + PORT_DIPSETTING( 0x01, "ABC 80/800/802/806" ) + + PORT_START("S6") + PORT_DIPNAME( 0x01, 0x01, "RAM Size" ) + PORT_DIPSETTING( 0x00, "2 KB" ) + PORT_DIPSETTING( 0x01, "8 KB" ) + + PORT_START("S8") + PORT_DIPNAME( 0x01, 0x01, "Drive Type" ) + PORT_DIPSETTING( 0x00, "8\"" ) + PORT_DIPSETTING( 0x01, "5.25\"" ) + + PORT_START("S9") + PORT_DIPNAME( 0x01, 0x01, "RDY Pin" ) + PORT_DIPSETTING( 0x00, "P2-6 (8\")" ) + PORT_DIPSETTING( 0x01, "P2-34 (5.25\")" ) +INPUT_PORTS_END + + +//------------------------------------------------- +// INPUT_PORTS( abc834 ) +//------------------------------------------------- + +INPUT_PORTS_START( abc834 ) + PORT_START("SW1") + PORT_DIPNAME( 0x01, 0x00, "Drive 0 Sides" ) PORT_DIPLOCATION("SW1:1") + PORT_DIPSETTING( 0x01, DEF_STR( Single ) ) + PORT_DIPSETTING( 0x00, "Double" ) + PORT_DIPNAME( 0x02, 0x00, "Drive 1 Sides" ) PORT_DIPLOCATION("SW1:2") + PORT_DIPSETTING( 0x02, DEF_STR( Single ) ) + PORT_DIPSETTING( 0x00, "Double" ) + PORT_DIPNAME( 0x04, 0x04, "Drive 0 Tracks" ) PORT_DIPLOCATION("SW1:3") + PORT_DIPSETTING( 0x00, "40" ) + PORT_DIPSETTING( 0x04, "80" ) + PORT_DIPNAME( 0x08, 0x08, "Drive 1 Tracks" ) PORT_DIPLOCATION("SW1:4") + PORT_DIPSETTING( 0x00, "40" ) + PORT_DIPSETTING( 0x08, "80" ) + + PORT_START("SW2") + PORT_DIPNAME( 0x0f, 0x01, "Drive Type" ) PORT_DIPLOCATION("SW2:1,2,3,4") + PORT_DIPSETTING( 0x01, "TEAC FD55F" ) + + PORT_START("SW3") + PORT_DIPNAME( 0x7f, 0x2c, "Card Address" ) PORT_DIPLOCATION("SW3:1,2,3,4,5,6,7") + PORT_DIPSETTING( 0x2c, "44" ) + + PORT_START("S1") // also S3,S5 + PORT_DIPNAME( 0x01, 0x01, "Interface Type" ) + PORT_DIPSETTING( 0x00, "ABC 1600" ) + PORT_DIPSETTING( 0x01, "ABC 80/800/802/806" ) + + PORT_START("S6") + PORT_DIPNAME( 0x01, 0x01, "RAM Size" ) + PORT_DIPSETTING( 0x00, "2 KB" ) + PORT_DIPSETTING( 0x01, "8 KB" ) + + PORT_START("S8") + PORT_DIPNAME( 0x01, 0x01, "Drive Type" ) + PORT_DIPSETTING( 0x00, "8\"" ) + PORT_DIPSETTING( 0x01, "5.25\"" ) + + PORT_START("S9") + PORT_DIPNAME( 0x01, 0x01, "RDY Pin" ) + PORT_DIPSETTING( 0x00, "P2-6 (8\")" ) + PORT_DIPSETTING( 0x01, "P2-34 (5.25\")" ) +INPUT_PORTS_END + + +//------------------------------------------------- +// INPUT_PORTS( abc838 ) +//------------------------------------------------- + +INPUT_PORTS_START( abc838 ) + PORT_START("SW1") + PORT_DIPNAME( 0x0f, 0x00, DEF_STR( Unused ) ) PORT_DIPLOCATION("SW1:1,2,3,4") + PORT_DIPSETTING( 0x00, DEF_STR( Unused ) ) + + PORT_START("SW2") + PORT_DIPNAME( 0x0f, 0x0e, "Drive Type" ) PORT_DIPLOCATION("SW2:1,2,3,4") + PORT_DIPSETTING( 0x0e, "BASF 6105" ) + PORT_DIPSETTING( 0x0f, "BASF 6106" ) + + PORT_START("SW3") + PORT_DIPNAME( 0x7f, 0x2e, "Card Address" ) PORT_DIPLOCATION("SW3:1,2,3,4,5,6,7") + PORT_DIPSETTING( 0x2e, "46" ) + + PORT_START("S1") // also S3,S5 + PORT_DIPNAME( 0x01, 0x01, "Interface Type" ) + PORT_DIPSETTING( 0x00, "ABC 1600" ) + PORT_DIPSETTING( 0x01, "ABC 80/800/802/806" ) + + PORT_START("S6") + PORT_DIPNAME( 0x01, 0x01, "RAM Size" ) + PORT_DIPSETTING( 0x00, "2 KB" ) + PORT_DIPSETTING( 0x01, "8 KB" ) + + PORT_START("S8") + PORT_DIPNAME( 0x01, 0x00, "Drive Type" ) + PORT_DIPSETTING( 0x00, "8\"" ) + PORT_DIPSETTING( 0x01, "5.25\"" ) + + PORT_START("S9") + PORT_DIPNAME( 0x01, 0x00, "RDY Pin" ) + PORT_DIPSETTING( 0x00, "P2-6 (8\")" ) + PORT_DIPSETTING( 0x01, "P2-34 (5.25\")" ) +INPUT_PORTS_END + + +//------------------------------------------------- +// INPUT_PORTS( abc850 ) +//------------------------------------------------- + +INPUT_PORTS_START( abc850 ) + PORT_START("SW1") + PORT_DIPNAME( 0x01, 0x01, "Drive 0 Sides" ) PORT_DIPLOCATION("SW1:1") + PORT_DIPSETTING( 0x00, DEF_STR( Single ) ) + PORT_DIPSETTING( 0x01, "Double" ) + PORT_DIPNAME( 0x02, 0x02, "Drive 1 Sides" ) PORT_DIPLOCATION("SW1:2") + PORT_DIPSETTING( 0x00, DEF_STR( Single ) ) + PORT_DIPSETTING( 0x02, "Double" ) + PORT_DIPNAME( 0x04, 0x04, "Drive 0 Tracks" ) PORT_DIPLOCATION("SW1:3") + PORT_DIPSETTING( 0x00, "40" ) + PORT_DIPSETTING( 0x04, "80" ) + PORT_DIPNAME( 0x08, 0x08, "Drive 1 Tracks" ) PORT_DIPLOCATION("SW1:4") + PORT_DIPSETTING( 0x00, "40" ) + PORT_DIPSETTING( 0x08, "80" ) + + PORT_START("SW2") + PORT_DIPNAME( 0x0f, 0x02, "Drive Type" ) PORT_DIPLOCATION("SW2:1,2,3,4") + PORT_DIPSETTING( 0x01, "TEAC FD55F" ) + PORT_DIPSETTING( 0x02, "BASF 6138" ) + + PORT_START("SW3") + PORT_DIPNAME( 0x7f, 0x2c, "Card Address" ) PORT_DIPLOCATION("SW3:1,2,3,4,5,6,7") + PORT_DIPSETTING( 0x2c, "44" ) + + PORT_START("S1") // also S3,S5 + PORT_DIPNAME( 0x01, 0x01, "Interface Type" ) + PORT_DIPSETTING( 0x00, "ABC 1600" ) + PORT_DIPSETTING( 0x01, "ABC 80/800/802/806" ) + + PORT_START("S6") + PORT_DIPNAME( 0x01, 0x01, "RAM Size" ) + PORT_DIPSETTING( 0x00, "2 KB" ) + PORT_DIPSETTING( 0x01, "8 KB" ) + + PORT_START("S8") + PORT_DIPNAME( 0x01, 0x01, "Drive Type" ) + PORT_DIPSETTING( 0x00, "8\"" ) + PORT_DIPSETTING( 0x01, "5.25\"" ) + + PORT_START("S9") + PORT_DIPNAME( 0x01, 0x01, "RDY Pin" ) + PORT_DIPSETTING( 0x00, "P2-6 (8\")" ) + PORT_DIPSETTING( 0x01, "P2-34 (5.25\")" ) +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor luxor_55_21046_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( luxor_55_21046 ); +} + +ioport_constructor abc830_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( abc830 ); +} + +ioport_constructor abc832_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( abc832 ); +} + +ioport_constructor abc834_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( abc834 ); +} + +ioport_constructor abc838_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( abc838 ); +} + +ioport_constructor abc850_floppy_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( abc850 ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// luxor_55_21046_device - constructor +//------------------------------------------------- + +luxor_55_21046_device::luxor_55_21046_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, LUXOR_55_21046, "Luxor 55 21046", tag, owner, clock, "lux21046", __FILE__), + device_abcbus_card_interface(mconfig, *this), + m_maincpu(*this, Z80_TAG), + m_dma(*this, Z80DMA_TAG), + m_fdc(*this, SAB1793_TAG), + m_floppy0(*this, SAB1793_TAG":0"), + m_floppy1(*this, SAB1793_TAG":1"), + m_floppy(NULL), + m_sw1(*this, "SW1"), + m_sw2(*this, "SW2"), + m_sw3(*this, "SW3"), + m_cs(false), + m_fdc_irq(0), + m_dma_irq(0), + m_busy(0), + m_force_busy(0) +{ +} + +luxor_55_21046_device::luxor_55_21046_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_abcbus_card_interface(mconfig, *this), + m_maincpu(*this, Z80_TAG), + m_dma(*this, Z80DMA_TAG), + m_fdc(*this, SAB1793_TAG), + m_floppy0(*this, SAB1793_TAG":0"), + m_floppy1(*this, SAB1793_TAG":1"), + m_floppy(NULL), + m_sw1(*this, "SW1"), + m_sw2(*this, "SW2"), + m_sw3(*this, "SW3"), + m_cs(false), + m_fdc_irq(0), + m_dma_irq(0), + m_busy(0), + m_force_busy(0) +{ +} + +abc830_device::abc830_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : luxor_55_21046_device(mconfig, ABC830, "ABC 830", tag, owner, clock, "abc830", __FILE__) +{ +} + +abc832_device::abc832_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : luxor_55_21046_device(mconfig, ABC832, "ABC 832", tag, owner, clock, "abc832", __FILE__) +{ +} + +abc834_device::abc834_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : luxor_55_21046_device(mconfig, ABC834, "ABC 834", tag, owner, clock, "abc834", __FILE__) +{ +} + +abc838_device::abc838_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : luxor_55_21046_device(mconfig, ABC838, "ABC 838", tag, owner, clock, "abc838", __FILE__) +{ +} + +abc850_floppy_device::abc850_floppy_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : luxor_55_21046_device(mconfig, ABC850_FLOPPY, "ABC 850 floppy", tag, owner, clock, "lux21046", __FILE__) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void luxor_55_21046_device::device_start() +{ + // state saving + save_item(NAME(m_cs)); + save_item(NAME(m_status)); + save_item(NAME(m_out)); + save_item(NAME(m_inp)); + save_item(NAME(m_fdc_irq)); + save_item(NAME(m_dma_irq)); + save_item(NAME(m_busy)); + save_item(NAME(m_force_busy)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void luxor_55_21046_device::device_reset() +{ + m_cs = false; + m_out = 0; + + m_maincpu->reset(); + + address_space &space = m_maincpu->space(AS_PROGRAM); + _4b_w(space, 0, 0); + _9b_w(space, 0, 0); + _8a_w(space, 0, 0); +} + + + +//************************************************************************** +// ABC BUS INTERFACE +//************************************************************************** + +//------------------------------------------------- +// abcbus_cs - +//------------------------------------------------- + +void luxor_55_21046_device::abcbus_cs(UINT8 data) +{ + m_cs = (data == m_sw3->read()); +} + + +//------------------------------------------------- +// abcbus_csb - +//------------------------------------------------- + +int luxor_55_21046_device::abcbus_csb() +{ + return m_cs ? 0 : 1; +} + + +//------------------------------------------------- +// abcbus_stat - +//------------------------------------------------- + +UINT8 luxor_55_21046_device::abcbus_stat() +{ + /* + + bit description + + 0 3A pin 8 + 1 4B Q1 + 2 4B Q2 + 3 4B Q3 + 4 1 + 5 PAL16R4 pin 17 + 6 S1/A: PREN*, S1/B: 4B Q6 + 7 S5/A: PAL16R4 pin 16 inverted, S5/B: 4B Q7 + + */ + + UINT8 data = 0; + + if (m_cs) + { + data = 0x30 | (m_status & 0xce) | m_busy; + } + + // LS240 inverts the data + return data ^ 0xff; +} + + +//------------------------------------------------- +// abcbus_inp - +//------------------------------------------------- + +UINT8 luxor_55_21046_device::abcbus_inp() +{ + UINT8 data = 0xff; + + if (m_cs) + { + data = m_inp; + m_busy = 1; + } + + return data; +} + + +//------------------------------------------------- +// abcbus_out - +//------------------------------------------------- + +void luxor_55_21046_device::abcbus_out(UINT8 data) +{ + if (m_cs) + { + m_out = data; + m_busy = 1; + } +} + + +//------------------------------------------------- +// abcbus_c1 - +//------------------------------------------------- + +void luxor_55_21046_device::abcbus_c1(UINT8 data) +{ + if (m_cs) + { + m_maincpu->set_input_line(INPUT_LINE_NMI, ASSERT_LINE); + m_maincpu->set_input_line(INPUT_LINE_NMI, CLEAR_LINE); + } +} + + +//------------------------------------------------- +// abcbus_c3 - +//------------------------------------------------- + +void luxor_55_21046_device::abcbus_c3(UINT8 data) +{ + if (m_cs) + { + device_reset(); + } +} + + +//------------------------------------------------- +// abcbus_c4 - +//------------------------------------------------- + +void luxor_55_21046_device::abcbus_c4(UINT8 data) +{ + // TODO connected to PAL16R4 pin 2 +} + + + +//************************************************************************** +// IMPLEMENTATION +//************************************************************************** + +//------------------------------------------------- +// 3d_r - +//------------------------------------------------- + +READ8_MEMBER( luxor_55_21046_device::out_r ) +{ + if (m_busy) + { + m_busy = 0; + } + + return m_out; +} + + +//------------------------------------------------- +// 4d_w - +//------------------------------------------------- + +WRITE8_MEMBER( luxor_55_21046_device::inp_w ) +{ + if (m_busy) + { + m_busy = 0; + } + + m_inp = data; +} + + +//------------------------------------------------- +// 4b_w - +//------------------------------------------------- + +WRITE8_MEMBER( luxor_55_21046_device::_4b_w ) +{ + /* + + bit description + + 0 force busy + 1 + 2 + 3 + 4 N/C + 5 N/C + 6 + 7 + + */ + + m_status = data & 0xce; + + // busy + if (!BIT(data, 0)) + { + m_busy = 1; + } +} + + +//------------------------------------------------- +// 9b_w - +//------------------------------------------------- + +WRITE8_MEMBER( luxor_55_21046_device::_9b_w ) +{ + /* + + bit signal description + + 0 DS0 drive select 0 + 1 DS1 drive select 1 + 2 DS2 drive select 2 + 3 MTRON motor on + 4 TG43 track > 43 + 5 SIDE1 side 1 select + 6 + 7 + + */ + + // drive select + m_floppy = NULL; + + if (BIT(data, 0)) m_floppy = m_floppy0->get_device(); + if (BIT(data, 1)) m_floppy = m_floppy1->get_device(); + + m_fdc->set_floppy(m_floppy); + + if (m_floppy) + { + // motor enable + m_floppy->mon_w(!BIT(data, 3)); + + // side select + m_floppy->ss_w(BIT(data, 5)); + } +} + + +//------------------------------------------------- +// 8a_w - +//------------------------------------------------- + +WRITE8_MEMBER( luxor_55_21046_device::_8a_w ) +{ + /* + + bit signal description + + 0 FD1793 _MR FDC master reset + 1 FD1793 _DDEN, FDC9229 DENS density select + 2 FDC9229 MINI + 3 FDC9229 P1 + 4 FDC9229 P2 + 5 READY signal polarity (0=inverted) + 6 + 7 + + FDC9229 P0 is grounded + + */ + + // FDC master reset + if (!BIT(data, 0)) m_fdc->soft_reset(); + + // density select + m_fdc->dden_w(BIT(data, 1)); + + if (BIT(data, 2)) + { + m_fdc->set_unscaled_clock(XTAL_16MHz/16); + } + else + { + m_fdc->set_unscaled_clock(XTAL_16MHz/8); + } +} + + +//------------------------------------------------- +// 9a_r - +//------------------------------------------------- + +READ8_MEMBER( luxor_55_21046_device::_9a_r ) +{ + /* + + bit description + + 0 busy + 1 _FD2S + 2 SW2 + 3 S1/A: PAL16R4 pin 15, S1/B: GND + 4 SW1-1 or DCG + 5 SW1-2 + 6 SW1-3 + 7 SW1-4 + + */ + + UINT8 data = 0; + + // busy + data |= m_busy; + + // floppy + data |= (m_floppy ? m_floppy->twosid_r() : 1) << 1; + //data |= (m_floppy ? m_floppy->dskchg_r() : 1) << 4; + + // SW2 + UINT8 sw2 = m_sw2->read() & 0x0f; + + int sw2_1 = BIT(sw2, 0) ? 1 : BIT(offset, 8); + int sw2_2 = BIT(sw2, 1) ? 1 : BIT(offset, 9); + int sw2_3 = BIT(sw2, 2) ? 1 : BIT(offset, 10); + int sw2_4 = BIT(sw2, 3) ? 1 : BIT(offset, 11); + int sw2_data = !(sw2_1 && sw2_2 && !(sw2_3 ^ sw2_4)); + + data |= sw2_data << 2; + + // SW1 + data |= (m_sw1->read() & 0x0f) << 4; + + return data ^ 0xff; +} diff --git a/src/devices/bus/abcbus/lux21046.h b/src/devices/bus/abcbus/lux21046.h new file mode 100644 index 00000000000..f670b9d5768 --- /dev/null +++ b/src/devices/bus/abcbus/lux21046.h @@ -0,0 +1,200 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Luxor 55 21046-11/-21/-41 5.25"/8" Controller Card emulation + +*********************************************************************/ + +#pragma once + +#ifndef __LUXOR_55_21046__ +#define __LUXOR_55_21046__ + +#include "emu.h" +#include "abcbus.h" +#include "cpu/z80/z80.h" +#include "cpu/z80/z80daisy.h" +#include "formats/abc800_dsk.h" +#include "machine/wd_fdc.h" +#include "machine/z80dma.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define ADDRESS_ABC832 44 +#define ADDRESS_ABC830 45 +#define ADDRESS_ABC838 46 + + +#define DRIVE_TEAC_FD55F 0x01 +#define DRIVE_BASF_6138 0x02 +#define DRIVE_MICROPOLIS_1015F 0x03 +#define DRIVE_BASF_6118 0x04 +#define DRIVE_MICROPOLIS_1115F 0x05 +#define DRIVE_BASF_6106_08 0x08 +#define DRIVE_MPI_51 0x09 +#define DRIVE_BASF_6105 0x0e +#define DRIVE_BASF_6106 0x0f + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> luxor_55_21046_device + +class luxor_55_21046_device : public device_t, + public device_abcbus_card_interface +{ +public: + // construction/destruction + luxor_55_21046_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + luxor_55_21046_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + virtual ioport_constructor device_input_ports() const; + + // not really public + DECLARE_READ8_MEMBER( out_r ); + DECLARE_WRITE8_MEMBER( inp_w ); + DECLARE_WRITE8_MEMBER( _4b_w ); + DECLARE_WRITE8_MEMBER( _9b_w ); + DECLARE_WRITE8_MEMBER( _8a_w ); + DECLARE_READ8_MEMBER( _9a_r ); + + DECLARE_WRITE_LINE_MEMBER( dma_int_w ); + + DECLARE_READ8_MEMBER(memory_read_byte); + DECLARE_WRITE8_MEMBER(memory_write_byte); + DECLARE_READ8_MEMBER(io_read_byte); + DECLARE_WRITE8_MEMBER(io_write_byte); + + DECLARE_WRITE_LINE_MEMBER( fdc_intrq_w ); + + DECLARE_FLOPPY_FORMATS( floppy_formats ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_abcbus_interface overrides + virtual void abcbus_cs(UINT8 data); + virtual int abcbus_csb(); + virtual UINT8 abcbus_inp(); + virtual void abcbus_out(UINT8 data); + virtual UINT8 abcbus_stat(); + virtual void abcbus_c1(UINT8 data); + virtual void abcbus_c3(UINT8 data); + virtual void abcbus_c4(UINT8 data); + +private: + required_device m_maincpu; + required_device m_dma; + required_device m_fdc; + required_device m_floppy0; + required_device m_floppy1; + floppy_image_device *m_floppy; + required_ioport m_sw1; + required_ioport m_sw2; + required_ioport m_sw3; + + bool m_cs; // card selected + UINT8 m_status; // ABC BUS status + UINT8 m_out; // ABC BUS data in + UINT8 m_inp; // ABC BUS data out + bool m_fdc_irq; // FDC interrupt + int m_dma_irq; // DMA interrupt + int m_busy; // busy bit + int m_force_busy; // force busy bit +}; + + +// ======================> abc830_device + +class abc830_device : public luxor_55_21046_device +{ +public: + // construction/destruction + abc830_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual ioport_constructor device_input_ports() const; +}; + + +// ======================> abc832_device + +class abc832_device : public luxor_55_21046_device +{ +public: + // construction/destruction + abc832_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual ioport_constructor device_input_ports() const; +}; + + +// ======================> abc834_device + +class abc834_device : public luxor_55_21046_device +{ +public: + // construction/destruction + abc834_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual ioport_constructor device_input_ports() const; +}; + + +// ======================> abc838_device + +class abc838_device : public luxor_55_21046_device +{ +public: + // construction/destruction + abc838_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual ioport_constructor device_input_ports() const; +}; + + +// ======================> abc850_floppy_device + +class abc850_floppy_device : public luxor_55_21046_device +{ +public: + // construction/destruction + abc850_floppy_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual ioport_constructor device_input_ports() const; +}; + + +// device type definition +extern const device_type LUXOR_55_21046; +extern const device_type ABC830; +extern const device_type ABC832; +extern const device_type ABC834; +extern const device_type ABC838; +extern const device_type ABC850_FLOPPY; + + + +#endif diff --git a/src/devices/bus/abcbus/lux21056.c b/src/devices/bus/abcbus/lux21056.c new file mode 100644 index 00000000000..375a5927c47 --- /dev/null +++ b/src/devices/bus/abcbus/lux21056.c @@ -0,0 +1,673 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Luxor 55 21056-00 Xebec Interface Host Adapter emulation + +*********************************************************************/ + +/* + + Use the CHDMAN utility to create a 10MB image for ABC 850: + + $ chdman createhd -o ro202.chd -chs 321,4,32 -ss 256 + $ chdman createhd -o basf6186.chd -chs 440,4,32 -ss 256 + + or a 20MB image for ABC 852: + + $ chdman createhd -o basf6185.chd -chs 440,6,32 -ss 256 + $ chdman createhd -o nec5126.chd -chs 615,4,32 -ss 256 + + or a 60MB image for ABC 856: + + $ chdman createhd -o micr1325.chd -chs 1024,8,32 -ss 256 + + Start the abc800 emulator with the ABC 850 attached on the ABC bus, + with the new CHD and a UFD-DOS floppy mounted: + + $ mess abc800m -bus abc850 -flop1 ufd631 -hard ro202.chd + $ mess abc800m -bus abc850 -bus:abc850:io2 xebec,bios=basf6186 -flop1 ufd631 -hard basf6186.chd + + or with the ABC 852 attached: + + $ mess abc800m -bus abc852 -flop1 ufd631 -hard basf6185.chd + $ mess abc800m -bus abc852 -bus:abc852:io2 xebec,bios=nec5126 -flop1 ufd631 -hard nec5126.chd + + or with the ABC 856 attached: + + $ mess abc800m -bus abc856 -flop1 ufd631 -hard micr1325.chd + + Configure the floppy controller for use with an ABC 850: + + - Drive 0 Sides: Double + - Drive 1 Sides: Double + - Drive 0 Tracks: 40 or 80 depending on the UFD DOS image used + - Drive 1 Tracks: 40 or 80 depending on the UFD DOS image used + - Card Address: 44 (ABC 832/834/850) + + Reset the emulated machine by pressing F3. + + You should now see the following text at the top of the screen: + + DOS ar UFD-DOS ver. 19 + DR_: motsvarar MF_: + + Enter "BYE" to get into the UFD-DOS command prompt. + Enter "DOSGEN,F HD0:" to start the formatting utility. + Enter "J", and enter "J" to confirm the formatting. + + If you have a 20MB image, format the second partition by entering "DOSGEN,F HD1:", "J", and "J". + + If you have a 60MB image, format the third partition by entering "DOSGEN,F HD2:", "J", and "J", + and format the fourth partition by entering "DOSGEN,F HD3:", "J", and "J". + + You can now list your freshly created partitions by entering "LIB". + + Or skip all of the above and use the preformatted images in the software list: + + $ mess abc800m -bus abc850 -flop1 ufd631 -hard abc850 + $ mess abc800m -bus abc852 -flop1 ufd631 -hard abc852 + $ mess abc800m -bus abc856 -flop1 ufd631 -hard abc856 + +*/ + +#include "lux21056.h" +#include "bus/scsi/s1410.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define Z80_TAG "5a" +#define Z80DMA_TAG "6a" +#define SASIBUS_TAG "sasi" + +#define STAT_DIR \ + BIT(m_stat, 6) + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type LUXOR_55_21056 = &device_creator; + + +//------------------------------------------------- +// ROM( luxor_55_21056 ) +//------------------------------------------------- + +ROM_START( luxor_55_21056 ) + ROM_REGION( 0x2000, Z80_TAG, 0 ) + // ABC 850 + ROM_SYSTEM_BIOS( 0, "ro202", "Rodime RO202 (CHS: 321,4,32,256)" ) + ROMX_LOAD( "rodi202.bin", 0x0000, 0x0800, CRC(337b4dcf) SHA1(791ebeb4521ddc11fb9742114018e161e1849bdf), ROM_BIOS(1) ) // Rodime RO202 (http://stason.org/TULARC/pc/hard-drives-hdd/rodime/RO202-11MB-5-25-FH-MFM-ST506.html) + ROM_SYSTEM_BIOS( 1, "basf6186", "BASF 6186 (CHS: 440,4,32,256)" ) + ROMX_LOAD( "basf6186.bin", 0x0000, 0x0800, NO_DUMP, ROM_BIOS(2) ) // BASF 6186 (http://stason.org/TULARC/pc/hard-drives-hdd/basf-magnetics/6186-14MB-5-25-FH-MFM-ST412.html) + // ABC 852 + ROM_SYSTEM_BIOS( 2, "basf6185", "BASF 6185 (CHS: 440,6,32,256)" ) + ROMX_LOAD( "basf6185.bin", 0x0000, 0x0800, CRC(06f8fe2e) SHA1(e81f2a47c854e0dbb096bee3428d79e63591059d), ROM_BIOS(3) ) // BASF 6185 (http://stason.org/TULARC/pc/hard-drives-hdd/basf-magnetics/6185-22MB-5-25-FH-MFM-ST412.html) + ROM_SYSTEM_BIOS( 3, "nec5126", "NEC 5126 (CHS: 615,4,32,256)" ) + ROMX_LOAD( "nec5126.bin", 0x0000, 0x1000, CRC(17c247e7) SHA1(7339738b87751655cb4d6414422593272fe72f5d), ROM_BIOS(4) ) // NEC 5126 (http://stason.org/TULARC/pc/hard-drives-hdd/nec/D5126-20MB-5-25-HH-MFM-ST506.html) + // ABC 856 + ROM_SYSTEM_BIOS( 4, "micr1325", "Micropolis 1325 (CHS: 1024,8,32,256)" ) + ROMX_LOAD( "micr1325.bin", 0x0000, 0x0800, CRC(084af409) SHA1(342b8e214a8c4c2b014604e53c45ef1bd1c69ea3), ROM_BIOS(5) ) // Micropolis 1325 (http://stason.org/TULARC/pc/hard-drives-hdd/micropolis/1325-69MB-5-25-FH-MFM-ST506.html) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *luxor_55_21056_device::device_rom_region() const +{ + return ROM_NAME( luxor_55_21056 ); +} + + +//------------------------------------------------- +// ADDRESS_MAP( luxor_55_21056_mem ) +//------------------------------------------------- + +static ADDRESS_MAP_START( luxor_55_21056_mem, AS_PROGRAM, 8, luxor_55_21056_device ) + ADDRESS_MAP_UNMAP_HIGH + ADDRESS_MAP_GLOBAL_MASK(0x3fff) + AM_RANGE(0x0000, 0x0fff) AM_MIRROR(0x1000) AM_ROM AM_REGION(Z80_TAG, 0) + AM_RANGE(0x2000, 0x27ff) AM_MIRROR(0x1800) AM_RAM +ADDRESS_MAP_END + + +//------------------------------------------------- +// ADDRESS_MAP( luxor_55_21056_io ) +//------------------------------------------------- + +static ADDRESS_MAP_START( luxor_55_21056_io, AS_IO, 8, luxor_55_21056_device ) + ADDRESS_MAP_UNMAP_HIGH + ADDRESS_MAP_GLOBAL_MASK(0xf8) + AM_RANGE(0x00, 0x00) AM_MIRROR(0xf0) AM_DEVREADWRITE(Z80DMA_TAG, z80dma_device, read, write) + AM_RANGE(0x08, 0x08) AM_READ(sasi_status_r) + AM_RANGE(0x18, 0x18) AM_WRITE(stat_w) + AM_RANGE(0x28, 0x28) AM_READ(out_r) + AM_RANGE(0x38, 0x38) AM_WRITE(inp_w) + AM_RANGE(0x48, 0x48) AM_READWRITE(sasi_data_r, sasi_data_w) + AM_RANGE(0x58, 0x58) AM_READWRITE(rdy_reset_r, rdy_reset_w) + AM_RANGE(0x68, 0x68) AM_READWRITE(sasi_sel_r, sasi_sel_w) + AM_RANGE(0x78, 0x78) AM_READWRITE(sasi_rst_r, sasi_rst_w) +ADDRESS_MAP_END + + +//------------------------------------------------- +// z80_daisy_config daisy_chain +//------------------------------------------------- + +static const z80_daisy_config daisy_chain[] = +{ + { Z80DMA_TAG }, + { NULL } +}; + + +//------------------------------------------------- +// Z80DMA +//------------------------------------------------- + +READ8_MEMBER( luxor_55_21056_device::memory_read_byte ) +{ + return m_maincpu->space(AS_PROGRAM).read_byte(offset); +} + +WRITE8_MEMBER( luxor_55_21056_device::memory_write_byte ) +{ + return m_maincpu->space(AS_PROGRAM).write_byte(offset, data); +} + +READ8_MEMBER( luxor_55_21056_device::io_read_byte ) +{ + return m_maincpu->space(AS_IO).read_byte(offset); +} + +WRITE8_MEMBER( luxor_55_21056_device::io_write_byte ) +{ + return m_maincpu->space(AS_IO).write_byte(offset, data); +} + + +WRITE_LINE_MEMBER( luxor_55_21056_device::write_sasi_bsy ) +{ + m_sasi_bsy = state; + + if (m_sasi_bsy) + { + m_sasibus->write_sel(!m_sasi_bsy); + } +} + +WRITE_LINE_MEMBER( luxor_55_21056_device::write_sasi_io ) +{ + m_sasi_io = state; + + if (!m_sasi_io) + { + m_sasi_data_out->write(m_sasi_data); + } + else + { + m_sasi_data_out->write(0); + } +} + +WRITE_LINE_MEMBER( luxor_55_21056_device::write_sasi_req ) +{ + m_sasi_req = state; + + if (m_sasi_req) + { + m_sasibus->write_ack(!m_sasi_req); + } +} + +WRITE_LINE_MEMBER( luxor_55_21056_device::write_sasi_cd ) +{ + m_sasi_cd = state; +} + +WRITE_LINE_MEMBER( luxor_55_21056_device::write_sasi_msg ) +{ + m_sasi_msg = state; +} + +//------------------------------------------------- +// MACHINE_DRIVER( luxor_55_21056 ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( luxor_55_21056 ) + MCFG_CPU_ADD(Z80_TAG, Z80, XTAL_8MHz/2) + MCFG_CPU_PROGRAM_MAP(luxor_55_21056_mem) + MCFG_CPU_IO_MAP(luxor_55_21056_io) + MCFG_CPU_CONFIG(daisy_chain) + + MCFG_DEVICE_ADD(Z80DMA_TAG, Z80DMA, XTAL_8MHz/2) + MCFG_Z80DMA_OUT_BUSREQ_CB(INPUTLINE(Z80_TAG, INPUT_LINE_HALT)) + MCFG_Z80DMA_OUT_INT_CB(INPUTLINE(Z80_TAG, INPUT_LINE_IRQ0)) + MCFG_Z80DMA_IN_MREQ_CB(READ8(luxor_55_21056_device, memory_read_byte)) + MCFG_Z80DMA_OUT_MREQ_CB(WRITE8(luxor_55_21056_device, memory_write_byte)) + MCFG_Z80DMA_IN_IORQ_CB(READ8(luxor_55_21056_device, io_read_byte)) + MCFG_Z80DMA_OUT_IORQ_CB(WRITE8(luxor_55_21056_device, io_write_byte)) + + MCFG_DEVICE_ADD(SASIBUS_TAG, SCSI_PORT, 0) + MCFG_SCSI_DATA_INPUT_BUFFER("sasi_data_in") + MCFG_SCSI_REQ_HANDLER(WRITELINE(luxor_55_21056_device, write_sasi_req)) + MCFG_SCSI_IO_HANDLER(WRITELINE(luxor_55_21056_device, write_sasi_io)) + MCFG_SCSI_CD_HANDLER(WRITELINE(luxor_55_21056_device, write_sasi_cd)) + MCFG_SCSI_MSG_HANDLER(WRITELINE(luxor_55_21056_device, write_sasi_msg)) + MCFG_SCSI_BSY_HANDLER(WRITELINE(luxor_55_21056_device, write_sasi_bsy)) + MCFG_SCSIDEV_ADD(SASIBUS_TAG ":" SCSI_PORT_DEVICE1, "harddisk", S1410, SCSI_ID_0) + + MCFG_SCSI_OUTPUT_LATCH_ADD("sasi_data_out", SASIBUS_TAG) + MCFG_DEVICE_ADD("sasi_data_in", INPUT_BUFFER, 0) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor luxor_55_21056_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( luxor_55_21056 ); +} + + +//------------------------------------------------- +// INPUT_PORTS( luxor_55_21046 ) +//------------------------------------------------- + +INPUT_PORTS_START( luxor_55_21056 ) + PORT_START("S1") + PORT_DIPNAME( 0x3f, 0x24, "Card Address" ) + PORT_DIPSETTING( 0x20, "32" ) + PORT_DIPSETTING( 0x21, "33" ) + PORT_DIPSETTING( 0x22, "34" ) + PORT_DIPSETTING( 0x23, "35" ) + PORT_DIPSETTING( 0x24, "36 (ABC 850)" ) + PORT_DIPSETTING( 0x25, "37" ) + PORT_DIPSETTING( 0x26, "38" ) + PORT_DIPSETTING( 0x27, "39" ) + PORT_DIPSETTING( 0x28, "40" ) + PORT_DIPSETTING( 0x29, "41" ) + PORT_DIPSETTING( 0x2a, "42" ) + PORT_DIPSETTING( 0x2b, "43" ) + PORT_DIPSETTING( 0x2c, "44" ) + PORT_DIPSETTING( 0x2d, "45" ) + PORT_DIPSETTING( 0x2e, "46" ) + PORT_DIPSETTING( 0x2f, "47" ) + + PORT_START("S2") + PORT_DIPNAME( 0x01, 0x00, "PROM Size" ) + PORT_DIPSETTING( 0x00, "2 KB" ) + PORT_DIPSETTING( 0x01, "8 KB" ) + + PORT_START("S3") + PORT_DIPNAME( 0x01, 0x00, "RAM Size" ) + PORT_DIPSETTING( 0x00, "2 KB" ) + PORT_DIPSETTING( 0x01, "8 KB" ) +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor luxor_55_21056_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( luxor_55_21056 ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// luxor_55_21056_device - constructor +//------------------------------------------------- + +luxor_55_21056_device::luxor_55_21056_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, LUXOR_55_21056, "Luxor 55 21056", tag, owner, clock, "lux21056", __FILE__), + device_abcbus_card_interface(mconfig, *this), + m_maincpu(*this, Z80_TAG), + m_dma(*this, Z80DMA_TAG), + m_sasibus(*this, SASIBUS_TAG), + m_sasi_data_out(*this, "sasi_data_out"), + m_sasi_data_in(*this, "sasi_data_in"), + m_s1(*this, "S1"), + m_cs(false), + m_rdy(0), + m_sasi_req(0), + m_sasi_io(0), + m_sasi_cd(0), + m_sasi_msg(0), + m_sasi_bsy(0), + m_stat(0), + m_sasi_data(0) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void luxor_55_21056_device::device_start() +{ + // state saving + save_item(NAME(m_cs)); + save_item(NAME(m_rdy)); + save_item(NAME(m_inp)); + save_item(NAME(m_out)); + save_item(NAME(m_stat)); + save_item(NAME(m_sasi_req)); + save_item(NAME(m_sasi_io)); + save_item(NAME(m_sasi_cd)); + save_item(NAME(m_sasi_msg)); + save_item(NAME(m_sasi_bsy)); + save_item(NAME(m_sasi_data)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void luxor_55_21056_device::device_reset() +{ + m_maincpu->reset(); + + m_cs = false; + m_stat = 0; + m_sasi_data = 0; + + set_rdy(m_rdy); +} + + + +//************************************************************************** +// ABC BUS INTERFACE +//************************************************************************** + +//------------------------------------------------- +// abcbus_cs - +//------------------------------------------------- + +void luxor_55_21056_device::abcbus_cs(UINT8 data) +{ + m_cs = (data == m_s1->read()); +} + + +//------------------------------------------------- +// abcbus_stat - +//------------------------------------------------- + +UINT8 luxor_55_21056_device::abcbus_stat() +{ + UINT8 data = 0xff; + + if (m_cs) + { + data = m_stat & 0xfe; + data |= m_rdy ^ STAT_DIR; + } + + return data; +} + + +//------------------------------------------------- +// abcbus_inp - +//------------------------------------------------- + +UINT8 luxor_55_21056_device::abcbus_inp() +{ + UINT8 data = 0xff; + + if (m_cs && !STAT_DIR) + { + data = m_inp; + + if (m_rdy) set_rdy(!m_rdy); + } + + return data; +} + + +//------------------------------------------------- +// abcbus_out - +//------------------------------------------------- + +void luxor_55_21056_device::abcbus_out(UINT8 data) +{ + if (m_cs) + { + m_out = data; + + if (STAT_DIR && !m_rdy) set_rdy(!m_rdy); + } +} + + +//------------------------------------------------- +// abcbus_c1 - +//------------------------------------------------- + +void luxor_55_21056_device::abcbus_c1(UINT8 data) +{ + if (m_cs) + { + m_maincpu->set_input_line(INPUT_LINE_NMI, ASSERT_LINE); + m_maincpu->set_input_line(INPUT_LINE_NMI, CLEAR_LINE); + } +} + + +//------------------------------------------------- +// abcbus_c3 - +//------------------------------------------------- + +void luxor_55_21056_device::abcbus_c3(UINT8 data) +{ + if (m_cs) + { + device_reset(); + } +} + + +//------------------------------------------------- +// sasi_status_r - +//------------------------------------------------- + +READ8_MEMBER( luxor_55_21056_device::sasi_status_r ) +{ + /* + + bit description + + 0 RDY + 1 REQ + 2 I/O + 3 C/D + 4 MSG + 5 BSY + 6 + 7 + + */ + + UINT8 data = 0; + + data |= m_rdy ^ STAT_DIR; + + data |= !m_sasi_req << 1; + data |= !m_sasi_io << 2; + data |= !m_sasi_cd << 3; + data |= !m_sasi_msg << 4; + data |= !m_sasi_bsy << 5; + + return data ^ 0xff; +} + + +//------------------------------------------------- +// stat_w - +//------------------------------------------------- + +WRITE8_MEMBER( luxor_55_21056_device::stat_w ) +{ + m_stat = data; + + set_rdy(m_rdy); +} + + +//------------------------------------------------- +// out_r - +//------------------------------------------------- + +READ8_MEMBER( luxor_55_21056_device::out_r ) +{ + UINT8 data = m_out; + + if (STAT_DIR && m_rdy) set_rdy(!m_rdy); + + return data; +} + + +//------------------------------------------------- +// inp_w - +//------------------------------------------------- + +WRITE8_MEMBER( luxor_55_21056_device::inp_w ) +{ + m_inp = data; + + if (!STAT_DIR && !m_rdy) set_rdy(!m_rdy); +} + + +//------------------------------------------------- +// sasi_data_r - +//------------------------------------------------- + +READ8_MEMBER( luxor_55_21056_device::sasi_data_r ) +{ + UINT8 data = m_sasi_data_in->read(); + + m_sasibus->write_ack(!m_sasi_req); + + return data; +} + + +//------------------------------------------------- +// sasi_data_w - +//------------------------------------------------- + +WRITE8_MEMBER( luxor_55_21056_device::sasi_data_w ) +{ + m_sasi_data = data; + + if (!m_sasi_io) + { + m_sasi_data_out->write(m_sasi_data); + } + + m_sasibus->write_ack(!m_sasi_req); +} + + +//------------------------------------------------- +// rdy_reset_r - +//------------------------------------------------- + +READ8_MEMBER( luxor_55_21056_device::rdy_reset_r ) +{ + rdy_reset_w(space, offset, 0xff); + + return 0xff; +} + + +//------------------------------------------------- +// rdy_reset_w - +//------------------------------------------------- + +WRITE8_MEMBER( luxor_55_21056_device::rdy_reset_w ) +{ + set_rdy(0); +} + + +//------------------------------------------------- +// sasi_sel_r - +//------------------------------------------------- + +READ8_MEMBER( luxor_55_21056_device::sasi_sel_r ) +{ + sasi_sel_w(space, offset, 0xff); + + return 0xff; +} + + +//------------------------------------------------- +// sasi_sel_w - +//------------------------------------------------- + +WRITE8_MEMBER( luxor_55_21056_device::sasi_sel_w ) +{ + m_sasibus->write_sel(!m_sasi_bsy); +} + + +//------------------------------------------------- +// sasi_rst_r - +//------------------------------------------------- + +READ8_MEMBER( luxor_55_21056_device::sasi_rst_r ) +{ + sasi_rst_w(space, offset, 0xff); + + return 0xff; +} + + +//------------------------------------------------- +// sasi_rst_w - +//------------------------------------------------- + +WRITE8_MEMBER( luxor_55_21056_device::sasi_rst_w ) +{ + m_sasibus->write_rst(1); + m_sasibus->write_rst(0); +} + + +//------------------------------------------------- +// set_rdy - +//------------------------------------------------- + +void luxor_55_21056_device::set_rdy(int state) +{ + m_rdy = state; + + m_dma->rdy_w(m_rdy ^ STAT_DIR); +} diff --git a/src/devices/bus/abcbus/lux21056.h b/src/devices/bus/abcbus/lux21056.h new file mode 100644 index 00000000000..56d550155bf --- /dev/null +++ b/src/devices/bus/abcbus/lux21056.h @@ -0,0 +1,108 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Luxor 55 21056-00 Xebec Interface Host Adapter emulation + +*********************************************************************/ + +#pragma once + +#ifndef __LUXOR_55_21056__ +#define __LUXOR_55_21056__ + +#include "emu.h" +#include "abcbus.h" +#include "bus/scsi/scsi.h" +#include "cpu/z80/z80.h" +#include "cpu/z80/z80daisy.h" +#include "machine/z80dma.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> luxor_55_21056_device + +class luxor_55_21056_device : public device_t, + public device_abcbus_card_interface +{ +public: + // construction/destruction + luxor_55_21056_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + virtual ioport_constructor device_input_ports() const; + + DECLARE_READ8_MEMBER( sasi_status_r ); + DECLARE_WRITE8_MEMBER( stat_w ); + DECLARE_READ8_MEMBER( out_r ); + DECLARE_WRITE8_MEMBER( inp_w ); + DECLARE_READ8_MEMBER( sasi_data_r ); + DECLARE_WRITE8_MEMBER( sasi_data_w ); + DECLARE_READ8_MEMBER( rdy_reset_r ); + DECLARE_WRITE8_MEMBER( rdy_reset_w ); + DECLARE_READ8_MEMBER( sasi_sel_r ); + DECLARE_WRITE8_MEMBER( sasi_sel_w ); + DECLARE_READ8_MEMBER( sasi_rst_r ); + DECLARE_WRITE8_MEMBER( sasi_rst_w ); + + DECLARE_READ8_MEMBER( memory_read_byte ); + DECLARE_WRITE8_MEMBER( memory_write_byte ); + DECLARE_READ8_MEMBER( io_read_byte ); + DECLARE_WRITE8_MEMBER( io_write_byte ); + + DECLARE_WRITE_LINE_MEMBER( write_sasi_req ); + DECLARE_WRITE_LINE_MEMBER( write_sasi_io ); + DECLARE_WRITE_LINE_MEMBER( write_sasi_cd ); + DECLARE_WRITE_LINE_MEMBER( write_sasi_msg ); + DECLARE_WRITE_LINE_MEMBER( write_sasi_bsy ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_abcbus_interface overrides + virtual void abcbus_cs(UINT8 data); + virtual UINT8 abcbus_inp(); + virtual void abcbus_out(UINT8 data); + virtual UINT8 abcbus_stat(); + virtual void abcbus_c1(UINT8 data); + virtual void abcbus_c3(UINT8 data); + +private: + void set_rdy(int state); + + required_device m_maincpu; + required_device m_dma; + required_device m_sasibus; + required_device m_sasi_data_out; + required_device m_sasi_data_in; + required_ioport m_s1; + + int m_cs; + int m_rdy; + int m_sasi_req; + int m_sasi_io; + int m_sasi_cd; + int m_sasi_msg; + int m_sasi_bsy; + + UINT8 m_inp; + UINT8 m_out; + UINT8 m_stat; + UINT8 m_sasi_data; +}; + + +// device type definition +extern const device_type LUXOR_55_21056; + + + +#endif diff --git a/src/devices/bus/abcbus/lux4105.c b/src/devices/bus/abcbus/lux4105.c new file mode 100644 index 00000000000..52e0446d86a --- /dev/null +++ b/src/devices/bus/abcbus/lux4105.c @@ -0,0 +1,393 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Luxor 4105 SASI hard disk controller emulation + +*********************************************************************/ + +#include "lux4105.h" +#include "bus/scsi/scsihd.h" +#include "bus/scsi/s1410.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define SASIBUS_TAG "sasi" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type LUXOR_4105 = &device_creator; + + +WRITE_LINE_MEMBER( luxor_4105_device::write_sasi_bsy ) +{ + m_sasi_bsy = state; + + if (state) + { + m_sasibus->write_sel(0); + } +} + +WRITE_LINE_MEMBER( luxor_4105_device::write_sasi_io ) +{ + m_sasi_io = state; + + if (!m_sasi_io) + { + m_sasi_data_out->write(m_data); + } + + update_trrq_int(); +} + +WRITE_LINE_MEMBER( luxor_4105_device::write_sasi_req ) +{ + m_sasi_req = state; + + if (m_sasi_req) + { + m_sasibus->write_ack(0); + } + + update_trrq_int(); +} + +WRITE_LINE_MEMBER( luxor_4105_device::write_sasi_cd ) +{ + m_sasi_cd = state; +} + + +//------------------------------------------------- +// MACHINE_DRIVER( luxor_4105 ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( luxor_4105 ) + MCFG_DEVICE_ADD(SASIBUS_TAG, SCSI_PORT, 0) + MCFG_SCSI_DATA_INPUT_BUFFER("sasi_data_in") + MCFG_SCSI_BSY_HANDLER(WRITELINE(luxor_4105_device, write_sasi_bsy)) + MCFG_SCSI_REQ_HANDLER(WRITELINE(luxor_4105_device, write_sasi_req)) + MCFG_SCSI_CD_HANDLER(WRITELINE(luxor_4105_device, write_sasi_cd)) + MCFG_SCSI_IO_HANDLER(WRITELINE(luxor_4105_device, write_sasi_io)) + MCFG_SCSIDEV_ADD(SASIBUS_TAG ":" SCSI_PORT_DEVICE1, "harddisk", S1410, SCSI_ID_0) + + MCFG_SCSI_OUTPUT_LATCH_ADD("sasi_data_out", SASIBUS_TAG) + MCFG_DEVICE_ADD("sasi_data_in", INPUT_BUFFER, 0) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor luxor_4105_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( luxor_4105 ); +} + + +//------------------------------------------------- +// INPUT_PORTS( luxor_4105 ) +//------------------------------------------------- + +INPUT_PORTS_START( luxor_4105 ) + PORT_START("1E") + PORT_DIPNAME( 0x03, 0x00, "Stepping" ) PORT_DIPLOCATION("1E:1,2") + PORT_DIPSETTING( 0x00, DEF_STR( Normal ) ) + PORT_DIPSETTING( 0x01, "Half (Seagate/Texas)" ) + PORT_DIPSETTING( 0x02, "Half (Tandon)" ) + PORT_DIPSETTING( 0x03, "Buffered" ) + PORT_DIPNAME( 0x0c, 0x00, "Heads" ) PORT_DIPLOCATION("1E:3,4") + PORT_DIPSETTING( 0x00, "2" ) + PORT_DIPSETTING( 0x04, "4" ) + PORT_DIPSETTING( 0x08, "6" ) + PORT_DIPSETTING( 0x0c, "8" ) + PORT_DIPNAME( 0xf0, 0x00, "Drive Type" ) PORT_DIPLOCATION("1E:5,6,7,8") + PORT_DIPSETTING( 0x00, "Seagate ST506" ) + PORT_DIPSETTING( 0x10, "Rodime RO100" ) + PORT_DIPSETTING( 0x20, "Shugart SA600" ) + PORT_DIPSETTING( 0x30, "Seagate ST412" ) + + PORT_START("5E") + PORT_DIPNAME( 0x7f, 0x25, "Card Address" ) PORT_DIPLOCATION("5E:1,2,3,4,5,6,7") + PORT_DIPSETTING( 0x25, "37" ) + PORT_DIPSETTING( 0x2d, "45" ) +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor luxor_4105_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( luxor_4105 ); +} + + +//************************************************************************** +// INLINE HELPERS +//************************************************************************** + +inline void luxor_4105_device::update_trrq_int() +{ + int cd = !m_sasi_cd; + int req = !m_sasi_req; + int trrq = !(cd & !req); + + if (BIT(m_dma, 5)) + { + m_slot->irq_w(trrq ? CLEAR_LINE : ASSERT_LINE); + } + else + { + m_slot->irq_w(CLEAR_LINE); + } + + if (BIT(m_dma, 6)) + { + m_slot->trrq_w(trrq); + } + else + { + m_slot->trrq_w(1); + } +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// luxor_4105_device - constructor +//------------------------------------------------- + +luxor_4105_device::luxor_4105_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, LUXOR_4105, "Luxor 4105", tag, owner, clock, "lux4105", __FILE__), + device_abcbus_card_interface(mconfig, *this), + m_sasibus(*this, SASIBUS_TAG), + m_sasi_data_out(*this, "sasi_data_out"), + m_sasi_data_in(*this, "sasi_data_in"), + m_1e(*this, "1E"), + m_5e(*this, "5E"), + m_cs(false), + m_data(0), + m_dma(0), + m_sasi_bsy(0), + m_sasi_req(0), + m_sasi_cd(0), + m_sasi_io(0) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void luxor_4105_device::device_start() +{ + // state saving + save_item(NAME(m_cs)); + save_item(NAME(m_data)); + save_item(NAME(m_dma)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void luxor_4105_device::device_reset() +{ + m_cs = false; + m_data = 0; + m_dma = 0; + + m_sasibus->write_rst(1); + m_sasibus->write_rst(0); + + m_slot->trrq_w(1); +} + + +//------------------------------------------------- +// abcbus_cs - +//------------------------------------------------- + +void luxor_4105_device::abcbus_cs(UINT8 data) +{ + m_cs = (data == m_5e->read()); +} + + +//------------------------------------------------- +// abcbus_csb - +//------------------------------------------------- + +int luxor_4105_device::abcbus_csb() +{ + return !m_cs; +} + + +//------------------------------------------------- +// abcbus_stat - +//------------------------------------------------- + +UINT8 luxor_4105_device::abcbus_stat() +{ + UINT8 data = 0xff; + + if (m_cs) + { + /* + + bit description + + 0 ? + 1 ? + 2 ? + 3 ? + 4 + 5 + 6 ? (tested at 014D9A, after command 08 sent and 1 byte read from SASI, should be 1) + 7 + + */ + + data = !m_sasi_bsy; + data |= !m_sasi_req << 2; + data |= !m_sasi_cd << 3; + data |= !m_sasi_io << 6; + } + + return data; +} + + +//------------------------------------------------- +// abcbus_inp - +//------------------------------------------------- + +UINT8 luxor_4105_device::abcbus_inp() +{ + UINT8 data = 0xff; + + if (m_cs) + { + if (!m_sasi_bsy) + { + data = m_1e->read(); + } + else + { + if (m_sasi_io) + { + data = m_sasi_data_in->read(); + + if (m_sasi_req) + { + m_sasibus->write_ack(1); + } + } + } + } + + return data; +} + + +//------------------------------------------------- +// abcbus_utp - +//------------------------------------------------- + +void luxor_4105_device::abcbus_out(UINT8 data) +{ + if (m_cs) + { + m_data = data; + + if (!m_sasi_io) + { + m_sasi_data_out->write(m_data); + + if (m_sasi_req) + { + m_sasibus->write_ack(1); + } + } + } +} + + +//------------------------------------------------- +// abcbus_c1 - +//------------------------------------------------- + +void luxor_4105_device::abcbus_c1(UINT8 data) +{ + if (m_cs) + { + m_sasibus->write_sel(1); + } +} + + +//------------------------------------------------- +// abcbus_c3 - +//------------------------------------------------- + +void luxor_4105_device::abcbus_c3(UINT8 data) +{ + if (m_cs) + { + m_data = 0; + m_dma = 0; + + m_sasibus->write_rst(1); + m_sasibus->write_rst(0); + } +} + + +//------------------------------------------------- +// abcbus_c4 - +//------------------------------------------------- + +void luxor_4105_device::abcbus_c4(UINT8 data) +{ + if (m_cs) + { + /* + + bit description + + 0 + 1 + 2 + 3 + 4 + 5 byte interrupt enable? + 6 DMA/CPU mode (1=DMA, 0=CPU)? + 7 error interrupt enable? + + */ + + m_dma = data; + + update_trrq_int(); + } +} diff --git a/src/devices/bus/abcbus/lux4105.h b/src/devices/bus/abcbus/lux4105.h new file mode 100644 index 00000000000..9d1aae90b4b --- /dev/null +++ b/src/devices/bus/abcbus/lux4105.h @@ -0,0 +1,92 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Luxor 4105 SASI hard disk controller emulation + +*********************************************************************/ + +#pragma once + +#ifndef __LUXOR_4105__ +#define __LUXOR_4105__ + + +#include "emu.h" +#include "abcbus.h" +#include "bus/scsi/scsi.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define LUXOR_4105_TAG "luxor_4105" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> luxor_4105_device + +class luxor_4105_device : public device_t, + public device_abcbus_card_interface +{ +public: + // construction/destruction + luxor_4105_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual ioport_constructor device_input_ports() const; + + // not really public + DECLARE_WRITE_LINE_MEMBER( write_sasi_bsy ); + DECLARE_WRITE_LINE_MEMBER( write_sasi_req ); + DECLARE_WRITE_LINE_MEMBER( write_sasi_cd ); + DECLARE_WRITE_LINE_MEMBER( write_sasi_io ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_abcbus_interface overrides + virtual void abcbus_cs(UINT8 data); + virtual int abcbus_csb(); + virtual UINT8 abcbus_inp(); + virtual void abcbus_out(UINT8 data); + virtual UINT8 abcbus_stat(); + virtual void abcbus_c1(UINT8 data); + virtual void abcbus_c3(UINT8 data); + virtual void abcbus_c4(UINT8 data); + +private: + inline void update_trrq_int(); + + required_device m_sasibus; + required_device m_sasi_data_out; + required_device m_sasi_data_in; + required_ioport m_1e; + required_ioport m_5e; + + bool m_cs; + UINT8 m_data; + UINT8 m_dma; + + int m_sasi_bsy; + int m_sasi_req; + int m_sasi_cd; + int m_sasi_io; +}; + + +// device type definition +extern const device_type LUXOR_4105; + + + +#endif diff --git a/src/devices/bus/abcbus/memcard.c b/src/devices/bus/abcbus/memcard.c new file mode 100644 index 00000000000..c7fbd2f3f31 --- /dev/null +++ b/src/devices/bus/abcbus/memcard.c @@ -0,0 +1,163 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Luxor ABC Memory Card 55 10762-01 emulation + +*********************************************************************/ + +/* + +PCB Layout +---------- + +55 10762-01 + +|-----------------------------------| +| | +| | +| | +| | +| ROM3 ROM2 | +| | +| | +| | +| | +| | +| ROM1 ROM0 | +| | +| | +| | +| | +| | +| | +| LS02 LS139 | +| | +| | +| | +| LS367 LS241 LS241 | +| | +| | +| | +| | +|--|-----------------------------|--| + |------------CON1-------------| + +Notes: + All IC's shown. + + ROM0 - Synertek C55022 4Kx8 ROM "DOSDD80" + ROM1 - Motorola MCM2708C 1Kx8 EPROM "9704" + ROM2 - empty socket + ROM3 - empty socket + CON1 - ABC bus connector + +*/ + +#include "memcard.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type ABC_MEMORY_CARD = &device_creator; + + +//------------------------------------------------- +// ROM( abc_dos ) +//------------------------------------------------- + +ROM_START( abc_dos ) + ROM_REGION( 0x1000, "dos", 0 ) + ROM_DEFAULT_BIOS("ufd20") + ROM_SYSTEM_BIOS( 0, "abcdos", "ABC-DOS" ) // Scandia Metric FD2 + ROMX_LOAD( "abcdos.3d", 0x0000, 0x1000, CRC(2cb2192f) SHA1(a6b3a9587714f8db807c05bee6c71c0684363744), ROM_BIOS(1) ) + ROM_SYSTEM_BIOS( 1, "dosdd80", "ABC-DOS DD" ) // ABC 830 + ROMX_LOAD( "dosdd80.3d", 0x0000, 0x1000, CRC(36db4c15) SHA1(ae462633f3a9c142bb029beb14749a84681377fa), ROM_BIOS(2) ) + ROM_SYSTEM_BIOS( 2, "ufd20", "UFD-DOS v.20" ) // ABC 830 + ROMX_LOAD( "ufddos20.3d", 0x0000, 0x1000, CRC(69b09c0b) SHA1(403997a06cf6495b8fa13dc74eff6a64ef7aa53e), ROM_BIOS(3) ) + + ROM_REGION( 0x400, "iec", 0 ) + ROM_LOAD( "iec.4b", 0x000, 0x400, NO_DUMP ) + + ROM_REGION( 0x400, "opt", 0 ) + ROM_LOAD( "spare.4a", 0x000, 0x400, NO_DUMP ) + + ROM_REGION( 0x400, "prn", 0 ) + ROM_LOAD( "printer.3b", 0x000, 0x400, NO_DUMP ) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *abc_memory_card_t::device_rom_region() const +{ + return ROM_NAME( abc_dos ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// abc_memory_card_t - constructor +//------------------------------------------------- + +abc_memory_card_t::abc_memory_card_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, ABC_MEMORY_CARD, "ABC Memory Card", tag, owner, clock, "abc_mem", __FILE__), + device_abcbus_card_interface(mconfig, *this), + m_dos_rom(*this, "dos"), + m_iec_rom(*this, "iec"), + m_opt_rom(*this, "opt"), + m_prn_rom(*this, "prn") +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void abc_memory_card_t::device_start() +{ +} + + + +//************************************************************************** +// ABC BUS INTERFACE +//************************************************************************** + +//------------------------------------------------- +// abcbus_xmemfl - +//------------------------------------------------- + +UINT8 abc_memory_card_t::abcbus_xmemfl(offs_t offset) +{ + UINT8 data = 0xff; + + if (offset >= 0x6000 && offset < 0x7000) + { + data = m_dos_rom->base()[offset & 0xfff]; + } + if (offset >= 0x7000 && offset < 0x7400) + { + data = m_iec_rom->base()[offset & 0x3ff]; + } + if (offset >= 0x7400 && offset < 0x7800) + { + data = m_opt_rom->base()[offset & 0x3ff]; + } + if (offset >= 0x7800 && offset < 0x7c00) + { + data = m_prn_rom->base()[offset & 0x3ff]; + } + + return data; +} diff --git a/src/devices/bus/abcbus/memcard.h b/src/devices/bus/abcbus/memcard.h new file mode 100644 index 00000000000..a3308c47f6f --- /dev/null +++ b/src/devices/bus/abcbus/memcard.h @@ -0,0 +1,56 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Luxor ABC Memory Card 55 10762-01 emulation + +*********************************************************************/ + +#pragma once + +#ifndef __ABC_MEMORY_CARD__ +#define __ABC_MEMORY_CARD__ + +#include "emu.h" +#include "abcbus.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> abc_memory_card_t + +class abc_memory_card_t : public device_t, + public device_abcbus_card_interface +{ +public: + // construction/destruction + abc_memory_card_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + +protected: + // device-level overrides + virtual void device_start(); + + // device_abcbus_interface overrides + virtual void abcbus_cs(UINT8 data) { }; + virtual UINT8 abcbus_xmemfl(offs_t offset); + +private: + required_memory_region m_dos_rom; + required_memory_region m_iec_rom; + required_memory_region m_opt_rom; + required_memory_region m_prn_rom; +}; + + +// device type definition +extern const device_type ABC_MEMORY_CARD; + + + +#endif diff --git a/src/devices/bus/abcbus/ram.c b/src/devices/bus/abcbus/ram.c new file mode 100644 index 00000000000..a91e29bd9c7 --- /dev/null +++ b/src/devices/bus/abcbus/ram.c @@ -0,0 +1,79 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + ABC 80 16 KB RAM expansion card emulation + +*********************************************************************/ + +#include "ram.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type ABC80_16KB_RAM_CARD = &device_creator; + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// abc80_16kb_ram_card_t - constructor +//------------------------------------------------- + +abc80_16kb_ram_card_t::abc80_16kb_ram_card_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, ABC80_16KB_RAM_CARD, "ABC 80 16KB RAM card", tag, owner, clock, "abc80_16kb", __FILE__), + device_abcbus_card_interface(mconfig, *this), + m_ram(*this, "ram") +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void abc80_16kb_ram_card_t::device_start() +{ + m_ram.allocate(0x4000); +} + + + +//************************************************************************** +// ABC BUS INTERFACE +//************************************************************************** + +//------------------------------------------------- +// abcbus_xmemfl - +//------------------------------------------------- + +UINT8 abc80_16kb_ram_card_t::abcbus_xmemfl(offs_t offset) +{ + UINT8 data = 0xff; + + if (offset >= 0x8000 && offset < 0xc000) + { + data = m_ram[offset & 0x3fff]; + } + + return data; +} + + +//------------------------------------------------- +// abcbus_xmemw - +//------------------------------------------------- + +void abc80_16kb_ram_card_t::abcbus_xmemw(offs_t offset, UINT8 data) +{ + if (offset >= 0x8000 && offset < 0xc000) + { + m_ram[offset & 0x3fff] = data; + } +} diff --git a/src/devices/bus/abcbus/ram.h b/src/devices/bus/abcbus/ram.h new file mode 100644 index 00000000000..f7fbd351927 --- /dev/null +++ b/src/devices/bus/abcbus/ram.h @@ -0,0 +1,51 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + ABC 80 16 KB RAM expansion card emulation + +*********************************************************************/ + +#pragma once + +#ifndef __ABC80_16KB_RAM_CARD__ +#define __ABC80_16KB_RAM_CARD__ + +#include "emu.h" +#include "abcbus.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> abc80_16kb_ram_card_t + +class abc80_16kb_ram_card_t : public device_t, + public device_abcbus_card_interface +{ +public: + // construction/destruction + abc80_16kb_ram_card_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // device-level overrides + virtual void device_start(); + + // device_abcbus_interface overrides + virtual void abcbus_cs(UINT8 data) { }; + virtual UINT8 abcbus_xmemfl(offs_t offset); + virtual void abcbus_xmemw(offs_t offset, UINT8 data); + +private: + optional_shared_ptr m_ram; +}; + + +// device type definition +extern const device_type ABC80_16KB_RAM_CARD; + + + +#endif diff --git a/src/devices/bus/abcbus/sio.c b/src/devices/bus/abcbus/sio.c new file mode 100644 index 00000000000..fe4d93ac2e7 --- /dev/null +++ b/src/devices/bus/abcbus/sio.c @@ -0,0 +1,160 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/* +ABC SIO + +PCB Layout +---------- + + |-------------------------------------------| +|-| | +|-| | +|-| Z80SIO CN2 | +|-| | +|-| 4.9152MHz | +|-| | +|-| ROM0 Z80CTC | +|-| CN1 | +|-| ROM1 | + |-------------------------------------------| + +Notes: + Relevant IC's shown. + + ROM0 - Hitachi HN462716 2Kx8 EPROM "SYN 1.6" + ROM1 - Mitsubishi MB8516 2Kx8 EPROM "T80 1.3" + Z80SIO - Zilog Z-80A SIO/0 + Z80CTC - Zilog Z-80A CTC + CN1 - DB9 serial connector + CN2 - DB25 serial connector + +*/ + +#include "sio.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define Z80CTC_TAG "z80ctc" +#define Z80SIO_TAG "z80sio" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type ABC_SIO = &device_creator; + + +//------------------------------------------------- +// ROM( abc_sio ) +//------------------------------------------------- + +ROM_START( abc_sio ) + ROM_REGION( 0x1000, "abc80", 0 ) + ROM_LOAD( "t80 1.3", 0x000, 0x800, CRC(f20ff827) SHA1(a1c4af1c374184a14872d7253d6f9e470603117f) ) + ROM_LOAD( "syn 1.6", 0x800, 0x800, CRC(7bd96b75) SHA1(d1f9b16530be28b03eeddb3f6ee4fa9e1cc9458e) ) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *abc_sio_device::device_rom_region() const +{ + return ROM_NAME( abc_sio ); +} + + +//------------------------------------------------- +// MACHINE_DRIVER( abc_sio ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( abc_sio ) + MCFG_DEVICE_ADD(Z80CTC_TAG, Z80CTC, XTAL_4_9152MHz) + MCFG_Z80DART_ADD(Z80SIO_TAG, 0, 0, 0, 0, 0) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor abc_sio_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( abc_sio ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// abc_sio_device - constructor +//------------------------------------------------- + +abc_sio_device::abc_sio_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, ABC_SIO, "ABC SIO", tag, owner, clock, "abcsio", __FILE__), + device_abcbus_card_interface(mconfig, *this), + m_ctc(*this, Z80CTC_TAG), + m_sio(*this, Z80SIO_TAG), + m_rom(*this, "abc80") +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void abc_sio_device::device_start() +{ +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void abc_sio_device::device_reset() +{ +} + + + +//************************************************************************** +// ABC BUS INTERFACE +//************************************************************************** + +//------------------------------------------------- +// abcbus_cs - +//------------------------------------------------- + +void abc_sio_device::abcbus_cs(UINT8 data) +{ +} + + +//------------------------------------------------- +// abcbus_xmemfl - +//------------------------------------------------- + +UINT8 abc_sio_device::abcbus_xmemfl(offs_t offset) +{ + UINT8 data = 0xff; + + if (offset >= 0x4000 && offset < 0x5000) // TODO where is this mapped? + { + data = m_rom->base()[offset & 0xfff]; + } + + return data; +} diff --git a/src/devices/bus/abcbus/sio.h b/src/devices/bus/abcbus/sio.h new file mode 100644 index 00000000000..6ad8b90df0e --- /dev/null +++ b/src/devices/bus/abcbus/sio.h @@ -0,0 +1,53 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +#pragma once + +#ifndef __ABC_SIO__ +#define __ABC_SIO__ + +#include "emu.h" +#include "abcbus.h" +#include "machine/z80ctc.h" +#include "machine/z80dart.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> abc_sio_device + +class abc_sio_device : public device_t, + public device_abcbus_card_interface +{ +public: + // construction/destruction + abc_sio_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_abcbus_interface overrides + virtual void abcbus_cs(UINT8 data); + virtual UINT8 abcbus_xmemfl(offs_t offset); + +private: + required_device m_ctc; + required_device m_sio; + required_memory_region m_rom; +}; + + +// device type definition +extern const device_type ABC_SIO; + + + +#endif diff --git a/src/devices/bus/abcbus/slutprov.c b/src/devices/bus/abcbus/slutprov.c new file mode 100644 index 00000000000..bd1184c15c5 --- /dev/null +++ b/src/devices/bus/abcbus/slutprov.c @@ -0,0 +1,79 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +#include "slutprov.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type ABC_SLUTPROV = &device_creator; + + +//------------------------------------------------- +// ROM( abc_slutprov ) +//------------------------------------------------- + +ROM_START( abc_slutprov ) + ROM_REGION( 0x800, "slutprov", 0 ) + ROM_LOAD( "slutprov.bin", 0x0000, 0x0800, CRC(a5bb56f4) SHA1(f97cb6526a1d10b189164f26157522e382ca6bc6) ) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *abc_slutprov_device::device_rom_region() const +{ + return ROM_NAME( abc_slutprov ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// abc_slutprov_device - constructor +//------------------------------------------------- + +abc_slutprov_device::abc_slutprov_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, ABC_SLUTPROV, "Slutprov", tag, owner, clock, "slutprov", __FILE__), + device_abcbus_card_interface(mconfig, *this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void abc_slutprov_device::device_start() +{ +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void abc_slutprov_device::device_reset() +{ +} + + + +//************************************************************************** +// ABC BUS INTERFACE +//************************************************************************** + +//------------------------------------------------- +// abcbus_cs - +//------------------------------------------------- + +void abc_slutprov_device::abcbus_cs(UINT8 data) +{ +} diff --git a/src/devices/bus/abcbus/slutprov.h b/src/devices/bus/abcbus/slutprov.h new file mode 100644 index 00000000000..99d0f8bcc3a --- /dev/null +++ b/src/devices/bus/abcbus/slutprov.h @@ -0,0 +1,44 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +#pragma once + +#ifndef __ABC_SLUTPROV__ +#define __ABC_SLUTPROV__ + +#include "emu.h" +#include "abcbus.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> abc_slutprov_device + +class abc_slutprov_device : public device_t, + public device_abcbus_card_interface +{ +public: + // construction/destruction + abc_slutprov_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_abcbus_interface overrides + virtual void abcbus_cs(UINT8 data); +}; + + +// device type definition +extern const device_type ABC_SLUTPROV; + + + +#endif diff --git a/src/devices/bus/abcbus/turbo.c b/src/devices/bus/abcbus/turbo.c new file mode 100644 index 00000000000..55ac6a7fa3d --- /dev/null +++ b/src/devices/bus/abcbus/turbo.c @@ -0,0 +1,149 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + MyAB Turbo-Kontroller disk controller emulation + +*********************************************************************/ + +#include "turbo.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define Z80_TAG "z80" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type TURBO_KONTROLLER = &device_creator; + + +//------------------------------------------------- +// ROM( turbo_kontroller ) +//------------------------------------------------- + +ROM_START( turbo_kontroller ) + ROM_REGION( 0x1000, Z80_TAG, 0 ) + ROM_SYSTEM_BIOS( 0, "525", "5\" 25-pin" ) + ROMX_LOAD( "unidis5d.bin", 0x0000, 0x1000, CRC(569dd60c) SHA1(47b810bcb5a063ffb3034fd7138dc5e15d243676), ROM_BIOS(1) ) + ROM_SYSTEM_BIOS( 1, "534", "5\" 34-pin" ) + ROMX_LOAD( "unidiskh.bin", 0x0000, 0x1000, CRC(5079ad85) SHA1(42bb91318f13929c3a440de3fa1f0491a0b90863), ROM_BIOS(2) ) + ROM_SYSTEM_BIOS( 2, "8", "8\"" ) + ROMX_LOAD( "unidisk8.bin", 0x0000, 0x1000, CRC(d04e6a43) SHA1(8db504d46ff0355c72bd58fd536abeb17425c532), ROM_BIOS(3) ) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *turbo_kontroller_device::device_rom_region() const +{ + return ROM_NAME( turbo_kontroller ); +} + + +//------------------------------------------------- +// ADDRESS_MAP( turbo_kontroller_mem ) +//------------------------------------------------- + +static ADDRESS_MAP_START( turbo_kontroller_mem, AS_PROGRAM, 8, turbo_kontroller_device ) + AM_RANGE(0x0000, 0x0fff) AM_ROM AM_REGION(Z80_TAG, 0) +ADDRESS_MAP_END + + +//------------------------------------------------- +// ADDRESS_MAP( turbo_kontroller_io ) +//------------------------------------------------- + +static ADDRESS_MAP_START( turbo_kontroller_io, AS_IO, 8, turbo_kontroller_device ) +ADDRESS_MAP_END + + +//------------------------------------------------- +// z80_daisy_config daisy_chain +//------------------------------------------------- + +static const z80_daisy_config daisy_chain[] = +{ + { NULL } +}; + + +//------------------------------------------------- +// MACHINE_DRIVER( turbo_kontroller ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( turbo_kontroller ) + MCFG_CPU_ADD(Z80_TAG, Z80, 4000000) + MCFG_CPU_PROGRAM_MAP(turbo_kontroller_mem) + MCFG_CPU_IO_MAP(turbo_kontroller_io) + MCFG_CPU_CONFIG(daisy_chain) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor turbo_kontroller_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( turbo_kontroller ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// turbo_kontroller_device - constructor +//------------------------------------------------- + +turbo_kontroller_device::turbo_kontroller_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, TURBO_KONTROLLER, "Turbo-Kontroller", tag, owner, clock, "unidisk", __FILE__), + device_abcbus_card_interface(mconfig, *this), + m_maincpu(*this, Z80_TAG) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void turbo_kontroller_device::device_start() +{ +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void turbo_kontroller_device::device_reset() +{ +} + + + +//************************************************************************** +// ABC BUS INTERFACE +//************************************************************************** + +//------------------------------------------------- +// abcbus_cs - +//------------------------------------------------- + +void turbo_kontroller_device::abcbus_cs(UINT8 data) +{ +} diff --git a/src/devices/bus/abcbus/turbo.h b/src/devices/bus/abcbus/turbo.h new file mode 100644 index 00000000000..c2242eca29e --- /dev/null +++ b/src/devices/bus/abcbus/turbo.h @@ -0,0 +1,56 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + MyAB Turbo-Kontroller disk controller emulation + +*********************************************************************/ + +#pragma once + +#ifndef __TURBO_KONTROLLER__ +#define __TURBO_KONTROLLER__ + +#include "emu.h" +#include "abcbus.h" +#include "cpu/z80/z80.h" +#include "cpu/z80/z80daisy.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> turbo_kontroller_device + +class turbo_kontroller_device : public device_t, + public device_abcbus_card_interface +{ +public: + // construction/destruction + turbo_kontroller_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_abcbus_interface overrides + virtual void abcbus_cs(UINT8 data); + +private: + required_device m_maincpu; +}; + + +// device type definition +extern const device_type TURBO_KONTROLLER; + + + +#endif diff --git a/src/devices/bus/abcbus/uni800.c b/src/devices/bus/abcbus/uni800.c new file mode 100644 index 00000000000..9d22dc0a6cd --- /dev/null +++ b/src/devices/bus/abcbus/uni800.c @@ -0,0 +1,110 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/* +UNI-800 + +PCB Layout +---------- + +8120 821025 REV.3 + +|-------------------------------------------| +| | +| 4164 PROM0 CN3 | +| 4164 | +| 4164 | +| 4164 | +| 4164 | +| 4164 | +|CN1 4164 CN2 | +| 4164 | +|-------------------------------------------| + +Notes: + Relevant IC's shown. + + 4164 - Hitachi HM4864P-2 64Kx1 RAM + PROM0 - Philips 82S129 256x4 Bipolar PROM ".800 1.2" + CN1 - 2x6 pin PCB header + CN2 - 2x10 pin PCB header + CN3 - 2x10 pin PCB header + +*/ + +#include "uni800.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type ABC_UNI800 = &device_creator; + + +//------------------------------------------------- +// ROM( abc_uni800 ) +//------------------------------------------------- + +ROM_START( abc_uni800 ) + ROM_REGION( 0x100, "uni800", 0 ) + ROM_LOAD( ".800 1.2.bin", 0x0000, 0x0100, CRC(df4897f8) SHA1(0c641f4cf321f0003da3fbd435edb138a9b949b4) ) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *abc_uni800_device::device_rom_region() const +{ + return ROM_NAME( abc_uni800 ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// abc_uni800_device - constructor +//------------------------------------------------- + +abc_uni800_device::abc_uni800_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, ABC_UNI800, "UNI-800", tag, owner, clock, "uni800", __FILE__), + device_abcbus_card_interface(mconfig, *this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void abc_uni800_device::device_start() +{ +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void abc_uni800_device::device_reset() +{ +} + + + +//************************************************************************** +// ABC BUS INTERFACE +//************************************************************************** + +//------------------------------------------------- +// abcbus_cs - +//------------------------------------------------- + +void abc_uni800_device::abcbus_cs(UINT8 data) +{ +} diff --git a/src/devices/bus/abcbus/uni800.h b/src/devices/bus/abcbus/uni800.h new file mode 100644 index 00000000000..37ed2e0917b --- /dev/null +++ b/src/devices/bus/abcbus/uni800.h @@ -0,0 +1,44 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +#pragma once + +#ifndef __ABC_UNI800__ +#define __ABC_UNI800__ + +#include "emu.h" +#include "abcbus.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> abc_uni800_device + +class abc_uni800_device : public device_t, + public device_abcbus_card_interface +{ +public: + // construction/destruction + abc_uni800_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_abcbus_interface overrides + virtual void abcbus_cs(UINT8 data); +}; + + +// device type definition +extern const device_type ABC_UNI800; + + + +#endif diff --git a/src/devices/bus/abckb/abc77.c b/src/devices/bus/abckb/abc77.c new file mode 100644 index 00000000000..c308cd8cf74 --- /dev/null +++ b/src/devices/bus/abckb/abc77.c @@ -0,0 +1,658 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Luxor ABC-55/77 keyboard emulation + +*********************************************************************/ + +/* + +PCB Layout +---------- + +KTC A65-02486-232 + +|-----------------------------------------------------------------------| +| SW1 CN1 LS393 | +| 4020 7406 LS132 7407 LS02 7407 NE556 LS1 | +| | +| 22-950-3B XTAL CPU ROM0 ROM1 LS373 LS240 22-908-03 | +| | +| | +| | +| | +| | +| | +| | +|-----------------------------------------------------------------------| + +Notes: + All IC's shown. + + CPU - Signetics SCN8035A 8035 CPU + ROM0 - NEC D2716D 2Kx8 ROM "-78" + ROM1 - not populated + 22-950-3B - Exar Semiconductor XR22-950-3B keyboard matrix row driver with 4 to 12 decoder/demultiplexer + 22-908-03 - Exar Semiconductor XR22-908-03 keyboard matrix capacitive readout latch + CN1 - 1x12 PCB header + LS1 - loudspeaker + SW1 - reset switch + +*/ + +#include "abc77.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define I8035_TAG "z16" +#define DISCRETE_TAG "discrete" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type ABC77 = &device_creator; +const device_type ABC55 = &device_creator; + + +//------------------------------------------------- +// ROM( abc77 ) +//------------------------------------------------- + +ROM_START( abc77 ) + ROM_REGION( 0x1000, I8035_TAG, 0 ) + ROM_LOAD( "-78.z10", 0x000, 0x800, CRC(635986ce) SHA1(04a30141ac611d0544bbb786061515040c23480c) ) +// ROM_LOAD( "keyboard.z14", 0x0800, 0x0800, NO_DUMP ) // non-Swedish keyboard encoding ROM +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *abc77_device::device_rom_region() const +{ + return ROM_NAME( abc77 ); +} + + +//------------------------------------------------- +// ADDRESS_MAP( abc77_mem ) +//------------------------------------------------- + +static ADDRESS_MAP_START( abc77_map, AS_PROGRAM, 8, abc77_device ) + AM_RANGE(0x000, 0xfff) AM_ROM AM_REGION("z16", 0) +ADDRESS_MAP_END + + +//------------------------------------------------- +// ADDRESS_MAP( abc77_io ) +//------------------------------------------------- + +static ADDRESS_MAP_START( abc77_io, AS_IO, 8, abc77_device ) + AM_RANGE(0x00, 0x00) AM_MIRROR(0xff) AM_WRITE(j3_w) + AM_RANGE(0x00, 0x00) AM_MIRROR(0xff) AM_READ_PORT("DSW") + AM_RANGE(MCS48_PORT_P1, MCS48_PORT_P1) AM_READ(p1_r) + AM_RANGE(MCS48_PORT_P2, MCS48_PORT_P2) AM_WRITE(p2_w) + AM_RANGE(MCS48_PORT_T1, MCS48_PORT_T1) AM_READ(t1_r) + AM_RANGE(MCS48_PORT_PROG, MCS48_PORT_PROG) AM_WRITE(prog_w) +ADDRESS_MAP_END + + +//------------------------------------------------- +// DISCRETE_SOUND( abc77 ) +//------------------------------------------------- + +static const discrete_555_desc abc77_ne556_a = +{ + DISC_555_OUT_SQW | DISC_555_OUT_DC, + 5, // B+ voltage of 555 + DEFAULT_555_VALUES +}; + + +static DISCRETE_SOUND_START( abc77 ) + DISCRETE_INPUT_LOGIC(NODE_01) + DISCRETE_555_ASTABLE(NODE_02, NODE_01, (int) RES_K(2.7), (int) RES_K(15), (int) CAP_N(22), &abc77_ne556_a) + DISCRETE_OUTPUT(NODE_02, 5000) +DISCRETE_SOUND_END + + +//------------------------------------------------- +// MACHINE_DRIVER( abc77 ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( abc77 ) + // keyboard cpu + MCFG_CPU_ADD(I8035_TAG, I8035, XTAL_4_608MHz) + MCFG_CPU_PROGRAM_MAP(abc77_map) + MCFG_CPU_IO_MAP(abc77_io) + + // watchdog + MCFG_WATCHDOG_TIME_INIT(attotime::from_hz(XTAL_4_608MHz/3/5/4096)) + + // discrete sound + MCFG_SPEAKER_STANDARD_MONO("mono") + MCFG_SOUND_ADD(DISCRETE_TAG, DISCRETE, 0) + MCFG_DISCRETE_INTF(abc77) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.80) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor abc77_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( abc77 ); +} + + +//------------------------------------------------- +// INPUT_CHANGED_MEMBER( keyboard_reset ) +//------------------------------------------------- + +INPUT_CHANGED_MEMBER( abc77_device::keyboard_reset ) +{ + if (oldval && !newval) + { + device_reset(); + } +} + + +//------------------------------------------------- +// INPUT_PORTS( abc55 ) +//------------------------------------------------- + +INPUT_PORTS_START( abc55 ) + PORT_START("X0") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("CAPS LOCK") PORT_CODE(KEYCODE_CAPSLOCK) PORT_CHAR(UCHAR_MAMEKEY(CAPSLOCK)) + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("CTRL") PORT_CODE(KEYCODE_LCONTROL) PORT_CHAR(UCHAR_MAMEKEY(LCONTROL)) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("RIGHT SHIFT") PORT_CODE(KEYCODE_RSHIFT) PORT_CHAR(UCHAR_SHIFT_1) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("LEFT SHIFT") PORT_CODE(KEYCODE_LSHIFT) PORT_CHAR(UCHAR_SHIFT_1) + + PORT_START("X1") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNUSED ) + + PORT_START("X2") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_BACKSLASH2) PORT_CHAR('<') PORT_CHAR('>') + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("RETURN") PORT_CODE(KEYCODE_ENTER) PORT_CHAR('\r') + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("\xE2\x86\x90") PORT_CODE(KEYCODE_BACKSPACE) PORT_CHAR(8) + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("\xE2\x86\x92") PORT_CODE(KEYCODE_RIGHT) PORT_CHAR(UCHAR_MAMEKEY(RIGHT)) + + PORT_START("X3") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_EQUALS) PORT_CHAR(0x00E9) PORT_CHAR(0x00C9) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_MINUS) PORT_CHAR('+') PORT_CHAR('?') + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_OPENBRACE) PORT_CHAR(0x00E5) PORT_CHAR(0x00C5) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_CLOSEBRACE) PORT_CHAR(0x00FC) PORT_CHAR(0x00DC) + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_QUOTE) PORT_CHAR(0x00E4) PORT_CHAR(0x00C4) + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_BACKSLASH) PORT_CHAR('\'') PORT_CHAR('*') + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("SPACE") PORT_CODE(KEYCODE_SPACE) PORT_CHAR(' ') + + PORT_START("X4") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_0) PORT_CHAR('0') PORT_CHAR('=') + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_9) PORT_CHAR('9') PORT_CHAR(')') + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_O) PORT_CHAR('o') PORT_CHAR('O') + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_P) PORT_CHAR('p') PORT_CHAR('P') + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_L) PORT_CHAR('l') PORT_CHAR('L') + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_COLON) PORT_CHAR(0x00F6) PORT_CHAR(0x00D6) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_STOP) PORT_CHAR('.') PORT_CHAR(':') + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_SLASH) PORT_CHAR('-') PORT_CHAR('_') + + PORT_START("X5") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_8) PORT_CHAR('8') PORT_CHAR('(') + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_7) PORT_CHAR('7') PORT_CHAR('/') + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_U) PORT_CHAR('u') PORT_CHAR('U') + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_I) PORT_CHAR('i') PORT_CHAR('I') + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_J) PORT_CHAR('j') PORT_CHAR('J') + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_K) PORT_CHAR('k') PORT_CHAR('K') + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_M) PORT_CHAR('m') PORT_CHAR('M') + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_COMMA) PORT_CHAR(',') PORT_CHAR(';') + + PORT_START("X6") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_6) PORT_CHAR('6') PORT_CHAR('&') + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_5) PORT_CHAR('5') PORT_CHAR('%') + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_T) PORT_CHAR('t') PORT_CHAR('T') + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Y) PORT_CHAR('y') PORT_CHAR('Y') + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_G) PORT_CHAR('g') PORT_CHAR('G') + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_H) PORT_CHAR('h') PORT_CHAR('H') + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_B) PORT_CHAR('b') PORT_CHAR('B') + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_N) PORT_CHAR('n') PORT_CHAR('N') + + PORT_START("X7") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("4 \xC2\xA4") PORT_CODE(KEYCODE_4) PORT_CHAR('4') PORT_CHAR(0x00A4) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_3) PORT_CHAR('3') PORT_CHAR('#') + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_E) PORT_CHAR('e') PORT_CHAR('E') + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_R) PORT_CHAR('r') PORT_CHAR('R') + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_D) PORT_CHAR('d') PORT_CHAR('D') + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F) PORT_CHAR('f') PORT_CHAR('F') + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_C) PORT_CHAR('c') PORT_CHAR('C') + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_V) PORT_CHAR('v') PORT_CHAR('V') + + PORT_START("X8") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_2) PORT_CHAR('2') PORT_CHAR('"') + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_1) PORT_CHAR('1') PORT_CHAR('!') + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Q) PORT_CHAR('q') PORT_CHAR('Q') + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_W) PORT_CHAR('w') PORT_CHAR('W') + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_A) PORT_CHAR('a') PORT_CHAR('A') + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_S) PORT_CHAR('s') PORT_CHAR('S') + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Z) PORT_CHAR('z') PORT_CHAR('Z') + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_X) PORT_CHAR('x') PORT_CHAR('X') + + PORT_START("X9") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNUSED ) + + PORT_START("X10") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNUSED ) + + PORT_START("X11") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("PF1") PORT_CODE(KEYCODE_F1) PORT_CHAR(UCHAR_MAMEKEY(F1)) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("PF2") PORT_CODE(KEYCODE_F2) PORT_CHAR(UCHAR_MAMEKEY(F2)) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("PF3") PORT_CODE(KEYCODE_F3) PORT_CHAR(UCHAR_MAMEKEY(F3)) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("PF4") PORT_CODE(KEYCODE_F4) PORT_CHAR(UCHAR_MAMEKEY(F4)) + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("PF5") PORT_CODE(KEYCODE_F5) PORT_CHAR(UCHAR_MAMEKEY(F5)) + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("PF6") PORT_CODE(KEYCODE_F6) PORT_CHAR(UCHAR_MAMEKEY(F6)) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("PF7") PORT_CODE(KEYCODE_F7) PORT_CHAR(UCHAR_MAMEKEY(F7)) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("PF8") PORT_CODE(KEYCODE_F8) PORT_CHAR(UCHAR_MAMEKEY(F8)) + + PORT_START("DSW") + PORT_DIPNAME( 0x01, 0x01, "Keyboard Program" ) + PORT_DIPSETTING( 0x00, "Internal (8048)" ) + PORT_DIPSETTING( 0x01, "External PROM" ) // @ Z10 + PORT_DIPNAME( 0x02, 0x02, "Character Set" ) + PORT_DIPSETTING( 0x02, "Swedish" ) + PORT_DIPSETTING( 0x00, "US ASCII" ) + PORT_DIPNAME( 0x04, 0x04, "External Encoding PROM" ) // @ Z14 + PORT_DIPSETTING( 0x04, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x00, DEF_STR( On ) ) + PORT_DIPNAME( 0x18, 0x18, "Keyboard Language" ) PORT_CONDITION("DSW", 0x04, EQUALS, 0x00) + PORT_DIPSETTING( 0x00, "Danish" ) + PORT_DIPSETTING( 0x10, DEF_STR( French ) ) + PORT_DIPSETTING( 0x08, DEF_STR( German ) ) + PORT_DIPSETTING( 0x18, DEF_STR( Spanish ) ) + PORT_BIT( 0xe0, IP_ACTIVE_LOW, IPT_UNUSED) + + PORT_START("SW1") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_SPECIAL ) PORT_NAME("Keyboard Reset") PORT_CHANGED_MEMBER(DEVICE_SELF, abc77_device, keyboard_reset, 0) +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor abc55_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( abc55 ); +} + + +//------------------------------------------------- +// INPUT_PORTS( abc77 ) +//------------------------------------------------- + +INPUT_PORTS_START( abc77 ) + PORT_INCLUDE( abc55 ) + + PORT_MODIFY("X9") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad 9") PORT_CODE(KEYCODE_9_PAD) PORT_CHAR(UCHAR_MAMEKEY(9_PAD)) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad +") PORT_CODE(KEYCODE_PLUS_PAD) PORT_CHAR(UCHAR_MAMEKEY(PLUS_PAD)) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad 6") PORT_CODE(KEYCODE_6_PAD) PORT_CHAR(UCHAR_MAMEKEY(6_PAD)) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad -") PORT_CODE(KEYCODE_MINUS_PAD) PORT_CHAR(UCHAR_MAMEKEY(MINUS_PAD)) + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad 3") PORT_CODE(KEYCODE_3_PAD) PORT_CHAR(UCHAR_MAMEKEY(3_PAD)) + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad RETURN") PORT_CODE(KEYCODE_ENTER_PAD) PORT_CHAR(UCHAR_MAMEKEY(ENTER_PAD)) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad .") PORT_CODE(KEYCODE_DEL_PAD) PORT_CHAR(UCHAR_MAMEKEY(DEL_PAD)) + + PORT_MODIFY("X10") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad 7") PORT_CODE(KEYCODE_7_PAD) PORT_CHAR(UCHAR_MAMEKEY(7_PAD)) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad 8") PORT_CODE(KEYCODE_8_PAD) PORT_CHAR(UCHAR_MAMEKEY(8_PAD)) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad 4") PORT_CODE(KEYCODE_4_PAD) PORT_CHAR(UCHAR_MAMEKEY(4_PAD)) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad 5") PORT_CODE(KEYCODE_5_PAD) PORT_CHAR(UCHAR_MAMEKEY(5_PAD)) + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad 1") PORT_CODE(KEYCODE_1_PAD) PORT_CHAR(UCHAR_MAMEKEY(1_PAD)) + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad 2") PORT_CODE(KEYCODE_2_PAD) PORT_CHAR(UCHAR_MAMEKEY(2_PAD)) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad 0") PORT_CODE(KEYCODE_0_PAD) PORT_CHAR(UCHAR_MAMEKEY(0_PAD)) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNUSED ) +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor abc77_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( abc77 ); +} + + + +//************************************************************************** +// INLINE HELPERS +//************************************************************************** + +//------------------------------------------------- +// serial_output - +//------------------------------------------------- + +inline void abc77_device::serial_output(int state) +{ + if (m_txd != state) + { + m_txd = state; + + m_slot->write_rx(m_txd); + } +} + + +//------------------------------------------------- +// serial_clock - +//------------------------------------------------- + +inline void abc77_device::serial_clock() +{ + m_clock = !m_clock; + + m_slot->trxc_w(!m_clock); +} + + +//------------------------------------------------- +// keydown - +//------------------------------------------------- + +inline void abc77_device::key_down(int state) +{ + if (m_keydown != state) + { + m_slot->keydown_w(state); + m_keydown = state; + } +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// abc77_device - constructor +//------------------------------------------------- + +abc77_device::abc77_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, ABC77, "Luxor ABC 77", tag, owner, clock, "abc77", __FILE__), + abc_keyboard_interface(mconfig, *this), + m_maincpu(*this, I8035_TAG), + m_discrete(*this, DISCRETE_TAG), + m_x0(*this, "X0"), + m_x1(*this, "X1"), + m_x2(*this, "X2"), + m_x3(*this, "X3"), + m_x4(*this, "X4"), + m_x5(*this, "X5"), + m_x6(*this, "X6"), + m_x7(*this, "X7"), + m_x8(*this, "X8"), + m_x9(*this, "X9"), + m_x10(*this, "X10"), + m_x11(*this, "X11"), + m_dsw(*this, "DSW"), + m_txd(1), + m_keydown(1), + m_clock(0), + m_stb(1) +{ +} + +abc77_device::abc77_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + abc_keyboard_interface(mconfig, *this), + m_maincpu(*this, I8035_TAG), + m_discrete(*this, DISCRETE_TAG), + m_x0(*this, "X0"), + m_x1(*this, "X1"), + m_x2(*this, "X2"), + m_x3(*this, "X3"), + m_x4(*this, "X4"), + m_x5(*this, "X5"), + m_x6(*this, "X6"), + m_x7(*this, "X7"), + m_x8(*this, "X8"), + m_x9(*this, "X9"), + m_x10(*this, "X10"), + m_x11(*this, "X11"), + m_dsw(*this, "DSW"), + m_txd(1), + m_keydown(1), + m_clock(0), + m_stb(1) +{ +} + +abc55_device::abc55_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + abc77_device(mconfig, ABC55, "Luxor ABC 55", tag, owner, clock, "abc55", __FILE__) { } + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void abc77_device::device_start() +{ + // allocate timers + m_serial_timer = timer_alloc(TIMER_SERIAL); + m_serial_timer->adjust(attotime::from_hz(19200), 0, attotime::from_hz(19200)); // ALE/32 + + m_reset_timer = timer_alloc(TIMER_RESET); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void abc77_device::device_reset() +{ + int t = 1.1 * RES_K(100) * CAP_N(100) * 1000; // t = 1.1 * R1 * C1 + int ea = BIT(m_dsw->read(), 7); + + // trigger reset + m_maincpu->set_input_line(INPUT_LINE_RESET, ASSERT_LINE); + m_reset_timer->adjust(attotime::from_msec(t)); + + m_maincpu->set_input_line(MCS48_INPUT_EA, ea ? CLEAR_LINE : ASSERT_LINE); + + m_slot->write_rx(1); +} + + +//------------------------------------------------- +// device_timer - handler timer events +//------------------------------------------------- + +void abc77_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch (id) + { + case TIMER_SERIAL: + serial_clock(); + break; + + case TIMER_RESET: + m_maincpu->set_input_line(INPUT_LINE_RESET, CLEAR_LINE); + break; + } +} + + +//------------------------------------------------- +// txd_w - +//------------------------------------------------- + +void abc77_device::txd_w(int state) +{ + m_maincpu->set_input_line(MCS48_INPUT_IRQ, state ? CLEAR_LINE : ASSERT_LINE); +} + + +//------------------------------------------------- +// p1_r - +//------------------------------------------------- + +READ8_MEMBER( abc77_device::p1_r ) +{ + /* + + bit description + + P10 Z17 Y0 + P11 Z17 Y1 + P12 Z17 Y2 + P13 Z17 Y3 + P14 Z17 Y4 + P15 Z17 Y5 + P16 Z17 Y6 + P17 Z17 Y7 + + */ + + UINT8 data = 0xff; + + if (m_stb) + { + switch (m_keylatch) + { + case 0: data = m_x0->read(); break; + case 1: data = m_x1->read(); break; + case 2: data = m_x2->read(); break; + case 3: data = m_x3->read(); break; + case 4: data = m_x4->read(); break; + case 5: data = m_x5->read(); break; + case 6: data = m_x6->read(); break; + case 7: data = m_x7->read(); break; + case 8: data = m_x8->read(); break; + case 9: data = m_x9->read(); break; + case 10: data = m_x10->read(); break; + case 11: data = m_x11->read(); break; + } + } + + return data; +} + + +//------------------------------------------------- +// p2_w - +//------------------------------------------------- + +WRITE8_MEMBER( abc77_device::p2_w ) +{ + /* + + bit description + + P20 Z2 A0 + P21 Z2 A1 + P22 Z2 A2 + P23 Z2 A3 + P24 NE556 2,6 + P25 TxD + P26 _KEYDOWN + P27 Z17 HYS + + */ + + if (!m_stb) + { + m_keylatch = data & 0x0f; + + if (m_keylatch == 1) + { + machine().watchdog_reset(); + } + } + + // beep + m_discrete->write(space, NODE_01, BIT(data, 4)); + + // transmit data + serial_output(BIT(data, 5)); + + // key down + key_down(BIT(data, 6)); + + // hysteresis + m_hys = BIT(data, 7); +} + + +//------------------------------------------------- +// t1_r - +//------------------------------------------------- + +READ8_MEMBER( abc77_device::t1_r ) +{ + return m_clock; +} + + +//------------------------------------------------- +// prog_w - +//------------------------------------------------- + +WRITE8_MEMBER( abc77_device::prog_w ) +{ + m_stb = BIT(data, 0); +} + + +//------------------------------------------------- +// j3_w - +//------------------------------------------------- + +WRITE8_MEMBER( abc77_device::j3_w ) +{ + m_j3 = data; +} diff --git a/src/devices/bus/abckb/abc77.h b/src/devices/bus/abckb/abc77.h new file mode 100644 index 00000000000..5ead0a32f96 --- /dev/null +++ b/src/devices/bus/abckb/abc77.h @@ -0,0 +1,116 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Luxor ABC-55/77 keyboard emulation + +*********************************************************************/ + +#pragma once + +#ifndef __ABC77__ +#define __ABC77__ + +#include "emu.h" +#include "cpu/mcs48/mcs48.h" +#include "abckb.h" +#include "sound/discrete.h" +#include "sound/speaker.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> abc77_device + +class abc77_device : public device_t, + public abc_keyboard_interface +{ +public: + // construction/destruction + abc77_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + abc77_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + virtual ioport_constructor device_input_ports() const; + + // abc_keyboard_interface overrides + virtual void txd_w(int state); + + DECLARE_INPUT_CHANGED_MEMBER( keyboard_reset ); + + DECLARE_READ8_MEMBER( p1_r ); + DECLARE_WRITE8_MEMBER( p2_w ); + DECLARE_READ8_MEMBER( t1_r ); + DECLARE_WRITE8_MEMBER( prog_w ); + DECLARE_WRITE8_MEMBER( j3_w ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + enum + { + TIMER_SERIAL, + TIMER_RESET + }; + + inline void serial_output(int state); + inline void serial_clock(); + inline void key_down(int state); + + required_device m_maincpu; + required_device m_discrete; + required_ioport m_x0; + required_ioport m_x1; + required_ioport m_x2; + required_ioport m_x3; + required_ioport m_x4; + required_ioport m_x5; + required_ioport m_x6; + required_ioport m_x7; + required_ioport m_x8; + required_ioport m_x9; + required_ioport m_x10; + required_ioport m_x11; + required_ioport m_dsw; + + int m_txd; // transmit data + int m_keylatch; // keyboard row latch + int m_keydown; // key down + int m_clock; // transmit clock + int m_hys; // hysteresis + int m_reset; // reset + int m_stb; // strobe + UINT8 m_j3; + + // timers + emu_timer *m_serial_timer; + emu_timer *m_reset_timer; +}; + + +class abc55_device : public abc77_device +{ +public: + // construction/destruction + abc55_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual ioport_constructor device_input_ports() const; +}; + + +// device type definition +extern const device_type ABC77; +extern const device_type ABC55; + + + +#endif diff --git a/src/devices/bus/abckb/abc800kb.c b/src/devices/bus/abckb/abc800kb.c new file mode 100644 index 00000000000..dd3cbbc7f51 --- /dev/null +++ b/src/devices/bus/abckb/abc800kb.c @@ -0,0 +1,507 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Luxor ABC-800 keyboard emulation + +**********************************************************************/ + +/* + +PCB Layout +---------- + +KTC A65-02201-201K + + |---------------| +|---| CN1 |---------------------------------------------------| +| | +| LS193 LS374 8048 22-008-03 | +| LS13 LS193 22-050-3B 5.9904MHz | +| | +| | +| | +| | +| | +| | +| | +| | +|-----------------------------------------------------------------------| + +Notes: + All IC's shown. + + 8048 - National Semiconductor INS8048 MCU "8048-132" + 22-008-03 - Exar Semiconductor XR22-008-03 keyboard matrix capacitive readout latch + 22-050-3B - Exar Semiconductor XR22-050-3B keyboard matrix row driver with 4 to 12 decoder/demultiplexer + CN1 - keyboard data connector + + +XR22-008-03 Pinout +------------------ + _____ _____ + D0 1 |* \_/ | 20 Vcc + D1 2 | | 19 _CLR + D2 3 | | 18 Q0 + D3 4 | | 17 Q1 + HYS 5 | 22-008-03 | 16 Q2 + D4 6 | | 15 Q3 + D5 7 | | 14 Q4 + D6 8 | | 13 Q5 + D7 9 | | 12 Q6 + GND 10 |_____________| 11 Q7 + + +XR22-050-3B Pinout +------------------ + _____ _____ + Y8 1 |* \_/ | 20 Vcc + Y9 2 | | 19 Y7 + Y10 3 | | 18 Y6 + Y11 4 | | 17 Y5 + _STB 5 | 22-050-3B | 16 Y4 + A0 6 | | 15 Y3 + A1 7 | | 14 Y2 + A2 8 | | 13 Y1 + A3 9 | | 12 Y0 + GND 10 |_____________| 11 OE? + +*/ + +#include "abc800kb.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define I8048_TAG "i8048" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type ABC800_KEYBOARD = &device_creator; + + +//------------------------------------------------- +// ROM( abc800_keyboard ) +//------------------------------------------------- + +ROM_START( abc800_keyboard ) + ROM_REGION( 0x400, I8048_TAG, 0 ) + ROM_LOAD( "8048-132.z9", 0x0000, 0x0400, CRC(05c4dce5) SHA1(1824c5d304bbd09f97056cfa408e1b18b5219ba2) ) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *abc800_keyboard_device::device_rom_region() const +{ + return ROM_NAME( abc800_keyboard ); +} + + +//------------------------------------------------- +// ADDRESS_MAP( abc800_keyboard_io ) +//------------------------------------------------- + +static ADDRESS_MAP_START( abc800_keyboard_io, AS_IO, 8, abc800_keyboard_device ) + AM_RANGE(MCS48_PORT_P1, MCS48_PORT_P1) AM_READWRITE(kb_p1_r, kb_p1_w) + AM_RANGE(MCS48_PORT_P2, MCS48_PORT_P2) AM_WRITE(kb_p2_w) + AM_RANGE(MCS48_PORT_T1, MCS48_PORT_T1) AM_READ(kb_t1_r) +ADDRESS_MAP_END + + +//------------------------------------------------- +// MACHINE_DRIVER( abc800_keyboard ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( abc800_keyboard ) + MCFG_CPU_ADD(I8048_TAG, I8048, XTAL_5_9904MHz) + MCFG_CPU_IO_MAP(abc800_keyboard_io) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor abc800_keyboard_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( abc800_keyboard ); +} + + +//------------------------------------------------- +// INPUT_PORTS( abc800_keyboard ) +//------------------------------------------------- + +INPUT_PORTS_START( abc800_keyboard ) + PORT_START("X0") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_1) PORT_CHAR('1') PORT_CHAR('!') + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("CAPS LOCK") PORT_CODE(KEYCODE_CAPSLOCK) PORT_CHAR(UCHAR_MAMEKEY(CAPSLOCK)) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("CTRL") PORT_CODE(KEYCODE_LCONTROL) PORT_CHAR(UCHAR_MAMEKEY(LCONTROL)) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Left SHIFT") PORT_CODE(KEYCODE_LSHIFT) PORT_CHAR(UCHAR_SHIFT_1) + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_UNUSED ) // 80 + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_UNUSED ) // 81 + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNUSED ) // 82 + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNUSED ) // 83 + + PORT_START("X1") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_2) PORT_CHAR('2') PORT_CHAR('"') + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Q) PORT_CHAR('q') PORT_CHAR('Q') + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_A) PORT_CHAR('a') PORT_CHAR('A') + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Z) PORT_CHAR('z') PORT_CHAR('Z') + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad -") PORT_CODE(KEYCODE_MINUS_PAD) PORT_CHAR(UCHAR_MAMEKEY(MINUS_PAD)) + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad RETURN") PORT_CODE(KEYCODE_ENTER_PAD) PORT_CHAR(UCHAR_MAMEKEY(ENTER_PAD)) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNUSED ) // 84 + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNUSED ) // 85 + + PORT_START("X2") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_3) PORT_CHAR('3') PORT_CHAR('#') + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_W) PORT_CHAR('w') PORT_CHAR('W') + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_S) PORT_CHAR('s') PORT_CHAR('S') + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_X) PORT_CHAR('x') PORT_CHAR('X') + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_UNUSED ) // 18 + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad 6") PORT_CODE(KEYCODE_6_PAD) PORT_CHAR(UCHAR_MAMEKEY(6_PAD)) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad 3") PORT_CODE(KEYCODE_3_PAD) PORT_CHAR(UCHAR_MAMEKEY(3_PAD)) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNUSED ) // 86 + + PORT_START("X3") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("4 \xC2\xA4") PORT_CODE(KEYCODE_4) PORT_CHAR('4') PORT_CHAR(0x00A4) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_E) PORT_CHAR('e') PORT_CHAR('E') + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_D) PORT_CHAR('d') PORT_CHAR('D') + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_C) PORT_CHAR('c') PORT_CHAR('C') + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad 9") PORT_CODE(KEYCODE_9_PAD) PORT_CHAR(UCHAR_MAMEKEY(9_PAD)) + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad 5") PORT_CODE(KEYCODE_5_PAD) PORT_CHAR(UCHAR_MAMEKEY(5_PAD)) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad 2") PORT_CODE(KEYCODE_2_PAD) PORT_CHAR(UCHAR_MAMEKEY(2_PAD)) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("SPACE") PORT_CODE(KEYCODE_SPACE) PORT_CHAR(' ') + + PORT_START("X4") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_5) PORT_CHAR('5') PORT_CHAR('%') + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_R) PORT_CHAR('r') PORT_CHAR('R') + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F) PORT_CHAR('f') PORT_CHAR('F') + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_V) PORT_CHAR('v') PORT_CHAR('V') + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad 8") PORT_CODE(KEYCODE_8_PAD) PORT_CHAR(UCHAR_MAMEKEY(8_PAD)) + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad 4") PORT_CODE(KEYCODE_4_PAD) PORT_CHAR(UCHAR_MAMEKEY(4_PAD)) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad 1") PORT_CODE(KEYCODE_1_PAD) PORT_CHAR(UCHAR_MAMEKEY(1_PAD)) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad .") PORT_CODE(KEYCODE_DEL_PAD) PORT_CHAR(UCHAR_MAMEKEY(DEL_PAD)) + + PORT_START("X5") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_6) PORT_CHAR('6') PORT_CHAR('&') + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_T) PORT_CHAR('t') PORT_CHAR('T') + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_G) PORT_CHAR('g') PORT_CHAR('G') + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_B) PORT_CHAR('b') PORT_CHAR('B') + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad 7") PORT_CODE(KEYCODE_7_PAD) PORT_CHAR(UCHAR_MAMEKEY(7_PAD)) + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("PF4") PORT_CODE(KEYCODE_F4) PORT_CHAR(UCHAR_MAMEKEY(F4)) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("PF6") PORT_CODE(KEYCODE_F6) PORT_CHAR(UCHAR_MAMEKEY(F6)) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad 0") PORT_CODE(KEYCODE_0_PAD) PORT_CHAR(UCHAR_MAMEKEY(0_PAD)) + + PORT_START("X6") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_7) PORT_CHAR('7') PORT_CHAR('/') + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Y) PORT_CHAR('y') PORT_CHAR('Y') + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_H) PORT_CHAR('h') PORT_CHAR('H') + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_N) PORT_CHAR('n') PORT_CHAR('N') + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("PF2") PORT_CODE(KEYCODE_F2) PORT_CHAR(UCHAR_MAMEKEY(F2)) + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("PF3") PORT_CODE(KEYCODE_F3) PORT_CHAR(UCHAR_MAMEKEY(F3)) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("PF5") PORT_CODE(KEYCODE_F5) PORT_CHAR(UCHAR_MAMEKEY(F5)) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("PF8") PORT_CODE(KEYCODE_F8) PORT_CHAR(UCHAR_MAMEKEY(F8)) + + PORT_START("X7") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_8) PORT_CHAR('8') PORT_CHAR('(') + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_U) PORT_CHAR('u') PORT_CHAR('U') + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_J) PORT_CHAR('j') PORT_CHAR('J') + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_M) PORT_CHAR('m') PORT_CHAR('M') + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("PF1") PORT_CODE(KEYCODE_F1) PORT_CHAR(UCHAR_MAMEKEY(F1)) + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("RETURN") PORT_CODE(KEYCODE_ENTER) PORT_CHAR('\r') + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME(UTF8_LEFT) PORT_CODE(KEYCODE_BACKSPACE) PORT_CHAR(8) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("PF7") PORT_CODE(KEYCODE_F7) PORT_CHAR(UCHAR_MAMEKEY(F7)) + + PORT_START("X8") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_9) PORT_CHAR('9') PORT_CHAR(')') + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_I) PORT_CHAR('i') PORT_CHAR('I') + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_K) PORT_CHAR('k') PORT_CHAR('K') + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_COMMA) PORT_CHAR(',') PORT_CHAR(';') + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_BACKSLASH) PORT_CHAR('<') PORT_CHAR('>') + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME(u_UMLAUT " " U_UMLAUT) PORT_CODE(KEYCODE_CLOSEBRACE) PORT_CHAR(0x00FC) PORT_CHAR(0x00DC) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_BACKSLASH2) PORT_CHAR('\'') PORT_CHAR('*') + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME(UTF8_RIGHT) PORT_CODE(KEYCODE_TAB) PORT_CHAR(UCHAR_MAMEKEY(TAB)) + + PORT_START("X9") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_0) PORT_CHAR('0') PORT_CHAR('=') + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_O) PORT_CHAR('o') PORT_CHAR('O') + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_L) PORT_CHAR('l') PORT_CHAR('L') + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_STOP) PORT_CHAR('.') PORT_CHAR(':') + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME(e_ACUTE " " E_ACUTE) PORT_CODE(KEYCODE_EQUALS) PORT_CHAR(0x00E9) PORT_CHAR(0x00C9) + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME(a_RING " " A_RING) PORT_CODE(KEYCODE_OPENBRACE) PORT_CHAR(0x00E5) PORT_CHAR(0x00C5) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME(a_UMLAUT " " A_UMLAUT) PORT_CODE(KEYCODE_QUOTE) PORT_CHAR(0x00E4) PORT_CHAR(0x00C4) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Right SHIFT") PORT_CODE(KEYCODE_RSHIFT) + + PORT_START("X10") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_MINUS) PORT_CHAR('+') PORT_CHAR('?') + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_P) PORT_CHAR('p') PORT_CHAR('P') + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME(o_UMLAUT " " O_UMLAUT) PORT_CODE(KEYCODE_COLON) PORT_CHAR(0x00F6) PORT_CHAR(0x00D6) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_SLASH) PORT_CHAR('-') PORT_CHAR('_') + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_UNUSED ) // 87 + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_UNUSED ) // 88 + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNUSED ) // 89 + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNUSED ) // 8a + + PORT_START("X11") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_UNUSED ) // 03 + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_UNUSED ) // 23 + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_UNUSED ) // 96 + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_UNUSED ) // 8b + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_UNUSED ) // 8c + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_UNUSED ) // 8d + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNUSED ) // 8e + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNUSED ) // 8f +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor abc800_keyboard_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( abc800_keyboard ); +} + + + +//************************************************************************** +// INLINE HELPERS +//************************************************************************** + +//------------------------------------------------- +// serial_output - +//------------------------------------------------- + +inline void abc800_keyboard_device::serial_output(int state) +{ + if (m_txd != state) + { + m_txd = state; + + m_slot->write_rx(m_txd); + } +} + + +//------------------------------------------------- +// serial_clock - +//------------------------------------------------- + +inline void abc800_keyboard_device::serial_clock() +{ + m_clk = !m_clk; + + m_slot->trxc_w(!m_clk); +} + + +//------------------------------------------------- +// keydown - +//------------------------------------------------- + +inline void abc800_keyboard_device::key_down(int state) +{ + if (m_keydown != state) + { + m_keydown = state; + + m_slot->keydown_w(state); + } +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// abc800_keyboard_device - constructor +//------------------------------------------------- + +abc800_keyboard_device::abc800_keyboard_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, ABC800_KEYBOARD, "ABC-800 Keyboard", tag, owner, clock, "abc800kb", __FILE__), + abc_keyboard_interface(mconfig, *this), + m_maincpu(*this, I8048_TAG), + m_x0(*this, "X0"), + m_x1(*this, "X1"), + m_x2(*this, "X2"), + m_x3(*this, "X3"), + m_x4(*this, "X4"), + m_x5(*this, "X5"), + m_x6(*this, "X6"), + m_x7(*this, "X7"), + m_x8(*this, "X8"), + m_x9(*this, "X9"), + m_x10(*this, "X10"), + m_x11(*this, "X11"), + m_row(0), + m_txd(1), + m_clk(0), + m_stb(1), + m_keydown(1) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void abc800_keyboard_device::device_start() +{ + // allocate timers + m_serial_timer = timer_alloc(); + m_serial_timer->adjust(attotime::from_hz(XTAL_5_9904MHz/(3*5)/20), 0, attotime::from_hz(XTAL_5_9904MHz/(3*5)/20)); // ??? + + // state saving + save_item(NAME(m_row)); + save_item(NAME(m_clk)); + save_item(NAME(m_txd)); + save_item(NAME(m_stb)); + save_item(NAME(m_keydown)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void abc800_keyboard_device::device_reset() +{ +} + + +//------------------------------------------------- +// device_timer - handler timer events +//------------------------------------------------- + +void abc800_keyboard_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + serial_clock(); +} + + +//------------------------------------------------- +// txd_w - +//------------------------------------------------- + +void abc800_keyboard_device::txd_w(int state) +{ + m_maincpu->set_input_line(MCS48_INPUT_IRQ, state ? CLEAR_LINE : ASSERT_LINE); +} + + +//------------------------------------------------- +// kb_p1_r - keyboard column data read +//------------------------------------------------- + +READ8_MEMBER( abc800_keyboard_device::kb_p1_r ) +{ + UINT8 data = 0xff; + + if (m_stb) + { + switch (m_row) + { + case 0: data = m_x0->read(); break; + case 1: data = m_x1->read(); break; + case 2: data = m_x2->read(); break; + case 3: data = m_x3->read(); break; + case 4: data = m_x4->read(); break; + case 5: data = m_x5->read(); break; + case 6: data = m_x6->read(); break; + case 7: data = m_x7->read(); break; + case 8: data = m_x8->read(); break; + case 9: data = m_x9->read(); break; + case 10: data = m_x10->read(); break; + case 11: data = m_x11->read(); break; + } + } + + return data; +} + + +//------------------------------------------------- +// kb_p1_w - keyboard row write +//------------------------------------------------- + +WRITE8_MEMBER( abc800_keyboard_device::kb_p1_w ) +{ + /* + + bit description + + 0 A0 + 1 A1 + 2 A2 + 3 A3 + 4 ? + 5 ? + 6 + 7 + + */ + + // keyboard row + if (!m_stb) + { + m_row = data & 0x0f; + } +} + + +//------------------------------------------------- +// kb_p2_w - keyboard control write +//------------------------------------------------- + +WRITE8_MEMBER( abc800_keyboard_device::kb_p2_w ) +{ + /* + + bit description + + 0 + 1 + 2 + 3 + 4 TxD + 5 ? + 6 22-008-03 CLR, 22-050-3B STB + 7 22-008-03 HYS + + */ + + // TxD + serial_output(!BIT(data, 4)); + + // keydown + key_down(!BIT(data, 5)); + + // strobe + m_stb = BIT(data, 6); +} + + +//------------------------------------------------- +// kb_t1_r - keyboard T1 timer read +//------------------------------------------------- + +READ8_MEMBER( abc800_keyboard_device::kb_t1_r ) +{ + return m_clk; +} diff --git a/src/devices/bus/abckb/abc800kb.h b/src/devices/bus/abckb/abc800kb.h new file mode 100644 index 00000000000..52719062314 --- /dev/null +++ b/src/devices/bus/abckb/abc800kb.h @@ -0,0 +1,90 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Luxor ABC-800 keyboard emulation + +**********************************************************************/ + +#pragma once + +#ifndef __ABC800_KEYBOARD__ +#define __ABC800_KEYBOARD__ + + +#include "emu.h" +#include "cpu/mcs48/mcs48.h" +#include "abckb.h" +#include "sound/discrete.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> abc800_keyboard_device + +class abc800_keyboard_device : public device_t, + public abc_keyboard_interface +{ +public: + // construction/destruction + abc800_keyboard_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + virtual ioport_constructor device_input_ports() const; + + // abc_keyboard_interface overrides + virtual void txd_w(int state); + + // not really public + DECLARE_READ8_MEMBER( kb_p1_r ); + DECLARE_WRITE8_MEMBER( kb_p1_w ); + DECLARE_WRITE8_MEMBER( kb_p2_w ); + DECLARE_READ8_MEMBER( kb_t1_r ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + +private: + inline void serial_output(int state); + inline void serial_clock(); + inline void key_down(int state); + + required_device m_maincpu; + required_ioport m_x0; + required_ioport m_x1; + required_ioport m_x2; + required_ioport m_x3; + required_ioport m_x4; + required_ioport m_x5; + required_ioport m_x6; + required_ioport m_x7; + required_ioport m_x8; + required_ioport m_x9; + required_ioport m_x10; + required_ioport m_x11; + + int m_row; + int m_txd; + int m_clk; + int m_stb; + int m_keydown; + + // timers + emu_timer *m_serial_timer; +}; + + +// device type definition +extern const device_type ABC800_KEYBOARD; + + + +#endif diff --git a/src/devices/bus/abckb/abc99.c b/src/devices/bus/abckb/abc99.c new file mode 100644 index 00000000000..63a3f0154f0 --- /dev/null +++ b/src/devices/bus/abckb/abc99.c @@ -0,0 +1,782 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Luxor ABC-99 keyboard and mouse emulation + +*********************************************************************/ + +/* + +Keyboard PCB Layout +------------------- + +|-----------------------------------------------------------------------| +| CN1 CN2 CPU1 ROM1 SW1 | +| | +| 6MHz CPU0 ROM0 GI | +| | +| | +| | +| | +| | +| | +| | +| | +|-----------------------------------------------------------------------| + +Notes: + Relevant IC's shown. + + CPU0 - STMicro ET8035N-6 8035 CPU + CPU1 - STMicro ET8035N-6 8035 CPU + ROM0 - Texas Instruments TMS2516JL-16 2Kx8 ROM "107268-16" + ROM1 - STMicro ET2716Q-1 2Kx8 ROM "107268-17" + GI - General Instruments 321239007 keyboard chip "4=7" + CN1 - DB15 connector, Luxor ABC R8 (3 button mouse) + CN2 - 12 pin PCB header, keyboard data cable + SW1 - reset switch? + +*/ + +/* + + TODO: + + - verify cursor keys + - language DIP + - mouse + - MCS-48 PC:01DC - Unimplemented opcode = 75 + - 75 = ENT0 CLK : enable CLK (unscaled_clock/3) output on T0 + - halt Z2 when Z5 is reset, resume Z2 when Z5 executes ENT0 CLK instruction + +*/ + +#include "abc99.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define I8035_Z2_TAG "z2" +#define I8035_Z5_TAG "z5" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type ABC99 = &device_creator; + + +//------------------------------------------------- +// ROM( abc99 ) +//------------------------------------------------- + +ROM_START( abc99 ) + ROM_REGION( 0x1000, I8035_Z2_TAG, 0 ) + ROM_DEFAULT_BIOS("107268") + ROM_SYSTEM_BIOS( 0, "107268", "107268-17" ) + ROMX_LOAD( "107268-17.z3", 0x0000, 0x0800, CRC(2f60cc35) SHA1(ebc6af9cd0a49a0d01698589370e628eebb6221c), ROM_BIOS(1) ) + ROM_SYSTEM_BIOS( 1, "106819", "106819-09" ) + ROMX_LOAD( "106819-09.z3", 0x0000, 0x1000, CRC(ffe32a71) SHA1(fa2ce8e0216a433f9bbad0bdd6e3dc0b540f03b7), ROM_BIOS(2) ) // ABC 99 6490423-01 + + ROM_REGION( 0x800, I8035_Z5_TAG, 0 ) + ROMX_LOAD( "107268-16.z6", 0x0000, 0x0800, CRC(785ec0c6) SHA1(0b261beae20dbc06fdfccc50b19ea48b5b6e22eb), ROM_BIOS(1) ) + ROMX_LOAD( "107268-64.z6", 0x0000, 0x0800, CRC(e33683ae) SHA1(0c1d9e320f82df05f4804992ef6f6f6cd20623f3), ROM_BIOS(2) ) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *abc99_device::device_rom_region() const +{ + return ROM_NAME( abc99 ); +} + + +//------------------------------------------------- +// ADDRESS_MAP( abc99_z2_mem ) +//------------------------------------------------- + +static ADDRESS_MAP_START( abc99_z2_mem, AS_PROGRAM, 8, abc99_device ) + AM_RANGE(0x0000, 0x0fff) AM_ROM AM_REGION(I8035_Z2_TAG, 0) +ADDRESS_MAP_END + + +//------------------------------------------------- +// ADDRESS_MAP( abc99_z2_io ) +//------------------------------------------------- + +static ADDRESS_MAP_START( abc99_z2_io, AS_IO, 8, abc99_device ) + AM_RANGE(0x21, 0x21) AM_WRITE(z2_led_w) + AM_RANGE(0x30, 0x30) AM_READ_PORT("X0") AM_WRITENOP + AM_RANGE(0x31, 0x31) AM_READ_PORT("X1") AM_WRITENOP + AM_RANGE(0x32, 0x32) AM_READ_PORT("X2") AM_WRITENOP + AM_RANGE(0x33, 0x33) AM_READ_PORT("X3") AM_WRITENOP + AM_RANGE(0x34, 0x34) AM_READ_PORT("X4") AM_WRITENOP + AM_RANGE(0x35, 0x35) AM_READ_PORT("X5") AM_WRITENOP + AM_RANGE(0x36, 0x36) AM_READ_PORT("X6") AM_WRITENOP + AM_RANGE(0x37, 0x37) AM_READ_PORT("X7") AM_WRITENOP + AM_RANGE(0x38, 0x38) AM_READ_PORT("X8") AM_WRITENOP + AM_RANGE(0x39, 0x39) AM_READ_PORT("X9") AM_WRITENOP + AM_RANGE(0x3a, 0x3a) AM_READ_PORT("X10") AM_WRITENOP + AM_RANGE(0x3b, 0x3b) AM_READ_PORT("X11") AM_WRITENOP + AM_RANGE(0x3c, 0x3c) AM_READ_PORT("X12") AM_WRITENOP + AM_RANGE(0x3d, 0x3d) AM_READ_PORT("X13") AM_WRITENOP + AM_RANGE(0x3e, 0x3e) AM_READ_PORT("X14") AM_WRITENOP + AM_RANGE(0x3f, 0x3f) AM_READ_PORT("X15") AM_WRITENOP + AM_RANGE(MCS48_PORT_P1, MCS48_PORT_P1) AM_WRITE(z2_p1_w) + AM_RANGE(MCS48_PORT_P2, MCS48_PORT_P2) AM_READ(z2_p2_r) + AM_RANGE(MCS48_PORT_T0, MCS48_PORT_T0) AM_READ(z2_t0_r) + AM_RANGE(MCS48_PORT_T1, MCS48_PORT_T1) AM_READ(z2_t1_r) +ADDRESS_MAP_END + + +//------------------------------------------------- +// ADDRESS_MAP( abc99_z5_mem ) +//------------------------------------------------- + +static ADDRESS_MAP_START( abc99_z5_mem, AS_PROGRAM, 8, abc99_device ) + AM_RANGE(0x0000, 0x07ff) AM_ROM AM_REGION(I8035_Z5_TAG, 0) +ADDRESS_MAP_END + + +//------------------------------------------------- +// ADDRESS_MAP( abc99_z5_io ) +//------------------------------------------------- + +static ADDRESS_MAP_START( abc99_z5_io, AS_IO, 8, abc99_device ) +/* AM_RANGE(MCS48_PORT_P1, MCS48_PORT_P1) AM_READ(z5_p1_r) + AM_RANGE(MCS48_PORT_P2, MCS48_PORT_P2) AM_WRITE(z5_p2_w) + AM_RANGE(MCS48_PORT_T0, MCS48_PORT_T0) AM_WRITENOP // Z2 CLK + AM_RANGE(MCS48_PORT_T1, MCS48_PORT_T1) AM_READ(z5_t1_r)*/ +ADDRESS_MAP_END + + +//------------------------------------------------- +// MACHINE_DRIVER( abc99 ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( abc99 ) + // keyboard CPU + MCFG_CPU_ADD(I8035_Z2_TAG, I8035, XTAL_6MHz/3) // from Z5 T0 output + MCFG_CPU_PROGRAM_MAP(abc99_z2_mem) + MCFG_CPU_IO_MAP(abc99_z2_io) + + // mouse CPU + MCFG_CPU_ADD(I8035_Z5_TAG, I8035, XTAL_6MHz) + MCFG_CPU_PROGRAM_MAP(abc99_z5_mem) + MCFG_CPU_IO_MAP(abc99_z5_io) + MCFG_DEVICE_DISABLE() // HACK fix for broken serial I/O + + // sound hardware + MCFG_SPEAKER_STANDARD_MONO("mono") + MCFG_SOUND_ADD("speaker", SPEAKER_SOUND, 0) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.25) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor abc99_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( abc99 ); +} + + +//------------------------------------------------- +// INPUT_CHANGED_MEMBER( keyboard_reset ) +//------------------------------------------------- + +INPUT_CHANGED_MEMBER( abc99_device::keyboard_reset ) +{ + if (newval) + { + m_mousecpu->reset(); + } +} + + +//------------------------------------------------- +// INPUT_PORTS( abc99 ) +//------------------------------------------------- + +INPUT_PORTS_START( abc99 ) + PORT_START("X0") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("PF13") PORT_CODE(KEYCODE_PRTSCR) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME(UTF8_RIGHT"|") PORT_CODE(KEYCODE_TAB) PORT_CHAR('\t') + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("RETURN") PORT_CODE(KEYCODE_ENTER) PORT_CHAR('\r') + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("LF") PORT_CODE(KEYCODE_RCONTROL) PORT_CHAR(UCHAR_MAMEKEY(RCONTROL)) + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_BACKSLASH2) PORT_CHAR('<') PORT_CHAR('>') + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("X1") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("ALT") PORT_CODE(KEYCODE_LALT) PORT_CHAR(UCHAR_MAMEKEY(LALT)) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Keypad CE") PORT_CODE(KEYCODE_MINUS_PAD) PORT_CHAR(UCHAR_MAMEKEY(MINUS_PAD)) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_U) PORT_CHAR('u') PORT_CHAR('U') + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Keypad RETURN") PORT_CODE(KEYCODE_ENTER_PAD) PORT_CHAR(UCHAR_MAMEKEY(ENTER_PAD)) + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("X2") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("PRINT") PORT_CODE(KEYCODE_PGUP) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Keypad 9") PORT_CODE(KEYCODE_9_PAD) PORT_CHAR(UCHAR_MAMEKEY(9_PAD)) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Keypad 6") PORT_CODE(KEYCODE_6_PAD) PORT_CHAR(UCHAR_MAMEKEY(6_PAD)) + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Keypad 3") PORT_CODE(KEYCODE_3_PAD) PORT_CHAR(UCHAR_MAMEKEY(3_PAD)) + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Keypad .") PORT_CODE(KEYCODE_DEL_PAD) PORT_CHAR(UCHAR_MAMEKEY(DEL_PAD)) + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Left SHIFT") PORT_CODE(KEYCODE_LSHIFT) PORT_CHAR(UCHAR_SHIFT_1) + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("X3") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("HELP") PORT_CODE(KEYCODE_HOME) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Keypad 7") PORT_CODE(KEYCODE_7_PAD) PORT_CHAR(UCHAR_MAMEKEY(7_PAD)) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Keypad 4") PORT_CODE(KEYCODE_4_PAD) PORT_CHAR(UCHAR_MAMEKEY(4_PAD)) + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Keypad 1") PORT_CODE(KEYCODE_1_PAD) PORT_CHAR(UCHAR_MAMEKEY(1_PAD)) + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Keypad 0") PORT_CODE(KEYCODE_0_PAD) PORT_CHAR(UCHAR_MAMEKEY(0_PAD)) + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Z) PORT_CHAR('z') PORT_CHAR('Z') + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("X4") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("PF15") PORT_CODE(KEYCODE_PAUSE) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("DEL") PORT_CODE(KEYCODE_DEL) PORT_CHAR(UCHAR_MAMEKEY(DEL)) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME(UTF8_RIGHT) PORT_CODE(KEYCODE_RIGHT) PORT_CHAR(UCHAR_MAMEKEY(RIGHT)) // cursor B + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME(UTF8_LEFT) PORT_CODE(KEYCODE_LEFT) PORT_CHAR(UCHAR_MAMEKEY(LEFT)) // cursor D + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_X) PORT_CHAR('x') PORT_CHAR('X') + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("X5") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("PF12") PORT_CODE(KEYCODE_F12) PORT_CHAR(UCHAR_MAMEKEY(F12)) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("BS") PORT_CODE(KEYCODE_BACKSPACE) PORT_CHAR(8) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_CLOSEBRACE) PORT_CHAR(0x00FC) PORT_CHAR(0x00DC) + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_BACKSLASH) PORT_CHAR('\'') PORT_CHAR('*') + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Right SHIFT") PORT_CODE(KEYCODE_RSHIFT) + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Q) PORT_CHAR('q') PORT_CHAR('Q') + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_A) PORT_CHAR('a') PORT_CHAR('A') + + PORT_START("X6") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("PF14") PORT_CODE(KEYCODE_SCRLOCK) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("INS") PORT_CODE(KEYCODE_INSERT) PORT_CHAR(UCHAR_MAMEKEY(INSERT)) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME(UTF8_UP) PORT_CODE(KEYCODE_UP) PORT_CHAR(UCHAR_MAMEKEY(UP)) // cursor A + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME(UTF8_DOWN) PORT_CODE(KEYCODE_DOWN) PORT_CHAR(UCHAR_MAMEKEY(DOWN)) // cursor C + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("CTRL") PORT_CODE(KEYCODE_LCONTROL) PORT_CHAR(UCHAR_MAMEKEY(LCONTROL)) + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("CAPS LOCK") PORT_CODE(KEYCODE_CAPSLOCK) PORT_CHAR(UCHAR_MAMEKEY(CAPSLOCK)) + + PORT_START("X7") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("PF11") PORT_CODE(KEYCODE_F11) PORT_CHAR(UCHAR_MAMEKEY(F11)) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_EQUALS) PORT_CHAR(0x00E9) PORT_CHAR(0x00C9) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_OPENBRACE) PORT_CHAR(0x00E5) PORT_CHAR(0x00C5) + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_QUOTE) PORT_CHAR(0x00E4) PORT_CHAR(0x00C4) + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_SLASH) PORT_CHAR('-') PORT_CHAR('_') + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_W) PORT_CHAR('w') PORT_CHAR('W') + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_S) PORT_CHAR('s') PORT_CHAR('S') + + PORT_START("X8") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("STOP") PORT_CODE(KEYCODE_END) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Keypad 8") PORT_CODE(KEYCODE_8_PAD) PORT_CHAR(UCHAR_MAMEKEY(8_PAD)) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Keypad 5") PORT_CODE(KEYCODE_5_PAD) PORT_CHAR(UCHAR_MAMEKEY(5_PAD)) + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Keypad 2") PORT_CODE(KEYCODE_2_PAD) PORT_CHAR(UCHAR_MAMEKEY(2_PAD)) + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("|" UTF8_LEFT) PORT_CODE(KEYCODE_RALT) PORT_CHAR(UCHAR_MAMEKEY(RALT)) + + PORT_START("X9") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_MINUS) PORT_CHAR('+') PORT_CHAR('?') + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_P) PORT_CHAR('p') PORT_CHAR('P') + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_COLON) PORT_CHAR(0x00F6) PORT_CHAR(0x00D6) + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_STOP) PORT_CHAR('.') PORT_CHAR(':') + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_E) PORT_CHAR('e') PORT_CHAR('E') + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_D) PORT_CHAR('d') PORT_CHAR('D') + + PORT_START("X10") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("PF10") PORT_CODE(KEYCODE_F10) PORT_CHAR(UCHAR_MAMEKEY(F10)) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_0) PORT_CHAR('0') PORT_CHAR('=') + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_O) PORT_CHAR('o') PORT_CHAR('O') + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_L) PORT_CHAR('l') PORT_CHAR('L') + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_COMMA) PORT_CHAR(',') PORT_CHAR(';') + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("PF1") PORT_CODE(KEYCODE_F1) PORT_CHAR(UCHAR_MAMEKEY(F1)) + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("ESC") PORT_CODE(KEYCODE_ESC) + + PORT_START("X11") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("PF9") PORT_CODE(KEYCODE_F9) PORT_CHAR(UCHAR_MAMEKEY(F9)) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_9) PORT_CHAR('9') PORT_CHAR(')') + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_I) PORT_CHAR('i') PORT_CHAR('I') + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_K) PORT_CHAR('k') PORT_CHAR('K') + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_M) PORT_CHAR('m') PORT_CHAR('M') + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("PF2") PORT_CODE(KEYCODE_F2) PORT_CHAR(UCHAR_MAMEKEY(F2)) + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_1) PORT_CHAR('1') PORT_CHAR('!') + + PORT_START("X12") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_5) PORT_CHAR('5') PORT_CHAR('%') + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_R) PORT_CHAR('r') PORT_CHAR('R') + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F) PORT_CHAR('f') PORT_CHAR('F') + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_C) PORT_CHAR('c') PORT_CHAR('C') + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("SPACE") PORT_CODE(KEYCODE_SPACE) PORT_CHAR(' ') + + PORT_START("X13") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("PF6") PORT_CODE(KEYCODE_F6) PORT_CHAR(UCHAR_MAMEKEY(F6)) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_6) PORT_CHAR('6') PORT_CHAR('&') + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_T) PORT_CHAR('t') PORT_CHAR('T') + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_G) PORT_CHAR('g') PORT_CHAR('G') + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_V) PORT_CHAR('v') PORT_CHAR('V') + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("PF5") PORT_CODE(KEYCODE_F5) PORT_CHAR(UCHAR_MAMEKEY(F5)) + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("4 \xC2\xA4") PORT_CODE(KEYCODE_4) PORT_CHAR('4') PORT_CHAR(0x00A4) + + PORT_START("X14") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("PF7") PORT_CODE(KEYCODE_F7) PORT_CHAR(UCHAR_MAMEKEY(F7)) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_7) PORT_CHAR('7') PORT_CHAR('/') + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Y) PORT_CHAR('y') PORT_CHAR('Y') + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_H) PORT_CHAR('h') PORT_CHAR('H') + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_B) PORT_CHAR('b') PORT_CHAR('B') + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("PF4") PORT_CODE(KEYCODE_F4) PORT_CHAR(UCHAR_MAMEKEY(F4)) + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_3) PORT_CHAR('3') PORT_CHAR('#') + + PORT_START("X15") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("PF8") PORT_CODE(KEYCODE_F8) PORT_CHAR(UCHAR_MAMEKEY(F8)) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_8) PORT_CHAR('8') PORT_CHAR('(') + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_U) PORT_CHAR('u') PORT_CHAR('U') + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_J) PORT_CHAR('j') PORT_CHAR('J') + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_N) PORT_CHAR('n') PORT_CHAR('N') + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("PF3") PORT_CODE(KEYCODE_F3) PORT_CHAR(UCHAR_MAMEKEY(F3)) + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_2) PORT_CHAR('2') PORT_CHAR('"') + + PORT_START("Z14") + PORT_DIPNAME( 0x07, 0x00, DEF_STR( Language ) ) PORT_DIPLOCATION("Z14:1,2,3") + PORT_DIPSETTING( 0x00, DEF_STR( Unknown ) ) + PORT_DIPSETTING( 0x01, DEF_STR( Unknown ) ) + PORT_DIPSETTING( 0x02, DEF_STR( Unknown ) ) + PORT_DIPSETTING( 0x03, DEF_STR( Unknown ) ) + PORT_DIPSETTING( 0x04, DEF_STR( Unknown ) ) + PORT_DIPSETTING( 0x05, DEF_STR( Unknown ) ) + PORT_DIPSETTING( 0x06, DEF_STR( Unknown ) ) + PORT_DIPSETTING( 0x07, DEF_STR( Unknown ) ) + PORT_DIPNAME( 0x08, 0x08, "Keyboard Program" ) PORT_DIPLOCATION("Z14:4") + PORT_DIPSETTING( 0x00, "Internal (8048)" ) + PORT_DIPSETTING( 0x08, "External PROM" ) + + PORT_START("MOUSEB") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_SPECIAL ) PORT_NAME("Left Mouse Button") PORT_CODE(MOUSECODE_BUTTON1) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_SPECIAL ) PORT_NAME("Middle Mouse Button") PORT_CODE(MOUSECODE_BUTTON3) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_SPECIAL ) PORT_NAME("Right Mouse Button") PORT_CODE(MOUSECODE_BUTTON2) + + PORT_START("MOUSEX") + PORT_BIT( 0xff, 0x00, IPT_MOUSE_X ) PORT_SENSITIVITY(100) PORT_KEYDELTA(5) PORT_MINMAX(0, 255) PORT_PLAYER(1) + + PORT_START("MOUSEY") + PORT_BIT( 0xff, 0x00, IPT_MOUSE_Y ) PORT_SENSITIVITY(100) PORT_KEYDELTA(5) PORT_MINMAX(0, 255) PORT_PLAYER(1) + + PORT_START("J4") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_SPECIAL ) PORT_NAME("Keyboard Reset") PORT_CHANGED_MEMBER(DEVICE_SELF, abc99_device, keyboard_reset, 0) +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor abc99_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( abc99 ); +} + + + +//************************************************************************** +// INLINE HELPERS +//************************************************************************** + +//------------------------------------------------- +// serial_input - +//------------------------------------------------- + +inline void abc99_device::serial_input() +{ + m_maincpu->set_input_line(MCS48_INPUT_IRQ, (m_si || m_si_en) ? CLEAR_LINE : ASSERT_LINE); + m_mousecpu->set_input_line(MCS48_INPUT_IRQ, m_si ? CLEAR_LINE : ASSERT_LINE); +} + + +//------------------------------------------------- +// serial_output - +//------------------------------------------------- + +inline void abc99_device::serial_output(int state) +{ + if (m_txd != state) + { + m_txd = state; + + m_slot->write_rx(m_txd); + } +} + + +//------------------------------------------------- +// serial_clock - +//------------------------------------------------- + +inline void abc99_device::serial_clock() +{ + m_slot->trxc_w(1); + m_slot->trxc_w(0); +} + + +//------------------------------------------------- +// keydown - +//------------------------------------------------- + +inline void abc99_device::key_down(int state) +{ + if (m_keydown != state) + { + m_slot->keydown_w(state); + m_keydown = state; + } +} + + +//------------------------------------------------- +// scan_mouse - +//------------------------------------------------- + +inline void abc99_device::scan_mouse() +{ +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// abc99_device - constructor +//------------------------------------------------- + +abc99_device::abc99_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, ABC99, "Luxor ABC 99", tag, owner, clock, "abc99", __FILE__), + abc_keyboard_interface(mconfig, *this), + m_maincpu(*this, I8035_Z2_TAG), + m_mousecpu(*this, I8035_Z5_TAG), + m_speaker(*this, "speaker"), + m_z14(*this, "Z14"), + m_mouseb(*this, "MOUSEB"), + m_si(1), + m_si_en(1), + m_so_z2(1), + m_so_z5(1), + m_keydown(0), + m_t1_z2(0), + m_t1_z5(0), + m_led_en(0), + m_reset(1), + m_txd(1) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void abc99_device::device_start() +{ + // allocate timers + m_serial_timer = timer_alloc(TIMER_SERIAL); + m_serial_timer->adjust(MCS48_ALE_CLOCK(XTAL_6MHz/3), 0, MCS48_ALE_CLOCK(XTAL_6MHz/3)); + + m_mouse_timer = timer_alloc(TIMER_MOUSE); + + // state saving + save_item(NAME(m_si)); + save_item(NAME(m_si_en)); + save_item(NAME(m_so_z2)); + save_item(NAME(m_so_z5)); + save_item(NAME(m_keydown)); + save_item(NAME(m_t1_z2)); + save_item(NAME(m_t1_z5)); + save_item(NAME(m_led_en)); + save_item(NAME(m_reset)); + save_item(NAME(m_txd)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void abc99_device::device_reset() +{ + // set EA lines + m_maincpu->set_input_line(MCS48_INPUT_EA, ASSERT_LINE); + m_mousecpu->set_input_line(MCS48_INPUT_EA, ASSERT_LINE); + + m_slot->write_rx(1); +} + + +//------------------------------------------------- +// device_timer - handler timer events +//------------------------------------------------- + +void abc99_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch (id) + { + case TIMER_SERIAL: + serial_clock(); + break; + + case TIMER_MOUSE: + scan_mouse(); + break; + } +} + + +//------------------------------------------------- +// txd_w - +//------------------------------------------------- + +void abc99_device::txd_w(int state) +{ + if (m_si != state) + { + m_si = state; + serial_input(); + } +} + + +//------------------------------------------------- +// z2_bus_w - +//------------------------------------------------- + +WRITE8_MEMBER( abc99_device::z2_led_w ) +{ + if (m_led_en) return; + + output_set_led_value(LED_1, BIT(data, 0)); + output_set_led_value(LED_2, BIT(data, 1)); + output_set_led_value(LED_3, BIT(data, 2)); + output_set_led_value(LED_4, BIT(data, 3)); + output_set_led_value(LED_5, BIT(data, 4)); + output_set_led_value(LED_6, BIT(data, 5)); + output_set_led_value(LED_7, BIT(data, 6)); + output_set_led_value(LED_8, BIT(data, 7)); +} + + +//------------------------------------------------- +// z2_p1_w - +//------------------------------------------------- + +WRITE8_MEMBER( abc99_device::z2_p1_w ) +{ + /* + + bit description + + P10 serial output + P11 KEY DOWN + P12 transmit -> Z5 T1 + P13 INS led + P14 ALT led + P15 CAPS LOCK led + P16 speaker output + P17 Z8 enable + + */ + + // serial output + m_so_z2 = BIT(data, 0); + serial_output(m_so_z2 && m_so_z5); + + // key down + key_down(!BIT(data, 1)); + + // master T1 + m_t1_z5 = BIT(data, 2); + + // key LEDs + output_set_led_value(LED_INS, BIT(data, 3)); + output_set_led_value(LED_ALT, BIT(data, 4)); + output_set_led_value(LED_CAPS_LOCK, BIT(data, 5)); + + // speaker output + m_speaker->level_w(!BIT(data, 6)); + + // Z8 enable + m_led_en = BIT(data, 7); +} + + +//------------------------------------------------- +// z2_p2_r - +//------------------------------------------------- + +READ8_MEMBER( abc99_device::z2_p2_r ) +{ + /* + + bit description + + P20 + P21 + P22 + P23 + P24 + P25 DIP0 + P26 DIP1 + P27 DIP2 + + */ + + UINT8 data = m_z14->read() << 5; + + return data; +} + + +//------------------------------------------------- +// z2_t0_r - +//------------------------------------------------- + +READ8_MEMBER( abc99_device::z2_t0_r ) +{ + return 1; // 0=mouse connected, 1=no mouse +} + + +//------------------------------------------------- +// z2_t1_r - +//------------------------------------------------- + +READ8_MEMBER( abc99_device::z2_t1_r ) +{ + return m_t1_z2; +} + + +//------------------------------------------------- +// z5_p1_r - +//------------------------------------------------- + +READ8_MEMBER( abc99_device::z5_p1_r ) +{ + /* + + bit description + + P10 XA + P11 XB + P12 YA + P13 YB + P14 LB + P15 MB + P16 RB + P17 input from host + + */ + + UINT8 data = 0; + + // mouse buttons + data |= (m_mouseb->read() & 0x07) << 4; + + // serial input + data |= m_si << 7; + + return data; +} + + +//------------------------------------------------- +// z5_p2_w - +//------------------------------------------------- + +WRITE8_MEMBER( abc99_device::z5_p2_w ) +{ + /* + + bit description + + P20 + P21 + P22 + P23 + P24 Z2 serial input enable + P25 Z2 RESET + P26 serial output + P27 Z2 T1 + + */ + + // serial input enable + int si_en = BIT(data, 4); + + if (m_si_en != si_en) + { + m_si_en = si_en; + serial_input(); + } + + // Z2 reset + int reset = BIT(data, 5); + + if (!m_reset && reset) + { + m_maincpu->reset(); + } + + m_reset = reset; + + // serial output + m_so_z5 = BIT(data, 6); + serial_output(m_so_z2 && m_so_z5); + + // keyboard CPU T1 + m_t1_z2 = BIT(data, 7); +} + + +//------------------------------------------------- +// z5_t1_r - +//------------------------------------------------- + +READ8_MEMBER( abc99_device::z5_t1_r ) +{ + return m_t1_z5; +} diff --git a/src/devices/bus/abckb/abc99.h b/src/devices/bus/abckb/abc99.h new file mode 100644 index 00000000000..366d9fa23ce --- /dev/null +++ b/src/devices/bus/abckb/abc99.h @@ -0,0 +1,114 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Luxor ABC-99 keyboard and mouse emulation + +*********************************************************************/ + +#pragma once + +#ifndef __ABC99__ +#define __ABC99__ + +#include "emu.h" +#include "cpu/mcs48/mcs48.h" +#include "abckb.h" +#include "sound/speaker.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> abc99_device + +class abc99_device : public device_t, + public abc_keyboard_interface +{ +public: + // construction/destruction + abc99_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + virtual ioport_constructor device_input_ports() const; + + // abc_keyboard_interface overrides + virtual void txd_w(int state); + + DECLARE_INPUT_CHANGED_MEMBER( keyboard_reset ); + + DECLARE_WRITE8_MEMBER( z2_led_w ); + DECLARE_WRITE8_MEMBER( z2_p1_w ); + DECLARE_READ8_MEMBER( z2_p2_r ); + DECLARE_READ8_MEMBER( z2_t0_r ); + DECLARE_READ8_MEMBER( z2_t1_r ); + DECLARE_READ8_MEMBER( z5_p1_r ); + DECLARE_WRITE8_MEMBER( z5_p2_w ); + DECLARE_READ8_MEMBER( z5_t1_r ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + +private: + enum + { + TIMER_SERIAL, + TIMER_MOUSE + }; + + enum + { + LED_1 = 0, + LED_2, + LED_3, + LED_4, + LED_5, + LED_6, + LED_7, + LED_8, + LED_INS, + LED_ALT, + LED_CAPS_LOCK + }; + + inline void serial_input(); + inline void serial_output(int state); + inline void serial_clock(); + inline void key_down(int state); + inline void scan_mouse(); + + emu_timer *m_serial_timer; + emu_timer *m_mouse_timer; + + required_device m_maincpu; + required_device m_mousecpu; + required_device m_speaker; + required_ioport m_z14; + required_ioport m_mouseb; + + int m_si; + int m_si_en; + int m_so_z2; + int m_so_z5; + int m_keydown; + int m_t1_z2; + int m_t1_z5; + int m_led_en; + int m_reset; + int m_txd; +}; + + +// device type definition +extern const device_type ABC99; + + + +#endif diff --git a/src/devices/bus/abckb/abckb.c b/src/devices/bus/abckb/abckb.c new file mode 100644 index 00000000000..dc9edd10bed --- /dev/null +++ b/src/devices/bus/abckb/abckb.c @@ -0,0 +1,136 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Luxor ABC 800/802/806/1600 keyboard port emulation + +**********************************************************************/ + +#include "abckb.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +// device type definition +const device_type ABC_KEYBOARD_PORT = &device_creator; + + + +//************************************************************************** +// CARD INTERFACE +//************************************************************************** + +//------------------------------------------------- +// abc_keyboard_interface - constructor +//------------------------------------------------- + +abc_keyboard_interface::abc_keyboard_interface(const machine_config &mconfig, device_t &device) + : device_slot_card_interface(mconfig,device) +{ + m_slot = dynamic_cast(device.owner()); +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// abc_keyboard_port_device - constructor +//------------------------------------------------- + +abc_keyboard_port_device::abc_keyboard_port_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, ABC_KEYBOARD_PORT, "Luxor ABC keyboard port", tag, owner, clock, "abc_keyboard_port", __FILE__), + device_slot_interface(mconfig, *this), + m_out_rx_handler(*this), + m_out_trxc_handler(*this), + m_out_keydown_handler(*this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void abc_keyboard_port_device::device_start() +{ + m_card = dynamic_cast(get_card_device()); + + // resolve callbacks + m_out_rx_handler.resolve_safe(); + m_out_trxc_handler.resolve_safe(); + m_out_keydown_handler.resolve_safe(); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void abc_keyboard_port_device::device_reset() +{ + if (m_card != NULL) + get_card_device()->reset(); +} + + +//------------------------------------------------- +// write_rx - +//------------------------------------------------- + +WRITE_LINE_MEMBER( abc_keyboard_port_device::write_rx ) +{ + m_out_rx_handler(state); +} + + +//------------------------------------------------- +// txd_w - +//------------------------------------------------- + +WRITE_LINE_MEMBER( abc_keyboard_port_device::txd_w ) +{ + if (m_card != NULL) + m_card->txd_w(state); +} + + +//------------------------------------------------- +// trxc_w - +//------------------------------------------------- + +WRITE_LINE_MEMBER( abc_keyboard_port_device::trxc_w ) +{ + m_out_trxc_handler(state); +} + + +//------------------------------------------------- +// keydown_w - +//------------------------------------------------- + +WRITE_LINE_MEMBER( abc_keyboard_port_device::keydown_w ) +{ + m_out_keydown_handler(state); +} + + + +//************************************************************************** +// SLOT INTERFACE +//************************************************************************** + +#include "abc800kb.h" +#include "abc77.h" +#include "abc99.h" + +SLOT_INTERFACE_START( abc_keyboard_devices ) + SLOT_INTERFACE("abc800", ABC800_KEYBOARD) + SLOT_INTERFACE("abc55", ABC55) + SLOT_INTERFACE("abc77", ABC77) + SLOT_INTERFACE("abc99", ABC99) +SLOT_INTERFACE_END diff --git a/src/devices/bus/abckb/abckb.h b/src/devices/bus/abckb/abckb.h new file mode 100644 index 00000000000..9b396f26983 --- /dev/null +++ b/src/devices/bus/abckb/abckb.h @@ -0,0 +1,97 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Luxor ABC 800/802/806/1600 keyboard port emulation + +**********************************************************************/ + +#pragma once + +#ifndef __ABC_KEYBOARD_PORT__ +#define __ABC_KEYBOARD_PORT__ + +#include "emu.h" + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_ABC_KEYBOARD_PORT_ADD(_tag, _def_slot) \ + MCFG_DEVICE_ADD(_tag, ABC_KEYBOARD_PORT, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(abc_keyboard_devices, _def_slot, false) + +#define MCFG_ABC_KEYBOARD_OUT_RX_HANDLER(_devcb) \ + devcb = &abc_keyboard_port_device::set_out_rx_handler(*device, DEVCB_##_devcb); + +#define MCFG_ABC_KEYBOARD_OUT_TRXC_HANDLER(_devcb) \ + devcb = &abc_keyboard_port_device::set_out_trxc_handler(*device, DEVCB_##_devcb); + +#define MCFG_ABC_KEYBOARD_OUT_KEYDOWN_HANDLER(_devcb) \ + devcb = &abc_keyboard_port_device::set_out_keydown_handler(*device, DEVCB_##_devcb); + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class abc_keyboard_interface; + +class abc_keyboard_port_device : public device_t, + public device_slot_interface +{ +public: + // construction/destruction + abc_keyboard_port_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + template static devcb_base &set_out_rx_handler(device_t &device, _Object object) { return downcast(device).m_out_rx_handler.set_callback(object); } + template static devcb_base &set_out_trxc_handler(device_t &device, _Object object) { return downcast(device).m_out_trxc_handler.set_callback(object); } + template static devcb_base &set_out_keydown_handler(device_t &device, _Object object) { return downcast(device).m_out_keydown_handler.set_callback(object); } + + // computer interface + DECLARE_WRITE_LINE_MEMBER( txd_w ); + + // peripheral interface + DECLARE_WRITE_LINE_MEMBER( write_rx ); + DECLARE_WRITE_LINE_MEMBER( trxc_w ); + DECLARE_WRITE_LINE_MEMBER( keydown_w ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + devcb_write_line m_out_rx_handler; + devcb_write_line m_out_trxc_handler; + devcb_write_line m_out_keydown_handler; + + abc_keyboard_interface *m_card; +}; + + +class abc_keyboard_interface : public device_slot_card_interface +{ +public: + // construction/destruction + abc_keyboard_interface(const machine_config &mconfig, device_t &device); + + virtual void txd_w(int state) { }; + +protected: + abc_keyboard_port_device *m_slot; +}; + + +// device type definition +extern const device_type ABC_KEYBOARD_PORT; + + +// supported devices +SLOT_INTERFACE_EXTERN( abc_keyboard_devices ); + + + +#endif diff --git a/src/devices/bus/adam/adamlink.c b/src/devices/bus/adam/adamlink.c new file mode 100644 index 00000000000..1ae12b1156f --- /dev/null +++ b/src/devices/bus/adam/adamlink.c @@ -0,0 +1,84 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Coleco AdamLink 300 Baud Modem emulation + +**********************************************************************/ + +#include "adamlink.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type ADAMLINK = &device_creator; + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// adamlink_device - constructor +//------------------------------------------------- + +adamlink_device::adamlink_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, ADAMLINK, "AdamLink modem", tag, owner, clock, "adamlink", __FILE__), + device_adam_expansion_slot_card_interface(mconfig, *this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void adamlink_device::device_start() +{ +} + + +//------------------------------------------------- +// adam_bd_r - buffered data read +//------------------------------------------------- + +UINT8 adamlink_device::adam_bd_r(address_space &space, offs_t offset, UINT8 data, int bmreq, int biorq, int aux_rom_cs, int cas1, int cas2) +{ + if (!biorq) + { + switch (offset) + { + case 0x5e: + break; + + case 0x5f: + break; + } + } + + return data; +} + + +//------------------------------------------------- +// adam_bd_w - buffered data write +//------------------------------------------------- + +void adamlink_device::adam_bd_w(address_space &space, offs_t offset, UINT8 data, int bmreq, int biorq, int aux_rom_cs, int cas1, int cas2) +{ + if (!biorq) + { + switch (offset) + { + case 0x5e: + break; + + case 0x5f: + break; + } + } +} diff --git a/src/devices/bus/adam/adamlink.h b/src/devices/bus/adam/adamlink.h new file mode 100644 index 00000000000..acf1d2fa31a --- /dev/null +++ b/src/devices/bus/adam/adamlink.h @@ -0,0 +1,47 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Coleco AdamLink 300 Baud Modem emulation + +**********************************************************************/ + +#pragma once + +#ifndef __ADAMLINK__ +#define __ADAMLINK__ + +#include "emu.h" +#include "exp.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> adamlink_device + +class adamlink_device : public device_t, + public device_adam_expansion_slot_card_interface +{ +public: + // construction/destruction + adamlink_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // device-level overrides + virtual void device_start(); + + // device_adam_expansion_slot_card_interface overrides + virtual UINT8 adam_bd_r(address_space &space, offs_t offset, UINT8 data, int bmreq, int biorq, int aux_rom_cs, int cas1, int cas2); + virtual void adam_bd_w(address_space &space, offs_t offset, UINT8 data, int bmreq, int biorq, int aux_rom_cs, int cas1, int cas2); +}; + + +// device type definition +extern const device_type ADAMLINK; + + + +#endif diff --git a/src/devices/bus/adam/exp.c b/src/devices/bus/adam/exp.c new file mode 100644 index 00000000000..110a1299188 --- /dev/null +++ b/src/devices/bus/adam/exp.c @@ -0,0 +1,190 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Coleco Adam Expansion Port emulation + +**********************************************************************/ + +#include "exp.h" + + + +//************************************************************************** +// MACROS/CONSTANTS +//************************************************************************** + +#define LOG 0 + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type ADAM_EXPANSION_SLOT = &device_creator; + + + +//************************************************************************** +// DEVICE C64_EXPANSION CARD INTERFACE +//************************************************************************** + +//------------------------------------------------- +// device_adam_expansion_slot_card_interface - constructor +//------------------------------------------------- + +device_adam_expansion_slot_card_interface::device_adam_expansion_slot_card_interface(const machine_config &mconfig, device_t &device) : + device_slot_card_interface(mconfig, device), + m_rom(*this, "rom") +{ + m_slot = dynamic_cast(device.owner()); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// adam_expansion_slot_device - constructor +//------------------------------------------------- + +adam_expansion_slot_device::adam_expansion_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, ADAM_EXPANSION_SLOT, "ADAM expansion slot", tag, owner, clock, "adam_expansion_slot", __FILE__), + device_slot_interface(mconfig, *this), + device_image_interface(mconfig, *this), + m_write_irq(*this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void adam_expansion_slot_device::device_start() +{ + m_card = dynamic_cast(get_card_device()); + + // resolve callbacks + m_write_irq.resolve_safe(); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void adam_expansion_slot_device::device_reset() +{ +} + + +//------------------------------------------------- +// call_load - +//------------------------------------------------- + +bool adam_expansion_slot_device::call_load() +{ + if (m_card) + { + size_t size = 0; + + if (software_entry() == NULL) + { + size = length(); + + fread(m_card->m_rom, size); + } + else + { + load_software_region("rom", m_card->m_rom); + } + } + + return IMAGE_INIT_PASS; +} + + +//------------------------------------------------- +// call_softlist_load - +//------------------------------------------------- + +bool adam_expansion_slot_device::call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry) +{ + load_software_part_region(*this, swlist, swname, start_entry); + + return true; +} + + +//------------------------------------------------- +// get_default_card_software - +//------------------------------------------------- + +void adam_expansion_slot_device::get_default_card_software(std::string &result) +{ + software_get_default_slot(result, "standard"); +} + + +//------------------------------------------------- +// bd_r - buffered data read +//------------------------------------------------- + +UINT8 adam_expansion_slot_device::bd_r(address_space &space, offs_t offset, UINT8 data, int bmreq, int biorq, int aux_rom_cs, int cas1, int cas2) +{ + if (m_card != NULL) + { + data = m_card->adam_bd_r(space, offset, data, bmreq, biorq, aux_rom_cs, cas1, cas2); + } + + return data; +} + + +//------------------------------------------------- +// cd_w - cartridge data write +//------------------------------------------------- + +void adam_expansion_slot_device::bd_w(address_space &space, offs_t offset, UINT8 data, int bmreq, int biorq, int aux_rom_cs, int cas1, int cas2) +{ + if (m_card != NULL) + { + m_card->adam_bd_w(space, offset, data, bmreq, biorq, aux_rom_cs, cas1, cas2); + } +} + + +// slot devices +#include "adamlink.h" +#include "ide.h" +#include "ram.h" + +//------------------------------------------------- +// SLOT_INTERFACE( adam_slot1_devices ) +//------------------------------------------------- + +SLOT_INTERFACE_START( adam_slot1_devices ) + SLOT_INTERFACE("adamlink", ADAMLINK) +SLOT_INTERFACE_END + + +//------------------------------------------------- +// SLOT_INTERFACE( adam_slot2_devices ) +//------------------------------------------------- + +SLOT_INTERFACE_START( adam_slot2_devices ) + SLOT_INTERFACE("ide", ADAM_IDE) +SLOT_INTERFACE_END + + +//------------------------------------------------- +// SLOT_INTERFACE( adam_slot3_devices ) +//------------------------------------------------- + +SLOT_INTERFACE_START( adam_slot3_devices ) + SLOT_INTERFACE("ram", ADAM_RAM) +SLOT_INTERFACE_END diff --git a/src/devices/bus/adam/exp.h b/src/devices/bus/adam/exp.h new file mode 100644 index 00000000000..7719c3f8d11 --- /dev/null +++ b/src/devices/bus/adam/exp.h @@ -0,0 +1,130 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Coleco Adam Expansion Port emulation + +**********************************************************************/ + +#pragma once + +#ifndef __ADAM_EXPANSION_SLOT__ +#define __ADAM_EXPANSION_SLOT__ + +#include "emu.h" + + + +//************************************************************************** +// CONSTANTS +//************************************************************************** + +#define ADAM_LEFT_EXPANSION_SLOT_TAG "slot1" +#define ADAM_CENTER_EXPANSION_SLOT_TAG "slot2" +#define ADAM_RIGHT_EXPANSION_SLOT_TAG "slot3" + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_ADAM_EXPANSION_SLOT_ADD(_tag, _clock, _slot_intf, _def_slot) \ + MCFG_DEVICE_ADD(_tag, ADAM_EXPANSION_SLOT, _clock) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) + + +#define MCFG_ADAM_EXPANSION_SLOT_IRQ_CALLBACK(_write) \ + devcb = &adam_expansion_slot_device::set_irq_wr_callback(*device, DEVCB_##_write); + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> adam_expansion_slot_device + +class device_adam_expansion_slot_card_interface; + +class adam_expansion_slot_device : public device_t, + public device_slot_interface, + public device_image_interface +{ +public: + // construction/destruction + adam_expansion_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual ~adam_expansion_slot_device() { } + + template static devcb_base &set_irq_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_irq.set_callback(object); } + + // computer interface + UINT8 bd_r(address_space &space, offs_t offset, UINT8 data, int bmreq, int biorq, int aux_rom_cs, int cas1, int cas2); + void bd_w(address_space &space, offs_t offset, UINT8 data, int bmreq, int biorq, int aux_rom_cs, int cas1, int cas2); + + // cartridge interface + DECLARE_WRITE_LINE_MEMBER( irq_w ) { m_write_irq(state); } + +protected: + // device-level overrides + virtual void device_config_complete() { update_names(); } + virtual void device_start(); + virtual void device_reset(); + + // image-level overrides + virtual bool call_load(); + virtual bool call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry); + + virtual iodevice_t image_type() const { return IO_CARTSLOT; } + + virtual bool is_readable() const { return 1; } + virtual bool is_writeable() const { return 0; } + virtual bool is_creatable() const { return 0; } + virtual bool must_be_loaded() const { return 0; } + virtual bool is_reset_on_load() const { return 1; } + virtual const char *image_interface() const { return "adam_rom"; } + virtual const char *file_extensions() const { return "bin,rom"; } + virtual const option_guide *create_option_guide() const { return NULL; } + + // slot interface overrides + virtual void get_default_card_software(std::string &result); + + devcb_write_line m_write_irq; + + device_adam_expansion_slot_card_interface *m_card; +}; + + +// ======================> device_adam_expansion_slot_card_interface + +class device_adam_expansion_slot_card_interface : public device_slot_card_interface +{ + friend class adam_expansion_slot_device; + +public: + // construction/destruction + device_adam_expansion_slot_card_interface(const machine_config &mconfig, device_t &device); + virtual ~device_adam_expansion_slot_card_interface() { } + +protected: + // runtime + virtual UINT8 adam_bd_r(address_space &space, offs_t offset, UINT8 data, int bmreq, int biorq, int aux_rom_cs, int cas1, int cas2) { return data; } + virtual void adam_bd_w(address_space &space, offs_t offset, UINT8 data, int bmreq, int biorq, int aux_rom_cs, int cas1, int cas2) { } + + adam_expansion_slot_device *m_slot; + + optional_shared_ptr m_rom; +}; + + +// device type definition +extern const device_type ADAM_EXPANSION_SLOT; + + +SLOT_INTERFACE_EXTERN( adam_slot1_devices ); +SLOT_INTERFACE_EXTERN( adam_slot2_devices ); +SLOT_INTERFACE_EXTERN( adam_slot3_devices ); + + + +#endif diff --git a/src/devices/bus/adam/ide.c b/src/devices/bus/adam/ide.c new file mode 100644 index 00000000000..7ea8a8b24a2 --- /dev/null +++ b/src/devices/bus/adam/ide.c @@ -0,0 +1,209 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Micro Innovations Powermate IDE Hard Disk emulation + +**********************************************************************/ + +/* + + TODO: + + - parallel status port + - memory bank switching port + - boot ROM + +*/ + +#include "ide.h" +#include "bus/centronics/ctronics.h" + + + +//************************************************************************** +// MACROS/CONSTANTS +//************************************************************************** + +#define ATA_TAG "ata" +#define CENTRONICS_TAG "centronics" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type ADAM_IDE = &device_creator; + + +//------------------------------------------------- +// ROM( adam_ata ) +//------------------------------------------------- + +ROM_START( adam_ata ) + ROM_REGION( 0x1000, "rom", 0 ) + ROM_LOAD( "exp.rom", 0x0000, 0x1000, NO_DUMP ) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *powermate_ide_device::device_rom_region() const +{ + return ROM_NAME( adam_ata ); +} + + +//------------------------------------------------- +// MACHINE_CONFIG_FRAGMENT( adam_ata ) +//------------------------------------------------- +static MACHINE_CONFIG_FRAGMENT( adam_ata ) + MCFG_ATA_INTERFACE_ADD(ATA_TAG, ata_devices, "hdd", NULL, false) + MCFG_CENTRONICS_ADD(CENTRONICS_TAG, centronics_devices, "printer") + + MCFG_CENTRONICS_OUTPUT_LATCH_ADD("cent_data_out", CENTRONICS_TAG) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor powermate_ide_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( adam_ata ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// powermate_ide_device - constructor +//------------------------------------------------- + +powermate_ide_device::powermate_ide_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, ADAM_IDE, "Powermate HP IDE", tag, owner, clock, "adam_ide", __FILE__), + device_adam_expansion_slot_card_interface(mconfig, *this), + m_ata(*this, ATA_TAG), + m_cent_data_out(*this, "cent_data_out") +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void powermate_ide_device::device_start() +{ +} + + +//------------------------------------------------- +// adam_bd_r - buffered data read +//------------------------------------------------- + +UINT8 powermate_ide_device::adam_bd_r(address_space &space, offs_t offset, UINT8 data, int bmreq, int biorq, int aux_rom_cs, int cas1, int cas2) +{ + if (!biorq) + { + switch (offset & 0xff) + { + case 0x01: + case 0x02: + case 0x03: + case 0x04: + case 0x05: + case 0x06: + case 0x07: + data = m_ata->read_cs0(space, offset & 0x07, 0xff); + break; + + case 0x40: // Printer status + /* + + bit description + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + + */ + break; + + case 0x58: + m_ata_data = m_ata->read_cs0(space, 0, 0xffff); + + data = m_ata_data & 0xff; + break; + + case 0x59: + data = m_ata_data >> 8; + break; + + case 0x5a: + data = m_ata->read_cs1(space, 6, 0xff); + break; + + case 0x5b: // Digital Input Register + data = 0xff; + break; + } + } + + return data; +} + + +//------------------------------------------------- +// adam_bd_w - buffered data write +//------------------------------------------------- + +void powermate_ide_device::adam_bd_w(address_space &space, offs_t offset, UINT8 data, int bmreq, int biorq, int aux_rom_cs, int cas1, int cas2) +{ + if (!biorq) + { + switch (offset & 0xff) + { + case 0x02: + case 0x03: + case 0x04: + case 0x05: + case 0x06: + case 0x07: + m_ata->write_cs0(space, offset & 0x07, data, 0xff); + break; + + case 0x40: + m_cent_data_out->write(space, 0, data); + break; + + case 0x42: // Bank Number + break; + + case 0x58: + m_ata_data |= data; + m_ata->write_cs0(space, 0, m_ata_data, 0xffff); + break; + + case 0x59: + m_ata_data = data << 8; + break; + + case 0x5a: // Fixed Disk Control Register + break; + } + } +} diff --git a/src/devices/bus/adam/ide.h b/src/devices/bus/adam/ide.h new file mode 100644 index 00000000000..35e26681bcd --- /dev/null +++ b/src/devices/bus/adam/ide.h @@ -0,0 +1,59 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Micro Innovations Powermate IDE Hard Disk emulation + +**********************************************************************/ + +#pragma once + +#ifndef __ADAM_IDE__ +#define __ADAM_IDE__ + +#include "emu.h" +#include "exp.h" +#include "machine/ataintf.h" +#include "machine/latch.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> powermate_ide_device + +class powermate_ide_device : public device_t, + public device_adam_expansion_slot_card_interface +{ +public: + // construction/destruction + powermate_ide_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + +protected: + // device-level overrides + virtual void device_start(); + + // device_adam_expansion_slot_card_interface overrides + virtual UINT8 adam_bd_r(address_space &space, offs_t offset, UINT8 data, int bmreq, int biorq, int aux_rom_cs, int cas1, int cas2); + virtual void adam_bd_w(address_space &space, offs_t offset, UINT8 data, int bmreq, int biorq, int aux_rom_cs, int cas1, int cas2); + +private: + required_device m_ata; + required_device m_cent_data_out; + + UINT16 m_ata_data; +}; + + +// device type definition +extern const device_type ADAM_IDE; + + + +#endif diff --git a/src/devices/bus/adam/ram.c b/src/devices/bus/adam/ram.c new file mode 100644 index 00000000000..6852de8959a --- /dev/null +++ b/src/devices/bus/adam/ram.c @@ -0,0 +1,72 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Coleco Adam Internal 64KB RAM Expansion emulation + +**********************************************************************/ + +#include "ram.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type ADAM_RAM = &device_creator; + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// adam_ram_expansion_device - constructor +//------------------------------------------------- + +adam_ram_expansion_device::adam_ram_expansion_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, ADAM_RAM, "Adam 64KB RAM expansion", tag, owner, clock, "adam_ram", __FILE__), + device_adam_expansion_slot_card_interface(mconfig, *this), + m_ram(*this, "ram") +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void adam_ram_expansion_device::device_start() +{ + m_ram.allocate(0x10000); +} + + +//------------------------------------------------- +// adam_bd_r - buffered data read +//------------------------------------------------- + +UINT8 adam_ram_expansion_device::adam_bd_r(address_space &space, offs_t offset, UINT8 data, int bmreq, int biorq, int aux_rom_cs, int cas1, int cas2) +{ + if (!cas2) + { + data = m_ram[offset]; + } + + return data; +} + + +//------------------------------------------------- +// adam_bd_w - buffered data write +//------------------------------------------------- + +void adam_ram_expansion_device::adam_bd_w(address_space &space, offs_t offset, UINT8 data, int bmreq, int biorq, int aux_rom_cs, int cas1, int cas2) +{ + if (!cas2) + { + m_ram[offset] = data; + } +} diff --git a/src/devices/bus/adam/ram.h b/src/devices/bus/adam/ram.h new file mode 100644 index 00000000000..d6c5e470ee5 --- /dev/null +++ b/src/devices/bus/adam/ram.h @@ -0,0 +1,50 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Coleco Adam Internal 64KB RAM Expansion emulation + +**********************************************************************/ + +#pragma once + +#ifndef __ADAM_RAM__ +#define __ADAM_RAM__ + +#include "emu.h" +#include "exp.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> adam_ram_expansion_device + +class adam_ram_expansion_device : public device_t, + public device_adam_expansion_slot_card_interface +{ +public: + // construction/destruction + adam_ram_expansion_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // device-level overrides + virtual void device_start(); + + // device_adam_expansion_slot_card_interface overrides + virtual UINT8 adam_bd_r(address_space &space, offs_t offset, UINT8 data, int bmreq, int biorq, int aux_rom_cs, int cas1, int cas2); + virtual void adam_bd_w(address_space &space, offs_t offset, UINT8 data, int bmreq, int biorq, int aux_rom_cs, int cas1, int cas2); + +private: + optional_shared_ptr m_ram; +}; + + +// device type definition +extern const device_type ADAM_RAM; + + + +#endif diff --git a/src/devices/bus/adamnet/adamnet.c b/src/devices/bus/adamnet/adamnet.c new file mode 100644 index 00000000000..9407b7fbaf2 --- /dev/null +++ b/src/devices/bus/adamnet/adamnet.c @@ -0,0 +1,264 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Coleco ADAMnet bus emulation + +**********************************************************************/ + +#include "adamnet.h" + + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type ADAMNET = &device_creator; +const device_type ADAMNET_SLOT = &device_creator; + + + +//************************************************************************** +// DEVICE ADAMNET CARD INTERFACE +//************************************************************************** + +//------------------------------------------------- +// device_adamnet_card_interface - constructor +//------------------------------------------------- + +device_adamnet_card_interface::device_adamnet_card_interface(const machine_config &mconfig, device_t &device) + : device_slot_card_interface(mconfig, device) +{ +} + + +//------------------------------------------------- +// ~device_adamnet_card_interface - destructor +//------------------------------------------------- + +device_adamnet_card_interface::~device_adamnet_card_interface() +{ +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// adamnet_slot_device - constructor +//------------------------------------------------- +adamnet_slot_device::adamnet_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, ADAMNET_SLOT, "ADAMnet slot", tag, owner, clock, "adamnet_slot", __FILE__), + device_slot_interface(mconfig, *this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void adamnet_slot_device::device_start() +{ + m_bus = machine().device(ADAMNET_TAG); + device_adamnet_card_interface *dev = dynamic_cast(get_card_device()); + if (dev) m_bus->add_device(get_card_device()); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// adamnet_device - constructor +//------------------------------------------------- + +adamnet_device::adamnet_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, ADAMNET, "ADAMnet bus", tag, owner, clock, "adamnet", __FILE__), + m_txd(1), + m_reset(CLEAR_LINE) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void adamnet_device::device_start() +{ +} + + +//------------------------------------------------- +// device_stop - device-specific stop +//------------------------------------------------- + +void adamnet_device::device_stop() +{ + m_device_list.reset(); +} + + +//------------------------------------------------- +// add_adamnet_card - add ADAMNET card +//------------------------------------------------- + +void adamnet_device::add_device(device_t *target) +{ + daisy_entry *entry = global_alloc(daisy_entry(target)); + + entry->m_interface->m_bus = this; + + m_device_list.append(*entry); +} + + +//------------------------------------------------- +// daisy_entry - constructor +//------------------------------------------------- + +adamnet_device::daisy_entry::daisy_entry(device_t *device) + : m_next(NULL), + m_device(device), + m_interface(NULL), + m_txd(1) +{ + device->interface(m_interface); +} + + +//------------------------------------------------- +// rxd_r - receive data +//------------------------------------------------- + +READ_LINE_MEMBER( adamnet_device::rxd_r ) +{ + int state = m_txd;//1; + + daisy_entry *entry = m_device_list.first(); + + while (entry) + { + state &= entry->m_txd; + + entry = entry->next(); + } + + return state; +} + + +//------------------------------------------------- +// rxd_r - receive data +//------------------------------------------------- + +int adamnet_device::rxd_r(device_t *device) +{ + int state = m_txd; + + daisy_entry *entry = m_device_list.first(); + + while (entry) + { + //if (strcmp(entry->m_device->tag(), device->tag())) + { + state &= entry->m_txd; + } + + entry = entry->next(); + } + + return state; +} + + +//------------------------------------------------- +// txd_w - transmit data +//------------------------------------------------- + +WRITE_LINE_MEMBER( adamnet_device::txd_w ) +{ + if (m_txd != state) + { + m_txd = state; + } +} + + +//------------------------------------------------- +// txd_w - transmit data +//------------------------------------------------- + +void adamnet_device::txd_w(device_t *device, int state) +{ + daisy_entry *entry = m_device_list.first(); + + while (entry) + { + if (!strcmp(entry->m_device->tag(), device->tag())) + { + if (entry->m_txd != state) + { + entry->m_txd = state; + } + break; + } + + entry = entry->next(); + } +} + + +//------------------------------------------------- +// reset_r - bus reset +//------------------------------------------------- + +READ_LINE_MEMBER( adamnet_device::reset_r ) +{ + return m_reset; +} + + +//------------------------------------------------- +// reset_w - bus reset +//------------------------------------------------- + +WRITE_LINE_MEMBER( adamnet_device::reset_w ) +{ + m_reset = state; + + daisy_entry *entry = m_device_list.first(); + + while (entry) + { + entry->m_interface->adamnet_reset_w(state); + + entry = entry->next(); + } +} + + +//------------------------------------------------- +// SLOT_INTERFACE( adamnet_devices ) +//------------------------------------------------- + +// slot devices +#include "ddp.h" +#include "fdc.h" +#include "kb.h" +#include "printer.h" +#include "spi.h" + +SLOT_INTERFACE_START( adamnet_devices ) + SLOT_INTERFACE("ddp", ADAM_DDP) + SLOT_INTERFACE("fdc", ADAM_FDC) + SLOT_INTERFACE("kb", ADAM_KB) + SLOT_INTERFACE("prn", ADAM_PRN) + SLOT_INTERFACE("spi", ADAM_SPI) +SLOT_INTERFACE_END diff --git a/src/devices/bus/adamnet/adamnet.h b/src/devices/bus/adamnet/adamnet.h new file mode 100644 index 00000000000..7bbf9105556 --- /dev/null +++ b/src/devices/bus/adamnet/adamnet.h @@ -0,0 +1,131 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Coleco ADAMnet bus emulation + +**********************************************************************/ + +#pragma once + +#ifndef __ADAMNET__ +#define __ADAMNET__ + +#include "emu.h" + + + +//************************************************************************** +// CONSTANTS +//************************************************************************** + +#define ADAMNET_TAG "adamnet" + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_ADAMNET_BUS_ADD() \ + MCFG_DEVICE_ADD(ADAMNET_TAG, ADAMNET, 0) + +#define MCFG_ADAMNET_SLOT_ADD(_tag, _slot_intf, _def_slot) \ + MCFG_DEVICE_ADD(_tag, ADAMNET_SLOT, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class device_adamnet_card_interface; + +// ======================> adamnet_device + +class adamnet_device : public device_t +{ +public: + // construction/destruction + adamnet_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + void add_device(device_t *target); + + DECLARE_READ_LINE_MEMBER( rxd_r ); + int rxd_r(device_t *device); + DECLARE_WRITE_LINE_MEMBER( txd_w ); + void txd_w(device_t *device, int state); + + DECLARE_READ_LINE_MEMBER( reset_r ); + DECLARE_WRITE_LINE_MEMBER( reset_w ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_stop(); + +private: + class daisy_entry + { + public: + daisy_entry(device_t *device); + daisy_entry *next() const { return m_next; } + + daisy_entry * m_next; // next device + device_t * m_device; // associated device + device_adamnet_card_interface * m_interface; // associated device's daisy interface + + int m_txd; + }; + + simple_list m_device_list; + + int m_txd; + int m_reset; +}; + + +// ======================> adamnet_slot_device + +class adamnet_slot_device : public device_t, + public device_slot_interface +{ +public: + // construction/destruction + adamnet_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + +protected: + // configuration + adamnet_device *m_bus; +}; + + +// ======================> device_adamnet_card_interface + +class device_adamnet_card_interface : public device_slot_card_interface +{ +public: + // construction/destruction + device_adamnet_card_interface(const machine_config &mconfig, device_t &device); + virtual ~device_adamnet_card_interface(); + + virtual void adamnet_reset_w(int state) = 0; + + adamnet_device *m_bus; +}; + + +// device type definitions +extern const device_type ADAMNET; +extern const device_type ADAMNET_SLOT; + + +SLOT_INTERFACE_EXTERN( adamnet_devices ); + + + +#endif diff --git a/src/devices/bus/adamnet/ddp.c b/src/devices/bus/adamnet/ddp.c new file mode 100644 index 00000000000..cca1617dd43 --- /dev/null +++ b/src/devices/bus/adamnet/ddp.c @@ -0,0 +1,308 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Coleco Adam Digital Data Pack emulation + +**********************************************************************/ + +#include "ddp.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define M6801_TAG "m6801" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type ADAM_DDP = &device_creator; + + +//------------------------------------------------- +// ROM( adam_ddp ) +//------------------------------------------------- + +ROM_START( adam_ddp ) + ROM_REGION( 0x800, M6801_TAG, 0 ) + ROM_LOAD( "tape rev a 8865.u24", 0x000, 0x800, CRC(6b9ea1cf) SHA1(b970f11e8f443fa130fba02ad1f60da51bf89673) ) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *adam_digital_data_pack_device::device_rom_region() const +{ + return ROM_NAME( adam_ddp ); +} + + +//------------------------------------------------- +// ADDRESS_MAP( adam_ddp_mem ) +//------------------------------------------------- + +static ADDRESS_MAP_START( adam_ddp_mem, AS_PROGRAM, 8, adam_digital_data_pack_device ) + AM_RANGE(0x0000, 0x001f) AM_DEVREADWRITE(M6801_TAG, m6801_cpu_device, m6801_io_r, m6801_io_w) + AM_RANGE(0x0080, 0x00ff) AM_RAM + AM_RANGE(0x0400, 0x07ff) AM_RAM + AM_RANGE(0xf800, 0xffff) AM_ROM AM_REGION(M6801_TAG, 0) +ADDRESS_MAP_END + + +//------------------------------------------------- +// ADDRESS_MAP( adam_ddp_io ) +//------------------------------------------------- + +static ADDRESS_MAP_START( adam_ddp_io, AS_IO, 8, adam_digital_data_pack_device ) + AM_RANGE(M6801_PORT1, M6801_PORT1) AM_WRITE(p1_w) + AM_RANGE(M6801_PORT2, M6801_PORT2) AM_READWRITE(p2_r, p2_w) + AM_RANGE(M6801_PORT3, M6801_PORT3) AM_NOP // Multiplexed Address/Data + AM_RANGE(M6801_PORT4, M6801_PORT4) AM_READ(p4_r) AM_WRITENOP +ADDRESS_MAP_END + +static const struct CassetteOptions adam_cassette_options = +{ + 2, /* channels */ + 16, /* bits per sample */ + 44100 /* sample frequency */ +}; + +//------------------------------------------------- +// MACHINE_DRIVER( adam_ddp ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( adam_ddp ) + MCFG_CPU_ADD(M6801_TAG, M6801, XTAL_4MHz) + MCFG_CPU_PROGRAM_MAP(adam_ddp_mem) + MCFG_CPU_IO_MAP(adam_ddp_io) + + MCFG_CASSETTE_ADD("cassette") + MCFG_CASSETTE_FORMATS(coleco_adam_cassette_formats) + MCFG_CASSETTE_CREATE_OPTS(&adam_cassette_options) + MCFG_CASSETTE_DEFAULT_STATE(CASSETTE_PLAY | CASSETTE_MOTOR_DISABLED | CASSETTE_SPEAKER_MUTED) + MCFG_CASSETTE_INTERFACE("adam_cass") + + MCFG_CASSETTE_ADD("cassette2") + MCFG_CASSETTE_FORMATS(coleco_adam_cassette_formats) + MCFG_CASSETTE_CREATE_OPTS(&adam_cassette_options) + MCFG_CASSETTE_DEFAULT_STATE(CASSETTE_PLAY | CASSETTE_MOTOR_DISABLED | CASSETTE_SPEAKER_MUTED) + MCFG_CASSETTE_INTERFACE("adam_cass") +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor adam_digital_data_pack_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( adam_ddp ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// adam_digital_data_pack_device - constructor +//------------------------------------------------- + +adam_digital_data_pack_device::adam_digital_data_pack_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, ADAM_DDP, "Adam DDP", tag, owner, clock, "adam_ddp", __FILE__), + device_adamnet_card_interface(mconfig, *this), + m_maincpu(*this, M6801_TAG), + m_ddp0(*this, "cassette"), + m_ddp1(*this, "cassette2") +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void adam_digital_data_pack_device::device_start() +{ + // state saving + save_item(NAME(m_wr0)); + save_item(NAME(m_wr1)); + save_item(NAME(m_track)); +} + + +//------------------------------------------------- +// adamnet_reset_w - +//------------------------------------------------- + +void adam_digital_data_pack_device::adamnet_reset_w(int state) +{ + m_maincpu->set_input_line(INPUT_LINE_RESET, state); +} + + +//------------------------------------------------- +// p1_w - +//------------------------------------------------- + +WRITE8_MEMBER( adam_digital_data_pack_device::p1_w ) +{ + /* + + bit description + + 0 SPD SEL (0=20 ips, 1=80ips) + 1 STOP0 + 2 STOP1 + 3 _GO FWD + 4 _GO REV + 5 BRAKE + 6 _WR0 + 7 _WR1 + + */ + + if (m_ddp0->exists()) + { + m_ddp0->set_speed(BIT(data, 0) ? (double) 80/1.875 : 20/1.875); // speed select + if(!(data & 0x08)) m_ddp0->go_forward(); + if(!(data & 0x10)) m_ddp0->go_reverse(); + m_ddp0->change_state(BIT(data, 1) ? CASSETTE_MOTOR_DISABLED : CASSETTE_MOTOR_ENABLED, CASSETTE_MASK_MOTOR); // motor control + } + + if (m_ddp1->exists()) + { + m_ddp1->set_speed(BIT(data, 0) ? (double) 80/1.875 : 20/1.875); // speed select + if(!(data & 0x08)) m_ddp1->go_forward(); + if(!(data & 0x10)) m_ddp1->go_reverse(); + m_ddp1->change_state(BIT(data, 2) ? CASSETTE_MOTOR_DISABLED : CASSETTE_MOTOR_ENABLED, CASSETTE_MASK_MOTOR); // motor control + } + + // data write 0 + m_wr0 = BIT(data, 6); + + // data write 1 + m_wr1 = BIT(data, 7); +} + + +//------------------------------------------------- +// p2_r - +//------------------------------------------------- + +READ8_MEMBER( adam_digital_data_pack_device::p2_r ) +{ + /* + + bit description + + 0 mode bit 0 + 1 mode bit 1 / CIP1 + 2 mode bit 2 + 3 NET RXD + 4 + + */ + + UINT8 data = 0; + + if (m_bus->reset_r()) + data |= M6801_MODE_6; + else + data |= m_ddp1->exists() << 1; // Cassette in place 1 + + // NET RXD + data |= m_bus->rxd_r(this) << 3; + + return data; +} + + +//------------------------------------------------- +// p2_w - +//------------------------------------------------- + +WRITE8_MEMBER( adam_digital_data_pack_device::p2_w ) +{ + /* + + bit description + + 0 WRT DATA + 1 + 2 TRACK A/B (0=B, 1=A) + 3 + 4 NET TXD + + */ + + if (m_ddp0->exists()) + { + m_ddp0->set_channel(!BIT(data, 2)); // Track select + if (!m_wr0) m_ddp0->output(BIT(data, 0) ? 1.0 : -1.0); // write data + } + + if (m_ddp1->exists()) + { + m_ddp1->set_channel(!BIT(data, 2)); + if (!m_wr1) m_ddp1->output(BIT(data, 0) ? 1.0 : -1.0); + } + + // NET TXD + m_bus->txd_w(this, BIT(data, 4)); +} + + +//------------------------------------------------- +// p4_r - +//------------------------------------------------- + +READ8_MEMBER( adam_digital_data_pack_device::p4_r ) +{ + /* + + bit description + + 0 A8 + 1 A9 + 2 A10 (2114 _S) + 3 MSENSE 0 + 4 MSENSE 1 + 5 CIP0 + 6 RD DATA 0 (always 1) + 7 RD DATA 1 (data from drives ORed together) + + */ + + UINT8 data = 0; + + // drive 0 + if (m_ddp0->exists()) + { + data |= ((m_ddp0->get_state() & CASSETTE_MASK_UISTATE) != CASSETTE_STOPPED) << 3; // motion sense + data |= 1 << 5; // cassette in place + data |= (m_ddp0->input() < 0) << 7; // read data + } + + // drive 1 + if (m_ddp1->exists()) + { + data |= ((m_ddp1->get_state() & CASSETTE_MASK_UISTATE) != CASSETTE_STOPPED) << 4; // motion sense + data |= (m_ddp1->input() < 0) << 7; // read data + } + + // read data 0 (always 1) + data |= 0x40; + + return data; +} diff --git a/src/devices/bus/adamnet/ddp.h b/src/devices/bus/adamnet/ddp.h new file mode 100644 index 00000000000..07c2bf0c0c1 --- /dev/null +++ b/src/devices/bus/adamnet/ddp.h @@ -0,0 +1,67 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Coleco Adam Digital Data Pack emulation + +**********************************************************************/ + +#pragma once + +#ifndef __ADAM_DDP__ +#define __ADAM_DDP__ + +#include "emu.h" +#include "adamnet.h" +#include "cpu/m6800/m6800.h" +#include "formats/adam_cas.h" +#include "imagedev/cassette.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> adam_digital_data_pack_device + +class adam_digital_data_pack_device : public device_t, + public device_adamnet_card_interface +{ +public: + // construction/destruction + adam_digital_data_pack_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + + // not really public + DECLARE_WRITE8_MEMBER( p1_w ); + DECLARE_READ8_MEMBER( p2_r ); + DECLARE_WRITE8_MEMBER( p2_w ); + DECLARE_READ8_MEMBER( p4_r ); + +protected: + // device-level overrides + virtual void device_start(); + + // device_adamnet_card_interface overrides + virtual void adamnet_reset_w(int state); + + required_device m_maincpu; + required_device m_ddp0; + required_device m_ddp1; + + int m_wr0; + int m_wr1; + int m_track; +}; + + +// device type definition +extern const device_type ADAM_DDP; + + + +#endif diff --git a/src/devices/bus/adamnet/fdc.c b/src/devices/bus/adamnet/fdc.c new file mode 100644 index 00000000000..afe93d74a29 --- /dev/null +++ b/src/devices/bus/adamnet/fdc.c @@ -0,0 +1,352 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Coleco Adam floppy disk controller emulation + +**********************************************************************/ + +/* + + TODO: + + - 320KB DSDD 5.25" + - 720KB DSDD 3.5" + - 1.44MB DSHD 3.5" + +*/ + +#include "fdc.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define M6801_TAG "u6" +#define WD2793_TAG "u11" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type ADAM_FDC = &device_creator; + + +//------------------------------------------------- +// ROM( adam_fdc ) +//------------------------------------------------- + +ROM_START( adam_fdc ) + ROM_REGION( 0x1000, M6801_TAG, 0 ) + ROM_DEFAULT_BIOS("ssdd") + ROM_SYSTEM_BIOS( 0, "ssdd", "Coleco 160KB SSDD" ) + ROMX_LOAD( "adam disk u10 ad 31 rev a 09-27-84.u10", 0x0000, 0x1000, CRC(4b0b7143) SHA1(1cb68891c3af80e99efad7e309136ca37244f060), ROM_BIOS(1) ) + ROM_SYSTEM_BIOS( 1, "320ta", "320KB DSDD" ) + ROMX_LOAD( "320ta.u10", 0x0000, 0x1000, CRC(dcd865b3) SHA1(dde583e0d18ce4406e9ea44ab34d083e73ee30e2), ROM_BIOS(2) ) + ROM_SYSTEM_BIOS( 2, "dbl24", "320KB DSDD" ) + ROMX_LOAD( "dbl2-4.u10", 0x0000, 0x1000, CRC(5df49f15) SHA1(43d5710e4fb05f520e813869a049585b41ada86b), ROM_BIOS(3) ) + ROM_SYSTEM_BIOS( 3, "dsdd", "320KB DSDD" ) + ROMX_LOAD( "unknown.u10", 0x0000, 0x1000, CRC(2b2a9c6d) SHA1(e40304cbb6b9f174d9f5762d920983c79c899b3e), ROM_BIOS(4) ) + ROM_SYSTEM_BIOS( 4, "a720dipi", "720KB 3.5\" A720DIPI 7607 MMSG" ) + ROMX_LOAD( "a720dipi 7607 mmsg (c) 1988.u10", 0x0000, 0x1000, CRC(5f248557) SHA1(15b3aaebba38af84f6a1a6ccdf840ca3d58635da), ROM_BIOS(5) ) + ROM_SYSTEM_BIOS( 5, "fp720at", "720KB 3.5\" FastPack 720A(T)" ) + ROMX_LOAD( "fastpack 720a(t).u10", 0x0000, 0x1000, CRC(8f952c88) SHA1(e593a89d7c6e7ea99e7ce376ffa2732d7b646d49), ROM_BIOS(6) ) + ROM_SYSTEM_BIOS( 6, "mihddd", "1.44MB 3.5\" Micro Innovations HD-DD" ) + ROMX_LOAD( "1440k micro innovations hd-dd.u10", 0x0000, 0x1000, CRC(2efec8c0) SHA1(f6df22339c93dca938b65d0cbe23abcad89ec230), ROM_BIOS(7) ) + ROM_SYSTEM_BIOS( 7, "pmhd", "1.44MB 3.5\" Powermate High Density" ) + ROMX_LOAD( "pmhdfdc.u10", 0x0000, 0x1000, CRC(fed4006c) SHA1(bc8dd00dd5cde9500a4cd7dc1e4d74330184472a), ROM_BIOS(8) ) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *adam_fdc_device::device_rom_region() const +{ + return ROM_NAME( adam_fdc ); +} + + +//------------------------------------------------- +// ADDRESS_MAP( fdc6801_mem ) +//------------------------------------------------- + +static ADDRESS_MAP_START( adam_fdc_mem, AS_PROGRAM, 8, adam_fdc_device ) + AM_RANGE(0x0000, 0x001f) AM_DEVREADWRITE(M6801_TAG, m6801_cpu_device, m6801_io_r, m6801_io_w) + AM_RANGE(0x0080, 0x00ff) AM_RAM + AM_RANGE(0x0400, 0x07ff) AM_RAM AM_WRITEONLY AM_SHARE("ram") + AM_RANGE(0x0800, 0x0800) AM_MIRROR(0x3ff) AM_DEVREAD(WD2793_TAG, wd2793_t, status_r) + AM_RANGE(0x1400, 0x17ff) AM_RAM AM_READONLY AM_SHARE("ram") + AM_RANGE(0x1800, 0x1800) AM_MIRROR(0x3ff) AM_DEVWRITE(WD2793_TAG, wd2793_t, cmd_w) + AM_RANGE(0x2800, 0x2800) AM_MIRROR(0x3ff) AM_DEVREAD(WD2793_TAG, wd2793_t, track_r) + AM_RANGE(0x3800, 0x3800) AM_MIRROR(0x3ff) AM_DEVWRITE(WD2793_TAG, wd2793_t, track_w) + AM_RANGE(0x4800, 0x4800) AM_MIRROR(0x3ff) AM_DEVREAD(WD2793_TAG, wd2793_t, sector_r) + AM_RANGE(0x5800, 0x5800) AM_MIRROR(0x3ff) AM_DEVWRITE(WD2793_TAG, wd2793_t, sector_w) + AM_RANGE(0x6800, 0x6800) AM_MIRROR(0x3ff) AM_DEVREAD(WD2793_TAG, wd2793_t, data_r) + AM_RANGE(0x6c00, 0x6fff) AM_READ(data_r) + AM_RANGE(0x7800, 0x7800) AM_MIRROR(0x3ff) AM_DEVWRITE(WD2793_TAG, wd2793_t, data_w) + AM_RANGE(0x8000, 0x8fff) AM_MIRROR(0x7000) AM_ROM AM_REGION(M6801_TAG, 0) +ADDRESS_MAP_END + + +//------------------------------------------------- +// ADDRESS_MAP( fdc6801_io ) +//------------------------------------------------- + +static ADDRESS_MAP_START( adam_fdc_io, AS_IO, 8, adam_fdc_device ) + AM_RANGE(M6801_PORT1, M6801_PORT1) AM_READWRITE(p1_r, p1_w) + AM_RANGE(M6801_PORT2, M6801_PORT2) AM_READWRITE(p2_r, p2_w) + AM_RANGE(M6801_PORT3, M6801_PORT3) + AM_RANGE(M6801_PORT4, M6801_PORT4) +ADDRESS_MAP_END + + +//------------------------------------------------- +// floppy_format_type floppy_formats +//------------------------------------------------- + +FLOPPY_FORMATS_MEMBER( adam_fdc_device::floppy_formats ) + FLOPPY_ADAM_FORMAT +FLOPPY_FORMATS_END + +static SLOT_INTERFACE_START( adam_fdc_floppies ) + SLOT_INTERFACE( "525ssdd", FLOPPY_525_SSDD ) +SLOT_INTERFACE_END + + +//------------------------------------------------- +// MACHINE_DRIVER( adam_fdc ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( adam_fdc ) + MCFG_CPU_ADD(M6801_TAG, M6801, XTAL_4MHz) + MCFG_CPU_PROGRAM_MAP(adam_fdc_mem) + MCFG_CPU_IO_MAP(adam_fdc_io) + + MCFG_WD2793_ADD(WD2793_TAG, XTAL_4MHz/4) + MCFG_WD_FDC_INTRQ_CALLBACK(INPUTLINE(M6801_TAG, INPUT_LINE_NMI)) + + MCFG_FLOPPY_DRIVE_ADD(WD2793_TAG":0", adam_fdc_floppies, "525ssdd", adam_fdc_device::floppy_formats) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor adam_fdc_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( adam_fdc ); +} + + +//------------------------------------------------- +// INPUT_PORTS( adam_fdc ) +//------------------------------------------------- + +static INPUT_PORTS_START( adam_fdc ) + PORT_START("SW3") + PORT_DIPNAME( 0x01, 0x00, "Drive Select" ) PORT_DIPLOCATION("SW3:1") + PORT_DIPSETTING( 0x00, "DS1" ) + PORT_DIPSETTING( 0x01, "DS2" ) +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor adam_fdc_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( adam_fdc ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// adam_fdc_device - constructor +//------------------------------------------------- + +adam_fdc_device::adam_fdc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, ADAM_FDC, "Adam FDC", tag, owner, clock, "adam_fdc", __FILE__), + device_adamnet_card_interface(mconfig, *this), + m_maincpu(*this, M6801_TAG), + m_fdc(*this, WD2793_TAG), + m_floppy0(*this, WD2793_TAG":0:525ssdd"), + m_floppy(NULL), + m_ram(*this, "ram"), + m_sw3(*this, "SW3") +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void adam_fdc_device::device_start() +{ +} + + +//------------------------------------------------- +// adamnet_reset_w - +//------------------------------------------------- + +void adam_fdc_device::adamnet_reset_w(int state) +{ + m_maincpu->set_input_line(INPUT_LINE_RESET, state); + + if (state == ASSERT_LINE) m_fdc->reset(); +} + + +//------------------------------------------------- +// data_r - +//------------------------------------------------- + +READ8_MEMBER( adam_fdc_device::data_r ) +{ + UINT8 data = m_fdc->data_r(); + + m_ram[offset & 0x3ff] = data; + + return data; +} + + +//------------------------------------------------- +// p1_r - +//------------------------------------------------- + +READ8_MEMBER( adam_fdc_device::p1_r ) +{ + /* + + bit description + + 0 disk in place + 1 + 2 FDC DRQ + 3 + 4 + 5 + 6 + 7 SW3 (0=DS1, 1=DS2) + + */ + + UINT8 data = 0x00; + + // disk in place + data |= m_floppy0->exists() ? 0x00 : 0x01; + + // floppy data request + data |= m_fdc->drq_r() ? 0x04 : 0x00; + + // drive select + data |= m_sw3->read() << 7; + + return data; +} + + +//------------------------------------------------- +// p1_w - +//------------------------------------------------- + +WRITE8_MEMBER( adam_fdc_device::p1_w ) +{ + /* + + bit description + + 0 + 1 FDC ENP + 2 + 3 FDC _DDEN + 4 + 5 DRIVE SELECT + 6 MOTOR ON + 7 + + */ + + // write precompensation + //m_fdc->enp_w(BIT(data, 1)); + + // density select + m_fdc->dden_w(BIT(data, 3)); + + // drive select + m_floppy = NULL; + + if (BIT(data, 5)) + { + m_floppy = m_floppy0; + } + + m_fdc->set_floppy(m_floppy); + + // motor enable + if (m_floppy) m_floppy->mon_w(!BIT(data, 6)); +} + + +//------------------------------------------------- +// p2_r - +//------------------------------------------------- + +READ8_MEMBER( adam_fdc_device::p2_r ) +{ + /* + + bit description + + 0 mode bit 0 + 1 mode bit 1 + 2 mode bit 2 + 3 NET RXD + 4 + + */ + + UINT8 data = M6801_MODE_2; + + // NET RXD + data |= m_bus->rxd_r(this) << 3; + + return data; +} + + +//------------------------------------------------- +// p2_w - +//------------------------------------------------- + +WRITE8_MEMBER( adam_fdc_device::p2_w ) +{ + /* + + bit description + + 0 + 1 + 2 + 3 + 4 NET TXD + + */ + + m_bus->txd_w(this, BIT(data, 4)); +} diff --git a/src/devices/bus/adamnet/fdc.h b/src/devices/bus/adamnet/fdc.h new file mode 100644 index 00000000000..fb519e1a5ba --- /dev/null +++ b/src/devices/bus/adamnet/fdc.h @@ -0,0 +1,69 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Coleco Adam floppy disk controller emulation + +**********************************************************************/ + +#pragma once + +#ifndef __ADAM_FDC__ +#define __ADAM_FDC__ + +#include "emu.h" +#include "adamnet.h" +#include "cpu/m6800/m6800.h" +#include "formats/adam_dsk.h" +#include "machine/wd_fdc.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> adam_fdc_device + +class adam_fdc_device : public device_t, + public device_adamnet_card_interface +{ +public: + // construction/destruction + adam_fdc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + virtual ioport_constructor device_input_ports() const; + + // not really public + DECLARE_READ8_MEMBER( data_r ); + DECLARE_READ8_MEMBER( p1_r ); + DECLARE_WRITE8_MEMBER( p1_w ); + DECLARE_READ8_MEMBER( p2_r ); + DECLARE_WRITE8_MEMBER( p2_w ); + + DECLARE_FLOPPY_FORMATS( floppy_formats ); + +protected: + // device-level overrides + virtual void device_start(); + + // device_adamnet_card_interface overrides + virtual void adamnet_reset_w(int state); + + required_device m_maincpu; + required_device m_fdc; + required_device m_floppy0; + floppy_image_device *m_floppy; + required_shared_ptr m_ram; + required_ioport m_sw3; +}; + + +// device type definition +extern const device_type ADAM_FDC; + + +#endif diff --git a/src/devices/bus/adamnet/kb.c b/src/devices/bus/adamnet/kb.c new file mode 100644 index 00000000000..a9cc31b8edf --- /dev/null +++ b/src/devices/bus/adamnet/kb.c @@ -0,0 +1,425 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Coleco Adam keyboard emulation + +**********************************************************************/ + +#include "kb.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define M6801_TAG "u2" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type ADAM_KB = &device_creator; + + +//------------------------------------------------- +// ROM( adam_kb ) +//------------------------------------------------- + +ROM_START( adam_kb ) + ROM_REGION( 0x800, M6801_TAG, 0 ) + ROM_LOAD( "keyboard.u2", 0x000, 0x800, CRC(ef204746) SHA1(83162ffc75847328a05429135b728a63efb05b93) ) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *adam_keyboard_device::device_rom_region() const +{ + return ROM_NAME( adam_kb ); +} + + +//------------------------------------------------- +// ADDRESS_MAP( adam_kb_mem ) +//------------------------------------------------- + +static ADDRESS_MAP_START( adam_kb_mem, AS_PROGRAM, 8, adam_keyboard_device ) + AM_RANGE(0x0000, 0x001f) AM_DEVREADWRITE(M6801_TAG, m6801_cpu_device, m6801_io_r, m6801_io_w) + AM_RANGE(0x0080, 0x00ff) AM_RAM + AM_RANGE(0xf800, 0xffff) AM_ROM AM_REGION(M6801_TAG, 0) +ADDRESS_MAP_END + + +//------------------------------------------------- +// ADDRESS_MAP( adam_kb_io ) +//------------------------------------------------- + +static ADDRESS_MAP_START( adam_kb_io, AS_IO, 8, adam_keyboard_device ) + AM_RANGE(M6801_PORT1, M6801_PORT1) AM_READ(p1_r) + AM_RANGE(M6801_PORT2, M6801_PORT2) AM_READWRITE(p2_r, p2_w) + AM_RANGE(M6801_PORT3, M6801_PORT3) AM_READWRITE(p3_r, p3_w) + AM_RANGE(M6801_PORT4, M6801_PORT4) AM_READWRITE(p4_r, p4_w) +ADDRESS_MAP_END + + +//------------------------------------------------- +// MACHINE_DRIVER( adam_kb ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( adam_kb ) + MCFG_CPU_ADD(M6801_TAG, M6801, XTAL_4MHz) + MCFG_CPU_PROGRAM_MAP(adam_kb_mem) + MCFG_CPU_IO_MAP(adam_kb_io) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor adam_keyboard_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( adam_kb ); +} + + +//------------------------------------------------- +// INPUT_PORTS( adam_kb ) +//------------------------------------------------- + +static INPUT_PORTS_START( adam_kb ) + PORT_START("Y0") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("WILD CARD") PORT_CODE(KEYCODE_F7) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("I") PORT_CODE(KEYCODE_F1) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("II") PORT_CODE(KEYCODE_F2) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("III") PORT_CODE(KEYCODE_F3) + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("IV") PORT_CODE(KEYCODE_F4) + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("V") PORT_CODE(KEYCODE_F5) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("VI") PORT_CODE(KEYCODE_F6) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("UNDO") PORT_CODE(KEYCODE_F8) + + PORT_START("Y1") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_1) PORT_CHAR('1') PORT_CHAR('!') + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_2) PORT_CHAR('2') PORT_CHAR('@') + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_3) PORT_CHAR('3') PORT_CHAR('#') + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_4) PORT_CHAR('4') PORT_CHAR('$') + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_5) PORT_CHAR('5') PORT_CHAR('%') + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_6) PORT_CHAR('6') PORT_CHAR('_') + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_7) PORT_CHAR('7') PORT_CHAR('&') + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_8) PORT_CHAR('8') PORT_CHAR('*') + + PORT_START("Y2") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("TAB") PORT_CODE(KEYCODE_TAB) PORT_CHAR('\t') + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Q) PORT_CHAR('q') PORT_CHAR('Q') + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_W) PORT_CHAR('w') PORT_CHAR('W') + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_E) PORT_CHAR('e') PORT_CHAR('E') + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_R) PORT_CHAR('r') PORT_CHAR('R') + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_T) PORT_CHAR('t') PORT_CHAR('T') + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Y) PORT_CHAR('y') PORT_CHAR('Y') + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_U) PORT_CHAR('u') PORT_CHAR('U') + + PORT_START("Y3") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_A) PORT_CHAR('a') PORT_CHAR('A') + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_S) PORT_CHAR('s') PORT_CHAR('S') + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_D) PORT_CHAR('d') PORT_CHAR('D') + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F) PORT_CHAR('f') PORT_CHAR('F') + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_G) PORT_CHAR('g') PORT_CHAR('G') + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_H) PORT_CHAR('h') PORT_CHAR('H') + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_J) PORT_CHAR('j') PORT_CHAR('J') + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_K) PORT_CHAR('k') PORT_CHAR('K') + + PORT_START("Y4") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Z) PORT_CHAR('z') PORT_CHAR('Z') + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_X) PORT_CHAR('x') PORT_CHAR('X') + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_C) PORT_CHAR('c') PORT_CHAR('C') + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_V) PORT_CHAR('v') PORT_CHAR('V') + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_B) PORT_CHAR('b') PORT_CHAR('B') + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_N) PORT_CHAR('n') PORT_CHAR('N') + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_M) PORT_CHAR('m') PORT_CHAR('M') + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_COMMA) PORT_CHAR(',') PORT_CHAR('<') + + PORT_START("Y5") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_9) PORT_CHAR('9') PORT_CHAR('(') + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_0) PORT_CHAR('0') PORT_CHAR(')') + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_MINUS) PORT_CHAR('-') PORT_CHAR('\'') + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_EQUALS) PORT_CHAR('+') PORT_CHAR('=') + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_TILDE) PORT_CHAR('^') PORT_CHAR('~') + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_L) PORT_CHAR('l') PORT_CHAR('L') + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_COLON) PORT_CHAR(';') PORT_CHAR(':') + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_QUOTE) PORT_CHAR('\'') PORT_CHAR('\"') + + PORT_START("Y6") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_I) PORT_CHAR('i') PORT_CHAR('I') + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_O) PORT_CHAR('o') PORT_CHAR('O') + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_P) PORT_CHAR('p') PORT_CHAR('P') + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_OPENBRACE) PORT_CHAR('[') PORT_CHAR('{') + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_CLOSEBRACE) PORT_CHAR(']') PORT_CHAR('}') + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_STOP) PORT_CHAR('.') PORT_CHAR('>') + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_SLASH) PORT_CHAR('/') PORT_CHAR('?') + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("RETURN") PORT_CODE(KEYCODE_ENTER) PORT_CHAR(13) + + PORT_START("Y7") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_BACKSLASH) PORT_CHAR('\\') PORT_CHAR('|') + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("ESCAPE/WP") PORT_CODE(KEYCODE_ESC) PORT_CHAR(UCHAR_MAMEKEY(ESC)) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Space") PORT_CODE(KEYCODE_SPACE) PORT_CHAR(' ') + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("MOVE/COPY") PORT_CODE(KEYCODE_INSERT) PORT_CHAR(UCHAR_MAMEKEY(INSERT)) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("STORE/GET") PORT_CODE(KEYCODE_HOME) PORT_CHAR(UCHAR_MAMEKEY(HOME)) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("CLEAR") PORT_CODE(KEYCODE_PGUP) PORT_CHAR(UCHAR_MAMEKEY(PGUP)) + + PORT_START("Y8") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME(UTF8_UP) PORT_CODE(KEYCODE_UP) PORT_CHAR(UCHAR_MAMEKEY(UP)) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME(UTF8_RIGHT) PORT_CODE(KEYCODE_RIGHT) PORT_CHAR(UCHAR_MAMEKEY(RIGHT)) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME(UTF8_DOWN) PORT_CODE(KEYCODE_DOWN) PORT_CHAR(UCHAR_MAMEKEY(DOWN)) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME(UTF8_LEFT) PORT_CODE(KEYCODE_LEFT) PORT_CHAR(UCHAR_MAMEKEY(LEFT)) + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("BACKSPACE") PORT_CODE(KEYCODE_BACKSPACE) PORT_CHAR(8) + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("INSERT") PORT_CODE(KEYCODE_DEL) PORT_CHAR(UCHAR_MAMEKEY(DEL)) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("PRINT") PORT_CODE(KEYCODE_END) PORT_CHAR(UCHAR_MAMEKEY(END)) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("DELETE") PORT_CODE(KEYCODE_PGDN) PORT_CHAR(UCHAR_MAMEKEY(PGDN)) + + PORT_START("Y9") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("CONTROL") PORT_CODE(KEYCODE_LCONTROL) PORT_CHAR(UCHAR_MAMEKEY(LCONTROL)) + PORT_BIT( 0xfe, IP_ACTIVE_LOW, IPT_UNUSED ) + + PORT_START("Y10") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("SHIFT") PORT_CODE(KEYCODE_LSHIFT) PORT_CODE(KEYCODE_RSHIFT) PORT_CHAR(UCHAR_SHIFT_1) + PORT_BIT( 0xfe, IP_ACTIVE_LOW, IPT_UNUSED ) + + PORT_START("Y11") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("LOCK") PORT_CODE(KEYCODE_CAPSLOCK) PORT_CHAR(UCHAR_MAMEKEY(CAPSLOCK)) + PORT_BIT( 0xfe, IP_ACTIVE_LOW, IPT_UNUSED ) + + PORT_START("Y12") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("HOME") PORT_CODE(KEYCODE_F9) + PORT_BIT( 0xfe, IP_ACTIVE_LOW, IPT_UNUSED ) +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor adam_keyboard_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( adam_kb ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// adam_keyboard_device - constructor +//------------------------------------------------- + +adam_keyboard_device::adam_keyboard_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, ADAM_KB, "Adam keyboard", tag, owner, clock, "adam_kb", __FILE__), + device_adamnet_card_interface(mconfig, *this), + m_maincpu(*this, M6801_TAG), + m_y0(*this, "Y0"), + m_y1(*this, "Y1"), + m_y2(*this, "Y2"), + m_y3(*this, "Y3"), + m_y4(*this, "Y4"), + m_y5(*this, "Y5"), + m_y6(*this, "Y6"), + m_y7(*this, "Y7"), + m_y8(*this, "Y8"), + m_y9(*this, "Y9"), + m_y10(*this, "Y10"), + m_y11(*this, "Y11"), + m_y12(*this, "Y12"), + m_key_y(0x1ff) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void adam_keyboard_device::device_start() +{ + // state saving + save_item(NAME(m_key_y)); +} + + +//------------------------------------------------- +// adamnet_reset_w - +//------------------------------------------------- + +void adam_keyboard_device::adamnet_reset_w(int state) +{ + m_maincpu->set_input_line(INPUT_LINE_RESET, state); +} + + +//------------------------------------------------- +// p1_r - +//------------------------------------------------- + +READ8_MEMBER( adam_keyboard_device::p1_r ) +{ + /* + + bit description + + 0 X0 + 1 X1 + 2 X2 + 3 X3 + 4 X4 + 5 X5 + 6 X6 + 7 X7 + + */ + + UINT8 data = 0xff; + + if (!BIT(m_key_y, 0)) data &= m_y0->read(); + if (!BIT(m_key_y, 1)) data &= m_y1->read(); + if (!BIT(m_key_y, 2)) data &= m_y2->read(); + if (!BIT(m_key_y, 3)) data &= m_y3->read(); + if (!BIT(m_key_y, 4)) data &= m_y4->read(); + if (!BIT(m_key_y, 5)) data &= m_y5->read(); + if (!BIT(m_key_y, 6)) data &= m_y6->read(); + if (!BIT(m_key_y, 7)) data &= m_y7->read(); + if (!BIT(m_key_y, 8)) data &= m_y8->read(); + if (!BIT(m_key_y, 9)) data &= m_y9->read(); + if (!BIT(m_key_y, 10)) data &= m_y10->read(); + if (!BIT(m_key_y, 11)) data &= m_y11->read(); + if (!BIT(m_key_y, 12)) data &= m_y12->read(); + + return data; +} + + +//------------------------------------------------- +// p2_r - +//------------------------------------------------- + +READ8_MEMBER( adam_keyboard_device::p2_r ) +{ + /* + + bit description + + 0 mode bit 0 + 1 mode bit 1 + 2 mode bit 2 + 3 NET RXD + 4 + + */ + + UINT8 data = M6801_MODE_7; + + // NET RXD + data |= m_bus->rxd_r(this) << 3; + + return data; +} + + +//------------------------------------------------- +// p2_w - +//------------------------------------------------- + +WRITE8_MEMBER( adam_keyboard_device::p2_w ) +{ + /* + + bit description + + 0 + 1 + 2 + 3 + 4 NET TXD + + */ + + m_bus->txd_w(this, BIT(data, 4)); +} + + +//------------------------------------------------- +// p3_r - +//------------------------------------------------- + +READ8_MEMBER( adam_keyboard_device::p3_r ) +{ + return 0xff; +} + + +//------------------------------------------------- +// p3_w - +//------------------------------------------------- + +WRITE8_MEMBER( adam_keyboard_device::p3_w ) +{ + /* + + bit description + + 0 Y0 + 1 Y1 + 2 Y2 + 3 Y3 + 4 Y4 + 5 Y5 + 6 Y6 + 7 Y7 + + */ + + m_key_y = (m_key_y & 0x1f00) | data; +} + + +//------------------------------------------------- +// p4_r - +//------------------------------------------------- + +READ8_MEMBER( adam_keyboard_device::p4_r ) +{ + return 0xff; +} + + +//------------------------------------------------- +// p4_w - +//------------------------------------------------- + +WRITE8_MEMBER( adam_keyboard_device::p4_w ) +{ + /* + + bit description + + 0 Y8 + 1 Y9 + 2 Y10 + 3 Y11 + 4 Y12 + 5 + 6 + 7 + + */ + + m_key_y = ((data & 0x1f) << 8) | (m_key_y & 0xff); +} diff --git a/src/devices/bus/adamnet/kb.h b/src/devices/bus/adamnet/kb.h new file mode 100644 index 00000000000..58bf9f07bc5 --- /dev/null +++ b/src/devices/bus/adamnet/kb.h @@ -0,0 +1,78 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Coleco Adam keyboard emulation + +**********************************************************************/ + +#pragma once + +#ifndef __ADAM_KB__ +#define __ADAM_KB__ + +#include "emu.h" +#include "adamnet.h" +#include "cpu/m6800/m6800.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> adam_keyboard_device + +class adam_keyboard_device : public device_t, + public device_adamnet_card_interface +{ +public: + // construction/destruction + adam_keyboard_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + virtual ioport_constructor device_input_ports() const; + + // not really public + DECLARE_READ8_MEMBER( p1_r ); + DECLARE_READ8_MEMBER( p2_r ); + DECLARE_WRITE8_MEMBER( p2_w ); + DECLARE_READ8_MEMBER( p3_r ); + DECLARE_WRITE8_MEMBER( p3_w ); + DECLARE_READ8_MEMBER( p4_r ); + DECLARE_WRITE8_MEMBER( p4_w ); + +protected: + // device-level overrides + virtual void device_start(); + + // device_adamnet_card_interface overrides + virtual void adamnet_reset_w(int state); + + required_device m_maincpu; + required_ioport m_y0; + required_ioport m_y1; + required_ioport m_y2; + required_ioport m_y3; + required_ioport m_y4; + required_ioport m_y5; + required_ioport m_y6; + required_ioport m_y7; + required_ioport m_y8; + required_ioport m_y9; + required_ioport m_y10; + required_ioport m_y11; + required_ioport m_y12; + + UINT16 m_key_y; +}; + + +// device type definition +extern const device_type ADAM_KB; + + + +#endif diff --git a/src/devices/bus/adamnet/printer.c b/src/devices/bus/adamnet/printer.c new file mode 100644 index 00000000000..7de2db87b2e --- /dev/null +++ b/src/devices/bus/adamnet/printer.c @@ -0,0 +1,257 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Coleco Adam printer emulation + +**********************************************************************/ + +#include "printer.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define M6801_TAG "u2" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type ADAM_PRN = &device_creator; + + +//------------------------------------------------- +// ROM( adam_prn ) +//------------------------------------------------- + +ROM_START( adam_prn ) + ROM_REGION( 0x800, M6801_TAG, 0 ) + ROM_LOAD( "printer.u2", 0x000, 0x800, CRC(e8db783b) SHA1(32b40679749ad0317c2c9ee9ca619fad6d850ce7) ) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *adam_printer_device::device_rom_region() const +{ + return ROM_NAME( adam_prn ); +} + + +//------------------------------------------------- +// ADDRESS_MAP( adam_prn_mem ) +//------------------------------------------------- + +static ADDRESS_MAP_START( adam_prn_mem, AS_PROGRAM, 8, adam_printer_device ) + AM_RANGE(0x0000, 0x001f) AM_DEVREADWRITE(M6801_TAG, m6801_cpu_device, m6801_io_r, m6801_io_w) + AM_RANGE(0x0080, 0x00ff) AM_RAM + AM_RANGE(0xf800, 0xffff) AM_ROM AM_REGION(M6801_TAG, 0) +ADDRESS_MAP_END + + +//------------------------------------------------- +// ADDRESS_MAP( adam_prn_io ) +//------------------------------------------------- + +static ADDRESS_MAP_START( adam_prn_io, AS_IO, 8, adam_printer_device ) + AM_RANGE(M6801_PORT1, M6801_PORT1) AM_WRITE(p1_w) + AM_RANGE(M6801_PORT2, M6801_PORT2) AM_READWRITE(p2_r, p2_w) + AM_RANGE(M6801_PORT3, M6801_PORT3) AM_READ(p3_r) + AM_RANGE(M6801_PORT4, M6801_PORT4) AM_READWRITE(p4_r, p4_w) +ADDRESS_MAP_END + + +//------------------------------------------------- +// MACHINE_DRIVER( adam_prn ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( adam_prn ) + MCFG_CPU_ADD(M6801_TAG, M6801, XTAL_4MHz) + MCFG_CPU_PROGRAM_MAP(adam_prn_mem) + MCFG_CPU_IO_MAP(adam_prn_io) + MCFG_DEVICE_DISABLE() // TODO +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor adam_printer_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( adam_prn ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// adam_printer_device - constructor +//------------------------------------------------- + +adam_printer_device::adam_printer_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, ADAM_PRN, "Adam printer", tag, owner, clock, "adam_prn", __FILE__), + device_adamnet_card_interface(mconfig, *this), + m_maincpu(*this, M6801_TAG) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void adam_printer_device::device_start() +{ +} + + +//------------------------------------------------- +// adamnet_reset_w - +//------------------------------------------------- + +void adam_printer_device::adamnet_reset_w(int state) +{ + m_maincpu->set_input_line(INPUT_LINE_RESET, state); +} + + +//------------------------------------------------- +// p1_w - +//------------------------------------------------- + +WRITE8_MEMBER( adam_printer_device::p1_w ) +{ + /* + + bit description + + 0 M2 phase D + 1 M2 phase B + 2 M2 phase C + 3 M2 phase A + 4 M3 phase B + 5 M3 phase D + 6 M3 phase A + 7 M3 phase C + + */ +} + + +//------------------------------------------------- +// p2_r - +//------------------------------------------------- + +READ8_MEMBER( adam_printer_device::p2_r ) +{ + /* + + bit description + + 0 mode bit 0 + 1 mode bit 1 + 2 mode bit 2 + 3 NET RXD + 4 NET TXD + + */ + + UINT8 data = M6801_MODE_7; + + // NET RXD + data |= m_bus->rxd_r(this) << 3; + + return data; +} + + +//------------------------------------------------- +// p2_w - +//------------------------------------------------- + +WRITE8_MEMBER( adam_printer_device::p2_w ) +{ + /* + + bit description + + 0 mode bit 0 + 1 mode bit 1 + 2 mode bit 2 + 3 NET RXD + 4 NET TXD + + */ + + m_bus->txd_w(this, BIT(data, 4)); +} + + +//------------------------------------------------- +// p3_r - +//------------------------------------------------- + +READ8_MEMBER( adam_printer_device::p3_r ) +{ + return 0xff; +} + + +//------------------------------------------------- +// p4_r - +//------------------------------------------------- + +READ8_MEMBER( adam_printer_device::p4_r ) +{ + /* + + bit description + + 0 + 1 + 2 + 3 + 4 left margin + 5 platen detent + 6 wheel home + 7 self-test + + */ + + return 0x80; +} + + +//------------------------------------------------- +// p4_w - +//------------------------------------------------- + +WRITE8_MEMBER( adam_printer_device::p4_w ) +{ + /* + + bit description + + 0 print hammer solenoid + 1 ribbon advance solenoid + 2 platen motor advance + 3 platen motor break + 4 + 5 + 6 + 7 + + */ +} diff --git a/src/devices/bus/adamnet/printer.h b/src/devices/bus/adamnet/printer.h new file mode 100644 index 00000000000..0a2fae5fac5 --- /dev/null +++ b/src/devices/bus/adamnet/printer.h @@ -0,0 +1,61 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Coleco Adam printer controller emulation + +**********************************************************************/ + +#pragma once + +#ifndef __ADAM_PRN__ +#define __ADAM_PRN__ + +#include "emu.h" +#include "adamnet.h" +#include "cpu/m6800/m6800.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> adam_printer_device + +class adam_printer_device : public device_t, + public device_adamnet_card_interface +{ +public: + // construction/destruction + adam_printer_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + + // not really public + DECLARE_WRITE8_MEMBER( p1_w ); + DECLARE_READ8_MEMBER( p2_r ); + DECLARE_WRITE8_MEMBER( p2_w ); + DECLARE_READ8_MEMBER( p3_r ); + DECLARE_READ8_MEMBER( p4_r ); + DECLARE_WRITE8_MEMBER( p4_w ); + +protected: + // device-level overrides + virtual void device_start(); + + // device_adamnet_card_interface overrides + virtual void adamnet_reset_w(int state); + + required_device m_maincpu; +}; + + +// device type definition +extern const device_type ADAM_PRN; + + + +#endif diff --git a/src/devices/bus/adamnet/spi.c b/src/devices/bus/adamnet/spi.c new file mode 100644 index 00000000000..7cfff9adfeb --- /dev/null +++ b/src/devices/bus/adamnet/spi.c @@ -0,0 +1,185 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Coleco Adam Serial/Parallel Interface emulation + +**********************************************************************/ + +#include "spi.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define M6801_TAG "m6801" +#define MC2661_TAG "mc2661" +#define RS232_TAG "rs232" +#define CENTRONICS_TAG "centronics" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type ADAM_SPI = &device_creator; + + +//------------------------------------------------- +// ROM( adam_spi ) +//------------------------------------------------- + +ROM_START( adam_spi ) + ROM_REGION( 0x800, M6801_TAG, 0 ) + ROM_LOAD( "spi.bin", 0x000, 0x800, CRC(4ba30352) SHA1(99fe5aebd505a208bea6beec5d7322b15426e9c1) ) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *adam_spi_device::device_rom_region() const +{ + return ROM_NAME( adam_spi ); +} + + +//------------------------------------------------- +// ADDRESS_MAP( adam_spi_mem ) +//------------------------------------------------- + +static ADDRESS_MAP_START( adam_spi_mem, AS_PROGRAM, 8, adam_spi_device ) + AM_RANGE(0x0000, 0x001f) AM_DEVREADWRITE(M6801_TAG, m6801_cpu_device, m6801_io_r, m6801_io_w) + AM_RANGE(0x0080, 0x00ff) AM_RAM + AM_RANGE(0xf800, 0xffff) AM_ROM AM_REGION(M6801_TAG, 0) +ADDRESS_MAP_END + + +//------------------------------------------------- +// ADDRESS_MAP( adam_spi_io ) +//------------------------------------------------- + +static ADDRESS_MAP_START( adam_spi_io, AS_IO, 8, adam_spi_device ) + AM_RANGE(M6801_PORT2, M6801_PORT2) AM_READWRITE(p2_r, p2_w) +ADDRESS_MAP_END + + +//------------------------------------------------- +// MACHINE_DRIVER( adam_spi ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( adam_spi ) + MCFG_CPU_ADD(M6801_TAG, M6801, XTAL_4MHz) + MCFG_CPU_PROGRAM_MAP(adam_spi_mem) + MCFG_CPU_IO_MAP(adam_spi_io) + MCFG_DEVICE_DISABLE() + + MCFG_DEVICE_ADD(MC2661_TAG, MC2661, XTAL_4_9152MHz) + + MCFG_RS232_PORT_ADD(RS232_TAG, default_rs232_devices, NULL) + + MCFG_CENTRONICS_ADD(CENTRONICS_TAG, centronics_devices, "printer") + MCFG_CENTRONICS_DATA_INPUT_BUFFER("cent_data_in") + MCFG_DEVICE_ADD("cent_data_in", INPUT_BUFFER, 0) + MCFG_CENTRONICS_OUTPUT_LATCH_ADD("cent_data_out", CENTRONICS_TAG) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor adam_spi_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( adam_spi ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// adam_spi_device - constructor +//------------------------------------------------- + +adam_spi_device::adam_spi_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, ADAM_SPI, "Adam SPI", tag, owner, clock, "adam_spi", __FILE__), + device_adamnet_card_interface(mconfig, *this), + m_maincpu(*this, M6801_TAG) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void adam_spi_device::device_start() +{ +} + + +//------------------------------------------------- +// adamnet_reset_w - +//------------------------------------------------- + +void adam_spi_device::adamnet_reset_w(int state) +{ + m_maincpu->set_input_line(INPUT_LINE_RESET, state); +} + + +//------------------------------------------------- +// p2_r - +//------------------------------------------------- + +READ8_MEMBER( adam_spi_device::p2_r ) +{ + /* + + bit description + + 0 mode bit 0 + 1 mode bit 1 + 2 mode bit 2 + 3 NET RXD + 4 + + */ + + UINT8 data = M6801_MODE_7; + + // NET RXD + data |= m_bus->rxd_r(this) << 3; + + return data; +} + + +//------------------------------------------------- +// p2_w - +//------------------------------------------------- + +WRITE8_MEMBER( adam_spi_device::p2_w ) +{ + /* + + bit description + + 0 + 1 + 2 + 3 + 4 NET TXD + + */ + + m_bus->txd_w(this, BIT(data, 4)); +} diff --git a/src/devices/bus/adamnet/spi.h b/src/devices/bus/adamnet/spi.h new file mode 100644 index 00000000000..19a1d5c9866 --- /dev/null +++ b/src/devices/bus/adamnet/spi.h @@ -0,0 +1,60 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Coleco Adam Serial/Parallel Interface emulation + +**********************************************************************/ + +#pragma once + +#ifndef __ADAM_SPI__ +#define __ADAM_SPI__ + +#include "emu.h" +#include "adamnet.h" +#include "bus/centronics/ctronics.h" +#include "bus/rs232/rs232.h" +#include "cpu/m6800/m6800.h" +#include "machine/mc2661.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> adam_spi_device + +class adam_spi_device : public device_t, + public device_adamnet_card_interface +{ +public: + // construction/destruction + adam_spi_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + + // not really public + DECLARE_READ8_MEMBER( p2_r ); + DECLARE_WRITE8_MEMBER( p2_w ); + +protected: + // device-level overrides + virtual void device_start(); + + // device_adamnet_card_interface overrides + virtual void adamnet_reset_w(int state); + + required_device m_maincpu; +}; + + +// device type definition +extern const device_type ADAM_SPI; + + + +#endif diff --git a/src/devices/bus/amiga/zorro/a2052.c b/src/devices/bus/amiga/zorro/a2052.c new file mode 100644 index 00000000000..dc2727d2117 --- /dev/null +++ b/src/devices/bus/amiga/zorro/a2052.c @@ -0,0 +1,134 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best +/*************************************************************************** + + Commodore A2052 + + Zorro-II RAM Expansion (0.5, 1 or 2 MB) + +***************************************************************************/ + +#include "a2052.h" + + +//************************************************************************** +// CONSTANTS / MACROS +//************************************************************************** + +#define VERBOSE 1 + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type A2052 = &device_creator; + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +static INPUT_PORTS_START( a2052 ) + PORT_START("config") + PORT_CONFNAME(0x03, 0x02, "A2052 Installed RAM") + PORT_CONFSETTING(0x00, "512 KB") + PORT_CONFSETTING(0x01, "1 MB") + PORT_CONFSETTING(0x02, "2 MB") +INPUT_PORTS_END + +ioport_constructor a2052_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( a2052 ); +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// a2052_device - constructor +//------------------------------------------------- + +a2052_device::a2052_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, A2052, "CBM A2052 Fast Memory", tag, owner, clock, "a2052", __FILE__), + device_zorro2_card_interface(mconfig, *this), + m_config(*this, "config") +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void a2052_device::device_start() +{ + set_zorro_device(); +} + + +//************************************************************************** +// IMPLEMENTATION +//************************************************************************** + +void a2052_device::autoconfig_base_address(offs_t address) +{ + if (VERBOSE) + logerror("%s('%s'): autoconfig_base_address received: 0x%06x\n", shortname(), basetag(), address); + + if (VERBOSE) + logerror("-> installing a2052\n"); + + // stop responding to default autoconfig + m_slot->m_space->unmap_readwrite(0xe80000, 0xe8007f); + + // install access to the rom space + m_slot->m_space->install_ram(address, address + m_ram.size()*2 - 1, &m_ram[0]); + + // we're done + m_slot->cfgout_w(0); +} + +WRITE_LINE_MEMBER( a2052_device::cfgin_w ) +{ + if (VERBOSE) + logerror("%s('%s'): configin_w (%d)\n", shortname(), basetag(), state); + + if (state == 0) + { + // setup autoconfig + autoconfig_board_type(BOARD_TYPE_ZORRO2); + + // setup ram + switch (m_config->read()) + { + case 0: + autoconfig_board_size(BOARD_SIZE_512K); + m_ram.resize(0x080000/2); + break; + case 1: + autoconfig_board_size(BOARD_SIZE_1M); + m_ram.resize(0x100000/2); + break; + case 2: + autoconfig_board_size(BOARD_SIZE_2M); + m_ram.resize(0x200000/2); + break; + } + + autoconfig_product(0x0a); + autoconfig_manufacturer(0x0202); + autoconfig_serial(0x00000000); + + autoconfig_link_into_memory(true); + autoconfig_rom_vector_valid(false); + autoconfig_multi_device(false); + autoconfig_8meg_preferred(false); + autoconfig_can_shutup(true); // ? + + // install autoconfig handler + m_slot->m_space->install_readwrite_handler(0xe80000, 0xe8007f, + read16_delegate(FUNC(amiga_autoconfig::autoconfig_read), static_cast(this)), + write16_delegate(FUNC(amiga_autoconfig::autoconfig_write), static_cast(this)), 0xffff); + } +} diff --git a/src/devices/bus/amiga/zorro/a2052.h b/src/devices/bus/amiga/zorro/a2052.h new file mode 100644 index 00000000000..9a189ec58c2 --- /dev/null +++ b/src/devices/bus/amiga/zorro/a2052.h @@ -0,0 +1,51 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best +/*************************************************************************** + + Commodore A2052 + + Zorro-II RAM Expansion (0.5, 1 or 2 MB) + +***************************************************************************/ + +#pragma once + +#ifndef __A2052_H__ +#define __A2052_H__ + +#include "emu.h" +#include "zorro.h" +#include "machine/autoconfig.h" + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> a2052_device + +class a2052_device : public device_t, public device_zorro2_card_interface, public amiga_autoconfig +{ +public: + // construction/destruction + a2052_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual ioport_constructor device_input_ports() const; + virtual void device_start(); + + // device_zorro2_card_interface overrides + virtual DECLARE_WRITE_LINE_MEMBER( cfgin_w ); + + // amiga_autoconfig overrides + virtual void autoconfig_base_address(offs_t address); + +private: + required_ioport m_config; + std::vector m_ram; +}; + +// device type definition +extern const device_type A2052; + +#endif diff --git a/src/devices/bus/amiga/zorro/a2232.c b/src/devices/bus/amiga/zorro/a2232.c new file mode 100644 index 00000000000..89e87d3588a --- /dev/null +++ b/src/devices/bus/amiga/zorro/a2232.c @@ -0,0 +1,651 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best +/*************************************************************************** + + Commodore A2232 + + Zorro-II Serial Card + +***************************************************************************/ + +#include "a2232.h" + + +//************************************************************************** +// CONSTANTS / MACROS +//************************************************************************** + +#define VERBOSE 0 +#define VERBOSE_DATA 0 + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type A2232 = &device_creator; + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +static ADDRESS_MAP_START( iocpu_map, AS_PROGRAM, 8, a2232_device) + AM_RANGE(0x0000, 0x3fff) AM_RAM AM_SHARE("shared") + AM_RANGE(0x4000, 0x47ff) AM_READWRITE(acia_0_r, acia_0_w) + AM_RANGE(0x4800, 0x4fff) AM_READWRITE(acia_1_r, acia_1_w) + AM_RANGE(0x5000, 0x57ff) AM_READWRITE(acia_2_r, acia_2_w) + AM_RANGE(0x5800, 0x5fff) AM_READWRITE(acia_3_r, acia_3_w) + AM_RANGE(0x6000, 0x67ff) AM_READWRITE(acia_4_r, acia_4_w) + AM_RANGE(0x6800, 0x6fff) AM_READWRITE(acia_5_r, acia_5_w) + AM_RANGE(0x7000, 0x73ff) AM_WRITE(int2_w) + AM_RANGE(0x7400, 0x77ff) AM_READWRITE(acia_6_r, acia_6_w) + AM_RANGE(0x7800, 0x7fff) AM_READWRITE(cia_r, cia_w) + AM_RANGE(0x8000, 0x8000) AM_WRITE(irq_ack_w) + AM_RANGE(0xc000, 0xffff) AM_RAM AM_SHARE("shared") +ADDRESS_MAP_END + +static MACHINE_CONFIG_FRAGMENT( a2232 ) + // main cpu + MCFG_CPU_ADD("iocpu", M65CE02, XTAL_28_37516MHz / 8) // should run at Amiga clock 7M / 2 + MCFG_CPU_PROGRAM_MAP(iocpu_map) + + // acia + MCFG_DEVICE_ADD("acia_0", MOS6551, XTAL_28_37516MHz / 8) + MCFG_MOS6551_XTAL(XTAL_1_8432MHz) + MCFG_MOS6551_TXD_HANDLER(DEVWRITELINE("rs232_1", rs232_port_device, write_txd)) + MCFG_MOS6551_IRQ_HANDLER(WRITELINE(a2232_device, acia_0_irq_w)) + + MCFG_DEVICE_ADD("acia_1", MOS6551, XTAL_28_37516MHz / 8) + MCFG_MOS6551_XTAL(XTAL_1_8432MHz) + MCFG_MOS6551_TXD_HANDLER(DEVWRITELINE("rs232_2", rs232_port_device, write_txd)) + MCFG_MOS6551_IRQ_HANDLER(WRITELINE(a2232_device, acia_1_irq_w)) + + MCFG_DEVICE_ADD("acia_2", MOS6551, XTAL_28_37516MHz / 8) + MCFG_MOS6551_XTAL(XTAL_1_8432MHz) + MCFG_MOS6551_TXD_HANDLER(DEVWRITELINE("rs232_3", rs232_port_device, write_txd)) + MCFG_MOS6551_IRQ_HANDLER(WRITELINE(a2232_device, acia_2_irq_w)) + + MCFG_DEVICE_ADD("acia_3", MOS6551, XTAL_28_37516MHz / 8) + MCFG_MOS6551_XTAL(XTAL_1_8432MHz) + MCFG_MOS6551_TXD_HANDLER(DEVWRITELINE("rs232_4", rs232_port_device, write_txd)) + MCFG_MOS6551_IRQ_HANDLER(WRITELINE(a2232_device, acia_3_irq_w)) + + MCFG_DEVICE_ADD("acia_4", MOS6551, XTAL_28_37516MHz / 8) + MCFG_MOS6551_XTAL(XTAL_1_8432MHz) + MCFG_MOS6551_TXD_HANDLER(DEVWRITELINE("rs232_5", rs232_port_device, write_txd)) + MCFG_MOS6551_IRQ_HANDLER(WRITELINE(a2232_device, acia_4_irq_w)) + + MCFG_DEVICE_ADD("acia_5", MOS6551, XTAL_28_37516MHz / 8) + MCFG_MOS6551_XTAL(XTAL_1_8432MHz) + MCFG_MOS6551_TXD_HANDLER(DEVWRITELINE("rs232_6", rs232_port_device, write_txd)) + MCFG_MOS6551_IRQ_HANDLER(WRITELINE(a2232_device, acia_5_irq_w)) + + MCFG_DEVICE_ADD("acia_6", MOS6551, XTAL_28_37516MHz / 8) + MCFG_MOS6551_XTAL(XTAL_1_8432MHz) + MCFG_MOS6551_TXD_HANDLER(DEVWRITELINE("rs232_7", rs232_port_device, write_txd)) + MCFG_MOS6551_IRQ_HANDLER(WRITELINE(a2232_device, acia_6_irq_w)) + + // cia + MCFG_DEVICE_ADD("cia", MOS8520, XTAL_1_8432MHz) + MCFG_MOS6526_IRQ_CALLBACK(WRITELINE(a2232_device, cia_irq_w)) + MCFG_MOS6526_PA_INPUT_CALLBACK(READ8(a2232_device, cia_port_a_r)) + MCFG_MOS6526_PB_INPUT_CALLBACK(READ8(a2232_device, cia_port_b_r)) + MCFG_MOS6526_PB_OUTPUT_CALLBACK(WRITE8(a2232_device, cia_port_b_w)) + + // rs232 ports + MCFG_RS232_PORT_ADD("rs232_1", default_rs232_devices, NULL) + MCFG_RS232_RXD_HANDLER(WRITELINE(a2232_device, rs232_1_rxd_w)) + MCFG_RS232_DCD_HANDLER(WRITELINE(a2232_device, rs232_1_dcd_w)) + MCFG_RS232_DSR_HANDLER(DEVWRITELINE("acia_0", mos6551_device, write_dsr)) + MCFG_RS232_CTS_HANDLER(WRITELINE(a2232_device, rs232_1_cts_w)) + + MCFG_RS232_PORT_ADD("rs232_2", default_rs232_devices, NULL) + MCFG_RS232_RXD_HANDLER(DEVWRITELINE("acia_1", mos6551_device, write_rxd)) + MCFG_RS232_DCD_HANDLER(WRITELINE(a2232_device, rs232_2_dcd_w)) + MCFG_RS232_DSR_HANDLER(DEVWRITELINE("acia_1", mos6551_device, write_dsr)) + MCFG_RS232_CTS_HANDLER(WRITELINE(a2232_device, rs232_2_cts_w)) + + MCFG_RS232_PORT_ADD("rs232_3", default_rs232_devices, NULL) + MCFG_RS232_RXD_HANDLER(DEVWRITELINE("acia_2", mos6551_device, write_rxd)) + MCFG_RS232_DCD_HANDLER(WRITELINE(a2232_device, rs232_3_dcd_w)) + MCFG_RS232_DSR_HANDLER(DEVWRITELINE("acia_2", mos6551_device, write_dsr)) + MCFG_RS232_CTS_HANDLER(WRITELINE(a2232_device, rs232_3_cts_w)) + + MCFG_RS232_PORT_ADD("rs232_4", default_rs232_devices, NULL) + MCFG_RS232_RXD_HANDLER(DEVWRITELINE("acia_3", mos6551_device, write_rxd)) + MCFG_RS232_DCD_HANDLER(WRITELINE(a2232_device, rs232_4_dcd_w)) + MCFG_RS232_DSR_HANDLER(DEVWRITELINE("acia_3", mos6551_device, write_dsr)) + MCFG_RS232_CTS_HANDLER(WRITELINE(a2232_device, rs232_4_cts_w)) + + MCFG_RS232_PORT_ADD("rs232_5", default_rs232_devices, NULL) + MCFG_RS232_RXD_HANDLER(DEVWRITELINE("acia_4", mos6551_device, write_rxd)) + MCFG_RS232_DCD_HANDLER(WRITELINE(a2232_device, rs232_5_dcd_w)) + MCFG_RS232_DSR_HANDLER(DEVWRITELINE("acia_4", mos6551_device, write_dsr)) + MCFG_RS232_CTS_HANDLER(WRITELINE(a2232_device, rs232_5_cts_w)) + + MCFG_RS232_PORT_ADD("rs232_6", default_rs232_devices, NULL) + MCFG_RS232_RXD_HANDLER(DEVWRITELINE("acia_5", mos6551_device, write_rxd)) + MCFG_RS232_DCD_HANDLER(WRITELINE(a2232_device, rs232_6_dcd_w)) + MCFG_RS232_DSR_HANDLER(DEVWRITELINE("acia_5", mos6551_device, write_dsr)) + MCFG_RS232_CTS_HANDLER(WRITELINE(a2232_device, rs232_6_cts_w)) + + MCFG_RS232_PORT_ADD("rs232_7", default_rs232_devices, NULL) + MCFG_RS232_RXD_HANDLER(DEVWRITELINE("acia_6", mos6551_device, write_rxd)) + MCFG_RS232_DCD_HANDLER(WRITELINE(a2232_device, rs232_7_dcd_w)) + MCFG_RS232_DSR_HANDLER(DEVWRITELINE("acia_6", mos6551_device, write_dsr)) + MCFG_RS232_CTS_HANDLER(WRITELINE(a2232_device, rs232_7_cts_w)) +MACHINE_CONFIG_END + +machine_config_constructor a2232_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( a2232 ); +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// a2232_device - constructor +//------------------------------------------------- + +a2232_device::a2232_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, A2232, "CBM A2232 Serial Card", tag, owner, clock, "a2232", __FILE__), + device_zorro2_card_interface(mconfig, *this), + m_iocpu(*this, "iocpu"), + m_acia_0(*this, "acia_0"), + m_acia_1(*this, "acia_1"), + m_acia_2(*this, "acia_2"), + m_acia_3(*this, "acia_3"), + m_acia_4(*this, "acia_4"), + m_acia_5(*this, "acia_5"), + m_acia_6(*this, "acia_6"), + m_cia(*this, "cia"), + m_shared_ram(*this, "shared"), + m_cia_port_a(0xff), + m_cia_port_b(0xff) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void a2232_device::device_start() +{ + set_zorro_device(); + memset(m_irqs, 0, sizeof(m_irqs)); +} + +//------------------------------------------------- +// device_reset_after_children - reset after child devices +//------------------------------------------------- + +void a2232_device::device_reset_after_children() +{ + // reset is kept high at reset, to allow the amiga time to upload its code + m_iocpu->set_input_line(INPUT_LINE_RESET, ASSERT_LINE); + + // cts connected to gnd + m_acia_0->write_cts(0); + m_acia_1->write_cts(0); + m_acia_2->write_cts(0); + m_acia_3->write_cts(0); + m_acia_4->write_cts(0); + m_acia_5->write_cts(0); + m_acia_6->write_cts(0); +} + + +//************************************************************************** +// IMPLEMENTATION +//************************************************************************** + +void a2232_device::update_irqs() +{ + // look for any active irq + for (int i = 0; i < IRQ_SOURCE_COUNT; i++) + { + if (m_irqs[i]) + { + m_iocpu->set_input_line(INPUT_LINE_IRQ0, ASSERT_LINE); + return; + } + } + + // if we get here no irqs are pending + m_iocpu->set_input_line(INPUT_LINE_IRQ0, CLEAR_LINE); +} + +WRITE8_MEMBER( a2232_device::int2_w ) +{ + if (VERBOSE) + logerror("%s('%s'): int2_w %04x\n", shortname(), basetag(), data); + + m_slot->int2_w(1); +} + +WRITE8_MEMBER( a2232_device::irq_ack_w ) +{ + if (VERBOSE) + logerror("%s('%s'): irq_ack_w %04x\n", shortname(), basetag(), data); + + m_irqs[IRQ_AMIGA] = CLEAR_LINE; + update_irqs(); +} + + +//************************************************************************** +// AUTOCONFIG +//************************************************************************** + +void a2232_device::autoconfig_base_address(offs_t address) +{ + if (VERBOSE) + logerror("%s('%s'): autoconfig_base_address received: 0x%06x\n", shortname(), basetag(), address); + + if (VERBOSE) + logerror("-> installing a2232\n"); + + // stop responding to default autoconfig + m_slot->m_space->unmap_readwrite(0xe80000, 0xe8007f); + + m_slot->m_space->install_readwrite_handler(address, address + 0x3fff, + read16_delegate(FUNC(a2232_device::shared_ram_r), this), + write16_delegate(FUNC(a2232_device::shared_ram_w), this), 0xffff); + + m_slot->m_space->install_readwrite_handler(address + 0x4000, address + 0x4001, + read16_delegate(FUNC(a2232_device::irq_ack_r), this), + write16_delegate(FUNC(a2232_device::irq_ack_w), this), 0xffff); + + m_slot->m_space->install_readwrite_handler(address + 0x8000, address + 0x8001, + read16_delegate(FUNC(a2232_device::reset_low_r), this), + write16_delegate(FUNC(a2232_device::reset_low_w), this), 0xffff); + + m_slot->m_space->install_readwrite_handler(address + 0xa000, address + 0xa001, + read16_delegate(FUNC(a2232_device::irq_r), this), + write16_delegate(FUNC(a2232_device::irq_w), this), 0xffff); + + m_slot->m_space->install_readwrite_handler(address + 0xc000, address + 0xc001, + read16_delegate(FUNC(a2232_device::reset_high_r), this), + write16_delegate(FUNC(a2232_device::reset_high_w), this), 0xffff); + + // we're done + m_slot->cfgout_w(0); +} + +WRITE_LINE_MEMBER( a2232_device::cfgin_w ) +{ + if (VERBOSE) + logerror("%s('%s'): configin_w (%d)\n", shortname(), basetag(), state); + + if (state == 0) + { + // setup autoconfig + autoconfig_board_type(BOARD_TYPE_ZORRO2); + autoconfig_board_size(BOARD_SIZE_64K); + + autoconfig_product(0x46); + autoconfig_manufacturer(0x0202); + autoconfig_serial(0x00000000); + + autoconfig_link_into_memory(false); + autoconfig_rom_vector_valid(false); + autoconfig_multi_device(false); + autoconfig_8meg_preferred(false); + autoconfig_can_shutup(true); // ? + + // install autoconfig handler + m_slot->m_space->install_readwrite_handler(0xe80000, 0xe8007f, + read16_delegate(FUNC(amiga_autoconfig::autoconfig_read), static_cast(this)), + write16_delegate(FUNC(amiga_autoconfig::autoconfig_write), static_cast(this)), 0xffff); + } +} + + +//************************************************************************** +// ZORRO +//************************************************************************** + +READ16_MEMBER( a2232_device::shared_ram_r ) +{ + UINT16 data = 0; + + if (ACCESSING_BITS_0_7) + data |= m_shared_ram[(offset << 1) + 1]; + else + data |= 0x00ff; + + if (ACCESSING_BITS_8_15) + data |= m_shared_ram[offset << 1] << 8; + else + data |= 0xff00; + + if (VERBOSE_DATA) + logerror("%s('%s'): shared_ram_r(%04x) %04x [mask = %04x]\n", shortname(), basetag(), offset << 1, data, mem_mask); + + return data; +} + +WRITE16_MEMBER( a2232_device::shared_ram_w ) +{ + if (VERBOSE_DATA) + logerror("%s('%s'): shared_ram_w(%04x) %04x [mask = %04x]\n", shortname(), basetag(), offset << 1, data, mem_mask); + + if (ACCESSING_BITS_0_7) + m_shared_ram[(offset << 1) + 1] = data & 0xff; + + if (ACCESSING_BITS_8_15) + m_shared_ram[offset << 1] = (data & 0xff00) >> 8; +} + +READ16_MEMBER( a2232_device::irq_ack_r ) +{ + m_slot->int2_w(0); + + return 0xffff; +} + +WRITE16_MEMBER( a2232_device::irq_ack_w ) +{ + m_slot->int2_w(0); +} + +READ16_MEMBER( a2232_device::reset_low_r ) +{ + m_iocpu->set_input_line(INPUT_LINE_RESET, ASSERT_LINE); + + return 0xffff; +} + +WRITE16_MEMBER( a2232_device::reset_low_w ) +{ + m_iocpu->set_input_line(INPUT_LINE_RESET, ASSERT_LINE); +} + +READ16_MEMBER( a2232_device::irq_r ) +{ + m_irqs[IRQ_AMIGA] = ASSERT_LINE; + update_irqs(); + + return 0xffff; +} + +WRITE16_MEMBER( a2232_device::irq_w ) +{ + m_irqs[IRQ_AMIGA] = ASSERT_LINE; + update_irqs(); +} + +READ16_MEMBER( a2232_device::reset_high_r ) +{ + UINT16 data = 0xffff; + + if (VERBOSE) + logerror("%s('%s'): reset_high_r %04x [mask = %04x]\n", shortname(), basetag(), data, mem_mask); + + m_iocpu->set_input_line(INPUT_LINE_RESET, CLEAR_LINE); + + return data; +} + +WRITE16_MEMBER( a2232_device::reset_high_w ) +{ + if (VERBOSE) + logerror("%s('%s'): reset_high_w %04x [mask = %04x]\n", shortname(), basetag(), data, mem_mask); + + m_iocpu->set_input_line(INPUT_LINE_RESET, CLEAR_LINE); +} + + +//************************************************************************** +// ACIA +//************************************************************************** + +READ8_MEMBER( a2232_device::acia_0_r ) +{ + return m_acia_0->read(space, offset >> 1); +} + +WRITE8_MEMBER( a2232_device::acia_0_w ) +{ + m_acia_0->write(space, offset >> 1, data); +} + +WRITE_LINE_MEMBER( a2232_device::acia_0_irq_w ) +{ + m_irqs[IRQ_ACIA_0] = state; + update_irqs(); +} + +READ8_MEMBER( a2232_device::acia_1_r ) +{ + return m_acia_1->read(space, offset >> 1); +} + +WRITE8_MEMBER( a2232_device::acia_1_w ) +{ + m_acia_1->write(space, offset >> 1, data); +} + +WRITE_LINE_MEMBER( a2232_device::acia_1_irq_w ) +{ + m_irqs[IRQ_ACIA_1] = state; + update_irqs(); +} + +READ8_MEMBER( a2232_device::acia_2_r ) +{ + return m_acia_2->read(space, offset >> 1); +} + +WRITE8_MEMBER( a2232_device::acia_2_w ) +{ + m_acia_2->write(space, offset >> 1, data); +} + +WRITE_LINE_MEMBER( a2232_device::acia_2_irq_w ) +{ + m_irqs[IRQ_ACIA_2] = state; + update_irqs(); +} + +READ8_MEMBER( a2232_device::acia_3_r ) +{ + return m_acia_3->read(space, offset >> 1); +} + +WRITE8_MEMBER( a2232_device::acia_3_w ) +{ + m_acia_3->write(space, offset >> 1, data); +} + +WRITE_LINE_MEMBER( a2232_device::acia_3_irq_w ) +{ + m_irqs[IRQ_ACIA_3] = state; + update_irqs(); +} + +READ8_MEMBER( a2232_device::acia_4_r ) +{ + return m_acia_4->read(space, offset >> 1); +} + +WRITE8_MEMBER( a2232_device::acia_4_w ) +{ + m_acia_4->write(space, offset >> 1, data); +} + +WRITE_LINE_MEMBER( a2232_device::acia_4_irq_w ) +{ + m_irqs[IRQ_ACIA_4] = state; + update_irqs(); +} + +READ8_MEMBER( a2232_device::acia_5_r ) +{ + return m_acia_5->read(space, offset >> 1); +} + +WRITE8_MEMBER( a2232_device::acia_5_w ) +{ + m_acia_5->write(space, offset >> 1, data); +} + +WRITE_LINE_MEMBER( a2232_device::acia_5_irq_w ) +{ + m_irqs[IRQ_ACIA_5] = state; + update_irqs(); +} + +READ8_MEMBER( a2232_device::acia_6_r ) +{ + return m_acia_6->read(space, offset >> 1); +} + +WRITE8_MEMBER( a2232_device::acia_6_w ) +{ + m_acia_6->write(space, offset >> 1, data); +} + +WRITE_LINE_MEMBER( a2232_device::acia_6_irq_w ) +{ + m_irqs[IRQ_ACIA_6] = state; + update_irqs(); +} + + +//************************************************************************** +// CIA +//************************************************************************** + +READ8_MEMBER( a2232_device::cia_r ) +{ + return m_cia->read(space, offset >> 1); +} + +WRITE8_MEMBER( a2232_device::cia_w ) +{ + m_cia->write(space, offset >> 1, data); +} + +WRITE_LINE_MEMBER( a2232_device::cia_irq_w ) +{ + m_irqs[IRQ_CIA] = state; + update_irqs(); +} + +READ8_MEMBER( a2232_device::cia_port_a_r ) +{ + return m_cia_port_a; +} + +READ8_MEMBER( a2232_device::cia_port_b_r ) +{ + return m_cia_port_b; +} + +WRITE8_MEMBER( a2232_device::cia_port_b_w ) +{ + // tod clock connected to pb7 + m_cia->tod_w(BIT(data, 7)); +} + + +//************************************************************************** +// RS232 +//************************************************************************** + +WRITE_LINE_MEMBER( a2232_device::rs232_1_rxd_w ) +{ + m_acia_0->write_rxd(state); + m_cia->sp_w(state); +} + +WRITE_LINE_MEMBER( a2232_device::rs232_1_dcd_w ) +{ + m_cia_port_a &= ~0x01; + m_cia_port_a |= state << 0; +} + +WRITE_LINE_MEMBER( a2232_device::rs232_1_cts_w ) +{ + m_cia_port_b &= ~0x01; + m_cia_port_b |= state << 0; + + m_cia->cnt_w(state); +} + +WRITE_LINE_MEMBER( a2232_device::rs232_2_dcd_w ) +{ + m_cia_port_a &= ~0x02; + m_cia_port_a |= state << 1; +} + +WRITE_LINE_MEMBER( a2232_device::rs232_2_cts_w ) +{ + m_cia_port_b &= ~0x02; + m_cia_port_b |= state << 1; +} + +WRITE_LINE_MEMBER( a2232_device::rs232_3_dcd_w ) +{ + m_cia_port_a &= ~0x04; + m_cia_port_a |= state << 2; +} + +WRITE_LINE_MEMBER( a2232_device::rs232_3_cts_w ) +{ + m_cia_port_b &= ~0x04; + m_cia_port_b |= state << 2; +} + +WRITE_LINE_MEMBER( a2232_device::rs232_4_dcd_w ) +{ + m_cia_port_a &= ~0x08; + m_cia_port_a |= state << 3; +} + +WRITE_LINE_MEMBER( a2232_device::rs232_4_cts_w ) +{ + m_cia_port_b &= ~0x08; + m_cia_port_b |= state << 3; +} + +WRITE_LINE_MEMBER( a2232_device::rs232_5_dcd_w ) +{ + m_cia_port_a &= ~0x10; + m_cia_port_a |= state << 4; +} + +WRITE_LINE_MEMBER( a2232_device::rs232_5_cts_w ) +{ + m_cia_port_b &= ~0x10; + m_cia_port_b |= state << 4; +} + +WRITE_LINE_MEMBER( a2232_device::rs232_6_dcd_w ) +{ + m_cia_port_a &= ~0x20; + m_cia_port_a |= state << 5; +} + +WRITE_LINE_MEMBER( a2232_device::rs232_6_cts_w ) +{ + m_cia_port_b &= ~0x20; + m_cia_port_b |= state << 5; +} + +WRITE_LINE_MEMBER( a2232_device::rs232_7_dcd_w ) +{ + m_cia_port_a &= ~0x40; + m_cia_port_a |= state << 6; +} + +WRITE_LINE_MEMBER( a2232_device::rs232_7_cts_w ) +{ + m_cia_port_b &= ~0x40; + m_cia_port_b |= state << 6; +} diff --git a/src/devices/bus/amiga/zorro/a2232.h b/src/devices/bus/amiga/zorro/a2232.h new file mode 100644 index 00000000000..c0a6bea2d8f --- /dev/null +++ b/src/devices/bus/amiga/zorro/a2232.h @@ -0,0 +1,151 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best +/*************************************************************************** + + Commodore A2232 + + Zorro-II Serial Card + + Provides the Amiga with 7 additional RS232 ports. + +***************************************************************************/ + +#pragma once + +#ifndef __A2232_H__ +#define __A2232_H__ + +#include "emu.h" +#include "zorro.h" +#include "machine/autoconfig.h" +#include "cpu/m6502/m65ce02.h" +#include "machine/mos6551.h" +#include "machine/mos6526.h" +#include "bus/rs232/rs232.h" + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> a2232_device + +class a2232_device : public device_t, public device_zorro2_card_interface, public amiga_autoconfig +{ +public: + // construction/destruction + a2232_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // cpu + WRITE8_MEMBER( int2_w ); + WRITE8_MEMBER( irq_ack_w ); + + // zorro slot + DECLARE_READ16_MEMBER( shared_ram_r ); + DECLARE_WRITE16_MEMBER( shared_ram_w ); + DECLARE_READ16_MEMBER( irq_ack_r ); + DECLARE_WRITE16_MEMBER( irq_ack_w ); + DECLARE_READ16_MEMBER( reset_low_r ); + DECLARE_WRITE16_MEMBER( reset_low_w ); + DECLARE_READ16_MEMBER( irq_r ); + DECLARE_WRITE16_MEMBER( irq_w ); + DECLARE_READ16_MEMBER( reset_high_r ); + DECLARE_WRITE16_MEMBER( reset_high_w ); + + // acia + DECLARE_READ8_MEMBER( acia_0_r ); + DECLARE_WRITE8_MEMBER( acia_0_w ); + DECLARE_WRITE_LINE_MEMBER( acia_0_irq_w ); + DECLARE_READ8_MEMBER( acia_1_r ); + DECLARE_WRITE8_MEMBER( acia_1_w ); + DECLARE_WRITE_LINE_MEMBER( acia_1_irq_w ); + DECLARE_READ8_MEMBER( acia_2_r ); + DECLARE_WRITE8_MEMBER( acia_2_w ); + DECLARE_WRITE_LINE_MEMBER( acia_2_irq_w ); + DECLARE_READ8_MEMBER( acia_3_r ); + DECLARE_WRITE8_MEMBER( acia_3_w ); + DECLARE_WRITE_LINE_MEMBER( acia_3_irq_w ); + DECLARE_READ8_MEMBER( acia_4_r ); + DECLARE_WRITE8_MEMBER( acia_4_w ); + DECLARE_WRITE_LINE_MEMBER( acia_4_irq_w ); + DECLARE_READ8_MEMBER( acia_5_r ); + DECLARE_WRITE8_MEMBER( acia_5_w ); + DECLARE_WRITE_LINE_MEMBER( acia_5_irq_w ); + DECLARE_READ8_MEMBER( acia_6_r ); + DECLARE_WRITE8_MEMBER( acia_6_w ); + DECLARE_WRITE_LINE_MEMBER( acia_6_irq_w ); + + // cia + DECLARE_READ8_MEMBER( cia_r ); + DECLARE_WRITE8_MEMBER( cia_w ); + DECLARE_WRITE_LINE_MEMBER( cia_irq_w ); + DECLARE_READ8_MEMBER( cia_port_a_r ); + DECLARE_READ8_MEMBER( cia_port_b_r ); + DECLARE_WRITE8_MEMBER( cia_port_b_w ); + + // rs232 + DECLARE_WRITE_LINE_MEMBER( rs232_1_rxd_w ); + DECLARE_WRITE_LINE_MEMBER( rs232_1_dcd_w ); + DECLARE_WRITE_LINE_MEMBER( rs232_1_cts_w ); + DECLARE_WRITE_LINE_MEMBER( rs232_2_dcd_w ); + DECLARE_WRITE_LINE_MEMBER( rs232_2_cts_w ); + DECLARE_WRITE_LINE_MEMBER( rs232_3_dcd_w ); + DECLARE_WRITE_LINE_MEMBER( rs232_3_cts_w ); + DECLARE_WRITE_LINE_MEMBER( rs232_4_dcd_w ); + DECLARE_WRITE_LINE_MEMBER( rs232_4_cts_w ); + DECLARE_WRITE_LINE_MEMBER( rs232_5_dcd_w ); + DECLARE_WRITE_LINE_MEMBER( rs232_5_cts_w ); + DECLARE_WRITE_LINE_MEMBER( rs232_6_dcd_w ); + DECLARE_WRITE_LINE_MEMBER( rs232_6_cts_w ); + DECLARE_WRITE_LINE_MEMBER( rs232_7_dcd_w ); + DECLARE_WRITE_LINE_MEMBER( rs232_7_cts_w ); + +protected: + virtual machine_config_constructor device_mconfig_additions() const; + virtual void device_start(); + virtual void device_reset_after_children(); + + // device_zorro2_card_interface overrides + virtual DECLARE_WRITE_LINE_MEMBER( cfgin_w ); + + // amiga_autoconfig overrides + virtual void autoconfig_base_address(offs_t address); + +private: + enum + { + IRQ_ACIA_0, + IRQ_ACIA_1, + IRQ_ACIA_2, + IRQ_ACIA_3, + IRQ_ACIA_4, + IRQ_ACIA_5, + IRQ_ACIA_6, + IRQ_CIA, + IRQ_AMIGA, + IRQ_SOURCE_COUNT + }; + + void update_irqs(); + + required_device m_iocpu; + required_device m_acia_0; + required_device m_acia_1; + required_device m_acia_2; + required_device m_acia_3; + required_device m_acia_4; + required_device m_acia_5; + required_device m_acia_6; + required_device m_cia; + required_shared_ptr m_shared_ram; + + int m_irqs[IRQ_SOURCE_COUNT]; + + UINT8 m_cia_port_a; + UINT8 m_cia_port_b; +}; + +// device type definition +extern const device_type A2232; + +#endif // __A2232_H__ diff --git a/src/devices/bus/amiga/zorro/a590.c b/src/devices/bus/amiga/zorro/a590.c new file mode 100644 index 00000000000..1d66ba99f6e --- /dev/null +++ b/src/devices/bus/amiga/zorro/a590.c @@ -0,0 +1,349 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best +/*************************************************************************** + + Commodore A590 / A2091 + + DMAC based HD controller for the Amiga 500 and Zorro-II + +***************************************************************************/ + +#include "a590.h" +#include "bus/scsi/scsi.h" +#include "bus/scsi/scsihd.h" + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type A590 = &device_creator; +const device_type A2091 = &device_creator; + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +static INPUT_PORTS_START( a590_pcb ) + PORT_START("dips") + PORT_DIPNAME(0x01, 0x01, "A590 Auto-Boot") + PORT_DIPLOCATION("DIP:1") + PORT_DIPSETTING(0x00, "Enabled") + PORT_DIPSETTING(0x01, "Disabled") + PORT_DIPNAME(0x02, 0x00, "A590 LUN") + PORT_DIPLOCATION("DIP:2") + PORT_DIPSETTING(0x00, "Disabled") + PORT_DIPSETTING(0x02, "Enabled") + PORT_DIPNAME(0x04, 0x04, "A590 Wait period") + PORT_DIPLOCATION("DIP:3") + PORT_DIPSETTING(0x00, "Short") + PORT_DIPSETTING(0x04, "Long") + PORT_DIPNAME(0x08, 0x00, "A590 Reserved") + PORT_DIPLOCATION("DIP:4") + PORT_DIPSETTING(0x00, "Enabled") + PORT_DIPSETTING(0x08, "Disabled") + PORT_START("jp1") + PORT_DIPNAME(0x0f, 0x01, "A590 Memory size") + PORT_DIPLOCATION("JP1:1,2,3,4") + PORT_DIPSETTING(0x01, "Amnesia") + PORT_DIPSETTING(0x02, "512K") + PORT_DIPSETTING(0x04, "1MB") + PORT_DIPSETTING(0x08, "2MB") + PORT_START("jp2") + PORT_DIPNAME(0x01, 0x00, "A590 Drive LED") + PORT_DIPLOCATION("JP2:1") + PORT_DIPSETTING(0x00, "XT Drive") + PORT_DIPSETTING(0x01, "SCSI Drive") + PORT_START("jp4") + PORT_DIPNAME(0x01, 0x00, "A590 Interrupt") + PORT_DIPLOCATION("JP4:1") + PORT_DIPSETTING(0x00, "INT 2") + PORT_DIPSETTING(0x01, "INT 6") +INPUT_PORTS_END + +ioport_constructor a590_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( a590_pcb ); +} + +static INPUT_PORTS_START( a2091_pcb ) + PORT_START("jp1") + PORT_DIPNAME(0x0f, 0x01, "A2091 Memory size") + PORT_DIPLOCATION("JP1:1,2,3,4") + PORT_DIPSETTING(0x01, "0K") + PORT_DIPSETTING(0x02, "512K") + PORT_DIPSETTING(0x04, "1MB") + PORT_DIPSETTING(0x08, "2MB") + PORT_START("jp2") + PORT_DIPNAME(0x01, 0x00, "A2091 Auto-Boot") + PORT_DIPLOCATION("JP2:1") + PORT_DIPSETTING(0x00, "Enabled") + PORT_DIPSETTING(0x01, "Disabled") + PORT_START("jp3") + PORT_DIPNAME(0x01, 0x00, "A2091 Interrupt") + PORT_DIPLOCATION("JP3:1") + PORT_DIPSETTING(0x00, "INT 2") + PORT_DIPSETTING(0x01, "INT 6") + PORT_START("jp5") + PORT_DIPNAME(0x01, 0x00, "A2091 LUN") + PORT_DIPLOCATION("JP5:1") + PORT_DIPSETTING(0x00, "Disabled") + PORT_DIPSETTING(0x01, "Enabled") + PORT_DIPNAME(0x02, 0x00, "A2091 Time-Out") + PORT_DIPLOCATION("JP5:2") + PORT_DIPSETTING(0x00, "Short") + PORT_DIPSETTING(0x02, "Long") + PORT_DIPNAME(0x04, 0x00, "A2091 Reserved") + PORT_DIPLOCATION("JP5:3") + PORT_DIPSETTING(0x00, "Disabled") + PORT_DIPSETTING(0x02, "Enabled") + PORT_START("jp201") + PORT_DIPNAME(0x01, 0x00, "A2091 WD33C93 Clock") + PORT_DIPLOCATION("JP201:1") + PORT_DIPSETTING(0x00, "7 MHz") + PORT_DIPSETTING(0x01, "14 MHz") +INPUT_PORTS_END + +ioport_constructor a2091_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( a2091_pcb ); +} + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( dmac_hdc ) + MCFG_DMAC_ADD("dmac", 0) + MCFG_DMAC_SCSI_READ_HANDLER(READ8(dmac_hdc_device, dmac_scsi_r)) + MCFG_DMAC_SCSI_WRITE_HANDLER(WRITE8(dmac_hdc_device, dmac_scsi_w)) + MCFG_DMAC_INT_HANDLER(WRITELINE(dmac_hdc_device, dmac_int_w)) + MCFG_DMAC_CFGOUT_HANDLER(WRITELINE(dmac_hdc_device, dmac_cfgout_w)) + MCFG_DEVICE_ADD("scsi", SCSI_PORT, 0) + MCFG_SCSIDEV_ADD("scsi:" SCSI_PORT_DEVICE1, "harddisk", SCSIHD, SCSI_ID_1) + MCFG_DEVICE_ADD("wd33c93", WD33C93, 0) + MCFG_LEGACY_SCSI_PORT("scsi") + MCFG_WD33C93_IRQ_CB(WRITELINE(dmac_hdc_device, scsi_irq_w)) +MACHINE_CONFIG_END + +machine_config_constructor dmac_hdc_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( dmac_hdc ); +} + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +ROM_START( dmac_hdc ) + ROM_REGION16_BE(0x8000, "bootrom", 0) + ROM_DEFAULT_BIOS("v70") + + ROM_SYSTEM_BIOS(0, "v60", "Version 6.0") + ROMX_LOAD("390388-03.u13", 0x0000, 0x2000, CRC(2e77bbff) SHA1(8a098845068f32cfa4d34a278cd290f61d35a52c), ROM_SKIP(1) | ROM_BIOS(1)) + ROMX_LOAD("390389-03.u12", 0x0001, 0x2000, CRC(b0b8cf24) SHA1(fcf4017505f4d441814b45d559c19eab43816b30), ROM_SKIP(1) | ROM_BIOS(1)) + ROMX_LOAD("390388-03.u13", 0x4000, 0x2000, CRC(2e77bbff) SHA1(8a098845068f32cfa4d34a278cd290f61d35a52c), ROM_SKIP(1) | ROM_BIOS(1)) + ROMX_LOAD("390389-03.u12", 0x4001, 0x2000, CRC(b0b8cf24) SHA1(fcf4017505f4d441814b45d559c19eab43816b30), ROM_SKIP(1) | ROM_BIOS(1)) + + // changelog v6.1: prevent accesses to location 0 by application programs + ROM_SYSTEM_BIOS(1, "v61", "Version 6.1") + ROMX_LOAD("390721-01.u13", 0x0000, 0x2000, CRC(00dbf615) SHA1(503940d04fb3b49eaa61100fd3a487018b35e25a), ROM_SKIP(1) | ROM_BIOS(2)) + ROMX_LOAD("390722-01.u12", 0x0001, 0x2000, CRC(c460cfdb) SHA1(0de457daec3b84f75e8fb344defe24ce56cda3e0), ROM_SKIP(1) | ROM_BIOS(2)) + ROMX_LOAD("390721-01.u13", 0x4000, 0x2000, CRC(00dbf615) SHA1(503940d04fb3b49eaa61100fd3a487018b35e25a), ROM_SKIP(1) | ROM_BIOS(2)) + ROMX_LOAD("390722-01.u12", 0x4001, 0x2000, CRC(c460cfdb) SHA1(0de457daec3b84f75e8fb344defe24ce56cda3e0), ROM_SKIP(1) | ROM_BIOS(2)) + + // changelog v6.6: fixes dual SCSI problems with the wd33c93a controller + ROM_SYSTEM_BIOS(2, "v66", "Version 6.6") + ROMX_LOAD("390721-02.u13", 0x0000, 0x2000, CRC(c0871d25) SHA1(e155f18abb90cf820589c15e70559d3b6b391af8), ROM_SKIP(1) | ROM_BIOS(3)) + ROMX_LOAD("390722-02.u12", 0x0001, 0x2000, CRC(e536bbb2) SHA1(fd7f8a6da18c1b02d07eb990c2467a24183ede12), ROM_SKIP(1) | ROM_BIOS(3)) + ROMX_LOAD("390721-02.u13", 0x4000, 0x2000, CRC(c0871d25) SHA1(e155f18abb90cf820589c15e70559d3b6b391af8), ROM_SKIP(1) | ROM_BIOS(3)) + ROMX_LOAD("390722-02.u12", 0x4001, 0x2000, CRC(e536bbb2) SHA1(fd7f8a6da18c1b02d07eb990c2467a24183ede12), ROM_SKIP(1) | ROM_BIOS(3)) + + // final Commodore released version + ROM_SYSTEM_BIOS(3, "v70", "Version 7.0") + ROMX_LOAD("390721-03.u13", 0x0000, 0x2000, CRC(2942747a) SHA1(dbd7648e79c753337ff3e4f491de224bf05e6bb6), ROM_SKIP(1) | ROM_BIOS(4)) + ROMX_LOAD("390722-03.u12", 0x0001, 0x2000, CRC(a9ccffed) SHA1(149f5bd52e2d29904e3de483b9ad772448e9278e), ROM_SKIP(1) | ROM_BIOS(4)) + ROMX_LOAD("390721-03.u13", 0x4000, 0x2000, CRC(2942747a) SHA1(dbd7648e79c753337ff3e4f491de224bf05e6bb6), ROM_SKIP(1) | ROM_BIOS(4)) + ROMX_LOAD("390722-03.u12", 0x4001, 0x2000, CRC(a9ccffed) SHA1(149f5bd52e2d29904e3de483b9ad772448e9278e), ROM_SKIP(1) | ROM_BIOS(4)) + + // third-party upgrade ROM, requires a small ROM adapter pcb + ROM_SYSTEM_BIOS(4, "g614", "Guru-ROM 6.14") + ROMX_LOAD("gururom_v614.bin", 0x0000, 0x8000, CRC(04e52f93) SHA1(6da21b6f5e8f8837d64507cd8a4d5cdcac4f426b), ROM_GROUPWORD | ROM_BIOS(5)) + + // pal16l8a + ROM_REGION(0x104, "ram_controller", 0) + ROM_LOAD("390333-03.u5", 0x000, 0x104, CRC(dc4a8d9b) SHA1(761a1318106e49057f95258699076ec1079967ad)) +ROM_END + +const rom_entry *dmac_hdc_device::device_rom_region() const +{ + return ROM_NAME( dmac_hdc ); +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// dmac_hdc_device - constructor +//------------------------------------------------- + +dmac_hdc_device::dmac_hdc_device(const machine_config &mconfig, device_type type, const char *tag, + device_t *owner, UINT32 clock, const char *name, const char *shortname) : + device_t(mconfig, type, name, tag, owner, clock, shortname, __FILE__), + m_int6(false), + m_dmac(*this, "dmac"), + m_wdc(*this, "wd33c93") +{ +} + +a590_device::a590_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + dmac_hdc_device(mconfig, A590, tag, owner, clock, "CBM A590 HD Controller", "a590"), + device_exp_card_interface(mconfig, *this), + m_dips(*this, "dips"), + m_jp1(*this, "jp1"), + m_jp2(*this, "jp2"), + m_jp4(*this, "jp4") +{ +} + +a2091_device::a2091_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + dmac_hdc_device(mconfig, A2091, tag, owner, clock, "CBM A2091 HD Controller", "a2091"), + device_zorro2_card_interface(mconfig, *this), + m_jp1(*this, "jp1"), + m_jp2(*this, "jp2"), + m_jp3(*this, "jp3"), + m_jp5(*this, "jp5"), + m_jp201(*this, "jp201") +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void dmac_hdc_device::device_start() +{ +} + +void a590_device::device_start() +{ + set_zorro_device(); + + // setup DMAC + m_dmac->set_address_space(m_slot->m_space); + m_dmac->set_rom(memregion("bootrom")->base()); +} + +void a2091_device::device_start() +{ + set_zorro_device(); + + // setup DMAC + m_dmac->set_address_space(m_slot->m_space); + m_dmac->set_rom(memregion("bootrom")->base()); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void dmac_hdc_device::device_reset() +{ +} + +void dmac_hdc_device::resize_ram(int config) +{ + // allocate space for RAM + switch (config & 0x0f) + { + case 0x01: + m_ram.resize(0); + m_dmac->ramsz_w(0); + break; + case 0x02: + m_ram.resize(0x080000); + m_dmac->ramsz_w(1); + break; + case 0x04: + m_ram.resize(0x100000); + m_dmac->ramsz_w(2); + break; + case 0x08: + m_ram.resize(0x200000); + m_dmac->ramsz_w(3); + break; + } + + m_dmac->set_ram(&m_ram[0]); +} + +void a590_device::device_reset() +{ +} + +void a2091_device::device_reset() +{ +} + + +//************************************************************************** +// IMPLEMENTATION +//************************************************************************** + +WRITE_LINE_MEMBER( a590_device::cfgin_w ) +{ + // make sure we configure ourselves first + m_int6 = m_jp4->read() & 0x01; + resize_ram(m_dips->read() & 0x0f); + + // then tell the DMAC to start configuring + m_dmac->configin_w(state); +} + +WRITE_LINE_MEMBER( a2091_device::cfgin_w ) +{ + // make sure we configure ourselves first + m_int6 = m_jp3->read() & 0x01; + resize_ram(m_jp1->read() & 0x0f); + + // then tell the DMAC to start configuring + m_dmac->configin_w(state); +} + +READ8_MEMBER( dmac_hdc_device::dmac_scsi_r ) +{ + switch (offset) + { + case 0x48: return m_wdc->read(space, 0); + case 0x49: return m_wdc->read(space, 1); + } + + return 0xff; +} + +WRITE8_MEMBER( dmac_hdc_device::dmac_scsi_w ) +{ + switch (offset) + { + case 0x48: m_wdc->write(space, 0, data); break; + case 0x49: m_wdc->write(space, 1, data); break; + } +} + +WRITE_LINE_MEMBER( dmac_hdc_device::dmac_int_w ) +{ + if (m_int6) + int6_w(state); + else + int2_w(state); +} + +WRITE_LINE_MEMBER( dmac_hdc_device::scsi_irq_w ) +{ + // should be or'ed with xt-ide IRQ + m_dmac->intx_w(state); +} diff --git a/src/devices/bus/amiga/zorro/a590.h b/src/devices/bus/amiga/zorro/a590.h new file mode 100644 index 00000000000..4c929f28b01 --- /dev/null +++ b/src/devices/bus/amiga/zorro/a590.h @@ -0,0 +1,134 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best +/*************************************************************************** + + Commodore A590 / A2091 + + DMAC based SCSI controller for the Amiga 500 and Zorro-II + +***************************************************************************/ + +#pragma once + +#ifndef __A590_H__ +#define __A590_H__ + +#include "emu.h" +#include "zorro.h" +#include "machine/dmac.h" +#include "machine/wd33c93.h" + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> dmac_hdc_device + +class dmac_hdc_device : public device_t +{ +public: + // construction/destruction + dmac_hdc_device(const machine_config &mconfig, device_type type, const char *tag, + device_t *owner, UINT32 clock, const char *name, const char *shortname); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual const rom_entry *device_rom_region() const; + + DECLARE_READ8_MEMBER( dmac_scsi_r ); + DECLARE_WRITE8_MEMBER( dmac_scsi_w ); + DECLARE_WRITE_LINE_MEMBER( dmac_int_w ); + DECLARE_WRITE_LINE_MEMBER( dmac_cfgout_w ) { cfgout_w(state); } + DECLARE_WRITE_LINE_MEMBER( scsi_irq_w ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // to slot + virtual void cfgout_w(int state) = 0; + virtual void int2_w(int state) = 0; + virtual void int6_w(int state) = 0; + + // should be called when the ram size changes + void resize_ram(int config); + + // amiga interrupt target, int 2 or 6 + bool m_int6; + + // sub-devices + required_device m_dmac; + required_device m_wdc; + + dynamic_buffer m_ram; +}; + +// ======================> a590_device + +class a590_device : public dmac_hdc_device, public device_exp_card_interface +{ +public: + // construction/destruction + a590_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // optional information overrides + virtual ioport_constructor device_input_ports() const; + + // output to slot + virtual void cfgout_w(int state) { m_slot->cfgout_w(state); } + virtual void int2_w(int state) { m_slot->int2_w(state); } + virtual void int6_w(int state) { m_slot->int6_w(state); } + + // input from slot + virtual DECLARE_WRITE_LINE_MEMBER( cfgin_w ); + +private: + required_ioport m_dips; + required_ioport m_jp1; + required_ioport m_jp2; + required_ioport m_jp4; +}; + +// ======================> a2091_device + +class a2091_device : public dmac_hdc_device, public device_zorro2_card_interface +{ +public: + // construction/destruction + a2091_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // optional information overrides + virtual ioport_constructor device_input_ports() const; + + // output to slot + virtual void cfgout_w(int state) { m_slot->cfgout_w(state); } + virtual void int2_w(int state) { m_slot->int2_w(state); } + virtual void int6_w(int state) { m_slot->int6_w(state); } + + // input from slot + virtual DECLARE_WRITE_LINE_MEMBER( cfgin_w ); + +private: + required_ioport m_jp1; + required_ioport m_jp2; + required_ioport m_jp3; + required_ioport m_jp5; + required_ioport m_jp201; +}; + +// device type definition +extern const device_type A590; +extern const device_type A2091; + +#endif diff --git a/src/devices/bus/amiga/zorro/action_replay.c b/src/devices/bus/amiga/zorro/action_replay.c new file mode 100644 index 00000000000..a5356114c2e --- /dev/null +++ b/src/devices/bus/amiga/zorro/action_replay.c @@ -0,0 +1,149 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best +/*************************************************************************** + + Datel Action Replay + + Freezer cartridge for Amiga 500 and Amiga 2000 + + Skeleton device, just loads the ROMs and generates the NMI + for now. + + Hardware notes: + - http://www.mways.co.uk/amiga/howtocode/text/actionreplay.php + +***************************************************************************/ + +#include "action_replay.h" + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type ACTION_REPLAY_MK1 = &device_creator; +const device_type ACTION_REPLAY_MK2 = &device_creator; +const device_type ACTION_REPLAY_MK3 = &device_creator; + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +static INPUT_PORTS_START( ar_button ) + PORT_START("freeze") + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Freeze") PORT_CODE(KEYCODE_F12) PORT_CHANGED_MEMBER(DEVICE_SELF, action_replay_device, freeze, 0) +INPUT_PORTS_END + +ioport_constructor action_replay_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( ar_button ); +} + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +ROM_START( ar_mk1 ) + ROM_REGION(0x10000, "firmware", 0) + ROM_DEFAULT_BIOS("v150") + ROM_SYSTEM_BIOS(0, "v100", "Version 1.00") + ROMX_LOAD("ar1_v100.bin", 0x0000, 0x10000, BAD_DUMP CRC(2d921771) SHA1(1ead9dda2dad29146441f5ef7218375022e01248), ROM_BIOS(1)) + ROM_SYSTEM_BIOS(1, "v150", "Version 1.50") + ROMX_LOAD("ar1_v150.bin", 0x0000, 0x10000, BAD_DUMP CRC(f82c4258) SHA1(843b433b2c56640e045d5fdc854dc6b1a4964e7c), ROM_BIOS(2)) +ROM_END + +const rom_entry *action_replay_mk1_device::device_rom_region() const +{ + return ROM_NAME( ar_mk1 ); +} + +ROM_START( ar_mk2 ) + ROM_REGION(0x20000, "firmware", 0) + ROM_DEFAULT_BIOS("v214") + ROM_SYSTEM_BIOS(0, "v205", "Version 2.05") + ROMX_LOAD("ar2_v205.bin", 0x0000, 0x20000, BAD_DUMP CRC(4051eef8) SHA1(9df22b1d3285b522c223697c83d144d04e961a4a), ROM_BIOS(1)) + ROM_SYSTEM_BIOS(1, "v212", "Version 2.12") + ROMX_LOAD("ar2_v212.bin", 0x0000, 0x20000, BAD_DUMP CRC(d29bdd86) SHA1(76c2900457badf22b742f0af48b78937e8b67694), ROM_BIOS(2)) + ROM_SYSTEM_BIOS(2, "v214", "Version 2.14") + ROMX_LOAD("ar2_v214.bin", 0x0000, 0x20000, BAD_DUMP CRC(1bb3d0a8) SHA1(14b1f5a69efb6f4e2331970e6ca0f33c0f04ac91), ROM_BIOS(3)) +ROM_END + +const rom_entry *action_replay_mk2_device::device_rom_region() const +{ + return ROM_NAME( ar_mk2 ); +} + +ROM_START( ar_mk3 ) + ROM_REGION(0x40000, "firmware", 0) + ROM_DEFAULT_BIOS("v309") + ROM_SYSTEM_BIOS(0, "v309", "Version 3.09") + ROMX_LOAD("ar3_v309.evn", 0x00000, 0x20000, CRC(2b84519f) SHA1(7841873bf009d8341dfa2794b3751bacf86adcc8), ROM_SKIP(1) | ROM_BIOS(1)) + ROMX_LOAD("ar3_v309.odd", 0x00001, 0x20000, CRC(1d35bd56) SHA1(6464be1626b519499e76e4e3409e8016515d48b6), ROM_SKIP(1) | ROM_BIOS(1)) + ROM_SYSTEM_BIOS(1, "v317", "Version 3.17") + ROMX_LOAD("ar3_v314.bin", 0x0000, 0x40000, BAD_DUMP CRC(009f7768) SHA1(0439d6ccc2a0e5c2e83fcf2389dc4d4a440a4c62), ROM_BIOS(2)) +ROM_END + +const rom_entry *action_replay_mk3_device::device_rom_region() const +{ + return ROM_NAME( ar_mk3 ); +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// action_replay_device - constructor +//------------------------------------------------- + +action_replay_device::action_replay_device(const machine_config &mconfig, device_type type, const char *tag, + device_t *owner, UINT32 clock, const char *name, const char *shortname) : + device_t(mconfig, type, name, tag, owner, clock, shortname, __FILE__), + device_exp_card_interface(mconfig, *this), + m_button(*this, "freeze") +{ +} + +action_replay_mk1_device::action_replay_mk1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + action_replay_device(mconfig, ACTION_REPLAY_MK1, tag, owner, clock, "Datel Action Replay MK-I", "amiga_ar1") +{ +} + +action_replay_mk2_device::action_replay_mk2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + action_replay_device(mconfig, ACTION_REPLAY_MK1, tag, owner, clock, "Datel Action Replay MK-II", "amiga_ar2") +{ +} + +action_replay_mk3_device::action_replay_mk3_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + action_replay_device(mconfig, ACTION_REPLAY_MK1, tag, owner, clock, "Datel Action Replay MK-III", "amiga_ar3") +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void action_replay_device::device_start() +{ + set_zorro_device(); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void action_replay_device::device_reset() +{ +} + + +//************************************************************************** +// IMPLEMENTATION +//************************************************************************** + +INPUT_CHANGED_MEMBER( action_replay_device::freeze ) +{ + // pushing the freeze button generates an nmi + m_slot->ipl_w(newval == 1 ? 7 : 0); +} diff --git a/src/devices/bus/amiga/zorro/action_replay.h b/src/devices/bus/amiga/zorro/action_replay.h new file mode 100644 index 00000000000..1e47a9b36f0 --- /dev/null +++ b/src/devices/bus/amiga/zorro/action_replay.h @@ -0,0 +1,82 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best +/*************************************************************************** + + Datel Action Replay + + Freezer cartridge for Amiga 500 and Amiga 2000 + +***************************************************************************/ + +#pragma once + +#ifndef __ACTION_REPLAY_H__ +#define __ACTION_REPLAY_H__ + +#include "emu.h" +#include "zorro.h" + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> action_replay_device + +class action_replay_device : public device_t, public device_exp_card_interface +{ +public: + // construction/destruction + action_replay_device(const machine_config &mconfig, device_type type, const char *tag, + device_t *owner, UINT32 clock, const char *name, const char *shortname); + + // optional information overrides + virtual ioport_constructor device_input_ports() const; + + DECLARE_INPUT_CHANGED_MEMBER( freeze ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + +private: + required_ioport m_button; +}; + +class action_replay_mk1_device : public action_replay_device +{ +public: + // construction/destruction + action_replay_mk1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; +}; + +class action_replay_mk2_device : public action_replay_device +{ +public: + // construction/destruction + action_replay_mk2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; +}; + +class action_replay_mk3_device : public action_replay_device +{ +public: + // construction/destruction + action_replay_mk3_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; +}; + +// device type definition +extern const device_type ACTION_REPLAY_MK1; +extern const device_type ACTION_REPLAY_MK2; +extern const device_type ACTION_REPLAY_MK3; + +#endif diff --git a/src/devices/bus/amiga/zorro/buddha.c b/src/devices/bus/amiga/zorro/buddha.c new file mode 100644 index 00000000000..761162269d3 --- /dev/null +++ b/src/devices/bus/amiga/zorro/buddha.c @@ -0,0 +1,350 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best +/*************************************************************************** + + Buddha + + Zorro-II IDE controller + +***************************************************************************/ + +#include "buddha.h" + +//************************************************************************** +// CONSTANTS / MACROS +//************************************************************************** + +#define VERBOSE 1 + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type BUDDHA = &device_creator; + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( buddha ) + MCFG_ATA_INTERFACE_ADD("ata_0", ata_devices, NULL, NULL, false) + MCFG_ATA_INTERFACE_IRQ_HANDLER(WRITELINE(buddha_device, ide_0_interrupt_w)) + MCFG_ATA_INTERFACE_ADD("ata_1", ata_devices, NULL, NULL, false) + MCFG_ATA_INTERFACE_IRQ_HANDLER(WRITELINE(buddha_device, ide_1_interrupt_w)) +MACHINE_CONFIG_END + +machine_config_constructor buddha_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( buddha ); +} + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +ROM_START( buddha ) + ROM_REGION16_BE(0x10000, "bootrom", 0) + ROM_DEFAULT_BIOS("v103-17") + ROM_SYSTEM_BIOS(0, "v103-8", "Version 103.8") + ROMX_LOAD("buddha_103-8.rom", 0x0000, 0x8000, CRC(44f81426) SHA1(95555c6690b5c697e1cdca2726e47c1c6c194d7c), ROM_SKIP(1) | ROM_BIOS(1)) + ROM_SYSTEM_BIOS(1, "v103-17", "Version 103.17") + ROMX_LOAD("buddha_103-17.rom", 0x0000, 0x8000, CRC(2b7b24e0) SHA1(ec17a58962c373a2892090ec9b1722d2c326d631), ROM_SKIP(1) | ROM_BIOS(2)) +ROM_END + +const rom_entry *buddha_device::device_rom_region() const +{ + return ROM_NAME( buddha ); +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// buddha_device - constructor +//------------------------------------------------- + +buddha_device::buddha_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, BUDDHA, "Buddha IDE controller", tag, owner, clock, "buddha", __FILE__), + device_zorro2_card_interface(mconfig, *this), + m_ata_0(*this, "ata_0"), + m_ata_1(*this, "ata_1"), + m_ide_interrupts_enabled(false), + m_ide_0_interrupt(0), + m_ide_1_interrupt(0) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void buddha_device::device_start() +{ + set_zorro_device(); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void buddha_device::device_reset() +{ +} + + +//************************************************************************** +// IMPLEMENTATION +//************************************************************************** + +void buddha_device::autoconfig_base_address(offs_t address) +{ + if (VERBOSE) + logerror("%s('%s'): autoconfig_base_address received: 0x%06x\n", shortname(), basetag(), address); + + if (VERBOSE) + logerror("-> installing buddha\n"); + + // stop responding to default autoconfig + m_slot->m_space->unmap_readwrite(0xe80000, 0xe8007f); + + // install autoconfig handler to new location + m_slot->m_space->install_readwrite_handler(address, address + 0x7f, + read16_delegate(FUNC(amiga_autoconfig::autoconfig_read), static_cast(this)), + write16_delegate(FUNC(amiga_autoconfig::autoconfig_write), static_cast(this)), 0xffff); + + // buddha registers + m_slot->m_space->install_readwrite_handler(address + 0x7fe, address + 0x7ff, + read16_delegate(FUNC(buddha_device::speed_r), this), + write16_delegate(FUNC(buddha_device::speed_w), this), 0xffff); + + m_slot->m_space->install_readwrite_handler(address + 0x800, address + 0x8ff, + read16_delegate(FUNC(buddha_device::ide_0_cs0_r), this), + write16_delegate(FUNC(buddha_device::ide_0_cs0_w), this), 0xffff); + + m_slot->m_space->install_readwrite_handler(address + 0x900, address + 0x9ff, + read16_delegate(FUNC(buddha_device::ide_0_cs1_r), this), + write16_delegate(FUNC(buddha_device::ide_0_cs1_w), this), 0xffff); + + m_slot->m_space->install_readwrite_handler(address + 0xa00, address + 0xaff, + read16_delegate(FUNC(buddha_device::ide_0_cs0_r), this), + write16_delegate(FUNC(buddha_device::ide_0_cs0_w), this), 0xffff); + + m_slot->m_space->install_readwrite_handler(address + 0xb00, address + 0xbff, + read16_delegate(FUNC(buddha_device::ide_0_cs1_r), this), + write16_delegate(FUNC(buddha_device::ide_0_cs1_w), this), 0xffff); + + m_slot->m_space->install_read_handler(address + 0xf00, address + 0xf3f, + read16_delegate(FUNC(buddha_device::ide_0_interrupt_r), this), 0xffff); + + m_slot->m_space->install_read_handler(address + 0xf40, address + 0xf7f, + read16_delegate(FUNC(buddha_device::ide_1_interrupt_r), this), 0xffff); + + m_slot->m_space->install_write_handler(address + 0xfc0, address + 0xfff, + write16_delegate(FUNC(buddha_device::ide_interrupt_enable_w), this), 0xffff); + + // install access to the rom space + m_slot->m_space->install_rom(address + 0x1000, address + 0xffff, memregion("bootrom")->base() + 0x1000); + + // we're done + m_slot->cfgout_w(0); +} + +WRITE_LINE_MEMBER( buddha_device::cfgin_w ) +{ + if (VERBOSE) + logerror("%s('%s'): configin_w (%d)\n", shortname(), basetag(), state); + + if (state == 0) + { + // setup autoconfig + autoconfig_board_type(BOARD_TYPE_ZORRO2); + autoconfig_board_size(BOARD_SIZE_64K); + autoconfig_link_into_memory(false); + autoconfig_rom_vector_valid(true); + autoconfig_multi_device(false); + autoconfig_8meg_preferred(false); + autoconfig_can_shutup(true); + autoconfig_product(0x00); + autoconfig_manufacturer(0x1212); + autoconfig_serial(0x00000000); + autoconfig_rom_vector(0x1000); + + // install autoconfig handler + m_slot->m_space->install_readwrite_handler(0xe80000, 0xe8007f, + read16_delegate(FUNC(amiga_autoconfig::autoconfig_read), static_cast(this)), + write16_delegate(FUNC(amiga_autoconfig::autoconfig_write), static_cast(this)), 0xffff); + } +} + +READ16_MEMBER( buddha_device::speed_r ) +{ + UINT16 data = 0xffff; + + if (VERBOSE) + logerror("%s('%s'): ide_0_interrupt_r %04x [mask = %04x]\n", shortname(), basetag(), data, mem_mask); + + return data; +} + +WRITE16_MEMBER( buddha_device::speed_w ) +{ + if (VERBOSE) + logerror("%s('%s'): speed_w %04x [mask = %04x]\n", shortname(), basetag(), data, mem_mask); +} + +WRITE_LINE_MEMBER( buddha_device::ide_0_interrupt_w) +{ + if (VERBOSE) + logerror("%s('%s'): ide_0_interrupt_w (%d)\n", shortname(), basetag(), state); + + m_ide_0_interrupt = state; + + if (m_ide_interrupts_enabled) + m_slot->int2_w(state); +} + +WRITE_LINE_MEMBER( buddha_device::ide_1_interrupt_w) +{ + if (VERBOSE) + logerror("%s('%s'): ide_1_interrupt_w (%d)\n", shortname(), basetag(), state); + + m_ide_1_interrupt = state; + + if (m_ide_interrupts_enabled) + m_slot->int2_w(state); +} + +READ16_MEMBER( buddha_device::ide_0_interrupt_r ) +{ + UINT16 data = 0xffff; + + data = m_ide_0_interrupt << 15; + + if (VERBOSE) + logerror("%s('%s'): ide_0_interrupt_r %04x [mask = %04x]\n", shortname(), basetag(), data, mem_mask); + + logerror("%s\n", device().machine().describe_context()); + + return data; +} + +READ16_MEMBER( buddha_device::ide_1_interrupt_r ) +{ + UINT16 data = 0xffff; + + data = m_ide_1_interrupt << 15; + + if (VERBOSE) + logerror("%s('%s'): ide_1_interrupt_r %04x [mask = %04x]\n", shortname(), basetag(), data, mem_mask); + + return data; +} + +WRITE16_MEMBER( buddha_device::ide_interrupt_enable_w ) +{ + if (VERBOSE) + logerror("%s('%s'): ide_interrupt_enable_w %04x [mask = %04x]\n", shortname(), basetag(), data, mem_mask); + + // writing any value here enables ide interrupts to the zorro slot + m_ide_interrupts_enabled = true; +} + +READ16_MEMBER( buddha_device::ide_0_cs0_r ) +{ + UINT16 data = 0xffff; + + mem_mask = (mem_mask << 8) | (mem_mask >> 8); + data = m_ata_0->read_cs0(space, (offset >> 1) & 0x07, mem_mask); + + if (VERBOSE) + logerror("%s('%s'): ide_0_cs0_r(%04x) %04x [mask = %04x]\n", shortname(), basetag(), offset, data, mem_mask); + + return (data << 8) | (data >> 8); +} + +WRITE16_MEMBER( buddha_device::ide_0_cs0_w ) +{ + if (VERBOSE) + logerror("%s('%s'): ide_0_cs0_w(%04x) %04x [mask = %04x]\n", shortname(), basetag(), offset, data, mem_mask); + + mem_mask = (mem_mask << 8) | (mem_mask >> 8); + data = (data << 8) | (data >> 8); + + m_ata_0->write_cs0(space, (offset >> 1) & 0x07, data, mem_mask); +} + +READ16_MEMBER( buddha_device::ide_0_cs1_r ) +{ + UINT16 data = 0xffff; + + mem_mask = (mem_mask << 8) | (mem_mask >> 8); + data = m_ata_0->read_cs1(space, (offset >> 1) & 0x07, mem_mask); + + if (VERBOSE) + logerror("%s('%s'): ide_0_cs1_r(%04x) %04x [mask = %04x]\n", shortname(), basetag(), offset, data, mem_mask); + + return (data << 8) | (data >> 8); +} + +WRITE16_MEMBER( buddha_device::ide_0_cs1_w ) +{ + if (VERBOSE) + logerror("%s('%s'): ide_0_cs1_w(%04x) %04x [mask = %04x]\n", shortname(), basetag(), offset, data, mem_mask); + + mem_mask = (mem_mask << 8) | (mem_mask >> 8); + data = (data << 8) | (data >> 8); + + m_ata_0->write_cs1(space, (offset >> 1) & 0x07, data, mem_mask); +} + +READ16_MEMBER( buddha_device::ide_1_cs0_r ) +{ + UINT16 data = 0xffff; + + mem_mask = (mem_mask << 8) | (mem_mask >> 8); + data = m_ata_1->read_cs0(space, (offset >> 1) & 0x07, mem_mask); + + if (VERBOSE) + logerror("%s('%s'): ide_1_cs0_r(%04x) %04x [mask = %04x]\n", shortname(), basetag(), offset, data, mem_mask); + + return (data << 8) | (data >> 8); +} + +WRITE16_MEMBER( buddha_device::ide_1_cs0_w ) +{ + if (VERBOSE) + logerror("%s('%s'): ide_1_cs0_w(%04x) %04x [mask = %04x]\n", shortname(), basetag(), offset, data, mem_mask); + + mem_mask = (mem_mask << 8) | (mem_mask >> 8); + data = (data << 8) | (data >> 8); + + m_ata_1->write_cs0(space, (offset >> 1) & 0x07, data, mem_mask); +} + +READ16_MEMBER( buddha_device::ide_1_cs1_r ) +{ + UINT16 data = 0xffff; + + mem_mask = (mem_mask << 8) | (mem_mask >> 8); + data = m_ata_1->read_cs1(space, (offset >> 1) & 0x07, mem_mask); + + if (VERBOSE) + logerror("%s('%s'): ide_1_cs1_r(%04x) %04x [mask = %04x]\n", shortname(), basetag(), offset, data, mem_mask); + + return (data << 8) | (data >> 8); +} + +WRITE16_MEMBER( buddha_device::ide_1_cs1_w ) +{ + if (VERBOSE) + logerror("%s('%s'): ide_1_cs1_w(%04x) %04x [mask = %04x]\n", shortname(), basetag(), offset, data, mem_mask); + + mem_mask = (mem_mask << 8) | (mem_mask >> 8); + data = (data << 8) | (data >> 8); + + m_ata_1->write_cs1(space, (offset >> 1) & 0x07, data, mem_mask); +} diff --git a/src/devices/bus/amiga/zorro/buddha.h b/src/devices/bus/amiga/zorro/buddha.h new file mode 100644 index 00000000000..d1a41dcf635 --- /dev/null +++ b/src/devices/bus/amiga/zorro/buddha.h @@ -0,0 +1,82 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best +/*************************************************************************** + + Buddha + + Zorro-II IDE controller + +***************************************************************************/ + +#pragma once + +#ifndef __BUDDHA_H__ +#define __BUDDHA_H__ + +#include "emu.h" +#include "zorro.h" +#include "machine/autoconfig.h" +#include "machine/ataintf.h" + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> buddha_device + +class buddha_device : public device_t, public device_zorro2_card_interface, public amiga_autoconfig +{ +public: + // construction/destruction + buddha_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // speed register + DECLARE_READ16_MEMBER( speed_r ); + DECLARE_WRITE16_MEMBER( speed_w ); + + // ide register + DECLARE_READ16_MEMBER( ide_0_cs0_r ); + DECLARE_WRITE16_MEMBER( ide_0_cs0_w ); + DECLARE_READ16_MEMBER( ide_0_cs1_r ); + DECLARE_WRITE16_MEMBER( ide_0_cs1_w ); + DECLARE_READ16_MEMBER( ide_1_cs0_r ); + DECLARE_WRITE16_MEMBER( ide_1_cs0_w ); + DECLARE_READ16_MEMBER( ide_1_cs1_r ); + DECLARE_WRITE16_MEMBER( ide_1_cs1_w ); + + // interrupt register + DECLARE_READ16_MEMBER( ide_0_interrupt_r ); + DECLARE_READ16_MEMBER( ide_1_interrupt_r ); + DECLARE_WRITE16_MEMBER( ide_interrupt_enable_w ); + + DECLARE_WRITE_LINE_MEMBER( ide_0_interrupt_w ); + DECLARE_WRITE_LINE_MEMBER( ide_1_interrupt_w ); + +protected: + // device-level overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual const rom_entry *device_rom_region() const; + + virtual void device_start(); + virtual void device_reset(); + + // device_zorro2_card_interface overrides + virtual DECLARE_WRITE_LINE_MEMBER( cfgin_w ); + + // amiga_autoconfig overrides + virtual void autoconfig_base_address(offs_t address); + +private: + required_device m_ata_0; + required_device m_ata_1; + + bool m_ide_interrupts_enabled; + int m_ide_0_interrupt; + int m_ide_1_interrupt; +}; + +// device type definition +extern const device_type BUDDHA; + +#endif diff --git a/src/devices/bus/amiga/zorro/cards.c b/src/devices/bus/amiga/zorro/cards.c new file mode 100644 index 00000000000..5fc67353d17 --- /dev/null +++ b/src/devices/bus/amiga/zorro/cards.c @@ -0,0 +1,39 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best +/*************************************************************************** + + Amiga Zorro Cards + +***************************************************************************/ + +#include "cards.h" + +SLOT_INTERFACE_START( a1000_expansion_cards ) +SLOT_INTERFACE_END + +SLOT_INTERFACE_START( a500_expansion_cards ) + SLOT_INTERFACE("ar1", ACTION_REPLAY_MK1) + SLOT_INTERFACE("ar2", ACTION_REPLAY_MK2) + SLOT_INTERFACE("ar3", ACTION_REPLAY_MK3) + SLOT_INTERFACE("a590", A590) +SLOT_INTERFACE_END + +SLOT_INTERFACE_START( a2000_expansion_cards ) + SLOT_INTERFACE("ar1", ACTION_REPLAY_MK1) + SLOT_INTERFACE("ar2", ACTION_REPLAY_MK2) + SLOT_INTERFACE("ar3", ACTION_REPLAY_MK3) +SLOT_INTERFACE_END + +SLOT_INTERFACE_START( zorro2_cards ) + SLOT_INTERFACE("a2052", A2052) + SLOT_INTERFACE("a2091", A2091) + SLOT_INTERFACE("a2232", A2232) + SLOT_INTERFACE("buddha", BUDDHA) +SLOT_INTERFACE_END + +SLOT_INTERFACE_START( zorro3_cards ) + SLOT_INTERFACE("a2052", A2052) + SLOT_INTERFACE("a2091", A2091) + SLOT_INTERFACE("a2232", A2232) + SLOT_INTERFACE("buddha", BUDDHA) +SLOT_INTERFACE_END diff --git a/src/devices/bus/amiga/zorro/cards.h b/src/devices/bus/amiga/zorro/cards.h new file mode 100644 index 00000000000..919c2c3c899 --- /dev/null +++ b/src/devices/bus/amiga/zorro/cards.h @@ -0,0 +1,44 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best +/*************************************************************************** + + Amiga Zorro Cards + + There are different card types and layouts: + + * 86-pin expansion slot + - A1000 + - A500 (rotated slot) + - A2000/B2000 (internal slot) + * Zorro-II + - A2000 + - B2000 + * Zorro-III + - A3000, A4000 + + For details see zorro.h. Zorro-II cards can be inserted into + Zorro-III slots. + +***************************************************************************/ + +#pragma once + +#ifndef __CARDS_H__ +#define __CARDS_H__ + +#include "emu.h" + +#include "a2052.h" +#include "a2232.h" +#include "a590.h" +#include "action_replay.h" +#include "buddha.h" + +SLOT_INTERFACE_EXTERN( a1000_expansion_cards ); +SLOT_INTERFACE_EXTERN( a500_expansion_cards ); +SLOT_INTERFACE_EXTERN( a2000_expansion_cards ); + +SLOT_INTERFACE_EXTERN( zorro2_cards ); +SLOT_INTERFACE_EXTERN( zorro3_cards ); + +#endif // __CARDS_H__ diff --git a/src/devices/bus/amiga/zorro/zorro.c b/src/devices/bus/amiga/zorro/zorro.c new file mode 100644 index 00000000000..aec7f5e54f8 --- /dev/null +++ b/src/devices/bus/amiga/zorro/zorro.c @@ -0,0 +1,378 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best +/*************************************************************************** + + Amiga Zorro Slots + + 86-pin Expansion Slot (Zorro-I), Zorro-II, Zorro-III + +***************************************************************************/ + +#include "zorro.h" + + +//************************************************************************** +// ZORRO SLOT DEVICE +//************************************************************************** + +const device_type ZORRO_SLOT = &device_creator; + +//------------------------------------------------- +// zorro_slot_device - constructor +//------------------------------------------------- + +zorro_slot_device::zorro_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, ZORRO_SLOT, "Zorro slot", tag, owner, clock, "zorro_slot", __FILE__), + device_slot_interface(mconfig, *this), + m_zorro_tag(NULL) +{ +} + +zorro_slot_device::zorro_slot_device(const machine_config &mconfig, device_type type, const char *name, + const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_slot_interface(mconfig, *this), + m_zorro_tag(NULL) +{ +} + +void zorro_slot_device::set_zorro_slot(device_t &device, device_t *owner, const char *zorro_tag) +{ + zorro_slot_device &zorro_card = dynamic_cast(device); + zorro_card.m_owner = owner; + zorro_card.m_zorro_tag = zorro_tag; +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void zorro_slot_device::device_start() +{ + device_zorro_card_interface *dev = dynamic_cast(get_card_device()); + + if (dev) + { + zorro_device *m_zorro_bus = downcast(m_owner->subdevice(m_zorro_tag)); + m_zorro_bus->add_card(dev); + } +} + + +//************************************************************************** +// BASE ZORRO BUS DEVICE +//************************************************************************** + +//------------------------------------------------- +// exp_slot_device - constructor +//------------------------------------------------- + +zorro_device::zorro_device(const machine_config &mconfig, device_type type, const char *name, + const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + m_space(NULL), + m_cputag(NULL), + m_ovr_handler(*this), + m_int2_handler(*this), + m_int6_handler(*this) +{ +} + +//------------------------------------------------- +// set_cputag - set cpu we are attached to +//------------------------------------------------- + +void zorro_device::set_cputag(device_t &device, const char *tag) +{ + zorro_device &zorro = downcast(device); + zorro.m_cputag = tag; +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void zorro_device::device_start() +{ + // get address space + device_t *cpu = machine().device(m_cputag); + m_space = &cpu->memory().space(AS_PROGRAM); + + // resolve callbacks + m_ovr_handler.resolve_safe(); + m_int2_handler.resolve_safe(); + m_int6_handler.resolve_safe(); +} + +// from slot device +WRITE_LINE_MEMBER( zorro_device::ovr_w ) { m_ovr_handler(state); } +WRITE_LINE_MEMBER( zorro_device::int2_w ) { m_int2_handler(state); } +WRITE_LINE_MEMBER( zorro_device::int6_w ) { m_int6_handler(state); } + + +//************************************************************************** +// EXPANSION SLOT DEVICE +//************************************************************************** + +const device_type EXP_SLOT = &device_creator; + +//------------------------------------------------- +// exp_slot_device - constructor +//------------------------------------------------- + +exp_slot_device::exp_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + zorro_device(mconfig, EXP_SLOT, "86-pin expansion slot", tag, owner, clock, "exp_slot", __FILE__), + m_ipl_handler(*this), + m_dev(NULL) +{ +} + +exp_slot_device::exp_slot_device(const machine_config &mconfig, device_type type, const char *name, + const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + zorro_device(mconfig, type, name, tag, owner, clock, shortname, source), + m_ipl_handler(*this), + m_dev(NULL) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void exp_slot_device::device_start() +{ + // resolve callbacks + m_ipl_handler.resolve_safe(); + + // call base device start + zorro_device::device_start(); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void exp_slot_device::device_reset() +{ + // if we have a device, start the autoconfig chain + if (m_dev) + m_dev->cfgin_w(0); +} + +//------------------------------------------------- +// add_card - add new card to our bus +//------------------------------------------------- + +void exp_slot_device::add_card(device_zorro_card_interface *card) +{ + m_dev = downcast(card); + card->set_zorro_bus(this); +} + +// from slot device +void exp_slot_device::ipl_w(int interrupt) { m_ipl_handler(0, interrupt, 0xff); } + +// from host +void exp_slot_device::fc_w(int code) { if (m_dev) m_dev->fc_w(code); } + + +//************************************************************************** +// ZORRO2 DEVICE +//************************************************************************** + +const device_type ZORRO2 = &device_creator; + +//------------------------------------------------- +// zorro2_device - constructor +//------------------------------------------------- + +zorro2_device::zorro2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + zorro_device(mconfig, ZORRO2, "Zorro-II bus", tag, owner, clock, "zorro2", __FILE__), + m_eint1_handler(*this), + m_eint4_handler(*this), + m_eint5_handler(*this), + m_eint7_handler(*this), + m_autoconfig_device(NULL) +{ +} + +zorro2_device::zorro2_device(const machine_config &mconfig, device_type type, const char *name, + const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + zorro_device(mconfig, type, name, tag, owner, clock, shortname, source), + m_eint1_handler(*this), + m_eint4_handler(*this), + m_eint5_handler(*this), + m_eint7_handler(*this), + m_autoconfig_device(NULL) +{ +} + +//------------------------------------------------- +// zorro2_device - destructor +//------------------------------------------------- + +zorro2_device::~zorro2_device() +{ + m_dev.detach_all(); +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void zorro2_device::device_start() +{ + // resolve callbacks + m_eint1_handler.resolve_safe(); + m_eint4_handler.resolve_safe(); + m_eint5_handler.resolve_safe(); + m_eint7_handler.resolve_safe(); + + // call base device start + zorro_device::device_start(); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void zorro2_device::device_reset() +{ + // initiate autoconfig + m_autoconfig_device = m_dev.first(); + + // if we have a device, start the autoconfig chain + if (m_autoconfig_device) + m_autoconfig_device->cfgin_w(0); +} + +//------------------------------------------------- +// add_card - add new card to our bus +//------------------------------------------------- + +void zorro2_device::add_card(device_zorro_card_interface *card) +{ + device_zorro2_card_interface *zorro2_card = downcast(card); + card->set_zorro_bus(this); + m_dev.append(*zorro2_card); +} + +// from slot device +WRITE_LINE_MEMBER( zorro2_device::eint1_w ) { m_eint1_handler(state); } +WRITE_LINE_MEMBER( zorro2_device::eint4_w ) { m_eint4_handler(state); } +WRITE_LINE_MEMBER( zorro2_device::eint5_w ) { m_eint5_handler(state); } +WRITE_LINE_MEMBER( zorro2_device::eint7_w ) { m_eint7_handler(state); } + +WRITE_LINE_MEMBER( zorro2_device::cfgout_w ) +{ + m_autoconfig_device = m_autoconfig_device->next(); + + // if there is still a device in the chain, tell it to configure itself + if (m_autoconfig_device) + m_autoconfig_device->cfgin_w(0); +} + +// from host +void zorro2_device::fc_w(int code) +{ + device_zorro2_card_interface *entry = m_dev.first(); + + while (entry) + { + entry->fc_w(code); + entry = entry->next(); + } +} + + +//************************************************************************** +// ZORRO INTERFACE +//************************************************************************** + +//------------------------------------------------- +// device_zorro_card_interface - constructor +//------------------------------------------------- + +device_zorro_card_interface::device_zorro_card_interface(const machine_config &mconfig, device_t &device) : + device_slot_card_interface(mconfig, device), + m_zorro(NULL) +{ +} + +//------------------------------------------------- +// ~device_zorro_card_interface - destructor +//------------------------------------------------- + +device_zorro_card_interface::~device_zorro_card_interface() +{ +} + +void device_zorro_card_interface::set_zorro_bus(zorro_device *device) +{ + m_zorro = device; +} + +void device_zorro_card_interface::fc_w(int code) +{ +} + +WRITE_LINE_MEMBER( device_zorro_card_interface::cfgin_w ) +{ +} + + +//************************************************************************** +// EXPANSION CARD INTERFACE +//************************************************************************** + +//------------------------------------------------- +// device_exp_card_interface - constructor +//------------------------------------------------- + +device_exp_card_interface::device_exp_card_interface(const machine_config &mconfig, device_t &device) : + device_zorro_card_interface(mconfig, device), + m_slot(NULL) +{ +} + +//------------------------------------------------- +// ~device_exp_card_interface - destructor +//------------------------------------------------- + +device_exp_card_interface::~device_exp_card_interface() +{ +} + +void device_exp_card_interface::set_zorro_device() +{ + m_slot = dynamic_cast(m_zorro); +} + + +//************************************************************************** +// ZORRO-II CARD INTERFACE +//************************************************************************** + +//------------------------------------------------- +// device_zorro2_interface - constructor +//------------------------------------------------- + +device_zorro2_card_interface::device_zorro2_card_interface(const machine_config &mconfig, device_t &device) : + device_zorro_card_interface(mconfig, device), + m_next(NULL), + m_slot(NULL) +{ +} + +//------------------------------------------------- +// ~device_zorro2_interface - destructor +//------------------------------------------------- + +device_zorro2_card_interface::~device_zorro2_card_interface() +{ +} + +void device_zorro2_card_interface::set_zorro_device() +{ + m_slot = dynamic_cast(m_zorro); +} diff --git a/src/devices/bus/amiga/zorro/zorro.h b/src/devices/bus/amiga/zorro/zorro.h new file mode 100644 index 00000000000..4b61b644136 --- /dev/null +++ b/src/devices/bus/amiga/zorro/zorro.h @@ -0,0 +1,449 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best +/*************************************************************************** + + Amiga Zorro Slots + + 86-pin Expansion Slot (Zorro-I), Zorro-II, Zorro-III + + 86-pin Expansion Slot + + 2 Ground 1 Ground + 4 Ground 3 Ground + 6 +5VDC 5 +5VDC + 8 -5VDC 7 N/C + 10 +12VDC 9 N/C *1 + 12 CFGIN 11 N/C *2 + 14 /C3 Clock 13 Ground + 16 /C1 Clock 15 CDAC + 18 XRDY 17 /OVR + 20 N/C *3 19 /INT2 + 22 /INT6 21 A5 + 24 A4 23 A6 + 26 A3 25 Ground + 28 A7 27 A2 + 30 A8 29 A1 + 32 A9 31 FC0 + 34 A10 33 FC1 + 36 A11 35 FC2 + 38 A12 37 Ground + 40 /IPL0 39 A13 + 42 /IPL1 41 A14 + 44 /IPL2 43 A15 + 46 /BEER 45 A16 + 48 /VPA 47 A17 + 50 E Clock 49 Ground + 52 A18 51 /VMA + 54 A19 53 /RST + 56 A20 55 /HLT + 58 A21 57 A22 + 60 /BR *4 59 A23 + 62 /BGACK 61 Ground + 64 /BG *5 63 D15 + 66 /DTACK 65 D14 + 68 R/W 67 D13 + 70 /LDS 69 D12 + 72 /UDS 71 D11 + 74 /AS 73 Ground + 76 D10 75 D0 + 78 D9 77 D1 + 80 D8 79 D2 + 82 D7 81 D3 + 84 D6 83 D4 + 86 D5 85 Ground + + *1 28 MHz Clock on A2000 and B2000 + *2 /COPCFG on B2000 + *3 /PALOPE on A1000, /BOSS on B2000 + *4 /CBR on B2000 + *5 /CBG on B2000 + + Zorro-II (differences only) + + 7 /OWN + 9 /SLAVEn + 11 /CFGOUTn + 12 /CFGINn + 20 -12VDC + 40 /EINT7 + 42 /EINT5 + 44 /EINT4 + 60 /BRn + 64 /BGn + + 88 Ground 87 Ground + 90 Ground 89 Ground + 92 7 MHz 91 Ground + 94 /BURST 93 DOE + 96 /EINT1 95 /BG *5 + 98 N/C 97 N/C + 100 Ground 99 Ground + + *6 /GBG on B2000 + + Zorro-III + + The Zorro-III is a multiplexed Zorro-II bus with address- and + data phases. Signals changes as follows: + + 17 /CINH + 18 /MTCR + 29 /LOCK + 30 AD8 (D0) + 32 AD9 (D1) + 34 AD10 (D2) + 36 AD11 (D3) + 38 AD12 (D4) + 39 AD13 (D5) + 40 Reserved + 41 AD14 (D6) + 42 Reserved + 43 AD15 (D7) + 44 Reserved + 45 AD16 (D8) + 47 AD17 (D9) + 48 /MTACK + 51 /DS0 + 52 AD18 (D10) + 54 AD19 (D11) + 56 AD20 (D12) + 57 AD22 (D14) + 58 AD21 (D13) + 59 AD23 (D15) + 63 AD31 + 65 AD30 + 67 AD29 + 69 AD28 + 70 /DS2 + 71 AD27 + 72 /DS3 + 74 /CCS + 75 SD0 (D16) + 76 AD26 + 77 SD1 (D17) + 78 AD25 + 79 SD2 (D18) + 80 AD24 + 81 SD3 (D19) + 82 SD7 (D23) + 83 SD4 (D20) + 84 SD6 (D22) + 86 SD5 (D21) + 91 Sense Z3 + 94 /IORST + 95 /BCLR + 97 /FCS + 98 /DS1 + + +***************************************************************************/ + +#pragma once + +#ifndef __ZORRO_H__ +#define __ZORRO_H__ + +#include "emu.h" + +//************************************************************************** +// CONSTANTS / MACROS +//************************************************************************** + +#define EXP_SLOT_TAG "exp" +#define ZORROBUS_TAG "zorrobus" + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_ZORRO_SLOT_ADD(_zorrotag, _tag, _slot_intf, _def_slot) \ + MCFG_DEVICE_ADD(_tag, ZORRO_SLOT, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) \ + zorro_slot_device::set_zorro_slot(*device, owner, _zorrotag); + +// ======================> expansion slot + +#define MCFG_EXPANSION_SLOT_ADD(_cputag, _slot_intf, _def_slot) \ + MCFG_DEVICE_ADD(EXP_SLOT_TAG, EXP_SLOT, 0) \ + zorro_device::set_cputag(*device, _cputag); \ + MCFG_ZORRO_SLOT_ADD(EXP_SLOT_TAG, "slot", _slot_intf, _def_slot) + +// callbacks +#define MCFG_EXPANSION_SLOT_OVR_HANDLER(_devcb) \ + devcb = &zorro_device::set_ovr_handler(*device, DEVCB_##_devcb); + +#define MCFG_EXPANSION_SLOT_INT2_HANDLER(_devcb) \ + devcb = &zorro_device::set_int2_handler(*device, DEVCB_##_devcb); + +#define MCFG_EXPANSION_SLOT_INT6_HANDLER(_devcb) \ + devcb = &zorro_device::set_int6_handler(*device, DEVCB_##_devcb); + +#define MCFG_EXPANSION_SLOT_IPL_HANDLER(_devcb) \ + devcb = &exp_slot_device::set_ipl_handler(*device, DEVCB_##_devcb); + +// ======================> zorro 2 bus + +#define MCFG_ZORRO2_ADD(_cputag) \ + MCFG_DEVICE_ADD(ZORROBUS_TAG, ZORRO2, 0) \ + zorro_device::set_cputag(*device, _cputag); + +#define MCFG_ZORRO2_SLOT_ADD(_tag, _slot_intf, _def_slot) \ + MCFG_ZORRO_SLOT_ADD(ZORROBUS_TAG, _tag, _slot_intf, _def_slot) + +#define MCFG_ZORRO2_OVR_HANDLER(_devcb) \ + devcb = &zorro_device::set_ovr_handler(*device, DEVCB_##_devcb); + +#define MCFG_ZORRO2_INT2_HANDLER(_devcb) \ + devcb = &zorro_device::set_int2_handler(*device, DEVCB_##_devcb); + +#define MCFG_ZORRO2_INT6_HANDLER(_devcb) \ + devcb = &zorro_device::set_int6_handler(*device, DEVCB_##_devcb); + +#define MCFG_ZORRO2_EINT1_HANDLER(_devcb) \ + devcb = &zorro2_device::set_eint1_handler(*device, DEVCB_##_devcb); + +#define MCFG_ZORRO2_EINT4_HANDLER(_devcb) \ + devcb = &zorro2_device::set_eint4_handler(*device, DEVCB_##_devcb); + +#define MCFG_ZORRO2_EINT5_HANDLER(_devcb) \ + devcb = &zorro2_device::set_eint5_handler(*device, DEVCB_##_devcb); + +#define MCFG_ZORRO2_EINT7_HANDLER(_devcb) \ + devcb = &zorro2_device::set_eint7_handler(*device, DEVCB_##_devcb); + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// forward declaration of card interfaces +class device_zorro_card_interface; +class device_exp_card_interface; +class device_zorro2_card_interface; + +// ======================> zorro slot device + +class zorro_slot_device : public device_t, public device_slot_interface +{ +public: + // construction/destruction + zorro_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + zorro_slot_device(const machine_config &mconfig, device_type type, const char *name, + const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + // device-level overrides + virtual void device_start(); + + // inline configuration + static void set_zorro_slot(device_t &device, device_t *owner, const char *zorro_tag); + +protected: + // configuration + const char *m_zorro_tag; +}; + +// device type definition +extern const device_type ZORRO_SLOT; + +// ======================> base zorro bus device + +class zorro_device : public device_t +{ +public: + // construction/destruction + zorro_device(const machine_config &mconfig, device_type type, const char *name, + const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + // static configuration helpers + static void set_cputag(device_t &device, const char *tag); + + template static devcb_base &set_int2_handler(device_t &device, _Object object) + { return downcast(device).m_int2_handler.set_callback(object); } + template static devcb_base &set_int6_handler(device_t &device, _Object object) + { return downcast(device).m_int6_handler.set_callback(object); } + template static devcb_base &set_ovr_handler(device_t &device, _Object object) + { return downcast(device).m_ovr_handler.set_callback(object); } + + virtual void add_card(device_zorro_card_interface *card) = 0; + + // interface (from slot device) + virtual DECLARE_WRITE_LINE_MEMBER( cfgout_w ) {}; + + DECLARE_WRITE_LINE_MEMBER( int2_w ); + DECLARE_WRITE_LINE_MEMBER( int6_w ); + DECLARE_WRITE_LINE_MEMBER( ovr_w ); + + // interface (from host) + virtual void fc_w(int code) = 0; + + // access to the host space + address_space *m_space; + +protected: + // device-level overrides + virtual void device_start(); + +private: + const char *m_cputag; + + devcb_write_line m_ovr_handler; + devcb_write_line m_int2_handler; + devcb_write_line m_int6_handler; +}; + +// ======================> expansion slot device + +class exp_slot_device : public zorro_device +{ +public: + // construction/destruction + exp_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + exp_slot_device(const machine_config &mconfig, device_type type, const char *name, + const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + template static devcb_base &set_ipl_handler(device_t &device, _Object object) + { return downcast(device).m_ipl_handler.set_callback(object); } + + // the expansion slot can only have a single card + virtual void add_card(device_zorro_card_interface *card); + + // interface (from slot device) + void ipl_w(int interrupt); + + // interface (from host) + virtual void fc_w(int code); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + +private: + devcb_write8 m_ipl_handler; + + device_exp_card_interface *m_dev; +}; + +// device type definition +extern const device_type EXP_SLOT; + +// ======================> zorro2 slot device + +class zorro2_device : public zorro_device +{ +public: + // construction/destruction + zorro2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + zorro2_device(const machine_config &mconfig, device_type type, const char *name, + const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + ~zorro2_device(); + + template static devcb_base &set_eint1_handler(device_t &device, _Object object) + { return downcast(device).m_eint1_handler.set_callback(object); } + template static devcb_base &set_eint4_handler(device_t &device, _Object object) + { return downcast(device).m_eint4_handler.set_callback(object); } + template static devcb_base &set_eint5_handler(device_t &device, _Object object) + { return downcast(device).m_eint5_handler.set_callback(object); } + template static devcb_base &set_eint7_handler(device_t &device, _Object object) + { return downcast(device).m_eint7_handler.set_callback(object); } + + // the zorro2 bus supports multiple cards + virtual void add_card(device_zorro_card_interface *card); + + // interface (from slot device) + virtual DECLARE_WRITE_LINE_MEMBER( cfgout_w ); + + DECLARE_WRITE_LINE_MEMBER( eint1_w ); + DECLARE_WRITE_LINE_MEMBER( eint4_w ); + DECLARE_WRITE_LINE_MEMBER( eint5_w ); + DECLARE_WRITE_LINE_MEMBER( eint7_w ); + + // interface (from host) + virtual void fc_w(int code); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + +private: + devcb_write_line m_eint1_handler; + devcb_write_line m_eint4_handler; + devcb_write_line m_eint5_handler; + devcb_write_line m_eint7_handler; + + simple_list m_dev; + + // the device which is currently configuring + device_zorro2_card_interface *m_autoconfig_device; +}; + +// device type definition +extern const device_type ZORRO2; + + +// ======================> base zorro card interface + +class device_zorro_card_interface : public device_slot_card_interface +{ +public: + // construction/destruction + device_zorro_card_interface(const machine_config &mconfig, device_t &device); + virtual ~device_zorro_card_interface(); + + virtual void set_zorro_device() = 0; + + void set_zorro_bus(zorro_device *device); + + // interface (from device) + void cfgout_w(int state) { m_zorro->cfgout_w(state); } + + // interface (from host) + virtual void fc_w(int code); + virtual DECLARE_WRITE_LINE_MEMBER( cfgin_w ); + +protected: + zorro_device *m_zorro; +}; + +// ======================> expansion slot card interface + +class device_exp_card_interface : public device_zorro_card_interface +{ +public: + // construction/destruction + device_exp_card_interface(const machine_config &mconfig, device_t &device); + virtual ~device_exp_card_interface(); + + virtual void set_zorro_device(); + +protected: + exp_slot_device *m_slot; +}; + +// ======================> zorro2 card interface + +class device_zorro2_card_interface : public device_zorro_card_interface +{ +public: + // construction/destruction + device_zorro2_card_interface(const machine_config &mconfig, device_t &device); + virtual ~device_zorro2_card_interface(); + + virtual void set_zorro_device(); + + device_zorro2_card_interface *next() const { return m_next; } + device_zorro2_card_interface *m_next; + +protected: + zorro2_device *m_slot; +}; + + +// include this here so that you don't need to include it into every +// driver that uses zorro slots +#include "cards.h" + + +#endif // __ZORRO_H__ diff --git a/src/devices/bus/apf/rom.c b/src/devices/bus/apf/rom.c new file mode 100644 index 00000000000..9eb83e4f12c --- /dev/null +++ b/src/devices/bus/apf/rom.c @@ -0,0 +1,78 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + APF Imagination / M-1000 cart emulation + + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "rom.h" + + +//------------------------------------------------- +// apf_rom_device - constructor +//------------------------------------------------- + +const device_type APF_ROM_STD = &device_creator; +const device_type APF_ROM_BASIC = &device_creator; +const device_type APF_ROM_SPACEDST = &device_creator; + + +apf_rom_device::apf_rom_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_apf_cart_interface( mconfig, *this ) +{ +} + +apf_rom_device::apf_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, APF_ROM_STD, "APF Standard Carts", tag, owner, clock, "apf_rom", __FILE__), + device_apf_cart_interface( mconfig, *this ) +{ +} + +apf_basic_device::apf_basic_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : apf_rom_device(mconfig, APF_ROM_BASIC, "APF BASIC Carts", tag, owner, clock, "apf_basic", __FILE__) +{ +} + +apf_spacedst_device::apf_spacedst_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : apf_rom_device(mconfig, APF_ROM_SPACEDST, "APF Space Destroyer Cart", tag, owner, clock, "apf_spacedst", __FILE__) +{ +} + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +READ8_MEMBER(apf_rom_device::read_rom) +{ + if (offset < m_rom_size) + return m_rom[offset]; + else + return 0xff; +} + + +READ8_MEMBER(apf_basic_device::extra_rom) +{ + if (offset < (m_rom_size - 0x2000)) + return m_rom[offset + 0x2000]; + else + return 0xff; +} + + +READ8_MEMBER(apf_spacedst_device::read_ram) +{ + return m_ram[offset]; +} + +WRITE8_MEMBER(apf_spacedst_device::write_ram) +{ + m_ram[offset] = data; +} diff --git a/src/devices/bus/apf/rom.h b/src/devices/bus/apf/rom.h new file mode 100644 index 00000000000..7c377a0cc77 --- /dev/null +++ b/src/devices/bus/apf/rom.h @@ -0,0 +1,62 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __APF_ROM_H +#define __APF_ROM_H + +#include "slot.h" + + +// ======================> apf_rom_device + +class apf_rom_device : public device_t, + public device_apf_cart_interface +{ +public: + // construction/destruction + apf_rom_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + apf_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start() {} + virtual void device_reset() {} + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_rom); +}; + +// ======================> apf_basic_device + +class apf_basic_device : public apf_rom_device +{ +public: + // construction/destruction + apf_basic_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // reading and writing + virtual DECLARE_READ8_MEMBER(extra_rom); +}; + +// ======================> apf_spacedst_device + +class apf_spacedst_device : public apf_rom_device +{ +public: + // construction/destruction + apf_spacedst_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_ram); + virtual DECLARE_WRITE8_MEMBER(write_ram); +}; + + + + + +// device type definition +extern const device_type APF_ROM_STD; +extern const device_type APF_ROM_BASIC; +extern const device_type APF_ROM_SPACEDST; + + +#endif diff --git a/src/devices/bus/apf/slot.c b/src/devices/bus/apf/slot.c new file mode 100644 index 00000000000..832e0cead45 --- /dev/null +++ b/src/devices/bus/apf/slot.c @@ -0,0 +1,294 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + APF Imagination / M-1000 cart emulation + (through slot devices) + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "slot.h" + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type APF_CART_SLOT = &device_creator; + +//************************************************************************** +// APF Cartridges Interface +//************************************************************************** + +//------------------------------------------------- +// device_apf_cart_interface - constructor +//------------------------------------------------- + +device_apf_cart_interface::device_apf_cart_interface(const machine_config &mconfig, device_t &device) + : device_slot_card_interface(mconfig, device), + m_rom(NULL), + m_rom_size(0) +{ +} + + +//------------------------------------------------- +// ~device_apf_cart_interface - destructor +//------------------------------------------------- + +device_apf_cart_interface::~device_apf_cart_interface() +{ +} + +//------------------------------------------------- +// rom_alloc - alloc the space for the cart +//------------------------------------------------- + +void device_apf_cart_interface::rom_alloc(UINT32 size, const char *tag) +{ + if (m_rom == NULL) + { + m_rom = device().machine().memory().region_alloc(std::string(tag).append(APFSLOT_ROM_REGION_TAG).c_str(), size, 1, ENDIANNESS_LITTLE)->base(); + m_rom_size = size; + } +} + + +//------------------------------------------------- +// ram_alloc - alloc the space for the ram +//------------------------------------------------- + +void device_apf_cart_interface::ram_alloc(UINT32 size) +{ + m_ram.resize(size); +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// apf_cart_slot_device - constructor +//------------------------------------------------- +apf_cart_slot_device::apf_cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, APF_CART_SLOT, "APF Cartridge Slot", tag, owner, clock, "apf_cart_slot", __FILE__), + device_image_interface(mconfig, *this), + device_slot_interface(mconfig, *this), + m_type(APF_STD) +{ +} + + +//------------------------------------------------- +// apf_cart_slot_device - destructor +//------------------------------------------------- + +apf_cart_slot_device::~apf_cart_slot_device() +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void apf_cart_slot_device::device_start() +{ + m_cart = dynamic_cast(get_card_device()); +} + +//------------------------------------------------- +// device_config_complete - perform any +// operations now that the configuration is +// complete +//------------------------------------------------- + +void apf_cart_slot_device::device_config_complete() +{ + // set brief and instance name + update_names(); +} + + +//------------------------------------------------- +// APF PCB +//------------------------------------------------- + +struct apf_slot +{ + int pcb_id; + const char *slot_option; +}; + +// Here, we take the feature attribute from .xml (i.e. the PCB name) and we assign a unique ID to it +static const apf_slot slot_list[] = +{ + { APF_STD, "std" }, + { APF_BASIC, "basic" }, + { APF_SPACEDST, "spacedst" } +}; + +static int apf_get_pcb_id(const char *slot) +{ + for (int i = 0; i < ARRAY_LENGTH(slot_list); i++) + { + if (!core_stricmp(slot_list[i].slot_option, slot)) + return slot_list[i].pcb_id; + } + + return 0; +} + +static const char *apf_get_slot(int type) +{ + for (int i = 0; i < ARRAY_LENGTH(slot_list); i++) + { + if (slot_list[i].pcb_id == type) + return slot_list[i].slot_option; + } + + return "std"; +} + + +/*------------------------------------------------- + call load + -------------------------------------------------*/ + +bool apf_cart_slot_device::call_load() +{ + if (m_cart) + { + UINT32 size = (software_entry() == NULL) ? length() : get_software_region_length("rom"); + + if (size > 0x3800) + { + seterror(IMAGE_ERROR_UNSPECIFIED, "Image extends beyond the expected size for an APF cart"); + return IMAGE_INIT_FAIL; + } + + m_cart->rom_alloc(size, tag()); + + if (software_entry() == NULL) + fread(m_cart->get_rom_base(), size); + else + memcpy(m_cart->get_rom_base(), get_software_region("rom"), size); + + if (software_entry() == NULL) + { + m_type = APF_STD; + // attempt to identify Space Destroyer, which needs 1K of additional RAM + if (size == 0x1800) + { + m_type = APF_SPACEDST; + m_cart->ram_alloc(0x400); + } + if (size > 0x2000) + m_type = APF_BASIC; + } + else + { + const char *pcb_name = get_feature("slot"); + if (pcb_name) + m_type = apf_get_pcb_id(pcb_name); + + if (get_software_region("ram")) + m_cart->ram_alloc(get_software_region_length("ram")); + } + + //printf("Type: %s\n", apf_get_slot(m_type)); + + return IMAGE_INIT_PASS; + } + + return IMAGE_INIT_PASS; +} + + +/*------------------------------------------------- + call softlist load + -------------------------------------------------*/ + +bool apf_cart_slot_device::call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry) +{ + load_software_part_region(*this, swlist, swname, start_entry); + return TRUE; +} + + +/*------------------------------------------------- + get default card software + -------------------------------------------------*/ + +void apf_cart_slot_device::get_default_card_software(std::string &result) +{ + if (open_image_file(mconfig().options())) + { + const char *slot_string = "std"; + UINT32 size = core_fsize(m_file); + int type = APF_STD; + + // attempt to identify Space Destroyer, which needs 1K of additional RAM + if (size == 0x1800) + type = APF_SPACEDST; + if (size > 0x2000) + type = APF_BASIC; + + slot_string = apf_get_slot(type); + + //printf("type: %s\n", slot_string); + clear(); + + result.assign(slot_string); + return; + } + + software_get_default_slot(result, "std"); +} + +/*------------------------------------------------- + read + -------------------------------------------------*/ + +READ8_MEMBER(apf_cart_slot_device::read_rom) +{ + if (m_cart) + return m_cart->read_rom(space, offset); + else + return 0xff; +} + +/*------------------------------------------------- + read + -------------------------------------------------*/ + +READ8_MEMBER(apf_cart_slot_device::extra_rom) +{ + if (m_cart) + return m_cart->extra_rom(space, offset); + else + return 0xff; +} + +/*------------------------------------------------- + read + -------------------------------------------------*/ + +READ8_MEMBER(apf_cart_slot_device::read_ram) +{ + if (m_cart) + return m_cart->read_ram(space, offset); + else + return 0xff; +} + +/*------------------------------------------------- + write + -------------------------------------------------*/ + +WRITE8_MEMBER(apf_cart_slot_device::write_ram) +{ + if (m_cart) + m_cart->write_ram(space, offset, data); +} diff --git a/src/devices/bus/apf/slot.h b/src/devices/bus/apf/slot.h new file mode 100644 index 00000000000..73853dd6bdd --- /dev/null +++ b/src/devices/bus/apf/slot.h @@ -0,0 +1,116 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __APF_SLOT_H +#define __APF_SLOT_H + +/*************************************************************************** + TYPE DEFINITIONS + ***************************************************************************/ + + +/* PCB */ +enum +{ + APF_STD = 0, + APF_BASIC, + APF_SPACEDST +}; + + +// ======================> device_apf_cart_interface + +class device_apf_cart_interface : public device_slot_card_interface +{ +public: + // construction/destruction + device_apf_cart_interface(const machine_config &mconfig, device_t &device); + virtual ~device_apf_cart_interface(); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_rom) { return 0xff; } + virtual DECLARE_READ8_MEMBER(extra_rom) { return 0xff; } + virtual DECLARE_READ8_MEMBER(read_ram) { return 0xff; } + virtual DECLARE_WRITE8_MEMBER(write_ram) {} + + void rom_alloc(UINT32 size, const char *tag); + void ram_alloc(UINT32 size); + UINT8* get_rom_base() { return m_rom; } + UINT8* get_ram_base() { return &m_ram[0]; } + UINT32 get_rom_size() { return m_rom_size; } + UINT32 get_ram_size() { return m_ram.size(); } + + void save_ram() { device().save_item(NAME(m_ram)); } + +protected: + // internal state + UINT8 *m_rom; + UINT32 m_rom_size; + dynamic_buffer m_ram; +}; + + +// ======================> apf_cart_slot_device + +class apf_cart_slot_device : public device_t, + public device_image_interface, + public device_slot_interface +{ +public: + // construction/destruction + apf_cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual ~apf_cart_slot_device(); + + // device-level overrides + virtual void device_start(); + virtual void device_config_complete(); + + // image-level overrides + virtual bool call_load(); + virtual void call_unload() {} + virtual bool call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry); + + int get_type() { return m_type; } + + void save_ram() { if (m_cart && m_cart->get_ram_size()) m_cart->save_ram(); } + + virtual iodevice_t image_type() const { return IO_CARTSLOT; } + virtual bool is_readable() const { return 1; } + virtual bool is_writeable() const { return 0; } + virtual bool is_creatable() const { return 0; } + virtual bool must_be_loaded() const { return 0; } + virtual bool is_reset_on_load() const { return 1; } + virtual const option_guide *create_option_guide() const { return NULL; } + virtual const char *image_interface() const { return "apfm1000_cart"; } + virtual const char *file_extensions() const { return "bin"; } + + // slot interface overrides + virtual void get_default_card_software(std::string &result); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_rom); + virtual DECLARE_READ8_MEMBER(extra_rom); + virtual DECLARE_READ8_MEMBER(read_ram); + virtual DECLARE_WRITE8_MEMBER(write_ram); + +protected: + + int m_type; + device_apf_cart_interface* m_cart; +}; + + + +// device type definition +extern const device_type APF_CART_SLOT; + + +/*************************************************************************** + DEVICE CONFIGURATION MACROS + ***************************************************************************/ + +#define APFSLOT_ROM_REGION_TAG ":cart:rom" + +#define MCFG_APF_CARTRIDGE_ADD(_tag,_slot_intf,_def_slot) \ + MCFG_DEVICE_ADD(_tag, APF_CART_SLOT, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) +#endif diff --git a/src/devices/bus/apricot/cards.c b/src/devices/bus/apricot/cards.c new file mode 100644 index 00000000000..9a97adffca6 --- /dev/null +++ b/src/devices/bus/apricot/cards.c @@ -0,0 +1,15 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best +/*************************************************************************** + + ACT Apricot Expansion Slot Devices + +***************************************************************************/ + +#include "cards.h" + +SLOT_INTERFACE_START( apricot_expansion_cards ) + SLOT_INTERFACE("128k", APRICOT_128K_RAM) + SLOT_INTERFACE("256k", APRICOT_256K_RAM) + SLOT_INTERFACE("512k", APRICOT_512K_RAM) +SLOT_INTERFACE_END diff --git a/src/devices/bus/apricot/cards.h b/src/devices/bus/apricot/cards.h new file mode 100644 index 00000000000..67766d51a8e --- /dev/null +++ b/src/devices/bus/apricot/cards.h @@ -0,0 +1,19 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best +/*************************************************************************** + + ACT Apricot Expansion Slot Devices + +***************************************************************************/ + +#pragma once + +#ifndef __APRICOT_CARDS_H__ +#define __APRICOT_CARDS_H__ + +#include "emu.h" +#include "ram.h" + +SLOT_INTERFACE_EXTERN( apricot_expansion_cards ); + +#endif // __APRICOT_CARDS_H__ diff --git a/src/devices/bus/apricot/expansion.c b/src/devices/bus/apricot/expansion.c new file mode 100644 index 00000000000..7fe2b2a721c --- /dev/null +++ b/src/devices/bus/apricot/expansion.c @@ -0,0 +1,192 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best +/*************************************************************************** + + ACT Apricot Expansion Slot + +***************************************************************************/ + +#include "expansion.h" + + +//************************************************************************** +// EXPANSION SLOT DEVICE +//************************************************************************** + +const device_type APRICOT_EXPANSION_SLOT = &device_creator; + +//------------------------------------------------- +// apricot_expansion_slot_device - constructor +//------------------------------------------------- + +apricot_expansion_slot_device::apricot_expansion_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, APRICOT_EXPANSION_SLOT, "Apricot Expansion Slot", tag, owner, clock, "apricot_exp_slot", __FILE__), + device_slot_interface(mconfig, *this) +{ +} + +apricot_expansion_slot_device::apricot_expansion_slot_device(const machine_config &mconfig, device_type type, const char *name, + const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_slot_interface(mconfig, *this) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void apricot_expansion_slot_device::device_start() +{ + device_apricot_expansion_card_interface *dev = dynamic_cast(get_card_device()); + + if (dev) + { + apricot_expansion_bus_device *bus = downcast(m_owner); + bus->add_card(dev); + } +} + + +//************************************************************************** +// EXPANSION BUS DEVICE +//************************************************************************** + +const device_type APRICOT_EXPANSION_BUS = &device_creator; + +//------------------------------------------------- +// apricot_expansion_bus_device - constructor +//------------------------------------------------- + +apricot_expansion_bus_device::apricot_expansion_bus_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, APRICOT_EXPANSION_BUS, "Apricot Expansion Bus", tag, owner, clock, "apricot_exp_bus", __FILE__), + m_program(NULL), + m_io(NULL), + m_program_iop(NULL), + m_io_iop(NULL), + m_dma1_handler(*this), + m_dma2_handler(*this), + m_ext1_handler(*this), + m_ext2_handler(*this), + m_int2_handler(*this), + m_int3_handler(*this) +{ +} + +//------------------------------------------------- +// apricot_expansion_bus_device - destructor +//------------------------------------------------- + +apricot_expansion_bus_device::~apricot_expansion_bus_device() +{ + m_dev.detach_all(); +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void apricot_expansion_bus_device::device_start() +{ + // resolve callbacks + m_dma1_handler.resolve_safe(); + m_dma2_handler.resolve_safe(); + m_ext1_handler.resolve_safe(); + m_ext2_handler.resolve_safe(); + m_int2_handler.resolve_safe(); + m_int3_handler.resolve_safe(); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void apricot_expansion_bus_device::device_reset() +{ + cpu_device *cpu = m_owner->subdevice(m_cpu_tag); + m_program = &cpu->space(AS_PROGRAM); + m_io = &cpu->space(AS_IO); + + cpu_device *iop = m_owner->subdevice(m_iop_tag); + m_program_iop = &iop->space(AS_PROGRAM); + m_io_iop = &iop->space(AS_IO); +} + +//------------------------------------------------- +// add_card - add new card to our bus +//------------------------------------------------- + +void apricot_expansion_bus_device::add_card(device_apricot_expansion_card_interface *card) +{ + card->set_bus_device(this); + m_dev.append(*card); +} + +//------------------------------------------------- +// set_cpu_tag - set cpu we are attached to +//------------------------------------------------- + +void apricot_expansion_bus_device::set_cpu_tag(device_t &device, device_t *owner, const char *tag) +{ + apricot_expansion_bus_device &bus = dynamic_cast(device); + bus.m_cpu_tag = tag; +} + +//------------------------------------------------- +// set_iop_tag - set iop we are attached to +//------------------------------------------------- + +void apricot_expansion_bus_device::set_iop_tag(device_t &device, device_t *owner, const char *tag) +{ + apricot_expansion_bus_device &bus = dynamic_cast(device); + bus.m_iop_tag = tag; +} + +// callbacks from slot device to the host +WRITE_LINE_MEMBER( apricot_expansion_bus_device::dma1_w ) { m_dma1_handler(state); } +WRITE_LINE_MEMBER( apricot_expansion_bus_device::dma2_w ) { m_dma2_handler(state); } +WRITE_LINE_MEMBER( apricot_expansion_bus_device::ext1_w ) { m_ext1_handler(state); } +WRITE_LINE_MEMBER( apricot_expansion_bus_device::ext2_w ) { m_ext2_handler(state); } +WRITE_LINE_MEMBER( apricot_expansion_bus_device::int2_w ) { m_int2_handler(state); } +WRITE_LINE_MEMBER( apricot_expansion_bus_device::int3_w ) { m_int3_handler(state); } + +//------------------------------------------------- +// install_ram - attach ram to cpu/iop +//------------------------------------------------- + +void apricot_expansion_bus_device::install_ram(offs_t addrstart, offs_t addrend, void *baseptr) +{ + m_program->install_ram(addrstart, addrend, baseptr); + + if (m_program_iop) + m_program_iop->install_ram(addrstart, addrend, baseptr); +} + + +//************************************************************************** +// CARTRIDGE INTERFACE +//************************************************************************** + +//------------------------------------------------- +// device_apricot_expansion_card_interface - constructor +//------------------------------------------------- + +device_apricot_expansion_card_interface::device_apricot_expansion_card_interface(const machine_config &mconfig, device_t &device) : + device_slot_card_interface(mconfig, device), + m_next(NULL), + m_bus(NULL) +{ +} + +//------------------------------------------------- +// ~device_apricot_expansion_card_interface - destructor +//------------------------------------------------- + +device_apricot_expansion_card_interface::~device_apricot_expansion_card_interface() +{ +} + +void device_apricot_expansion_card_interface::set_bus_device(apricot_expansion_bus_device *bus) +{ + m_bus = bus; +} diff --git a/src/devices/bus/apricot/expansion.h b/src/devices/bus/apricot/expansion.h new file mode 100644 index 00000000000..38687db4399 --- /dev/null +++ b/src/devices/bus/apricot/expansion.h @@ -0,0 +1,208 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best +/*************************************************************************** + + ACT Apricot Expansion Slot + + A B + + -12V 32 +12V + +5V 31 +5V + DB0 30 DB1 + DB2 29 DB3 + DB4 28 DB5 + DB6 27 DB7 + AB10 26 AB9 + AB11 25 AB12 + /AMWC 24 /MRDC + /DMA2 23 DT/R + /DMA1 22 /IORC + /MWTC 21 /RES + /IOWC 20 /AIOWC + GND 19 GND + /CLK5 18 DEN + /IRDY 17 /MRDY + /EXT1 16 /EXT2 + /INT3 15 /ALE + AB6 14 /INT2 + AB8 13 AB7 + DB9 12 DB8 + DB11 11 DB10 + DB13 10 DB12 + DB15 9 DB14 + AB2 8 AB1 + AB4 7 AB3 + AB0 6 AB5 + AB14 5 AB13 + AB15 4 AB16 + AB17 3 AB18 + AB19 2 /BHE + NMI 1 CLK15 + +***************************************************************************/ + +#pragma once + +#ifndef __APRICOT_EXPANSION_H__ +#define __APRICOT_EXPANSION_H__ + +#include "emu.h" + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_EXPANSION_ADD(_tag, _cpu_tag) \ + MCFG_DEVICE_ADD(_tag, APRICOT_EXPANSION_BUS, 0) \ + apricot_expansion_bus_device::set_cpu_tag(*device, owner, _cpu_tag); + +#define MCFG_EXPANSION_IOP_ADD(_tag) \ + apricot_expansion_bus_device::set_iop_tag(*device, owner, _tag); + +#define MCFG_EXPANSION_SLOT_ADD(_tag, _slot_intf, _def_slot) \ + MCFG_DEVICE_ADD(_tag, APRICOT_EXPANSION_SLOT, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) + +#define MCFG_EXPANSION_DMA1_HANDLER(_devcb) \ + devcb = &apricot_expansion_bus_device::set_dma1_handler(*device, DEVCB_##_devcb); + +#define MCFG_EXPANSION_DMA2_HANDLER(_devcb) \ + devcb = &apricot_expansion_bus_device::set_dma2_handler(*device, DEVCB_##_devcb); + +#define MCFG_EXPANSION_EXT1_HANDLER(_devcb) \ + devcb = &apricot_expansion_bus_device::set_ext1_handler(*device, DEVCB_##_devcb); + +#define MCFG_EXPANSION_EXT2_HANDLER(_devcb) \ + devcb = &apricot_expansion_bus_device::set_ext2_handler(*device, DEVCB_##_devcb); + +#define MCFG_EXPANSION_INT2_HANDLER(_devcb) \ + devcb = &apricot_expansion_bus_device::set_int2_handler(*device, DEVCB_##_devcb); + +#define MCFG_EXPANSION_INT3_HANDLER(_devcb) \ + devcb = &apricot_expansion_bus_device::set_int3_handler(*device, DEVCB_##_devcb); + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// forward declaration +class device_apricot_expansion_card_interface; + + +// ======================> apricot_expansion_slot_device + +class apricot_expansion_slot_device : public device_t, public device_slot_interface +{ +public: + // construction/destruction + apricot_expansion_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + apricot_expansion_slot_device(const machine_config &mconfig, device_type type, const char *name, + const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + // device-level overrides + virtual void device_start(); +}; + +// device type definition +extern const device_type APRICOT_EXPANSION_SLOT; + + +// ======================> apricot_expansion_bus_device + +class apricot_expansion_bus_device : public device_t +{ +public: + // construction/destruction + apricot_expansion_bus_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual ~apricot_expansion_bus_device(); + + template static devcb_base &set_dma1_handler(device_t &device, _Object object) + { return downcast(device).m_dma1_handler.set_callback(object); } + + template static devcb_base &set_dma2_handler(device_t &device, _Object object) + { return downcast(device).m_dma2_handler.set_callback(object); } + + template static devcb_base &set_ext1_handler(device_t &device, _Object object) + { return downcast(device).m_ext1_handler.set_callback(object); } + + template static devcb_base &set_ext2_handler(device_t &device, _Object object) + { return downcast(device).m_ext2_handler.set_callback(object); } + + template static devcb_base &set_int2_handler(device_t &device, _Object object) + { return downcast(device).m_int2_handler.set_callback(object); } + + template static devcb_base &set_int3_handler(device_t &device, _Object object) + { return downcast(device).m_int3_handler.set_callback(object); } + + // inline configuration + static void set_cpu_tag(device_t &device, device_t *owner, const char *tag); + static void set_iop_tag(device_t &device, device_t *owner, const char *tag); + + void add_card(device_apricot_expansion_card_interface *card); + + // from cards + DECLARE_WRITE_LINE_MEMBER( dma1_w ); + DECLARE_WRITE_LINE_MEMBER( dma2_w ); + DECLARE_WRITE_LINE_MEMBER( ext1_w ); + DECLARE_WRITE_LINE_MEMBER( ext2_w ); + DECLARE_WRITE_LINE_MEMBER( int2_w ); + DECLARE_WRITE_LINE_MEMBER( int3_w ); + + void install_ram(offs_t addrstart, offs_t addrend, void *baseptr); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + +private: + simple_list m_dev; + + // address spaces we have access to + address_space *m_program; + address_space *m_io; + address_space *m_program_iop; + address_space *m_io_iop; + + devcb_write_line m_dma1_handler; + devcb_write_line m_dma2_handler; + devcb_write_line m_ext1_handler; + devcb_write_line m_ext2_handler; + devcb_write_line m_int2_handler; + devcb_write_line m_int3_handler; + + // configuration + const char *m_cpu_tag; + const char *m_iop_tag; +}; + +// device type definition +extern const device_type APRICOT_EXPANSION_BUS; + + +// ======================> device_apricot_expansion_card_interface + +class device_apricot_expansion_card_interface : public device_slot_card_interface +{ +public: + // construction/destruction + device_apricot_expansion_card_interface(const machine_config &mconfig, device_t &device); + virtual ~device_apricot_expansion_card_interface(); + + void set_bus_device(apricot_expansion_bus_device *bus); + + device_apricot_expansion_card_interface *next() const { return m_next; } + device_apricot_expansion_card_interface *m_next; + +protected: + apricot_expansion_bus_device *m_bus; +}; + + +// include here so drivers don't need to +#include "cards.h" + + +#endif // __APRICOT_EXPANSION_H__ diff --git a/src/devices/bus/apricot/ram.c b/src/devices/bus/apricot/ram.c new file mode 100644 index 00000000000..2221ae37227 --- /dev/null +++ b/src/devices/bus/apricot/ram.c @@ -0,0 +1,177 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best +/*************************************************************************** + + ACT Apricot RAM Expansions + +***************************************************************************/ + +#include "ram.h" + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type APRICOT_256K_RAM = &device_creator; +const device_type APRICOT_128K_RAM = &device_creator; +const device_type APRICOT_512K_RAM = &device_creator; + + +//************************************************************************** +// APRICOT 256K RAM DEVICE +//************************************************************************** + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +static INPUT_PORTS_START( apricot_256k ) + PORT_START("sw") + PORT_DIPNAME(0x01, 0x00, "Base Address") + PORT_DIPSETTING(0x00, "40000H") + PORT_DIPSETTING(0x01, "80000H") +INPUT_PORTS_END + +ioport_constructor apricot_256k_ram_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( apricot_256k ); +} + +//------------------------------------------------- +// apricot_256k_ram_device - constructor +//------------------------------------------------- + +apricot_256k_ram_device::apricot_256k_ram_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, APRICOT_256K_RAM, "Apricot 256K RAM Expansion Board", tag, owner, clock, "apricot_256k_ram", __FILE__), + device_apricot_expansion_card_interface(mconfig, *this), + m_sw(*this, "sw") +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void apricot_256k_ram_device::device_start() +{ + m_ram.resize(0x40000 / 2); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void apricot_256k_ram_device::device_reset() +{ + if (m_sw->read() == 0) + m_bus->install_ram(0x40000, 0x7ffff, &m_ram[0]); + else + m_bus->install_ram(0x80000, 0xbffff, &m_ram[0]); +} + + +//************************************************************************** +// APRICOT 128K RAM DEVICE +//************************************************************************** + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +static INPUT_PORTS_START( apricot_128k ) + PORT_START("strap") + PORT_DIPNAME(0x03, 0x01, "Base Address") + PORT_DIPSETTING(0x00, "512K") + PORT_DIPSETTING(0x01, "256K - 384K") + PORT_DIPSETTING(0x02, "384K - 512K") +INPUT_PORTS_END + +ioport_constructor apricot_128k_ram_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( apricot_128k ); +} + +//------------------------------------------------- +// apricot_128_512k_ram_device - constructor +//------------------------------------------------- + +apricot_128k_ram_device::apricot_128k_ram_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, APRICOT_128K_RAM, "Apricot 128/512K RAM Expansion Board (128K)", tag, owner, clock, "apricot_128k_ram", __FILE__), + device_apricot_expansion_card_interface(mconfig, *this), + m_strap(*this, "strap") +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void apricot_128k_ram_device::device_start() +{ + m_ram.resize(0x20000 / 2); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void apricot_128k_ram_device::device_reset() +{ + if (m_strap->read() == 1) + m_bus->install_ram(0x40000, 0x5ffff, &m_ram[0]); + else if (m_strap->read() == 2) + m_bus->install_ram(0x60000, 0x7ffff, &m_ram[0]); +} + + +//************************************************************************** +// APRICOT 512K RAM DEVICE +//************************************************************************** + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +static INPUT_PORTS_START( apricot_512k ) + PORT_START("strap") + PORT_DIPNAME(0x03, 0x00, "Base Address") + PORT_DIPSETTING(0x00, "512K") + PORT_DIPSETTING(0x01, "256K - 384K") + PORT_DIPSETTING(0x02, "384K - 512K") +INPUT_PORTS_END + +ioport_constructor apricot_512k_ram_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( apricot_512k ); +} + +//------------------------------------------------- +// apricot_128_512k_ram_device - constructor +//------------------------------------------------- + +apricot_512k_ram_device::apricot_512k_ram_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, APRICOT_512K_RAM, "Apricot 128/512K RAM Expansion Board (512K)", tag, owner, clock, "apricot_512k_ram", __FILE__), + device_apricot_expansion_card_interface(mconfig, *this), + m_strap(*this, "strap") +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void apricot_512k_ram_device::device_start() +{ + m_ram.resize(0x80000 / 2); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void apricot_512k_ram_device::device_reset() +{ + if (m_strap->read() == 0) + m_bus->install_ram(0x40000, 0xbffff, &m_ram[0]); +} diff --git a/src/devices/bus/apricot/ram.h b/src/devices/bus/apricot/ram.h new file mode 100644 index 00000000000..20ac01f2867 --- /dev/null +++ b/src/devices/bus/apricot/ram.h @@ -0,0 +1,89 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best +/*************************************************************************** + + ACT Apricot RAM Expansions + +***************************************************************************/ + +#pragma once + +#ifndef __APRICOT_RAM__ +#define __APRICOT_RAM__ + +#include "emu.h" +#include "expansion.h" + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + + +// ======================> apricot_256k_ram_device + +class apricot_256k_ram_device : public device_t, public device_apricot_expansion_card_interface +{ +public: + // construction/destruction + apricot_256k_ram_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual ioport_constructor device_input_ports() const; + virtual void device_start(); + virtual void device_reset(); + +private: + required_ioport m_sw; + + std::vector m_ram; +}; + + +// ======================> apricot_128k_ram_device + +class apricot_128k_ram_device : public device_t, public device_apricot_expansion_card_interface +{ +public: + // construction/destruction + apricot_128k_ram_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual ioport_constructor device_input_ports() const; + virtual void device_start(); + virtual void device_reset(); + +private: + required_ioport m_strap; + + std::vector m_ram; +}; + + +// ======================> apricot_512k_ram_device + +class apricot_512k_ram_device : public device_t, public device_apricot_expansion_card_interface +{ +public: + // construction/destruction + apricot_512k_ram_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual ioport_constructor device_input_ports() const; + virtual void device_start(); + virtual void device_reset(); + +private: + required_ioport m_strap; + + std::vector m_ram; +}; + + +// device type definition +extern const device_type APRICOT_256K_RAM; +extern const device_type APRICOT_128K_RAM; +extern const device_type APRICOT_512K_RAM; + + +#endif // __APRICOT_RAM__ diff --git a/src/devices/bus/arcadia/rom.c b/src/devices/bus/arcadia/rom.c new file mode 100644 index 00000000000..5a6186aa8de --- /dev/null +++ b/src/devices/bus/arcadia/rom.c @@ -0,0 +1,62 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + Emerson Arcadia 2001 cart emulation + + Golf carts have the "extra_rom" handler installed at $4000 instead of $2000 + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "rom.h" + + +//------------------------------------------------- +// arcadia_rom_device - constructor +//------------------------------------------------- + +const device_type ARCADIA_ROM_STD = &device_creator; +const device_type ARCADIA_ROM_GOLF = &device_creator; + + +arcadia_rom_device::arcadia_rom_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_arcadia_cart_interface( mconfig, *this ) +{ +} + +arcadia_rom_device::arcadia_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, ARCADIA_ROM_STD, "Emerson Arcadia Standard Carts", tag, owner, clock, "arcadia_rom", __FILE__), + device_arcadia_cart_interface( mconfig, *this ) +{ +} + +arcadia_golf_device::arcadia_golf_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : arcadia_rom_device(mconfig, ARCADIA_ROM_GOLF, "Emerson Arcadia Golf Cart", tag, owner, clock, "arcadia_golf", __FILE__) +{ +} + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +READ8_MEMBER(arcadia_rom_device::read_rom) +{ + if (offset < m_rom_size) + return m_rom[offset]; + else + return 0xff; +} + + +READ8_MEMBER(arcadia_rom_device::extra_rom) +{ + if (offset + 0x1000 < m_rom_size) + return m_rom[offset + 0x1000]; + else + return 0xff; +} diff --git a/src/devices/bus/arcadia/rom.h b/src/devices/bus/arcadia/rom.h new file mode 100644 index 00000000000..f070ac3aecd --- /dev/null +++ b/src/devices/bus/arcadia/rom.h @@ -0,0 +1,44 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __ARCADIA_ROM_H +#define __ARCADIA_ROM_H + +#include "slot.h" + + +// ======================> arcadia_rom_device + +class arcadia_rom_device : public device_t, + public device_arcadia_cart_interface +{ +public: + // construction/destruction + arcadia_rom_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + arcadia_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start() {} + virtual void device_reset() {} + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_rom); + virtual DECLARE_READ8_MEMBER(extra_rom); +}; + +// ======================> arcadia_golf_device + +class arcadia_golf_device : public arcadia_rom_device +{ +public: + // construction/destruction + arcadia_golf_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + + + +// device type definition +extern const device_type ARCADIA_ROM_STD; +extern const device_type ARCADIA_ROM_GOLF; + +#endif diff --git a/src/devices/bus/arcadia/slot.c b/src/devices/bus/arcadia/slot.c new file mode 100644 index 00000000000..b93e7fd211c --- /dev/null +++ b/src/devices/bus/arcadia/slot.c @@ -0,0 +1,260 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + Emerson Arcadia 2001 (and clones) cart emulation + (through slot devices) + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "slot.h" + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type EA2001_CART_SLOT = &device_creator; + +//************************************************************************** +// ARCADIA Cartridges Interface +//************************************************************************** + +//------------------------------------------------- +// device_arcadia_cart_interface - constructor +//------------------------------------------------- + +device_arcadia_cart_interface::device_arcadia_cart_interface(const machine_config &mconfig, device_t &device) + : device_slot_card_interface(mconfig, device), + m_rom(NULL), + m_rom_size(0) +{ +} + + +//------------------------------------------------- +// ~device_arcadia_cart_interface - destructor +//------------------------------------------------- + +device_arcadia_cart_interface::~device_arcadia_cart_interface() +{ +} + +//------------------------------------------------- +// rom_alloc - alloc the space for the cart +//------------------------------------------------- + +void device_arcadia_cart_interface::rom_alloc(UINT32 size, const char *tag) +{ + if (m_rom == NULL) + { + m_rom = device().machine().memory().region_alloc(std::string(tag).append(EA2001SLOT_ROM_REGION_TAG).c_str(), size, 1, ENDIANNESS_LITTLE)->base(); + m_rom_size = size; + } +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// arcadia_cart_slot_device - constructor +//------------------------------------------------- +arcadia_cart_slot_device::arcadia_cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, EA2001_CART_SLOT, "Emerson Arcadia Cartridge Slot", tag, owner, clock, "arcadia_cart_slot", __FILE__), + device_image_interface(mconfig, *this), + device_slot_interface(mconfig, *this), + m_type(ARCADIA_STD) +{ +} + + +//------------------------------------------------- +// arcadia_cart_slot_device - destructor +//------------------------------------------------- + +arcadia_cart_slot_device::~arcadia_cart_slot_device() +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void arcadia_cart_slot_device::device_start() +{ + m_cart = dynamic_cast(get_card_device()); +} + +//------------------------------------------------- +// device_config_complete - perform any +// operations now that the configuration is +// complete +//------------------------------------------------- + +void arcadia_cart_slot_device::device_config_complete() +{ + // set brief and instance name + update_names(); +} + + +//------------------------------------------------- +// ARCADIA PCB +//------------------------------------------------- + +struct arcadia_slot +{ + int pcb_id; + const char *slot_option; +}; + +// Here, we take the feature attribute from .xml (i.e. the PCB name) and we assign a unique ID to it +static const arcadia_slot slot_list[] = +{ + { ARCADIA_STD, "std" }, + { ARCADIA_GOLF, "golf" } +}; + +static int arcadia_get_pcb_id(const char *slot) +{ + for (int i = 0; i < ARRAY_LENGTH(slot_list); i++) + { + if (!core_stricmp(slot_list[i].slot_option, slot)) + return slot_list[i].pcb_id; + } + + return 0; +} + +#if 0 +static const char *arcadia_get_slot(int type) +{ + for (int i = 0; i < ARRAY_LENGTH(slot_list); i++) + { + if (slot_list[i].pcb_id == type) + return slot_list[i].slot_option; + } + + return "std"; +} +#endif + +/*------------------------------------------------- + call load + -------------------------------------------------*/ + +bool arcadia_cart_slot_device::call_load() +{ + if (m_cart) + { + UINT32 len = (software_entry() == NULL) ? length() : get_software_region_length("rom"); + + m_cart->rom_alloc(len, tag()); + + if (software_entry() == NULL) + fread(m_cart->get_rom_base(), len); + else + memcpy(m_cart->get_rom_base(), get_software_region("rom"), len); + + if (software_entry() == NULL) + { + // we need to identify Golf! + m_type = ARCADIA_STD; + + +// the patch below is kept in case it could be used to identify golf cart from fullpath +#if 0 + // this is a testpatch for the golf cartridge + // so to make it work on a standard arcadia 2001 + // cart (i.e. mapping the hi 2K to $2000) + // not enough yet (some pointers stored as data?) + patch[]= { + // addr, orig. value, patched value + { 0x0077, 0x40, 0x20 }, + { 0x011e, 0x40, 0x20 }, + { 0x0348, 0x40, 0x20 }, + { 0x03be, 0x40, 0x20 }, + { 0x04ce, 0x40, 0x20 }, + { 0x04da, 0x40, 0x20 }, + { 0x0562, 0x42, 0x22 }, + { 0x0617, 0x40, 0x20 }, + { 0x0822, 0x40, 0x20 }, + { 0x095e, 0x42, 0x22 }, + { 0x09d3, 0x42, 0x22 }, + { 0x0bb0, 0x42, 0x22 }, + { 0x0efb, 0x40, 0x20 }, + { 0x0ec1, 0x43, 0x23 }, + { 0x0f00, 0x40, 0x20 }, + { 0x0f12, 0x40, 0x20 }, + { 0x0ff5, 0x43, 0x23 }, + { 0x0ff7, 0x41, 0x21 }, + { 0x0ff9, 0x40, 0x20 }, + { 0x0ffb, 0x41, 0x21 }, + { 0x20ec, 0x42, 0x22 } + }; +#endif + + } + else + { + const char *pcb_name = get_feature("slot"); + if (pcb_name) + m_type = arcadia_get_pcb_id(pcb_name); + } + + //printf("Type: %s\n", arcadia_get_slot(m_type)); + + return IMAGE_INIT_PASS; + } + + return IMAGE_INIT_PASS; +} + + +/*------------------------------------------------- + call softlist load + -------------------------------------------------*/ + +bool arcadia_cart_slot_device::call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry) +{ + load_software_part_region(*this, swlist, swname, start_entry); + return TRUE; +} + + + +/*------------------------------------------------- + get default card software + -------------------------------------------------*/ + +void arcadia_cart_slot_device::get_default_card_software(std::string &result) +{ + software_get_default_slot(result, "std"); +} + +/*------------------------------------------------- + read + -------------------------------------------------*/ + +READ8_MEMBER(arcadia_cart_slot_device::read_rom) +{ + if (m_cart) + return m_cart->read_rom(space, offset); + else + return 0xff; +} + +/*------------------------------------------------- + write + -------------------------------------------------*/ + +READ8_MEMBER(arcadia_cart_slot_device::extra_rom) +{ + if (m_cart) + return m_cart->extra_rom(space, offset); + else + return 0xff; +} diff --git a/src/devices/bus/arcadia/slot.h b/src/devices/bus/arcadia/slot.h new file mode 100644 index 00000000000..f1f3ca97f07 --- /dev/null +++ b/src/devices/bus/arcadia/slot.h @@ -0,0 +1,103 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __ARCADIA_SLOT_H +#define __ARCADIA_SLOT_H + +/*************************************************************************** + TYPE DEFINITIONS + ***************************************************************************/ + + +/* PCB */ +enum +{ + ARCADIA_STD = 0, + ARCADIA_GOLF +}; + + +// ======================> device_arcadia_cart_interface + +class device_arcadia_cart_interface : public device_slot_card_interface +{ +public: + // construction/destruction + device_arcadia_cart_interface(const machine_config &mconfig, device_t &device); + virtual ~device_arcadia_cart_interface(); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_rom) { return 0xff; } + virtual DECLARE_READ8_MEMBER(extra_rom) { return 0xff; } + + void rom_alloc(UINT32 size, const char *tag); + UINT8* get_rom_base() { return m_rom; } + UINT32 get_rom_size() { return m_rom_size; } + +protected: + // internal state + UINT8 *m_rom; + UINT32 m_rom_size; +}; + + +// ======================> arcadia_cart_slot_device + +class arcadia_cart_slot_device : public device_t, + public device_image_interface, + public device_slot_interface +{ +public: + // construction/destruction + arcadia_cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual ~arcadia_cart_slot_device(); + + // device-level overrides + virtual void device_start(); + virtual void device_config_complete(); + + // image-level overrides + virtual bool call_load(); + virtual void call_unload() {} + virtual bool call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry); + + int get_type() { return m_type; } + + virtual iodevice_t image_type() const { return IO_CARTSLOT; } + virtual bool is_readable() const { return 1; } + virtual bool is_writeable() const { return 0; } + virtual bool is_creatable() const { return 0; } + virtual bool must_be_loaded() const { return 1; } + virtual bool is_reset_on_load() const { return 1; } + virtual const option_guide *create_option_guide() const { return NULL; } + virtual const char *image_interface() const { return "arcadia_cart"; } + virtual const char *file_extensions() const { return "bin"; } + + // slot interface overrides + virtual void get_default_card_software(std::string &result); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_rom); + virtual DECLARE_READ8_MEMBER(extra_rom); + +protected: + + int m_type; + device_arcadia_cart_interface* m_cart; +}; + + + +// device type definition +extern const device_type EA2001_CART_SLOT; + + +/*************************************************************************** + DEVICE CONFIGURATION MACROS + ***************************************************************************/ + +#define EA2001SLOT_ROM_REGION_TAG ":cart:rom" + +#define MCFG_ARCADIA_CARTRIDGE_ADD(_tag,_slot_intf,_def_slot) \ + MCFG_DEVICE_ADD(_tag, EA2001_CART_SLOT, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) +#endif diff --git a/src/devices/bus/astrocde/exp.c b/src/devices/bus/astrocde/exp.c new file mode 100644 index 00000000000..28017230f0d --- /dev/null +++ b/src/devices/bus/astrocde/exp.c @@ -0,0 +1,85 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + Bally Astrocade Expansion port + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "exp.h" + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type ASTROCADE_EXP_SLOT = &device_creator; + + +device_astrocade_card_interface::device_astrocade_card_interface(const machine_config &mconfig, device_t &device) + : device_slot_card_interface(mconfig, device) +{ +} + + +device_astrocade_card_interface::~device_astrocade_card_interface() +{ +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// astrocade_exp_device - constructor +//------------------------------------------------- +astrocade_exp_device::astrocade_exp_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, ASTROCADE_EXP_SLOT, "Bally Astrocade expansion", tag, owner, clock, "astrocde_exp", __FILE__), + device_slot_interface(mconfig, *this), + m_card_mounted(false) +{ +} + + +//------------------------------------------------- +// astrocade_exp_device - destructor +//------------------------------------------------- + +astrocade_exp_device::~astrocade_exp_device() +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void astrocade_exp_device::device_start() +{ + m_card = dynamic_cast(get_card_device()); + if (m_card) + m_card_mounted = true; +} + +/*------------------------------------------------- + read + -------------------------------------------------*/ + +READ8_MEMBER(astrocade_exp_device::read) +{ + if (m_card) + return m_card->read(space, offset); + else + return 0xff; +} + +/*------------------------------------------------- + write + -------------------------------------------------*/ + +WRITE8_MEMBER(astrocade_exp_device::write) +{ + if (m_card) + m_card->write(space, offset, data); +} diff --git a/src/devices/bus/astrocde/exp.h b/src/devices/bus/astrocde/exp.h new file mode 100644 index 00000000000..e691a5b946a --- /dev/null +++ b/src/devices/bus/astrocde/exp.h @@ -0,0 +1,57 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __ASTROCADE_EXP_H +#define __ASTROCADE_EXP_H + +// ======================> device_astrocade_card_interface + +class device_astrocade_card_interface : public device_slot_card_interface +{ +public: + // construction/destruction + device_astrocade_card_interface(const machine_config &mconfig, device_t &device); + virtual ~device_astrocade_card_interface(); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read) { return 0xff; } + virtual DECLARE_WRITE8_MEMBER(write) {} + +protected: +}; + + +// ======================> astrocade_exp_device + +class astrocade_exp_device : public device_t, + public device_slot_interface +{ +public: + // construction/destruction + astrocade_exp_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual ~astrocade_exp_device(); + + // device-level overrides + virtual void device_start(); + + bool get_card_mounted() { return m_card_mounted; } + + // reading and writing + virtual DECLARE_READ8_MEMBER(read); + virtual DECLARE_WRITE8_MEMBER(write); + +protected: + bool m_card_mounted; + device_astrocade_card_interface* m_card; +}; + + + +// device type definition +extern const device_type ASTROCADE_EXP_SLOT; + + +#define MCFG_ASTROCADE_EXPANSION_SLOT_ADD(_tag, _slot_intf, _def_slot) \ + MCFG_DEVICE_ADD(_tag, ASTROCADE_EXP_SLOT, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) + +#endif diff --git a/src/devices/bus/astrocde/ram.c b/src/devices/bus/astrocde/ram.c new file mode 100644 index 00000000000..95ebb6816aa --- /dev/null +++ b/src/devices/bus/astrocde/ram.c @@ -0,0 +1,211 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + Bally Astrocade RAM expansion emulation + + RAM Expansions (info below courtesy of Paul Thacker) + + Several third party RAM expansions have been made for the Astrocade. These + allow access to various ranges of the expansion memory ($5000 to $FFFF). + A RAM expansion is required to use extended BASIC programs like Blue RAM BASIC + and VIPERSoft BASIC. All of the expansions also have a RAM protect switch, which + can be flipped at any time to make the RAM act like ROM. Extended BASIC + programs need access to the RAM and won't work with RAM protect enabled, but + this can be useful with Bally and Astrocade BASIC. They also have a range switch + (not implemented). The default position is 6K, but it can be switched to + 2K. This means that the expanded memory starting at $6000 will instead be + mapped to the cartridge memory starting at $2000. So it would be possible to + load a cartridge program from tape into the expansion memory, then flip the range + switch and run it as a cartridge. This is useful for cartridge development. + + Blue RAM -- available in 4K, 16K, and 32K. These also use an INS8154 chip, + (not yet implemented) which has an additional $80 bytes of RAM mapped + immediately after the end of the expansion address space. This memory + can't be write protected. The INS8154 has I/O features needed for loading + tape programs into Blue RAM BASIC, as well as running the Blue RAM Utility cart. + 4K: $6000 to $6FFF (can't run VIPERSoft BASIC, because this program needs memory + past this range) + 16K: $6000 to $9FFF + 32K: $6000 to $DFFF + + VIPER System 1 -- This is available in 16K only. It also includes a keyboard (not implemented). + 16K: $6000 to $9FFF + + Lil' WHITE RAM -- This is available in 32K only. Attempts to read and write + to memory outside of its address range ($D000 to $FFFF) are mapped to the expansion + memory $5000 to $7FFF. The current implementation won't allow the shadow RAM area + to be accessed when RAM protect is on, but there is no known software that will + access the upper range of the expansion RAM when RAM protect is enabled. + 32K: $5000 to $CFFF + + R&L 64K RAM Board -- This is a highly configurable kit. RAM can be installed in + 2K increments. So, the entire 44K expansion memory can be filled. It is also + possible to override the rest of the memory map with RAM (not implemented). + There are 32 switches allowing users to activate and deactivate each 2K block (not implemented). + RAM write protection can be implemented in three ranges through jumpers or by + installing switches. The ranges are $0000 to $0FFF (first 4K), $0000 to $3FFF (first 16K), + and $0000 to $FFFF (all 64K). The current implementation is for 44K expansion memory mapped from + $5000 to $FFFF, with only a single write protect covering this entire range. + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "ram.h" + + +//------------------------------------------------- +// astrocade_rom_device - constructor +//------------------------------------------------- + +const device_type ASTROCADE_BLUERAM_4K = &device_creator; +const device_type ASTROCADE_BLUERAM_16K = &device_creator; +const device_type ASTROCADE_BLUERAM_32K = &device_creator; +const device_type ASTROCADE_VIPER_SYS1 = &device_creator; +const device_type ASTROCADE_WHITERAM = &device_creator; +const device_type ASTROCADE_RL64RAM = &device_creator; + + +astrocade_blueram_4k_device::astrocade_blueram_4k_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_astrocade_card_interface(mconfig, *this), + m_write_prot(*this, "RAM_PROTECT") +{ +} + +astrocade_blueram_4k_device::astrocade_blueram_4k_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, ASTROCADE_BLUERAM_4K, "Bally Astrocade Blue RAM 4K", tag, owner, clock, "astrocade_br4", __FILE__), + device_astrocade_card_interface(mconfig, *this), + m_write_prot(*this, "RAM_PROTECT") +{ +} + +astrocade_blueram_16k_device::astrocade_blueram_16k_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : astrocade_blueram_4k_device(mconfig, ASTROCADE_BLUERAM_16K, "Bally Astrocade Blue RAM 16K", tag, owner, clock, "astrocade_br16", __FILE__) +{ +} + +astrocade_blueram_32k_device::astrocade_blueram_32k_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : astrocade_blueram_4k_device(mconfig, ASTROCADE_BLUERAM_32K, "Bally Astrocade Blue RAM 32K", tag, owner, clock, "astrocade_br32", __FILE__) +{ +} + +astrocade_viper_sys1_device::astrocade_viper_sys1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, ASTROCADE_VIPER_SYS1, "Bally Astrocade Viper System 1", tag, owner, clock, "astrocade_vs1", __FILE__), + device_astrocade_card_interface(mconfig, *this), + m_write_prot(*this, "RAM_PROTECT") +{ +} + +astrocade_whiteram_device::astrocade_whiteram_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, ASTROCADE_WHITERAM, "Bally Astrocade Lil' White RAM 32K", tag, owner, clock, "astrocade_lwr", __FILE__), + device_astrocade_card_interface(mconfig, *this), + m_write_prot(*this, "RAM_PROTECT") +{ +} + +astrocade_rl64ram_device::astrocade_rl64ram_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, ASTROCADE_RL64RAM, "Bally Astrocade R&L RAM 64K", tag, owner, clock, "astrocade_rl64", __FILE__), + device_astrocade_card_interface(mconfig, *this), + m_write_prot(*this, "RAM_PROTECT") +{ +} + + +//------------------------------------------------- +// RAM Write protect switch +//------------------------------------------------- + +static INPUT_PORTS_START( exp_switches ) + PORT_START("RAM_PROTECT") + PORT_CONFNAME( 0x01, 0x00, "Write Protect RAM") + PORT_CONFSETTING( 0x00, DEF_STR(Off)) + PORT_CONFSETTING( 0x01, DEF_STR(On)) +INPUT_PORTS_END + + +ioport_constructor astrocade_blueram_4k_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( exp_switches ); +} + +ioport_constructor astrocade_viper_sys1_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( exp_switches ); +} + +ioport_constructor astrocade_whiteram_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( exp_switches ); +} + +ioport_constructor astrocade_rl64ram_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( exp_switches ); +} + +/*------------------------------------------------- + specific handlers + -------------------------------------------------*/ + +// Blue RAM expansions have RAM starting at 0x6000, up to the RAM size +READ8_MEMBER(astrocade_blueram_4k_device::read) +{ + if (offset >= 0x1000 && offset < 0x1000 + m_ram.size()) + return m_ram[offset - 0x1000]; + else + return 0; +} + +WRITE8_MEMBER(astrocade_blueram_4k_device::write) +{ + if (offset >= 0x1000 && offset < 0x1000 + m_ram.size() && !m_write_prot->read()) + m_ram[offset - 0x1000] = data; +} + + + +// Viper System 1 expansion has RAM in 0x6000-0x9fff +READ8_MEMBER(astrocade_viper_sys1_device::read) +{ + if (offset >= 0x1000 && offset < 0xa000) + return m_ram[offset - 0x1000]; + else + return 0; +} + +WRITE8_MEMBER(astrocade_viper_sys1_device::write) +{ + if (offset >= 0x1000 && offset < 0xa000 && !m_write_prot->read()) + m_ram[offset - 0x1000] = data; +} + + + +// Lil' WHITE RAM expansion has RAM in 0x5000-0xcfff + a mirror of the first 0x3000 bytes up to 0xffff +READ8_MEMBER(astrocade_whiteram_device::read) +{ + return m_ram[offset % 0x8000]; +} + +WRITE8_MEMBER(astrocade_whiteram_device::write) +{ + if (!m_write_prot->read()) + m_ram[offset % 0x8000] = data; +} + + + +// R&L 64K RAM Board (44KB installed) has RAM in 0x5000-0xffff +READ8_MEMBER(astrocade_rl64ram_device::read) +{ + return m_ram[offset]; +} + +WRITE8_MEMBER(astrocade_rl64ram_device::write) +{ + if (!m_write_prot->read()) + m_ram[offset] = data; +} diff --git a/src/devices/bus/astrocde/ram.h b/src/devices/bus/astrocde/ram.h new file mode 100644 index 00000000000..9df04bdad0e --- /dev/null +++ b/src/devices/bus/astrocde/ram.h @@ -0,0 +1,135 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __ASTROCADE_RAM_H +#define __ASTROCADE_RAM_H + +#include "exp.h" + + +// ======================> astrocade_blueram_4k_device + +class astrocade_blueram_4k_device : public device_t, + public device_astrocade_card_interface +{ +public: + // construction/destruction + astrocade_blueram_4k_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + astrocade_blueram_4k_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start() { m_ram.resize(0x1000); save_item(NAME(m_ram)); } + virtual void device_reset() {} + virtual ioport_constructor device_input_ports() const; + + // reading and writing + virtual DECLARE_READ8_MEMBER(read); + virtual DECLARE_WRITE8_MEMBER(write); + +protected: + dynamic_buffer m_ram; + required_ioport m_write_prot; +}; + +// ======================> astrocade_blueram_16k_device + +class astrocade_blueram_16k_device : public astrocade_blueram_4k_device +{ +public: + // construction/destruction + astrocade_blueram_16k_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual void device_start() { m_ram.resize(0x4000); save_item(NAME(m_ram)); } +}; + +// ======================> astrocade_blueram_32k_device + +class astrocade_blueram_32k_device : public astrocade_blueram_4k_device +{ +public: + // construction/destruction + astrocade_blueram_32k_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual void device_start() { m_ram.resize(0x8000); save_item(NAME(m_ram)); } +}; + +// ======================> astrocade_viper_sys1_device + +class astrocade_viper_sys1_device : public device_t, + public device_astrocade_card_interface +{ +public: + // construction/destruction + astrocade_viper_sys1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start() { m_ram.resize(0x4000); save_item(NAME(m_ram)); } + virtual void device_reset() {} + virtual ioport_constructor device_input_ports() const; + + // reading and writing + virtual DECLARE_READ8_MEMBER(read); + virtual DECLARE_WRITE8_MEMBER(write); + +private: + dynamic_buffer m_ram; + required_ioport m_write_prot; +}; + +// ======================> astrocade_whiteram_device + +class astrocade_whiteram_device : public device_t, + public device_astrocade_card_interface +{ +public: + // construction/destruction + astrocade_whiteram_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start() { m_ram.resize(0x8000); save_item(NAME(m_ram)); } + virtual void device_reset() {} + virtual ioport_constructor device_input_ports() const; + + // reading and writing + virtual DECLARE_READ8_MEMBER(read); + virtual DECLARE_WRITE8_MEMBER(write); + +private: + dynamic_buffer m_ram; + required_ioport m_write_prot; +}; + +// ======================> astrocade_rl64ram_device + +class astrocade_rl64ram_device : public device_t, + public device_astrocade_card_interface +{ +public: + // construction/destruction + astrocade_rl64ram_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start() { m_ram.resize(0xb000); save_item(NAME(m_ram)); } + virtual void device_reset() {} + virtual ioport_constructor device_input_ports() const; + + // reading and writing + virtual DECLARE_READ8_MEMBER(read); + virtual DECLARE_WRITE8_MEMBER(write); + +private: + dynamic_buffer m_ram; + required_ioport m_write_prot; +}; + + + +// device type definition +extern const device_type ASTROCADE_BLUERAM_4K; +extern const device_type ASTROCADE_BLUERAM_16K; +extern const device_type ASTROCADE_BLUERAM_32K; +extern const device_type ASTROCADE_VIPER_SYS1; +extern const device_type ASTROCADE_WHITERAM; +extern const device_type ASTROCADE_RL64RAM; + + +#endif diff --git a/src/devices/bus/astrocde/rom.c b/src/devices/bus/astrocde/rom.c new file mode 100644 index 00000000000..d8067daa062 --- /dev/null +++ b/src/devices/bus/astrocde/rom.c @@ -0,0 +1,99 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + Bally Astrocade cart emulation + + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "rom.h" + + +//------------------------------------------------- +// astrocade_rom_device - constructor +//------------------------------------------------- + +const device_type ASTROCADE_ROM_STD = &device_creator; +const device_type ASTROCADE_ROM_256K = &device_creator; +const device_type ASTROCADE_ROM_512K = &device_creator; + + +astrocade_rom_device::astrocade_rom_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_astrocade_cart_interface(mconfig, *this) +{ +} + +astrocade_rom_device::astrocade_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, ASTROCADE_ROM_STD, "Bally Astrocade Standard Carts", tag, owner, clock, "astrocade_rom", __FILE__), + device_astrocade_cart_interface(mconfig, *this) +{ +} + +astrocade_rom_256k_device::astrocade_rom_256k_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : astrocade_rom_device(mconfig, ASTROCADE_ROM_256K, "Bally Astrocade 256K Carts", tag, owner, clock, "astrocade_256k", __FILE__) +{ +} + +astrocade_rom_512k_device::astrocade_rom_512k_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : astrocade_rom_device(mconfig, ASTROCADE_ROM_512K, "Bally Astrocade 512K Carts", tag, owner, clock, "astrocade_512k", __FILE__) +{ +} + + +void astrocade_rom_256k_device::device_start() +{ + save_item(NAME(m_base_bank)); +} + +void astrocade_rom_256k_device::device_reset() +{ + m_base_bank = 0; +} + +void astrocade_rom_512k_device::device_start() +{ + save_item(NAME(m_base_bank)); +} + +void astrocade_rom_512k_device::device_reset() +{ + m_base_bank = 0; +} + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +READ8_MEMBER(astrocade_rom_device::read_rom) +{ + if (offset < m_rom_size) + return m_rom[offset]; + else + return 0xff; +} + +READ8_MEMBER(astrocade_rom_256k_device::read_rom) +{ + if (offset < 0x1000) // 0x2000-0x2fff + return m_rom[offset + 0x1000 * 0x3f]; + else if (offset < 0x1fc0) // 0x3000-0x3fbf + return m_rom[(offset & 0xfff) + (0x1000 * m_base_bank)]; + else // 0x3fc0-0x3fff + return m_base_bank = offset & 0x3f; +} + +READ8_MEMBER(astrocade_rom_512k_device::read_rom) +{ + if (offset < 0x1000) // 0x2000-0x2fff + return m_rom[offset + 0x1000 * 0x7f]; + else if (offset < 0x1f80) // 0x3000-0x3fbf + return m_rom[(offset & 0xfff) + (0x1000 * m_base_bank)]; + else // 0x3fc0-0x3fff + return m_base_bank = offset & 0x7f; +} diff --git a/src/devices/bus/astrocde/rom.h b/src/devices/bus/astrocde/rom.h new file mode 100644 index 00000000000..e0b5647742a --- /dev/null +++ b/src/devices/bus/astrocde/rom.h @@ -0,0 +1,73 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __ASTROCADE_ROM_H +#define __ASTROCADE_ROM_H + +#include "slot.h" + + +// ======================> astrocade_rom_device + +class astrocade_rom_device : public device_t, + public device_astrocade_cart_interface +{ +public: + // construction/destruction + astrocade_rom_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + astrocade_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start() {} + virtual void device_reset() {} + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_rom); +}; + +// ======================> astrocade_rom_256k_device + +class astrocade_rom_256k_device : public astrocade_rom_device +{ +public: + // construction/destruction + astrocade_rom_256k_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual void device_start(); + virtual void device_reset(); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_rom); + +private: + UINT8 m_base_bank; +}; + +// ======================> astrocade_rom_512k_device + +class astrocade_rom_512k_device : public astrocade_rom_device +{ +public: + // construction/destruction + astrocade_rom_512k_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual void device_start(); + virtual void device_reset(); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_rom); + +private: + UINT8 m_base_bank; +}; + + + + + +// device type definition +extern const device_type ASTROCADE_ROM_STD; +extern const device_type ASTROCADE_ROM_256K; +extern const device_type ASTROCADE_ROM_512K; + + +#endif diff --git a/src/devices/bus/astrocde/slot.c b/src/devices/bus/astrocde/slot.c new file mode 100644 index 00000000000..5345d90b7fb --- /dev/null +++ b/src/devices/bus/astrocde/slot.c @@ -0,0 +1,236 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + Bally Astrocade cart emulation + (through slot devices) + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "slot.h" + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type ASTROCADE_CART_SLOT = &device_creator; + +//************************************************************************** +// Astrocade Cartridges Interface +//************************************************************************** + +//------------------------------------------------- +// device_astrocade_cart_interface - constructor +//------------------------------------------------- + +device_astrocade_cart_interface::device_astrocade_cart_interface(const machine_config &mconfig, device_t &device) + : device_slot_card_interface(mconfig, device), + m_rom(NULL), + m_rom_size(0) +{ +} + + +//------------------------------------------------- +// ~device_astrocade_cart_interface - destructor +//------------------------------------------------- + +device_astrocade_cart_interface::~device_astrocade_cart_interface() +{ +} + +//------------------------------------------------- +// rom_alloc - alloc the space for the cart +//------------------------------------------------- + +void device_astrocade_cart_interface::rom_alloc(UINT32 size, const char *tag) +{ + if (m_rom == NULL) + { + m_rom = device().machine().memory().region_alloc(std::string(tag).append(ASTROCADESLOT_ROM_REGION_TAG).c_str(), size, 1, ENDIANNESS_LITTLE)->base(); + m_rom_size = size; + } +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// astrocade_cart_slot_device - constructor +//------------------------------------------------- +astrocade_cart_slot_device::astrocade_cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, ASTROCADE_CART_SLOT, "Bally Astrocade Cartridge Slot", tag, owner, clock, "astrocade_cart_slot", __FILE__), + device_image_interface(mconfig, *this), + device_slot_interface(mconfig, *this), + m_type(ASTROCADE_STD) +{ +} + + +//------------------------------------------------- +// astrocade_cart_slot_device - destructor +//------------------------------------------------- + +astrocade_cart_slot_device::~astrocade_cart_slot_device() +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void astrocade_cart_slot_device::device_start() +{ + m_cart = dynamic_cast(get_card_device()); +} + +//------------------------------------------------- +// device_config_complete - perform any +// operations now that the configuration is +// complete +//------------------------------------------------- + +void astrocade_cart_slot_device::device_config_complete() +{ + // set brief and instance name + update_names(); +} + + +//------------------------------------------------- +// ASTROCADE PCB +//------------------------------------------------- + +struct astrocade_slot +{ + int pcb_id; + const char *slot_option; +}; + +// Here, we take the feature attribute from .xml (i.e. the PCB name) and we assign a unique ID to it +static const astrocade_slot slot_list[] = +{ + { ASTROCADE_STD, "rom" }, + { ASTROCADE_256K, "rom_256k" }, + { ASTROCADE_512K, "rom_512k" } +}; + +static int astrocade_get_pcb_id(const char *slot) +{ + for (int i = 0; i < ARRAY_LENGTH(slot_list); i++) + { + if (!core_stricmp(slot_list[i].slot_option, slot)) + return slot_list[i].pcb_id; + } + + return 0; +} + +static const char *astrocade_get_slot(int type) +{ + for (int i = 0; i < ARRAY_LENGTH(slot_list); i++) + { + if (slot_list[i].pcb_id == type) + return slot_list[i].slot_option; + } + + return "std"; +} + + +/*------------------------------------------------- + call load + -------------------------------------------------*/ + +bool astrocade_cart_slot_device::call_load() +{ + if (m_cart) + { + UINT32 size = (software_entry() == NULL) ? length() : get_software_region_length("rom"); + m_cart->rom_alloc(size, tag()); + + if (software_entry() == NULL) + fread(m_cart->get_rom_base(), size); + else + memcpy(m_cart->get_rom_base(), get_software_region("rom"), size); + + if (software_entry() == NULL) + { + m_type = ASTROCADE_STD; + + if (size == 0x40000) + m_type = ASTROCADE_256K; + if (size == 0x80000) + m_type = ASTROCADE_512K; + } + else + { + const char *pcb_name = get_feature("slot"); + if (pcb_name) + m_type = astrocade_get_pcb_id(pcb_name); + } + + //printf("Type: %s\n", astrocade_get_slot(m_type)); + + return IMAGE_INIT_PASS; + } + + return IMAGE_INIT_PASS; +} + + +/*------------------------------------------------- + call softlist load + -------------------------------------------------*/ + +bool astrocade_cart_slot_device::call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry) +{ + load_software_part_region(*this, swlist, swname, start_entry); + return TRUE; +} + + +/*------------------------------------------------- + get default card software + -------------------------------------------------*/ + +void astrocade_cart_slot_device::get_default_card_software(std::string &result) +{ + if (open_image_file(mconfig().options())) + { + const char *slot_string = "rom"; + UINT32 size = core_fsize(m_file); + int type = ASTROCADE_STD; + + if (size == 0x40000) + type = ASTROCADE_256K; + if (size == 0x80000) + type = ASTROCADE_512K; + + slot_string = astrocade_get_slot(type); + + //printf("type: %s\n", slot_string); + clear(); + + result.assign(slot_string); + return; + } + + software_get_default_slot(result, "rom"); +} + +/*------------------------------------------------- + read + -------------------------------------------------*/ + +READ8_MEMBER(astrocade_cart_slot_device::read_rom) +{ + if (m_cart) + return m_cart->read_rom(space, offset); + else + return 0xff; +} diff --git a/src/devices/bus/astrocde/slot.h b/src/devices/bus/astrocde/slot.h new file mode 100644 index 00000000000..738c32a6faa --- /dev/null +++ b/src/devices/bus/astrocde/slot.h @@ -0,0 +1,103 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __ASTROCADE_SLOT_H +#define __ASTROCADE_SLOT_H + +/*************************************************************************** + TYPE DEFINITIONS + ***************************************************************************/ + + +/* PCB */ +enum +{ + ASTROCADE_STD = 0, + ASTROCADE_256K, + ASTROCADE_512K +}; + + +// ======================> device_astrocade_cart_interface + +class device_astrocade_cart_interface : public device_slot_card_interface +{ +public: + // construction/destruction + device_astrocade_cart_interface(const machine_config &mconfig, device_t &device); + virtual ~device_astrocade_cart_interface(); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_rom) { return 0xff; } + + void rom_alloc(UINT32 size, const char *tag); + void ram_alloc(UINT32 size); + UINT8* get_rom_base() { return m_rom; } + UINT32 get_rom_size() { return m_rom_size; } + +protected: + // internal state + UINT8 *m_rom; + UINT32 m_rom_size; +}; + + +// ======================> astrocade_cart_slot_device + +class astrocade_cart_slot_device : public device_t, + public device_image_interface, + public device_slot_interface +{ +public: + // construction/destruction + astrocade_cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual ~astrocade_cart_slot_device(); + + // device-level overrides + virtual void device_start(); + virtual void device_config_complete(); + + // image-level overrides + virtual bool call_load(); + virtual void call_unload() {} + virtual bool call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry); + + int get_type() { return m_type; } + + virtual iodevice_t image_type() const { return IO_CARTSLOT; } + virtual bool is_readable() const { return 1; } + virtual bool is_writeable() const { return 0; } + virtual bool is_creatable() const { return 0; } + virtual bool must_be_loaded() const { return 0; } + virtual bool is_reset_on_load() const { return 1; } + virtual const option_guide *create_option_guide() const { return NULL; } + virtual const char *image_interface() const { return "astrocde_cart"; } + virtual const char *file_extensions() const { return "bin"; } + + // slot interface overrides + virtual void get_default_card_software(std::string &result); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_rom); + +protected: + + int m_type; + device_astrocade_cart_interface* m_cart; +}; + + + +// device type definition +extern const device_type ASTROCADE_CART_SLOT; + + +/*************************************************************************** + DEVICE CONFIGURATION MACROS + ***************************************************************************/ + +#define ASTROCADESLOT_ROM_REGION_TAG ":cart:rom" + +#define MCFG_ASTROCADE_CARTRIDGE_ADD(_tag,_slot_intf,_def_slot) \ + MCFG_DEVICE_ADD(_tag, ASTROCADE_CART_SLOT, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) +#endif diff --git a/src/devices/bus/bml3/bml3bus.c b/src/devices/bus/bml3/bml3bus.c new file mode 100644 index 00000000000..5839ea00196 --- /dev/null +++ b/src/devices/bus/bml3/bml3bus.c @@ -0,0 +1,241 @@ +// license:GPL-2.0+ +// copyright-holders:Jonathan Edwards +/*************************************************************************** + + bml3bus.c - Hitachi MB-6890 slot bus and card emulation + + Adapted from a2bus by Jonathan Edwards + + Pinout (/ indicates an inverted signal, ie, one that would have a bar over it + on a schematic diagram) + + out <-> CPU CPU <-> out + ---------- ----------- + +5V <-- 1 2 <-> GND + D0 <-> 3 4 <-> D1 + D2 <-> 5 6 <-> D3 + D4 <-> 7 8 <-> D5 + D6 <-> 9 10 <-> D7 + A0 <-> 11 12 <-> A1 + A2 <-> 13 14 <-> A3 + A4 <-> 15 16 <-> A5 + A6 <-> 17 18 <-> A7 + A8 <-> 19 20 <-> A9 + A10 <-> 21 22 <-> A11 + A12 <-> 23 24 <-> A13 + A14 <-> 25 26 <-> A15 + BA <-- 27 28 --> BS + /ROM-KIL --> 29 30 --> EXROM-KIL + R/W IN --> 31 32 --> /EX-I/O + R/W OUT <-- 33 34 --> VMA OUT + E <-- 35 36 --> Q + /RES <-- 37 38 <-- /NMI + /IRQ --> 39 40 <-- /FIRQ + /HALT --> 41 42 <-- /VMA CTRL + /DMA --> 43 44 --> /BANK-SW + HALT ACK <-- 45 46 <-- SOUND IN + 16MCK <-- 47 48 <-> GND + 2MCK <-- 49 50 <-> GND + -5V <-- 51 52 --> /EX-I/O2 + -12V <-- 53 54 --> +12V + GND <-> 55 56 --> +5V + +***************************************************************************/ + +#include "emu.h" +#include "emuopts.h" +#include "bml3bus.h" + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type BML3BUS_SLOT = &device_creator; + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// bml3bus_slot_device - constructor +//------------------------------------------------- +bml3bus_slot_device::bml3bus_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, BML3BUS_SLOT, "Hitachi MB-6890 Slot", tag, owner, clock, "bml3bus_slot", __FILE__), + device_slot_interface(mconfig, *this) +{ +} + +bml3bus_slot_device::bml3bus_slot_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_slot_interface(mconfig, *this) +{ +} + +void bml3bus_slot_device::static_set_bml3bus_slot(device_t &device, const char *tag, const char *slottag) +{ + bml3bus_slot_device &bml3bus_card = dynamic_cast(device); + bml3bus_card.m_bml3bus_tag = tag; + bml3bus_card.m_bml3bus_slottag = slottag; +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void bml3bus_slot_device::device_start() +{ + device_bml3bus_card_interface *dev = dynamic_cast(get_card_device()); + + if (dev) device_bml3bus_card_interface::static_set_bml3bus_tag(*dev, m_bml3bus_tag, m_bml3bus_slottag); +} + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type BML3BUS = &device_creator; + +void bml3bus_device::static_set_cputag(device_t &device, const char *tag) +{ + bml3bus_device &bml3bus = downcast(device); + bml3bus.m_cputag = tag; +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// bml3bus_device - constructor +//------------------------------------------------- + +bml3bus_device::bml3bus_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, BML3BUS, "Hitachi MB-6890 Bus", tag, owner, clock, "bml3bus", __FILE__), + m_out_nmi_cb(*this), + m_out_irq_cb(*this), + m_out_firq_cb(*this) +{ +} + +bml3bus_device::bml3bus_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + m_out_nmi_cb(*this), + m_out_irq_cb(*this), + m_out_firq_cb(*this) +{ +} +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void bml3bus_device::device_start() +{ + m_maincpu = machine().device(m_cputag); + + // resolve callbacks + m_out_nmi_cb.resolve_safe(); + m_out_irq_cb.resolve_safe(); + m_out_firq_cb.resolve_safe(); + + // clear slots + for (int i = 0; i < BML3BUS_MAX_SLOTS; i++) + { + m_device_list[i] = NULL; + } +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void bml3bus_device::device_reset() +{ +} + +device_bml3bus_card_interface *bml3bus_device::get_bml3bus_card(int slot) +{ + if (slot < 0) + { + return NULL; + } + + return m_device_list[slot]; +} + +void bml3bus_device::add_bml3bus_card(int slot, device_bml3bus_card_interface *card) +{ + m_device_list[slot] = card; +} + +void bml3bus_device::set_nmi_line(int state) +{ + m_out_nmi_cb(state); +} + +void bml3bus_device::set_irq_line(int state) +{ + m_out_irq_cb(state); +} + +void bml3bus_device::set_firq_line(int state) +{ + m_out_firq_cb(state); +} + +// interrupt request from bml3bus card +WRITE_LINE_MEMBER( bml3bus_device::nmi_w ) { m_out_nmi_cb(state); } +WRITE_LINE_MEMBER( bml3bus_device::irq_w ) { m_out_irq_cb(state); } +WRITE_LINE_MEMBER( bml3bus_device::firq_w ) { m_out_firq_cb(state); } + +//************************************************************************** +// DEVICE CONFIG BML3BUS CARD INTERFACE +//************************************************************************** + + +//************************************************************************** +// DEVICE BML3BUS CARD INTERFACE +//************************************************************************** + +//------------------------------------------------- +// device_bml3bus_card_interface - constructor +//------------------------------------------------- + +device_bml3bus_card_interface::device_bml3bus_card_interface(const machine_config &mconfig, device_t &device) + : device_slot_card_interface(mconfig, device), + m_bml3bus(NULL), + m_bml3bus_tag(NULL) +{ +} + + +//------------------------------------------------- +// ~device_bml3bus_card_interface - destructor +//------------------------------------------------- + +device_bml3bus_card_interface::~device_bml3bus_card_interface() +{ +} + +void device_bml3bus_card_interface::static_set_bml3bus_tag(device_t &device, const char *tag, const char *slottag) +{ + device_bml3bus_card_interface &bml3bus_card = dynamic_cast(device); + bml3bus_card.m_bml3bus_tag = tag; + bml3bus_card.m_bml3bus_slottag = slottag; +} + +void device_bml3bus_card_interface::set_bml3bus_device() +{ + // extract the slot number from the last digit of the slot tag + int tlen = strlen(m_bml3bus_slottag); + + m_slot = (m_bml3bus_slottag[tlen-1] - '1'); + + if (m_slot < 0 || m_slot >= BML3BUS_MAX_SLOTS) + { + fatalerror("Slot %x out of range for Hitachi MB-6890 Bus\n", m_slot); + } + + m_bml3bus = dynamic_cast(device().machine().device(m_bml3bus_tag)); + m_bml3bus->add_bml3bus_card(m_slot, this); +} diff --git a/src/devices/bus/bml3/bml3bus.h b/src/devices/bus/bml3/bml3bus.h new file mode 100644 index 00000000000..63da81fd1fc --- /dev/null +++ b/src/devices/bus/bml3/bml3bus.h @@ -0,0 +1,153 @@ +// license:GPL-2.0+ +// copyright-holders:Jonathan Edwards +/*************************************************************************** + + bml3bus.h - Hitachi MB-6890 slot bus and card emulation + + Adapted from a2bus by Jonathan Edwards + +***************************************************************************/ + +#pragma once + +#ifndef __BML3BUS_H__ +#define __BML3BUS_H__ + +#include "emu.h" + +#define BML3BUS_MAX_SLOTS 6 + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_BML3BUS_CPU(_cputag) \ + bml3bus_device::static_set_cputag(*device, _cputag); + +#define MCFG_BML3BUS_OUT_NMI_CB(_devcb) \ + devcb = &bml3bus_device::set_out_nmi_callback(*device, DEVCB_##_devcb); + +#define MCFG_BML3BUS_OUT_IRQ_CB(_devcb) \ + devcb = &bml3bus_device::set_out_irq_callback(*device, DEVCB_##_devcb); + +#define MCFG_BML3BUS_OUT_FIRQ_CB(_devcb) \ + devcb = &bml3bus_device::set_out_firq_callback(*device, DEVCB_##_devcb); + +#define MCFG_BML3BUS_SLOT_ADD(_nbtag, _tag, _slot_intf, _def_slot) \ + MCFG_DEVICE_ADD(_tag, BML3BUS_SLOT, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) \ + bml3bus_slot_device::static_set_bml3bus_slot(*device, _nbtag, _tag); +#define MCFG_BML3BUS_SLOT_REMOVE(_tag) \ + MCFG_DEVICE_REMOVE(_tag) + +#define MCFG_BML3BUS_ONBOARD_ADD(_nbtag, _tag, _dev_type) \ + MCFG_DEVICE_ADD(_tag, _dev_type, 0) \ + device_bml3bus_card_interface::static_set_bml3bus_tag(*device, _nbtag, _tag); + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class bml3bus_device; + +class bml3bus_slot_device : public device_t, + public device_slot_interface +{ +public: + // construction/destruction + bml3bus_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + bml3bus_slot_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + // device-level overrides + virtual void device_start(); + + // inline configuration + static void static_set_bml3bus_slot(device_t &device, const char *tag, const char *slottag); +protected: + // configuration + const char *m_bml3bus_tag, *m_bml3bus_slottag; +}; + +// device type definition +extern const device_type BML3BUS_SLOT; + + +class device_bml3bus_card_interface; +// ======================> bml3bus_device +class bml3bus_device : public device_t +{ +public: + // construction/destruction + bml3bus_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + bml3bus_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + // inline configuration + static void static_set_cputag(device_t &device, const char *tag); + template static devcb_base &set_out_nmi_callback(device_t &device, _Object object) { return downcast(device).m_out_nmi_cb.set_callback(object); } + template static devcb_base &set_out_irq_callback(device_t &device, _Object object) { return downcast(device).m_out_irq_cb.set_callback(object); } + template static devcb_base &set_out_firq_callback(device_t &device, _Object object) { return downcast(device).m_out_firq_cb.set_callback(object); } + + void add_bml3bus_card(int slot, device_bml3bus_card_interface *card); + device_bml3bus_card_interface *get_bml3bus_card(int slot); + + void set_nmi_line(int state); + void set_irq_line(int state); + void set_firq_line(int state); + + DECLARE_WRITE_LINE_MEMBER( nmi_w ); + DECLARE_WRITE_LINE_MEMBER( irq_w ); + DECLARE_WRITE_LINE_MEMBER( firq_w ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // internal state + cpu_device *m_maincpu; + + devcb_write_line m_out_nmi_cb; + devcb_write_line m_out_irq_cb; + devcb_write_line m_out_firq_cb; + + device_bml3bus_card_interface *m_device_list[BML3BUS_MAX_SLOTS]; + const char *m_cputag; +}; + + +// device type definition +extern const device_type BML3BUS; + +// ======================> device_bml3bus_card_interface + +// class representing interface-specific live bml3bus card +class device_bml3bus_card_interface : public device_slot_card_interface +{ + friend class bml3bus_device; +public: + // construction/destruction + device_bml3bus_card_interface(const machine_config &mconfig, device_t &device); + virtual ~device_bml3bus_card_interface(); + + device_bml3bus_card_interface *next() const { return m_next; } + + void set_bml3bus_device(); + + void raise_slot_nmi() { m_bml3bus->set_nmi_line(ASSERT_LINE); } + void lower_slot_nmi() { m_bml3bus->set_nmi_line(CLEAR_LINE); } + void raise_slot_irq() { m_bml3bus->set_irq_line(ASSERT_LINE); } + void lower_slot_irq() { m_bml3bus->set_irq_line(CLEAR_LINE); } + void raise_slot_firq() { m_bml3bus->set_firq_line(ASSERT_LINE); } + void lower_slot_firq() { m_bml3bus->set_firq_line(CLEAR_LINE); } + + // inline configuration + static void static_set_bml3bus_tag(device_t &device, const char *tag, const char *slottag); +public: + bml3bus_device *m_bml3bus; + const char *m_bml3bus_tag, *m_bml3bus_slottag; + int m_slot; + device_bml3bus_card_interface *m_next; +}; + +#endif /* __BML3BUS_H__ */ diff --git a/src/devices/bus/bml3/bml3kanji.c b/src/devices/bus/bml3/bml3kanji.c new file mode 100644 index 00000000000..f07e95c8bba --- /dev/null +++ b/src/devices/bus/bml3/bml3kanji.c @@ -0,0 +1,101 @@ +// license:GPL-2.0+ +// copyright-holders:Jonathan Edwards +/********************************************************************* + + bml3kanji.c + + Hitachi MP-9740 (?) kanji character ROM for the MB-689x + +*********************************************************************/ + +#include "emu.h" +#include "bml3kanji.h" + + +/*************************************************************************** + PARAMETERS +***************************************************************************/ + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type BML3BUS_KANJI = &device_creator; + +#define KANJI_ROM_REGION "kanji_rom" + +ROM_START( kanji ) + ROM_REGION( 0x20000, KANJI_ROM_REGION, ROMREGION_ERASEFF ) + ROM_LOAD("kanji.rom", 0x00000, 0x20000, BAD_DUMP CRC(de99a726) SHA1(65fead5d0d779b242f6e0ac25fcc9899dc343101)) +ROM_END + +MACHINE_CONFIG_FRAGMENT( kanji ) + // nothing to add +MACHINE_CONFIG_END + +/*************************************************************************** + FUNCTION PROTOTYPES +***************************************************************************/ + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor bml3bus_kanji_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( kanji ); +} + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *bml3bus_kanji_device::device_rom_region() const +{ + return ROM_NAME( kanji ); +} + +READ8_MEMBER( bml3bus_kanji_device::bml3_kanji_r ) +{ + return m_rom[((UINT32)m_kanji_addr << 1) + offset]; +} + +WRITE8_MEMBER( bml3bus_kanji_device::bml3_kanji_w ) +{ + m_kanji_addr &= (0xff << (offset*8)); + m_kanji_addr |= (data << ((offset^1)*8)); +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +bml3bus_kanji_device::bml3bus_kanji_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, BML3BUS_KANJI, "Hitachi MP-9740 Kanji Character ROM Card", tag, owner, clock, "bml3kanji", __FILE__), + device_bml3bus_card_interface(mconfig, *this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void bml3bus_kanji_device::device_start() +{ + // set_bml3bus_device makes m_slot valid + set_bml3bus_device(); + + m_rom = memregion(KANJI_ROM_REGION)->base(); + + // install into memory + address_space &space_prg = machine().firstcpu->space(AS_PROGRAM); + space_prg.install_readwrite_handler(0xff75, 0xff76, read8_delegate( FUNC(bml3bus_kanji_device::bml3_kanji_r), this), write8_delegate(FUNC(bml3bus_kanji_device::bml3_kanji_w), this) ); +} + +void bml3bus_kanji_device::device_reset() +{ + m_kanji_addr = 0; +} diff --git a/src/devices/bus/bml3/bml3kanji.h b/src/devices/bus/bml3/bml3kanji.h new file mode 100644 index 00000000000..e05a4fd96d2 --- /dev/null +++ b/src/devices/bus/bml3/bml3kanji.h @@ -0,0 +1,49 @@ +// license:GPL-2.0+ +// copyright-holders:Jonathan Edwards +/********************************************************************* + + bml3kanji.h + + Hitachi MP-9740 (?) kanji character ROM for the MB-689x + +*********************************************************************/ + +#ifndef __BML3BUS_KANJI__ +#define __BML3BUS_KANJI__ + +#include "emu.h" +#include "bml3bus.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class bml3bus_kanji_device: + public device_t, + public device_bml3bus_card_interface +{ +public: + // construction/destruction + bml3bus_kanji_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual const rom_entry *device_rom_region() const; + + DECLARE_READ8_MEMBER(bml3_kanji_r); + DECLARE_WRITE8_MEMBER(bml3_kanji_w); + +protected: + virtual void device_start(); + virtual void device_reset(); + + UINT16 m_kanji_addr; + +private: + UINT8 *m_rom; +}; + +// device type definition +extern const device_type BML3BUS_KANJI; + +#endif /* __BML3BUS_KANJI__ */ diff --git a/src/devices/bus/bml3/bml3mp1802.c b/src/devices/bus/bml3/bml3mp1802.c new file mode 100644 index 00000000000..64db414fa21 --- /dev/null +++ b/src/devices/bus/bml3/bml3mp1802.c @@ -0,0 +1,143 @@ +// license:GPL-2.0+ +// copyright-holders:Jonathan Edwards +/********************************************************************* + + bml3mp1802.c + + Hitachi MP-1802 floppy disk controller card for the MB-6890 + Hitachi MP-3550 floppy drive is attached + +*********************************************************************/ + +#include "emu.h" +#include "bml3mp1802.h" + + +/*************************************************************************** + PARAMETERS +***************************************************************************/ + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type BML3BUS_MP1802 = &device_creator; + +static SLOT_INTERFACE_START( mp1802_floppies ) + SLOT_INTERFACE("dd", FLOPPY_525_DD) +SLOT_INTERFACE_END + +WRITE_LINE_MEMBER( bml3bus_mp1802_device::bml3_wd17xx_intrq_w ) +{ + if (state) { + m_bml3bus->set_nmi_line(PULSE_LINE); + } +} + +#define MP1802_ROM_REGION "mp1802_rom" + +ROM_START( mp1802 ) + ROM_REGION(0x10000, MP1802_ROM_REGION, 0) + // MP-1802 disk controller ROM, which replaces part of the system ROM + ROM_LOAD( "mp1802.rom", 0xf800, 0x800, BAD_DUMP CRC(8d0dc101) SHA1(92f7d1cebecafa7472e45c4999520de5c01c6dbc)) +ROM_END + +MACHINE_CONFIG_FRAGMENT( mp1802 ) + MCFG_MB8866_ADD("fdc", XTAL_1MHz) + MCFG_WD_FDC_INTRQ_CALLBACK(WRITELINE(bml3bus_mp1802_device, bml3_wd17xx_intrq_w)) + + MCFG_FLOPPY_DRIVE_ADD("fdc:0", mp1802_floppies, "dd", floppy_image_device::default_floppy_formats) + MCFG_FLOPPY_DRIVE_ADD("fdc:1", mp1802_floppies, "dd", floppy_image_device::default_floppy_formats) + MCFG_FLOPPY_DRIVE_ADD("fdc:2", mp1802_floppies, "", floppy_image_device::default_floppy_formats) + MCFG_FLOPPY_DRIVE_ADD("fdc:3", mp1802_floppies, "", floppy_image_device::default_floppy_formats) +MACHINE_CONFIG_END + +/*************************************************************************** + FUNCTION PROTOTYPES +***************************************************************************/ + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor bml3bus_mp1802_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( mp1802 ); +} + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *bml3bus_mp1802_device::device_rom_region() const +{ + return ROM_NAME( mp1802 ); +} + +READ8_MEMBER( bml3bus_mp1802_device::bml3_mp1802_r) +{ + return m_fdc->drq_r() ? 0x00 : 0x80; +} + +WRITE8_MEMBER( bml3bus_mp1802_device::bml3_mp1802_w) +{ + floppy_image_device *floppy = NULL; + + switch (data & 0x03) + { + case 0: floppy = m_floppy0->get_device(); break; + case 1: floppy = m_floppy1->get_device(); break; + case 2: floppy = m_floppy2->get_device(); break; + case 3: floppy = m_floppy3->get_device(); break; + } + + m_fdc->set_floppy(floppy); + + if (floppy) + { + floppy->mon_w(!BIT(data, 3)); + floppy->ss_w(BIT(data, 4)); + } +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +bml3bus_mp1802_device::bml3bus_mp1802_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, BML3BUS_MP1802, "Hitachi MP-1802 Floppy Controller Card", tag, owner, clock, "bml3mp1802", __FILE__), + device_bml3bus_card_interface(mconfig, *this), + m_fdc(*this, "fdc"), + m_floppy0(*this, "fdc:0"), + m_floppy1(*this, "fdc:1"), + m_floppy2(*this, "fdc:2"), + m_floppy3(*this, "fdc:3") +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void bml3bus_mp1802_device::device_start() +{ + // set_bml3bus_device makes m_slot valid + set_bml3bus_device(); + + m_rom = memregion(MP1802_ROM_REGION)->base(); + + // install into memory + address_space &space_prg = machine().firstcpu->space(AS_PROGRAM); + space_prg.install_readwrite_handler(0xff00, 0xff03, read8_delegate(FUNC(mb8866_t::read),(mb8866_t*)m_fdc), write8_delegate(FUNC(mb8866_t::write),(mb8866_t*)m_fdc)); + space_prg.install_readwrite_handler(0xff04, 0xff04, read8_delegate(FUNC(bml3bus_mp1802_device::bml3_mp1802_r), this), write8_delegate(FUNC(bml3bus_mp1802_device::bml3_mp1802_w), this)); + // overwriting the main ROM (rather than using e.g. install_rom) should mean that bank switches for RAM expansion still work... + UINT8 *mainrom = device().machine().root_device().memregion("maincpu")->base(); + memcpy(mainrom + 0xf800, m_rom + 0xf800, 0x800); +} + +void bml3bus_mp1802_device::device_reset() +{ +} diff --git a/src/devices/bus/bml3/bml3mp1802.h b/src/devices/bus/bml3/bml3mp1802.h new file mode 100644 index 00000000000..0c4088c0d4f --- /dev/null +++ b/src/devices/bus/bml3/bml3mp1802.h @@ -0,0 +1,58 @@ +// license:GPL-2.0+ +// copyright-holders:Jonathan Edwards +/********************************************************************* + + bml3mp1802.h + + Hitachi MP-1802 floppy disk controller card for the MB-6890 + Hitachi MP-3550 floppy drive is attached + +*********************************************************************/ + +#ifndef __BML3BUS_MP1802__ +#define __BML3BUS_MP1802__ + +#include "emu.h" +#include "bml3bus.h" +#include "imagedev/flopdrv.h" +#include "machine/wd_fdc.h" + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class bml3bus_mp1802_device: + public device_t, + public device_bml3bus_card_interface +{ +public: + // construction/destruction + bml3bus_mp1802_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual const rom_entry *device_rom_region() const; + + DECLARE_READ8_MEMBER(bml3_mp1802_r); + DECLARE_WRITE8_MEMBER(bml3_mp1802_w); + DECLARE_WRITE_LINE_MEMBER(bml3_wd17xx_intrq_w); + +protected: + virtual void device_start(); + virtual void device_reset(); + +private: + required_device m_fdc; + required_device m_floppy0; + required_device m_floppy1; + required_device m_floppy2; + required_device m_floppy3; + + UINT8 *m_rom; +}; + +// device type definition +extern const device_type BML3BUS_MP1802; + +#endif /* __BML3BUS_MP1802__ */ diff --git a/src/devices/bus/bml3/bml3mp1805.c b/src/devices/bus/bml3/bml3mp1805.c new file mode 100644 index 00000000000..f87e0604476 --- /dev/null +++ b/src/devices/bus/bml3/bml3mp1805.c @@ -0,0 +1,170 @@ +// license:GPL-2.0+ +// copyright-holders:Jonathan Edwards +/********************************************************************* + + bml3mp1805.c + + Hitachi MP-1805 floppy disk controller card for the MB-6890 + Floppy drive is attached + +*********************************************************************/ + +#include "emu.h" +#include "bml3mp1805.h" + + +/*************************************************************************** + PARAMETERS +***************************************************************************/ + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type BML3BUS_MP1805 = &device_creator; + +static const floppy_interface bml3_mp1805_floppy_interface = +{ + FLOPPY_STANDARD_3_SSDD, + LEGACY_FLOPPY_OPTIONS_NAME(default), + NULL +}; + +WRITE_LINE_MEMBER( bml3bus_mp1805_device::bml3_mc6843_intrq_w ) +{ + if (state) { + m_bml3bus->set_nmi_line(PULSE_LINE); + } +} + +#define MP1805_ROM_REGION "mp1805_rom" + +ROM_START( mp1805 ) + ROM_REGION(0x10000, MP1805_ROM_REGION, 0) + // MP-1805 disk controller ROM, which replaces part of the system ROM + ROM_LOAD( "mp1805.rom", 0xf800, 0x0800, BAD_DUMP CRC(b532d8d9) SHA1(6f1160356d5bf64b5926b1fdb60db414edf65f22)) +ROM_END + +MACHINE_CONFIG_FRAGMENT( mp1805 ) + MCFG_DEVICE_ADD( "mc6843", MC6843, 0 ) + MCFG_MC6843_IRQ_CALLBACK(WRITELINE(bml3bus_mp1805_device, bml3_mc6843_intrq_w)) + MCFG_LEGACY_FLOPPY_4_DRIVES_ADD(bml3_mp1805_floppy_interface) +MACHINE_CONFIG_END + +/*************************************************************************** + FUNCTION PROTOTYPES +***************************************************************************/ + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor bml3bus_mp1805_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( mp1805 ); +} + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *bml3bus_mp1805_device::device_rom_region() const +{ + return ROM_NAME( mp1805 ); +} + +READ8_MEMBER( bml3bus_mp1805_device::bml3_mp1805_r) +{ + // TODO: read supported or not? + // return mc6843_drq_r(m_mc6843) ? 0x00 : 0x80; + return -1; +} + +WRITE8_MEMBER( bml3bus_mp1805_device::bml3_mp1805_w) +{ + // b7 b6 b5 b4 b3 b2 b1 b0 + // MT ? ? ? D3 D2 D1 D0 + // MT: 0=motor off, 1=motor on + // Dn: 1=select drive + int drive_select = data & 0x0f; + int drive; + // TODO: MESS UI for flipping disk? Note that D88 images are double-sided, but the physical drive is single-sided + int side = 0; + int motor = BIT(data, 7); + const char *floppy_name = NULL; + switch (drive_select) { + case 1: + drive = 0; + break; + case 2: + drive = 1; + break; + case 4: + drive = 2; + break; + case 8: + drive = 3; + break; + default: + // TODO: what's the correct behaviour if more than one drive select bit is set? Or no bit set? + drive = 0; + break; + } + switch (drive) { + case 0: + floppy_name = FLOPPY_0; + break; + case 1: + floppy_name = FLOPPY_1; + break; + case 2: + floppy_name = FLOPPY_2; + break; + case 3: + floppy_name = FLOPPY_3; + break; + } + legacy_floppy_image_device *floppy = subdevice(floppy_name); + m_mc6843->set_drive(drive); + floppy->floppy_mon_w(motor); + floppy->floppy_drive_set_ready_state(ASSERT_LINE, 0); + m_mc6843->set_side(side); +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +bml3bus_mp1805_device::bml3bus_mp1805_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, BML3BUS_MP1805, "Hitachi MP-1805 Floppy Controller Card", tag, owner, clock, "bml3mp1805", __FILE__), + device_bml3bus_card_interface(mconfig, *this), + m_mc6843(*this, "mc6843") +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void bml3bus_mp1805_device::device_start() +{ + // set_bml3bus_device makes m_slot valid + set_bml3bus_device(); + + m_rom = memregion(MP1805_ROM_REGION)->base(); + + // install into memory + address_space &space_prg = machine().firstcpu->space(AS_PROGRAM); + space_prg.install_readwrite_handler(0xff18, 0xff1f, read8_delegate( FUNC(mc6843_device::read), (mc6843_device*)m_mc6843), write8_delegate(FUNC(mc6843_device::write), (mc6843_device*)m_mc6843) ); + space_prg.install_readwrite_handler(0xff20, 0xff20, read8_delegate( FUNC(bml3bus_mp1805_device::bml3_mp1805_r), this), write8_delegate(FUNC(bml3bus_mp1805_device::bml3_mp1805_w), this) ); + // overwriting the main ROM (rather than using e.g. install_rom) should mean that bank switches for RAM expansion still work... + UINT8 *mainrom = device().machine().root_device().memregion("maincpu")->base(); + memcpy(mainrom + 0xf800, m_rom + 0xf800, 0x800); +} + +void bml3bus_mp1805_device::device_reset() +{ +} diff --git a/src/devices/bus/bml3/bml3mp1805.h b/src/devices/bus/bml3/bml3mp1805.h new file mode 100644 index 00000000000..ca819b4c061 --- /dev/null +++ b/src/devices/bus/bml3/bml3mp1805.h @@ -0,0 +1,54 @@ +// license:GPL-2.0+ +// copyright-holders:Jonathan Edwards +/********************************************************************* + + bml3mp1805.h + + Hitachi MP-1805 floppy disk controller card for the MB-6890 + Floppy drive is attached + +*********************************************************************/ + +#ifndef __BML3BUS_MP1805__ +#define __BML3BUS_MP1805__ + +#include "emu.h" +#include "bml3bus.h" +#include "imagedev/flopdrv.h" +#include "machine/mc6843.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class bml3bus_mp1805_device: + public device_t, + public device_bml3bus_card_interface +{ +public: + // construction/destruction + bml3bus_mp1805_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual const rom_entry *device_rom_region() const; + + DECLARE_READ8_MEMBER(bml3_mp1805_r); + DECLARE_WRITE8_MEMBER(bml3_mp1805_w); + + DECLARE_WRITE_LINE_MEMBER( bml3_mc6843_intrq_w ); + +protected: + virtual void device_start(); + virtual void device_reset(); + + required_device m_mc6843; + +private: + UINT8 *m_rom; +}; + +// device type definition +extern const device_type BML3BUS_MP1805; + +#endif /* __BML3BUS_MP1805__ */ diff --git a/src/devices/bus/bw2/exp.c b/src/devices/bus/bw2/exp.c new file mode 100644 index 00000000000..b094283a862 --- /dev/null +++ b/src/devices/bus/bw2/exp.c @@ -0,0 +1,191 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Bondwell 2 Expansion Port emulation + +**********************************************************************/ + +#include "exp.h" + + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type BW2_EXPANSION_SLOT = &device_creator; + + + +//************************************************************************** +// CARD INTERFACE +//************************************************************************** + +//------------------------------------------------- +// device_bw2_expansion_slot_interface - constructor +//------------------------------------------------- + +device_bw2_expansion_slot_interface::device_bw2_expansion_slot_interface(const machine_config &mconfig, device_t &device) + : device_slot_card_interface(mconfig,device) +{ + m_slot = dynamic_cast(device.owner()); +} + + +//------------------------------------------------- +// ~device_bw2_expansion_slot_interface - destructor +//------------------------------------------------- + +device_bw2_expansion_slot_interface::~device_bw2_expansion_slot_interface() +{ +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// bw2_expansion_slot_device - constructor +//------------------------------------------------- + +bw2_expansion_slot_device::bw2_expansion_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, BW2_EXPANSION_SLOT, "Bondwell 2 expansion port", tag, owner, clock, "bw2_expansion_slot", __FILE__), + device_slot_interface(mconfig, *this) +{ +} + + +//------------------------------------------------- +// bw2_expansion_slot_device - destructor +//------------------------------------------------- + +bw2_expansion_slot_device::~bw2_expansion_slot_device() +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void bw2_expansion_slot_device::device_start() +{ + m_cart = dynamic_cast(get_card_device()); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void bw2_expansion_slot_device::device_reset() +{ + if (m_cart != NULL) + { + m_cart->device().reset(); + } +} + + +//------------------------------------------------- +// cd_r - cartridge data read +//------------------------------------------------- + +UINT8 bw2_expansion_slot_device::cd_r(address_space &space, offs_t offset, UINT8 data, int ram2, int ram3, int ram4, int ram5, int ram6) +{ + if (m_cart != NULL) + { + data = m_cart->bw2_cd_r(space, offset, data, ram2, ram3, ram4, ram5, ram6); + } + + return data; +} + + +//------------------------------------------------- +// cd_w - cartridge data write +//------------------------------------------------- + +void bw2_expansion_slot_device::cd_w(address_space &space, offs_t offset, UINT8 data, int ram2, int ram3, int ram4, int ram5, int ram6) +{ + if (m_cart != NULL) + { + m_cart->bw2_cd_w(space, offset, data, ram2, ram3, ram4, ram5, ram6); + } +} + + +//------------------------------------------------- +// slot_r - slot read +//------------------------------------------------- + +READ8_MEMBER( bw2_expansion_slot_device::slot_r ) +{ + UINT8 data = 0xff; + + if (m_cart != NULL) + { + data = m_cart->bw2_slot_r(space, offset); + } + + return data; +} + + +//------------------------------------------------- +// slot_w - slot write +//------------------------------------------------- + +WRITE8_MEMBER( bw2_expansion_slot_device::slot_w ) +{ + if (m_cart != NULL) + { + m_cart->bw2_slot_w(space, offset, data); + } +} + + +//------------------------------------------------- +// modsel_r - modsel read +//------------------------------------------------- + +READ8_MEMBER( bw2_expansion_slot_device::modsel_r ) +{ + UINT8 data = 0xff; + + if (m_cart != NULL) + { + data = m_cart->bw2_modsel_r(space, offset); + } + + return data; +} + + +//------------------------------------------------- +// modsel_w - modsel write +//------------------------------------------------- + +WRITE8_MEMBER( bw2_expansion_slot_device::modsel_w ) +{ + if (m_cart != NULL) + { + m_cart->bw2_modsel_w(space, offset, data); + } +} + + + +//------------------------------------------------- +// SLOT_INTERFACE( bw2_expansion_cards ) +//------------------------------------------------- + +// slot devices +#include "ramcard.h" + +SLOT_INTERFACE_START( bw2_expansion_cards ) + SLOT_INTERFACE("ramcard", BW2_RAMCARD) +SLOT_INTERFACE_END diff --git a/src/devices/bus/bw2/exp.h b/src/devices/bus/bw2/exp.h new file mode 100644 index 00000000000..4d87f1d3ea1 --- /dev/null +++ b/src/devices/bus/bw2/exp.h @@ -0,0 +1,131 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Bondwell 2 Expansion Port emulation + +********************************************************************** + + 5V 1 26 12V + D3 2 27 12V + A1 3 28 A3 + A2 4 29 A4 + _CTSB 5 30 A5 + _RST 6 31 A6 + _MODSEL 7 32 A7 + 16MHZ 8 33 A8 + _IORQ 9 34 A9 + _RD 10 35 A10 + D0 11 36 A11 + D1 12 37 A12 + D2 13 38 A13 + A0 14 39 A14 + D4 15 40 _RAM6 + D5 16 41 _RAM5 + D6 17 42 _RFSH + D7 18 43 _WR + DCDB 19 44 SELECT + _DTRB 20 45 _RAM2 + _RTSB 21 46 _RAM3 + _DSRB 22 47 _RAM4 + TXDB 23 48 _SLOT + RXDB 24 49 GND + GND 25 50 5V + +**********************************************************************/ + +#pragma once + +#ifndef __BW2_EXPANSION_SLOT__ +#define __BW2_EXPANSION_SLOT__ + +#include "emu.h" + + + +//************************************************************************** +// CONSTANTS +//************************************************************************** + +#define BW2_EXPANSION_SLOT_TAG "exp" + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_BW2_EXPANSION_SLOT_ADD(_tag, _clock, _slot_intf, _def_slot) \ + MCFG_DEVICE_ADD(_tag, BW2_EXPANSION_SLOT, _clock) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> bw2_expansion_slot_device + +class device_bw2_expansion_slot_interface; + +class bw2_expansion_slot_device : public device_t, + public device_slot_interface +{ +public: + // construction/destruction + bw2_expansion_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual ~bw2_expansion_slot_device(); + + // computer interface + UINT8 cd_r(address_space &space, offs_t offset, UINT8 data, int ram2, int ram3, int ram4, int ram5, int ram6); + void cd_w(address_space &space, offs_t offset, UINT8 data, int ram2, int ram3, int ram4, int ram5, int ram6); + + DECLARE_READ8_MEMBER( slot_r ); + DECLARE_WRITE8_MEMBER( slot_w ); + + DECLARE_READ8_MEMBER( modsel_r ); + DECLARE_WRITE8_MEMBER( modsel_w ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + device_bw2_expansion_slot_interface *m_cart; +}; + + +// ======================> device_bw2_expansion_slot_interface + +// class representing interface-specific live bw2_expansion card +class device_bw2_expansion_slot_interface : public device_slot_card_interface +{ +public: + // construction/destruction + device_bw2_expansion_slot_interface(const machine_config &mconfig, device_t &device); + virtual ~device_bw2_expansion_slot_interface(); + + virtual UINT8 bw2_cd_r(address_space &space, offs_t offset, UINT8 data, int ram2, int ram3, int ram4, int ram5, int ram6) { return data; }; + virtual void bw2_cd_w(address_space &space, offs_t offset, UINT8 data, int ram2, int ram3, int ram4, int ram5, int ram6) { }; + + virtual UINT8 bw2_slot_r(address_space &space, offs_t offset) { return 0xff; } + virtual void bw2_slot_w(address_space &space, offs_t offset, UINT8 data) { } + + virtual UINT8 bw2_modsel_r(address_space &space, offs_t offset) { return 0xff; } + virtual void bw2_modsel_w(address_space &space, offs_t offset, UINT8 data) { } + +protected: + bw2_expansion_slot_device *m_slot; +}; + + +// device type definition +extern const device_type BW2_EXPANSION_SLOT; + + +SLOT_INTERFACE_EXTERN( bw2_expansion_cards ); + + + +#endif diff --git a/src/devices/bus/bw2/ramcard.c b/src/devices/bus/bw2/ramcard.c new file mode 100644 index 00000000000..16f5da689cc --- /dev/null +++ b/src/devices/bus/bw2/ramcard.c @@ -0,0 +1,126 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Bondwell 2 RAMCARD emulation + +**********************************************************************/ + +#include "ramcard.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type BW2_RAMCARD = &device_creator; + + +//------------------------------------------------- +// ROM( bw2_ramcard ) +//------------------------------------------------- + +ROM_START( bw2_ramcard ) + ROM_REGION( 0x4000, "ramcard", 0 ) + ROM_LOAD( "ramcard-10.ic10", 0x0000, 0x4000, CRC(68cde1ba) SHA1(a776a27d64f7b857565594beb63aa2cd692dcf04) ) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *bw2_ramcard_device::device_rom_region() const +{ + return ROM_NAME( bw2_ramcard ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// bw2_ramcard_device - constructor +//------------------------------------------------- + +bw2_ramcard_device::bw2_ramcard_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, BW2_RAMCARD, "RAMCARD", tag, owner, clock, "bw2_ramcard", __FILE__), + device_bw2_expansion_slot_interface(mconfig, *this), + m_rom(*this, "ramcard"), + m_ram(*this, "ram"), + m_en(0), + m_bank(0) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void bw2_ramcard_device::device_start() +{ + // allocate memory + m_ram.allocate(512 * 1024); + + // state saving + save_item(NAME(m_en)); + save_item(NAME(m_bank)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void bw2_ramcard_device::device_reset() +{ + m_en = 0; + m_bank = 0; +} + + +//------------------------------------------------- +// bw2_cd_r - cartridge data read +//------------------------------------------------- + +UINT8 bw2_ramcard_device::bw2_cd_r(address_space &space, offs_t offset, UINT8 data, int ram2, int ram3, int ram4, int ram5, int ram6) +{ + if (!ram2) + { + data = m_rom->base()[offset & 0x3fff]; + } + else if (m_en && !ram5) + { + data = m_ram[(m_bank << 15) | offset]; + } + + return data; +} + + +//------------------------------------------------- +// bw2_cd_r - cartridge data write +//------------------------------------------------- + +void bw2_ramcard_device::bw2_cd_w(address_space &space, offs_t offset, UINT8 data, int ram2, int ram3, int ram4, int ram5, int ram6) +{ + if (m_en && !ram5) + { + m_ram[(m_bank << 15) | offset] = data; + } +} + + +//------------------------------------------------- +// bw2_slot_w - slot write +//------------------------------------------------- + +void bw2_ramcard_device::bw2_slot_w(address_space &space, offs_t offset, UINT8 data) +{ + m_en = 1; + m_bank = data & 0x0f; +} diff --git a/src/devices/bus/bw2/ramcard.h b/src/devices/bus/bw2/ramcard.h new file mode 100644 index 00000000000..1d346370567 --- /dev/null +++ b/src/devices/bus/bw2/ramcard.h @@ -0,0 +1,59 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Bondwell 2 RAMCARD emulation + +**********************************************************************/ + +#pragma once + +#ifndef __BW2_RAMCARD__ +#define __BW2_RAMCARD__ + +#include "emu.h" +#include "exp.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> bw2_ramcard_device + +class bw2_ramcard_device : public device_t, + public device_bw2_expansion_slot_interface +{ +public: + // construction/destruction + bw2_ramcard_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_bw2_expansion_slot_interface overrides + virtual UINT8 bw2_cd_r(address_space &space, offs_t offset, UINT8 data, int ram2, int ram3, int ram4, int ram5, int ram6); + virtual void bw2_cd_w(address_space &space, offs_t offset, UINT8 data, int ram2, int ram3, int ram4, int ram5, int ram6); + virtual void bw2_slot_w(address_space &space, offs_t offset, UINT8 data); + +private: + required_memory_region m_rom; + optional_shared_ptr m_ram; + + int m_en; + UINT8 m_bank; +}; + + +// device type definition +extern const device_type BW2_RAMCARD; + + + +#endif diff --git a/src/devices/bus/c64/16kb.c b/src/devices/bus/c64/16kb.c new file mode 100644 index 00000000000..ff2ce6e3932 --- /dev/null +++ b/src/devices/bus/c64/16kb.c @@ -0,0 +1,124 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Commodore 64 16KB EPROM cartridge emulation + +**********************************************************************/ + +#include "16kb.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type C64_16KB = &device_creator; + + +//------------------------------------------------- +// MACHINE_CONFIG_FRAGMENT( c64_16kb ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( c64_16kb ) + MCFG_GENERIC_CARTSLOT_ADD("roml", generic_linear_slot, NULL) + MCFG_GENERIC_EXTENSIONS("rom,bin,80") + + MCFG_GENERIC_CARTSLOT_ADD("romh", generic_linear_slot, NULL) + MCFG_GENERIC_EXTENSIONS("rom,bin,a0,e0") +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor c64_16kb_cartridge_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( c64_16kb ); +} + + +//------------------------------------------------- +// INPUT_PORTS( c64_16kb ) +//------------------------------------------------- + +static INPUT_PORTS_START( c64_16kb ) + PORT_START("SW1") + PORT_DIPNAME( 0x03, 0x00, "Mode" ) + PORT_DIPSETTING( 0x03, "Off" ) + PORT_DIPSETTING( 0x02, "8 KB" ) + PORT_DIPSETTING( 0x00, "16 KB" ) + PORT_DIPSETTING( 0x01, "Ultimax" ) +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor c64_16kb_cartridge_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( c64_16kb ); +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// c64_16kb_cartridge_device - constructor +//------------------------------------------------- + +c64_16kb_cartridge_device::c64_16kb_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, C64_16KB, "C64 16KB EPROM cartridge", tag, owner, clock, "c64_16kb", __FILE__), + device_c64_expansion_card_interface(mconfig, *this), + m_sw1(*this, "SW1"), + m_low(*this, "roml"), + m_high(*this, "romh") +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void c64_16kb_cartridge_device::device_start() +{ +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void c64_16kb_cartridge_device::device_reset() +{ + UINT8 mode = m_sw1->read(); + + m_exrom = BIT(mode, 0); + m_game = BIT(mode, 1); +} + + +//------------------------------------------------- +// c64_cd_r - cartridge data read +//------------------------------------------------- + +UINT8 c64_16kb_cartridge_device::c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (!roml) + { + data = m_low->read_rom(space, offset & 0x1fff); + } + else if (!romh) + { + data = m_high->read_rom(space, offset & 0x1fff); + } + + return data; +} diff --git a/src/devices/bus/c64/16kb.h b/src/devices/bus/c64/16kb.h new file mode 100644 index 00000000000..6ebec5dca7e --- /dev/null +++ b/src/devices/bus/c64/16kb.h @@ -0,0 +1,59 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Commodore 64 16KB EPROM cartridge emulation + +**********************************************************************/ + +#pragma once + +#ifndef __C64_16KB__ +#define __C64_16KB__ + + +#include "emu.h" +#include "bus/generic/slot.h" +#include "bus/generic/carts.h" +#include "exp.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> c64_16kb_cartridge_device + +class c64_16kb_cartridge_device : public device_t, + public device_c64_expansion_card_interface +{ +public: + // construction/destruction + c64_16kb_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual ioport_constructor device_input_ports() const; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_c64_expansion_card_interface overrides + virtual UINT8 c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + +private: + required_ioport m_sw1; + required_device m_low; + required_device m_high; +}; + + +// device type definition +extern const device_type C64_16KB; + + + +#endif diff --git a/src/devices/bus/c64/4dxh.c b/src/devices/bus/c64/4dxh.c new file mode 100644 index 00000000000..2dd54543203 --- /dev/null +++ b/src/devices/bus/c64/4dxh.c @@ -0,0 +1,77 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/********************************************************************** + + The Digital Excess & Hitmen 4-Player Joystick adapter emulation + + http://hitmen.c02.at/html/hardware.html + +**********************************************************************/ + +#include "4dxh.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type C64_4DXH = &device_creator; + + +//------------------------------------------------- +// INPUT_PORTS( c64_4dxh ) +//------------------------------------------------- + +static INPUT_PORTS_START( c64_4dxh ) + PORT_START("SP2") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(2) PORT_WRITE_LINE_DEVICE_MEMBER(DEVICE_SELF, device_pet_user_port_interface, output_7) + + PORT_START("PB") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_8WAY PORT_PLAYER(1) PORT_WRITE_LINE_DEVICE_MEMBER(DEVICE_SELF, device_pet_user_port_interface, output_c) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_8WAY PORT_PLAYER(1) PORT_WRITE_LINE_DEVICE_MEMBER(DEVICE_SELF, device_pet_user_port_interface, output_d) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_8WAY PORT_PLAYER(1) PORT_WRITE_LINE_DEVICE_MEMBER(DEVICE_SELF, device_pet_user_port_interface, output_e) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_8WAY PORT_PLAYER(1) PORT_WRITE_LINE_DEVICE_MEMBER(DEVICE_SELF, device_pet_user_port_interface, output_f) + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_8WAY PORT_PLAYER(2) PORT_WRITE_LINE_DEVICE_MEMBER(DEVICE_SELF, device_pet_user_port_interface, output_h) + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_8WAY PORT_PLAYER(2) PORT_WRITE_LINE_DEVICE_MEMBER(DEVICE_SELF, device_pet_user_port_interface, output_j) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_8WAY PORT_PLAYER(2) PORT_WRITE_LINE_DEVICE_MEMBER(DEVICE_SELF, device_pet_user_port_interface, output_k) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_8WAY PORT_PLAYER(2) PORT_WRITE_LINE_DEVICE_MEMBER(DEVICE_SELF, device_pet_user_port_interface, output_l) + + PORT_START("PA2") + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(1) PORT_WRITE_LINE_DEVICE_MEMBER(DEVICE_SELF, device_pet_user_port_interface, output_m) +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor c64_4dxh_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( c64_4dxh ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// c64_4dxh_device - constructor +//------------------------------------------------- + +c64_4dxh_device::c64_4dxh_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, C64_4DXH, "C64 DXH 4-Player Adapter", tag, owner, clock, "c64_4dxh", __FILE__), + device_pet_user_port_interface(mconfig, *this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void c64_4dxh_device::device_start() +{ +} diff --git a/src/devices/bus/c64/4dxh.h b/src/devices/bus/c64/4dxh.h new file mode 100644 index 00000000000..3e99406ab89 --- /dev/null +++ b/src/devices/bus/c64/4dxh.h @@ -0,0 +1,50 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/********************************************************************** + + The Digital Excess & Hitmen 4-Player Joystick adapter emulation + +**********************************************************************/ + +#pragma once + +#ifndef __C64_4DXH__ +#define __C64_4DXH__ + + +#include "emu.h" +#include "user.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> c64_4dxh_device + +class c64_4dxh_device : public device_t, + public device_pet_user_port_interface +{ +public: + // construction/destruction + c64_4dxh_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual ioport_constructor device_input_ports() const; + + // device_pet_user_port_interface overrides + virtual WRITE_LINE_MEMBER( input_4 ) { output_6(state); } + virtual WRITE_LINE_MEMBER( input_6 ) { output_4(state); } + +protected: + // device-level overrides + virtual void device_start(); +}; + + +// device type definition +extern const device_type C64_4DXH; + + +#endif diff --git a/src/devices/bus/c64/4ksa.c b/src/devices/bus/c64/4ksa.c new file mode 100644 index 00000000000..749053fde32 --- /dev/null +++ b/src/devices/bus/c64/4ksa.c @@ -0,0 +1,77 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/********************************************************************** + + Kingsoft 4-Player Adapter emulation + + http://hitmen.c02.at/html/hardware.html + +**********************************************************************/ + +#include "4ksa.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type C64_4KSA = &device_creator; + + +//------------------------------------------------- +// INPUT_PORTS( c64_4ksa ) +//------------------------------------------------- + +static INPUT_PORTS_START( c64_4ksa ) + PORT_START("SP2") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(2) PORT_WRITE_LINE_DEVICE_MEMBER(DEVICE_SELF, device_pet_user_port_interface, output_7) + + PORT_START("PB") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_8WAY PORT_PLAYER(2) PORT_WRITE_LINE_DEVICE_MEMBER(DEVICE_SELF, device_pet_user_port_interface, output_c) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_8WAY PORT_PLAYER(2) PORT_WRITE_LINE_DEVICE_MEMBER(DEVICE_SELF, device_pet_user_port_interface, output_d) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_8WAY PORT_PLAYER(2) PORT_WRITE_LINE_DEVICE_MEMBER(DEVICE_SELF, device_pet_user_port_interface, output_e) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_8WAY PORT_PLAYER(2) PORT_WRITE_LINE_DEVICE_MEMBER(DEVICE_SELF, device_pet_user_port_interface, output_f) + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(1) PORT_WRITE_LINE_DEVICE_MEMBER(DEVICE_SELF, device_pet_user_port_interface, output_h) + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_8WAY PORT_PLAYER(1) PORT_WRITE_LINE_DEVICE_MEMBER(DEVICE_SELF, device_pet_user_port_interface, output_j) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_8WAY PORT_PLAYER(1) PORT_WRITE_LINE_DEVICE_MEMBER(DEVICE_SELF, device_pet_user_port_interface, output_k) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_8WAY PORT_PLAYER(1) PORT_WRITE_LINE_DEVICE_MEMBER(DEVICE_SELF, device_pet_user_port_interface, output_l) + + PORT_START("PA2") + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_8WAY PORT_PLAYER(1) PORT_WRITE_LINE_DEVICE_MEMBER(DEVICE_SELF, device_pet_user_port_interface, output_m) +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor c64_4ksa_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( c64_4ksa ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// c64_4ksa_device - constructor +//------------------------------------------------- + +c64_4ksa_device::c64_4ksa_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, C64_4KSA, "C64 Kingsoft 4-Player Adapter", tag, owner, clock, "c64_4ksa", __FILE__), + device_pet_user_port_interface(mconfig, *this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void c64_4ksa_device::device_start() +{ +} diff --git a/src/devices/bus/c64/4ksa.h b/src/devices/bus/c64/4ksa.h new file mode 100644 index 00000000000..8177922fb1e --- /dev/null +++ b/src/devices/bus/c64/4ksa.h @@ -0,0 +1,50 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/********************************************************************** + + Kingsoft 4-Player Adapter emulation + +**********************************************************************/ + +#pragma once + +#ifndef __C64_4KSA__ +#define __C64_4KSA__ + + +#include "emu.h" +#include "user.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> c64_4ksa_device + +class c64_4ksa_device : public device_t, + public device_pet_user_port_interface +{ +public: + // construction/destruction + c64_4ksa_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual ioport_constructor device_input_ports() const; + + // device_pet_user_port_interface overrides + virtual WRITE_LINE_MEMBER( input_4 ) { output_6(state); } + virtual WRITE_LINE_MEMBER( input_6 ) { output_4(state); } + +protected: + // device-level overrides + virtual void device_start(); +}; + + +// device type definition +extern const device_type C64_4KSA; + + +#endif diff --git a/src/devices/bus/c64/4tba.c b/src/devices/bus/c64/4tba.c new file mode 100644 index 00000000000..56266f5d916 --- /dev/null +++ b/src/devices/bus/c64/4tba.c @@ -0,0 +1,77 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/********************************************************************** + + Starbyte Software Tie Break Adaptor emulation + + http://hitmen.c02.at/html/hardware.html + +**********************************************************************/ + +#include "4tba.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type C64_4TBA = &device_creator; + + +//------------------------------------------------- +// INPUT_PORTS( c64_4tba ) +//------------------------------------------------- + +static INPUT_PORTS_START( c64_4tba ) + PORT_START("SP2") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(1) PORT_WRITE_LINE_DEVICE_MEMBER(DEVICE_SELF, device_pet_user_port_interface, output_7) + + PORT_START("PB") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_8WAY PORT_PLAYER(1) PORT_WRITE_LINE_DEVICE_MEMBER(DEVICE_SELF, device_pet_user_port_interface, output_c) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_8WAY PORT_PLAYER(1) PORT_WRITE_LINE_DEVICE_MEMBER(DEVICE_SELF, device_pet_user_port_interface, output_d) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_8WAY PORT_PLAYER(1) PORT_WRITE_LINE_DEVICE_MEMBER(DEVICE_SELF, device_pet_user_port_interface, output_e) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_8WAY PORT_PLAYER(1) PORT_WRITE_LINE_DEVICE_MEMBER(DEVICE_SELF, device_pet_user_port_interface, output_f) + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(2) PORT_WRITE_LINE_DEVICE_MEMBER(DEVICE_SELF, device_pet_user_port_interface, output_h) + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_8WAY PORT_PLAYER(2) PORT_WRITE_LINE_DEVICE_MEMBER(DEVICE_SELF, device_pet_user_port_interface, output_j) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_8WAY PORT_PLAYER(2) PORT_WRITE_LINE_DEVICE_MEMBER(DEVICE_SELF, device_pet_user_port_interface, output_k) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_8WAY PORT_PLAYER(2) PORT_WRITE_LINE_DEVICE_MEMBER(DEVICE_SELF, device_pet_user_port_interface, output_l) + + PORT_START("PA2") + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_8WAY PORT_PLAYER(2) PORT_WRITE_LINE_DEVICE_MEMBER(DEVICE_SELF, device_pet_user_port_interface, output_m) +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor c64_4tba_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( c64_4tba ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// c64_4tba_device - constructor +//------------------------------------------------- + +c64_4tba_device::c64_4tba_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, C64_4TBA, "C64 Tie Break Adapter", tag, owner, clock, "c64_4tba", __FILE__), + device_pet_user_port_interface(mconfig, *this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void c64_4tba_device::device_start() +{ +} diff --git a/src/devices/bus/c64/4tba.h b/src/devices/bus/c64/4tba.h new file mode 100644 index 00000000000..5b4329b5463 --- /dev/null +++ b/src/devices/bus/c64/4tba.h @@ -0,0 +1,50 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/********************************************************************** + + Starbyte Software Tie Break Adaptor emulation + +**********************************************************************/ + +#pragma once + +#ifndef __C64_4TBA__ +#define __C64_4TBA__ + + +#include "emu.h" +#include "user.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> c64_4tba_device + +class c64_4tba_device : public device_t, + public device_pet_user_port_interface +{ +public: + // construction/destruction + c64_4tba_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual ioport_constructor device_input_ports() const; + + // device_pet_user_port_interface overrides + virtual WRITE_LINE_MEMBER( input_4 ) { output_6(state); } + virtual WRITE_LINE_MEMBER( input_6 ) { output_4(state); } + +protected: + // device-level overrides + virtual void device_start(); +}; + + +// device type definition +extern const device_type C64_4TBA; + + +#endif diff --git a/src/devices/bus/c64/bn1541.c b/src/devices/bus/c64/bn1541.c new file mode 100644 index 00000000000..41e37f17fdd --- /dev/null +++ b/src/devices/bus/c64/bn1541.c @@ -0,0 +1,154 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder, smf +/********************************************************************** + + SpeedDOS / Burst Nibbler 1541/1571 Parallel Cable emulation + + http://sta.c64.org/cbmparc2.html + +**********************************************************************/ + +#include "bn1541.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define LOG 0 + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type C64_BN1541 = &device_creator; + + + +//************************************************************************** +// FLOPPY DRIVE INTERFACE +//************************************************************************** + +//------------------------------------------------- +// device_c64_floppy_parallel_interface - constructor +//------------------------------------------------- + +device_c64_floppy_parallel_interface::device_c64_floppy_parallel_interface(const machine_config &mconfig, device_t &device) : + m_other(NULL) +{ +} + + +//------------------------------------------------- +// ~device_c64_floppy_parallel_interface - destructor +//------------------------------------------------- + +device_c64_floppy_parallel_interface::~device_c64_floppy_parallel_interface() +{ +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// c64_bn1541_device - constructor +//------------------------------------------------- + +c64_bn1541_device::c64_bn1541_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, C64_BN1541, "C64 Burst Nibbler 1541/1571 Parallel Cable", tag, owner, clock, "c64_bn1541", __FILE__), + device_pet_user_port_interface(mconfig, *this), + device_c64_floppy_parallel_interface(mconfig, *this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void c64_bn1541_device::device_start() +{ + device_iterator iter(machine().root_device()); + + for (device_t *device = iter.first(); device != NULL; device = iter.next()) + { + device_iterator subiter(*device); + + for (device_t *subdevice = subiter.first(); subdevice != NULL; subdevice = iter.next()) + { + if (subdevice->interface(m_other) && subdevice != this) + { + if (LOG) logerror("Parallel device %s\n", subdevice->tag()); + + // grab the first 1541/1571 and run to the hills + m_other->m_other = this; + return; + } + } + } +} + + +//------------------------------------------------- +// parallel_data_w - +//------------------------------------------------- + +void c64_bn1541_device::parallel_data_w(UINT8 data) +{ + if (LOG) logerror("1541 parallel data %02x\n", data); + + output_c((data>>0)&1); + output_d((data>>1)&1); + output_e((data>>2)&1); + output_f((data>>3)&1); + output_h((data>>4)&1); + output_j((data>>5)&1); + output_k((data>>6)&1); + output_l((data>>7)&1); +} + + +//------------------------------------------------- +// parallel_strobe_w - +//------------------------------------------------- + +void c64_bn1541_device::parallel_strobe_w(int state) +{ + if (LOG) logerror("1541 parallel strobe %u\n", state); + + output_b(state); +} + + +//------------------------------------------------- +// update_output +//------------------------------------------------- + +void c64_bn1541_device::update_output() +{ + if (m_other != NULL) + { + m_other->parallel_data_w(m_parallel_output); + } +} + + +//------------------------------------------------- +// input_8 - CIA2 PC write +//------------------------------------------------- + +WRITE_LINE_MEMBER(c64_bn1541_device::input_8) +{ + if (LOG) logerror("C64 parallel strobe %u\n", state); + + if (m_other != NULL) + { + m_other->parallel_strobe_w(state); + } +} diff --git a/src/devices/bus/c64/bn1541.h b/src/devices/bus/c64/bn1541.h new file mode 100644 index 00000000000..3ad7aee1c87 --- /dev/null +++ b/src/devices/bus/c64/bn1541.h @@ -0,0 +1,82 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder, smf +/********************************************************************** + + SpeedDOS / Burst Nibbler 1541/1571 Parallel Cable emulation + +**********************************************************************/ + +#pragma once + +#ifndef __C64_BN1541__ +#define __C64_BN1541__ + + +#include "emu.h" +#include "user.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> device_c64_floppy_parallel_interface + +class device_c64_floppy_parallel_interface +{ +public: + // construction/destruction + device_c64_floppy_parallel_interface(const machine_config &mconfig, device_t &device); + virtual ~device_c64_floppy_parallel_interface(); + + virtual void parallel_data_w(UINT8 data) = 0; + virtual void parallel_strobe_w(int state) = 0; + + device_c64_floppy_parallel_interface *m_other; + +protected: + UINT8 m_parallel_data; +}; + + +// ======================> c64_bn1541_device + +class c64_bn1541_device : public device_t, + public device_pet_user_port_interface, + public device_c64_floppy_parallel_interface +{ +public: + // construction/destruction + c64_bn1541_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // device-level overrides + virtual void device_start(); + + // device_c64_floppy_parallel_interface overrides + virtual void parallel_data_w(UINT8 data); + virtual void parallel_strobe_w(int state); + + // device_pet_user_port_interface overrides + virtual DECLARE_WRITE_LINE_MEMBER(input_8); + virtual WRITE_LINE_MEMBER(input_c) { if (state) m_parallel_output |= 1; else m_parallel_output &= ~1; update_output(); } + virtual WRITE_LINE_MEMBER(input_d) { if (state) m_parallel_output |= 2; else m_parallel_output &= ~2; update_output(); } + virtual WRITE_LINE_MEMBER(input_e) { if (state) m_parallel_output |= 4; else m_parallel_output &= ~4; update_output(); } + virtual WRITE_LINE_MEMBER(input_f) { if (state) m_parallel_output |= 8; else m_parallel_output &= ~8; update_output(); } + virtual WRITE_LINE_MEMBER(input_h) { if (state) m_parallel_output |= 16; else m_parallel_output &= ~16; update_output(); } + virtual WRITE_LINE_MEMBER(input_j) { if (state) m_parallel_output |= 32; else m_parallel_output &= ~32; update_output(); } + virtual WRITE_LINE_MEMBER(input_k) { if (state) m_parallel_output |= 64; else m_parallel_output &= ~64; update_output(); } + virtual WRITE_LINE_MEMBER(input_l) { if (state) m_parallel_output |= 128; else m_parallel_output &= ~128; update_output(); } + +private: + void update_output(); + UINT8 m_parallel_output; +}; + + +// device type definition +extern const device_type C64_BN1541; + + +#endif diff --git a/src/devices/bus/c64/c128_comal80.c b/src/devices/bus/c64/c128_comal80.c new file mode 100644 index 00000000000..25accd52fa0 --- /dev/null +++ b/src/devices/bus/c64/c128_comal80.c @@ -0,0 +1,103 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Commodore 128 COMAL 80 cartridge emulation + +**********************************************************************/ + +#include "c128_comal80.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type C128_COMAL80 = &device_creator; + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// c128_comal80_cartridge_device - constructor +//------------------------------------------------- + +c128_comal80_cartridge_device::c128_comal80_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, C128_COMAL80, "C128 COMAL 80 cartridge", tag, owner, clock, "c128_comal80", __FILE__), + device_c64_expansion_card_interface(mconfig, *this), + m_bank(0) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void c128_comal80_cartridge_device::device_start() +{ + // state saving + save_item(NAME(m_bank)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void c128_comal80_cartridge_device::device_reset() +{ + m_bank = 0; +} + + +//------------------------------------------------- +// c64_cd_r - cartridge data read +//------------------------------------------------- + +UINT8 c128_comal80_cartridge_device::c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (!romh) + { + offs_t addr = ((m_bank & 0x07) << 14) | (offset & 0x3fff); + data = m_romh[addr]; + } + else if (!io1) + { + data = (m_bank << 4) | (data & 0x0f); + } + + return data; +} + + +//------------------------------------------------- +// c64_cd_w - cartridge data write +//------------------------------------------------- + +void c128_comal80_cartridge_device::c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (!io1) + { + /* + + bit description + + 0 + 1 + 2 + 3 + 4 A14 + 5 A15 + 6 A16 + 7 A17 + + */ + + m_bank = data >> 4; + } +} diff --git a/src/devices/bus/c64/c128_comal80.h b/src/devices/bus/c64/c128_comal80.h new file mode 100644 index 00000000000..de7cfc862de --- /dev/null +++ b/src/devices/bus/c64/c128_comal80.h @@ -0,0 +1,51 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Commodore 128 COMAL 80 cartridge emulation + +**********************************************************************/ + +#pragma once + +#ifndef __C128_COMAL80__ +#define __C128_COMAL80__ + + +#include "emu.h" +#include "exp.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> c128_comal80_cartridge_device + +class c128_comal80_cartridge_device : public device_t, + public device_c64_expansion_card_interface +{ +public: + // construction/destruction + c128_comal80_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_c64_expansion_card_interface overrides + virtual UINT8 c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + virtual void c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + +private: + UINT8 m_bank; +}; + + +// device type definition +extern const device_type C128_COMAL80; + + +#endif diff --git a/src/devices/bus/c64/c128_partner.c b/src/devices/bus/c64/c128_partner.c new file mode 100644 index 00000000000..00f5a8e2cb9 --- /dev/null +++ b/src/devices/bus/c64/c128_partner.c @@ -0,0 +1,250 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Timeworks PARTNER 128 cartridge emulation + +**********************************************************************/ + +/* + + PCB Layout + ---------- + + |---------------| + |LS74 SW * | + |LS09 LS273| + |LS139 RAM | + |LS133 | + | LS240 | + |LS33 ROM | + |LS09 | + ||||||||||||||| + + ROM - Toshiba TMM24128AP 16Kx8 EPROM (blank label) + RAM - Sony CXK5864PN-15L 8Kx8 SRAM + SW - push button switch + * - solder point for joystick port dongle + +*/ + +#include "c128_partner.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type C128_PARTNER = &device_creator; + + +//------------------------------------------------- +// INPUT_PORTS( c128_partner ) +//------------------------------------------------- + +WRITE_LINE_MEMBER( partner128_t::nmi_w ) +{ + if (state) + { + m_ls74_q1 = 1; + } +} + +static INPUT_PORTS_START( c128_partner ) + PORT_START("NMI") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Menu") PORT_CODE(KEYCODE_END) PORT_WRITE_LINE_DEVICE_MEMBER(DEVICE_SELF, partner128_t, nmi_w) +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor partner128_t::device_input_ports() const +{ + return INPUT_PORTS_NAME( c128_partner ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// partner128_t - constructor +//------------------------------------------------- + +partner128_t::partner128_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, C128_PARTNER, "PARTNER 128", tag, owner, clock, "c128_partner", __FILE__), + device_c64_expansion_card_interface(mconfig, *this), + //device_vcs_control_port_interface(mconfig, *this), + m_ram(*this, "ram"), + m_ram_a12_a7(0), + m_ls74_cd(0), + m_ls74_q1(0), + m_ls74_q2(0), + m_joyb2(0) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void partner128_t::device_start() +{ + // allocate memory + m_ram.allocate(0x2000); + + // simulate the 16.7ms pulse from CIA1 PB2 that would arrive thru the joystick port dongle + t_joyb2 = timer_alloc(); + t_joyb2->adjust(attotime::from_msec(16), 0, attotime::from_msec(16)); + + // state saving + save_item(NAME(m_ram_a12_a7)); + save_item(NAME(m_ls74_cd)); + save_item(NAME(m_ls74_q1)); + save_item(NAME(m_ls74_q2)); + save_item(NAME(m_joyb2)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void partner128_t::device_reset() +{ + m_ram_a12_a7 = 0; + + m_ls74_cd = 0; + m_ls74_q1 = 0; + m_ls74_q2 = 0; + + nmi_w(CLEAR_LINE); +} + + +//------------------------------------------------- +// device_timer - +//------------------------------------------------- + +void partner128_t::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + if (m_ls74_cd) + { + m_ls74_q2 = m_ls74_q1; + + nmi_w(m_ls74_q2 ? ASSERT_LINE : CLEAR_LINE); + } +} + + +//------------------------------------------------- +// c64_cd_r - cartridge data read +//------------------------------------------------- + +UINT8 partner128_t::c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (!roml) + { + data = m_roml[offset & 0x3fff]; + } + + if (!io1) + { + if (BIT(offset, 7)) + { + data = m_roml[offset & 0x3fff]; + + if (m_ls74_cd) + { + m_ls74_q1 = 0; + } + } + else + { + data = m_ram[(m_ram_a12_a7 << 7) | (offset & 0x7f)]; + } + } + + if (m_ls74_q2 && ((offset & 0xfffa) == 0xfffa)) + { + // override the 8502 NMI/IRQ vectors with 0xdede + data = 0xde; + } + + return data; +} + + +//------------------------------------------------- +// c64_cd_w - cartridge data write +//------------------------------------------------- + +void partner128_t::c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (!io1) + { + if (BIT(offset, 7)) + { + /* + + bit description + + 0 RAM A7 + 1 RAM A8 + 2 RAM A9 + 3 RAM A10 + 4 RAM A11 + 5 RAM A12 + 6 LS74 1Cd,2Cd + 7 N/C + + */ + + m_ram_a12_a7 = data & 0x3f; + + m_ls74_cd = BIT(data, 6); + + if (!m_ls74_cd) + { + m_ls74_q1 = 0; + m_ls74_q2 = 0; + + nmi_w(CLEAR_LINE); + } + } + else + { + m_ram[(m_ram_a12_a7 << 7) | (offset & 0x7f)] = data; + } + } + + if (sphi2 && ((offset & 0xfff0) == 0xd600)) + { + m_ram[(m_ram_a12_a7 << 7) | (offset & 0x7f)] = data; + } +} + + +//------------------------------------------------- +// vcs_joy_w - joystick write +//------------------------------------------------- + +void partner128_t::vcs_joy_w(UINT8 data) +{ + int joyb2 = BIT(data, 2); + + if (!m_joyb2 && joyb2 && m_ls74_cd) + { + m_ls74_q2 = m_ls74_q1; + + nmi_w(m_ls74_q2 ? ASSERT_LINE : CLEAR_LINE); + } + + m_joyb2 = joyb2; +} diff --git a/src/devices/bus/c64/c128_partner.h b/src/devices/bus/c64/c128_partner.h new file mode 100644 index 00000000000..2210cdc7388 --- /dev/null +++ b/src/devices/bus/c64/c128_partner.h @@ -0,0 +1,68 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Timeworks PARTNER 128 cartridge emulation + +**********************************************************************/ + +#pragma once + +#ifndef __C128_PARTNER__ +#define __C128_PARTNER__ + +#include "emu.h" +#include "bus/c64/exp.h" +#include "bus/vcs_ctrl/ctrl.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> partner128_t + +class partner128_t : public device_t, + public device_c64_expansion_card_interface + //public device_vcs_control_port_interface +{ +public: + // construction/destruction + partner128_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual ioport_constructor device_input_ports() const; + + DECLARE_WRITE_LINE_MEMBER( nmi_w ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + // device_c64_expansion_card_interface overrides + virtual UINT8 c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + virtual void c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + + // device_vcs_control_port_interface overrides + virtual void vcs_joy_w(UINT8 data); + +private: + optional_shared_ptr m_ram; + + emu_timer *t_joyb2; + int m_ram_a12_a7; + int m_ls74_cd; + int m_ls74_q1; + int m_ls74_q2; + int m_joyb2; +}; + + +// device type definition +extern const device_type C128_PARTNER; + + +#endif diff --git a/src/devices/bus/c64/comal80.c b/src/devices/bus/c64/comal80.c new file mode 100644 index 00000000000..ee8ffe0d6fd --- /dev/null +++ b/src/devices/bus/c64/comal80.c @@ -0,0 +1,86 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + COMAL 80 cartridge emulation + +**********************************************************************/ + +#include "comal80.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type C64_COMAL80 = &device_creator; + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// c64_comal80_cartridge_device - constructor +//------------------------------------------------- + +c64_comal80_cartridge_device::c64_comal80_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, C64_COMAL80, "C64 COMAL 80 cartridge", tag, owner, clock, "c64_comal80", __FILE__), + device_c64_expansion_card_interface(mconfig, *this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void c64_comal80_cartridge_device::device_start() +{ + // state saving + save_item(NAME(m_bank)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void c64_comal80_cartridge_device::device_reset() +{ + m_bank = 0; +} + + +//------------------------------------------------- +// c64_cd_r - cartridge data read +//------------------------------------------------- + +UINT8 c64_comal80_cartridge_device::c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (!roml || !romh) + { + offs_t addr = (m_bank << 14) | (offset & 0x3fff); + data = m_roml[addr]; + } + + return data; +} + + +//------------------------------------------------- +// c64_cd_w - cartridge data write +//------------------------------------------------- + +void c64_comal80_cartridge_device::c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (!io1) + { + if (BIT(data, 7)) + { + m_bank = data & 0x03; + } + } +} diff --git a/src/devices/bus/c64/comal80.h b/src/devices/bus/c64/comal80.h new file mode 100644 index 00000000000..766b6ed10d7 --- /dev/null +++ b/src/devices/bus/c64/comal80.h @@ -0,0 +1,51 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + COMAL 80 cartridge emulation + +**********************************************************************/ + +#pragma once + +#ifndef __COMAL80__ +#define __COMAL80__ + + +#include "emu.h" +#include "exp.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> c64_comal80_cartridge_device + +class c64_comal80_cartridge_device : public device_t, + public device_c64_expansion_card_interface +{ +public: + // construction/destruction + c64_comal80_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_c64_expansion_card_interface overrides + virtual UINT8 c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + virtual void c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + +private: + UINT8 m_bank; +}; + + +// device type definition +extern const device_type C64_COMAL80; + + +#endif diff --git a/src/devices/bus/c64/cpm.c b/src/devices/bus/c64/cpm.c new file mode 100644 index 00000000000..1533ab9f93b --- /dev/null +++ b/src/devices/bus/c64/cpm.c @@ -0,0 +1,230 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Commodore 64 CP/M cartridge emulation + + http://www.baltissen.org/newhtm/c64_cpm.htm + +**********************************************************************/ + +/* + + TODO: + + - Z80 clock speed + +*/ + +#include "cpm.h" + + + +//************************************************************************** +// MACROS/CONSTANTS +//************************************************************************** + +#define Z80_TAG "z80" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type C64_CPM = &device_creator; + + +//------------------------------------------------- +// ADDRESS_MAP( z80_mem ) +//------------------------------------------------- + +static ADDRESS_MAP_START( z80_mem, AS_PROGRAM, 8, c64_cpm_cartridge_device ) + AM_RANGE(0x0000, 0xffff) AM_READWRITE(dma_r, dma_w) +ADDRESS_MAP_END + + +//------------------------------------------------- +// ADDRESS_MAP( z80_io ) +//------------------------------------------------- + +static ADDRESS_MAP_START( z80_io, AS_IO, 8, c64_cpm_cartridge_device ) + AM_RANGE(0x0000, 0xffff) AM_READWRITE(dma_r, dma_w) +ADDRESS_MAP_END + + +//------------------------------------------------- +// MACHINE_CONFIG_FRAGMENT( c64_cpm ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( c64_cpm ) + MCFG_CPU_ADD(Z80_TAG, Z80, 3000000) + MCFG_CPU_PROGRAM_MAP(z80_mem) + MCFG_CPU_IO_MAP(z80_io) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor c64_cpm_cartridge_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( c64_cpm ); +} + + + +//************************************************************************** +// INLINE HELPERS +//************************************************************************** + +//------------------------------------------------- +// update_signals - +//------------------------------------------------- + +inline void c64_cpm_cartridge_device::update_signals() +{ + if (m_enabled) + { + m_maincpu->set_input_line(INPUT_LINE_HALT, CLEAR_LINE); + m_slot->dma_w(ASSERT_LINE); + + if (m_reset) + { + m_maincpu->reset(); + m_maincpu->set_state_int(Z80_PC, 0); + m_reset = 0; + } + } + else + { + m_maincpu->set_input_line(INPUT_LINE_HALT, ASSERT_LINE); + m_slot->dma_w(CLEAR_LINE); + } + +/* + // NOTE: the following is how it actually works once the Z80 core has been rewritten + + // C64 DMA + m_slot->dma_w(m_enabled ? ASSERT_LINE : CLEAR_LINE); + + // Z80 BUSRQ + int busrq = !(m_enabled & !m_ba) ? CLEAR_LINE : ASSERT_LINE; + m_maincpu->set_input_line(Z80_INPUT_LINE_BUSRQ, busrq); + + // Z80 WAIT + m_maincpu->set_input_line(Z80_INPUT_LINE_WAIT, m_enabled ? CLEAR_LINE : ASSERT_LINE); +*/ +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// c64_cpm_cartridge_device - constructor +//------------------------------------------------- + +c64_cpm_cartridge_device::c64_cpm_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, C64_CPM, "C64 CP/M cartridge", tag, owner, clock, "c64_cpm", __FILE__), + device_c64_expansion_card_interface(mconfig, *this), + m_maincpu(*this, Z80_TAG), + m_enabled(0), + m_ba(1) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void c64_cpm_cartridge_device::device_start() +{ + // state saving + save_item(NAME(m_enabled)); + save_item(NAME(m_ba)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void c64_cpm_cartridge_device::device_reset() +{ + m_enabled = 0; + m_reset = 1; + + update_signals(); +} + + +//------------------------------------------------- +// c64_cd_w - cartridge data write +//------------------------------------------------- + +void c64_cpm_cartridge_device::c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (!io1) + { + m_enabled = !BIT(data, 0); + + update_signals(); + } +} + + +//------------------------------------------------- +// c64_game_r - GAME read +//------------------------------------------------- + +int c64_cpm_cartridge_device::c64_game_r(offs_t offset, int sphi2, int ba, int rw) +{ + if (m_ba != ba) + { + m_ba = ba; + + update_signals(); + } + + return 1; +} + + +//------------------------------------------------- +// dma_r - +//------------------------------------------------- + +READ8_MEMBER( c64_cpm_cartridge_device::dma_r ) +{ + UINT8 data = 0xff; + + if (m_enabled) + { + offs_t addr = (offset + 0x1000) & 0xffff; + + data = m_slot->dma_cd_r(space, addr); + } + + return data; +} + + +//------------------------------------------------- +// dma_w - +//------------------------------------------------- + +WRITE8_MEMBER( c64_cpm_cartridge_device::dma_w ) +{ + if (m_enabled) + { + offs_t addr = (offset + 0x1000) & 0xffff; + + m_slot->dma_cd_w(space, addr, data); + } +} diff --git a/src/devices/bus/c64/cpm.h b/src/devices/bus/c64/cpm.h new file mode 100644 index 00000000000..67e7495d027 --- /dev/null +++ b/src/devices/bus/c64/cpm.h @@ -0,0 +1,65 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Commodore 64 CP/M cartridge emulation + +**********************************************************************/ + +#pragma once + +#ifndef __CPM__ +#define __CPM__ + +#include "emu.h" +#include "cpu/z80/z80.h" +#include "exp.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> c64_cpm_cartridge_device + +class c64_cpm_cartridge_device : public device_t, + public device_c64_expansion_card_interface +{ +public: + // construction/destruction + c64_cpm_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + + // not really public + DECLARE_READ8_MEMBER( dma_r ); + DECLARE_WRITE8_MEMBER( dma_w ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_c64_expansion_card_interface overrides + virtual void c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + virtual int c64_game_r(offs_t offset, int sphi2, int ba, int rw); + +private: + inline void update_signals(); + + required_device m_maincpu; + + int m_enabled; + int m_ba; + + int m_reset; +}; + + +// device type definition +extern const device_type C64_CPM; + + +#endif diff --git a/src/devices/bus/c64/currah_speech.c b/src/devices/bus/c64/currah_speech.c new file mode 100644 index 00000000000..8e73f0801f1 --- /dev/null +++ b/src/devices/bus/c64/currah_speech.c @@ -0,0 +1,255 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Currah Speech 64 cartridge emulation + +**********************************************************************/ + +/* + +PCB Layout +---------- + +|===========================| +|=| | +|=| VLSI | +|=| | +|=| | +|=| ROM | +|=| | +|=| | +|=| SP0256 | +|===========================| + +Notes: + All IC's shown. + + VLSI - General Instruments LA05-164 custom + ROM - General Instruments R09864CS-2030 8Kx8 ROM "778R01" + SP0256 - General Instruments SP0256A-AL2 Speech Synthesizer + + +LA05-164 Pinout +--------------- + _____ _____ +DOTCLK 1 |* \_/ | 28 +5V + CA7 2 | | 27 CD7 + CA6 3 | | 26 CA8 + CA5 4 | | 25 CA9 + CA4 5 | | 24 CA11 + CA3 6 | | 23 BA + CA2 7 | LA05-164 | 22 CA10 + CA1 8 | | 21 SP0256 _ALD + CA0 9 | | 20 SP0256 OSC1 + 10 | | 19 SP0256 SBY +_GA+EX 11 | | 18 CA15 + I/O1 12 | | 17 CA12 + _CR/W 13 | | 16 CA13 + GND 14 |_____________| 15 CA14 + +Notes: + _GA+EX - _GAME and _EXROM tied together + +*/ + +/* + + BASIC Commands + -------------- + + INIT Initialize the cartridge + BYE Disable the cartridge + KON 0 Enable keyvoices, low voice + KON 1 Enable keyvoices, high voice + KOFF Disable keyvoices + SAY 0/1 "" Say words + +*/ + +#include "currah_speech.h" + + + +//************************************************************************** +// MACROS/CONSTANTS +//************************************************************************** + +#define SP0256_TAG "sp0256" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type C64_CURRAH_SPEECH = &device_creator; + + +//------------------------------------------------- +// ROM( c64_currah_speech ) +//------------------------------------------------- + +ROM_START( c64_currah_speech ) + ROM_REGION( 0x10000, SP0256_TAG, 0 ) + ROM_LOAD( "sp0256a-al2", 0x1000, 0x0800, CRC(b504ac15) SHA1(e60fcb5fa16ff3f3b69d36c7a6e955744d3feafc) ) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *c64_currah_speech_cartridge_device::device_rom_region() const +{ + return ROM_NAME( c64_currah_speech ); +} + +//------------------------------------------------- +// MACHINE_CONFIG_FRAGMENT( c64_currah_speech ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( c64_currah_speech ) + MCFG_SPEAKER_STANDARD_MONO("mono") + MCFG_SOUND_ADD(SP0256_TAG, SP0256, 4000000) // ??? + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 1.00) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor c64_currah_speech_cartridge_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( c64_currah_speech ); +} + + + +//************************************************************************** +// INLINE HELPERS +//************************************************************************** + +//------------------------------------------------- +// set_osc1 - +//------------------------------------------------- + +void c64_currah_speech_cartridge_device::set_osc1(int voice, int intonation) +{ + int dotclock = m_slot->dotclock(); + + // TODO intonation and correct dividers + m_nsp->set_clock(dotclock / (2 << voice)); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// c64_currah_speech_cartridge_device - constructor +//------------------------------------------------- + +c64_currah_speech_cartridge_device::c64_currah_speech_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, C64_CURRAH_SPEECH, "C64 Currah Speech", tag, owner, clock, "c64_cs", __FILE__), + device_c64_expansion_card_interface(mconfig, *this), + m_nsp(*this, SP0256_TAG) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void c64_currah_speech_cartridge_device::device_start() +{ +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void c64_currah_speech_cartridge_device::device_reset() +{ + m_game = 1; + m_exrom = 1; +} + + +//------------------------------------------------- +// c64_cd_r - cartridge data read +//------------------------------------------------- + +UINT8 c64_currah_speech_cartridge_device::c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (!romh) + { + data = m_romh[offset & 0x1fff]; + } + else if (!io1) + { + /* + + bit description + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 SBY + + */ + + data = m_nsp->sby_r() << 7; + } + + if (!space.debugger_access() && (offset == 0xa7f0)) + { + m_game = !m_game; + m_exrom = !m_exrom; + } + + return data; +} + + +//------------------------------------------------- +// c64_cd_w - cartridge data write +//------------------------------------------------- + +void c64_currah_speech_cartridge_device::c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (!io1) + { + /* + + bit description + + 0 A1 + 1 A2 + 2 A3 + 3 A4 + 4 A5 + 5 A6 + 6 + 7 intonation + + */ + + int voice = BIT(offset, 0); + int intonation = BIT(data, 7); + + set_osc1(voice, intonation); + + m_nsp->ald_w(space, 0, data & 0x3f); + } +} diff --git a/src/devices/bus/c64/currah_speech.h b/src/devices/bus/c64/currah_speech.h new file mode 100644 index 00000000000..db687704252 --- /dev/null +++ b/src/devices/bus/c64/currah_speech.h @@ -0,0 +1,58 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Currah Speech 64 cartridge emulation + +**********************************************************************/ + +#pragma once + +#ifndef __CURRAH_SPEECH_64__ +#define __CURRAH_SPEECH_64__ + + +#include "emu.h" +#include "exp.h" +#include "sound/sp0256.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> c64_currah_speech_cartridge_device + +class c64_currah_speech_cartridge_device : public device_t, + public device_c64_expansion_card_interface +{ +public: + // construction/destruction + c64_currah_speech_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_c64_expansion_card_interface overrides + virtual UINT8 c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + virtual void c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + +private: + inline void set_osc1(int voice, int intonation); + + required_device m_nsp; +}; + + +// device type definition +extern const device_type C64_CURRAH_SPEECH; + + +#endif diff --git a/src/devices/bus/c64/dela_ep256.c b/src/devices/bus/c64/dela_ep256.c new file mode 100644 index 00000000000..b4708e13856 --- /dev/null +++ b/src/devices/bus/c64/dela_ep256.c @@ -0,0 +1,156 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Dela 256KB EPROM cartridge emulation + +**********************************************************************/ + +#include "dela_ep256.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type C64_DELA_EP256 = &device_creator; + + +//------------------------------------------------- +// MACHINE_CONFIG_FRAGMENT( c64_dela_ep256 ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( c64_dela_ep256 ) + MCFG_GENERIC_SOCKET_ADD("rom1", generic_linear_slot, NULL) + MCFG_GENERIC_EXTENSIONS("bin,rom") + MCFG_GENERIC_SOCKET_ADD("rom2", generic_linear_slot, NULL) + MCFG_GENERIC_EXTENSIONS("bin,rom") + MCFG_GENERIC_SOCKET_ADD("rom3", generic_linear_slot, NULL) + MCFG_GENERIC_EXTENSIONS("bin,rom") + MCFG_GENERIC_SOCKET_ADD("rom4", generic_linear_slot, NULL) + MCFG_GENERIC_EXTENSIONS("bin,rom") + MCFG_GENERIC_SOCKET_ADD("rom5", generic_linear_slot, NULL) + MCFG_GENERIC_EXTENSIONS("bin,rom") + MCFG_GENERIC_SOCKET_ADD("rom6", generic_linear_slot, NULL) + MCFG_GENERIC_EXTENSIONS("bin,rom") + MCFG_GENERIC_SOCKET_ADD("rom7", generic_linear_slot, NULL) + MCFG_GENERIC_EXTENSIONS("bin,rom") + MCFG_GENERIC_SOCKET_ADD("rom8", generic_linear_slot, NULL) + MCFG_GENERIC_EXTENSIONS("bin,rom") +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor c64_dela_ep256_cartridge_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( c64_dela_ep256 ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// c64_dela_ep256_cartridge_device - constructor +//------------------------------------------------- + +c64_dela_ep256_cartridge_device::c64_dela_ep256_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, C64_DELA_EP256, "C64 Dela 256KB EPROM cartridge", tag, owner, clock, "delep256", __FILE__), + device_c64_expansion_card_interface(mconfig, *this) +{ + for (int i = 0; i < 8; i++) + { + char str[6]; + sprintf(str, "rom%i", i + 1); + m_eproms[i] = subdevice(str); + } +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void c64_dela_ep256_cartridge_device::device_start() +{ + // state saving + save_item(NAME(m_bank)); + save_item(NAME(m_reset)); + save_item(NAME(m_socket)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void c64_dela_ep256_cartridge_device::device_reset() +{ + m_reset = 1; + m_bank = 0; + m_exrom = 0; + m_socket = 0; +} + + +//------------------------------------------------- +// c64_cd_r - cartridge data read +//------------------------------------------------- + +UINT8 c64_dela_ep256_cartridge_device::c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (!roml) + { + if (m_reset) + { + data = m_roml[offset & 0x1fff]; + } + else + { + offs_t addr = (m_bank << 13) | (offset & 0x1fff); + data = m_eproms[m_socket]->read_rom(space, addr); + } + } + + return data; +} + + +//------------------------------------------------- +// c64_cd_w - cartridge data write +//------------------------------------------------- + +void c64_dela_ep256_cartridge_device::c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (!io2 && ((offset & 0xf0) == 0xa0)) + { + /* + + bit description + + 0 socket selection bit 0 + 1 socket selection bit 1 + 2 socket selection bit 2 + 3 + 4 bank selection bit 0 + 5 bank selection bit 1 + 6 + 7 EXROM + + */ + + m_reset = 0; + + m_socket = data & 0x07; + m_bank = (data >> 4) & 0x03; + + m_exrom = BIT(data, 7); + } +} diff --git a/src/devices/bus/c64/dela_ep256.h b/src/devices/bus/c64/dela_ep256.h new file mode 100644 index 00000000000..8cae8b25b25 --- /dev/null +++ b/src/devices/bus/c64/dela_ep256.h @@ -0,0 +1,60 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Dela 256KB EPROM cartridge emulation + +**********************************************************************/ + +#pragma once + +#ifndef __DELA_EP256__ +#define __DELA_EP256__ + + +#include "emu.h" +#include "exp.h" +#include "bus/generic/slot.h" +#include "bus/generic/carts.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> c64_dela_ep256_cartridge_device + +class c64_dela_ep256_cartridge_device : public device_t, + public device_c64_expansion_card_interface +{ +public: + // construction/destruction + c64_dela_ep256_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_c64_expansion_card_interface overrides + virtual UINT8 c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + virtual void c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + +private: + generic_slot_device *m_eproms[8]; + + UINT8 m_bank, m_socket; + int m_reset; +}; + + +// device type definition +extern const device_type C64_DELA_EP256; + + + +#endif diff --git a/src/devices/bus/c64/dela_ep64.c b/src/devices/bus/c64/dela_ep64.c new file mode 100644 index 00000000000..006b915908f --- /dev/null +++ b/src/devices/bus/c64/dela_ep64.c @@ -0,0 +1,146 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Dela 64KB EPROM cartridge emulation + +**********************************************************************/ + +#include "dela_ep64.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type C64_DELA_EP64 = &device_creator; + + +//------------------------------------------------- +// MACHINE_CONFIG_FRAGMENT( c64_dela_ep64 ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( c64_dela_ep64 ) + MCFG_GENERIC_SOCKET_ADD("eprom1", generic_linear_slot, NULL) + MCFG_GENERIC_EXTENSIONS("rom,bin") + MCFG_GENERIC_SOCKET_ADD("eprom2", generic_linear_slot, NULL) + MCFG_GENERIC_EXTENSIONS("rom,bin") +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor c64_dela_ep64_cartridge_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( c64_dela_ep64 ); +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// c64_dela_ep64_cartridge_device - constructor +//------------------------------------------------- + +c64_dela_ep64_cartridge_device::c64_dela_ep64_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, C64_DELA_EP64, "C64 Rex 64KB EPROM cartridge", tag, owner, clock, "c64_dela_ep64", __FILE__), + device_c64_expansion_card_interface(mconfig, *this), + m_eprom1(*this, "eprom1"), + m_eprom2(*this, "eprom2") +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void c64_dela_ep64_cartridge_device::device_start() +{ + // state saving + save_item(NAME(m_bank)); + save_item(NAME(m_reset)); + save_item(NAME(m_rom0_ce)); + save_item(NAME(m_rom1_ce)); + save_item(NAME(m_rom2_ce)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void c64_dela_ep64_cartridge_device::device_reset() +{ + m_exrom = 0; + + m_reset = 1; +} + + +//------------------------------------------------- +// c64_cd_r - cartridge data read +//------------------------------------------------- + +UINT8 c64_dela_ep64_cartridge_device::c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (!roml) + { + if (m_reset) + { + data = m_roml[offset & 0x1fff]; + } + else + { + offs_t addr = (m_bank << 13) | (offset & 0x1fff); + + if (!m_rom0_ce) data |= m_roml[offset & 0x1fff]; + if (!m_rom1_ce) data |= m_eprom1->read_rom(space, addr); + if (!m_rom2_ce) data |= m_eprom2->read_rom(space, addr); + } + } + + return data; +} + + +//------------------------------------------------- +// c64_cd_w - cartridge data write +//------------------------------------------------- + +void c64_dela_ep64_cartridge_device::c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (!io1) + { + /* + + bit description + + 0 IC6 _CE + 1 IC5 _CE + 2 + 3 IC4 _CE + 4 A13 + 5 A14 + 6 + 7 EXROM + + */ + + m_reset = 0; + + m_rom0_ce = BIT(data, 3); + m_rom1_ce = BIT(data, 1); + m_rom2_ce = BIT(data, 0); + + m_bank = (data >> 4) & 0x03; + + m_exrom = BIT(data, 7); + } +} diff --git a/src/devices/bus/c64/dela_ep64.h b/src/devices/bus/c64/dela_ep64.h new file mode 100644 index 00000000000..9ee3455aeba --- /dev/null +++ b/src/devices/bus/c64/dela_ep64.h @@ -0,0 +1,64 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Dela 64KB EPROM cartridge emulation + +**********************************************************************/ + +#pragma once + +#ifndef __DELA_EP64__ +#define __DELA_EP64__ + + +#include "emu.h" +#include "bus/generic/slot.h" +#include "bus/generic/carts.h" +#include "exp.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> c64_dela_ep64_cartridge_device + +class c64_dela_ep64_cartridge_device : public device_t, + public device_c64_expansion_card_interface +{ +public: + // construction/destruction + c64_dela_ep64_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_c64_expansion_card_interface overrides + virtual UINT8 c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + virtual void c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + +private: + required_device m_eprom1; + required_device m_eprom2; + + UINT8 m_bank; + int m_reset; + int m_rom0_ce; + int m_rom1_ce; + int m_rom2_ce; +}; + + +// device type definition +extern const device_type C64_DELA_EP64; + + + +#endif diff --git a/src/devices/bus/c64/dela_ep7x8.c b/src/devices/bus/c64/dela_ep7x8.c new file mode 100644 index 00000000000..f79b3828fe5 --- /dev/null +++ b/src/devices/bus/c64/dela_ep7x8.c @@ -0,0 +1,133 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Dela 7x8K EPROM cartridge emulation + +**********************************************************************/ + +#include "dela_ep7x8.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type C64_DELA_EP7X8 = &device_creator; + + +//------------------------------------------------- +// MACHINE_CONFIG_FRAGMENT( c64_dela_ep7x8 ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( c64_dela_ep7x8 ) + MCFG_GENERIC_SOCKET_ADD("rom1", generic_linear_slot, NULL) + MCFG_GENERIC_EXTENSIONS("bin,rom") + MCFG_GENERIC_SOCKET_ADD("rom2", generic_linear_slot, NULL) + MCFG_GENERIC_EXTENSIONS("bin,rom") + MCFG_GENERIC_SOCKET_ADD("rom3", generic_linear_slot, NULL) + MCFG_GENERIC_EXTENSIONS("bin,rom") + MCFG_GENERIC_SOCKET_ADD("rom4", generic_linear_slot, NULL) + MCFG_GENERIC_EXTENSIONS("bin,rom") + MCFG_GENERIC_SOCKET_ADD("rom5", generic_linear_slot, NULL) + MCFG_GENERIC_EXTENSIONS("bin,rom") + MCFG_GENERIC_SOCKET_ADD("rom6", generic_linear_slot, NULL) + MCFG_GENERIC_EXTENSIONS("bin,rom") + MCFG_GENERIC_SOCKET_ADD("rom7", generic_linear_slot, NULL) + MCFG_GENERIC_EXTENSIONS("bin,rom") +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor c64_dela_ep7x8_cartridge_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( c64_dela_ep7x8 ); +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// c64_dela_ep7x8_cartridge_device - constructor +//------------------------------------------------- + +c64_dela_ep7x8_cartridge_device::c64_dela_ep7x8_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, C64_DELA_EP7X8, "C64 Dela 7x8KB EPROM cartridge", tag, owner, clock, "ep7x8", __FILE__), + device_c64_expansion_card_interface(mconfig, *this), + m_eprom1(*this, "rom1"), + m_eprom2(*this, "rom2"), + m_eprom3(*this, "rom3"), + m_eprom4(*this, "rom4"), + m_eprom5(*this, "rom5"), + m_eprom6(*this, "rom6"), + m_eprom7(*this, "rom7") +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void c64_dela_ep7x8_cartridge_device::device_start() +{ + // state saving + save_item(NAME(m_bank)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void c64_dela_ep7x8_cartridge_device::device_reset() +{ + m_bank = 0xfe; + m_exrom = 0; +} + + +//------------------------------------------------- +// c64_cd_r - cartridge data read +//------------------------------------------------- + +UINT8 c64_dela_ep7x8_cartridge_device::c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (!roml) + { + offs_t addr = offset & 0x1fff; + + if (!BIT(m_bank, 0)) data |= m_roml[addr]; + if (!BIT(m_bank, 1)) data |= m_eprom1->read_rom(space, addr); + if (!BIT(m_bank, 2)) data |= m_eprom2->read_rom(space, addr); + if (!BIT(m_bank, 3)) data |= m_eprom3->read_rom(space, addr); + if (!BIT(m_bank, 4)) data |= m_eprom4->read_rom(space, addr); + if (!BIT(m_bank, 5)) data |= m_eprom5->read_rom(space, addr); + if (!BIT(m_bank, 6)) data |= m_eprom6->read_rom(space, addr); + if (!BIT(m_bank, 7)) data |= m_eprom7->read_rom(space, addr); + } + + return data; +} + + +//------------------------------------------------- +// c64_cd_w - cartridge data write +//------------------------------------------------- + +void c64_dela_ep7x8_cartridge_device::c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (!io1) + { + m_bank = data; + + m_exrom = (data == 0xff); + } +} diff --git a/src/devices/bus/c64/dela_ep7x8.h b/src/devices/bus/c64/dela_ep7x8.h new file mode 100644 index 00000000000..cf236fadc07 --- /dev/null +++ b/src/devices/bus/c64/dela_ep7x8.h @@ -0,0 +1,65 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Dela 7x8K EPROM cartridge emulation + +**********************************************************************/ + +#pragma once + +#ifndef __DELA_EP7X8__ +#define __DELA_EP7X8__ + + +#include "emu.h" +#include "bus/generic/slot.h" +#include "bus/generic/carts.h" +#include "exp.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> c64_dela_ep7x8_cartridge_device + +class c64_dela_ep7x8_cartridge_device : public device_t, + public device_c64_expansion_card_interface +{ +public: + // construction/destruction + c64_dela_ep7x8_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_c64_expansion_card_interface overrides + virtual UINT8 c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + virtual void c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + +private: + required_device m_eprom1; + required_device m_eprom2; + required_device m_eprom3; + required_device m_eprom4; + required_device m_eprom5; + required_device m_eprom6; + required_device m_eprom7; + + UINT8 m_bank; +}; + + +// device type definition +extern const device_type C64_DELA_EP7X8; + + + +#endif diff --git a/src/devices/bus/c64/dinamic.c b/src/devices/bus/c64/dinamic.c new file mode 100644 index 00000000000..812e0fcdc92 --- /dev/null +++ b/src/devices/bus/c64/dinamic.c @@ -0,0 +1,74 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Dinamic Software cartridge emulation + +**********************************************************************/ + +#include "dinamic.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type C64_DINAMIC = &device_creator; + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// c64_dinamic_cartridge_device - constructor +//------------------------------------------------- + +c64_dinamic_cartridge_device::c64_dinamic_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, C64_DINAMIC, "C64 Dinamic cartridge", tag, owner, clock, "c64_dinamic", __FILE__), + device_c64_expansion_card_interface(mconfig, *this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void c64_dinamic_cartridge_device::device_start() +{ + // state saving + save_item(NAME(m_bank)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void c64_dinamic_cartridge_device::device_reset() +{ + m_bank = 0; +} + + +//------------------------------------------------- +// c64_cd_r - cartridge data read +//------------------------------------------------- + +UINT8 c64_dinamic_cartridge_device::c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (!roml) + { + offs_t addr = (m_bank << 13) | (offset & 0x1fff); + data = m_roml[addr]; + } + else if (!io1) + { + m_bank = offset & 0x0f; + } + + return data; +} diff --git a/src/devices/bus/c64/dinamic.h b/src/devices/bus/c64/dinamic.h new file mode 100644 index 00000000000..2f3ecc07302 --- /dev/null +++ b/src/devices/bus/c64/dinamic.h @@ -0,0 +1,50 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Dinamic Software cartridge emulation + +**********************************************************************/ + +#pragma once + +#ifndef __DINAMIC__ +#define __DINAMIC__ + + +#include "emu.h" +#include "exp.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> c64_dinamic_cartridge_device + +class c64_dinamic_cartridge_device : public device_t, + public device_c64_expansion_card_interface +{ +public: + // construction/destruction + c64_dinamic_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_c64_expansion_card_interface overrides + virtual UINT8 c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + +private: + UINT8 m_bank; +}; + + +// device type definition +extern const device_type C64_DINAMIC; + + +#endif diff --git a/src/devices/bus/c64/dqbb.c b/src/devices/bus/c64/dqbb.c new file mode 100644 index 00000000000..7e30cdd1545 --- /dev/null +++ b/src/devices/bus/c64/dqbb.c @@ -0,0 +1,121 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Brown Boxes Double Quick Brown Box emulation + +**********************************************************************/ + +/* + + TODO: + + - 64/128 mode switch + - dump of the initial NVRAM contents + +*/ + +#include "dqbb.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type C64_DQBB = &device_creator; + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// c64_dqbb_cartridge_device - constructor +//------------------------------------------------- + +c64_dqbb_cartridge_device::c64_dqbb_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, C64_DQBB, "C64 Double Quick Brown Box cartridge", tag, owner, clock, "c64_dqbb", __FILE__), + device_c64_expansion_card_interface(mconfig, *this), + device_nvram_interface(mconfig, *this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void c64_dqbb_cartridge_device::device_start() +{ + // allocate memory + m_nvram.allocate(0x4000); + + // state saving + save_item(NAME(m_cs)); + save_item(NAME(m_we)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void c64_dqbb_cartridge_device::device_reset() +{ + m_exrom = 0; // TODO 1 in 128 mode + m_game = 1; + m_cs = 0; + m_we = 0; +} + + +//------------------------------------------------- +// c64_cd_r - cartridge data read +//------------------------------------------------- + +UINT8 c64_dqbb_cartridge_device::c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (!m_cs && (!roml || !romh)) + { + data = m_nvram[offset & 0x3fff]; + } + + return data; +} + + +//------------------------------------------------- +// c64_cd_w - cartridge data write +//------------------------------------------------- + +void c64_dqbb_cartridge_device::c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (!m_cs && m_we && (offset >= 0x8000 && offset < 0xc000)) + { + m_nvram[offset & 0x3fff] = data; + } + else if (!io1) + { + /* + + bit description + + 0 + 1 + 2 GAME + 3 + 4 WE + 5 + 6 EXROM + 7 _CS + + */ + + m_exrom = !BIT(data, 6); + m_game = !BIT(data, 2); + m_we = BIT(data, 4); + m_cs = BIT(data, 7); + } +} diff --git a/src/devices/bus/c64/dqbb.h b/src/devices/bus/c64/dqbb.h new file mode 100644 index 00000000000..387be1f2203 --- /dev/null +++ b/src/devices/bus/c64/dqbb.h @@ -0,0 +1,59 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Brown Boxes Double Quick Brown Box emulation + +**********************************************************************/ + +#pragma once + +#ifndef __DQBB__ +#define __DQBB__ + + +#include "emu.h" +#include "exp.h" +#include "machine/nvram.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> c64_dqbb_cartridge_device + +class c64_dqbb_cartridge_device : public device_t, + public device_c64_expansion_card_interface, + public device_nvram_interface +{ +public: + // construction/destruction + c64_dqbb_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_nvram_interface overrides + virtual void nvram_default() { } + virtual void nvram_read(emu_file &file) { if (m_nvram != NULL) { file.read(m_nvram, m_nvram.bytes()); } } + virtual void nvram_write(emu_file &file) { if (m_nvram != NULL) { file.write(m_nvram, m_nvram.bytes()); } } + + // device_c64_expansion_card_interface overrides + virtual UINT8 c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + virtual void c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + +private: + int m_cs; + int m_we; +}; + + +// device type definition +extern const device_type C64_DQBB; + + +#endif diff --git a/src/devices/bus/c64/easy_calc_result.c b/src/devices/bus/c64/easy_calc_result.c new file mode 100644 index 00000000000..d6a4a6b4cf9 --- /dev/null +++ b/src/devices/bus/c64/easy_calc_result.c @@ -0,0 +1,107 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Easy Calc Result cartridge emulation + +**********************************************************************/ + +/* + + PCB Layout + ---------- + + |===========================| + |=| | + |=| ROM0 LS73 | + |=| | + |=| | + |=| | + |=| | + |=| ROM1 LS00 | + |=| | + |===========================| + + ROM0 - Hitachi HN61364P 8Kx8 EPROM "CR2001" + ROM1 - Hitachi HN613128P 16Kx8 EPROM "CR3001" + +*/ + +#include "easy_calc_result.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type C64_EASY_CALC_RESULT = &device_creator; + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// c64_easy_calc_result_cartridge_device - constructor +//------------------------------------------------- + +c64_easy_calc_result_cartridge_device::c64_easy_calc_result_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, C64_EASY_CALC_RESULT, "C64 Easy Calc Result cartridge", tag, owner, clock, "c64_easy_calc_result", __FILE__), + device_c64_expansion_card_interface(mconfig, *this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void c64_easy_calc_result_cartridge_device::device_start() +{ + // state saving + save_item(NAME(m_bank)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void c64_easy_calc_result_cartridge_device::device_reset() +{ + m_bank = 0; +} + + +//------------------------------------------------- +// c64_cd_r - cartridge data read +//------------------------------------------------- + +UINT8 c64_easy_calc_result_cartridge_device::c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (!roml) + { + data = m_roml[offset & 0x1fff]; + } + else if (!romh) + { + data = m_romh[(m_bank << 13) | (offset & 0x1fff)]; + } + + return data; +} + + +//------------------------------------------------- +// c64_cd_w - cartridge data write +//------------------------------------------------- + +void c64_easy_calc_result_cartridge_device::c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (!io1) + { + m_bank = !BIT(offset, 0); + } +} diff --git a/src/devices/bus/c64/easy_calc_result.h b/src/devices/bus/c64/easy_calc_result.h new file mode 100644 index 00000000000..e0fe1e34ac8 --- /dev/null +++ b/src/devices/bus/c64/easy_calc_result.h @@ -0,0 +1,51 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Easy Calc Result cartridge emulation + +**********************************************************************/ + +#pragma once + +#ifndef __EASY_CALC_RESULT__ +#define __EASY_CALC_RESULT__ + + +#include "emu.h" +#include "exp.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> c64_easy_calc_result_cartridge_device + +class c64_easy_calc_result_cartridge_device : public device_t, + public device_c64_expansion_card_interface +{ +public: + // construction/destruction + c64_easy_calc_result_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_c64_expansion_card_interface overrides + virtual UINT8 c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + virtual void c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + +private: + int m_bank; +}; + + +// device type definition +extern const device_type C64_EASY_CALC_RESULT; + + +#endif diff --git a/src/devices/bus/c64/easyflash.c b/src/devices/bus/c64/easyflash.c new file mode 100644 index 00000000000..0af06b0cc48 --- /dev/null +++ b/src/devices/bus/c64/easyflash.c @@ -0,0 +1,228 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + EasyFlash cartridge emulation + +**********************************************************************/ + +#include "easyflash.h" + + +//************************************************************************** +// MACROS/CONSTANTS +//************************************************************************** + +#define AM29F040_0_TAG "u3" +#define AM29F040_1_TAG "u4" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type C64_EASYFLASH = &device_creator; + + +//------------------------------------------------- +// MACHINE_CONFIG_FRAGMENT( c64_easyflash ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( c64_easyflash ) + MCFG_AMD_29F040_ADD(AM29F040_0_TAG) + MCFG_AMD_29F040_ADD(AM29F040_1_TAG) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor c64_easyflash_cartridge_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( c64_easyflash ); +} + + +//------------------------------------------------- +// INPUT_PORTS( c64_easyflash ) +//------------------------------------------------- + +static INPUT_PORTS_START( c64_easyflash ) + PORT_START("JP1") + PORT_DIPNAME( 0x01, 0x00, "Boot" ) + PORT_DIPSETTING( 0x00, "Disable" ) + PORT_DIPSETTING( 0x01, "Boot" ) + + PORT_START("RESET") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Reset") PORT_CODE(KEYCODE_F11) PORT_WRITE_LINE_DEVICE_MEMBER(DEVICE_SELF_OWNER, c64_expansion_slot_device, reset_w) +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor c64_easyflash_cartridge_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( c64_easyflash ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// c64_easyflash_cartridge_device - constructor +//------------------------------------------------- + +c64_easyflash_cartridge_device::c64_easyflash_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, C64_EASYFLASH, "C64 EasyFlash cartridge", tag, owner, clock, "c64_easyflash", __FILE__), + device_c64_expansion_card_interface(mconfig, *this), + m_flash_roml(*this, AM29F040_0_TAG), + m_flash_romh(*this, AM29F040_1_TAG), + m_jp1(*this, "JP1"), + m_ram(*this, "ram"), + m_bank(0), + m_mode(0) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void c64_easyflash_cartridge_device::device_start() +{ + // allocate memory + m_ram.allocate(0x100); + + // state saving + save_item(NAME(m_bank)); + save_item(NAME(m_mode)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void c64_easyflash_cartridge_device::device_reset() +{ + m_bank = 0; + m_mode = 0; +} + + +//------------------------------------------------- +// c64_cd_r - cartridge data read +//------------------------------------------------- + +UINT8 c64_easyflash_cartridge_device::c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (!roml) + { + offs_t addr = (m_bank << 13) | (offset & 0x1fff); + data = m_flash_roml->read(addr); + } + else if (!romh) + { + offs_t addr = (m_bank << 13) | (offset & 0x1fff); + data = m_flash_romh->read(addr); + } + else if (!io2) + { + data = m_ram[offset & 0xff]; + } + + return data; +} + + +//------------------------------------------------- +// c64_cd_w - cartridge data write +//------------------------------------------------- + +void c64_easyflash_cartridge_device::c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (!roml) + { + offs_t addr = (m_bank << 13) | (offset & 0x1fff); + m_flash_roml->write(addr, data); + } + else if (!romh) + { + offs_t addr = (m_bank << 13) | (offset & 0x1fff); + m_flash_romh->write(addr, data); + } + else if (!io1) + { + if (!BIT(offset, 1)) + { + /* + + bit description + + 0 BA13 + 1 BA14 + 2 BA15 + 3 BA16 + 4 BA17 + 5 BA18 + 6 + 7 + + */ + + m_bank = data & 0x3f; + } + else + { + /* + + bit description + + 0 GAME + 1 EXROM + 2 MODE + 3 + 4 + 5 + 6 + 7 LED + + */ + + m_mode = data; + } + } + else if (!io2) + { + m_ram[offset & 0xff] = data; + } +} + + +//------------------------------------------------- +// c64_exrom_r - EXROM read +//------------------------------------------------- + +int c64_easyflash_cartridge_device::c64_exrom_r(offs_t offset, int sphi2, int ba, int rw) +{ + return !BIT(m_mode, 1); +} + + +//------------------------------------------------- +// c64_game_r - GAME read +//------------------------------------------------- + +int c64_easyflash_cartridge_device::c64_game_r(offs_t offset, int sphi2, int ba, int rw) +{ + return !(BIT(m_mode, 0) | !(BIT(m_mode, 2) | m_jp1->read())); +} diff --git a/src/devices/bus/c64/easyflash.h b/src/devices/bus/c64/easyflash.h new file mode 100644 index 00000000000..4dba6c1e5be --- /dev/null +++ b/src/devices/bus/c64/easyflash.h @@ -0,0 +1,64 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + EasyFlash cartridge emulation + +**********************************************************************/ + +#pragma once + +#ifndef __EASYFLASH__ +#define __EASYFLASH__ + + +#include "emu.h" +#include "exp.h" +#include "machine/intelfsh.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> c64_easyflash_cartridge_device + +class c64_easyflash_cartridge_device : public device_t, + public device_c64_expansion_card_interface +{ +public: + // construction/destruction + c64_easyflash_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual ioport_constructor device_input_ports() const; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_c64_expansion_card_interface overrides + virtual UINT8 c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + virtual void c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + virtual int c64_exrom_r(offs_t offset, int sphi2, int ba, int rw); + virtual int c64_game_r(offs_t offset, int sphi2, int ba, int rw); + +private: + required_device m_flash_roml; + required_device m_flash_romh; + required_ioport m_jp1; + optional_shared_ptr m_ram; + + UINT8 m_bank; + UINT8 m_mode; +}; + + +// device type definition +extern const device_type C64_EASYFLASH; + + +#endif diff --git a/src/devices/bus/c64/epyx_fast_load.c b/src/devices/bus/c64/epyx_fast_load.c new file mode 100644 index 00000000000..7b0dfeb5934 --- /dev/null +++ b/src/devices/bus/c64/epyx_fast_load.c @@ -0,0 +1,116 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Epyx Fast Load cartridge emulation + +**********************************************************************/ + +#include "epyx_fast_load.h" + + + +//************************************************************************** +// MACROS/CONSTANTS +//************************************************************************** + +// t = R*C = 3.3K * 0.47uF * 40% Vtr = 792.2905424610516 usec +// (3.3K pull-up on the EXROM line inside the C64, PLA Vih min = 2.0V = 40% of 5.0V) +#define TIMER_PERIOD 792 + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type C64_EPYX_FAST_LOAD = &device_creator; + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// c64_epyx_fast_load_cartridge_device - constructor +//------------------------------------------------- + +c64_epyx_fast_load_cartridge_device::c64_epyx_fast_load_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, C64_EPYX_FAST_LOAD, "C64 Epyx Fast Load cartridge", tag, owner, clock, "c64_epyx_fast_load", __FILE__), + device_c64_expansion_card_interface(mconfig, *this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void c64_epyx_fast_load_cartridge_device::device_start() +{ + // allocate timer + m_exrom_timer = timer_alloc(); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void c64_epyx_fast_load_cartridge_device::device_reset() +{ + m_exrom = 0; + m_exrom_timer->adjust(attotime::from_usec(TIMER_PERIOD), 0); +} + + +//------------------------------------------------- +// device_timer - handler timer events +//------------------------------------------------- + +void c64_epyx_fast_load_cartridge_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + m_exrom = 1; +} + + +//------------------------------------------------- +// c64_cd_r - cartridge data read +//------------------------------------------------- + +UINT8 c64_epyx_fast_load_cartridge_device::c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (!roml) + { + m_exrom = 0; + m_exrom_timer->adjust(attotime::from_usec(TIMER_PERIOD), 0); + + data = m_roml[offset & 0x1fff]; + } + else if (!io1) + { + m_exrom = 0; + m_exrom_timer->adjust(attotime::from_usec(TIMER_PERIOD), 0); + } + else if (!io2) + { + data = m_roml[offset & 0x1fff]; + } + + return data; +} + + +//------------------------------------------------- +// c64_cd_w - cartridge data write +//------------------------------------------------- + +void c64_epyx_fast_load_cartridge_device::c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (!io1) + { + m_exrom = 0; + m_exrom_timer->adjust(attotime::from_usec(TIMER_PERIOD), 0); + } +} diff --git a/src/devices/bus/c64/epyx_fast_load.h b/src/devices/bus/c64/epyx_fast_load.h new file mode 100644 index 00000000000..f0f30c5ccc6 --- /dev/null +++ b/src/devices/bus/c64/epyx_fast_load.h @@ -0,0 +1,52 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Epyx Fast Load cartridge emulation + +**********************************************************************/ + +#pragma once + +#ifndef __EPYX_FAST_LOAD__ +#define __EPYX_FAST_LOAD__ + + +#include "emu.h" +#include "exp.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> c64_epyx_fast_load_cartridge_device + +class c64_epyx_fast_load_cartridge_device : public device_t, + public device_c64_expansion_card_interface +{ +public: + // construction/destruction + c64_epyx_fast_load_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + // device_c64_expansion_card_interface overrides + virtual UINT8 c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + virtual void c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + +private: + emu_timer *m_exrom_timer; +}; + + +// device type definition +extern const device_type C64_EPYX_FAST_LOAD; + + +#endif diff --git a/src/devices/bus/c64/exos.c b/src/devices/bus/c64/exos.c new file mode 100644 index 00000000000..0b0ce6c8257 --- /dev/null +++ b/src/devices/bus/c64/exos.c @@ -0,0 +1,67 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Rex ExOS cartridge emulation + +**********************************************************************/ + +#include "exos.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type C64_EXOS = &device_creator; + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// c64_exos_cartridge_device - constructor +//------------------------------------------------- + +c64_exos_cartridge_device::c64_exos_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, C64_EXOS, "C64 ExOS cartridge", tag, owner, clock, "c64_exos", __FILE__), + device_c64_expansion_card_interface(mconfig, *this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void c64_exos_cartridge_device::device_start() +{ +} + + +//------------------------------------------------- +// c64_cd_r - cartridge data read +//------------------------------------------------- + +UINT8 c64_exos_cartridge_device::c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (!romh) + { + data = m_romh[offset & 0x1fff]; + } + + return data; +} + + +//------------------------------------------------- +// c64_game_r - GAME read +//------------------------------------------------- + +int c64_exos_cartridge_device::c64_game_r(offs_t offset, int sphi2, int ba, int rw) +{ + return !(ba & rw & ((offset & 0xe000) == 0xe000) & m_slot->hiram()); +} diff --git a/src/devices/bus/c64/exos.h b/src/devices/bus/c64/exos.h new file mode 100644 index 00000000000..1fffb003c86 --- /dev/null +++ b/src/devices/bus/c64/exos.h @@ -0,0 +1,47 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Rex ExOS cartridge emulation + +**********************************************************************/ + +#pragma once + +#ifndef __EXOS__ +#define __EXOS__ + + +#include "emu.h" +#include "exp.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> c64_exos_cartridge_device + +class c64_exos_cartridge_device : public device_t, + public device_c64_expansion_card_interface +{ +public: + // construction/destruction + c64_exos_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // device-level overrides + virtual void device_start(); + + // device_c64_expansion_card_interface overrides + virtual UINT8 c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + virtual int c64_game_r(offs_t offset, int sphi2, int ba, int rw); +}; + + +// device type definition +extern const device_type C64_EXOS; + + +#endif diff --git a/src/devices/bus/c64/exp.c b/src/devices/bus/c64/exp.c new file mode 100644 index 00000000000..a1c449d180e --- /dev/null +++ b/src/devices/bus/c64/exp.c @@ -0,0 +1,445 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Commodore 64 Expansion Port emulation + +**********************************************************************/ + +#include "exp.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type C64_EXPANSION_SLOT = &device_creator; + + + +//************************************************************************** +// DEVICE C64_EXPANSION CARD INTERFACE +//************************************************************************** + +//------------------------------------------------- +// device_c64_expansion_card_interface - constructor +//------------------------------------------------- + +device_c64_expansion_card_interface::device_c64_expansion_card_interface(const machine_config &mconfig, device_t &device) + : device_slot_card_interface(mconfig, device), + m_roml(*this, "roml"), + m_romh(*this, "romh"), + m_nvram(*this, "nvram"), + m_game(1), + m_exrom(1) +{ + m_slot = dynamic_cast(device.owner()); +} + + +//------------------------------------------------- +// ~device_c64_expansion_card_interface - destructor +//------------------------------------------------- + +device_c64_expansion_card_interface::~device_c64_expansion_card_interface() +{ +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// c64_expansion_slot_device - constructor +//------------------------------------------------- + +c64_expansion_slot_device::c64_expansion_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, C64_EXPANSION_SLOT, "C64 expansion port", tag, owner, clock, "c64_expansion_slot", __FILE__), + device_slot_interface(mconfig, *this), + device_image_interface(mconfig, *this), + m_read_dma_cd(*this), + m_write_dma_cd(*this), + m_write_irq(*this), + m_write_nmi(*this), + m_write_dma(*this), + m_write_reset(*this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void c64_expansion_slot_device::device_start() +{ + m_card = dynamic_cast(get_card_device()); + + // resolve callbacks + m_read_dma_cd.resolve_safe(0); + m_write_dma_cd.resolve_safe(); + m_write_irq.resolve_safe(); + m_write_nmi.resolve_safe(); + m_write_dma.resolve_safe(); + m_write_reset.resolve_safe(); + + // inherit bus clock + if (clock() == 0) + { + c64_expansion_slot_device *root = machine().device(C64_EXPANSION_SLOT_TAG); + assert(root); + set_unscaled_clock(root->clock()); + } +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void c64_expansion_slot_device::device_reset() +{ + if (get_card_device()) + { + get_card_device()->reset(); + } +} + + +//------------------------------------------------- +// call_load - +//------------------------------------------------- + +bool c64_expansion_slot_device::call_load() +{ + if (m_card) + { + size_t size = 0; + + if (software_entry() == NULL) + { + size = length(); + + if (!core_stricmp(filetype(), "80")) + { + fread(m_card->m_roml, size); + m_card->m_exrom = (0); + + if (size == 0x4000) + { + m_card->m_game = 0; + } + } + else if (!core_stricmp(filetype(), "a0")) + { + fread(m_card->m_romh, 0x2000); + + m_card->m_exrom = 0; + m_card->m_game = 0; + } + else if (!core_stricmp(filetype(), "e0")) + { + fread(m_card->m_romh, 0x2000); + + m_card->m_game = 0; + } + else if (!core_stricmp(filetype(), "crt")) + { + size_t roml_size = 0; + size_t romh_size = 0; + int exrom = 1; + int game = 1; + + if (cbm_crt_read_header(m_file, &roml_size, &romh_size, &exrom, &game)) + { + UINT8 *roml = NULL; + UINT8 *romh = NULL; + + m_card->m_roml.allocate(roml_size); + m_card->m_romh.allocate(romh_size); + + if (roml_size) roml = m_card->m_roml; + if (romh_size) romh = m_card->m_roml; + + cbm_crt_read_data(m_file, roml, romh); + } + + m_card->m_exrom = exrom; + m_card->m_game = game; + } + } + else + { + size = get_software_region_length("uprom"); + + if (size) + { + // Ultimax (VIC-10) cartridge + load_software_region("lorom", m_card->m_roml); + load_software_region("uprom", m_card->m_romh); + + m_card->m_exrom = 1; + m_card->m_game = 0; + } + else + { + // Commodore 64/128 cartridge + load_software_region("roml", m_card->m_roml); + load_software_region("romh", m_card->m_romh); + load_software_region("nvram", m_card->m_nvram); + + if (get_feature("exrom") != NULL) m_card->m_exrom = atol(get_feature("exrom")); + if (get_feature("game") != NULL) m_card->m_game = atol(get_feature("game")); + } + } + } + + return IMAGE_INIT_PASS; +} + + +//------------------------------------------------- +// call_softlist_load - +//------------------------------------------------- + +bool c64_expansion_slot_device::call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry) +{ + load_software_part_region(*this, swlist, swname, start_entry); + + return true; +} + + +//------------------------------------------------- +// get_default_card_software - +//------------------------------------------------- + +void c64_expansion_slot_device::get_default_card_software(std::string &result) +{ + if (open_image_file(mconfig().options())) + { + if (!core_stricmp(filetype(), "crt")) + { + cbm_crt_get_card(result, m_file); + return; + } + + clear(); + } + + software_get_default_slot(result, "standard"); +} + + +//------------------------------------------------- +// cd_r - cartridge data read +//------------------------------------------------- + +UINT8 c64_expansion_slot_device::cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (m_card != NULL) + { + data = m_card->c64_cd_r(space, offset, data, sphi2, ba, roml, romh, io1, io2); + } + + return data; +} + + +//------------------------------------------------- +// cd_w - cartridge data write +//------------------------------------------------- + +void c64_expansion_slot_device::cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (m_card != NULL) + { + m_card->c64_cd_w(space, offset, data, sphi2, ba, roml, romh, io1, io2); + } +} + + +//------------------------------------------------- +// game_r - GAME read +//------------------------------------------------- + +int c64_expansion_slot_device::game_r(offs_t offset, int sphi2, int ba, int rw, int hiram) +{ + int state = 1; + + m_hiram = hiram; + + if (m_card != NULL) + { + state = m_card->c64_game_r(offset, sphi2, ba, rw); + } + + return state; +} + + +//------------------------------------------------- +// exrom_r - EXROM read +//------------------------------------------------- + +int c64_expansion_slot_device::exrom_r(offs_t offset, int sphi2, int ba, int rw, int hiram) +{ + int state = 1; + + m_hiram = hiram; + + if (m_card != NULL) + { + state = m_card->c64_exrom_r(offset, sphi2, ba, rw); + } + + return state; +} + + +//------------------------------------------------- +// SLOT_INTERFACE( c64_expansion_cards ) +//------------------------------------------------- + + +// slot devices +#include "16kb.h" +#include "c128_comal80.h" +#include "c128_partner.h" +#include "comal80.h" +#include "cpm.h" +#include "currah_speech.h" +#include "dela_ep256.h" +#include "dela_ep64.h" +#include "dela_ep7x8.h" +#include "dinamic.h" +#include "dqbb.h" +#include "easy_calc_result.h" +#include "easyflash.h" +#include "epyx_fast_load.h" +#include "exos.h" +#include "fcc.h" +#include "final.h" +#include "final3.h" +#include "fun_play.h" +#include "georam.h" +#include "ide64.h" +#include "ieee488.h" +#include "kingsoft.h" +#include "mach5.h" +#include "magic_desk.h" +#include "magic_formel.h" +#include "magic_voice.h" +#include "midi_maplin.h" +#include "midi_namesoft.h" +#include "midi_passport.h" +#include "midi_sci.h" +#include "midi_siel.h" +#include "mikro_assembler.h" +#include "multiscreen.h" +#include "music64.h" +#include "neoram.h" +#include "ocean.h" +#include "pagefox.h" +#include "partner.h" +#include "prophet64.h" +#include "ps64.h" +#include "reu.h" +#include "rex.h" +#include "rex_ep256.h" +#include "ross.h" +#include "sfx_sound_expander.h" +#include "silverrock.h" +#include "simons_basic.h" +#include "stardos.h" +#include "std.h" +#include "structured_basic.h" +#include "super_explode.h" +#include "super_games.h" +#include "supercpu.h" +#include "sw8k.h" +#include "swiftlink.h" +#include "system3.h" +#include "tdos.h" +#include "turbo232.h" +#include "vizastar.h" +#include "vw64.h" +#include "warp_speed.h" +#include "westermann.h" +#include "xl80.h" +#include "zaxxon.h" + +SLOT_INTERFACE_START( c64_expansion_cards ) + SLOT_INTERFACE("16k", C64_16KB) + SLOT_INTERFACE("cpm", C64_CPM) + SLOT_INTERFACE("dqbb", C64_DQBB) + SLOT_INTERFACE("easyflash", C64_EASYFLASH) + SLOT_INTERFACE("georam", C64_GEORAM) + SLOT_INTERFACE("ide64", C64_IDE64) + SLOT_INTERFACE("midimap", C64_MIDI_MAPLIN) + SLOT_INTERFACE("midins", C64_MIDI_NAMESOFT) + SLOT_INTERFACE("midipp", C64_MIDI_PASSPORT) + SLOT_INTERFACE("midisci", C64_MIDI_SCI) + SLOT_INTERFACE("midisiel", C64_MIDI_SIEL) + SLOT_INTERFACE("music64", C64_MUSIC64) + SLOT_INTERFACE("neoram", C64_NEORAM) + SLOT_INTERFACE("reu1700", C64_REU1700) + SLOT_INTERFACE("reu1750", C64_REU1750) + SLOT_INTERFACE("reu1764", C64_REU1764) + SLOT_INTERFACE("sfxse", C64_SFX_SOUND_EXPANDER) + SLOT_INTERFACE("supercpu", C64_SUPERCPU) + SLOT_INTERFACE("swiftlink", C64_SWIFTLINK) + SLOT_INTERFACE("turbo232", C64_TURBO232) + + // the following need ROMs from the software list + SLOT_INTERFACE_INTERNAL("standard", C64_STD) + SLOT_INTERFACE_INTERNAL("comal80", C64_COMAL80) + SLOT_INTERFACE_INTERNAL("c128_comal80", C128_COMAL80) + SLOT_INTERFACE_INTERNAL("cs64", C64_CURRAH_SPEECH) + SLOT_INTERFACE_INTERNAL("dela_ep256", C64_DELA_EP256) + SLOT_INTERFACE_INTERNAL("ep64", C64_DELA_EP64) + SLOT_INTERFACE_INTERNAL("ep7x8", C64_DELA_EP7X8) + SLOT_INTERFACE_INTERNAL("dinamic", C64_DINAMIC) + SLOT_INTERFACE_INTERNAL("easycalcres", C64_EASY_CALC_RESULT) + SLOT_INTERFACE_INTERNAL("epyxfastload", C64_EPYX_FAST_LOAD) + SLOT_INTERFACE_INTERNAL("exos", C64_EXOS) + SLOT_INTERFACE_INTERNAL("fcc", C64_FCC) + SLOT_INTERFACE_INTERNAL("final", C64_FINAL) + SLOT_INTERFACE_INTERNAL("final3", C64_FINAL3) + SLOT_INTERFACE_INTERNAL("fun_play", C64_FUN_PLAY) + SLOT_INTERFACE_INTERNAL("ieee488", C64_IEEE488) + SLOT_INTERFACE_INTERNAL("kingsoft", C64_KINGSOFT) + SLOT_INTERFACE_INTERNAL("mach5", C64_MACH5) + SLOT_INTERFACE_INTERNAL("magic_desk", C64_MAGIC_DESK) + SLOT_INTERFACE_INTERNAL("magic_formel", C64_MAGIC_FORMEL) + SLOT_INTERFACE_INTERNAL("magic_voice", C64_MAGIC_VOICE) + SLOT_INTERFACE_INTERNAL("mikroasm", C64_MIKRO_ASSEMBLER) + SLOT_INTERFACE_INTERNAL("multiscreen", C64_MULTISCREEN) + SLOT_INTERFACE_INTERNAL("ocean", C64_OCEAN) + SLOT_INTERFACE_INTERNAL("pagefox", C64_PAGEFOX) + SLOT_INTERFACE_INTERNAL("partner", C64_PARTNER) + SLOT_INTERFACE_INTERNAL("partner128", C128_PARTNER) + SLOT_INTERFACE_INTERNAL("prophet64", C64_PROPHET64) + SLOT_INTERFACE_INTERNAL("ps64", C64_PS64) + SLOT_INTERFACE_INTERNAL("rex", C64_REX) + SLOT_INTERFACE_INTERNAL("rex_ep256", C64_REX_EP256) + SLOT_INTERFACE_INTERNAL("ross", C64_ROSS) + SLOT_INTERFACE_INTERNAL("silverrock", C64_SILVERROCK) + SLOT_INTERFACE_INTERNAL("simons_basic", C64_SIMONS_BASIC) + SLOT_INTERFACE_INTERNAL("stardos", C64_STARDOS) + SLOT_INTERFACE_INTERNAL("struct_basic", C64_STRUCTURED_BASIC) + SLOT_INTERFACE_INTERNAL("super_explode", C64_SUPER_EXPLODE) + SLOT_INTERFACE_INTERNAL("super_games", C64_SUPER_GAMES) + SLOT_INTERFACE_INTERNAL("sw8k", C64_SW8K) + SLOT_INTERFACE_INTERNAL("system3", C64_SYSTEM3) + SLOT_INTERFACE_INTERNAL("tdos", C64_TDOS) + SLOT_INTERFACE_INTERNAL("vizastar", C64_VIZASTAR) + SLOT_INTERFACE_INTERNAL("vizawrite", C64_VW64) + SLOT_INTERFACE_INTERNAL("warp_speed", C64_WARP_SPEED) + SLOT_INTERFACE_INTERNAL("westermann", C64_WESTERMANN) + SLOT_INTERFACE_INTERNAL("zaxxon", C64_ZAXXON) + SLOT_INTERFACE_INTERNAL("xl80", C64_XL80) +SLOT_INTERFACE_END diff --git a/src/devices/bus/c64/exp.h b/src/devices/bus/c64/exp.h new file mode 100644 index 00000000000..8ece3920e82 --- /dev/null +++ b/src/devices/bus/c64/exp.h @@ -0,0 +1,202 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Commodore 64 Expansion Port emulation + +********************************************************************** + + GND 1 A GND + +5V 2 B _ROMH + +5V 3 C _RESET + _IRQ 4 D _NMI + _CR/W 5 E Sphi2 + DOTCLK 6 F CA15 + _I/O1 7 H CA14 + _GAME 8 J CA13 + _EXROM 9 K CA12 + _I/O2 10 L CA11 + _ROML 11 M CA10 + BA 12 N CA9 + _DMA 13 P CA8 + CD7 14 R CA7 + CD6 15 S CA6 + CD5 16 T CA5 + CD4 17 U CA4 + CD3 18 V CA3 + CD2 19 W CA2 + CD1 20 X CA1 + CD0 21 Y CA0 + GND 22 Z GND + +**********************************************************************/ + +#pragma once + +#ifndef __C64_EXPANSION_SLOT__ +#define __C64_EXPANSION_SLOT__ + +#include "emu.h" +#include "formats/cbm_crt.h" + + + +//************************************************************************** +// CONSTANTS +//************************************************************************** + +#define C64_EXPANSION_SLOT_TAG "exp" + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_C64_EXPANSION_SLOT_ADD(_tag, _clock, _slot_intf, _def_slot) \ + MCFG_DEVICE_ADD(_tag, C64_EXPANSION_SLOT, _clock) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) + +#define MCFG_C64_PASSTHRU_EXPANSION_SLOT_ADD() \ + MCFG_C64_EXPANSION_SLOT_ADD(C64_EXPANSION_SLOT_TAG, 0, c64_expansion_cards, NULL) \ + MCFG_C64_EXPANSION_SLOT_IRQ_CALLBACK(DEVWRITELINE(DEVICE_SELF_OWNER, c64_expansion_slot_device, irq_w)) \ + MCFG_C64_EXPANSION_SLOT_NMI_CALLBACK(DEVWRITELINE(DEVICE_SELF_OWNER, c64_expansion_slot_device, nmi_w)) \ + MCFG_C64_EXPANSION_SLOT_RESET_CALLBACK(DEVWRITELINE(DEVICE_SELF_OWNER, c64_expansion_slot_device, reset_w)) \ + MCFG_C64_EXPANSION_SLOT_CD_INPUT_CALLBACK(DEVREAD8(DEVICE_SELF_OWNER, c64_expansion_slot_device, dma_cd_r)) \ + MCFG_C64_EXPANSION_SLOT_CD_OUTPUT_CALLBACK(DEVWRITE8(DEVICE_SELF_OWNER, c64_expansion_slot_device, dma_cd_w)) \ + MCFG_C64_EXPANSION_SLOT_DMA_CALLBACK(DEVWRITELINE(DEVICE_SELF_OWNER, c64_expansion_slot_device, dma_w)) + + +#define MCFG_C64_EXPANSION_SLOT_IRQ_CALLBACK(_write) \ + devcb = &c64_expansion_slot_device::set_irq_wr_callback(*device, DEVCB_##_write); + +#define MCFG_C64_EXPANSION_SLOT_NMI_CALLBACK(_write) \ + devcb = &c64_expansion_slot_device::set_nmi_wr_callback(*device, DEVCB_##_write); + +#define MCFG_C64_EXPANSION_SLOT_RESET_CALLBACK(_write) \ + devcb = &c64_expansion_slot_device::set_reset_wr_callback(*device, DEVCB_##_write); + +#define MCFG_C64_EXPANSION_SLOT_CD_INPUT_CALLBACK(_read) \ + devcb = &c64_expansion_slot_device::set_cd_rd_callback(*device, DEVCB_##_read); + +#define MCFG_C64_EXPANSION_SLOT_CD_OUTPUT_CALLBACK(_write) \ + devcb = &c64_expansion_slot_device::set_cd_wr_callback(*device, DEVCB_##_write); + +#define MCFG_C64_EXPANSION_SLOT_DMA_CALLBACK(_write) \ + devcb = &c64_expansion_slot_device::set_dma_wr_callback(*device, DEVCB_##_write); + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> c64_expansion_slot_device + +class device_c64_expansion_card_interface; + +class c64_expansion_slot_device : public device_t, + public device_slot_interface, + public device_image_interface +{ +public: + // construction/destruction + c64_expansion_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + template static devcb_base &set_irq_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_irq.set_callback(object); } + template static devcb_base &set_nmi_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_nmi.set_callback(object); } + template static devcb_base &set_reset_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_reset.set_callback(object); } + template static devcb_base &set_cd_rd_callback(device_t &device, _Object object) { return downcast(device).m_read_dma_cd.set_callback(object); } + template static devcb_base &set_cd_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_dma_cd.set_callback(object); } + template static devcb_base &set_dma_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_dma.set_callback(object); } + + // computer interface + UINT8 cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + void cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + int game_r(offs_t offset, int sphi2, int ba, int rw, int hiram); + int exrom_r(offs_t offset, int sphi2, int ba, int rw, int hiram); + + // cartridge interface + DECLARE_READ8_MEMBER( dma_cd_r ) { return m_read_dma_cd(offset); } + DECLARE_WRITE8_MEMBER( dma_cd_w ) { m_write_dma_cd(offset, data); } + DECLARE_WRITE_LINE_MEMBER( irq_w ) { m_write_irq(state); } + DECLARE_WRITE_LINE_MEMBER( nmi_w ) { m_write_nmi(state); } + DECLARE_WRITE_LINE_MEMBER( dma_w ) { m_write_dma(state); } + DECLARE_WRITE_LINE_MEMBER( reset_w ) { m_write_reset(state); } + int phi2() { return clock(); } + int dotclock() { return phi2() * 8; } + int hiram() { return m_hiram; } + +protected: + // device-level overrides + virtual void device_config_complete() { update_names(); } + virtual void device_start(); + virtual void device_reset(); + + // image-level overrides + virtual bool call_load(); + virtual bool call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry); + + virtual iodevice_t image_type() const { return IO_CARTSLOT; } + + virtual bool is_readable() const { return 1; } + virtual bool is_writeable() const { return 0; } + virtual bool is_creatable() const { return 0; } + virtual bool must_be_loaded() const { return 0; } + virtual bool is_reset_on_load() const { return 1; } + virtual const char *image_interface() const { return "c64_cart,vic10_cart"; } + virtual const char *file_extensions() const { return "80,a0,e0,crt"; } + virtual const option_guide *create_option_guide() const { return NULL; } + + // slot interface overrides + virtual void get_default_card_software(std::string &result); + + devcb_read8 m_read_dma_cd; + devcb_write8 m_write_dma_cd; + devcb_write_line m_write_irq; + devcb_write_line m_write_nmi; + devcb_write_line m_write_dma; + devcb_write_line m_write_reset; + + device_c64_expansion_card_interface *m_card; + + int m_hiram; +}; + + +// ======================> device_c64_expansion_card_interface + +class device_c64_expansion_card_interface : public device_slot_card_interface +{ + friend class c64_expansion_slot_device; + +public: + // construction/destruction + device_c64_expansion_card_interface(const machine_config &mconfig, device_t &device); + virtual ~device_c64_expansion_card_interface(); + + virtual UINT8 c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) { return data; }; + virtual void c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) { }; + virtual int c64_game_r(offs_t offset, int sphi2, int ba, int rw) { return m_game; } + virtual int c64_exrom_r(offs_t offset, int sphi2, int ba, int rw) { return m_exrom; } + +protected: + optional_shared_ptr m_roml; + optional_shared_ptr m_romh; + optional_shared_ptr m_nvram; + + int m_game; + int m_exrom; + + c64_expansion_slot_device *m_slot; +}; + + +// device type definition +extern const device_type C64_EXPANSION_SLOT; + +SLOT_INTERFACE_EXTERN( c64_expansion_cards ); + + + +#endif diff --git a/src/devices/bus/c64/fcc.c b/src/devices/bus/c64/fcc.c new file mode 100644 index 00000000000..0757ae94e76 --- /dev/null +++ b/src/devices/bus/c64/fcc.c @@ -0,0 +1,255 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Tasc Final ChessCard cartridge emulation + +**********************************************************************/ + +/* + + TODO: + + 629D ldx #$00 + 629F stx $0e + 62A1 sta $df00 + 62A4 inc $d020 + 62A7 dec $d020 + 62AA cpx $0e + 62AC beq $62a4 <-- eternal loop here + 62AE rts + +*/ + +#include "fcc.h" + + + +//************************************************************************** +// MACROS/CONSTANTS +//************************************************************************** + +#define G65SC02P4_TAG "g65sc02p4" + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type C64_FCC = &device_creator; + + +//------------------------------------------------- +// ROM( c64_fcc ) +//------------------------------------------------- + +ROM_START( c64_fcc ) + ROM_REGION( 0x8000, G65SC02P4_TAG, 0 ) + ROM_LOAD( "fcc_rom1", 0x0000, 0x8000, CRC(2949836a) SHA1(9e6283095df9e3f4802ed0c654101f8e37168bf6) ) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *c64_final_chesscard_device::device_rom_region() const +{ + return ROM_NAME( c64_fcc ); +} + + +//------------------------------------------------- +// ADDRESS_MAP( c64_fcc_map ) +//------------------------------------------------- + +static ADDRESS_MAP_START( c64_fcc_map, AS_PROGRAM, 8, c64_final_chesscard_device ) + AM_RANGE(0x0000, 0x1fff) AM_MIRROR(0x6000) AM_READWRITE(nvram_r, nvram_w) + AM_RANGE(0x8000, 0xffff) AM_ROM AM_REGION(G65SC02P4_TAG, 0) +ADDRESS_MAP_END + + +//------------------------------------------------- +// MACHINE_CONFIG_FRAGMENT( c64_fcc ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( c64_fcc ) + MCFG_CPU_ADD(G65SC02P4_TAG, M65SC02, XTAL_5MHz) + MCFG_CPU_PROGRAM_MAP(c64_fcc_map) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor c64_final_chesscard_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( c64_fcc ); +} + + +//------------------------------------------------- +// INPUT_PORTS( c64_fcc ) +//------------------------------------------------- + +static INPUT_PORTS_START( c64_fcc ) + PORT_START("RESET") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_OTHER ) PORT_NAME("Reset") PORT_CODE(KEYCODE_F11) PORT_WRITE_LINE_DEVICE_MEMBER(DEVICE_SELF_OWNER, c64_expansion_slot_device, reset_w) +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor c64_final_chesscard_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( c64_fcc ); +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// c64_final_chesscard_device - constructor +//------------------------------------------------- + +c64_final_chesscard_device::c64_final_chesscard_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, C64_FCC, "Final ChessCard", tag, owner, clock, "c64_fcc", __FILE__), + device_c64_expansion_card_interface(mconfig, *this), + device_nvram_interface(mconfig, *this), + m_maincpu(*this, G65SC02P4_TAG), + m_bank(0), + m_ramen(0) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void c64_final_chesscard_device::device_start() +{ +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void c64_final_chesscard_device::device_reset() +{ + m_maincpu->reset(); + + m_bank = 0; + m_ramen = 0; + m_game = 0; +} + + +//------------------------------------------------- +// c64_cd_r - cartridge data read +//------------------------------------------------- + +UINT8 c64_final_chesscard_device::c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (!roml) + { + if (m_ramen) + { + data = m_nvram[offset & 0x1fff]; + } + else + { + data = m_roml[(m_bank << 14) | (offset & 0x3fff)]; + } + } + else if (!romh) + { + data = m_roml[(m_bank << 14) | (offset & 0x3fff)]; + } + + return data; +} + + +//------------------------------------------------- +// c64_cd_w - cartridge data write +//------------------------------------------------- + +void c64_final_chesscard_device::c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (!roml) + { + if (m_ramen) + { + m_nvram[offset & 0x1fff] = data; + } + } + else if (!io1) + { + /* + + bit description + + 0 ? + 1 + 2 + 3 + 4 + 5 + 6 + 7 + + */ + + printf("IO1 %04x %02x\n", offset, data); + m_bank = BIT(data, 0); + } + else if (!io2) + { + /* + + bit description + + 0 ? + 1 + 2 + 3 + 4 + 5 + 6 + 7 ? + + */ + + printf("IO2 %04x %02x\n", offset, data); + m_ramen = BIT(data, 0); + m_game = BIT(data, 7); + } +} + + +//------------------------------------------------- +// nvram_r - NVRAM read +//------------------------------------------------- + +READ8_MEMBER( c64_final_chesscard_device::nvram_r ) +{ + return m_nvram[offset & m_nvram.mask()]; +} + + +//------------------------------------------------- +// nvram_w - NVRAM write +//------------------------------------------------- + +WRITE8_MEMBER( c64_final_chesscard_device::nvram_w ) +{ + m_nvram[offset & m_nvram.mask()] = data; +} diff --git a/src/devices/bus/c64/fcc.h b/src/devices/bus/c64/fcc.h new file mode 100644 index 00000000000..0727e3ebec4 --- /dev/null +++ b/src/devices/bus/c64/fcc.h @@ -0,0 +1,69 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Tasc Final ChessCard cartridge emulation + +**********************************************************************/ + +#pragma once + +#ifndef __FCC__ +#define __FCC__ + +#include "emu.h" +#include "exp.h" +#include "cpu/m6502/m65sc02.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> c64_final_chesscard_device + +class c64_final_chesscard_device : public device_t, + public device_c64_expansion_card_interface, + public device_nvram_interface +{ +public: + // construction/destruction + c64_final_chesscard_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + virtual ioport_constructor device_input_ports() const; + + DECLARE_READ8_MEMBER( nvram_r ); + DECLARE_WRITE8_MEMBER( nvram_w ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_nvram_interface overrides + virtual void nvram_default() { } + virtual void nvram_read(emu_file &file) { if (m_nvram != NULL) { file.read(m_nvram, m_nvram.bytes()); } } + virtual void nvram_write(emu_file &file) { if (m_nvram != NULL) { file.write(m_nvram, m_nvram.bytes()); } } + + // device_c64_expansion_card_interface overrides + virtual UINT8 c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + virtual void c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + +private: + required_device m_maincpu; + + UINT8 m_bank; + int m_ramen; +}; + + +// device type definition +extern const device_type C64_FCC; + + + +#endif diff --git a/src/devices/bus/c64/final.c b/src/devices/bus/c64/final.c new file mode 100644 index 00000000000..8e29c886a16 --- /dev/null +++ b/src/devices/bus/c64/final.c @@ -0,0 +1,134 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Final Cartridge emulation + +**********************************************************************/ + +#include "final.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type C64_FINAL = &device_creator; + + +//------------------------------------------------- +// INPUT_CHANGED_MEMBER( freeze ) +//------------------------------------------------- + +INPUT_CHANGED_MEMBER( c64_final_cartridge_device::freeze ) +{ + if (newval) + { + m_game = 0; + } + + m_slot->nmi_w(newval); +} + + +//------------------------------------------------- +// INPUT_PORTS( c64_final ) +//------------------------------------------------- + +static INPUT_PORTS_START( c64_final ) + PORT_START("SW") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_OTHER ) PORT_NAME("Reset") PORT_CODE(KEYCODE_F11) PORT_WRITE_LINE_DEVICE_MEMBER(DEVICE_SELF_OWNER, c64_expansion_slot_device, reset_w) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Freeze") PORT_CODE(KEYCODE_F12) PORT_CHANGED_MEMBER(DEVICE_SELF, c64_final_cartridge_device, freeze, 0) +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor c64_final_cartridge_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( c64_final ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// c64_final_cartridge_device - constructor +//------------------------------------------------- + +c64_final_cartridge_device::c64_final_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, C64_FINAL, "C64 Final cartridge", tag, owner, clock, "c64_final", __FILE__), + device_c64_expansion_card_interface(mconfig, *this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void c64_final_cartridge_device::device_start() +{ +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void c64_final_cartridge_device::device_reset() +{ + m_exrom = 0; + m_game = 0; +} + + +//------------------------------------------------- +// c64_cd_r - cartridge data read +//------------------------------------------------- + +UINT8 c64_final_cartridge_device::c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (!roml || !romh || !io1 || !io2) + { + data = m_roml[offset & 0x3fff]; + } + + if (!io1) + { + m_game = 1; + m_exrom = 1; + } + else if (!io2) + { + m_exrom = 0; + m_game = 0; + } + + return data; +} + + +//------------------------------------------------- +// c64_cd_w - cartridge data write +//------------------------------------------------- + +void c64_final_cartridge_device::c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (!io1) + { + m_game = 1; + m_exrom = 1; + } + else if (!io2) + { + m_exrom = 0; + m_game = 0; + } +} diff --git a/src/devices/bus/c64/final.h b/src/devices/bus/c64/final.h new file mode 100644 index 00000000000..44ce29e3fee --- /dev/null +++ b/src/devices/bus/c64/final.h @@ -0,0 +1,53 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Final Cartridge emulation + +**********************************************************************/ + +#pragma once + +#ifndef __FINAL__ +#define __FINAL__ + + +#include "emu.h" +#include "exp.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> c64_final_cartridge_device + +class c64_final_cartridge_device : public device_t, + public device_c64_expansion_card_interface +{ +public: + // construction/destruction + c64_final_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual ioport_constructor device_input_ports() const; + + DECLARE_INPUT_CHANGED_MEMBER( freeze ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_c64_expansion_card_interface overrides + virtual UINT8 c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + virtual void c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); +}; + + +// device type definition +extern const device_type C64_FINAL; + + +#endif diff --git a/src/devices/bus/c64/final3.c b/src/devices/bus/c64/final3.c new file mode 100644 index 00000000000..20f969bcbe7 --- /dev/null +++ b/src/devices/bus/c64/final3.c @@ -0,0 +1,150 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Final Cartridge III emulation + +**********************************************************************/ + +#include "final3.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type C64_FINAL3 = &device_creator; + + +//------------------------------------------------- +// INPUT_CHANGED_MEMBER( freeze ) +//------------------------------------------------- + +INPUT_CHANGED_MEMBER( c64_final3_cartridge_device::freeze ) +{ + if (newval) + { + m_game = 0; + m_hidden = 0; + } + + m_slot->nmi_w(newval); +} + + +//------------------------------------------------- +// INPUT_PORTS( c64_final3 ) +//------------------------------------------------- + +static INPUT_PORTS_START( c64_final3 ) + PORT_START("SW") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_OTHER ) PORT_NAME("Reset") PORT_CODE(KEYCODE_F11) PORT_WRITE_LINE_DEVICE_MEMBER(DEVICE_SELF_OWNER, c64_expansion_slot_device, reset_w) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Freeze") PORT_CODE(KEYCODE_F12) PORT_CHANGED_MEMBER(DEVICE_SELF, c64_final3_cartridge_device, freeze, 0) +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor c64_final3_cartridge_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( c64_final3 ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// c64_final3_cartridge_device - constructor +//------------------------------------------------- + +c64_final3_cartridge_device::c64_final3_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, C64_FINAL3, "C64 Final Cartridge III", tag, owner, clock, "c64_final3", __FILE__), + device_c64_expansion_card_interface(mconfig, *this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void c64_final3_cartridge_device::device_start() +{ + // state saving + save_item(NAME(m_bank)); + save_item(NAME(m_hidden)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void c64_final3_cartridge_device::device_reset() +{ + m_bank = 0; + + m_exrom = 0; + m_game = 0; + + m_slot->nmi_w(CLEAR_LINE); + + m_hidden = 0; +} + + +//------------------------------------------------- +// c64_cd_r - cartridge data read +//------------------------------------------------- + +UINT8 c64_final3_cartridge_device::c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (!roml || !romh || !io1 || !io2) + { + offs_t addr = (m_bank << 14) | (offset & 0x3fff); + data = m_roml[addr]; + } + + return data; +} + + +//------------------------------------------------- +// c64_cd_w - cartridge data write +//------------------------------------------------- + +void c64_final3_cartridge_device::c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (!m_hidden && !io2 && ((offset & 0xff) == 0xff)) + { + /* + + bit description + + 0 A14 + 1 A15 + 2 + 3 + 4 EXROM + 5 GAME + 6 NMI + 7 hide register + + */ + + m_bank = data & 0x03; + + m_exrom = BIT(data, 4); + m_game = BIT(data, 5); + + m_slot->nmi_w(BIT(data, 6) ? CLEAR_LINE : ASSERT_LINE); + + m_hidden = BIT(data, 7); + } +} diff --git a/src/devices/bus/c64/final3.h b/src/devices/bus/c64/final3.h new file mode 100644 index 00000000000..766e40a942b --- /dev/null +++ b/src/devices/bus/c64/final3.h @@ -0,0 +1,57 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Final Cartridge III emulation + +**********************************************************************/ + +#pragma once + +#ifndef __FINAL3__ +#define __FINAL3__ + + +#include "emu.h" +#include "exp.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> c64_final3_cartridge_device + +class c64_final3_cartridge_device : public device_t, + public device_c64_expansion_card_interface +{ +public: + // construction/destruction + c64_final3_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual ioport_constructor device_input_ports() const; + + DECLARE_INPUT_CHANGED_MEMBER( freeze ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_c64_expansion_card_interface overrides + virtual UINT8 c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + virtual void c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + +private: + UINT8 m_bank; + int m_hidden; +}; + + +// device type definition +extern const device_type C64_FINAL3; + + +#endif diff --git a/src/devices/bus/c64/fun_play.c b/src/devices/bus/c64/fun_play.c new file mode 100644 index 00000000000..69aa80288bc --- /dev/null +++ b/src/devices/bus/c64/fun_play.c @@ -0,0 +1,98 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Fun Play / Power Play cartridge emulation + +**********************************************************************/ + +#include "fun_play.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type C64_FUN_PLAY = &device_creator; + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// c64_fun_play_cartridge_device - constructor +//------------------------------------------------- + +c64_fun_play_cartridge_device::c64_fun_play_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, C64_FUN_PLAY, "C64 Fun Play cartridge", tag, owner, clock, "c64_fun_play", __FILE__), + device_c64_expansion_card_interface(mconfig, *this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void c64_fun_play_cartridge_device::device_start() +{ + // state saving + save_item(NAME(m_bank)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void c64_fun_play_cartridge_device::device_reset() +{ + m_bank = 0; +} + + +//------------------------------------------------- +// c64_cd_r - cartridge data read +//------------------------------------------------- + +UINT8 c64_fun_play_cartridge_device::c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (!roml) + { + offs_t addr = (m_bank << 13) | (offset & 0x1fff); + data = m_roml[addr]; + } + + return data; +} + + +//------------------------------------------------- +// c64_cd_w - cartridge data write +//------------------------------------------------- + +void c64_fun_play_cartridge_device::c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (!io1) + { + /* + + bit description + + 0 A16 + 1 + 2 + 3 A13 + 4 A14 + 5 A15 + 6 + 7 + + */ + + m_bank = ((data & 0x01) << 3) | ((data >> 3) & 0x07); + } +} diff --git a/src/devices/bus/c64/fun_play.h b/src/devices/bus/c64/fun_play.h new file mode 100644 index 00000000000..6ea38b0ac7f --- /dev/null +++ b/src/devices/bus/c64/fun_play.h @@ -0,0 +1,51 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Fun Play / Power Play cartridge emulation + +**********************************************************************/ + +#pragma once + +#ifndef __FUN_PLAY__ +#define __FUN_PLAY__ + + +#include "emu.h" +#include "exp.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> c64_fun_play_cartridge_device + +class c64_fun_play_cartridge_device : public device_t, + public device_c64_expansion_card_interface +{ +public: + // construction/destruction + c64_fun_play_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_c64_expansion_card_interface overrides + virtual UINT8 c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + virtual void c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + +private: + UINT8 m_bank; +}; + + +// device type definition +extern const device_type C64_FUN_PLAY; + + +#endif diff --git a/src/devices/bus/c64/geocable.c b/src/devices/bus/c64/geocable.c new file mode 100644 index 00000000000..3b6acc54d2a --- /dev/null +++ b/src/devices/bus/c64/geocable.c @@ -0,0 +1,72 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder, smf +/********************************************************************** + + geoCable Centronics Cable emulation + +**********************************************************************/ + +#include "geocable.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define CENTRONICS_TAG "centronics" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type C64_GEOCABLE = &device_creator; + + +//------------------------------------------------- +// MACHINE_CONFIG_FRAGMENT( c64_geocable ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( c64_geocable ) + MCFG_CENTRONICS_ADD("centronics", centronics_devices, "printer") + MCFG_CENTRONICS_BUSY_HANDLER(WRITELINE(c64_geocable_device, output_b)) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor c64_geocable_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( c64_geocable ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// c64_geocable_device - constructor +//------------------------------------------------- + +c64_geocable_device::c64_geocable_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, C64_GEOCABLE, "C64 geoCable", tag, owner, clock, "c64_geocable", __FILE__), + device_pet_user_port_interface(mconfig, *this), + m_centronics(*this, CENTRONICS_TAG) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void c64_geocable_device::device_start() +{ +} diff --git a/src/devices/bus/c64/geocable.h b/src/devices/bus/c64/geocable.h new file mode 100644 index 00000000000..16d7b831d7a --- /dev/null +++ b/src/devices/bus/c64/geocable.h @@ -0,0 +1,63 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder, smf +/********************************************************************** + + geoCable Centronics Cable emulation + +**********************************************************************/ + +#pragma once + +#ifndef __C64_GEOCABLE__ +#define __C64_GEOCABLE__ + + +#include "emu.h" +#include "user.h" +#include "bus/centronics/ctronics.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> c64_geocable_device + +class c64_geocable_device : public device_t, + public device_pet_user_port_interface +{ +public: + // construction/destruction + c64_geocable_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + +protected: + // device-level overrides + virtual void device_start(); + + // device_pet_user_port_interface overrides + virtual DECLARE_WRITE_LINE_MEMBER(input_c) { m_centronics->write_data0(state); } + virtual DECLARE_WRITE_LINE_MEMBER(input_d) { m_centronics->write_data1(state); } + virtual DECLARE_WRITE_LINE_MEMBER(input_e) { m_centronics->write_data2(state); } + virtual DECLARE_WRITE_LINE_MEMBER(input_f) { m_centronics->write_data3(state); } + virtual DECLARE_WRITE_LINE_MEMBER(input_h) { m_centronics->write_data4(state); } + virtual DECLARE_WRITE_LINE_MEMBER(input_j) { m_centronics->write_data5(state); } + virtual DECLARE_WRITE_LINE_MEMBER(input_k) { m_centronics->write_data6(state); } + virtual DECLARE_WRITE_LINE_MEMBER(input_l) { m_centronics->write_data7(state); } + virtual DECLARE_WRITE_LINE_MEMBER(input_m) { m_centronics->write_strobe(state); } + +private: + required_device m_centronics; + + void update_output(); +}; + + +// device type definition +extern const device_type C64_GEOCABLE; + + +#endif diff --git a/src/devices/bus/c64/georam.c b/src/devices/bus/c64/georam.c new file mode 100644 index 00000000000..d3c30bf029e --- /dev/null +++ b/src/devices/bus/c64/georam.c @@ -0,0 +1,99 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Berkeley Softworks GeoRAM emulation + +**********************************************************************/ + +#include "georam.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type C64_GEORAM = &device_creator; + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// c64_georam_cartridge_device - constructor +//------------------------------------------------- + +c64_georam_cartridge_device::c64_georam_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, C64_GEORAM, "C64 GeoRAM cartridge", tag, owner, clock, "c64_georam", __FILE__), + device_c64_expansion_card_interface(mconfig, *this), + m_ram(*this, "ram") +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void c64_georam_cartridge_device::device_start() +{ + // allocate memory + m_ram.allocate(0x80000); + + // state saving + save_item(NAME(m_bank)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void c64_georam_cartridge_device::device_reset() +{ + m_bank = 0; +} + + +//------------------------------------------------- +// c64_cd_r - cartridge data read +//------------------------------------------------- + +UINT8 c64_georam_cartridge_device::c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (!io1) + { + offs_t addr = (m_bank << 8) | (offset & 0xff); + data = m_ram[addr]; + } + + return data; +} + + +//------------------------------------------------- +// c64_cd_w - cartridge data write +//------------------------------------------------- + +void c64_georam_cartridge_device::c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (!io1) + { + offs_t addr = (m_bank << 8) | (offset & 0xff); + m_ram[addr] = data; + } + else if (!io2) + { + if (BIT(offset, 0)) + { + m_bank = ((data & 0x1f) << 6) | (m_bank & 0x3f); + } + else + { + m_bank = (m_bank & 0x7c0) | (data & 0x3f); + } + } +} diff --git a/src/devices/bus/c64/georam.h b/src/devices/bus/c64/georam.h new file mode 100644 index 00000000000..7415b911dc2 --- /dev/null +++ b/src/devices/bus/c64/georam.h @@ -0,0 +1,53 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Berkeley Softworks GeoRAM emulation + +**********************************************************************/ + +#pragma once + +#ifndef __GEORAM__ +#define __GEORAM__ + + +#include "emu.h" +#include "exp.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> c64_georam_cartridge_device + +class c64_georam_cartridge_device : public device_t, + public device_c64_expansion_card_interface +{ +public: + // construction/destruction + c64_georam_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_c64_expansion_card_interface overrides + virtual UINT8 c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + virtual void c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + +private: + optional_shared_ptr m_ram; + + UINT16 m_bank; +}; + + +// device type definition +extern const device_type C64_GEORAM; + + +#endif diff --git a/src/devices/bus/c64/ide64.c b/src/devices/bus/c64/ide64.c new file mode 100644 index 00000000000..c327b694fd5 --- /dev/null +++ b/src/devices/bus/c64/ide64.c @@ -0,0 +1,357 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + IDE64 v4.1 cartridge emulation + +**********************************************************************/ + +/* + + TODO: + + - fast loader does not work with 1541 + - IDE unknown command (E8) + - FT245 USB + - CompactFlash slot + - ShortBus (ETH64, DUART, DigiMAX, ETFE) + - clock port (ETH64 II, RR-Net, SilverSurfer, MP3@64) + +*/ + +#include "ide64.h" + + + +//************************************************************************** +// MACROS/CONSTANTS +//************************************************************************** + +#define AT29C010A_TAG "u3" +#define DS1302_TAG "u4" +#define FT245R_TAG "u21" +#define ATA_TAG "ata" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type C64_IDE64 = &device_creator; + + +//------------------------------------------------- +// MACHINE_CONFIG_FRAGMENT( c64_ide64 ) +//------------------------------------------------- +static MACHINE_CONFIG_FRAGMENT( c64_ide64 ) + MCFG_ATMEL_29C010_ADD(AT29C010A_TAG) + MCFG_DS1302_ADD(DS1302_TAG, XTAL_32_768kHz) + + MCFG_ATA_INTERFACE_ADD(ATA_TAG, ata_devices, "hdd", NULL, false) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor c64_ide64_cartridge_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( c64_ide64 ); +} + + +//------------------------------------------------- +// INPUT_PORTS( c64_ide64 ) +//------------------------------------------------- + +static INPUT_PORTS_START( c64_ide64 ) + PORT_START("JP1") + PORT_DIPNAME( 0x01, 0x01, "Flash ROM Write Protect" ) + PORT_DIPSETTING( 0x00, "Disabled" ) + PORT_DIPSETTING( 0x01, "Enabled" ) +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor c64_ide64_cartridge_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( c64_ide64 ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// c64_ide64_cartridge_device - constructor +//------------------------------------------------- + +c64_ide64_cartridge_device::c64_ide64_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, C64_IDE64, "C64 IDE64 cartridge", tag, owner, clock, "c64_ide64", __FILE__), + device_c64_expansion_card_interface(mconfig, *this), + m_flash_rom(*this, AT29C010A_TAG), + m_rtc(*this, DS1302_TAG), + m_ata(*this, ATA_TAG), + m_jp1(*this, "JP1"), + m_ram(*this, "ram") +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void c64_ide64_cartridge_device::device_start() +{ + // allocate memory + m_ram.allocate(0x8000); + + // state saving + save_item(NAME(m_bank)); + save_item(NAME(m_ata_data)); + save_item(NAME(m_enable)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void c64_ide64_cartridge_device::device_reset() +{ + m_bank = 0; + + m_enable = 1; + + m_wp = m_jp1->read(); + m_game = !m_wp; + m_exrom = !m_wp; +} + + +//------------------------------------------------- +// c64_cd_r - cartridge data read +//------------------------------------------------- + +UINT8 c64_ide64_cartridge_device::c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (!m_enable) return data; + + int rom_oe = 1, ram_oe = 1; + + if (!m_game && m_exrom && sphi2 && ba) + { + if (offset >= 0x1000 && offset < 0x8000) + { + ram_oe = 0; + } + else if (offset >= 0x8000 && offset < 0xc000) + { + rom_oe = 0; + } + else if (offset >= 0xc000 && offset < 0xd000) + { + ram_oe = 0; + } + } + + if (!roml || !romh) + { + rom_oe = 0; + } + + if (!io1 && sphi2 && ba) + { + // 0x20-0x2f IDE + // 0x30-0x37 I/O + // 0x5d-0x5e FT245 + // 0x5f-0x5f DS1302 + // 0x60-0xff ROM + + UINT8 io1_offset = offset & 0xff; + + if (io1_offset >= 0x20 && io1_offset < 0x28) + { + m_ata_data = m_ata->read_cs0(space, offset & 0x07, 0xffff); + + data = m_ata_data & 0xff; + } + else if (io1_offset >= 0x28 && io1_offset < 0x30) + { + m_ata_data = m_ata->read_cs1(space, offset & 0x07, 0xffff); + + data = m_ata_data & 0xff; + } + else if (io1_offset == 0x31) + { + data = m_ata_data >> 8; + } + else if (io1_offset == 0x32) + { + /* + + bit description + + 0 EXROM + 1 GAME + 2 A14 + 3 A15 + 4 A16 + 5 v4.x + 6 + 7 + + */ + + data = 0x20 | (m_bank << 2) | (m_game << 1) | m_exrom; + } + else if (io1_offset == 0x5f) + { + m_rtc->sclk_w(0); + + data &= ~0x01; + data |= m_rtc->io_r(); + + m_rtc->sclk_w(1); + } + else if (io1_offset >= 0x60) + { + rom_oe = 0; + } + } + + if (!rom_oe) + { + offs_t addr = (m_bank << 14) | (offset & 0x3fff); + + data = m_flash_rom->read(addr); + } + else if (!ram_oe) + { + data = m_ram[offset & 0x7fff]; + } + + return data; +} + + +//------------------------------------------------- +// c64_cd_w - cartridge data write +//------------------------------------------------- + +void c64_ide64_cartridge_device::c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (!m_enable) return; + + if (!m_game && m_exrom) + { + if (offset >= 0x1000 && offset < 0x8000) + { + m_ram[offset & 0x7fff] = data; + } + else if (offset >= 0xc000 && offset < 0xd000) + { + m_ram[offset & 0x7fff] = data; + } + } + + if ((offset >= 0x8000 && offset < 0xc000) && !m_wp) + { + offs_t addr = (m_bank << 14) | (offset & 0x3fff); + m_flash_rom->write(addr, data); + } + + if (!io1) + { + // 0x20-0x2f IDE + // 0x30-0x37 I/O + // 0x5d-0x5e FT245 + // 0x5f-0x5f DS1302 + // 0x60-0xff ROM + + UINT8 io1_offset = offset & 0xff; + + if (io1_offset >= 0x20 && io1_offset < 0x28) + { + m_ata_data = (m_ata_data & 0xff00) | data; + + m_ata->write_cs0(space, offset & 0x07, m_ata_data, 0xffff); + } + else if (io1_offset >= 0x28 && io1_offset < 0x30) + { + m_ata_data = (m_ata_data & 0xff00) | data; + + m_ata->write_cs1(space, offset & 0x07, m_ata_data, 0xffff); + } + else if (io1_offset == 0x31) + { + m_ata_data = (data << 8) | (m_ata_data & 0xff); + } + else if (io1_offset == 0x5f) + { + m_rtc->sclk_w(0); + + m_rtc->io_w(BIT(data, 0)); + + m_rtc->sclk_w(1); + } + else if (io1_offset >= 0x60 && io1_offset < 0x68) + { + m_bank = offset & 0x07; + } + else if (io1_offset == 0xfb) + { + /* + + bit description + + 0 disable cartridge + 1 RTC CE + 2 + 3 + 4 + 5 + 6 + 7 + + */ + + m_enable = !BIT(data, 0); + m_rtc->ce_w(BIT(data, 1)); + } + else if (io1_offset >= 0xfc) + { + m_game = BIT(offset, 0); + m_exrom = BIT(offset, 1); + } + } +} + + +//------------------------------------------------- +// c64_game_r - GAME read +//------------------------------------------------- + +int c64_ide64_cartridge_device::c64_game_r(offs_t offset, int sphi2, int ba, int rw) +{ + return (sphi2 && ba) ? m_game : 1; +} + + +//------------------------------------------------- +// c64_exrom_r - EXROM read +//------------------------------------------------- + +int c64_ide64_cartridge_device::c64_exrom_r(offs_t offset, int sphi2, int ba, int rw) +{ + return (sphi2 && ba) ? m_exrom : 1; +} diff --git a/src/devices/bus/c64/ide64.h b/src/devices/bus/c64/ide64.h new file mode 100644 index 00000000000..c87cbf41479 --- /dev/null +++ b/src/devices/bus/c64/ide64.h @@ -0,0 +1,70 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + IDE64 v4.1 cartridge emulation + +**********************************************************************/ + +#pragma once + +#ifndef __IDE64__ +#define __IDE64__ + + +#include "emu.h" +#include "exp.h" +#include "machine/ds1302.h" +#include "machine/ataintf.h" +#include "machine/intelfsh.h" +#include "imagedev/harddriv.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> c64_ide64_cartridge_device + +class c64_ide64_cartridge_device : public device_t, + public device_c64_expansion_card_interface +{ +public: + // construction/destruction + c64_ide64_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual ioport_constructor device_input_ports() const; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_c64_expansion_card_interface overrides + virtual UINT8 c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + virtual void c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + virtual int c64_game_r(offs_t offset, int sphi2, int ba, int rw); + virtual int c64_exrom_r(offs_t offset, int sphi2, int ba, int rw); + +private: + required_device m_flash_rom; + required_device m_rtc; + required_device m_ata; + required_ioport m_jp1; + optional_shared_ptr m_ram; + + UINT8 m_bank; + UINT16 m_ata_data; + int m_wp; + int m_enable; +}; + + +// device type definition +extern const device_type C64_IDE64; + + +#endif diff --git a/src/devices/bus/c64/ieee488.c b/src/devices/bus/c64/ieee488.c new file mode 100644 index 00000000000..4b41417b42d --- /dev/null +++ b/src/devices/bus/c64/ieee488.c @@ -0,0 +1,249 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Commodore IEEE-488 cartridge emulation + +**********************************************************************/ + +#include "ieee488.h" + + + +//************************************************************************** +// MACROS/CONSTANTS +//************************************************************************** + +#define MOS6525_TAG "u3" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type C64_IEEE488 = &device_creator; + + +//------------------------------------------------- +// tpi6525_interface tpi_intf +//------------------------------------------------- + +READ8_MEMBER( c64_ieee488_device::tpi_pa_r ) +{ + /* + + bit description + + PA0 + PA1 + PA2 REN + PA3 ATN + PA4 DAV + PA5 EOI + PA6 NDAC + PA7 NRFD + + */ + + UINT8 data = 0; + + data |= m_bus->ren_r() << 2; + data |= m_bus->atn_r() << 3; + data |= m_bus->dav_r() << 4; + data |= m_bus->eoi_r() << 5; + data |= m_bus->ndac_r() << 6; + data |= m_bus->nrfd_r() << 7; + + return data; +} + +WRITE8_MEMBER( c64_ieee488_device::tpi_pa_w ) +{ + /* + + bit description + + PA0 U4 DC + PA1 U4/U5 TE + PA2 REN + PA3 ATN + PA4 DAV + PA5 EOI + PA6 NDAC + PA7 NRFD + + */ + + m_bus->ren_w(BIT(data, 2)); + m_bus->atn_w(BIT(data, 3)); + m_bus->dav_w(BIT(data, 4)); + m_bus->eoi_w(BIT(data, 5)); + m_bus->ndac_w(BIT(data, 6)); + m_bus->nrfd_w(BIT(data, 7)); +} + +READ8_MEMBER( c64_ieee488_device::tpi_pc_r ) +{ + /* + + bit description + + PC0 IFC + PC1 SRQ + PC2 + PC3 + PC4 + PC5 + PC6 + PC7 slot _EXROM + + */ + + UINT8 data = 0; + + data |= m_bus->ifc_r(); + data |= m_bus->srq_r() << 1; + + data |= m_exp->exrom_r(offset, 1, 1, 1, 0) << 7; + + return data; +} + +WRITE8_MEMBER( c64_ieee488_device::tpi_pc_w ) +{ + /* + + bit description + + PC0 IFC + PC1 SRQ + PC2 + PC3 C64 _EXROM + PC4 _ROML select + PC5 + PC6 + PC7 + + */ + + m_bus->ifc_w(BIT(data, 0)); + m_bus->srq_w(BIT(data, 1)); + + m_exrom = !BIT(data, 3); + + m_roml_sel = BIT(data, 4); +} + +//------------------------------------------------- +// MACHINE_CONFIG_FRAGMENT( c64_ieee488 ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( c64_ieee488 ) + MCFG_DEVICE_ADD(MOS6525_TAG, TPI6525, 0) + MCFG_TPI6525_IN_PA_CB(READ8(c64_ieee488_device, tpi_pa_r)) + MCFG_TPI6525_OUT_PA_CB(WRITE8(c64_ieee488_device, tpi_pa_w)) + MCFG_TPI6525_IN_PB_CB(DEVREAD8(IEEE488_TAG, ieee488_device, dio_r)) + MCFG_TPI6525_OUT_PB_CB(DEVWRITE8(IEEE488_TAG, ieee488_device, dio_w)) + MCFG_TPI6525_IN_PC_CB(READ8(c64_ieee488_device, tpi_pc_r)) + MCFG_TPI6525_OUT_PC_CB(WRITE8(c64_ieee488_device, tpi_pc_w)) + + MCFG_CBM_IEEE488_ADD(NULL) + MCFG_C64_PASSTHRU_EXPANSION_SLOT_ADD() +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor c64_ieee488_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( c64_ieee488 ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// c64_ieee488_device - constructor +//------------------------------------------------- + +c64_ieee488_device::c64_ieee488_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, C64_IEEE488, "IEEE-488", tag, owner, clock, "c64_ieee488", __FILE__), + device_c64_expansion_card_interface(mconfig, *this), + m_tpi(*this, MOS6525_TAG), + m_bus(*this, IEEE488_TAG), + m_exp(*this, C64_EXPANSION_SLOT_TAG), + m_roml_sel(1) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void c64_ieee488_device::device_start() +{ +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void c64_ieee488_device::device_reset() +{ + m_exrom = 0; +} + + +//------------------------------------------------- +// c64_cd_r - cartridge data read +//------------------------------------------------- + +UINT8 c64_ieee488_device::c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + data = m_exp->cd_r(space, offset, data, sphi2, ba, roml, romh, io1, io2); + + if (!roml && m_roml_sel) + { + data = m_roml[offset & 0xfff]; + } + else if (!io2) + { + data = m_tpi->read(space, offset & 0x07); + } + + return data; +} + + +//------------------------------------------------- +// c64_cd_w - cartridge data write +//------------------------------------------------- + +void c64_ieee488_device::c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (!io2) + { + m_tpi->write(space, offset & 0x07, data); + } + + m_exp->cd_w(space, offset, data, sphi2, ba, roml, romh, io1, io2); +} + + +//------------------------------------------------- +// c64_game_r - GAME read +//------------------------------------------------- + +int c64_ieee488_device::c64_game_r(offs_t offset, int sphi2, int ba, int rw) +{ + return m_exp->game_r(offset, sphi2, ba, rw, m_slot->hiram()); +} diff --git a/src/devices/bus/c64/ieee488.h b/src/devices/bus/c64/ieee488.h new file mode 100644 index 00000000000..9e8b2ee8e4d --- /dev/null +++ b/src/devices/bus/c64/ieee488.h @@ -0,0 +1,67 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Commodore IEEE-488 cartridge emulation + +**********************************************************************/ + +#pragma once + +#ifndef __C64_IEEE488__ +#define __C64_IEEE488__ + +#include "emu.h" +#include "bus/ieee488/ieee488.h" +#include "machine/6525tpi.h" +#include "exp.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> c64_ieee488_device + +class c64_ieee488_device : public device_t, + public device_c64_expansion_card_interface +{ +public: + // construction/destruction + c64_ieee488_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + + // not really public + DECLARE_READ8_MEMBER( tpi_pa_r ); + DECLARE_WRITE8_MEMBER( tpi_pa_w ); + DECLARE_READ8_MEMBER( tpi_pc_r ); + DECLARE_WRITE8_MEMBER( tpi_pc_w ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_c64_expansion_card_interface overrides + virtual UINT8 c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + virtual void c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + virtual int c64_game_r(offs_t offset, int sphi2, int ba, int rw); + +private: + required_device m_tpi; + required_device m_bus; + required_device m_exp; + + int m_roml_sel; +}; + + + +// device type definition +extern const device_type C64_IEEE488; + + +#endif diff --git a/src/devices/bus/c64/kingsoft.c b/src/devices/bus/c64/kingsoft.c new file mode 100644 index 00000000000..215670ae78e --- /dev/null +++ b/src/devices/bus/c64/kingsoft.c @@ -0,0 +1,98 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Kingsoft cartridge emulation + +**********************************************************************/ + +#include "kingsoft.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type C64_KINGSOFT = &device_creator; + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// c64_kingsoft_cartridge_device - constructor +//------------------------------------------------- + +c64_kingsoft_cartridge_device::c64_kingsoft_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, C64_KINGSOFT, "C64 Kingsoft cartridge", tag, owner, clock, "c64_kingsoft", __FILE__), + device_c64_expansion_card_interface(mconfig, *this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void c64_kingsoft_cartridge_device::device_start() +{ +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void c64_kingsoft_cartridge_device::device_reset() +{ + m_exrom = 0; +} + + +//------------------------------------------------- +// c64_cd_r - cartridge data read +//------------------------------------------------- + +UINT8 c64_kingsoft_cartridge_device::c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (!roml) + { + data = m_roml[offset & 0x1fff]; + } + else if (!romh) + { + data = m_romh[(m_exrom << 13) | (offset & 0x1fff)]; + } + else if (!io1) + { + m_exrom = 0; + } + + return data; +} + + +//------------------------------------------------- +// c64_cd_w - cartridge data write +//------------------------------------------------- + +void c64_kingsoft_cartridge_device::c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (!io1) + { + m_exrom = 1; + } +} + + +//------------------------------------------------- +// c64_game_r - GAME read +//------------------------------------------------- + +int c64_kingsoft_cartridge_device::c64_game_r(offs_t offset, int sphi2, int ba, int rw) +{ + return m_exrom & !(ba & rw & ((offset >= 0x8000 && offset < 0xc000) || (offset >= 0xe000))); +} diff --git a/src/devices/bus/c64/kingsoft.h b/src/devices/bus/c64/kingsoft.h new file mode 100644 index 00000000000..d6ca889b5fa --- /dev/null +++ b/src/devices/bus/c64/kingsoft.h @@ -0,0 +1,49 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Kingsoft cartridge emulation + +**********************************************************************/ + +#pragma once + +#ifndef __KINGSOFT__ +#define __KINGSOFT__ + + +#include "emu.h" +#include "exp.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> c64_kingsoft_cartridge_device + +class c64_kingsoft_cartridge_device : public device_t, + public device_c64_expansion_card_interface +{ +public: + // construction/destruction + c64_kingsoft_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_c64_expansion_card_interface overrides + virtual UINT8 c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + virtual void c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + virtual int c64_game_r(offs_t offset, int sphi2, int ba, int rw); +}; + + +// device type definition +extern const device_type C64_KINGSOFT; + + +#endif diff --git a/src/devices/bus/c64/mach5.c b/src/devices/bus/c64/mach5.c new file mode 100644 index 00000000000..dea893ca627 --- /dev/null +++ b/src/devices/bus/c64/mach5.c @@ -0,0 +1,118 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Access Software MACH 5 cartridge emulation + +**********************************************************************/ + +#include "mach5.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type C64_MACH5 = &device_creator; + + +//------------------------------------------------- +// INPUT_PORTS( c64_mach5 ) +//------------------------------------------------- + +static INPUT_PORTS_START( c64_mach5 ) + PORT_START("S1") + PORT_DIPNAME( 0x01, 0x00, "Mode" ) + PORT_DIPSETTING( 0x00, "C64" ) + PORT_DIPSETTING( 0x01, "C128" ) + + PORT_START("S2") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_OTHER ) PORT_NAME("Reset") PORT_CODE(KEYCODE_F11) PORT_WRITE_LINE_DEVICE_MEMBER(DEVICE_SELF_OWNER, c64_expansion_slot_device, reset_w) +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor c64_mach5_cartridge_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( c64_mach5 ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// c64_mach5_cartridge_device - constructor +//------------------------------------------------- + +c64_mach5_cartridge_device::c64_mach5_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, C64_MACH5, "C64 MACH5 cartridge", tag, owner, clock, "c64_mach5", __FILE__), + device_c64_expansion_card_interface(mconfig, *this), + m_s1(*this, "S1") +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void c64_mach5_cartridge_device::device_start() +{ +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void c64_mach5_cartridge_device::device_reset() +{ + m_c128 = m_s1->read(); + + if (!m_c128) + { + m_exrom = 0; + } +} + + +//------------------------------------------------- +// c64_cd_r - cartridge data read +//------------------------------------------------- + +UINT8 c64_mach5_cartridge_device::c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (!roml || !romh || !io1 || !io2) + { + data = m_roml[offset & 0x1fff]; + } + + return data; +} + + +//------------------------------------------------- +// c64_cd_w - cartridge data write +//------------------------------------------------- + +void c64_mach5_cartridge_device::c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (!m_c128) + { + if (!io1) + { + m_exrom = 0; + } + else if (!io2) + { + m_exrom = 1; + } + } +} diff --git a/src/devices/bus/c64/mach5.h b/src/devices/bus/c64/mach5.h new file mode 100644 index 00000000000..b3e448e77b4 --- /dev/null +++ b/src/devices/bus/c64/mach5.h @@ -0,0 +1,55 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Access Software MACH 5 cartridge emulation + +**********************************************************************/ + +#pragma once + +#ifndef __MACH5__ +#define __MACH5__ + +#include "emu.h" +#include "exp.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> c64_mach5_cartridge_device + +class c64_mach5_cartridge_device : public device_t, + public device_c64_expansion_card_interface +{ +public: + // construction/destruction + c64_mach5_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual ioport_constructor device_input_ports() const; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_c64_expansion_card_interface overrides + virtual UINT8 c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + virtual void c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + +private: + required_ioport m_s1; + + bool m_c128; +}; + + +// device type definition +extern const device_type C64_MACH5; + + +#endif diff --git a/src/devices/bus/c64/magic_desk.c b/src/devices/bus/c64/magic_desk.c new file mode 100644 index 00000000000..7c050abb315 --- /dev/null +++ b/src/devices/bus/c64/magic_desk.c @@ -0,0 +1,85 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Magic Desk cartridge emulation + +**********************************************************************/ + +#include "magic_desk.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type C64_MAGIC_DESK = &device_creator; + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// c64_magic_desk_cartridge_device - constructor +//------------------------------------------------- + +c64_magic_desk_cartridge_device::c64_magic_desk_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, C64_MAGIC_DESK, "C64 Magic Desk cartridge", tag, owner, clock, "c64_magic_desk", __FILE__), + device_c64_expansion_card_interface(mconfig, *this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void c64_magic_desk_cartridge_device::device_start() +{ + // state saving + save_item(NAME(m_bank)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void c64_magic_desk_cartridge_device::device_reset() +{ + m_bank = 0; +} + + +//------------------------------------------------- +// c64_cd_r - cartridge data read +//------------------------------------------------- + +UINT8 c64_magic_desk_cartridge_device::c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (!roml) + { + offs_t addr = (m_bank << 13) | (offset & 0x1fff); + data = m_roml[addr]; + } + + return data; +} + + +//------------------------------------------------- +// c64_cd_w - cartridge data write +//------------------------------------------------- + +void c64_magic_desk_cartridge_device::c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (!io1) + { + m_exrom = BIT(data, 7); + + m_bank = data & 0x3f; + } +} diff --git a/src/devices/bus/c64/magic_desk.h b/src/devices/bus/c64/magic_desk.h new file mode 100644 index 00000000000..a1db772cb2c --- /dev/null +++ b/src/devices/bus/c64/magic_desk.h @@ -0,0 +1,51 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Magic Desk cartridge emulation + +**********************************************************************/ + +#pragma once + +#ifndef __MAGIC_DESK__ +#define __MAGIC_DESK__ + + +#include "emu.h" +#include "exp.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> c64_magic_desk_cartridge_device + +class c64_magic_desk_cartridge_device : public device_t, + public device_c64_expansion_card_interface +{ +public: + // construction/destruction + c64_magic_desk_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_c64_expansion_card_interface overrides + virtual UINT8 c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + virtual void c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + +private: + UINT8 m_bank; +}; + + +// device type definition +extern const device_type C64_MAGIC_DESK; + + +#endif diff --git a/src/devices/bus/c64/magic_formel.c b/src/devices/bus/c64/magic_formel.c new file mode 100644 index 00000000000..22faa6cbc9b --- /dev/null +++ b/src/devices/bus/c64/magic_formel.c @@ -0,0 +1,267 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Magic Formel cartridge emulation + +**********************************************************************/ + +/* + + TODO: + + - pia6821 port A DDR needs to reset to 0xff or this won't boot + +*/ + +#include "magic_formel.h" + + + +//************************************************************************** +// MACROS/CONSTANTS +//************************************************************************** + +#define MC6821_TAG "mc6821" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type C64_MAGIC_FORMEL = &device_creator; + + +WRITE8_MEMBER( c64_magic_formel_cartridge_device::pia_pa_w ) +{ + /* + + bit description + + PA0 ROM A13 + PA1 ROM A14 + PA2 ROM A15 + PA3 ROM _OE + PA4 RAM _OE + PA5 + PA6 + PA7 + + */ + + m_rom_bank = data & 0x0f; + + m_ram_oe = BIT(data, 4); +} + +WRITE8_MEMBER( c64_magic_formel_cartridge_device::pia_pb_w ) +{ + /* + + bit description + + PB0 RAM A10 + PB1 RAM A11 + PB2 RAM A9 + PB3 RAM A8 + PB4 RAM A12 + PB5 U9A clr + PB6 + PB7 ROMH enable + + */ + + m_ram_bank = data & 0x1f; + + if (!BIT(data, 5)) + { + m_u9a = 0; + } + + m_pb7 = BIT(data, 7); +} + +WRITE_LINE_MEMBER( c64_magic_formel_cartridge_device::pia_cb2_w ) +{ + if (!state) + { + m_u9b = 1; + } +} + + +//------------------------------------------------- +// MACHINE_CONFIG_FRAGMENT( c64_magic_formel ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( c64_magic_formel ) + MCFG_DEVICE_ADD(MC6821_TAG, PIA6821, 0) + MCFG_PIA_WRITEPA_HANDLER(WRITE8(c64_magic_formel_cartridge_device, pia_pa_w)) + MCFG_PIA_WRITEPB_HANDLER(WRITE8(c64_magic_formel_cartridge_device, pia_pb_w)) + MCFG_PIA_CB2_HANDLER(WRITELINE(c64_magic_formel_cartridge_device, pia_cb2_w)) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor c64_magic_formel_cartridge_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( c64_magic_formel ); +} + + +//------------------------------------------------- +// INPUT_CHANGED_MEMBER( freeze ) +//------------------------------------------------- + +INPUT_CHANGED_MEMBER( c64_magic_formel_cartridge_device::freeze ) +{ + if (newval && (!m_u9a && !m_u9b)) + { + m_u9b = 1; + + m_slot->nmi_w(ASSERT_LINE); + } + else + { + m_slot->nmi_w(CLEAR_LINE); + } +} + + +//------------------------------------------------- +// INPUT_PORTS( c64_magic_formel ) +//------------------------------------------------- + +static INPUT_PORTS_START( c64_magic_formel ) + PORT_START("FREEZE") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Freeze") PORT_CODE(KEYCODE_F12) PORT_CHANGED_MEMBER(DEVICE_SELF, c64_magic_formel_cartridge_device, freeze, 0) +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor c64_magic_formel_cartridge_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( c64_magic_formel ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// c64_magic_formel_cartridge_device - constructor +//------------------------------------------------- + +c64_magic_formel_cartridge_device::c64_magic_formel_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, C64_MAGIC_FORMEL, "C64 Magic Formel cartridge", tag, owner, clock, "c64_magic_formel", __FILE__), + device_c64_expansion_card_interface(mconfig, *this), + m_pia(*this, MC6821_TAG), + m_ram(*this, "ram"), + m_rom_bank(0), + m_ram_bank(0), + m_ram_oe(0), + m_pb7(1), + m_u9a(1), + m_u9b(1) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void c64_magic_formel_cartridge_device::device_start() +{ + // allocate memory + m_ram.allocate(0x2000); + + // state saving + save_item(NAME(m_rom_bank)); + save_item(NAME(m_ram_bank)); + save_item(NAME(m_ram_oe)); + save_item(NAME(m_pb7)); + save_item(NAME(m_u9a)); + save_item(NAME(m_u9b)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void c64_magic_formel_cartridge_device::device_reset() +{ + m_rom_bank = 0; + m_ram_bank = 0; + m_ram_oe = 0; + m_pb7 = 0; + m_u9a = 1; + m_u9b = 1; +} + + +//------------------------------------------------- +// c64_cd_r - cartridge data read +//------------------------------------------------- + +UINT8 c64_magic_formel_cartridge_device::c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (!romh) + { + offs_t addr = (m_rom_bank << 13) | (offset & 0x1fff); + data = m_romh[addr]; + } + else if (!io1 && !m_ram_oe) + { + offs_t addr = (m_ram_bank << 8) | (offset & 0xff); + data = m_ram[addr]; + } + + return data; +} + + +//------------------------------------------------- +// c64_cd_w - cartridge data write +//------------------------------------------------- + +void c64_magic_formel_cartridge_device::c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (!io1 && !m_ram_oe) + { + offs_t addr = (m_ram_bank << 8) | (offset & 0xff); + m_ram[addr] = data; + } + else if (!io2 && !(!m_u9b && m_ram_oe)) + { + offs_t addr = (offset >> 6) & 0x03; + UINT8 new_data = (BIT(data, 1) << 7) | (offset & 0x3f); + + m_pia->write(space, addr, new_data); + } + else if (offset == 0x0001) + { + m_u9a = 1; + } +} + + +//------------------------------------------------- +// c64_game_r - GAME read +//------------------------------------------------- + +int c64_magic_formel_cartridge_device::c64_game_r(offs_t offset, int sphi2, int ba, int rw) +{ + return !(ba && rw && ((offset & 0xe000) == 0xe000) && !(!m_pb7 && !m_u9b)); +} diff --git a/src/devices/bus/c64/magic_formel.h b/src/devices/bus/c64/magic_formel.h new file mode 100644 index 00000000000..251fbbb0c90 --- /dev/null +++ b/src/devices/bus/c64/magic_formel.h @@ -0,0 +1,71 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Magic Formel cartridge emulation + +**********************************************************************/ + +#pragma once + +#ifndef __MAGIC_FORMEL__ +#define __MAGIC_FORMEL__ + +#include "emu.h" +#include "exp.h" +#include "machine/6821pia.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> c64_magic_formel_cartridge_device + +class c64_magic_formel_cartridge_device : public device_t, + public device_c64_expansion_card_interface +{ +public: + // construction/destruction + c64_magic_formel_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual ioport_constructor device_input_ports() const; + + DECLARE_INPUT_CHANGED_MEMBER( freeze ); + + // not really public + DECLARE_WRITE8_MEMBER( pia_pa_w ); + DECLARE_WRITE8_MEMBER( pia_pb_w ); + DECLARE_WRITE_LINE_MEMBER( pia_cb2_w ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_c64_expansion_card_interface overrides + virtual UINT8 c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + virtual void c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + virtual int c64_game_r(offs_t offset, int sphi2, int ba, int rw); + +private: + required_device m_pia; + optional_shared_ptr m_ram; + + UINT8 m_rom_bank; + UINT8 m_ram_bank; + int m_ram_oe; + int m_pb7; + int m_u9a; + int m_u9b; +}; + + +// device type definition +extern const device_type C64_MAGIC_FORMEL; + + +#endif diff --git a/src/devices/bus/c64/magic_voice.c b/src/devices/bus/c64/magic_voice.c new file mode 100644 index 00000000000..c23c87052e4 --- /dev/null +++ b/src/devices/bus/c64/magic_voice.c @@ -0,0 +1,372 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Commodore Magic Voice cartridge emulation + +**********************************************************************/ + +/* + +LA05-123 Pinout +--------------- + _____ _____ + NEXTP 1 |* \_/ | 28 +5V + PD0 2 | | 27 _ROML2 + PD1 3 | | 26 _ROML + PD2 4 | | 25 _I/O2 + PD3 5 | | 24 _GAME + CLEAR 6 | | 23 PHI2 +_RAM/EPROM 7 | LA05-123 | 22 _ROMH2 + PB5 8 | LA05-124 | 21 _ROMH + PB6 9 | | 20 CLOCK + _6525 10 | | 19 SDO + _EPROM 11 | | 18 NEXTS + CA12 12 | | 17 _DA/CA + CA14 13 | | 16 CA15 + GND 14 |_____________| 15 CA13 + + +http://www.stefan-uhlmann.de/cbm/MVM/index.html + +*/ + +/* + + TODO: + + - T6721A speech synthesis + +*/ + +#include "magic_voice.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define T6721A_TAG "u5" +#define MOS6525_TAG "u2" +#define CMOS40105_TAG "u1" + +#define A12 BIT(offset, 12) +#define A13 BIT(offset, 13) +#define A14 BIT(offset, 14) +#define A15 BIT(offset, 15) +#define PB5 BIT(m_tpi_pb, 5) +#define PB6 BIT(m_tpi_pb, 6) + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type C64_MAGIC_VOICE = &device_creator; + + +//------------------------------------------------- +// tpi6525_interface tpi_intf +//------------------------------------------------- + +WRITE_LINE_MEMBER( c64_magic_voice_cartridge_device::tpi_irq_w ) +{ + m_slot->nmi_w(state); +} + +READ8_MEMBER( c64_magic_voice_cartridge_device::tpi_pa_r ) +{ + /* + + bit description + + 0 + 1 + 2 + 3 + 4 + 5 J1 _GAME + 6 T6721 _EOS + 7 FIFO DIR + + */ + + UINT8 data = 0; + + data |= m_exp->game_r(get_offset(m_ca), 1, 1, 1, 0) << 5; + data |= m_vslsi->eos_r() << 6; + data |= m_fifo->dir_r() << 7; + + return data; +} + +WRITE8_MEMBER( c64_magic_voice_cartridge_device::tpi_pa_w ) +{ + /* + + bit description + + 0 FIFO D0 + 1 FIFO D1 + 2 FIFO D2 + 3 FIFO D3 + 4 FIFO SI + 5 + 6 + 7 + + */ + + m_fifo->write(data & 0x0f); + m_fifo->si_w(BIT(data, 4)); +} + +READ8_MEMBER( c64_magic_voice_cartridge_device::tpi_pb_r ) +{ + /* + + bit description + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 J1 _EXROM + + */ + + UINT8 data = 0; + + data |= m_exp->exrom_r(get_offset(m_ca), 1, 1, 1, 0) << 7; + + return data; +} + +WRITE8_MEMBER( c64_magic_voice_cartridge_device::tpi_pb_w ) +{ + /* + + bit description + + 0 T6721 D0 + 1 T6721 D1 + 2 T6721 D2 + 3 T6721 D3 + 4 T6721 _WR + 5 LA05-124 pin 8 (DA/CA) + 6 LA05-124 pin 9 (passthru) + 7 + + */ + + if (!BIT(m_tpi_pb, 4) && BIT(data, 4)) + { + m_vslsi->write(space, 0, data & 0x0f); + } + + m_tpi_pb = data; +} + +WRITE_LINE_MEMBER( c64_magic_voice_cartridge_device::tpi_ca_w ) +{ + m_tpi_pc6 = state; +} + +WRITE_LINE_MEMBER( c64_magic_voice_cartridge_device::tpi_cb_w ) +{ + m_exrom = state; +} + +//------------------------------------------------- +// t6721_interface +//------------------------------------------------- + +WRITE_LINE_MEMBER( c64_magic_voice_cartridge_device::phi2_w ) +{ + if (state) + { + m_vslsi->di_w(m_pd & 0x01); + + m_pd >>= 1; + } +} + +WRITE_LINE_MEMBER( c64_magic_voice_cartridge_device::dtrd_w ) +{ + m_fifo->so_w(!state); + + m_pd = m_fifo->read(); +} + +WRITE_LINE_MEMBER( c64_magic_voice_cartridge_device::apd_w ) +{ + if (state) + { + m_fifo->reset(); + m_pd = 0; + } +} + + +//------------------------------------------------- +// MACHINE_CONFIG_FRAGMENT( c64_magic_voice ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( c64_magic_voice ) + MCFG_DEVICE_ADD(MOS6525_TAG, TPI6525, 0) + MCFG_TPI6525_OUT_IRQ_CB(WRITELINE(c64_magic_voice_cartridge_device, tpi_irq_w)) + MCFG_TPI6525_IN_PA_CB(READ8(c64_magic_voice_cartridge_device, tpi_pa_r)) + MCFG_TPI6525_OUT_PA_CB(WRITE8(c64_magic_voice_cartridge_device, tpi_pa_w)) + MCFG_TPI6525_IN_PB_CB(READ8(c64_magic_voice_cartridge_device, tpi_pb_r)) + MCFG_TPI6525_OUT_PB_CB(WRITE8(c64_magic_voice_cartridge_device, tpi_pb_w)) + MCFG_TPI6525_OUT_CA_CB(WRITELINE(c64_magic_voice_cartridge_device, tpi_ca_w)) + MCFG_TPI6525_OUT_CA_CB(WRITELINE(c64_magic_voice_cartridge_device, tpi_cb_w)) + MCFG_40105_ADD(CMOS40105_TAG, DEVWRITELINE(MOS6525_TAG, tpi6525_device, i3_w), NULL) + + MCFG_SPEAKER_STANDARD_MONO("mono") + MCFG_SOUND_ADD(T6721A_TAG, T6721A, XTAL_640kHz) + MCFG_T6721A_EOS_HANDLER(DEVWRITELINE(MOS6525_TAG, tpi6525_device, i2_w)) + MCFG_T6721A_PHI2_HANDLER(DEVWRITELINE(DEVICE_SELF, c64_magic_voice_cartridge_device, phi2_w)) + MCFG_T6721A_DTRD_HANDLER(DEVWRITELINE(DEVICE_SELF, c64_magic_voice_cartridge_device, dtrd_w)) + MCFG_T6721A_APD_HANDLER(DEVWRITELINE(DEVICE_SELF, c64_magic_voice_cartridge_device, apd_w)) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.25) + + MCFG_C64_PASSTHRU_EXPANSION_SLOT_ADD() +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor c64_magic_voice_cartridge_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( c64_magic_voice ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// c64_magic_voice_cartridge_device - constructor +//------------------------------------------------- + +c64_magic_voice_cartridge_device::c64_magic_voice_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, C64_MAGIC_VOICE, "C64 Magic Voice cartridge", tag, owner, clock, "c64_magic_voice", __FILE__), + device_c64_expansion_card_interface(mconfig, *this), + m_vslsi(*this, T6721A_TAG), + m_tpi(*this, MOS6525_TAG), + m_fifo(*this, CMOS40105_TAG), + m_exp(*this, C64_EXPANSION_SLOT_TAG), + m_tpi_pb(0x60), + m_tpi_pc6(1), + m_pd(0) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void c64_magic_voice_cartridge_device::device_start() +{ + // state saving + save_item(NAME(m_tpi_pb)); + save_item(NAME(m_tpi_pc6)); + save_item(NAME(m_pd)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void c64_magic_voice_cartridge_device::device_reset() +{ + m_tpi->reset(); + + m_exrom = 1; + + m_tpi_pb = 0x60; + m_tpi_pc6 = 1; + m_pd = 0; +} + + +//------------------------------------------------- +// c64_cd_r - cartridge data read +//------------------------------------------------- + +UINT8 c64_magic_voice_cartridge_device::c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (!io2 && sphi2) + { + m_ca = offset; + data = m_tpi->read(space, offset & 0x07); + } + + if (PB6 && A13 && A15) + { + data = m_romh[(A14 << 13) | (offset & 0x1fff)]; + } + + int roml2 = !(!roml || (roml && !PB5 && A12 && A13 && !A14 && A15)); + int romh2 = !((!romh && !PB6) || (!PB5 && A12 && A13 && !A14 && !A15)); + + data = m_exp->cd_r(space, get_offset(offset), data, sphi2, ba, roml2, romh2, io1, 1); + + return data; +} + + +//------------------------------------------------- +// c64_cd_w - cartridge data write +//------------------------------------------------- + +void c64_magic_voice_cartridge_device::c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (!io2 && sphi2) + { + m_tpi->write(space, offset & 0x07, data); + } + + int roml2 = !(!roml || (roml && !PB5 && A12 && A13 && !A14 && A15)); + int romh2 = !((!romh && !PB6) || (!PB5 && A12 && A13 && !A14 && !A15)); + + m_exp->cd_w(space, get_offset(offset), data, sphi2, ba, roml2, romh2, io1, 1); +} + + +//------------------------------------------------- +// c64_game_r - GAME read +//------------------------------------------------- + +int c64_magic_voice_cartridge_device::c64_game_r(offs_t offset, int sphi2, int ba, int rw) +{ + return !((m_tpi_pc6 && sphi2) || (!m_tpi_pc6 && sphi2 && !PB5 && A12 && A13 && !A14)); +} + + +//------------------------------------------------- +// get_offset - +//------------------------------------------------- + +offs_t c64_magic_voice_cartridge_device::get_offset(offs_t offset) +{ + if (!PB5 && A12 && A13 && !A14) + { + offset = ((m_tpi_pb & 0x0f) << 12) | (offset & 0xfff); + } + + return offset; +} diff --git a/src/devices/bus/c64/magic_voice.h b/src/devices/bus/c64/magic_voice.h new file mode 100644 index 00000000000..ef385a5a502 --- /dev/null +++ b/src/devices/bus/c64/magic_voice.h @@ -0,0 +1,82 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Commodore Magic Voice cartridge emulation + +**********************************************************************/ + +#pragma once + +#ifndef __MAGIC_VOICE__ +#define __MAGIC_VOICE__ + +#include "emu.h" +#include "machine/40105.h" +#include "machine/6525tpi.h" +#include "exp.h" +#include "sound/t6721a.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> c64_magic_voice_cartridge_device + +class c64_magic_voice_cartridge_device : public device_t, + public device_c64_expansion_card_interface +{ +public: + // construction/destruction + c64_magic_voice_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + + DECLARE_WRITE_LINE_MEMBER( tpi_irq_w ); + DECLARE_READ8_MEMBER( tpi_pa_r ); + DECLARE_WRITE8_MEMBER( tpi_pa_w ); + DECLARE_READ8_MEMBER( tpi_pb_r ); + DECLARE_WRITE8_MEMBER( tpi_pb_w ); + DECLARE_READ8_MEMBER( tpi_pc_r ); + DECLARE_WRITE8_MEMBER( tpi_pc_w ); + DECLARE_WRITE_LINE_MEMBER( tpi_ca_w ); + DECLARE_WRITE_LINE_MEMBER( tpi_cb_w ); + + DECLARE_WRITE_LINE_MEMBER( phi2_w ); + DECLARE_WRITE_LINE_MEMBER( dtrd_w ); + DECLARE_WRITE_LINE_MEMBER( apd_w ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_c64_expansion_card_interface overrides + virtual UINT8 c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + virtual void c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + virtual int c64_game_r(offs_t offset, int sphi2, int ba, int rw); + +private: + offs_t get_offset(offs_t offset); + + required_device m_vslsi; + required_device m_tpi; + required_device m_fifo; + required_device m_exp; + + UINT16 m_ca; + UINT8 m_tpi_pb; + int m_tpi_pc6; + UINT8 m_pd; +}; + + +// device type definition +extern const device_type C64_MAGIC_VOICE; + + + +#endif diff --git a/src/devices/bus/c64/midi_maplin.c b/src/devices/bus/c64/midi_maplin.c new file mode 100644 index 00000000000..7a143391129 --- /dev/null +++ b/src/devices/bus/c64/midi_maplin.c @@ -0,0 +1,152 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Maplin MIDI Interface cartridge emulation + +**********************************************************************/ + +#include "midi_maplin.h" +#include "machine/clock.h" +#include "bus/midi/midi.h" + + + +//************************************************************************** +// MACROS/CONSTANTS +//************************************************************************** + +#define MC6850_TAG "mc6850" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type C64_MIDI_MAPLIN = &device_creator; + + +WRITE_LINE_MEMBER( c64_maplin_midi_cartridge_device::acia_irq_w ) +{ + m_slot->irq_w(state); +} + +WRITE_LINE_MEMBER( c64_maplin_midi_cartridge_device::write_acia_clock ) +{ + m_acia->write_txc(state); + m_acia->write_rxc(state); +} + + +//------------------------------------------------- +// MACHINE_CONFIG_FRAGMENT( c64_maplin_midi ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( c64_maplin_midi ) + MCFG_DEVICE_ADD(MC6850_TAG, ACIA6850, 0) + MCFG_ACIA6850_TXD_HANDLER(DEVWRITELINE("mdout", midi_port_device, write_txd)) + MCFG_ACIA6850_IRQ_HANDLER(WRITELINE(c64_maplin_midi_cartridge_device, acia_irq_w)) + + MCFG_MIDI_PORT_ADD("mdin", midiin_slot, "midiin") + MCFG_MIDI_RX_HANDLER(DEVWRITELINE(MC6850_TAG, acia6850_device, write_rxd)) + + MCFG_MIDI_PORT_ADD("mdout", midiout_slot, "midiout") + + MCFG_DEVICE_ADD("acia_clock", CLOCK, 31250*16) + MCFG_CLOCK_SIGNAL_HANDLER(WRITELINE(c64_maplin_midi_cartridge_device, write_acia_clock)) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor c64_maplin_midi_cartridge_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( c64_maplin_midi ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// c64_maplin_midi_cartridge_device - constructor +//------------------------------------------------- + +c64_maplin_midi_cartridge_device::c64_maplin_midi_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, C64_MIDI_MAPLIN, "C64 Maplin MIDI", tag, owner, clock, "c64_midimap", __FILE__), + device_c64_expansion_card_interface(mconfig, *this), + m_acia(*this, MC6850_TAG) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void c64_maplin_midi_cartridge_device::device_start() +{ + // state saving +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void c64_maplin_midi_cartridge_device::device_reset() +{ + m_acia->reset(); +} + + +//------------------------------------------------- +// c64_cd_r - cartridge data read +//------------------------------------------------- + +UINT8 c64_maplin_midi_cartridge_device::c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (!io2) + { + switch (offset & 0xff) + { + case 0: + data = m_acia->status_r(space, 0); + break; + + case 1: + data = m_acia->data_r(space, 0); + break; + } + } + + return data; +} + + +//------------------------------------------------- +// c64_cd_w - cartridge data write +//------------------------------------------------- + +void c64_maplin_midi_cartridge_device::c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (!io2) + { + switch (offset & 0xff) + { + case 0: + m_acia->control_w(space, 0, data); + break; + + case 1: + m_acia->data_w(space, 0, data); + break; + } + } +} diff --git a/src/devices/bus/c64/midi_maplin.h b/src/devices/bus/c64/midi_maplin.h new file mode 100644 index 00000000000..95f447f122e --- /dev/null +++ b/src/devices/bus/c64/midi_maplin.h @@ -0,0 +1,56 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Maplin MIDI Interface cartridge emulation + +**********************************************************************/ + +#pragma once + +#ifndef __C64_MIDI_MAPLIN__ +#define __C64_MIDI_MAPLIN__ + +#include "exp.h" +#include "machine/6850acia.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> c64_maplin_midi_cartridge_device + +class c64_maplin_midi_cartridge_device : public device_t, + public device_c64_expansion_card_interface +{ +public: + // construction/destruction + c64_maplin_midi_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + + DECLARE_WRITE_LINE_MEMBER( acia_irq_w ); + DECLARE_WRITE_LINE_MEMBER( write_acia_clock ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_c64_expansion_card_interface overrides + virtual UINT8 c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + virtual void c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + +private: + required_device m_acia; +}; + + +// device type definition +extern const device_type C64_MIDI_MAPLIN; + + +#endif diff --git a/src/devices/bus/c64/midi_namesoft.c b/src/devices/bus/c64/midi_namesoft.c new file mode 100644 index 00000000000..cd1553b6187 --- /dev/null +++ b/src/devices/bus/c64/midi_namesoft.c @@ -0,0 +1,150 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Namesoft MIDI Interface cartridge emulation + +**********************************************************************/ + +#include "midi_namesoft.h" +#include "machine/clock.h" +#include "bus/midi/midi.h" + + + +//************************************************************************** +// MACROS/CONSTANTS +//************************************************************************** + +#define MC6850_TAG "mc6850" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type C64_MIDI_NAMESOFT = &device_creator; + + +WRITE_LINE_MEMBER( c64_namesoft_midi_cartridge_device::acia_irq_w ) +{ + m_slot->nmi_w(state); +} + +WRITE_LINE_MEMBER( c64_namesoft_midi_cartridge_device::write_acia_clock ) +{ + m_acia->write_txc(state); + m_acia->write_rxc(state); +} + + +//------------------------------------------------- +// MACHINE_CONFIG_FRAGMENT( c64_passport_midi ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( c64_passport_midi ) + MCFG_DEVICE_ADD(MC6850_TAG, ACIA6850, 0) + MCFG_ACIA6850_TXD_HANDLER(DEVWRITELINE("mdout", midi_port_device, write_txd)) + MCFG_ACIA6850_IRQ_HANDLER(WRITELINE(c64_namesoft_midi_cartridge_device, acia_irq_w)) + + MCFG_MIDI_PORT_ADD("mdin", midiin_slot, "midiin") + MCFG_MIDI_RX_HANDLER(DEVWRITELINE(MC6850_TAG, acia6850_device, write_rxd)) + + MCFG_MIDI_PORT_ADD("mdout", midiout_slot, "midiout") + + MCFG_DEVICE_ADD("acia_clock", CLOCK, 31250*16) + MCFG_CLOCK_SIGNAL_HANDLER(WRITELINE(c64_namesoft_midi_cartridge_device, write_acia_clock)) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor c64_namesoft_midi_cartridge_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( c64_passport_midi ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// c64_namesoft_midi_cartridge_device - constructor +//------------------------------------------------- + +c64_namesoft_midi_cartridge_device::c64_namesoft_midi_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, C64_MIDI_NAMESOFT, "C64 Namesoft MIDI", tag, owner, clock, "c64_midins", __FILE__), + device_c64_expansion_card_interface(mconfig, *this), + m_acia(*this, MC6850_TAG) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void c64_namesoft_midi_cartridge_device::device_start() +{ +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void c64_namesoft_midi_cartridge_device::device_reset() +{ + m_acia->reset(); +} + + +//------------------------------------------------- +// c64_cd_r - cartridge data read +//------------------------------------------------- + +UINT8 c64_namesoft_midi_cartridge_device::c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (!io1) + { + switch (offset & 0xff) + { + case 2: + data = m_acia->status_r(space, 0); + break; + + case 3: + data = m_acia->data_r(space, 0); + break; + } + } + + return data; +} + + +//------------------------------------------------- +// c64_cd_w - cartridge data write +//------------------------------------------------- + +void c64_namesoft_midi_cartridge_device::c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (!io1) + { + switch (offset & 0xff) + { + case 0: + m_acia->control_w(space, 0, data); + break; + + case 1: + m_acia->data_w(space, 0, data); + break; + } + } +} diff --git a/src/devices/bus/c64/midi_namesoft.h b/src/devices/bus/c64/midi_namesoft.h new file mode 100644 index 00000000000..bc91dbd8f86 --- /dev/null +++ b/src/devices/bus/c64/midi_namesoft.h @@ -0,0 +1,56 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Namesoft MIDI Interface cartridge emulation + +**********************************************************************/ + +#pragma once + +#ifndef __C64_MIDI_NAMESOFT__ +#define __C64_MIDI_NAMESOFT__ + +#include "exp.h" +#include "machine/6850acia.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> c64_namesoft_midi_cartridge_device + +class c64_namesoft_midi_cartridge_device : public device_t, + public device_c64_expansion_card_interface +{ +public: + // construction/destruction + c64_namesoft_midi_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + + DECLARE_WRITE_LINE_MEMBER( acia_irq_w ); + DECLARE_WRITE_LINE_MEMBER( write_acia_clock ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_c64_expansion_card_interface overrides + virtual UINT8 c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + virtual void c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + +private: + required_device m_acia; +}; + + +// device type definition +extern const device_type C64_MIDI_NAMESOFT; + + +#endif diff --git a/src/devices/bus/c64/midi_passport.c b/src/devices/bus/c64/midi_passport.c new file mode 100644 index 00000000000..2948503f675 --- /dev/null +++ b/src/devices/bus/c64/midi_passport.c @@ -0,0 +1,195 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Passport/Syntech MIDI Interface cartridge emulation + +**********************************************************************/ + +#include "midi_passport.h" +#include "machine/clock.h" +#include "bus/midi/midi.h" + + + +//************************************************************************** +// MACROS/CONSTANTS +//************************************************************************** + +#define MC6840_TAG "mc6840" +#define MC6850_TAG "mc6850" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type C64_MIDI_PASSPORT = &device_creator; + + +//------------------------------------------------- +// ptm6840_interface ptm_intf +//------------------------------------------------- + +WRITE_LINE_MEMBER( c64_passport_midi_cartridge_device::ptm_irq_w ) +{ + m_ptm_irq = state; + + m_slot->irq_w(m_ptm_irq || m_acia_irq); +} + +WRITE_LINE_MEMBER( c64_passport_midi_cartridge_device::acia_irq_w ) +{ + m_acia_irq = state; + + m_slot->irq_w(m_ptm_irq || m_acia_irq); +} + +WRITE_LINE_MEMBER( c64_passport_midi_cartridge_device::write_acia_clock ) +{ + m_acia->write_txc(state); + m_acia->write_rxc(state); +} + + +//------------------------------------------------- +// MACHINE_CONFIG_FRAGMENT( c64_passport_midi ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( c64_passport_midi ) + MCFG_DEVICE_ADD(MC6850_TAG, ACIA6850, 0) + MCFG_ACIA6850_TXD_HANDLER(DEVWRITELINE("mdout", midi_port_device, write_txd)) + MCFG_ACIA6850_IRQ_HANDLER(WRITELINE(c64_passport_midi_cartridge_device, acia_irq_w)) + + MCFG_DEVICE_ADD(MC6840_TAG, PTM6840, 0) + MCFG_PTM6840_INTERNAL_CLOCK(1021800.0f) + MCFG_PTM6840_EXTERNAL_CLOCKS(1021800.0f, 1021800.0f, 1021800.0f) + MCFG_PTM6840_IRQ_CB(WRITELINE(c64_passport_midi_cartridge_device, ptm_irq_w)) + + MCFG_MIDI_PORT_ADD("mdin", midiin_slot, "midiin") + MCFG_MIDI_RX_HANDLER(DEVWRITELINE(MC6850_TAG, acia6850_device, write_rxd)) + + MCFG_MIDI_PORT_ADD("mdout", midiout_slot, "midiout") + + MCFG_DEVICE_ADD("acia_clock", CLOCK, 31250*16) /// TODO: work out if the clock should come from the 6840 + MCFG_CLOCK_SIGNAL_HANDLER(WRITELINE(c64_passport_midi_cartridge_device, write_acia_clock)) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor c64_passport_midi_cartridge_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( c64_passport_midi ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// c64_passport_midi_cartridge_device - constructor +//------------------------------------------------- + +c64_passport_midi_cartridge_device::c64_passport_midi_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, C64_MIDI_PASSPORT, "C64 Passport MIDI", tag, owner, clock, "c64_midipp", __FILE__), + device_c64_expansion_card_interface(mconfig, *this), + m_acia(*this, MC6850_TAG), + m_ptm(*this, MC6840_TAG), + m_ptm_irq(CLEAR_LINE), + m_acia_irq(CLEAR_LINE) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void c64_passport_midi_cartridge_device::device_start() +{ + // state saving + save_item(NAME(m_ptm_irq)); + save_item(NAME(m_acia_irq)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void c64_passport_midi_cartridge_device::device_reset() +{ + m_acia->reset(); + m_ptm->reset(); +} + + +//------------------------------------------------- +// c64_cd_r - cartridge data read +//------------------------------------------------- + +UINT8 c64_passport_midi_cartridge_device::c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (!io1) + { + switch (offset & 0xff) + { + case 0: case 1: case 2: case 3: + case 4: case 5: case 6: case 7: + data = m_ptm->read(space, offset & 0x07); + break; + + case 8: + data = m_acia->status_r(space, 0); + break; + + case 9: + data = m_acia->data_r(space, 0); + break; + } + } + + return data; +} + + +//------------------------------------------------- +// c64_cd_w - cartridge data write +//------------------------------------------------- + +void c64_passport_midi_cartridge_device::c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (!io1) + { + switch (offset & 0xff) + { + case 0: case 1: case 2: case 3: + case 4: case 5: case 6: case 7: + m_ptm->write(space, offset & 0x07, data); + break; + + case 8: + m_acia->control_w(space, 0, data); + break; + + case 9: + m_acia->data_w(space, 0, data); + break; + + case 0x30: + // Drum sync SET + break; + + case 0x38: + // Drum sync CLEAR + break; + } + } +} diff --git a/src/devices/bus/c64/midi_passport.h b/src/devices/bus/c64/midi_passport.h new file mode 100644 index 00000000000..e60331cd727 --- /dev/null +++ b/src/devices/bus/c64/midi_passport.h @@ -0,0 +1,62 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Passport/Syntech MIDI Interface cartridge emulation + +**********************************************************************/ + +#pragma once + +#ifndef __C64_MIDI_PASSPORT__ +#define __C64_MIDI_PASSPORT__ + +#include "exp.h" +#include "machine/6840ptm.h" +#include "machine/6850acia.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> c64_passport_midi_cartridge_device + +class c64_passport_midi_cartridge_device : public device_t, + public device_c64_expansion_card_interface +{ +public: + // construction/destruction + c64_passport_midi_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + + DECLARE_WRITE_LINE_MEMBER( ptm_irq_w ); + DECLARE_WRITE_LINE_MEMBER( acia_irq_w ); + DECLARE_WRITE_LINE_MEMBER( write_acia_clock ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_c64_expansion_card_interface overrides + virtual UINT8 c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + virtual void c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + +private: + required_device m_acia; + required_device m_ptm; + + int m_ptm_irq; + int m_acia_irq; +}; + + +// device type definition +extern const device_type C64_MIDI_PASSPORT; + + +#endif diff --git a/src/devices/bus/c64/midi_sci.c b/src/devices/bus/c64/midi_sci.c new file mode 100644 index 00000000000..40e2c56cbfc --- /dev/null +++ b/src/devices/bus/c64/midi_sci.c @@ -0,0 +1,151 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Sequential Circuits MIDI Interface cartridge emulation + +**********************************************************************/ + +#include "midi_sci.h" +#include "machine/clock.h" +#include "bus/midi/midi.h" + + + +//************************************************************************** +// MACROS/CONSTANTS +//************************************************************************** + +#define MC6850_TAG "mc6850" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type C64_MIDI_SCI = &device_creator; + + +WRITE_LINE_MEMBER( c64_sequential_midi_cartridge_device::acia_irq_w ) +{ + m_slot->irq_w(state); +} + +WRITE_LINE_MEMBER( c64_sequential_midi_cartridge_device::write_acia_clock ) +{ + m_acia->write_txc(state); + m_acia->write_rxc(state); +} + + +//------------------------------------------------- +// MACHINE_CONFIG_FRAGMENT( c64_sequential_midi ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( c64_sequential_midi ) + MCFG_DEVICE_ADD(MC6850_TAG, ACIA6850, 0) + MCFG_ACIA6850_TXD_HANDLER(DEVWRITELINE("mdout", midi_port_device, write_txd)) + MCFG_ACIA6850_IRQ_HANDLER(WRITELINE(c64_sequential_midi_cartridge_device, acia_irq_w)) + + MCFG_MIDI_PORT_ADD("mdin", midiin_slot, "midiin") + MCFG_MIDI_RX_HANDLER(DEVWRITELINE(MC6850_TAG, acia6850_device, write_rxd)) + + MCFG_MIDI_PORT_ADD("mdout", midiout_slot, "midiout") + + MCFG_DEVICE_ADD("acia_clock", CLOCK, 31250*16) + MCFG_CLOCK_SIGNAL_HANDLER(WRITELINE(c64_sequential_midi_cartridge_device, write_acia_clock)) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor c64_sequential_midi_cartridge_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( c64_sequential_midi ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// c64_sequential_midi_cartridge_device - constructor +//------------------------------------------------- + +c64_sequential_midi_cartridge_device::c64_sequential_midi_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, C64_MIDI_SCI, "C64 Sequential Circuits MIDI", tag, owner, clock, "c64_midisci", __FILE__), + device_c64_expansion_card_interface(mconfig, *this), + m_acia(*this, MC6850_TAG) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void c64_sequential_midi_cartridge_device::device_start() +{ + // state saving +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void c64_sequential_midi_cartridge_device::device_reset() +{ + m_acia->reset(); +} + + +//------------------------------------------------- +// c64_cd_r - cartridge data read +//------------------------------------------------- + +UINT8 c64_sequential_midi_cartridge_device::c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (!io1) + { + switch (offset & 0xff) + { + case 2: + data = m_acia->status_r(space, 0); + break; + + case 3: + data = m_acia->data_r(space, 0); + break; + } + } + + return data; +} + + +//------------------------------------------------- +// c64_cd_w - cartridge data write +//------------------------------------------------- + +void c64_sequential_midi_cartridge_device::c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (!io1) + { + switch (offset & 0xff) + { + case 0: + m_acia->control_w(space, 0, data); + break; + + case 1: + m_acia->data_w(space, 0, data); + break; + } + } +} diff --git a/src/devices/bus/c64/midi_sci.h b/src/devices/bus/c64/midi_sci.h new file mode 100644 index 00000000000..0401f3a82a1 --- /dev/null +++ b/src/devices/bus/c64/midi_sci.h @@ -0,0 +1,56 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Sequential Circuits MIDI Interface cartridge emulation + +**********************************************************************/ + +#pragma once + +#ifndef __C64_MIDI_SCI__ +#define __C64_MIDI_SCI__ + +#include "exp.h" +#include "machine/6850acia.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> c64_sequential_midi_cartridge_device + +class c64_sequential_midi_cartridge_device : public device_t, + public device_c64_expansion_card_interface +{ +public: + // construction/destruction + c64_sequential_midi_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + + DECLARE_WRITE_LINE_MEMBER( acia_irq_w ); + DECLARE_WRITE_LINE_MEMBER( write_acia_clock ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_c64_expansion_card_interface overrides + virtual UINT8 c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + virtual void c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + +private: + required_device m_acia; +}; + + +// device type definition +extern const device_type C64_MIDI_SCI; + + +#endif diff --git a/src/devices/bus/c64/midi_siel.c b/src/devices/bus/c64/midi_siel.c new file mode 100644 index 00000000000..cce956a1427 --- /dev/null +++ b/src/devices/bus/c64/midi_siel.c @@ -0,0 +1,152 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Siel/JMS/DATEL MIDI Interface cartridge emulation + +**********************************************************************/ + +#include "midi_siel.h" +#include "machine/clock.h" +#include "bus/midi/midi.h" + + + +//************************************************************************** +// MACROS/CONSTANTS +//************************************************************************** + +#define MC6850_TAG "mc6850" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type C64_MIDI_SIEL = &device_creator; + + +WRITE_LINE_MEMBER( c64_siel_midi_cartridge_device::acia_irq_w ) +{ + m_slot->irq_w(state); +} + +WRITE_LINE_MEMBER( c64_siel_midi_cartridge_device::write_acia_clock ) +{ + m_acia->write_txc(state); + m_acia->write_rxc(state); +} + + +//------------------------------------------------- +// MACHINE_CONFIG_FRAGMENT( c64_siel_midi ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( c64_siel_midi ) + MCFG_DEVICE_ADD(MC6850_TAG, ACIA6850, 0) + MCFG_ACIA6850_TXD_HANDLER(DEVWRITELINE("mdout", midi_port_device, write_txd)) + MCFG_ACIA6850_IRQ_HANDLER(WRITELINE(c64_siel_midi_cartridge_device, acia_irq_w)) + + MCFG_MIDI_PORT_ADD("mdin", midiin_slot, "midiin") + MCFG_MIDI_RX_HANDLER(DEVWRITELINE(MC6850_TAG, acia6850_device, write_rxd)) + + MCFG_MIDI_PORT_ADD("mdout", midiout_slot, "midiout") + + MCFG_DEVICE_ADD("acia_clock", CLOCK, 31250*16) + MCFG_CLOCK_SIGNAL_HANDLER(WRITELINE(c64_siel_midi_cartridge_device, write_acia_clock)) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor c64_siel_midi_cartridge_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( c64_siel_midi ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// c64_siel_midi_cartridge_device - constructor +//------------------------------------------------- + +c64_siel_midi_cartridge_device::c64_siel_midi_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, C64_MIDI_SIEL, "C64 Siel MIDI", tag, owner, clock, "c64_midisiel", __FILE__), + device_c64_expansion_card_interface(mconfig, *this), + m_acia(*this, MC6850_TAG) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void c64_siel_midi_cartridge_device::device_start() +{ + // state saving +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void c64_siel_midi_cartridge_device::device_reset() +{ + m_acia->reset(); +} + + +//------------------------------------------------- +// c64_cd_r - cartridge data read +//------------------------------------------------- + +UINT8 c64_siel_midi_cartridge_device::c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (!io1) + { + switch (offset & 0xff) + { + case 6: + data = m_acia->status_r(space, 0); + break; + + case 7: + data = m_acia->data_r(space, 0); + break; + } + } + + return data; +} + + +//------------------------------------------------- +// c64_cd_w - cartridge data write +//------------------------------------------------- + +void c64_siel_midi_cartridge_device::c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (!io1) + { + switch (offset & 0xff) + { + case 4: + m_acia->control_w(space, 0, data); + break; + + case 5: + m_acia->data_w(space, 0, data); + break; + } + } +} diff --git a/src/devices/bus/c64/midi_siel.h b/src/devices/bus/c64/midi_siel.h new file mode 100644 index 00000000000..f566489259e --- /dev/null +++ b/src/devices/bus/c64/midi_siel.h @@ -0,0 +1,56 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Siel/JMS/DATEL MIDI Interface cartridge emulation + +**********************************************************************/ + +#pragma once + +#ifndef __C64_MIDI_SIEL__ +#define __C64_MIDI_SIEL__ + +#include "exp.h" +#include "machine/6850acia.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> c64_siel_midi_cartridge_device + +class c64_siel_midi_cartridge_device : public device_t, + public device_c64_expansion_card_interface +{ +public: + // construction/destruction + c64_siel_midi_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + + DECLARE_WRITE_LINE_MEMBER( acia_irq_w ); + DECLARE_WRITE_LINE_MEMBER( write_acia_clock ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_c64_expansion_card_interface overrides + virtual UINT8 c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + virtual void c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + +private: + required_device m_acia; +}; + + +// device type definition +extern const device_type C64_MIDI_SIEL; + + +#endif diff --git a/src/devices/bus/c64/mikro_assembler.c b/src/devices/bus/c64/mikro_assembler.c new file mode 100644 index 00000000000..2578d4ae5b4 --- /dev/null +++ b/src/devices/bus/c64/mikro_assembler.c @@ -0,0 +1,57 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Mikro Assembler cartridge emulation + +**********************************************************************/ + +#include "mikro_assembler.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type C64_MIKRO_ASSEMBLER = &device_creator; + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// c64_mikro_assembler_cartridge_device - constructor +//------------------------------------------------- + +c64_mikro_assembler_cartridge_device::c64_mikro_assembler_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, C64_MIKRO_ASSEMBLER, "C64 Mikro Assembler cartridge", tag, owner, clock, "c64_mikro_assembler", __FILE__), + device_c64_expansion_card_interface(mconfig, *this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void c64_mikro_assembler_cartridge_device::device_start() +{ +} + + +//------------------------------------------------- +// c64_cd_r - cartridge data read +//------------------------------------------------- + +UINT8 c64_mikro_assembler_cartridge_device::c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (!roml || !romh || !io1 || !io2) + { + data = m_roml[offset & 0x1fff]; + } + + return data; +} diff --git a/src/devices/bus/c64/mikro_assembler.h b/src/devices/bus/c64/mikro_assembler.h new file mode 100644 index 00000000000..15c4e06279d --- /dev/null +++ b/src/devices/bus/c64/mikro_assembler.h @@ -0,0 +1,46 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Mikro Assembler cartridge emulation + +**********************************************************************/ + +#pragma once + +#ifndef __MIKRO_ASSEMBLER__ +#define __MIKRO_ASSEMBLER__ + + +#include "emu.h" +#include "exp.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> c64_mikro_assembler_cartridge_device + +class c64_mikro_assembler_cartridge_device : public device_t, + public device_c64_expansion_card_interface +{ +public: + // construction/destruction + c64_mikro_assembler_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // device-level overrides + virtual void device_start(); + + // device_c64_expansion_card_interface overrides + virtual UINT8 c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); +}; + + +// device type definition +extern const device_type C64_MIKRO_ASSEMBLER; + + +#endif diff --git a/src/devices/bus/c64/multiscreen.c b/src/devices/bus/c64/multiscreen.c new file mode 100644 index 00000000000..0edb8b90c1c --- /dev/null +++ b/src/devices/bus/c64/multiscreen.c @@ -0,0 +1,226 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Multiscreen cartridge emulation + +**********************************************************************/ + +/* + + PCB Layout + ---------- + + |===================| + | ROM6 | + | MC14066 | + | | + |===============| ROM5 | + |=| | + |=| | + |=| RAM BAT ROM4 | + |=| | + |=| | + |=| ROM0 ROM3 | + |=| | + |=| | + |===============| LS138 ROM2 | + | LS138 | + | LS174 | + | LS133 ROM1 | + |===================| + + BAT - BR2325 lithium battery + RAM - ? 8Kx8 RAM + ROM0 - ? 16Kx8 EPROM + ROM1 - ? 32Kx8 EPROM + ROM2 - ? 32Kx8 EPROM + ROM3 - ? 32Kx8 EPROM + ROM4 - not populated + ROM5 - not populated + ROM6 - not populated + +*/ + +/* + + TODO: + + - M6802 board + - crashes on boot + + 805A: lda $01 + 805C: and #$FE + 805E: sta $01 + 8060: m6502_brk#$00 <-- BOOM! + +*/ + +#include "multiscreen.h" + + + +//************************************************************************** +// MACROS/CONSTANTS +//************************************************************************** + +#define MC6802P_TAG "m6802" +#define MC6821P_0_TAG "m6821_0" +#define MC6821P_1_TAG "m6821_1" + + +#define BANK_RAM 0x0d + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type C64_MULTISCREEN = &device_creator; + + +//------------------------------------------------- +// ROM( c64_multiscreen ) +//------------------------------------------------- + +ROM_START( c64_multiscreen ) + ROM_REGION( 0x2000, MC6802P_TAG, 0 ) + ROM_LOAD( "1", 0x0000, 0x1000, CRC(35be02a8) SHA1(5912bc3d8e0c0949c1e66c19116d6b71c7574e46) ) + ROM_LOAD( "2 cr", 0x1000, 0x1000, CRC(76a9ac6d) SHA1(87e7335e626bdb73498b46c28c7baab72df38d1f) ) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *c64_multiscreen_cartridge_device::device_rom_region() const +{ + return ROM_NAME( c64_multiscreen ); +} + + +static ADDRESS_MAP_START( multiscreen_mem, AS_PROGRAM, 8, c64_multiscreen_cartridge_device ) + AM_RANGE(0x0000, 0x1fff) AM_ROM AM_REGION(MC6802P_TAG, 0) +ADDRESS_MAP_END + + +//------------------------------------------------- +// MACHINE_CONFIG_FRAGMENT( c64_multiscreen ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( c64_multiscreen ) + MCFG_CPU_ADD(MC6802P_TAG, M6802, XTAL_4MHz) + MCFG_CPU_PROGRAM_MAP(multiscreen_mem) + + MCFG_DEVICE_ADD(MC6821P_0_TAG, PIA6821, 0) + MCFG_DEVICE_ADD(MC6821P_1_TAG, PIA6821, 0) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor c64_multiscreen_cartridge_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( c64_multiscreen ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// c64_multiscreen_cartridge_device - constructor +//------------------------------------------------- + +c64_multiscreen_cartridge_device::c64_multiscreen_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, C64_MULTISCREEN, "C64 Multiscreen cartridge", tag, owner, clock, "c64_mscr", __FILE__), + device_c64_expansion_card_interface(mconfig, *this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void c64_multiscreen_cartridge_device::device_start() +{ + // state saving + save_item(NAME(m_bank)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void c64_multiscreen_cartridge_device::device_reset() +{ + m_bank = 0; +} + + +//------------------------------------------------- +// c64_cd_r - cartridge data read +//------------------------------------------------- + +UINT8 c64_multiscreen_cartridge_device::c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (!roml) + { + int bank = m_bank & 0x0f; + + if (bank == BANK_RAM) + { + data = m_nvram[offset & 0x1fff]; + } + else + { + data = m_roml[(bank << 14) | (offset & 0x3fff)]; + } + } + else if (!romh) + { + int bank = m_bank & 0x0f; + + if (bank == BANK_RAM) + { + data = m_roml[offset & 0x3fff]; + } + else + { + data = m_roml[(bank << 14) | (offset & 0x3fff)]; + } + } + + return data; +} + + +//------------------------------------------------- +// c64_cd_w - cartridge data write +//------------------------------------------------- + +void c64_multiscreen_cartridge_device::c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (offset >= 0x8000 && offset < 0xa000) + { + int bank = m_bank & 0x0f; + + if (bank == BANK_RAM) + { + m_nvram[offset & 0x1fff] = data; + } + } + else if (!io2) + { + m_bank = data; + } +} diff --git a/src/devices/bus/c64/multiscreen.h b/src/devices/bus/c64/multiscreen.h new file mode 100644 index 00000000000..08d570f8308 --- /dev/null +++ b/src/devices/bus/c64/multiscreen.h @@ -0,0 +1,57 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Multiscreen cartridge emulation + +**********************************************************************/ + +#pragma once + +#ifndef __MULTISCREEN__ +#define __MULTISCREEN__ + + +#include "emu.h" +#include "cpu/m6800/m6800.h" +#include "machine/6821pia.h" +#include "exp.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> c64_multiscreen_cartridge_device + +class c64_multiscreen_cartridge_device : public device_t, + public device_c64_expansion_card_interface +{ +public: + // construction/destruction + c64_multiscreen_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_c64_expansion_card_interface overrides + virtual UINT8 c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + virtual void c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + +private: + UINT8 m_bank; +}; + + +// device type definition +extern const device_type C64_MULTISCREEN; + + +#endif diff --git a/src/devices/bus/c64/music64.c b/src/devices/bus/c64/music64.c new file mode 100644 index 00000000000..723acad7fa7 --- /dev/null +++ b/src/devices/bus/c64/music64.c @@ -0,0 +1,238 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Wersi Wersiboard Music 64 / Siel CMK 49 Keyboard emulation + +**********************************************************************/ + +/* +5 PRINT "MUSIC 64 & CMK 49 TEST" +6 PRINT " BY CARLO MERLANO" +7 PRINT "PLAY THE MUSIC KEYBOARD!" +8 F1=65.4:POKE 54296,15 +9 POKE 54277,25:POKE 54278,68 +10 IF PE=255 THEN POKE 54276,0 +20 FOR I=1 TO 8 +30 PO=57087+I:PE=PEEK(PO) +40 IF PE<255 THEN GOSUB 100 +50 NEXT I +60 GOTO 10 +100 KK=LOG(255-PE)/LOG(2)+8*I-7 +110 FKK=(2^(1/12))^(KK-1)*F1 +120 N=FKK*16.3835 +130 NHI=INT(N/256):NLO=N-NHI*256 +140 POKE 54276,17 +150 POKE 54273,NHI:POKE 54272,NLO +160 I=0 +170 RETURN +*/ + +#include "music64.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type C64_MUSIC64 = &device_creator; + + +//------------------------------------------------- +// MACHINE_CONFIG_FRAGMENT( c64_music64 ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( c64_music64 ) + MCFG_C64_PASSTHRU_EXPANSION_SLOT_ADD() +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor c64_music64_cartridge_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( c64_music64 ); +} + + +//------------------------------------------------- +// INPUT_PORTS( c64_music64 ) +//------------------------------------------------- + +static INPUT_PORTS_START( c64_music64 ) + PORT_START("KB0") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("C2") + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("C#2") + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("D") + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("D#2") + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("E2") + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("F2") + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("F#2") + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("G2") + + PORT_START("KB1") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("G#2") + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("A3") + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("A#3") + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("B3") + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("C3") + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("C#3") + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("D3") + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("D#3") + + PORT_START("KB2") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("E3") + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("F3") + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("F#3") + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("G3") + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("G#3") + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("A4") + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("A#4") + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("B4") + + PORT_START("KB3") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("C4") + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("C#4") + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("D4") + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("D#4") + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("E4") + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("F4") + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("F#4") + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("G4") + + PORT_START("KB4") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("G#4") + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("A5") + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("A#5") + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("B5") + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("C5") + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("C#5") + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("D5") + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("D#5") + + PORT_START("KB5") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("E5") + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("F5") + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("F#5") + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("G5") + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("G#5") + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("A6") + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("A#6") + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("B6") + + PORT_START("KB6") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("C6") + PORT_BIT( 0xfe, IP_ACTIVE_LOW, IPT_UNUSED ) +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor c64_music64_cartridge_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( c64_music64 ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// c64_music64_cartridge_device - constructor +//------------------------------------------------- + +c64_music64_cartridge_device::c64_music64_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, C64_MUSIC64, "C64 Music 64 cartridge", tag, owner, clock, "c64_music64", __FILE__), + device_c64_expansion_card_interface(mconfig, *this), + m_exp(*this, C64_EXPANSION_SLOT_TAG), + m_kb0(*this, "KB0"), + m_kb1(*this, "KB1"), + m_kb2(*this, "KB2"), + m_kb3(*this, "KB3"), + m_kb4(*this, "KB4"), + m_kb5(*this, "KB5"), + m_kb6(*this, "KB6") +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void c64_music64_cartridge_device::device_start() +{ +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void c64_music64_cartridge_device::device_reset() +{ +} + + +//------------------------------------------------- +// c64_cd_r - cartridge data read +//------------------------------------------------- + +UINT8 c64_music64_cartridge_device::c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + data = m_exp->cd_r(space, offset, data, sphi2, ba, roml, romh, io1, io2); + + if (!io2) + { + switch (offset & 0x07) + { + case 0x00: data = m_kb0->read(); break; + case 0x01: data = m_kb1->read(); break; + case 0x02: data = m_kb2->read(); break; + case 0x03: data = m_kb3->read(); break; + case 0x04: data = m_kb4->read(); break; + case 0x05: data = m_kb5->read(); break; + case 0x06: data = m_kb6->read(); break; + } + } + + return data; +} + + +//------------------------------------------------- +// c64_cd_w - cartridge data write +//------------------------------------------------- + +void c64_music64_cartridge_device::c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + m_exp->cd_w(space, offset, data, sphi2, ba, roml, romh, io1, io2); +} + + +//------------------------------------------------- +// c64_game_r - GAME read +//------------------------------------------------- + +int c64_music64_cartridge_device::c64_game_r(offs_t offset, int sphi2, int ba, int rw) +{ + return m_exp->game_r(offset, sphi2, ba, rw, m_slot->hiram()); +} + + +//------------------------------------------------- +// c64_exrom_r - EXROM read +//------------------------------------------------- + +int c64_music64_cartridge_device::c64_exrom_r(offs_t offset, int sphi2, int ba, int rw) +{ + return m_exp->exrom_r(offset, sphi2, ba, rw, m_slot->hiram()); +} diff --git a/src/devices/bus/c64/music64.h b/src/devices/bus/c64/music64.h new file mode 100644 index 00000000000..bd1cfe2774b --- /dev/null +++ b/src/devices/bus/c64/music64.h @@ -0,0 +1,63 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Wersi Wersiboard Music 64 / Siel CMK 49 Keyboard emulation + +**********************************************************************/ + +#pragma once + +#ifndef __MUSIC64__ +#define __MUSIC64__ + +#include "emu.h" +#include "exp.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> c64_music64_cartridge_device + +class c64_music64_cartridge_device : public device_t, + public device_c64_expansion_card_interface +{ +public: + // construction/destruction + c64_music64_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual ioport_constructor device_input_ports() const; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_c64_expansion_card_interface overrides + virtual UINT8 c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + virtual void c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + virtual int c64_game_r(offs_t offset, int sphi2, int ba, int rw); + virtual int c64_exrom_r(offs_t offset, int sphi2, int ba, int rw); + +private: + required_device m_exp; + required_ioport m_kb0; + required_ioport m_kb1; + required_ioport m_kb2; + required_ioport m_kb3; + required_ioport m_kb4; + required_ioport m_kb5; + required_ioport m_kb6; +}; + + +// device type definition +extern const device_type C64_MUSIC64; + + +#endif diff --git a/src/devices/bus/c64/neoram.c b/src/devices/bus/c64/neoram.c new file mode 100644 index 00000000000..2b885c86f55 --- /dev/null +++ b/src/devices/bus/c64/neoram.c @@ -0,0 +1,99 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + NeoRAM cartridge emulation + +**********************************************************************/ + +#include "neoram.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type C64_NEORAM = &device_creator; + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// c64_neoram_cartridge_device - constructor +//------------------------------------------------- + +c64_neoram_cartridge_device::c64_neoram_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, C64_NEORAM, "C64 NeoRAM cartridge", tag, owner, clock, "c64_neoram", __FILE__), + device_c64_expansion_card_interface(mconfig, *this), + device_nvram_interface(mconfig, *this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void c64_neoram_cartridge_device::device_start() +{ + // allocate memory + m_nvram.allocate(0x200000); + + // state saving + save_item(NAME(m_bank)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void c64_neoram_cartridge_device::device_reset() +{ + m_bank = 0; +} + + +//------------------------------------------------- +// c64_cd_r - cartridge data read +//------------------------------------------------- + +UINT8 c64_neoram_cartridge_device::c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (!io1) + { + offs_t addr = (m_bank << 8) | (offset & 0xff); + data = m_nvram[addr]; + } + + return data; +} + + +//------------------------------------------------- +// c64_cd_w - cartridge data write +//------------------------------------------------- + +void c64_neoram_cartridge_device::c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (!io1) + { + offs_t addr = (m_bank << 8) | (offset & 0xff); + m_nvram[addr] = data; + } + else if (!io2) + { + if (BIT(offset, 0)) + { + m_bank = ((data & 0x7f) << 6) | (m_bank & 0x3f); + } + else + { + m_bank = (m_bank & 0x1fc0) | (data & 0x3f); + } + } +} diff --git a/src/devices/bus/c64/neoram.h b/src/devices/bus/c64/neoram.h new file mode 100644 index 00000000000..0011e942a53 --- /dev/null +++ b/src/devices/bus/c64/neoram.h @@ -0,0 +1,57 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + NeoRAM cartridge emulation + +**********************************************************************/ + +#pragma once + +#ifndef __NEORAM__ +#define __NEORAM__ + + +#include "emu.h" +#include "exp.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> c64_neoram_cartridge_device + +class c64_neoram_cartridge_device : public device_t, + public device_c64_expansion_card_interface, + public device_nvram_interface +{ +public: + // construction/destruction + c64_neoram_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_nvram_interface overrides + virtual void nvram_default() { } + virtual void nvram_read(emu_file &file) { if (m_nvram != NULL) { file.read(m_nvram, m_nvram.bytes()); } } + virtual void nvram_write(emu_file &file) { if (m_nvram != NULL) { file.write(m_nvram, m_nvram.bytes()); } } + + // device_c64_expansion_card_interface overrides + virtual UINT8 c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + virtual void c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + +private: + UINT16 m_bank; +}; + + +// device type definition +extern const device_type C64_NEORAM; + + +#endif diff --git a/src/devices/bus/c64/ocean.c b/src/devices/bus/c64/ocean.c new file mode 100644 index 00000000000..496651a1b25 --- /dev/null +++ b/src/devices/bus/c64/ocean.c @@ -0,0 +1,115 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Ocean Software cartridge emulation + +**********************************************************************/ + +/* + + Chase H.Q. 2: Special Criminal Investigation + + PCB Layout + ---------- + + |===========================| + |=| LS02 | + |=| | + |=| | + |=| ROM0 ROM1 | + |=| LS273 | + |=| | + |=| | + |=| | + |===========================| + + ROM0,1 - 28-pin ROM (Toshiba TC531000 pinout, markings scratched off) + +*/ + +#include "ocean.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type C64_OCEAN = &device_creator; + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// c64_ocean_cartridge_device - constructor +//------------------------------------------------- + +c64_ocean_cartridge_device::c64_ocean_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, C64_OCEAN, "C64 Ocean cartridge", tag, owner, clock, "c64_ocean", __FILE__), + device_c64_expansion_card_interface(mconfig, *this), + m_bank(0) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void c64_ocean_cartridge_device::device_start() +{ + // state saving + save_item(NAME(m_bank)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void c64_ocean_cartridge_device::device_reset() +{ + m_bank = 0; +} + + +//------------------------------------------------- +// c64_cd_r - cartridge data read +//------------------------------------------------- + +UINT8 c64_ocean_cartridge_device::c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (!roml && m_roml.bytes()) + { + offs_t addr = (m_bank << 13) | (offset & 0x1fff); + data = m_roml[addr & m_roml.mask()]; + } + else if (!romh && m_romh.bytes()) + { + offs_t addr = (m_bank << 13) | (offset & 0x1fff); + data = m_romh[addr & m_romh.mask()]; + } + else if (!io1) + { + return m_bank; + } + + return data; +} + + +//------------------------------------------------- +// c64_cd_w - cartridge data write +//------------------------------------------------- + +void c64_ocean_cartridge_device::c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (!io1) + { + m_bank = data & 0x3f; + } +} diff --git a/src/devices/bus/c64/ocean.h b/src/devices/bus/c64/ocean.h new file mode 100644 index 00000000000..6a44f6a4ace --- /dev/null +++ b/src/devices/bus/c64/ocean.h @@ -0,0 +1,51 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Ocean Software cartridge emulation + +**********************************************************************/ + +#pragma once + +#ifndef __OCEAN__ +#define __OCEAN__ + + +#include "emu.h" +#include "exp.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> c64_ocean_cartridge_device + +class c64_ocean_cartridge_device : public device_t, + public device_c64_expansion_card_interface +{ +public: + // construction/destruction + c64_ocean_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_c64_expansion_card_interface overrides + virtual UINT8 c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + virtual void c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + +private: + UINT8 m_bank; +}; + + +// device type definition +extern const device_type C64_OCEAN; + + +#endif diff --git a/src/devices/bus/c64/pagefox.c b/src/devices/bus/c64/pagefox.c new file mode 100644 index 00000000000..8f163f41692 --- /dev/null +++ b/src/devices/bus/c64/pagefox.c @@ -0,0 +1,137 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Scanntronik Pagefox cartridge emulation + +**********************************************************************/ + +/* + + PCB Layout + ---------- + + |===========================| + |=| | + |=| RAM LS11 | + |=| | + |=| LS139 | + |=| ROM0 | + |=| LS273 | + |=| | + |=| ROM1 LS00 | + |===========================| + + RAM - NEC D43256-12L 32Kx8 RAM + ROM0 - SGS M27256-2FI 32Kx8 EPROM + ROM1 - National Instruments NMC27C256Q 32Kx8 EPROM + +*/ + +#include "pagefox.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type C64_PAGEFOX = &device_creator; + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// c64_pagefox_cartridge_device - constructor +//------------------------------------------------- + +c64_pagefox_cartridge_device::c64_pagefox_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, C64_PAGEFOX, "C64 Pagefox cartridge", tag, owner, clock, "c64_pagefox", __FILE__), + device_c64_expansion_card_interface(mconfig, *this), + m_ram(*this, "ram") +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void c64_pagefox_cartridge_device::device_start() +{ + // allocate memory + m_ram.allocate(0x8000); + + // state saving + save_item(NAME(m_bank)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void c64_pagefox_cartridge_device::device_reset() +{ + m_bank = 0; +} + + +//------------------------------------------------- +// c64_cd_r - cartridge data read +//------------------------------------------------- + +UINT8 c64_pagefox_cartridge_device::c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (!roml || !romh) + { + if (BIT(m_bank, 3)) + { + offs_t addr = (BIT(m_bank, 1) << 14) | (offset & 0x3fff); + data = m_ram[addr]; + } + else + { + int bank = (m_bank >> 1) & 0x07; + offs_t addr = (bank << 14) | (offset & 0x3fff); + data = m_roml[addr]; + } + } + + return data; +} + + +//------------------------------------------------- +// c64_cd_w - cartridge data write +//------------------------------------------------- + +void c64_pagefox_cartridge_device::c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (offset >= 0x8000 && offset < 0xc000) + { + if (BIT(m_bank, 3)) + { + offs_t addr = (BIT(m_bank, 1) << 14) | (offset & 0x3fff); + m_ram[addr] = data; + } + } + else if (!io1 && BIT(offset, 7)) + { + if (data == 0xff) + { + m_game = 1; + m_exrom = 1; + } + else + { + m_game = 0; + m_exrom = 0; + } + + m_bank = data; + } +} diff --git a/src/devices/bus/c64/pagefox.h b/src/devices/bus/c64/pagefox.h new file mode 100644 index 00000000000..d9c71206e10 --- /dev/null +++ b/src/devices/bus/c64/pagefox.h @@ -0,0 +1,53 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Scanntronik Pagefox cartridge emulation + +**********************************************************************/ + +#pragma once + +#ifndef __PAGEFOX__ +#define __PAGEFOX__ + + +#include "emu.h" +#include "exp.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> c64_pagefox_cartridge_device + +class c64_pagefox_cartridge_device : public device_t, + public device_c64_expansion_card_interface +{ +public: + // construction/destruction + c64_pagefox_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_c64_expansion_card_interface overrides + virtual UINT8 c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + virtual void c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + +private: + optional_shared_ptr m_ram; + + UINT8 m_bank; +}; + + +// device type definition +extern const device_type C64_PAGEFOX; + + +#endif diff --git a/src/devices/bus/c64/partner.c b/src/devices/bus/c64/partner.c new file mode 100644 index 00000000000..4feb8022b08 --- /dev/null +++ b/src/devices/bus/c64/partner.c @@ -0,0 +1,208 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Timeworks PARTNER 64 cartridge emulation + +**********************************************************************/ + +/* + + PCB Layout + ---------- + + |===========================| + |=| | + |=|LS05 LS09 LS00 HC74 | + |=| | + |=| | + |=| ROM RAM | + |=| LS133 | + |=| LS156 | + |=| | + |===========================| + + ROM - General Instrument 27C128-25 16Kx8 EPROM "TIMEWORKS C-64 VER 2-16-87" + RAM - Sony CXK5864PN-15L 8Kx8 SRAM + +*/ + +#include "partner.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type C64_PARTNER = &device_creator; + + +//------------------------------------------------- +// INPUT_PORTS( c64_partner ) +//------------------------------------------------- + +WRITE_LINE_MEMBER( c64_partner_cartridge_device::nmi_w ) +{ + if (!state && !m_a6 && !m_nmi) + { + m_slot->nmi_w(ASSERT_LINE); + m_nmi = 1; + } +} + +static INPUT_PORTS_START( c64_partner ) + PORT_START("NMI") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Menu") PORT_CODE(KEYCODE_F11) PORT_WRITE_LINE_DEVICE_MEMBER(DEVICE_SELF, c64_partner_cartridge_device, nmi_w) +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor c64_partner_cartridge_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( c64_partner ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// c64_partner_cartridge_device - constructor +//------------------------------------------------- + +c64_partner_cartridge_device::c64_partner_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, C64_PARTNER, "C64 PARTNER 64 cartridge", tag, owner, clock, "c64_partner", __FILE__), + device_c64_expansion_card_interface(mconfig, *this), + m_ram(*this, "ram"), + m_a0(1), + m_a6(1), + m_nmi(0) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void c64_partner_cartridge_device::device_start() +{ + // allocate memory + m_ram.allocate(0x2000); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void c64_partner_cartridge_device::device_reset() +{ + m_a0 = 1; + m_a6 = 1; + + if (m_nmi && m_a6) + { + m_slot->nmi_w(CLEAR_LINE); + m_nmi = 0; + } +} + + +//------------------------------------------------- +// c64_cd_r - cartridge data read +//------------------------------------------------- + +UINT8 c64_partner_cartridge_device::c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (!io1) + { + data = m_romh[offset & 0x3fff]; + } + + if (m_nmi && (offset == 0xfffa || offset == 0xfffb)) + { + m_a0 = 1; + } + + if (m_a0 && BIT(offset, 15)) + { + switch ((offset >> 13) & 0x03) + { + case 0: case 3: + data = m_romh[offset & 0x3fff]; + break; + + case 1: + data = m_ram[offset & 0x1fff]; + break; + } + } + + return data; +} + + +//------------------------------------------------- +// c64_cd_w - cartridge data write +//------------------------------------------------- + +void c64_partner_cartridge_device::c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (!io1) + { + m_a0 = BIT(offset, 0); + m_a6 = BIT(offset, 6); + + if (m_nmi && m_a6) + { + m_slot->nmi_w(CLEAR_LINE); + m_nmi = 0; + } + } + + if (m_a0 && BIT(offset, 15)) + { + switch ((offset >> 13) & 0x03) + { + case 1: + m_ram[offset & 0x1fff] = data; + break; + } + } + + if (m_nmi && (offset == 0xfffa || offset == 0xfffb)) + { + m_a0 = 1; + } +} + + +//------------------------------------------------- +// c64_game_r - GAME read +//------------------------------------------------- + +int c64_partner_cartridge_device::c64_game_r(offs_t offset, int sphi2, int ba, int rw) +{ + int game = 1; + + if (m_a0 && BIT(offset, 15)) + { + switch ((offset >> 13) & 0x03) + { + case 0: case 1: case 3: + game = 0; + break; + } + } + + // TODO if I/O1=0, GAME=0 + + return game; +} diff --git a/src/devices/bus/c64/partner.h b/src/devices/bus/c64/partner.h new file mode 100644 index 00000000000..bfa2abb314b --- /dev/null +++ b/src/devices/bus/c64/partner.h @@ -0,0 +1,60 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Timeworks PARTNER 64 cartridge emulation + +**********************************************************************/ + +#pragma once + +#ifndef __PARTNER__ +#define __PARTNER__ + +#include "emu.h" +#include "exp.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> c64_partner_cartridge_device + +class c64_partner_cartridge_device : public device_t, + public device_c64_expansion_card_interface +{ +public: + // construction/destruction + c64_partner_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual ioport_constructor device_input_ports() const; + + DECLARE_WRITE_LINE_MEMBER( nmi_w ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_c64_expansion_card_interface overrides + virtual UINT8 c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + virtual void c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + virtual int c64_game_r(offs_t offset, int sphi2, int ba, int rw); + +private: + optional_shared_ptr m_ram; + + int m_a0; + int m_a6; + int m_nmi; +}; + + +// device type definition +extern const device_type C64_PARTNER; + + +#endif diff --git a/src/devices/bus/c64/prophet64.c b/src/devices/bus/c64/prophet64.c new file mode 100644 index 00000000000..bd61247eed3 --- /dev/null +++ b/src/devices/bus/c64/prophet64.c @@ -0,0 +1,86 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + PROPHET64 cartridge emulation + +**********************************************************************/ + +#include "prophet64.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type C64_PROPHET64 = &device_creator; + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// c64_prophet64_cartridge_device - constructor +//------------------------------------------------- + +c64_prophet64_cartridge_device::c64_prophet64_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, C64_PROPHET64, "PROPHET64", tag, owner, clock, "c64_prophet64", __FILE__), + device_c64_expansion_card_interface(mconfig, *this), + m_bank(0) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void c64_prophet64_cartridge_device::device_start() +{ + // state saving + save_item(NAME(m_bank)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void c64_prophet64_cartridge_device::device_reset() +{ + m_bank = 0; + m_exrom = 0; +} + + +//------------------------------------------------- +// c64_cd_r - cartridge data read +//------------------------------------------------- + +UINT8 c64_prophet64_cartridge_device::c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (!roml) + { + offs_t addr = (m_bank << 13) | (offset & 0x1fff); + data = m_roml[addr]; + } + + return data; +} + + +//------------------------------------------------- +// c64_cd_w - cartridge data write +//------------------------------------------------- + +void c64_prophet64_cartridge_device::c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (!io2) + { + m_bank = data & 0x1f; + m_exrom = BIT(data, 5); + } +} diff --git a/src/devices/bus/c64/prophet64.h b/src/devices/bus/c64/prophet64.h new file mode 100644 index 00000000000..d9ee926de3c --- /dev/null +++ b/src/devices/bus/c64/prophet64.h @@ -0,0 +1,51 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + PROPHET64 cartridge emulation + +**********************************************************************/ + +#pragma once + +#ifndef __PROPHET64__ +#define __PROPHET64__ + +#include "emu.h" +#include "exp.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> c64_prophet64_cartridge_device + +class c64_prophet64_cartridge_device : public device_t, + public device_c64_expansion_card_interface +{ +public: + // construction/destruction + c64_prophet64_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_c64_expansion_card_interface overrides + virtual UINT8 c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + virtual void c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + +private: + UINT8 m_bank; +}; + + +// device type definition +extern const device_type C64_PROPHET64; + + + +#endif diff --git a/src/devices/bus/c64/ps64.c b/src/devices/bus/c64/ps64.c new file mode 100644 index 00000000000..af9ea9d2402 --- /dev/null +++ b/src/devices/bus/c64/ps64.c @@ -0,0 +1,157 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + PS-64 speech cartridge emulation + +**********************************************************************/ + +/* + + PCB Layout + ---------- + + |===========================| + |=| | + |=| SW1| + |=| SC02 | + |=| | + |=| CN1| + |=| ROM LF347 | + |=| | + |=| | + |===========================| + + SC02 - Votrax SSI-263AP Speech Synthesizer + ROM - Hynix Semiconductor HY27C64D-20 8Kx8 EPROM + LF347 - National Instruments LF347N JFET Operational Amplifier + SW1 - Module on/off switch + CN1 - connector to C64 video/audio port + +*/ + +/* + + TODO: + + - Votrax SC02 emulation + - route sound to SID audio input + - on/off switch + +*/ + +#include "ps64.h" + + + +//************************************************************************** +// MACROS/CONSTANTS +//************************************************************************** + +#define SSI263_TAG "ssi263" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type C64_PS64 = &device_creator; + + +//------------------------------------------------- +// votrax_sc02_interface votrax_intf +//------------------------------------------------- +/* +static struct votrax_sc02_interface votrax_intf = +{ + DEVCB_NULL +}; +*/ + +//------------------------------------------------- +// MACHINE_CONFIG_FRAGMENT( c64_ps64 ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( c64_ps64 ) + //MCFG_SPEAKER_STANDARD_MONO("mono") + //MCFG_VOTRAX_SC02_ADD(SSI263_TAG, 2000000, votrax_intf) + //MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 1.00) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor c64_ps64_cartridge_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( c64_ps64 ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// c64_ps64_cartridge_device - constructor +//------------------------------------------------- + +c64_ps64_cartridge_device::c64_ps64_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, C64_PS64, "C64 PS-64", tag, owner, clock, "c64_ps64", __FILE__), + device_c64_expansion_card_interface(mconfig, *this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void c64_ps64_cartridge_device::device_start() +{ +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void c64_ps64_cartridge_device::device_reset() +{ +} + + +//------------------------------------------------- +// c64_cd_r - cartridge data read +//------------------------------------------------- + +UINT8 c64_ps64_cartridge_device::c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (!roml) + { + data = m_roml[offset & 0x1fff]; + } + else if (!io1) + { + //sc02->read(offset & 0x07); + } + + return data; +} + + +//------------------------------------------------- +// c64_cd_w - cartridge data write +//------------------------------------------------- + +void c64_ps64_cartridge_device::c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (!io1) + { + // sc02->write(offset & 0x07, data); + } +} diff --git a/src/devices/bus/c64/ps64.h b/src/devices/bus/c64/ps64.h new file mode 100644 index 00000000000..6c7a183c487 --- /dev/null +++ b/src/devices/bus/c64/ps64.h @@ -0,0 +1,52 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + PS-64 speech cartridge emulation + +**********************************************************************/ + +#pragma once + +#ifndef __PS64__ +#define __PS64__ + + +#include "emu.h" +#include "exp.h" +#include "sound/votrax.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> c64_ps64_cartridge_device + +class c64_ps64_cartridge_device : public device_t, + public device_c64_expansion_card_interface +{ +public: + // construction/destruction + c64_ps64_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_c64_expansion_card_interface overrides + virtual UINT8 c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + virtual void c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); +}; + + +// device type definition +extern const device_type C64_PS64; + + +#endif diff --git a/src/devices/bus/c64/reu.c b/src/devices/bus/c64/reu.c new file mode 100644 index 00000000000..bc83c9554d2 --- /dev/null +++ b/src/devices/bus/c64/reu.c @@ -0,0 +1,137 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Commodore 1700/1750/1764 RAM Expansion Unit emulation + +**********************************************************************/ + +#include "reu.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define MOS8726R1_TAG "u1" + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type C64_REU1700 = &device_creator; +const device_type C64_REU1750 = &device_creator; +const device_type C64_REU1764 = &device_creator; + + +//------------------------------------------------- +// MACHINE_CONFIG_FRAGMENT( c64_reu ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( c64_reu ) + MCFG_MOS8726_ADD(MOS8726R1_TAG) + + MCFG_GENERIC_SOCKET_ADD("rom", generic_linear_slot, NULL) + MCFG_GENERIC_EXTENSIONS("bin,rom") +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor c64_reu_cartridge_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( c64_reu ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// c64_reu_cartridge_device - constructor +//------------------------------------------------- + +c64_reu_cartridge_device::c64_reu_cartridge_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, UINT32 variant, int jp1, size_t ram_size, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_c64_expansion_card_interface(mconfig, *this), + m_dmac(*this, MOS8726R1_TAG), + m_eprom(*this, "rom"), + m_ram(*this, "ram"), + m_variant(variant), + m_jp1(jp1), + m_ram_size(ram_size) +{ +} + +c64_reu1700_cartridge_device::c64_reu1700_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : c64_reu_cartridge_device(mconfig, C64_REU1700, "1700 REU", tag, owner, clock, TYPE_1700, 0, 128 * 1024, "c64_1700reu", __FILE__) { } + +c64_reu1750_cartridge_device::c64_reu1750_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : c64_reu_cartridge_device(mconfig, C64_REU1750, "1750 REU", tag, owner, clock, TYPE_1750, 1, 256 * 1024, "c64_1750reu", __FILE__) { } + +c64_reu1764_cartridge_device::c64_reu1764_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : c64_reu_cartridge_device(mconfig, C64_REU1764, "1764 REU", tag, owner, clock, TYPE_1764, 1, 512 * 1024, "c64_1764reu", __FILE__) { } + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void c64_reu_cartridge_device::device_start() +{ + // allocate memory + m_ram.allocate(m_ram_size); + + // setup DMA controller + m_dmac->set_unscaled_clock(m_slot->phi2()); + m_dmac->bs_w(m_jp1); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void c64_reu_cartridge_device::device_reset() +{ + m_dmac->reset(); +} + + +//------------------------------------------------- +// c64_cd_r - cartridge data read +//------------------------------------------------- + +UINT8 c64_reu_cartridge_device::c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (!m_dmac->romsel_r(roml, romh)) + { + data = m_eprom->read_rom(space, offset & 0x7fff); + } + else if (!io2) + { + data = m_dmac->read(space, offset); + } + + return data; +} + + +//------------------------------------------------- +// c64_cd_w - cartridge data write +//------------------------------------------------- + +void c64_reu_cartridge_device::c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (!io2) + { + m_dmac->write(space, offset, data); + } +} diff --git a/src/devices/bus/c64/reu.h b/src/devices/bus/c64/reu.h new file mode 100644 index 00000000000..d3df7f4d1d9 --- /dev/null +++ b/src/devices/bus/c64/reu.h @@ -0,0 +1,101 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Commodore 1700/1750/1764 RAM Expansion Unit emulation + +**********************************************************************/ + +#pragma once + +#ifndef __REU__ +#define __REU__ + + +#include "emu.h" +#include "bus/generic/slot.h" +#include "bus/generic/carts.h" +#include "exp.h" +#include "machine/mos8726.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> c64_reu_cartridge_device + +class c64_reu_cartridge_device : public device_t, + public device_c64_expansion_card_interface +{ +public: + // construction/destruction + c64_reu_cartridge_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, UINT32 variant, int jp1, size_t ram_size, const char *shortname, const char *source); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + +protected: + enum + { + TYPE_1700, + TYPE_1750, + TYPE_1764 + }; + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_c64_expansion_card_interface overrides + virtual UINT8 c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + virtual void c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + + required_device m_dmac; + required_device m_eprom; + optional_shared_ptr m_ram; + + int m_variant; + int m_jp1; + size_t m_ram_size; +}; + + +// ======================> c64_reu1700_cartridge_device + +class c64_reu1700_cartridge_device : public c64_reu_cartridge_device +{ +public: + // construction/destruction + c64_reu1700_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +// ======================> c64_reu1750_cartridge_device + +class c64_reu1750_cartridge_device : public c64_reu_cartridge_device +{ +public: + // construction/destruction + c64_reu1750_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +// ======================> c64_reu1700_cartridge_device + +class c64_reu1764_cartridge_device : public c64_reu_cartridge_device +{ +public: + // construction/destruction + c64_reu1764_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +// device type definition +extern const device_type C64_REU1700; +extern const device_type C64_REU1750; +extern const device_type C64_REU1764; + + + +#endif diff --git a/src/devices/bus/c64/rex.c b/src/devices/bus/c64/rex.c new file mode 100644 index 00000000000..5a4a0abaf78 --- /dev/null +++ b/src/devices/bus/c64/rex.c @@ -0,0 +1,78 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + REX Datentechnik cartridge emulation + +**********************************************************************/ + +#include "rex.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type C64_REX = &device_creator; + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// c64_rex_cartridge_device - constructor +//------------------------------------------------- + +c64_rex_cartridge_device::c64_rex_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, C64_REX, "C64 Rex cartridge", tag, owner, clock, "c64_rex", __FILE__), + device_c64_expansion_card_interface(mconfig, *this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void c64_rex_cartridge_device::device_start() +{ +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void c64_rex_cartridge_device::device_reset() +{ + m_exrom = 0; +} + + +//------------------------------------------------- +// c64_cd_r - cartridge data read +//------------------------------------------------- + +UINT8 c64_rex_cartridge_device::c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (!roml) + { + data = m_roml[offset & 0x1fff]; + } + else if (!io2) + { + if ((offset & 0xc0) == 0xc0) + { + m_exrom = 0; + } + else + { + m_exrom = 1; + } + } + + return data; +} diff --git a/src/devices/bus/c64/rex.h b/src/devices/bus/c64/rex.h new file mode 100644 index 00000000000..d94b720f22d --- /dev/null +++ b/src/devices/bus/c64/rex.h @@ -0,0 +1,47 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + REX Datentechnik cartridge emulation + +**********************************************************************/ + +#pragma once + +#ifndef __REX__ +#define __REX__ + + +#include "emu.h" +#include "exp.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> c64_rex_cartridge_device + +class c64_rex_cartridge_device : public device_t, + public device_c64_expansion_card_interface +{ +public: + // construction/destruction + c64_rex_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_c64_expansion_card_interface overrides + virtual UINT8 c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); +}; + + +// device type definition +extern const device_type C64_REX; + + +#endif diff --git a/src/devices/bus/c64/rex_ep256.c b/src/devices/bus/c64/rex_ep256.c new file mode 100644 index 00000000000..ef87cf9dc6f --- /dev/null +++ b/src/devices/bus/c64/rex_ep256.c @@ -0,0 +1,165 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Rex Datentechnik 256KB EPROM cartridge emulation + +**********************************************************************/ + +#include "rex_ep256.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type C64_REX_EP256 = &device_creator; + + +//------------------------------------------------- +// MACHINE_CONFIG_FRAGMENT( c64_rex_ep256 ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( c64_rex_ep256 ) + MCFG_GENERIC_SOCKET_ADD("rom1", generic_linear_slot, NULL) + MCFG_GENERIC_EXTENSIONS("bin,rom") + MCFG_GENERIC_SOCKET_ADD("rom2", generic_linear_slot, NULL) + MCFG_GENERIC_EXTENSIONS("bin,rom") + MCFG_GENERIC_SOCKET_ADD("rom3", generic_linear_slot, NULL) + MCFG_GENERIC_EXTENSIONS("bin,rom") + MCFG_GENERIC_SOCKET_ADD("rom4", generic_linear_slot, NULL) + MCFG_GENERIC_EXTENSIONS("bin,rom") + MCFG_GENERIC_SOCKET_ADD("rom5", generic_linear_slot, NULL) + MCFG_GENERIC_EXTENSIONS("bin,rom") + MCFG_GENERIC_SOCKET_ADD("rom6", generic_linear_slot, NULL) + MCFG_GENERIC_EXTENSIONS("bin,rom") + MCFG_GENERIC_SOCKET_ADD("rom7", generic_linear_slot, NULL) + MCFG_GENERIC_EXTENSIONS("bin,rom") + MCFG_GENERIC_SOCKET_ADD("rom8", generic_linear_slot, NULL) + MCFG_GENERIC_EXTENSIONS("bin,rom") +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor c64_rex_ep256_cartridge_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( c64_rex_ep256 ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// c64_rex_ep256_cartridge_device - constructor +//------------------------------------------------- + +c64_rex_ep256_cartridge_device::c64_rex_ep256_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, C64_REX_EP256, "C64 Rex 256KB EPROM cartridge", tag, owner, clock, "rexep256", __FILE__), + device_c64_expansion_card_interface(mconfig, *this) +{ + for (int i = 0; i < 8; i++) + { + char str[6]; + sprintf(str, "rom%i", i + 1); + m_eproms[i] = subdevice(str); + } +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void c64_rex_ep256_cartridge_device::device_start() +{ + // state saving + save_item(NAME(m_bank)); + save_item(NAME(m_reset)); + save_item(NAME(m_socket)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void c64_rex_ep256_cartridge_device::device_reset() +{ + m_exrom = 0; + m_reset = 1; + m_bank = 0; + m_socket = 0; +} + + +//------------------------------------------------- +// c64_cd_r - cartridge data read +//------------------------------------------------- + +UINT8 c64_rex_ep256_cartridge_device::c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (!roml) + { + if (m_reset) + { + data = m_roml[offset & 0x1fff]; + } + else + { + offs_t addr = (m_bank << 13) | (offset & 0x1fff); + data = m_eproms[m_socket]->read_rom(space, addr); + } + } + else if (!io2) + { + if ((offset & 0xf0) == 0xc0) + { + m_exrom = 1; + } + else if ((offset & 0xf0) == 0xe0) + { + m_exrom = 0; + } + } + + return data; +} + + +//------------------------------------------------- +// c64_cd_w - cartridge data write +//------------------------------------------------- + +void c64_rex_ep256_cartridge_device::c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (!io2 && ((offset & 0xf0) == 0xa0)) + { + /* + + bit description + + 0 socket selection bit 0 + 1 socket selection bit 1 + 2 socket selection bit 2 + 3 + 4 + 5 bank selection bit 0 + 6 bank selection bit 1 + 7 + + */ + + m_reset = 0; + + m_socket = data & 0x07; + m_bank = (data >> 5) & 0x03; + } +} diff --git a/src/devices/bus/c64/rex_ep256.h b/src/devices/bus/c64/rex_ep256.h new file mode 100644 index 00000000000..140e8402ce3 --- /dev/null +++ b/src/devices/bus/c64/rex_ep256.h @@ -0,0 +1,60 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Rex Datentechnik 256KB EPROM cartridge emulation + +**********************************************************************/ + +#pragma once + +#ifndef __REX_EP256__ +#define __REX_EP256__ + + +#include "emu.h" +#include "bus/generic/slot.h" +#include "bus/generic/carts.h" +#include "exp.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> c64_rex_ep256_cartridge_device + +class c64_rex_ep256_cartridge_device : public device_t, + public device_c64_expansion_card_interface +{ +public: + // construction/destruction + c64_rex_ep256_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_c64_expansion_card_interface overrides + virtual UINT8 c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + virtual void c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + +private: + generic_slot_device *m_eproms[8]; + + UINT8 m_bank, m_socket; + int m_reset; +}; + + +// device type definition +extern const device_type C64_REX_EP256; + + + +#endif diff --git a/src/devices/bus/c64/ross.c b/src/devices/bus/c64/ross.c new file mode 100644 index 00000000000..a610d8c987c --- /dev/null +++ b/src/devices/bus/c64/ross.c @@ -0,0 +1,92 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Ross cartridge emulation + +**********************************************************************/ + +#include "ross.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type C64_ROSS = &device_creator; + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// c64_ross_cartridge_device - constructor +//------------------------------------------------- + +c64_ross_cartridge_device::c64_ross_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, C64_ROSS, "C64 Ross cartridge", tag, owner, clock, "c64_ross", __FILE__), + device_c64_expansion_card_interface(mconfig, *this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void c64_ross_cartridge_device::device_start() +{ + // state saving + save_item(NAME(m_bank)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void c64_ross_cartridge_device::device_reset() +{ + m_exrom = 0; + m_game = 0; + + m_bank = 0; +} + + +//------------------------------------------------- +// c64_cd_r - cartridge data read +//------------------------------------------------- + +UINT8 c64_ross_cartridge_device::c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (!roml || !romh) + { + offs_t addr = (m_bank << 14) | (offset & 0x3fff); + + data = m_roml[addr & m_roml.mask()]; + } + + return data; +} + + +//------------------------------------------------- +// c64_cd_w - cartridge data write +//------------------------------------------------- + +void c64_ross_cartridge_device::c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (!io1) + { + m_bank = 1; + } + else if (!io2) + { + m_exrom = 1; + m_game = 1; + } +} diff --git a/src/devices/bus/c64/ross.h b/src/devices/bus/c64/ross.h new file mode 100644 index 00000000000..0cb4d1f36b5 --- /dev/null +++ b/src/devices/bus/c64/ross.h @@ -0,0 +1,52 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Ross cartridge emulation + +**********************************************************************/ + +#pragma once + +#ifndef __ROSS__ +#define __ROSS__ + + +#include "emu.h" +#include "exp.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> c64_ross_cartridge_device + +class c64_ross_cartridge_device : public device_t, + public device_c64_expansion_card_interface +{ +public: + // construction/destruction + c64_ross_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_c64_expansion_card_interface overrides + virtual UINT8 c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + virtual void c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + +private: + UINT8 m_bank; +}; + + +// device type definition +extern const device_type C64_ROSS; + + + +#endif diff --git a/src/devices/bus/c64/sfx_sound_expander.c b/src/devices/bus/c64/sfx_sound_expander.c new file mode 100644 index 00000000000..8c3f7291620 --- /dev/null +++ b/src/devices/bus/c64/sfx_sound_expander.c @@ -0,0 +1,286 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Commodore SFX Sound Expander cartridge emulation + +**********************************************************************/ + +#include "sfx_sound_expander.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define YM3526_TAG "ic3" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type C64_SFX_SOUND_EXPANDER = &device_creator; + + +//------------------------------------------------- +// ym3526_interface ym3526_config +//------------------------------------------------- + +WRITE_LINE_MEMBER( c64_sfx_sound_expander_cartridge_device::opl_irq_w ) +{ + m_slot->irq_w(state); +} + + +//------------------------------------------------- +// MACHINE_CONFIG_FRAGMENT( c64_sfx_sound_expander ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( c64_sfx_sound_expander ) + MCFG_SPEAKER_STANDARD_MONO("mono") + MCFG_SOUND_ADD(YM3526_TAG, YM3526, XTAL_3_579545MHz) + MCFG_YM3526_IRQ_HANDLER(WRITELINE(c64_sfx_sound_expander_cartridge_device, opl_irq_w)) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.70) + + MCFG_C64_PASSTHRU_EXPANSION_SLOT_ADD() +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor c64_sfx_sound_expander_cartridge_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( c64_sfx_sound_expander ); +} + + +//------------------------------------------------- +// INPUT_PORTS( c64_sfx_sound_expander ) +//------------------------------------------------- + +static INPUT_PORTS_START( c64_sfx_sound_expander ) + PORT_START("KB0") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("C2") + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("C#2") + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("D") + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("D#2") + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("E2") + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("F2") + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("F#2") + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("G2") + + PORT_START("KB1") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("G#2") + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("A3") + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("A#3") + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("B3") + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("C3") + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("C#3") + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("D3") + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("D#3") + + PORT_START("KB2") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("E3") + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("F3") + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("F#3") + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("G3") + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("G#3") + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("A4") + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("A#4") + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("B4") + + PORT_START("KB3") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("C4") + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("C#4") + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("D4") + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("D#4") + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("E4") + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("F4") + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("F#4") + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("G4") + + PORT_START("KB4") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("G#4") + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("A5") + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("A#5") + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("B5") + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("C5") + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("C#5") + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("D5") + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("D#5") + + PORT_START("KB5") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("E5") + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("F5") + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("F#5") + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("G5") + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("G#5") + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("A6") + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("A#6") + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("B6") + + PORT_START("KB6") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("C6") + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("C#6") + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("D6") + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("D#6") + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("E6") + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("F6") + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("F#6") + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("G6") + + PORT_START("KB7") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("G#6") + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("A7") + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("A#7") + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("B7") + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("C7") + PORT_BIT( 0xe0, IP_ACTIVE_LOW, IPT_UNUSED ) +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor c64_sfx_sound_expander_cartridge_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( c64_sfx_sound_expander ); +} + + + +//************************************************************************** +// INLINE HELPERS +//************************************************************************** + +//------------------------------------------------- +// get_offset - get passthru expansion port offset +//------------------------------------------------- + +inline offs_t c64_sfx_sound_expander_cartridge_device::get_offset(offs_t offset, int rw) +{ + // assimilate the 3 different MIDI cartridge 6850 ACIA register mappings? + return (offset & 0xfffc) | (rw << 1) | BIT(offset, 1); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// c64_sfx_sound_expander_cartridge_device - constructor +//------------------------------------------------- + +c64_sfx_sound_expander_cartridge_device::c64_sfx_sound_expander_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, C64_SFX_SOUND_EXPANDER, "C64 SFX Sound Expander cartridge", tag, owner, clock, "c64_sfxse", __FILE__), + device_c64_expansion_card_interface(mconfig, *this), + m_opl(*this, YM3526_TAG), + m_exp(*this, C64_EXPANSION_SLOT_TAG), + m_kb0(*this, "KB0"), + m_kb1(*this, "KB1"), + m_kb2(*this, "KB2"), + m_kb3(*this, "KB3"), + m_kb4(*this, "KB4"), + m_kb5(*this, "KB5"), + m_kb6(*this, "KB6"), + m_kb7(*this, "KB7") +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void c64_sfx_sound_expander_cartridge_device::device_start() +{ +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void c64_sfx_sound_expander_cartridge_device::device_reset() +{ + m_opl->reset(); +} + + +//------------------------------------------------- +// c64_cd_r - cartridge data read +//------------------------------------------------- + +UINT8 c64_sfx_sound_expander_cartridge_device::c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + data = m_exp->cd_r(space, get_offset(offset, 1), data, sphi2, ba, roml, romh, io1, io2); + + if (!io2 && sphi2) + { + if (BIT(offset, 3)) + { + switch (offset & 0x07) + { + case 0: data = m_kb0->read(); break; + case 1: data = m_kb1->read(); break; + case 2: data = m_kb2->read(); break; + case 3: data = m_kb3->read(); break; + case 4: data = m_kb4->read(); break; + case 5: data = m_kb5->read(); break; + case 6: data = m_kb6->read(); break; + case 7: data = m_kb7->read(); break; + } + } + + if (BIT(offset, 5)) + { + data = m_opl->read(space, BIT(offset, 4)); + } + } + + return data; +} + + +//------------------------------------------------- +// c64_cd_w - cartridge data write +//------------------------------------------------- + +void c64_sfx_sound_expander_cartridge_device::c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (!io2 && sphi2) + { + m_opl->write(space, BIT(offset, 4), data); + } + + m_exp->cd_w(space, get_offset(offset, 0), data, sphi2, ba, roml, romh, io1, io2); +} + + +//------------------------------------------------- +// c64_game_r - GAME read +//------------------------------------------------- + +int c64_sfx_sound_expander_cartridge_device::c64_game_r(offs_t offset, int sphi2, int ba, int rw) +{ + return m_exp->game_r(get_offset(offset, rw), sphi2, ba, rw, m_slot->hiram()); +} + + +//------------------------------------------------- +// c64_exrom_r - EXROM read +//------------------------------------------------- + +int c64_sfx_sound_expander_cartridge_device::c64_exrom_r(offs_t offset, int sphi2, int ba, int rw) +{ + return m_exp->exrom_r(get_offset(offset, rw), sphi2, ba, rw, m_slot->hiram()); +} diff --git a/src/devices/bus/c64/sfx_sound_expander.h b/src/devices/bus/c64/sfx_sound_expander.h new file mode 100644 index 00000000000..d7a0d229b45 --- /dev/null +++ b/src/devices/bus/c64/sfx_sound_expander.h @@ -0,0 +1,71 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Commodore SFX Sound Expander cartridge emulation + +**********************************************************************/ + +#pragma once + +#ifndef __SFX_SOUND_EXPANDER__ +#define __SFX_SOUND_EXPANDER__ + +#include "emu.h" +#include "exp.h" +#include "sound/3526intf.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> c64_sfx_sound_expander_cartridge_device + +class c64_sfx_sound_expander_cartridge_device : public device_t, + public device_c64_expansion_card_interface +{ +public: + // construction/destruction + c64_sfx_sound_expander_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual ioport_constructor device_input_ports() const; + + DECLARE_WRITE_LINE_MEMBER( opl_irq_w ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_c64_expansion_card_interface overrides + virtual UINT8 c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + virtual void c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + virtual int c64_game_r(offs_t offset, int sphi2, int ba, int rw); + virtual int c64_exrom_r(offs_t offset, int sphi2, int ba, int rw); + +private: + required_device m_opl; + required_device m_exp; + required_ioport m_kb0; + required_ioport m_kb1; + required_ioport m_kb2; + required_ioport m_kb3; + required_ioport m_kb4; + required_ioport m_kb5; + required_ioport m_kb6; + required_ioport m_kb7; + + inline offs_t get_offset(offs_t offset, int rw); +}; + + +// device type definition +extern const device_type C64_SFX_SOUND_EXPANDER; + + + +#endif diff --git a/src/devices/bus/c64/silverrock.c b/src/devices/bus/c64/silverrock.c new file mode 100644 index 00000000000..9e9ce421a6c --- /dev/null +++ b/src/devices/bus/c64/silverrock.c @@ -0,0 +1,132 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + SilverRock Productions cartridge emulation + +**********************************************************************/ + +/* + + PCB Layout + ---------- + + e9048 + |=============| + |=| LS00 | + |=| LS273| + |=| | + |=| | + |=| ROM | + |=| | + |=| | + |=| | + |=============| + + ROM - Atmel AT27C010-25PC 128Kx8 OTP EPROM "HUGO 2012" + +*/ + +#include "silverrock.h" + + + +//************************************************************************** +// MACROS/CONSTANTS +//************************************************************************** + +#define UNSCRAMBLE_ADDRESS(_offset) \ + BITSWAP16(_offset,15,14,13,12,1,0,2,3,11,10,9,8,7,6,5,4) + +#define UNSCRAMBLE_DATA(_data) \ + BITSWAP8(_data,7,6,5,4,0,1,2,3) + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type C64_SILVERROCK = &device_creator; + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// c64_silverrock_cartridge_device - constructor +//------------------------------------------------- + +c64_silverrock_cartridge_device::c64_silverrock_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, C64_SILVERROCK, "C64 SilverRock cartridge", tag, owner, clock, "c64_silverrock", __FILE__), + device_c64_expansion_card_interface(mconfig, *this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void c64_silverrock_cartridge_device::device_start() +{ + // state saving + save_item(NAME(m_bank)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void c64_silverrock_cartridge_device::device_reset() +{ + m_bank = 0; +} + + +//------------------------------------------------- +// c64_cd_r - cartridge data read +//------------------------------------------------- + +UINT8 c64_silverrock_cartridge_device::c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (!roml) + { + offs_t addr = (m_bank << 13) | (offset & 0x1fff); + addr = (addr & 0x10000) | UNSCRAMBLE_ADDRESS(addr); + data = UNSCRAMBLE_DATA(m_roml[addr]); + } + + return data; +} + + +//------------------------------------------------- +// c64_cd_w - cartridge data write +//------------------------------------------------- + +void c64_silverrock_cartridge_device::c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (!io1) + { + /* + + bit description + + 0 + 1 + 2 + 3 + 4 A14 + 5 A15 + 6 A16 + 7 A13 + + */ + + m_bank = ((data >> 3) & 0x0e) | BIT(data, 7); + } +} diff --git a/src/devices/bus/c64/silverrock.h b/src/devices/bus/c64/silverrock.h new file mode 100644 index 00000000000..65e20f1ccf6 --- /dev/null +++ b/src/devices/bus/c64/silverrock.h @@ -0,0 +1,51 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + SilverRock Productions cartridge emulation + +**********************************************************************/ + +#pragma once + +#ifndef __SILVERROCK__ +#define __SILVERROCK__ + + +#include "emu.h" +#include "exp.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> c64_silverrock_cartridge_device + +class c64_silverrock_cartridge_device : public device_t, + public device_c64_expansion_card_interface +{ +public: + // construction/destruction + c64_silverrock_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_c64_expansion_card_interface overrides + virtual UINT8 c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + virtual void c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + +private: + UINT8 m_bank; +}; + + +// device type definition +extern const device_type C64_SILVERROCK; + + +#endif diff --git a/src/devices/bus/c64/simons_basic.c b/src/devices/bus/c64/simons_basic.c new file mode 100644 index 00000000000..01baf228189 --- /dev/null +++ b/src/devices/bus/c64/simons_basic.c @@ -0,0 +1,84 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + VizaWrite 64 cartridge emulation + +**********************************************************************/ + +#include "simons_basic.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type C64_SIMONS_BASIC = &device_creator; + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// c64_simons_basic_cartridge_device - constructor +//------------------------------------------------- + +c64_simons_basic_cartridge_device::c64_simons_basic_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, C64_SIMONS_BASIC, "Simons' BASIC", tag, owner, clock, "c64_simons_basic", __FILE__), + device_c64_expansion_card_interface(mconfig, *this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void c64_simons_basic_cartridge_device::device_start() +{ +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void c64_simons_basic_cartridge_device::device_reset() +{ + m_game = 1; +} + + +//------------------------------------------------- +// c64_cd_r - cartridge data read +//------------------------------------------------- + +UINT8 c64_simons_basic_cartridge_device::c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (!roml) + { + data = m_roml[offset & 0x1fff]; + } + else if (!romh) + { + data = m_romh[offset & 0x1fff]; + } + + return data; +} + + +//------------------------------------------------- +// c64_cd_w - cartridge data write +//------------------------------------------------- + +void c64_simons_basic_cartridge_device::c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (!io1) + { + m_game = !BIT(data, 0); + } +} diff --git a/src/devices/bus/c64/simons_basic.h b/src/devices/bus/c64/simons_basic.h new file mode 100644 index 00000000000..3ebff2b672a --- /dev/null +++ b/src/devices/bus/c64/simons_basic.h @@ -0,0 +1,48 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Simons' BASIC cartridge emulation + +**********************************************************************/ + +#pragma once + +#ifndef __SIMONS_BASIC__ +#define __SIMONS_BASIC__ + + +#include "emu.h" +#include "exp.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> c64_simons_basic_cartridge_device + +class c64_simons_basic_cartridge_device : public device_t, + public device_c64_expansion_card_interface +{ +public: + // construction/destruction + c64_simons_basic_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_c64_expansion_card_interface overrides + virtual UINT8 c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + virtual void c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); +}; + + +// device type definition +extern const device_type C64_SIMONS_BASIC; + + +#endif diff --git a/src/devices/bus/c64/stardos.c b/src/devices/bus/c64/stardos.c new file mode 100644 index 00000000000..4c92982c695 --- /dev/null +++ b/src/devices/bus/c64/stardos.c @@ -0,0 +1,194 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + StarPoint Software StarDOS cartridge emulation + +**********************************************************************/ + +/* + + PCB Layout + ---------- + + |===========================| + |=| | + |=| LS30 | + |=| LS157 | + |=| LS00 | + |=| ROM | + |=| 7407 | + |=| | + |=| SW1| + |===========================| + + ROM - Toshiba TMM271128D-25 16Kx8 EPROM + +*/ + +#include "stardos.h" + + + +//************************************************************************** +// MACROS/CONSTANTS +//************************************************************************** + +#define IO1_FULL_CHARGE 27 +#define IO2_FULL_CHARGE 42 + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type C64_STARDOS = &device_creator; + + +//------------------------------------------------- +// INPUT_PORTS( c64_stardos ) +//------------------------------------------------- + +static INPUT_PORTS_START( c64_stardos ) + PORT_START("RESET") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_OTHER ) PORT_NAME("Reset") PORT_CODE(KEYCODE_F11) PORT_WRITE_LINE_DEVICE_MEMBER(DEVICE_SELF_OWNER, c64_expansion_slot_device, reset_w) +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor c64_stardos_cartridge_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( c64_stardos ); +} + + + +//************************************************************************** +// INLINE HELPERS +//************************************************************************** + +//------------------------------------------------- +// charge_io1_capacitor - +//------------------------------------------------- + +inline void c64_stardos_cartridge_device::charge_io1_capacitor() +{ + m_io1_charge++; + + if (m_io1_charge >= IO1_FULL_CHARGE) + { + m_exrom = 0; + m_io1_charge = 0; + } +} + + +//------------------------------------------------- +// charge_io2_capacitor - +//------------------------------------------------- + +void c64_stardos_cartridge_device::charge_io2_capacitor() +{ + m_io2_charge++; + + if (m_io2_charge >= IO2_FULL_CHARGE) + { + m_exrom = 1; + m_io2_charge = 0; + } +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// c64_stardos_cartridge_device - constructor +//------------------------------------------------- + +c64_stardos_cartridge_device::c64_stardos_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, C64_STARDOS, "C64 StarDOS cartridge", tag, owner, clock, "c64_stardos", __FILE__), + device_c64_expansion_card_interface(mconfig, *this), + m_io1_charge(0), + m_io2_charge(0) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void c64_stardos_cartridge_device::device_start() +{ + // state saving + save_item(NAME(m_io1_charge)); + save_item(NAME(m_io2_charge)); +} + + +//------------------------------------------------- +// c64_cd_r - cartridge data read +//------------------------------------------------- + +UINT8 c64_stardos_cartridge_device::c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (!roml || !romh) + { + // TODO BITSWAP8(7,6,5,4,3,1,2,0) ? + data = m_roml[offset & 0x3fff]; + } + else if (!io1) + { + charge_io1_capacitor(); + } + else if (!io2) + { + charge_io2_capacitor(); + } + + return data; +} + + +//------------------------------------------------- +// c64_cd_w - cartridge data write +//------------------------------------------------- + +void c64_stardos_cartridge_device::c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (!io1) + { + charge_io1_capacitor(); + } + else if (!io2) + { + charge_io2_capacitor(); + } +} + + +//------------------------------------------------- +// c64_game_r - GAME read +//------------------------------------------------- + +int c64_stardos_cartridge_device::c64_game_r(offs_t offset, int sphi2, int ba, int rw) +{ + return !(sphi2 && ba & rw & ((offset & 0xe000) == 0xe000) & m_slot->hiram()); +} + + +//------------------------------------------------- +// c64_exrom_r - EXROM read +//------------------------------------------------- + +int c64_stardos_cartridge_device::c64_exrom_r(offs_t offset, int sphi2, int ba, int rw) +{ + return (BIT(offset, 13)) ? 1 : m_exrom; +} diff --git a/src/devices/bus/c64/stardos.h b/src/devices/bus/c64/stardos.h new file mode 100644 index 00000000000..a1cbe520afb --- /dev/null +++ b/src/devices/bus/c64/stardos.h @@ -0,0 +1,60 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + StarPoint Software StarDOS cartridge emulation + +**********************************************************************/ + +#pragma once + +#ifndef __STARDOS__ +#define __STARDOS__ + + +#include "emu.h" +#include "exp.h" +#include "machine/6821pia.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> c64_stardos_cartridge_device + +class c64_stardos_cartridge_device : public device_t, + public device_c64_expansion_card_interface +{ +public: + // construction/destruction + c64_stardos_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual ioport_constructor device_input_ports() const; + +protected: + // device-level overrides + virtual void device_start(); + + // device_c64_expansion_card_interface overrides + virtual UINT8 c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + virtual void c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + virtual int c64_game_r(offs_t offset, int sphi2, int ba, int rw); + virtual int c64_exrom_r(offs_t offset, int sphi2, int ba, int rw); + +private: + inline void charge_io1_capacitor(); + inline void charge_io2_capacitor(); + + int m_io1_charge; + int m_io2_charge; +}; + + +// device type definition +extern const device_type C64_STARDOS; + + +#endif diff --git a/src/devices/bus/c64/std.c b/src/devices/bus/c64/std.c new file mode 100644 index 00000000000..6fa3abfef1d --- /dev/null +++ b/src/devices/bus/c64/std.c @@ -0,0 +1,68 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Commodore 64 Standard 8K/16K cartridge emulation + +**********************************************************************/ + +#include "std.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type C64_STD = &device_creator; + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// c64_standard_cartridge_device - constructor +//------------------------------------------------- + +c64_standard_cartridge_device::c64_standard_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, C64_STD, "C64 standard cartridge", tag, owner, clock, "c64_standard", __FILE__), + device_c64_expansion_card_interface(mconfig, *this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void c64_standard_cartridge_device::device_start() +{ +} + + +//------------------------------------------------- +// c64_cd_r - cartridge data read +//------------------------------------------------- + +UINT8 c64_standard_cartridge_device::c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (!roml && m_roml.bytes()) + { + data = m_roml[offset & m_roml.mask()]; + } + else if (!romh) + { + if (m_romh.bytes()) + { + data = m_romh[offset & m_romh.mask()]; + } + else if (m_roml.mask() == 0x3fff) + { + data = m_roml[offset & m_roml.mask()]; + } + } + + return data; +} diff --git a/src/devices/bus/c64/std.h b/src/devices/bus/c64/std.h new file mode 100644 index 00000000000..c726e901025 --- /dev/null +++ b/src/devices/bus/c64/std.h @@ -0,0 +1,46 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Commodore 64 Standard 8K/16K cartridge emulation + +**********************************************************************/ + +#pragma once + +#ifndef __C64_STANDARD_CARTRIDGE__ +#define __C64_STANDARD_CARTRIDGE__ + + +#include "emu.h" +#include "exp.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> c64_standard_cartridge_device + +class c64_standard_cartridge_device : public device_t, + public device_c64_expansion_card_interface +{ +public: + // construction/destruction + c64_standard_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // device-level overrides + virtual void device_start(); + + // device_c64_expansion_card_interface overrides + virtual UINT8 c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); +}; + + +// device type definition +extern const device_type C64_STD; + + +#endif diff --git a/src/devices/bus/c64/structured_basic.c b/src/devices/bus/c64/structured_basic.c new file mode 100644 index 00000000000..404d1b9d753 --- /dev/null +++ b/src/devices/bus/c64/structured_basic.c @@ -0,0 +1,103 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Structured Basic cartridge emulation + +**********************************************************************/ + +#include "structured_basic.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type C64_STRUCTURED_BASIC = &device_creator; + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// c64_structured_basic_cartridge_device - constructor +//------------------------------------------------- + +c64_structured_basic_cartridge_device::c64_structured_basic_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, C64_STRUCTURED_BASIC, "C64 Structured Basic cartridge", tag, owner, clock, "c64_structured_basic", __FILE__), + device_c64_expansion_card_interface(mconfig, *this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void c64_structured_basic_cartridge_device::device_start() +{ + // state saving + save_item(NAME(m_bank)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void c64_structured_basic_cartridge_device::device_reset() +{ + m_exrom = 0; + + m_bank = 0; +} + + +//------------------------------------------------- +// c64_cd_r - cartridge data read +//------------------------------------------------- + +UINT8 c64_structured_basic_cartridge_device::c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (!roml) + { + offs_t addr = (m_bank << 13) | (offset & 0x1fff); + + data = m_roml[addr]; + } + + return data; +} + + +//------------------------------------------------- +// c64_cd_w - cartridge data write +//------------------------------------------------- + +void c64_structured_basic_cartridge_device::c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (!io1) + { + switch (data & 0x03) + { + case 0: + case 1: + m_exrom = 0; + m_bank = 0; + break; + + case 2: + m_exrom = 0; + m_bank = 1; + break; + + case 3: + m_exrom = 1; + m_bank = 0; + break; + } + } +} diff --git a/src/devices/bus/c64/structured_basic.h b/src/devices/bus/c64/structured_basic.h new file mode 100644 index 00000000000..18465113d94 --- /dev/null +++ b/src/devices/bus/c64/structured_basic.h @@ -0,0 +1,52 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Structured Basic cartridge emulation + +**********************************************************************/ + +#pragma once + +#ifndef __STRUCTURED_BASIC__ +#define __STRUCTURED_BASIC__ + + +#include "emu.h" +#include "exp.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> c64_structured_basic_cartridge_device + +class c64_structured_basic_cartridge_device : public device_t, + public device_c64_expansion_card_interface +{ +public: + // construction/destruction + c64_structured_basic_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_c64_expansion_card_interface overrides + virtual UINT8 c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + virtual void c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + +private: + UINT8 m_bank; +}; + + +// device type definition +extern const device_type C64_STRUCTURED_BASIC; + + + +#endif diff --git a/src/devices/bus/c64/super_explode.c b/src/devices/bus/c64/super_explode.c new file mode 100644 index 00000000000..d58923fa97e --- /dev/null +++ b/src/devices/bus/c64/super_explode.c @@ -0,0 +1,125 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Super Explode! cartridge emulation + +**********************************************************************/ + +#include "super_explode.h" + + + +//************************************************************************** +// MACROS/CONSTANTS +//************************************************************************** + +// t = R*C = 3.3K * 0.47uF * 40% Vtr = 792.2905424610516 usec +// (3.3K pull-up on the EXROM line inside the C64, PLA Vih min = 2.0V = 40% of 5.0V) +#define TIMER_PERIOD 792 + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type C64_SUPER_EXPLODE = &device_creator; + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// c64_super_explode_cartridge_device - constructor +//------------------------------------------------- + +c64_super_explode_cartridge_device::c64_super_explode_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, C64_SUPER_EXPLODE, "C64 Super Explode! cartridge", tag, owner, clock, "c64_super_explode", __FILE__), + device_c64_expansion_card_interface(mconfig, *this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void c64_super_explode_cartridge_device::device_start() +{ + // allocate timer + m_exrom_timer = timer_alloc(); + + // state saving + save_item(NAME(m_bank)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void c64_super_explode_cartridge_device::device_reset() +{ + m_bank = 0; + + m_exrom = 0; + m_exrom_timer->adjust(attotime::from_usec(TIMER_PERIOD), 0); +} + + +//------------------------------------------------- +// device_timer - handler timer events +//------------------------------------------------- + +void c64_super_explode_cartridge_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + m_exrom = 1; +} + + +//------------------------------------------------- +// c64_cd_r - cartridge data read +//------------------------------------------------- + +UINT8 c64_super_explode_cartridge_device::c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (!roml) + { + m_exrom = 0; + m_exrom_timer->adjust(attotime::from_usec(TIMER_PERIOD), 0); + + data = m_roml[(m_bank << 13) | (offset & 0x1fff)]; + } + else if (!io1) + { + m_exrom = 0; + m_exrom_timer->adjust(attotime::from_usec(TIMER_PERIOD), 0); + } + else if (!io2) + { + data = m_roml[(m_bank << 13) | (offset & 0x1fff)]; + } + + return data; +} + + +//------------------------------------------------- +// c64_cd_w - cartridge data write +//------------------------------------------------- + +void c64_super_explode_cartridge_device::c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (!io1) + { + m_exrom = 0; + m_exrom_timer->adjust(attotime::from_usec(TIMER_PERIOD), 0); + } + else if (!io2) + { + m_bank = BIT(data, 7); + } +} diff --git a/src/devices/bus/c64/super_explode.h b/src/devices/bus/c64/super_explode.h new file mode 100644 index 00000000000..d33b4047725 --- /dev/null +++ b/src/devices/bus/c64/super_explode.h @@ -0,0 +1,54 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Super Explode! cartridge emulation + +**********************************************************************/ + +#pragma once + +#ifndef __SUPER_EXPLODE__ +#define __SUPER_EXPLODE__ + + +#include "emu.h" +#include "exp.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> c64_super_explode_cartridge_device + +class c64_super_explode_cartridge_device : public device_t, + public device_c64_expansion_card_interface +{ +public: + // construction/destruction + c64_super_explode_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + // device_c64_expansion_card_interface overrides + virtual UINT8 c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + virtual void c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + +private: + UINT8 m_bank; + + emu_timer *m_exrom_timer; +}; + + +// device type definition +extern const device_type C64_SUPER_EXPLODE; + + +#endif diff --git a/src/devices/bus/c64/super_games.c b/src/devices/bus/c64/super_games.c new file mode 100644 index 00000000000..0e15485993b --- /dev/null +++ b/src/devices/bus/c64/super_games.c @@ -0,0 +1,102 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Commodore Super Games cartridge emulation + +**********************************************************************/ + +#include "super_games.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type C64_SUPER_GAMES = &device_creator; + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// c64_super_games_cartridge_device - constructor +//------------------------------------------------- + +c64_super_games_cartridge_device::c64_super_games_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, C64_SUPER_GAMES, "C64 Super Games cartridge", tag, owner, clock, "c64_super_games", __FILE__), + device_c64_expansion_card_interface(mconfig, *this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void c64_super_games_cartridge_device::device_start() +{ + // state saving + save_item(NAME(m_bank)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void c64_super_games_cartridge_device::device_reset() +{ + m_bank = 0; +} + + +//------------------------------------------------- +// c64_cd_r - cartridge data read +//------------------------------------------------- + +UINT8 c64_super_games_cartridge_device::c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (!roml || !romh) + { + offs_t addr = (m_bank << 14) | (offset & 0x3fff); + data = m_roml[addr]; + } + + return data; +} + + +//------------------------------------------------- +// c64_cd_w - cartridge data write +//------------------------------------------------- + +void c64_super_games_cartridge_device::c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (!io2) + { + m_bank = data & 0x03; + + if (BIT(data, 2)) + { + if (BIT(data, 3)) + { + m_game = 1; + m_exrom = 1; + } + else + { + m_game = 1; + m_exrom = 0; + } + } + else + { + m_game = 0; + m_exrom = 0; + } + } +} diff --git a/src/devices/bus/c64/super_games.h b/src/devices/bus/c64/super_games.h new file mode 100644 index 00000000000..689fe7c79b9 --- /dev/null +++ b/src/devices/bus/c64/super_games.h @@ -0,0 +1,51 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Commodore Super Games cartridge emulation + +**********************************************************************/ + +#pragma once + +#ifndef __SUPER_GAMES__ +#define __SUPER_GAMES__ + + +#include "emu.h" +#include "exp.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> c64_super_games_cartridge_device + +class c64_super_games_cartridge_device : public device_t, + public device_c64_expansion_card_interface +{ +public: + // construction/destruction + c64_super_games_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_c64_expansion_card_interface overrides + virtual UINT8 c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + virtual void c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + +private: + UINT8 m_bank; +}; + + +// device type definition +extern const device_type C64_SUPER_GAMES; + + +#endif diff --git a/src/devices/bus/c64/supercpu.c b/src/devices/bus/c64/supercpu.c new file mode 100644 index 00000000000..cb8a28e2198 --- /dev/null +++ b/src/devices/bus/c64/supercpu.c @@ -0,0 +1,306 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + CMD SuperCPU v2 + SuperRAM emulation + +**********************************************************************/ + +#include "supercpu.h" + + + +//************************************************************************** +// MACROS/CONSTANTS +//************************************************************************** + +#define G65816_TAG "g65816" + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type C64_SUPERCPU = &device_creator; + + +//------------------------------------------------- +// ROM( c64_supercpu ) +//------------------------------------------------- + +ROM_START( c64_supercpu ) + ROM_REGION( 0x20000, G65816_TAG, 0 ) + ROM_LOAD( "supercpu_dos_204.bin", 0x00000, 0x20000, CRC(f4151454) SHA1(6aa529a7b1b6de53e8979e407a77b4d5657727f5) ) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *c64_supercpu_device::device_rom_region() const +{ + return ROM_NAME( c64_supercpu ); +} + + +//------------------------------------------------- +// ADDRESS_MAP( c64_supercpu_map ) +//------------------------------------------------- + +static ADDRESS_MAP_START( c64_supercpu_map, AS_PROGRAM, 8, c64_supercpu_device ) + AM_RANGE(0x000000, 0x01ffff) AM_RAM AM_SHARE("sram") + AM_RANGE(0x020000, 0xf7ffff) AM_RAM AM_SHARE("dimm") + AM_RANGE(0xf80000, 0xf9ffff) AM_MIRROR(0x60000) AM_ROM AM_REGION(G65816_TAG, 0) +ADDRESS_MAP_END + + +//------------------------------------------------- +// MACHINE_CONFIG_FRAGMENT( c64_supercpu ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( c64_supercpu ) + MCFG_CPU_ADD(G65816_TAG, G65816, 1000000) + MCFG_CPU_PROGRAM_MAP(c64_supercpu_map) + + MCFG_C64_PASSTHRU_EXPANSION_SLOT_ADD() +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor c64_supercpu_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( c64_supercpu ); +} + + +//------------------------------------------------- +// INPUT_PORTS( c64_supercpu ) +//------------------------------------------------- + +static INPUT_PORTS_START( c64_supercpu ) + PORT_START("FRONT") + PORT_DIPNAME( 0x01, 0x01, "Unit" ) + PORT_DIPSETTING( 0x00, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x01, DEF_STR( On ) ) + PORT_DIPNAME( 0x02, 0x02, "JiffyDOS" ) + PORT_DIPSETTING( 0x00, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x02, DEF_STR( On ) ) + PORT_DIPNAME( 0x04, 0x00, "Speed" ) + PORT_DIPSETTING( 0x04, "Normal" ) + PORT_DIPSETTING( 0x00, "Turbo" ) + + PORT_START("RESET") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_OTHER ) PORT_NAME("Reset") PORT_CODE(KEYCODE_F11) PORT_WRITE_LINE_DEVICE_MEMBER(DEVICE_SELF_OWNER, c64_expansion_slot_device, reset_w) +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor c64_supercpu_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( c64_supercpu ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// c64_supercpu_device - constructor +//------------------------------------------------- + +c64_supercpu_device::c64_supercpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, C64_SUPERCPU, "SuperCPU", tag, owner, clock, "c64_supercpu", __FILE__), + device_c64_expansion_card_interface(mconfig, *this), + m_maincpu(*this, G65816_TAG), + m_exp(*this, C64_EXPANSION_SLOT_TAG), + m_sram(*this, "sram"), + m_dimm(*this, "dimm") +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void c64_supercpu_device::device_start() +{ +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void c64_supercpu_device::device_reset() +{ +} + + +//------------------------------------------------- +// c64_cd_r - cartridge data read +//------------------------------------------------- + +UINT8 c64_supercpu_device::c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + data = m_exp->cd_r(space, offset, data, sphi2, ba, roml, romh, io1, io2); + + switch (offset) + { + case 0xd0b0: + data = 0x40; + break; + + case 0xd0b1: + break; + + case 0xd0b2: + break; + + case 0xd0b3: + case 0xd0b4: + break; + + case 0xd0b5: + break; + + case 0xd0b6: + break; + + case 0xd0b7: + break; + + case 0xd0b8: + case 0xd0b9: + break; + + case 0xd0ba: + break; + + case 0xd0bb: + break; + + case 0xd0bc: + case 0xd0bd: + case 0xd0be: + case 0xd0bf: + break; + } + + return data; +} + + +//------------------------------------------------- +// c64_cd_w - cartridge data write +//------------------------------------------------- + +void c64_supercpu_device::c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + switch (offset) + { + case 0xd071: + break; + + case 0xd072: + break; + + case 0xd073: + break; + + case 0xd074: + case 0xd075: + case 0xd076: + case 0xd077: + break; + + case 0xd078: + break; + + case 0xd07a: + break; + + case 0xd079: + case 0xd07b: + break; + + case 0xd07c: + break; + + case 0xd07d: + case 0xd07f: + break; + + case 0xd0b0: + case 0xd0b1: + break; + + case 0xd0b2: + break; + + case 0xd0b3: + break; + + case 0xd0b4: + break; + + case 0xd0b5: + break; + + case 0xd0b6: + break; + + case 0xd0b7: + break; + + case 0xd0b8: + break; + + case 0xd0b9: + case 0xd0ba: + case 0xd0bb: + break; + + case 0xd0bc: + break; + + case 0xd0be: + break; + + case 0xd0bd: + case 0xd0bf: + break; + } + + m_exp->cd_w(space, offset, data, sphi2, ba, roml, romh, io1, io2); +} + + +//------------------------------------------------- +// c64_game_r - GAME read +//------------------------------------------------- + +int c64_supercpu_device::c64_game_r(offs_t offset, int sphi2, int ba, int rw) +{ + return m_exp->game_r(offset, sphi2, ba, rw, m_slot->hiram()); +} + + +//------------------------------------------------- +// c64_exrom_r - EXROM read +//------------------------------------------------- + +int c64_supercpu_device::c64_exrom_r(offs_t offset, int sphi2, int ba, int rw) +{ + return m_exp->exrom_r(offset, sphi2, ba, rw, m_slot->hiram()); +} diff --git a/src/devices/bus/c64/supercpu.h b/src/devices/bus/c64/supercpu.h new file mode 100644 index 00000000000..857f6feb47f --- /dev/null +++ b/src/devices/bus/c64/supercpu.h @@ -0,0 +1,63 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + CMD SuperCPU v2 + SuperRAM emulation + +**********************************************************************/ + +#pragma once + +#ifndef __SUPERCPU__ +#define __SUPERCPU__ + +#include "emu.h" +#include "exp.h" +#include "cpu/g65816/g65816.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> c64_supercpu_device + +class c64_supercpu_device : public device_t, + public device_c64_expansion_card_interface +{ +public: + // construction/destruction + c64_supercpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + virtual ioport_constructor device_input_ports() const; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_c64_expansion_card_interface overrides + virtual UINT8 c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + virtual void c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + virtual int c64_game_r(offs_t offset, int sphi2, int ba, int rw); + virtual int c64_exrom_r(offs_t offset, int sphi2, int ba, int rw); + +private: + required_device m_maincpu; + required_device m_exp; + + required_shared_ptr m_sram; + required_shared_ptr m_dimm; +}; + + +// device type definition +extern const device_type C64_SUPERCPU; + + + +#endif diff --git a/src/devices/bus/c64/sw8k.c b/src/devices/bus/c64/sw8k.c new file mode 100644 index 00000000000..9b0cce8c55d --- /dev/null +++ b/src/devices/bus/c64/sw8k.c @@ -0,0 +1,114 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + C64 switchable 8K cartridge emulation + +**********************************************************************/ + +/* + + 4040 + Fast Hack'em + + PCB Layout + ---------- + + |===========================| + |=| | + |=| SW1 | + |=| ROM0 | + |=| | + |=| | + |=| ROM1 | + |=| | + |=| | + |===========================| + + ROM0,1 - National Semiconductor NMC27C64Q 8Kx8 EPROM + SW1 - ROM selection switch + +*/ + +#include "sw8k.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type C64_SW8K = &device_creator; + + +//------------------------------------------------- +// INPUT_PORTS( c64_easyflash ) +//------------------------------------------------- + +static INPUT_PORTS_START( c64_switchable_8k ) + PORT_START("SW") + PORT_DIPNAME( 0x01, 0x00, "ROM Select" ) + PORT_DIPSETTING( 0x00, "ROM 0" ) + PORT_DIPSETTING( 0x01, "ROM 1" ) +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor c64_switchable_8k_cartridge_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( c64_switchable_8k ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// c64_switchable_8k_cartridge_device - constructor +//------------------------------------------------- + +c64_switchable_8k_cartridge_device::c64_switchable_8k_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, C64_SW8K, "C64 Switchable 8K cartridge", tag, owner, clock, "c64_sw8k", __FILE__), + device_c64_expansion_card_interface(mconfig, *this), + m_sw(*this, "SW") +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void c64_switchable_8k_cartridge_device::device_start() +{ +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void c64_switchable_8k_cartridge_device::device_reset() +{ + m_bank = m_sw->read(); +} + + +//------------------------------------------------- +// c64_cd_r - cartridge data read +//------------------------------------------------- + +UINT8 c64_switchable_8k_cartridge_device::c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (!roml) + { + offs_t addr = (m_bank << 13) | (offset & 0x1fff); + data = m_roml[addr]; + } + + return data; +} diff --git a/src/devices/bus/c64/sw8k.h b/src/devices/bus/c64/sw8k.h new file mode 100644 index 00000000000..0838baf68a7 --- /dev/null +++ b/src/devices/bus/c64/sw8k.h @@ -0,0 +1,55 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + C64 switchable 8K cartridge emulation + +**********************************************************************/ + +#pragma once + +#ifndef __C64_SW8K__ +#define __C64_SW8K__ + + +#include "emu.h" +#include "exp.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> c64_switchable_8k_cartridge_device + +class c64_switchable_8k_cartridge_device : public device_t, + public device_c64_expansion_card_interface +{ +public: + // construction/destruction + c64_switchable_8k_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual ioport_constructor device_input_ports() const; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_c64_expansion_card_interface overrides + virtual UINT8 c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + +private: + required_ioport m_sw; + + int m_bank; +}; + + +// device type definition +extern const device_type C64_SW8K; + + +#endif diff --git a/src/devices/bus/c64/swiftlink.c b/src/devices/bus/c64/swiftlink.c new file mode 100644 index 00000000000..19e4ea5161a --- /dev/null +++ b/src/devices/bus/c64/swiftlink.c @@ -0,0 +1,175 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + CMD SwiftLink RS-232 cartridge emulation + +**********************************************************************/ + +/* + + http://mclauchlan.site.net.au/scott/C=Hacking/C-Hacking10/C-Hacking10-swiftlink.html + +*/ + +#include "swiftlink.h" +#include "bus/rs232/rs232.h" + + + +//************************************************************************** +// MACROS/CONSTANTS +//************************************************************************** + +#define MOS6551_TAG "mos6551" +#define RS232_TAG "rs232" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type C64_SWIFTLINK = &device_creator; + + +//------------------------------------------------- +// MACHINE_CONFIG_FRAGMENT( c64_swiftlink ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( c64_swiftlink ) + MCFG_DEVICE_ADD(MOS6551_TAG, MOS6551, 0) + MCFG_MOS6551_XTAL(XTAL_3_6864MHz) + MCFG_MOS6551_IRQ_HANDLER(WRITELINE(c64_swiftlink_cartridge_device, acia_irq_w)) + MCFG_MOS6551_TXD_HANDLER(DEVWRITELINE(RS232_TAG, rs232_port_device, write_txd)) + + MCFG_RS232_PORT_ADD(RS232_TAG, default_rs232_devices, NULL) + MCFG_RS232_RXD_HANDLER(DEVWRITELINE(MOS6551_TAG, mos6551_device, write_rxd)) + MCFG_RS232_DCD_HANDLER(DEVWRITELINE(MOS6551_TAG, mos6551_device, write_dcd)) + MCFG_RS232_DSR_HANDLER(DEVWRITELINE(MOS6551_TAG, mos6551_device, write_dsr)) + MCFG_RS232_CTS_HANDLER(DEVWRITELINE(MOS6551_TAG, mos6551_device, write_cts)) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor c64_swiftlink_cartridge_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( c64_swiftlink ); +} + + +//------------------------------------------------- +// INPUT_PORTS( c64_swiftlink ) +//------------------------------------------------- + +static INPUT_PORTS_START( c64_swiftlink ) + PORT_START("CS") + PORT_DIPNAME( 0x03, 0x01, "Base Address" ) + PORT_DIPSETTING( 0x00, "$D700 (C128)" ) + PORT_DIPSETTING( 0x01, "$DE00" ) + PORT_DIPSETTING( 0x02, "$DF00" ) + + PORT_START("IRQ") + PORT_DIPNAME( 0x01, 0x01, "Interrupt" ) + PORT_DIPSETTING( 0x00, "IRQ" ) + PORT_DIPSETTING( 0x01, "NMI" ) +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor c64_swiftlink_cartridge_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( c64_swiftlink ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// c64_swiftlink_cartridge_device - constructor +//------------------------------------------------- + +c64_swiftlink_cartridge_device::c64_swiftlink_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, C64_SWIFTLINK, "C64 SwiftLink cartridge", tag, owner, clock, "c64_swiftlink", __FILE__), + device_c64_expansion_card_interface(mconfig, *this), + m_acia(*this, MOS6551_TAG), + m_io_cs(*this, "CS"), + m_io_irq(*this, "IRQ") +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void c64_swiftlink_cartridge_device::device_start() +{ +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void c64_swiftlink_cartridge_device::device_reset() +{ + m_acia->reset(); + + m_cs = m_io_cs->read(); + m_irq = m_io_irq->read(); +} + + +//------------------------------------------------- +// c64_cd_r - cartridge data read +//------------------------------------------------- + +UINT8 c64_swiftlink_cartridge_device::c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (((m_cs == DE00) && !io1) || ((m_cs == DF00) && !io2) || + ((m_cs == D700) && ((offset & 0xff00) == 0xd700))) + { + data = m_acia->read(space, offset & 0x03); + } + + return data; +} + + +//------------------------------------------------- +// c64_cd_w - cartridge data write +//------------------------------------------------- + +void c64_swiftlink_cartridge_device::c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (((m_cs == DE00) && !io1) || ((m_cs == DF00) && !io2) || + ((m_cs == D700) && ((offset & 0xff00) == 0xd700))) + { + m_acia->write(space, offset & 0x03, data); + } +} + + +//------------------------------------------------- +// acia_irq_w - +//------------------------------------------------- + +WRITE_LINE_MEMBER( c64_swiftlink_cartridge_device::acia_irq_w ) +{ + switch (m_irq) + { + case IRQ: m_slot->irq_w(state); break; + case NMI: m_slot->nmi_w(state); break; + } +} diff --git a/src/devices/bus/c64/swiftlink.h b/src/devices/bus/c64/swiftlink.h new file mode 100644 index 00000000000..713bafbb289 --- /dev/null +++ b/src/devices/bus/c64/swiftlink.h @@ -0,0 +1,76 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + CMD SwiftLink RS-232 cartridge emulation + +**********************************************************************/ + +#pragma once + +#ifndef __SWIFTLINK__ +#define __SWIFTLINK__ + + +#include "exp.h" +#include "machine/mos6551.h" + + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> c64_swiftlink_cartridge_device + +class c64_swiftlink_cartridge_device : public device_t, + public device_c64_expansion_card_interface +{ +public: + // construction/destruction + c64_swiftlink_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual ioport_constructor device_input_ports() const; + + DECLARE_WRITE_LINE_MEMBER( acia_irq_w ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_c64_expansion_card_interface overrides + virtual UINT8 c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + virtual void c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + +private: + required_device m_acia; + required_ioport m_io_cs; + required_ioport m_io_irq; + + enum + { + D700 = 0, + DE00, + DF00 + }; + + enum + { + IRQ = 0, + NMI + }; + + int m_cs; + int m_irq; +}; + + +// device type definition +extern const device_type C64_SWIFTLINK; + + +#endif diff --git a/src/devices/bus/c64/system3.c b/src/devices/bus/c64/system3.c new file mode 100644 index 00000000000..b14ca7ecc87 --- /dev/null +++ b/src/devices/bus/c64/system3.c @@ -0,0 +1,90 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + System 3 cartridge emulation + +**********************************************************************/ + +#include "system3.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type C64_SYSTEM3 = &device_creator; + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// c64_system3_cartridge_device - constructor +//------------------------------------------------- + +c64_system3_cartridge_device::c64_system3_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, C64_SYSTEM3, "C64 System 3 cartridge", tag, owner, clock, "c64_system3", __FILE__), + device_c64_expansion_card_interface(mconfig, *this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void c64_system3_cartridge_device::device_start() +{ + // state saving + save_item(NAME(m_bank)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void c64_system3_cartridge_device::device_reset() +{ + m_bank = 0; +} + + +//------------------------------------------------- +// c64_cd_r - cartridge data read +//------------------------------------------------- + +UINT8 c64_system3_cartridge_device::c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (!roml) + { + offs_t addr = (m_bank << 13) | (offset & 0x1fff); + data = m_roml[addr]; + } + else if (!io1) + { + m_bank = offset & 0x3f; + m_game = 1; + data = 0; + } + + return data; +} + + +//------------------------------------------------- +// c64_cd_w - cartridge data write +//------------------------------------------------- + +void c64_system3_cartridge_device::c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (!io1) + { + m_bank = offset & 0x3f; + m_game = 0; + } +} diff --git a/src/devices/bus/c64/system3.h b/src/devices/bus/c64/system3.h new file mode 100644 index 00000000000..c6adc33c880 --- /dev/null +++ b/src/devices/bus/c64/system3.h @@ -0,0 +1,51 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Dinamic Software cartridge emulation + +**********************************************************************/ + +#pragma once + +#ifndef __SYSTEM3__ +#define __SYSTEM3__ + + +#include "emu.h" +#include "exp.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> c64_system3_cartridge_device + +class c64_system3_cartridge_device : public device_t, + public device_c64_expansion_card_interface +{ +public: + // construction/destruction + c64_system3_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_c64_expansion_card_interface overrides + virtual UINT8 c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + virtual void c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + +private: + UINT8 m_bank; +}; + + +// device type definition +extern const device_type C64_SYSTEM3; + + +#endif diff --git a/src/devices/bus/c64/tdos.c b/src/devices/bus/c64/tdos.c new file mode 100644 index 00000000000..e472ab7e1db --- /dev/null +++ b/src/devices/bus/c64/tdos.c @@ -0,0 +1,341 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Triton QD TDOS cartridge emulation + +**********************************************************************/ + +/* + +PCB Layout +---------- + +XM-2206-A (top) +XM-2205-A (bottom) + + |===========================| + | CN4 | + | | + | ULA | + | | + | 6.5MHz | + | | + | SSDA | + | LS175 | + | LS367 | + | CN3 | + |=========|||||||||=========| + ||||||||| + |=============|||||||||============| + | CN2 | + | LS00 LS02 LS138 | +|=======| | +|=| LS245 ROM | +|=| | +|=| | +|=| CN1| +|=| | +|=| | +|=| | +|=| SW1 | +|==========================================| + +ROM - Hitachi HN482764G 8Kx8 EPROM "TDOS 1.2" +ULA - Ferranti ULA5RB073E1 XZ-2085-1 40-pin custom ULA +SSDA - Motorola MC68A52P SSDA +CN1 - C64 expansion connector (pass-thru) +CN2,3 - 18x1 flat ribbon cable to other PCB +CN4 - 9 wire cable to Mitsumi Quick Disk 3" drive +SW1 - cartridge on/off switch + + +Flat ribbon cable pinout +------------------------ +1 D7 +2 D6 +3 D5 +4 D4 +5 D3 +6 LS00 4Y -> LS367 _G1 +7 phi2 +8 LS00 3Y -> LS175 CP +9 D2 +10 D1 +11 D0 +12 RESET +13 A0 +14 R/_W +15 GND +16 +5V +17 LS138 O2 -> LS367 _G1 +18 LS138 O0 -> SSDA _CS + + +Drive cable pinout +------------------ +1 WP Write Protected +2 WD Write Data +3 WG Write Gate +4 MO Motor +5 RD Read Data +6 RY Ready +7 MS Media Set +8 RS Reset +9 +5V +10 GND + + +ULA pinout +---------- + _____ _____ + 1 |* \_/ | 40 + 2 | | 39 + 3 | | 38 + 4 | | 37 + 5 | | 36 GND + 6 | | 35 + RD 7 | | 34 + _D5 8 | | 33 + RxC 9 | | 32 + RxD 10 | XZ-2085-1 | 31 + 11 | | 30 + WD 12 | | 29 + TxC 13 | | 28 + TxD 14 | | 27 + D7 15 | | 26 + WG 16 | | 25 +5V + 17 | | 24 XTAL2 + 18 | | 23 XTAL1 + RS 19 | | 22 GND + 20 |_____________| 21 + + +BASIC commands (SYS 32768 to activate) +-------------------------------------- +@Dn +@Format +@Dir +@Save +@ASave +@Write +@Load +@Run +@Aload +@Kill +@Quit +@ACopy +@CassCopy + +*/ + +#include "tdos.h" + + + +//************************************************************************** +// MACROS/CONSTANTS +//************************************************************************** + +#define MC68A52P_TAG "mc6852" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type C64_TDOS = &device_creator; + + +//------------------------------------------------- +// MACHINE_CONFIG_FRAGMENT( c64_multiscreen ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( c64_tdos ) + MCFG_DEVICE_ADD(MC68A52P_TAG, MC6852, XTAL_6_5MHz) + + MCFG_C64_PASSTHRU_EXPANSION_SLOT_ADD() +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor c64_tdos_cartridge_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( c64_tdos ); +} + + +//------------------------------------------------- +// INPUT_PORTS( c64_tdos ) +//------------------------------------------------- + +static INPUT_PORTS_START( c64_tdos ) + PORT_START("SW1") + PORT_DIPNAME( 0x01, 0x01, "Enabled" ) + PORT_DIPSETTING( 0x00, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x01, DEF_STR( On ) ) +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor c64_tdos_cartridge_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( c64_tdos ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// c64_tdos_cartridge_device - constructor +//------------------------------------------------- + +c64_tdos_cartridge_device::c64_tdos_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, C64_TDOS, "C64 TDOS cartridge", tag, owner, clock, "c64_tdos", __FILE__), + device_c64_expansion_card_interface(mconfig, *this), + m_ssda(*this, MC68A52P_TAG), + m_exp(*this, C64_EXPANSION_SLOT_TAG), + m_sw1(*this, "SW1") +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void c64_tdos_cartridge_device::device_start() +{ +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void c64_tdos_cartridge_device::device_reset() +{ + m_ssda->reset(); + //m_ula->reset(); + //flip-flop reset + + m_enabled = m_sw1->read(); +} + + +//------------------------------------------------- +// c64_cd_r - cartridge data read +//------------------------------------------------- + +UINT8 c64_tdos_cartridge_device::c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + data = m_exp->cd_r(space, offset, data, sphi2, ba, roml, romh, io1, io2); + + if (m_enabled && !roml) + { + data = m_roml[offset & 0x1fff]; + } + + if (m_enabled && !io2 && sphi2) + { + switch ((offset >> 1) & 0x7f) + { + case 0: + data = m_ssda->read(space, offset & 0x01); + break; + + case 1: + break; + + case 2: + /* + + bit description + + 0 + 1 + 2 + 3 + 4 + 5 drive MS + 6 drive WP + 7 drive RY + + */ + break; + } + } + + return data; +} + + +//------------------------------------------------- +// c64_cd_w - cartridge data write +//------------------------------------------------- + +void c64_tdos_cartridge_device::c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + m_exp->cd_w(space, offset, data, sphi2, ba, roml, romh, io1, io2); + + if (m_enabled && !io2 && sphi2) + { + switch ((offset >> 1) & 0x7f) + { + case 0: + m_ssda->write(space, offset & 0x01, data); + break; + + case 1: + /* + + bit description + + 0 + 1 + 2 + 3 + 4 + 5 ULA pin 8, inverted + 6 drive MO + 7 ULA pin 15 + + */ + break; + + case 2: + break; + } + } +} + + +//------------------------------------------------- +// c64_game_r - GAME read +//------------------------------------------------- + +int c64_tdos_cartridge_device::c64_game_r(offs_t offset, int sphi2, int ba, int rw) +{ + return m_enabled ? 1 : m_exp->game_r(offset, sphi2, ba, rw, m_slot->hiram()); +} + + +//------------------------------------------------- +// c64_exrom_r - EXROM read +//------------------------------------------------- + +int c64_tdos_cartridge_device::c64_exrom_r(offs_t offset, int sphi2, int ba, int rw) +{ + return m_enabled ? 0 : m_exp->exrom_r(offset, sphi2, ba, rw, m_slot->hiram()); +} diff --git a/src/devices/bus/c64/tdos.h b/src/devices/bus/c64/tdos.h new file mode 100644 index 00000000000..93e3823d180 --- /dev/null +++ b/src/devices/bus/c64/tdos.h @@ -0,0 +1,61 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Triton QD TDOS cartridge emulation + +**********************************************************************/ + +#pragma once + +#ifndef __TDOS__ +#define __TDOS__ + +#include "emu.h" +#include "exp.h" +#include "machine/mc6852.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> c64_tdos_cartridge_device + +class c64_tdos_cartridge_device : public device_t, + public device_c64_expansion_card_interface +{ +public: + // construction/destruction + c64_tdos_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual ioport_constructor device_input_ports() const; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_c64_expansion_card_interface overrides + virtual UINT8 c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + virtual void c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + virtual int c64_game_r(offs_t offset, int sphi2, int ba, int rw); + virtual int c64_exrom_r(offs_t offset, int sphi2, int ba, int rw); + +private: + required_device m_ssda; + required_device m_exp; + required_ioport m_sw1; + + bool m_enabled; +}; + + +// device type definition +extern const device_type C64_TDOS; + + +#endif diff --git a/src/devices/bus/c64/turbo232.c b/src/devices/bus/c64/turbo232.c new file mode 100644 index 00000000000..8fe00f65fd1 --- /dev/null +++ b/src/devices/bus/c64/turbo232.c @@ -0,0 +1,219 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + CMD Turbo232 RS-232 cartridge emulation + +**********************************************************************/ + +/* + + http://ar.c64.org/wiki/Turbo232_Programming.txt + +*/ + +#include "turbo232.h" + + + +//************************************************************************** +// MACROS/CONSTANTS +//************************************************************************** + +#define MOS6551_TAG "mos6551" +#define RS232_TAG "rs232" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type C64_TURBO232 = &device_creator; + + +//------------------------------------------------- +// MACHINE_CONFIG_FRAGMENT( c64_turbo232 ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( c64_turbo232 ) + MCFG_DEVICE_ADD(MOS6551_TAG, MOS6551, 0) + MCFG_MOS6551_XTAL(XTAL_3_6864MHz) + MCFG_MOS6551_IRQ_HANDLER(WRITELINE(c64_turbo232_cartridge_device, acia_irq_w)) + MCFG_MOS6551_TXD_HANDLER(DEVWRITELINE(RS232_TAG, rs232_port_device, write_txd)) + + MCFG_RS232_PORT_ADD(RS232_TAG, default_rs232_devices, NULL) + MCFG_RS232_RXD_HANDLER(DEVWRITELINE(MOS6551_TAG, mos6551_device, write_rxd)) + MCFG_RS232_DCD_HANDLER(DEVWRITELINE(MOS6551_TAG, mos6551_device, write_dcd)) + MCFG_RS232_DSR_HANDLER(DEVWRITELINE(MOS6551_TAG, mos6551_device, write_dsr)) + MCFG_RS232_CTS_HANDLER(DEVWRITELINE(MOS6551_TAG, mos6551_device, write_cts)) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor c64_turbo232_cartridge_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( c64_turbo232 ); +} + + +//------------------------------------------------- +// INPUT_PORTS( c64_turbo232 ) +//------------------------------------------------- + +static INPUT_PORTS_START( c64_turbo232 ) + PORT_START("CS") + PORT_DIPNAME( 0x03, 0x01, "Base Address" ) + PORT_DIPSETTING( 0x00, "$D700 (C128)" ) + PORT_DIPSETTING( 0x01, "$DE00" ) + PORT_DIPSETTING( 0x02, "$DF00" ) + + PORT_START("IRQ") + PORT_DIPNAME( 0x01, 0x01, "Interrupt" ) + PORT_DIPSETTING( 0x00, "IRQ" ) + PORT_DIPSETTING( 0x01, "NMI" ) +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor c64_turbo232_cartridge_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( c64_turbo232 ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// c64_turbo232_cartridge_device - constructor +//------------------------------------------------- + +c64_turbo232_cartridge_device::c64_turbo232_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, C64_TURBO232, "C64 Turbo232 cartridge", tag, owner, clock, "c64_turbo232", __FILE__), + device_c64_expansion_card_interface(mconfig, *this), + m_acia(*this, MOS6551_TAG), + m_rs232(*this, RS232_TAG), + m_io_cs(*this, "CS"), + m_io_irq(*this, "IRQ") +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void c64_turbo232_cartridge_device::device_start() +{ +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void c64_turbo232_cartridge_device::device_reset() +{ + m_acia->reset(); + + m_cs = m_io_cs->read(); + m_irq = m_io_irq->read(); + + m_es = 0; +} + + +//------------------------------------------------- +// c64_cd_r - cartridge data read +//------------------------------------------------- + +UINT8 c64_turbo232_cartridge_device::c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (((m_cs == DE00) && !io1) || ((m_cs == DF00) && !io2) || + ((m_cs == D700) && ((offset & 0xff00) == 0xd700))) + { + if (!(offset & 0xe0)) + { + switch (offset & 0x07) + { + case 0: case 1: case 2: case 3: + data = m_acia->read(space, offset & 0x03); + break; + + case 7: + data = m_es; + } + } + } + + return data; +} + + +//------------------------------------------------- +// c64_cd_w - cartridge data write +//------------------------------------------------- + +void c64_turbo232_cartridge_device::c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (((m_cs == DE00) && !io1) || ((m_cs == DF00) && !io2) || + ((m_cs == D700) && ((offset & 0xff00) == 0xd700))) + { + if (!(offset & 0xe0)) + { + switch (offset & 0x07) + { + case 0: case 1: case 2: + m_acia->write(space, offset & 0x03, data); + break; + + case 3: + m_acia->write(space, offset & 0x03, data); + + if (data & 0x0f) + m_es &= ~ES_M; + else + m_es |= ES_M; + break; + + case 7: + if (m_es & ES_M) + { + data = m_es; + + switch (m_es & ES_S_MASK) + { + case ES_S_230400: m_acia->set_xtal(XTAL_3_6864MHz); break; + case ES_S_115200: m_acia->set_xtal(XTAL_3_6864MHz/2); break; + case ES_S_57600: m_acia->set_xtal(XTAL_3_6864MHz/4); break; + case ES_S_UNDEFINED: m_acia->set_xtal(0); break; + } + } + } + } + } +} + + +//------------------------------------------------- +// acia_irq_w - +//------------------------------------------------- + +WRITE_LINE_MEMBER( c64_turbo232_cartridge_device::acia_irq_w ) +{ + switch (m_irq) + { + case IRQ: m_slot->irq_w(state); break; + case NMI: m_slot->nmi_w(state); break; + } +} diff --git a/src/devices/bus/c64/turbo232.h b/src/devices/bus/c64/turbo232.h new file mode 100644 index 00000000000..b8ff5a17c8c --- /dev/null +++ b/src/devices/bus/c64/turbo232.h @@ -0,0 +1,89 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + CMD Turbo232 RS-232 cartridge emulation + +**********************************************************************/ + +#pragma once + +#ifndef __TURBO232__ +#define __TURBO232__ + + +#include "exp.h" +#include "machine/mos6551.h" +#include "bus/rs232/rs232.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> c64_turbo232_cartridge_device + +class c64_turbo232_cartridge_device : public device_t, + public device_c64_expansion_card_interface +{ +public: + // construction/destruction + c64_turbo232_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual ioport_constructor device_input_ports() const; + + DECLARE_WRITE_LINE_MEMBER( acia_irq_w ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_c64_expansion_card_interface overrides + virtual UINT8 c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + virtual void c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + +private: + required_device m_acia; + required_device m_rs232; + required_ioport m_io_cs; + required_ioport m_io_irq; + + enum + { + D700 = 0, + DE00, + DF00 + }; + + enum + { + IRQ = 0, + NMI + }; + + enum + { + ES_S_230400 = 0x00, + ES_S_115200 = 0x01, + ES_S_57600 = 0x02, + ES_S_UNDEFINED = 0x03, + ES_S_MASK = 0x03, + ES_M = 0x04 + }; + + int m_cs; + int m_irq; + + UINT8 m_es; +}; + + +// device type definition +extern const device_type C64_TURBO232; + + +#endif diff --git a/src/devices/bus/c64/user.c b/src/devices/bus/c64/user.c new file mode 100644 index 00000000000..54e8bc560d2 --- /dev/null +++ b/src/devices/bus/c64/user.c @@ -0,0 +1,32 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/********************************************************************** + + Commodore 64 User Port emulation + +**********************************************************************/ + +#include "user.h" + +//------------------------------------------------- +// SLOT_INTERFACE( c64_user_port_cards ) +//------------------------------------------------- + +// slot devices +#include "bus/vic20/4cga.h" +#include "4dxh.h" +#include "4ksa.h" +#include "4tba.h" +#include "bn1541.h" +#include "geocable.h" +#include "bus/vic20/vic1011.h" + +SLOT_INTERFACE_START( c64_user_port_cards ) + SLOT_INTERFACE("4cga", C64_4CGA) + SLOT_INTERFACE("4dxh", C64_4DXH) + SLOT_INTERFACE("4ksa", C64_4KSA) + SLOT_INTERFACE("4tba", C64_4TBA) + SLOT_INTERFACE("bn1541", C64_BN1541) + SLOT_INTERFACE("geocable", C64_GEOCABLE) + SLOT_INTERFACE("rs232", VIC1011) +SLOT_INTERFACE_END diff --git a/src/devices/bus/c64/user.h b/src/devices/bus/c64/user.h new file mode 100644 index 00000000000..52aed6eb972 --- /dev/null +++ b/src/devices/bus/c64/user.h @@ -0,0 +1,33 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/********************************************************************** + + Commodore 64 User Port emulation + +********************************************************************** + + GND 1 A GND + +5V 2 B /FLAG2 + /RESET 3 C PB0 + CNT1 4 D PB1 + SP1 5 E PB2 + CNT2 6 F PB3 + SP2 7 H PB4 + /PC2 8 J PB5 + ATN 9 K PB6 + +9VAC 10 L PB7 + +9VAC 11 M PA2 + GND 12 N GND + +**********************************************************************/ + +#pragma once + +#ifndef __C64_USER_PORT__ +#define __C64_USER_PORT__ + +#include "bus/pet/user.h" + +SLOT_INTERFACE_EXTERN( c64_user_port_cards ); + +#endif diff --git a/src/devices/bus/c64/vizastar.c b/src/devices/bus/c64/vizastar.c new file mode 100644 index 00000000000..d635ffec656 --- /dev/null +++ b/src/devices/bus/c64/vizastar.c @@ -0,0 +1,89 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + VizaStar 64 XL4 cartridge emulation + +**********************************************************************/ + +/* + + PCB Layout + ---------- + RB84 (C) MICROPORT + |===========================| + |=| | + |=| | + |=| | + |=| | + |=| ROM | + |=| | + |=| | + |=| | + |===========================| + + ROM - Hitachi HN462732G 4Kx8 EPROM "V" + +*/ + +#include "vizastar.h" + + + +//************************************************************************** +// MACROS/CONSTANTS +//************************************************************************** + +#define UNSCRAMBLE_ADDRESS(_offset) \ + BITSWAP16(_offset,15,14,13,12,5,0,7,10,11,9,8,6,4,3,2,1) + +#define UNSCRAMBLE_DATA(_data) \ + BITSWAP8(_data,7,6,0,5,1,4,2,3) + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type C64_VIZASTAR = &device_creator; + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// c64_vizastar_cartridge_device - constructor +//------------------------------------------------- + +c64_vizastar_cartridge_device::c64_vizastar_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, C64_VIZASTAR, "VizaStar 64 XL4", tag, owner, clock, "c64_vizastar", __FILE__), + device_c64_expansion_card_interface(mconfig, *this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void c64_vizastar_cartridge_device::device_start() +{ +} + + +//------------------------------------------------- +// c64_cd_r - cartridge data read +//------------------------------------------------- + +UINT8 c64_vizastar_cartridge_device::c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (!roml) + { + data = UNSCRAMBLE_DATA(m_roml[UNSCRAMBLE_ADDRESS(offset & 0xfff)]); + } + + return data; +} diff --git a/src/devices/bus/c64/vizastar.h b/src/devices/bus/c64/vizastar.h new file mode 100644 index 00000000000..0b01f4424a7 --- /dev/null +++ b/src/devices/bus/c64/vizastar.h @@ -0,0 +1,46 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + VizaStar 64 XL4 cartridge emulation + +**********************************************************************/ + +#pragma once + +#ifndef __VIZASTAR__ +#define __VIZASTAR__ + + +#include "emu.h" +#include "exp.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> c64_vizastar_cartridge_device + +class c64_vizastar_cartridge_device : public device_t, + public device_c64_expansion_card_interface +{ +public: + // construction/destruction + c64_vizastar_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // device-level overrides + virtual void device_start(); + + // device_c64_expansion_card_interface overrides + virtual UINT8 c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); +}; + + +// device type definition +extern const device_type C64_VIZASTAR; + + +#endif diff --git a/src/devices/bus/c64/vw64.c b/src/devices/bus/c64/vw64.c new file mode 100644 index 00000000000..fdc21ff4a05 --- /dev/null +++ b/src/devices/bus/c64/vw64.c @@ -0,0 +1,127 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + VizaWrite 64 cartridge emulation + +**********************************************************************/ + +/* + + PCB Layout + ---------- + + |===========================| + |=| LS10 LS122 C | + |=| R | + |=| | + |=| | + |=| ROM0 ROM2 ROM1 | + |=| | + |=| | + |=| | + |===========================| + + ROM0 - Mitsubishi M5L2764K 8Kx8 EPROM "U" + ROM1 - Mitsubishi M5L2764K 8Kx8 EPROM "3" + ROM2 - Mitsubishi M5L2764K 8Kx8 EPROM "2" (located on solder side) + R - 56K + C - 47uF + +*/ + +#include "vw64.h" + + + +//************************************************************************** +// MACROS/CONSTANTS +//************************************************************************** + +#define UNSCRAMBLE_ADDRESS(_offset) \ + BITSWAP16(_offset,15,14,13,12,6,2,8,10,11,9,7,5,4,3,1,0) + +#define UNSCRAMBLE_DATA(_data) \ + BITSWAP8(_data,7,6,0,5,1,4,2,3) + + +// 74LS122 tW=0.45*R*C = 1.1844s +#define TIMER_PERIOD 1184 + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type C64_VW64 = &device_creator; + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// c64_vizawrite_cartridge_device - constructor +//------------------------------------------------- + +c64_vizawrite_cartridge_device::c64_vizawrite_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, C64_VW64, "VizaWrite 64", tag, owner, clock, "c64_vizawrite", __FILE__), + device_c64_expansion_card_interface(mconfig, *this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void c64_vizawrite_cartridge_device::device_start() +{ + // allocate timer + m_game_timer = timer_alloc(); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void c64_vizawrite_cartridge_device::device_reset() +{ + m_game = 0; + + m_game_timer->adjust(attotime::from_msec(TIMER_PERIOD), 0); +} + + +//------------------------------------------------- +// device_timer - handler timer events +//------------------------------------------------- + +void c64_vizawrite_cartridge_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + m_game = 1; +} + + +//------------------------------------------------- +// c64_cd_r - cartridge data read +//------------------------------------------------- + +UINT8 c64_vizawrite_cartridge_device::c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (!roml) + { + offs_t addr = (m_game << 13) | (offset & 0x1fff); + data = UNSCRAMBLE_DATA(m_roml[UNSCRAMBLE_ADDRESS(addr)]); + } + else if (!romh) + { + offs_t addr = offset & 0x1fff; + data = UNSCRAMBLE_DATA(m_romh[UNSCRAMBLE_ADDRESS(addr)]); + } + + return data; +} diff --git a/src/devices/bus/c64/vw64.h b/src/devices/bus/c64/vw64.h new file mode 100644 index 00000000000..fac67142a1a --- /dev/null +++ b/src/devices/bus/c64/vw64.h @@ -0,0 +1,52 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + VizaWrite 64 cartridge emulation + +**********************************************************************/ + +#pragma once + +#ifndef __VW64__ +#define __VW64__ + + +#include "emu.h" +#include "exp.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> c64_vizawrite_cartridge_device + +class c64_vizawrite_cartridge_device : public device_t, + public device_c64_expansion_card_interface +{ +public: + // construction/destruction + c64_vizawrite_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + // device_c64_expansion_card_interface overrides + virtual UINT8 c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + virtual int c64_exrom_r(offs_t offset, int sphi2, int ba, int rw) { return 0; } + +private: + emu_timer *m_game_timer; +}; + + +// device type definition +extern const device_type C64_VW64; + + +#endif diff --git a/src/devices/bus/c64/warp_speed.c b/src/devices/bus/c64/warp_speed.c new file mode 100644 index 00000000000..d625fa5ea7d --- /dev/null +++ b/src/devices/bus/c64/warp_speed.c @@ -0,0 +1,147 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Cinemaware Warp Speed cartridge emulation + +**********************************************************************/ + +/* + + PCB Layout + ---------- + + |===================| + |=| SW1 | + |=| | + |=| SW2 | + |=| | + |=| | + |=| ROM | + |=| LS109| + |=| | + |===================| + + ROM - "DEI-356NR-WRPIIDA1 (C) NCR A8847 609-2415038 F833071" 16Kx8 ROM + SW1 - mode switch (C64/C128) + SW2 - reset button + +*/ + +#include "warp_speed.h" + + + +//************************************************************************** +// MACROS/CONSTANTS +//************************************************************************** + +#define UNSCRAMBLE_ADDRESS(_offset) \ + BITSWAP16(_offset,15,14,12,13,5,2,7,9,11,10,8,6,4,3,1,0) + +#define UNSCRAMBLE_DATA(_data) \ + BITSWAP8(_data,7,6,5,0,1,4,2,3) + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type C64_WARP_SPEED = &device_creator; + + +//------------------------------------------------- +// INPUT_PORTS( c64_warp_speed ) +//------------------------------------------------- + +static INPUT_PORTS_START( c64_warp_speed ) + PORT_START("SW1") + PORT_DIPNAME( 0x01, 0x01, "Mode" ) + PORT_DIPSETTING( 0x01, "C64" ) + PORT_DIPSETTING( 0x00, "C128" ) + + PORT_START("SW2") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_OTHER ) PORT_NAME("Reset") PORT_CODE(KEYCODE_F11) PORT_WRITE_LINE_DEVICE_MEMBER(DEVICE_SELF_OWNER, c64_expansion_slot_device, reset_w) +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor c64_warp_speed_cartridge_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( c64_warp_speed ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// c64_warp_speed_cartridge_device - constructor +//------------------------------------------------- + +c64_warp_speed_cartridge_device::c64_warp_speed_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, C64_WARP_SPEED, "C64 Warp Speed cartridge", tag, owner, clock, "c64_warp_speed", __FILE__), + device_c64_expansion_card_interface(mconfig, *this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void c64_warp_speed_cartridge_device::device_start() +{ +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void c64_warp_speed_cartridge_device::device_reset() +{ + m_exrom = 0; + m_game = 0; +} + + +//------------------------------------------------- +// c64_cd_r - cartridge data read +//------------------------------------------------- + +UINT8 c64_warp_speed_cartridge_device::c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (!roml || !romh || !io1 || !io2) + { + offs_t addr = UNSCRAMBLE_ADDRESS(offset & 0x3fff); + data = UNSCRAMBLE_DATA(m_roml[addr]); + } + + return data; +} + + +//------------------------------------------------- +// c64_cd_w - cartridge data write +//------------------------------------------------- + +void c64_warp_speed_cartridge_device::c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (!io1) + { + m_exrom = 0; + m_game = 0; + } + else if (!io2) + { + m_exrom = 1; + m_game = 1; + } +} diff --git a/src/devices/bus/c64/warp_speed.h b/src/devices/bus/c64/warp_speed.h new file mode 100644 index 00000000000..e115c7be256 --- /dev/null +++ b/src/devices/bus/c64/warp_speed.h @@ -0,0 +1,54 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Cinemaware Warp Speed cartridge emulation + +**********************************************************************/ + +#pragma once + +#ifndef __WARP_SPEED__ +#define __WARP_SPEED__ + + +#include "emu.h" +#include "exp.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> c64_warp_speed_cartridge_device + +class c64_warp_speed_cartridge_device : public device_t, + public device_c64_expansion_card_interface +{ +public: + // construction/destruction + c64_warp_speed_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual ioport_constructor device_input_ports() const; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_c64_expansion_card_interface overrides + virtual UINT8 c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + virtual void c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + +private: + //UINT8 m_bank; +}; + + +// device type definition +extern const device_type C64_WARP_SPEED; + + +#endif diff --git a/src/devices/bus/c64/westermann.c b/src/devices/bus/c64/westermann.c new file mode 100644 index 00000000000..6a758428a1f --- /dev/null +++ b/src/devices/bus/c64/westermann.c @@ -0,0 +1,82 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Westermann Learning cartridge emulation + +**********************************************************************/ + +#include "westermann.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type C64_WESTERMANN = &device_creator; + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// c64_westermann_cartridge_device - constructor +//------------------------------------------------- + +c64_westermann_cartridge_device::c64_westermann_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, C64_WESTERMANN, "C64 Westermann cartridge", tag, owner, clock, "c64_westermann", __FILE__), + device_c64_expansion_card_interface(mconfig, *this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void c64_westermann_cartridge_device::device_start() +{ +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void c64_westermann_cartridge_device::device_reset() +{ + m_game = 0; +} + + +//------------------------------------------------- +// c64_cd_r - cartridge data read +//------------------------------------------------- + +UINT8 c64_westermann_cartridge_device::c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (!roml) + { + data = m_roml[offset & m_roml.mask()]; + } + else if (!romh) + { + if (m_romh.bytes()) + { + data = m_romh[offset & m_romh.mask()]; + } + else + { + data = m_roml[offset & m_roml.mask()]; + } + } + else if (!io2) + { + m_game = 1; + } + + return data; +} diff --git a/src/devices/bus/c64/westermann.h b/src/devices/bus/c64/westermann.h new file mode 100644 index 00000000000..9ea1d0d605c --- /dev/null +++ b/src/devices/bus/c64/westermann.h @@ -0,0 +1,47 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Westermann Learning cartridge emulation + +**********************************************************************/ + +#pragma once + +#ifndef __WESTERMANN__ +#define __WESTERMANN__ + + +#include "emu.h" +#include "exp.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> c64_westermann_cartridge_device + +class c64_westermann_cartridge_device : public device_t, + public device_c64_expansion_card_interface +{ +public: + // construction/destruction + c64_westermann_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_c64_expansion_card_interface overrides + virtual UINT8 c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); +}; + + +// device type definition +extern const device_type C64_WESTERMANN; + + +#endif diff --git a/src/devices/bus/c64/xl80.c b/src/devices/bus/c64/xl80.c new file mode 100644 index 00000000000..c1f7fe0f1dd --- /dev/null +++ b/src/devices/bus/c64/xl80.c @@ -0,0 +1,239 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/* + +XL 80 cartridge +(c) 1984 Data 20 Corporation + +PCB Layout +---------- + + |==================================| + | LS175 LS20 LS139 | + | LS157 | +|=======| | +|=| RAM | +|=| LS157 LS157 LS165 | +|=| | +|=| CN1| +|=| CRTC ROM1 | +|=| | +|=| ROM0 LS245 LS151 | +|=| 14.31818MHz| +|=======| LS174 LS00 | + | HCU04 | + | LS74 LS161 LS74 | + |==================================| + +Notes: + All IC's shown. + + CRTC - Hitachi HD46505SP + RAM - Toshiba TMM2016AP-12 2Kx8 Static RAM + ROM0 - GI 9433CS-0090 8Kx8 ROM + ROM1 - GI 9316CS-F67 2Kx8 ROM "DTC" + CN1 - RCA video output + +*/ + +#include "xl80.h" + + + +//************************************************************************** +// MACROS/CONSTANTS +//************************************************************************** + +#define RAM_SIZE 0x800 + +#define HD46505SP_TAG "mc6845" +#define MC6845_SCREEN_TAG "screen80" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type C64_XL80 = &device_creator; + + +//------------------------------------------------- +// ROM( c64_xl80 ) +//------------------------------------------------- + +ROM_START( c64_xl80 ) + ROM_REGION( 0x800, HD46505SP_TAG, 0 ) + ROM_LOAD( "dtc.u14", 0x000, 0x800, CRC(9edf5e58) SHA1(4b244e6d94a7653a2e52c351589f0b469119fb04) ) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *c64_xl80_device::device_rom_region() const +{ + return ROM_NAME( c64_xl80 ); +} + +//------------------------------------------------- +// mc6845 +//------------------------------------------------- + +MC6845_UPDATE_ROW( c64_xl80_device::crtc_update_row ) +{ + const pen_t *pen = m_palette->pens(); + + for (int column = 0; column < x_count; column++) + { + UINT8 code = m_ram[((ma + column) & 0x7ff)]; + UINT16 addr = (code << 3) | (ra & 0x07); + UINT8 data = m_char_rom->base()[addr & 0x7ff]; + + if (column == cursor_x) + { + data = 0xff; + } + + for (int bit = 0; bit < 8; bit++) + { + int x = (column * 8) + bit; + int color = BIT(data, 7) && de; + + bitmap.pix32(vbp + y, hbp + x) = pen[color]; + + data <<= 1; + } + } +} + +//------------------------------------------------- +// GFXDECODE( c64_xl80 ) +//------------------------------------------------- + +static GFXDECODE_START( c64_xl80 ) + GFXDECODE_ENTRY(HD46505SP_TAG, 0x0000, gfx_8x8x1, 0, 1) +GFXDECODE_END + + +//------------------------------------------------- +// MACHINE_CONFIG_FRAGMENT( c64_xl80 ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( c64_xl80 ) + MCFG_SCREEN_ADD(MC6845_SCREEN_TAG, RASTER) + MCFG_SCREEN_UPDATE_DEVICE(HD46505SP_TAG, h46505_device, screen_update) + MCFG_SCREEN_SIZE(80*8, 24*8) + MCFG_SCREEN_VISIBLE_AREA(0, 80*8-1, 0, 24*8-1) + MCFG_SCREEN_REFRESH_RATE(50) + + MCFG_GFXDECODE_ADD("gfxdecode", "palette", c64_xl80) + MCFG_PALETTE_ADD_BLACK_AND_WHITE("palette") + + MCFG_MC6845_ADD(HD46505SP_TAG, H46505, MC6845_SCREEN_TAG, XTAL_14_31818MHz / 8) + MCFG_MC6845_SHOW_BORDER_AREA(true) + MCFG_MC6845_CHAR_WIDTH(8) + MCFG_MC6845_UPDATE_ROW_CB(c64_xl80_device, crtc_update_row) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor c64_xl80_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( c64_xl80 ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// c64_xl80_device - constructor +//------------------------------------------------- + +c64_xl80_device::c64_xl80_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, C64_XL80, "XL 80", tag, owner, clock, "c64_xl80", __FILE__), + device_c64_expansion_card_interface(mconfig, *this), + m_crtc(*this, HD46505SP_TAG), + m_palette(*this, "palette"), + m_char_rom(*this, HD46505SP_TAG), + m_ram(*this, "ram") +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void c64_xl80_device::device_start() +{ + // allocate memory + m_ram.allocate(RAM_SIZE); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void c64_xl80_device::device_reset() +{ +} + + +//------------------------------------------------- +// c64_cd_r - cartridge data read +//------------------------------------------------- + +UINT8 c64_xl80_device::c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (!io2 && BIT(offset, 2)) + { + if (offset & 0x01) + { + data = m_crtc->register_r(space, 0); + } + } + else if (offset >= 0x8000 && offset < 0x9000) + { + data = m_roml[offset & 0xfff]; + } + else if (offset >= 0x9800 && offset < 0xa000) + { + data = m_ram[offset & 0x7ff]; + } + + return data; +} + + +//------------------------------------------------- +// c64_cd_w - cartridge data write +//------------------------------------------------- + +void c64_xl80_device::c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (offset >= 0x9800 && offset < 0xa000) + { + m_ram[offset & 0x7ff] = data; + } + else if (!io2 && BIT(offset, 2)) + { + if (offset & 0x01) + { + m_crtc->register_w(space, 0, data); + } + else + { + m_crtc->address_w(space, 0, data); + } + } +} diff --git a/src/devices/bus/c64/xl80.h b/src/devices/bus/c64/xl80.h new file mode 100644 index 00000000000..38a90baf6b1 --- /dev/null +++ b/src/devices/bus/c64/xl80.h @@ -0,0 +1,64 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + XL 80 cartridge emulation + +**********************************************************************/ + +#pragma once + +#ifndef __XL80__ +#define __XL80__ + + +#include "emu.h" +#include "exp.h" +#include "video/mc6845.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> c64_xl80_device + +class c64_xl80_device : public device_t, + public device_c64_expansion_card_interface +{ +public: + // construction/destruction + c64_xl80_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + + // not really public + MC6845_UPDATE_ROW( crtc_update_row ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_c64_expansion_card_interface overrides + virtual UINT8 c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + virtual void c64_cd_w(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + virtual int c64_game_r(offs_t offset, int sphi2, int ba, int rw) { return 1; } + virtual int c64_exrom_r(offs_t offset, int sphi2, int ba, int rw) { return 0; } + +private: + required_device m_crtc; + required_device m_palette; + required_memory_region m_char_rom; + optional_shared_ptr m_ram; +}; + + +// device type definition +extern const device_type C64_XL80; + + +#endif diff --git a/src/devices/bus/c64/zaxxon.c b/src/devices/bus/c64/zaxxon.c new file mode 100644 index 00000000000..22ce1f35ce9 --- /dev/null +++ b/src/devices/bus/c64/zaxxon.c @@ -0,0 +1,66 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Zaxxon/Super Zaxxon cartridge emulation + +**********************************************************************/ + +#include "zaxxon.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type C64_ZAXXON = &device_creator; + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// c64_zaxxon_cartridge_device - constructor +//------------------------------------------------- + +c64_zaxxon_cartridge_device::c64_zaxxon_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, C64_ZAXXON, "C64 Zaxxon cartridge", tag, owner, clock, "c64_zaxxon", __FILE__), + device_c64_expansion_card_interface(mconfig, *this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void c64_zaxxon_cartridge_device::device_start() +{ + // state saving + save_item(NAME(m_bank)); +} + + +//------------------------------------------------- +// c64_cd_r - cartridge data read +//------------------------------------------------- + +UINT8 c64_zaxxon_cartridge_device::c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2) +{ + if (!roml) + { + data = m_roml[offset & 0xfff]; + + m_bank = BIT(offset, 12); + } + else if (!romh) + { + offs_t addr = (m_bank << 13) | (offset & 0x1fff); + data = m_romh[addr]; + } + + return data; +} diff --git a/src/devices/bus/c64/zaxxon.h b/src/devices/bus/c64/zaxxon.h new file mode 100644 index 00000000000..b5740605ef0 --- /dev/null +++ b/src/devices/bus/c64/zaxxon.h @@ -0,0 +1,49 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Zaxxon/Super Zaxxon cartridge emulation + +**********************************************************************/ + +#pragma once + +#ifndef __ZAXXON__ +#define __ZAXXON__ + + +#include "emu.h" +#include "exp.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> c64_zaxxon_cartridge_device + +class c64_zaxxon_cartridge_device : public device_t, + public device_c64_expansion_card_interface +{ +public: + // construction/destruction + c64_zaxxon_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // device-level overrides + virtual void device_start(); + + // device_c64_expansion_card_interface overrides + virtual UINT8 c64_cd_r(address_space &space, offs_t offset, UINT8 data, int sphi2, int ba, int roml, int romh, int io1, int io2); + +private: + int m_bank; +}; + + +// device type definition +extern const device_type C64_ZAXXON; + + +#endif diff --git a/src/devices/bus/cbm2/24k.c b/src/devices/bus/cbm2/24k.c new file mode 100644 index 00000000000..a31c58a7aaf --- /dev/null +++ b/src/devices/bus/cbm2/24k.c @@ -0,0 +1,88 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + GLA 24K RAM cartridge emulation + +**********************************************************************/ + +#include "24k.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type CBM2_24K = &device_creator; + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// cbm2_24k_cartridge_device - constructor +//------------------------------------------------- + +cbm2_24k_cartridge_device::cbm2_24k_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, CBM2_24K, "24K RAM/ROM cartridge", tag, owner, clock, "cbm2_24k", __FILE__), + device_cbm2_expansion_card_interface(mconfig, *this), + m_ram(*this, "ram") +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void cbm2_24k_cartridge_device::device_start() +{ + m_ram.allocate(0x6000); +} + + +//------------------------------------------------- +// cbm2_bd_r - cartridge data read +//------------------------------------------------- + +UINT8 cbm2_24k_cartridge_device::cbm2_bd_r(address_space &space, offs_t offset, UINT8 data, int csbank1, int csbank2, int csbank3) +{ + if (!csbank1) + { + data = m_ram[offset]; + } + else if (!csbank2) + { + data = m_ram[0x2000 | offset]; + } + else if (!csbank3) + { + data = m_ram[0x4000 | offset]; + } + + return data; +} + + +//------------------------------------------------- +// cbm2_bd_w - cartridge data write +//------------------------------------------------- + +void cbm2_24k_cartridge_device::cbm2_bd_w(address_space &space, offs_t offset, UINT8 data, int csbank1, int csbank2, int csbank3) +{ + if (!csbank1) + { + m_ram[offset] = data; + } + else if (!csbank2) + { + m_ram[0x2000 | offset] = data; + } + else if (!csbank3) + { + m_ram[0x4000 | offset] = data; + } +} diff --git a/src/devices/bus/cbm2/24k.h b/src/devices/bus/cbm2/24k.h new file mode 100644 index 00000000000..80dbc52046b --- /dev/null +++ b/src/devices/bus/cbm2/24k.h @@ -0,0 +1,48 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + GLA 24K RAM cartridge emulation + +**********************************************************************/ + +#pragma once + +#ifndef __CBM2_24K_CARTRIDGE__ +#define __CBM2_24K_CARTRIDGE__ + +#include "emu.h" +#include "exp.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> cbm2_24k_cartridge_device + +class cbm2_24k_cartridge_device : public device_t, + public device_cbm2_expansion_card_interface +{ +public: + // construction/destruction + cbm2_24k_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // device-level overrides + virtual void device_start(); + + // device_cbm2_expansion_card_interface overrides + virtual UINT8 cbm2_bd_r(address_space &space, offs_t offset, UINT8 data, int csbank1, int csbank2, int csbank3); + virtual void cbm2_bd_w(address_space &space, offs_t offset, UINT8 data, int csbank1, int csbank2, int csbank3); + + optional_shared_ptr m_ram; +}; + + +// device type definition +extern const device_type CBM2_24K; + + +#endif diff --git a/src/devices/bus/cbm2/exp.c b/src/devices/bus/cbm2/exp.c new file mode 100644 index 00000000000..f45dbc2caca --- /dev/null +++ b/src/devices/bus/cbm2/exp.c @@ -0,0 +1,206 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Commodore CBM-II Expansion Port emulation + +**********************************************************************/ + +#include "exp.h" + + + +//************************************************************************** +// MACROS/CONSTANTS +//************************************************************************** + +#define LOG 0 + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type CBM2_EXPANSION_SLOT = &device_creator; + + + +//************************************************************************** +// DEVICE CBM2_EXPANSION CARD INTERFACE +//************************************************************************** + +//------------------------------------------------- +// device_cbm2_expansion_card_interface - constructor +//------------------------------------------------- + +device_cbm2_expansion_card_interface::device_cbm2_expansion_card_interface(const machine_config &mconfig, device_t &device) + : device_slot_card_interface(mconfig, device), + m_bank1(*this, "bank1"), + m_bank2(*this, "bank2"), + m_bank3(*this, "bank3") +{ + m_slot = dynamic_cast(device.owner()); +} + + +//------------------------------------------------- +// ~device_cbm2_expansion_card_interface - destructor +//------------------------------------------------- + +device_cbm2_expansion_card_interface::~device_cbm2_expansion_card_interface() +{ +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// cbm2_expansion_slot_device - constructor +//------------------------------------------------- + +cbm2_expansion_slot_device::cbm2_expansion_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, CBM2_EXPANSION_SLOT, "CBM-II expansion port", tag, owner, clock, "cbm2_expansion_slot", __FILE__), + device_slot_interface(mconfig, *this), + device_image_interface(mconfig, *this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void cbm2_expansion_slot_device::device_start() +{ + m_card = dynamic_cast(get_card_device()); + + // inherit bus clock + if (clock() == 0) + { + cbm2_expansion_slot_device *root = machine().device(CBM2_EXPANSION_SLOT_TAG); + assert(root); + set_unscaled_clock(root->clock()); + } +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void cbm2_expansion_slot_device::device_reset() +{ +} + + +//------------------------------------------------- +// call_load - +//------------------------------------------------- + +bool cbm2_expansion_slot_device::call_load() +{ + size_t size = 0; + + if (m_card) + { + if (software_entry() == NULL) + { + size = length(); + + if (!core_stricmp(filetype(), "20")) + { + m_card->m_bank1.allocate(size); + fread(m_card->m_bank1, size); + } + else if (!core_stricmp(filetype(), "40")) + { + m_card->m_bank2.allocate(size); + fread(m_card->m_bank2, size); + } + else if (!core_stricmp(filetype(), "60")) + { + m_card->m_bank3.allocate(size); + fread(m_card->m_bank3, size); + } + } + else + { + load_software_region("bank1", m_card->m_bank1); + load_software_region("bank2", m_card->m_bank2); + load_software_region("bank3", m_card->m_bank3); + } + } + + return IMAGE_INIT_PASS; +} + + +//------------------------------------------------- +// call_softlist_load - +//------------------------------------------------- + +bool cbm2_expansion_slot_device::call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry) +{ + load_software_part_region(*this, swlist, swname, start_entry); + + return true; +} + + +//------------------------------------------------- +// get_default_card_software - +//------------------------------------------------- + +void cbm2_expansion_slot_device::get_default_card_software(std::string &result) +{ + software_get_default_slot(result, "standard"); +} + + +//------------------------------------------------- +// read - cartridge data read +//------------------------------------------------- + +UINT8 cbm2_expansion_slot_device::read(address_space &space, offs_t offset, UINT8 data, int csbank1, int csbank2, int csbank3) +{ + if (m_card != NULL) + { + data = m_card->cbm2_bd_r(space, offset, data, csbank1, csbank2, csbank3); + } + + return data; +} + + +//------------------------------------------------- +// write - cartridge data write +//------------------------------------------------- + +void cbm2_expansion_slot_device::write(address_space &space, offs_t offset, UINT8 data, int csbank1, int csbank2, int csbank3) +{ + if (m_card != NULL) + { + m_card->cbm2_bd_w(space, offset, data, csbank1, csbank2, csbank3); + } +} + + +//------------------------------------------------- +// SLOT_INTERFACE( cbm2_expansion_cards ) +//------------------------------------------------- + +// slot devices +#include "24k.h" +#include "hrg.h" +#include "std.h" + +SLOT_INTERFACE_START( cbm2_expansion_cards ) + SLOT_INTERFACE("24k", CBM2_24K) + SLOT_INTERFACE("hrga", CBM2_HRG_A) + SLOT_INTERFACE("hrgb", CBM2_HRG_B) + SLOT_INTERFACE_INTERNAL("standard", CBM2_STD) +SLOT_INTERFACE_END diff --git a/src/devices/bus/cbm2/exp.h b/src/devices/bus/cbm2/exp.h new file mode 100644 index 00000000000..338e4ad1cda --- /dev/null +++ b/src/devices/bus/cbm2/exp.h @@ -0,0 +1,136 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Commodore CBM-II Expansion Port emulation + +********************************************************************** + + A0 1 A BD0 + A1 2 B BD1 + A2 3 C BD2 + A3 4 D BD3 + A4 5 E BD4 + A5 6 F BD5 + A6 7 H BD6 + A7 8 J BD7 + A8 9 K GND + A9 10 L GND + A10 11 M SR/_W + A11 12 N Sphi2 + A12 13 P _CSBANK1 + +5V 14 R _CSBANK2 + +5V 15 S _CSBANK2 + +**********************************************************************/ + +#pragma once + +#ifndef __CBM2_EXPANSION_SLOT__ +#define __CBM2_EXPANSION_SLOT__ + +#include "emu.h" + + + +//************************************************************************** +// CONSTANTS +//************************************************************************** + +#define CBM2_EXPANSION_SLOT_TAG "exp" + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_CBM2_EXPANSION_SLOT_ADD(_tag, _clock, _slot_intf, _def_slot) \ + MCFG_DEVICE_ADD(_tag, CBM2_EXPANSION_SLOT, _clock) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> cbm2_expansion_slot_device + +class device_cbm2_expansion_card_interface; + +class cbm2_expansion_slot_device : public device_t, + public device_slot_interface, + public device_image_interface +{ +public: + // construction/destruction + cbm2_expansion_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // computer interface + UINT8 read(address_space &space, offs_t offset, UINT8 data, int csbank1, int csbank2, int csbank3); + void write(address_space &space, offs_t offset, UINT8 data, int csbank1, int csbank2, int csbank3); + + // cartridge interface + int phi2() { return clock(); } + +protected: + // device-level overrides + virtual void device_config_complete() { update_names(); } + virtual void device_start(); + virtual void device_reset(); + + // image-level overrides + virtual bool call_load(); + virtual bool call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry); + + virtual iodevice_t image_type() const { return IO_CARTSLOT; } + + virtual bool is_readable() const { return 1; } + virtual bool is_writeable() const { return 0; } + virtual bool is_creatable() const { return 0; } + virtual bool must_be_loaded() const { return 0; } + virtual bool is_reset_on_load() const { return 1; } + virtual const char *image_interface() const { return "cbm2_cart"; } + virtual const char *file_extensions() const { return "20,40,60"; } + virtual const option_guide *create_option_guide() const { return NULL; } + + // slot interface overrides + virtual void get_default_card_software(std::string &result); + + device_cbm2_expansion_card_interface *m_card; +}; + + +// ======================> device_cbm2_expansion_card_interface + +class device_cbm2_expansion_card_interface : public device_slot_card_interface +{ + friend class cbm2_expansion_slot_device; + +public: + // construction/destruction + device_cbm2_expansion_card_interface(const machine_config &mconfig, device_t &device); + virtual ~device_cbm2_expansion_card_interface(); + + virtual UINT8 cbm2_bd_r(address_space &space, offs_t offset, UINT8 data, int csbank1, int csbank2, int csbank3) { return data; }; + virtual void cbm2_bd_w(address_space &space, offs_t offset, UINT8 data, int csbank1, int csbank2, int csbank3) { }; + +protected: + optional_shared_ptr m_bank1; + optional_shared_ptr m_bank2; + optional_shared_ptr m_bank3; + + cbm2_expansion_slot_device *m_slot; +}; + + +// device type definition +extern const device_type CBM2_EXPANSION_SLOT; + + +SLOT_INTERFACE_EXTERN( cbm2_expansion_cards ); + + + +#endif diff --git a/src/devices/bus/cbm2/hrg.c b/src/devices/bus/cbm2/hrg.c new file mode 100644 index 00000000000..cb489ec359f --- /dev/null +++ b/src/devices/bus/cbm2/hrg.c @@ -0,0 +1,231 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + CBM 500/600/700 High Resolution Graphics cartridge emulation + +**********************************************************************/ + +/* + + TODO: + + http://www.wfking.de/hires.htm + + - version A (EF9365, 512x512 interlaced, 1 page) + - version B (EF9366, 512x256 non-interlaced, 2 pages) + +*/ + +#include "hrg.h" + + + +//************************************************************************** +// MACROS/CONSTANTS +//************************************************************************** + +#define EF9365_TAG "ef9365" +#define EF9366_TAG "ef9366" +#define SCREEN_TAG "screen" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type CBM2_HRG_A = &device_creator; +const device_type CBM2_HRG_B = &device_creator; + + +//------------------------------------------------- +// ROM( cbm2_hrg ) +//------------------------------------------------- + +ROM_START( cbm2_hrg ) + ROM_REGION( 0x2000, "bank3", 0 ) + ROM_LOAD( "324688-01 sw gr 600.bin", 0x0000, 0x2000, CRC(863e9ef8) SHA1(d75ffa97b2dd4e1baefe4acaa130daae866ab0e8) ) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *cbm2_graphic_cartridge_device::device_rom_region() const +{ + return ROM_NAME( cbm2_hrg ); +} + + +//------------------------------------------------- +// MACHINE_CONFIG_FRAGMENT( cbm2_hrg_a ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( cbm2_hrg_a ) +/* MCFG_SCREEN_ADD(SCREEN_TAG, RASTER) + MCFG_SCREEN_UPDATE_DEVICE(EF9365_TAG, ef9365_device, screen_update) + MCFG_SCREEN_SIZE(512, 512) + MCFG_SCREEN_VISIBLE_AREA(0, 512-1, 0, 512-1) + MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(2500)) + MCFG_SCREEN_REFRESH_RATE(50) + + MCFG_EF9365_ADD(EF9365_TAG, gdp_intf)*/ +MACHINE_CONFIG_END + + +//------------------------------------------------- +// MACHINE_CONFIG_FRAGMENT( cbm2_hrg_b ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( cbm2_hrg_b ) +/* MCFG_SCREEN_ADD(SCREEN_TAG, RASTER) + MCFG_SCREEN_UPDATE_DEVICE(EF9366_TAG, ef9366_device, screen_update) + MCFG_SCREEN_SIZE(512, 256) + MCFG_SCREEN_VISIBLE_AREA(0, 512-1, 0, 256-1) + MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(2500)) + MCFG_SCREEN_REFRESH_RATE(50) + + MCFG_EF9366_ADD(EF9366_TAG, gdp_intf)*/ +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor cbm2_graphic_cartridge_a_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( cbm2_hrg_a ); +} + +machine_config_constructor cbm2_graphic_cartridge_b_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( cbm2_hrg_b ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// cbm2_graphic_cartridge_device - constructor +//------------------------------------------------- + +cbm2_graphic_cartridge_device::cbm2_graphic_cartridge_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_cbm2_expansion_card_interface(mconfig, *this), + m_bank3(*this, "bank3") +{ +} + +cbm2_graphic_cartridge_a_device::cbm2_graphic_cartridge_a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + cbm2_graphic_cartridge_device(mconfig, CBM2_HRG_A, "CBM 500/600/700 High Resolution Graphics (A)", tag, owner, clock, "cbm2_hrga", __FILE__) + //m_gdc(*this, EF9365_TAG) +{ +} + +cbm2_graphic_cartridge_b_device::cbm2_graphic_cartridge_b_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + cbm2_graphic_cartridge_device(mconfig, CBM2_HRG_B, "CBM 500/600/700 High Resolution Graphics (B)", tag, owner, clock, "cbm2_hrgb", __FILE__) + //m_gdc(*this, EF9366_TAG) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void cbm2_graphic_cartridge_device::device_start() +{ +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void cbm2_graphic_cartridge_device::device_reset() +{ + //m_gdc->reset(); +} + + +//------------------------------------------------- +// cbm2_bd_r - cartridge data read +//------------------------------------------------- + +UINT8 cbm2_graphic_cartridge_device::cbm2_bd_r(address_space &space, offs_t offset, UINT8 data, int csbank1, int csbank2, int csbank3) +{ + if (!csbank3) + { + if (offset < 0x7f80) + { + data = m_bank3->base()[offset & 0x1fff]; + } + else if (offset == 0x7f90) + { + /* + + bit description + + 0 light pen + 1 + 2 + 3 + 4 + 5 + 6 + 7 + + */ + } + else if (offset == 0x7fb0) + { + // hard copy + } + else if (offset >= 0x7ff0) + { + //data = m_gdc->data_r(space, offset & 0x07); + } + } + + return data; +} + + +//------------------------------------------------- +// cbm2_bd_w - cartridge data write +//------------------------------------------------- + +void cbm2_graphic_cartridge_device::cbm2_bd_w(address_space &space, offs_t offset, UINT8 data, int csbank1, int csbank2, int csbank3) +{ + if (!csbank3) + { + if (offset == 0x7f80) + { + /* + + bit description + + 0 hard copy (0=active) + 1 operating page select (version B) + 2 + 3 read-modify-write (1=active) + 4 display switch (1=graphic) + 5 display page select (version B) + 6 + 7 + + */ + } + else if (offset >= 0x7ff0) + { + //m_gdc->data_w(space, offset & 0x07, data); + } + } +} diff --git a/src/devices/bus/cbm2/hrg.h b/src/devices/bus/cbm2/hrg.h new file mode 100644 index 00000000000..91892274fc1 --- /dev/null +++ b/src/devices/bus/cbm2/hrg.h @@ -0,0 +1,83 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + CBM 500/600/700 High Resolution Graphics cartridge emulation + +**********************************************************************/ + +#pragma once + +#ifndef __CBM2_GRAPHIC__ +#define __CBM2_GRAPHIC__ + +#include "emu.h" +#include "exp.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> cbm2_graphic_cartridge_device + +class cbm2_graphic_cartridge_device : public device_t, + public device_cbm2_expansion_card_interface +{ +public: + // construction/destruction + cbm2_graphic_cartridge_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + cbm2_graphic_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_cbm2_expansion_card_interface overrides + virtual UINT8 cbm2_bd_r(address_space &space, offs_t offset, UINT8 data, int csbank1, int csbank2, int csbank3); + virtual void cbm2_bd_w(address_space &space, offs_t offset, UINT8 data, int csbank1, int csbank2, int csbank3); + +private: + //required_device m_gdc; + required_memory_region m_bank3; +}; + + +// ======================> cbm2_graphic_cartridge_a_device + +class cbm2_graphic_cartridge_a_device : public cbm2_graphic_cartridge_device +{ +public: + // construction/destruction + cbm2_graphic_cartridge_a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; +}; + + +// ======================> cbm2_graphic_cartridge_b_device + +class cbm2_graphic_cartridge_b_device : public cbm2_graphic_cartridge_device +{ +public: + // construction/destruction + cbm2_graphic_cartridge_b_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; +}; + + +// device type definition +extern const device_type CBM2_HRG_A; +extern const device_type CBM2_HRG_B; + + + +#endif diff --git a/src/devices/bus/cbm2/std.c b/src/devices/bus/cbm2/std.c new file mode 100644 index 00000000000..e6e697927dc --- /dev/null +++ b/src/devices/bus/cbm2/std.c @@ -0,0 +1,65 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Commodore CBM-II Standard cartridge emulation + +**********************************************************************/ + +#include "std.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type CBM2_STD = &device_creator; + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// cbm2_standard_cartridge_device - constructor +//------------------------------------------------- + +cbm2_standard_cartridge_device::cbm2_standard_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, CBM2_STD, "CBM-II standard cartridge", tag, owner, clock, "cbm2_standard", __FILE__), + device_cbm2_expansion_card_interface(mconfig, *this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void cbm2_standard_cartridge_device::device_start() +{ +} + + +//------------------------------------------------- +// cbm2_bd_r - cartridge data read +//------------------------------------------------- + +UINT8 cbm2_standard_cartridge_device::cbm2_bd_r(address_space &space, offs_t offset, UINT8 data, int csbank1, int csbank2, int csbank3) +{ + if (!csbank1 && m_bank1.bytes()) + { + data = m_bank1[offset & m_bank1.mask()]; + } + else if (!csbank2 && m_bank2.bytes()) + { + data = m_bank2[offset & m_bank2.mask()]; + } + else if (!csbank3 && m_bank3.bytes()) + { + data = m_bank3[offset & m_bank3.mask()]; + } + + return data; +} diff --git a/src/devices/bus/cbm2/std.h b/src/devices/bus/cbm2/std.h new file mode 100644 index 00000000000..8dee67b9c11 --- /dev/null +++ b/src/devices/bus/cbm2/std.h @@ -0,0 +1,45 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Commodore CBM-II Standard cartridge emulation + +**********************************************************************/ + +#pragma once + +#ifndef __CBM2_STANDARD_CARTRIDGE__ +#define __CBM2_STANDARD_CARTRIDGE__ + +#include "emu.h" +#include "exp.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> cbm2_standard_cartridge_device + +class cbm2_standard_cartridge_device : public device_t, + public device_cbm2_expansion_card_interface +{ +public: + // construction/destruction + cbm2_standard_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // device-level overrides + virtual void device_start(); + + // device_cbm2_expansion_card_interface overrides + virtual UINT8 cbm2_bd_r(address_space &space, offs_t offset, UINT8 data, int csbank1, int csbank2, int csbank3); +}; + + +// device type definition +extern const device_type CBM2_STD; + + +#endif diff --git a/src/devices/bus/cbm2/user.c b/src/devices/bus/cbm2/user.c new file mode 100644 index 00000000000..6383f39b061 --- /dev/null +++ b/src/devices/bus/cbm2/user.c @@ -0,0 +1,77 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Commodore CBM-II User Port emulation + +**********************************************************************/ + +#include "user.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type CBM2_USER_PORT = &device_creator; + + + +//************************************************************************** +// CARD INTERFACE +//************************************************************************** + +//------------------------------------------------- +// device_cbm2_user_port_interface - constructor +//------------------------------------------------- + +device_cbm2_user_port_interface::device_cbm2_user_port_interface(const machine_config &mconfig, device_t &device) : + device_slot_card_interface(mconfig,device) +{ + m_slot = dynamic_cast(device.owner()); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// cbm2_user_port_device - constructor +//------------------------------------------------- + +cbm2_user_port_device::cbm2_user_port_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, CBM2_USER_PORT, "CBM2 user port", tag, owner, clock, "cbm2_user_port", __FILE__), + device_slot_interface(mconfig, *this), + m_write_irq(*this), + m_write_sp(*this), + m_write_cnt(*this), + m_write_flag(*this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void cbm2_user_port_device::device_start() +{ + m_card = dynamic_cast(get_card_device()); + + // resolve callbacks + m_write_irq.resolve_safe(); + m_write_sp.resolve_safe(); + m_write_cnt.resolve_safe(); + m_write_flag.resolve_safe(); +} + + +//------------------------------------------------- +// SLOT_INTERFACE( cbm2_user_port_cards ) +//------------------------------------------------- + +SLOT_INTERFACE_START( cbm2_user_port_cards ) +SLOT_INTERFACE_END diff --git a/src/devices/bus/cbm2/user.h b/src/devices/bus/cbm2/user.h new file mode 100644 index 00000000000..7952517ed05 --- /dev/null +++ b/src/devices/bus/cbm2/user.h @@ -0,0 +1,157 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Commodore CBM-II User Port emulation + +********************************************************************** + + GND 1 14 2D0 + PB2 2 15 1D7 + GND 3 16 1D6 + PB3 4 17 1D5 + PC 5 18 1D4 + FLAG 6 19 1D3 + 2D7 7 20 1D2 + 2D6 8 21 1D1 + 2D5 9 22 1D0 + 2D4 10 23 CNT + 2D3 11 24 +5V + 2D2 12 25 IRQ + 2D1 13 26 SP + +**********************************************************************/ + +#pragma once + +#ifndef __CBM2_USER_PORT__ +#define __CBM2_USER_PORT__ + +#include "emu.h" + + + +//************************************************************************** +// CONSTANTS +//************************************************************************** + +#define CBM2_USER_PORT_TAG "user" + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_CBM2_USER_PORT_ADD(_tag, _slot_intf, _def_slot) \ + MCFG_DEVICE_ADD(_tag, CBM2_USER_PORT, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) + + +#define MCFG_CBM2_USER_PORT_IRQ_CALLBACK(_write) \ + devcb = &cbm2_user_port_device::set_irq_wr_callback(*device, DEVCB_##_write); + +#define MCFG_CBM2_USER_PORT_SP_CALLBACK(_write) \ + devcb = &cbm2_user_port_device::set_sp_wr_callback(*device, DEVCB_##_write); + +#define MCFG_CBM2_USER_PORT_CNT_CALLBACK(_write) \ + devcb = &cbm2_user_port_device::set_cnt_wr_callback(*device, DEVCB_##_write); + +#define MCFG_CBM2_USER_PORT_FLAG_CALLBACK(_write) \ + devcb = &cbm2_user_port_device::set_flag_wr_callback(*device, DEVCB_##_write); + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class cbm2_user_port_device; + +// ======================> device_cbm2_user_port_interface + +// class representing interface-specific live cbm2_expansion card +class device_cbm2_user_port_interface : public device_slot_card_interface +{ +public: + // construction/destruction + device_cbm2_user_port_interface(const machine_config &mconfig, device_t &device); + virtual ~device_cbm2_user_port_interface() { } + + virtual UINT8 cbm2_d1_r(address_space &space, offs_t offset) { return 0xff; }; + virtual void cbm2_d1_w(address_space &space, offs_t offset, UINT8 data) { }; + + virtual UINT8 cbm2_d2_r(address_space &space, offs_t offset) { return 0xff; }; + virtual void cbm2_d2_w(address_space &space, offs_t offset, UINT8 data) { }; + + virtual int cbm2_pb2_r() { return 1; } + virtual void cbm2_pb2_w(int state) { }; + virtual int cbm2_pb3_r() { return 1; } + virtual void cbm2_pb3_w(int state) { }; + + virtual void cbm2_pc_w(int state) { }; + virtual void cbm2_cnt_w(int state) { }; + virtual void cbm2_sp_w(int state) { }; + +protected: + cbm2_user_port_device *m_slot; +}; + + +// ======================> cbm2_user_port_device + +class cbm2_user_port_device : public device_t, + public device_slot_interface +{ +public: + // construction/destruction + cbm2_user_port_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual ~cbm2_user_port_device() { } + + template static devcb_base &set_irq_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_irq.set_callback(object); } + template static devcb_base &set_sp_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_sp.set_callback(object); } + template static devcb_base &set_cnt_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_cnt.set_callback(object); } + template static devcb_base &set_flag_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_flag.set_callback(object); } + + // computer interface + DECLARE_READ8_MEMBER( d1_r ) { UINT8 data = 0xff; if (m_card != NULL) data = m_card->cbm2_d1_r(space, offset); return data; } + DECLARE_WRITE8_MEMBER( d1_w ) { if (m_card != NULL) m_card->cbm2_d1_w(space, offset, data); } + DECLARE_READ8_MEMBER( d2_r ) { UINT8 data = 0xff; if (m_card != NULL) data = m_card->cbm2_d2_r(space, offset); return data; } + DECLARE_WRITE8_MEMBER( d2_w ) { if (m_card != NULL) m_card->cbm2_d2_w(space, offset, data); } + DECLARE_READ_LINE_MEMBER( pb2_r ) { return m_card ? m_card->cbm2_pb2_r() : 1; } + DECLARE_WRITE_LINE_MEMBER( pb2_w ) { if (m_card != NULL) m_card->cbm2_pb2_w(state); } + DECLARE_READ_LINE_MEMBER( pb3_r ) { return m_card ? m_card->cbm2_pb3_r() : 1; } + DECLARE_WRITE_LINE_MEMBER( pb3_w ) { if (m_card != NULL) m_card->cbm2_pb3_w(state); } + DECLARE_WRITE_LINE_MEMBER( pc_w ) { if (m_card != NULL) m_card->cbm2_pc_w(state); } + DECLARE_WRITE_LINE_MEMBER( cnt_w ) { if (m_card != NULL) m_card->cbm2_cnt_w(state); } + DECLARE_WRITE_LINE_MEMBER( sp_w ) { if (m_card != NULL) m_card->cbm2_sp_w(state); } + + // cartridge interface + DECLARE_WRITE_LINE_MEMBER( irq_w ) { m_write_irq(state); } + DECLARE_WRITE_LINE_MEMBER( cia_sp_w ) { m_write_sp(state); } + DECLARE_WRITE_LINE_MEMBER( cia_cnt_w ) { m_write_cnt(state); } + DECLARE_WRITE_LINE_MEMBER( flag_w ) { m_write_flag(state); } + +protected: + // device-level overrides + virtual void device_start(); + + devcb_write_line m_write_irq; + devcb_write_line m_write_sp; + devcb_write_line m_write_cnt; + devcb_write_line m_write_flag; + + device_cbm2_user_port_interface *m_card; +}; + + +// device type definition +extern const device_type CBM2_USER_PORT; + + +// slot devices +SLOT_INTERFACE_EXTERN( cbm2_user_port_cards ); + + + +#endif diff --git a/src/devices/bus/cbmiec/c1526.c b/src/devices/bus/cbmiec/c1526.c new file mode 100644 index 00000000000..da2cf7197c0 --- /dev/null +++ b/src/devices/bus/cbmiec/c1526.c @@ -0,0 +1,269 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Commodore 1526/MPS-802/4023 Printer emulation + +**********************************************************************/ + +#include "c1526.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define M6504_TAG "u7d" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type C1526 = &device_creator; +const device_type MPS802 = &device_creator; +const device_type C4023 = &device_creator; + + +//------------------------------------------------- +// ROM( c1526 ) +//------------------------------------------------- + +ROM_START( c1526 ) + ROM_REGION( 0x2000, M6504_TAG, 0 ) + ROM_SYSTEM_BIOS( 0, "r05", "Revision 5" ) + ROMX_LOAD( "325341-05.u8d", 0x0000, 0x2000, CRC(3ef63c59) SHA1(a71be83a476d2777d33dddb0103c036a047975ba), ROM_BIOS(1) ) + ROM_SYSTEM_BIOS( 1, "r07c", "Revision 7c" ) + ROMX_LOAD( "325341-08.u8d", 0x0000, 0x2000, CRC(38f85b4a) SHA1(25880091979b21fdaf713b53ef2f1cb8063a3505), ROM_BIOS(2) ) + ROM_SYSTEM_BIOS( 2, "r07b", "Revision 7b (Swe/Fin)" ) + ROMX_LOAD( "cbm 1526 vers. 1.0 skand.gen.u8d", 0x0000, 0x2000, CRC(21051f69) SHA1(7e622fc39985ebe9333d2b546b3c85fd6ab17a53), ROM_BIOS(3) ) + ROM_SYSTEM_BIOS( 3, "grafik", "MPS802 GrafikROM II v60.12" ) + ROMX_LOAD( "mps802 grafikrom ii v60.12.u8d", 0x0000, 0x2000, CRC(9f5e6b18) SHA1(8b7f620a8f85e250b142d72b812a67fd0e292d68), ROM_BIOS(4) ) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *c1526_t::device_rom_region() const +{ + return ROM_NAME( c1526 ); +} + + +//------------------------------------------------- +// ROM( c4023 ) +//------------------------------------------------- + +ROM_START( c4023 ) + ROM_REGION( 0x2000, M6504_TAG, 0 ) + ROM_LOAD( "325360-03.u8d", 0x0000, 0x2000, CRC(c6bb0977) SHA1(7a8c43d2e205f58d83709c04bc7795602a892ddd) ) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *c4023_t::device_rom_region() const +{ + return ROM_NAME( c4023 ); +} + + +//------------------------------------------------- +// ADDRESS_MAP( c1526_mem ) +//------------------------------------------------- + +static ADDRESS_MAP_START( c1526_mem, AS_PROGRAM, 8, c1526_base_t ) + AM_RANGE(0xe000, 0xffff) AM_ROM AM_REGION(M6504_TAG, 0) +ADDRESS_MAP_END + + +//------------------------------------------------- +// MACHINE_DRIVER( c1526 ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( c1526 ) + MCFG_CPU_ADD(M6504_TAG, M6504, XTAL_4MHz/4) + MCFG_CPU_PROGRAM_MAP(c1526_mem) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor c1526_t::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( c1526 ); +} + + +//------------------------------------------------- +// MACHINE_DRIVER( c4023 ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( c4023 ) + MCFG_CPU_ADD(M6504_TAG, M6504, XTAL_4MHz/4) + MCFG_CPU_PROGRAM_MAP(c1526_mem) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor c4023_t::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( c4023 ); +} + + +//------------------------------------------------- +// INPUT_PORTS( c1526 ) +//------------------------------------------------- + +static INPUT_PORTS_START( c1526 ) +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor c1526_t::device_input_ports() const +{ + return INPUT_PORTS_NAME( c1526 ); +} + + +//------------------------------------------------- +// INPUT_PORTS( c4023 ) +//------------------------------------------------- + +static INPUT_PORTS_START( c4023 ) +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor c4023_t::device_input_ports() const +{ + return INPUT_PORTS_NAME( c4023 ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// c1526_base_t - constructor +//------------------------------------------------- + +c1526_base_t:: c1526_base_t(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source) +{ +} + + +//------------------------------------------------- +// c1526_t - constructor +//------------------------------------------------- + +c1526_t::c1526_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + c1526_base_t(mconfig, C1526, "1526", tag, owner, clock, "c1526", __FILE__), + device_cbm_iec_interface(mconfig, *this) +{ +} + + +//------------------------------------------------- +// c4023_t - constructor +//------------------------------------------------- + +c4023_t::c4023_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + c1526_base_t(mconfig, C4023, "4023", tag, owner, clock, "c4023", __FILE__), + device_ieee488_interface(mconfig, *this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void c1526_base_t::device_start() +{ +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void c1526_base_t::device_reset() +{ +} + + +//------------------------------------------------- +// cbm_iec_atn - +//------------------------------------------------- + +void c1526_t::cbm_iec_atn(int state) +{ +} + + +//------------------------------------------------- +// cbm_iec_data - +//------------------------------------------------- + +void c1526_t::cbm_iec_data(int state) +{ +} + + +//------------------------------------------------- +// cbm_iec_reset - +//------------------------------------------------- + +void c1526_t::cbm_iec_reset(int state) +{ + if (!state) + { + device_reset(); + } +} + + +//------------------------------------------------- +// ieee488_atn_w - +//------------------------------------------------- + +void c4023_t::ieee488_atn(int state) +{ +} + + +//------------------------------------------------- +// ieee488_ifc_w - +//------------------------------------------------- + +void c4023_t::ieee488_ifc(int state) +{ + if (!state) + { + device_reset(); + } +} diff --git a/src/devices/bus/cbmiec/c1526.h b/src/devices/bus/cbmiec/c1526.h new file mode 100644 index 00000000000..c6389bf4662 --- /dev/null +++ b/src/devices/bus/cbmiec/c1526.h @@ -0,0 +1,90 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Commodore 1526/MPS-802/4023 Printer emulation + +**********************************************************************/ + +#pragma once + +#ifndef __C1526__ +#define __C1526__ + +#include "emu.h" +#include "cbmiec.h" +#include "bus/ieee488/ieee488.h" +#include "cpu/m6502/m6504.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> c1526_base_t + +class c1526_base_t : public device_t +{ +public: + // construction/destruction + c1526_base_t(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); +}; + + +// ======================> c1526_t + +class c1526_t : public c1526_base_t, + public device_cbm_iec_interface +{ +public: + // construction/destruction + c1526_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual ioport_constructor device_input_ports() const; + virtual const rom_entry *device_rom_region() const; + +protected: + // device_cbm_iec_interface overrides + void cbm_iec_atn(int state); + void cbm_iec_data(int state); + void cbm_iec_reset(int state); +}; + + +// ======================> c4023_t + +class c4023_t : public c1526_base_t, + public device_ieee488_interface +{ +public: + // construction/destruction + c4023_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual ioport_constructor device_input_ports() const; + virtual const rom_entry *device_rom_region() const; + +protected: + // device_ieee488_interface overrides + virtual void ieee488_atn(int state); + virtual void ieee488_ifc(int state); +}; + + +// device type definition +extern const device_type C1526; +extern const device_type MPS802; +extern const device_type C4023; + + + +#endif diff --git a/src/devices/bus/cbmiec/c1541.c b/src/devices/bus/cbmiec/c1541.c new file mode 100644 index 00000000000..054c6e27120 --- /dev/null +++ b/src/devices/bus/cbmiec/c1541.c @@ -0,0 +1,1211 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Commodore 1540/1541/1541C/1541-II Single Disk Drive emulation + +**********************************************************************/ + +/* + + TODO: + + - c1540 fails to load the directory intermittently + + - hardware extensions + - Dolphin-DOS 2.0 + - Dolphin-DOS 3.0 + - Professional-DOS + - Prologic-DOS + +*/ + +/* + + 1540/1541/1541A/SX-64 Parts + + Location Part Number Description + 2016 2K x 8 bit Static RAM (short board) + UA2-UB3 2114 (4) 1K x 4 bit Static RAM (long board) + 325572-01 64H105 40 pin Gate Array (short board) + 325302-01 2364-130 ROM DOS 2.6 C000-DFFF + 325303-01 2364-131 ROM DOS 2.6 (1540) E000-FFFF + 901229-01 2364-173 ROM DOS 2.6 rev. 0 E000-FFFF + 901229-03 2364-197 ROM DOS 2.6 rev. 1 E000-FFFF + 901229-05 8K ROM DOS 2.6 rev. 2 E000-FFFF + 6502 CPU + 6522 (2) VIA + drive Alps DFB111M25A + drive Alps FDM2111-B2 + drive Newtronics D500 + + 1541B/1541C Parts + + Location Part Number Description + UA3 2016 2K x 8 bit Static RAM + UC2 6502 CPU + UC1, UC3 6522 (2) CIA + UC4 251828-02 64H156 42 pin Gate Array + UC5 251829-01 64H157 20 pin Gate Array + UD1 * 251853-01 R/W Hybrid + UD1 * 251853-02 R/W Hybrid + UA2 251968-01 27128 EPROM DOS 2.6 rev. 3 C000-FFFF + drive Newtronics D500 + * Not interchangeable. + + 1541-II Parts + + Location Part Number Description + U5 2016-15 2K x 8 bit Static RAM + U12 SONY CX20185 R/W Amp. + U3 6502A CPU + U6, U8 6522 (2) CIA + U10 251828-01 64H156 40 pin Gate Array + U4 251968-03 16K ROM DOS 2.6 rev. 4 C000-FFFF + drive Chinon FZ-501M REV A + drive Digital System DS-50F + drive Newtronics D500 + drive Safronic DS-50F + + ... + + PCB Assy # 1540008-01 + Schematic # 1540001 + Original "Long" Board + Has 4 discreet 2114 RAMs + ALPS Drive only + + PCB Assy # 1540048 + Schematic # 1540049 + Referred to as the CR board + Changed to 2048 x 8 bit RAM pkg. + A 40 pin Gate Array is used + Alps Drive (-01) + Newtronics Drive (-03) + + PCB Assy # 250442-01 + Schematic # 251748 + Termed the 1541 A + Just one jumper change to accommodate both types of drive + + PCB Assy # 250446-01 + Schematic # 251748 (See Notes) + Termed the 1541 A-2 + Just one jumper change to accommodate both types of drive + + ... + + VIC1541 1540001-01 Very early version, long board. + 1540001-03 As above, only the ROMs are different. + 1540008-01 + + 1541 1540048-01 Shorter board with a 40 pin gate array, Alps mech. + 1540048-03 As above, but Newtronics mech. + 1540049 Similar to above + 1540050 Similar to above, Alps mechanism. + + SX64 250410-01 Design most similar to 1540048-01, Alps mechanism. + + 1541 251777 Function of bridge rects. reversed, Newtronics mech. + 251830 Same as above + + 1541A 250442-01 Alps or Newtronics drive selected by a jumper. + 1541A2 250446-01 A 74LS123 replaces the 9602 at UD4. + 1541B 250448-01 Same as the 1541C, but in a case like the 1541. + 1541C 250448-01 Short board, new 40/42 pin gate array, 20 pin gate + array and a R/W hybrid chip replace many components. + Uses a Newtronics drive with optical trk 0 sensor. + 1541C 251854 As above, single DOS ROM IC, trk 0 sensor, 30 pin + IC for R/W ampl & stepper motor control (like 1541). + + 1541-II A complete redesign using the 40 pin gate array + from the 1451C and a Sony R/W hybrid, but not the + 20 pin gate array, single DOS ROM IC. + + NOTE: These system boards are the 60 Hz versions. + The -02 and -04 boards are probably the 50 Hz versions. + + The ROMs appear to be completely interchangeable. For instance, the + first version of ROM for the 1541-II contained the same code as the + last version of the 1541. I copy the last version of the 1541-II ROM + into two 68764 EPROMs and use them in my original 1541 (long board). + Not only do they work, but they work better than the originals. + + + http://www.amiga-stuff.com/hardware/cbmboards.html + +*/ + +#include "c1541.h" +#include "bus/centronics/ctronics.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define M6502_TAG "ucd5" +#define M6522_0_TAG "uab1" +#define M6522_1_TAG "ucd4" +#define C64H156_TAG "uc4" +#define C64H157_TAG "uc5" + +#define MC6821_TAG "pia" +#define CENTRONICS_TAG "centronics" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type C1540 = &device_creator; +const device_type C1541 = &device_creator; +const device_type C1541C = &device_creator; +const device_type C1541II = &device_creator; +const device_type SX1541 = &device_creator; +const device_type FSD1 = &device_creator; +const device_type FSD2 = &device_creator; +const device_type CSD1 = &device_creator; +const device_type C1541_DOLPHIN_DOS = &device_creator; +const device_type C1541_PROFESSIONAL_DOS_V1 = &device_creator; +const device_type C1541_PROLOGIC_DOS_CLASSIC = &device_creator; +const device_type INDUS_GT = &device_creator; + + +//------------------------------------------------- +// ROM( c1540 ) +//------------------------------------------------- + +ROM_START( c1540 ) + ROM_REGION( 0x4000, M6502_TAG, 0 ) + ROM_LOAD( "325302-01.uab4", 0x0000, 0x2000, CRC(29ae9752) SHA1(8e0547430135ba462525c224e76356bd3d430f11) ) + ROM_LOAD( "325303-01.uab5", 0x2000, 0x2000, CRC(10b39158) SHA1(56dfe79b26f50af4e83fd9604857756d196516b9) ) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *c1540_t::device_rom_region() const +{ + return ROM_NAME( c1540 ); +} + + +//------------------------------------------------- +// ROM( c1541 ) +//------------------------------------------------- + +ROM_START( c1541 ) + ROM_REGION( 0x8000, M6502_TAG, 0 ) + ROM_LOAD( "325302-01.uab4", 0x0000, 0x2000, CRC(29ae9752) SHA1(8e0547430135ba462525c224e76356bd3d430f11) ) + + ROM_DEFAULT_BIOS("r6") + ROM_SYSTEM_BIOS( 0, "r1", "Revision 1" ) + ROMX_LOAD( "901229-01.uab5", 0x2000, 0x2000, CRC(9a48d3f0) SHA1(7a1054c6156b51c25410caec0f609efb079d3a77), ROM_BIOS(1) ) + ROM_SYSTEM_BIOS( 1, "r2", "Revision 2" ) + ROMX_LOAD( "901229-02.uab5", 0x2000, 0x2000, CRC(b29bab75) SHA1(91321142e226168b1139c30c83896933f317d000), ROM_BIOS(2) ) + ROM_SYSTEM_BIOS( 2, "r3", "Revision 3" ) + ROMX_LOAD( "901229-03.uab5", 0x2000, 0x2000, CRC(9126e74a) SHA1(03d17bd745066f1ead801c5183ac1d3af7809744), ROM_BIOS(3) ) + ROM_SYSTEM_BIOS( 3, "r4", "Revision 4" ) + ROMX_LOAD( "901229-04.uab5", 0x2000, 0x2000, NO_DUMP, ROM_BIOS(4) ) + ROM_SYSTEM_BIOS( 4, "r5", "Revision 5" ) + ROMX_LOAD( "901229-05 ae.uab5", 0x2000, 0x2000, CRC(361c9f37) SHA1(f5d60777440829e46dc91285e662ba072acd2d8b), ROM_BIOS(5) ) + ROM_SYSTEM_BIOS( 5, "r6", "Revision 6" ) + ROMX_LOAD( "901229-06 aa.uab5", 0x2000, 0x2000, CRC(3a235039) SHA1(c7f94f4f51d6de4cdc21ecbb7e57bb209f0530c0), ROM_BIOS(6) ) + ROM_SYSTEM_BIOS( 6, "jiffydos", "JiffyDOS v6.01" ) + ROMX_LOAD( "jiffydos 1541.uab5", 0x2000, 0x2000, CRC(bc7e4aeb) SHA1(db6cfaa6d9b78d58746c811de29f3b1f44d99ddf), ROM_BIOS(7) ) + ROM_SYSTEM_BIOS( 7, "speeddos", "SpeedDOS-Plus+" ) + ROMX_LOAD( "speed-dosplus.uab5", 0x0000, 0x4000, CRC(f9db1eac) SHA1(95407e59a9c1d26a0e4bcf2c244cfe8942576e2c), ROM_BIOS(8) ) + ROM_SYSTEM_BIOS( 8, "rolo27", "Rolo DOS v2.7" ) + ROMX_LOAD( "rolo27.uab5", 0x0000, 0x2000, CRC(171c7962) SHA1(04c892c4b3d7c74750576521fa081f07d8ca8557), ROM_BIOS(9) ) + ROM_SYSTEM_BIOS( 9, "tt34", "TurboTrans v3.4" ) + ROMX_LOAD( "ttd34.uab5", 0x0000, 0x8000, CRC(518d34a1) SHA1(4d6ffdce6ab122e9627b0a839861687bcd4e03ec), ROM_BIOS(10) ) + ROM_SYSTEM_BIOS( 10, "digidos", "DigiDOS" ) + ROMX_LOAD( "digidos.uab5", 0x0000, 0x2000, CRC(b3f05ea3) SHA1(99d3d848344c68410b686cda812f3788b41fead3), ROM_BIOS(11) ) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *c1541_t::device_rom_region() const +{ + return ROM_NAME( c1541 ); +} + + +//------------------------------------------------- +// ROM( c1541c ) +//------------------------------------------------- + +ROM_START( c1541c ) + ROM_REGION( 0x4000, M6502_TAG, 0 ) + ROM_DEFAULT_BIOS("r2") + ROM_SYSTEM_BIOS( 0, "r1", "Revision 1" ) + ROMX_LOAD( "251968-01.ua2", 0x0000, 0x4000, CRC(1b3ca08d) SHA1(8e893932de8cce244117fcea4c46b7c39c6a7765), ROM_BIOS(1) ) + ROM_SYSTEM_BIOS( 1, "r2", "Revision 2" ) + ROMX_LOAD( "251968-02.ua2", 0x0000, 0x4000, CRC(2d862d20) SHA1(38a7a489c7bbc8661cf63476bf1eb07b38b1c704), ROM_BIOS(2) ) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *c1541c_t::device_rom_region() const +{ + return ROM_NAME( c1541c ); +} + + +//------------------------------------------------- +// ROM( c1541ii ) +//------------------------------------------------- + +ROM_START( c1541ii ) + ROM_REGION( 0x8000, M6502_TAG, 0 ) + ROM_LOAD( "251968-03.u4", 0x0000, 0x4000, CRC(899fa3c5) SHA1(d3b78c3dbac55f5199f33f3fe0036439811f7fb3) ) + + ROM_DEFAULT_BIOS("r1") + ROM_SYSTEM_BIOS( 0, "r1", "Revision 1" ) + ROMX_LOAD( "355640-01.u4", 0x0000, 0x4000, CRC(57224cde) SHA1(ab16f56989b27d89babe5f89c5a8cb3da71a82f0), ROM_BIOS(1) ) + ROM_SYSTEM_BIOS( 1, "jiffydos", "JiffyDOS v6.01" ) + ROMX_LOAD( "jiffydos 1541-ii.u4", 0x0000, 0x4000, CRC(dd409902) SHA1(b1a5b826304d3df2a27d7163c6a81a532e040d32), ROM_BIOS(2) ) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *c1541ii_t::device_rom_region() const +{ + return ROM_NAME( c1541ii ); +} + + +//------------------------------------------------- +// ROM( sx1541 ) +//------------------------------------------------- + +ROM_START( sx1541 ) + ROM_REGION( 0x4000, M6502_TAG, 0 ) + ROM_LOAD( "325302-01.uab4", 0x0000, 0x2000, CRC(29ae9752) SHA1(8e0547430135ba462525c224e76356bd3d430f11) ) + + ROM_DEFAULT_BIOS("r5") + ROM_SYSTEM_BIOS( 0, "r5", "Revision 5" ) + ROMX_LOAD( "901229-05 ae.uab5", 0x2000, 0x2000, CRC(361c9f37) SHA1(f5d60777440829e46dc91285e662ba072acd2d8b), ROM_BIOS(1) ) + ROM_SYSTEM_BIOS( 1, "jiffydos", "JiffyDOS v6.01" ) + ROMX_LOAD( "jiffydos sx1541", 0x0000, 0x4000, CRC(783575f6) SHA1(36ccb9ff60328c4460b68522443ecdb7f002a234), ROM_BIOS(2) ) + ROM_SYSTEM_BIOS( 2, "flash", "1541 FLASH!" ) + ROMX_LOAD( "1541 flash.uab5", 0x2000, 0x2000, CRC(22f7757e) SHA1(86a1e43d3d22b35677064cca400a6bd06767a3dc), ROM_BIOS(3) ) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *sx1541_t::device_rom_region() const +{ + return ROM_NAME( sx1541 ); +} + + +//------------------------------------------------- +// ROM( fsd1 ) +//------------------------------------------------- + +ROM_START( fsd1 ) + ROM_REGION( 0x4000, M6502_TAG, 0 ) + ROM_LOAD( "fsd1.bin", 0x0000, 0x4000, CRC(57224cde) SHA1(ab16f56989b27d89babe5f89c5a8cb3da71a82f0) ) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *fsd1_t::device_rom_region() const +{ + return ROM_NAME( fsd1 ); +} + + +//------------------------------------------------- +// ROM( fsd2 ) +//------------------------------------------------- + +ROM_START( fsd2 ) + ROM_REGION( 0x4000, M6502_TAG, 0 ) // data lines D3 and D4 are swapped + ROM_DEFAULT_BIOS("fsd2") + ROM_SYSTEM_BIOS( 0, "ra", "Revision A" ) + ROMX_LOAD( "fsd2a.u3", 0x0000, 0x4000, CRC(edf18265) SHA1(47a7c4bdcc20ecc5e59d694b151f493229becaea), ROM_BIOS(1) ) + ROM_SYSTEM_BIOS( 1, "rb", "Revision B" ) + ROMX_LOAD( "fsd2b.u3", 0x0000, 0x4000, CRC(b39e4600) SHA1(991132fcc6e70e9a428062ae76055a150f2f7ac6), ROM_BIOS(2) ) + ROM_SYSTEM_BIOS( 2, "jiffydos", "JiffyDOS v5.0" ) + ROMX_LOAD( "jiffydos v5.0.u3", 0x0000, 0x4000, CRC(46c3302c) SHA1(e3623658cb7af30c9d3bce2ba3b6ad5ee89ac1b8), ROM_BIOS(3) ) + ROM_SYSTEM_BIOS( 3, "rexdos", "REX-DOS" ) + ROMX_LOAD( "rdos.bin", 0x0000, 0x4000, CRC(8ad6dba1) SHA1(f279d327d5e16ea1b62fb18514fb679d0b442941), ROM_BIOS(4) ) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *fsd2_t::device_rom_region() const +{ + return ROM_NAME( fsd2 ); +} + + +//------------------------------------------------- +// ROM( csd1 ) +//------------------------------------------------- + +ROM_START( csd1 ) + ROM_REGION( 0x4000, M6502_TAG, 0 ) + ROM_LOAD( "ic14", 0x0000, 0x2000, CRC(adb6980e) SHA1(13051587dfe43b04ce1bf354b89438ddf6d8d76b) ) + ROM_LOAD( "ic15", 0x2000, 0x2000, CRC(b0cecfa1) SHA1(c67e79a7ffefc9e9eafc238cb6ff6bb718f19afb) ) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *csd1_t::device_rom_region() const +{ + return ROM_NAME( csd1 ); +} + + +//------------------------------------------------- +// ROM( c1541dd ) +//------------------------------------------------- + +ROM_START( c1541dd ) + ROM_REGION( 0x8000, M6502_TAG, 0 ) + ROM_LOAD( "dd20.bin", 0x0000, 0x8000, CRC(94c7fe19) SHA1(e4d5b9ad6b719dd988276214aa4536d3525d313c) ) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *c1541_dolphin_dos_t::device_rom_region() const +{ + return ROM_NAME( c1541dd ); +} + + +//------------------------------------------------- +// ROM( c1541pd ) +//------------------------------------------------- + +ROM_START( c1541pd ) + ROM_REGION( 0x6000, M6502_TAG, 0 ) + ROM_LOAD( "325302-01.uab4", 0x0000, 0x2000, CRC(29ae9752) SHA1(8e0547430135ba462525c224e76356bd3d430f11) ) + ROM_LOAD( "professionaldos-v1-floppy-expansion-eprom-27128.bin", 0x2000, 0x4000, CRC(c9abf072) SHA1(2b26adc1f4192b6ca1514754f73c929087b24426) ) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *c1541_professional_dos_v1_t::device_rom_region() const +{ + return ROM_NAME( c1541pd ); +} + + +//------------------------------------------------- +// ROM( c1541pdc ) +//------------------------------------------------- + +ROM_START( c1541pdc ) + ROM_REGION( 0x8000, M6502_TAG, 0 ) + ROM_LOAD( "325302-01.uab4", 0x0000, 0x2000, CRC(29ae9752) SHA1(8e0547430135ba462525c224e76356bd3d430f11) ) + ROM_LOAD( "901229-06 aa.uab5", 0x2000, 0x2000, CRC(3a235039) SHA1(c7f94f4f51d6de4cdc21ecbb7e57bb209f0530c0) ) + ROM_LOAD( "kernal.bin", 0x4000, 0x4000, CRC(79032ed5) SHA1(0ca4d5ef41c7e3d18d8945476d1481573af3e27c) ) + + ROM_REGION( 0x2000, "mmu", 0 ) + ROM_LOAD( "mmu.bin", 0x0000, 0x2000, CRC(4c41392c) SHA1(78846af2ee6a56fceee44f9246659685ab2cbb7e) ) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *c1541_prologic_dos_classic_t::device_rom_region() const +{ + return ROM_NAME( c1541pdc ); +} + + +//------------------------------------------------- +// ROM( indusgt ) +//------------------------------------------------- + +ROM_START( indusgt ) + ROM_REGION( 0x4000, M6502_TAG, 0 ) + ROM_LOAD( "u18 v1.1.u18", 0x0000, 0x2000, CRC(e401ce56) SHA1(9878053bdff7a036f57285c2c4974459df2602d8) ) + ROM_LOAD( "u17 v1.1.u17", 0x2000, 0x2000, CRC(575ad906) SHA1(f48837b024add84f888acd83a9cf9eb7d2379172) ) + + ROM_REGION( 0x2000, "romdisk", 0 ) + ROM_LOAD( "u19 v1.1.u19", 0x0000, 0x2000, CRC(8f83e7a5) SHA1(5bceaad520dac9d0527723b3b454e8ec99748e5b) ) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *indus_gt_t::device_rom_region() const +{ + return ROM_NAME( indusgt ); +} + + +//------------------------------------------------- +// read - +//------------------------------------------------- + +READ8_MEMBER( c1541_prologic_dos_classic_t::read ) +{ + return 0; +} + + +//------------------------------------------------- +// write - +//------------------------------------------------- + +WRITE8_MEMBER( c1541_prologic_dos_classic_t::write ) +{ +} + + +//------------------------------------------------- +// ADDRESS_MAP( c1541_mem ) +//------------------------------------------------- + +static ADDRESS_MAP_START( c1541_mem, AS_PROGRAM, 8, c1541_base_t ) + AM_RANGE(0x0000, 0x07ff) AM_MIRROR(0x6000) AM_RAM + AM_RANGE(0x1800, 0x180f) AM_MIRROR(0x63f0) AM_DEVREADWRITE(M6522_0_TAG, via6522_device, read, write) + AM_RANGE(0x1c00, 0x1c0f) AM_MIRROR(0x63f0) AM_DEVREADWRITE(M6522_1_TAG, via6522_device, read, write) + AM_RANGE(0x8000, 0xbfff) AM_MIRROR(0x4000) AM_ROM AM_REGION(M6502_TAG, 0) +ADDRESS_MAP_END + + +//------------------------------------------------- +// ADDRESS_MAP( c1541dd_mem ) +//------------------------------------------------- + +static ADDRESS_MAP_START( c1541dd_mem, AS_PROGRAM, 8, c1541_base_t ) + AM_RANGE(0x0000, 0x07ff) AM_MIRROR(0x6000) AM_RAM + AM_RANGE(0x1800, 0x180f) AM_MIRROR(0x63f0) AM_DEVREADWRITE(M6522_0_TAG, via6522_device, read, write) + AM_RANGE(0x1c00, 0x1c0f) AM_MIRROR(0x63f0) AM_DEVREADWRITE(M6522_1_TAG, via6522_device, read, write) + AM_RANGE(0x8000, 0x9fff) AM_RAM + AM_RANGE(0xa000, 0xffff) AM_ROM AM_REGION(M6502_TAG, 0x2000) +ADDRESS_MAP_END + + +//------------------------------------------------- +// ADDRESS_MAP( c1541pd_mem ) +//------------------------------------------------- + +static ADDRESS_MAP_START( c1541pd_mem, AS_PROGRAM, 8, c1541_base_t ) + AM_RANGE(0x0000, 0x07ff) AM_MIRROR(0x6000) AM_RAM + AM_RANGE(0x1800, 0x180f) AM_MIRROR(0x63f0) AM_DEVREADWRITE(M6522_0_TAG, via6522_device, read, write) + AM_RANGE(0x1c00, 0x1c0f) AM_MIRROR(0x63f0) AM_DEVREADWRITE(M6522_1_TAG, via6522_device, read, write) + AM_RANGE(0x8000, 0x9fff) AM_ROM AM_REGION(M6502_TAG, 0x4000) + AM_RANGE(0xa000, 0xbfff) AM_RAM + AM_RANGE(0xc000, 0xffff) AM_ROM AM_REGION(M6502_TAG, 0x0000) + AM_RANGE(0xe000, 0xffff) AM_ROM AM_REGION(M6502_TAG, 0x2000) +ADDRESS_MAP_END + + +//------------------------------------------------- +// ADDRESS_MAP( c1541pdc_mem ) +//------------------------------------------------- + +static ADDRESS_MAP_START( c1541pdc_mem, AS_PROGRAM, 8, c1541_prologic_dos_classic_t ) + AM_RANGE(0x0000, 0xffff) AM_READWRITE(read, write) +/* AM_RANGE(0x0000, 0x07ff) AM_MIRROR(0x6000) AM_RAM AM_SHARE("share1") + AM_RANGE(0x1800, 0x180f) AM_MIRROR(0x63f0) AM_DEVREADWRITE(M6522_0_TAG, via6522_device, read, write) + AM_RANGE(0x1c00, 0x1c0f) AM_MIRROR(0x63f0) AM_DEVREADWRITE(M6522_1_TAG, via6522_device, read, write) + AM_RANGE(0x8000, 0x87ff) AM_RAM AM_SHARE("share1") + AM_RANGE(0x8800, 0x9fff) AM_RAM + AM_RANGE(0xa000, 0xb7ff) AM_ROM AM_REGION(M6502_TAG, 0x0000) + AM_RANGE(0xb800, 0xb80f) AM_READWRITE(pia_r, pia_w) + AM_RANGE(0xf000, 0xffff) AM_ROM AM_REGION(M6502_TAG, 0x2000)*/ +ADDRESS_MAP_END + + +WRITE_LINE_MEMBER( c1541_base_t::via0_irq_w ) +{ + m_via0_irq = state; + + m_maincpu->set_input_line(INPUT_LINE_IRQ0, (m_via0_irq || m_via1_irq) ? ASSERT_LINE : CLEAR_LINE); +} + +READ8_MEMBER( c1541_base_t::via0_pa_r ) +{ + // dummy read to acknowledge ATN IN interrupt + return m_parallel_data; +} + +WRITE8_MEMBER( c1541_base_t::via0_pa_w ) +{ + if (m_other != NULL) + { + m_other->parallel_data_w(data); + } +} + +READ8_MEMBER( c1541_base_t::via0_pb_r ) +{ + /* + + bit description + + PB0 DATA IN + PB1 + PB2 CLK IN + PB3 + PB4 + PB5 J1 + PB6 J2 + PB7 ATN IN + + */ + + UINT8 data = 0; + + // data in + data = !m_bus->data_r() && !m_ga->atn_r(); + + // clock in + data |= !m_bus->clk_r() << 2; + + // serial bus address + data |= ((m_slot->get_address() - 8) & 0x03) << 5; + + // attention in + data |= !m_bus->atn_r() << 7; + + return data; +} + +WRITE8_MEMBER( c1541_base_t::via0_pb_w ) +{ + /* + + bit description + + PB0 + PB1 DATA OUT + PB2 + PB3 CLK OUT + PB4 ATNA + PB5 + PB6 + PB7 + + */ + + // data out + m_data_out = BIT(data, 1); + + // attention acknowledge + m_ga->atna_w(BIT(data, 4)); + + // clock out + m_bus->clk_w(this, !BIT(data, 3)); +} + +WRITE_LINE_MEMBER( c1541_base_t::via0_ca2_w ) +{ + if (m_other != NULL) + { + m_other->parallel_strobe_w(state); + } +} + +READ8_MEMBER( c1541c_t::via0_pa_r ) +{ + /* + + bit description + + PA0 TR00 SENCE + PA1 + PA2 + PA3 + PA4 + PA5 + PA6 + PA7 + + */ + + return !m_floppy->trk00_r(); +} + + +WRITE_LINE_MEMBER( c1541_base_t::via1_irq_w ) +{ + m_via1_irq = state; + + m_maincpu->set_input_line(INPUT_LINE_IRQ0, (m_via0_irq || m_via1_irq) ? ASSERT_LINE : CLEAR_LINE); +} + +READ8_MEMBER( c1541_base_t::via1_pb_r ) +{ + /* + + bit signal description + + PB0 + PB1 + PB2 + PB3 + PB4 WPS write protect sense + PB5 + PB6 + PB7 SYNC SYNC detect line + + */ + + UINT8 data = 0; + + // write protect sense + data |= !m_floppy->wpt_r() << 4; + + // SYNC detect line + data |= m_ga->sync_r() << 7; + + return data; +} + +WRITE8_MEMBER( c1541_base_t::via1_pb_w ) +{ + /* + + bit signal description + + PB0 STP0 stepping motor bit 0 + PB1 STP1 stepping motor bit 1 + PB2 MTR motor ON/OFF + PB3 ACT drive 0 LED + PB4 + PB5 DS0 density select 0 + PB6 DS1 density select 1 + PB7 SYNC SYNC detect line + + */ + + // spindle motor + m_ga->mtr_w(BIT(data, 2)); + + // stepper motor + m_ga->stp_w(data & 0x03); + + // activity LED + output_set_led_value(LED_ACT, BIT(data, 3)); + + // density select + m_ga->ds_w((data >> 5) & 0x03); +} + + +//------------------------------------------------- +// C64H156_INTERFACE( ga_intf ) +//------------------------------------------------- + +WRITE_LINE_MEMBER( c1541_base_t::atn_w ) +{ + set_iec_data(); +} + +WRITE_LINE_MEMBER( c1541_base_t::byte_w ) +{ + m_maincpu->set_input_line(M6502_SET_OVERFLOW, state); + + m_via1->write_ca1(state); +} + + +//------------------------------------------------- +// SLOT_INTERFACE( c1540_floppies ) +//------------------------------------------------- + +static SLOT_INTERFACE_START( c1540_floppies ) + SLOT_INTERFACE( "525ssqd", ALPS_3255190x ) +SLOT_INTERFACE_END + + +//------------------------------------------------- +// FLOPPY_FORMATS( floppy_formats ) +//------------------------------------------------- + +FLOPPY_FORMATS_MEMBER( c1541_base_t::floppy_formats ) + FLOPPY_D64_FORMAT, + FLOPPY_G64_FORMAT +FLOPPY_FORMATS_END + + +READ8_MEMBER( c1541_prologic_dos_classic_t::pia_r ) +{ + return m_pia->read(space, (offset >> 2) & 0x03); +} + +WRITE8_MEMBER( c1541_prologic_dos_classic_t::pia_w ) +{ + m_pia->write(space, (offset >> 2) & 0x03, data); +} + +WRITE8_MEMBER( c1541_prologic_dos_classic_t::pia_pa_w ) +{ + /* + + bit description + + 0 1/2 MHz + 1 + 2 + 3 35/40 tracks + 4 + 5 + 6 + 7 Hi + + */ +} + +READ8_MEMBER( c1541_prologic_dos_classic_t::pia_pb_r ) +{ + return m_parallel_data; +} + +WRITE8_MEMBER( c1541_prologic_dos_classic_t::pia_pb_w ) +{ + m_parallel_data = data; + + m_cent_data_out->write(space, 0, data); +} + + +//------------------------------------------------- +// MACHINE_DRIVER( c1541 ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( c1541 ) + MCFG_CPU_ADD(M6502_TAG, M6502, XTAL_16MHz/16) + MCFG_CPU_PROGRAM_MAP(c1541_mem) + MCFG_QUANTUM_PERFECT_CPU(M6502_TAG) + + MCFG_DEVICE_ADD(M6522_0_TAG, VIA6522, XTAL_16MHz/16) + MCFG_VIA6522_READPA_HANDLER(READ8(c1541_base_t, via0_pa_r)) + MCFG_VIA6522_READPB_HANDLER(READ8(c1541_base_t, via0_pb_r)) + MCFG_VIA6522_WRITEPA_HANDLER(WRITE8(c1541_base_t, via0_pa_w)) + MCFG_VIA6522_WRITEPB_HANDLER(WRITE8(c1541_base_t, via0_pb_w)) + MCFG_VIA6522_CB2_HANDLER(WRITELINE(c1541_base_t, via0_ca2_w)) + MCFG_VIA6522_IRQ_HANDLER(WRITELINE(c1541_base_t, via0_irq_w)) + + MCFG_DEVICE_ADD(M6522_1_TAG, VIA6522, XTAL_16MHz/16) + MCFG_VIA6522_READPA_HANDLER(DEVREAD8(C64H156_TAG, c64h156_device, yb_r)) + MCFG_VIA6522_READPB_HANDLER(READ8(c1541_base_t, via1_pb_r)) + MCFG_VIA6522_WRITEPA_HANDLER(DEVWRITE8(C64H156_TAG, c64h156_device, yb_w)) + MCFG_VIA6522_WRITEPB_HANDLER(WRITE8(c1541_base_t, via1_pb_w)) + MCFG_VIA6522_CA2_HANDLER(DEVWRITELINE(C64H156_TAG, c64h156_device, soe_w)) + MCFG_VIA6522_CB2_HANDLER(DEVWRITELINE(C64H156_TAG, c64h156_device, oe_w)) + MCFG_VIA6522_IRQ_HANDLER(WRITELINE(c1541_base_t, via1_irq_w)) + + MCFG_DEVICE_ADD(C64H156_TAG, C64H156, XTAL_16MHz) + MCFG_64H156_ATN_CALLBACK(WRITELINE(c1541_base_t, atn_w)) + MCFG_64H156_BYTE_CALLBACK(WRITELINE(c1541_base_t, byte_w)) + MCFG_FLOPPY_DRIVE_ADD(C64H156_TAG":0", c1540_floppies, "525ssqd", c1541_base_t::floppy_formats) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor c1541_base_t::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( c1541 ); +} + + +//------------------------------------------------- +// MACHINE_DRIVER( c1541c ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( c1541c ) + MCFG_FRAGMENT_ADD(c1541) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor c1541c_t::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( c1541c ); +} + + +//------------------------------------------------- +// MACHINE_DRIVER( c1541dd ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( c1541dd ) + MCFG_FRAGMENT_ADD(c1541) + + MCFG_CPU_MODIFY(M6502_TAG) + MCFG_CPU_PROGRAM_MAP(c1541dd_mem) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor c1541_dolphin_dos_t::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( c1541dd ); +} + + +//------------------------------------------------- +// MACHINE_DRIVER( c1541pd ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( c1541pd ) + MCFG_FRAGMENT_ADD(c1541) + + MCFG_CPU_MODIFY(M6502_TAG) + MCFG_CPU_PROGRAM_MAP(c1541pd_mem) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor c1541_professional_dos_v1_t::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( c1541pd ); +} + + +//------------------------------------------------- +// MACHINE_DRIVER( c1541pdc ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( c1541pdc ) + MCFG_FRAGMENT_ADD(c1541) + + MCFG_CPU_MODIFY(M6502_TAG) + MCFG_CPU_PROGRAM_MAP(c1541pdc_mem) + + MCFG_DEVICE_ADD(MC6821_TAG, PIA6821, 0) + MCFG_PIA_READPB_HANDLER(READ8(c1541_prologic_dos_classic_t, pia_pb_r)) + MCFG_PIA_WRITEPA_HANDLER(WRITE8(c1541_prologic_dos_classic_t, pia_pa_w)) + MCFG_PIA_WRITEPB_HANDLER(WRITE8(c1541_prologic_dos_classic_t, pia_pb_w)) + MCFG_PIA_CA2_HANDLER(DEVWRITELINE(CENTRONICS_TAG, centronics_device, write_strobe)) + + MCFG_CENTRONICS_ADD(CENTRONICS_TAG, centronics_devices, "printer") + MCFG_CENTRONICS_ACK_HANDLER(DEVWRITELINE(MC6821_TAG, pia6821_device, ca1_w)) + MCFG_CENTRONICS_OUTPUT_LATCH_ADD("cent_data_out", "centronics") +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor c1541_prologic_dos_classic_t::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( c1541pdc ); +} + + +//------------------------------------------------- +// INPUT_PORTS( c1541 ) +//------------------------------------------------- + +static INPUT_PORTS_START( c1541 ) + PORT_START("ADDRESS") + PORT_DIPNAME( 0x03, 0x00, "Device Address" ) + PORT_DIPSETTING( 0x00, "8" ) + PORT_DIPSETTING( 0x01, "9" ) + PORT_DIPSETTING( 0x02, "10" ) + PORT_DIPSETTING( 0x03, "11" ) +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor c1541_base_t::device_input_ports() const +{ + return INPUT_PORTS_NAME( c1541 ); +} + + + +//************************************************************************** +// INLINE HELPERS +//************************************************************************** + +//------------------------------------------------- +// set_iec_data - +//------------------------------------------------- + +inline void c1541_base_t::set_iec_data() +{ + int data = !m_data_out && !m_ga->atn_r(); + + m_bus->data_w(this, data); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// c1541_base_t - constructor +//------------------------------------------------- + +c1541_base_t:: c1541_base_t(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_cbm_iec_interface(mconfig, *this), + device_c64_floppy_parallel_interface(mconfig, *this), + m_maincpu(*this, M6502_TAG), + m_via0(*this, M6522_0_TAG), + m_via1(*this, M6522_1_TAG), + m_ga(*this, C64H156_TAG), + m_floppy(*this, C64H156_TAG":0:525ssqd"), + m_address(*this, "ADDRESS"), + m_data_out(1), + m_via0_irq(CLEAR_LINE), + m_via1_irq(CLEAR_LINE) +{ +} + + +//------------------------------------------------- +// c1540_t - constructor +//------------------------------------------------- + +c1540_t::c1540_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : c1541_base_t(mconfig, C1540, "C1540", tag, owner, clock, "c1540", __FILE__) { } + + +//------------------------------------------------- +// c1541_t - constructor +//------------------------------------------------- + +c1541_t::c1541_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : c1541_base_t(mconfig, C1541, "C1541", tag, owner, clock, "c1541", __FILE__) { } + + +//------------------------------------------------- +// c1541c_t - constructor +//------------------------------------------------- + +c1541c_t::c1541c_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : c1541_base_t(mconfig, C1541C, "C1541C", tag, owner, clock, "c1541c", __FILE__) { } + + +//------------------------------------------------- +// c1541ii_t - constructor +//------------------------------------------------- + +c1541ii_t::c1541ii_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : c1541_base_t(mconfig, C1541II, "C1541-II", tag, owner, clock, "c1541ii", __FILE__) { } + + +//------------------------------------------------- +// sx1541_t - constructor +//------------------------------------------------- + +sx1541_t::sx1541_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : c1541_base_t(mconfig, SX1541, "SX1541", tag, owner, clock, "sx1541", __FILE__) { } + + +//------------------------------------------------- +// fsd1_t - constructor +//------------------------------------------------- + +fsd1_t::fsd1_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : c1541_base_t(mconfig, FSD1, "FSD-1", tag, owner, clock, "fsd1", __FILE__) { } + + +//------------------------------------------------- +// fsd2_t - constructor +//------------------------------------------------- + +fsd2_t::fsd2_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : c1541_base_t(mconfig, FSD2, "FSD-2", tag, owner, clock, "fsd2", __FILE__) { } + + +//------------------------------------------------- +// csd1_t - constructor +//------------------------------------------------- + +csd1_t::csd1_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : c1541_base_t(mconfig, CSD1, "CSD-1", tag, owner, clock, "csd1", __FILE__) { } + + +//------------------------------------------------- +// c1541_dolphin_dos_t - constructor +//------------------------------------------------- + +c1541_dolphin_dos_t::c1541_dolphin_dos_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : c1541_base_t(mconfig, C1541_DOLPHIN_DOS, "C1541 Dolphin-DOS 2.0", tag, owner, clock, "c1541dd", __FILE__) { } + + +//------------------------------------------------- +// c1541_professional_dos_v1_t - constructor +//------------------------------------------------- + +c1541_professional_dos_v1_t::c1541_professional_dos_v1_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : c1541_base_t(mconfig, C1541_PROFESSIONAL_DOS_V1, "C1541 Professional-DOS v1", tag, owner, clock, "c1541pd", __FILE__) { } + + +//------------------------------------------------- +// c1541_prologic_dos_classic_t - constructor +//------------------------------------------------- + +c1541_prologic_dos_classic_t::c1541_prologic_dos_classic_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : c1541_base_t(mconfig, C1541_PROLOGIC_DOS_CLASSIC, "C1541 ProLogic-DOS Classic", tag, owner, clock, "c1541pdc", __FILE__), + m_pia(*this, MC6821_TAG), + m_cent_data_out(*this, "cent_data_out"), + m_mmu_rom(*this, "mmu") +{ +} + + +//------------------------------------------------- +// indus_gt_t - constructor +//------------------------------------------------- + +indus_gt_t::indus_gt_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : c1541_base_t(mconfig, INDUS_GT, "Indus GT", tag, owner, clock, "indusgt", __FILE__) { } + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void c1541_base_t::device_start() +{ + // install image callbacks + m_ga->set_floppy(m_floppy); + + // register for state saving + save_item(NAME(m_data_out)); + save_item(NAME(m_via0_irq)); + save_item(NAME(m_via1_irq)); +} + +void fsd2_t::device_start() +{ + c1541_base_t::device_start(); + + // decrypt ROM + UINT8 *rom = memregion(M6502_TAG)->base(); + + for (offs_t offset = 0; offset < 0x4000; offset++) + { + UINT8 data = BITSWAP8(rom[offset], 7, 6, 5, 3, 4, 2, 1, 0); + + rom[offset] = data; + } +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void c1541_base_t::device_reset() +{ + m_maincpu->reset(); + + m_via0->reset(); + m_via1->reset(); + + // initialize gate array + m_ga->accl_w(0); + m_ga->ted_w(1); +} + + +//------------------------------------------------- +// iec_atn_w - +//------------------------------------------------- + +void c1541_base_t::cbm_iec_atn(int state) +{ + m_via0->write_ca1(!state); + m_ga->atni_w(!state); + + set_iec_data(); +} + + +//------------------------------------------------- +// iec_reset_w - +//------------------------------------------------- + +void c1541_base_t::cbm_iec_reset(int state) +{ + if (!state) + { + device_reset(); + } +} + + +//------------------------------------------------- +// parallel_data_w - +//------------------------------------------------- + +void c1541_base_t::parallel_data_w(UINT8 data) +{ + m_parallel_data = data; +} + + +//------------------------------------------------- +// parallel_strobe_w - +//------------------------------------------------- + +void c1541_base_t::parallel_strobe_w(int state) +{ + m_via0->write_cb1(state); +} diff --git a/src/devices/bus/cbmiec/c1541.h b/src/devices/bus/cbmiec/c1541.h new file mode 100644 index 00000000000..7195b93293e --- /dev/null +++ b/src/devices/bus/cbmiec/c1541.h @@ -0,0 +1,300 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Commodore 1540/1541/1541C/1541-II Single Disk Drive emulation + +**********************************************************************/ + +#pragma once + +#ifndef __C1541__ +#define __C1541__ + +#include "emu.h" +#include "cbmiec.h" +#include "bus/c64/bn1541.h" +#include "cpu/m6502/m6502.h" +#include "machine/64h156.h" +#include "machine/6522via.h" +#include "machine/6821pia.h" +#include "machine/latch.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define C1541_TAG "c1541" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> c1541_base_t + +class c1541_base_t : public device_t, + public device_cbm_iec_interface, + public device_c64_floppy_parallel_interface +{ +public: + // construction/destruction + c1541_base_t(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual ioport_constructor device_input_ports() const; + + DECLARE_WRITE_LINE_MEMBER( via0_irq_w ); + virtual DECLARE_READ8_MEMBER( via0_pa_r ); + DECLARE_WRITE8_MEMBER( via0_pa_w ); + DECLARE_READ8_MEMBER( via0_pb_r ); + DECLARE_WRITE8_MEMBER( via0_pb_w ); + DECLARE_WRITE_LINE_MEMBER( via0_ca2_w ); + DECLARE_WRITE_LINE_MEMBER( via1_irq_w ); + DECLARE_READ8_MEMBER( via1_pb_r ); + DECLARE_WRITE8_MEMBER( via1_pb_w ); + DECLARE_WRITE_LINE_MEMBER( atn_w ); + DECLARE_WRITE_LINE_MEMBER( byte_w ); + + DECLARE_FLOPPY_FORMATS( floppy_formats ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_cbm_iec_interface overrides + virtual void cbm_iec_atn(int state); + virtual void cbm_iec_reset(int state); + + // device_c64_floppy_parallel_interface overrides + virtual void parallel_data_w(UINT8 data); + virtual void parallel_strobe_w(int state); + + enum + { + LED_POWER = 0, + LED_ACT + }; + + inline void set_iec_data(); + + required_device m_maincpu; + required_device m_via0; + required_device m_via1; + required_device m_ga; + required_device m_floppy; + required_ioport m_address; + + // IEC bus + int m_data_out; // serial data out + + // interrupts + int m_via0_irq; // VIA #0 interrupt request + int m_via1_irq; // VIA #1 interrupt request +}; + + +// ======================> c1540_t + +class c1540_t : public c1541_base_t +{ +public: + // construction/destruction + c1540_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; +}; + + +// ======================> c1541_t + +class c1541_t : public c1541_base_t +{ +public: + // construction/destruction + c1541_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; +}; + + +// ======================> c1541c_t + +class c1541c_t : public c1541_base_t +{ +public: + // construction/destruction + c1541c_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + + // not really public + virtual DECLARE_READ8_MEMBER( via0_pa_r ); +}; + + +// ======================> c1541ii_t + +class c1541ii_t : public c1541_base_t +{ +public: + // construction/destruction + c1541ii_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; +}; + + +// ======================> sx1541_t + +class sx1541_t : public c1541_base_t +{ +public: + // construction/destruction + sx1541_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; +}; + + +// ======================> fsd1_t + +class fsd1_t : public c1541_base_t +{ +public: + // construction/destruction + fsd1_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; +}; + + +// ======================> fsd2_t + +class fsd2_t : public c1541_base_t +{ +public: + // construction/destruction + fsd2_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + + // device-level overrides + virtual void device_start(); +}; + + +// ======================> csd1_t + +class csd1_t : public c1541_base_t +{ +public: + // construction/destruction + csd1_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; +}; + + +// ======================> c1541_dolphin_dos_t + +class c1541_dolphin_dos_t : public c1541_base_t +{ +public: + // construction/destruction + c1541_dolphin_dos_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; +}; + + +// ======================> c1541_professional_dos_v1_t + +class c1541_professional_dos_v1_t : public c1541_base_t +{ +public: + // construction/destruction + c1541_professional_dos_v1_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; +}; + + +// ======================> c1541_prologic_dos_classic_t + +class c1541_prologic_dos_classic_t : public c1541_base_t +{ +public: + // construction/destruction + c1541_prologic_dos_classic_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + + // not really public + DECLARE_READ8_MEMBER( read ); + DECLARE_WRITE8_MEMBER( write ); + + DECLARE_READ8_MEMBER( pia_r ); + DECLARE_WRITE8_MEMBER( pia_w ); + + DECLARE_WRITE8_MEMBER( pia_pa_w ); + DECLARE_READ8_MEMBER( pia_pb_r ); + DECLARE_WRITE8_MEMBER( pia_pb_w ); + +protected: + required_device m_pia; + required_device m_cent_data_out; + required_memory_region m_mmu_rom; +}; + + +// ======================> indus_gt_t + +class indus_gt_t : public c1541_base_t +{ +public: + // construction/destruction + indus_gt_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; +}; + + +// device type definition +extern const device_type C1540; +extern const device_type C1541; +extern const device_type C1541C; +extern const device_type C1541II; +extern const device_type SX1541; +extern const device_type FSD1; +extern const device_type FSD2; +extern const device_type CSD1; +extern const device_type C1541_DOLPHIN_DOS; +extern const device_type C1541_PROFESSIONAL_DOS_V1; +extern const device_type C1541_PROLOGIC_DOS_CLASSIC; +extern const device_type INDUS_GT; + + + +#endif diff --git a/src/devices/bus/cbmiec/c1571.c b/src/devices/bus/cbmiec/c1571.c new file mode 100644 index 00000000000..a08e88fb696 --- /dev/null +++ b/src/devices/bus/cbmiec/c1571.c @@ -0,0 +1,1040 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Commodore 1570/1571/1571CR Single Disk Drive emulation + +**********************************************************************/ + +/* + + TODO: + + - WD1770 set_floppy + - 1571CR + - MOS5710 + - ICT Mini Chief MC-20 + - WD1002A-WX1 ISA controller card + - Seagate ST225 (-chs 615,4,17 -ss 512) + +*/ + +#include "c1571.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define M6502_TAG "u1" +#define M6522_0_TAG "u9" +#define M6522_1_TAG "u4" +#define M6526_TAG "u20" +#define M5710_TAG "u107" +#define WD1770_TAG "u11" +#define C64H156_TAG "u6" +#define C64H157_TAG "u5" +#define ISA_BUS_TAG "isabus" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type C1570 = &device_creator; +const device_type C1571 = &device_creator; +const device_type C1571CR = &device_creator; +const device_type MINI_CHIEF = &device_creator; + + +//------------------------------------------------- +// ROM( c1570 ) +//------------------------------------------------- + +ROM_START( c1570 ) + ROM_REGION( 0x8000, M6502_TAG, 0 ) + ROM_LOAD( "315090-01.u2", 0x0000, 0x8000, CRC(5a0c7937) SHA1(5fc06dc82ff6840f183bd43a4d9b8a16956b2f56) ) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *c1570_t::device_rom_region() const +{ + return ROM_NAME( c1570 ); +} + + +//------------------------------------------------- +// ROM( c1571 ) +//------------------------------------------------- + +ROM_START( c1571 ) + ROM_REGION( 0x8000, M6502_TAG, 0 ) + ROM_DEFAULT_BIOS("r5") + ROM_SYSTEM_BIOS( 0, "r3", "Revision 3" ) + ROMX_LOAD( "310654-03.u2", 0x0000, 0x8000, CRC(3889b8b8) SHA1(e649ef4419d65829d2afd65e07d31f3ce147d6eb), ROM_BIOS(1) ) + ROM_SYSTEM_BIOS( 1, "r5", "Revision 5" ) + ROMX_LOAD( "310654-05.u2", 0x0000, 0x8000, CRC(5755bae3) SHA1(f1be619c106641a685f6609e4d43d6fc9eac1e70), ROM_BIOS(2) ) + ROM_SYSTEM_BIOS( 2, "jiffydos", "JiffyDOS v6.01" ) + ROMX_LOAD( "jiffydos 1571.u2", 0x0000, 0x8000, CRC(fe6cac6d) SHA1(d4b79b60cf1eaa399d0932200eb7811e00455249), ROM_BIOS(3) ) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *c1571_t::device_rom_region() const +{ + return ROM_NAME( c1571 ); +} + + +//------------------------------------------------- +// ROM( c1571cr ) +//------------------------------------------------- + +ROM_START( c1571cr ) + ROM_REGION( 0x8000, M6502_TAG, 0 ) + ROM_DEFAULT_BIOS("cbm") + ROM_SYSTEM_BIOS( 0, "cbm", "Commodore" ) + ROMX_LOAD( "318047-01.u102", 0x0000, 0x8000, CRC(f24efcc4) SHA1(14ee7a0fb7e1c59c51fbf781f944387037daa3ee), ROM_BIOS(1) ) + ROM_SYSTEM_BIOS( 1, "jiffydos", "JiffyDOS v6.01" ) + ROMX_LOAD( "jiffydos 1571d.u102", 0x0000, 0x8000, CRC(9cba146d) SHA1(823b178561302b403e6bfd8dd741d757efef3958), ROM_BIOS(2) ) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *c1571cr_t::device_rom_region() const +{ + return ROM_NAME( c1571cr ); +} + + +//------------------------------------------------- +// ROM( minichief ) +//------------------------------------------------- + +ROM_START( minichief ) + ROM_REGION( 0x8000, M6502_TAG, 0 ) + ROM_LOAD( "ictdos710.u2", 0x0000, 0x8000, CRC(aaacf7e9) SHA1(c1296995238ef23f18e7fec70a144a0566a25a27) ) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *mini_chief_t::device_rom_region() const +{ + return ROM_NAME( minichief ); +} + + +//------------------------------------------------- +// ADDRESS_MAP( c1571_mem ) +//------------------------------------------------- + +static ADDRESS_MAP_START( c1571_mem, AS_PROGRAM, 8, c1571_t ) + AM_RANGE(0x0000, 0x07ff) AM_RAM + AM_RANGE(0x1800, 0x180f) AM_MIRROR(0x03f0) AM_DEVREADWRITE(M6522_0_TAG, via6522_device, read, write) + AM_RANGE(0x1c00, 0x1c0f) AM_MIRROR(0x03f0) AM_READWRITE(via1_r, via1_w) + AM_RANGE(0x2000, 0x2003) AM_MIRROR(0x1ffc) AM_DEVREADWRITE(WD1770_TAG, wd1770_t, read, write) + AM_RANGE(0x4000, 0x400f) AM_MIRROR(0x3ff0) AM_DEVREADWRITE(M6526_TAG, mos6526_device, read, write) + AM_RANGE(0x8000, 0xffff) AM_ROM AM_REGION(M6502_TAG, 0) +ADDRESS_MAP_END + + +//------------------------------------------------- +// ADDRESS_MAP( mini_chief_mem ) +//------------------------------------------------- + +static ADDRESS_MAP_START( mini_chief_mem, AS_PROGRAM, 8, mini_chief_t ) + AM_RANGE(0x0000, 0x07ff) AM_RAM + AM_RANGE(0x1800, 0x180f) AM_MIRROR(0x03f0) AM_DEVREADWRITE(M6522_0_TAG, via6522_device, read, write) + AM_RANGE(0x1c00, 0x1c0f) AM_MIRROR(0x03f0) AM_READWRITE(via1_r, via1_w) + AM_RANGE(0x2000, 0x2003) AM_MIRROR(0x1ffc) AM_DEVREADWRITE(WD1770_TAG, wd1770_t, read, write) + AM_RANGE(0x4000, 0x400f) AM_MIRROR(0xff0) AM_DEVREADWRITE(M6526_TAG, mos6526_device, read, write) + AM_RANGE(0x5000, 0x5fff) AM_MIRROR(0x2000) AM_RAM + AM_RANGE(0x6000, 0x6fff) AM_RAM + AM_RANGE(0x8000, 0xffff) AM_ROM AM_REGION(M6502_TAG, 0) +ADDRESS_MAP_END + + +WRITE_LINE_MEMBER( c1571_t::via0_irq_w ) +{ + m_via0_irq = state; + + m_maincpu->set_input_line(INPUT_LINE_IRQ0, (m_via0_irq || m_via1_irq || m_cia_irq) ? ASSERT_LINE : CLEAR_LINE); +} + +READ8_MEMBER( c1571_t::via0_pa_r ) +{ + /* + + bit description + + PA0 TRK0 SNS + PA1 + PA2 + PA3 + PA4 + PA5 + PA6 + PA7 BYTE RDY + + */ + + UINT8 data = 0; + + // track 0 sense + data |= (m_floppy->trk00_r() ? 0x01 : 0x00); + + // byte ready + data |= m_ga->byte_r() << 7; + + return data; +} + +WRITE8_MEMBER( c1571_t::via0_pa_w ) +{ + /* + + bit description + + PA0 + PA1 SER DIR + PA2 SIDE + PA3 + PA4 + PA5 _1/2 MHZ + PA6 ATN OUT + PA7 + + */ + + // fast serial direction + m_ser_dir = BIT(data, 1); + + // side select + m_floppy->ss_w(BIT(data, 2)); + + // 1/2 MHz + int clock_1_2 = BIT(data, 5); + + if (m_1_2mhz != clock_1_2) + { + UINT32 clock = clock_1_2 ? XTAL_16MHz/8 : XTAL_16MHz/16; + + m_maincpu->set_unscaled_clock(clock); + m_cia->set_unscaled_clock(clock); + m_via0->set_unscaled_clock(clock); + m_via1->set_unscaled_clock(clock); + m_ga->accl_w(clock_1_2); + + m_1_2mhz = clock_1_2; + } + + // attention out + m_bus->atn_w(this, !BIT(data, 6)); + + update_iec(); +} + +WRITE8_MEMBER( c1571cr_t::via0_pa_w ) +{ + /* + + bit description + + PA0 + PA1 + PA2 SIDE + PA3 + PA4 + PA5 _1/2 MHZ + PA6 + PA7 + + */ + + // side select + m_floppy->ss_w(BIT(data, 2)); + + // 1/2 MHz + int clock_1_2 = BIT(data, 5); + + if (m_1_2mhz != clock_1_2) + { + UINT32 clock = clock_1_2 ? XTAL_16MHz/8 : XTAL_16MHz/16; + + m_maincpu->set_unscaled_clock(clock); + m_cia->set_unscaled_clock(clock); + m_via0->set_unscaled_clock(clock); + m_via1->set_unscaled_clock(clock); + m_ga->accl_w(clock_1_2); + + m_1_2mhz = clock_1_2; + } +} + +READ8_MEMBER( c1571_t::via0_pb_r ) +{ + /* + + bit description + + PB0 DATA IN + PB1 + PB2 CLK IN + PB3 + PB4 + PB5 DEV# SEL + PB6 DEV# SEL + PB7 ATN IN + + */ + + UINT8 data = 0; + + // data in + data = !m_bus->data_r(); + + // clock in + data |= !m_bus->clk_r() << 2; + + // serial bus address + data |= ((m_slot->get_address() - 8) & 0x03) << 5; + + // attention in + data |= !m_bus->atn_r() << 7; + + return data; +} + +WRITE8_MEMBER( c1571_t::via0_pb_w ) +{ + /* + + bit description + + PB0 + PB1 DATA OUT + PB2 + PB3 CLK OUT + PB4 ATN ACK + PB5 + PB6 + PB7 + + */ + + // data out + m_data_out = BIT(data, 1); + + // clock out + m_bus->clk_w(this, !BIT(data, 3)); + + // attention acknowledge + m_ga->atna_w(BIT(data, 4)); + + update_iec(); +} + +WRITE8_MEMBER( c1571cr_t::via0_pb_w ) +{ + /* + + bit description + + PB0 + PB1 DATA OUT + PB2 + PB3 CLK OUT + PB4 ATNI + PB5 + PB6 + PB7 + + */ + + // data out + m_data_out = BIT(data, 1); + + // clock out + m_bus->clk_w(this, !BIT(data, 3)); + + // attention in + m_ga->atni_w(BIT(data, 4)); + + update_iec(); +} + + +READ8_MEMBER( c1571_t::via1_r ) +{ + UINT8 data = m_via1->read(space, offset); + + m_ga->ted_w(!m_1_2mhz); + m_ga->ted_w(1); + + return data; +} + +WRITE8_MEMBER( c1571_t::via1_w ) +{ + m_via1->write(space, offset, data); + + m_ga->ted_w(!m_1_2mhz); + m_ga->ted_w(1); +} + +WRITE_LINE_MEMBER( c1571_t::via1_irq_w ) +{ + m_via1_irq = state; + + m_maincpu->set_input_line(INPUT_LINE_IRQ0, (m_via0_irq || m_via1_irq || m_cia_irq) ? ASSERT_LINE : CLEAR_LINE); +} + +READ8_MEMBER( c1571_t::via1_pb_r ) +{ + /* + + bit signal description + + PB0 + PB1 + PB2 + PB3 + PB4 _WPRT write protect sense + PB5 + PB6 + PB7 _SYNC SYNC detect line + + */ + + UINT8 data = 0; + + // write protect sense + data |= !m_floppy->wpt_r() << 4; + + // SYNC detect line + data |= m_ga->sync_r() << 7; + + return data; +} + +WRITE8_MEMBER( c1571_t::via1_pb_w ) +{ + /* + + bit signal description + + PB0 STP0 stepping motor bit 0 + PB1 STP1 stepping motor bit 1 + PB2 MTR motor ON/OFF + PB3 ACT drive 0 LED + PB4 + PB5 DS0 density select 0 + PB6 DS1 density select 1 + PB7 + + */ + + // spindle motor + m_ga->mtr_w(BIT(data, 2)); + + // stepper motor + m_ga->stp_w(data & 0x03); // TODO actually STP1=0, STP0=!(PB0^PB1), Y0=PB1, Y2=!PB1 + + // activity LED + output_set_led_value(LED_ACT, BIT(data, 3)); + + // density select + m_ga->ds_w((data >> 5) & 0x03); +} + + +//------------------------------------------------- +// MOS6526_INTERFACE( cia_intf ) +//------------------------------------------------- + +WRITE_LINE_MEMBER( c1571_t::cia_irq_w ) +{ + m_cia_irq = state; + + m_maincpu->set_input_line(INPUT_LINE_IRQ0, (m_via0_irq || m_via1_irq || m_cia_irq) ? ASSERT_LINE : CLEAR_LINE); +} + +WRITE_LINE_MEMBER( c1571_t::cia_pc_w ) +{ + if (m_other != NULL) + { + m_other->parallel_strobe_w(state); + } +} + +WRITE_LINE_MEMBER( c1571_t::cia_cnt_w ) +{ + m_cnt_out = state; + + update_iec(); +} + +WRITE_LINE_MEMBER( c1571_t::cia_sp_w ) +{ + m_sp_out = state; + + update_iec(); +} + +READ8_MEMBER( c1571_t::cia_pb_r ) +{ + return m_parallel_data; +} + +WRITE8_MEMBER( c1571_t::cia_pb_w ) +{ + if (m_other != NULL) + { + m_other->parallel_data_w(data); + } +} + + +//------------------------------------------------- +// MOS6526_INTERFACE( mini_chief_cia_intf ) +//------------------------------------------------- + +READ8_MEMBER( mini_chief_t::cia_pa_r ) +{ + // TODO read from ISA bus @ 0x320 | A2 A1 A0 + + return 0; +} + +WRITE8_MEMBER( mini_chief_t::cia_pa_w ) +{ + // TODO write to ISA bus @ 0x320 | A2 A1 A0 +} + +WRITE8_MEMBER( mini_chief_t::cia_pb_w ) +{ + /* + + bit description + + 0 ISA A0 + 1 ISA A1 + 2 ISA A2 + 3 ISA /SMEMR + 4 ISA /SMEMW + 5 ISA RESET + 6 + 7 + + */ +} + + +//------------------------------------------------- +// C64H156_INTERFACE( ga_intf ) +//------------------------------------------------- + +WRITE_LINE_MEMBER( c1571_t::byte_w ) +{ + m_via1->write_ca1(state); + + m_maincpu->set_input_line(M6502_SET_OVERFLOW, state); +} + + +//------------------------------------------------- +// SLOT_INTERFACE( c1571_floppies ) +//------------------------------------------------- + +static SLOT_INTERFACE_START( c1571_floppies ) + SLOT_INTERFACE( "525qd", FLOPPY_525_QD ) +SLOT_INTERFACE_END + + +//------------------------------------------------- +// floppy_interface c1571_floppy_interface +//------------------------------------------------- + +void c1571_t::wpt_callback(floppy_image_device *floppy, int state) +{ + m_via0->write_ca2(!state); +} + + +//------------------------------------------------- +// FLOPPY_FORMATS( floppy_formats ) +//------------------------------------------------- + +FLOPPY_FORMATS_MEMBER( c1571_t::floppy_formats ) + FLOPPY_D64_FORMAT, + FLOPPY_G64_FORMAT, + FLOPPY_D71_FORMAT +FLOPPY_FORMATS_END + + +//------------------------------------------------- +// isa8bus_interface isabus_intf +//------------------------------------------------- + +static SLOT_INTERFACE_START( mini_chief_isa8_cards ) + SLOT_INTERFACE("wd1002a_wx1", ISA8_WD1002A_WX1) +SLOT_INTERFACE_END + +//------------------------------------------------- +// MACHINE_DRIVER( c1570 ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( c1570 ) + MCFG_CPU_ADD(M6502_TAG, M6502, XTAL_16MHz/16) + MCFG_CPU_PROGRAM_MAP(c1571_mem) + MCFG_QUANTUM_PERFECT_CPU(M6502_TAG) + + MCFG_DEVICE_ADD(M6522_0_TAG, VIA6522, XTAL_16MHz/16) + MCFG_VIA6522_READPA_HANDLER(READ8(c1571_t, via0_pa_r)) + MCFG_VIA6522_READPB_HANDLER(READ8(c1571_t, via0_pb_r)) + MCFG_VIA6522_WRITEPA_HANDLER(WRITE8(c1571_t, via0_pa_w)) + MCFG_VIA6522_WRITEPB_HANDLER(WRITE8(c1571_t, via0_pb_w)) + MCFG_VIA6522_IRQ_HANDLER(WRITELINE(c1571_t, via0_irq_w)) + + MCFG_DEVICE_ADD(M6522_1_TAG, VIA6522, XTAL_16MHz/16) + MCFG_VIA6522_READPA_HANDLER(DEVREAD8(C64H156_TAG, c64h156_device, yb_r)) + MCFG_VIA6522_READPB_HANDLER(READ8(c1571_t, via1_pb_r)) + MCFG_VIA6522_WRITEPA_HANDLER(DEVWRITE8(C64H156_TAG, c64h156_device, yb_w)) + MCFG_VIA6522_WRITEPB_HANDLER(WRITE8(c1571_t, via1_pb_w)) + MCFG_VIA6522_CA2_HANDLER(DEVWRITELINE(C64H156_TAG, c64h156_device, soe_w)) + MCFG_VIA6522_CB2_HANDLER(DEVWRITELINE(C64H156_TAG, c64h156_device, oe_w)) + MCFG_VIA6522_IRQ_HANDLER(WRITELINE(c1571_t, via1_irq_w)) + + MCFG_DEVICE_ADD(M6526_TAG, MOS6526, XTAL_16MHz/16) + MCFG_MOS6526_IRQ_CALLBACK(WRITELINE(c1571_t, cia_irq_w)) + MCFG_MOS6526_CNT_CALLBACK(WRITELINE(c1571_t, cia_cnt_w)) + MCFG_MOS6526_SP_CALLBACK(WRITELINE(c1571_t, cia_sp_w)) + MCFG_MOS6526_PB_INPUT_CALLBACK(READ8(c1571_t, cia_pb_r)) + MCFG_MOS6526_PB_OUTPUT_CALLBACK(WRITE8(c1571_t, cia_pb_w)) + MCFG_MOS6526_PC_CALLBACK(WRITELINE(c1571_t, cia_pc_w)) + + MCFG_WD1770_ADD(WD1770_TAG, XTAL_16MHz/2) + MCFG_DEVICE_ADD(C64H156_TAG, C64H156, XTAL_16MHz) + MCFG_64H156_BYTE_CALLBACK(WRITELINE(c1571_t, byte_w)) + MCFG_FLOPPY_DRIVE_ADD(C64H156_TAG":0", c1571_floppies, "525qd", c1571_t::floppy_formats) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor c1570_t::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( c1570 ); +} + + +//------------------------------------------------- +// MACHINE_DRIVER( c1571 ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( c1571 ) + MCFG_CPU_ADD(M6502_TAG, M6502, XTAL_16MHz/16) + MCFG_CPU_PROGRAM_MAP(c1571_mem) + MCFG_QUANTUM_PERFECT_CPU(M6502_TAG) + + MCFG_DEVICE_ADD(M6522_0_TAG, VIA6522, XTAL_16MHz/16) + MCFG_VIA6522_READPA_HANDLER(READ8(c1571_t, via0_pa_r)) + MCFG_VIA6522_READPB_HANDLER(READ8(c1571_t, via0_pb_r)) + MCFG_VIA6522_WRITEPA_HANDLER(WRITE8(c1571_t, via0_pa_w)) + MCFG_VIA6522_WRITEPB_HANDLER(WRITE8(c1571_t, via0_pb_w)) + MCFG_VIA6522_IRQ_HANDLER(WRITELINE(c1571_t, via0_irq_w)) + + MCFG_DEVICE_ADD(M6522_1_TAG, VIA6522, XTAL_16MHz/16) + MCFG_VIA6522_READPA_HANDLER(DEVREAD8(C64H156_TAG, c64h156_device, yb_r)) + MCFG_VIA6522_READPB_HANDLER(READ8(c1571_t, via1_pb_r)) + MCFG_VIA6522_WRITEPA_HANDLER(DEVWRITE8(C64H156_TAG, c64h156_device, yb_w)) + MCFG_VIA6522_WRITEPB_HANDLER(WRITE8(c1571_t, via1_pb_w)) + MCFG_VIA6522_CA2_HANDLER(DEVWRITELINE(C64H156_TAG, c64h156_device, soe_w)) + MCFG_VIA6522_CB2_HANDLER(DEVWRITELINE(C64H156_TAG, c64h156_device, oe_w)) + MCFG_VIA6522_IRQ_HANDLER(WRITELINE(c1571_t, via1_irq_w)) + + MCFG_DEVICE_ADD(M6526_TAG, MOS6526, XTAL_16MHz/16) + MCFG_MOS6526_IRQ_CALLBACK(WRITELINE(c1571_t, cia_irq_w)) + MCFG_MOS6526_CNT_CALLBACK(WRITELINE(c1571_t, cia_cnt_w)) + MCFG_MOS6526_SP_CALLBACK(WRITELINE(c1571_t, cia_sp_w)) + MCFG_MOS6526_PB_INPUT_CALLBACK(READ8(c1571_t, cia_pb_r)) + MCFG_MOS6526_PB_OUTPUT_CALLBACK(WRITE8(c1571_t, cia_pb_w)) + MCFG_MOS6526_PC_CALLBACK(WRITELINE(c1571_t, cia_pc_w)) + + MCFG_WD1770_ADD(WD1770_TAG, XTAL_16MHz/2) + MCFG_DEVICE_ADD(C64H156_TAG, C64H156, XTAL_16MHz) + MCFG_64H156_BYTE_CALLBACK(WRITELINE(c1571_t, byte_w)) + MCFG_FLOPPY_DRIVE_ADD(C64H156_TAG":0", c1571_floppies, "525qd", c1571_t::floppy_formats) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor c1571_t::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( c1571 ); +} + + +//------------------------------------------------- +// MACHINE_DRIVER( c1571cr ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( c1571cr ) + MCFG_CPU_ADD(M6502_TAG, M6502, XTAL_16MHz/16) + MCFG_CPU_PROGRAM_MAP(c1571_mem) + MCFG_QUANTUM_PERFECT_CPU(M6502_TAG) + + MCFG_DEVICE_ADD(M6522_0_TAG, VIA6522, XTAL_16MHz/16) + MCFG_VIA6522_READPA_HANDLER(READ8(c1571_t, via0_pa_r)) + MCFG_VIA6522_READPB_HANDLER(READ8(c1571_t, via0_pb_r)) + MCFG_VIA6522_WRITEPA_HANDLER(WRITE8(c1571cr_t, via0_pa_w)) + MCFG_VIA6522_WRITEPB_HANDLER(WRITE8(c1571cr_t, via0_pb_w)) + MCFG_VIA6522_IRQ_HANDLER(WRITELINE(c1571_t, via0_irq_w)) + + MCFG_DEVICE_ADD(M6522_1_TAG, VIA6522, XTAL_16MHz/16) + MCFG_VIA6522_READPA_HANDLER(DEVREAD8(C64H156_TAG, c64h156_device, yb_r)) + MCFG_VIA6522_READPB_HANDLER(READ8(c1571_t, via1_pb_r)) + MCFG_VIA6522_WRITEPA_HANDLER(DEVWRITE8(C64H156_TAG, c64h156_device, yb_w)) + MCFG_VIA6522_WRITEPB_HANDLER(WRITE8(c1571_t, via1_pb_w)) + MCFG_VIA6522_CA2_HANDLER(DEVWRITELINE(C64H156_TAG, c64h156_device, soe_w)) + MCFG_VIA6522_CB2_HANDLER(DEVWRITELINE(C64H156_TAG, c64h156_device, oe_w)) + MCFG_VIA6522_IRQ_HANDLER(WRITELINE(c1571_t, via1_irq_w)) + + //MCFG_MOS5710_ADD(M5710_TAG, XTAL_16MHz/16, 0) + + MCFG_WD1770_ADD(WD1770_TAG, XTAL_16MHz/2) + MCFG_DEVICE_ADD(C64H156_TAG, C64H156, XTAL_16MHz) + MCFG_64H156_BYTE_CALLBACK(WRITELINE(c1571_t, byte_w)) + MCFG_FLOPPY_DRIVE_ADD(C64H156_TAG":0", c1571_floppies, "525qd", c1571_t::floppy_formats) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor c1571cr_t::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( c1571cr ); +} + + +//------------------------------------------------- +// MACHINE_DRIVER( mini_chief ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( mini_chief ) + MCFG_CPU_ADD(M6502_TAG, M6502, XTAL_16MHz/16) + MCFG_CPU_PROGRAM_MAP(mini_chief_mem) + MCFG_QUANTUM_PERFECT_CPU(M6502_TAG) + + MCFG_DEVICE_ADD(M6522_0_TAG, VIA6522, XTAL_16MHz/16) + MCFG_VIA6522_READPA_HANDLER(READ8(c1571_t, via0_pa_r)) + MCFG_VIA6522_READPB_HANDLER(READ8(c1571_t, via0_pb_r)) + MCFG_VIA6522_WRITEPA_HANDLER(WRITE8(c1571_t, via0_pa_w)) + MCFG_VIA6522_WRITEPB_HANDLER(WRITE8(c1571_t, via0_pb_w)) + MCFG_VIA6522_IRQ_HANDLER(WRITELINE(c1571_t, via0_irq_w)) + + MCFG_DEVICE_ADD(M6522_1_TAG, VIA6522, XTAL_16MHz/16) + MCFG_VIA6522_READPA_HANDLER(DEVREAD8(C64H156_TAG, c64h156_device, yb_r)) + MCFG_VIA6522_READPB_HANDLER(READ8(c1571_t, via1_pb_r)) + MCFG_VIA6522_WRITEPA_HANDLER(DEVWRITE8(C64H156_TAG, c64h156_device, yb_w)) + MCFG_VIA6522_WRITEPB_HANDLER(WRITE8(c1571_t, via1_pb_w)) + MCFG_VIA6522_CA2_HANDLER(DEVWRITELINE(C64H156_TAG, c64h156_device, soe_w)) + MCFG_VIA6522_CB2_HANDLER(DEVWRITELINE(C64H156_TAG, c64h156_device, oe_w)) + MCFG_VIA6522_IRQ_HANDLER(WRITELINE(c1571_t, via1_irq_w)) + + MCFG_DEVICE_ADD(M6526_TAG, MOS6526, XTAL_16MHz/16) + MCFG_MOS6526_IRQ_CALLBACK(WRITELINE(c1571_t, cia_irq_w)) + MCFG_MOS6526_CNT_CALLBACK(WRITELINE(c1571_t, cia_cnt_w)) + MCFG_MOS6526_SP_CALLBACK(WRITELINE(c1571_t, cia_sp_w)) + MCFG_MOS6526_PB_INPUT_CALLBACK(READ8(c1571_t, cia_pb_r)) + MCFG_MOS6526_PB_OUTPUT_CALLBACK(WRITE8(c1571_t, cia_pb_w)) + MCFG_MOS6526_PC_CALLBACK(WRITELINE(c1571_t, cia_pc_w)) + + MCFG_WD1770_ADD(WD1770_TAG, XTAL_16MHz/2) + MCFG_DEVICE_ADD(C64H156_TAG, C64H156, XTAL_16MHz) + MCFG_64H156_BYTE_CALLBACK(WRITELINE(c1571_t, byte_w)) + MCFG_FLOPPY_DRIVE_ADD(C64H156_TAG":0", c1571_floppies, "525qd", c1571_t::floppy_formats) + + MCFG_DEVICE_ADD(ISA_BUS_TAG, ISA8, 0) + MCFG_ISA8_CPU(M6502_TAG) + MCFG_ISA8_SLOT_ADD(ISA_BUS_TAG, "isa1", mini_chief_isa8_cards, "wd1002a_wx1", false) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor mini_chief_t::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( mini_chief ); +} + + +//------------------------------------------------- +// INPUT_PORTS( c1571 ) +//------------------------------------------------- + +static INPUT_PORTS_START( c1571 ) + PORT_START("ADDRESS") + PORT_DIPNAME( 0x03, 0x00, "Device Address" ) + PORT_DIPSETTING( 0x00, "8" ) + PORT_DIPSETTING( 0x01, "9" ) + PORT_DIPSETTING( 0x02, "10" ) + PORT_DIPSETTING( 0x03, "11" ) +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor c1571_t::device_input_ports() const +{ + return INPUT_PORTS_NAME( c1571 ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// c1571_t - constructor +//------------------------------------------------- + +c1571_t::c1571_t(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_cbm_iec_interface(mconfig, *this), + device_c64_floppy_parallel_interface(mconfig, *this), + m_maincpu(*this, M6502_TAG), + m_via0(*this, M6522_0_TAG), + m_via1(*this, M6522_1_TAG), + m_cia(*this, M6526_TAG), + m_fdc(*this, WD1770_TAG), + m_ga(*this, C64H156_TAG), + m_floppy(*this, C64H156_TAG":0:525qd"), + m_address(*this, "ADDRESS"), + m_1_2mhz(0), + m_data_out(1), + m_ser_dir(0), + m_sp_out(1), + m_cnt_out(1), + m_via0_irq(CLEAR_LINE), + m_via1_irq(CLEAR_LINE), + m_cia_irq(CLEAR_LINE) +{ +} + +c1571_t::c1571_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, C1571, "C1571", tag, owner, clock, "c1571", __FILE__), + device_cbm_iec_interface(mconfig, *this), + device_c64_floppy_parallel_interface(mconfig, *this), + m_maincpu(*this, M6502_TAG), + m_via0(*this, M6522_0_TAG), + m_via1(*this, M6522_1_TAG), + m_cia(*this, M6526_TAG), + m_fdc(*this, WD1770_TAG), + m_ga(*this, C64H156_TAG), + m_floppy(*this, C64H156_TAG":0:525qd"), + m_address(*this, "ADDRESS"), + m_1_2mhz(0), + m_data_out(1), + m_ser_dir(0), + m_sp_out(1), + m_cnt_out(1), + m_via0_irq(CLEAR_LINE), + m_via1_irq(CLEAR_LINE), + m_cia_irq(CLEAR_LINE) +{ +} + + +//------------------------------------------------- +// c1570_t - constructor +//------------------------------------------------- + +c1570_t::c1570_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : c1571_t(mconfig, C1570, "C1570", tag, owner, clock, "c1570", __FILE__) +{ +} + + +//------------------------------------------------- +// c1571cr_t - constructor +//------------------------------------------------- + +c1571cr_t::c1571cr_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : c1571_t(mconfig, C1571CR, "C1571CR", tag, owner, clock, "c1571cr", __FILE__) +{ +} + + +//------------------------------------------------- +// mini_chief_t - constructor +//------------------------------------------------- + +mini_chief_t::mini_chief_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : c1571_t(mconfig, MINI_CHIEF, "ICT Mini Chief", tag, owner, clock, "minichif", __FILE__) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void c1571_t::device_start() +{ + // install image callbacks + m_ga->set_floppy(m_floppy); + //m_fdc->set_floppy(m_floppy); + m_floppy->setup_wpt_cb(floppy_image_device::wpt_cb(FUNC(c1571_t::wpt_callback), this)); + + // register for state saving + save_item(NAME(m_1_2mhz)); + save_item(NAME(m_data_out)); + save_item(NAME(m_ser_dir)); + save_item(NAME(m_sp_out)); + save_item(NAME(m_cnt_out)); + save_item(NAME(m_via0_irq)); + save_item(NAME(m_via1_irq)); + save_item(NAME(m_cia_irq)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void c1571_t::device_reset() +{ + m_maincpu->reset(); + + m_via0->reset(); + m_via1->reset(); + m_cia->reset(); + m_fdc->reset(); + + m_fdc->dden_w(0); + + m_sp_out = 1; + m_cnt_out = 1; + + update_iec(); +} + + +//------------------------------------------------- +// cbm_iec_srq - +//------------------------------------------------- + +void c1571_t::cbm_iec_srq(int state) +{ + update_iec(); +} + + +//------------------------------------------------- +// cbm_iec_atn - +//------------------------------------------------- + +void c1571_t::cbm_iec_atn(int state) +{ + update_iec(); +} + + +//------------------------------------------------- +// cbm_iec_data - +//------------------------------------------------- + +void c1571_t::cbm_iec_data(int state) +{ + update_iec(); +} + + +//------------------------------------------------- +// cbm_iec_reset - +//------------------------------------------------- + +void c1571_t::cbm_iec_reset(int state) +{ + if (!state) + { + device_reset(); + } +} + + +//------------------------------------------------- +// parallel_data_w - +//------------------------------------------------- + +void c1571_t::parallel_data_w(UINT8 data) +{ + m_parallel_data = data; +} + + +//------------------------------------------------- +// parallel_strobe_w - +//------------------------------------------------- + +void c1571_t::parallel_strobe_w(int state) +{ + m_cia->flag_w(state); +} + + +//------------------------------------------------- +// update_iec - +//------------------------------------------------- + +void c1571_t::update_iec() +{ + m_cia->cnt_w(m_ser_dir || m_bus->srq_r()); + m_cia->sp_w(m_ser_dir || m_bus->data_r()); + + int atn = m_bus->atn_r(); + m_via0->write_ca1(!atn); + m_ga->atni_w(!atn); + + // serial data + int data = !m_data_out && !m_ga->atn_r(); + if (m_ser_dir) data &= m_sp_out; + m_bus->data_w(this, data); + + // fast clock + int srq = 1; + if (m_ser_dir) srq &= m_cnt_out; + m_bus->srq_w(this, srq); +} diff --git a/src/devices/bus/cbmiec/c1571.h b/src/devices/bus/cbmiec/c1571.h new file mode 100644 index 00000000000..6a938b73291 --- /dev/null +++ b/src/devices/bus/cbmiec/c1571.h @@ -0,0 +1,187 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Commodore 1570/1571/1571CR Single Disk Drive emulation + +**********************************************************************/ + +#pragma once + +#ifndef __C1571__ +#define __C1571__ + +#include "emu.h" +#include "cbmiec.h" +#include "bus/c64/bn1541.h" +#include "cpu/m6502/m6502.h" +#include "machine/64h156.h" +#include "machine/6522via.h" +#include "bus/isa/isa.h" +#include "bus/isa/wd1002a_wx1.h" +#include "machine/mos6526.h" +#include "machine/wd_fdc.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define C1571_TAG "c1571" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> c1571_t + +class c1571_t : public device_t, + public device_cbm_iec_interface, + public device_c64_floppy_parallel_interface +{ +public: + // construction/destruction + c1571_t(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + c1571_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + virtual ioport_constructor device_input_ports() const; + + DECLARE_WRITE_LINE_MEMBER( via0_irq_w ); + DECLARE_READ8_MEMBER( via0_pa_r ); + DECLARE_WRITE8_MEMBER( via0_pa_w ); + DECLARE_READ8_MEMBER( via0_pb_r ); + DECLARE_WRITE8_MEMBER( via0_pb_w ); + + DECLARE_READ8_MEMBER( via1_r ); + DECLARE_WRITE8_MEMBER( via1_w ); + DECLARE_WRITE_LINE_MEMBER( via1_irq_w ); + DECLARE_READ8_MEMBER( via1_pb_r ); + DECLARE_WRITE8_MEMBER( via1_pb_w ); + + DECLARE_WRITE_LINE_MEMBER( cia_irq_w ); + DECLARE_WRITE_LINE_MEMBER( cia_pc_w ); + DECLARE_WRITE_LINE_MEMBER( cia_cnt_w ); + DECLARE_WRITE_LINE_MEMBER( cia_sp_w ); + DECLARE_READ8_MEMBER( cia_pb_r ); + DECLARE_WRITE8_MEMBER( cia_pb_w ); + + DECLARE_WRITE_LINE_MEMBER( byte_w ); + + DECLARE_WRITE_LINE_MEMBER( wpt_w ); + + DECLARE_FLOPPY_FORMATS( floppy_formats ); + + void wpt_callback(floppy_image_device *floppy, int state); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_cbm_iec_interface overrides + virtual void cbm_iec_srq(int state); + virtual void cbm_iec_atn(int state); + virtual void cbm_iec_data(int state); + virtual void cbm_iec_reset(int state); + + // device_c64_floppy_parallel_interface overrides + virtual void parallel_data_w(UINT8 data); + virtual void parallel_strobe_w(int state); + + enum + { + LED_POWER = 0, + LED_ACT + }; + + void update_iec(); + + required_device m_maincpu; + required_device m_via0; + required_device m_via1; + required_device m_cia; + required_device m_fdc; + required_device m_ga; + required_device m_floppy; + required_ioport m_address; + + // signals + int m_1_2mhz; // clock speed + + // IEC bus + int m_data_out; // serial data out + int m_ser_dir; // fast serial direction + int m_sp_out; // fast serial data out + int m_cnt_out; // fast serial clock out + + // interrupts + int m_via0_irq; // VIA #0 interrupt request + int m_via1_irq; // VIA #1 interrupt request + int m_cia_irq; // CIA interrupt request +}; + + +// ======================> c1570_t + +class c1570_t : public c1571_t +{ +public: + // construction/destruction + c1570_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; +}; + + +// ======================> c1571cr_t + +class c1571cr_t : public c1571_t +{ +public: + // construction/destruction + c1571cr_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + + DECLARE_WRITE8_MEMBER( via0_pa_w ); + DECLARE_WRITE8_MEMBER( via0_pb_w ); +}; + + +// ======================> mini_chief_t + +class mini_chief_t : public c1571_t +{ +public: + // construction/destruction + mini_chief_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + + DECLARE_READ8_MEMBER( cia_pa_r ); + DECLARE_WRITE8_MEMBER( cia_pa_w ); + DECLARE_WRITE8_MEMBER( cia_pb_w ); +}; + + +// device type definition +extern const device_type C1570; +extern const device_type C1571; +extern const device_type C1571CR; +extern const device_type MINI_CHIEF; + + + +#endif diff --git a/src/devices/bus/cbmiec/c1581.c b/src/devices/bus/cbmiec/c1581.c new file mode 100644 index 00000000000..33bc082241e --- /dev/null +++ b/src/devices/bus/cbmiec/c1581.c @@ -0,0 +1,470 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Commodore 1581/1563 Single Disk Drive emulation + +**********************************************************************/ + +/* + + TODO: + + - drive not ready if ready_r() is connected to CIA + +*/ + +#include "c1581.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define M6502_TAG "u1" +#define M8520_TAG "u5" +#define WD1772_TAG "u4" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type C1563 = &device_creator; +const device_type C1581 = &device_creator; + + +//------------------------------------------------- +// ROM( c1581 ) +//------------------------------------------------- + +ROM_START( c1581 ) + ROM_REGION( 0x8000, M6502_TAG, 0 ) + ROM_DEFAULT_BIOS("r1") + ROM_SYSTEM_BIOS( 0, "beta", "Beta" ) + ROMX_LOAD( "beta.u2", 0x0000, 0x8000, CRC(ecc223cd) SHA1(a331d0d46ead1f0275b4ca594f87c6694d9d9594), ROM_BIOS(1) ) + ROM_SYSTEM_BIOS( 1, "r1", "Revision 1" ) + ROMX_LOAD( "318045-01.u2", 0x0000, 0x8000, CRC(113af078) SHA1(3fc088349ab83e8f5948b7670c866a3c954e6164), ROM_BIOS(2) ) + ROM_SYSTEM_BIOS( 2, "r2", "Revision 2" ) + ROMX_LOAD( "318045-02.u2", 0x0000, 0x8000, CRC(a9011b84) SHA1(01228eae6f066bd9b7b2b6a7fa3f667e41dad393), ROM_BIOS(3) ) + ROM_SYSTEM_BIOS( 3, "jiffydos", "JiffyDOS v6.01" ) + ROMX_LOAD( "jiffydos 1581.u2", 0x0000, 0x8000, CRC(98873d0f) SHA1(65bbf2be7bcd5bdcbff609d6c66471ffb9d04bfe), ROM_BIOS(4) ) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *c1581_t::device_rom_region() const +{ + return ROM_NAME( c1581 ); +} + + +//------------------------------------------------- +// ROM( c1563 ) +//------------------------------------------------- + +ROM_START( c1563 ) + ROM_REGION( 0x8000, M6502_TAG, 0 ) + ROM_LOAD( "1563-rom.bin", 0x0000, 0x8000, CRC(1d184687) SHA1(2c5111a9c15be7b7955f6c8775fea25ec10c0ca0) ) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *c1563_t::device_rom_region() const +{ + return ROM_NAME( c1563 ); +} + + +//------------------------------------------------- +// ADDRESS_MAP( c1581_mem ) +//------------------------------------------------- + +static ADDRESS_MAP_START( c1581_mem, AS_PROGRAM, 8, c1581_t ) + AM_RANGE(0x0000, 0x1fff) AM_MIRROR(0x2000) AM_RAM + AM_RANGE(0x4000, 0x400f) AM_MIRROR(0x1ff0) AM_DEVREADWRITE(M8520_TAG, mos8520_device, read, write) + AM_RANGE(0x6000, 0x6003) AM_MIRROR(0x1ffc) AM_DEVREADWRITE(WD1772_TAG, wd1772_t, read, write) + AM_RANGE(0x8000, 0xffff) AM_ROM AM_REGION(M6502_TAG, 0) +ADDRESS_MAP_END + + +//------------------------------------------------- +// MOS8520_INTERFACE( cia_intf ) +//------------------------------------------------- + +WRITE_LINE_MEMBER( c1581_t::cnt_w ) +{ + m_cnt_out = state; + + update_iec(); +} + +WRITE_LINE_MEMBER( c1581_t::sp_w ) +{ + m_sp_out = state; + + update_iec(); +} + +READ8_MEMBER( c1581_t::cia_pa_r ) +{ + /* + + bit description + + PA0 + PA1 /RDY + PA2 + PA3 DEV# SEL (SW1) + PA4 DEV# SEL (SW1) + PA5 + PA6 + PA7 /DISK CHNG + + */ + + UINT8 data = 0; + + // ready + //data |= !m_floppy->ready_r() << 1; + + // device number + data |= ((m_slot->get_address() - 8) & 0x03) << 3; + + // disk change + data |= m_floppy->dskchg_r() << 7; + + return data; +} + +WRITE8_MEMBER( c1581_t::cia_pa_w ) +{ + /* + + bit description + + PA0 SIDE0 + PA1 + PA2 /MOTOR + PA3 + PA4 + PA5 POWER LED + PA6 ACT LED + PA7 + + */ + + // side select + m_floppy->ss_w(BIT(data, 0)); + + // motor + m_floppy->mon_w(BIT(data, 2)); + + // power led + output_set_led_value(LED_POWER, BIT(data, 5)); + + // activity led + output_set_led_value(LED_ACT, BIT(data, 6)); +} + +READ8_MEMBER( c1581_t::cia_pb_r ) +{ + /* + + bit description + + PB0 DATA IN + PB1 + PB2 CLK IN + PB3 + PB4 + PB5 + PB6 /WPRT + PB7 ATN IN + + */ + + UINT8 data = 0; + + // data in + data = !m_bus->data_r(); + + // clock in + data |= !m_bus->clk_r() << 2; + + // write protect + data |= !m_floppy->wpt_r() << 6; + + // attention in + data |= !m_bus->atn_r() << 7; + + return data; +} + +WRITE8_MEMBER( c1581_t::cia_pb_w ) +{ + /* + + bit description + + PB0 + PB1 DATA OUT + PB2 + PB3 CLK OUT + PB4 ATN ACK + PB5 FAST SER DIR + PB6 + PB7 + + */ + + // data out + m_data_out = BIT(data, 1); + + // clock out + m_bus->clk_w(this, !BIT(data, 3)); + + // attention acknowledge + m_atn_ack = BIT(data, 4); + + // fast serial direction + m_fast_ser_dir = BIT(data, 5); + + update_iec(); +} + + +//------------------------------------------------- +// SLOT_INTERFACE( c1581_floppies ) +//------------------------------------------------- + +static SLOT_INTERFACE_START( c1581_floppies ) + SLOT_INTERFACE( "35dd", FLOPPY_35_DD ) // Chinon F-354-E +SLOT_INTERFACE_END + + +//------------------------------------------------- +// FLOPPY_FORMATS( c1581_t::floppy_formats ) +//------------------------------------------------- + +FLOPPY_FORMATS_MEMBER( c1581_t::floppy_formats ) + FLOPPY_D81_FORMAT +FLOPPY_FORMATS_END + + +//------------------------------------------------- +// MACHINE_DRIVER( c1581 ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( c1581 ) + MCFG_CPU_ADD(M6502_TAG, M6502, XTAL_16MHz/8) + MCFG_CPU_PROGRAM_MAP(c1581_mem) + + MCFG_DEVICE_ADD(M8520_TAG, MOS8520, XTAL_16MHz/8) + MCFG_MOS6526_IRQ_CALLBACK(INPUTLINE(M6502_TAG, INPUT_LINE_IRQ0)) + MCFG_MOS6526_CNT_CALLBACK(WRITELINE(c1581_t, cnt_w)) + MCFG_MOS6526_SP_CALLBACK(WRITELINE(c1581_t, sp_w)) + MCFG_MOS6526_PA_INPUT_CALLBACK(READ8(c1581_t, cia_pa_r)) + MCFG_MOS6526_PA_OUTPUT_CALLBACK(WRITE8(c1581_t, cia_pa_w)) + MCFG_MOS6526_PB_INPUT_CALLBACK(READ8(c1581_t, cia_pb_r)) + MCFG_MOS6526_PB_OUTPUT_CALLBACK(WRITE8(c1581_t, cia_pb_w)) + + MCFG_WD1772_ADD(WD1772_TAG, XTAL_16MHz/2) + MCFG_FLOPPY_DRIVE_ADD(WD1772_TAG":0", c1581_floppies, "35dd", c1581_t::floppy_formats) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor c1581_t::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( c1581 ); +} + + +//------------------------------------------------- +// INPUT_PORTS( c1581 ) +//------------------------------------------------- + +static INPUT_PORTS_START( c1581 ) + PORT_START("ADDRESS") + PORT_DIPNAME( 0x03, 0x00, "Device Address" ) + PORT_DIPSETTING( 0x00, "8" ) + PORT_DIPSETTING( 0x01, "9" ) + PORT_DIPSETTING( 0x02, "10" ) + PORT_DIPSETTING( 0x03, "11" ) +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor c1581_t::device_input_ports() const +{ + return INPUT_PORTS_NAME( c1581 ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// c1581_t - constructor +//------------------------------------------------- + +c1581_t::c1581_t(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_cbm_iec_interface(mconfig, *this), + m_maincpu(*this, M6502_TAG), + m_cia(*this, M8520_TAG), + m_fdc(*this, WD1772_TAG), + m_floppy(*this, WD1772_TAG":0:35dd"), + m_address(*this, "ADDRESS"), + m_data_out(0), + m_atn_ack(0), + m_fast_ser_dir(0), + m_sp_out(1), + m_cnt_out(1) +{ +} + +c1581_t::c1581_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, C1581, "C1581", tag, owner, clock, "c1581", __FILE__), + device_cbm_iec_interface(mconfig, *this), + m_maincpu(*this, M6502_TAG), + m_cia(*this, M8520_TAG), + m_fdc(*this, WD1772_TAG), + m_floppy(*this, WD1772_TAG":0:35dd"), + m_address(*this, "ADDRESS"), + m_data_out(0), + m_atn_ack(0), + m_fast_ser_dir(0), + m_sp_out(1), + m_cnt_out(1) +{ +} + + +//------------------------------------------------- +// c1563_t - constructor +//------------------------------------------------- + +c1563_t::c1563_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : c1581_t(mconfig, C1563, "C1563", tag, owner, clock, "c1563", __FILE__) { } + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void c1581_t::device_start() +{ + // state saving + save_item(NAME(m_data_out)); + save_item(NAME(m_atn_ack)); + save_item(NAME(m_fast_ser_dir)); + save_item(NAME(m_sp_out)); + save_item(NAME(m_cnt_out)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void c1581_t::device_reset() +{ + m_maincpu->reset(); + + m_cia->reset(); + m_fdc->reset(); + + m_fdc->set_floppy(m_floppy); + m_fdc->dden_w(0); + + m_sp_out = 1; + m_cnt_out = 1; + + update_iec(); +} + + +//------------------------------------------------- +// cbm_iec_srq - +//------------------------------------------------- + +void c1581_t::cbm_iec_srq(int state) +{ + update_iec(); +} + + +//------------------------------------------------- +// cbm_iec_atn - +//------------------------------------------------- + +void c1581_t::cbm_iec_atn(int state) +{ + update_iec(); +} + + +//------------------------------------------------- +// cbm_iec_data - +//------------------------------------------------- + +void c1581_t::cbm_iec_data(int state) +{ + update_iec(); +} + + +//------------------------------------------------- +// cbm_iec_reset - +//------------------------------------------------- + +void c1581_t::cbm_iec_reset(int state) +{ + if (!state) + { + device_reset(); + } +} + + +//------------------------------------------------- +// update_iec - +//------------------------------------------------- + +void c1581_t::update_iec() +{ + m_cia->cnt_w(m_fast_ser_dir || m_bus->srq_r()); + m_cia->sp_w(m_fast_ser_dir || m_bus->data_r()); + + int atn = m_bus->atn_r(); + m_cia->flag_w(atn); + + // serial data + int data = !m_data_out && !(m_atn_ack && !atn); + if (m_fast_ser_dir) data &= m_sp_out; + m_bus->data_w(this, data); + + // fast clock + int srq = 1; + if (m_fast_ser_dir) srq &= m_cnt_out; + m_bus->srq_w(this, srq); +} diff --git a/src/devices/bus/cbmiec/c1581.h b/src/devices/bus/cbmiec/c1581.h new file mode 100644 index 00000000000..4a2ac6a28a5 --- /dev/null +++ b/src/devices/bus/cbmiec/c1581.h @@ -0,0 +1,112 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Commodore 1581/1563 Single Disk Drive emulation + +**********************************************************************/ + +#pragma once + +#ifndef __C1581__ +#define __C1581__ + +#include "emu.h" +#include "cbmiec.h" +#include "cpu/m6502/m6502.h" +#include "formats/d81_dsk.h" +#include "machine/mos6526.h" +#include "machine/wd_fdc.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define C1581_TAG "c1581" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> c1581_t + +class c1581_t : public device_t, + public device_cbm_iec_interface +{ +public: + // construction/destruction + c1581_t(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + c1581_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + virtual ioport_constructor device_input_ports() const; + + // not really public + DECLARE_WRITE_LINE_MEMBER( cnt_w ); + DECLARE_WRITE_LINE_MEMBER( sp_w ); + DECLARE_READ8_MEMBER( cia_pa_r ); + DECLARE_WRITE8_MEMBER( cia_pa_w ); + DECLARE_READ8_MEMBER( cia_pb_r ); + DECLARE_WRITE8_MEMBER( cia_pb_w ); + + DECLARE_FLOPPY_FORMATS( floppy_formats ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_cbm_iec_interface overrides + virtual void cbm_iec_srq(int state); + virtual void cbm_iec_atn(int state); + virtual void cbm_iec_data(int state); + virtual void cbm_iec_reset(int state); + + enum + { + LED_POWER = 0, + LED_ACT + }; + + void update_iec(); + + required_device m_maincpu; + required_device m_cia; + required_device m_fdc; + required_device m_floppy; + required_ioport m_address; + + int m_data_out; // serial data out + int m_atn_ack; // attention acknowledge + int m_fast_ser_dir; // fast serial direction + int m_sp_out; // fast serial data out + int m_cnt_out; // fast serial clock out +}; + + +// ======================> c1563_t + +class c1563_t : public c1581_t +{ +public: + // construction/destruction + c1563_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; +}; + + +// device type definition +extern const device_type C1563; +extern const device_type C1581; + + + +#endif diff --git a/src/devices/bus/cbmiec/c64_nl10.c b/src/devices/bus/cbmiec/c64_nl10.c new file mode 100644 index 00000000000..970baa2f941 --- /dev/null +++ b/src/devices/bus/cbmiec/c64_nl10.c @@ -0,0 +1,102 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Star NL-10 Printer Interface Cartridge emulation + +**********************************************************************/ + +#include "c64_nl10.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type C64_NL10_INTERFACE = &device_creator; + + +//------------------------------------------------- +// ROM( c64_nl10_interface ) +//------------------------------------------------- + +ROM_START( c64_nl10_interface ) + ROM_REGION( 0x8000, "rom", 0 ) + ROM_LOAD( "nlc 1.5.ic2", 0x0000, 0x8000, CRC(748840b6) SHA1(5b3b9e8a93d5d77a49160b3d0c2489ba7be99c9a) ) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *c64_nl10_interface_device::device_rom_region() const +{ + return ROM_NAME( c64_nl10_interface ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// c64_nl10_interface_device - constructor +//------------------------------------------------- + +c64_nl10_interface_device::c64_nl10_interface_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, C64_NL10_INTERFACE, "Star NL-10 C64 Interface Cartridge", tag, owner, clock, "c64_nl10", __FILE__), + device_cbm_iec_interface(mconfig, *this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void c64_nl10_interface_device::device_start() +{ +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void c64_nl10_interface_device::device_reset() +{ +} + + +//------------------------------------------------- +// cbm_iec_atn - +//------------------------------------------------- + +void c64_nl10_interface_device::cbm_iec_atn(int state) +{ +} + + +//------------------------------------------------- +// cbm_iec_data - +//------------------------------------------------- + +void c64_nl10_interface_device::cbm_iec_data(int state) +{ +} + + +//------------------------------------------------- +// cbm_iec_reset - +//------------------------------------------------- + +void c64_nl10_interface_device::cbm_iec_reset(int state) +{ + if (!state) + { + device_reset(); + } +} diff --git a/src/devices/bus/cbmiec/c64_nl10.h b/src/devices/bus/cbmiec/c64_nl10.h new file mode 100644 index 00000000000..f0ceafd3f2d --- /dev/null +++ b/src/devices/bus/cbmiec/c64_nl10.h @@ -0,0 +1,52 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Star NL-10 Printer Interface Cartridge emulation + +**********************************************************************/ + +#pragma once + +#ifndef __C64_NL10_INTERFACE__ +#define __C64_NL10_INTERFACE__ + +#include "emu.h" +#include "cbmiec.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> c64_nl10_interface_device + +class c64_nl10_interface_device : public device_t, + public device_cbm_iec_interface +{ +public: + // construction/destruction + c64_nl10_interface_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_cbm_iec_interface overrides + void cbm_iec_atn(int state); + void cbm_iec_data(int state); + void cbm_iec_reset(int state); +}; + + +// device type definition +extern const device_type C64_NL10_INTERFACE; + + + +#endif diff --git a/src/devices/bus/cbmiec/cbmiec.c b/src/devices/bus/cbmiec/cbmiec.c new file mode 100644 index 00000000000..f546d2ac649 --- /dev/null +++ b/src/devices/bus/cbmiec/cbmiec.c @@ -0,0 +1,526 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Commodore IEC Serial Bus emulation + +**********************************************************************/ + +/* + +C64 SERIAL BUS + + + Serial Bus Pinouts + + + Pin Name Description + 1 SRQ Serial Service Request In + 2 GND Ground + 3 ATN Serial Attention In/Out + 4 CLK Serial Clock In/Out + 5 DATA Serial Data In/Out + 6 RESET Serial Reset + + All signals are active low. + + + SRQ: Serial Service Request In + + This signal is not used on the C64. On C128 it is replaced with Fast Serial + Clock for the 1571 disk drive. + + + ATN: Serial Attention In/Out + + Sending any byte with the ATN line low (sending under attention) causes it + to be interpreted as a Bus Command for peripherals on the serial bus. + + When the C64 brings this signal LOW, all other devices start listening for + it to transmit an address. The device addressed must respond in a preset + period of time; otherwise, the C64 will assume that the device addressed is + not on the bus, and will return an error in the STATUS word. + + Usually, the address byte will be followed by one to two commands for the + device addressed, meaning the secondary address and channel on the peripheral. + Such a command can be one of the following: + + 20 + 40 + 60 + E0 + F0 + + + CLK: Serial Clock In/Out + + This signal is for timing the data sent on the serial bus. This signal is + always generated by the active TALKER. RISING EDGE OF THE CLOCK means data + bit is valid. + + + DATA: Serial Data In/Out + + Data on the serial bus is transmitted bit by bit at a time on this line. + + + RESET: Serial Reset + + You may disconnect this line to save your disk drive. The easiest way is to + do that on the cable, thus avoiding any modifications on your peripherals. + + + + Serial Bus Timing + + ___ + CLK |____|~~~~| Ts Bit Set-up time + : Ts : Tv : Tv Bit Valid time + + + + |<--------- Byte sent under attention (to devices) ------------>| + + ___ ____ _____ _____ + ATN |________________________________________________________| + : : + ___ ______ ________ ___ ___ ___ ___ ___ ___ ___ ___ : + CLK : |_____| |_| |_| |_| |_| |_| |_| |_| |_| |______________ _____ + : : : : : + : Tat : :Th: Tne : : Tf : Tr : + ____ ________ : : :___________________________________:____: + DATA ___|\\\\\\\\\\__:__| |__||__||__||__||__||__||__||__| |_________ _____ + : 0 1 2 3 4 5 6 7 : + : LSB MSB : + : : : + : : Data Valid Listener: Data Accepted + : Listener READY-FOR-DATA + + + + + END-OR-IDENTIFY HANDSHAKE (LAST BYTE IN MESSAGE) + ___ _______________________________________________________________________ + ATN + ___ ___ ___ ________________ ___ ___ ___ ___ ___ ___ ___ ___ __ + CLK _| |_| |______| |_| |_| |_| |_| |_| |_| |_| |_| |_______|_ + : : : : : + :Tf:Tbb:Th:Tye:Tei:Try: :Tf :Tfr: + ____ __________: : :___: :_______________________________________: :_ + DATA |__||__| |______| |___| : |___|_ + 6 7 : : : : : : + MSB : : : : : Talker Sending : + : : : : Listener READY-FOR-DATA System + : : : EOI-Timeout Handshake Line Release + : : Listener READY-FOR-DATA + : Talker Ready-To-Send + + + + + TALK-ATTENTION TURN AROUND (TALKER AND LISTENER REVERSED) + ___ _________________________________________________________ + ATN _____________| + : + ___ ___ ___ : _____ ________ ___ ___ ___ ___ ___ ___ ___ ___ + CLK _| |_| |_________| |___| |_| |_| |_| |_| |_| |_| |_| |_| |_____ + : : : : : : : + :Tf:Tr:Ttk:Tdc:Tda:Th:Try: :Tf : + ____ __________: : : : :_______________________________________: + DATA |__||__| |_________________| :|__||__||__||__||__||__||__||__| |_ + 6 7 : : : : : : 0 1 2 3 4 5 6 7 + MSB : : : : : :LSB MSB + : : : : : : + : : : : : : Data Valid + : : : : : Listener READY-FOR-DATA + : : : : Talker Ready-To-Send + : : : Device acknowledges it's now TALKER. + : : Becomes LISTENER, Clock = High, Data = Low + : Talker Ready-To-Send + + + + + ___ _____________________________________________________________________ + ATN + ___ _________ ___ ___ ___ ___ ___ ___ ___ ___ ________ ___ ___ + CLK ____| |_| |_| |_| |_| |_| |_| |_| |_| |_______| |_| |_| |_ + : : : : : + :Th :Tne: :Tf :Tbb:Th:Tne: + ____ : :___:___________________________________: :_____________ + DATA ________| :|__||__||__||__||__||__||__||__| |______| + : : : 0 1 2 3 4 5 6 7 : + : : :LSB MSB : + : : : : + : : : TALKER SENDING Listener: Data Accepted + : : LISTENER READY-FOR-DATA + : TALKER READY-TO-SEND + + + + Serial Bus Timing + + + Description Symbol Min Typ Max + + ATN Response (required) 1) Tat - - 1000us + Listener Hold-Off Th 0 - oo + Non-EOI Response to RFD 2) Tne - 40us 200us + Bit Set-Up Talker 4) Ts 20us 70us - + Data Valid Tv 20us 20us - + Frame Handshake 3) Tf 0 20 1000us + Frame to Release of ATN Tr 20us - - + Between Bytes Time Tbb 100us - - + EOI Response Time Tye 200us 250us - + EOI Response Hold Time 5) Tei 60us - - + Talker Response Limit Try 0 30us 60us + Byte-Acknowledge 4) Tpr 20us 30us - + Talk-Attention Release Ttk 20us 30us 100us + Talk-Attention Acknowledge Tdc 0 - - + Talk-Attention Ack. Hold Tda 80us - - + EOI Acknowledge Tfr 60us - - + + + Notes: + 1) If maximum time exceeded, device not present error. + 2) If maximum time exceeded, EOI response required. + 3) If maximum time exceeded, frame error. + 4) Tv and Tpr minimum must be 60us for external device to be a talker. + 5) Tei minimum must be 80us for external device to be a listener. +*/ + +#include "cbmiec.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define LOG 0 + + +static const char *const SIGNAL_NAME[] = { "SRQ", "ATN", "CLK", "DATA", "RESET" }; + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type CBM_IEC = &device_creator; +const device_type CBM_IEC_SLOT = &device_creator; + + + +//************************************************************************** +// DEVICE INTERFACE +//************************************************************************** + +//------------------------------------------------- +// device_cbm_iec_interface - constructor +//------------------------------------------------- + +device_cbm_iec_interface::device_cbm_iec_interface(const machine_config &mconfig, device_t &device) + : device_slot_card_interface(mconfig, device) +{ +} + + +//------------------------------------------------- +// ~device_cbm_iec_interface - destructor +//------------------------------------------------- + +device_cbm_iec_interface::~device_cbm_iec_interface() +{ +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// cbm_iec_slot_device - constructor +//------------------------------------------------- + +cbm_iec_slot_device::cbm_iec_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, CBM_IEC_SLOT, "CBM IEC slot", tag, owner, clock, "cbm_iec_slot", __FILE__), + device_slot_interface(mconfig, *this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void cbm_iec_slot_device::device_start() +{ + cbm_iec_device* bus = NULL; + + for (device_t *device = owner(); device != NULL; device = device->owner()) + { + bus = device->subdevice(CBM_IEC_TAG); + if (bus != NULL) break; + } + + assert(bus); + + device_cbm_iec_interface *dev = dynamic_cast(get_card_device()); + if (dev) bus->add_device(this, get_card_device()); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// cbm_iec_device - constructor +//------------------------------------------------- + +cbm_iec_device::cbm_iec_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, CBM_IEC, "CBM IEC bus", tag, owner, clock, "cbm_iec", __FILE__), + m_write_srq(*this), + m_write_atn(*this), + m_write_clk(*this), + m_write_data(*this), + m_write_reset(*this) +{ + for (int i = 0; i < SIGNAL_COUNT; i++) + { + m_line[i] = 1; + } +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void cbm_iec_device::device_start() +{ + // resolve callbacks + m_write_srq.resolve_safe(); + m_write_atn.resolve_safe(); + m_write_clk.resolve_safe(); + m_write_data.resolve_safe(); + m_write_reset.resolve_safe(); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void cbm_iec_device::device_reset() +{ + reset_w(0); + reset_w(1); +} + + +//------------------------------------------------- +// device_stop - device-specific stop +//------------------------------------------------- + +void cbm_iec_device::device_stop() +{ + m_device_list.reset(); +} + + +//------------------------------------------------- +// add_device - +//------------------------------------------------- + +void cbm_iec_device::add_device(cbm_iec_slot_device *slot, device_t *target) +{ + daisy_entry *entry = global_alloc(daisy_entry(target)); + + entry->m_interface->m_slot = slot; + entry->m_interface->m_bus = this; + + m_device_list.append(*entry); +} + + +//------------------------------------------------- +// daisy_entry - constructor +//------------------------------------------------- + +cbm_iec_device::daisy_entry::daisy_entry(device_t *device) + : m_next(NULL), + m_device(device), + m_interface(NULL) +{ + for (int i = 0; i < SIGNAL_COUNT; i++) + { + m_line[i] = 1; + } + + device->interface(m_interface); +} + + +//------------------------------------------------- +// set_signal - +//------------------------------------------------- + +void cbm_iec_device::set_signal(device_t *device, int signal, int state) +{ + bool changed = false; + + if (device == this) + { + if (m_line[signal] != state) + { + if (LOG) logerror("CBM IEC: '%s' %s %u\n", tag(), SIGNAL_NAME[signal], state); + m_line[signal] = state; + changed = true; + } + } + else + { + daisy_entry *entry = m_device_list.first(); + + while (entry) + { + if (!strcmp(entry->m_device->tag(), device->tag())) + { + if (entry->m_line[signal] != state) + { + if (LOG) logerror("CBM IEC: '%s' %s %u\n", device->tag(), SIGNAL_NAME[signal], state); + entry->m_line[signal] = state; + changed = true; + } + } + + entry = entry->next(); + } + } + + if (changed) + { + switch (signal) + { + case SRQ: m_write_srq(state); break; + case ATN: m_write_atn(state); break; + case CLK: m_write_clk(state); break; + case DATA: m_write_data(state); break; + case RESET: m_write_reset(state);break; + } + + daisy_entry *entry = m_device_list.first(); + + while (entry) + { + switch (signal) + { + case SRQ: + entry->m_interface->cbm_iec_srq(state); + break; + + case ATN: + entry->m_interface->cbm_iec_atn(state); + break; + + case CLK: + entry->m_interface->cbm_iec_clk(state); + break; + + case DATA: + entry->m_interface->cbm_iec_data(state); + break; + + case RESET: + entry->m_interface->cbm_iec_reset(state); + break; + } + + entry = entry->next(); + } + + if (LOG) logerror("CBM IEC: SRQ %u ATN %u CLK %u DATA %u RESET %u\n", + get_signal(SRQ), get_signal(ATN), get_signal(CLK), get_signal(DATA), get_signal(RESET)); + } +} + + +//------------------------------------------------- +// get_signal - +//------------------------------------------------- + +int cbm_iec_device::get_signal(int signal) +{ + int state = m_line[signal]; + + if (state) + { + daisy_entry *entry = m_device_list.first(); + + while (entry) + { + if (!entry->m_line[signal]) + { + state = 0; + break; + } + + entry = entry->next(); + } + } + + return state; +} + + +//------------------------------------------------- +// SLOT_INTERFACE( cbm_iec_devices ) +//------------------------------------------------- + +// slot devices +#include "c1541.h" +#include "c1571.h" +#include "c1581.h" +#include "c64_nl10.h" +#include "cmdhd.h" +#include "diag264_lb_iec.h" +#include "fd2000.h" +#include "interpod.h" +#include "serialbox.h" +#include "vic1515.h" +#include "vic1520.h" +#include "c1526.h" + +SLOT_INTERFACE_START( cbm_iec_devices ) + SLOT_INTERFACE("c1540", C1540) + SLOT_INTERFACE("c1541", C1541) + SLOT_INTERFACE("c1541c", C1541C) + SLOT_INTERFACE("c1541ii", C1541II) + SLOT_INTERFACE("fsd1", FSD1) + SLOT_INTERFACE("fsd2", FSD2) + SLOT_INTERFACE("csd1", CSD1) + SLOT_INTERFACE("c1541dd", C1541_DOLPHIN_DOS) + SLOT_INTERFACE("c1541pd", C1541_PROFESSIONAL_DOS_V1) + SLOT_INTERFACE("c1541pdc", C1541_PROLOGIC_DOS_CLASSIC) + SLOT_INTERFACE("c1570", C1570) + SLOT_INTERFACE("c1571", C1571) + SLOT_INTERFACE("c1581", C1581) + SLOT_INTERFACE("indusgt", INDUS_GT) + SLOT_INTERFACE("cmdhd", CMD_HD) + SLOT_INTERFACE("fd2000", FD2000) + SLOT_INTERFACE("fd4000", FD4000) + SLOT_INTERFACE("interpod", INTERPOD) + SLOT_INTERFACE("minichief", MINI_CHIEF) + SLOT_INTERFACE("serialbox", SERIAL_BOX) + SLOT_INTERFACE("diag264", DIAG264_SERIAL_LOOPBACK) + SLOT_INTERFACE("nl10", C64_NL10_INTERFACE) + SLOT_INTERFACE("vic1515", VIC1515) + SLOT_INTERFACE("vic1520", VIC1520) + SLOT_INTERFACE("c1526", C1526) + SLOT_INTERFACE("mps802", MPS802) +SLOT_INTERFACE_END diff --git a/src/devices/bus/cbmiec/cbmiec.h b/src/devices/bus/cbmiec/cbmiec.h new file mode 100644 index 00000000000..627e3dc203f --- /dev/null +++ b/src/devices/bus/cbmiec/cbmiec.h @@ -0,0 +1,210 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Commodore IEC Serial Bus emulation + +**********************************************************************/ + +#pragma once + +#ifndef __CBM_IEC__ +#define __CBM_IEC__ + +#include "emu.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define CBM_IEC_TAG "iec_bus" + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_CBM_IEC_BUS_ADD() \ + MCFG_DEVICE_ADD(CBM_IEC_TAG, CBM_IEC, 0) + + +#define MCFG_CBM_IEC_BUS_SRQ_CALLBACK(_write) \ + downcast(device)->set_srq_callback(DEVCB_##_write); + +#define MCFG_CBM_IEC_BUS_ATN_CALLBACK(_write) \ + downcast(device)->set_atn_callback(DEVCB_##_write); + +#define MCFG_CBM_IEC_BUS_CLK_CALLBACK(_write) \ + downcast(device)->set_clk_callback(DEVCB_##_write); + +#define MCFG_CBM_IEC_BUS_DATA_CALLBACK(_write) \ + downcast(device)->set_data_callback(DEVCB_##_write); + +#define MCFG_CBM_IEC_BUS_RESET_CALLBACK(_write) \ + downcast(device)->set_reset_callback(DEVCB_##_write); + + +#define MCFG_CBM_IEC_SLOT_ADD(_tag, _address, _slot_intf, _def_slot) \ + MCFG_DEVICE_ADD(_tag, CBM_IEC_SLOT, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) \ + downcast(device)->set_address(_address); + + +#define MCFG_CBM_IEC_ADD(_default_drive) \ + MCFG_CBM_IEC_SLOT_ADD("iec4", 4, cbm_iec_devices, NULL) \ + MCFG_CBM_IEC_SLOT_ADD("iec8", 8, cbm_iec_devices, _default_drive) \ + MCFG_CBM_IEC_SLOT_ADD("iec9", 9, cbm_iec_devices, NULL) \ + MCFG_CBM_IEC_SLOT_ADD("iec10", 10, cbm_iec_devices, NULL) \ + MCFG_CBM_IEC_SLOT_ADD("iec11", 11, cbm_iec_devices, NULL) \ + MCFG_CBM_IEC_BUS_ADD() + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> cbm_iec_device + +class cbm_iec_slot_device; +class device_cbm_iec_interface; + +class cbm_iec_device : public device_t +{ +public: + // construction/destruction + cbm_iec_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + template void set_srq_callback(_write wr) { m_write_srq.set_callback(wr); } + template void set_atn_callback(_write wr) { m_write_atn.set_callback(wr); } + template void set_clk_callback(_write wr) { m_write_clk.set_callback(wr); } + template void set_data_callback(_write wr) { m_write_data.set_callback(wr); } + template void set_reset_callback(_write wr) { m_write_reset.set_callback(wr); } + + void add_device(cbm_iec_slot_device *slot, device_t *target); + + // reads for both host and peripherals + DECLARE_READ_LINE_MEMBER( srq_r ) { return get_signal(SRQ); } + DECLARE_READ_LINE_MEMBER( atn_r ) { return get_signal(ATN); } + DECLARE_READ_LINE_MEMBER( clk_r ) { return get_signal(CLK); } + DECLARE_READ_LINE_MEMBER( data_r ) { return get_signal(DATA); } + DECLARE_READ_LINE_MEMBER( reset_r ) { return get_signal(RESET); } + + // writes for host (driver_device) + DECLARE_WRITE_LINE_MEMBER( srq_w ) { set_signal(this, SRQ, state); } + DECLARE_WRITE_LINE_MEMBER( atn_w ) { set_signal(this, ATN, state); } + DECLARE_WRITE_LINE_MEMBER( clk_w ) { set_signal(this, CLK, state); } + DECLARE_WRITE_LINE_MEMBER( data_w ) { set_signal(this, DATA, state); } + DECLARE_WRITE_LINE_MEMBER( reset_w ) { set_signal(this, RESET, state); } + + // writes for peripherals (device_t) + void srq_w(device_t *device, int state) { set_signal(device, SRQ, state); } + void atn_w(device_t *device, int state) { set_signal(device, ATN, state); } + void clk_w(device_t *device, int state) { set_signal(device, CLK, state); } + void data_w(device_t *device, int state) { set_signal(device, DATA, state); } + void reset_w(device_t *device, int state) { set_signal(device, RESET, state); } + +protected: + enum + { + SRQ = 0, + ATN, + CLK, + DATA, + RESET, + SIGNAL_COUNT + }; + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_stop(); + + class daisy_entry + { + public: + daisy_entry(device_t *device); + daisy_entry *next() const { return m_next; } + + daisy_entry * m_next; // next device + device_t * m_device; // associated device + device_cbm_iec_interface * m_interface; // associated device's daisy interface + + int m_line[SIGNAL_COUNT]; + }; + + simple_list m_device_list; + +private: + devcb_write_line m_write_srq; + devcb_write_line m_write_atn; + devcb_write_line m_write_clk; + devcb_write_line m_write_data; + devcb_write_line m_write_reset; + + void set_signal(device_t *device, int signal, int state); + int get_signal(int signal); + + int m_line[SIGNAL_COUNT]; +}; + + +// ======================> cbm_iec_slot_device + +class cbm_iec_slot_device : public device_t, + public device_slot_interface +{ +public: + // construction/destruction + cbm_iec_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + void set_address(int address) { m_address = address; } + int get_address() { return m_address; } + + // device-level overrides + virtual void device_start(); + +protected: + int m_address; +}; + + +// ======================> device_cbm_iec_interface + +class device_cbm_iec_interface : public device_slot_card_interface +{ + friend class cbm_iec_device; + +public: + // construction/destruction + device_cbm_iec_interface(const machine_config &mconfig, device_t &device); + virtual ~device_cbm_iec_interface(); + + device_cbm_iec_interface *next() const { return m_next; } + device_cbm_iec_interface *m_next; + + // optional operation overrides + virtual void cbm_iec_srq(int state) { }; + virtual void cbm_iec_atn(int state) { }; + virtual void cbm_iec_clk(int state) { }; + virtual void cbm_iec_data(int state) { }; + virtual void cbm_iec_reset(int state) { }; + + cbm_iec_device *m_bus; + cbm_iec_slot_device *m_slot; +}; + + +// device type definition +extern const device_type CBM_IEC; +extern const device_type CBM_IEC_SLOT; + + +SLOT_INTERFACE_EXTERN( cbm_iec_devices ); + + + +#endif diff --git a/src/devices/bus/cbmiec/cmdhd.c b/src/devices/bus/cbmiec/cmdhd.c new file mode 100644 index 00000000000..d3025700fa7 --- /dev/null +++ b/src/devices/bus/cbmiec/cmdhd.c @@ -0,0 +1,198 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + CMD HD hard drive emulation + +**********************************************************************/ + +#include "cmdhd.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define M6502_TAG "m6502" +#define M6522_1_TAG "m6522_1" +#define M6522_2_TAG "m6522_2" +#define I8255A_TAG "i8255a" +#define RTC72421A_TAG "rtc" +#define SCSIBUS_TAG "scsi" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type CMD_HD = &device_creator; + + +//------------------------------------------------- +// ROM( cmd_hd ) +//------------------------------------------------- + +ROM_START( cmd_hd ) + ROM_REGION( 0x8000, M6502_TAG, 0 ) + ROM_LOAD( "cmd_hd_bootrom_v280.bin", 0x0000, 0x8000, CRC(da68435d) SHA1(defd8bc04a52904b8a3560f11c82126619513a10) ) + + ROM_REGION( 0x104, "plds", 0 ) + ROM_LOAD( "pal16l8_1", 0x000, 0x001, NO_DUMP ) + ROM_LOAD( "pal16l8_2", 0x000, 0x001, NO_DUMP ) + ROM_LOAD( "pal16l8_3", 0x000, 0x001, NO_DUMP ) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *cmd_hd_device::device_rom_region() const +{ + return ROM_NAME( cmd_hd ); +} + + +//------------------------------------------------- +// ADDRESS_MAP( cmd_hd_mem ) +//------------------------------------------------- + +static ADDRESS_MAP_START( cmd_hd_mem, AS_PROGRAM, 8, cmd_hd_device ) + AM_RANGE(0x0000, 0x7fff) AM_RAM + AM_RANGE(0x8000, 0xffff) AM_ROM AM_REGION(M6502_TAG, 0) + AM_RANGE(0x8000, 0x800f) AM_MIRROR(0x1f0) AM_DEVREADWRITE(M6522_1_TAG, via6522_device, read, write) + AM_RANGE(0x8400, 0x840f) AM_MIRROR(0x1f0) AM_DEVREADWRITE(M6522_2_TAG, via6522_device, read, write) + AM_RANGE(0x8800, 0x8803) AM_MIRROR(0x1fc) AM_DEVREADWRITE(I8255A_TAG, i8255_device, read, write) + AM_RANGE(0x8c00, 0x8c0f) AM_MIRROR(0x1f0) //AM_DEVREADWRITE(RTC72421A_TAG, rtc72421a_device, read, write) + AM_RANGE(0x8f00, 0x8f00) AM_MIRROR(0xff) AM_WRITE(led_w) +ADDRESS_MAP_END + + +//------------------------------------------------- +// MACHINE_DRIVER( cmd_hd ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( cmd_hd ) + MCFG_CPU_ADD(M6502_TAG, M6502, 2000000) + MCFG_CPU_PROGRAM_MAP(cmd_hd_mem) + + MCFG_DEVICE_ADD(M6522_1_TAG, VIA6522, 2000000) + MCFG_DEVICE_ADD(M6522_2_TAG, VIA6522, 2000000) + MCFG_DEVICE_ADD(I8255A_TAG, I8255A, 0) + //MCFG_RTC72421A_ADD(RTC72421A_TAG) + + MCFG_DEVICE_ADD(SCSIBUS_TAG, SCSI_PORT, 0) + MCFG_SCSIDEV_ADD(SCSIBUS_TAG ":" SCSI_PORT_DEVICE1, "harddisk", SCSIHD, SCSI_ID_0) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor cmd_hd_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( cmd_hd ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// cmd_hd_device - constructor +//------------------------------------------------- + +cmd_hd_device::cmd_hd_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, CMD_HD, "HD", tag, owner, clock, "cmdhd", __FILE__), + device_cbm_iec_interface(mconfig, *this), + m_maincpu(*this, M6502_TAG), + m_scsibus(*this, SCSIBUS_TAG) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void cmd_hd_device::device_start() +{ +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void cmd_hd_device::device_reset() +{ +} + + +//------------------------------------------------- +// cbm_iec_srq - +//------------------------------------------------- + +void cmd_hd_device::cbm_iec_srq(int state) +{ +} + + +//------------------------------------------------- +// cbm_iec_atn - +//------------------------------------------------- + +void cmd_hd_device::cbm_iec_atn(int state) +{ +} + + +//------------------------------------------------- +// cbm_iec_data - +//------------------------------------------------- + +void cmd_hd_device::cbm_iec_data(int state) +{ +} + + +//------------------------------------------------- +// cbm_iec_reset - +//------------------------------------------------- + +void cmd_hd_device::cbm_iec_reset(int state) +{ + if (!state) + { + device_reset(); + } +} + + +//------------------------------------------------- +// led_w - +//------------------------------------------------- + +WRITE8_MEMBER( cmd_hd_device::led_w ) +{ + /* + + bit description + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + + */ +} diff --git a/src/devices/bus/cbmiec/cmdhd.h b/src/devices/bus/cbmiec/cmdhd.h new file mode 100644 index 00000000000..f71c0ad2741 --- /dev/null +++ b/src/devices/bus/cbmiec/cmdhd.h @@ -0,0 +1,72 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + CMD HD disk drive emulation + +**********************************************************************/ + +#pragma once + +#ifndef __CMD_HD__ +#define __CMD_HD__ + +#include "emu.h" +#include "cbmiec.h" +#include "cpu/m6502/m6502.h" +#include "imagedev/harddriv.h" +#include "machine/6522via.h" +#include "machine/i8255.h" +#include "bus/scsi/scsihd.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define CMD_HD_TAG "cmdhd" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> cmd_hd_device + +class cmd_hd_device : public device_t, + public device_cbm_iec_interface +{ +public: + // construction/destruction + cmd_hd_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + + DECLARE_WRITE8_MEMBER( led_w ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_cbm_iec_interface overrides + void cbm_iec_srq(int state); + void cbm_iec_atn(int state); + void cbm_iec_data(int state); + void cbm_iec_reset(int state); + + required_device m_maincpu; + required_device m_scsibus; +}; + + +// device type definition +extern const device_type CMD_HD; + + + +#endif diff --git a/src/devices/bus/cbmiec/diag264_lb_iec.c b/src/devices/bus/cbmiec/diag264_lb_iec.c new file mode 100644 index 00000000000..d9c2e5ed303 --- /dev/null +++ b/src/devices/bus/cbmiec/diag264_lb_iec.c @@ -0,0 +1,52 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Diag264 Serial Loop Back Connector emulation + +**********************************************************************/ + +#include "diag264_lb_iec.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type DIAG264_SERIAL_LOOPBACK = &device_creator; + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// diag264_serial_loopback_device - constructor +//------------------------------------------------- + +diag264_serial_loopback_device::diag264_serial_loopback_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, DIAG264_SERIAL_LOOPBACK, "Diag264 Serial Loopback", tag, owner, clock, "diag264_serial_loopback", __FILE__), + device_cbm_iec_interface(mconfig, *this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void diag264_serial_loopback_device::device_start() +{ +} + + +//------------------------------------------------- +// cbm_iec_atn - +//------------------------------------------------- + +void diag264_serial_loopback_device::cbm_iec_atn(int state) +{ + m_bus->clk_w(state); +} diff --git a/src/devices/bus/cbmiec/diag264_lb_iec.h b/src/devices/bus/cbmiec/diag264_lb_iec.h new file mode 100644 index 00000000000..ac963ec231e --- /dev/null +++ b/src/devices/bus/cbmiec/diag264_lb_iec.h @@ -0,0 +1,46 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Diag264 Serial Loop Back Connector emulation + +**********************************************************************/ + +#pragma once + +#ifndef __DIAG264_IEC_LOOPBACK__ +#define __DIAG264_IEC_LOOPBACK__ + +#include "emu.h" +#include "cbmiec.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> diag264_serial_loopback_device + +class diag264_serial_loopback_device : public device_t, + public device_cbm_iec_interface +{ +public: + // construction/destruction + diag264_serial_loopback_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // device-level overrides + virtual void device_start(); + + // device_cbm_iec_interface overrides + virtual void cbm_iec_atn(int state); +}; + + +// device type definition +extern const device_type DIAG264_SERIAL_LOOPBACK; + + + +#endif diff --git a/src/devices/bus/cbmiec/fd2000.c b/src/devices/bus/cbmiec/fd2000.c new file mode 100644 index 00000000000..d31b9d97507 --- /dev/null +++ b/src/devices/bus/cbmiec/fd2000.c @@ -0,0 +1,361 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + CMD FD-2000/FD-4000 disk drive emulation + +**********************************************************************/ + +/* + + TODO: + + - IEC + - VIA + - DP8473/PC8477A command extensions to upd765 + - D1M/D2M/D4M image format (http://ist.uwaterloo.ca/~schepers/formats/D2M-DNP.TXT) + +*/ + +#include "fd2000.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define G65SC02PI2_TAG "m6502" +#define R65C02P4_TAG "m6502" +#define G65SC22P2_TAG "m6522" +#define DP8473V_TAG "dp8473" +#define PC8477AV1_TAG "pc8477av1" +#define DS1216E_TAG "ds1216e" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type FD2000 = &device_creator; +const device_type FD4000 = &device_creator; + + +//------------------------------------------------- +// ROM( fd2000 ) +//------------------------------------------------- + +ROM_START( fd2000 ) + ROM_REGION( 0x8000, G65SC02PI2_TAG, 0 ) + ROM_DEFAULT_BIOS( "v140" ) + ROM_SYSTEM_BIOS( 0, "v134", "Version 1.34" ) + ROMX_LOAD( "cmd fd-2000 dos v1.34 fd-350026.bin", 0x0000, 0x8000, CRC(859a5edc) SHA1(487fa82a7977e5208d5088f3580f34e8c89560d1), ROM_BIOS(1) ) + ROM_SYSTEM_BIOS( 1, "v140", "Version 1.40" ) + ROMX_LOAD( "cmd fd-2000 dos v1.40 cs 33cc6f.bin", 0x0000, 0x8000, CRC(4e6ca15c) SHA1(0c61ba58269baf2b8aadf3bbc4648c7a5a6d2128), ROM_BIOS(2) ) +ROM_END + + +//------------------------------------------------- +// ROM( fd4000 ) +//------------------------------------------------- + +ROM_START( fd4000 ) + ROM_REGION( 0x8000, R65C02P4_TAG, 0 ) + ROM_DEFAULT_BIOS( "v140" ) + ROM_SYSTEM_BIOS( 0, "v134", "Version 1.34" ) + ROMX_LOAD( "cmd fd-4000 dos v1.34 fd-350022.bin", 0x0000, 0x8000, CRC(1f4820c1) SHA1(7a2966662e7840fd9377549727ccba62e4349c6f), ROM_BIOS(1) ) + ROM_SYSTEM_BIOS( 1, "v140", "Version 1.40" ) + ROMX_LOAD( "cmd fd-4000 dos v1.40 fd-350022.bin", 0x0000, 0x8000, CRC(b563ef10) SHA1(d936d76fd8b50ce4c65f885703653d7c1bd7d3c9), ROM_BIOS(2) ) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *fd2000_device::device_rom_region() const +{ + switch (m_variant) + { + default: + return ROM_NAME( fd2000 ); + + case TYPE_FD4000: + return ROM_NAME( fd4000 ); + } +} + + +//------------------------------------------------- +// ADDRESS_MAP( fd2000_mem ) +//------------------------------------------------- + +static ADDRESS_MAP_START( fd2000_mem, AS_PROGRAM, 8, fd2000_device ) + AM_RANGE(0x0000, 0x3fff) AM_RAM + AM_RANGE(0x4000, 0x400f) AM_MIRROR(0xbf0) AM_DEVREADWRITE(G65SC22P2_TAG, via6522_device, read, write) + AM_RANGE(0x4e00, 0x4e07) AM_MIRROR(0x1f8) AM_DEVICE(DP8473V_TAG, dp8473_device, map) + AM_RANGE(0x5000, 0x7fff) AM_RAM + AM_RANGE(0x8000, 0xffff) AM_ROM AM_REGION(G65SC02PI2_TAG, 0) +ADDRESS_MAP_END + + +//------------------------------------------------- +// ADDRESS_MAP( fd4000_mem ) +//------------------------------------------------- + +static ADDRESS_MAP_START( fd4000_mem, AS_PROGRAM, 8, fd4000_device ) + AM_RANGE(0x0000, 0x3fff) AM_RAM + AM_RANGE(0x4000, 0x400f) AM_MIRROR(0xbf0) AM_DEVREADWRITE(G65SC22P2_TAG, via6522_device, read, write) + AM_RANGE(0x4e00, 0x4e07) AM_MIRROR(0x1f8) AM_DEVICE(PC8477AV1_TAG, pc8477a_device, map) + AM_RANGE(0x5000, 0x7fff) AM_RAM + AM_RANGE(0x8000, 0xffff) AM_ROM AM_REGION(R65C02P4_TAG, 0) +ADDRESS_MAP_END + + +READ8_MEMBER( fd2000_device::via_pa_r ) +{ + /* + + bit description + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + + */ + + return 0; +} + +WRITE8_MEMBER( fd2000_device::via_pa_w ) +{ + /* + + bit description + + 0 + 1 + 2 + 3 + 4 + 5 FAST DIR + 6 + 7 + + */ +} + +READ8_MEMBER( fd2000_device::via_pb_r ) +{ + /* + + bit description + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 FDC INTRQ + + */ + + UINT8 data = 0; + + // FDC interrupt + data |= m_fdc->get_irq() << 7; + + return data; +} + +WRITE8_MEMBER( fd2000_device::via_pb_w ) +{ + /* + + bit description + + 0 + 1 + 2 + 3 + 4 + 5 LED + 6 LED + 7 + + */ +} + +static SLOT_INTERFACE_START( fd2000_floppies ) + SLOT_INTERFACE( "35hd", FLOPPY_35_HD ) // TEAC FD-235HF +SLOT_INTERFACE_END + +static SLOT_INTERFACE_START( fd4000_floppies ) + SLOT_INTERFACE( "35ed", FLOPPY_35_ED ) // TEAC FD-235J +SLOT_INTERFACE_END +/* +FLOPPY_FORMATS_MEMBER( fd2000_device::floppy_formats ) + FLOPPY_D81_FORMAT + FLOPPY_D2M_FORMAT +FLOPPY_FORMATS_END +*/ + +//------------------------------------------------- +// MACHINE_DRIVER( fd2000 ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( fd2000 ) + MCFG_CPU_ADD(G65SC02PI2_TAG, M65C02, XTAL_24MHz/12) + MCFG_CPU_PROGRAM_MAP(fd2000_mem) + + MCFG_DEVICE_ADD(G65SC22P2_TAG, VIA6522, XTAL_24MHz/12) + MCFG_VIA6522_READPA_HANDLER(READ8(fd2000_device, via_pa_r)) + MCFG_VIA6522_READPB_HANDLER(READ8(fd2000_device, via_pb_r)) + MCFG_VIA6522_WRITEPA_HANDLER(WRITE8(fd2000_device, via_pa_w)) + MCFG_VIA6522_WRITEPB_HANDLER(WRITE8(fd2000_device, via_pb_w)) + + MCFG_DP8473_ADD(DP8473V_TAG) + + MCFG_FLOPPY_DRIVE_ADD(DP8473V_TAG":0", fd2000_floppies, "35hd", floppy_image_device::default_floppy_formats)//fd2000_device::floppy_formats) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// MACHINE_DRIVER( fd4000 ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( fd4000 ) + MCFG_CPU_ADD(R65C02P4_TAG, M65C02, XTAL_24MHz/6) + MCFG_CPU_PROGRAM_MAP(fd4000_mem) + + MCFG_DEVICE_ADD(G65SC22P2_TAG, VIA6522, XTAL_24MHz/12) + MCFG_VIA6522_READPA_HANDLER(READ8(fd2000_device, via_pa_r)) + MCFG_VIA6522_READPB_HANDLER(READ8(fd2000_device, via_pb_r)) + MCFG_VIA6522_WRITEPA_HANDLER(WRITE8(fd2000_device, via_pa_w)) + MCFG_VIA6522_WRITEPB_HANDLER(WRITE8(fd2000_device, via_pb_w)) + + MCFG_PC8477A_ADD(PC8477AV1_TAG) + + MCFG_FLOPPY_DRIVE_ADD(PC8477AV1_TAG":0", fd4000_floppies, "35ed", floppy_image_device::default_floppy_formats)//fd2000_device::floppy_formats) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor fd2000_device::device_mconfig_additions() const +{ + switch (m_variant) + { + default: + return MACHINE_CONFIG_NAME( fd2000 ); + + case TYPE_FD4000: + return MACHINE_CONFIG_NAME( fd4000 ); + } +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// fd2000_device - constructor +//------------------------------------------------- + +fd2000_device::fd2000_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, FD2000, "FD-2000", tag, owner, clock, "fd2000", __FILE__), + device_cbm_iec_interface(mconfig, *this), + m_maincpu(*this, G65SC02PI2_TAG), + m_fdc(*this, DP8473V_TAG), + m_floppy0(*this, DP8473V_TAG":0"), + m_variant(TYPE_FD2000) +{ +} + +fd2000_device::fd2000_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, UINT32 variant, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_cbm_iec_interface(mconfig, *this), + m_maincpu(*this, R65C02P4_TAG), + m_fdc(*this, PC8477AV1_TAG), + m_floppy0(*this, PC8477AV1_TAG":0"), + m_variant(variant) +{ +} + + +//------------------------------------------------- +// fd4000_device - constructor +//------------------------------------------------- + +fd4000_device::fd4000_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : fd2000_device(mconfig, FD4000, "FD-4000", tag, owner, clock, TYPE_FD4000, "fd4000", __FILE__ ) { } + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void fd2000_device::device_start() +{ +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void fd2000_device::device_reset() +{ +} + + +//------------------------------------------------- +// cbm_iec_srq - +//------------------------------------------------- + +void fd2000_device::cbm_iec_srq(int state) +{ +} + + +//------------------------------------------------- +// cbm_iec_atn - +//------------------------------------------------- + +void fd2000_device::cbm_iec_atn(int state) +{ +} + + +//------------------------------------------------- +// cbm_iec_data - +//------------------------------------------------- + +void fd2000_device::cbm_iec_data(int state) +{ +} + + +//------------------------------------------------- +// cbm_iec_reset - +//------------------------------------------------- + +void fd2000_device::cbm_iec_reset(int state) +{ + if (!state) + { + device_reset(); + } +} diff --git a/src/devices/bus/cbmiec/fd2000.h b/src/devices/bus/cbmiec/fd2000.h new file mode 100644 index 00000000000..00ff81a038d --- /dev/null +++ b/src/devices/bus/cbmiec/fd2000.h @@ -0,0 +1,97 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + CMD FD-2000/FD-4000 disk drive emulation + +**********************************************************************/ + +#pragma once + +#ifndef __FD2000__ +#define __FD2000__ + +#include "emu.h" +#include "cbmiec.h" +#include "cpu/m6502/m65c02.h" +#include "formats/d81_dsk.h" +#include "machine/6522via.h" +#include "machine/upd765.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define FD2000_TAG "fd2000" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> fd2000_device + +class fd2000_device : public device_t, + public device_cbm_iec_interface +{ +public: + // construction/destruction + fd2000_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + fd2000_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, UINT32 variant, const char *shortname, const char *source); + + enum + { + TYPE_FD2000, + TYPE_FD4000 + }; + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + + DECLARE_READ8_MEMBER( via_pa_r ); + DECLARE_WRITE8_MEMBER( via_pa_w ); + DECLARE_READ8_MEMBER( via_pb_r ); + DECLARE_WRITE8_MEMBER( via_pb_w ); + + //DECLARE_FLOPPY_FORMATS( floppy_formats ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_cbm_iec_interface overrides + void cbm_iec_srq(int state); + void cbm_iec_atn(int state); + void cbm_iec_data(int state); + void cbm_iec_reset(int state); + + required_device m_maincpu; + required_device m_fdc; + required_device m_floppy0; + + int m_variant; +}; + + +// ======================> fd4000_device + +class fd4000_device : public fd2000_device +{ +public: + // construction/destruction + fd4000_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +// device type definition +extern const device_type FD2000; +extern const device_type FD4000; + + + +#endif diff --git a/src/devices/bus/cbmiec/interpod.c b/src/devices/bus/cbmiec/interpod.c new file mode 100644 index 00000000000..0326210bb54 --- /dev/null +++ b/src/devices/bus/cbmiec/interpod.c @@ -0,0 +1,182 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Oxford Computer Systems Interpod IEC to IEEE interface emulation + +*********************************************************************/ + +/* + +PCB Layout +---------- + +INTERPOD 1000 ISS.3 + +|---------------------------------------| +| | +| ACIA ROM CPU | +| | +|CN1 75188 LS73 LS04 RIOT | +| 75189 | +| 7417 VIA | +|CN2 | +| 3446 3446 3446 | +| CN3 CN4 LD1 | +|---------------------------| CN5 |-| + |---------| + +Notes: + All IC's shown. + + ROM - 2716 "1.4" + CPU - Rockwell R6502P + RIOT - Rockwell R6532AP + VIA - Rockwell R6522P + ACIA - Thomson-CSF EF6850P + 3446 - Motorola MC3446AP + CN1 - DB25 serial connector + CN2 - power connector + CN3 - DIN5 IEC connector + CN4 - DIN5 IEC connector + CN5 - 2x12 PCB edge IEEE-488 connector + LD1 - LED + +*/ + +/* + + TODO: + + - everything + + 0 OPEN 2,4,31 : INPUT #2, A$ : CLOSE #2 + 1 PRINT A$ + + http://mikenaberezny.com/hardware/projects/interpod-ieee-488-interface/ + +*/ + +#include "interpod.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define R6502_TAG "u1" +#define R6532_TAG "u3" +#define R6522_TAG "u4" +#define MC6850_TAG "u5" + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type INTERPOD = &device_creator; + + + +//************************************************************************** +// DEVICE CONFIGURATION +//************************************************************************** + +//------------------------------------------------- +// ROM( interpod ) +//------------------------------------------------- + +ROM_START( interpod ) + ROM_REGION( 0x800, R6502_TAG, 0 ) + ROM_LOAD( "1.4.u2", 0x000, 0x800, CRC(c5b71982) SHA1(614d677b7c6273f6b84fa61affaf91cfdaeed6a6) ) + ROM_LOAD( "1.6.u2", 0x000, 0x800, CRC(67bb0436) SHA1(7659c45b73f577233f7657c4da9141dcfe8b6d97) ) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *interpod_device::device_rom_region() const +{ + return ROM_NAME( interpod ); +} + + +//------------------------------------------------- +// ADDRESS_MAP( interpod_mem ) +//------------------------------------------------- + +static ADDRESS_MAP_START( interpod_mem, AS_PROGRAM, 8, interpod_device ) + AM_RANGE(0x0000, 0x007f) AM_MIRROR(0x3b80) AM_DEVICE(R6532_TAG, mos6532_t, ram_map) + AM_RANGE(0x0400, 0x041f) AM_MIRROR(0x3be0) AM_DEVICE(R6532_TAG, mos6532_t, io_map) + AM_RANGE(0x2000, 0x2000) AM_MIRROR(0x9ffe) AM_DEVREADWRITE(MC6850_TAG, acia6850_device, status_r, control_w) + AM_RANGE(0x2001, 0x2001) AM_MIRROR(0x9ffe) AM_DEVREADWRITE(MC6850_TAG, acia6850_device, data_r, data_w) + AM_RANGE(0x4000, 0x47ff) AM_MIRROR(0xb800) AM_ROM AM_REGION(R6502_TAG, 0) + AM_RANGE(0x8000, 0x800f) AM_MIRROR(0x5ff0) AM_DEVREADWRITE(R6522_TAG, via6522_device, read, write) +ADDRESS_MAP_END + + +//------------------------------------------------- +// MACHINE_DRIVER( interpod ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( interpod ) + MCFG_CPU_ADD(R6502_TAG, M6502, 1000000) + MCFG_CPU_PROGRAM_MAP(interpod_mem) + + MCFG_DEVICE_ADD(R6522_TAG, VIA6522, 1000000) + MCFG_DEVICE_ADD(R6532_TAG, MOS6532n, 1000000) + MCFG_DEVICE_ADD(MC6850_TAG, ACIA6850, 0) + + MCFG_CBM_IEEE488_ADD(NULL) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor interpod_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( interpod ); +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// interpod_device - constructor +//------------------------------------------------- + +interpod_device::interpod_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, INTERPOD, "Interpod", tag, owner, clock, "interpod", __FILE__), + device_cbm_iec_interface(mconfig, *this), + m_maincpu(*this, R6502_TAG), + m_via(*this, R6522_TAG), + m_riot(*this, R6532_TAG), + m_acia(*this, MC6850_TAG), + m_ieee(*this, IEEE488_TAG) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void interpod_device::device_start() +{ +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void interpod_device::device_reset() +{ +} diff --git a/src/devices/bus/cbmiec/interpod.h b/src/devices/bus/cbmiec/interpod.h new file mode 100644 index 00000000000..fbbe194cca6 --- /dev/null +++ b/src/devices/bus/cbmiec/interpod.h @@ -0,0 +1,76 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Oxford Computer Systems Interpod IEC to IEEE interface emulation + +*********************************************************************/ + +#pragma once + +#ifndef __INTERPOD__ +#define __INTERPOD__ + +#include "emu.h" +#include "cbmiec.h" +#include "bus/ieee488/ieee488.h" +#include "cpu/m6502/m6502.h" +#include "machine/6522via.h" +#include "machine/mos6530n.h" +#include "machine/6850acia.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define INTERPOD_TAG "interpod" + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_INTERPOD_ADD() \ + MCFG_DEVICE_ADD(INTERPOD_TAG, INTERPOD, 0) + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> interpod_device + +class interpod_device : public device_t, + public device_cbm_iec_interface +{ +public: + // construction/destruction + interpod_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + required_device m_maincpu; + required_device m_via; + required_device m_riot; + required_device m_acia; + required_device m_ieee; +}; + + +// device type definition +extern const device_type INTERPOD; + + + +#endif diff --git a/src/devices/bus/cbmiec/serialbox.c b/src/devices/bus/cbmiec/serialbox.c new file mode 100644 index 00000000000..c3b653cb030 --- /dev/null +++ b/src/devices/bus/cbmiec/serialbox.c @@ -0,0 +1,150 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Serial Box 64K Serial Port Buffer emulation + +**********************************************************************/ + +#include "serialbox.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define M6502_TAG "u1" +#define M8520_TAG "u5" +#define WD1770_TAG "u4" + + +enum +{ + LED_POWER = 0, + LED_ACT +}; + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type SERIAL_BOX = &device_creator; + + +//------------------------------------------------- +// ROM( serial_box ) +//------------------------------------------------- + +ROM_START( serial_box ) + ROM_REGION( 0x1000, M6502_TAG, 0 ) + ROM_LOAD( "serialbx.bin", 0x0000, 0x1000, CRC(d0e0218c) SHA1(9b922f1e9f9b71e771361c52d4df2aa5695488a5) ) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *serial_box_device::device_rom_region() const +{ + return ROM_NAME( serial_box ); +} + + +//------------------------------------------------- +// ADDRESS_MAP( serial_box_mem ) +//------------------------------------------------- + +static ADDRESS_MAP_START( serial_box_mem, AS_PROGRAM, 8, serial_box_device ) + AM_RANGE(0xf000, 0xffff) AM_ROM AM_REGION(M6502_TAG, 0) +ADDRESS_MAP_END + + +//------------------------------------------------- +// MACHINE_DRIVER( serial_box ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( serial_box ) + MCFG_CPU_ADD(M6502_TAG, M65C02, XTAL_4MHz/4) + MCFG_CPU_PROGRAM_MAP(serial_box_mem) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor serial_box_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( serial_box ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// serial_box_device - constructor +//------------------------------------------------- + +serial_box_device::serial_box_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, SERIAL_BOX, "Serial Box", tag, owner, clock, "serbox", __FILE__), + device_cbm_iec_interface(mconfig, *this), + m_maincpu(*this, M6502_TAG) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void serial_box_device::device_start() +{ +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void serial_box_device::device_reset() +{ +} + + +//------------------------------------------------- +// cbm_iec_atn - +//------------------------------------------------- + +void serial_box_device::cbm_iec_atn(int state) +{ +} + + +//------------------------------------------------- +// cbm_iec_data - +//------------------------------------------------- + +void serial_box_device::cbm_iec_data(int state) +{ +} + + +//------------------------------------------------- +// cbm_iec_reset - +//------------------------------------------------- + +void serial_box_device::cbm_iec_reset(int state) +{ + if (!state) + { + device_reset(); + } +} diff --git a/src/devices/bus/cbmiec/serialbox.h b/src/devices/bus/cbmiec/serialbox.h new file mode 100644 index 00000000000..f045fd05dfb --- /dev/null +++ b/src/devices/bus/cbmiec/serialbox.h @@ -0,0 +1,65 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Serial Box 64K Serial Port Buffer emulation + +**********************************************************************/ + +#pragma once + +#ifndef __SERIAL_BOX__ +#define __SERIAL_BOX__ + +#include "emu.h" +#include "cpu/m6502/m65c02.h" +#include "bus/cbmiec/cbmiec.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define SERIAL_BOX_TAG "serialbox" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> serial_box_device + +class serial_box_device : public device_t, + public device_cbm_iec_interface +{ +public: + // construction/destruction + serial_box_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_cbm_iec_interface overrides + void cbm_iec_atn(int state); + void cbm_iec_data(int state); + void cbm_iec_reset(int state); + +private: + required_device m_maincpu; +}; + + +// device type definition +extern const device_type SERIAL_BOX; + + + +#endif diff --git a/src/devices/bus/cbmiec/vic1515.c b/src/devices/bus/cbmiec/vic1515.c new file mode 100644 index 00000000000..61f19761d7a --- /dev/null +++ b/src/devices/bus/cbmiec/vic1515.c @@ -0,0 +1,164 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Commodore VIC-1515 Printer emulation + +**********************************************************************/ + +#include "vic1515.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type VIC1515 = &device_creator; + + +//------------------------------------------------- +// ROM( vic1515 ) +//------------------------------------------------- + +ROM_START( vic1515 ) + ROM_REGION( 0x1000, "rom", 0 ) + ROM_LOAD( "805-5.p4", 0x0000, 0x1000, CRC(05a99a5a) SHA1(035c23dc83923eea34feea260445356a909fbd98) ) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *vic1515_t::device_rom_region() const +{ + return ROM_NAME( vic1515 ); +} + + +//------------------------------------------------- +// ADDRESS_MAP( vic1515_mem ) +//------------------------------------------------- + +static ADDRESS_MAP_START( vic1515_mem, AS_PROGRAM, 8, vic1515_t ) + AM_RANGE(0x0000, 0x0fff) AM_ROM AM_REGION("rom", 0) +ADDRESS_MAP_END + + +//------------------------------------------------- +// ADDRESS_MAP( vic1515_io ) +//------------------------------------------------- + +static ADDRESS_MAP_START( vic1515_io, AS_IO, 8, vic1515_t ) +ADDRESS_MAP_END + + +//------------------------------------------------- +// MACHINE_DRIVER( vic1515 ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( vic1515 ) + MCFG_CPU_ADD("maincpu", I8039, XTAL_6MHz) + MCFG_CPU_PROGRAM_MAP(vic1515_mem) + MCFG_CPU_IO_MAP(vic1515_io) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor vic1515_t::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( vic1515 ); +} + + +//------------------------------------------------- +// INPUT_PORTS( vic1515 ) +//------------------------------------------------- + +static INPUT_PORTS_START( vic1515 ) + PORT_START("ADDRESS") + PORT_DIPNAME( 0x03, 0x00, "Device Address" ) + PORT_DIPSETTING( 0x00, "4" ) + PORT_DIPSETTING( 0x01, "5" ) + PORT_DIPSETTING( 0x02, "T" ) +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor vic1515_t::device_input_ports() const +{ + return INPUT_PORTS_NAME( vic1515 ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// vic1515_t - constructor +//------------------------------------------------- + +vic1515_t::vic1515_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, VIC1515, "VIC-1515", tag, owner, clock, "vic1515", __FILE__), + device_cbm_iec_interface(mconfig, *this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void vic1515_t::device_start() +{ +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void vic1515_t::device_reset() +{ +} + + +//------------------------------------------------- +// cbm_iec_atn - +//------------------------------------------------- + +void vic1515_t::cbm_iec_atn(int state) +{ +} + + +//------------------------------------------------- +// cbm_iec_data - +//------------------------------------------------- + +void vic1515_t::cbm_iec_data(int state) +{ +} + + +//------------------------------------------------- +// cbm_iec_reset - +//------------------------------------------------- + +void vic1515_t::cbm_iec_reset(int state) +{ + if (!state) + { + device_reset(); + } +} diff --git a/src/devices/bus/cbmiec/vic1515.h b/src/devices/bus/cbmiec/vic1515.h new file mode 100644 index 00000000000..cd3d4554994 --- /dev/null +++ b/src/devices/bus/cbmiec/vic1515.h @@ -0,0 +1,55 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Commodore VIC-1515 Printer emulation + +**********************************************************************/ + +#pragma once + +#ifndef __VIC1515__ +#define __VIC1515__ + +#include "emu.h" +#include "cbmiec.h" +#include "cpu/mcs48/mcs48.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> vic1515_t + +class vic1515_t : public device_t, + public device_cbm_iec_interface +{ +public: + // construction/destruction + vic1515_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + virtual ioport_constructor device_input_ports() const; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_cbm_iec_interface overrides + void cbm_iec_atn(int state); + void cbm_iec_data(int state); + void cbm_iec_reset(int state); +}; + + +// device type definition +extern const device_type VIC1515; + + + +#endif diff --git a/src/devices/bus/cbmiec/vic1520.c b/src/devices/bus/cbmiec/vic1520.c new file mode 100644 index 00000000000..55cd372f385 --- /dev/null +++ b/src/devices/bus/cbmiec/vic1520.c @@ -0,0 +1,192 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Commodore VIC-1520 Plotter emulation + +**********************************************************************/ + +/* +PA0 ATN +PA1 _CLK +PA5 ATTN ACK +PA6 NRFD +PA7 _DATA IN + +PB0 IEEE SELECT +PB1 IEEE SELECT +PB2 IEEE SELECT +PB4 LED +PB5 REMOVE +PB6 CHANGE +PB7 FEED + +PC0 _DN +PC1 _UP +PC7 COLOR SENSOR SW + +PD0 X MOTOR COM A +PD1 X MOTOR COM B +PD2 X MOTOR COM C +PD3 X MOTOR COM D +PD4 Y MOTOR COM A +PD5 Y MOTOR COM B +PD6 Y MOTOR COM C +PD7 Y MOTOR COM D +*/ + +#include "vic1520.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define M6500_1_TAG "u1" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type VIC1520 = &device_creator; + + +//------------------------------------------------- +// ROM( vic1520 ) +//------------------------------------------------- + +ROM_START( vic1520 ) + ROM_REGION( 0x800, M6500_1_TAG, 0 ) + ROM_SYSTEM_BIOS( 0, "r01", "325340-01" ) + ROMX_LOAD( "325340-01.u1", 0x000, 0x800, CRC(3757da6f) SHA1(8ab43603f74b0f269bbe890d1939a9ae31307eb1), ROM_BIOS(1) ) + ROM_SYSTEM_BIOS( 1, "r03", "325340-03" ) + ROMX_LOAD( "325340-03.u1", 0x000, 0x800, CRC(f72ea2b6) SHA1(74c15b2cc1f7632bffa37439609cbdb50b82ea92), ROM_BIOS(2) ) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *vic1520_t::device_rom_region() const +{ + return ROM_NAME( vic1520 ); +} + + +//------------------------------------------------- +// ADDRESS_MAP( vic1520_mem ) +//------------------------------------------------- + +static ADDRESS_MAP_START( vic1520_mem, AS_PROGRAM, 8, vic1520_t ) + ADDRESS_MAP_GLOBAL_MASK(0xfff) + AM_RANGE(0x000, 0x03f) AM_RAM + AM_RANGE(0x800, 0xfff) AM_ROM AM_REGION(M6500_1_TAG, 0) +ADDRESS_MAP_END + + +//------------------------------------------------- +// MACHINE_DRIVER( vic1520 ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( vic1520 ) + MCFG_CPU_ADD(M6500_1_TAG, M6502, XTAL_2MHz) // M6500/1 + MCFG_CPU_PROGRAM_MAP(vic1520_mem) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor vic1520_t::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( vic1520 ); +} + + +//------------------------------------------------- +// INPUT_PORTS( vic1520 ) +//------------------------------------------------- + +static INPUT_PORTS_START( vic1520 ) +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor vic1520_t::device_input_ports() const +{ + return INPUT_PORTS_NAME( vic1520 ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// vic1520_t - constructor +//------------------------------------------------- + +vic1520_t::vic1520_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, VIC1520, "VIC-1520", tag, owner, clock, "vic1520", __FILE__), + device_cbm_iec_interface(mconfig, *this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void vic1520_t::device_start() +{ +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void vic1520_t::device_reset() +{ +} + + +//------------------------------------------------- +// cbm_iec_atn - +//------------------------------------------------- + +void vic1520_t::cbm_iec_atn(int state) +{ +} + + +//------------------------------------------------- +// cbm_iec_data - +//------------------------------------------------- + +void vic1520_t::cbm_iec_data(int state) +{ +} + + +//------------------------------------------------- +// cbm_iec_reset - +//------------------------------------------------- + +void vic1520_t::cbm_iec_reset(int state) +{ + if (!state) + { + device_reset(); + } +} diff --git a/src/devices/bus/cbmiec/vic1520.h b/src/devices/bus/cbmiec/vic1520.h new file mode 100644 index 00000000000..4169164d0ae --- /dev/null +++ b/src/devices/bus/cbmiec/vic1520.h @@ -0,0 +1,55 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Commodore VIC-1520 Plotter emulation + +**********************************************************************/ + +#pragma once + +#ifndef __VIC1520__ +#define __VIC1520__ + +#include "emu.h" +#include "cbmiec.h" +#include "cpu/m6502/m6502.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> vic1520_t + +class vic1520_t : public device_t, + public device_cbm_iec_interface +{ +public: + // construction/destruction + vic1520_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + virtual ioport_constructor device_input_ports() const; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_cbm_iec_interface overrides + void cbm_iec_atn(int state); + void cbm_iec_data(int state); + void cbm_iec_reset(int state); +}; + + +// device type definition +extern const device_type VIC1520; + + + +#endif diff --git a/src/devices/bus/centronics/comxpl80.c b/src/devices/bus/centronics/comxpl80.c new file mode 100644 index 00000000000..6c3fa83a8d7 --- /dev/null +++ b/src/devices/bus/centronics/comxpl80.c @@ -0,0 +1,328 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + COMX PL-80 plotter emulation + +**********************************************************************/ + +/* + + TODO: + + - CPU type? + +*/ + +#include "comxpl80.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define CX005_TAG "cx005" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type COMX_PL80 = &device_creator; + + +//------------------------------------------------- +// ROM( comxpl80 ) +//------------------------------------------------- + +ROM_START( comxpl80 ) + ROM_REGION( 0x1000, CX005_TAG, 0 ) + ROM_LOAD( "pl80.pt6", 0x0080, 0x0e00, CRC(ae059e5b) SHA1(f25812606b0082d32eb603d0a702a2187089d332) ) + + ROM_REGION( 0x6000, "gfx1", ROMREGION_ERASEFF ) // Plotter fonts + ROM_LOAD( "it.em.ou.bin", 0x2000, 0x2000, CRC(1b4a3198) SHA1(138ff6666a31c2d18cd63e609dd94d9cd1529931) ) + ROM_LOAD( "tiny.bin", 0x4000, 0x0400, CRC(940ec1ed) SHA1(ad83a3b57e2f0fbaa1e40644cd999b3f239635e8) ) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *comx_pl80_device::device_rom_region() const +{ + return ROM_NAME( comxpl80 ); +} + + +//------------------------------------------------- +// ADDRESS_MAP( comxpl80_mem ) +//------------------------------------------------- + +static ADDRESS_MAP_START( comxpl80_mem, AS_PROGRAM, 8, comx_pl80_device ) +/* AM_RANGE(0x000, 0x000) AM_READWRITE(cx005_port_a_r, cx005_port_a_w) + AM_RANGE(0x001, 0x001) AM_READWRITE(cx005_port_b_r, cx005_port_b_w) + AM_RANGE(0x002, 0x002) AM_READWRITE(cx005_port_c_r, cx005_port_c_w) + AM_RANGE(0x003, 0x003) AM_READ(cx005_port_d_digital_r) + AM_RANGE(0x004, 0x004) AM_WRITE(cx005_port_a_ddr_w) + AM_RANGE(0x005, 0x005) AM_WRITE(cx005_port_b_ddr_w) + AM_RANGE(0x006, 0x006) AM_WRITE(cx005_port_c_ddr_w) + AM_RANGE(0x007, 0x007) AM_READ(cx005_port_d_analog_r) + AM_RANGE(0x008, 0x008) AM_READWRITE(cx005_timer_data_r, cx005_timer_data_w) + AM_RANGE(0x008, 0x008) AM_READWRITE(cx005_timer_ctrl_r, cx005_timer_ctrl_w)*/ + AM_RANGE(0x00a, 0x01f) AM_NOP // Not Used + AM_RANGE(0x020, 0x07f) AM_RAM // Internal RAM + AM_RANGE(0x080, 0xf7f) AM_ROM AM_REGION(CX005_TAG, 0) // Internal ROM + AM_RANGE(0xf80, 0xff7) AM_ROM AM_REGION(CX005_TAG, 0xf00) // Self-Test + AM_RANGE(0xff8, 0xfff) AM_ROM AM_REGION(CX005_TAG, 0xf78) // Interrupt Vectors +ADDRESS_MAP_END + + +//------------------------------------------------- +// ADDRESS_MAP( comxpl80_io ) +//------------------------------------------------- + +static ADDRESS_MAP_START( comxpl80_io, AS_IO, 8, comx_pl80_device ) + ADDRESS_MAP_UNMAP_HIGH + AM_RANGE(0x00, 0x00) AM_WRITE(pa_w) + AM_RANGE(0x01, 0x01) AM_WRITE(pb_w) + AM_RANGE(0x02, 0x02) AM_WRITE(pc_w) + AM_RANGE(0x03, 0x03) AM_READ(pd_r) +ADDRESS_MAP_END + + +//------------------------------------------------- +// MACHINE_DRIVER( comxpl80 ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( comxpl80 ) + MCFG_CPU_ADD(CX005_TAG, M6805, 4000000) // CX005: some kind of MC6805/MC68HC05 clone + MCFG_CPU_PROGRAM_MAP(comxpl80_mem) + MCFG_CPU_IO_MAP(comxpl80_io) + MCFG_DEVICE_DISABLE() +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor comx_pl80_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( comxpl80 ); +} + + +//------------------------------------------------- +// INPUT_PORTS( comxpl80 ) +//------------------------------------------------- + +INPUT_PORTS_START( comxpl80 ) + PORT_START("SW") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_SPECIAL ) PORT_NAME("DOWN") + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_SPECIAL ) PORT_NAME("PEN-SEL") + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_SPECIAL ) PORT_NAME("UP") + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_SPECIAL ) PORT_NAME("CR") + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_SPECIAL ) PORT_NAME("ON LINE") + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_SPECIAL ) PORT_NAME("PE") + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_SPECIAL ) PORT_NAME("RIGHT") + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_SPECIAL ) PORT_NAME("LEFT") + + PORT_START("FONT") + PORT_CONFNAME( 0x03, 0x00, "COMX PL-80 Font Pack") + PORT_CONFSETTING( 0x00, DEF_STR( None ) ) + PORT_CONFSETTING( 0x01, "Italic, Emphasized and Outline" ) + PORT_CONFSETTING( 0x02, "Tiny" ) +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor comx_pl80_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( comxpl80 ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// comx_pl80_device - constructor +//------------------------------------------------- + +comx_pl80_device::comx_pl80_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, COMX_PL80, "COMX PL-80", tag, owner, clock, "comx_pl80", __FILE__), + device_centronics_peripheral_interface(mconfig, *this), + m_plotter(*this, "PLOTTER"), + m_font(*this, "FONT"), + m_sw(*this, "SW") +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void comx_pl80_device::device_start() +{ + // state saving + save_item(NAME(m_font_addr)); + save_item(NAME(m_x_motor_phase)); + save_item(NAME(m_y_motor_phase)); + save_item(NAME(m_z_motor_phase)); + save_item(NAME(m_plotter_data)); + save_item(NAME(m_plotter_ack)); + save_item(NAME(m_plotter_online)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void comx_pl80_device::device_reset() +{ +} + + +//------------------------------------------------- +// pa_w - +//------------------------------------------------- + +WRITE8_MEMBER( comx_pl80_device::pa_w ) +{ + /* + + bit description + + 0 Y motor phase A + 1 Y motor phase B + 2 Y motor phase C + 3 Y motor phase D + 4 ROM A12 + 5 ROM CE /PT5 CK + 6 PT4 OE + 7 SW & PE ENABLE + + */ + + m_y_motor_phase = data & 0x0f; + m_font_addr = (BIT(data, 4) << 12) | (m_font_addr & 0xfff); + + m_plotter_data = 0xff; + + if (BIT(data, 5)) + { + // write motor phase data + } + else + { + // read data from font ROM + int font_rom = (m_font->read() & 0x03) * 0x2000; + + m_plotter_data = m_plotter->base()[font_rom | m_font_addr]; + } + + if (!BIT(data, 6)) + { + // read data from Centronics bus + m_plotter_data = m_data; + } + + if (BIT(data, 7)) + { + // read switches + m_plotter_data = m_sw->read(); + } +} + + +//------------------------------------------------- +// pb_w - +//------------------------------------------------- + +WRITE8_MEMBER( comx_pl80_device::pb_w ) +{ + /* + + bit description + + 0 Z motor phase A + 1 Z motor phase B + 2 Z motor phase C + 3 Z motor phase D + 4 ROM A8 + 5 ROM A9 + 6 ROM A10 + 7 ROM A11 + + */ + + m_z_motor_phase = data & 0x0f; + + m_font_addr = (m_font_addr & 0x10ff) | (data << 4); +} + + +//------------------------------------------------- +// pc_w - +//------------------------------------------------- + +WRITE8_MEMBER( comx_pl80_device::pc_w ) +{ + /* + + bit description + + 0 ROM A0 /X motor phase A + 1 ROM A1 /X motor phase B + 2 ROM A2 /X motor phase C + 3 ROM A3 /X motor phase D + 4 ROM A4 /ACK + 5 ROM A5 /On-line LED + 6 ROM A6 + 7 ROM A7 + + */ + + m_font_addr = (m_font_addr & 0x1f00) | data; + + m_x_motor_phase = data & 0x0f; + + m_plotter_ack = BIT(data, 4); + m_plotter_online = BIT(data, 5); +} + + +//------------------------------------------------- +// pd_r - +//------------------------------------------------- + +READ8_MEMBER( comx_pl80_device::pd_r ) +{ + /* + + bit description + + 0 D0 /ROM D0 /DOWN SW + 1 D1 /ROM D1 /PEN-SEL SW + 2 D2 /ROM D2 /UP SW + 3 D3 /ROM D3 /CRSW + 4 D4 /ROM D4 /ON LINE SW + 5 D5 /ROM D5 /PE Sensor + 6 D6 /ROM D6 /RIGHT SW + 7 D7 /ROM D7 /LEFT SW + + */ + + return m_plotter_data; +} diff --git a/src/devices/bus/centronics/comxpl80.h b/src/devices/bus/centronics/comxpl80.h new file mode 100644 index 00000000000..4a943459c09 --- /dev/null +++ b/src/devices/bus/centronics/comxpl80.h @@ -0,0 +1,81 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + COMX PL-80 plotter emulation + +**********************************************************************/ + +#pragma once + +#ifndef __COMX_PL80__ +#define __COMX_PL80__ + +#include "emu.h" +#include "cpu/m6805/m6805.h" +#include "bus/centronics/ctronics.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> comx_pl80_device + +class comx_pl80_device : public device_t, + public device_centronics_peripheral_interface +{ +public: + // construction/destruction + comx_pl80_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + virtual ioport_constructor device_input_ports() const; + + // not really public + DECLARE_WRITE8_MEMBER( pa_w ); + DECLARE_WRITE8_MEMBER( pb_w ); + DECLARE_WRITE8_MEMBER( pc_w ); + DECLARE_READ8_MEMBER( pd_r ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + virtual DECLARE_WRITE_LINE_MEMBER( input_data0 ) { if (state) m_data |= 0x01; else m_data &= ~0x01; } + virtual DECLARE_WRITE_LINE_MEMBER( input_data1 ) { if (state) m_data |= 0x02; else m_data &= ~0x02; } + virtual DECLARE_WRITE_LINE_MEMBER( input_data2 ) { if (state) m_data |= 0x04; else m_data &= ~0x04; } + virtual DECLARE_WRITE_LINE_MEMBER( input_data3 ) { if (state) m_data |= 0x08; else m_data &= ~0x08; } + virtual DECLARE_WRITE_LINE_MEMBER( input_data4 ) { if (state) m_data |= 0x10; else m_data &= ~0x10; } + virtual DECLARE_WRITE_LINE_MEMBER( input_data5 ) { if (state) m_data |= 0x20; else m_data &= ~0x20; } + virtual DECLARE_WRITE_LINE_MEMBER( input_data6 ) { if (state) m_data |= 0x40; else m_data &= ~0x40; } + virtual DECLARE_WRITE_LINE_MEMBER( input_data7 ) { if (state) m_data |= 0x80; else m_data &= ~0x80; } + +private: + required_memory_region m_plotter; + required_ioport m_font; + required_ioport m_sw; + + // PL-80 plotter state + UINT16 m_font_addr; // font ROM pack address latch + UINT8 m_x_motor_phase; // X motor phase + UINT8 m_y_motor_phase; // Y motor phase + UINT8 m_z_motor_phase; // Z motor phase + UINT8 m_plotter_data; // plotter data bus + int m_plotter_ack; // plotter acknowledge + int m_plotter_online; // online LED + + UINT8 m_data; +}; + + +// device type definition +extern const device_type COMX_PL80; + + + +#endif diff --git a/src/devices/bus/centronics/covox.c b/src/devices/bus/centronics/covox.c new file mode 100644 index 00000000000..6cf0f6c02e9 --- /dev/null +++ b/src/devices/bus/centronics/covox.c @@ -0,0 +1,127 @@ +// license:BSD-3-Clause +// copyright-holders:Miodrag Milanovic +/*************************************************************************** + + Covox Speech Thing + +***************************************************************************/ + +#include "emu.h" +#include "sound/dac.h" +#include "covox.h" + +//************************************************************************** +// COVOX DEVICE +//************************************************************************** + +// device type definition +const device_type CENTRONICS_COVOX = &device_creator; + +static MACHINE_CONFIG_FRAGMENT( covox ) + /* sound hardware */ + MCFG_SPEAKER_STANDARD_MONO("mono") + + MCFG_SOUND_ADD("dac", DAC, 0) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 1.0) +MACHINE_CONFIG_END + + +/*************************************************************************** + IMPLEMENTATION +***************************************************************************/ +//------------------------------------------------- +// centronics_covox_device - constructor +//------------------------------------------------- + +centronics_covox_device::centronics_covox_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, CENTRONICS_COVOX, "Covox Speech Thing", tag, owner, clock, "covox", __FILE__), + device_centronics_peripheral_interface( mconfig, *this ), + m_dac(*this, "dac"), + m_data(0) +{ +} + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor centronics_covox_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( covox ); +} + +void centronics_covox_device::device_start() +{ + save_item(NAME(m_data)); +} + +void centronics_covox_device::update_dac() +{ + if (started()) + m_dac->write_unsigned8(m_data); +} + +//************************************************************************** +// COVOX STEREO DEVICE +//************************************************************************** + +// device type definition +const device_type CENTRONICS_COVOX_STEREO = &device_creator; + +static MACHINE_CONFIG_FRAGMENT( covox_stereo ) + /* sound hardware */ + MCFG_SPEAKER_STANDARD_STEREO("lspeaker", "rspeaker") + + MCFG_SOUND_ADD("dac_left", DAC, 0) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "lspeaker", 1.0) + + MCFG_SOUND_ADD("dac_right", DAC, 0) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "rspeaker", 1.0) +MACHINE_CONFIG_END + + +/*************************************************************************** + IMPLEMENTATION +***************************************************************************/ +//------------------------------------------------- +// centronics_covox_stereo_device - constructor +//------------------------------------------------- + +centronics_covox_stereo_device::centronics_covox_stereo_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, CENTRONICS_COVOX_STEREO, "Covox (Stereo-in-1)", tag, owner, clock, "covox_stereo", __FILE__), + device_centronics_peripheral_interface( mconfig, *this ), + m_dac_left(*this, "dac_left"), + m_dac_right(*this, "dac_right"), + m_data(0) +{ +} + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor centronics_covox_stereo_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( covox_stereo ); +} + +void centronics_covox_stereo_device::device_start() +{ + save_item(NAME(m_data)); + save_item(NAME(m_strobe)); + save_item(NAME(m_autofd)); +} + +void centronics_covox_stereo_device::update_dac() +{ + if (started()) + { + if (m_strobe) + m_dac_left->write_unsigned8(m_data); + + if (m_autofd) + m_dac_right->write_unsigned8(m_data); + } +} diff --git a/src/devices/bus/centronics/covox.h b/src/devices/bus/centronics/covox.h new file mode 100644 index 00000000000..c4d3d3ea94a --- /dev/null +++ b/src/devices/bus/centronics/covox.h @@ -0,0 +1,94 @@ +// license:BSD-3-Clause +// copyright-holders:Miodrag Milanovic +/*************************************************************************** + + Covox Speech Thing + +***************************************************************************/ + +#ifndef __CENTRONICS_COVOX_H__ +#define __CENTRONICS_COVOX_H__ + +#pragma once + +#include "ctronics.h" +#include "sound/dac.h" + +// ======================> centronics_covox_device + +class centronics_covox_device : public device_t, + public device_centronics_peripheral_interface +{ +public: + // construction/destruction + centronics_covox_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + +protected: + // device-level overrides + virtual void device_start(); + + virtual DECLARE_WRITE_LINE_MEMBER( input_data0 ) { if (state) m_data |= 0x01; else m_data &= ~0x01; update_dac(); } + virtual DECLARE_WRITE_LINE_MEMBER( input_data1 ) { if (state) m_data |= 0x02; else m_data &= ~0x02; update_dac(); } + virtual DECLARE_WRITE_LINE_MEMBER( input_data2 ) { if (state) m_data |= 0x04; else m_data &= ~0x04; update_dac(); } + virtual DECLARE_WRITE_LINE_MEMBER( input_data3 ) { if (state) m_data |= 0x08; else m_data &= ~0x08; update_dac(); } + virtual DECLARE_WRITE_LINE_MEMBER( input_data4 ) { if (state) m_data |= 0x10; else m_data &= ~0x10; update_dac(); } + virtual DECLARE_WRITE_LINE_MEMBER( input_data5 ) { if (state) m_data |= 0x20; else m_data &= ~0x20; update_dac(); } + virtual DECLARE_WRITE_LINE_MEMBER( input_data6 ) { if (state) m_data |= 0x40; else m_data &= ~0x40; update_dac(); } + virtual DECLARE_WRITE_LINE_MEMBER( input_data7 ) { if (state) m_data |= 0x80; else m_data &= ~0x80; update_dac(); } + +private: + required_device m_dac; + + void update_dac(); + + UINT8 m_data; +}; + +// device type definition +extern const device_type CENTRONICS_COVOX; + +// ======================> centronics_covox_stereo_device + +class centronics_covox_stereo_device : public device_t, + public device_centronics_peripheral_interface +{ +public: + // construction/destruction + centronics_covox_stereo_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + +protected: + // device-level overrides + virtual void device_start(); + + virtual DECLARE_WRITE_LINE_MEMBER( input_strobe ) { m_strobe = state; update_dac(); } + virtual DECLARE_WRITE_LINE_MEMBER( input_data0 ) { if (state) m_data |= 0x01; else m_data &= ~0x01; update_dac(); } + virtual DECLARE_WRITE_LINE_MEMBER( input_data1 ) { if (state) m_data |= 0x02; else m_data &= ~0x02; update_dac(); } + virtual DECLARE_WRITE_LINE_MEMBER( input_data2 ) { if (state) m_data |= 0x04; else m_data &= ~0x04; update_dac(); } + virtual DECLARE_WRITE_LINE_MEMBER( input_data3 ) { if (state) m_data |= 0x08; else m_data &= ~0x08; update_dac(); } + virtual DECLARE_WRITE_LINE_MEMBER( input_data4 ) { if (state) m_data |= 0x10; else m_data &= ~0x10; update_dac(); } + virtual DECLARE_WRITE_LINE_MEMBER( input_data5 ) { if (state) m_data |= 0x20; else m_data &= ~0x20; update_dac(); } + virtual DECLARE_WRITE_LINE_MEMBER( input_data6 ) { if (state) m_data |= 0x40; else m_data &= ~0x40; update_dac(); } + virtual DECLARE_WRITE_LINE_MEMBER( input_data7 ) { if (state) m_data |= 0x80; else m_data &= ~0x80; update_dac(); if (started()) output_busy(state); } + virtual DECLARE_WRITE_LINE_MEMBER( input_autofd ) { m_autofd = state; update_dac(); } + +private: + required_device m_dac_left; + required_device m_dac_right; + + void update_dac(); + + int m_strobe; + UINT8 m_data; + int m_autofd; +}; + +// device type definition +extern const device_type CENTRONICS_COVOX_STEREO; + +#endif /* __CENTRONICS_COVOX_H__ */ diff --git a/src/devices/bus/centronics/ctronics.c b/src/devices/bus/centronics/ctronics.c new file mode 100644 index 00000000000..c27affa41ea --- /dev/null +++ b/src/devices/bus/centronics/ctronics.c @@ -0,0 +1,132 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/*************************************************************************** + + Centronics printer interface + +***************************************************************************/ + +#include "ctronics.h" + +// class centronics_device + +const device_type CENTRONICS = &device_creator; + +centronics_device::centronics_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, CENTRONICS, "Centronics", tag, owner, clock, "centronics", __FILE__), + device_slot_interface(mconfig, *this), + m_strobe_handler(*this), + m_data0_handler(*this), + m_data1_handler(*this), + m_data2_handler(*this), + m_data3_handler(*this), + m_data4_handler(*this), + m_data5_handler(*this), + m_data6_handler(*this), + m_data7_handler(*this), + m_ack_handler(*this), + m_busy_handler(*this), + m_perror_handler(*this), + m_select_handler(*this), + m_autofd_handler(*this), + m_fault_handler(*this), + m_init_handler(*this), + m_select_in_handler(*this), + m_dev(NULL) +{ +} + +void centronics_device::device_config_complete() +{ + m_dev = dynamic_cast(get_card_device()); +} + +void centronics_device::device_start() +{ + m_strobe_handler.resolve_safe(); + m_data0_handler.resolve_safe(); + m_data1_handler.resolve_safe(); + m_data2_handler.resolve_safe(); + m_data3_handler.resolve_safe(); + m_data4_handler.resolve_safe(); + m_data5_handler.resolve_safe(); + m_data6_handler.resolve_safe(); + m_data7_handler.resolve_safe(); + m_ack_handler.resolve_safe(); + m_busy_handler.resolve_safe(); + m_perror_handler.resolve_safe(); + m_select_handler.resolve_safe(); + m_autofd_handler.resolve_safe(); + m_fault_handler.resolve_safe(); + m_init_handler.resolve_safe(); + m_select_in_handler.resolve_safe(); + + // pull up + m_strobe_handler(1); + m_data0_handler(1); + m_data1_handler(1); + m_data2_handler(1); + m_data3_handler(1); + m_data4_handler(1); + m_data5_handler(1); + m_data6_handler(1); + m_data7_handler(1); + m_ack_handler(1); + m_busy_handler(1); + m_perror_handler(1); + m_select_handler(1); + m_autofd_handler(1); + m_fault_handler(1); + m_init_handler(1); + m_select_in_handler(1); +} + +WRITE_LINE_MEMBER( centronics_device::write_strobe ) { if (m_dev) m_dev->input_strobe(state); } +WRITE_LINE_MEMBER( centronics_device::write_data0 ) { if (m_dev) m_dev->input_data0(state); } +WRITE_LINE_MEMBER( centronics_device::write_data1 ) { if (m_dev) m_dev->input_data1(state); } +WRITE_LINE_MEMBER( centronics_device::write_data2 ) { if (m_dev) m_dev->input_data2(state); } +WRITE_LINE_MEMBER( centronics_device::write_data3 ) { if (m_dev) m_dev->input_data3(state); } +WRITE_LINE_MEMBER( centronics_device::write_data4 ) { if (m_dev) m_dev->input_data4(state); } +WRITE_LINE_MEMBER( centronics_device::write_data5 ) { if (m_dev) m_dev->input_data5(state); } +WRITE_LINE_MEMBER( centronics_device::write_data6 ) { if (m_dev) m_dev->input_data6(state); } +WRITE_LINE_MEMBER( centronics_device::write_data7 ) { if (m_dev) m_dev->input_data7(state); } +WRITE_LINE_MEMBER( centronics_device::write_ack ) { if (m_dev) m_dev->input_ack(state); } +WRITE_LINE_MEMBER( centronics_device::write_busy ) { if (m_dev) m_dev->input_busy(state); } +WRITE_LINE_MEMBER( centronics_device::write_perror ) { if (m_dev) m_dev->input_perror(state); } +WRITE_LINE_MEMBER( centronics_device::write_select ) { if (m_dev) m_dev->input_select(state); } +WRITE_LINE_MEMBER( centronics_device::write_autofd ) { if (m_dev) m_dev->input_autofd(state); } +WRITE_LINE_MEMBER( centronics_device::write_fault ) { if (m_dev) m_dev->input_fault(state); } +WRITE_LINE_MEMBER( centronics_device::write_init ) { if (m_dev) m_dev->input_init(state); } +WRITE_LINE_MEMBER( centronics_device::write_select_in ) { if (m_dev) m_dev->input_select_in(state); } + + +// class device_centronics_peripheral_interface + +device_centronics_peripheral_interface::device_centronics_peripheral_interface(const machine_config &mconfig, device_t &device) + : device_slot_card_interface(mconfig, device) +{ + m_slot = dynamic_cast(device.owner()); +} + +device_centronics_peripheral_interface::~device_centronics_peripheral_interface() +{ +} + + +#include "comxpl80.h" +#include "epson_ex800.h" +#include "epson_lx800.h" +#include "epson_lx810l.h" +#include "printer.h" +#include "covox.h" + +SLOT_INTERFACE_START(centronics_devices) + SLOT_INTERFACE("pl80", COMX_PL80) + SLOT_INTERFACE("ex800", EPSON_EX800) + SLOT_INTERFACE("lx800", EPSON_LX800) + SLOT_INTERFACE("lx810l", EPSON_LX810L) + SLOT_INTERFACE("ap2000", EPSON_AP2000) + SLOT_INTERFACE("printer", CENTRONICS_PRINTER) + SLOT_INTERFACE("covox", CENTRONICS_COVOX) + SLOT_INTERFACE("covox_stereo", CENTRONICS_COVOX_STEREO) +SLOT_INTERFACE_END diff --git a/src/devices/bus/centronics/ctronics.h b/src/devices/bus/centronics/ctronics.h new file mode 100644 index 00000000000..1235179fdf6 --- /dev/null +++ b/src/devices/bus/centronics/ctronics.h @@ -0,0 +1,222 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/*************************************************************************** + + Centronics printer interface + +***************************************************************************/ + +#pragma once + +#ifndef __CTRONICS_H__ +#define __CTRONICS_H__ + +#include "emu.h" +#include "machine/buffer.h" +#include "machine/latch.h" + + +#define MCFG_CENTRONICS_ADD(_tag, _slot_intf, _def_slot) \ + MCFG_DEVICE_ADD(_tag, CENTRONICS, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) + +#define MCFG_CENTRONICS_STROBE_HANDLER(_devcb) \ + devcb = ¢ronics_device::set_strobe_handler(*device, DEVCB_##_devcb); + +#define MCFG_CENTRONICS_DATA0_HANDLER(_devcb) \ + devcb = ¢ronics_device::set_data0_handler(*device, DEVCB_##_devcb); + +#define MCFG_CENTRONICS_DATA1_HANDLER(_devcb) \ + devcb = ¢ronics_device::set_data1_handler(*device, DEVCB_##_devcb); + +#define MCFG_CENTRONICS_DATA2_HANDLER(_devcb) \ + devcb = ¢ronics_device::set_data2_handler(*device, DEVCB_##_devcb); + +#define MCFG_CENTRONICS_DATA3_HANDLER(_devcb) \ + devcb = ¢ronics_device::set_data3_handler(*device, DEVCB_##_devcb); + +#define MCFG_CENTRONICS_DATA4_HANDLER(_devcb) \ + devcb = ¢ronics_device::set_data4_handler(*device, DEVCB_##_devcb); + +#define MCFG_CENTRONICS_DATA5_HANDLER(_devcb) \ + devcb = ¢ronics_device::set_data5_handler(*device, DEVCB_##_devcb); + +#define MCFG_CENTRONICS_DATA6_HANDLER(_devcb) \ + devcb = ¢ronics_device::set_data6_handler(*device, DEVCB_##_devcb); + +#define MCFG_CENTRONICS_DATA7_HANDLER(_devcb) \ + devcb = ¢ronics_device::set_data7_handler(*device, DEVCB_##_devcb); + +#define MCFG_CENTRONICS_ACK_HANDLER(_devcb) \ + devcb = ¢ronics_device::set_ack_handler(*device, DEVCB_##_devcb); + +#define MCFG_CENTRONICS_BUSY_HANDLER(_devcb) \ + devcb = ¢ronics_device::set_busy_handler(*device, DEVCB_##_devcb); + +#define MCFG_CENTRONICS_PERROR_HANDLER(_devcb) \ + devcb = ¢ronics_device::set_perror_handler(*device, DEVCB_##_devcb); + +#define MCFG_CENTRONICS_SELECT_HANDLER(_devcb) \ + devcb = ¢ronics_device::set_select_handler(*device, DEVCB_##_devcb); + +#define MCFG_CENTRONICS_AUTOFD_HANDLER(_devcb) \ + devcb = ¢ronics_device::set_autofd_handler(*device, DEVCB_##_devcb); + +#define MCFG_CENTRONICS_FAULT_HANDLER(_devcb) \ + devcb = ¢ronics_device::set_fault_handler(*device, DEVCB_##_devcb); + +#define MCFG_CENTRONICS_INIT_HANDLER(_devcb) \ + devcb = ¢ronics_device::set_init_handler(*device, DEVCB_##_devcb); + +#define MCFG_CENTRONICS_SELECT_IN_HANDLER(_devcb) \ + devcb = ¢ronics_device::set_select_in_handler(*device, DEVCB_##_devcb); + +#define MCFG_CENTRONICS_OUTPUT_LATCH_ADD(_tag, _centronics_tag) \ + MCFG_DEVICE_ADD(_tag, OUTPUT_LATCH, 0) \ + MCFG_OUTPUT_LATCH_BIT0_HANDLER(DEVWRITELINE(_centronics_tag, centronics_device, write_data0)) \ + MCFG_OUTPUT_LATCH_BIT1_HANDLER(DEVWRITELINE(_centronics_tag, centronics_device, write_data1)) \ + MCFG_OUTPUT_LATCH_BIT2_HANDLER(DEVWRITELINE(_centronics_tag, centronics_device, write_data2)) \ + MCFG_OUTPUT_LATCH_BIT3_HANDLER(DEVWRITELINE(_centronics_tag, centronics_device, write_data3)) \ + MCFG_OUTPUT_LATCH_BIT4_HANDLER(DEVWRITELINE(_centronics_tag, centronics_device, write_data4)) \ + MCFG_OUTPUT_LATCH_BIT5_HANDLER(DEVWRITELINE(_centronics_tag, centronics_device, write_data5)) \ + MCFG_OUTPUT_LATCH_BIT6_HANDLER(DEVWRITELINE(_centronics_tag, centronics_device, write_data6)) \ + MCFG_OUTPUT_LATCH_BIT7_HANDLER(DEVWRITELINE(_centronics_tag, centronics_device, write_data7)) + +#define MCFG_CENTRONICS_DATA_INPUT_BUFFER(_tag) \ + MCFG_CENTRONICS_DATA0_HANDLER(DEVWRITELINE(_tag, input_buffer_device, write_bit0)) \ + MCFG_CENTRONICS_DATA1_HANDLER(DEVWRITELINE(_tag, input_buffer_device, write_bit1)) \ + MCFG_CENTRONICS_DATA2_HANDLER(DEVWRITELINE(_tag, input_buffer_device, write_bit2)) \ + MCFG_CENTRONICS_DATA3_HANDLER(DEVWRITELINE(_tag, input_buffer_device, write_bit3)) \ + MCFG_CENTRONICS_DATA4_HANDLER(DEVWRITELINE(_tag, input_buffer_device, write_bit4)) \ + MCFG_CENTRONICS_DATA5_HANDLER(DEVWRITELINE(_tag, input_buffer_device, write_bit5)) \ + MCFG_CENTRONICS_DATA6_HANDLER(DEVWRITELINE(_tag, input_buffer_device, write_bit6)) \ + MCFG_CENTRONICS_DATA7_HANDLER(DEVWRITELINE(_tag, input_buffer_device, write_bit7)) + +extern const device_type CENTRONICS; + +class device_centronics_peripheral_interface; + +class centronics_device : public device_t, + public device_slot_interface +{ + friend class device_centronics_peripheral_interface; + +public: + centronics_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + template static devcb_base &set_strobe_handler(device_t &device, _Object object) { return downcast(device).m_strobe_handler.set_callback(object); } + template static devcb_base &set_data0_handler(device_t &device, _Object object) { return downcast(device).m_data0_handler.set_callback(object); } + template static devcb_base &set_data1_handler(device_t &device, _Object object) { return downcast(device).m_data1_handler.set_callback(object); } + template static devcb_base &set_data2_handler(device_t &device, _Object object) { return downcast(device).m_data2_handler.set_callback(object); } + template static devcb_base &set_data3_handler(device_t &device, _Object object) { return downcast(device).m_data3_handler.set_callback(object); } + template static devcb_base &set_data4_handler(device_t &device, _Object object) { return downcast(device).m_data4_handler.set_callback(object); } + template static devcb_base &set_data5_handler(device_t &device, _Object object) { return downcast(device).m_data5_handler.set_callback(object); } + template static devcb_base &set_data6_handler(device_t &device, _Object object) { return downcast(device).m_data6_handler.set_callback(object); } + template static devcb_base &set_data7_handler(device_t &device, _Object object) { return downcast(device).m_data7_handler.set_callback(object); } + template static devcb_base &set_ack_handler(device_t &device, _Object object) { return downcast(device).m_ack_handler.set_callback(object); } + template static devcb_base &set_busy_handler(device_t &device, _Object object) { return downcast(device).m_busy_handler.set_callback(object); } + template static devcb_base &set_perror_handler(device_t &device, _Object object) { return downcast(device).m_perror_handler.set_callback(object); } + template static devcb_base &set_select_handler(device_t &device, _Object object) { return downcast(device).m_select_handler.set_callback(object); } + template static devcb_base &set_autofd_handler(device_t &device, _Object object) { return downcast(device).m_autofd_handler.set_callback(object); } + template static devcb_base &set_fault_handler(device_t &device, _Object object) { return downcast(device).m_fault_handler.set_callback(object); } + template static devcb_base &set_init_handler(device_t &device, _Object object) { return downcast(device).m_init_handler.set_callback(object); } + template static devcb_base &set_select_in_handler(device_t &device, _Object object) { return downcast(device).m_select_in_handler.set_callback(object); } + + DECLARE_WRITE_LINE_MEMBER( write_strobe ); + DECLARE_WRITE_LINE_MEMBER( write_data0 ); + DECLARE_WRITE_LINE_MEMBER( write_data1 ); + DECLARE_WRITE_LINE_MEMBER( write_data2 ); + DECLARE_WRITE_LINE_MEMBER( write_data3 ); + DECLARE_WRITE_LINE_MEMBER( write_data4 ); + DECLARE_WRITE_LINE_MEMBER( write_data5 ); + DECLARE_WRITE_LINE_MEMBER( write_data6 ); + DECLARE_WRITE_LINE_MEMBER( write_data7 ); + DECLARE_WRITE_LINE_MEMBER( write_ack ); + DECLARE_WRITE_LINE_MEMBER( write_busy ); + DECLARE_WRITE_LINE_MEMBER( write_perror ); + DECLARE_WRITE_LINE_MEMBER( write_select ); + DECLARE_WRITE_LINE_MEMBER( write_autofd ); + DECLARE_WRITE_LINE_MEMBER( write_fault ); + DECLARE_WRITE_LINE_MEMBER( write_init ); + DECLARE_WRITE_LINE_MEMBER( write_select_in ); + +protected: + // device-level overrides + virtual void device_config_complete(); + virtual void device_start(); + + devcb_write_line m_strobe_handler; + devcb_write_line m_data0_handler; + devcb_write_line m_data1_handler; + devcb_write_line m_data2_handler; + devcb_write_line m_data3_handler; + devcb_write_line m_data4_handler; + devcb_write_line m_data5_handler; + devcb_write_line m_data6_handler; + devcb_write_line m_data7_handler; + devcb_write_line m_ack_handler; + devcb_write_line m_busy_handler; + devcb_write_line m_perror_handler; + devcb_write_line m_select_handler; + devcb_write_line m_autofd_handler; + devcb_write_line m_fault_handler; + devcb_write_line m_init_handler; + devcb_write_line m_select_in_handler; + +private: + device_centronics_peripheral_interface *m_dev; +}; + + +class device_centronics_peripheral_interface : public device_slot_card_interface +{ + friend class centronics_device; + +public: + device_centronics_peripheral_interface(const machine_config &mconfig, device_t &device); + virtual ~device_centronics_peripheral_interface(); + + DECLARE_WRITE_LINE_MEMBER( output_strobe ) { m_slot->m_strobe_handler(state); } + DECLARE_WRITE_LINE_MEMBER( output_data0 ) { m_slot->m_data0_handler(state); } + DECLARE_WRITE_LINE_MEMBER( output_data1 ) { m_slot->m_data1_handler(state); } + DECLARE_WRITE_LINE_MEMBER( output_data2 ) { m_slot->m_data2_handler(state); } + DECLARE_WRITE_LINE_MEMBER( output_data3 ) { m_slot->m_data3_handler(state); } + DECLARE_WRITE_LINE_MEMBER( output_data4 ) { m_slot->m_data4_handler(state); } + DECLARE_WRITE_LINE_MEMBER( output_data5 ) { m_slot->m_data5_handler(state); } + DECLARE_WRITE_LINE_MEMBER( output_data6 ) { m_slot->m_data6_handler(state); } + DECLARE_WRITE_LINE_MEMBER( output_data7 ) { m_slot->m_data7_handler(state); } + DECLARE_WRITE_LINE_MEMBER( output_ack ) { m_slot->m_ack_handler(state); } + DECLARE_WRITE_LINE_MEMBER( output_busy ) { m_slot->m_busy_handler(state); } + DECLARE_WRITE_LINE_MEMBER( output_perror ) { m_slot->m_perror_handler(state); } + DECLARE_WRITE_LINE_MEMBER( output_select ) { m_slot->m_select_handler(state); } + DECLARE_WRITE_LINE_MEMBER( output_autofd ) { m_slot->m_autofd_handler(state); } + DECLARE_WRITE_LINE_MEMBER( output_fault ) { m_slot->m_fault_handler(state); } + DECLARE_WRITE_LINE_MEMBER( output_init ) { m_slot->m_init_handler(state); } + DECLARE_WRITE_LINE_MEMBER( output_select_in ) { m_slot->m_select_in_handler(state); } + +protected: + virtual DECLARE_WRITE_LINE_MEMBER( input_strobe ) {} + virtual DECLARE_WRITE_LINE_MEMBER( input_data0 ) {} + virtual DECLARE_WRITE_LINE_MEMBER( input_data1 ) {} + virtual DECLARE_WRITE_LINE_MEMBER( input_data2 ) {} + virtual DECLARE_WRITE_LINE_MEMBER( input_data3 ) {} + virtual DECLARE_WRITE_LINE_MEMBER( input_data4 ) {} + virtual DECLARE_WRITE_LINE_MEMBER( input_data5 ) {} + virtual DECLARE_WRITE_LINE_MEMBER( input_data6 ) {} + virtual DECLARE_WRITE_LINE_MEMBER( input_data7 ) {} + virtual DECLARE_WRITE_LINE_MEMBER( input_ack ) {} + virtual DECLARE_WRITE_LINE_MEMBER( input_busy ) {} + virtual DECLARE_WRITE_LINE_MEMBER( input_perror ) {} + virtual DECLARE_WRITE_LINE_MEMBER( input_select ) {} + virtual DECLARE_WRITE_LINE_MEMBER( input_autofd ) {} + virtual DECLARE_WRITE_LINE_MEMBER( input_fault ) {} + virtual DECLARE_WRITE_LINE_MEMBER( input_init ) {} + virtual DECLARE_WRITE_LINE_MEMBER( input_select_in ) {} + + centronics_device *m_slot; +}; + + +SLOT_INTERFACE_EXTERN( centronics_devices ); + +#endif diff --git a/src/devices/bus/centronics/digiblst.c b/src/devices/bus/centronics/digiblst.c new file mode 100644 index 00000000000..9fdbfd5c279 --- /dev/null +++ b/src/devices/bus/centronics/digiblst.c @@ -0,0 +1,63 @@ +// license:BSD-3-Clause +// copyright-holders:Barry Rodewald +/* + * digiblst.c + * + * Created on: 23/08/2014 + */ + +#include "emu.h" +#include "sound/dac.h" +#include "digiblst.h" + +//************************************************************************** +// COVOX DEVICE +//************************************************************************** + +// device type definition +const device_type CENTRONICS_DIGIBLASTER = &device_creator; + +static MACHINE_CONFIG_FRAGMENT( digiblst ) + /* sound hardware */ + MCFG_SPEAKER_STANDARD_MONO("mono") + + MCFG_SOUND_ADD("dac", DAC, 0) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 1.0) +MACHINE_CONFIG_END + + +/*************************************************************************** + IMPLEMENTATION +***************************************************************************/ +//------------------------------------------------- +// centronics_covox_device - constructor +//------------------------------------------------- + +centronics_digiblaster_device::centronics_digiblaster_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, CENTRONICS_DIGIBLASTER, "Digiblaster (DIY)", tag, owner, clock, "digiblst", __FILE__), + device_centronics_peripheral_interface( mconfig, *this ), + m_dac(*this, "dac"), + m_data(0) +{ +} + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor centronics_digiblaster_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( digiblst ); +} + +void centronics_digiblaster_device::device_start() +{ + save_item(NAME(m_data)); +} + +void centronics_digiblaster_device::update_dac() +{ + if (started()) + m_dac->write_unsigned8(m_data); +} diff --git a/src/devices/bus/centronics/digiblst.h b/src/devices/bus/centronics/digiblst.h new file mode 100644 index 00000000000..340e5cd0f4c --- /dev/null +++ b/src/devices/bus/centronics/digiblst.h @@ -0,0 +1,60 @@ +// license:BSD-3-Clause +// copyright-holders:Barry Rodewald +/* + * digiblst.h + * + * Digiblaster - a DIY printer port DAC for the Amstrad CPC + * Printed in the German magazine CPC Amstrad International issue 8-9/1991 + * Uses Strobe (inverted on the CPC) for the 8th bit (CPCs only have 7-bit printer ports) + * + * Code borrows from the Covox Speech Thing device. + * + * Created on: 23/08/2014 + */ + +#ifndef DIGIBLST_H_ +#define DIGIBLST_H_ + +#pragma once + +#include "ctronics.h" +#include "sound/dac.h" + +// ======================> centronics_covox_device + +class centronics_digiblaster_device : public device_t, + public device_centronics_peripheral_interface +{ +public: + // construction/destruction + centronics_digiblaster_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + +protected: + // device-level overrides + virtual void device_start(); + + virtual DECLARE_WRITE_LINE_MEMBER( input_data0 ) { if (state) m_data |= 0x01; else m_data &= ~0x01; update_dac(); } + virtual DECLARE_WRITE_LINE_MEMBER( input_data1 ) { if (state) m_data |= 0x02; else m_data &= ~0x02; update_dac(); } + virtual DECLARE_WRITE_LINE_MEMBER( input_data2 ) { if (state) m_data |= 0x04; else m_data &= ~0x04; update_dac(); } + virtual DECLARE_WRITE_LINE_MEMBER( input_data3 ) { if (state) m_data |= 0x08; else m_data &= ~0x08; update_dac(); } + virtual DECLARE_WRITE_LINE_MEMBER( input_data4 ) { if (state) m_data |= 0x10; else m_data &= ~0x10; update_dac(); } + virtual DECLARE_WRITE_LINE_MEMBER( input_data5 ) { if (state) m_data |= 0x20; else m_data &= ~0x20; update_dac(); } + virtual DECLARE_WRITE_LINE_MEMBER( input_data6 ) { if (state) m_data |= 0x40; else m_data &= ~0x40; update_dac(); } + virtual DECLARE_WRITE_LINE_MEMBER( input_strobe ) { if (state) m_data &= ~0x80; else m_data |= 0x80; update_dac(); } + +private: + required_device m_dac; + + void update_dac(); + + UINT8 m_data; +}; + +// device type definition +extern const device_type CENTRONICS_DIGIBLASTER; + + +#endif /* DIGIBLST_H_ */ diff --git a/src/devices/bus/centronics/dsjoy.c b/src/devices/bus/centronics/dsjoy.c new file mode 100644 index 00000000000..de9b1138ec8 --- /dev/null +++ b/src/devices/bus/centronics/dsjoy.c @@ -0,0 +1,48 @@ +// license:BSD-3-Clause +// copyright-holders:smf + +#include "dsjoy.h" + +const device_type DEMPA_SHINBUNSHA_JOYSTICK = &device_creator; + +dempa_shinbunsha_joystick_device::dempa_shinbunsha_joystick_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, DEMPA_SHINBUNSHA_JOYSTICK, "Dempa Shinbunsha Joystick", tag, owner, clock, "dempa_shinbunsha_joystick", __FILE__), + device_centronics_peripheral_interface( mconfig, *this ), + m_lptjoy(*this, "lptjoy"), + m_data(0xff), + m_perror(1) +{ +} + +void dempa_shinbunsha_joystick_device::device_start() +{ + save_item(NAME(m_data)); + save_item(NAME(m_perror)); +} + +void dempa_shinbunsha_joystick_device::update_perror() +{ + int perror = (~m_data & ~m_lptjoy->read() & 0x3f) == 0; + + if (m_perror != perror) + { + m_perror = perror; + + output_perror(perror); + } +} + +static INPUT_PORTS_START( dempa_shinbunsha_joystick ) + PORT_START("lptjoy") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT) PORT_NAME("LPT Joystick Right") PORT_8WAY PORT_PLAYER(1) + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT) PORT_NAME("LPT Joystick Left") PORT_8WAY PORT_PLAYER(1) + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_JOYSTICK_UP) PORT_NAME("LPT Joystick Up") PORT_8WAY PORT_PLAYER(1) + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN) PORT_NAME("LPT Joystick Down") PORT_8WAY PORT_PLAYER(1) + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_BUTTON2) PORT_NAME("LPT Joystick Button 2") PORT_PLAYER(1) + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_BUTTON1) PORT_NAME("LPT Joystick Button 1") PORT_PLAYER(1) +INPUT_PORTS_END + +ioport_constructor dempa_shinbunsha_joystick_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( dempa_shinbunsha_joystick ); +} diff --git a/src/devices/bus/centronics/dsjoy.h b/src/devices/bus/centronics/dsjoy.h new file mode 100644 index 00000000000..a6eec3668ad --- /dev/null +++ b/src/devices/bus/centronics/dsjoy.h @@ -0,0 +1,47 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/*************************************************************************** + + Dempa Shinbunsha Joystick + +***************************************************************************/ + +#ifndef __CENTRONICS_DSJOY_H__ +#define __CENTRONICS_DSJOY_H__ + +#pragma once + +#include "ctronics.h" + +class dempa_shinbunsha_joystick_device : public device_t, + public device_centronics_peripheral_interface +{ +public: + // construction/destruction + dempa_shinbunsha_joystick_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // device-level overrides + virtual void device_start(); + virtual ioport_constructor device_input_ports() const; + + virtual DECLARE_WRITE_LINE_MEMBER( input_data0 ) { if (state) m_data |= 0x01; else m_data &= ~0x01; update_perror(); } + virtual DECLARE_WRITE_LINE_MEMBER( input_data1 ) { if (state) m_data |= 0x02; else m_data &= ~0x02; update_perror(); } + virtual DECLARE_WRITE_LINE_MEMBER( input_data2 ) { if (state) m_data |= 0x04; else m_data &= ~0x04; update_perror(); } + virtual DECLARE_WRITE_LINE_MEMBER( input_data3 ) { if (state) m_data |= 0x08; else m_data &= ~0x08; update_perror(); } + virtual DECLARE_WRITE_LINE_MEMBER( input_data4 ) { if (state) m_data |= 0x10; else m_data &= ~0x10; update_perror(); } + virtual DECLARE_WRITE_LINE_MEMBER( input_data5 ) { if (state) m_data |= 0x20; else m_data &= ~0x20; update_perror(); } + +private: + required_ioport m_lptjoy; + + void update_perror(); + + UINT8 m_data; + int m_perror; +}; + +// device type definition +extern const device_type DEMPA_SHINBUNSHA_JOYSTICK; + +#endif diff --git a/src/devices/bus/centronics/epson_ex800.c b/src/devices/bus/centronics/epson_ex800.c new file mode 100644 index 00000000000..9555284c711 --- /dev/null +++ b/src/devices/bus/centronics/epson_ex800.c @@ -0,0 +1,496 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best +/****************************************************************************** + + Epson EX-800 Dot Matrix printer + + + -- + + Main CPU is a UPD7810H6 running at 12 MHz. + + -- + + On startup, the ports are initialized as follows: + + Port A lines PA0-PA7 are configured as output + Port B lines PB0-PB7 are configured as output + Port C lines PC2, PC4 and PC5 are configured as output + the other lines are control lines + PC0: TxD output + PC1: RxD input + PC3: TI input + PC6: CO0 output + PC7: CO1 output + +The I/O lines are connected as follows: + +PA0: \ +PA1: Carriage motor +PA2: driving pulses +PA3: / +PA4: High when carriage assembly reaches either end +PA5: High when carriage assembly reaches either end +PA6: Bank 0 +PA7: Bank 1 + +PB0: Line feed motor driving pulses +PB1: Line feed motor driving pulses +PB2: Line feed motor current control +PB3: LED09, Online +PB4: (used for serial port) +PB5: ERR signal +PB6: ACKNLG signal, data received at printer +PB7: LED12, Paper empty + +PC0: TxD output +PC1: RxD input +PC2: +PC3: TI input +PC4: +PC5: +PC6: PWD signal of 5a +PC7: Buzzer + +PD0-7: Data bus D0-D7 + +PF0-7: Address bus A8-A15 + +AN0: DSW 2 +AN1: DSW 1 +AN2: +AN3: +AN4: Print head operating temperature sensor +AN5: Scanner Unit, Color Home sensor +AN6: +AN7: Color Home sensor adjust + +INT: Online switch + + +Gate array 5a (parallel port, printer head) + +IN0-IN7: DATA1 to DATA8 from parallel port +HD1-HD9: Head driving pulses +STROBE: STROBE signal +PWD: PC6 of CPU +ALE: ALE of CPU + +Gate array 7a (inputs) + +- activated when carriage assembly reaches either end? + +PA0: Draft switch +PA1: NLQ Roman switch +PA2: Pica switch +PA3: NLQ sans-serif switch +PA4: Elite switch +PA5: Proportional switch +PA6: Normal switch +PA7: Condensed switch + +PB0: Form feed switch +PB1: Line feed switch +PB2: Autoload switch +PB3: Low when paper empty +PB4: Low when carriage assembly is in home position +PB5: SLCTIN (connected to parallel port), disable with DSW2-1 +PB6: AUTO FEEDXT (connected to parallel port), disable with DSW2-4 + "When this signal is LOW, the paper is automatically fed 1 line after + printing." +PB7: + +PC0: Dipswitch SW1-1 and SW1-2, Draft LED +PC1: Dipswitch SW1-3 and SW1-4, Roman LED +PC2: Dipswitch SW1-5 and SW1-6, Pica LED +PC3: Dipswitch SW1-7 and SW1-8, Sans-Serif LED +PC4: Dipswitch SW2-2 and SW2-3, Elite LED +PC5: Dipswitch SW2-5 and SW2-6, Proportional LED +PC6: Normal LED +PC7: Condensed LED + +-- + +LED state on startup: + +The power light comes on, then draft, pica and normal. If there is no paper, +the paper empty LED comes on. + +Power LED is green, selectype LED is orange, paper out LED is red. + +-- + +TODO: - The UPD7810 core is missing analog port emulation + - Figure out the gate arrays (using trojan code?) + - (much later) write an interface so that other drivers can hook + into this one and use to print + +******************************************************************************/ + +#include "epson_ex800.h" +#include "ex800.lh" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define PA0 (data & 0x01) +#define PA1 (data & 0x02) +#define PA2 (data & 0x04) +#define PA3 (data & 0x08) +#define PA4 (data & 0x10) +#define PA5 (data & 0x20) +#define PA6 (data & 0x40) +#define PA7 (data & 0x80) + +#define PB0 (data & 0x01) +#define PB1 (data & 0x02) +#define PB2 (data & 0x04) +#define PB3 (data & 0x08) +#define PB4 (data & 0x10) +#define PB5 (data & 0x20) +#define PB6 (data & 0x40) +#define PB7 (data & 0x80) + +#define PC0 (data & 0x01) +#define PC1 (data & 0x02) +#define PC2 (data & 0x04) +#define PC3 (data & 0x08) +#define PC4 (data & 0x10) +#define PC5 (data & 0x20) +#define PC6 (data & 0x40) +#define PC7 (data & 0x80) + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type EPSON_EX800 = &device_creator; + + +//------------------------------------------------- +// ROM( ex800 ) +//------------------------------------------------- + +ROM_START( ex800 ) + ROM_REGION(0x8000, "maincpu", 0) + ROM_LOAD("w8_pe9.9b", 0x0000, 0x8000, CRC(6dd41e9b) SHA1(8e30ead727b9317154742efd881206e9f9bbf95b)) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *epson_ex800_t::device_rom_region() const +{ + return ROM_NAME( ex800 ); +} + + +//------------------------------------------------- +// ADDRESS_MAP( ex800_mem ) +//------------------------------------------------- + +static ADDRESS_MAP_START( ex800_mem, AS_PROGRAM, 8, epson_ex800_t ) + AM_RANGE(0x0000, 0x7fff) AM_ROM AM_REGION("maincpu", 0) + AM_RANGE(0x8000, 0xbfff) AM_RAM /* external RAM */ + AM_RANGE(0xc000, 0xc7ff) AM_MIRROR(0x1800) AM_READWRITE(devsel_r, devsel_w) + AM_RANGE(0xe000, 0xe7ff) AM_READWRITE(gate5a_r, gate5a_w) + AM_RANGE(0xe800, 0xefff) AM_READWRITE(iosel_r, iosel_w) + AM_RANGE(0xf000, 0xf001) AM_MIRROR(0x07fc) AM_READ(gate7a_r) + AM_RANGE(0xf002, 0xf003) AM_MIRROR(0x07fc) AM_WRITE(gate7a_w) + AM_RANGE(0xf800, 0xfeff) AM_NOP /* not connected */ + AM_RANGE(0xff00, 0xffff) AM_RAM /* internal CPU RAM */ +ADDRESS_MAP_END + + +//------------------------------------------------- +// ADDRESS_MAP( ex800_io ) +//------------------------------------------------- + +static ADDRESS_MAP_START( ex800_io, AS_IO, 8, epson_ex800_t ) + AM_RANGE(UPD7810_PORTA, UPD7810_PORTA) AM_READ(porta_r) AM_WRITE(porta_w) + AM_RANGE(UPD7810_PORTB, UPD7810_PORTB) AM_READ(portb_r) AM_WRITE(portb_w) + AM_RANGE(UPD7810_PORTC, UPD7810_PORTC) AM_READ(portc_r) AM_WRITE(portc_w) +ADDRESS_MAP_END + + +//------------------------------------------------- +// MACHINE_DRIVER( epson_ex800 ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( epson_ex800 ) + /* basic machine hardware */ + MCFG_CPU_ADD("maincpu", UPD7810, 12000000) /* 12 MHz? */ + MCFG_CPU_PROGRAM_MAP(ex800_mem) + MCFG_CPU_IO_MAP(ex800_io) + + + MCFG_DEFAULT_LAYOUT(layout_ex800) + + /* audio hardware */ + MCFG_SPEAKER_STANDARD_MONO("mono") + MCFG_SOUND_ADD("beeper", BEEP, 0) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 1.0) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor epson_ex800_t::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( epson_ex800 ); +} + + +/* The ON LINE switch is directly connected to the INT1 input of the CPU */ +INPUT_CHANGED_MEMBER(epson_ex800_t::online_switch) +{ + if (newval) + { + m_maincpu->set_input_line(UPD7810_INTF1, m_irq_state); + m_irq_state = (m_irq_state == ASSERT_LINE) ? CLEAR_LINE : ASSERT_LINE; + } +} + + +//------------------------------------------------- +// INPUT_PORTS( epson_ex800 ) +//------------------------------------------------- + +INPUT_PORTS_START( epson_ex800 ) + PORT_START("ONLISW") + PORT_BIT(0xfe, IP_ACTIVE_HIGH, IPT_UNUSED) + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("ON LINE") PORT_CODE(KEYCODE_F9) PORT_CHANGED_MEMBER(DEVICE_SELF, epson_ex800_t, online_switch, NULL) + + PORT_START("FEED") + PORT_BIT(0xfc, IP_ACTIVE_LOW, IPT_UNUSED) + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("FORM FEED") PORT_CODE(KEYCODE_F10) + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("LINE FEED") PORT_CODE(KEYCODE_F11) + + PORT_START("SelecType") + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Draft") PORT_CODE(KEYCODE_F8) + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("NLQ Roman") PORT_CODE(KEYCODE_F7) + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Pica") PORT_CODE(KEYCODE_F6) + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("NLQ Sans Serif") PORT_CODE(KEYCODE_F5) + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Elite") PORT_CODE(KEYCODE_F4) + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Proportional") PORT_CODE(KEYCODE_F3) + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME(DEF_STR(Normal)) PORT_CODE(KEYCODE_F2) + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Condensed") PORT_CODE(KEYCODE_F1) + + PORT_START("DSW_1") + PORT_DIPNAME(0x01, 0x00, "Condensed characters") + PORT_DIPSETTING( 0x00, DEF_STR(Off)) + PORT_DIPSETTING( 0x01, DEF_STR(On)) + PORT_DIPNAME(0x02, 0x00, "Slashed zero") + PORT_DIPSETTING( 0x00, DEF_STR(Off)) + PORT_DIPSETTING( 0x02, DEF_STR(On)) + PORT_DIPNAME(0x04, 0x00, "Character table") + PORT_DIPSETTING( 0x00, "Italics") + PORT_DIPSETTING( 0x04, "Graphics") + PORT_DIPNAME(0x08, 0x00, "Printer commands") + PORT_DIPSETTING( 0x00, "ESC/P") + PORT_DIPSETTING( 0x08, "IBM printer emulation") + PORT_DIPNAME(0x10, 0x00, "Print quality") + PORT_DIPSETTING( 0x00, "Draft") + PORT_DIPSETTING( 0x10, "NLQ") + PORT_DIPNAME(0xe0, 0x00, "Int. character set") + PORT_DIPSETTING( 0x00, DEF_STR(USA)) + PORT_DIPSETTING( 0x20, DEF_STR(French)) + PORT_DIPSETTING( 0x30, DEF_STR(German)) + PORT_DIPSETTING( 0x40, "UK") + PORT_DIPSETTING( 0x50, "Danish") + PORT_DIPSETTING( 0x60, "Swedish") + PORT_DIPSETTING( 0x70, DEF_STR(Italian)) + PORT_DIPSETTING( 0x80, DEF_STR(Spanish)) + + PORT_START("DSW_2") + PORT_DIPNAME(0x01, 0x00, "Page length") + PORT_DIPSETTING( 0x00, "11 inch") + PORT_DIPSETTING( 0x01, "12 inch") + PORT_DIPNAME(0x02, 0x00, "Auto. sheet feeder") + PORT_DIPSETTING( 0x00, "Canceled") + PORT_DIPSETTING( 0x02, "Selected") + PORT_DIPNAME(0x04, 0x00, "Skip-over-perforation") + PORT_DIPSETTING( 0x00, DEF_STR(None)) + PORT_DIPSETTING( 0x04, "1 inch") + PORT_DIPNAME(0x08, 0x00, "Add LF after CR") + PORT_DIPSETTING( 0x00, "CR only") + PORT_DIPSETTING( 0x08, "CR + LF") + PORT_DIPNAME(0x30, 0x00, "Interface type") + PORT_DIPSETTING( 0x00, "Parallel") + PORT_DIPSETTING( 0x10, "Serial (odd parity)") + PORT_DIPSETTING( 0x20, "Serial (even parity)") + PORT_DIPSETTING( 0x30, "Serial (no parity)") + PORT_DIPNAME(0xc0, 0x00, "Baud rate") + PORT_DIPSETTING( 0x00, "9600") + PORT_DIPSETTING( 0x40, "4800") + PORT_DIPSETTING( 0x80, "1200") + PORT_DIPSETTING( 0xc0, "300") +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor epson_ex800_t::device_input_ports() const +{ + return INPUT_PORTS_NAME( epson_ex800 ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// epson_ex800_t - constructor +//------------------------------------------------- + +epson_ex800_t::epson_ex800_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, EPSON_EX800, "Epson EX-800", tag, owner, clock, "ex800", __FILE__), + device_centronics_peripheral_interface(mconfig, *this), + m_maincpu(*this, "maincpu"), + m_beeper(*this, "beeper") +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void epson_ex800_t::device_start() +{ + m_irq_state = ASSERT_LINE; +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void epson_ex800_t::device_reset() +{ + /* Setup beep */ + m_beeper->set_state(0); + m_beeper->set_frequency(4000); /* measured at 4000 Hz */ +} + + +READ8_MEMBER(epson_ex800_t::porta_r) +{ + logerror("PA R @%x\n", space.device().safe_pc()); + return machine().rand(); +} + +READ8_MEMBER(epson_ex800_t::portb_r) +{ + logerror("PB R @%x\n", space.device().safe_pc()); + return machine().rand(); +} + +READ8_MEMBER(epson_ex800_t::portc_r) +{ + logerror("PC R @%x\n", space.device().safe_pc()); + return machine().rand(); +} + +WRITE8_MEMBER(epson_ex800_t::porta_w) +{ + if (PA6) logerror("BNK0 selected.\n"); + if (PA7) logerror("BNK1 selected.\n"); + + logerror("PA W %x @%x\n", data, space.device().safe_pc()); +} + +WRITE8_MEMBER(epson_ex800_t::portb_w) +{ + if (data & 3) + logerror("PB0/1 Line feed @%x\n", space.device().safe_pc()); + if (!(data & 4)) + logerror("PB2 Line feed @%x\n", space.device().safe_pc()); + if (data & 8) + logerror("PB3 Online LED on @%x\n", space.device().safe_pc()); + else + logerror("PB3 Online LED off @%x\n", space.device().safe_pc()); + if (data & 16) + logerror("PB4 Serial @%x\n", space.device().safe_pc()); + if (data & 32) + logerror("PB4 Serial @%x\n", space.device().safe_pc()); + if (data & 64) + logerror("PB4 Serial @%x\n", space.device().safe_pc()); + if (data & 128) + logerror("PB3 Paper empty LED on @%x\n", space.device().safe_pc()); + else + logerror("PB3 Paper empty LED off @%x\n", space.device().safe_pc()); + +// logerror("PB W %x @%x\n", data, space.device().safe_pc()); +} + +WRITE8_MEMBER(epson_ex800_t::portc_w) +{ + if (data & 0x80) + m_beeper->set_state(0); + else + m_beeper->set_state(1); + + logerror("PC W %x @%x\n", data, space.device().safe_pc()); +} + + +/* Memory mapped I/O access */ + +READ8_MEMBER(epson_ex800_t::devsel_r) +{ + logerror("DEVSEL R @%x with offset %x\n", space.device().safe_pc(), offset); + return machine().rand(); +} + +WRITE8_MEMBER(epson_ex800_t::devsel_w) +{ + logerror("DEVSEL W %x @%x with offset %x\n", data, space.device().safe_pc(), offset); +} + +READ8_MEMBER(epson_ex800_t::gate5a_r) +{ + logerror("GATE5A R @%x with offset %x\n", space.device().safe_pc(), offset); + return machine().rand(); +} + +WRITE8_MEMBER(epson_ex800_t::gate5a_w) +{ + logerror("GATE5A W %x @%x with offset %x\n", data, space.device().safe_pc(), offset); +} + +READ8_MEMBER(epson_ex800_t::iosel_r) +{ + logerror("IOSEL R @%x with offset %x\n", space.device().safe_pc(), offset); + return machine().rand(); +} + +WRITE8_MEMBER(epson_ex800_t::iosel_w) +{ + logerror("IOSEL W %x @%x with offset %x\n", data, space.device().safe_pc(), offset); +} + +READ8_MEMBER(epson_ex800_t::gate7a_r) +{ + logerror("GATE7A R @%x with offset %x\n", space.device().safe_pc(), offset); + return machine().rand(); +} + +WRITE8_MEMBER(epson_ex800_t::gate7a_w) +{ + logerror("GATE7A W %x @%x with offset %x\n", data, space.device().safe_pc(), offset); +} diff --git a/src/devices/bus/centronics/epson_ex800.h b/src/devices/bus/centronics/epson_ex800.h new file mode 100644 index 00000000000..274eac50bf0 --- /dev/null +++ b/src/devices/bus/centronics/epson_ex800.h @@ -0,0 +1,76 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best +/********************************************************************** + + Epson EX-800 dot matrix printer emulation + +**********************************************************************/ + +#pragma once + +#ifndef __EPSON_EX800__ +#define __EPSON_EX800__ + +#include "emu.h" +#include "ctronics.h" +#include "cpu/upd7810/upd7810.h" +#include "sound/beep.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> epson_ex800_t + +class epson_ex800_t : public device_t, + public device_centronics_peripheral_interface +{ +public: + // construction/destruction + epson_ex800_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + epson_ex800_t(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + virtual ioport_constructor device_input_ports() const; + + DECLARE_READ8_MEMBER(porta_r); + DECLARE_READ8_MEMBER(portb_r); + DECLARE_READ8_MEMBER(portc_r); + DECLARE_WRITE8_MEMBER(porta_w); + DECLARE_WRITE8_MEMBER(portb_w); + DECLARE_WRITE8_MEMBER(portc_w); + DECLARE_READ8_MEMBER(devsel_r); + DECLARE_WRITE8_MEMBER(devsel_w); + DECLARE_READ8_MEMBER(gate5a_r); + DECLARE_WRITE8_MEMBER(gate5a_w); + DECLARE_READ8_MEMBER(iosel_r); + DECLARE_WRITE8_MEMBER(iosel_w); + DECLARE_READ8_MEMBER(gate7a_r); + DECLARE_WRITE8_MEMBER(gate7a_w); + + DECLARE_INPUT_CHANGED_MEMBER(online_switch); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + +private: + required_device m_maincpu; + required_device m_beeper; + + int m_irq_state; +}; + + + +// device type definition +extern const device_type EPSON_EX800; + + + +#endif diff --git a/src/devices/bus/centronics/epson_lx800.c b/src/devices/bus/centronics/epson_lx800.c new file mode 100644 index 00000000000..cfcffb7329c --- /dev/null +++ b/src/devices/bus/centronics/epson_lx800.c @@ -0,0 +1,358 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best +/********************************************************************** + + Epson LX-800 dot matrix printer + + Skeleton driver + + - CPU type uPD7810HG + - CPU PORTD and PORTF are connected to the Gate Array + - processing gets stuck in a loop, and never gets to scan the + input buttons and switches. + - CPU disassembly doesn't seem to indicate conditional JR or RET. + +**********************************************************************/ + +#include "epson_lx800.h" +#include "lx800.lh" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type EPSON_LX800 = &device_creator; + + +//------------------------------------------------- +// ROM( lx800 ) +//------------------------------------------------- + +ROM_START( lx800 ) + ROM_REGION(0x8000, "maincpu", 0) + ROM_LOAD("lx800.ic3c", 0x0000, 0x8000, CRC(da06c45b) SHA1(9618c940dd10d5b43cd1edd5763b90e6447de667) ) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *epson_lx800_t::device_rom_region() const +{ + return ROM_NAME( lx800 ); +} + + +//------------------------------------------------- +// ADDRESS_MAP( lx800_mem ) +//------------------------------------------------- + +static ADDRESS_MAP_START( lx800_mem, AS_PROGRAM, 8, epson_lx800_t ) + AM_RANGE(0x0000, 0x7fff) AM_ROM /* 32k firmware */ + AM_RANGE(0x8000, 0x9fff) AM_RAM /* 8k external RAM */ + AM_RANGE(0xa000, 0xbfff) AM_NOP /* not used */ + AM_RANGE(0xc000, 0xdfff) AM_MIRROR(0x1ff8) AM_DEVREADWRITE("ic3b", e05a03_device, read, write) + AM_RANGE(0xe000, 0xfeff) AM_NOP /* not used */ + AM_RANGE(0xff00, 0xffff) AM_RAM /* internal CPU RAM */ +ADDRESS_MAP_END + + +//------------------------------------------------- +// ADDRESS_MAP( lx800_io ) +//------------------------------------------------- + +static ADDRESS_MAP_START( lx800_io, AS_IO, 8, epson_lx800_t ) + AM_RANGE(UPD7810_PORTA, UPD7810_PORTA) AM_READWRITE(porta_r, porta_w) + AM_RANGE(UPD7810_PORTB, UPD7810_PORTB) AM_READ_PORT("DIPSW1") + AM_RANGE(UPD7810_PORTC, UPD7810_PORTC) AM_READWRITE(portc_r, portc_w) +ADDRESS_MAP_END + + +//------------------------------------------------- +// MACHINE_DRIVER( epson_lx800 ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( epson_lx800 ) + /* basic machine hardware */ + MCFG_CPU_ADD("maincpu", UPD7810, XTAL_14_7456MHz) + MCFG_CPU_PROGRAM_MAP(lx800_mem) + MCFG_CPU_IO_MAP(lx800_io) + MCFG_UPD7810_AN0(READLINE(epson_lx800_t, an0_r)) + MCFG_UPD7810_AN1(READLINE(epson_lx800_t, an1_r)) + MCFG_UPD7810_AN2(READLINE(epson_lx800_t, an2_r)) + MCFG_UPD7810_AN3(READLINE(epson_lx800_t, an3_r)) + MCFG_UPD7810_AN4(READLINE(epson_lx800_t, an4_r)) + MCFG_UPD7810_AN5(READLINE(epson_lx800_t, an5_r)) + + MCFG_DEFAULT_LAYOUT(layout_lx800) + + /* audio hardware */ + MCFG_SPEAKER_STANDARD_MONO("mono") + MCFG_SOUND_ADD("beeper", BEEP, 0) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.05) + + /* gate array */ + MCFG_DEVICE_ADD("ic3b", E05A03, 0) + MCFG_E05A03_PE_LP_CALLBACK(WRITELINE(epson_lx800_t, paperempty_led_w)) + MCFG_E05A03_RESO_CALLBACK(WRITELINE(epson_lx800_t, reset_w)) + MCFG_E05A03_PE_CALLBACK(WRITELINE(epson_lx800_t, centronics_pe_w)) + MCFG_E05A03_DATA_CALLBACK(READ8(epson_lx800_t, centronics_data_r)) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor epson_lx800_t::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( epson_lx800 ); +} + + +//------------------------------------------------- +// INPUT_PORTS( epson_lx800 ) +//------------------------------------------------- + +INPUT_PORTS_START( epson_lx800 ) + PORT_START("ONLINE") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("On Line") PORT_CODE(KEYCODE_O) + + PORT_START("FORMFEED") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Form Feed") PORT_CODE(KEYCODE_F) + + PORT_START("LINEFEED") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Line Feed") PORT_CODE(KEYCODE_L) + + PORT_START("DIPSW1") + PORT_DIPNAME(0x01, 0x00, "Typeface") + PORT_DIPLOCATION("DIP:8") + PORT_DIPSETTING(0x01, "Condensed") + PORT_DIPSETTING(0x00, DEF_STR(Normal)) + PORT_DIPNAME(0x02, 0x00, "ZERO font") + PORT_DIPLOCATION("DIP:7") + PORT_DIPSETTING(0x02, "0") + PORT_DIPSETTING(0x00, "0") + PORT_DIPNAME(0x04, 0x00, "Character Table") + PORT_DIPLOCATION("DIP:6") + PORT_DIPSETTING(0x04, "Graphic") + PORT_DIPSETTING(0x00, "Italic") + PORT_DIPNAME(0x08, 0x00, "Paper-out detection") + PORT_DIPLOCATION("DIP:5") + PORT_DIPSETTING(0x08, "Valid") + PORT_DIPSETTING(0x00, "Invalid") + PORT_DIPNAME(0x10, 0x00, "Printing quality") + PORT_DIPLOCATION("DIP:4") + PORT_DIPSETTING(0x10, "NLQ") + PORT_DIPSETTING(0x00, "Draft") + PORT_DIPNAME(0xe0, 0xe0, "International character set") + PORT_DIPLOCATION("DIP:3,2,1") + PORT_DIPSETTING(0xe0, "U.S.A.") + PORT_DIPSETTING(0x60, "France") + PORT_DIPSETTING(0xa0, "Germany") + PORT_DIPSETTING(0x20, "U.K.") + PORT_DIPSETTING(0xc0, "Denmark") + PORT_DIPSETTING(0x40, "Sweden") + PORT_DIPSETTING(0x80, "Italy") + PORT_DIPSETTING(0x00, "Spain") + + PORT_START("DIPSW2") + PORT_DIPNAME(0x01, 0x00, "Page length") + PORT_DIPLOCATION("DIP:4") + PORT_DIPSETTING(0x01, "12\"") + PORT_DIPSETTING(0x00, "11\"") + PORT_DIPNAME(0x02, 0x00, "Cut sheet feeder mode") + PORT_DIPLOCATION("DIP:3") + PORT_DIPSETTING(0x02, "Valid") + PORT_DIPSETTING(0x00, "Invalid") + PORT_DIPNAME(0x04, 0x00, "1\" skip over perforation") + PORT_DIPLOCATION("DIP:2") + PORT_DIPSETTING(0x04, "Valid") + PORT_DIPSETTING(0x00, "Invalid") + PORT_DIPNAME(0x08, 0x00, "AUTO FEED XT control") + PORT_DIPLOCATION("DIP:1") + PORT_DIPSETTING(0x08, "Fix to LOW") + PORT_DIPSETTING(0x00, "Depends on external signal") +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor epson_lx800_t::device_input_ports() const +{ + return INPUT_PORTS_NAME( epson_lx800 ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// epson_lx800_t - constructor +//------------------------------------------------- + +epson_lx800_t::epson_lx800_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, EPSON_LX800, "Epson LX-800", tag, owner, clock, "lx800", __FILE__), + device_centronics_peripheral_interface(mconfig, *this), + m_maincpu(*this, "maincpu"), + m_beep(*this, "beeper") +{ +} + +epson_lx800_t::epson_lx800_t(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, __FILE__), + device_centronics_peripheral_interface(mconfig, *this), + m_maincpu(*this, "maincpu"), + m_beep(*this, "beeper") +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void epson_lx800_t::device_start() +{ +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void epson_lx800_t::device_reset() +{ + m_beep->set_state(0); + m_beep->set_frequency(4000); /* ? */ +} + + +/*************************************************************************** + I/O PORTS +***************************************************************************/ + +/* PA0 W CRCOM carriage motor, 0 = holding voltage, 1 = drive voltage + * PA1 not used + * PA2 W PFCOM paper feed motor, 0 = holding voltage, 1 = drive voltage + * PA3 R LF SW line feed switch + * PA4 R FF SW form feed switch + * PA5 R PE SW paper end sensor, 0 = no paper, 1 = paper + * PA6 not used + * PA7 R P/S P/S signal from the optional interface + */ +READ8_MEMBER( epson_lx800_t::porta_r ) +{ + UINT8 result = 0; + + logerror("%s: lx800_porta_r(%02x)\n", machine().describe_context(), offset); + + result |= ioport("LINEFEED")->read() << 3; + result |= ioport("FORMFEED")->read() << 4; + result |= 1 << 5; + + result |= 1 << 7; + + return result; +} + +WRITE8_MEMBER( epson_lx800_t::porta_w ) +{ + logerror("%s: lx800_porta_w(%02x): %02x\n", machine().describe_context(), offset, data); + logerror("--> carriage: %d, paper feed: %d\n", BIT(data, 0), BIT(data, 2)); +} + +/* PC0 W TXD serial i/o txd + * PC1 R RXD serial i/o rxd + * PC2 W ONLINE LP online led + * PC3 R ONLINE SW online switch + * PC4 W ERR centronics error + * PC5 W ACK centronics acknowledge + * PC6 W FIRE drive pulse width signal + * PC7 W BUZZER buzzer signal + */ +READ8_MEMBER( epson_lx800_t::portc_r ) +{ + UINT8 result = 0; + + logerror("%s: lx800_portc_r(%02x)\n", machine().describe_context(), offset); + + result |= ioport("ONLINE")->read() << 3; + + return result; +} + +WRITE8_MEMBER( epson_lx800_t::portc_w ) +{ + logerror("%s: lx800_portc_w(%02x): %02x\n", machine().describe_context(), offset, data); + logerror("--> err: %d, ack: %d, fire: %d, buzzer: %d\n", BIT(data, 4), BIT(data, 5), BIT(data, 6), BIT(data, 7)); + + output_set_value("online_led", !BIT(data, 2)); + m_beep->set_state(!BIT(data, 7)); +} + +READ_LINE_MEMBER( epson_lx800_t::an0_r ) +{ + return BIT(ioport("DIPSW2")->read(), 0); +} + +READ_LINE_MEMBER( epson_lx800_t::an1_r ) +{ + return BIT(ioport("DIPSW2")->read(), 1); +} + +READ_LINE_MEMBER( epson_lx800_t::an2_r ) +{ + return BIT(ioport("DIPSW2")->read(), 2); +} + +READ_LINE_MEMBER( epson_lx800_t::an3_r ) +{ + return BIT(ioport("DIPSW2")->read(), 3); // can also read an external line AUTO_FEED_XT +} + +READ_LINE_MEMBER( epson_lx800_t::an4_r ) +{ + return 0; // Printer select line (0=always selected) +} + +READ_LINE_MEMBER( epson_lx800_t::an5_r ) +{ + return 1; // Monitors 24v line, should return 4.08 volts +} + + +/*************************************************************************** + GATE ARRAY +***************************************************************************/ + +READ8_MEMBER( epson_lx800_t::centronics_data_r ) +{ + logerror("centronics: data read\n"); + return 0x55; +} + +WRITE_LINE_MEMBER( epson_lx800_t::centronics_pe_w ) +{ + logerror("centronics: pe = %d\n", state); +} + +WRITE_LINE_MEMBER( epson_lx800_t::paperempty_led_w ) +{ + logerror("setting paperout led: %d\n", state); + output_set_value("paperout_led", state); +} + +WRITE_LINE_MEMBER( epson_lx800_t::reset_w ) +{ + logerror("cpu reset"); + m_maincpu->reset(); +} diff --git a/src/devices/bus/centronics/epson_lx800.h b/src/devices/bus/centronics/epson_lx800.h new file mode 100644 index 00000000000..591d75cbcf3 --- /dev/null +++ b/src/devices/bus/centronics/epson_lx800.h @@ -0,0 +1,73 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best +/********************************************************************** + + Epson LX-800 dot matrix printer emulation + +**********************************************************************/ + +#pragma once + +#ifndef __EPSON_LX800__ +#define __EPSON_LX800__ + +#include "emu.h" +#include "ctronics.h" +#include "cpu/upd7810/upd7810.h" +#include "machine/e05a03.h" +#include "sound/beep.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> epson_lx800_t + +class epson_lx800_t : public device_t, + public device_centronics_peripheral_interface +{ +public: + // construction/destruction + epson_lx800_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + epson_lx800_t(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + virtual ioport_constructor device_input_ports() const; + + DECLARE_READ8_MEMBER(porta_r); + DECLARE_WRITE8_MEMBER(porta_w); + DECLARE_READ8_MEMBER(portc_r); + DECLARE_WRITE8_MEMBER(portc_w); + DECLARE_READ8_MEMBER(centronics_data_r); + DECLARE_WRITE_LINE_MEMBER(centronics_pe_w); + DECLARE_WRITE_LINE_MEMBER(paperempty_led_w); + DECLARE_WRITE_LINE_MEMBER(reset_w); + DECLARE_READ_LINE_MEMBER(an0_r); + DECLARE_READ_LINE_MEMBER(an1_r); + DECLARE_READ_LINE_MEMBER(an2_r); + DECLARE_READ_LINE_MEMBER(an3_r); + DECLARE_READ_LINE_MEMBER(an4_r); + DECLARE_READ_LINE_MEMBER(an5_r); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + +private: + required_device m_maincpu; + required_device m_beep; +}; + + + +// device type definition +extern const device_type EPSON_LX800; + + + +#endif diff --git a/src/devices/bus/centronics/epson_lx810l.c b/src/devices/bus/centronics/epson_lx810l.c new file mode 100644 index 00000000000..eed6401875f --- /dev/null +++ b/src/devices/bus/centronics/epson_lx810l.c @@ -0,0 +1,632 @@ +// license:BSD-3-Clause +// copyright-holders:Ramiro Polla, Felipe Sanches +/* + * Epson LX-810L dot matrix printer emulation + + * IC list: + * uPD7810HG (cpu) + * E05A30 (gate array) + * 2064C (8k RAM) + * ER59256 (EEP-ROM - serial nvram) + * SLA7020M (step motor driver) + * uPC494C (pulse width modulation control) + * + * Devices boot and enter main input loop. Data is received through the + * centronics bus and printed as expected. The actual paper output is + * still not implemented, though. Look at the output from the fire signal + * (epson_lx810l_t::co0_w()) to see what's actually being printed. + * + * It is possible to run the printers' self test with this procedure: + * - Turn on device; + * - Toggle Line Feed button (press 'L'); + * - Reset device; + * - Toggle Line Feed button again; + * - Press Online button (press 'O'); + * - Press Online button again; + * + * The printer's carriage will seek home, it will pull in paper for a while, + * and it will start printing some test data. The Online LED will blink at + * each line. Look at the output from the fire signal to see what's actually + * being printed (epson_lx810l_t::co0_w()). + */ + +#include "epson_lx810l.h" +extern const char layout_lx800[]; /* use layout from lx800 */ + +//#define LX810LDEBUG +#ifdef LX810LDEBUG +#define LX810LLOG(...) fprintf(stderr, __VA_ARGS__) +#else +#define LX810LLOG(...) +#endif + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type EPSON_LX810L = &device_creator; +const device_type EPSON_AP2000 = &device_creator; + + +//------------------------------------------------- +// ROM( lx810l ) +//------------------------------------------------- + +ROM_START( lx810l ) + ROM_REGION(0x8000, "maincpu", 0) + ROM_LOAD("lx810l.ic3c", 0x0000, 0x8000, CRC(a66454e1) SHA1(8e6f2f98abcbd8af6e34b9ba746edf0d18aef843) ) + ROM_REGION(0x20, "eeprom", 0) + ROM_LOAD( "at93c06", 0x00, 0x20, NO_DUMP ) +ROM_END + + +//------------------------------------------------- +// ROM( ap2000 ) +//------------------------------------------------- + +ROM_START( ap2000 ) + ROM_REGION(0x8000, "maincpu", 0) + ROM_LOAD("ap2k.ic3c", 0x0000, 0x8000, CRC(ee7294b7) SHA1(219ffa6ff661ce95d5772c9fc1967093718f04e9) ) + ROM_REGION(0x20, "eeprom", 0) + ROM_LOAD( "at93c06", 0x00, 0x20, NO_DUMP ) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *epson_lx810l_t::device_rom_region() const +{ + return ROM_NAME( lx810l ); +} + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *epson_ap2000_t::device_rom_region() const +{ + return ROM_NAME( ap2000 ); +} + + +//------------------------------------------------- +// ADDRESS_MAP( lx810l_mem ) +//------------------------------------------------- + +static ADDRESS_MAP_START( lx810l_mem, AS_PROGRAM, 8, epson_lx810l_t ) + AM_RANGE(0x0000, 0x7fff) AM_ROM /* 32k firmware */ + AM_RANGE(0x8000, 0x9fff) AM_RAM /* 8k external RAM */ + AM_RANGE(0xa000, 0xbfff) AM_READWRITE(fakemem_r, fakemem_w) /* fake memory, write one, set all */ + AM_RANGE(0xc000, 0xdfff) AM_MIRROR(0x1ff0) AM_DEVREADWRITE("e05a30", e05a30_device, read, write) + AM_RANGE(0xe000, 0xfeff) AM_NOP /* not used */ + AM_RANGE(0xff00, 0xffff) AM_RAM /* internal CPU RAM */ +ADDRESS_MAP_END + + +//------------------------------------------------- +// ADDRESS_MAP( lx810l_io ) +//------------------------------------------------- + +static ADDRESS_MAP_START( lx810l_io, AS_IO, 8, epson_lx810l_t ) + AM_RANGE(UPD7810_PORTA, UPD7810_PORTA) AM_READWRITE(porta_r, porta_w) + AM_RANGE(UPD7810_PORTB, UPD7810_PORTB) AM_READWRITE(portb_r, portb_w) + AM_RANGE(UPD7810_PORTC, UPD7810_PORTC) AM_READWRITE(portc_r, portc_w) +ADDRESS_MAP_END + + +//------------------------------------------------- +// MACHINE_DRIVER( epson_lx810l ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( epson_lx810l ) + /* basic machine hardware */ + MCFG_CPU_ADD("maincpu", UPD7810, XTAL_14_7456MHz) + MCFG_CPU_PROGRAM_MAP(lx810l_mem) + MCFG_CPU_IO_MAP(lx810l_io) + MCFG_UPD7810_AN0(READ8(epson_lx810l_t, an0_r)) + MCFG_UPD7810_AN1(READ8(epson_lx810l_t, an1_r)) + MCFG_UPD7810_AN2(READ8(epson_lx810l_t, an2_r)) + MCFG_UPD7810_AN3(READ8(epson_lx810l_t, an3_r)) + MCFG_UPD7810_AN4(READ8(epson_lx810l_t, an4_r)) + MCFG_UPD7810_AN5(READ8(epson_lx810l_t, an5_r)) + MCFG_UPD7810_AN6(READ8(epson_lx810l_t, an6_r)) + MCFG_UPD7810_AN7(READ8(epson_lx810l_t, an7_r)) + MCFG_UPD7810_CO0(WRITELINE(epson_lx810l_t, co0_w)) + MCFG_UPD7810_CO1(WRITELINE(epson_lx810l_t, co1_w)) + + MCFG_DEFAULT_LAYOUT(layout_lx800) + + /* audio hardware */ + MCFG_SPEAKER_STANDARD_MONO("mono") + MCFG_SOUND_ADD("speaker", SPEAKER_SOUND, 0) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.25) + + /* gate array */ + MCFG_DEVICE_ADD("e05a30", E05A30, 0) + MCFG_E05A30_PRINTHEAD_CALLBACK(WRITE16(epson_lx810l_t, printhead)) + MCFG_E05A30_PF_STEPPER_CALLBACK(WRITE8(epson_lx810l_t, pf_stepper)) + MCFG_E05A30_CR_STEPPER_CALLBACK(WRITE8(epson_lx810l_t, cr_stepper)) + MCFG_E05A30_READY_CALLBACK(WRITELINE(epson_lx810l_t, e05a30_ready)) + MCFG_E05A30_CENTRONICS_ACK_CALLBACK(WRITELINE(epson_lx810l_t, e05a30_centronics_ack)) + MCFG_E05A30_CENTRONICS_BUSY_CALLBACK(WRITELINE(epson_lx810l_t, e05a30_centronics_busy)) + MCFG_E05A30_CENTRONICS_PERROR_CALLBACK(WRITELINE(epson_lx810l_t, e05a30_centronics_perror)) + MCFG_E05A30_CENTRONICS_FAULT_CALLBACK(WRITELINE(epson_lx810l_t, e05a30_centronics_fault)) + MCFG_E05A30_CENTRONICS_SELECT_CALLBACK(WRITELINE(epson_lx810l_t, e05a30_centronics_select)) + + /* 256-bit eeprom */ + MCFG_EEPROM_SERIAL_93C06_ADD("eeprom") + + /* steppers */ + //should this have MCFG_STEPPER_MAX_STEPS(200*2) ? code shows 200 steps... + MCFG_STEPPER_ADD("pf_stepper") + MCFG_STEPPER_REEL_TYPE(NOT_A_REEL) + MCFG_STEPPER_START_INDEX(16) + MCFG_STEPPER_END_INDEX(24) + MCFG_STEPPER_INDEX_PATTERN(0x00) + MCFG_STEPPER_INIT_PHASE(0) + + MCFG_STEPPER_ADD("cr_stepper") + MCFG_STEPPER_REEL_TYPE(NOT_A_REEL) + MCFG_STEPPER_START_INDEX(16) + MCFG_STEPPER_END_INDEX(24) + MCFG_STEPPER_INDEX_PATTERN(0x00) + MCFG_STEPPER_INIT_PHASE(2) + +MACHINE_CONFIG_END + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor epson_lx810l_t::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( epson_lx810l ); +} + + +/*************************************************************************** + INPUT PORTS +***************************************************************************/ + +static INPUT_PORTS_START( epson_lx810l ) + + /* Buttons on printer */ + PORT_START("ONLINE") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("On Line") PORT_CODE(KEYCODE_O) PORT_CHANGED_MEMBER(DEVICE_SELF, epson_lx810l_t, online_sw, NULL) + PORT_START("FORMFEED") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Form Feed") PORT_CODE(KEYCODE_F) PORT_TOGGLE + PORT_START("LINEFEED") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Line Feed") PORT_CODE(KEYCODE_L) PORT_TOGGLE + PORT_START("LOADEJECT") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Load/Eject") PORT_CODE(KEYCODE_E) + + /* DIPSW1 */ + PORT_START("DIPSW1") + + PORT_DIPNAME(0x01, 0x01, "Character spacing") + PORT_DIPLOCATION("DIP:1") + PORT_DIPSETTING(0x01, "12 cpi") /* default */ + PORT_DIPSETTING(0x00, "10 cpi") + + PORT_DIPNAME(0x02, 0x00, "Shape of zero") + PORT_DIPLOCATION("DIP:2") + PORT_DIPSETTING(0x02, "Slashed") + PORT_DIPSETTING(0x00, "Not slashed") /* default */ + + PORT_DIPNAME(0x0c, 0x08, "Page length") + PORT_DIPLOCATION("DIP:3,4") + PORT_DIPSETTING(0x00, "11 inches") + PORT_DIPSETTING(0x04, "12 inches") + PORT_DIPSETTING(0x08, "8.5 inches") /* default */ + PORT_DIPSETTING(0x0c, "11.7 inches") + + PORT_DIPNAME(0x10, 0x10, "Character table") + PORT_DIPLOCATION("DIP:5") + PORT_DIPSETTING(0x10, "Graphics") /* default */ + PORT_DIPSETTING(0x00, "Italics") + + PORT_DIPNAME(0xe0, 0xe0, "International characters and PC selection") + PORT_DIPLOCATION("DIP:6,7,8") + PORT_DIPSETTING(0xe0, "United States") /* default */ + PORT_DIPSETTING(0x60, "France") + PORT_DIPSETTING(0xa0, "Germany") + PORT_DIPSETTING(0x20, "United Kingdom") + PORT_DIPSETTING(0xc0, "Denmark") + PORT_DIPSETTING(0x40, "Sweden") + PORT_DIPSETTING(0x80, "Italy") + PORT_DIPSETTING(0x00, "Spain") + + /* DIPSW2 */ + PORT_START("DIPSW2") + + PORT_DIPNAME(0x01, 0x01, "Short tear-off") + PORT_DIPLOCATION("DIP:1") + PORT_DIPSETTING(0x01, "Invalid") /* default */ + PORT_DIPSETTING(0x00, "Valid") + + PORT_DIPNAME(0x02, 0x00, "Cut-sheet feeder mode") + PORT_DIPLOCATION("DIP:2") + PORT_DIPSETTING(0x02, "ON") + PORT_DIPSETTING(0x00, "OFF") /* default */ + + PORT_DIPNAME(0x04, 0x00, "Skip-over-perforation") + PORT_DIPLOCATION("DIP:3") + PORT_DIPSETTING(0x04, "ON") + PORT_DIPSETTING(0x00, "OFF") /* default */ + + PORT_DIPNAME(0x08, 0x00, "Auto line feed") + PORT_DIPLOCATION("DIP:4") + PORT_DIPSETTING(0x08, "ON") + PORT_DIPSETTING(0x00, "OFF") /* default */ + +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor epson_lx810l_t::device_input_ports() const +{ + return INPUT_PORTS_NAME( epson_lx810l ); +} + +INPUT_CHANGED_MEMBER(epson_lx810l_t::online_sw) +{ + m_maincpu->set_input_line(UPD7810_INTF2, newval ? CLEAR_LINE : ASSERT_LINE); +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// epson_lx810l_t - constructor +//------------------------------------------------- + +epson_lx810l_t::epson_lx810l_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, EPSON_LX810L, "Epson LX-810L", tag, owner, clock, "lx810l", __FILE__), + device_centronics_peripheral_interface(mconfig, *this), + m_maincpu(*this, "maincpu"), + m_pf_stepper(*this, "pf_stepper"), + m_cr_stepper(*this, "cr_stepper"), + m_eeprom(*this, "eeprom"), + m_speaker(*this, "speaker"), + m_e05a30(*this, "e05a30"), + m_93c06_clk(0), + m_93c06_cs(0), + m_printhead(0), + m_pf_pos_abs(200), + m_cr_pos_abs(200), + m_real_cr_pos(200), + m_real_cr_steps(0), + m_real_cr_dir(0) +{ +} + +epson_lx810l_t::epson_lx810l_t(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, __FILE__), + device_centronics_peripheral_interface(mconfig, *this), + m_maincpu(*this, "maincpu"), + m_pf_stepper(*this, "pf_stepper"), + m_cr_stepper(*this, "cr_stepper"), + m_eeprom(*this, "eeprom"), + m_speaker(*this, "speaker"), + m_e05a30(*this, "e05a30"), + m_93c06_clk(0), + m_93c06_cs(0), + m_printhead(0), + m_pf_pos_abs(200), + m_cr_pos_abs(200), + m_real_cr_pos(200), + m_real_cr_steps(0), + m_real_cr_dir(0) +{ +} + +epson_ap2000_t::epson_ap2000_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : epson_lx810l_t(mconfig, EPSON_AP2000, "Epson ActionPrinter 2000", tag, owner, clock, "ap2000", __FILE__) +{ } + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + + + + +void epson_lx810l_t::device_start() +{ +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void epson_lx810l_t::device_reset() +{ + m_speaker->level_w(0); +} + + +//------------------------------------------------- +// device_timer - device-specific timer +//------------------------------------------------- + +void epson_lx810l_t::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch (id) { + case TIMER_CR: + /* The firmware issues two half-steps in sequence, one immediately + * after the other. At full speed, the motor does two half-steps at + * each 833 microseconds. A timer fires the printhead twice, with + * the same period as each half-step (417 microseconds), but with + * a 356 microseconds delay relative to the motor steps. + */ + m_real_cr_pos += param; + m_real_cr_steps--; + if (m_real_cr_steps) + timer_set(attotime::from_usec(400), TIMER_CR, m_real_cr_dir); + break; + } +} + + +/*************************************************************************** + FAKEMEM READ/WRITE +***************************************************************************/ + +READ8_MEMBER(epson_lx810l_t::fakemem_r) +{ + return m_fakemem; +} + +WRITE8_MEMBER(epson_lx810l_t::fakemem_w) +{ + m_fakemem = data; +} + + +/*************************************************************************** + I/O PORTS +***************************************************************************/ + +/* + * PA0 R CN7 sensor (Home Position, HP, active low) + * PA1 R CN6 sensor (Paper-End, PE, active low) + * PA2 R CN4 sensor (Release, low = tractor) + * PA3 W Stepper motor voltage reference (these 3 pins make up one voltage) + * PA4 W Stepper motor voltage reference (these 3 pins make up one voltage) + * PA5 W Stepper motor voltage reference (these 3 pins make up one voltage) + * PA6 R Line Feed SWITCH + * PA7 R Form Feed SWITCH + */ +READ8_MEMBER( epson_lx810l_t::porta_r ) +{ + UINT8 result = 0; + UINT8 hp_sensor = m_cr_pos_abs <= 0 ? 0 : 1; + UINT8 pe_sensor = m_pf_pos_abs <= 0 ? 1 : 0; + + result |= hp_sensor; /* home position */ + result |= pe_sensor << 1; /* paper end */ + result |= ioport("LINEFEED")->read() << 6; + result |= ioport("FORMFEED")->read() << 7; + + LX810LLOG("%s: lx810l_PA_r(%02x): result %02x\n", machine().describe_context(), offset, result); + + return result; +} + +WRITE8_MEMBER( epson_lx810l_t::porta_w ) +{ + LX810LLOG("%s: lx810l_PA_w(%02x): %02x: stepper vref %d\n", machine().describe_context(), offset, data, BIT(data, 3) | (BIT(data, 4)<<1) | (BIT(data, 5)<<2)); +} + +/* + * PB0 R DIP1.0 & 93C06.DO + * PB1 RW DIP1.1 & 93C06.DI + * PB2 R DIP1.2 + * PB3 R DIP1.3 + * PB4 R DIP1.4 + * PB5 R DIP1.5 + * PB6 R DIP1.6 + * PB7 R DIP1.7 + */ +READ8_MEMBER( epson_lx810l_t::portb_r ) +{ + UINT8 result = ~ioport("DIPSW1")->read(); + + /* if 93C06 is selected */ + if (m_93c06_cs) { + UINT8 do_r = m_eeprom->do_read(); + result &= 0xfe; + result |= do_r; + } + + LX810LLOG("%s: lx810l_PB_r(%02x): result %02x\n", machine().describe_context(), offset, result); + + return result; +} + +WRITE8_MEMBER( epson_lx810l_t::portb_w ) +{ + UINT8 data_in = BIT(data, 1); + + /* if 93C06 is selected */ + if (m_93c06_cs) + m_eeprom->di_write(data_in); + + LX810LLOG("%s: lx810l_PB_w(%02x): %02x: 93c06 data %d\n", machine().describe_context(), offset, data, data_in); +} + +/* + * PC0 W TXD serial i/o txd, also TAMA.25 + * PC1 R RXD serial i/o rxd, also E05A30.28 + * PC2 W ONLINE LP online led + * PC3 R ONLINE SW online switch + * PC4 W 93C06.SK + * PC5 W 93C06.CS + * PC6 W FIRE drive pulse width signal, also E05A30.57 + * PC7 W BUZZER buzzer signal + */ +READ8_MEMBER( epson_lx810l_t::portc_r ) +{ + UINT8 result = 0; + + /* result |= ioport("serial")->read() << 1; */ + result |= !ioport("ONLINE")->read() << 3; + result |= m_93c06_clk << 4; + result |= m_93c06_cs << 5; + + LX810LLOG("%s: lx810l_PC_r(%02x): %02x\n", machine().describe_context(), offset, result); + + return result; +} + +WRITE8_MEMBER( epson_lx810l_t::portc_w ) +{ + /* ioport("serial")->write(BIT(data, 0)); */ + + m_93c06_clk = BIT(data, 4); + m_93c06_cs = !BIT(data, 5); + + LX810LLOG("%s: PC_w(%02x): %02x 93c06 clk: %d cs: %d\n", machine().describe_context(), offset, data, m_93c06_clk, m_93c06_cs); + + m_eeprom->clk_write(m_93c06_clk ? ASSERT_LINE : CLEAR_LINE); + m_eeprom->cs_write (m_93c06_cs ? ASSERT_LINE : CLEAR_LINE); + + output_set_value("online_led", !BIT(data, 2)); +} + + +/*************************************************************************** + GATE ARRAY +***************************************************************************/ + +WRITE16_MEMBER( epson_lx810l_t::printhead ) +{ + m_printhead = data; +} + +WRITE8_MEMBER( epson_lx810l_t::pf_stepper ) +{ + m_pf_stepper->update(data); + m_pf_pos_abs = 200 - m_pf_stepper->get_absolute_position(); + + LX810LLOG("%s: %s(%02x); abs %d\n", machine().describe_context(), __func__, data, m_pf_pos_abs); +} + +WRITE8_MEMBER( epson_lx810l_t::cr_stepper ) +{ + int m_cr_pos_abs_prev = m_cr_pos_abs; + + m_cr_stepper->update(data); + m_cr_pos_abs = 200 - m_cr_stepper->get_absolute_position(); + + if (m_cr_pos_abs > m_cr_pos_abs_prev) { + /* going right */ + m_real_cr_dir = 1; + } else { + /* going left */ + m_real_cr_dir = -1; + } + + if (!m_real_cr_steps) + timer_set(attotime::from_usec(400), TIMER_CR, m_real_cr_dir); + m_real_cr_steps++; + + LX810LLOG("%s: %s(%02x); abs %d\n", machine().describe_context(), __func__, data, m_cr_pos_abs); +} + +WRITE_LINE_MEMBER( epson_lx810l_t::e05a30_ready ) +{ + m_maincpu->set_input_line(INPUT_LINE_NMI, PULSE_LINE); +} + + +/*************************************************************************** + Extended Timer Output +***************************************************************************/ + +WRITE_LINE_MEMBER( epson_lx810l_t::co0_w ) +{ + /* TODO Draw the dots on the paper using this information. */ + + /* Printhead is being fired on !state. */ + if (!state) { + /* The firmware expects a 300 microseconds delay between the fire + * signal and the impact of the printhead on the paper. This can be + * verified by the timings of the steps and fire signals for the + * same positions with different directions (left to right or right + * to left). We don't simulate this delay since it is smaller than + * the time it takes the printhead to travel one pixel (which would + * be 417 microseconds), so it makes no difference to us. + * It is interesting to note that the vertical alignment between + * lines which are being printed in different directions is + * noticeably off in the 20+ years old printer used for testing =). + */ + LX810LLOG("FIRE0 %d %d %04x\n", m_pf_pos_abs, m_real_cr_pos, m_printhead); + } +} + +WRITE_LINE_MEMBER( epson_lx810l_t::co1_w ) +{ + m_speaker->level_w(state); +} + + +/*************************************************************************** + ADC +***************************************************************************/ + +READ8_MEMBER(epson_lx810l_t::an0_r) +{ + UINT8 res = !!(ioport("DIPSW2")->read() & 0x01); + return res - 1; /* DIPSW2.1 */ +} + +READ8_MEMBER(epson_lx810l_t::an1_r) +{ + UINT8 res = !!(ioport("DIPSW2")->read() & 0x02); + return res - 1; /* DIPSW2.2 */ +} + +READ8_MEMBER(epson_lx810l_t::an2_r) +{ + UINT8 res = !!(ioport("DIPSW2")->read() & 0x04); + return res - 1; /* DIPSW2.3 */ +} + +READ8_MEMBER(epson_lx810l_t::an3_r) +{ + UINT8 res = !!(ioport("DIPSW2")->read() & 0x08); + return res - 1; /* DIPSW2.4 */ +} + +READ8_MEMBER(epson_lx810l_t::an4_r) +{ + return 0xff; +} + +READ8_MEMBER(epson_lx810l_t::an5_r) +{ + return 0xCB; /* motor voltage, 0xcb = 24V */ +} + +READ8_MEMBER(epson_lx810l_t::an6_r) +{ + UINT8 res = !ioport("LOADEJECT")->read(); + return res - 1; +} + +READ8_MEMBER(epson_lx810l_t::an7_r) +{ + return 0xff; +} diff --git a/src/devices/bus/centronics/epson_lx810l.h b/src/devices/bus/centronics/epson_lx810l.h new file mode 100644 index 00000000000..71bcc68db6a --- /dev/null +++ b/src/devices/bus/centronics/epson_lx810l.h @@ -0,0 +1,141 @@ +// license:BSD-3-Clause +// copyright-holders:Ramiro Polla, Felipe Sanches +/* + * Epson LX-810L dot matrix printer emulation + * + */ + +#pragma once + +#ifndef __EPSON_LX810L__ +#define __EPSON_LX810L__ + +#include "emu.h" +#include "ctronics.h" +#include "cpu/upd7810/upd7810.h" +#include "machine/e05a30.h" +#include "machine/eepromser.h" +#include "machine/steppers.h" +#include "sound/speaker.h" + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> epson_lx810l_t + +class epson_lx810l_t : public device_t, + public device_centronics_peripheral_interface +{ +public: + // construction/destruction + epson_lx810l_t(const machine_config &mconfig, const char *tag, + device_t *owner, UINT32 clock); + epson_lx810l_t(const machine_config &mconfig, device_type type, + const char *name, const char *tag, device_t *owner, + UINT32 clock, const char *shortname, const char *source); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + virtual ioport_constructor device_input_ports() const; + + DECLARE_READ8_MEMBER(porta_r); + DECLARE_WRITE8_MEMBER(porta_w); + DECLARE_READ8_MEMBER(portb_r); + DECLARE_WRITE8_MEMBER(portb_w); + DECLARE_READ8_MEMBER(portc_r); + DECLARE_WRITE8_MEMBER(portc_w); + + /* Extended Timer Output */ + DECLARE_WRITE_LINE_MEMBER(co0_w); + DECLARE_WRITE_LINE_MEMBER(co1_w); + + /* ADC */ + DECLARE_READ8_MEMBER(an0_r); + DECLARE_READ8_MEMBER(an1_r); + DECLARE_READ8_MEMBER(an2_r); + DECLARE_READ8_MEMBER(an3_r); + DECLARE_READ8_MEMBER(an4_r); + DECLARE_READ8_MEMBER(an5_r); + DECLARE_READ8_MEMBER(an6_r); + DECLARE_READ8_MEMBER(an7_r); + + /* fake memory I/O to get past memory reset check */ + DECLARE_READ8_MEMBER(fakemem_r); + DECLARE_WRITE8_MEMBER(fakemem_w); + + /* GATE ARRAY */ + DECLARE_WRITE16_MEMBER(printhead); + DECLARE_WRITE8_MEMBER(pf_stepper); + DECLARE_WRITE8_MEMBER(cr_stepper); + DECLARE_WRITE_LINE_MEMBER(e05a30_ready); + + /* Centronics stuff */ + virtual DECLARE_WRITE_LINE_MEMBER( input_strobe ) { if (m_e05a30) m_e05a30->centronics_input_strobe(state); } + virtual DECLARE_WRITE_LINE_MEMBER( input_data0 ) { if (m_e05a30) m_e05a30->centronics_input_data0(state); } + virtual DECLARE_WRITE_LINE_MEMBER( input_data1 ) { if (m_e05a30) m_e05a30->centronics_input_data1(state); } + virtual DECLARE_WRITE_LINE_MEMBER( input_data2 ) { if (m_e05a30) m_e05a30->centronics_input_data2(state); } + virtual DECLARE_WRITE_LINE_MEMBER( input_data3 ) { if (m_e05a30) m_e05a30->centronics_input_data3(state); } + virtual DECLARE_WRITE_LINE_MEMBER( input_data4 ) { if (m_e05a30) m_e05a30->centronics_input_data4(state); } + virtual DECLARE_WRITE_LINE_MEMBER( input_data5 ) { if (m_e05a30) m_e05a30->centronics_input_data5(state); } + virtual DECLARE_WRITE_LINE_MEMBER( input_data6 ) { if (m_e05a30) m_e05a30->centronics_input_data6(state); } + virtual DECLARE_WRITE_LINE_MEMBER( input_data7 ) { if (m_e05a30) m_e05a30->centronics_input_data7(state); } + DECLARE_WRITE_LINE_MEMBER(e05a30_centronics_ack) { output_ack(state); } + DECLARE_WRITE_LINE_MEMBER(e05a30_centronics_busy) { output_busy(state); } + DECLARE_WRITE_LINE_MEMBER(e05a30_centronics_perror) { output_perror(state); } + DECLARE_WRITE_LINE_MEMBER(e05a30_centronics_fault) { output_fault(state); } + DECLARE_WRITE_LINE_MEMBER(e05a30_centronics_select) { output_select(state); } + + /* Panel buttons */ + DECLARE_INPUT_CHANGED_MEMBER(online_sw); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + +private: + required_device m_maincpu; + required_device m_pf_stepper; + required_device m_cr_stepper; + required_device m_eeprom; + required_device m_speaker; + required_device m_e05a30; + + int m_93c06_clk; + int m_93c06_cs; + UINT16 m_printhead; + int m_pf_pos_abs; + int m_cr_pos_abs; + int m_real_cr_pos; + int m_real_cr_steps; + int m_real_cr_dir; /* 1 is going right, -1 is going left */ + UINT8 m_fakemem; + + enum { + TIMER_CR + }; +}; + +// ======================> epson_ap2000_t + +class epson_ap2000_t : public epson_lx810l_t +{ +public: + // construction/destruction + epson_ap2000_t(const machine_config &mconfig, const char *tag, + device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; +}; + + +// device type definition +extern const device_type EPSON_LX810L; +extern const device_type EPSON_AP2000; + +#endif diff --git a/src/devices/bus/centronics/printer.c b/src/devices/bus/centronics/printer.c new file mode 100644 index 00000000000..8aa924f23d2 --- /dev/null +++ b/src/devices/bus/centronics/printer.c @@ -0,0 +1,133 @@ +// license:BSD-3-Clause +// copyright-holders:smf +#include "emu.h" +#include "printer.h" + +//************************************************************************** +// CENTRONICS PRINTER DEVICE +//************************************************************************** + +// device type definition +const device_type CENTRONICS_PRINTER = &device_creator; + + +static MACHINE_CONFIG_FRAGMENT( centronics_printer ) + MCFG_DEVICE_ADD("printer", PRINTER, 0) + MCFG_PRINTER_ONLINE_CB(WRITELINE(centronics_printer_device, printer_online)) +MACHINE_CONFIG_END + + +/*************************************************************************** + IMPLEMENTATION +***************************************************************************/ +//------------------------------------------------- +// centronics_printer_device - constructor +//------------------------------------------------- + +centronics_printer_device::centronics_printer_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, CENTRONICS_PRINTER, "Centronics Printer", tag, owner, clock, "centronics_printer", __FILE__), + device_centronics_peripheral_interface( mconfig, *this ), + m_strobe(0), + m_printer(*this, "printer") +{ +} +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor centronics_printer_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( centronics_printer ); +} + +/*------------------------------------------------- + printer_online - callback that + sets us busy when the printer goes offline +-------------------------------------------------*/ + +WRITE_LINE_MEMBER(centronics_printer_device::printer_online) +{ + output_perror(!state); +} + +void centronics_printer_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch (id) + { + case TIMER_ACK: + output_ack(param); + + if (param == FALSE) + { + /* data is now ready, output it */ + m_printer->output(m_data); + + /* ready to receive more data, return BUSY to low */ + timer_set(attotime::from_usec(7), TIMER_BUSY, FALSE); + } + break; + + case TIMER_BUSY: + m_busy = param; + output_busy(m_busy); + + if (param == TRUE) + { + /* timer to turn ACK low to receive data */ + timer_set(attotime::from_usec(10), TIMER_ACK, FALSE); + } + else + { + /* timer to return ACK to high state */ + timer_set(attotime::from_usec(5), TIMER_ACK, TRUE); + } + } +} + +void centronics_printer_device::device_start() +{ + /* register for state saving */ + save_item(NAME(m_strobe)); + save_item(NAME(m_data)); + save_item(NAME(m_busy)); +} + +void centronics_printer_device::device_reset() +{ + m_busy = FALSE; + output_busy(m_busy); + output_fault(1); + output_ack(1); + output_select(1); +} + +/*------------------------------------------------- + centronics_strobe_w - signal that data is + ready +-------------------------------------------------*/ + +WRITE_LINE_MEMBER( centronics_printer_device::input_strobe ) +{ + /* look for a high -> low transition */ + if (m_strobe == TRUE && state == FALSE && m_busy == FALSE) + { + /* STROBE has gone low, data is ready */ + timer_set(attotime::zero, TIMER_BUSY, TRUE); + } + + m_strobe = state; +} + + +/*------------------------------------------------- + centronics_prime_w - initialize and reset + printer (centronics mode) +-------------------------------------------------*/ + +WRITE_LINE_MEMBER(centronics_printer_device::input_init) +{ + /* reset printer if line is low */ + if (state == FALSE) + device_reset(); +} diff --git a/src/devices/bus/centronics/printer.h b/src/devices/bus/centronics/printer.h new file mode 100644 index 00000000000..7f10fd7e4c2 --- /dev/null +++ b/src/devices/bus/centronics/printer.h @@ -0,0 +1,58 @@ +// license:BSD-3-Clause +// copyright-holders:smf +#pragma once + +#ifndef __CENTRONICS_PRINTER_H__ +#define __CENTRONICS_PRINTER_H__ + +#include "ctronics.h" +#include "imagedev/printer.h" + +// ======================> centronics_printer_device + +class centronics_printer_device : public device_t, + public device_centronics_peripheral_interface +{ +public: + // construction/destruction + centronics_printer_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual DECLARE_WRITE_LINE_MEMBER( input_strobe ); + virtual DECLARE_WRITE_LINE_MEMBER( input_data0 ) { if (state) m_data |= 0x01; else m_data &= ~0x01; } + virtual DECLARE_WRITE_LINE_MEMBER( input_data1 ) { if (state) m_data |= 0x02; else m_data &= ~0x02; } + virtual DECLARE_WRITE_LINE_MEMBER( input_data2 ) { if (state) m_data |= 0x04; else m_data &= ~0x04; } + virtual DECLARE_WRITE_LINE_MEMBER( input_data3 ) { if (state) m_data |= 0x08; else m_data &= ~0x08; } + virtual DECLARE_WRITE_LINE_MEMBER( input_data4 ) { if (state) m_data |= 0x10; else m_data &= ~0x10; } + virtual DECLARE_WRITE_LINE_MEMBER( input_data5 ) { if (state) m_data |= 0x20; else m_data &= ~0x20; } + virtual DECLARE_WRITE_LINE_MEMBER( input_data6 ) { if (state) m_data |= 0x40; else m_data &= ~0x40; } + virtual DECLARE_WRITE_LINE_MEMBER( input_data7 ) { if (state) m_data |= 0x80; else m_data &= ~0x80; } + virtual DECLARE_WRITE_LINE_MEMBER( input_init ); + + DECLARE_WRITE_LINE_MEMBER( printer_online ); + +protected: + // device-level overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + +private: + + enum + { + TIMER_ACK, + TIMER_BUSY + }; + + int m_strobe; + UINT8 m_data; + int m_busy; + + required_device m_printer; +}; + +// device type definition +extern const device_type CENTRONICS_PRINTER; + +#endif diff --git a/src/devices/bus/cgenie/expansion/carts.c b/src/devices/bus/cgenie/expansion/carts.c new file mode 100644 index 00000000000..f4b23a5cf9d --- /dev/null +++ b/src/devices/bus/cgenie/expansion/carts.c @@ -0,0 +1,13 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best +/*************************************************************************** + + EACA Colour Genie Expansion Carts + +***************************************************************************/ + +#include "carts.h" + +SLOT_INTERFACE_START( expansion_slot_carts ) + SLOT_INTERFACE("floppy", CGENIE_FDC) +SLOT_INTERFACE_END diff --git a/src/devices/bus/cgenie/expansion/carts.h b/src/devices/bus/cgenie/expansion/carts.h new file mode 100644 index 00000000000..45bf66a4c90 --- /dev/null +++ b/src/devices/bus/cgenie/expansion/carts.h @@ -0,0 +1,20 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best +/*************************************************************************** + + EACA Colour Genie Expansion Carts + +***************************************************************************/ + +#pragma once + +#ifndef __CGENIE_EXPANSION_CARTS_H__ +#define __CGENIE_EXPANSION_CARTS_H__ + +#include "emu.h" + +#include "floppy.h" + +SLOT_INTERFACE_EXTERN( expansion_slot_carts ); + +#endif // __CGENIE_EXPANSION_CARTS_H__ diff --git a/src/devices/bus/cgenie/expansion/expansion.c b/src/devices/bus/cgenie/expansion/expansion.c new file mode 100644 index 00000000000..88a89a32cce --- /dev/null +++ b/src/devices/bus/cgenie/expansion/expansion.c @@ -0,0 +1,108 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best +/*************************************************************************** + + EACA Colour Genie Expansion Slot + + 50-pin slot + +***************************************************************************/ + +#include "expansion.h" + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type EXPANSION_SLOT = &device_creator; + + +//************************************************************************** +// SLOT DEVICE +//************************************************************************** + +//------------------------------------------------- +// expansion_slot_device - constructor +//------------------------------------------------- + +expansion_slot_device::expansion_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, EXPANSION_SLOT, "Expansion Slot", tag, owner, clock, "expansion_slot", __FILE__), + device_slot_interface(mconfig, *this), + m_program(NULL), + m_io(NULL), + m_cart(NULL), + m_int_handler(*this), + m_nmi_handler(*this), + m_reset_handler(*this) +{ +} + +//------------------------------------------------- +// expansion_slot_device - destructor +//------------------------------------------------- + +expansion_slot_device::~expansion_slot_device() +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void expansion_slot_device::device_start() +{ + // resolve callbacks + m_int_handler.resolve_safe(); + m_nmi_handler.resolve_safe(); + m_reset_handler.resolve_safe(); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void expansion_slot_device::device_reset() +{ +} + +//------------------------------------------------- +// set_program_space - set address space we are attached to +//------------------------------------------------- + +void expansion_slot_device::set_program_space(address_space *program) +{ + m_program = program; +} + +//------------------------------------------------- +// set_io_space - set address space we are attached to +//------------------------------------------------- + +void expansion_slot_device::set_io_space(address_space *io) +{ + m_io = io; +} + + +//************************************************************************** +// CARTRIDGE INTERFACE +//************************************************************************** + +//------------------------------------------------- +// device_expansion_interface - constructor +//------------------------------------------------- + +device_expansion_interface::device_expansion_interface(const machine_config &mconfig, device_t &device) : + device_slot_card_interface(mconfig, device) +{ + m_slot = dynamic_cast(device.owner()); +} + +//------------------------------------------------- +// ~device_expansion_interface - destructor +//------------------------------------------------- + +device_expansion_interface::~device_expansion_interface() +{ +} diff --git a/src/devices/bus/cgenie/expansion/expansion.h b/src/devices/bus/cgenie/expansion/expansion.h new file mode 100644 index 00000000000..311da3afa6d --- /dev/null +++ b/src/devices/bus/cgenie/expansion/expansion.h @@ -0,0 +1,128 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best +/*************************************************************************** + + EACA Colour Genie Expansion Slot + + 50-pin slot + + 1 GND 26 /MREQ + 2 A8 27 /WR + 3 A7 28 /C4 + 4 A6 29 (not used) + 5 A9 30 /C1 + 6 A5 31 BD3 + 7 A4 32 /C3 + 8 A3 33 (not used) + 9 A10 34 /C2 + 10 A2 35 DB6 + 11 A11 36 /RD + 12 A1 37 BD4 + 13 A0 38 (not used) + 14 A12 39 BD7 + 15 A14 40 (not used) + 16 A13 41 BD5 + 17 /RFSH 42 (not useD) + 18 A15 43 BD0 + 19 /INT 44 (not used) + 20 /BUSRQ 45 BD2 + 21 /NMI 46 /RESET + 22 /WAIT 47 /M1 + 23 /HALT 48 /IORQ + 24 /BUSAK 49 BD1 + 25 /ROMDIS 50 +5V + +***************************************************************************/ + +#pragma once + +#ifndef __CGENIE_EXPANSION_H__ +#define __CGENIE_EXPANSION_H__ + +#include "emu.h" + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_EXPANSION_SLOT_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, EXPANSION_SLOT, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(expansion_slot_carts, NULL, false) + +#define MCFG_EXPANSION_SLOT_INT_HANDLER(_devcb) \ + devcb = &expansion_slot_device::set_int_handler(*device, DEVCB_##_devcb); + +#define MCFG_EXPANSION_SLOT_NMI_HANDLER(_devcb) \ + devcb = &expansion_slot_device::set_nmi_handler(*device, DEVCB_##_devcb); + +#define MCFG_EXPANSION_SLOT_RESET_HANDLER(_devcb) \ + devcb = &expansion_slot_device::set_reset_handler(*device, DEVCB_##_devcb); + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class device_expansion_interface; + +class expansion_slot_device : public device_t, public device_slot_interface +{ +public: + // construction/destruction + expansion_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual ~expansion_slot_device(); + + void set_program_space(address_space *program); + void set_io_space(address_space *io); + + // callbacks + template static devcb_base &set_int_handler(device_t &device, _Object object) + { return downcast(device).m_int_handler.set_callback(object); } + + template static devcb_base &set_nmi_handler(device_t &device, _Object object) + { return downcast(device).m_nmi_handler.set_callback(object); } + + template static devcb_base &set_reset_handler(device_t &device, _Object object) + { return downcast(device).m_reset_handler.set_callback(object); } + + // called from cart device + DECLARE_WRITE_LINE_MEMBER( int_w ) { m_int_handler(state); } + DECLARE_WRITE_LINE_MEMBER( nmi_w ) { m_nmi_handler(state); } + DECLARE_WRITE_LINE_MEMBER( reset_w ) { m_reset_handler(state); } + + address_space *m_program; + address_space *m_io; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + device_expansion_interface *m_cart; + +private: + devcb_write_line m_int_handler; + devcb_write_line m_nmi_handler; + devcb_write_line m_reset_handler; +}; + +// class representing interface-specific live expansion device +class device_expansion_interface : public device_slot_card_interface +{ +public: + // construction/destruction + device_expansion_interface(const machine_config &mconfig, device_t &device); + virtual ~device_expansion_interface(); + +protected: + expansion_slot_device *m_slot; +}; + +// device type definition +extern const device_type EXPANSION_SLOT; + +// include here so drivers don't need to +#include "carts.h" + +#endif // __CGENIE_EXPANSION_H__ diff --git a/src/devices/bus/cgenie/expansion/floppy.c b/src/devices/bus/cgenie/expansion/floppy.c new file mode 100644 index 00000000000..6941ae33ad3 --- /dev/null +++ b/src/devices/bus/cgenie/expansion/floppy.c @@ -0,0 +1,226 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best +/*************************************************************************** + + EACA Colour Genie Floppy Disc Controller + + TODO: + - What's the exact FD1793 model? + - How does it turn off the motor? + - What's the source of the timer and the exact timings? + +***************************************************************************/ + +#include "floppy.h" +#include "formats/cgenie_dsk.h" +#include "bus/generic/carts.h" + + +//************************************************************************** +// CONSTANTS/MACROS +//************************************************************************** + +#define VERBOSE 0 + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type CGENIE_FDC = &device_creator; + +DEVICE_ADDRESS_MAP_START( mmio, 8, cgenie_fdc_device ) + AM_RANGE(0xe0, 0xe3) AM_MIRROR(0x10) AM_READWRITE(irq_r, select_w) + AM_RANGE(0xec, 0xec) AM_MIRROR(0x10) AM_DEVREAD("fd1793", fd1793_t, status_r) AM_WRITE(command_w) + AM_RANGE(0xed, 0xed) AM_MIRROR(0x10) AM_DEVREADWRITE("fd1793", fd1793_t, track_r, track_w) + AM_RANGE(0xee, 0xee) AM_MIRROR(0x10) AM_DEVREADWRITE("fd1793", fd1793_t, sector_r, sector_w) + AM_RANGE(0xef, 0xef) AM_MIRROR(0x10) AM_DEVREADWRITE("fd1793", fd1793_t, data_r, data_w) +ADDRESS_MAP_END + +FLOPPY_FORMATS_MEMBER( cgenie_fdc_device::floppy_formats ) + FLOPPY_CGENIE_FORMAT +FLOPPY_FORMATS_END + +static SLOT_INTERFACE_START( cgenie_floppies ) + SLOT_INTERFACE("sssd", FLOPPY_525_SSSD) + SLOT_INTERFACE("sd", FLOPPY_525_SD) + SLOT_INTERFACE("ssdd", FLOPPY_525_SSDD) + SLOT_INTERFACE("dd", FLOPPY_525_DD) + SLOT_INTERFACE("ssqd", FLOPPY_525_SSQD) + SLOT_INTERFACE("qd", FLOPPY_525_QD) +SLOT_INTERFACE_END + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +ROM_START( cgenie_fdc ) + ROM_REGION(0x3000, "software", 0) + ROM_LOAD("cgdos.rom", 0x0000, 0x2000, CRC(2a96cf74) SHA1(6dcac110f87897e1ee7521aefbb3d77a14815893)) +ROM_END + +const rom_entry *cgenie_fdc_device::device_rom_region() const +{ + return ROM_NAME( cgenie_fdc ); +} + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( cgenie_fdc ) + MCFG_TIMER_DRIVER_ADD_PERIODIC("timer", cgenie_fdc_device, timer_callback, attotime::from_msec(25)) + + MCFG_FD1793_ADD("fd1793", XTAL_1MHz) + MCFG_WD_FDC_INTRQ_CALLBACK(WRITELINE(cgenie_fdc_device, intrq_w)) + + MCFG_FLOPPY_DRIVE_ADD("fd1793:0", cgenie_floppies, "ssdd", cgenie_fdc_device::floppy_formats) + MCFG_FLOPPY_DRIVE_ADD("fd1793:1", cgenie_floppies, "ssdd", cgenie_fdc_device::floppy_formats) + MCFG_FLOPPY_DRIVE_ADD("fd1793:2", cgenie_floppies, NULL, cgenie_fdc_device::floppy_formats) + MCFG_FLOPPY_DRIVE_ADD("fd1793:3", cgenie_floppies, NULL, cgenie_fdc_device::floppy_formats) + +// MCFG_SOFTWARE_LIST_ADD("floppy_list", "cgenie_flop") + + MCFG_GENERIC_SOCKET_ADD("socket", generic_plain_slot, "cgenie_socket") + MCFG_GENERIC_EXTENSIONS("bin,rom") + MCFG_GENERIC_LOAD(cgenie_fdc_device, socket_load) + + MCFG_SOFTWARE_LIST_ADD("cart_list", "cgenie_cart") +MACHINE_CONFIG_END + +machine_config_constructor cgenie_fdc_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( cgenie_fdc ); +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// cgenie_fdc_device - constructor +//------------------------------------------------- + +cgenie_fdc_device::cgenie_fdc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, CGENIE_FDC, "Floppy Disc Controller", tag, owner, clock, "cgenie_fdc", __FILE__), + device_expansion_interface(mconfig, *this), + m_fdc(*this, "fd1793"), + m_floppy0(*this, "fd1793:0"), + m_floppy1(*this, "fd1793:1"), + m_floppy2(*this, "fd1793:2"), + m_floppy3(*this, "fd1793:3"), + m_socket(*this, "socket"), + m_floppy(NULL), + m_irq_status(0) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void cgenie_fdc_device::device_start() +{ +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void cgenie_fdc_device::device_reset() +{ + // dos rom + m_slot->m_program->install_rom(0xc000, 0xdfff, memregion("software")->base()); + + // memory mapped i/o + m_slot->m_program->install_device(0xff00, 0xffff, *this, &cgenie_fdc_device::mmio); + + // map extra socket + if (m_socket->exists()) + { + m_slot->m_program->install_read_handler(0xe000, 0xefff, read8_delegate(FUNC(generic_slot_device::read_rom), (generic_slot_device *) m_socket)); + } +} + + +//************************************************************************** +// IMPLEMENTATION +//************************************************************************** + +READ8_MEMBER( cgenie_fdc_device::irq_r ) +{ + UINT8 data = m_irq_status; + + m_irq_status &= ~IRQ_TIMER; + m_slot->int_w(m_irq_status ? ASSERT_LINE : CLEAR_LINE); + + return data; +} + +TIMER_DEVICE_CALLBACK_MEMBER( cgenie_fdc_device::timer_callback ) +{ + m_irq_status |= IRQ_TIMER; + m_slot->int_w(ASSERT_LINE); +} + +DEVICE_IMAGE_LOAD_MEMBER( cgenie_fdc_device, socket_load ) +{ + UINT32 size = m_socket->common_get_size("rom"); + + if (size > 0x1000) + { + image.seterror(IMAGE_ERROR_UNSPECIFIED, "Unsupported ROM size"); + return IMAGE_INIT_FAIL; + } + + m_socket->rom_alloc(0x1000, GENERIC_ROM8_WIDTH, ENDIANNESS_LITTLE); + m_socket->common_load_rom(m_socket->get_rom_base(), size, "rom"); + + return IMAGE_INIT_PASS; +} + +WRITE_LINE_MEMBER( cgenie_fdc_device::intrq_w ) +{ + if (VERBOSE) + logerror("cgenie_fdc_device::intrq_w: %d\n", state); + + if (state) + m_irq_status |= IRQ_WDC; + else + m_irq_status &= ~IRQ_WDC; + + m_slot->int_w(m_irq_status ? ASSERT_LINE : CLEAR_LINE); +} + +WRITE8_MEMBER( cgenie_fdc_device::select_w ) +{ + if (VERBOSE) + logerror("cgenie_fdc_device::motor_w: 0x%02x\n", data); + + m_floppy = NULL; + + if (BIT(data, 0)) m_floppy = m_floppy0->get_device(); + if (BIT(data, 1)) m_floppy = m_floppy1->get_device(); + if (BIT(data, 2)) m_floppy = m_floppy2->get_device(); + if (BIT(data, 3)) m_floppy = m_floppy3->get_device(); + + m_fdc->set_floppy(m_floppy); + + if (m_floppy) + { + m_floppy->ss_w(BIT(data, 4)); + m_floppy->mon_w(0); + } +} + +WRITE8_MEMBER( cgenie_fdc_device::command_w ) +{ + // density select is encoded into this pseudo-command + if ((data & 0xfe) == 0xfe) + m_fdc->dden_w(!BIT(data, 0)); + + // forward to the controller + m_fdc->cmd_w(data); +} diff --git a/src/devices/bus/cgenie/expansion/floppy.h b/src/devices/bus/cgenie/expansion/floppy.h new file mode 100644 index 00000000000..67926ba9954 --- /dev/null +++ b/src/devices/bus/cgenie/expansion/floppy.h @@ -0,0 +1,76 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best +/*************************************************************************** + + EACA Colour Genie Floppy Controller Cartridge + +***************************************************************************/ + +#pragma once + +#ifndef __CGENIE_EXPANSION_FLOPPY_H__ +#define __CGENIE_EXPANSION_FLOPPY_H__ + +#include "emu.h" +#include "expansion.h" +#include "machine/wd_fdc.h" +#include "bus/generic/slot.h" + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> floppy_controller_device + +class cgenie_fdc_device : public device_t, public device_expansion_interface +{ +public: + // construction/destruction + cgenie_fdc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + DECLARE_ADDRESS_MAP(mmio, 8); + + TIMER_DEVICE_CALLBACK_MEMBER(timer_callback); + + DECLARE_DEVICE_IMAGE_LOAD_MEMBER(socket_load); + + DECLARE_WRITE_LINE_MEMBER(intrq_w); + DECLARE_READ8_MEMBER(irq_r); + DECLARE_WRITE8_MEMBER(select_w); + DECLARE_WRITE8_MEMBER(command_w); + + DECLARE_FLOPPY_FORMATS(floppy_formats); + + +protected: + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + virtual void device_start(); + virtual void device_reset(); + +private: + void update_irq(); + + required_device m_fdc; + required_device m_floppy0; + required_device m_floppy1; + required_device m_floppy2; + required_device m_floppy3; + required_device m_socket; + + enum + { + IRQ_WDC = 0x40, + IRQ_TIMER = 0x80 + }; + + floppy_image_device *m_floppy; + + UINT8 m_irq_status; +}; + +// device type definition +extern const device_type CGENIE_FDC; + +#endif // __CGENIE_EXPANSION_FLOPPY_H__ diff --git a/src/devices/bus/cgenie/parallel/carts.c b/src/devices/bus/cgenie/parallel/carts.c new file mode 100644 index 00000000000..61a6380117f --- /dev/null +++ b/src/devices/bus/cgenie/parallel/carts.c @@ -0,0 +1,14 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best +/*************************************************************************** + + EACA Colour Genie Parallel Carts + +***************************************************************************/ + +#include "carts.h" + +SLOT_INTERFACE_START( parallel_slot_carts ) + SLOT_INTERFACE("joystick", CGENIE_JOYSTICK) + SLOT_INTERFACE("printer", CGENIE_PRINTER) +SLOT_INTERFACE_END diff --git a/src/devices/bus/cgenie/parallel/carts.h b/src/devices/bus/cgenie/parallel/carts.h new file mode 100644 index 00000000000..29c092b9d0a --- /dev/null +++ b/src/devices/bus/cgenie/parallel/carts.h @@ -0,0 +1,21 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best +/*************************************************************************** + + EACA Colour Genie Parallel Carts + +***************************************************************************/ + +#pragma once + +#ifndef __CGENIE_PARALLEL_CARTS_H__ +#define __CGENIE_PARALLEL_CARTS_H__ + +#include "emu.h" + +#include "joystick.h" +#include "printer.h" + +SLOT_INTERFACE_EXTERN( parallel_slot_carts ); + +#endif // __CGENIE_PARALLEL_CARTS_H__ diff --git a/src/devices/bus/cgenie/parallel/joystick.c b/src/devices/bus/cgenie/parallel/joystick.c new file mode 100644 index 00000000000..de520ba0669 --- /dev/null +++ b/src/devices/bus/cgenie/parallel/joystick.c @@ -0,0 +1,153 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best +/*************************************************************************** + + EACA Colour Genie Joystick Interface EG2013 + + Keypads are organized as 3x4 matrix. + +***************************************************************************/ + +#include "joystick.h" + + +//************************************************************************** +// CONSTANTS/MACROS +//************************************************************************** + +#define VERBOSE 0 + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type CGENIE_JOYSTICK = &device_creator; + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +static INPUT_PORTS_START( cgenie_joystick ) + PORT_START("JOY.0") + PORT_BIT(0x3f, 0x00, IPT_AD_STICK_X) PORT_SENSITIVITY(100) PORT_PLAYER(1) + + PORT_START("JOY.1") + PORT_BIT(0x3f, 0x00, IPT_AD_STICK_Y) PORT_SENSITIVITY(100) PORT_PLAYER(1) PORT_REVERSE + + PORT_START("JOY.2") + PORT_BIT(0x3f, 0x00, IPT_AD_STICK_X) PORT_SENSITIVITY(100) PORT_PLAYER(2) + + PORT_START("JOY.3") + PORT_BIT(0x3f, 0x00, IPT_AD_STICK_Y) PORT_SENSITIVITY(100) PORT_PLAYER(2) PORT_REVERSE + + PORT_START("KEYPAD.0") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_BUTTON1) PORT_NAME("Keypad 1 Button 3") PORT_PLAYER(1) PORT_CODE(KEYCODE_3_PAD) + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_BUTTON2) PORT_NAME("Keypad 1 Button 6") PORT_PLAYER(1) PORT_CODE(KEYCODE_6_PAD) + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_BUTTON3) PORT_NAME("Keypad 1 Button 9") PORT_PLAYER(1) PORT_CODE(KEYCODE_9_PAD) + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_BUTTON4) PORT_NAME("Keypad 1 Button #") PORT_PLAYER(1) PORT_CODE(KEYCODE_SLASH_PAD) + + PORT_START("KEYPAD.1") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_BUTTON5) PORT_NAME("Keypad 1 Button 2") PORT_PLAYER(1) PORT_CODE(KEYCODE_2_PAD) + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_BUTTON6) PORT_NAME("Keypad 1 Button 5") PORT_PLAYER(1) PORT_CODE(KEYCODE_5_PAD) + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_BUTTON7) PORT_NAME("Keypad 1 Button 8") PORT_PLAYER(1) PORT_CODE(KEYCODE_8_PAD) + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_BUTTON8) PORT_NAME("Keypad 1 Button 0") PORT_PLAYER(1) PORT_CODE(KEYCODE_0_PAD) + + PORT_START("KEYPAD.2") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_BUTTON9) PORT_NAME("Keypad 1 Button 1") PORT_PLAYER(1) PORT_CODE(KEYCODE_1_PAD) + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_BUTTON10) PORT_NAME("Keypad 1 Button 4") PORT_PLAYER(1) PORT_CODE(KEYCODE_4_PAD) + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_BUTTON11) PORT_NAME("Keypad 1 Button 7") PORT_PLAYER(1) PORT_CODE(KEYCODE_7_PAD) + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_BUTTON12) PORT_NAME("Keypad 1 Button *") PORT_PLAYER(1) PORT_CODE(KEYCODE_ASTERISK) + + PORT_START("KEYPAD.3") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_BUTTON1) PORT_NAME("Keypad 2 Button 3") PORT_PLAYER(2) PORT_CODE(JOYCODE_BUTTON2) + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_BUTTON2) PORT_NAME("Keypad 2 Button 6") PORT_PLAYER(2) PORT_CODE(JOYCODE_BUTTON5) + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_BUTTON3) PORT_NAME("Keypad 2 Button 9") PORT_PLAYER(2) + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_BUTTON4) PORT_NAME("Keypad 2 Button #") PORT_PLAYER(2) PORT_CODE(JOYCODE_BUTTON1) + + PORT_START("KEYPAD.4") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_BUTTON5) PORT_NAME("Keypad 2 Button 2") PORT_PLAYER(2) PORT_CODE(JOYCODE_BUTTON2) + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_BUTTON6) PORT_NAME("Keypad 2 Button 5") PORT_PLAYER(2) PORT_CODE(JOYCODE_BUTTON5) + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_BUTTON7) PORT_NAME("Keypad 2 Button 8") PORT_PLAYER(2) + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_BUTTON8) PORT_NAME("Keypad 2 Button 0") PORT_PLAYER(2) + + PORT_START("KEYPAD.5") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_BUTTON9) PORT_NAME("Keypad 2 Button 1") PORT_PLAYER(2) PORT_CODE(JOYCODE_BUTTON1) + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_BUTTON10) PORT_NAME("Keypad 2 Button 4") PORT_PLAYER(2) PORT_CODE(JOYCODE_BUTTON4) + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_BUTTON11) PORT_NAME("Keypad 2 Button 7") PORT_PLAYER(2) + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_BUTTON12) PORT_NAME("Keypad 2 Button *") PORT_PLAYER(2) PORT_CODE(JOYCODE_BUTTON1) +INPUT_PORTS_END + +ioport_constructor cgenie_joystick_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( cgenie_joystick ); +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// cgenie_joystick_device - constructor +//------------------------------------------------- + +cgenie_joystick_device::cgenie_joystick_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, CGENIE_JOYSTICK, "Joystick Interface EG2013", tag, owner, clock, "cgenie_joystick", __FILE__), + device_parallel_interface(mconfig, *this), + m_joy(*this, "JOY"), + m_keypad(*this, "KEYPAD"), + m_select(0) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void cgenie_joystick_device::device_start() +{ +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void cgenie_joystick_device::device_reset() +{ +} + + +//************************************************************************** +// IMPLEMENTATION +//************************************************************************** + +void cgenie_joystick_device::pa_w(UINT8 data) +{ + if (VERBOSE) + logerror("%s: pa_w %02x\n", tag(), data); + + // d0 to d5 connected + m_select = data & 0x3f; +} + +UINT8 cgenie_joystick_device::pb_r() +{ + UINT8 data = 0x0f; + + // read button state + for (int i = 0; i < 4; i++) + if (!BIT(m_select, i)) + data &= m_keypad[i]->read(); + + // and joystick state + data |= m_joy[3]->read() > m_select ? 0x10 : 0x00; + data |= m_joy[2]->read() > m_select ? 0x20 : 0x00; + data |= m_joy[1]->read() > m_select ? 0x40 : 0x00; + data |= m_joy[0]->read() > m_select ? 0x80 : 0x00; + + if (VERBOSE) + logerror("%s: pb_r %02x\n", tag(), data); + + return data; +} diff --git a/src/devices/bus/cgenie/parallel/joystick.h b/src/devices/bus/cgenie/parallel/joystick.h new file mode 100644 index 00000000000..28be43b00e6 --- /dev/null +++ b/src/devices/bus/cgenie/parallel/joystick.h @@ -0,0 +1,48 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best +/*************************************************************************** + + EACA Colour Genie Joystick Interface EG2013 + +***************************************************************************/ + +#pragma once + +#ifndef __CGENIE_PARALLEL_JOYSTICK_H__ +#define __CGENIE_PARALLEL_JOYSTICK_H__ + +#include "emu.h" +#include "parallel.h" + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> cgenie_joystick_device + +class cgenie_joystick_device : public device_t, public device_parallel_interface +{ +public: + // construction/destruction + cgenie_joystick_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual void device_start(); + virtual void device_reset(); + virtual ioport_constructor device_input_ports() const; + + virtual void pa_w(UINT8 data); + virtual UINT8 pb_r(); + +private: + required_ioport_array<4> m_joy; + required_ioport_array<6> m_keypad; + + UINT8 m_select; +}; + +// device type definition +extern const device_type CGENIE_JOYSTICK; + +#endif // __CGENIE_PARALLEL_JOYSTICK_H__ diff --git a/src/devices/bus/cgenie/parallel/parallel.c b/src/devices/bus/cgenie/parallel/parallel.c new file mode 100644 index 00000000000..e948af9c00a --- /dev/null +++ b/src/devices/bus/cgenie/parallel/parallel.c @@ -0,0 +1,115 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best +/*************************************************************************** + + EACA Colour Genie Parallel Slot + + 20-pin slot + +***************************************************************************/ + +#include "parallel.h" + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type PARALLEL_SLOT = &device_creator; + + +//************************************************************************** +// SLOT DEVICE +//************************************************************************** + +//------------------------------------------------- +// parallel_slot_device - constructor +//------------------------------------------------- + +parallel_slot_device::parallel_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, PARALLEL_SLOT, "Parallel Slot", tag, owner, clock, "parallel_slot", __FILE__), + device_slot_interface(mconfig, *this), + m_cart(NULL) +{ +} + +//------------------------------------------------- +// parallel_slot_device - destructor +//------------------------------------------------- + +parallel_slot_device::~parallel_slot_device() +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void parallel_slot_device::device_start() +{ + m_cart = dynamic_cast(get_card_device()); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void parallel_slot_device::device_reset() +{ +} + + +//************************************************************************** +// I/O PORTS +//************************************************************************** + +READ8_MEMBER( parallel_slot_device::pa_r ) +{ + if (m_cart) + return m_cart->pa_r(); + else + return 0xff; +} + +WRITE8_MEMBER( parallel_slot_device::pa_w ) +{ + if (m_cart) + m_cart->pa_w(data); +} + +READ8_MEMBER( parallel_slot_device::pb_r ) +{ + if (m_cart) + return m_cart->pb_r(); + else + return 0xff; +} + +WRITE8_MEMBER( parallel_slot_device::pb_w ) +{ + if (m_cart) + m_cart->pb_w(data); +} + + +//************************************************************************** +// CARTRIDGE INTERFACE +//************************************************************************** + +//------------------------------------------------- +// device_parallel_interface - constructor +//------------------------------------------------- + +device_parallel_interface::device_parallel_interface(const machine_config &mconfig, device_t &device) : + device_slot_card_interface(mconfig, device) +{ + m_slot = dynamic_cast(device.owner()); +} + +//------------------------------------------------- +// ~device_parallel_interface - destructor +//------------------------------------------------- + +device_parallel_interface::~device_parallel_interface() +{ +} diff --git a/src/devices/bus/cgenie/parallel/parallel.h b/src/devices/bus/cgenie/parallel/parallel.h new file mode 100644 index 00000000000..4976e5caaf9 --- /dev/null +++ b/src/devices/bus/cgenie/parallel/parallel.h @@ -0,0 +1,94 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best +/*************************************************************************** + + EACA Colour Genie Parallel Slot + + 20-pin slot + + 1 GND 11 IOB2 + 2 +12V 12 IOB1 + 3 IOA3 13 IOB0 + 4 IOA4 14 IOB3 + 5 IOA0 15 IOB4 + 6 IOA5 16 IOB5 + 7 IOA1 17 IOB7 + 8 IOA2 18 IOB6 + 9 IOA7 19 +5V + 10 IOA6 20 -12V + +***************************************************************************/ + +#pragma once + +#ifndef __CGENIE_PARALLEL_H__ +#define __CGENIE_PARALLEL_H__ + +#include "emu.h" + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_PARALLEL_SLOT_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, PARALLEL_SLOT, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(parallel_slot_carts, NULL, false) + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class device_parallel_interface; + +class parallel_slot_device : public device_t, public device_slot_interface +{ +public: + // construction/destruction + parallel_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual ~parallel_slot_device(); + + // IOA + DECLARE_READ8_MEMBER(pa_r); + DECLARE_WRITE8_MEMBER(pa_w); + + // IOB + DECLARE_READ8_MEMBER(pb_r); + DECLARE_WRITE8_MEMBER(pb_w); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + device_parallel_interface *m_cart; + +private: +}; + +// class representing interface-specific live parallel device +class device_parallel_interface : public device_slot_card_interface +{ +public: + // construction/destruction + device_parallel_interface(const machine_config &mconfig, device_t &device); + virtual ~device_parallel_interface(); + + virtual UINT8 pa_r() { return 0xff; }; + virtual void pa_w(UINT8 data) {}; + + virtual UINT8 pb_r() { return 0xff; }; + virtual void pb_w(UINT8 data) {}; + +protected: + parallel_slot_device *m_slot; +}; + +// device type definition +extern const device_type PARALLEL_SLOT; + +// include here so drivers don't need to +#include "carts.h" + +#endif // __CGENIE_PARALLEL_H__ diff --git a/src/devices/bus/cgenie/parallel/printer.c b/src/devices/bus/cgenie/parallel/printer.c new file mode 100644 index 00000000000..f9963844dd5 --- /dev/null +++ b/src/devices/bus/cgenie/parallel/printer.c @@ -0,0 +1,132 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best +/*************************************************************************** + + EACA Colour Genie Printer Interface EG2012 + +***************************************************************************/ + +#include "printer.h" + + +//************************************************************************** +// CONSTANTS/MACROS +//************************************************************************** + +#define VERBOSE 0 + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type CGENIE_PRINTER = &device_creator; + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( cgenie_printer ) + MCFG_CENTRONICS_ADD("centronics", centronics_devices, "printer") + MCFG_CENTRONICS_BUSY_HANDLER(WRITELINE(cgenie_printer_device, busy_w)) + MCFG_CENTRONICS_PERROR_HANDLER(WRITELINE(cgenie_printer_device, perror_w)) + MCFG_CENTRONICS_SELECT_HANDLER(WRITELINE(cgenie_printer_device, select_w)) + MCFG_CENTRONICS_FAULT_HANDLER(WRITELINE(cgenie_printer_device, fault_w)) + MCFG_CENTRONICS_OUTPUT_LATCH_ADD("latch", "centronics") +MACHINE_CONFIG_END + +machine_config_constructor cgenie_printer_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( cgenie_printer ); +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// cgenie_printer_device - constructor +//------------------------------------------------- + +cgenie_printer_device::cgenie_printer_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, CGENIE_PRINTER, "Printer Interface EG2012", tag, owner, clock, "cgenie_printer", __FILE__), + device_parallel_interface(mconfig, *this), + m_centronics(*this, "centronics"), + m_latch(*this, "latch"), + m_centronics_busy(0), + m_centronics_out_of_paper(0), + m_centronics_unit_sel(1), + m_centronics_ready(1) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void cgenie_printer_device::device_start() +{ +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void cgenie_printer_device::device_reset() +{ +} + + +//************************************************************************** +// IMPLEMENTATION +//************************************************************************** + +WRITE_LINE_MEMBER( cgenie_printer_device::busy_w ) +{ + m_centronics_busy = state; +} + +WRITE_LINE_MEMBER( cgenie_printer_device::perror_w ) +{ + m_centronics_out_of_paper = state; +} + +WRITE_LINE_MEMBER( cgenie_printer_device::select_w ) +{ + m_centronics_unit_sel = state; +} + +WRITE_LINE_MEMBER( cgenie_printer_device::fault_w ) +{ + m_centronics_ready = state; +} + +void cgenie_printer_device::pa_w(UINT8 data) +{ + if (VERBOSE) + logerror("%s: pa_w %02x\n", tag(), data); + + m_latch->write(data); +} + +UINT8 cgenie_printer_device::pb_r() +{ + UINT8 data = 0x0f; + + data |= m_centronics_ready << 4; + data |= m_centronics_unit_sel << 5; + data |= m_centronics_out_of_paper << 6; + data |= m_centronics_busy << 7; + + return data; +} + +void cgenie_printer_device::pb_w(UINT8 data) +{ + if (VERBOSE) + logerror("%s: pa_w %02x\n", tag(), data); + + m_centronics->write_strobe(BIT(data, 0)); +} diff --git a/src/devices/bus/cgenie/parallel/printer.h b/src/devices/bus/cgenie/parallel/printer.h new file mode 100644 index 00000000000..52479c73d5c --- /dev/null +++ b/src/devices/bus/cgenie/parallel/printer.h @@ -0,0 +1,58 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best +/*************************************************************************** + + EACA Colour Genie Printer Interface EG2012 + +***************************************************************************/ + +#pragma once + +#ifndef __CGENIE_PARALLEL_PRINTER_H__ +#define __CGENIE_PARALLEL_PRINTER_H__ + +#include "emu.h" +#include "parallel.h" +#include "bus/centronics/ctronics.h" + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> cgenie_printer_device + +class cgenie_printer_device : public device_t, public device_parallel_interface +{ +public: + // construction/destruction + cgenie_printer_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + DECLARE_WRITE_LINE_MEMBER(busy_w); + DECLARE_WRITE_LINE_MEMBER(perror_w); + DECLARE_WRITE_LINE_MEMBER(select_w); + DECLARE_WRITE_LINE_MEMBER(fault_w); + +protected: + virtual machine_config_constructor device_mconfig_additions() const; + virtual void device_start(); + virtual void device_reset(); + + virtual void pa_w(UINT8 data); + virtual UINT8 pb_r(); + virtual void pb_w(UINT8 data); + +private: + required_device m_centronics; + required_device m_latch; + + int m_centronics_busy; + int m_centronics_out_of_paper; + int m_centronics_unit_sel; + int m_centronics_ready; +}; + +// device type definition +extern const device_type CGENIE_PRINTER; + +#endif // __CGENIE_PARALLEL_PRINTER_H__ diff --git a/src/devices/bus/chanf/rom.c b/src/devices/bus/chanf/rom.c new file mode 100644 index 00000000000..12beebafa4b --- /dev/null +++ b/src/devices/bus/chanf/rom.c @@ -0,0 +1,242 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + Fairchild Channel F cart emulation + + Three kind of carts: + - ROM only (the vast majority of carts) + - ROM + 2102 RAM chip (used by carts 10 and 18, with different I/O ports) + - ROM + 3853 RAM chip (used by Schach + some homebrew) + + Based on Sean Riddle's documentation (especially for the 2102 RAM!) + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "rom.h" + + +//------------------------------------------------- +// chanf_rom_device - constructor +//------------------------------------------------- + +const device_type CHANF_ROM_STD = &device_creator; +const device_type CHANF_ROM_MAZE = &device_creator; +const device_type CHANF_ROM_HANGMAN = &device_creator; +const device_type CHANF_ROM_CHESS = &device_creator; +const device_type CHANF_ROM_MULTI_OLD = &device_creator; +const device_type CHANF_ROM_MULTI_FINAL = &device_creator; + + +chanf_rom_device::chanf_rom_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_channelf_cart_interface( mconfig, *this ) +{ +} + +chanf_rom_device::chanf_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, CHANF_ROM_STD, "Channel F Standard Carts", tag, owner, clock, "chanf_rom", __FILE__), + device_channelf_cart_interface( mconfig, *this ) +{ +} + +chanf_maze_device::chanf_maze_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : chanf_rom_device(mconfig, CHANF_ROM_MAZE, "Channel F Maze Cart", tag, owner, clock, "chanf_maze", __FILE__) +{ +} + +chanf_hangman_device::chanf_hangman_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : chanf_rom_device(mconfig, CHANF_ROM_HANGMAN, "Channel F Hangman Cart", tag, owner, clock, "chanf_hang", __FILE__) +{ +} + +chanf_chess_device::chanf_chess_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : chanf_rom_device(mconfig, CHANF_ROM_CHESS, "Channel F Chess Cart", tag, owner, clock, "chanf_chess", __FILE__) +{ +} + +chanf_multi_old_device::chanf_multi_old_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : chanf_rom_device(mconfig, CHANF_ROM_MULTI_OLD, "Channel F Multigame (Earlier Version) Cart", tag, owner, clock, "chanf_multi_old", __FILE__) +{ +} + +chanf_multi_final_device::chanf_multi_final_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : chanf_rom_device(mconfig, CHANF_ROM_MULTI_FINAL, "Channel F Multigame (Final Version) Cart", tag, owner, clock, "chanf_multi_fin", __FILE__) +{ +} + + + +//------------------------------------------------- +// mapper specific start/reset +//------------------------------------------------- + + +void chanf_maze_device::device_start() +{ + // 2012 RAM related + save_item(NAME(m_latch)); + save_item(NAME(m_addr_latch)); + save_item(NAME(m_addr)); + save_item(NAME(m_read_write)); + save_item(NAME(m_data0)); +} + +void chanf_maze_device::device_reset() +{ + m_latch[0] = 0; + m_latch[1] = 0; + m_addr = 0; + m_addr_latch = 0; + m_read_write = 0; + m_data0 = 0; +} + + +void chanf_hangman_device::device_start() +{ + // 2012 RAM related + save_item(NAME(m_latch)); + save_item(NAME(m_addr_latch)); + save_item(NAME(m_addr)); + save_item(NAME(m_read_write)); + save_item(NAME(m_data0)); +} + +void chanf_hangman_device::device_reset() +{ + m_latch[0] = 0; + m_latch[1] = 0; + m_addr = 0; + m_addr_latch = 0; + m_read_write = 0; + m_data0 = 0; +} + + +void chanf_multi_old_device::device_start() +{ + save_item(NAME(m_base_bank)); +} + +void chanf_multi_old_device::device_reset() +{ + m_base_bank = 0; +} + + +void chanf_multi_final_device::device_start() +{ + save_item(NAME(m_base_bank)); + save_item(NAME(m_half_bank)); +} + +void chanf_multi_final_device::device_reset() +{ + m_base_bank = 0; + m_half_bank = 0; +} + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +READ8_MEMBER(chanf_rom_device::read_rom) +{ + if (offset < m_rom_size) + return m_rom[offset]; + else + return 0xff; +} + +// These are shared among Maze & Hangman cart types (not directly used by base chanf_rom_device) +UINT8 chanf_rom_device::common_read_2102(UINT32 offset) +{ + if (offset == 0) + { + if (m_read_write == 0) + { + m_addr = m_addr_latch; + m_data0 = m_ram[m_addr] & 1; + return (m_latch[0] & 0x7f) | (m_data0 << 7); + } + + return m_latch[0]; + } + else + return m_latch[1]; +} + +void chanf_rom_device::common_write_2102(UINT32 offset, UINT8 data) +{ + if (offset == 0) + { + m_latch[0] = data; + + m_read_write = BIT(data, 0); + + m_addr_latch = (m_addr_latch & 0x3f3) | (BIT(data, 2) << 2) | (BIT(data, 1) << 3); // bits 2,3 come from this write! + m_addr = m_addr_latch; + + m_data0 = BIT(data, 3); + + if (m_read_write == 1) + m_ram[m_addr] = m_data0; + } + else + { + m_latch[1] = data; + // all bits but 2,3 come from this write, but they are shuffled + // notice that data is 8bits, so when swapping bit8 & bit9 are always 0! + m_addr_latch = (m_addr_latch & 0x0c) | (BITSWAP16((UINT16) data, 15, 14, 13, 12, 11, 10, 7, 6, 5, 3, 2, 1, 9, 8, 4, 0)); + } +} + + +// These are shared among Schach & Multigame cart types (not directly used by base chanf_rom_device) +UINT8 chanf_rom_device::common_read_3853(UINT32 offset) +{ + if (offset < m_ram.size()) + return m_ram[offset]; + else + return 0xff; +} + +void chanf_rom_device::common_write_3853(UINT32 offset, UINT8 data) +{ + if (offset < m_ram.size()) + m_ram[offset] = data; +} + +READ8_MEMBER(chanf_multi_old_device::read_rom) +{ + if (offset < 0x2000) + return m_rom[offset + m_base_bank * 0x2000]; + else + return 0xff; +} + +WRITE8_MEMBER(chanf_multi_old_device::write_bank) +{ + //printf("0x%x\n", data); + m_base_bank = data & 0x1f; +} + +READ8_MEMBER(chanf_multi_final_device::read_rom) +{ + if (offset < 0x2000) + return m_rom[offset + (m_base_bank * 0x2000) + (m_half_bank * 0x1000)]; + else + return 0xff; +} + +WRITE8_MEMBER(chanf_multi_final_device::write_bank) +{ + //printf("0x%x\n", data); + m_base_bank = data & 0x1f; + m_half_bank = BIT(data, 5); +} diff --git a/src/devices/bus/chanf/rom.h b/src/devices/bus/chanf/rom.h new file mode 100644 index 00000000000..5a13e38b2df --- /dev/null +++ b/src/devices/bus/chanf/rom.h @@ -0,0 +1,144 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __CHANF_ROM_H +#define __CHANF_ROM_H + +#include "slot.h" + + +// ======================> chanf_rom_device + +class chanf_rom_device : public device_t, + public device_channelf_cart_interface +{ +public: + // construction/destruction + chanf_rom_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + chanf_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start() {} + virtual void device_reset() {} + + UINT8 common_read_2102(UINT32 offset); + UINT8 common_read_3853(UINT32 offset); + void common_write_2102(UINT32 offset, UINT8 data); + void common_write_3853(UINT32 offset, UINT8 data); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_rom); + + +protected: + // used for RAM chip in Hangman & Maze + UINT8 m_latch[2]; // PORT A & PORT B + UINT16 m_addr_latch, m_addr; + int m_read_write, m_data0; +}; + +// ======================> chanf_maze_device + +class chanf_maze_device : public chanf_rom_device +{ +public: + // construction/destruction + chanf_maze_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_ram) { return common_read_2102(offset); } + virtual DECLARE_WRITE8_MEMBER(write_ram) { common_write_2102(offset, data); } +}; + + +// ======================> chanf_hangman_device + +class chanf_hangman_device : public chanf_rom_device +{ +public: + // construction/destruction + chanf_hangman_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_ram) { return common_read_2102(offset); } + virtual DECLARE_WRITE8_MEMBER(write_ram) { common_write_2102(offset, data); } +}; + + +// ======================> chanf_chess_device + +class chanf_chess_device : public chanf_rom_device +{ +public: + // construction/destruction + chanf_chess_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_ram) { return common_read_3853(offset); } + virtual DECLARE_WRITE8_MEMBER(write_ram) { common_write_3853(offset, data); } +}; + + +// ======================> chanf_multi_old_device + +class chanf_multi_old_device : public chanf_rom_device +{ +public: + // construction/destruction + chanf_multi_old_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_rom); + virtual DECLARE_READ8_MEMBER(read_ram) { return common_read_3853(offset); } + virtual DECLARE_WRITE8_MEMBER(write_ram) { common_write_3853(offset, data); } + virtual DECLARE_WRITE8_MEMBER(write_bank); + +private: + int m_base_bank; +}; + + +// ======================> chanf_multi_final_device + +class chanf_multi_final_device : public chanf_rom_device +{ +public: + // construction/destruction + chanf_multi_final_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_rom); + virtual DECLARE_READ8_MEMBER(read_ram) { return common_read_3853(offset); } + virtual DECLARE_WRITE8_MEMBER(write_ram) { common_write_3853(offset, data); } + virtual DECLARE_WRITE8_MEMBER(write_bank); + +private: + int m_base_bank, m_half_bank; +}; + + +// device type definition +extern const device_type CHANF_ROM_STD; +extern const device_type CHANF_ROM_MAZE; +extern const device_type CHANF_ROM_HANGMAN; +extern const device_type CHANF_ROM_CHESS; +extern const device_type CHANF_ROM_MULTI_OLD; +extern const device_type CHANF_ROM_MULTI_FINAL; + + +#endif diff --git a/src/devices/bus/chanf/slot.c b/src/devices/bus/chanf/slot.c new file mode 100644 index 00000000000..3bb58417a9c --- /dev/null +++ b/src/devices/bus/chanf/slot.c @@ -0,0 +1,286 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + Fairchild Channel F cart emulation + (through slot devices) + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "slot.h" + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type CHANF_CART_SLOT = &device_creator; + +//************************************************************************** +// Channel F cartridges Interface +//************************************************************************** + +//------------------------------------------------- +// device_channelf_cart_interface - constructor +//------------------------------------------------- + +device_channelf_cart_interface::device_channelf_cart_interface(const machine_config &mconfig, device_t &device) + : device_slot_card_interface(mconfig, device), + m_rom(NULL), + m_rom_size(0) +{ +} + + +//------------------------------------------------- +// ~device_channelf_cart_interface - destructor +//------------------------------------------------- + +device_channelf_cart_interface::~device_channelf_cart_interface() +{ +} + +//------------------------------------------------- +// rom_alloc - alloc the space for the cart +//------------------------------------------------- + +void device_channelf_cart_interface::rom_alloc(UINT32 size, const char *tag) +{ + if (m_rom == NULL) + { + m_rom = device().machine().memory().region_alloc(std::string(tag).append(CHANFSLOT_ROM_REGION_TAG).c_str(), size, 1, ENDIANNESS_LITTLE)->base(); + m_rom_size = size; + } +} + + +//------------------------------------------------- +// ram_alloc - alloc the space for the ram +//------------------------------------------------- + +void device_channelf_cart_interface::ram_alloc(UINT32 size) +{ + m_ram.resize(size); +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// channelf_cart_slot_device - constructor +//------------------------------------------------- +channelf_cart_slot_device::channelf_cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, CHANF_CART_SLOT, "Fairchild Channel F Cartridge Slot", tag, owner, clock, "cf_cart_slot", __FILE__), + device_image_interface(mconfig, *this), + device_slot_interface(mconfig, *this), + m_type(CF_CHESS) +{ +} + + +//------------------------------------------------- +// ~channelf_cart_slot_device - destructor +//------------------------------------------------- + +channelf_cart_slot_device::~channelf_cart_slot_device() +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void channelf_cart_slot_device::device_start() +{ + m_cart = dynamic_cast(get_card_device()); +} + +//------------------------------------------------- +// device_config_complete - perform any +// operations now that the configuration is +// complete +//------------------------------------------------- + +void channelf_cart_slot_device::device_config_complete() +{ + // set brief and instance name + update_names(); +} + + +//------------------------------------------------- +// Channel F PCB +//------------------------------------------------- + +struct chanf_slot +{ + int pcb_id; + const char *slot_option; +}; + +// Here, we take the feature attribute from .xml (i.e. the PCB name) and we assign a unique ID to it +static const chanf_slot slot_list[] = +{ + { CF_STD, "std" }, + { CF_MAZE, "maze" }, + { CF_HANGMAN, "hangman" }, + { CF_CHESS, "chess" }, + { CF_MULTI_OLD,"multi_old" }, + { CF_MULTI, "multi" } +}; + +static int chanf_get_pcb_id(const char *slot) +{ + for (int i = 0; i < ARRAY_LENGTH(slot_list); i++) + { + if (!core_stricmp(slot_list[i].slot_option, slot)) + return slot_list[i].pcb_id; + } + + return 0; +} + +static const char *chanf_get_slot(int type) +{ + for (int i = 0; i < ARRAY_LENGTH(slot_list); i++) + { + if (slot_list[i].pcb_id == type) + return slot_list[i].slot_option; + } + + return "chess"; +} + + +/*------------------------------------------------- + call load + -------------------------------------------------*/ + +bool channelf_cart_slot_device::call_load() +{ + if (m_cart) + { + UINT32 len = (software_entry() == NULL) ? length() : get_software_region_length("rom"); + m_cart->rom_alloc(len, tag()); + + if (software_entry() == NULL) + fread(m_cart->get_rom_base(), len); + else + memcpy(m_cart->get_rom_base(), get_software_region("rom"), len); + + if (software_entry() == NULL) + { + // we default to "chess" slot because some homebrew programs have been written to run + // on PCBs with RAM at $2000-$2800 as Saba Schach! + if (len == 0x40000) + m_type = CF_MULTI; // TODO1: differentiate multicart final and earlier from fullpath + else + m_type = CF_CHESS; // TODO2: is there any way to detect Maze and Hangman from fullpath? + + m_cart->ram_alloc(0x800); + } + else + { + const char *pcb_name = get_feature("slot"); + if (pcb_name) + m_type = chanf_get_pcb_id(pcb_name); + + if (get_software_region("ram")) + m_cart->ram_alloc(get_software_region_length("ram")); + } + + //printf("Type: %s\n", chanf_get_slot(m_type)); + + return IMAGE_INIT_PASS; + } + + return IMAGE_INIT_PASS; +} + + +/*------------------------------------------------- + call softlist load + -------------------------------------------------*/ + +bool channelf_cart_slot_device::call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry) +{ + load_software_part_region(*this, swlist, swname, start_entry); + return TRUE; +} + + + +/*------------------------------------------------- + get default card software + -------------------------------------------------*/ + +void channelf_cart_slot_device::get_default_card_software(std::string &result) +{ + if (open_image_file(mconfig().options())) + { + const char *slot_string = "chess"; + UINT32 len = core_fsize(m_file); + int type; + + if (len == 0x40000) + type = CF_MULTI; + else + type = CF_CHESS; // is there any way to detect the other carts from fullpath? + + slot_string = chanf_get_slot(type); + + //printf("type: %s\n", slot_string); + clear(); + + result.assign(slot_string); + return; + } + software_get_default_slot(result, "chess"); +} + +/*------------------------------------------------- + read + -------------------------------------------------*/ + +READ8_MEMBER(channelf_cart_slot_device::read_rom) +{ + if (m_cart) + return m_cart->read_rom(space, offset); + else + return 0xff; +} + +/*------------------------------------------------- + read + -------------------------------------------------*/ + +READ8_MEMBER(channelf_cart_slot_device::read_ram) +{ + if (m_cart) + return m_cart->read_ram(space, offset); + else + return 0xff; +} + +/*------------------------------------------------- + write + -------------------------------------------------*/ + +WRITE8_MEMBER(channelf_cart_slot_device::write_ram) +{ + if (m_cart) + m_cart->write_ram(space, offset, data); +} + +/*------------------------------------------------- + write + -------------------------------------------------*/ + +WRITE8_MEMBER(channelf_cart_slot_device::write_bank) +{ + if (m_cart) + m_cart->write_bank(space, offset, data); +} diff --git a/src/devices/bus/chanf/slot.h b/src/devices/bus/chanf/slot.h new file mode 100644 index 00000000000..98276b81b9f --- /dev/null +++ b/src/devices/bus/chanf/slot.h @@ -0,0 +1,119 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __CHANF_SLOT_H +#define __CHANF_SLOT_H + +/*************************************************************************** + TYPE DEFINITIONS + ***************************************************************************/ + + +/* PCB */ +enum +{ + CF_STD = 0, + CF_MAZE, + CF_HANGMAN, + CF_CHESS, + CF_MULTI_OLD, + CF_MULTI +}; + + +// ======================> device_channelf_cart_interface + +class device_channelf_cart_interface : public device_slot_card_interface +{ +public: + // device_channelf_cart_interface/destruction + device_channelf_cart_interface(const machine_config &mconfig, device_t &device); + virtual ~device_channelf_cart_interface(); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_rom) { return 0xff; } + virtual DECLARE_READ8_MEMBER(read_ram) { return 0xff; } + virtual DECLARE_WRITE8_MEMBER(write_ram) {} + virtual DECLARE_WRITE8_MEMBER(write_bank) {} + + void rom_alloc(UINT32 size, const char *tag); + void ram_alloc(UINT32 size); + UINT8* get_rom_base() { return m_rom; } + UINT8* get_ram_base() { return &m_ram[0]; } + UINT32 get_rom_size() { return m_rom_size; } + UINT32 get_ram_size() { return m_ram.size(); } + + void save_ram() { device().save_item(NAME(m_ram)); } + +protected: + // internal state + UINT8 *m_rom; + UINT32 m_rom_size; + dynamic_buffer m_ram; +}; + + +// ======================> channelf_cart_slot_device + +class channelf_cart_slot_device : public device_t, + public device_image_interface, + public device_slot_interface +{ +public: + // construction/destruction + channelf_cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual ~channelf_cart_slot_device(); + + // device-level overrides + virtual void device_start(); + virtual void device_config_complete(); + + // image-level overrides + virtual bool call_load(); + virtual void call_unload() {} + virtual bool call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry); + + int get_type() { return m_type; } + + void save_ram() { if (m_cart && m_cart->get_ram_size()) m_cart->save_ram(); } + + virtual iodevice_t image_type() const { return IO_CARTSLOT; } + virtual bool is_readable() const { return 1; } + virtual bool is_writeable() const { return 0; } + virtual bool is_creatable() const { return 0; } + virtual bool must_be_loaded() const { return 0; } + virtual bool is_reset_on_load() const { return 1; } + virtual const option_guide *create_option_guide() const { return NULL; } + virtual const char *image_interface() const { return "channelf_cart"; } + virtual const char *file_extensions() const { return "bin,chf"; } + + // slot interface overrides + virtual void get_default_card_software(std::string &result); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_rom); + virtual DECLARE_READ8_MEMBER(read_ram); + virtual DECLARE_WRITE8_MEMBER(write_ram); + virtual DECLARE_WRITE8_MEMBER(write_bank); + +protected: + + int m_type; + device_channelf_cart_interface* m_cart; +}; + + + +// device type definition +extern const device_type CHANF_CART_SLOT; + + +/*************************************************************************** + DEVICE CONFIGURATION MACROS + ***************************************************************************/ + +#define CHANFSLOT_ROM_REGION_TAG ":cart:rom" + +#define MCFG_CHANNELF_CARTRIDGE_ADD(_tag,_slot_intf,_def_slot) \ + MCFG_DEVICE_ADD(_tag, CHANF_CART_SLOT, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) +#endif diff --git a/src/devices/bus/coco/coco_232.c b/src/devices/bus/coco/coco_232.c new file mode 100644 index 00000000000..a1b9c673c4b --- /dev/null +++ b/src/devices/bus/coco/coco_232.c @@ -0,0 +1,92 @@ +// license:BSD-3-Clause +// copyright-holders:Nathan Woods +/*************************************************************************** + + coco_232.c + + Code for emulating the CoCo RS-232 PAK + +***************************************************************************/ + +#include "emu.h" +#include "coco_232.h" + + +/*************************************************************************** + CONSTANTS +***************************************************************************/ + +#define UART_TAG "uart" + +/*************************************************************************** + IMPLEMENTATION +***************************************************************************/ + +static MACHINE_CONFIG_FRAGMENT(coco_rs232) + MCFG_DEVICE_ADD(UART_TAG, MOS6551, 0) + MCFG_MOS6551_XTAL(XTAL_1_8432MHz) +MACHINE_CONFIG_END + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type COCO_232 = &device_creator; + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// coco_232_device - constructor +//------------------------------------------------- + +coco_232_device::coco_232_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, COCO_232, "CoCo RS-232 PAK", tag, owner, clock, "coco_232", __FILE__), + device_cococart_interface( mconfig, *this ), + m_uart(*this, UART_TAG) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void coco_232_device::device_start() +{ +} + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor coco_232_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( coco_rs232 ); +} + +/*------------------------------------------------- + read +-------------------------------------------------*/ + +READ8_MEMBER(coco_232_device::read) +{ + UINT8 result = 0x00; + + if ((offset >= 0x28) && (offset <= 0x2F)) + result = m_uart->read(space, offset - 0x28); + + return result; +} + + +/*------------------------------------------------- + write +-------------------------------------------------*/ + +WRITE8_MEMBER(coco_232_device::write) +{ + if ((offset >= 0x28) && (offset <= 0x2F)) + m_uart->write(space, offset - 0x28, data); +} diff --git a/src/devices/bus/coco/coco_232.h b/src/devices/bus/coco/coco_232.h new file mode 100644 index 00000000000..362e4928de6 --- /dev/null +++ b/src/devices/bus/coco/coco_232.h @@ -0,0 +1,42 @@ +// license:BSD-3-Clause +// copyright-holders:Nathan Woods +#pragma once + +#ifndef __COCO_232_H__ +#define __COCO_232_H__ + +#include "emu.h" +#include "cococart.h" +#include "machine/mos6551.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> coco_232_device + +class coco_232_device : + public device_t, + public device_cococart_interface +{ +public: + // construction/destruction + coco_232_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; +protected: + // device-level overrides + virtual void device_start(); + virtual DECLARE_READ8_MEMBER(read); + virtual DECLARE_WRITE8_MEMBER(write); +private: + // internal state + required_device m_uart; +}; + + +// device type definition +extern const device_type COCO_232; + +#endif /* __COCO_232_H__ */ diff --git a/src/devices/bus/coco/coco_dwsock.c b/src/devices/bus/coco/coco_dwsock.c new file mode 100644 index 00000000000..0c8ee07bd42 --- /dev/null +++ b/src/devices/bus/coco/coco_dwsock.c @@ -0,0 +1,210 @@ +// license:BSD-3-Clause +// copyright-holders:Nathan Woods +#include +#include +#ifdef __GNUC__ +#include +#endif +#include +#include + +#include "emu.h" +#include "osdcore.h" +#include "includes/coco.h" + +#include "coco_dwsock.h" + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type COCO_DWSOCK = &device_creator; + +//------------------------------------------------- +// INPUT_PORTS( coco_drivewire ) +//------------------------------------------------- + +INPUT_PORTS_START( coco_drivewire ) + PORT_START(DRIVEWIRE_PORT_TAG) + PORT_CONFNAME( 0xffff, 65504, "Drivewire Server TCP Port") + PORT_CHANGED_MEMBER(DEVICE_SELF, beckerport_device, drivewire_port_changed, NULL ) + PORT_CONFSETTING( 65500, "65500" ) + PORT_CONFSETTING( 65501, "65501" ) + PORT_CONFSETTING( 65502, "65502" ) + PORT_CONFSETTING( 65503, "65503" ) + PORT_CONFSETTING( 65504, "65504" ) + PORT_CONFSETTING( 65505, "65505" ) + PORT_CONFSETTING( 65506, "65506" ) + PORT_CONFSETTING( 65507, "65507" ) + PORT_CONFSETTING( 65508, "65508" ) + PORT_CONFSETTING( 65509, "65509" ) +INPUT_PORTS_END + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor beckerport_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( coco_drivewire ); +} + +//------------------------------------------------- +// drivewire_port_changed +//------------------------------------------------- +INPUT_CHANGED_MEMBER(beckerport_device::drivewire_port_changed) +{ + this->update_port(); +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// beckerport_device - constructor / destructor +//------------------------------------------------- + +beckerport_device::beckerport_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, COCO_DWSOCK, "Virtual Becker Port", tag, owner, clock, "coco_dwsock", __FILE__), + m_dwconfigport(*this, DRIVEWIRE_PORT_TAG) +{ + m_pSocket = NULL; + m_head = 0; + m_rx_pending = 0; +} + +beckerport_device::~beckerport_device() +{ + if (m_pSocket != NULL) + device_stop(); +} + +/*------------------------------------------------- + device_start +-------------------------------------------------*/ + +void beckerport_device::device_start(void) +{ + char chAddress[64]; + + /* format address string for opening the port */ + snprintf(chAddress, sizeof(chAddress), "socket.%s:%d", m_hostname, m_dwtcpport); + + osd_printf_verbose("Connecting to Drivewire server on %s:%d... ", m_hostname, m_dwtcpport); + + UINT64 filesize; // unused + file_error filerr = osd_open(chAddress, 0, &m_pSocket, &filesize); + if (filerr != FILERR_NONE) + { + osd_printf_verbose("Error: osd_open returned error %i!\n", (int) filerr); + return; + } + + osd_printf_verbose("Connected!\n"); +} + +/*------------------------------------------------- + device_stop +-------------------------------------------------*/ + +void beckerport_device::device_stop(void) +{ + if (m_pSocket != NULL) + { + printf("Closing connection to Drivewire server\n"); + osd_close(m_pSocket); + m_pSocket = NULL; + } +} + +/*------------------------------------------------- + device_config_complete +-------------------------------------------------*/ + +void beckerport_device::device_config_complete(void) +{ + m_hostname = "127.0.0.1"; + m_dwtcpport = 65504; +} + +/*------------------------------------------------- + read +-------------------------------------------------*/ + +READ8_MEMBER(beckerport_device::read) +{ + unsigned char data = 0x5a; + + if (m_pSocket == NULL) + return data; + + switch (offset) + { + case DWS_STATUS: + if (!m_rx_pending) + { + /* Try to read from dws */ + file_error filerr = osd_read(m_pSocket, m_buf, 0, sizeof(m_buf), &m_rx_pending); + if (filerr != FILERR_NONE && filerr != FILERR_FAILURE) // FILERR_FAILURE means no data available, so don't throw error message + fprintf(stderr, "coco_dwsock.c: beckerport_device::read() socket read operation failed with file_error %i\n", filerr); + else + m_head = 0; + } + //printf("beckerport_device: status read. %i bytes remaining.\n", m_rx_pending); + data = (m_rx_pending > 0) ? 2 : 0; + break; + case DWS_DATA: + if (!m_rx_pending) { + fprintf(stderr, "coco_dwsock.c: beckerport_device::read() buffer underrun\n"); + break; + } + data = m_buf[m_head++]; + m_rx_pending--; + //printf("beckerport_device: data read 1 byte (0x%02x). %i bytes remaining.\n", data&0xff, m_rx_pending); + break; + default: + fprintf(stderr, "%s: read from bad offset %d\n", __FILE__, offset); + } + + return (int)data; +} + +/*------------------------------------------------- + write +-------------------------------------------------*/ + +WRITE8_MEMBER(beckerport_device::write) +{ + char d = (char)data; + file_error filerr; + + if (m_pSocket == NULL) + return; + + switch (offset) + { + case DWS_STATUS: + //printf("beckerport_write: error: write (0x%02x) to status register\n", d); + break; + case DWS_DATA: + filerr = osd_write(m_pSocket, &d, 0, 1, NULL); + if (filerr != FILERR_NONE) + fprintf(stderr, "coco_dwsock.c: beckerport_device::write() socket write operation failed with file_error %i\n", filerr); + //printf("beckerport_write: data write one byte (0x%02x)\n", d & 0xff); + break; + default: + fprintf(stderr, "%s: write to bad offset %d\n", __FILE__, offset); + } +} + +/*------------------------------------------------- + update_port +-------------------------------------------------*/ + +void beckerport_device::update_port(void) +{ + device_stop(); + m_dwtcpport = m_dwconfigport->read_safe(65504); + device_start(); +} diff --git a/src/devices/bus/coco/coco_dwsock.h b/src/devices/bus/coco/coco_dwsock.h new file mode 100644 index 00000000000..21b0ceb2170 --- /dev/null +++ b/src/devices/bus/coco/coco_dwsock.h @@ -0,0 +1,73 @@ +// license:BSD-3-Clause +// copyright-holders:Nathan Woods +#ifndef _DWSOCK_H_ +#define _DWSOCK_H_ + +#include "emu.h" +#include "osdcore.h" + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define DRIVEWIRE_PORT_TAG "drivewire_port" + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> beckerport_device + +class beckerport_device : public device_t +{ +public: + beckerport_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual ~beckerport_device(); + + // optional information overrides + virtual ioport_constructor device_input_ports() const; + + virtual void device_start(void); + virtual void device_stop(void); + virtual void device_config_complete(void); + + void update_port(void); + + // driver update handlers + DECLARE_INPUT_CHANGED_MEMBER(drivewire_port_changed); + + virtual DECLARE_READ8_MEMBER(read); + virtual DECLARE_WRITE8_MEMBER(write); + + // types + enum dwsock_ports { + DWS_STATUS, + DWS_DATA + }; + +private: + /* IP hostname */ + const char * m_hostname; + + /* IP port */ + required_ioport m_dwconfigport; + int m_dwtcpport; + + osd_file *m_pSocket; + + unsigned int m_rx_pending; + unsigned int m_head; + char m_buf[0x80]; +}; + +// device type definition +extern const device_type COCO_DWSOCK; + +// device iterator +typedef device_type_iterator<&device_creator, beckerport_device> beckerport_device_iterator; + +#endif /* _DWSOCK_H_ */ diff --git a/src/devices/bus/coco/coco_fdc.c b/src/devices/bus/coco/coco_fdc.c new file mode 100644 index 00000000000..bf165df42f5 --- /dev/null +++ b/src/devices/bus/coco/coco_fdc.c @@ -0,0 +1,713 @@ +// license:BSD-3-Clause +// copyright-holders:Nathan Woods +/********************************************************************* + + coco_fdc.c + + CoCo/Dragon FDC + + The CoCo and Dragon both use the Western Digital floppy disk controllers. + The CoCo uses either the WD1793 or the WD1773, the Dragon uses the WD2797, + which mostly uses the same command set with some subtle differences, most + notably the 2797 handles disk side select internally. The Dragon Alpha also + uses the WD2797, however as this is a built in interface and not an external + cartrige, it is dealt with in the main coco.c file. + + The wd's variables are mapped to $FF48-$FF4B on the CoCo and on $FF40-$FF43 + on the Dragon. In addition, there is another register + called DSKREG that controls the interface with the wd1793. DSKREG is + detailed below: But they appear to be + + References: + CoCo: Disk Basic Unravelled + Dragon: Inferences from the PC-Dragon source code + DragonDos Controller, Disk and File Formats by Graham E Kinns + + --------------------------------------------------------------------------- + + DSKREG - the control register + CoCo ($FF40) Dragon ($FF48) + + Bit Bit + 7 halt enable flag 7 not used + 6 drive select #3 6 not used + 5 density (0=single, 1=double) 5 NMI enable flag + and NMI enable flag + 4 write precompensation 4 write precompensation + 3 drive motor activation 3 single density enable + 2 drive select #2 2 drive motor activation + 1 drive select #1 1 drive select high bit + 0 drive select #0 0 drive select low bit + + Reading from $FF48-$FF4F clears bit 7 of DSKREG ($FF40) + + --------------------------------------------------------------------------- + + 2007-02-22, P.Harvey-Smith + + Began implementing the Dragon Delta Dos controler, this was actually the first + Dragon disk controler to market, beating Dragon Data's by a couple of months, + it is based around the WD2791 FDC, which is compatible with the WD1793/WD2797 used + by the standard CoCo and Dragon disk controlers except that it used an inverted + data bus, which is the reason the read/write handlers invert the data. This + controler like, the DragonDos WD2797 is mapped at $FF40-$FF43, in the normal + register order. + + The Delta cart also has a register (74LS174 hex flipflop) at $FF44 encoded as + follows :- + + Bit + 7 not used + 6 not used + 5 not used + 4 Single (0) / Double (1) density select + 3 5.25"(0) / 8"(1) Clock select + 2 Side select + 1 Drive select ms bit + 0 Drive select ls bit + +*********************************************************************/ + +#include "emu.h" +#include "coco_fdc.h" +#include "imagedev/flopdrv.h" +#include "includes/coco.h" +#include "imagedev/flopdrv.h" +#include "formats/dmk_dsk.h" +#include "formats/jvc_dsk.h" +#include "formats/vdk_dsk.h" + + +/*************************************************************************** + PARAMETERS +***************************************************************************/ + +#define LOG_FDC 0 +#define WD_TAG "wd17xx" +#define WD2797_TAG "wd2797" +#define DISTO_TAG "disto" +#define CLOUD9_TAG "cloud9" + +/*************************************************************************** + TYPE DEFINITIONS +***************************************************************************/ + +/*************************************************************************** + LOCAL VARIABLES +***************************************************************************/ + +FLOPPY_FORMATS_MEMBER( coco_fdc_device::floppy_formats ) + FLOPPY_DMK_FORMAT, + FLOPPY_JVC_FORMAT, + FLOPPY_VDK_FORMAT +FLOPPY_FORMATS_END + +static SLOT_INTERFACE_START( coco_fdc_floppies ) + SLOT_INTERFACE("qd", FLOPPY_525_QD) +SLOT_INTERFACE_END + + +/*************************************************************************** + IMPLEMENTATION +***************************************************************************/ +/*------------------------------------------------- + real_time_clock +-------------------------------------------------*/ + +coco_rtc_type_t coco_fdc_device::real_time_clock() +{ + coco_rtc_type_t result = (coco_rtc_type_t) machine().root_device().ioport("real_time_clock")->read_safe(RTC_NONE); + + /* check to make sure we don't have any invalid values */ + if (((result == RTC_DISTO) && (m_disto_msm6242 == NULL)) + || ((result == RTC_CLOUD9) && (m_ds1315 == NULL))) + { + result = RTC_NONE; + } + + return result; +} +/*------------------------------------------------- + fdc_intrq_w - callback from the FDC +-------------------------------------------------*/ + +WRITE_LINE_MEMBER( coco_fdc_device::fdc_intrq_w ) +{ + set_intrq(state); + update_lines(); +} + + +/*------------------------------------------------- + fdc_drq_w - callback from the FDC +-------------------------------------------------*/ + +WRITE_LINE_MEMBER( coco_fdc_device::fdc_drq_w ) +{ + set_drq(state); + update_lines(); +} + + +//************************************************************************** +// COCO FDC +//************************************************************************** + +static MACHINE_CONFIG_FRAGMENT(coco_fdc) + MCFG_WD1773_ADD(WD_TAG, XTAL_8MHz) + MCFG_WD_FDC_INTRQ_CALLBACK(WRITELINE(coco_fdc_device, fdc_intrq_w)) + MCFG_WD_FDC_DRQ_CALLBACK(WRITELINE(coco_fdc_device, fdc_drq_w)) + + MCFG_FLOPPY_DRIVE_ADD(WD_TAG ":0", coco_fdc_floppies, "qd", coco_fdc_device::floppy_formats) + MCFG_FLOPPY_DRIVE_ADD(WD_TAG ":1", coco_fdc_floppies, "qd", coco_fdc_device::floppy_formats) + MCFG_FLOPPY_DRIVE_ADD(WD_TAG ":2", coco_fdc_floppies, "", coco_fdc_device::floppy_formats) + MCFG_FLOPPY_DRIVE_ADD(WD_TAG ":3", coco_fdc_floppies, "", coco_fdc_device::floppy_formats) + + MCFG_DEVICE_ADD(DISTO_TAG, MSM6242, XTAL_32_768kHz) + MCFG_DS1315_ADD(CLOUD9_TAG) +MACHINE_CONFIG_END + +ROM_START( coco_fdc ) + ROM_REGION(0x4000,"eprom",ROMREGION_ERASE00) + ROM_LOAD_OPTIONAL( "disk10.rom", 0x0000, 0x2000, CRC(b4f9968e) SHA1(04115be3f97952b9d9310b52f806d04f80b40d03)) +ROM_END + +const device_type COCO_FDC = &device_creator; + +//------------------------------------------------- +// coco_fdc_device - constructor +//------------------------------------------------- +coco_fdc_device::coco_fdc_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_cococart_interface( mconfig, *this ), + m_wd17xx(*this, WD_TAG), + m_wd2797(*this, WD2797_TAG), + m_ds1315(*this, CLOUD9_TAG), + m_disto_msm6242(*this, DISTO_TAG) +{ +} + +coco_fdc_device::coco_fdc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, COCO_FDC, "CoCo FDC", tag, owner, clock, "coco_fdc", __FILE__), + device_cococart_interface( mconfig, *this ), + m_wd17xx(*this, WD_TAG), + m_wd2797(*this, WD2797_TAG), + m_ds1315(*this, CLOUD9_TAG), + m_disto_msm6242(*this, DISTO_TAG) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void coco_fdc_device::device_start() +{ + m_owner = dynamic_cast(owner()); + m_drq = 1; + m_dskreg = 0x00; + m_intrq = 0; + m_msm6242_rtc_address = 0; +} + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor coco_fdc_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( coco_fdc ); +} + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *coco_fdc_device::device_rom_region() const +{ + return ROM_NAME( coco_fdc ); +} + +/*------------------------------------------------- + get_cart_base +-------------------------------------------------*/ + +UINT8* coco_fdc_device::get_cart_base() +{ + return memregion("eprom")->base(); +} + +/*------------------------------------------------- + update_lines - CoCo specific disk + controller lines +-------------------------------------------------*/ + +void coco_fdc_device::update_lines() +{ + /* clear HALT enable under certain circumstances */ + if ((m_intrq != 0) && (m_dskreg & 0x20)) + m_dskreg &= ~0x80; /* clear halt enable */ + + /* set the NMI line */ + m_owner->cart_set_line(COCOCART_LINE_NMI, + ((m_intrq != 0) && (m_dskreg & 0x20)) ? COCOCART_LINE_VALUE_ASSERT : COCOCART_LINE_VALUE_CLEAR); + + /* set the HALT line */ + m_owner->cart_set_line(COCOCART_LINE_HALT, + ((m_drq == 0) && (m_dskreg & 0x80)) ? COCOCART_LINE_VALUE_ASSERT : COCOCART_LINE_VALUE_CLEAR); +} + +/*------------------------------------------------- + dskreg_w - function to write to CoCo + dskreg +-------------------------------------------------*/ + +void coco_fdc_device::dskreg_w(UINT8 data) +{ + UINT8 drive = 0; + UINT8 head = 0; + + if (LOG_FDC) + { + logerror("fdc_coco_dskreg_w(): %c%c%c%c%c%c%c%c ($%02x)\n", + data & 0x80 ? 'H' : 'h', + data & 0x40 ? '3' : '.', + data & 0x20 ? 'D' : 'S', + data & 0x10 ? 'P' : 'p', + data & 0x08 ? 'M' : 'm', + data & 0x04 ? '2' : '.', + data & 0x02 ? '1' : '.', + data & 0x01 ? '0' : '.', + data); + } + + /* An email from John Kowalski informed me that if the DS3 is + * high, and one of the other drive bits is selected (DS0-DS2), then the + * second side of DS0, DS1, or DS2 is selected. If multiple bits are + * selected in other situations, then both drives are selected, and any + * read signals get yucky. + */ + + if (data & 0x04) + drive = 2; + else if (data & 0x02) + drive = 1; + else if (data & 0x01) + drive = 0; + else if (data & 0x40) + drive = 3; + + floppy_image_device *floppy[4]; + + floppy[0] = subdevice(WD_TAG ":0")->get_device(); + floppy[1] = subdevice(WD_TAG ":1")->get_device(); + floppy[2] = subdevice(WD_TAG ":2")->get_device(); + floppy[3] = subdevice(WD_TAG ":3")->get_device(); + + for (int i = 0; i < 4; i++) + { + if (floppy[i]) + floppy[i]->mon_w(i == drive ? CLEAR_LINE : ASSERT_LINE); + } + + head = ((data & 0x40) && (drive != 3)) ? 1 : 0; + + m_dskreg = data; + + update_lines(); + + m_wd17xx->set_floppy(floppy[drive]); + + if (floppy[drive]) + floppy[drive]->ss_w(head); + + m_wd17xx->dden_w(!BIT(m_dskreg, 5)); +} + +/*------------------------------------------------- + read +-------------------------------------------------*/ + +READ8_MEMBER(coco_fdc_device::read) +{ + UINT8 result = 0; + + switch(offset & 0xEF) + { + case 8: + result = m_wd17xx->status_r(space, 0); + break; + case 9: + result = m_wd17xx->track_r(space, 0); + break; + case 10: + result = m_wd17xx->sector_r(space, 0); + break; + case 11: + result = m_wd17xx->data_r(space, 0); + break; + } + + /* other stuff for RTCs */ + switch(offset) + { + case 0x10: /* FF50 */ + if (real_time_clock() == RTC_DISTO) + result = m_disto_msm6242->read(space,m_msm6242_rtc_address); + break; + + case 0x38: /* FF78 */ + if (real_time_clock() == RTC_CLOUD9) + m_ds1315->read_0(space, offset); + break; + + case 0x39: /* FF79 */ + if (real_time_clock() == RTC_CLOUD9) + m_ds1315->read_1(space, offset); + break; + + case 0x3C: /* FF7C */ + if (real_time_clock() == RTC_CLOUD9) + result = m_ds1315->read_data(space, offset); + break; + } + return result; +} + + + +/*------------------------------------------------- + write +-------------------------------------------------*/ + +WRITE8_MEMBER(coco_fdc_device::write) +{ + switch(offset & 0x1F) + { + case 0: case 1: case 2: case 3: + case 4: case 5: case 6: case 7: + dskreg_w(data); + break; + case 8: + m_wd17xx->cmd_w(space, 0, data); + break; + case 9: + m_wd17xx->track_w(space, 0, data); + break; + case 10: + m_wd17xx->sector_w(space, 0, data); + break; + case 11: + //printf("data w %02x\n", data); + m_wd17xx->data_w(space, 0, data); + break; + }; + + /* other stuff for RTCs */ + switch(offset) + { + case 0x10: /* FF50 */ + if (real_time_clock() == RTC_DISTO) + m_disto_msm6242->write(space,m_msm6242_rtc_address, data); + break; + + case 0x11: /* FF51 */ + if (real_time_clock() == RTC_DISTO) + m_msm6242_rtc_address = data & 0x0f; + break; + } +} + + +//************************************************************************** +// DRAGON FDC +//************************************************************************** + +static MACHINE_CONFIG_FRAGMENT(dragon_fdc) + MCFG_WD2797_ADD(WD2797_TAG, XTAL_1MHz) + + MCFG_FLOPPY_DRIVE_ADD(WD2797_TAG ":0", coco_fdc_floppies, "qd", coco_fdc_device::floppy_formats) + MCFG_FLOPPY_DRIVE_ADD(WD2797_TAG ":1", coco_fdc_floppies, "qd", coco_fdc_device::floppy_formats) + MCFG_FLOPPY_DRIVE_ADD(WD2797_TAG ":2", coco_fdc_floppies, "", coco_fdc_device::floppy_formats) + MCFG_FLOPPY_DRIVE_ADD(WD2797_TAG ":3", coco_fdc_floppies, "", coco_fdc_device::floppy_formats) +MACHINE_CONFIG_END + + +ROM_START( dragon_fdc ) + ROM_REGION(0x4000,"eprom",ROMREGION_ERASE00) + ROM_LOAD_OPTIONAL( "ddos10.rom", 0x0000, 0x2000, CRC(b44536f6) SHA1(a8918c71d319237c1e3155bb38620acb114a80bc)) +ROM_END + +const device_type DRAGON_FDC = &device_creator; + +//------------------------------------------------- +// dragon_fdc_device - constructor +//------------------------------------------------- +dragon_fdc_device::dragon_fdc_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : coco_fdc_device(mconfig, type, name, tag, owner, clock, shortname, source) +{ +} +dragon_fdc_device::dragon_fdc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : coco_fdc_device(mconfig, DRAGON_FDC, "Dragon FDC", tag, owner, clock, "dragon_fdc", __FILE__) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void dragon_fdc_device::device_start() +{ + m_owner = dynamic_cast(owner()); + m_drq = 0; + m_dskreg = 0x00; + m_intrq = 0; + m_msm6242_rtc_address = 0; +} + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor dragon_fdc_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( dragon_fdc ); +} + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *dragon_fdc_device::device_rom_region() const +{ + return ROM_NAME( dragon_fdc ); +} + + + +/*------------------------------------------------- + update_lines - Dragon specific disk + controller lines +-------------------------------------------------*/ + +void dragon_fdc_device::update_lines() +{ + /* set the NMI line */ + m_owner->cart_set_line(COCOCART_LINE_NMI, + ((m_intrq != 0) && (m_dskreg & 0x20)) ? COCOCART_LINE_VALUE_ASSERT : COCOCART_LINE_VALUE_CLEAR); + + /* set the CART line */ + m_owner->cart_set_line(COCOCART_LINE_CART, + (m_drq != 0) ? COCOCART_LINE_VALUE_ASSERT : COCOCART_LINE_VALUE_CLEAR); +} + + +/*------------------------------------------------- + dskreg_w - function to write to + Dragon dskreg +-------------------------------------------------*/ + +void dragon_fdc_device::dskreg_w(UINT8 data) +{ + if (LOG_FDC) + { + logerror("fdc_dragon_dskreg_w(): %c%c%c%c%c%c%c%c ($%02x)\n", + data & 0x80 ? 'X' : 'x', + data & 0x40 ? 'X' : 'x', + data & 0x20 ? 'N' : 'n', + data & 0x10 ? 'P' : 'p', + data & 0x08 ? 'S' : 'D', + data & 0x04 ? 'M' : 'm', + data & 0x02 ? '1' : '0', + data & 0x01 ? '1' : '0', + data); + } + + floppy_image_device *floppy = NULL; + + switch (data & 0x03) + { + case 0: floppy = subdevice(WD2797_TAG ":0")->get_device(); break; + case 1: floppy = subdevice(WD2797_TAG ":1")->get_device(); break; + case 2: floppy = subdevice(WD2797_TAG ":2")->get_device(); break; + case 3: floppy = subdevice(WD2797_TAG ":3")->get_device(); break; + } + + m_wd2797->set_floppy(floppy); + + m_wd2797->dden_w(BIT(data, 3)); + + m_dskreg = data; +} + + + +/*------------------------------------------------- + read +-------------------------------------------------*/ + +READ8_MEMBER(dragon_fdc_device::read) +{ + UINT8 result = 0; + switch(offset & 0xEF) + { + case 0: + result = m_wd2797->status_r(space, 0); + break; + case 1: + result = m_wd2797->track_r(space, 0); + break; + case 2: + result = m_wd2797->sector_r(space, 0); + break; + case 3: + result = m_wd2797->data_r(space, 0); + break; + } + return result; +} + + + +/*------------------------------------------------- + write +-------------------------------------------------*/ + +WRITE8_MEMBER(dragon_fdc_device::write) +{ + switch(offset & 0xEF) + { + case 0: + m_wd2797->cmd_w(space, 0, data); + break; + case 1: + m_wd2797->track_w(space, 0, data); + break; + case 2: + m_wd2797->sector_w(space, 0, data); + break; + case 3: + m_wd2797->data_w(space, 0, data); + break; + case 8: case 9: case 10: case 11: + case 12: case 13: case 14: case 15: + dskreg_w(data); + break; + }; +} + +//************************************************************************** +// SDTANDY FDC +//************************************************************************** + +ROM_START( sdtandy_fdc ) + ROM_REGION(0x4000,"eprom",ROMREGION_ERASE00) + ROM_LOAD_OPTIONAL( "sdtandy.rom", 0x0000, 0x2000, CRC(5d7779b7) SHA1(ca03942118f2deab2f6c8a89b8a4f41f2d0b94f1)) +ROM_END + +const device_type SDTANDY_FDC = &device_creator; + +//------------------------------------------------- +// sdtandy_fdc_device - constructor +//------------------------------------------------- + +sdtandy_fdc_device::sdtandy_fdc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : dragon_fdc_device(mconfig, SDTANDY_FDC, "SDTANDY FDC", tag, owner, clock, "sdtandy_fdc", __FILE__) +{ +} + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *sdtandy_fdc_device::device_rom_region() const +{ + return ROM_NAME( sdtandy_fdc ); +} + +//************************************************************************** +// COCO FDC v1.1 +//************************************************************************** + +ROM_START( coco_fdc_v11 ) + ROM_REGION(0x8000,"eprom",ROMREGION_ERASE00) + ROM_LOAD_OPTIONAL( "disk11.rom", 0x0000, 0x2000, CRC(0b9c5415) SHA1(10bdc5aa2d7d7f205f67b47b19003a4bd89defd1)) + ROM_RELOAD(0x2000, 0x2000) + ROM_RELOAD(0x4000, 0x2000) + ROM_RELOAD(0x6000, 0x2000) +ROM_END + +const device_type COCO_FDC_V11 = &device_creator; + +//------------------------------------------------- +// coco_fdc_v11_device - constructor +//------------------------------------------------- + +coco_fdc_v11_device::coco_fdc_v11_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : coco_fdc_device(mconfig, COCO_FDC_V11, "CoCo FDC v1.1", tag, owner, clock, "coco_fdc_v11", __FILE__) +{ +} + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *coco_fdc_v11_device::device_rom_region() const +{ + return ROM_NAME( coco_fdc_v11 ); +} + +//************************************************************************** +// COCO-3 HDB-DOS +//************************************************************************** + +ROM_START( coco3_hdb1 ) + ROM_REGION(0x8000,"eprom",ROMREGION_ERASE00) + ROM_LOAD("hdbdw3bc3.rom", 0x0000, 0x2000, CRC(309a9efd) SHA1(671605d61811953860466f771c1594bbade331f4)) + ROM_RELOAD(0x2000, 0x2000) + ROM_RELOAD(0x4000, 0x2000) + ROM_RELOAD(0x6000, 0x2000) +ROM_END + +const device_type COCO3_HDB1 = &device_creator; + +coco3_hdb1_device::coco3_hdb1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : coco_fdc_device(mconfig, COCO3_HDB1, "CoCo3 HDB-DOS", tag, owner, clock, "coco3_hdb1", __FILE__) +{ +} + +const rom_entry *coco3_hdb1_device::device_rom_region() const +{ + return ROM_NAME( coco3_hdb1 ); +} + +//************************************************************************** +// CP400 FDC +//************************************************************************** + +ROM_START( cp400_fdc ) + ROM_REGION(0x4000,"eprom",ROMREGION_ERASE00) + ROM_LOAD("cp400dsk.rom", 0x0000, 0x2000, CRC(e9ad60a0) SHA1(827697fa5b755f5dc1efb054cdbbeb04e405405b)) +ROM_END + +const device_type CP400_FDC = &device_creator; + +//------------------------------------------------- +// cp400_fdc_device - constructor +//------------------------------------------------- + +cp400_fdc_device::cp400_fdc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : coco_fdc_device(mconfig, CP400_FDC, "CP400 FDC", tag, owner, clock, "cp400_fdc", __FILE__) +{ +} + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *cp400_fdc_device::device_rom_region() const +{ + return ROM_NAME( cp400_fdc ); +} diff --git a/src/devices/bus/coco/coco_fdc.h b/src/devices/bus/coco/coco_fdc.h new file mode 100644 index 00000000000..8773a48bea4 --- /dev/null +++ b/src/devices/bus/coco/coco_fdc.h @@ -0,0 +1,180 @@ +// license:BSD-3-Clause +// copyright-holders:Nathan Woods +#pragma once + +#ifndef __COCO_FDC_H__ +#define __COCO_FDC_H__ + +#include "emu.h" +#include "cococart.h" +#include "machine/msm6242.h" +#include "machine/ds1315.h" +#include "machine/wd_fdc.h" + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> coco_rtc_type_t + +enum coco_rtc_type_t +{ + RTC_DISTO = 0x00, + RTC_CLOUD9 = 0x01, + + RTC_NONE = 0xFF +}; + +// ======================> coco_fdc_device + +class coco_fdc_device : + public device_t, + public device_cococart_interface +{ +public: + // construction/destruction + coco_fdc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + coco_fdc_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + DECLARE_FLOPPY_FORMATS(floppy_formats); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual const rom_entry *device_rom_region() const; + + virtual UINT8* get_cart_base(); + + virtual void update_lines(); + virtual void dskreg_w(UINT8 data); + + void set_intrq(UINT8 val) { m_intrq = val; } + void set_drq(UINT8 val) { m_drq = val; } + + DECLARE_WRITE_LINE_MEMBER(fdc_intrq_w); + DECLARE_WRITE_LINE_MEMBER(fdc_drq_w); +protected: + // device-level overrides + virtual void device_start(); + virtual DECLARE_READ8_MEMBER(read); + virtual DECLARE_WRITE8_MEMBER(write); + + coco_rtc_type_t real_time_clock(); + + // internal state + cococart_slot_device *m_owner; + + UINT8 m_dskreg; + UINT8 m_drq : 1; + UINT8 m_intrq : 1; + + optional_device m_wd17xx; /* WD17xx */ + optional_device m_wd2797; /* WD2797 */ + optional_device m_ds1315; /* DS1315 */ + + /* Disto RTC */ + optional_device m_disto_msm6242; /* 6242 RTC on Disto interface */ + + offs_t m_msm6242_rtc_address; +}; + + +// device type definition +extern const device_type COCO_FDC; + +// ======================> coco_fdc_v11_device + +class coco_fdc_v11_device : + public coco_fdc_device +{ +public: + // construction/destruction + coco_fdc_v11_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; +}; + + +// device type definition +extern const device_type COCO_FDC_V11; + +// ======================> coco3_hdb1_device + +class coco3_hdb1_device : + public coco_fdc_device +{ +public: + // construction/destruction + coco3_hdb1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; +}; + + +// device type definition +extern const device_type COCO3_HDB1; + +// ======================> cp400_fdc_device + +class cp400_fdc_device : + public coco_fdc_device +{ +public: + // construction/destruction + cp400_fdc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; +}; + + +// device type definition +extern const device_type CP400_FDC; + +// ======================> dragon_fdc_device + +class dragon_fdc_device : + public coco_fdc_device +{ +public: + // construction/destruction + dragon_fdc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + dragon_fdc_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual const rom_entry *device_rom_region() const; + virtual void update_lines(); + virtual void dskreg_w(UINT8 data); +protected: + // device-level overrides + virtual void device_start(); + virtual DECLARE_READ8_MEMBER(read); + virtual DECLARE_WRITE8_MEMBER(write); +private: +}; + + +// device type definition +extern const device_type DRAGON_FDC; + +// ======================> sdtandy_fdc_device + +class sdtandy_fdc_device : + public dragon_fdc_device +{ +public: + // construction/destruction + sdtandy_fdc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; +}; + + +// device type definition +extern const device_type SDTANDY_FDC; + +#endif /* __COCO_FDC_H__ */ diff --git a/src/devices/bus/coco/coco_multi.c b/src/devices/bus/coco/coco_multi.c new file mode 100644 index 00000000000..0e488c582d8 --- /dev/null +++ b/src/devices/bus/coco/coco_multi.c @@ -0,0 +1,274 @@ +// license:BSD-3-Clause +// copyright-holders:Nathan Woods +/*************************************************************************** + + coco_multi.c + + Code for emulating CoCo's Multi-Pak Interface + + The Multi-Pak interface multiplexes all I/O lines from the Color + Computer's expansion port to four identical ports. All I/O lines + are continuously multiplexed except: + + Pin 36 - *SCS + Pin 32 - *CTS + Pin 8 - *CART + + These I/O lines are switched in one of two ways. First, is the front + panel, four position switch. When adjusted the switch will direct the + MPI to target these three I/O lines to the selected slot. + + Second, the MPI will listen to writes to 0xff7f and respond accordingly: + + bit 0 --\___ Target *SCS to this slot number + bit 1 --/ + bit 2 ------ Ignore + bit 3 ------ Ignore + bit 4 --\___ Target *CTS and *CART to this slot number + bit 5 --/ + bit 6 ------ Ignore + bit 7 ------ Ignore + + After writing to 0xff7f, the position of the physical switch has no + effect until reset. + + Reading is supported on 0xff7f. It will reflect the position of the + physical switch. Until data is written to 0xff7f, then it will only + reflect what has been written until a reset. + + A common modification users of the OS-9 operating system made was to + tie all of the *CART pins together on the MPI motherboard. The *CART + line is connected to the 6809's IRQ line. This allowed any hardware + device in any slot to signal an IRQ to the CPU, no matter what the + switch position was. OS-9 was designed from the very start to poll + each device attached on every IRQ signal. + + Because of sloppy address decoding the original MPI also responds to + $FF9F. No software is known to take advantage of this. After the + introduction of the CoCo 3, which uses $FF9F internally, Tandy provided + free upgrades to any MPI to fix this problem. + + +***************************************************************************/ + +#include "emu.h" +#include "includes/coco.h" +#include "coco_multi.h" +#include "coco_232.h" +#include "coco_orch90.h" +#include "coco_pak.h" +#include "coco_fdc.h" + +#define SLOT1_TAG "slot1" +#define SLOT2_TAG "slot2" +#define SLOT3_TAG "slot3" +#define SLOT4_TAG "slot4" + + + +/*************************************************************************** + IMPLEMENTATION +***************************************************************************/ + +static SLOT_INTERFACE_START(coco_cart_slot1_3) + SLOT_INTERFACE("rs232", COCO_232) + SLOT_INTERFACE("orch90", COCO_ORCH90) + SLOT_INTERFACE("banked_16k", COCO_PAK_BANKED) + SLOT_INTERFACE("pak", COCO_PAK) +SLOT_INTERFACE_END +static SLOT_INTERFACE_START(coco_cart_slot4) + SLOT_INTERFACE("cc3hdb1", COCO3_HDB1) + SLOT_INTERFACE("fdcv11", COCO_FDC_V11) + SLOT_INTERFACE("rs232", COCO_232) + SLOT_INTERFACE("orch90", COCO_ORCH90) + SLOT_INTERFACE("banked_16k", COCO_PAK_BANKED) + SLOT_INTERFACE("pak", COCO_PAK) +SLOT_INTERFACE_END + +WRITE_LINE_MEMBER(coco_multipak_device::multi_cart_w) +{ + cococart_slot_device *cart = dynamic_cast(owner()); + cart->m_cart_callback(state); +} + +WRITE_LINE_MEMBER(coco_multipak_device::multi_nmi_w) +{ + cococart_slot_device *cart = dynamic_cast(owner()); + cart->m_nmi_callback(state); +} + +WRITE_LINE_MEMBER(coco_multipak_device::multi_halt_w) +{ + cococart_slot_device *cart = dynamic_cast(owner()); + cart->m_halt_callback(state); +} + +static MACHINE_CONFIG_FRAGMENT(coco_multi) + MCFG_COCO_CARTRIDGE_ADD(SLOT1_TAG, coco_cart_slot1_3, NULL) + MCFG_COCO_CARTRIDGE_CART_CB(DEVWRITELINE(DEVICE_SELF, coco_multipak_device, multi_cart_w)) + MCFG_COCO_CARTRIDGE_NMI_CB(DEVWRITELINE(DEVICE_SELF, coco_multipak_device, multi_nmi_w)) + MCFG_COCO_CARTRIDGE_HALT_CB(DEVWRITELINE(DEVICE_SELF, coco_multipak_device, multi_halt_w)) + MCFG_COCO_CARTRIDGE_ADD(SLOT2_TAG, coco_cart_slot1_3, NULL) + MCFG_COCO_CARTRIDGE_CART_CB(DEVWRITELINE(DEVICE_SELF, coco_multipak_device, multi_cart_w)) + MCFG_COCO_CARTRIDGE_NMI_CB(DEVWRITELINE(DEVICE_SELF, coco_multipak_device, multi_nmi_w)) + MCFG_COCO_CARTRIDGE_HALT_CB(DEVWRITELINE(DEVICE_SELF, coco_multipak_device, multi_halt_w)) + MCFG_COCO_CARTRIDGE_ADD(SLOT3_TAG, coco_cart_slot1_3, NULL) + MCFG_COCO_CARTRIDGE_CART_CB(DEVWRITELINE(DEVICE_SELF, coco_multipak_device, multi_cart_w)) + MCFG_COCO_CARTRIDGE_NMI_CB(DEVWRITELINE(DEVICE_SELF, coco_multipak_device, multi_nmi_w)) + MCFG_COCO_CARTRIDGE_HALT_CB(DEVWRITELINE(DEVICE_SELF, coco_multipak_device, multi_halt_w)) + MCFG_COCO_CARTRIDGE_ADD(SLOT4_TAG, coco_cart_slot4, "fdcv11") + MCFG_COCO_CARTRIDGE_CART_CB(DEVWRITELINE(DEVICE_SELF, coco_multipak_device, multi_cart_w)) + MCFG_COCO_CARTRIDGE_NMI_CB(DEVWRITELINE(DEVICE_SELF, coco_multipak_device, multi_nmi_w)) + MCFG_COCO_CARTRIDGE_HALT_CB(DEVWRITELINE(DEVICE_SELF, coco_multipak_device, multi_halt_w)) +MACHINE_CONFIG_END + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type COCO_MULTIPAK = &device_creator; + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// coco_multipak_device - constructor +//------------------------------------------------- + +coco_multipak_device::coco_multipak_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, COCO_MULTIPAK, "CoCo Multi-Pak Interface", tag, owner, clock, "coco_multipak", __FILE__), + device_cococart_interface( mconfig, *this ) +{ +} + + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void coco_multipak_device::device_start() +{ + // identify slots + m_slots[0] = dynamic_cast(subdevice(SLOT1_TAG)); + m_slots[1] = dynamic_cast(subdevice(SLOT2_TAG)); + m_slots[2] = dynamic_cast(subdevice(SLOT3_TAG)); + m_slots[3] = dynamic_cast(subdevice(SLOT4_TAG)); + m_owner = dynamic_cast(owner()); + + // install $FF7F handler + write8_delegate wh = write8_delegate(FUNC(coco_multipak_device::ff7f_write), this); + machine().device(MAINCPU_TAG)->memory().space(AS_PROGRAM).install_write_handler(0xFF7F, 0xFF7F, wh); + + // initial state + m_select = 0xFF; + + // save state + save_item(NAME(m_select)); +} + + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void coco_multipak_device::device_reset() +{ + m_select = 0xFF; +} + + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor coco_multipak_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( coco_multi ); +} + + + +//------------------------------------------------- +// get_cart_base +//------------------------------------------------- + +UINT8* coco_multipak_device::get_cart_base() +{ + return active_cts_slot()->get_cart_base(); +} + + + +//------------------------------------------------- +// read +//------------------------------------------------- + +READ8_MEMBER(coco_multipak_device::read) +{ + return active_scs_slot()->read(space,offset); +} + + + +//------------------------------------------------- +// write +//------------------------------------------------- + +WRITE8_MEMBER(coco_multipak_device::write) +{ + active_scs_slot()->write(space,offset,data); +} + + + +//------------------------------------------------- +// ff7f_write +//------------------------------------------------- + +WRITE8_MEMBER(coco_multipak_device::ff7f_write) +{ + set_select(data); +} + + + +//------------------------------------------------- +// set_select +//------------------------------------------------- + +void coco_multipak_device::set_select(UINT8 new_select) +{ + UINT8 xorval = m_select ^ new_select; + m_select = new_select; + if (xorval & 0x30) + cart_base_changed(); +} + + + +//------------------------------------------------- +// active_scs_slot +//------------------------------------------------- + +cococart_slot_device *coco_multipak_device::active_scs_slot(void) +{ + return m_slots[(m_select >> 0) & 0x03]; +} + + + +//------------------------------------------------- +// active_cts_slot +//------------------------------------------------- + +cococart_slot_device *coco_multipak_device::active_cts_slot(void) +{ + return m_slots[(m_select >> 4) & 0x03]; +} diff --git a/src/devices/bus/coco/coco_multi.h b/src/devices/bus/coco/coco_multi.h new file mode 100644 index 00000000000..6c894b6377d --- /dev/null +++ b/src/devices/bus/coco/coco_multi.h @@ -0,0 +1,69 @@ +// license:BSD-3-Clause +// copyright-holders:Nathan Woods +/*************************************************************************** + + coco_multi.h + + Multi-Pak interface emulation + +***************************************************************************/ + +#pragma once + +#ifndef __COCO_MULTI_H__ +#define __COCO_MULTI_H__ + +#include "emu.h" +#include "cococart.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> coco_multipak_device + +class coco_multipak_device : + public device_t, + public device_cococart_interface +{ +public: + // construction/destruction + coco_multipak_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + + virtual UINT8* get_cart_base(); + + DECLARE_WRITE_LINE_MEMBER(multi_cart_w); + DECLARE_WRITE_LINE_MEMBER(multi_nmi_w); + DECLARE_WRITE_LINE_MEMBER(multi_halt_w); +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual DECLARE_READ8_MEMBER(read); + virtual DECLARE_WRITE8_MEMBER(write); + +private: + // device references + cococart_slot_device *m_owner; + cococart_slot_device *m_slots[4]; + + // internal state + UINT8 m_select; + + // methods + DECLARE_WRITE8_MEMBER(ff7f_write); + cococart_slot_device *active_scs_slot(void); + cococart_slot_device *active_cts_slot(void); + void set_select(UINT8 new_select); +}; + + +// device type definition +extern const device_type COCO_MULTIPAK; + +#endif /* __COCO_MULTI_H__ */ diff --git a/src/devices/bus/coco/coco_orch90.c b/src/devices/bus/coco/coco_orch90.c new file mode 100644 index 00000000000..83f2acaee54 --- /dev/null +++ b/src/devices/bus/coco/coco_orch90.c @@ -0,0 +1,85 @@ +// license:BSD-3-Clause +// copyright-holders:Nathan Woods +/*************************************************************************** + + orch90.c + + Code for emulating the CoCo Orch-90 (Orchestra 90) sound cartridge + + The Orch-90 was a simple sound cartridge; it had two 8-bit DACs + supporting stereo sound. The left channel was at $FF7A, and the right + channel was at $FF7B + +***************************************************************************/ + +#include "emu.h" +#include "coco_orch90.h" +#include "sound/dac.h" + +static MACHINE_CONFIG_FRAGMENT(coco_orch90) + MCFG_SPEAKER_STANDARD_STEREO("lspeaker", "rspeaker") + MCFG_SOUND_ADD("dac_left", DAC, 0) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "lspeaker", 1.0) + MCFG_SOUND_ADD("dac_right", DAC, 0) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "rspeaker", 1.0) +MACHINE_CONFIG_END + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type COCO_ORCH90 = &device_creator; + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// coco_orch90_device - constructor +//------------------------------------------------- + +coco_orch90_device::coco_orch90_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, COCO_ORCH90, "CoCo Orch-90 PAK", tag, owner, clock, "coco_orch90", __FILE__), + device_cococart_interface( mconfig, *this ) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void coco_orch90_device::device_start() +{ + m_left_dac = subdevice("dac_left"); + m_right_dac = subdevice("dac_right"); +} + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor coco_orch90_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( coco_orch90 ); +} + +/*------------------------------------------------- + write +-------------------------------------------------*/ + +WRITE8_MEMBER(coco_orch90_device::write) +{ + switch(offset) + { + case 0x3A: + /* left channel write */ + m_left_dac->write_unsigned8(data); + break; + + case 0x3B: + /* right channel write */ + m_right_dac->write_unsigned8(data); + break; + } +} diff --git a/src/devices/bus/coco/coco_orch90.h b/src/devices/bus/coco/coco_orch90.h new file mode 100644 index 00000000000..d96c99a911a --- /dev/null +++ b/src/devices/bus/coco/coco_orch90.h @@ -0,0 +1,42 @@ +// license:BSD-3-Clause +// copyright-holders:Nathan Woods +#pragma once + +#ifndef __COCO_ORCH90_H__ +#define __COCO_ORCH90_H__ + +#include "emu.h" +#include "sound/dac.h" +#include "cococart.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> coco_orch90_device + +class coco_orch90_device : + public device_t, + public device_cococart_interface +{ +public: + // construction/destruction + coco_orch90_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; +protected: + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write); +private: + // internal state + dac_device *m_left_dac; + dac_device *m_right_dac; +}; + + +// device type definition +extern const device_type COCO_ORCH90; + +#endif /* __COCO_ORCH90_H__ */ diff --git a/src/devices/bus/coco/coco_pak.c b/src/devices/bus/coco/coco_pak.c new file mode 100644 index 00000000000..72729f156a4 --- /dev/null +++ b/src/devices/bus/coco/coco_pak.c @@ -0,0 +1,179 @@ +// license:BSD-3-Clause +// copyright-holders:Nathan Woods +/*************************************************************************** + + coco_pak.c + + Code for emulating standard CoCo cartridges + +***************************************************************************/ + +#include "emu.h" +#include "coco_pak.h" +#include "includes/coco.h" + +#define CARTSLOT_TAG "cart" + +/*************************************************************************** + IMPLEMENTATION +***************************************************************************/ + +static MACHINE_CONFIG_FRAGMENT(coco_pak) +MACHINE_CONFIG_END + +ROM_START( coco_pak ) + ROM_REGION(0x8000, CARTSLOT_TAG, ROMREGION_ERASE00) + // this region is filled by cococart_slot_device::call_load() +ROM_END + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type COCO_PAK = &device_creator; + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// coco_pak_device - constructor +//------------------------------------------------- +coco_pak_device::coco_pak_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_cococart_interface( mconfig, *this ) +{ +} + +coco_pak_device::coco_pak_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, COCO_PAK, "CoCo Program PAK", tag, owner, clock, "cocopak", __FILE__), + device_cococart_interface( mconfig, *this ) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void coco_pak_device::device_start() +{ + m_cart = dynamic_cast(owner()); + m_owner = dynamic_cast(owner()); +} + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor coco_pak_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( coco_pak ); +} + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *coco_pak_device::device_rom_region() const +{ + return ROM_NAME( coco_pak ); +} + +/*------------------------------------------------- + device_reset - device-specific startup +-------------------------------------------------*/ + +void coco_pak_device::device_reset() +{ + if (m_cart->exists()) { + cococart_line_value cart_line; + + cart_line = machine().root_device().ioport(CART_AUTOSTART_TAG)->read_safe(0x01) + ? COCOCART_LINE_VALUE_Q + : COCOCART_LINE_VALUE_CLEAR; + + /* normal CoCo PAKs tie their CART line to Q - the system clock */ + m_owner->cart_set_line(COCOCART_LINE_CART,cart_line); + } +} + +/*------------------------------------------------- + get_cart_base +-------------------------------------------------*/ + +UINT8* coco_pak_device::get_cart_base() +{ + return memregion(CARTSLOT_TAG)->base(); +} + +/*************************************************************************** + BANKED CARTRIDGES +***************************************************************************/ + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type COCO_PAK_BANKED = &device_creator; + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// coco_pak_device - constructor +//------------------------------------------------- + +coco_pak_banked_device::coco_pak_banked_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : coco_pak_device(mconfig, COCO_PAK_BANKED, "CoCo Program PAK (Banked)", tag, owner, clock, "cocopak_banked", __FILE__) +{ +} + +/*------------------------------------------------- + device_reset - device-specific startup +-------------------------------------------------*/ + +void coco_pak_banked_device::device_reset() +{ + coco_pak_device::device_reset(); + + banked_pak_set_bank(0); +} + +/*------------------------------------------------- + banked_pak_set_bank - function to set the bank +-------------------------------------------------*/ + +void coco_pak_banked_device::banked_pak_set_bank(UINT32 bank) +{ + UINT64 pos; + UINT32 i; + UINT8 *rom = memregion(CARTSLOT_TAG)->base(); + UINT32 rom_length = memregion(CARTSLOT_TAG)->bytes(); + + if (m_cart->exists()) { + pos = (bank * 0x4000) % m_cart->length(); + + for (i = 0; i < rom_length / 0x4000; i++) + { + m_cart->fseek(pos, SEEK_SET); + m_cart->fread(&rom[i * 0x4000], 0x4000); + } + } +} + +/*------------------------------------------------- + write +-------------------------------------------------*/ + +WRITE8_MEMBER(coco_pak_banked_device::write) +{ + switch(offset) + { + case 0: + /* set the bank */ + banked_pak_set_bank(data); + break; + } +} diff --git a/src/devices/bus/coco/coco_pak.h b/src/devices/bus/coco/coco_pak.h new file mode 100644 index 00000000000..50df99ea4d5 --- /dev/null +++ b/src/devices/bus/coco/coco_pak.h @@ -0,0 +1,65 @@ +// license:BSD-3-Clause +// copyright-holders:Nathan Woods +#pragma once + +#ifndef __COCO_PAK_H__ +#define __COCO_PAK_H__ + +#include "emu.h" +#include "cococart.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> coco_pak_device + +class coco_pak_device : + public device_t, + public device_cococart_interface +{ +public: + // construction/destruction + coco_pak_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + coco_pak_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual const rom_entry *device_rom_region() const; + + virtual UINT8* get_cart_base(); +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // internal state + device_image_interface *m_cart; + cococart_slot_device *m_owner; +}; + + +// device type definition +extern const device_type COCO_PAK; + +// ======================> coco_pak_banked_device + +class coco_pak_banked_device : + public coco_pak_device +{ +public: + // construction/destruction + coco_pak_banked_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // device-level overrides + virtual void device_reset(); + virtual DECLARE_WRITE8_MEMBER(write); +private: + void banked_pak_set_bank(UINT32 bank); +}; + + +// device type definition +extern const device_type COCO_PAK_BANKED; +#endif /* __COCO_PAK_H__ */ diff --git a/src/devices/bus/coco/cococart.c b/src/devices/bus/coco/cococart.c new file mode 100644 index 00000000000..11687681810 --- /dev/null +++ b/src/devices/bus/coco/cococart.c @@ -0,0 +1,451 @@ +// license:BSD-3-Clause +// copyright-holders:Nathan Woods +/********************************************************************* + + cococart.c + + CoCo/Dragon cartridge management + +*********************************************************************/ + +#include "emu.h" +#include "cococart.h" +#include "emuopts.h" + +/*************************************************************************** + PARAMETERS +***************************************************************************/ + +#define LOG_LINE 0 + + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type COCOCART_SLOT = &device_creator; + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// cococart_slot_device - constructor +//------------------------------------------------- +cococart_slot_device::cococart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, COCOCART_SLOT, "CoCo Cartridge Slot", tag, owner, clock, "cococart_slot", __FILE__), + device_slot_interface(mconfig, *this), + device_image_interface(mconfig, *this), + m_cart_callback(*this), + m_nmi_callback(*this), + m_halt_callback(*this) +{ +} + + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void cococart_slot_device::device_start() +{ + for(int i=0; i(get_card_device()); +} + + + +//------------------------------------------------- +// device_config_complete - perform any +// operations now that the configuration is +// complete +//------------------------------------------------- + +void cococart_slot_device::device_config_complete() +{ + // set brief and instance name + update_names(); +} + + + +//------------------------------------------------- +// device_timer - handle timer callbacks +//------------------------------------------------- + +void cococart_slot_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch(id) + { + case TIMER_CART: + set_line("CART", m_cart_line, (cococart_line_value) param); + break; + + case TIMER_NMI: + set_line("NMI", m_nmi_line, (cococart_line_value) param); + break; + + case TIMER_HALT: + set_line("HALT", m_halt_line, (cococart_line_value) param); + break; + } +} + + + +//------------------------------------------------- +// coco_cartridge_r +//------------------------------------------------- + +READ8_MEMBER(cococart_slot_device::read) +{ + UINT8 result = 0x00; + if (m_cart) + result = m_cart->read(space, offset); + return result; +} + + +//------------------------------------------------- +// coco_cartridge_w +//------------------------------------------------- + +WRITE8_MEMBER(cococart_slot_device::write) +{ + if (m_cart) + m_cart->write(space, offset, data); +} + + + +//------------------------------------------------- +// line_value_string +//------------------------------------------------- + +static const char *line_value_string(cococart_line_value value) +{ + const char *s = NULL; + switch(value) + { + case COCOCART_LINE_VALUE_CLEAR: + s = "CLEAR"; + break; + case COCOCART_LINE_VALUE_ASSERT: + s = "ASSERT"; + break; + case COCOCART_LINE_VALUE_Q: + s = "Q"; + break; + default: + fatalerror("Invalid value\n"); + } + return s; +} + + + +//------------------------------------------------- +// set_line +//------------------------------------------------- + +void cococart_slot_device::set_line(const char *line_name, coco_cartridge_line &line, cococart_line_value value) +{ + if ((line.value != value) || (value == COCOCART_LINE_VALUE_Q)) + { + line.value = value; + + if (LOG_LINE) + logerror("[%s]: set_line(): %s <= %s\n", machine().describe_context(), line_name, line_value_string(value)); + /* engage in a bit of gymnastics for this odious 'Q' value */ + switch(line.value) + { + case COCOCART_LINE_VALUE_CLEAR: + line.line = 0x00; + line.q_count = 0; + break; + + case COCOCART_LINE_VALUE_ASSERT: + line.line = 0x01; + line.q_count = 0; + break; + + case COCOCART_LINE_VALUE_Q: + line.line = line.line ? 0x00 : 0x01; + if (line.q_count++ < 4) + set_line_timer(line, value); + break; + } + + /* invoke the callback, if present */ + if (!(*line.callback).isnull()) + (*line.callback)(line.line); + } +} + + + +//------------------------------------------------- +// set_line_timer() +//------------------------------------------------- + +void cococart_slot_device::set_line_timer(coco_cartridge_line &line, cococart_line_value value) +{ + /* calculate delay; delay dependant on cycles per second */ + attotime delay = (line.delay != 0) + ? machine().firstcpu->cycles_to_attotime(line.delay) + : attotime::zero; + + line.timer[line.timer_index]->adjust(delay, (int) value); + line.timer_index = (line.timer_index + 1) % TIMER_POOL; +} + + + +//------------------------------------------------- +// twiddle_line_if_q +//------------------------------------------------- + +void cococart_slot_device::twiddle_line_if_q(coco_cartridge_line &line) +{ + if (line.value == COCOCART_LINE_VALUE_Q) + { + line.q_count = 0; + set_line_timer(line, COCOCART_LINE_VALUE_Q); + } +} + + + +//------------------------------------------------- +// coco_cartridge_twiddle_q_lines - hack to +// support twiddling the Q line +//------------------------------------------------- + +void cococart_slot_device::twiddle_q_lines() +{ + twiddle_line_if_q(m_cart_line); + twiddle_line_if_q(m_nmi_line); + twiddle_line_if_q(m_halt_line); +} + + +//------------------------------------------------- +// coco_cartridge_set_line +//------------------------------------------------- + +void cococart_slot_device::cart_set_line(cococart_line line, cococart_line_value value) +{ + switch (line) + { + case COCOCART_LINE_CART: + set_line_timer(m_cart_line, value); + break; + + case COCOCART_LINE_NMI: + set_line_timer(m_nmi_line, value); + break; + + case COCOCART_LINE_HALT: + set_line_timer(m_halt_line, value); + break; + + case COCOCART_LINE_SOUND_ENABLE: + // do nothing for now + break; + } +} + + + +//------------------------------------------------- +// get_cart_base +//------------------------------------------------- + +UINT8* cococart_slot_device::get_cart_base() +{ + if (m_cart != NULL) + return m_cart->get_cart_base(); + return NULL; +} + + + +//------------------------------------------------- +// set_cart_base_update +//------------------------------------------------- + +void cococart_slot_device::set_cart_base_update(cococart_base_update_delegate update) +{ + if (m_cart != NULL) + m_cart->set_cart_base_update(update); +} + + + +//------------------------------------------------- +// call_load +//------------------------------------------------- + +bool cococart_slot_device::call_load() +{ + if (m_cart) + { + offs_t read_length = 0; + if (software_entry() == NULL) + { + read_length = fread(m_cart->get_cart_base(), 0x8000); + } + else + { + read_length = get_software_region_length("rom"); + memcpy(m_cart->get_cart_base(), get_software_region("rom"), read_length); + } + while(read_length < 0x8000) + { + offs_t len = MIN(read_length, 0x8000 - read_length); + memcpy(m_cart->get_cart_base() + read_length, m_cart->get_cart_base(), len); + read_length += len; + } + } + return IMAGE_INIT_PASS; +} + + + +//------------------------------------------------- +// call_softlist_load +//------------------------------------------------- + +bool cococart_slot_device::call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry) +{ + load_software_part_region(*this, swlist, swname, start_entry ); + return TRUE; +} + + + +//------------------------------------------------- +// get_default_card_software +//------------------------------------------------- + +void cococart_slot_device::get_default_card_software(std::string &result) +{ + software_get_default_slot(result, "pak"); +} + + + + +//************************************************************************** +// DEVICE COCO CART INTERFACE +//************************************************************************** + +//------------------------------------------------- +// device_cococart_interface - constructor +//------------------------------------------------- + +device_cococart_interface::device_cococart_interface(const machine_config &mconfig, device_t &device) + : device_slot_card_interface(mconfig, device) +{ +} + + + +//------------------------------------------------- +// ~device_cococart_interface - destructor +//------------------------------------------------- + +device_cococart_interface::~device_cococart_interface() +{ +} + + + +//------------------------------------------------- +// read +//------------------------------------------------- + +READ8_MEMBER(device_cococart_interface::read) +{ + return 0x00; +} + + + +//------------------------------------------------- +// write +//------------------------------------------------- + +WRITE8_MEMBER(device_cococart_interface::write) +{ +} + + + +//------------------------------------------------- +// get_cart_base +//------------------------------------------------- + +UINT8* device_cococart_interface::get_cart_base() +{ + return NULL; +} + + + +//------------------------------------------------- +// set_cart_base_update +//------------------------------------------------- + +void device_cococart_interface::set_cart_base_update(cococart_base_update_delegate update) +{ + m_update = update; +} + + + +//------------------------------------------------- +// cart_base_changed +//------------------------------------------------- + +void device_cococart_interface::cart_base_changed(void) +{ + if (!m_update.isnull()) + m_update(get_cart_base()); +} diff --git a/src/devices/bus/coco/cococart.h b/src/devices/bus/coco/cococart.h new file mode 100644 index 00000000000..a583935b5a2 --- /dev/null +++ b/src/devices/bus/coco/cococart.h @@ -0,0 +1,183 @@ +// license:BSD-3-Clause +// copyright-holders:Nathan Woods +/********************************************************************* + + cococart.h + + CoCo/Dragon cartridge management + +*********************************************************************/ + +#ifndef __COCOCART_H__ +#define __COCOCART_H__ + + +/*************************************************************************** + CONSTANTS +***************************************************************************/ + +/* TIMER_POOL: Must be power of two */ +#define TIMER_POOL 2 + +/*************************************************************************** + TYPE DEFINITIONS +***************************************************************************/ + +/* output lines on the CoCo cartridge slot */ +enum cococart_line +{ + COCOCART_LINE_CART, /* connects to PIA1 CB1 */ + COCOCART_LINE_NMI, /* connects to NMI line on CPU */ + COCOCART_LINE_HALT, /* connects to HALT line on CPU */ + COCOCART_LINE_SOUND_ENABLE /* sound enable */ +}; + +/* since we have a special value "Q" - we have to use a special enum here */ +enum cococart_line_value +{ + COCOCART_LINE_VALUE_CLEAR, + COCOCART_LINE_VALUE_ASSERT, + COCOCART_LINE_VALUE_Q +}; + +struct coco_cartridge_line +{ + emu_timer *timer[TIMER_POOL]; + int timer_index; + int delay; + cococart_line_value value; + int line; + int q_count; + devcb_write_line *callback; +}; + +// ======================> cococart_base_update_delegate + +// direct region update handler +typedef delegate cococart_base_update_delegate; + +#define MCFG_COCO_CARTRIDGE_CART_CB(_devcb) \ + devcb = &cococart_slot_device::static_set_cart_callback(*device, DEVCB_##_devcb); + +#define MCFG_COCO_CARTRIDGE_NMI_CB(_devcb) \ + devcb = &cococart_slot_device::static_set_nmi_callback(*device, DEVCB_##_devcb); + +#define MCFG_COCO_CARTRIDGE_HALT_CB(_devcb) \ + devcb = &cococart_slot_device::static_set_halt_callback(*device, DEVCB_##_devcb); + + +// ======================> cococart_slot_device +class device_cococart_interface; + +class cococart_slot_device : public device_t, + public device_slot_interface, + public device_image_interface +{ +public: + // construction/destruction + cococart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + template static devcb_base &static_set_cart_callback(device_t &device, _Object object) { return downcast(device).m_cart_callback.set_callback(object); } + template static devcb_base &static_set_nmi_callback(device_t &device, _Object object) { return downcast(device).m_nmi_callback.set_callback(object); } + template static devcb_base &static_set_halt_callback(device_t &device, _Object object) { return downcast(device).m_halt_callback.set_callback(object); } + + // device-level overrides + virtual void device_start(); + virtual void device_config_complete(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + // image-level overrides + virtual bool call_load(); + virtual bool call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry); + + virtual iodevice_t image_type() const { return IO_CARTSLOT; } + + virtual bool is_readable() const { return 1; } + virtual bool is_writeable() const { return 0; } + virtual bool is_creatable() const { return 0; } + virtual bool must_be_loaded() const { return 0; } + virtual bool is_reset_on_load() const { return 1; } + virtual const char *image_interface() const { return "coco_cart"; } + virtual const char *file_extensions() const { return "ccc,rom"; } + virtual const option_guide *create_option_guide() const { return NULL; } + + // slot interface overrides + virtual void get_default_card_software(std::string &result); + + // reading and writing to $FF40-$FF7F + DECLARE_READ8_MEMBER(read); + DECLARE_WRITE8_MEMBER(write); + + // sets a cartridge line + void cart_set_line(cococart_line line, cococart_line_value value); + + // hack to support twiddling the Q line + void twiddle_q_lines(); + + // cart base + UINT8* get_cart_base(); + void set_cart_base_update(cococart_base_update_delegate update); + +private: + enum + { + TIMER_CART, + TIMER_NMI, + TIMER_HALT + }; + + // configuration + coco_cartridge_line m_cart_line; + coco_cartridge_line m_nmi_line; + coco_cartridge_line m_halt_line; +public: + devcb_write_line m_cart_callback; + devcb_write_line m_nmi_callback; + devcb_write_line m_halt_callback; +private: + // cartridge + device_cococart_interface *m_cart; + + // methods + void set_line(const char *line_name, coco_cartridge_line &line, cococart_line_value value); + void set_line_timer(coco_cartridge_line &line, cococart_line_value value); + void twiddle_line_if_q(coco_cartridge_line &line); +}; + +// device type definition +extern const device_type COCOCART_SLOT; + +// ======================> device_cococart_interface + +class device_cococart_interface : public device_slot_card_interface +{ +public: + // construction/destruction + device_cococart_interface(const machine_config &mconfig, device_t &device); + virtual ~device_cococart_interface(); + + virtual DECLARE_READ8_MEMBER(read); + virtual DECLARE_WRITE8_MEMBER(write); + + virtual UINT8* get_cart_base(); + void set_cart_base_update(cococart_base_update_delegate update); + +protected: + void cart_base_changed(void); + +private: + cococart_base_update_delegate m_update; +}; + +/*************************************************************************** + DEVICE CONFIGURATION MACROS +***************************************************************************/ + +#define MCFG_COCO_CARTRIDGE_ADD(_tag,_slot_intf,_def_slot) \ + MCFG_DEVICE_ADD(_tag, COCOCART_SLOT, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) + +#define MCFG_COCO_CARTRIDGE_REMOVE(_tag) \ + MCFG_DEVICE_REMOVE(_tag) + +#endif /* __COCOCART_H__ */ diff --git a/src/devices/bus/coleco/ctrl.c b/src/devices/bus/coleco/ctrl.c new file mode 100644 index 00000000000..575276ee231 --- /dev/null +++ b/src/devices/bus/coleco/ctrl.c @@ -0,0 +1,77 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + ColecoVision controller port emulation + +**********************************************************************/ + +#include "ctrl.h" + + + +//************************************************************************** +// DEVICE DEFINITION +//************************************************************************** + +const device_type COLECOVISION_CONTROL_PORT = &device_creator; + + + +//************************************************************************** +// CARD INTERFACE +//************************************************************************** + +//------------------------------------------------- +// device_colecovision_control_port_interface - constructor +//------------------------------------------------- + +device_colecovision_control_port_interface::device_colecovision_control_port_interface(const machine_config &mconfig, device_t &device) : + device_slot_card_interface(mconfig, device), + m_common0(1), + m_common1(1) +{ + m_port = dynamic_cast(device.owner()); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// colecovision_control_port_device - constructor +//------------------------------------------------- + +colecovision_control_port_device::colecovision_control_port_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, COLECOVISION_CONTROL_PORT, "ColecoVision control port", tag, owner, clock, "colecovision_control_port", __FILE__), + device_slot_interface(mconfig, *this), + m_write_irq(*this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void colecovision_control_port_device::device_start() +{ + m_device = dynamic_cast(get_card_device()); + + m_write_irq.resolve_safe(); +} + + +//------------------------------------------------- +// SLOT_INTERFACE( colecovision_control_port_devices ) +//------------------------------------------------- + +#include "hand.h" +#include "sac.h" + +SLOT_INTERFACE_START( colecovision_control_port_devices ) + SLOT_INTERFACE("hand", COLECO_HAND_CONTROLLER) + SLOT_INTERFACE("sac", COLECO_SUPER_ACTION_CONTROLLER) +SLOT_INTERFACE_END diff --git a/src/devices/bus/coleco/ctrl.h b/src/devices/bus/coleco/ctrl.h new file mode 100644 index 00000000000..dc45d18c1aa --- /dev/null +++ b/src/devices/bus/coleco/ctrl.h @@ -0,0 +1,105 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + ColecoVision controller port emulation + +********************************************************************** + + +**********************************************************************/ + +#pragma once + +#ifndef __COLECOVISION_CONTROL_PORT__ +#define __COLECOVISION_CONTROL_PORT__ + +#include "emu.h" + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_COLECOVISION_CONTROL_PORT_ADD(_tag, _slot_intf, _def_slot) \ + MCFG_DEVICE_ADD(_tag, COLECOVISION_CONTROL_PORT, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) + + +#define MCFG_COLECOVISION_CONTROL_PORT_IRQ_CALLBACK(_write) \ + devcb = &colecovision_control_port_device::set_irq_wr_callback(*device, DEVCB_##_write); + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class colecovision_control_port_device; + + +// ======================> device_colecovision_control_port_interface + +class device_colecovision_control_port_interface : public device_slot_card_interface +{ +public: + // construction/destruction + device_colecovision_control_port_interface(const machine_config &mconfig, device_t &device); + virtual ~device_colecovision_control_port_interface() { } + + virtual UINT8 joy_r() { return 0xff; }; + virtual void common0_w(int state) { m_common0 = state; }; + virtual void common1_w(int state) { m_common1 = state; }; + +protected: + colecovision_control_port_device *m_port; + + int m_common0; + int m_common1; +}; + + +// ======================> colecovision_control_port_device + +class colecovision_control_port_device : public device_t, + public device_slot_interface +{ +public: + // construction/destruction + colecovision_control_port_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual ~colecovision_control_port_device() { } + + // static configuration helpers + template static devcb_base &set_irq_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_irq.set_callback(object); } + + // computer interface + UINT8 read() { UINT8 data = 0xff; if (exists()) data = m_device->joy_r(); return data; } + DECLARE_READ8_MEMBER( read ) { return read(); } + + DECLARE_WRITE_LINE_MEMBER( common0_w ) { if (exists()) m_device->common0_w(state); } + DECLARE_WRITE_LINE_MEMBER( common1_w ) { if (exists()) m_device->common1_w(state); } + + bool exists() { return m_device != NULL; } + + void irq_w(int state) { m_write_irq(state); } + +protected: + // device-level overrides + virtual void device_start(); + + device_colecovision_control_port_interface *m_device; + +private: + devcb_write_line m_write_irq; +}; + + +// device type definition +extern const device_type COLECOVISION_CONTROL_PORT; + +SLOT_INTERFACE_EXTERN( colecovision_control_port_devices ); + + + +#endif diff --git a/src/devices/bus/coleco/exp.c b/src/devices/bus/coleco/exp.c new file mode 100644 index 00000000000..c981406017e --- /dev/null +++ b/src/devices/bus/coleco/exp.c @@ -0,0 +1,156 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + ColecoVision cartridge port emulation + +**********************************************************************/ + +#include "exp.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type COLECOVISION_CARTRIDGE_SLOT = &device_creator; + + + +//************************************************************************** +// DEVICE C64_EXPANSION CARD INTERFACE +//************************************************************************** + +//------------------------------------------------- +// device_colecovision_cartridge_interface - constructor +//------------------------------------------------- + +device_colecovision_cartridge_interface::device_colecovision_cartridge_interface(const machine_config &mconfig, device_t &device) : + device_slot_card_interface(mconfig, device), + m_rom(NULL), + m_rom_size(0) +{ + m_slot = dynamic_cast(device.owner()); +} + +void device_colecovision_cartridge_interface::rom_alloc(size_t size) +{ + if (m_rom == NULL) + { + m_rom = device().machine().memory().region_alloc("coleco_cart:rom", size, 1, ENDIANNESS_LITTLE)->base(); + m_rom_size = size; + } +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// colecovision_cartridge_slot_device - constructor +//------------------------------------------------- + +colecovision_cartridge_slot_device::colecovision_cartridge_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, COLECOVISION_CARTRIDGE_SLOT, "ColecoVision cartridge port", tag, owner, clock, "coleco_cartridge_port", __FILE__), + device_slot_interface(mconfig, *this), + device_image_interface(mconfig, *this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void colecovision_cartridge_slot_device::device_start() +{ + m_card = dynamic_cast(get_card_device()); +} + + +//------------------------------------------------- +// call_load - +//------------------------------------------------- + +bool colecovision_cartridge_slot_device::call_load() +{ + if (m_card) + { + size_t size = (software_entry() == NULL) ? length() : get_software_region_length("rom"); + m_card->rom_alloc(size); + + if (software_entry() == NULL) + { + fread(m_card->m_rom, size); + } + else + { + // TODO 8000/a000/c000/e000 + memcpy(m_card->m_rom, get_software_region("rom"), size); + } + } + + return IMAGE_INIT_PASS; +} + + +//------------------------------------------------- +// call_softlist_load - +//------------------------------------------------- + +bool colecovision_cartridge_slot_device::call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry) +{ + load_software_part_region(*this, swlist, swname, start_entry); + + return true; +} + + +//------------------------------------------------- +// get_default_card_software - +//------------------------------------------------- + +void colecovision_cartridge_slot_device::get_default_card_software(std::string &result) +{ + if (open_image_file(mconfig().options())) + { + UINT32 length = core_fsize(m_file); + if (length == 0x100000 || length == 0x200000) + { + software_get_default_slot(result, "xin1"); + return; + } + } + software_get_default_slot(result, "standard"); +} + + +//------------------------------------------------- +// bd_r - cartridge data read +//------------------------------------------------- + +UINT8 colecovision_cartridge_slot_device::bd_r(address_space &space, offs_t offset, UINT8 data, int _8000, int _a000, int _c000, int _e000) +{ + if (m_card != NULL) + { + data = m_card->bd_r(space, offset, data, _8000, _a000, _c000, _e000); + } + + return data; +} + + +//------------------------------------------------- +// SLOT_INTERFACE( colecovision_cartridges ) +//------------------------------------------------- + +#include "std.h" +#include "xin1.h" + +SLOT_INTERFACE_START( colecovision_cartridges ) + // the following need ROMs from the software list + SLOT_INTERFACE_INTERNAL("standard", COLECOVISION_STANDARD) + SLOT_INTERFACE_INTERNAL("xin1", COLECOVISION_XIN1) +SLOT_INTERFACE_END diff --git a/src/devices/bus/coleco/exp.h b/src/devices/bus/coleco/exp.h new file mode 100644 index 00000000000..882bb04b659 --- /dev/null +++ b/src/devices/bus/coleco/exp.h @@ -0,0 +1,132 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + ColecoVision cartridge port emulation + +********************************************************************** + + D2 1 2 /C000 + D1 3 4 D3 + D0 5 6 D4 + A0 7 8 D5 + A1 9 10 D6 + A2 11 12 D7 + SHLD 13 14 A11 + A3 15 16 A10 + A4 17 18 /8000 + A13 19 20 A14 + A5 21 22 /A000 + A6 23 24 A12 + A7 25 26 A9 + /E000 27 28 A8 + GND 29 30 +5V + + +**********************************************************************/ + +#pragma once + +#ifndef __COLECOVISION_CARTRIDGE_SLOT__ +#define __COLECOVISION_CARTRIDGE_SLOT__ + +#include "emu.h" + + + +//************************************************************************** +// CONSTANTS +//************************************************************************** + +#define COLECOVISION_CARTRIDGE_SLOT_TAG "cartslot" + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_COLECOVISION_CARTRIDGE_SLOT_ADD(_tag, _slot_intf, _def_slot) \ + MCFG_DEVICE_ADD(_tag, COLECOVISION_CARTRIDGE_SLOT, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> colecovision_cartridge_slot_device + +class device_colecovision_cartridge_interface; + +class colecovision_cartridge_slot_device : public device_t, + public device_slot_interface, + public device_image_interface +{ +public: + // construction/destruction + colecovision_cartridge_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual ~colecovision_cartridge_slot_device() { } + + // computer interface + UINT8 bd_r(address_space &space, offs_t offset, UINT8 data, int _8000, int _a000, int _c000, int _e000); + +protected: + // device-level overrides + virtual void device_config_complete() { update_names(); } + virtual void device_start(); + + // image-level overrides + virtual bool call_load(); + virtual bool call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry); + + virtual iodevice_t image_type() const { return IO_CARTSLOT; } + + virtual bool is_readable() const { return 1; } + virtual bool is_writeable() const { return 0; } + virtual bool is_creatable() const { return 0; } + virtual bool must_be_loaded() const { return 0; } + virtual bool is_reset_on_load() const { return 1; } + virtual const char *image_interface() const { return "coleco_cart"; } + virtual const char *file_extensions() const { return "rom,col,bin"; } + virtual const option_guide *create_option_guide() const { return NULL; } + + // slot interface overrides + virtual void get_default_card_software(std::string &result); + + device_colecovision_cartridge_interface *m_card; +}; + + +// ======================> device_colecovision_cartridge_interface + +class device_colecovision_cartridge_interface : public device_slot_card_interface +{ + friend class colecovision_cartridge_slot_device; + +public: + // construction/destruction + device_colecovision_cartridge_interface(const machine_config &mconfig, device_t &device); + virtual ~device_colecovision_cartridge_interface() { } + + virtual UINT8 bd_r(address_space &space, offs_t offset, UINT8 data, int _8000, int _a000, int _c000, int _e000) { return 0xff; } + + void rom_alloc(size_t size); + +protected: + UINT8 *m_rom; + size_t m_rom_size; + + colecovision_cartridge_slot_device *m_slot; +}; + + +// device type definition +extern const device_type COLECOVISION_CARTRIDGE_SLOT; + +SLOT_INTERFACE_EXTERN( colecovision_cartridges ); + + + +#endif diff --git a/src/devices/bus/coleco/hand.c b/src/devices/bus/coleco/hand.c new file mode 100644 index 00000000000..058f06a3711 --- /dev/null +++ b/src/devices/bus/coleco/hand.c @@ -0,0 +1,126 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + ColecoVision Hand Controller emulation + +**********************************************************************/ + +#include "hand.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type COLECO_HAND_CONTROLLER = &device_creator; + + +CUSTOM_INPUT_MEMBER( coleco_hand_controller_t::keypad_r ) +{ + UINT8 data = 0xf; + UINT16 keypad = m_io_keypad->read(); + + if (!BIT(keypad, 0)) data &= 0x0a; + if (!BIT(keypad, 1)) data &= 0x0d; + if (!BIT(keypad, 2)) data &= 0x07; + if (!BIT(keypad, 3)) data &= 0x0c; + if (!BIT(keypad, 4)) data &= 0x02; + if (!BIT(keypad, 5)) data &= 0x03; + if (!BIT(keypad, 6)) data &= 0x0e; + if (!BIT(keypad, 7)) data &= 0x05; + if (!BIT(keypad, 8)) data &= 0x01; + if (!BIT(keypad, 9)) data &= 0x0b; + if (!BIT(keypad, 10)) data &= 0x06; + if (!BIT(keypad, 11)) data &= 0x09; + + return data; +} + +static INPUT_PORTS_START( coleco_hand_controller ) + PORT_START("COMMON0") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) + PORT_BIT( 0x30, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_BUTTON1 ) + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_SPECIAL ) + + PORT_START("COMMON1") + PORT_BIT( 0x0f, IP_ACTIVE_HIGH, IPT_SPECIAL ) PORT_CUSTOM_MEMBER(DEVICE_SELF, coleco_hand_controller_t, keypad_r, 0) + PORT_BIT( 0x30, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_BUTTON2 ) + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_SPECIAL ) + + PORT_START("KEYPAD") + PORT_BIT( 0x0001, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Keypad 0") PORT_CODE(KEYCODE_0_PAD) + PORT_BIT( 0x0002, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Keypad 1") PORT_CODE(KEYCODE_1_PAD) + PORT_BIT( 0x0004, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Keypad 2") PORT_CODE(KEYCODE_2_PAD) + PORT_BIT( 0x0008, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Keypad 3") PORT_CODE(KEYCODE_3_PAD) + PORT_BIT( 0x0010, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Keypad 4") PORT_CODE(KEYCODE_4_PAD) + PORT_BIT( 0x0020, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Keypad 5") PORT_CODE(KEYCODE_5_PAD) + PORT_BIT( 0x0040, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Keypad 6") PORT_CODE(KEYCODE_6_PAD) + PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Keypad 7") PORT_CODE(KEYCODE_7_PAD) + PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Keypad 8") PORT_CODE(KEYCODE_8_PAD) + PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Keypad 9") PORT_CODE(KEYCODE_9_PAD) + PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Keypad #") PORT_CODE(KEYCODE_MINUS_PAD) + PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Keypad *") PORT_CODE(KEYCODE_PLUS_PAD) +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor coleco_hand_controller_t::device_input_ports() const +{ + return INPUT_PORTS_NAME( coleco_hand_controller ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// coleco_hand_controller_t - constructor +//------------------------------------------------- + +coleco_hand_controller_t::coleco_hand_controller_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, COLECO_HAND_CONTROLLER, "ColecoVision Hand Controller", tag, owner, clock, "coleco_hand", __FILE__), + device_colecovision_control_port_interface(mconfig, *this), + m_io_common0(*this, "COMMON0"), + m_io_common1(*this, "COMMON1"), + m_io_keypad(*this, "KEYPAD") +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void coleco_hand_controller_t::device_start() +{ + // state saving + save_item(NAME(m_common0)); + save_item(NAME(m_common1)); +} + + +//------------------------------------------------- +// joy_r - joystick read +//------------------------------------------------- + +UINT8 coleco_hand_controller_t::joy_r() +{ + UINT8 data = 0x7f; + + if (!m_common0) data &= m_io_common0->read(); + if (!m_common1) data &= m_io_common1->read(); + + return data; +} diff --git a/src/devices/bus/coleco/hand.h b/src/devices/bus/coleco/hand.h new file mode 100644 index 00000000000..d57ea3ea212 --- /dev/null +++ b/src/devices/bus/coleco/hand.h @@ -0,0 +1,55 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + ColecoVision Hand Controller emulation + +**********************************************************************/ + +#pragma once + +#ifndef __COLECO_HAND_CONTROLLER__ +#define __COLECO_HAND_CONTROLLER__ + +#include "emu.h" +#include "ctrl.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> coleco_hand_controller_t + +class coleco_hand_controller_t : public device_t, + public device_colecovision_control_port_interface +{ +public: + // construction/destruction + coleco_hand_controller_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual ioport_constructor device_input_ports() const; + + DECLARE_CUSTOM_INPUT_MEMBER( keypad_r ); + +protected: + // device-level overrides + virtual void device_start(); + + // device_vcs_control_port_interface overrides + virtual UINT8 joy_r(); + +private: + required_ioport m_io_common0; + required_ioport m_io_common1; + required_ioport m_io_keypad; +}; + + +// device type definition +extern const device_type COLECO_HAND_CONTROLLER; + + +#endif diff --git a/src/devices/bus/coleco/sac.c b/src/devices/bus/coleco/sac.c new file mode 100644 index 00000000000..42ef14ca909 --- /dev/null +++ b/src/devices/bus/coleco/sac.c @@ -0,0 +1,138 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + ColecoVision Super Action Controller emulation + +**********************************************************************/ + +#include "sac.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type COLECO_SUPER_ACTION_CONTROLLER = &device_creator; + + +CUSTOM_INPUT_MEMBER( coleco_super_action_controller_t::keypad_r ) +{ + UINT8 data = 0xf; + UINT16 keypad = m_io_keypad->read(); + + if (!BIT(keypad, 0)) data &= 0x0a; + if (!BIT(keypad, 1)) data &= 0x0d; + if (!BIT(keypad, 2)) data &= 0x07; + if (!BIT(keypad, 3)) data &= 0x0c; + if (!BIT(keypad, 4)) data &= 0x02; + if (!BIT(keypad, 5)) data &= 0x03; + if (!BIT(keypad, 6)) data &= 0x0e; + if (!BIT(keypad, 7)) data &= 0x05; + if (!BIT(keypad, 8)) data &= 0x01; + if (!BIT(keypad, 9)) data &= 0x0b; + if (!BIT(keypad, 10)) data &= 0x06; + if (!BIT(keypad, 11)) data &= 0x09; + if (!BIT(keypad, 12)) data &= 0x04; + if (!BIT(keypad, 13)) data &= 0x08; + + return data; +} + +INPUT_CHANGED_MEMBER( coleco_super_action_controller_t::slider_w ) +{ + // TODO +} + +static INPUT_PORTS_START( coleco_super_action_controller ) + PORT_START("COMMON0") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) + PORT_BIT( 0x30, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_BUTTON1 ) + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_SPECIAL ) + + PORT_START("COMMON1") + PORT_BIT( 0x0f, IP_ACTIVE_HIGH, IPT_SPECIAL ) PORT_CUSTOM_MEMBER(DEVICE_SELF, coleco_super_action_controller_t, keypad_r, 0) + PORT_BIT( 0x30, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_BUTTON2 ) + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_SPECIAL ) + + PORT_START("KEYPAD") + PORT_BIT( 0x0001, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Keypad 0") PORT_CODE(KEYCODE_0_PAD) + PORT_BIT( 0x0002, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Keypad 1") PORT_CODE(KEYCODE_1_PAD) + PORT_BIT( 0x0004, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Keypad 2") PORT_CODE(KEYCODE_2_PAD) + PORT_BIT( 0x0008, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Keypad 3") PORT_CODE(KEYCODE_3_PAD) + PORT_BIT( 0x0010, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Keypad 4") PORT_CODE(KEYCODE_4_PAD) + PORT_BIT( 0x0020, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Keypad 5") PORT_CODE(KEYCODE_5_PAD) + PORT_BIT( 0x0040, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Keypad 6") PORT_CODE(KEYCODE_6_PAD) + PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Keypad 7") PORT_CODE(KEYCODE_7_PAD) + PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Keypad 8") PORT_CODE(KEYCODE_8_PAD) + PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Keypad 9") PORT_CODE(KEYCODE_9_PAD) + PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Keypad #") PORT_CODE(KEYCODE_MINUS_PAD) + PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Keypad *") PORT_CODE(KEYCODE_PLUS_PAD) + PORT_BIT( 0x1000, IP_ACTIVE_LOW, IPT_BUTTON3 ) + PORT_BIT( 0x2000, IP_ACTIVE_LOW, IPT_BUTTON4 ) + + PORT_START("SLIDER") + PORT_BIT( 0xff, 0x00, IPT_DIAL ) PORT_SENSITIVITY(100) PORT_KEYDELTA(25) PORT_REVERSE PORT_RESET PORT_CHANGED_MEMBER(DEVICE_SELF, coleco_super_action_controller_t, slider_w, 0) +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor coleco_super_action_controller_t::device_input_ports() const +{ + return INPUT_PORTS_NAME( coleco_super_action_controller ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// coleco_super_action_controller_t - constructor +//------------------------------------------------- + +coleco_super_action_controller_t::coleco_super_action_controller_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, COLECO_SUPER_ACTION_CONTROLLER, "ColecoVision Super Action Controller", tag, owner, clock, "coleco_sac", __FILE__), + device_colecovision_control_port_interface(mconfig, *this), + m_io_common0(*this, "COMMON0"), + m_io_common1(*this, "COMMON1"), + m_io_keypad(*this, "KEYPAD") +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void coleco_super_action_controller_t::device_start() +{ + // state saving + save_item(NAME(m_common0)); + save_item(NAME(m_common1)); +} + + +//------------------------------------------------- +// joy_r - joystick read +//------------------------------------------------- + +UINT8 coleco_super_action_controller_t::joy_r() +{ + UINT8 data = 0x7f; + + if (!m_common0) data &= m_io_common0->read(); + if (!m_common1) data &= m_io_common1->read(); + + return data; +} diff --git a/src/devices/bus/coleco/sac.h b/src/devices/bus/coleco/sac.h new file mode 100644 index 00000000000..b4bf3b09111 --- /dev/null +++ b/src/devices/bus/coleco/sac.h @@ -0,0 +1,56 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + ColecoVision Super Action Controller emulation + +**********************************************************************/ + +#pragma once + +#ifndef __COLECO_SUPER_ACTION_CONTROLLER__ +#define __COLECO_SUPER_ACTION_CONTROLLER__ + +#include "emu.h" +#include "ctrl.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> coleco_super_action_controller_t + +class coleco_super_action_controller_t : public device_t, + public device_colecovision_control_port_interface +{ +public: + // construction/destruction + coleco_super_action_controller_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual ioport_constructor device_input_ports() const; + + DECLARE_CUSTOM_INPUT_MEMBER( keypad_r ); + DECLARE_INPUT_CHANGED_MEMBER( slider_w ); + +protected: + // device-level overrides + virtual void device_start(); + + // device_vcs_control_port_interface overrides + virtual UINT8 joy_r(); + +private: + required_ioport m_io_common0; + required_ioport m_io_common1; + required_ioport m_io_keypad; +}; + + +// device type definition +extern const device_type COLECO_SUPER_ACTION_CONTROLLER; + + +#endif diff --git a/src/devices/bus/coleco/std.c b/src/devices/bus/coleco/std.c new file mode 100644 index 00000000000..f66a0463eae --- /dev/null +++ b/src/devices/bus/coleco/std.c @@ -0,0 +1,60 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + ColecoVision standard cartridge emulation + +**********************************************************************/ + +#include "std.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type COLECOVISION_STANDARD = &device_creator; + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// colecovision_standard_cartridge_device - constructor +//------------------------------------------------- + +colecovision_standard_cartridge_device::colecovision_standard_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, COLECOVISION_STANDARD, "ColecoVision standard cartridge", tag, owner, clock, "colecovision_standard", __FILE__), + device_colecovision_cartridge_interface(mconfig, *this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void colecovision_standard_cartridge_device::device_start() +{ +} + + +//------------------------------------------------- +// read - cartridge data read +//------------------------------------------------- + +UINT8 colecovision_standard_cartridge_device::bd_r(address_space &space, offs_t offset, UINT8 data, int _8000, int _a000, int _c000, int _e000) +{ + if (!_8000 || !_a000 || !_c000 || !_e000) + { + if (offset < m_rom_size) + data = m_rom[offset]; + else + data = 0xff; + } + + return data; +} diff --git a/src/devices/bus/coleco/std.h b/src/devices/bus/coleco/std.h new file mode 100644 index 00000000000..ee0a6e24e9a --- /dev/null +++ b/src/devices/bus/coleco/std.h @@ -0,0 +1,44 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + ColecoVision standard cartridge emulation + +**********************************************************************/ + +#pragma once + +#ifndef __COLECOVISION_STANDARD_CARTRIDGE__ +#define __COLECOVISION_STANDARD_CARTRIDGE__ + +#include "exp.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> colecovision_standard_cartridge_device + +class colecovision_standard_cartridge_device : public device_t, + public device_colecovision_cartridge_interface +{ +public: + // construction/destruction + colecovision_standard_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // device-level overrides + virtual void device_start(); + + // device_colecovision_expansion_card_interface overrides + virtual UINT8 bd_r(address_space &space, offs_t offset, UINT8 data, int _8000, int _a000, int _c000, int _e000); +}; + + +// device type definition +extern const device_type COLECOVISION_STANDARD; + + +#endif diff --git a/src/devices/bus/coleco/xin1.c b/src/devices/bus/coleco/xin1.c new file mode 100644 index 00000000000..e46b65eeadd --- /dev/null +++ b/src/devices/bus/coleco/xin1.c @@ -0,0 +1,71 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +/********************************************************************** + + ColecoVision X-in-1 cartridge emulation + +**********************************************************************/ + +#include "xin1.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type COLECOVISION_XIN1 = &device_creator; + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// colecovision_xin1_cartridge_device - constructor +//------------------------------------------------- + +colecovision_xin1_cartridge_device::colecovision_xin1_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, COLECOVISION_XIN1, "ColecoVision X-in-1 cartridge", tag, owner, clock, "colecovision_xin1", __FILE__), + device_colecovision_cartridge_interface(mconfig, *this), + m_current_offset(0) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void colecovision_xin1_cartridge_device::device_start() +{ +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void colecovision_xin1_cartridge_device::device_reset() +{ + m_current_offset = m_rom_size - 0x8000; +} + + +//------------------------------------------------- +// read - cartridge data read +//------------------------------------------------- + +UINT8 colecovision_xin1_cartridge_device::bd_r(address_space &space, offs_t offset, UINT8 data, int _8000, int _a000, int _c000, int _e000) +{ + if (!_8000 || !_a000 || !_c000 || !_e000) + { + data = m_rom[m_current_offset + offset]; + if (!_e000 && offset >= 0x7fc0) { + m_current_offset = (0x8000 * (offset - 0x7fc0)) % m_rom_size; + } + } + + return data; +} diff --git a/src/devices/bus/coleco/xin1.h b/src/devices/bus/coleco/xin1.h new file mode 100644 index 00000000000..79a940c646f --- /dev/null +++ b/src/devices/bus/coleco/xin1.h @@ -0,0 +1,48 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +/********************************************************************** + + ColecoVision X-in-1 cartridge emulation + +**********************************************************************/ + +#pragma once + +#ifndef __COLECOVISION_XIN1_CARTRIDGE__ +#define __COLECOVISION_XIN1_CARTRIDGE__ + +#include "exp.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> colecovision_xin1_cartridge_device + +class colecovision_xin1_cartridge_device : public device_t, + public device_colecovision_cartridge_interface +{ +public: + // construction/destruction + colecovision_xin1_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_colecovision_expansion_card_interface overrides + virtual UINT8 bd_r(address_space &space, offs_t offset, UINT8 data, int _8000, int _a000, int _c000, int _e000); + +private: + UINT32 m_current_offset; +}; + + +// device type definition +extern const device_type COLECOVISION_XIN1; + + +#endif diff --git a/src/devices/bus/compucolor/floppy.c b/src/devices/bus/compucolor/floppy.c new file mode 100644 index 00000000000..7fa7e678dc2 --- /dev/null +++ b/src/devices/bus/compucolor/floppy.c @@ -0,0 +1,252 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Compucolor Floppy Disk Drive emulation + +*********************************************************************/ + +#include "floppy.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type COMPUCOLOR_FLOPPY_PORT = &device_creator; +const device_type COMPUCOLOR_FLOPPY = &device_creator; + + +//------------------------------------------------- +// SLOT_INTERFACE( compucolor_floppy_port_devices ) +//------------------------------------------------- + +SLOT_INTERFACE_START( compucolor_floppy_port_devices ) + SLOT_INTERFACE("floppy", COMPUCOLOR_FLOPPY) +SLOT_INTERFACE_END + + +//------------------------------------------------- +// FLOPPY_FORMATS( floppy_formats ) +//------------------------------------------------- + +FLOPPY_FORMATS_MEMBER( compucolor_floppy_device::floppy_formats ) + FLOPPY_CCVF_FORMAT +FLOPPY_FORMATS_END + + +//------------------------------------------------- +// SLOT_INTERFACE( compucolor_floppies ) +//------------------------------------------------- + +static SLOT_INTERFACE_START( compucolor_floppies ) + SLOT_INTERFACE_INTERNAL( "525sssd", FLOPPY_525_SSSD ) +SLOT_INTERFACE_END + + +//------------------------------------------------- +// MACHINE_DRIVER( compucolor_floppy ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( compucolor_floppy ) + MCFG_FLOPPY_DRIVE_ADD("floppy", compucolor_floppies, "525sssd", compucolor_floppy_device::floppy_formats) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor compucolor_floppy_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( compucolor_floppy ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// device_compucolor_floppy_port_interface - constructor +//------------------------------------------------- + +device_compucolor_floppy_port_interface::device_compucolor_floppy_port_interface(const machine_config &mconfig, device_t &device) + : device_rs232_port_interface(mconfig, device) +{ +} + + +//------------------------------------------------- +// compucolor_floppy_port_device - constructor +//------------------------------------------------- + +compucolor_floppy_port_device::compucolor_floppy_port_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : rs232_port_device(mconfig, COMPUCOLOR_FLOPPY_PORT, "Compucolor Floppy Port", tag, owner, clock, "compclr_flp_port", __FILE__) +{ +} + + +//------------------------------------------------- +// compucolor_floppy_device - constructor +//------------------------------------------------- + +compucolor_floppy_device::compucolor_floppy_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, COMPUCOLOR_FLOPPY, "Compucolor floppy", tag, owner, clock, "compclr_flp", __FILE__), + device_compucolor_floppy_port_interface(mconfig, *this), + m_floppy(*this, "floppy:525sssd"), + m_rw(1), + m_stp(0), + m_sel(1), + m_period(attotime::from_hz(9600*8)) +{ + m_owner = dynamic_cast(this->owner()); +} + + +//------------------------------------------------- +// device_config_complete - +//------------------------------------------------- + +void compucolor_floppy_port_device::device_config_complete() +{ + rs232_port_device::device_config_complete(); + + m_dev = dynamic_cast(get_card_device()); +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void compucolor_floppy_port_device::device_start() +{ + rs232_port_device::device_start(); +} + + +void compucolor_floppy_device::device_start() +{ + // allocate timer + m_timer = timer_alloc(); + m_timer->adjust(attotime::from_hz(9600*8), 0, attotime::from_hz(9600*8)); + + // state saving + save_item(NAME(m_rw)); + save_item(NAME(m_stp)); + save_item(NAME(m_sel)); +} + + +//------------------------------------------------- +// device_timer - handle timer events +//------------------------------------------------- + +void compucolor_floppy_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + if (!m_sel && !m_rw) + { + output_rxd(read_bit()); + } +} + + +//------------------------------------------------- +// tx_w - +//------------------------------------------------- + +void compucolor_floppy_device::tx(UINT8 state) +{ + if (!m_sel && m_rw) + { + write_bit(state); + } +} + + +//------------------------------------------------- +// rw_w - +//------------------------------------------------- + +void compucolor_floppy_device::rw_w(int state) +{ + if (!m_rw && state) + { + output_rxd(1); + } + + m_rw = state; +} + + +//------------------------------------------------- +// stepper_w - +//------------------------------------------------- + +void compucolor_floppy_device::stepper_w(UINT8 data) +{ + if (!m_sel) + { + if ((m_stp == 1 && data == 4) || (m_stp == 2 && data == 1) || (m_stp == 4 && data == 2)) + { + // step in + m_floppy->dir_w(1); + m_floppy->stp_w(0); + m_floppy->stp_w(1); + } + else if ((m_stp == 1 && data == 2) || (m_stp == 2 && data == 4) || (m_stp == 4 && data == 1)) + { + // step out + m_floppy->dir_w(0); + m_floppy->stp_w(0); + m_floppy->stp_w(1); + } + } + + m_stp = data; +} + + +//------------------------------------------------- +// select_w - +//------------------------------------------------- + +void compucolor_floppy_device::select_w(int state) +{ + m_floppy->mon_w(state); + + if (!m_sel && state) + { + output_rxd(1); + } + + m_sel = state; +} + + +//------------------------------------------------- +// read_bit - +//------------------------------------------------- + +bool compucolor_floppy_device::read_bit() +{ + attotime when = machine().time(); + attotime edge = m_floppy->get_next_transition(when); + attotime next = when + m_period; + + return (edge.is_never() || edge >= next) ? 0 : 1; +} + + +//------------------------------------------------- +// write_bit - +//------------------------------------------------- + +void compucolor_floppy_device::write_bit(bool bit) +{ + // TODO +} diff --git a/src/devices/bus/compucolor/floppy.h b/src/devices/bus/compucolor/floppy.h new file mode 100644 index 00000000000..f229e96c3a9 --- /dev/null +++ b/src/devices/bus/compucolor/floppy.h @@ -0,0 +1,123 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Compucolor Floppy Disk Drive emulation + +*********************************************************************/ + +#pragma once + +#ifndef __COMPCLR_FLP__ +#define __COMPCLR_FLP__ + +#include "bus/rs232/rs232.h" +#include "formats/ccvf_dsk.h" +#include "imagedev/floppy.h" + + + +//************************************************************************** +// INTERFACE MACROS +//************************************************************************** + +#define MCFG_COMPUCOLOR_FLOPPY_PORT_ADD(_tag, _slot_intf, _def_slot) \ + MCFG_DEVICE_ADD(_tag, COMPUCOLOR_FLOPPY_PORT, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> device_compucolor_floppy_port_interface + +class device_compucolor_floppy_port_interface : public device_rs232_port_interface +{ +public: + device_compucolor_floppy_port_interface(const machine_config &mconfig, device_t &device); + virtual ~device_compucolor_floppy_port_interface() { } + + virtual void rw_w(int state) = 0; + virtual void stepper_w(UINT8 data) = 0; + virtual void select_w(int state) = 0; +}; + + +// ======================> compucolor_floppy_port_device + +class compucolor_floppy_port_device : public rs232_port_device +{ +public: + compucolor_floppy_port_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual ~compucolor_floppy_port_device() { } + + DECLARE_WRITE_LINE_MEMBER( rw_w ) { if (m_dev) m_dev->rw_w(state); } + void stepper_w(UINT8 data) { if (m_dev) m_dev->stepper_w(data); } + DECLARE_WRITE_LINE_MEMBER( select_w ) { if (m_dev) m_dev->select_w(state); } + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_config_complete(); + +private: + device_compucolor_floppy_port_interface *m_dev; +}; + + +// ======================> compucolor_floppy_device + +class compucolor_floppy_device : public device_t, + public device_compucolor_floppy_port_interface +{ +public: + // construction/destruction + compucolor_floppy_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + DECLARE_FLOPPY_FORMATS( floppy_formats ); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + // device_serial_port_interface overrides + virtual void tx(UINT8 state); + + // device_compucolor_floppy_port_interface overrides + virtual void rw_w(int state); + virtual void stepper_w(UINT8 data); + virtual void select_w(int state); + +private: + required_device m_floppy; + + bool read_bit(); + void write_bit(bool bit); + + int m_rw; + int m_stp; + int m_sel; + + attotime m_period; + + compucolor_floppy_port_device *m_owner; + + emu_timer *m_timer; +}; + + +// device type definition +extern const device_type COMPUCOLOR_FLOPPY_PORT; +extern const device_type COMPUCOLOR_FLOPPY; + + +// slot devices +SLOT_INTERFACE_EXTERN( compucolor_floppy_port_devices ); + +#endif diff --git a/src/devices/bus/comx35/clm.c b/src/devices/bus/comx35/clm.c new file mode 100644 index 00000000000..b9cc57b836f --- /dev/null +++ b/src/devices/bus/comx35/clm.c @@ -0,0 +1,263 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + COMX-35 80-Column Card emulation + +**********************************************************************/ + +/* + +(c) 1985 Comx World Operations + +PCB Layout +---------- + +F-003-CLM-REV 1 + + |---------------| + | CN1 | +|---| |---------------------------| +| | +| MC14174 LS86 LS175 LS10 LS161 | +| 14.31818MHz | +| LS245 LS04 | +| ROM1 6845 CN2 | +| LS374 LS165 | +|LD2 LS138 LS157 LS157 | +|LD1 6116 ROM2 SW1 | +| LS126 LS32 LS157 | +|-----------------------------------------------| + +Notes: + All IC's shown. + + 6845 - Motorola MC6845P CRT Controller + 6116 - Motorola MCM6116P15 2Kx8 Asynchronous CMOS Static RAM + ROM1 - Mitsubishi 2Kx8 EPROM "C" + ROM2 - Mitsubishi 2Kx8 EPROM "P" + CN1 - COMX-35 bus PCB edge connector + CN2 - RCA video output connector + LD1 - LED + LD2 - LED + SW1 - switch + +*/ + +#include "clm.h" + + + +//************************************************************************** +// MACROS/CONSTANTS +//************************************************************************** + +#define MC6845_TAG "mc6845" +#define MC6845_SCREEN_TAG "screen80" +#define VIDEORAM_SIZE 0x800 + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type COMX_CLM = &device_creator; + + +//------------------------------------------------- +// ROM( comx_clm ) +//------------------------------------------------- + +ROM_START( comx_clm ) + ROM_REGION( 0x2000, "c000", 0 ) + ROM_DEFAULT_BIOS( "v11" ) + ROM_SYSTEM_BIOS( 0, "v10", "v1.0" ) + ROMX_LOAD( "p 1.0.cl1", 0x0000, 0x0800, CRC(b417d30a) SHA1(d428b0467945ecb9aec884211d0f4b1d8d56d738), ROM_BIOS(1) ) + ROM_SYSTEM_BIOS( 1, "v11", "v1.1" ) + ROMX_LOAD( "p 1.1.cl1", 0x0000, 0x0800, CRC(0a2eaf19) SHA1(3f1f640caef964fb47aaa147cab6d215c2b30e9d), ROM_BIOS(2) ) + + ROM_REGION( 0x800, MC6845_TAG, 0 ) + ROMX_LOAD( "c 1.0.cl4", 0x0000, 0x0800, CRC(69dd7b07) SHA1(71d368adbb299103d165eab8359a97769e463e26), ROM_BIOS(1) ) + ROMX_LOAD( "c 1.1.cl4", 0x0000, 0x0800, CRC(dc9b5046) SHA1(4e041cec03dda6dba5e2598d060c49908a4fab2a), ROM_BIOS(2) ) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *comx_clm_device::device_rom_region() const +{ + return ROM_NAME( comx_clm ); +} + + +//------------------------------------------------- +// mc6845 +//------------------------------------------------- + +MC6845_UPDATE_ROW( comx_clm_device::crtc_update_row ) +{ + for (int column = 0; column < x_count; column++) + { + UINT8 code = m_video_ram[((ma + column) & 0x7ff)]; + UINT16 addr = (code << 3) | (ra & 0x07); + UINT8 data = m_char_rom->base()[addr & 0x7ff]; + + if (BIT(ra, 3) && column == cursor_x) + { + data = 0xff; + } + + for (int bit = 0; bit < 8; bit++) + { + int x = (column * 8) + bit; + + bitmap.pix32(vbp + y, hbp + x) = m_palette->pen(BIT(data, 7) && de); + + data <<= 1; + } + } +} + +//------------------------------------------------- +// GFXDECODE( comx_clm ) +//------------------------------------------------- + +static GFXDECODE_START( comx_clm ) + GFXDECODE_ENTRY(MC6845_TAG, 0x0000, gfx_8x8x1, 0, 1) +GFXDECODE_END + + +//------------------------------------------------- +// MACHINE_CONFIG_FRAGMENT( comx_clm ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( comx_clm ) + MCFG_SCREEN_ADD(MC6845_SCREEN_TAG, RASTER) + MCFG_SCREEN_UPDATE_DEVICE(MC6845_TAG, mc6845_device, screen_update) + MCFG_SCREEN_SIZE(80*8, 24*8) + MCFG_SCREEN_VISIBLE_AREA(0, 80*8-1, 0, 24*8-1) + MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(2500)) + MCFG_SCREEN_REFRESH_RATE(50) + + MCFG_GFXDECODE_ADD("gfxdecode", "palette", comx_clm) + MCFG_PALETTE_ADD_BLACK_AND_WHITE("palette") + + MCFG_MC6845_ADD(MC6845_TAG, MC6845, MC6845_SCREEN_TAG, XTAL_14_31818MHz/7) + MCFG_MC6845_SHOW_BORDER_AREA(true) + MCFG_MC6845_CHAR_WIDTH(8) + MCFG_MC6845_UPDATE_ROW_CB(comx_clm_device, crtc_update_row) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor comx_clm_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( comx_clm ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// comx_clm_device - constructor +//------------------------------------------------- + +comx_clm_device::comx_clm_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, COMX_CLM, "COMX 80 Column Card", tag, owner, clock, "comx_clm", __FILE__), + device_comx_expansion_card_interface(mconfig, *this), + m_crtc(*this, MC6845_TAG), + m_palette(*this, "palette"), + m_rom(*this, "c000"), + m_char_rom(*this, MC6845_TAG), + m_video_ram(*this, "video_ram") +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void comx_clm_device::device_start() +{ + // allocate memory + m_video_ram.allocate(VIDEORAM_SIZE); + + // state saving + save_item(NAME(m_ds)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void comx_clm_device::device_reset() +{ +} + + +//------------------------------------------------- +// comx_ef4_r - external flag 4 read +//------------------------------------------------- + +int comx_clm_device::comx_ef4_r() +{ + return m_ds ? m_crtc->hsync_r() : CLEAR_LINE; +} + + +//------------------------------------------------- +// comx_mrd_r - memory read +//------------------------------------------------- + +UINT8 comx_clm_device::comx_mrd_r(address_space &space, offs_t offset, int *extrom) +{ + UINT8 data = 0xff; + + if (offset >= 0xc000 && offset < 0xc800) + { + data = m_rom->base()[offset & 0x7ff]; + } + else if (offset >= 0xd000 && offset < 0xd800) + { + data = m_video_ram[offset & 0x7ff]; + } + else if (offset == 0xd801) + { + data = m_crtc->register_r(space, 0); + } + + return data; +} + + +//------------------------------------------------- +// comx_mwr_w - memory write +//------------------------------------------------- + +void comx_clm_device::comx_mwr_w(address_space &space, offs_t offset, UINT8 data) +{ + if (offset >= 0xd000 && offset < 0xd800) + { + m_video_ram[offset & 0x7ff] = data; + } + else if (offset == 0xd800) + { + m_crtc->address_w(space, 0, data); + } + else if (offset == 0xd801) + { + m_crtc->register_w(space, 0, data); + } +} diff --git a/src/devices/bus/comx35/clm.h b/src/devices/bus/comx35/clm.h new file mode 100644 index 00000000000..c64e57956bd --- /dev/null +++ b/src/devices/bus/comx35/clm.h @@ -0,0 +1,63 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + COMX-35 80-Column Card emulation + +**********************************************************************/ + +#pragma once + +#ifndef __COMX_CLM__ +#define __COMX_CLM__ + +#include "emu.h" +#include "exp.h" +#include "video/mc6845.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> comx_clm_device + +class comx_clm_device : public device_t, + public device_comx_expansion_card_interface +{ +public: + // construction/destruction + comx_clm_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + + // not really public + MC6845_UPDATE_ROW( crtc_update_row ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_comx_expansion_card_interface overrides + virtual int comx_ef4_r(); + virtual UINT8 comx_mrd_r(address_space &space, offs_t offset, int *extrom); + virtual void comx_mwr_w(address_space &space, offs_t offset, UINT8 data); + +private: + required_device m_crtc; + required_device m_palette; + required_memory_region m_rom; + required_memory_region m_char_rom; + optional_shared_ptr m_video_ram; +}; + + +// device type definition +extern const device_type COMX_CLM; + + +#endif diff --git a/src/devices/bus/comx35/eprom.c b/src/devices/bus/comx35/eprom.c new file mode 100644 index 00000000000..56be84b4902 --- /dev/null +++ b/src/devices/bus/comx35/eprom.c @@ -0,0 +1,121 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + COMX-35 F&M EPROM Card emulation + +**********************************************************************/ + +#include "eprom.h" + + + +//************************************************************************** +// MACROS/CONSTANTS +//************************************************************************** + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type COMX_EPR = &device_creator; + + +//------------------------------------------------- +// ROM( comx_epr ) +//------------------------------------------------- + +ROM_START( comx_epr ) + ROM_REGION( 0x800, "f800", 0 ) + ROM_LOAD( "f&m.eprom.board.1.1.bin", 0x0000, 0x0800, CRC(a042a31a) SHA1(13831a1350aa62a87988bfcc99c4b7db8ef1cf62) ) + + ROM_REGION( 0x10000, "eprom", 0 ) + ROM_LOAD( "f&m.basic.bin", 0x0000, 0x2000, CRC(22ab7b61) SHA1(68b5770bca37b1ba94083f944086884e612b5a1b) ) + ROM_LOAD( "disk.utilities.bin", 0x2000, 0x2000, CRC(2576c945) SHA1(e80481054c6997a5f418d8a5872ac0110ae7b75a) ) + ROM_LOAD( "tennismania.bin", 0x4000, 0x2000, CRC(a956cc74) SHA1(8bc914f52f0dd2cf792da74ec4e9e333365619ef) ) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *comx_epr_device::device_rom_region() const +{ + return ROM_NAME( comx_epr ); +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// comx_epr_device - constructor +//------------------------------------------------- + +comx_epr_device::comx_epr_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, COMX_EPR, "COMX-35 F&M EPROM Switchboard", tag, owner, clock, "comx_epr", __FILE__), + device_comx_expansion_card_interface(mconfig, *this), + m_rom(*this, "f800"), + m_eprom(*this, "eprom"), + m_select(0) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void comx_epr_device::device_start() +{ + // state saving + save_item(NAME(m_select)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void comx_epr_device::device_reset() +{ +} + + +//------------------------------------------------- +// comx_mrd_r - memory read +//------------------------------------------------- + +UINT8 comx_epr_device::comx_mrd_r(address_space &space, offs_t offset, int *extrom) +{ + UINT8 data = 0; + + if (offset >= 0xc000 && offset < 0xe000) + { + offs_t address = (m_select << 13) | (offset & 0x1fff); + data = m_eprom->base()[address]; + } + else if (offset >= 0xf800) + { + data = m_rom->base()[offset & 0x7ff]; + } + + return data; +} + + +//------------------------------------------------- +// comx_io_w - I/O write +//------------------------------------------------- + +void comx_epr_device::comx_io_w(address_space &space, offs_t offset, UINT8 data) +{ + if (offset == 1) + { + m_select = data >> 5; + } +} diff --git a/src/devices/bus/comx35/eprom.h b/src/devices/bus/comx35/eprom.h new file mode 100644 index 00000000000..f3b03f42367 --- /dev/null +++ b/src/devices/bus/comx35/eprom.h @@ -0,0 +1,56 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + COMX-35 F&M EPROM Card emulation + +**********************************************************************/ + +#pragma once + +#ifndef __COMX_EPR__ +#define __COMX_EPR__ + +#include "emu.h" +#include "exp.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> comx_epr_device + +class comx_epr_device : public device_t, + public device_comx_expansion_card_interface +{ +public: + // construction/destruction + comx_epr_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_comx_expansion_card_interface overrides + virtual UINT8 comx_mrd_r(address_space &space, offs_t offset, int *extrom); + virtual void comx_io_w(address_space &space, offs_t offset, UINT8 data); + +private: + required_memory_region m_rom; + required_memory_region m_eprom; + + UINT8 m_select; +}; + + +// device type definition +extern const device_type COMX_EPR; + + +#endif diff --git a/src/devices/bus/comx35/exp.c b/src/devices/bus/comx35/exp.c new file mode 100644 index 00000000000..b0ff7aa77c3 --- /dev/null +++ b/src/devices/bus/comx35/exp.c @@ -0,0 +1,187 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + COMX-35 Expansion Slot emulation + +**********************************************************************/ + +#include "exp.h" + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type COMX_EXPANSION_SLOT = &device_creator; + + + +//************************************************************************** +// DEVICE COMX_EXPANSION CARD INTERFACE +//************************************************************************** + +//------------------------------------------------- +// device_comx_expansion_card_interface - constructor +//------------------------------------------------- + +device_comx_expansion_card_interface::device_comx_expansion_card_interface(const machine_config &mconfig, device_t &device) : + device_slot_card_interface(mconfig, device), + m_ds(1) +{ + m_slot = dynamic_cast(device.owner()); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// comx_expansion_slot_device - constructor +//------------------------------------------------- + +comx_expansion_slot_device::comx_expansion_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, COMX_EXPANSION_SLOT, "COMX-35 expansion slot", tag, owner, clock, "comx_expansion_slot", __FILE__), + device_slot_interface(mconfig, *this), + m_write_irq(*this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void comx_expansion_slot_device::device_start() +{ + m_card = dynamic_cast(get_card_device()); + + // resolve callbacks + m_write_irq.resolve_safe(); +} + + +//------------------------------------------------- +// mrd_r - memory read +//------------------------------------------------- + +UINT8 comx_expansion_slot_device::mrd_r(address_space &space, offs_t offset, int *extrom) +{ + UINT8 data = 0; + + if (m_card != NULL) + { + data = m_card->comx_mrd_r(space, offset, extrom); + } + + return data; +} + + +//------------------------------------------------- +// mwr_w - memory write +//------------------------------------------------- + +void comx_expansion_slot_device::mwr_w(address_space &space, offs_t offset, UINT8 data) +{ + if (m_card != NULL) + { + m_card->comx_mwr_w(space, offset, data); + } +} + + +//------------------------------------------------- +// io_r - I/O read +//------------------------------------------------- + +UINT8 comx_expansion_slot_device::io_r(address_space &space, offs_t offset) +{ + UINT8 data = 0; + + if (m_card != NULL) + { + data = m_card->comx_io_r(space, offset); + } + + return data; +} + + +//------------------------------------------------- +// sout_w - I/O write +//------------------------------------------------- + +void comx_expansion_slot_device::io_w(address_space &space, offs_t offset, UINT8 data) +{ + if (m_card != NULL) + { + m_card->comx_io_w(space, offset, data); + } +} + + +//------------------------------------------------- +// ds_w - device select write +//------------------------------------------------- + +WRITE_LINE_MEMBER( comx_expansion_slot_device::ds_w ) +{ + if (m_card != NULL) + { + m_card->comx_ds_w(state); + } +} + + +//------------------------------------------------- +// q_w - Q write +//------------------------------------------------- + +WRITE_LINE_MEMBER( comx_expansion_slot_device::q_w ) +{ + if (m_card != NULL) + { + m_card->comx_q_w(state); + } +} + +READ_LINE_MEMBER( comx_expansion_slot_device::ef4_r ) +{ + int state = CLEAR_LINE; + + if (m_card != NULL) + { + state = m_card->comx_ef4_r(); + } + + return state; +} + + +//------------------------------------------------- +// SLOT_INTERFACE( comx_expansion_cards ) +//------------------------------------------------- + +// slot devices +#include "clm.h" +#include "eprom.h" +#include "expbox.h" +#include "fdc.h" +#include "joycard.h" +#include "printer.h" +#include "ram.h" +#include "thermal.h" + +SLOT_INTERFACE_START( comx_expansion_cards ) + SLOT_INTERFACE("eb", COMX_EB) + SLOT_INTERFACE("fd", COMX_FD) + SLOT_INTERFACE("clm", COMX_CLM) + SLOT_INTERFACE("ram", COMX_RAM) + SLOT_INTERFACE("joy", COMX_JOY) + SLOT_INTERFACE("prn", COMX_PRN) + SLOT_INTERFACE("thm", COMX_THM) + SLOT_INTERFACE("epr", COMX_EPR) +SLOT_INTERFACE_END diff --git a/src/devices/bus/comx35/exp.h b/src/devices/bus/comx35/exp.h new file mode 100644 index 00000000000..df4f7fffb68 --- /dev/null +++ b/src/devices/bus/comx35/exp.h @@ -0,0 +1,145 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + COMX-35 Expansion Slot emulation + +********************************************************************** + + GND 1 A GND + NC 2 B DS + +5V 3 C V+ + D0 4 D D1 + D2 5 E D3 + D4 6 F D5 + D6 7 H D7 + _DP 8 J Q + _CLEAR 9 K _MRD + TPA 10 L N0 + N1 11 M N2 + _RAS 12 N _INT + _WAIT 13 P CLOCK + SC1 14 R SC0 + _EF4 15 S _CASE + TPB 16 T _A15 + _MWR 17 U A14 + MA7 18 V _A14 + MA5 19 W MA6 + MA4 20 X MA3 + MA2 21 Y _EXTROM + MA1 22 Z MA0 + +**********************************************************************/ + +#pragma once + +#ifndef __COMX35_EXPANSION_SLOT__ +#define __COMX35_EXPANSION_SLOT__ + +#include "emu.h" + + + +//************************************************************************** +// CONSTANTS +//************************************************************************** + +#define COMX_EXPANSION_BUS_TAG "comxexp" + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_COMX_EXPANSION_SLOT_ADD(_tag, _slot_intf, _def_slot) \ + MCFG_DEVICE_ADD(_tag, COMX_EXPANSION_SLOT, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) + + +#define MCFG_COMX_EXPANSION_SLOT_IRQ_CALLBACK(_write) \ + devcb = &comx_expansion_slot_device::set_irq_wr_callback(*device, DEVCB_##_write); + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> comx_expansion_slot_device + +class device_comx_expansion_card_interface; + +class comx_expansion_slot_device : public device_t, + public device_slot_interface +{ +public: + // construction/destruction + comx_expansion_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual ~comx_expansion_slot_device() { } + + template static devcb_base &set_irq_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_irq.set_callback(object); } + + UINT8 mrd_r(address_space &space, offs_t offset, int *extrom); + void mwr_w(address_space &space, offs_t offset, UINT8 data); + + UINT8 io_r(address_space &space, offs_t offset); + void io_w(address_space &space, offs_t offset, UINT8 data); + + DECLARE_READ_LINE_MEMBER( ef4_r ); + + DECLARE_WRITE_LINE_MEMBER( ds_w ); + DECLARE_WRITE_LINE_MEMBER( q_w ); + + DECLARE_WRITE_LINE_MEMBER( irq_w ) { m_write_irq(state); } + +protected: + // device-level overrides + virtual void device_start(); + + devcb_write_line m_write_irq; + + device_comx_expansion_card_interface *m_card; +}; + + +// ======================> device_comx_expansion_card_interface + +// class representing interface-specific live comx_expansion card +class device_comx_expansion_card_interface : public device_slot_card_interface +{ + friend class comx_expansion_slot_device; + +public: + // construction/destruction + device_comx_expansion_card_interface(const machine_config &mconfig, device_t &device); + virtual ~device_comx_expansion_card_interface() { } + +protected: + // signals + virtual int comx_ef4_r() { return CLEAR_LINE; } + virtual void comx_ds_w(int state) { m_ds = state; }; + virtual void comx_q_w(int state) { }; + + // memory access + virtual UINT8 comx_mrd_r(address_space &space, offs_t offset, int *extrom) { return 0; }; + virtual void comx_mwr_w(address_space &space, offs_t offset, UINT8 data) { }; + + // I/O access + virtual UINT8 comx_io_r(address_space &space, offs_t offset) { return 0; }; + virtual void comx_io_w(address_space &space, offs_t offset, UINT8 data) { }; + + comx_expansion_slot_device *m_slot; + + int m_ds; +}; + + +// device type definition +extern const device_type COMX_EXPANSION_SLOT; + + +SLOT_INTERFACE_EXTERN( comx_expansion_cards ); + + +#endif diff --git a/src/devices/bus/comx35/expbox.c b/src/devices/bus/comx35/expbox.c new file mode 100644 index 00000000000..7e4e9799e29 --- /dev/null +++ b/src/devices/bus/comx35/expbox.c @@ -0,0 +1,306 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + COMX-35E Expansion Box emulation + +**********************************************************************/ + +/* + +(c) 1984 Comx World Operations + +PCB Layout +---------- + +F-001-EB-REV0 + + |--------------------------------------| + | 40174 4073 4049 4075 | + | | + | ROM 40175 4073 4075 | + | | +|----| - - - - | +| | | | | 7805 | +| | | | | | +| | | | | | +|C C C C C | +|N N N N N | +|5 1 2 3 4 | +| | | | | | +| | | | | | +| | | | | | +| - - - LD1 - | +|-------------------------------------------| + +Notes: + All IC's shown. + + ROM - NEC D2732D-4 4Kx8 EPROM, unlabeled + CN1 - COMX-35 bus connector slot 1 + CN2 - COMX-35 bus connector slot 2 + CN3 - COMX-35 bus connector slot 3 + CN4 - COMX-35 bus connector slot 4 + CN5 - COMX-35 bus PCB edge connector + LD1 - LED + +*/ + +#include "expbox.h" + + + +//************************************************************************** +// MACROS/CONSTANTS +//************************************************************************** + +#define SLOT1_TAG "slot1" +#define SLOT2_TAG "slot2" +#define SLOT3_TAG "slot3" +#define SLOT4_TAG "slot4" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type COMX_EB = &device_creator; + + +//------------------------------------------------- +// ROM( comx_eb ) +//------------------------------------------------- + +ROM_START( comx_eb ) + ROM_REGION( 0x1000, "e000", 0 ) + ROM_SYSTEM_BIOS( 0, "comx", "Original" ) + ROMX_LOAD( "expansion.e5", 0x0000, 0x1000, CRC(52cb44e2) SHA1(3f9a3d9940b36d4fee5eca9f1359c99d7ed545b9), ROM_BIOS(1) ) + ROM_SYSTEM_BIOS( 1, "fm31", "F&M 3.1" ) + ROMX_LOAD( "f&m.expansion.3.1.e5", 0x0000, 0x1000, CRC(818ca2ef) SHA1(ea000097622e7fd472d53e7899e3c83773433045), ROM_BIOS(2) ) + ROM_SYSTEM_BIOS( 2, "fm32", "F&M 3.2" ) + ROMX_LOAD( "f&m.expansion.3.2.e5", 0x0000, 0x1000, CRC(0f0fc960) SHA1(eb6b6e7bc9e761d13554482025d8cb5e260c0619), ROM_BIOS(3) ) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *comx_eb_device::device_rom_region() const +{ + return ROM_NAME( comx_eb ); +} + + +//------------------------------------------------- +// MACHINE_CONFIG_FRAGMENT( comx_eb ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( comx_eb ) + MCFG_COMX_EXPANSION_SLOT_ADD(SLOT1_TAG, comx_expansion_cards, "fd") + MCFG_COMX_EXPANSION_SLOT_IRQ_CALLBACK(WRITELINE(comx_eb_device, slot1_irq_w)) + MCFG_COMX_EXPANSION_SLOT_ADD(SLOT2_TAG, comx_expansion_cards, "clm") + MCFG_COMX_EXPANSION_SLOT_IRQ_CALLBACK(WRITELINE(comx_eb_device, slot2_irq_w)) + MCFG_COMX_EXPANSION_SLOT_ADD(SLOT3_TAG, comx_expansion_cards, "joy") + MCFG_COMX_EXPANSION_SLOT_IRQ_CALLBACK(WRITELINE(comx_eb_device, slot3_irq_w)) + MCFG_COMX_EXPANSION_SLOT_ADD(SLOT4_TAG, comx_expansion_cards, "ram") + MCFG_COMX_EXPANSION_SLOT_IRQ_CALLBACK(WRITELINE(comx_eb_device, slot4_irq_w)) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor comx_eb_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( comx_eb ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// comx_eb_device - constructor +//------------------------------------------------- + +comx_eb_device::comx_eb_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, COMX_EB, "COMX-35E Expansion Box", tag, owner, clock, "comx_eb", __FILE__), + device_comx_expansion_card_interface(mconfig, *this), + m_rom(*this, "e000"), + m_select(0) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void comx_eb_device::device_start() +{ + m_expansion_slot[0] = dynamic_cast(subdevice(SLOT1_TAG)); + m_expansion_slot[1] = dynamic_cast(subdevice(SLOT2_TAG)); + m_expansion_slot[2] = dynamic_cast(subdevice(SLOT3_TAG)); + m_expansion_slot[3] = dynamic_cast(subdevice(SLOT4_TAG)); + + for (int slot = 0; slot < MAX_EB_SLOTS; slot++) + { + m_irq[slot] = CLEAR_LINE; + } +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void comx_eb_device::device_reset() +{ + for (int slot = 0; slot < MAX_EB_SLOTS; slot++) + { + if (m_expansion_slot[slot] != NULL) + { + m_expansion_slot[slot]->device().reset(); + m_expansion_slot[slot]->ds_w(0); + } + } +} + + +//------------------------------------------------- +// comx_ef4_r - external flag 4 read +//------------------------------------------------- + +int comx_eb_device::comx_ef4_r() +{ + int state = CLEAR_LINE; + + for (int slot = 0; slot < MAX_EB_SLOTS; slot++) + { + if (m_expansion_slot[slot] != NULL) + { + state |= m_expansion_slot[slot]->ef4_r(); + } + } + + return state; +} + + +//------------------------------------------------- +// comx_q_w - Q write +//------------------------------------------------- + +void comx_eb_device::comx_q_w(int state) +{ + for (int slot = 0; slot < MAX_EB_SLOTS; slot++) + { + if (m_expansion_slot[slot] != NULL) + { + m_expansion_slot[slot]->q_w(state); + } + } +} + + +//------------------------------------------------- +// comx_mrd_r - memory read +//------------------------------------------------- + +UINT8 comx_eb_device::comx_mrd_r(address_space &space, offs_t offset, int *extrom) +{ + UINT8 data = 0; + + if (offset >= 0x1000 && offset < 0x1800) + { + data = m_rom->base()[offset & 0x7ff]; + *extrom = 0; + } + else if (offset >= 0xe000 && offset < 0xf000) + { + data = m_rom->base()[offset & 0xfff]; + } + else + { + for (int slot = 0; slot < MAX_EB_SLOTS; slot++) + { + if (BIT(m_select, slot) && m_expansion_slot[slot] != NULL) + { + data |= m_expansion_slot[slot]->mrd_r(space, offset, extrom); + } + } + } + + return data; +} + + +//------------------------------------------------- +// comx_mwr_w - memory write +//------------------------------------------------- + +void comx_eb_device::comx_mwr_w(address_space &space, offs_t offset, UINT8 data) +{ + for (int slot = 0; slot < MAX_EB_SLOTS; slot++) + { + if (BIT(m_select, slot) && m_expansion_slot[slot] != NULL) + { + m_expansion_slot[slot]->mwr_w(space, offset, data); + } + } +} + + +//------------------------------------------------- +// comx_io_r - I/O read +//------------------------------------------------- + +UINT8 comx_eb_device::comx_io_r(address_space &space, offs_t offset) +{ + UINT8 data = 0; + + for (int slot = 0; slot < MAX_EB_SLOTS; slot++) + { + if (BIT(m_select, slot) && m_expansion_slot[slot] != NULL) + { + data |= m_expansion_slot[slot]->io_r(space, offset); + } + } + + return data; +} + + +//------------------------------------------------- +// comx_io_w - I/O write +//------------------------------------------------- + +void comx_eb_device::comx_io_w(address_space &space, offs_t offset, UINT8 data) +{ + if (offset == 1 && !(BIT(data, 0))) + { + m_select = data >> 1; + + for (int slot = 0; slot < MAX_EB_SLOTS; slot++) + { + if (m_expansion_slot[slot] != NULL) + { + m_expansion_slot[slot]->ds_w(BIT(m_select, slot)); + } + } + } + + for (int slot = 0; slot < MAX_EB_SLOTS; slot++) + { + if (BIT(m_select, slot) && m_expansion_slot[slot] != NULL) + { + m_expansion_slot[slot]->io_w(space, offset, data); + } + } +} diff --git a/src/devices/bus/comx35/expbox.h b/src/devices/bus/comx35/expbox.h new file mode 100644 index 00000000000..6863f2c1339 --- /dev/null +++ b/src/devices/bus/comx35/expbox.h @@ -0,0 +1,77 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + COMX-35E Expansion Box emulation + +**********************************************************************/ + +#pragma once + +#ifndef __COMX_EB__ +#define __COMX_EB__ + +#include "exp.h" + + + +//************************************************************************** +// CONSTANTS +//************************************************************************** + +#define MAX_EB_SLOTS 4 + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> comx_eb_device + +class comx_eb_device : public device_t, + public device_comx_expansion_card_interface +{ +public: + // construction/destruction + comx_eb_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + DECLARE_WRITE_LINE_MEMBER( slot1_irq_w ) { m_irq[0] = state; set_irq(); } + DECLARE_WRITE_LINE_MEMBER( slot2_irq_w ) { m_irq[1] = state; set_irq(); } + DECLARE_WRITE_LINE_MEMBER( slot3_irq_w ) { m_irq[2] = state; set_irq(); } + DECLARE_WRITE_LINE_MEMBER( slot4_irq_w ) { m_irq[3] = state; set_irq(); } + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + + // device_comx_expansion_card_interface overrides + virtual int comx_ef4_r(); + virtual void comx_q_w(int state); + virtual UINT8 comx_mrd_r(address_space &space, offs_t offset, int *extrom); + virtual void comx_mwr_w(address_space &space, offs_t offset, UINT8 data); + virtual UINT8 comx_io_r(address_space &space, offs_t offset); + virtual void comx_io_w(address_space &space, offs_t offset, UINT8 data); + + void set_irq() { m_slot->irq_w(m_irq[0] || m_irq[1] || m_irq[2] || m_irq[3]); } + +private: + required_memory_region m_rom; + + comx_expansion_slot_device *m_expansion_slot[MAX_EB_SLOTS]; + int m_irq[MAX_EB_SLOTS]; + + UINT8 m_select; +}; + + +// device type definition +extern const device_type COMX_EB; + + +#endif diff --git a/src/devices/bus/comx35/fdc.c b/src/devices/bus/comx35/fdc.c new file mode 100644 index 00000000000..0c83d5bed29 --- /dev/null +++ b/src/devices/bus/comx35/fdc.c @@ -0,0 +1,286 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + COMX-35 Disk Controller Card emulation + +**********************************************************************/ + +/* + +(c) 1984 Comx World Operations + +PCB Layout +---------- + +F-001-FD-REV0 + + |---------------| + | CN1 | +|---| |---------------------------| +| | +| 40174 4068 4072 -| +| ROM || +| LS04 4072 4050 7438 C| +|8MHz N| +| 4049 4075 LS08 2| +|LD1 WD1770 || +| 40174 4503 4075 7438 -| +|LD2 | +|-----------------------------------------------| + +Notes: + All IC's shown. + + ROM - "D.O.S. V1.2" + WD1770 - Western Digital WD1770-xx Floppy Disc Controller @ 8MHz + CN1 - COMX-35 bus PCB edge connector + CN2 - 34 pin floppy connector + LD1 - card selected LED + LD2 - floppy motor on LED + +*/ + +#include "fdc.h" + + + +//************************************************************************** +// MACROS/CONSTANTS +//************************************************************************** + +#define WD1770_TAG "wd1770" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type COMX_FD = &device_creator; + + +//------------------------------------------------- +// ROM( comx_fd ) +//------------------------------------------------- + +ROM_START( comx_fd ) + ROM_REGION( 0x2000, "c000", 0 ) + ROM_LOAD( "d.o.s. v1.2.f4", 0x0000, 0x2000, CRC(cf4ecd2e) SHA1(290e19bdc89e3c8059e63d5ae3cca4daa194e1fe) ) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *comx_fd_device::device_rom_region() const +{ + return ROM_NAME( comx_fd ); +} + + +FLOPPY_FORMATS_MEMBER( comx_fd_device::floppy_formats ) + FLOPPY_COMX35_FORMAT +FLOPPY_FORMATS_END + +static SLOT_INTERFACE_START( comx_fd_floppies ) + SLOT_INTERFACE( "525sd35t", FLOPPY_525_SD_35T ) + SLOT_INTERFACE( "525qd", FLOPPY_525_QD ) +SLOT_INTERFACE_END + + +//------------------------------------------------- +// MACHINE_CONFIG_FRAGMENT( comx_fd ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( comx_fd ) + MCFG_WD1770_ADD(WD1770_TAG, XTAL_8MHz) + + MCFG_FLOPPY_DRIVE_ADD(WD1770_TAG":0", comx_fd_floppies, "525sd35t", comx_fd_device::floppy_formats) + MCFG_FLOPPY_DRIVE_ADD(WD1770_TAG":1", comx_fd_floppies, NULL, comx_fd_device::floppy_formats) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor comx_fd_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( comx_fd ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// comx_fd_device - constructor +//------------------------------------------------- + +comx_fd_device::comx_fd_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, COMX_FD, "COMX FD", tag, owner, clock, "comx_fd", __FILE__), + device_comx_expansion_card_interface(mconfig, *this), + m_fdc(*this, WD1770_TAG), + m_floppy0(*this, WD1770_TAG":0"), + m_floppy1(*this, WD1770_TAG":1"), + m_rom(*this, "c000"), + m_q(0), + m_addr(0), + m_disb(1) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void comx_fd_device::device_start() +{ + // state saving + save_item(NAME(m_ds)); + save_item(NAME(m_q)); + save_item(NAME(m_addr)); + save_item(NAME(m_disb)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void comx_fd_device::device_reset() +{ + m_fdc->reset(); + m_fdc->dden_w(1); + m_fdc->set_floppy(NULL); + + m_addr = 0; + m_disb = 1; +} + + +//------------------------------------------------- +// comx_ef4_r - external flag 4 read +//------------------------------------------------- + +int comx_fd_device::comx_ef4_r() +{ + int state = CLEAR_LINE; + + if (m_ds && !m_disb) + { + state = !m_fdc->drq_r(); + } + + return state; +} + + +//------------------------------------------------- +// comx_q_w - Q write +//------------------------------------------------- + +void comx_fd_device::comx_q_w(int state) +{ + m_q = state; +} + + +//------------------------------------------------- +// comx_mrd_r - memory read +//------------------------------------------------- + +UINT8 comx_fd_device::comx_mrd_r(address_space &space, offs_t offset, int *extrom) +{ + UINT8 data = 0xff; + + if (offset >= 0x0dd0 && offset < 0x0de0) + { + data = m_rom->base()[offset & 0x1fff]; + *extrom = 0; + } + else if (offset >= 0xc000 && offset < 0xe000) + { + data = m_rom->base()[offset & 0x1fff]; + } + + return data; +} + + +//------------------------------------------------- +// comx_io_r - I/O read +//------------------------------------------------- + +UINT8 comx_fd_device::comx_io_r(address_space &space, offs_t offset) +{ + UINT8 data = 0xff; + + if (offset == 2) + { + if (m_q) + { + data = 0xfe | (m_fdc->intrq_r() ? 1 : 0); + } + else + { + data = m_fdc->gen_r(m_addr); + if (m_addr==3) logerror("%s FDC read %u:%02x\n", machine().describe_context(), m_addr,data); + } + } + + return data; +} + + +//------------------------------------------------- +// comx_io_w - I/O write +//------------------------------------------------- + +void comx_fd_device::comx_io_w(address_space &space, offs_t offset, UINT8 data) +{ + if (offset == 2) + { + if (m_q) + { + /* + + bit description + + 0 FDC A0 + 1 FDC A1 + 2 DRIVE0 + 3 DRIVE1 + 4 F9 DISB + 5 SIDE SELECT + + */ + + // latch data to F3 + m_addr = data & 0x03; + + // drive select + floppy_image_device *floppy = NULL; + + if (BIT(data, 2)) floppy = m_floppy0->get_device(); + if (BIT(data, 3)) floppy = m_floppy1->get_device(); + + m_fdc->set_floppy(floppy); + + if (floppy) floppy->ss_w(BIT(data, 5)); + + m_disb = !BIT(data, 4); + } + else + { + // write data to WD1770 + m_fdc->gen_w(m_addr, data); + } + } +} diff --git a/src/devices/bus/comx35/fdc.h b/src/devices/bus/comx35/fdc.h new file mode 100644 index 00000000000..ce1a71c46a2 --- /dev/null +++ b/src/devices/bus/comx35/fdc.h @@ -0,0 +1,70 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + COMX-35 Disk Controller Card emulation + +**********************************************************************/ + +#pragma once + +#ifndef __COMX_FD__ +#define __COMX_FD__ + +#include "emu.h" +#include "exp.h" +#include "formats/comx35_dsk.h" +#include "machine/wd_fdc.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> comx_fd_device + +class comx_fd_device : public device_t, + public device_comx_expansion_card_interface +{ +public: + // construction/destruction + comx_fd_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + + DECLARE_FLOPPY_FORMATS( floppy_formats ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_comx_expansion_card_interface overrides + virtual int comx_ef4_r(); + virtual void comx_q_w(int state); + virtual UINT8 comx_mrd_r(address_space &space, offs_t offset, int *extrom); + virtual UINT8 comx_io_r(address_space &space, offs_t offset); + virtual void comx_io_w(address_space &space, offs_t offset, UINT8 data); + +private: + // internal state + required_device m_fdc; + required_device m_floppy0; + required_device m_floppy1; + required_memory_region m_rom; + + // floppy state + int m_q; // FDC register select + int m_addr; // FDC address + int m_disb; // data request disable +}; + + +// device type definition +extern const device_type COMX_FD; + + +#endif diff --git a/src/devices/bus/comx35/joycard.c b/src/devices/bus/comx35/joycard.c new file mode 100644 index 00000000000..2408693f1b8 --- /dev/null +++ b/src/devices/bus/comx35/joycard.c @@ -0,0 +1,114 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + COMX-35 F&M Joycard emulation + +**********************************************************************/ + +#include "joycard.h" + + + +//************************************************************************** +// MACROS/CONSTANTS +//************************************************************************** + + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type COMX_JOY = &device_creator; + + +//------------------------------------------------- +// INPUT_PORTS( comx_joy ) +//------------------------------------------------- + +static INPUT_PORTS_START( comx_joy ) + PORT_START("JOY1") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP ) PORT_PLAYER(1) PORT_8WAY + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN ) PORT_PLAYER(1) PORT_8WAY + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT ) PORT_PLAYER(1) PORT_8WAY + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(1) PORT_8WAY + PORT_BIT( 0xf0, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("JOY2") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP ) PORT_PLAYER(2) PORT_8WAY + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN ) PORT_PLAYER(2) PORT_8WAY + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT ) PORT_PLAYER(2) PORT_8WAY + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(2) PORT_8WAY + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_PLAYER(1) + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_PLAYER(2) + PORT_BIT( 0xc0, IP_ACTIVE_HIGH, IPT_UNUSED ) +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor comx_joy_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( comx_joy ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// comx_joy_device - constructor +//------------------------------------------------- + +comx_joy_device::comx_joy_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, COMX_JOY, "COMX JoyCard", tag, owner, clock, "comx_joy", __FILE__), + device_comx_expansion_card_interface(mconfig, *this), + m_joy1(*this, "JOY1"), + m_joy2(*this, "JOY2") +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void comx_joy_device::device_start() +{ +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void comx_joy_device::device_reset() +{ +} + + +//------------------------------------------------- +// comx_mrd_r - I/O read +//------------------------------------------------- + +UINT8 comx_joy_device::comx_io_r(address_space &space, offs_t offset) +{ + UINT8 data = 0; + + if (offset == 2) + { + data = m_joy1->read(); + } + else if (offset == 4) + { + data = m_joy2->read(); + } + + return data; +} diff --git a/src/devices/bus/comx35/joycard.h b/src/devices/bus/comx35/joycard.h new file mode 100644 index 00000000000..be7bd63e528 --- /dev/null +++ b/src/devices/bus/comx35/joycard.h @@ -0,0 +1,53 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + COMX-35 F&M Joycard emulation + +**********************************************************************/ + +#pragma once + +#ifndef __COMX_JOY__ +#define __COMX_JOY__ + +#include "emu.h" +#include "exp.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> comx_joy_device + +class comx_joy_device : public device_t, + public device_comx_expansion_card_interface +{ +public: + // construction/destruction + comx_joy_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual ioport_constructor device_input_ports() const; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_comx_expansion_card_interface overrides + virtual UINT8 comx_io_r(address_space &space, offs_t offset); + +private: + required_ioport m_joy1; + required_ioport m_joy2; +}; + + +// device type definition +extern const device_type COMX_JOY; + + +#endif diff --git a/src/devices/bus/comx35/printer.c b/src/devices/bus/comx35/printer.c new file mode 100644 index 00000000000..2f36fffd9bd --- /dev/null +++ b/src/devices/bus/comx35/printer.c @@ -0,0 +1,191 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + COMX-35 Serial/Parallel Printer Card emulation + +**********************************************************************/ + +#include "printer.h" +#include "bus/centronics/printer.h" + + + +//************************************************************************** +// MACROS/CONSTANTS +//************************************************************************** + +#define CENTRONICS_TAG "centronics" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type COMX_PRN = &device_creator; + + +//------------------------------------------------- +// ROM( comx_prn ) +//------------------------------------------------- + +ROM_START( comx_prn ) + ROM_REGION( 0x2000, "c000", 0 ) + ROM_SYSTEM_BIOS( 0, "comx", "COMX" ) + ROMX_LOAD( "printer.bin", 0x0000, 0x0800, CRC(3bbc2b2e) SHA1(08bf7ea4174713ab24969c553affd5c1401876b8), ROM_BIOS(1) ) + ROM_SYSTEM_BIOS( 1, "fm12", "F&M v1.2" ) + ROMX_LOAD( "f&m.printer.1.2.bin", 0x0000, 0x1000, CRC(2feb997d) SHA1(ee9cb91042696c88ff5f2f44d2f702dc93369ba0), ROM_BIOS(2) ) + ROM_LOAD( "rs232.bin", 0x1000, 0x0800, CRC(926ff2d1) SHA1(be02bd388bba0211ea72d4868264a63308e4318d) ) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *comx_prn_device::device_rom_region() const +{ + return ROM_NAME( comx_prn ); +} + + +//------------------------------------------------- +// MACHINE_CONFIG_FRAGMENT( comx_prn ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( comx_prn ) + MCFG_CENTRONICS_ADD(CENTRONICS_TAG, centronics_devices, "printer") + MCFG_CENTRONICS_ACK_HANDLER(DEVWRITELINE("cent_status_in", input_buffer_device, write_bit0)) + MCFG_CENTRONICS_BUSY_HANDLER(DEVWRITELINE("cent_status_in", input_buffer_device, write_bit1)) + MCFG_CENTRONICS_PERROR_HANDLER(DEVWRITELINE("cent_status_in", input_buffer_device, write_bit2)) + MCFG_CENTRONICS_SELECT_HANDLER(DEVWRITELINE("cent_status_in", input_buffer_device, write_bit3)) + MCFG_CENTRONICS_OUTPUT_LATCH_ADD("cent_data_out", "centronics") + + MCFG_DEVICE_ADD("cent_status_in", INPUT_BUFFER, 0) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor comx_prn_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( comx_prn ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// comx_prn_device - constructor +//------------------------------------------------- + +comx_prn_device::comx_prn_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, COMX_PRN, "COMX-35 Printer Card", tag, owner, clock, "comx_prn", __FILE__), + device_comx_expansion_card_interface(mconfig, *this), + m_centronics(*this, CENTRONICS_TAG), + m_cent_data_out(*this, "cent_data_out"), + m_cent_status_in(*this, "cent_status_in"), + m_rom(*this, "c000") +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void comx_prn_device::device_start() +{ +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void comx_prn_device::device_reset() +{ +} + + +//------------------------------------------------- +// comx_mrd_r - memory read +//------------------------------------------------- + +UINT8 comx_prn_device::comx_mrd_r(address_space &space, offs_t offset, int *extrom) +{ + UINT8 data = 0; + + if (offset >= 0xc000 && offset < 0xe000) + { + data = m_rom->base()[offset & 0x1fff]; + } + + return data; +} + + +//------------------------------------------------- +// comx_io_r - I/O read +//------------------------------------------------- + +UINT8 comx_prn_device::comx_io_r(address_space &space, offs_t offset) +{ + /* + Parallel: + + INP 2 for the printer status, where: + b0=1: Acknowledge Fault + b1=0: Device Busy + b2=0: Paper Empty + b3=1: Device Not Selected + + Serial: + + INP 2 for the printer status and to start a new range of bits for the next byte. + */ + + /* + + bit description + + 0 Acknowledge Fault + 1 Device Busy + 2 Paper Empty + 3 Device Not Selected + 4 + 5 + 6 + 7 + + */ + + return m_cent_status_in->read(); +} + + +//------------------------------------------------- +// comx_io_w - I/O write +//------------------------------------------------- + +void comx_prn_device::comx_io_w(address_space &space, offs_t offset, UINT8 data) +{ + /* + Parallel: + + OUT 2 is used to send a byte to the printer + + Serial: + + OUT 2 is used to send a bit to the printer + */ + + m_cent_data_out->write(space, 0, data); +} diff --git a/src/devices/bus/comx35/printer.h b/src/devices/bus/comx35/printer.h new file mode 100644 index 00000000000..f67997b19ea --- /dev/null +++ b/src/devices/bus/comx35/printer.h @@ -0,0 +1,60 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + COMX-35 Serial/Parallel Printer Card emulation + +**********************************************************************/ + +#pragma once + +#ifndef __COMX_PRN__ +#define __COMX_PRN__ + +#include "emu.h" +#include "exp.h" +#include "machine/buffer.h" +#include "bus/centronics/ctronics.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> comx_prn_device + +class comx_prn_device : public device_t, + public device_comx_expansion_card_interface +{ +public: + // construction/destruction + comx_prn_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_comx_expansion_card_interface overrides + virtual UINT8 comx_mrd_r(address_space &space, offs_t offset, int *extrom); + virtual UINT8 comx_io_r(address_space &space, offs_t offset); + virtual void comx_io_w(address_space &space, offs_t offset, UINT8 data); + +private: + required_device m_centronics; + required_device m_cent_data_out; + required_device m_cent_status_in; + required_memory_region m_rom; +}; + + +// device type definition +extern const device_type COMX_PRN; + + +#endif diff --git a/src/devices/bus/comx35/ram.c b/src/devices/bus/comx35/ram.c new file mode 100644 index 00000000000..0a2caafa1da --- /dev/null +++ b/src/devices/bus/comx35/ram.c @@ -0,0 +1,103 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + COMX-35 RAM Card emulation + +**********************************************************************/ + +#include "ram.h" + + + +//************************************************************************** +// MACROS/CONSTANTS +//************************************************************************** + +#define RAM_SIZE 0x8000 + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type COMX_RAM = &device_creator; + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// comx_ram_device - constructor +//------------------------------------------------- + +comx_ram_device::comx_ram_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, COMX_RAM, "COMX-35 RAM Card", tag, owner, clock, "comx_ram", __FILE__), + device_comx_expansion_card_interface(mconfig, *this), + m_ram(*this, "ram") +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void comx_ram_device::device_start() +{ + m_ram.allocate(RAM_SIZE); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void comx_ram_device::device_reset() +{ +} + + +//------------------------------------------------- +// comx_mrd_r - memory read +//------------------------------------------------- + +UINT8 comx_ram_device::comx_mrd_r(address_space &space, offs_t offset, int *extrom) +{ + UINT8 data = 0; + + if (offset >= 0xc000 && offset < 0xd000) + { + data = m_ram[(m_bank << 12) | (offset & 0xfff)]; + } + + return data; +} + + +//------------------------------------------------- +// comx_mwr_w - memory write +//------------------------------------------------- + +void comx_ram_device::comx_mwr_w(address_space &space, offs_t offset, UINT8 data) +{ + if (offset >= 0xc000 && offset < 0xd000) + { + m_ram[(m_bank << 12) | (offset & 0xfff)] = data; + } +} + + +//------------------------------------------------- +// comx_io_w - I/O write +//------------------------------------------------- + +void comx_ram_device::comx_io_w(address_space &space, offs_t offset, UINT8 data) +{ + if (offset == 1) + { + m_bank = (data >> 4) & 0x03; + } +} diff --git a/src/devices/bus/comx35/ram.h b/src/devices/bus/comx35/ram.h new file mode 100644 index 00000000000..3618d6e2b4b --- /dev/null +++ b/src/devices/bus/comx35/ram.h @@ -0,0 +1,53 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + COMX-35 RAM Card emulation + +**********************************************************************/ + +#pragma once + +#ifndef __COMX_RAM__ +#define __COMX_RAM__ + +#include "emu.h" +#include "exp.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> comx_ram_device + +class comx_ram_device : public device_t, + public device_comx_expansion_card_interface +{ +public: + // construction/destruction + comx_ram_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_comx_expansion_card_interface overrides + virtual UINT8 comx_mrd_r(address_space &space, offs_t offset, int *extrom); + virtual void comx_mwr_w(address_space &space, offs_t offset, UINT8 data); + virtual void comx_io_w(address_space &space, offs_t offset, UINT8 data); + +private: + optional_shared_ptr m_ram; + + int m_bank; +}; + + +// device type definition +extern const device_type COMX_RAM; + + +#endif diff --git a/src/devices/bus/comx35/thermal.c b/src/devices/bus/comx35/thermal.c new file mode 100644 index 00000000000..e74b62978d6 --- /dev/null +++ b/src/devices/bus/comx35/thermal.c @@ -0,0 +1,127 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + COMX-35 Thermal Printer Card emulation + +**********************************************************************/ + +#include "thermal.h" + + + +//************************************************************************** +// MACROS/CONSTANTS +//************************************************************************** + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type COMX_THM = &device_creator; + + +//------------------------------------------------- +// ROM( comx_thm ) +//------------------------------------------------- + +ROM_START( comx_thm ) + ROM_REGION( 0x2000, "c000", 0 ) + ROM_LOAD( "thermal.bin", 0x0000, 0x1000, CRC(41a72ba8) SHA1(3a8760c78bd8c7bec2dbf26657b930c9a6814803) ) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *comx_thm_device::device_rom_region() const +{ + return ROM_NAME( comx_thm ); +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// comx_thm_device - constructor +//------------------------------------------------- + +comx_thm_device::comx_thm_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, COMX_THM, "COMX-35 Thermal Printer Card", tag, owner, clock, "comx_thm", __FILE__), + device_comx_expansion_card_interface(mconfig, *this), + m_rom(*this, "c000") +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void comx_thm_device::device_start() +{ +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void comx_thm_device::device_reset() +{ +} + + +//------------------------------------------------- +// comx_mrd_r - memory read +//------------------------------------------------- + +UINT8 comx_thm_device::comx_mrd_r(address_space &space, offs_t offset, int *extrom) +{ + UINT8 data = 0; + + if (offset >= 0xc000 && offset < 0xd000) + { + data = m_rom->base()[offset & 0xfff]; + } + + return data; +} + + +//------------------------------------------------- +// comx_io_r - I/O read +//------------------------------------------------- + +UINT8 comx_thm_device::comx_io_r(address_space &space, offs_t offset) +{ + /* + INP 2 is used for the printer status, where: + b0=1: Printer Not Ready + b1=1: Energizing Head + b2=1: Head At Position 0 + */ + + return 0; +} + + +//------------------------------------------------- +// comx_io_w - I/O write +//------------------------------------------------- + +void comx_thm_device::comx_io_w(address_space &space, offs_t offset, UINT8 data) +{ + /* + OUT 2 is used to control the thermal printer where: + Q = 0, b0-7: Pixel 1 to 8 + Q = 1, b7: Pixel 9 (if b0-6=#21) + Q = 1, b3=1: Move head right + Q = 1, b0-7=#12: Move head left + */ +} diff --git a/src/devices/bus/comx35/thermal.h b/src/devices/bus/comx35/thermal.h new file mode 100644 index 00000000000..8314039301c --- /dev/null +++ b/src/devices/bus/comx35/thermal.h @@ -0,0 +1,54 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + COMX-35 Thermal Printer Card emulation + +**********************************************************************/ + +#pragma once + +#ifndef __COMX_THM__ +#define __COMX_THM__ + +#include "emu.h" +#include "exp.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> comx_thm_device + +class comx_thm_device : public device_t, + public device_comx_expansion_card_interface +{ +public: + // construction/destruction + comx_thm_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_comx_expansion_card_interface overrides + virtual UINT8 comx_mrd_r(address_space &space, offs_t offset, int *extrom); + virtual UINT8 comx_io_r(address_space &space, offs_t offset); + virtual void comx_io_w(address_space &space, offs_t offset, UINT8 data); + +private: + required_memory_region m_rom; +}; + + +// device type definition +extern const device_type COMX_THM; + + +#endif diff --git a/src/devices/bus/cpc/amdrum.c b/src/devices/bus/cpc/amdrum.c new file mode 100644 index 00000000000..8bf9fa8ad34 --- /dev/null +++ b/src/devices/bus/cpc/amdrum.c @@ -0,0 +1,69 @@ +// license:BSD-3-Clause +// copyright-holders:Barry Rodewald +/* + * amdrum.c + * + * Created on: 23/08/2014 + */ + +#include "emu.h" +#include "amdrum.h" +#include "includes/amstrad.h" + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type CPC_AMDRUM = &device_creator; + + +static MACHINE_CONFIG_FRAGMENT( cpc_amdrum ) + MCFG_SPEAKER_STANDARD_MONO("mono") + MCFG_DAC_ADD("dac") + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 1.00) + // no pass-through +MACHINE_CONFIG_END + +machine_config_constructor cpc_amdrum_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( cpc_amdrum ); +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +cpc_amdrum_device::cpc_amdrum_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, CPC_AMDRUM, "Amdrum", tag, owner, clock, "cpc_amdrum", __FILE__), + device_cpc_expansion_card_interface(mconfig, *this), + m_dac(*this,"dac") +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void cpc_amdrum_device::device_start() +{ + device_t* cpu = machine().device("maincpu"); + address_space& space = cpu->memory().space(AS_IO); + m_slot = dynamic_cast(owner()); + + space.install_write_handler(0xff00,0xffff,0,0,write8_delegate(FUNC(cpc_amdrum_device::dac_w),this)); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void cpc_amdrum_device::device_reset() +{ + // TODO +} + +WRITE8_MEMBER(cpc_amdrum_device::dac_w) +{ + m_dac->write_unsigned8(data); +} diff --git a/src/devices/bus/cpc/amdrum.h b/src/devices/bus/cpc/amdrum.h new file mode 100644 index 00000000000..5040e7d4457 --- /dev/null +++ b/src/devices/bus/cpc/amdrum.h @@ -0,0 +1,48 @@ +// license:BSD-3-Clause +// copyright-holders:Barry Rodewald +/* + * amdrum.h + * + * Created on: 23/08/2014 + * + * Cheetah Marketing Amdrum + * + * I/O FFxx - 8-bit unsigned DAC, write only (Ferranti ZN428E-8) + * Lower 8 address bits are not decoded. + * + */ + +#ifndef AMDRUM_H_ +#define AMDRUM_H_ + +#include "emu.h" +#include "cpcexp.h" +#include "sound/dac.h" + +class cpc_amdrum_device : public device_t, + public device_cpc_expansion_card_interface +{ +public: + // construction/destruction + cpc_amdrum_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + + DECLARE_WRITE8_MEMBER(dac_w); +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + +private: + cpc_expansion_slot_device *m_slot; + + required_device m_dac; +}; + +// device type definition +extern const device_type CPC_AMDRUM; + + +#endif /* AMDRUM_H_ */ diff --git a/src/devices/bus/cpc/brunword4.c b/src/devices/bus/cpc/brunword4.c new file mode 100644 index 00000000000..cd3ab420349 --- /dev/null +++ b/src/devices/bus/cpc/brunword4.c @@ -0,0 +1,110 @@ +// license:BSD-3-Clause +// copyright-holders:Barry Rodewald +/* + + Brunword MK4 - Word processor ROM / expansion + + Software is provided as an expansion device, which uses it own ROM mapping + + The ROM select port will be handled by this device, calling back to the standard driver when necessary. + Not enabled for the CPC Plus, as ROM selection wraps after 63, making it impossible to see cartridge + banks in the upper ROM area (0x80-0xff) +*/ + +#include "brunword4.h" + +const device_type CPC_BRUNWORD_MK4 = &device_creator; + + +ROM_START( cpc_brunword4 ) + ROM_REGION( 0xc000, "exp_rom", 0 ) + ROM_LOAD( "brunw-c1.rom", 0x0000, 0x4000, CRC(3200299b) SHA1(d7d5fcacf3c6707a6629b0c65564ac44267d2b49) ) + ROM_LOAD( "brunw-c2.rom", 0x4000, 0x4000, CRC(aa19aff1) SHA1(5aa4e87ae6ad2063540e3f5179298657bbd82bfb) ) + ROM_LOAD( "brunw-c3.rom", 0x8000, 0x4000, CRC(eabe60fe) SHA1(41f605f1e1b5e2bc7dcbd702f2d202ab4d2f44ec) ) + + ROM_REGION( 0x80000, "mk4_roms", 0 ) + ROM_LOAD( "brunw-c0.rom", 0x0000, 0x4000, CRC(45493337) SHA1(a971e2e63adb004c605cf642edde828e8b3ab897) ) + ROM_LOAD( "brunw-c1.rom", 0x4000, 0x4000, CRC(3200299b) SHA1(d7d5fcacf3c6707a6629b0c65564ac44267d2b49) ) + ROM_LOAD( "brunw-c2.rom", 0x8000, 0x4000, CRC(aa19aff1) SHA1(5aa4e87ae6ad2063540e3f5179298657bbd82bfb) ) + ROM_LOAD( "brunw-c3.rom", 0xc000, 0x4000, CRC(eabe60fe) SHA1(41f605f1e1b5e2bc7dcbd702f2d202ab4d2f44ec) ) + ROM_LOAD( "brunw-c8.rom", 0x10000, 0x4000, CRC(5522b3ee) SHA1(0b7a97134b9d093f668350206e181f1dfc919540) ) + ROM_LOAD( "brunw-c9.rom", 0x14000, 0x4000, CRC(8ba85101) SHA1(85dec683b5e55f1bba0e5f5ab87380b22743909c) ) + ROM_LOAD( "brunw-ca.rom", 0x18000, 0x4000, CRC(2c81fe99) SHA1(221370c021dad839884c2fc4f5fbdbc964db99d5) ) + ROM_LOAD( "brunw-cb.rom", 0x1c000, 0x4000, CRC(e011d6c4) SHA1(bdfb7ee08291bebd30443d4f6bb5b52a4d6468e7) ) + ROM_LOAD( "brunw-d0.rom", 0x20000, 0x4000, CRC(e2aacb30) SHA1(e75e53991c88e9e586e97be2e6aba8b58c79b7e7) ) + ROM_LOAD( "brunw-d1.rom", 0x24000, 0x4000, CRC(b166a6bd) SHA1(f070ca29b2046f3b87c3eafdc59ac1e0c6f39755) ) + ROM_LOAD( "brunw-d2.rom", 0x28000, 0x4000, CRC(5919f1c3) SHA1(227e74fecab244aa2a8baa483679719fa4939cc0) ) + ROM_LOAD( "brunw-d3.rom", 0x2c000, 0x4000, CRC(d29b6a50) SHA1(de83771d6641c16199412efef4aa706f3da5a1e5) ) + ROM_LOAD( "brunw-d8.rom", 0x30000, 0x4000, CRC(28cb6163) SHA1(0d9a05d1c7eeaaf8b94ba551df3b2a6fbabcdcc9) ) + ROM_LOAD( "brunw-d9.rom", 0x34000, 0x4000, CRC(6d528a78) SHA1(fa8659f07ea4b69c0c699fe03c5068a490326ed8) ) + ROM_LOAD( "brunw-da.rom", 0x38000, 0x4000, CRC(c47589c4) SHA1(6b66d1a24388d95310f536710c5d718472800af0) ) + ROM_LOAD( "brunw-db.rom", 0x3c000, 0x4000, CRC(af69c4b9) SHA1(a6849e774de05acb5ba3cf76ded132ef4ea7c271) ) + ROM_LOAD( "brunw-e0.rom", 0x40000, 0x4000, CRC(aef8fdbb) SHA1(425b863df65f106753ce258ed445b8edb3428ad7) ) + ROM_LOAD( "brunw-e1.rom", 0x44000, 0x4000, CRC(7508b568) SHA1(1d7581fafd0f1119a60b9fc108e60a4274d182ab) ) + ROM_LOAD( "brunw-e2.rom", 0x48000, 0x4000, CRC(c7f9a0f6) SHA1(2f89841ab4431a400491c49b20a484375ddebda9) ) + ROM_LOAD( "brunw-e3.rom", 0x4c000, 0x4000, CRC(1adab4cd) SHA1(82e0a30f16b7b6ca5f65da691c5a84ff0aff9dcf) ) + ROM_LOAD( "brunw-e8.rom", 0x50000, 0x4000, CRC(2450e2b3) SHA1(a85f67ef5f683634ef82f4eee6306be44b6d5f9b) ) + ROM_LOAD( "brunw-e9.rom", 0x54000, 0x4000, CRC(f2d6084c) SHA1(8f9b24478dfb4df691d8f7a13bb7e676766f9154) ) + ROM_LOAD( "brunw-ea.rom", 0x58000, 0x4000, CRC(213176b8) SHA1(61d60a10f12d09045801de013346c889ae194985) ) + ROM_LOAD( "brunw-eb.rom", 0x5c000, 0x4000, CRC(ae811538) SHA1(c92169b385599e0c2ceead17d81689adea9dd164) ) + ROM_LOAD( "brunw-f0.rom", 0x60000, 0x4000, CRC(b3ebc6d3) SHA1(b01e6d23eca4cafca7a7102669fd77a158796159) ) + ROM_LOAD( "brunw-f1.rom", 0x64000, 0x4000, CRC(8faae309) SHA1(1caa585a2c4e1f0ffe6923aa9aaf66e4b0275e17) ) + ROM_LOAD( "brunw-f2.rom", 0x68000, 0x4000, CRC(e6afde30) SHA1(3f1e06ebd8319822de25ed731d9e95ec22568c3d) ) + ROM_LOAD( "brunw-f3.rom", 0x6c000, 0x4000, CRC(637d4c20) SHA1(233ae9507bfbea0ae1e8a3b068e1b19df0151a72) ) + ROM_LOAD( "brunw-f8.rom", 0x70000, 0x4000, CRC(2be3aa82) SHA1(b1896b4f78869632fa5a08a82e126a7ba041e00f) ) + ROM_LOAD( "brunw-f9.rom", 0x74000, 0x4000, CRC(0645f1d0) SHA1(83634937142def1e96306d4be53b491da9f5a25d) ) + ROM_LOAD( "brunw-fa.rom", 0x78000, 0x4000, CRC(f99b181e) SHA1(0533e96a71d2a694efcc7677a446af7fee1eb463) ) + ROM_LOAD( "brunw-fb.rom", 0x7c000, 0x4000, CRC(88383953) SHA1(50c6417b26134b68a80912bdb91c8578eb00c8a2) ) +ROM_END + +const rom_entry *cpc_brunword4_device::device_rom_region() const +{ + return ROM_NAME( cpc_brunword4 ); +} + +cpc_brunword4_device::cpc_brunword4_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, CPC_BRUNWORD_MK4, "Brunword Elite MK4", tag, owner, clock, "cpc_brunword4", __FILE__), + device_cpc_expansion_card_interface(mconfig, *this) +{ +} + +void cpc_brunword4_device::device_start() +{ + device_t* cpu = machine().device("maincpu"); + address_space& space = cpu->memory().space(AS_IO); + m_slot = dynamic_cast(owner()); + + space.install_write_handler(0xdf00,0xdfff,0,0,write8_delegate(FUNC(cpc_brunword4_device::rombank_w),this)); +} + +void cpc_brunword4_device::device_reset() +{ + m_rombank_active = false; +} + +WRITE8_MEMBER(cpc_brunword4_device::rombank_w) +{ + if((data & 0xc0) == 0xc0 && (data & 0x04) == 0) + { + m_bank_sel = data; + m_rombank_active = true; + return; + } + if((data & 0xc0) == 0x40) // disable ROM? + { + m_rombank_active = false; + return; + } + m_slot->rom_select(space,0,data & 0x3f); // repeats every 64 ROMs, this breaks upper cart ROM selection on the Plus +} + +void cpc_brunword4_device::set_mapping() +{ + if(m_rombank_active) + { + UINT8* ROM = memregion("mk4_roms")->base(); + UINT8 bank = ((m_bank_sel & 0x38) >> 1) | (m_bank_sel & 0x03); + membank(":bank3")->set_base(ROM+(bank*0x4000)); + membank(":bank4")->set_base(ROM+((bank*0x4000) + 0x2000)); + } +} diff --git a/src/devices/bus/cpc/brunword4.h b/src/devices/bus/cpc/brunword4.h new file mode 100644 index 00000000000..8b66afaefae --- /dev/null +++ b/src/devices/bus/cpc/brunword4.h @@ -0,0 +1,38 @@ +// license:BSD-3-Clause +// copyright-holders:Barry Rodewald +/* + + Brunword MK4 - Word processor ROM / expansion + +*/ + +#include "emu.h" +#include "cpcexp.h" + +class cpc_brunword4_device : public device_t, + public device_cpc_expansion_card_interface +{ +public: + // construction/destruction + cpc_brunword4_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + + DECLARE_WRITE8_MEMBER(rombank_w); + virtual void set_mapping(); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + +private: + cpc_expansion_slot_device *m_slot; + + bool m_rombank_active; + UINT8 m_bank_sel; +}; + +// device type definition +extern const device_type CPC_BRUNWORD_MK4; diff --git a/src/devices/bus/cpc/cpc_pds.c b/src/devices/bus/cpc/cpc_pds.c new file mode 100644 index 00000000000..b1453d9338b --- /dev/null +++ b/src/devices/bus/cpc/cpc_pds.c @@ -0,0 +1,76 @@ +// license:BSD-3-Clause +// copyright-holders:Barry Rodewald +/* + * cpc_pds.c -- CPC interface hardware for the Programmers Development System + * + * Created on: 10/02/2014 + */ + +#include "emu.h" +#include "cpc_pds.h" +#include "includes/amstrad.h" + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type CPC_PDS = &device_creator; + + +static MACHINE_CONFIG_FRAGMENT( cpc_pds ) + MCFG_DEVICE_ADD("pio", Z80PIO, XTAL_4MHz) // no clock on the PCB, so will presume that it uses the CPC's clock + + // no pass-through seen on remake PCBs, unknown if actual hardware had a pass-through port or not +MACHINE_CONFIG_END + + +machine_config_constructor cpc_pds_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( cpc_pds ); +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +cpc_pds_device::cpc_pds_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, CPC_PDS, "Programmers Development System (CPC Target)", tag, owner, clock, "cpc_pds", __FILE__), + device_cpc_expansion_card_interface(mconfig, *this), + m_pio(*this,"pio") +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void cpc_pds_device::device_start() +{ + device_t* cpu = machine().device("maincpu"); + address_space& space = cpu->memory().space(AS_IO); + m_slot = dynamic_cast(owner()); + + space.install_readwrite_handler(0xfbec,0xfbef,0,0,read8_delegate(FUNC(cpc_pds_device::pio_r),this),write8_delegate(FUNC(cpc_pds_device::pio_w),this)); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void cpc_pds_device::device_reset() +{ + // TODO +} + + +READ8_MEMBER(cpc_pds_device::pio_r) +{ + return m_pio->read(space,offset); +} + +WRITE8_MEMBER(cpc_pds_device::pio_w) +{ + m_pio->write(space,offset,data); +} diff --git a/src/devices/bus/cpc/cpc_pds.h b/src/devices/bus/cpc/cpc_pds.h new file mode 100644 index 00000000000..12100e8acbe --- /dev/null +++ b/src/devices/bus/cpc/cpc_pds.h @@ -0,0 +1,58 @@ +// license:BSD-3-Clause +// copyright-holders:Barry Rodewald +/* + * cpc_pds.h -- CPC interface hardware for the Programmers Development System + * + * Created on: 10/02/2014 + * + * Contains a Z80 PIO used to communicate with PC-side hardware (8-bit ISA card containing an 8255 PPI), + * connected via a 16-pin cable. Although it would seem that the C64 has a different cable that directly + * interfaces with the user port. + * + * The Z80 PIO is mapped to the CPC at: + * FBEC Z80 PIO Port A Data (8bit data to/from PC) + * FBED Z80 PIO Port B Data (handshake to/from PC) + * FBEE Z80 PIO Port A Control + * FBEF Z80 PIO Port B Control + * + * More info: http://cpcwiki.eu/index.php/PDS_development_system + * + * TODO: Come up with some way to connect two instances of MESS, one running the PC software, the other + * running the target side + */ + +#ifndef CPC_PDS_H_ +#define CPC_PDS_H_ + +#include "emu.h" +#include "cpcexp.h" +#include "machine/z80pio.h" + +class cpc_pds_device : public device_t, + public device_cpc_expansion_card_interface +{ +public: + // construction/destruction + cpc_pds_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + + DECLARE_READ8_MEMBER(pio_r); + DECLARE_WRITE8_MEMBER(pio_w); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + +private: + cpc_expansion_slot_device *m_slot; + + required_device m_pio; +}; + +// device type definition +extern const device_type CPC_PDS; + +#endif /* CPC_PDS_H_ */ diff --git a/src/devices/bus/cpc/cpc_rom.c b/src/devices/bus/cpc/cpc_rom.c new file mode 100644 index 00000000000..36ccb82e867 --- /dev/null +++ b/src/devices/bus/cpc/cpc_rom.c @@ -0,0 +1,135 @@ +// license:BSD-3-Clause +// copyright-holders:Barry Rodewald +/* + * cpc_rom.c + * Amstrad CPC mountable ROM image device + * + */ + +#include "emu.h" +#include "cpc_rom.h" +#include "includes/amstrad.h" + +const device_type CPC_ROM = &device_creator; + + +//************************************************************************** +// DEVICE CONFIG INTERFACE +//************************************************************************** + +// device machine config +static MACHINE_CONFIG_FRAGMENT( cpc_rom ) + MCFG_ROMSLOT_ADD("rom1") + MCFG_ROMSLOT_ADD("rom2") + MCFG_ROMSLOT_ADD("rom3") + MCFG_ROMSLOT_ADD("rom4") + MCFG_ROMSLOT_ADD("rom5") + MCFG_ROMSLOT_ADD("rom6") + MCFG_ROMSLOT_ADD("rom7") + MCFG_ROMSLOT_ADD("rom8") + + // pass-through + MCFG_DEVICE_ADD("exp", CPC_EXPANSION_SLOT, 0) + MCFG_DEVICE_SLOT_INTERFACE(cpc_exp_cards, NULL, false) + MCFG_CPC_EXPANSION_SLOT_OUT_IRQ_CB(DEVWRITELINE("^", cpc_expansion_slot_device, irq_w)) + MCFG_CPC_EXPANSION_SLOT_OUT_NMI_CB(DEVWRITELINE("^", cpc_expansion_slot_device, nmi_w)) + MCFG_CPC_EXPANSION_SLOT_OUT_ROMDIS_CB(DEVWRITELINE("^", cpc_expansion_slot_device, romdis_w)) // ROMDIS + +MACHINE_CONFIG_END + + +machine_config_constructor cpc_rom_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( cpc_rom ); +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +cpc_rom_device::cpc_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, CPC_ROM, "ROM Box", tag, owner, clock, "cpc_rom", __FILE__), + device_cpc_expansion_card_interface(mconfig, *this) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void cpc_rom_device::device_start() +{ +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void cpc_rom_device::device_reset() +{ +} + + +/*** ROM image device ***/ + +// device type definition +const device_type ROMSLOT = &device_creator; + +//------------------------------------------------- +// rom_image_device - constructor +//------------------------------------------------- + +rom_image_device::rom_image_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, ROMSLOT, "ROM image", tag, owner, clock, "rom_image", __FILE__), + device_image_interface(mconfig, *this) +{ +} + +//------------------------------------------------- +// rom_image_device - destructor +//------------------------------------------------- + +rom_image_device::~rom_image_device() +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void rom_image_device::device_start() +{ + m_base = NULL; +} + +/*------------------------------------------------- + DEVICE_IMAGE_LOAD( rom ) +-------------------------------------------------*/ +bool rom_image_device::call_load() +{ + device_image_interface* image = this; + UINT64 size = image->length(); + + m_base = global_alloc_array(UINT8, 16384); + if(size <= 16384) + { + image->fread(m_base,size); + } + else + { + image->fseek(size-16384,SEEK_SET); + image->fread(m_base,16384); + } + + return IMAGE_INIT_PASS; +} + + +/*------------------------------------------------- + DEVICE_IMAGE_UNLOAD( rom ) +-------------------------------------------------*/ +void rom_image_device::call_unload() +{ + global_free_array(m_base); + m_base = NULL; +} diff --git a/src/devices/bus/cpc/cpc_rom.h b/src/devices/bus/cpc/cpc_rom.h new file mode 100644 index 00000000000..06908b14539 --- /dev/null +++ b/src/devices/bus/cpc/cpc_rom.h @@ -0,0 +1,90 @@ +// license:BSD-3-Clause +// copyright-holders:Barry Rodewald +/* + * cpc_rom.h + * Amstrad CPC mountable ROM image device + * + */ + +#ifndef CPC_ROM_H_ +#define CPC_ROM_H_ + +#include "emu.h" +#include "cpcexp.h" + +/*** ROM image device ***/ + +// ======================> rom_image_device + +class rom_image_device : public device_t, + public device_image_interface +{ +public: + // construction/destruction + rom_image_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual ~rom_image_device(); + + // image-level overrides + virtual bool call_load(); + virtual void call_unload(); + + virtual iodevice_t image_type() const { return IO_ROM; } + + virtual bool is_readable() const { return 1; } + virtual bool is_writeable() const { return 0; } + virtual bool is_creatable() const { return 0; } + virtual bool must_be_loaded() const { return 0; } + virtual bool is_reset_on_load() const { return 1; } + virtual const char *image_interface() const { return "cpc_rom"; } + virtual const char *file_extensions() const { return "rom,bin"; } + virtual const option_guide *create_option_guide() const { return NULL; } + + UINT8* base() { return m_base; } + +protected: + // device-level overrides + virtual void device_config_complete() { update_names(); } + virtual void device_start(); + +private: + UINT8* m_base; +}; + + +// device type definition +extern const device_type ROMSLOT; + + +#define MCFG_ROMSLOT_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, ROMSLOT, 0) + +/*** ROM box device ***/ + +class cpc_rom_device : public device_t, + public device_cpc_expansion_card_interface +{ +public: + // construction/destruction + cpc_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + + UINT8* base(UINT8 slot) { if(slot >=1 && slot <= 8) return m_rom[slot]->base(); else return NULL; } + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + +private: + //cpc_expansion_slot_device *m_slot; + + rom_image_device* m_rom[8]; +}; + +// device type definition +extern const device_type CPC_ROM; + + +#endif diff --git a/src/devices/bus/cpc/cpc_rs232.c b/src/devices/bus/cpc/cpc_rs232.c new file mode 100644 index 00000000000..8dba63da31c --- /dev/null +++ b/src/devices/bus/cpc/cpc_rs232.c @@ -0,0 +1,164 @@ +// license:BSD-3-Clause +// copyright-holders:Barry Rodewald +/* + * cpc_rs232.c + * + * Created on: 22/04/2014 + */ + +#include "cpc_rs232.h" +#include "includes/amstrad.h" + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type CPC_RS232 = &device_creator; +const device_type CPC_RS232_AMS = &device_creator; + +// device machine config +static MACHINE_CONFIG_FRAGMENT( cpc_rs232 ) + MCFG_DEVICE_ADD("pit", PIT8253, 0) + MCFG_PIT8253_CLK0(2000000) + MCFG_PIT8253_CLK1(2000000) + MCFG_PIT8253_CLK2(2000000) + MCFG_PIT8253_OUT0_HANDLER(WRITELINE(cpc_rs232_device, pit_out0_w)) + MCFG_PIT8253_OUT1_HANDLER(WRITELINE(cpc_rs232_device, pit_out1_w)) + MCFG_PIT8253_OUT2_HANDLER(WRITELINE(cpc_rs232_device, pit_out2_w)) + + MCFG_Z80DART_ADD("dart", XTAL_4MHz, 0, 0, 0, 0 ) + MCFG_Z80DART_OUT_TXDA_CB(DEVWRITELINE("rs232", rs232_port_device, write_txd)) + MCFG_Z80DART_OUT_DTRA_CB(DEVWRITELINE("rs232", rs232_port_device, write_dtr)) + MCFG_Z80DART_OUT_RTSA_CB(DEVWRITELINE("rs232", rs232_port_device, write_rts)) + + MCFG_RS232_PORT_ADD("rs232",default_rs232_devices,NULL) + MCFG_RS232_RXD_HANDLER(DEVWRITELINE("dart",z80dart_device,rxa_w)) + MCFG_RS232_DCD_HANDLER(DEVWRITELINE("dart",z80dart_device,dcda_w)) + MCFG_RS232_CTS_HANDLER(DEVWRITELINE("dart",z80dart_device,ctsa_w)) +// MCFG_RS232_RI_HANDLER(DEVWRITELINE("dart",z80dart_device,ria_w)) + + // pass-through + MCFG_DEVICE_ADD("exp", CPC_EXPANSION_SLOT, 0) + MCFG_DEVICE_SLOT_INTERFACE(cpc_exp_cards, NULL, false) + MCFG_CPC_EXPANSION_SLOT_OUT_IRQ_CB(DEVWRITELINE("^", cpc_expansion_slot_device, irq_w)) + MCFG_CPC_EXPANSION_SLOT_OUT_NMI_CB(DEVWRITELINE("^", cpc_expansion_slot_device, nmi_w)) + MCFG_CPC_EXPANSION_SLOT_OUT_ROMDIS_CB(DEVWRITELINE("^", cpc_expansion_slot_device, romdis_w)) // ROMDIS + +MACHINE_CONFIG_END + +ROM_START( cpc_rs232 ) + ROM_REGION( 0x8000, "exp_rom", 0 ) + ROM_LOAD( "comstar1.rom", 0x0000, 0x4000, CRC(ddcade50) SHA1(d09ee0bd51a8e1cafc5107a75fed839dda3d21e5) ) + ROM_LOAD( "comstar2.rom", 0x4000, 0x4000, CRC(664e788c) SHA1(13d033f2d1cad70140deb903d787ba514f236a59) ) +ROM_END + +ROM_START( cpc_rs232_ams ) + ROM_REGION( 0x4000, "exp_rom", 0 ) + ROM_SYSTEM_BIOS( 0, "amstrad", "Amstrad RS232C interface (v1)" ) + ROMX_LOAD( "rs232101.rom", 0x0000, 0x2000, CRC(c6eb52b2) SHA1(8a7e0a1183fdde8d07bc8827a3e159ca3022f93b), ROM_BIOS(1) ) + ROM_SYSTEM_BIOS( 1, "mercitel", "Amstrad RS232C interface (v1) + Mercitel (v1.4)" ) + ROMX_LOAD( "rs232mercitel14.rom", 0x0000, 0x4000, CRC(8ffb114b) SHA1(145233fe8d4db9f5265eeac767d8ee8d45d14755), ROM_BIOS(2) ) +ROM_END + +machine_config_constructor cpc_rs232_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( cpc_rs232 ); +} + +const rom_entry *cpc_rs232_device::device_rom_region() const +{ + return ROM_NAME( cpc_rs232 ); +} + +const rom_entry *cpc_ams_rs232_device::device_rom_region() const +{ + return ROM_NAME( cpc_rs232_ams ); +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +cpc_rs232_device::cpc_rs232_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, CPC_RS232, "Pace RS232C interface", tag, owner, clock, "cpc_ser", __FILE__), + device_cpc_expansion_card_interface(mconfig, *this), + m_pit(*this,"pit"), + m_dart(*this,"dart"), + m_rs232(*this,"rs232") +{ +} + +cpc_rs232_device::cpc_rs232_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_cpc_expansion_card_interface(mconfig, *this), + m_pit(*this,"pit"), + m_dart(*this,"dart"), + m_rs232(*this,"rs232") +{ +} + +cpc_ams_rs232_device::cpc_ams_rs232_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + cpc_rs232_device(mconfig, CPC_RS232_AMS, "Amstrad RS232C interface", tag, owner, clock, "cpc_serams", __FILE__) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void cpc_rs232_device::device_start() +{ + device_t* cpu = machine().device("maincpu"); + address_space& space = cpu->memory().space(AS_IO); + m_slot = dynamic_cast(owner()); + + space.install_readwrite_handler(0xfadc,0xfadf,0,0,read8_delegate(FUNC(cpc_rs232_device::dart_r),this),write8_delegate(FUNC(cpc_rs232_device::dart_w),this)); + space.install_readwrite_handler(0xfbdc,0xfbdf,0,0,read8_delegate(FUNC(cpc_rs232_device::pit_r),this),write8_delegate(FUNC(cpc_rs232_device::pit_w),this)); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void cpc_rs232_device::device_reset() +{ +} + + +WRITE_LINE_MEMBER(cpc_rs232_device::pit_out0_w) +{ + m_dart->txca_w(state); +} + +WRITE_LINE_MEMBER(cpc_rs232_device::pit_out1_w) +{ + m_dart->rxca_w(state); +} + +WRITE_LINE_MEMBER(cpc_rs232_device::pit_out2_w) +{ + m_dart->txcb_w(state); + m_dart->rxcb_w(state); +} + +READ8_MEMBER(cpc_rs232_device::dart_r) +{ + return m_dart->ba_cd_r(space,offset); +} + +WRITE8_MEMBER(cpc_rs232_device::dart_w) +{ + m_dart->ba_cd_w(space,offset,data); +} + +READ8_MEMBER(cpc_rs232_device::pit_r) +{ + return m_pit->read(space,offset); +} + +WRITE8_MEMBER(cpc_rs232_device::pit_w) +{ + m_pit->write(space,offset,data); +} diff --git a/src/devices/bus/cpc/cpc_rs232.h b/src/devices/bus/cpc/cpc_rs232.h new file mode 100644 index 00000000000..b11960c01f9 --- /dev/null +++ b/src/devices/bus/cpc/cpc_rs232.h @@ -0,0 +1,65 @@ +// license:BSD-3-Clause +// copyright-holders:Barry Rodewald +/* + * cpc_rs232.h + * + * Created on: 22/04/2014 + */ + +#ifndef CPC_RS232_H_ +#define CPC_RS232_H_ + +#include "emu.h" +#include "machine/z80dart.h" +#include "machine/pit8253.h" +#include "bus/rs232/rs232.h" +#include "cpcexp.h" + +class cpc_rs232_device : public device_t, + public device_cpc_expansion_card_interface +{ +public: + // construction/destruction + cpc_rs232_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + cpc_rs232_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + + DECLARE_WRITE_LINE_MEMBER(pit_out0_w); + DECLARE_WRITE_LINE_MEMBER(pit_out1_w); + DECLARE_WRITE_LINE_MEMBER(pit_out2_w); + + DECLARE_READ8_MEMBER(dart_r); + DECLARE_WRITE8_MEMBER(dart_w); + DECLARE_READ8_MEMBER(pit_r); + DECLARE_WRITE8_MEMBER(pit_w); + + required_device m_pit; + required_device m_dart; + required_device m_rs232; +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual const rom_entry *device_rom_region() const; + +private: + cpc_expansion_slot_device *m_slot; +}; + +class cpc_ams_rs232_device : public cpc_rs232_device +{ +public: + // construction/destruction + cpc_ams_rs232_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual const rom_entry *device_rom_region() const; +}; + +// device type definition +extern const device_type CPC_RS232; +extern const device_type CPC_RS232_AMS; + +#endif /* CPC_RS232_H_ */ diff --git a/src/devices/bus/cpc/cpc_ssa1.c b/src/devices/bus/cpc/cpc_ssa1.c new file mode 100644 index 00000000000..0c638b5cf37 --- /dev/null +++ b/src/devices/bus/cpc/cpc_ssa1.c @@ -0,0 +1,220 @@ +// license:BSD-3-Clause +// copyright-holders:Barry Rodewald +/* + * cpc_ssa1.c -- Amstrad SSA-1 Speech Synthesiser, dk'Tronics Speech Synthesiser + * + * Created on: 16/07/2011 + * + */ + + +#include "emu.h" +#include "cpc_ssa1.h" +#include "includes/amstrad.h" + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type CPC_SSA1 = &device_creator; +const device_type CPC_DKSPEECH = &device_creator; + +//------------------------------------------------- +// device I/O handlers +//------------------------------------------------- + +READ8_MEMBER(cpc_ssa1_device::ssa1_r) +{ + UINT8 ret = 0xff; + + if(get_sby() == 0) + ret &= ~0x80; + + if(get_lrq() != 0) + ret &= ~0x40; + + return ret; +} + +WRITE8_MEMBER(cpc_ssa1_device::ssa1_w) +{ + m_sp0256_device->ald_w(space, 0, data); +} + +READ8_MEMBER(cpc_dkspeech_device::dkspeech_r) +{ + UINT8 ret = 0xff; + + // SBY is not connected + + if(get_lrq() != 0) + ret &= ~0x80; + + return ret; +} + +WRITE8_MEMBER(cpc_dkspeech_device::dkspeech_w) +{ + m_sp0256_device->ald_w(space, 0, data & 0x3f); +} + +WRITE_LINE_MEMBER(cpc_ssa1_device::lrq_cb) +{ + set_lrq(state); +} + +WRITE_LINE_MEMBER(cpc_ssa1_device::sby_cb) +{ + set_sby(state); +} + +WRITE_LINE_MEMBER(cpc_dkspeech_device::lrq_cb) +{ + set_lrq(state); +} + +WRITE_LINE_MEMBER(cpc_dkspeech_device::sby_cb) +{ + set_sby(state); +} + +//------------------------------------------------- +// Device ROM definition +//------------------------------------------------- + +// Has no actual ROM, just that internal to the SP0256 +ROM_START( cpc_ssa1 ) + ROM_REGION( 0x10000, "sp0256", 0 ) + ROM_LOAD( "sp0256-al2.bin", 0x1000, 0x0800, CRC(b504ac15) SHA1(e60fcb5fa16ff3f3b69d36c7a6e955744d3feafc) ) +ROM_END + +// Available in ROM and cassette versions. We'll add the ROM for convenience. +ROM_START( cpc_dkspeech ) + ROM_REGION( 0x10000, "sp0256", 0 ) + ROM_LOAD( "sp0256-al2.bin", 0x1000, 0x0800, CRC(b504ac15) SHA1(e60fcb5fa16ff3f3b69d36c7a6e955744d3feafc) ) + + ROM_REGION( 0x4000, "exp_rom", 0 ) + ROM_LOAD( "dkspeech.rom", 0x0000, 0x4000, CRC(4957c2f5) SHA1(bf28e07d5fada3678faab77f582b802164e82f62) ) +ROM_END + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *cpc_ssa1_device::device_rom_region() const +{ + return ROM_NAME( cpc_ssa1 ); +} + +const rom_entry *cpc_dkspeech_device::device_rom_region() const +{ + return ROM_NAME( cpc_dkspeech ); +} + +// device machine config +static MACHINE_CONFIG_FRAGMENT( cpc_ssa1 ) + MCFG_SPEAKER_STANDARD_MONO("mono") + MCFG_SOUND_ADD("sp0256",SP0256,XTAL_3_12MHz) + MCFG_SP0256_DATA_REQUEST_CB(WRITELINE(cpc_ssa1_device, lrq_cb)) + MCFG_SP0256_STANDBY_CB(WRITELINE(cpc_ssa1_device, sby_cb)) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 1.00) + + // pass-through + MCFG_DEVICE_ADD("exp", CPC_EXPANSION_SLOT, 0) + MCFG_DEVICE_SLOT_INTERFACE(cpc_exp_cards, NULL, false) + MCFG_CPC_EXPANSION_SLOT_OUT_IRQ_CB(DEVWRITELINE("^", cpc_expansion_slot_device, irq_w)) + MCFG_CPC_EXPANSION_SLOT_OUT_NMI_CB(DEVWRITELINE("^", cpc_expansion_slot_device, nmi_w)) + MCFG_CPC_EXPANSION_SLOT_OUT_ROMDIS_CB(DEVWRITELINE("^", cpc_expansion_slot_device, romdis_w)) // ROMDIS + +MACHINE_CONFIG_END + +static MACHINE_CONFIG_FRAGMENT( cpc_dkspeech ) + MCFG_SPEAKER_STANDARD_MONO("mono") + MCFG_SOUND_ADD("sp0256",SP0256,XTAL_4MHz) // uses the CPC's clock from pin 50 of the expansion port + MCFG_SP0256_DATA_REQUEST_CB(WRITELINE(cpc_dkspeech_device, lrq_cb)) + MCFG_SP0256_STANDBY_CB(WRITELINE(cpc_dkspeech_device, sby_cb)) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 1.00) + + // pass-through + MCFG_DEVICE_ADD("exp", CPC_EXPANSION_SLOT, 0) + MCFG_DEVICE_SLOT_INTERFACE(cpc_exp_cards, NULL, false) + MCFG_CPC_EXPANSION_SLOT_OUT_IRQ_CB(DEVWRITELINE("^", cpc_expansion_slot_device, irq_w)) + MCFG_CPC_EXPANSION_SLOT_OUT_NMI_CB(DEVWRITELINE("^", cpc_expansion_slot_device, nmi_w)) + MCFG_CPC_EXPANSION_SLOT_OUT_ROMDIS_CB(DEVWRITELINE("^", cpc_expansion_slot_device, romdis_w)) // ROMDIS + +MACHINE_CONFIG_END + +machine_config_constructor cpc_ssa1_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( cpc_ssa1 ); +} + +machine_config_constructor cpc_dkspeech_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( cpc_dkspeech ); +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +cpc_ssa1_device::cpc_ssa1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, CPC_SSA1, "SSA-1", tag, owner, clock, "cpc_ssa1", __FILE__), + device_cpc_expansion_card_interface(mconfig, *this), + m_lrq(1), + m_sp0256_device(*this,"sp0256") +{ +} + +cpc_dkspeech_device::cpc_dkspeech_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, CPC_DKSPEECH, "DK'Tronics Speech Synthesiser", tag, owner, clock, "cpc_dkspeech", __FILE__), + device_cpc_expansion_card_interface(mconfig, *this), + m_lrq(1), + m_sp0256_device(*this,"sp0256") +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void cpc_ssa1_device::device_start() +{ + device_t* cpu = machine().device("maincpu"); + address_space& space = cpu->memory().space(AS_IO); + m_slot = dynamic_cast(owner()); + + m_rom = memregion("sp0256")->base(); + +// m_sp0256_device = subdevice("sp0256"); + + space.install_readwrite_handler(0xfaee,0xfaee,0,0,read8_delegate(FUNC(cpc_ssa1_device::ssa1_r),this),write8_delegate(FUNC(cpc_ssa1_device::ssa1_w),this)); + space.install_readwrite_handler(0xfbee,0xfbee,0,0,read8_delegate(FUNC(cpc_ssa1_device::ssa1_r),this),write8_delegate(FUNC(cpc_ssa1_device::ssa1_w),this)); +} + +void cpc_dkspeech_device::device_start() +{ + device_t* cpu = machine().device("maincpu"); + address_space& space = cpu->memory().space(AS_IO); + m_slot = dynamic_cast(owner()); + + m_rom = memregion("sp0256")->base(); + +// m_sp0256_device = subdevice("sp0256"); + + space.install_readwrite_handler(0xfbfe,0xfbfe,0,0,read8_delegate(FUNC(cpc_dkspeech_device::dkspeech_r),this),write8_delegate(FUNC(cpc_dkspeech_device::dkspeech_w),this)); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void cpc_ssa1_device::device_reset() +{ + m_sp0256_device->reset(); +} + +void cpc_dkspeech_device::device_reset() +{ + m_sp0256_device->reset(); +} diff --git a/src/devices/bus/cpc/cpc_ssa1.h b/src/devices/bus/cpc/cpc_ssa1.h new file mode 100644 index 00000000000..32c311f5b65 --- /dev/null +++ b/src/devices/bus/cpc/cpc_ssa1.h @@ -0,0 +1,128 @@ +// license:BSD-3-Clause +// copyright-holders:Barry Rodewald +/* + * cpc_ssa1.h -- Amstrad SSA-1 Speech Synthesiser, dk'Tronics Speech Synthesiser + * + * Created on: 16/07/2011 + * + * Amstrad SSA-1 - SP0256-AL2 based Speech Synthesiser and Sound Amplifier + * + * Uses on-board resonator, clocked at 3.12MHz + * + * Decodes only I/O lines A10, A4 and A0 + * Official I/O ports: + * &FBEE (read) + * - bit 7: SP0256 Status 1 (SBY) + * - bit 6: SP0256 Status 2 (/LRQ) + * + * &FBEE (write) + * - bits 7-0: SP0256 Allophone number (must be 0x00 to 0x3f, however, all data lines are hooked up) + * + * &FAEE (write) + * - same as above, used because of a bug in the driver software, but still works due to the way the I/O ports are + * decoded on the CPC. + * + * More info and PCB pics at http://www.cpcwiki.eu/index.php/Amstrad_SSA-1_Speech_Synthesizer + * + * + * dk'Tronics Speech Synthesiser - SP0256-AL2 based speech synthesiser + * + * Uses the CPC's clock of 4MHz from pin 50 of the expansion port, gives faster and higher pitched voices than the SSA-1 + * + * Official I/O ports: + * &FBFE (read) + * - bit 7: SP0256 Status 2 (/LRQ) + * + * &FBFE (write) + * - bits 5-0: SP0256 Allophone number + * + * More info and PCB pics at http://www.cpcwiki.eu/index.php/Dk%27tronics_Speech_Synthesizer + * + */ + +#ifndef CPC_SSA1_H_ +#define CPC_SSA1_H_ + + +#include "emu.h" +#include "cpcexp.h" +#include "sound/sp0256.h" + +class cpc_ssa1_device : public device_t, + public device_cpc_expansion_card_interface +{ +public: + // construction/destruction + cpc_ssa1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + + void set_lrq(UINT8 state) { m_lrq = state; } + UINT8 get_lrq() { return m_lrq; } + void set_sby(UINT8 state) { m_sby = state; } + UINT8 get_sby() { return m_sby; } + + DECLARE_READ8_MEMBER(ssa1_r); + DECLARE_WRITE8_MEMBER(ssa1_w); + DECLARE_WRITE_LINE_MEMBER(lrq_cb); + DECLARE_WRITE_LINE_MEMBER(sby_cb); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + +private: + cpc_expansion_slot_device *m_slot; + + UINT8 *m_rom; + UINT8 m_lrq; + UINT8 m_sby; + + required_device m_sp0256_device; +}; + +class cpc_dkspeech_device : public device_t, + public device_cpc_expansion_card_interface +{ +public: + // construction/destruction + cpc_dkspeech_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + + void set_lrq(UINT8 state) { m_lrq = state; } + UINT8 get_lrq() { return m_lrq; } + void set_sby(UINT8 state) { m_sby = state; } + UINT8 get_sby() { return m_sby; } + + DECLARE_READ8_MEMBER(dkspeech_r); + DECLARE_WRITE8_MEMBER(dkspeech_w); + DECLARE_WRITE_LINE_MEMBER(lrq_cb); + DECLARE_WRITE_LINE_MEMBER(sby_cb); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + +private: + cpc_expansion_slot_device *m_slot; + + UINT8 *m_rom; + UINT8 m_lrq; + UINT8 m_sby; + + required_device m_sp0256_device; +}; + +// device type definition +extern const device_type CPC_SSA1; +extern const device_type CPC_DKSPEECH; + + +#endif /* CPC_SSA1_H_ */ diff --git a/src/devices/bus/cpc/cpcexp.c b/src/devices/bus/cpc/cpcexp.c new file mode 100644 index 00000000000..a6d8d77db16 --- /dev/null +++ b/src/devices/bus/cpc/cpcexp.c @@ -0,0 +1,89 @@ +// license:BSD-3-Clause +// copyright-holders:Barry Rodewald +/* + * cpcexp.c -- Amstrad CPC Expansion port + * + * Created on: 16/07/2011 + * + */ + + +#include "emu.h" +#include "emuopts.h" +#include "cpcexp.h" + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type CPC_EXPANSION_SLOT = &device_creator; + + +//************************************************************************** +// DEVICE CPC_EXPANSION CARD INTERFACE +//************************************************************************** + + +device_cpc_expansion_card_interface::device_cpc_expansion_card_interface(const machine_config &mconfig, device_t &device) + : device_slot_card_interface(mconfig,device) +{ +} + + +device_cpc_expansion_card_interface::~device_cpc_expansion_card_interface() +{ +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +cpc_expansion_slot_device::cpc_expansion_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, CPC_EXPANSION_SLOT, "Amstrad CPC expansion port", tag, owner, clock, "cpc_expansion_slot", __FILE__), + device_slot_interface(mconfig, *this), + m_out_irq_cb(*this), + m_out_nmi_cb(*this), + m_out_reset_cb(*this), + m_out_romdis_cb(*this), + m_out_rom_select(*this) +{ +} + +cpc_expansion_slot_device::~cpc_expansion_slot_device() +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void cpc_expansion_slot_device::device_start() +{ + m_card = dynamic_cast(get_card_device()); + + // resolve callbacks + m_out_irq_cb.resolve_safe(); + m_out_nmi_cb.resolve_safe(); + m_out_reset_cb.resolve_safe(); + m_out_romdis_cb.resolve_safe(); + m_out_rom_select.resolve_safe(); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void cpc_expansion_slot_device::device_reset() +{ +} + + +WRITE_LINE_MEMBER( cpc_expansion_slot_device::irq_w ) { m_out_irq_cb(state); } +WRITE_LINE_MEMBER( cpc_expansion_slot_device::nmi_w ) { m_out_nmi_cb(state); } +WRITE_LINE_MEMBER( cpc_expansion_slot_device::reset_w ) { m_out_reset_cb(state); } +WRITE_LINE_MEMBER( cpc_expansion_slot_device::romdis_w ) { m_out_romdis_cb(state); } +WRITE8_MEMBER( cpc_expansion_slot_device::rom_select ) { m_out_rom_select(data); } diff --git a/src/devices/bus/cpc/cpcexp.h b/src/devices/bus/cpc/cpcexp.h new file mode 100644 index 00000000000..e52c447b72b --- /dev/null +++ b/src/devices/bus/cpc/cpcexp.h @@ -0,0 +1,154 @@ +// license:BSD-3-Clause +// copyright-holders:Barry Rodewald +/* + * cpcexp.h -- Amstrad CPC Expansion port + * + * Created on: 16/07/2011 + * + * Pinout from CPC6128 User's Manual + * SOUND 1 2 GND + * A15 3 4 A14 + * A13 5 6 A12 + * A11 7 8 A10 + * A9 9 10 A8 + * A7 11 12 A6 + * A5 13 14 A4 + * A3 15 16 A2 + * A1 17 18 A0 + * D7 19 20 D6 + * D5 21 22 D4 + * D3 23 24 D2 + * D1 25 26 D0 + * +5v 27 28 _MREQ + * _M1 29 30 _RFSH + * _IORQ 31 32 _RD + * _WR 33 34 _HALT + * _INT 35 36 _NMI + * _BUSR2 37 38 _BUSAK + * READY 39 40 _BUS RESET + * _RESET 41 42 _ROMEN + * ROMDIS 43 44 _RAMRD + * RAMDIS 45 46 CURSOR + * L.PEN 47 48 _EXP + * GND 49 50 CLOCK + * + * Aleste 520EX expansion port is 62-pin. Same as the CPC above, except that pin 40 is not connected, plus the following: + * + * MAP14 A26 B26 MAP15 + * MAP16 A27 B27 MAP17 + * MAP18 A28 B28 MAPBLK + * _INTA A29 B29 _DISP + * Agnd A30 B30 _CPU + * Aucc A31 B31 HIGH + * + */ + +#pragma once + +#ifndef CPCEXP_H_ +#define CPCEXP_H_ + +#include "emu.h" + +//************************************************************************** +// CONSTANTS +//************************************************************************** + +#define CPC_EXP_SLOT_TAG "cpcexp" + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_CPC_EXPANSION_SLOT_OUT_IRQ_CB(_devcb) \ + devcb = &cpc_expansion_slot_device::set_out_irq_callback(*device, DEVCB_##_devcb); + +#define MCFG_CPC_EXPANSION_SLOT_OUT_NMI_CB(_devcb) \ + devcb = &cpc_expansion_slot_device::set_out_nmi_callback(*device, DEVCB_##_devcb); + +#define MCFG_CPC_EXPANSION_SLOT_OUT_RESET_CB(_devcb) \ + devcb = &cpc_expansion_slot_device::set_out_reset_callback(*device, DEVCB_##_devcb); + +#define MCFG_CPC_EXPANSION_SLOT_OUT_ROMDIS_CB(_devcb) \ + devcb = &cpc_expansion_slot_device::set_out_romdis_callback(*device, DEVCB_##_devcb); + +#define MCFG_CPC_EXPANSION_SLOT_ROM_SELECT(_devcb) \ + devcb = &cpc_expansion_slot_device::set_out_rom_select_callback(*device, DEVCB_##_devcb); + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> device_cpc_expansion_card_interface + +// class representing interface-specific live cpc_expansion card +class device_cpc_expansion_card_interface : public device_slot_card_interface +{ +public: + // construction/destruction + device_cpc_expansion_card_interface(const machine_config &mconfig, device_t &device); + virtual ~device_cpc_expansion_card_interface(); + + // reset + virtual void cpc_reset_w() { }; + virtual WRITE_LINE_MEMBER( cursor_w ) { }; + virtual WRITE_LINE_MEMBER( romen_w ) { }; + + void set_rom_bank(UINT8 sel) { m_rom_sel = sel; } // tell device the currently selected ROM + UINT8 get_rom_bank() { return m_rom_sel; } + virtual void set_mapping() { }; + +private: + UINT8 m_rom_sel; // currently selected ROM +}; + + +// ======================> cpc_expansion_slot_device + +class cpc_expansion_slot_device : public device_t, + public device_slot_interface +{ +public: + // construction/destruction + cpc_expansion_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual ~cpc_expansion_slot_device(); + + template static devcb_base &set_out_irq_callback(device_t &device, _Object object) { return downcast(device).m_out_irq_cb.set_callback(object); } + template static devcb_base &set_out_nmi_callback(device_t &device, _Object object) { return downcast(device).m_out_nmi_cb.set_callback(object); } + template static devcb_base &set_out_reset_callback(device_t &device, _Object object) { return downcast(device).m_out_reset_cb.set_callback(object); } + template static devcb_base &set_out_romdis_callback(device_t &device, _Object object) { return downcast(device).m_out_romdis_cb.set_callback(object); } + template static devcb_base &set_out_rom_select_callback(device_t &device, _Object object) { return downcast(device).m_out_rom_select.set_callback(object); } + + DECLARE_WRITE_LINE_MEMBER( irq_w ); + DECLARE_WRITE_LINE_MEMBER( nmi_w ); + DECLARE_WRITE_LINE_MEMBER( reset_w ); + DECLARE_WRITE_LINE_MEMBER( romdis_w ); + DECLARE_WRITE8_MEMBER( rom_select ); + + void set_rom_bank(UINT8 sel) { if(m_card) m_card->set_rom_bank(sel); } // tell device the currently selected ROM + void set_mapping() { if(m_card) m_card->set_mapping(); } // tell device to enable any ROM or RAM mapping + DECLARE_WRITE_LINE_MEMBER( cursor_w ) { if(m_card) m_card->cursor_w(state); } // pass on CRTC Cursor signal + DECLARE_WRITE_LINE_MEMBER( romen_w ) { if(m_card) m_card->romen_w(state); } // pass on /ROMEN signal + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + devcb_write_line m_out_irq_cb; + devcb_write_line m_out_nmi_cb; + devcb_write_line m_out_reset_cb; + devcb_write_line m_out_romdis_cb; + devcb_write8 m_out_rom_select; + + device_cpc_expansion_card_interface *m_card; + +}; + + +// device type definition +extern const device_type CPC_EXPANSION_SLOT; + +#endif /* CPCEXP_H_ */ diff --git a/src/devices/bus/cpc/ddi1.c b/src/devices/bus/cpc/ddi1.c new file mode 100644 index 00000000000..b7d7e5a74de --- /dev/null +++ b/src/devices/bus/cpc/ddi1.c @@ -0,0 +1,139 @@ +// license:BSD-3-Clause +// copyright-holders:Barry Rodewald +/* + * ddi1.c -- Amstrad DDI-1 Floppy Disk Drive interface + */ + +#include "emu.h" +#include "ddi1.h" +#include "includes/amstrad.h" + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type CPC_DDI1 = &device_creator; + +static SLOT_INTERFACE_START( ddi1_floppies ) + SLOT_INTERFACE( "3ssdd", FLOPPY_3_SSDD ) +SLOT_INTERFACE_END + +//------------------------------------------------- +// Device ROM definition +//------------------------------------------------- + +ROM_START( cpc_ddi1 ) + ROM_REGION( 0x4000, "exp_rom", 0 ) + ROM_LOAD("cpcados.rom", 0x0000, 0x4000, CRC(1fe22ecd) SHA1(39102c8e9cb55fcc0b9b62098780ed4a3cb6a4bb)) +ROM_END + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *cpc_ddi1_device::device_rom_region() const +{ + return ROM_NAME( cpc_ddi1 ); +} + +// device machine config +static MACHINE_CONFIG_FRAGMENT( cpc_ddi1 ) + MCFG_UPD765A_ADD("upd765", true, true) + MCFG_FLOPPY_DRIVE_ADD("upd765:0", ddi1_floppies, "3ssdd", floppy_image_device::default_floppy_formats) + MCFG_SOFTWARE_LIST_ADD("flop_list","cpc_flop") + + // pass-through + MCFG_DEVICE_ADD("exp", CPC_EXPANSION_SLOT, 0) + MCFG_DEVICE_SLOT_INTERFACE(cpc_exp_cards, NULL, false) + MCFG_CPC_EXPANSION_SLOT_OUT_IRQ_CB(DEVWRITELINE("^", cpc_expansion_slot_device, irq_w)) + MCFG_CPC_EXPANSION_SLOT_OUT_NMI_CB(DEVWRITELINE("^", cpc_expansion_slot_device, nmi_w)) + MCFG_CPC_EXPANSION_SLOT_OUT_ROMDIS_CB(DEVWRITELINE("^", cpc_expansion_slot_device, romdis_w)) // ROMDIS + +MACHINE_CONFIG_END + +machine_config_constructor cpc_ddi1_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( cpc_ddi1 ); +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +cpc_ddi1_device::cpc_ddi1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, CPC_DDI1, "DDI-1", tag, owner, clock, "cpc_ddi1", __FILE__), + device_cpc_expansion_card_interface(mconfig, *this), + m_fdc(*this,"upd765"), + m_connector(*this,"upd765:0") +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void cpc_ddi1_device::device_start() +{ + device_t* cpu = machine().device("maincpu"); + address_space& space = cpu->memory().space(AS_IO); + m_slot = dynamic_cast(owner()); + + space.install_write_handler(0xfa7e,0xfa7f,0,0,write8_delegate(FUNC(cpc_ddi1_device::motor_w),this)); + space.install_readwrite_handler(0xfb7e,0xfb7f,0,0,read8_delegate(FUNC(cpc_ddi1_device::fdc_r),this),write8_delegate(FUNC(cpc_ddi1_device::fdc_w),this)); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void cpc_ddi1_device::device_reset() +{ +} + +WRITE8_MEMBER(cpc_ddi1_device::motor_w) +{ + switch(offset) + { + case 0x00: + case 0x01: + { + /* FDC Motor Control - Bit 0 defines the state of the FDD motor: + * "1" the FDD motor will be active. + * "0" the FDD motor will be in-active.*/ + floppy_image_device *floppy; + if(m_connector) + { + floppy = m_connector->get_device(); + if(floppy) + floppy->mon_w(!BIT(data, 0)); + } + break; + } + } +} + +WRITE8_MEMBER(cpc_ddi1_device::fdc_w) +{ + switch(offset) + { + case 0x01: + m_fdc->fifo_w(space, 0,data); + break; + } +} + +READ8_MEMBER(cpc_ddi1_device::fdc_r) +{ + UINT8 data = 0xff; + + switch(offset) + { + case 0x00: + data = m_fdc->msr_r(space, 0); + break; + case 0x01: + data = m_fdc->fifo_r(space, 0); + break; + } + return data; +} diff --git a/src/devices/bus/cpc/ddi1.h b/src/devices/bus/cpc/ddi1.h new file mode 100644 index 00000000000..8f813e8c09a --- /dev/null +++ b/src/devices/bus/cpc/ddi1.h @@ -0,0 +1,47 @@ +// license:BSD-3-Clause +// copyright-holders:Barry Rodewald +/* + * ddi1.h -- Amstrad DDI-1 Floppy Disk Drive interface + * + * Provides uPD765A FDC, AMSDOS ROM, and 3" floppy disk drive. + * CPC464 only, 664/6128/464+/6128+ already has this hardware built-in (AMSDOS is on the included Burnin' Rubber / BASIC cartridge for the 464+ and 6128+) + * + */ + +#ifndef CPC_DDI1_H_ +#define CPC_DDI1_H_ + +#include "emu.h" +#include "cpcexp.h" +#include "machine/upd765.h" + +class cpc_ddi1_device : public device_t, + public device_cpc_expansion_card_interface +{ +public: + // construction/destruction + cpc_ddi1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + + DECLARE_WRITE8_MEMBER(motor_w); + DECLARE_WRITE8_MEMBER(fdc_w); + DECLARE_READ8_MEMBER(fdc_r); +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + +private: + cpc_expansion_slot_device *m_slot; + + required_device m_fdc; + required_device m_connector; +}; + +// device type definition +extern const device_type CPC_DDI1; + +#endif /* CPC_DDI1_H_ */ diff --git a/src/devices/bus/cpc/hd20.c b/src/devices/bus/cpc/hd20.c new file mode 100644 index 00000000000..a6cb2772719 --- /dev/null +++ b/src/devices/bus/cpc/hd20.c @@ -0,0 +1,131 @@ +// license:BSD-3-Clause +// copyright-holders:Barry Rodewald +/* + + Dobbertin HD20 hard disk + +*/ + +#include "emu.h" +#include "hd20.h" +#include "includes/amstrad.h" + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type CPC_HD20 = &device_creator; + +static MACHINE_CONFIG_FRAGMENT( cpc_hd20 ) + MCFG_DEVICE_ADD("hdc",ST11M_HDC,0) + MCFG_XTHDC_IRQ_HANDLER(WRITELINE(cpc_hd20_device,irq_w)) + MCFG_HARDDISK_ADD("hdc:primary") + // no pass-through (?) +MACHINE_CONFIG_END + +machine_config_constructor cpc_hd20_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( cpc_hd20 ); +} + +ROM_START( cpc_hd20 ) + ROM_REGION( 0x4000, "exp_rom", 0 ) + ROM_DEFAULT_BIOS("xddos210") + + ROM_SYSTEM_BIOS( 0, "xddos210", "X-DDOS 2.10" ) + ROMX_LOAD( "xddos210.rom", 0x0000, 0x4000, CRC(5477fdb4) SHA1(2f1bd4d6e2d2e62818b01e6e7a26488362a7a8ee), ROM_BIOS(1) ) + ROM_SYSTEM_BIOS( 1, "xddos200", "X-DDOS 2.00" ) + ROMX_LOAD( "x-ddos20.rom", 0x0000, 0x4000, CRC(c2d9cc03) SHA1(8a20788be5f957e84e849c226aa97b55b2a3aab9), ROM_BIOS(2) ) +ROM_END + +const rom_entry *cpc_hd20_device::device_rom_region() const +{ + return ROM_NAME( cpc_hd20 ); +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +cpc_hd20_device::cpc_hd20_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, CPC_HD20, "Dobbertin HD20", tag, owner, clock, "cpc_hd20", __FILE__), + device_cpc_expansion_card_interface(mconfig, *this), + m_hdc(*this,"hdc") +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void cpc_hd20_device::device_start() +{ + device_t* cpu = machine().device("maincpu"); + address_space& space = cpu->memory().space(AS_IO); + m_slot = dynamic_cast(owner()); + + space.install_write_handler(0xfbe0,0xfbe4,0,0,write8_delegate(FUNC(cpc_hd20_device::hdc_w),this)); + space.install_read_handler(0xfbe0,0xfbe4,0,0,read8_delegate(FUNC(cpc_hd20_device::hdc_r),this)); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void cpc_hd20_device::device_reset() +{ + // TODO +} + +READ8_MEMBER(cpc_hd20_device::hdc_r) +{ + UINT8 ret = 0x00; + + switch(offset) + { + case 0: + ret = m_hdc->data_r(); + break; + case 1: + ret = m_hdc->status_r(); + break; + case 2: + m_hdc->set_ready(); + ret = 0x01; + break; + case 4: + m_hdc->reset_w(0); // reset on read also? + break; + } + + return ret; +} + +WRITE8_MEMBER(cpc_hd20_device::hdc_w) +{ + switch(offset) + { + case 0: + m_hdc->data_w(data); + break; + case 1: + m_hdc->reset_w(data); + break; + case 2: + m_hdc->select_w(data); + break; + case 3: + m_hdc->control_w(data); + break; + case 4: + m_hdc->reset_w(data); + break; + } +} + +WRITE_LINE_MEMBER(cpc_hd20_device::irq_w) +{ +// if(state) +// m_hdc->set_ready(); +} diff --git a/src/devices/bus/cpc/hd20.h b/src/devices/bus/cpc/hd20.h new file mode 100644 index 00000000000..0926e6bd5be --- /dev/null +++ b/src/devices/bus/cpc/hd20.h @@ -0,0 +1,50 @@ +// license:BSD-3-Clause +// copyright-holders:Barry Rodewald +/* + + Dobbertin HD20 hard disk + + Fixed disk interface for the Amstrad CPC + + Controller: Seagate ST11M XT HD Controller + Disk: 3.5" 20MB Seagate, Kyocera, NEC or Miniscribe (Geometry: 615 cylinders/4 heads/17 sectors) + +*/ + +#ifndef HD20_H_ +#define HD20_H_ + +#include "emu.h" +#include "cpcexp.h" +#include "bus/isa/hdc.h" + +class cpc_hd20_device : public device_t, + public device_cpc_expansion_card_interface +{ +public: + // construction/destruction + cpc_hd20_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual const rom_entry *device_rom_region() const; + + DECLARE_READ8_MEMBER(hdc_r); + DECLARE_WRITE8_MEMBER(hdc_w); + DECLARE_WRITE_LINE_MEMBER(irq_w); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + +private: + cpc_expansion_slot_device *m_slot; + + required_device m_hdc; +}; + +// device type definition +extern const device_type CPC_HD20; + +#endif /* HD20_H_ */ diff --git a/src/devices/bus/cpc/magicsound.c b/src/devices/bus/cpc/magicsound.c new file mode 100644 index 00000000000..601672a2e58 --- /dev/null +++ b/src/devices/bus/cpc/magicsound.c @@ -0,0 +1,190 @@ +// license:BSD-3-Clause +// copyright-holders:Barry Rodewald +/* + * magicsound.c + * + * Magic Sound Board for the Aleste 520EX + * + */ + +#include "emu.h" +#include "magicsound.h" +#include "includes/amstrad.h" + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type AL_MAGICSOUND = &device_creator; + + +static MACHINE_CONFIG_FRAGMENT( al_magicsound ) + MCFG_DEVICE_ADD( "dmac", AM9517A, XTAL_4MHz ) // CLK from expansion port + // According to the schematics, the TC pin (EOP on western chips) is connected to NMI on the expansion port. + // NMIs seem to occur too quickly when this is active, so either EOP is not triggered at the correct time, or + // the K1810WT37 is different to the i8237/AM9517A + //MCFG_I8237_OUT_EOP_CB(DEVWRITELINE("^", cpc_expansion_slot_device, nmi_w)) // MCFG_DEVCB_INVERT + MCFG_I8237_OUT_HREQ_CB(DEVWRITELINE("dmac", am9517a_device, hack_w)) + MCFG_I8237_IN_MEMR_CB(READ8(al_magicsound_device,dma_read_byte)) + MCFG_I8237_OUT_IOW_0_CB(WRITE8(al_magicsound_device,dma_write_byte)) + MCFG_I8237_OUT_IOW_1_CB(WRITE8(al_magicsound_device,dma_write_byte)) + MCFG_I8237_OUT_IOW_2_CB(WRITE8(al_magicsound_device,dma_write_byte)) + MCFG_I8237_OUT_IOW_3_CB(WRITE8(al_magicsound_device,dma_write_byte)) + MCFG_I8237_OUT_DACK_0_CB(WRITELINE(al_magicsound_device, dack0_w)) + MCFG_I8237_OUT_DACK_1_CB(WRITELINE(al_magicsound_device, dack1_w)) + MCFG_I8237_OUT_DACK_2_CB(WRITELINE(al_magicsound_device, dack2_w)) + MCFG_I8237_OUT_DACK_3_CB(WRITELINE(al_magicsound_device, dack3_w)) + + // Timing does not seem to be correct. + // According to the schematics, the clock is from the clock pin on the expansion port (4MHz), and + // passes through an inverter to each CLK pin on both timers. This seems to be too fast. + // Timer outputs to SAM0/1/2/3 are sample clocks for each sound channel, D/A0 is the low bit of the channel select. + MCFG_DEVICE_ADD("timer1", PIT8254, 0) + MCFG_PIT8253_CLK0(XTAL_4MHz) + MCFG_PIT8253_OUT0_HANDLER(WRITELINE(al_magicsound_device,sam0_w)) + MCFG_PIT8253_CLK1(XTAL_4MHz) + MCFG_PIT8253_OUT1_HANDLER(WRITELINE(al_magicsound_device,sam1_w)) + MCFG_PIT8253_CLK2(XTAL_4MHz) + MCFG_PIT8253_OUT2_HANDLER(WRITELINE(al_magicsound_device,sam2_w)) + + MCFG_DEVICE_ADD("timer2", PIT8254, 0) + MCFG_PIT8253_CLK0(XTAL_4MHz) + MCFG_PIT8253_OUT0_HANDLER(WRITELINE(al_magicsound_device,sam3_w)) + MCFG_PIT8253_CLK1(XTAL_4MHz) + MCFG_PIT8253_OUT1_HANDLER(WRITELINE(al_magicsound_device,da0_w)) + MCFG_PIT8253_CLK2(XTAL_4MHz) + + MCFG_SPEAKER_STANDARD_MONO("mono") + MCFG_DAC_ADD("dac1") + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 1.00) + // no pass-through(?) +MACHINE_CONFIG_END + +machine_config_constructor al_magicsound_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( al_magicsound ); +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +al_magicsound_device::al_magicsound_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, AL_MAGICSOUND, "Magic Sound Board", tag, owner, clock, "al_magicsound", __FILE__), + device_cpc_expansion_card_interface(mconfig, *this), + m_dac1(*this,"dac1"), + m_dmac(*this,"dmac"), + m_timer1(*this,"timer1"), + m_timer2(*this,"timer2") +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void al_magicsound_device::device_start() +{ + device_t* cpu = machine().device("maincpu"); + address_space& space = cpu->memory().space(AS_IO); + m_slot = dynamic_cast(owner()); + + space.install_readwrite_handler(0xf8d0,0xf8df,0,0,read8_delegate(FUNC(al_magicsound_device::dmac_r),this),write8_delegate(FUNC(al_magicsound_device::dmac_w),this)); + space.install_write_handler(0xf9d0,0xf9df,0,0,write8_delegate(FUNC(al_magicsound_device::timer_w),this)); + space.install_write_handler(0xfad0,0xfadf,0,0,write8_delegate(FUNC(al_magicsound_device::volume_w),this)); + space.install_write_handler(0xfbd0,0xfbdf,0,0,write8_delegate(FUNC(al_magicsound_device::mapper_w),this)); + + m_ramptr = machine().device(":" RAM_TAG); + + for(int x=0;x<4;x++) + { + save_item(NAME(m_output[x]),x); + } +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void al_magicsound_device::device_reset() +{ + m_current_channel = -1; + m_current_output = 0; + set_timer_gate(false); +} + +READ8_MEMBER(al_magicsound_device::dmac_r) +{ + return m_dmac->read(space,offset); +} + +WRITE8_MEMBER(al_magicsound_device::dmac_w) +{ + m_dmac->write(space,offset,data); +} + +WRITE8_MEMBER(al_magicsound_device::timer_w) +{ + // can both PITs be selected at the same time? + if(offset & 0x08) + m_timer1->write(space,offset & 0x03,data); + if(offset & 0x04) + m_timer2->write(space,offset & 0x03,data); +} + +WRITE8_MEMBER(al_magicsound_device::volume_w) +{ + m_volume[offset & 0x03] = data & 0x3f; +} + +WRITE8_MEMBER(al_magicsound_device::mapper_w) +{ + UINT8 channel = (offset & 0x0c) >> 2; + UINT8 page = offset & 0x03; + m_page[channel][page] = (~(data) & 0x3f) * 0x4000; + set_timer_gate(true); +} + +WRITE_LINE_MEMBER(al_magicsound_device::da0_w) +{ + m_dac1->write_unsigned8(m_output[m_current_output++]); + if(m_current_output > 3) + m_current_output = 0; +} + +WRITE_LINE_MEMBER(al_magicsound_device::dack0_w) { m_dack[0] = state; } +WRITE_LINE_MEMBER(al_magicsound_device::dack1_w) { m_dack[1] = state; } +WRITE_LINE_MEMBER(al_magicsound_device::dack2_w) { m_dack[2] = state; } +WRITE_LINE_MEMBER(al_magicsound_device::dack3_w) { m_dack[3] = state; } + +WRITE_LINE_MEMBER(al_magicsound_device::sam0_w) { m_current_channel = 0; if(m_dack[0] && state) m_dmac->dreq0_w(1); } +WRITE_LINE_MEMBER(al_magicsound_device::sam1_w) { m_current_channel = 1; if(m_dack[1] && state) m_dmac->dreq1_w(1); } +WRITE_LINE_MEMBER(al_magicsound_device::sam2_w) { m_current_channel = 2; if(m_dack[2] && state) m_dmac->dreq2_w(1); } +WRITE_LINE_MEMBER(al_magicsound_device::sam3_w) { m_current_channel = 3; if(m_dack[3] && state) m_dmac->dreq3_w(1); } + +READ8_MEMBER(al_magicsound_device::dma_read_byte) +{ + UINT8 ret = 0xff; + UINT8 page = (offset & 0xc000) >> 14; + + if(m_current_channel != -1) + ret = m_ramptr->read(m_page[m_current_channel][page] + (offset & 0x3fff)); + return ret; +} + +WRITE8_MEMBER(al_magicsound_device::dma_write_byte) +{ + m_output[m_current_channel] = data; +} + +void al_magicsound_device::set_timer_gate(bool state) +{ + m_timer1->write_gate0(state); + m_timer1->write_gate1(state); + m_timer1->write_gate2(state); + m_timer2->write_gate0(state); + m_timer2->write_gate1(state); + m_timer2->write_gate2(state); +} + diff --git a/src/devices/bus/cpc/magicsound.h b/src/devices/bus/cpc/magicsound.h new file mode 100644 index 00000000000..3332dbee889 --- /dev/null +++ b/src/devices/bus/cpc/magicsound.h @@ -0,0 +1,91 @@ +// license:BSD-3-Clause +// copyright-holders:Barry Rodewald +/* + * magicsound.h + * + * Magic Sound Board for the Aleste 520EX + * + * DMA-based 4-channel sound board + * + * 1x K1810WT37 DMA controller (i8237/AM9517A) + * 2x K1810WT54 programmable timers (i8254) + * 1x K1118PA1 DAC (MC10318) + * + * I/O Ports: + * FxDx: selects the board + * F8Dx: DMA controller (R/w) + * F9Dx: PIT timers (A2 active for channels 0-2, A3 active for channels 3-5) (W/O) + * FADx: Volume control (A1-A0 = channel) (W/O, 6-bit) + * FBDx: Mapper (A1-A0 = mapper page number, A3-A2 = channel, D5-D0 = inverted page number) (W/O) + * + * Further info available here: http://cpcwiki.eu/index.php/Magic_Sound_Board + * + */ + +#ifndef MAGICSOUND_H_ +#define MAGICSOUND_H_ + +#include "emu.h" +#include "cpcexp.h" +#include "sound/dmadac.h" +#include "sound/dac.h" +#include "machine/am9517a.h" +#include "machine/pit8253.h" +#include "machine/ram.h" + +class al_magicsound_device : public device_t, + public device_cpc_expansion_card_interface +{ +public: + // construction/destruction + al_magicsound_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + + DECLARE_READ8_MEMBER(dmac_r); + DECLARE_WRITE8_MEMBER(dmac_w); + DECLARE_WRITE8_MEMBER(timer_w); + DECLARE_WRITE8_MEMBER(volume_w); + DECLARE_WRITE8_MEMBER(mapper_w); + DECLARE_WRITE_LINE_MEMBER(da0_w); + DECLARE_READ8_MEMBER(dma_read_byte); + DECLARE_WRITE8_MEMBER(dma_write_byte); + DECLARE_WRITE_LINE_MEMBER(dack0_w); + DECLARE_WRITE_LINE_MEMBER(dack1_w); + DECLARE_WRITE_LINE_MEMBER(dack2_w); + DECLARE_WRITE_LINE_MEMBER(dack3_w); + DECLARE_WRITE_LINE_MEMBER(sam0_w); + DECLARE_WRITE_LINE_MEMBER(sam1_w); + DECLARE_WRITE_LINE_MEMBER(sam2_w); + DECLARE_WRITE_LINE_MEMBER(sam3_w); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + +private: + cpc_expansion_slot_device *m_slot; + + required_device m_dac1; + required_device m_dmac; + required_device m_timer1; + required_device m_timer2; + + void set_timer_gate(bool state); + + UINT8 m_volume[4]; + UINT32 m_page[4][4]; + UINT8 m_output[4]; + bool m_dack[4]; + INT8 m_current_channel; + ram_device* m_ramptr; + UINT8 m_current_output; +}; + +// device type definition +extern const device_type AL_MAGICSOUND; + + +#endif /* MAGICSOUND_H_ */ diff --git a/src/devices/bus/cpc/mface2.c b/src/devices/bus/cpc/mface2.c new file mode 100644 index 00000000000..122f97fe46a --- /dev/null +++ b/src/devices/bus/cpc/mface2.c @@ -0,0 +1,343 @@ +// license:BSD-3-Clause +// copyright-holders:Kevin Thacker, Barry Rodewald +/* + * mface2.c -- Romantic Robot Multiface II expansion device for the Amstrad CPC/CPC+ + * + * Created on: 31/07/2011 + */ + +#include "emu.h" +#include "mface2.h" +#include "includes/amstrad.h" + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type CPC_MFACE2 = &device_creator; + +// device machine config +static MACHINE_CONFIG_FRAGMENT( cpc_mface2 ) + // pass-through + MCFG_DEVICE_ADD("exp", CPC_EXPANSION_SLOT, 0) + MCFG_DEVICE_SLOT_INTERFACE(cpc_exp_cards, NULL, false) + MCFG_CPC_EXPANSION_SLOT_OUT_IRQ_CB(DEVWRITELINE("^", cpc_expansion_slot_device, irq_w)) + MCFG_CPC_EXPANSION_SLOT_OUT_NMI_CB(DEVWRITELINE("^", cpc_expansion_slot_device, nmi_w)) + MCFG_CPC_EXPANSION_SLOT_OUT_ROMDIS_CB(DEVWRITELINE("^", cpc_expansion_slot_device, romdis_w)) // ROMDIS +MACHINE_CONFIG_END + +DIRECT_UPDATE_MEMBER( cpc_multiface2_device::amstrad_default ) +{ + return address; +} + +/* used to setup computer if a snapshot was specified */ +DIRECT_UPDATE_MEMBER( cpc_multiface2_device::amstrad_multiface_directoverride ) +{ + int pc; + + pc = machine().device("maincpu")->safe_pc(); + /* there are two places where CALL &0065 can be found + in the multiface rom. At this address there is a RET. + + To disable the multiface from being detected, the multiface + stop button must be pressed, then the program that was stopped + must be returned to. When this is done, the multiface cannot + be detected and the out operations to page the multiface + ram/rom into the address space will not work! */ + + /* I assume that the hardware in the multiface detects + the PC set to 0x065 and uses this to enable/disable the multiface + */ + + /* I also use this to allow the stop button to be pressed again */ + if (pc==0x0164) + { + /* first call? */ + m_multiface_flags |= MULTIFACE_VISIBLE; + } + else if (pc==0x0c98) + { + /* second call */ + + /* no longer visible */ + m_multiface_flags &= ~(MULTIFACE_VISIBLE|MULTIFACE_STOP_BUTTON_PRESSED); + + m_romdis=0; + + /* clear op base override */ + machine().device("maincpu")->memory().space(AS_PROGRAM).set_direct_update_handler(direct_update_delegate(FUNC(cpc_multiface2_device::amstrad_default),this)); + } + + return pc; +} + +int cpc_multiface2_device::multiface_hardware_enabled() +{ + if (m_multiface_ram!=NULL) + { + if ((ioport("multiface")->read() & 0x01)!=0) + { + return 1; + } + } + + return 0; +} + +/* multiface traps calls to 0x0065 when it is active. +This address has a RET and so executes no code. + +It is believed that it is used to make multiface invisible to programs */ + +/*#define MULTIFACE_0065_TOGGLE 0x0008*/ + + +void cpc_multiface2_device::multiface_rethink_memory() +{ + unsigned char *multiface_rom; + + /* multiface hardware enabled? */ + if (!multiface_hardware_enabled()) + return; + + multiface_rom = memregion("multiface")->base(); + + if ((m_multiface_flags & MULTIFACE_RAM_ROM_ENABLED)!=0 && m_romdis != 0) + { + /* set bank addressess */ + machine().root_device().membank("bank1")->set_base(multiface_rom); + machine().root_device().membank("bank2")->set_base(m_multiface_ram); + machine().root_device().membank("bank9")->set_base(multiface_rom); + machine().root_device().membank("bank10")->set_base(m_multiface_ram); + } +} + +machine_config_constructor cpc_multiface2_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( cpc_mface2 ); +} + +void cpc_multiface2_device::check_button_state() +{ + if(!multiface_hardware_enabled()) + return; + // TODO: reset button + if (ioport("multiface")->read() & 0x02) + { + multiface_stop(); + } +} + +/* simulate the stop button has been pressed */ +void cpc_multiface2_device::multiface_stop() +{ + /* multiface hardware enabled? */ + if (!multiface_hardware_enabled()) + return; + + /* if stop button not already pressed, do press action */ + /* pressing stop button while multiface is running has no effect */ + if ((m_multiface_flags & MULTIFACE_STOP_BUTTON_PRESSED)==0) + { + /* initialise 0065 toggle */ + /*state->m_multiface_flags &= ~MULTIFACE_0065_TOGGLE;*/ + + m_multiface_flags |= MULTIFACE_RAM_ROM_ENABLED; + + /* stop button has been pressed, furthur pressess will not issue a NMI */ + m_multiface_flags |= MULTIFACE_STOP_BUTTON_PRESSED; + + m_romdis = 1; + + /* page rom into memory */ + multiface_rethink_memory(); + + /* pulse the nmi line */ + m_slot->nmi_w(1); + m_slot->nmi_w(0); + + /* initialise 0065 override to monitor calls to 0065 */ + machine().device("maincpu")->memory().space(AS_PROGRAM).set_direct_update_handler(direct_update_delegate(FUNC(cpc_multiface2_device::amstrad_multiface_directoverride),this)); + } +} + +/* any io writes are passed through here */ +int cpc_multiface2_device::multiface_io_write(UINT16 offset, UINT8 data) +{ + int ret = 0; + + /* multiface hardware enabled? */ + if (!multiface_hardware_enabled()) + return 0; + + /* visible? */ + if (m_multiface_flags & MULTIFACE_VISIBLE) + { + if (offset==0x0fee8) + { + m_multiface_flags |= MULTIFACE_RAM_ROM_ENABLED; + ret = 1; + } + + if (offset==0x0feea) + { + m_multiface_flags &= ~MULTIFACE_RAM_ROM_ENABLED; + ret = 1; + } + } + + /* update multiface ram with data */ + /* these are decoded fully! */ + switch ((offset>>8) & 0x0ff) + { + /* gate array */ + case 0x07f: + { + switch (data & 0x0c0) + { + /* pen index */ + case 0x00: + { + m_multiface_ram[0x01fcf] = data; + } + break; + /* pen colour */ + case 0x040: + { + int pen_index; + pen_index = m_multiface_ram[0x01fcf] & 0x0f; + if (m_multiface_ram[0x01fcf] & 0x010) + { + m_multiface_ram[0x01fdf + pen_index] = data; + } + else + { + m_multiface_ram[0x01f90 + pen_index] = data & 0x01f; + } + } + break; + /* rom/mode selection */ + case 0x080: + { + m_multiface_ram[0x01fef] = data; + } + break; + /* ram configuration */ + case 0x0c0: + { + m_multiface_ram[0x01fff] = data; + } + break; + default: + break; + } + } + break; + + /* crtc register index */ + case 0x0bc: + { + m_multiface_ram[0x01cff] = data; + } + break; + /* crtc register write */ + case 0x0bd: + { + int reg_index; + reg_index = m_multiface_ram[0x01cff] & 0x0f; + m_multiface_ram[0x01db0 + reg_index] = data; + } + break; + + + /* 8255 ppi control */ + case 0x0f7: + { + m_multiface_ram[0x017ff] = data; + } + break; + /* rom select */ + case 0x0df: + { + m_multiface_ram[0x01aac] = data; + } + break; + default: + break; + } + return ret; +} + +static INPUT_PORTS_START(cpc_mface2) + PORT_START("multiface") + PORT_CONFNAME(0x01, 0x00, "Multiface Two" ) + PORT_CONFSETTING(0x00, DEF_STR( Off) ) + PORT_CONFSETTING(0x01, DEF_STR( On) ) + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_OTHER) PORT_NAME("Multiface Two's Stop Button") PORT_CODE(KEYCODE_F6) + // PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_OTHER) PORT_NAME("Multiface Two's Reset Button") PORT_CODE(KEYCODE_F3) Not implemented +INPUT_PORTS_END + + + +//------------------------------------------------- +// Device ROM definition +//------------------------------------------------- + +// Second known revision (1988) +ROM_START( cpc_mface2 ) + ROM_REGION( 0x2000, "multiface", 0 ) + ROM_LOAD("multface.rom", 0x0000, 0x2000, CRC(f36086de) SHA1(1431ec628d38f000715545dd2186b684c5fe5a6f)) +ROM_END + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *cpc_multiface2_device::device_rom_region() const +{ + return ROM_NAME( cpc_mface2 ); +} + +ioport_constructor cpc_multiface2_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( cpc_mface2 ); +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +cpc_multiface2_device::cpc_multiface2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, CPC_MFACE2, "Multiface II", tag, owner, clock, "cpc_mf2", __FILE__), + device_cpc_expansion_card_interface(mconfig, *this) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void cpc_multiface2_device::device_start() +{ + m_slot = dynamic_cast(owner()); + + /* after a reset the multiface is visible */ + m_multiface_flags = MULTIFACE_VISIBLE; + + /* allocate ram */ + m_multiface_ram = auto_alloc_array(machine(), UINT8, 8192); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void cpc_multiface2_device::device_reset() +{ + /* stop button not pressed and ram/rom disabled */ + m_multiface_flags &= ~(MULTIFACE_STOP_BUTTON_PRESSED | + MULTIFACE_RAM_ROM_ENABLED); + /* as on the real hardware the multiface is visible after a reset! */ + m_multiface_flags |= MULTIFACE_VISIBLE; +} diff --git a/src/devices/bus/cpc/mface2.h b/src/devices/bus/cpc/mface2.h new file mode 100644 index 00000000000..56eb017b208 --- /dev/null +++ b/src/devices/bus/cpc/mface2.h @@ -0,0 +1,71 @@ +// license:BSD-3-Clause +// copyright-holders:Kevin Thacker, Barry Rodewald +/* + * mface2.h -- Romantic Robot Multiface II expansion device for the Amstrad CPC/CPC+ + * + * Created on: 31/07/2011 + * + * I/O Ports: + * - FEE8: Enables Multiface ROM and RAM + * - FEEA: Disables Multiface ROM and RAM + * + * When enabled, Multiface ROM is mapped to &0000, and RAM to &2000 + * + * When the Stop button is pressed, the Multiface II will generate an NMI + * (I guess the ROM/RAM is enabled when you do this also?) + * + * It also monitors all I/O port writes, so that it can restore them when resuming the current application. + */ + +#ifndef MFACE2_H_ +#define MFACE2_H_ + +#include "emu.h" +#include "cpcexp.h" + +/* stop button has been pressed */ +#define MULTIFACE_STOP_BUTTON_PRESSED 0x0001 +/* ram/rom is paged into memory space */ +#define MULTIFACE_RAM_ROM_ENABLED 0x0002 +/* when visible OUT commands are performed! */ +#define MULTIFACE_VISIBLE 0x0004 + + +class cpc_multiface2_device : public device_t, + public device_cpc_expansion_card_interface +{ +public: + // construction/destruction + cpc_multiface2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual ioport_constructor device_input_ports() const; + virtual machine_config_constructor device_mconfig_additions() const; + + int multiface_hardware_enabled(); + void multiface_rethink_memory(); + void multiface_stop(); + int multiface_io_write(UINT16 offset, UINT8 data); + void check_button_state(); +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + +private: + cpc_expansion_slot_device *m_slot; + + DIRECT_UPDATE_MEMBER( amstrad_default ); + DIRECT_UPDATE_MEMBER( amstrad_multiface_directoverride ); + + unsigned char *m_multiface_ram; + unsigned long m_multiface_flags; + + UINT8 m_romdis; +}; + +// device type definition +extern const device_type CPC_MFACE2; + +#endif /* MFACE2_H_ */ diff --git a/src/devices/bus/cpc/playcity.c b/src/devices/bus/cpc/playcity.c new file mode 100644 index 00000000000..9686ce952f7 --- /dev/null +++ b/src/devices/bus/cpc/playcity.c @@ -0,0 +1,162 @@ +// license:BSD-3-Clause +// copyright-holders:Barry Rodewald +/* + PlayCity expansion device + + Z80 CTC + 2x YMZ294 (clocks provided by CTC) + + TODO: + IRQs aren't working currently, the Z80CTC core requires the daisy chain setup to acknowledge IRQs properly, and that can't be used in a slot device currently. +*/ + +#include "playcity.h" +#include "includes/amstrad.h" + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type CPC_PLAYCITY = &device_creator; + +// device machine config +static MACHINE_CONFIG_FRAGMENT( cpc_playcity ) + MCFG_DEVICE_ADD("ctc", Z80CTC, XTAL_4MHz) + MCFG_Z80CTC_ZC1_CB(WRITELINE(cpc_playcity_device,ctc_zc1_cb)) + MCFG_Z80CTC_ZC2_CB(DEVWRITELINE("ctc",z80ctc_device,trg3)) + MCFG_Z80CTC_INTR_CB(WRITELINE(cpc_playcity_device,ctc_intr_cb)) + + MCFG_SPEAKER_STANDARD_STEREO("lspeaker","rspeaker") + MCFG_SOUND_ADD("ymz_1",YMZ294,XTAL_4MHz) // when timer is not set, operates at 4MHz (interally divided by 2, so equivalent to the ST) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "rspeaker", 0.30) + MCFG_SOUND_ADD("ymz_2",YMZ294,XTAL_4MHz) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "lspeaker", 0.30) + + // pass-through + MCFG_DEVICE_ADD("exp", CPC_EXPANSION_SLOT, 0) + MCFG_DEVICE_SLOT_INTERFACE(cpc_exp_cards, NULL, false) + MCFG_CPC_EXPANSION_SLOT_OUT_IRQ_CB(DEVWRITELINE("^", cpc_expansion_slot_device, irq_w)) + MCFG_CPC_EXPANSION_SLOT_OUT_NMI_CB(DEVWRITELINE("^", cpc_expansion_slot_device, nmi_w)) + MCFG_CPC_EXPANSION_SLOT_OUT_ROMDIS_CB(DEVWRITELINE("^", cpc_expansion_slot_device, romdis_w)) // ROMDIS + +MACHINE_CONFIG_END + + +machine_config_constructor cpc_playcity_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( cpc_playcity ); +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +cpc_playcity_device::cpc_playcity_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, CPC_PLAYCITY, "PlayCity", tag, owner, clock, "cpc_playcity", __FILE__), + device_cpc_expansion_card_interface(mconfig, *this), + m_ctc(*this,"ctc"), + m_ymz1(*this,"ymz_1"), + m_ymz2(*this,"ymz_2") +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void cpc_playcity_device::device_start() +{ + device_t* cpu = machine().device("maincpu"); + address_space& space = cpu->memory().space(AS_IO); + m_slot = dynamic_cast(owner()); + + space.install_readwrite_handler(0xf880,0xf883,0,0,read8_delegate(FUNC(cpc_playcity_device::ctc_r),this),write8_delegate(FUNC(cpc_playcity_device::ctc_w),this)); + space.install_readwrite_handler(0xf884,0xf884,0,0,read8_delegate(FUNC(cpc_playcity_device::ymz1_data_r),this),write8_delegate(FUNC(cpc_playcity_device::ymz1_data_w),this)); + space.install_readwrite_handler(0xf888,0xf888,0,0,read8_delegate(FUNC(cpc_playcity_device::ymz2_data_r),this),write8_delegate(FUNC(cpc_playcity_device::ymz2_data_w),this)); + space.install_write_handler(0xf984,0xf984,0,0,write8_delegate(FUNC(cpc_playcity_device::ymz1_address_w),this)); + space.install_write_handler(0xf988,0xf988,0,0,write8_delegate(FUNC(cpc_playcity_device::ymz2_address_w),this)); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void cpc_playcity_device::device_reset() +{ +} + + +READ8_MEMBER(cpc_playcity_device::ctc_r) +{ + return m_ctc->read(space,offset); +} + +WRITE8_MEMBER(cpc_playcity_device::ctc_w) +{ + m_ctc->write(space,offset,data); + if(offset == 0) + update_ymz_clock(); +} + +WRITE8_MEMBER(cpc_playcity_device::ymz1_address_w) +{ + m_ymz1->address_w(space,offset,data); +} + +WRITE8_MEMBER(cpc_playcity_device::ymz2_address_w) +{ + m_ymz2->address_w(space,offset,data); +} + +WRITE8_MEMBER(cpc_playcity_device::ymz1_data_w) +{ + m_ymz1->data_w(space,offset,data); +} + +WRITE8_MEMBER(cpc_playcity_device::ymz2_data_w) +{ + m_ymz2->data_w(space,offset,data); +} + +READ8_MEMBER(cpc_playcity_device::ymz1_data_r) +{ + return m_ymz1->data_r(space,offset); +} + +READ8_MEMBER(cpc_playcity_device::ymz2_data_r) +{ + return m_ymz2->data_r(space,offset); +} + +void cpc_playcity_device::update_ymz_clock() +{ + // Bit of a hack job here, since there is no way currently to connect the CTC channel output directly to the YMZ clocks. + UINT8 rate = m_ctc->get_channel_constant(0); + UINT32 clk = XTAL_4MHz; + + switch(rate) + { + case 0x00: clk = 3980000; break; + case 0x01: clk = 2000000; break; + case 0x02: clk = 3000000; break; + case 0x03: clk = 3330000; break; + case 0x04: clk = 3500000; break; + case 0x05: clk = 3600000; break; + case 0x06: clk = 3670000; break; + case 0x07: clk = 3710000; break; + case 0x08: clk = 3750000; break; + case 0x09: clk = 3780000; break; + case 0x0a: clk = 3800000; break; + case 0x0b: clk = 3820000; break; + case 0x0c: clk = 3830000; break; + case 0x0d: clk = 3850000; break; + case 0x0e: clk = 3860000; break; + case 0x0f: clk = 3870000; break; + } + + clk = clk / 2; // YMZ294 has an internal /2 divider (not handled in AY core?) + m_ymz1->ay_set_clock(clk); + m_ymz2->ay_set_clock(clk); + popmessage("YMZ clocks set to %d Hz",clk); +} diff --git a/src/devices/bus/cpc/playcity.h b/src/devices/bus/cpc/playcity.h new file mode 100644 index 00000000000..d7abaa08c33 --- /dev/null +++ b/src/devices/bus/cpc/playcity.h @@ -0,0 +1,68 @@ +// license:BSD-3-Clause +// copyright-holders:Barry Rodewald +/* + PlayCity expansion device + + I/O ports: + * F880 - Z80CTC channel 0 (input is system clock (4MHz), output to YMZ294 clock) + * F881 - Z80CTC channel 1 (input from CRTC CURSOR, output to /NMI) + * F882 - Z80CTC channel 2 (input is system clock (4MHz), output to channel 3 input) + * F883 - Z80CTC channel 3 (input is channel 2 output) + * F884 - YMZ294 #1 (right) data + * F888 - YMZ294 #2 (left) data + * F984 - YMZ294 #1 (right) register select + * F988 - YMZ294 #2 (left) register select +*/ + +#ifndef CPC_PLAYCITY_H_ +#define CPC_PLAYCITY_H_ + + +#include "emu.h" +#include "cpcexp.h" +#include "sound/ay8910.h" +#include "machine/z80ctc.h" + +class cpc_playcity_device : public device_t, + public device_cpc_expansion_card_interface +{ +public: + // construction/destruction + cpc_playcity_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + + DECLARE_READ8_MEMBER(ctc_r); + DECLARE_WRITE8_MEMBER(ctc_w); + DECLARE_WRITE8_MEMBER(ymz1_address_w); + DECLARE_WRITE8_MEMBER(ymz2_address_w); + DECLARE_WRITE8_MEMBER(ymz1_data_w); + DECLARE_WRITE8_MEMBER(ymz2_data_w); + DECLARE_READ8_MEMBER(ymz1_data_r); + DECLARE_READ8_MEMBER(ymz2_data_r); + DECLARE_WRITE_LINE_MEMBER(ctc_zc1_cb) { if(state) { m_slot->nmi_w(1); m_slot->nmi_w(0); } } + DECLARE_WRITE_LINE_MEMBER(ctc_intr_cb) { m_slot->irq_w(state); } + + virtual WRITE_LINE_MEMBER(cursor_w) { m_ctc->trg1(state); } + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + +private: + cpc_expansion_slot_device *m_slot; + + required_device m_ctc; + required_device m_ymz1; + required_device m_ymz2; + + void update_ymz_clock(); +}; + +// device type definition +extern const device_type CPC_PLAYCITY; + + +#endif /* CPC_PLAYCITY_H_ */ diff --git a/src/devices/bus/cpc/smartwatch.c b/src/devices/bus/cpc/smartwatch.c new file mode 100644 index 00000000000..75cc3bb8a89 --- /dev/null +++ b/src/devices/bus/cpc/smartwatch.c @@ -0,0 +1,91 @@ +// license:BSD-3-Clause +// copyright-holders:Barry Rodewald +/* + Dobbertin Smartwatch + + Created: 23/2/2015 + + TODO: setting the time (requires the DS1315 core to be able to do this, + at the moment it just reads the current time) +*/ + +#include "emu.h" +#include "smartwatch.h" +#include "includes/amstrad.h" + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type CPC_SMARTWATCH = &device_creator; + + +static MACHINE_CONFIG_FRAGMENT( cpc_smartwatch ) + MCFG_DS1315_ADD("rtc") + // no pass-through (?) +MACHINE_CONFIG_END + +machine_config_constructor cpc_smartwatch_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( cpc_smartwatch ); +} + +ROM_START( cpc_smartwatch ) + ROM_REGION( 0x4000, "exp_rom", 0 ) + ROM_LOAD( "timerom+.rom", 0x0000, 0x4000, CRC(ed42a147) SHA1(61750d0535a1fbf2a4addad9def332cbcf8917c3) ) +ROM_END + +const rom_entry *cpc_smartwatch_device::device_rom_region() const +{ + return ROM_NAME( cpc_smartwatch ); +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +cpc_smartwatch_device::cpc_smartwatch_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, CPC_SMARTWATCH, "Dobbertin Smartwatch", tag, owner, clock, "cpc_smartwatch", __FILE__), + device_cpc_expansion_card_interface(mconfig, *this), + m_rtc(*this,"rtc") +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void cpc_smartwatch_device::device_start() +{ + m_slot = dynamic_cast(owner()); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void cpc_smartwatch_device::device_reset() +{ + device_t* cpu = machine().device(":maincpu"); + address_space& space = cpu->memory().space(AS_PROGRAM); + space.install_read_handler(0xc000,0xc001,0,0,read8_delegate(FUNC(cpc_smartwatch_device::rtc_w),this)); + space.install_read_handler(0xc004,0xc004,0,0,read8_delegate(FUNC(cpc_smartwatch_device::rtc_r),this)); + m_bank = membank(":bank7"); +} + +READ8_MEMBER(cpc_smartwatch_device::rtc_w) +{ + UINT8* bank = (UINT8*)m_bank->base(); + if(offset & 1) + m_rtc->read_1(space,0); + else + m_rtc->read_0(space,0); + return bank[offset & 1]; +} + +READ8_MEMBER(cpc_smartwatch_device::rtc_r) +{ + UINT8* bank = (UINT8*)m_bank->base(); + return ((bank[(offset & 1)+4]) & 0xfe) | (m_rtc->read_data(space,0) & 0x01); +} diff --git a/src/devices/bus/cpc/smartwatch.h b/src/devices/bus/cpc/smartwatch.h new file mode 100644 index 00000000000..3a4655f4304 --- /dev/null +++ b/src/devices/bus/cpc/smartwatch.h @@ -0,0 +1,48 @@ +// license:BSD-3-Clause +// copyright-holders:Barry Rodewald +/* + Dobbertin Smartwatch + + Dallas DS1216 Smartwatch + DS1315 Phantom Time chip + + Further info at: http://www.cpcwiki.eu/index.php/Dobbertin_Smart_Watch + +*/ + +#ifndef SMARTWATCH_H_ +#define SMARTWATCH_H_ + +#include "emu.h" +#include "cpcexp.h" +#include "machine/ds1315.h" + +class cpc_smartwatch_device : public device_t, + public device_cpc_expansion_card_interface +{ +public: + // construction/destruction + cpc_smartwatch_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual const rom_entry *device_rom_region() const; + + DECLARE_READ8_MEMBER(rtc_w); + DECLARE_READ8_MEMBER(rtc_r); +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + +private: + cpc_expansion_slot_device *m_slot; + + required_device m_rtc; + memory_bank* m_bank; +}; + +// device type definition +extern const device_type CPC_SMARTWATCH; + + +#endif /* SMARTWATCH_H_ */ diff --git a/src/devices/bus/cpc/symbfac2.c b/src/devices/bus/cpc/symbfac2.c new file mode 100644 index 00000000000..7fd8e756d5c --- /dev/null +++ b/src/devices/bus/cpc/symbfac2.c @@ -0,0 +1,295 @@ +// license:BSD-3-Clause +// copyright-holders:Barry Rodewald +/* + * symbfac2.c + * SYMBiFACE II expansion device + * - IDE + * - RTC (Dallas DS1287A) + * - PS/2 compatible mouse connector + * - 512kB RAM expansion + * - 512kB rewritable ROM + * + * Created on: 2/08/2014 + * + * TODO: + * - expansion RAM (for now handled by -ramsize) + * - rewritable ROM + * - mouse controls still need some work + */ + +#include "symbfac2.h" + + +const device_type CPC_SYMBIFACE2 = &device_creator; + +//************************************************************************** +// DEVICE CONFIG INTERFACE +//************************************************************************** + +// device machine config +static MACHINE_CONFIG_FRAGMENT( cpc_symbiface2 ) + MCFG_ATA_INTERFACE_ADD("ide",ata_devices,"hdd",NULL,false) + MCFG_DS12885_ADD("rtc") + MCFG_NVRAM_ADD_1FILL("nvram") + // no pass-through +MACHINE_CONFIG_END + +static INPUT_PORTS_START(cpc_symbiface2) + PORT_START("sf2_mouse_x") + PORT_BIT(0x3f , 0x00, IPT_MOUSE_X) PORT_SENSITIVITY(50) PORT_KEYDELTA(0) PORT_REVERSE PORT_PLAYER(1) PORT_CODE(MOUSECODE_X) PORT_CHANGED_MEMBER(DEVICE_SELF,cpc_symbiface2_device,mouse_change_x,NULL) + + PORT_START("sf2_mouse_y") + PORT_BIT(0x3f , 0x00, IPT_MOUSE_Y) PORT_SENSITIVITY(50) PORT_KEYDELTA(0) PORT_PLAYER(1) PORT_CODE(MOUSECODE_Y) PORT_CHANGED_MEMBER(DEVICE_SELF,cpc_symbiface2_device,mouse_change_x,NULL) + + PORT_START("sf2_mouse_buttons") + PORT_BIT(0x00000001, IP_ACTIVE_HIGH, IPT_OTHER) PORT_NAME("PS/2 Mouse left button") PORT_CODE(MOUSECODE_BUTTON1) PORT_CHANGED_MEMBER(DEVICE_SELF,cpc_symbiface2_device,mouse_change_x,NULL) + PORT_BIT(0x00000002, IP_ACTIVE_HIGH, IPT_OTHER) PORT_NAME("PS/2 Mouse right button") PORT_CODE(MOUSECODE_BUTTON3) PORT_CHANGED_MEMBER(DEVICE_SELF,cpc_symbiface2_device,mouse_change_x,NULL) + PORT_BIT(0x00000004, IP_ACTIVE_HIGH, IPT_OTHER) PORT_NAME("PS/2 Mouse middle button") PORT_CODE(MOUSECODE_BUTTON2) PORT_CHANGED_MEMBER(DEVICE_SELF,cpc_symbiface2_device,mouse_change_x,NULL) + PORT_BIT(0x00000008, IP_ACTIVE_HIGH, IPT_OTHER) PORT_NAME("PS/2 Mouse back button") PORT_CODE(MOUSECODE_BUTTON4) PORT_CHANGED_MEMBER(DEVICE_SELF,cpc_symbiface2_device,mouse_change_x,NULL) + PORT_BIT(0x00000010, IP_ACTIVE_HIGH, IPT_OTHER) PORT_NAME("PS/2 Mouse forward button") PORT_CODE(MOUSECODE_BUTTON5) PORT_CHANGED_MEMBER(DEVICE_SELF,cpc_symbiface2_device,mouse_change_x,NULL) + + // TODO: mouse scroll wheel support +// PORT_START("sf2_mouse_scroll") +// PORT_BIT(0x1f , 0, IPT_TRACKBALL_Y) +// PORT_SENSITIVITY(100) +// PORT_KEYDELTA(10) +// PORT_PLAYER(1) +INPUT_PORTS_END + + +machine_config_constructor cpc_symbiface2_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( cpc_symbiface2 ); +} + +ioport_constructor cpc_symbiface2_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( cpc_symbiface2 ); +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +cpc_symbiface2_device::cpc_symbiface2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, CPC_SYMBIFACE2, "SYMBiFACE II", tag, owner, clock, "cpc_symf2", __FILE__), + device_cpc_expansion_card_interface(mconfig, *this), + m_ide(*this,"ide"), + m_rtc(*this,"rtc"), + m_nvram(*this,"nvram"), + m_mouse_x(*this,"sf2_mouse_x"), + m_mouse_y(*this,"sf2_mouse_y"), + m_mouse_buttons(*this,"sf2_mouse_buttons") +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void cpc_symbiface2_device::device_start() +{ + device_t* cpu = machine().device("maincpu"); + address_space& space = cpu->memory().space(AS_IO); + + m_slot = dynamic_cast(owner()); + + space.install_readwrite_handler(0xfd00,0xfd07,0,0,read8_delegate(FUNC(cpc_symbiface2_device::ide_cs1_r),this),write8_delegate(FUNC(cpc_symbiface2_device::ide_cs1_w),this)); + space.install_readwrite_handler(0xfd08,0xfd0f,0,0,read8_delegate(FUNC(cpc_symbiface2_device::ide_cs0_r),this),write8_delegate(FUNC(cpc_symbiface2_device::ide_cs0_w),this)); + space.install_read_handler(0xfd10,0xfd10,0,0,read8_delegate(FUNC(cpc_symbiface2_device::mouse_r),this)); + space.install_readwrite_handler(0xfd14,0xfd15,0,0,read8_delegate(FUNC(cpc_symbiface2_device::rtc_r),this),write8_delegate(FUNC(cpc_symbiface2_device::rtc_w),this)); + space.install_readwrite_handler(0xfd17,0xfd17,0,0,read8_delegate(FUNC(cpc_symbiface2_device::rom_rewrite_r),this),write8_delegate(FUNC(cpc_symbiface2_device::rom_rewrite_w),this)); + + // set up ROM space (these can be writable, when mapped to &4000, or completely disabled, allowing the built-in ROMs to be visible) + // 32 banks of 16kB (512kB) + m_rom_space.resize(32*16384); + + m_nvram->set_base(&m_rom_space[0],m_rom_space.size()); + save_item(NAME(m_rom_space)); + +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void cpc_symbiface2_device::device_reset() +{ + m_iohigh = false; + m_mouse_state = PS2_MOUSE_IDLE; + m_input_x = m_mouse_x->read() & 0x3f; + m_input_y = m_mouse_y->read() & 0x3f; +} + +// IDE controller (custom) +// #FD00-07 - CS1 +// #FD08-0F - CS0 +READ8_MEMBER(cpc_symbiface2_device::ide_cs0_r) +{ + // data is returned in words, so it must be buffered + if(offset == 0x00) // data register + { + if(m_iohigh) + { + m_iohigh = false; + return m_ide_data >> 8; + } + else + { + m_iohigh = true; + m_ide_data = m_ide->read_cs0(space,offset); + return m_ide_data & 0xff; + } + } + else + return m_ide->read_cs0(space,offset); +} + +WRITE8_MEMBER(cpc_symbiface2_device::ide_cs0_w) +{ + m_ide->write_cs0(space,offset,data); +} + +READ8_MEMBER(cpc_symbiface2_device::ide_cs1_r) +{ + return m_ide->read_cs1(space,offset); +} + +WRITE8_MEMBER(cpc_symbiface2_device::ide_cs1_w) +{ + m_ide->write_cs1(space,offset,data); +} + +// RTC (Dallas DS1287A) +// #FD15 (write only) register select +// #FD14 (read/write) read from or write into selected register +READ8_MEMBER(cpc_symbiface2_device::rtc_r) +{ + switch(offset & 0x01) + { + case 0x00: + return m_rtc->read(space,1); + case 0x01: + return m_rtc->read(space,0); + } + return 0; +} + +WRITE8_MEMBER(cpc_symbiface2_device::rtc_w) +{ + switch(offset & 0x01) + { + case 0x00: + m_rtc->write(space,1,data); + break; + case 0x01: + m_rtc->write(space,0,data); + break; + } +} + +// PS/2 Mouse connector +// #FD10 (read only) read mouse status +/* + Status byte + Bit 76543210 + Use mmDDDDDD + + m: Mode + D: Use-Data + + If read and... + + m = 00 -> no more data available, you can stop reading the status for a while + m = 01 -> D = X offset (signed); you will receive positive values, if the user + is moving the mouse to the right + m = 10 -> D = Y offset (signed); you will receive positive values, if the user + is moving the mouse upwards + m = 11 -> D[bit5] = 0 -> D[bit0] = left button + D[bit1] = right button + D[bit2] = middle button + D[bit3] = forward button + D[bit4] = backward button + D[bit5] = 1 -> D[bit0-4] = scroll wheel offset (signed) + */ +READ8_MEMBER(cpc_symbiface2_device::mouse_r) +{ + UINT8 ret = 0; + int input; + int input_diff; + + switch(m_mouse_state) + { + case PS2_MOUSE_IDLE: + m_mouse_state = PS2_MOUSE_IDLE; + ret = 0; + break; + case PS2_MOUSE_X: + input = m_mouse_x->read() & 0x3f; + input_diff = m_input_x - input; + ret = 0x40 | (input_diff & 0x3f); + m_input_x = input; + m_mouse_state = PS2_MOUSE_Y; + break; + case PS2_MOUSE_Y: + input = m_mouse_y->read() & 0x3f; + input_diff = m_input_y - input; + ret = 0x80 | (input_diff & 0x3f); + m_input_y = input; + m_mouse_state = PS2_MOUSE_BUTTONS; + break; + case PS2_MOUSE_BUTTONS: + ret = 0xc0 | (m_mouse_buttons->read() & 0x1f); + m_mouse_state = PS2_MOUSE_IDLE; + break; + case PS2_MOUSE_SCROLL: + m_mouse_state = PS2_MOUSE_IDLE; + break; // TODO + } + //popmessage("Mouse: X: %02x Y: %02x\n",m_input_x,m_input_y); + return ret; +} + +INPUT_CHANGED_MEMBER(cpc_symbiface2_device::mouse_change_x) +{ + m_mouse_state = PS2_MOUSE_X; +} + +INPUT_CHANGED_MEMBER(cpc_symbiface2_device::mouse_change_y) +{ + m_mouse_state = PS2_MOUSE_Y; +} + +INPUT_CHANGED_MEMBER(cpc_symbiface2_device::mouse_change_buttons) +{ + m_mouse_state = PS2_MOUSE_BUTTONS; +} + +// #FD17 (read) - map currently selected ROM to 0x4000 for read/write +READ8_MEMBER(cpc_symbiface2_device::rom_rewrite_r) +{ + UINT8 bank = get_rom_bank(); + + if(bank >= 32) + return 0xff; + + m_4xxx_ptr_r = (UINT8*)machine().root_device().membank("bank3")->base(); + m_4xxx_ptr_w = (UINT8*)machine().root_device().membank("bank11")->base(); + m_6xxx_ptr_r = (UINT8*)machine().root_device().membank("bank4")->base(); + m_6xxx_ptr_w = (UINT8*)machine().root_device().membank("bank12")->base(); + machine().root_device().membank("bank3")->set_base(&m_rom_space[bank*16384]); + machine().root_device().membank("bank4")->set_base(&m_rom_space[bank*16384+8192]); + machine().root_device().membank("bank11")->set_base(&m_rom_space[bank*16384]); + machine().root_device().membank("bank12")->set_base(&m_rom_space[bank*16384+8192]); + + return 0xff; +} + +// #FD17 (write) - unmap selected ROM at 0x4000 +WRITE8_MEMBER(cpc_symbiface2_device::rom_rewrite_w) +{ + machine().root_device().membank("bank3")->set_base(m_4xxx_ptr_r); + machine().root_device().membank("bank4")->set_base(m_6xxx_ptr_r); + machine().root_device().membank("bank11")->set_base(m_4xxx_ptr_w); + machine().root_device().membank("bank12")->set_base(m_4xxx_ptr_w); +} diff --git a/src/devices/bus/cpc/symbfac2.h b/src/devices/bus/cpc/symbfac2.h new file mode 100644 index 00000000000..2392dbf7bd0 --- /dev/null +++ b/src/devices/bus/cpc/symbfac2.h @@ -0,0 +1,85 @@ +// license:BSD-3-Clause +// copyright-holders:Barry Rodewald +/* + * symbfac2.h + * + * Created on: 2/08/2014 + */ + +#ifndef SYMBFAC2_H_ +#define SYMBFAC2_H_ + +#include "emu.h" +#include "machine/ataintf.h" +#include "machine/ds128x.h" +#include "machine/nvram.h" +#include "cpcexp.h" + +class cpc_symbiface2_device : public device_t, + public device_cpc_expansion_card_interface +{ +public: + // construction/destruction + cpc_symbiface2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual ioport_constructor device_input_ports() const; + + DECLARE_READ8_MEMBER(ide_cs0_r); + DECLARE_WRITE8_MEMBER(ide_cs0_w); + DECLARE_READ8_MEMBER(ide_cs1_r); + DECLARE_WRITE8_MEMBER(ide_cs1_w); + DECLARE_READ8_MEMBER(rtc_r); + DECLARE_WRITE8_MEMBER(rtc_w); + DECLARE_READ8_MEMBER(mouse_r); + DECLARE_READ8_MEMBER(rom_rewrite_r); + DECLARE_WRITE8_MEMBER(rom_rewrite_w); + DECLARE_INPUT_CHANGED_MEMBER(mouse_change_x); + DECLARE_INPUT_CHANGED_MEMBER(mouse_change_y); + DECLARE_INPUT_CHANGED_MEMBER(mouse_change_buttons); + + enum + { + PS2_MOUSE_IDLE = 0, + PS2_MOUSE_X, + PS2_MOUSE_Y, + PS2_MOUSE_BUTTONS, + PS2_MOUSE_SCROLL + }; +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + +private: + cpc_expansion_slot_device *m_slot; + required_device m_ide; + required_device m_rtc; + required_device m_nvram; + + required_ioport m_mouse_x; + required_ioport m_mouse_y; + required_ioport m_mouse_buttons; + + dynamic_buffer m_rom_space; + + bool m_iohigh; + UINT16 m_ide_data; + + UINT8 m_mouse_state; + UINT8 m_input_x; + UINT8 m_input_y; + + // stores backup pointers so that mapping can be restored + UINT8* m_4xxx_ptr_r; + UINT8* m_4xxx_ptr_w; + UINT8* m_6xxx_ptr_r; + UINT8* m_6xxx_ptr_w; +}; + +// device type definition +extern const device_type CPC_SYMBIFACE2; + + +#endif /* SYMBFAC2_H_ */ diff --git a/src/devices/bus/crvision/rom.c b/src/devices/bus/crvision/rom.c new file mode 100644 index 00000000000..875a2b40fbc --- /dev/null +++ b/src/devices/bus/crvision/rom.c @@ -0,0 +1,140 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + V-Tech CreatiVision cart emulation + + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "rom.h" + + +//------------------------------------------------- +// crvision_rom_device - constructor +//------------------------------------------------- + +const device_type CRVISION_ROM_4K = &device_creator; +const device_type CRVISION_ROM_6K = &device_creator; +const device_type CRVISION_ROM_8K = &device_creator; +const device_type CRVISION_ROM_10K = &device_creator; +const device_type CRVISION_ROM_12K = &device_creator; +const device_type CRVISION_ROM_16K = &device_creator; +const device_type CRVISION_ROM_18K = &device_creator; + + +crvision_rom_device::crvision_rom_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_crvision_cart_interface(mconfig, *this) +{ +} + +crvision_rom_device::crvision_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, CRVISION_ROM_4K, "CreatiVision 4K Carts", tag, owner, clock, "crvision_4k", __FILE__), + device_crvision_cart_interface(mconfig, *this) +{ +} + +crvision_rom6k_device::crvision_rom6k_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : crvision_rom_device(mconfig, CRVISION_ROM_6K, "CreatiVision 6K Carts", tag, owner, clock, "crvision_6k", __FILE__) +{ +} + +crvision_rom8k_device::crvision_rom8k_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : crvision_rom_device(mconfig, CRVISION_ROM_8K, "CreatiVision 8K Carts", tag, owner, clock, "crvision_8k", __FILE__) +{ +} + +crvision_rom10k_device::crvision_rom10k_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : crvision_rom_device(mconfig, CRVISION_ROM_10K, "CreatiVision 10K Carts", tag, owner, clock, "crvision_10k", __FILE__) +{ +} + +crvision_rom12k_device::crvision_rom12k_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : crvision_rom_device(mconfig, CRVISION_ROM_12K, "CreatiVision 12K Carts", tag, owner, clock, "crvision_12k", __FILE__) +{ +} + +crvision_rom16k_device::crvision_rom16k_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : crvision_rom_device(mconfig, CRVISION_ROM_16K, "CreatiVision 16K Carts", tag, owner, clock, "crvision_16k", __FILE__) +{ +} + +crvision_rom18k_device::crvision_rom18k_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : crvision_rom_device(mconfig, CRVISION_ROM_18K, "CreatiVision 18K Carts", tag, owner, clock, "crvision_18k", __FILE__) +{ +} + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +READ8_MEMBER(crvision_rom_device::read_rom80) +{ + offset &= 0x1fff; + if (offset < 0x1000) + return 0xff; + + return m_rom[offset & 0xfff]; +} + + +READ8_MEMBER(crvision_rom6k_device::read_rom80) +{ + offset &= 0x1fff; + if (offset < 0x1000) + return m_rom[0x1000 + (offset & 0x7ff)]; + + return m_rom[offset & 0xfff]; +} + + +READ8_MEMBER(crvision_rom8k_device::read_rom80) +{ + return m_rom[offset & 0x1fff]; +} + + +READ8_MEMBER(crvision_rom10k_device::read_rom80) +{ + return m_rom[offset & 0x1fff]; +} + +READ8_MEMBER(crvision_rom10k_device::read_rom40) +{ + return m_rom[0x2000 + (offset & 0x7ff)]; +} + + +READ8_MEMBER(crvision_rom12k_device::read_rom80) +{ + return m_rom[offset & 0x1fff]; +} + +READ8_MEMBER(crvision_rom12k_device::read_rom40) +{ + return m_rom[0x2000 + (offset & 0xfff)]; +} + + +READ8_MEMBER(crvision_rom16k_device::read_rom80) +{ + // lower 8K in 0xa000-0xbfff, higher 8K in 0x8000-0x9fff + return m_rom[offset ^ 0x2000]; +} + + +READ8_MEMBER(crvision_rom18k_device::read_rom80) +{ + // lower 8K in 0xa000-0xbfff, higher 8K in 0x8000-0x9fff + return m_rom[offset ^ 0x2000]; +} + +READ8_MEMBER(crvision_rom18k_device::read_rom40) +{ + return m_rom[0x4000 + (offset & 0x7ff)]; +} diff --git a/src/devices/bus/crvision/rom.h b/src/devices/bus/crvision/rom.h new file mode 100644 index 00000000000..2d8330f0d1e --- /dev/null +++ b/src/devices/bus/crvision/rom.h @@ -0,0 +1,116 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __CRVISION_ROM_H +#define __CRVISION_ROM_H + +#include "slot.h" + + +// ======================> crvision_rom_device + +class crvision_rom_device : public device_t, + public device_crvision_cart_interface +{ +public: + // construction/destruction + crvision_rom_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + crvision_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start() {} + virtual void device_reset() {} + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_rom80); +}; + +// ======================> crvision_rom6k_device + +class crvision_rom6k_device : public crvision_rom_device +{ +public: + // construction/destruction + crvision_rom6k_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_rom80); +}; + +// ======================> crvision_rom8k_device + +class crvision_rom8k_device : public crvision_rom_device +{ +public: + // construction/destruction + crvision_rom8k_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_rom80); +}; + +// ======================> crvision_rom10k_device + +class crvision_rom10k_device : public crvision_rom_device +{ +public: + // construction/destruction + crvision_rom10k_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_rom40); + virtual DECLARE_READ8_MEMBER(read_rom80); +}; + +// ======================> crvision_rom12k_device + +class crvision_rom12k_device : public crvision_rom_device +{ +public: + // construction/destruction + crvision_rom12k_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_rom40); + virtual DECLARE_READ8_MEMBER(read_rom80); +}; + +// ======================> crvision_rom16k_device + +class crvision_rom16k_device : public crvision_rom_device +{ +public: + // construction/destruction + crvision_rom16k_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_rom80); +}; + +// ======================> crvision_rom18k_device + +class crvision_rom18k_device : public crvision_rom_device +{ +public: + // construction/destruction + crvision_rom18k_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_rom40); + virtual DECLARE_READ8_MEMBER(read_rom80); +}; + + + + + +// device type definition +extern const device_type CRVISION_ROM_4K; +extern const device_type CRVISION_ROM_6K; +extern const device_type CRVISION_ROM_8K; +extern const device_type CRVISION_ROM_10K; +extern const device_type CRVISION_ROM_12K; +extern const device_type CRVISION_ROM_16K; +extern const device_type CRVISION_ROM_18K; + + +#endif diff --git a/src/devices/bus/crvision/slot.c b/src/devices/bus/crvision/slot.c new file mode 100644 index 00000000000..af3bce0a016 --- /dev/null +++ b/src/devices/bus/crvision/slot.c @@ -0,0 +1,295 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + V-Tech CreatiVision cart emulation + (through slot devices) + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "slot.h" + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type CRVISION_CART_SLOT = &device_creator; + +//************************************************************************** +// CreatiVision Cartridges Interface +//************************************************************************** + +//------------------------------------------------- +// device_crvision_cart_interface - constructor +//------------------------------------------------- + +device_crvision_cart_interface::device_crvision_cart_interface(const machine_config &mconfig, device_t &device) + : device_slot_card_interface(mconfig, device), + m_rom(NULL), + m_rom_size(0) +{ +} + + +//------------------------------------------------- +// ~device_crvision_cart_interface - destructor +//------------------------------------------------- + +device_crvision_cart_interface::~device_crvision_cart_interface() +{ +} + +//------------------------------------------------- +// rom_alloc - alloc the space for the cart +//------------------------------------------------- + +void device_crvision_cart_interface::rom_alloc(UINT32 size, const char *tag) +{ + if (m_rom == NULL) + { + m_rom = device().machine().memory().region_alloc(std::string(tag).append(CRVSLOT_ROM_REGION_TAG).c_str(), size, 1, ENDIANNESS_LITTLE)->base(); + m_rom_size = size; + } +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// crvision_cart_slot_device - constructor +//------------------------------------------------- +crvision_cart_slot_device::crvision_cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, CRVISION_CART_SLOT, "CreatiVision Cartridge Slot", tag, owner, clock, "crvision_cart_slot", __FILE__), + device_image_interface(mconfig, *this), + device_slot_interface(mconfig, *this), + m_type(CRV_4K) +{ +} + + +//------------------------------------------------- +// crvision_cart_slot_device - destructor +//------------------------------------------------- + +crvision_cart_slot_device::~crvision_cart_slot_device() +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void crvision_cart_slot_device::device_start() +{ + m_cart = dynamic_cast(get_card_device()); +} + +//------------------------------------------------- +// device_config_complete - perform any +// operations now that the configuration is +// complete +//------------------------------------------------- + +void crvision_cart_slot_device::device_config_complete() +{ + // set brief and instance name + update_names(); +} + + +//------------------------------------------------- +// APF PCB +//------------------------------------------------- + +struct crvision_slot +{ + int pcb_id; + const char *slot_option; +}; + +// Here, we take the feature attribute from .xml (i.e. the PCB name) and we assign a unique ID to it +static const crvision_slot slot_list[] = +{ + { CRV_4K, "crv_rom4k" }, + { CRV_6K, "crv_rom6k" }, + { CRV_8K, "crv_rom8k" }, + { CRV_10K, "crv_rom10k" }, + { CRV_12K, "crv_rom12k" }, + { CRV_16K, "crv_rom16k" }, + { CRV_18K, "crv_rom18k" } +}; + +static int crvision_get_pcb_id(const char *slot) +{ + for (int i = 0; i < ARRAY_LENGTH(slot_list); i++) + { + if (!core_stricmp(slot_list[i].slot_option, slot)) + return slot_list[i].pcb_id; + } + + return 0; +} + +static const char *crvision_get_slot(int type) +{ + for (int i = 0; i < ARRAY_LENGTH(slot_list); i++) + { + if (slot_list[i].pcb_id == type) + return slot_list[i].slot_option; + } + + return "crv_rom4k"; +} + + +/*------------------------------------------------- + call load + -------------------------------------------------*/ + +bool crvision_cart_slot_device::call_load() +{ + if (m_cart) + { + UINT32 size = (software_entry() == NULL) ? length() : get_software_region_length("rom"); + + if (size > 0x4800) + { + seterror(IMAGE_ERROR_UNSPECIFIED, "Image extends beyond the expected size for an APF cart"); + return IMAGE_INIT_FAIL; + } + + m_cart->rom_alloc(size, tag()); + + if (software_entry() == NULL) + fread(m_cart->get_rom_base(), size); + else + memcpy(m_cart->get_rom_base(), get_software_region("rom"), size); + + if (software_entry() == NULL) + { + m_type = CRV_4K; + + switch (size) + { + case 0x4800: + m_type = CRV_18K; + break; + case 0x4000: + m_type = CRV_16K; + break; + case 0x3000: + m_type = CRV_12K; + break; + case 0x2800: + m_type = CRV_10K; + break; + case 0x2000: + m_type = CRV_8K; + break; + case 0x1800: + m_type = CRV_6K; + break; + case 0x1000: + default: + break; + } + } + else + { + const char *pcb_name = get_feature("slot"); + if (pcb_name) + m_type = crvision_get_pcb_id(pcb_name); + } + + printf("Type: %s\n", crvision_get_slot(m_type)); + + return IMAGE_INIT_PASS; + } + + return IMAGE_INIT_PASS; +} + + +/*------------------------------------------------- + call softlist load + -------------------------------------------------*/ + +bool crvision_cart_slot_device::call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry) +{ + load_software_part_region(*this, swlist, swname, start_entry); + return TRUE; +} + + +/*------------------------------------------------- + get default card software + -------------------------------------------------*/ + +void crvision_cart_slot_device::get_default_card_software(std::string &result) +{ + if (open_image_file(mconfig().options())) + { + const char *slot_string = "crv_rom4k"; + UINT32 size = core_fsize(m_file); + int type = CRV_4K; + + switch (size) + { + case 0x4800: + type = CRV_18K; + break; + case 0x4000: + type = CRV_16K; + break; + case 0x3000: + type = CRV_12K; + break; + case 0x2800: + type = CRV_10K; + break; + case 0x2000: + type = CRV_8K; + break; + case 0x1800: + type = CRV_6K; + break; + case 0x1000: + default: + break; + } + + slot_string = crvision_get_slot(type); + + //printf("type: %s\n", slot_string); + clear(); + + result.assign(slot_string); + return; + } + + software_get_default_slot(result, "crv_rom4k"); +} + +/*------------------------------------------------- + read_rom + -------------------------------------------------*/ + +READ8_MEMBER(crvision_cart_slot_device::read_rom40) +{ + if (m_cart) + return m_cart->read_rom40(space, offset); + else + return 0xff; +} + +READ8_MEMBER(crvision_cart_slot_device::read_rom80) +{ + if (m_cart) + return m_cart->read_rom80(space, offset); + else + return 0xff; +} diff --git a/src/devices/bus/crvision/slot.h b/src/devices/bus/crvision/slot.h new file mode 100644 index 00000000000..006f1522d40 --- /dev/null +++ b/src/devices/bus/crvision/slot.h @@ -0,0 +1,108 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __CRVISION_SLOT_H +#define __CRVISION_SLOT_H + +/*************************************************************************** + TYPE DEFINITIONS + ***************************************************************************/ + + +/* PCB */ +enum +{ + CRV_4K = 0, + CRV_6K, + CRV_8K, + CRV_10K, + CRV_12K, + CRV_16K, + CRV_18K +}; + + +// ======================> device_crvision_cart_interface + +class device_crvision_cart_interface : public device_slot_card_interface +{ +public: + // construction/destruction + device_crvision_cart_interface(const machine_config &mconfig, device_t &device); + virtual ~device_crvision_cart_interface(); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_rom40) { return 0xff; } + virtual DECLARE_READ8_MEMBER(read_rom80) { return 0xff; } + + void rom_alloc(UINT32 size, const char *tag); + UINT8* get_rom_base() { return m_rom; } + UINT32 get_rom_size() { return m_rom_size; } + +protected: + // internal state + UINT8 *m_rom; + UINT32 m_rom_size; +}; + + +// ======================> crvision_cart_slot_device + +class crvision_cart_slot_device : public device_t, + public device_image_interface, + public device_slot_interface +{ +public: + // construction/destruction + crvision_cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual ~crvision_cart_slot_device(); + + // device-level overrides + virtual void device_start(); + virtual void device_config_complete(); + + // image-level overrides + virtual bool call_load(); + virtual void call_unload() {} + virtual bool call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry); + + int get_type() { return m_type; } + + virtual iodevice_t image_type() const { return IO_CARTSLOT; } + virtual bool is_readable() const { return 1; } + virtual bool is_writeable() const { return 0; } + virtual bool is_creatable() const { return 0; } + virtual bool must_be_loaded() const { return 0; } + virtual bool is_reset_on_load() const { return 1; } + virtual const option_guide *create_option_guide() const { return NULL; } + virtual const char *image_interface() const { return "crvision_cart"; } + virtual const char *file_extensions() const { return "bin,rom"; } + + // slot interface overrides + virtual void get_default_card_software(std::string &result); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_rom40); + virtual DECLARE_READ8_MEMBER(read_rom80); + +protected: + + int m_type; + device_crvision_cart_interface* m_cart; +}; + + + +// device type definition +extern const device_type CRVISION_CART_SLOT; + + +/*************************************************************************** + DEVICE CONFIGURATION MACROS + ***************************************************************************/ + +#define CRVSLOT_ROM_REGION_TAG ":cart:rom" + +#define MCFG_CRVISION_CARTRIDGE_ADD(_tag,_slot_intf,_def_slot) \ + MCFG_DEVICE_ADD(_tag, CRVISION_CART_SLOT, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) +#endif diff --git a/src/devices/bus/dmv/dmvbus.c b/src/devices/bus/dmv/dmvbus.c new file mode 100644 index 00000000000..7e1a45779c9 --- /dev/null +++ b/src/devices/bus/dmv/dmvbus.c @@ -0,0 +1,381 @@ +// license:BSD-3-Clause +// copyright-holders:Sandro Ronco +/********************************************************************* + + NCR Decision mate slot bus and module emulation + + From the NCR System Technical manual: + + "The lower part of the controller board contains the I/0 bus together with + seven user-accessible connectors. These connectors are identified on the board + as J1 through J7 (reading from left to right), and correspond to the seven slots + (numbers 1 through 7) at the rear of the cabinet. + Position J1 is reserved for the connection of any one of the memory expansion modules + (K200, K202, K208). + Position J7 is reserved for the connection of either the diagnostic module (K220), + or the customer-installable 16-bit processor module (K231). + Positions J2 through J6 are the general purpose slots for the connection of the peripheral + adapter and other interfaces to the computer. These five positions are identical, and Figure 2.2 + defines the type of connector, while the pin assignments are shown in Figure 2.3." + + Pinout (/ indicates an inverted signal, ie, one that would have a bar over it + on a schematic diagram) + + a c + |-------------------------| + |+5V 1 +5 V | + | | + | 2 +12 V | + | | + System Reset Output, act. low |RESET/ 3 RESET IN/| active low, general system RESET + | | + I/O Write |IOW/ 4 IOR/ | I/O read R/W lines are Processor control lines + | | + Memory Write |MEMW/ 5 MEMR/ | Memory read active low, Tri-State possible + | | + BD0-BD7: Switch by IFSEL |BD1 6 BDO | BD0 - BD7: Data-Bus lines (8 bit) + (I/O-Read). Normal Output. | | bidirectional, active high + |BD3 7 BD2 | + | | + Direction can be changed |BD5 8 BD4 | Bus-Driver to peripheral Bus (LS245) + by DIR/ signal. | | automatic detection + |BD7 9 BD6 | + | | + Ready Signal from the |READY DMA 10 ABTRI / | Address Bus Tri-State, active low signal + mem. contr. (XACK), act. hi. | | + End of Process-EOP signals that|EOP/ 11 | cf. 8234A-6 spec. + DMA service has been completed | | + |INTACK/ 12 IFSEL 4/ | + | | + Change peripheral from board |AUTO/ 13 DIR/ | Direction of the databus driver. Low signal + type 1 to 2.NC on type 1 | | change to input. + Test Hold. External request |THOLD/ 14 HLDA | Hold Acknowledge. A response from the Z80 + to set the Z80 in hold state. | | The Z80 CPU is in hold state, active high. + Processor-Clock: inverse signal|PCLK/ 15 CLK1 | Clock Output 1 MHz + of the CPU clock, freq. 4MHz | | + Logic Ground |LGRD 16 TRAMD/ | Test RAM-Disable. For ext. ROM or RAM expansion. + | | Switching with the System RAM, RAM output disabled. act. low + |BA19 17 BA18 | BA0-BA19: Buffered 20bit Address Bus + | | + |BA17 18 BA16 | + | | + |BA15 19 BA14 | Range to 1MB Normal output, active high + | | + |BA13 20 BA12 | + | | + |BA11 21 BA10 | Tri-State possible with ABTRI/ signal + | | + |BA9 22 BA8 | + | | + |BA7 23 BA6 | + | | + |BA5 24 BA4 | + | | + |BA3 25 BA2 | + | | + |BA1 26 BAO | + | | + IFSEL 0-4, active low |IFSEL3/ 27 IFSEL2/ | The select of the I/O pprts in the peripherals is made + The interface does not need | | by any IFSEL and BA3 (BA3/). (10 peripherals). Automatic + own address decoder |IFSEL1/ 28 IFSELO/ | change of the data bus direction. This change is not possible + | | while a dma function is performed + DRQ0-DRQ1: DMA Request for |DRQ1 29 DRQ0 | Asynchr. channel requests are used by peripherals + resp. channels, act. high | | to request DMA service + DACK0-DACK1: |DACK1 / 30 DACK0/ | DMA-Acknowledge Channels 0 and 1, active low + | | These lines indicate an active DMA channel + |WAIT/ 31 INT/ | + | | + Logic Ground |LGRD 32 LGRD | Logic Ground + |-------------------------| + + Two additional plug/socket connections are possible on the bus. These are made on the solder side of the controller board + and are designated J2A and J7 A. These connectors are not considered to be user accessible , rather for factory use , + or for use by field engineers and system integrators. Normally, these two connectors are used for: + ??? J2A - The connection of the fixed disk interface board, or a custom design board. + ??? J7A - The connection of the 16-bit processor board (factory option and kit K230). + + The processor and diagnostics module for Slots J7 and J7A have the following additional signals in addition to the ones present on Slots J2-J6. + Note that the middle row of the connector (row "b") carries some signals too: + + A2 - OPT 2 + Signals A19-A26 and C19-C26 are called e.g. A7 instead of BA7 in the processor module schematic (fig. 2.14, page 2.21 System Technical Manual Hardware) + Signals A6-A9 and C6-D9 are called e.g. D4 instead of BD4 in the processor module schematic + B10 - READYP + B11 - HOLD + B12 - SWITCH 16/ + B13 - HLDA 16 + B14 - 16 BITAV + B15 - STDMARQ + B16 - LGRD + B17 - 16 BITSET/ + B20 - MEMRQ/ + B32 - LGRD + + The memory modules on J1 share the same physical connector with the other expansion modules, but carry different signals: + + A1 - +5V C1 - +5V + A2 C2 + A3 - AOUT7 C3 + A4 - AOUT6 C4 - AOUT5 + A5 - AOUT4 C5 - AOUT3 + A6 C6 + A7 C7 + A8 C8 + A9 C9 + A10 C10 - AOUT2 + A11 C11 - AOUT1 + A12 - OD0 C12 - AOUT0 + A13 - OD1 C13 - OD2 + A14 - OD3 C14 + A15 C15 + A16 - LGRD C16 - LGRD + A17 C17 + A18 C18 + A19 - ID0 C19 + A20 - ID1 C20 + A21 - ID2 C21 + A22 - ID3 C22 + A23 - ID4 C23 - CAS7/ + A24 - ID5 C24 - CAS6/ + A25 - ID6 C25 - CAS5/ + A26 - ID7 C26 - CAS4/ + A27 - CAS2/ C27 - CAS1/ + A28 - CAS3/ C28 + A29 - OD4 C29 - OD5 + A30 - RAS/ C30 - WE/ + A31 - OD6 C31 - OD7 + A32 - LGRD C32 - LGRD + + +***************************************************************************/ + + +#include "emu.h" +#include "dmvbus.h" + + +/*************************************************************************** + PARAMETERS +***************************************************************************/ + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type DMVCART_SLOT = &device_creator; + +//************************************************************************** +// DMV cartridge interface +//************************************************************************** + +//------------------------------------------------- +// device_dmvslot_interface - constructor +//------------------------------------------------- + +device_dmvslot_interface::device_dmvslot_interface(const machine_config &mconfig, device_t &device) + : device_slot_card_interface(mconfig, device) +{ +} + + +//------------------------------------------------- +// ~device_dmvslot_interface - destructor +//------------------------------------------------- + +device_dmvslot_interface::~device_dmvslot_interface() +{ +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// dmvcart_slot_device - constructor +//------------------------------------------------- +dmvcart_slot_device::dmvcart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, DMVCART_SLOT, "Decision Mate V cartridge slot", tag, owner, clock, "dmvcart_slot", __FILE__), + device_slot_interface(mconfig, *this), + m_prog_read_cb(*this), + m_prog_write_cb(*this), + m_out_int_cb(*this), + m_out_irq_cb(*this), + m_out_thold_cb(*this) +{ +} + + +//------------------------------------------------- +// dmvcart_slot_device - destructor +//------------------------------------------------- + +dmvcart_slot_device::~dmvcart_slot_device() +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void dmvcart_slot_device::device_start() +{ + m_cart = dynamic_cast(get_card_device()); + + // resolve callbacks + m_prog_read_cb.resolve_safe(0); + m_prog_write_cb.resolve_safe(); + m_out_int_cb.resolve_safe(); + m_out_irq_cb.resolve_safe(); + m_out_thold_cb.resolve_safe(); +} + +/*------------------------------------------------- + read +-------------------------------------------------*/ + +bool dmvcart_slot_device::read(offs_t offset, UINT8 &data) +{ + if (m_cart) + return m_cart->read(offset, data); + return false; +} + +/*------------------------------------------------- + write +-------------------------------------------------*/ + +bool dmvcart_slot_device::write(offs_t offset, UINT8 data) +{ + if (m_cart) + return m_cart->write(offset, data); + return false; +} + +/*------------------------------------------------- + read +-------------------------------------------------*/ + +void dmvcart_slot_device::ram_read(UINT8 cas, offs_t offset, UINT8 &data) +{ + if (m_cart) + m_cart->ram_read(cas, offset, data); +} + +/*------------------------------------------------- + write +-------------------------------------------------*/ + +void dmvcart_slot_device::ram_write(UINT8 cas, offs_t offset, UINT8 data) +{ + if (m_cart) + return m_cart->ram_write(cas, offset, data); +} + +/*------------------------------------------------- + IO read +-------------------------------------------------*/ + +void dmvcart_slot_device::io_read(address_space &space, int ifsel, offs_t offset, UINT8 &data) +{ + if (m_cart) + m_cart->io_read(space, ifsel, offset, data); +} + + +/*------------------------------------------------- + IO write +-------------------------------------------------*/ + +void dmvcart_slot_device::io_write(address_space &space, int ifsel, offs_t offset, UINT8 data) +{ + if (m_cart) + m_cart->io_write(space, ifsel, offset, data); +} + +/*------------------------------------------------- + av16bit +-------------------------------------------------*/ + +bool dmvcart_slot_device::av16bit() +{ + if (m_cart) + return m_cart->av16bit(); + return false; +} + +/*------------------------------------------------- + hold_w +-------------------------------------------------*/ + +void dmvcart_slot_device::hold_w(int state) +{ + if (m_cart) + m_cart->hold_w(state); +} + +void dmvcart_slot_device::switch16_w(int state) +{ + if (m_cart) + m_cart->switch16_w(state); +} + +void dmvcart_slot_device::timint_w(int state) +{ + if (m_cart) + m_cart->timint_w(state); +} + +void dmvcart_slot_device::keyint_w(int state) +{ + if (m_cart) + m_cart->keyint_w(state); +} + +void dmvcart_slot_device::busint_w(int state) +{ + if (m_cart) + m_cart->busint_w(state); +} + +void dmvcart_slot_device::flexint_w(int state) +{ + if (m_cart) + m_cart->flexint_w(state); +} + +void dmvcart_slot_device::irq2_w(int state) +{ + if (m_cart) + m_cart->irq2_w(state); +} + +void dmvcart_slot_device::irq2a_w(int state) +{ + if (m_cart) + m_cart->irq2a_w(state); +} + +void dmvcart_slot_device::irq3_w(int state) +{ + if (m_cart) + m_cart->irq3_w(state); +} + +void dmvcart_slot_device::irq4_w(int state) +{ + if (m_cart) + m_cart->irq4_w(state); +} + +void dmvcart_slot_device::irq5_w(int state) +{ + if (m_cart) + m_cart->irq5_w(state); +} + +void dmvcart_slot_device::irq6_w(int state) +{ + if (m_cart) + m_cart->irq6_w(state); +} diff --git a/src/devices/bus/dmv/dmvbus.h b/src/devices/bus/dmv/dmvbus.h new file mode 100644 index 00000000000..7043423dc1a --- /dev/null +++ b/src/devices/bus/dmv/dmvbus.h @@ -0,0 +1,122 @@ +// license:BSD-3-Clause +// copyright-holders:Sandro Ronco +/********************************************************************* + + Decision Mate V expansion slot + +*********************************************************************/ + +#ifndef __DMV_CART_H__ +#define __DMV_CART_H__ + +/*************************************************************************** + TYPE DEFINITIONS +***************************************************************************/ + +// ======================> device_dmvslot_interface + +class device_dmvslot_interface : public device_slot_card_interface +{ +public: + // construction/destruction + device_dmvslot_interface(const machine_config &mconfig, device_t &device); + virtual ~device_dmvslot_interface(); + + virtual bool read(offs_t offset, UINT8 &data) { return false; } + virtual bool write(offs_t offset, UINT8 data) { return false; } + virtual void io_read(address_space &space, int ifsel, offs_t offset, UINT8 &data) { } + virtual void io_write(address_space &space, int ifsel, offs_t offset, UINT8 data) { } + + // slot 1 + virtual void ram_read(UINT8 cas, offs_t offset, UINT8 &data) { } + virtual void ram_write(UINT8 cas, offs_t offset, UINT8 data) { } + + // slot 7 and 7A + virtual bool av16bit() { return false; } + virtual void hold_w(int state) { } + virtual void switch16_w(int state) { } + virtual void timint_w(int state) { } + virtual void keyint_w(int state) { } + virtual void busint_w(int state) { } + virtual void flexint_w(int state) { } + virtual void irq2_w(int state) { } + virtual void irq2a_w(int state) { } + virtual void irq3_w(int state) { } + virtual void irq4_w(int state) { } + virtual void irq5_w(int state) { } + virtual void irq6_w(int state) { } +}; + + +// ======================> dmvcart_slot_device + +class dmvcart_slot_device : public device_t, + public device_slot_interface +{ +public: + // construction/destruction + dmvcart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual ~dmvcart_slot_device(); + + template static devcb_base &set_prog_read_callback(device_t &device, _Object object) { return downcast(device).m_prog_read_cb.set_callback(object); } + template static devcb_base &set_prog_write_callback(device_t &device, _Object object) { return downcast(device).m_prog_write_cb.set_callback(object); } + template static devcb_base &set_out_int_callback(device_t &device, _Object object) { return downcast(device).m_out_int_cb.set_callback(object); } + template static devcb_base &set_out_irq_callback(device_t &device, _Object object) { return downcast(device).m_out_irq_cb.set_callback(object); } + template static devcb_base &set_out_thold_callback(device_t &device, _Object object) { return downcast(device).m_out_thold_cb.set_callback(object); } + + // device-level overrides + virtual void device_start(); + + // reading and writing + virtual bool read(offs_t offset, UINT8 &data); + virtual bool write(offs_t offset, UINT8 data); + virtual void ram_read(UINT8 cas, offs_t offset, UINT8 &data); + virtual void ram_write(UINT8 cas, offs_t offset, UINT8 data); + virtual void io_read(address_space &space, int ifsel, offs_t offset, UINT8 &data); + virtual void io_write(address_space &space, int ifsel, offs_t offset, UINT8 data); + virtual void hold_w(int state); + virtual void switch16_w(int state); + virtual void timint_w(int state); + virtual void keyint_w(int state); + virtual void busint_w(int state); + virtual void flexint_w(int state); + virtual void irq2_w(int state); + virtual void irq2a_w(int state); + virtual void irq3_w(int state); + virtual void irq4_w(int state); + virtual void irq5_w(int state); + virtual void irq6_w(int state); + virtual bool av16bit(); + + // internal state + devcb_read8 m_prog_read_cb; + devcb_write8 m_prog_write_cb; + devcb_write_line m_out_int_cb; + devcb_write_line m_out_irq_cb; + devcb_write_line m_out_thold_cb; + device_dmvslot_interface* m_cart; +}; + + +// device type definition +extern const device_type DMVCART_SLOT; + + +/*************************************************************************** + DEVICE CONFIGURATION MACROS +***************************************************************************/ + +#define MCFG_DMVCART_SLOT_PROGRAM_READWRITE_CB(_read_devcb, _write_devcb) \ + devcb = &dmvcart_slot_device::set_prog_read_callback(*device, DEVCB_##_read_devcb); \ + devcb = &dmvcart_slot_device::set_prog_write_callback(*device, DEVCB_##_write_devcb); + +#define MCFG_DMVCART_SLOT_OUT_INT_CB(_devcb) \ + devcb = &dmvcart_slot_device::set_out_int_callback(*device, DEVCB_##_devcb); + +#define MCFG_DMVCART_SLOT_OUT_IRQ_CB(_devcb) \ + devcb = &dmvcart_slot_device::set_out_irq_callback(*device, DEVCB_##_devcb); + +#define MCFG_DMVCART_SLOT_OUT_THOLD_CB(_devcb) \ + devcb = &dmvcart_slot_device::set_out_thold_callback(*device, DEVCB_##_devcb); + +#endif /* __DMV_CART_H__ */ diff --git a/src/devices/bus/dmv/k210.c b/src/devices/bus/dmv/k210.c new file mode 100644 index 00000000000..0b0e86fb27a --- /dev/null +++ b/src/devices/bus/dmv/k210.c @@ -0,0 +1,166 @@ +// license:BSD-3-Clause +// copyright-holders:Sandro Ronco +/*************************************************************************** + + K210 Centronics module + +***************************************************************************/ + +#include "emu.h" +#include "k210.h" + +/*************************************************************************** + IMPLEMENTATION +***************************************************************************/ + + +static MACHINE_CONFIG_FRAGMENT( dmv_k210 ) + MCFG_DEVICE_ADD("ppi8255", I8255, 0) + MCFG_I8255_IN_PORTA_CB(READ8(dmv_k210_device, porta_r)) + MCFG_I8255_IN_PORTB_CB(READ8(dmv_k210_device, portb_r)) + MCFG_I8255_IN_PORTC_CB(READ8(dmv_k210_device, portc_r)) + MCFG_I8255_OUT_PORTA_CB(WRITE8(dmv_k210_device, porta_w)) + MCFG_I8255_OUT_PORTB_CB(WRITE8(dmv_k210_device, portb_w)) + MCFG_I8255_OUT_PORTC_CB(WRITE8(dmv_k210_device, portc_w)) + + MCFG_CENTRONICS_ADD("centronics", centronics_devices, "printer") + MCFG_CENTRONICS_DATA_INPUT_BUFFER("cent_data_in") + MCFG_CENTRONICS_ACK_HANDLER(WRITELINE(dmv_k210_device, cent_ack_w)) + MCFG_CENTRONICS_BUSY_HANDLER(WRITELINE(dmv_k210_device, cent_busy_w)) + MCFG_CENTRONICS_SELECT_IN_HANDLER(WRITELINE(dmv_k210_device, cent_slct_w)) + MCFG_CENTRONICS_PERROR_HANDLER(WRITELINE(dmv_k210_device, cent_pe_w)) + MCFG_CENTRONICS_FAULT_HANDLER(WRITELINE(dmv_k210_device, cent_fault_w)) + MCFG_CENTRONICS_AUTOFD_HANDLER(WRITELINE(dmv_k210_device, cent_autofd_w)) + MCFG_CENTRONICS_INIT_HANDLER(WRITELINE(dmv_k210_device, cent_init_w)) + + MCFG_DEVICE_ADD("cent_data_in", INPUT_BUFFER, 0) + MCFG_CENTRONICS_OUTPUT_LATCH_ADD("cent_data_out", "centronics") +MACHINE_CONFIG_END + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type DMV_K210 = &device_creator; + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// dmv_k210_device - constructor +//------------------------------------------------- + +dmv_k210_device::dmv_k210_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, DMV_K210, "K210 Centronics", tag, owner, clock, "dmv_k210", __FILE__), + device_dmvslot_interface( mconfig, *this ), + m_ppi(*this, "ppi8255"), + m_centronics(*this, "centronics"), + m_cent_data_in(*this, "cent_data_in"), + m_cent_data_out(*this, "cent_data_out") +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void dmv_k210_device::device_start() +{ + m_clk1_timer = timer_alloc(0, NULL); + m_bus = static_cast(owner()); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void dmv_k210_device::device_reset() +{ + m_clk1_timer->adjust(attotime::never); + m_portb = 0x00; + m_portc = 0x00; +} + +//------------------------------------------------- +// device_timer - handler timer events +//------------------------------------------------- + +void dmv_k210_device::device_timer(emu_timer &timer, device_timer_id tid, int param, void *ptr) +{ + m_centronics->write_strobe(CLEAR_LINE); +} + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor dmv_k210_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( dmv_k210 ); +} + +void dmv_k210_device::io_read(address_space &space, int ifsel, offs_t offset, UINT8 &data) +{ + if (ifsel == 0) + data = m_ppi->read(space, offset & 0x03); +} + +void dmv_k210_device::io_write(address_space &space, int ifsel, offs_t offset, UINT8 data) +{ + if (ifsel == 0) + m_ppi->write(space, offset & 0x03, data); +} + +READ8_MEMBER( dmv_k210_device::porta_r ) +{ + return m_cent_data_in->read(); +} + +READ8_MEMBER( dmv_k210_device::portb_r ) +{ + return m_portb; +} + +READ8_MEMBER( dmv_k210_device::portc_r ) +{ + return m_portc; +} + +WRITE8_MEMBER( dmv_k210_device::porta_w ) +{ + m_cent_data_out->write(data); +} + +WRITE8_MEMBER( dmv_k210_device::portb_w ) +{ + m_centronics->write_ack(BIT(data, 2)); + m_centronics->write_select(BIT(data, 4)); + m_centronics->write_busy(BIT(data, 5)); + m_centronics->write_perror(BIT(data, 6)); + m_centronics->write_fault(BIT(data, 7)); +} + +WRITE8_MEMBER( dmv_k210_device::portc_w ) +{ + if (!(data & 0x80)) + { + m_centronics->write_strobe(ASSERT_LINE); + m_clk1_timer->adjust(attotime::from_hz(XTAL_1MHz)); + } + + m_centronics->write_init(!BIT(data, 1)); + m_centronics->write_autofd(!BIT(data, 2)); + m_centronics->write_ack(BIT(data, 6)); + m_bus->m_out_irq_cb(BIT(data, 3)); +} + +WRITE_LINE_MEMBER( dmv_k210_device::cent_ack_w ) { if (state) m_portb |= 0x04; else m_portb &= ~0x04; m_ppi->pc6_w(state); } +WRITE_LINE_MEMBER( dmv_k210_device::cent_slct_w ) { if (state) m_portb |= 0x10; else m_portb &= ~0x10; } +WRITE_LINE_MEMBER( dmv_k210_device::cent_busy_w ) { if (state) m_portb |= 0x20; else m_portb &= ~0x20; } +WRITE_LINE_MEMBER( dmv_k210_device::cent_pe_w ) { if (state) m_portb |= 0x40; else m_portb &= ~0x40; } +WRITE_LINE_MEMBER( dmv_k210_device::cent_fault_w ) { if (state) m_portb |= 0x80; else m_portb &= ~0x80; } + +WRITE_LINE_MEMBER( dmv_k210_device::cent_autofd_w ) { if (state) m_portc |= 0x02; else m_portc &= ~0x02; } +WRITE_LINE_MEMBER( dmv_k210_device::cent_init_w ) { if (state) m_portc |= 0x04; else m_portc &= ~0x04; } diff --git a/src/devices/bus/dmv/k210.h b/src/devices/bus/dmv/k210.h new file mode 100644 index 00000000000..705e1afe978 --- /dev/null +++ b/src/devices/bus/dmv/k210.h @@ -0,0 +1,71 @@ +// license:BSD-3-Clause +// copyright-holders:Sandro Ronco +#pragma once + +#ifndef __DMV_K210_H__ +#define __DMV_K210_H__ + +#include "emu.h" +#include "dmvbus.h" +#include "machine/i8255.h" +#include "bus/centronics/ctronics.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> dmv_k210_device + +class dmv_k210_device : + public device_t, + public device_dmvslot_interface +{ +public: + // construction/destruction + dmv_k210_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + + DECLARE_READ8_MEMBER(porta_r); + DECLARE_READ8_MEMBER(portb_r); + DECLARE_READ8_MEMBER(portc_r); + DECLARE_WRITE8_MEMBER(porta_w); + DECLARE_WRITE8_MEMBER(portb_w); + DECLARE_WRITE8_MEMBER(portc_w); + + DECLARE_WRITE_LINE_MEMBER(cent_ack_w); + DECLARE_WRITE_LINE_MEMBER(cent_busy_w); + DECLARE_WRITE_LINE_MEMBER(cent_slct_w); + DECLARE_WRITE_LINE_MEMBER(cent_pe_w); + DECLARE_WRITE_LINE_MEMBER(cent_fault_w); + DECLARE_WRITE_LINE_MEMBER(cent_autofd_w); + DECLARE_WRITE_LINE_MEMBER(cent_init_w); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + void device_timer(emu_timer &timer, device_timer_id tid, int param, void *ptr); + + // dmvcart_interface overrides + virtual void io_read(address_space &space, int ifsel, offs_t offset, UINT8 &data); + virtual void io_write(address_space &space, int ifsel, offs_t offset, UINT8 data); + +private: + required_device m_ppi; + required_device m_centronics; + required_device m_cent_data_in; + required_device m_cent_data_out; + dmvcart_slot_device * m_bus; + + emu_timer * m_clk1_timer; + UINT8 m_portb; + UINT8 m_portc; +}; + + +// device type definition +extern const device_type DMV_K210; + +#endif /* __DMV_K210_H__ */ diff --git a/src/devices/bus/dmv/k220.c b/src/devices/bus/dmv/k220.c new file mode 100644 index 00000000000..de6092f3d71 --- /dev/null +++ b/src/devices/bus/dmv/k220.c @@ -0,0 +1,275 @@ +// license:BSD-3-Clause +// copyright-holders:Sandro Ronco +/*************************************************************************** + + NCR DMV K220 Diagnostic module + + to be inserted into slot 7 only + + all semiconductors shown: + + |-----------------------------------------------------------------------| + | | + | S S NEC D8255AC-5 | + | PB1 E E | + | X1 G G | + | 1 2 SN84LS247N ROM1 | + | LED1 | + | LED2 SW1 SN74LS247N C | + | LED3 TCA965 SW2 N | + | 8302 SW3 PROM1 ROM2 1 | + | LED4 SW4 | + | LED5 TCA965 SW5 | + | LED6 8240 SW6 | + | SW7 M5L8253P-5 RAM | + | LED7 SW8 | + | LED8 SN7407N | + | LED9 | + | | + | SN74LS14N DM74LS05N DM74LS00M DM74LS04N | + |-----------------------------------------------------------------------| + + PB1: Push Button + X1: Crystal 24 MHz + LED 1: red, 5V> + LED 2: green, 5V- + LED 3: red, 5V< + LED 4: red, 12V> + LED 5: green, 12V- + LED 6: red, 12V< + LED 7: green, PCLK/ + LED 8: green, MEMR/ + LED 9: green, HLDA + SEG 1&2 Seven segment displays + SW1-8 Switches marked top=>bottom Off / Start, S Run / Loop, M Mes / D Mes, CRT / LED, SEL 1, SEL 2, SEL 3, SEL 4 + PROM 1: TBP24S10N marked 32084 + ROM 1: MBM2764-30 marked 32564 + ROM 2: M5L2764K marked 32563 + RAM: HM6116LP-3 + + Inserting the diagnostics module into Slot 7 changes the DMV's memory map: + + The diagnostics ROM is inserted between 0x2000 and 0x3FFF, the diagnostics RAM between 0xF000 and 0xF7FF with the diagnostics stack at 0xF700 + +***************************************************************************/ + +#include "emu.h" +#include "k220.h" + + +/*************************************************************************** + IMPLEMENTATION +***************************************************************************/ + +ROM_START( dmv_k220 ) + ROM_REGION(0x4000, "rom", 0) + ROM_SYSTEM_BIOS(0, "v4", "V 04.00") + ROMX_LOAD("34014.u17", 0x0000, 0x2000, CRC(552c2247) SHA1(7babd264ead2e04afe624c3035f211279c203f41), ROM_BIOS(1)) + ROMX_LOAD("34015.u18", 0x2000, 0x2000, CRC(d714f2d8) SHA1(1a7095401d63951ba9189bc3e384c26996113815), ROM_BIOS(1)) + + ROM_SYSTEM_BIOS(1, "v2", "V 02.00") + ROMX_LOAD("32563.u17", 0x0000, 0x2000, CRC(57445768) SHA1(59b615437444789bf10ba6768cd3c43a69c7ed7b), ROM_BIOS(2)) + ROMX_LOAD("32564.u18", 0x2000, 0x2000, CRC(172e0c60) SHA1(eedae538636009a5b86fc78e50a03c72eeb0e73b), ROM_BIOS(2)) + + ROM_REGION(0x0080, "prom", 0) + ROM_LOAD( "u11.bin", 0x0000, 0x0080, NO_DUMP) // used for address decoding + + ROM_REGION(0x0800, "ram", ROMREGION_ERASE) +ROM_END + +static MACHINE_CONFIG_FRAGMENT( dmv_k220 ) + MCFG_DEVICE_ADD("ppi8255", I8255, 0) + MCFG_I8255_OUT_PORTA_CB(WRITE8(dmv_k220_device, porta_w)) + MCFG_I8255_IN_PORTB_CB(IOPORT("SWITCH")) + MCFG_I8255_OUT_PORTC_CB(WRITE8(dmv_k220_device, portc_w)) + + MCFG_DEVICE_ADD("pit8253", PIT8253, 0) + MCFG_PIT8253_CLK0(XTAL_1MHz) // CLK1 + MCFG_PIT8253_OUT0_HANDLER(WRITELINE(dmv_k220_device, write_out0)) + MCFG_PIT8253_OUT1_HANDLER(WRITELINE(dmv_k220_device, write_out1)) + MCFG_PIT8253_OUT2_HANDLER(WRITELINE(dmv_k220_device, write_out2)) +MACHINE_CONFIG_END + +static INPUT_PORTS_START( dmv_k220 ) + PORT_START("SWITCH") + PORT_DIPNAME( 0x01, 0x00, "Select 1" ) + PORT_DIPSETTING( 0x00, DEF_STR(Off) ) + PORT_DIPSETTING( 0x01, DEF_STR(On) ) + PORT_DIPNAME( 0x02, 0x00, "Select 2" ) + PORT_DIPSETTING( 0x00, DEF_STR(Off) ) + PORT_DIPSETTING( 0x02, DEF_STR(On) ) + PORT_DIPNAME( 0x04, 0x00, "Select 3" ) + PORT_DIPSETTING( 0x00, DEF_STR(Off) ) + PORT_DIPSETTING( 0x04, DEF_STR(On) ) + PORT_DIPNAME( 0x08, 0x00, "Select 4" ) + PORT_DIPSETTING( 0x00, DEF_STR(Off) ) + PORT_DIPSETTING( 0x08, DEF_STR(On) ) + PORT_DIPNAME( 0x10, 0x10, "Maintenance" ) + PORT_DIPSETTING( 0x00, DEF_STR(Off) ) + PORT_DIPSETTING( 0x10, DEF_STR(On) ) + PORT_DIPNAME( 0x20, 0x20, "Detail Message" ) + PORT_DIPSETTING( 0x00, DEF_STR(Off) ) + PORT_DIPSETTING( 0x20, DEF_STR(On) ) + PORT_DIPNAME( 0x40, 0x40, "Continuous Run" ) + PORT_DIPSETTING( 0x00, DEF_STR(Off) ) + PORT_DIPSETTING( 0x40, DEF_STR(On) ) + PORT_DIPNAME( 0x80, 0x80, "Diagnostic module" ) + PORT_DIPSETTING( 0x00, DEF_STR(Off) ) + PORT_DIPSETTING( 0x80, DEF_STR(On) ) +INPUT_PORTS_END + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type DMV_K220 = &device_creator; + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// dmv_k220_device - constructor +//------------------------------------------------- + +dmv_k220_device::dmv_k220_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, DMV_K220, "K220 diagnostic", tag, owner, clock, "dmv_k220", __FILE__), + device_dmvslot_interface( mconfig, *this ), + m_pit(*this, "pit8253"), + m_ppi(*this, "ppi8255"), + m_ram(*this, "ram"), + m_rom(*this, "rom") +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void dmv_k220_device::device_start() +{ + address_space &space = machine().device("maincpu")->space(AS_IO); + space.install_readwrite_handler(0x08, 0x0b, 0, 0, read8_delegate(FUNC(pit8253_device::read), &(*m_pit)), write8_delegate(FUNC(pit8253_device::write), &(*m_pit)), 0); + space.install_readwrite_handler(0x0c, 0x0f, 0, 0, read8_delegate(FUNC(i8255_device::read), &(*m_ppi)), write8_delegate(FUNC(i8255_device::write), &(*m_ppi)), 0); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void dmv_k220_device::device_reset() +{ + // active the correct layout + machine().render().first_target()->set_view(1); +} + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor dmv_k220_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( dmv_k220 ); +} + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor dmv_k220_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( dmv_k220 ); +} + +//------------------------------------------------- +// device_rom_region +//------------------------------------------------- + +const rom_entry *dmv_k220_device::device_rom_region() const +{ + return ROM_NAME( dmv_k220 ); +} + +//------------------------------------------------- +// read +//------------------------------------------------- + +bool dmv_k220_device::read(offs_t offset, UINT8 &data) +{ + if ((m_portc & 0x01) && offset >= 0x2000 && offset < 0x6000) + { + data = m_rom->base()[offset - 0x2000]; + return true; + } + else if ((m_portc & 0x02) && offset >= 0xf000 && offset < 0xf800) + { + data = m_ram->base()[offset & 0x7ff]; + return true; + } + + return false; +} + +//------------------------------------------------- +// write +//------------------------------------------------- + +bool dmv_k220_device::write(offs_t offset, UINT8 data) +{ + if ((m_portc & 0x01) && offset >= 0x2000 && offset < 0x4000) + { + logerror("k220: write on ROM %x %x\n", offset, data); + return true; + } + else if ((m_portc & 0x02) && offset >= 0xf000 && offset < 0xf800) + { + m_ram->base()[offset & 0x7ff] = data; + return true; + } + + return false; +} + +WRITE8_MEMBER( dmv_k220_device::porta_w ) +{ + // 74LS247 BCD-to-Seven-Segment Decoder + static UINT8 bcd2hex[] = { 0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f, 0x58, 0x4c, 0x62, 0x69, 0x78, 0x00 }; + + output_set_digit_value(0, bcd2hex[(data >> 4) & 0x0f]); + output_set_digit_value(1, bcd2hex[data & 0x0f]); +} + + +WRITE8_MEMBER( dmv_k220_device::portc_w ) +{ + /* + xxxx ---- not connected + ---- x--- PIT gate 2 + ---- -x-- PIT gate 1 + ---- --x- enable RAM + ---- ---x enable ROM + + */ + m_pit->write_gate1(BIT(data, 2)); + m_pit->write_gate2(BIT(data, 3)); + + m_portc = data; +} + + +WRITE_LINE_MEMBER( dmv_k220_device::write_out0 ) +{ + m_pit->write_clk1(state); + m_pit->write_clk2(state); +} + + +WRITE_LINE_MEMBER( dmv_k220_device::write_out1 ) +{ +} + + +WRITE_LINE_MEMBER( dmv_k220_device::write_out2 ) +{ +} diff --git a/src/devices/bus/dmv/k220.h b/src/devices/bus/dmv/k220.h new file mode 100644 index 00000000000..0465d3de706 --- /dev/null +++ b/src/devices/bus/dmv/k220.h @@ -0,0 +1,60 @@ +// license:BSD-3-Clause +// copyright-holders:Sandro Ronco +#pragma once + +#ifndef __DMV_K220_H__ +#define __DMV_K220_H__ + +#include "emu.h" +#include "dmvbus.h" +#include "machine/i8255.h" +#include "machine/pit8253.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> dmv_k220_device + +class dmv_k220_device : + public device_t, + public device_dmvslot_interface +{ +public: + // construction/destruction + dmv_k220_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + virtual ioport_constructor device_input_ports() const; + + DECLARE_WRITE8_MEMBER(porta_w); + DECLARE_WRITE8_MEMBER(portc_w); + DECLARE_WRITE_LINE_MEMBER(write_out0); + DECLARE_WRITE_LINE_MEMBER(write_out1); + DECLARE_WRITE_LINE_MEMBER(write_out2); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // dmvcart_interface overrides + virtual bool read(offs_t offset, UINT8 &data); + virtual bool write(offs_t offset, UINT8 data); + +private: + required_device m_pit; + required_device m_ppi; + required_memory_region m_ram; + required_memory_region m_rom; + + UINT8 m_portc; +}; + + +// device type definition +extern const device_type DMV_K220; + +#endif /* __DMV_K220_H__ */ diff --git a/src/devices/bus/dmv/k230.c b/src/devices/bus/dmv/k230.c new file mode 100644 index 00000000000..4ce6a97f807 --- /dev/null +++ b/src/devices/bus/dmv/k230.c @@ -0,0 +1,315 @@ +// license:BSD-3-Clause +// copyright-holders:Sandro Ronco +/*************************************************************************** + + K230 Internal 8088 module without interrupt controller + K231 External 8088 module without interrupt controller + K234 External 68008 module + K235 Internal 8088 module with interrupt controller + +***************************************************************************/ + +#include "emu.h" +#include "k230.h" + + +/*************************************************************************** + IMPLEMENTATION +***************************************************************************/ + +ROM_START( dmv_k230 ) + ROM_REGION(0x1000, "rom", 0) + ROM_LOAD( "dmv_int_8088_32167.bin", 0x0000, 0x1000, CRC(f4a58880) SHA1(4f50ef25008851ae6f0c670f19d63f4e61249581)) +ROM_END + +ROM_START( dmv_k231 ) + ROM_REGION(0x1000, "rom", 0) + ROM_LOAD( "dmv_ext_8088_32167.bin", 0x0000, 0x1000, CRC(f4a58880) SHA1(4f50ef25008851ae6f0c670f19d63f4e61249581)) +ROM_END + +ROM_START( dmv_k235 ) + ROM_REGION(0x1000, "rom", 0) + ROM_LOAD( "dmv_int_8088_pic_33473.bin", 0x0000, 0x1000, CRC(104195dc) SHA1(08d48ca3b84ab26c1a764792e04ec4def7dad2ad)) +ROM_END + +static ADDRESS_MAP_START(k230_mem, AS_PROGRAM, 8, dmv_k230_device) + ADDRESS_MAP_UNMAP_HIGH + AM_RANGE( 0x00000, 0x7ffff ) AM_READWRITE(program_r, program_w) + AM_RANGE( 0x80000, 0xfffff ) AM_READ(rom_r) +ADDRESS_MAP_END + +static ADDRESS_MAP_START(k230_io, AS_IO, 8, dmv_k230_device) + ADDRESS_MAP_UNMAP_HIGH + ADDRESS_MAP_GLOBAL_MASK(0xff) + AM_RANGE( 0x00, 0xff ) AM_READWRITE(io_r, io_w) +ADDRESS_MAP_END + +static ADDRESS_MAP_START(k234_mem, AS_PROGRAM, 8, dmv_k230_device) + ADDRESS_MAP_UNMAP_HIGH + AM_RANGE( 0x00000, 0x7ffff ) AM_READWRITE(program_r, program_w) + AM_RANGE( 0xfff00, 0xfffff ) AM_READWRITE(io_r, io_w) +ADDRESS_MAP_END + +static ADDRESS_MAP_START(k235_io, AS_IO, 8, dmv_k230_device) + ADDRESS_MAP_UNMAP_HIGH + ADDRESS_MAP_GLOBAL_MASK(0xff) + AM_RANGE( 0x90, 0x91 ) AM_DEVREADWRITE("pic8259", pic8259_device, read, write) + AM_RANGE( 0x00, 0xff ) AM_READWRITE(io_r, io_w) +ADDRESS_MAP_END + +static MACHINE_CONFIG_FRAGMENT( dmv_k230 ) + MCFG_CPU_ADD("maincpu", I8088, XTAL_15MHz / 3) + MCFG_CPU_PROGRAM_MAP(k230_mem) + MCFG_CPU_IO_MAP(k230_io) +MACHINE_CONFIG_END + +static MACHINE_CONFIG_FRAGMENT( dmv_k234 ) + MCFG_CPU_ADD("maincpu", M68008, XTAL_16MHz / 2) + MCFG_CPU_PROGRAM_MAP(k234_mem) +MACHINE_CONFIG_END + +static MACHINE_CONFIG_FRAGMENT( dmv_k235 ) + MCFG_CPU_ADD("maincpu", V20, XTAL_15MHz / 3) + MCFG_CPU_PROGRAM_MAP(k230_mem) + MCFG_CPU_IO_MAP(k235_io) + MCFG_CPU_IRQ_ACKNOWLEDGE_DEVICE("pic8259", pic8259_device, inta_cb) + + MCFG_PIC8259_ADD("pic8259", INPUTLINE("maincpu", 0), VCC, NULL) +MACHINE_CONFIG_END + + +static INPUT_PORTS_START( dmv_k235 ) + PORT_START("DSW") + PORT_DIPNAME( 0x01, 0x00, "K235 INT7" ) PORT_DIPLOCATION("S:1") + PORT_DIPSETTING( 0x00, "Slot 5" ) + PORT_DIPSETTING( 0x01, "Slot 6" ) + PORT_DIPNAME( 0x02, 0x00, "K235 INT5" ) PORT_DIPLOCATION("S:2") + PORT_DIPSETTING( 0x00, "Slot 2a" ) + PORT_DIPSETTING( 0x02, "Slot 2" ) +INPUT_PORTS_END + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type DMV_K230 = &device_creator; +const device_type DMV_K231 = &device_creator; +const device_type DMV_K234 = &device_creator; +const device_type DMV_K235 = &device_creator; + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// dmv_k230_device - constructor +//------------------------------------------------- + +dmv_k230_device::dmv_k230_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, DMV_K230, "K230 8088 without interrupt controller", tag, owner, clock, "dmv_k230", __FILE__), + device_dmvslot_interface( mconfig, *this ), + m_maincpu(*this, "maincpu"), + m_rom(*this, "rom") +{ +} + +dmv_k230_device::dmv_k230_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_dmvslot_interface( mconfig, *this ), + m_maincpu(*this, "maincpu"), + m_rom(*this, "rom") +{ +} + +//------------------------------------------------- +// dmv_k231_device - constructor +//------------------------------------------------- + +dmv_k231_device::dmv_k231_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : dmv_k230_device(mconfig, DMV_K231, "K231 8088 without interrupt controller", tag, owner, clock, "dmv_k231", __FILE__) +{ +} + +//------------------------------------------------- +// dmv_k234_device - constructor +//------------------------------------------------- + +dmv_k234_device::dmv_k234_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : dmv_k230_device(mconfig, DMV_K234, "K234 68008", tag, owner, clock, "dmv_k234", __FILE__) +{ +} + +//------------------------------------------------- +// dmv_k235_device - constructor +//------------------------------------------------- + +dmv_k235_device::dmv_k235_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : dmv_k230_device(mconfig, DMV_K235, "K235 8088 with interrupt controller", tag, owner, clock, "dmv_k235", __FILE__), + m_pic(*this, "pic8259"), + m_dsw(*this, "DSW") +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void dmv_k230_device::device_start() +{ + m_bus = static_cast(owner()); + m_io = &machine().device("maincpu")->space(AS_IO); +} + +void dmv_k234_device::device_start() +{ + dmv_k230_device::device_start(); + m_io->install_readwrite_handler(0xd8, 0xdf, 0, 0, read8_delegate(FUNC(dmv_k234_device::snr_r), this), write8_delegate(FUNC(dmv_k234_device::snr_w), this), 0); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void dmv_k230_device::device_reset() +{ + m_switch16 = 0; + m_hold = 0; +} + +void dmv_k234_device::device_reset() +{ + dmv_k230_device::device_reset(); + m_snr = 0; +} + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor dmv_k230_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( dmv_k230 ); +} + +machine_config_constructor dmv_k234_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( dmv_k234 ); +} + +machine_config_constructor dmv_k235_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( dmv_k235 ); +} + +//------------------------------------------------- +// device_rom_region +//------------------------------------------------- + +const rom_entry *dmv_k230_device::device_rom_region() const +{ + return ROM_NAME( dmv_k230 ); +} + +const rom_entry *dmv_k231_device::device_rom_region() const +{ + return ROM_NAME( dmv_k231 ); +} + +const rom_entry *dmv_k234_device::device_rom_region() const +{ + return NULL; +} + +const rom_entry *dmv_k235_device::device_rom_region() const +{ + return ROM_NAME( dmv_k235 ); +} + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor dmv_k235_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( dmv_k235 ); +} + +bool dmv_k230_device::av16bit() +{ + return true; +} + +void dmv_k230_device::hold_w(int state) +{ + m_hold = state; + m_maincpu->set_input_line(INPUT_LINE_HALT, (m_hold || !m_switch16) ? ASSERT_LINE : CLEAR_LINE); +} + +void dmv_k230_device::switch16_w(int state) +{ + m_switch16 = state; + m_maincpu->set_input_line(INPUT_LINE_HALT, (m_hold || !m_switch16) ? ASSERT_LINE : CLEAR_LINE); +} + +READ8_MEMBER(dmv_k230_device::rom_r) +{ + return m_rom->base()[offset & 0x0fff]; +} + +READ8_MEMBER( dmv_k230_device::io_r ) +{ + return m_io->read_byte(offset); +} + +WRITE8_MEMBER( dmv_k230_device::io_w ) +{ + m_io->write_byte(offset, data); +} + +READ8_MEMBER( dmv_k230_device::program_r ) +{ + return m_bus->m_prog_read_cb(space, offset); +} + +WRITE8_MEMBER( dmv_k230_device::program_w ) +{ + m_bus->m_prog_write_cb(space, offset, data); +} + +void dmv_k234_device::hold_w(int state) +{ + m_hold = state; + m_maincpu->set_input_line(INPUT_LINE_HALT, (m_hold || !m_snr) ? ASSERT_LINE : CLEAR_LINE); +} + +void dmv_k234_device::switch16_w(int state) +{ + if (m_switch16 != state) + { + m_snr = CLEAR_LINE; + m_maincpu->set_input_line(INPUT_LINE_HALT, ASSERT_LINE); + m_bus->m_out_thold_cb(CLEAR_LINE); + m_switch16 = state; + } +} + +READ8_MEMBER( dmv_k234_device::snr_r ) +{ + m_snr = ASSERT_LINE; + m_maincpu->set_input_line(INPUT_LINE_HALT, CLEAR_LINE); + m_maincpu->reset(); + m_bus->m_out_thold_cb(ASSERT_LINE); + + return 0xff; +} + +WRITE8_MEMBER( dmv_k234_device::snr_w ) +{ + m_snr = ASSERT_LINE; + m_maincpu->set_input_line(INPUT_LINE_HALT, CLEAR_LINE); + m_maincpu->reset(); + m_bus->m_out_thold_cb(ASSERT_LINE); +} diff --git a/src/devices/bus/dmv/k230.h b/src/devices/bus/dmv/k230.h new file mode 100644 index 00000000000..6c658f2d2c3 --- /dev/null +++ b/src/devices/bus/dmv/k230.h @@ -0,0 +1,146 @@ +// license:BSD-3-Clause +// copyright-holders:Sandro Ronco +#pragma once + +#ifndef __DMV_K230_H__ +#define __DMV_K230_H__ + +#include "emu.h" +#include "dmvbus.h" +#include "cpu/i86/i86.h" + +// K234 +#include "cpu/m68000/m68000.h" + +// K235 +#include "cpu/nec/nec.h" +#include "machine/pic8259.h" + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> dmv_k230_device + +class dmv_k230_device : + public device_t, + public device_dmvslot_interface +{ +public: + // construction/destruction + dmv_k230_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + dmv_k230_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + + DECLARE_READ8_MEMBER(io_r); + DECLARE_READ8_MEMBER(program_r); + DECLARE_WRITE8_MEMBER(io_w); + DECLARE_WRITE8_MEMBER(program_w); + DECLARE_READ8_MEMBER(rom_r); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // dmvcart_interface overrides + virtual void hold_w(int state); + virtual void switch16_w(int state); + virtual bool av16bit(); + +protected: + required_device m_maincpu; + optional_memory_region m_rom; + dmvcart_slot_device * m_bus; + address_space * m_io; + int m_switch16; + int m_hold; +}; + + +// ======================> dmv_k231_device + +class dmv_k231_device : + public dmv_k230_device +{ +public: + // construction/destruction + dmv_k231_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; +}; + + +// ======================> dmv_k234_device + +class dmv_k234_device : + public dmv_k230_device +{ +public: + // construction/destruction + dmv_k234_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + DECLARE_READ8_MEMBER(snr_r); + DECLARE_WRITE8_MEMBER(snr_w); + +protected: + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // dmvcart_interface overrides + virtual void hold_w(int state); + virtual void switch16_w(int state); + +private: + int m_snr; +}; + + +// ======================> dmv_k235_device + +class dmv_k235_device : + public dmv_k230_device +{ +public: + // construction/destruction + dmv_k235_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + virtual ioport_constructor device_input_ports() const; + + void timint_w(int state) { m_pic->ir0_w(state); } + void keyint_w(int state) { m_pic->ir1_w(state); } + void busint_w(int state) { m_pic->ir2_w(state); } + void flexint_w(int state) { m_pic->ir6_w(state); } + void irq2a_w(int state) { if (!(m_dsw->read() & 0x02)) m_pic->ir5_w(state); } + void irq2_w(int state) { if ( (m_dsw->read() & 0x02)) m_pic->ir5_w(state); } + void irq3_w(int state) { m_pic->ir3_w(state); } + void irq4_w(int state) { m_pic->ir4_w(state); } + void irq5_w(int state) { if (!(m_dsw->read() & 0x01)) m_pic->ir7_w(state); } + void irq6_w(int state) { if ( (m_dsw->read() & 0x01)) m_pic->ir7_w(state); } + +private: + required_device m_pic; + required_ioport m_dsw; +}; + +// device type definition +extern const device_type DMV_K230; +extern const device_type DMV_K231; +extern const device_type DMV_K234; +extern const device_type DMV_K235; + +#endif /* __DMV_K230_H__ */ diff --git a/src/devices/bus/dmv/k233.c b/src/devices/bus/dmv/k233.c new file mode 100644 index 00000000000..859b8b7f8f8 --- /dev/null +++ b/src/devices/bus/dmv/k233.c @@ -0,0 +1,89 @@ +// license:BSD-3-Clause +// copyright-holders:Sandro Ronco +/*************************************************************************** + + K233 16K Shared RAM + +***************************************************************************/ + +#include "emu.h" +#include "k233.h" + + +/*************************************************************************** + IMPLEMENTATION +***************************************************************************/ + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type DMV_K233 = &device_creator; + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// dmv_k233_device - constructor +//------------------------------------------------- + +dmv_k233_device::dmv_k233_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, DMV_K233, "K233 16K Shared RAM", tag, owner, clock, "dmv_k233", __FILE__), + device_dmvslot_interface( mconfig, *this ) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void dmv_k233_device::device_start() +{ + m_ram = machine().memory().region_alloc( "sharedram", 0x4000, 1, ENDIANNESS_LITTLE )->base(); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void dmv_k233_device::device_reset() +{ + m_enabled = false; +} + +void dmv_k233_device::io_write(address_space &space, int ifsel, offs_t offset, UINT8 data) +{ + if (ifsel == 1) + m_enabled = !m_enabled; +} + +//------------------------------------------------- +// read +//------------------------------------------------- + +bool dmv_k233_device::read(offs_t offset, UINT8 &data) +{ + if (m_enabled && offset >= 0xc000 && offset < 0x10000) + { + data = m_ram[offset & 0x3fff]; + return true; + } + + return false; +} + +//------------------------------------------------- +// write +//------------------------------------------------- + +bool dmv_k233_device::write(offs_t offset, UINT8 data) +{ + if (m_enabled && offset >= 0xc000 && offset < 0x10000) + { + m_ram[offset & 0x3fff] = data; + return true; + } + + return false; +} diff --git a/src/devices/bus/dmv/k233.h b/src/devices/bus/dmv/k233.h new file mode 100644 index 00000000000..5aeb5b6c782 --- /dev/null +++ b/src/devices/bus/dmv/k233.h @@ -0,0 +1,44 @@ +// license:BSD-3-Clause +// copyright-holders:Sandro Ronco +#pragma once + +#ifndef __DMV_K233_H__ +#define __DMV_K233_H__ + +#include "emu.h" +#include "dmvbus.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> + +class dmv_k233_device : + public device_t, + public device_dmvslot_interface +{ +public: + // construction/destruction + dmv_k233_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // dmvcart_interface overrides + virtual void io_write(address_space &space, int ifsel, offs_t offset, UINT8 data); + virtual bool read(offs_t offset, UINT8 &data); + virtual bool write(offs_t offset, UINT8 data); + +private: + bool m_enabled; + UINT8 * m_ram; +}; + + +// device type definition +extern const device_type DMV_K233; + +#endif /* __DMV_K233_H__ */ diff --git a/src/devices/bus/dmv/k801.c b/src/devices/bus/dmv/k801.c new file mode 100644 index 00000000000..b091d117088 --- /dev/null +++ b/src/devices/bus/dmv/k801.c @@ -0,0 +1,280 @@ +// license:BSD-3-Clause +// copyright-holders:Sandro Ronco +/*************************************************************************** + + K801 RS-232 Switchable Interface + K211 RS-232 Communications Interface + K212 RS-232 Printer Interface + K213 RS-232 Plotter Interface + + K211, K212 and K213 have same board, but different cables. + K801 uses a 2661 instead of the 2651 and has 4 switches for + select the IFSEL. + +***************************************************************************/ + +#include "emu.h" +#include "k801.h" + +/*************************************************************************** + IMPLEMENTATION +***************************************************************************/ + + +static MACHINE_CONFIG_FRAGMENT( dmv_k801 ) + MCFG_DEVICE_ADD("epci", MC2661, XTAL_5_0688MHz) + MCFG_MC2661_TXD_HANDLER(DEVWRITELINE("rs232", rs232_port_device, write_txd)) + MCFG_MC2661_RTS_HANDLER(DEVWRITELINE("rs232", rs232_port_device, write_rts)) + MCFG_MC2661_DTR_HANDLER(DEVWRITELINE("rs232", rs232_port_device, write_dtr)) + MCFG_MC2661_RXRDY_HANDLER(WRITELINE(dmv_k801_device, epci_irq_w)) + MCFG_MC2661_TXRDY_HANDLER(WRITELINE(dmv_k801_device, epci_irq_w)) + + MCFG_RS232_PORT_ADD("rs232", default_rs232_devices, "printer") + MCFG_RS232_RXD_HANDLER(DEVWRITELINE("epci", mc2661_device, rx_w)) + MCFG_RS232_DCD_HANDLER(DEVWRITELINE("epci", mc2661_device, dcd_w)) + MCFG_RS232_DSR_HANDLER(DEVWRITELINE("epci", mc2661_device, dsr_w)) + MCFG_RS232_CTS_HANDLER(DEVWRITELINE("epci", mc2661_device, cts_w)) +MACHINE_CONFIG_END + +static MACHINE_CONFIG_FRAGMENT( dmv_k211 ) + MCFG_FRAGMENT_ADD( dmv_k801 ) + + MCFG_DEVICE_MODIFY("rs232") + MCFG_SLOT_DEFAULT_OPTION("null_modem") +MACHINE_CONFIG_END + +static MACHINE_CONFIG_FRAGMENT( dmv_k212 ) + MCFG_FRAGMENT_ADD( dmv_k801 ) + + MCFG_DEVICE_MODIFY("rs232") + MCFG_SLOT_DEFAULT_OPTION("printer") +MACHINE_CONFIG_END + +static MACHINE_CONFIG_FRAGMENT( dmv_k213 ) + MCFG_FRAGMENT_ADD( dmv_k801 ) + + MCFG_DEVICE_MODIFY("rs232") + MCFG_SLOT_DEFAULT_OPTION(NULL) +MACHINE_CONFIG_END + +static INPUT_PORTS_START( dmv_k801 ) + PORT_START("DSW") + PORT_DIPNAME( 0x0f, 0x00, "K801 IFSEL" ) PORT_DIPLOCATION("S:!4,S:!3,S:!2,S:!1") + PORT_DIPSETTING( 0x00, "0A" ) + PORT_DIPSETTING( 0x01, "0B" ) + PORT_DIPSETTING( 0x02, "1A" ) + PORT_DIPSETTING( 0x03, "1B" ) + PORT_DIPSETTING( 0x04, "2A" ) + PORT_DIPSETTING( 0x05, "2B" ) + PORT_DIPSETTING( 0x06, "3A" ) + PORT_DIPSETTING( 0x07, "3B" ) + PORT_DIPSETTING( 0x08, "4A" ) + PORT_DIPSETTING( 0x09, "4B" ) +INPUT_PORTS_END + +static INPUT_PORTS_START( dmv_k211 ) + PORT_START("DSW") + PORT_DIPNAME( 0x03, 0x02, "K211 Jumpers" ) PORT_DIPLOCATION("J:1,J:2") + PORT_DIPSETTING( 0x01, "IFSEL 0" ) + PORT_DIPSETTING( 0x02, "IFSEL 1" ) +INPUT_PORTS_END + +static INPUT_PORTS_START( dmv_k212 ) + PORT_START("DSW") + PORT_DIPNAME( 0x03, 0x01, "K212 Jumpers" ) PORT_DIPLOCATION("J:1,J:2") + PORT_DIPSETTING( 0x01, "IFSEL 0" ) + PORT_DIPSETTING( 0x02, "IFSEL 1" ) +INPUT_PORTS_END + +static INPUT_PORTS_START( dmv_k213 ) + PORT_START("DSW") + PORT_DIPNAME( 0x03, 0x01, "K213 Jumpers" ) PORT_DIPLOCATION("J:1,J:2") + PORT_DIPSETTING( 0x01, "IFSEL 0" ) + PORT_DIPSETTING( 0x02, "IFSEL 1" ) +INPUT_PORTS_END + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type DMV_K801 = &device_creator; +const device_type DMV_K211 = &device_creator; +const device_type DMV_K212 = &device_creator; +const device_type DMV_K213 = &device_creator; + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// dmv_k801_device - constructor +//------------------------------------------------- + +dmv_k801_device::dmv_k801_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, DMV_K801, "K801 RS-232 Switchable Interface", tag, owner, clock, "dmv_k801", __FILE__), + device_dmvslot_interface( mconfig, *this ), + m_epci(*this, "epci"), + m_dsw(*this, "DSW") +{ +} + +dmv_k801_device::dmv_k801_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_dmvslot_interface( mconfig, *this ), + m_epci(*this, "epci"), + m_dsw(*this, "DSW") +{ +} + +//------------------------------------------------- +// dmv_k211_device - constructor +//------------------------------------------------- + +dmv_k211_device::dmv_k211_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : dmv_k801_device(mconfig, DMV_K211, "K211 RS-232 Communications Interface", tag, owner, clock, "dmv_k211", __FILE__) +{ +} + + +dmv_k211_device::dmv_k211_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : dmv_k801_device(mconfig, type, name, tag, owner, clock, shortname, source) +{ +} + +//------------------------------------------------- +// dmv_k212_device - constructor +//------------------------------------------------- + +dmv_k212_device::dmv_k212_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : dmv_k211_device(mconfig, DMV_K212, "K212 RS-232 Printer Interface", tag, owner, clock, "dmv_k212", __FILE__) +{ +} + +//------------------------------------------------- +// dmv_k213_device - constructor +//------------------------------------------------- + +dmv_k213_device::dmv_k213_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : dmv_k211_device(mconfig, DMV_K213, "K213 RS-232 Plotter Interface", tag, owner, clock, "dmv_k213", __FILE__) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void dmv_k801_device::device_start() +{ + m_bus = static_cast(owner()); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void dmv_k801_device::device_reset() +{ +} + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor dmv_k801_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( dmv_k801 ); +} + +machine_config_constructor dmv_k211_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( dmv_k211 ); +} + +machine_config_constructor dmv_k212_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( dmv_k212 ); +} + +machine_config_constructor dmv_k213_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( dmv_k213 ); +} + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor dmv_k801_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( dmv_k801 ); +} + +ioport_constructor dmv_k211_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( dmv_k211 ); +} + +ioport_constructor dmv_k212_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( dmv_k212 ); +} + +ioport_constructor dmv_k213_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( dmv_k213 ); +} + +WRITE_LINE_MEMBER(dmv_k801_device::epci_irq_w) +{ + m_bus->m_out_irq_cb(state); +} + +void dmv_k801_device::io_read(address_space &space, int ifsel, offs_t offset, UINT8 &data) +{ + UINT8 dsw = m_dsw->read() & 0x0f; + if ((dsw >> 1) == ifsel && BIT(offset, 3) == BIT(dsw, 0)) + { + if (offset & 0x04) + m_epci->write(space, offset & 0x03, data); + else + data = m_epci->read(space, offset & 0x03); + } +} + +void dmv_k801_device::io_write(address_space &space, int ifsel, offs_t offset, UINT8 data) +{ + UINT8 dsw = m_dsw->read() & 0x0f; + if ((dsw >> 1) == ifsel && BIT(offset, 3) == BIT(dsw, 0)) + { + if (offset & 0x04) + m_epci->write(space, offset & 0x03, data); + else + data = m_epci->read(space, offset & 0x03); + } +} + +void dmv_k211_device::io_read(address_space &space, int ifsel, offs_t offset, UINT8 &data) +{ + UINT8 jumpers = m_dsw->read() & 0x03; + if ((BIT(jumpers, 0) && ifsel == 0) || (BIT(jumpers, 1) && ifsel == 1)) + { + if (offset & 0x04) + m_epci->write(space, offset & 0x03, data); + else + data = m_epci->read(space, offset & 0x03); + } +} + +void dmv_k211_device::io_write(address_space &space, int ifsel, offs_t offset, UINT8 data) +{ + UINT8 jumpers = m_dsw->read() & 0x03; + if ((BIT(jumpers, 0) && ifsel == 0) || (BIT(jumpers, 1) && ifsel == 1)) + { + if (offset & 0x04) + m_epci->write(space, offset & 0x03, data); + else + data = m_epci->read(space, offset & 0x03); + } +} diff --git a/src/devices/bus/dmv/k801.h b/src/devices/bus/dmv/k801.h new file mode 100644 index 00000000000..9ad8489a4c2 --- /dev/null +++ b/src/devices/bus/dmv/k801.h @@ -0,0 +1,106 @@ +// license:BSD-3-Clause +// copyright-holders:Sandro Ronco +#pragma once + +#ifndef __DMV_K801_H__ +#define __DMV_K801_H__ + +#include "emu.h" +#include "dmvbus.h" +#include "machine/mc2661.h" +#include "bus/rs232/rs232.h" + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> dmv_k801_device + +class dmv_k801_device : + public device_t, + public device_dmvslot_interface +{ +public: + // construction/destruction + dmv_k801_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + dmv_k801_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + // optional information overrides + virtual ioport_constructor device_input_ports() const; + virtual machine_config_constructor device_mconfig_additions() const; + + DECLARE_WRITE_LINE_MEMBER(epci_irq_w); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // dmvcart_interface overrides + virtual void io_read(address_space &space, int ifsel, offs_t offset, UINT8 &data); + virtual void io_write(address_space &space, int ifsel, offs_t offset, UINT8 data); + +protected: + required_device m_epci; + required_ioport m_dsw; + dmvcart_slot_device * m_bus; +}; + + +// ======================> dmv_k211_device + +class dmv_k211_device : + public dmv_k801_device +{ +public: + // construction/destruction + dmv_k211_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + dmv_k211_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + // optional information overrides + virtual ioport_constructor device_input_ports() const; + virtual machine_config_constructor device_mconfig_additions() const; + +protected: + // dmvcart_interface overrides + virtual void io_read(address_space &space, int ifsel, offs_t offset, UINT8 &data); + virtual void io_write(address_space &space, int ifsel, offs_t offset, UINT8 data); +}; + +// ======================> dmv_k212_device + +class dmv_k212_device : + public dmv_k211_device +{ +public: + // construction/destruction + dmv_k212_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual ioport_constructor device_input_ports() const; + virtual machine_config_constructor device_mconfig_additions() const; +}; + +// ======================> dmv_k213_device + +class dmv_k213_device : + public dmv_k211_device +{ +public: + // construction/destruction + dmv_k213_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual ioport_constructor device_input_ports() const; + virtual machine_config_constructor device_mconfig_additions() const; +}; + + +// device type definition +extern const device_type DMV_K801; +extern const device_type DMV_K211; +extern const device_type DMV_K212; +extern const device_type DMV_K213; + +#endif /* __DMV_K801_H__ */ diff --git a/src/devices/bus/dmv/k803.c b/src/devices/bus/dmv/k803.c new file mode 100644 index 00000000000..7f748cc4806 --- /dev/null +++ b/src/devices/bus/dmv/k803.c @@ -0,0 +1,133 @@ +// license:BSD-3-Clause +// copyright-holders:Sandro Ronco +/*************************************************************************** + + K803 RTC module + +***************************************************************************/ + +#include "emu.h" +#include "k803.h" + + +/*************************************************************************** + IMPLEMENTATION +***************************************************************************/ + +static MACHINE_CONFIG_FRAGMENT( dmv_k803 ) + MCFG_DEVICE_ADD("rtc", MM58167, XTAL_32_768kHz) + MCFG_MM58167_IRQ_CALLBACK(WRITELINE(dmv_k803_device, rtc_irq_w)) +MACHINE_CONFIG_END + +static INPUT_PORTS_START( dmv_k803 ) + PORT_START("DSW") + PORT_DIPNAME( 0x0f, 0x09, "K803 IFSEL" ) PORT_DIPLOCATION("S:!4,S:!3,S:!2,S:!1") + PORT_DIPSETTING( 0x00, "0A" ) + PORT_DIPSETTING( 0x01, "0B" ) + PORT_DIPSETTING( 0x02, "1A" ) + PORT_DIPSETTING( 0x03, "1B" ) + PORT_DIPSETTING( 0x04, "2A" ) + PORT_DIPSETTING( 0x05, "2B" ) + PORT_DIPSETTING( 0x06, "3A" ) + PORT_DIPSETTING( 0x07, "3B" ) + PORT_DIPSETTING( 0x08, "4A" ) + PORT_DIPSETTING( 0x09, "4B" ) // default +INPUT_PORTS_END + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type DMV_K803 = &device_creator; + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// dmv_k803_device - constructor +//------------------------------------------------- + +dmv_k803_device::dmv_k803_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, DMV_K803, "K803 RTC", tag, owner, clock, "dmv_k803", __FILE__), + device_dmvslot_interface( mconfig, *this ), + m_rtc(*this, "rtc"), + m_dsw(*this, "DSW") +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void dmv_k803_device::device_start() +{ + m_bus = static_cast(owner()); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void dmv_k803_device::device_reset() +{ + m_latch = 0; + m_rtc_int = CLEAR_LINE; +} + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor dmv_k803_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( dmv_k803 ); +} + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor dmv_k803_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( dmv_k803 ); +} + +void dmv_k803_device::io_read(address_space &space, int ifsel, offs_t offset, UINT8 &data) +{ + UINT8 dsw = m_dsw->read() & 0x0f; + if ((dsw >> 1) == ifsel && BIT(offset, 3) == BIT(dsw, 0)) + { + if (offset & 0x04) + data = m_rtc->read(space, ((m_latch & 0x07) << 2) | (offset & 0x03)); + } +} + +void dmv_k803_device::io_write(address_space &space, int ifsel, offs_t offset, UINT8 data) +{ + UINT8 dsw = m_dsw->read() & 0x0f; + if ((dsw >> 1) == ifsel && BIT(offset, 3) == BIT(dsw, 0)) + { + if (offset & 0x04) + m_rtc->write(space, ((m_latch & 0x07) << 2) | (offset & 0x03), data); + else + { + m_latch = data; + update_int(); + } + } +} + +WRITE_LINE_MEMBER(dmv_k803_device::rtc_irq_w) +{ + m_rtc_int = state; + update_int(); +} + +void dmv_k803_device::update_int() +{ + bool state = ((m_latch & 0x80) && m_rtc_int); + m_bus->m_out_int_cb(state ? ASSERT_LINE : CLEAR_LINE); +} diff --git a/src/devices/bus/dmv/k803.h b/src/devices/bus/dmv/k803.h new file mode 100644 index 00000000000..51fd9eaaa9c --- /dev/null +++ b/src/devices/bus/dmv/k803.h @@ -0,0 +1,54 @@ +// license:BSD-3-Clause +// copyright-holders:Sandro Ronco +#pragma once + +#ifndef __DMV_K803_H__ +#define __DMV_K803_H__ + +#include "emu.h" +#include "dmvbus.h" +#include "machine/mm58167.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> dmv_k803_device + +class dmv_k803_device : + public device_t, + public device_dmvslot_interface +{ +public: + // construction/destruction + dmv_k803_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual ioport_constructor device_input_ports() const; + virtual machine_config_constructor device_mconfig_additions() const; + + DECLARE_WRITE_LINE_MEMBER(rtc_irq_w); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + virtual void io_read(address_space &space, int ifsel, offs_t offset, UINT8 &data); + virtual void io_write(address_space &space, int ifsel, offs_t offset, UINT8 data); + + void update_int(); + +private: + required_device m_rtc; + required_ioport m_dsw; + dmvcart_slot_device * m_bus; + UINT8 m_latch; + int m_rtc_int; +}; + + +// device type definition +extern const device_type DMV_K803; + +#endif /* __DMV_K803_H__ */ diff --git a/src/devices/bus/dmv/k806.c b/src/devices/bus/dmv/k806.c new file mode 100644 index 00000000000..612940f01c1 --- /dev/null +++ b/src/devices/bus/dmv/k806.c @@ -0,0 +1,243 @@ +// license:BSD-3-Clause +// copyright-holders:Sandro Ronco +/*************************************************************************** + + K806 Mouse module + +***************************************************************************/ + +#include "emu.h" +#include "k806.h" + + +/*************************************************************************** + IMPLEMENTATION +***************************************************************************/ + +ROM_START( dmv_k806 ) + ROM_REGION( 0x0400, "mcu", 0 ) + ROM_LOAD( "dmv_mouse_8741a.bin", 0x0000, 0x0400, CRC(2163737a) SHA1(b82c14dba6c25cb1f60cf623989ca8c0c1ee4cc3)) +ROM_END + +static ADDRESS_MAP_START( k806_io, AS_IO, 8, dmv_k806_device ) + AM_RANGE(MCS48_PORT_P1, MCS48_PORT_P1) AM_READ(port1_r) + AM_RANGE(MCS48_PORT_P2, MCS48_PORT_P2) AM_WRITE(port2_w) + AM_RANGE(MCS48_PORT_T1, MCS48_PORT_T1) AM_READ(portt1_r) +ADDRESS_MAP_END + +static MACHINE_CONFIG_FRAGMENT( dmv_k806 ) + MCFG_CPU_ADD("mcu", I8741, XTAL_6MHz) + MCFG_CPU_IO_MAP(k806_io) + + MCFG_TIMER_DRIVER_ADD_PERIODIC("mouse_timer", dmv_k806_device, mouse_timer, attotime::from_hz(1000)) +MACHINE_CONFIG_END + +static INPUT_PORTS_START( dmv_k806 ) + PORT_START("JUMPERS") + PORT_DIPNAME( 0x7f, 0x24, "K806 IFSEL" ) PORT_DIPLOCATION("J:!1,J:!2,J:!3,J:!4,J:!5,J:!6,J:!7") + PORT_DIPSETTING( 0x21, "0A" ) + PORT_DIPSETTING( 0x41, "0B" ) + PORT_DIPSETTING( 0x22, "1A" ) + PORT_DIPSETTING( 0x42, "1B" ) + PORT_DIPSETTING( 0x24, "2A" ) // default + PORT_DIPSETTING( 0x44, "2B" ) + PORT_DIPSETTING( 0x28, "3A" ) + PORT_DIPSETTING( 0x48, "3B" ) + PORT_DIPSETTING( 0x30, "4A" ) + PORT_DIPSETTING( 0x50, "4B" ) + PORT_DIPNAME( 0x380, 0x00, "K806 Mouse" ) PORT_DIPLOCATION("J:!8,J:!9,J:!10") + PORT_DIPSETTING( 0x000, "Hawley, Alps" ) + PORT_DIPSETTING( 0x380, "Depraz" ) + + PORT_START("MOUSE") + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_BUTTON1) PORT_NAME("Righ Mouse Button") PORT_CODE(MOUSECODE_BUTTON1) + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_BUTTON3) PORT_NAME("Middte Mouse Button") PORT_CODE(MOUSECODE_BUTTON3) + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_BUTTON2) PORT_NAME("Left Mouse Button") PORT_CODE(MOUSECODE_BUTTON2) + + PORT_START("MOUSEX") + PORT_BIT( 0xfff, 0x000, IPT_MOUSE_X ) PORT_SENSITIVITY(20) PORT_KEYDELTA(0) + + PORT_START("MOUSEY") + PORT_BIT( 0xfff, 0x000, IPT_MOUSE_Y ) PORT_SENSITIVITY(20) PORT_KEYDELTA(0) +INPUT_PORTS_END + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type DMV_K806 = &device_creator; + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// dmv_k806_device - constructor +//------------------------------------------------- + +dmv_k806_device::dmv_k806_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, DMV_K806, "K806 mouse", tag, owner, clock, "dmv_k806", __FILE__), + device_dmvslot_interface( mconfig, *this ), + m_mcu(*this, "mcu"), + m_jumpers(*this, "JUMPERS"), + m_mouse_buttons(*this, "MOUSE"), + m_mouse_x(*this, "MOUSEX"), + m_mouse_y(*this, "MOUSEY") +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void dmv_k806_device::device_start() +{ + m_bus = static_cast(owner()); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void dmv_k806_device::device_reset() +{ + m_mouse.phase = 0; + m_mouse.xa = m_mouse.xb = ASSERT_LINE; + m_mouse.ya = m_mouse.yb = ASSERT_LINE; + m_mouse.x = m_mouse.y = 0; + m_mouse.prev_x = m_mouse.prev_y = 0; +} + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor dmv_k806_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( dmv_k806 ); +} + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor dmv_k806_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( dmv_k806 ); +} + +//------------------------------------------------- +// device_rom_region +//------------------------------------------------- + +const rom_entry *dmv_k806_device::device_rom_region() const +{ + return ROM_NAME( dmv_k806 ); +} + +void dmv_k806_device::io_read(address_space &space, int ifsel, offs_t offset, UINT8 &data) +{ + UINT8 jumpers = m_jumpers->read(); + if (BIT(jumpers, ifsel) && ((!BIT(offset, 3) && BIT(jumpers, 5)) || (BIT(offset, 3) && BIT(jumpers, 6)))) + data = m_mcu->upi41_master_r(space, offset & 1); +} + +void dmv_k806_device::io_write(address_space &space, int ifsel, offs_t offset, UINT8 data) +{ + UINT8 jumpers = m_jumpers->read(); + if (BIT(jumpers, ifsel) && ((!BIT(offset, 3) && BIT(jumpers, 5)) || (BIT(offset, 3) && BIT(jumpers, 6)))) + { + m_mcu->upi41_master_w(space, offset & 1, data); + m_bus->m_out_int_cb(CLEAR_LINE); + } +} + +READ8_MEMBER( dmv_k806_device::port1_r ) +{ + // ---- ---x Left button + // ---- --x- Middle button + // ---- -x-- Right button + // ---- x--- XA / Y1 + // ---x ---- XB / Y2 + // --x- ---- YA / X2 + // -x-- ---- YB / X1 + // x--- ---- not used + + UINT8 data = m_mouse_buttons->read() & 0x07; + + data |= (m_mouse.xa != CLEAR_LINE ? 0 : 0x08); + data |= (m_mouse.xb != CLEAR_LINE ? 0 : 0x10); + data |= (m_mouse.ya != CLEAR_LINE ? 0 : 0x20); + data |= (m_mouse.yb != CLEAR_LINE ? 0 : 0x40); + + return data; +} + +READ8_MEMBER( dmv_k806_device::portt1_r ) +{ + return BIT(m_jumpers->read(), 7) ? 0 : 1; +} + +WRITE8_MEMBER( dmv_k806_device::port2_w ) +{ + m_bus->m_out_int_cb((data & 1) ? CLEAR_LINE : ASSERT_LINE); +} + +/*------------------------------------------------------------------- + + Generate a sequence of pulses that have their phases shifted + by 90 degree for simulate the mouse movement. + + Right Left + -+ +---+ +---+ +--- ---+ +---+ +---+ +- + XA | | | | | | | | | | | | + +---+ +---+ +---+ +---+ +---+ +---+ + + ---+ +---+ +---+ +- -+ +---+ +---+ +--- + XB | | | | | | | | | | | | + +---+ +---+ +---+ +---+ +---+ +---+ + + Down Up + -+ +---+ +---+ +--- ---+ +---+ +---+ +- + YA | | | | | | | | | | | | + +---+ +---+ +---+ +---+ +---+ +---+ + + ---+ +---+ +---+ +- -+ +---+ +---+ +--- + YB | | | | | | | | | | | | + +---+ +---+ +---+ +---+ +---+ +---+ + +-------------------------------------------------------------------*/ + +TIMER_DEVICE_CALLBACK_MEMBER(dmv_k806_device::mouse_timer) +{ + switch(m_mouse.phase) + { + case 0: + m_mouse.xa = m_mouse.x > m_mouse.prev_x ? CLEAR_LINE : ASSERT_LINE; + m_mouse.xb = m_mouse.x < m_mouse.prev_x ? CLEAR_LINE : ASSERT_LINE; + m_mouse.ya = m_mouse.y > m_mouse.prev_y ? CLEAR_LINE : ASSERT_LINE; + m_mouse.yb = m_mouse.y < m_mouse.prev_y ? CLEAR_LINE : ASSERT_LINE; + break; + case 1: + m_mouse.xa = m_mouse.xb = m_mouse.x != m_mouse.prev_x ? CLEAR_LINE : ASSERT_LINE; + m_mouse.ya = m_mouse.yb = m_mouse.y != m_mouse.prev_y ? CLEAR_LINE : ASSERT_LINE; + break; + case 2: + m_mouse.xa = m_mouse.x < m_mouse.prev_x ? CLEAR_LINE : ASSERT_LINE; + m_mouse.xb = m_mouse.x > m_mouse.prev_x ? CLEAR_LINE : ASSERT_LINE; + m_mouse.ya = m_mouse.y < m_mouse.prev_y ? CLEAR_LINE : ASSERT_LINE; + m_mouse.yb = m_mouse.y > m_mouse.prev_y ? CLEAR_LINE : ASSERT_LINE; + break; + case 3: + m_mouse.xa = m_mouse.xb = ASSERT_LINE; + m_mouse.ya = m_mouse.yb = ASSERT_LINE; + m_mouse.prev_x = m_mouse.x; + m_mouse.prev_y = m_mouse.y; + m_mouse.x = m_mouse_x->read(); + m_mouse.y = m_mouse_y->read(); + break; + } + + m_mouse.phase = (m_mouse.phase + 1) & 3; +} diff --git a/src/devices/bus/dmv/k806.h b/src/devices/bus/dmv/k806.h new file mode 100644 index 00000000000..a1cf7c7b145 --- /dev/null +++ b/src/devices/bus/dmv/k806.h @@ -0,0 +1,72 @@ +// license:BSD-3-Clause +// copyright-holders:Sandro Ronco +#pragma once + +#ifndef __DMV_K806_H__ +#define __DMV_K806_H__ + +#include "emu.h" +#include "dmvbus.h" +#include "cpu/mcs48/mcs48.h" + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> dmv_k806_device + +class dmv_k806_device : + public device_t, + public device_dmvslot_interface +{ +public: + // construction/destruction + dmv_k806_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual ioport_constructor device_input_ports() const; + virtual machine_config_constructor device_mconfig_additions() const; + + DECLARE_READ8_MEMBER(portt1_r); + DECLARE_READ8_MEMBER(port1_r); + DECLARE_WRITE8_MEMBER(port2_w); + + TIMER_DEVICE_CALLBACK_MEMBER(mouse_timer); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + virtual void io_read(address_space &space, int ifsel, offs_t offset, UINT8 &data); + virtual void io_write(address_space &space, int ifsel, offs_t offset, UINT8 data); + +private: + required_device m_mcu; + required_ioport m_jumpers; + required_ioport m_mouse_buttons; + required_ioport m_mouse_x; + required_ioport m_mouse_y; + dmvcart_slot_device * m_bus; + + struct + { + int phase; + int x; + int y; + int prev_x; + int prev_y; + int xa; + int xb; + int ya; + int yb; + } m_mouse; +}; + + +// device type definition +extern const device_type DMV_K806; + +#endif /* __DMV_K806_H__ */ diff --git a/src/devices/bus/dmv/ram.c b/src/devices/bus/dmv/ram.c new file mode 100644 index 00000000000..32039302b14 --- /dev/null +++ b/src/devices/bus/dmv/ram.c @@ -0,0 +1,96 @@ +// license:BSD-3-Clause +// copyright-holders:Sandro Ronco +/*************************************************************************** + + K200 64K RAM expansion + K202 192K RAM expansion + K208 448K RAM expansion + +***************************************************************************/ + +#include "emu.h" +#include "ram.h" + + +/*************************************************************************** + IMPLEMENTATION +***************************************************************************/ + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type DMV_K200 = &device_creator; +const device_type DMV_K202 = &device_creator; +const device_type DMV_K208 = &device_creator; + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// dmv_ram_device - constructor +//------------------------------------------------- + +dmv_ram_device::dmv_ram_device(const machine_config &mconfig, device_type type, UINT32 size, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_dmvslot_interface( mconfig, *this ), + m_size(size) +{ +} + +//------------------------------------------------- +// dmv_k200_device - constructor +//------------------------------------------------- + +dmv_k200_device::dmv_k200_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : dmv_ram_device(mconfig, DMV_K200, 1, "K200 64K RAM expansion", tag, owner, clock, "dmv_k200", __FILE__) +{ +} + +//------------------------------------------------- +// dmv_k202_device - constructor +//------------------------------------------------- + +dmv_k202_device::dmv_k202_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : dmv_ram_device(mconfig, DMV_K202, 3, "K202 192K RAM expansion", tag, owner, clock, "dmv_k202", __FILE__) +{ +} + +//------------------------------------------------- +// dmv_k208_device - constructor +//------------------------------------------------- + +dmv_k208_device::dmv_k208_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : dmv_ram_device(mconfig, DMV_K208, 7 , "K208 448K RAM expansion", tag, owner, clock, "dmv_k208", __FILE__) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void dmv_ram_device::device_start() +{ + m_ram = machine().memory().region_alloc( "expram", m_size * 0x10000, 1, ENDIANNESS_LITTLE )->base(); +} + +//------------------------------------------------- +// read +//------------------------------------------------- + +void dmv_ram_device::ram_read(UINT8 cas, offs_t offset, UINT8 &data) +{ + if (cas && cas <= m_size) + data = m_ram[((cas - 1) << 16) | (offset & 0xffff)]; +} + +//------------------------------------------------- +// write +//------------------------------------------------- + +void dmv_ram_device::ram_write(UINT8 cas, offs_t offset, UINT8 data) +{ + if (cas && cas <= m_size) + m_ram[((cas - 1) << 16) | (offset & 0xffff)] = data; +} diff --git a/src/devices/bus/dmv/ram.h b/src/devices/bus/dmv/ram.h new file mode 100644 index 00000000000..ac841932532 --- /dev/null +++ b/src/devices/bus/dmv/ram.h @@ -0,0 +1,71 @@ +// license:BSD-3-Clause +// copyright-holders:Sandro Ronco +#pragma once + +#ifndef __DMV_RAM_H__ +#define __DMV_RAM_H__ + +#include "emu.h" +#include "dmvbus.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> + +class dmv_ram_device : + public device_t, + public device_dmvslot_interface +{ +public: + // construction/destruction + dmv_ram_device(const machine_config &mconfig, device_type type, UINT32 size, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + +protected: + // device-level overrides + virtual void device_start(); + + // dmvcart_interface overrides + virtual void ram_read(UINT8 cas, offs_t offset, UINT8 &data); + virtual void ram_write(UINT8 cas, offs_t offset, UINT8 data); + +private: + UINT8 * m_ram; + UINT8 m_size; +}; + + +class dmv_k200_device : + public dmv_ram_device +{ +public: + // construction/destruction + dmv_k200_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +class dmv_k202_device : + public dmv_ram_device +{ +public: + // construction/destruction + dmv_k202_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +class dmv_k208_device : + public dmv_ram_device +{ +public: + // construction/destruction + dmv_k208_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +// device type definition +extern const device_type DMV_K200; +extern const device_type DMV_K202; +extern const device_type DMV_K208; + +#endif /* __DMV_RAM_H__ */ diff --git a/src/devices/bus/ecbbus/ecbbus.c b/src/devices/bus/ecbbus/ecbbus.c new file mode 100644 index 00000000000..b3c5fa54ab1 --- /dev/null +++ b/src/devices/bus/ecbbus/ecbbus.c @@ -0,0 +1,211 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Kontron Europe Card Bus emulation + +**********************************************************************/ + +#include "ecbbus.h" + + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type ECBBUS_SLOT = &device_creator; + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// ecbbus_slot_device - constructor +//------------------------------------------------- + +ecbbus_slot_device::ecbbus_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, ECBBUS_SLOT, "ECB bus slot", tag, owner, clock, "ecbbus_slot", __FILE__), + device_slot_interface(mconfig, *this) +{ +} + + +//------------------------------------------------- +// static_set_ecbbus_slot - +//------------------------------------------------- + +void ecbbus_slot_device::static_set_ecbbus_slot(device_t &device, const char *tag, int num) +{ + ecbbus_slot_device &ecbbus_card = dynamic_cast(device); + ecbbus_card.m_bus_tag = tag; + ecbbus_card.m_bus_num = num; +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void ecbbus_slot_device::device_start() +{ + m_bus = machine().device(m_bus_tag); + device_ecbbus_card_interface *dev = dynamic_cast(get_card_device()); + if (dev) m_bus->add_card(dev, m_bus_num); +} + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type ECBBUS = &device_creator; + + + +//************************************************************************** +// DEVICE ECBBUS CARD INTERFACE +//************************************************************************** + +//------------------------------------------------- +// device_ecbbus_card_interface - constructor +//------------------------------------------------- + +device_ecbbus_card_interface::device_ecbbus_card_interface(const machine_config &mconfig, device_t &device) : + device_slot_card_interface(mconfig, device) +{ + m_slot = dynamic_cast(device.owner()); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// ecbbus_device - constructor +//------------------------------------------------- + +ecbbus_device::ecbbus_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, ECBBUS, "ECB bus", tag, owner, clock, "ecbbus", __FILE__), + m_write_irq(*this), + m_write_nmi(*this) +{ + for (int i = 0; i < MAX_ECBBUS_SLOTS; i++) + m_ecbbus_device[i] = NULL; +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void ecbbus_device::device_start() +{ + // resolve callbacks + m_write_irq.resolve_safe(); + m_write_nmi.resolve_safe(); +} + + +//------------------------------------------------- +// add_card - add ECB bus card +//------------------------------------------------- + +void ecbbus_device::add_card(device_ecbbus_card_interface *card, int pos) +{ + m_ecbbus_device[pos] = card; +} + + +//------------------------------------------------- +// mem_r - +//------------------------------------------------- + +READ8_MEMBER( ecbbus_device::mem_r ) +{ + UINT8 data = 0; + + for (int i = 0; i < MAX_ECBBUS_SLOTS; i++) + { + if (m_ecbbus_device[i] != NULL) + { + data |= m_ecbbus_device[i]->ecbbus_mem_r(offset); + } + } + + return data; +} + + +//------------------------------------------------- +// mem_w - +//------------------------------------------------- + +WRITE8_MEMBER( ecbbus_device::mem_w ) +{ + for (int i = 0; i < MAX_ECBBUS_SLOTS; i++) + { + if (m_ecbbus_device[i] != NULL) + { + m_ecbbus_device[i]->ecbbus_mem_w(offset, data); + } + } +} + + +//------------------------------------------------- +// io_r - +//------------------------------------------------- + +READ8_MEMBER( ecbbus_device::io_r ) +{ + UINT8 data = 0; + + for (int i = 0; i < MAX_ECBBUS_SLOTS; i++) + { + if (m_ecbbus_device[i] != NULL) + { + data |= m_ecbbus_device[i]->ecbbus_io_r(offset); + } + } + + return data; +} + + +//------------------------------------------------- +// io_w - +//------------------------------------------------- + +WRITE8_MEMBER( ecbbus_device::io_w ) +{ + for (int i = 0; i < MAX_ECBBUS_SLOTS; i++) + { + if (m_ecbbus_device[i] != NULL) + { + m_ecbbus_device[i]->ecbbus_io_w(offset, data); + } + } +} + + +//------------------------------------------------- +// SLOT_INTERFACE( ecbbus_cards ) +//------------------------------------------------- + +// slot devices +#include "grip.h" + +SLOT_INTERFACE_START( ecbbus_cards ) + SLOT_INTERFACE("grip21", ECB_GRIP21) +/* SLOT_INTERFACE("grip25", ECB_GRIP25) + SLOT_INTERFACE("grip26", ECB_GRIP26) + SLOT_INTERFACE("grip31", ECB_GRIP31) + SLOT_INTERFACE("grip562", ECB_GRIP562) + SLOT_INTERFACE("grips115", ECB_GRIPS115)*/ +SLOT_INTERFACE_END diff --git a/src/devices/bus/ecbbus/ecbbus.h b/src/devices/bus/ecbbus/ecbbus.h new file mode 100644 index 00000000000..c04a0245596 --- /dev/null +++ b/src/devices/bus/ecbbus/ecbbus.h @@ -0,0 +1,187 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Kontron Europe Card Bus emulation + +********************************************************************** + + A B C + +5 V --- * 1 * --- +5V + D5 --- * 2 * --- D0 + D6 --- * 3 * --- D7 + D3 --- * 4 * --- D2 + D4 --- * 5 * --- A0 + A2 --- * 6 * --- A3 + A4 --- * 7 * --- A1 + A5 --- * 8 * --- A8 + A6 --- * 9 * --- A7 + WAIT* --- * 10 * --- D8 + BUSRQ* --- * 11 * --- IEI + BAI1 --- * 12 * --- D9 + +12 V --- * 13 * --- D10 + D11 --- * 14 * --- D1 + -5 V --- * 15 * --- -15 V + phi2 --- * 16 * --- IEO + BAO1 --- * 17 * --- A11 + A14 --- * 18 * --- A10 + +15 V --- * 19 * --- D13 + M1* --- * 20 * --- NMI* + D14 --- * 21 * --- INT* + D15 --- * 22 * --- WR* + DPR* --- * 23 * --- D12 + +5VBAT --- * 24 * --- RD* + phiN --- * 25 * --- HALT* + WRITE EN--- * 26 * --- PWRRCL* + IORQ* --- * 27 * --- A12 + RFSH* --- * 28 * --- A15 + A13 --- * 29 * --- PHI + A9 --- * 30 * --- MREQ* + BUSAK* --- * 31 * --- RESET* + GND --- * 32 * --- GND + +**********************************************************************/ + +#pragma once + +#ifndef __ECBBUS__ +#define __ECBBUS__ + +#include "emu.h" + + +//************************************************************************** +// CONSTANTS +//************************************************************************** + +#define ECBBUS_TAG "ecbbus" + + +#define MAX_ECBBUS_SLOTS 16 + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_ECBBUS_ADD() \ + MCFG_DEVICE_ADD(ECBBUS_TAG, ECBBUS, 0) +#define MCFG_ECBBUS_SLOT_ADD(_num, _tag, _slot_intf, _def_slot) \ + MCFG_DEVICE_ADD(_tag, ECBBUS_SLOT, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) \ + ecbbus_slot_device::static_set_ecbbus_slot(*device, ECBBUS_TAG, _num); + + +#define MCFG_ECBBUS_IRQ_CALLBACK(_write) \ + devcb = &ecbbus_device::set_irq_wr_callback(*device, DEVCB_##_write); + +#define MCFG_ECBBUS_NMI_CALLBACK(_write) \ + devcb = &ecbbus_device::set_nmi_wr_callback(*device, DEVCB_##_write); + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> ecbbus_slot_device + +class ecbbus_device; + +class ecbbus_slot_device : public device_t, + public device_slot_interface +{ +public: + // construction/destruction + ecbbus_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + + // inline configuration + static void static_set_ecbbus_slot(device_t &device, const char *tag, int num); + +private: + // configuration + const char *m_bus_tag; + int m_bus_num; + ecbbus_device *m_bus; +}; + + +// device type definition +extern const device_type ECBBUS_SLOT; + + +// ======================> ecbbus_interface + +class device_ecbbus_card_interface; + + +// ======================> ecbbus_device + +class ecbbus_device : public device_t +{ +public: + // construction/destruction + ecbbus_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + template static devcb_base &set_irq_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_irq.set_callback(object); } + template static devcb_base &set_nmi_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_nmi.set_callback(object); } + + void add_card(device_ecbbus_card_interface *card, int pos); + + DECLARE_READ8_MEMBER( mem_r ); + DECLARE_WRITE8_MEMBER( mem_w ); + + DECLARE_READ8_MEMBER( io_r ); + DECLARE_WRITE8_MEMBER( io_w ); + + DECLARE_WRITE_LINE_MEMBER( irq_w ) { m_write_irq(state); } + DECLARE_WRITE_LINE_MEMBER( nmi_w ) { m_write_nmi(state); } + +protected: + // device-level overrides + virtual void device_start(); + +private: + devcb_write_line m_write_irq; + devcb_write_line m_write_nmi; + + device_ecbbus_card_interface *m_ecbbus_device[MAX_ECBBUS_SLOTS]; +}; + + +// device type definition +extern const device_type ECBBUS; + + +// ======================> device_ecbbus_card_interface + +// class representing interface-specific live ecbbus card +class device_ecbbus_card_interface : public device_slot_card_interface +{ + friend class ecbbus_device; + +public: + // construction/destruction + device_ecbbus_card_interface(const machine_config &mconfig, device_t &device); + virtual ~device_ecbbus_card_interface() { } + + // optional operation overrides + virtual UINT8 ecbbus_mem_r(offs_t offset) { return 0; }; + virtual void ecbbus_mem_w(offs_t offset, UINT8 data) { }; + virtual UINT8 ecbbus_io_r(offs_t offset) { return 0; }; + virtual void ecbbus_io_w(offs_t offset, UINT8 data) { }; + +public: + ecbbus_slot_device *m_slot; +}; + + +SLOT_INTERFACE_EXTERN( ecbbus_cards ); + + + +#endif diff --git a/src/devices/bus/ecbbus/grip.c b/src/devices/bus/ecbbus/grip.c new file mode 100644 index 00000000000..f2db25938d8 --- /dev/null +++ b/src/devices/bus/ecbbus/grip.c @@ -0,0 +1,902 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Conitec Datensysteme GRIP graphics card emulation + +**********************************************************************/ + +#include "grip.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define SCREEN_TAG "screen" +#define Z80_TAG "grip_z1" +#define MC6845_TAG "z30" +#define HD6345_TAG "z30" +#define I8255A_TAG "z6" +#define Z80STI_TAG "z9" +#define CENTRONICS_TAG "centronics" + + +#define VIDEORAM_SIZE 0x10000 + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type ECB_GRIP21 = &device_creator; + + + +//************************************************************************** +// ROMS +//************************************************************************** + +//------------------------------------------------- +// ROM( grip21 ) +//------------------------------------------------- + +ROM_START( grip21 ) + ROM_REGION( 0x4000, Z80_TAG, 0 ) + ROM_LOAD( "grip21.z2", 0x0000, 0x4000, CRC(7f6a37dd) SHA1(2e89f0b0c378257ff7e41c50d57d90865c6e214b) ) +ROM_END + + +#if 0 +//------------------------------------------------- +// ROM( grip25 ) +//------------------------------------------------- + +ROM_START( grip25 ) + ROM_REGION( 0x4000, Z80_TAG, 0 ) + ROM_LOAD( "grip25.z2", 0x0000, 0x4000, CRC(49ebb284) SHA1(0a7eaaf89da6db2750f820146c8f480b7157c6c7) ) +ROM_END + + +//------------------------------------------------- +// ROM( grip26 ) +//------------------------------------------------- + +ROM_START( grip26 ) + ROM_REGION( 0x4000, Z80_TAG, 0 ) + ROM_LOAD( "grip26.z2", 0x0000, 0x4000, CRC(a1c424f0) SHA1(83942bc75b9475f044f936b8d9d7540551d87db9) ) +ROM_END + + +//------------------------------------------------- +// ROM( grip31 ) +//------------------------------------------------- + +ROM_START( grip31 ) + ROM_REGION( 0x4000, Z80_TAG, 0 ) + ROM_LOAD( "grip31.z2", 0x0000, 0x4000, CRC(e0e4e8ab) SHA1(73d3d14c9b06fed0c187fb0fffe5ec035d8dd256) ) +ROM_END + + +//------------------------------------------------- +// ROM( grip562 ) +//------------------------------------------------- + +ROM_START( grip562 ) + ROM_REGION( 0x8000, Z80_TAG, 0 ) + ROM_LOAD( "grip562.z2", 0x0000, 0x8000, CRC(74be0455) SHA1(1c423ecca6363345a8690ddc45dbafdf277490d3) ) +ROM_END + + +//------------------------------------------------- +// ROM( grips115 ) +//------------------------------------------------- + +ROM_START( grips115 ) + ROM_REGION( 0x4000, Z80_TAG, 0 ) + ROM_LOAD( "grips115.z2", 0x0000, 0x4000, CRC(505706ef) SHA1(05fb032fb1a504c534c30c352ba4bd47623503d0) ) +ROM_END +#endif + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *grip_device::device_rom_region() const +{ + return ROM_NAME( grip21 ); +} + + + +//************************************************************************** +// ADDRESS MAPS +//************************************************************************** + +//------------------------------------------------- +// ADDRESS_MAP( grip_mem ) +//------------------------------------------------- + +static ADDRESS_MAP_START( grip_mem, AS_PROGRAM, 8, grip_device ) + AM_RANGE(0x0000, 0x3fff) AM_ROM + AM_RANGE(0x4000, 0x47ff) AM_RAM + AM_RANGE(0x8000, 0xffff) AM_RAMBANK("videoram") +ADDRESS_MAP_END + + +//------------------------------------------------- +// ADDRESS_MAP( grip_io ) +//------------------------------------------------- + +static ADDRESS_MAP_START( grip_io, AS_IO, 8, grip_device ) + ADDRESS_MAP_GLOBAL_MASK(0xff) + AM_RANGE(0x00, 0x00) AM_READWRITE(cxstb_r, cxstb_w) +// AM_RANGE(0x10, 0x10) AM_WRITE(ccon_w) + AM_RANGE(0x11, 0x11) AM_WRITE(vol0_w) +// AM_RANGE(0x12, 0x12) AM_WRITE(rts_w) + AM_RANGE(0x13, 0x13) AM_WRITE(page_w) +// AM_RANGE(0x14, 0x14) AM_WRITE(cc1_w) +// AM_RANGE(0x15, 0x15) AM_WRITE(cc2_w) + AM_RANGE(0x16, 0x16) AM_WRITE(flash_w) + AM_RANGE(0x17, 0x17) AM_WRITE(vol1_w) + AM_RANGE(0x20, 0x2f) AM_DEVREADWRITE(Z80STI_TAG, z80sti_device, read, write) + AM_RANGE(0x30, 0x30) AM_READWRITE(lrs_r, lrs_w) + AM_RANGE(0x40, 0x40) AM_READ(stat_r) + AM_RANGE(0x50, 0x50) AM_DEVWRITE(MC6845_TAG, mc6845_device, address_w) + AM_RANGE(0x52, 0x52) AM_DEVWRITE(MC6845_TAG, mc6845_device, register_w) + AM_RANGE(0x53, 0x53) AM_DEVREAD(MC6845_TAG, mc6845_device, register_r) + AM_RANGE(0x60, 0x60) AM_DEVWRITE("cent_data_out", output_latch_device, write) + AM_RANGE(0x70, 0x73) AM_DEVREADWRITE(I8255A_TAG, i8255_device, read, write) +// AM_RANGE(0x80, 0x80) AM_WRITE(bl2out_w) +// AM_RANGE(0x90, 0x90) AM_WRITE(gr2out_w) +// AM_RANGE(0xa0, 0xa0) AM_WRITE(rd2out_w) +// AM_RANGE(0xb0, 0xb0) AM_WRITE(clrg2_w) +// AM_RANGE(0xc0, 0xc0) AM_WRITE(bluout_w) +// AM_RANGE(0xd0, 0xd0) AM_WRITE(grnout_w) +// AM_RANGE(0xe0, 0xe0) AM_WRITE(redout_w) +// AM_RANGE(0xf0, 0xf0) AM_WRITE(clrg1_w) +ADDRESS_MAP_END + +/* +//------------------------------------------------- +// ADDRESS_MAP( grip5_mem ) +//------------------------------------------------- + +static ADDRESS_MAP_START( grip5_mem, AS_PROGRAM, 8, grip5_state ) + AM_RANGE(0x0000, 0x3fff) AM_ROMBANK("eprom") + AM_RANGE(0x4000, 0x5fff) AM_RAM + AM_RANGE(0x8000, 0xffff) AM_RAMBANK("videoram") +ADDRESS_MAP_END + + +//------------------------------------------------- +// ADDRESS_MAP( grip5_io ) +//------------------------------------------------- + +static ADDRESS_MAP_START( grip5_io, AS_IO, 8, grip5_device ) + ADDRESS_MAP_GLOBAL_MASK(0xff) + AM_RANGE(0x00, 0x00) AM_READWRITE(cxstb_r, cxstb_w) + AM_RANGE(0x10, 0x10) AM_WRITE(eprom_w) + AM_RANGE(0x11, 0x11) AM_WRITE(vol0_w) +// AM_RANGE(0x12, 0x12) AM_WRITE(rts_w) + AM_RANGE(0x13, 0x13) AM_WRITE(page_w) +// AM_RANGE(0x14, 0x14) AM_WRITE(str_w) +// AM_RANGE(0x15, 0x15) AM_WRITE(intl_w) + AM_RANGE(0x16, 0x16) AM_WRITE(dpage_w) + AM_RANGE(0x17, 0x17) AM_WRITE(vol1_w) + AM_RANGE(0x20, 0x2f) AM_DEVREADWRITE(Z80STI_TAG, z80sti_device, read, write) + AM_RANGE(0x30, 0x30) AM_READWRITE(lrs_r, lrs_w) + AM_RANGE(0x40, 0x40) AM_READ(stat_r) + AM_RANGE(0x50, 0x50) AM_DEVWRITE(HD6345_TAG, hd6345_device, address_w) + AM_RANGE(0x52, 0x52) AM_DEVWRITE(HD6345_TAG, hd6345_device, register_w) + AM_RANGE(0x53, 0x53) AM_DEVREAD(HD6345_TAG, hd6345_device, register_r) + AM_RANGE(0x60, 0x60) AM_DEVWRITE("cent_data_out", output_latch_device, write) + AM_RANGE(0x70, 0x73) AM_DEVREADWRITE(I8255A_TAG, i8255_device, read, write) + +// AM_RANGE(0x80, 0x80) AM_WRITE(xrflgs_w) +// AM_RANGE(0xc0, 0xc0) AM_WRITE(xrclrg_w) +// AM_RANGE(0xe0, 0xe0) AM_WRITE(xrclu0_w) +// AM_RANGE(0xe1, 0xe1) AM_WRITE(xrclu1_w) +// AM_RANGE(0xe2, 0xe2) AM_WRITE(xrclu2_w) + +// AM_RANGE(0x80, 0x80) AM_WRITE(bl2out_w) +// AM_RANGE(0x90, 0x90) AM_WRITE(gr2out_w) +// AM_RANGE(0xa0, 0xa0) AM_WRITE(rd2out_w) +// AM_RANGE(0xb0, 0xb0) AM_WRITE(clrg2_w) +// AM_RANGE(0xc0, 0xc0) AM_WRITE(bluout_w) +// AM_RANGE(0xd0, 0xd0) AM_WRITE(grnout_w) +// AM_RANGE(0xe0, 0xe0) AM_WRITE(redout_w) +// AM_RANGE(0xf0, 0xf0) AM_WRITE(clrg1_w) +ADDRESS_MAP_END +*/ + + + +//************************************************************************** +// DEVICE CONFIGURATION +//************************************************************************** + +//------------------------------------------------- +// mc6845 +//------------------------------------------------- + +MC6845_UPDATE_ROW( grip_device::crtc_update_row ) +{ + for (int column = 0; column < x_count; column++) + { + UINT16 address = (m_page << 12) | (((ma + column) & 0xfff) << 3) | (ra & 0x07); + UINT8 data = m_video_ram[address]; + + for (int bit = 0; bit < 8; bit++) + { + int x = (column * 8) + bit; + int color = (m_flash ? 0 : BIT(data, bit)) && de; + + bitmap.pix32(vbp + y, hbp + x) = m_palette->pen(color); + } + } +} +/* +MC6845_UPDATE_ROW( grip_device::grip5_update_row ) +{ + const rgb_t *palette = m_palette->palette()->entry_list_raw(); + int column, bit; + + for (column = 0; column < x_count; column++) + { + UINT16 address = (m_dpage << 12) | (((ma + column) & 0xfff) << 3) | (ra & 0x07); + UINT8 data = m_video_ram[address]; + + for (bit = 0; bit < 8; bit++) + { + int x = (column * 8) + bit; + int color = m_flash ? 0 : BIT(data, bit); + + bitmap.pix32(y, x) = palette[color]; + } + } +} + +MC6845_ON_UPDATE_ADDR_CHANGED( grip_device::grip5_addr_changed ) +{ +} +*/ + +static const INT16 speaker_levels[] = { -32768, 0, 32767, 0 }; + +//------------------------------------------------- +// I8255A interface +//------------------------------------------------- + +READ8_MEMBER( grip_device::ppi_pa_r ) +{ + /* + + bit description + + PA0 ECB bus D0 + PA1 ECB bus D1 + PA2 ECB bus D2 + PA3 ECB bus D3 + PA4 ECB bus D4 + PA5 ECB bus D5 + PA6 ECB bus D6 + PA7 ECB bus D7 + + */ + + return m_ppi_pa; +} + +WRITE8_MEMBER( grip_device::ppi_pa_w ) +{ + /* + + bit description + + PA0 ECB bus D0 + PA1 ECB bus D1 + PA2 ECB bus D2 + PA3 ECB bus D3 + PA4 ECB bus D4 + PA5 ECB bus D5 + PA6 ECB bus D6 + PA7 ECB bus D7 + + */ + + m_ppi_pa = data; +} + +READ8_MEMBER( grip_device::ppi_pb_r ) +{ + /* + + bit description + + PB0 Keyboard input + PB1 Keyboard input + PB2 Keyboard input + PB3 Keyboard input + PB4 Keyboard input + PB5 Keyboard input + PB6 Keyboard input + PB7 Keyboard input + + */ + + return m_keydata; +} + +WRITE8_MEMBER( grip_device::ppi_pc_w ) +{ + /* + + bit signal description + + PC0 INTRB interrupt B output (keyboard) + PC1 KBF input buffer B full output (keyboard) + PC2 _KBSTB strobe B input (keyboard) + PC3 INTRA interrupt A output (PROF-80) + PC4 _STBA strobe A input (PROF-80) + PC5 IBFA input buffer A full output (PROF-80) + PC6 _ACKA acknowledge A input (PROF-80) + PC7 _OBFA output buffer full output (PROF-80) + + */ + + // keyboard interrupt + m_ib = BIT(data, 0); + m_sti->i4_w(m_ib); + + // keyboard buffer full + m_kbf = BIT(data, 1); + + // PROF-80 interrupt + m_ia = BIT(data, 3); + m_sti->i7_w(m_ia); + + // PROF-80 handshaking + m_ppi_pc = (!BIT(data, 7) << 7) | (!BIT(data, 5) << 6) | (m_ppi->pa_r() & 0x3f); +} + +//------------------------------------------------- +// Z80STI_INTERFACE( sti_intf ) +//------------------------------------------------- + +WRITE_LINE_MEMBER(grip_device::write_centronics_busy) +{ + m_centronics_busy = state; +} + +READ8_MEMBER( grip_device::sti_gpio_r ) +{ + /* + + bit signal description + + I0 _CTS RS-232 clear to send input + I1 DE MC6845 display enable input + I2 CURSOR MC6845 cursor input + I3 BUSY Centronics busy input + I4 IB PPI8255 PC0 input + I5 _SKBD Serial keyboard input + I6 EXIN External interrupt input + I7 IA PPI8255 PC3 input + + */ + + UINT8 data = 0x20; + + // display enable + data |= m_crtc->de_r() << 1; + + // cursor + data |= m_crtc->cursor_r() << 2; + + // centronics busy + data |= m_centronics_busy << 3; + + // keyboard interrupt + data |= m_ib << 4; + + // PROF-80 interrupt + data |= m_ia << 7; + + return data; +} + +WRITE_LINE_MEMBER( grip_device::speaker_w ) +{ + int level = state && ((m_vol1 << 1) | m_vol0); + + m_speaker->level_w(level); +} + +//------------------------------------------------- +// z80_daisy_config grip_daisy_chain +//------------------------------------------------- + +static const z80_daisy_config grip_daisy_chain[] = +{ + { Z80STI_TAG }, + { NULL } +}; + + +//------------------------------------------------- +// ASCII_KEYBOARD_INTERFACE( kb_intf ) +//------------------------------------------------- + +WRITE8_MEMBER( grip_device::kb_w ) +{ + if (!m_kbf) + { + m_keydata = data; + + // trigger GRIP 8255 port C bit 2 (_STBB) + m_ppi->pc2_w(0); + m_ppi->pc2_w(1); + } +} + +//************************************************************************** +// MACHINE CONFIGURATION +//************************************************************************** + +//------------------------------------------------- +// MACHINE_CONFIG_FRAGMENT( grip ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( grip ) + // basic machine hardware + MCFG_CPU_ADD(Z80_TAG, Z80, XTAL_16MHz/4) + MCFG_CPU_CONFIG(grip_daisy_chain) + MCFG_CPU_PROGRAM_MAP(grip_mem) + MCFG_CPU_IO_MAP(grip_io) + + // video hardware + MCFG_SCREEN_ADD(SCREEN_TAG, RASTER) + MCFG_SCREEN_REFRESH_RATE(50) + MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(2500)) // not accurate + MCFG_SCREEN_UPDATE_DEVICE(MC6845_TAG, mc6845_device, screen_update) + MCFG_SCREEN_SIZE(640, 480) + MCFG_SCREEN_VISIBLE_AREA(0, 640-1, 0, 480-1) + + MCFG_PALETTE_ADD_BLACK_AND_WHITE("palette") + + // sound hardware + MCFG_SPEAKER_STANDARD_MONO("mono") + MCFG_SOUND_ADD("speaker", SPEAKER_SOUND, 0) + MCFG_SPEAKER_LEVELS(4, speaker_levels) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.25) + + // devices + MCFG_MC6845_ADD(MC6845_TAG, MC6845, SCREEN_TAG, XTAL_16MHz/4) + MCFG_MC6845_SHOW_BORDER_AREA(true) + MCFG_MC6845_CHAR_WIDTH(8) + MCFG_MC6845_UPDATE_ROW_CB(grip_device, crtc_update_row) + MCFG_MC6845_OUT_DE_CB(DEVWRITELINE(Z80STI_TAG, z80sti_device, i1_w)) + MCFG_MC6845_OUT_CUR_CB(DEVWRITELINE(Z80STI_TAG, z80sti_device, i1_w)) + +// MCFG_MC6845_ADD(HD6345_TAG, HD6345, SCREEN_TAG, XTAL_16MHz/4) + + MCFG_DEVICE_ADD(I8255A_TAG, I8255A, 0) + MCFG_I8255_IN_PORTA_CB(READ8(grip_device, ppi_pa_r)) + MCFG_I8255_OUT_PORTA_CB(WRITE8(grip_device, ppi_pa_w)) + MCFG_I8255_IN_PORTB_CB(READ8(grip_device, ppi_pb_r)) + MCFG_I8255_OUT_PORTC_CB(WRITE8(grip_device, ppi_pc_w)) + + MCFG_DEVICE_ADD(Z80STI_TAG, Z80STI, XTAL_16MHz/4) + MCFG_Z80STI_OUT_INT_CB(INPUTLINE(Z80_TAG, INPUT_LINE_IRQ0)) + MCFG_Z80STI_IN_GPIO_CB(READ8(grip_device, sti_gpio_r)) + MCFG_Z80STI_OUT_TBO_CB(WRITELINE(grip_device, speaker_w)) + MCFG_Z80STI_OUT_TCO_CB(DEVWRITELINE(Z80STI_TAG, z80sti_device, tc_w)) + MCFG_Z80STI_OUT_TDO_CB(DEVWRITELINE(Z80STI_TAG, z80sti_device, tc_w)) + + MCFG_CENTRONICS_ADD(CENTRONICS_TAG, centronics_devices, "printer") + MCFG_CENTRONICS_BUSY_HANDLER(WRITELINE(grip_device, write_centronics_busy)) + MCFG_CENTRONICS_FAULT_HANDLER(WRITELINE(grip_device, write_centronics_fault)) + + MCFG_CENTRONICS_OUTPUT_LATCH_ADD("cent_data_out", CENTRONICS_TAG) + + MCFG_DEVICE_ADD("keyboard", GENERIC_KEYBOARD, 0) + MCFG_GENERIC_KEYBOARD_CB(WRITE8(grip_device, kb_w)) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor grip_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( grip ); +} + + +//************************************************************************** +// INPUT PORTS +//************************************************************************** + +//------------------------------------------------- +// INPUT_PORTS( grip ) +//------------------------------------------------- + +static INPUT_PORTS_START( grip ) + PORT_START("J1") + PORT_CONFNAME( 0x01, 0x00, "J1 EPROM Type") + PORT_CONFSETTING( 0x00, "2732" ) + PORT_CONFSETTING( 0x01, "2764/27128" ) + + PORT_START("J2") + PORT_CONFNAME( 0x03, 0x00, "J2 Centronics Mode") + PORT_CONFSETTING( 0x00, "Mode 1" ) + PORT_CONFSETTING( 0x01, "Mode 2" ) + PORT_CONFSETTING( 0x02, "Mode 3" ) + + PORT_START("J3A") + PORT_CONFNAME( 0x07, 0x00, "J3 Host") + PORT_CONFSETTING( 0x00, "ECB Bus" ) + PORT_CONFSETTING( 0x01, "V24 9600 Baud" ) + PORT_CONFSETTING( 0x02, "V24 4800 Baud" ) + PORT_CONFSETTING( 0x03, "V24 1200 Baud" ) + PORT_CONFSETTING( 0x04, "Keyboard" ) + + PORT_START("J3B") + PORT_CONFNAME( 0x07, 0x00, "J3 Keyboard") + PORT_CONFSETTING( 0x00, "Parallel" ) + PORT_CONFSETTING( 0x01, "Serial (1200 Baud, 8 Bits)" ) + PORT_CONFSETTING( 0x02, "Serial (1200 Baud, 7 Bits)" ) + PORT_CONFSETTING( 0x03, "Serial (600 Baud, 8 Bits)" ) + PORT_CONFSETTING( 0x04, "Serial (600 Baud, 7 Bits)" ) + + PORT_START("J4") + PORT_CONFNAME( 0x01, 0x00, "J4 COLOR") + PORT_CONFSETTING( 0x00, DEF_STR( No ) ) + PORT_CONFSETTING( 0x01, DEF_STR( Yes ) ) + + PORT_START("J5") + PORT_CONFNAME( 0x01, 0x01, "J5 Power On Reset") + PORT_CONFSETTING( 0x00, "External" ) + PORT_CONFSETTING( 0x01, "Internal" ) + + PORT_START("J6") + PORT_CONFNAME( 0x03, 0x00, "J6 Serial Clock") + PORT_CONFSETTING( 0x00, "TC/16, TD/16, TD" ) + PORT_CONFSETTING( 0x01, "TD/16, TD/16, TD" ) + PORT_CONFSETTING( 0x02, "TC/16, BAUD/16, input" ) + PORT_CONFSETTING( 0x03, "BAUD/16, BAUD/16, input" ) + + PORT_START("J7") + PORT_CONFNAME( 0xff, 0xc0, "J7 ECB Bus Address") + PORT_CONFSETTING( 0xc0, "C0/C1" ) + PORT_CONFSETTING( 0xa0, "A0/A1" ) + + PORT_START("J8") + PORT_CONFNAME( 0x01, 0x00, "J8 Video RAM") + PORT_CONFSETTING( 0x00, "32 KB" ) + PORT_CONFSETTING( 0x01, "64 KB" ) + + PORT_START("J9") + PORT_CONFNAME( 0x01, 0x01, "J9 CPU Clock") + PORT_CONFSETTING( 0x00, "2 MHz" ) + PORT_CONFSETTING( 0x01, "4 MHz" ) + + PORT_START("J10") + PORT_CONFNAME( 0x01, 0x01, "J10 Pixel Clock") + PORT_CONFSETTING( 0x00, "External" ) + PORT_CONFSETTING( 0x01, "Internal" ) +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor grip_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( grip ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// grip_device - constructor +//------------------------------------------------- + +grip_device::grip_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, ECB_GRIP21, "GRIP-2.1", tag, owner, clock, "grip", __FILE__), + device_ecbbus_card_interface(mconfig, *this), + m_ppi(*this, I8255A_TAG), + m_sti(*this, Z80STI_TAG), + m_crtc(*this, MC6845_TAG), + m_centronics(*this, CENTRONICS_TAG), + m_palette(*this, "palette"), + m_speaker(*this, "speaker"), + m_video_ram(*this, "video_ram"), + m_j3a(*this, "J3A"), + m_j3b(*this, "J3B"), + m_j7(*this, "J7") +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void grip_device::device_start() +{ + // allocate video RAM + m_video_ram.allocate(VIDEORAM_SIZE); + + // setup GRIP memory banking + membank("videoram")->configure_entries(0, 2, m_video_ram, 0x8000); + membank("videoram")->set_entry(0); + + // allocate keyboard scan timer + m_kb_timer = timer_alloc(); + m_kb_timer->adjust(attotime::zero, 0, attotime::from_hz(2500)); + + // register for state saving + save_item(NAME(m_vol0)); + save_item(NAME(m_vol1)); + save_item(NAME(m_keydata)); + save_item(NAME(m_kbf)); + save_item(NAME(m_lps)); + save_item(NAME(m_page)); + save_item(NAME(m_flash)); +} + +/* +void grip5_state::machine_start() +{ + grip_device::machine_start(); + + // setup ROM banking + membank("eprom")->configure_entries(0, 2, memregion(Z80_TAG)->base(), 0x4000); + *this.root_device().membank("eprom")->set_entry(0); + + // register for state saving + save_item(NAME(m_dpage)); +} +*/ + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void grip_device::device_reset() +{ + m_base = m_j7->read(); + m_page = 0; + m_lps = 0; +} + + +//------------------------------------------------- +// vol0_w - volume 0 +//------------------------------------------------- + +WRITE8_MEMBER( grip_device::vol0_w ) +{ + m_vol0 = BIT(data, 7); +} + + +//------------------------------------------------- +// vol1_w - volume 1 +//------------------------------------------------- + +WRITE8_MEMBER( grip_device::vol1_w ) +{ + m_vol1 = BIT(data, 7); +} + + +//------------------------------------------------- +// flash_w - +//------------------------------------------------- + +WRITE8_MEMBER( grip_device::flash_w ) +{ + m_flash = BIT(data, 7); +} + + +//------------------------------------------------- +// page_w - video page select +//------------------------------------------------- + +WRITE8_MEMBER( grip_device::page_w ) +{ + m_page = BIT(data, 7); + + membank("videoram")->set_entry(m_page); +} + + +//------------------------------------------------- +// stat_r - +//------------------------------------------------- + +WRITE_LINE_MEMBER(grip_device::write_centronics_fault) +{ + m_centronics_fault = state; +} + +READ8_MEMBER( grip_device::stat_r ) +{ + /* + + bit signal description + + 0 LPA0 + 1 LPA1 + 2 LPA2 + 3 SENSE + 4 JS0 + 5 JS1 + 6 _ERROR + 7 LPSTB light pen strobe + + */ + + UINT8 data = 0; + int js0 = 0, js1 = 0; + + // JS0 + switch (m_j3a->read()) + { + case 0: js0 = 0; break; + case 1: js0 = 1; break; + case 2: js0 = m_vol0; break; + case 3: js0 = m_vol1; break; + case 4: js0 = m_page; break; + } + + data |= js0 << 4; + + // JS1 + switch (m_j3b->read()) + { + case 0: js1 = 0; break; + case 1: js1 = 1; break; + case 2: js1 = m_vol0; break; + case 3: js1 = m_vol1; break; + case 4: js1 = m_page; break; + } + + data |= js1 << 5; + + // centronics fault + data |= m_centronics_fault << 6; + + // light pen strobe + data |= m_lps << 7; + + return data; +} + + +//------------------------------------------------- +// lrs_r - +//------------------------------------------------- + +READ8_MEMBER( grip_device::lrs_r ) +{ + m_lps = 0; + + return 0; +} + + +//------------------------------------------------- +// lrs_w - +//------------------------------------------------- + +WRITE8_MEMBER( grip_device::lrs_w ) +{ + m_lps = 0; +} + + +//------------------------------------------------- +// cxstb_r - centronics strobe +//------------------------------------------------- + +READ8_MEMBER( grip_device::cxstb_r ) +{ + m_centronics->write_strobe(0); + m_centronics->write_strobe(1); + + return 0; +} + + +//------------------------------------------------- +// cxstb_w - centronics strobe +//------------------------------------------------- + +WRITE8_MEMBER( grip_device::cxstb_w ) +{ + m_centronics->write_strobe(0); + m_centronics->write_strobe(1); +} + +/* +//------------------------------------------------- +// eprom_w - EPROM bank select +//------------------------------------------------- + +WRITE8_MEMBER( grip5_state::eprom_w ) +{ + membank("eprom")->set_entry(BIT(data, 0)); +} + + +//------------------------------------------------- +// dpage_w - display page select +//------------------------------------------------- + +WRITE8_MEMBER( grip5_state::dpage_w ) +{ + m_dpage = BIT(data, 7); +} +*/ + + +//------------------------------------------------- +// ecbbus_io_r - I/O read +//------------------------------------------------- + +UINT8 grip_device::ecbbus_io_r(offs_t offset) +{ + UINT8 data = 0; + + if ((offset & 0xfe) == m_base) + { + if (BIT(offset, 0)) + { + data = m_ppi_pa; + + // acknowledge PPI port A + m_ppi->pc6_w(0); + m_ppi->pc6_w(1); + } + else + { + data = m_ppi_pc; + } + } + + return data; +} + + +//------------------------------------------------- +// ecbbus_io_w - I/O write +//------------------------------------------------- + +void grip_device::ecbbus_io_w(offs_t offset, UINT8 data) +{ + if ((offset & 0xfe) == m_base) + { + if (BIT(offset, 0)) + { + m_ppi_pa = data; + + // strobe PPI port A + m_ppi->pc4_w(0); + m_ppi->pc4_w(1); + } + } +} diff --git a/src/devices/bus/ecbbus/grip.h b/src/devices/bus/ecbbus/grip.h new file mode 100644 index 00000000000..9c4f098d2b9 --- /dev/null +++ b/src/devices/bus/ecbbus/grip.h @@ -0,0 +1,131 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Conitec Datensysteme GRIP graphics card emulation + +**********************************************************************/ + +#pragma once + +#ifndef __GRIP__ +#define __GRIP__ + +#include "emu.h" +#include "ecbbus.h" +#include "cpu/z80/z80.h" +#include "cpu/z80/z80daisy.h" +#include "bus/centronics/ctronics.h" +#include "machine/i8255.h" +#include "machine/keyboard.h" +#include "machine/z80sti.h" +#include "sound/speaker.h" +#include "video/mc6845.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> grip_device + +class grip_device : public device_t, + public device_ecbbus_card_interface +{ +public: + // construction/destruction + grip_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + virtual ioport_constructor device_input_ports() const; + + // not really public + DECLARE_WRITE8_MEMBER( vol0_w ); + DECLARE_WRITE8_MEMBER( vol1_w ); + DECLARE_WRITE8_MEMBER( flash_w ); + DECLARE_WRITE8_MEMBER( page_w ); + DECLARE_READ8_MEMBER( stat_r ); + DECLARE_READ8_MEMBER( lrs_r ); + DECLARE_WRITE8_MEMBER( lrs_w ); + DECLARE_READ8_MEMBER( cxstb_r ); + DECLARE_WRITE8_MEMBER( cxstb_w ); + DECLARE_READ8_MEMBER( ppi_pa_r ); + DECLARE_WRITE8_MEMBER( ppi_pa_w ); + DECLARE_READ8_MEMBER( ppi_pb_r ); + DECLARE_WRITE8_MEMBER( ppi_pc_w ); + DECLARE_READ8_MEMBER( sti_gpio_r ); + DECLARE_WRITE_LINE_MEMBER( speaker_w ); + DECLARE_WRITE8_MEMBER( kb_w ); + + DECLARE_WRITE_LINE_MEMBER( write_centronics_busy ); + DECLARE_WRITE_LINE_MEMBER( write_centronics_fault ); + + MC6845_UPDATE_ROW( crtc_update_row ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_ecbbus_card_interface overrides + virtual UINT8 ecbbus_io_r(offs_t offset); + virtual void ecbbus_io_w(offs_t offset, UINT8 data); + +private: + required_device m_ppi; + required_device m_sti; + required_device m_crtc; + required_device m_centronics; + required_device m_palette; + required_device m_speaker; + optional_shared_ptr m_video_ram; + required_ioport m_j3a; + required_ioport m_j3b; + required_ioport m_j7; + + int m_centronics_busy; + int m_centronics_fault; + + // sound state + int m_vol0; + int m_vol1; + + // keyboard state + int m_ia; // PPI port A interrupt + int m_ib; // PPI port B interrupt + UINT8 m_keydata; // keyboard data + int m_kbf; // keyboard buffer full + + // video state + int m_lps; // light pen sense + int m_page; // video page + int m_flash; // flash + + // ECB bus state + UINT8 m_base; // ECB base address + UINT8 m_ppi_pa; // PPI port A data + UINT8 m_ppi_pc; // PPI port C data + + // timers + emu_timer *m_kb_timer; +}; + + + /* + required_device m_crtc; + DECLARE_WRITE8_MEMBER( eprom_w ); + DECLARE_WRITE8_MEMBER( dpage_w ); + + // video state + int m_dpage; // displayed video page + */ + + + +// device type definition +extern const device_type ECB_GRIP21; + +#endif diff --git a/src/devices/bus/econet/e01.c b/src/devices/bus/econet/e01.c new file mode 100644 index 00000000000..bcb9b4b6bae --- /dev/null +++ b/src/devices/bus/econet/e01.c @@ -0,0 +1,716 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Acorn FileStore E01/E01S network hard disk emulation + + http://acorn.chriswhy.co.uk/Network/Econet.html + http://acorn.chriswhy.co.uk/Network/Pics/Acorn_FileStoreE01.html + http://acorn.chriswhy.co.uk/8bit_Upgrades/Acorn_FileStoreE01S.html + http://www.heyrick.co.uk/econet/fs/emulator.html + http://www.pdfio.com/k-1019481.html# + +**********************************************************************/ + +/* + + The FileStore E01 is an Econet station in its own right which acts as a fileserver when connected to a network. It is a single unit + which does not require a monitor or keyboard. Communication with the FileStore is done via another Econet station when the FileStore + is in one of two "maintenance modes" + + The E01 can be seen as a slimmed-down BBC computer tailored for its function as a fileserver. It has a 6502 processor at its heart + along with a 6522 VIA just like the BBC. It requires a Master series Econet module to be plugged in and connects to the network via + an Econet port in the same way as any other station. + + The FileStore E01S was Acorns second generation Filestore replacing the FileStore E01. The FileStore is a dedicated Econet fileserver, + it does not support a keyboard and monitor, instead you use an Econet attached station to logon and perform administrative tasks. + + Hitachi HD146818P Real Time Clock + Rockwell R65C102P3 CPU + 2 x TMM27256D-20 white labelled EPROMs, TMSE01 MOS on left and E01 FS on the right + IC20 WD2793-APL-02 floppy disc controller + 2 x NEC D41464C-12 64k x 4bit NMOS RAM ICs giving 64K memory + IC21 Rockwell RC6522AP VIA behind to the right + +*/ + +/* + + TODO: + + - centronics strobe + - econet clock speed select + - ADLC interrupts + - ECONET device + - artwork + - hard disk + + E20: Rodime RO652 (-chs 306,4,17,512) + E40S: Rodime RO3057S (-chs 680,5,26,512) + E60S: + +*/ + +#include "e01.h" +#include "bus/scsi/scsihd.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define R65C102_TAG "r65c102" +#define R6522_TAG "ic21" +#define WD2793_TAG "ic20" +#define MC6854_TAG "mc6854" +#define HD146818_TAG "hd146818" +#define CENTRONICS_TAG "centronics" +#define SCSIBUS_TAG "scsi" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type E01 = &device_creator; +const device_type E01S = &device_creator; + +e01s_device::e01s_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + :e01_device(mconfig, E01S, "Acorn FileStore E01S", tag, owner, clock, "e01s", __FILE__) { m_variant = TYPE_E01S; } + + +//------------------------------------------------- +// ROM( e01 ) +//------------------------------------------------- + +ROM_START( e01 ) + ROM_REGION( 0x10000, R65C102_TAG, 0 ) + //ROM_DEFAULT_BIOS("v131") + //ROM_SYSTEM_BIOS( 0, "v131", "V 1.31" ) + ROM_LOAD( "0254,205-04 e01 fs", 0x0000, 0x8000, CRC(ae666c76) SHA1(0954119eb5cd09cdbadf76d60d812aa845838d5a) ) + ROM_LOAD( "0254,205-03 e01 mos", 0x8000, 0x8000, CRC(a13e8014) SHA1(6f44a1a48108c60a64a1774cb30c1a59c4a6a199) ) +ROM_END + + +//------------------------------------------------- +// ROM( e01s ) +//------------------------------------------------- + +ROM_START( e01s ) + ROM_REGION( 0x10000, R65C102_TAG, 0 ) + //ROM_DEFAULT_BIOS("v140") + //ROM_SYSTEM_BIOS( 0, "v133", "V 1.33" ) // 0282,008-02 e01s rom + ROM_LOAD( "e01sv133.rom", 0x0000, 0x10000, CRC(2a4a0032) SHA1(54ad68ceae44992293ccdd64ec88ad8520deec22) ) // which label? + //ROM_SYSTEM_BIOS( 1, "v140", "V 1.40" ) + ROM_LOAD( "e01sv140.rom", 0x0000, 0x10000, CRC(5068fe86) SHA1(9b8740face15b5541e2375b3054988af00757931) ) // which label? +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *e01_device::device_rom_region() const +{ + switch (m_variant) + { + default: + case TYPE_E01: + return ROM_NAME( e01 ); + + case TYPE_E01S: + return ROM_NAME( e01s ); + } +} + + +//------------------------------------------------- +// MC146818_INTERFACE( rtc_intf ) +//------------------------------------------------- + +WRITE_LINE_MEMBER( e01_device::rtc_irq_w ) +{ + m_rtc_irq = state; + + update_interrupts(); +} + + +//------------------------------------------------- +// mc6854_interface adlc_intf +//------------------------------------------------- + +WRITE_LINE_MEMBER( e01_device::adlc_irq_w ) +{ + m_adlc_irq = state; + + update_interrupts(); +} + +WRITE_LINE_MEMBER( e01_device::econet_data_w ) +{ + m_econet->data_w(this, state); +} + +WRITE_LINE_MEMBER( e01_device::via_irq_w ) +{ + m_via_irq = state; + + update_interrupts(); +} + +WRITE_LINE_MEMBER( e01_device::clk_en_w ) +{ + m_clk_en = state; +} + +static SLOT_INTERFACE_START( e01_floppies ) + SLOT_INTERFACE( "35dd", FLOPPY_35_DD ) // NEC FD1036 A +SLOT_INTERFACE_END + +WRITE_LINE_MEMBER( e01_device::fdc_irq_w ) +{ + m_fdc_irq = state; + + update_interrupts(); +} + +WRITE_LINE_MEMBER( e01_device::fdc_drq_w ) +{ + m_fdc_drq = state; + + update_interrupts(); +} + +WRITE_LINE_MEMBER( e01_device::scsi_bsy_w ) +{ + m_scsi_ctrl_in->write_bit1(state); + + if (state) + { + m_scsibus->write_sel(0); + } +} + +WRITE_LINE_MEMBER( e01_device::scsi_req_w ) +{ + m_scsi_ctrl_in->write_bit5(state); + + if (!state) + { + m_scsibus->write_ack(0); + } + + m_hdc_irq = !state; + update_interrupts(); +} + + +//------------------------------------------------- +// ADDRESS_MAP( e01_mem ) +//------------------------------------------------- + +static ADDRESS_MAP_START( e01_mem, AS_PROGRAM, 8, e01_device ) + AM_RANGE(0x0000, 0xffff) AM_READWRITE(read, write) + AM_RANGE(0xfc00, 0xfc00) AM_MIRROR(0x00c3) AM_READWRITE(rtc_address_r, rtc_address_w) + AM_RANGE(0xfc04, 0xfc04) AM_MIRROR(0x00c3) AM_READWRITE(rtc_data_r, rtc_data_w) + AM_RANGE(0xfc08, 0xfc08) AM_MIRROR(0x00c0) AM_READ(ram_select_r) AM_WRITE(floppy_w) + AM_RANGE(0xfc0c, 0xfc0f) AM_MIRROR(0x00c0) AM_DEVREADWRITE(WD2793_TAG, wd2793_t, read, write) + AM_RANGE(0xfc10, 0xfc1f) AM_MIRROR(0x00c0) AM_DEVREADWRITE(R6522_TAG, via6522_device, read, write) + AM_RANGE(0xfc20, 0xfc23) AM_MIRROR(0x00c0) AM_DEVREADWRITE(MC6854_TAG, mc6854_device, read, write) + AM_RANGE(0xfc24, 0xfc24) AM_MIRROR(0x00c3) AM_READWRITE(network_irq_disable_r, network_irq_disable_w) + AM_RANGE(0xfc28, 0xfc28) AM_MIRROR(0x00c3) AM_READWRITE(network_irq_enable_r, network_irq_enable_w) + AM_RANGE(0xfc2c, 0xfc2c) AM_MIRROR(0x00c3) AM_READ_PORT("FLAP") + AM_RANGE(0xfc30, 0xfc30) AM_MIRROR(0x00c0) AM_READWRITE(hdc_data_r, hdc_data_w) + AM_RANGE(0xfc31, 0xfc31) AM_MIRROR(0x00c0) AM_DEVREAD("scsi_ctrl_in", input_buffer_device, read) + AM_RANGE(0xfc32, 0xfc32) AM_MIRROR(0x00c0) AM_WRITE(hdc_select_w) + AM_RANGE(0xfc33, 0xfc33) AM_MIRROR(0x00c0) AM_WRITE(hdc_irq_enable_w) +ADDRESS_MAP_END + + +//------------------------------------------------- +// MACHINE_DRIVER( e01 ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( e01 ) + // basic machine hardware + MCFG_CPU_ADD(R65C102_TAG, M65C02, XTAL_8MHz/4) // Rockwell R65C102P3 + MCFG_CPU_PROGRAM_MAP(e01_mem) + + MCFG_MC146818_ADD(HD146818_TAG, XTAL_32_768kHz) + MCFG_MC146818_IRQ_HANDLER(WRITELINE(e01_device, rtc_irq_w)) + + // devices + MCFG_DEVICE_ADD(R6522_TAG, VIA6522, XTAL_8MHz/4) + MCFG_VIA6522_WRITEPA_HANDLER(DEVWRITE8("cent_data_out", output_latch_device, write)) + MCFG_VIA6522_IRQ_HANDLER(WRITELINE(e01_device, via_irq_w)) + + MCFG_DEVICE_ADD(MC6854_TAG, MC6854, 0) + MCFG_MC6854_OUT_IRQ_CB(WRITELINE(e01_device, adlc_irq_w)) + MCFG_MC6854_OUT_TXD_CB(WRITELINE(e01_device, econet_data_w)) + MCFG_WD2793_ADD(WD2793_TAG, XTAL_8MHz/4) + MCFG_WD_FDC_INTRQ_CALLBACK(WRITELINE(e01_device, fdc_irq_w)) + MCFG_WD_FDC_DRQ_CALLBACK(WRITELINE(e01_device, fdc_drq_w)) + MCFG_FLOPPY_DRIVE_ADD(WD2793_TAG":0", e01_floppies, "35dd", floppy_image_device::default_floppy_formats) + MCFG_FLOPPY_DRIVE_ADD(WD2793_TAG":1", e01_floppies, "35dd", floppy_image_device::default_floppy_formats) + + MCFG_CENTRONICS_ADD(CENTRONICS_TAG, centronics_devices, "printer") + MCFG_CENTRONICS_ACK_HANDLER(DEVWRITELINE(R6522_TAG, via6522_device, write_ca1)) + + MCFG_CENTRONICS_OUTPUT_LATCH_ADD("cent_data_out", CENTRONICS_TAG) + + MCFG_DEVICE_ADD(SCSIBUS_TAG, SCSI_PORT, 0) + MCFG_SCSI_DATA_INPUT_BUFFER("scsi_data_in") + MCFG_SCSI_MSG_HANDLER(DEVWRITELINE("scsi_ctrl_in", input_buffer_device, write_bit0)) + MCFG_SCSI_BSY_HANDLER(WRITELINE(e01_device, scsi_bsy_w)) // bit1 + // bit 2 0 + // bit 3 0 + // bit 4 NIRQ + MCFG_SCSI_REQ_HANDLER(WRITELINE(e01_device, scsi_req_w)) // bit5 + MCFG_SCSI_IO_HANDLER(DEVWRITELINE("scsi_ctrl_in", input_buffer_device, write_bit6)) + MCFG_SCSI_CD_HANDLER(DEVWRITELINE("scsi_ctrl_in", input_buffer_device, write_bit7)) + MCFG_SCSIDEV_ADD(SCSIBUS_TAG ":" SCSI_PORT_DEVICE1, "harddisk", SCSIHD, SCSI_ID_0) + + MCFG_SCSI_OUTPUT_LATCH_ADD("scsi_data_out", SCSIBUS_TAG) + MCFG_DEVICE_ADD("scsi_data_in", INPUT_BUFFER, 0) + MCFG_DEVICE_ADD("scsi_ctrl_in", INPUT_BUFFER, 0) + + // internal ram + MCFG_RAM_ADD(RAM_TAG) + MCFG_RAM_DEFAULT_SIZE("64K") +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor e01_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( e01 ); +} + + +//------------------------------------------------- +// INPUT_PORTS( e01 ) +//------------------------------------------------- + +static INPUT_PORTS_START( e01 ) + PORT_START("FLAP") + PORT_BIT( 0x3f, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_CONFNAME( 0x40, 0x00, "Front Flap") + PORT_CONFSETTING( 0x00, "Closed" ) + PORT_CONFSETTING( 0x40, "Open" ) + PORT_DIPNAME( 0x80, 0x00, "SW3") + PORT_DIPSETTING( 0x00, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x80, DEF_STR( On ) ) +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor e01_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( e01 ); +} + + + +//************************************************************************** +// INLINE HELPERS +//************************************************************************** + +//------------------------------------------------- +// update_interrupts - update interrupt state +//------------------------------------------------- + +inline void e01_device::update_interrupts() +{ + int irq = (m_via_irq || (m_hdc_ie & m_hdc_irq) || m_rtc_irq) ? ASSERT_LINE : CLEAR_LINE; + int nmi = (m_fdc_irq || m_fdc_drq || (m_adlc_ie & m_adlc_irq)) ? ASSERT_LINE : CLEAR_LINE; + + m_maincpu->set_input_line(INPUT_LINE_IRQ0, irq); + m_maincpu->set_input_line(INPUT_LINE_NMI, nmi); +} + + +//------------------------------------------------- +// network_irq_enable - network interrupt enable +//------------------------------------------------- + +inline void e01_device::network_irq_enable(int enabled) +{ + m_adlc_ie = enabled; + + update_interrupts(); +} + + +//------------------------------------------------- +// hdc_irq_enable - hard disk interrupt enable +//------------------------------------------------- + +inline void e01_device::hdc_irq_enable(int enabled) +{ + m_hdc_ie = enabled; + + update_interrupts(); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// e01_device - constructor +//------------------------------------------------- + +e01_device::e01_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, E01, "Acorn FileStore E01", tag, owner, clock, "e01" , __FILE__), + device_econet_interface(mconfig, *this), + m_maincpu(*this, R65C102_TAG), + m_fdc(*this, WD2793_TAG), + m_adlc(*this, MC6854_TAG), + m_rtc(*this, HD146818_TAG), + m_ram(*this, RAM_TAG), + m_scsibus(*this, SCSIBUS_TAG), + m_scsi_data_out(*this, "scsi_data_out"), + m_scsi_data_in(*this, "scsi_data_in"), + m_scsi_ctrl_in(*this, "scsi_ctrl_in"), + m_floppy0(*this, WD2793_TAG":0"), + m_floppy1(*this, WD2793_TAG":1"), + m_rom(*this, R65C102_TAG), + m_centronics(*this, CENTRONICS_TAG), + m_adlc_ie(0), + m_hdc_ie(0), + m_rtc_irq(CLEAR_LINE), + m_via_irq(CLEAR_LINE), + m_hdc_irq(CLEAR_LINE), + m_fdc_irq(CLEAR_LINE), + m_fdc_drq(CLEAR_LINE), + m_adlc_irq(CLEAR_LINE), + m_clk_en(0) +{ +} + + +e01_device::e01_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_econet_interface(mconfig, *this), + m_maincpu(*this, R65C102_TAG), + m_fdc(*this, WD2793_TAG), + m_adlc(*this, MC6854_TAG), + m_rtc(*this, HD146818_TAG), + m_ram(*this, RAM_TAG), + m_scsibus(*this, SCSIBUS_TAG), + m_scsi_data_out(*this, "scsi_data_out"), + m_scsi_data_in(*this, "scsi_data_in"), + m_scsi_ctrl_in(*this, "scsi_ctrl_in"), + m_floppy0(*this, WD2793_TAG":0"), + m_floppy1(*this, WD2793_TAG":1"), + m_rom(*this, R65C102_TAG), + m_centronics(*this, CENTRONICS_TAG), + m_adlc_ie(0), + m_hdc_ie(0), + m_rtc_irq(CLEAR_LINE), + m_via_irq(CLEAR_LINE), + m_hdc_irq(CLEAR_LINE), + m_fdc_irq(CLEAR_LINE), + m_fdc_drq(CLEAR_LINE), + m_adlc_irq(CLEAR_LINE), + m_clk_en(0) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void e01_device::device_start() +{ + // allocate timers + m_clk_timer = timer_alloc(); + + // register for state saving + save_item(NAME(m_adlc_ie)); + save_item(NAME(m_hdc_ie)); + save_item(NAME(m_rtc_irq)); + save_item(NAME(m_via_irq)); + save_item(NAME(m_hdc_irq)); + save_item(NAME(m_fdc_drq)); + save_item(NAME(m_adlc_irq)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void e01_device::device_reset() +{ + m_clk_timer->adjust(attotime::zero, 0, attotime::from_hz(200000)); + m_ram_en = false; +} + + +//------------------------------------------------- +// device_timer - handler timer events +//------------------------------------------------- + +void e01_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + if (m_clk_en) + { + m_econet->clk_w(this, 1); + m_econet->clk_w(this, 0); + } +} + + +//------------------------------------------------- +// read - +//------------------------------------------------- + +READ8_MEMBER( e01_device::read ) +{ + UINT8 data = 0; + + if (m_ram_en) + { + data = m_ram->pointer()[offset]; + } + else + { + data = m_rom->base()[offset]; + } + + return data; +} + + +//------------------------------------------------- +// write - +//------------------------------------------------- + +WRITE8_MEMBER( e01_device::write ) +{ + m_ram->pointer()[offset] = data; +} + + +//------------------------------------------------- +// eprom_r - ROM/RAM select read +//------------------------------------------------- + +READ8_MEMBER( e01_device::ram_select_r ) +{ + m_ram_en = true; + + return 0; +} + + +//------------------------------------------------- +// floppy_w - floppy control write +//------------------------------------------------- + +WRITE8_MEMBER( e01_device::floppy_w ) +{ + /* + + bit description + + 0 floppy 1 select + 1 floppy 2 select + 2 floppy side select + 3 NVRAM select + 4 floppy density + 5 floppy master reset + 6 floppy test + 7 mode LED + + */ + + // floppy select + floppy_image_device *floppy = NULL; + + if (!BIT(data, 0)) floppy = m_floppy0->get_device(); + if (!BIT(data, 1)) floppy = m_floppy1->get_device(); + + m_fdc->set_floppy(floppy); + + // floppy side select + if (floppy) floppy->ss_w(BIT(data, 2)); + + // TODO NVRAM select + //mc146818_stby_w(m_rtc, BIT(data, 3)); + + // floppy density + m_fdc->dden_w(BIT(data, 4)); + + // floppy master reset + if (!BIT(data, 5)) m_fdc->soft_reset(); + + // TODO floppy test + + // mode LED + output_set_value("led_0", BIT(data, 7)); +} + + +//------------------------------------------------- +// network_irq_disable_r - +//------------------------------------------------- + +READ8_MEMBER( e01_device::network_irq_disable_r ) +{ + network_irq_enable(0); + + return 0; +} + + +//------------------------------------------------- +// network_irq_disable_w - +//------------------------------------------------- + +WRITE8_MEMBER( e01_device::network_irq_disable_w ) +{ + network_irq_enable(0); +} + + +//------------------------------------------------- +// network_irq_enable_r - +//------------------------------------------------- + +READ8_MEMBER( e01_device::network_irq_enable_r ) +{ + network_irq_enable(1); + + return 0; +} + + +//------------------------------------------------- +// network_irq_enable_w - +//------------------------------------------------- + +WRITE8_MEMBER( e01_device::network_irq_enable_w ) +{ + network_irq_enable(1); +} + + +//------------------------------------------------- +// hdc_data_r - +//------------------------------------------------- + +READ8_MEMBER( e01_device::hdc_data_r ) +{ + UINT8 data = m_scsi_data_in->read(); + + m_scsibus->write_ack(1); + + return data; +} + + +//------------------------------------------------- +// hdc_data_w - +//------------------------------------------------- + +WRITE8_MEMBER( e01_device::hdc_data_w ) +{ + m_scsi_data_out->write(data); + + m_scsibus->write_ack(1); +} + + +//------------------------------------------------- +// hdc_select_w - +//------------------------------------------------- + +WRITE8_MEMBER( e01_device::hdc_select_w ) +{ + m_scsibus->write_sel(1); +} + + +//------------------------------------------------- +// hdc_irq_enable_w - +//------------------------------------------------- + +WRITE8_MEMBER( e01_device::hdc_irq_enable_w ) +{ + hdc_irq_enable(BIT(data, 0)); +} + + +//------------------------------------------------- +// rtc_address_r - +//------------------------------------------------- + +READ8_MEMBER( e01_device::rtc_address_r ) +{ + return m_rtc->read(space, 0); +} + + +//------------------------------------------------- +// rtc_address_w - +//------------------------------------------------- + +WRITE8_MEMBER( e01_device::rtc_address_w ) +{ + m_rtc->write(space, 0, data); +} + + +//------------------------------------------------- +// rtc_data_r - +//------------------------------------------------- + +READ8_MEMBER( e01_device::rtc_data_r ) +{ + return m_rtc->read(space, 1); +} + + +//------------------------------------------------- +// rtc_data_w - +//------------------------------------------------- + +WRITE8_MEMBER( e01_device::rtc_data_w ) +{ + m_rtc->write(space, 1, data); +} + + +//------------------------------------------------- +// econet_clk_w - +//------------------------------------------------- + +void e01_device::econet_data(int state) +{ + m_adlc->set_rx(state); +} + + +//------------------------------------------------- +// econet_clk_w - +//------------------------------------------------- + +void e01_device::econet_clk(int state) +{ + m_adlc->rxc_w(state); + m_adlc->txc_w(state); +} diff --git a/src/devices/bus/econet/e01.h b/src/devices/bus/econet/e01.h new file mode 100644 index 00000000000..dc8708ef78d --- /dev/null +++ b/src/devices/bus/econet/e01.h @@ -0,0 +1,135 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Acorn FileStore E01/E01S network hard disk emulation + +**********************************************************************/ + +#pragma once + +#ifndef __E01__ +#define __E01__ + +#include "econet.h" +#include "bus/centronics/ctronics.h" +#include "bus/scsi/scsi.h" +#include "cpu/m6502/m65c02.h" +#include "machine/6522via.h" +#include "machine/buffer.h" +#include "machine/latch.h" +#include "machine/mc146818.h" +#include "machine/mc6854.h" +#include "machine/ram.h" +#include "machine/wd_fdc.h" + +class e01_device : public device_t, + public device_econet_interface +{ +public: + // construction/destruction + e01_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + e01_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + enum + { + TYPE_E01 = 0, + TYPE_E01S + }; + + DECLARE_READ8_MEMBER( read ); + DECLARE_WRITE8_MEMBER( write ); + DECLARE_READ8_MEMBER( ram_select_r ); + DECLARE_WRITE8_MEMBER( floppy_w ); + DECLARE_READ8_MEMBER( network_irq_disable_r ); + DECLARE_WRITE8_MEMBER( network_irq_disable_w ); + DECLARE_READ8_MEMBER( network_irq_enable_r ); + DECLARE_WRITE8_MEMBER( network_irq_enable_w ); + DECLARE_READ8_MEMBER( hdc_data_r ); + DECLARE_WRITE8_MEMBER( hdc_data_w ); + DECLARE_READ8_MEMBER( hdc_status_r ); + DECLARE_WRITE8_MEMBER( hdc_select_w ); + DECLARE_WRITE8_MEMBER( hdc_irq_enable_w ); + DECLARE_READ8_MEMBER( rtc_address_r ); + DECLARE_WRITE8_MEMBER( rtc_address_w ); + DECLARE_READ8_MEMBER( rtc_data_r ); + DECLARE_WRITE8_MEMBER( rtc_data_w ); + DECLARE_WRITE_LINE_MEMBER( rtc_irq_w ); + DECLARE_WRITE_LINE_MEMBER( adlc_irq_w ); + DECLARE_WRITE_LINE_MEMBER( econet_data_w ); + DECLARE_WRITE_LINE_MEMBER( via_irq_w ); + DECLARE_WRITE_LINE_MEMBER( clk_en_w ); + DECLARE_WRITE_LINE_MEMBER( fdc_irq_w ); + DECLARE_WRITE_LINE_MEMBER( fdc_drq_w ); + DECLARE_WRITE_LINE_MEMBER( scsi_bsy_w ); + DECLARE_WRITE_LINE_MEMBER( scsi_req_w ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + virtual ioport_constructor device_input_ports() const; + + // device_econet_interface overrides + virtual void econet_data(int state); + virtual void econet_clk(int state); + + required_device m_maincpu; + required_device m_fdc; + required_device m_adlc; + required_device m_rtc; + required_device m_ram; + required_device m_scsibus; + required_device m_scsi_data_out; + required_device m_scsi_data_in; + required_device m_scsi_ctrl_in; + required_device m_floppy0; + required_device m_floppy1; + required_memory_region m_rom; + required_device m_centronics; + + inline void update_interrupts(); + inline void network_irq_enable(int enabled); + inline void hdc_irq_enable(int enabled); + + // interrupt state + int m_adlc_ie; + int m_hdc_ie; + int m_rtc_irq; + int m_via_irq; + int m_hdc_irq; + int m_fdc_irq; + bool m_fdc_drq; + int m_adlc_irq; + int m_clk_en; + bool m_ram_en; + + int m_variant; + + // timers + emu_timer *m_clk_timer; +}; + + +// ======================> e01s_device + +class e01s_device : public e01_device +{ +public: + // construction/destruction + e01s_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +// device type definition +extern const device_type E01; +extern const device_type E01S; + + + +#endif diff --git a/src/devices/bus/econet/econet.c b/src/devices/bus/econet/econet.c new file mode 100644 index 00000000000..94b0bb77786 --- /dev/null +++ b/src/devices/bus/econet/econet.c @@ -0,0 +1,313 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Acorn Computers Econet local area network emulation + +**********************************************************************/ + +#include "econet.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define LOG 0 + + +static const char *const SIGNAL_NAME[] = { "CLK", "DATA" }; + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type ECONET = &device_creator; +const device_type ECONET_SLOT = &device_creator; + + + +//************************************************************************** +// DEVICE INTERFACE +//************************************************************************** + +//------------------------------------------------- +// device_econet_interface - constructor +//------------------------------------------------- + +device_econet_interface::device_econet_interface(const machine_config &mconfig, device_t &device) : + device_slot_card_interface(mconfig, device) +{ +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// econet_slot_device - constructor +//------------------------------------------------- + +econet_slot_device::econet_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, ECONET_SLOT, "Econet station", tag, owner, clock, "econet_slot", __FILE__), + device_slot_interface(mconfig, *this) +{ +} + + +//------------------------------------------------- +// static_set_slot - +//------------------------------------------------- + +void econet_slot_device::static_set_slot(device_t &device, int address) +{ + econet_slot_device &econet_card = dynamic_cast(device); + econet_card.m_address = address; +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void econet_slot_device::device_start() +{ + m_econet = machine().device(ECONET_TAG); + device_econet_interface *dev = dynamic_cast(get_card_device()); + if (dev) m_econet->add_device(get_card_device(), m_address); +} + + + +//************************************************************************** +// INLINE HELPERS +//************************************************************************** + +//------------------------------------------------- +// set_signal - +//------------------------------------------------- + +inline void econet_device::set_signal(device_t *device, int signal, int state) +{ + bool changed = false; + + if (device == this) + { + if (m_line[signal] != state) + { + if (LOG) logerror("Econet: '%s' %s %u\n", tag(), SIGNAL_NAME[signal], state); + m_line[signal] = state; + changed = true; + } + } + else + { + daisy_entry *entry = m_device_list.first(); + + while (entry) + { + if (!strcmp(entry->m_device->tag(), device->tag())) + { + if (entry->m_line[signal] != state) + { + if (LOG) logerror("Econet: '%s' %s %u\n", device->tag(), SIGNAL_NAME[signal], state); + entry->m_line[signal] = state; + changed = true; + } + } + + entry = entry->next(); + } + } + + if (changed) + { + switch (signal) + { + case CLK: m_write_clk(state); break; + case DATA: m_write_data(state); break; + } + + daisy_entry *entry = m_device_list.first(); + + while (entry) + { + switch (signal) + { + case CLK: + entry->m_interface->econet_clk(state); + break; + + case DATA: + entry->m_interface->econet_data(state); + break; + } + + entry = entry->next(); + } + + if (LOG) logerror("Econet: CLK %u DATA %u\n", get_signal(CLK), get_signal(DATA)); + } +} + + +//------------------------------------------------- +// get_signal - +//------------------------------------------------- + +inline int econet_device::get_signal(int signal) +{ + int state = m_line[signal]; + + if (state) + { + daisy_entry *entry = m_device_list.first(); + + while (entry) + { + if (!entry->m_line[signal]) + { + state = 0; + break; + } + + entry = entry->next(); + } + } + + return state; +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// econet_device - constructor +//------------------------------------------------- + +econet_device::econet_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, ECONET, "Econet", tag, owner, clock, "econet", __FILE__), + m_write_clk(*this), + m_write_data(*this) +{ + for (int i = 0; i < SIGNAL_COUNT; i++) + { + m_line[i] = 1; + } +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void econet_device::device_start() +{ + // resolve callbacks + m_write_clk.resolve_safe(); + m_write_data.resolve_safe(); +} + + +//------------------------------------------------- +// device_stop - device-specific stop +//------------------------------------------------- + +void econet_device::device_stop() +{ + m_device_list.reset(); +} + + +//------------------------------------------------- +// add_device - +//------------------------------------------------- + +void econet_device::add_device(device_t *target, int address) +{ + daisy_entry *entry = global_alloc(daisy_entry(target)); + + entry->m_interface->m_econet = this; + entry->m_interface->m_address = address; + + m_device_list.append(*entry); +} + + +//------------------------------------------------- +// daisy_entry - constructor +//------------------------------------------------- + +econet_device::daisy_entry::daisy_entry(device_t *device) : + m_next(NULL), + m_device(device), + m_interface(NULL) +{ + for (int i = 0; i < SIGNAL_COUNT; i++) + { + m_line[i] = 1; + } + + device->interface(m_interface); +} + + +//------------------------------------------------- +// clk_w - +//------------------------------------------------- + +WRITE_LINE_MEMBER( econet_device::clk_w ) +{ + set_signal(this, CLK, state); +} + + +//------------------------------------------------- +// data_w - +//------------------------------------------------- + +WRITE_LINE_MEMBER( econet_device::data_w ) +{ + set_signal(this, DATA, state); +} + + +//------------------------------------------------- +// clk_w - +//------------------------------------------------- + +void econet_device::clk_w(device_t *device, int state) +{ + set_signal(device, CLK, state); +} + + +//------------------------------------------------- +// data_w - +//------------------------------------------------- + +void econet_device::data_w(device_t *device, int state) +{ + set_signal(device, DATA, state); +} + + +//------------------------------------------------- +// SLOT_INTERFACE( econet_devices ) +//------------------------------------------------- + +// slot devices +#include "e01.h" + +SLOT_INTERFACE_START( econet_devices ) + SLOT_INTERFACE("e01", E01) + SLOT_INTERFACE("e01s", E01S) +SLOT_INTERFACE_END diff --git a/src/devices/bus/econet/econet.h b/src/devices/bus/econet/econet.h new file mode 100644 index 00000000000..e072c7bb43b --- /dev/null +++ b/src/devices/bus/econet/econet.h @@ -0,0 +1,165 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Acorn Computers Econet local area network emulation + +**********************************************************************/ + +#pragma once + +#ifndef __ECONET__ +#define __ECONET__ + +#include "emu.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define ECONET_TAG "econet" + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_ECONET_ADD() \ + MCFG_DEVICE_ADD(ECONET_TAG, ECONET, 0) + +#define MCFG_ECONET_SLOT_ADD(_tag, _num, _slot_intf, _def_slot) \ + MCFG_DEVICE_ADD(_tag, ECONET_SLOT, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) \ + econet_slot_device::static_set_slot(*device, _num); + + +#define MCFG_ECONET_CLK_CALLBACK(_write) \ + devcb = &econet_device::set_clk_wr_callback(*device, DEVCB_##_write); + +#define MCFG_ECONET_DATA_CALLBACK(_write) \ + devcb = &econet_device::set_data_wr_callback(*device, DEVCB_##_write); + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> econet_device + +class device_econet_interface; + +class econet_device : public device_t +{ +public: + // construction/destruction + econet_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + template static devcb_base &set_clk_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_clk.set_callback(object); } + template static devcb_base &set_data_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_data.set_callback(object); } + + void add_device(device_t *target, int address); + + // writes for host (driver_device) + DECLARE_WRITE_LINE_MEMBER( clk_w ); + DECLARE_WRITE_LINE_MEMBER( data_w ); + + // writes for peripherals (device_t) + void clk_w(device_t *device, int state); + void data_w(device_t *device, int state); + +protected: + enum + { + CLK = 0, + DATA, + SIGNAL_COUNT + }; + + // device-level overrides + virtual void device_start(); + virtual void device_stop(); + + class daisy_entry + { + public: + daisy_entry(device_t *device); + daisy_entry *next() const { return m_next; } + + daisy_entry * m_next; // next device + device_t * m_device; // associated device + device_econet_interface * m_interface; // associated device's daisy interface + + int m_line[SIGNAL_COUNT]; + }; + + simple_list m_device_list; + +private: + devcb_write_line m_write_clk; + devcb_write_line m_write_data; + + inline void set_signal(device_t *device, int signal, int state); + inline int get_signal(int signal); + + int m_line[SIGNAL_COUNT]; +}; + + +// ======================> econet_slot_device + +class econet_slot_device : public device_t, + public device_slot_interface +{ +public: + // construction/destruction + econet_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + + // inline configuration + static void static_set_slot(device_t &device, int address); + +private: + // configuration + UINT8 m_address; + econet_device *m_econet; +}; + + +// ======================> device_econet_interface + +class device_econet_interface : public device_slot_card_interface +{ + friend class econet_device; + +public: + // construction/destruction + device_econet_interface(const machine_config &mconfig, device_t &device); + virtual ~device_econet_interface() { } + + device_econet_interface *next() const { return m_next; } + device_econet_interface *m_next; + + virtual void econet_clk(int state) = 0; + virtual void econet_data(int state) = 0; + + econet_device *m_econet; + UINT8 m_address; +}; + + +// device type definition +extern const device_type ECONET; +extern const device_type ECONET_SLOT; + + +SLOT_INTERFACE_EXTERN( econet_devices ); + + + +#endif diff --git a/src/devices/bus/ep64/exdos.c b/src/devices/bus/ep64/exdos.c new file mode 100644 index 00000000000..f0813ff8d7e --- /dev/null +++ b/src/devices/bus/ep64/exdos.c @@ -0,0 +1,243 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Intelligent Software EXDOS Disk Controller Module emulation + +**********************************************************************/ + +/* + +Floppy Drive Controller PCB Layout +---------------------------------- + +INTELLIGENT SOFTWARE LTD DISK CONTROLLER +ISS1 + |--------------------------------------------| + | | + | | +|-| 7438 74LS273 WD1770 | +|I| | +|D| | +|C| EPROM.IC2| +|3| 74LS32 74LS02 74LS266 | +|4| 7438 | +|-| 74LS126 74LS10 74LS245 74LS266 | + | | + | | + |----------------------------||||||||||||||||| + |---------------| +Notes: (All IC's shown) + +This PCB plugs into the external expansion connector on the right side of the mainboard + + EPROM.IC2 - 16k x8-bit EPROM labelled 'EXDOS V1.0 P/N 08-60' (DIP28) + WD1770 - Western Digital WD1770 Floppy Drive Controller (DIP28) + 74LS02 - Quad 2-Input NOR Gate (DIP14) + 74LS10 - Triple 3-input NAND Gate (DIP14) + 74LS32 - Quad 2-Input Positive OR Gate (DIP14) + 7438 - Quad 2-input NAND Buffer (DIP14) + 74LS126 - Quad Bus Buffer (DIP14) + 74LS245 - Octal Bus Tranceiver with Tri-State Outputs (DIP20) + 74LS266 - Quad EXCLUSIVE-NOR Gate (DIP14) + 74LS273 - Octal D-Type Flip-Flop With Clear (DIP20) + IDC34 - IDC 34-way flat cable connector for floppy drive data cable + +*/ + +#include "exdos.h" + + + +//************************************************************************** +// MACROS/CONSTANTS +//************************************************************************** + +#define WD1770_TAG "u1" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type EP64_EXDOS = &device_creator; + + +//------------------------------------------------- +// ROM( ep64_exdos ) +//------------------------------------------------- + +ROM_START( ep64_exdos ) + ROM_REGION( 0x8000, "rom", 0 ) + ROM_LOAD( "exdos13.rom", 0x0000, 0x8000, CRC(d1d7e157) SHA1(31c8be089526aa8aa019c380cdf51ddd3ee76454) ) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *ep64_exdos_device::device_rom_region() const +{ + return ROM_NAME( ep64_exdos ); +} + + +//------------------------------------------------- +// SLOT_INTERFACE( ep64_exdos_floppies ) +//------------------------------------------------- + +FLOPPY_FORMATS_MEMBER( ep64_exdos_device::floppy_formats ) + FLOPPY_EP64_FORMAT +FLOPPY_FORMATS_END + +static SLOT_INTERFACE_START( ep64_exdos_floppies ) + SLOT_INTERFACE( "35dd", FLOPPY_35_DD ) +SLOT_INTERFACE_END + + +//------------------------------------------------- +// MACHINE_CONFIG_FRAGMENT( ep64_exdos ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( ep64_exdos ) + MCFG_WD1770_ADD(WD1770_TAG, XTAL_8MHz) + + MCFG_FLOPPY_DRIVE_ADD(WD1770_TAG":0", ep64_exdos_floppies, "35dd", ep64_exdos_device::floppy_formats) + MCFG_FLOPPY_DRIVE_ADD(WD1770_TAG":1", ep64_exdos_floppies, NULL, ep64_exdos_device::floppy_formats) + MCFG_FLOPPY_DRIVE_ADD(WD1770_TAG":2", ep64_exdos_floppies, NULL, ep64_exdos_device::floppy_formats) + MCFG_FLOPPY_DRIVE_ADD(WD1770_TAG":3", ep64_exdos_floppies, NULL, ep64_exdos_device::floppy_formats) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor ep64_exdos_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( ep64_exdos ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// ep64_exdos_device - constructor +//------------------------------------------------- + +ep64_exdos_device::ep64_exdos_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, EP64_EXDOS, "EXDOS", tag, owner, clock, "ep64_exdos", __FILE__), + device_ep64_expansion_bus_card_interface(mconfig, *this), + m_fdc(*this, WD1770_TAG), + m_floppy0(*this, WD1770_TAG":0"), + m_floppy1(*this, WD1770_TAG":1"), + m_floppy2(*this, WD1770_TAG":2"), + m_floppy3(*this, WD1770_TAG":3"), + m_floppy(NULL), + m_rom(*this, "rom") +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void ep64_exdos_device::device_start() +{ + m_slot->program().install_rom(0x080000, 0x087fff, 0, 0, m_rom->base()); + + m_slot->io().install_readwrite_handler(0x10, 0x13, 0, 0x04, READ8_DEVICE_DELEGATE(m_fdc, wd_fdc_t, read), WRITE8_DEVICE_DELEGATE(m_fdc, wd_fdc_t, write)); + m_slot->io().install_readwrite_handler(0x18, 0x18, 0, 0x04, READ8_DELEGATE(ep64_exdos_device, read), WRITE8_DELEGATE(ep64_exdos_device, write)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void ep64_exdos_device::device_reset() +{ + m_fdc->reset(); + + m_floppy = NULL; + m_fdc->set_floppy(m_floppy); + m_fdc->dden_w(0); +} + + +//------------------------------------------------- +// read - +//------------------------------------------------- + +READ8_MEMBER( ep64_exdos_device::read ) +{ + /* + + bit description + + 0 + 1 INTRQ + 2 + 3 + 4 + 5 + 6 DCHG + 7 DRQ + + */ + + UINT8 data = 0; + + data |= m_fdc->intrq_r() << 1; + data |= m_fdc->drq_r() << 7; + + data |= (m_floppy ? m_floppy->dskchg_r() : 1) << 6; + + return data; +} + + +//------------------------------------------------- +// write - +//------------------------------------------------- + +WRITE8_MEMBER( ep64_exdos_device::write ) +{ + /* + + bit description + + 0 SELECT 0 + 1 SELECT 1 + 2 SELECT 2 + 3 SELECT 3 + 4 SIDE 1 + 5 _DDEN + 6 DISK CHANGE RESET + 7 IN USE + + */ + + m_floppy = NULL; + + if (BIT(data, 0)) m_floppy = m_floppy0->get_device(); + if (BIT(data, 1)) m_floppy = m_floppy1->get_device(); + if (BIT(data, 2)) m_floppy = m_floppy2->get_device(); + if (BIT(data, 3)) m_floppy = m_floppy3->get_device(); + + m_fdc->set_floppy(m_floppy); + + if (m_floppy) + { + m_floppy->ss_w(BIT(data, 4)); + } + + m_fdc->dden_w(BIT(data, 5)); +} diff --git a/src/devices/bus/ep64/exdos.h b/src/devices/bus/ep64/exdos.h new file mode 100644 index 00000000000..2ac9f5bca85 --- /dev/null +++ b/src/devices/bus/ep64/exdos.h @@ -0,0 +1,64 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Intelligent Software EXDOS Disk Controller Module emulation + +**********************************************************************/ + +#pragma once + +#ifndef __EP64_EXDOS__ +#define __EP64_EXDOS__ + +#include "emu.h" +#include "exp.h" +#include "formats/ep64_dsk.h" +#include "machine/wd_fdc.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> ep64_exdos_device + +class ep64_exdos_device : public device_t, + public device_ep64_expansion_bus_card_interface +{ +public: + // construction/destruction + ep64_exdos_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + + DECLARE_READ8_MEMBER( read ); + DECLARE_WRITE8_MEMBER( write ); + + DECLARE_FLOPPY_FORMATS( floppy_formats ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + +private: + required_device m_fdc; + required_device m_floppy0; + required_device m_floppy1; + required_device m_floppy2; + required_device m_floppy3; + floppy_image_device *m_floppy; + required_memory_region m_rom; +}; + + +// device type definition +extern const device_type EP64_EXDOS; + + + +#endif diff --git a/src/devices/bus/ep64/exp.c b/src/devices/bus/ep64/exp.c new file mode 100644 index 00000000000..55747d8b0ea --- /dev/null +++ b/src/devices/bus/ep64/exp.c @@ -0,0 +1,90 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Enterprise Sixty Four / One Two Eight Expansion Bus emulation + +**********************************************************************/ + +#include "exp.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type EP64_EXPANSION_BUS_SLOT = &device_creator; + + + +//************************************************************************** +// DEVICE EP64_EXPANSION_BUS CARD INTERFACE +//************************************************************************** + +//------------------------------------------------- +// device_ep64_expansion_bus_card_interface - constructor +//------------------------------------------------- + +device_ep64_expansion_bus_card_interface::device_ep64_expansion_bus_card_interface(const machine_config &mconfig, device_t &device) + : device_slot_card_interface(mconfig, device) +{ + m_slot = dynamic_cast(device.owner()); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// ep64_expansion_bus_slot_device - constructor +//------------------------------------------------- + +ep64_expansion_bus_slot_device::ep64_expansion_bus_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, EP64_EXPANSION_BUS_SLOT, "Enterprise Sixty Four expansion bus slot", tag, owner, clock, "ep64_expansion_bus_slot", __FILE__), + device_slot_interface(mconfig, *this), + m_write_irq(*this), + m_write_nmi(*this), + m_write_wait(*this), + m_dave(*this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void ep64_expansion_bus_slot_device::device_start() +{ + m_card = dynamic_cast(get_card_device()); + + // resolve callbacks + m_write_irq.resolve_safe(); + m_write_nmi.resolve_safe(); + m_write_wait.resolve_safe(); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void ep64_expansion_bus_slot_device::device_reset() +{ + if (m_card) get_card_device()->reset(); +} + + +//------------------------------------------------- +// SLOT_INTERFACE( ep64_expansion_bus_cards ) +//------------------------------------------------- + +// slot devices +#include "exdos.h" + +SLOT_INTERFACE_START( ep64_expansion_bus_cards ) + SLOT_INTERFACE("exdos", EP64_EXDOS) +SLOT_INTERFACE_END diff --git a/src/devices/bus/ep64/exp.h b/src/devices/bus/ep64/exp.h new file mode 100644 index 00000000000..cbd7b4394a1 --- /dev/null +++ b/src/devices/bus/ep64/exp.h @@ -0,0 +1,151 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Enterprise Sixty Four / One Two Eight Expansion Bus emulation + +********************************************************************** + + LH SOUND IN B1 A1 RH SOUND IN + _WR B2 A2 _RFSH + _IORQ B3 A3 _RD + +17V* B4 A4 +17V* + _NMI B5 A5 _MREQ + A9 B6 A6 A8 + A11 B7 A7 A10 + A13 B8 A8 A12 + A15 B9 A9 A14 + A1 B10 A10 A0 + A3 B11 A11 A2 + A5 B12 A12 A4 + A7 B13 A13 A6 + D1 B14 A14 D0 + D3 B15 A15 D2 + D5 B16 A16 D4 + D7 B17 A17 D6 + _INT B18 A18 _RESET + GND B19 A19 _WAIT + GND B20 A20 _M1 + GND B21 A21 1M + GND B22 A22 phi + GND B23 A23 8M + EC1 B24 A24 EC0 + EC3 B25 A25 EC2 + A16 B26 A26 _EXTC + A18 B27 A27 A17 + A20 B28 A28 A19 + 14M B29 A29 A21 + VSYNC B30 A30 _LOCATE + _EXP B31 A31 GND + GND B32 A32 HSYNC + +9V B33 A33 +9V + +**********************************************************************/ + +#pragma once + +#ifndef __EP64_EXPANSION_BUS__ +#define __EP64_EXPANSION_BUS__ + +#include "emu.h" +#include "audio/dave.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define EP64_EXPANSION_BUS_TAG "exp" + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_EP64_EXPANSION_BUS_SLOT_ADD(_tag, _def_slot) \ + MCFG_DEVICE_ADD(_tag, EP64_EXPANSION_BUS_SLOT, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(ep64_expansion_bus_cards, _def_slot, false) + +#define MCFG_EP64_EXPANSION_BUS_SLOT_DAVE(_tag) \ + ep64_expansion_bus_slot_device::static_set_dave_tag(*device, "^" _tag); + +#define MCFG_EP64_EXPANSION_BUS_SLOT_IRQ_CALLBACK(_write) \ + devcb = &ep64_expansion_bus_slot_device::set_irq_wr_callback(*device, DEVCB_##_write); + +#define MCFG_EP64_EXPANSION_BUS_SLOT_NMI_CALLBACK(_write) \ + devcb = &ep64_expansion_bus_slot_device::set_nmi_wr_callback(*device, DEVCB_##_write); + +#define MCFG_EP64_EXPANSION_BUS_SLOT_WAIT_CALLBACK(_write) \ + devcb = &ep64_expansion_bus_slot_device::set_wait_wr_callback(*device, DEVCB_##_write); + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> ep64_expansion_bus_slot_device + +class device_ep64_expansion_bus_card_interface; + +class ep64_expansion_bus_slot_device : public device_t, + public device_slot_interface +{ + friend class device_ep64_expansion_bus_card_interface; + +public: + // construction/destruction + ep64_expansion_bus_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + static void static_set_dave_tag(device_t &device, const char* tag) { downcast(device).m_dave.set_tag(tag); } + template static devcb_base &set_irq_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_irq.set_callback(object); } + template static devcb_base &set_nmi_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_nmi.set_callback(object); } + template static devcb_base &set_wait_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_wait.set_callback(object); } + + DECLARE_WRITE_LINE_MEMBER( irq_w ) { m_write_irq(state); } + DECLARE_WRITE_LINE_MEMBER( nmi_w ) { m_write_nmi(state); } + DECLARE_WRITE_LINE_MEMBER( wait_w ) { m_write_wait(state); } + + address_space& program() { return m_dave->space(AS_PROGRAM); } + address_space& io() { return m_dave->space(AS_IO); } + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + +private: + devcb_write_line m_write_irq; + devcb_write_line m_write_nmi; + devcb_write_line m_write_wait; + + required_device m_dave; + + device_ep64_expansion_bus_card_interface *m_card; +}; + + +// ======================> device_ep64_expansion_bus_card_interface + +class device_ep64_expansion_bus_card_interface : public device_slot_card_interface +{ +public: + // construction/destruction + device_ep64_expansion_bus_card_interface(const machine_config &mconfig, device_t &device); + +protected: + ep64_expansion_bus_slot_device *m_slot; +}; + + +// device type definition +extern const device_type EP64_EXPANSION_BUS_SLOT; + + +SLOT_INTERFACE_EXTERN( ep64_expansion_bus_cards ); + + + +#endif diff --git a/src/devices/bus/epson_sio/epson_sio.c b/src/devices/bus/epson_sio/epson_sio.c new file mode 100644 index 00000000000..b281d076f82 --- /dev/null +++ b/src/devices/bus/epson_sio/epson_sio.c @@ -0,0 +1,115 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best +/********************************************************************** + + EPSON SIO port emulation + +**********************************************************************/ + +#include "epson_sio.h" + +// supported devices +#include "pf10.h" +#include "tf20.h" + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type EPSON_SIO = &device_creator; + + +//************************************************************************** +// CARD INTERFACE +//************************************************************************** + +//------------------------------------------------- +// device_epson_sio_interface - constructor +//------------------------------------------------- + +device_epson_sio_interface::device_epson_sio_interface(const machine_config &mconfig, device_t &device) : + device_slot_card_interface(mconfig, device) +{ + m_slot = dynamic_cast(device.owner()); +} + + +//------------------------------------------------- +// ~device_epson_sio_interface - destructor +//------------------------------------------------- + +device_epson_sio_interface::~device_epson_sio_interface() +{ +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// epson_sio_device - constructor +//------------------------------------------------- + +epson_sio_device::epson_sio_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, EPSON_SIO, "EPSON SIO port", tag, owner, clock, "epson_sio", __FILE__), + device_slot_interface(mconfig, *this), + m_write_rx(*this), + m_write_pin(*this) +{ +} + + +//------------------------------------------------- +// epson_sio_device - destructor +//------------------------------------------------- + +epson_sio_device::~epson_sio_device() +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void epson_sio_device::device_start() +{ + m_cart = dynamic_cast(get_card_device()); + + m_write_rx.resolve_safe(); + m_write_pin.resolve_safe(); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void epson_sio_device::device_reset() +{ +} + + +WRITE_LINE_MEMBER( epson_sio_device::tx_w ) +{ + if (m_cart != NULL) + m_cart->tx_w(state); +} + +WRITE_LINE_MEMBER( epson_sio_device::pout_w ) +{ + if (m_cart != NULL) + m_cart->pout_w(state); +} + + +//************************************************************************** +// SLOT INTERFACE +//************************************************************************** + +SLOT_INTERFACE_START( epson_sio_devices ) + SLOT_INTERFACE("pf10", EPSON_PF10) + SLOT_INTERFACE("tf20", EPSON_TF20) +SLOT_INTERFACE_END diff --git a/src/devices/bus/epson_sio/epson_sio.h b/src/devices/bus/epson_sio/epson_sio.h new file mode 100644 index 00000000000..828d64a3eae --- /dev/null +++ b/src/devices/bus/epson_sio/epson_sio.h @@ -0,0 +1,96 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best +/********************************************************************** + + EPSON SIO port emulation + +**********************************************************************/ + +#pragma once + +#ifndef __EPSON_SIO_H__ +#define __EPSON_SIO_H__ + +#include "emu.h" + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_EPSON_SIO_ADD(_tag, _def_slot) \ + MCFG_DEVICE_ADD(_tag, EPSON_SIO, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(epson_sio_devices, _def_slot, false) + +#define MCFG_EPSON_SIO_RX(_rx) \ + downcast(device)->set_rx_callback(DEVCB_##_rx); + +#define MCFG_EPSON_SIO_PIN(_pin) \ + downcast(device)->set_pin_callback(DEVCB_##_pin); + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class device_epson_sio_interface; + + +class epson_sio_device : public device_t, + public device_slot_interface +{ +public: + // construction/destruction + epson_sio_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual ~epson_sio_device(); + + // callbacks + template void set_rx_callback(_rx rx) { m_write_rx.set_callback(rx); } + template void set_pin_callback(_pin pin) { m_write_pin.set_callback(pin); } + + // called from owner + DECLARE_WRITE_LINE_MEMBER( tx_w ); + DECLARE_WRITE_LINE_MEMBER( pout_w ); + + // called from subdevice + DECLARE_WRITE_LINE_MEMBER( rx_w ) { m_write_rx(state); } + DECLARE_WRITE_LINE_MEMBER( pin_w ) { m_write_pin(state); } + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + device_epson_sio_interface *m_cart; + +private: + devcb_write_line m_write_rx; + devcb_write_line m_write_pin; +}; + + +// class representing interface-specific live sio device +class device_epson_sio_interface : public device_slot_card_interface +{ +public: + // construction/destruction + device_epson_sio_interface(const machine_config &mconfig, device_t &device); + virtual ~device_epson_sio_interface(); + + virtual void tx_w(int state) { }; + virtual void pout_w(int state) { }; + +protected: + epson_sio_device *m_slot; +}; + + +// device type definition +extern const device_type EPSON_SIO; + + +// supported devices +SLOT_INTERFACE_EXTERN( epson_sio_devices ); + + +#endif // __EPSON_SIO_H__ diff --git a/src/devices/bus/epson_sio/pf10.c b/src/devices/bus/epson_sio/pf10.c new file mode 100644 index 00000000000..e3b6651e2b9 --- /dev/null +++ b/src/devices/bus/epson_sio/pf10.c @@ -0,0 +1,241 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best +/********************************************************************** + + EPSON PF-10 + + Battery operated portable 3.5" floppy drive + + Status: Needs lots of work. + +**********************************************************************/ + +#include "pf10.h" + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type EPSON_PF10 = &device_creator; + + +//------------------------------------------------- +// address maps +//------------------------------------------------- + +static ADDRESS_MAP_START( cpu_mem, AS_PROGRAM, 8, epson_pf10_device ) + AM_RANGE(0x0000, 0x001f) AM_DEVREADWRITE("maincpu", hd6303y_cpu_device, m6801_io_r, m6801_io_w) + AM_RANGE(0x0040, 0x00ff) AM_RAM /* 192 bytes internal ram */ + AM_RANGE(0x0800, 0x0fff) AM_RAM /* external 2k ram */ + AM_RANGE(0x1000, 0x17ff) AM_READWRITE(fdc_r, fdc_w) + AM_RANGE(0x1800, 0x1fff) AM_WRITE(fdc_tc_w) + AM_RANGE(0xe000, 0xffff) AM_ROM AM_REGION("maincpu", 0) +ADDRESS_MAP_END + +static ADDRESS_MAP_START( cpu_io, AS_IO, 8, epson_pf10_device ) + AM_RANGE(M6801_PORT1, M6801_PORT1) AM_READWRITE(port1_r, port1_w) + AM_RANGE(M6801_PORT2, M6801_PORT2) AM_READWRITE(port2_r, port2_w) +ADDRESS_MAP_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +ROM_START( pf10 ) + ROM_REGION(0x2000, "maincpu", 0) + ROM_LOAD("k3pf1.bin", 0x0000, 0x2000, CRC(eef4593a) SHA1(bb176e4baf938fe58c2d32f7c46d7bb7b0627755)) +ROM_END + +const rom_entry *epson_pf10_device::device_rom_region() const +{ + return ROM_NAME( pf10 ); +} + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +static SLOT_INTERFACE_START( pf10_floppies ) + SLOT_INTERFACE( "smd165", EPSON_SMD_165 ) +SLOT_INTERFACE_END + +static MACHINE_CONFIG_FRAGMENT( pf10 ) + MCFG_CPU_ADD("maincpu", HD6303Y, XTAL_4_9152MHz) // HD63A03XF + MCFG_CPU_PROGRAM_MAP(cpu_mem) + MCFG_CPU_IO_MAP(cpu_io) + MCFG_M6801_SER_TX(DEVWRITELINE(DEVICE_SELF, epson_pf10_device, hd6303_tx_w)) + + MCFG_UPD765A_ADD("upd765a", false, true) + MCFG_FLOPPY_DRIVE_ADD("upd765a:0", pf10_floppies, "smd165", floppy_image_device::default_floppy_formats) + + MCFG_EPSON_SIO_ADD("sio", NULL) + MCFG_EPSON_SIO_RX(DEVWRITELINE(DEVICE_SELF, epson_pf10_device, rxc_w)) + MCFG_EPSON_SIO_PIN(DEVWRITELINE(DEVICE_SELF, epson_pf10_device, pinc_w)) +MACHINE_CONFIG_END + +machine_config_constructor epson_pf10_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( pf10 ); +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// epson_pf10_device - constructor +//------------------------------------------------- + +epson_pf10_device::epson_pf10_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, EPSON_PF10, "EPSON PF-10 Portable Floppy Unit", tag, owner, clock, "epson_pf10", __FILE__), + device_epson_sio_interface(mconfig, *this), + m_cpu(*this, "maincpu"), + m_fdc(*this, "upd765a"), + m_sio_output(*this, "sio"), + m_port1(0xff), + m_port2(0xff), + m_rxc(1) +{ + m_sio_input = dynamic_cast(owner); +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void epson_pf10_device::device_start() +{ + m_timer = timer_alloc(0, NULL); + m_floppy = subdevice("upd765a:0")->get_device(); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void epson_pf10_device::device_reset() +{ + m_timer->adjust(attotime::zero, 0, attotime::from_hz(38400 * 8)); +} + +//------------------------------------------------- +// device_timer - handler timer events +//------------------------------------------------- + +void epson_pf10_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch (id) + { + case 0: + m_cpu->m6801_clock_serial(); + break; + } +} + + +//************************************************************************** +// CPU +//************************************************************************** + +READ8_MEMBER( epson_pf10_device::port1_r ) +{ + logerror("%s: port1_r(%02x)\n", tag(), m_port1); + return m_port1; +} + +WRITE8_MEMBER( epson_pf10_device::port1_w ) +{ + logerror("%s: port1_w(%02x)\n", tag(), data); +} + +READ8_MEMBER( epson_pf10_device::port2_r ) +{ + logerror("%s: port2_r(%02x)\n", tag(), m_port2); + return m_port2; +} + +WRITE8_MEMBER( epson_pf10_device::port2_w ) +{ + m_floppy->mon_w(data & PORT2_MON); + logerror("%s: port2_w(%02x)\n", tag(), data); +} + +READ8_MEMBER( epson_pf10_device::fdc_r ) +{ + logerror("%s: fdc_r @ %04x\n", tag(), offset); + return 0xff; +} + +WRITE8_MEMBER( epson_pf10_device::fdc_w ) +{ + logerror("%s: fdc_w @ %04x (%02x)\n", tag(), offset, data); +} + +WRITE8_MEMBER( epson_pf10_device::fdc_tc_w ) +{ + logerror("%s: fdc_tc_w(%02x)\n", tag(), data); +} + + +//************************************************************************** +// SIO INTERFACE +//************************************************************************** + +//------------------------------------------------- +// rxc_w - rx input +//------------------------------------------------- + +WRITE_LINE_MEMBER( epson_pf10_device::rxc_w ) +{ + m_rxc = state; + m_sio_input->rx_w(m_hd6303_tx & m_rxc); +} + +//------------------------------------------------- +// pinc_w - pin input +//------------------------------------------------- + +WRITE_LINE_MEMBER( epson_pf10_device::pinc_w ) +{ + m_pinc = state; + m_sio_input->pin_w(m_pinc); +} + +//------------------------------------------------- +// hd6303_tx_w - rx output +//------------------------------------------------- + +WRITE_LINE_MEMBER( epson_pf10_device::hd6303_tx_w ) +{ + m_hd6303_tx = state; + m_sio_input->rx_w(m_hd6303_tx & m_rxc); +} + +//------------------------------------------------- +// tx_w - tx input +//------------------------------------------------- + +void epson_pf10_device::tx_w(int level) +{ + if (level) + m_port2 |= PORT2_RXD; + else + m_port2 &= ~PORT2_RXD; + + m_sio_output->tx_w(level); +} + +//------------------------------------------------- +// pout_w - pout input +//------------------------------------------------- + +void epson_pf10_device::pout_w(int level) +{ + m_sio_output->pout_w(level); +} diff --git a/src/devices/bus/epson_sio/pf10.h b/src/devices/bus/epson_sio/pf10.h new file mode 100644 index 00000000000..dd937ff0526 --- /dev/null +++ b/src/devices/bus/epson_sio/pf10.h @@ -0,0 +1,101 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best +/********************************************************************** + + EPSON PF-10 + + Battery operated portable 3.5" floppy drive + +**********************************************************************/ + +#pragma once + +#ifndef __PF10_H__ +#define __PF10_H__ + +#include "emu.h" +#include "cpu/m6800/m6800.h" +#include "machine/upd765.h" +#include "epson_sio.h" + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class epson_pf10_device : public device_t, + public device_epson_sio_interface +{ +public: + // construction/destruction + epson_pf10_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + + // floppy disk controller + DECLARE_READ8_MEMBER( fdc_r ); + DECLARE_WRITE8_MEMBER( fdc_w ); + DECLARE_WRITE8_MEMBER( fdc_tc_w ); + + // hd6303 i/o + DECLARE_READ8_MEMBER( port1_r ); + DECLARE_WRITE8_MEMBER( port1_w ); + DECLARE_READ8_MEMBER( port2_r ); + DECLARE_WRITE8_MEMBER( port2_w ); + + // serial output from main cpu + DECLARE_WRITE_LINE_MEMBER( hd6303_tx_w ); + + // from sio output + DECLARE_WRITE_LINE_MEMBER( rxc_w ); + DECLARE_WRITE_LINE_MEMBER( pinc_w ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + // device_epson_sio_interface overrides + virtual void tx_w(int level); + virtual void pout_w(int level); + +private: + required_device m_cpu; + required_device m_fdc; + required_device m_sio_output; + + epson_sio_device *m_sio_input; + floppy_image_device *m_floppy; + + emu_timer *m_timer; + + UINT8 m_port1; + UINT8 m_port2; + + int m_rxc; + int m_hd6303_tx; + int m_pinc; + + // port definitions + enum + { + PORT2_SEEK = 0x01, + PORT2_SWCOM = 0x02, // ? + PORT2_RS232ON = 0x04, // to nmi? + PORT2_RXD = 0x08, + PORT2_TXD = 0x10, + PORT2_FDCRST = 0x20, + PORT2_MON = 0x40, + PORT2_BATCKEN = 0x80 // ? + }; +}; + + +// device type definition +extern const device_type EPSON_PF10; + + +#endif // __PF10_H__ diff --git a/src/devices/bus/epson_sio/tf20.c b/src/devices/bus/epson_sio/tf20.c new file mode 100644 index 00000000000..084ca861be0 --- /dev/null +++ b/src/devices/bus/epson_sio/tf20.c @@ -0,0 +1,320 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best +/********************************************************************** + + EPSON TF-20 + + Dual 5.25" floppy drive with HX-20 factory option + + Status: Needs testing. + + http://fjkraan.home.xs4all.nl/comp/tf20/index.html + +**********************************************************************/ + +#include "tf20.h" + +#define XTAL_CR1 XTAL_8MHz +#define XTAL_CR2 XTAL_4_9152MHz + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type EPSON_TF20 = &device_creator; + +//------------------------------------------------- +// address maps +//------------------------------------------------- + +static ADDRESS_MAP_START( cpu_mem, AS_PROGRAM, 8, epson_tf20_device ) + AM_RANGE(0x0000, 0x7fff) AM_RAMBANK("bank1") + AM_RANGE(0x8000, 0xffff) AM_RAMBANK("bank2") +ADDRESS_MAP_END + +static ADDRESS_MAP_START( cpu_io, AS_IO, 8, epson_tf20_device ) + ADDRESS_MAP_UNMAP_HIGH + ADDRESS_MAP_GLOBAL_MASK(0xff) + AM_RANGE(0xf0, 0xf3) AM_DEVREADWRITE("3a", upd7201_device, ba_cd_r, ba_cd_w) + AM_RANGE(0xf6, 0xf6) AM_READ(rom_disable_r) + AM_RANGE(0xf7, 0xf7) AM_READ_PORT("tf20_dip") + AM_RANGE(0xf8, 0xf8) AM_READWRITE(upd765_tc_r, fdc_control_w) + AM_RANGE(0xfa, 0xfb) AM_DEVICE("5a", upd765a_device, map) +ADDRESS_MAP_END + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +ROM_START( tf20 ) + ROM_REGION(0x0800, "rom", 0) + ROM_LOAD("tfx.15e", 0x0000, 0x0800, CRC(af34f084) SHA1(c9bdf393f757ba5d8f838108ceb2b079be1d616e)) +ROM_END + +const rom_entry *epson_tf20_device::device_rom_region() const +{ + return ROM_NAME( tf20 ); +} + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +INPUT_PORTS_START( tf20 ) + PORT_START("tf20_dip") + PORT_DIPNAME(0x0f, 0x00, "Drive extension") + PORT_DIPLOCATION("TF-20:8,7,6,5") + PORT_DIPSETTING(0x00, "A & B Drive") + PORT_DIPSETTING(0x01, "C & D Drive") +INPUT_PORTS_END + +ioport_constructor epson_tf20_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( tf20 ); +} + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +static SLOT_INTERFACE_START( tf20_floppies ) + SLOT_INTERFACE( "sd320", EPSON_SD_320 ) +SLOT_INTERFACE_END + +static MACHINE_CONFIG_FRAGMENT( tf20 ) + MCFG_CPU_ADD("19b", Z80, XTAL_CR1 / 2) /* uPD780C */ + MCFG_CPU_PROGRAM_MAP(cpu_mem) + MCFG_CPU_IO_MAP(cpu_io) + MCFG_CPU_IRQ_ACKNOWLEDGE_DEVICE(DEVICE_SELF, epson_tf20_device,irq_callback) + + // 64k internal ram + MCFG_RAM_ADD("ram") + MCFG_RAM_DEFAULT_SIZE("64k") + + // upd7201 serial interface + MCFG_UPD7201_ADD("3a", XTAL_CR1 / 2, 0, 0, 0, 0) + MCFG_Z80DART_OUT_TXDA_CB(WRITELINE(epson_tf20_device, txda_w)) + MCFG_Z80DART_OUT_DTRA_CB(WRITELINE(epson_tf20_device, dtra_w)) + + // floppy disk controller + MCFG_UPD765A_ADD("5a", true, true) + MCFG_UPD765_INTRQ_CALLBACK(INPUTLINE("19b", INPUT_LINE_IRQ0)) + + // floppy drives + MCFG_FLOPPY_DRIVE_ADD("5a:0", tf20_floppies, "sd320", floppy_image_device::default_floppy_formats) + MCFG_FLOPPY_DRIVE_ADD("5a:1", tf20_floppies, "sd320", floppy_image_device::default_floppy_formats) + + // serial interface to another device + MCFG_EPSON_SIO_ADD("sio", NULL) + MCFG_EPSON_SIO_RX(DEVWRITELINE(DEVICE_SELF, epson_tf20_device, rxc_w)) + MCFG_EPSON_SIO_PIN(DEVWRITELINE(DEVICE_SELF, epson_tf20_device, pinc_w)) +MACHINE_CONFIG_END + +machine_config_constructor epson_tf20_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( tf20 ); +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// epson_tf20_device - constructor +//------------------------------------------------- + +epson_tf20_device::epson_tf20_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, EPSON_TF20, "EPSON TF-20 Dual Floppy Disk Drive", tag, owner, clock, "epson_tf20", __FILE__), + device_epson_sio_interface(mconfig, *this), + m_cpu(*this, "19b"), + m_ram(*this, "ram"), + m_fdc(*this, "5a"), + m_mpsc(*this, "3a"), + m_sio_output(*this, "sio"), + m_rxc(1) +{ + m_sio_input = dynamic_cast(owner); +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void epson_tf20_device::device_start() +{ + // make sure the ram device is already running + if (!m_ram->started()) + throw device_missing_dependencies(); + + m_timer_serial = timer_alloc(0, NULL); + m_timer_tc = timer_alloc(1, NULL); + + m_fd0 = subdevice("5a:0")->get_device(); + m_fd1 = subdevice("5a:1")->get_device(); + + // enable second half of ram + m_cpu->space(AS_PROGRAM).install_ram(0x8000, 0xffff, m_ram->pointer() + 0x8000); + +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void epson_tf20_device::device_reset() +{ + // init timers + m_timer_serial->adjust(attotime::zero, 0, attotime::from_hz(XTAL_CR2 / 8)); + m_timer_tc->adjust(attotime::never); + + m_mpsc->rxa_w(1); + m_mpsc->rxb_w(1); + + // enable rom + m_cpu->space(AS_PROGRAM).install_rom(0x0000, 0x07ff, 0, 0x7800, memregion("rom")->base()); +} + +//------------------------------------------------- +// device_timer - handler timer events +//------------------------------------------------- + +void epson_tf20_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch (id) + { + case 0: + m_mpsc->rxca_w(1); + m_mpsc->rxca_w(0); + m_mpsc->txca_w(1); + m_mpsc->txca_w(0); + m_mpsc->rxcb_w(1); + m_mpsc->rxcb_w(0); + m_mpsc->txcb_w(1); + m_mpsc->txcb_w(0); + break; + + case 1: + logerror("%s: tc off\n", tag()); + m_fdc->tc_w(false); + break; + } +} + + +//************************************************************************** +// CPU & MEMORY +//************************************************************************** + +//------------------------------------------------- +// irq vector callback +//------------------------------------------------- + +IRQ_CALLBACK_MEMBER( epson_tf20_device::irq_callback ) +{ + return 0x00; +} + +// a read from this location disables the rom +READ8_MEMBER( epson_tf20_device::rom_disable_r ) +{ + // switch in ram + m_cpu->space(AS_PROGRAM).install_ram(0x0000, 0x7fff, m_ram->pointer()); + return 0xff; +} + + +//************************************************************************** +// FLOPPY DISK CONTROLLER +//************************************************************************** + +//------------------------------------------------- +// fdc interrupt +//------------------------------------------------- + +READ8_MEMBER( epson_tf20_device::upd765_tc_r ) +{ + logerror("%s: upd765_tc_r\n", space.machine().describe_context()); + + // toggle tc on read + m_fdc->tc_w(true); + m_timer_tc->adjust(attotime::zero); + + return 0xff; +} + +WRITE8_MEMBER( epson_tf20_device::fdc_control_w ) +{ + logerror("%s: tf20_fdc_control_w(%02x)\n", space.machine().describe_context(), data); + + // bit 0, motor on signal + m_fd0->mon_w(!BIT(data, 0)); + m_fd1->mon_w(!BIT(data, 0)); +} + + +//************************************************************************** +// SIO INTERFACE +//************************************************************************** + +//------------------------------------------------- +// rxc_w - rx input +//------------------------------------------------- + +WRITE_LINE_MEMBER( epson_tf20_device::rxc_w ) +{ + m_rxc = state; + m_sio_input->rx_w(m_txda && m_rxc); +} + +//------------------------------------------------- +// pinc_w - pin input +//------------------------------------------------- + +WRITE_LINE_MEMBER( epson_tf20_device::pinc_w ) +{ + m_pinc = state; + m_sio_input->pin_w(!m_dtra || m_pinc); +} + +//------------------------------------------------- +// txda_w - rx output +//------------------------------------------------- + +WRITE_LINE_MEMBER( epson_tf20_device::txda_w ) +{ + m_txda = state; + m_sio_input->rx_w(m_txda && m_rxc); +} + +//------------------------------------------------- +// dtra_w - pin output +//------------------------------------------------- + +WRITE_LINE_MEMBER( epson_tf20_device::dtra_w ) +{ + m_dtra = state; + m_sio_input->pin_w(!m_dtra || m_pinc); +} + +//------------------------------------------------- +// tx_w - tx input +//------------------------------------------------- + +void epson_tf20_device::tx_w(int level) +{ + m_mpsc->rxa_w(level); + m_sio_output->tx_w(level); +} + +//------------------------------------------------- +// pout_w - pout input +//------------------------------------------------- + +void epson_tf20_device::pout_w(int level) +{ + m_mpsc->ctsa_w(!level); + m_sio_output->pout_w(level); +} diff --git a/src/devices/bus/epson_sio/tf20.h b/src/devices/bus/epson_sio/tf20.h new file mode 100644 index 00000000000..a51848ffc38 --- /dev/null +++ b/src/devices/bus/epson_sio/tf20.h @@ -0,0 +1,91 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best +/********************************************************************** + + EPSON TF-20 + + Dual 5.25" floppy drive with HX-20 factory option + +**********************************************************************/ + +#pragma once + +#ifndef __TF20_H__ +#define __TF20_H__ + +#include "emu.h" +#include "cpu/z80/z80.h" +#include "machine/ram.h" +#include "machine/upd765.h" +#include "machine/z80dart.h" +#include "epson_sio.h" + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class epson_tf20_device : public device_t, + public device_epson_sio_interface +{ +public: + // construction/destruction + epson_tf20_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + virtual ioport_constructor device_input_ports() const; + + // not really public + DECLARE_READ8_MEMBER( rom_disable_r ); + DECLARE_READ8_MEMBER( upd765_tc_r ); + DECLARE_WRITE8_MEMBER( fdc_control_w ); + IRQ_CALLBACK_MEMBER( irq_callback ); + DECLARE_WRITE_LINE_MEMBER( txda_w ); + DECLARE_WRITE_LINE_MEMBER( dtra_w ); + + // from sio output + DECLARE_WRITE_LINE_MEMBER( rxc_w ); + DECLARE_WRITE_LINE_MEMBER( pinc_w ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + // device_epson_sio_interface overrides + virtual void tx_w(int level); + virtual void pout_w(int level); + +private: + required_device m_cpu; + required_device m_ram; + required_device m_fdc; + required_device m_mpsc; + required_device m_sio_output; + + floppy_image_device *m_fd0; + floppy_image_device *m_fd1; + + emu_timer *m_timer_serial; + emu_timer *m_timer_tc; + + int m_rxc; + int m_txda; + int m_dtra; + int m_pinc; + + epson_sio_device *m_sio_input; + + static const int XTAL_CR1 = XTAL_8MHz; + static const int XTAL_CR2 = XTAL_4_9152MHz; +}; + + +// device type definition +extern const device_type EPSON_TF20; + + +#endif // __TF20_H__ diff --git a/src/devices/bus/gameboy/gb_slot.c b/src/devices/bus/gameboy/gb_slot.c new file mode 100644 index 00000000000..922dc91cce2 --- /dev/null +++ b/src/devices/bus/gameboy/gb_slot.c @@ -0,0 +1,860 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli, Wilbert Pol +/*********************************************************************************************************** + + + Game Boy cart emulation + (through slot devices) + + + The driver exposes address ranges + 0x0000-0x7fff to read_rom/write_bank + 0xa000-0xbfff to read_ram/write_ram (typically RAM/NVRAM accesses, but megaduck uses the write for bankswitch) + + currently available slot devices: + gb_rom: standard carts + TAMA5 mapper + pirate carts with protection & bankswitch + gb_mbc: MBC1-MBC7 carts (more complex bankswitch + RAM + possibly RTC/Rumble/etc.) + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "gb_slot.h" + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type GB_CART_SLOT = &device_creator; +const device_type MEGADUCK_CART_SLOT = &device_creator; + +//************************************************************************** +// GB cartridges Interface +//************************************************************************** + +//------------------------------------------------- +// device_gb_cart_interface - constructor +//------------------------------------------------- + +device_gb_cart_interface::device_gb_cart_interface(const machine_config &mconfig, device_t &device) + : device_slot_card_interface(mconfig, device), + m_rom(NULL), + m_rom_size(0), + has_rumble(false), + has_timer(false), + has_battery(false) +{ +} + + +//------------------------------------------------- +// ~device_gb_cart_interface - destructor +//------------------------------------------------- + +device_gb_cart_interface::~device_gb_cart_interface() +{ +} + +//------------------------------------------------- +// rom_alloc - alloc the space for the cart +//------------------------------------------------- + +void device_gb_cart_interface::rom_alloc(UINT32 size, const char *tag) +{ + if (m_rom == NULL) + { + m_rom = device().machine().memory().region_alloc(std::string(tag).append(GBSLOT_ROM_REGION_TAG).c_str(), size, 1, ENDIANNESS_LITTLE)->base(); + m_rom_size = size; + } +} + + +//------------------------------------------------- +// ram_alloc - alloc the space for the ram +//------------------------------------------------- + +void device_gb_cart_interface::ram_alloc(UINT32 size) +{ + m_ram.resize(size); +} + + +//------------------------------------------------- +// rom_map_setup - setup map of rom banks in 16K +// blocks, so to simplify ROM access +//------------------------------------------------- + +void device_gb_cart_interface::rom_map_setup(UINT32 size) +{ + int i; + // setup the rom_bank_map array to faster ROM read + for (i = 0; i < size / 0x4000; i++) + rom_bank_map[i] = i; + + // fill up remaining blocks with mirrors + while (i % 512) + { + int j = 0, repeat_banks; + while ((i % (512 >> j)) && j < 9) + j++; + repeat_banks = i % (512 >> (j - 1)); + for (int k = 0; k < repeat_banks; k++) + rom_bank_map[i + k] = rom_bank_map[i + k - repeat_banks]; + i += repeat_banks; + } + +// check bank map! +// for (i = 0; i < 256; i++) +// { +// printf("bank %3d = %3d\t", i, rom_bank_map[i]); +// if ((i%8) == 7) +// printf("\n"); +// } +} + +//------------------------------------------------- +// ram_map_setup - setup map of ram banks in 16K +// blocks, so to simplify ROM access +//------------------------------------------------- + +void device_gb_cart_interface::ram_map_setup(UINT8 banks) +{ + int mask = banks - 1; + + for (int i = 0; i < banks; i++) + ram_bank_map[i] = i; + + // Set up rest of the (mirrored) RAM pages + for (int i = banks; i < 256; i++) + ram_bank_map[i] = i & mask; +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// base_gb_cart_slot_device - constructor +//------------------------------------------------- +base_gb_cart_slot_device::base_gb_cart_slot_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_image_interface(mconfig, *this), + device_slot_interface(mconfig, *this), + m_sgb_hack(0), + m_type(GB_MBC_UNKNOWN) +{ +} + +gb_cart_slot_device::gb_cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + base_gb_cart_slot_device(mconfig, GB_CART_SLOT, "Game Boy Cartridge Slot", tag, owner, clock, "gb_cart_slot", __FILE__) +{ +} + +megaduck_cart_slot_device::megaduck_cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + base_gb_cart_slot_device(mconfig, MEGADUCK_CART_SLOT, "Megaduck Cartridge Slot", tag, owner, clock, "megaduck_cart_slot", __FILE__) +{ +} + +//------------------------------------------------- +// base_gb_cart_slot_device - destructor +//------------------------------------------------- + +base_gb_cart_slot_device::~base_gb_cart_slot_device() +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void base_gb_cart_slot_device::device_start() +{ + m_cart = dynamic_cast(get_card_device()); +} + +//------------------------------------------------- +// device_config_complete - perform any +// operations now that the configuration is +// complete +//------------------------------------------------- + +void base_gb_cart_slot_device::device_config_complete() +{ + // set brief and instance name + update_names(); +} + + +//------------------------------------------------- +// GB PCB +//------------------------------------------------- + + +struct gb_slot +{ + int pcb_id; + const char *slot_option; +}; + +// Here, we take the feature attribute from .xml (i.e. the PCB name) and we assign a unique ID to it +static const gb_slot slot_list[] = +{ + { GB_MBC_MBC1, "rom_mbc1" }, + { GB_MBC_MBC1_COL, "rom_mbc1col" }, + { GB_MBC_MBC2, "rom_mbc2" }, + { GB_MBC_MBC3, "rom_mbc3" }, + { GB_MBC_MBC5, "rom_mbc5" }, + { GB_MBC_MBC6, "rom_mbc6" }, + { GB_MBC_MBC7, "rom_mbc7" }, + { GB_MBC_TAMA5, "rom_tama5" }, + { GB_MBC_MMM01, "rom_mmm01" }, + { GB_MBC_M161, "rom_m161_m12" }, + { GB_MBC_MBC3, "rom_huc1" }, // for now treat this as alias for MBC3 + { GB_MBC_MBC3, "rom_huc3" }, // for now treat this as alias for MBC3 + { GB_MBC_SACHEN1, "rom_sachen1" }, + { GB_MBC_SACHEN2, "rom_sachen2" }, + { GB_MBC_WISDOM, "rom_wisdom" }, + { GB_MBC_YONGYONG, "rom_yong" }, + { GB_MBC_LASAMA, "rom_lasama" }, + { GB_MBC_ATVRACIN, "rom_atvrac" }, + { GB_MBC_SINTAX, "rom_sintax" }, + { GB_MBC_CHONGWU, "rom_chong" }, + { GB_MBC_LICHENG, "rom_licheng" }, + { GB_MBC_DIGIMON, "rom_digimon" }, + { GB_MBC_ROCKMAN8, "rom_rock8" }, + { GB_MBC_SM3SP, "rom_sm3sp" }, + { GB_MBC_UNK01, "rom_unk01" }, + { GB_MBC_DKONG5, "rom_dkong5" }, + { GB_MBC_CAMERA, "rom_camera" }, + { GB_MBC_188IN1, "rom_188in1" } +}; + +static int gb_get_pcb_id(const char *slot) +{ + for (int i = 0; i < ARRAY_LENGTH(slot_list); i++) + { + if (!core_stricmp(slot_list[i].slot_option, slot)) + return slot_list[i].pcb_id; + } + + return 0; +} + +static const char *gb_get_slot(int type) +{ + for (int i = 0; i < ARRAY_LENGTH(slot_list); i++) + { + if (slot_list[i].pcb_id == type) + return slot_list[i].slot_option; + } + + return "rom"; +} + + +/*------------------------------------------------- + call load + -------------------------------------------------*/ + + +bool base_gb_cart_slot_device::call_load() +{ + if (m_cart) + { + UINT32 offset = 0; + UINT32 len = (software_entry() == NULL) ? length() : get_software_region_length("rom"); + UINT8 *ROM; + int rambanks = 0; + + // From fullpath, check for presence of a header and skip it + check filesize is valid + if (software_entry() == NULL) + { + if ((len % 0x4000) == 512) + { + logerror("Rom-header found, skipping\n"); + offset = 512; + len -= offset; + fseek(offset, SEEK_SET); + } + /* Verify that the file contains 16kb blocks */ + if ((len == 0) || ((len % 0x4000) != 0)) + { + seterror(IMAGE_ERROR_UNSPECIFIED, "Invalid rom file size\n"); + return IMAGE_INIT_FAIL; + } + } + + m_cart->rom_alloc(len, tag()); + ROM = m_cart->get_rom_base(); + + if (software_entry() == NULL) + fread(ROM, len); + else + memcpy(ROM, get_software_region("rom"), len); + + // determine cart type + offset = 0; + if (get_mmm01_candidate(ROM, len)) + offset = len - 0x8000; + + if (software_entry() != NULL) + m_type = gb_get_pcb_id(get_feature("slot") ? get_feature("slot") : "rom"); + else + m_type = get_cart_type(ROM + offset, len - offset); + + // setup additional mask/shift for MBC1 variants: + // a few game collections use the same mapper with slightly + // different lines connection with the ROM / RAM + if (m_type == GB_MBC_MBC1 || m_type == GB_MBC_188IN1) + m_cart->set_additional_wirings(0x1f, 0); + if (m_type == GB_MBC_MBC1_COL) + m_cart->set_additional_wirings(0x0f, -1); + + // setup RAM/NVRAM/RTC/RUMBLE + if (software_entry() != NULL) + { + // from softlist we only rely on xml + if (get_software_region("ram")) + rambanks = get_software_region_length("ram") / 0x2000; + + if (get_software_region("nvram")) + { + m_cart->set_has_battery(true); + rambanks = get_software_region_length("nvram") / 0x2000; + } + + if (get_feature("rumble")) + { + if (!core_stricmp(get_feature("rumble"), "yes")) + m_cart->set_has_rumble(true); + } + + if (get_feature("rtc")) + { + if (!core_stricmp(get_feature("rtc"), "yes")) + m_cart->set_has_timer(true); + } + } + else + { + // from fullpath we rely on header + switch (ROM[0x0147 + offset]) + { + case 0x03: case 0x06: case 0x09: case 0x0d: case 0x13: case 0x17: case 0x1b: case 0x22: + m_cart->set_has_battery(true); + break; + + case 0x0f: case 0x10: + m_cart->set_has_battery(true); + m_cart->set_has_timer(true); + break; + + case 0x1c: case 0x1d: + m_cart->set_has_rumble(true); + break; + + case 0x1e: + m_cart->set_has_battery(true); + m_cart->set_has_rumble(true); + break; + } + + switch (ROM[0x0149 + offset] & 0x07) + { + case 0x00: case 0x06: case 0x07: + rambanks = 0; + break; + case 0x01: case 0x02: + rambanks = 1; + break; + case 0x03: + rambanks = 4; + break; + case 0x04: + rambanks = 16; + break; + case 0x05: + default: + rambanks = 8; + break; + } + + if (m_type == GB_MBC_MBC2 || m_type == GB_MBC_MBC7) + rambanks = 1; + } + + // setup rom bank map based on real length, not header value + m_cart->rom_map_setup(len); + + if (rambanks) + setup_ram(rambanks); + + if (m_cart->get_ram_size() && m_cart->get_has_battery()) + battery_load(m_cart->get_ram_base(), m_cart->get_ram_size(), 0xff); + + //printf("Type: %s\n", gb_get_slot(m_type)); + + internal_header_logging(ROM + offset, len); + + // Hack to support Donkey Kong Land 2 + 3 in SGB + // For some reason, these store the tile data differently. Hacks will go once it's been figured out + if (strncmp((const char*)(ROM + 0x134), "DONKEYKONGLAND 2", 16) == 0 || + strncmp((const char*)(ROM + 0x134), "DONKEYKONGLAND 3", 16) == 0) + m_sgb_hack = 1; + + return IMAGE_INIT_PASS; + } + + return IMAGE_INIT_PASS; +} + +bool megaduck_cart_slot_device::call_load() +{ + if (m_cart) + { + UINT32 len = (software_entry() == NULL) ? length() : get_software_region_length("rom"); + + m_cart->rom_alloc(len, tag()); + + if (software_entry() == NULL) + fread(m_cart->get_rom_base(), len); + else + memcpy(m_cart->get_rom_base(), get_software_region("rom"), len); + + // setup rom bank map based on real length, not header value + m_cart->rom_map_setup(len); + + return IMAGE_INIT_PASS; + } + + return IMAGE_INIT_PASS; +} + + +/*------------------------------------------------- + call_unload + -------------------------------------------------*/ + +void base_gb_cart_slot_device::call_unload() +{ + if (m_cart && m_cart->get_ram_base() && m_cart->get_ram_size() && m_cart->get_has_battery()) + battery_save(m_cart->get_ram_base(), m_cart->get_ram_size()); +} + +void base_gb_cart_slot_device::setup_ram(UINT8 banks) +{ + m_cart->ram_alloc(banks * 0x2000); + memset(m_cart->get_ram_base(), 0xff, m_cart->get_ram_size()); + m_cart->ram_map_setup(banks); +} + + + +/*------------------------------------------------- + call softlist load + -------------------------------------------------*/ + +bool base_gb_cart_slot_device::call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry) +{ + load_software_part_region(*this, swlist, swname, start_entry); + return true; +} + +// This fails to catch Mani 4-in-1 carts... even when they match this, then they have MBC1/3 in the internal header instead of MMM01... +bool base_gb_cart_slot_device::get_mmm01_candidate(UINT8 *ROM, UINT32 len) +{ + if (len < 0x8147) + return false; + + static const UINT8 nintendo_logo[0x18] = { + 0xCE, 0xED, 0x66, 0x66, 0xCC, 0x0D, 0x00, 0x0B, + 0x03, 0x73, 0x00, 0x83, 0x00, 0x0C, 0x00, 0x0D, + 0x00, 0x08, 0x11, 0x1F, 0x88, 0x89, 0x00, 0x0E + }; + int bytes_matched = 0; + for (int i = 0; i < 0x18; i++) + { + if (ROM[(len - 0x8000) + 0x104 + i] == nintendo_logo[i]) + bytes_matched++; + } + + if (bytes_matched == 0x18 && ROM[(len - 0x8000) + 0x147] >= 0x0b && ROM[(len - 0x8000) + 0x147] <= 0x0d) + return true; + else + return false; +} + +int base_gb_cart_slot_device::get_cart_type(UINT8 *ROM, UINT32 len) +{ + int type = GB_MBC_NONE; + + if (len < 0x014c) + fatalerror("Checking header of a corrupted image!\n"); + + switch(ROM[0x0147]) + { + case 0x00: type = GB_MBC_NONE; break; + case 0x01: type = GB_MBC_MBC1; break; + case 0x02: type = GB_MBC_MBC1; break; + case 0x03: type = GB_MBC_MBC1; break; + case 0x05: type = GB_MBC_MBC2; break; + case 0x06: type = GB_MBC_MBC2; break; + case 0x08: type = GB_MBC_NONE; break; + case 0x09: type = GB_MBC_NONE; break; + case 0x0b: type = GB_MBC_MMM01; break; + case 0x0c: type = GB_MBC_MMM01; break; + case 0x0d: type = GB_MBC_MMM01; break; + case 0x0f: type = GB_MBC_MBC3; break; + case 0x10: type = GB_MBC_MBC3; break; + case 0x11: type = GB_MBC_MBC3; break; + case 0x12: type = GB_MBC_MBC3; break; + case 0x13: type = GB_MBC_MBC3; break; + case 0x15: type = GB_MBC_MBC4; break; + case 0x16: type = GB_MBC_MBC4; break; + case 0x17: type = GB_MBC_MBC4; break; + case 0x19: type = GB_MBC_MBC5; break; + case 0x1a: type = GB_MBC_MBC5; break; + case 0x1b: type = GB_MBC_MBC5; break; + case 0x1c: type = GB_MBC_MBC5; break; + case 0x1d: type = GB_MBC_MBC5; break; + case 0x1e: type = GB_MBC_MBC5; break; + case 0x20: type = GB_MBC_MBC6; break; + case 0x22: type = GB_MBC_MBC7; break; + case 0xbe: type = GB_MBC_NONE; break; /* used in Flash2Advance GB Bridge boot program */ + case 0xea: type = GB_MBC_YONGYONG; break; /* Found in Sonic 3D Blast 5 pirate */ + case 0xfc: type = GB_MBC_CAMERA; break; + case 0xfd: type = GB_MBC_TAMA5; break; + case 0xfe: type = GB_MBC_HUC3; break; + case 0xff: type = GB_MBC_HUC1; break; + } + + // Check for special mappers + if (type == GB_MBC_NONE) + { + int count = 0; + for (int i = 0x0134; i <= 0x014c; i++) + { + count += ROM[i]; + } + if (count == 0) + { + type = GB_MBC_WISDOM; + } + } + + // Check for some unlicensed games + //if (type == GB_MBC_MBC5) + { + int count = 0; + for (int i = 0x0184; i < 0x0184 + 0x30; i++) + { + count += ROM[i]; + } + + if (count == 4876) + { +// printf("Li Cheng %d\n", count); + type = GB_MBC_LICHENG; + } + if (count == 4138 || count == 4125) + { + // Zhi Huan Wang uses 4138 + // most sintax use 4125 +// printf("Sintax %d!\n", count); + type = GB_MBC_SINTAX; + } + } + + /* Check if we're dealing with the multigame variant of the MBC1 mapper */ + if (type == GB_MBC_MBC1) + { // bomberman collection korea + if (ROM[0x134] == 0x42 && ROM[0x135] == 0x4f && ROM[0x136] == 0x4d && ROM[0x137] == 0x53) + type = GB_MBC_MBC1_COL; +// if (ROM[0x13f] == 0x42 && ROM[0x140] == 0x32 && ROM[0x141] == 0x43 && ROM[0x142] == 0x4B) +// type = GB_MBC_MBC1_COL; + // genjin collection + if (ROM[0x134] == 0x47 && ROM[0x135] == 0x45 && ROM[0x136] == 0x4e && ROM[0x137] == 0x43) + type = GB_MBC_MBC1_COL; + // bomberman collection japan + if (ROM[0x134] == 0x42 && ROM[0x135] == 0x4f && ROM[0x136] == 0x4d && ROM[0x137] == 0x43) + type = GB_MBC_MBC1_COL; + // mortal kombat I & II US + if (ROM[0x140] == 0x49 && ROM[0x141] == 0x26 && ROM[0x142] == 0x49 && ROM[0x143] == 0x49) + type = GB_MBC_MBC1_COL; + // mortal kombat I & II japan + if (ROM[0x140] == 0x20 && ROM[0x141] == 0x44 && ROM[0x142] == 0x55 && ROM[0x143] == 0x4f) + type = GB_MBC_MBC1_COL; + // momotarou collection 1 japan + if (ROM[0x137] == 0x4f && ROM[0x138] == 0x43 && ROM[0x139] == 0x4f && ROM[0x13a] == 0x4c) + type = GB_MBC_MBC1_COL; + // super chinese 123 dash japan + if (ROM[0x142] == 0x32 && ROM[0x143] == 0x33 && ROM[0x144] == 0x42 && ROM[0x145] == 0x41) + type = GB_MBC_MBC1_COL; + } + + return type; +} + +/*------------------------------------------------- + get default card software + -------------------------------------------------*/ + +void base_gb_cart_slot_device::get_default_card_software(std::string &result) +{ + if (open_image_file(mconfig().options())) + { + const char *slot_string = "rom"; + UINT32 len = core_fsize(m_file), offset = 0; + dynamic_buffer rom(len); + int type; + + core_fread(m_file, &rom[0], len); + + if ((len % 0x4000) == 512) + offset = 512; + + if (get_mmm01_candidate(&rom[offset], len - offset)) + offset += (len - 0x8000); + + type = get_cart_type(&rom[offset], len - offset); + slot_string = gb_get_slot(type); + + //printf("type: %s\n", slot_string); + clear(); + + result.assign(slot_string); + return; + } + + software_get_default_slot(result, "rom"); +} + + +void megaduck_cart_slot_device::get_default_card_software(std::string &result) +{ + if (open_image_file(mconfig().options())) + { + result.assign("rom"); + return; + } + + software_get_default_slot(result, "rom"); +} + + + +/*------------------------------------------------- + read + -------------------------------------------------*/ + +READ8_MEMBER(base_gb_cart_slot_device::read_rom) +{ + if (m_cart) + return m_cart->read_rom(space, offset); + else + return 0xff; +} + +READ8_MEMBER(base_gb_cart_slot_device::read_ram) +{ + if (m_cart) + return m_cart->read_ram(space, offset); + else + return 0xff; +} + + +/*------------------------------------------------- + write + -------------------------------------------------*/ + +WRITE8_MEMBER(base_gb_cart_slot_device::write_bank) +{ + if (m_cart) + m_cart->write_bank(space, offset, data); +} + +WRITE8_MEMBER(base_gb_cart_slot_device::write_ram) +{ + if (m_cart) + m_cart->write_ram(space, offset, data); +} + + +/*------------------------------------------------- + Internal header logging + -------------------------------------------------*/ + +void base_gb_cart_slot_device::internal_header_logging(UINT8 *ROM, UINT32 len) +{ + static const char *const cart_types[] = + { + "ROM ONLY", "ROM+MBC1", "ROM+MBC1+RAM", + "ROM+MBC1+RAM+BATTERY", "UNKNOWN", "ROM+MBC2", + "ROM+MBC2+BATTERY", "UNKNOWN", "ROM+RAM", + "ROM+RAM+BATTERY", "UNKNOWN", "ROM+MMM01", + "ROM+MMM01+SRAM", "ROM+MMM01+SRAM+BATTERY", "UNKNOWN", + "ROM+MBC3+TIMER+BATTERY", "ROM+MBC3+TIMER+RAM+BATTERY", "ROM+MBC3", + "ROM+MBC3+RAM", "ROM+MBC3+RAM+BATTERY", "UNKNOWN", + "UNKNOWN", "UNKNOWN", "UNKNOWN", + "UNKNOWN", "ROM+MBC5", "ROM+MBC5+RAM", + "ROM+MBC5+RAM+BATTERY", "ROM+MBC5+RUMBLE", "ROM+MBC5+RUMBLE+SRAM", + "ROM+MBC5+RUMBLE+SRAM+BATTERY", "Pocket Camera", "Bandai TAMA5", + /* Need heaps of unknowns here */ + "Hudson HuC-3", "Hudson HuC-1" + }; + + // some company codes + static const struct + { + UINT16 code; + const char *name; + } + companies[] = + { + {0x3301, "Nintendo"}, + {0x7901, "Accolade"}, + {0xA400, "Konami"}, + {0x6701, "Ocean"}, + {0x5601, "LJN"}, + {0x9900, "ARC?"}, + {0x0101, "Nintendo"}, + {0x0801, "Capcom"}, + {0x0100, "Nintendo"}, + {0xBB01, "SunSoft"}, + {0xA401, "Konami"}, + {0xAF01, "Namcot?"}, + {0x4901, "Irem"}, + {0x9C01, "Imagineer"}, + {0xA600, "Kawada?"}, + {0xB101, "Nexoft"}, + {0x5101, "Acclaim"}, + {0x6001, "Titus"}, + {0xB601, "HAL"}, + {0x3300, "Nintendo"}, + {0x0B00, "Coconuts?"}, + {0x5401, "Gametek"}, + {0x7F01, "Kemco?"}, + {0xC001, "Taito"}, + {0xEB01, "Atlus"}, + {0xE800, "Asmik?"}, + {0xDA00, "Tomy?"}, + {0xB100, "ASCII?"}, + {0xEB00, "Atlus"}, + {0xC000, "Taito"}, + {0x9C00, "Imagineer"}, + {0xC201, "Kemco?"}, + {0xD101, "Sofel?"}, + {0x6101, "Virgin"}, + {0xBB00, "SunSoft"}, + {0xCE01, "FCI?"}, + {0xB400, "Enix?"}, + {0xBD01, "Imagesoft"}, + {0x0A01, "Jaleco?"}, + {0xDF00, "Altron?"}, + {0xA700, "Takara?"}, + {0xEE00, "IGS?"}, + {0x8300, "Lozc?"}, + {0x5001, "Absolute?"}, + {0xDD00, "NCS?"}, + {0xE500, "Epoch?"}, + {0xCB00, "VAP?"}, + {0x8C00, "Vic Tokai"}, + {0xC200, "Kemco?"}, + {0xBF00, "Sammy?"}, + {0x1800, "Hudson Soft"}, + {0xCA01, "Palcom/Ultra"}, + {0xCA00, "Palcom/Ultra"}, + {0xC500, "Data East?"}, + {0xA900, "Technos Japan?"}, + {0xD900, "Banpresto?"}, + {0x7201, "Broderbund?"}, + {0x7A01, "Triffix Entertainment?"}, + {0xE100, "Towachiki?"}, + {0x9300, "Tsuburava?"}, + {0xC600, "Tonkin House?"}, + {0xCE00, "Pony Canyon"}, + {0x7001, "Infogrames?"}, + {0x8B01, "Bullet-Proof Software?"}, + {0x5501, "Park Place?"}, + {0xEA00, "King Records?"}, + {0x5D01, "Tradewest?"}, + {0x6F01, "ElectroBrain?"}, + {0xAA01, "Broderbund?"}, + {0xC301, "SquareSoft"}, + {0x5201, "Activision?"}, + {0x5A01, "Bitmap Brothers/Mindscape"}, + {0x5301, "American Sammy"}, + {0x4701, "Spectrum Holobyte"}, + {0x1801, "Hudson Soft"}, + {0x0000, NULL} + }; + static const int ramsize[8] = { 0, 2, 8, 32, 128, 64, 0, 0 }; + + char soft[17]; + UINT32 tmp = 0; + int csum = 0, i = 0; + int rom_banks; + + switch (ROM[0x0148]) + { + case 0x52: + rom_banks = 72; + break; + case 0x53: + rom_banks = 80; + break; + case 0x54: + rom_banks = 96; + break; + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x04: case 0x05: case 0x06: case 0x07: + rom_banks = 2 << ROM[0x0148]; + break; + default: + rom_banks = 256; + break; + } + + strncpy(soft, (char *)&ROM[0x0134], 16); + soft[16] = '\0'; + logerror("Cart Information\n"); + logerror("\tName: %s\n", soft); + logerror("\tType: %s [0x%2X]\n", (ROM[0x0147] <= 32) ? cart_types[ROM[0x0147]] : "", ROM[0x0147] ); + logerror("\tGame Boy: %s\n", (ROM[0x0143] == 0xc0) ? "No" : "Yes" ); + logerror("\tSuper GB: %s [0x%2X]\n", (ROM[0x0146] == 0x03) ? "Yes" : "No", ROM[0x0146] ); + logerror("\tColor GB: %s [0x%2X]\n", (ROM[0x0143] == 0x80 || ROM[0x0143] == 0xc0) ? "Yes" : "No", ROM[0x0143] ); + logerror("\tROM Size: %d 16kB Banks [0x%2X]\n", rom_banks, ROM[0x0148]); + logerror("\tRAM Size: %d kB [0x%2X]\n", ramsize[ROM[0x0149] & 0x07], ROM[0x0149]); + logerror("\tLicense code: 0x%2X%2X\n", ROM[0x0145], ROM[0x0144] ); + tmp = (ROM[0x014b] << 8) + ROM[0x014a]; + for (i = 0; i < ARRAY_LENGTH(companies); i++) + if (tmp == companies[i].code) + break; + logerror("\tManufacturer ID: 0x%2X", tmp); + logerror(" [%s]\n", (i < ARRAY_LENGTH(companies)) ? companies[i].name : "?"); + logerror("\tVersion Number: 0x%2X\n", ROM[0x014c]); + logerror("\tComplement Check: 0x%2X\n", ROM[0x014d]); + logerror("\tChecksum: 0x%2X\n", ((ROM[0x014e] << 8) + ROM[0x014f])); + tmp = (ROM[0x0103] << 8) + ROM[0x0102]; + logerror("\tStart Address: 0x%2X\n", tmp); + + // Additional checks + if (rom_banks == 256) + logerror("\nWarning loading cartridge: Unknown ROM size in header [0x%x].\n", ROM[0x0148]); + + if ((len / 0x4000) != rom_banks) + logerror("\nWarning loading cartridge: Filesize (0x%x) and reported ROM banks (0x%x) don't match.\n", + len, rom_banks * 0x4000); + /* Calculate and check checksum */ + tmp = (ROM[0x014e] << 8) + ROM[0x014f]; + for (int i = 0; i < len; i++) + csum += ROM[i]; + csum -= (ROM[0x014e] + ROM[0x014f]); + csum &= 0xffff; + + if (csum != tmp) + logerror("\nWarning loading cartridge: Checksum is wrong (Actual %X vs Internal %X)\n", csum, tmp); + +} diff --git a/src/devices/bus/gameboy/gb_slot.h b/src/devices/bus/gameboy/gb_slot.h new file mode 100644 index 00000000000..711037a0da8 --- /dev/null +++ b/src/devices/bus/gameboy/gb_slot.h @@ -0,0 +1,211 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli, Wilbert Pol +#ifndef __GB_SLOT_H +#define __GB_SLOT_H + +/*************************************************************************** + TYPE DEFINITIONS + ***************************************************************************/ + + +/* PCB */ +enum +{ + GB_MBC_NONE = 0, /* 32KB ROM - No memory bank controller */ + GB_MBC_MBC1, /* ~2MB ROM, 8KB RAM -or- 512KB ROM, 32KB RAM */ + GB_MBC_MBC2, /* 256KB ROM, 32KB RAM */ + GB_MBC_MBC3, /* 2MB ROM, 32KB RAM, RTC */ + GB_MBC_MBC4, /* ?? ROM, ?? RAM */ + GB_MBC_MBC5, /* 8MB ROM, 128KB RAM (32KB w/ Rumble) */ + GB_MBC_TAMA5, /* ?? ROM ?? RAM - What is this? */ + GB_MBC_HUC1, /* ?? ROM, ?? RAM - Hudson Soft Controller */ + GB_MBC_HUC3, /* ?? ROM, ?? RAM - Hudson Soft Controller */ + GB_MBC_MBC6, /* ?? ROM, 32KB SRAM */ + GB_MBC_MBC7, /* ?? ROM, ?? RAM */ + GB_MBC_M161, /* ?? ROM, ?? RAM */ + GB_MBC_MMM01, /* ?? ROM, ?? RAM */ + GB_MBC_WISDOM, /* ?? ROM, ?? RAM - Wisdom tree controller */ + GB_MBC_MBC1_COL, /* 1MB ROM, 32KB RAM - workaround for MBC1 on PCB that maps rom address lines differently */ + GB_MBC_SACHEN1, /* ?? ROM, ?? RAM - Sachen MMC-1 variant */ + GB_MBC_SACHEN2, /* ?? ROM, ?? RAM - Sachen MMC-2 variant */ + GB_MBC_YONGYONG, /* ?? ROM, ?? RAM - Appears in Sonic 3D Blast 5 pirate */ + GB_MBC_LASAMA, /* ?? ROM, ?? RAM - Appears in La Sa Ma */ + GB_MBC_ATVRACIN, + GB_MBC_CAMERA, + GB_MBC_188IN1, + GB_MBC_SINTAX, + GB_MBC_CHONGWU, + GB_MBC_LICHENG, + GB_MBC_DIGIMON, + GB_MBC_ROCKMAN8, + GB_MBC_SM3SP, + GB_MBC_DKONG5, + GB_MBC_UNK01, + GB_MBC_MEGADUCK, /* MEGADUCK style banking */ + GB_MBC_UNKNOWN /* Unknown mapper */ +}; + + +// ======================> device_gb_cart_interface + +class device_gb_cart_interface : public device_slot_card_interface +{ +public: + // construction/destruction + device_gb_cart_interface(const machine_config &mconfig, device_t &device); + virtual ~device_gb_cart_interface(); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_rom) { return 0xff; } + virtual DECLARE_WRITE8_MEMBER(write_bank) {} + virtual DECLARE_READ8_MEMBER(read_ram) { return 0xff; } + virtual DECLARE_WRITE8_MEMBER(write_ram) {} + + void rom_alloc(UINT32 size, const char *tag); + void ram_alloc(UINT32 size); + UINT8* get_rom_base() { return m_rom; } + UINT8* get_ram_base() { return &m_ram[0]; } + UINT32 get_rom_size() { return m_rom_size; } + UINT32 get_ram_size() { return m_ram.size(); } + + void rom_map_setup(UINT32 size); + void ram_map_setup(UINT8 banks); + + virtual void set_additional_wirings(UINT8 mask, int shift) { } // MBC-1 will then overwrite this! + void set_has_timer(bool val) { has_timer = val; } + void set_has_rumble(bool val) { has_rumble = val; } + void set_has_battery(bool val) { has_battery = val; } + bool get_has_battery() { return has_battery; } + + void save_ram() { device().save_item(NAME(m_ram)); } + + // internal state + UINT8 *m_rom; + UINT32 m_rom_size; + dynamic_buffer m_ram; + + // bankswitch variables + // we access ROM/RAM banks through these bank maps + // default accesses are: + // 0x0000-0x3fff = rom_bank_map[m_latch_bank] (generally defaults to m_latch_bank = 0) + // 0x4000-0x7fff = rom_bank_map[m_latch_bank2] (generally defaults to m_latch_bank2 = 1) + // 0xa000-0xbfff = ram_bank_map[m_ram_bank] (generally defaults to m_ram_bank = 0) + // suitable writes to 0x0000-0x7fff can then modify m_latch_bank/m_latch_bank2 + UINT8 rom_bank_map[512]; // 16K chunks of ROM + UINT8 ram_bank_map[256]; // 16K chunks of RAM + UINT8 m_ram_bank; + UINT16 m_latch_bank, m_latch_bank2; + + bool has_rumble, has_timer, has_battery; +}; + + +// ======================> base_gb_cart_slot_device + +class base_gb_cart_slot_device : public device_t, + public device_image_interface, + public device_slot_interface +{ +public: + // construction/destruction + base_gb_cart_slot_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + virtual ~base_gb_cart_slot_device(); + + // device-level overrides + virtual void device_start(); + virtual void device_config_complete(); + + // image-level overrides + virtual bool call_load(); + virtual void call_unload(); + virtual bool call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry); + + int get_type() { return m_type; } + int get_cart_type(UINT8 *ROM, UINT32 len); + bool get_mmm01_candidate(UINT8 *ROM, UINT32 len); + // remove me when SGB is properly emulated + int get_sgb_hack() { return m_sgb_hack; } + + void setup_ram(UINT8 banks); + void internal_header_logging(UINT8 *ROM, UINT32 len); + void save_ram() { if (m_cart && m_cart->get_ram_size()) m_cart->save_ram(); } + + virtual iodevice_t image_type() const { return IO_CARTSLOT; } + virtual bool is_readable() const { return 1; } + virtual bool is_writeable() const { return 0; } + virtual bool is_creatable() const { return 0; } + virtual bool must_be_loaded() const { return 0; } + virtual bool is_reset_on_load() const { return 1; } + virtual const option_guide *create_option_guide() const { return NULL; } + virtual const char *image_interface() const { return "gameboy_cart"; } + virtual const char *file_extensions() const { return "bin,gb,gbc"; } + + // slot interface overrides + virtual void get_default_card_software(std::string &result); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_rom); + virtual DECLARE_WRITE8_MEMBER(write_bank); + virtual DECLARE_READ8_MEMBER(read_ram); + virtual DECLARE_WRITE8_MEMBER(write_ram); + + +protected: + // Donkey Kong Land 2 + 3 store SGB border tiles differently... this will be hopefully be removed when SGB is properly emulated! + int m_sgb_hack; + + int m_type; + device_gb_cart_interface* m_cart; +}; + +// ======================> gb_cart_slot_device + +class gb_cart_slot_device : public base_gb_cart_slot_device +{ +public: + // construction/destruction + gb_cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +// ======================> megaduck_cart_slot_device + +class megaduck_cart_slot_device : public base_gb_cart_slot_device +{ +public: + // construction/destruction + megaduck_cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // image-level overrides + virtual bool call_load(); + virtual const char *image_interface() const { return "megaduck_cart"; } + virtual const char *file_extensions() const { return "bin"; } + + // slot interface overrides + virtual void get_default_card_software(std::string &result); +}; + + + + +// device type definition +extern const device_type GB_CART_SLOT; +extern const device_type MEGADUCK_CART_SLOT; + + +/*************************************************************************** + DEVICE CONFIGURATION MACROS + ***************************************************************************/ + +#define GBSLOT_ROM_REGION_TAG ":cart:rom" + +#define MCFG_GB_CARTRIDGE_ADD(_tag,_slot_intf,_def_slot) \ + MCFG_DEVICE_ADD(_tag, GB_CART_SLOT, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) + +#define MCFG_MEGADUCK_CARTRIDGE_ADD(_tag,_slot_intf,_def_slot) \ + MCFG_DEVICE_ADD(_tag, MEGADUCK_CART_SLOT, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) + + +#endif diff --git a/src/devices/bus/gameboy/mbc.c b/src/devices/bus/gameboy/mbc.c new file mode 100644 index 00000000000..4c0a81459b6 --- /dev/null +++ b/src/devices/bus/gameboy/mbc.c @@ -0,0 +1,1274 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli, Wilbert Pol +/*********************************************************************************************************** + + Game Boy carts with MBC (Memory Bank Controller) + + + TODO: add proper RTC and Rumble support + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "mbc.h" + + +//------------------------------------------------- +// gb_rom_mbc*_device - constructor +//------------------------------------------------- + +const device_type GB_ROM_MBC1 = &device_creator; +const device_type GB_ROM_MBC2 = &device_creator; +const device_type GB_ROM_MBC3 = &device_creator; +const device_type GB_ROM_MBC5 = &device_creator; +const device_type GB_ROM_MBC6 = &device_creator; +const device_type GB_ROM_MBC7 = &device_creator; +const device_type GB_ROM_M161_M12 = &device_creator; +const device_type GB_ROM_MMM01 = &device_creator; +const device_type GB_ROM_SACHEN1 = &device_creator; +const device_type GB_ROM_SACHEN2 = &device_creator; +const device_type GB_ROM_188IN1 = &device_creator; +const device_type GB_ROM_SINTAX = &device_creator; +const device_type GB_ROM_CHONGWU = &device_creator; +const device_type GB_ROM_LICHENG = &device_creator; +const device_type GB_ROM_DIGIMON = &device_creator; +const device_type GB_ROM_ROCKMAN8 = &device_creator; +const device_type GB_ROM_SM3SP = &device_creator; + + +gb_rom_mbc_device::gb_rom_mbc_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_gb_cart_interface( mconfig, *this ) +{ +} + +gb_rom_mbc1_device::gb_rom_mbc1_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : gb_rom_mbc_device(mconfig, type, name, tag, owner, clock, shortname, source), + m_mask(0x1f), + m_shift(0) +{ +} + +gb_rom_mbc1_device::gb_rom_mbc1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : gb_rom_mbc_device(mconfig, GB_ROM_MBC1, "GB MBC1 Carts", tag, owner, clock, "gb_rom_mbc1", __FILE__), + m_mask(0x1f), + m_shift(0) +{ +} + +gb_rom_mbc2_device::gb_rom_mbc2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : gb_rom_mbc_device(mconfig, GB_ROM_MBC2, "GB MBC2 Carts", tag, owner, clock, "gb_rom_mbc2", __FILE__) +{ +} + +gb_rom_mbc3_device::gb_rom_mbc3_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : gb_rom_mbc_device(mconfig, GB_ROM_MBC3, "GB MBC3 Carts", tag, owner, clock, "gb_rom_mbc3", __FILE__) +{ +} + +gb_rom_mbc5_device::gb_rom_mbc5_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : gb_rom_mbc_device(mconfig, type, name, tag, owner, clock, shortname, source) +{ +} + +gb_rom_mbc5_device::gb_rom_mbc5_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : gb_rom_mbc_device(mconfig, GB_ROM_MBC5, "GB MBC5 Carts", tag, owner, clock, "gb_rom_mbc5", __FILE__) +{ +} + +gb_rom_mbc6_device::gb_rom_mbc6_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : gb_rom_mbc_device(mconfig, GB_ROM_MBC6, "GB MBC6 Carts", tag, owner, clock, "gb_rom_mbc6", __FILE__) +{ +} + +gb_rom_mbc7_device::gb_rom_mbc7_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : gb_rom_mbc_device(mconfig, GB_ROM_MBC7, "GB MBC7 Carts", tag, owner, clock, "gb_rom_mbc7", __FILE__) +{ +} + +gb_rom_m161_device::gb_rom_m161_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : gb_rom_mbc_device(mconfig, GB_ROM_M161_M12, "GB M161-M12 Carts", tag, owner, clock, "gb_rom_m161m12", __FILE__) +{ +} + +gb_rom_mmm01_device::gb_rom_mmm01_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : gb_rom_mbc_device(mconfig, GB_ROM_MMM01, "GB MMM01 Carts", tag, owner, clock, "gb_rom_mmm01", __FILE__) +{ +} + +gb_rom_sachen_mmc1_device::gb_rom_sachen_mmc1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : gb_rom_mbc_device(mconfig, GB_ROM_SACHEN1, "GB Sachen MMC1 Carts", tag, owner, clock, "gb_rom_sachen1", __FILE__) +{ +} + +gb_rom_sachen_mmc1_device::gb_rom_sachen_mmc1_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : gb_rom_mbc_device(mconfig, type, name, tag, owner, clock, shortname, source) +{ +} + +gb_rom_sachen_mmc2_device::gb_rom_sachen_mmc2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : gb_rom_sachen_mmc1_device(mconfig, GB_ROM_SACHEN2, "GB Sachen MMC2 Carts", tag, owner, clock, "gb_rom_sachen2", __FILE__) +{ +} + +gb_rom_188in1_device::gb_rom_188in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : gb_rom_mbc1_device(mconfig, GB_ROM_188IN1, "GB 188in1", tag, owner, clock, "gb_rom_188in1", __FILE__) +{ +} + +gb_rom_sintax_device::gb_rom_sintax_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : gb_rom_mbc_device(mconfig, GB_ROM_SINTAX, "GB MBC5 Sintax Carts", tag, owner, clock, "gb_rom_sintax", __FILE__) +{ +} + +gb_rom_chongwu_device::gb_rom_chongwu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : gb_rom_mbc5_device(mconfig, GB_ROM_CHONGWU, "GB Chong Wu Xiao Jing Ling", tag, owner, clock, "gb_rom_chongwu", __FILE__) +{ +} + +gb_rom_licheng_device::gb_rom_licheng_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : gb_rom_mbc5_device(mconfig, GB_ROM_LICHENG, "GB MBC5 Li Cheng Carts", tag, owner, clock, "gb_rom_licheng", __FILE__) +{ +} + +gb_rom_digimon_device::gb_rom_digimon_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : gb_rom_mbc5_device(mconfig, GB_ROM_DIGIMON, "GB Digimon", tag, owner, clock, "gb_rom_digimon", __FILE__) +{ +} + +gb_rom_rockman8_device::gb_rom_rockman8_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : gb_rom_mbc_device(mconfig, GB_ROM_ROCKMAN8, "GB MBC1 Rockman 8", tag, owner, clock, "gb_rom_rockman8", __FILE__) +{ +} + +gb_rom_sm3sp_device::gb_rom_sm3sp_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : gb_rom_mbc_device(mconfig, GB_ROM_SM3SP, "GB MBC1 Super Mario 3 Special", tag, owner, clock, "gb_rom_sm3sp", __FILE__) +{ +} + + +//------------------------------------------------- +// shared_start +//------------------------------------------------- + +void gb_rom_mbc_device::shared_start() +{ + save_item(NAME(m_latch_bank)); + save_item(NAME(m_latch_bank2)); + save_item(NAME(m_ram_bank)); + save_item(NAME(m_ram_enable)); +} + +//------------------------------------------------- +// shared_reset +//------------------------------------------------- + +void gb_rom_mbc_device::shared_reset() +{ + m_latch_bank = 0; + m_latch_bank2 = 1; + m_ram_bank = 0; + m_ram_enable = 0; +} + +//------------------------------------------------- +// mapper specific start/reset +//------------------------------------------------- + +void gb_rom_mbc3_device::device_start() +{ + shared_start(); + save_item(NAME(m_rtc_map)); +} + +void gb_rom_mbc3_device::device_reset() +{ + shared_reset(); + memset(m_rtc_map, 0, sizeof(m_rtc_map)); +} + +void gb_rom_mbc6_device::device_start() +{ + save_item(NAME(m_bank_4000)); + save_item(NAME(m_bank_6000)); + save_item(NAME(m_latch1)); + save_item(NAME(m_latch2)); + save_item(NAME(m_latch_bank)); + save_item(NAME(m_latch_bank2)); + save_item(NAME(m_ram_bank)); + save_item(NAME(m_ram_enable)); +} + +void gb_rom_mbc6_device::device_reset() +{ + m_bank_4000 = 2; // correct default? + m_bank_6000 = 3; // correct default? + m_latch1 = 0; // correct default? + m_latch2 = 0; // correct default? + + m_latch_bank = 2; // correct default? + m_latch_bank2 = 3; // correct default? + m_ram_bank = 0; + m_ram_enable = 0; +} + +void gb_rom_m161_device::device_start() +{ + shared_start(); + save_item(NAME(m_base_bank)); +} + +void gb_rom_m161_device::device_reset() +{ + shared_reset(); + m_base_bank = 0; +} + +void gb_rom_mmm01_device::device_start() +{ + shared_start(); + save_item(NAME(m_bank_mask)); + save_item(NAME(m_bank)); + save_item(NAME(m_reg)); +} + +void gb_rom_mmm01_device::device_reset() +{ + m_latch_bank = 0x200 - 2; + m_latch_bank2 = 0x200 - 1; + m_ram_bank = 0; + m_bank_mask = 0xff; + m_bank = 0; + m_reg = 0; +} + +void gb_rom_sachen_mmc1_device::device_start() +{ + shared_start(); + save_item(NAME(m_base_bank)); + save_item(NAME(m_mask)); + save_item(NAME(m_mode)); + save_item(NAME(m_unlock_cnt)); +} + +void gb_rom_sachen_mmc1_device::device_reset() +{ + shared_reset(); + m_base_bank = 0x00; + m_mask = 0x00; + m_mode = MODE_LOCKED; + m_unlock_cnt = 0x00; +} + +void gb_rom_sachen_mmc2_device::device_start() +{ + shared_start(); + save_item(NAME(m_base_bank)); + save_item(NAME(m_mask)); + save_item(NAME(m_mode)); + save_item(NAME(m_unlock_cnt)); +} + +void gb_rom_sachen_mmc2_device::device_reset() +{ + shared_reset(); + m_base_bank = 0x00; + m_mask = 0x00; + m_mode = MODE_LOCKED_DMG; + m_unlock_cnt = 0x00; +} + +void gb_rom_sintax_device::device_start() +{ + shared_start(); + save_item(NAME(m_sintax_mode)); + save_item(NAME(m_currentxor)); + save_item(NAME(m_xor2)); + save_item(NAME(m_xor3)); + save_item(NAME(m_xor4)); + save_item(NAME(m_xor5)); +} + +void gb_rom_sintax_device::device_reset() +{ + shared_reset(); + m_sintax_mode = 0; + m_currentxor = 0; + m_xor2 = 0; + m_xor3 = 0; + m_xor4 = 0; + m_xor5 = 0; +} + +void gb_rom_chongwu_device::device_start() +{ + shared_start(); + save_item(NAME(m_protection_checked)); +} + +void gb_rom_chongwu_device::device_reset() +{ + shared_reset(); + m_protection_checked = 0; +} + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +READ8_MEMBER(gb_rom_mbc_device::read_rom) +{ + return m_rom[rom_bank_map[m_latch_bank] + offset]; +} + +READ8_MEMBER(gb_rom_mbc_device::read_ram) +{ + if (!m_ram.empty()) + return m_ram[ram_bank_map[m_ram_bank] * 0x2000 + offset]; + else + return 0xff; +} + +WRITE8_MEMBER(gb_rom_mbc_device::write_ram) +{ + if (!m_ram.empty()) + m_ram[ram_bank_map[m_ram_bank] * 0x2000 + offset] = data; +} + + +// MBC1 + +READ8_MEMBER(gb_rom_mbc1_device::read_rom) +{ + if (offset & 0x4000) /* RB1 */ + return m_rom[rom_bank_map[(m_ram_bank << (5 + m_shift)) | m_latch_bank2] * 0x4000 + (offset & 0x3fff)]; + else + { /* RB0 */ + int bank = (m_mode == MODE_4M_256k) ? (m_ram_bank << (5 + m_shift)) : 0; + return m_rom[rom_bank_map[bank] * 0x4000 + (offset & 0x3fff)]; + } +} + +WRITE8_MEMBER(gb_rom_mbc1_device::write_bank) +{ + // the mapper only uses inputs A15..A13 + switch (offset & 0xe000) + { + case 0x0000: // RAM Enable Register + m_ram_enable = ((data & 0x0f) == 0x0a) ? 1 : 0; + break; + case 0x2000: // ROM Bank Register + data &= 0x1f; + m_latch_bank2 = data ? data : 1; + m_latch_bank2 &= m_mask; + break; + case 0x4000: // RAM Bank Register + m_ram_bank = data & 0x3; + break; + case 0x6000: // MBC1 Mode Register + m_mode = (data & 0x1) ? MODE_4M_256k : MODE_16M_64k; + break; + } +} + +READ8_MEMBER(gb_rom_mbc1_device::read_ram) +{ + if (!m_ram.empty() && m_ram_enable) + { + int bank = (m_mode == MODE_4M_256k) ? m_ram_bank : 0; + return m_ram[ram_bank_map[bank] * 0x2000 + offset]; + } + else + return 0xff; +} + +WRITE8_MEMBER(gb_rom_mbc1_device::write_ram) +{ + if (!m_ram.empty() && m_ram_enable) + { + int bank = (m_mode == MODE_4M_256k) ? m_ram_bank : 0; + m_ram[ram_bank_map[bank] * 0x2000 + offset] = data; + } +} + + +// MBC2 + +READ8_MEMBER(gb_rom_mbc2_device::read_rom) +{ + if (offset & 0x4000) /* RB1 */ + return m_rom[rom_bank_map[m_latch_bank2] * 0x4000 + (offset & 0x3fff)]; + else /* RB0 */ + return m_rom[rom_bank_map[m_latch_bank] * 0x4000 + (offset & 0x3fff)]; +} + +WRITE8_MEMBER(gb_rom_mbc2_device::write_bank) +{ + // the mapper only has data lines D3..D0 + data &= 0x0f; + + // the mapper only uses inputs A15..A14, A8 for register accesses + switch (offset & 0xc100) + { + case 0x0000: // RAM Enable Register + m_ram_enable = (data == 0x0a) ? 1 : 0; + break; + case 0x0100: // ROM Bank Register + m_latch_bank2 = (data == 0x00) ? 0x01 : data; + break; + } +} + +READ8_MEMBER(gb_rom_mbc2_device::read_ram) +{ + if (!m_ram.empty() && m_ram_enable) + return m_ram[ram_bank_map[m_ram_bank] * 0x2000 + (offset & 0x01ff)] | 0xF0; + else + return 0xff; +} + +WRITE8_MEMBER(gb_rom_mbc2_device::write_ram) +{ + if (!m_ram.empty() && m_ram_enable) + m_ram[ram_bank_map[m_ram_bank] * 0x2000 + (offset & 0x01ff)] = data & 0x0F; +} + + +// MBC3 + +READ8_MEMBER(gb_rom_mbc3_device::read_rom) +{ + if (offset < 0x4000) + return m_rom[rom_bank_map[m_latch_bank] * 0x4000 + (offset & 0x3fff)]; + else + return m_rom[rom_bank_map[m_latch_bank2] * 0x4000 + (offset & 0x3fff)]; +} + +WRITE8_MEMBER(gb_rom_mbc3_device::write_bank) +{ + if (offset < 0x2000) + m_ram_enable = ((data & 0x0f) == 0x0a) ? 1 : 0; + else if (offset < 0x4000) + { + // 7bits + data &= 0x7f; + /* Selecting bank 0 == selecting bank 1 */ + if (data == 0) + data = 1; + + m_latch_bank2 = data; + } + else if (offset < 0x6000) + { + m_ram_bank = data; + } + else + { + if (has_timer) + { + /* FIXME: RTC Latch goes here */ + m_rtc_map[0] = 50; /* Seconds */ + m_rtc_map[1] = 40; /* Minutes */ + m_rtc_map[2] = 15; /* Hours */ + m_rtc_map[3] = 25; /* Day counter lowest 8 bits */ + m_rtc_map[4] = 0x01; /* Day counter upper bit, timer off, no day overflow occurred (bit7) */ + } + } +} + +READ8_MEMBER(gb_rom_mbc3_device::read_ram) +{ + if (m_ram_bank < 4 && m_ram_enable) + { // RAM + if (!m_ram.empty()) + return m_ram[ram_bank_map[m_ram_bank] * 0x2000 + (offset & 0x1fff)]; + } + if (m_ram_bank >= 0x8 && m_ram_bank <= 0xc) + { // RAM + if (has_timer) + return m_rtc_map[m_ram_bank - 8]; + } + return 0xff; +} + +WRITE8_MEMBER(gb_rom_mbc3_device::write_ram) +{ + if (m_ram_bank < 4 && m_ram_enable) + { // RAM + if (!m_ram.empty()) + m_ram[ram_bank_map[m_ram_bank] * 0x2000 + (offset & 0x1fff)] = data; + } + if (m_ram_bank >= 0x8 && m_ram_bank <= 0xc) + { // RAM + if (has_timer) + { + // what to do here? + } + } +} + +// MBC5 + +READ8_MEMBER(gb_rom_mbc5_device::read_rom) +{ + if (offset < 0x4000) + return m_rom[rom_bank_map[m_latch_bank] * 0x4000 + (offset & 0x3fff)]; + else + return m_rom[rom_bank_map[m_latch_bank2] * 0x4000 + (offset & 0x3fff)]; +} + +WRITE8_MEMBER(gb_rom_mbc5_device::write_bank) +{ + if (offset < 0x2000) + m_ram_enable = ((data & 0x0f) == 0x0a) ? 1 : 0; + else if (offset < 0x3000) + { + // MBC5 has a 9 bit bank select + // Writing into 2000-2fff sets the lower 8 bits + m_latch_bank2 = (m_latch_bank2 & 0x100) | data; + } + else if (offset < 0x4000) + { + // MBC5 has a 9 bit bank select + // Writing into 3000-3fff sets the 9th bit + m_latch_bank2 = (m_latch_bank2 & 0xff) | ((data & 0x01) << 8); + } + else if (offset < 0x6000) + { + data &= 0x0f; + if (has_rumble) + data &= 0x7; + m_ram_bank = data; + } +} + +READ8_MEMBER(gb_rom_mbc5_device::read_ram) +{ + if (!m_ram.empty() && m_ram_enable) + return m_ram[ram_bank_map[m_ram_bank] * 0x2000 + (offset & 0x1fff)]; + else + return 0xff; +} + +WRITE8_MEMBER(gb_rom_mbc5_device::write_ram) +{ + if (!m_ram.empty() && m_ram_enable) + m_ram[ram_bank_map[m_ram_bank] * 0x2000 + (offset & 0x1fff)] = data; +} + +// MBC6 + +READ8_MEMBER(gb_rom_mbc6_device::read_rom) +{ + if (offset < 0x4000) + return m_rom[rom_bank_map[m_latch_bank] * 0x4000 + (offset & 0x3fff)]; + else if (offset < 0x6000) + return m_rom[rom_bank_map[m_bank_4000 >> 1] * 0x4000 + (m_bank_4000 & 0x01) * 0x2000 + (offset & 0x1fff)]; + else + return m_rom[rom_bank_map[m_bank_6000 >> 1] * 0x4000 + (m_bank_6000 & 0x01) * 0x2000 + (offset & 0x1fff)]; +} + +WRITE8_MEMBER(gb_rom_mbc6_device::write_bank) +{ + if (offset < 0x2000) + { + logerror( "0x%04X: write to mbc6 ram enable area: %04X <- 0x%02X\n", space.device().safe_pc(), offset, data ); + } + else if (offset < 0x3000) + { + if (!(offset & 0x0800)) + m_latch1 = data; + else if (data == 0x00) + m_bank_4000 = m_latch1; + } + else if (offset < 0x4000) + { + if (!(offset & 0x0800)) + m_latch2 = data; + else if (data == 0x00) + m_bank_6000 = m_latch2; + } +} + +READ8_MEMBER(gb_rom_mbc6_device::read_ram) +{ + if (!m_ram.empty()) + return m_ram[ram_bank_map[m_ram_bank] * 0x2000 + (offset & 0x1fff)]; + else + return 0xff; +} + +WRITE8_MEMBER(gb_rom_mbc6_device::write_ram) +{ + if (!m_ram.empty()) + m_ram[ram_bank_map[m_ram_bank] * 0x2000 + (offset & 0x1fff)] = data; +} + +// MBC7 + +READ8_MEMBER(gb_rom_mbc7_device::read_rom) +{ + if (offset < 0x4000) + return m_rom[rom_bank_map[m_latch_bank] * 0x4000 + (offset & 0x3fff)]; + else + return m_rom[rom_bank_map[m_latch_bank2] * 0x4000 + (offset & 0x3fff)]; +} + +WRITE8_MEMBER(gb_rom_mbc7_device::write_bank) +{ + if (offset < 0x2000) + { + // FIXME: Add RAM enable support + logerror("0x%04X: Write to ram enable register 0x%04X <- 0x%02X\n", space.device().safe_pc( ), offset, data); + } + else if (offset < 0x3000) + { + logerror( "0x%04X: write to mbc7 rom select register: 0x%04X <- 0x%02X\n", space.device() .safe_pc( ), 0x2000 + offset, data ); + /* Bit 12 must be set for writing to the mbc register */ + if (offset & 0x0100) + m_latch_bank2 = data; + } + else + { + logerror( "0x%04X: write to mbc7 rom area: 0x%04X <- 0x%02X\n", space.device() .safe_pc( ), 0x3000 + offset, data ); + /* Bit 12 must be set for writing to the mbc register */ + if (offset & 0x0100) + { + switch (offset & 0x7000) + { + case 0x3000: /* 0x3000-0x3fff */ + case 0x4000: /* 0x4000-0x4fff */ + case 0x5000: /* 0x5000-0x5fff */ + case 0x6000: /* 0x6000-0x6fff */ + case 0x7000: /* 0x7000-0x7fff */ + break; + } + } + } +} + +READ8_MEMBER(gb_rom_mbc7_device::read_ram) +{ + if (!m_ram.empty()) + return m_ram[ram_bank_map[m_ram_bank] * 0x2000 + (offset & 0x1fff)]; + else + return 0xff; +} + +WRITE8_MEMBER(gb_rom_mbc7_device::write_ram) +{ + if (!m_ram.empty()) + m_ram[ram_bank_map[m_ram_bank] * 0x2000 + (offset & 0x1fff)] = data; +} + + +// M161-M12 + +READ8_MEMBER(gb_rom_m161_device::read_rom) +{ + if (offset < 0x4000) + return m_rom[rom_bank_map[m_base_bank] * 0x4000 + offset]; + else + return m_rom[rom_bank_map[m_base_bank] * 0x4000 + (offset & 0x3fff)]; +} + +WRITE8_MEMBER(gb_rom_m161_device::write_bank) +{ + switch (offset & 0xe000) + { + case 0x4000: // Base Bank Register + m_base_bank = data << 1; + break; + case 0x2000: // Tetris writes 1 here when selected... + default: + break; + } +} + + +// MMM01 +// This mmm01 implementation is mostly guess work, no clue how correct it all is +/* TODO: This implementation is wrong. Tauwasser + * + * Register 0: Map Latch, AA Mask, RAM Enable + * Register 1: EA1..EA0, RA18..RA14 + * Register 2: ??, AA18..AA15, AA14..AA13 + * Register 3: AA Multiplex, RA Mask, ???, MBC1 Mode + * + */ + +READ8_MEMBER(gb_rom_mmm01_device::read_rom) +{ + if (offset < 0x4000) + return m_rom[rom_bank_map[m_latch_bank] * 0x4000 + offset]; + else + return m_rom[rom_bank_map[m_latch_bank2] * 0x4000 + (offset & 0x3fff)]; +} + +WRITE8_MEMBER(gb_rom_mmm01_device::write_bank) +{ + if (offset < 0x2000) + { + if (data & 0x40) + { + m_latch_bank = m_reg; + m_latch_bank2 = m_latch_bank + m_bank; + } + } + else if (offset < 0x4000) + { + m_reg = data & ((m_rom_size / 0x4000) - 1); + m_bank = m_reg & m_bank_mask; + if (m_bank == 0) + m_bank = 1; + m_latch_bank2 = m_latch_bank + m_bank; + } + else if (offset < 0x6000) + logerror("0x%04X: write 0x%02X to 0x%04X\n", space.device().safe_pc(), data, offset); + else + { + logerror("0x%04X: write 0x%02X to 0x%04X\n", space.device().safe_pc(), data, offset); + /* Not sure if this is correct, Taito Variety Pack sets these values */ + /* Momotarou Collection 2 writes 01 and 21 here */ + switch (data) + { + case 0x30: m_bank_mask = 0x07; break; + case 0x38: m_bank_mask = 0x03; break; + default: m_bank_mask = 0xff; break; + } + } +} + +// Sachen MMC1 + +READ8_MEMBER(gb_rom_sachen_mmc1_device::read_rom) +{ + UINT16 off_edit = offset; + + /* Wait for 0x31 transitions of A15 (hi -> lo), i.e. ROM accesses; A15 = HI while in bootstrap */ + /* This is 0x31 transitions, because we increment counter _after_ checking it */ + if (m_unlock_cnt == 0x30) + m_mode = MODE_UNLOCKED; + else + m_unlock_cnt++; + + /* Logo Switch */ + if (m_mode == MODE_LOCKED) + off_edit |= 0x80; + + /* Header Un-Scramble */ + if ((off_edit & 0xFF00) == 0x0100) { + off_edit &= 0xFFAC; + off_edit |= ((offset >> 6) & 0x01) << 0; + off_edit |= ((offset >> 4) & 0x01) << 1; + off_edit |= ((offset >> 1) & 0x01) << 4; + off_edit |= ((offset >> 0) & 0x01) << 6; + } + //logerror("read from %04X (%04X)\n", offset, off_edit); + + if (offset & 0x4000) /* RB1 */ + return m_rom[rom_bank_map[(m_base_bank & m_mask) | (m_latch_bank2 & ~m_mask)] * 0x4000 + (offset & 0x3fff)]; + else /* RB0 */ + return m_rom[rom_bank_map[(m_base_bank & m_mask) | (m_latch_bank & ~m_mask)] * 0x4000 + (off_edit & 0x3fff)]; +} + +WRITE8_MEMBER(gb_rom_sachen_mmc1_device::write_bank) +{ + /* Only A15..A6, A4, A1..A0 are connected */ + /* We only decode upper three bits */ + switch ((offset & 0xFFD3) & 0xE000) + { + case 0x0000: /* Base ROM Bank Register */ + + if ((m_latch_bank2 & 0x30) == 0x30) + m_base_bank = data; + //logerror("write to base bank %X - %X\n", data, (m_base_bank & m_mask) | (m_latch_bank2 & ~m_mask)); + break; + + case 0x2000: /* ROM Bank Register */ + + m_latch_bank2 = data ? data : 0x01; + //logerror("write to latch %X - %X\n", data, (m_base_bank & m_mask) | (m_latch_bank2 & ~m_mask)); + break; + + case 0x4000: /* ROM Bank Mask Register */ + + if ((m_latch_bank2 & 0x30) == 0x30) + m_mask = data; + //logerror("write to mask %X - %X\n", data, (m_base_bank & m_mask) | (m_latch_bank2 & ~m_mask)); + break; + + case 0x6000: + + /* nothing happens when writing to 0x6000-0x7fff, as verified by Tauwasser */ + break; + + default: + + //logerror("write to unknown/unmapped area %04X <= %02X\n", offset, data); + /* did not extensively test other unlikely ranges */ + break; + } +} + +// Sachen MMC2 + +READ8_MEMBER(gb_rom_sachen_mmc2_device::read_rom) +{ + UINT16 off_edit = offset; + + /* Wait for 0x30 transitions of A15 (lo -> hi), i.e. ROM accesses; A15 = HI while in bootstrap */ + /* This is 0x30 transitions, because we increment counter _after_ checking it, but A15 lo -> hi*/ + /* transition means first read (hi -> lo transition) must not count */ + + if (m_unlock_cnt == 0x30 && m_mode == MODE_LOCKED_DMG) { + m_mode = MODE_LOCKED_CGB; + m_unlock_cnt = 0x00; + } else if (m_unlock_cnt == 0x30 && m_mode == MODE_LOCKED_CGB) { + m_mode = MODE_UNLOCKED; + } + + if (m_unlock_cnt != 0x30) + m_unlock_cnt++; + + /* Logo Switch */ + if (m_mode == MODE_LOCKED_CGB) + off_edit |= 0x80; + + /* Header Un-Scramble */ + if ((off_edit & 0xFF00) == 0x0100) { + off_edit &= 0xFFAC; + off_edit |= ((offset >> 6) & 0x01) << 0; + off_edit |= ((offset >> 4) & 0x01) << 1; + off_edit |= ((offset >> 1) & 0x01) << 4; + off_edit |= ((offset >> 0) & 0x01) << 6; + } + //logerror("read from %04X (%04X) cnt: %02X\n", offset, off_edit, m_unlock_cnt); + + if (offset & 0x4000) /* RB1 */ + return m_rom[rom_bank_map[(m_base_bank & m_mask) | (m_latch_bank2 & ~m_mask)] * 0x4000 + (offset & 0x3fff)]; + else /* RB0 */ + return m_rom[rom_bank_map[(m_base_bank & m_mask) | (m_latch_bank & ~m_mask)] * 0x4000 + (off_edit & 0x3fff)]; +} + +READ8_MEMBER(gb_rom_sachen_mmc2_device::read_ram) +{ + if (m_mode == MODE_LOCKED_DMG) { + m_unlock_cnt = 0x00; + m_mode = MODE_LOCKED_CGB; + } + return 0xFF; + +} + +WRITE8_MEMBER(gb_rom_sachen_mmc2_device::write_ram) +{ + if (m_mode == MODE_LOCKED_DMG) { + m_unlock_cnt = 0x00; + m_mode = MODE_LOCKED_CGB; + } + +} + + +// 188 in 1 pirate (only preliminary) + +READ8_MEMBER(gb_rom_188in1_device::read_rom) +{ + if (offset < 0x4000) + return m_rom[m_game_base + rom_bank_map[m_latch_bank] * 0x4000 + (offset & 0x3fff)]; + else + return m_rom[m_game_base + rom_bank_map[m_latch_bank2] * 0x4000 + (offset & 0x3fff)]; +} + +WRITE8_MEMBER(gb_rom_188in1_device::write_bank) +{ + if (offset == 0x7b00) + { + if (data < 0x80) + logerror("write to 0x%X data 0x%X\n", offset, data); + else + { + data -= 0x80; + m_game_base = 0x400000 + (data * 0x8000); + //logerror("offset 0x%X\n", m_game_base); + } + } + else if (offset == 0x7b01 || offset == 0x7b02) + { + // what do these writes do? + printf("write to 0x%X data 0x%X\n", offset, data); + } + else + gb_rom_mbc1_device::write_bank(space, offset, data); +} + + +// MBC5 variant used by Li Cheng / Niutoude games + +WRITE8_MEMBER(gb_rom_licheng_device::write_bank) +{ + if (offset > 0x2100 && offset < 0x3000) + return; + + gb_rom_mbc5_device::write_bank(space, offset, data); +} + +// MBC5 variant used by Chong Wu Xiao Jing Ling (this appears to be a re-release of a Li Cheng / Niutoude game, +// given that it contains the Niutoude logo, with most protection checks patched out) + +READ8_MEMBER(gb_rom_chongwu_device::read_rom) +{ + // protection check at the first read here... + if (offset == 0x41c3 && !m_protection_checked) + { + m_protection_checked = 1; + return 0x5d; + } + + if (offset < 0x4000) + return m_rom[rom_bank_map[m_latch_bank] * 0x4000 + (offset & 0x3fff)]; + else + return m_rom[rom_bank_map[m_latch_bank2] * 0x4000 + (offset & 0x3fff)]; +} + +// MBC5 variant used by Sintax games + +void gb_rom_sintax_device::set_xor_for_bank(UINT8 bank) +{ + switch (bank & 0x0f) + { + case 0x00: case 0x04: case 0x08: case 0x0c: + m_currentxor = m_xor2; + break; + case 0x01: case 0x05: case 0x09: case 0x0d: + m_currentxor = m_xor3; + break; + case 0x02: case 0x06: case 0x0a: case 0x0e: + m_currentxor = m_xor4; + break; + case 0x03: case 0x07: case 0x0b: case 0x0f: + m_currentxor = m_xor5; + break; + } +} + +READ8_MEMBER(gb_rom_sintax_device::read_rom) +{ + if (offset < 0x4000) + return m_rom[rom_bank_map[m_latch_bank] * 0x4000 + (offset & 0x3fff)]; + else + return m_rom[rom_bank_map[m_latch_bank2] * 0x4000 + (offset & 0x3fff)] ^ m_currentxor; +} + +WRITE8_MEMBER(gb_rom_sintax_device::write_bank) +{ + if (offset < 0x2000) + m_ram_enable = ((data & 0x0f) == 0x0a) ? 1 : 0; + else if (offset < 0x3000) + { + set_xor_for_bank(data); + + switch (m_sintax_mode & 0x0f) + { + case 0x0d: + data = BITSWAP8(data, 1,0,7,6,5,4,3,2); + break; + case 0x09: + //data = BITSWAP8(data, 3,2,5,4,0,1,6,7); // Monkey..no + data = BITSWAP8(data, 4,5,2,3,0,1,6,7); + break; + case 0x00: // 0x10=lion 0x00 hmmmmm // 1 and 0 unconfirmed + data = BITSWAP8(data, 7,0,5,6,3,4,1,2); + break; + case 0x01: + data = BITSWAP8(data, 0,1,6,7,4,5,2,3); + break; + case 0x05: + data = BITSWAP8(data, 7,6,1,0,3,2,5,4); // Not 100% on this one + break; + case 0x07: + data = BITSWAP8(data, 2,0,3,1,5,4,7,6); // 5 and 7 unconfirmed + break; + case 0x0b: + data = BITSWAP8(data, 2,3,0,1,6,7,4,5); // 5 and 6 unconfirmed + break; + } + m_latch_bank2 = (m_latch_bank2 & 0x100) | data; + } + else if (offset < 0x4000) + { + m_latch_bank2 = (m_latch_bank2 & 0xff) | ((data & 0x01) << 8); + } + else if (offset < 0x5000) + { + data &= 0x0f; + if (has_rumble) + data &= 0x7; + m_ram_bank = data; + } + else if (offset < 0x6000) + { + if (!m_sintax_mode) + { + m_sintax_mode = data; + write_bank(space, 0x2000, 1); //force a fake bank switch + } +// printf("sintax mode %x\n", m_sintax_mode & 0xf); + } + else if (offset >= 0x7000) + { + switch ((offset & 0x00f0) >> 4) + { + case 2: + m_xor2 = data; + break; + case 3: + m_xor3 = data; + break; + case 4: + m_xor4 = data; + break; + case 5: + m_xor5 = data; + break; + } + + if (m_currentxor == 0) + set_xor_for_bank(4); + } + +} + +READ8_MEMBER(gb_rom_sintax_device::read_ram) +{ + if (!m_ram.empty() && m_ram_enable) + return m_ram[ram_bank_map[m_ram_bank] * 0x2000 + (offset & 0x1fff)]; + else + return 0xff; +} + +WRITE8_MEMBER(gb_rom_sintax_device::write_ram) +{ + if (!m_ram.empty() && m_ram_enable) + m_ram[ram_bank_map[m_ram_bank] * 0x2000 + (offset & 0x1fff)] = data; +} + +/* + + Further MBC5 variants to emulate: + + Digimon 2 & Digimon 4 (Yong Yong) + + Digimon 2 writes at $2000 to select latch2 (data must be divided by 2, and 0 becomes 1), + then writes to $2400 a series of values that the patched version does not write... + Digimon 4 seems to share part of the $2000 behavior, but does not write to $2400... + + */ + +// MBC5 variant used by Digimon 2 (and maybe 4?) + +READ8_MEMBER(gb_rom_digimon_device::read_rom) +{ + if (offset < 0x4000) + return m_rom[rom_bank_map[m_latch_bank] * 0x4000 + (offset & 0x3fff)]; + else + return m_rom[rom_bank_map[m_latch_bank2] * 0x4000 + (offset & 0x3fff)]; +} + +WRITE8_MEMBER(gb_rom_digimon_device::write_bank) +{ + if (offset < 0x2000) + m_ram_enable = ((data & 0x0f) == 0x0a) ? 1 : 0; + else if (offset == 0x2000) + { +// printf("written $02 %X at %X\n", data, offset); + if (!data) + data++; + m_latch_bank2 = data/2; + } + else if (offset < 0x3000) + { +// printf("written $03 %X at %X\n", data, offset); + } + else if (offset < 0x4000) + { +// printf("written $04 %X at %X\n", data, offset); + } + else if (offset < 0x6000) + { +// printf("written $05-$06 %X at %X\n", data, offset); + data &= 0x0f; + if (has_rumble) + data &= 0x7; + m_ram_bank = data; + } +// else +// printf("written $07 %X at %X\n", data, offset); +} + +READ8_MEMBER(gb_rom_digimon_device::read_ram) +{ + if (!m_ram.empty() && m_ram_enable) + return m_ram[ram_bank_map[m_ram_bank] * 0x2000 + (offset & 0x1fff)]; + else + return 0xff; +} + +WRITE8_MEMBER(gb_rom_digimon_device::write_ram) +{ + if (!m_ram.empty() && m_ram_enable) + m_ram[ram_bank_map[m_ram_bank] * 0x2000 + (offset & 0x1fff)] = data; +} + + +// MBC1 variant used by Yong Yong for Rockman 8 + +READ8_MEMBER(gb_rom_rockman8_device::read_rom) +{ + if (offset < 0x4000) + return m_rom[m_latch_bank * 0x4000 + (offset & 0x3fff)]; + else + return m_rom[m_latch_bank2 * 0x4000 + (offset & 0x3fff)]; +} + +WRITE8_MEMBER(gb_rom_rockman8_device::write_bank) +{ + if (offset < 0x2000) + return; + else if (offset < 0x4000) + { + // 5bits only + data &= 0x1f; + if (data == 0) + data = 1; + if (data > 0xf) + data -= 8; + + m_latch_bank2 = data; + } +} + +READ8_MEMBER(gb_rom_rockman8_device::read_ram) +{ + if (!m_ram.empty()) + return m_ram[offset]; + else + return 0xff; +} + +WRITE8_MEMBER(gb_rom_rockman8_device::write_ram) +{ + if (!m_ram.empty()) + m_ram[offset] = data; +} + +// MBC1 variant used by Yong Yong for Super Mario 3 Special + +// Mario special seems to be 512k image (mirrored up to 1m or 2m [redump needed to establish this]) +// it consists of 13 unique 16k chunks layed out as follows +// unique chunk --> bank in bin +// 1st to 7th --> 0x00 to 0x06 +// 8th --> 0x08 +// 9th --> 0x0b +// 10th --> 0x0c +// 11th --> 0x0d +// 12th --> 0x0f +// 13th --> 0x13 + +// writing data to 0x2000-0x2fff switches bank according to the table below +// (the value values corresponding to table[0x0f] is not confirmed, choices +// 0,1,2,3,8,c,f freeze the game, while 4,5,6,7,b,d,0x13 work with glitches) +static UINT8 smb3_table1[0x20] = +{ + 0x00,0x04,0x01,0x05, 0x02,0x06,0x03,0x05, 0x08,0x0c,0x03,0x0d, 0x03,0x0b,0x0b,0x08 /* original doc here put 0x0f (i.e. 11th unique bank) */, + 0x05,0x06,0x0b,0x0d, 0x08,0x06,0x13,0x0b, 0x08,0x05,0x05,0x08, 0x0b,0x0d,0x06,0x05 +}; + +// according to old doc from Brian Provinciano, writing bit5 in 0x5000-0x5fff should +// change the bank layout, in the sense that writing to bankswitch acts like if +// the original rom has a different layout (as if unique chunks were under permutations +// (24), (365) and (8a9) with 0,1,7,b,c fixed) and the same table above is used +// however, no such a write ever happen (only bit4 is written, but changing mode with +// bit4 breaks the gfx...) + +READ8_MEMBER(gb_rom_sm3sp_device::read_rom) +{ + if (offset < 0x4000) + return m_rom[rom_bank_map[0] * 0x4000 + (offset & 0x3fff)]; + else + return m_rom[m_latch_bank2 * 0x4000 + (offset & 0x3fff)]; +} + +WRITE8_MEMBER(gb_rom_sm3sp_device::write_bank) +{ +// printf("write 0x%x at %x\n", data, offset); + if (offset < 0x2000) + return; + else if (offset < 0x3000) + { + // Table 1 confirmed... + // 0->0, 4->2, 6->3 + // 1e -> 6 (level 1 bg gfx) + // 19 -> 5 (level 2 bg gfx) + // 1b -> 8 (level 3 bg gfx) + // 1d -> D (level 4 bg gfx) + // 1c -> B (bonus house bg gfx) + // 1 (9 maybe, or 3)? f (5 maybe)? 2->1? + // 16 -> 4-8? b? + + // 5bits only + data &= 0x1f; + + m_latch_bank2 = smb3_table1[data]; + if (m_mode) + { + switch (m_latch_bank2) + { + case 0x02: m_latch_bank2 = 4; break; + case 0x03: m_latch_bank2 = 6; break; + case 0x04: m_latch_bank2 = 2; break; + case 0x05: m_latch_bank2 = 3; break; + case 0x06: m_latch_bank2 = 5; break; + case 0x0b: m_latch_bank2 = 0xd; break; + case 0x0c: m_latch_bank2 = 0xb; break; + case 0x0d: m_latch_bank2 = 0xc; break; + + case 0x00: + case 0x01: + case 0x08: + case 0x0f: + case 0x13: + default: + break; + } + } + } + else if (offset < 0x5000) + { +// printf("write $5 %X at %X\n", data, offset); + //maybe rumble?? + } + else if (offset < 0x6000) + { +// printf("write mode %x\n", data); + m_mode = BIT(data, 5); +// write_bank(space, 0x2000, 1); + } +} + +READ8_MEMBER(gb_rom_sm3sp_device::read_ram) +{ + if (!m_ram.empty()) + return m_ram[offset]; + else + return 0xff; +} + +WRITE8_MEMBER(gb_rom_sm3sp_device::write_ram) +{ + if (!m_ram.empty()) + m_ram[offset] = data; +} diff --git a/src/devices/bus/gameboy/mbc.h b/src/devices/bus/gameboy/mbc.h new file mode 100644 index 00000000000..3ad27d2cdee --- /dev/null +++ b/src/devices/bus/gameboy/mbc.h @@ -0,0 +1,393 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli, Wilbert Pol +#ifndef __GB_MBC_H +#define __GB_MBC_H + +#include "gb_slot.h" + + +// ======================> gb_rom_mbc_device + +class gb_rom_mbc_device : public device_t, + public device_gb_cart_interface +{ +public: + // construction/destruction + gb_rom_mbc_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + // device-level overrides + virtual void device_start() { shared_start(); }; + virtual void device_reset() { shared_reset(); }; + + void shared_start(); + void shared_reset(); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_rom); + virtual DECLARE_READ8_MEMBER(read_ram); + virtual DECLARE_WRITE8_MEMBER(write_ram); + + UINT8 m_ram_enable; +}; + +// ======================> gb_rom_mbc1_device + +class gb_rom_mbc1_device : public gb_rom_mbc_device +{ +public: + + enum { + MODE_16M_64k = 0, /// 16Mbit ROM, 64kBit RAM + MODE_4M_256k = 1 /// 4Mbit ROM, 256kBit RAM + }; + + // construction/destruction + gb_rom_mbc1_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + gb_rom_mbc1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start() { shared_start(); save_item(NAME(m_mode)); }; + virtual void device_reset() { shared_reset(); m_mode = MODE_16M_64k; }; + virtual void set_additional_wirings(UINT8 mask, int shift) { m_mask = mask; m_shift = shift; } // these get set at cart loading + + virtual DECLARE_READ8_MEMBER(read_rom); + virtual DECLARE_WRITE8_MEMBER(write_bank); + virtual DECLARE_READ8_MEMBER(read_ram); + virtual DECLARE_WRITE8_MEMBER(write_ram); + + UINT8 m_mode, m_mask; + int m_shift; +}; + +// ======================> gb_rom_mbc2_device + +class gb_rom_mbc2_device : public gb_rom_mbc_device +{ +public: + // construction/destruction + gb_rom_mbc2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start() { shared_start(); }; + virtual void device_reset() { shared_reset(); }; + + virtual DECLARE_READ8_MEMBER(read_rom); + virtual DECLARE_WRITE8_MEMBER(write_bank); + virtual DECLARE_READ8_MEMBER(read_ram); + virtual DECLARE_WRITE8_MEMBER(write_ram); +}; + +// ======================> gb_rom_mbc3_device + +class gb_rom_mbc3_device : public gb_rom_mbc_device +{ +public: + // construction/destruction + gb_rom_mbc3_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + virtual DECLARE_READ8_MEMBER(read_rom); + virtual DECLARE_WRITE8_MEMBER(write_bank); + virtual DECLARE_READ8_MEMBER(read_ram); + virtual DECLARE_WRITE8_MEMBER(write_ram); + UINT8 m_rtc_map[5]; +}; + +// ======================> gb_rom_mbc5_device + +class gb_rom_mbc5_device : public gb_rom_mbc_device +{ +public: + // construction/destruction + gb_rom_mbc5_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + gb_rom_mbc5_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start() { shared_start(); }; + virtual void device_reset() { shared_reset(); }; + + virtual DECLARE_READ8_MEMBER(read_rom); + virtual DECLARE_WRITE8_MEMBER(write_bank); + virtual DECLARE_READ8_MEMBER(read_ram); + virtual DECLARE_WRITE8_MEMBER(write_ram); +}; + +// ======================> gb_rom_mbc6_device + +class gb_rom_mbc6_device : public gb_rom_mbc_device +{ +public: + // construction/destruction + gb_rom_mbc6_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + virtual DECLARE_READ8_MEMBER(read_rom); + virtual DECLARE_WRITE8_MEMBER(write_bank); + virtual DECLARE_READ8_MEMBER(read_ram); + virtual DECLARE_WRITE8_MEMBER(write_ram); + UINT16 m_latch1, m_latch2; + UINT8 m_bank_4000, m_bank_6000; +}; + +// ======================> gb_rom_mbc7_device + +class gb_rom_mbc7_device : public gb_rom_mbc_device +{ +public: + // construction/destruction + gb_rom_mbc7_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start() { shared_start(); }; + virtual void device_reset() { shared_reset(); }; + + virtual DECLARE_READ8_MEMBER(read_rom); + virtual DECLARE_WRITE8_MEMBER(write_bank); + virtual DECLARE_READ8_MEMBER(read_ram); + virtual DECLARE_WRITE8_MEMBER(write_ram); +}; + +// ======================> gb_rom_m161_device + +class gb_rom_m161_device : public gb_rom_mbc_device +{ +public: + + // construction/destruction + gb_rom_m161_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + virtual DECLARE_READ8_MEMBER(read_rom); + virtual DECLARE_WRITE8_MEMBER(write_bank); + virtual DECLARE_READ8_MEMBER(read_ram) { return 0xff; } + virtual DECLARE_WRITE8_MEMBER(write_ram) { } + + UINT8 m_base_bank; +}; + +// ======================> gb_rom_mmm01_device +class gb_rom_mmm01_device : public gb_rom_mbc_device +{ +public: + // construction/destruction + gb_rom_mmm01_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_rom); + virtual DECLARE_WRITE8_MEMBER(write_bank); + UINT8 m_bank_mask, m_bank, m_reg; +}; + +// ======================> gb_rom_sachen_mmc1_device + +class gb_rom_sachen_mmc1_device : public gb_rom_mbc_device +{ +public: + + enum { + MODE_LOCKED, + MODE_UNLOCKED + }; + + // construction/destruction + gb_rom_sachen_mmc1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + gb_rom_sachen_mmc1_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + virtual DECLARE_READ8_MEMBER(read_rom); + virtual DECLARE_WRITE8_MEMBER(write_bank); + virtual DECLARE_READ8_MEMBER(read_ram) { return 0xff; } + virtual DECLARE_WRITE8_MEMBER(write_ram) { } + + UINT8 m_base_bank, m_mask, m_mode, m_unlock_cnt; +}; + +// ======================> gb_rom_sachen_mmc2_device + +class gb_rom_sachen_mmc2_device : public gb_rom_sachen_mmc1_device +{ +public: + + enum { + MODE_LOCKED_DMG, + MODE_LOCKED_CGB, + MODE_UNLOCKED + }; + + // construction/destruction + gb_rom_sachen_mmc2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + virtual DECLARE_READ8_MEMBER(read_rom); + virtual DECLARE_READ8_MEMBER(read_ram); + virtual DECLARE_WRITE8_MEMBER(write_ram); + +}; + +// ======================> gb_rom_188in1_device +class gb_rom_188in1_device : public gb_rom_mbc1_device +{ +public: + // construction/destruction + gb_rom_188in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start() { shared_start(); save_item(NAME(m_game_base)); }; + virtual void device_reset() { shared_reset(); m_game_base = 0; }; + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_rom); + virtual DECLARE_WRITE8_MEMBER(write_bank); + +private: + UINT32 m_game_base; +}; + +// ======================> gb_rom_sintax_device +class gb_rom_sintax_device : public gb_rom_mbc_device +{ +public: + // construction/destruction + gb_rom_sintax_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + void set_xor_for_bank(UINT8 bank); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_rom); + virtual DECLARE_WRITE8_MEMBER(write_bank); + virtual DECLARE_READ8_MEMBER(read_ram); + virtual DECLARE_WRITE8_MEMBER(write_ram); + UINT8 m_bank_mask, m_bank, m_reg; + + UINT8 m_currentxor, m_xor2, m_xor3, m_xor4, m_xor5, m_sintax_mode; +}; + +// ======================> gb_rom_chongwu_device + +class gb_rom_chongwu_device : public gb_rom_mbc5_device +{ +public: + // construction/destruction + gb_rom_chongwu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + virtual DECLARE_READ8_MEMBER(read_rom); + UINT8 m_protection_checked; +}; + +// ======================> gb_rom_licheng_device + +class gb_rom_licheng_device : public gb_rom_mbc5_device +{ +public: + // construction/destruction + gb_rom_licheng_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual DECLARE_WRITE8_MEMBER(write_bank); +}; + +// ======================> gb_rom_digimon_device + +class gb_rom_digimon_device : public gb_rom_mbc5_device +{ +public: + // construction/destruction + gb_rom_digimon_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start() { shared_start(); }; + virtual void device_reset() { shared_reset(); }; + + virtual DECLARE_READ8_MEMBER(read_rom); + virtual DECLARE_WRITE8_MEMBER(write_bank); + virtual DECLARE_READ8_MEMBER(read_ram); + virtual DECLARE_WRITE8_MEMBER(write_ram); +}; + +// ======================> gb_rom_rockman8_device +class gb_rom_rockman8_device : public gb_rom_mbc_device +{ +public: + // construction/destruction + gb_rom_rockman8_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start() { shared_start(); }; + virtual void device_reset() { shared_reset(); }; + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_rom); + virtual DECLARE_WRITE8_MEMBER(write_bank); + virtual DECLARE_READ8_MEMBER(read_ram); + virtual DECLARE_WRITE8_MEMBER(write_ram); + UINT8 m_bank_mask, m_bank, m_reg; +}; + +// ======================> gb_rom_sm3sp_device +class gb_rom_sm3sp_device : public gb_rom_mbc_device +{ +public: + // construction/destruction + gb_rom_sm3sp_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start() { shared_start(); }; + virtual void device_reset() { shared_reset(); }; + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_rom); + virtual DECLARE_WRITE8_MEMBER(write_bank); + virtual DECLARE_READ8_MEMBER(read_ram); + virtual DECLARE_WRITE8_MEMBER(write_ram); + UINT8 m_bank_mask, m_bank, m_reg, m_mode; +}; + + + +// device type definition +extern const device_type GB_ROM_MBC1; +extern const device_type GB_ROM_MBC1_COL; +extern const device_type GB_ROM_MBC2; +extern const device_type GB_ROM_MBC3; +extern const device_type GB_ROM_MBC4; +extern const device_type GB_ROM_MBC5; +extern const device_type GB_ROM_MBC6; +extern const device_type GB_ROM_MBC7; +extern const device_type GB_ROM_M161_M12; +extern const device_type GB_ROM_MMM01; +extern const device_type GB_ROM_SACHEN1; +extern const device_type GB_ROM_SACHEN2; +extern const device_type GB_ROM_188IN1; +extern const device_type GB_ROM_SINTAX; +extern const device_type GB_ROM_CHONGWU; +extern const device_type GB_ROM_LICHENG; +extern const device_type GB_ROM_DIGIMON; +extern const device_type GB_ROM_ROCKMAN8; +extern const device_type GB_ROM_SM3SP; + +#endif diff --git a/src/devices/bus/gameboy/rom.c b/src/devices/bus/gameboy/rom.c new file mode 100644 index 00000000000..2be759adf1b --- /dev/null +++ b/src/devices/bus/gameboy/rom.c @@ -0,0 +1,364 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli, Wilbert Pol +/*********************************************************************************************************** + + Game Boy cart emulation + + + Here we emulate carts with no RAM and simple bankswitch + + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "rom.h" + + +//------------------------------------------------- +// gb_rom_device - constructor +//------------------------------------------------- + +const device_type GB_STD_ROM = &device_creator; +const device_type GB_ROM_TAMA5 = &device_creator; +const device_type GB_ROM_WISDOM = &device_creator; +const device_type GB_ROM_YONG = &device_creator; +const device_type GB_ROM_ATVRAC = &device_creator; +const device_type GB_ROM_LASAMA = &device_creator; + +const device_type MEGADUCK_ROM = &device_creator; + + +gb_rom_device::gb_rom_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_gb_cart_interface( mconfig, *this ) +{ +} + +gb_rom_device::gb_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, GB_STD_ROM, "GB Carts", tag, owner, clock, "gb_rom", __FILE__), + device_gb_cart_interface( mconfig, *this ) +{ +} + +gb_rom_tama5_device::gb_rom_tama5_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : gb_rom_device(mconfig, GB_ROM_TAMA5, "GB Tamagotchi", tag, owner, clock, "gb_rom_tama5", __FILE__) +{ +} + +gb_rom_wisdom_device::gb_rom_wisdom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : gb_rom_device(mconfig, GB_ROM_WISDOM, "GB Wisdom Tree Carts", tag, owner, clock, "gb_rom_wisdom", __FILE__) +{ +} + +gb_rom_yong_device::gb_rom_yong_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : gb_rom_device(mconfig, GB_ROM_YONG, "GB Yong Yong Carts", tag, owner, clock, "gb_rom_yong", __FILE__) +{ +} + +gb_rom_atvrac_device::gb_rom_atvrac_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : gb_rom_device(mconfig, GB_ROM_ATVRAC, "GB ATV Racin'", tag, owner, clock, "gb_rom_atvrac", __FILE__) +{ +} + +gb_rom_lasama_device::gb_rom_lasama_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : gb_rom_device(mconfig, GB_ROM_LASAMA, "GB LaSaMa", tag, owner, clock, "gb_rom_lasama", __FILE__) +{ +} + + +megaduck_rom_device::megaduck_rom_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_gb_cart_interface( mconfig, *this ) +{ +} + +megaduck_rom_device::megaduck_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, MEGADUCK_ROM, "MegaDuck Carts", tag, owner, clock, "megaduck_rom", __FILE__), + device_gb_cart_interface( mconfig, *this ) +{ +} + + +//------------------------------------------------- +// shared_start +//------------------------------------------------- + +void gb_rom_device::shared_start() +{ + save_item(NAME(m_latch_bank)); + save_item(NAME(m_latch_bank2)); + save_item(NAME(m_ram_bank)); +} + +//------------------------------------------------- +// shared_reset +//------------------------------------------------- + +void gb_rom_device::shared_reset() +{ + m_ram_bank = 0; + m_latch_bank = 0; + m_latch_bank2 = 1; +} + +//------------------------------------------------- +// mapper specific start/reset +//------------------------------------------------- + +void gb_rom_tama5_device::device_start() +{ + shared_start(); + save_item(NAME(m_tama5_data)); + save_item(NAME(m_tama5_addr)); + save_item(NAME(m_tama5_cmd)); + save_item(NAME(m_regs)); + save_item(NAME(m_rtc_reg)); +} + +void gb_rom_tama5_device::device_reset() +{ + shared_reset(); + m_tama5_data = 0; + m_tama5_addr= 0; + m_tama5_cmd = 0; + memset(m_regs, 0xff, sizeof(m_regs)); + m_rtc_reg = 0xff; +} + + +// these are identical to shared ones above, but megaduck cart class is not derived from gb cart class... +void megaduck_rom_device::device_start() +{ + save_item(NAME(m_latch_bank)); + save_item(NAME(m_latch_bank2)); + save_item(NAME(m_ram_bank)); +} + +void megaduck_rom_device::device_reset() +{ + m_ram_bank = 0; + m_latch_bank = 0; + m_latch_bank2 = 1; +} + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +READ8_MEMBER(gb_rom_device::read_rom) +{ + m_latch_bank = offset / 0x4000; + return m_rom[rom_bank_map[m_latch_bank] * 0x4000 + (offset & 0x3fff)]; +} + +READ8_MEMBER(gb_rom_device::read_ram) +{ + if (!m_ram.empty()) + return m_ram[ram_bank_map[m_ram_bank] * 0x2000 + offset]; + else + return 0xff; +} + +WRITE8_MEMBER(gb_rom_device::write_ram) +{ + if (!m_ram.empty()) + m_ram[ram_bank_map[m_ram_bank] * 0x2000 + offset] = data; +} + + +// Tamagotchi + +READ8_MEMBER(gb_rom_tama5_device::read_rom) +{ + if (offset < 0x4000) + return m_rom[rom_bank_map[m_latch_bank] * 0x4000 + (offset & 0x3fff)]; + else + return m_rom[rom_bank_map[m_latch_bank2] * 0x4000 + (offset & 0x3fff)]; +} + +READ8_MEMBER(gb_rom_tama5_device::read_ram) +{ + return m_rtc_reg; +} + +WRITE8_MEMBER(gb_rom_tama5_device::write_ram) +{ + switch (offset & 0x0001) + { + case 0x0000: /* Write to data register */ + switch (m_tama5_cmd) + { + case 0x00: /* Bits 0-3 for rom bank selection */ + m_latch_bank2 = (m_latch_bank2 & 0xf0) | (data & 0x0f); + break; + case 0x01: /* Bit 4(-7?) for rom bank selection */ + m_latch_bank2 = (m_latch_bank2 & 0x0f) | ((data & 0x0f) << 4); + break; + case 0x04: /* Data to write lo */ + m_tama5_data = (m_tama5_data & 0xf0) | (data & 0x0f); + break; + case 0x05: /* Data to write hi */ + m_tama5_data = (m_tama5_data & 0x0f) | ((data & 0x0f) << 4); + break; + case 0x06: /* Address selection hi */ + m_tama5_addr = (m_tama5_addr & 0x0f) | ((data & 0x0f) << 4); + break; + case 0x07: /* Address selection lo */ + /* This address always seems to written last, so we'll just + execute the command here */ + m_tama5_addr = (m_tama5_addr & 0xf0) | (data & 0x0f); + switch (m_tama5_addr & 0xe0) + { + case 0x00: /* Write memory */ + //logerror( "Write tama5 memory 0x%02X <- 0x%02X\n", m_tama5_addr & 0x1f, m_tama5_data); + m_regs[m_tama5_addr & 0x1f] = m_tama5_data; + break; + case 0x20: /* Read memory */ + //logerror( "Read tama5 memory 0x%02X\n", m_tama5_addr & 0x1f); + m_tama5_data = m_regs[m_tama5_addr & 0x1f]; + break; + case 0x40: /* Unknown, some kind of read */ + if ((m_tama5_addr & 0x1f) == 0x12) + m_tama5_data = 0xff; + case 0x80: /* Unknown, some kind of read (when 07=01)/write (when 07=00/02) */ + default: + logerror( "0x%04X: Unknown addressing mode\n", space.device() .safe_pc( ) ); + break; + } + break; + } + break; + case 0x0001: /* Write to control register */ + switch (data) + { + case 0x00: /* Bits 0-3 for rom bank selection */ + case 0x01: /* Bits 4-7 for rom bank selection */ + case 0x04: /* Data write register lo */ + case 0x05: /* Data write register hi */ + case 0x06: /* Address register hi */ + case 0x07: /* Address register lo */ + break; + case 0x0a: /* Are we ready for the next command? */ + m_rtc_reg = 0x01; + break; + case 0x0c: /* Data read register lo */ + m_rtc_reg = m_tama5_data & 0x0f; + break; + case 0x0d: /* Data read register hi */ + m_rtc_reg = (m_tama5_data & 0xf0) >> 4; + break; + default: + logerror( "0x%04X: Unknown tama5 command 0x%02X\n", space.device() .safe_pc( ), data ); + break; + } + m_tama5_cmd = data; + break; + } +} + + +// Wisdom Tree + +READ8_MEMBER(gb_rom_wisdom_device::read_rom) +{ + return m_rom[rom_bank_map[m_latch_bank] * 0x4000 + offset]; +} + +WRITE8_MEMBER(gb_rom_wisdom_device::write_bank) +{ + if (offset < 0x4000) + m_latch_bank = (offset << 1) & 0x1ff; +} + + +// Yong Yong pirate + +READ8_MEMBER(gb_rom_yong_device::read_rom) +{ + if (offset < 0x4000) + return m_rom[rom_bank_map[m_latch_bank] * 0x4000 + (offset & 0x3fff)]; + else + return m_rom[rom_bank_map[m_latch_bank2] * 0x4000 + (offset & 0x3fff)]; +} + +WRITE8_MEMBER(gb_rom_yong_device::write_bank) +{ + if (offset == 0x2000) + m_latch_bank2 = data; +} + + +// ATV Racin pirate (incomplete) + +READ8_MEMBER(gb_rom_atvrac_device::read_rom) +{ + if (offset < 0x4000) + return m_rom[rom_bank_map[m_latch_bank] * 0x4000 + (offset & 0x3fff)]; + else + return m_rom[rom_bank_map[m_latch_bank2] * 0x4000 + (offset & 0x3fff)]; +} + +WRITE8_MEMBER(gb_rom_atvrac_device::write_bank) +{ + if (offset == 0x3f00) + { + if (data == 0) + data = 1; + m_latch_bank2 = m_latch_bank | data; + } + if (offset == 0x3fc0) + m_latch_bank = data * 16; +} + +// La Sa Ma pirate (incomplete) + +READ8_MEMBER(gb_rom_lasama_device::read_rom) +{ + if (offset < 0x4000) + return m_rom[rom_bank_map[m_latch_bank] * 0x4000 + (offset & 0x3fff)]; + else + return m_rom[rom_bank_map[m_latch_bank2] * 0x4000 + (offset & 0x3fff)]; +} + +WRITE8_MEMBER(gb_rom_lasama_device::write_bank) +{ + if (offset == 0x2080) + { + // Actual banking? + m_latch_bank2 = m_latch_bank | (data & 0x03); + } + if (offset == 0x6000) + { + // On boot the following two get written right after each other: + // 02 + // BE + // Disable logo switching? + if (!(data & 0x80)) + m_latch_bank = (data & 0x02) << 1; + } +} + + +// MegaDuck carts + +READ8_MEMBER(megaduck_rom_device::read_rom) +{ + if (offset < 0x4000) + return m_rom[rom_bank_map[m_latch_bank] * 0x4000 + (offset & 0x3fff)]; + else + return m_rom[rom_bank_map[m_latch_bank2] * 0x4000 + (offset & 0x3fff)]; +} + +WRITE8_MEMBER(megaduck_rom_device::write_bank) +{ + if (offset == 0x0001) + m_latch_bank2 = data; +} + +WRITE8_MEMBER(megaduck_rom_device::write_ram) +{ + m_latch_bank = data * 2; + m_latch_bank2 = data * 2 + 1; +} diff --git a/src/devices/bus/gameboy/rom.h b/src/devices/bus/gameboy/rom.h new file mode 100644 index 00000000000..3bd27a362c8 --- /dev/null +++ b/src/devices/bus/gameboy/rom.h @@ -0,0 +1,146 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli, Wilbert Pol +#ifndef __GB_ROM_H +#define __GB_ROM_H + +#include "gb_slot.h" + + +// ======================> gb_rom_device + +class gb_rom_device : public device_t, + public device_gb_cart_interface +{ +public: + // construction/destruction + gb_rom_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + gb_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start() { shared_start(); }; + virtual void device_reset() { shared_reset(); }; + + void shared_start(); + void shared_reset(); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_rom); + virtual DECLARE_READ8_MEMBER(read_ram); + virtual DECLARE_WRITE8_MEMBER(write_ram); +}; + +// ======================> gb_rom_tama5_device +class gb_rom_tama5_device : public gb_rom_device +{ +public: + // construction/destruction + gb_rom_tama5_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_rom); + virtual DECLARE_READ8_MEMBER(read_ram); + virtual DECLARE_WRITE8_MEMBER(write_ram); + UINT16 m_tama5_data, m_tama5_addr, m_tama5_cmd; + UINT8 m_regs[32]; + UINT8 m_rtc_reg; +}; + +// ======================> gb_rom_wisdom_device +class gb_rom_wisdom_device : public gb_rom_device +{ +public: + // construction/destruction + gb_rom_wisdom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start() { shared_start(); }; + virtual void device_reset() { shared_reset(); }; + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_rom); + virtual DECLARE_WRITE8_MEMBER(write_bank); +}; + +// ======================> gb_rom_yong_device +class gb_rom_yong_device : public gb_rom_device +{ +public: + // construction/destruction + gb_rom_yong_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start() { shared_start(); }; + virtual void device_reset() { shared_reset(); }; + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_rom); + virtual DECLARE_WRITE8_MEMBER(write_bank); +}; + +// ======================> gb_rom_atvrac_device +class gb_rom_atvrac_device : public gb_rom_device +{ +public: + // construction/destruction + gb_rom_atvrac_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start() { shared_start(); }; + virtual void device_reset() { shared_reset(); }; + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_rom); + virtual DECLARE_WRITE8_MEMBER(write_bank); +}; + +// ======================> gb_rom_lasama_device +class gb_rom_lasama_device : public gb_rom_device +{ +public: + // construction/destruction + gb_rom_lasama_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start() { shared_start(); }; + virtual void device_reset() { shared_reset(); }; + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_rom); + virtual DECLARE_WRITE8_MEMBER(write_bank); +}; + + +// ======================> megaduck_rom_device +class megaduck_rom_device :public device_t, + public device_gb_cart_interface +{ +public: + // construction/destruction + megaduck_rom_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + megaduck_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_rom); + virtual DECLARE_WRITE8_MEMBER(write_bank); + virtual DECLARE_WRITE8_MEMBER(write_ram); +}; + +// device type definition +extern const device_type GB_STD_ROM; +extern const device_type GB_ROM_TAMA5; +extern const device_type GB_ROM_WISDOM; +extern const device_type GB_ROM_YONG; +extern const device_type GB_ROM_ATVRAC; +extern const device_type GB_ROM_LASAMA; + +extern const device_type MEGADUCK_ROM; + +#endif diff --git a/src/devices/bus/gamegear/ggext.c b/src/devices/bus/gamegear/ggext.c new file mode 100644 index 00000000000..7419ec1d45a --- /dev/null +++ b/src/devices/bus/gamegear/ggext.c @@ -0,0 +1,120 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/********************************************************************** + + Sega Game Gear EXT port emulation + Also known as Gear-to-Gear (or VS, in Japan) cable connector + +**********************************************************************/ + +#include "ggext.h" +// slot devices +#include "smsctrladp.h" + + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type GG_EXT_PORT = &device_creator; + + + +//************************************************************************** +// CARD INTERFACE +//************************************************************************** + +//------------------------------------------------- +// device_gg_ext_port_interface - constructor +//------------------------------------------------- + +device_gg_ext_port_interface::device_gg_ext_port_interface(const machine_config &mconfig, device_t &device) + : device_slot_card_interface(mconfig,device) +{ + m_port = dynamic_cast(device.owner()); +} + + +//------------------------------------------------- +// ~device_gg_ext_port_interface - destructor +//------------------------------------------------- + +device_gg_ext_port_interface::~device_gg_ext_port_interface() +{ +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// gg_ext_port_device - constructor +//------------------------------------------------- + +gg_ext_port_device::gg_ext_port_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, GG_EXT_PORT, "EXT Port", tag, owner, clock, "gg_ext_port", __FILE__), + device_slot_interface(mconfig, *this), + m_th_pin_handler(*this), + m_pixel_handler(*this) +{ +} + + +//------------------------------------------------- +// gg_ext_port_device - destructor +//------------------------------------------------- + +gg_ext_port_device::~gg_ext_port_device() +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void gg_ext_port_device::device_start() +{ + m_device = dynamic_cast(get_card_device()); + + m_th_pin_handler.resolve_safe(); + m_pixel_handler.resolve_safe(0); +} + + +UINT8 gg_ext_port_device::port_r() +{ + UINT8 data = 0xff; + if (m_device) + data = m_device->peripheral_r(); + return data; +} + +void gg_ext_port_device::port_w( UINT8 data ) +{ + if (m_device) + m_device->peripheral_w(data); +} + + +void gg_ext_port_device::th_pin_w(int state) +{ + m_th_pin_handler(state); +} + +UINT32 gg_ext_port_device::pixel_r() +{ + return m_pixel_handler(); +} + + +//------------------------------------------------- +// SLOT_INTERFACE( gg_ext_port_devices ) +//------------------------------------------------- + +SLOT_INTERFACE_START( gg_ext_port_devices ) + SLOT_INTERFACE("smsctrladp", SMS_CTRL_ADAPTOR) +SLOT_INTERFACE_END diff --git a/src/devices/bus/gamegear/ggext.h b/src/devices/bus/gamegear/ggext.h new file mode 100644 index 00000000000..a3110dea711 --- /dev/null +++ b/src/devices/bus/gamegear/ggext.h @@ -0,0 +1,122 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/********************************************************************** + + Sega Game Gear EXT port emulation + Also known as Gear-to-Gear (or VS, in Japan) cable connector + +********************************************************************** + + +**********************************************************************/ + +#pragma once + +#ifndef __GG_EXT_PORT__ +#define __GG_EXT_PORT__ + +#include "emu.h" + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_GG_EXT_PORT_ADD(_tag, _slot_intf, _def_slot) \ + MCFG_DEVICE_ADD(_tag, GG_EXT_PORT, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) +#define MCFG_GG_EXT_PORT_MODIFY(_tag) \ + MCFG_DEVICE_MODIFY(_tag) + + +#define MCFG_GG_EXT_PORT_TH_INPUT_HANDLER(_devcb) \ + devcb = &gg_ext_port_device::set_th_input_handler(*device, DEVCB_##_devcb); + + +#define MCFG_GG_EXT_PORT_PIXEL_HANDLER(_devcb) \ + devcb = &gg_ext_port_device::set_pixel_handler(*device, DEVCB_##_devcb); + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> gg_ext_port_device + +class device_gg_ext_port_interface; + +class gg_ext_port_device : public device_t, + public device_slot_interface +{ +public: + // construction/destruction + gg_ext_port_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual ~gg_ext_port_device(); + + // static configuration helpers + template static devcb_base &set_th_input_handler(device_t &device, _Object object) { return downcast(device).m_th_pin_handler.set_callback(object); } + + template static devcb_base &set_pixel_handler(device_t &device, _Object object) { return downcast(device).m_pixel_handler.set_callback(object); } + + // Currently, only the support for SMS Controller Adaptor is emulated, + // for when SMS Compatibility mode is enabled. In that mode, the 10 pins + // of the EXT port follows the same numbering of a SMS Control port. + + // Data returned by the port_r methods: + // bit 0 - pin 1 - Up + // bit 1 - pin 2 - Down + // bit 2 - pin 3 - Left + // bit 3 - pin 4 - Right + // bit 4 - pin 5 - Vcc (no data) + // bit 5 - pin 6 - TL (Button 1/Light Phaser Trigger) + // bit 6 - pin 7 - TH (Light Phaser sensor) + // pin 8 - GND + // bit 7 - pin 9 - TR (Button 2) + // pin 10 - Not connected + // + UINT8 port_r(); + void port_w( UINT8 data ); + + void th_pin_w(int state); + UINT32 pixel_r(); + +//protected: + // device-level overrides + virtual void device_start(); + + device_gg_ext_port_interface *m_device; + +private: + devcb_write_line m_th_pin_handler; + devcb_read32 m_pixel_handler; +}; + + +// ======================> device_gg_ext_port_interface + +// class representing interface-specific live sms_expansion card +class device_gg_ext_port_interface : public device_slot_card_interface +{ +public: + // construction/destruction + device_gg_ext_port_interface(const machine_config &mconfig, device_t &device); + virtual ~device_gg_ext_port_interface(); + + virtual UINT8 peripheral_r() { return 0xff; }; + virtual void peripheral_w(UINT8 data) { }; + +protected: + gg_ext_port_device *m_port; +}; + + +// device type definition +extern const device_type GG_EXT_PORT; + + +SLOT_INTERFACE_EXTERN( gg_ext_port_devices ); + + +#endif diff --git a/src/devices/bus/gamegear/smsctrladp.c b/src/devices/bus/gamegear/smsctrladp.c new file mode 100644 index 00000000000..54b9139b433 --- /dev/null +++ b/src/devices/bus/gamegear/smsctrladp.c @@ -0,0 +1,94 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/********************************************************************** + + Sega Game Gear "SMS Controller Adaptor" emulation + Also known as "Master Link" cable. + +**********************************************************************/ + +#include "smsctrladp.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type SMS_CTRL_ADAPTOR = &device_creator; + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// sms_ctrl_adaptor_device - constructor +//------------------------------------------------- + +sms_ctrl_adaptor_device::sms_ctrl_adaptor_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, SMS_CTRL_ADAPTOR, "SMS Controller Adaptor", tag, owner, clock, "sms_ctrl_adaptor", __FILE__), + device_gg_ext_port_interface(mconfig, *this), + m_subctrl_port(*this, "ctrl") +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void sms_ctrl_adaptor_device::device_start() +{ + m_subctrl_port->device_start(); +} + + +//------------------------------------------------- +// sms_peripheral_r - rapid fire read +//------------------------------------------------- + +UINT8 sms_ctrl_adaptor_device::peripheral_r() +{ + return m_subctrl_port->port_r(); +} + + +//------------------------------------------------- +// sms_peripheral_w - rapid fire write +//------------------------------------------------- + +void sms_ctrl_adaptor_device::peripheral_w(UINT8 data) +{ + m_subctrl_port->port_w(data); +} + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +WRITE_LINE_MEMBER( sms_ctrl_adaptor_device::th_pin_w ) +{ + m_port->th_pin_w(state); +} + + +READ32_MEMBER( sms_ctrl_adaptor_device::pixel_r ) +{ + return m_port->pixel_r(); +} + + +static MACHINE_CONFIG_FRAGMENT( sms_adp_slot ) + MCFG_SMS_CONTROL_PORT_ADD("ctrl", sms_control_port_devices, "joypad") + MCFG_SMS_CONTROL_PORT_TH_INPUT_HANDLER(WRITELINE(sms_ctrl_adaptor_device, th_pin_w)) + MCFG_SMS_CONTROL_PORT_PIXEL_HANDLER(READ32(sms_ctrl_adaptor_device, pixel_r)) +MACHINE_CONFIG_END + + +machine_config_constructor sms_ctrl_adaptor_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( sms_adp_slot ); +} diff --git a/src/devices/bus/gamegear/smsctrladp.h b/src/devices/bus/gamegear/smsctrladp.h new file mode 100644 index 00000000000..76c629f4dd8 --- /dev/null +++ b/src/devices/bus/gamegear/smsctrladp.h @@ -0,0 +1,56 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/********************************************************************** + + Sega Game Gear "SMS Controller Adaptor" emulation + Also known as "Master Link" cable. + +**********************************************************************/ + +#pragma once + +#ifndef __SMS_CTRL_ADAPTOR__ +#define __SMS_CTRL_ADAPTOR__ + + +#include "emu.h" +#include "ggext.h" +#include "bus/sms_ctrl/smsctrl.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> sms_ctrl_adaptor_device + +class sms_ctrl_adaptor_device : public device_t, + public device_gg_ext_port_interface +{ +public: + // construction/destruction + sms_ctrl_adaptor_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + DECLARE_WRITE_LINE_MEMBER(th_pin_w); + DECLARE_READ32_MEMBER(pixel_r); + +protected: + // device-level overrides + virtual void device_start(); + virtual machine_config_constructor device_mconfig_additions() const; + + // device_gg_ext_port_interface overrides + virtual UINT8 peripheral_r(); + virtual void peripheral_w(UINT8 data); + +private: + required_device m_subctrl_port; +}; + + +// device type definition +extern const device_type SMS_CTRL_ADAPTOR; + + +#endif diff --git a/src/devices/bus/gba/gba_slot.c b/src/devices/bus/gba/gba_slot.c new file mode 100644 index 00000000000..8844acbccb5 --- /dev/null +++ b/src/devices/bus/gba/gba_slot.c @@ -0,0 +1,465 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont,Ryan Holtz,Fabio Priuli +/*********************************************************************************************************** + + + Game Boy Advance cart emulation + (through slot devices) + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "gba_slot.h" + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type GBA_CART_SLOT = &device_creator; + +//************************************************************************** +// GBA cartridges Interface +//************************************************************************** + +//------------------------------------------------- +// device_gba_cart_interface - constructor +//------------------------------------------------- + +device_gba_cart_interface::device_gba_cart_interface(const machine_config &mconfig, device_t &device) + : device_slot_card_interface(mconfig, device), + m_rom(NULL), + m_rom_size(0) +{ +} + + +//------------------------------------------------- +// ~device_gba_cart_interface - destructor +//------------------------------------------------- + +device_gba_cart_interface::~device_gba_cart_interface() +{ +} + +//------------------------------------------------- +// rom_alloc - alloc the space for the cart +//------------------------------------------------- + +void device_gba_cart_interface::rom_alloc(UINT32 size, const char *tag) +{ + if (m_rom == NULL) + { + // we always alloc 32MB of rom region! + m_rom = (UINT32 *)device().machine().memory().region_alloc(std::string(tag).append(GBASLOT_ROM_REGION_TAG).c_str(), 0x2000000, 4, ENDIANNESS_LITTLE)->base(); + m_rom_size = size; + } +} + + +//------------------------------------------------- +// nvram_alloc - alloc the space for the ram +//------------------------------------------------- + +void device_gba_cart_interface::nvram_alloc(UINT32 size) +{ + m_nvram.resize(size/sizeof(UINT32)); +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// gba_cart_slot_device - constructor +//------------------------------------------------- +gba_cart_slot_device::gba_cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, GBA_CART_SLOT, "Game Boy Advance Cartridge Slot", tag, owner, clock, "gba_cart_slot", __FILE__), + device_image_interface(mconfig, *this), + device_slot_interface(mconfig, *this), + m_type(GBA_STD) +{ +} + + +//------------------------------------------------- +// gba_cart_slot_device - destructor +//------------------------------------------------- + +gba_cart_slot_device::~gba_cart_slot_device() +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void gba_cart_slot_device::device_start() +{ + m_cart = dynamic_cast(get_card_device()); +} + +//------------------------------------------------- +// device_config_complete - perform any +// operations now that the configuration is +// complete +//------------------------------------------------- + +void gba_cart_slot_device::device_config_complete() +{ + // set brief and instance name + update_names(); +} + + +//------------------------------------------------- +// GBA PCB +//------------------------------------------------- + +struct gba_slot +{ + int pcb_id; + const char *slot_option; +}; + +// Here, we take the feature attribute from .xml (i.e. the PCB name) and we assign a unique ID to it +static const gba_slot slot_list[] = +{ + { GBA_STD, "gba_rom" }, + { GBA_SRAM, "gba_sram" }, + { GBA_EEPROM, "gba_eeprom" }, + { GBA_EEPROM4, "gba_eeprom_4k" }, + { GBA_EEPROM64, "gba_eeprom_64k" }, + { GBA_FLASH, "gba_flash" }, + { GBA_FLASH512, "gba_flash_512" }, + { GBA_FLASH1M, "gba_flash_1m" }, +}; + +static int gba_get_pcb_id(const char *slot) +{ + for (int i = 0; i < ARRAY_LENGTH(slot_list); i++) + { + if (!core_stricmp(slot_list[i].slot_option, slot)) + return slot_list[i].pcb_id; + } + + return 0; +} + +static const char *gba_get_slot(int type) +{ + for (int i = 0; i < ARRAY_LENGTH(slot_list); i++) + { + if (slot_list[i].pcb_id == type) + return slot_list[i].slot_option; + } + + return "gba_rom"; +} + + +/*------------------------------------------------- + call load + -------------------------------------------------*/ + +bool gba_cart_slot_device::call_load() +{ + if (m_cart) + { + UINT8 *ROM; + UINT32 size = (software_entry() != NULL) ? get_software_region_length("rom") : length(); + if (size > 0x2000000) + { + seterror(IMAGE_ERROR_UNSPECIFIED, "Attempted loading a cart larger than 32MB"); + return IMAGE_INIT_FAIL; + } + + m_cart->rom_alloc(size, tag()); + ROM = (UINT8 *)m_cart->get_rom_base(); + + if (software_entry() == NULL) + { + fread(ROM, size); + m_type = get_cart_type(ROM, size); + } + else + { + const char *pcb_name = get_feature("slot"); + + memcpy(ROM, get_software_region("rom"), size); + + if (pcb_name) + m_type = gba_get_pcb_id(pcb_name); + + //printf("Type: %s\n", gba_get_slot(m_type)); + + osd_printf_info("GBA: Detected (XML) %s\n", pcb_name ? pcb_name : "NONE"); + } + + if (m_type == GBA_SRAM) + m_cart->nvram_alloc(0x10000); + + // mirror the ROM + switch (size) + { + case 2 * 1024 * 1024: + memcpy(ROM + 0x200000, ROM, 0x200000); + // intentional fall-through + case 4 * 1024 * 1024: + memcpy(ROM + 0x400000, ROM, 0x400000); + // intentional fall-through + case 8 * 1024 * 1024: + memcpy(ROM + 0x800000, ROM, 0x800000); + // intentional fall-through + case 16 * 1024 * 1024: + memcpy(ROM + 0x1000000, ROM, 0x1000000); + break; + } + + if (m_cart->get_nvram_size()) + battery_load(m_cart->get_nvram_base(), m_cart->get_nvram_size(), 0x00); + + return IMAGE_INIT_PASS; + } + + return IMAGE_INIT_PASS; +} + + +/*------------------------------------------------- + call_unload + -------------------------------------------------*/ + +void gba_cart_slot_device::call_unload() +{ + if (m_cart && m_cart->get_nvram_size()) + battery_save(m_cart->get_nvram_base(), m_cart->get_nvram_size()); +} + + + +/*------------------------------------------------- + call softlist load + -------------------------------------------------*/ + +bool gba_cart_slot_device::call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry) +{ + load_software_part_region(*this, swlist, swname, start_entry); + return TRUE; +} + + + +/*------------------------------------------------- + get_cart_type - code to detect NVRAM type from + fullpath + -------------------------------------------------*/ + +INLINE std::string gba_chip_string( UINT32 chip ) +{ + std::string str; + if (chip == 0) str += "NONE "; + if (chip & GBA_CHIP_EEPROM) str += "EEPROM "; + if (chip & GBA_CHIP_EEPROM_64K) str += "EEPROM_64K "; + if (chip & GBA_CHIP_EEPROM_4K) str += "EEPROM_4K "; + if (chip & GBA_CHIP_FLASH) str += "FLASH "; + if (chip & GBA_CHIP_FLASH_1M) str += "FLASH_1M "; + if (chip & GBA_CHIP_FLASH_512) str += "FLASH_512 "; + if (chip & GBA_CHIP_SRAM) str += "SRAM "; + if (chip & GBA_CHIP_RTC) str += "RTC "; + strtrimspace(str); + return str; +} + + +INLINE int gba_chip_has_conflict( UINT32 chip ) +{ + int count1 = 0, count2 = 0; + if (chip & GBA_CHIP_EEPROM) count1++; + if (chip & GBA_CHIP_EEPROM_4K) count1++; + if (chip & GBA_CHIP_EEPROM_64K) count1++; + if (chip & GBA_CHIP_FLASH) count2++; + if (chip & GBA_CHIP_FLASH_1M) count2++; + if (chip & GBA_CHIP_FLASH_512) count2++; + if (chip & GBA_CHIP_SRAM) count2++; + return (count1 + count2) > 1; // if EEPROM + FLASH or EEPROM + SRAM carts exist, change to "(count1 > 1) || (count2 > 1)" +} + + +int gba_cart_slot_device::get_cart_type(UINT8 *ROM, UINT32 len) +{ + UINT32 chip = 0; + int type = GBA_STD; + + // first detect nvram type based on strings inside the file + for (int i = 0; i < len; i++) + { + if (!memcmp(&ROM[i], "EEPROM_V", 8)) + chip |= GBA_CHIP_EEPROM; // should be either GBA_CHIP_EEPROM_4K or GBA_CHIP_EEPROM_64K, but it is not yet possible to automatically detect which one + else if ((!memcmp(&ROM[i], "SRAM_V", 6)) || (!memcmp(&ROM[i], "SRAM_F_V", 8))) // || (!memcmp(&data[i], "ADVANCEWARS", 11))) //advance wars 1 & 2 has SRAM, but no "SRAM_" string can be found inside the ROM space + chip |= GBA_CHIP_SRAM; + else if (!memcmp(&ROM[i], "FLASH1M_V", 9)) + chip |= GBA_CHIP_FLASH_1M; + else if (!memcmp(&ROM[i], "FLASH512_V", 10)) + chip |= GBA_CHIP_FLASH_512; + else if (!memcmp(&ROM[i], "FLASH_V", 7)) + chip |= GBA_CHIP_FLASH; + else if (!memcmp(&ROM[i], "SIIRTC_V", 8)) + chip |= GBA_CHIP_RTC; + } + osd_printf_info("GBA: Detected (ROM) %s\n", gba_chip_string(chip).c_str()); + + // fix for games which return more than one kind of chip: either it is one of the known titles, or we default to no battery + if (gba_chip_has_conflict(chip)) + { + char game_code[5] = { 0 }; + bool resolved = FALSE; + + if (len >= 0xac + 4) + memcpy(game_code, ROM + 0xac, 4); + + osd_printf_info("GBA: Game Code \"%s\"\n", game_code); + + chip &= ~(GBA_CHIP_EEPROM | GBA_CHIP_EEPROM_4K | GBA_CHIP_EEPROM_64K | GBA_CHIP_FLASH | GBA_CHIP_FLASH_1M | GBA_CHIP_FLASH_512 | GBA_CHIP_SRAM); + + // search if it is one of the known titles with NVRAM conflicts + for (int i = 0; i < sizeof(gba_chip_fix_conflict_list) / sizeof(gba_chip_fix_conflict_item); i++) + { + const gba_chip_fix_conflict_item *item = &gba_chip_fix_conflict_list[i]; + if (!strcmp(game_code, item->game_code)) + { + chip |= item->chip; + resolved = TRUE; + break; + } + } + if (!resolved) + osd_printf_warning("GBA: NVRAM is disabled because multiple NVRAM chips were detected!\n"); + } + + // fix for games which are known to require an eeprom with 14-bit addressing (64 kbit) + if (chip & GBA_CHIP_EEPROM) + { + char game_code[5] = { 0 }; + + if (len >= 0xac + 4) + memcpy(game_code, ROM + 0xac, 4); + + osd_printf_info("GBA: Game Code \"%s\"\n", game_code); + + for (int i = 0; i < sizeof(gba_chip_fix_eeprom_list) / sizeof(gba_chip_fix_eeprom_item); i++) + { + const gba_chip_fix_eeprom_item *item = &gba_chip_fix_eeprom_list[i]; + if (!strcmp(game_code, item->game_code)) + { + chip = (chip & ~GBA_CHIP_EEPROM) | GBA_CHIP_EEPROM_64K; + break; + } + } + } + + if (chip & GBA_CHIP_RTC) + { + osd_printf_info("game has RTC - not emulated at the moment\n"); + chip &= ~GBA_CHIP_RTC; + } + + osd_printf_info("GBA: Emulate %s\n", gba_chip_string(chip).c_str()); + + switch (chip) + { + case GBA_CHIP_SRAM: + type = GBA_SRAM; + break; + case GBA_CHIP_EEPROM: + type = GBA_EEPROM; + break; + case GBA_CHIP_EEPROM_4K: + type = GBA_EEPROM4; + break; + case GBA_CHIP_EEPROM_64K: + type = GBA_EEPROM64; + break; + case GBA_CHIP_FLASH: + type = GBA_FLASH; + break; + case GBA_CHIP_FLASH_512: + type = GBA_FLASH512; + break; + case GBA_CHIP_FLASH_1M: + type = GBA_FLASH1M; + break; + default: + break; + } + + return type; +} +/*------------------------------------------------- + get default card software + -------------------------------------------------*/ + +void gba_cart_slot_device::get_default_card_software(std::string &result) +{ + if (open_image_file(mconfig().options())) + { + const char *slot_string = "gba_rom"; + UINT32 len = core_fsize(m_file); + dynamic_buffer rom(len); + int type; + + core_fread(m_file, &rom[0], len); + + type = get_cart_type(&rom[0], len); + slot_string = gba_get_slot(type); + + //printf("type: %s\n", slot_string); + clear(); + + result.assign(slot_string); + return; + } + + software_get_default_slot(result, "gba_rom"); +} + +/*------------------------------------------------- + read + -------------------------------------------------*/ + +READ32_MEMBER(gba_cart_slot_device::read_rom) +{ + if (m_cart) + return m_cart->read_rom(space, offset, mem_mask); + else + return 0xffffffff; +} + +READ32_MEMBER(gba_cart_slot_device::read_ram) +{ + if (m_cart) + return m_cart->read_ram(space, offset, mem_mask); + else + return 0xffffffff; +} + + +/*------------------------------------------------- + write + -------------------------------------------------*/ + +WRITE32_MEMBER(gba_cart_slot_device::write_ram) +{ + if (m_cart) + m_cart->write_ram(space, offset, data, mem_mask); +} + + +/*------------------------------------------------- + Internal header logging + -------------------------------------------------*/ + +void gba_cart_slot_device::internal_header_logging(UINT8 *ROM, UINT32 len) +{ +} diff --git a/src/devices/bus/gba/gba_slot.h b/src/devices/bus/gba/gba_slot.h new file mode 100644 index 00000000000..05181d29d4c --- /dev/null +++ b/src/devices/bus/gba/gba_slot.h @@ -0,0 +1,583 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont,Ryan Holtz,Fabio Priuli +#ifndef __GBA_SLOT_H +#define __GBA_SLOT_H + +/*************************************************************************** + TYPE DEFINITIONS + ***************************************************************************/ + + +/* PCB */ +enum +{ + GBA_STD = 0, + GBA_SRAM, + GBA_EEPROM, + GBA_EEPROM4, + GBA_EEPROM64, + GBA_FLASH, + GBA_FLASH512, + GBA_FLASH1M +}; + + +// ======================> device_gba_cart_interface + +class device_gba_cart_interface : public device_slot_card_interface +{ +public: + // construction/destruction + device_gba_cart_interface(const machine_config &mconfig, device_t &device); + virtual ~device_gba_cart_interface(); + + // reading and writing + virtual DECLARE_READ32_MEMBER(read_rom) { return 0xffffffff; } + virtual DECLARE_READ32_MEMBER(read_ram) { return 0xffffffff; } + virtual DECLARE_WRITE32_MEMBER(write_ram) {}; + + void rom_alloc(UINT32 size, const char *tag); + void nvram_alloc(UINT32 size); + UINT32* get_rom_base() { return m_rom; } + UINT32* get_nvram_base() { return &m_nvram[0]; } + UINT32 get_rom_size() { return m_rom_size; } + UINT32 get_nvram_size() { return m_nvram.size()*sizeof(UINT32); } + void set_rom_size(UINT32 val) { m_rom_size = val; } + + void save_nvram() { device().save_item(NAME(m_nvram)); } + + // internal state + UINT32 *m_rom; // this points to the cart rom region + UINT32 m_rom_size; // this is the actual game size, not the rom region size! + std::vector m_nvram; +}; + + +// ======================> gba_cart_slot_device + +class gba_cart_slot_device : public device_t, + public device_image_interface, + public device_slot_interface +{ +public: + // construction/destruction + gba_cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual ~gba_cart_slot_device(); + + // device-level overrides + virtual void device_start(); + virtual void device_config_complete(); + + // image-level overrides + virtual bool call_load(); + virtual void call_unload(); + virtual bool call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry); + + int get_type() { return m_type; } + int get_cart_type(UINT8 *ROM, UINT32 len); + + void setup_ram(UINT8 banks); + void internal_header_logging(UINT8 *ROM, UINT32 len); + + void save_nvram() { if (m_cart && m_cart->get_nvram_size()) m_cart->save_nvram(); } + + virtual iodevice_t image_type() const { return IO_CARTSLOT; } + virtual bool is_readable() const { return 1; } + virtual bool is_writeable() const { return 0; } + virtual bool is_creatable() const { return 0; } + virtual bool must_be_loaded() const { return 0; } + virtual bool is_reset_on_load() const { return 1; } + virtual const option_guide *create_option_guide() const { return NULL; } + virtual const char *image_interface() const { return "gba_cart"; } + virtual const char *file_extensions() const { return "gba,bin"; } + + // slot interface overrides + virtual void get_default_card_software(std::string &result); + + // reading and writing + virtual DECLARE_READ32_MEMBER(read_rom); + virtual DECLARE_READ32_MEMBER(read_ram); + virtual DECLARE_WRITE32_MEMBER(write_ram); + + +protected: + + int m_type; + device_gba_cart_interface* m_cart; +}; + + + +// device type definition +extern const device_type GBA_CART_SLOT; + + +/*************************************************************************** + DEVICE CONFIGURATION MACROS + ***************************************************************************/ + +#define GBASLOT_ROM_REGION_TAG ":cart:rom" + +#define MCFG_GBA_CARTRIDGE_ADD(_tag,_slot_intf,_def_slot) \ + MCFG_DEVICE_ADD(_tag, GBA_CART_SLOT, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) + + + +//------------------------------------------------------------------------ +// +// Misc structs to attempt NVRAM identification when loading from fullpath +// +//------------------------------------------------------------------------ + + +#define GBA_CHIP_EEPROM (1 << 0) +#define GBA_CHIP_SRAM (1 << 1) +#define GBA_CHIP_FLASH (1 << 2) +#define GBA_CHIP_FLASH_1M (1 << 3) +#define GBA_CHIP_RTC (1 << 4) +#define GBA_CHIP_FLASH_512 (1 << 5) +#define GBA_CHIP_EEPROM_64K (1 << 6) +#define GBA_CHIP_EEPROM_4K (1 << 7) + + +struct gba_chip_fix_conflict_item +{ + char game_code[5]; + UINT32 chip; +}; + +static const gba_chip_fix_conflict_item gba_chip_fix_conflict_list[] = +{ + { "ABFJ", GBA_CHIP_SRAM }, // 0059 - Breath of Fire - Ryuu no Senshi (JPN) + { "AHMJ", GBA_CHIP_EEPROM_4K }, // 0364 - Dai-Mahjong (JPN) + { "A2GJ", GBA_CHIP_EEPROM_64K }, // 0399 - Advance GT2 (JPN) + { "AK9E", GBA_CHIP_EEPROM_4K }, // 0479 - Medabots AX - Rokusho Version (USA) + { "AK8E", GBA_CHIP_EEPROM_4K }, // 0480 - Medabots AX - Metabee Version (USA) + { "AK9P", GBA_CHIP_EEPROM_4K }, // 0515 - Medabots AX - Rokusho Version (EUR) + { "AGIJ", GBA_CHIP_EEPROM_4K }, // 0548 - Medarot G - Kuwagata Version (JPN) + { "A3DJ", GBA_CHIP_EEPROM_4K }, // 0567 - Disney Sports - American Football (JPN) + { "AF7J", GBA_CHIP_EEPROM_64K }, // 0605 - Tokimeki Yume Series 1 - Ohanaya-san ni Narou! (JPN) + { "AH7J", GBA_CHIP_EEPROM_64K }, // 0617 - Nakayoshi Pet Advance Series 1 - Kawaii Hamster (JPN) + { "AGHJ", GBA_CHIP_EEPROM_4K }, // 0620 - Medarot G - Kabuto Version (JPN) + { "AR8E", GBA_CHIP_SRAM }, // 0727 - Rocky (USA) + { "ALUE", GBA_CHIP_EEPROM_4K }, // 0751 - Super Monkey Ball Jr. (USA) + { "A3DE", GBA_CHIP_EEPROM_4K }, // 0800 - Disney Sports - Football (USA) + { "A87J", GBA_CHIP_EEPROM_64K }, // 0817 - Ohanaya-San Monogatari GBA (JPN) + { "A56J", GBA_CHIP_EEPROM_64K }, // 0827 - DokiDoki Cooking Series 1 - Komugi-chan no Happy Cake (JPN) + { "AUSJ", GBA_CHIP_FLASH }, // 0906 - One Piece - Mezase! King of Berries (JPN) + { "ANTJ", GBA_CHIP_SRAM }, // 0950 - Nippon Pro Mahjong Renmei Kounin - Tetsuman Advance (JPN) + { "A8OJ", GBA_CHIP_EEPROM_64K }, // 0988 - DokiDoki Cooking Series 2 - Gourmet Kitchen - Suteki na Obentou (JPN) + { "AK8P", GBA_CHIP_EEPROM_4K }, // 1022 - Medabots AX - Metabee Version (EUR) + { "A6OJ", GBA_CHIP_EEPROM_64K }, // 1092 - Onimusha Tactics (JPN) + { "A6OE", GBA_CHIP_EEPROM_64K }, // 1241 - Onimusha Tactics (USA) + { "A6OP", GBA_CHIP_EEPROM_64K }, // 1288 - Onimusha Tactics (EUR) + { "BKME", GBA_CHIP_EEPROM_4K }, // 1545 - Kim Possible 2 - Drakken's Demise (USA) + { "BDKJ", GBA_CHIP_EEPROM_64K }, // 1555 - Digi Communication 2 in 1 Datou! Black Gemagema Dan (JPN) + { "BR4J", GBA_CHIP_FLASH }, // 1586 - Rockman EXE 4.5 - Real Operation (JPN) + { "BG8J", GBA_CHIP_EEPROM_64K }, // 1853 - Ganbare! Dodge Fighters (JPN) + { "AROP", GBA_CHIP_EEPROM_4K }, // 1862 - Rocky (EUR) +// "A2YE" - 1906 - Top Gun - Combat Zones (USA) - multiple NVRAM chips detected, but none present (protection against emu?) + { "BKMJ", GBA_CHIP_EEPROM_4K }, // 2039 - Kim Possible (JPN) + { "BKEJ", GBA_CHIP_EEPROM_64K }, // 2047 - Konjiki no Gashbell - The Card Battle for GBA (JPN) + { "BKMP", GBA_CHIP_EEPROM_4K }, // 2297 - Kim Possible 2 - Drakken's Demise (EUR) + { "BUHJ", GBA_CHIP_EEPROM_4K }, // 2311 - Ueki no Housoku Shinki Sakuretsu! Nouryokumono Battle (JPN) + { "BYUJ", GBA_CHIP_EEPROM_64K }, // 2322 - Yggdra Union (JPN) +}; + +struct gba_chip_fix_eeprom_item +{ + char game_code[5]; +}; + +static const gba_chip_fix_eeprom_item gba_chip_fix_eeprom_list[] = +{ + // gba scan no. 7 + { "AKTJ" }, // 0145 - Hello Kitty Collection - Miracle Fashion Maker (JPN) + { "AISP" }, // 0185 - International Superstar Soccer (EUR) + { "AKGP" }, // 0204 - Mech Platoon (EUR) + { "AX2E" }, // 0207 - Dave Mirra Freestyle BMX 2 (USA) + { "AASJ" }, // 0234 - World Advance Soccer - Shouri heno Michi (JPN) + { "AA2J" }, // 0237 - Super Mario World - Super Mario Advance 2 (JPN) + { "AJWJ" }, // 0242 - Jikkyou World Soccer Pocket (JPN) + { "AABE" }, // 0244 - American Bass Challenge (USA) + { "AWXJ" }, // 0254 - ESPN Winter X-Games Snowboarding 2002 (JPN) + { "AALJ" }, // 0259 - Kidou Tenshi Angelic Layer - Misaki to Yume no Tenshi-tachi (JPN) + { "AKGE" }, // 0263 - Mech Platoon (USA) + { "AGLJ" }, // 0273 - Tomato Adventure (JPN) + { "AWIJ" }, // 0274 - Hyper Sports 2002 Winter (JPN) + { "APNJ" }, // 0286 - Pinky Monkey Town (JPN) + { "AA2E" }, // 0288 - Super Mario World - Super Mario Advance 2 (USA) + { "AX2P" }, // 0293 - Dave Mirra Freestyle BMX 2 (EUR) + { "AMGP" }, // 0296 - ESPN Great Outdoor Games - Bass Tournament (EUR) + { "AMHJ" }, // 0308 - Bomberman Max 2 - Bomberman Version (JPN) + { "AGNJ" }, // 0311 - Goemon - New Age Shutsudou! (JPN) + { "AMYJ" }, // 0324 - Bomberman Max 2 - Max Version (JPN) + { "AT3E" }, // 0326 - Tony Hawk's Pro Skater 3 (USA) + { "AHHE" }, // 0327 - High Heat - Major League Baseball 2003 (USA) + { "ANLE" }, // 0328 - NHL 2002 (USA) + { "AAGJ" }, // 0345 - Angelique (JPN) + { "ABJP" }, // 0351 - Broken Sword - The Shadow of the Templars (EUR) + { "AKVJ" }, // 0357 - K-1 Pocket Grand Prix (JPN) + { "AKGJ" }, // 0361 - Kikaika Guntai - Mech Platoon (JPN) + { "ADDJ" }, // 0362 - Diadroids World - Evil Teikoku no Yabou (JPN) + { "ABJE" }, // 0365 - Broken Sword - The Shadow of the Templars (USA) + { "AABP" }, // 0380 - Super Black Bass Advance (EUR) + { "AA2P" }, // 0390 - Super Mario World - Super Mario Advance 2 (EUR) + { "A2GJ" }, // 0399 - Advance GT2 (JPN) + { "AEWJ" }, // 0400 - Ui-Ire - World Soccer Winning Eleven (JPN) + { "ADPJ" }, // 0417 - Doraemon - Dokodemo Walker (JPN) + { "AN5J" }, // 0420 - Kawa no Nushi Tsuri 5 - Fushigi no Mori Kara (JPN) + { "ACBJ" }, // 0421 - Gekitou! Car Battler Go!! (JPN) + { "AHIJ" }, // 0426 - Hitsuji no Kimochi (JPN) + { "ATFP" }, // 0429 - Alex Ferguson's Player Manager 2002 (EUR) + { "AFUJ" }, // 0431 - Youkaidou (JPN) + { "AEPP" }, // 0435 - Sheep (EUR) + { "AMHE" }, // 0442 - Bomberman Max 2 - Blue Advance (USA) + { "AMYE" }, // 0443 - Bomberman Max 2 - Red Advance (USA) + { "AT3F" }, // 0457 - Tony Hawk's Pro Skater 3 (FRA) + { "ARJJ" }, // 0497 - Custom Robo GX (JPN) + { "AFCJ" }, // 0521 - RockMan & Forte (JPN) + { "ANJE" }, // 0528 - Madden NFL 2003 (USA) + { "AN7J" }, // 0533 - Famista Advance (JPN) + { "ATYJ" }, // 0540 - Gambler Densetsu Tetsuya - Yomigaeru Densetsu (JPN) + { "AXBJ" }, // 0551 - Black Matrix Zero (JPN) + { "A3AE" }, // 0580 - Yoshi's Island - Super Mario Advance 3 (USA) + { "A3AJ" }, // 0582 - Super Mario Advance 3 (JPN) + { "AZUJ" }, // 0595 - Street Fighter Zero 3 - Upper (JPN) + { "ALOE" }, // 0600 - The Lord of the Rings - The Fellowship of the Ring (USA) + { "A2SE" }, // 0602 - Spyro 2 - Season of Flame (USA) + { "AF7J" }, // 0605 - Tokimeki Yume Series 1 - Ohanaya-san ni Narou! (JPN) + { "A3AP" }, // 0610 - Yoshi's Island - Super Mario Advance 3 (EUR) + { "AH7J" }, // 0617 - Nakayoshi Pet Advance Series 1 - Kawaii Hamster (JPN) + { "AI7J" }, // 0618 - Nakayoshi Pet Advance Series 2 - Kawaii Koinu (JPN) + { "AN3J" }, // 0619 - Nakayoshi Pet Advance Series 3 - Kawaii Koneko (JPN) + { "AAPJ" }, // 0632 - Metalgun Slinger (JPN) + { "A2JJ" }, // 0643 - J.League - Winning Eleven Advance 2002 (JPN) + { "AHXJ" }, // 0649 - High Heat - Major League Baseball 2003 (JPN) + { "AHAJ" }, // 0651 - Hamster Paradise Advance (JPN) + { "APUJ" }, // 0653 - PukuPuku Tennen Kairanban (JPN) + { "A2SP" }, // 0673 - Spyro 2 - Season of Flame (EUR) + { "AN9J" }, // 0675 - Tales of the World - Narikiri Dungeon 2 (JPN) + { "ACBE" }, // 0683 - Car Battler Joe (USA) + { "AT6E" }, // 0693 - Tony Hawk's Pro Skater 4 (USA) + { "ALOP" }, // 0702 - The Lord of the Rings - The Fellowship of the Ring (EUR) + { "A63J" }, // 0710 - Kawaii Pet Shop Monogatari 3 (JPN) + { "AAXJ" }, // 0748 - Fantastic Maerchen - Cake-yasan Monogatari (JPN) + { "AZLE" }, // 0763 - The Legend of Zelda - A Link to the Past & Four Swords (USA) + { "AZUP" }, // 0765 - Street Fighter Alpha 3 - Upper (EUR) + { "AJKJ" }, // 0769 - Jikkyou World Soccer Pocket 2 (JPN) + { "AB3E" }, // 0781 - Dave Mirra Freestyle BMX 3 (USA) + { "A2IJ" }, // 0791 - Magi Nation (JPN) + { "AK7J" }, // 0792 - Klonoa Heroes - Densetsu no Star Medal (JPN) + { "A2HJ" }, // 0794 - Hajime no Ippo - The Fighting! (JPN) + { "ALNE" }, // 0795 - Lunar Legend (USA) + { "AUCJ" }, // 0808 - Uchuu Daisakusen Choco Vader - Uchuu Kara no Shinryakusha (JPN) + { "A59J" }, // 0809 - Toukon Heat (JPN) + { "ALJE" }, // 0815 - Sea Trader - Rise of Taipan (USA) + { "A87J" }, // 0817 - Ohanaya-San Monogatari GBA (JPN) + { "A56J" }, // 0827 - DokiDoki Cooking Series 1 - Komugi-chan no Happy Cake (JPN) + { "AHZJ" }, // 0830 - Higanbana (JPN) + { "A8BP" }, // 0832 - Medabots - Metabee Version (EUR) + { "A2OJ" }, // 0833 - K-1 Pocket Grand Prix 2 (JPN) + { "AY2P" }, // 0843 - International Superstar Soccer Advance (EUR) + { "ANSJ" }, // 0845 - Marie, Elie & Anis no Atelier - Soyokaze Kara no Dengon (JPN) + { "ACOJ" }, // 0865 - Manga-ka Debut Monogatari (JPN) + { "AZLP" }, // 0870 - The Legend of Zelda - A Link to the Past & Four Swords (EUR) + { "AWKJ" }, // 0879 - Wagamama Fairy Mirumo de Pon! - Ougon Maracas no Densetsu (JPN) + { "AZUE" }, // 0886 - Street Fighter Alpha 3 - Upper (USA) + { "AZLJ" }, // 0887 - Zelda no Densetsu - Kamigami no Triforce & 4tsu no Tsurugi (JPN) + { "A6ME" }, // 0889 - MegaMan & Bass (USA) + { "A64J" }, // 0915 - Shimura Ken no Baka Tonosama (JPN) + { "A9HJ" }, // 0917 - Dragon Quest Monsters - Caravan Heart (JPN) + { "AMHP" }, // 0929 - Bomberman Max 2 - Blue Advance (EUR) + { "AMYP" }, // 0930 - Bomberman Max 2 - Red Advance (EUR) + { "AMGJ" }, // 0943 - Exciting Bass (JPN) + { "A5KJ" }, // 0946 - Medarot 2 Core - Kabuto Version (JPN) + { "A4LJ" }, // 0949 - Sylvania Family 4 - Meguru Kisetsu no Tapestry (JPN) + { "A2VJ" }, // 0955 - Kisekko Gurumi - Chesty to Nuigurumi-tachi no Mahou no Bouken (JPN) + { "A5QJ" }, // 0956 - Medarot 2 Core - Kuwagata Version (JPN) + { "AZBJ" }, // 0958 - Bass Tsuri Shiyouze! (JPN) + { "AO2J" }, // 0961 - Oshare Princess 2 (JPN) + { "AB4J" }, // 0965 - Summon Night - Craft Sword Monogatari (JPN) + { "AZAJ" }, // 0971 - Azumanga Daiou Advance (JPN) + { "AF3J" }, // 0974 - Zero One (JPN) + { "A8OJ" }, // 0988 - DokiDoki Cooking Series 2 - Gourmet Kitchen - Suteki na Obentou (JPN) + { "AT3D" }, // 1016 - Tony Hawk's Pro Skater 3 (GER) + { "A6MP" }, // 1031 - MegaMan & Bass (EUR) + { "ANNJ" }, // 1032 - Gekitou Densetsu Noah - Dream Management (JPN) + { "AFNJ" }, // 1036 - Angel Collection - Mezase! Gakuen no Fashion Leader (JPN) + { "ALFP" }, // 1041 - Dragon Ball Z - The Legacy of Goku II (EUR) + { "A9TJ" }, // 1055 - Metal Max 2 Kai (JPN) + { "ALFE" }, // 1070 - Dragon Ball Z - The Legacy of Goku II (USA) + { "BHCJ" }, // 1074 - Hamster Monogatari Collection (JPN) + { "BKKJ" }, // 1075 - Minna no Shiiku Series - Boku no Kabuto-Kuwagata (JPN) + { "BKIJ" }, // 1083 - Nakayoshi Pet Advance Series 4 - Kawaii Koinu Kogata Inu (JPN) + { "BGBJ" }, // 1084 - Get! - Boku no Mushi Tsukamaete (JPN) + { "A82J" }, // 1085 - Hamster Paradise - Pure Heart (JPN) + { "U3IJ" }, // 1087 - Bokura no Taiyou - Taiyou Action RPG (JPN) + { "A6OJ" }, // 1092 - Onimusha Tactics (JPN) + { "AN8J" }, // 1102 - Tales of Phantasia (JPN) + { "AC4J" }, // 1104 - Meitantei Conan - Nerawareta Tantei (JPN) + { "A8ZJ" }, // 1108 - Shin Megami Tensei Devil Children - Puzzle de Call! (JPN) + { "BGMJ" }, // 1113 - Gensou Maden Saiyuuki - Hangyaku no Toushin-taishi (JPN) + { "BMDE" }, // 1115 - Madden NFL 2004 (USA) + { "BO3J" }, // 1141 - Oshare Princess 3 (JPN) + { "U3IE" }, // 1145 - Boktai - The Sun is in Your Hand (USA) + { "BMRJ" }, // 1194 - Matantei Loki Ragnarok - Gensou no Labyrinth (JPN) + { "BLME" }, // 1204 - Lizzie McGuire (USA) + { "AOWE" }, // 1208 - Spyro - Attack of the Rhynocs (USA) + { "BTOE" }, // 1209 - Tony Hawk's Underground (USA) + { "BFJE" }, // 1212 - Frogger's Journey - The Forgotten Relic (USA) + { "A88P" }, // 1229 - Mario & Luigi - Superstar Saga (EUR) + { "BEYP" }, // 1236 - Beyblade VForce - Ultimate Blader Jam (EUR) + { "A85J" }, // 1239 - Sanrio Puroland All Characters (JPN) + { "BMZJ" }, // 1240 - Zooo (JPN) + { "A6OE" }, // 1241 - Onimusha Tactics (USA) + { "AOWP" }, // 1253 - Spyro Adventure (EUR) + { "A88E" }, // 1260 - Mario & Luigi - Superstar Saga (USA) + { "BEYE" }, // 1262 - Beyblade VForce - Ultimate Blader Jam (USA) + { "BCME" }, // 1264 - CIMA - The Enemy (USA) + { "A88J" }, // 1266 - Mario & Luigi RPG (JPN) + { "A5CP" }, // 1269 - Sim City 2000 (EUR) + { "BGAJ" }, // 1277 - SD Gundam G Generation (JPN) + { "A6OP" }, // 1288 - Onimusha Tactics (EUR) + { "BLMP" }, // 1289 - Lizzie McGuire (EUR) + { "ASIE" }, // 1295 - The Sims - Bustin' Out (USA) + { "BISJ" }, // 1299 - Koinu-Chan no Hajimete no Osanpo - Koinu no Kokoro Ikusei Game (JPN) + { "BK3J" }, // 1305 - Card Captor Sakura - Sakura Card de Mini Game (JPN) + { "A4GJ" }, // 1306 - Konjiki no Gashbell!! - Unare! Yuujou no Zakeru (JPN) + { "BTAJ" }, // 1315 - Astro Boy - Tetsuwan Atom (JPN) + { "BS5J" }, // 1322 - Sylvanian Family - Yousei no Stick to Fushigi no Ki (JPN) + { "A5CE" }, // 1326 - Sim City 2000 (USA) + { "B4PJ" }, // 1342 - The Sims (JPN) + { "BDTJ" }, // 1383 - Downtown - Nekketsu Monogatari EX (JPN) + { "B08J" }, // 1391 - One Piece - Going Baseball (JPN) + { "AWUP" }, // 1394 - Sabre Wulf (EUR) + { "BRPJ" }, // 1421 - Liliput Oukoku (JPN) + { "BPNJ" }, // 1435 - Pika Pika Nurse Monogatari - Nurse Ikusei Game (JPN) + { "BP3J" }, // 1446 - Pia Carrot he Youkoso!! 3.3 (JPN) + { "BKCJ" }, // 1461 - Crayon Shin-Chan - Arashi no Yobu Cinema-Land no Daibouken! (JPN) + { "BGNJ" }, // 1464 - Battle Suit Gundam Seed - Battle Assault (JPN) + { "U3IP" }, // 1465 - Boktai - The Sun is in Your Hand (EUR) + { "BDTE" }, // 1484 - River City Ransom EX (USA) + { "BHTE" }, // 1485 - Harry Potter and the Prisoner of Azkaban (USA) + { "FZLE" }, // 1494 - Classic NES Series - The Legend of Zelda (USA) + { "FEBE" }, // 1499 - Classic NES Series - ExciteBike (USA) + { "BUCE" }, // 1505 - Ultimate Card Games (USA) + { "AWUE" }, // 1511 - Sabre Wulf (USA) + { "B2DP" }, // 1522 - Donkey Kong Country 2 (EUR) + { "BHTJ" }, // 1528 - Harry Potter to Azkaban no Shuujin (JPN) + { "A5SJ" }, // 1534 - Oshare Wanko (JPN) + { "B2DJ" }, // 1541 - Super Donkey Kong 2 (JPN) + { "BTAE" }, // 1551 - Astro Boy - Omega Factor (USA) + { "BKOJ" }, // 1553 - Kaiketsu Zorori to Mahou no Yuuenchi (JPN) + { "BDKJ" }, // 1555 - Digi Communication 2 in 1 Datou! Black Gemagema Dan (JPN) + { "U32J" }, // 1567 - Zoku Bokura no Taiyou - Taiyou Shounen Django (JPN) + { "ALFJ" }, // 1573 - Dragon Ball Z - The Legacy of Goku II - International (JPN) + { "BGHJ" }, // 1575 - Gakkou no Kaidan - Hyakuyobako no Fuuin (JPN) + { "BZOJ" }, // 1576 - Zero One SP (JPN) + { "BDXJ" }, // 1587 - B-Densetsu! Battle B-Daman Moero! B-Kon (JPN) + { "BNBJ" }, // 1589 - Himawari Doubutsu Byouin Pet no Oishasan (JPN) + { "BMFE" }, // 1595 - Madden NFL 2005 (USA) + { "FMRJ" }, // 1599 - Famicom Mini Series 23 - Metroid (JPN) + { "FPTJ" }, // 1600 - Famicom Mini Series 24 - Hikari Shinwa - Palutena no Kagame (JPN) + { "FLBJ" }, // 1601 - Famicom Mini Series 25 - The Legend of Zelda 2 - Link no Bouken (JPN) + { "FSDJ" }, // 1606 - Famicom Mini Series 30 - SD Gundam World - Gachapon Senshi Scramble Wars (JPN) + { "BSKJ" }, // 1611 - Summon Night - Craft Sword Monogatari 2 (JPN) + { "BG3E" }, // 1628 - Dragon Ball Z - Buu's Fury (USA) + { "BECJ" }, // 1644 - Angel Collection 2 - Pichimo ni Narou (JPN) + { "B2TE" }, // 1672 - Tony Hawk's Underground 2 (USA) + { "BTYE" }, // 1689 - Ty the Tasmanian Tiger 2 - Bush Rescue (USA) + { "BT2E" }, // 1695 - Teenage Mutant Ninja Turtles 2 - Battlenexus (USA) + { "U32E" }, // 1697 - Boktai 2 - Solar Boy Django (USA) + { "BFDJ" }, // 1708 - Fruit Mura no Doubutsu Tachi (JPN) + { "BPQJ" }, // 1717 - PukuPuku Tennen Kairanban - Koi no Cupid Daisakusen (JPN) + { "BZMJ" }, // 1721 - The Legend of Zelda - Fushigi no Boushi (JPN) + { "FLBE" }, // 1723 - Classic NES Series - Zelda II - The Adventure of Link (USA) + { "BZMP" }, // 1736 - The Legend of Zelda - The Minish Cap (EUR) + { "B2DE" }, // 1754 - Donkey Kong Country 2 (USA) + { "BT2P" }, // 1758 - Teenage Mutant Ninja Turtles 2 - Battle Nexus (EUR) + { "BB2E" }, // 1759 - Beyblade G-Revolution (USA) + { "BRGE" }, // 1761 - Yu-Yu-Hakusho - Tournament Tactics (USA) + { "BFJJ" }, // 1766 - Frogger - Kodaibunmei no Nazo (JPN) + { "BB2P" }, // 1776 - Beyblade G-Revolution (EUR) + { "BSFJ" }, // 1791 - Sylvania Family - Fashion Designer ni Naritai (JPN) + { "BPIE" }, // 1798 - It's Mr Pants (USA) + { "B3PJ" }, // 1809 - Pukupuku Tennen Kairanban Youkoso Illusion Land (JPN) + { "BHDJ" }, // 1812 - Hello Idol Debut (JPN) + { "BKUJ" }, // 1823 - Shingata Medarot - Kuwagata Version (JPN) + { "BKVJ" }, // 1824 - Shingata Medarot - Kabuto Version (JPN) + { "BLIJ" }, // 1825 - Little Patissier Cake no Oshiro (JPN) + { "B3TJ" }, // 1833 - Tales of the World - Narikiri Dungeon 3 (JPN) + { "B2KJ" }, // 1836 - Kiss x Kiss - Seirei Gakuen (JPN) + { "A9BE" }, // 1837 - Medabots - Rokusho Version (USA) + { "BZME" }, // 1842 - The Legend of Zelda - The Minish Cap (USA) + { "B8MJ" }, // 1845 - Mario Party Advance (JPN) + { "A8BE" }, // 1871 - Medabots - Metabee Version (USA) + { "BTAP" }, // 1879 - Astro Boy - Omega Factor (EUR) + { "FSRJ" }, // 1916 - Famicom Mini Series - Dai 2 Ji Super Robot Taisen (JPN) + { "B8ME" }, // 1931 - Mario Party Advance (USA) + { "BO8K" }, // 1938 - One Piece - Going Baseball Haejeok Yaku (KOR) + { "B4ZJ" }, // 1941 - Rockman Zero 4 (JPN) + { "BQAJ" }, // 1953 - Meitantei Conan Akatsuki no Monument (JPN) + { "BIPJ" }, // 1956 - One Piece - Dragon Dream (JPN) + { "BQBJ" }, // 1970 - Konchu Monster Battle Master (JPN) + { "BQSJ" }, // 1971 - Konchu Monster Battle Stadium (JPN) + { "BWXJ" }, // 1982 - Wanko Mix Chiwanko World (JPN) + { "A9TJ" }, // 1984 - Metal Max 2 - Kai Version (JPN) + { "U32P" }, // 1992 - Boktai 2 - Solar Boy Django (EUR) + { "B4RJ" }, // 2005 - Shikakui Atama wo Marukusuru Advance - Kokugo Sansu Rika Shakai (JPN) + { "B4KJ" }, // 2007 - Shikakui Atama wo Marukusuru Advance - Kanji Keisan (JPN) + { "BFCJ" }, // 2019 - Fantasic Children (JPN) + { "BCSP" }, // 2020 - 2 in 1 - V-Rally 3 - Stuntman (EUR) + { "BM2J" }, // 2024 - Momotarou Densetsu G Gold Deck wo Tsukure! (JPN) + { "BEJJ" }, // 2026 - Erementar Gerad (JPN) + { "B5AP" }, // 2034 - Crash & Spyro - Super Pack Volume 1 (EUR) + { "B52P" }, // 2035 - Crash & Spyro - Super Pack Volume 2 (EUR) + { "BFMJ" }, // 2046 - Futari wa Precure Max Heart Maji! Maji! Fight de IN Janai (JPN) + { "BKEJ" }, // 2047 - Konjiki no Gashbell - The Card Battle for GBA (JPN) + { "U33J" }, // 2048 - Shin Bokura no Taiyou - Gyakushuu no Sabata (JPN) + { "BHFJ" }, // 2050 - Twin Series 4 - Ham Ham Monster EX + Fantasy Puzzle Hamster Monogatari (JPN) + { "BMWJ" }, // 2051 - Twin Series 5 - Wan Wan Meitantei EX + Mahou no Kuni no Keaki-Okusan Monogatari (JPN) + { "BMZP" }, // 2055 - Zooo (EUR) + { "B6ME" }, // 2057 - Madden NFL 06 (USA) + { "BT4E" }, // 2058 - Dragon Ball GT - Transformation (USA) + { "B2OJ" }, // 2071 - Pro Mahjong - Tsuwamono GBA (JPN) + { "BX4E" }, // 2079 - 2 in 1 - Tony Hawk's Underground + Kelly Slater's Pro Surfer (USA) + { "BRLE" }, // 2097 - Rebelstar - Tactical Command (USA) + { "BX5P" }, // 2100 - Rayman - 10th Anniversary (EUR) + { "B4ZP" }, // 2108 - MegaMan Zero 4 (EUR) + { "BX5E" }, // 2123 - Rayman - 10th Anniversary (USA) + { "BGXJ" }, // 2143 - Gunstar Super Heroes (JPN) + { "B4ZE" }, // 2144 - Megaman Zero 4 (USA) + { "B53P" }, // 2164 - Crash & Spyro - Super Pack Volume 3 (EUR) + { "B26E" }, // 2169 - World Poker Tour (USA) + { "BH9E" }, // 2172 - Tony Hawk's American Sk8land (USA) + { "BHGE" }, // 2177 - Gunstar Super Heroes (USA) + { "BCMJ" }, // 2178 - Frontier Stories (JPN) + { "BUZE" }, // 2182 - Ultimate Arcade Games (USA) + { "BTVE" }, // 2198 - Ty the Tasmanian Tiger 3 - Night of the Quinkan (USA) + { "BHGP" }, // 2199 - Gunstar Future Heroes (EUR) + { "BH9X" }, // 2214 - Tony Hawk's American Sk8land (EUR) + { "BWIP" }, // 2231 - Win X Club (EUR) + { "BQTP" }, // 2232 - My Pet Hotel (EUR) + { "B4LJ" }, // 2245 - Sugar Sugar Une - Heart Gaippai! Moegi Gakuen (JPN) + { "B3CJ" }, // 2249 - Summon Night Craft Sword Monogatari - Hajimari no Ishi (JPN) + { "A4GE" }, // 2260 - ZatchBell! - Electric Arena (USA) + { "BLFE" }, // 2264 - 2 in 1 - Dragon Ball Z 1 and 2 (USA) + { "BO2J" }, // 2272 - Ochainu no Bouken Jima (JPN) + { "BWIE" }, // 2276 - WinX Club (USA) + { "BGQE" }, // 2279 - Greg Hastings' Tournament Paintball Max'd (USA) + { "BURE" }, // 2298 - Paws & Claws - Pet Resort (USA) + { "A3AC" }, // 2303 - Yaoxi Dao (CHN) + { "AN8E" }, // 2305 - Tales of Phantasia (USA) + { "BZWJ" }, // 2309 - Akagi (JPN) + { "BT8P" }, // 2316 - Teenage Mutant Ninja Turtles Double Pack (EUR) + { "BYUJ" }, // 2322 - Yggdra Union (JPN) + { "AN3E" }, // 2324 - Catz (USA) + { "AN8P" }, // 2325 - Tales of Phantasia (EUR) + { "AA2C" }, // 2332 - Chaoji Maliou Shijie (CHN) + { "BWOP" }, // 2333 - World Poker Tour (EUR) + { "BKCS" }, // 2334 - Shinchan - Aventuras en Cineland (ESP) + { "BC2J" }, // 2341 - Crayon Shin chan - Densetsu wo Yobu Omake no Miyako Shockgaan (JPN) + { "BUOJ" }, // 2345 - Minna no Soft Series - Numpla Advance (JPN) + { "AN3J" }, // 2347 - Minna no Soft Series - Kawaii Koneko (JPN) + { "BUOE" }, // 2366 - Dr. Sudoku (USA) + { "B8SE" }, // 2368 - Spyro Superpack - Season of Ice + Season of Flame (USA) + { "U32J" }, // 2369 - Zoku Bokura no Taiyou - Taiyou Shounen Django (v01) (JPN) + { "BBMJ" }, // 2388 - B-Legend! Battle B-Daman - Moero! B-Damashi!! (JPN) + { "B53E" }, // 2395 - Crash & Spyro Superpack - Ripto's Rampage + The Cortex Conspiracy (USA) + { "BH9P" }, // 2399 - Tony Hawk's American Sk8land (EUR) + { "BAQP" }, // 2406 - Premier Action Soccer (EUR) + { "AB4E" }, // 2432 - Summon Night - Swordcraft Story (USA) + { "BBYE" }, // 2436 - Barnyard (USA) + { "BDXE" }, // 2438 - Battle B-Daman (USA) + { "B7ME" }, // 2446 - Madden NFL 07 (USA) + { "BUFE" }, // 2447 - 2 Games in 1 - Dragon Ball Z - Buu's Fury + Dragon Ball GT - Transformation (USA) + { "BUOP" }, // 2449 - Dr. Sudoku (EUR) + { "BBYX" }, // 2461 - Barnyard (EUR) + { "BFEE" }, // 2466 - Dogz - Fashion (USA) + { "AN3X" }, // 2468 - Catz (EUR) + { "BBME" }, // 2481 - Battle B-Daman - Fire Spirits (USA) + { "BQZE" }, // 2487 - Avatar - The Last Airbender (USA) + { "BXFE" }, // 2498 - Bratz - Forever Diamondz (USA) + { "BT8E" }, // 2500 - Teenage Mutant Ninja Turtles Double Pack (USA) + { "B3YE" }, // 2504 - The Legend of Spyro - A New Beginning (USA) + { "BSKE" }, // 2505 - Summon Night - Swordcraft Story 2 (USA) + { "BHBP" }, // 2513 - Best Friends - Hunde & Katzen (EUR) + { "B3YP" }, // 2519 - The Legend Of Spyro - A New Beginning (EUR) + { "BXFD" }, // 2520 - Bratz - Forever Diamondz (GER) + { "BRLP" }, // 2532 - Rebelstar - Tactical Command (EUR) + { "BENP" }, // 2560 - Eragon (EUR) + { "BENE" }, // 2561 - Eragon (USA) + { "BYUE" }, // 2573 - Yggdra Union - We'll Never Fight Alone (USA) + { "BFRP" }, // 2588 - My Animal Centre in Africa (EUR) + { "BFQE" }, // 2606 - Mazes of Fate (USA) + { "BQZP" }, // 2607 - Avatar - The Legend of Aang (EUR) + { "BFEP" }, // 2613 - Dogz Fashion (EUR) + { "BC2S" }, // 2631 - Shinchan contra los Munecos de Shock Gahn (ESP) + { "BXFP" }, // 2640 - Bratz - Forever Diamondz (EUR) + { "BEFP" }, // 2652 - Best Friends - My Horse (EUR) + { "BNBE" }, // 2695 - Petz Vet (USA) + { "BIME" }, // 2696 - Dogz 2 (USA) + { "BQTX" }, // 2710 - Mijn Dierenpension (EUR) + { "BIMP" }, // 2720 - Dogz 2 (EUR) + { "BIMX" }, // 2727 - Dogz 2 (EUR) + { "BHUE" }, // 2730 - Horsez (USA) + { "BQTF" }, // 2732 - Lea - Passion Veterinaire (FRA) + { "BJPP" }, // 2770 - Harry Potter Collection (EUR) + { "BEFE" }, // 2772 - Let's Ride - Friends Forever (USA) + { "BHBE" }, // 2774 - Best Friends - Dogs & Cats (USA) + { "BYUP" }, // 2781 - Yggdra Union - We'll Never Fight Alone (EUR) + { "ACOJ" }, // 2787 - Manga-ka Debut Monogatari (v01) (JPN) + { "BFDJ" }, // 2789 - Fruit Mura no Doubutsu Tachi (v02) (JPN) + // gba scan no. 8 + { "AYSJ" }, // 0229 - Gakkou wo Tsukurou!! Advance (JPN) + { "ASNJ" }, // 0260 - Sansara Naga 1x2 (JPN) + { "ACTX" }, // 0265 - Creatures (EUR) + { "ASFJ" }, // 0359 - Slot! Pro Advance - Takarabune & Ooedo Sakurafubuki 2 (JPN) + { "ABGJ" }, // 0404 - Sweet Cookie Pie (JPN) + { "ARNJ" }, // 0615 - Harukanaru Toki no Naka de (JPN) + { "AOPJ" }, // 0646 - Oshare Princess (JPN) + { "AHVJ" }, // 0664 - Nakayoshi Youchien - Sukoyaka Enji Ikusei Game (JPN) + { "AYCE" }, // 0758 - Phantasy Star Collection (USA) + { "AYCP" }, // 0877 - Phantasy Star Collection (EUR) + { "ATBJ" }, // 0948 - Slot! Pro 2 Advance - GoGo Juggler & New Tairyou (JPN) + { "A83J" }, // 1012 - Hamster Monogatari 3 GBA (JPN) + { "AEHJ" }, // 1014 - Puzzle & Tantei Collection (JPN) + { "BWDJ" }, // 1114 - Wan Nyan Doubutsu Byouin (JPN) + { "BKZE" }, // 1138 - Banjo-Kazooie - Grunty's Revenge (USA) + { "FZLJ" }, // 1369 - Famicom Mini Series 5 - Zelda no Denzetsu 1 (JPN) + { "BPVP" }, // 1738 - Pferd & Pony - Mein Pferdehof (EUR) + { "ACTY" }, // 1763 - Creatures (EUR) + { "BITJ" }, // 1811 - Onmyou Taisenki Zeroshik (JPN) + { "BOVJ" }, // 1848 - Bouken-Ou Beet - Busters Road (JPN) + { "BT3J" }, // 1852 - Tantei Jinguuji Saburou Shiroi Kage no Syoujyo (JPN) + { "BG8J" }, // 1853 - Ganbare! Dodge Fighters (JPN) + { "BLDS" }, // 1919 - 2 Games in 1 - Lizzie McGuire - Disney Princesas (ESP) + { "BLDP" }, // 1934 - 2 Games in 1 - Lizzie McGuire - Disney Princess (EUR) + { "B8MP" }, // 1993 - Mario Party Advance (EUR) + { "BYPP" }, // 2155 - Horse & Pony - Let`s Ride 2 (EUR) + { "B8AE" }, // 2174 - Crash Superpack - N-Tranced + Nitro Kart (USA) + { "BL9E" }, // 2329 - Let's Ride! Dreamer (USA) + { "B34E" }, // 2331 - Let's Ride! - Sunshine Stables (USA) + { "BQVP" }, // 2414 - Meine Tierarztpraxis (EUR) + { "BHUP" }, // 2480 - Horse and Pony - My Stud Farm (EUR) + { "BPVX" }, // 2645 - Pippa Funnell - Stable Adventures (EUR) + { "BYPX" }, // 2653 - Pippa Funell 2 (EUR) + { "BQVX" }, // 2711 - Mijn Dierenpraktijk (EUR) + { "BPVY" }, // 2712 - Paard & Pony - Mijn Manege (EUR) + { "BYPY" }, // 2713 - Paard & Pony - Paard in Galop (EUR) + { "B54E" }, // 2757 - Crash & Spyro Superpack - The Huge Adventure + Season of Ice (USA) + // gba scan no. 9 + { "BKZX" }, // 1199 - Banjo-Kazooie - Grunty's Revenge (EUR) + { "BKZI" }, // 1381 - Banjo Kazooie - La Vendetta di Grunty (ITA) + { "BAZJ" }, // 1710 - Akachan Doubutsu Sono (JPN) + { "BKZS" }, // 1883 - Banjo Kazooie - La Venganza de Grunty (ESP) + // gba scan no. 11 + { "A9BP" }, // 0925 - Medabots - Rokusho Version (EUR) + { "A3IJ" }, // bokura no taiyou - taiyou action rpg - kabunushi go-yuutai ban (japan) (demo) +}; + +#endif diff --git a/src/devices/bus/gba/rom.c b/src/devices/bus/gba/rom.c new file mode 100644 index 00000000000..3b7f775e7cf --- /dev/null +++ b/src/devices/bus/gba/rom.c @@ -0,0 +1,438 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont,Ryan Holtz,Fabio Priuli +/*********************************************************************************************************** + + + Game Boy Advance cart emulation + + + We support carts with several kind of Save RAM (actual SRAM, Flash RAM or EEPROM) + + + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "rom.h" + + +//------------------------------------------------- +// gba_rom_device - constructor +//------------------------------------------------- + +const device_type GBA_ROM_STD = &device_creator; +const device_type GBA_ROM_SRAM = &device_creator; +const device_type GBA_ROM_EEPROM = &device_creator; +const device_type GBA_ROM_EEPROM64 = &device_creator; +const device_type GBA_ROM_FLASH = &device_creator; +const device_type GBA_ROM_FLASH1M = &device_creator; + + +gba_rom_device::gba_rom_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_gba_cart_interface( mconfig, *this ) +{ +} + +gba_rom_device::gba_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, GBA_ROM_STD, "GBA Carts", tag, owner, clock, "gba_rom", __FILE__), + device_gba_cart_interface( mconfig, *this ) +{ +} + +gba_rom_sram_device::gba_rom_sram_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : gba_rom_device(mconfig, GBA_ROM_SRAM, "GBA Carts + SRAM", tag, owner, clock, "gba_sram", __FILE__) +{ +} + +gba_rom_eeprom_device::gba_rom_eeprom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : gba_rom_device(mconfig, GBA_ROM_EEPROM, "GBA Carts + EEPROM", tag, owner, clock, "gba_eeprom", __FILE__) +{ +} + +gba_rom_eeprom64_device::gba_rom_eeprom64_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : gba_rom_device(mconfig, GBA_ROM_EEPROM64, "GBA Carts + EEPROM 64K", tag, owner, clock, "gba_eeprom64", __FILE__) +{ +} + +gba_rom_flash_device::gba_rom_flash_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : gba_rom_device(mconfig, GBA_ROM_FLASH, "GBA Carts + Panasonic Flash", tag, owner, clock, "gba_flash", __FILE__), + m_flash(*this, "flash") +{ +} + +gba_rom_flash1m_device::gba_rom_flash1m_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : gba_rom_device(mconfig, GBA_ROM_FLASH1M, "GBA Carts + Sanyo Flash", tag, owner, clock, "gba_flash1m", __FILE__), + m_flash(*this, "flash") +{ +} + + +//------------------------------------------------- +// mapper specific start/reset +//------------------------------------------------- + +void gba_rom_device::device_start() +{ +} + +void gba_rom_device::device_reset() +{ +} + +void gba_rom_flash_device::device_reset() +{ + m_flash_mask = 0xffff/4; +} + +void gba_rom_flash1m_device::device_reset() +{ + m_flash_mask = 0x1ffff/4; +} + + +void gba_rom_eeprom_device::device_start() +{ + // for the moment we use a custom eeprom implementation, so we alloc/save it as nvram + nvram_alloc(0x200); + m_eeprom.reset(global_alloc(gba_eeprom_device(machine(), (UINT8*)get_nvram_base(), get_nvram_size(), 6))); +} + +void gba_rom_eeprom64_device::device_start() +{ + // for the moment we use a custom eeprom implementation, so we alloc/save it as nvram + nvram_alloc(0x2000); + m_eeprom.reset(global_alloc(gba_eeprom_device(machine(), (UINT8*)get_nvram_base(), get_nvram_size(), 14))); +} + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + + +/*------------------------------------------------- + Carts with SRAM + -------------------------------------------------*/ + +READ32_MEMBER(gba_rom_sram_device::read_ram) +{ + if (!m_nvram.empty() && offset < m_nvram.size()) + return m_nvram[offset]; + else // this cannot actually happen... + return 0xffffffff; +} + +WRITE32_MEMBER(gba_rom_sram_device::write_ram) +{ + if (!m_nvram.empty() && offset < m_nvram.size()) + COMBINE_DATA(&m_nvram[offset]); +} + + +/*------------------------------------------------- + Carts with Flash RAM + -------------------------------------------------*/ + +static MACHINE_CONFIG_FRAGMENT( panasonic_flash ) + MCFG_PANASONIC_MN63F805MNP_ADD("flash") +MACHINE_CONFIG_END + +machine_config_constructor gba_rom_flash_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( panasonic_flash ); +} + + +READ32_MEMBER(gba_rom_flash_device::read_ram) +{ + UINT32 rv = 0; + + offset &= m_flash_mask; + + if (mem_mask & 0xff) + rv |= m_flash->read(offset * 4); + if (mem_mask & 0xff00) + rv |= m_flash->read((offset * 4) + 1) << 8; + if (mem_mask & 0xff0000) + rv |= m_flash->read((offset * 4) + 2) << 16; + if (mem_mask & 0xff000000) + rv |= m_flash->read((offset * 4) + 3) << 24; + + return rv; +} + +WRITE32_MEMBER(gba_rom_flash_device::write_ram) +{ + offset &= m_flash_mask; + + switch (mem_mask) + { + case 0xff: + m_flash->write(offset * 4, data & 0xff); + break; + case 0xff00: + m_flash->write((offset * 4) + 1, (data >> 8) & 0xff); + break; + case 0xff0000: + m_flash->write((offset * 4) + 2, (data >> 16) & 0xff); + break; + case 0xff000000: + m_flash->write((offset * 4) + 3, (data >> 24) & 0xff); + break; + default: + fatalerror("Unknown mem_mask for GBA flash write %x\n", mem_mask); + } +} + +static MACHINE_CONFIG_FRAGMENT( sanyo_flash ) + MCFG_SANYO_LE26FV10N1TS_ADD("flash") +MACHINE_CONFIG_END + +machine_config_constructor gba_rom_flash1m_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( sanyo_flash ); +} + + +READ32_MEMBER(gba_rom_flash1m_device::read_ram) +{ + UINT32 rv = 0; + + offset &= m_flash_mask; + + if (mem_mask & 0xff) + rv |= m_flash->read(offset * 4); + if (mem_mask & 0xff00) + rv |= m_flash->read((offset * 4) + 1) << 8; + if (mem_mask & 0xff0000) + rv |= m_flash->read((offset * 4) + 2) << 16; + if (mem_mask & 0xff000000) + rv |= m_flash->read((offset * 4) + 3) << 24; + + return rv; +} + +WRITE32_MEMBER(gba_rom_flash1m_device::write_ram) +{ + offset &= m_flash_mask; + + switch (mem_mask) + { + case 0xff: + m_flash->write(offset * 4, data & 0xff); + break; + case 0xff00: + m_flash->write((offset * 4) + 1, (data >> 8) & 0xff); + break; + case 0xff0000: + m_flash->write((offset * 4) + 2, (data >> 16) & 0xff); + break; + case 0xff000000: + m_flash->write((offset * 4) + 3, (data >> 24) & 0xff); + break; + default: + fatalerror("Unknown mem_mask for GBA flash write %x\n", mem_mask); + } +} + + +/*------------------------------------------------- + Carts with EEPROM + + TODO: can this sketchy EEPROM device be merged + with the core implementation? + -------------------------------------------------*/ + +// GBA EEPROM Device + +gba_eeprom_device::gba_eeprom_device(running_machine &machine, UINT8 *eeprom, UINT32 size, int addr_bits) : + m_state(EEP_IDLE), + m_machine(machine) +{ + m_data = eeprom; + m_data_size = size; + m_addr_bits = addr_bits; + + m_machine.save().save_item(m_state, "GBA_EEPROM/m_state"); + m_machine.save().save_item(m_command, "GBA_EEPROM/m_command"); + m_machine.save().save_item(m_count, "GBA_EEPROM/m_count"); + m_machine.save().save_item(m_addr, "GBA_EEPROM/m_addr"); + m_machine.save().save_item(m_bits, "GBA_EEPROM/m_bits"); + m_machine.save().save_item(m_eep_data, "GBA_EEPROM/m_eep_data"); +} + +UINT32 gba_eeprom_device::read() +{ + UINT32 out; + + switch (m_state) + { + case EEP_IDLE: +// printf("eeprom_r: @ %x, mask %08x (state %d) (PC=%x) = %d\n", offset, ~mem_mask, m_state, activecpu_get_pc(), 1); + return 0x00010001; // "ready" + + case EEP_READFIRST: + m_count--; + + if (!m_count) + { + m_count = 64; + m_bits = 0; + m_eep_data = 0; + m_state = EEP_READ; + } + break; + case EEP_READ: + if ((m_bits == 0) && (m_count)) + { + if (m_addr >= m_data_size) + { + fatalerror("eeprom: invalid address (%x)\n", m_addr); + } + m_eep_data = m_data[m_addr]; + //printf("EEPROM read @ %x = %x (%x)\n", m_addr, m_eep_data, (m_eep_data & 0x80) ? 1 : 0); + m_addr++; + m_bits = 8; + } + + out = (m_eep_data & 0x80) ? 1 : 0; + out |= (out<<16); + m_eep_data <<= 1; + + m_bits--; + m_count--; + + if (!m_count) + { + m_state = EEP_IDLE; + } + +// printf("out = %08x\n", out); +// printf("eeprom_r: @ %x, mask %08x (state %d) (PC=%x) = %08x\n", offset, ~mem_mask, m_state, activecpu_get_pc(), out); + return out; + } +// printf("eeprom_r: @ %x, mask %08x (state %d) (PC=%x) = %d\n", offset, ~mem_mask, m_state, space.device().safe_pc(), 0); + return 0; +} + +void gba_eeprom_device::write(UINT32 data) +{ +// printf("eeprom_w: %x @ %x (state %d) (PC=%x)\n", data, offset, m_state, space.device().safe_pc()); + switch (m_state) + { + case EEP_IDLE: + if (data == 1) + m_state++; + break; + + case EEP_COMMAND: + if (data == 1) + m_command = EEP_READFIRST; + else + m_command = EEP_WRITE; + m_state = EEP_ADDR; + m_count = m_addr_bits; + m_addr = 0; + break; + + case EEP_ADDR: + m_addr <<= 1; + m_addr |= (data & 1); + m_count--; + if (!m_count) + { + m_addr *= 8; // each address points to 8 bytes + if (m_command == EEP_READFIRST) + m_state = EEP_AFTERADDR; + else + { + m_count = 64; + m_bits = 8; + m_state = EEP_WRITE; + m_eep_data = 0; + } + } + break; + + case EEP_AFTERADDR: + m_state = m_command; + m_count = 64; + m_bits = 0; + m_eep_data = 0; + if (m_state == EEP_READFIRST) + m_count = 4; + break; + + case EEP_WRITE: + m_eep_data <<= 1; + m_eep_data |= (data & 1); + m_bits--; + m_count--; + + if (m_bits == 0) + { + osd_printf_verbose("%08x: EEPROM: %02x to %x\n", machine().device("maincpu")->safe_pc(), m_eep_data, m_addr); + if (m_addr >= m_data_size) + fatalerror("eeprom: invalid address (%x)\n", m_addr); + + m_data[m_addr] = m_eep_data; + m_addr++; + m_eep_data = 0; + m_bits = 8; + } + + if (!m_count) + m_state = EEP_AFTERWRITE; + break; + + case EEP_AFTERWRITE: + m_state = EEP_IDLE; + break; + } +} + + + +READ32_MEMBER(gba_rom_eeprom_device::read_ram) +{ + // Larger games have smaller access to EERPOM content + if (m_rom_size > (16 * 1024 * 1024) && offset < 0xffff00/4) + return 0xffffffff; + + return m_eeprom->read(); +} + +WRITE32_MEMBER(gba_rom_eeprom_device::write_ram) +{ + // Larger games have smaller access to EEPROM content + if (m_rom_size > (16 * 1024 * 1024) && offset < 0xffff00/4) + return; + + if (~mem_mask == 0x0000ffff) + data >>= 16; + + m_eeprom->write(data); +} + +READ32_MEMBER(gba_rom_eeprom64_device::read_ram) +{ + // Larger games have smaller access to EERPOM content + if (m_rom_size > (16 * 1024 * 1024) && offset < 0xffff00/4) + return 0xffffffff; + + return m_eeprom->read(); +} + +WRITE32_MEMBER(gba_rom_eeprom64_device::write_ram) +{ + // Larger games have smaller access to EEPROM content + if (m_rom_size > (16 * 1024 * 1024) && offset < 0xffff00/4) + return; + + if (~mem_mask == 0x0000ffff) + data >>= 16; + + m_eeprom->write(data); +} diff --git a/src/devices/bus/gba/rom.h b/src/devices/bus/gba/rom.h new file mode 100644 index 00000000000..e008c318b7c --- /dev/null +++ b/src/devices/bus/gba/rom.h @@ -0,0 +1,174 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont,Ryan Holtz,Fabio Priuli +#ifndef __GBA_ROM_H +#define __GBA_ROM_H + +#include "gba_slot.h" +#include "machine/intelfsh.h" + + +// ======================> gba_rom_device + +class gba_rom_device : public device_t, + public device_gba_cart_interface +{ +public: + // construction/destruction + gba_rom_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + gba_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // reading and writing + virtual DECLARE_READ32_MEMBER(read_rom) { return m_rom[offset]; } +}; + +// ======================> gba_rom_sram_device + +class gba_rom_sram_device : public gba_rom_device +{ +public: + // construction/destruction + gba_rom_sram_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // reading and writing + virtual DECLARE_READ32_MEMBER(read_ram); + virtual DECLARE_WRITE32_MEMBER(write_ram); +}; + +// ======================> gba_rom_flash_device + +class gba_rom_flash_device : public gba_rom_device +{ +public: + // construction/destruction + gba_rom_flash_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual void device_reset(); + + // reading and writing + virtual DECLARE_READ32_MEMBER(read_ram); + virtual DECLARE_WRITE32_MEMBER(write_ram); + +private: + //UINT32 m_flash_size; + UINT32 m_flash_mask; + required_device m_flash; +}; + +// ======================> gba_rom_flash1m_device + +class gba_rom_flash1m_device : public gba_rom_device +{ +public: + // construction/destruction + gba_rom_flash1m_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual void device_reset(); + + // reading and writing + virtual DECLARE_READ32_MEMBER(read_ram); + virtual DECLARE_WRITE32_MEMBER(write_ram); + +private: + //UINT32 m_flash_size; + UINT32 m_flash_mask; + required_device m_flash; +}; + +// GBA EEPROM device +// TODO: is it possible to merge this with the standard EEPROM devices in the core? + +enum +{ + EEP_IDLE = 0, + EEP_COMMAND, + EEP_ADDR, + EEP_AFTERADDR, + EEP_READ, + EEP_WRITE, + EEP_AFTERWRITE, + EEP_READFIRST +}; + +class gba_eeprom_device +{ +public: + gba_eeprom_device(running_machine &machine, UINT8 *eeprom, UINT32 size, int addr_bits); + running_machine &machine() const { return m_machine; } + + UINT32 read(); + void write(UINT32 data); + +protected: + UINT8 *m_data; + UINT32 m_data_size; + int m_state; + int m_command; + int m_count; + int m_addr; + int m_bits; + int m_addr_bits; + UINT8 m_eep_data; + + running_machine& m_machine; +}; + + +// ======================> gba_rom_eeprom_device + +class gba_rom_eeprom_device : public gba_rom_device +{ +public: + // construction/destruction + gba_rom_eeprom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + + // reading and writing + virtual DECLARE_READ32_MEMBER(read_ram); + virtual DECLARE_WRITE32_MEMBER(write_ram); + +private: + auto_pointer m_eeprom; +}; + + +// ======================> gba_rom_eeprom64_device + +class gba_rom_eeprom64_device : public gba_rom_device +{ +public: + // construction/destruction + gba_rom_eeprom64_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + + // reading and writing + virtual DECLARE_READ32_MEMBER(read_ram); + virtual DECLARE_WRITE32_MEMBER(write_ram); + +private: + auto_pointer m_eeprom; +}; + + +// device type definition +extern const device_type GBA_ROM_STD; +extern const device_type GBA_ROM_SRAM; +extern const device_type GBA_ROM_EEPROM; +extern const device_type GBA_ROM_EEPROM64; +extern const device_type GBA_ROM_FLASH; +extern const device_type GBA_ROM_FLASH1M; + + + +#endif diff --git a/src/devices/bus/generic/carts.c b/src/devices/bus/generic/carts.c new file mode 100644 index 00000000000..23a079289c9 --- /dev/null +++ b/src/devices/bus/generic/carts.c @@ -0,0 +1,22 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/********************************************************************** + + Generic ROM / RAM socket slots + + **********************************************************************/ + + +#include "carts.h" + +SLOT_INTERFACE_START(generic_plain_slot) + SLOT_INTERFACE_INTERNAL("rom", GENERIC_ROM_PLAIN) +SLOT_INTERFACE_END + +SLOT_INTERFACE_START(generic_linear_slot) + SLOT_INTERFACE_INTERNAL("rom", GENERIC_ROM_LINEAR) +SLOT_INTERFACE_END + +SLOT_INTERFACE_START(generic_romram_plain_slot) + SLOT_INTERFACE_INTERNAL("rom", GENERIC_ROMRAM_PLAIN) +SLOT_INTERFACE_END diff --git a/src/devices/bus/generic/carts.h b/src/devices/bus/generic/carts.h new file mode 100644 index 00000000000..fdd354314ed --- /dev/null +++ b/src/devices/bus/generic/carts.h @@ -0,0 +1,24 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/********************************************************************** + + Generic ROM/RAM socket slots + +**********************************************************************/ + +#pragma once + +#ifndef __GENERIC_CARTS_H__ +#define __GENERIC_CARTS_H__ + +#include "emu.h" + +#include "rom.h" +#include "ram.h" + + +SLOT_INTERFACE_EXTERN( generic_plain_slot ); +SLOT_INTERFACE_EXTERN( generic_linear_slot ); +SLOT_INTERFACE_EXTERN( generic_romram_plain_slot ); + +#endif diff --git a/src/devices/bus/generic/ram.c b/src/devices/bus/generic/ram.c new file mode 100644 index 00000000000..3767ddae724 --- /dev/null +++ b/src/devices/bus/generic/ram.c @@ -0,0 +1,123 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + Generic RAM socket emulation + + This offers generic access to RAM + + generic_ram_plain : returns 0xff when the system reads beyond the end of the RAM + generic_ram_linear : maps linearly the RAM in the accessed area (i.e., read/write offset is masked with + (RAM size - 1) ) + + TODO: + - support variable RAM size + - possibly support linear mapping when non-power of 2 RAMs are mapped + - add support for 16bit & 32bit RAM access + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "ram.h" + +//------------------------------------------------- +// constructor +//------------------------------------------------- + +const device_type GENERIC_RAM_32K_PLAIN = &device_creator; +const device_type GENERIC_RAM_64K_PLAIN = &device_creator; +const device_type GENERIC_RAM_128K_PLAIN = &device_creator; +const device_type GENERIC_RAM_32K_LINEAR = &device_creator; +const device_type GENERIC_RAM_64K_LINEAR = &device_creator; +const device_type GENERIC_RAM_128K_LINEAR = &device_creator; + + +generic_ram_plain_device::generic_ram_plain_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, UINT32 size, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_generic_cart_interface(mconfig, *this), + m_size(size) +{ +} + +generic_ram_linear_device::generic_ram_linear_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, UINT32 size, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_generic_cart_interface(mconfig, *this), + m_size(size) +{ +} + + +generic_ram_32k_plain_device::generic_ram_32k_plain_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : generic_ram_plain_device(mconfig, GENERIC_RAM_32K_PLAIN, "Generic RAM 32K (plain mapping)", tag, owner, clock, 0x8000, "generic_ram32p", __FILE__) +{ +} + +generic_ram_64k_plain_device::generic_ram_64k_plain_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : generic_ram_plain_device(mconfig, GENERIC_RAM_64K_PLAIN, "Generic RAM 64K (plain mapping)", tag, owner, clock, 0x10000, "generic_ram64p", __FILE__) +{ +} + +generic_ram_128k_plain_device::generic_ram_128k_plain_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : generic_ram_plain_device(mconfig, GENERIC_RAM_128K_PLAIN, "Generic RAM 128K (plain mapping)", tag, owner, clock, 0x20000, "generic_ram128p", __FILE__) +{ +} + +generic_ram_32k_linear_device::generic_ram_32k_linear_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : generic_ram_linear_device(mconfig, GENERIC_RAM_32K_LINEAR, "Generic RAM 32K (linear mapping)", tag, owner, clock, 0x8000, "generic_ram32l", __FILE__) +{ +} + +generic_ram_64k_linear_device::generic_ram_64k_linear_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : generic_ram_linear_device(mconfig, GENERIC_RAM_64K_LINEAR, "Generic RAM 64K (linear mapping)", tag, owner, clock, 0x10000, "generic_ram64l", __FILE__) +{ +} + +generic_ram_128k_linear_device::generic_ram_128k_linear_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : generic_ram_linear_device(mconfig, GENERIC_RAM_128K_LINEAR, "Generic RAM 128K (linear mapping)", tag, owner, clock, 0x20000, "generic_ram128l", __FILE__) +{ +} + + +void generic_ram_plain_device::device_start() +{ + m_ram.resize(m_size); + save_item(NAME(m_ram)); +} + +void generic_ram_linear_device::device_start() +{ + m_ram.resize(m_size); + save_item(NAME(m_ram)); +} + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +READ8_MEMBER(generic_ram_plain_device::read_ram) +{ + if (offset < m_ram.size()) + return m_ram[offset]; + else + return 0xff; +} + +WRITE8_MEMBER(generic_ram_plain_device::write_ram) +{ + if (offset < m_ram.size()) + m_ram[offset] = data; +} + + +READ8_MEMBER(generic_ram_linear_device::read_ram) +{ + return m_ram[offset % m_ram.size()]; +} + +WRITE8_MEMBER(generic_ram_linear_device::write_ram) +{ + m_ram[offset % m_ram.size()] = data; +} diff --git a/src/devices/bus/generic/ram.h b/src/devices/bus/generic/ram.h new file mode 100644 index 00000000000..ac3cfdbb113 --- /dev/null +++ b/src/devices/bus/generic/ram.h @@ -0,0 +1,109 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __GENERIC_RAM_H +#define __GENERIC_RAM_H + +#include "slot.h" + + +// ======================> generic_ram_plain_device + +class generic_ram_plain_device : public device_t, + public device_generic_cart_interface +{ +public: + // construction/destruction + generic_ram_plain_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, UINT32 size, const char *shortname, const char *source); + + // device-level overrides + virtual void device_start(); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_ram); + virtual DECLARE_WRITE8_MEMBER(write_ram); + +private: + UINT32 m_size; +}; + + +// ======================> generic_ram_linear_device + +class generic_ram_linear_device : public device_t, + public device_generic_cart_interface +{ +public: + // construction/destruction + generic_ram_linear_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, UINT32 size, const char *shortname, const char *source); + + // device-level overrides + virtual void device_start(); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_ram); + virtual DECLARE_WRITE8_MEMBER(write_ram); + +private: + UINT32 m_size; +}; + + +// ======================> generic_ram_*k_plain_device + +class generic_ram_32k_plain_device : public generic_ram_plain_device +{ +public: + // construction/destruction + generic_ram_32k_plain_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class generic_ram_64k_plain_device : public generic_ram_plain_device +{ +public: + // construction/destruction + generic_ram_64k_plain_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class generic_ram_128k_plain_device : public generic_ram_plain_device +{ +public: + // construction/destruction + generic_ram_128k_plain_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +// ======================> generic_ram_*k_linear_device + +class generic_ram_32k_linear_device : public generic_ram_linear_device +{ +public: + // construction/destruction + generic_ram_32k_linear_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class generic_ram_64k_linear_device : public generic_ram_linear_device +{ +public: + // construction/destruction + generic_ram_64k_linear_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class generic_ram_128k_linear_device : public generic_ram_linear_device +{ +public: + // construction/destruction + generic_ram_128k_linear_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + + +// device type definition +extern const device_type GENERIC_RAM_32K_PLAIN; +extern const device_type GENERIC_RAM_64K_PLAIN; +extern const device_type GENERIC_RAM_128K_PLAIN; +extern const device_type GENERIC_RAM_32K_LINEAR; +extern const device_type GENERIC_RAM_64K_LINEAR; +extern const device_type GENERIC_RAM_128K_LINEAR; + + +#endif diff --git a/src/devices/bus/generic/rom.c b/src/devices/bus/generic/rom.c new file mode 100644 index 00000000000..a816040e229 --- /dev/null +++ b/src/devices/bus/generic/rom.c @@ -0,0 +1,122 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + Generic ROM emulation (for carts and ROM sockets) + + This offers generic access to a ROM + + generic_rom_plain : returns 0xff when the system reads beyond the end of the ROM + generic_rom_linear : maps linearly the ROM in the accessed area (i.e., read offset is masked with (ROM size - 1) ) + + generic_romram_plain : allows support for carts always containing ROM + RAM (e.g. X07) + + + TODO: + - possibly support linear mapping when non-power of 2 ROMs are mapped + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "rom.h" + +//------------------------------------------------- +// constructor +//------------------------------------------------- + +const device_type GENERIC_ROM_PLAIN = &device_creator; +const device_type GENERIC_ROM_LINEAR = &device_creator; +const device_type GENERIC_ROMRAM_PLAIN = &device_creator; + + +generic_rom_device::generic_rom_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_generic_cart_interface(mconfig, *this) +{ +} + +generic_rom_plain_device::generic_rom_plain_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : generic_rom_device(mconfig, type, name, tag, owner, clock, shortname, source) +{ +} + +generic_rom_plain_device::generic_rom_plain_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : generic_rom_device(mconfig, GENERIC_ROM_PLAIN, "Generic ROM (plain mapping)", tag, owner, clock, "generic_rom_plain", __FILE__) +{ +} + +generic_rom_linear_device::generic_rom_linear_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : generic_rom_device(mconfig, GENERIC_ROM_LINEAR, "Generic ROM (linear mapping)", tag, owner, clock, "generic_rom_linear", __FILE__) +{ +} + +generic_romram_plain_device::generic_romram_plain_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : generic_rom_plain_device(mconfig, GENERIC_ROMRAM_PLAIN, "Generic ROM + RAM (plain mapping)", tag, owner, clock, "generic_romram_plain", __FILE__) +{ +} + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +READ8_MEMBER(generic_rom_plain_device::read_rom) +{ + if (offset < m_rom_size) + return m_rom[offset]; + else + return 0xff; +} + +READ16_MEMBER(generic_rom_plain_device::read16_rom) +{ + UINT16 *ROM = (UINT16 *)m_rom; + if (offset < m_rom_size/2) + return ROM[offset]; + else + return 0xffff; +} + +READ32_MEMBER(generic_rom_plain_device::read32_rom) +{ + UINT32 *ROM = (UINT32 *)m_rom; + if (offset < m_rom_size/4) + return ROM[offset]; + else + return 0xffffffff; +} + + +READ8_MEMBER(generic_rom_linear_device::read_rom) +{ + return m_rom[offset % m_rom_size]; +} + +READ16_MEMBER(generic_rom_linear_device::read16_rom) +{ + UINT16 *ROM = (UINT16 *)m_rom; + return ROM[offset % (m_rom_size/2)]; +} + +READ32_MEMBER(generic_rom_linear_device::read32_rom) +{ + UINT32 *ROM = (UINT32 *)m_rom; + return ROM[offset % (m_rom_size/4)]; +} + + +READ8_MEMBER(generic_romram_plain_device::read_ram) +{ + if (offset < m_ram.size()) + return m_ram[offset]; + else + return 0xff; +} + +WRITE8_MEMBER(generic_romram_plain_device::write_ram) +{ + if (offset < m_ram.size()) + m_ram[offset] = data; +} diff --git a/src/devices/bus/generic/rom.h b/src/devices/bus/generic/rom.h new file mode 100644 index 00000000000..f6c9da14341 --- /dev/null +++ b/src/devices/bus/generic/rom.h @@ -0,0 +1,75 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __GENERIC_ROM_H +#define __GENERIC_ROM_H + +#include "slot.h" + + +// ======================> generic_rom_device + +class generic_rom_device : public device_t, + public device_generic_cart_interface +{ +public: + // construction/destruction + generic_rom_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + // device-level overrides + virtual void device_start() {} +}; + + +// ======================> generic_rom_plain_device + +class generic_rom_plain_device : public generic_rom_device +{ +public: + // construction/destruction + generic_rom_plain_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + generic_rom_plain_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_rom); + virtual DECLARE_READ16_MEMBER(read16_rom); + virtual DECLARE_READ32_MEMBER(read32_rom); +}; + + +// ======================> generic_romram_plain_device + +class generic_romram_plain_device : public generic_rom_plain_device +{ +public: + // construction/destruction + generic_romram_plain_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_ram); + virtual DECLARE_WRITE8_MEMBER(write_ram); +}; + + +// ======================> generic_rom_linear_device + +class generic_rom_linear_device : public generic_rom_device +{ +public: + // construction/destruction + generic_rom_linear_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_rom); + virtual DECLARE_READ16_MEMBER(read16_rom); + virtual DECLARE_READ32_MEMBER(read32_rom); +}; + + + +// device type definition +extern const device_type GENERIC_ROM_PLAIN; +extern const device_type GENERIC_ROM_LINEAR; +extern const device_type GENERIC_ROMRAM_PLAIN; + + +#endif diff --git a/src/devices/bus/generic/slot.c b/src/devices/bus/generic/slot.c new file mode 100644 index 00000000000..f88740cc048 --- /dev/null +++ b/src/devices/bus/generic/slot.c @@ -0,0 +1,283 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + Generic ROM / RAM Socket and Cartslot device + + This device offers basic RAM / ROM allocation and access + + The available handlers are suited for any situation where a system opens a + "window" over a ROM or RAM area and we want to access it during emulation. + + This device is not suited whenever the system exposes additional lines to + the socket/slot: e.g. whenever input/output lines are present, whenever + there are lines controlling bankswitch / paging, and whenever different + cart configurations have to be supported (like some PCBs containing ROM + only, and other containing both ROM and RAM) + In the latter situations, per-system slot devices have to be created (see + e.g. APF cart slot device for an example of a simple device with multiple + pcbs supported) + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "slot.h" + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type GENERIC_SOCKET = &device_creator; + + +//------------------------------------------------- +// device_generic_cart_interface - constructor +//------------------------------------------------- + +device_generic_cart_interface::device_generic_cart_interface(const machine_config &mconfig, device_t &device) + : device_slot_card_interface(mconfig, device), + m_rom(NULL), + m_rom_size(0) +{ +} + + +//------------------------------------------------- +// ~device_generic_cart_interface - destructor +//------------------------------------------------- + +device_generic_cart_interface::~device_generic_cart_interface() +{ +} + +//------------------------------------------------- +// rom_alloc - alloc the space for the cart +//------------------------------------------------- + +void device_generic_cart_interface::rom_alloc(size_t size, int width, endianness_t endian, const char *tag) +{ + if (m_rom == NULL) + { + m_rom = device().machine().memory().region_alloc(std::string(tag).append(GENERIC_ROM_REGION_TAG).c_str(), size, width, endian)->base(); + m_rom_size = size; + } +} + + +//------------------------------------------------- +// ram_alloc - alloc the space for the ram +//------------------------------------------------- + +void device_generic_cart_interface::ram_alloc(UINT32 size) +{ + m_ram.resize(size); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// generic_slot_device - constructor +//------------------------------------------------- +generic_slot_device::generic_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, GENERIC_SOCKET, "Generic ROM Socket / RAM Socket / Cartridge Slot", tag, owner, clock, "generic_socket", __FILE__), + device_image_interface(mconfig, *this), + device_slot_interface(mconfig, *this), + m_interface(NULL), + m_default_card("rom"), + m_extensions("bin"), + m_must_be_loaded(FALSE), + m_width(GENERIC_ROM8_WIDTH), + m_endianness(ENDIANNESS_LITTLE) +{ +} + + +//------------------------------------------------- +// generic_slot_device - destructor +//------------------------------------------------- + +generic_slot_device::~generic_slot_device() +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void generic_slot_device::device_start() +{ + m_cart = dynamic_cast(get_card_device()); +} + +//------------------------------------------------- +// device_config_complete - perform any +// operations now that the configuration is +// complete +//------------------------------------------------- + +void generic_slot_device::device_config_complete() +{ + // set brief and instance name + update_names(); +} + + +/*------------------------------------------------- + call load + -------------------------------------------------*/ + +bool generic_slot_device::call_load() +{ + if (m_cart) + { + if (!m_device_image_load.isnull()) + return m_device_image_load(*this); + else + { + UINT32 len = common_get_size("rom"); + + rom_alloc(len, m_width, m_endianness); + common_load_rom(get_rom_base(), len, "rom"); + + return IMAGE_INIT_PASS; + } + } + + return IMAGE_INIT_PASS; +} + + +/*------------------------------------------------- + call_unload + -------------------------------------------------*/ + +void generic_slot_device::call_unload() +{ + if (!m_device_image_unload.isnull()) + return m_device_image_unload(*this); +} + + +/*------------------------------------------------- + call softlist load + -------------------------------------------------*/ + +bool generic_slot_device::call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry) +{ + load_software_part_region(*this, swlist, swname, start_entry); + return TRUE; +} + + + +/*------------------------------------------------- + get default card software + -------------------------------------------------*/ + +void generic_slot_device::get_default_card_software(std::string &result) +{ + software_get_default_slot(result, m_default_card); +} + + +/************************************************** + + Implementation + + **************************************************/ + + +/*------------------------------------------------- + common_get_size - it gets image file size both + for fullpath and for softlist + -------------------------------------------------*/ + +UINT32 generic_slot_device::common_get_size(const char *region) +{ + // if we are loading from softlist, you have to specify a region + assert((software_entry() == NULL) || (region != NULL)); + + return (software_entry() == NULL) ? length() : get_software_region_length(region); +} + +/*------------------------------------------------- + common_load_rom - it loads from image file both + for fullpath and for softlist + -------------------------------------------------*/ + +void generic_slot_device::common_load_rom(UINT8 *ROM, UINT32 len, const char *region) +{ + // basic sanity check + assert((ROM != NULL) && (len > 0)); + + // if we are loading from softlist, you have to specify a region + assert((software_entry() == NULL) || (region != NULL)); + + if (software_entry() == NULL) + fread(ROM, len); + else + memcpy(ROM, get_software_region(region), len); +} + +/*------------------------------------------------- + read_rom + -------------------------------------------------*/ + +READ8_MEMBER(generic_slot_device::read_rom) +{ + if (m_cart) + return m_cart->read_rom(space, offset); + else + return 0xff; +} + +/*------------------------------------------------- + read16_rom + -------------------------------------------------*/ + +READ16_MEMBER(generic_slot_device::read16_rom) +{ + if (m_cart) + return m_cart->read16_rom(space, offset, mem_mask); + else + return 0xffff; +} + +/*------------------------------------------------- + read32_rom + -------------------------------------------------*/ + +READ32_MEMBER(generic_slot_device::read32_rom) +{ + if (m_cart) + return m_cart->read32_rom(space, offset, mem_mask); + else + return 0xffffffff; +} + +/*------------------------------------------------- + read_ram + -------------------------------------------------*/ + +READ8_MEMBER(generic_slot_device::read_ram) +{ + if (m_cart) + return m_cart->read_ram(space, offset); + else + return 0xff; +} + +/*------------------------------------------------- + write_ram + -------------------------------------------------*/ + +WRITE8_MEMBER(generic_slot_device::write_ram) +{ + if (m_cart) + m_cart->write_ram(space, offset, data); +} diff --git a/src/devices/bus/generic/slot.h b/src/devices/bus/generic/slot.h new file mode 100644 index 00000000000..7c8725e89a7 --- /dev/null +++ b/src/devices/bus/generic/slot.h @@ -0,0 +1,176 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __GENERIC_SLOT_H +#define __GENERIC_SLOT_H + +/*************************************************************************** + TYPE DEFINITIONS + ***************************************************************************/ + + +// ======================> device_generic_cart_interface + +class device_generic_cart_interface : public device_slot_card_interface +{ +public: + // construction/destruction + device_generic_cart_interface(const machine_config &mconfig, device_t &device); + virtual ~device_generic_cart_interface(); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_rom) { return 0xff; } + virtual DECLARE_READ16_MEMBER(read16_rom) { return 0xffff; } + virtual DECLARE_READ32_MEMBER(read32_rom) { return 0xffffffff; } + + virtual DECLARE_READ8_MEMBER(read_ram) { return 0xff; } + virtual DECLARE_WRITE8_MEMBER(write_ram) {}; + + virtual void rom_alloc(size_t size, int width, endianness_t end, const char *tag); + virtual void ram_alloc(UINT32 size); + + UINT8* get_rom_base() { return m_rom; } + UINT32 get_rom_size() { return m_rom_size; } + + UINT8* get_ram_base() { return &m_ram[0]; } + UINT32 get_ram_size() { return m_ram.size(); } + + void save_ram() { device().save_item(NAME(m_ram)); } + + // internal state + UINT8 *m_rom; + UINT32 m_rom_size; + dynamic_buffer m_ram; +}; + + +enum +{ + GENERIC_ROM8_WIDTH = 1, + GENERIC_ROM16_WIDTH = 2, + GENERIC_ROM32_WIDTH = 4 +}; + +#define GENERIC_ROM_REGION_TAG ":cart:rom" + + + +#define MCFG_GENERIC_MANDATORY \ + static_cast(device)->set_must_be_loaded(TRUE); + +#define MCFG_GENERIC_WIDTH(_width) \ + static_cast(device)->set_width(_width); + +#define MCFG_GENERIC_ENDIAN(_endianness) \ + static_cast(device)->set_endian(_endianness); + +#define MCFG_GENERIC_DEFAULT_CARD(_def_card) \ + static_cast(device)->set_default_card(_def_card); + +#define MCFG_GENERIC_INTERFACE(_intf) \ + static_cast(device)->set_interface(_intf); + +#define MCFG_GENERIC_EXTENSIONS(_ext) \ + static_cast(device)->set_extensions(_ext); + +#define MCFG_GENERIC_LOAD(_class, _method) \ + generic_slot_device::static_set_device_load(*device, device_image_load_delegate(&DEVICE_IMAGE_LOAD_NAME(_class,_method), #_class "::device_image_load_" #_method, downcast<_class *>(owner))); + +#define MCFG_GENERIC_UNLOAD(_class, _method) \ + generic_slot_device::static_set_device_unload(*device, device_image_func_delegate(&DEVICE_IMAGE_UNLOAD_NAME(_class,_method), #_class "::device_image_unload_" #_method, downcast<_class *>(owner))); + + + +// ======================> generic_slot_device + +class generic_slot_device : public device_t, + public device_image_interface, + public device_slot_interface +{ +public: + // construction/destruction + generic_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual ~generic_slot_device(); + + static void static_set_device_load(device_t &device, device_image_load_delegate callback) { downcast(device).m_device_image_load = callback; } + static void static_set_device_unload(device_t &device, device_image_func_delegate callback) { downcast(device).m_device_image_unload = callback; } + + void set_interface(const char * interface) { m_interface = interface; } + void set_default_card(const char * def) { m_default_card = def; } + void set_extensions(const char * exts) { m_extensions = exts; } + void set_must_be_loaded(bool mandatory) { m_must_be_loaded = mandatory; } + void set_width(int width) { m_width = width; } + void set_endian(endianness_t end) { m_endianness = end; } + + // device-level overrides + virtual void device_start(); + virtual void device_config_complete(); + + // image-level overrides + virtual bool call_load(); + virtual void call_unload(); + virtual bool call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry); + + UINT32 common_get_size(const char *region); + void common_load_rom(UINT8 *ROM, UINT32 len, const char *region); + + virtual iodevice_t image_type() const { return IO_CARTSLOT; } + virtual bool is_readable() const { return 1; } + virtual bool is_writeable() const { return 0; } + virtual bool is_creatable() const { return 0; } + virtual bool must_be_loaded() const { return m_must_be_loaded; } + virtual bool is_reset_on_load() const { return 1; } + virtual const option_guide *create_option_guide() const { return NULL; } + virtual const char *image_interface() const { return m_interface; } + virtual const char *file_extensions() const { return m_extensions; } + + // slot interface overrides + virtual void get_default_card_software(std::string &result); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_rom); + virtual DECLARE_READ16_MEMBER(read16_rom); + virtual DECLARE_READ32_MEMBER(read32_rom); + + virtual DECLARE_READ8_MEMBER(read_ram); + virtual DECLARE_WRITE8_MEMBER(write_ram); + + virtual void rom_alloc(size_t size, int width, endianness_t end) { if (m_cart) m_cart->rom_alloc(size, width, end, tag()); } + virtual void ram_alloc(UINT32 size) { if (m_cart) m_cart->ram_alloc(size); } + + UINT8* get_rom_base() { if (m_cart) return m_cart->get_rom_base(); return NULL; } + UINT8* get_ram_base() { if (m_cart) return m_cart->get_ram_base(); return NULL; } + UINT32 get_rom_size() { if (m_cart) return m_cart->get_rom_size(); return 0; } + + void save_ram() { if (m_cart && m_cart->get_ram_size()) m_cart->save_ram(); } + +protected: + + const char *m_interface; + const char *m_default_card; + const char *m_extensions; + bool m_must_be_loaded; + int m_width; + endianness_t m_endianness; + device_generic_cart_interface *m_cart; + device_image_load_delegate m_device_image_load; + device_image_func_delegate m_device_image_unload; +}; + + +// device type definition +extern const device_type GENERIC_SOCKET; + + +/*************************************************************************** + DEVICE CONFIGURATION MACROS + ***************************************************************************/ + +#define MCFG_GENERIC_CARTSLOT_ADD(_tag, _slot_intf, _dev_intf) \ + MCFG_DEVICE_ADD(_tag, GENERIC_SOCKET, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, NULL, false) \ + MCFG_GENERIC_INTERFACE(_dev_intf) +#define MCFG_GENERIC_SOCKET_ADD(_tag, _slot_intf, _dev_intf) \ + MCFG_DEVICE_ADD(_tag, GENERIC_SOCKET, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, NULL, false) \ + MCFG_GENERIC_INTERFACE(_dev_intf) +#endif diff --git a/src/devices/bus/ieee488/c2031.c b/src/devices/bus/ieee488/c2031.c new file mode 100644 index 00000000000..b26c27c2ff6 --- /dev/null +++ b/src/devices/bus/ieee488/c2031.c @@ -0,0 +1,482 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Commodore 2031 Single Disk Drive emulation + +**********************************************************************/ + +#include "c2031.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define M6502_TAG "ucd5" +#define M6522_0_TAG "uab1" +#define M6522_1_TAG "ucd4" +#define C64H156_TAG "64h156" + + +enum +{ + LED_POWER = 0, + LED_ACT +}; + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type C2031 = &device_creator; + + +//------------------------------------------------- +// ROM( c2031 ) +//------------------------------------------------- + +ROM_START( c2031 ) + ROM_REGION( 0x4000, M6502_TAG, 0 ) + ROM_LOAD( "901484-03.u5f", 0x0000, 0x2000, CRC(ee4b893b) SHA1(54d608f7f07860f24186749f21c96724dd48bc50) ) + ROM_LOAD( "901484-05.u5h", 0x2000, 0x2000, CRC(6a629054) SHA1(ec6b75ecfdd4744e5d57979ef6af990444c11ae1) ) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *c2031_device::device_rom_region() const +{ + return ROM_NAME( c2031 ); +} + + +//------------------------------------------------- +// ADDRESS_MAP( c2031_mem ) +//------------------------------------------------- + +static ADDRESS_MAP_START( c2031_mem, AS_PROGRAM, 8, c2031_device ) + AM_RANGE(0x0000, 0x07ff) AM_MIRROR(0x6000) AM_RAM + AM_RANGE(0x1800, 0x180f) AM_MIRROR(0x63f0) AM_DEVREADWRITE(M6522_0_TAG, via6522_device, read, write) + AM_RANGE(0x1c00, 0x1c0f) AM_MIRROR(0x63f0) AM_DEVREADWRITE(M6522_1_TAG, via6522_device, read, write) + AM_RANGE(0x8000, 0xbfff) AM_MIRROR(0x4000) AM_ROM AM_REGION(M6502_TAG, 0) +ADDRESS_MAP_END + + +WRITE_LINE_MEMBER( c2031_device::via0_irq_w ) +{ + m_via0_irq = state; + + m_maincpu->set_input_line(INPUT_LINE_IRQ0, (m_via0_irq || m_via1_irq) ? ASSERT_LINE : CLEAR_LINE); +} + +READ8_MEMBER( c2031_device::via0_pa_r ) +{ + /* + + bit description + + PA0 DI0 + PA1 DI1 + PA2 DI2 + PA3 DI3 + PA4 DI4 + PA5 DI5 + PA6 DI6 + PA7 DI7 + + */ + + return m_bus->dio_r(); +} + +WRITE8_MEMBER( c2031_device::via0_pa_w ) +{ + /* + + bit description + + PA0 DI0 + PA1 DI1 + PA2 DI2 + PA3 DI3 + PA4 DI4 + PA5 DI5 + PA6 DI6 + PA7 DI7 + + */ + + m_bus->dio_w(this, data); +} + +READ8_MEMBER( c2031_device::via0_pb_r ) +{ + /* + + bit description + + PB0 ATNA + PB1 NRFD + PB2 NDAC + PB3 EOI + PB4 T/_R + PB5 HD SEL + PB6 DAV + PB7 _ATN + + */ + + UINT8 data = 0; + + // not ready for data + data |= m_bus->nrfd_r() << 1; + + // not data accepted + data |= m_bus->ndac_r() << 2; + + // end or identify + data |= m_bus->eoi_r() << 3; + + // data valid + data |= m_bus->dav_r() << 6; + + // attention + data |= !m_bus->atn_r() << 7; + + return data; +} + +WRITE8_MEMBER( c2031_device::via0_pb_w ) +{ + /* + + bit description + + PB0 ATNA + PB1 NRFD + PB2 NDAC + PB3 EOI + PB4 T/_R + PB5 HD SEL + PB6 DAV + PB7 _ATN + + */ + + int atna = BIT(data, 0); + int nrfd = BIT(data, 1); + int ndac = BIT(data, 2); + + // not ready for data + m_nrfd_out = nrfd; + + // not data accepted + m_ndac_out = ndac; + + // end or identify + m_bus->eoi_w(this, BIT(data, 3)); + + // data valid + m_bus->dav_w(this, BIT(data, 6)); + + // attention acknowledge + m_atna = atna; + + if ((!m_bus->atn_r()) ^ atna) + { + nrfd = ndac = 0; + } + + m_bus->nrfd_w(this, nrfd); + m_bus->ndac_w(this, ndac); + + m_via0->write_ca2(get_device_number()); +} + + +WRITE_LINE_MEMBER( c2031_device::via1_irq_w ) +{ + m_via1_irq = state; + + m_maincpu->set_input_line(INPUT_LINE_IRQ0, (m_via0_irq || m_via1_irq) ? ASSERT_LINE : CLEAR_LINE); +} + +READ8_MEMBER( c2031_device::via1_pb_r ) +{ + /* + + bit signal description + + PB0 + PB1 + PB2 + PB3 + PB4 WPS write protect sense + PB5 + PB6 + PB7 SYNC SYNC detect line + + */ + + UINT8 data = 0; + + // write protect sense + data |= !m_floppy->wpt_r() << 4; + + // SYNC detect line + data |= m_ga->sync_r() << 7; + + return data; +} + +WRITE8_MEMBER( c2031_device::via1_pb_w ) +{ + /* + + bit signal description + + PB0 STP0 stepping motor bit 0 + PB1 STP1 stepping motor bit 1 + PB2 MTR motor ON/OFF + PB3 ACT drive 0 LED + PB4 + PB5 DS0 density select 0 + PB6 DS1 density select 1 + PB7 SYNC SYNC detect line + + */ + + // spindle motor + m_ga->mtr_w(BIT(data, 2)); + + // stepper motor + m_ga->stp_w(data & 0x03); + + // activity LED + output_set_led_value(LED_ACT, BIT(data, 3)); + + // density select + m_ga->ds_w((data >> 5) & 0x03); +} + + +//------------------------------------------------- +// C64H156_INTERFACE( ga_intf ) +//------------------------------------------------- + +WRITE_LINE_MEMBER( c2031_device::byte_w ) +{ + m_maincpu->set_input_line(M6502_SET_OVERFLOW, state); + + m_via1->write_ca1(state); +} + + +//------------------------------------------------- +// SLOT_INTERFACE( c2031_floppies ) +//------------------------------------------------- + +static SLOT_INTERFACE_START( c2031_floppies ) + SLOT_INTERFACE( "525ssqd", FLOPPY_525_SSQD ) +SLOT_INTERFACE_END + + +//------------------------------------------------- +// FLOPPY_FORMATS( floppy_formats ) +//------------------------------------------------- + +FLOPPY_FORMATS_MEMBER( c2031_device::floppy_formats ) + FLOPPY_D64_FORMAT, + FLOPPY_G64_FORMAT +FLOPPY_FORMATS_END + + +//------------------------------------------------- +// MACHINE_DRIVER( c2031 ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( c2031 ) + MCFG_CPU_ADD(M6502_TAG, M6502, XTAL_16MHz/16) + MCFG_CPU_PROGRAM_MAP(c2031_mem) + MCFG_QUANTUM_PERFECT_CPU(M6502_TAG) + + MCFG_DEVICE_ADD(M6522_0_TAG, VIA6522, XTAL_16MHz/16) + MCFG_VIA6522_READPA_HANDLER(READ8(c2031_device, via0_pa_r)) + MCFG_VIA6522_READPB_HANDLER(READ8(c2031_device, via0_pb_r)) + MCFG_VIA6522_WRITEPA_HANDLER(WRITE8(c2031_device, via0_pa_w)) + MCFG_VIA6522_WRITEPB_HANDLER(WRITE8(c2031_device, via0_pb_w)) + MCFG_VIA6522_IRQ_HANDLER(WRITELINE(c2031_device, via0_irq_w)) + + MCFG_DEVICE_ADD(M6522_1_TAG, VIA6522, XTAL_16MHz/16) + MCFG_VIA6522_READPA_HANDLER(DEVREAD8(C64H156_TAG, c64h156_device, yb_r)) + MCFG_VIA6522_READPB_HANDLER(READ8(c2031_device, via1_pb_r)) + MCFG_VIA6522_WRITEPA_HANDLER(DEVWRITE8(C64H156_TAG, c64h156_device, yb_w)) + MCFG_VIA6522_WRITEPB_HANDLER(WRITE8(c2031_device, via1_pb_w)) + MCFG_VIA6522_CA2_HANDLER(DEVWRITELINE(C64H156_TAG, c64h156_device, soe_w)) + MCFG_VIA6522_CB2_HANDLER(DEVWRITELINE(C64H156_TAG, c64h156_device, oe_w)) + MCFG_VIA6522_IRQ_HANDLER(WRITELINE(c2031_device, via1_irq_w)) + + MCFG_DEVICE_ADD(C64H156_TAG, C64H156, XTAL_16MHz) + MCFG_64H156_BYTE_CALLBACK(WRITELINE(c2031_device, byte_w)) + MCFG_FLOPPY_DRIVE_ADD(C64H156_TAG":0", c2031_floppies, "525ssqd", c2031_device::floppy_formats) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor c2031_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( c2031 ); +} + + +//------------------------------------------------- +// INPUT_PORTS( c2031 ) +//------------------------------------------------- + +static INPUT_PORTS_START( c2031 ) + PORT_START("ADDRESS") + PORT_DIPNAME( 0x03, 0x00, "Device Address" ) + PORT_DIPSETTING( 0x00, "8" ) + PORT_DIPSETTING( 0x01, "9" ) + PORT_DIPSETTING( 0x02, "10" ) + PORT_DIPSETTING( 0x03, "11" ) +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor c2031_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( c2031 ); +} + + + +//************************************************************************** +// INLINE HELPERS +//************************************************************************** + +//------------------------------------------------- +// get_device_number - +//------------------------------------------------- + +inline int c2031_device::get_device_number() +{ + int state = 1; + + switch ((m_slot->get_address() - 8) & 0x03) + { + case 0: state = (m_atna && m_nrfd_out); break; + case 1: state = m_nrfd_out; break; + case 2: state = m_atna; break; + case 3: state = 1; break; + } + + return state; +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// c2031_device - constructor +//------------------------------------------------- + +c2031_device::c2031_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, C2031, "C2031", tag, owner, clock, "c2031", __FILE__), + device_ieee488_interface(mconfig, *this), + m_maincpu(*this, M6502_TAG), + m_via0(*this, M6522_0_TAG), + m_via1(*this, M6522_1_TAG), + m_ga(*this, C64H156_TAG), + m_floppy(*this, C64H156_TAG":0:525ssqd"), + m_address(*this, "ADDRESS"), + m_nrfd_out(1), + m_ndac_out(1), + m_atna(1), + m_via0_irq(0), + m_via1_irq(0) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void c2031_device::device_start() +{ + // install image callbacks + m_ga->set_floppy(m_floppy); + + // register for state saving + save_item(NAME(m_nrfd_out)); + save_item(NAME(m_ndac_out)); + save_item(NAME(m_atna)); + save_item(NAME(m_via0_irq)); + save_item(NAME(m_via1_irq)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void c2031_device::device_reset() +{ + m_maincpu->reset(); + + m_via0->reset(); + m_via1->reset(); +} + + +//------------------------------------------------- +// ieee488_atn_w - +//------------------------------------------------- + +void c2031_device::ieee488_atn(int state) +{ + int nrfd = m_nrfd_out; + int ndac = m_ndac_out; + + m_via0->write_ca1(!state); + + if ((!state) ^ m_atna) + { + nrfd = ndac = 0; + } + + m_bus->nrfd_w(this, nrfd); + m_bus->ndac_w(this, ndac); +} + + +//------------------------------------------------- +// ieee488_ifc_w - +//------------------------------------------------- + +void c2031_device::ieee488_ifc(int state) +{ + if (!m_ifc && state) + { + device_reset(); + } + + m_ifc = state; +} diff --git a/src/devices/bus/ieee488/c2031.h b/src/devices/bus/ieee488/c2031.h new file mode 100644 index 00000000000..8423a8c1c95 --- /dev/null +++ b/src/devices/bus/ieee488/c2031.h @@ -0,0 +1,87 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Commodore 2031 Single Disk Drive emulation + +**********************************************************************/ + +#pragma once + +#ifndef __C2031__ +#define __C2031__ + +#include "emu.h" +#include "ieee488.h" +#include "cpu/m6502/m6502.h" +#include "machine/64h156.h" +#include "machine/6522via.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> c2031_device + +class c2031_device : public device_t, + public device_ieee488_interface +{ +public: + // construction/destruction + c2031_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + virtual ioport_constructor device_input_ports() const; + + DECLARE_WRITE_LINE_MEMBER( via0_irq_w ); + DECLARE_READ8_MEMBER( via0_pa_r ); + DECLARE_WRITE8_MEMBER( via0_pa_w ); + DECLARE_READ8_MEMBER( via0_pb_r ); + DECLARE_WRITE8_MEMBER( via0_pb_w ); + DECLARE_WRITE_LINE_MEMBER( via1_irq_w ); + DECLARE_READ8_MEMBER( via1_pb_r ); + DECLARE_WRITE8_MEMBER( via1_pb_w ); + DECLARE_WRITE_LINE_MEMBER( byte_w ); + + DECLARE_FLOPPY_FORMATS( floppy_formats ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_ieee488_interface overrides + virtual void ieee488_atn(int state); + virtual void ieee488_ifc(int state); + + inline int get_device_number(); + + required_device m_maincpu; + required_device m_via0; + required_device m_via1; + required_device m_ga; + required_device m_floppy; + required_ioport m_address; + + // IEEE-488 bus + int m_nrfd_out; // not ready for data + int m_ndac_out; // not data accepted + int m_atna; // attention acknowledge + int m_ifc; + + // interrupts + int m_via0_irq; // VIA #0 interrupt request + int m_via1_irq; // VIA #1 interrupt request +}; + + +// device type definition +extern const device_type C2031; + + + +#endif diff --git a/src/devices/bus/ieee488/c2040.c b/src/devices/bus/ieee488/c2040.c new file mode 100644 index 00000000000..8ce2856e371 --- /dev/null +++ b/src/devices/bus/ieee488/c2040.c @@ -0,0 +1,802 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Commodore 2040/3040/4040 Disk Drive emulation + +**********************************************************************/ + +/* + + 2040/3040 disk initialization + ----------------------------- + You need to initialize each diskette before trying to access it + or you will get a DISK ID MISMATCH error upon disk commands. + On the 4040 this is done automatically by the DOS. + + open 15,8,15:print 15,"i":close 15 + + List directory + -------------- + directory / diR + + Format disk + ----------- + header "label,id",d0,i01 + + Load file + --------- + dload "name" / dL"name + + Save file + --------- + dsave "name" / dS"name + +*/ + +/* + + TODO: + + - 2040/3040/4040 have a Shugart SA390 drive (FLOPPY_525_SSSD_35T) + + - 2040 DOS 1 FDC rom (jumps to 104d while getting block header) + + FE70: jsr $104D + 104D: m6502_brk#$00 + +*/ + +#include "c2040.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define M6502_TAG "un1" +#define M6532_0_TAG "uc1" +#define M6532_1_TAG "ue1" +#define M6504_TAG "uh3" +#define M6522_TAG "um3" +#define M6530_TAG "uk3" +#define FDC_TAG "fdc" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type C2040 = &device_creator; +const device_type C3040 = &device_creator; +const device_type C4040 = &device_creator; + + +//------------------------------------------------- +// ROM( c2040 ) +//------------------------------------------------- + +ROM_START( c2040 ) // schematic 320806, DOS 1.0 + ROM_REGION( 0x3000, M6502_TAG, 0 ) + ROM_DEFAULT_BIOS("dos12") + ROM_LOAD( "901468-xx.ul1", 0x1000, 0x1000, NO_DUMP ) + ROM_LOAD( "901468-xx.uh1", 0x2000, 0x1000, NO_DUMP ) + + ROM_REGION( 0x400, M6504_TAG, 0 ) + ROM_LOAD( "901466-01.uk3", 0x000, 0x400, CRC(9d1e25ce) SHA1(d539858f839f96393f218307df7394362a84a26a) ) + + ROM_REGION( 0x800, "gcr", 0) + ROM_LOAD( "901467.uk6", 0x000, 0x800, CRC(a23337eb) SHA1(97df576397608455616331f8e837cb3404363fa2) ) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *c2040_t::device_rom_region() const +{ + return ROM_NAME( c2040 ); +} + + +//------------------------------------------------- +// ROM( c3040 ) +//------------------------------------------------- + +ROM_START( c3040 ) // schematic 320806, DOS 1.2 + ROM_REGION( 0x3000, M6502_TAG, 0 ) + ROM_LOAD( "901468-06.ul1", 0x1000, 0x1000, CRC(25b5eed5) SHA1(4d9658f2e6ff3276e5c6e224611a66ce44b16fc7) ) + ROM_LOAD( "901468-07.uh1", 0x2000, 0x1000, CRC(9b09ae83) SHA1(6a51c7954938439ca8342fc295bda050c06e1791) ) + + ROM_REGION( 0x400, M6504_TAG, 0 ) + ROM_LOAD( "901466-02.uk3", 0x000, 0x400, CRC(9d1e25ce) SHA1(d539858f839f96393f218307df7394362a84a26a) ) + + ROM_REGION( 0x800, "gcr", 0) + ROM_LOAD( "901467.uk6", 0x000, 0x800, CRC(a23337eb) SHA1(97df576397608455616331f8e837cb3404363fa2) ) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *c3040_t::device_rom_region() const +{ + return ROM_NAME( c3040 ); +} + + +//------------------------------------------------- +// ROM( c4040 ) +//------------------------------------------------- + +ROM_START( c4040 ) // schematic ? + ROM_REGION( 0x3000, M6502_TAG, 0 ) + ROM_DEFAULT_BIOS("dos20r2") + ROM_SYSTEM_BIOS( 0, "dos20r1", "DOS 2.0 Revision 1" ) + ROMX_LOAD( "901468-11.uj1", 0x0000, 0x1000, CRC(b7157458) SHA1(8415f3159dea73161e0cef7960afa6c76953b6f8), ROM_BIOS(1) ) + ROMX_LOAD( "901468-12.ul1", 0x1000, 0x1000, CRC(02c44ff9) SHA1(e8a94f239082d45f64f01b2d8e488d18fe659cbb), ROM_BIOS(1) ) + ROMX_LOAD( "901468-13.uh1", 0x2000, 0x1000, CRC(cbd785b3) SHA1(6ada7904ac9d13c3f1c0a8715f9c4be1aa6eb0bb), ROM_BIOS(1) ) + ROM_SYSTEM_BIOS( 1, "dos20r2", "DOS 2.0 Revision 2" ) + ROMX_LOAD( "901468-14.uj1", 0x0000, 0x1000, CRC(bc4d4872) SHA1(ffb992b82ec913ddff7be964d7527aca3e21580c), ROM_BIOS(2) ) + ROMX_LOAD( "901468-15.ul1", 0x1000, 0x1000, CRC(b6970533) SHA1(f702d6917fe8a798740ba4d467b500944ae7b70a), ROM_BIOS(2) ) + ROMX_LOAD( "901468-16.uh1", 0x2000, 0x1000, CRC(1f5eefb7) SHA1(04b918cf4adeee8015b43383d3cea7288a7d0aa8), ROM_BIOS(2) ) + + ROM_REGION( 0x400, M6504_TAG, 0 ) + // RIOT DOS 2 + ROM_LOAD( "901466-04.uk3", 0x000, 0x400, CRC(0ab338dc) SHA1(6645fa40b81be1ff7d1384e9b52df06a26ab0bfb) ) + + ROM_REGION( 0x800, "gcr", 0) + ROM_LOAD( "901467.uk6", 0x000, 0x800, CRC(a23337eb) SHA1(97df576397608455616331f8e837cb3404363fa2) ) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *c4040_t::device_rom_region() const +{ + return ROM_NAME( c4040 ); +} + + +//------------------------------------------------- +// ADDRESS_MAP( c2040_main_mem ) +//------------------------------------------------- + +static ADDRESS_MAP_START( c2040_main_mem, AS_PROGRAM, 8, c2040_t ) + ADDRESS_MAP_GLOBAL_MASK(0x7fff) + AM_RANGE(0x0000, 0x007f) AM_MIRROR(0x0100) AM_DEVICE(M6532_0_TAG, mos6532_t, ram_map) + AM_RANGE(0x0080, 0x00ff) AM_MIRROR(0x0100) AM_DEVICE(M6532_1_TAG, mos6532_t, ram_map) + AM_RANGE(0x0200, 0x021f) AM_MIRROR(0x0d60) AM_DEVICE(M6532_0_TAG, mos6532_t, io_map) + AM_RANGE(0x0280, 0x029f) AM_MIRROR(0x0d60) AM_DEVICE(M6532_1_TAG, mos6532_t, io_map) + AM_RANGE(0x1000, 0x13ff) AM_MIRROR(0x0c00) AM_RAM AM_SHARE("share1") + AM_RANGE(0x2000, 0x23ff) AM_MIRROR(0x0c00) AM_RAM AM_SHARE("share2") + AM_RANGE(0x3000, 0x33ff) AM_MIRROR(0x0c00) AM_RAM AM_SHARE("share3") + AM_RANGE(0x4000, 0x43ff) AM_MIRROR(0x0c00) AM_RAM AM_SHARE("share4") + AM_RANGE(0x5000, 0x7fff) AM_ROM AM_REGION(M6502_TAG, 0) +ADDRESS_MAP_END + + +//------------------------------------------------- +// ADDRESS_MAP( c2040_fdc_mem ) +//------------------------------------------------- + +static ADDRESS_MAP_START( c2040_fdc_mem, AS_PROGRAM, 8, c2040_t ) + ADDRESS_MAP_GLOBAL_MASK(0x1fff) + AM_RANGE(0x0000, 0x003f) AM_MIRROR(0x0300) AM_DEVICE(M6530_TAG, mos6530_t, ram_map) + AM_RANGE(0x0040, 0x004f) AM_MIRROR(0x0330) AM_DEVICE(M6522_TAG, via6522_device, map) + AM_RANGE(0x0080, 0x008f) AM_MIRROR(0x0330) AM_DEVICE(M6530_TAG, mos6530_t, io_map) + AM_RANGE(0x0400, 0x07ff) AM_RAM AM_SHARE("share1") + AM_RANGE(0x0800, 0x0bff) AM_RAM AM_SHARE("share2") + AM_RANGE(0x0c00, 0x0fff) AM_RAM AM_SHARE("share3") + AM_RANGE(0x1000, 0x13ff) AM_RAM AM_SHARE("share4") + AM_RANGE(0x1c00, 0x1fff) AM_ROM AM_REGION(M6504_TAG, 0) +ADDRESS_MAP_END + + +//------------------------------------------------- +// riot6532 uc1 +//------------------------------------------------- + +READ8_MEMBER( c2040_t::dio_r ) +{ + /* + + bit description + + PA0 DI0 + PA1 DI1 + PA2 DI2 + PA3 DI3 + PA4 DI4 + PA5 DI5 + PA6 DI6 + PA7 DI7 + + */ + + return m_bus->dio_r(); +} + +WRITE8_MEMBER( c2040_t::dio_w ) +{ + /* + + bit description + + PB0 DO0 + PB1 DO1 + PB2 DO2 + PB3 DO3 + PB4 DO4 + PB5 DO5 + PB6 DO6 + PB7 DO7 + + */ + + m_bus->dio_w(this, data); +} + + +//------------------------------------------------- +// riot6532 ue1 +//------------------------------------------------- + +READ8_MEMBER( c2040_t::riot1_pa_r ) +{ + /* + + bit description + + PA0 ATNA + PA1 DACO + PA2 RFDO + PA3 EOIO + PA4 DAVO + PA5 EOII + PA6 DAVI + PA7 _ATN + + */ + + UINT8 data = 0; + + // end or identify in + data |= m_bus->eoi_r() << 5; + + // data valid in + data |= m_bus->dav_r() << 6; + + // attention + data |= !m_bus->atn_r() << 7; + + return data; +} + +WRITE8_MEMBER( c2040_t::riot1_pa_w ) +{ + /* + + bit description + + PA0 ATNA + PA1 DACO + PA2 RFDO + PA3 EOIO + PA4 DAVO + PA5 EOII + PA6 DAVI + PA7 _ATN + + */ + + // attention acknowledge + m_atna = BIT(data, 0); + + // data accepted out + m_daco = BIT(data, 1); + + // not ready for data out + m_rfdo = BIT(data, 2); + + // end or identify out + m_bus->eoi_w(this, BIT(data, 3)); + + // data valid out + m_bus->dav_w(this, BIT(data, 4)); + + update_ieee_signals(); +} + +READ8_MEMBER( c2040_t::riot1_pb_r ) +{ + /* + + bit description + + PB0 DEVICE NUMBER SELECTION + PB1 DEVICE NUMBER SELECTION + PB2 DEVICE NUMBER SELECTION + PB3 + PB4 + PB5 + PB6 DACI + PB7 RFDI + + */ + + UINT8 data = 0; + + // device number selection + data |= m_slot->get_address() - 8; + + // data accepted in + data |= m_bus->ndac_r() << 6; + + // ready for data in + data |= m_bus->nrfd_r() << 7; + + return data; +} + +WRITE8_MEMBER( c2040_t::riot1_pb_w ) +{ + /* + + bit description + + PB0 + PB1 + PB2 + PB3 ACT LED 1 + PB4 ACT LED 0 + PB5 ERR LED + PB6 + PB7 + + */ + + // activity led 1 + output_set_led_value(LED_ACT1, BIT(data, 3)); + + // activity led 0 + output_set_led_value(LED_ACT0, BIT(data, 4)); + + // error led + output_set_led_value(LED_ERR, BIT(data, 5)); +} + + +WRITE8_MEMBER( c2040_t::via_pb_w ) +{ + /* + + bit description + + PB0 S1A + PB1 S1B + PB2 S0A + PB3 S0B + PB4 MTR1 + PB5 MTR0 + PB6 + PB7 + + */ + + // spindle motor 1 + m_fdc->mtr1_w(BIT(data, 4)); + + // spindle motor 0 + m_fdc->mtr0_w(BIT(data, 5)); + + // stepper motor 1 + m_fdc->stp1_w(data & 0x03); + + // stepper motor 0 + m_fdc->stp0_w((data >> 2) & 0x03); +} + + +//------------------------------------------------- +// SLOT_INTERFACE( c2040_floppies ) +//------------------------------------------------- + +static SLOT_INTERFACE_START( c2040_floppies ) + SLOT_INTERFACE( "525ssqd", FLOPPY_525_SSQD ) +SLOT_INTERFACE_END + + +//------------------------------------------------- +// FLOPPY_FORMATS( floppy_formats ) +//------------------------------------------------- + +FLOPPY_FORMATS_MEMBER( c2040_t::floppy_formats ) + FLOPPY_C3040_FORMAT, + FLOPPY_G64_FORMAT +FLOPPY_FORMATS_END + + +//------------------------------------------------- +// FLOPPY_FORMATS( floppy_formats ) +//------------------------------------------------- + +FLOPPY_FORMATS_MEMBER( c3040_t::floppy_formats ) + FLOPPY_C3040_FORMAT, + FLOPPY_G64_FORMAT +FLOPPY_FORMATS_END + + +//------------------------------------------------- +// FLOPPY_FORMATS( floppy_formats ) +//------------------------------------------------- + +FLOPPY_FORMATS_MEMBER( c4040_t::floppy_formats ) + FLOPPY_C4040_FORMAT, + FLOPPY_G64_FORMAT +FLOPPY_FORMATS_END + + +//------------------------------------------------- +// MACHINE_CONFIG_FRAGMENT( c2040 ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( c2040 ) + // DOS + MCFG_CPU_ADD(M6502_TAG, M6502, XTAL_16MHz/16) + MCFG_CPU_PROGRAM_MAP(c2040_main_mem) + + MCFG_DEVICE_ADD(M6532_0_TAG, MOS6532n, XTAL_16MHz/16) + MCFG_MOS6530n_IN_PA_CB(READ8(c2040_t, dio_r)) + MCFG_MOS6530n_OUT_PB_CB(WRITE8(c2040_t, dio_w)) + + MCFG_DEVICE_ADD(M6532_1_TAG, MOS6532n, XTAL_16MHz/16) + MCFG_MOS6530n_IN_PA_CB(READ8(c2040_t, riot1_pa_r)) + MCFG_MOS6530n_OUT_PA_CB(WRITE8(c2040_t, riot1_pa_w)) + MCFG_MOS6530n_IN_PB_CB(READ8(c2040_t, riot1_pb_r)) + MCFG_MOS6530n_OUT_PB_CB(WRITE8(c2040_t, riot1_pb_w)) + MCFG_MOS6530n_IRQ_CB(INPUTLINE(M6502_TAG, INPUT_LINE_IRQ0)) + + // controller + MCFG_CPU_ADD(M6504_TAG, M6504, XTAL_16MHz/16) + MCFG_CPU_PROGRAM_MAP(c2040_fdc_mem) + + MCFG_DEVICE_ADD(M6522_TAG, VIA6522, XTAL_16MHz/16) + MCFG_VIA6522_READPA_HANDLER(DEVREAD8(FDC_TAG, c2040_fdc_t, read)) + MCFG_VIA6522_WRITEPB_HANDLER(WRITE8(c2040_t, via_pb_w)) + MCFG_VIA6522_CA2_HANDLER(DEVWRITELINE(FDC_TAG, c2040_fdc_t, mode_sel_w)) + MCFG_VIA6522_CB2_HANDLER(DEVWRITELINE(FDC_TAG, c2040_fdc_t, rw_sel_w)) + + MCFG_DEVICE_ADD(M6530_TAG, MOS6530n, XTAL_16MHz/16) + MCFG_MOS6530n_OUT_PA_CB(DEVWRITE8(FDC_TAG, c2040_fdc_t, write)) + MCFG_MOS6530n_OUT_PB0_CB(DEVWRITELINE(FDC_TAG, c2040_fdc_t, drv_sel_w)) + MCFG_MOS6530n_OUT_PB1_CB(DEVWRITELINE(FDC_TAG, c2040_fdc_t, ds0_w)) + MCFG_MOS6530n_OUT_PB2_CB(DEVWRITELINE(FDC_TAG, c2040_fdc_t, ds1_w)) + MCFG_MOS6530n_OUT_PB7_CB(INPUTLINE(M6504_TAG, M6502_IRQ_LINE)) + MCFG_MOS6530n_IN_PB3_CB(DEVREADLINE(FDC_TAG, c2040_fdc_t, wps_r)) + + MCFG_DEVICE_ADD(FDC_TAG, C2040_FDC, XTAL_16MHz) + MCFG_C2040_SYNC_CALLBACK(DEVWRITELINE(M6530_TAG, mos6530_t, pb6_w)) + MCFG_C2040_READY_CALLBACK(DEVWRITELINE(M6522_TAG, via6522_device, write_ca1)) + MCFG_C2040_ERROR_CALLBACK(DEVWRITELINE(M6522_TAG, via6522_device, write_cb1)) + MCFG_FLOPPY_DRIVE_ADD(FDC_TAG":0", c2040_floppies, "525ssqd", c2040_t::floppy_formats) + MCFG_FLOPPY_DRIVE_ADD(FDC_TAG":1", c2040_floppies, "525ssqd", c2040_t::floppy_formats) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor c2040_t::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( c2040 ); +} + + +//------------------------------------------------- +// MACHINE_CONFIG_FRAGMENT( c3040 ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( c3040 ) + // DOS + MCFG_CPU_ADD(M6502_TAG, M6502, XTAL_16MHz/16) + MCFG_CPU_PROGRAM_MAP(c2040_main_mem) + + MCFG_DEVICE_ADD(M6532_0_TAG, MOS6532n, XTAL_16MHz/16) + MCFG_MOS6530n_IN_PA_CB(READ8(c2040_t, dio_r)) + MCFG_MOS6530n_OUT_PB_CB(WRITE8(c2040_t, dio_w)) + + MCFG_DEVICE_ADD(M6532_1_TAG, MOS6532n, XTAL_16MHz/16) + MCFG_MOS6530n_IN_PA_CB(READ8(c2040_t, riot1_pa_r)) + MCFG_MOS6530n_OUT_PA_CB(WRITE8(c2040_t, riot1_pa_w)) + MCFG_MOS6530n_IN_PB_CB(READ8(c2040_t, riot1_pb_r)) + MCFG_MOS6530n_OUT_PB_CB(WRITE8(c2040_t, riot1_pb_w)) + MCFG_MOS6530n_IRQ_CB(INPUTLINE(M6502_TAG, INPUT_LINE_IRQ0)) + + // controller + MCFG_CPU_ADD(M6504_TAG, M6504, XTAL_16MHz/16) + MCFG_CPU_PROGRAM_MAP(c2040_fdc_mem) + + MCFG_DEVICE_ADD(M6522_TAG, VIA6522, XTAL_16MHz/16) + MCFG_VIA6522_READPA_HANDLER(DEVREAD8(FDC_TAG, c2040_fdc_t, read)) + MCFG_VIA6522_WRITEPB_HANDLER(WRITE8(c2040_t, via_pb_w)) + MCFG_VIA6522_CA2_HANDLER(DEVWRITELINE(FDC_TAG, c2040_fdc_t, mode_sel_w)) + MCFG_VIA6522_CB2_HANDLER(DEVWRITELINE(FDC_TAG, c2040_fdc_t, rw_sel_w)) + + MCFG_DEVICE_ADD(M6530_TAG, MOS6530n, XTAL_16MHz/16) + MCFG_MOS6530n_OUT_PA_CB(DEVWRITE8(FDC_TAG, c2040_fdc_t, write)) + MCFG_MOS6530n_OUT_PB0_CB(DEVWRITELINE(FDC_TAG, c2040_fdc_t, drv_sel_w)) + MCFG_MOS6530n_OUT_PB1_CB(DEVWRITELINE(FDC_TAG, c2040_fdc_t, ds0_w)) + MCFG_MOS6530n_OUT_PB2_CB(DEVWRITELINE(FDC_TAG, c2040_fdc_t, ds1_w)) + MCFG_MOS6530n_IN_PB3_CB(DEVREADLINE(FDC_TAG, c2040_fdc_t, wps_r)) + MCFG_MOS6530n_OUT_PB7_CB(INPUTLINE(M6504_TAG, M6502_IRQ_LINE)) + + MCFG_DEVICE_ADD(FDC_TAG, C2040_FDC, XTAL_16MHz) + MCFG_C2040_SYNC_CALLBACK(DEVWRITELINE(M6530_TAG, mos6530_t, pb6_w)) + MCFG_C2040_READY_CALLBACK(DEVWRITELINE(M6522_TAG, via6522_device, write_ca1)) + MCFG_C2040_ERROR_CALLBACK(DEVWRITELINE(M6522_TAG, via6522_device, write_cb1)) + MCFG_FLOPPY_DRIVE_ADD(FDC_TAG":0", c2040_floppies, "525ssqd", c3040_t::floppy_formats) + MCFG_FLOPPY_DRIVE_ADD(FDC_TAG":1", c2040_floppies, "525ssqd", c3040_t::floppy_formats) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor c3040_t::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( c3040 ); +} + + +//------------------------------------------------- +// MACHINE_CONFIG_FRAGMENT( c4040 ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( c4040 ) + // DOS + MCFG_CPU_ADD(M6502_TAG, M6502, XTAL_16MHz/16) + MCFG_CPU_PROGRAM_MAP(c2040_main_mem) + + MCFG_DEVICE_ADD(M6532_0_TAG, MOS6532n, XTAL_16MHz/16) + MCFG_MOS6530n_IN_PA_CB(READ8(c2040_t, dio_r)) + MCFG_MOS6530n_OUT_PB_CB(WRITE8(c2040_t, dio_w)) + + MCFG_DEVICE_ADD(M6532_1_TAG, MOS6532n, XTAL_16MHz/16) + MCFG_MOS6530n_IN_PA_CB(READ8(c2040_t, riot1_pa_r)) + MCFG_MOS6530n_OUT_PA_CB(WRITE8(c2040_t, riot1_pa_w)) + MCFG_MOS6530n_IN_PB_CB(READ8(c2040_t, riot1_pb_r)) + MCFG_MOS6530n_OUT_PB_CB(WRITE8(c2040_t, riot1_pb_w)) + MCFG_MOS6530n_IRQ_CB(INPUTLINE(M6502_TAG, INPUT_LINE_IRQ0)) + + // controller + MCFG_CPU_ADD(M6504_TAG, M6504, XTAL_16MHz/16) + MCFG_CPU_PROGRAM_MAP(c2040_fdc_mem) + + MCFG_DEVICE_ADD(M6522_TAG, VIA6522, XTAL_16MHz/16) + MCFG_VIA6522_READPA_HANDLER(DEVREAD8(FDC_TAG, c2040_fdc_t, read)) + MCFG_VIA6522_WRITEPB_HANDLER(WRITE8(c2040_t, via_pb_w)) + MCFG_VIA6522_CA2_HANDLER(DEVWRITELINE(FDC_TAG, c2040_fdc_t, mode_sel_w)) + MCFG_VIA6522_CB2_HANDLER(DEVWRITELINE(FDC_TAG, c2040_fdc_t, rw_sel_w)) + + MCFG_DEVICE_ADD(M6530_TAG, MOS6530n, XTAL_16MHz/16) + MCFG_MOS6530n_OUT_PA_CB(DEVWRITE8(FDC_TAG, c2040_fdc_t, write)) + MCFG_MOS6530n_OUT_PB0_CB(DEVWRITELINE(FDC_TAG, c2040_fdc_t, drv_sel_w)) + MCFG_MOS6530n_OUT_PB1_CB(DEVWRITELINE(FDC_TAG, c2040_fdc_t, ds0_w)) + MCFG_MOS6530n_OUT_PB2_CB(DEVWRITELINE(FDC_TAG, c2040_fdc_t, ds1_w)) + MCFG_MOS6530n_IN_PB3_CB(DEVREADLINE(FDC_TAG, c2040_fdc_t, wps_r)) + MCFG_MOS6530n_OUT_PB7_CB(INPUTLINE(M6504_TAG, M6502_IRQ_LINE)) + + MCFG_DEVICE_ADD(FDC_TAG, C2040_FDC, XTAL_16MHz) + MCFG_C2040_SYNC_CALLBACK(DEVWRITELINE(M6530_TAG, mos6530_t, pb6_w)) + MCFG_C2040_READY_CALLBACK(DEVWRITELINE(M6522_TAG, via6522_device, write_ca1)) + MCFG_C2040_ERROR_CALLBACK(DEVWRITELINE(M6522_TAG, via6522_device, write_cb1)) + MCFG_FLOPPY_DRIVE_ADD(FDC_TAG":0", c2040_floppies, "525ssqd", c4040_t::floppy_formats) + MCFG_FLOPPY_DRIVE_ADD(FDC_TAG":1", c2040_floppies, "525ssqd", c4040_t::floppy_formats) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor c4040_t::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( c4040 ); +} + + +//------------------------------------------------- +// INPUT_PORTS( c2040 ) +//------------------------------------------------- + +static INPUT_PORTS_START( c2040 ) + PORT_START("ADDRESS") + PORT_DIPNAME( 0x07, 0x00, "Device Address" ) + PORT_DIPSETTING( 0x00, "8" ) + PORT_DIPSETTING( 0x01, "9" ) + PORT_DIPSETTING( 0x02, "10" ) + PORT_DIPSETTING( 0x03, "11" ) + PORT_DIPSETTING( 0x04, "12" ) + PORT_DIPSETTING( 0x05, "13" ) + PORT_DIPSETTING( 0x06, "14" ) + PORT_DIPSETTING( 0x07, "15" ) +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor c2040_t::device_input_ports() const +{ + return INPUT_PORTS_NAME( c2040 ); +} + + + +//************************************************************************** +// INLINE HELPERS +//************************************************************************** + +//------------------------------------------------- +// update_ieee_signals - +//------------------------------------------------- + +inline void c2040_t::update_ieee_signals() +{ + int atn = m_bus->atn_r(); + int nrfd = !(!(!(atn && m_atna) && m_rfdo) || !(atn || m_atna)); + int ndac = !(m_daco || !(atn || m_atna)); + + m_bus->nrfd_w(this, nrfd); + m_bus->ndac_w(this, ndac); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// c2040_t - constructor +//------------------------------------------------- + +c2040_t::c2040_t(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_ieee488_interface(mconfig, *this), + m_maincpu(*this, M6502_TAG), + m_fdccpu(*this, M6504_TAG), + m_riot0(*this, M6532_0_TAG), + m_riot1(*this, M6532_1_TAG), + m_miot(*this, M6530_TAG), + m_via(*this, M6522_TAG), + m_floppy0(*this, FDC_TAG":0:525ssqd"), + m_floppy1(*this, FDC_TAG":1:525ssqd"), + m_fdc(*this, FDC_TAG), + m_gcr(*this, "gcr"), + m_address(*this, "ADDRESS"), + m_rfdo(1), + m_daco(1), + m_atna(1) +{ +} + +c2040_t::c2040_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, C2040, "C2040", tag, owner, clock, "c2040", __FILE__), + device_ieee488_interface(mconfig, *this), + m_maincpu(*this, M6502_TAG), + m_fdccpu(*this, M6504_TAG), + m_riot0(*this, M6532_0_TAG), + m_riot1(*this, M6532_1_TAG), + m_miot(*this, M6530_TAG), + m_via(*this, M6522_TAG), + m_floppy0(*this, FDC_TAG":0:525ssqd"), + m_floppy1(*this, FDC_TAG":1:525ssqd"), + m_fdc(*this, FDC_TAG), + m_gcr(*this, "gcr"), + m_address(*this, "ADDRESS"), + m_rfdo(1), + m_daco(1), + m_atna(1) +{ +} + + +//------------------------------------------------- +// c3040_t - constructor +//------------------------------------------------- + +c3040_t::c3040_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + c2040_t(mconfig, C3040, "C3040", tag, owner, clock, "c3040", __FILE__) { } + + +//------------------------------------------------- +// c4040_t - constructor +//------------------------------------------------- + +c4040_t::c4040_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + c2040_t(mconfig, C4040, "C4040", tag, owner, clock, "c4040", __FILE__) { } + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void c2040_t::device_start() +{ + // install image callbacks + m_fdc->set_floppy(m_floppy0, m_floppy1); + + // register for state saving + save_item(NAME(m_rfdo)); + save_item(NAME(m_daco)); + save_item(NAME(m_atna)); + save_item(NAME(m_ifc)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void c2040_t::device_reset() +{ + m_maincpu->reset(); + + // toggle M6502 SO + m_maincpu->set_input_line(M6502_SET_OVERFLOW, ASSERT_LINE); + m_maincpu->set_input_line(M6502_SET_OVERFLOW, CLEAR_LINE); + + m_fdccpu->reset(); + + m_riot0->reset(); + m_riot1->reset(); + m_miot->reset(); + m_via->reset(); + + m_riot1->pa7_w(0); + + // turn off spindle motors + m_fdc->mtr0_w(1); + m_fdc->mtr1_w(1); +} + + +//------------------------------------------------- +// ieee488_atn - +//------------------------------------------------- + +void c2040_t::ieee488_atn(int state) +{ + update_ieee_signals(); + + m_riot1->pa7_w(!state); +} + + +//------------------------------------------------- +// ieee488_ifc - +//------------------------------------------------- + +void c2040_t::ieee488_ifc(int state) +{ + if (!m_ifc && state) + { + device_reset(); + } + + m_ifc = state; +} diff --git a/src/devices/bus/ieee488/c2040.h b/src/devices/bus/ieee488/c2040.h new file mode 100644 index 00000000000..1618a46599f --- /dev/null +++ b/src/devices/bus/ieee488/c2040.h @@ -0,0 +1,133 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Commodore 2040/3040/4040 Disk Drive emulation + +**********************************************************************/ + +#pragma once + +#ifndef __C2040__ +#define __C2040__ + +#include "emu.h" +#include "ieee488.h" +#include "c2040fdc.h" +#include "cpu/m6502/m6502.h" +#include "cpu/m6502/m6504.h" +#include "machine/6522via.h" +#include "machine/mos6530n.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> c2040_t + +class c2040_t : public device_t, + public device_ieee488_interface +{ +public: + // construction/destruction + c2040_t(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + c2040_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + virtual ioport_constructor device_input_ports() const; + + DECLARE_READ8_MEMBER( dio_r ); + DECLARE_WRITE8_MEMBER( dio_w ); + DECLARE_READ8_MEMBER( riot1_pa_r ); + DECLARE_WRITE8_MEMBER( riot1_pa_w ); + DECLARE_READ8_MEMBER( riot1_pb_r ); + DECLARE_WRITE8_MEMBER( riot1_pb_w ); + DECLARE_WRITE8_MEMBER( via_pb_w ); + DECLARE_WRITE_LINE_MEMBER( mode_sel_w ); + DECLARE_WRITE_LINE_MEMBER( rw_sel_w ); + + DECLARE_FLOPPY_FORMATS( floppy_formats ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_ieee488_interface overrides + virtual void ieee488_atn(int state); + virtual void ieee488_ifc(int state); + + enum + { + LED_POWER = 0, + LED_ACT0, + LED_ACT1, + LED_ERR + }; + + inline void update_ieee_signals(); + + required_device m_maincpu; + required_device m_fdccpu; + required_device m_riot0; + required_device m_riot1; + required_device m_miot; + required_device m_via; + required_device m_floppy0; + optional_device m_floppy1; + required_device m_fdc; + required_memory_region m_gcr; + required_ioport m_address; + + // IEEE-488 bus + int m_rfdo; // not ready for data output + int m_daco; // not data accepted output + int m_atna; // attention acknowledge + int m_ifc; +}; + + +// ======================> c3040_t + +class c3040_t : public c2040_t +{ +public: + // construction/destruction + c3040_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + + DECLARE_FLOPPY_FORMATS( floppy_formats ); +}; + + +// ======================> c4040_t + +class c4040_t : public c2040_t +{ +public: + // construction/destruction + c4040_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + + DECLARE_FLOPPY_FORMATS( floppy_formats ); +}; + + +// device type definition +extern const device_type C2040; +extern const device_type C3040; +extern const device_type C4040; + + + +#endif diff --git a/src/devices/bus/ieee488/c2040fdc.c b/src/devices/bus/ieee488/c2040fdc.c new file mode 100644 index 00000000000..4dfccbde366 --- /dev/null +++ b/src/devices/bus/ieee488/c2040fdc.c @@ -0,0 +1,623 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Commodore 2040 floppy disk controller emulation + +**********************************************************************/ + +/* + + TODO: + + - write protect + - separate read/write methods + +*/ + +#include "c2040fdc.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define LOG 0 + +#define GCR_DECODE(_e, _i) \ + ((BIT(_e, 6) << 7) | (BIT(_i, 7) << 6) | (_e & 0x33) | (BIT(_e, 2) << 3) | (_i & 0x04)) + +#define GCR_ENCODE(_e, _i) \ + ((_e & 0xc0) << 2 | (_i & 0x80) | (_e & 0x3c) << 1 | (_i & 0x04) | (_e & 0x03)) + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type C2040_FDC = &device_creator; + + +//------------------------------------------------- +// ROM( c2040_fdc ) +//------------------------------------------------- + +ROM_START( c2040_fdc ) + ROM_REGION( 0x800, "gcr", 0) + ROM_LOAD( "901467.uk6", 0x000, 0x800, CRC(a23337eb) SHA1(97df576397608455616331f8e837cb3404363fa2) ) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *c2040_fdc_t::device_rom_region() const +{ + return ROM_NAME( c2040_fdc ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// c2040_fdc_t - constructor +//------------------------------------------------- + +c2040_fdc_t::c2040_fdc_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, C2040_FDC, "C2040 FDC", tag, owner, clock, "c2040fdc", __FILE__), + m_write_sync(*this), + m_write_ready(*this), + m_write_error(*this), + m_gcr_rom(*this, "gcr"), + m_floppy0(NULL), + m_floppy1(NULL), + m_mtr0(1), + m_mtr1(1), + m_stp0(0), + m_stp1(0), + m_ds(0), + m_ds0(0), + m_ds1(0), + m_drv_sel(0), + m_mode_sel(0), + m_rw_sel(0), + m_period(attotime::from_hz(clock)) +{ + cur_live.tm = attotime::never; + cur_live.state = IDLE; + cur_live.next_state = -1; + cur_live.write_position = 0; + cur_live.write_start_time = attotime::never; + cur_live.drv_sel = m_drv_sel; +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void c2040_fdc_t::device_start() +{ + // resolve callbacks + m_write_sync.resolve_safe(); + m_write_ready.resolve_safe(); + m_write_error.resolve_safe(); + + // allocate timer + t_gen = timer_alloc(0); + + // register for state saving + save_item(NAME(m_mtr0)); + save_item(NAME(m_mtr1)); + save_item(NAME(m_stp0)); + save_item(NAME(m_stp1)); + save_item(NAME(m_ds)); + save_item(NAME(m_ds0)); + save_item(NAME(m_ds1)); + save_item(NAME(m_drv_sel)); + save_item(NAME(m_mode_sel)); + save_item(NAME(m_rw_sel)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void c2040_fdc_t::device_reset() +{ + live_abort(); +} + + +//------------------------------------------------- +// device_timer - handler timer events +//------------------------------------------------- + +void c2040_fdc_t::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + live_sync(); + live_run(); +} + +floppy_image_device* c2040_fdc_t::get_floppy() +{ + return cur_live.drv_sel ? m_floppy1 : m_floppy0; +} + +void c2040_fdc_t::live_start() +{ + cur_live.tm = machine().time(); + cur_live.state = RUNNING; + cur_live.next_state = -1; + + cur_live.shift_reg = 0; + cur_live.shift_reg_write = 0; + cur_live.cycle_counter = 0; + cur_live.cell_counter = 0; + cur_live.bit_counter = 0; + cur_live.ds = m_ds; + cur_live.drv_sel = m_drv_sel; + cur_live.mode_sel = m_mode_sel; + cur_live.rw_sel = m_rw_sel; + cur_live.pi = m_pi; + + checkpoint_live = cur_live; + + live_run(); +} + +void c2040_fdc_t::checkpoint() +{ + get_next_edge(machine().time()); + checkpoint_live = cur_live; +} + +void c2040_fdc_t::rollback() +{ + cur_live = checkpoint_live; + get_next_edge(cur_live.tm); +} + +void c2040_fdc_t::start_writing(const attotime &tm) +{ + cur_live.write_start_time = tm; + cur_live.write_position = 0; +} + +void c2040_fdc_t::stop_writing(const attotime &tm) +{ + commit(tm); + cur_live.write_start_time = attotime::never; +} + +bool c2040_fdc_t::write_next_bit(bool bit, const attotime &limit) +{ + if(cur_live.write_start_time.is_never()) { + cur_live.write_start_time = cur_live.tm; + cur_live.write_position = 0; + } + + attotime etime = cur_live.tm + m_period; + if(etime > limit) + return true; + + if(bit && cur_live.write_position < ARRAY_LENGTH(cur_live.write_buffer)) + cur_live.write_buffer[cur_live.write_position++] = cur_live.tm - m_period; + + if (LOG) logerror("%s write bit %u (%u)\n", cur_live.tm.as_string(), cur_live.bit_counter, bit); + + return false; +} + +void c2040_fdc_t::commit(const attotime &tm) +{ + if(cur_live.write_start_time.is_never() || tm == cur_live.write_start_time || !cur_live.write_position) + return; + + if (LOG) logerror("%s committing %u transitions since %s\n", tm.as_string(), cur_live.write_position, cur_live.write_start_time.as_string()); + + if(get_floppy()) + get_floppy()->write_flux(cur_live.write_start_time, tm, cur_live.write_position, cur_live.write_buffer); + + cur_live.write_start_time = tm; + cur_live.write_position = 0; +} + +void c2040_fdc_t::live_delay(int state) +{ + cur_live.next_state = state; + if(cur_live.tm != machine().time()) + t_gen->adjust(cur_live.tm - machine().time()); + else + live_sync(); +} + +void c2040_fdc_t::live_sync() +{ + if(!cur_live.tm.is_never()) { + if(cur_live.tm > machine().time()) { + rollback(); + live_run(machine().time()); + commit(cur_live.tm); + } else { + commit(cur_live.tm); + if(cur_live.next_state != -1) { + cur_live.state = cur_live.next_state; + cur_live.next_state = -1; + } + if(cur_live.state == IDLE) { + stop_writing(cur_live.tm); + cur_live.tm = attotime::never; + } + } + cur_live.next_state = -1; + checkpoint(); + } +} + +void c2040_fdc_t::live_abort() +{ + if(!cur_live.tm.is_never() && cur_live.tm > machine().time()) { + rollback(); + live_run(machine().time()); + } + + stop_writing(cur_live.tm); + + cur_live.tm = attotime::never; + cur_live.state = IDLE; + cur_live.next_state = -1; + cur_live.write_position = 0; + cur_live.write_start_time = attotime::never; + + cur_live.ready = 1; + cur_live.sync = 1; + cur_live.error = 1; +} + +void c2040_fdc_t::live_run(const attotime &limit) +{ + if(cur_live.state == IDLE || cur_live.next_state != -1) + return; + + for(;;) { + switch(cur_live.state) { + case RUNNING: { + bool syncpoint = false; + + if (cur_live.tm > limit) + return; + + int bit = get_next_bit(cur_live.tm, limit); + if(bit < 0) + return; + + int cell_counter = cur_live.cell_counter; + + if (bit) { + cur_live.cycle_counter = cur_live.ds; + cur_live.cell_counter = 0; + } else { + cur_live.cycle_counter++; + } + + if (cur_live.cycle_counter == 16) { + cur_live.cycle_counter = cur_live.ds; + + cur_live.cell_counter++; + cur_live.cell_counter &= 0xf; + } + + if (!BIT(cell_counter, 1) && BIT(cur_live.cell_counter, 1)) { + // read bit + cur_live.shift_reg <<= 1; + cur_live.shift_reg |= !(BIT(cur_live.cell_counter, 3) || BIT(cur_live.cell_counter, 2)); + cur_live.shift_reg &= 0x3ff; + + if (LOG) logerror("%s read bit %u (%u) >> %03x, rw=%u mode=%u\n", cur_live.tm.as_string(), cur_live.bit_counter, + !(BIT(cur_live.cell_counter, 3) || BIT(cur_live.cell_counter, 2)), cur_live.shift_reg, cur_live.rw_sel, cur_live.mode_sel); + + // write bit + if (!cur_live.rw_sel) { // TODO WPS + write_next_bit(BIT(cur_live.shift_reg_write, 9), limit); + } + + syncpoint = true; + } + + int sync = !((cur_live.shift_reg == 0x3ff) && cur_live.rw_sel); + + if (!sync) { + cur_live.bit_counter = 0; + } else if (!BIT(cell_counter, 1) && BIT(cur_live.cell_counter, 1) && cur_live.sync) { + cur_live.bit_counter++; + if (cur_live.bit_counter == 10) { + cur_live.bit_counter = 0; + } + } + + // update GCR + if (cur_live.rw_sel) { + cur_live.i = (cur_live.rw_sel << 10) | cur_live.shift_reg; + } else { + cur_live.i = (cur_live.rw_sel << 10) | ((cur_live.pi & 0xf0) << 1) | (cur_live.mode_sel << 4) | (cur_live.pi & 0x0f); + } + + cur_live.e = m_gcr_rom->base()[cur_live.i]; + + int ready = !(BIT(cell_counter, 1) && !BIT(cur_live.cell_counter, 1) && (cur_live.bit_counter == 9)); + + if (!ready) { + // load write shift register + cur_live.shift_reg_write = GCR_ENCODE(cur_live.e, cur_live.i); + + if (LOG) logerror("%s load write shift register %03x\n",cur_live.tm.as_string(),cur_live.shift_reg_write); + } else if (BIT(cell_counter, 1) && !BIT(cur_live.cell_counter, 1)) { + // clock write shift register + cur_live.shift_reg_write <<= 1; + cur_live.shift_reg_write &= 0x3ff; + + if (LOG) logerror("%s write shift << %03x\n",cur_live.tm.as_string(),cur_live.shift_reg_write); + } + + int error = !(BIT(cur_live.e, 3) || ready); + + if (ready != cur_live.ready) { + if (LOG) logerror("%s READY %u\n", cur_live.tm.as_string(),ready); + cur_live.ready = ready; + syncpoint = true; + } + + if (sync != cur_live.sync) { + if (LOG) logerror("%s SYNC %u\n", cur_live.tm.as_string(),sync); + cur_live.sync = sync; + syncpoint = true; + } + + if (error != cur_live.error) { + cur_live.error = error; + syncpoint = true; + } + + if (syncpoint) { + commit(cur_live.tm); + + cur_live.tm += m_period; + live_delay(RUNNING_SYNCPOINT); + return; + } + + cur_live.tm += m_period; + break; + } + + case RUNNING_SYNCPOINT: { + m_write_ready(cur_live.ready); + m_write_sync(cur_live.sync); + m_write_error(cur_live.error); + + cur_live.state = RUNNING; + checkpoint(); + break; + } + } + } +} + +void c2040_fdc_t::get_next_edge(const attotime &when) +{ + floppy_image_device *floppy = get_floppy(); + + cur_live.edge = floppy ? floppy->get_next_transition(when) : attotime::never; +} + +int c2040_fdc_t::get_next_bit(attotime &tm, const attotime &limit) +{ + attotime next = tm + m_period; + + int bit = (cur_live.edge.is_never() || cur_live.edge >= next) ? 0 : 1; + + if (bit) { + get_next_edge(next); + } + + return bit && cur_live.rw_sel; +} + +READ8_MEMBER( c2040_fdc_t::read ) +{ + UINT8 e = checkpoint_live.e; + offs_t i = checkpoint_live.i; + + UINT8 data = GCR_DECODE(e, i); + + if (LOG) logerror("%s %s VIA reads data %02x (%03x)\n", machine().time().as_string(), machine().describe_context(), data, checkpoint_live.shift_reg); + + return data; +} + +WRITE8_MEMBER( c2040_fdc_t::write ) +{ + if (m_pi != data) + { + live_sync(); + m_pi = cur_live.pi = data; + checkpoint(); + if (LOG) logerror("%s %s PI %02x\n", machine().time().as_string(), machine().describe_context(), data); + live_run(); + } +} + +WRITE_LINE_MEMBER( c2040_fdc_t::ds0_w ) +{ + m_ds0 = state; +} + +WRITE_LINE_MEMBER( c2040_fdc_t::ds1_w ) +{ + m_ds1 = state; + + ds_w(m_ds1 << 1 | m_ds0); +} + +WRITE_LINE_MEMBER( c2040_fdc_t::drv_sel_w ) +{ + if (m_drv_sel != state) + { + live_sync(); + m_drv_sel = cur_live.drv_sel = state; + checkpoint(); + if (LOG) logerror("%s %s DRV SEL %u\n", machine().time().as_string(), machine().describe_context(), state); + live_run(); + } +} + +WRITE_LINE_MEMBER( c2040_fdc_t::mode_sel_w ) +{ + if (m_mode_sel != state) + { + live_sync(); + m_mode_sel = cur_live.mode_sel = state; + checkpoint(); + if (LOG) logerror("%s %s MODE SEL %u\n", machine().time().as_string(), machine().describe_context(), state); + live_run(); + } +} + +WRITE_LINE_MEMBER( c2040_fdc_t::rw_sel_w ) +{ + if (m_rw_sel != state) + { + live_sync(); + m_rw_sel = cur_live.rw_sel = state; + checkpoint(); + if (LOG) logerror("%s %s RW SEL %u\n", machine().time().as_string(), machine().describe_context(), state); + if (m_rw_sel) { + stop_writing(machine().time()); + } else { + start_writing(machine().time()); + } + live_run(); + } +} + +WRITE_LINE_MEMBER( c2040_fdc_t::mtr0_w ) +{ + if (m_mtr0 != state) + { + live_sync(); + m_mtr0 = state; + if (LOG) logerror("%s %s MTR0 %u\n", machine().time().as_string(), machine().describe_context(), state); + m_floppy0->mon_w(state); + checkpoint(); + + if (!m_mtr0 || !m_mtr1) { + if(cur_live.state == IDLE) { + live_start(); + } + } else { + live_abort(); + } + + live_run(); + } +} + +WRITE_LINE_MEMBER( c2040_fdc_t::mtr1_w ) +{ + if (m_mtr1 != state) + { + live_sync(); + m_mtr1 = state; + if (LOG) logerror("%s %s MTR1 %u\n", machine().time().as_string(), machine().describe_context(), state); + if (m_floppy1) m_floppy1->mon_w(state); + checkpoint(); + + if (!m_mtr0 || !m_mtr1) { + if(cur_live.state == IDLE) { + live_start(); + } + } else { + live_abort(); + } + + live_run(); + } +} + +void c2040_fdc_t::stp_w(floppy_image_device *floppy, int mtr, int &old_stp, int stp) +{ + if (mtr) return; + + int tracks = 0; + + switch (old_stp) + { + case 0: if (stp == 1) tracks++; else if (stp == 3) tracks--; break; + case 1: if (stp == 2) tracks++; else if (stp == 0) tracks--; break; + case 2: if (stp == 3) tracks++; else if (stp == 1) tracks--; break; + case 3: if (stp == 0) tracks++; else if (stp == 2) tracks--; break; + } + + if (tracks == -1) + { + floppy->dir_w(1); + floppy->stp_w(1); + floppy->stp_w(0); + } + else if (tracks == 1) + { + floppy->dir_w(0); + floppy->stp_w(1); + floppy->stp_w(0); + } + + old_stp = stp; +} + +void c2040_fdc_t::stp0_w(int stp) +{ + if (m_stp0 != stp) + { + live_sync(); + this->stp_w(m_floppy0, m_mtr0, m_stp0, stp); + checkpoint(); + live_run(); + } +} + +void c2040_fdc_t::stp1_w(int stp) +{ + if (m_stp1 != stp) + { + live_sync(); + if (m_floppy1) this->stp_w(m_floppy1, m_mtr1, m_stp1, stp); + checkpoint(); + live_run(); + } +} + +void c2040_fdc_t::ds_w(int ds) +{ + if (m_ds != ds) + { + live_sync(); + m_ds = cur_live.ds = ds; + if (LOG) logerror("%s %s DS %u\n", machine().time().as_string(), machine().describe_context(), ds); + checkpoint(); + live_run(); + } +} + +void c2040_fdc_t::set_floppy(floppy_image_device *floppy0, floppy_image_device *floppy1) +{ + m_floppy0 = floppy0; + m_floppy1 = floppy1; +} diff --git a/src/devices/bus/ieee488/c2040fdc.h b/src/devices/bus/ieee488/c2040fdc.h new file mode 100644 index 00000000000..178e81240a2 --- /dev/null +++ b/src/devices/bus/ieee488/c2040fdc.h @@ -0,0 +1,168 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Commodore 2040 floppy disk controller emulation + +**********************************************************************/ + +#pragma once + +#ifndef __C2040_FLOPPY__ +#define __C2040_FLOPPY__ + +#include "emu.h" +#include "formats/c3040_dsk.h" +#include "formats/c4040_dsk.h" +#include "formats/d64_dsk.h" +#include "formats/g64_dsk.h" +#include "imagedev/floppy.h" + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_C2040_SYNC_CALLBACK(_write) \ + devcb = &c2040_fdc_t::set_sync_wr_callback(*device, DEVCB_##_write); + +#define MCFG_C2040_READY_CALLBACK(_write) \ + devcb = &c2040_fdc_t::set_ready_wr_callback(*device, DEVCB_##_write); + +#define MCFG_C2040_ERROR_CALLBACK(_write) \ + devcb = &c2040_fdc_t::set_error_wr_callback(*device, DEVCB_##_write); + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> c2040_fdc_t + +class c2040_fdc_t : public device_t +{ +public: + // construction/destruction + c2040_fdc_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + template static devcb_base &set_sync_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_sync.set_callback(object); } + template static devcb_base &set_ready_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_ready.set_callback(object); } + template static devcb_base &set_error_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_error.set_callback(object); } + + DECLARE_READ8_MEMBER( read ); + DECLARE_WRITE8_MEMBER( write ); + + DECLARE_WRITE_LINE_MEMBER( ds0_w ); + DECLARE_WRITE_LINE_MEMBER( ds1_w ); + DECLARE_WRITE_LINE_MEMBER( drv_sel_w ); + DECLARE_WRITE_LINE_MEMBER( mode_sel_w ); + DECLARE_WRITE_LINE_MEMBER( rw_sel_w ); + DECLARE_WRITE_LINE_MEMBER( mtr0_w ); + DECLARE_WRITE_LINE_MEMBER( mtr1_w ); + + DECLARE_READ_LINE_MEMBER( wps_r ) { return checkpoint_live.drv_sel ? m_floppy1->wpt_r() : m_floppy0->wpt_r(); } + DECLARE_READ_LINE_MEMBER( sync_r ) { return checkpoint_live.sync; } + + void stp0_w(int stp); + void stp1_w(int stp); + void ds_w(int ds); + + void set_floppy(floppy_image_device *floppy0, floppy_image_device *floppy1); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + + void stp_w(floppy_image_device *floppy, int mtr, int &old_stp, int stp); + + enum { + IDLE, + RUNNING, + RUNNING_SYNCPOINT + }; + + struct live_info { + attotime tm; + int state, next_state; + int sync; + int ready; + int error; + int ds; + int drv_sel; + int mode_sel; + int rw_sel; + int odd_hd; + + attotime edge; + UINT16 shift_reg; + int cycle_counter; + int cell_counter; + int bit_counter; + UINT8 e; + offs_t i; + + UINT8 pi; + UINT16 shift_reg_write; + attotime write_start_time; + attotime write_buffer[32]; + int write_position; + }; + + devcb_write_line m_write_sync; + devcb_write_line m_write_ready; + devcb_write_line m_write_error; + + required_memory_region m_gcr_rom; + + floppy_image_device *m_floppy0; + floppy_image_device *m_floppy1; + + int m_mtr0; + int m_mtr1; + int m_stp0; + int m_stp1; + int m_ds; + int m_ds0; + int m_ds1; + int m_drv_sel; + int m_mode_sel; + int m_rw_sel; + int m_odd_hd; + UINT8 m_pi; + + attotime m_period; + + live_info cur_live, checkpoint_live; + emu_timer *t_gen; + + floppy_image_device* get_floppy(); + + void live_start(); + void checkpoint(); + void rollback(); + bool write_next_bit(bool bit, const attotime &limit); + void start_writing(const attotime &tm); + void commit(const attotime &tm); + void stop_writing(const attotime &tm); + void live_delay(int state); + void live_sync(); + void live_abort(); + void live_run(const attotime &limit = attotime::never); + void get_next_edge(const attotime &when); + int get_next_bit(attotime &tm, const attotime &limit); +}; + + +// device type definition +extern const device_type C2040_FDC; + + + +#endif diff --git a/src/devices/bus/ieee488/c8050.c b/src/devices/bus/ieee488/c8050.c new file mode 100644 index 00000000000..e60386db689 --- /dev/null +++ b/src/devices/bus/ieee488/c8050.c @@ -0,0 +1,950 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Commodore 8050/8250/SFD-1001 Disk Drive emulation + +**********************************************************************/ + +/* + + TODO: + + - Micropolis 8x50 stepper motor is same as 4040, except it takes 4 pulses to step a track instead of 1 + + - BASIC program to set 8250/SFD-1001 to 8050 mode: + + 10 OPEN 15,8,15 + 20 PRINT#15,"M-W"CHR$(172)CHR$(16)CHR$(1)CHR$(1) + 30 PRINT#15,"M-W"CHR$(195)CHR$(16)CHR$(1)CHR$(0) + 40 PRINT#15,"U9" + 50 CLOSE 15 + +*/ + +#include "c8050.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define M6502_TAG "un1" +#define M6532_0_TAG "uc1" +#define M6532_1_TAG "ue1" +#define M6504_TAG "uh3" +#define M6522_TAG "um3" +#define M6530_TAG "uk3" +#define FDC_TAG "fdc" + + +enum +{ + LED_POWER = 0, + LED_ACT0, + LED_ACT1, + LED_ERR +}; + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type C8050 = &device_creator; +const device_type C8250 = &device_creator; +const device_type C8250LP = &device_creator; +const device_type SFD1001 = &device_creator; + + +//------------------------------------------------- +// ROM( c8050 ) +//------------------------------------------------- + +/* + + DOS/CONTROLLER ROMS FOR DIGITAL PCB #8050002 + + DESCRIPTION PCB PART NO. UL1 UH1 UK3 + + 2.5 Micropolis 8050002-01 901482-07 901482-06 901483-03 + 2.5 Tandon 8050002-02 901482-07 901482-06 901483-04 + 2.7 Tandon 8050002-03 901887-01 901888-01 901884-01 + 2.7 Micropolis 8050002-04 901887-01 901888-01 901885-04 + 2.7 MPI 8050 8050002-05 901887-01 901888-01 901869-01 + 2.7 MPI 8250 8050002-06 901887-01 901888-01 901869-01 + +*/ + +ROM_START( c8050 ) // schematic 8050001 + ROM_REGION( 0x4000, M6502_TAG, 0 ) + ROM_DEFAULT_BIOS("dos27") + ROM_SYSTEM_BIOS( 0, "dos25r1", "DOS 2.5 Revision 1" ) + ROMX_LOAD( "901482-01.ul1", 0x0000, 0x2000, NO_DUMP, ROM_BIOS(1) ) + ROMX_LOAD( "901482-02.uh1", 0x2000, 0x2000, NO_DUMP, ROM_BIOS(1) ) + ROM_SYSTEM_BIOS( 1, "dos25r2", "DOS 2.5 Revision 2" ) + ROMX_LOAD( "901482-03.ul1", 0x0000, 0x2000, CRC(09a609b9) SHA1(166d8bfaaa9c4767f9b17ad63fc7ae77c199a64e), ROM_BIOS(2) ) + ROMX_LOAD( "901482-04.uh1", 0x2000, 0x2000, CRC(1bcf9df9) SHA1(217f4a8b348658bb365f4a1de21ecbaa6402b1c0), ROM_BIOS(2) ) + ROM_SYSTEM_BIOS( 2, "dos25r3", "DOS 2.5 Revision 3" ) + ROMX_LOAD( "901482-06.ul1", 0x0000, 0x2000, CRC(3cbd2756) SHA1(7f5fbed0cddb95138dd99b8fe84fddab900e3650), ROM_BIOS(3) ) + ROMX_LOAD( "901482-07.uh1", 0x2000, 0x2000, CRC(c7532d90) SHA1(0b6d1e55afea612516df5f07f4a6dccd3bd73963), ROM_BIOS(3) ) + ROM_SYSTEM_BIOS( 3, "dos27", "DOS 2.7" )// 2364 ROM DOS 2.7 + ROMX_LOAD( "901887-01.ul1", 0x0000, 0x2000, CRC(0073b8b2) SHA1(b10603195f240118fe5fb6c6dfe5c5097463d890), ROM_BIOS(4) ) + ROMX_LOAD( "901888-01.uh1", 0x2000, 0x2000, CRC(de9b6132) SHA1(2e6c2d7ca934e5c550ad14bd5e9e7749686b7af4), ROM_BIOS(4) ) + + ROM_REGION( 0x400, M6530_TAG, 0 ) + ROM_LOAD_OPTIONAL( "901483-02.uk3", 0x000, 0x400, CRC(d7277f95) SHA1(7607f9357f3a08f2a9f20931058d60d9e3c17d39) ) // 6530-036 + ROM_LOAD_OPTIONAL( "901483-03.uk3", 0x000, 0x400, CRC(9e83fa70) SHA1(e367ea8a5ddbd47f13570088427293138a10784b) ) // 6530-038 RIOT DOS 2.5 Micropolis + ROM_LOAD_OPTIONAL( "901483-04.uk3", 0x000, 0x400, CRC(ae1c7866) SHA1(13bdf0bb387159167534c07a4554964734373f11) ) // 6530-039 RIOT DOS 2.5 Tandon + ROM_LOAD_OPTIONAL( "901884-01.uk3", 0x000, 0x400, CRC(9e9a9f90) SHA1(39498d7369a31ea7527b5044071acf35a84ea2ac) ) // 6530-40 RIOT DOS 2.7 Tandon + ROM_LOAD_OPTIONAL( "901885-01.uk3", 0x000, 0x400, NO_DUMP ) // 6530-044 + ROM_LOAD_OPTIONAL( "901885-04.uk3", 0x000, 0x400, CRC(bab998c9) SHA1(0dc9a3b60f1b866c63eebd882403532fc59fe57f) ) // 6530-47 RIOT DOS 2.7 Micropolis + ROM_LOAD( "901869-01.uk3", 0x000, 0x400, CRC(2915327a) SHA1(3a9a80f72ce76e5f5c72513f8ef7553212912ae3) ) // 6530-48 RIOT DOS 2.7 MPI +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *c8050_t::device_rom_region() const +{ + return ROM_NAME( c8050 ); +} + + +//------------------------------------------------- +// ROM( c8250lp ) +//------------------------------------------------- + +ROM_START( c8250lp ) + ROM_REGION( 0x4000, M6502_TAG, 0 ) + ROM_DEFAULT_BIOS("dos27") + ROM_SYSTEM_BIOS( 0, "dos27", "DOS 2.7" ) + ROMX_LOAD( "251165-01.ua11", 0x0000, 0x2000, NO_DUMP, ROM_BIOS(1) ) + ROMX_LOAD( "251166-01.ua13", 0x2000, 0x2000, NO_DUMP, ROM_BIOS(1) ) + ROM_SYSTEM_BIOS( 1, "dos27b", "DOS 2.7B" ) + ROMX_LOAD( "dos-2.7b.bin", 0x0000, 0x4000, CRC(96e3b209) SHA1(9849300be9f2e0143c2ed2564d26a4ba3b27526c), ROM_BIOS(2) ) // CBM DOS 2.7B from the 8250LP inside 8296D + ROM_SYSTEM_BIOS( 2, "speeddos", "SpeedDOS" ) + ROMX_LOAD( "speeddos-c000.ua11", 0x0000, 0x2000, CRC(46cc260f) SHA1(e9838635d6868e35ec9c161b6e5c1ad92a4a241a), ROM_BIOS(3) ) + ROMX_LOAD( "speeddos-e000.ua13", 0x2000, 0x2000, CRC(88cfd505) SHA1(0fb570b180504cd1fcb7d203d8d37ea3d7e72ab4), ROM_BIOS(3) ) + + ROM_REGION( 0x800, M6504_TAG, 0 ) + ROMX_LOAD( "251256-02", 0x000, 0x400, NO_DUMP, ROM_BIOS(1) ) // 6530-050 + ROMX_LOAD( "251474-01b", 0x000, 0x400, CRC(9e9a9f90) SHA1(39498d7369a31ea7527b5044071acf35a84ea2ac), ROM_BIOS(1) ) // Matsushita + ROMX_LOAD( "fdc-2.7b.bin", 0x000, 0x800, CRC(13a24482) SHA1(1cfa52d2ed245a95e6369b46a36c6c7aa3929931), ROM_BIOS(2) ) // CBM DOS 2.7B FDC ROM from the 8250LP inside 8296D + ROMX_LOAD( "speeddos-fdc-f800.bin", 0x000, 0x800, CRC(253e760f) SHA1(3f7892a9bab84b633f45686bbbbe66bc2948c8e5), ROM_BIOS(3) ) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *c8250lp_t::device_rom_region() const +{ + return ROM_NAME( c8250lp ); +} + + +//------------------------------------------------- +// ROM( sfd1001 ) +//------------------------------------------------- + +ROM_START( sfd1001 ) // schematic 251406 + ROM_REGION( 0x4000, M6502_TAG, 0 ) + ROM_LOAD( "901887-01.1j", 0x0000, 0x2000, CRC(0073b8b2) SHA1(b10603195f240118fe5fb6c6dfe5c5097463d890) ) + ROM_LOAD( "901888-01.3j", 0x2000, 0x2000, CRC(de9b6132) SHA1(2e6c2d7ca934e5c550ad14bd5e9e7749686b7af4) ) + + ROM_REGION( 0x400, M6530_TAG, 0 ) + ROM_LOAD( "901885-04.u1", 0x000, 0x400, CRC(bab998c9) SHA1(0dc9a3b60f1b866c63eebd882403532fc59fe57f) ) + + ROM_REGION( 0x800, M6504_TAG, 0 ) + ROM_LOAD( "251257-02a.u2", 0x000, 0x800, CRC(b51150de) SHA1(3b954eb34f7ea088eed1d33ebc6d6e83a3e9be15) ) + + ROM_REGION( 0x800, "gcr", 0) + ROM_LOAD( "901467-01.5c", 0x000, 0x800, CRC(a23337eb) SHA1(97df576397608455616331f8e837cb3404363fa2) ) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *sfd1001_t::device_rom_region() const +{ + return ROM_NAME( sfd1001 ); +} + + +//------------------------------------------------- +// ADDRESS_MAP( c8050_main_mem ) +//------------------------------------------------- + +static ADDRESS_MAP_START( c8050_main_mem, AS_PROGRAM, 8, c8050_t ) + AM_RANGE(0x0000, 0x007f) AM_MIRROR(0x0100) AM_DEVICE(M6532_0_TAG, mos6532_t, ram_map) + AM_RANGE(0x0080, 0x00ff) AM_MIRROR(0x0100) AM_DEVICE(M6532_1_TAG, mos6532_t, ram_map) + AM_RANGE(0x0200, 0x021f) AM_MIRROR(0x0d60) AM_DEVICE(M6532_0_TAG, mos6532_t, io_map) + AM_RANGE(0x0280, 0x029f) AM_MIRROR(0x0d60) AM_DEVICE(M6532_1_TAG, mos6532_t, io_map) + AM_RANGE(0x1000, 0x13ff) AM_MIRROR(0x0c00) AM_RAM AM_SHARE("share1") + AM_RANGE(0x2000, 0x23ff) AM_MIRROR(0x0c00) AM_RAM AM_SHARE("share2") + AM_RANGE(0x3000, 0x33ff) AM_MIRROR(0x0c00) AM_RAM AM_SHARE("share3") + AM_RANGE(0x4000, 0x43ff) AM_MIRROR(0x0c00) AM_RAM AM_SHARE("share4") + AM_RANGE(0xc000, 0xffff) AM_ROM AM_REGION(M6502_TAG, 0) +ADDRESS_MAP_END + + +//------------------------------------------------- +// ADDRESS_MAP( c8050_fdc_mem ) +//------------------------------------------------- + +static ADDRESS_MAP_START( c8050_fdc_mem, AS_PROGRAM, 8, c8050_t ) + ADDRESS_MAP_GLOBAL_MASK(0x1fff) + AM_RANGE(0x0000, 0x003f) AM_MIRROR(0x0300) AM_DEVICE(M6530_TAG, mos6530_t, ram_map) + AM_RANGE(0x0040, 0x004f) AM_MIRROR(0x0330) AM_DEVICE(M6522_TAG, via6522_device, map) + AM_RANGE(0x0080, 0x008f) AM_MIRROR(0x0330) AM_DEVICE(M6530_TAG, mos6530_t, io_map) + AM_RANGE(0x0400, 0x07ff) AM_RAM AM_SHARE("share1") + AM_RANGE(0x0800, 0x0bff) AM_RAM AM_SHARE("share2") + AM_RANGE(0x0c00, 0x0fff) AM_RAM AM_SHARE("share3") + AM_RANGE(0x1000, 0x13ff) AM_RAM AM_SHARE("share4") + AM_RANGE(0x1c00, 0x1fff) AM_DEVICE(M6530_TAG, mos6530_t, rom_map) +ADDRESS_MAP_END + + +//------------------------------------------------- +// ADDRESS_MAP( c8250lp_fdc_mem ) +//------------------------------------------------- + +static ADDRESS_MAP_START( c8250lp_fdc_mem, AS_PROGRAM, 8, c8050_t ) + ADDRESS_MAP_GLOBAL_MASK(0x1fff) + AM_RANGE(0x0000, 0x003f) AM_MIRROR(0x0300) AM_DEVICE(M6530_TAG, mos6530_t, ram_map) + AM_RANGE(0x0040, 0x004f) AM_MIRROR(0x0330) AM_DEVICE(M6522_TAG, via6522_device, map) + AM_RANGE(0x0080, 0x008f) AM_MIRROR(0x0330) AM_DEVICE(M6530_TAG, mos6530_t, io_map) + AM_RANGE(0x0400, 0x07ff) AM_RAM AM_SHARE("share1") + AM_RANGE(0x0800, 0x0bff) AM_RAM AM_SHARE("share2") + AM_RANGE(0x0c00, 0x0fff) AM_RAM AM_SHARE("share3") + AM_RANGE(0x1000, 0x13ff) AM_RAM AM_SHARE("share4") + AM_RANGE(0x1800, 0x1fff) AM_ROM AM_REGION(M6504_TAG, 0) +ADDRESS_MAP_END + + +//------------------------------------------------- +// ADDRESS_MAP( sfd1001_fdc_mem ) +//------------------------------------------------- + +static ADDRESS_MAP_START( sfd1001_fdc_mem, AS_PROGRAM, 8, c8050_t ) + ADDRESS_MAP_GLOBAL_MASK(0x1fff) + AM_RANGE(0x0000, 0x003f) AM_MIRROR(0x0300) AM_DEVICE(M6530_TAG, mos6530_t, ram_map) + AM_RANGE(0x0040, 0x004f) AM_MIRROR(0x0330) AM_DEVICE(M6522_TAG, via6522_device, map) + AM_RANGE(0x0080, 0x008f) AM_MIRROR(0x0330) AM_DEVICE(M6530_TAG, mos6530_t, io_map) + AM_RANGE(0x0400, 0x07ff) AM_RAM AM_SHARE("share1") + AM_RANGE(0x0800, 0x0bff) AM_RAM AM_SHARE("share2") + AM_RANGE(0x0c00, 0x0fff) AM_RAM AM_SHARE("share3") + AM_RANGE(0x1000, 0x13ff) AM_RAM AM_SHARE("share4") + AM_RANGE(0x1800, 0x1fff) AM_ROM AM_REGION(M6504_TAG, 0) +ADDRESS_MAP_END + + +//------------------------------------------------- +// riot6532 uc1 +//------------------------------------------------- + +READ8_MEMBER( c8050_t::dio_r ) +{ + /* + + bit description + + PA0 DI0 + PA1 DI1 + PA2 DI2 + PA3 DI3 + PA4 DI4 + PA5 DI5 + PA6 DI6 + PA7 DI7 + + */ + + return m_bus->dio_r(); +} + +WRITE8_MEMBER( c8050_t::dio_w ) +{ + /* + + bit description + + PB0 DO0 + PB1 DO1 + PB2 DO2 + PB3 DO3 + PB4 DO4 + PB5 DO5 + PB6 DO6 + PB7 DO7 + + */ + + m_bus->dio_w(this, data); +} + +//------------------------------------------------- +// riot6532 ue1 +//------------------------------------------------- + +READ8_MEMBER( c8050_t::riot1_pa_r ) +{ + /* + + bit description + + PA0 ATNA + PA1 DACO + PA2 RFDO + PA3 EOIO + PA4 DAVO + PA5 EOII + PA6 DAVI + PA7 _ATN + + */ + + UINT8 data = 0; + + // end or identify in + data |= m_bus->eoi_r() << 5; + + // data valid in + data |= m_bus->dav_r() << 6; + + // attention + data |= !m_bus->atn_r() << 7; + + return data; +} + +WRITE8_MEMBER( c8050_t::riot1_pa_w ) +{ + /* + + bit description + + PA0 ATNA + PA1 DACO + PA2 RFDO + PA3 EOIO + PA4 DAVO + PA5 EOII + PA6 DAVI + PA7 _ATN + + */ + + // attention acknowledge + m_atna = BIT(data, 0); + + // data accepted out + m_daco = BIT(data, 1); + + // not ready for data out + m_rfdo = BIT(data, 2); + + // end or identify out + m_bus->eoi_w(this, BIT(data, 3)); + + // data valid out + m_bus->dav_w(this, BIT(data, 4)); + + update_ieee_signals(); +} + +READ8_MEMBER( c8050_t::riot1_pb_r ) +{ + /* + + bit description + + PB0 DEVICE NUMBER SELECTION + PB1 DEVICE NUMBER SELECTION + PB2 DEVICE NUMBER SELECTION + PB3 + PB4 + PB5 + PB6 DACI + PB7 RFDI + + */ + + UINT8 data = 0; + + // device number selection + data |= m_slot->get_address() - 8; + + // data accepted in + data |= m_bus->ndac_r() << 6; + + // ready for data in + data |= m_bus->nrfd_r() << 7; + + return data; +} + +WRITE8_MEMBER( c8050_t::riot1_pb_w ) +{ + /* + + bit description + + PB0 + PB1 + PB2 + PB3 ACT LED 1 + PB4 ACT LED 0 + PB5 ERR LED + PB6 + PB7 + + */ + + // activity led 1 + output_set_led_value(LED_ACT1, BIT(data, 3)); + + // activity led 0 + output_set_led_value(LED_ACT0, BIT(data, 4)); + + // error led + output_set_led_value(LED_ERR, BIT(data, 5)); +} + +WRITE8_MEMBER( c8050_t::via_pb_w ) +{ + /* + + bit description + + PB0 S1A + PB1 S1B + PB2 S0A + PB3 S0B + PB4 MTR1 + PB5 MTR0 + PB6 PULL SYNC + PB7 + + */ + + // spindle motor 1 + m_fdc->mtr1_w(BIT(data, 4)); + + // spindle motor 0 + m_fdc->mtr0_w(BIT(data, 5)); + + // stepper motor 1 + m_fdc->stp1_w(data & 0x03); + + // stepper motor 0 + m_fdc->stp0_w((data >> 2) & 0x03); + + // PLL sync + m_fdc->pull_sync_w(!BIT(data, 6)); +} + + +//------------------------------------------------- +// SLOT_INTERFACE( c8050_floppies ) +//------------------------------------------------- + +static SLOT_INTERFACE_START( c8050_floppies ) + SLOT_INTERFACE( "525ssqd", FLOPPY_525_SSQD ) +SLOT_INTERFACE_END + + +//------------------------------------------------- +// FLOPPY_FORMATS( floppy_formats ) +//------------------------------------------------- + +FLOPPY_FORMATS_MEMBER( c8050_t::floppy_formats ) + FLOPPY_D80_FORMAT +FLOPPY_FORMATS_END + + +//------------------------------------------------- +// SLOT_INTERFACE( c8250_floppies ) +//------------------------------------------------- + +static SLOT_INTERFACE_START( c8250_floppies ) + SLOT_INTERFACE( "525qd", FLOPPY_525_QD ) +SLOT_INTERFACE_END + + +//------------------------------------------------- +// SLOT_INTERFACE( sfd1001_floppies ) +//------------------------------------------------- + +static SLOT_INTERFACE_START( sfd1001_floppies ) + SLOT_INTERFACE( "525qd", FLOPPY_525_QD ) // Matsushita JU-570 / JU-570-2 +SLOT_INTERFACE_END + + +//------------------------------------------------- +// FLOPPY_FORMATS( floppy_formats ) +//------------------------------------------------- + +FLOPPY_FORMATS_MEMBER( c8250_t::floppy_formats ) + FLOPPY_D80_FORMAT, + FLOPPY_D82_FORMAT +FLOPPY_FORMATS_END + + +//------------------------------------------------- +// FLOPPY_FORMATS( floppy_formats ) +//------------------------------------------------- + +FLOPPY_FORMATS_MEMBER( c8250lp_t::floppy_formats ) + FLOPPY_D80_FORMAT, + FLOPPY_D82_FORMAT +FLOPPY_FORMATS_END + + +//------------------------------------------------- +// FLOPPY_FORMATS( floppy_formats ) +//------------------------------------------------- + +FLOPPY_FORMATS_MEMBER( sfd1001_t::floppy_formats ) + FLOPPY_D80_FORMAT, + FLOPPY_D82_FORMAT +FLOPPY_FORMATS_END + + +//------------------------------------------------- +// MACHINE_CONFIG_FRAGMENT( c8050 ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( c8050 ) + // DOS + MCFG_CPU_ADD(M6502_TAG, M6502, XTAL_12MHz/12) + MCFG_CPU_PROGRAM_MAP(c8050_main_mem) + + MCFG_DEVICE_ADD(M6532_0_TAG, MOS6532n, XTAL_12MHz/12) + MCFG_MOS6530n_IN_PA_CB(READ8(c8050_t, dio_r)) + MCFG_MOS6530n_OUT_PB_CB(WRITE8(c8050_t, dio_w)) + + MCFG_DEVICE_ADD(M6532_1_TAG, MOS6532n, XTAL_12MHz/12) + MCFG_MOS6530n_IN_PA_CB(READ8(c8050_t, riot1_pa_r)) + MCFG_MOS6530n_OUT_PA_CB(WRITE8(c8050_t, riot1_pa_w)) + MCFG_MOS6530n_IN_PB_CB(READ8(c8050_t, riot1_pb_r)) + MCFG_MOS6530n_OUT_PB_CB(WRITE8(c8050_t, riot1_pb_w)) + MCFG_MOS6530n_IRQ_CB(INPUTLINE(M6502_TAG, INPUT_LINE_IRQ0)) + + // controller + MCFG_CPU_ADD(M6504_TAG, M6504, XTAL_12MHz/12) + MCFG_CPU_PROGRAM_MAP(c8050_fdc_mem) + + MCFG_DEVICE_ADD(M6522_TAG, VIA6522, XTAL_12MHz/12) + MCFG_VIA6522_READPA_HANDLER(DEVREAD8(FDC_TAG, c8050_fdc_t, read)) + MCFG_VIA6522_WRITEPB_HANDLER(WRITE8(c8050_t, via_pb_w)) + MCFG_VIA6522_CA2_HANDLER(DEVWRITELINE(FDC_TAG, c8050_fdc_t, mode_sel_w)) + MCFG_VIA6522_CB2_HANDLER(DEVWRITELINE(FDC_TAG, c8050_fdc_t, rw_sel_w)) + + MCFG_DEVICE_ADD(M6530_TAG, MOS6530n, XTAL_12MHz/12) + MCFG_MOS6530n_OUT_PA_CB(DEVWRITE8(FDC_TAG, c8050_fdc_t, write)) + MCFG_MOS6530n_OUT_PB0_CB(DEVWRITELINE(FDC_TAG, c8050_fdc_t, drv_sel_w)) + MCFG_MOS6530n_OUT_PB1_CB(DEVWRITELINE(FDC_TAG, c8050_fdc_t, ds0_w)) + MCFG_MOS6530n_OUT_PB2_CB(DEVWRITELINE(FDC_TAG, c8050_fdc_t, ds1_w)) + MCFG_MOS6530n_IN_PB3_CB(DEVREADLINE(FDC_TAG, c8050_fdc_t, wps_r)) + MCFG_MOS6530n_IN_PB6_CB(VCC) // SINGLE SIDED + MCFG_MOS6530n_OUT_PB7_CB(INPUTLINE(M6504_TAG, M6502_IRQ_LINE)) + + MCFG_DEVICE_ADD(FDC_TAG, C8050_FDC, XTAL_12MHz/2) + MCFG_C8050_SYNC_CALLBACK(DEVWRITELINE(M6522_TAG, via6522_device, write_pb7)) + MCFG_C8050_READY_CALLBACK(DEVWRITELINE(M6522_TAG, via6522_device, write_ca1)) + MCFG_C8050_BRDY_CALLBACK(INPUTLINE(M6504_TAG, M6502_SET_OVERFLOW)) MCFG_DEVCB_XOR(1) + MCFG_C8050_ERROR_CALLBACK(DEVWRITELINE(M6522_TAG, via6522_device, write_cb1)) + MCFG_FLOPPY_DRIVE_ADD(FDC_TAG ":0", c8050_floppies, "525ssqd", c8050_t::floppy_formats) + MCFG_FLOPPY_DRIVE_ADD(FDC_TAG ":1", c8050_floppies, "525ssqd", c8050_t::floppy_formats) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor c8050_t::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( c8050 ); +} + + +//------------------------------------------------- +// MACHINE_CONFIG_FRAGMENT( c8250 ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( c8250 ) + // DOS + MCFG_CPU_ADD(M6502_TAG, M6502, XTAL_12MHz/12) + MCFG_CPU_PROGRAM_MAP(c8050_main_mem) + + MCFG_DEVICE_ADD(M6532_0_TAG, MOS6532n, XTAL_12MHz/12) + MCFG_MOS6530n_IN_PA_CB(READ8(c8050_t, dio_r)) + MCFG_MOS6530n_OUT_PB_CB(WRITE8(c8050_t, dio_w)) + + MCFG_DEVICE_ADD(M6532_1_TAG, MOS6532n, XTAL_12MHz/12) + MCFG_MOS6530n_IN_PA_CB(READ8(c8050_t, riot1_pa_r)) + MCFG_MOS6530n_OUT_PA_CB(WRITE8(c8050_t, riot1_pa_w)) + MCFG_MOS6530n_IN_PB_CB(READ8(c8050_t, riot1_pb_r)) + MCFG_MOS6530n_OUT_PB_CB(WRITE8(c8050_t, riot1_pb_w)) + MCFG_MOS6530n_IRQ_CB(INPUTLINE(M6502_TAG, INPUT_LINE_IRQ0)) + + // controller + MCFG_CPU_ADD(M6504_TAG, M6504, XTAL_12MHz/12) + MCFG_CPU_PROGRAM_MAP(c8050_fdc_mem) + + MCFG_DEVICE_ADD(M6522_TAG, VIA6522, XTAL_12MHz/12) + MCFG_VIA6522_READPA_HANDLER(DEVREAD8(FDC_TAG, c8050_fdc_t, read)) + MCFG_VIA6522_WRITEPB_HANDLER(WRITE8(c8050_t, via_pb_w)) + MCFG_VIA6522_CA2_HANDLER(DEVWRITELINE(FDC_TAG, c8050_fdc_t, mode_sel_w)) + MCFG_VIA6522_CB2_HANDLER(DEVWRITELINE(FDC_TAG, c8050_fdc_t, rw_sel_w)) + + MCFG_DEVICE_ADD(M6530_TAG, MOS6530n, XTAL_12MHz/12) + MCFG_MOS6530n_OUT_PA_CB(DEVWRITE8(FDC_TAG, c8050_fdc_t, write)) + MCFG_MOS6530n_OUT_PB0_CB(DEVWRITELINE(FDC_TAG, c8050_fdc_t, drv_sel_w)) + MCFG_MOS6530n_OUT_PB1_CB(DEVWRITELINE(FDC_TAG, c8050_fdc_t, ds0_w)) + MCFG_MOS6530n_OUT_PB2_CB(DEVWRITELINE(FDC_TAG, c8050_fdc_t, ds1_w)) + MCFG_MOS6530n_IN_PB3_CB(DEVREADLINE(FDC_TAG, c8050_fdc_t, wps_r)) + MCFG_MOS6530n_OUT_PB4_CB(DEVWRITELINE(FDC_TAG, c8050_fdc_t, odd_hd_w)) + MCFG_MOS6530n_IN_PB6_CB(GND) // DOUBLE SIDED + MCFG_MOS6530n_OUT_PB7_CB(INPUTLINE(M6504_TAG, M6502_IRQ_LINE)) + + MCFG_DEVICE_ADD(FDC_TAG, C8050_FDC, XTAL_12MHz/2) + MCFG_C8050_SYNC_CALLBACK(DEVWRITELINE(M6522_TAG, via6522_device, write_pb7)) + MCFG_C8050_READY_CALLBACK(DEVWRITELINE(M6522_TAG, via6522_device, write_ca1)) + MCFG_C8050_BRDY_CALLBACK(INPUTLINE(M6504_TAG, M6502_SET_OVERFLOW)) MCFG_DEVCB_XOR(1) + MCFG_C8050_ERROR_CALLBACK(DEVWRITELINE(M6522_TAG, via6522_device, write_cb1)) + MCFG_FLOPPY_DRIVE_ADD(FDC_TAG ":0", c8250_floppies, "525qd", c8250_t::floppy_formats) + MCFG_FLOPPY_DRIVE_ADD(FDC_TAG ":1", c8250_floppies, "525qd", c8250_t::floppy_formats) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor c8250_t::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( c8250 ); +} + + +//------------------------------------------------- +// MACHINE_CONFIG_FRAGMENT( c8250lp ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( c8250lp ) + // DOS + MCFG_CPU_ADD(M6502_TAG, M6502, XTAL_12MHz/12) + MCFG_CPU_PROGRAM_MAP(c8050_main_mem) + + MCFG_DEVICE_ADD(M6532_0_TAG, MOS6532n, XTAL_12MHz/12) + MCFG_MOS6530n_IN_PA_CB(READ8(c8050_t, dio_r)) + MCFG_MOS6530n_OUT_PB_CB(WRITE8(c8050_t, dio_w)) + + MCFG_DEVICE_ADD(M6532_1_TAG, MOS6532n, XTAL_12MHz/12) + MCFG_MOS6530n_IN_PA_CB(READ8(c8050_t, riot1_pa_r)) + MCFG_MOS6530n_OUT_PA_CB(WRITE8(c8050_t, riot1_pa_w)) + MCFG_MOS6530n_IN_PB_CB(READ8(c8050_t, riot1_pb_r)) + MCFG_MOS6530n_OUT_PB_CB(WRITE8(c8050_t, riot1_pb_w)) + MCFG_MOS6530n_IRQ_CB(INPUTLINE(M6502_TAG, INPUT_LINE_IRQ0)) + + // controller + MCFG_CPU_ADD(M6504_TAG, M6504, XTAL_12MHz/12) + MCFG_CPU_PROGRAM_MAP(c8250lp_fdc_mem) + + MCFG_DEVICE_ADD(M6522_TAG, VIA6522, XTAL_12MHz/12) + MCFG_VIA6522_READPA_HANDLER(DEVREAD8(FDC_TAG, c8050_fdc_t, read)) + MCFG_VIA6522_WRITEPB_HANDLER(WRITE8(c8050_t, via_pb_w)) + MCFG_VIA6522_CA2_HANDLER(DEVWRITELINE(FDC_TAG, c8050_fdc_t, mode_sel_w)) + MCFG_VIA6522_CB2_HANDLER(DEVWRITELINE(FDC_TAG, c8050_fdc_t, rw_sel_w)) + + MCFG_DEVICE_ADD(M6530_TAG, MOS6530n, XTAL_12MHz/12) + MCFG_MOS6530n_OUT_PA_CB(DEVWRITE8(FDC_TAG, c8050_fdc_t, write)) + MCFG_MOS6530n_OUT_PB0_CB(DEVWRITELINE(FDC_TAG, c8050_fdc_t, drv_sel_w)) + MCFG_MOS6530n_OUT_PB1_CB(DEVWRITELINE(FDC_TAG, c8050_fdc_t, ds0_w)) + MCFG_MOS6530n_OUT_PB2_CB(DEVWRITELINE(FDC_TAG, c8050_fdc_t, ds1_w)) + MCFG_MOS6530n_IN_PB3_CB(DEVREADLINE(FDC_TAG, c8050_fdc_t, wps_r)) + MCFG_MOS6530n_OUT_PB4_CB(DEVWRITELINE(FDC_TAG, c8050_fdc_t, odd_hd_w)) + MCFG_MOS6530n_IN_PB6_CB(GND) // DOUBLE SIDED + MCFG_MOS6530n_OUT_PB7_CB(INPUTLINE(M6504_TAG, M6502_IRQ_LINE)) + + MCFG_DEVICE_ADD(FDC_TAG, C8050_FDC, XTAL_12MHz/2) + MCFG_C8050_SYNC_CALLBACK(DEVWRITELINE(M6522_TAG, via6522_device, write_pb7)) + MCFG_C8050_READY_CALLBACK(DEVWRITELINE(M6522_TAG, via6522_device, write_ca1)) + MCFG_C8050_BRDY_CALLBACK(INPUTLINE(M6504_TAG, M6502_SET_OVERFLOW)) MCFG_DEVCB_XOR(1) + MCFG_C8050_ERROR_CALLBACK(DEVWRITELINE(M6522_TAG, via6522_device, write_cb1)) + MCFG_FLOPPY_DRIVE_ADD(FDC_TAG ":0", c8250_floppies, "525qd", c8250lp_t::floppy_formats) + MCFG_FLOPPY_DRIVE_ADD(FDC_TAG ":1", c8250_floppies, "525qd", c8250lp_t::floppy_formats) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor c8250lp_t::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( c8250lp ); +} + + +//------------------------------------------------- +// MACHINE_CONFIG_FRAGMENT( sfd1001 ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( sfd1001 ) + // DOS + MCFG_CPU_ADD(M6502_TAG, M6502, XTAL_12MHz/12) + MCFG_CPU_PROGRAM_MAP(c8050_main_mem) + + MCFG_DEVICE_ADD(M6532_0_TAG, MOS6532n, XTAL_12MHz/12) + MCFG_MOS6530n_IN_PA_CB(READ8(c8050_t, dio_r)) + MCFG_MOS6530n_OUT_PB_CB(WRITE8(c8050_t, dio_w)) + + MCFG_DEVICE_ADD(M6532_1_TAG, MOS6532n, XTAL_12MHz/12) + MCFG_MOS6530n_IN_PA_CB(READ8(c8050_t, riot1_pa_r)) + MCFG_MOS6530n_OUT_PA_CB(WRITE8(c8050_t, riot1_pa_w)) + MCFG_MOS6530n_IN_PB_CB(READ8(c8050_t, riot1_pb_r)) + MCFG_MOS6530n_OUT_PB_CB(WRITE8(c8050_t, riot1_pb_w)) + MCFG_MOS6530n_IRQ_CB(INPUTLINE(M6502_TAG, INPUT_LINE_IRQ0)) + + // controller + MCFG_CPU_ADD(M6504_TAG, M6504, XTAL_12MHz/12) + MCFG_CPU_PROGRAM_MAP(sfd1001_fdc_mem) + + MCFG_DEVICE_ADD(M6522_TAG, VIA6522, XTAL_12MHz/12) + MCFG_VIA6522_READPA_HANDLER(DEVREAD8(FDC_TAG, c8050_fdc_t, read)) + MCFG_VIA6522_WRITEPB_HANDLER(WRITE8(c8050_t, via_pb_w)) + MCFG_VIA6522_CA2_HANDLER(DEVWRITELINE(FDC_TAG, c8050_fdc_t, mode_sel_w)) + MCFG_VIA6522_CB2_HANDLER(DEVWRITELINE(FDC_TAG, c8050_fdc_t, rw_sel_w)) + + MCFG_DEVICE_ADD(M6530_TAG, MOS6530n, XTAL_12MHz/12) + MCFG_MOS6530n_OUT_PA_CB(DEVWRITE8(FDC_TAG, c8050_fdc_t, write)) + MCFG_MOS6530n_OUT_PB1_CB(DEVWRITELINE(FDC_TAG, c8050_fdc_t, ds0_w)) + MCFG_MOS6530n_OUT_PB2_CB(DEVWRITELINE(FDC_TAG, c8050_fdc_t, ds1_w)) + MCFG_MOS6530n_IN_PB3_CB(DEVREADLINE(FDC_TAG, c8050_fdc_t, wps_r)) + MCFG_MOS6530n_OUT_PB4_CB(DEVWRITELINE(FDC_TAG, c8050_fdc_t, odd_hd_w)) + MCFG_MOS6530n_IN_PB6_CB(GND) // DOUBLE SIDED + MCFG_MOS6530n_OUT_PB7_CB(INPUTLINE(M6504_TAG, M6502_IRQ_LINE)) + + MCFG_DEVICE_ADD(FDC_TAG, C8050_FDC, XTAL_12MHz/2) + MCFG_C8050_SYNC_CALLBACK(DEVWRITELINE(M6522_TAG, via6522_device, write_pb7)) + MCFG_C8050_READY_CALLBACK(DEVWRITELINE(M6522_TAG, via6522_device, write_ca1)) + MCFG_C8050_BRDY_CALLBACK(INPUTLINE(M6504_TAG, M6502_SET_OVERFLOW)) MCFG_DEVCB_XOR(1) + MCFG_C8050_ERROR_CALLBACK(DEVWRITELINE(M6522_TAG, via6522_device, write_cb1)) + MCFG_FLOPPY_DRIVE_ADD(FDC_TAG ":0", sfd1001_floppies, "525qd", sfd1001_t::floppy_formats) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor sfd1001_t::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( sfd1001 ); +} + + +//------------------------------------------------- +// INPUT_PORTS( c8050 ) +//------------------------------------------------- + +static INPUT_PORTS_START( c8050 ) + PORT_START("ADDRESS") + PORT_DIPNAME( 0x07, 0x00, "Device Address" ) + PORT_DIPSETTING( 0x00, "8" ) + PORT_DIPSETTING( 0x01, "9" ) + PORT_DIPSETTING( 0x02, "10" ) + PORT_DIPSETTING( 0x03, "11" ) + PORT_DIPSETTING( 0x04, "12" ) + PORT_DIPSETTING( 0x05, "13" ) + PORT_DIPSETTING( 0x06, "14" ) + PORT_DIPSETTING( 0x07, "15" ) +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor c8050_t::device_input_ports() const +{ + return INPUT_PORTS_NAME( c8050 ); +} + + + +//************************************************************************** +// INLINE HELPERS +//************************************************************************** + +//------------------------------------------------- +// update_ieee_signals - +//------------------------------------------------- + +inline void c8050_t::update_ieee_signals() +{ + int atn = m_bus->atn_r(); + int nrfd = !(!(!(atn && m_atna) && m_rfdo) || !(atn || m_atna)); + int ndac = !(m_daco || !(atn || m_atna)); + + m_bus->nrfd_w(this, nrfd); + m_bus->ndac_w(this, ndac); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// c8050_t - constructor +//------------------------------------------------- + +c8050_t::c8050_t(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_ieee488_interface(mconfig, *this), + m_maincpu(*this, M6502_TAG), + m_fdccpu(*this, M6504_TAG), + m_riot0(*this, M6532_0_TAG), + m_riot1(*this, M6532_1_TAG), + m_miot(*this, M6530_TAG), + m_via(*this, M6522_TAG), + m_floppy0(*this, FDC_TAG ":0"), + m_floppy1(*this, FDC_TAG ":1"), + m_fdc(*this, FDC_TAG), + m_address(*this, "ADDRESS"), + m_rfdo(1), + m_daco(1), + m_atna(1) +{ +} + +c8050_t::c8050_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, C8050, "C8050", tag, owner, clock, "c8050", __FILE__), + device_ieee488_interface(mconfig, *this), + m_maincpu(*this, M6502_TAG), + m_fdccpu(*this, M6504_TAG), + m_riot0(*this, M6532_0_TAG), + m_riot1(*this, M6532_1_TAG), + m_miot(*this, M6530_TAG), + m_via(*this, M6522_TAG), + m_floppy0(*this, FDC_TAG ":0"), + m_floppy1(*this, FDC_TAG ":1"), + m_fdc(*this, FDC_TAG), + m_address(*this, "ADDRESS"), + m_rfdo(1), + m_daco(1), + m_atna(1) +{ +} + + +//------------------------------------------------- +// c8250_t - constructor +//------------------------------------------------- + +c8250_t::c8250_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + c8050_t(mconfig, C8250, "C8250", tag, owner, clock, "c8250", __FILE__) { } + + +//------------------------------------------------- +// c8250lp_t - constructor +//------------------------------------------------- + +c8250lp_t::c8250lp_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + c8050_t(mconfig, C8250LP, "C8250LP", tag, owner, clock, "c8250lp", __FILE__) { } + + +//------------------------------------------------- +// sfd1001_t - constructor +//------------------------------------------------- + +sfd1001_t::sfd1001_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + c8050_t(mconfig, SFD1001, "SFD1001", tag, owner, clock, "sfd1001", __FILE__) { } + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void c8050_t::device_start() +{ + // install image callbacks + m_fdc->set_floppy(m_floppy0, m_floppy1); + + // register for state saving + save_item(NAME(m_rfdo)); + save_item(NAME(m_daco)); + save_item(NAME(m_atna)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void c8050_t::device_reset() +{ + m_maincpu->reset(); + + // toggle M6502 SO + m_maincpu->set_input_line(M6502_SET_OVERFLOW, ASSERT_LINE); + m_maincpu->set_input_line(M6502_SET_OVERFLOW, CLEAR_LINE); + + m_fdccpu->reset(); + + m_riot0->reset(); + m_riot1->reset(); + m_miot->reset(); + m_via->reset(); + + m_riot1->pa7_w(1); + + // turn off spindle motors + m_fdc->mtr0_w(1); + m_fdc->mtr1_w(1); +} + + +//------------------------------------------------- +// ieee488_atn - +//------------------------------------------------- + +void c8050_t::ieee488_atn(int state) +{ + update_ieee_signals(); + + m_riot1->pa7_w(state); +} + + +//------------------------------------------------- +// ieee488_ifc - +//------------------------------------------------- + +void c8050_t::ieee488_ifc(int state) +{ + if (!m_ifc && state) + { + device_reset(); + } + + m_ifc = state; +} diff --git a/src/devices/bus/ieee488/c8050.h b/src/devices/bus/ieee488/c8050.h new file mode 100644 index 00000000000..3d5904dd6cb --- /dev/null +++ b/src/devices/bus/ieee488/c8050.h @@ -0,0 +1,140 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Commodore 8050/8250/SFD-1001 Disk Drive emulation + +**********************************************************************/ + +#pragma once + +#ifndef __C8050__ +#define __C8050__ + +#include "emu.h" +#include "ieee488.h" +#include "c8050fdc.h" +#include "cpu/m6502/m6502.h" +#include "cpu/m6502/m6504.h" +#include "machine/6522via.h" +#include "machine/mos6530n.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> c8050_t + +class c8050_t : public device_t, + public device_ieee488_interface +{ +public: + // construction/destruction + c8050_t(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + c8050_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + virtual ioport_constructor device_input_ports() const; + + DECLARE_READ8_MEMBER( dio_r ); + DECLARE_WRITE8_MEMBER( dio_w ); + DECLARE_READ8_MEMBER( riot1_pa_r ); + DECLARE_WRITE8_MEMBER( riot1_pa_w ); + DECLARE_READ8_MEMBER( riot1_pb_r ); + DECLARE_WRITE8_MEMBER( riot1_pb_w ); + DECLARE_WRITE8_MEMBER( via_pb_w ); + DECLARE_READ8_MEMBER( pi_r ); + DECLARE_WRITE8_MEMBER( pi_w ); + + DECLARE_FLOPPY_FORMATS( floppy_formats ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_ieee488_interface overrides + virtual void ieee488_atn(int state); + virtual void ieee488_ifc(int state); + + inline void update_ieee_signals(); + + required_device m_maincpu; + required_device m_fdccpu; + required_device m_riot0; + required_device m_riot1; + required_device m_miot; + required_device m_via; + required_device m_floppy0; + optional_device m_floppy1; + required_device m_fdc; + required_ioport m_address; + + // IEEE-488 bus + int m_rfdo; // not ready for data output + int m_daco; // not data accepted output + int m_atna; // attention acknowledge + int m_ifc; +}; + + +// ======================> c8250_t + +class c8250_t : public c8050_t +{ +public: + // construction/destruction + c8250_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + + DECLARE_FLOPPY_FORMATS( floppy_formats ); +}; + + +// ======================> c8250lp_t + +class c8250lp_t : public c8050_t +{ +public: + // construction/destruction + c8250lp_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + + DECLARE_FLOPPY_FORMATS( floppy_formats ); +}; + + +// ======================> sfd1001_t + +class sfd1001_t : public c8050_t +{ +public: + // construction/destruction + sfd1001_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + + DECLARE_FLOPPY_FORMATS( floppy_formats ); +}; + + +// device type definition +extern const device_type C8050; +extern const device_type C8250; +extern const device_type C8250LP; +extern const device_type SFD1001; + + + +#endif diff --git a/src/devices/bus/ieee488/c8050fdc.c b/src/devices/bus/ieee488/c8050fdc.c new file mode 100644 index 00000000000..02bceb80328 --- /dev/null +++ b/src/devices/bus/ieee488/c8050fdc.c @@ -0,0 +1,634 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Commodore 8050 floppy disk controller emulation + +**********************************************************************/ + +/* + + TODO: + + - write protect + - 75,format speed error,01,00,0 + +*/ + +#include "c8050fdc.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define LOG 0 +#define LOG_MORE 0 +#define LOG_BITS 0 + +#define GCR_DECODE(_e, _i) \ + ((BIT(_e, 6) << 7) | (BIT(_i, 7) << 6) | (_e & 0x33) | (BIT(_e, 2) << 3) | (_i & 0x04)) + +#define GCR_ENCODE(_e, _i) \ + ((_e & 0xc0) << 2 | (_i & 0x80) | (_e & 0x3c) << 1 | (_i & 0x04) | (_e & 0x03)) + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type C8050_FDC = &device_creator; + + +//------------------------------------------------- +// ROM( c8050_fdc ) +//------------------------------------------------- + +ROM_START( c8050_fdc ) + ROM_REGION( 0x800, "gcr", 0) + ROM_LOAD( "901467.uk6", 0x000, 0x800, CRC(a23337eb) SHA1(97df576397608455616331f8e837cb3404363fa2) ) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *c8050_fdc_t::device_rom_region() const +{ + return ROM_NAME( c8050_fdc ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// c8050_fdc_t - constructor +//------------------------------------------------- + +c8050_fdc_t::c8050_fdc_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, C8050_FDC, "Commodore 8050 FDC", tag, owner, clock, "c8050fdc", __FILE__), + m_write_sync(*this), + m_write_ready(*this), + m_write_brdy(*this), + m_write_error(*this), + m_gcr_rom(*this, "gcr"), + m_floppy0(NULL), + m_floppy1(NULL), + m_mtr0(1), + m_mtr1(1), + m_stp0(0), + m_stp1(0), + m_ds(0), + m_ds0(0), + m_ds1(0), + m_drv_sel(0), + m_mode_sel(0), + m_rw_sel(1) +{ + cur_live.tm = attotime::never; + cur_live.state = IDLE; + cur_live.next_state = -1; + cur_live.drv_sel = m_drv_sel; +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void c8050_fdc_t::device_start() +{ + // resolve callbacks + m_write_sync.resolve_safe(); + m_write_ready.resolve_safe(); + m_write_brdy.resolve_safe(); + m_write_error.resolve_safe(); + + // allocate timer + t_gen = timer_alloc(0); + + // register for state saving + save_item(NAME(m_mtr0)); + save_item(NAME(m_mtr1)); + save_item(NAME(m_stp0)); + save_item(NAME(m_stp1)); + save_item(NAME(m_ds)); + save_item(NAME(m_ds0)); + save_item(NAME(m_ds1)); + save_item(NAME(m_drv_sel)); + save_item(NAME(m_mode_sel)); + save_item(NAME(m_rw_sel)); + save_item(NAME(m_odd_hd)); + save_item(NAME(m_pi)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void c8050_fdc_t::device_reset() +{ + live_abort(); +} + + +//------------------------------------------------- +// device_timer - handler timer events +//------------------------------------------------- + +void c8050_fdc_t::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + live_sync(); + live_run(); +} + +floppy_image_device* c8050_fdc_t::get_floppy() +{ + return cur_live.drv_sel ? m_floppy1 : m_floppy0; +} + +void c8050_fdc_t::stp_w(floppy_image_device *floppy, int mtr, int &old_stp, int stp) +{ + if (mtr) return; + + int tracks = 0; + + switch (old_stp) + { + case 0: if (stp == 1) tracks++; else if (stp == 2) tracks--; break; + case 1: if (stp == 3) tracks++; else if (stp == 0) tracks--; break; + case 2: if (stp == 0) tracks++; else if (stp == 3) tracks--; break; + case 3: if (stp == 2) tracks++; else if (stp == 1) tracks--; break; + } + + if (tracks == -1) + { + floppy->dir_w(1); + floppy->stp_w(1); + floppy->stp_w(0); + } + else if (tracks == 1) + { + floppy->dir_w(0); + floppy->stp_w(1); + floppy->stp_w(0); + } + + old_stp = stp; +} + +void c8050_fdc_t::stp0_w(int stp) +{ + if (m_stp0 != stp) + { + live_sync(); + stp_w(m_floppy0, m_mtr0, m_stp0, stp); + checkpoint(); + live_run(); + } +} + +void c8050_fdc_t::stp1_w(int stp) +{ + if (m_stp1 != stp) + { + live_sync(); + if (m_floppy1) stp_w(m_floppy1, m_mtr1, m_stp1, stp); + checkpoint(); + live_run(); + } +} + +void c8050_fdc_t::ds_w(int ds) +{ + if (m_ds != ds) + { + live_sync(); + m_ds = cur_live.ds = ds; + pll_reset(cur_live.tm); + if (LOG) logerror("%s %s DS %u\n", machine().time().as_string(), machine().describe_context(), ds); + checkpoint(); + live_run(); + } +} + +void c8050_fdc_t::set_floppy(floppy_connector *floppy0, floppy_connector *floppy1) +{ + m_floppy0 = floppy0->get_device(); + + if (floppy1) { + m_floppy1 = floppy1->get_device(); + } +} + +void c8050_fdc_t::live_start() +{ + cur_live.tm = machine().time(); + cur_live.state = RUNNING; + cur_live.next_state = -1; + + cur_live.shift_reg = 0; + cur_live.shift_reg_write = 0; + cur_live.bit_counter = 0; + cur_live.ds = m_ds; + cur_live.drv_sel = m_drv_sel; + cur_live.mode_sel = m_mode_sel; + cur_live.rw_sel = m_rw_sel; + cur_live.pi = m_pi; + + pll_reset(cur_live.tm); + checkpoint_live = cur_live; + pll_save_checkpoint(); + + live_run(); +} + +void c8050_fdc_t::pll_reset(const attotime &when) +{ + cur_pll.reset(when); + cur_pll.set_clock(attotime::from_hz(clock() / (16 - m_ds))); +} + +void c8050_fdc_t::pll_start_writing(const attotime &tm) +{ + cur_pll.start_writing(tm); + pll_reset(cur_live.tm); +} + +void c8050_fdc_t::pll_commit(floppy_image_device *floppy, const attotime &tm) +{ + cur_pll.commit(floppy, tm); +} + +void c8050_fdc_t::pll_stop_writing(floppy_image_device *floppy, const attotime &tm) +{ + cur_pll.stop_writing(floppy, tm); + pll_reset(cur_live.tm); +} + +void c8050_fdc_t::pll_save_checkpoint() +{ + checkpoint_pll = cur_pll; +} + +void c8050_fdc_t::pll_retrieve_checkpoint() +{ + cur_pll = checkpoint_pll; +} + +int c8050_fdc_t::pll_get_next_bit(attotime &tm, floppy_image_device *floppy, const attotime &limit) +{ + return cur_pll.get_next_bit(tm, floppy, limit); +} + +bool c8050_fdc_t::pll_write_next_bit(bool bit, attotime &tm, floppy_image_device *floppy, const attotime &limit) +{ + return cur_pll.write_next_bit(bit, tm, floppy, limit); +} + +void c8050_fdc_t::checkpoint() +{ + pll_commit(get_floppy(), cur_live.tm); + checkpoint_live = cur_live; + pll_save_checkpoint(); +} + +void c8050_fdc_t::rollback() +{ + cur_live = checkpoint_live; + pll_retrieve_checkpoint(); +} + +void c8050_fdc_t::live_delay(int state) +{ + cur_live.next_state = state; + if(cur_live.tm != machine().time()) + t_gen->adjust(cur_live.tm - machine().time()); + else + live_sync(); +} + +void c8050_fdc_t::live_sync() +{ + if(!cur_live.tm.is_never()) { + if(cur_live.tm > machine().time()) { + rollback(); + live_run(machine().time()); + pll_commit(get_floppy(), cur_live.tm); + } else { + pll_commit(get_floppy(), cur_live.tm); + if(cur_live.next_state != -1) { + cur_live.state = cur_live.next_state; + cur_live.next_state = -1; + } + if(cur_live.state == IDLE) { + pll_stop_writing(get_floppy(), cur_live.tm); + cur_live.tm = attotime::never; + } + } + cur_live.next_state = -1; + checkpoint(); + } +} + +void c8050_fdc_t::live_abort() +{ + if(!cur_live.tm.is_never() && cur_live.tm > machine().time()) { + rollback(); + live_run(machine().time()); + } + + pll_stop_writing(get_floppy(), cur_live.tm); + + cur_live.tm = attotime::never; + cur_live.state = IDLE; + cur_live.next_state = -1; + + cur_live.ready = 1; + cur_live.brdy = 1; + cur_live.sync = 1; + cur_live.error = 1; +} + +void c8050_fdc_t::live_run(const attotime &limit) +{ + if(cur_live.state == IDLE || cur_live.next_state != -1) + return; + + for(;;) { + switch(cur_live.state) { + case RUNNING: { + bool syncpoint = false; + + if (cur_live.tm > limit) + return; + + // read bit + int bit = 0; + if (cur_live.rw_sel) { + bit = pll_get_next_bit(cur_live.tm, get_floppy(), limit); + if(bit < 0) + return; + } + + // write bit + int write_bit = BIT(cur_live.shift_reg_write, 9); + if (!cur_live.rw_sel) { // TODO WPS + /* + write precompensation + + UA5.A = UM6.Qc + UA5.B = !(!(!BRDY && UM6.Qa) && !(BRDY && E7)) + UA5.C0 = UA4.Qb = bit clock delayed 333ns + UA5.C1 = UA4.Qa = bit clock delayed 166ns + UA5.C2 = UA4.Qc = bit clock delayed 499ns + UA5.C3 = UA5.Qb = bit clock delayed 333ns + + DATA OUT = !(!BITCLK || !(UA5.Y && !(WRITE_ENABLE && !UM6.Qb))) + */ + if (pll_write_next_bit(write_bit, cur_live.tm, get_floppy(), limit)) + return; + } + + // clock read shift register + cur_live.shift_reg <<= 1; + cur_live.shift_reg |= bit; + cur_live.shift_reg &= 0x3ff; + + // sync + int sync = !((cur_live.shift_reg == 0x3ff) && cur_live.rw_sel); + + // bit counter + if (!sync) { + cur_live.bit_counter = 0; + } else if (cur_live.sync) { + cur_live.bit_counter++; + if (cur_live.bit_counter == 10) { + cur_live.bit_counter = 0; + } + } + + // GCR decoder + if (cur_live.rw_sel) { + cur_live.i = (cur_live.rw_sel << 10) | cur_live.shift_reg; + } else { + cur_live.i = (cur_live.rw_sel << 10) | ((cur_live.pi & 0xf0) << 1) | (cur_live.mode_sel << 4) | (cur_live.pi & 0x0f); + } + + cur_live.e = m_gcr_rom->base()[cur_live.i]; + + // byte ready + int ready = !(cur_live.bit_counter == 9); // 74190 _RC, should be triggered on the falling edge of the clock + int brdy = ready; // 74190 TC + + // GCR error + int error = !(ready || BIT(cur_live.e, 3)); + + if (LOG_BITS) { + if (cur_live.rw_sel) { + logerror("%s cyl %u bit %u sync %u bc %u sr %03x i %03x e %02x\n",cur_live.tm.as_string(),get_floppy()->get_cyl(),bit,sync,cur_live.bit_counter,cur_live.shift_reg,cur_live.i,cur_live.e); + } else { + logerror("%s cyl %u writing bit %u bc %u sr %03x i %03x e %02x\n",cur_live.tm.as_string(),get_floppy()->get_cyl(),write_bit,cur_live.bit_counter,cur_live.shift_reg_write,cur_live.i,cur_live.e); + } + } + + if (!ready) { + // load write shift register + cur_live.shift_reg_write = GCR_ENCODE(cur_live.e, cur_live.i); + + if (LOG_BITS) logerror("%s load write shift register %03x\n",cur_live.tm.as_string(),cur_live.shift_reg_write); + } else { + // clock write shift register + cur_live.shift_reg_write <<= 1; + cur_live.shift_reg_write &= 0x3ff; + } + + if (ready != cur_live.ready) { + if (cur_live.rw_sel && !ready) + if (LOG) logerror("%s READY %u : %02x\n", cur_live.tm.as_string(),ready,GCR_DECODE(cur_live.e, cur_live.i)); + cur_live.ready = ready; + syncpoint = true; + } + + if (brdy != cur_live.brdy) { + if (LOG_MORE) logerror("%s BRDY %u\n", cur_live.tm.as_string(), brdy); + cur_live.brdy = brdy; + syncpoint = true; + } + + if (sync != cur_live.sync) { + if (LOG) logerror("%s SYNC %u\n", cur_live.tm.as_string(), sync); + cur_live.sync = sync; + syncpoint = true; + } + + if (error != cur_live.error) { + if (LOG_MORE) logerror("%s ERROR %u\n", cur_live.tm.as_string(), error); + cur_live.error = error; + syncpoint = true; + } + + if (syncpoint) { + live_delay(RUNNING_SYNCPOINT); + return; + } + break; + } + + case RUNNING_SYNCPOINT: { + m_write_ready(cur_live.ready); + m_write_brdy(cur_live.brdy); + m_write_sync(cur_live.sync); + m_write_error(cur_live.error); + + cur_live.state = RUNNING; + checkpoint(); + break; + } + } + } +} + +READ8_MEMBER( c8050_fdc_t::read ) +{ + UINT8 e = checkpoint_live.e; + offs_t i = checkpoint_live.i; + + return GCR_DECODE(e, i); +} + +WRITE8_MEMBER( c8050_fdc_t::write ) +{ + if (LOG) logerror("%s %s PI %02x\n", machine().time().as_string(), machine().describe_context(), data); + + if (m_pi != data) + { + live_sync(); + m_pi = cur_live.pi = data; + checkpoint(); + live_run(); + } +} + +WRITE_LINE_MEMBER( c8050_fdc_t::ds0_w ) +{ + m_ds0 = state; +} + +WRITE_LINE_MEMBER( c8050_fdc_t::ds1_w ) +{ + m_ds1 = state; + + ds_w(m_ds1 << 1 | m_ds0); +} + +WRITE_LINE_MEMBER( c8050_fdc_t::drv_sel_w ) +{ + if (m_drv_sel != state) + { + live_sync(); + m_drv_sel = cur_live.drv_sel = state; + checkpoint(); + if (LOG) logerror("%s %s DRV SEL %u\n", machine().time().as_string(), machine().describe_context(), state); + live_run(); + } +} + +WRITE_LINE_MEMBER( c8050_fdc_t::mode_sel_w ) +{ + if (m_mode_sel != state) + { + live_sync(); + m_mode_sel = cur_live.mode_sel = state; + checkpoint(); + if (LOG) logerror("%s %s MODE SEL %u\n", machine().time().as_string(), machine().describe_context(), state); + live_run(); + } +} + +WRITE_LINE_MEMBER( c8050_fdc_t::rw_sel_w ) +{ + if (m_rw_sel != state) + { + live_sync(); + m_rw_sel = cur_live.rw_sel = state; + checkpoint(); + if (LOG) logerror("%s %s RW SEL %u\n", machine().time().as_string(), machine().describe_context(), state); + if (m_rw_sel) { + pll_stop_writing(get_floppy(), cur_live.tm); + } else { + pll_start_writing(cur_live.tm); + } + live_run(); + } +} + +WRITE_LINE_MEMBER( c8050_fdc_t::mtr0_w ) +{ + if (m_mtr0 != state) + { + live_sync(); + m_mtr0 = state; + if (LOG) logerror("%s %s MTR0 %u\n", machine().time().as_string(), machine().describe_context(), state); + m_floppy0->mon_w(state); + checkpoint(); + + if (!m_mtr0 || !m_mtr1) { + if(cur_live.state == IDLE) { + live_start(); + } + } else { + live_abort(); + } + + live_run(); + } +} + +WRITE_LINE_MEMBER( c8050_fdc_t::mtr1_w ) +{ + if (m_mtr1 != state) + { + live_sync(); + m_mtr1 = state; + if (LOG) logerror("%s %s MTR1 %u\n", machine().time().as_string(), machine().describe_context(), state); + if (m_floppy1) m_floppy1->mon_w(state); + checkpoint(); + + if (!m_mtr0 || !m_mtr1) { + if(cur_live.state == IDLE) { + live_start(); + } + } else { + live_abort(); + } + + live_run(); + } +} + +WRITE_LINE_MEMBER( c8050_fdc_t::odd_hd_w ) +{ + if (m_odd_hd != state) + { + live_sync(); + m_odd_hd = cur_live.odd_hd = state; + if (LOG) logerror("%s %s ODD HD %u\n", machine().time().as_string(), machine().describe_context(), state); + m_floppy0->ss_w(!state); + if (m_floppy1) m_floppy1->ss_w(!state); + checkpoint(); + live_run(); + } +} + +WRITE_LINE_MEMBER( c8050_fdc_t::pull_sync_w ) +{ + if (LOG_MORE) logerror("%s %s PULL SYNC %u\n", machine().time().as_string(), machine().describe_context(), state); +} diff --git a/src/devices/bus/ieee488/c8050fdc.h b/src/devices/bus/ieee488/c8050fdc.h new file mode 100644 index 00000000000..8228c9660d0 --- /dev/null +++ b/src/devices/bus/ieee488/c8050fdc.h @@ -0,0 +1,170 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Commodore 8050 floppy disk controller emulation + +**********************************************************************/ + +#pragma once + +#ifndef __C8050_FLOPPY__ +#define __C8050_FLOPPY__ + +#include "emu.h" +#include "formats/d80_dsk.h" +#include "formats/d82_dsk.h" +#include "imagedev/floppy.h" +#include "machine/fdc_pll.h" + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_C8050_SYNC_CALLBACK(_write) \ + devcb = &c8050_fdc_t::set_sync_wr_callback(*device, DEVCB_##_write); + +#define MCFG_C8050_READY_CALLBACK(_write) \ + devcb = &c8050_fdc_t::set_ready_wr_callback(*device, DEVCB_##_write); + +#define MCFG_C8050_BRDY_CALLBACK(_write) \ + devcb = &c8050_fdc_t::set_brdy_wr_callback(*device, DEVCB_##_write); + +#define MCFG_C8050_ERROR_CALLBACK(_write) \ + devcb = &c8050_fdc_t::set_error_wr_callback(*device, DEVCB_##_write); + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> c8050_fdc_t + +class c8050_fdc_t : public device_t +{ +public: + // construction/destruction + c8050_fdc_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + template static devcb_base &set_sync_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_sync.set_callback(object); } + template static devcb_base &set_ready_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_ready.set_callback(object); } + template static devcb_base &set_brdy_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_brdy.set_callback(object); } + template static devcb_base &set_error_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_error.set_callback(object); } + + DECLARE_READ8_MEMBER( read ); + DECLARE_WRITE8_MEMBER( write ); + + DECLARE_WRITE_LINE_MEMBER( ds0_w ); + DECLARE_WRITE_LINE_MEMBER( ds1_w ); + DECLARE_WRITE_LINE_MEMBER( drv_sel_w ); + DECLARE_WRITE_LINE_MEMBER( mode_sel_w ); + DECLARE_WRITE_LINE_MEMBER( rw_sel_w ); + DECLARE_WRITE_LINE_MEMBER( mtr0_w ); + DECLARE_WRITE_LINE_MEMBER( mtr1_w ); + DECLARE_WRITE_LINE_MEMBER( odd_hd_w ); + DECLARE_WRITE_LINE_MEMBER( pull_sync_w ); + + DECLARE_READ_LINE_MEMBER( wps_r ) { return checkpoint_live.drv_sel ? m_floppy1->wpt_r() : m_floppy0->wpt_r(); } + + void stp0_w(int stp); + void stp1_w(int stp); + void ds_w(int ds); + + void set_floppy(floppy_connector *floppy0, floppy_connector *floppy1); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + + void stp_w(floppy_image_device *floppy, int mtr, int &old_stp, int stp); + + enum { + IDLE, + RUNNING, + RUNNING_SYNCPOINT + }; + + struct live_info { + attotime tm; + int state, next_state; + int sync; + int ready; + int brdy; + int error; + int ds; + int drv_sel; + int mode_sel; + int rw_sel; + int odd_hd; + + attotime edge; + UINT16 shift_reg; + int bit_counter; + UINT8 e; + offs_t i; + + UINT8 pi; + UINT16 shift_reg_write; + }; + + devcb_write_line m_write_sync; + devcb_write_line m_write_ready; + devcb_write_line m_write_brdy; + devcb_write_line m_write_error; + + required_memory_region m_gcr_rom; + + floppy_image_device *m_floppy0; + floppy_image_device *m_floppy1; + + int m_mtr0; + int m_mtr1; + int m_stp0; + int m_stp1; + int m_ds; + int m_ds0; + int m_ds1; + int m_drv_sel; + int m_mode_sel; + int m_rw_sel; + int m_odd_hd; + UINT8 m_pi; + + live_info cur_live, checkpoint_live; + fdc_pll_t cur_pll, checkpoint_pll; + emu_timer *t_gen; + + floppy_image_device* get_floppy(); + + void live_start(); + void checkpoint(); + void rollback(); + void pll_reset(const attotime &when); + void pll_start_writing(const attotime &tm); + void pll_commit(floppy_image_device *floppy, const attotime &tm); + void pll_stop_writing(floppy_image_device *floppy, const attotime &tm); + int pll_get_next_bit(attotime &tm, floppy_image_device *floppy, const attotime &limit); + bool pll_write_next_bit(bool bit, attotime &tm, floppy_image_device *floppy, const attotime &limit); + void pll_save_checkpoint(); + void pll_retrieve_checkpoint(); + void live_delay(int state); + void live_sync(); + void live_abort(); + void live_run(const attotime &limit = attotime::never); +}; + + +// device type definition +extern const device_type C8050_FDC; + + + +#endif diff --git a/src/devices/bus/ieee488/c8280.c b/src/devices/bus/ieee488/c8280.c new file mode 100644 index 00000000000..1dd1c679c5d --- /dev/null +++ b/src/devices/bus/ieee488/c8280.c @@ -0,0 +1,527 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Commodore 8280 Dual 8" Disk Drive emulation + +**********************************************************************/ + +#include "c8280.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define M6502_DOS_TAG "5c" +#define M6502_FDC_TAG "9e" +#define M6532_0_TAG "9f" +#define M6532_1_TAG "9g" +#define WD1797_TAG "5e" + + +enum +{ + LED_POWER = 0, + LED_ACT0, + LED_ACT1, + LED_ERR +}; + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type C8280 = &device_creator; + + +//------------------------------------------------- +// ROM( c8280 ) +//------------------------------------------------- + +ROM_START( c8280 ) + ROM_REGION( 0x4000, M6502_DOS_TAG, 0 ) + ROM_DEFAULT_BIOS("r2") + ROM_SYSTEM_BIOS( 0, "r1", "Revision 1" ) + ROMX_LOAD( "300542-001.10c", 0x0000, 0x2000, CRC(3c6eee1e) SHA1(0726f6ab4de4fc9c18707fe87780ffd9f5ed72ab), ROM_BIOS(1) ) + ROMX_LOAD( "300543-001.10d", 0x2000, 0x2000, CRC(f58e665e) SHA1(9e58b47c686c91efc6ef1a27f72dbb5e26c485ec), ROM_BIOS(1) ) + ROM_SYSTEM_BIOS( 1, "r2", "Revision 2" ) + ROMX_LOAD( "300542-reva.10c", 0x0000, 0x2000, CRC(6f32ccfb) SHA1(6926c049f1635e6769ec69891de8c92941ff880e), ROM_BIOS(2) ) + ROMX_LOAD( "300543-reva.10d", 0x2000, 0x2000, CRC(1af93f2c) SHA1(ad197b1d5dfa273487b33f473403ebd20dd15b2b), ROM_BIOS(2) ) + + ROM_REGION( 0x800, M6502_FDC_TAG, 0 ) + ROMX_LOAD( "300541-001.3c", 0x000, 0x800, BAD_DUMP CRC(cb07b2db) SHA1(a1f9c5a7bd3798f5a97dc0b465c3bf5e3513e148), ROM_BIOS(1) ) + ROMX_LOAD( "300541-revb.3c", 0x000, 0x800, CRC(403e632c) SHA1(a0994c80025240d2b49ffd209dbfe8a4de3975b0), ROM_BIOS(2) ) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *c8280_t::device_rom_region() const +{ + return ROM_NAME( c8280 ); +} + + +//------------------------------------------------- +// ADDRESS_MAP( c8280_main_mem ) +//------------------------------------------------- + +static ADDRESS_MAP_START( c8280_main_mem, AS_PROGRAM, 8, c8280_t ) + AM_RANGE(0x0000, 0x007f) AM_MIRROR(0x100) AM_DEVICE(M6532_0_TAG, mos6532_t, ram_map) + AM_RANGE(0x0080, 0x00ff) AM_MIRROR(0x100) AM_DEVICE(M6532_1_TAG, mos6532_t, ram_map) + AM_RANGE(0x0200, 0x021f) AM_MIRROR(0xd60) AM_DEVICE(M6532_0_TAG, mos6532_t, io_map) + AM_RANGE(0x0280, 0x029f) AM_MIRROR(0xd60) AM_DEVICE(M6532_1_TAG, mos6532_t, io_map) + AM_RANGE(0x1000, 0x13ff) AM_MIRROR(0xc00) AM_RAM AM_SHARE("share1") + AM_RANGE(0x2000, 0x23ff) AM_MIRROR(0xc00) AM_RAM AM_SHARE("share2") + AM_RANGE(0x3000, 0x33ff) AM_MIRROR(0xc00) AM_RAM AM_SHARE("share3") + AM_RANGE(0x4000, 0x43ff) AM_MIRROR(0xc00) AM_RAM AM_SHARE("share4") + AM_RANGE(0xc000, 0xffff) AM_ROM AM_REGION(M6502_DOS_TAG, 0) +ADDRESS_MAP_END + + +//------------------------------------------------- +// ADDRESS_MAP( c8280_fdc_mem ) +//------------------------------------------------- + +static ADDRESS_MAP_START( c8280_fdc_mem, AS_PROGRAM, 8, c8280_t ) + ADDRESS_MAP_GLOBAL_MASK(0x1fff) + AM_RANGE(0x0000, 0x007f) AM_MIRROR(0x300) AM_RAM + AM_RANGE(0x0080, 0x0083) AM_MIRROR(0x37c) AM_DEVREADWRITE(WD1797_TAG, fd1797_t, read, write) + AM_RANGE(0x0400, 0x07ff) AM_RAM AM_SHARE("share1") + AM_RANGE(0x0800, 0x0bff) AM_RAM AM_SHARE("share2") + AM_RANGE(0x0c00, 0x0fff) AM_RAM AM_SHARE("share3") + AM_RANGE(0x1000, 0x13ff) AM_RAM AM_SHARE("share4") + AM_RANGE(0x1400, 0x1400) AM_MIRROR(0x3ff) AM_READWRITE(fk5_r, fk5_w) + AM_RANGE(0x1800, 0x1fff) AM_ROM AM_REGION(M6502_FDC_TAG, 0) +ADDRESS_MAP_END + + +//------------------------------------------------- +// riot6532 0 +//------------------------------------------------- + +READ8_MEMBER( c8280_t::dio_r ) +{ + /* + + bit description + + PA0 DI0 + PA1 DI1 + PA2 DI2 + PA3 DI3 + PA4 DI4 + PA5 DI5 + PA6 DI6 + PA7 DI7 + + */ + + return m_bus->dio_r(); +} + +WRITE8_MEMBER( c8280_t::dio_w ) +{ + /* + + bit description + + PB0 DO0 + PB1 DO1 + PB2 DO2 + PB3 DO3 + PB4 DO4 + PB5 DO5 + PB6 DO6 + PB7 DO7 + + */ + + m_bus->dio_w(this, data); +} + + +//------------------------------------------------- +// riot6532 1 +//------------------------------------------------- + +READ8_MEMBER( c8280_t::riot1_pa_r ) +{ + /* + + bit description + + PA0 + PA1 + PA2 + PA3 + PA4 + PA5 EOII + PA6 DAVI + PA7 _ATN + + */ + + UINT8 data = 0; + + // end or identify in + data |= m_bus->eoi_r() << 5; + + // data valid in + data |= m_bus->dav_r() << 6; + + // attention + data |= !m_bus->atn_r() << 7; + + return data; +} + +WRITE8_MEMBER( c8280_t::riot1_pa_w ) +{ + /* + + bit description + + PA0 ATNA + PA1 DACO + PA2 RFDO + PA3 EOIO + PA4 DAVO + PA5 + PA6 + PA7 + + */ + + // attention acknowledge + m_atna = BIT(data, 0); + + // data accepted out + m_daco = BIT(data, 1); + + // not ready for data out + m_rfdo = BIT(data, 2); + + // end or identify out + m_bus->eoi_w(this, BIT(data, 3)); + + // data valid out + m_bus->dav_w(this, BIT(data, 4)); + + update_ieee_signals(); +} + +READ8_MEMBER( c8280_t::riot1_pb_r ) +{ + /* + + bit description + + PB0 DEVICE NUMBER SELECTION + PB1 DEVICE NUMBER SELECTION + PB2 DEVICE NUMBER SELECTION + PB3 + PB4 + PB5 + PB6 DACI + PB7 RFDI + + */ + + UINT8 data = 0; + + // device number selection + data |= m_slot->get_address() - 8; + + // data accepted in + data |= m_bus->ndac_r() << 6; + + // ready for data in + data |= m_bus->nrfd_r() << 7; + + return data; +} + +WRITE8_MEMBER( c8280_t::riot1_pb_w ) +{ + /* + + bit description + + PB0 + PB1 + PB2 + PB3 ACT LED 1 + PB4 ACT LED 0 + PB5 ERR LED + PB6 + PB7 + + */ + + // activity led 1 + output_set_led_value(LED_ACT1, BIT(data, 3)); + + // activity led 0 + output_set_led_value(LED_ACT0, BIT(data, 4)); + + // error led + output_set_led_value(LED_ERR, BIT(data, 5)); +} + +static SLOT_INTERFACE_START( c8280_floppies ) + SLOT_INTERFACE( "8dsdd", FLOPPY_8_DSDD ) +SLOT_INTERFACE_END + +FLOPPY_FORMATS_MEMBER( c8280_t::floppy_formats ) + FLOPPY_C8280_FORMAT +FLOPPY_FORMATS_END + + +//------------------------------------------------- +// MACHINE_CONFIG_FRAGMENT( c8280 ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( c8280 ) + MCFG_CPU_ADD(M6502_DOS_TAG, M6502, XTAL_12MHz/8) + MCFG_CPU_PROGRAM_MAP(c8280_main_mem) + + MCFG_DEVICE_ADD(M6532_0_TAG, MOS6532n, XTAL_12MHz/8) + MCFG_MOS6530n_IN_PA_CB(READ8(c8280_t, dio_r)) + MCFG_MOS6530n_OUT_PB_CB(WRITE8(c8280_t, dio_w)) + + MCFG_DEVICE_ADD(M6532_1_TAG, MOS6532n, XTAL_12MHz/8) + MCFG_MOS6530n_IN_PA_CB(READ8(c8280_t, riot1_pa_r)) + MCFG_MOS6530n_OUT_PA_CB(WRITE8(c8280_t, riot1_pa_w)) + MCFG_MOS6530n_IN_PB_CB(READ8(c8280_t, riot1_pb_r)) + MCFG_MOS6530n_OUT_PB_CB(WRITE8(c8280_t, riot1_pb_w)) + MCFG_MOS6530n_IRQ_CB(INPUTLINE(M6502_DOS_TAG, INPUT_LINE_IRQ0)) + + MCFG_CPU_ADD(M6502_FDC_TAG, M6502, XTAL_12MHz/8) + MCFG_CPU_PROGRAM_MAP(c8280_fdc_mem) + + MCFG_FD1797_ADD(WD1797_TAG, XTAL_12MHz/6) + MCFG_WD_FDC_INTRQ_CALLBACK(INPUTLINE(M6502_FDC_TAG, M6502_IRQ_LINE)) + MCFG_WD_FDC_DRQ_CALLBACK(INPUTLINE(M6502_FDC_TAG, M6502_SET_OVERFLOW)) + MCFG_FLOPPY_DRIVE_ADD(WD1797_TAG ":0", c8280_floppies, "8dsdd", c8280_t::floppy_formats) + MCFG_FLOPPY_DRIVE_ADD(WD1797_TAG ":1", c8280_floppies, "8dsdd", c8280_t::floppy_formats) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor c8280_t::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( c8280 ); +} + + +//------------------------------------------------- +// INPUT_PORTS( c8280 ) +//------------------------------------------------- + +static INPUT_PORTS_START( c8280 ) + PORT_START("ADDRESS") + PORT_DIPNAME( 0x07, 0x00, "Device Address" ) + PORT_DIPSETTING( 0x00, "8" ) + PORT_DIPSETTING( 0x01, "9" ) + PORT_DIPSETTING( 0x02, "10" ) + PORT_DIPSETTING( 0x03, "11" ) + PORT_DIPSETTING( 0x04, "12" ) + PORT_DIPSETTING( 0x05, "13" ) + PORT_DIPSETTING( 0x06, "14" ) + PORT_DIPSETTING( 0x07, "15" ) +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor c8280_t::device_input_ports() const +{ + return INPUT_PORTS_NAME( c8280 ); +} + + + +//************************************************************************** +// INLINE HELPERS +//************************************************************************** + +//------------------------------------------------- +// update_ieee_signals - +//------------------------------------------------- + +inline void c8280_t::update_ieee_signals() +{ + int atn = m_bus->atn_r(); + int nrfd = !(!(!(atn && m_atna) && m_rfdo) || !(atn || m_atna)); + int ndac = !(m_daco || !(atn || m_atna)); + + m_bus->nrfd_w(this, nrfd); + m_bus->ndac_w(this, ndac); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// c8280_t - constructor +//------------------------------------------------- + +c8280_t::c8280_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, C8280, "C8280", tag, owner, clock, "c8280", __FILE__), + device_ieee488_interface(mconfig, *this), + m_maincpu(*this, M6502_DOS_TAG), + m_fdccpu(*this, M6502_FDC_TAG), + m_riot0(*this, M6532_0_TAG), + m_riot1(*this, M6532_1_TAG), + m_fdc(*this, WD1797_TAG), + m_floppy0(*this, WD1797_TAG ":0"), + m_floppy1(*this, WD1797_TAG ":1"), + m_address(*this, "ADDRESS"), + m_rfdo(1), + m_daco(1), + m_atna(1) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void c8280_t::device_start() +{ + // state saving + save_item(NAME(m_rfdo)); + save_item(NAME(m_daco)); + save_item(NAME(m_atna)); + save_item(NAME(m_ifc)); + save_item(NAME(m_fk5)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void c8280_t::device_reset() +{ + m_maincpu->reset(); + + // toggle M6502 SO + m_maincpu->set_input_line(M6502_SET_OVERFLOW, ASSERT_LINE); + m_maincpu->set_input_line(M6502_SET_OVERFLOW, CLEAR_LINE); + + m_fdccpu->reset(); + + m_riot0->reset(); + m_riot1->reset(); + m_fdc->reset(); + + m_riot1->pa7_w(1); + + m_fk5 = 0; + m_floppy = NULL; + m_fdc->set_floppy(m_floppy); + m_fdc->dden_w(0); +} + + +//------------------------------------------------- +// ieee488_atn - +//------------------------------------------------- + +void c8280_t::ieee488_atn(int state) +{ + update_ieee_signals(); + + m_riot1->pa7_w(state); +} + + +//------------------------------------------------- +// ieee488_ifc - +//------------------------------------------------- + +void c8280_t::ieee488_ifc(int state) +{ + if (!m_ifc && state) + { + device_reset(); + } + + m_ifc = state; +} + +READ8_MEMBER( c8280_t::fk5_r ) +{ + /* + + bit description + + 0 + 1 + 2 + 3 DCHG + 4 TSID + 5 + 6 0 + 7 0 + + */ + + UINT8 data = m_fk5; + + data |= (m_floppy ? m_floppy->dskchg_r() : 1) << 3; + data |= (m_floppy ? m_floppy->twosid_r() : 1) << 4; + + return data; +} + +WRITE8_MEMBER( c8280_t::fk5_w ) +{ + /* + + bit description + + 0 DS1 + 1 DS2 + 2 _DDEN + 3 + 4 + 5 MOTOR ENABLE + 6 + 7 + + */ + + m_fk5 = data & 0x27; + + // drive select + m_floppy = NULL; + + if (BIT(data, 0)) m_floppy = m_floppy0->get_device(); + if (BIT(data, 1)) m_floppy = m_floppy1->get_device(); + + m_fdc->set_floppy(m_floppy); + + if (m_floppy) m_floppy->mon_w(!BIT(data, 5)); + + // density select + m_fdc->dden_w(BIT(data, 2)); +} diff --git a/src/devices/bus/ieee488/c8280.h b/src/devices/bus/ieee488/c8280.h new file mode 100644 index 00000000000..076edcd736c --- /dev/null +++ b/src/devices/bus/ieee488/c8280.h @@ -0,0 +1,90 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Commodore 8280 Dual 8" Disk Drive emulation + +**********************************************************************/ + +#pragma once + +#ifndef __C8280__ +#define __C8280__ + +#include "emu.h" +#include "ieee488.h" +#include "cpu/m6502/m6502.h" +#include "formats/c8280_dsk.h" +#include "machine/mos6530n.h" +#include "machine/wd_fdc.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> c8280_t + +class c8280_t : public device_t, + public device_ieee488_interface +{ +public: + // construction/destruction + c8280_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + virtual ioport_constructor device_input_ports() const; + + // not really public + DECLARE_READ8_MEMBER( dio_r ); + DECLARE_WRITE8_MEMBER( dio_w ); + DECLARE_READ8_MEMBER( riot1_pa_r ); + DECLARE_WRITE8_MEMBER( riot1_pa_w ); + DECLARE_READ8_MEMBER( riot1_pb_r ); + DECLARE_WRITE8_MEMBER( riot1_pb_w ); + DECLARE_READ8_MEMBER( fk5_r ); + DECLARE_WRITE8_MEMBER( fk5_w ); + + DECLARE_FLOPPY_FORMATS( floppy_formats ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_ieee488_interface overrides + void ieee488_atn(int state); + void ieee488_ifc(int state); + +private: + inline void update_ieee_signals(); + + required_device m_maincpu; + required_device m_fdccpu; + required_device m_riot0; + required_device m_riot1; + required_device m_fdc; + required_device m_floppy0; + required_device m_floppy1; + required_ioport m_address; + floppy_image_device *m_floppy; + + // IEEE-488 bus + int m_rfdo; // not ready for data output + int m_daco; // not data accepted output + int m_atna; // attention acknowledge + int m_ifc; + + UINT8 m_fk5; +}; + + +// device type definition +extern const device_type C8280; + + + +#endif diff --git a/src/devices/bus/ieee488/d9060.c b/src/devices/bus/ieee488/d9060.c new file mode 100644 index 00000000000..f21653efb09 --- /dev/null +++ b/src/devices/bus/ieee488/d9060.c @@ -0,0 +1,578 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Commodore 9060/9090 Hard Disk Drive emulation + +**********************************************************************/ + +/* + + Use the CHDMAN utility to create a 5MB image for D9060: + + $ chdman createhd -o tm602s.chd -chs 153,4,32 -ss 256 + + or a 10MB image for D9090: + + $ chdman createhd -o tm603s.chd -chs 153,6,32 -ss 256 + + Start the PET emulator with the D9060 attached on the IEEE-488 bus, + with the new CHD mounted: + + $ mess pet8032 -ieee8 d9060 -hard tm602s.chd + $ mess pet8032 -ieee8 d9090 -hard tm603s.chd + + Enter 'HEADER "LABEL",D0,I01' to format the hard drive. + Wait up to 1 hour and 20 minutes. + +*/ + +#include "d9060.h" +#include "bus/scsi/d9060hd.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define M6502_DOS_TAG "7e" +#define M6532_0_TAG "7f" +#define M6532_1_TAG "7g" + +#define M6502_HDC_TAG "4a" +#define M6522_TAG "4b" + +#define AM2910_TAG "9d" + +#define SASIBUS_TAG "sasi" + +enum +{ + LED_POWER = 0, + LED_READY, + LED_ERROR +}; + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type D9060 = &device_creator; +const device_type D9090 = &device_creator; + + +//------------------------------------------------- +// ROM( d9060 ) +//------------------------------------------------- + +ROM_START( d9060 ) + ROM_REGION( 0x4000, M6502_DOS_TAG, 0 ) + ROM_DEFAULT_BIOS("rc") + ROM_SYSTEM_BIOS( 0, "ra", "Revision A" ) + ROMX_LOAD( "300516-001.7c", 0x0000, 0x2000, NO_DUMP, ROM_BIOS(1) ) + ROMX_LOAD( "300517-001.7d", 0x2000, 0x2000, CRC(566df630) SHA1(b1602dfff408b165ee52a6a4ca3e2ec27e689ba9), ROM_BIOS(1) ) + ROM_SYSTEM_BIOS( 1, "rb", "Revision B" ) + ROMX_LOAD( "300516-002.7c", 0x0000, 0x2000, CRC(2d758a14) SHA1(c959cc9dde84fc3d64e95e58a0a096a26d8107fd), ROM_BIOS(2) ) + ROMX_LOAD( "300517-002.7d", 0x2000, 0x2000, CRC(f0382bc3) SHA1(0b0a8dc520f5b41ffa832e4a636b3d226ccbb7f1), ROM_BIOS(2) ) + ROM_SYSTEM_BIOS( 2, "rc", "Revision C" ) + ROMX_LOAD( "300516-003.7c", 0x0000, 0x2000, CRC(d6a3e88f) SHA1(bb1ddb5da94a86266012eca54818aa21dc4cef6a), ROM_BIOS(3) ) + ROMX_LOAD( "300517-003.7d", 0x2000, 0x2000, CRC(2a9ad4ad) SHA1(4c17d014de48c906871b9b6c7d037d8736b1fd52), ROM_BIOS(3) ) + + ROM_REGION( 0x800, M6502_HDC_TAG, 0 ) + ROM_LOAD( "300515-001.4c", 0x000, 0x800, CRC(99e096f7) SHA1(a3d1deb27bf5918b62b89c27fa3e488eb8f717a4) ) // Revision A + ROM_LOAD( "300515-002.4c", 0x000, 0x800, CRC(49adf4fb) SHA1(59dafbd4855083074ba8dc96a04d4daa5b76e0d6) ) // Revision B + + ROM_REGION( 0x5000, AM2910_TAG, 0 ) + ROM_LOAD( "441.5b", 0x0000, 0x1000, NO_DUMP ) // 82S137 + ROM_LOAD( "442.6b", 0x1000, 0x1000, NO_DUMP ) // 82S137 + ROM_LOAD( "573.7b", 0x2000, 0x1000, NO_DUMP ) // 82S137 + ROM_LOAD( "444.8b", 0x3000, 0x1000, NO_DUMP ) // 82S137 + ROM_LOAD( "445.9b", 0x4000, 0x1000, NO_DUMP ) // 82S137 +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *d9060_base_t::device_rom_region() const +{ + return ROM_NAME( d9060 ); +} + + +//------------------------------------------------- +// ADDRESS_MAP( d9060_main_mem ) +//------------------------------------------------- + +static ADDRESS_MAP_START( d9060_main_mem, AS_PROGRAM, 8, d9060_base_t ) + AM_RANGE(0x0000, 0x007f) AM_MIRROR(0x0100) AM_DEVICE(M6532_0_TAG, mos6532_t, ram_map) + AM_RANGE(0x0080, 0x00ff) AM_MIRROR(0x0100) AM_DEVICE(M6532_1_TAG, mos6532_t, ram_map) + AM_RANGE(0x0200, 0x021f) AM_MIRROR(0x0d60) AM_DEVICE(M6532_0_TAG, mos6532_t, io_map) + AM_RANGE(0x0280, 0x029f) AM_MIRROR(0x0d60) AM_DEVICE(M6532_1_TAG, mos6532_t, io_map) + AM_RANGE(0x1000, 0x13ff) AM_MIRROR(0x0c00) AM_RAM AM_SHARE("share1") + AM_RANGE(0x2000, 0x23ff) AM_MIRROR(0x0c00) AM_RAM AM_SHARE("share2") + AM_RANGE(0x3000, 0x33ff) AM_MIRROR(0x0c00) AM_RAM AM_SHARE("share3") + AM_RANGE(0x4000, 0x43ff) AM_MIRROR(0x0c00) AM_RAM AM_SHARE("share4") + AM_RANGE(0xc000, 0xffff) AM_ROM AM_REGION(M6502_DOS_TAG, 0) +ADDRESS_MAP_END + + +//------------------------------------------------- +// ADDRESS_MAP( d9060_hdc_mem ) +//------------------------------------------------- + +static ADDRESS_MAP_START( d9060_hdc_mem, AS_PROGRAM, 8, d9060_base_t ) + ADDRESS_MAP_GLOBAL_MASK(0x1fff) + AM_RANGE(0x0000, 0x007f) AM_MIRROR(0x300) AM_RAM + AM_RANGE(0x0080, 0x008f) AM_MIRROR(0x380) AM_DEVREADWRITE(M6522_TAG, via6522_device, read, write) + AM_RANGE(0x0400, 0x07ff) AM_RAM AM_SHARE("share1") + AM_RANGE(0x0800, 0x0bff) AM_RAM AM_SHARE("share2") + AM_RANGE(0x0c00, 0x0fff) AM_RAM AM_SHARE("share3") + AM_RANGE(0x1000, 0x13ff) AM_RAM AM_SHARE("share4") + AM_RANGE(0x1800, 0x1fff) AM_ROM AM_REGION(M6502_HDC_TAG, 0) +ADDRESS_MAP_END + + +//------------------------------------------------- +// riot6532 0 +//------------------------------------------------- + +READ8_MEMBER( d9060_base_t::dio_r ) +{ + /* + + bit description + + PA0 DI0 + PA1 DI1 + PA2 DI2 + PA3 DI3 + PA4 DI4 + PA5 DI5 + PA6 DI6 + PA7 DI7 + + */ + + return m_bus->dio_r(); +} + + +WRITE8_MEMBER( d9060_base_t::dio_w ) +{ + /* + + bit description + + PB0 DO0 + PB1 DO1 + PB2 DO2 + PB3 DO3 + PB4 DO4 + PB5 DO5 + PB6 DO6 + PB7 DO7 + + */ + + m_bus->dio_w(this, data); +} + + +//------------------------------------------------- +// riot6532 1 +//------------------------------------------------- + +READ8_MEMBER( d9060_base_t::riot1_pa_r ) +{ + /* + + bit description + + PA0 + PA1 + PA2 + PA3 + PA4 + PA5 EOII + PA6 DAVI + PA7 _ATN + + */ + + UINT8 data = 0; + + // end or identify in + data |= m_bus->eoi_r() << 5; + + // data valid in + data |= m_bus->dav_r() << 6; + + // attention + data |= !m_bus->atn_r() << 7; + + return data; +} + +WRITE8_MEMBER( d9060_base_t::riot1_pa_w ) +{ + /* + + bit description + + PA0 ATNA + PA1 DACO + PA2 RFDO + PA3 EOIO + PA4 DAVO + PA5 + PA6 + PA7 + + */ + + // attention acknowledge + m_atna = BIT(data, 0); + + // data accepted out + m_daco = BIT(data, 1); + + // not ready for data out + m_rfdo = BIT(data, 2); + + // end or identify out + m_bus->eoi_w(this, BIT(data, 3)); + + // data valid out + m_bus->dav_w(this, BIT(data, 4)); + + update_ieee_signals(); +} + +READ8_MEMBER( d9060_base_t::riot1_pb_r ) +{ + /* + + bit description + + PB0 device # + PB1 device # + PB2 device # + PB3 + PB4 + PB5 + PB6 DACI + PB7 RFDI + + */ + + UINT8 data = 0; + + // device number selection + data |= m_slot->get_address() - 8; + + // data accepted in + data |= m_bus->ndac_r() << 6; + + // ready for data in + data |= m_bus->nrfd_r() << 7; + + return data; +} + +WRITE8_MEMBER( d9060_base_t::riot1_pb_w ) +{ + /* + + bit description + + PB0 + PB1 + PB2 + PB3 + PB4 DRIVE RDY + PB5 PWR ON AND NO ERRORS + PB6 + PB7 + + */ + + // ready led + output_set_led_value(LED_READY, BIT(data, 4)); + + // power led + output_set_led_value(LED_POWER, BIT(data, 5)); + + // error led + output_set_led_value(LED_ERROR, !BIT(data, 5)); +} + + +WRITE8_MEMBER( d9060_base_t::via_pb_w ) +{ + /* + + bit description + + PB0 SEL + PB1 RST + PB2 C/D + PB3 BUSY + PB4 J14 (1=9060, 0=9090) + PB5 J13 + PB6 I/O + PB7 MSG + + */ + + m_sasibus->write_sel(BIT(data, 0)); + m_sasibus->write_rst(BIT(data, 1)); +} + +WRITE_LINE_MEMBER( d9060_base_t::ack_w ) +{ + m_sasibus->write_ack(!state); +} + +WRITE_LINE_MEMBER( d9060_base_t::enable_w ) +{ + m_enable = state; + + if( !m_enable ) + { + m_sasi_data_out->write( m_data ); + } + else + { + m_sasi_data_out->write( 0 ); + } +} + +WRITE8_MEMBER( d9060_base_t::scsi_data_w ) +{ + m_data = data; + + if( !m_enable ) + { + m_sasi_data_out->write( m_data ); + } +} + + +//------------------------------------------------- +// MACHINE_CONFIG_FRAGMENT( d9060 ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( d9060 ) + // DOS + MCFG_CPU_ADD(M6502_DOS_TAG, M6502, XTAL_4MHz/4) + MCFG_CPU_PROGRAM_MAP(d9060_main_mem) + + MCFG_DEVICE_ADD(M6532_0_TAG, MOS6532n, XTAL_4MHz/4) + MCFG_MOS6530n_IN_PA_CB(READ8(d9060_base_t, dio_r)) + MCFG_MOS6530n_OUT_PB_CB(WRITE8(d9060_base_t, dio_w)) + + MCFG_DEVICE_ADD(M6532_1_TAG, MOS6532n, XTAL_4MHz/4) + MCFG_MOS6530n_IN_PA_CB(READ8(d9060_base_t, riot1_pa_r)) + MCFG_MOS6530n_OUT_PA_CB(WRITE8(d9060_base_t, riot1_pa_w)) + MCFG_MOS6530n_IN_PB_CB(READ8(d9060_base_t, riot1_pb_r)) + MCFG_MOS6530n_OUT_PB_CB(WRITE8(d9060_base_t, riot1_pb_w)) + MCFG_MOS6530n_IRQ_CB(INPUTLINE(M6502_DOS_TAG, INPUT_LINE_IRQ0)) + + // controller + MCFG_CPU_ADD(M6502_HDC_TAG, M6502, XTAL_4MHz/4) + MCFG_CPU_PROGRAM_MAP(d9060_hdc_mem) + + MCFG_DEVICE_ADD(M6522_TAG, VIA6522, XTAL_4MHz/4) + MCFG_VIA6522_WRITEPA_HANDLER(WRITE8(d9060_base_t, scsi_data_w)) + MCFG_VIA6522_WRITEPB_HANDLER(WRITE8(d9060_base_t, via_pb_w)) + MCFG_VIA6522_CA2_HANDLER(WRITELINE(d9060_base_t, ack_w)) + MCFG_VIA6522_CB2_HANDLER(WRITELINE(d9060_base_t, enable_w)) + MCFG_VIA6522_IRQ_HANDLER(DEVWRITELINE(M6502_HDC_TAG, m6502_device, irq_line)) + + MCFG_DEVICE_ADD(SASIBUS_TAG, SCSI_PORT, 0) + MCFG_SCSI_REQ_HANDLER(DEVWRITELINE(M6522_TAG, via6522_device, write_ca1)) + MCFG_SCSI_CD_HANDLER(DEVWRITELINE(M6522_TAG, via6522_device, write_pb2)) + MCFG_SCSI_BSY_HANDLER(DEVWRITELINE(M6522_TAG, via6522_device, write_pb3)) + MCFG_SCSI_IO_HANDLER(DEVWRITELINE(M6522_TAG, via6522_device, write_pb6)) + MCFG_SCSI_MSG_HANDLER(DEVWRITELINE(M6522_TAG, via6522_device, write_pb7)) + MCFG_SCSI_DATA0_HANDLER(DEVWRITELINE(M6522_TAG, via6522_device, write_pa0)) + MCFG_SCSI_DATA1_HANDLER(DEVWRITELINE(M6522_TAG, via6522_device, write_pa1)) + MCFG_SCSI_DATA2_HANDLER(DEVWRITELINE(M6522_TAG, via6522_device, write_pa2)) + MCFG_SCSI_DATA3_HANDLER(DEVWRITELINE(M6522_TAG, via6522_device, write_pa3)) + MCFG_SCSI_DATA4_HANDLER(DEVWRITELINE(M6522_TAG, via6522_device, write_pa4)) + MCFG_SCSI_DATA5_HANDLER(DEVWRITELINE(M6522_TAG, via6522_device, write_pa5)) + MCFG_SCSI_DATA6_HANDLER(DEVWRITELINE(M6522_TAG, via6522_device, write_pa6)) + MCFG_SCSI_DATA7_HANDLER(DEVWRITELINE(M6522_TAG, via6522_device, write_pa7)) + + MCFG_SCSI_OUTPUT_LATCH_ADD("sasi_data_out", SASIBUS_TAG) + + MCFG_SCSIDEV_ADD(SASIBUS_TAG ":" SCSI_PORT_DEVICE1, "harddisk", D9060HD, SCSI_ID_0) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor d9060_base_t::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( d9060 ); +} + + +//------------------------------------------------- +// INPUT_PORTS( d9060 ) +//------------------------------------------------- + +static INPUT_PORTS_START( d9060 ) + PORT_START("ADDRESS") + PORT_DIPNAME( 0x07, 0x01, "Device Address" ) + PORT_DIPSETTING( 0x00, "8" ) + PORT_DIPSETTING( 0x01, "9" ) + PORT_DIPSETTING( 0x02, "10" ) + PORT_DIPSETTING( 0x03, "11" ) + PORT_DIPSETTING( 0x04, "12" ) + PORT_DIPSETTING( 0x05, "13" ) + PORT_DIPSETTING( 0x06, "14" ) + PORT_DIPSETTING( 0x07, "15" ) +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor d9060_base_t::device_input_ports() const +{ + return INPUT_PORTS_NAME( d9060 ); +} + + + +//************************************************************************** +// INLINE HELPERS +//************************************************************************** + +//------------------------------------------------- +// update_ieee_signals - +//------------------------------------------------- + +inline void d9060_base_t::update_ieee_signals() +{ + int atn = m_bus->atn_r(); + int nrfd = !(!(!(atn && m_atna) && m_rfdo) || !(atn || m_atna)); + int ndac = !(m_daco || !(atn || m_atna)); + + m_bus->nrfd_w(this, nrfd); + m_bus->ndac_w(this, ndac); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// d9060_base_t - constructor +//------------------------------------------------- + +d9060_base_t::d9060_base_t(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, UINT32 variant, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_ieee488_interface(mconfig, *this), + m_maincpu(*this, M6502_DOS_TAG), + m_hdccpu(*this, M6502_HDC_TAG), + m_riot0(*this, M6532_0_TAG), + m_riot1(*this, M6532_1_TAG), + m_via(*this, M6522_TAG), + m_sasibus(*this, SASIBUS_TAG), + m_sasi_data_out(*this, "sasi_data_out"), + m_address(*this, "ADDRESS"), + m_rfdo(1), + m_daco(1), + m_atna(1), + m_enable(0), + m_variant(variant) +{ +} + + +//------------------------------------------------- +// d9060_t - constructor +//------------------------------------------------- + +d9060_t::d9060_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : d9060_base_t(mconfig, D9060, "D9060", tag, owner, clock, TYPE_9060, "d9060", __FILE__) { } + + +//------------------------------------------------- +// d9090_t - constructor +//------------------------------------------------- + +d9090_t::d9090_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : d9060_base_t(mconfig, D9090, "D9090", tag, owner, clock, TYPE_9090, "d9090", __FILE__) { } + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void d9060_base_t::device_start() +{ + // state saving + save_item(NAME(m_rfdo)); + save_item(NAME(m_daco)); + save_item(NAME(m_atna)); + save_item(NAME(m_enable)); + + m_via->write_pb4(!(m_variant == TYPE_9090)); // J14 (6 HEADS) + m_via->write_pb5(!(m_variant == TYPE_9060)); // J13 (4 HEADS) +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void d9060_base_t::device_reset() +{ + m_maincpu->set_input_line(M6502_SET_OVERFLOW, ASSERT_LINE); + m_maincpu->set_input_line(M6502_SET_OVERFLOW, CLEAR_LINE); + + m_hdccpu->set_input_line(M6502_SET_OVERFLOW, ASSERT_LINE); + + m_riot1->pa7_w(1); +} + + +//------------------------------------------------- +// ieee488_atn - attention +//------------------------------------------------- + +void d9060_base_t::ieee488_atn(int state) +{ + update_ieee_signals(); + + m_riot1->pa7_w(state); +} + + +//------------------------------------------------- +// ieee488_ifc - interface clear +//------------------------------------------------- + +void d9060_base_t::ieee488_ifc(int state) +{ + if (!m_ifc && state) + { + device_reset(); + } + + m_ifc = state; +} diff --git a/src/devices/bus/ieee488/d9060.h b/src/devices/bus/ieee488/d9060.h new file mode 100644 index 00000000000..7efc20006cf --- /dev/null +++ b/src/devices/bus/ieee488/d9060.h @@ -0,0 +1,122 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Commodore D9060/D9090 Hard Disk Drive emulation + +**********************************************************************/ + +#pragma once + +#ifndef __D9060__ +#define __D9060__ + +#include "emu.h" +#include "ieee488.h" +#include "cpu/m6502/m6502.h" +#include "machine/6522via.h" +#include "machine/mos6530n.h" +#include "bus/scsi/scsi.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + + +// ======================> d9060_base_t + +class d9060_base_t : public device_t, + public device_ieee488_interface +{ +public: + enum + { + TYPE_9060, + TYPE_9090 + }; + + // construction/destruction + d9060_base_t(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, UINT32 variant, const char *shortname, const char *source); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + virtual ioport_constructor device_input_ports() const; + + // not really public + DECLARE_READ8_MEMBER( dio_r ); + DECLARE_WRITE8_MEMBER( dio_w ); + DECLARE_READ8_MEMBER( riot1_pa_r ); + DECLARE_WRITE8_MEMBER( riot1_pa_w ); + DECLARE_READ8_MEMBER( riot1_pb_r ); + DECLARE_WRITE8_MEMBER( riot1_pb_w ); + DECLARE_READ8_MEMBER( via_pb_r ); + DECLARE_WRITE8_MEMBER( via_pb_w ); + DECLARE_WRITE_LINE_MEMBER( ack_w ); + DECLARE_WRITE_LINE_MEMBER( enable_w ); + DECLARE_WRITE8_MEMBER( scsi_data_w ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_ieee488_interface overrides + void ieee488_atn(int state); + void ieee488_ifc(int state); + +private: + inline void update_ieee_signals(); + + required_device m_maincpu; + required_device m_hdccpu; + required_device m_riot0; + required_device m_riot1; + required_device m_via; + required_device m_sasibus; + required_device m_sasi_data_out; + required_ioport m_address; + + // IEEE-488 bus + int m_rfdo; // not ready for data output + int m_daco; // not data accepted output + int m_atna; // attention acknowledge + int m_ifc; + + // SASI bus + int m_enable; + UINT8 m_data; + + int m_variant; +}; + + +// ======================> d9060_t + +class d9060_t : public d9060_base_t +{ +public: + // construction/destruction + d9060_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +// ======================> d9090_t + +class d9090_t : public d9060_base_t +{ +public: + // construction/destruction + d9090_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +// device type definition +extern const device_type D9060; +extern const device_type D9090; + + + +#endif diff --git a/src/devices/bus/ieee488/hardbox.c b/src/devices/bus/ieee488/hardbox.c new file mode 100644 index 00000000000..4a2a0c16dae --- /dev/null +++ b/src/devices/bus/ieee488/hardbox.c @@ -0,0 +1,401 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder, Mike Naberezny +/**************************************************************************** + + SSE HardBox emulation + +****************************************************************************/ + +/* + http://mikenaberezny.com/hardware/pet-cbm/sse-hardbox-corvus-interface/ + + The HardBox provides a CBM DOS interface for a Corvus hard disk. Before + it can be used, a hard disk image must first be created and formatted. + Use the CHDMAN utility to create a 20MB image: + + $ chdman createhd -o /path/to/corvus20mb.chd -chs 388,5,20 -ss 512 + + Start the pet8032 emulator with the HardBox attached as device 9, + with the new CHD and the utilities floppy mounted: + + $ mess pet8032 -ieee9 hardbox \ + -hard1 /path/to/corvus20mb.chd \ + -flop1 /path/to/hardbox-utils.d80 + + Load and run the "configure" program from the floppy. When prompted + for the HardBox device number, enter "9". + + Select "q" for quick configure at the menu. It will present a default + drive size and ask if you want to alter it. If the size is not 20, + change it to 20. + + After accepting the drive size, it will prompt if you want to perform + a format check. This is optional. If you enter "y" to proceed with + the format check, it will always report no bad sectors. + + Enter "y" to proceed with the format. After it has completed, the + program will exit back to BASIC. The drive should now be usable. +*/ + + +#include "hardbox.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define Z80_TAG "z80" +#define I8255_0_TAG "ic17" +#define I8255_1_TAG "ic16" +#define CORVUS_HDC_TAG "corvus" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type HARDBOX = &device_creator; + + +//------------------------------------------------- +// ROM( hardbox ) +//------------------------------------------------- + +ROM_START( hardbox ) + ROM_REGION( 0x2000, Z80_TAG, 0 ) + ROM_DEFAULT_BIOS("v2.4") + + ROM_SYSTEM_BIOS( 0, "v2.3", "Version 2.3 (Corvus)" ) + ROMX_LOAD( "295-2.3.ic3", 0x0000, 0x1000, CRC(a3eb5fc2) SHA1(39941b45b0696db928615c41c7eae18d951d9ada), ROM_BIOS(1) ) + ROMX_LOAD( "296-2.3.ic4", 0x1000, 0x1000, CRC(fb55b058) SHA1(8f9ec313ec6beaf7b513edf39d9628e6abcc7bc3), ROM_BIOS(1) ) + + ROM_SYSTEM_BIOS( 1, "v2.4", "Version 2.4 (Corvus)" ) + ROMX_LOAD( "289.ic3", 0x0000, 0x1000, CRC(c39e058f) SHA1(45b390d7125a40f84c7b411a479218baff079746), ROM_BIOS(2) ) + ROMX_LOAD( "290.ic4", 0x1000, 0x1000, CRC(62f51405) SHA1(fdfa0d7b7e8d0182f2df0aa8163c790506104dcf), ROM_BIOS(2) ) + + ROM_SYSTEM_BIOS( 2, "v3.1", "Version 3.1 (Sunol)" ) + ROMX_LOAD( "295-3.1.ic3", 0x0000, 0x1000, CRC(654a5db1) SHA1(c40859526921e3d8bfd58fc28cc9cc64e59ec638), ROM_BIOS(3) ) + ROMX_LOAD( "296-3.1.ic4", 0x1000, 0x1000, CRC(4c62ddc0) SHA1(151f99dc554d3762b805fc8383cf1b3e1455784f), ROM_BIOS(3) ) + + /* Note: Two sets of EPROMs were found marked only "295" and "296" but they have different contents. + The version numbers listed are the ROM version reported by the HardBox diagnostics program. + Disassembling the ROMs showed that v2.3 and v2.4 are for Corvus Systems drives but v3.1 is + for Sunol Systems drives. Both types use the Corvus flat cable interface but there may be + some programming differences, e.g. the v3.1 firmware for Sunol does not have the park heads + routine in the Corvus versions. MESS emulates a Corvus drive so we default to the last + known HardBox firmware for Corvus (v2.4). */ +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *hardbox_device::device_rom_region() const +{ + return ROM_NAME( hardbox ); +} + + +//------------------------------------------------- +// ADDRESS_MAP( hardbox_mem ) +//------------------------------------------------- + +static ADDRESS_MAP_START( hardbox_mem, AS_PROGRAM, 8, hardbox_device ) + AM_RANGE(0x0000, 0x3fff) AM_RAM + AM_RANGE(0xe000, 0xffff) AM_ROM AM_REGION(Z80_TAG, 0) +ADDRESS_MAP_END + + +//------------------------------------------------- +// ADDRESS_MAP( hardbox_io ) +//------------------------------------------------- + +static ADDRESS_MAP_START( hardbox_io, AS_IO, 8, hardbox_device ) + ADDRESS_MAP_GLOBAL_MASK(0xff) + AM_RANGE(0x10, 0x13) AM_DEVREADWRITE(I8255_0_TAG, i8255_device, read, write) + AM_RANGE(0x14, 0x17) AM_DEVREADWRITE(I8255_1_TAG, i8255_device, read, write) + AM_RANGE(0x18, 0x18) AM_DEVREADWRITE(CORVUS_HDC_TAG, corvus_hdc_t, read, write) +ADDRESS_MAP_END + + +//------------------------------------------------- +// I8255A 0 interface +//------------------------------------------------- + +READ8_MEMBER( hardbox_device::ppi0_pa_r ) +{ + return m_bus->dio_r() ^ 0xff; +} + +WRITE8_MEMBER( hardbox_device::ppi0_pb_w ) +{ + m_bus->dio_w(this, data ^ 0xff); +} + +READ8_MEMBER( hardbox_device::ppi0_pc_r ) +{ + UINT8 data = ioport("SW1")->read(); + + /* DIP switches on PC1,PC2,PC3 configure the IEEE-488 primary address. + We get the address from the slot instead. */ + data |= ((m_slot->get_address() - 8) << 1) ^ 0xff; + + return data; +} + +//------------------------------------------------- +// I8255A 1 interface +//------------------------------------------------- + +READ8_MEMBER( hardbox_device::ppi1_pa_r ) +{ + /* + + bit description + + PA0 ATN + PA1 DAV + PA2 NDAC + PA3 NRFD + PA4 EOI + PA5 SRQ + PA6 REN + PA7 IFC + + */ + + UINT8 data = 0; + + data |= !m_bus->atn_r(); + data |= !m_bus->dav_r() << 1; + data |= !m_bus->ndac_r() << 2; + data |= !m_bus->nrfd_r() << 3; + data |= !m_bus->eoi_r() << 4; + data |= !m_bus->srq_r() << 5; + data |= !m_bus->ren_r() << 6; + data |= !m_bus->ifc_r() << 7; + + return data; +} + +WRITE8_MEMBER( hardbox_device::ppi1_pb_w ) +{ + /* + + bit description + + PB0 ATN + PB1 DAV + PB2 NDAC + PB3 NRFD + PB4 EOI + PB5 SRQ + PB6 REN + PB7 IFC + + Note: When the PCB is configured as a HardBox instead of a SoftBox, + IFC is read only. Do not connect IFC for output here. + + */ + + m_bus->atn_w(this, !BIT(data, 0)); + m_bus->dav_w(this, !BIT(data, 1)); + m_bus->ndac_w(this, !BIT(data, 2)); + m_bus->nrfd_w(this, !BIT(data, 3)); + m_bus->eoi_w(this, !BIT(data, 4)); + m_bus->srq_w(this, !BIT(data, 5)); + m_bus->ren_w(this, !BIT(data, 6)); +} + +READ8_MEMBER( hardbox_device::ppi1_pc_r ) +{ + /* + + bit description + + PC0 + PC1 + PC2 + PC3 + PC4 Corvus READY + PC5 Corvus DIRC + PC6 + PC7 + + */ + + UINT8 status = m_hdc->status_r(space, 0); + UINT8 data = 0; + + data |= (status & CONTROLLER_BUSY) ? 0 : 0x10; + data |= (status & CONTROLLER_DIRECTION) ? 0 : 0x20; + + return data; +} + +WRITE8_MEMBER( hardbox_device::ppi1_pc_w ) +{ + /* + + bit description + + PC0 LED "A" + PC1 LED "B" + PC2 LED "READY" + PC3 + PC4 + PC5 + PC6 + PC7 + + */ + + output_set_led_value(LED_A, !BIT(data, 0)); + output_set_led_value(LED_B, !BIT(data, 1)); + output_set_led_value(LED_READY, !BIT(data, 2)); +} + +//------------------------------------------------- +// MACHINE_CONFIG_FRAGMENT( hardbox ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( hardbox ) + // basic machine hardware + MCFG_CPU_ADD(Z80_TAG, Z80, XTAL_8MHz/2) + MCFG_CPU_PROGRAM_MAP(hardbox_mem) + MCFG_CPU_IO_MAP(hardbox_io) + + // devices + MCFG_DEVICE_ADD(I8255_0_TAG, I8255A, 0) + MCFG_I8255_IN_PORTA_CB(READ8(hardbox_device, ppi0_pa_r)) + MCFG_I8255_OUT_PORTB_CB(WRITE8(hardbox_device, ppi0_pb_w)) + MCFG_I8255_IN_PORTC_CB(READ8(hardbox_device, ppi0_pc_r)) + + MCFG_DEVICE_ADD(I8255_1_TAG, I8255A, 0) + MCFG_I8255_IN_PORTA_CB(READ8(hardbox_device, ppi1_pa_r)) + MCFG_I8255_OUT_PORTB_CB(WRITE8(hardbox_device, ppi1_pb_w)) + MCFG_I8255_IN_PORTC_CB(READ8(hardbox_device, ppi1_pc_r)) + MCFG_I8255_OUT_PORTC_CB(WRITE8(hardbox_device, ppi1_pc_w)) + + MCFG_DEVICE_ADD(CORVUS_HDC_TAG, CORVUS_HDC, 0) + MCFG_HARDDISK_ADD("harddisk1") + MCFG_HARDDISK_INTERFACE("corvus_hdd") + MCFG_HARDDISK_ADD("harddisk2") + MCFG_HARDDISK_INTERFACE("corvus_hdd") + MCFG_HARDDISK_ADD("harddisk3") + MCFG_HARDDISK_INTERFACE("corvus_hdd") + MCFG_HARDDISK_ADD("harddisk4") + MCFG_HARDDISK_INTERFACE("corvus_hdd") +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor hardbox_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( hardbox ); +} + + +//------------------------------------------------- +// INPUT_PORTS( hardbox ) +//------------------------------------------------- + +INPUT_PORTS_START( hardbox ) + PORT_START("SW1") + PORT_DIPUNKNOWN_DIPLOC( 0x01, IP_ACTIVE_LOW, "SW1:1" ) + PORT_DIPNAME( 0x0e, 0x0c, "Device Address" ) PORT_DIPLOCATION("SW1:2,3,4") + PORT_DIPSETTING( 0x0e, "8" ) + PORT_DIPSETTING( 0x0c, "9" ) + PORT_DIPSETTING( 0x0a, "10" ) + PORT_DIPSETTING( 0x08, "11" ) + PORT_DIPSETTING( 0x06, "12" ) + PORT_DIPSETTING( 0x04, "13" ) + PORT_DIPSETTING( 0x02, "14" ) + PORT_DIPSETTING( 0x00, "15" ) + PORT_DIPUNKNOWN_DIPLOC( 0x10, IP_ACTIVE_LOW, "SW1:5" ) + PORT_DIPUNKNOWN_DIPLOC( 0x20, IP_ACTIVE_LOW, "SW1:6" ) + PORT_DIPUNKNOWN_DIPLOC( 0x40, IP_ACTIVE_LOW, "SW1:7" ) + PORT_DIPUNKNOWN_DIPLOC( 0x80, IP_ACTIVE_LOW, "SW1:8" ) +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor hardbox_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( hardbox ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// hardbox_device - constructor +//------------------------------------------------- + +hardbox_device::hardbox_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, HARDBOX, "HardBox", tag, owner, clock, "hardbox", __FILE__), + device_ieee488_interface(mconfig, *this), + m_maincpu(*this, Z80_TAG), + m_hdc(*this, CORVUS_HDC_TAG) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void hardbox_device::device_start() +{ +} + + +//------------------------------------------------- +// device_reset_after_children - device-specific +// reset that must happen after child devices +// have performed their resets +//------------------------------------------------- + +void hardbox_device::device_reset_after_children() +{ + /* The Z80 starts at address 0x0000 but the HardBox has RAM there and + needs to start from the BIOS at 0xe000. The PCB has logic and a + 74S287 PROM that temporarily changes the memory map so that the + IC3 EPROM at 0xe000 is mapped to 0x0000 for the first instruction + fetch only. The instruction normally at 0xe000 is an absolute jump + into the ROM. On reset, the Z80 will fetch it from 0x0000 and set + its PC, then the normal map will be restored before the next + instruction fetch. Here we just set the PC to 0xe000 after the Z80 + resets, which has the same effect. */ + + m_maincpu->set_state_int(Z80_PC, 0xe000); +} + + +//------------------------------------------------- +// ieee488_ifc - interface clear (reset) +//------------------------------------------------- + +void hardbox_device::ieee488_ifc(int state) +{ + if (!m_ifc && state) + { + device_reset(); + } + + m_ifc = state; +} diff --git a/src/devices/bus/ieee488/hardbox.h b/src/devices/bus/ieee488/hardbox.h new file mode 100644 index 00000000000..77cbd23fb07 --- /dev/null +++ b/src/devices/bus/ieee488/hardbox.h @@ -0,0 +1,77 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder, Mike Naberezny +/********************************************************************** + + SSE HardBox emulation + +**********************************************************************/ + +#pragma once + +#ifndef __PET_HARDBOX__ +#define __PET_HARDBOX__ + +#include "ieee488.h" +#include "cpu/z80/z80.h" +#include "machine/i8251.h" +#include "machine/i8255.h" +#include "imagedev/harddriv.h" +#include "machine/corvushd.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> hardbox_device + +class hardbox_device : public device_t, + public device_ieee488_interface +{ +public: + // construction/destruction + hardbox_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + virtual ioport_constructor device_input_ports() const; + + DECLARE_READ8_MEMBER( ppi0_pa_r ); + DECLARE_WRITE8_MEMBER( ppi0_pb_w ); + DECLARE_READ8_MEMBER( ppi0_pc_r ); + + DECLARE_READ8_MEMBER( ppi1_pa_r ); + DECLARE_WRITE8_MEMBER( ppi1_pb_w ); + DECLARE_READ8_MEMBER( ppi1_pc_r ); + DECLARE_WRITE8_MEMBER( ppi1_pc_w ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset_after_children(); + + // device_ieee488_interface overrides + virtual void ieee488_ifc(int state); + +private: + enum + { + LED_A, + LED_B, + LED_READY + }; + + required_device m_maincpu; + required_device m_hdc; + + int m_ifc; // Tracks previous state of IEEE-488 IFC line +}; + +// device type definition +extern const device_type HARDBOX; + + + +#endif diff --git a/src/devices/bus/ieee488/ieee488.c b/src/devices/bus/ieee488/ieee488.c new file mode 100644 index 00000000000..f3d61fa539a --- /dev/null +++ b/src/devices/bus/ieee488/ieee488.c @@ -0,0 +1,396 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + IEEE-488.1 General Purpose Interface Bus emulation + (aka HP-IB, GPIB, CBM IEEE) + +**********************************************************************/ + +#include "ieee488.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define LOG 0 + + +static const char *const SIGNAL_NAME[] = { "EOI", "DAV", "NRFD", "NDAC", "IFC", "SRQ", "ATN", "REN" }; + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type IEEE488 = &device_creator; +const device_type IEEE488_SLOT = &device_creator; + + + +//************************************************************************** +// DEVICE INTERFACE +//************************************************************************** + +//------------------------------------------------- +// device_ieee488_interface - constructor +//------------------------------------------------- + +device_ieee488_interface::device_ieee488_interface(const machine_config &mconfig, device_t &device) + : device_slot_card_interface(mconfig, device) +{ +} + + +//------------------------------------------------- +// ~device_ieee488_interface - destructor +//------------------------------------------------- + +device_ieee488_interface::~device_ieee488_interface() +{ +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// ieee488_slot_device - constructor +//------------------------------------------------- + +ieee488_slot_device::ieee488_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, IEEE488_SLOT, "IEEE-488 slot", tag, owner, clock, "ieee488_slot", __FILE__), + device_slot_interface(mconfig, *this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void ieee488_slot_device::device_start() +{ + ieee488_device* bus = NULL; + + for (device_t *device = owner(); device != NULL; device = device->owner()) + { + bus = device->subdevice(IEEE488_TAG); + if (bus != NULL) break; + } + + assert(bus); + + device_ieee488_interface *dev = dynamic_cast(get_card_device()); + if (dev) bus->add_device(this, get_card_device()); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// ieee488_device - constructor +//------------------------------------------------- + +ieee488_device::ieee488_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, IEEE488, "IEEE-488 bus", tag, owner, clock, "ieee488", __FILE__), + m_write_eoi(*this), + m_write_dav(*this), + m_write_nrfd(*this), + m_write_ndac(*this), + m_write_ifc(*this), + m_write_srq(*this), + m_write_atn(*this), + m_write_ren(*this), + m_dio(0xff) +{ + for (int i = 0; i < SIGNAL_COUNT; i++) + { + m_line[i] = 1; + } +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void ieee488_device::device_start() +{ + // resolve callbacks + m_write_eoi.resolve_safe(); + m_write_dav.resolve_safe(); + m_write_nrfd.resolve_safe(); + m_write_ndac.resolve_safe(); + m_write_ifc.resolve_safe(); + m_write_srq.resolve_safe(); + m_write_atn.resolve_safe(); + m_write_ren.resolve_safe(); +} + + +//------------------------------------------------- +// device_stop - device-specific stop +//------------------------------------------------- + +void ieee488_device::device_stop() +{ + m_device_list.reset(); +} + + +//------------------------------------------------- +// add_device - +//------------------------------------------------- + +void ieee488_device::add_device(ieee488_slot_device *slot, device_t *target) +{ + daisy_entry *entry = global_alloc(daisy_entry(target)); + + entry->m_interface->m_bus = this; + entry->m_interface->m_slot = slot; + + m_device_list.append(*entry); +} + + +//------------------------------------------------- +// daisy_entry - constructor +//------------------------------------------------- + +ieee488_device::daisy_entry::daisy_entry(device_t *device) + : m_next(NULL), + m_device(device), + m_interface(NULL), + m_dio(0xff) +{ + for (int i = 0; i < SIGNAL_COUNT; i++) + { + m_line[i] = 1; + } + + device->interface(m_interface); +} + + +//------------------------------------------------- +// set_signal - +//------------------------------------------------- + +void ieee488_device::set_signal(device_t *device, int signal, int state) +{ + bool changed = false; + + if (device == this) + { + if (m_line[signal] != state) + { + if (LOG) logerror("%s IEEE488: '%s' %s %u\n", machine().describe_context(), tag(), SIGNAL_NAME[signal], state); + m_line[signal] = state; + changed = true; + } + } + else + { + daisy_entry *entry = m_device_list.first(); + + while (entry) + { + if (!strcmp(entry->m_device->tag(), device->tag())) + { + if (entry->m_line[signal] != state) + { + if (LOG) logerror("%s IEEE488: '%s' %s %u\n", machine().describe_context(), device->tag(), SIGNAL_NAME[signal], state); + entry->m_line[signal] = state; + changed = true; + } + } + + entry = entry->next(); + } + } + + if (changed) + { + switch (signal) + { + case EOI: m_write_eoi(state); break; + case DAV: m_write_dav(state); break; + case NRFD: m_write_nrfd(state); break; + case NDAC: m_write_ndac(state); break; + case IFC: m_write_ifc(state); break; + case SRQ: m_write_srq(state); break; + case ATN: m_write_atn(state); break; + case REN: m_write_ren(state); break; + } + + daisy_entry *entry = m_device_list.first(); + + while (entry) + { + switch (signal) + { + case EOI: + entry->m_interface->ieee488_eoi(state); + break; + + case DAV: + entry->m_interface->ieee488_dav(state); + break; + + case NRFD: + entry->m_interface->ieee488_nrfd(state); + break; + + case NDAC: + entry->m_interface->ieee488_ndac(state); + break; + + case IFC: + entry->m_interface->ieee488_ifc(state); + break; + + case SRQ: + entry->m_interface->ieee488_srq(state); + break; + + case ATN: + entry->m_interface->ieee488_atn(state); + break; + + case REN: + entry->m_interface->ieee488_ren(state); + break; + } + + entry = entry->next(); + } + + if (LOG) logerror("IEEE488: EOI %u DAV %u NRFD %u NDAC %u IFC %u SRQ %u ATN %u REN %u DIO %02x\n", + get_signal(EOI), get_signal(DAV), get_signal(NRFD), get_signal(NDAC), + get_signal(IFC), get_signal(SRQ), get_signal(ATN), get_signal(REN), get_data()); + } +} + + +//------------------------------------------------- +// get_signal - +//------------------------------------------------- + +int ieee488_device::get_signal(int signal) +{ + int state = m_line[signal]; + + if (state) + { + daisy_entry *entry = m_device_list.first(); + + while (entry) + { + if (!entry->m_line[signal]) + { + state = 0; + break; + } + + entry = entry->next(); + } + } + + return state; +} + + +//------------------------------------------------- +// set_data - +//------------------------------------------------- + +void ieee488_device::set_data(device_t *device, UINT8 data) +{ + if (device == this) + { + if (LOG) logerror("%s IEEE488: '%s' DIO %02x\n", machine().describe_context(), tag(), data); + + m_dio = data; + } + else + { + daisy_entry *entry = m_device_list.first(); + + while (entry) + { + if (!strcmp(entry->m_device->tag(), device->tag())) + { + if (entry->m_dio != data) + { + if (LOG) logerror("%s IEEE488: '%s' DIO %02x\n", machine().describe_context(), device->tag(), data); + entry->m_dio = data; + } + } + + entry = entry->next(); + } + } +} + + +//------------------------------------------------- +// get_data - +//------------------------------------------------- + +UINT8 ieee488_device::get_data() +{ + UINT8 data = m_dio; + + daisy_entry *entry = m_device_list.first(); + + while (entry) + { + data &= entry->m_dio; + + entry = entry->next(); + } + + return data; +} + + +//------------------------------------------------- +// SLOT_INTERFACE( cbm_ieee488_devices ) +//------------------------------------------------- + +// slot devices +#include "bus/cbmiec/c1526.h" +#include "c2031.h" +#include "c2040.h" +#include "c8050.h" +#include "c8280.h" +#include "d9060.h" +#include "hardbox.h" +#include "shark.h" +#include "softbox.h" + +SLOT_INTERFACE_START( cbm_ieee488_devices ) + SLOT_INTERFACE("c2040", C2040) + SLOT_INTERFACE("c3040", C3040) + SLOT_INTERFACE("c4040", C4040) + SLOT_INTERFACE("c8050", C8050) + SLOT_INTERFACE("c8250", C8250) + SLOT_INTERFACE("sfd1001", SFD1001) + SLOT_INTERFACE("c2031", C2031) + SLOT_INTERFACE("c8280", C8280) + SLOT_INTERFACE("d9060", D9060) + SLOT_INTERFACE("d9090", D9090) + SLOT_INTERFACE("softbox", SOFTBOX) + SLOT_INTERFACE("hardbox", HARDBOX) + SLOT_INTERFACE("shark", SHARK) + SLOT_INTERFACE("c4023", C4023) +SLOT_INTERFACE_END diff --git a/src/devices/bus/ieee488/ieee488.h b/src/devices/bus/ieee488/ieee488.h new file mode 100644 index 00000000000..3a6c53966f1 --- /dev/null +++ b/src/devices/bus/ieee488/ieee488.h @@ -0,0 +1,253 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + IEEE-488.1 General Purpose Interface Bus emulation + (aka HP-IB, GPIB, CBM IEEE) + +**********************************************************************/ + +#pragma once + +#ifndef __IEEE488__ +#define __IEEE488__ + +#include "emu.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define IEEE488_TAG "ieee_bus" + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_IEEE488_BUS_ADD() \ + MCFG_DEVICE_ADD(IEEE488_TAG, IEEE488, 0) + + +#define MCFG_IEEE488_EOI_CALLBACK(_write) \ + downcast(device)->set_eoi_callback(DEVCB_##_write); + +#define MCFG_IEEE488_DAV_CALLBACK(_write) \ + downcast(device)->set_dav_callback(DEVCB_##_write); + +#define MCFG_IEEE488_NRFD_CALLBACK(_write) \ + downcast(device)->set_nrfd_callback(DEVCB_##_write); + +#define MCFG_IEEE488_NDAC_CALLBACK(_write) \ + downcast(device)->set_ndac_callback(DEVCB_##_write); + +#define MCFG_IEEE488_IFC_CALLBACK(_write) \ + downcast(device)->set_ifc_callback(DEVCB_##_write); + +#define MCFG_IEEE488_SRQ_CALLBACK(_write) \ + downcast(device)->set_srq_callback(DEVCB_##_write); + +#define MCFG_IEEE488_ATN_CALLBACK(_write) \ + downcast(device)->set_atn_callback(DEVCB_##_write); + +#define MCFG_IEEE488_REN_CALLBACK(_write) \ + downcast(device)->set_ren_callback(DEVCB_##_write); + + +#define MCFG_IEEE488_SLOT_ADD(_tag, _address, _slot_intf, _def_slot) \ + MCFG_DEVICE_ADD(_tag, IEEE488_SLOT, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) \ + downcast(device)->set_address(_address); + + +#define MCFG_CBM_IEEE488_ADD(_default_drive) \ + MCFG_IEEE488_SLOT_ADD("ieee4", 4, cbm_ieee488_devices, NULL) \ + MCFG_IEEE488_SLOT_ADD("ieee8", 8, cbm_ieee488_devices, _default_drive) \ + MCFG_IEEE488_SLOT_ADD("ieee9", 9, cbm_ieee488_devices, NULL) \ + MCFG_IEEE488_SLOT_ADD("ieee10", 10, cbm_ieee488_devices, NULL) \ + MCFG_IEEE488_SLOT_ADD("ieee11", 11, cbm_ieee488_devices, NULL) \ + MCFG_IEEE488_SLOT_ADD("ieee12", 12, cbm_ieee488_devices, NULL) \ + MCFG_IEEE488_SLOT_ADD("ieee13", 13, cbm_ieee488_devices, NULL) \ + MCFG_IEEE488_SLOT_ADD("ieee14", 14, cbm_ieee488_devices, NULL) \ + MCFG_IEEE488_SLOT_ADD("ieee15", 15, cbm_ieee488_devices, NULL) \ + MCFG_IEEE488_BUS_ADD() + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> ieee488_device + +class ieee488_slot_device; +class device_ieee488_interface; + +class ieee488_device : public device_t +{ +public: + // construction/destruction + ieee488_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + template void set_eoi_callback(_write wr) { m_write_eoi.set_callback(wr); } + template void set_dav_callback(_write wr) { m_write_dav.set_callback(wr); } + template void set_nrfd_callback(_write wr) { m_write_nrfd.set_callback(wr); } + template void set_ndac_callback(_write wr) { m_write_ndac.set_callback(wr); } + template void set_ifc_callback(_write wr) { m_write_ifc.set_callback(wr); } + template void set_srq_callback(_write wr) { m_write_srq.set_callback(wr); } + template void set_atn_callback(_write wr) { m_write_atn.set_callback(wr); } + template void set_ren_callback(_write wr) { m_write_ren.set_callback(wr); } + + void add_device(ieee488_slot_device *slot, device_t *target); + + // reads for both host and peripherals + UINT8 dio_r() { return get_data(); } + DECLARE_READ8_MEMBER( dio_r ) { return get_data(); } + DECLARE_READ_LINE_MEMBER( eoi_r ) { return get_signal(EOI); } + DECLARE_READ_LINE_MEMBER( dav_r ) { return get_signal(DAV); } + DECLARE_READ_LINE_MEMBER( nrfd_r ) { return get_signal(NRFD); } + DECLARE_READ_LINE_MEMBER( ndac_r ) { return get_signal(NDAC); } + DECLARE_READ_LINE_MEMBER( ifc_r ) { return get_signal(IFC); } + DECLARE_READ_LINE_MEMBER( srq_r ) { return get_signal(SRQ); } + DECLARE_READ_LINE_MEMBER( atn_r ) { return get_signal(ATN); } + DECLARE_READ_LINE_MEMBER( ren_r ) { return get_signal(REN); } + + // writes for host (driver_device) + void dio_w(UINT8 data) { return set_data(this, data); } + DECLARE_WRITE8_MEMBER( dio_w ) { set_data(this, data); } + DECLARE_WRITE_LINE_MEMBER( eoi_w ) { set_signal(this, EOI, state); } + DECLARE_WRITE_LINE_MEMBER( dav_w ) { set_signal(this, DAV, state); } + DECLARE_WRITE_LINE_MEMBER( nrfd_w ) { set_signal(this, NRFD, state); } + DECLARE_WRITE_LINE_MEMBER( ndac_w ) { set_signal(this, NDAC, state); } + DECLARE_WRITE_LINE_MEMBER( ifc_w ) { set_signal(this, IFC, state); } + DECLARE_WRITE_LINE_MEMBER( srq_w ) { set_signal(this, SRQ, state); } + DECLARE_WRITE_LINE_MEMBER( atn_w ) { set_signal(this, ATN, state); } + DECLARE_WRITE_LINE_MEMBER( ren_w ) { set_signal(this, REN, state); } + + // writes for peripherals (device_t) + void dio_w(device_t *device, UINT8 data) { set_data(device, data); } + void eoi_w(device_t *device, int state) { set_signal(device, EOI, state); } + void dav_w(device_t *device, int state) { set_signal(device, DAV, state); } + void nrfd_w(device_t *device, int state) { set_signal(device, NRFD, state); } + void ndac_w(device_t *device, int state) { set_signal(device, NDAC, state); } + void ifc_w(device_t *device, int state) { set_signal(device, IFC, state); } + void srq_w(device_t *device, int state) { set_signal(device, SRQ, state); } + void atn_w(device_t *device, int state) { set_signal(device, ATN, state); } + void ren_w(device_t *device, int state) { set_signal(device, REN, state); } + +protected: + enum + { + EOI = 0, + DAV, + NRFD, + NDAC, + IFC, + SRQ, + ATN, + REN, + SIGNAL_COUNT + }; + + // device-level overrides + virtual void device_start(); + virtual void device_stop(); + + class daisy_entry + { + public: + daisy_entry(device_t *device); + daisy_entry *next() const { return m_next; } + + daisy_entry * m_next; // next device + device_t * m_device; // associated device + device_ieee488_interface * m_interface; // associated device's daisy interface + + int m_line[SIGNAL_COUNT]; + UINT8 m_dio; + }; + + simple_list m_device_list; + +private: + devcb_write_line m_write_eoi; + devcb_write_line m_write_dav; + devcb_write_line m_write_nrfd; + devcb_write_line m_write_ndac; + devcb_write_line m_write_ifc; + devcb_write_line m_write_srq; + devcb_write_line m_write_atn; + devcb_write_line m_write_ren; + + void set_signal(device_t *device, int signal, int state); + int get_signal(int signal); + void set_data(device_t *device, UINT8 data); + UINT8 get_data(); + + int m_line[SIGNAL_COUNT]; + UINT8 m_dio; +}; + + +// ======================> ieee488_slot_device + +class ieee488_slot_device : public device_t, + public device_slot_interface +{ +public: + // construction/destruction + ieee488_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + void set_address(int address) { m_address = address; } + int get_address() { return m_address; } + + // device-level overrides + virtual void device_start(); + +protected: + int m_address; +}; + + +// ======================> device_ieee488_interface + +class device_ieee488_interface : public device_slot_card_interface +{ + friend class ieee488_device; + +public: + // construction/destruction + device_ieee488_interface(const machine_config &mconfig, device_t &device); + virtual ~device_ieee488_interface(); + + device_ieee488_interface *next() const { return m_next; } + device_ieee488_interface *m_next; + + // optional operation overrides + virtual void ieee488_eoi(int state) { }; + virtual void ieee488_dav(int state) { }; + virtual void ieee488_nrfd(int state) { }; + virtual void ieee488_ndac(int state) { }; + virtual void ieee488_ifc(int state) { }; + virtual void ieee488_srq(int state) { }; + virtual void ieee488_atn(int state) { }; + virtual void ieee488_ren(int state) { }; + + ieee488_device *m_bus; + ieee488_slot_device *m_slot; +}; + + +// device type definition +extern const device_type IEEE488; +extern const device_type IEEE488_SLOT; + + +SLOT_INTERFACE_EXTERN( cbm_ieee488_devices ); + + + +#endif diff --git a/src/devices/bus/ieee488/shark.c b/src/devices/bus/ieee488/shark.c new file mode 100644 index 00000000000..47582aa42b8 --- /dev/null +++ b/src/devices/bus/ieee488/shark.c @@ -0,0 +1,144 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Mator Systems SHARK Intelligent Winchester Disc Subsystem emulation + +**********************************************************************/ + +#include "shark.h" +#include "bus/rs232/rs232.h" +#include "cpu/i8085/i8085.h" +#include "imagedev/harddriv.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define I8085_TAG "i8085" +#define RS232_TAG "rs232" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type SHARK = &device_creator; + + +//------------------------------------------------- +// ROM( mshark ) +//------------------------------------------------- + +ROM_START( mshark ) + ROM_REGION( 0x5000, I8085_TAG, 0 ) + ROM_LOAD( "pch488 3450 v22.1 #1", 0x0000, 0x1000, CRC(03bff9d7) SHA1(ac506df6509e1b2185a69f9f8f44b8b456aa9834) ) + ROM_LOAD( "pch488 3450 v22.1 #2", 0x1000, 0x1000, CRC(c14fa5fe) SHA1(bcfd1dd65d692c76b90e6134b85f22c39c049430) ) + ROM_LOAD( "pch488 3450 v22.1 #3", 0x2000, 0x1000, CRC(4dfaa482) SHA1(fe2c44bb650572616c8bdad6358032fe64b1e363) ) + ROM_LOAD( "pch488 3450 v22.1 #4", 0x3000, 0x1000, CRC(aef665e9) SHA1(80a4c00b717100b4e22fa3704e34060fffce2bc3) ) + ROM_LOAD( "pch488 3450 v22.1 #5", 0x4000, 0x1000, CRC(f30adf60) SHA1(96c15264d5a9b52e1d238921880c48a797a6da1e) ) + + ROM_REGION( 0x800, "micro", 0 ) // address decoder + ROM_LOAD( "micro p3450 v1.3", 0x000, 0x800, CRC(0e69202e) SHA1(3b384951ff54c4b45a3a778a88966d13e2c9d57a) ) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *mshark_device::device_rom_region() const +{ + return ROM_NAME( mshark ); +} + + +//------------------------------------------------- +// ADDRESS_MAP( mshark_mem ) +//------------------------------------------------- + +static ADDRESS_MAP_START( mshark_mem, AS_PROGRAM, 8, mshark_device ) + AM_RANGE(0x0000, 0x4fff) AM_ROM AM_REGION(I8085_TAG, 0) +ADDRESS_MAP_END + + +//------------------------------------------------- +// ADDRESS_MAP( mshark_io ) +//------------------------------------------------- + +static ADDRESS_MAP_START( mshark_io, AS_IO, 8, mshark_device ) +ADDRESS_MAP_END + + +//------------------------------------------------- +// MACHINE_CONFIG_FRAGMENT( mshark ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( mshark ) + // basic machine hardware + MCFG_CPU_ADD(I8085_TAG, I8085A, 1000000) + MCFG_CPU_PROGRAM_MAP(mshark_mem) + MCFG_CPU_IO_MAP(mshark_io) + + // devices + MCFG_HARDDISK_ADD("harddisk1") + MCFG_RS232_PORT_ADD(RS232_TAG, default_rs232_devices, NULL) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor mshark_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( mshark ); +} + + +//------------------------------------------------- +// INPUT_PORTS( mshark ) +//------------------------------------------------- + +INPUT_PORTS_START( mshark ) +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor mshark_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( mshark ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// mshark_device - constructor +//------------------------------------------------- + +mshark_device::mshark_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, SHARK, "Mator SHARK", tag, owner, clock, "mshark", __FILE__), + device_ieee488_interface(mconfig, *this), + m_maincpu(*this, I8085_TAG) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void mshark_device::device_start() +{ +} diff --git a/src/devices/bus/ieee488/shark.h b/src/devices/bus/ieee488/shark.h new file mode 100644 index 00000000000..d5e2f1fe1f8 --- /dev/null +++ b/src/devices/bus/ieee488/shark.h @@ -0,0 +1,52 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Mator Systems SHARK Intelligent Winchester Disc Subsystem emulation + + 35MB PRIAM DISKOS 3450 8" Winchester Hard Disk (-chs 525,5,? -ss ?) + +**********************************************************************/ + +#pragma once + +#ifndef __SHARK__ +#define __SHARK__ + +#include "ieee488.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> mshark_device + +class mshark_device : public device_t, + public device_ieee488_interface +{ +public: + // construction/destruction + mshark_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + virtual ioport_constructor device_input_ports() const; + +protected: + // device-level overrides + virtual void device_start(); + +private: + required_device m_maincpu; +}; + + +// device type definition +extern const device_type SHARK; + + + +#endif diff --git a/src/devices/bus/ieee488/softbox.c b/src/devices/bus/ieee488/softbox.c new file mode 100644 index 00000000000..7f1dfe64b9d --- /dev/null +++ b/src/devices/bus/ieee488/softbox.c @@ -0,0 +1,393 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder, Mike Naberezny +/********************************************************************** + + SSE SoftBox emulation + +**********************************************************************/ + +/* + This is an emulation of the SoftBox as a PET/CBM peripheral, where + the PET is used as a terminal over IEEE-488. For the standalone + mode where an RS-232 terminal is used, and also information on + how to set up the Corvus drive, see: src/mess/drivers/softbox.c. +*/ + + +#include "softbox.h" + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define Z80_TAG "z80" +#define I8251_TAG "ic15" +#define I8255_0_TAG "ic17" +#define I8255_1_TAG "ic16" +#define COM8116_TAG "ic14" +#define RS232_TAG "rs232" +#define CORVUS_HDC_TAG "corvus" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type SOFTBOX = &device_creator; + + +//------------------------------------------------- +// ROM( softbox ) +//------------------------------------------------- + +ROM_START( softbox ) + ROM_REGION( 0x1000, Z80_TAG, 0 ) + ROM_DEFAULT_BIOS("19830609") + ROM_SYSTEM_BIOS( 0, "19810908", "8/9/81" ) + ROMX_LOAD( "375.ic3", 0x000, 0x800, CRC(177580e7) SHA1(af6a97495de825b80cdc9fbf72329d5440826177), ROM_BIOS(1) ) + ROMX_LOAD( "376.ic4", 0x800, 0x800, CRC(edfee5be) SHA1(5662e9071cc622a1c071d89b00272fc6ba122b9a), ROM_BIOS(1) ) + ROM_SYSTEM_BIOS( 1, "19811027", "27-Oct-81" ) + ROMX_LOAD( "379.ic3", 0x000, 0x800, CRC(7b5a737c) SHA1(2348590884b026b7647f6864af8c9ba1c6f8746b), ROM_BIOS(2) ) + ROMX_LOAD( "380.ic4", 0x800, 0x800, CRC(65a13029) SHA1(46de02e6f04be298047efeb412e00a5714dc21b3), ROM_BIOS(2) ) + ROM_SYSTEM_BIOS( 2, "19830609", "09-June-1983" ) + ROMX_LOAD( "389.ic3", 0x000, 0x800, CRC(d66e581a) SHA1(2403e25c140c41b0e6d6975d39c9cd9d6f335048), ROM_BIOS(3) ) + ROMX_LOAD( "390.ic4", 0x800, 0x800, CRC(abe6cb30) SHA1(4b26d5db36f828e01268f718799f145d09b449ad), ROM_BIOS(3) ) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *softbox_device::device_rom_region() const +{ + return ROM_NAME( softbox ); +} + + +//------------------------------------------------- +// ADDRESS_MAP( softbox_mem ) +//------------------------------------------------- + +static ADDRESS_MAP_START( softbox_mem, AS_PROGRAM, 8, softbox_device ) + AM_RANGE(0x0000, 0xefff) AM_RAM + AM_RANGE(0xf000, 0xffff) AM_ROM AM_REGION(Z80_TAG, 0) +ADDRESS_MAP_END + + +//------------------------------------------------- +// ADDRESS_MAP( softbox_io ) +//------------------------------------------------- + +static ADDRESS_MAP_START( softbox_io, AS_IO, 8, softbox_device ) + ADDRESS_MAP_GLOBAL_MASK(0xff) + AM_RANGE(0x08, 0x08) AM_DEVREADWRITE(I8251_TAG, i8251_device, data_r, data_w) + AM_RANGE(0x09, 0x09) AM_DEVREADWRITE(I8251_TAG, i8251_device, status_r, control_w) + AM_RANGE(0x0c, 0x0c) AM_WRITE(dbrg_w) + AM_RANGE(0x10, 0x13) AM_DEVREADWRITE(I8255_0_TAG, i8255_device, read, write) + AM_RANGE(0x14, 0x17) AM_DEVREADWRITE(I8255_1_TAG, i8255_device, read, write) + AM_RANGE(0x18, 0x18) AM_DEVREADWRITE(CORVUS_HDC_TAG, corvus_hdc_t, read, write) +ADDRESS_MAP_END + + + +//------------------------------------------------- +// I8255A 0 Interface +//------------------------------------------------- + +READ8_MEMBER( softbox_device::ppi0_pa_r ) +{ + return m_bus->dio_r() ^ 0xff; +} + +WRITE8_MEMBER( softbox_device::ppi0_pb_w ) +{ + m_bus->dio_w(this, data ^ 0xff); +} + +//------------------------------------------------- +// I8255A 1 Interface +//------------------------------------------------- + +READ8_MEMBER( softbox_device::ppi1_pa_r ) +{ + /* + + bit description + + PA0 ATN + PA1 DAV + PA2 NDAC + PA3 NRFD + PA4 EOI + PA5 SRQ + PA6 REN + PA7 IFC + + */ + + UINT8 data = 0; + + data |= !m_bus->atn_r(); + data |= !m_bus->dav_r() << 1; + data |= !m_bus->ndac_r() << 2; + data |= !m_bus->nrfd_r() << 3; + data |= !m_bus->eoi_r() << 4; + data |= !m_bus->srq_r() << 5; + data |= !m_bus->ren_r() << 6; + data |= !m_bus->ifc_r() << 7; + + return data; +} + +WRITE8_MEMBER( softbox_device::ppi1_pb_w ) +{ + /* + + bit description + + PB0 ATN + PB1 DAV + PB2 NDAC + PB3 NRFD + PB4 EOI + PB5 SRQ + PB6 REN + PB7 IFC + + */ + + m_bus->atn_w(this, !BIT(data, 0)); + m_bus->dav_w(this, !BIT(data, 1)); + m_bus->ndac_w(this, !BIT(data, 2)); + m_bus->nrfd_w(this, !BIT(data, 3)); + m_bus->eoi_w(this, !BIT(data, 4)); + m_bus->srq_w(this, !BIT(data, 5)); + m_bus->ren_w(this, !BIT(data, 6)); + m_bus->ifc_w(this, !BIT(data, 7)); +} + +READ8_MEMBER( softbox_device::ppi1_pc_r ) +{ + /* + + bit description + + PC0 + PC1 + PC2 + PC3 + PC4 Corvus READY + PC5 Corvus DIRC + PC6 + PC7 + + */ + + UINT8 status = m_hdc->status_r(space, 0); + UINT8 data = 0; + + data |= (status & CONTROLLER_BUSY) ? 0 : 0x10; + data |= (status & CONTROLLER_DIRECTION) ? 0 : 0x20; + + return data; +} + +WRITE8_MEMBER( softbox_device::ppi1_pc_w ) +{ + /* + + bit description + + PC0 LED "A" + PC1 LED "B" + PC2 LED "READY" + PC3 + PC4 + PC5 + PC6 + PC7 + + */ + + output_set_led_value(LED_A, !BIT(data, 0)); + output_set_led_value(LED_B, !BIT(data, 1)); + output_set_led_value(LED_READY, !BIT(data, 2)); +} + +static DEVICE_INPUT_DEFAULTS_START( terminal ) + DEVICE_INPUT_DEFAULTS( "RS232_TXBAUD", 0xff, RS232_BAUD_9600 ) + DEVICE_INPUT_DEFAULTS( "RS232_RXBAUD", 0xff, RS232_BAUD_9600 ) + DEVICE_INPUT_DEFAULTS( "RS232_STARTBITS", 0xff, RS232_STARTBITS_1 ) + DEVICE_INPUT_DEFAULTS( "RS232_DATABITS", 0xff, RS232_DATABITS_7 ) + DEVICE_INPUT_DEFAULTS( "RS232_PARITY", 0xff, RS232_PARITY_EVEN ) + DEVICE_INPUT_DEFAULTS( "RS232_STOPBITS", 0xff, RS232_STOPBITS_1 ) +DEVICE_INPUT_DEFAULTS_END + + +//------------------------------------------------- +// MACHINE_CONFIG_FRAGMENT( softbox ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( softbox ) + // basic machine hardware + MCFG_CPU_ADD(Z80_TAG, Z80, XTAL_8MHz/2) + MCFG_CPU_PROGRAM_MAP(softbox_mem) + MCFG_CPU_IO_MAP(softbox_io) + + // devices + MCFG_DEVICE_ADD(I8251_TAG, I8251, 0) + MCFG_I8251_TXD_HANDLER(DEVWRITELINE(RS232_TAG, rs232_port_device, write_txd)) + MCFG_I8251_DTR_HANDLER(DEVWRITELINE(RS232_TAG, rs232_port_device, write_dtr)) + MCFG_I8251_RTS_HANDLER(DEVWRITELINE(RS232_TAG, rs232_port_device, write_rts)) + + MCFG_RS232_PORT_ADD(RS232_TAG, default_rs232_devices, NULL) + MCFG_RS232_RXD_HANDLER(DEVWRITELINE(I8251_TAG, i8251_device, write_rxd)) + MCFG_RS232_DSR_HANDLER(DEVWRITELINE(I8251_TAG, i8251_device, write_dsr)) + MCFG_DEVICE_CARD_DEVICE_INPUT_DEFAULTS("terminal", terminal) + + MCFG_DEVICE_ADD(I8255_0_TAG, I8255A, 0) + MCFG_I8255_IN_PORTA_CB(READ8(softbox_device, ppi0_pa_r)) + MCFG_I8255_OUT_PORTB_CB(WRITE8(softbox_device, ppi0_pb_w)) + MCFG_I8255_IN_PORTC_CB(IOPORT("SW1")) + + MCFG_DEVICE_ADD(I8255_1_TAG, I8255A, 0) + MCFG_I8255_IN_PORTA_CB(READ8(softbox_device, ppi1_pa_r)) + MCFG_I8255_OUT_PORTB_CB(WRITE8(softbox_device, ppi1_pb_w)) + MCFG_I8255_IN_PORTC_CB(READ8(softbox_device, ppi1_pc_r)) + MCFG_I8255_OUT_PORTC_CB(WRITE8(softbox_device, ppi1_pc_w)) + + MCFG_DEVICE_ADD(COM8116_TAG, COM8116, XTAL_5_0688MHz) + MCFG_COM8116_FR_HANDLER(DEVWRITELINE(I8251_TAG, i8251_device, write_rxc)) + MCFG_COM8116_FT_HANDLER(DEVWRITELINE(I8251_TAG, i8251_device, write_txc)) + + MCFG_DEVICE_ADD(CORVUS_HDC_TAG, CORVUS_HDC, 0) + MCFG_HARDDISK_ADD("harddisk1") + MCFG_HARDDISK_INTERFACE("corvus_hdd") + MCFG_HARDDISK_ADD("harddisk2") + MCFG_HARDDISK_INTERFACE("corvus_hdd") + MCFG_HARDDISK_ADD("harddisk3") + MCFG_HARDDISK_INTERFACE("corvus_hdd") + MCFG_HARDDISK_ADD("harddisk4") + MCFG_HARDDISK_INTERFACE("corvus_hdd") + //MCFG_IMI7000_BUS_ADD("imi5000h", NULL, NULL, NULL) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor softbox_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( softbox ); +} + + +//------------------------------------------------- +// INPUT_PORTS( softbox ) +//------------------------------------------------- + +INPUT_PORTS_START( softbox ) + /* An 8-position DIP switch may be installed at SW1. Some + SoftBox units have it and some do not. The switches are + not used by the SoftBox BIOS. */ + PORT_START("SW1") + PORT_DIPUNUSED_DIPLOC( 0x01, IP_ACTIVE_LOW, "SW1:1" ) + PORT_DIPUNUSED_DIPLOC( 0x02, IP_ACTIVE_LOW, "SW1:2" ) + PORT_DIPUNUSED_DIPLOC( 0x04, IP_ACTIVE_LOW, "SW1:3" ) + PORT_DIPUNUSED_DIPLOC( 0x08, IP_ACTIVE_LOW, "SW1:4" ) + PORT_DIPUNUSED_DIPLOC( 0x10, IP_ACTIVE_LOW, "SW1:5" ) + PORT_DIPUNUSED_DIPLOC( 0x20, IP_ACTIVE_LOW, "SW1:6" ) + PORT_DIPUNUSED_DIPLOC( 0x40, IP_ACTIVE_LOW, "SW1:7" ) + PORT_DIPUNUSED_DIPLOC( 0x80, IP_ACTIVE_LOW, "SW1:8" ) +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor softbox_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( softbox ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// softbox_device - constructor +//------------------------------------------------- + +softbox_device::softbox_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, SOFTBOX, "PET SoftBox", tag, owner, clock, "pet_softbox", __FILE__), + device_ieee488_interface(mconfig, *this), + m_maincpu(*this, Z80_TAG), + m_dbrg(*this, COM8116_TAG), + m_hdc(*this, CORVUS_HDC_TAG) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void softbox_device::device_start() +{ +} + + +//------------------------------------------------- +// device_reset_after_children - device-specific +// reset that must happen after child devices +// have performed their resets +//------------------------------------------------- + +void softbox_device::device_reset_after_children() +{ + /* The Z80 starts at address 0x0000 but the SoftBox has RAM there and + needs to start from the BIOS at 0xf000. The PCB has logic and a + 74S287 PROM that temporarily changes the memory map so that the + IC3 EPROM at 0xf000 is mapped to 0x0000 for the first instruction + fetch only. The instruction normally at 0xf000 is an absolute jump + into the BIOS. On reset, the Z80 will fetch it from 0x0000 and set + its PC, then the normal map will be restored before the next + instruction fetch. Here we just set the PC to 0xf000 after the Z80 + resets, which has the same effect. */ + + m_maincpu->set_state_int(Z80_PC, 0xf000); +} + + +//------------------------------------------------- +// ieee488_ifc - interface clear (reset) +//------------------------------------------------- + +void softbox_device::ieee488_ifc(int state) +{ + if (!m_ifc && state) + { + device_reset(); + } + + m_ifc = state; +} + + +//------------------------------------------------- +// dbrg_w - baud rate selection +//------------------------------------------------- + +WRITE8_MEMBER( softbox_device::dbrg_w ) +{ + m_dbrg->str_w(data & 0x0f); + m_dbrg->stt_w(data >> 4); +} diff --git a/src/devices/bus/ieee488/softbox.h b/src/devices/bus/ieee488/softbox.h new file mode 100644 index 00000000000..97e729fcc8d --- /dev/null +++ b/src/devices/bus/ieee488/softbox.h @@ -0,0 +1,82 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder, Mike Naberezny +/********************************************************************** + + SSE SoftBox emulation + +**********************************************************************/ + +#pragma once + +#ifndef __PET_SOFTBOX__ +#define __PET_SOFTBOX__ + +#include "ieee488.h" +#include "bus/rs232/rs232.h" +#include "cpu/z80/z80.h" +#include "imagedev/harddriv.h" +#include "machine/corvushd.h" +#include "machine/com8116.h" +#include "machine/i8251.h" +#include "machine/i8255.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> softbox_device + +class softbox_device : public device_t, + public device_ieee488_interface +{ +public: + // construction/destruction + softbox_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + virtual ioport_constructor device_input_ports() const; + + DECLARE_WRITE8_MEMBER( dbrg_w ); + + DECLARE_READ8_MEMBER( ppi0_pa_r ); + DECLARE_WRITE8_MEMBER( ppi0_pb_w ); + + DECLARE_READ8_MEMBER( ppi1_pa_r ); + DECLARE_WRITE8_MEMBER( ppi1_pb_w ); + DECLARE_READ8_MEMBER( ppi1_pc_r ); + DECLARE_WRITE8_MEMBER( ppi1_pc_w ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset_after_children(); + + // device_ieee488_interface overrides + virtual void ieee488_ifc(int state); + +private: + enum + { + LED_A, + LED_B, + LED_READY + }; + + required_device m_maincpu; + required_device m_dbrg; + required_device m_hdc; + + int m_ifc; // Tracks previous state of IEEE-488 IFC line +}; + + +// device type definition +extern const device_type SOFTBOX; + + + +#endif diff --git a/src/devices/bus/imi7000/imi5000h.c b/src/devices/bus/imi7000/imi5000h.c new file mode 100644 index 00000000000..ff57b942f17 --- /dev/null +++ b/src/devices/bus/imi7000/imi5000h.c @@ -0,0 +1,478 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + IMI 5000H 5.25" Winchester Hard Disk Controller emulation + + Used in Corvus Systems H-Series drives (Model 6/11/20) + +**********************************************************************/ + +#include "imi5000h.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define Z80_TAG "u70" +#define Z80CTC_TAG "u45" +#define Z80PIO_0_TAG "u25" +#define Z80PIO_2_TAG "u64" +#define Z80PIO_3_TAG "u73" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type IMI5000H = &device_creator; + + +//------------------------------------------------- +// ROM( imi5000h ) +//------------------------------------------------- + +ROM_START( imi5000h ) + ROM_REGION( 0x1000, Z80_TAG, 0 ) + ROM_LOAD( "c 7.63.u62", 0x0000, 0x1000, CRC(822aac68) SHA1(ab3ad7726ab20dd1041cb754d266e2f191fa3ec3) ) + + ROM_REGION( 0x320, "proms", 0 ) + ROM_LOAD( "8152323-2a.u52", 0x000, 0x100, CRC(b36bc7e1) SHA1(de00b5bc17ff86b66af3e974dfd9b53245de12bd) ) + ROM_LOAD( "8152323-4a.u53", 0x100, 0x100, CRC(016fe2f7) SHA1(909f815a61e759fdf998674ee383512ecd8fee65) ) + ROM_LOAD( "8152323-1a.u54", 0x200, 0x100, CRC(512f1f39) SHA1(50c68289a19fdfca3665dbb0e98373608458c5d8) ) + ROM_LOAD( "8152323-3a.u71", 0x300, 0x020, CRC(b1092f02) SHA1(646c5a3e951535a80d24d9ce8764a3f373c508db) ) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *imi5000h_device::device_rom_region() const +{ + return ROM_NAME( imi5000h ); +} + + +//------------------------------------------------- +// ADDRESS_MAP( imi5000h_mem ) +//------------------------------------------------- + +static ADDRESS_MAP_START( imi5000h_mem, AS_PROGRAM, 8, imi5000h_device ) + ADDRESS_MAP_UNMAP_HIGH + AM_RANGE(0x0000, 0x0fff) AM_MIRROR(0x1000) AM_ROM AM_REGION(Z80_TAG, 0) + AM_RANGE(0x4000, 0x47ff) AM_MIRROR(0x1800) AM_RAM + AM_RANGE(0x6000, 0x63ff) AM_MIRROR(0x1c00) AM_RAM + AM_RANGE(0x8000, 0x83ff) AM_MIRROR(0x1c00) AM_RAM + AM_RANGE(0xa000, 0xa3ff) AM_MIRROR(0x1c00) AM_RAM +ADDRESS_MAP_END + + +//------------------------------------------------- +// ADDRESS_MAP( imi5000h_io ) +//------------------------------------------------- + +static ADDRESS_MAP_START( imi5000h_io, AS_IO, 8, imi5000h_device ) + ADDRESS_MAP_UNMAP_HIGH + ADDRESS_MAP_GLOBAL_MASK(0x9f) + AM_RANGE(0x00, 0x03) AM_DEVREADWRITE(Z80PIO_0_TAG, z80pio_device, read, write) + AM_RANGE(0x08, 0x0b) AM_DEVREADWRITE(Z80PIO_2_TAG, z80pio_device, read, write) + AM_RANGE(0x0c, 0x0f) AM_DEVREADWRITE(Z80PIO_3_TAG, z80pio_device, read, write) + AM_RANGE(0x10, 0x13) AM_MIRROR(0x03) // BEGRDY + AM_RANGE(0x14, 0x14) AM_MIRROR(0x03) // HSXCLR + AM_RANGE(0x18, 0x18) AM_MIRROR(0x03) // XFERSTB + AM_RANGE(0x1c, 0x1f) AM_DEVREADWRITE(Z80CTC_TAG, z80ctc_device, read, write) +ADDRESS_MAP_END + + +//------------------------------------------------- +// z80_daisy_config z80_daisy_chain +//------------------------------------------------- + +static const z80_daisy_config z80_daisy_chain[] = +{ + { Z80PIO_0_TAG }, + { Z80CTC_TAG }, + { Z80PIO_2_TAG }, + { NULL } +}; + + +//------------------------------------------------- +// Z80CTC +//------------------------------------------------- + +WRITE_LINE_MEMBER( imi5000h_device::ctc_z0_w ) +{ + m_ctc->trg1(state); +} + +WRITE_LINE_MEMBER( imi5000h_device::ctc_z1_w ) +{ + m_ctc->trg2(state); + m_ctc->trg3(state); +} + +WRITE_LINE_MEMBER( imi5000h_device::ctc_z2_w ) +{ + //m_memory_enable = state; + m_maincpu->set_input_line(INPUT_LINE_NMI, state); +} + +//------------------------------------------------- +// Z80PIO 1 +//------------------------------------------------- + +READ8_MEMBER( imi5000h_device::pio0_pa_r ) +{ + /* + + bit description + + 0 -SEEK COMPLETE + 1 -SECTOR SIZE 2 (UB4:4) + 2 -SECTOR SIZE 1 (UB4:1) + 3 -SECTOR SEL + 4 CRC ERROR + 5 WRITE FAULT + 6 -INDEX SEL + 7 + + */ + + return 0; +} + +WRITE8_MEMBER( imi5000h_device::pio0_pa_w ) +{ + /* + + bit description + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 ACTIVITY LED + + */ +} + +READ8_MEMBER( imi5000h_device::pio0_pb_r ) +{ + /* + + bit description + + 0 -READY + 1 + 2 + 3 + 4 + 5 + 6 + 7 + + */ + + return 0; +} + +WRITE8_MEMBER( imi5000h_device::pio0_pb_w ) +{ + /* + + bit description + + 0 + 1 DIRECTION IN + 2 -HSXSTB + 3 STEP + 4 HEAD SEL 2^0 + 5 HEAD SEL 2^1 + 6 HEAD SEL 2^2 + 7 REDUCE WR CURRENT + + */ +} + +//------------------------------------------------- +// Z80PIO 2 +//------------------------------------------------- + +READ8_MEMBER( imi5000h_device::pio2_pa_r ) +{ + /* + + bit description + + 0 + 1 + 2 + 3 + 4 + 5 + 6 -SYNC + 7 -DRV.ACK + + */ + + return 0; +} + +WRITE8_MEMBER( imi5000h_device::pio2_pa_w ) +{ + /* + + bit description + + 0 BUS DIR + 1 -DRV.ACK + 2 -ALT SEL + 3 -HSXFER + 4 PIO RDY + 5 -COMPL + 6 + 7 + + */ +} + +READ8_MEMBER( imi5000h_device::pio2_pb_r ) +{ + // command bus + return 0; +} + +WRITE8_MEMBER( imi5000h_device::pio2_pb_w ) +{ + // command bus +} + +//------------------------------------------------- +// Z80PIO 3 +//------------------------------------------------- + +READ8_MEMBER( imi5000h_device::pio3_pa_r ) +{ + /* + + bit description + + 0 -TIMEOUT DISABLE (UB4:8) + 1 -UNIT SELECT 1 (UB4:7) + 2 -UNIT SELECT 2 (UB4:6) + 3 SYSTEM/-DIAG (UB4:5) + 4 -RXD + 5 + 6 -TRACK 00 + 7 + + */ + + return 0; +} + +WRITE8_MEMBER( imi5000h_device::pio3_pa_w ) +{ + /* + + bit description + + 0 + 1 + 2 + 3 + 4 + 5 TXD + 6 + 7 -WRITE DISABLE + + */ +} + +READ8_MEMBER( imi5000h_device::pio3_pb_r ) +{ + /* + + bit description + + 0 + 1 + 2 6MB1 + 3 -WRITE PROTECT (W2) + 4 -FORMAT ENABLE + 5 6MB2 + 6 12MB1 + 7 12MB2 + + */ + + return 0; +} + +WRITE8_MEMBER( imi5000h_device::pio3_pb_w ) +{ + /* + + bit description + + 0 -DRV 1 SEL + 1 -DRV 2 SEL + 2 + 3 + 4 + 5 + 6 + 7 + + */ +} + +//------------------------------------------------- +// MACHINE_DRIVER( imi5000h ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( imi5000h ) + MCFG_CPU_ADD(Z80_TAG, Z80, XTAL_8MHz/2) + MCFG_CPU_CONFIG(z80_daisy_chain) + MCFG_CPU_PROGRAM_MAP(imi5000h_mem) + MCFG_CPU_IO_MAP(imi5000h_io) + + MCFG_DEVICE_ADD(Z80CTC_TAG, Z80CTC, XTAL_8MHz / 2) + MCFG_Z80CTC_INTR_CB(INPUTLINE(Z80_TAG, INPUT_LINE_IRQ0)) + MCFG_Z80CTC_ZC0_CB(WRITELINE(imi5000h_device, ctc_z0_w)) + MCFG_Z80CTC_ZC1_CB(WRITELINE(imi5000h_device, ctc_z1_w)) + MCFG_Z80CTC_ZC2_CB(WRITELINE(imi5000h_device, ctc_z2_w)) + + MCFG_DEVICE_ADD(Z80PIO_0_TAG, Z80PIO, XTAL_8MHz/2) + MCFG_Z80PIO_OUT_INT_CB(INPUTLINE(Z80_TAG, INPUT_LINE_IRQ0)) + MCFG_Z80PIO_IN_PA_CB(READ8(imi5000h_device, pio0_pa_r)) + MCFG_Z80PIO_OUT_PA_CB(WRITE8(imi5000h_device, pio0_pa_w)) + MCFG_Z80PIO_OUT_ARDY_CB(DEVWRITELINE(Z80PIO_0_TAG, z80pio_device, strobe_a)) + MCFG_Z80PIO_IN_PB_CB(READ8(imi5000h_device, pio0_pb_r)) + MCFG_Z80PIO_OUT_PB_CB(WRITE8(imi5000h_device, pio0_pb_w)) + MCFG_Z80PIO_OUT_BRDY_CB(DEVWRITELINE(Z80PIO_0_TAG, z80pio_device, strobe_b)) + + MCFG_DEVICE_ADD(Z80PIO_2_TAG, Z80PIO, XTAL_8MHz/2) + MCFG_Z80PIO_OUT_INT_CB(INPUTLINE(Z80_TAG, INPUT_LINE_IRQ0)) + MCFG_Z80PIO_IN_PA_CB(READ8(imi5000h_device, pio2_pa_r)) + MCFG_Z80PIO_OUT_PA_CB(WRITE8(imi5000h_device, pio2_pa_w)) + MCFG_Z80PIO_OUT_ARDY_CB(DEVWRITELINE(Z80PIO_2_TAG, z80pio_device, strobe_a)) + MCFG_Z80PIO_IN_PB_CB(READ8(imi5000h_device, pio2_pb_r)) + MCFG_Z80PIO_OUT_PB_CB(WRITE8(imi5000h_device, pio2_pb_w)) + + MCFG_DEVICE_ADD(Z80PIO_3_TAG, Z80PIO, XTAL_8MHz/2) + MCFG_Z80PIO_IN_PA_CB(READ8(imi5000h_device, pio3_pa_r)) + MCFG_Z80PIO_OUT_PA_CB(WRITE8(imi5000h_device, pio3_pa_w)) + MCFG_Z80PIO_OUT_ARDY_CB(DEVWRITELINE(Z80PIO_3_TAG, z80pio_device, strobe_a)) + MCFG_Z80PIO_IN_PB_CB(READ8(imi5000h_device, pio3_pb_r)) + MCFG_Z80PIO_OUT_PB_CB(WRITE8(imi5000h_device, pio3_pb_w)) + MCFG_Z80PIO_OUT_BRDY_CB(DEVWRITELINE(Z80PIO_3_TAG, z80pio_device, strobe_b)) + + //MCFG_HARDDISK_ADD("harddisk1") +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor imi5000h_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( imi5000h ); +} + + +//------------------------------------------------- +// INPUT_PORTS( imi5000h ) +//------------------------------------------------- + +static INPUT_PORTS_START( imi5000h ) + PORT_START("LSI-11") + PORT_DIPNAME( 0x01, 0x00, "LSI-11" ) + PORT_DIPSETTING( 0x01, "Normal" ) + PORT_DIPSETTING( 0x00, "LSI-11" ) // emulate DEC RL01 and RL02 + + PORT_START("MUX") + PORT_DIPNAME( 0x01, 0x00, "MUX" ) + PORT_DIPSETTING( 0x01, "Single" ) + PORT_DIPSETTING( 0x00, "Multiplexer" ) // Corvus Multiplexer Network + + PORT_START("FORMAT") + PORT_DIPNAME( 0x01, 0x00, "FORMAT" ) + PORT_DIPSETTING( 0x01, "Normal" ) // read controller firmware from cylinders 0 and 1 + PORT_DIPSETTING( 0x00, "Format" ) // drive ready after self-test, allow format + + PORT_START("RESET") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("RESET") + + PORT_START("UB4") + PORT_DIPUNKNOWN_DIPLOC( 0x01, IP_ACTIVE_LOW, "UB4:1" ) + PORT_DIPUNKNOWN_DIPLOC( 0x02, IP_ACTIVE_LOW, "UB4:2" ) + PORT_DIPUNKNOWN_DIPLOC( 0x04, IP_ACTIVE_LOW, "UB4:3" ) + PORT_DIPUNKNOWN_DIPLOC( 0x08, IP_ACTIVE_LOW, "UB4:4" ) + PORT_DIPUNKNOWN_DIPLOC( 0x10, IP_ACTIVE_LOW, "UB4:5" ) + PORT_DIPUNKNOWN_DIPLOC( 0x20, IP_ACTIVE_LOW, "UB4:6" ) + PORT_DIPUNKNOWN_DIPLOC( 0x40, IP_ACTIVE_LOW, "UB4:7" ) + PORT_DIPUNKNOWN_DIPLOC( 0x80, IP_ACTIVE_LOW, "UB4:8" ) +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor imi5000h_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( imi5000h ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// imi5000h_device - constructor +//------------------------------------------------- + +imi5000h_device::imi5000h_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, IMI5000H, "IMI 5000H", tag, owner, clock, "imi5000h", __FILE__), + device_imi7000_interface(mconfig, *this), + m_maincpu(*this, Z80_TAG), + m_ctc(*this, Z80CTC_TAG), + m_lsi11(*this, "LSI-11"), + m_mux(*this, "MUX"), + m_format(*this, "FORMAT"), + m_ub4(*this, "UB4") +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void imi5000h_device::device_start() +{ +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void imi5000h_device::device_reset() +{ + m_maincpu->reset(); + m_ctc->reset(); +} diff --git a/src/devices/bus/imi7000/imi5000h.h b/src/devices/bus/imi7000/imi5000h.h new file mode 100644 index 00000000000..2577293ae20 --- /dev/null +++ b/src/devices/bus/imi7000/imi5000h.h @@ -0,0 +1,89 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + IMI 5000H 5.25" Winchester Hard Disk Controller emulation + + Used in Corvus Systems H-Series drives (Model 6/11/20) + +**********************************************************************/ + +#pragma once + +#ifndef __IMI5000H__ +#define __IMI5000H__ + +#include "emu.h" +#include "imi7000.h" +#include "cpu/z80/z80.h" +#include "cpu/z80/z80daisy.h" +#include "machine/z80ctc.h" +#include "machine/z80pio.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> imi5000h_device + +class imi5000h_device : public device_t, + public device_imi7000_interface +{ +public: + // construction/destruction + imi5000h_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + virtual ioport_constructor device_input_ports() const; + + DECLARE_WRITE_LINE_MEMBER( ctc_z0_w ); + DECLARE_WRITE_LINE_MEMBER( ctc_z1_w ); + DECLARE_WRITE_LINE_MEMBER( ctc_z2_w ); + + DECLARE_READ8_MEMBER( pio0_pa_r ); + DECLARE_WRITE8_MEMBER( pio0_pa_w ); + DECLARE_READ8_MEMBER( pio0_pb_r ); + DECLARE_WRITE8_MEMBER( pio0_pb_w ); + + DECLARE_READ8_MEMBER( pio2_pa_r ); + DECLARE_WRITE8_MEMBER( pio2_pa_w ); + DECLARE_READ8_MEMBER( pio2_pb_r ); + DECLARE_WRITE8_MEMBER( pio2_pb_w ); + + DECLARE_READ8_MEMBER( pio3_pa_r ); + DECLARE_WRITE8_MEMBER( pio3_pa_w ); + DECLARE_READ8_MEMBER( pio3_pb_r ); + DECLARE_WRITE8_MEMBER( pio3_pb_w ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + +private: + enum + { + LED_FAULT, + LED_BUSY, + LED_READY + }; + + required_device m_maincpu; + required_device m_ctc; + required_ioport m_lsi11; + required_ioport m_mux; + required_ioport m_format; + required_ioport m_ub4; +}; + + +// device type definition +extern const device_type IMI5000H; + + + +#endif diff --git a/src/devices/bus/imi7000/imi7000.c b/src/devices/bus/imi7000/imi7000.c new file mode 100644 index 00000000000..b67c980c466 --- /dev/null +++ b/src/devices/bus/imi7000/imi7000.c @@ -0,0 +1,101 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + International Memories Incorporated IMI 7000 Series bus emulation + +**********************************************************************/ + +#include "imi7000.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define LOG 0 + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type IMI7000_BUS = &device_creator; +const device_type IMI7000_SLOT = &device_creator; + + + +//************************************************************************** +// DEVICE INTERFACE +//************************************************************************** + +//------------------------------------------------- +// device_imi7000_interface - constructor +//------------------------------------------------- + +device_imi7000_interface::device_imi7000_interface(const machine_config &mconfig, device_t &device) + : device_slot_card_interface(mconfig, device) +{ +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// imi7000_slot_device - constructor +//------------------------------------------------- + +imi7000_slot_device::imi7000_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, IMI7000_SLOT, "IMI 7000 slot", tag, owner, clock, "imi7000_slot", __FILE__), + device_slot_interface(mconfig, *this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void imi7000_slot_device::device_start() +{ +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// imi7000_bus_device - constructor +//------------------------------------------------- + +imi7000_bus_device::imi7000_bus_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, IMI7000_BUS, "IMI 7000 bus", tag, owner, clock, "imi7000", __FILE__) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void imi7000_bus_device::device_start() +{ +} + + +//------------------------------------------------- +// SLOT_INTERFACE( imi7000_devices ) +//------------------------------------------------- + +#include "imi5000h.h" + +SLOT_INTERFACE_START( imi7000_devices ) + SLOT_INTERFACE("imi5000h", IMI5000H) +SLOT_INTERFACE_END diff --git a/src/devices/bus/imi7000/imi7000.h b/src/devices/bus/imi7000/imi7000.h new file mode 100644 index 00000000000..257ad0c562c --- /dev/null +++ b/src/devices/bus/imi7000/imi7000.h @@ -0,0 +1,132 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + International Memories Incorporated IMI 7000 Series bus emulation + +********************************************************************** + + GND 1 2 GND + SPARE 3 4 SPARE + -SEL UNIT ADDR 3 5 6 -SEL UNIT ADDR 2 + +R/W DATA 7 8 -R/W DATA + -SEL UNIT ADDR 1 9 10 -SEL UNIT ADDR 0 + +SYS CLOCK 11 12 -SYS CLOCK + GND 13 14 GND + -SECTOR 15 16 -INDEX + -SEEK COMPLETE 17 18 -FAULT + -CMD STROBE 19 20 -CMD R/W + -CMD SELECT 0 21 22 -CMD SELECT 1 + SPARE 23 24 SPARE + -CMD ACK 25 26 SPARE + -CMD BUS 6 27 28 -CMD BUS 7 + -CMD BUS 4 29 30 -CMD BUS 5 + -CMD BUS 2 31 32 -CMD BUS 3 + -CMD BUS 0 33 34 -CMD BUS 1 + +**********************************************************************/ + +#pragma once + +#ifndef __IMI7000_BUS__ +#define __IMI7000_BUS__ + +#include "emu.h" + + + +//************************************************************************** +// CONSTANTS +//************************************************************************** + +#define IMI7000_BUS_TAG "imi7000" + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_IMI7000_BUS_ADD(_def_slot1, _def_slot2, _def_slot3, _def_slot4) \ + MCFG_DEVICE_ADD(IMI7000_BUS_TAG, IMI7000_BUS, 0) \ + MCFG_DEVICE_ADD(IMI7000_BUS_TAG":0", IMI7000_SLOT, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(imi7000_devices, _def_slot1, false) \ + MCFG_DEVICE_ADD(IMI7000_BUS_TAG":1", IMI7000_SLOT, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(imi7000_devices, _def_slot2, false) \ + MCFG_DEVICE_ADD(IMI7000_BUS_TAG":2", IMI7000_SLOT, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(imi7000_devices, _def_slot3, false) \ + MCFG_DEVICE_ADD(IMI7000_BUS_TAG":3", IMI7000_SLOT, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(imi7000_devices, _def_slot4, false) + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class imi7000_slot_device; +class device_imi7000_interface; + + +// ======================> imi7000_bus_device + +class imi7000_bus_device : public device_t +{ +public: + // construction/destruction + imi7000_bus_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + void add_device(imi7000_slot_device *slot, device_t *target); + +protected: + // device-level overrides + virtual void device_start(); + + imi7000_slot_device *m_unit[4]; +}; + + +// ======================> imi7000_slot_device + +class imi7000_slot_device : public device_t, + public device_slot_interface +{ +public: + // construction/destruction + imi7000_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // device-level overrides + virtual void device_start(); + + device_imi7000_interface *m_card; +}; + + +// ======================> device_imi7000_interface + +class device_imi7000_interface : public device_slot_card_interface +{ + friend class imi7000_slot_device; + +public: + // construction/destruction + device_imi7000_interface(const machine_config &mconfig, device_t &device); + virtual ~device_imi7000_interface() { } + +protected: + imi7000_slot_device *m_slot; +}; + + +// device type definition +extern const device_type IMI7000_BUS; +extern const device_type IMI7000_SLOT; + + +// slot interface +SLOT_INTERFACE_EXTERN( imi7000_devices ); + + + +#endif diff --git a/src/devices/bus/intv/ecs.c b/src/devices/bus/intv/ecs.c new file mode 100644 index 00000000000..f9d140bb62d --- /dev/null +++ b/src/devices/bus/intv/ecs.c @@ -0,0 +1,589 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + Mattel Intellivision Entertainment Computer System expansion emulation + + TODO: + - Make paged rom emulation more accurate (according to + http://spatula-city.org/~im14u2c/intv/tech/ecs.html + writes to $xa5y should be available for every x and every y, i.e. we shall + have writes to every 4K chunk of the memory map, and there shall be 16 pages + for each) + Current emulation is instead tailored around the minimal usage necessary to + make the main expansion and World Series Major League Baseball happy + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "ecs.h" + + +//------------------------------------------------- +// intv_ecs_device - constructor +//------------------------------------------------- + +const device_type INTV_ROM_ECS = &device_creator; + +intv_ecs_device::intv_ecs_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : intv_rom_device(mconfig, INTV_ROM_ECS, "Intellivision ECS Expansion", tag, owner, clock, "intv_ecs", __FILE__), + m_snd(*this, "ay8914"), + m_subslot(*this, "subslot"), + m_keybd(*this, "ROW"), + m_synth(*this, "SYNTH"), + m_cntrlsel(*this, "CNTRLSEL"), + m_options(*this, "OPTIONS"), + m_keypad(*this, "KEYPAD"), + m_disc(*this, "DISC"), + m_discx(*this, "DISCX"), + m_discy(*this, "DISCY"), + m_psg_porta(0), + m_voice_enabled(false), + m_ramd0_enabled(false), + m_ram88_enabled(false) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void intv_ecs_device::device_start() +{ + // if the ECS is mounted directly in the system, use device rom and alloc RAM + if (m_rom == NULL) + { + std::string region_tag; + m_rom = memregion(region_tag.assign(tag()).append(":ecs").c_str())->base(); + } + if (m_ram.empty()) + { + m_ram.resize(0x800); + } + + save_item(NAME(m_bank_base)); + save_item(NAME(m_psg_porta)); +} + +void intv_ecs_device::device_reset() +{ + memset(m_bank_base, 0, sizeof(m_bank_base)); +} + +void intv_ecs_device::late_subslot_setup() +{ + switch (m_subslot->get_type()) + { + case INTV_RAM: + m_ramd0_enabled = true; + break; + case INTV_GFACT: + m_ram88_enabled = true; + break; + case INTV_VOICE: + m_voice_enabled = true; + m_subslot->late_subslot_setup(); + break; + case INTV_ECS: + printf("WARNING: You cannot connect serially multiple ECS units.\n"); + printf("WARNING: Emulation will likely misbehave.\n"); + break; + case INTV_KEYCOMP: + printf("WARNING: You cannot connect the Keyboard component to the ECS unit.\n"); + printf("WARNING: Emulation will likely misbehave.\n"); + break; + } +} + +//------------------------------------------------- +// MACHINE_CONFIG_FRAGMENT( sub_slot ) +//------------------------------------------------- + +UINT8 intv_ecs_device::intv_control_r(int hand) +{ + static const UINT8 keypad_table[] = + { + 0xFF, 0x3F, 0x9F, 0x5F, 0xD7, 0xB7, 0x77, 0xDB, + 0xBB, 0x7B, 0xDD, 0xBD, 0x7D, 0xDE, 0xBE, 0x7E + }; + + static const UINT8 disc_table[] = + { + 0xF3, 0xE3, 0xE7, 0xF7, 0xF6, 0xE6, 0xEE, 0xFE, + 0xFC, 0xEC, 0xED, 0xFD, 0xF9, 0xE9, 0xEB, 0xFB + }; + + static const UINT8 discyx_table[5][5] = + { + { 0xE3, 0xF3, 0xFB, 0xEB, 0xE9 }, + { 0xE7, 0xE3, 0xFB, 0xE9, 0xF9 }, + { 0xF7, 0xF7, 0xFF, 0xFD, 0xFD }, + { 0xF6, 0xE6, 0xFE, 0xEC, 0xED }, + { 0xE6, 0xEE, 0xFE, 0xFC, 0xEC } + }; + + int x, y; + UINT8 val = 0xff; + + /* keypad */ + x = m_keypad[hand]->read(); + for (y = 0; y < 16; y++) + { + if (x & (1 << y)) + { + val &= keypad_table[y]; + } + } + + switch ((m_options->read() >> hand) & 4) + { + case 0: /* disc == digital */ + default: + + x = m_disc[hand]->read(); + for (y = 0; y < 16; y++) + { + if (x & (1 << y)) + { + val &= disc_table[y]; + } + } + break; + + case 4: /* disc == _fake_ analog */ + + x = m_discx[hand]->read(); + y = m_discy[hand]->read(); + val &= discyx_table[y / 32][x / 32]; + } + + return val; +} + +READ8_MEMBER( intv_ecs_device::ay_porta_r ) +{ + if (m_cntrlsel->read() == 0) + return intv_control_r(0); + else + return 0xff; // not sure what to return here, maybe it should be last output? +} + +READ8_MEMBER( intv_ecs_device::ay_portb_r ) +{ + switch (m_cntrlsel->read()) + { + case 0x00: // hand controller + return intv_control_r(1); + + case 0x01: // synthesizer keyboard + { + UINT8 val = 0xff; + // return correct result if more than one bit of 0xFE is set + for (int i = 0; i < 7; i++) + { + if (BIT(m_psg_porta, i)) + val &= m_synth[i]->read(); + } + return val; + } + case 0x02: // ecs keyboard + { + UINT8 val = 0xff; + // return correct result if more than one bit of 0xFE is set + for (int i = 0; i < 7; i++) + { + if (BIT(m_psg_porta, i)) + val &= m_keybd[i]->read(); + } + return val; + } + default: + return 0xff; + } +} + +WRITE8_MEMBER( intv_ecs_device::ay_porta_w ) +{ + m_psg_porta = (~data) & 0xff; +} + +static MACHINE_CONFIG_FRAGMENT( sub_slot ) + MCFG_SPEAKER_STANDARD_MONO("mono_ecs") + + MCFG_SOUND_ADD("ay8914", AY8914, XTAL_3_579545MHz/2) + MCFG_AY8910_PORT_A_READ_CB(READ8(intv_ecs_device, ay_porta_r)) + MCFG_AY8910_PORT_B_READ_CB(READ8(intv_ecs_device, ay_portb_r)) + MCFG_AY8910_PORT_A_WRITE_CB(WRITE8(intv_ecs_device, ay_porta_w)) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono_ecs", 0.33) + + MCFG_INTV_CARTRIDGE_ADD("subslot", intv_cart, NULL) +MACHINE_CONFIG_END + + +machine_config_constructor intv_ecs_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( sub_slot ); +} + + +ROM_START( ecs ) + ROM_REGION( 0x20000, "ecs", ROMREGION_ERASEFF ) + ROM_LOAD16_WORD_SWAP( "ecs_rom.20", 0x04000, 0x2000, CRC(5f9d05e5) SHA1(083a3e7405b8f8b4b8a5003ca9c31b8d824b535c)) + ROM_LOAD16_WORD_SWAP( "ecs_rom.70", 0x0e000, 0x2000, CRC(46bb1f48) SHA1(eda44a8476fdada1ae90fba0d0287611e2efa074)) + ROM_LOAD16_WORD_SWAP( "ecs_rom.e0", 0x1c000, 0x2000, CRC(c2ebcd90) SHA1(b3c14955f56c57e6f0d8fbb695771946cfcf6582)) +ROM_END + +const rom_entry *intv_ecs_device::device_rom_region() const +{ + return ROM_NAME( ecs ); +} + + +static INPUT_PORTS_START( intv_ecs_kbd ) +/* + ECS matrix scanned by setting 0xFE bits to output and reading 0xFF + ECS Keyboard Layout: + FF\FE Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0 + Bit 0 NC RTN 0 ESC P ; . (left) + Bit 1 L O 8 9 I K M , + Bit 2 J U 6 7 Y H B N + Bit 3 G T 4 5 R F C V + Bit 4 D E 2 3 W S Z X + Bit 5 A CTL (right) 1 Q (up) (down) (space) + Bit 6 SHIFT NC NC NC NC NC NC NC + + Shifted keys that differ from pc: + Key : 1 2 5 6 7 (left) (right) (up) (down) + Shift + key: = " + - / % ' ^ ? + */ + + PORT_START("ROW.0") + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("RTN") PORT_CODE(KEYCODE_ENTER) PORT_CHAR(13) PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x02) + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_0) PORT_CHAR('0') PORT_CHAR(')') PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x02) + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_ESC) PORT_CHAR(UCHAR_MAMEKEY(ESC)) PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x02) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_P) PORT_CHAR('P') PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x02) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_COLON) PORT_CHAR(';') PORT_CHAR(':') PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x02) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_STOP) PORT_CHAR('.') PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x02) + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_LEFT) PORT_CHAR(UCHAR_MAMEKEY(LEFT)) PORT_CHAR('%') PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x02) + + PORT_START("ROW.1") + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_L) PORT_CHAR('L') PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x02) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_O) PORT_CHAR('O') PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x02) + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_8) PORT_CHAR('8') PORT_CHAR('*') PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x02) + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_9) PORT_CHAR('9') PORT_CHAR('(') PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x02) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_I) PORT_CHAR('I') PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x02) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_K) PORT_CHAR('K') PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x02) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_M) PORT_CHAR('M') PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x02) + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_COMMA) PORT_CHAR(',') PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x02) + + PORT_START("ROW.2") + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_J) PORT_CHAR('J') PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x02) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_U) PORT_CHAR('U') PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x02) + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_6) PORT_CHAR('6') PORT_CHAR('-') PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x02) + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_7) PORT_CHAR('7') PORT_CHAR('/') PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x02) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_Y) PORT_CHAR('Y') PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x02) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_H) PORT_CHAR('H') PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x02) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_B) PORT_CHAR('B') PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x02) + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_N) PORT_CHAR('N') PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x02) + + PORT_START("ROW.3") + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_G) PORT_CHAR('G') PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x02) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_T) PORT_CHAR('T') PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x02) + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_4) PORT_CHAR('4') PORT_CHAR('$') PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x02) + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_5) PORT_CHAR('5') PORT_CHAR('%') PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x02) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_R) PORT_CHAR('R') PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x02) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_F) PORT_CHAR('F') PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x02) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_C) PORT_CHAR('C') PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x02) + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_V) PORT_CHAR('V') PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x02) + + PORT_START("ROW.4") + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_D) PORT_CHAR('D') PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x02) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_E) PORT_CHAR('E') PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x02) + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_2) PORT_CHAR('2') PORT_CHAR('"') PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x02) + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_3) PORT_CHAR('3') PORT_CHAR('#') PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x02) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_W) PORT_CHAR('W') PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x02) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_S) PORT_CHAR('S') PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x02) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_Z) PORT_CHAR('Z') PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x02) + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_X) PORT_CHAR('X') PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x02) + + PORT_START("ROW.5") + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_A) PORT_CHAR('A') PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x02) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("CTL") PORT_CODE(KEYCODE_RCONTROL) PORT_CODE(KEYCODE_LCONTROL) PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x02) + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_RIGHT) PORT_CHAR(UCHAR_MAMEKEY(RIGHT)) PORT_CHAR('\'') PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x02) + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_1) PORT_CHAR('1') PORT_CHAR('=') PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x02) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_Q) PORT_CHAR('Q') PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x02) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_UP) PORT_CHAR(UCHAR_MAMEKEY(UP)) PORT_CHAR('^') PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x02) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_DOWN) PORT_CHAR(UCHAR_MAMEKEY(DOWN)) PORT_CHAR('?') PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x02) + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_SPACE) PORT_CHAR(' ') PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x02) + + PORT_START("ROW.6") + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("SHIFT") PORT_CODE(KEYCODE_RSHIFT) PORT_CODE(KEYCODE_LSHIFT) PORT_CHAR(UCHAR_SHIFT_1) PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x02) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_UNUSED ) +INPUT_PORTS_END + +static INPUT_PORTS_START( intv_ecs_synth ) +/* + ECS Synthesizer Layout: + FF\FE Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0 + Bit 0 G2 Gb2 F2 E2 Eb2 D2 Db2 C2 + Bit 1 Eb3 D3 Db3 C3 B2 Bb2 A2 Ab2 + Bit 2 B3 Bb3 A3 Ab3 G3 Gb3 F3 E3 + Bit 3 G4 Gb4 F4 E4 Eb4 D4 Db4 C4 + Bit 4 Eb5 D5 Db5 C5 B4 Bb4 A4 Ab4 + Bit 5 B5 Bb5 A5 Ab5 G5 Gb5 F5 E5 + Bit 6 C6 NC NC NC NC NC NC NC + */ + PORT_START("SYNTH.0") + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("G2") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x01) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Gb2") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x01) + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("F2") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x01) + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("E2") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x01) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Eb2") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x01) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("D2") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x01) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Db2") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x01) + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("C2") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x01) + + PORT_START("SYNTH.1") + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Eb3") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x01) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("D3") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x01) + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Db3") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x01) + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("C3") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x01) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("B2") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x01) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Bb2") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x01) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("A2") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x01) + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Ab2") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x01) + + PORT_START("SYNTH.2") + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("B3") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x01) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Bb3") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x01) + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("A3") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x01) + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Ab3") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x01) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("G3") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x01) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Gb3") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x01) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("F3") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x01) + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("E3") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x01) + + PORT_START("SYNTH.3") + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("G4") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x01) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Gb4") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x01) + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("F4") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x01) + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("E4") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x01) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Eb4") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x01) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("D4") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x01) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Db4") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x01) + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("C4") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x01) + + PORT_START("SYNTH.4") + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Eb5") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x01) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("D5") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x01) + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Db5") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x01) + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("C5") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x01) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("B4") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x01) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Bb4") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x01) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("A4") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x01) + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Ab4") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x01) + + PORT_START("SYNTH.5") + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("B5") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x01) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Bb5") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x01) + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("A5") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x01) + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Ab5") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x01) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("G5") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x01) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Gb5") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x01) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("F5") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x01) + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("E5") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x01) + + PORT_START("SYNTH.6") + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("C6") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x01) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_UNUSED ) +INPUT_PORTS_END + +static INPUT_PORTS_START( intv_ecs_pads ) + // First ECS Hand Controller + PORT_START("KEYPAD.0") + PORT_BIT( 0x8000, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("P3/1") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00) + PORT_BIT( 0x4000, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("P3/2") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00) + PORT_BIT( 0x2000, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("P3/3") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00) + PORT_BIT( 0x1000, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("P3/4") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00) + PORT_BIT( 0x0800, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("P3/5") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00) + PORT_BIT( 0x0400, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("P3/6") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00) + PORT_BIT( 0x0200, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("P3/7") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00) + PORT_BIT( 0x0100, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("P3/8") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00) + PORT_BIT( 0x0080, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("P3/9") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00) + PORT_BIT( 0x0040, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("P3/Clear") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00) + PORT_BIT( 0x0020, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("P3/0") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00) + PORT_BIT( 0x0010, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("P3/Enter") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00) + PORT_BIT( 0x0008, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("P3/Upper") PORT_PLAYER(3) PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00) + PORT_BIT( 0x0004, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_NAME("P3/Lower-Left") PORT_PLAYER(3) PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00) + PORT_BIT( 0x0002, IP_ACTIVE_HIGH, IPT_BUTTON3 ) PORT_NAME("P3/Lower-Right") PORT_PLAYER(3) PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00) + PORT_BIT( 0x0001, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("DISC.0") + PORT_BIT( 0x8000, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP ) PORT_NAME("P3/Up") PORT_PLAYER(3) PORT_CONDITION("OPTIONS",0x04,EQUALS,0x00) PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00) + PORT_BIT( 0x4000, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("P3/Up-Up-Right") PORT_CONDITION("OPTIONS",0x04,EQUALS,0x00) PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00) + PORT_BIT( 0x2000, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("P3/Right") PORT_CONDITION("OPTIONS",0x04,EQUALS,0x00) PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00) + PORT_BIT( 0x1000, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("P3/Right-Up-Right") PORT_CONDITION("OPTIONS",0x04,EQUALS,0x00) PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00) + PORT_BIT( 0x0800, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT ) PORT_NAME("P3/Right") PORT_PLAYER(3) PORT_CONDITION("OPTIONS",0x04,EQUALS,0x00) PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00) + PORT_BIT( 0x0400, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("P3/Right-Down-Right") PORT_CONDITION("OPTIONS",0x04,EQUALS,0x00) PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00) + PORT_BIT( 0x0200, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("P3/Down-Right") PORT_CONDITION("OPTIONS",0x04,EQUALS,0x00) PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00) + PORT_BIT( 0x0100, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("P3/Down-Down-Right") PORT_CONDITION("OPTIONS",0x04,EQUALS,0x00) PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00) + PORT_BIT( 0x0080, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN ) PORT_NAME("P3/Down") PORT_PLAYER(3) PORT_CONDITION("OPTIONS",0x04,EQUALS,0x00) PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00) + PORT_BIT( 0x0040, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("P3/Down-Down-Left") PORT_CONDITION("OPTIONS",0x04,EQUALS,0x00) PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00) + PORT_BIT( 0x0020, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("P3/Down-Left") PORT_CONDITION("OPTIONS",0x04,EQUALS,0x00) PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00) + PORT_BIT( 0x0010, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("P3/Left-Down-Left") PORT_CONDITION("OPTIONS",0x04,EQUALS,0x00) PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00) + PORT_BIT( 0x0008, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT ) PORT_NAME("P3/Left") PORT_PLAYER(3) PORT_CONDITION("OPTIONS",0x04,EQUALS,0x00) PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00) + PORT_BIT( 0x0004, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("P3/Left-Up-Left") PORT_CONDITION("OPTIONS",0x04,EQUALS,0x00) PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00) + PORT_BIT( 0x0002, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("P3/Up-Left") PORT_CONDITION("OPTIONS",0x04,EQUALS,0x00) PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00) + PORT_BIT( 0x0001, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("P3/Up-Up-Left") PORT_CONDITION("OPTIONS",0x04,EQUALS,0x00) PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00) + + PORT_START("DISCX.0") + PORT_BIT( 0xff, 0x50, IPT_AD_STICK_X ) PORT_NAME("P3/X") PORT_MINMAX(0x00,0x9f) PORT_SENSITIVITY(100) PORT_KEYDELTA(0x50) PORT_PLAYER(3) PORT_CONDITION("OPTIONS",0x04,EQUALS,0x04) PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00) + + PORT_START("DISCY.0") + PORT_BIT( 0xff, 0x50, IPT_AD_STICK_Y ) PORT_NAME("P3/Y") PORT_MINMAX(0x00,0x9f) PORT_SENSITIVITY(100) PORT_KEYDELTA(0x50) PORT_PLAYER(3) PORT_CONDITION("OPTIONS",0x04,EQUALS,0x04) PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00) + + // Second ECS Hand Controller + PORT_START("KEYPAD.1") + PORT_BIT( 0x8000, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("P4/1") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00) + PORT_BIT( 0x4000, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("P4/2") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00) + PORT_BIT( 0x2000, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("P4/3") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00) + PORT_BIT( 0x1000, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("P4/4") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00) + PORT_BIT( 0x0800, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("P4/5") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00) + PORT_BIT( 0x0400, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("P4/6") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00) + PORT_BIT( 0x0200, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("P4/7") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00) + PORT_BIT( 0x0100, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("P4/8") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00) + PORT_BIT( 0x0080, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("P4/9") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00) + PORT_BIT( 0x0040, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("P4/Clear") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00) + PORT_BIT( 0x0020, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("P4/0") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00) + PORT_BIT( 0x0010, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("P4/Enter") PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00) + PORT_BIT( 0x0008, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("P4/Upper") PORT_PLAYER(4) PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00) + PORT_BIT( 0x0004, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_NAME("P4/Lower-Left") PORT_PLAYER(4) PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00) + PORT_BIT( 0x0002, IP_ACTIVE_HIGH, IPT_BUTTON3 ) PORT_NAME("P4/Lower-Right") PORT_PLAYER(4) PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00) + PORT_BIT( 0x0001, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("DISC.1") + PORT_BIT( 0x8000, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP ) PORT_NAME("P4/Up") PORT_PLAYER(4) PORT_CONDITION("OPTIONS",0x08,EQUALS,0x00) PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00) + PORT_BIT( 0x4000, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("P4/Up-Up-Right") PORT_CONDITION("OPTIONS",0x08,EQUALS,0x00) PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00) + PORT_BIT( 0x2000, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("P4/Up-Right") PORT_CONDITION("OPTIONS",0x08,EQUALS,0x00) PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00) + PORT_BIT( 0x1000, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("P4/Right-Up-Right") PORT_CONDITION("OPTIONS",0x08,EQUALS,0x00) PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00) + PORT_BIT( 0x0800, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT ) PORT_NAME("P4/Right") PORT_PLAYER(4) PORT_CONDITION("OPTIONS",0x08,EQUALS,0x00) PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00) + PORT_BIT( 0x0400, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("P4/Right-Down-Right") PORT_CONDITION("OPTIONS",0x08,EQUALS,0x00) PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00) + PORT_BIT( 0x0200, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("P4/Down-Right") PORT_CONDITION("OPTIONS",0x08,EQUALS,0x00) PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00) + PORT_BIT( 0x0100, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("P4/Down-Down-Right") PORT_CONDITION("OPTIONS",0x08,EQUALS,0x00) PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00) + PORT_BIT( 0x0080, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN ) PORT_NAME("P4/Down") PORT_PLAYER(4) PORT_CONDITION("OPTIONS",0x08,EQUALS,0x00) PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00) + PORT_BIT( 0x0040, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("P4/Down-Down-Left") PORT_CONDITION("OPTIONS",0x08,EQUALS,0x00) PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00) + PORT_BIT( 0x0020, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("P4/Down-Left") PORT_CONDITION("OPTIONS",0x08,EQUALS,0x00) PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00) + PORT_BIT( 0x0010, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("P4/Left-Down-Left") PORT_CONDITION("OPTIONS",0x08,EQUALS,0x00) PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00) + PORT_BIT( 0x0008, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT ) PORT_NAME("P4/Left") PORT_PLAYER(4) PORT_CONDITION("OPTIONS",0x08,EQUALS,0x00) PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00) + PORT_BIT( 0x0004, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("P4/Left-Up-Left") PORT_CONDITION("OPTIONS",0x08,EQUALS,0x00) PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00) + PORT_BIT( 0x0002, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("P4/Up-Left") PORT_CONDITION("OPTIONS",0x08,EQUALS,0x00) PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00) + PORT_BIT( 0x0001, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("P4/Up-Up-Left") PORT_CONDITION("OPTIONS",0x08,EQUALS,0x00) PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00) + + PORT_START("DISCX.1") + PORT_BIT( 0xff, 0x50, IPT_AD_STICK_X ) PORT_NAME("P4/X") PORT_MINMAX(0x00,0x9f) PORT_SENSITIVITY(100) PORT_KEYDELTA(0x50) PORT_CODE_DEC(KEYCODE_D) PORT_CODE_INC(KEYCODE_G) PORT_PLAYER(4) PORT_CONDITION("OPTIONS",0x08,EQUALS,0x08) PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00) + + PORT_START("DISCY.1") + PORT_BIT( 0xff, 0x50, IPT_AD_STICK_Y ) PORT_NAME("P4/Y") PORT_MINMAX(0x00,0x9f) PORT_SENSITIVITY(100) PORT_KEYDELTA(0x50) PORT_CODE_DEC(KEYCODE_R) PORT_CODE_INC(KEYCODE_F) PORT_PLAYER(4) PORT_CONDITION("OPTIONS",0x08,EQUALS,0x08) PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00) +INPUT_PORTS_END + +static INPUT_PORTS_START( intv_ecs ) + PORT_INCLUDE( intv_ecs_pads ) + PORT_INCLUDE( intv_ecs_synth ) + PORT_INCLUDE( intv_ecs_kbd ) + + PORT_START("OPTIONS") + PORT_CONFNAME( 0x04, 0x00, "ECS_P3 Disc" ) PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00) + PORT_CONFSETTING( 0x00, "Digital" ) + PORT_CONFSETTING( 0x04, "Analog" ) + PORT_CONFNAME( 0x08, 0x00, "ECS_P4 Disc" ) PORT_CONDITION("CNTRLSEL",0x0f,EQUALS,0x00) + PORT_CONFSETTING( 0x00, "Digital" ) + PORT_CONFSETTING( 0x08, "Analog" ) + + PORT_START("CNTRLSEL") + PORT_CONFNAME( 0x0F, 0x02, "ECS Controller") + PORT_CONFSETTING( 0x00, "Gamepads" ) + PORT_CONFSETTING( 0x01, "Piano" ) + PORT_CONFSETTING( 0x02, "Keyboard" ) +INPUT_PORTS_END + +ioport_constructor intv_ecs_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( intv_ecs ); +} + + +/*------------------------------------------------- + Paged ROM handling + -------------------------------------------------*/ + +READ16_MEMBER(intv_ecs_device::read_rom20) +{ + if (m_bank_base[2]) + return INTV_ROM16_READ(offset + 0x2000); + else + return 0xffff; +} + +READ16_MEMBER(intv_ecs_device::read_rom70) +{ + if (m_bank_base[7]) + return 0xffff; + else + return INTV_ROM16_READ(offset + 0x7000); +} + +READ16_MEMBER(intv_ecs_device::read_rome0) +{ + if (m_bank_base[14]) + return INTV_ROM16_READ(offset + 0xe000); + else // if WSMLB is loaded, it shall go here, otherwise 0xffff + return m_subslot->read_rome0(space, offset, mem_mask); +} + +READ16_MEMBER(intv_ecs_device::read_romf0) +{ + // only WSMLB should come here with bank_base = 1 + if (m_bank_base[15]) + return m_subslot->read_romf0(space, offset + 0x1000, mem_mask); + else + return m_subslot->read_romf0(space, offset, mem_mask); +} + + +/*------------------------------------------------- + read_audio + -------------------------------------------------*/ + +READ16_MEMBER(intv_ecs_device::read_ay) +{ + if (ACCESSING_BITS_0_7) + return m_snd->read(space, offset, mem_mask); + else + return 0xffff; +} + +/*------------------------------------------------- + write_audio + -------------------------------------------------*/ + +WRITE16_MEMBER(intv_ecs_device::write_ay) +{ + if (ACCESSING_BITS_0_7) + return m_snd->write(space, offset, data, mem_mask); +} diff --git a/src/devices/bus/intv/ecs.h b/src/devices/bus/intv/ecs.h new file mode 100644 index 00000000000..8148459fc22 --- /dev/null +++ b/src/devices/bus/intv/ecs.h @@ -0,0 +1,147 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __INTV_ECS_H +#define __INTV_ECS_H + +#include "slot.h" +#include "rom.h" +#include "sound/ay8910.h" + + + +// ======================> intv_ecs_device + +class intv_ecs_device : public intv_rom_device +{ +public: + // construction/destruction + intv_ecs_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual machine_config_constructor device_mconfig_additions() const; + virtual ioport_constructor device_input_ports() const; + virtual const rom_entry *device_rom_region() const; + + // reading and writing + + // actual ECS accesses + // paged ROMs + virtual DECLARE_READ16_MEMBER(read_rom20); + virtual DECLARE_READ16_MEMBER(read_rom70); + virtual DECLARE_READ16_MEMBER(read_rome0); + virtual DECLARE_READ16_MEMBER(read_romf0); + // RAM + virtual DECLARE_READ16_MEMBER(read_ram) { return (int)m_ram[offset & (m_ram.size() - 1)]; } + virtual DECLARE_WRITE16_MEMBER(write_ram) { m_ram[offset & (m_ram.size() - 1)] = data & 0xff; } + // AY8914 + virtual DECLARE_READ16_MEMBER(read_ay); + virtual DECLARE_WRITE16_MEMBER(write_ay); + DECLARE_READ8_MEMBER(ay_porta_r); + DECLARE_READ8_MEMBER(ay_portb_r); + DECLARE_WRITE8_MEMBER(ay_porta_w); + + // passthru accesses + virtual DECLARE_READ16_MEMBER(read_rom04) { return m_subslot->read_rom04(space, offset, mem_mask); } + virtual DECLARE_READ16_MEMBER(read_rom40) { return m_subslot->read_rom40(space, offset, mem_mask); } + virtual DECLARE_READ16_MEMBER(read_rom48) { return m_subslot->read_rom48(space, offset, mem_mask); } + virtual DECLARE_READ16_MEMBER(read_rom50) { return m_subslot->read_rom50(space, offset, mem_mask); } + virtual DECLARE_READ16_MEMBER(read_rom60) { return m_subslot->read_rom60(space, offset, mem_mask); } + virtual DECLARE_READ16_MEMBER(read_rom80) + { + if (m_ram88_enabled && offset >= 0x800) + return m_subslot->read_ram(space, offset & 0x7ff, mem_mask); + else + return m_subslot->read_rom80(space, offset, mem_mask); + } + virtual DECLARE_READ16_MEMBER(read_rom90) { return m_subslot->read_rom90(space, offset, mem_mask); } + virtual DECLARE_READ16_MEMBER(read_roma0) { return m_subslot->read_roma0(space, offset, mem_mask); } + virtual DECLARE_READ16_MEMBER(read_romb0) { return m_subslot->read_romb0(space, offset, mem_mask); } + virtual DECLARE_READ16_MEMBER(read_romc0) { return m_subslot->read_romc0(space, offset, mem_mask); } + virtual DECLARE_READ16_MEMBER(read_romd0) + { + if (m_ramd0_enabled && offset < 0x800) + return m_subslot->read_ram(space, offset, mem_mask); + else + return m_subslot->read_romd0(space, offset, mem_mask); + } + + // paged ROM banking + virtual DECLARE_WRITE16_MEMBER(write_rom20) + { + if (offset == 0xfff) + { + if (data == 0x2a50) + m_bank_base[2] = 0; + else if (data == 0x2a51) + m_bank_base[2] = 1; + } + } + virtual DECLARE_WRITE16_MEMBER(write_rom70) + { + if (offset == 0xfff) + { + if (data == 0x7a50) + m_bank_base[7] = 0; + else if (data == 0x7a51) + m_bank_base[7] = 1; + } + } + virtual DECLARE_WRITE16_MEMBER(write_rome0) + { + if (offset == 0xfff) + { + if (data == 0xea50) + m_bank_base[14] = 0; + else if (data == 0xea51) + m_bank_base[14] = 1; + } + } + virtual DECLARE_WRITE16_MEMBER(write_romf0) + { + if (offset == 0xfff) + { + if (data == 0xfa50) + m_bank_base[15] = 0; + else if (data == 0xfa51) + m_bank_base[15] = 1; + } + } + // RAM passthru write + virtual DECLARE_WRITE16_MEMBER(write_88) { if (m_ram88_enabled) m_subslot->write_ram(space, offset, data, mem_mask); } + virtual DECLARE_WRITE16_MEMBER(write_d0) { if (m_ramd0_enabled) m_subslot->write_ram(space, offset, data, mem_mask); } + // IntelliVoice passthru + virtual DECLARE_READ16_MEMBER(read_speech) { if (m_voice_enabled) return m_subslot->read_speech(space, offset, mem_mask); else return 0xffff; } + virtual DECLARE_WRITE16_MEMBER(write_speech) { if (m_voice_enabled) m_subslot->write_speech(space, offset, data, mem_mask); } + + virtual void late_subslot_setup(); + + UINT8 intv_control_r(int hand); + +private: + + required_device m_snd; + required_device m_subslot; + required_ioport_array<7> m_keybd; + required_ioport_array<7> m_synth; + required_ioport m_cntrlsel; + required_ioport m_options; + required_ioport_array<2> m_keypad; + required_ioport_array<2> m_disc; + required_ioport_array<2> m_discx; + required_ioport_array<2> m_discy; + + int m_bank_base[0x10]; + UINT8 m_psg_porta; + bool m_voice_enabled, m_ramd0_enabled, m_ram88_enabled; +}; + + + + + +// device type definition +extern const device_type INTV_ROM_ECS; + +#endif diff --git a/src/devices/bus/intv/rom.c b/src/devices/bus/intv/rom.c new file mode 100644 index 00000000000..74b5664a6fc --- /dev/null +++ b/src/devices/bus/intv/rom.c @@ -0,0 +1,51 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + Mattel Intellivision cart emulation + + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "rom.h" + + +//------------------------------------------------- +// intv_rom_device - constructor +//------------------------------------------------- + +const device_type INTV_ROM_STD = &device_creator; +const device_type INTV_ROM_RAM = &device_creator; +const device_type INTV_ROM_GFACT = &device_creator; +const device_type INTV_ROM_WSMLB = &device_creator; + + +intv_rom_device::intv_rom_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_intv_cart_interface( mconfig, *this ) +{ +} + +intv_rom_device::intv_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, INTV_ROM_STD, "Intellivision Standard Carts", tag, owner, clock, "intv_rom", __FILE__), + device_intv_cart_interface( mconfig, *this ) +{ +} + +intv_ram_device::intv_ram_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : intv_rom_device(mconfig, INTV_ROM_RAM, "Intellivision Carts w/RAM", tag, owner, clock, "intv_ram", __FILE__) +{ +} + +intv_gfact_device::intv_gfact_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : intv_rom_device(mconfig, INTV_ROM_GFACT, "Intellivision Game Factory Cart", tag, owner, clock, "intv_gfact", __FILE__) +{ +} + +intv_wsmlb_device::intv_wsmlb_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : intv_rom_device(mconfig, INTV_ROM_WSMLB, "Intellivision World Series Baseball Cart", tag, owner, clock, "intv_wsmlb", __FILE__) +{ +} diff --git a/src/devices/bus/intv/rom.h b/src/devices/bus/intv/rom.h new file mode 100644 index 00000000000..15a66e10817 --- /dev/null +++ b/src/devices/bus/intv/rom.h @@ -0,0 +1,84 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __INTV_ROM_H +#define __INTV_ROM_H + +#include "slot.h" + + +// ======================> intv_rom_device + +class intv_rom_device : public device_t, + public device_intv_cart_interface +{ +public: + // construction/destruction + intv_rom_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + intv_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // reading and writing + virtual DECLARE_READ16_MEMBER(read_rom04) { return INTV_ROM16_READ(offset + 0x0400); } + virtual DECLARE_READ16_MEMBER(read_rom20) { return INTV_ROM16_READ(offset + 0x2000); } + virtual DECLARE_READ16_MEMBER(read_rom40) { return INTV_ROM16_READ(offset + 0x4000); } + virtual DECLARE_READ16_MEMBER(read_rom48) { return INTV_ROM16_READ(offset + 0x4800); } + virtual DECLARE_READ16_MEMBER(read_rom50) { return INTV_ROM16_READ(offset + 0x5000); } + virtual DECLARE_READ16_MEMBER(read_rom60) { return INTV_ROM16_READ(offset + 0x6000); } + virtual DECLARE_READ16_MEMBER(read_rom70) { return INTV_ROM16_READ(offset + 0x7000); } + virtual DECLARE_READ16_MEMBER(read_rom80) { return INTV_ROM16_READ(offset + 0x8000); } + virtual DECLARE_READ16_MEMBER(read_rom90) { return INTV_ROM16_READ(offset + 0x9000); } + virtual DECLARE_READ16_MEMBER(read_roma0) { return INTV_ROM16_READ(offset + 0xa000); } + virtual DECLARE_READ16_MEMBER(read_romb0) { return INTV_ROM16_READ(offset + 0xb000); } + virtual DECLARE_READ16_MEMBER(read_romc0) { return INTV_ROM16_READ(offset + 0xc000); } + virtual DECLARE_READ16_MEMBER(read_romd0) { return INTV_ROM16_READ(offset + 0xd000); } + virtual DECLARE_READ16_MEMBER(read_rome0) { return INTV_ROM16_READ(offset + 0xe000); } + virtual DECLARE_READ16_MEMBER(read_romf0) { return INTV_ROM16_READ(offset + 0xf000); } + + // device-level overrides + virtual void device_start() {} + virtual void device_reset() {} +}; + +// ======================> intv_ram_device + +class intv_ram_device : public intv_rom_device +{ +public: + // construction/destruction + intv_ram_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // reading and writing + virtual DECLARE_READ16_MEMBER(read_ram) { return (int)m_ram[offset & (m_ram.size() - 1)]; } + virtual DECLARE_WRITE16_MEMBER(write_ram) { m_ram[offset & (m_ram.size() - 1)] = data & 0xff; } +}; + +// ======================> intv_gfact_device + +class intv_gfact_device : public intv_rom_device +{ +public: + // construction/destruction + intv_gfact_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // reading and writing + virtual DECLARE_READ16_MEMBER(read_ram) { return (int)m_ram[offset & (m_ram.size() - 1)]; } + virtual DECLARE_WRITE16_MEMBER(write_ram) { m_ram[offset & (m_ram.size() - 1)] = data & 0xff; } +}; + +// ======================> intv_wsmlb_device + +class intv_wsmlb_device : public intv_rom_device +{ +public: + // construction/destruction + intv_wsmlb_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + + +// device type definition +extern const device_type INTV_ROM_STD; +extern const device_type INTV_ROM_RAM; +extern const device_type INTV_ROM_GFACT; +extern const device_type INTV_ROM_WSMLB; + +#endif diff --git a/src/devices/bus/intv/slot.c b/src/devices/bus/intv/slot.c new file mode 100644 index 00000000000..6b48f976e7f --- /dev/null +++ b/src/devices/bus/intv/slot.c @@ -0,0 +1,571 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + Mattel Intellivision cart emulation + (through slot devices) + + + This is a strange beast, because INTV carts had potentially access to + a *LOT* of memory ranges! + Quoting Joe Zbiciak's documentation for his emu (jzIntv): + + + The Intellivision leaves many addresses available to cartridges. However, + several address ranges come with caveats, such as interactions with other + devices in the system, or incompatibilities with various peripherals. + + Below is a summary. + + ADDRESSES NOTES + -------------- -------------------------------------------------------------- + $0400 - $04FF RAM/ROM ok on all but Intellivision 2. + $0500 - $06FF RAM/ROM ok. + $0700 - $0CFF RAM/ROM ok if no Intellivoice. + $0D00 - $0FFF RAM/ROM ok. + $2000 - $2FFF RAM/ROM ok if no ECS. + $4000 - $47FF RAM/ROM ok if no ECS. + $4800 ROM ok. RAM ok only if boot ROM at $7000. + $4801 - $4FFF RAM/ROM ok. + $5000 - $5014 ROM ok. RAM ok only if boot ROM at $7000 or $4800. + $5015 - $6FFF RAM/ROM ok. + $7000 ROM ok if no ECS. RAM at $7000 confuses EXEC boot sequence. + $7001 - $77FF RAM/ROM ok if no ECS. + $7800 - $7FFF ROM ok if no ECS. Do not map RAM here due to GRAM alias. + $8000 - $8FFF RAM/ROM ok. Avoid STIC alias at $8000 - $803F. + $9000 - $B7FF RAM/ROM ok. + $B800 - $BFFF ROM ok. Do not map RAM here due to GRAM alias. + $C000 - $CFFF RAM/ROM ok. Avoid STIC alias at $C000 - $C03F. + $D000 - $DFFF RAM/ROM ok. + $E000 - $EFFF RAM/ROM ok if no ECS. + $F000 - $F7FF RAM/ROM ok. + $F800 - $FFFF ROM ok. Do not map RAM here due to GRAM alias. + + + We handle this, by always creating a 0x10000 wide ROM region to load the + cart image and exposing the following (long list of) read handlers: + read_rom04 + read_rom20 + read_rom40 + read_rom48 + read_rom50 + read_rom60 + read_rom70 + read_rom80 + read_rom90 + read_roma0 + read_romb0 + read_romc0 + read_romd0 + read_rome0 + read_romf0 + Each pcb types will then use the correct ones for its wiring setup. + + The BIN+CFG format introduced by INTVPC emulator includes metadata about where to + load ROM into memory in the CFG file, but we don't support it (because we don't parse + the CFG at all) and we rely instead on the intv.hsi metadata for fullpath loading of + these. + Alternatively, we support the .ROM format used by jzIntv. + + + TODO: + - Convert also the keyboard component to be a passthru slot device + - Merge some of the ROM accessor above, once it is clear which ones can be merged + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "slot.h" +#include "hashfile.h" + +#define INTELLIVOICE_MASK 0x02 +#define ECS_MASK 0x01 + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type INTV_CART_SLOT = &device_creator; + +//************************************************************************** +// Intellivision Cartridges Interface +//************************************************************************** + +//------------------------------------------------- +// device_intv_cart_interface - constructor +//------------------------------------------------- + +device_intv_cart_interface::device_intv_cart_interface(const machine_config &mconfig, device_t &device) + : device_slot_card_interface(mconfig, device), + m_rom(NULL), + m_rom_size(0) +{ +} + + +//------------------------------------------------- +// ~device_intv_cart_interface - destructor +//------------------------------------------------- + +device_intv_cart_interface::~device_intv_cart_interface() +{ +} + +//------------------------------------------------- +// rom_alloc - alloc the space for the cart +//------------------------------------------------- + +void device_intv_cart_interface::rom_alloc(UINT32 size, const char *tag) +{ + if (m_rom == NULL) + { + m_rom = device().machine().memory().region_alloc(std::string(tag).append(INTVSLOT_ROM_REGION_TAG).c_str(), size, 1, ENDIANNESS_LITTLE)->base(); + memset(m_rom, 0xff, size); + m_rom_size = size; + } +} + + +//------------------------------------------------- +// ram_alloc - alloc the space for the ram +//------------------------------------------------- + +void device_intv_cart_interface::ram_alloc(UINT32 size) +{ + m_ram.resize(size); +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// intv_cart_slot_device - constructor +//------------------------------------------------- +intv_cart_slot_device::intv_cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, INTV_CART_SLOT, "Intellivision Cartridge Slot", tag, owner, clock, "intv_cart_slot", __FILE__), + device_image_interface(mconfig, *this), + device_slot_interface(mconfig, *this), + m_type(INTV_STD) +{ +} + + +//------------------------------------------------- +// intv_cart_slot_device - destructor +//------------------------------------------------- + +intv_cart_slot_device::~intv_cart_slot_device() +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void intv_cart_slot_device::device_start() +{ + m_cart = dynamic_cast(get_card_device()); +} + +//------------------------------------------------- +// device_config_complete - perform any +// operations now that the configuration is +// complete +//------------------------------------------------- + +void intv_cart_slot_device::device_config_complete() +{ + // set brief and instance name + update_names(); +} + + +//------------------------------------------------- +// INTV PCB +//------------------------------------------------- + +struct intv_slot +{ + int pcb_id; + const char *slot_option; +}; + +// Here, we take the feature attribute from .xml (i.e. the PCB name) and we assign a unique ID to it +static const intv_slot slot_list[] = +{ + { INTV_STD, "intv_rom" }, + { INTV_RAM, "intv_ram" }, + { INTV_GFACT, "intv_gfact" }, + { INTV_WSMLB, "intv_wsmlb" }, + { INTV_VOICE, "intv_voice" }, + { INTV_ECS, "intv_ecs" }, + { INTV_KEYCOMP, "intv_keycomp" } +}; + +static int intv_get_pcb_id(const char *slot) +{ + for (int i = 0; i < ARRAY_LENGTH(slot_list); i++) + { + if (!core_stricmp(slot_list[i].slot_option, slot)) + return slot_list[i].pcb_id; + } + + return 0; +} + +#if 1 +static const char *intv_get_slot(int type) +{ + for (int i = 0; i < ARRAY_LENGTH(slot_list); i++) + { + if (slot_list[i].pcb_id == type) + return slot_list[i].slot_option; + } + + return "intv_rom"; +} +#endif + +/*------------------------------------------------- + call load + -------------------------------------------------*/ + +int intv_cart_slot_device::load_fullpath() +{ + UINT8 temp; + UINT8 num_segments; + UINT8 start_seg; + UINT8 end_seg; + + UINT32 current_address; + UINT32 end_address; + + UINT8 high_byte; + UINT8 low_byte; + + UINT8 *ROM; + const char *file_type = filetype(); + + /* if it is in .rom format, we enter here */ + if (!core_stricmp (file_type, "rom")) + { + // header + fread(&temp, 1); + if (temp != 0xa8) + return IMAGE_INIT_FAIL; + + fread(&num_segments, 1); + + fread(&temp, 1); + if (temp != (num_segments ^ 0xff)) + return IMAGE_INIT_FAIL; + + m_cart->rom_alloc(0x20000, tag()); + ROM = (UINT8 *)m_cart->get_rom_base(); + + for (int i = 0; i < num_segments; i++) + { + fread(&start_seg, 1); + current_address = start_seg * 0x100; + + fread(&end_seg, 1); + end_address = end_seg * 0x100 + 0xff; + + while (current_address <= end_address) + { + fread(&low_byte, 1); + ROM[(current_address << 1) + 1] = low_byte; + fread(&high_byte, 1); + ROM[current_address << 1] = high_byte; + current_address++; + } + + // Here we should calculate and compare the CRC16... + fread(&temp, 1); + fread(&temp, 1); + } + + // Access tables and fine address restriction tables are not supported ATM + for (int i = 0; i < (16 + 32 + 2); i++) + { + fread(&temp, 1); + } + return IMAGE_INIT_PASS; + } + /* otherwise, we load it as a .bin file, using extrainfo from intv.hsi in place of .cfg */ + else + { + // This code is a blatant hack, due to impossibility to load a separate .cfg file in MESS. + // It shall be eventually replaced by the .xml loading + + // extrainfo format + // 1. mapper number (to deal with bankswitch). no bankswitch is mapper 0 (most games). + // 2.->5. current images have at most 4 chunks of data. we store here block size and location to load + // (value & 0xf0) >> 4 is the location / 0x1000 + // (value & 0x0f) is the size / 0x800 + // 6. some images have a ram chunk. as above we store location and size in 8 bits + // 7. extra = 1 ECS, 2 Intellivoice + int start, size; + int mapper, rom[5], ram, extra; + std::string extrainfo; + + m_cart->rom_alloc(0x20000, tag()); + ROM = (UINT8 *)m_cart->get_rom_base(); + + if (!hashfile_extrainfo(*this, extrainfo)) + { + // If no extrainfo, we assume a single 0x2000 chunk at 0x5000 + for (int i = 0; i < 0x2000; i++ ) + { + fread(&low_byte, 1); + ROM[((0x5000 + i) << 1) + 1] = low_byte; + fread(&high_byte, 1); + ROM[(0x5000 + i) << 1] = high_byte; + } + } + else + { + sscanf(extrainfo.c_str() ,"%d %d %d %d %d %d %d", &mapper, &rom[0], &rom[1], &rom[2], + &rom[3], &ram, &extra); + //printf("extrainfo: %d %d %d %d %d %d %d \n", mapper, rom[0], rom[1], rom[2], rom[3], ram, extra); + + if (mapper) + logerror("Bankswitch not yet implemented!\n"); + + if (ram) + { + start = ((ram & 0xf0) >> 4) * 0x1000; + size = (ram & 0x0f) * 0x800; + + if (start == 0xd000 && size == 0x800) + { + m_type = INTV_RAM; + m_cart->ram_alloc(0x800); + } + else if (start == 0x8800 && size == 0x800) + { + m_type = INTV_GFACT; + m_cart->ram_alloc(0x800); + } + else + printf("Unrecognized RAM setup [Start 0x%X - End 0x%X]. Please contact MESSdevs.\n", start, start + size); + } + if (extra & INTELLIVOICE_MASK) + { + printf("WARNING: This game requires emulation of the IntelliVoice module.\n"); + } + + if (extra & ECS_MASK) + { + printf("WARNING: This game requires emulation of the ECS module.\n"); + } + + for (int j = 0; j < 4; j++) + { + start = ((rom[j] & 0xf0) >> 4) * 0x1000; + size = (rom[j] & 0x0f) * 0x800; + + // some cart has to be loaded to 0x4800, but none of the available ones goes to 0x4000. + // Hence, we use 0x04 << 4 in extrainfo (to reduce the stored values) and fix the value here. + if (start == 0x4000) start += 0x800; + +// logerror("step %d: %d %d \n", j, start / 0x1000, size / 0x1000); + + for (int i = 0; i < size; i++) + { + fread(&low_byte, 1); + ROM[((start + i) << 1) + 1] = low_byte; + fread(&high_byte, 1); + ROM[(start + i) << 1] = high_byte; + } + } + } + + return IMAGE_INIT_PASS; + } +} + +bool intv_cart_slot_device::call_load() +{ + if (m_cart) + { + if (software_entry() == NULL) + return load_fullpath(); + else + { + UINT16 offset[] = { 0x400, 0x2000, 0x4000, 0x4800, 0x5000, 0x6000, 0x7000, 0x8000, 0x9000, 0xa000, 0xb000, 0xc000, 0xd000, 0xe000, 0xf000}; + const char* region_name[] = {"0400", "2000", "4000", "4800", "5000", "6000", "7000", "8000", "9000", "A000", "B000", "C000", "D000", "E000", "F000"}; + const char *pcb_name = get_feature("slot"); + bool extra_bank = false; + + if (pcb_name) + m_type = intv_get_pcb_id(pcb_name); + + // these two carts have paged roms, which does not work well with our 0x10000 rom region + // so if we are loading one of these, we allocate additional 0x2000 bytes for the paged bank + if (m_type == INTV_WSMLB) + extra_bank = true; + + UINT32 size = 0; + UINT16 address = 0; + UINT8 *ROM, *region; + + m_cart->rom_alloc(extra_bank ? 0x22000 : 0x20000, tag()); + ROM = m_cart->get_rom_base(); + + for (int i = 0; i < 15; i++) + { + address = offset[i]; + size = get_software_region_length(region_name[i]); + if (size) + { + region = get_software_region(region_name[i]); + + for (int j = 0; j < size / 2; j++) + { + ROM[((address + j) << 1) + 1] = region[2 * j]; + ROM[(address + j) << 1] = region[2 * j + 1]; + } + } + } + + if (m_type == INTV_RAM || m_type == INTV_GFACT || m_type == INTV_ECS) + m_cart->ram_alloc(get_software_region_length("ram")); + + //printf("Type: %s\n", intv_get_slot(m_type)); + return IMAGE_INIT_PASS; + } + } + + return IMAGE_INIT_PASS; +} + + +/*------------------------------------------------- + call softlist load + -------------------------------------------------*/ + +bool intv_cart_slot_device::call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry) +{ + load_software_part_region(*this, swlist, swname, start_entry); + return TRUE; +} + + +/*------------------------------------------------- + get default card software + -------------------------------------------------*/ + +void intv_cart_slot_device::get_default_card_software(std::string &result) +{ + if (open_image_file(mconfig().options())) + { + const char *slot_string = "intv_rom"; + UINT32 len = core_fsize(m_file); + dynamic_buffer rom(len); + int type = INTV_STD; + + core_fread(m_file, &rom[0], len); + + if (rom[0] == 0xa8 && (rom[1] == (rom[2] ^ 0xff))) + { + // it's .ROM file, so that we don't have currently any way to distinguish RAM-equipped carts + } + else + { + // assume it's .BIN and try to use .hsi file to determine type (just RAM) + int start; + int mapper, rom[5], ram, extra; + std::string extrainfo; + + if (hashfile_extrainfo(*this, extrainfo)) + { + sscanf(extrainfo.c_str() ,"%d %d %d %d %d %d %d", &mapper, &rom[0], &rom[1], &rom[2], + &rom[3], &ram, &extra); + + if (ram) + { + start = ((ram & 0xf0) >> 4) * 0x1000; + if (start == 0xd000) + type = INTV_RAM; + if (start == 0x8800) + type = INTV_GFACT; + } + } + + } + + slot_string = intv_get_slot(type); + + //printf("type: %s\n", slot_string); + clear(); + + result.assign(slot_string); + return; + } + software_get_default_slot(result, "intv_rom"); +} + +/*------------------------------------------------- + read_ay + -------------------------------------------------*/ + +READ16_MEMBER(intv_cart_slot_device::read_ay) +{ + if (m_cart) + return m_cart->read_ay(space, offset, mem_mask); + else + return 0xffff; +} + +/*------------------------------------------------- + write_ay + -------------------------------------------------*/ + +WRITE16_MEMBER(intv_cart_slot_device::write_ay) +{ + if (m_cart) + m_cart->write_ay(space, offset, data, mem_mask); +} + +/*------------------------------------------------- + read_speech + -------------------------------------------------*/ + +READ16_MEMBER(intv_cart_slot_device::read_speech) +{ + if (m_cart) + return m_cart->read_speech(space, offset, mem_mask); + else + return 0xffff; +} + +/*------------------------------------------------- + write_speech + -------------------------------------------------*/ + +WRITE16_MEMBER(intv_cart_slot_device::write_speech) +{ + if (m_cart) + m_cart->write_speech(space, offset, data, mem_mask); +} + + + +#include "bus/intv/rom.h" +#include "bus/intv/ecs.h" +//#include "bus/intv/keycomp.h" +#include "bus/intv/voice.h" + +SLOT_INTERFACE_START(intv_cart) + SLOT_INTERFACE_INTERNAL("intv_rom", INTV_ROM_STD) + SLOT_INTERFACE_INTERNAL("intv_ram", INTV_ROM_RAM) + SLOT_INTERFACE_INTERNAL("intv_gfact", INTV_ROM_GFACT) + SLOT_INTERFACE_INTERNAL("intv_wsmlb", INTV_ROM_WSMLB) + SLOT_INTERFACE_INTERNAL("intv_voice", INTV_ROM_VOICE) + SLOT_INTERFACE_INTERNAL("intv_ecs", INTV_ROM_ECS) +// SLOT_INTERFACE_INTERNAL("intv_keycomp", INTV_ROM_KEYCOMP) +SLOT_INTERFACE_END diff --git a/src/devices/bus/intv/slot.h b/src/devices/bus/intv/slot.h new file mode 100644 index 00000000000..2b5269edb8b --- /dev/null +++ b/src/devices/bus/intv/slot.h @@ -0,0 +1,185 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __INTV_SLOT_H +#define __INTV_SLOT_H + +/*************************************************************************** + TYPE DEFINITIONS + ***************************************************************************/ + + +/* PCB */ +enum +{ + INTV_STD = 0, + INTV_RAM, + INTV_GFACT, // has RAM too but at diff offset + INTV_WSMLB, + INTV_VOICE, + INTV_ECS, + INTV_KEYCOMP +}; + + +#define INTV_ROM16_READ(addr) \ + (UINT16) (m_rom[(addr) << 1] | (m_rom[((addr) << 1) + 1] << 8)) + + +// ======================> device_intv_cart_interface + +class device_intv_cart_interface : public device_slot_card_interface +{ +public: + // construction/destruction + device_intv_cart_interface(const machine_config &mconfig, device_t &device); + virtual ~device_intv_cart_interface(); + + // reading and writing + virtual DECLARE_READ16_MEMBER(read_rom04) { return 0xffff; } + virtual DECLARE_READ16_MEMBER(read_rom20) { return 0xffff; } + virtual DECLARE_READ16_MEMBER(read_rom40) { return 0xffff; } + virtual DECLARE_READ16_MEMBER(read_rom48) { return 0xffff; } + virtual DECLARE_READ16_MEMBER(read_rom50) { return 0xffff; } + virtual DECLARE_READ16_MEMBER(read_rom60) { return 0xffff; } + virtual DECLARE_READ16_MEMBER(read_rom70) { return 0xffff; } + virtual DECLARE_READ16_MEMBER(read_rom80) { return 0xffff; } + virtual DECLARE_READ16_MEMBER(read_rom90) { return 0xffff; } + virtual DECLARE_READ16_MEMBER(read_roma0) { return 0xffff; } + virtual DECLARE_READ16_MEMBER(read_romb0) { return 0xffff; } + virtual DECLARE_READ16_MEMBER(read_romc0) { return 0xffff; } + virtual DECLARE_READ16_MEMBER(read_romd0) { return 0xffff; } + virtual DECLARE_READ16_MEMBER(read_rome0) { return 0xffff; } + virtual DECLARE_READ16_MEMBER(read_romf0) { return 0xffff; } + + virtual DECLARE_READ16_MEMBER(read_ram) { return 0xffff; } + virtual DECLARE_WRITE16_MEMBER(write_ram) {} + + // Used by IntelliVoice & ECS + virtual DECLARE_READ16_MEMBER(read_ay) { return 0xffff; } + virtual DECLARE_WRITE16_MEMBER(write_ay) {} + virtual DECLARE_READ16_MEMBER(read_speech) { return 0xffff; } + virtual DECLARE_WRITE16_MEMBER(write_speech) {} + virtual DECLARE_WRITE16_MEMBER(write_d0) {} + virtual DECLARE_WRITE16_MEMBER(write_88) {} + virtual DECLARE_WRITE16_MEMBER(write_rom20) {} + virtual DECLARE_WRITE16_MEMBER(write_rom70) {} + virtual DECLARE_WRITE16_MEMBER(write_rome0) {} + virtual DECLARE_WRITE16_MEMBER(write_romf0) {} + + void rom_alloc(UINT32 size, const char *tag); + void ram_alloc(UINT32 size); + UINT8* get_rom_base() { return m_rom; } + UINT8* get_ram_base() { return &m_ram[0]; } + UINT32 get_rom_size() { return m_rom_size; } + UINT32 get_ram_size() { return m_ram.size(); } + + void save_ram() { device().save_item(NAME(m_ram)); } + virtual void late_subslot_setup() {} + +protected: + // internal state + UINT8 *m_rom; + UINT32 m_rom_size; + dynamic_buffer m_ram; +}; + + +// ======================> intv_cart_slot_device + +class intv_cart_slot_device : public device_t, + public device_image_interface, + public device_slot_interface +{ +public: + // construction/destruction + intv_cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual ~intv_cart_slot_device(); + + // device-level overrides + virtual void device_start(); + virtual void device_config_complete(); + + // image-level overrides + virtual bool call_load(); + virtual void call_unload() {} + virtual bool call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry); + + int get_type() { return m_type; } + int load_fullpath(); + + void save_ram() { if (m_cart && m_cart->get_ram_size()) m_cart->save_ram(); } + + virtual iodevice_t image_type() const { return IO_CARTSLOT; } + virtual bool is_readable() const { return 1; } + virtual bool is_writeable() const { return 0; } + virtual bool is_creatable() const { return 0; } + virtual bool must_be_loaded() const { return 0; } + virtual bool is_reset_on_load() const { return 1; } + virtual const option_guide *create_option_guide() const { return NULL; } + virtual const char *image_interface() const { return "intv_cart"; } + virtual const char *file_extensions() const { return "bin,int,rom,itv"; } + + // slot interface overrides + virtual void get_default_card_software(std::string &result); + + // reading and writing + virtual DECLARE_READ16_MEMBER(read_rom04) { if (m_cart) return m_cart->read_rom04(space, offset, mem_mask); else return 0xffff; } + virtual DECLARE_READ16_MEMBER(read_rom20) { if (m_cart) return m_cart->read_rom20(space, offset, mem_mask); else return 0xffff; } + virtual DECLARE_READ16_MEMBER(read_rom40) { if (m_cart) return m_cart->read_rom40(space, offset, mem_mask); else return 0xffff; } + virtual DECLARE_READ16_MEMBER(read_rom48) { if (m_cart) return m_cart->read_rom48(space, offset, mem_mask); else return 0xffff; } + virtual DECLARE_READ16_MEMBER(read_rom50) { if (m_cart) return m_cart->read_rom50(space, offset, mem_mask); else return 0xffff; } + virtual DECLARE_READ16_MEMBER(read_rom60) { if (m_cart) return m_cart->read_rom60(space, offset, mem_mask); else return 0xffff; } + virtual DECLARE_READ16_MEMBER(read_rom70) { if (m_cart) return m_cart->read_rom70(space, offset, mem_mask); else return 0xffff; } + virtual DECLARE_READ16_MEMBER(read_rom80) { if (m_cart) return m_cart->read_rom80(space, offset, mem_mask); else return 0xffff; } + virtual DECLARE_READ16_MEMBER(read_rom90) { if (m_cart) return m_cart->read_rom90(space, offset, mem_mask); else return 0xffff; } + virtual DECLARE_READ16_MEMBER(read_roma0) { if (m_cart) return m_cart->read_roma0(space, offset, mem_mask); else return 0xffff; } + virtual DECLARE_READ16_MEMBER(read_romb0) { if (m_cart) return m_cart->read_romb0(space, offset, mem_mask); else return 0xffff; } + virtual DECLARE_READ16_MEMBER(read_romc0) { if (m_cart) return m_cart->read_romc0(space, offset, mem_mask); else return 0xffff; } + virtual DECLARE_READ16_MEMBER(read_romd0) { if (m_cart) return m_cart->read_romd0(space, offset, mem_mask); else return 0xffff; } + virtual DECLARE_READ16_MEMBER(read_rome0) { if (m_cart) return m_cart->read_rome0(space, offset, mem_mask); else return 0xffff; } + virtual DECLARE_READ16_MEMBER(read_romf0) { if (m_cart) return m_cart->read_romf0(space, offset, mem_mask); else return 0xffff; } + + virtual DECLARE_READ16_MEMBER(read_ay); + virtual DECLARE_WRITE16_MEMBER(write_ay); + virtual DECLARE_READ16_MEMBER(read_speech); + virtual DECLARE_WRITE16_MEMBER(write_speech); + virtual DECLARE_READ16_MEMBER(read_ram) { if (m_cart) return m_cart->read_ram(space, offset, mem_mask); else return 0xffff; } + virtual DECLARE_WRITE16_MEMBER(write_ram) { if (m_cart) m_cart->write_ram(space, offset, data, mem_mask); } + + virtual void late_subslot_setup() { if (m_cart) return m_cart->late_subslot_setup(); } + + // these RAM accessors are needed to deal with IntelliVoice and ECS mounting RAM-equipped carts + virtual DECLARE_WRITE16_MEMBER(write_d0) { if (m_cart) m_cart->write_d0(space, offset, data, mem_mask); } + virtual DECLARE_WRITE16_MEMBER(write_88) { if (m_cart) m_cart->write_88(space, offset, data, mem_mask); } + + // ECS paged roms need these + virtual DECLARE_WRITE16_MEMBER(write_rom20) { if (m_cart) m_cart->write_rom20(space, offset, data, mem_mask); } + virtual DECLARE_WRITE16_MEMBER(write_rom70) { if (m_cart) m_cart->write_rom70(space, offset, data, mem_mask); } + virtual DECLARE_WRITE16_MEMBER(write_rome0) { if (m_cart) m_cart->write_rome0(space, offset, data, mem_mask); } + virtual DECLARE_WRITE16_MEMBER(write_romf0) { if (m_cart) m_cart->write_romf0(space, offset, data, mem_mask); } + +//protected: + + int m_type; + device_intv_cart_interface* m_cart; +}; + + + +// device type definition +extern const device_type INTV_CART_SLOT; + + +/*************************************************************************** + DEVICE CONFIGURATION MACROS + ***************************************************************************/ + +#define INTVSLOT_ROM_REGION_TAG ":cart:rom" + +#define MCFG_INTV_CARTRIDGE_ADD(_tag,_slot_intf,_def_slot) \ + MCFG_DEVICE_ADD(_tag, INTV_CART_SLOT, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) + +SLOT_INTERFACE_EXTERN(intv_cart); + +#endif diff --git a/src/devices/bus/intv/voice.c b/src/devices/bus/intv/voice.c new file mode 100644 index 00000000000..2ec50862d0d --- /dev/null +++ b/src/devices/bus/intv/voice.c @@ -0,0 +1,124 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + Mattel Intellivoice cart emulation + + TODO: + - speech ROM shall be loaded from softlist + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "voice.h" + + +//------------------------------------------------- +// intv_voice_device - constructor +//------------------------------------------------- + +const device_type INTV_ROM_VOICE = &device_creator; + +intv_voice_device::intv_voice_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : intv_rom_device(mconfig, INTV_ROM_VOICE, "Intellivision Intellivoice Expansion", tag, owner, clock, "intv_voice", __FILE__), + m_speech(*this, "sp0256_speech"), + m_subslot(*this, "subslot"), + m_ramd0_enabled(false), + m_ram88_enabled(false) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void intv_voice_device::device_start() +{ +} + +void intv_voice_device::late_subslot_setup() +{ + switch (m_subslot->get_type()) + { + case INTV_RAM: + m_ramd0_enabled = true; + break; + case INTV_GFACT: + m_ram88_enabled = true; + break; + case INTV_VOICE: + printf("WARNING: You cannot connect serially multiple IntelliVoice units.\n"); + printf("WARNING: Emulation will likely misbehave.\n"); + break; + case INTV_ECS: + printf("WARNING: You cannot connect ECS to IntelliVoice in this manner.\n"); + printf("WARNING: Emulation will likely misbehave.\n"); + break; + case INTV_KEYCOMP: + printf("WARNING: You cannot connect the Keyboard component to the IntelliVoice unit.\n"); + printf("WARNING: Emulation will likely misbehave.\n"); + break; + } +} + + +//------------------------------------------------- +// MACHINE_CONFIG_FRAGMENT( intellivoice ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( intellivoice ) + MCFG_SPEAKER_STANDARD_MONO("mono_voice") + + MCFG_SOUND_ADD("sp0256_speech", SP0256, 3120000) + /* The Intellivoice uses a speaker with its own volume control so the relative volumes to use are subjective */ + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono_voice", 1.00) + + MCFG_INTV_CARTRIDGE_ADD("subslot", intv_cart, NULL) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor intv_voice_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( intellivoice ); +} + + +ROM_START( intellivoice ) + ROM_REGION( 0x10000, "sp0256_speech", 0 ) + /* SP0256-012 Speech chip w/2KiB mask rom */ + ROM_LOAD( "sp0256-012.bin", 0x1000, 0x0800, CRC(0de7579d) SHA1(618563e512ff5665183664f52270fa9606c9d289) ) +ROM_END + +const rom_entry *intv_voice_device::device_rom_region() const +{ + return ROM_NAME( intellivoice ); +} + +/*------------------------------------------------- + read_audio + -------------------------------------------------*/ + +READ16_MEMBER(intv_voice_device::read_speech) +{ + if (ACCESSING_BITS_0_7) + return m_speech->spb640_r(space, offset, mem_mask); + else + return 0xff; +} + +/*------------------------------------------------- + write_audio + -------------------------------------------------*/ + +WRITE16_MEMBER(intv_voice_device::write_speech) +{ + if (ACCESSING_BITS_0_7) + return m_speech->spb640_w(space, offset, data, mem_mask); +} diff --git a/src/devices/bus/intv/voice.h b/src/devices/bus/intv/voice.h new file mode 100644 index 00000000000..412d3de7760 --- /dev/null +++ b/src/devices/bus/intv/voice.h @@ -0,0 +1,78 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __INTV_VOICE_H +#define __INTV_VOICE_H + +#include "slot.h" +#include "rom.h" +#include "sound/sp0256.h" + + +// ======================> intv_voice_device + +class intv_voice_device : public intv_rom_device +{ +public: + // construction/destruction + intv_voice_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual machine_config_constructor device_mconfig_additions() const; + virtual const rom_entry *device_rom_region() const; + + // reading and writing + // actual IntelliVoice access + virtual DECLARE_READ16_MEMBER(read_speech); + virtual DECLARE_WRITE16_MEMBER(write_speech); + + // passthru access + virtual DECLARE_READ16_MEMBER(read_rom04) { return m_subslot->read_rom04(space, offset, mem_mask); } + virtual DECLARE_READ16_MEMBER(read_rom20) { return m_subslot->read_rom20(space, offset, mem_mask); } + virtual DECLARE_READ16_MEMBER(read_rom40) { return m_subslot->read_rom40(space, offset, mem_mask); } + virtual DECLARE_READ16_MEMBER(read_rom48) { return m_subslot->read_rom48(space, offset, mem_mask); } + virtual DECLARE_READ16_MEMBER(read_rom50) { return m_subslot->read_rom50(space, offset, mem_mask); } + virtual DECLARE_READ16_MEMBER(read_rom60) { return m_subslot->read_rom60(space, offset, mem_mask); } + virtual DECLARE_READ16_MEMBER(read_rom70) { return m_subslot->read_rom70(space, offset, mem_mask); } + virtual DECLARE_READ16_MEMBER(read_rom80) + { + if (m_ram88_enabled && offset >= 0x800) + return m_subslot->read_ram(space, offset & 0x7ff, mem_mask); + else + return m_subslot->read_rom80(space, offset, mem_mask); + } + virtual DECLARE_READ16_MEMBER(read_rom90) { return m_subslot->read_rom90(space, offset, mem_mask); } + virtual DECLARE_READ16_MEMBER(read_roma0) { return m_subslot->read_roma0(space, offset, mem_mask); } + virtual DECLARE_READ16_MEMBER(read_romb0) { return m_subslot->read_romb0(space, offset, mem_mask); } + virtual DECLARE_READ16_MEMBER(read_romc0) { return m_subslot->read_romc0(space, offset, mem_mask); } + virtual DECLARE_READ16_MEMBER(read_romd0) + { + if (m_ramd0_enabled && offset < 0x800) + return m_subslot->read_ram(space, offset, mem_mask); + else + return m_subslot->read_romd0(space, offset, mem_mask); + } + virtual DECLARE_READ16_MEMBER(read_rome0) { return m_subslot->read_rome0(space, offset, mem_mask); } + virtual DECLARE_READ16_MEMBER(read_romf0) { return m_subslot->read_romf0(space, offset, mem_mask); } + + // RAM passthru write + virtual DECLARE_WRITE16_MEMBER(write_88) { if (m_ram88_enabled) m_subslot->write_ram(space, offset, data, mem_mask); } + virtual DECLARE_WRITE16_MEMBER(write_d0) { if (m_ramd0_enabled) m_subslot->write_ram(space, offset, data, mem_mask); } + virtual DECLARE_READ16_MEMBER(read_ram) { return m_subslot->read_ram(space, offset, mem_mask); } + virtual DECLARE_WRITE16_MEMBER(write_ram) { m_subslot->write_ram(space, offset, data, mem_mask); } + + virtual void late_subslot_setup(); + +private: + required_device m_speech; + required_device m_subslot; + bool m_ramd0_enabled, m_ram88_enabled; +}; + + + + +// device type definition +extern const device_type INTV_ROM_VOICE; + +#endif diff --git a/src/devices/bus/iq151/disc2.c b/src/devices/bus/iq151/disc2.c new file mode 100644 index 00000000000..795813b30bb --- /dev/null +++ b/src/devices/bus/iq151/disc2.c @@ -0,0 +1,132 @@ +// license:BSD-3-Clause +// copyright-holders:Sandro Ronco +/*************************************************************************** + + IQ151 Disc2 cartridge emulation + +***************************************************************************/ + +#include "emu.h" +#include "disc2.h" +#include "formats/iq151_dsk.h" + + +/*************************************************************************** + IMPLEMENTATION +***************************************************************************/ + +FLOPPY_FORMATS_MEMBER( iq151_disc2_device::floppy_formats ) + FLOPPY_IQ151_FORMAT +FLOPPY_FORMATS_END + +static SLOT_INTERFACE_START( iq151_disc2_floppies ) + SLOT_INTERFACE( "8sssd", FLOPPY_8_SSSD ) +SLOT_INTERFACE_END + +static MACHINE_CONFIG_FRAGMENT( iq151_disc2 ) + MCFG_UPD765A_ADD("fdc", false, true) + MCFG_FLOPPY_DRIVE_ADD("fdc:1", iq151_disc2_floppies, "8sssd", iq151_disc2_device::floppy_formats) + MCFG_FLOPPY_DRIVE_ADD("fdc:2", iq151_disc2_floppies, "8sssd", iq151_disc2_device::floppy_formats) +MACHINE_CONFIG_END + +ROM_START( iq151_disc2 ) + ROM_REGION(0x0800, "disc2", 0) + ROM_LOAD( "iq151_disc2_12_5_1987_v4_0.rom", 0x0000, 0x0800, CRC(b189b170) SHA1(3e2ca80934177e7a32d0905f5a0ad14072f9dabf)) +ROM_END + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type IQ151_DISC2 = &device_creator; + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// iq151_disc2_device - constructor +//------------------------------------------------- + +iq151_disc2_device::iq151_disc2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, IQ151_DISC2, "IQ151 Disc2", tag, owner, clock, "iq151_disc2", __FILE__), + device_iq151cart_interface( mconfig, *this ), + m_fdc(*this, "fdc") +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void iq151_disc2_device::device_start() +{ + m_rom = (UINT8*)memregion("disc2")->base(); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void iq151_disc2_device::device_reset() +{ + m_rom_enabled = false; +} + +//------------------------------------------------- +// device_mconfig_additions +//------------------------------------------------- + +machine_config_constructor iq151_disc2_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( iq151_disc2 ); +} + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *iq151_disc2_device::device_rom_region() const +{ + return ROM_NAME( iq151_disc2 ); +} + +//------------------------------------------------- +// read +//------------------------------------------------- + +void iq151_disc2_device::read(offs_t offset, UINT8 &data) +{ + // interal ROM is mapped at 0xe000-0xe7ff + if (offset >= 0xe000 && offset < 0xe800 && m_rom_enabled) + data = m_rom[offset & 0x7ff]; +} + + +//------------------------------------------------- +// IO read +//------------------------------------------------- + +void iq151_disc2_device::io_read(offs_t offset, UINT8 &data) +{ + /* This is gross */ + address_space *space = NULL; + if (offset == 0xaa) + data = m_fdc->msr_r(*space, 0, 0xff); + else if (offset == 0xab) + data = m_fdc->fifo_r(*space, 0, 0xff); +} + +//------------------------------------------------- +// IO write +//------------------------------------------------- + +void iq151_disc2_device::io_write(offs_t offset, UINT8 data) +{ + address_space *space = NULL; + if (offset == 0xab) + m_fdc->fifo_w(*space, 0, data, 0xff); + else if (offset == 0xac) + m_rom_enabled = (data == 0x01); +} diff --git a/src/devices/bus/iq151/disc2.h b/src/devices/bus/iq151/disc2.h new file mode 100644 index 00000000000..1f35778429a --- /dev/null +++ b/src/devices/bus/iq151/disc2.h @@ -0,0 +1,53 @@ +// license:BSD-3-Clause +// copyright-holders:Sandro Ronco +#pragma once + +#ifndef __IQ151_DISC2_H__ +#define __IQ151_DISC2_H__ + +#include "emu.h" +#include "iq151.h" +#include "machine/upd765.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> iq151_disc2_device + +class iq151_disc2_device : + public device_t, + public device_iq151cart_interface +{ +public: + // construction/destruction + iq151_disc2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual const rom_entry *device_rom_region() const; + + DECLARE_FLOPPY_FORMATS( floppy_formats ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // iq151cart_interface overrides + virtual void read(offs_t offset, UINT8 &data); + virtual void io_read(offs_t offset, UINT8 &data); + virtual void io_write(offs_t offset, UINT8 data); + +private: + + required_device m_fdc; + UINT8 * m_rom; + bool m_rom_enabled; +}; + + +// device type definition +extern const device_type IQ151_DISC2; + +#endif /* __IQ151_DISC2_H__ */ diff --git a/src/devices/bus/iq151/grafik.c b/src/devices/bus/iq151/grafik.c new file mode 100644 index 00000000000..e1a9aac6254 --- /dev/null +++ b/src/devices/bus/iq151/grafik.c @@ -0,0 +1,190 @@ +// license:BSD-3-Clause +// copyright-holders:Sandro Ronco +/*************************************************************************** + + IQ151 grafik emulation + +***************************************************************************/ + +#include "emu.h" +#include "grafik.h" + +#define LOG 0 + +/*************************************************************************** + IMPLEMENTATION +***************************************************************************/ + +static MACHINE_CONFIG_FRAGMENT( iq151_grafik ) + MCFG_DEVICE_ADD("ppi8255", I8255, 0) + MCFG_I8255_OUT_PORTA_CB(WRITE8(iq151_grafik_device, x_write)) + MCFG_I8255_OUT_PORTB_CB(WRITE8(iq151_grafik_device, y_write)) + MCFG_I8255_OUT_PORTC_CB(WRITE8(iq151_grafik_device, control_w)) +MACHINE_CONFIG_END + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type IQ151_GRAFIK = &device_creator; + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// iq151_grafik_device - constructor +//------------------------------------------------- + +iq151_grafik_device::iq151_grafik_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, IQ151_GRAFIK, "IQ151 grafik", tag, owner, clock, "iq151_grafik", __FILE__), + device_iq151cart_interface( mconfig, *this ), + m_ppi8255(*this, "ppi8255") +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void iq151_grafik_device::device_start() +{ +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void iq151_grafik_device::device_reset() +{ + screen_device *screen = machine().first_screen(); + + // if required adjust screen size + if (screen->visible_area().max_x < 64*8-1) + screen->set_visible_area(0, 64*8-1, 0, 32*8-1); + + memset(m_videoram, 0x00, sizeof(m_videoram)); +} + +//------------------------------------------------- +// device_mconfig_additions +//------------------------------------------------- + +machine_config_constructor iq151_grafik_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( iq151_grafik ); +} + +//------------------------------------------------- +// I8255 port a +//------------------------------------------------- + +WRITE8_MEMBER(iq151_grafik_device::x_write) +{ + if (LOG) logerror("Grafik: set posx 0x%02x\n", data); + + m_posx = data & 0x3f; +} + +//------------------------------------------------- +// I8255 port b +//------------------------------------------------- + +WRITE8_MEMBER(iq151_grafik_device::y_write) +{ + if (LOG) logerror("Grafik: set posy 0x%02x\n", data); + + m_posy = data; +} + +//------------------------------------------------- +// I8255 port c +//------------------------------------------------- + +WRITE8_MEMBER(iq151_grafik_device::control_w) +{ + if (LOG) logerror("Grafik: control write 0x%02x\n", data); + + m_all = BIT(data, 0); + m_pen = BIT(data, 1); + m_fast = BIT(data, 2); + m_ev = BIT(data, 3); + m_ex = (data>>4) & 0x03; + m_sel = BIT(data, 7); +} + + +//------------------------------------------------- +// IO read +//------------------------------------------------- + +void iq151_grafik_device::io_read(offs_t offset, UINT8 &data) +{ + if (offset >= 0xd0 && offset < 0xd4) + { + address_space& space = machine().device("maincpu")->memory().space(AS_IO); + data = m_ppi8255->read(space, offset & 3); + } + else if (offset == 0xd4) + { + if (LOG) logerror("Grafik: vram read 0x%04x\n", m_posx + 0x40 * m_posy); + + if (m_sel) + data = m_videoram[m_posx + 0x40 * m_posy]; + } +} + +//------------------------------------------------- +// IO write +//------------------------------------------------- + +void iq151_grafik_device::io_write(offs_t offset, UINT8 data) +{ + if (offset >= 0xd0 && offset < 0xd4) + { + address_space& space = machine().device("maincpu")->memory().space(AS_IO); + m_ppi8255->write(space, offset & 3, data); + } + else if (offset == 0xd4) + { + if (m_sel) + { + if (LOG) logerror("Grafik: vram write 0x%04x 0x%02x\n", m_posx + 0x40 * m_posy, data); + + if (m_all) + { + m_videoram[m_posx + 0x40 * m_posy] = data; + } + else + { + if (m_pen) + m_videoram[m_posx + 0x40 * m_posy] &= ~(1 << (data >> 5)); + else + m_videoram[m_posx + 0x40 * m_posy] |= (1 << (data >> 5)); + } + } + } +} + + +//------------------------------------------------- +// video update +//------------------------------------------------- + +void iq151_grafik_device::video_update(bitmap_ind16 &bitmap, const rectangle &cliprect) +{ + if (m_ev) + { + for (int y = 0; y < 32*8; y++) + { + for (int x = 0; x < 64; x++) + { + for (int ra = 0; ra < 8; ra++) + { + bitmap.pix16(y, x*8 + ra) |= BIT(m_videoram[(32*8 -1 - y)*64 + x], ra); + } + } + } + } +} diff --git a/src/devices/bus/iq151/grafik.h b/src/devices/bus/iq151/grafik.h new file mode 100644 index 00000000000..c93c534e72d --- /dev/null +++ b/src/devices/bus/iq151/grafik.h @@ -0,0 +1,63 @@ +// license:BSD-3-Clause +// copyright-holders:Sandro Ronco +#pragma once + +#ifndef __IQ151_GRAFIK_H__ +#define __IQ151_GRAFIK_H__ + +#include "emu.h" +#include "iq151.h" +#include "machine/i8255.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> iq151_grafik_device + +class iq151_grafik_device : + public device_t, + public device_iq151cart_interface +{ +public: + // construction/destruction + iq151_grafik_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + + // ppi8255 callback + DECLARE_WRITE8_MEMBER(x_write); + DECLARE_WRITE8_MEMBER(y_write); + DECLARE_WRITE8_MEMBER(control_w); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // iq151cart_interface overrides + virtual void io_read(offs_t offset, UINT8 &data); + virtual void io_write(offs_t offset, UINT8 data); + virtual void video_update(bitmap_ind16 &bitmap, const rectangle &cliprect); + +private: + + required_device m_ppi8255; + + UINT8 m_posx; // horizontal position + UINT8 m_posy; // vertical position + UINT8 m_all; // 0: bit mode 1: byte mode + UINT8 m_pen; + UINT8 m_fast; + UINT8 m_ev; // enable video out + UINT8 m_ex; + UINT8 m_sel; // enable vram access + UINT8 m_videoram[0x4000]; +}; + + +// device type definition +extern const device_type IQ151_GRAFIK; + +#endif /* __IQ151_GRAFIK_H__ */ diff --git a/src/devices/bus/iq151/iq151.c b/src/devices/bus/iq151/iq151.c new file mode 100644 index 00000000000..842602aceb8 --- /dev/null +++ b/src/devices/bus/iq151/iq151.c @@ -0,0 +1,210 @@ +// license:BSD-3-Clause +// copyright-holders:Sandro Ronco +/********************************************************************* + + IQ151 cartridge slot emulation + +*********************************************************************/ + +#include "emu.h" +#include "iq151.h" +#include "emuopts.h" + +#define LOG 0 + + +/*************************************************************************** + PARAMETERS +***************************************************************************/ + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type IQ151CART_SLOT = &device_creator; + +//************************************************************************** +// IQ151 cartridge interface +//************************************************************************** + +//------------------------------------------------- +// device_iq151cart_interface - constructor +//------------------------------------------------- + +device_iq151cart_interface::device_iq151cart_interface(const machine_config &mconfig, device_t &device) + : device_slot_card_interface(mconfig, device) +{ +} + + +//------------------------------------------------- +// ~device_iq151cart_interface - destructor +//------------------------------------------------- + +device_iq151cart_interface::~device_iq151cart_interface() +{ +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// iq151cart_slot_device - constructor +//------------------------------------------------- +iq151cart_slot_device::iq151cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, IQ151CART_SLOT, "IQ151 cartridge slot", tag, owner, clock, "iq151cart_slot", __FILE__), + device_slot_interface(mconfig, *this), + device_image_interface(mconfig, *this), + m_out_irq0_cb(*this), + m_out_irq1_cb(*this), + m_out_irq2_cb(*this), + m_out_irq3_cb(*this), + m_out_irq4_cb(*this), + m_out_drq_cb(*this) +{ +} + + +//------------------------------------------------- +// iq151cart_slot_device - destructor +//------------------------------------------------- + +iq151cart_slot_device::~iq151cart_slot_device() +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void iq151cart_slot_device::device_start() +{ + m_cart = dynamic_cast(get_card_device()); + + // resolve callbacks + m_out_irq0_cb.resolve_safe(); + m_out_irq1_cb.resolve_safe(); + m_out_irq2_cb.resolve_safe(); + m_out_irq3_cb.resolve_safe(); + m_out_irq4_cb.resolve_safe(); + m_out_drq_cb.resolve_safe(); + +} + +//------------------------------------------------- +// device_config_complete - perform any +// operations now that the configuration is +// complete +//------------------------------------------------- + +void iq151cart_slot_device::device_config_complete() +{ + // set brief and instance name + update_names(); +} + + +/*------------------------------------------------- + read +-------------------------------------------------*/ + +void iq151cart_slot_device::read(offs_t offset, UINT8 &data) +{ + if (m_cart) + m_cart->read(offset, data); +} + +/*------------------------------------------------- + write +-------------------------------------------------*/ + +void iq151cart_slot_device::write(offs_t offset, UINT8 data) +{ + if (m_cart) + m_cart->write(offset, data); +} + +/*------------------------------------------------- + IO read +-------------------------------------------------*/ + +void iq151cart_slot_device::io_read(offs_t offset, UINT8 &data) +{ + if (m_cart) + m_cart->io_read(offset, data); +} + + +/*------------------------------------------------- + IO write +-------------------------------------------------*/ + +void iq151cart_slot_device::io_write(offs_t offset, UINT8 data) +{ + if (m_cart) + m_cart->io_write(offset, data); +} + + +/*------------------------------------------------- + video update +-------------------------------------------------*/ + +void iq151cart_slot_device::video_update(bitmap_ind16 &bitmap, const rectangle &cliprect) +{ + if (m_cart) + m_cart->video_update(bitmap, cliprect); +} + + +/*------------------------------------------------- + call load +-------------------------------------------------*/ + +bool iq151cart_slot_device::call_load() +{ + if (m_cart) + { + offs_t read_length = 0; + UINT8 *cart_base = m_cart->get_cart_base(); + + if (cart_base != NULL) + { + if (software_entry() == NULL) + { + read_length = length(); + fread(m_cart->get_cart_base(), read_length); + } + else + { + read_length = get_software_region_length("rom"); + memcpy(m_cart->get_cart_base(), get_software_region("rom"), read_length); + } + } + else + return IMAGE_INIT_FAIL; + } + + return IMAGE_INIT_PASS; +} + +/*------------------------------------------------- + call softlist load +-------------------------------------------------*/ + +bool iq151cart_slot_device::call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry) +{ + load_software_part_region(*this, swlist, swname, start_entry ); + return TRUE; +} + +/*------------------------------------------------- + get default card software +-------------------------------------------------*/ + +void iq151cart_slot_device::get_default_card_software(std::string &result) +{ + software_get_default_slot(result, "basic6"); +} diff --git a/src/devices/bus/iq151/iq151.h b/src/devices/bus/iq151/iq151.h new file mode 100644 index 00000000000..4b9c5db9887 --- /dev/null +++ b/src/devices/bus/iq151/iq151.h @@ -0,0 +1,155 @@ +// license:BSD-3-Clause +// copyright-holders:Sandro Ronco +/********************************************************************* + + iq151cart.h + + IQ151 cartridge slot pinout: + + +--------+ + +12V | 01 32 | IO /MW + +12V | 02 33 | IO /IOR + +5V | 03 34 | IO /IOW + +5V | 04 35 | O /NRDY + GND | 05 36 | O /HOLD + GND | 06 37 | I HLDA + A0 IO | 07 38 | O /RAM + A1 IO | 08 39 | O /INT0 + A2 IO | 09 40 | O /INT1 + A3 IO | 10 41 | O /INT2 + A4 IO | 11 42 | O /INT3 + A5 IO | 12 43 | O /INT4 + A6 IO | 13 44 | O /VID + A7 IO | 14 45 | I OSC + A8 IO | 15 46 | I TTL + A9 IO | 16 47 | O NF + A10 IO | 17 48 | N.C. + A11 IO | 18 49 | N.C. + A12 IO | 19 50 | I /INIT + A13 IO | 20 51 | IO /SS + A14 IO | 21 52 | IO /SR + A15 IO | 22 53 | N.C. + D0 IO | 23 54 | IO /ZS + D1 IO | 24 55 | IO /ZR + D2 IO | 25 56 | O /DMA + D3 IO | 26 57 | GND + D4 IO | 27 58 | GND + D5 IO | 28 59 | -5V + D6 IO | 29 60 | -5V + D7 IO | 30 61 | -12V + /MR IO | 31 62 | -12V + +--------+ + +*********************************************************************/ + +#ifndef __IQ151CART_H__ +#define __IQ151CART_H__ + +/*************************************************************************** + TYPE DEFINITIONS +***************************************************************************/ + +// ======================> device_iq151cart_interface + +class device_iq151cart_interface : public device_slot_card_interface +{ +public: + // construction/destruction + device_iq151cart_interface(const machine_config &mconfig, device_t &device); + virtual ~device_iq151cart_interface(); + + // reading and writing + virtual void read(offs_t offset, UINT8 &data) { } + virtual void write(offs_t offset, UINT8 data) { } + virtual void io_read(offs_t offset, UINT8 &data) { } + virtual void io_write(offs_t offset, UINT8 data) { } + virtual UINT8* get_cart_base() { return NULL; } + + // video update + virtual void video_update(bitmap_ind16 &bitmap, const rectangle &cliprect) { } +}; + +// ======================> iq151cart_slot_device + +class iq151cart_slot_device : public device_t, + public device_slot_interface, + public device_image_interface +{ +public: + // construction/destruction + iq151cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual ~iq151cart_slot_device(); + + template static devcb_base &set_out_irq0_callback(device_t &device, _Object object) { return downcast(device).m_out_irq0_cb.set_callback(object); } + template static devcb_base &set_out_irq1_callback(device_t &device, _Object object) { return downcast(device).m_out_irq1_cb.set_callback(object); } + template static devcb_base &set_out_irq2_callback(device_t &device, _Object object) { return downcast(device).m_out_irq2_cb.set_callback(object); } + template static devcb_base &set_out_irq3_callback(device_t &device, _Object object) { return downcast(device).m_out_irq3_cb.set_callback(object); } + template static devcb_base &set_out_irq4_callback(device_t &device, _Object object) { return downcast(device).m_out_irq4_cb.set_callback(object); } + template static devcb_base &set_out_drq_callback(device_t &device, _Object object) { return downcast(device).m_out_drq_cb.set_callback(object); } + + // device-level overrides + virtual void device_start(); + virtual void device_config_complete(); + + // image-level overrides + virtual bool call_load(); + virtual bool call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry); + + virtual iodevice_t image_type() const { return IO_CARTSLOT; } + virtual bool is_readable() const { return 1; } + virtual bool is_writeable() const { return 0; } + virtual bool is_creatable() const { return 0; } + virtual bool must_be_loaded() const { return 0; } + virtual bool is_reset_on_load() const { return 1; } + virtual const char *image_interface() const { return "iq151_cart"; } + virtual const char *file_extensions() const { return "bin,rom"; } + virtual const option_guide *create_option_guide() const { return NULL; } + + // slot interface overrides + virtual void get_default_card_software(std::string &result); + + // reading and writing + virtual void read(offs_t offset, UINT8 &data); + virtual void write(offs_t offset, UINT8 data); + virtual void io_read(offs_t offset, UINT8 &data); + virtual void io_write(offs_t offset, UINT8 data); + virtual void video_update(bitmap_ind16 &bitmap, const rectangle &cliprect); + + devcb_write_line m_out_irq0_cb; + devcb_write_line m_out_irq1_cb; + devcb_write_line m_out_irq2_cb; + devcb_write_line m_out_irq3_cb; + devcb_write_line m_out_irq4_cb; + devcb_write_line m_out_drq_cb; + + device_iq151cart_interface* m_cart; +}; + + +// device type definition +extern const device_type IQ151CART_SLOT; + + +/*************************************************************************** + DEVICE CONFIGURATION MACROS +***************************************************************************/ + +#define MCFG_IQ151CART_SLOT_OUT_IRQ0_CB(_devcb) \ + devcb = &iq151cart_slot_device::set_out_irq0_callback(*device, DEVCB_##_devcb); + +#define MCFG_IQ151CART_SLOT_OUT_IRQ1_CB(_devcb) \ + devcb = &iq151cart_slot_device::set_out_irq1_callback(*device, DEVCB_##_devcb); + +#define MCFG_IQ151CART_SLOT_OUT_IRQ2_CB(_devcb) \ + devcb = &iq151cart_slot_device::set_out_irq2_callback(*device, DEVCB_##_devcb); + +#define MCFG_IQ151CART_SLOT_OUT_IRQ3_CB(_devcb) \ + devcb = &iq151cart_slot_device::set_out_irq3_callback(*device, DEVCB_##_devcb); + +#define MCFG_IQ151CART_SLOT_OUT_IRQ4_CB(_devcb) \ + devcb = &iq151cart_slot_device::set_out_irq4_callback(*device, DEVCB_##_devcb); + +#define MCFG_IQ151CART_SLOT_OUT_DRQ_CB(_devcb) \ + devcb = &iq151cart_slot_device::set_out_drq_callback(*device, DEVCB_##_devcb); + +#endif /* __IQ151CART_H__ */ diff --git a/src/devices/bus/iq151/minigraf.c b/src/devices/bus/iq151/minigraf.c new file mode 100644 index 00000000000..1cec65a47d1 --- /dev/null +++ b/src/devices/bus/iq151/minigraf.c @@ -0,0 +1,167 @@ +// license:BSD-3-Clause +// copyright-holders:Sandro Ronco +/*************************************************************************** + + IQ151 Aritma Minigraf 0507 module emulation + +***************************************************************************/ + +#include "emu.h" +#include "minigraf.h" + +#include "emuopts.h" +#include "png.h" + +// paper is A4 (297x210mm) +#define PAPER_WIDTH (210*8) +#define PAPER_HEIGHT (297*8) + +// usable area is 187.5x262.5mm step is 0.125mm +#define PAPER_MAX_X 1500 +#define PAPER_MAX_Y 2100 + +// dump the m_paper bitmap into a png +#define DUMP_PAPER_INTO_PNG 0 + +/*************************************************************************** + IMPLEMENTATION +***************************************************************************/ + +ROM_START( iq151_minigraf ) + ROM_REGION(0x1000, "minigraf", 0) + ROM_LOAD( "minigraf_010787.rom", 0x0000, 0x0800, CRC(d854d203) SHA1(ae19c2859f8d78fda227a74ab50c6eb095d14014)) + ROM_LOAD( "minigraf_050986.rom", 0x0800, 0x0800, CRC(e0559e9e) SHA1(475d294e4976f88ad13e77a39b1c607827c791dc)) +ROM_END + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type IQ151_MINIGRAF = &device_creator; + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// iq151_minigraf_device - constructor +//------------------------------------------------- + +iq151_minigraf_device::iq151_minigraf_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, IQ151_MINIGRAF, "IQ151 Minigraf", tag, owner, clock, "iq151_minigraf", __FILE__), + device_iq151cart_interface( mconfig, *this ) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void iq151_minigraf_device::device_start() +{ + m_rom = (UINT8*)memregion("minigraf")->base(); + + // allocate a bitmap for represent the paper + m_paper = auto_bitmap_ind16_alloc(machine(), PAPER_WIDTH, PAPER_HEIGHT); + m_paper->fill(0); + + m_pen = 0; + m_posx = m_posy = 0; +} + +//------------------------------------------------- +// device_stop - clean up anything that needs to +// happen before the running_machine goes away +//------------------------------------------------- + +void iq151_minigraf_device::device_stop() +{ +#if DUMP_PAPER_INTO_PNG + emu_file file(machine().options().snapshot_directory(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS); + file_error filerr = file.open("iq151_minigraf.png"); + + if (filerr == FILERR_NONE) + { + static const rgb_t png_palette[] = { rgb_t::white, rgb_t::black }; + + // save the paper into a png + png_write_bitmap(file, NULL, *m_paper, 2, png_palette); + } +#endif +} + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *iq151_minigraf_device::device_rom_region() const +{ + return ROM_NAME( iq151_minigraf ); +} + +//------------------------------------------------- +// read +//------------------------------------------------- + +void iq151_minigraf_device::read(offs_t offset, UINT8 &data) +{ + // interal ROM is mapped at 0xc000-0xc7ff + if (offset >= 0xc000 && offset < 0xc800) + data = m_rom[offset & 0x7ff]; +} + +//------------------------------------------------- +// IO write +//------------------------------------------------- + +void iq151_minigraf_device::io_write(offs_t offset, UINT8 data) +{ + if (offset >= 0xf0 && offset < 0xf4) + { + /* + Plotter control lines + + ---- -xxx horizontal step + --xx x--- vertical step + -x-- ---- ??? + x--- ---- pen up/down + */ + + plotter_update(data); + } +} + + +//************************************************************************** +// Aritma MINIGRAF 0507 +//************************************************************************** + +inline int iq151_minigraf_device::get_direction(UINT8 old_val, UINT8 new_val) +{ + if (new_val == 0 && old_val == 7) return +1; + if (new_val == 7 && old_val == 0) return -1; + + return (new_val - old_val); +} + +void iq151_minigraf_device::plotter_update(UINT8 control) +{ + // update pen and paper positions + m_posy += get_direction(m_control & 7, control & 7); + m_posx += get_direction((m_control>>3) & 7, (control>>3) & 7); + + // bit 7 is pen up/down + m_pen = BIT(control, 7); + + // clamp within range + m_posx = MAX(m_posx, 0); + m_posx = MIN(m_posx, PAPER_MAX_X); + m_posy = MAX(m_posy, 0); + m_posy = MIN(m_posy, PAPER_MAX_Y); + + // if pen is down draws a point + if (m_pen) + m_paper->pix16(((PAPER_HEIGHT-PAPER_MAX_Y)/2) + m_posy, ((PAPER_WIDTH-PAPER_MAX_X)/2) + m_posx) = 1; + + m_control = control; +} diff --git a/src/devices/bus/iq151/minigraf.h b/src/devices/bus/iq151/minigraf.h new file mode 100644 index 00000000000..6226d0ffa2d --- /dev/null +++ b/src/devices/bus/iq151/minigraf.h @@ -0,0 +1,56 @@ +// license:BSD-3-Clause +// copyright-holders:Sandro Ronco +#pragma once + +#ifndef __IQ151_MINIGRAF_H__ +#define __IQ151_MINIGRAF_H__ + +#include "emu.h" +#include "iq151.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> iq151_minigraf_device + +class iq151_minigraf_device : + public device_t, + public device_iq151cart_interface +{ +public: + // construction/destruction + iq151_minigraf_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_stop(); + + // iq151cart_interface overrides + virtual void read(offs_t offset, UINT8 &data); + virtual void io_write(offs_t offset, UINT8 data); + + // Aritma MINIGRAF 0507 + void plotter_update(UINT8 control); + int get_direction(UINT8 old_val, UINT8 new_val); + +private: + + UINT8 * m_rom; + INT16 m_posx; + INT16 m_posy; + UINT8 m_pen; + UINT8 m_control; + + bitmap_ind16 * m_paper; +}; + + +// device type definition +extern const device_type IQ151_MINIGRAF; + +#endif /* __IQ151_MINIGRAF_H__ */ diff --git a/src/devices/bus/iq151/ms151a.c b/src/devices/bus/iq151/ms151a.c new file mode 100644 index 00000000000..67909362f8e --- /dev/null +++ b/src/devices/bus/iq151/ms151a.c @@ -0,0 +1,167 @@ +// license:BSD-3-Clause +// copyright-holders:Sandro Ronco +/*************************************************************************** + + IQ151 MS151A XY plotter module emulation + +***************************************************************************/ + +#include "emu.h" +#include "ms151a.h" + +#include "emuopts.h" +#include "png.h" + +// paper is A4 (210x297mm) +#define PAPER_WIDTH (210*10) +#define PAPER_HEIGHT (297*10) + +// usable area is 175x250mm step is 0.1mm +#define PAPER_MAX_X (175*10) +#define PAPER_MAX_Y (250*10) + +// dump the m_paper bitmap into a png +#define DUMP_PAPER_INTO_PNG 0 + +/*************************************************************************** + IMPLEMENTATION +***************************************************************************/ + +ROM_START( iq151_ms151a ) + ROM_REGION(0x0800, "ms151a", 0) + ROM_LOAD( "ms151a.rom", 0x0000, 0x0800, CRC(995c58d6) SHA1(ebdc4278cfe6d3cc7dafbaa05bc6c239e4e6c09b)) +ROM_END + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type IQ151_MS151A = &device_creator; + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// iq151_ms151a_device - constructor +//------------------------------------------------- + +iq151_ms151a_device::iq151_ms151a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, IQ151_MS151A, "IQ151 MS151A", tag, owner, clock, "iq151_ms151a", __FILE__), + device_iq151cart_interface( mconfig, *this ) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void iq151_ms151a_device::device_start() +{ + m_rom = (UINT8*)memregion("ms151a")->base(); + + // allocate a bitmap for represent the paper + m_paper = auto_bitmap_ind16_alloc(machine(), PAPER_WIDTH, PAPER_HEIGHT); + m_paper->fill(0); + + m_pen = 0; + m_posx = m_posy = 0; +} + +//------------------------------------------------- +// device_stop - clean up anything that needs to +// happen before the running_machine goes away +//------------------------------------------------- + +void iq151_ms151a_device::device_stop() +{ +#if DUMP_PAPER_INTO_PNG + emu_file file(machine().options().snapshot_directory(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS); + file_error filerr = file.open("iq151_ms151a.png"); + + if (filerr == FILERR_NONE) + { + static const rgb_t png_palette[] = { rgb_t::white, rgb_t::black }; + + // save the paper into a png + png_write_bitmap(file, NULL, *m_paper, 2, png_palette); + } +#endif +} + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *iq151_ms151a_device::device_rom_region() const +{ + return ROM_NAME( iq151_ms151a ); +} + +//------------------------------------------------- +// read +//------------------------------------------------- + +void iq151_ms151a_device::read(offs_t offset, UINT8 &data) +{ + // interal ROM is mapped at 0xc000-0xc7ff + if (offset >= 0xc000 && offset < 0xc800) + data = m_rom[offset & 0x7ff]; +} + +//------------------------------------------------- +// IO read +//------------------------------------------------- + +void iq151_ms151a_device::io_read(offs_t offset, UINT8 &data) +{ + if (offset == 0xc4) + data = plotter_status(); +} + +//------------------------------------------------- +// IO write +//------------------------------------------------- + +void iq151_ms151a_device::io_write(offs_t offset, UINT8 data) +{ + if (offset >= 0xc0 && offset <= 0xc4) + plotter_update(offset - 0xc0, data); +} + + +//************************************************************************** +// XY 4130/4131 +//************************************************************************** + +UINT8 iq151_ms151a_device::plotter_status() +{ + /* + bit 7 - plotter READY line + */ + + return 0x80; +} + +void iq151_ms151a_device::plotter_update(UINT8 offset, UINT8 data) +{ + // update pen and paper positions + switch (offset) + { + case 0: m_posy++; break; + case 1: m_posy--; break; + case 2: m_posx++; break; + case 3: m_posx--; break; + case 4: m_pen = data & 0x01; break; + } + + // clamp within range + m_posx = MAX(m_posx, 0); + m_posx = MIN(m_posx, PAPER_MAX_X); + m_posy = MAX(m_posy, 0); + m_posy = MIN(m_posy, PAPER_MAX_Y); + + // if pen is down draws a point + if (m_pen) + m_paper->pix16(((PAPER_HEIGHT-PAPER_MAX_Y)/2) + m_posy, ((PAPER_WIDTH-PAPER_MAX_X)/2) + m_posx) = 1; +} diff --git a/src/devices/bus/iq151/ms151a.h b/src/devices/bus/iq151/ms151a.h new file mode 100644 index 00000000000..cbba64981c5 --- /dev/null +++ b/src/devices/bus/iq151/ms151a.h @@ -0,0 +1,56 @@ +// license:BSD-3-Clause +// copyright-holders:Sandro Ronco +#pragma once + +#ifndef __IQ151_MS151A_H__ +#define __IQ151_MS151A_H__ + +#include "emu.h" +#include "iq151.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> iq151_ms151a_device + +class iq151_ms151a_device : + public device_t, + public device_iq151cart_interface +{ +public: + // construction/destruction + iq151_ms151a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_stop(); + + // iq151cart_interface overrides + virtual void read(offs_t offset, UINT8 &data); + virtual void io_read(offs_t offset, UINT8 &data); + virtual void io_write(offs_t offset, UINT8 data); + + // XY 4130/4131 + UINT8 plotter_status(); + void plotter_update(UINT8 offset, UINT8 data); + +private: + + UINT8 * m_rom; + INT32 m_posx; + INT32 m_posy; + UINT8 m_pen; + + bitmap_ind16 * m_paper; +}; + + +// device type definition +extern const device_type IQ151_MS151A; + +#endif /* __IQ151_MS151A_H__ */ diff --git a/src/devices/bus/iq151/rom.c b/src/devices/bus/iq151/rom.c new file mode 100644 index 00000000000..4505732486c --- /dev/null +++ b/src/devices/bus/iq151/rom.c @@ -0,0 +1,229 @@ +// license:BSD-3-Clause +// copyright-holders:Sandro Ronco +/*************************************************************************** + + IQ151 rom cartridge emulation + + Supported cart: + - BASIC6 + - BASICG + - AMOS OS (3 cart) + +***************************************************************************/ + +#include "emu.h" +#include "rom.h" + +/*************************************************************************** + IMPLEMENTATION +***************************************************************************/ + +ROM_START( iq151_rom ) + ROM_REGION(0x4000, "rom", ROMREGION_ERASEFF) +ROM_END + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type IQ151_BASIC6 = &device_creator; +const device_type IQ151_BASICG = &device_creator; +const device_type IQ151_AMOS1 = &device_creator; +const device_type IQ151_AMOS2 = &device_creator; +const device_type IQ151_AMOS3 = &device_creator; + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// iq151_rom_device - constructor +//------------------------------------------------- + +iq151_rom_device::iq151_rom_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_iq151cart_interface(mconfig, *this) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void iq151_rom_device::device_start() +{ + m_rom = (UINT8*)memregion("rom")->base(); +} + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *iq151_rom_device::device_rom_region() const +{ + return ROM_NAME( iq151_rom ); +} + +/*------------------------------------------------- + get_cart_base +-------------------------------------------------*/ + +UINT8* iq151_rom_device::get_cart_base() +{ + return m_rom; +} + + +//************************************************************************** +// BASIC6 +//************************************************************************** + +//------------------------------------------------- +// iq151_basic6_device - constructor +//------------------------------------------------- + +iq151_basic6_device::iq151_basic6_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : iq151_rom_device(mconfig, IQ151_BASIC6, "IQ151 BASIC6", tag, owner, clock, "iq151_basic6", __FILE__) +{ +} + + +//------------------------------------------------- +// read +//------------------------------------------------- + +void iq151_basic6_device::read(offs_t offset, UINT8 &data) +{ + if (offset >= 0xc800 && offset < 0xe800) + data = m_rom[offset - 0xc800]; +} + + +//************************************************************************** +// BASICG +//************************************************************************** + +//------------------------------------------------- +// iq151_basicg_device - constructor +//------------------------------------------------- + +iq151_basicg_device::iq151_basicg_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : iq151_rom_device(mconfig, IQ151_BASICG, "IQ151 BASICG", tag, owner, clock, "iq151_basicg", __FILE__) +{ +} + +/*------------------------------------------------- + read +-------------------------------------------------*/ + +void iq151_basicg_device::read(offs_t offset, UINT8 &data) +{ + if (offset >= 0xb000 && offset < 0xc000) + data = m_rom[offset & 0x0fff]; + else if (offset >= 0xc800 && offset < 0xe800) + data = m_rom[offset - 0xb800]; +} + + +//************************************************************************** +// AMOS cartridge 1 +//************************************************************************** + +//------------------------------------------------- +// iq151_amos1_device - constructor +//------------------------------------------------- + +iq151_amos1_device::iq151_amos1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : iq151_rom_device(mconfig, IQ151_AMOS1, "IQ151 AMOS cart 1", tag, owner, clock, "iq151_amos1", __FILE__), + m_active(true) +{ +} + +/*------------------------------------------------- + read +-------------------------------------------------*/ + +void iq151_amos1_device::read(offs_t offset, UINT8 &data) +{ + if (offset >= 0x8000 && offset < 0xc000 && m_active) + data = m_rom[offset & 0x3fff]; +} + +/*------------------------------------------------- + IO write +-------------------------------------------------*/ + +void iq151_amos1_device::io_write(offs_t offset, UINT8 data) +{ + if (offset >= 0xec && offset < 0xf0) + m_active = data == 0x00; +} + +//************************************************************************** +// AMOS cartridge 2 +//************************************************************************** + +//------------------------------------------------- +// iq151_amos2_device - constructor +//------------------------------------------------- + +iq151_amos2_device::iq151_amos2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : iq151_rom_device(mconfig, IQ151_AMOS2, "IQ151 AMOS cart 2", tag, owner, clock, "iq151_amos2", __FILE__), + m_active(false) +{ +} + +/*------------------------------------------------- + read +-------------------------------------------------*/ + +void iq151_amos2_device::read(offs_t offset, UINT8 &data) +{ + if (offset >= 0x8000 && offset < 0xc000 && m_active) + data = m_rom[offset & 0x3fff]; +} + +/*------------------------------------------------- + IO write +-------------------------------------------------*/ + +void iq151_amos2_device::io_write(offs_t offset, UINT8 data) +{ + if (offset >= 0xec && offset < 0xf0) + m_active = data == 0x01; +} + +//************************************************************************** +// AMOS cartridge 3 +//************************************************************************** + +//------------------------------------------------- +// iq151_amos3_device - constructor +//------------------------------------------------- + +iq151_amos3_device::iq151_amos3_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : iq151_rom_device(mconfig, IQ151_AMOS3, "IQ151 AMOS cart 3", tag, owner, clock, "iq151_amos3", __FILE__), + m_active(true) +{ +} + +/*------------------------------------------------- + read +-------------------------------------------------*/ + +void iq151_amos3_device::read(offs_t offset, UINT8 &data) +{ + if (offset >= 0x8000 && offset < 0xc000 && m_active) + data = m_rom[offset & 0x3fff]; +} + +/*------------------------------------------------- + IO write +-------------------------------------------------*/ + +void iq151_amos3_device::io_write(offs_t offset, UINT8 data) +{ + if (offset >= 0xec && offset < 0xf0) + m_active = data == 0x02; +} diff --git a/src/devices/bus/iq151/rom.h b/src/devices/bus/iq151/rom.h new file mode 100644 index 00000000000..da1f72bcec4 --- /dev/null +++ b/src/devices/bus/iq151/rom.h @@ -0,0 +1,130 @@ +// license:BSD-3-Clause +// copyright-holders:Sandro Ronco +#pragma once + +#ifndef __IQ151_ROM_H__ +#define __IQ151_ROM_H__ + +#include "emu.h" +#include "iq151.h" +#include "machine/i8255.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> iq151_rom_device + +class iq151_rom_device : + public device_t, + public device_iq151cart_interface +{ +public: + // construction/destruction + iq151_rom_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + +protected: + // device-level overrides + virtual void device_start(); + + // iq151cart_interface overrides + virtual UINT8* get_cart_base(); + + UINT8 * m_rom; +}; + + +// ======================> iq151_basic6_device + +class iq151_basic6_device : + public iq151_rom_device +{ +public: + // construction/destruction + iq151_basic6_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // iq151cart_interface overrides + virtual void read(offs_t offset, UINT8 &data); +}; + +// ======================> iq151_basicg_device + +class iq151_basicg_device : + public iq151_rom_device +{ +public: + // construction/destruction + iq151_basicg_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // iq151cart_interface overrides + virtual void read(offs_t offset, UINT8 &data); +}; + + +// ======================> iq151_amos1_device + +class iq151_amos1_device : + public iq151_rom_device +{ +public: + // construction/destruction + iq151_amos1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // iq151cart_interface overrides + virtual void read(offs_t offset, UINT8 &data); + virtual void io_write(offs_t offset, UINT8 data); + + bool m_active; +}; + + +// ======================> iq151_amos2_device + +class iq151_amos2_device : + public iq151_rom_device +{ +public: + // construction/destruction + iq151_amos2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // iq151cart_interface overrides + virtual void read(offs_t offset, UINT8 &data); + virtual void io_write(offs_t offset, UINT8 data); + + bool m_active; +}; + + +// ======================> iq151_amos3_device + +class iq151_amos3_device : + public iq151_rom_device +{ +public: + // construction/destruction + iq151_amos3_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // iq151cart_interface overrides + virtual void read(offs_t offset, UINT8 &data); + virtual void io_write(offs_t offset, UINT8 data); + + bool m_active; +}; + + +// device type definition +extern const device_type IQ151_BASIC6; +extern const device_type IQ151_BASICG; +extern const device_type IQ151_AMOS1; +extern const device_type IQ151_AMOS2; +extern const device_type IQ151_AMOS3; + +#endif /* __IQ151_ROM_H__ */ diff --git a/src/devices/bus/iq151/staper.c b/src/devices/bus/iq151/staper.c new file mode 100644 index 00000000000..49079c74b3c --- /dev/null +++ b/src/devices/bus/iq151/staper.c @@ -0,0 +1,144 @@ +// license:BSD-3-Clause +// copyright-holders:Sandro Ronco +/*************************************************************************** + + IQ151 STAPER (STAndard PERipheral) module emulation + + STAPER module includes cables for connect: + - a printer (CONSUL 2112 or 2113) + - a paper tape puncher (DT-105S) + - a paper tape reader (FS-1503) + + Currently only the printer is emulated + +***************************************************************************/ + +#include "emu.h" +#include "staper.h" + + +/*************************************************************************** + IMPLEMENTATION +***************************************************************************/ + +static MACHINE_CONFIG_FRAGMENT( iq151_staper ) + MCFG_DEVICE_ADD("ppi8255", I8255A, 0) + MCFG_I8255_IN_PORTA_CB(READ8(iq151_staper_device, ppi_porta_r)) + MCFG_I8255_OUT_PORTB_CB(WRITE8(iq151_staper_device, ppi_portb_w)) + MCFG_I8255_OUT_PORTC_CB(WRITE8(iq151_staper_device, ppi_portc_w)) + + MCFG_DEVICE_ADD("printer", PRINTER, 0) +MACHINE_CONFIG_END + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type IQ151_STAPER = &device_creator; + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// iq151_staper_device - constructor +//------------------------------------------------- + +iq151_staper_device::iq151_staper_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, IQ151_STAPER, "IQ151 STAPER", tag, owner, clock, "iq151_staper", __FILE__), + device_iq151cart_interface( mconfig, *this ), + m_ppi(*this, "ppi8255"), + m_printer(*this, "printer") +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void iq151_staper_device::device_start() +{ + m_printer_timer = timer_alloc(TIMER_PRINTER); + m_printer_timer->reset(); +} + +//------------------------------------------------- +// device_mconfig_additions +//------------------------------------------------- + +machine_config_constructor iq151_staper_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( iq151_staper ); +} + +//------------------------------------------------- +// device_timer - handler timer events +//------------------------------------------------- + +void iq151_staper_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + if (id == TIMER_PRINTER) + m_ppi->pc2_w(0); +} + + +//------------------------------------------------- +// IO read +//------------------------------------------------- + +void iq151_staper_device::io_read(offs_t offset, UINT8 &data) +{ + address_space& space = machine().device("maincpu")->memory().space(AS_IO); + + if (offset >= 0xf8 && offset < 0xfc) + data = m_ppi->read(space, offset & 0x03); +} + +//------------------------------------------------- +// IO write +//------------------------------------------------- + +void iq151_staper_device::io_write(offs_t offset, UINT8 data) +{ + address_space& space = machine().device("maincpu")->memory().space(AS_IO); + + if (offset >= 0xf8 && offset < 0xfc) + m_ppi->write(space, offset & 0x03, data); +} + + +//************************************************************************** +// I8255 interface +//************************************************************************** + +READ8_MEMBER( iq151_staper_device::ppi_porta_r ) +{ + // TODO: paper tape reader input + return 0; +} + +WRITE8_MEMBER( iq151_staper_device::ppi_portb_w ) +{ + if (m_ppi_portc & 0x80) + { + // printer out + m_printer->output(data); + + // CONSUL 2112/3 usually print 65/70 cps + m_printer_timer->adjust(attotime::from_msec(15)); + } + if (m_ppi_portc & 0x40) + { + // TODO: paper tape puncher out + } +} + +WRITE8_MEMBER( iq151_staper_device::ppi_portc_w ) +{ + /* + x--- ---- printer select + -x-- ---- punchtape select + */ + + m_ppi_portc = data; +} diff --git a/src/devices/bus/iq151/staper.h b/src/devices/bus/iq151/staper.h new file mode 100644 index 00000000000..e8aa6639d4e --- /dev/null +++ b/src/devices/bus/iq151/staper.h @@ -0,0 +1,59 @@ +// license:BSD-3-Clause +// copyright-holders:Sandro Ronco +#pragma once + +#ifndef __IQ151_STAPER_H__ +#define __IQ151_STAPER_H__ + +#include "emu.h" +#include "iq151.h" +#include "machine/i8255.h" +#include "imagedev/printer.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> iq151_staper_device + +class iq151_staper_device : + public device_t, + public device_iq151cart_interface +{ +public: + // construction/destruction + iq151_staper_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + + // i8255 callbacks + DECLARE_READ8_MEMBER( ppi_porta_r ); + DECLARE_WRITE8_MEMBER( ppi_portb_w ); + DECLARE_WRITE8_MEMBER( ppi_portc_w ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + // iq151cart_interface overrides + virtual void io_read(offs_t offset, UINT8 &data); + virtual void io_write(offs_t offset, UINT8 data); + +private: + + static const device_timer_id TIMER_PRINTER = 0; + + required_device m_ppi; + required_device m_printer; + + emu_timer* m_printer_timer; + UINT8 m_ppi_portc; +}; + + +// device type definition +extern const device_type IQ151_STAPER; + +#endif /* __IQ151_STAPER_H__ */ diff --git a/src/devices/bus/iq151/video32.c b/src/devices/bus/iq151/video32.c new file mode 100644 index 00000000000..24ee5d1438b --- /dev/null +++ b/src/devices/bus/iq151/video32.c @@ -0,0 +1,170 @@ +// license:BSD-3-Clause +// copyright-holders:Sandro Ronco +/*************************************************************************** + + IQ151 video32 cartridge emulation + +***************************************************************************/ + +#include "emu.h" +#include "video32.h" + + +/*************************************************************************** + IMPLEMENTATION +***************************************************************************/ + +ROM_START( iq151_video32 ) + ROM_REGION(0x0400, "chargen", ROMREGION_INVERT) + ROM_LOAD( "iq151_video32font.rom", 0x0000, 0x0400, CRC(395567a7) SHA1(18800543daf4daed3f048193c6ae923b4b0e87db)) + + ROM_REGION(0x0400, "videoram", ROMREGION_ERASE) +ROM_END + + +/* F4 Character Displayer */ +static const gfx_layout iq151_video32_charlayout = +{ + 8, 8, /* 8 x 8 characters */ + 128, /* 128 characters */ + 1, /* 1 bits per pixel */ + { 0 }, /* no bitplanes */ + /* x offsets */ + { 0, 1, 2, 3, 4, 5, 6, 7 }, + /* y offsets */ + { 0*8, 1*8, 2*8, 3*8, 4*8, 5*8, 6*8, 7*8 }, + 8*8 /* every char takes 8 bytes */ +}; + +static GFXDECODE_START( video32 ) +GFXDECODE_END + +static MACHINE_CONFIG_FRAGMENT( video32 ) + MCFG_GFXDECODE_ADD("gfxdecode", "^^palette", video32) +MACHINE_CONFIG_END + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type IQ151_VIDEO32 = &device_creator; + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// iq151_video32_device - constructor +//------------------------------------------------- + +iq151_video32_device::iq151_video32_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, IQ151_VIDEO32, "IQ151 video32", tag, owner, clock, "iq151_video32", __FILE__), + device_iq151cart_interface( mconfig, *this ), + m_gfxdecode(*this, "gfxdecode"), + m_palette(*this, "^^palette") +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void iq151_video32_device::device_start() +{ + m_videoram = (UINT8*)memregion("videoram")->base(); + m_chargen = (UINT8*)memregion("chargen")->base(); + + m_gfxdecode->set_gfx(0, global_alloc(gfx_element(m_palette, iq151_video32_charlayout, m_chargen, 0, 1, 0))); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void iq151_video32_device::device_reset() +{ + screen_device *screen = machine().first_screen(); + + // if required adjust screen size + if (screen->visible_area().max_x < 32*8 - 1) + screen->set_visible_area(0, 32*8-1, 0, 32*8-1); +} + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor iq151_video32_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( video32 ); +} + +//------------------------------------------------- +// device_rom_region +//------------------------------------------------- + +const rom_entry *iq151_video32_device::device_rom_region() const +{ + return ROM_NAME( iq151_video32 ); +} + +//------------------------------------------------- +// read +//------------------------------------------------- + +void iq151_video32_device::read(offs_t offset, UINT8 &data) +{ + // videoram is mapped at 0xec00-0xefff + if (offset >= 0xec00 && offset < 0xf000) + data = m_videoram[offset & 0x3ff]; +} + +//------------------------------------------------- +// write +//------------------------------------------------- + +void iq151_video32_device::write(offs_t offset, UINT8 data) +{ + if (offset >= 0xec00 && offset < 0xf000) + m_videoram[offset & 0x3ff] = data; +} + +//------------------------------------------------- +// video update +//------------------------------------------------- + +void iq151_video32_device::video_update(bitmap_ind16 &bitmap, const rectangle &cliprect) +{ + UINT16 ma = 0, sy = 0; + + for (int y = 0; y < 32; y++) + { + for (int ra = 0; ra < 8; ra++) + { + UINT16 *p = &bitmap.pix16(sy++); + + for (int x = ma; x < ma + 32; x++) + { + UINT8 chr = m_videoram[x] & 0x7f; // rom only has 128 characters + UINT8 gfx = m_chargen[(chr<<3) | ra ]; + + // chars above 0x7f have colors inverted + if (m_videoram[x] > 0x7f) + gfx = ~gfx; + + /* Display a scanline of a character */ + *p++ |= BIT(gfx, 7); + *p++ |= BIT(gfx, 6); + *p++ |= BIT(gfx, 5); + *p++ |= BIT(gfx, 4); + *p++ |= BIT(gfx, 3); + *p++ |= BIT(gfx, 2); + *p++ |= BIT(gfx, 1); + *p++ |= BIT(gfx, 0); + } + } + ma += 32; + } +} diff --git a/src/devices/bus/iq151/video32.h b/src/devices/bus/iq151/video32.h new file mode 100644 index 00000000000..f813ca6edb2 --- /dev/null +++ b/src/devices/bus/iq151/video32.h @@ -0,0 +1,50 @@ +// license:BSD-3-Clause +// copyright-holders:Sandro Ronco +#pragma once + +#ifndef __IQ151_VIDEO32_H__ +#define __IQ151_VIDEO32_H__ + +#include "emu.h" +#include "iq151.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> iq151_video32_device + +class iq151_video32_device : + public device_t, + public device_iq151cart_interface +{ +public: + // construction/destruction + iq151_video32_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // iq151cart_interface overrides + virtual void read(offs_t offset, UINT8 &data); + virtual void write(offs_t offset, UINT8 data); + virtual void video_update(bitmap_ind16 &bitmap, const rectangle &cliprect); + +private: + UINT8 * m_videoram; + UINT8 * m_chargen; + required_device m_gfxdecode; + required_device m_palette; +}; + + +// device type definition +extern const device_type IQ151_VIDEO32; + +#endif /* __IQ151_VIDEO32_H__ */ diff --git a/src/devices/bus/iq151/video64.c b/src/devices/bus/iq151/video64.c new file mode 100644 index 00000000000..c6751adfe3d --- /dev/null +++ b/src/devices/bus/iq151/video64.c @@ -0,0 +1,177 @@ +// license:BSD-3-Clause +// copyright-holders:Sandro Ronco +/*************************************************************************** + + IQ151 video64 cartridge emulation + +***************************************************************************/ + +#include "emu.h" +#include "video64.h" + + +/*************************************************************************** + IMPLEMENTATION +***************************************************************************/ + +ROM_START( iq151_video64 ) + ROM_REGION(0x0800, "chargen", ROMREGION_INVERT) + ROM_LOAD( "iq151_video64font.rom", 0x0000, 0x0800, CRC(cb6f43c0) SHA1(4b2c1d41838d569228f61568c1a16a8d68b3dadf)) + + ROM_REGION(0x0800, "videoram", ROMREGION_ERASE) +ROM_END + + +/* F4 Character Displayer */ +static const gfx_layout iq151_video64_charlayout = +{ + 6, 8, /* 6 x 8 characters */ + 256, /* 256 characters */ + 1, /* 1 bits per pixel */ + { 0 }, /* no bitplanes */ + /* x offsets */ + { 2, 3, 4, 5, 6, 7 }, + /* y offsets */ + { 0*8, 1*8, 2*8, 3*8, 4*8, 5*8, 6*8, 7*8 }, + 8*8 /* every char takes 8 bytes */ +}; + +static GFXDECODE_START( video64 ) +GFXDECODE_END + +static MACHINE_CONFIG_FRAGMENT( video64 ) + MCFG_GFXDECODE_ADD("gfxdecode", "^^palette", video64) +MACHINE_CONFIG_END + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type IQ151_VIDEO64 = &device_creator; + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// iq151_video64_device - constructor +//------------------------------------------------- + +iq151_video64_device::iq151_video64_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, IQ151_VIDEO64, "IQ151 video64", tag, owner, clock, "iq151_video64", __FILE__), + device_iq151cart_interface( mconfig, *this ), + m_gfxdecode(*this, "gfxdecode"), + m_palette(*this, "^^palette") +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void iq151_video64_device::device_start() +{ + m_videoram = (UINT8*)memregion("videoram")->base(); + m_chargen = (UINT8*)memregion("chargen")->base(); + + m_gfxdecode->set_gfx(0,global_alloc(gfx_element(m_palette, iq151_video64_charlayout, m_chargen, 0, 1, 0))); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void iq151_video64_device::device_reset() +{ + screen_device *screen = machine().first_screen(); + + // if required adjust screen size + if (screen->visible_area().max_x < 64*6 - 1) + screen->set_visible_area(0, 64*6-1, 0, 32*8-1); +} + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor iq151_video64_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( video64 ); +} + +//------------------------------------------------- +// device_rom_region +//------------------------------------------------- + +const rom_entry *iq151_video64_device::device_rom_region() const +{ + return ROM_NAME( iq151_video64 ); +} + +//------------------------------------------------- +// read +//------------------------------------------------- + +void iq151_video64_device::read(offs_t offset, UINT8 &data) +{ + // videoram is mapped at 0xe800-0xefff + if (offset >= 0xe800 && offset < 0xf000) + data = m_videoram[offset & 0x7ff]; +} + +//------------------------------------------------- +// write +//------------------------------------------------- + +void iq151_video64_device::write(offs_t offset, UINT8 data) +{ + if (offset >= 0xe800 && offset < 0xf000) + m_videoram[offset & 0x7ff] = data; +} + +//------------------------------------------------- +// IO read +//------------------------------------------------- + +void iq151_video64_device::io_read(offs_t offset, UINT8 &data) +{ + if (offset >= 0xfc && offset < 0x100) + { + // this value is used by the IQ151 for detect if the installed + // cart is video64 or video32 + data = 0xfe; + } +} + +//------------------------------------------------- +// video update +//------------------------------------------------- + +void iq151_video64_device::video_update(bitmap_ind16 &bitmap, const rectangle &cliprect) +{ + UINT16 ma = 0, sy = 0; + + for (int y = 0; y < 32; y++) + { + for (int ra = 0; ra < 8; ra++) + { + UINT16 *p = &bitmap.pix16(sy++); + + for (int x = ma; x < ma + 64; x++) + { + UINT8 chr = m_videoram[x]; + UINT8 gfx = m_chargen[(chr<<3) | ra ]; + + /* Display a scanline of a character */ + *p++ |= BIT(gfx, 5); + *p++ |= BIT(gfx, 4); + *p++ |= BIT(gfx, 3); + *p++ |= BIT(gfx, 2); + *p++ |= BIT(gfx, 1); + *p++ |= BIT(gfx, 0); + } + } + ma += 64; + } +} diff --git a/src/devices/bus/iq151/video64.h b/src/devices/bus/iq151/video64.h new file mode 100644 index 00000000000..36487711acf --- /dev/null +++ b/src/devices/bus/iq151/video64.h @@ -0,0 +1,51 @@ +// license:BSD-3-Clause +// copyright-holders:Sandro Ronco +#pragma once + +#ifndef __IQ151_VIDEO64_H__ +#define __IQ151_VIDEO64_H__ + +#include "emu.h" +#include "iq151.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> iq151_video64_device + +class iq151_video64_device : + public device_t, + public device_iq151cart_interface +{ +public: + // construction/destruction + iq151_video64_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // iq151cart_interface overrides + virtual void read(offs_t offset, UINT8 &data); + virtual void write(offs_t offset, UINT8 data); + virtual void io_read(offs_t offset, UINT8 &data); + virtual void video_update(bitmap_ind16 &bitmap, const rectangle &cliprect); + +private: + UINT8 * m_videoram; + UINT8 * m_chargen; + required_device m_gfxdecode; + required_device m_palette; +}; + + +// device type definition +extern const device_type IQ151_VIDEO64; + +#endif /* __IQ151_VIDEO64_H__ */ diff --git a/src/devices/bus/isa/3c503.c b/src/devices/bus/isa/3c503.c new file mode 100644 index 00000000000..84af1d2db32 --- /dev/null +++ b/src/devices/bus/isa/3c503.c @@ -0,0 +1,304 @@ +// license:BSD-3-Clause +// copyright-holders:Carl +#include "emu.h" +#include "3c503.h" + +#define SADDR 0xcc000 + +static MACHINE_CONFIG_FRAGMENT(el2_3c503_config) + MCFG_DEVICE_ADD("dp8390d", DP8390D, 0) + MCFG_DP8390D_IRQ_CB(WRITELINE(el2_3c503_device, el2_3c503_irq_w)) + MCFG_DP8390D_MEM_READ_CB(READ8(el2_3c503_device, el2_3c503_mem_read)) + MCFG_DP8390D_MEM_WRITE_CB(WRITE8(el2_3c503_device, el2_3c503_mem_write)) +MACHINE_CONFIG_END + +const device_type EL2_3C503 = &device_creator; + +machine_config_constructor el2_3c503_device::device_mconfig_additions() const { + return MACHINE_CONFIG_NAME(el2_3c503_config); +} + +el2_3c503_device::el2_3c503_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, EL2_3C503, "3C503 Network Adapter", tag, owner, clock, "el2_3c503", __FILE__), + device_isa8_card_interface(mconfig, *this), + m_dp8390(*this, "dp8390d") { +} + +void el2_3c503_device::device_start() { + char mac[7]; + UINT32 num = rand(); + memset(m_prom, 0x57, 16); + sprintf(mac, "\x02\x60\x8c%c%c%c", (num >> 16) & 0xff, (num >> 8) & 0xff, num & 0xff); + memcpy(m_prom, mac, 6); + memset(m_rom, 0, 8*1024); // empty + m_dp8390->set_mac(mac); + set_isa_device(); + m_isa->install_device(0x0300, 0x030f, 0, 0, read8_delegate(FUNC(el2_3c503_device::el2_3c503_loport_r), this), write8_delegate(FUNC(el2_3c503_device::el2_3c503_loport_w), this)); + m_isa->install_device(0x0700, 0x070f, 0, 0, read8_delegate(FUNC(el2_3c503_device::el2_3c503_hiport_r), this), write8_delegate(FUNC(el2_3c503_device::el2_3c503_hiport_w), this)); + + // TODO: This is wrong, fix if anything actually uses it + // DMA can change in runtime + int chan = 0, idcfr = m_regs.idcfr & 0x0f; + if((m_regs.streg & 0x08)) { + while(idcfr) { + chan++; + idcfr >>= 1; + } + m_isa->set_dma_channel(chan, this, FALSE); + } +} + +void el2_3c503_device::device_reset() { + memcpy(m_prom, m_dp8390->get_mac(), 6); + memset(&m_regs, 0, sizeof(m_regs)); + m_regs.bcfr = 0x80; // port 0x300 + m_regs.pcfr = 0x20; // address 0xcc000 + m_regs.ctrl = 0x0a; + m_irq_state = CLEAR_LINE; + m_isa->unmap_bank(SADDR, SADDR + 0x1fff, 0, 0); + m_isa->install_bank(SADDR, SADDR + 0x1fff, 0, 0, "3c503 rom", m_rom); +} + +void el2_3c503_device::set_irq(int state) { + switch(m_regs.idcfr & 0xf0) { + case 0x10: + m_isa->irq2_w(state); + break; + case 0x20: + m_isa->irq3_w(state); + break; + case 0x40: + m_isa->irq4_w(state); + break; + case 0x80: + m_isa->irq5_w(state); + break; + } +} + +void el2_3c503_device::set_drq(int state) { + switch(m_regs.idcfr & 0x0f) { + case 0x01: + m_isa->drq1_w(state); + break; + case 0x02: + m_isa->drq2_w(state); + break; + case 0x04: + m_isa->drq3_w(state); + break; + } +} + +void el2_3c503_device::eop_w(int state) { + if((m_regs.streg & 0x08) && (state == ASSERT_LINE)) { + m_regs.streg |= 0x10; + m_regs.streg &= ~0x08; + if(!(m_regs.gacfr & 0x40)) set_irq(ASSERT_LINE); + } +} + +UINT8 el2_3c503_device::dack_r(int line) { + set_drq(CLEAR_LINE); + return el2_3c503_mem_read(m_regs.da++); +} + +void el2_3c503_device::dack_w(int line, UINT8 data) { + set_drq(CLEAR_LINE); + el2_3c503_mem_write(m_regs.da++, data); +} + +READ8_MEMBER(el2_3c503_device::el2_3c503_loport_r) { + switch((m_regs.ctrl >> 2) & 3) { + case 0: + m_dp8390->dp8390_cs(CLEAR_LINE); + return m_dp8390->dp8390_r(space, offset, mem_mask); + case 1: + return m_prom[offset]; + case 2: + return m_prom[offset + 16]; + case 3: + logerror("3c503: invalid low register read, page 3\n"); + } + return 0; +} + +WRITE8_MEMBER(el2_3c503_device::el2_3c503_loport_w) { + switch((m_regs.ctrl >> 2) & 3) { + case 0: + m_dp8390->dp8390_cs(CLEAR_LINE); + return m_dp8390->dp8390_w(space, offset, data, mem_mask); + case 1: + case 2: + logerror("3c503: invalid attempt to write to prom\n"); + return; + case 3: + logerror("3c503: invalid low register write, page 3\n"); + return; + } +} + +READ8_MEMBER(el2_3c503_device::el2_3c503_hiport_r) { + switch(offset) { + case 0: + return m_regs.pstr; + case 1: + return m_regs.pspr; + case 2: + return m_regs.dqtr; + case 3: + return m_regs.bcfr; + case 4: + return m_regs.pcfr; + case 5: + return m_regs.gacfr; + case 6: + return m_regs.ctrl; + case 7: + return m_regs.streg; + case 8: + return m_regs.idcfr; + case 9: + return m_regs.da >> 8; + case 10: + return m_regs.da & 0xff; + case 11: + return (m_regs.vptr >> 12) & 0xff; + case 12: + return (m_regs.vptr >> 4) & 0xff; + case 13: + return (m_regs.vptr & 0x0f) << 4; + case 14: + if(!(m_regs.ctrl & 0x80)) return 0xff; + return el2_3c503_mem_read(space, m_regs.da++, mem_mask); + case 15: + if(!(m_regs.ctrl & 0x80)) return 0xff; + return el2_3c503_mem_read(space, m_regs.da++, mem_mask); + } + return 0; +} + +WRITE8_MEMBER(el2_3c503_device::el2_3c503_hiport_w) { + switch(offset) { + case 0: + m_regs.pstr = data; // pstr and pspr are supposed to be set same as 8390 pstart and pstop + return; // what happens if they aren't? + case 1: + m_regs.pspr = data; + return; + case 2: + m_regs.dqtr = data; + return; + case 5: + if((m_regs.gacfr & 0xf) != (data & 0xf)) { + m_isa->unmap_bank(SADDR, SADDR + 0x1fff, 0, 0); + switch(data & 0xf) { + case 0: + m_isa->install_bank(SADDR, SADDR + 0x1fff, 0, 0, "3c503 rom", m_rom); + break; + case 9: + m_isa->install_bank(SADDR, SADDR + 0x1fff, 0, 0, "3c503 ram", m_board_ram); + break; + default: + m_isa->install_bank(SADDR, SADDR + 0x1fff, 0, 0, "3c503 no map", m_rom); + break; + } + } + + if(!(data & 0x80)) set_irq(m_irq_state); + else set_irq(CLEAR_LINE); + + m_regs.gacfr = data; + return; + case 6: + if(data & 1) { + device_reset(); + m_regs.ctrl = 0x0b; + return; + } + if((data & 0x80) != (m_regs.ctrl & 0x80)) { + if(data & 0x80) m_regs.streg |= 0x88; + else m_regs.streg &= ~0x88; + m_regs.streg &= ~0x10; + } + m_regs.ctrl = data; + return; + case 8: + // allow only one irq and drq to be set, hw may not enforce this + switch(data & 0xf0) { + case 0x00: + case 0x10: + case 0x20: + case 0x40: + case 0x80: + m_regs.idcfr = (m_regs.idcfr & 0xf) | (data & 0xf0); + break; + default: + logerror("3c503: trying to set multiple irqs %X\n", data); + } + switch(data & 0x0f) { + case 0x00: + case 0x01: + case 0x02: + case 0x04: + m_regs.idcfr = (m_regs.idcfr & 0xf0) | (data & 0xf); + break; + case 0x08: + break; + default: + logerror("3c503: trying to set multiple drqs %X\n", data); + } + case 9: + if(m_regs.ctrl & 0x80) logerror("3c503: changing dma address during dma is undefined\n"); + m_regs.da = (data << 8) | (m_regs.da & 0xff); + return; + case 10: + if(m_regs.ctrl & 0x80) logerror("3c503: changing dma address during dma is undefined\n"); + m_regs.da = (m_regs.da & 0xff00) | data; + return; + case 11: + // vptr requires access to system memory address bus and so isn't currently emulatable + // it enables mmio to be set to rom on soft reset in case the machine is remote booted + m_regs.vptr = (data << 12) | (m_regs.vptr & 0xfff); + return; + case 12: + m_regs.vptr = (data << 4) | (m_regs.vptr & 0xff00f); + return; + case 13: + m_regs.vptr = (data >> 4) | (m_regs.vptr & 0xffff0); + return; + case 14: + if(!(m_regs.ctrl & 0x80)) return; + el2_3c503_mem_write(space, m_regs.da++, data, mem_mask); + return; + case 15: + if(!(m_regs.ctrl & 0x80)) return; + el2_3c503_mem_write(space, m_regs.da++, data, mem_mask); + return; + default: + logerror("3c503: invalid high register write %02x\n", offset); + } +} + +WRITE_LINE_MEMBER(el2_3c503_device::el2_3c503_irq_w) { + m_irq_state = state; + if(!(m_regs.gacfr & 0x80)) set_irq(state); +} + +READ8_MEMBER(el2_3c503_device::el2_3c503_mem_read) { + return el2_3c503_mem_read(offset); +} + +WRITE8_MEMBER(el2_3c503_device::el2_3c503_mem_write) { + el2_3c503_mem_write(offset, data); +} + +UINT8 el2_3c503_device::el2_3c503_mem_read(offs_t offset) { + if((offset < 8*1024) || (offset >= 16*1024)) return 0xff; + return m_board_ram[offset - (8*1024)]; +} + +void el2_3c503_device::el2_3c503_mem_write(offs_t offset, UINT8 data) { + if((offset < 8*1024) || (offset >= 16*1024)) return; + m_board_ram[offset - (8*1024)] = data; +} diff --git a/src/devices/bus/isa/3c503.h b/src/devices/bus/isa/3c503.h new file mode 100644 index 00000000000..ad5da16dac8 --- /dev/null +++ b/src/devices/bus/isa/3c503.h @@ -0,0 +1,64 @@ +// license:BSD-3-Clause +// copyright-holders:Carl +/* 3com Etherlink II 3c503 */ + +#ifndef __3C503_H__ +#define __3C503_H__ + +#include "emu.h" +#include "isa.h" +#include "machine/dp8390.h" + +class el2_3c503_device: public device_t, + public device_isa8_card_interface +{ +public: + el2_3c503_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual machine_config_constructor device_mconfig_additions() const; + + void el2_3c503_irq_w(int state); + DECLARE_READ8_MEMBER(el2_3c503_mem_read); + DECLARE_WRITE8_MEMBER(el2_3c503_mem_write); + DECLARE_READ8_MEMBER(el2_3c503_loport_r); + DECLARE_WRITE8_MEMBER(el2_3c503_loport_w); + DECLARE_READ8_MEMBER(el2_3c503_hiport_r); + DECLARE_WRITE8_MEMBER(el2_3c503_hiport_w); + void eop_w(int state); + UINT8 dack_r(int line); + void dack_w(int line, UINT8 data); +protected: + virtual void device_start(); + virtual void device_reset(); +private: + required_device m_dp8390; + UINT8 m_board_ram[8*1024]; + UINT8 m_rom[8*1024]; + UINT8 m_prom[32]; + UINT8 m_irq_state; + + UINT8 el2_3c503_mem_read(offs_t offset); + void el2_3c503_mem_write(offs_t offset, UINT8 data); + + void set_irq(int state); + void set_drq(int state); + + struct { + UINT8 pstr; + UINT8 pspr; + UINT8 dqtr; + UINT8 bcfr; + UINT8 pcfr; + UINT8 gacfr; + UINT8 ctrl; + UINT8 streg; + UINT8 idcfr; + UINT16 da; + UINT32 vptr; + UINT8 rfmsb; + UINT8 rflsb; + } m_regs; +}; + +extern const device_type EL2_3C503; + +#endif diff --git a/src/devices/bus/isa/3c505.c b/src/devices/bus/isa/3c505.c new file mode 100644 index 00000000000..98328c41683 --- /dev/null +++ b/src/devices/bus/isa/3c505.c @@ -0,0 +1,1667 @@ +// license:BSD-3-Clause +// copyright-holders:Hans Ostermeyer,R. Belmont +/* + * 3c505.c - 3COM 3C505 ethernet controller (for Apollo DN3x00) + * + * Created on: August 27, 2010 + * Author: Hans Ostermeyer + * ISA conversion by R. Belmont + * + * see also: + * - http://lxr.free-electrons.com/source/drivers/net/3c505.h + * - http://lxr.free-electrons.com/source/drivers/net/3c505.c + * - http://stason.org/TULARC/pc/network-cards/O/OLIVETTI-Ethernet-NPU-9144-3C505.html + * - http://www.bitsavers.org/pdf/3Com/3c505_Etherlink_Plus_Developers_Guide_May86.pdf' + * - http://www.bitsavers.org/pdf/3Com/1569-03_EtherLink_Plus_Technical_Reference_Jan89.pdf + * + */ + +#include "3c505.h" + +#define VERBOSE 0 + +static int verbose = VERBOSE; + +#define LOG(x) { logerror ("%s: ", cpu_context()); logerror x; logerror ("\n"); } +#define LOG1(x) { if (verbose > 0) LOG(x)} +#define LOG2(x) { if (verbose > 1) LOG(x)} + +#define MAINCPU "maincpu" + +#ifdef LSB_FIRST +static UINT16 uint16_to_le(UINT16 value) +{ + return value; +} + +static UINT16 uint16_from_le(UINT16 value) +{ + return value; +} +#else +static UINT16 uint16_to_le(UINT16 value) +{ + return ((value&0x00ff)<<8)|((value&0xff00)>>8); +} + +static UINT16 uint16_from_le(UINT16 value) +{ + return ((value&0x00ff)<<8)|((value&0xff00)>>8); +} +#endif + +//************************************************************************** +// CONSTANTS +//************************************************************************** + +// Apollo microcode version +#define APOLLO_MC_VERSION_SR10_2 0x0302 +#define APOLLO_MC_VERSION_SR10_4 0x0303 + +#define PORT_DATA_FIFO_SIZE 20 + +/* + * I/O register offsets + */ +#define PORT_COMMAND 0x00 /* read/write, 8-bit */ +#define PORT_STATUS 0x02 /* read only, 8-bit */ +#define PORT_AUXDMA 0x02 /* write only, 8-bit */ +#define PORT_DATA 0x04 /* read/write, 16-bit */ +#define PORT_CONTROL 0x06 /* read/write, 8-bit */ + +#define ELP_IO_EXTENT 0x10 /* size of used IO registers */ + +/* + * host control registers bits + */ +#define ATTN 0x80 /* attention */ +#define FLSH 0x40 /* flush data register */ +#define DMAE 0x20 /* DMA enable */ +#define DIR_ 0x10 /* direction */ +#define TCEN 0x08 /* terminal count interrupt enable */ +#define CMDE 0x04 /* command register interrupt enable */ +#define HSF2 0x02 /* host status flag 2 */ +#define HSF1 0x01 /* host status flag 1 */ + +/* + * combinations of HSF flags used for PCB transmission + */ +#define HSF_PCB_ACK HSF1 +#define HSF_PCB_NAK HSF2 +#define HSF_PCB_END (HSF2|HSF1) +#define HSF_PCB_MASK (HSF2|HSF1) + +/* + * host status register bits + */ +#define HRDY 0x80 /* data register ready */ +#define HCRE 0x40 /* command register empty */ +#define ACRF 0x20 /* adapter command register full */ +/* #define DIR_ 0x10 direction - same as in control register */ +#define DONE 0x08 /* DMA done */ +#define ASF3 0x04 /* adapter status flag 3 */ +#define ASF2 0x02 /* adapter status flag 2 */ +#define ASF1 0x01 /* adapter status flag 1 */ + +/* + * combinations of ASF flags used for PCB reception + */ +#define ASF_PCB_ACK ASF1 +#define ASF_PCB_NAK ASF2 +#define ASF_PCB_END (ASF2|ASF1) +#define ASF_PCB_MASK (ASF3|ASF2|ASF1) + +/* + * host aux DMA register bits + */ +#define DMA_BRST 0x01 /* DMA burst */ + +/* + * maximum amount of data allowed in a PCB + */ +#define MAX_PCB_DATA 62 + +#define CMD_RESPONSE_OFFSET 0x30 +enum +{ + /* host PCB commands */ + CMD_RESET = 0x00, + CMD_CONFIGURE_ADAPTER_MEMORY = 0x01, + CMD_CONFIGURE_82586 = 0x02, + CMD_STATION_ADDRESS = 0x03, + CMD_DMA_DOWNLOAD = 0x04, + CMD_DMA_UPLOAD = 0x05, + CMD_PIO_DOWNLOAD = 0x06, + CMD_PIO_UPLOAD = 0x07, + CMD_RECEIVE_PACKET = 0x08, + CMD_TRANSMIT_PACKET = 0x09, + CMD_NETWORK_STATISTICS = 0x0a, + CMD_LOAD_MULTICAST_LIST = 0x0b, + CMD_CLEAR_PROGRAM = 0x0c, + CMD_DOWNLOAD_PROGRAM = 0x0d, + CMD_EXECUTE_PROGRAM = 0x0e, + CMD_SELF_TEST = 0x0f, + CMD_SET_STATION_ADDRESS = 0x10, + CMD_ADAPTER_INFO = 0x11, + + CMD_MC_17 = 0x17, + CMD_TRANSMIT_PACKET_18 = 0x18, + CMD_MC_F8 = 0xf8, + CMD_TRANSMIT_PACKET_F9 = 0xf9, + CMD_MC_FA = 0xfa, + + /*adapter PCB commands */ + CMD_RESET_RESPONSE = 0x30, + CMD_CONFIGURE_ADAPTER_RESPONSE = 0x31, + CMD_CONFIGURE_82586_RESPONSE = 0x32, + CMD_ADDRESS_RESPONSE = 0x33, + CMD_DOWNLOAD_DATA_REQUEST = 0x34, + CMD_UPLOAD_DATA_REQUEST = 0x35, + CMD_RECEIVE_PACKET_COMPLETE = 0x38, + CMD_TRANSMIT_PACKET_COMPLETE = 0x39, + CMD_NETWORK_STATISTICS_RESPONSE = 0x3a, + CMD_LOAD_MULTICAST_RESPONSE = 0x3b, + CMD_CLEAR_PROGRAM_RESPONSE = 0x3c, + CMD_DOWNLOAD_PROGRAM_RESPONSE = 0x3d, + CMD_EXECUTE_PROGRAM_RESPONSE = 0x3e, + CMD_SELF_TEST_RESPONSE = 0x3f, + CMD_SET_ADDRESS_RESPONSE = 0x40, + CMD_ADAPTER_INFO_RESPONSE = 0x41, + + CMD_MC_17_COMPLETE = 0x47, + CMD_TRANSMIT_PACKET_18_COMPLETE = 0x48, + + CMD_MC_E1_RESPONSE = 0xe1, + CMD_MC_E2_RESPONSE = 0xe2 +}; + +/* defines for 'configure' */ + +#define RECV_STATION 0x00 +#define RECV_BROAD 0x01 +#define RECV_MULTI 0x02 +#define RECV_PROMISC 0x04 +#define NO_LOOPBACK 0x00 +#define INT_LOOPBACK 0x08 +#define EXT_LOOPBACK 0x10 + +ROM_START( threecom3c505 ) + ROM_REGION( 0x02000, "threecom3c505", 0 ) + ROM_LOAD_OPTIONAL( "3000_3c505_010728-00.bin", 0x00000, 0x02000, CRC(69b77ec6) SHA1(7ac36cc6fc90b90ddfc56c45303b514cbe18ae58) ) + // see http://www.bitsavers.org/bits/Apollo/firmware/ +ROM_END + +static INPUT_PORTS_START( tc3c505_port ) + PORT_START("IO_BASE") + PORT_DIPNAME( 0x3f0, 0x300, "3C505 I/O base") + PORT_DIPSETTING( 0x010, "010h" ) + PORT_DIPSETTING( 0x020, "020h" ) + PORT_DIPSETTING( 0x030, "030h" ) + PORT_DIPSETTING( 0x040, "040h" ) + PORT_DIPSETTING( 0x050, "050h" ) + PORT_DIPSETTING( 0x060, "060h" ) + PORT_DIPSETTING( 0x070, "070h" ) + PORT_DIPSETTING( 0x080, "080h" ) + PORT_DIPSETTING( 0x090, "090h" ) + PORT_DIPSETTING( 0x0a0, "0a0h" ) + PORT_DIPSETTING( 0x0b0, "0b0h" ) + PORT_DIPSETTING( 0x0c0, "0c0h" ) + PORT_DIPSETTING( 0x0d0, "0d0h" ) + PORT_DIPSETTING( 0x0e0, "0e0h" ) + PORT_DIPSETTING( 0x0f0, "0f0h" ) + PORT_DIPSETTING( 0x100, "0100h" ) + PORT_DIPSETTING( 0x110, "0110h" ) + PORT_DIPSETTING( 0x120, "0120h" ) + PORT_DIPSETTING( 0x130, "0130h" ) + PORT_DIPSETTING( 0x140, "0140h" ) + PORT_DIPSETTING( 0x150, "0150h" ) + PORT_DIPSETTING( 0x160, "0160h" ) + PORT_DIPSETTING( 0x170, "0170h" ) + PORT_DIPSETTING( 0x180, "0180h" ) + PORT_DIPSETTING( 0x190, "0190h" ) + PORT_DIPSETTING( 0x1a0, "01a0h" ) + PORT_DIPSETTING( 0x1b0, "01b0h" ) + PORT_DIPSETTING( 0x1c0, "01c0h" ) + PORT_DIPSETTING( 0x1d0, "01d0h" ) + PORT_DIPSETTING( 0x1e0, "01e0h" ) + PORT_DIPSETTING( 0x1f0, "01f0h" ) + PORT_DIPSETTING( 0x200, "0200h" ) + PORT_DIPSETTING( 0x210, "0210h" ) + PORT_DIPSETTING( 0x220, "0220h" ) + PORT_DIPSETTING( 0x230, "0230h" ) + PORT_DIPSETTING( 0x240, "0240h" ) + PORT_DIPSETTING( 0x250, "0250h" ) + PORT_DIPSETTING( 0x260, "0260h" ) + PORT_DIPSETTING( 0x270, "0270h" ) + PORT_DIPSETTING( 0x280, "0280h" ) + PORT_DIPSETTING( 0x290, "0290h" ) + PORT_DIPSETTING( 0x2a0, "02a0h" ) + PORT_DIPSETTING( 0x2b0, "02b0h" ) + PORT_DIPSETTING( 0x2c0, "02c0h" ) + PORT_DIPSETTING( 0x2d0, "02d0h" ) + PORT_DIPSETTING( 0x2e0, "02e0h" ) + PORT_DIPSETTING( 0x2f0, "02f0h" ) + PORT_DIPSETTING( 0x300, "0300h" ) + PORT_DIPSETTING( 0x310, "0310h" ) + PORT_DIPSETTING( 0x320, "0320h" ) + PORT_DIPSETTING( 0x330, "0330h" ) + PORT_DIPSETTING( 0x340, "0340h" ) + PORT_DIPSETTING( 0x350, "0350h" ) + PORT_DIPSETTING( 0x360, "0360h" ) + PORT_DIPSETTING( 0x370, "0370h" ) + PORT_DIPSETTING( 0x380, "0380h" ) + PORT_DIPSETTING( 0x390, "0390h" ) + PORT_DIPSETTING( 0x3a0, "03a0h" ) + PORT_DIPSETTING( 0x3b0, "03b0h" ) + PORT_DIPSETTING( 0x3c0, "03c0h" ) + PORT_DIPSETTING( 0x3d0, "03d0h" ) + PORT_DIPSETTING( 0x3e0, "03e0h" ) + PORT_DIPSETTING( 0x3f0, "03f0h" ) + + PORT_START("IRQ_DRQ") + PORT_DIPNAME( 0x0f, 0x0a, "3C505 IRQ") + PORT_DIPSETTING( 0x03, "IRQ 3" ) + PORT_DIPSETTING( 0x04, "IRQ 4" ) + PORT_DIPSETTING( 0x05, "IRQ 5" ) + PORT_DIPSETTING( 0x06, "IRQ 6" ) + PORT_DIPSETTING( 0x07, "IRQ 7" ) + PORT_DIPSETTING( 0x09, "IRQ 9" ) + PORT_DIPSETTING( 0x0a, "IRQ 10" ) + PORT_DIPSETTING( 0x0b, "IRQ 11" ) + PORT_DIPSETTING( 0x0c, "IRQ 12" ) + PORT_DIPSETTING( 0x0e, "IRQ 14" ) + PORT_DIPSETTING( 0x0f, "IRQ 15" ) + + PORT_DIPNAME( 0x70, 0x60, "3C505 DMA") + PORT_DIPSETTING( 0x00, "none" ) + PORT_DIPSETTING( 0x10, "DRQ 1" ) + PORT_DIPSETTING( 0x30, "DRQ 3" ) + PORT_DIPSETTING( 0x50, "DRQ 5" ) + PORT_DIPSETTING( 0x60, "DRQ 6" ) + PORT_DIPSETTING( 0x70, "DRQ 7" ) + + PORT_START("ROM_OPTS") + PORT_DIPNAME( 0x01, 0x01, "ROM control") + PORT_DIPSETTING( 0x00, "Disabled" ) + PORT_DIPSETTING( 0x01, "Enabled" ) + PORT_DIPNAME( 0x06, 0x00, "ROM base") + PORT_DIPSETTING( 0x00, "80000h" ) + PORT_DIPSETTING( 0x02, "82000h" ) + PORT_DIPSETTING( 0x04, "84000h" ) + PORT_DIPSETTING( 0x06, "86000h" ) + +INPUT_PORTS_END + +/*************************************************************************** + IMPLEMENTATION + ***************************************************************************/ + +// device type definition +const device_type ISA16_3C505 = &device_creator ; + +//------------------------------------------------- +// threecom3c505_device - constructor +//------------------------------------------------- + +threecom3c505_device::threecom3c505_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, ISA16_3C505, "3Com 3C505 Network Adaptor", tag, owner, clock, "3c505", __FILE__), + device_network_interface(mconfig, *this, 10.0f), + device_isa16_card_interface(mconfig, *this), + m_iobase(*this, "IO_BASE"), + m_irqdrq(*this, "IRQ_DRQ"), + m_romopts(*this, "ROM_OPTS") +{ +} + +threecom3c505_device::threecom3c505_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, type, "3Com 3C505 Network Adaptor", tag, owner, clock, "3c505", __FILE__), + device_network_interface(mconfig, *this, 10.0f), + device_isa16_card_interface(mconfig, *this), + m_iobase(*this, "IO_BASE"), + m_irqdrq(*this, "IRQ_DRQ"), + m_romopts(*this, "ROM_OPTS") +{ +} + +ioport_constructor threecom3c505_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( tc3c505_port ); +} + +const rom_entry *threecom3c505_device::device_rom_region() const +{ + return ROM_NAME( threecom3c505 ); +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void threecom3c505_device::device_start() +{ + set_isa_device(); + + LOG1(("start 3COM 3C505")); + + m_installed = false; + + m_rx_fifo.start(this, RX_FIFO_SIZE, ETH_BUFFER_SIZE); + m_rx_data_buffer.start(this, ETH_BUFFER_SIZE); + m_tx_data_buffer.start(this, ETH_BUFFER_SIZE); + m_program_buffer.start(this, PGM_BUFFER_SIZE); + + m_do_command_timer = timer_alloc(0, NULL); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void threecom3c505_device::device_reset() +{ + LOG1(("reset 3COM 3C505")); + + m_rx_fifo.reset(); + m_rx_data_buffer.reset(); + m_tx_data_buffer.reset(); + m_program_buffer.reset(); + + memset(m_reg, 0, sizeof(m_reg)); + m_status = HCRE | DIR_; + m_control = 0; + m_command_index = 0; + m_command_pending = 0; + m_wait_for_nak = 0; + m_wait_for_ack = 0; + m_rx_data_index = 0; + m_rx_pending = 0; + m_tx_data_length = 0; + m_response_length = 0; + m_response_index = 0; + m_microcode_running = 0; + m_microcode_version = 0; + m_i82586_config = 0; + + // these will appear in /etc/nodestat -l + m_netstat.tot_recv = 0; + m_netstat.tot_xmit = 0; + m_netstat.err_CRC = 0; + m_netstat.err_align = 0; + m_netstat.err_res = 0; + m_netstat.err_ovrrun = 0; + + memset(m_station_address, 0, sizeof(m_station_address)); + memset(m_multicast_list, 0, sizeof(m_multicast_list)); + set_filter_list(); + set_promisc(true); + + if (!m_installed) + { + int base = m_iobase->read(); + + m_irq = m_irqdrq->read() & 0xf; + m_drq = (m_irqdrq->read() >> 4) & 0x7; + + m_isa->install16_device(base, base + ELP_IO_EXTENT - 1, 0, 0, read16_delegate(FUNC(threecom3c505_device::read), this), write16_delegate(FUNC(threecom3c505_device::write), this)); + + if (m_romopts->read() & 1) + { + // host ROM is enabled, get base address + static const int rom_bases[4] = { 0x0000, 0x2000, 0x4000, 0x6000 }; + int rom_base = rom_bases[(m_romopts->read() >> 1) & 3]; + m_isa->install_rom(this, rom_base, rom_base + 0x01fff, 0, 0, "threecom3c505", "threecom3c505"); + } + + m_installed = true; + } +} + +/*************************************************************************** + cpu_context - return a string describing the current CPU context + ***************************************************************************/ + +const char *threecom3c505_device::cpu_context() +{ + static char statebuf[64]; /* string buffer containing state description */ + + device_t *cpu = machine().device(MAINCPU); + osd_ticks_t t = osd_ticks(); + int s = t / osd_ticks_per_second(); + int ms = (t % osd_ticks_per_second()) / 1000; + + /* if we have an executing CPU, output data */ + if (cpu != NULL) + { + sprintf(statebuf, "%d.%03d %s pc=%08x - %s", s, ms, cpu->tag(), + cpu->safe_pcbase(), tag()); + } + else + { + sprintf(statebuf, "%d.%03d", s, ms); + } + return statebuf; +} + +//************************************************************************** +// data_buffer +//************************************************************************** + +threecom3c505_device::data_buffer::data_buffer() : + m_device(NULL) +{ +} + +void threecom3c505_device::data_buffer::start(threecom3c505_device *device, INT32 size) +{ + m_device = device; + LOG2(("start threecom3c505_device::data_buffer with size %0x", size)); + m_data.resize(size); +} + +void threecom3c505_device::data_buffer::reset() +{ + LOG2(("reset threecom3c505_device::data_buffer")); + m_length = 0; +} + +void threecom3c505_device::data_buffer::copy(data_buffer *db) const +{ + db->m_data.resize(m_data.size()); + db->m_length = m_length; + memcpy(&db->m_data[0], &m_data[0], m_data.size()); +} + +int threecom3c505_device::data_buffer::append(UINT8 data) +{ + if (m_length >= m_data.size()) + { + return 0; + } + else + { + m_data[m_length++] = data; + return 1; + } +} + +void threecom3c505_device::data_buffer::log(const char * title) const +{ + if (verbose > 0) + { + int i; + logerror("%s: %s (length=%02x)", m_device->cpu_context(), title, m_length); + for (i = 0; i < m_length; i++) + { + logerror(" %02x", m_data[i]); + if (i >= 1023) + { + logerror(" ..."); + break; + } + } + logerror("\n"); + } +} + +//************************************************************************** +// data_buffer fifo +//************************************************************************** + +threecom3c505_device::data_buffer_fifo::data_buffer_fifo() : + m_device(NULL), + m_size(0) +{ +} + +void threecom3c505_device::data_buffer_fifo::start( + threecom3c505_device *device, INT32 size, INT32 db_size) +{ + m_device = device; + LOG2(("start threecom3c505_device::data_buffer_fifo")); + + int i; + // FIXME: fifo size is hardcoded + m_size = RX_FIFO_SIZE; // size; + for (i = 0; i < m_size; i++) + { + m_db[i] = global_alloc(data_buffer()); + m_db[i]->start(device, db_size); + } +} + +void threecom3c505_device::data_buffer_fifo::reset() +{ + LOG2(("reset threecom3c505_device::data_buffer_fifo")); + m_get_index = m_put_index = 0; + m_count = 0; +} + +threecom3c505_device::data_buffer_fifo::~data_buffer_fifo() +{ + for (int i = 0; i < m_size; i++) + { + global_free(m_db[i]); + } +} + +int threecom3c505_device::data_buffer_fifo::put(const UINT8 data[], const int length) +{ + UINT16 next_index = (m_put_index + 1) % m_size; + + LOG2(("threecom3c505_device::data_buffer_fifo::put %d", m_count)); + + if (next_index == m_get_index) + { + // overflow, fifo full + return 0; + } + else if (length > ETH_BUFFER_SIZE) + { + // data size exceeds buffer size + LOG(("threecom3c505_device::data_buffer_fifo::put %d: data size (%d) exceeds buffer size (%d)!!!", m_count, length,ETH_BUFFER_SIZE)); + return 0; + } + else + { + memcpy(&m_db[m_put_index]->m_data[0], data, length); + m_db[m_put_index]->m_length = length; + m_put_index = next_index; + m_count++; + return 1; + } +} + +int threecom3c505_device::data_buffer_fifo::get(data_buffer *db) +{ + LOG2(("threecom3c505_device::data_buffer_fifo::get %d", m_count)); + + if (m_get_index == m_put_index) + { + // fifo empty + return 0; + } + else + { + m_db[m_get_index]->copy(db); + m_get_index = (m_get_index + 1) % m_size; + m_count--; + return 1; + } +} + +/*------------------------------------------------- + set_filter_list - set the ethernet packet filter list + -------------------------------------------------*/ + +void threecom3c505_device::set_filter_list() +{ + memset(m_filter_list, 0, sizeof(m_filter_list)); + memcpy(m_filter_list, m_station_address, ETHERNET_ADDR_SIZE); + memset(m_filter_list + ETHERNET_ADDR_SIZE, 0xff, ETHERNET_ADDR_SIZE); + memcpy(m_filter_list + ETHERNET_ADDR_SIZE * 2, m_multicast_list, sizeof(m_multicast_list)); + + int node_id = (((m_station_address[3] << 8) + m_station_address[4]) << 8) + m_station_address[5]; + LOG2(("set_filter_list node_id=%x",node_id)); + + setfilter(this, node_id); +} + +/*------------------------------------------------- + set_interrupt - set the IRQ state + -------------------------------------------------*/ + +void threecom3c505_device::set_interrupt(enum line_state state) +{ + if (state != irq_state) + { + LOG2(("set_interrupt(%d)",state)); + switch (m_irq) + { + case 3: m_isa->irq3_w(state); break; + case 4: m_isa->irq4_w(state); break; + case 5: m_isa->irq5_w(state); break; + case 6: m_isa->irq6_w(state); break; + case 7: m_isa->irq7_w(state); break; + case 9: m_isa->irq2_w(state); break; // IRQ 9 on ISA16 goes to IRQ 2 + case 10: m_isa->irq10_w(state); break; + case 11: m_isa->irq11_w(state); break; + case 12: m_isa->irq12_w(state); break; + case 14: m_isa->irq14_w(state); break; + case 15: m_isa->irq15_w(state); break; + default: logerror("3c505: invalid IRQ %d\n", m_irq); break; + } + irq_state = state; + } +} + +// ------------------------------------- + +void threecom3c505_device::log_command() +{ + if (verbose > 0) + { + int i; + logerror("%s: Command ", cpu_context()); + switch (m_command_buffer[0]) + { + case CMD_RESET: // 0x00 + logerror("!!! unexpected CMD_RESET"); + break; + case CMD_CONFIGURE_ADAPTER_MEMORY: // 0x01 + logerror("CMD_CONFIGURE_ADAPTER_MEMORY"); + break; + case CMD_CONFIGURE_82586: // 0x02 + logerror("CMD_CONFIGURE_82586"); + break; + case CMD_RECEIVE_PACKET: // 0x08 + logerror("CMD_RECEIVE_PACKET"); + break; + case CMD_TRANSMIT_PACKET: // 0x09 + logerror("CMD_TRANSMIT_PACKET"); + break; + case CMD_NETWORK_STATISTICS: // 0x0a + logerror("CMD_NETWORK_STATISTICS"); + break; + case CMD_LOAD_MULTICAST_LIST: // 0x0b, + logerror("CMD_LOAD_MULTICAST_LIST"); + break; + case CMD_CLEAR_PROGRAM: // 0x0c + logerror("!!! unexpected CMD_CLEAR_PROGRAM"); + break; + case CMD_DOWNLOAD_PROGRAM: // 0x0d + logerror("CMD_DOWNLOAD_PROGRAM"); + break; + case CMD_EXECUTE_PROGRAM: // 0x0e + logerror("CMD_EXECUTE_PROGRAM"); + break; + case CMD_SET_STATION_ADDRESS: // 0x10 + logerror("CMD_SET_STATION_ADDRESS"); + break; + case CMD_ADAPTER_INFO: // 0x11 + logerror("CMD_ADAPTER_INFO"); + break; + case CMD_MC_17: // 0x17 + logerror("CMD_MC_17"); + break; + case CMD_TRANSMIT_PACKET_18: // 0x18 + logerror("CMD_TRANSMIT_PACKET_18"); + break; + + case CMD_MC_F8: // 0xf8 + logerror("!!! CMD_MC_F8"); + break; + case CMD_TRANSMIT_PACKET_F9: // 0xf9 + logerror("CMD_TRANSMIT_PACKET_F9"); + break; + case CMD_MC_FA: // 0xfa + logerror("!!! CMD_MC_FA"); + break; + + default: + logerror("!!! unexpected Command"); + } + + switch (m_command_buffer[0]) + { + case CMD_TRANSMIT_PACKET_F9: // 0xf9 + logerror(" (%02x, length=00)", m_command_buffer[0]); + break; + + default: + logerror(" (%02x, length=%02x)", m_command_buffer[0], + m_command_buffer[1]); + for (i = 2; i < m_command_index; i++) + { + logerror(" %02x", m_command_buffer[i]); + } + break; + } + logerror("\n"); + } +} + +void threecom3c505_device::log_response() +{ + if (verbose > 0) + { + int i; + logerror("%s: Response ", cpu_context()); + switch (m_response.command) + { + case CMD_RESET_RESPONSE: // 0x30 + logerror("CMD_RESET_RESPONSE"); + break; + case CMD_CONFIGURE_ADAPTER_RESPONSE: // 0x31 + logerror("CMD_CONFIGURE_ADAPTER_RESPONSE"); + break; + case CMD_CONFIGURE_82586_RESPONSE: // 0x32 + logerror("CMD_CONFIGURE_82586_RESPONSE"); + break; + case CMD_RECEIVE_PACKET_COMPLETE: // 0x38 + logerror("CMD_RECEIVE_PACKET_COMPLETE"); + break; + case CMD_TRANSMIT_PACKET_COMPLETE: // 0x39 + logerror("CMD_TRANSMIT_PACKET_COMPLETE"); + break; + case CMD_NETWORK_STATISTICS_RESPONSE: // 0x3a + logerror("CMD_NETWORK_STATISTICS_RESPONSE"); + break; + case CMD_LOAD_MULTICAST_RESPONSE: // 0x3b + logerror("CMD_LOAD_MULTICAST_RESPONSE"); + break; + case CMD_DOWNLOAD_PROGRAM_RESPONSE: // 0x3d + logerror("CMD_DOWNLOAD_PROGRAM_RESPONSE"); + break; + case CMD_EXECUTE_PROGRAM_RESPONSE: // 0x3e + logerror("CMD_EXECUTE_PROGRAM_RESPONSE"); + break; + case CMD_SET_ADDRESS_RESPONSE: // 0x40 + logerror("CMD_SET_ADDRESS_RESPONSE"); + break; + case CMD_ADAPTER_INFO_RESPONSE: // 0x41 + logerror("CMD_ADAPTER_INFO_RESPONSE"); + break; + case CMD_MC_17_COMPLETE: // 0x47 + logerror("CMD_MC_17_COMPLETE"); + break; + case CMD_TRANSMIT_PACKET_18_COMPLETE: // 0x48 + logerror("CMD_TRANSMIT_PACKET_18_COMPLETE"); + break; + case CMD_MC_E1_RESPONSE: // 0xe1 + logerror("!!! CMD_MC_E1_RESPONSE"); + break; + case CMD_MC_E2_RESPONSE: // 0xe2 + logerror("!!! CMD_MC_E2_RESPONSE"); + break; + default: + logerror("!!! unexpected Response"); + } + logerror(" (%02x, length=%02x)", m_response.command, m_response.length); + for (i = 0; i < m_response.length; i++) + { + logerror(" %02x", m_response.data.raw[i]); + } + logerror("\n"); + } +} + +/*************************************************************************** + do_receive_command + ***************************************************************************/ + +void threecom3c505_device::do_receive_command() +{ + // receive pending and no other command is pending + if (m_rx_pending > 0 && !m_command_pending) + { + if (m_rx_data_buffer.get_length() == 0 && !m_rx_fifo.is_empty()) + { + m_rx_fifo.get(&m_rx_data_buffer); + } + + // receive data available ? + if (m_rx_data_buffer.get_length() > 0) + { + LOG2(("do_receive_command - data_length=%x rx_pending=%d", + m_rx_data_buffer.get_length(), m_rx_pending)); + + m_rx_pending--; + set_command_pending(1); + + // preset receive response PCB + memcpy(&m_response, &m_rcv_response, sizeof(m_rcv_response)); + +// m_response.command = CMD_RECEIVE_PACKET_COMPLETE; // 0x38 +// m_response.length = 16; +// m_response.data.rcv_resp.buf_ofs = htole16(0); +// m_response.data.rcv_resp.buf_seg = htole16(0); +// m_response.data.rcv_resp.buf_len = htole16(buf_len); + + // htole16 and friends are not portable beyond Linux. It's named differently on *BSD and differently again on OS X. Avoid! + m_response.data.rcv_resp.pkt_len = uint16_to_le(m_rx_data_buffer.get_length()); + m_response.data.rcv_resp.timeout = 0; // successful completion + m_response.data.rcv_resp.status = uint16_to_le(m_rx_data_buffer.get_length() > 0 ? 0 : 0xffff); + m_response.data.rcv_resp.timetag = 0; // TODO: time tag + + // compute and check no of bytes to be DMA'ed (must be even) + UINT16 buf_len = uint16_from_le(m_response.data.rcv_resp.buf_len) & ~1; + if (m_rx_data_buffer.get_length() > buf_len) + { + LOG1(("do_receive_command !!! buffer size too small (%d < %d)", buf_len, m_rx_data_buffer.get_length())); + m_response.data.rcv_resp.pkt_len = uint16_to_le(buf_len); + m_response.data.rcv_resp.status = 0xffff; + } + else + { + buf_len = (m_rx_data_buffer.get_length() + 1) & ~1; + m_response.data.rcv_resp.buf_len = uint16_to_le(buf_len); + } + + m_response_length = m_response.length + 2; + m_response_index = 0; + + m_status |= ACRF; /* set adapter command register full */ + if (m_control & CMDE) + { + set_interrupt(ASSERT_LINE); + } + } + } +} + +/*************************************************************************** + set_command_pending onoff + ***************************************************************************/ + +void threecom3c505_device::set_command_pending(int state) +{ + LOG2(("set_command_pending %d -> %d m_wait_for_ack=%d m_wait_for_nak=%d m_rx_pending=%d%s", + m_command_pending, state, m_wait_for_ack, m_wait_for_nak, m_rx_pending, state ? "" :"\n")); + +//- verbose = onoff ? 1 : 2; + + switch (state) + { + case 0: + // command is no longer pending + m_command_pending = 0; + + // clear previous command byte + m_command_buffer[0] = 0; + + m_wait_for_ack = 0; + m_wait_for_nak = 0; + + do_receive_command(); + break; + case 1: + // command is pending + m_command_pending = 1; + break; + case 2: + // wait for nak/ack + if (m_microcode_running && m_microcode_version == APOLLO_MC_VERSION_SR10_4) + { + m_wait_for_nak = 1; + } + else + { + m_wait_for_ack = 1; + } + break; + default: + LOG(("set_command_pending %d unexpected" , state)); + break; + } + +} + +/*************************************************************************** + execute the commands (formerly do_command) + ***************************************************************************/ + +void threecom3c505_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + do_command(); +} + +void threecom3c505_device::do_command() +{ + pcb_struct &command_pcp = (pcb_struct &) m_command_buffer; + + // default to successful completion + m_response.command = command_pcp.command + CMD_RESPONSE_OFFSET; + m_response.length = 1; + m_response.data.failed = 0; // successful completion + + switch (command_pcp.command) + { + case CMD_RESET: // 0x00 + // FIXME: should never occur + break; + + case CMD_CONFIGURE_ADAPTER_MEMORY: // 0x01 + // TODO + break; + + case CMD_CONFIGURE_82586: // 0x02 + m_i82586_config = command_pcp.data.raw[0] + (command_pcp.data.raw[1] << 8); + break; + + case CMD_RECEIVE_PACKET: // 0x08 + // preset response PCB from the Receive Command PCB + m_rcv_response.command = CMD_RECEIVE_PACKET_COMPLETE; // 0x38 + m_rcv_response.length = sizeof(struct Rcv_resp); + m_rcv_response.data.rcv_resp.buf_ofs = command_pcp.data.rcv_pkt.buf_ofs; + m_rcv_response.data.rcv_resp.buf_seg = command_pcp.data.rcv_pkt.buf_seg; + m_rcv_response.data.rcv_resp.buf_len = command_pcp.data.rcv_pkt.buf_len; + m_rcv_response.data.rcv_resp.pkt_len = 0; + m_rcv_response.data.rcv_resp.timeout = 0; + m_rcv_response.data.rcv_resp.status = 0; + m_rcv_response.data.rcv_resp.timetag = 0L; // TODO + + m_rx_pending++; + set_command_pending(0); + return; + // break; + + case CMD_TRANSMIT_PACKET_F9: + m_response.command = CMD_TRANSMIT_PACKET_COMPLETE; + // fall through + + case CMD_TRANSMIT_PACKET: // 0x09 + case CMD_TRANSMIT_PACKET_18: // 0x18 + m_response.length = sizeof(struct Xmit_resp); + m_response.data.xmit_resp.buf_ofs = 0; + m_response.data.xmit_resp.buf_seg = 0; + m_response.data.xmit_resp.c_stat = 0; // successful completion + m_response.data.xmit_resp.status = 0; + break; + + case CMD_EXECUTE_PROGRAM: // 0x0e + // m_response.length = 0; + + // FIXME: hack? + m_status |= ASF_PCB_END; + break; + + case CMD_NETWORK_STATISTICS: // 0x0a + m_response.length = sizeof(struct Netstat); + m_response.data.netstat.tot_recv = uint16_to_le(m_netstat.tot_recv); + m_response.data.netstat.tot_xmit = uint16_to_le(m_netstat.tot_xmit); + m_response.data.netstat.err_CRC = uint16_to_le(m_netstat.err_CRC); + m_response.data.netstat.err_align = uint16_to_le(m_netstat.err_align); + m_response.data.netstat.err_res = uint16_to_le(m_netstat.err_res); + m_response.data.netstat.err_ovrrun = uint16_to_le(m_netstat.err_ovrrun); + break; + + case CMD_ADAPTER_INFO: // 0x11 + m_response.length = sizeof(struct Info); + // FIXME: using demo data + m_response.data.info.minor_vers = 1; + m_response.data.info.major_vers = 2; + m_response.data.info.ROM_cksum = uint16_to_le(3); + m_response.data.info.RAM_sz = uint16_to_le(4); + m_response.data.info.free_ofs = uint16_to_le(5); + m_response.data.info.free_seg = uint16_to_le(6); + break; + + case CMD_LOAD_MULTICAST_LIST:// 0x0b + if (command_pcp.length > sizeof(m_multicast_list) + || (command_pcp.length % ETHERNET_ADDR_SIZE) != 0) + { + LOG(("CMD_LOAD_MULTICAST_LIST - unexpected data size %d", command_pcp.length)); + } + else + { + memset(m_multicast_list, 0, sizeof(m_multicast_list)); + memcpy(m_multicast_list, command_pcp.data.multicast, command_pcp.length- 2); + set_filter_list(); + } + break; + + case CMD_SET_STATION_ADDRESS: // 0x10 + if (command_pcp.length != sizeof(m_station_address)) + { + LOG(("CMD_SET_STATION_ADDRESS - unexpected data size %d", command_pcp.length)); + memset(m_station_address, 0, sizeof(m_station_address)); + } + else + { + memcpy(m_station_address, command_pcp.data.eth_addr, command_pcp.length); + } + set_filter_list(); + set_mac((char *) m_station_address); + break; + + case CMD_MC_17: // 0x17 + m_microcode_running = 1; + break; + + case CMD_DOWNLOAD_PROGRAM: // 0x0d + UINT16 mc_version = m_program_buffer.get_word(1); + switch (mc_version) + { + case APOLLO_MC_VERSION_SR10_2: + case APOLLO_MC_VERSION_SR10_4: + m_microcode_version = mc_version; + break; + default: + m_microcode_version = 0; + LOG(("CMD_DOWNLOAD_PROGRAM - unexpected microcode version %04x", mc_version)); + break; + } + // return microcode version as program id + m_response.length = 2; + m_response.data.raw[0] = m_microcode_version & 0xff; + m_response.data.raw[1] = (m_microcode_version >> 8) & 0xff; + break; + } + + m_response_index = 0; + m_response_length = m_response.length + 2; + + m_status |= ACRF; /* set adapter command register full */ + if (m_control & CMDE) + { + set_interrupt(ASSERT_LINE); + } +} + +/*************************************************************************** + ethernet_packet_is_for_me - check if ethernet address is for me + ***************************************************************************/ + +int threecom3c505_device::ethernet_packet_is_for_me(const UINT8 mac_address[]) +{ + // tcpdump -i eth0 -q ether host 08:00:1e:01:ae:a5 or ether broadcast or ether dst 09:00:1e:00:00:00 or ether dst 09:00:1e:00:00:01 + // wireshark filter: eth.addr eq 08:00:1e:01:ae:a5 or eth.dst eq ff:ff:ff:ff:ff:ff or eth.dst eq 09:00:1e:00:00:00 or eth.dst eq 09:00:1e:00:00:01 + + int i; + static const UINT8 broadcast_address[ETHERNET_ADDR_SIZE] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + + // accept all packets if RECV_PROMISC is set + if (m_i82586_config & RECV_PROMISC) + { + return 1; + } + + // skip Ethernet broadcast packets if RECV_BROAD is not set + if (!(m_i82586_config & RECV_BROAD) && memcmp(mac_address, + broadcast_address, ETHERNET_ADDR_SIZE) == 0) + { + return 0; + } + + // skip Ethernet multicast packets if RECV_MULTI is not set + if (!(m_i82586_config & RECV_MULTI) && (mac_address[0] & 0x01) != 0) + { + return 0; + } + + for (i = 0; i + ETHERNET_ADDR_SIZE < sizeof(m_filter_list); i += ETHERNET_ADDR_SIZE) + { + if (memcmp(mac_address, m_filter_list + i, ETHERNET_ADDR_SIZE) == 0) + { + return 1; + } + } + for (i = 0; i + ETHERNET_ADDR_SIZE < sizeof(m_multicast_list); i += ETHERNET_ADDR_SIZE) + { + if (memcmp(mac_address, m_multicast_list + i, ETHERNET_ADDR_SIZE) == 0) + { + return 1; + } + } + return 0; +} + +/*************************************************************************** + recv_cb - receive callback - receive and process an ethernet packet + ***************************************************************************/ + +void threecom3c505_device::recv_cb(UINT8 *data, int length) +{ + if (length < ETHERNET_ADDR_SIZE || !ethernet_packet_is_for_me(data)) + { + // skip packet + } + else if (!m_rx_fifo.put(data, length)) + { + m_netstat.tot_recv++; + m_netstat.err_ovrrun++; + // fifo overrun + LOG1(("recv_cb: data_length=%x !!! RX FIFO OVERRUN !!!", length)); + + } + else + { + m_netstat.tot_recv++; + LOG2(("recv_cb: data_length=%x m_rx_pending=%d", length, m_rx_pending)); + + do_receive_command(); + } +} + +/*************************************************************************** + write_command_port +***************************************************************************/ + +void threecom3c505_device::write_command_port(UINT8 data) +{ + LOG2(("writing 3C505 command port %02x - m_status=%02x m_control=%02x m_command_index=%02x", + data, m_status, m_control, m_command_index)); + + if (m_command_index == 0) + { + switch (data) + { + case 0: + LOG2(("!!! writing 3C505 Command Register = %02x", data)); + // spurious data; reset? + break; + + case CMD_TRANSMIT_PACKET_F9: + // read data length from data port (not from command port) + m_tx_data_buffer.reset(); + m_status |= HRDY; /* data register ready */ + m_command_buffer[m_command_index++] = data; + set_command_pending(1); + break; + + default: + m_command_buffer[m_command_index++] = data; + set_command_pending(1); + break; + } + } + else if ((m_control & HSF_PCB_MASK) != HSF_PCB_END) + { + m_command_buffer[m_command_index++] = data; + } + else + { + m_status &= ~ASF_PCB_MASK; + m_status |= (data == m_command_index) ? ASF_PCB_END : ASF_PCB_NAK; + + log_command(); + + switch (m_command_buffer[0]) + { + case CMD_TRANSMIT_PACKET_18: + // read transmit data into m_tx_data_buffer + m_tx_data_buffer.reset(); + m_tx_data_length = m_command_buffer[2] + (m_command_buffer[3] << 8); + m_status |= HRDY; /* data register ready */ + break; + + case CMD_TRANSMIT_PACKET: + // read transmit data into m_tx_data_buffer + m_tx_data_buffer.reset(); + m_tx_data_length = m_command_buffer[6] + (m_command_buffer[7] << 8); + m_status |= HRDY; /* data register ready */ + break; + + case CMD_DOWNLOAD_PROGRAM: + // read program data into m_program_buffer + m_program_buffer.reset(); + m_program_length = m_command_buffer[2] + (m_command_buffer[3] << 8); + m_status |= HRDY; /* data register ready */ + break; + + case CMD_NETWORK_STATISTICS: // 0x0a + case CMD_EXECUTE_PROGRAM: // 0x0e + case CMD_ADAPTER_INFO: // 0x11 + // delay command execution + m_do_command_timer->adjust(attotime::from_usec(100)); + break; + + default: + do_command(); + break; + } + } + + m_status |= HCRE; /* command register empty */ +} + +/*************************************************************************** + read_command_port + ***************************************************************************/ + +UINT8 threecom3c505_device::read_command_port() +{ + UINT8 data; + + // the interrupt request is cleared when the Command Register is read + set_interrupt(CLEAR_LINE); + + if (m_response_index == 0) + { + data = m_response.command; + } + else if (m_response_index == 1) + { + data = m_response.length; + } + else if (m_response_index < m_response_length) + { + data = m_response.data.raw[m_response_index - 2]; + } + else if (m_response_index == m_response_length) + { + data = m_response.length + 2; + } + else if (m_response_index == m_response_length + 1 /*&& m_microcode_running*/) + { + // FIXME: special for SR10.4 microcode, content doesn't matter? + data = 0; // ? + m_response_index++; + + m_status &= ~ACRF; /* the adapter command register is no longer full */ + + LOG2(("read_command_port: !!! reading 3C505 Command Register = %02x - m_status=%02x m_control=%02x", + data, m_status, m_control)); + + // wait for nak in control register + set_command_pending(2); + } + else + { + // should never happen + data = 0; // 0xff; + LOG(("read_command_port: unexpected reading Command Register at index %04x", m_response_index)); + } + + if (m_response_index <= m_response_length + 1) + { + if (++m_response_index == m_response_length) + { + m_status = (m_status & ~ASF_PCB_MASK) | ASF_PCB_END; + } + else if (m_response_index == m_response_length + 1) + { + log_response(); + + switch (m_response.command) + { + case CMD_MC_E1_RESPONSE: + m_status |= HRDY; /* data register ready */ + // prepend data length + m_rx_data_index = -2; + break; + + case CMD_RECEIVE_PACKET_COMPLETE: + m_status |= HRDY; /* data register ready */ + m_rx_data_index = 0; + break; + + case CMD_TRANSMIT_PACKET_COMPLETE: + case CMD_TRANSMIT_PACKET_18_COMPLETE: + m_netstat.tot_xmit++; + + if (!send(m_tx_data_buffer.get_data(), m_tx_data_buffer.get_length())) + { + // FIXME: failed to send the Ethernet packet + LOG(("read_command_port(): !!! failed to send Ethernet packet")); + } + + if (!tx_data(this, m_tx_data_buffer.get_data(), m_tx_data_buffer.get_length())) + { + // FIXME: failed to transmit the Ethernet packet + LOG(("read_command_port(): !!! failed to transmit Ethernet packet")); + } + + m_tx_data_buffer.reset(); + if (m_command_buffer[0] != CMD_TRANSMIT_PACKET_F9) + { + set_command_pending(2); + } + break; + + case CMD_DOWNLOAD_PROGRAM_RESPONSE: + m_program_buffer.reset(); + set_command_pending(2); + break; + + default: + set_command_pending(2); + break; + } + } + } + return data; +} + +/*************************************************************************** + write_data_port + ***************************************************************************/ + +void threecom3c505_device::write_data_port(UINT8 data) +{ + if (m_control & FLSH) + { + // flush input data + } + else if ((m_status & HRDY) == 0) + { + // this happened in ether.dex Test 20/1 + LOG(("write_data_port: failed to write tx data (data register not ready), data length=%x status=%x", + m_tx_data_buffer.get_length(), m_status)); + } + +#if 0 + else if (m_command_buffer[0] == CMD_MC_F8) + { + // FIXME: what does it do? + LOG(("write_data_port: !!! TODO: CMD_MC_F8 !!! command=%x data=%02x", m_command_buffer[0], data)); + } +#endif + + else if (m_command_buffer[0] == CMD_TRANSMIT_PACKET_F9) + { + switch (m_command_index) + { + case 1: + m_command_buffer[m_command_index++] = data; + break; + case 2: + m_command_buffer[m_command_index++] = data; + m_tx_data_length = m_command_buffer[1] + (m_command_buffer[2] << 8); + log_command(); + break; + default: + if (!m_tx_data_buffer.append(data)) + { + LOG(("write_data_port: failed to write tx data (buffer size exceeded), data length=%x", + m_tx_data_buffer.get_length())); + } + if (m_tx_data_buffer.get_length() == m_tx_data_length) + { + // CMD_TRANSMIT_PACKET_COMPLETE + m_tx_data_buffer.log("Tx Data"); + do_command(); + } + break; + } + } + else if (m_command_buffer[0] == CMD_TRANSMIT_PACKET || // + m_command_buffer[0] == CMD_TRANSMIT_PACKET_18) + { + if (!m_tx_data_buffer.append(data)) + { + LOG(("write_data_port: failed to write tx data (buffer size exceeded), data length=%x", + m_tx_data_buffer.get_length())); + } + + if (m_tx_data_buffer.get_length() == m_tx_data_length) + { + // CMD_TRANSMIT_PACKET_COMPLETE + m_tx_data_buffer.log("Tx Data"); + do_command(); + } + } + else if (m_command_buffer[0] == CMD_DOWNLOAD_PROGRAM) + { + if (!m_program_buffer.append(data)) + { + LOG(("write_data_port: failed to write program data (buffer size exceeded), data length=%x", + m_program_buffer.get_length())); + } + + if (m_program_buffer.get_length() == m_program_length) + { + m_program_buffer.log("Program Data"); + do_command(); + } + } + else if (m_tx_data_buffer.get_length() < PORT_DATA_FIFO_SIZE) + { + // write to data fifo + if (!m_tx_data_buffer.append(data)) + { + LOG(("write_data_port: failed to write tx data (buffer size exceeded), data length=%x", + m_tx_data_buffer.get_length())); + } + } + else + { + LOG(("write_data_port: unexpected command %02x data=%02x", m_command_buffer[0], data)); + } + + if (m_command_buffer[0] != CMD_DOWNLOAD_PROGRAM && + m_tx_data_buffer.get_length() >= PORT_DATA_FIFO_SIZE + && m_tx_data_buffer.get_length() >= m_tx_data_length) + { + m_status &= ~HRDY; /* data register not ready */ + if (m_tx_data_buffer.get_length() > PORT_DATA_FIFO_SIZE + && m_tx_data_buffer.get_length() > m_tx_data_length) + { + LOG(("write_data_port: port_data tx fifo exhausted, data length=%x status=%x", + m_tx_data_buffer.get_length(), m_status)); + } + } +} + +/*************************************************************************** + read_data_port + ***************************************************************************/ + +UINT8 threecom3c505_device::read_data_port() +{ + UINT8 data; + UINT16 data_length = m_rx_data_buffer.get_length(); + // DomainOS will read words (i.e. even number of bytes); must handle packets with odd byte length + UINT16 even_data_length = (data_length + 1) & ~1; + + if (m_rx_data_index < even_data_length) + { + // eventually prepend data length (for CMD_MC_E1_RESPONSE) + data = m_rx_data_index == -2 ? (data_length & 0xff) : // + m_rx_data_index == -1 ? (data_length << 8) : // + m_rx_data_buffer.get(m_rx_data_index); + + m_rx_data_index++; + + if (m_rx_data_index == even_data_length) + { + m_status &= ~HRDY; /* data register no longer ready */ + m_rx_data_buffer.log("Rx Data"); + m_rx_data_buffer.reset(); + set_command_pending(2); + } + } + else + { + // FIXME: should never happen + data = 0xff; + LOG(("read_data_port: unexpected reading data at index %04x)", m_rx_data_index)); + } + return data; +} + +/*************************************************************************** + write_control_port + ***************************************************************************/ + +void threecom3c505_device::write_control_port(UINT8 data) +{ + switch (data & (ATTN | FLSH)) + { + case ATTN: + LOG2(("write_control_port %02x - Soft Reset", data)); + // TODO: soft reset + break; + + case FLSH: + LOG2(("write_control_port %02x - Flush Data Register", data)); + // flush data register + if (data & DIR_) + { + m_status &= ~HRDY; /* data register not ready */ + } + else + { + // download to adapter + m_status |= HRDY; /* data register ready */ + + // flush data register (reset tx data fifo) + // m_tx_data_length = 0; + m_tx_data_buffer.reset(); + } + break; + + case ATTN | FLSH: + LOG2(("write_control_port %02x - Reset Adapter", data)); + device_reset(); + break; + + case 0: + LOG2(("write_control_port %02x", data)); + + // end reset + if ((m_control & (ATTN | FLSH)) == (ATTN | FLSH)) + { + m_status |= ASF_PCB_END; + m_status |= HRDY; /* 20 byte data fifo is empty */ + } + + if (data == DIR_) + { + // why?? dex ether 20 expects HRDY + m_status |= HRDY; /* data register ready */ + } + break; + } + + // propagate DIR_ from Control to Status register + m_status = (m_status & ~DIR_) | (data & DIR_); + + switch (data & HSF_PCB_MASK) + { + case HSF_PCB_ACK: // HSF1 + if (m_wait_for_ack) + { + set_command_pending(0); + } + break; + + case HSF_PCB_END: // (HSF2|HSF1) + m_status &= ~ACRF; /* adapter command register is not full */ + // fall through + + case HSF_PCB_NAK: // HSF2 + if (m_microcode_running) + { + if (m_wait_for_nak) + { + set_command_pending(0); + } + m_status = (m_status & ~ASF_PCB_MASK) | ASF_PCB_ACK; + } + break; + + default: // 0 + m_command_index = 0; + m_status |= HCRE; /* host command register is empty */ + break; + } + + m_control = data; +} + +/*************************************************************************** + read_status_port + ***************************************************************************/ + +UINT8 threecom3c505_device::read_status_port() +{ + UINT8 data = m_status; + m_status &= ~ASF_PCB_MASK; + + switch (data & ASF_PCB_MASK) + { + case ASF_PCB_END: + m_status |= ASF_PCB_ACK; + break; + } + return data; +} + + +/*************************************************************************** + write_port + ***************************************************************************/ + +WRITE16_MEMBER(threecom3c505_device::write) +{ + // make byte offset + offset *= 2; + + m_reg[offset & 0x0f] = data; + LOG2(("writing 3C505 Register at offset=%02x with mem_mask=%04x = %04x", offset, mem_mask, data)); + + switch (offset) + { + case PORT_COMMAND: /* 0x00 read/write, 8-bit */ + write_command_port(data); + break; + case PORT_AUXDMA: /* 0x02 write only, 8-bit */ + break; + case PORT_DATA: /* 0x04 read/write, 16-bit */ + write_data_port(data & 0xff); + write_data_port(data >> 8); + break; + case PORT_CONTROL: /* 0x06 read/write, 8-bit */ + write_control_port(data); + break; + default: + break; + } +} + +/*************************************************************************** + read_port + ***************************************************************************/ + +READ16_MEMBER(threecom3c505_device::read) +{ + // data to omit excessive logging + static UINT16 last_data = 0xff; + static UINT32 last_pc = 0; + + // make byte offset + offset *= 2; + + UINT16 data = m_reg[offset & 0x0f]; + switch (offset) + { + case PORT_COMMAND: /* 0x00 read/write, 8-bit */ + data = read_command_port(); + break; + case PORT_STATUS: /* 0x02 read only, 8-bit */ + data = read_status_port(); + + // omit excessive logging + if (data == last_data) + { + UINT32 pc = space.device().safe_pcbase(); + if (pc == last_pc) + { + return data; + } + last_pc = pc; + } + last_data = data; + break; + case PORT_DATA: /* 0x04 read/write, 16-bit */ + data = read_data_port(); + data |= (read_data_port() << 8); + break; + case PORT_CONTROL: /* 0x06 read/write, 8-bit */ + data = m_control; + break; + default: + break; + } + + LOG2(("reading 3C505 Register at offset=%02x with mem_mask=%04x = %04x", offset, mem_mask, data)); + + return data; +} + +void threecom3c505_device::set_verbose(int on_off) +{ + verbose = on_off == 0 ? 0 : VERBOSE > 1 ? VERBOSE : 1; +} + +int threecom3c505_device::tx_data(device_t *device, const UINT8 data[], int length) +{ + LOG1(("threecom3c505_device::tx_data length=%d", length)); + return 1; +} + +int threecom3c505_device::setfilter(device_t *device, int node_id) +{ + return 0; +} diff --git a/src/devices/bus/isa/3c505.h b/src/devices/bus/isa/3c505.h new file mode 100644 index 00000000000..929089628ef --- /dev/null +++ b/src/devices/bus/isa/3c505.h @@ -0,0 +1,283 @@ +// license:BSD-3-Clause +// copyright-holders:Hans Ostermeyer,R. Belmont +/* + * threecom3c505.h - 3COM 3C505 ethernet controller + * + * Created on: August 27, 2010 + * Author: Hans Ostermeyer + * + */ + +#pragma once + +#ifndef THREECOM3C505_H_ +#define THREECOM3C505_H_ + +#include "emu.h" +#include "bus/isa/isa.h" + +#define CMD_BUFFER_SIZE 100 +#define ETH_BUFFER_SIZE 2048 +#define PGM_BUFFER_SIZE 0x2000 + +#define ETHERNET_ADDR_SIZE 6 /* size of ethernet addr */ + +#define RX_FIFO_SIZE 32 + +// ======================> PCB data structure + +#pragma pack(1) + +struct Memconf +{ + UINT16 cmd_q, rcv_q, mcast, frame, rcv_b, progs; +}; + +struct Rcv_pkt +{ + UINT16 buf_ofs, buf_seg, buf_len, timeout; +}; + +struct Xmit_pkt +{ + UINT16 buf_ofs, buf_seg, pkt_len; +}; + +struct Rcv_resp +{ + UINT16 buf_ofs, buf_seg, buf_len, pkt_len, timeout, status; + UINT32 timetag; +}; + +struct Xmit_resp +{ + UINT16 buf_ofs, buf_seg, c_stat, status; +}; + +struct Netstat +{ + UINT32 tot_recv, tot_xmit; + UINT16 err_CRC, err_align, err_res, err_ovrrun; +}; + +struct Selftest +{ + UINT16 error; + union + { + UINT16 ROM_cksum; + struct + { + UINT16 ofs, seg; + } RAM; + UINT16 i82586; + } failure; +}; + +struct Info +{ + UINT8 minor_vers, major_vers; + UINT16 ROM_cksum, RAM_sz, free_ofs, free_seg; +}; + +struct Memdump +{ + UINT16 size, off, seg; +}; + +/* + Primary Command Block. The most important data structure. All communication + between the host and the adapter is done with these. (Except for the actual + Ethernet data, which has different packaging.) + */ +struct pcb_struct +{ + UINT8 command; + UINT8 length; + union + { + struct Memconf memconf; + UINT16 configure; + struct Rcv_pkt rcv_pkt; + struct Xmit_pkt xmit_pkt; + UINT8 multicast[10][6]; + UINT8 eth_addr[6]; + INT16 failed; + struct Rcv_resp rcv_resp; + struct Xmit_resp xmit_resp; + struct Netstat netstat; + struct Selftest selftest; + struct Info info; + struct Memdump memdump; + UINT8 raw[62]; + } data; +}; + +#pragma pack() + +// ======================> threecom3c505_device + +class threecom3c505_device: public device_t, + public device_network_interface, + public device_isa16_card_interface +{ +public: + // construction/destruction + threecom3c505_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + threecom3c505_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, UINT32 clock); + + // device register I/O + virtual DECLARE_READ16_MEMBER(read); + virtual DECLARE_WRITE16_MEMBER(write); + + static void set_verbose(int on_off); + + required_ioport m_iobase; + required_ioport m_irqdrq; + required_ioport m_romopts; + + virtual void recv_cb(UINT8 *data, int length); + +protected: + virtual int tx_data(device_t *, const UINT8 *, int); + virtual int setfilter(device_t *, int); + + const char *cpu_context(); + + // device-level overrides + virtual void device_start(); + virtual const rom_entry *device_rom_region() const; + +private: + // device-level overrides + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + virtual ioport_constructor device_input_ports() const; + + class data_buffer_fifo; + + /* data buffer */ + class data_buffer + { + friend class data_buffer_fifo; + + public: + data_buffer(); + void start(threecom3c505_device *device, INT32 size); + void reset(); + int append(UINT8 data); + UINT8 get(int i) { return m_data[i]; }; + UINT16 get_word(int i) { return (m_data[i*2+1] << 8) + m_data[i*2]; }; + int is_empty() {return m_length == 0; }; + int is_full() {return m_length >= m_data.size(); }; + UINT16 get_length() { return m_length; }; + UINT16 get_size() { return m_data.size(); }; + UINT8 *get_data() { return &m_data[0]; }; + void copy(data_buffer *db) const; + void log(const char *title) const; + + private: + const char *cpu_context() { return m_device->cpu_context(); } + + threecom3c505_device *m_device; // pointer back to our device + UINT16 m_length; + dynamic_buffer m_data; + }; + + /* data_buffer fifo (used to buffer the received data) */ + class data_buffer_fifo + { + public: + data_buffer_fifo(); + ~data_buffer_fifo(); + void start(threecom3c505_device *device, INT32 size, INT32 db_size); + void reset(); + int put(const UINT8 data[], const int length); + int get(data_buffer *db); + int is_empty () { return m_get_index == m_put_index; } + int is_full () { return ((m_put_index + 1) % m_size) == m_get_index; } + private: + const char *cpu_context() { return m_device->cpu_context(); } + + threecom3c505_device *m_device; // pointer back to our device + UINT16 m_size; + UINT16 m_count; + UINT16 m_get_index; + UINT16 m_put_index; + data_buffer *m_db[RX_FIFO_SIZE]; + }; + + void set_filter_list(); + void set_interrupt(enum line_state state); + + void log_command(); + void log_response(); + void log_tx_data(); + void log_rx_data(); + + void do_receive_command(); + void set_command_pending(int onoff); + + int ethernet_packet_is_for_me(const UINT8 mac_address[]); + + void write_command_port( UINT8 data); + UINT8 read_command_port(); + void write_data_port( UINT8 data); + UINT8 read_data_port(); + void write_control_port( UINT8 data); + UINT8 read_status_port(); + + void do_command(); + + UINT8 m_reg[16]; + + UINT8 m_status; + UINT8 m_control; + + UINT8 m_command_buffer[CMD_BUFFER_SIZE]; + int m_command_index; + int m_command_pending; + int m_wait_for_ack; + int m_wait_for_nak; + + data_buffer_fifo m_rx_fifo; + + data_buffer m_rx_data_buffer; // the ethernet receive buffer + int m_rx_data_index; + int m_rx_pending; + + data_buffer m_tx_data_buffer; // the ethernet transmit buffer + int m_tx_data_length; + + data_buffer m_program_buffer; // the program data buffer + int m_program_length; + + pcb_struct m_response; + int m_response_length; + int m_response_index; + + pcb_struct m_rcv_response; + + UINT16 m_microcode_version; + UINT16 m_microcode_running; + + UINT16 m_i82586_config; + + struct Netstat m_netstat; + + UINT8 m_station_address[ETHERNET_ADDR_SIZE]; + UINT8 m_multicast_list[ETHERNET_ADDR_SIZE*2]; + UINT8 m_filter_list[ETHERNET_ADDR_SIZE*4]; + + enum line_state irq_state; + + emu_timer * m_do_command_timer; // timer to delay command execution + + bool m_installed; + int m_irq, m_drq; +}; + +// device type definition +extern const device_type ISA16_3C505; + +#endif /* THREECOM3C505_H_ */ diff --git a/src/devices/bus/isa/adlib.c b/src/devices/bus/isa/adlib.c new file mode 100644 index 00000000000..42e2afd9604 --- /dev/null +++ b/src/devices/bus/isa/adlib.c @@ -0,0 +1,87 @@ +// license:BSD-3-Clause +// copyright-holders:Miodrag Milanovic +/*************************************************************************** + + ISA 8 bit Adlib Sound Card + +***************************************************************************/ + +#include "emu.h" +#include "adlib.h" +#include "sound/speaker.h" + +#define ym3812_StdClock 3579545 + +static MACHINE_CONFIG_FRAGMENT( adlib_config ) + MCFG_SPEAKER_STANDARD_MONO("mono") + MCFG_SOUND_ADD("ym3812", YM3812, ym3812_StdClock) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 3.00) +MACHINE_CONFIG_END + +READ8_MEMBER( isa8_adlib_device::ym3812_16_r ) +{ + UINT8 retVal = 0xff; + switch(offset) + { + case 0 : retVal = m_ym3812->status_port_r( space, offset ); break; + } + return retVal; +} + +WRITE8_MEMBER( isa8_adlib_device::ym3812_16_w ) +{ + switch(offset) + { + case 0 : m_ym3812->control_port_w( space, offset, data ); break; + case 1 : m_ym3812->write_port_w( space, offset, data ); break; + } +} + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type ISA8_ADLIB = &device_creator; + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor isa8_adlib_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( adlib_config ); +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// isa8_adlib_device - constructor +//------------------------------------------------- + +isa8_adlib_device::isa8_adlib_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, ISA8_ADLIB, "Ad Lib Sound Card", tag, owner, clock, "isa_adlib", __FILE__), + device_isa8_card_interface( mconfig, *this ), + m_ym3812(*this, "ym3812") +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void isa8_adlib_device::device_start() +{ + set_isa_device(); + m_isa->install_device(0x0388, 0x0389, 0, 0, read8_delegate( FUNC(isa8_adlib_device::ym3812_16_r), this ), write8_delegate( FUNC(isa8_adlib_device::ym3812_16_w), this ) ); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void isa8_adlib_device::device_reset() +{ +} diff --git a/src/devices/bus/isa/adlib.h b/src/devices/bus/isa/adlib.h new file mode 100644 index 00000000000..873b60a7ad1 --- /dev/null +++ b/src/devices/bus/isa/adlib.h @@ -0,0 +1,44 @@ +// license:BSD-3-Clause +// copyright-holders:Miodrag Milanovic +#pragma once + +#ifndef __ISA_ADLIB_H__ +#define __ISA_ADLIB_H__ + +#include "emu.h" +#include "isa.h" +#include "sound/3812intf.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> isa8_adlib_device + +class isa8_adlib_device : + public device_t, + public device_isa8_card_interface +{ +public: + // construction/destruction + isa8_adlib_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + + DECLARE_READ8_MEMBER(ym3812_16_r); + DECLARE_WRITE8_MEMBER(ym3812_16_w); +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); +private: + // internal state + required_device m_ym3812; +}; + + +// device type definition +extern const device_type ISA8_ADLIB; + +#endif /* __ISA_ADLIB_H__ */ diff --git a/src/devices/bus/isa/aga.c b/src/devices/bus/isa/aga.c new file mode 100644 index 00000000000..1d321533391 --- /dev/null +++ b/src/devices/bus/isa/aga.c @@ -0,0 +1,1008 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +/***************************************************************************** + * + * aga.c + * + ****************************************************************************/ +#include "aga.h" +#include "video/cgapal.h" + +#define CGA_HCLK (XTAL_14_31818MHz/8) +#define CGA_LCLK (XTAL_14_31818MHz/16) + +#define AGA_SCREEN_NAME "screen" +#define AGA_MC6845_NAME "mc6845_aga" + +enum +{ + MDA_TEXT_INTEN = 0, + MDA_TEXT_BLINK, + CGA_TEXT_INTEN, + CGA_TEXT_INTEN_ALT, + CGA_TEXT_BLINK, + CGA_TEXT_BLINK_ALT, + CGA_GFX_1BPP, + CGA_GFX_2BPP, + CGA_GFX_4BPPL, + CGA_GFX_4BPPH +}; + +static INPUT_PORTS_START( aga ) + PORT_START( "cga_config" ) + PORT_CONFNAME( 0x03, 0x00, "CGA character set") + PORT_CONFSETTING(0x00, DEF_STR( Normal )) + PORT_CONFSETTING(0x01, "Alternative") + PORT_CONFNAME( 0x1C, 0x00, "CGA monitor type") + PORT_CONFSETTING(0x00, "Colour RGB") + PORT_CONFSETTING(0x04, "Mono RGB") + PORT_CONFSETTING(0x08, "Colour composite") + PORT_CONFSETTING(0x0C, "Television") + PORT_CONFSETTING(0x10, "LCD") + PORT_CONFNAME( 0xE0, 0x00, "CGA chipset") + PORT_CONFSETTING(0x00, "IBM") + PORT_CONFSETTING(0x20, "Amstrad PC1512") + PORT_CONFSETTING(0x40, "Amstrad PPC512") + PORT_CONFSETTING(0x60, "ATI") + PORT_CONFSETTING(0x80, "Paradise") +INPUT_PORTS_END + +#define CGA_MONITOR (m_cga_config->read()&0x1C) +#define CGA_MONITOR_COMPOSITE 0x08 /* Colour composite */ + +const device_type ISA8_AGA = &device_creator; + +//------------------------------------------------- +// isa8_aga_device - constructor +//------------------------------------------------- + +isa8_aga_device::isa8_aga_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t( mconfig, ISA8_AGA, "AGA", tag, owner, clock, "aga", __FILE__), + device_isa8_card_interface(mconfig, *this), + m_palette(*this, "palette"), + m_mc6845(*this, AGA_MC6845_NAME), + m_cga_config(*this, "cga_config"), + m_update_row_type(-1), + m_mda_mode_control(0), + m_mda_status(0), + m_cga_mode_control(0), + m_cga_color_select(0), + m_cga_status(0), + m_framecnt(0), + m_vsync(0), + m_hsync(0) +{ +} + +isa8_aga_device::isa8_aga_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_isa8_card_interface(mconfig, *this), + m_palette(*this, "palette"), + m_mc6845(*this, AGA_MC6845_NAME), + m_cga_config(*this, "cga_config"), + m_update_row_type(-1), + m_mda_mode_control(0), + m_mda_status(0), + m_cga_mode_control(0), + m_cga_color_select(0), + m_cga_status(0), + m_framecnt(0), + m_vsync(0), + m_hsync(0) +{ +} +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void isa8_aga_device::device_start() +{ + if (m_palette != NULL && !m_palette->started()) + throw device_missing_dependencies(); + + m_mode = AGA_COLOR; + m_mda_chr_gen = memregion("gfx1")->base() + 0x1000; + m_cga_chr_gen = memregion("gfx1")->base(); + m_videoram = auto_alloc_array(machine(), UINT8, 0x10000); + + set_isa_device(); + m_isa->install_memory(0xb0000, 0xbffff, 0, 0, read8_delegate(FUNC(isa8_aga_device::pc_aga_videoram_r),this), write8_delegate(FUNC(isa8_aga_device::pc_aga_videoram_w),this)); + m_isa->install_device(0x3b0, 0x3bf, 0, 0, read8_delegate( FUNC(isa8_aga_device::pc_aga_mda_r), this ), write8_delegate( FUNC(isa8_aga_device::pc_aga_mda_w), this ) ); + m_isa->install_device(0x3d0, 0x3df, 0, 0, read8_delegate( FUNC(isa8_aga_device::pc_aga_cga_r), this ), write8_delegate( FUNC(isa8_aga_device::pc_aga_cga_w), this ) ); + + /* Initialise the cga palette */ + int i; + + for ( i = 0; i < CGA_PALETTE_SETS * 16; i++ ) + { + m_palette->set_pen_color( i, cga_palette[i][0], cga_palette[i][1], cga_palette[i][2] ); + } + + i = 0x8000; + for ( int r = 0; r < 32; r++ ) + { + for ( int g = 0; g < 32; g++ ) + { + for ( int b = 0; b < 32; b++ ) + { + m_palette->set_pen_color( i, r << 3, g << 3, b << 3 ); + i++; + } + } + } + + UINT8 *gfx = &memregion("gfx1")->base()[0x8000]; + /* just a plain bit pattern for graphics data generation */ + for (i = 0; i < 256; i++) + gfx[i] = i; +} + +ROM_START( aga ) + ROM_REGION(0x8100,"gfx1", 0) + ROM_LOAD("50146 char d1.0 euro.u16", 0x00000, 0x02000, CRC(1305dcf5) SHA1(aca488a16ae4ff05a1f4d14574379ff49cd48343)) //D1.0 +ROM_END + +const rom_entry *isa8_aga_device::device_rom_region() const +{ + return ROM_NAME( aga ); +} + +ioport_constructor isa8_aga_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( aga ); +} + + + +const device_type ISA8_AGA_PC200 = &device_creator; + +//------------------------------------------------- +// isa8_aga_pc200_device - constructor +//------------------------------------------------- + +isa8_aga_pc200_device::isa8_aga_pc200_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + isa8_aga_device( mconfig, ISA8_AGA_PC200, "AGA PC200", tag, owner, clock, "aga_pc200", __FILE__), + m_port8(0), + m_portd(0), + m_porte(0) +{ +} + +ROM_START( aga_pc200 ) + ROM_REGION(0x08100,"gfx1", 0) + ROM_LOAD("40109.ic159", 0x00000, 0x08000, CRC(a8b67639) SHA1(99663bfb61798526e092205575370c2ad34249a1)) +ROM_END + +const rom_entry *isa8_aga_pc200_device::device_rom_region() const +{ + return ROM_NAME( aga_pc200 ); +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void isa8_aga_pc200_device::device_start() +{ + if (m_palette != NULL && !m_palette->started()) + throw device_missing_dependencies(); + + m_mode = AGA_COLOR; + m_mda_chr_gen = memregion("gfx1")->base(); + m_cga_chr_gen = memregion("gfx1")->base() + 0x1000; + m_videoram = auto_alloc_array(machine(), UINT8, 0x10000); + + set_isa_device(); + m_isa->install_memory(0xb0000, 0xbffff, 0, 0, read8_delegate(FUNC(isa8_aga_pc200_device::pc200_videoram_r),this), write8_delegate(FUNC(isa8_aga_pc200_device::pc200_videoram_w),this)); + m_isa->install_device(0x3b0, 0x3bf, 0, 0, read8_delegate( FUNC(isa8_aga_device::pc_aga_mda_r), this ), write8_delegate( FUNC(isa8_aga_device::pc_aga_mda_w), this ) ); + m_isa->install_device(0x3d0, 0x3df, 0, 0, read8_delegate( FUNC(isa8_aga_pc200_device::pc200_cga_r), this ), write8_delegate( FUNC(isa8_aga_pc200_device::pc200_cga_w), this ) ); + + /* Initialise the cga palette */ + int i; + + for ( i = 0; i < CGA_PALETTE_SETS * 16; i++ ) + { + m_palette->set_pen_color( i, cga_palette[i][0], cga_palette[i][1], cga_palette[i][2] ); + } + + i = 0x8000; + for ( int r = 0; r < 32; r++ ) + { + for ( int g = 0; g < 32; g++ ) + { + for ( int b = 0; b < 32; b++ ) + { + m_palette->set_pen_color( i, r << 3, g << 3, b << 3 ); + i++; + } + } + } + + UINT8 *gfx = &memregion("gfx1")->base()[0x8000]; + /* just a plain bit pattern for graphics data generation */ + for (i = 0; i < 256; i++) + gfx[i] = i; +} + +WRITE_LINE_MEMBER( isa8_aga_device::hsync_changed ) +{ + m_hsync = state ? 1 : 0; +} + + +WRITE_LINE_MEMBER( isa8_aga_device::vsync_changed ) +{ + m_vsync = state ? 8 : 0; + if ( state ) + { + m_framecnt++; + } +} + + +MC6845_UPDATE_ROW( isa8_aga_device::aga_update_row ) +{ + if (m_update_row_type == -1) + return; + + switch (m_update_row_type) + { + case MDA_TEXT_INTEN: + mda_text_inten_update_row(bitmap, cliprect, ma, ra, y, x_count, cursor_x, de, hbp, vbp); + break; + case MDA_TEXT_BLINK: + mda_text_blink_update_row(bitmap, cliprect, ma, ra, y, x_count, cursor_x, de, hbp, vbp); + break; + case CGA_TEXT_INTEN: + cga_text_inten_update_row(bitmap, cliprect, ma, ra, y, x_count, cursor_x, de, hbp, vbp); + break; + case CGA_TEXT_INTEN_ALT: + cga_text_inten_alt_update_row(bitmap, cliprect, ma, ra, y, x_count, cursor_x, de, hbp, vbp); + break; + case CGA_TEXT_BLINK: + cga_text_blink_update_row(bitmap, cliprect, ma, ra, y, x_count, cursor_x, de, hbp, vbp); + break; + case CGA_TEXT_BLINK_ALT: + cga_text_blink_alt_update_row(bitmap, cliprect, ma, ra, y, x_count, cursor_x, de, hbp, vbp); + break; + case CGA_GFX_1BPP: + cga_gfx_1bpp_update_row(bitmap, cliprect, ma, ra, y, x_count, cursor_x, de, hbp, vbp); + break; + case CGA_GFX_2BPP: + cga_gfx_2bpp_update_row(bitmap, cliprect, ma, ra, y, x_count, cursor_x, de, hbp, vbp); + break; + case CGA_GFX_4BPPL: + cga_gfx_4bppl_update_row(bitmap, cliprect, ma, ra, y, x_count, cursor_x, de, hbp, vbp); + break; + case CGA_GFX_4BPPH: + cga_gfx_4bpph_update_row(bitmap, cliprect, ma, ra, y, x_count, cursor_x, de, hbp, vbp); + break; + } +} + + +MACHINE_CONFIG_FRAGMENT( pcvideo_aga ) + MCFG_SCREEN_ADD( AGA_SCREEN_NAME, RASTER ) + MCFG_SCREEN_RAW_PARAMS( XTAL_14_31818MHz,912,0,640,262,0,200 ) + MCFG_SCREEN_UPDATE_DEVICE( AGA_MC6845_NAME, mc6845_device, screen_update ) + + MCFG_PALETTE_ADD( "palette", /* CGA_PALETTE_SETS * 16*/ 65536 ) + + MCFG_MC6845_ADD(AGA_MC6845_NAME, MC6845, AGA_SCREEN_NAME, XTAL_14_31818MHz/8) + MCFG_MC6845_SHOW_BORDER_AREA(false) + MCFG_MC6845_CHAR_WIDTH(8) + MCFG_MC6845_UPDATE_ROW_CB(isa8_aga_device, aga_update_row) + MCFG_MC6845_OUT_HSYNC_CB(WRITELINE(isa8_aga_device, hsync_changed)) + MCFG_MC6845_OUT_VSYNC_CB(WRITELINE(isa8_aga_device, vsync_changed)) +MACHINE_CONFIG_END + +machine_config_constructor isa8_aga_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( pcvideo_aga ); +} + +/************************************* + * + * row update functions + * + *************************************/ + +/* colors need fixing in the mda_text_* functions ! */ +MC6845_UPDATE_ROW( isa8_aga_device::mda_text_inten_update_row ) +{ + const rgb_t *palette = m_palette->palette()->entry_list_raw(); + UINT8 *videoram = m_videoram; + UINT32 *p = &bitmap.pix32(y); + UINT16 chr_base = ( ra & 0x08 ) ? 0x800 | ( ra & 0x07 ) : ra; + int i; + + if ( y == 0 ) logerror("mda_text_inten_update_row\n"); + for ( i = 0; i < x_count; i++ ) { + UINT16 offset = ( ( ma + i ) << 1 ) & 0x0FFF; + UINT8 chr = videoram[ offset ]; + UINT8 attr = videoram[ offset + 1 ]; + UINT8 data = m_mda_chr_gen[ chr_base + chr * 8 ]; + UINT8 fg = ( attr & 0x08 ) ? 3 : 2; + UINT8 bg = 0; + + if ( ( attr & ~0x88 ) == 0 ) { + data = 0x00; + } + + switch( attr ) { + case 0x70: + bg = 2; + fg = 0; + break; + case 0x78: + bg = 2; + fg = 1; + break; + case 0xF0: + bg = 3; + fg = 0; + break; + case 0xF8: + bg = 3; + fg = 1; + break; + } + + if ( i == cursor_x || ( attr & 0x07 ) == 0x01 ) { + data = 0xFF; + } + + *p = palette[( data & 0x80 ) ? fg : bg]; p++; + *p = palette[( data & 0x40 ) ? fg : bg]; p++; + *p = palette[( data & 0x20 ) ? fg : bg]; p++; + *p = palette[( data & 0x10 ) ? fg : bg]; p++; + *p = palette[( data & 0x08 ) ? fg : bg]; p++; + *p = palette[( data & 0x04 ) ? fg : bg]; p++; + *p = palette[( data & 0x02 ) ? fg : bg]; p++; + *p = palette[( data & 0x01 ) ? fg : bg]; p++; + if ( ( chr & 0xE0 ) == 0xC0 ) { + *p = palette[( data & 0x01 ) ? fg : bg]; p++; + } else { + *p = palette[bg]; p++; + } + } +} + + +MC6845_UPDATE_ROW( isa8_aga_device::mda_text_blink_update_row ) +{ + UINT8 *videoram = m_videoram; + const rgb_t *palette = m_palette->palette()->entry_list_raw(); + UINT32 *p = &bitmap.pix32(y); + UINT16 chr_base = ( ra & 0x08 ) ? 0x800 | ( ra & 0x07 ) : ra; + int i; + + if ( y == 0 ) logerror("mda_text_blink_update_row\n"); + for ( i = 0; i < x_count; i++ ) { + UINT16 offset = ( ( ma + i ) << 1 ) & 0x0FFF; + UINT8 chr = videoram[ offset ]; + UINT8 attr = videoram[ offset + 1 ]; + UINT8 data = m_mda_chr_gen[ chr_base + chr * 8 ]; + UINT8 fg = ( attr & 0x08 ) ? 3 : 2; + UINT8 bg = 0; + + if ( ( attr & ~0x88 ) == 0 ) { + data = 0x00; + } + + switch( attr ) { + case 0x70: + case 0xF0: + bg = 2; + fg = 0; + break; + case 0x78: + case 0xF8: + bg = 2; + fg = 1; + break; + } + + if ( i == cursor_x ) { + data = 0xFF; + } else { + if ( ( attr & 0x07 ) == 0x01 ) { + data = 0xFF; + } + if ( ( attr & 0x80 ) && ( m_framecnt & 0x40 ) ) { + data = 0x00; + } + } + + *p = palette[( data & 0x80 ) ? fg : bg]; p++; + *p = palette[( data & 0x40 ) ? fg : bg]; p++; + *p = palette[( data & 0x20 ) ? fg : bg]; p++; + *p = palette[( data & 0x10 ) ? fg : bg]; p++; + *p = palette[( data & 0x08 ) ? fg : bg]; p++; + *p = palette[( data & 0x04 ) ? fg : bg]; p++; + *p = palette[( data & 0x02 ) ? fg : bg]; p++; + *p = palette[( data & 0x01 ) ? fg : bg]; p++; + if ( ( chr & 0xE0 ) == 0xC0 ) { + *p = palette[( data & 0x01 ) ? fg : bg]; p++; + } else { + *p = palette[bg]; p++; + } + } +} + + +MC6845_UPDATE_ROW( isa8_aga_device::cga_text_inten_update_row ) +{ + UINT8 *videoram = m_videoram; + const rgb_t *palette = m_palette->palette()->entry_list_raw(); + UINT32 *p = &bitmap.pix32(y); + int i; + + if ( y == 0 ) logerror("cga_text_inten_update_row\n"); + for ( i = 0; i < x_count; i++ ) { + UINT16 offset = ( ( ma + i ) << 1 ) & 0x3fff; + UINT8 chr = videoram[ offset ]; + UINT8 attr = videoram[ offset +1 ]; + UINT8 data = m_cga_chr_gen[ chr * 16 + ra ]; + UINT16 fg = attr & 0x0F; + UINT16 bg = ( attr >> 4 ) & 0x07; + + if ( i == cursor_x ) { + data = 0xFF; + } + + *p = palette[( data & 0x80 ) ? fg : bg]; p++; + *p = palette[( data & 0x40 ) ? fg : bg]; p++; + *p = palette[( data & 0x20 ) ? fg : bg]; p++; + *p = palette[( data & 0x10 ) ? fg : bg]; p++; + *p = palette[( data & 0x08 ) ? fg : bg]; p++; + *p = palette[( data & 0x04 ) ? fg : bg]; p++; + *p = palette[( data & 0x02 ) ? fg : bg]; p++; + *p = palette[( data & 0x01 ) ? fg : bg]; p++; + } +} + +MC6845_UPDATE_ROW( isa8_aga_device::cga_text_inten_alt_update_row ) +{ + const rgb_t *palette = m_palette->palette()->entry_list_raw(); + UINT8 *videoram = m_videoram; + UINT32 *p = &bitmap.pix32(y); + int i; + + if ( y == 0 ) logerror("cga_text_inten_alt_update_row\n"); + for ( i = 0; i < x_count; i++ ) { + UINT16 offset = ( ( ma + i ) << 1 ) & 0x3fff; + UINT8 chr = videoram[ offset ]; + UINT8 attr = videoram[ offset +1 ]; + UINT8 data = m_cga_chr_gen[ chr * 16 + ra ]; + UINT16 fg = attr & 0x0F; + + if ( i == cursor_x ) { + data = 0xFF; + } + + *p = palette[( data & 0x80 ) ? fg : 0]; p++; + *p = palette[( data & 0x40 ) ? fg : 0]; p++; + *p = palette[( data & 0x20 ) ? fg : 0]; p++; + *p = palette[( data & 0x10 ) ? fg : 0]; p++; + *p = palette[( data & 0x08 ) ? fg : 0]; p++; + *p = palette[( data & 0x04 ) ? fg : 0]; p++; + *p = palette[( data & 0x02 ) ? fg : 0]; p++; + *p = palette[( data & 0x01 ) ? fg : 0]; p++; + } +} + +MC6845_UPDATE_ROW( isa8_aga_device::cga_text_blink_update_row ) +{ + const rgb_t *palette = m_palette->palette()->entry_list_raw(); + UINT8 *videoram = m_videoram; + UINT32 *p = &bitmap.pix32(y); + int i; + + for ( i = 0; i < x_count; i++ ) { + UINT16 offset = ( ( ma + i ) << 1 ) & 0x3fff; + UINT8 chr = videoram[ offset ]; + UINT8 attr = videoram[ offset +1 ]; + UINT8 data = m_cga_chr_gen[ chr * 16 + ra ]; + UINT16 fg = attr & 0x0F; + UINT16 bg = (attr >> 4) & 0x07; + + if ( i == cursor_x ) { + data = 0xFF; + } else { + if ( ( attr & 0x80 ) && ( m_framecnt & 0x10 ) ) { + data = 0x00; + } + } + + *p = palette[( data & 0x80 ) ? fg : bg]; p++; + *p = palette[( data & 0x40 ) ? fg : bg]; p++; + *p = palette[( data & 0x20 ) ? fg : bg]; p++; + *p = palette[( data & 0x10 ) ? fg : bg]; p++; + *p = palette[( data & 0x08 ) ? fg : bg]; p++; + *p = palette[( data & 0x04 ) ? fg : bg]; p++; + *p = palette[( data & 0x02 ) ? fg : bg]; p++; + *p = palette[( data & 0x01 ) ? fg : bg]; p++; + } +} + +MC6845_UPDATE_ROW( isa8_aga_device::cga_text_blink_alt_update_row ) +{ + const rgb_t *palette = m_palette->palette()->entry_list_raw(); + UINT8 *videoram = m_videoram; + UINT32 *p = &bitmap.pix32(y); + int i; + + if ( y == 0 ) logerror("cga_text_blink_alt_update_row\n"); + for ( i = 0; i < x_count; i++ ) { + UINT16 offset = ( ( ma + i ) << 1 ) & 0x3fff; + UINT8 chr = videoram[ offset ]; + UINT8 attr = videoram[ offset +1 ]; + UINT8 data = m_cga_chr_gen[ chr * 16 + ra ]; + UINT16 fg = attr & 0x07; + UINT16 bg = 0; + + if ( i == cursor_x ) { + data = 0xFF; + } else { + if ( ( attr & 0x80 ) && ( m_framecnt & 0x10 ) ) { + data = 0x00; + bg = ( attr >> 4 ) & 0x07; + } + } + + *p = palette[( data & 0x80 ) ? fg : bg]; p++; + *p = palette[( data & 0x40 ) ? fg : bg]; p++; + *p = palette[( data & 0x20 ) ? fg : bg]; p++; + *p = palette[( data & 0x10 ) ? fg : bg]; p++; + *p = palette[( data & 0x08 ) ? fg : bg]; p++; + *p = palette[( data & 0x04 ) ? fg : bg]; p++; + *p = palette[( data & 0x02 ) ? fg : bg]; p++; + *p = palette[( data & 0x01 ) ? fg : bg]; p++; + } +} + +MC6845_UPDATE_ROW( isa8_aga_device::cga_gfx_4bppl_update_row ) +{ + const rgb_t *palette = m_palette->palette()->entry_list_raw(); + UINT8 *videoram = m_videoram; + UINT32 *p = &bitmap.pix32(y); + int i; + + if ( y == 0 ) logerror("cga_gfx_4bppl_update_row\n"); + for ( i = 0; i < x_count; i++ ) { + UINT16 offset = ( ( ( ma + i ) << 1 ) & 0x1fff ) | ( ( y & 1 ) << 13 ); + UINT8 data = videoram[ offset ]; + + *p = palette[data >> 4]; p++; + *p = palette[data >> 4]; p++; + *p = palette[data & 0x0F]; p++; + *p = palette[data & 0x0F]; p++; + + data = videoram[ offset + 1 ]; + + *p = palette[data >> 4]; p++; + *p = palette[data >> 4]; p++; + *p = palette[data & 0x0F]; p++; + *p = palette[data & 0x0F]; p++; + } +} + +MC6845_UPDATE_ROW( isa8_aga_device::cga_gfx_4bpph_update_row ) +{ + UINT8 *videoram = m_videoram; + const rgb_t *palette = m_palette->palette()->entry_list_raw(); + UINT32 *p = &bitmap.pix32(y); + int i; + + if ( y == 0 ) logerror("cga_gfx_4bpph_update_row\n"); + for ( i = 0; i < x_count; i++ ) { + UINT16 offset = ( ( ( ma + i ) << 1 ) & 0x1fff ) | ( ( y & 1 ) << 13 ); + UINT8 data = videoram[ offset ]; + + *p = palette[data >> 4]; p++; + *p = palette[data >> 4]; p++; + *p = palette[data >> 4]; p++; + *p = palette[data >> 4]; p++; + *p = palette[data & 0x0F]; p++; + *p = palette[data & 0x0F]; p++; + *p = palette[data & 0x0F]; p++; + *p = palette[data & 0x0F]; p++; + + data = videoram[ offset + 1 ]; + + *p = palette[data >> 4]; p++; + *p = palette[data >> 4]; p++; + *p = palette[data >> 4]; p++; + *p = palette[data >> 4]; p++; + *p = palette[data & 0x0F]; p++; + *p = palette[data & 0x0F]; p++; + *p = palette[data & 0x0F]; p++; + *p = palette[data & 0x0F]; p++; + } +} + +MC6845_UPDATE_ROW( isa8_aga_device::cga_gfx_2bpp_update_row ) +{ + UINT8 *videoram = m_videoram; + const rgb_t *palette = m_palette->palette()->entry_list_raw(); + UINT32 *p = &bitmap.pix32(y); + int i; + +// if ( y == 0 ) logerror("cga_gfx_2bpp_update_row\n"); + for ( i = 0; i < x_count; i++ ) { + UINT16 offset = ( ( ( ma + i ) << 1 ) & 0x1fff ) | ( ( y & 1 ) << 13 ); + UINT8 data = videoram[ offset ]; + + *p = palette[m_cga_palette_lut_2bpp[ ( data >> 6 ) & 0x03 ]]; p++; + *p = palette[m_cga_palette_lut_2bpp[ ( data >> 4 ) & 0x03 ]]; p++; + *p = palette[m_cga_palette_lut_2bpp[ ( data >> 2 ) & 0x03 ]]; p++; + *p = palette[m_cga_palette_lut_2bpp[ data & 0x03 ]]; p++; + + data = videoram[ offset+1 ]; + + *p = palette[m_cga_palette_lut_2bpp[ ( data >> 6 ) & 0x03 ]]; p++; + *p = palette[m_cga_palette_lut_2bpp[ ( data >> 4 ) & 0x03 ]]; p++; + *p = palette[m_cga_palette_lut_2bpp[ ( data >> 2 ) & 0x03 ]]; p++; + *p = palette[m_cga_palette_lut_2bpp[ data & 0x03 ]]; p++; + } +} + +MC6845_UPDATE_ROW( isa8_aga_device::cga_gfx_1bpp_update_row ) +{ + UINT8 *videoram = m_videoram; + const rgb_t *palette = m_palette->palette()->entry_list_raw(); + UINT32 *p = &bitmap.pix32(y); + UINT8 fg = m_cga_color_select & 0x0F; + int i; + + if ( y == 0 ) logerror("cga_gfx_1bpp_update_row\n"); + for ( i = 0; i < x_count; i++ ) { + UINT16 offset = ( ( ( ma + i ) << 1 ) & 0x1fff ) | ( ( ra & 1 ) << 13 ); + UINT8 data = videoram[ offset ]; + + *p = palette[( data & 0x80 ) ? fg : 0]; p++; + *p = palette[( data & 0x40 ) ? fg : 0]; p++; + *p = palette[( data & 0x20 ) ? fg : 0]; p++; + *p = palette[( data & 0x10 ) ? fg : 0]; p++; + *p = palette[( data & 0x08 ) ? fg : 0]; p++; + *p = palette[( data & 0x04 ) ? fg : 0]; p++; + *p = palette[( data & 0x02 ) ? fg : 0]; p++; + *p = palette[( data & 0x01 ) ? fg : 0]; p++; + + data = videoram[ offset + 1 ]; + + *p = palette[( data & 0x80 ) ? fg : 0]; p++; + *p = palette[( data & 0x40 ) ? fg : 0]; p++; + *p = palette[( data & 0x20 ) ? fg : 0]; p++; + *p = palette[( data & 0x10 ) ? fg : 0]; p++; + *p = palette[( data & 0x08 ) ? fg : 0]; p++; + *p = palette[( data & 0x04 ) ? fg : 0]; p++; + *p = palette[( data & 0x02 ) ? fg : 0]; p++; + *p = palette[( data & 0x01 ) ? fg : 0]; p++; + } +} + +/************************************* + * + * AGA MDA/CGA read/write handlers + * + *************************************/ + +READ8_MEMBER ( isa8_aga_device::pc_aga_mda_r ) +{ + UINT8 data = 0xFF; + + if ( m_mode == AGA_MONO ) { + switch( offset ) + { + case 0: case 2: case 4: case 6: + /* return last written mc6845 address value here? */ + break; + case 1: case 3: case 5: case 7: + data = m_mc6845->register_r(space, offset); + break; + case 10: + data = m_vsync | 0x08 | m_hsync; + break; + /* 12, 13, 14 are the LPT1 ports */ + } + } + return data; +} + +WRITE8_MEMBER ( isa8_aga_device::pc_aga_mda_w ) +{ + if ( m_mode == AGA_MONO ) { + switch( offset ) + { + case 0: case 2: case 4: case 6: + m_mc6845->address_w( space, offset, data ); + break; + case 1: case 3: case 5: case 7: + m_mc6845->register_w( space, offset, data ); + break; + case 8: + m_mda_mode_control = data; + + switch (m_mda_mode_control & 0x2a) + { + case 0x08: + m_update_row_type = MDA_TEXT_INTEN; + break; + case 0x28: + m_update_row_type = MDA_TEXT_BLINK; + break; + default: + m_update_row_type = -1; + } + break; + } + } +} + +READ8_MEMBER ( isa8_aga_device::pc_aga_cga_r ) +{ + UINT8 data = 0xFF; + + if ( m_mode == AGA_COLOR ) { + switch( offset ) { + case 0: case 2: case 4: case 6: + /* return last written mc6845 address value here? */ + break; + case 1: case 3: case 5: case 7: + data = m_mc6845->register_r( space, offset); + break; + case 10: + data = m_vsync | ( ( data & 0x40 ) >> 4 ) | m_hsync; + break; + } + } + return data; +} + +void isa8_aga_device::set_palette_luts(void) +{ + /* Setup 2bpp palette lookup table */ + if ( m_cga_mode_control & 0x10 ) + { + m_cga_palette_lut_2bpp[0] = 0; + } + else + { + m_cga_palette_lut_2bpp[0] = m_cga_color_select & 0x0F; + } + if ( m_cga_mode_control & 0x04 ) + { + m_cga_palette_lut_2bpp[1] = ( ( m_cga_color_select & 0x10 ) >> 1 ) | 3; + m_cga_palette_lut_2bpp[2] = ( ( m_cga_color_select & 0x10 ) >> 1 ) | 4; + m_cga_palette_lut_2bpp[3] = ( ( m_cga_color_select & 0x10 ) >> 1 ) | 7; + } + else + { + if ( m_cga_color_select & 0x20 ) + { + m_cga_palette_lut_2bpp[1] = ( ( m_cga_color_select & 0x10 ) >> 1 ) | 3; + m_cga_palette_lut_2bpp[2] = ( ( m_cga_color_select & 0x10 ) >> 1 ) | 5; + m_cga_palette_lut_2bpp[3] = ( ( m_cga_color_select & 0x10 ) >> 1 ) | 7; + } + else + { + m_cga_palette_lut_2bpp[1] = ( ( m_cga_color_select & 0x10 ) >> 1 ) | 2; + m_cga_palette_lut_2bpp[2] = ( ( m_cga_color_select & 0x10 ) >> 1 ) | 4; + m_cga_palette_lut_2bpp[3] = ( ( m_cga_color_select & 0x10 ) >> 1 ) | 6; + } + } + //logerror("2bpp lut set to %d,%d,%d,%d\n", cga.palette_lut_2bpp[0], cga.palette_lut_2bpp[1], cga.palette_lut_2bpp[2], cga.palette_lut_2bpp[3]); +} + + +WRITE8_MEMBER (isa8_aga_device:: pc_aga_cga_w ) +{ + if ( m_mode == AGA_COLOR ) { + switch(offset) { + case 0: case 2: case 4: case 6: + m_mc6845->address_w( space, offset, data ); + break; + case 1: case 3: case 5: case 7: + m_mc6845->register_w( space, offset, data ); + break; + case 8: + m_cga_mode_control = data; + + //logerror("mode set to %02X\n", m_cga_mode_control & 0x3F ); + switch ( m_cga_mode_control & 0x3F ) { + case 0x08: case 0x09: case 0x0C: case 0x0D: + m_mc6845->set_hpixels_per_column( 8 ); + m_update_row_type = CGA_TEXT_INTEN; + break; + case 0x0A: case 0x0B: case 0x2A: case 0x2B: + m_mc6845->set_hpixels_per_column( 8 ); + if ( CGA_MONITOR == CGA_MONITOR_COMPOSITE ) { + m_update_row_type = CGA_GFX_4BPPL; + } else { + m_update_row_type = CGA_GFX_2BPP; + } + break; + case 0x0E: case 0x0F: case 0x2E: case 0x2F: + m_mc6845->set_hpixels_per_column( 8 ); + m_update_row_type = CGA_GFX_2BPP; + break; + case 0x18: case 0x19: case 0x1C: case 0x1D: + m_mc6845->set_hpixels_per_column( 8 ); + m_update_row_type = CGA_TEXT_INTEN_ALT; + break; + case 0x1A: case 0x1B: case 0x3A: case 0x3B: + m_mc6845->set_hpixels_per_column( 8 ); + if ( CGA_MONITOR == CGA_MONITOR_COMPOSITE ) { + m_update_row_type = CGA_GFX_4BPPH; + } else { + m_update_row_type = CGA_GFX_1BPP; + } + break; + case 0x1E: case 0x1F: case 0x3E: case 0x3F: + m_mc6845->set_hpixels_per_column( 16 ); + m_update_row_type = CGA_GFX_1BPP; + break; + case 0x28: case 0x29: case 0x2C: case 0x2D: + m_mc6845->set_hpixels_per_column( 8 ); + m_update_row_type = CGA_TEXT_BLINK; + break; + case 0x38: case 0x39: case 0x3C: case 0x3D: + m_mc6845->set_hpixels_per_column( 8 ); + m_update_row_type = CGA_TEXT_BLINK_ALT; + break; + default: + m_update_row_type = -1; + break; + } + + set_palette_luts(); + break; + case 9: + m_cga_color_select = data; + set_palette_luts(); + break; + } + } +} + +/*************************************/ + +void isa8_aga_device::pc_aga_set_mode( AGA_MODE mode) +{ + m_mode = mode; + + switch (m_mode) { + case AGA_COLOR: + m_mc6845->set_clock( XTAL_14_31818MHz/8 ); + break; + case AGA_MONO: + m_mc6845->set_clock( 16257000/9 ); + break; + case AGA_OFF: + break; + } +} + + +WRITE8_MEMBER ( isa8_aga_device::pc_aga_videoram_w ) +{ + switch (m_mode) { + case AGA_COLOR: + if (offset>=0x8000) + m_videoram[offset-0x8000]=data; + break; + case AGA_MONO: + m_videoram[offset]=data; + break; + case AGA_OFF: break; + } +} + +READ8_MEMBER( isa8_aga_device::pc_aga_videoram_r ) +{ + switch (m_mode) { + case AGA_COLOR: + if (offset>=0x8000) return m_videoram[offset-0x8000]; + return 0; + case AGA_MONO: + return m_videoram[offset]; + case AGA_OFF: break; + } + return 0; +} + +READ8_MEMBER( isa8_aga_pc200_device::pc200_videoram_r ) +{ + switch (m_mode) + { + default: + if (offset>=0x8000) return m_videoram[offset-0x8000]; + return 0; + case AGA_MONO: + return m_videoram[offset]; + } +} + +WRITE8_MEMBER ( isa8_aga_pc200_device::pc200_videoram_w ) +{ + switch (m_mode) + { + default: + if (offset>=0x8000) + m_videoram[offset-0x8000]=data; + break; + case AGA_MONO: + m_videoram[offset]=data; + break; + } +} + +// in reality it is of course only 1 graphics adapter, +// but now cga and mda are splitted in mess +WRITE8_MEMBER( isa8_aga_pc200_device::pc200_cga_w ) +{ + pc_aga_cga_w(space, offset,data,mem_mask); + switch(offset) { + case 4: + m_portd |= 0x20; + break; + case 8: + m_port8 = data; + m_portd |= 0x80; + break; + case 0xe: + m_portd = 0x1f; + if (data & 0x80) + m_portd |= 0x40; + +/* The bottom 3 bits of this port are: + * Bit 2: Disable AGA + * Bit 1: Select MDA + * Bit 0: Select external display (monitor) rather than internal display + * (TV for PC200; LCD for PPC512) */ + if ((m_porte & 7) != (data & 7)) + { + if (data & 4) + pc_aga_set_mode(AGA_OFF); + else if (data & 2) + pc_aga_set_mode(AGA_MONO); + else + pc_aga_set_mode(AGA_COLOR); + } + m_porte = data; + break; + + default: + break; + } +} + +READ8_MEMBER ( isa8_aga_pc200_device::pc200_cga_r ) +{ + UINT8 result = 0xff; + + switch(offset) { + case 8: + result = m_port8; + break; + + case 0xd: + // after writing 0x80 to 0x3de, bits 7..5 of 0x3dd from the 2nd read must be 0 + result=m_portd; + m_portd&=0x1f; + break; + + case 0xe: + // 0x20 low cga + // 0x10 low special + result = machine().root_device().ioport("DSW0")->read() & 0x38; + break; + + default: + result = pc_aga_cga_r(space, offset, mem_mask); + break; + } + return result; +} diff --git a/src/devices/bus/isa/aga.h b/src/devices/bus/isa/aga.h new file mode 100644 index 00000000000..1526fade3a6 --- /dev/null +++ b/src/devices/bus/isa/aga.h @@ -0,0 +1,128 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +/* + pc cga/mda combi adapters + + one type hardware switchable between cga and mda/hercules + another type software switchable between cga and mda/hercules + + some support additional modes like + commodore pc10 320x200 in 16 colors + + + // aga + // 256 8x8 thick chars + // 256 8x8 thin chars + // 256 9x14 in 8x16 chars, line 3 is connected to a10 + ROM_LOAD("aga.chr", 0x00000, 0x02000, CRC(aca81498)) + // hercules font of above + ROM_LOAD("hercules.chr", 0x00000, 0x1000, CRC(7e8c9d76)) + +*/ +#ifndef __ISA_AGA_H__ +#define __ISA_AGA_H__ + +#include "emu.h" +#include "isa.h" +#include "cga.h" +#include "video/mc6845.h" + +enum AGA_MODE { AGA_OFF, AGA_COLOR, AGA_MONO }; + +// ======================> isa8_aga_device + +class isa8_aga_device : + public device_t, + public device_isa8_card_interface +{ +public: + // construction/destruction + isa8_aga_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + isa8_aga_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + // device-level overrides + virtual void device_start(); + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual const rom_entry *device_rom_region() const; + virtual ioport_constructor device_input_ports() const; + + DECLARE_WRITE_LINE_MEMBER( hsync_changed ); + DECLARE_WRITE_LINE_MEMBER( vsync_changed ); + + DECLARE_READ8_MEMBER( pc_aga_mda_r ); + DECLARE_WRITE8_MEMBER( pc_aga_mda_w ); + DECLARE_READ8_MEMBER( pc_aga_cga_r ); + DECLARE_WRITE8_MEMBER( pc_aga_cga_w ); + void set_palette_luts(void); + void pc_aga_set_mode(AGA_MODE mode); + DECLARE_WRITE8_MEMBER( pc_aga_videoram_w ); + DECLARE_READ8_MEMBER( pc_aga_videoram_r ); + + MC6845_UPDATE_ROW( aga_update_row ); + MC6845_UPDATE_ROW( mda_text_inten_update_row ); + MC6845_UPDATE_ROW( mda_text_blink_update_row ); + MC6845_UPDATE_ROW( cga_text_inten_update_row ); + MC6845_UPDATE_ROW( cga_text_inten_alt_update_row ); + MC6845_UPDATE_ROW( cga_text_blink_update_row ); + MC6845_UPDATE_ROW( cga_text_blink_alt_update_row ); + MC6845_UPDATE_ROW( cga_gfx_4bppl_update_row ); + MC6845_UPDATE_ROW( cga_gfx_4bpph_update_row ); + MC6845_UPDATE_ROW( cga_gfx_2bpp_update_row ); + MC6845_UPDATE_ROW( cga_gfx_1bpp_update_row ); + + required_device m_palette; + required_device m_mc6845; + + required_ioport m_cga_config; + + int m_update_row_type; + AGA_MODE m_mode; + UINT8 m_mda_mode_control; + UINT8 m_mda_status; + UINT8 *m_mda_chr_gen; + + UINT8 m_cga_mode_control; + UINT8 m_cga_color_select; + UINT8 m_cga_status; + UINT8 *m_cga_chr_gen; + + int m_framecnt; + UINT8 m_vsync; + UINT8 m_hsync; + + + UINT8 m_cga_palette_lut_2bpp[4]; + + UINT8 *m_videoram; +}; + +// device type definition +extern const device_type ISA8_AGA; + +// ======================> isa8_aga_pc200_device + +class isa8_aga_pc200_device : + public isa8_aga_device +{ +public: + // construction/destruction + isa8_aga_pc200_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + // device-level overrides + virtual void device_start(); + // optional information overrides + virtual const rom_entry *device_rom_region() const; + + UINT8 m_port8; + UINT8 m_portd; + UINT8 m_porte; + + DECLARE_READ8_MEMBER( pc200_videoram_r ); + DECLARE_WRITE8_MEMBER( pc200_videoram_w ); + DECLARE_WRITE8_MEMBER( pc200_cga_w ); + DECLARE_READ8_MEMBER( pc200_cga_r ); +}; + +// device type definition +extern const device_type ISA8_AGA_PC200; + +#endif diff --git a/src/devices/bus/isa/aha1542.c b/src/devices/bus/isa/aha1542.c new file mode 100644 index 00000000000..cc557c47eaa --- /dev/null +++ b/src/devices/bus/isa/aha1542.c @@ -0,0 +1,203 @@ +// license:BSD-3-Clause +// copyright-holders:Darkstar +/********************************************************************** + * + * Adaptec AHA-1542{,C,CF} SCSI Controller + * + **********************************************************************/ + +/* + PCB layout + ---------- + Floppy SCSI + +-----------+ +------------------+ +- + +-----+-----------+-+------------------+--+ + | | + | DIPSW DS1 |\ + | +-----+ | | + | | | Y1 +---+ TRM TRM | | + | | U3 | |U5 | |S| + | U8 +-----+ +---+ |C| + | +---+ +------+ +-------+ |S| + | |U13| |U15 | Y2 | | |I| + | +---+ +------+ | | | | + | |U16 | |U17 | | | + | +------+ +-------+ |/ + +-----------------------------------------+ + ||||||||| ||||||||||||||||||||||||| | + + + DIPSW sw1 - sw8 + U3 Intel chip labelled "AHA-1542CF/552800-01 D/9346", probably FDC (82077) + U5 Z84C0010VEC + U8 EEPROM(?) labelled 545120A + U13 CXK5864CM-10LL (64kbit SRAM) + U15 M27C256B labelled "ADAPTEC INC/553801-00 C/MCODE 563D/(C) 1993" + U16 M27C256B labelled "ADAPTEC INC/553601-00 C/BIOS C38D/(C) 1993" + U17 AIC-7970Q + Y1 XTAL SRX4054 93-38 + Y2 XTAL SRX4053 93-40 + TRM Dallas DS2107AS (SCSI termination) + DS1 LED + +*/ + +/* + * The PCB has a couple of DIP switches: + * + * sw1 on enable termination + * off software-controlled termination + * + * sw2 sw3 sw4 I/O Port + * off off off 0x330 - 0x333 (default) + * on off off 0x334 - 0x337 + * off on off 0x230 - 0x233 + * on on off 0x234 - 0x237 + * off off on 0x130 - 0x133 + * on off on 0x134 - 0x137 + * off on on reserved + * on on on reserved + * + * sw5 on disable floppy interface + * off enable floppy interface + * + * sw6 sw7 sw8 BIOS base address + * off off off 0xdc000 (default) + * on off off 0xd8000 + * off on off 0xd4000 + * on on off 0xd0000 + * off off on 0xcc000 + * on off on 0xc8000 + * off on on reserved + * on on on BIOS disabled + * + * source: http://download.adaptec.com/pdfs/installation_guides/1540cfig.pdf + */ + +#include "aha1542.h" +#include "cpu/z80/z80.h" + +// I/O Port interface +// READ Port x+0: STATUS +// WRITE Port x+0: CONTROL +// +// READ Port x+1: DATA +// WRITE Port x+1: COMMAND +// +// READ Port x+2: INTERRUPT STATUS +// WRITE Port x+2: (undefined?) +// +// R/W Port x+3: (undefined) + +// READ STATUS flags +#define STAT_STST 0x80 // self-test in progress +#define STAT_DIAGF 0x40 // internal diagnostic failure +#define STAT_INIT 0x20 // mailbox initialization required +#define STAT_IDLE 0x10 // HBA is idle +#define STAT_CDFULL 0x08 // Command/Data output port is full +#define STAT_DFULL 0x04 // Data input port is full +#define STAT_INVCMD 0x01 // Invalid command + +// READ INTERRUPT STATUS flags +#define INTR_ANY 0x80 // any interrupt +#define INTR_SRCD 0x08 // SCSI reset detected +#define INTR_HACC 0x04 // HA command complete +#define INTR_MBOA 0x02 // MBO empty +#define INTR_MBIF 0x01 // MBI full + +// WRITE CONTROL commands +#define CTRL_HRST 0x80 // Hard reset +#define CTRL_SRST 0x40 // Soft reset +#define CTRL_IRST 0x20 // interrupt reset +#define CTRL_SCRST 0x10 // SCSI bus reset + +// READ/WRITE DATA commands +#define CMD_NOP 0x00 // No operation +#define CMD_MBINIT 0x01 // mailbox initialization +#define CMD_START_SCSI 0x02 // Start SCSI command +#define CMD_BIOSCMD 0x03 // undocumented BIOS conmmand (shadow RAM etc.) +#define CMD_INQUIRY 0x04 // Adapter inquiry +#define CMD_EMBOI 0x05 // enable Mailbox Out Interrupt +#define CMD_SELTIMEOUT 0x06 // Set SEL timeout +#define CMD_BUSON_TIME 0x07 // set bus-On time +#define CMD_BUSOFF_TIME 0x08 // set bus-off time +#define CMD_DMASPEED 0x09 // set ISA DMA speed +#define CMD_RETDEVS 0x0a // return installed devices +#define CMD_RETCONF 0x0b // return configuration data +#define CMD_TARGET 0x0c // set HBA to target mode +#define CMD_RETSETUP 0x0d // return setup data +#define CMD_ECHO 0x1f // ECHO command data (NetBSD says it is 0x1e) + +// these are for 1541C only: +#define CMD_RETDEVSHI 0x23 // return devices 8-15 (from NetBSD) +#define CMD_EXTBIOS 0x28 // return extended BIOS information +#define CMD_MBENABLE 0x29 // set mailbox interface enable + +const device_type AHA1542 = &device_creator; + +#define Z84C0010_TAG "u5" + +READ8_MEMBER( aha1542_device::aha1542_r ) +{ + printf("%s aha1542_r(): offset=%d\n", machine().describe_context(), offset); + return 0xff; +} + +WRITE8_MEMBER( aha1542_device::aha1542_w ) +{ + printf("%s aha1542_w(): offset=%d data=0x%02x\n", machine().describe_context(), offset, data); +} + +//------------------------------------------------- +// ROM( aha1542 ) +//------------------------------------------------- + +ROM_START( aha1542 ) + ROM_REGION( 0x8000, "aha1542", 0 ) + ROM_LOAD( "553601-00.u16", 0x0000, 0x8000, CRC(ab22fc02) SHA1(f9f783e0272fc14ba3de32316997f1f6cadc67d0) ) /* Adaptec 1540CF/1542CF BIOS v2.01 */ + + ROM_REGION( 0x8000, Z84C0010_TAG, 0 ) + ROM_LOAD( "553801-00.u15", 0x0000, 0x8000, CRC(7824397e) SHA1(35bc2c8fab31aad3190a478f2dc8f3a72958cf04) ) /* ADAPTEC, INC MCODE */ +ROM_END + +static ADDRESS_MAP_START( z84c0010_mem, AS_PROGRAM, 8, aha1542_device ) + AM_RANGE(0x0000, 0x7fff) AM_ROM AM_REGION(Z84C0010_TAG, 0) + AM_RANGE(0x8000, 0x800f) AM_NOP // something is mapped there + AM_RANGE(0x9000, 0xafff) AM_RAM // 2kb RAM chip + AM_RANGE(0xe000, 0xe0ff) AM_RAM // probably PC<->Z80 communication area + AM_RANGE(0xb000, 0xb000) AM_NOP // something? +ADDRESS_MAP_END + +static MACHINE_CONFIG_FRAGMENT( aha1542 ) + MCFG_CPU_ADD(Z84C0010_TAG, Z80, XTAL_12MHz) + MCFG_CPU_PROGRAM_MAP( z84c0010_mem ) +MACHINE_CONFIG_END + +const rom_entry *aha1542_device::device_rom_region() const +{ + return ROM_NAME( aha1542 ); +} + +machine_config_constructor aha1542_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( aha1542 ); +} + +aha1542_device::aha1542_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, AHA1542, "AHA1542 SCSI Controller", tag, owner, clock, "aha1542", __FILE__ ), + device_isa16_card_interface(mconfig, *this) +{ +} + +void aha1542_device::device_start() +{ + set_isa_device(); + m_isa->install_rom(this, 0xdc000, 0xdffff, 0, 0, "aha1542", "aha1542"); + m_isa->install_device(0x330, 0x333, 0, 0, read8_delegate(FUNC( aha1542_device::aha1542_r ), this), + write8_delegate(FUNC( aha1542_device::aha1542_w ), this) ); +} + + +void aha1542_device::device_reset() +{ +} diff --git a/src/devices/bus/isa/aha1542.h b/src/devices/bus/isa/aha1542.h new file mode 100644 index 00000000000..035a9ebdd46 --- /dev/null +++ b/src/devices/bus/isa/aha1542.h @@ -0,0 +1,57 @@ +// license:BSD-3-Clause +// copyright-holders:Darkstar +/********************************************************************** + * + * Adaptec AHA-1542{,C,CF} SCSI Controller + * + ********************************************************************** + + + + **********************************************************************/ + +#pragma once + +#ifndef __AHA1542__ +#define __AHA1542__ + + +#include "emu.h" +#include "isa.h" + +//********************************************************************* +// TYPE DEFINITIONS +//********************************************************************* + +// ====================> aha1542_device + +class aha1542_device : public device_t, + public device_isa16_card_interface +{ +public: + // construction/destruction + aha1542_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + + DECLARE_READ8_MEMBER( aha1542_r ); + DECLARE_WRITE8_MEMBER( aha1542_w ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_isa16_card_interface + +private: + // internal state +}; + +// device type definition + +extern const device_type AHA1542; + +#endif diff --git a/src/devices/bus/isa/cga.c b/src/devices/bus/isa/cga.c new file mode 100644 index 00000000000..6041df5f9ce --- /dev/null +++ b/src/devices/bus/isa/cga.c @@ -0,0 +1,2011 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +/*************************************************************************** + + Color Graphics Adapter (CGA) section + + + Notes on Port 3D8 + (http://www.clipx.net/ng/interrupts_and_ports/ng2d045.php) + + Port 3D8 - Color/VGA Mode control register + + xx1x xxxx Attribute bit 7. 0=blink, 1=Intesity + xxx1 xxxx 640x200 mode + xxxx 1xxx Enable video signal + xxxx x1xx Select B/W mode + xxxx xx1x Select graphics + xxxx xxx1 80x25 text + + + The usage of the above control register for various modes is: + xx10 1100 40x25 alpha B/W + xx10 1000 40x25 alpha color + xx10 1101 80x25 alpha B/W + xx10 1001 80x25 alpha color + xxx0 1110 320x200 graph B/W + xxx0 1010 320x200 graph color + xxx1 1110 640x200 graph B/W + + + PC1512 display notes + + The PC1512 built-in display adaptor is an emulation of IBM's CGA. Unlike a + real CGA, it is not built around a real MC6845 controller, and so attempts + to get custom video modes out of it may not work as expected. Its 640x200 + CGA mode can be set up to be a 16-color mode rather than mono. + + If you program it with BIOS calls, the PC1512 behaves just like a real CGA, + except: + + - The 'greyscale' text modes (0 and 2) behave just like the 'color' + ones (1 and 3). On a color monitor both are in color; on a mono + monitor both are in greyscale. + - Mode 5 (the 'greyscale' graphics mode) displays in color, using + an alternative color palette: Cyan, Red and White. + - The undocumented 160x100x16 "graphics" mode works correctly. + + (source John Elliott http://www.seasip.info/AmstradXT/pc1512disp.html) + + + Cursor signal handling: + + The alpha dots signal is set when a character pixel should be set. This signal is + also set when the cursor should be displayed. The following formula for alpha + dots is derived from the schematics: + ALPHA DOTS = ( ( CURSOR DLY ) AND ( CURSOR BLINK ) ) OR ( ( ( NOT AT7 ) OR CURSOR DLY OR -BLINK OR NOT ENABLE BLINK ) AND ( CHG DOTS ) ) + + -CURSOR BLINK = VSYNC DLY (LS393) (changes every 8 vsyncs) + -BLINK = -CURSOR BLINK (LS393) (changes every 16 vsyncs) + -CURSOR DLY = -CURSOR signal from mc6845 and LS174 + CHG DOTS = character pixel (from character rom) + + For non-blinking modes this formula reduces to: + ALPHA DOTS = ( ( CURSOR DLY ) AND ( CURSOR BLINK ) ) OR ( CHG DOTS ) + + This means the cursor switches on/off state every 8 vsyncs. + + + For blinking modes this formula reduces to: + ALPHA DOTS = ( ( CURSOR DLY ) AND ( CURSOR BLINK ) ) OR ( ( ( NOT AT7 ) OR CURSOR DLY OR -BLINK ) AND ( CHG DOTS ) ) + + So, at the cursor location the attribute blinking is ignored and only regular + cursor blinking takes place (state switches every 8 vsyncs). On non-cursor + locations with the highest attribute bits set the character will switch + on/off every 16 vsyncs. In all other cases the character is displayed as + usual. + + +TODO: +- Update more drivers in MESS and MAME and unify with src/emu/video/pc_cga.c +- Separate out more cards/implementations + +***************************************************************************/ + +#include "emu.h" +#include "video/mc6845.h" +#include "cga.h" +#include "video/cgapal.h" + +#define VERBOSE_CGA 0 /* CGA (Color Graphics Adapter) */ + +#define CGA_SCREEN_NAME "screen" +#define CGA_MC6845_NAME "mc6845_cga" + +#define CGA_LOG(N,M,A) \ + do { \ + if(VERBOSE_CGA>=N) \ + { \ + if( M ) \ + logerror("%11.6f: %-24s",machine().time().as_double(),(char*)M ); \ + logerror A; \ + } \ + } while (0) + +enum +{ + CGA_TEXT_INTEN = 0, + CGA_TEXT_INTEN_ALT, + CGA_TEXT_INTEN_CG, + CGA_TEXT_BLINK, + CGA_TEXT_BLINK_ALT, + CGA_TEXT_BLINK_SI, + CGA_GFX_1BPP, + CGA_GFX_2BPP, + CGA_GFX_4BPPL, + CGA_GFX_4BPPH, + PC1512_GFX_4BPP +}; + +/*************************************************************************** + + Static declarations + +***************************************************************************/ + +static INPUT_PORTS_START( cga ) + PORT_START( "cga_config" ) + PORT_CONFNAME( 0x03, 0x00, "CGA character set") + PORT_CONFSETTING(0x00, DEF_STR( Normal )) + PORT_CONFSETTING(0x01, "Alternative") + PORT_CONFNAME( 0x1C, 0x00, "CGA monitor type") + PORT_CONFSETTING(0x00, "Colour RGB") + PORT_CONFSETTING(0x04, "Mono RGB") + PORT_CONFSETTING(0x08, "Colour composite") + PORT_CONFSETTING(0x0C, "Television") + PORT_CONFSETTING(0x10, "LCD") + PORT_CONFNAME( 0xE0, 0x00, "CGA chipset") + PORT_CONFSETTING(0x00, "IBM") + PORT_CONFSETTING(0x20, "Amstrad PC1512") + PORT_CONFSETTING(0x40, "Amstrad PPC512") + PORT_CONFSETTING(0x60, "ATI") + PORT_CONFSETTING(0x80, "Paradise") +INPUT_PORTS_END + + +static INPUT_PORTS_START( pc1512 ) + PORT_START( "cga_config" ) + PORT_CONFNAME( 0x03, 0x03, "CGA character set") + PORT_CONFSETTING(0x00, "Greek") + PORT_CONFSETTING(0x01, "Danish 2") + PORT_CONFSETTING(0x02, "Danish 1") + PORT_CONFSETTING(0x03, "Default") + PORT_CONFNAME( 0x1C, 0x00, "CGA monitor type") + PORT_CONFSETTING(0x00, "Colour RGB") + PORT_CONFSETTING(0x04, "Mono RGB") + PORT_BIT ( 0xE0, 0x20, IPT_UNUSED ) /* Chipset is always PC1512 */ +INPUT_PORTS_END + + +/* Dipswitch for font selection */ +#define CGA_FONT (m_cga_config->read() & m_font_selection_mask) + +/* Dipswitch for monitor selection */ +#define CGA_MONITOR (m_cga_config->read()&0x1C) +#define CGA_MONITOR_RGB 0x00 /* Colour RGB */ +#define CGA_MONITOR_MONO 0x04 /* Greyscale RGB */ +#define CGA_MONITOR_COMPOSITE 0x08 /* Colour composite */ +#define CGA_MONITOR_TELEVISION 0x0C /* Television */ +#define CGA_MONITOR_LCD 0x10 /* LCD, eg PPC512 */ + + +/* Dipswitch for chipset selection */ +/* TODO: Get rid of this; these should be handled by separate classes */ +#define CGA_CHIPSET (m_cga_config->read() & 0xE0) +#define CGA_CHIPSET_IBM 0x00 /* Original IBM CGA */ +#define CGA_CHIPSET_PC1512 0x20 /* PC1512 CGA subset */ +#define CGA_CHIPSET_PC200 0x40 /* PC200 in CGA mode */ +#define CGA_CHIPSET_ATI 0x60 /* ATI (supports Plantronics) */ +#define CGA_CHIPSET_PARADISE 0x80 /* Paradise (used in PC1640) */ + +MC6845_UPDATE_ROW( isa8_cga_device::crtc_update_row ) +{ + if (m_update_row_type == -1) + return; + + switch (m_update_row_type) + { + case CGA_TEXT_INTEN: + cga_text_inten_update_row(bitmap, cliprect, ma, ra, y, x_count, cursor_x, de, hbp, vbp); + break; + case CGA_TEXT_INTEN_ALT: + cga_text_inten_alt_update_row(bitmap, cliprect, ma, ra, y, x_count, cursor_x, de, hbp, vbp); + break; + case CGA_TEXT_INTEN_CG: + cga_text_inten_comp_grey_update_row(bitmap, cliprect, ma, ra, y, x_count, cursor_x, de, hbp, vbp); + break; + case CGA_TEXT_BLINK: + cga_text_blink_update_row(bitmap, cliprect, ma, ra, y, x_count, cursor_x, de, hbp, vbp); + break; + case CGA_TEXT_BLINK_ALT: + cga_text_blink_alt_update_row(bitmap, cliprect, ma, ra, y, x_count, cursor_x, de, hbp, vbp); + break; + case CGA_TEXT_BLINK_SI: + cga_text_blink_update_row_si(bitmap, cliprect, ma, ra, y, x_count, cursor_x, de, hbp, vbp); + break; + case CGA_GFX_1BPP: + cga_gfx_1bpp_update_row(bitmap, cliprect, ma, ra, y, x_count, cursor_x, de, hbp, vbp); + break; + case CGA_GFX_2BPP: + cga_gfx_2bpp_update_row(bitmap, cliprect, ma, ra, y, x_count, cursor_x, de, hbp, vbp); + break; + case CGA_GFX_4BPPL: + cga_gfx_4bppl_update_row(bitmap, cliprect, ma, ra, y, x_count, cursor_x, de, hbp, vbp); + break; + case CGA_GFX_4BPPH: + cga_gfx_4bpph_update_row(bitmap, cliprect, ma, ra, y, x_count, cursor_x, de, hbp, vbp); + break; + } +} + + +MC6845_UPDATE_ROW( isa8_cga_pc1512_device::crtc_update_row ) +{ + if (m_update_row_type == -1) + return; + + switch (m_update_row_type) + { + case PC1512_GFX_4BPP: + pc1512_gfx_4bpp_update_row(bitmap, cliprect, ma, ra, y, x_count, cursor_x, de, hbp, vbp); + break; + default: + isa8_cga_device::crtc_update_row(bitmap, cliprect, ma, ra, y, x_count, cursor_x, de, hbp, vbp); + break; + } +} + + +#define CGA_HCLK (XTAL_14_31818MHz/8) +#define CGA_LCLK (XTAL_14_31818MHz/16) + + +static MACHINE_CONFIG_FRAGMENT( cga ) + MCFG_SCREEN_ADD(CGA_SCREEN_NAME, RASTER) + MCFG_SCREEN_RAW_PARAMS(XTAL_14_31818MHz,912,0,640,262,0,200) + MCFG_SCREEN_UPDATE_DEVICE( DEVICE_SELF, isa8_cga_device, screen_update ) + + MCFG_PALETTE_ADD("palette", /* CGA_PALETTE_SETS * 16*/ 65536 ) + + MCFG_MC6845_ADD(CGA_MC6845_NAME, MC6845, CGA_SCREEN_NAME, XTAL_14_31818MHz/8) + MCFG_MC6845_SHOW_BORDER_AREA(false) + MCFG_MC6845_CHAR_WIDTH(8) + MCFG_MC6845_UPDATE_ROW_CB(isa8_cga_device, crtc_update_row) + MCFG_MC6845_OUT_HSYNC_CB(WRITELINE(isa8_cga_device, hsync_changed)) + MCFG_MC6845_OUT_VSYNC_CB(WRITELINE(isa8_cga_device, vsync_changed)) +MACHINE_CONFIG_END + + +ROM_START( cga ) + /* IBM 1501981(CGA) and 1501985(MDA) Character rom */ + ROM_REGION(0x2000,"gfx1", 0) + ROM_LOAD("5788005.u33", 0x00000, 0x2000, CRC(0bf56d70) SHA1(c2a8b10808bf51a3c123ba3eb1e9dd608231916f)) /* "AMI 8412PI // 5788005 // (C) IBM CORP. 1981 // KOREA" */ +ROM_END + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type ISA8_CGA = &device_creator; + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor isa8_cga_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( cga ); +} + +ioport_constructor isa8_cga_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( cga ); +} + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *isa8_cga_device::device_rom_region() const +{ + return ROM_NAME( cga ); +} + + +//------------------------------------------------- +// isa8_cga_device - constructor +//------------------------------------------------- + +isa8_cga_device::isa8_cga_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, ISA8_CGA, "IBM Color/Graphics Monitor Adapter", tag, owner, clock, "cga", __FILE__), + device_isa8_card_interface(mconfig, *this), + m_cga_config(*this, "cga_config"), + m_update_row_type(-1), + m_vram_size( 0x4000 ), + m_palette(*this, "palette") +{ + m_chr_gen_offset[0] = m_chr_gen_offset[2] = 0x1800; + m_chr_gen_offset[1] = m_chr_gen_offset[3] = 0x1000; + m_font_selection_mask = 0x01; + m_start_offset = 0; + m_superimpose = false; +} + +isa8_cga_device::isa8_cga_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_isa8_card_interface(mconfig, *this), + m_cga_config(*this, "cga_config"), + m_update_row_type(-1), + m_vram_size( 0x4000 ), + m_palette(*this, "palette") +{ + m_chr_gen_offset[0] = m_chr_gen_offset[2] = 0x1800; + m_chr_gen_offset[1] = m_chr_gen_offset[3] = 0x1000; + m_font_selection_mask = 0x01; + m_start_offset = 0; + m_superimpose = false; +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void isa8_cga_device::device_start() +{ + if (m_palette != NULL && !m_palette->started()) + throw device_missing_dependencies(); + + set_isa_device(); + m_vram.resize(m_vram_size); + m_isa->install_device(0x3d0, 0x3df, 0, 0, read8_delegate( FUNC(isa8_cga_device::io_read), this ), write8_delegate( FUNC(isa8_cga_device::io_write), this ) ); + m_isa->install_bank(0xb8000, 0xb8000 + MIN(0x8000,m_vram_size) - 1, 0, m_vram_size & 0x4000, "bank_cga", &m_vram[0]); + + /* Initialise the cga palette */ + int i; + + for ( i = 0; i < CGA_PALETTE_SETS * 16; i++ ) + { + m_palette->set_pen_color( i, cga_palette[i][0], cga_palette[i][1], cga_palette[i][2] ); + } + + i = 0x8000; + for ( int r = 0; r < 32; r++ ) + { + for ( int g = 0; g < 32; g++ ) + { + for ( int b = 0; b < 32; b++ ) + { + m_palette->set_pen_color( i, r << 3, g << 3, b << 3 ); + i++; + } + } + } + + m_chr_gen_base = memregion(subtag("gfx1").c_str())->base(); + m_chr_gen = m_chr_gen_base + m_chr_gen_offset[1]; + + save_item(NAME(m_framecnt)); + save_item(NAME(m_mode_control)); + save_item(NAME(m_color_select)); + //save_item(NAME(m_status)); uncomment when used + save_item(NAME(m_update_row_type)); + save_item(NAME(m_vsync)); + save_item(NAME(m_hsync)); + save_item(NAME(m_vram)); + save_item(NAME(m_plantronics)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void isa8_cga_device::device_reset() +{ + m_framecnt = 0; + m_mode_control = 0; + m_vsync = 0; + m_hsync = 0; + m_color_select = 0; + memset(m_palette_lut_2bpp, 0, sizeof(m_palette_lut_2bpp)); +} + +/*************************************************************************** + + Methods + +***************************************************************************/ + + +UINT32 isa8_cga_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + mc6845_device *mc6845 = subdevice(CGA_MC6845_NAME); + + mc6845->screen_update( screen, bitmap, cliprect); + + /* Check for changes in font dipsetting */ + switch ( CGA_FONT ) + { + case 0: + m_chr_gen = m_chr_gen_base + m_chr_gen_offset[0]; + break; + case 1: + m_chr_gen = m_chr_gen_base + m_chr_gen_offset[1]; + break; + case 2: + m_chr_gen = m_chr_gen_base + m_chr_gen_offset[2]; + break; + case 3: + m_chr_gen = m_chr_gen_base + m_chr_gen_offset[3]; + break; + } + return 0; +} + + +const device_type ISA8_CGA_POISK2 = &device_creator; + +//------------------------------------------------- +// isa8_cga_poisk2_device - constructor +//------------------------------------------------- + +isa8_cga_poisk2_device::isa8_cga_poisk2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + isa8_cga_device( mconfig, ISA8_CGA_POISK2, "ISA8_CGA_POISK2", tag, owner, clock, "cga_poisk2", __FILE__) +{ + m_chr_gen_offset[0] = 0x0000; + m_chr_gen_offset[1] = 0x0800; +} + +ROM_START( cga_poisk2 ) + ROM_REGION(0x2000,"gfx1", 0) + ROM_LOAD( "p2_ecga.rf4", 0x0000, 0x2000, CRC(d537f665) SHA1(d70f085b9b0cbd53df7c3122fbe7592998ba8fed)) +ROM_END + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *isa8_cga_poisk2_device::device_rom_region() const +{ + return ROM_NAME( cga_poisk2 ); +} + + +/* for superimposing CGA over a different source video (i.e. tetriskr) */ +const device_type ISA8_CGA_SUPERIMPOSE = &device_creator; + +//------------------------------------------------- +// isa8_cga_superimpose_device - constructor +//------------------------------------------------- + +isa8_cga_superimpose_device::isa8_cga_superimpose_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + isa8_cga_device( mconfig, ISA8_CGA_SUPERIMPOSE, "ISA8_CGA_SUPERIMPOSE", tag, owner, clock, "cga_superimpose", __FILE__) +{ + m_superimpose = true; +} + +isa8_cga_superimpose_device::isa8_cga_superimpose_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + isa8_cga_device( mconfig, type, name, tag, owner, clock, shortname, source) +{ + m_superimpose = true; +} + +/*************************************************************************** + Draw text mode with 40x25 characters (default) with high intensity bg. + The character cell size is 16x8 +***************************************************************************/ + +MC6845_UPDATE_ROW( isa8_cga_device::cga_text_inten_update_row ) +{ + UINT8 *videoram = &m_vram[m_start_offset]; + UINT32 *p = &bitmap.pix32(y); + const rgb_t *palette = m_palette->palette()->entry_list_raw(); + int i; + + if ( y == 0 ) CGA_LOG(1,"cga_text_inten_update_row",("\n")); + for ( i = 0; i < x_count; i++ ) + { + UINT16 offset = ( ( ma + i ) << 1 ) & 0x3fff; + UINT8 chr = videoram[ offset ]; + UINT8 attr = videoram[ offset +1 ]; + UINT8 data = m_chr_gen[ chr * 8 + ra ]; + UINT16 fg = attr & 0x0F; + UINT16 bg = attr >> 4; + + if ( i == cursor_x && ( m_framecnt & 0x08 ) ) + { + data = 0xFF; + } + + *p = palette[( data & 0x80 ) ? fg : bg]; p++; + *p = palette[( data & 0x40 ) ? fg : bg]; p++; + *p = palette[( data & 0x20 ) ? fg : bg]; p++; + *p = palette[( data & 0x10 ) ? fg : bg]; p++; + *p = palette[( data & 0x08 ) ? fg : bg]; p++; + *p = palette[( data & 0x04 ) ? fg : bg]; p++; + *p = palette[( data & 0x02 ) ? fg : bg]; p++; + *p = palette[( data & 0x01 ) ? fg : bg]; p++; + } +} + + +/*************************************************************************** + Draw text mode with 40x25 characters (default) with high intensity bg. + The character cell size is 16x8. Composite monitor, greyscale. +***************************************************************************/ + +MC6845_UPDATE_ROW( isa8_cga_device::cga_text_inten_comp_grey_update_row ) +{ + UINT8 *videoram = &m_vram[m_start_offset]; + UINT32 *p = &bitmap.pix32(y); + const rgb_t *palette = m_palette->palette()->entry_list_raw(); + int i; + + if ( y == 0 ) CGA_LOG(1,"cga_text_inten_comp_grey_update_row",("\n")); + for ( i = 0; i < x_count; i++ ) + { + UINT16 offset = ( ( ma + i ) << 1 ) & 0x3fff; + UINT8 chr = videoram[ offset ]; + UINT8 attr = videoram[ offset +1 ]; + UINT8 data = m_chr_gen[ chr * 8 + ra ]; + UINT16 fg = 0x10 + ( attr & 0x0F ); + UINT16 bg = 0x10 + ( ( attr >> 4 ) & 0x07 ); + + if ( i == cursor_x && ( m_framecnt & 0x08 ) ) + { + data = 0xFF; + } + + *p = palette[( data & 0x80 ) ? fg : bg]; p++; + *p = palette[( data & 0x40 ) ? fg : bg]; p++; + *p = palette[( data & 0x20 ) ? fg : bg]; p++; + *p = palette[( data & 0x10 ) ? fg : bg]; p++; + *p = palette[( data & 0x08 ) ? fg : bg]; p++; + *p = palette[( data & 0x04 ) ? fg : bg]; p++; + *p = palette[( data & 0x02 ) ? fg : bg]; p++; + *p = palette[( data & 0x01 ) ? fg : bg]; p++; + } +} + +/*************************************************************************** + Draw text mode with 40x25 characters (default) with high intensity bg. + The character cell size is 16x8 +***************************************************************************/ + +MC6845_UPDATE_ROW( isa8_cga_device::cga_text_inten_alt_update_row ) +{ + UINT8 *videoram = &m_vram[m_start_offset]; + UINT32 *p = &bitmap.pix32(y); + const rgb_t *palette = m_palette->palette()->entry_list_raw(); + int i; + + if ( y == 0 ) CGA_LOG(1,"cga_text_inten_alt_update_row",("\n")); + for ( i = 0; i < x_count; i++ ) + { + UINT16 offset = ( ( ma + i ) << 1 ) & 0x3fff; + UINT8 chr = videoram[ offset ]; + UINT8 attr = videoram[ offset +1 ]; + UINT8 data = m_chr_gen[ chr * 8 + ra ]; + UINT16 fg = attr & 0x0F; + + if ( i == cursor_x && ( m_framecnt & 0x08 ) ) + { + data = 0xFF; + } + + *p = palette[( data & 0x80 ) ? fg : 0]; p++; + *p = palette[( data & 0x40 ) ? fg : 0]; p++; + *p = palette[( data & 0x20 ) ? fg : 0]; p++; + *p = palette[( data & 0x10 ) ? fg : 0]; p++; + *p = palette[( data & 0x08 ) ? fg : 0]; p++; + *p = palette[( data & 0x04 ) ? fg : 0]; p++; + *p = palette[( data & 0x02 ) ? fg : 0]; p++; + *p = palette[( data & 0x01 ) ? fg : 0]; p++; + } +} + + +/*************************************************************************** + Draw text mode with 40x25 characters (default) and blinking colors. + The character cell size is 16x8 +***************************************************************************/ + +MC6845_UPDATE_ROW( isa8_cga_device::cga_text_blink_update_row ) +{ + UINT8 *videoram = &m_vram[m_start_offset]; + UINT32 *p = &bitmap.pix32(y); + const rgb_t *palette = m_palette->palette()->entry_list_raw(); + int i; + + if ( y == 0 ) CGA_LOG(1,"cga_text_blink_update_row",("\n")); + for ( i = 0; i < x_count; i++ ) + { + UINT16 offset = ( ( ma + i ) << 1 ) & 0x3fff; + UINT8 chr = videoram[ offset ]; + UINT8 attr = videoram[ offset +1 ]; + UINT8 data = m_chr_gen[ chr * 8 + ra ]; + UINT16 fg = attr & 0x0F; + UINT16 bg = (attr >> 4) & 0x07; + + if ( i == cursor_x ) + { + if ( m_framecnt & 0x08 ) + { + data = 0xFF; + } + } + else + { + if ( ( attr & 0x80 ) && ( m_framecnt & 0x10 ) ) + { + data = 0x00; + } + } + + *p = palette[( data & 0x80 ) ? fg : bg]; p++; + *p = palette[( data & 0x40 ) ? fg : bg]; p++; + *p = palette[( data & 0x20 ) ? fg : bg]; p++; + *p = palette[( data & 0x10 ) ? fg : bg]; p++; + *p = palette[( data & 0x08 ) ? fg : bg]; p++; + *p = palette[( data & 0x04 ) ? fg : bg]; p++; + *p = palette[( data & 0x02 ) ? fg : bg]; p++; + *p = palette[( data & 0x01 ) ? fg : bg]; p++; + } +} + +MC6845_UPDATE_ROW( isa8_cga_device::cga_text_blink_update_row_si ) +{ + UINT8 *videoram = &m_vram[m_start_offset]; + UINT32 *p = &bitmap.pix32(y); + const rgb_t *palette = m_palette->palette()->entry_list_raw(); + int i; + + if ( y == 0 ) CGA_LOG(1,"cga_text_blink_update_row_si",("\n")); + for ( i = 0; i < x_count; i++ ) + { + UINT16 offset = ( ( ma + i ) << 1 ) & 0x3fff; + UINT8 chr = videoram[ offset ]; + UINT8 attr = videoram[ offset +1 ]; + UINT8 data = m_chr_gen[ chr * 8 + ra ]; + UINT16 fg = attr & 0x0F; + UINT16 bg = (attr >> 4) & 0x07; + UINT8 xi; + + if ( i == cursor_x ) + { + if ( m_framecnt & 0x08 ) + { + data = 0xFF; + } + } + else + { + if ( ( attr & 0x80 ) && ( m_framecnt & 0x10 ) ) + { + data = 0x00; + } + } + + for(xi=0;xi<8;xi++) + { + UINT8 pen_data, dot; + + dot = (data & (1 << (7-xi))); + pen_data = dot ? fg : bg; + if(pen_data || dot) + *p = palette[pen_data]; + p++; + } + } +} + +/*************************************************************************** + Draw text mode with 40x25 characters (default) and blinking colors. + The character cell size is 16x8 +***************************************************************************/ + +MC6845_UPDATE_ROW( isa8_cga_device::cga_text_blink_alt_update_row ) +{ + UINT8 *videoram = &m_vram[m_start_offset]; + UINT32 *p = &bitmap.pix32(y); + const rgb_t *palette = m_palette->palette()->entry_list_raw(); + int i; + + if ( y == 0 ) CGA_LOG(1,"cga_text_blink_alt_update_row",("\n")); + for ( i = 0; i < x_count; i++ ) + { + UINT16 offset = ( ( ma + i ) << 1 ) & 0x3fff; + UINT8 chr = videoram[ offset ]; + UINT8 attr = videoram[ offset +1 ]; + UINT8 data = m_chr_gen[ chr * 8 + ra ]; + UINT16 fg = attr & 0x07; + UINT16 bg = 0; + + if ( i == cursor_x ) + { + if ( m_framecnt & 0x08 ) + { + data = 0xFF; + } + } + else + { + if ( ( attr & 0x80 ) && ( m_framecnt & 0x10 ) ) + { + data = 0x00; + bg = ( attr >> 4 ) & 0x07; + } + } + + *p = palette[( data & 0x80 ) ? fg : bg]; p++; + *p = palette[( data & 0x40 ) ? fg : bg]; p++; + *p = palette[( data & 0x20 ) ? fg : bg]; p++; + *p = palette[( data & 0x10 ) ? fg : bg]; p++; + *p = palette[( data & 0x08 ) ? fg : bg]; p++; + *p = palette[( data & 0x04 ) ? fg : bg]; p++; + *p = palette[( data & 0x02 ) ? fg : bg]; p++; + *p = palette[( data & 0x01 ) ? fg : bg]; p++; + } +} + + +/* The lo-res (320x200) graphics mode on a colour composite monitor */ + +MC6845_UPDATE_ROW( isa8_cga_device::cga_gfx_4bppl_update_row ) +{ + UINT8 *videoram = &m_vram[m_start_offset]; + UINT32 *p = &bitmap.pix32(y); + const rgb_t *palette = m_palette->palette()->entry_list_raw(); + int i; + + if ( y == 0 ) CGA_LOG(1,"cga_gfx_4bppl_update_row",("\n")); + for ( i = 0; i < x_count; i++ ) + { + UINT16 offset = ( ( ( ma + i ) << 1 ) & 0x1fff ) | ( ( y & 1 ) << 13 ); + UINT8 data = videoram[ offset ]; + + *p = palette[data >> 4]; p++; + *p = palette[data >> 4]; p++; + *p = palette[data & 0x0F]; p++; + *p = palette[data & 0x0F]; p++; + + data = videoram[ offset + 1 ]; + + *p = palette[data >> 4]; p++; + *p = palette[data >> 4]; p++; + *p = palette[data & 0x0F]; p++; + *p = palette[data & 0x0F]; p++; + } +} + + +#if 0 +/* The hi-res graphics mode on a colour composite monitor + * + * The different scaling factors mean that the '160x200' versions of screens + * are the same size as the normal colour ones. + */ + +static const UINT8 yc_lut2[4] = { 0, 182, 71, 255 }; + +static const UINT8 yc_lut[16][8] = +{ + { 0, 0, 0, 0, 0, 0, 0, 0 }, /* black */ + { 0, 0, 0, 0, 1, 1, 1, 1 }, /* blue */ + { 0, 1, 1, 1, 1, 0, 0, 0 }, /* green */ + { 0, 0, 1, 1, 1, 1, 0, 0 }, /* cyan */ + { 1, 1, 0, 0, 0, 0, 1, 1 }, /* red */ + { 1, 0, 0, 0, 0, 1, 1, 1 }, /* magenta */ + { 1, 1, 1, 1, 0, 0, 0, 0 }, /* yellow */ + { 1, 1, 1, 1, 1, 1, 1, 1 }, /* white */ + /* Intensity set */ + { 2, 2, 2, 2, 2, 2, 2, 2 }, /* black */ + { 2, 2, 2, 2, 3, 3, 3, 3 }, /* blue */ + { 2, 3, 3, 3, 3, 2, 2, 2 }, /* green */ + { 2, 2, 3, 3, 3, 3, 2, 2 }, /* cyan */ + { 3, 3, 2, 2, 2, 2, 3, 3 }, /* red */ + { 3, 2, 2, 2, 2, 3, 3, 3 }, /* magenta */ + { 3, 3, 3, 3, 2, 2, 2, 2 }, /* yellow */ + { 3, 3, 3, 3, 3, 3, 3, 3 }, /* white */ +}; +#endif + +MC6845_UPDATE_ROW( isa8_cga_device::cga_gfx_4bpph_update_row ) +{ + UINT8 *videoram = &m_vram[m_start_offset]; + UINT32 *p = &bitmap.pix32(y); + const rgb_t *palette = m_palette->palette()->entry_list_raw(); + int i; + + if ( y == 0 ) CGA_LOG(1,"cga_gfx_4bpph_update_row",("\n")); + + for ( i = 0; i < x_count; i++ ) + { + UINT16 offset = ( ( ( ma + i ) << 1 ) & 0x1fff ) | ( ( y & 1 ) << 13 ); + UINT8 data = videoram[ offset ]; + + *p = palette[data >> 4]; p++; + *p = palette[data >> 4]; p++; + *p = palette[data >> 4]; p++; + *p = palette[data >> 4]; p++; + *p = palette[data & 0x0F]; p++; + *p = palette[data & 0x0F]; p++; + *p = palette[data & 0x0F]; p++; + *p = palette[data & 0x0F]; p++; + + data = videoram[ offset + 1 ]; + + *p = palette[data >> 4]; p++; + *p = palette[data >> 4]; p++; + *p = palette[data >> 4]; p++; + *p = palette[data >> 4]; p++; + *p = palette[data & 0x0F]; p++; + *p = palette[data & 0x0F]; p++; + *p = palette[data & 0x0F]; p++; + *p = palette[data & 0x0F]; p++; + } +} + + +/*************************************************************************** + Draw graphics mode with 320x200 pixels (default) with 2 bits/pixel. + Even scanlines are from CGA_base + 0x0000, odd from CGA_base + 0x2000 + cga fetches 2 byte per mc6845 access. +***************************************************************************/ + +MC6845_UPDATE_ROW( isa8_cga_device::cga_gfx_2bpp_update_row ) +{ + UINT8 *videoram = &m_vram[m_start_offset]; + UINT32 *p = &bitmap.pix32(y); + const rgb_t *palette = m_palette->palette()->entry_list_raw(); + int i; + + if ( y == 0 ) CGA_LOG(1,"cga_gfx_2bpp_update_row",("\n")); + for ( i = 0; i < x_count; i++ ) + { + UINT16 offset = ( ( ( ma + i ) << 1 ) & 0x1fff ) | ( ( ra & 1 ) << 13 ); + UINT8 data = videoram[ offset ]; + + *p = palette[m_palette_lut_2bpp[ ( data >> 6 ) & 0x03 ]]; p++; + *p = palette[m_palette_lut_2bpp[ ( data >> 4 ) & 0x03 ]]; p++; + *p = palette[m_palette_lut_2bpp[ ( data >> 2 ) & 0x03 ]]; p++; + *p = palette[m_palette_lut_2bpp[ data & 0x03 ]]; p++; + + data = videoram[ offset+1 ]; + + *p = palette[m_palette_lut_2bpp[ ( data >> 6 ) & 0x03 ]]; p++; + *p = palette[m_palette_lut_2bpp[ ( data >> 4 ) & 0x03 ]]; p++; + *p = palette[m_palette_lut_2bpp[ ( data >> 2 ) & 0x03 ]]; p++; + *p = palette[m_palette_lut_2bpp[ data & 0x03 ]]; p++; + } +} + + + +/*************************************************************************** + Draw graphics mode with 640x200 pixels (default). + The cell size is 1x1 (1 scanline is the real default) + Even scanlines are from CGA_base + 0x0000, odd from CGA_base + 0x2000 +***************************************************************************/ + +MC6845_UPDATE_ROW( isa8_cga_device::cga_gfx_1bpp_update_row ) +{ + UINT8 *videoram = &m_vram[m_start_offset]; + UINT32 *p = &bitmap.pix32(y); + const rgb_t *palette = m_palette->palette()->entry_list_raw(); + UINT8 fg = m_color_select & 0x0F; + int i; + + if ( y == 0 ) CGA_LOG(1,"cga_gfx_1bpp_update_row",("\n")); + for ( i = 0; i < x_count; i++ ) + { + UINT16 offset = ( ( ( ma + i ) << 1 ) & 0x1fff ) | ( ( ra & 1 ) << 13 ); + UINT8 data = videoram[ offset ]; + + *p = palette[( data & 0x80 ) ? fg : 0]; p++; + *p = palette[( data & 0x40 ) ? fg : 0]; p++; + *p = palette[( data & 0x20 ) ? fg : 0]; p++; + *p = palette[( data & 0x10 ) ? fg : 0]; p++; + *p = palette[( data & 0x08 ) ? fg : 0]; p++; + *p = palette[( data & 0x04 ) ? fg : 0]; p++; + *p = palette[( data & 0x02 ) ? fg : 0]; p++; + *p = palette[( data & 0x01 ) ? fg : 0]; p++; + + data = videoram[ offset + 1 ]; + + *p = palette[( data & 0x80 ) ? fg : 0]; p++; + *p = palette[( data & 0x40 ) ? fg : 0]; p++; + *p = palette[( data & 0x20 ) ? fg : 0]; p++; + *p = palette[( data & 0x10 ) ? fg : 0]; p++; + *p = palette[( data & 0x08 ) ? fg : 0]; p++; + *p = palette[( data & 0x04 ) ? fg : 0]; p++; + *p = palette[( data & 0x02 ) ? fg : 0]; p++; + *p = palette[( data & 0x01 ) ? fg : 0]; p++; + } +} + + +WRITE_LINE_MEMBER( isa8_cga_device::hsync_changed ) +{ + m_hsync = state ? 1 : 0; +} + + +WRITE_LINE_MEMBER( isa8_cga_device::vsync_changed ) +{ + m_vsync = state ? 9 : 0; + if ( state ) + { + m_framecnt++; + } +} + + +void isa8_cga_device::set_palette_luts(void) +{ + /* Setup 2bpp palette lookup table */ + if ( m_mode_control & 0x10 ) + { + m_palette_lut_2bpp[0] = 0; + } + else + { + m_palette_lut_2bpp[0] = m_color_select & 0x0F; + } + if ( m_mode_control & 0x04 ) + { + m_palette_lut_2bpp[1] = ( ( m_color_select & 0x10 ) >> 1 ) | 3; + m_palette_lut_2bpp[2] = ( ( m_color_select & 0x10 ) >> 1 ) | 4; + m_palette_lut_2bpp[3] = ( ( m_color_select & 0x10 ) >> 1 ) | 7; + } + else + { + if ( m_color_select & 0x20 ) + { + m_palette_lut_2bpp[1] = ( ( m_color_select & 0x10 ) >> 1 ) | 3; + m_palette_lut_2bpp[2] = ( ( m_color_select & 0x10 ) >> 1 ) | 5; + m_palette_lut_2bpp[3] = ( ( m_color_select & 0x10 ) >> 1 ) | 7; + } + else + { + m_palette_lut_2bpp[1] = ( ( m_color_select & 0x10 ) >> 1 ) | 2; + m_palette_lut_2bpp[2] = ( ( m_color_select & 0x10 ) >> 1 ) | 4; + m_palette_lut_2bpp[3] = ( ( m_color_select & 0x10 ) >> 1 ) | 6; + } + } + //logerror("2bpp lut set to %d,%d,%d,%d\n", cga.palette_lut_2bpp[0], cga.palette_lut_2bpp[1], cga.palette_lut_2bpp[2], cga.palette_lut_2bpp[3]); +} + +/* + * rW CGA mode control register (see #P138) + * + * x x x 0 1 0 0 0 - 320x200, 40x25 text. Colour on RGB and composite monitors. + * x x x 0 1 0 0 1 - 640x200, 80x25 text. Colour on RGB and composite monitors. + * x x x 0 1 0 1 0 - 320x200 graphics. Colour on RGB and composite monitors. + * x x x 0 1 0 1 1 - unknown/invalid. + * x x x 0 1 1 0 0 - 320x200, 40x25 text. Colour on RGB, greyscale on composite monitors. + * x x x 0 1 1 0 1 - 640x200, 80x25 text. Colour on RGB, greyscale on composite monitors. + * x x x 0 1 1 1 0 - 320x200 graphics. Alternative palette on RGB, greyscale on composite monitors. + * x x x 0 1 1 1 1 - unknown/invalid. + * x x x 1 1 0 0 0 - unknown/invalid. + * x x x 1 1 0 0 1 - unknown/invalid. + * x x x 1 1 0 1 0 - 160x200/640x200 graphics. 640x200 ?? on RGB monitor, 160x200 on composite monitor. + * x x x 1 1 0 1 1 - unknown/invalid. + * x x x 1 1 1 0 0 - unknown/invalid. + * x x x 1 1 1 0 1 - unknown/invalid. + * x x x 1 1 1 1 0 - 640x200 graphics. Colour on black on RGB monitor, monochrome on composite monitor. + * x x x 1 1 1 1 1 - unknown/invalid. + */ +void isa8_cga_device::mode_control_w(UINT8 data) +{ + mc6845_device *mc6845 = subdevice(CGA_MC6845_NAME); + UINT8 monitor = CGA_MONITOR; + + m_mode_control = data; + + //logerror("mode set to %02X\n", cga.mode_control & 0x3F ); + switch ( m_mode_control & 0x3F ) + { + case 0x08: case 0x09: case 0x0C: case 0x0D: + mc6845->set_hpixels_per_column( 8 ); + if ( monitor == CGA_MONITOR_COMPOSITE ) + { + if ( m_mode_control & 0x04 ) + { + /* Composite greyscale */ + m_update_row_type = CGA_TEXT_INTEN_CG; + } + else + { + /* Composite colour */ + m_update_row_type = CGA_TEXT_INTEN; + } + } + else + { + /* RGB colour */ + m_update_row_type = CGA_TEXT_INTEN; + } + break; + case 0x0A: case 0x0B: case 0x2A: case 0x2B: + mc6845->set_hpixels_per_column( 8 ); + if ( monitor == CGA_MONITOR_COMPOSITE ) + { + m_update_row_type = CGA_GFX_4BPPL; + } + else + { + m_update_row_type = CGA_GFX_2BPP; + } + break; + case 0x0E: case 0x0F: case 0x2E: case 0x2F: + mc6845->set_hpixels_per_column( 8 ); + m_update_row_type = CGA_GFX_2BPP; + break; + case 0x18: case 0x19: case 0x1C: case 0x1D: + mc6845->set_hpixels_per_column( 8 ); + m_update_row_type = CGA_TEXT_INTEN_ALT; + break; + case 0x1A: case 0x1B: case 0x3A: case 0x3B: + mc6845->set_hpixels_per_column( 16 ); + if ( monitor == CGA_MONITOR_COMPOSITE ) + { + m_update_row_type = CGA_GFX_4BPPH; + } + else + { + m_update_row_type = CGA_GFX_1BPP; + } + break; + case 0x1E: case 0x1F: case 0x3E: case 0x3F: + mc6845->set_hpixels_per_column( 16 ); + m_update_row_type = CGA_GFX_1BPP; + break; + case 0x28: case 0x29: case 0x2C: case 0x2D: + mc6845->set_hpixels_per_column( 8 ); + if ( monitor == CGA_MONITOR_COMPOSITE ) + { + if ( m_mode_control & 0x04 ) + { + /* Composite greyscale */ + m_update_row_type = m_superimpose ? CGA_TEXT_BLINK_SI : CGA_TEXT_BLINK; + } + else + { + /* Composite colour */ + m_update_row_type = m_superimpose ? CGA_TEXT_BLINK_SI : CGA_TEXT_BLINK; + } + } + else + { + /* RGB colour */ + m_update_row_type = m_superimpose ? CGA_TEXT_BLINK_SI : CGA_TEXT_BLINK; + } + break; + case 0x38: case 0x39: case 0x3C: case 0x3D: + mc6845->set_hpixels_per_column( 8 ); + m_update_row_type = CGA_TEXT_BLINK_ALT; + break; + default: + m_update_row_type = -1; + break; + } + + // The lowest bit of the mode register selects, among others, the + // input clock to the 6845. + mc6845->set_clock( ( m_mode_control & 1 ) ? CGA_HCLK : CGA_LCLK ); + + set_palette_luts(); +} + + + +/* + * Select Plantronics modes + */ +void isa8_cga_device::plantronics_w(UINT8 data) +{ + if ( ( CGA_CHIPSET ) != CGA_CHIPSET_ATI) return; + + data &= 0x70; /* Only bits 6-4 are used */ + m_plantronics = data; +} + + + +/************************************************************************* + * + * CGA + * color graphics adapter + * + *************************************************************************/ + + +READ8_MEMBER( isa8_cga_device::io_read ) +{ + mc6845_device *mc6845 = subdevice(CGA_MC6845_NAME); + UINT8 data = 0xff; + + switch( offset ) + { + case 0: case 2: case 4: case 6: + /* return last written mc6845 address value here? */ + break; + case 1: case 3: case 5: case 7: + data = mc6845->register_r( space, offset ); + break; + case 10: + data = m_vsync | ( ( data & 0x40 ) >> 4 ) | m_hsync; + break; + } + return data; +} + + + +WRITE8_MEMBER( isa8_cga_device::io_write ) +{ + mc6845_device *mc6845 = subdevice(CGA_MC6845_NAME); + + switch(offset) { + case 0: case 2: case 4: case 6: + mc6845->address_w( space, offset, data ); + break; + case 1: case 3: case 5: case 7: + mc6845->register_w( space, offset, data ); + break; + case 8: + mode_control_w(data); + break; + case 9: + m_color_select = data; + set_palette_luts(); + break; + case 0x0d: + plantronics_w(data); + break; + } +} + + + +/* Old plantronics rendering code, leaving it uncommented until we have re-implemented it */ + +// +// From choosevideomode: +// +// /* Plantronics high-res */ +// if ((cga.mode_control & 2) && (cga.plantronics & 0x20)) +// proc = cga_pgfx_2bpp; +// /* Plantronics low-res */ +// if ((cga.mode_control & 2) && (cga.plantronics & 0x10)) +// proc = cga_pgfx_4bpp; +// + +//INLINE void pgfx_plot_unit_4bpp(bitmap_ind16 &bitmap, +// int x, int y, int offs) +//{ +// int color, values[2]; +// int i; +// +// if (cga.plantronics & 0x40) +// { +// values[0] = videoram[offs | 0x4000]; +// values[1] = videoram[offs]; +// } +// else +// { +// values[0] = videoram[offs]; +// values[1] = videoram[offs | 0x4000]; +// } +// for (i=3; i>=0; i--) +// { +// color = ((values[0] & 0x3) << 1) | +// ((values[1] & 2) >> 1) | +// ((values[1] & 1) << 3); +// bitmap.pix16(y, x+i) = Machine->pens[color]; +// values[0]>>=2; +// values[1]>>=2; +// } +//} +// +// +// +///*************************************************************************** +// Draw graphics mode with 640x200 pixels (default) with 2 bits/pixel. +// Even scanlines are from CGA_base + 0x0000, odd from CGA_base + 0x2000 +// Second plane at CGA_base + 0x4000 / 0x6000 +//***************************************************************************/ +// +//static void cga_pgfx_4bpp(bitmap_ind16 &bitmap, struct mscrtc6845 *crtc) +//{ +// int i, sx, sy, sh; +// int offs = mscrtc6845_get_start(crtc)*2; +// int lines = mscrtc6845_get_char_lines(crtc); +// int height = mscrtc6845_get_char_height(crtc); +// int columns = mscrtc6845_get_char_columns(crtc)*2; +// +// for (sy=0; sy=0; i--) +// { +// bmap[0] = bmap[0] << 1; if (values[0] & 0x80) bmap[0] |= 1; +// bmap[0] = bmap[0] << 1; if (values[1] & 0x80) bmap[0] |= 1; +// bmap[1] = bmap[1] << 1; if (values[0] & 0x08) bmap[1] |= 1; +// bmap[1] = bmap[1] << 1; if (values[1] & 0x08) bmap[1] |= 1; +// values[0] = values[0] << 1; +// values[1] = values[1] << 1; +// } +// +// dest = &bitmap.pix16(y, x); +// *(dest++) = palette[(bmap[0] >> 6) & 0x03]; +// *(dest++) = palette[(bmap[0] >> 4) & 0x03]; +// *(dest++) = palette[(bmap[0] >> 2) & 0x03]; +// *(dest++) = palette[(bmap[0] >> 0) & 0x03]; +// *(dest++) = palette[(bmap[1] >> 6) & 0x03]; +// *(dest++) = palette[(bmap[1] >> 4) & 0x03]; +// *(dest++) = palette[(bmap[1] >> 2) & 0x03]; +// *(dest++) = palette[(bmap[1] >> 0) & 0x03]; +//} +// +// +// +///*************************************************************************** +// Draw graphics mode with 320x200 pixels (default) with 2 bits/pixel. +// Even scanlines are from CGA_base + 0x0000, odd from CGA_base + 0x2000 +// cga fetches 2 byte per mscrtc6845 access (not modeled here)! +//***************************************************************************/ +// +//static void cga_pgfx_2bpp(bitmap_ind16 &bitmap, struct mscrtc6845 *crtc) +//{ +// int i, sx, sy, sh; +// int offs = mscrtc6845_get_start(crtc)*2; +// int lines = mscrtc6845_get_char_lines(crtc); +// int height = mscrtc6845_get_char_height(crtc); +// int columns = mscrtc6845_get_char_columns(crtc)*2; +// int colorset = cga.color_select & 0x3F; +// const UINT16 *palette; +// +// /* Most chipsets use bit 2 of the mode control register to +// * access a third palette. But not consistently. */ +// pc_cga_check_palette(); +// switch(CGA_CHIPSET) +// { +// /* The IBM Professional Graphics Controller behaves like +// * the PC1512, btw. */ +// case CGA_CHIPSET_PC1512: +// if ((colorset < 32) && (cga.mode_control & 4)) colorset += 64; +// break; +// +// case CGA_CHIPSET_IBM: +// case CGA_CHIPSET_PC200: +// case CGA_CHIPSET_ATI: +// case CGA_CHIPSET_PARADISE: +// if (cga.mode_control & 4) colorset = (colorset & 0x1F) + 64; +// break; +// } +// +// +// /* The fact that our palette is located in cga_colortable is a vestigial +// * aspect from when we were doing that ugly trick where drawgfx() would +// * handle graphics drawing. Truthfully, we should probably be using +// * palette_set_color_rgb() here and not doing the palette lookup in the loop +// */ +// palette = &cga_colortable[256*2 + 16*2] + colorset * 4; +// +// for (sy=0; sypalette()->entry_list_raw(); + UINT16 offset_base = ra << 13; + int j; + + if ( y == 0 ) CGA_LOG(1,"pc1512_gfx_4bpp_update_row",("\n")); + for ( j = 0; j < x_count; j++ ) + { + UINT16 offset = offset_base | ( ( ma + j ) & 0x1FFF ); + UINT16 i = ( m_color_select & 8 ) ? videoram[ isa8_cga_pc1512_device::vram_offset[3] | offset ] << 3 : 0; + UINT16 r = ( m_color_select & 4 ) ? videoram[ isa8_cga_pc1512_device::vram_offset[2] | offset ] << 2 : 0; + UINT16 g = ( m_color_select & 2 ) ? videoram[ isa8_cga_pc1512_device::vram_offset[1] | offset ] << 1 : 0; + UINT16 b = ( m_color_select & 1 ) ? videoram[ isa8_cga_pc1512_device::vram_offset[0] | offset ] : 0; + + *p = palette[( ( i & 0x400 ) | ( r & 0x200 ) | ( g & 0x100 ) | ( b & 0x80 ) ) >> 7]; p++; + *p = palette[( ( i & 0x200 ) | ( r & 0x100 ) | ( g & 0x080 ) | ( b & 0x40 ) ) >> 6]; p++; + *p = palette[( ( i & 0x100 ) | ( r & 0x080 ) | ( g & 0x040 ) | ( b & 0x20 ) ) >> 5]; p++; + *p = palette[( ( i & 0x080 ) | ( r & 0x040 ) | ( g & 0x020 ) | ( b & 0x10 ) ) >> 4]; p++; + *p = palette[( ( i & 0x040 ) | ( r & 0x020 ) | ( g & 0x010 ) | ( b & 0x08 ) ) >> 3]; p++; + *p = palette[( ( i & 0x020 ) | ( r & 0x010 ) | ( g & 0x008 ) | ( b & 0x04 ) ) >> 2]; p++; + *p = palette[( ( i & 0x010 ) | ( r & 0x008 ) | ( g & 0x004 ) | ( b & 0x02 ) ) >> 1]; p++; + *p = palette[ ( i & 0x008 ) | ( r & 0x004 ) | ( g & 0x002 ) | ( b & 0x01 ) ]; p++; + } +} + + +WRITE8_MEMBER( isa8_cga_pc1512_device::io_write ) +{ + mc6845_device *mc6845 = subdevice(CGA_MC6845_NAME); + + switch (offset) + { + case 0: case 2: case 4: case 6: + data &= 0x1F; + mc6845->address_w( space, offset, data ); + m_mc6845_address = data; + break; + + case 1: case 3: case 5: case 7: + if ( ! m_mc6845_locked_register[m_mc6845_address] ) + { + mc6845->register_w( space, offset, data ); + if ( isa8_cga_pc1512_device::mc6845_writeonce_register[m_mc6845_address] ) + { + m_mc6845_locked_register[m_mc6845_address] = 1; + } + } + break; + + case 0x8: + /* Check if we're changing to graphics mode 2 */ + if ( ( m_mode_control & 0x12 ) != 0x12 && ( data & 0x12 ) == 0x12 ) + { + m_write = 0x0F; + } + else + { + membank("bank1")->set_base(&m_vram[isa8_cga_pc1512_device::vram_offset[0]]); + } + m_mode_control = data; + switch( m_mode_control & 0x3F ) + { + case 0x08: case 0x09: case 0x0C: case 0x0D: + mc6845->set_hpixels_per_column( 8 ); + m_update_row_type = CGA_TEXT_INTEN; + break; + case 0x0A: case 0x0B: case 0x2A: case 0x2B: + mc6845->set_hpixels_per_column( 8 ); + if ( ( CGA_MONITOR ) == CGA_MONITOR_COMPOSITE ) + { + m_update_row_type = CGA_GFX_4BPPL; + } + else + { + m_update_row_type = CGA_GFX_2BPP; + } + break; + case 0x0E: case 0x0F: case 0x2E: case 0x2F: + mc6845->set_hpixels_per_column( 8 ); + m_update_row_type = CGA_GFX_2BPP; + break; + case 0x18: case 0x19: case 0x1C: case 0x1D: + mc6845->set_hpixels_per_column( 8 ); + m_update_row_type = CGA_TEXT_INTEN_ALT; + break; + case 0x1A: case 0x1B: case 0x3A: case 0x3B: + mc6845->set_hpixels_per_column( 8 ); + m_update_row_type = PC1512_GFX_4BPP; + break; + case 0x1E: case 0x1F: case 0x3E: case 0x3F: + mc6845->set_hpixels_per_column( 16 ); + m_update_row_type = CGA_GFX_1BPP; + break; + case 0x28: case 0x29: case 0x2C: case 0x2D: + mc6845->set_hpixels_per_column( 8 ); + m_update_row_type = CGA_TEXT_BLINK; + break; + case 0x38: case 0x39: case 0x3C: case 0x3D: + mc6845->set_hpixels_per_column( 8 ); + m_update_row_type = CGA_TEXT_BLINK_ALT; + break; + default: + m_update_row_type = -1; + break; + } + break; + + case 0xd: + m_write = data; + break; + + case 0xe: + m_read = data; + if ( ( m_mode_control & 0x12 ) == 0x12 ) + { + membank("bank1")->set_base(&m_vram[isa8_cga_pc1512_device::vram_offset[data & 3]]); + } + break; + + default: + isa8_cga_device::io_write(space, offset,data); + break; + } +} + + +READ8_MEMBER( isa8_cga_pc1512_device::io_read ) +{ + UINT8 data; + + switch (offset) + { + case 0xd: + data = m_write; + break; + + case 0xe: + data = m_read; + break; + + default: + data = isa8_cga_device::io_read(space, offset); + break; + } + return data; +} + + +WRITE8_MEMBER( isa8_cga_pc1512_device::vram_w ) +{ + if ( ( m_mode_control & 0x12 ) == 0x12 ) + { + if (m_write & 1) + m_vram[offset+isa8_cga_pc1512_device::vram_offset[0]] = data; /* blue plane */ + if (m_write & 2) + m_vram[offset+isa8_cga_pc1512_device::vram_offset[1]] = data; /* green */ + if (m_write & 4) + m_vram[offset+isa8_cga_pc1512_device::vram_offset[2]] = data; /* red */ + if (m_write & 8) + m_vram[offset+isa8_cga_pc1512_device::vram_offset[3]] = data; /* intensity (text, 4color) */ + } + else + { + m_vram[offset + isa8_cga_pc1512_device::vram_offset[0]] = data; + } +} + + +const device_type ISA8_CGA_PC1512 = &device_creator; + +const offs_t isa8_cga_pc1512_device::vram_offset[4]= { 0x0000, 0x4000, 0x8000, 0xC000 }; +const UINT8 isa8_cga_pc1512_device::mc6845_writeonce_register[31] = +{ + 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +//------------------------------------------------- +// isa8_cga_pc1512_device - constructor +//------------------------------------------------- + +isa8_cga_pc1512_device::isa8_cga_pc1512_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + isa8_cga_device( mconfig, ISA8_CGA_PC1512, "ISA8_CGA_PC1512", tag, owner, clock, "cga_pc1512", __FILE__) +{ + m_vram_size = 0x10000; + m_chr_gen_offset[0] = 0x0000; + m_chr_gen_offset[1] = 0x0800; + m_chr_gen_offset[2] = 0x1000; + m_chr_gen_offset[3] = 0x1800; +} + + +const rom_entry *isa8_cga_pc1512_device::device_rom_region() const +{ + return NULL; +} + + +ioport_constructor isa8_cga_pc1512_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( pc1512 ); +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void isa8_cga_pc1512_device::device_start() +{ + isa8_cga_device::device_start(); + + m_isa->install_device(0x3d0, 0x3df, 0, 0, read8_delegate( FUNC(isa8_cga_pc1512_device::io_read), this ), write8_delegate( FUNC(isa8_cga_pc1512_device::io_write), this ) ); + m_isa->install_bank(0xb8000, 0xbbfff, 0, 0, "bank1", &m_vram[0]); + + address_space &space = machine().firstcpu->space( AS_PROGRAM ); + + space.install_write_handler( 0xb8000, 0xbbfff, 0, 0x0C000, write8_delegate( FUNC(isa8_cga_pc1512_device::vram_w), this ) ); +} + +void isa8_cga_pc1512_device::device_reset() +{ + isa8_cga_device::device_reset(); + + m_write = 0x0f; + m_read = 0; + m_mc6845_address = 0; + for ( int i = 0; i < 31; i++ ) + { + m_mc6845_locked_register[i] = 0; + } + + membank("bank1")->set_base(&m_vram[isa8_cga_pc1512_device::vram_offset[0]]); +} + +void isa8_wyse700_device::change_resolution(UINT8 mode) +{ + int width = 0, height = 0; + if (mode & 2) { + machine().root_device().membank("bank_wy1")->set_base(&m_vram[0x10000]); + } else { + machine().root_device().membank("bank_wy1")->set_base(&m_vram[0x00000]); + } + if ((m_control & 0xf0) == (mode & 0xf0)) return; + + switch(mode & 0xf0) { + case 0xc0: width = 1280; height = 800; break; + case 0xa0: width = 1280; height = 400; break; + case 0x80: width = 640; height = 400; break; + case 0x00: width = 640; height = 400; break; // unhandled + } + rectangle visarea(0, width-1, 0, height-1); + subdevice(CGA_SCREEN_NAME)->configure(width, height, visarea, HZ_TO_ATTOSECONDS(60)); + +} + +WRITE8_MEMBER( isa8_wyse700_device::io_write ) +{ + switch (offset) + { + case 0xd: + m_bank_offset = data; + break; + + case 0xe: + m_bank_base = data; + break; + + case 0xf: + change_resolution(data); + m_control = data; + break; + default: + isa8_cga_device::io_write(space, offset,data); + break; + } +} + + +READ8_MEMBER( isa8_wyse700_device::io_read ) +{ + UINT8 data; + + switch (offset) + { + case 0xd: + data = m_bank_offset; + break; + + case 0xe: + data = m_bank_base; + break; + + case 0xf: + data = m_control; + break; + default: + data = isa8_cga_device::io_read(space, offset); + break; + } + return data; +} + + +const device_type ISA8_WYSE700 = &device_creator; + + +//------------------------------------------------- +// isa8_wyse700_device - constructor +//------------------------------------------------- + +isa8_wyse700_device::isa8_wyse700_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + isa8_cga_device( mconfig, ISA8_WYSE700, "Wyse 700", tag, owner, clock, "wyse700", __FILE__) +{ + m_vram_size = 0x20000; + m_start_offset = 0x18000; +} + +/* +Character ROMs: + +250211-03.e5: Character ROM Label: "(C) WYSE TECH / REV.A / 250211-03" +250212-03.f5: Character ROM Label: "(C) WYSE TECH / REV.A / 250212-03" + +Not dumped: + +250026-03.2d: MC68705 MCU Label: "(C) WYSE TECH / REV.1 / 250026-03" +250270-01.8b: PAL? Label: "250270-01" +250024-01.8g: PAL? Label: "250024-01" +250210-01.c2: PAL? Label: "250210-01" +*/ +ROM_START( wyse700 ) + ROM_REGION(0x4000,"gfx1", 0) + ROM_LOAD( "250211-03.e5", 0x0000, 0x2000, CRC(58b61f63) SHA1(29ecb7cf7d07d692f0fc54e2dea8389f17a65f1a)) + ROM_LOAD( "250212-03.f5", 0x2000, 0x2000, CRC(6930d741) SHA1(1beeb133c5e39eee9914bdc5924039d70b5edcad)) +ROM_END + +const rom_entry *isa8_wyse700_device::device_rom_region() const +{ + return ROM_NAME( wyse700 ); +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void isa8_wyse700_device::device_start() +{ + isa8_cga_device::device_start(); + + m_isa->install_device(0x3d0, 0x3df, 0, 0, read8_delegate( FUNC(isa8_wyse700_device::io_read), this ), write8_delegate( FUNC(isa8_wyse700_device::io_write), this ) ); + m_isa->install_bank(0xa0000, 0xaffff, 0, 0, "bank_wy1", &m_vram[0x00000]); + m_isa->install_bank(0xb0000, 0xbffff, 0, 0, "bank_cga", &m_vram[0x10000]); +} + +void isa8_wyse700_device::device_reset() +{ + isa8_cga_device::device_reset(); + m_control = 0; + m_bank_offset = 0; + m_bank_base = 0; +} + +UINT32 isa8_wyse700_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + if (m_control & 0x08) { + const rgb_t *palette = m_palette->palette()->entry_list_raw(); + UINT8 fg = m_color_select & 0x0F; + UINT32 addr = 0; + for (int y = 0; y < 800; y++) { + UINT8 *src = &m_vram[addr]; + + if (y & 1) { + src += 0x10000; + addr += 160; + } + + for (int x = 0; x < (1280 / 8); x++) { + UINT8 val = src[x]; + + for (int i = 0; i < 8; i++) { + bitmap.pix32(y,x*8+i) = (val & 0x80) ? palette[fg] : palette[0x00]; + val <<= 1; + } + } + } + } else { + return isa8_cga_device::screen_update(screen, bitmap, cliprect); + } + return 0; +} + + +const device_type ISA8_EC1841_0002 = &device_creator; + +//------------------------------------------------- +// isa8_ec1841_0002_device - constructor +//------------------------------------------------- + +isa8_ec1841_0002_device::isa8_ec1841_0002_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + isa8_cga_device( mconfig, ISA8_EC1841_0002, "EC 1841.0002 (CGA)", tag, owner, clock, "ec1841_0002", __FILE__) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void isa8_ec1841_0002_device::device_start() +{ + isa8_cga_device::device_start(); + + m_isa->install_device(0x3d0, 0x3df, 0, 0, read8_delegate( FUNC(isa8_ec1841_0002_device::io_read), this ), write8_delegate( FUNC(isa8_ec1841_0002_device::io_write), this ) ); +} + +void isa8_ec1841_0002_device::device_reset() +{ + isa8_cga_device::device_reset(); + m_p3df = 0; +} + +WRITE8_MEMBER( isa8_ec1841_0002_device::char_ram_write ) +{ + offset ^= BIT(offset, 12); +// logerror("write char ram %04x %02x\n",offset,data); + m_chr_gen_base[offset + 0x0000] = data; + m_chr_gen_base[offset + 0x0800] = data; + m_chr_gen_base[offset + 0x1000] = data; + m_chr_gen_base[offset + 0x1800] = data; +} + +READ8_MEMBER( isa8_ec1841_0002_device::char_ram_read ) +{ + offset ^= BIT(offset, 12); + return m_chr_gen_base[offset]; +} + +WRITE8_MEMBER( isa8_ec1841_0002_device::io_write ) +{ + switch (offset) + { + case 0x0f: + m_p3df = data; + if (data & 1) { + m_isa->install_memory(0xb8000, 0xb9fff, 0, m_vram_size & 0x4000, + read8_delegate( FUNC(isa8_ec1841_0002_device::char_ram_read), this), + write8_delegate(FUNC(isa8_ec1841_0002_device::char_ram_write), this) ); + } else { + m_isa->install_bank(0xb8000, 0xb8000 + MIN(0x8000,m_vram_size) - 1, 0, m_vram_size & 0x4000, "bank_cga", &m_vram[0]); + } + break; + default: + isa8_cga_device::io_write(space, offset, data); + break; + } +} + +READ8_MEMBER( isa8_ec1841_0002_device::io_read ) +{ + UINT8 data; + + switch (offset) + { + case 0x0f: + data = m_p3df; + break; + default: + data = isa8_cga_device::io_read(space, offset); + break; + } + return data; +} + +const device_type ISA8_CGA_MC1502 = &device_creator; + +//------------------------------------------------- +// isa8_cga_mc1502_device - constructor +//------------------------------------------------- + +isa8_cga_mc1502_device::isa8_cga_mc1502_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + isa8_cga_device( mconfig, ISA8_CGA_MC1502, "MC1502 CGA", tag, owner, clock, "cga_mc1502", __FILE__) +{ + m_vram_size = 0x8000; + m_chr_gen_offset[0] = 0x0000; + m_chr_gen_offset[1] = 0x0800; + +} + +ROM_START( cga_iskr1031 ) + ROM_REGION(0x2000,"gfx1", 0) + ROM_LOAD( "iskra-1031_font.bin", 0x0000, 0x2000, CRC(f4d62e80) SHA1(ad7e81a0c9abc224671422bbcf6f6262da92b510)) +ROM_END + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *isa8_cga_iskr1031_device::device_rom_region() const +{ + return ROM_NAME( cga_iskr1031 ); +} + +const device_type ISA8_CGA_ISKR1031 = &device_creator; + +//------------------------------------------------- +// isa8_cga_iskr1031_device - constructor +//------------------------------------------------- + +isa8_cga_iskr1031_device::isa8_cga_iskr1031_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + isa8_cga_device( mconfig, ISA8_CGA_ISKR1031, "Iskra-1031 CGA", tag, owner, clock, "cga_iskr1031", __FILE__) +{ +} + +ROM_START( cga_iskr1030m ) + ROM_REGION(0x2000,"gfx1", 0) + ROM_LOAD( "iskra-1030m.chr", 0x0000, 0x2000, CRC(50b162eb) SHA1(5bd7cb1705a69bd16115a4c9ed1c2748a5c8ad51)) +ROM_END + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *isa8_cga_iskr1030m_device::device_rom_region() const +{ + return ROM_NAME( cga_iskr1030m ); +} + +const device_type ISA8_CGA_ISKR1030M = &device_creator; + +//------------------------------------------------- +// isa8_cga_iskr1030m_device - constructor +//------------------------------------------------- + +isa8_cga_iskr1030m_device::isa8_cga_iskr1030m_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + isa8_cga_device( mconfig, ISA8_CGA_ISKR1030M, "Iskra-1030M CGA", tag, owner, clock, "cga_iskr1030m", __FILE__) +{ +} + +// XXX + +ROM_START( mc1502 ) + ROM_REGION(0x2000,"gfx1", 0) + // taken from mc1502 + ROM_LOAD( "symgen.rom", 0x0000, 0x2000, CRC(b2747a52) SHA1(6766d275467672436e91ac2997ac6b77700eba1e)) +ROM_END + +const rom_entry *isa8_cga_mc1502_device::device_rom_region() const +{ + return ROM_NAME( mc1502 ); +} + +const device_type ISA8_CGA_M24 = &device_creator; + +isa8_cga_m24_device::isa8_cga_m24_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + isa8_cga_device( mconfig, ISA8_CGA_M24, "Olivetti M24 CGA", tag, owner, clock, "cga_m24", __FILE__) +{ + m_vram_size = 0x8000; +} + +void isa8_cga_m24_device::device_reset() +{ + isa8_cga_device::device_reset(); + m_mode2 = 0; + m_start_offset = 0; +} + +WRITE8_MEMBER( isa8_cga_m24_device::io_write ) +{ + mc6845_device *mc6845 = subdevice(CGA_MC6845_NAME); + switch(offset) + { + case 0: case 2: case 4: case 6: + m_index = data; + mc6845->address_w( space, offset, data ); + break; + case 1: case 3: case 5: case 7: + switch(m_index & 0x1f) // TODO: this is handled by a pal and prom + { + case 0: + data &= 0x7f; + break; + case 9: + if((data < 0x80) && (data != 3)) + data = (data << 1) + 1; + break; + case 10: + data = ((data << 1) & 0x1f) | (data & 0x60); + break; + case 11: + data <<= 1; + break; + } + mc6845->register_w( space, offset, data ); + break; + case 0x0e: + m_mode2 = data; + if((data & 8) && !(data & 1)) + m_start_offset = 0x4000; + else + m_start_offset = 0; + break; + default: + isa8_cga_device::io_write(space, offset, data); + break; + } +} + +READ8_MEMBER( isa8_cga_m24_device::io_read ) +{ + UINT8 data = 0xff; + + switch(offset) + { + case 0x0a: + data = 0xc0 | m_vsync | ( ( data & 0x40 ) >> 4 ) | m_hsync; // 0xc0 == no expansion + break; + case 0x0e: + data = m_mode2; + break; + default: + data = isa8_cga_device::io_read(space, offset); + break; + } + return data; +} + +MC6845_UPDATE_ROW( isa8_cga_m24_device::crtc_update_row ) +{ + if(m_mode2 & 1) + m24_gfx_1bpp_m24_update_row(bitmap, cliprect, ma, ra, y, x_count, cursor_x, de, hbp, vbp); + else + isa8_cga_device::crtc_update_row(bitmap, cliprect, ma, ra >> 1, y, x_count, cursor_x, de, hbp, vbp); +} + +MC6845_UPDATE_ROW( isa8_cga_m24_device::m24_gfx_1bpp_m24_update_row ) +{ + UINT8 *videoram = &m_vram[m_start_offset]; + UINT32 *p = &bitmap.pix32(y); + const rgb_t *palette = m_palette->palette()->entry_list_raw(); + UINT8 fg = m_color_select & 0x0F; + int i; + + if ( y == 0 ) CGA_LOG(1,"m24_gfx_1bpp_m24_update_row",("\n")); + for ( i = 0; i < x_count; i++ ) + { + UINT16 offset = ( ( ( ma + i ) << 1 ) & 0x1fff ) | ( ( ra & 3 ) << 13 ); + UINT8 data = videoram[ offset ]; + + *p = palette[( data & 0x80 ) ? fg : 0]; p++; + *p = palette[( data & 0x40 ) ? fg : 0]; p++; + *p = palette[( data & 0x20 ) ? fg : 0]; p++; + *p = palette[( data & 0x10 ) ? fg : 0]; p++; + *p = palette[( data & 0x08 ) ? fg : 0]; p++; + *p = palette[( data & 0x04 ) ? fg : 0]; p++; + *p = palette[( data & 0x02 ) ? fg : 0]; p++; + *p = palette[( data & 0x01 ) ? fg : 0]; p++; + + data = videoram[ offset + 1 ]; + + *p = palette[( data & 0x80 ) ? fg : 0]; p++; + *p = palette[( data & 0x40 ) ? fg : 0]; p++; + *p = palette[( data & 0x20 ) ? fg : 0]; p++; + *p = palette[( data & 0x10 ) ? fg : 0]; p++; + *p = palette[( data & 0x08 ) ? fg : 0]; p++; + *p = palette[( data & 0x04 ) ? fg : 0]; p++; + *p = palette[( data & 0x02 ) ? fg : 0]; p++; + *p = palette[( data & 0x01 ) ? fg : 0]; p++; + } +} diff --git a/src/devices/bus/isa/cga.h b/src/devices/bus/isa/cga.h new file mode 100644 index 00000000000..d6dcb791bf3 --- /dev/null +++ b/src/devices/bus/isa/cga.h @@ -0,0 +1,286 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +#pragma once + +#ifndef __ISA_CGA_H__ +#define __ISA_CGA_H__ + +#include "emu.h" +#include "isa.h" +#include "video/mc6845.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> isa8_cga_device + +class isa8_cga_device : + public device_t, + public device_isa8_card_interface +{ + friend class isa8_cga_superimpose_device; +// friend class isa8_ec1841_0002_device; + friend class isa8_cga_poisk2_device; + friend class isa8_cga_pc1512_device; + +public: + // construction/destruction + isa8_cga_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + isa8_cga_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + virtual MC6845_UPDATE_ROW( crtc_update_row ); + MC6845_UPDATE_ROW( cga_text_inten_update_row ); + MC6845_UPDATE_ROW( cga_text_inten_comp_grey_update_row ); + MC6845_UPDATE_ROW( cga_text_inten_alt_update_row ); + MC6845_UPDATE_ROW( cga_text_blink_update_row ); + MC6845_UPDATE_ROW( cga_text_blink_update_row_si ); + MC6845_UPDATE_ROW( cga_text_blink_alt_update_row ); + MC6845_UPDATE_ROW( cga_gfx_4bppl_update_row ); + MC6845_UPDATE_ROW( cga_gfx_4bpph_update_row ); + MC6845_UPDATE_ROW( cga_gfx_2bpp_update_row ); + MC6845_UPDATE_ROW( cga_gfx_1bpp_update_row ); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual ioport_constructor device_input_ports() const; + virtual const rom_entry *device_rom_region() const; + +protected: + required_ioport m_cga_config; + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); +public: + void mode_control_w(UINT8 data); + void set_palette_luts(); + void plantronics_w(UINT8 data); + virtual DECLARE_READ8_MEMBER( io_read ); + virtual DECLARE_WRITE8_MEMBER( io_write ); + DECLARE_WRITE_LINE_MEMBER( hsync_changed ); + DECLARE_WRITE_LINE_MEMBER( vsync_changed ); + virtual UINT32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); + +public: + int m_framecnt; + + UINT8 m_mode_control; /* wo 0x3d8 */ + UINT8 m_color_select; /* wo 0x3d9 */ + //UINT8 m_status; //unused? /* ro 0x3da */ + + int m_update_row_type; + UINT8 m_palette_lut_2bpp[4]; + offs_t m_chr_gen_offset[4]; + UINT8 m_font_selection_mask; + UINT8 *m_chr_gen_base; + UINT8 *m_chr_gen; + UINT8 m_vsync; + UINT8 m_hsync; + size_t m_vram_size; + dynamic_buffer m_vram; + bool m_superimpose; + UINT8 m_plantronics; /* This should be moved into the appropriate subclass */ + offs_t m_start_offset; + required_device m_palette; +}; + +// device type definition +extern const device_type ISA8_CGA; + + +// ======================> isa8_cga_superimpose_device + +class isa8_cga_superimpose_device : + public isa8_cga_device +{ +public: + // construction/destruction + isa8_cga_superimpose_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + isa8_cga_superimpose_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); +}; + +// device type definition +extern const device_type ISA8_CGA_SUPERIMPOSE; + + +// ======================> isa8_poisk2_device + +class isa8_cga_poisk2_device : + public isa8_cga_device +{ +public: + // construction/destruction + isa8_cga_poisk2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + // optional information overrides + virtual const rom_entry *device_rom_region() const; +}; + +// device type definition +extern const device_type ISA8_CGA_POISK2; + + +// ======================> isa8_pc1512_device + +class isa8_cga_pc1512_device : + public isa8_cga_device +{ +public: + // construction/destruction + isa8_cga_pc1512_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + // optional information overrides + virtual ioport_constructor device_input_ports() const; + virtual const rom_entry *device_rom_region() const; + + virtual MC6845_UPDATE_ROW( crtc_update_row ); + MC6845_UPDATE_ROW( pc1512_gfx_4bpp_update_row ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + +public: + UINT8 m_write; + UINT8 m_read; + UINT8 m_mc6845_address; + UINT8 m_mc6845_locked_register[31]; + +public: + // Static information + // mapping of the 4 planes into videoram + // (text data should be readable at videoram+0) + static const offs_t vram_offset[4]; + static const UINT8 mc6845_writeonce_register[31]; + + virtual DECLARE_READ8_MEMBER( io_read ); + virtual DECLARE_WRITE8_MEMBER( io_write ); + + DECLARE_WRITE8_MEMBER( vram_w ); +}; + +// device type definition +extern const device_type ISA8_CGA_PC1512; + +// ======================> isa8_wyse700_device + +class isa8_wyse700_device : + public isa8_cga_device +{ +public: + // construction/destruction + isa8_wyse700_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + // optional information overrides + virtual const rom_entry *device_rom_region() const; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + +public: + virtual DECLARE_READ8_MEMBER( io_read ); + virtual DECLARE_WRITE8_MEMBER( io_write ); + virtual UINT32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); + void change_resolution(UINT8 mode); + + UINT8 m_bank_offset; + UINT8 m_bank_base; + UINT8 m_control; +}; + +// device type definition +extern const device_type ISA8_WYSE700; + +// ======================> isa8_ec1841_0002_device + +class isa8_ec1841_0002_device : + public isa8_cga_device +{ +public: + // construction/destruction + isa8_ec1841_0002_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + +public: + virtual DECLARE_READ8_MEMBER( io_read ); + virtual DECLARE_WRITE8_MEMBER( io_write ); + + UINT8 m_p3df; + DECLARE_READ8_MEMBER( char_ram_read ); + DECLARE_WRITE8_MEMBER( char_ram_write ); +}; + +// device type definition +extern const device_type ISA8_EC1841_0002; + +// ======================> isa8_cga_iskr1031_device + +class isa8_cga_iskr1030m_device : + public isa8_cga_device +{ +public: + // construction/destruction + isa8_cga_iskr1030m_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual const rom_entry *device_rom_region() const; +}; + +// device type definition +extern const device_type ISA8_CGA_ISKR1030M; + +// ======================> isa8_cga_iskr1031_device + +class isa8_cga_iskr1031_device : + public isa8_cga_device +{ +public: + // construction/destruction + isa8_cga_iskr1031_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual const rom_entry *device_rom_region() const; +}; + +// device type definition +extern const device_type ISA8_CGA_ISKR1031; + +// ======================> isa8_cga_mc1502_device + +class isa8_cga_mc1502_device : + public isa8_cga_device +{ +public: + // construction/destruction + isa8_cga_mc1502_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + // optional information overrides + virtual const rom_entry *device_rom_region() const; +}; + +// device type definition +extern const device_type ISA8_CGA_MC1502; + + +class isa8_cga_m24_device : + public isa8_cga_device +{ +public: + // construction/destruction + isa8_cga_m24_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + // optional information overrides + //virtual const rom_entry *device_rom_region() const; + virtual DECLARE_READ8_MEMBER( io_read ); + virtual DECLARE_WRITE8_MEMBER( io_write ); + virtual MC6845_UPDATE_ROW( crtc_update_row ); + MC6845_UPDATE_ROW( m24_gfx_1bpp_m24_update_row ); +protected: + virtual void device_reset(); +private: + UINT8 m_mode2, m_index; +}; + +// device type definition +extern const device_type ISA8_CGA_M24; + +#endif /* __ISA_CGA_H__ */ diff --git a/src/devices/bus/isa/com.c b/src/devices/bus/isa/com.c new file mode 100644 index 00000000000..6d4873009a4 --- /dev/null +++ b/src/devices/bus/isa/com.c @@ -0,0 +1,194 @@ +// license:BSD-3-Clause +// copyright-holders:Carl,Miodrag Milanovic +/*************************************************************************** + + ISA 8 bit Generic Communication Card + +***************************************************************************/ + +#include "com.h" +#include "bus/rs232/rs232.h" +#include "bus/rs232/ser_mouse.h" +#include "bus/rs232/terminal.h" +#include "bus/rs232/null_modem.h" +#include "machine/ins8250.h" + +static SLOT_INTERFACE_START(isa_com) + SLOT_INTERFACE("microsoft_mouse", MSFT_SERIAL_MOUSE) + SLOT_INTERFACE("msystems_mouse", MSYSTEM_SERIAL_MOUSE) + SLOT_INTERFACE("terminal", SERIAL_TERMINAL) + SLOT_INTERFACE("null_modem", NULL_MODEM) +SLOT_INTERFACE_END + +static MACHINE_CONFIG_FRAGMENT( com_config ) + MCFG_DEVICE_ADD( "uart_0", INS8250, XTAL_1_8432MHz ) + MCFG_INS8250_OUT_TX_CB(DEVWRITELINE("serport0", rs232_port_device, write_txd)) + MCFG_INS8250_OUT_DTR_CB(DEVWRITELINE("serport0", rs232_port_device, write_dtr)) + MCFG_INS8250_OUT_RTS_CB(DEVWRITELINE("serport0", rs232_port_device, write_rts)) + MCFG_INS8250_OUT_INT_CB(WRITELINE(isa8_com_device, pc_com_interrupt_1)) + MCFG_DEVICE_ADD( "uart_1", INS8250, XTAL_1_8432MHz ) + MCFG_INS8250_OUT_TX_CB(DEVWRITELINE("serport1", rs232_port_device, write_txd)) + MCFG_INS8250_OUT_DTR_CB(DEVWRITELINE("serport1", rs232_port_device, write_dtr)) + MCFG_INS8250_OUT_RTS_CB(DEVWRITELINE("serport1", rs232_port_device, write_rts)) + MCFG_INS8250_OUT_INT_CB(WRITELINE(isa8_com_device, pc_com_interrupt_2)) + /*MCFG_DEVICE_ADD( "uart_2", INS8250, XTAL_1_8432MHz ) + MCFG_INS8250_OUT_TX_CB(DEVWRITELINE("serport2", rs232_port_device, write_txd)) + MCFG_INS8250_OUT_DTR_CB(DEVWRITELINE("serport2", rs232_port_device, write_dtr)) + MCFG_INS8250_OUT_RTS_CB(DEVWRITELINE("serport2", rs232_port_device, write_rts)) + MCFG_INS8250_OUT_INT_CB(WRITELINE(isa8_com_device, pc_com_interrupt_1)) + MCFG_DEVICE_ADD( "uart_3", INS8250, XTAL_1_8432MHz ) + MCFG_INS8250_OUT_TX_CB(DEVWRITELINE("serport3", rs232_port_device, write_txd)) + MCFG_INS8250_OUT_DTR_CB(DEVWRITELINE("serport3", rs232_port_device, write_dtr)) + MCFG_INS8250_OUT_RTS_CB(DEVWRITELINE("serport3", rs232_port_device, write_rts)) + MCFG_INS8250_OUT_INT_CB(WRITELINE(isa8_com_device, pc_com_interrupt_2))*/ + + MCFG_RS232_PORT_ADD( "serport0", isa_com, "microsoft_mouse" ) + MCFG_RS232_RXD_HANDLER(DEVWRITELINE("uart_0", ins8250_uart_device, rx_w)) + MCFG_RS232_DCD_HANDLER(DEVWRITELINE("uart_0", ins8250_uart_device, dcd_w)) + MCFG_RS232_DSR_HANDLER(DEVWRITELINE("uart_0", ins8250_uart_device, dsr_w)) + MCFG_RS232_RI_HANDLER(DEVWRITELINE("uart_0", ins8250_uart_device, ri_w)) + MCFG_RS232_CTS_HANDLER(DEVWRITELINE("uart_0", ins8250_uart_device, cts_w)) + + MCFG_RS232_PORT_ADD( "serport1", isa_com, NULL ) + MCFG_RS232_RXD_HANDLER(DEVWRITELINE("uart_1", ins8250_uart_device, rx_w)) + MCFG_RS232_DCD_HANDLER(DEVWRITELINE("uart_1", ins8250_uart_device, dcd_w)) + MCFG_RS232_DSR_HANDLER(DEVWRITELINE("uart_1", ins8250_uart_device, dsr_w)) + MCFG_RS232_RI_HANDLER(DEVWRITELINE("uart_1", ins8250_uart_device, ri_w)) + MCFG_RS232_CTS_HANDLER(DEVWRITELINE("uart_1", ins8250_uart_device, cts_w)) + + //MCFG_RS232_PORT_ADD( "serport2", isa_com, NULL ) + //MCFG_RS232_RXD_HANDLER(DEVWRITELINE("uart_1", ins8250_uart_device, rx_w)) + //MCFG_RS232_DCD_HANDLER(DEVWRITELINE("uart_1", ins8250_uart_device, dcd_w)) + //MCFG_RS232_DSR_HANDLER(DEVWRITELINE("uart_1", ins8250_uart_device, dsr_w)) + //MCFG_RS232_RI_HANDLER(DEVWRITELINE("uart_1", ins8250_uart_device, ri_w)) + //MCFG_RS232_CTS_HANDLER(DEVWRITELINE("uart_1", ins8250_uart_device, cts_w)) + + //MCFG_RS232_PORT_ADD( "serport3", isa_com, NULL ) + //MCFG_RS232_RXD_HANDLER(DEVWRITELINE("uart_2", ins8250_uart_device, rx_w)) + //MCFG_RS232_DCD_HANDLER(DEVWRITELINE("uart_2", ins8250_uart_device, dcd_w)) + //MCFG_RS232_DSR_HANDLER(DEVWRITELINE("uart_2", ins8250_uart_device, dsr_w)) + //MCFG_RS232_RI_HANDLER(DEVWRITELINE("uart_2", ins8250_uart_device, ri_w)) + //MCFG_RS232_CTS_HANDLER(DEVWRITELINE("uart_2", ins8250_uart_device, cts_w)) +MACHINE_CONFIG_END + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type ISA8_COM = &device_creator; + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor isa8_com_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( com_config ); +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// isa8_com_device - constructor +//------------------------------------------------- + +isa8_com_device::isa8_com_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, ISA8_COM, "Communications Adapter PC/XT", tag, owner, clock, "isa_com", __FILE__), + device_isa8_card_interface(mconfig, *this) +{ +} + +isa8_com_device::isa8_com_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_isa8_card_interface(mconfig, *this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void isa8_com_device::device_start() +{ + set_isa_device(); + m_isa->install_device(0x03f8, 0x03ff, 0, 0, read8_delegate(FUNC(ins8250_device::ins8250_r), subdevice("uart_0")), write8_delegate(FUNC(ins8250_device::ins8250_w), subdevice("uart_0")) ); + m_isa->install_device(0x02f8, 0x02ff, 0, 0, read8_delegate(FUNC(ins8250_device::ins8250_r), subdevice("uart_1")), write8_delegate(FUNC(ins8250_device::ins8250_w), subdevice("uart_1")) ); +// m_isa->install_device(0x03e8, 0x03ef, 0, 0, read8_delegate(FUNC(ins8250_device::ins8250_r), subdevice("uart_2")), write8_delegate(FUNC(ins8250_device::ins8250_w), subdevice("uart_2")) ); +// m_isa->install_device(0x02e8, 0x02ef, 0, 0, read8_delegate(FUNC(ins8250_device::ins8250_r), subdevice("uart_3")), write8_delegate(FUNC(ins8250_device::ins8250_w), subdevice("uart_3")) ); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void isa8_com_device::device_reset() +{ +} + +static MACHINE_CONFIG_FRAGMENT( com_at_config ) + MCFG_DEVICE_ADD( "uart_0", NS16450, XTAL_1_8432MHz ) /* Verified: IBM P/N 6320947 Serial/Parallel card uses an NS16450N */ + MCFG_INS8250_OUT_TX_CB(DEVWRITELINE("serport0", rs232_port_device, write_txd)) + MCFG_INS8250_OUT_DTR_CB(DEVWRITELINE("serport0", rs232_port_device, write_dtr)) + MCFG_INS8250_OUT_RTS_CB(DEVWRITELINE("serport0", rs232_port_device, write_rts)) + MCFG_INS8250_OUT_INT_CB(WRITELINE(isa8_com_device, pc_com_interrupt_1)) + MCFG_DEVICE_ADD( "uart_1", NS16450, XTAL_1_8432MHz ) + MCFG_INS8250_OUT_TX_CB(DEVWRITELINE("serport1", rs232_port_device, write_txd)) + MCFG_INS8250_OUT_DTR_CB(DEVWRITELINE("serport1", rs232_port_device, write_dtr)) + MCFG_INS8250_OUT_RTS_CB(DEVWRITELINE("serport1", rs232_port_device, write_rts)) + MCFG_INS8250_OUT_INT_CB(WRITELINE(isa8_com_device, pc_com_interrupt_2)) + /*MCFG_DEVICE_ADD( "uart_2", NS16450, XTAL_1_8432MHz ) + MCFG_INS8250_OUT_TX_CB(DEVWRITELINE("serport2", rs232_port_device, write_txd)) + MCFG_INS8250_OUT_DTR_CB(DEVWRITELINE("serport2", rs232_port_device, write_dtr)) + MCFG_INS8250_OUT_RTS_CB(DEVWRITELINE("serport2", rs232_port_device, write_rts)) + MCFG_INS8250_OUT_INT_CB(WRITELINE(isa8_com_device, pc_com_interrupt_1)) + MCFG_DEVICE_ADD( "uart_3", NS16450, XTAL_1_8432MHz ) + MCFG_INS8250_OUT_TX_CB(DEVWRITELINE("serport3", rs232_port_device, write_txd)) + MCFG_INS8250_OUT_DTR_CB(DEVWRITELINE("serport3", rs232_port_device, write_dtr)) + MCFG_INS8250_OUT_RTS_CB(DEVWRITELINE("serport3", rs232_port_device, write_rts)) + MCFG_INS8250_OUT_INT_CB(WRITELINE(isa8_com_device, pc_com_interrupt_2))*/ + MCFG_RS232_PORT_ADD( "serport0", isa_com, "microsoft_mouse" ) + MCFG_RS232_RXD_HANDLER(DEVWRITELINE("uart_0", ins8250_uart_device, rx_w)) + MCFG_RS232_DCD_HANDLER(DEVWRITELINE("uart_0", ins8250_uart_device, dcd_w)) + MCFG_RS232_DSR_HANDLER(DEVWRITELINE("uart_0", ins8250_uart_device, dsr_w)) + MCFG_RS232_RI_HANDLER(DEVWRITELINE("uart_0", ins8250_uart_device, ri_w)) + MCFG_RS232_CTS_HANDLER(DEVWRITELINE("uart_0", ins8250_uart_device, cts_w)) + + MCFG_RS232_PORT_ADD( "serport1", isa_com, NULL ) + MCFG_RS232_RXD_HANDLER(DEVWRITELINE("uart_1", ins8250_uart_device, rx_w)) + MCFG_RS232_DCD_HANDLER(DEVWRITELINE("uart_1", ins8250_uart_device, dcd_w)) + MCFG_RS232_DSR_HANDLER(DEVWRITELINE("uart_1", ins8250_uart_device, dsr_w)) + MCFG_RS232_RI_HANDLER(DEVWRITELINE("uart_1", ins8250_uart_device, ri_w)) + MCFG_RS232_CTS_HANDLER(DEVWRITELINE("uart_1", ins8250_uart_device, cts_w)) + +// MCFG_RS232_PORT_ADD( "serport2", isa_com, NULL ) +// MCFG_RS232_PORT_ADD( "serport3", isa_com, NULL ) +MACHINE_CONFIG_END + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type ISA8_COM_AT = &device_creator; + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor isa8_com_at_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( com_at_config ); +} + +//------------------------------------------------- +// isa8_com_device - constructor +//------------------------------------------------- + +isa8_com_at_device::isa8_com_at_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + isa8_com_device(mconfig, ISA8_COM_AT, "Communications Adapter", tag, owner, clock, "isa_com_at", __FILE__) +{ +} diff --git a/src/devices/bus/isa/com.h b/src/devices/bus/isa/com.h new file mode 100644 index 00000000000..ff48980dc12 --- /dev/null +++ b/src/devices/bus/isa/com.h @@ -0,0 +1,58 @@ +// license:BSD-3-Clause +// copyright-holders:Carl,Miodrag Milanovic +#pragma once + +#ifndef __ISA_COM_H__ +#define __ISA_COM_H__ + +#include "emu.h" +#include "isa.h" + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> isa8_com_device + +class isa8_com_device : + public device_t, + public device_isa8_card_interface +{ +public: + // construction/destruction + isa8_com_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + isa8_com_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + DECLARE_WRITE_LINE_MEMBER(pc_com_interrupt_1) { m_isa->irq4_w(state); } + DECLARE_WRITE_LINE_MEMBER(pc_com_interrupt_2) { m_isa->irq3_w(state); } +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); +}; + + +// device type definition +extern const device_type ISA8_COM; + +// ======================> isa8_com_at_device + +class isa8_com_at_device : + public isa8_com_device +{ +public: + // construction/destruction + isa8_com_at_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; +}; + + +// device type definition +extern const device_type ISA8_COM_AT; + +#endif /* __ISA_COM_H__ */ diff --git a/src/devices/bus/isa/dectalk.c b/src/devices/bus/isa/dectalk.c new file mode 100644 index 00000000000..5cd014b7b6e --- /dev/null +++ b/src/devices/bus/isa/dectalk.c @@ -0,0 +1,220 @@ +// license:BSD-3-Clause +// copyright-holders:Carl +#include "dectalk.h" + +const device_type ISA8_DECTALK = &device_creator; + +dectalk_isa_device::dectalk_isa_device(const machine_config& mconfig, const char* tag, device_t* owner, UINT32 clock) : + device_t(mconfig, ISA8_DECTALK, "DECTalk-PC", tag, owner, clock, "dectalk_isa", __FILE__), + device_isa8_card_interface(mconfig, *this), + m_cpu(*this, "dectalk_cpu"), + m_dac(*this, "dac"), + m_dsp(*this, "dectalk_dsp") +{ +} + +WRITE16_MEMBER(dectalk_isa_device::status_w) +{ + m_stat = data; +} + +READ16_MEMBER(dectalk_isa_device::cmd_r) +{ + return m_cmd; +} + +WRITE16_MEMBER(dectalk_isa_device::data_w) +{ + m_data = data; +} + +READ16_MEMBER(dectalk_isa_device::data_r) +{ + return m_data; +} + +READ16_MEMBER(dectalk_isa_device::host_irq_r) +{ + //m_isa->ir?_w(1); + return 0; +} + +READ8_MEMBER(dectalk_isa_device::dma_r) +{ + m_cpu->drq1_w(0); + return m_dma; +} + +WRITE8_MEMBER(dectalk_isa_device::dma_w) +{ + m_cpu->drq1_w(0); + m_dma = data; +} + +WRITE16_MEMBER(dectalk_isa_device::dac_w) +{ + m_dac->write(data & 0xfff0); +} + +WRITE16_MEMBER(dectalk_isa_device::output_ctl_w) +{ + // X9C503P potentiometer, 8-CS, 4-U/D, 2-INC + if(!(data & 8) && !(m_ctl & 2) && (data & 2)) + { + if((data & 4) && (m_vol < 64)) + m_vol++; + else if(!(data & 4) && m_vol) + m_vol--; + + m_dac->set_output_gain(ALL_OUTPUTS, m_vol / 63.0); + } + m_dsp->set_input_line(INPUT_LINE_RESET, (data & 0x10) ? CLEAR_LINE : ASSERT_LINE); + m_ctl = data; +} + +READ16_MEMBER(dectalk_isa_device::dsp_dma_r) +{ + m_bio = ASSERT_LINE; + m_cpu->drq1_w(0); + return m_dsp_dma; +} + +WRITE16_MEMBER(dectalk_isa_device::dsp_dma_w) +{ + m_bio = CLEAR_LINE; + m_dsp_dma = data; +} + +READ16_MEMBER(dectalk_isa_device::bio_line_r) +{ + // TODO: reading the bio line doesn't cause any direct external effects so this is wrong + if(m_bio == ASSERT_LINE) + m_cpu->drq0_w(1); + return m_bio; +} + +WRITE16_MEMBER(dectalk_isa_device::irq_line_w) +{ + m_cpu->int1_w(0); +} + +WRITE_LINE_MEMBER(dectalk_isa_device::clock_w) +{ + m_dsp->set_input_line(INPUT_LINE_IRQ0, (!(m_ctl & 0x20) || state) ? CLEAR_LINE : ASSERT_LINE); +} + +static ADDRESS_MAP_START(dectalk_cpu_io, AS_IO, 16, dectalk_isa_device) + AM_RANGE(0x0400, 0x0401) AM_READWRITE(cmd_r, status_w) //PCS0 + AM_RANGE(0x0480, 0x0481) AM_READWRITE(data_r, data_w) //PCS1 + AM_RANGE(0x0500, 0x0501) AM_WRITE(dsp_dma_w) //PCS2 + AM_RANGE(0x0580, 0x0581) AM_READ(host_irq_r) //PCS3 + AM_RANGE(0x0600, 0x0601) AM_WRITE(output_ctl_w) //PCS4 + AM_RANGE(0x0680, 0x0681) AM_READWRITE8(dma_r, dma_w, 0xff) //PCS5 + AM_RANGE(0x0700, 0x0701) AM_WRITE(irq_line_w) //PCS6 +ADDRESS_MAP_END + +static ADDRESS_MAP_START(dectalk_cpu_map, AS_PROGRAM, 16, dectalk_isa_device) + AM_RANGE(0x00000, 0xFBFFF) AM_RAM + AM_RANGE(0xFC000, 0xFFFFF) AM_ROM AM_REGION("dectalk_cpu", 0) +ADDRESS_MAP_END + +static ADDRESS_MAP_START(dectalk_dsp_io, AS_IO, 16, dectalk_isa_device) + AM_RANGE(0x0, 0x0) AM_READ(dsp_dma_r) + AM_RANGE(0x1, 0x1) AM_READWRITE(dsp_dma_r, dac_w) + AM_RANGE(TMS32010_BIO, TMS32010_BIO) AM_READ(bio_line_r) +ADDRESS_MAP_END + +static ADDRESS_MAP_START(dectalk_dsp_map, AS_PROGRAM, 16, dectalk_isa_device) + AM_RANGE(0x0000, 0x0FFF) AM_ROM AM_REGION("dectalk_dsp", 0) +ADDRESS_MAP_END + +static MACHINE_CONFIG_FRAGMENT( dectalk_isa ) + MCFG_CPU_ADD("dectalk_cpu", I80186, XTAL_20MHz) + MCFG_CPU_IO_MAP(dectalk_cpu_io) + MCFG_CPU_PROGRAM_MAP(dectalk_cpu_map) + MCFG_80186_TMROUT0_HANDLER(WRITELINE(dectalk_isa_device, clock_w)); + + MCFG_CPU_ADD("dectalk_dsp", TMS32015, XTAL_20MHz) + MCFG_CPU_IO_MAP(dectalk_dsp_io) + MCFG_CPU_PROGRAM_MAP(dectalk_dsp_map) + + MCFG_SPEAKER_STANDARD_MONO("speaker") + MCFG_SOUND_ADD("dac", DAC, 0) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "speaker", 1.00) +MACHINE_CONFIG_END + +ROM_START( dectalk_isa ) + ROM_REGION( 0x4000, "dectalk_cpu", 0 ) + ROM_LOAD16_BYTE("pc_boot_hxl.am27c64.d6.e26", 0x0000, 0x2000, CRC(7492f1e3) SHA1(fe6946a227f01c94f2b99220320a616445c96ee0)) // Some cards have a different label on the chip which lists the sum16: 31AC (matches contents) + ROM_LOAD16_BYTE("pc_boot_hxh.am27c64.d8.e27", 0x0001, 0x2000, CRC(1fe7fe40) SHA1(6e89c237f01aa22e0d21ff4d6fdf8137c6ace374)) // Some cards have a different label on the chip which lists the sum16: 1A25 (matches contents) + ROM_REGION( 0x2000, "dectalk_dsp", 0 ) + ROM_LOAD("spc_034c__2-1-92.tms320p15nl.d3.bin", 0x0000, 0x2000, CRC(d8b1201e) SHA1(4b873a5e882205fcac79a27562054b5c4d1a117c)) +ROM_END + +const rom_entry* dectalk_isa_device::device_rom_region() const +{ + return ROM_NAME( dectalk_isa ); +} + +machine_config_constructor dectalk_isa_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( dectalk_isa ); +} + +WRITE8_MEMBER(dectalk_isa_device::write) +{ + switch(offset) + { + case 0: + m_cmd = (m_cmd & 0xff00) | data; + break; + case 1: + m_cmd = (m_cmd & 0xff) | (data << 8); + break; + case 2: + m_data = (m_data & 0xff00) | data; + break; + case 3: + m_data = (m_data & 0xff) | (data << 8); + break; + case 4: + m_dma = data; + m_cpu->drq1_w(1); + break; + case 6: + m_cpu->int1_w(1); + break; + } +} + +READ8_MEMBER(dectalk_isa_device::read) +{ + switch(offset) + { + case 0: + return m_stat & 0xff; + case 1: + return m_stat >> 8; + case 2: + return m_data & 0xff; + case 3: + return m_data >> 8; + case 4: + m_cpu->drq1_w(1); + return m_dma; + } + return 0; +} + +void dectalk_isa_device::device_start() +{ + set_isa_device(); + m_isa->install_device(0x0250, 0x0257, 0, 0, read8_delegate(FUNC(dectalk_isa_device::read), this), write8_delegate(FUNC(dectalk_isa_device::write), this)); +} + +void dectalk_isa_device::device_reset() +{ + m_ctl = 0; + m_vol = 63; + m_bio = ASSERT_LINE; +} diff --git a/src/devices/bus/isa/dectalk.h b/src/devices/bus/isa/dectalk.h new file mode 100644 index 00000000000..029d41e8263 --- /dev/null +++ b/src/devices/bus/isa/dectalk.h @@ -0,0 +1,56 @@ +// license:BSD-3-Clause +// copyright-holders:Carl +#ifndef ISA_DECTALK_H_ +#define ISA_DECTALK_H_ + +#include "emu.h" +#include "isa.h" +#include "sound/dac.h" +#include "cpu/i86/i186.h" +#include "cpu/tms32010/tms32010.h" + +class dectalk_isa_device : public device_t, + public device_isa8_card_interface +{ +public: + dectalk_isa_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + + DECLARE_WRITE8_MEMBER(write); + DECLARE_READ8_MEMBER(read); + + DECLARE_WRITE16_MEMBER(status_w); + DECLARE_READ16_MEMBER(cmd_r); + DECLARE_WRITE16_MEMBER(data_w); + DECLARE_READ16_MEMBER(data_r); + DECLARE_READ16_MEMBER(host_irq_r); + DECLARE_READ8_MEMBER(dma_r); + DECLARE_WRITE8_MEMBER(dma_w); + DECLARE_WRITE16_MEMBER(dac_w); + DECLARE_READ16_MEMBER(dsp_dma_r); + DECLARE_WRITE16_MEMBER(dsp_dma_w); + DECLARE_WRITE16_MEMBER(output_ctl_w); + DECLARE_READ16_MEMBER(bio_line_r); + DECLARE_WRITE16_MEMBER(irq_line_w); + DECLARE_WRITE_LINE_MEMBER(clock_w); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + +private: + UINT16 m_cmd, m_stat, m_data, m_dsp_dma, m_ctl; + UINT8 m_dma, m_vol, m_bio; + + required_device m_cpu; + required_device m_dac; + required_device m_dsp; +}; + +extern const device_type ISA8_DECTALK; + +#endif /* ISA_DECTALK_H_ */ diff --git a/src/devices/bus/isa/ega.c b/src/devices/bus/isa/ega.c new file mode 100644 index 00000000000..4da4ead2c6d --- /dev/null +++ b/src/devices/bus/isa/ega.c @@ -0,0 +1,1416 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +/*************************************************************************** + + Enhanced Graphics Adapter (EGA) section + +TODO - Write documentation + +"Regular" register on an EGA graphics card: + + 3C2 - 7 6 5 4 3 2 1 0 - Misc Output Register - Write Only + | | | | | | | | + | | | | | | | +-- 3Bx/3Dx I/O port select + | | | | | | | 0 = 3Bx for CRTC I/O, 3BA for status reg 1 + | | | | | | | 1 = 3Dx for CRTC I/O, 3DA for status reg 1 + | | | | | | +---- enable ram + | | | | | | 0 = disable ram from the processor + | | | | | | 1 = enable ram to respond to addresses + | | | | | | designated by the Control Data Select + | | | | | | value in the Graphics Controllers. + | | | | | +------ clock select bit 0 + | | | | +-------- clock select bit 1 + | | | | 00 = 14MHz from Processor I/O channel + | | | | 01 = 16MHz on-bord clock + | | | | 10 = External clock from feature connector + | | | | 11 = reserved/unused + | | | +---------- disable video drivers + | | | 0 = activate internal video drivers + | | | 1 = disable internal video drivers + | | +------------ page bit for odd/even. Selects between 2 pages + | | of 64KB of memory when in odd/even mode. + | | 0 = select low page + | | 1 = select high page + | +-------------- horizontal retrace polarity + | 0 = select positive + | 1 = select negative + +---------------- vertical retrace polarity + 0 = select positive + 1 = select negative + + + 3C2 - 7 6 5 4 3 2 1 0 - Input Status Reg 0 - Read Only + | | | | | | | | + | | | | | | | +-- reserved/unused + | | | | | | +---- reserved/unused + | | | | | +------ reserved/unused + | | | | +-------- reserved/unused + | | | +---------- switch sense + | | | 0 = switch is closed + | | | 1 = allows processor to read the 4 config switches + | | | on the EGA adapter. The setting of CLKSEL determines + | | | switch to read. + | | +------------ input from FEAT0 on the feature connector + | +-------------- input from FEAT1 on the feature connector + +---------------- CRT Interrupt + 0 = vertical retrace if occurring + 1 = video is being displayed + + + Configuration switches + SW1 SW2 SW3 SW4 + OFF OFF OFF ON - EGA, Color 80x25 (5153) + - EGA (primary) + MDA, Color 80x25 + Monochrome + OFF OFF ON OFF - EGA, Monochrome (5151) + - EGA (primary) + CGA, Monochrome + Color 80x25 + OFF OFF ON ON - EGA + MDA (primary), 5154 + Enhanced Monochrome + OFF ON OFF ON - EGA + CGA (primary), Monochrome + Color 80x25 + OFF ON ON OFF - EGA, Enhanced Color - Enhanced Mode (5154) + - EGA (primary) + MDA, 5154 monitor + Enhanced Monochrome + OFF ON ON ON - EGA + MDA (primary), Color 80x25 + Monochrome + ON OFF OFF ON - EGA, Color 40x25 (5153) + - EGA (primary) + MDA, Color 40x25 + Monochrome + ON OFF ON OFF - EGA (primary) + CGA, Monochrome + Color 40x25 + ON OFF ON ON - EGA + MDA (primary), 5154 + Normal Monochrome + ON ON OFF ON - EGA + CGA (primary), Monochrome + Color 40x25 + ON ON ON OFF - EGA, Enhanced Color - Enhanced Mode (5154) + - EGA (primary) + MDA, 5154 monitor + Normal Monochrome + ON ON ON ON - EGA + MDA (primary), Color 40x25 + Monochrome + + + 3XA - 7 6 5 4 3 2 1 0 - Feature Control Register - Write Only + | | | | | | | | + | | | | | | | +-- output to FEAT0 of the feature connector + | | | | | | +---- output to FEAT1 of the feature connector + | | | | | +------ reserved/unused + | | | | +-------- reserved/unused + | | | +---------- reserved/unused + | | +------------ reserved/unused + | +-------------- reserved/unused + +---------------- reserved/unused + + 3XA - 7 6 5 4 3 2 1 0 - Input Status Reg 1 - Read Only + | | | | | | | | + | | | | | | | +-- display enable + | | | | | | | 0 = indicates the CRT raster is in a horizontal or vertical retrace + | | | | | | | 1 = otherwise + | | | | | | +---- light pen strobe + | | | | | | 0 = light pen trigger has not been set + | | | | | | 1 = light pen trigger has been set + | | | | | +------ light pen switch + | | | | | 0 = switch is closed + | | | | | 1 = switch is open + | | | | +-------- vertical blank + | | | | 0 = video information is being displayed + | | | | 1 = CRT is in vertical blank + | | | +---------- diagnostic usage, output depends on AR12 video status mux bits + | | | mux bits - output + | | | 00 - blue + | | | 01 - I blue + | | | 10 - I red + | | | 11 - unknown + | | +------------ diagnostic usage, output depends on AR12 video status mux bits + | | mux bits - output + | | 00 - red + | | 01 - green + | | 10 - I green + | | 11 - unknown + | +-------------- reserved/unused + +---------------- reserved/unused + + + +The EGA graphics card introduces a lot of new indexed registers to handle the +enhanced graphics. These new indexed registers can be divided into three +groups: +- attribute registers +- sequencer registers +- graphics controllers registers + + +Attribute Registers AR00 - AR13 + +The Attribute Registers are all accessed through I/O port 0x3C0. The first +write to I/O port 0x3C0 sets the index register. The next write to I/O port +0x3C0 actually sets the data to the indexed register. + + 3C0 - 7 6 5 4 3 2 1 0 - Attribute Access Register + | | | | | | | | + | | | | | | | +-- index bit 0 + | | | | | | +---- index bit 1 + | | | | | +------ index bit 2 + | | | | +-------- index bit 3 + | | | +---------- index bit 4 + | | +------------ palette source + | +-------------- reserved/unused + +---------------- reserved/unused + + + AR00-AR0F - 7 6 5 4 3 2 1 0 - Palette Register #00 - #0F + | | | | | | | | + | | | | | | | +-- MSB B + | | | | | | +---- MSB G + | | | | | +------ MSB R + | | | | +-------- LSB B + | | | +---------- LSB G + | | +------------ LSB R + | +-------------- reserved/unused + +---------------- reserved/unused + + + AR10 - 7 6 5 4 3 2 1 0 - Mode Control Register + | | | | | | | | + | | | | | | | +-- Text/Graphics select + | | | | | | +---- Monochrome/Color select + | | | | | +------ 9th dot setting + | | | | +-------- Blink Enable + | | | +---------- reserved/unsued + | | +------------ 0 = line compare does not affect pixel output + | | 1 = line compare does affect pixel output + | +-------------- 0 = pixel changes every dot clock + | 1 = pixel changes every other dot clock + +---------------- reserved/unused + + + AR11 - 7 6 5 4 3 2 1 0 - Overscan Color Register + | | | | | | | | + | | | | | | | +-- MSB B + | | | | | | +---- MSB G + | | | | | +------ MSB R + | | | | +-------- LSB B + | | | +---------- LSB G + | | +------------ LSB R + | +-------------- reserved/unused + +---------------- reserved/unused + + + AR12 - 7 6 5 4 3 2 1 0 - Color Plane Enable Register + | | | | | | | | + | | | | | | | +-- Enable plane 0 + | | | | | | +---- Enable plane 1 + | | | | | +------ Enable plane 2 + | | | | +-------- Enable plane 3 + | | | +---------- Video Status Mux bit 0 + | | +------------ Video Status Mux bit 1 + | +-------------- reserved/unused + +---------------- reserved/unused + + + AR13 - 7 6 5 4 3 2 1 0 - Horizontal Panning Register + | | | | | | | | + | | | | | | | +-- Pixel left shift bit 0 + | | | | | | +---- Pixel left shift bit 1 + | | | | | +------ Pixel left shift bit 2 + | | | | +-------- Pixel left shift bit 3 + | | | +---------- reserved/unused + | | +------------ reserved/unused + | +-------------- reserved/unused + +---------------- reserved/unused + + +Sequencer Registers SR00 - SR04 + +The Sequencer Registers are accessed through an index register located at I/O +port 0x3C4, and a data register located at I/O port 0x3C5. + + 3C4 - 7 6 5 4 3 2 1 0 - Sequencer Index Register - Write Only + | | | | | | | | + | | | | | | | +-- index bit 0 + | | | | | | +---- index bit 1 + | | | | | +------ index bit 2 + | | | | +-------- reserved/unused + | | | +---------- reserved/unused + | | +------------ reserved/unused + | +-------------- reserved/unused + +---------------- reserved/unused + + + 3C5 - 7 6 5 4 3 2 1 0 - Sequencer Data Register - Write Only + | | | | | | | | + | | | | | | | +-- data bit 0 + | | | | | | +---- data bit 1 + | | | | | +------ data bit 2 + | | | | +-------- data bit 3 + | | | +---------- data bit 4 + | | +------------ data bit 5 + | +-------------- data bit 6 + +---------------- data bit 7 + + + SR00 - 7 6 5 4 3 2 1 0 - Reset Control Register + | | | | | | | | + | | | | | | | +-- Must be 1 for normal operation + | | | | | | +---- Must be 1 for normal operation + | | | | | +------ reserved/unused + | | | | +-------- reserved/unused + | | | +---------- reserved/unused + | | +------------ reserved/unused + | +-------------- reserved/unused + +---------------- reserved/unused + + + SR01 - 7 6 5 4 3 2 1 0 - Clocking Mode + | | | | | | | | + | | | | | | | +-- 0 = 9 dots per char, 1 = 8 dots per char + | | | | | | +---- clock frequency, 0 = 4 out of 5 memory cycles, 1 = 2 out of 5 memory cycles + | | | | | +------ shift load + | | | | +-------- 0 = normal dot clock, 1 = master dot clock / 2 + | | | +---------- reserved/unused + | | +------------ reserved/unused + | +-------------- reserved/unused + +---------------- reserved/unused + + + SR02 - 7 6 5 4 3 2 1 0 - Map Mask + | | | | | | | | + | | | | | | | +-- 1 = enable map 0 for writing + | | | | | | +---- 1 = enable map 1 for writing + | | | | | +------ 1 = enable map 2 for writing + | | | | +-------- 1 = enable map 3 for writing + | | | +---------- reserved/unused + | | +------------ reserved/unused + | +-------------- reserved/unused + +---------------- reserved/unused + + + SR03 - 7 6 5 4 3 2 1 0 - Character Map Select + | | | | | | | | + | | | | | | | +-- character map select B bit 0 + | | | | | | +---- character map select B bit 1 + | | | | | | Selects the map used to generate alpha characters when + | | | | | | attribute bit 3 is set to 0 + | | | | | | 00 = map 0 - 1st 8KB of plane 2 bank 0 + | | | | | | 01 = map 1 - 2nd 8KB of plane 2 bank 1 + | | | | | | 10 = map 2 - 3rd 8KB of plane 2 bank 2 + | | | | | | 11 = map 3 - 4th 8KB of plane 2 bank 3 + | | | | | +------ character map select A bit 0 + | | | | +-------- character map select A bit 1 + | | | | Selects the map used to generate alpha characters when + | | | | attribute bit 3 is set to 1 + | | | | 00 = map 0 - 1st 8KB of plane 2 bank 0 + | | | | 01 = map 1 - 2nd 8KB of plane 2 bank 1 + | | | | 10 = map 2 - 3rd 8KB of plane 2 bank 2 + | | | | 11 = map 3 - 4th 8KB of plane 2 bank 3 + | | | +---------- reserved/unused + | | +------------ reserved/unused + | +-------------- reserved/unused + +---------------- reserved/unused + + + SR04 - 7 6 5 4 3 2 1 0 - Memory Mode Register + | | | | | | | | + | | | | | | | +-- 0 = graphics mode, 1 = text mode + | | | | | | +---- 0 = no memory extension, 1 = memory extension + | | | | | +------ 0 = odd/even storage, 1 = sequential storage + | | | | +-------- reserved/unused + | | | +---------- reserved/unused + | | +------------ reserved/unused + | +-------------- reserved/unused + +---------------- reserved/unused + + +Graphics Controller Registers GR00 - GR08 + +The Graphics Controller Registers are accessed through an index register +located at I/O port 0x3CE, and a data register located at I/O port 0x3CF. + + GR00 - 7 6 5 4 3 2 1 0 - Set/Reset Register + | | | | | | | | + | | | | | | | +-- set/reset for plane 0 + | | | | | | +---- set/reset for plane 1 + | | | | | +------ set/reset for plane 2 + | | | | +-------- set/reset for plane 3 + | | | +---------- reserved/unused + | | +------------ reserved/unused + | +-------------- reserved/unused + +---------------- reserved/unused + + + GR01 - 7 6 5 4 3 2 1 0 - Enable Set/Reset Register + | | | | | | | | + | | | | | | | +-- enable set/reset for plane 0 + | | | | | | +---- enable set/reset for plane 1 + | | | | | +------ enable set/reset for plane 2 + | | | | +-------- enable set/reset for plane 3 + | | | +---------- reserved/unused + | | +------------ reserved/unused + | +-------------- reserved/unused + +---------------- reserved/unused + + + GR02 - 7 6 5 4 3 2 1 0 - Color Compare Register + | | | | | | | | + | | | | | | | +-- color compare 0 + | | | | | | +---- color compare 1 + | | | | | +------ color compare 2 + | | | | +-------- color compare 3 + | | | +---------- reserved/unused + | | +------------ reserved/unused + | +-------------- reserved/unused + +---------------- reserved/unused + + + GR03 - 7 6 5 4 3 2 1 0 - Data Rotate Register + | | | | | | | | + | | | | | | | +-- number of positions to rotate bit 0 + | | | | | | +---- number of positions to rotate bit 1 + | | | | | +------ number of positions to rotate bit 2 + | | | | +-------- function select bit 0 + | | | +---------- function select bit 1 + | | | 00 = data overwrites in specified color + | | | 01 = data ANDed with latched data + | | | 10 = data ORed with latched data + | | | 11 = data XORed with latched data + | | +------------ reserved/unused + | +-------------- reserved/unused + +---------------- reserved/unused + + + GR04 - 7 6 5 4 3 2 1 0 - Read Map Select Register + | | | | | | | | + | | | | | | | +-- plane select bit 0 + | | | | | | +---- plane select bit 1 + | | | | | +------ reserved/unused + | | | | +-------- reserved/unused + | | | +---------- reserved/unused + | | +------------ reserved/unused + | +-------------- reserved/unused + +---------------- reserved/unused + + + GR05 - 7 6 5 4 3 2 1 0 - Mode Register + | | | | | | | | + | | | | | | | +-- write mode bit 0 + | | | | | | +---- write mode bit 1 + | | | | | | 00 = write 8 bits of value in set/reset register if enabled, + | | | | | | otherwise write rotated processor data + | | | | | | 01 = write with contents of processor latches + | | | | | | 10 = memory plane 0-3 filled with 8 bits of value of data bit 0-3 + | | | | | | 11 = reserved/unused + | | | | | +------ test condition + | | | | | 0 = normal operation + | | | | | 1 = put outputs in high impedance state + | | | | +-------- read mode + | | | | 0 = read from plane selected by GR04 + | | | | 1 = do color compare + | | | +---------- odd/even addressing mode + | | +------------ shift register mode + | | 0 = sequential + | | 1 = even bits from even maps, odd bits from odd maps + | +-------------- reserved/unused + +---------------- reserved/unused + + + GR06 - 7 6 5 4 3 2 1 0 - Miscellaneous Register + | | | | | | | | + | | | | | | | +-- 0 = text mode, 1 = graphics mode + | | | | | | +---- chain odd maps to even + | | | | | +------ memory map bit 0 + | | | | +-------- memory map bit 1 + | | | | 00 = 0xA0000, 128KB + | | | | 01 = 0xA0000, 64KB + | | | | 10 = 0xB0000, 32KB + | | | | 11 = 0xB8000, 32KB + | | | +---------- reserved/unused + | | +------------ reserved/unused + | +-------------- reserved/unused + +---------------- reserved/unused + + + GR07 - 7 6 5 4 3 2 1 0 - Color Plane Ignore Register + | | | | | | | | + | | | | | | | +-- ignore color plane 0 + | | | | | | +---- ignore color plane 1 + | | | | | +------ ignore color plane 2 + | | | | +-------- ignore color plane 3 + | | | +---------- reserved/unused + | | +------------ reserved/unused + | +-------------- reserved/unused + +---------------- reserved/unused + + + GR08 - 7 6 5 4 3 2 1 0 - Bit Mask Register + | | | | | | | | + | | | | | | | +-- write enable bit 0 + | | | | | | +---- write enable bit 1 + | | | | | +------ write enable bit 2 + | | | | +-------- write enable bit 3 + | | | +---------- write enable bit 4 + | | +------------ write enable bit 5 + | +-------------- write enable bit 6 + +---------------- write enable bit 7 + + +***************************************************************************/ + +#include "emu.h" +#include "ega.h" + +#define VERBOSE_EGA 1 + +#define EGA_SCREEN_NAME "ega_screen" +#define EGA_CRTC_NAME "crtc_ega_ega" + + +#define EGA_MODE_GRAPHICS 1 +#define EGA_MODE_TEXT 2 + + +/* + Prototypes +*/ + +MACHINE_CONFIG_FRAGMENT( pcvideo_ega ) + MCFG_SCREEN_ADD(EGA_SCREEN_NAME, RASTER) + MCFG_SCREEN_RAW_PARAMS(16257000,912,0,640,262,0,200) + MCFG_SCREEN_UPDATE_DEVICE(EGA_CRTC_NAME, crtc_ega_device, screen_update) + MCFG_SCREEN_PALETTE("palette") + + MCFG_PALETTE_ADD( "palette", 64 ) + + MCFG_DEVICE_ADD(EGA_CRTC_NAME, CRTC_EGA, 16257000/8) + MCFG_CRTC_EGA_SET_SCREEN(EGA_SCREEN_NAME) + MCFG_CRTC_EGA_HPIXELS_PER_COLUMN(8) + MCFG_CRTC_EGA_ROW_UPDATE_CB(isa8_ega_device, ega_update_row) + MCFG_CRTC_EGA_RES_OUT_DE_CB(WRITELINE(isa8_ega_device, de_changed)) + MCFG_CRTC_EGA_RES_OUT_HSYNC_CB(WRITELINE(isa8_ega_device, hsync_changed)) + MCFG_CRTC_EGA_RES_OUT_VSYNC_CB(WRITELINE(isa8_ega_device, vsync_changed)) + MCFG_CRTC_EGA_RES_OUT_VBLANK_CB(WRITELINE(isa8_ega_device, vblank_changed)) +MACHINE_CONFIG_END + +ROM_START( ega ) + ROM_REGION(0x4000, "user1", 0) + ROM_DEFAULT_BIOS("ega") + ROM_SYSTEM_BIOS(0, "ega", "IBM EGA BIOS") + ROMX_LOAD("6277356.u44", 0x0000, 0x4000, CRC(dc146448) SHA1(dc0794499b3e499c5777b3aa39554bbf0f2cc19b), ROM_BIOS(1)) + ROM_SYSTEM_BIOS(1, "iskr3104", "Iskra-3104 EGA BIOS") + ROMX_LOAD( "143-03.bin", 0x0001, 0x2000, CRC(d0706345) SHA1(e04bb40d944426a4ae2e3a614d3f4953d7132ede),ROM_SKIP(1)|ROM_BIOS(2)) + ROMX_LOAD( "143-02.bin", 0x0000, 0x2000, CRC(c8c18ebb) SHA1(fd6dac76d43ab8b582e70f1d5cc931d679036fb9),ROM_SKIP(1)|ROM_BIOS(2)) + ROM_REGION(0x4000, "user2", ROMREGION_ERASE00) +ROM_END + +/* +0000 - MONOC PRIMARY, EGA COLOR, 40x25 +0001 - MONOC PRIMARY, EGA COLOR, 80x25 +0010 - MONOC PRIMARY, EGA HI RES EMULATE (SAME AS 0001) +0011 - MONOC PRIMARY, EGA HI RES ENHANCED +0100 - COLOR 40 PRIMARY, EGA MONOCHROME +0101 - COLOR 80 PRIMARY, EGA MONOCHROME + +0110 - MONOC SECONDARY, EGA COLOR, 40x24 +0111 - MONOC SECONDARY, EGA COLOR, 80x25 +1000 - MONOC SECONDARY, EGA HI RES EMULATE (SAME AS 0111) +1001 - MONOC SECONDARY, EGA HI RES ENHANCED +1010 - COLOR 40 SECONDARY, EGA +1011 - COLOR 80 SECONDARY, EGA + +1100 - RESERVED +1101 - RESERVED +1110 - RESERVED +1111 - RESERVED +*/ + +INPUT_PORTS_START( ega ) + PORT_START( "config" ) + PORT_CONFNAME( 0x0f, 0x09, "dipswitches" ) + PORT_CONFSETTING( 0x00, "0000 - MDA PRIMARY, EGA COLOR, 40x25" ) /* DIAG: ?? 40 cols, RGBI */ + PORT_CONFSETTING( 0x08, "0001 - MDA PRIMARY, EGA COLOR, 80x25" ) /* DIAG: ?? 80 cols, RGBI */ + PORT_CONFSETTING( 0x04, "0010 - MDA PRIMARY, EGA HI RES EMULATE (SAME AS 0001)" ) /* DIAG: ?? 80 cols, RGBI */ + PORT_CONFSETTING( 0x0c, "0011 - MDA PRIMARY, EGA HI RES ENHANCED" ) /* DIAG: Color Display 40 cols, RrGgBb */ + PORT_CONFSETTING( 0x02, "0100 - CGA 40 PRIMARY, EGA MONOCHROME" ) /* DIAG: ??, Mono RGBI */ + PORT_CONFSETTING( 0x0a, "0101 - CGA 80 PRIMARY, EGA MONOCHROME" ) /* DIAG: ??, Mono RGBI */ + PORT_CONFSETTING( 0x06, "0110 - MDA SECONDARY, EGA COLOR, 40x25" ) /* DIAG: Color Display 40 cols, RGBI */ + PORT_CONFSETTING( 0x0e, "0111 - MDA SECONDARY, EGA COLOR, 80x25" ) /* DIAG: Color Display 80 cols, RGBI */ + PORT_CONFSETTING( 0x01, "1000 - MDA SECONDARY, EGA HI RES EMULATE (SAME AS 0111)" ) /* DIAG: Color Display 80 cols, RGBI */ + PORT_CONFSETTING( 0x09, "1001 - MDA SECONDARY, EGA HI RES ENHANCED" ) /* DIAG: Color Display 40 cols, RrGgBb */ + PORT_CONFSETTING( 0x05, "1010 - COLOR 40 SECONDARY, EGA" ) /* DIAG: Monochrome display, Mono RGBI */ + PORT_CONFSETTING( 0x0d, "1011 - COLOR 80 SECONDARY, EGA" ) /* DIAG: Monochrome display, Mono RGBI */ + PORT_CONFSETTING( 0x03, "1100 - RESERVED" ) /* ??, RGBI */ + PORT_CONFSETTING( 0x0b, "1101 - RESERVED" ) /* ??, RGBI */ + PORT_CONFSETTING( 0x07, "1110 - RESERVED" ) /* ??, RGBI */ + PORT_CONFSETTING( 0x0f, "1111 - RESERVED" ) /* ??, RGBI */ +INPUT_PORTS_END + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type ISA8_EGA = &device_creator; + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor isa8_ega_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( pcvideo_ega ); +} + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *isa8_ega_device::device_rom_region() const +{ + return ROM_NAME( ega ); +} + +ioport_constructor isa8_ega_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( ega ); +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// isa8_ega_device - constructor +//------------------------------------------------- + +isa8_ega_device::isa8_ega_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, ISA8_EGA, "IBM Enhanced Graphics Adapter", tag, owner, clock, "ega", __FILE__), + device_isa8_card_interface(mconfig, *this), + m_misc_output(0), + m_palette(*this, "palette") +{ +} + +isa8_ega_device::isa8_ega_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_isa8_card_interface(mconfig, *this), + m_misc_output(0), + m_palette(*this, "palette") +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void isa8_ega_device::device_start() +{ + if (m_palette != NULL && !m_palette->started()) + throw device_missing_dependencies(); + + set_isa_device(); + + for (int i = 0; i < 64; i++ ) + { + UINT8 r = ( ( i & 0x04 ) ? 0xAA : 0x00 ) + ( ( i & 0x20 ) ? 0x55 : 0x00 ); + UINT8 g = ( ( i & 0x02 ) ? 0xAA : 0x00 ) + ( ( i & 0x10 ) ? 0x55 : 0x00 ); + UINT8 b = ( ( i & 0x01 ) ? 0xAA : 0x00 ) + ( ( i & 0x08 ) ? 0x55 : 0x00 ); + + m_palette->set_pen_color( i, r, g, b ); + } + + if(m_default_bios_tag != "iskr3104") + { + UINT8 *dst = memregion(subtag("user2").c_str())->base() + 0x0000; + UINT8 *src = memregion(subtag("user1").c_str())->base() + 0x3fff; + int i; + + /* Perform the EGA bios address line swaps */ + for( i = 0; i < 0x4000; i++ ) + { + *dst++ = *src--; + } + } + else + memcpy(memregion(subtag("user2").c_str())->base(), memregion(subtag("user1").c_str())->base(), 0x4000); + + /* Install 256KB Video ram on our EGA card */ + m_vram = machine().memory().region_alloc(subtag("vram").c_str(), 256 * 1024, 1, ENDIANNESS_LITTLE); + + m_videoram = m_vram->base(); + m_plane[0] = m_videoram + 0x00000; + memset(m_plane[0], 0, sizeof(UINT8) * 0x10000); + m_plane[1] = m_videoram + 0x10000; + memset(m_plane[1], 0, sizeof(UINT8) * 0x10000); + m_plane[2] = m_videoram + 0x20000; + memset(m_plane[2], 0, sizeof(UINT8) * 0x10000); + m_plane[3] = m_videoram + 0x30000; + memset(m_plane[3], 0, sizeof(UINT8) * 0x10000); + + m_crtc_ega = subdevice(EGA_CRTC_NAME); + + m_isa->install_rom(this, 0xc0000, 0xc3fff, 0, 0, "ega", "user2"); + m_isa->install_device(0x3b0, 0x3bf, 0, 0, read8_delegate(FUNC(isa8_ega_device::pc_ega8_3b0_r), this), write8_delegate(FUNC(isa8_ega_device::pc_ega8_3b0_w), this)); + m_isa->install_device(0x3c0, 0x3cf, 0, 0, read8_delegate(FUNC(isa8_ega_device::pc_ega8_3c0_r), this), write8_delegate(FUNC(isa8_ega_device::pc_ega8_3c0_w), this)); + m_isa->install_device(0x3d0, 0x3df, 0, 0, read8_delegate(FUNC(isa8_ega_device::pc_ega8_3d0_r), this), write8_delegate(FUNC(isa8_ega_device::pc_ega8_3d0_w), this)); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void isa8_ega_device::device_reset() +{ + m_feature_control = 0; + + memset(&m_attribute,0,sizeof(m_attribute)); + memset(&m_sequencer,0,sizeof(m_sequencer)); + memset(&m_graphics_controller,0,sizeof(m_graphics_controller)); + + m_frame_cnt = 0; + m_hsync = 0; + m_vsync = 0; + m_vblank = 0; + m_display_enable = 0; + + install_banks(); + + m_misc_output = 0; + m_attribute.index_write = 1; + + /* Set up default palette */ + m_attribute.data[0] = 0; + m_attribute.data[1] = 1; + m_attribute.data[2] = 2; + m_attribute.data[3] = 3; + m_attribute.data[4] = 4; + m_attribute.data[5] = 5; + m_attribute.data[6] = 0x14; + m_attribute.data[7] = 7; + m_attribute.data[8] = 0x38; + m_attribute.data[9] = 0x39; + m_attribute.data[10] = 0x3A; + m_attribute.data[11] = 0x3B; + m_attribute.data[12] = 0x3C; + m_attribute.data[13] = 0x3D; + m_attribute.data[14] = 0x3E; + m_attribute.data[15] = 0x3F; + + m_video_mode = 0; +} + +void isa8_ega_device::install_banks() +{ + switch ( m_graphics_controller.data[6] & 0x0c ) + { + case 0x00: /* 0xA0000, 128KB */ + if ( m_misc_output & 0x02 ) + { + m_isa->install_memory(0xa0000, 0xbffff, 0, 0, read8_delegate(FUNC(isa8_ega_device::read), this), write8_delegate(FUNC(isa8_ega_device::write), this)); + } + else + { + m_isa->unmap_bank(0xa0000, 0xaffff,0,0); + m_isa->unmap_bank(0xb0000, 0xb7fff,0,0); + m_isa->unmap_bank(0xb8000, 0xbffff,0,0); + } + break; + case 0x04: /* 0xA0000, 64KB */ + if ( m_misc_output & 0x02 ) + { + m_isa->install_memory(0xa0000, 0xaffff, 0, 0, read8_delegate(FUNC(isa8_ega_device::read), this), write8_delegate(FUNC(isa8_ega_device::write), this)); + } + else + { + m_isa->unmap_bank(0xa0000, 0xaffff,0,0); + } + /* These unmaps may break multi graphics card support */ + m_isa->unmap_bank(0xb0000, 0xb7fff,0,0); + m_isa->unmap_bank(0xb8000, 0xbffff,0,0); + break; + case 0x08: /* 0xB0000, 32KB */ + if ( m_misc_output & 0x02 ) + { + m_isa->install_memory(0xb0000, 0xb7fff, 0, 0, read8_delegate(FUNC(isa8_ega_device::read), this), write8_delegate(FUNC(isa8_ega_device::write), this)); + } + else + { + m_isa->unmap_bank(0xb0000, 0xb7fff,0,0); + } + /* These unmaps may break multi graphics card support */ + m_isa->unmap_bank(0xa0000, 0xaffff,0,0); + m_isa->unmap_bank(0xb8000, 0xbffff,0,0); + break; + case 0x0c: /* 0xB8000, 32KB */ + if ( m_misc_output & 0x02 ) + { + m_isa->install_memory(0xb8000, 0xbffff, 0, 0, read8_delegate(FUNC(isa8_ega_device::read), this), write8_delegate(FUNC(isa8_ega_device::write), this)); + } + else + { + m_isa->unmap_bank(0xb8000, 0xbffff,0,0); + } + /* These unmaps may break multi graphics card support */ + m_isa->unmap_bank(0xa0000, 0xaffff,0,0); + m_isa->unmap_bank(0xb0000, 0xb7fff,0,0); + break; + } +} + +CRTC_EGA_ROW_UPDATE( isa8_ega_device::ega_update_row ) +{ + if (m_video_mode == EGA_MODE_GRAPHICS) + pc_ega_graphics(bitmap, cliprect, ma, ra, y, x_count, cursor_x); + else if (m_video_mode == EGA_MODE_TEXT) + pc_ega_text(bitmap, cliprect, ma, ra, y, x_count, cursor_x); +} + + +WRITE_LINE_MEMBER( isa8_ega_device::de_changed ) +{ + m_display_enable = state ? 1 : 0; +} + + +WRITE_LINE_MEMBER( isa8_ega_device::hsync_changed ) +{ + m_hsync = state ? 1 : 0; +} + + +WRITE_LINE_MEMBER( isa8_ega_device::vsync_changed ) +{ + m_vsync = state ? 1 : 0; + if ( state ) + { + m_frame_cnt++; + } +} + + +WRITE_LINE_MEMBER( isa8_ega_device::vblank_changed ) +{ + m_vblank = state ? 8 : 0; +} + + +CRTC_EGA_ROW_UPDATE( isa8_ega_device::pc_ega_graphics ) +{ + UINT16 *p = &bitmap.pix16(y); + +// logerror( "pc_ega_graphics: y = %d, x_count = %d, ma = %d, ra = %d\n", y, x_count, ma, ra ); + + if ( m_graphics_controller.data[5] & 0x10 ) + { + // Odd/Even mode (CGA compatible) + + for ( int i = 0; i < x_count; i++ ) + { + UINT16 offset = ( ( ma + i ) & 0x1fff ) | ( ( y & 1 ) << 12 ); + UINT8 data = m_plane[0][offset]; + + *p = m_attribute.data[ ( data >> 6 ) ]; p++; + *p = m_attribute.data[ ( data >> 4 ) & 0x03 ]; p++; + *p = m_attribute.data[ ( data >> 2 ) & 0x03 ]; p++; + *p = m_attribute.data[ data & 0x03 ]; p++; + + data = m_plane[1][offset]; + + *p = m_attribute.data[ ( data >> 6 ) ]; p++; + *p = m_attribute.data[ ( data >> 4 ) & 0x03 ]; p++; + *p = m_attribute.data[ ( data >> 2 ) & 0x03 ]; p++; + *p = m_attribute.data[ data & 0x03 ]; p++; + } + } + else + { + // EGA mode + + UINT8 mask = m_attribute.data[0x12] & 0x0f; + + for ( int i = 0; i < x_count; i++ ) + { + UINT16 offset = ma + i; + UINT16 data0 = m_plane[0][offset]; + UINT16 data1 = m_plane[1][offset] << 1; + UINT16 data2 = m_plane[2][offset] << 2; + UINT16 data3 = m_plane[3][offset] << 3; + + for ( int j = 7; j >= 0; j-- ) + { + UINT16 col = ( data0 & 0x01 ) | ( data1 & 0x02 ) | ( data2 & 0x04 ) | ( data3 & 0x08 ); + + col &= mask; + + p[j] = m_attribute.data[col]; + + data0 >>= 1; + data1 >>= 1; + data2 >>= 1; + data3 >>= 1; + } + p += 8; + } + } +} + + +CRTC_EGA_ROW_UPDATE( isa8_ega_device::pc_ega_text ) +{ + UINT16 *p = &bitmap.pix16(y); + int i; + +// logerror( "pc_ega_text: y = %d, x_count = %d, ma = %d, ra = %d\n", y, x_count, ma, ra ); + + for ( i = 0; i < x_count; i++ ) + { + UINT16 offset = ma + i; + UINT8 chr = m_plane[0][ offset ]; + UINT8 attr = m_plane[1][ offset ]; + UINT8 data = 0; + UINT16 fg = m_attribute.data[ attr & 0x07 ]; + UINT16 bg = m_attribute.data[ ( attr >> 4 ) & 0x07 ]; + + /* If character set A and B are equal attribute bit 3 is used as intensity */ + if ( m_charA == m_charB ) + { + /* intensity selector */ + data = m_charB[ chr * 32 + ra ]; + fg += ( attr & 0x08 ) ? 0x38 : 0x00; + } + else + { + /* character set selector */ + data = ( attr & 0x08 ) ? m_charA[ chr * 32 + ra ] : m_charB[ chr * 32 + ra ]; + } + + if ( i == cursor_x ) + { + if ( m_frame_cnt & 0x08 ) + { + data = 0xFF; + } + } + else + { + /* Check for blinking */ + if ( ( m_attribute.data[0x10] & 0x08 ) && ( attr & 0x80 ) && ( m_frame_cnt & 0x10 ) ) + { + data = 0x00; + } + } + + *p = ( data & 0x80 ) ? fg : bg; p++; + *p = ( data & 0x40 ) ? fg : bg; p++; + *p = ( data & 0x20 ) ? fg : bg; p++; + *p = ( data & 0x10 ) ? fg : bg; p++; + *p = ( data & 0x08 ) ? fg : bg; p++; + *p = ( data & 0x04 ) ? fg : bg; p++; + *p = ( data & 0x02 ) ? fg : bg; p++; + *p = ( data & 0x01 ) ? fg : bg; p++; + } +} + + +void isa8_ega_device::change_mode() +{ + int clock, pixels; + + m_video_mode = 0; + + /* Check for graphics mode */ + if ( ( m_attribute.data[0x10] & 0x01 ) && + ! ( m_sequencer.data[0x04] & 0x01 ) && + ( m_graphics_controller.data[0x06] & 0x01 ) ) + { + if ( VERBOSE_EGA ) + { + logerror("change_mode(): Switch to graphics mode\n"); + } + + m_video_mode = EGA_MODE_GRAPHICS; + } + + /* Check for text mode */ + if ( ! ( m_attribute.data[0x10] & 0x01 ) && + ( m_sequencer.data[0x04] & 0x01 ) && + ! ( m_graphics_controller.data[0x06] & 0x01 ) ) + { + if ( VERBOSE_EGA ) + { + logerror("chnage_mode(): Switching to text mode\n"); + } + + m_video_mode = EGA_MODE_TEXT; + + /* Set character maps */ + if ( m_sequencer.data[0x04] & 0x02 ) + { + m_charA = m_plane[2] + ( ( m_sequencer.data[0x03] & 0x0c ) >> 1 ) * 0x2000; + m_charB = m_plane[2] + ( m_sequencer.data[0x03] & 0x03 ) * 0x2000; + } + else + { + m_charA = m_plane[2]; + m_charB = m_plane[2]; + } + } + + /* Check for changes to the crtc input clock and number of pixels per clock */ + clock = ( ( m_misc_output & 0x0c ) ? 16257000 : XTAL_14_31818MHz ); + pixels = ( ( m_sequencer.data[0x01] & 0x01 ) ? 8 : 9 ); + + if ( m_sequencer.data[0x01] & 0x08 ) + { + clock >>= 1; + } + m_crtc_ega->set_clock( clock / pixels ); + m_crtc_ega->set_hpixels_per_column( pixels ); + + if (!m_video_mode) + logerror("unknown video mode\n"); +} + + +READ8_MEMBER( isa8_ega_device::read ) +{ + UINT8 data = 0xFF; + + if ( !space.debugger_access() && ! ( m_sequencer.data[4] & 0x04 ) ) + { + /* Fill read latches */ + m_read_latch[0] = m_plane[0][offset & 0xffff]; + m_read_latch[1] = m_plane[1][offset & 0xffff]; + m_read_latch[2] = m_plane[2][offset & 0xffff]; + m_read_latch[3] = m_plane[3][offset & 0xffff]; + } + + if ( m_graphics_controller.data[5] & 0x08 ) + { + // Read mode #1 + popmessage("ega: Read mode 1 not supported yet!"); + printf("EGA: Read mode 1 not supported yet!\n"); + } + else + { + // Read mode #0 + if ( m_sequencer.data[4] & 0x04 ) + { + // Normal addressing mode + data = m_plane[ m_graphics_controller.data[4] & 0x03 ][offset & 0xffff]; + } + else + { + // Odd/Even addressing mode + data = m_plane[offset & 1][(offset & 0xffff) >> 1]; + } + } + + return data; +} + + +UINT8 isa8_ega_device::alu_op( UINT8 data, UINT8 latch_data ) +{ + UINT8 mask = m_graphics_controller.data[8]; + + switch( m_graphics_controller.data[3] & 0x18 ) + { + case 0x00: // Unmodified + return ( data & mask ) | ( latch_data & ~mask ); + + case 0x08: // AND + return ( data | ~mask ) & latch_data; + + case 0x10: // OR + return ( data & mask ) | latch_data; + + case 0x18: // XOR + return ( data & mask ) ^ latch_data; + } + return 0; +} + + +WRITE8_MEMBER( isa8_ega_device::write ) +{ + UINT8 d[4]; + UINT8 alu[4]; + UINT8 target_mask = m_graphics_controller.data[8]; + + alu[0] =alu[1] = alu[2] = alu[3] = 0; + + switch( m_graphics_controller.data[5] & 0x03 ) + { + case 0: // Write mode 0 + // Pass through barrel shifter + data = ( ( ( data << 8 ) | data ) >> ( m_graphics_controller.data[3] & 0x07 ) ) & 0xFF; + + d[0] = d[1] = d[2] = d[3] = data; + + /* Apply Set/Reset settings */ + if ( m_graphics_controller.data[1] & 0x01 ) + { + d[0] = ( m_graphics_controller.data[0] & 0x01 ) ? 0xff : 0x00; + } + if ( m_graphics_controller.data[1] & 0x02 ) + { + d[1] = ( m_graphics_controller.data[0] & 0x02 ) ? 0xff : 0x00; + } + if ( m_graphics_controller.data[1] & 0x04 ) + { + d[2] = ( m_graphics_controller.data[0] & 0x04 ) ? 0xff : 0x00; + } + if ( m_graphics_controller.data[1] & 0x08 ) + { + d[3] = ( m_graphics_controller.data[0] & 0x08 ) ? 0xff : 0x00; + } + + // Pass through ALUs + alu[0] = alu_op( d[0], m_read_latch[0] ); + alu[1] = alu_op( d[1], m_read_latch[1] ); + alu[2] = alu_op( d[2], m_read_latch[2] ); + alu[3] = alu_op( d[3], m_read_latch[3] ); + + break; + + case 1: // Write mode 1 + alu[0] = m_read_latch[0]; + alu[1] = m_read_latch[1]; + alu[2] = m_read_latch[2]; + alu[3] = m_read_latch[3]; + target_mask = 0xff; + return; + + case 2: // Write mode 2 + d[0] = ( data & 0x01 ) ? 0xff : 0x00; + d[1] = ( data & 0x02 ) ? 0xff : 0x00; + d[2] = ( data & 0x04 ) ? 0xff : 0x00; + d[3] = ( data & 0x08 ) ? 0xff : 0x00; + + alu[0] = alu_op( d[0], m_read_latch[0] ); + alu[1] = alu_op( d[1], m_read_latch[1] ); + alu[2] = alu_op( d[2], m_read_latch[2] ); + alu[3] = alu_op( d[3], m_read_latch[3] ); + break; + + case 3: // Write mode 3 + popmessage("EGA: Write mode 3 not supported!"); + return; + } + + offset &= 0xffff; + + // + // Plane selection + // TODO: Get this logic clearer. The documentation is unclear on the exact magic combination of bits. + // + if ( m_sequencer.data[4] & 0x04 ) + { + // Sequential addressing mode + if ( m_sequencer.data[2] & 0x01 ) + { + // Plane 0 + // Bit selection + m_plane[0][offset] = ( m_plane[0][offset] & ~ target_mask ) | ( alu[0] & target_mask ); + } + if ( m_sequencer.data[2] & 0x02 ) + { + // Plane 1 + // Bit selection + m_plane[1][offset] = ( m_plane[1][offset] & ~ target_mask ) | ( alu[1] & target_mask ); + } + if ( m_sequencer.data[2] & 0x04 ) + { + // Plane 2 + // Bit selection + m_plane[2][offset] = ( m_plane[2][offset] & ~ target_mask ) | ( alu[2] & target_mask ); + } + if ( m_sequencer.data[2] & 0x08 ) + { + // Plane 3 + // Bit selection + m_plane[3][offset] = ( m_plane[3][offset] & ~ target_mask ) | ( alu[3] & target_mask ); + } + } + else + { + // Odd/Even addressing mode + if ( offset & 1 ) + { + // Odd addresses go to planes 1 and 3 + + offset >>= 1; + + if ( m_sequencer.data[2] & 0x02 ) + { + // Plane 1 + // Bit selection + m_plane[1][offset] = ( m_plane[1][offset] & ~ target_mask ) | ( alu[1] & target_mask ); + } + if ( ( m_sequencer.data[2] & 0x08 ) && ! ( m_sequencer.data[4] & 0x01 ) ) + { + // Plane 3 + // Bit selection + m_plane[3][offset] = ( m_plane[3][offset] & ~ target_mask ) | ( alu[3] & target_mask ); + } + } + else + { + // Even addresses go to planes 0 and 2 + + offset >>= 1; + + if ( m_sequencer.data[2] & 0x01 ) + { + // Plane 0 + // Bit selection + m_plane[0][offset] = ( m_plane[0][offset] & ~ target_mask ) | ( alu[0] & target_mask ); + } + if ( ( m_sequencer.data[2] & 0x04 ) && ! ( m_sequencer.data[4] & 0x01 ) ) + { + // Plane 2 + // Bit selection + m_plane[2][offset] = ( m_plane[2][offset] & ~ target_mask ) | ( alu[2] & target_mask ); + } + } + } +} + + +READ8_MEMBER( isa8_ega_device::pc_ega8_3X0_r ) +{ + int data = 0xff; + + switch ( offset ) + { + /* CRT Controller - address register */ + case 0: case 2: case 4: case 6: + /* return last written mc6845 address value here? */ + break; + + /* CRT Controller - data register */ + case 1: case 3: case 5: case 7: + data = m_crtc_ega->register_r( space, offset ); + break; + + /* Input Status Register 1 */ + case 10: + data = m_vblank | ( m_hsync | m_vsync ); // m_display_enable; + + if ( m_display_enable ) + { + /* For the moment i'm putting in some bogus data */ + static int pixel_data; + + pixel_data = ( pixel_data + 1 ) & 0x03; + data |= ( pixel_data << 4 ); + } + + /* Reset the attirubte writing flip flop to let the next write go to the index reigster */ + m_attribute.index_write = 1; + break; + } + + return data; +} + +WRITE8_MEMBER( isa8_ega_device::pc_ega8_3X0_w ) +{ + if ( VERBOSE_EGA ) + { +// logerror("pc_ega_3X0_w: offset = %02x, data = %02x\n", offset, data ); + } + + switch ( offset ) + { + /* CRT Controller - address register */ + case 0: case 2: case 4: case 6: + m_crtc_ega->address_w( space, offset, data ); + break; + + /* CRT Controller - data register */ + case 1: case 3: case 5: case 7: + m_crtc_ega->register_w( space, offset, data ); + break; + + /* Set Light Pen Flip Flop */ + case 9: + break; + + /* Feature Control */ + case 10: + m_feature_control = data; + break; + + /* Clear Light Pen Flip Flop */ + case 11: + break; + } +} + + + +READ8_MEMBER(isa8_ega_device::pc_ega8_3b0_r ) +{ + return ( m_misc_output & 0x01 ) ? 0xFF : pc_ega8_3X0_r(space, offset); +} + + +READ8_MEMBER(isa8_ega_device::pc_ega8_3d0_r ) +{ + return ( m_misc_output & 0x01 ) ? pc_ega8_3X0_r(space, offset) : 0xFF; +} + + +WRITE8_MEMBER(isa8_ega_device::pc_ega8_3b0_w ) +{ + if ( ! ( m_misc_output & 0x01 ) ) + { + pc_ega8_3X0_w( space, offset, data ); + } +} + + +WRITE8_MEMBER(isa8_ega_device::pc_ega8_3d0_w ) +{ + if ( m_misc_output & 0x01 ) + { + pc_ega8_3X0_w( space, offset, data ); + } +} + + +READ8_MEMBER(isa8_ega_device::pc_ega8_3c0_r ) +{ + int data = 0xff; + + if ( VERBOSE_EGA ) + { +// logerror("pc_ega_3c0_r: offset = %02x\n", offset ); + } + + switch ( offset ) + { + /* Attributes Controller */ + case 0: + break; + + /* Feature Read */ + case 2: + { + UINT8 dips = ioport("config")->read(); + + data = ( data & 0x0f ); + data |= ( ( m_feature_control & 0x03 ) << 5 ); + data |= ( m_vsync ? 0x00 : 0x80 ); + data |= ( ( ( dips >> ( ( ( m_misc_output & 0x0c ) >> 2 ) ) ) & 0x01 ) << 4 ); + } + break; + + /* Sequencer */ + case 4: + break; + case 5: + break; + + /* Graphics Controller */ + case 14: + break; + case 15: + break; + } + return data; +} + + +WRITE8_MEMBER(isa8_ega_device::pc_ega8_3c0_w ) +{ + static const UINT8 ar_reg_mask[0x20] = + { + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x7F, 0x3F, 0x3F, 0x0F, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + static const UINT8 sr_reg_mask[0x08] = + { + 0x03, 0x0F, 0x0F, 0x0F, 0x07, 0x00, 0x00, 0x00 + }; + static const UINT8 gr_reg_mask[0x10] = + { + 0x0F, 0x0F, 0x0F, 0x1F, 0x07, 0x3F, 0x0F, 0x0F, + 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + int index = 0; + + if ( VERBOSE_EGA ) + { +// logerror("pc_ega_3c0_w: offset = %02x, data = %02x\n", offset, data ); + } + + switch ( offset ) + { + /* Attributes Controller */ + case 0: + if ( m_attribute.index_write ) + { + m_attribute.index = data; + } + else + { + index = m_attribute.index & 0x1F; + + logerror("AR%02X = 0x%02x\n", index, data ); + + /* Clear unused bits */ + m_attribute.data[ index ] = data & ar_reg_mask[ index ]; + + switch ( index ) + { + case 0x10: /* AR10 */ + change_mode(); + break; + } + } + m_attribute.index_write ^= 0x01; + break; + + /* Misccellaneous Output */ + case 2: + m_misc_output = data; + install_banks(); + change_mode(); + break; + + /* Sequencer */ + case 4: + m_sequencer.index = data; + break; + case 5: + index = m_sequencer.index & 0x07; + + logerror("SR%02X = 0x%02x\n", index & 0x07, data ); + + /* Clear unused bits */ + m_sequencer.data[ index ] = data & sr_reg_mask[ index ]; + + switch ( index ) + { + case 0x01: /* SR01 */ + case 0x03: /* SR03 */ + case 0x04: /* SR04 */ + change_mode(); + break; + } + break; + + /* Graphics Controller */ + case 14: + m_graphics_controller.index = data; + break; + case 15: + index = m_graphics_controller.index & 0x0F; + + logerror("GR%02X = 0x%02x\n", index, data ); + + /* Clear unused bits */ + m_graphics_controller.data[ index ] = data & gr_reg_mask[ index ]; + + switch ( index ) + { + case 0x06: /* GR06 */ + change_mode(); + install_banks(); + break; + } + break; + } +} diff --git a/src/devices/bus/isa/ega.h b/src/devices/bus/isa/ega.h new file mode 100644 index 00000000000..dc449e81ee7 --- /dev/null +++ b/src/devices/bus/isa/ega.h @@ -0,0 +1,111 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +#pragma once + +#ifndef __ISA_EGA_H__ +#define __ISA_EGA_H__ + +#include "emu.h" +#include "isa.h" +#include "video/crtc_ega.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> isa8_ega_device + +class isa8_ega_device : + public device_t, + public device_isa8_card_interface +{ +public: + // construction/destruction + isa8_ega_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + isa8_ega_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual const rom_entry *device_rom_region() const; + virtual ioport_constructor device_input_ports() const; + + DECLARE_READ8_MEMBER(read); + DECLARE_WRITE8_MEMBER(write); + DECLARE_READ8_MEMBER(pc_ega8_3b0_r); + DECLARE_WRITE8_MEMBER(pc_ega8_3b0_w); + DECLARE_READ8_MEMBER(pc_ega8_3c0_r); + DECLARE_WRITE8_MEMBER(pc_ega8_3c0_w); + DECLARE_READ8_MEMBER(pc_ega8_3d0_r); + DECLARE_WRITE8_MEMBER(pc_ega8_3d0_w); + DECLARE_WRITE_LINE_MEMBER(de_changed); + DECLARE_WRITE_LINE_MEMBER(hsync_changed); + DECLARE_WRITE_LINE_MEMBER(vsync_changed); + DECLARE_WRITE_LINE_MEMBER(vblank_changed); + + CRTC_EGA_ROW_UPDATE(ega_update_row); + CRTC_EGA_ROW_UPDATE(pc_ega_graphics); + CRTC_EGA_ROW_UPDATE(pc_ega_text); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + UINT8 alu_op( UINT8 data, UINT8 latch_data ); + +public: + crtc_ega_device *m_crtc_ega; + + void install_banks(); + void change_mode(); + DECLARE_WRITE8_MEMBER(pc_ega8_3X0_w); + DECLARE_READ8_MEMBER(pc_ega8_3X0_r); + + /* Video memory and related variables */ + memory_region *m_vram; + UINT8 *m_plane[4]; + UINT8 m_read_latch[4]; + UINT8 *m_videoram; + UINT8 *m_charA; + UINT8 *m_charB; + + /* Registers */ + UINT8 m_misc_output; + UINT8 m_feature_control; + + /* Attribute registers AR00 - AR14 + */ + struct { + UINT8 index; + UINT8 data[32]; + UINT8 index_write; + } m_attribute; + + /* Sequencer registers SR00 - SR04 + */ + struct { + UINT8 index; + UINT8 data[8]; + } m_sequencer; + + /* Graphics controller registers GR00 - GR08 + */ + struct { + UINT8 index; + UINT8 data[16]; + } m_graphics_controller; + + UINT8 m_frame_cnt; + UINT8 m_hsync; + UINT8 m_vsync; + UINT8 m_vblank; + UINT8 m_display_enable; + int m_video_mode; + required_device m_palette; +}; + + +// device type definition +extern const device_type ISA8_EGA; + +#endif /* __ISA_EGA_H__ */ diff --git a/src/devices/bus/isa/fdc.c b/src/devices/bus/isa/fdc.c new file mode 100644 index 00000000000..a7698784a26 --- /dev/null +++ b/src/devices/bus/isa/fdc.c @@ -0,0 +1,167 @@ +// license:BSD-3-Clause +// copyright-holders:Miodrag Milanovic +/********************************************************************** + + ISA 8 bit Floppy Disk Controller + +**********************************************************************/ + +#include "emu.h" +#include "fdc.h" +#include "machine/pc_fdc.h" +#include "imagedev/flopdrv.h" +#include "formats/pc_dsk.h" +#include "formats/naslite_dsk.h" + + +FLOPPY_FORMATS_MEMBER( isa8_fdc_device::floppy_formats ) + FLOPPY_PC_FORMAT, + FLOPPY_NASLITE_FORMAT +FLOPPY_FORMATS_END + +static SLOT_INTERFACE_START( pc_dd_floppies ) + SLOT_INTERFACE( "525dd", FLOPPY_525_DD ) + SLOT_INTERFACE( "35dd", FLOPPY_35_DD ) +SLOT_INTERFACE_END + +static SLOT_INTERFACE_START( pc_hd_floppies ) + SLOT_INTERFACE( "525hd", FLOPPY_525_HD ) + SLOT_INTERFACE( "35hd", FLOPPY_35_HD ) + SLOT_INTERFACE( "525dd", FLOPPY_525_DD ) + SLOT_INTERFACE( "35dd", FLOPPY_35_DD ) +SLOT_INTERFACE_END + +static MACHINE_CONFIG_FRAGMENT( cfg_xt ) + MCFG_PC_FDC_XT_ADD("fdc") + MCFG_PC_FDC_INTRQ_CALLBACK(WRITELINE(isa8_fdc_device, irq_w)) + MCFG_PC_FDC_DRQ_CALLBACK(WRITELINE(isa8_fdc_device, drq_w)) + MCFG_FLOPPY_DRIVE_ADD("fdc:0", pc_dd_floppies, "525dd", isa8_fdc_device::floppy_formats) + MCFG_FLOPPY_DRIVE_ADD("fdc:1", pc_dd_floppies, "525dd", isa8_fdc_device::floppy_formats) +MACHINE_CONFIG_END + +static MACHINE_CONFIG_FRAGMENT( cfg_at ) + MCFG_PC_FDC_AT_ADD("fdc") + MCFG_PC_FDC_INTRQ_CALLBACK(WRITELINE(isa8_fdc_device, irq_w)) + MCFG_PC_FDC_DRQ_CALLBACK(WRITELINE(isa8_fdc_device, drq_w)) + MCFG_FLOPPY_DRIVE_ADD("fdc:0", pc_hd_floppies, "35hd", isa8_fdc_device::floppy_formats) + MCFG_FLOPPY_DRIVE_ADD("fdc:1", pc_hd_floppies, "35hd", isa8_fdc_device::floppy_formats) +MACHINE_CONFIG_END + +static MACHINE_CONFIG_FRAGMENT( cfg_smc ) + MCFG_SMC37C78_ADD("fdc") + MCFG_UPD765_INTRQ_CALLBACK(WRITELINE(isa8_fdc_device, irq_w)) + MCFG_UPD765_DRQ_CALLBACK(WRITELINE(isa8_fdc_device, drq_w)) + MCFG_FLOPPY_DRIVE_ADD("fdc:0", pc_hd_floppies, "35hd", isa8_fdc_device::floppy_formats) + MCFG_FLOPPY_DRIVE_ADD("fdc:1", pc_hd_floppies, "35hd", isa8_fdc_device::floppy_formats) +MACHINE_CONFIG_END + +static MACHINE_CONFIG_FRAGMENT( cfg_ps2 ) + MCFG_N82077AA_ADD("fdc", n82077aa_device::MODE_PS2) + MCFG_UPD765_INTRQ_CALLBACK(WRITELINE(isa8_fdc_device, irq_w)) + MCFG_UPD765_DRQ_CALLBACK(WRITELINE(isa8_fdc_device, drq_w)) + MCFG_FLOPPY_DRIVE_ADD("fdc:0", pc_hd_floppies, "35hd", isa8_fdc_device::floppy_formats) + MCFG_FLOPPY_DRIVE_ADD("fdc:1", pc_hd_floppies, "35hd", isa8_fdc_device::floppy_formats) +MACHINE_CONFIG_END + +static MACHINE_CONFIG_FRAGMENT( cfg_superio ) + MCFG_PC_FDC_SUPERIO_ADD("fdc") + MCFG_UPD765_INTRQ_CALLBACK(WRITELINE(isa8_fdc_device, irq_w)) + MCFG_UPD765_DRQ_CALLBACK(WRITELINE(isa8_fdc_device, drq_w)) + MCFG_FLOPPY_DRIVE_ADD("fdc:0", pc_hd_floppies, "35hd", isa8_fdc_device::floppy_formats) + MCFG_FLOPPY_DRIVE_ADD("fdc:1", pc_hd_floppies, "35hd", isa8_fdc_device::floppy_formats) +MACHINE_CONFIG_END + + +isa8_fdc_device::isa8_fdc_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_isa8_card_interface(mconfig, *this), + fdc(*this, "fdc") +{ +} + +void isa8_fdc_device::device_start() +{ + set_isa_device(); + m_isa->install_device(0x03f0, 0x03f7, *fdc, &pc_fdc_interface::map); + m_isa->set_dma_channel(2, this, TRUE); +} + +void isa8_fdc_device::device_reset() +{ +} + +WRITE_LINE_MEMBER( isa8_fdc_device::irq_w ) +{ + m_isa->irq6_w(state ? ASSERT_LINE : CLEAR_LINE); +} + +WRITE_LINE_MEMBER( isa8_fdc_device::drq_w ) +{ + m_isa->drq2_w(state ? ASSERT_LINE : CLEAR_LINE); +} + +UINT8 isa8_fdc_device::dack_r(int line) +{ + return fdc->dma_r(); +} + +void isa8_fdc_device::dack_w(int line, UINT8 data) +{ + return fdc->dma_w(data); +} + +void isa8_fdc_device::eop_w(int state) +{ + fdc->tc_w(state == ASSERT_LINE); +} + +isa8_fdc_xt_device::isa8_fdc_xt_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : isa8_fdc_device(mconfig, ISA8_FDC_XT, "ISA 8bits XT FDC hookup", tag, owner, clock, "isa8_fdc_xt", __FILE__) +{ +} + +machine_config_constructor isa8_fdc_xt_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME(cfg_xt); +} + +isa8_fdc_at_device::isa8_fdc_at_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : isa8_fdc_device(mconfig, ISA8_FDC_AT, "ISA 8bits AT FDC hookup", tag, owner, clock, "isa8_fdc_at", __FILE__) +{ +} + +machine_config_constructor isa8_fdc_at_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME(cfg_at); +} + +isa8_fdc_smc_device::isa8_fdc_smc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : isa8_fdc_device(mconfig, ISA8_FDC_XT, "ISA 8bits SMC FDC hookup", tag, owner, clock, "isa8_fdc_smc", __FILE__) +{ +} + +machine_config_constructor isa8_fdc_smc_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME(cfg_smc); +} + +isa8_fdc_ps2_device::isa8_fdc_ps2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : isa8_fdc_device(mconfig, ISA8_FDC_PS2, "ISA 8bits PS/2 FDC hookup", tag, owner, clock, "isa8_fdc_ps2", __FILE__) +{ +} + +machine_config_constructor isa8_fdc_ps2_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME(cfg_ps2); +} + +isa8_fdc_superio_device::isa8_fdc_superio_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : isa8_fdc_device(mconfig, ISA8_FDC_SUPERIO, "ISA 8bits SUPERIO FDC hookup", tag, owner, clock, "isa8_fdc_superio", __FILE__) +{ +} + +machine_config_constructor isa8_fdc_superio_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME(cfg_superio); +} + +const device_type ISA8_FDC_XT = &device_creator; +const device_type ISA8_FDC_AT = &device_creator; +const device_type ISA8_FDC_SMC = &device_creator; +const device_type ISA8_FDC_PS2 = &device_creator; +const device_type ISA8_FDC_SUPERIO = &device_creator; diff --git a/src/devices/bus/isa/fdc.h b/src/devices/bus/isa/fdc.h new file mode 100644 index 00000000000..2c929259c9c --- /dev/null +++ b/src/devices/bus/isa/fdc.h @@ -0,0 +1,84 @@ +// license:BSD-3-Clause +// copyright-holders:Miodrag Milanovic +/********************************************************************** + + ISA 8 bit Floppy Disk Controller + +**********************************************************************/ +#pragma once + +#ifndef ISA_FDC_H +#define ISA_FDC_H + +#include "emu.h" +#include "isa.h" +#include "machine/upd765.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> isa8_fdc_device + +class isa8_fdc_device : + public device_t, + public device_isa8_card_interface +{ +public: + // construction/destruction + isa8_fdc_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + required_device fdc; + + DECLARE_WRITE_LINE_MEMBER( irq_w ); + DECLARE_WRITE_LINE_MEMBER( drq_w ); + DECLARE_FLOPPY_FORMATS( floppy_formats ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + virtual UINT8 dack_r(int line); + virtual void dack_w(int line, UINT8 data); + virtual void eop_w(int state); +}; + +class isa8_fdc_xt_device : public isa8_fdc_device { +public: + isa8_fdc_xt_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual machine_config_constructor device_mconfig_additions() const; +}; + +class isa8_fdc_at_device : public isa8_fdc_device { +public: + isa8_fdc_at_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual machine_config_constructor device_mconfig_additions() const; +}; + +class isa8_fdc_smc_device : public isa8_fdc_device { +public: + isa8_fdc_smc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual machine_config_constructor device_mconfig_additions() const; +}; + +class isa8_fdc_ps2_device : public isa8_fdc_device { +public: + isa8_fdc_ps2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual machine_config_constructor device_mconfig_additions() const; +}; + +class isa8_fdc_superio_device : public isa8_fdc_device { +public: + isa8_fdc_superio_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual machine_config_constructor device_mconfig_additions() const; +}; + +// device type definition +extern const device_type ISA8_FDC_XT; +extern const device_type ISA8_FDC_AT; +extern const device_type ISA8_FDC_SMC; +extern const device_type ISA8_FDC_PS2; +extern const device_type ISA8_FDC_SUPERIO; + +#endif /* ISA_FDC_H */ diff --git a/src/devices/bus/isa/finalchs.c b/src/devices/bus/isa/finalchs.c new file mode 100644 index 00000000000..212a05cad87 --- /dev/null +++ b/src/devices/bus/isa/finalchs.c @@ -0,0 +1,127 @@ +// license:BSD-3-Clause +// copyright-holders:Jonathan Gevaryahu +/*************************************************************************** + + Final Chess Card by TASC + + TODO: + - skeleton, just boots the CPU + +***************************************************************************/ + +#include "emu.h" +#include "finalchs.h" +#include "cpu/m6502/m65c02.h" + +WRITE8_MEMBER( isa8_finalchs_device::io7ff8_write ) +{ + m_FCH_latch_data = data; +} + +READ8_MEMBER( isa8_finalchs_device::io7ff8_read ) +{ + static unsigned char table[] = { 0xff, 0xfd, 0xfe }; + static int i = -1; + i++; + if (i == 3) i = 0; + return table[i]; // exercise the NMI handler for now with known commands +} + +READ8_MEMBER( isa8_finalchs_device::io6000_read ) +{ + return 0x55; +} + +WRITE8_MEMBER( isa8_finalchs_device::io6000_write ) +{ + m_FCH_latch_data = data; +} + +static ADDRESS_MAP_START(finalchs_mem , AS_PROGRAM, 8, isa8_finalchs_device) + AM_RANGE( 0x0000, 0x1fff ) AM_RAM + AM_RANGE( 0x7ff8, 0x7ff8 ) AM_READ(io7ff8_read) + AM_RANGE( 0x7ff8, 0x7ff8 ) AM_WRITE(io7ff8_write) + AM_RANGE( 0x6000, 0x6000 ) AM_READ(io6000_read) + AM_RANGE( 0x6000, 0x6000 ) AM_WRITE(io6000_write) + AM_RANGE( 0x8000, 0xffff ) AM_ROM +ADDRESS_MAP_END + +static MACHINE_CONFIG_FRAGMENT( finalchs_config ) + MCFG_CPU_ADD("maincpu",M65C02,5000000) + MCFG_CPU_PROGRAM_MAP(finalchs_mem) +MACHINE_CONFIG_END + +ROM_START(finalchs) + ROM_REGION(0x10000,"maincpu",0) + ROM_LOAD("finalchs.bin", 0x8000, 0x8000, CRC(c8e72dff) SHA1(f422b19a806cef4fadd580caefaaf8c32b644098)) +ROM_END + +READ8_MEMBER( isa8_finalchs_device::finalchs_r ) +{ + return 0; +} + +WRITE8_MEMBER( isa8_finalchs_device::finalchs_w ) +{ +} + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type ISA8_FINALCHS = &device_creator; + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor isa8_finalchs_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( finalchs_config ); +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// isa8_finalchs_device - constructor +//------------------------------------------------- + +isa8_finalchs_device::isa8_finalchs_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, ISA8_FINALCHS, "Final Chess Card", tag, owner, clock, "finalchs", __FILE__), + device_isa8_card_interface( mconfig, *this ) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void isa8_finalchs_device::device_start() +{ + set_isa_device(); + //the included setup program allows any port from 0x100 to 0x1F0 to be selected, at increments of 0x10 + //picked the following at random until we get dips hooked up + m_isa->install_device(0x160, 0x0161, 0, 0, read8_delegate(FUNC(isa8_finalchs_device::finalchs_r), this), write8_delegate(FUNC(isa8_finalchs_device::finalchs_w), this)); +// timer_pulse(machine, ATTOTIME_IN_HZ(1), NULL, 0, cause_M6502_irq); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void isa8_finalchs_device::device_reset() +{ + m_FCH_latch_data = 0; +} + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *isa8_finalchs_device::device_rom_region() const +{ + return ROM_NAME( finalchs ); +} diff --git a/src/devices/bus/isa/finalchs.h b/src/devices/bus/isa/finalchs.h new file mode 100644 index 00000000000..ec1d05e1f43 --- /dev/null +++ b/src/devices/bus/isa/finalchs.h @@ -0,0 +1,50 @@ +// license:BSD-3-Clause +// copyright-holders:Jonathan Gevaryahu +#pragma once + +#ifndef __ISA_FINALCHS_H__ +#define __ISA_FINALCHS_H__ + +#include "emu.h" +#include "isa.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> isa8_finalchs_device + +class isa8_finalchs_device : + public device_t, + public device_isa8_card_interface +{ +public: + // construction/destruction + isa8_finalchs_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + DECLARE_READ8_MEMBER(finalchs_r); + DECLARE_WRITE8_MEMBER(finalchs_w); + + DECLARE_WRITE8_MEMBER( io7ff8_write ); + DECLARE_READ8_MEMBER( io7ff8_read ); + DECLARE_READ8_MEMBER( io6000_read ); + DECLARE_WRITE8_MEMBER( io6000_write ); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual const rom_entry *device_rom_region() const; +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + +private: + // internal state + UINT8 m_FCH_latch_data; +}; + + +// device type definition +extern const device_type ISA8_FINALCHS; + +#endif /* __ISA_FINALCHS_H__ */ diff --git a/src/devices/bus/isa/gblaster.c b/src/devices/bus/isa/gblaster.c new file mode 100644 index 00000000000..6ee9600cdb6 --- /dev/null +++ b/src/devices/bus/isa/gblaster.c @@ -0,0 +1,124 @@ +// license:BSD-3-Clause +// copyright-holders:Miodrag Milanovic +/*************************************************************************** + + ISA 8 bit Creative Labs Game Blaster Sound Card + +***************************************************************************/ + +#include "emu.h" +#include "gblaster.h" +#include "sound/speaker.h" + +/* + creative labs game blaster (CMS creative music system) + 2 x saa1099 chips + also on sound blaster 1.0 + option on sound blaster 1.5 + + jumperable? normally 0x220 +*/ +static MACHINE_CONFIG_FRAGMENT( game_blaster_config ) + MCFG_SPEAKER_STANDARD_MONO("mono") + MCFG_SAA1099_ADD("saa1099.1", 7159000) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.50) + MCFG_SAA1099_ADD("saa1099.2", 7159000) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.50) +MACHINE_CONFIG_END + +READ8_MEMBER( isa8_gblaster_device::saa1099_16_r ) +{ + return 0xff; +} + +WRITE8_MEMBER( isa8_gblaster_device::saa1099_1_16_w ) +{ + switch(offset) + { + case 0 : m_saa1099_1->data_w( space, offset, data ); break; + case 1 : m_saa1099_1->control_w( space, offset, data ); break; + } +} + +WRITE8_MEMBER( isa8_gblaster_device::saa1099_2_16_w ) +{ + switch(offset) + { + case 0 : m_saa1099_2->data_w( space, offset, data ); break; + case 1 : m_saa1099_2->control_w( space, offset, data ); break; + } +} + +READ8_MEMBER( isa8_gblaster_device::detect_r ) +{ + switch(offset) + { + case 0: + case 1: return 0x7f; break; // this register reportedly returns 0x3f on a Tandy 1000 TL, and 0x7f on a generic 486 PC. + case 6: + case 7: return detect_reg; break; + default: return 0xff; + } +} + +WRITE8_MEMBER( isa8_gblaster_device::detect_w ) +{ + switch(offset) + { + case 2: + case 3: detect_reg = (data & 0xff); break; + } +} + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type ISA8_GAME_BLASTER = &device_creator; + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor isa8_gblaster_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( game_blaster_config ); +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// isa8_gblaster_device - constructor +//------------------------------------------------- + +isa8_gblaster_device::isa8_gblaster_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, ISA8_GAME_BLASTER, "Game Blaster Sound Card", tag, owner, clock, "isa_gblaster", __FILE__), + device_isa8_card_interface(mconfig, *this), + m_saa1099_1(*this, "saa1099.1"), + m_saa1099_2(*this, "saa1099.2"), + detect_reg(0xFF) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void isa8_gblaster_device::device_start() +{ + set_isa_device(); + m_isa->install_device(0x0220, 0x0221, 0, 0, read8_delegate( FUNC(isa8_gblaster_device::saa1099_16_r), this ), write8_delegate( FUNC(isa8_gblaster_device::saa1099_1_16_w), this ) ); + m_isa->install_device(0x0222, 0x0223, 0, 0, read8_delegate( FUNC(isa8_gblaster_device::saa1099_16_r), this ), write8_delegate( FUNC(isa8_gblaster_device::saa1099_2_16_w), this ) ); + m_isa->install_device(0x0224, 0x022F, 0, 0, read8_delegate( FUNC(isa8_gblaster_device::detect_r), this ), write8_delegate( FUNC(isa8_gblaster_device::detect_w), this ) ); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void isa8_gblaster_device::device_reset() +{ +} diff --git a/src/devices/bus/isa/gblaster.h b/src/devices/bus/isa/gblaster.h new file mode 100644 index 00000000000..b2625e98975 --- /dev/null +++ b/src/devices/bus/isa/gblaster.h @@ -0,0 +1,49 @@ +// license:BSD-3-Clause +// copyright-holders:Miodrag Milanovic +#pragma once + +#ifndef __ISA_GAME_BLASTER_H__ +#define __ISA_GAME_BLASTER_H__ + +#include "emu.h" +#include "isa.h" +#include "sound/saa1099.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> isa8_gblaster_device + +class isa8_gblaster_device : + public device_t, + public device_isa8_card_interface +{ +public: + // construction/destruction + isa8_gblaster_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + + DECLARE_READ8_MEMBER(saa1099_16_r); + DECLARE_WRITE8_MEMBER(saa1099_1_16_w); + DECLARE_WRITE8_MEMBER(saa1099_2_16_w); + DECLARE_READ8_MEMBER(detect_r); + DECLARE_WRITE8_MEMBER(detect_w); +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); +private: + // internal state + required_device m_saa1099_1; + required_device m_saa1099_2; + UINT8 detect_reg; +}; + + +// device type definition +extern const device_type ISA8_GAME_BLASTER; + +#endif /* __ISA_GAME_BLASTER_H__ */ diff --git a/src/devices/bus/isa/gus.c b/src/devices/bus/isa/gus.c new file mode 100644 index 00000000000..ad7d034a183 --- /dev/null +++ b/src/devices/bus/isa/gus.c @@ -0,0 +1,1724 @@ +// license:BSD-3-Clause +// copyright-holders:Barry Rodewald +/* + * Gravis Ultrasound ISA card + * + * Started: 28/01/2012 + */ + + +#include "gus.h" +#include "bus/midi/midi.h" +#include "machine/clock.h" + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +// uncomment this to save wave RAM content to a file +//#define SAVE_WAVE_RAM 1 +//#define LOG_SOUND 1 + +static const UINT16 rate_table[33] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 44100, 41160, 38587, 36317, 34300, 32494, 30870, 29400, + 28063, 26843, 25725, 24696, 23746, 22866, 22050, 21289, + 20580, 19916, 19293 +}; + +static const UINT16 volume_ramp_table[4] = +{ + 1, 8, 64, 512 +}; + +const device_type GGF1 = &device_creator; +const device_type ISA16_GUS = &device_creator; + +#ifdef LOG_SOUND +FILE* f; +#endif + +void gf1_device::update_irq() +{ + int txirq = calculate_txirq(); + + if (m_txirq != txirq) + { + m_txirq = txirq; + m_txirq_handler(!m_txirq); + } + + int rxirq = calculate_rxirq(); + + if (m_rxirq != rxirq) + { + m_rxirq = rxirq; + m_rxirq_handler(!m_rxirq); + } +} + +/* only the Adlib timers are implemented in hardware */ +READ8_MEMBER( gf1_device::adlib_r ) +{ + UINT8 retVal = 0xff; + switch(offset) + { + case 0: +// if(m_timer_ctrl & 0x01) + return m_adlib_status; +// return m_fake_adlib_status; + case 1: + return m_adlib_data; + } + return retVal; +} + +WRITE8_MEMBER( gf1_device::adlib_w ) +{ + switch(offset) + { + case 0: + m_adlib_cmd = data; + break; + case 1: + if(m_adlib_cmd == 0x04 && !(m_timer_ctrl & 0x01)) + { + if(data & 0x80) + { + m_timer1_irq_handler(0); + m_timer2_irq_handler(0); + m_adlib_status &= ~0xe0; + logerror("GUS: Timer flags reset\n"); + } + else + { + if((data & 0x01) && !(data & 0x40)) + { + m_adlib_timer1_enable = 1; + m_timer1->adjust(attotime::zero,0,attotime::from_usec(80)); + } + if((data & 0x02) && !(data & 0x20)) + { + m_adlib_timer2_enable = 1; + m_timer2->adjust(attotime::zero,0,attotime::from_usec(320)); + } + if(!(data & 0x01) && !(data & 0x40)) + { + m_adlib_timer1_enable = 0; + m_timer1->reset(); + } + if(!(data & 0x02) && !(data & 0x20)) + { + m_adlib_timer2_enable = 0; + m_timer2->reset(); + } + logerror("GUS: Timer enable - %02x\n",data); + } + m_adlib_timer_cmd = data; + } + else + { + m_adlib_data = data; + if(m_timer_ctrl & 0x02) + { + m_adlib_status |= 0x01; + m_nmi_handler(1); + logerror("GUS: 2X9 Timer triggered!\n"); + } + } + break; + } +} + +void gf1_device::update_volume_ramps() +{ + int x; + + for(x=0;x<32;x++) + { + if(!(m_voice[x].vol_ramp_ctrl & 0x01)) // if ramping is enabled + { + m_voice[x].vol_count++; + if(m_voice[x].vol_count % volume_ramp_table[(m_voice[x].vol_ramp_rate & 0xc0)>>6] == 0) + { + // increase/decrease volume + if(m_voice[x].vol_ramp_ctrl & 0x40) + { + //m_voice[x].current_vol = (m_voice[x].current_vol & 0xf000) | ((m_voice[x].current_vol & 0x0ff0) + ((m_voice[x].vol_ramp_rate & 0x0f)<<8)); + m_voice[x].current_vol -= ((m_voice[x].vol_ramp_rate & 0x3f) << 4); + if(m_voice[x].current_vol <= (m_voice[x].vol_ramp_start << 8)) // end of ramp? + { + if(m_voice[x].vol_ramp_ctrl & 0x08) + { + if(m_voice[x].vol_ramp_ctrl & 0x10) + { + m_voice[x].vol_ramp_ctrl &= ~0x40; // change direction and continue + m_voice[x].current_vol = (m_voice[x].vol_ramp_start << 8); + } + else + m_voice[x].current_vol = (m_voice[x].vol_ramp_end << 8); + } + else + { + m_voice[x].vol_ramp_ctrl |= 0x01; // stop volume ramp + m_voice[x].current_vol = (m_voice[x].vol_ramp_start << 8); + } + if(m_voice[x].vol_ramp_ctrl & 0x20) + set_irq(IRQ_VOLUME_RAMP,x); + } + } + else + { + //m_voice[x].current_vol = (m_voice[x].current_vol & 0xf000) | ((m_voice[x].current_vol & 0x0ff0) - ((m_voice[x].vol_ramp_rate & 0x0f)<<8)); + m_voice[x].current_vol += ((m_voice[x].vol_ramp_rate & 0x3f) << 4); + if(m_voice[x].current_vol >= (m_voice[x].vol_ramp_end << 8)) // end of ramp? + { + if(m_voice[x].vol_ramp_ctrl & 0x08) + { + if(m_voice[x].vol_ramp_ctrl & 0x10) + { + m_voice[x].vol_ramp_ctrl |= 0x40; // change direction and continue + m_voice[x].current_vol = (m_voice[x].vol_ramp_end << 8); + } + else + m_voice[x].current_vol = (m_voice[x].vol_ramp_start << 8); + } + else + { + m_voice[x].vol_ramp_ctrl |= 0x01; // stop volume ramp + m_voice[x].current_vol = (m_voice[x].vol_ramp_end << 8); + } + if(m_voice[x].vol_ramp_ctrl & 0x20) + set_irq(IRQ_VOLUME_RAMP,x); + } + } + } + } + } +} + +void gf1_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch(id) + { + case ADLIB_TIMER1: + if(m_adlib_timer1_enable != 0) + { + if(m_timer1_count == 0xff) + { + m_adlib_status |= 0xc0; + m_timer1_count = m_timer1_value; + if(m_timer_ctrl & 0x04) + m_timer1_irq_handler(1); + } + m_timer1_count++; + } + break; + case ADLIB_TIMER2: + if(m_adlib_timer2_enable != 0) + { + if(m_timer2_count == 0xff) + { + m_adlib_status |= 0xa0; + m_timer2_count = m_timer2_value; + if(m_timer_ctrl & 0x08) + m_timer2_irq_handler(1); + } + m_timer2_count++; + } + break; + case DMA_TIMER: + m_drq1_handler(1); + break; + case VOL_RAMP_TIMER: + update_volume_ramps(); + break; + } +} + +void gf1_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + int x,y; + //UINT32 count; + + stream_sample_t* outputl = outputs[0]; + stream_sample_t* outputr = outputs[1]; + memset( outputl, 0x00, samples * sizeof(*outputl) ); + memset( outputr, 0x00, samples * sizeof(*outputr) ); + + for(x=0;x<32;x++) // for each voice + { + stream_sample_t* left = outputl; + stream_sample_t* right = outputr; + UINT16 vol = (m_volume_table[(m_voice[x].current_vol & 0xfff0) >> 4]); + for(y=samples-1; y>=0; y--) + { + UINT32 current = m_voice[x].current_addr >> 9; + // TODO: implement proper panning + (*left) += ((m_voice[x].sample) * (vol/8192.0)); + (*right) += ((m_voice[x].sample) * (vol/8192.0)); + left++; + right++; + if((!(m_voice[x].voice_ctrl & 0x40)) && (m_voice[x].current_addr >= m_voice[x].end_addr) && !m_voice[x].rollover && !(m_voice[x].voice_ctrl & 0x01)) + { + if(m_voice[x].vol_ramp_ctrl & 0x04) + { + m_voice[x].rollover = true; // set roll over condition - generate IRQ, but keep voice playing + } + + if(m_voice[x].voice_ctrl & 0x20) + set_irq(IRQ_WAVETABLE,x); + + // end voice, unless looping, or rollover is active, which disables looping + if(!m_voice[x].rollover) + { + if(!(m_voice[x].voice_ctrl & 0x08)) + { + m_voice[x].voice_ctrl |= 0x01; +// m_voice[x].current_addr = m_voice[x].end_addr; + } + } + // looping is not supposed to happen when rollover is active, but the Windows drivers have other ideas... + if(m_voice[x].voice_ctrl & 0x08) + { + if(m_voice[x].voice_ctrl & 0x10) + m_voice[x].voice_ctrl |= 0x40; // change direction + else + m_voice[x].current_addr = m_voice[x].start_addr; // start sample again + } + } + if((m_voice[x].voice_ctrl & 0x40) && (m_voice[x].current_addr <= m_voice[x].start_addr) && !m_voice[x].rollover && !(m_voice[x].voice_ctrl & 0x01)) + { + if(m_voice[x].vol_ramp_ctrl & 0x04) + { + m_voice[x].rollover = true; // set roll over condition - generate IRQ, but keep voice playing + } + + if(m_voice[x].voice_ctrl & 0x20) + set_irq(IRQ_WAVETABLE,x); + + // end voice, unless looping, or rollover is active, which disables looping + if(!m_voice[x].rollover) + { + // end voice, unless looping + if(!(m_voice[x].voice_ctrl & 0x08)) + { + m_voice[x].voice_ctrl |= 0x01; +// m_voice[x].current_addr = m_voice[x].start_addr; + } + } + // looping is not supposed to happen when rollover is active, but the Windows drivers have other ideas... + if(m_voice[x].voice_ctrl & 0x08) + { + if(m_voice[x].voice_ctrl & 0x10) + m_voice[x].voice_ctrl &= ~0x40; // change direction + else + m_voice[x].current_addr = m_voice[x].end_addr; // start sample again + } + } + if(!(m_voice[x].voice_ctrl & 0x01)) + { + if(m_voice[x].voice_ctrl & 0x04) + { // 16-bit PCM + current = ((m_voice[x].current_addr >> 9) & 0xc0000) + (((m_voice[x].current_addr >> 9) & 0x1ffff) << 1); + m_voice[x].sample = (INT16)((m_wave_ram[current & 0xffffe]) | ((m_wave_ram[(current & 0xffffe)+1])<<8)); + } + else + { // 8-bit PCM + m_voice[x].sample = (INT16)(m_wave_ram[current & 0xfffff] << 8); + } + if(m_voice[x].voice_ctrl & 0x40) // voice direction + m_voice[x].current_addr -= (m_voice[x].freq_ctrl >> 1); + else + m_voice[x].current_addr += (m_voice[x].freq_ctrl >> 1); + } +#ifdef LOG_SOUND + INT16 smp = (m_voice[x].sample) * (vol / 8192.0); + fwrite(&smp,4,1,f); +#endif + } + } +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// gf1_device - constructor +//------------------------------------------------- + +gf1_device::gf1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + acia6850_device(mconfig, GGF1, "Gravis GF1", tag, owner, clock, "gf1", __FILE__), + device_sound_interface( mconfig, *this ), + m_txirq_handler(*this), + m_rxirq_handler(*this), + m_wave_irq_handler(*this), + m_ramp_irq_handler(*this), + m_timer1_irq_handler(*this), + m_timer2_irq_handler(*this), + m_sb_irq_handler(*this), + m_dma_irq_handler(*this), + m_drq1_handler(*this), + m_drq2_handler(*this), + m_nmi_handler(*this) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void gf1_device::device_start() +{ + acia6850_device::device_start(); + + int i; + double out = (double)(1 << 13); + + m_txirq_handler.resolve_safe(); + m_rxirq_handler.resolve_safe(); + m_wave_irq_handler.resolve_safe(); + m_ramp_irq_handler.resolve_safe(); + m_timer1_irq_handler.resolve_safe(); + m_timer2_irq_handler.resolve_safe(); + m_sb_irq_handler.resolve_safe(); + m_dma_irq_handler.resolve_safe(); + m_drq1_handler.resolve_safe(); + m_drq2_handler.resolve_safe(); + m_nmi_handler.resolve_safe(); + + // TODO: make DRAM size configurable. Can be 256k, 512k, 768k, or 1024k + m_wave_ram.resize(1024*1024); + memset(&m_wave_ram[0], 0, 1024*1024); + + m_stream = stream_alloc(0,2,44100); + + // init timers + m_timer1 = timer_alloc(ADLIB_TIMER1); + m_timer2 = timer_alloc(ADLIB_TIMER2); + m_dmatimer = timer_alloc(DMA_TIMER); + m_voltimer = timer_alloc(VOL_RAMP_TIMER); + + save_item(NAME(m_wave_ram)); + + m_voice_irq_current = 0; + m_voice_irq_ptr = 0; + m_dma_channel1 = 0; + m_dma_channel2 = 0; + m_gf1_irq = 0; + m_midi_irq = 0; + + for (i=4095;i>=0;i--) + { + m_volume_table[i] = (INT16)out; + out /= 1.002709201; /* 0.0235 dB Steps */ + } + +#ifdef LOG_SOUND + f = fopen("soundlog.bin","wb"); +#endif +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void gf1_device::device_reset() +{ + int x; + + memset(m_voice, 0x00, sizeof(m_voice)); + // init voices + for(x=0;x<32;x++) + { + m_voice[x].voice_ctrl = 0x01; // stop all voices + m_voice[x].vol_ramp_ctrl = 0x01; // stop all volume ramps + m_voice[x].current_vol = 0; // silence all voices + } + m_irq_source = 0xe0; + m_reg_ctrl = 0; + m_active_voices = 14; + m_stream->set_sample_rate(44100); + m_voltimer->adjust(attotime::zero,0,attotime::from_usec(1000/(1.6*m_active_voices))); +} + +void gf1_device::device_stop() +{ +#ifdef SAVE_WAVE_RAM + FILE* f; + f=fopen("waveout.bin","wb"); + fwrite(m_wave_ram,1024*1024,1,f); + fclose(f); +#endif +#ifdef LOG_SOUND + fclose(f); +#endif +} +// ------------------------------------------------ +// device I/O handlers +// ------------------------------------------------ + +READ8_MEMBER(gf1_device::global_reg_select_r) +{ + if(offset == 0) + return m_current_voice; + else + return m_current_reg | 0xc0; +} + +WRITE8_MEMBER(gf1_device::global_reg_select_w) +{ + if(offset == 0) + m_current_voice = data & 0x1f; + else + m_current_reg = data; +} + +READ8_MEMBER(gf1_device::global_reg_data_r) +{ + UINT16 ret = 0x00; + + switch(m_current_reg) + { + case 0x41: // DMA DRAM control + if(offset == 1) + { + ret = m_dma_dram_ctrl; + m_dma_dram_ctrl &= ~0x40; + m_dma_irq_handler(0); + return ret; + } + case 0x45: // Timer control + if(offset == 1) + return m_timer_ctrl & 0x0c; + break; + case 0x49: // Sampling control + if(offset == 1) + return m_sampling_ctrl & 0xe7; + case 0x4c: // Reset + if(offset == 1) + return m_reset; + case 0x80: // Voice control +/* bit 0 - 1 if voice is stopped + * bit 6 - 1 if addresses are decreasing, can change when looping is enabled + * bit 7 - 1 if Wavetable IRQ is pending */ + if(offset == 1) + return m_voice[m_current_voice].voice_ctrl & 0xff; + case 0x81: // Frequency Control + ret = m_voice[m_current_voice].freq_ctrl; + if(offset == 0) + return ret & 0x00ff; + else + return (ret >> 8) & 0x00ff; + case 0x82: // Starting address (high 13 bits) + ret = (m_voice[m_current_voice].start_addr >> 16); + if(offset == 0) + return ret & 0x00ff; + else + return (ret >> 8) & 0x00ff; + case 0x83: // Starting address (low 7 bits plus 4 bits fractional) + ret = (m_voice[m_current_voice].start_addr & 0xffff); + if(offset == 0) + return ret & 0x00ff; + else + return (ret >> 8) & 0x00ff; + case 0x84: // End address (high 13 bits) + ret = (m_voice[m_current_voice].end_addr >> 16); + if(offset == 0) + return ret & 0x00ff; + else + return (ret >> 8) & 0x00ff; + case 0x85: // End address (low 7 bits plus 4 bits fractional) + ret = (m_voice[m_current_voice].end_addr & 0xffff); + if(offset == 0) + return ret & 0x00ff; + else + return (ret >> 8) & 0x00ff; + case 0x86: // Volume Ramp rate + if(offset == 1) + return m_voice[m_current_voice].vol_ramp_rate; + case 0x87: // Volume Ramp start (high 4 bits = exponent, low 4 bits = mantissa) + if(offset == 1) + return m_voice[m_current_voice].vol_ramp_start; + case 0x88: // Volume Ramp end (high 4 bits = exponent, low 4 bits = mantissa) + if(offset == 1) + return m_voice[m_current_voice].vol_ramp_end; + case 0x89: // Current Volume (high 4 bits = exponent, middle 8 bits = mantissa, low 4 bits = 0 [reserved]) + ret = m_voice[m_current_voice].current_vol; + if(offset == 0) + return ret & 0x00ff; + else + return (ret >> 8) & 0x00ff; + case 0x8a: // Current position (high 13 bits) + ret = (m_voice[m_current_voice].current_addr >> 16); + if(offset == 0) + return ret & 0x00ff; + else + return (ret >> 8) & 0x00ff; + case 0x8b: // Current position (low 7 bits, plus 9 bit fractional) + ret = (m_voice[m_current_voice].current_addr & 0xffff); + if(offset == 0) + return ret & 0x00ff; + else + return (ret >> 8) & 0x00ff; + case 0x8c: // Pan position (4 bits, 0=full left, 15=full right) + if(offset == 1) + return m_voice[m_current_voice].pan_position; + case 0x8d: // Volume Ramp control +/* bit 0 - Ramp has stopped + * bit 6 - Ramp direction + * bit 7 - Ramp IRQ pending */ + if(offset == 1) + return m_voice[m_current_voice].vol_ramp_ctrl; + case 0x8e: // Active voices (6 bits, high 2 bits are always 1) + if(offset == 1) + return m_active_voices | 0xc0; + case 0x8f: // IRQ source register + if(offset == 1) + { + ret = m_voice_irq_fifo[m_voice_irq_current % 32]; + if((m_voice_irq_current % 32) != (m_voice_irq_ptr % 32)) + m_voice_irq_current++; + else + ret = 0xe0; + m_wave_irq_handler(0); + m_ramp_irq_handler(0); + return ret; + } + break; + default: + logerror("GUS: Read from unimplemented or unknown global register %02x\n",m_current_reg); + return 0xff; + } + return 0xff; +} + +WRITE8_MEMBER(gf1_device::global_reg_data_w) +{ + switch(m_current_reg) + { + case 0x00: // Voice control +/* bit 1 - set to 1 to stop current voice + * bit 2 - set to 1 for 16-bit wave data, otherwise is 8-bit + * bit 3 - set to 1 to loop to start address when the end address is reached + * bit 4 - set to 1 to enable bi-directional looping + * bit 5 - set to 1 to enable wavetable IRQ when end address is reached */ + if(offset == 1) + { + m_voice[m_current_voice].voice_ctrl = data & 0xff; + m_voice[m_current_voice].rollover = false; + if(data & 0x02) + m_voice[m_current_voice].voice_ctrl |= 0x01; + } + logerror("GUS: Ch%i Voice control write %02x\n", m_current_voice,data); + break; + case 0x01: // Frequency Control +/* bits 15-10 - Integer portion + * bits 9-1 - Fractional portion + * bit 0 - not used */ + if(offset == 0) + m_voice[m_current_voice].freq_ctrl = (m_voice[m_current_voice].freq_ctrl & 0xff00) | data; + else + m_voice[m_current_voice].freq_ctrl = (m_voice[m_current_voice].freq_ctrl & 0x00ff) | (data << 8); + logerror("GUS: Ch%i Frequency control write %04x\n", m_current_voice, m_voice[m_current_voice].freq_ctrl); + break; + case 0x02: // Starting address (high 13 bits) + if(offset == 0) + m_voice[m_current_voice].start_addr = (m_voice[m_current_voice].start_addr & 0xff00ffff) | (data << 16); + else + m_voice[m_current_voice].start_addr = (m_voice[m_current_voice].start_addr & 0x00ffffff) | (data << 24); + logerror("GUS: Ch%i [high] Start address set to %08x\n", m_current_voice,m_voice[m_current_voice].start_addr); + break; + case 0x03: // Starting address (low 7 bits plus 4 bits fractional) + if(offset == 0) + m_voice[m_current_voice].start_addr = (m_voice[m_current_voice].start_addr & 0xffffff00) | data; + else + m_voice[m_current_voice].start_addr = (m_voice[m_current_voice].start_addr & 0xffff00ff) | (data << 8); + logerror("GUS: Ch%i [low] Start address set to %08x\n", m_current_voice,m_voice[m_current_voice].start_addr); + break; + case 0x04: // End address (high 13 bits) + if(offset == 0) + m_voice[m_current_voice].end_addr = (m_voice[m_current_voice].end_addr & 0xff00ffff) | (data << 16); + else + m_voice[m_current_voice].end_addr = (m_voice[m_current_voice].end_addr & 0x00ffffff) | (data << 24); + logerror("GUS: Ch%i [high] End address set to %08x\n", m_current_voice,m_voice[m_current_voice].end_addr); + break; + case 0x05: // End address (low 7 bits plus 4 bits fractional) + if(offset == 0) + m_voice[m_current_voice].end_addr = (m_voice[m_current_voice].end_addr & 0xffffff00) | data; + else + m_voice[m_current_voice].end_addr = (m_voice[m_current_voice].end_addr & 0xffff00ff) | (data << 8); + logerror("GUS: Ch%i [low] End address set to %08x\n", m_current_voice,m_voice[m_current_voice].end_addr); + break; + case 0x06: // Volume Ramp rate + if(offset == 1) + m_voice[m_current_voice].vol_ramp_rate = data; + logerror("GUS: Ch%i Volume ramp rate write %02x\n", m_current_voice,data); + break; + case 0x07: // Volume Ramp start (high 4 bits = exponent, low 4 bits = mantissa) + if(offset == 1) + m_voice[m_current_voice].vol_ramp_start = data; + logerror("GUS: Ch%i Volume ramp start write %02x\n", m_current_voice, data); + break; + case 0x08: // Volume Ramp end (high 4 bits = exponent, low 4 bits = mantissa) + if(offset == 1) + m_voice[m_current_voice].vol_ramp_end = data; + logerror("GUS: Ch%i Volume ramp end write %02x\n", m_current_voice, data); + break; + case 0x09: // Current Volume (high 4 bits = exponent, middle 8 bits = mantissa, low 4 bits = 0 [reserved]) + if(offset == 0) + m_voice[m_current_voice].current_vol = (m_voice[m_current_voice].current_vol & 0xff00) | data; + else + m_voice[m_current_voice].current_vol = (m_voice[m_current_voice].current_vol & 0x00ff) | (data << 8); + logerror("GUS: Ch%i Current volume write %02x\n", m_current_voice, data); + break; + case 0x0a: // Current position (high 13 bits) + if(offset == 0) + m_voice[m_current_voice].current_addr = (m_voice[m_current_voice].current_addr & 0xff00ffff) | (data << 16); + else + m_voice[m_current_voice].current_addr = (m_voice[m_current_voice].current_addr & 0x00ffffff) | (data << 24); + logerror("GUS: Ch%i Current address write %08x\n", m_current_voice, m_voice[m_current_voice].current_addr); + break; + case 0x0b: // Current position (low 7 bits, plus 9 bit fractional) + if(offset == 0) + m_voice[m_current_voice].current_addr = (m_voice[m_current_voice].current_addr & 0xffffff00) | data; + else + m_voice[m_current_voice].current_addr = (m_voice[m_current_voice].current_addr & 0xffff00ff) | (data << 8); + logerror("GUS: Ch%i Current address write %08x\n", m_current_voice, m_voice[m_current_voice].current_addr); + break; + case 0x0c: // Pan position (4 bits, 0=full left, 15=full right) + if(offset == 1) + m_voice[m_current_voice].pan_position = data & 0x0f; + logerror("GUS: Ch%i Pan Position write %02x\n", m_current_voice, data); + break; + case 0x0d: // Volume Ramp control +/* bit 1 - set to 1 to stop the ramp + * bit 2 - roll over condition (generate IRQ, and not stop playing voice, no looping) + * bit 3 - enable looping + * bit 4 - enable bi-directional looping + * bit 5 - rnable IRQ at end of ramp */ + if(offset == 1) + { + m_voice[m_current_voice].vol_ramp_ctrl = data & 0x7f; + if(!(data & 0x01)) + { + m_voice[m_current_voice].vol_count = 0; + if(m_voice[m_current_voice].vol_ramp_ctrl & 0x40) + m_voice[m_current_voice].current_vol = (m_voice[m_current_voice].vol_ramp_end << 8); + else + m_voice[m_current_voice].current_vol = (m_voice[m_current_voice].vol_ramp_start << 8); + } + if(data & 0x02) + { + m_voice[m_current_voice].vol_ramp_ctrl |= 0x01; + } + } + logerror("GUS: Ch%i Volume Ramp control write %02x\n", m_current_voice, data); + break; + case 0x0e: // Active voices (6 bits, high 2 bits are always 1) + if(offset == 1) + { + m_active_voices = data & 0x3f; + if((data & 0x3f) < 14) + m_active_voices = 14; + if((data & 0x3f) > 32) + m_active_voices = 32; + m_stream->set_sample_rate(rate_table[m_active_voices]); + m_voltimer->adjust(attotime::zero,0,attotime::from_usec(1000/(1.6*m_active_voices))); + } + logerror("GUS: Active Voices write %02x (%i Hz)\n", data, rate_table[m_active_voices]); + break; + case 0x41: +/* bit 0 - Enable the DMA channel. + * bit 1 - DMA transfer direction (1 = read from the GUS) + * bit 2 - DMA channel width (0=8-bit, 1=16-bit) + * bits 3,4 - DMA rate divider + * bit 5 - DMA terminal count IRQ enable + * bit 6 - DMA terminal count IRQ pending (read), Data size (write, 0=8bit, 1=16-bit, independent of channel size) + * bit 7 - Invert MSB of data + */ + if(offset == 1) + { + m_dma_dram_ctrl = data & 0xbf; + m_dma_16bit = data & 0x40; + if(data & 0x01) + { + m_dmatimer->adjust(attotime::zero,0,attotime::from_nsec(11489)); // based on 680Kb/sec mentioned in UltraMID docs + logerror("GUS: DMA start from DRAM address 0x%05x\n",m_dma_start_addr<<4); + } + else + { + m_dmatimer->reset(); // stop transfer + logerror("GUS: DMA aborted.\n"); + } + } + logerror("GUS: DMA DRAM control write %02x\n",data); + break; + case 0x42: // DMA start address (high 16 bits, address lines 4-19) + if(offset == 0) + m_dma_start_addr = (m_dma_start_addr & 0xff00) | data; + else + m_dma_start_addr = (m_dma_start_addr & 0x00ff) | (data << 8); + m_dma_current = m_dma_start_addr << 4; + logerror("GUS: DMA start address set to %08x\n",m_dma_start_addr); + break; + case 0x43: // DRAM I/O address (low 16 bits) + if(offset == 0) + m_dram_addr = (m_dram_addr & 0x000fff00) | data; + else + m_dram_addr = (m_dram_addr & 0x000f00ff) | (data << 8); + //logerror("GUS: [low] DRAM I/O address set to %08x\n",m_dram_addr); + break; + case 0x44: // DRAM I/O address (high 4 bits) + if(offset == 1) + m_dram_addr = (m_dram_addr & 0x0000ffff) | (data << 16); + //logerror("GUS: [high] DRAM I/O address set to %08x\n",m_dram_addr); + break; + case 0x45: // Timer control +/* bit 3 - Enable timer 1 IRQ + * bit 4 - Enable timer 2 IRQ */ + if(offset == 1) + { + m_timer_ctrl = data; + if(!(data & 0x20)) + m_adlib_status &= ~0x18; + if(!(data & 0x02)) + m_adlib_status &= ~0x01; + if(!(m_adlib_status & 0x19)) + m_sb_irq_handler(0); + if(!(data & 0x04)) + { + m_adlib_status &= ~0x40; + m_timer1_irq_handler(0); + } + if(!(data & 0x08)) + { + m_adlib_status &= ~0x20; + m_timer2_irq_handler(0); + } + if((m_adlib_status & 0x60) != 0) + m_adlib_status &= ~0x80; + } + logerror("GUS: Timer control write %02x\n",data); + break; + case 0x46: // Timer 1 count + if(offset == 1) + { + m_timer1_count = data; + m_timer1_value = data; + logerror("GUS: Timer 1 count write %02x\n",data); + } + break; + case 0x47: // Timer 2 count + if(offset == 1) + { + m_timer2_count = data; + m_timer2_value = data; + logerror("GUS: Timer 2 count write %02x\n",data); + } + break; + case 0x48: // Sampling Frequency - 9878400/(16*(FREQ+2)) + if(offset == 0) + m_sampling_freq = (m_sampling_freq & 0xff00) | data; + else + m_sampling_freq = (m_sampling_freq & 0x00ff) | (data << 8); + logerror("GUS: Sampling frequency write %02x\n",data); + break; + case 0x49: // Sampling control +/* bit 0 - Start sampling + * bit 1 - Mode (0=mono, 1=stereo) + * bit 2 - DMA width (0=8-bit, 1=16-bit) + * bit 5 - DMA IRQ enable + * bit 6 - DMA IRQ pending (read only) + * bit 7 - Invert MSB */ + if(offset == 1) + m_sampling_ctrl = data; + logerror("GUS: Sampling control write %02x\n",data); + break; + case 0x4b: // Joystick trim DAC + if(offset == 1) + m_joy_trim_dac = data; + logerror("GUS: Joystick trim DAC write %02x\n",data); + break; + case 0x4c: // Reset + if(offset == 1) + { + if(!(data & 0x01)) + device_reset(); + m_reset = data & 0xf9; + } + logerror("GUS: Reset write %02x\n",data); + break; + default: + logerror("GUS: Write %02x to unimplemented or unknown global register %02x\n",data,m_current_reg); + } +} + +/* port 0x3X7 - DRAM I/O + * read and write bytes directly to wavetable DRAM */ +READ8_MEMBER(gf1_device::dram_r) +{ + if(offset == 1) + { + return m_wave_ram[m_dram_addr & 0xfffff]; + } + else + return 0xff; +} + +WRITE8_MEMBER(gf1_device::dram_w) +{ + if(offset == 1) + { + m_wave_ram[m_dram_addr & 0xfffff] = data; + } +} + +/* port 2XA - read selected adlib command? + * the GUS driver installation writes 0x55 to port 0x388, then expects to reads the same from 0x2XA */ +READ8_MEMBER(gf1_device::adlib_cmd_r) +{ + if(offset == 0) + { + return m_adlib_cmd; + } + else + { + // TODO + return 0xff; + } +} + +/* port 0x2XB - set IRQ/DMA latch + * if IRQ (bit 6 of 0x2X0 = 1) + * bits 2-0 = channel 1 (GF1) IRQ selector + * 0 = reserved, 1 = IRQ2, 2 = IRQ5, 3 = IRQ3, 4 = IRQ7, 5 = IRQ11, 6 = IRQ12, 7 = IRQ13 + * bits 5-3 = channel 2 (MIDI) IRQ selector + * 0 = No interrupt selected, rest are as for the GF1 + * bit 6 = combine both IRQs using channel 1 IRQ + * if DMA (bit 6 of 0x2X0 = 0) + * bits 2-0 = DMA select register 1 + * 0 = No DMA, 1 = DMA1, 2 = DMA3, 3 = DMA5, 4 = DMA6, 5 = DMA7 + * bits 5-3 = DMA select register 2 (values same as reg 1) + * bit 6 = combine both on same DMA channel + */ +WRITE8_MEMBER(gf1_device::adlib_cmd_w) +{ + if(offset == 1) + { + switch(m_reg_ctrl & 0x07) + { + case 0x00: + if(m_mix_ctrl & 0x40) + { + switch(data & 0x07) + { + case 1: + m_gf1_irq = 2; + break; + case 2: + m_gf1_irq = 5; + break; + case 3: + m_gf1_irq = 3; + break; + case 4: + m_gf1_irq = 7; + break; + case 5: + m_gf1_irq = 11; + break; + case 6: + m_gf1_irq = 12; + break; + case 7: + m_gf1_irq = 15; + break; + default: + m_gf1_irq = 0; + logerror("GUS: Invalid GF1 IRQ set! [%02x]\n",data); + } + switch((data >> 3) & 0x07) + { + case 0: + m_midi_irq = 0; + break; + case 1: + m_midi_irq = 2; + break; + case 2: + m_midi_irq = 5; + break; + case 3: + m_midi_irq = 3; + break; + case 4: + m_midi_irq = 7; + break; + case 5: + m_midi_irq = 11; + break; + case 6: + m_midi_irq = 12; + break; + case 7: + m_midi_irq = 15; + break; + default: + logerror("GUS: Invalid MIDI IRQ set! [%02x]\n",data); + } + if(data & 0x40) + m_irq_combine = 1; + else + m_irq_combine = 0; + logerror("GUS: IRQs set: GF1 = IRQ%i, MIDI = IRQ%i\n",m_gf1_irq,m_midi_irq); + } + else + { + switch(data & 0x07) + { + case 0: + m_dma_channel1 = 0; + break; + case 1: + m_dma_channel1 = 1; + break; + case 2: + m_dma_channel1 = 3; + break; + case 3: + m_dma_channel1 = 5; + break; + case 4: + m_dma_channel1 = 6; + break; + case 5: + m_dma_channel1 = 7; + break; + default: + logerror("GUS: Invalid DMA channel #1 set! [%02x]\n",data); + } + switch((data >> 3) & 0x07) + { + case 0: + m_dma_channel2 = 0; + break; + case 1: + m_dma_channel2 = 1; + break; + case 2: + m_dma_channel2 = 3; + break; + case 3: + m_dma_channel2 = 5; + break; + case 4: + m_dma_channel2 = 6; + break; + case 5: + m_dma_channel2 = 7; + break; + default: + logerror("GUS: Invalid DMA channel #2 set! [%02x]\n",data); + } + if(data & 0x40) + m_dma_combine = 1; + else + m_dma_combine = 0; + logerror("GUS: DMA channels set: DMA%i, DMA%i\n",m_dma_channel1,m_dma_channel2); + } + break; + case 0x05: + m_statread = 0; + //m_other_irq_handler(0); + break; + case 0x06: + // TODO: Jumper register (joy/MIDI enable) + break; + } + } + else + { + m_fake_adlib_status = data; + logerror("GUS: Adlib status set to %02x\n",data); + } +} + +/* port 0x2X0 - Mix control register + * bit 0 - 0=Enable Line In + * bit 1 - 0=Enable Line Out + * bit 2 - 1=Enable MIC In + * bit 3 - Enable latches (once enabled, must remain enabled) + * bit 4 - Combine GF1 IRQs with MIDI IRQs + * bit 5 - Enable MIDI TxD to RxD loopback + * bit 6 - Control Reg Select - set next I/O write to 0x2XB to be DMA (0) or IRQ (1) channel latches */ +READ8_MEMBER(gf1_device::mix_ctrl_r) +{ + return 0xff; // read only +} + +WRITE8_MEMBER(gf1_device::mix_ctrl_w) +{ + if(offset == 0) + m_mix_ctrl = data; +} + +READ8_MEMBER(gf1_device::sb_r) +{ + UINT8 val; + + switch(offset) + { + case 0x00: + val = m_sb_data_2xc; + if(m_statread & 0x20) + m_sb_data_2xc ^= 0x80; // flip MSB on read + return val; + // port 0x2XD is write-only + case 0x02: + if(m_reg_ctrl & 0x80) + { + m_statread |= 0x80; + m_nmi_handler(1); + } + return m_sb_data_2xe; + } + return 0xff; +} + +WRITE8_MEMBER(gf1_device::sb_w) +{ + switch(offset) + { + case 0x00: + if(m_timer_ctrl & 0x20) + { + m_adlib_status |= 0x10; + m_nmi_handler(1); + logerror("GUS: SB 0x2XC IRQ active\n"); + } + break; + case 0x01: + m_sb_data_2xc = data; + break; + case 0x02: + m_sb_data_2xe = data; + break; + } +} + +WRITE8_MEMBER(gf1_device::sb2x6_w) +{ + if(offset==0) + { + if(m_timer_ctrl & 0x20) + { + m_adlib_status |= 0x08; + m_nmi_handler(1); + logerror("GUS: SB 0x2X6 IRQ active\n"); + } + } +} + +READ8_MEMBER(gf1_device::stat_r) +{ + UINT8 val = m_statread & 0xf9; + if(m_mix_ctrl & 0x08) + val |= 0x02; + return val; +} + +WRITE8_MEMBER(gf1_device::stat_w) +{ + m_reg_ctrl = data; +} + +void gf1_device::set_irq(UINT8 source, UINT8 voice) +{ + if(source & IRQ_WAVETABLE) + { + m_irq_source = 0xe0 | (voice & 0x1f); + m_irq_source &= ~0x80; + m_wave_irq_handler(1); + m_voice_irq_fifo[m_voice_irq_ptr % 32] = m_irq_source; + m_voice_irq_ptr++; + m_voice[voice].voice_ctrl |= 0x80; + } + if(source & IRQ_VOLUME_RAMP) + { + m_irq_source = 0xe0 | (voice & 0x1f); + m_irq_source &= ~0x40; + m_ramp_irq_handler(1); + m_voice_irq_fifo[m_voice_irq_ptr % 32] = m_irq_source; + m_voice_irq_ptr++; + } +} + +void gf1_device::reset_irq(UINT8 source) +{ + if(source & IRQ_WAVETABLE) + { + m_irq_source |= 0x80; + m_wave_irq_handler(0); + } + if(source & IRQ_VOLUME_RAMP) + { + m_irq_source |= 0x40; + m_ramp_irq_handler(0); + } +} + +// TODO: support 16-bit transfers +UINT8 gf1_device::dack_r(int line) +{ + return m_wave_ram[m_dma_current++ & 0xfffff]; +} + +void gf1_device::dack_w(int line,UINT8 data) +{ + if(m_dma_dram_ctrl & 0x80) // flip data MSB + { + if(m_dma_16bit != 0) // if data is 16-bit + { + if((m_dma_current & 1)) + data ^= 0x80; + } + else // data is 8-bit + { + data ^= 0x80; + } + } + m_wave_ram[m_dma_current & 0xfffff] = data; + m_dma_current++; + m_drq1_handler(0); +} + +void gf1_device::eop_w(int state) +{ + if(state == ASSERT_LINE) { + // end of transfer + m_dmatimer->reset(); + //m_drq1_handler(0); + if(m_dma_dram_ctrl & 0x20) + { + m_dma_dram_ctrl |= 0x40; + m_dma_irq_handler(1); + } + logerror("GUS: End of transfer. (%05x)\n",m_dma_current); + } +} + + +/* 16-bit ISA card device implementation */ + +static MACHINE_CONFIG_FRAGMENT( gus_config ) + MCFG_SPEAKER_STANDARD_STEREO("lspeaker","rspeaker") + MCFG_SOUND_ADD("gf1",GGF1,GF1_CLOCK) + MCFG_SOUND_ROUTE(0,"lspeaker",0.50) + MCFG_SOUND_ROUTE(1,"rspeaker",0.50) + + MCFG_ACIA6850_TXD_HANDLER(DEVWRITELINE("mdout", midi_port_device, write_txd)) + MCFG_GF1_TXIRQ_HANDLER(WRITELINE(isa16_gus_device, midi_txirq)) + MCFG_GF1_RXIRQ_HANDLER(WRITELINE(isa16_gus_device, midi_txirq)) + MCFG_GF1_WAVE_IRQ_HANDLER(WRITELINE(isa16_gus_device, wavetable_irq)) + MCFG_GF1_RAMP_IRQ_HANDLER(WRITELINE(isa16_gus_device, volumeramp_irq)) + MCFG_GF1_TIMER1_IRQ_HANDLER(WRITELINE(isa16_gus_device, timer1_irq)) + MCFG_GF1_TIMER2_IRQ_HANDLER(WRITELINE(isa16_gus_device, timer2_irq)) + MCFG_GF1_SB_IRQ_HANDLER(WRITELINE(isa16_gus_device, sb_irq)) + MCFG_GF1_DMA_IRQ_HANDLER(WRITELINE(isa16_gus_device, dma_irq)) + MCFG_GF1_DRQ1_HANDLER(WRITELINE(isa16_gus_device, drq1_w)) + MCFG_GF1_DRQ2_HANDLER(WRITELINE(isa16_gus_device, drq2_w)) + MCFG_GF1_NMI_HANDLER(WRITELINE(isa16_gus_device, nmi_w)) + + MCFG_MIDI_PORT_ADD("mdin", midiin_slot, "midiin") + MCFG_MIDI_RX_HANDLER(DEVWRITELINE("gf1", acia6850_device, write_rxd)) + + MCFG_MIDI_PORT_ADD("mdout", midiout_slot, "midiout") + + MCFG_DEVICE_ADD("acia_clock", CLOCK, 31250*16) + MCFG_CLOCK_SIGNAL_HANDLER(WRITELINE(isa16_gus_device, write_acia_clock)) +MACHINE_CONFIG_END + +static INPUT_PORTS_START( gus_joy ) + PORT_START("gus_joy") + PORT_BIT( 0x0f, IP_ACTIVE_LOW, IPT_UNUSED ) // x/y ad stick to digital converters + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_BUTTON1) PORT_NAME("GUS Joystick Button 1") + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_BUTTON2) PORT_NAME("GUS Joystick Button 2") + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_BUTTON3) PORT_NAME("GUS Joystick Button 3") + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_BUTTON4) PORT_NAME("GUS Joystick Button 4") + + PORT_START("gus_joy_1") + PORT_BIT(0xff,0x80,IPT_AD_STICK_X) PORT_SENSITIVITY(100) PORT_KEYDELTA(1) PORT_MINMAX(1,0xff) PORT_CODE_DEC(KEYCODE_LEFT) PORT_CODE_INC(KEYCODE_RIGHT) PORT_CODE_DEC(JOYCODE_X_LEFT_SWITCH) PORT_CODE_INC(JOYCODE_X_RIGHT_SWITCH) + + PORT_START("gus_joy_2") + PORT_BIT(0xff,0x80,IPT_AD_STICK_Y) PORT_SENSITIVITY(100) PORT_KEYDELTA(1) PORT_MINMAX(1,0xff) PORT_CODE_DEC(KEYCODE_UP) PORT_CODE_INC(KEYCODE_DOWN) PORT_CODE_DEC(JOYCODE_Y_UP_SWITCH) PORT_CODE_INC(JOYCODE_Y_DOWN_SWITCH) +INPUT_PORTS_END + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor isa16_gus_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( gus_config ); +} + +ioport_constructor isa16_gus_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( gus_joy ); +} + + +isa16_gus_device::isa16_gus_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, ISA16_GUS, "Gravis Ultrasound", tag, owner, clock, "isa_gus", __FILE__), + device_isa16_card_interface( mconfig, *this ), + m_gf1(*this, "gf1") +{ +} + +void isa16_gus_device::device_start() +{ + set_isa_device(); + m_isa->install_device(0x0200, 0x0201, 0, 0, read8_delegate(FUNC(isa16_gus_device::joy_r),this), write8_delegate(FUNC(isa16_gus_device::joy_w),this) ); + m_isa->install_device(0x0220, 0x022f, 0, 0, read8_delegate(FUNC(isa16_gus_device::board_r),this), write8_delegate(FUNC(isa16_gus_device::board_w),this) ); + m_isa->install_device(0x0320, 0x0327, 0, 0, read8_delegate(FUNC(isa16_gus_device::synth_r),this), write8_delegate(FUNC(isa16_gus_device::synth_w),this) ); + m_isa->install_device(0x0388, 0x0389, 0, 0, read8_delegate(FUNC(isa16_gus_device::adlib_r),this), write8_delegate(FUNC(isa16_gus_device::adlib_w),this) ); +} + +void isa16_gus_device::device_reset() +{ +} + +void isa16_gus_device::device_stop() +{ +} + +READ8_MEMBER(isa16_gus_device::board_r) +{ + switch(offset) + { + case 0x00: + case 0x01: + return m_gf1->mix_ctrl_r(space,offset); + /* port 0x2X6 - IRQ status (active high) + * bit 0 - MIDI transmit IRQ + * bit 1 - MIDI receive IRQ + * bit 2 - Timer 1 IRQ + * bit 3 - Timer 2 IRQ + * bit 4 - reserved (always 0) + * bit 5 - wavetable IRQ + * bit 6 - volume ramp IRQ + * bit 7 - DRAM TC DMA IRQ + */ + case 0x06: + return m_irq_status; + case 0x08: + case 0x09: + return m_gf1->adlib_r(space,offset-8); + case 0x0a: + case 0x0b: + return m_gf1->adlib_cmd_r(space,offset-10); + case 0x0c: + case 0x0d: + case 0x0e: + return m_gf1->sb_r(space,offset-12); + case 0x0f: + return m_gf1->stat_r(space,offset-15); + default: + logerror("GUS: Invalid or unimplemented read of port 0x2X%01x\n",offset); + return 0xff; + } +} + +WRITE8_MEMBER(isa16_gus_device::board_w) +{ + switch(offset) + { + case 0x00: + case 0x01: + m_gf1->mix_ctrl_w(space,offset,data); + break; + case 0x06: + m_gf1->sb2x6_w(space,offset-6,data); + break; + case 0x08: + case 0x09: + m_gf1->adlib_w(space,offset-8,data); + break; + case 0x0a: + case 0x0b: + m_gf1->adlib_cmd_w(space,offset-10,data); + break; + case 0x0c: + case 0x0d: + case 0x0e: + m_gf1->sb_w(space,offset-12,data); + break; + case 0x0f: + m_gf1->stat_w(space,offset-15,data); + break; + default: + logerror("GUS: Invalid or unimplemented register write %02x of port 0x2X%01x\n",data,offset); + } +} + +READ8_MEMBER(isa16_gus_device::synth_r) +{ + switch(offset) + { + case 0x00: + return m_gf1->status_r(space,0); + case 0x01: + return m_gf1->data_r(space,0); + case 0x02: + case 0x03: + return m_gf1->global_reg_select_r(space,offset-2); + case 0x04: + case 0x05: + return m_gf1->global_reg_data_r(space,offset-4); + case 0x06: + case 0x07: + return m_gf1->dram_r(space,offset-6); + default: + logerror("GUS: Invalid or unimplemented register read of port 0x3X%01x\n",offset); + return 0xff; + } +} + +WRITE8_MEMBER(isa16_gus_device::synth_w) +{ + switch(offset) + { + case 0x00: + m_gf1->control_w(space,0,data); + break; + case 0x01: + m_gf1->data_w(space,0,data); + break; + case 0x02: + case 0x03: + m_gf1->global_reg_select_w(space,offset-2,data); + break; + case 0x04: + case 0x05: + m_gf1->global_reg_data_w(space,offset-4,data); + break; + case 0x06: + case 0x07: + m_gf1->dram_w(space,offset-6,data); + break; + default: + logerror("GUS: Invalid or unimplemented register write %02x of port 0x3X%01x\n",data,offset); + } +} + +READ8_MEMBER(isa16_gus_device::adlib_r) +{ + return m_gf1->adlib_r(space,offset); +} + +WRITE8_MEMBER(isa16_gus_device::adlib_w) +{ + m_gf1->adlib_w(space,offset,data); +} + +READ8_MEMBER(isa16_gus_device::joy_r) +{ + if(offset == 1) + { + UINT8 data = 0; + int delta; + attotime new_time = machine().time(); + + { + data = ioport("gus_joy")->read() | 0x0f; + + { + delta = ((new_time - m_joy_time) * 256 * 1000).seconds(); + + if (ioport("gus_joy_1")->read() < delta) data &= ~0x01; + if (ioport("gus_joy_2")->read() < delta) data &= ~0x02; + } + } + return data; + } + return 0xff; +} + +WRITE8_MEMBER(isa16_gus_device::joy_w) +{ + m_joy_time = machine().time(); +} + +WRITE_LINE_MEMBER(isa16_gus_device::wavetable_irq) +{ + if(state) + set_irq(IRQ_WAVETABLE); + else + reset_irq(IRQ_WAVETABLE); +} + +WRITE_LINE_MEMBER(isa16_gus_device::volumeramp_irq) +{ + if(state) + set_irq(IRQ_VOLUME_RAMP); + else + reset_irq(IRQ_VOLUME_RAMP); +} + +WRITE_LINE_MEMBER(isa16_gus_device::timer1_irq) +{ + if(state) + set_irq(IRQ_TIMER1); + else + reset_irq(IRQ_TIMER1); +} + +WRITE_LINE_MEMBER(isa16_gus_device::timer2_irq) +{ + if(state) + set_irq(IRQ_TIMER2); + else + reset_irq(IRQ_TIMER2); +} + +WRITE_LINE_MEMBER(isa16_gus_device::dma_irq) +{ + if(state) + set_irq(IRQ_DRAM_TC_DMA); + else + reset_irq(IRQ_DRAM_TC_DMA); +} + +WRITE_LINE_MEMBER(isa16_gus_device::sb_irq) +{ + if(state) + set_midi_irq(IRQ_SB); + else + reset_midi_irq(IRQ_SB); +} + +WRITE_LINE_MEMBER(isa16_gus_device::drq1_w) +{ + m_isa->set_dma_channel(m_gf1->dma_channel1(), this, TRUE); + switch(m_gf1->dma_channel1()) + { + case 1: + m_isa->drq1_w(state); + break; + case 3: + m_isa->drq3_w(state); + break; + case 5: + m_isa->drq5_w(state); + break; + case 6: + m_isa->drq6_w(state); + break; + case 7: + m_isa->drq7_w(state); + break; + default: + logerror("GUS: Invalid DMA channel %i, ignoring.\n",m_gf1->dma_channel1()); + } +} + +WRITE_LINE_MEMBER(isa16_gus_device::drq2_w) +{ + m_isa->set_dma_channel(m_gf1->dma_channel2(), this, TRUE); + switch(m_gf1->dma_channel2()) + { + case 1: + m_isa->drq1_w(state); + break; + case 3: + m_isa->drq3_w(state); + break; + case 5: + m_isa->drq5_w(state); + break; + case 6: + m_isa->drq6_w(state); + break; + case 7: + m_isa->drq7_w(state); + break; + default: + logerror("GUS: Invalid DMA channel %i, ignoring.\n",m_gf1->dma_channel2()); + } +} + +void isa16_gus_device::set_irq(UINT8 source) +{ + m_irq_status |= source; + + switch(m_gf1->gf1_irq()) + { + case 2: + m_isa->irq2_w(1); + break; + case 3: + m_isa->irq3_w(1); + break; + case 5: + m_isa->irq5_w(1); + break; + case 7: + m_isa->irq7_w(1); + break; + case 11: + m_isa->irq11_w(1); + break; + case 12: + m_isa->irq12_w(1); + break; + case 15: + m_isa->irq15_w(1); + break; + } + logerror("GUS: Set IRQ %02x\n",source); +} + +void isa16_gus_device::reset_irq(UINT8 source) +{ + m_irq_status &= ~source; + + switch(m_gf1->gf1_irq()) + { + case 2: + m_isa->irq2_w(0); + break; + case 3: + m_isa->irq3_w(0); + break; + case 5: + m_isa->irq5_w(0); + break; + case 7: + m_isa->irq7_w(0); + break; + case 11: + m_isa->irq11_w(0); + break; + case 12: + m_isa->irq12_w(0); + break; + case 15: + m_isa->irq15_w(0); + break; + } + logerror("GUS: Reset IRQ %02x\n",source); +} + +void isa16_gus_device::set_midi_irq(UINT8 source) +{ + m_irq_status |= source; + + switch(m_gf1->midi_irq()) + { + case 2: + m_isa->irq2_w(1); + break; + case 3: + m_isa->irq3_w(1); + break; + case 5: + m_isa->irq5_w(1); + break; + case 7: + m_isa->irq7_w(1); + break; + case 11: + m_isa->irq11_w(1); + break; + case 12: + m_isa->irq12_w(1); + break; + case 15: + m_isa->irq15_w(1); + break; + } + logerror("GUS: Set MIDI IRQ %02x\n",source); +} + +void isa16_gus_device::reset_midi_irq(UINT8 source) +{ + m_irq_status &= ~source; + + switch(m_gf1->midi_irq()) + { + case 2: + m_isa->irq2_w(0); + break; + case 3: + m_isa->irq3_w(0); + break; + case 5: + m_isa->irq5_w(0); + break; + case 7: + m_isa->irq7_w(0); + break; + case 11: + m_isa->irq11_w(0); + break; + case 12: + m_isa->irq12_w(0); + break; + case 15: + m_isa->irq15_w(0); + break; + } + logerror("GUS: Reset MIDI IRQ %02x\n",source); +} + +WRITE_LINE_MEMBER( isa16_gus_device::midi_txirq ) +{ + if (state) + set_midi_irq(IRQ_MIDI_TRANSMIT); + else + reset_midi_irq(IRQ_MIDI_TRANSMIT | IRQ_MIDI_RECEIVE); +} + +WRITE_LINE_MEMBER( isa16_gus_device::midi_rxirq ) +{ + if (state) + set_midi_irq(IRQ_MIDI_RECEIVE); + else + reset_midi_irq(IRQ_MIDI_TRANSMIT | IRQ_MIDI_RECEIVE); +} + +WRITE_LINE_MEMBER( isa16_gus_device::write_acia_clock ) +{ + m_gf1->write_txc(state); + m_gf1->write_rxc(state); +} + +WRITE_LINE_MEMBER( isa16_gus_device::nmi_w) +{ + m_irq_status |= IRQ_SB; + m_isa->nmi(); +} + +UINT8 isa16_gus_device::dack_r(int line) +{ + if(line == m_gf1->dma_channel1()) + return m_gf1->dack_r(line); + else + return 0; +} + +void isa16_gus_device::dack_w(int line,UINT8 data) +{ + if(line == m_gf1->dma_channel1()) + m_gf1->dack_w(line,data); +} + +void isa16_gus_device::eop_w(int state) +{ + m_gf1->eop_w(state); +} diff --git a/src/devices/bus/isa/gus.h b/src/devices/bus/isa/gus.h new file mode 100644 index 00000000000..60d03cf0262 --- /dev/null +++ b/src/devices/bus/isa/gus.h @@ -0,0 +1,323 @@ +// license:BSD-3-Clause +// copyright-holders:Barry Rodewald +/* + * Gravis Ultrasound ISA card + * + * Started: 28/01/2012 + * + * I/O port map (info from the Gravis Ultrasound SDK documentation): + * Base port is 0x2X0 - where X is defined by a jumper + * + * MIDI: + * 0x3X0 - MIDI Control (read), MIDI Status (write) + * 0x3X1 - MIDI Transmit (write), MIDI Receive (read) + * MIDI operates identically to a 6850 UART + * + * Joystick: + * 0x201 - Joystick trigger timer (write), Joystick data (read) + * + * GF1 Synthesiser: + * 0x3X2 - Page register (voice select) + * 0x3X3 - Global Register select + * 0x3X4 - Global Data (low byte) + * 0x3X5 - Global Data (high byte) + * 0x2X6 - IRQ status register (read only, active high) + * 0x2X8 - Timer control register + * 0x2X9 - Timer data + * 0x3X7 - DRAM data (can be via DMA also) + * + * Board: + * 0x2X0: Mix control register (write only) + * 0x2XB: IRQ/DMA control register (write only) - dependant on mix control bit 6 + * 0x2XF: Register controls (board rev 3.4+ only) + * 0x7X6: Board version (read only, board rev 3.7+ only) + * + * Mixer Control: + * 0x7X6: Control port (write only) + * 0x3X6: Data port (write only) + */ + +#pragma once + +#ifndef __ISA_GUS_H__ +#define __ISA_GUS_H__ + +#include "emu.h" +#include "isa.h" +#include "machine/6850acia.h" + +#define MCFG_GF1_TXIRQ_HANDLER(_devcb) \ + devcb = &gf1_device::set_txirq_handler(*device, DEVCB_##_devcb); + +#define MCFG_GF1_RXIRQ_HANDLER(_devcb) \ + devcb = &gf1_device::set_rxirq_handler(*device, DEVCB_##_devcb); + +#define MCFG_GF1_WAVE_IRQ_HANDLER(_devcb) \ + devcb = &gf1_device::set_wave_irq_handler(*device, DEVCB_##_devcb); + +#define MCFG_GF1_RAMP_IRQ_HANDLER(_devcb) \ + devcb = &gf1_device::set_ramp_irq_handler(*device, DEVCB_##_devcb); + +#define MCFG_GF1_TIMER1_IRQ_HANDLER(_devcb) \ + devcb = &gf1_device::set_timer1_irq_handler(*device, DEVCB_##_devcb); + +#define MCFG_GF1_TIMER2_IRQ_HANDLER(_devcb) \ + devcb = &gf1_device::set_timer2_irq_handler(*device, DEVCB_##_devcb); + +#define MCFG_GF1_SB_IRQ_HANDLER(_devcb) \ + devcb = &gf1_device::set_sb_irq_handler(*device, DEVCB_##_devcb); + +#define MCFG_GF1_DMA_IRQ_HANDLER(_devcb) \ + devcb = &gf1_device::set_dma_irq_handler(*device, DEVCB_##_devcb); + +#define MCFG_GF1_DRQ1_HANDLER(_devcb) \ + devcb = &gf1_device::set_drq1_handler(*device, DEVCB_##_devcb); + +#define MCFG_GF1_DRQ2_HANDLER(_devcb) \ + devcb = &gf1_device::set_drq2_handler(*device, DEVCB_##_devcb); + +#define MCFG_GF1_NMI_HANDLER(_devcb) \ + devcb = &gf1_device::set_nmi_handler(*device, DEVCB_##_devcb); + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> gf1_device + +#define GF1_CLOCK 9878400 + +#define IRQ_2XF 0x00 +#define IRQ_MIDI_TRANSMIT 0x01 +#define IRQ_MIDI_RECEIVE 0x02 +#define IRQ_TIMER1 0x04 +#define IRQ_TIMER2 0x08 +#define IRQ_SB 0x10 +#define IRQ_WAVETABLE 0x20 +#define IRQ_VOLUME_RAMP 0x40 +#define IRQ_DRAM_TC_DMA 0x80 + +struct gus_voice +{ + UINT8 voice_ctrl; + UINT16 freq_ctrl; + UINT32 start_addr; + UINT32 end_addr; + UINT8 vol_ramp_rate; + UINT8 vol_ramp_start; + UINT8 vol_ramp_end; + UINT16 current_vol; + UINT32 current_addr; + UINT8 pan_position; + UINT8 vol_ramp_ctrl; + UINT32 vol_count; + bool rollover; + INT16 sample; // current sample data +}; + +class gf1_device : + public acia6850_device, + public device_sound_interface +{ +public: + // construction/destruction + gf1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + template static devcb_base &set_txirq_handler(device_t &device, _Object object) { return downcast(device).m_txirq_handler.set_callback(object); } + template static devcb_base &set_rxirq_handler(device_t &device, _Object object) { return downcast(device).m_rxirq_handler.set_callback(object); } + template static devcb_base &set_wave_irq_handler(device_t &device, _Object object) { return downcast(device).m_wave_irq_handler.set_callback(object); } + template static devcb_base &set_ramp_irq_handler(device_t &device, _Object object) { return downcast(device).m_ramp_irq_handler.set_callback(object); } + template static devcb_base &set_timer1_irq_handler(device_t &device, _Object object) { return downcast(device).m_timer1_irq_handler.set_callback(object); } + template static devcb_base &set_timer2_irq_handler(device_t &device, _Object object) { return downcast(device).m_timer2_irq_handler.set_callback(object); } + template static devcb_base &set_sb_irq_handler(device_t &device, _Object object) { return downcast(device).m_sb_irq_handler.set_callback(object); } + template static devcb_base &set_dma_irq_handler(device_t &device, _Object object) { return downcast(device).m_dma_irq_handler.set_callback(object); } + template static devcb_base &set_drq1_handler(device_t &device, _Object object) { return downcast(device).m_drq1_handler.set_callback(object); } + template static devcb_base &set_drq2_handler(device_t &device, _Object object) { return downcast(device).m_drq2_handler.set_callback(object); } + template static devcb_base &set_nmi_handler(device_t &device, _Object object) { return downcast(device).m_nmi_handler.set_callback(object); } + + // current IRQ/DMA channel getters + UINT8 gf1_irq() { if(m_gf1_irq != 0) return m_gf1_irq; else return m_midi_irq; } // workaround for win95 loading dumb values + UINT8 midi_irq() { if(m_irq_combine == 0) return m_midi_irq; else return m_gf1_irq; } + UINT8 dma_channel1() { return m_dma_channel1; } + UINT8 dma_channel2() { if(m_dma_combine == 0) return m_dma_channel2; else return m_dma_channel1; } + + DECLARE_READ8_MEMBER(global_reg_select_r); + DECLARE_WRITE8_MEMBER(global_reg_select_w); + DECLARE_READ8_MEMBER(global_reg_data_r); + DECLARE_WRITE8_MEMBER(global_reg_data_w); + DECLARE_READ8_MEMBER(dram_r); + DECLARE_WRITE8_MEMBER(dram_w); + DECLARE_READ8_MEMBER(adlib_r); + DECLARE_WRITE8_MEMBER(adlib_w); + DECLARE_READ8_MEMBER(adlib_cmd_r); + DECLARE_WRITE8_MEMBER(adlib_cmd_w); + DECLARE_READ8_MEMBER(mix_ctrl_r); + DECLARE_WRITE8_MEMBER(mix_ctrl_w); + DECLARE_READ8_MEMBER(stat_r); + DECLARE_WRITE8_MEMBER(stat_w); + DECLARE_READ8_MEMBER(sb_r); + DECLARE_WRITE8_MEMBER(sb_w); + DECLARE_WRITE8_MEMBER(sb2x6_w); + + // DMA signals + UINT8 dack_r(int line); + void dack_w(int line,UINT8 data); + void eop_w(int state); + + // optional information overrides + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + + // voice-specific registers + gus_voice m_voice[32]; + + // global registers (not voice-specific) + UINT8 m_dma_dram_ctrl; + UINT16 m_dma_start_addr; + UINT32 m_dram_addr; + UINT8 m_timer_ctrl; + UINT8 m_timer1_count; + UINT8 m_timer2_count; + UINT8 m_timer1_value; + UINT8 m_timer2_value; + UINT16 m_sampling_freq; + UINT8 m_sampling_ctrl; + UINT8 m_joy_trim_dac; + UINT8 m_reset; + UINT8 m_active_voices; + UINT8 m_irq_source; + + void set_irq(UINT8 source, UINT8 voice); + void reset_irq(UINT8 source); + void update_volume_ramps(); + + dynamic_buffer m_wave_ram; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_stop(); + + virtual void update_irq(); + +private: + // internal state + sound_stream* m_stream; + + emu_timer* m_timer1; + emu_timer* m_timer2; + emu_timer* m_dmatimer; + emu_timer* m_voltimer; + + UINT8 m_current_voice; + UINT8 m_current_reg; + //UINT8 m_port; + //UINT8 m_irq; + //UINT8 m_dma; + + UINT8 m_adlib_cmd; + UINT8 m_mix_ctrl; + UINT8 m_gf1_irq; + UINT8 m_midi_irq; + UINT8 m_dma_channel1; + UINT8 m_dma_channel2; + UINT8 m_irq_combine; + UINT8 m_dma_combine; + UINT8 m_adlib_timer_cmd; + UINT8 m_adlib_timer1_enable; + UINT8 m_adlib_timer2_enable; + UINT8 m_adlib_status; + UINT8 m_adlib_data; + UINT8 m_voice_irq_fifo[32]; + UINT8 m_voice_irq_ptr; + UINT8 m_voice_irq_current; + UINT8 m_dma_16bit; // set by bit 6 of the DMA DRAM control reg + UINT8 m_statread; + UINT8 m_sb_data_2xc; + UINT8 m_sb_data_2xe; + UINT8 m_reg_ctrl; + UINT8 m_fake_adlib_status; + UINT32 m_dma_current; + UINT16 m_volume_table[4096]; + + static const device_timer_id ADLIB_TIMER1 = 0; + static const device_timer_id ADLIB_TIMER2 = 1; + static const device_timer_id DMA_TIMER = 2; + static const device_timer_id VOL_RAMP_TIMER = 3; + + int m_txirq; + int m_rxirq; + + devcb_write_line m_txirq_handler; + devcb_write_line m_rxirq_handler; + devcb_write_line m_wave_irq_handler; + devcb_write_line m_ramp_irq_handler; + devcb_write_line m_timer1_irq_handler; + devcb_write_line m_timer2_irq_handler; + devcb_write_line m_sb_irq_handler; + devcb_write_line m_dma_irq_handler; + devcb_write_line m_drq1_handler; + devcb_write_line m_drq2_handler; + devcb_write_line m_nmi_handler; +}; + +class isa16_gus_device : + public device_t, + public device_isa16_card_interface +{ +public: + isa16_gus_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + void set_irq(UINT8 source); + void reset_irq(UINT8 source); + void set_midi_irq(UINT8 source); + void reset_midi_irq(UINT8 source); + + DECLARE_READ8_MEMBER(board_r); + DECLARE_READ8_MEMBER(synth_r); + DECLARE_WRITE8_MEMBER(board_w); + DECLARE_WRITE8_MEMBER(synth_w); + DECLARE_READ8_MEMBER(adlib_r); + DECLARE_WRITE8_MEMBER(adlib_w); + DECLARE_READ8_MEMBER(joy_r); + DECLARE_WRITE8_MEMBER(joy_w); + DECLARE_WRITE_LINE_MEMBER(midi_txirq); + DECLARE_WRITE_LINE_MEMBER(midi_rxirq); + DECLARE_WRITE_LINE_MEMBER(wavetable_irq); + DECLARE_WRITE_LINE_MEMBER(volumeramp_irq); + DECLARE_WRITE_LINE_MEMBER(timer1_irq); + DECLARE_WRITE_LINE_MEMBER(timer2_irq); + DECLARE_WRITE_LINE_MEMBER(sb_irq); + DECLARE_WRITE_LINE_MEMBER(dma_irq); + DECLARE_WRITE_LINE_MEMBER(drq1_w); + DECLARE_WRITE_LINE_MEMBER(drq2_w); + DECLARE_WRITE_LINE_MEMBER(nmi_w); + DECLARE_WRITE_LINE_MEMBER(write_acia_clock); + + // DMA overrides + virtual UINT8 dack_r(int line); + virtual void dack_w(int line,UINT8 data); + virtual void eop_w(int state); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual ioport_constructor device_input_ports() const; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_stop(); + +private: + required_device m_gf1; + + UINT8 m_irq_status; + attotime m_joy_time; +}; + +// device type definition +extern const device_type GGF1; +extern const device_type ISA16_GUS; + +#endif /* __ISA_GUS_H__ */ diff --git a/src/devices/bus/isa/hdc.c b/src/devices/bus/isa/hdc.c new file mode 100644 index 00000000000..45b6bc334dd --- /dev/null +++ b/src/devices/bus/isa/hdc.c @@ -0,0 +1,1050 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +/********************************************************************** + + ISA 8 bit XT Hard Disk Controller + +**********************************************************************/ + +#include "emu.h" +#include "hdc.h" + +#define LOG_HDC_STATUS 0 +#define LOG_HDC_CALL 0 +#define LOG_HDC_DATA 0 + +#define CMD_TESTREADY 0x00 +#define CMD_RECALIBRATE 0x01 +#define CMD_SENSE 0x03 +#define CMD_FORMATDRV 0x04 +#define CMD_VERIFY 0x05 +#define CMD_FORMATTRK 0x06 +#define CMD_FORMATBAD 0x07 +#define CMD_READ 0x08 +#define CMD_WRITE 0x0a +#define CMD_SEEK 0x0b + +#define CMD_SETPARAM 0x0c +#define CMD_GETECC 0x0d + +#define CMD_READSBUFF 0x0e +#define CMD_WRITESBUFF 0x0f + +#define CMD_RAMDIAG 0xe0 +#define CMD_DRIVEDIAG 0xe3 +#define CMD_INTERNDIAG 0xe4 +#define CMD_READLONG 0xe5 +#define CMD_WRITELONG 0xe6 + +/* Bits for command status byte */ +#define CSB_ERROR 0x02 +#define CSB_LUN 0x20 + +/* XT hard disk controller status bits */ +#define STA_READY 0x01 +#define STA_INPUT 0x02 +#define STA_COMMAND 0x04 +#define STA_SELECT 0x08 +#define STA_REQUEST 0x10 +#define STA_INTERRUPT 0x20 + +/* XT hard disk controller control bits */ +#define CTL_PIO 0x00 +#define CTL_DMA 0x01 + +static const char *const hdc_command_names[] = +{ + "CMD_TESTREADY", /* 0x00 */ + "CMD_RECALIBRATE", /* 0x01 */ + NULL, /* 0x02 */ + "CMD_SENSE", /* 0x03 */ + "CMD_FORMATDRV", /* 0x04 */ + "CMD_VERIFY", /* 0x05 */ + "CMD_FORMATTRK", /* 0x06 */ + "CMD_FORMATBAD", /* 0x07 */ + "CMD_READ", /* 0x08 */ + NULL, /* 0x09 */ + "CMD_WRITE", /* 0x0A */ + "CMD_SEEK", /* 0x0B */ + "CMD_SETPARAM", /* 0x0C */ + "CMD_GETECC", /* 0x0D */ + "CMD_READSBUFF", /* 0x0E */ + "CMD_WRITESBUFF", /* 0x0F */ + + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 0x10-0x17 */ + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 0x18-0x1F */ + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 0x20-0x27 */ + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 0x28-0x2F */ + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 0x30-0x37 */ + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 0x38-0x3F */ + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 0x40-0x47 */ + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 0x48-0x4F */ + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 0x50-0x57 */ + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 0x58-0x5F */ + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 0x60-0x67 */ + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 0x68-0x6F */ + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 0x70-0x77 */ + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 0x78-0x7F */ + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 0x80-0x87 */ + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 0x88-0x8F */ + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 0x90-0x97 */ + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 0x98-0x9F */ + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 0xA0-0xA7 */ + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 0xA8-0xAF */ + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 0xB0-0xB7 */ + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 0xB8-0xBF */ + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 0xC0-0xC7 */ + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 0xC8-0xCF */ + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 0xD0-0xD7 */ + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 0xD8-0xDF */ + + "CMD_RAMDIAG", /* 0xE0 */ + NULL, /* 0xE1 */ + NULL, /* 0xE2 */ + "CMD_DRIVEDIAG", /* 0xE3 */ + "CMD_INTERNDIAG", /* 0xE4 */ + "CMD_READLONG", /* 0xE5 */ + "CMD_WRITELONG", /* 0xE6 */ + NULL, /* 0xE7 */ + + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 0xE8-0xEF */ + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 0xF0-0xF7 */ + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL /* 0xF8-0xFF */ +}; + +static MACHINE_CONFIG_FRAGMENT( xt_hdc_config ) + MCFG_DEVICE_ADD("hdc",XT_HDC,0) + MCFG_XTHDC_IRQ_HANDLER(WRITELINE(isa8_hdc_device,irq_w)) + MCFG_XTHDC_DRQ_HANDLER(WRITELINE(isa8_hdc_device,drq_w)) + MCFG_HARDDISK_ADD("hdc:primary") + MCFG_HARDDISK_ADD("hdc:slave") +MACHINE_CONFIG_END + +static MACHINE_CONFIG_FRAGMENT( ec1841_hdc_config ) + MCFG_DEVICE_ADD("hdc",EC1841_HDC,0) + MCFG_XTHDC_IRQ_HANDLER(WRITELINE(isa8_hdc_ec1841_device,irq_w)) + MCFG_XTHDC_DRQ_HANDLER(WRITELINE(isa8_hdc_ec1841_device,drq_w)) + MCFG_HARDDISK_ADD("hdc:primary") + MCFG_HARDDISK_ADD("hdc:slave") +MACHINE_CONFIG_END + +ROM_START( hdc ) + ROM_REGION(0x02000,"hdc", 0) + // Bios taken from WD1002A-WX1 + ROM_LOAD("wdbios.rom", 0x00000, 0x02000, CRC(8e9e2bd4) SHA1(601d7ceab282394ebab50763c267e915a6a2166a)) /* WDC IDE Superbios 2.0 (06/28/89) Expansion Rom C8000-C9FFF */ +ROM_END + +static INPUT_PORTS_START( isa_hdc ) + PORT_START("HDD") + PORT_BIT( 0xb0, 0xb0, IPT_UNUSED ) + PORT_DIPNAME( 0x40, 0x40, "IRQ level") + PORT_DIPSETTING( 0x40, "5" ) + PORT_DIPSETTING( 0x00, "2" ) + PORT_DIPNAME( 0x0c, 0x0c, "Type of 1st drive") + PORT_DIPSETTING( 0x0c, "0" ) + PORT_DIPSETTING( 0x08, "1" ) + PORT_DIPSETTING( 0x04, "2" ) + PORT_DIPSETTING( 0x00, "3" ) + PORT_DIPNAME( 0x03, 0x03, "Type of 2nd drive") + PORT_DIPSETTING( 0x03, "0" ) + PORT_DIPSETTING( 0x02, "1" ) + PORT_DIPSETTING( 0x01, "2" ) + PORT_DIPSETTING( 0x00, "3" ) + + PORT_START("ROM") + PORT_DIPNAME( 0x01, 0x01, "Install ROM?") + PORT_DIPSETTING( 0x01, DEF_STR(Yes) ) + PORT_DIPSETTING( 0x00, DEF_STR(No) ) +INPUT_PORTS_END + +const device_type XT_HDC = &device_creator; +const device_type EC1841_HDC = &device_creator; +const device_type ST11M_HDC = &device_creator; + +xt_hdc_device::xt_hdc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, XT_HDC, "Generic PC-XT Fixed Disk Controller", tag, owner, clock, "xt_hdc", __FILE__), + m_irq_handler(*this), + m_drq_handler(*this) +{ + m_type = STANDARD; +} + +xt_hdc_device::xt_hdc_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + m_irq_handler(*this), + m_drq_handler(*this) +{ +} + +ec1841_device::ec1841_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + xt_hdc_device(mconfig, EC1841_HDC, "EC1841 Fixed Disk Controller", tag, owner, clock, "ec1481", __FILE__), + m_irq_handler(*this), + m_drq_handler(*this) +{ + m_type = EC1841; +} + +st11m_device::st11m_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + xt_hdc_device(mconfig, EC1841_HDC, "Seagate ST11M Fixed Disk Controller", tag, owner, clock, "st11m", __FILE__), + m_irq_handler(*this), + m_drq_handler(*this) +{ + m_type = ST11M; +} + +void xt_hdc_device::device_start() +{ + buffer.resize(256*512); // maximum possible transfer + timer = timer_alloc(); + m_irq_handler.resolve_safe(); + m_drq_handler.resolve_safe(); +} + +void xt_hdc_device::device_reset() +{ + drv = 0; + data_cnt = 0; + buffer_ptr = NULL; + hdc_control = 0; + for (int i = 0; i < 2; i++) + { + cylinders[i] = 612; + rwc[i] = 613; + wp[i] = 613; + heads[i] = 4; + ecc[i] = 11; + + /* indexes */ + cylinder[i] = 0; + head[i] = 0; + sector[i] = 0; + sector_cnt[i] = 0; + control[i] = 0; + } + + csb = 0; + status = 0; + error = 0; +} + +hard_disk_file *xt_hdc_device::pc_hdc_file(int id) +{ + harddisk_image_device *img = NULL; + switch( id ) + { + case 0: + img = dynamic_cast(machine().device(subtag("primary").c_str())); + break; + case 1: + img = dynamic_cast(machine().device(subtag("slave").c_str())); + break; + } + if ( img == NULL ) + return NULL; + + if (!img->exists()) + return NULL; + + return img->get_hard_disk_file(); +} + +void xt_hdc_device::pc_hdc_result(int set_error_info) +{ + if ( ( hdc_control & 0x02 )) + { + // dip switch selected IRQ 5 or 2 + m_irq_handler(1); + } + + if (LOG_HDC_STATUS) + logerror("pc_hdc_result(): $%02x to $%04x\n", csb, data_cnt); + + buffer[data_cnt++] = csb; + + if (set_error_info && ( csb & CSB_ERROR ) ) + { + buffer[data_cnt++] = error; + if (error & 0x80) + { + buffer[data_cnt++] = (drv << 5) | head[drv]; + buffer[data_cnt++] = ((cylinder[drv] >> 2) & 0xc0) | sector[drv]; + buffer[data_cnt++] = cylinder[drv] & 0xff; + + if (LOG_HDC_STATUS) + { + logerror("pc_hdc_result(): result [%02x %02x %02x %02x]\n", + buffer[data_cnt-4], buffer[data_cnt-3], buffer[data_cnt-2], buffer[data_cnt-1]); + } + } + else + { + if (LOG_HDC_STATUS) + logerror("pc_hdc_result(): result [%02x]\n", buffer[data_cnt-1]); + } + } + status |= STA_INTERRUPT | STA_INPUT | STA_REQUEST | STA_COMMAND | STA_READY; +} + + + +int xt_hdc_device::no_dma(void) +{ + return (hdc_control & CTL_DMA) == 0; +} + + + +int xt_hdc_device::get_lbasector() +{ + hard_disk_info *info; + hard_disk_file *file; + int lbasector; + + file = pc_hdc_file(drv); + info = hard_disk_get_info(file); + + lbasector = cylinder[drv]; + lbasector *= info->heads; + lbasector += head[drv]; + lbasector *= info->sectors; + lbasector += sector[drv]; + return lbasector; +} + +/******************************************************************** + * + * Read a number of sectors to the address set up for DMA chan #3 + * + ********************************************************************/ + +/* the following crap is an abomination; it is a relic of the old crappy DMA + * implementation that threw the idea of "emulating the hardware" to the wind + */ + +int xt_hdc_device::dack_r() +{ + UINT8 result; + hard_disk_info *info; + hard_disk_file *file; + + file = pc_hdc_file(drv); + if (!file) + return 0; + info = hard_disk_get_info(file); + + if (hdcdma_read == 0) + { + hard_disk_read(file, get_lbasector(), hdcdma_data); + hdcdma_read = 512; + hdcdma_size -= 512; + hdcdma_src = hdcdma_data; + sector[drv]++; + } + + result = *(hdcdma_src++); + + if( --hdcdma_read == 0 ) + { + /* end of cylinder ? */ + if (sector[drv] >= info->sectors) + { + sector[drv] = 0; + if (++head[drv] >= info->heads) /* beyond heads? */ + { + head[drv] = 0; /* reset head */ + cylinder[drv]++; /* next cylinder */ + } + } + } + + if (!no_dma()) + { + m_drq_handler((hdcdma_read || hdcdma_size ) ? 1 : 0); + if(!(hdcdma_read || hdcdma_size)) pc_hdc_result(0); + } + + return result; +} + + + +void xt_hdc_device::dack_w(int data) +{ + hard_disk_info *info; + hard_disk_file *file; + + file = pc_hdc_file(drv); + if (!file) + return; + info = hard_disk_get_info(file); + + *(hdcdma_dst++) = data; + + if( --hdcdma_write == 0 ) + { + hard_disk_write(file, get_lbasector(), hdcdma_data); + hdcdma_write = 512; + hdcdma_size -= 512; + + /* end of cylinder ? */ + if( ++sector[drv] >= info->sectors ) + { + sector[drv] = 0; + if (++head[drv] >= info->heads) /* beyond heads? */ + { + head[drv] = 0; /* reset head */ + cylinder[drv]++; /* next cylinder */ + } + } + hdcdma_dst = hdcdma_data; + } + + if (!no_dma()) + { + m_drq_handler(hdcdma_size ? 1 : 0); + if(!hdcdma_size) pc_hdc_result(1); + } +} + + + +void xt_hdc_device::dack_ws(int data) +{ + *(hdcdma_dst++) = data; + + if( --hdcdma_write == 0 ) + { + hdcdma_write = 512; + hdcdma_size -= 512; + hdcdma_dst = hdcdma_data; + } + + if (!no_dma()) + { + m_drq_handler(hdcdma_size ? 1 : 0); + if(!hdcdma_size) pc_hdc_result(1); + } +} + + + +void xt_hdc_device::execute_read() +{ + hard_disk_file *disk = NULL; + int size = sector_cnt[drv] * 512; + int read_ = 0; + + if(sector_cnt[drv] == 0) + size = 256 * 512; + + disk = pc_hdc_file(drv); + if (!disk) + return; + + status |= STA_READY; // ready to recieve data + status &= ~STA_INPUT; + status &= ~STA_COMMAND; + + hdcdma_src = hdcdma_data; + hdcdma_read = read_; + hdcdma_size = size; + + if(!no_dma()) + { + m_drq_handler(1); + if(!hdcdma_size) pc_hdc_result(0); + } +} + + + +void xt_hdc_device::execute_write() +{ + hard_disk_file *disk = NULL; + int size = sector_cnt[drv] * 512; + int write_ = 512; + + if(sector_cnt[drv] == 0) + size = 256 * 512; + + disk = pc_hdc_file(drv); + if (!disk) + return; + + status |= STA_READY; // ready to recieve data + status |= STA_INPUT; + status &= ~STA_COMMAND; + + hdcdma_dst = hdcdma_data; + hdcdma_write = write_; + hdcdma_size = size; + + if (!no_dma()) + { + m_drq_handler(1); + } +} + + + +void xt_hdc_device::execute_writesbuff() +{ + hdcdma_dst = hdcdma_data; + hdcdma_write = 512; + hdcdma_size = 512; + + status |= STA_READY; // ready to recieve data + status |= STA_INPUT; + status &= ~STA_COMMAND; + + if (!no_dma()) + { + m_drq_handler(1); + } +} + + + +void xt_hdc_device::get_drive() +{ + drv = (buffer[1] >> 5) & 1; + csb = (drv) ? CSB_LUN : 0x00; +} + + + +void xt_hdc_device::get_chsn() +{ + head[drv] = buffer[1] & 0x1f; + sector[drv] = buffer[2] & 0x3f; + cylinder[drv] = (buffer[2] & 0xc0) << 2; + cylinder[drv] |= buffer[3]; + sector_cnt[drv] = buffer[4]; + control[drv] = buffer[5]; /* 7: no retry, 6: no ecc retry, 210: step rate */ + + error = 0x80; /* a potential error has C/H/S/N info */ +} + +int xt_hdc_device::test_ready() +{ + if( !pc_hdc_file(drv) ) + { + csb |= CSB_ERROR; + error |= 0x04; /* drive not ready */ + return 0; + } + return 1; +} + +void xt_hdc_device::command() +{ + int set_error_info = 1; + int old_error = error; /* Previous error data is needed for CMD_SENSE */ + const char *command_name; + + csb = 0x00; + error = 0; + + buffer_ptr = &buffer[0]; + + get_drive(); + data_cnt = 0; + + if (LOG_HDC_STATUS) + { + command_name = hdc_command_names[m_current_cmd] ? hdc_command_names[m_current_cmd] : "Unknown"; + logerror("%s pc_hdc_command(): Executing command; cmd=0x%02x (%s) drv=%d\n", + machine().describe_context(), m_current_cmd, command_name, drv); + } + + switch (m_current_cmd) + { + case CMD_TESTREADY: + set_error_info = 0; + test_ready(); + if(no_dma()) pc_hdc_result(set_error_info); + break; + case CMD_SENSE: + /* Perform error code translation. This may need to be expanded in the future. */ + buffer[data_cnt++] = ( old_error & 0xC0 ) | ( ( old_error & 0x04 ) ? 0x04 : 0x00 ) ; + buffer[data_cnt++] = (drv << 5) | head[drv]; + buffer[data_cnt++] = ((cylinder[drv] >> 2) & 0xc0) | sector[drv]; + buffer[data_cnt++] = cylinder[drv] & 0xff; + set_error_info = 0; + if(no_dma()) pc_hdc_result(set_error_info); + break; + case CMD_RECALIBRATE: + get_chsn(); + if(no_dma()) pc_hdc_result(set_error_info); + break; + + case CMD_FORMATDRV: + case CMD_VERIFY: + case CMD_FORMATTRK: + case CMD_FORMATBAD: + case CMD_SEEK: + case CMD_DRIVEDIAG: + get_chsn(); + test_ready(); + if(no_dma()) pc_hdc_result(set_error_info); + break; + + case CMD_READ: + case CMD_READLONG: + get_chsn(); + + if (LOG_HDC_STATUS) + { + logerror("%s hdc read D:%d C:%d H:%d S:%d N:%d CTL:$%02x\n", + machine().describe_context(), drv, cylinder[drv], head[drv], sector[drv], sector_cnt[drv], control[drv]); + } + + if (test_ready()) + execute_read(); + else + pc_hdc_result(1); + set_error_info = 0; + break; + + case CMD_WRITE: + case CMD_WRITELONG: + get_chsn(); + + if (LOG_HDC_STATUS) + { + logerror("%s hdc write D:%d C:%d H:%d S:%d N:%d CTL:$%02x\n", + machine().describe_context(), drv, cylinder[drv], head[drv], sector[drv], sector_cnt[drv], control[drv]); + } + + if (test_ready()) + execute_write(); + break; + + case CMD_WRITESBUFF: + if (LOG_HDC_STATUS) + { + logerror("%s hdc write sector buffer\n", machine().describe_context()); + } + + execute_writesbuff(); + break; + + case CMD_SETPARAM: + get_chsn(); + cylinders[drv] = ((buffer[6]&3)<<8) | buffer[7]; + heads[drv] = buffer[8] & 0x1f; + rwc[drv] = ((buffer[9]&3)<<8) | buffer[10]; + wp[drv] = ((buffer[11]&3)<<8) | buffer[12]; + ecc[drv] = buffer[13]; + if(no_dma()) pc_hdc_result(set_error_info); + break; + + case CMD_GETECC: + buffer[data_cnt++] = ecc[drv]; + if(no_dma()) pc_hdc_result(set_error_info); + break; + + case CMD_READSBUFF: + case CMD_RAMDIAG: + case CMD_INTERNDIAG: + if(no_dma()) pc_hdc_result(set_error_info); + break; + } +} + +void xt_hdc_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + command(); +} + + +/* Command format + * Bits Description + * 7 0 + * xxxxxxxx command + * dddhhhhh drive / head + * ccssssss cylinder h / sector + * cccccccc cylinder l + * nnnnnnnn count + * xxxxxxxx control + * + * Command format extra for set drive characteristics + * 000000cc cylinders h + * cccccccc cylinders l + * 000hhhhh heads + * 000000cc reduced write h + * cccccccc reduced write l + * 000000cc write precomp h + * cccccccc write precomp l + * eeeeeeee ecc + */ +void xt_hdc_device::data_w(int data) +{ + if(!(status & STA_COMMAND) && m_current_cmd != CMD_SETPARAM) + { + if (LOG_HDC_DATA) + logerror("hdc_data_w PIO $%02x (%i) (%s): \n", data,data_cnt,hdc_command_names[m_current_cmd] ? hdc_command_names[m_current_cmd] : "Unknown"); + // PIO data transfer + buffer[data_cnt++] = data; + if(data_cnt >= hdcdma_size) + { + data_cnt = 0; + // write to disk + do + { + if(m_current_cmd == CMD_WRITESBUFF) + dack_ws(buffer[data_cnt++]); + else + dack_w(buffer[data_cnt++]); + } + while (hdcdma_size); + data_cnt = 0; + pc_hdc_result(1); + } + return; + } + + if( data_cnt == 0 ) + { + buffer_ptr = &buffer[0]; + m_current_cmd = data; + data_cnt = 6; /* expect 6 bytes including this one */ + status &= ~STA_READY; + status &= ~STA_INPUT; + switch (data) + { + case CMD_SETPARAM: + data_cnt += 8; + break; + + case CMD_TESTREADY: + case CMD_RECALIBRATE: + case CMD_SENSE: + case CMD_FORMATDRV: + case CMD_VERIFY: + case CMD_FORMATTRK: + case CMD_FORMATBAD: + case CMD_READ: + case CMD_WRITE: + case CMD_SEEK: + case CMD_GETECC: + case CMD_READSBUFF: + case CMD_WRITESBUFF: + case CMD_RAMDIAG: + case CMD_DRIVEDIAG: + case CMD_INTERNDIAG: + case CMD_READLONG: + case CMD_WRITELONG: + break; + + default: + data_cnt = 0; + status |= STA_INPUT; + csb |= CSB_ERROR | 0x20; /* unknown command */ + pc_hdc_result(1); + break; + } + if( data_cnt ) + status |= STA_REQUEST; + } + + if (data_cnt) + { + if (LOG_HDC_DATA) + logerror("hdc_data_w $%02x (%i) (%s): \n", data,data_cnt,hdc_command_names[m_current_cmd] ? hdc_command_names[m_current_cmd] : "Unknown"); + + *buffer_ptr++ = data; + // XXX ec1841 wants this + if (m_current_cmd == CMD_SETPARAM && data_cnt == 9 && (m_type == EC1841)) { + status &= ~STA_READY; + } else { + status |= STA_READY; + if(m_current_cmd == CMD_SETPARAM && data_cnt == 9) // some controllers want geometry info as data, not as a command (true for the Seagate ST11M?) + status &= ~STA_COMMAND; + } + if (--data_cnt == 0) + { + if (LOG_HDC_STATUS) + logerror("%s pc_hdc_data_w(): Launching command\n", machine().describe_context()); + + status &= ~STA_COMMAND; + status &= ~STA_REQUEST; + status &= ~STA_READY; + status &= ~STA_INPUT; + timer->adjust(attotime::from_msec(1),0); + } + } +} + + + +void xt_hdc_device::reset_w(int data) +{ + cylinder[0] = cylinder[1] = 0; + head[0] = head[1] = 0; + sector[0] = sector[1] = 0; + csb = 0; + status = STA_COMMAND | STA_READY; + memset(&buffer[0], 0, buffer.size()); + buffer_ptr = &buffer[0]; + data_cnt = 0; +} + + + +void xt_hdc_device::select_w(int data) +{ + status &= ~STA_INTERRUPT; + status |= STA_SELECT; +} + + + +void xt_hdc_device::control_w(int data) +{ + if (LOG_HDC_STATUS) + logerror("%s: pc_hdc_control_w(): control write %d\n", machine().describe_context(), data); + + hdc_control = data; + + if (!(hdc_control & 0x02)) + { + m_irq_handler(0); + } +} + + + +UINT8 xt_hdc_device::data_r() +{ + UINT8 data = 0xff; + + if(!(status & STA_COMMAND) && (m_current_cmd == CMD_READ || m_current_cmd == CMD_READLONG || m_current_cmd == CMD_READSBUFF)) + { + // PIO data transfer + if(data_cnt == 0) + { + do + { + buffer[data_cnt++] = dack_r(); + } while (hdcdma_read); + data_cnt = 0; + } + data = buffer[data_cnt++]; + if(data_cnt >= ((sector_cnt[drv] * 512) ? (sector_cnt[drv] * 512) : (256 * 512))) + { + data_cnt = 0; + pc_hdc_result(1); + } + if (LOG_HDC_DATA) + logerror("hdc_data_r PIO $%02x (%i): \n", data,data_cnt); + return data; + } + + if( data_cnt ) + { + data = *buffer_ptr++; + status &= ~STA_INTERRUPT; + if( --data_cnt == 0 ) + { + status &= ~STA_INPUT; + status &= ~STA_REQUEST; + status &= ~STA_SELECT; + status |= STA_COMMAND; + } + if (LOG_HDC_DATA) + logerror("hdc_data_r $%02x (%i): \n", data,data_cnt); + } + return data; +} + + + +UINT8 xt_hdc_device::status_r() +{ + return status; +} + +void xt_hdc_device::set_ready() +{ + status |= STA_READY; // XXX +} + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type ISA8_HDC = &device_creator; +const device_type ISA8_HDC_EC1841 = &device_creator; + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor isa8_hdc_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( xt_hdc_config ); +} + +machine_config_constructor isa8_hdc_ec1841_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( ec1841_hdc_config ); +} + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *isa8_hdc_device::device_rom_region() const +{ + return ROM_NAME( hdc ); +} + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor isa8_hdc_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( isa_hdc ); +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// isa8_hdc_device - constructor +//------------------------------------------------- + +isa8_hdc_device::isa8_hdc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, ISA8_HDC, "Fixed Disk Controller Card", tag, owner, clock, "hdc", __FILE__), + device_isa8_card_interface(mconfig, *this), + m_hdc(*this,"hdc") +{ +} + +isa8_hdc_device::isa8_hdc_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_isa8_card_interface(mconfig, *this), + m_hdc(*this,"hdc") +{ +} + +isa8_hdc_ec1841_device::isa8_hdc_ec1841_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + isa8_hdc_device( mconfig, ISA8_HDC_EC1841, "EC1841 HDC", tag, owner, clock, "hdc_ec1841", __FILE__), + m_hdc(*this,"hdc") +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void isa8_hdc_device::device_start() +{ + set_isa_device(); + m_isa->install_device(0x0320, 0x0323, 0, 0, read8_delegate( FUNC(isa8_hdc_device::pc_hdc_r), this ), write8_delegate( FUNC(isa8_hdc_device::pc_hdc_w), this ) ); + m_isa->set_dma_channel(3, this, FALSE); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void isa8_hdc_device::device_reset() +{ + dip = ioport("HDD")->read(); + + if (ioport("ROM")->read() == 1) + m_isa->install_rom(this, 0xc8000, 0xc9fff, 0, 0, "hdc", "hdc"); +} + +/************************************************************************* + * + * HDC + * hard disk controller + * + *************************************************************************/ +READ8_MEMBER( isa8_hdc_device::pc_hdc_r ) +{ + UINT8 data = 0xff; + + switch( offset ) + { + case 0: data = m_hdc->data_r(); break; + case 1: data = m_hdc->status_r(); break; + case 2: data = pc_hdc_dipswitch_r(); break; + case 3: break; + } + + if (LOG_HDC_CALL) + logerror("%s pc_hdc_r(): offs=%d result=0x%02x\n", machine().describe_context(), offset, data); + + return data; +} + +WRITE8_MEMBER( isa8_hdc_device::pc_hdc_w ) +{ + if (LOG_HDC_CALL) + logerror("%s pc_hdc_w(): offs=%d data=0x%02x\n", machine().describe_context(), offset, data); + + switch( offset ) + { + case 0: m_hdc->data_w(data); break; + case 1: m_hdc->reset_w(data); break; + case 2: m_hdc->select_w(data); break; + case 3: m_hdc->control_w(data); break; + } +} + + +UINT8 isa8_hdc_device::dack_r(int line) +{ + return m_hdc->dack_r(); +} + +void isa8_hdc_device::dack_w(int line,UINT8 data) +{ + if (m_hdc->get_command() == CMD_WRITESBUFF) + m_hdc->dack_ws(data); + else + m_hdc->dack_w(data); +} + +/* + Dipswitch configuration + + + Tandon/Western Digital Fixed Disk Controller + bit0-1 : Determine disk size(?) + Causes geometry data to be read from c8043, c8053, c8063, c8073 (?) + 00 - 40 Mbytes + 01 - 30 Mbytes + 10 - 10 Mbytes + 11 - 20 Mbytes + bit2-7 : unknown + + */ + +UINT8 isa8_hdc_device::pc_hdc_dipswitch_r() +{ + m_hdc->set_ready(); + if (LOG_HDC_STATUS) + logerror("%s: pc_hdc_dipswitch_r: status $%02X\n", machine().describe_context(), m_hdc->status_r()); + return dip; +} + +WRITE_LINE_MEMBER( isa8_hdc_device::irq_w ) +{ + if (BIT(dip, 6)) + m_isa->irq5_w(state); + else + m_isa->irq2_w(state); +} + +WRITE_LINE_MEMBER( isa8_hdc_device::drq_w ) +{ + m_isa->drq3_w(state); +} diff --git a/src/devices/bus/isa/hdc.h b/src/devices/bus/isa/hdc.h new file mode 100644 index 00000000000..21a47707e69 --- /dev/null +++ b/src/devices/bus/isa/hdc.h @@ -0,0 +1,186 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +/********************************************************************** + + ISA 8 bit XT Hard Disk Controller + +**********************************************************************/ +#pragma once + +#ifndef ISA_HDC_H +#define ISA_HDC_H + +#include "emu.h" +#include "isa.h" +#include "imagedev/harddriv.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// XT HD controller device + +#define MCFG_XTHDC_IRQ_HANDLER(_devcb) \ + devcb = &xt_hdc_device::set_irq_handler(*device, DEVCB_##_devcb); + +#define MCFG_XTHDC_DRQ_HANDLER(_devcb) \ + devcb = &xt_hdc_device::set_drq_handler(*device, DEVCB_##_devcb); + +class xt_hdc_device : + public device_t +{ +public: + // construction/destruction + xt_hdc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + xt_hdc_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + template static devcb_base &set_irq_handler(device_t &device, _Object object) { return downcast(device).m_irq_handler.set_callback(object); } + template static devcb_base &set_drq_handler(device_t &device, _Object object) { return downcast(device).m_drq_handler.set_callback(object); } + + int dack_r(); + void dack_w(int data); + void dack_ws(int data); + + virtual void command(); + void data_w(int data); + void reset_w(int data); + void select_w(int data); + void control_w(int data); + UINT8 data_r(); + UINT8 status_r(); + void set_ready(); + UINT8 get_command() { return buffer[0]; } + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + hard_disk_file *pc_hdc_file(int id); + void pc_hdc_result(int set_error_info); + int no_dma(void); + int get_lbasector(); + void execute_read(); + void execute_write(); + void execute_writesbuff(); + void get_drive(); + void get_chsn(); + int test_ready(); + + dynamic_buffer buffer; /* data buffer */ + UINT8 *buffer_ptr; /* data pointer */ + int csb; /* command status byte */ + int status; /* drive status */ + int error; /* error code */ + + enum { + STANDARD, + EC1841, + ST11M + }; + int m_type; + UINT8 m_current_cmd; + devcb_write_line m_irq_handler; + devcb_write_line m_drq_handler; + +private: + int drv; /* 0 master, 1 slave drive */ + int cylinders[2]; /* number of cylinders */ + int rwc[2]; /* reduced write current from cyl */ + int wp[2]; /* write precompensation from cyl */ + int heads[2]; /* heads */ + int ecc[2]; /* ECC bytes */ + + /* indexes */ + int cylinder[2]; /* current cylinder */ + int head[2]; /* current head */ + int sector[2]; /* current sector */ + int sector_cnt[2]; /* sector count */ + int control[2]; /* control */ + + emu_timer *timer; + + int data_cnt; /* data count */ + UINT8 hdc_control; + + UINT8 hdcdma_data[512]; + UINT8 *hdcdma_src; + UINT8 *hdcdma_dst; + int hdcdma_read; + int hdcdma_write; + int hdcdma_size; +}; + +class ec1841_device : public xt_hdc_device +{ +public: + ec1841_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +protected: + devcb_write_line m_irq_handler; + devcb_write_line m_drq_handler; +}; + +class st11m_device : public xt_hdc_device +{ +public: + st11m_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + devcb_write_line m_irq_handler; + devcb_write_line m_drq_handler; +}; + +extern const device_type XT_HDC; +extern const device_type EC1841_HDC; +extern const device_type ST11M_HDC; + +// ======================> isa8_hdc_device + +class isa8_hdc_device : + public device_t, + public device_isa8_card_interface +{ +public: + // construction/destruction + isa8_hdc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + isa8_hdc_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + DECLARE_READ8_MEMBER(pc_hdc_r); + DECLARE_WRITE8_MEMBER(pc_hdc_w); + DECLARE_WRITE_LINE_MEMBER(irq_w); + DECLARE_WRITE_LINE_MEMBER(drq_w); + required_device m_hdc; + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual const rom_entry *device_rom_region() const; + virtual ioport_constructor device_input_ports() const; +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); +public: + virtual UINT8 dack_r(int line); + virtual void dack_w(int line,UINT8 data); + UINT8 pc_hdc_dipswitch_r(); + + int dip; /* dip switches */ +}; + + +class isa8_hdc_ec1841_device : public isa8_hdc_device +{ +public: + isa8_hdc_ec1841_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + + required_device m_hdc; +}; + +// device type definition +extern const device_type ISA8_HDC; +extern const device_type ISA8_HDC_EC1841; + +#endif /* ISA_HDC_H */ diff --git a/src/devices/bus/isa/ibm_mfc.c b/src/devices/bus/isa/ibm_mfc.c new file mode 100644 index 00000000000..293162aa70a --- /dev/null +++ b/src/devices/bus/isa/ibm_mfc.c @@ -0,0 +1,484 @@ +// license:BSD-3-Clause +// copyright-holders:Philip Bennett +/*************************************************************************** + + ISA 8 bit IBM PC Music Feature Card + + TODO: + - YM-2164 + - MIDI + - IRQ/base address selection + + Notes: + - Some software does not function correctly at higher CPU speeds + (e.g. the Sierra games and Yamaha Compose/PlayRec) + +***************************************************************************/ + + +#include "emu.h" +#include "ibm_mfc.h" +#include "cpu/z80/z80.h" +#include "machine/clock.h" +#include "machine/pit8253.h" + + +//------------------------------------------------- +// Constants +//------------------------------------------------- + +#define TCR_TAC 0x01 +#define TCR_TBC 0x02 +#define TCR_TAE 0x04 +#define TCR_TBE 0x08 +#define TCR_EXT8 0x10 +#define TCR_TMSK 0x40 +#define TCR_IBE 0x80 + +#define TSR_TAS 0x01 +#define TSR_TBS 0x02 +#define TSR_TCS 0x80 + +enum +{ + PC_IRQ_TIMERA, + PC_IRQ_TIMERB, + PC_IRQ_RXRDY, + PC_IRQ_TXRDY +}; + +enum +{ + Z80_IRQ_YM, + Z80_IRQ_RXRDY, + Z80_IRQ_TXRDY, + Z80_IRQ_MIDI_RXRDY, + Z80_IRQ_MIDI_TXRDY +}; + + +//------------------------------------------------- +// Globals +//------------------------------------------------- + +const device_type ISA8_IBM_MFC = &device_creator; + + +//------------------------------------------------- +// Interrupt handling +//------------------------------------------------- + +void isa8_ibm_mfc_device::set_pc_interrupt(int src, int state) +{ + if (state) + m_pc_irq_state |= 1 << src; + else + m_pc_irq_state &= ~(1 << src); + + update_pc_interrupts(); +} + +void isa8_ibm_mfc_device::update_pc_interrupts(void) +{ + // IRQs enabled? + if (m_tcr & TCR_IBE) + { + // IRQs unmasked? + if (m_tcr & TCR_TMSK) + { + m_isa->irq3_w(m_pc_irq_state ? ASSERT_LINE : CLEAR_LINE); + } + } +} + +void isa8_ibm_mfc_device::set_z80_interrupt(int src, int state) +{ + if (state) + m_z80_irq_state |= 1 << src; + else + m_z80_irq_state &= ~(1 << src); + + update_z80_interrupts(); +} + +void isa8_ibm_mfc_device::update_z80_interrupts(void) +{ + m_cpu->set_input_line(0, m_z80_irq_state ? ASSERT_LINE : CLEAR_LINE); +} + + +//------------------------------------------------- +// Z80 memory map +//------------------------------------------------- + +static ADDRESS_MAP_START( prg_map, AS_PROGRAM, 8, isa8_ibm_mfc_device ) + AM_RANGE(0x0000, 0x7fff) AM_ROM + AM_RANGE(0x8000, 0x8000) AM_RAM // Unknown - tested on startup + AM_RANGE(0xbfff, 0xbfff) AM_RAM // Unknown - tested on startup + AM_RANGE(0xc000, 0xdfff) AM_RAM + AM_RANGE(0xe000, 0xffff) AM_RAM +ADDRESS_MAP_END + +static ADDRESS_MAP_START( io_map, AS_IO, 8, isa8_ibm_mfc_device ) + ADDRESS_MAP_UNMAP_HIGH + ADDRESS_MAP_GLOBAL_MASK(0xff) + AM_RANGE(0x00, 0x01) AM_DEVREADWRITE("ym2151", ym2151_device, read, write) + AM_RANGE(0x10, 0x10) AM_DEVREADWRITE("d71051", i8251_device, data_r, data_w) + AM_RANGE(0x11, 0x11) AM_DEVREADWRITE("d71051", i8251_device, status_r, control_w) + AM_RANGE(0x20, 0x23) AM_DEVREADWRITE("d71055c_1", i8255_device, read, write) +ADDRESS_MAP_END + + +//------------------------------------------------- +// Jumpers and DIP switches +//------------------------------------------------- + +static INPUT_PORTS_START( ibm_mfc ) + PORT_START("J1") + PORT_DIPNAME( 0x07, 0x03, "IBM MFC J1: IRQ" ) + PORT_DIPSETTING( 0x02, "2" ) + PORT_DIPSETTING( 0x03, "3" ) + PORT_DIPSETTING( 0x04, "4" ) + PORT_DIPSETTING( 0x05, "5" ) + PORT_DIPSETTING( 0x06, "6" ) + PORT_DIPSETTING( 0x07, "7" ) + + PORT_START("SW1") + PORT_DIPNAME( 0x03, 0x00, "IBM MFC SW1: Base Address" ) + PORT_DIPSETTING( 0x00, "2A00" ) + PORT_DIPSETTING( 0x01, "2A10" ) + PORT_DIPSETTING( 0x02, "2A20" ) + PORT_DIPSETTING( 0x03, "2A30" ) +INPUT_PORTS_END + +//------------------------------------------------- +// D71055C PPI (PC) +//------------------------------------------------- + +READ8_MEMBER( isa8_ibm_mfc_device::ppi0_i_a ) +{ + // Read data from the Z80 PIU + return m_d71055c_1->pa_r(); +} + +WRITE8_MEMBER( isa8_ibm_mfc_device::ppi0_o_b ) +{ + // Write data to the Z80 PIU - no action required +} + +WRITE8_MEMBER( isa8_ibm_mfc_device::ppi0_o_c ) +{ + // PC Port B /OBF (C1) -> Z80 Port B /STB (C2) + m_d71055c_1->pc2_w(BIT(data, 1)); + + // PC Port A IBF (C5) -> Z80 Port A /ACK (C6) +#if 0 // TODO + m_d71055c_1->pc6_w(!BIT(data, 5)); +#else + if (!BIT(data, 5) && BIT(m_pc_ppi_c, 5)) + m_d71055c_1->pc6_w(0); +#endif + + // Bit 0 (INTRB) is TxRDY + set_pc_interrupt(PC_IRQ_TXRDY, BIT(data, 0)); + + // Bit 3 (INTRA) is RxRDY + set_pc_interrupt(PC_IRQ_RXRDY, BIT(data, 3)); + + m_pc_ppi_c = data; +} + +READ8_MEMBER( isa8_ibm_mfc_device::ppi0_i_c ) +{ + // Receive data bit 8 + return BIT(m_z80_ppi_c, 5) << 7; +} + +//------------------------------------------------- +// D71055C PPI (Z80) +//------------------------------------------------- + +WRITE8_MEMBER( isa8_ibm_mfc_device::ppi1_o_a ) +{ + // Write data to the PC PIU - no action required +} + +READ8_MEMBER( isa8_ibm_mfc_device::ppi1_i_b ) +{ + // Read data from the PC PIU + return m_d71055c_0->pb_r(); +} + +WRITE8_MEMBER( isa8_ibm_mfc_device::ppi1_o_c ) +{ + // PortA /OBF (C7) -> PortA /STB (C2) + m_d71055c_0->pc4_w(BIT(data, 7)); + + // PortB IBF (C1) -> PortB /ACK (C2) +#if 0 // TODO + m_d71055c_0->pc2_w(!BIT(data, 1)); +#else + if (!BIT(data, 1) && BIT(m_z80_ppi_c, 1)) + m_d71055c_0->pc2_w(0); +#endif + + set_z80_interrupt(Z80_IRQ_TXRDY, BIT(data, 3)); + set_z80_interrupt(Z80_IRQ_RXRDY, BIT(data, 0)); + + m_z80_ppi_c = data; +} + +//------------------------------------------------- +// D8253 PIT +//------------------------------------------------- + +WRITE_LINE_MEMBER( isa8_ibm_mfc_device::d8253_out0 ) +{ + if (m_tcr & TCR_TAE) + set_pc_interrupt(PC_IRQ_TIMERA, 1); +} + +WRITE_LINE_MEMBER( isa8_ibm_mfc_device::d8253_out1 ) +{ + if (m_tcr & TCR_TBE) + set_pc_interrupt(PC_IRQ_TIMERB, 1); +} + + +//------------------------------------------------- +// uPD71051 USART +//------------------------------------------------- + +WRITE_LINE_MEMBER( isa8_ibm_mfc_device::write_usart_clock ) +{ + m_d71051->write_txc(state); + m_d71051->write_rxc(state); +} + +//------------------------------------------------- +// YM-2164 +//------------------------------------------------- + + +WRITE_LINE_MEMBER(isa8_ibm_mfc_device::ibm_mfc_ym_irq) +{ + set_z80_interrupt(Z80_IRQ_YM, state); +} + + +//------------------------------------------------- +// Machine config +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( ibm_mfc ) + MCFG_CPU_ADD("ibm_mfc", Z80, XTAL_11_8MHz / 2) + MCFG_CPU_PROGRAM_MAP(prg_map) + MCFG_CPU_IO_MAP(io_map) + + MCFG_DEVICE_ADD("d71055c_0", I8255, 0) + MCFG_I8255_IN_PORTA_CB(READ8(isa8_ibm_mfc_device, ppi0_i_a)) + MCFG_I8255_OUT_PORTB_CB(WRITE8(isa8_ibm_mfc_device, ppi0_o_b)) + MCFG_I8255_IN_PORTC_CB(READ8(isa8_ibm_mfc_device, ppi0_i_c)) + MCFG_I8255_OUT_PORTC_CB(WRITE8(isa8_ibm_mfc_device, ppi0_o_c)) + + MCFG_DEVICE_ADD("d71055c_1", I8255, 0) + MCFG_I8255_OUT_PORTA_CB(WRITE8(isa8_ibm_mfc_device, ppi1_o_a)) + MCFG_I8255_IN_PORTB_CB(READ8(isa8_ibm_mfc_device, ppi1_i_b)) + MCFG_I8255_OUT_PORTC_CB(WRITE8(isa8_ibm_mfc_device, ppi1_o_c)) + + MCFG_DEVICE_ADD("d71051", I8251, 0) + + MCFG_DEVICE_ADD("usart_clock", CLOCK, XTAL_4MHz / 8) // 500KHz + MCFG_CLOCK_SIGNAL_HANDLER(WRITELINE(isa8_ibm_mfc_device, write_usart_clock)) + + MCFG_DEVICE_ADD("d8253", PIT8253, 0) + MCFG_PIT8253_CLK0(XTAL_4MHz / 8) + MCFG_PIT8253_OUT0_HANDLER(WRITELINE(isa8_ibm_mfc_device, d8253_out0)) + MCFG_PIT8253_CLK1(0) + MCFG_PIT8253_OUT1_HANDLER(WRITELINE(isa8_ibm_mfc_device, d8253_out1)) + MCFG_PIT8253_CLK2(XTAL_4MHz / 2) + MCFG_PIT8253_OUT2_HANDLER(DEVWRITELINE("d8253", pit8253_device, write_clk1)) + + MCFG_SPEAKER_STANDARD_STEREO("ymleft", "ymright") + MCFG_YM2151_ADD("ym2151", XTAL_4MHz) + MCFG_YM2151_IRQ_HANDLER(WRITELINE(isa8_ibm_mfc_device, ibm_mfc_ym_irq)) + MCFG_SOUND_ROUTE(0, "ymleft", 1.00) + MCFG_SOUND_ROUTE(1, "ymright", 1.00) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// ISA interface +//------------------------------------------------- + +READ8_MEMBER( isa8_ibm_mfc_device::ibm_mfc_r ) +{ + UINT8 val = 0xff; + + switch (offset) + { + case 0x0: + case 0x1: + case 0x2: + case 0x3: + { + val = m_d71055c_0->read(space, offset); + break; + } + + case 0xc: + case 0xd: + case 0xe: + case 0xf: + { + val = (m_pc_irq_state ? 0x80 : 0) | (m_pc_irq_state & 3); + break; + } + + default: + { + fatalerror("Unhandled IBM MFC read from %d\n", offset); + } + } + + return val; +} + +WRITE8_MEMBER( isa8_ibm_mfc_device::ibm_mfc_w ) +{ + switch (offset) + { + case 0x0: + case 0x1: + case 0x2: + case 0x3: + { + machine().scheduler().boost_interleave(attotime::zero, attotime::from_usec(1000)); + m_d71055c_0->write(space, offset, data); + break; + } + + case 0x4: + case 0x5: + case 0x6: + case 0x7: + { + m_d8253->write(space, offset & 3, data); + break; + } + + case 0x8: + case 0x9: + case 0xa: + case 0xb: + { + m_tcr = data; + + if (~m_tcr & TCR_TAC) + set_pc_interrupt(PC_IRQ_TIMERA, 0); + + if (~m_tcr & TCR_TBC) + set_pc_interrupt(PC_IRQ_TIMERB, 0); + + m_d71051->write_dsr((m_tcr & TCR_EXT8) ? 1 : 0); + + break; + } + + case 0xc: + case 0xd: + case 0xe: + case 0xf: + { + // TSR is read-only but Yamaha software attempts to write to it + break; + } + } +} + + +//------------------------------------------------- +// ROM definition +//------------------------------------------------- + +ROM_START( ibm_mfc ) + ROM_REGION( 0x8000, "ibm_mfc", 0 ) + ROM_LOAD( "xc215 c 0.bin", 0x0000, 0x8000, CRC(28c58a4f) SHA1(e7edf28d20e6c146e3144526c89cd6beea64663b) ) +ROM_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor isa8_ibm_mfc_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( ibm_mfc ); +} + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor isa8_ibm_mfc_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( ibm_mfc ); +} + + +//------------------------------------------------- +// rom_region - return a pointer to the device's +// internal ROM region +//------------------------------------------------- + +const rom_entry *isa8_ibm_mfc_device::device_rom_region() const +{ + return ROM_NAME( ibm_mfc ); +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// isa8_ibm_mfc_device - constructor +//------------------------------------------------- + +isa8_ibm_mfc_device::isa8_ibm_mfc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, ISA8_IBM_MFC, "IBM PC Music Feature Card", tag, owner, clock, "ibm_mfc", __FILE__), + device_isa8_card_interface(mconfig, *this), + m_cpu(*this, "ibm_mfc"), + m_ym2151(*this, "ym2151"), + m_d8253(*this, "d8253"), + m_d71051(*this, "d71051"), + m_d71055c_0(*this, "d71055c_0"), + m_d71055c_1(*this, "d71055c_1") +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void isa8_ibm_mfc_device::device_start() +{ + set_isa_device(); + m_isa->install_device(0x2a20, 0x2a20 + 15, 0, 0, read8_delegate(FUNC(isa8_ibm_mfc_device::ibm_mfc_r), this), write8_delegate(FUNC(isa8_ibm_mfc_device::ibm_mfc_w), this)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void isa8_ibm_mfc_device::device_reset() +{ + m_tcr = 0; + m_d71051->write_dsr(0); + m_pc_irq_state = 0; + m_z80_irq_state = 0; +} diff --git a/src/devices/bus/isa/ibm_mfc.h b/src/devices/bus/isa/ibm_mfc.h new file mode 100644 index 00000000000..51bcace8bd8 --- /dev/null +++ b/src/devices/bus/isa/ibm_mfc.h @@ -0,0 +1,90 @@ +// license:BSD-3-Clause +// copyright-holders:Philip Bennett +/*************************************************************************** + + ISA 8 bit IBM PC Music Feature Card + +***************************************************************************/ + +#pragma once + +#ifndef __ISA_IBM_MUSIC_FEATURE_CARD_H__ +#define __ISA_IBM_MUSIC_FEATURE_CARD_H__ + + +#include "emu.h" +#include "isa.h" +#include "machine/i8255.h" +#include "machine/i8251.h" +#include "machine/pit8253.h" +#include "sound/2151intf.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> isa8_ibm_mfc_device + +class isa8_ibm_mfc_device : public device_t, + public device_isa8_card_interface +{ +public: + // Construction/destruction + isa8_ibm_mfc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + DECLARE_READ8_MEMBER( ppi0_i_a ); + DECLARE_WRITE8_MEMBER( ppi0_o_b ); + DECLARE_READ8_MEMBER( ppi0_i_c ); + DECLARE_WRITE8_MEMBER( ppi0_o_c ); + + DECLARE_WRITE8_MEMBER( ppi1_o_a ); + DECLARE_READ8_MEMBER( ppi1_i_b ); + + DECLARE_WRITE8_MEMBER( ppi1_o_c ); + + DECLARE_READ8_MEMBER( ibm_mfc_r ); + DECLARE_WRITE8_MEMBER( ibm_mfc_w ); + + DECLARE_WRITE_LINE_MEMBER( d8253_out0 ); + DECLARE_WRITE_LINE_MEMBER( d8253_out1 ); + + DECLARE_WRITE_LINE_MEMBER( write_usart_clock ); + + DECLARE_WRITE_LINE_MEMBER( ibm_mfc_ym_irq ); + +protected: + // Device-level overrides + virtual void device_start(); + virtual void device_reset(); + + virtual machine_config_constructor device_mconfig_additions() const; + virtual ioport_constructor device_input_ports() const; + + virtual const rom_entry* device_rom_region() const; + +private: + void set_z80_interrupt(int src, int state); + void set_pc_interrupt(int src, int state); + void update_pc_interrupts(void); + void update_z80_interrupts(void); + + UINT8 m_tcr; + UINT8 m_pc_ppi_c; + UINT8 m_z80_ppi_c; + + UINT8 m_pc_irq_state; + UINT8 m_z80_irq_state; + + required_device m_cpu; + required_device m_ym2151; + required_device m_d8253; + required_device m_d71051; + required_device m_d71055c_0; + required_device m_d71055c_1; +}; + + +// Device type definition +extern const device_type ISA8_IBM_MFC; + +#endif /* __ISA_IBM_MUSIC_FEATURE_CARD_H__ */ diff --git a/src/devices/bus/isa/ide.c b/src/devices/bus/isa/ide.c new file mode 100644 index 00000000000..9215572bb19 --- /dev/null +++ b/src/devices/bus/isa/ide.c @@ -0,0 +1,120 @@ +// license:BSD-3-Clause +// copyright-holders:Miodrag Milanovic +/*************************************************************************** + + ISA 16 bit IDE controller + +***************************************************************************/ + +#include "emu.h" +#include "ide.h" +#include "machine/idectrl.h" +#include "imagedev/harddriv.h" + +READ8_MEMBER(isa16_ide_device::ide16_alt_r ) +{ + return m_ide->read_cs1(space, 6/2, 0xff); +} + +WRITE8_MEMBER(isa16_ide_device::ide16_alt_w ) +{ + m_ide->write_cs1(space, 6/2, data, 0xff); +} + +DEVICE_ADDRESS_MAP_START(map, 16, isa16_ide_device) + AM_RANGE(0x0, 0x7) AM_DEVREADWRITE("ide", ide_controller_device, read_cs0, write_cs0) +ADDRESS_MAP_END + +DEVICE_ADDRESS_MAP_START(alt_map, 8, isa16_ide_device) + AM_RANGE(0x6, 0x6) AM_READWRITE(ide16_alt_r, ide16_alt_w) +ADDRESS_MAP_END + +WRITE_LINE_MEMBER(isa16_ide_device::ide_interrupt) +{ + if (is_primary()) + { + m_isa->irq14_w(state); + } + else + { + m_isa->irq15_w(state); + } +} + +static MACHINE_CONFIG_FRAGMENT( ide ) + MCFG_IDE_CONTROLLER_ADD("ide", ata_devices, "hdd", NULL, false) + MCFG_ATA_INTERFACE_IRQ_HANDLER(WRITELINE(isa16_ide_device, ide_interrupt)) +MACHINE_CONFIG_END + +static INPUT_PORTS_START( ide ) + PORT_START("DSW") + PORT_DIPNAME( 0x01, 0x00, "IDE Configuration") + PORT_DIPSETTING( 0x00, "Primary" ) + PORT_DIPSETTING( 0x01, "Secondary" ) +INPUT_PORTS_END + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type ISA16_IDE = &device_creator; + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor isa16_ide_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( ide ); +} + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor isa16_ide_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( ide ); +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// isa16_ide_device - constructor +//------------------------------------------------- + +isa16_ide_device::isa16_ide_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, ISA16_IDE, "IDE Fixed Drive Adapter", tag, owner, clock, "isa_ide", __FILE__), + device_isa16_card_interface( mconfig, *this ), + m_is_primary(true), + m_ide(*this, "ide") +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void isa16_ide_device::device_start() +{ + set_isa_device(); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void isa16_ide_device::device_reset() +{ + m_is_primary = (ioport("DSW")->read() & 1) ? false : true; + if (m_is_primary) { + m_isa->install_device(0x01f0, 0x01f7, *this, &isa16_ide_device::map, 16); + m_isa->install_device(0x03f0, 0x03f7, *this, &isa16_ide_device::alt_map); + } else { + m_isa->install_device(0x0170, 0x0177, *this, &isa16_ide_device::map, 16); + m_isa->install_device(0x0370, 0x0377, *this, &isa16_ide_device::alt_map); + } +} diff --git a/src/devices/bus/isa/ide.h b/src/devices/bus/isa/ide.h new file mode 100644 index 00000000000..290eee2a153 --- /dev/null +++ b/src/devices/bus/isa/ide.h @@ -0,0 +1,50 @@ +// license:BSD-3-Clause +// copyright-holders:Miodrag Milanovic +#pragma once + +#ifndef __ISA_IDE_H__ +#define __ISA_IDE_H__ + +#include "emu.h" +#include "isa.h" +#include "machine/idectrl.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> isa16_ide_device + +class isa16_ide_device : public device_t, + public device_isa16_card_interface +{ +public: + // construction/destruction + isa16_ide_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual ioport_constructor device_input_ports() const; + + bool is_primary() { return m_is_primary; } + DECLARE_WRITE_LINE_MEMBER(ide_interrupt); + DECLARE_ADDRESS_MAP(map, 16); + DECLARE_ADDRESS_MAP(alt_map, 8); + READ8_MEMBER(ide16_alt_r); + WRITE8_MEMBER(ide16_alt_w); +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + +private: + // internal state + bool m_is_primary; + required_device m_ide; +}; + + +// device type definition +extern const device_type ISA16_IDE; + +#endif /* __ISA_IDE_H__ */ diff --git a/src/devices/bus/isa/isa.c b/src/devices/bus/isa/isa.c new file mode 100644 index 00000000000..5b8b213580e --- /dev/null +++ b/src/devices/bus/isa/isa.c @@ -0,0 +1,646 @@ +// license:BSD-3-Clause +// copyright-holders:Miodrag Milanovic +/*************************************************************************** + + ISA bus device + +***************************************************************************/ + +#include "emu.h" +#include "emuopts.h" +#include "isa.h" + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type ISA8_SLOT = &device_creator; + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// isa8_slot_device - constructor +//------------------------------------------------- +isa8_slot_device::isa8_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, ISA8_SLOT, "ISA8_SLOT", tag, owner, clock, "isa8_slot", __FILE__), + device_slot_interface(mconfig, *this) +{ +} + +isa8_slot_device::isa8_slot_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_slot_interface(mconfig, *this) +{ +} + +void isa8_slot_device::static_set_isa8_slot(device_t &device, device_t *owner, const char *isa_tag) +{ + isa8_slot_device &isa_card = dynamic_cast(device); + isa_card.m_owner = owner; + isa_card.m_isa_tag = isa_tag; +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void isa8_slot_device::device_start() +{ + device_isa8_card_interface *dev = dynamic_cast(get_card_device()); + const device_isa16_card_interface *intf; + if (get_card_device()->interface(intf)) + fatalerror("Error ISA16 device in ISA8 slot\n"); + + if (dev) device_isa8_card_interface::static_set_isabus(*dev,m_owner->subdevice(m_isa_tag)); +} + + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type ISA16_SLOT = &device_creator; + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// isa16_slot_device - constructor +//------------------------------------------------- +isa16_slot_device::isa16_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + isa8_slot_device(mconfig, ISA16_SLOT, "ISA16_SLOT", tag, owner, clock, "isa16_slot", __FILE__) +{ +} + +void isa16_slot_device::static_set_isa16_slot(device_t &device, device_t *owner, const char *isa_tag) +{ + isa16_slot_device &isa_card = dynamic_cast(device); + isa_card.m_owner = owner; + isa_card.m_isa_tag = isa_tag; +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void isa16_slot_device::device_start() +{ + device_isa8_card_interface *dev = dynamic_cast(get_card_device()); + if (dev) device_isa8_card_interface::static_set_isabus(*dev,m_owner->subdevice(m_isa_tag)); +} + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type ISA8 = &device_creator; + +void isa8_device::static_set_cputag(device_t &device, const char *tag) +{ + isa8_device &isa = downcast(device); + isa.m_cputag = tag; +} + +void isa8_device::static_set_custom_spaces(device_t &device) +{ + isa8_device &isa = downcast(device); + + isa.m_allocspaces = true; +} + +//------------------------------------------------- +// device_config_complete - perform any +// operations now that the configuration is +// complete +//------------------------------------------------- + +void isa8_device::device_config_complete() +{ + m_maincpu = subdevice(m_cputag); +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// isa8_device - constructor +//------------------------------------------------- + +isa8_device::isa8_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, ISA8, "ISA8", tag, owner, clock, "isa8", __FILE__), + device_memory_interface(mconfig, *this), + m_program_config("ISA 8-bit program", ENDIANNESS_LITTLE, 8, 24, 0, NULL), + m_io_config("ISA 8-bit I/O", ENDIANNESS_LITTLE, 8, 16, 0, NULL), + m_program16_config("ISA 16-bit program", ENDIANNESS_LITTLE, 16, 24, 0, NULL), + m_io16_config("ISA 16-bit I/O", ENDIANNESS_LITTLE, 16, 16, 0, NULL), + m_out_irq2_cb(*this), + m_out_irq3_cb(*this), + m_out_irq4_cb(*this), + m_out_irq5_cb(*this), + m_out_irq6_cb(*this), + m_out_irq7_cb(*this), + m_out_drq1_cb(*this), + m_out_drq2_cb(*this), + m_out_drq3_cb(*this), + m_write_iochck(*this) +{ + for(int i=0;i<8;i++) + { + m_dma_device[i] = NULL; + m_dma_eop[i] = false; + } + m_nmi_enabled = false; + m_iowidth = m_prgwidth = 0; + m_allocspaces = false; +} + +isa8_device::isa8_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_memory_interface(mconfig, *this), + m_program_config("ISA 8-bit program", ENDIANNESS_LITTLE, 8, 24, 0, NULL), + m_io_config("ISA 8-bit I/O", ENDIANNESS_LITTLE, 8, 16, 0, NULL), + m_program16_config("ISA 16-bit program", ENDIANNESS_LITTLE, 16, 24, 0, NULL), + m_io16_config("ISA 16-bit I/O", ENDIANNESS_LITTLE, 16, 16, 0, NULL), + m_out_irq2_cb(*this), + m_out_irq3_cb(*this), + m_out_irq4_cb(*this), + m_out_irq5_cb(*this), + m_out_irq6_cb(*this), + m_out_irq7_cb(*this), + m_out_drq1_cb(*this), + m_out_drq2_cb(*this), + m_out_drq3_cb(*this), + m_write_iochck(*this) +{ + for(int i=0;i<8;i++) + { + m_dma_device[i] = NULL; + m_dma_eop[i] = false; + } + m_nmi_enabled = false; + m_iowidth = m_prgwidth = 0; + m_allocspaces = false; +} + +READ8_MEMBER(isa8_device::prog_r) +{ + return m_prgspace->read_byte(offset); +} + +WRITE8_MEMBER(isa8_device::prog_w) +{ + m_prgspace->write_byte(offset, data); +} + +READ8_MEMBER(isa8_device::io_r) +{ + return m_iospace->read_byte(offset); +} + +WRITE8_MEMBER(isa8_device::io_w) +{ + m_iospace->write_byte(offset, data); +} + +void isa8_device::set_dma_channel(UINT8 channel, device_isa8_card_interface *dev, bool do_eop) +{ + m_dma_device[channel] = dev; + m_dma_eop[channel] = do_eop; +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void isa8_device::device_start() +{ + // resolve callbacks + m_write_iochck.resolve_safe(); + + m_out_irq2_cb.resolve_safe(); + m_out_irq3_cb.resolve_safe(); + m_out_irq4_cb.resolve_safe(); + m_out_irq5_cb.resolve_safe(); + m_out_irq6_cb.resolve_safe(); + m_out_irq7_cb.resolve_safe(); + m_out_drq1_cb.resolve_safe(); + m_out_drq2_cb.resolve_safe(); + m_out_drq3_cb.resolve_safe(); + + m_maincpu = subdevice(m_cputag); + + if (m_allocspaces) + { + m_iospace = &space(AS_IO); + m_prgspace = &space(AS_PROGRAM); + m_iowidth = m_iospace->data_width(); + m_prgwidth = m_prgspace->data_width(); + } + else // use host CPU's program and I/O spaces directly + { + m_iospace = &m_maincpu->space(AS_IO); + m_iowidth = m_maincpu->space_config(AS_IO)->m_databus_width; + m_prgspace = &m_maincpu->space(AS_PROGRAM); + m_prgwidth = m_maincpu->space_config(AS_PROGRAM)->m_databus_width; + } +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void isa8_device::device_reset() +{ +} + + +void isa8_device::install_space(address_spacenum spacenum, offs_t start, offs_t end, offs_t mask, offs_t mirror, read8_delegate rhandler, write8_delegate whandler) +{ + int buswidth; + address_space *space; + + if (spacenum == AS_IO) + { + space = m_iospace; + buswidth = m_iowidth; + } + else if (spacenum == AS_PROGRAM) + { + space = m_prgspace; + buswidth = m_prgwidth; + } + else + { + fatalerror("Unknown space passed to isa8_device::install_space!\n"); + } + + switch(buswidth) + { + case 8: + space->install_readwrite_handler(start, end, mask, mirror, rhandler, whandler, 0); + break; + case 16: + space->install_readwrite_handler(start, end, mask, mirror, rhandler, whandler, 0xffff); + break; + case 32: + if ((start % 4) == 0) { + if ((end-start)==1) { + space->install_readwrite_handler(start, end+2, mask, mirror, rhandler, whandler, 0x0000ffff); + } else { + space->install_readwrite_handler(start, end, mask, mirror, rhandler, whandler, 0xffffffff); + } + } else { + // we handle just misalligned by 2 + space->install_readwrite_handler(start-2, end, mask, mirror, rhandler, whandler, 0xffff0000); + } + break; + default: + fatalerror("ISA8: Bus width %d not supported\n", buswidth); + } +} + + +void isa8_device::install_memory(offs_t start, offs_t end, offs_t mask, offs_t mirror, read8_delegate rhandler, write8_delegate whandler) +{ + install_space(AS_PROGRAM, start, end, mask, mirror, rhandler, whandler); +} + +void isa8_device::install_device(offs_t start, offs_t end, offs_t mask, offs_t mirror, read8_delegate rhandler, write8_delegate whandler) +{ + install_space(AS_IO, start, end, mask, mirror, rhandler, whandler); +} + + +void isa8_device::install_bank(offs_t start, offs_t end, offs_t mask, offs_t mirror, const char *tag, UINT8 *data) +{ + m_prgspace->install_readwrite_bank(start, end, mask, mirror, tag ); + machine().root_device().membank(tag)->set_base(data); +} + +void isa8_device::unmap_bank(offs_t start, offs_t end, offs_t mask, offs_t mirror) +{ + m_prgspace->unmap_readwrite(start, end, mask, mirror); +} + +void isa8_device::install_rom(device_t *dev, offs_t start, offs_t end, offs_t mask, offs_t mirror, const char *tag, const char *region) +{ + if (machine().root_device().memregion("isa")) { + UINT8 *src = dev->memregion(region)->base(); + UINT8 *dest = machine().root_device().memregion("isa")->base() + start - 0xc0000; + memcpy(dest,src, end - start + 1); + } else { + m_prgspace->install_read_bank(start, end, mask, mirror, tag); + m_prgspace->unmap_write(start, end, mask, mirror); + machine().root_device().membank(tag)->set_base(machine().root_device().memregion(dev->subtag(region).c_str())->base()); + } +} + +void isa8_device::unmap_rom(offs_t start, offs_t end, offs_t mask, offs_t mirror) +{ + m_prgspace->unmap_read(start, end, mask, mirror); +} + +bool isa8_device::is_option_rom_space_available(offs_t start, int size) +{ + m_maincpu = machine().device(m_cputag); + for(int i = 0; i < size; i += 4096) // 4KB granularity should be enough + if(m_prgspace->get_read_ptr(start + i)) return false; + return true; +} + +// interrupt request from isa card +WRITE_LINE_MEMBER( isa8_device::irq2_w ) { m_out_irq2_cb(state); } +WRITE_LINE_MEMBER( isa8_device::irq3_w ) { m_out_irq3_cb(state); } +WRITE_LINE_MEMBER( isa8_device::irq4_w ) { m_out_irq4_cb(state); } +WRITE_LINE_MEMBER( isa8_device::irq5_w ) { m_out_irq5_cb(state); } +WRITE_LINE_MEMBER( isa8_device::irq6_w ) { m_out_irq6_cb(state); } +WRITE_LINE_MEMBER( isa8_device::irq7_w ) { m_out_irq7_cb(state); } + +// dma request from isa card +WRITE_LINE_MEMBER( isa8_device::drq1_w ) { m_out_drq1_cb(state); } +WRITE_LINE_MEMBER( isa8_device::drq2_w ) { m_out_drq2_cb(state); } +WRITE_LINE_MEMBER( isa8_device::drq3_w ) { m_out_drq3_cb(state); } + +UINT8 isa8_device::dack_r(int line) +{ + if (m_dma_device[line]) + return m_dma_device[line]->dack_r(line); + return 0xff; +} + +void isa8_device::dack_w(int line,UINT8 data) +{ + if (m_dma_device[line]) + return m_dma_device[line]->dack_w(line,data); +} + +void isa8_device::eop_w(int channel, int state) +{ + if (m_dma_eop[channel] && m_dma_device[channel]) + m_dma_device[channel]->eop_w(state); +} + +void isa8_device::nmi() +{ + if (m_write_iochck.isnull()) + { + if (m_nmi_enabled) + { + m_maincpu->set_input_line(INPUT_LINE_NMI, PULSE_LINE ); + } + } + else + { + m_write_iochck(0); + m_write_iochck(1); + } +} + +//************************************************************************** +// DEVICE CONFIG ISA8 CARD INTERFACE +//************************************************************************** + + +//************************************************************************** +// DEVICE ISA8 CARD INTERFACE +//************************************************************************** + +//------------------------------------------------- +// device_isa8_card_interface - constructor +//------------------------------------------------- + +device_isa8_card_interface::device_isa8_card_interface(const machine_config &mconfig, device_t &device) + : device_slot_card_interface(mconfig, device), + m_isa(NULL) +{ +} + + +//------------------------------------------------- +// ~device_isa8_card_interface - destructor +//------------------------------------------------- + +device_isa8_card_interface::~device_isa8_card_interface() +{ +} + +UINT8 device_isa8_card_interface::dack_r(int line) +{ + return 0; +} +void device_isa8_card_interface::dack_w(int line,UINT8 data) +{ +} +void device_isa8_card_interface::eop_w(int state) +{ +} + +void device_isa8_card_interface::static_set_isabus(device_t &device, device_t *isa_device) +{ + device_isa8_card_interface &isa_card = dynamic_cast(device); + isa_card.m_isa_dev = isa_device; +} + +void device_isa8_card_interface::set_isa_device() +{ + m_isa = dynamic_cast(m_isa_dev); +} + + +const device_type ISA16 = &device_creator; + +//------------------------------------------------- +// isa16_device - constructor +//------------------------------------------------- + +isa16_device::isa16_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + isa8_device(mconfig, ISA16, "ISA16", tag, owner, clock, "isa16", __FILE__), + m_out_irq10_cb(*this), + m_out_irq11_cb(*this), + m_out_irq12_cb(*this), + m_out_irq14_cb(*this), + m_out_irq15_cb(*this), + m_out_drq0_cb(*this), + m_out_drq5_cb(*this), + m_out_drq6_cb(*this), + m_out_drq7_cb(*this) +{ +} + +//------------------------------------------------- +// device_config_complete - perform any +// operations now that the configuration is +// complete +//------------------------------------------------- + +void isa16_device::device_config_complete() +{ + m_maincpu = mconfig().device(m_cputag); +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void isa16_device::device_start() +{ + isa8_device::device_start(); + + // resolve callbacks + m_out_irq10_cb.resolve_safe(); + m_out_irq11_cb.resolve_safe(); + m_out_irq12_cb.resolve_safe(); + m_out_irq14_cb.resolve_safe(); + m_out_irq15_cb.resolve_safe(); + + m_out_drq0_cb.resolve_safe(); + m_out_drq5_cb.resolve_safe(); + m_out_drq6_cb.resolve_safe(); + m_out_drq7_cb.resolve_safe(); +} + +void isa16_device::install16_device(offs_t start, offs_t end, offs_t mask, offs_t mirror, read16_delegate rhandler, write16_delegate whandler) +{ + int buswidth = m_prgwidth; + switch(buswidth) + { + case 16: + m_iospace->install_readwrite_handler(start, end, mask, mirror, rhandler, whandler, 0); + break; + case 32: + m_iospace->install_readwrite_handler(start, end, mask, mirror, rhandler, whandler, 0xffffffff); + if ((start % 4) == 0) { + if ((end-start)==1) { + m_iospace->install_readwrite_handler(start, end+2, mask, mirror, rhandler, whandler, 0x0000ffff); + } else { + m_iospace->install_readwrite_handler(start, end, mask, mirror, rhandler, whandler, 0xffffffff); + } + } else { + // we handle just misalligned by 2 + m_iospace->install_readwrite_handler(start-2, end, mask, mirror, rhandler, whandler, 0xffff0000); + } + + break; + default: + fatalerror("ISA16: Bus width %d not supported\n", buswidth); + } +} + +READ16_MEMBER(isa16_device::prog16_r) +{ + return m_prgspace->read_word(offset<<1, mem_mask); +} + +WRITE16_MEMBER(isa16_device::prog16_w) +{ + m_prgspace->write_word(offset<<1, data, mem_mask); +} + +READ16_MEMBER(isa16_device::io16_r) +{ + return m_iospace->read_word(offset<<1, mem_mask); +} + +WRITE16_MEMBER(isa16_device::io16_w) +{ + m_iospace->write_word(offset<<1, data, mem_mask); +} + +READ16_MEMBER(isa16_device::prog16_swap_r) +{ + UINT16 rv; + mem_mask = (mem_mask<<8) | (mem_mask>>8); + + rv = m_prgspace->read_word(offset<<1, mem_mask); + + return (rv<<8) | (rv>>8); +} + +WRITE16_MEMBER(isa16_device::prog16_swap_w) +{ + mem_mask = (mem_mask<<8) | (mem_mask>>8); + data = (data<<8) | (data>>8); + m_prgspace->write_word(offset<<1, data, mem_mask); +} + +READ16_MEMBER(isa16_device::io16_swap_r) +{ + UINT16 rv; + mem_mask = (mem_mask<<8) | (mem_mask>>8); + + rv = m_iospace->read_word(offset<<1, mem_mask); + + return (rv<<8) | (rv>>8); +} + +WRITE16_MEMBER(isa16_device::io16_swap_w) +{ + mem_mask = (mem_mask<<8) | (mem_mask>>8); + data = (data<<8) | (data>>8); + m_iospace->write_word(offset<<1, data, mem_mask); +} + +// interrupt request from isa card +WRITE_LINE_MEMBER( isa16_device::irq10_w ) { m_out_irq10_cb(state); } +WRITE_LINE_MEMBER( isa16_device::irq11_w ) { m_out_irq11_cb(state); } +WRITE_LINE_MEMBER( isa16_device::irq12_w ) { m_out_irq12_cb(state); } +WRITE_LINE_MEMBER( isa16_device::irq14_w ) { m_out_irq14_cb(state); } +WRITE_LINE_MEMBER( isa16_device::irq15_w ) { m_out_irq15_cb(state); } + +// dma request from isa card +WRITE_LINE_MEMBER( isa16_device::drq0_w ) { m_out_drq0_cb(state); } +WRITE_LINE_MEMBER( isa16_device::drq5_w ) { m_out_drq5_cb(state); } +WRITE_LINE_MEMBER( isa16_device::drq6_w ) { m_out_drq6_cb(state); } +WRITE_LINE_MEMBER( isa16_device::drq7_w ) { m_out_drq7_cb(state); } + +UINT16 isa16_device::dack16_r(int line) +{ + if (m_dma_device[line]) + return dynamic_cast(m_dma_device[line])->dack16_r(line); + return 0xffff; +} + +void isa16_device::dack16_w(int line,UINT16 data) +{ + if (m_dma_device[line]) + return dynamic_cast(m_dma_device[line])->dack16_w(line,data); +} + +//------------------------------------------------- +// device_isa16_card_interface - constructor +//------------------------------------------------- + +device_isa16_card_interface::device_isa16_card_interface(const machine_config &mconfig, device_t &device) + : device_isa8_card_interface(mconfig,device) +{ +} + + +//------------------------------------------------- +// ~device_isa16_card_interface - destructor +//------------------------------------------------- + +device_isa16_card_interface::~device_isa16_card_interface() +{ +} + +void device_isa16_card_interface::set_isa_device() +{ + m_isa = dynamic_cast(m_isa_dev); +} + +UINT16 device_isa16_card_interface::dack16_r(int line) +{ + return 0; +} + +void device_isa16_card_interface::dack16_w(int line,UINT16 data) +{ +} diff --git a/src/devices/bus/isa/isa.h b/src/devices/bus/isa/isa.h new file mode 100644 index 00000000000..e851cebe8af --- /dev/null +++ b/src/devices/bus/isa/isa.h @@ -0,0 +1,439 @@ +// license:BSD-3-Clause +// copyright-holders:Miodrag Milanovic +/*************************************************************************** + + ISA bus device + + + 8 bit ISA bus connector: + + A1 O I/O CH CHK B1 GND + A2 IO D7 B2 I RESET + A3 IO D6 B3 +5V + A4 IO D5 B4 O IRQ2 + A5 IO D4 B5 -5V + A6 IO D3 B6 O DRQ2 + A7 IO D2 B7 -12V + A8 IO D1 B8 O /NOWS + A9 IO D0 B9 +12V + A10 O I/O CH RDY B10 GND + A11 I AEN B11 I /SMEMW + A12 IO A19 B12 I /SMEMR + A13 IO A18 B13 I /IOW + A14 IO A17 B14 I /IOR + A15 IO A16 B15 I /DACK3 + A16 IO A15 B16 O DRQ3 + A17 IO A14 B17 I /DACK1 + A18 IO A13 B18 O DRQ1 + A19 IO A12 B19 IO /REFRESH + A20 IO A11 B20 I CLOCK + A21 IO A10 B21 O IRQ7 + A22 IO A9 B22 O IRQ6 + A23 IO A8 B23 O IRQ5 + A24 IO A7 B24 O IRQ4 + A25 IO A6 B25 O IRQ3 + A26 IO A5 B26 I /DACK2 + A27 IO A4 B27 I T/C + A28 IO A3 B28 I ALE + A29 IO A2 B29 +5V + A30 IO A1 B30 I OSC + A31 IO A0 B31 GND + + 16 bit ISA bus extension + + C1 I SBHE D1 I /MEM CS 16 + C2 IO A23 D2 I /I/O CS 16 + C3 IO A22 D3 O IRQ10 + C4 IO A21 D4 O IRQ11 + C5 IO A20 D5 O IRQ12 + C6 IO A19 D6 O IRQ15 + C7 IO A18 D7 O IRQ14 + C8 IO A17 D8 I /DACK0 + C9 I /MEMR D9 O DRQ0 + C10 I /MEMW D10 I /DACK5 + C11 IO D8 D11 O DRQ5 + C12 IO D9 D12 I /DACK6 + C13 IO D10 D13 O DRQ6 + C14 IO D11 D14 I /DACK7 + C15 IO D12 D15 O DRQ7 + C16 IO D13 D16 +5V + C17 IO D14 D17 I MASTER + C18 IO D15 D18 GND + +***************************************************************************/ + +#pragma once + +#ifndef __ISA_H__ +#define __ISA_H__ + +#include "emu.h" + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_ISA8_CPU(_cputag) \ + isa8_device::static_set_cputag(*device, _cputag); +// include this in a driver to have ISA allocate it's own address spaces (e.g. non-x86) +#define MCFG_ISA8_BUS_CUSTOM_SPACES() \ + isa8_device::static_set_custom_spaces(*device); +#define MCFG_ISA8_SLOT_ADD(_isatag, _tag, _slot_intf, _def_slot, _fixed) \ + MCFG_DEVICE_ADD(_tag, ISA8_SLOT, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, _fixed) \ + isa8_slot_device::static_set_isa8_slot(*device, owner, _isatag); +#define MCFG_ISA16_CPU(_cputag) \ + isa8_device::static_set_cputag(*device, _cputag); +#define MCFG_ISA16_BUS_CUSTOM_SPACES() \ + isa8_device::static_set_custom_spaces(*device); +#define MCFG_ISA16_SLOT_ADD(_isatag, _tag, _slot_intf, _def_slot, _fixed) \ + MCFG_DEVICE_ADD(_tag, ISA16_SLOT, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, _fixed) \ + isa16_slot_device::static_set_isa16_slot(*device, owner, _isatag); + +#define MCFG_ISA_BUS_IOCHCK(_iochck) \ + downcast(device)->set_iochck_callback(DEVCB_##_iochck); + +#define MCFG_ISA_OUT_IRQ2_CB(_devcb) \ + devcb = &isa8_device::set_out_irq2_callback(*device, DEVCB_##_devcb); + +#define MCFG_ISA_OUT_IRQ3_CB(_devcb) \ + devcb = &isa8_device::set_out_irq3_callback(*device, DEVCB_##_devcb); + +#define MCFG_ISA_OUT_IRQ4_CB(_devcb) \ + devcb = &isa8_device::set_out_irq4_callback(*device, DEVCB_##_devcb); + +#define MCFG_ISA_OUT_IRQ5_CB(_devcb) \ + devcb = &isa8_device::set_out_irq5_callback(*device, DEVCB_##_devcb); + +#define MCFG_ISA_OUT_IRQ6_CB(_devcb) \ + devcb = &isa8_device::set_out_irq6_callback(*device, DEVCB_##_devcb); + +#define MCFG_ISA_OUT_IRQ7_CB(_devcb) \ + devcb = &isa8_device::set_out_irq7_callback(*device, DEVCB_##_devcb); + +#define MCFG_ISA_OUT_DRQ1_CB(_devcb) \ + devcb = &isa8_device::set_out_drq1_callback(*device, DEVCB_##_devcb); + +#define MCFG_ISA_OUT_DRQ2_CB(_devcb) \ + devcb = &isa8_device::set_out_drq2_callback(*device, DEVCB_##_devcb); + +#define MCFG_ISA_OUT_DRQ3_CB(_devcb) \ + devcb = &isa8_device::set_out_drq3_callback(*device, DEVCB_##_devcb); + + +#define MCFG_ISA_OUT_IRQ10_CB(_devcb) \ + devcb = &isa16_device::set_out_irq10_callback(*device, DEVCB_##_devcb); + +#define MCFG_ISA_OUT_IRQ11_CB(_devcb) \ + devcb = &isa16_device::set_out_irq11_callback(*device, DEVCB_##_devcb); + +#define MCFG_ISA_OUT_IRQ12_CB(_devcb) \ + devcb = &isa16_device::set_out_irq12_callback(*device, DEVCB_##_devcb); + +#define MCFG_ISA_OUT_IRQ14_CB(_devcb) \ + devcb = &isa16_device::set_out_irq14_callback(*device, DEVCB_##_devcb); + +#define MCFG_ISA_OUT_IRQ15_CB(_devcb) \ + devcb = &isa16_device::set_out_irq15_callback(*device, DEVCB_##_devcb); + +#define MCFG_ISA_OUT_DRQ0_CB(_devcb) \ + devcb = &isa16_device::set_out_drq0_callback(*device, DEVCB_##_devcb); + +#define MCFG_ISA_OUT_DRQ5_CB(_devcb) \ + devcb = &isa16_device::set_out_drq5_callback(*device, DEVCB_##_devcb); + +#define MCFG_ISA_OUT_DRQ6_CB(_devcb) \ + devcb = &isa16_device::set_out_drq6_callback(*device, DEVCB_##_devcb); + +#define MCFG_ISA_OUT_DRQ7_CB(_devcb) \ + devcb = &isa16_device::set_out_drq7_callback(*device, DEVCB_##_devcb); + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class isa8_device; + +class isa8_slot_device : public device_t, + public device_slot_interface +{ +public: + // construction/destruction + isa8_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + isa8_slot_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + // device-level overrides + virtual void device_start(); + + // inline configuration + static void static_set_isa8_slot(device_t &device, device_t *owner, const char *isa_tag); +protected: + // configuration + device_t *m_owner; + const char *m_isa_tag; +}; + +// device type definition +extern const device_type ISA8_SLOT; + +class device_isa8_card_interface; +// ======================> isa8_device +class isa8_device : public device_t, + public device_memory_interface +{ +public: + // construction/destruction + isa8_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + isa8_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + // inline configuration + static void static_set_cputag(device_t &device, const char *tag); + static void static_set_custom_spaces(device_t &device); + template void set_iochck_callback(_iochck iochck) { m_write_iochck.set_callback(iochck); } + template static devcb_base &set_out_irq2_callback(device_t &device, _Object object) { return downcast(device).m_out_irq2_cb.set_callback(object); } + template static devcb_base &set_out_irq3_callback(device_t &device, _Object object) { return downcast(device).m_out_irq3_cb.set_callback(object); } + template static devcb_base &set_out_irq4_callback(device_t &device, _Object object) { return downcast(device).m_out_irq4_cb.set_callback(object); } + template static devcb_base &set_out_irq5_callback(device_t &device, _Object object) { return downcast(device).m_out_irq5_cb.set_callback(object); } + template static devcb_base &set_out_irq6_callback(device_t &device, _Object object) { return downcast(device).m_out_irq6_cb.set_callback(object); } + template static devcb_base &set_out_irq7_callback(device_t &device, _Object object) { return downcast(device).m_out_irq7_cb.set_callback(object); } + template static devcb_base &set_out_drq1_callback(device_t &device, _Object object) { return downcast(device).m_out_drq1_cb.set_callback(object); } + template static devcb_base &set_out_drq2_callback(device_t &device, _Object object) { return downcast(device).m_out_drq2_cb.set_callback(object); } + template static devcb_base &set_out_drq3_callback(device_t &device, _Object object) { return downcast(device).m_out_drq3_cb.set_callback(object); } + + // for ISA8, put the 8-bit configs in the primary slots and the 16-bit configs in the secondary + virtual const address_space_config *memory_space_config(address_spacenum spacenum) const + { + switch (spacenum) + { + case AS_PROGRAM: return &m_program_config; + case AS_IO: return &m_io_config; + case AS_DATA: return &m_program16_config; + case AS_3: return &m_io16_config; + default: fatalerror("isa: invalid memory space!\n"); + } + } + + void install_device(offs_t start, offs_t end, offs_t mask, offs_t mirror, read8_delegate rhandler, write8_delegate whandler); + template void install_device(offs_t addrstart, offs_t addrend, T &device, void (T::*map)(class address_map &map, device_t &device), int bits = 8, UINT64 unitmask = U64(0xffffffffffffffff)) + { + m_iospace->install_device(addrstart, addrend, device, map, bits, unitmask); + } + void install_bank(offs_t start, offs_t end, offs_t mask, offs_t mirror, const char *tag, UINT8 *data); + void install_rom(device_t *dev, offs_t start, offs_t end, offs_t mask, offs_t mirror, const char *tag, const char *region); + void install_memory(offs_t start, offs_t end, offs_t mask, offs_t mirror, read8_delegate rhandler, write8_delegate whandler); + + void unmap_bank(offs_t start, offs_t end, offs_t mask, offs_t mirror); + void unmap_rom(offs_t start, offs_t end, offs_t mask, offs_t mirror); + bool is_option_rom_space_available(offs_t start, int size); + + DECLARE_WRITE_LINE_MEMBER( irq2_w ); + DECLARE_WRITE_LINE_MEMBER( irq3_w ); + DECLARE_WRITE_LINE_MEMBER( irq4_w ); + DECLARE_WRITE_LINE_MEMBER( irq5_w ); + DECLARE_WRITE_LINE_MEMBER( irq6_w ); + DECLARE_WRITE_LINE_MEMBER( irq7_w ); + + DECLARE_WRITE_LINE_MEMBER( drq1_w ); + DECLARE_WRITE_LINE_MEMBER( drq2_w ); + DECLARE_WRITE_LINE_MEMBER( drq3_w ); + + // 8 bit accessors for ISA-defined address spaces + DECLARE_READ8_MEMBER(prog_r); + DECLARE_WRITE8_MEMBER(prog_w); + DECLARE_READ8_MEMBER(io_r); + DECLARE_WRITE8_MEMBER(io_w); + + UINT8 dack_r(int line); + void dack_w(int line,UINT8 data); + void eop_w(int channels, int state); + + void nmi(); + void set_nmi_state(bool enabled) { m_nmi_enabled = enabled; } + + virtual void set_dma_channel(UINT8 channel, device_isa8_card_interface *dev, bool do_eop); + + const address_space_config m_program_config, m_io_config, m_program16_config, m_io16_config; + +protected: + void install_space(address_spacenum spacenum, offs_t start, offs_t end, offs_t mask, offs_t mirror, read8_delegate rhandler, write8_delegate whandler); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_config_complete(); + + // internal state + cpu_device *m_maincpu; + + // address spaces + address_space *m_iospace, *m_prgspace; + int m_iowidth, m_prgwidth; + bool m_allocspaces; + + devcb_write_line m_out_irq2_cb; + devcb_write_line m_out_irq3_cb; + devcb_write_line m_out_irq4_cb; + devcb_write_line m_out_irq5_cb; + devcb_write_line m_out_irq6_cb; + devcb_write_line m_out_irq7_cb; + devcb_write_line m_out_drq1_cb; + devcb_write_line m_out_drq2_cb; + devcb_write_line m_out_drq3_cb; + + device_isa8_card_interface *m_dma_device[8]; + bool m_dma_eop[8]; + const char *m_cputag; + bool m_nmi_enabled; + +private: + devcb_write_line m_write_iochck; +}; + + +// device type definition +extern const device_type ISA8; + +// ======================> device_isa8_card_interface + +// class representing interface-specific live isa8 card +class device_isa8_card_interface : public device_slot_card_interface +{ + friend class isa8_device; +public: + // construction/destruction + device_isa8_card_interface(const machine_config &mconfig, device_t &device); + virtual ~device_isa8_card_interface(); + + device_isa8_card_interface *next() const { return m_next; } + + void set_isa_device(); + // configuration access + virtual UINT8 dack_r(int line); + virtual void dack_w(int line,UINT8 data); + virtual void eop_w(int state); + + // inline configuration + static void static_set_isabus(device_t &device, device_t *isa_device); +public: + isa8_device *m_isa; + device_t *m_isa_dev; + device_isa8_card_interface *m_next; +}; + +class isa16_device; + +class isa16_slot_device : public isa8_slot_device +{ +public: + // construction/destruction + isa16_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + // device-level overrides + virtual void device_start(); + + // inline configuration + static void static_set_isa16_slot(device_t &device, device_t *owner, const char *isa_tag); +}; + + +// device type definition +extern const device_type ISA16_SLOT; + +// ======================> isa16_device +class isa16_device : public isa8_device +{ +public: + // construction/destruction + isa16_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + template static devcb_base &set_out_irq10_callback(device_t &device, _Object object) { return downcast(device).m_out_irq10_cb.set_callback(object); } + template static devcb_base &set_out_irq11_callback(device_t &device, _Object object) { return downcast(device).m_out_irq11_cb.set_callback(object); } + template static devcb_base &set_out_irq12_callback(device_t &device, _Object object) { return downcast(device).m_out_irq12_cb.set_callback(object); } + template static devcb_base &set_out_irq14_callback(device_t &device, _Object object) { return downcast(device).m_out_irq14_cb.set_callback(object); } + template static devcb_base &set_out_irq15_callback(device_t &device, _Object object) { return downcast(device).m_out_irq15_cb.set_callback(object); } + template static devcb_base &set_out_drq0_callback(device_t &device, _Object object) { return downcast(device).m_out_drq0_cb.set_callback(object); } + template static devcb_base &set_out_drq5_callback(device_t &device, _Object object) { return downcast(device).m_out_drq5_cb.set_callback(object); } + template static devcb_base &set_out_drq6_callback(device_t &device, _Object object) { return downcast(device).m_out_drq6_cb.set_callback(object); } + template static devcb_base &set_out_drq7_callback(device_t &device, _Object object) { return downcast(device).m_out_drq7_cb.set_callback(object); } + + void install16_device(offs_t start, offs_t end, offs_t mask, offs_t mirror, read16_delegate rhandler, write16_delegate whandler); + + // for ISA16, put the 16-bit configs in the primary slots and the 8-bit configs in the secondary + virtual const address_space_config *memory_space_config(address_spacenum spacenum) const + { + switch (spacenum) + { + case AS_PROGRAM: return &m_program16_config; + case AS_IO: return &m_io16_config; + case AS_DATA: return &m_program_config; + case AS_3: return &m_io_config; + default: fatalerror("isa: invalid memory space!\n"); + } + } + + DECLARE_WRITE_LINE_MEMBER( irq10_w ); + DECLARE_WRITE_LINE_MEMBER( irq11_w ); + DECLARE_WRITE_LINE_MEMBER( irq12_w ); + DECLARE_WRITE_LINE_MEMBER( irq14_w ); + DECLARE_WRITE_LINE_MEMBER( irq15_w ); + + DECLARE_WRITE_LINE_MEMBER( drq0_w ); + DECLARE_WRITE_LINE_MEMBER( drq5_w ); + DECLARE_WRITE_LINE_MEMBER( drq6_w ); + DECLARE_WRITE_LINE_MEMBER( drq7_w ); + + UINT16 dack16_r(int line); + void dack16_w(int line,UINT16 data); + + // 16 bit accessors for ISA-defined address spaces + DECLARE_READ16_MEMBER(prog16_r); + DECLARE_WRITE16_MEMBER(prog16_w); + DECLARE_READ16_MEMBER(io16_r); + DECLARE_WRITE16_MEMBER(io16_w); + // byte-swapped versions of 16-bit accessors + DECLARE_READ16_MEMBER(prog16_swap_r); + DECLARE_WRITE16_MEMBER(prog16_swap_w); + DECLARE_READ16_MEMBER(io16_swap_r); + DECLARE_WRITE16_MEMBER(io16_swap_w); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_config_complete(); + +private: + // internal state + devcb_write_line m_out_irq10_cb; + devcb_write_line m_out_irq11_cb; + devcb_write_line m_out_irq12_cb; + devcb_write_line m_out_irq14_cb; + devcb_write_line m_out_irq15_cb; + devcb_write_line m_out_drq0_cb; + devcb_write_line m_out_drq5_cb; + devcb_write_line m_out_drq6_cb; + devcb_write_line m_out_drq7_cb; +}; + + +// device type definition +extern const device_type ISA16; + +// ======================> device_isa16_card_interface + +// class representing interface-specific live isa16 card +class device_isa16_card_interface : public device_isa8_card_interface +{ + friend class isa16_device; +public: + // construction/destruction + device_isa16_card_interface(const machine_config &mconfig, device_t &device); + virtual ~device_isa16_card_interface(); + virtual UINT16 dack16_r(int line); + virtual void dack16_w(int line,UINT16 data); + + void set_isa_device(); + isa16_device *m_isa; +}; + +#endif /* __ISA_H__ */ diff --git a/src/devices/bus/isa/isa_cards.c b/src/devices/bus/isa/isa_cards.c new file mode 100644 index 00000000000..a9ab1b9dc8f --- /dev/null +++ b/src/devices/bus/isa/isa_cards.c @@ -0,0 +1,103 @@ +// license:BSD-3-Clause +// copyright-holders:Dirk Best +/********************************************************************** + + ISA cards + +**********************************************************************/ + +#include "isa_cards.h" + +SLOT_INTERFACE_START( pc_isa8_cards ) + SLOT_INTERFACE("mda", ISA8_MDA) + SLOT_INTERFACE("cga", ISA8_CGA) + SLOT_INTERFACE("cga_ec1841", ISA8_EC1841_0002) + SLOT_INTERFACE("cga_poisk2", ISA8_CGA_POISK2) + SLOT_INTERFACE("cga_mc1502", ISA8_CGA_MC1502) + SLOT_INTERFACE("cga_m24", ISA8_CGA_M24) + SLOT_INTERFACE("aga", ISA8_AGA) + SLOT_INTERFACE("aga_pc200", ISA8_AGA_PC200) + SLOT_INTERFACE("ega", ISA8_EGA) + SLOT_INTERFACE("pgc", ISA8_PGC) + SLOT_INTERFACE("svga_et4k", ISA8_SVGA_ET4K) + SLOT_INTERFACE("num9rev",ISA8_NUM_9_REV) + SLOT_INTERFACE("com", ISA8_COM) + SLOT_INTERFACE("fdc", ISA8_FDC_SUPERIO) + SLOT_INTERFACE("fdc_xt", ISA8_FDC_XT) + SLOT_INTERFACE("fdc_at", ISA8_FDC_AT) + SLOT_INTERFACE("fdc_smc", ISA8_FDC_SMC) + SLOT_INTERFACE("fdc_ps2", ISA8_FDC_PS2) + SLOT_INTERFACE("fdc344", ISA8_FDC344) + SLOT_INTERFACE("fdcmag", ISA8_FDCMAG) + SLOT_INTERFACE("wdxt_gen", ISA8_WDXT_GEN) + SLOT_INTERFACE("finalchs", ISA8_FINALCHS) + SLOT_INTERFACE("xtide", ISA8_XTIDE) + SLOT_INTERFACE("side116", ISA8_SIDE116) + SLOT_INTERFACE("hdc", ISA8_HDC) + SLOT_INTERFACE("adlib", ISA8_ADLIB) + SLOT_INTERFACE("hercules", ISA8_HERCULES) + SLOT_INTERFACE("gblaster", ISA8_GAME_BLASTER) + SLOT_INTERFACE("sblaster1_0", ISA8_SOUND_BLASTER_1_0) + SLOT_INTERFACE("sblaster1_5", ISA8_SOUND_BLASTER_1_5) + SLOT_INTERFACE("stereo_fx", ISA8_STEREO_FX) + SLOT_INTERFACE("mpu401", ISA8_MPU401) + SLOT_INTERFACE("ne1000", NE1000) + SLOT_INTERFACE("3c503", EL2_3C503) + SLOT_INTERFACE("lpt", ISA8_LPT) + SLOT_INTERFACE("ibm_mfc", ISA8_IBM_MFC) + SLOT_INTERFACE("wd1002a_wx1", ISA8_WD1002A_WX1) + SLOT_INTERFACE("dectalk", ISA8_DECTALK) + SLOT_INTERFACE("pds", ISA8_PDS) +SLOT_INTERFACE_END + +SLOT_INTERFACE_START( pc_isa16_cards ) + // 8-bit + SLOT_INTERFACE("mda", ISA8_MDA) + SLOT_INTERFACE("cga", ISA8_CGA) + SLOT_INTERFACE("wyse700", ISA8_WYSE700) + SLOT_INTERFACE("ega", ISA8_EGA) + SLOT_INTERFACE("pgc", ISA8_PGC) + SLOT_INTERFACE("vga", ISA8_VGA) + SLOT_INTERFACE("svga_et4k", ISA8_SVGA_ET4K) + SLOT_INTERFACE("num9rev",ISA8_NUM_9_REV) + SLOT_INTERFACE("com", ISA8_COM) + SLOT_INTERFACE("comat", ISA8_COM_AT) + SLOT_INTERFACE("fdc", ISA8_FDC_AT) + SLOT_INTERFACE("fdc344", ISA8_FDC344) + SLOT_INTERFACE("fdcmag", ISA8_FDCMAG) + SLOT_INTERFACE("hdc", ISA8_HDC) + SLOT_INTERFACE("side116", ISA8_SIDE116) + SLOT_INTERFACE("adlib", ISA8_ADLIB) + SLOT_INTERFACE("hercules", ISA8_HERCULES) + SLOT_INTERFACE("gblaster", ISA8_GAME_BLASTER) + SLOT_INTERFACE("sblaster1_0", ISA8_SOUND_BLASTER_1_0) + SLOT_INTERFACE("sblaster1_5", ISA8_SOUND_BLASTER_1_5) + SLOT_INTERFACE("stereo_fx", ISA8_STEREO_FX) + SLOT_INTERFACE("ssi2001", ISA8_SSI2001) + SLOT_INTERFACE("ne1000", NE1000) + SLOT_INTERFACE("3c503", EL2_3C503) + SLOT_INTERFACE("mpu401", ISA8_MPU401) + SLOT_INTERFACE("lpt", ISA8_LPT) + SLOT_INTERFACE("ibm_mfc", ISA8_IBM_MFC) + SLOT_INTERFACE("fdcsmc", ISA8_FDC_SMC) + SLOT_INTERFACE("dectalk", ISA8_DECTALK) + SLOT_INTERFACE("pds", ISA8_PDS) + // 16-bit + SLOT_INTERFACE("ide", ISA16_IDE) + SLOT_INTERFACE("ne2000", NE2000) + SLOT_INTERFACE("aha1542", AHA1542) + SLOT_INTERFACE("gus",ISA16_GUS) + SLOT_INTERFACE("sblaster_16", ISA16_SOUND_BLASTER_16) + SLOT_INTERFACE("svga_s3", ISA16_SVGA_S3) + SLOT_INTERFACE("s3virge", ISA16_S3VIRGE) + SLOT_INTERFACE("s3virgedx", ISA16_S3VIRGEDX) + SLOT_INTERFACE("dms3d2kp", ISA16_DMS3D2KPRO) + SLOT_INTERFACE("svga_dm",ISA16_SVGA_CIRRUS) + SLOT_INTERFACE("clgd542x",ISA16_SVGA_CIRRUS_GD542X) + SLOT_INTERFACE("gfxultra", ISA16_VGA_GFXULTRA) + SLOT_INTERFACE("gfxultrap", ISA16_SVGA_GFXULTRAPRO) + SLOT_INTERFACE("tgui9680",ISA16_SVGA_TGUI9680) + SLOT_INTERFACE("3c505", ISA16_3C505) + SLOT_INTERFACE("mach64", ISA16_SVGA_MACH64) + SLOT_INTERFACE("sb16_lle", ISA16_SB16) +SLOT_INTERFACE_END diff --git a/src/devices/bus/isa/isa_cards.h b/src/devices/bus/isa/isa_cards.h new file mode 100644 index 00000000000..5133d4772d4 --- /dev/null +++ b/src/devices/bus/isa/isa_cards.h @@ -0,0 +1,71 @@ +// license:BSD-3-Clause +// copyright-holders:Dirk Best +/********************************************************************** + + ISA cards + +**********************************************************************/ + +#pragma once + +#ifndef __ISA_CARDS_H__ +#define __ISA_CARDS_H__ + +#include "emu.h" + +// video +#include "mda.h" +#include "cga.h" +#include "aga.h" +#include "ega.h" +#include "pgc.h" +#include "vga.h" +#include "vga_ati.h" +#include "svga_cirrus.h" +#include "svga_s3.h" +#include "svga_tseng.h" +#include "svga_trident.h" +#include "num9rev.h" + +// storage +#include "fdc.h" +#include "mufdc.h" +#include "hdc.h" +#include "wdxt_gen.h" +#include "ide.h" +#include "xtide.h" +#include "side116.h" +#include "aha1542.h" +#include "wd1002a_wx1.h" + +// sound +#include "adlib.h" +#include "gblaster.h" +#include "gus.h" +#include "ibm_mfc.h" +#include "mpu401.h" +#include "sblaster.h" +#include "ssi2001.h" +#include "stereo_fx.h" +#include "dectalk.h" +#include "sb16.h" + +// network +#include "3c503.h" +#include "ne1000.h" +#include "ne2000.h" +#include "3c505.h" + +// communication ports +#include "lpt.h" +#include "com.h" +#include "pds.h" + +// other +#include "finalchs.h" + +// supported devices +SLOT_INTERFACE_EXTERN( pc_isa8_cards ); +SLOT_INTERFACE_EXTERN( pc_isa16_cards ); + +#endif // __ISA_CARDS_H__ diff --git a/src/devices/bus/isa/lpt.c b/src/devices/bus/isa/lpt.c new file mode 100644 index 00000000000..28219c8a988 --- /dev/null +++ b/src/devices/bus/isa/lpt.c @@ -0,0 +1,67 @@ +// license:BSD-3-Clause +// copyright-holders:Miodrag Milanovic +/*************************************************************************** + + IBM-PC printer interface + +***************************************************************************/ + +#include "emu.h" +#include "lpt.h" +#include "machine/pc_lpt.h" + +const device_type ISA8_LPT = &device_creator; + +isa8_lpt_device::isa8_lpt_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, ISA8_LPT, "Printer Adapter", tag, owner, clock, "isa_lpt", __FILE__), + device_isa8_card_interface(mconfig, *this) +{ +} + +static MACHINE_CONFIG_FRAGMENT( lpt_config ) + MCFG_DEVICE_ADD("lpt", PC_LPT, 0) + MCFG_PC_LPT_IRQ_HANDLER(WRITELINE(isa8_lpt_device, pc_cpu_line)) +MACHINE_CONFIG_END + +machine_config_constructor isa8_lpt_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( lpt_config ); +} + +static INPUT_PORTS_START( lpt_dsw ) + PORT_START("DSW") + PORT_DIPNAME( 0x01, 0x00, "Base address") + PORT_DIPSETTING( 0x00, "0x378" ) + PORT_DIPSETTING( 0x01, "0x278" ) +INPUT_PORTS_END + +ioport_constructor isa8_lpt_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( lpt_dsw ); +} + +void isa8_lpt_device::device_start() +{ + set_isa_device(); +} + +void isa8_lpt_device::device_reset() +{ + m_is_primary = (ioport("DSW")->read() & 1) ? false : true; + if (m_is_primary) + { + m_isa->install_device(0x0378, 0x037b, 0, 0, read8_delegate(FUNC(pc_lpt_device::read), subdevice("lpt")), write8_delegate(FUNC(pc_lpt_device::write), subdevice("lpt"))); + } + else + { + m_isa->install_device(0x0278, 0x027b, 0, 0, read8_delegate(FUNC(pc_lpt_device::read), subdevice("lpt")), write8_delegate(FUNC(pc_lpt_device::write), subdevice("lpt"))); + } +} + +WRITE_LINE_MEMBER(isa8_lpt_device::pc_cpu_line) +{ + if (is_primary()) + m_isa->irq7_w(state); + else + m_isa->irq5_w(state); +} diff --git a/src/devices/bus/isa/lpt.h b/src/devices/bus/isa/lpt.h new file mode 100644 index 00000000000..4f73b68c5d5 --- /dev/null +++ b/src/devices/bus/isa/lpt.h @@ -0,0 +1,50 @@ +// license:BSD-3-Clause +// copyright-holders:Miodrag Milanovic +/*************************************************************************** + + IBM-PC printer interface + +***************************************************************************/ + +#ifndef __ISA_LPT_H__ +#define __ISA_LPT_H__ + +#include "isa.h" + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> isa8_lpt_device + +class isa8_lpt_device : public device_t, + public device_isa8_card_interface +{ +public: + // construction/destruction + isa8_lpt_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual ioport_constructor device_input_ports() const; + + bool is_primary() { return m_is_primary; } + + WRITE_LINE_MEMBER(pc_cpu_line); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + +private: + + // internal state + bool m_is_primary; +}; + +// device type definition +extern const device_type ISA8_LPT; + +#endif /* __ISA_LPT_H__ */ diff --git a/src/devices/bus/isa/mach32.c b/src/devices/bus/isa/mach32.c new file mode 100644 index 00000000000..46121451182 --- /dev/null +++ b/src/devices/bus/isa/mach32.c @@ -0,0 +1,156 @@ +// license:BSD-3-Clause +// copyright-holders:Barry Rodewald +/* + * mach32.c + * + * Implementation of the ATi mach32 and mach64 video chips + * Based on ati_vga and mach8 + * + * Created on: 16/05/2014 + */ + +#include "mach32.h" + +const device_type ATIMACH32 = &device_creator; +const device_type ATIMACH32_8514A = &device_creator; +const device_type ATIMACH64 = &device_creator; +const device_type ATIMACH64_8514A = &device_creator; + + +/* + * mach32 + */ + +// 8514/A device +mach32_8514a_device::mach32_8514a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : mach8_device(mconfig, ATIMACH32_8514A, "ATi mach32 (2D acceleration module)", tag, owner, clock, "mach32_8514a", __FILE__) +{ +} + +mach32_8514a_device::mach32_8514a_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : mach8_device(mconfig, type, name, tag, owner, clock, shortname, source) +{ +} + + +// SVGA device +mach32_device::mach32_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : ati_vga_device(mconfig, ATIMACH32, "ATi mach32", tag, owner, clock, "mach32", __FILE__), + m_8514a(*this,"8514a") +{ +} + +mach32_device::mach32_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : ati_vga_device(mconfig, type, name, tag, owner, clock, shortname, source), + m_8514a(*this,"8514a") +{ +} + +static MACHINE_CONFIG_FRAGMENT( mach32_8514a ) + MCFG_DEVICE_ADD("8514a", ATIMACH32_8514A, 0) + MCFG_EEPROM_SERIAL_93C56_ADD("ati_eeprom") +MACHINE_CONFIG_END + +machine_config_constructor mach32_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( mach32_8514a ); +} + +void mach32_8514a_device::device_config_complete() +{ + m_vga = dynamic_cast(owner()); +} + +void mach32_8514a_device::device_start() +{ + mach8_device::device_start(); + // 017h 68800-AX + // 177h 68800-LX + // 2F7h 68800-6 + // The 68800-3 appears to return 0 for this field (undocumented) + m_chip_ID = 0x000; + m_membounds = 0; +} + +void mach32_8514a_device::device_reset() +{ +} + +void mach32_device::device_start() +{ + ati_vga_device::device_start(); +} + +void mach32_device::device_reset() +{ + ati_vga_device::device_reset(); +} + +/* + * mach64 + */ + +// 8514/A device +mach64_8514a_device::mach64_8514a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : mach32_8514a_device(mconfig, ATIMACH64_8514A, "ATi mach64 (2D acceleration module)", tag, owner, clock, "mach64_8514a", __FILE__) +{ +} + +mach64_8514a_device::mach64_8514a_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : mach32_8514a_device(mconfig, type, name, tag, owner, clock, shortname, source) +{ +} + + +// SVGA device +mach64_device::mach64_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : mach32_device(mconfig, ATIMACH64, "ATi mach64", tag, owner, clock, "mach64", __FILE__), + m_8514a(*this,"8514a") +{ +} + +mach64_device::mach64_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : mach32_device(mconfig, type, name, tag, owner, clock, shortname, source), + m_8514a(*this,"8514a") +{ +} + +static MACHINE_CONFIG_FRAGMENT( mach64_8514a ) + MCFG_DEVICE_ADD("8514a", ATIMACH64_8514A, 0) + MCFG_EEPROM_SERIAL_93C56_ADD("ati_eeprom") +MACHINE_CONFIG_END + +machine_config_constructor mach64_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( mach64_8514a ); +} + +void mach64_8514a_device::device_config_complete() +{ + m_vga = dynamic_cast(owner()); +} + +void mach64_8514a_device::device_start() +{ + mach32_8514a_device::device_start(); + // 017h 68800-AX + // 177h 68800-LX + // 2F7h 68800-6 + // The 68800-3 appears to return 0 for this field (undocumented) + m_chip_ID = 0x0000; // value is unknown for mach64 + m_membounds = 0; +} + +void mach64_8514a_device::device_reset() +{ +} + +void mach64_device::device_start() +{ + mach32_device::device_start(); +} + +void mach64_device::device_reset() +{ + mach32_device::device_reset(); +} diff --git a/src/devices/bus/isa/mach32.h b/src/devices/bus/isa/mach32.h new file mode 100644 index 00000000000..340ca31a8bb --- /dev/null +++ b/src/devices/bus/isa/mach32.h @@ -0,0 +1,176 @@ +// license:BSD-3-Clause +// copyright-holders:Barry Rodewald +/* + * mach32.h + * + * Created on: 16/05/2014 + */ + +#ifndef MACH32_H_ +#define MACH32_H_ + +#include "emu.h" +#include "video/pc_vga.h" +#include "machine/eepromser.h" + +// 8514/A module of the Mach32 +class mach32_8514a_device : public mach8_device +{ +public: + // construction/destruction + mach32_8514a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + mach32_8514a_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + DECLARE_READ16_MEMBER(mach32_chipid_r) { return m_chip_ID; } + DECLARE_WRITE16_MEMBER(mach32_clksel_w) { mach8.clksel = data; } // read only on the mach8 + DECLARE_READ16_MEMBER(mach32_mem_boundary_r) { return m_membounds; } + DECLARE_WRITE16_MEMBER(mach32_mem_boundary_w) { m_membounds = data; if(data & 0x10) logerror("ATI: Unimplemented memory boundary activated."); } + +protected: + virtual void device_start(); + virtual void device_reset(); + virtual void device_config_complete(); + + UINT16 m_chip_ID; + UINT16 m_membounds; +}; + +// main SVGA device +class mach32_device : public ati_vga_device +{ +public: + // construction/destruction + mach32_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + mach32_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + required_device m_8514a; // provides accelerated 2D drawing, derived from the Mach8 device + + // map 8514/A functions to 8514/A module + DECLARE_READ16_MEMBER(mach8_ec0_r) { return m_8514a->mach8_ec0_r(space,offset,mem_mask); } + DECLARE_WRITE16_MEMBER(mach8_ec0_w) { m_8514a->mach8_ec0_w(space,offset,data,mem_mask); } + DECLARE_READ16_MEMBER(mach8_ec1_r) { return m_8514a->mach8_ec1_r(space,offset,mem_mask); } + DECLARE_WRITE16_MEMBER(mach8_ec1_w) { m_8514a->mach8_ec1_w(space,offset,data,mem_mask); } + DECLARE_READ16_MEMBER(mach8_ec2_r) { return m_8514a->mach8_ec2_r(space,offset,mem_mask); } + DECLARE_WRITE16_MEMBER(mach8_ec2_w) { m_8514a->mach8_ec2_w(space,offset,data,mem_mask); } + DECLARE_READ16_MEMBER(mach8_ec3_r) { return m_8514a->mach8_ec3_r(space,offset,mem_mask); } + DECLARE_WRITE16_MEMBER(mach8_ec3_w) { m_8514a->mach8_ec3_w(space,offset,data,mem_mask); } + DECLARE_READ16_MEMBER(mach8_ext_fifo_r) { return m_8514a->mach8_ext_fifo_r(space,offset,mem_mask); } + DECLARE_WRITE16_MEMBER(mach8_linedraw_index_w) { m_8514a->mach8_linedraw_index_w(space,offset,data,mem_mask); } + DECLARE_READ16_MEMBER(mach8_bresenham_count_r) { return m_8514a->mach8_bresenham_count_r(space,offset,mem_mask); } + DECLARE_WRITE16_MEMBER(mach8_bresenham_count_w) { m_8514a->mach8_bresenham_count_w(space,offset,data,mem_mask); } + DECLARE_WRITE16_MEMBER(mach8_linedraw_w) { m_8514a->mach8_linedraw_w(space,offset,data,mem_mask); } + DECLARE_READ16_MEMBER(mach8_linedraw_r) { return m_8514a->mach8_linedraw_r(space,offset,mem_mask); } + DECLARE_READ16_MEMBER(mach8_scratch0_r) { return m_8514a->mach8_scratch0_r(space,offset,mem_mask); } + DECLARE_WRITE16_MEMBER(mach8_scratch0_w) { m_8514a->mach8_scratch0_w(space,offset,data,mem_mask); } + DECLARE_READ16_MEMBER(mach8_scratch1_r) { return m_8514a->mach8_scratch1_r(space,offset,mem_mask); } + DECLARE_WRITE16_MEMBER(mach8_scratch1_w) { m_8514a->mach8_scratch1_w(space,offset,data,mem_mask); } + DECLARE_READ16_MEMBER(mach8_config1_r) { return m_8514a->mach8_config1_r(space,offset,mem_mask); } + DECLARE_READ16_MEMBER(mach8_config2_r) { return m_8514a->mach8_config2_r(space,offset,mem_mask); } + DECLARE_READ16_MEMBER(mach8_sourcex_r) { return m_8514a->mach8_sourcex_r(space,offset,mem_mask); } + DECLARE_READ16_MEMBER(mach8_sourcey_r) { return m_8514a->mach8_sourcey_r(space,offset,mem_mask); } + DECLARE_WRITE16_MEMBER(mach8_ext_leftscissor_w) { m_8514a->mach8_ext_leftscissor_w(space,offset,data,mem_mask); } + DECLARE_WRITE16_MEMBER(mach8_ext_topscissor_w) { m_8514a->mach8_ext_topscissor_w(space,offset,data,mem_mask); } + + DECLARE_READ16_MEMBER(ibm8514_vtotal_r) { return m_8514a->ibm8514_vtotal_r(space,offset,mem_mask); } + DECLARE_WRITE16_MEMBER(ibm8514_vtotal_w) { m_8514a->ibm8514_vtotal_w(space,offset,data,mem_mask); } + DECLARE_READ16_MEMBER(ibm8514_htotal_r) { return m_8514a->ibm8514_htotal_r(space,offset,mem_mask); } + DECLARE_WRITE16_MEMBER(ibm8514_htotal_w) { m_8514a->ibm8514_htotal_w(space,offset,data,mem_mask); } + DECLARE_READ16_MEMBER(ibm8514_vdisp_r) { return m_8514a->ibm8514_vdisp_r(space,offset,mem_mask); } + DECLARE_WRITE16_MEMBER(ibm8514_vdisp_w) { m_8514a->ibm8514_vdisp_w(space,offset,data,mem_mask); } + DECLARE_READ16_MEMBER(ibm8514_vsync_r) { return m_8514a->ibm8514_vsync_r(space,offset,mem_mask); } + DECLARE_WRITE16_MEMBER(ibm8514_vsync_w) { m_8514a->ibm8514_vsync_w(space,offset,data,mem_mask); } + DECLARE_READ16_MEMBER(ibm8514_substatus_r) { return m_8514a->ibm8514_substatus_r(space,offset,mem_mask); } + DECLARE_WRITE16_MEMBER(ibm8514_subcontrol_w) { m_8514a->ibm8514_subcontrol_w(space,offset,data,mem_mask); } + DECLARE_READ16_MEMBER(ibm8514_subcontrol_r) { return m_8514a->ibm8514_subcontrol_r(space,offset,mem_mask); } + DECLARE_READ16_MEMBER(ibm8514_currentx_r) { return m_8514a->ibm8514_currentx_r(space,offset,mem_mask); } + DECLARE_WRITE16_MEMBER(ibm8514_currentx_w) { m_8514a->ibm8514_currentx_w(space,offset,data,mem_mask); } + DECLARE_READ16_MEMBER(ibm8514_currenty_r) { return m_8514a->ibm8514_currenty_r(space,offset,mem_mask); } + DECLARE_WRITE16_MEMBER(ibm8514_currenty_w) { m_8514a->ibm8514_currenty_w(space,offset,data,mem_mask); } + DECLARE_READ16_MEMBER(ibm8514_desty_r) { return m_8514a->ibm8514_desty_r(space,offset,mem_mask); } + DECLARE_WRITE16_MEMBER(ibm8514_desty_w) { m_8514a->ibm8514_desty_w(space,offset,data,mem_mask); } + DECLARE_READ16_MEMBER(ibm8514_destx_r) { return m_8514a->ibm8514_destx_r(space,offset,mem_mask); } + DECLARE_WRITE16_MEMBER(ibm8514_destx_w) { m_8514a->ibm8514_destx_w(space,offset,data,mem_mask); } + DECLARE_READ16_MEMBER(ibm8514_line_error_r) { return m_8514a->ibm8514_line_error_r(space,offset,mem_mask); } + DECLARE_WRITE16_MEMBER(ibm8514_line_error_w) { m_8514a->ibm8514_line_error_w(space,offset,data,mem_mask); } + DECLARE_READ16_MEMBER(ibm8514_width_r) { return m_8514a->ibm8514_width_r(space,offset,mem_mask); } + DECLARE_WRITE16_MEMBER(ibm8514_width_w) { m_8514a->ibm8514_width_w(space,offset,data,mem_mask); } + DECLARE_READ16_MEMBER(ibm8514_gpstatus_r) { return m_8514a->ibm8514_gpstatus_r(space,offset,mem_mask); } + DECLARE_WRITE16_MEMBER(ibm8514_cmd_w) { m_8514a->ibm8514_cmd_w(space,offset,data,mem_mask); } + DECLARE_READ16_MEMBER(ibm8514_ssv_r) { return m_8514a->ibm8514_ssv_r(space,offset,mem_mask); } + DECLARE_WRITE16_MEMBER(ibm8514_ssv_w) { m_8514a->ibm8514_ssv_w(space,offset,data,mem_mask); } + DECLARE_READ16_MEMBER(ibm8514_fgcolour_r) { return m_8514a->ibm8514_fgcolour_r(space,offset,mem_mask); } + DECLARE_WRITE16_MEMBER(ibm8514_fgcolour_w) { m_8514a->ibm8514_fgcolour_w(space,offset,data,mem_mask); } + DECLARE_READ16_MEMBER(ibm8514_bgcolour_r) { return m_8514a->ibm8514_bgcolour_r(space,offset,mem_mask); } + DECLARE_WRITE16_MEMBER(ibm8514_bgcolour_w) { m_8514a->ibm8514_bgcolour_w(space,offset,data,mem_mask); } + DECLARE_READ16_MEMBER(ibm8514_read_mask_r) { return m_8514a->ibm8514_read_mask_r(space,offset,mem_mask); } + DECLARE_WRITE16_MEMBER(ibm8514_read_mask_w) { m_8514a->ibm8514_read_mask_w(space,offset,data,mem_mask); } + DECLARE_READ16_MEMBER(ibm8514_write_mask_r) { return m_8514a->ibm8514_write_mask_r(space,offset,mem_mask); } + DECLARE_WRITE16_MEMBER(ibm8514_write_mask_w) { m_8514a->ibm8514_write_mask_w(space,offset,data,mem_mask); } + DECLARE_READ16_MEMBER(ibm8514_backmix_r) { return m_8514a->ibm8514_backmix_r(space,offset,mem_mask); } + DECLARE_WRITE16_MEMBER(ibm8514_backmix_w) { m_8514a->ibm8514_backmix_w(space,offset,data,mem_mask); } + DECLARE_READ16_MEMBER(ibm8514_foremix_r) { return m_8514a->ibm8514_foremix_r(space,offset,mem_mask); } + DECLARE_WRITE16_MEMBER(ibm8514_foremix_w) { m_8514a->ibm8514_foremix_w(space,offset,data,mem_mask); } + DECLARE_READ16_MEMBER(ibm8514_multifunc_r) { return m_8514a->ibm8514_multifunc_r(space,offset,mem_mask); } + DECLARE_WRITE16_MEMBER(ibm8514_multifunc_w) { m_8514a->ibm8514_multifunc_w(space,offset,data,mem_mask); } + DECLARE_READ16_MEMBER(ibm8514_pixel_xfer_r) { return m_8514a->ibm8514_pixel_xfer_r(space,offset,mem_mask); } + DECLARE_WRITE16_MEMBER(ibm8514_pixel_xfer_w) { m_8514a->ibm8514_pixel_xfer_w(space,offset,data,mem_mask); } + + DECLARE_READ16_MEMBER(mach32_chipid_r) { return m_8514a->mach32_chipid_r(space,offset,mem_mask); } + DECLARE_READ16_MEMBER(mach8_clksel_r) { return m_8514a->mach8_clksel_r(space,offset,mem_mask); } + DECLARE_WRITE16_MEMBER(mach32_clksel_w) { m_8514a->mach32_clksel_w(space,offset,data,mem_mask); } // read only on the mach8 + DECLARE_READ16_MEMBER(mach32_mem_boundary_r) { return m_8514a->mach32_mem_boundary_r(space,offset,mem_mask); } + DECLARE_WRITE16_MEMBER(mach32_mem_boundary_w) { m_8514a->mach32_mem_boundary_w(space,offset,data,mem_mask); } // read only on the mach8 + DECLARE_READ16_MEMBER(mach32_status_r) { return vga_vblank() << 1; } +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual machine_config_constructor device_mconfig_additions() const; + +private: +}; + +/* + * ATi mach64 + */ + +// 8514/A module of the Mach64 +class mach64_8514a_device : public mach32_8514a_device +{ +public: + // construction/destruction + mach64_8514a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + mach64_8514a_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + +protected: + virtual void device_start(); + virtual void device_reset(); + virtual void device_config_complete(); +}; + +// main SVGA device +class mach64_device : public mach32_device +{ +public: + // construction/destruction + mach64_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + mach64_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + required_device m_8514a; // provides accelerated 2D drawing, derived from the Mach8 device + + DECLARE_WRITE16_MEMBER(mach64_config1_w) { } // why does the mach64 BIOS write to these, they are read only on the mach32 and earlier + DECLARE_WRITE16_MEMBER(mach64_config2_w) { } + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual machine_config_constructor device_mconfig_additions() const; +}; +// device type definition +extern const device_type ATIMACH32; +extern const device_type ATIMACH32_8514A; +extern const device_type ATIMACH64; +extern const device_type ATIMACH64_8514A; + +#endif /* MACH32_H_ */ diff --git a/src/devices/bus/isa/mc1502_fdc.c b/src/devices/bus/isa/mc1502_fdc.c new file mode 100644 index 00000000000..ada13d1d4ec --- /dev/null +++ b/src/devices/bus/isa/mc1502_fdc.c @@ -0,0 +1,221 @@ +// license:BSD-3-Clause +// copyright-holders:Sergey Svishchev +/********************************************************************** + + Electronika MC 1502 FDC device + +**********************************************************************/ + +#include "mc1502_fdc.h" + +#include "cpu/i86/i86.h" +#include "formats/pc_dsk.h" + +#define VERBOSE_DBG 0 + +#define DBG_LOG(N,M,A) \ + do { \ + if(VERBOSE_DBG>=N) \ + { \ + if( M ) \ + logerror("%11.6f: %-24s",machine().time().as_double(),(char*)M ); \ + logerror A; \ + } \ + } while (0) + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type MC1502_FDC = &device_creator; + +FLOPPY_FORMATS_MEMBER( mc1502_fdc_device::floppy_formats ) + FLOPPY_PC_FORMAT +FLOPPY_FORMATS_END + +static SLOT_INTERFACE_START( mc1502_floppies ) + SLOT_INTERFACE( "525qd", FLOPPY_525_QD ) +SLOT_INTERFACE_END + +static MACHINE_CONFIG_FRAGMENT( mc1502_fdc ) + MCFG_FD1793_ADD("fdc", XTAL_16MHz / 16) + MCFG_WD_FDC_INTRQ_CALLBACK(WRITELINE(mc1502_fdc_device, mc1502_fdc_irq_drq)) + MCFG_WD_FDC_DRQ_CALLBACK(WRITELINE(mc1502_fdc_device, mc1502_fdc_irq_drq)) + MCFG_FLOPPY_DRIVE_ADD("fdc:0", mc1502_floppies, "525qd", mc1502_fdc_device::floppy_formats) + MCFG_FLOPPY_DRIVE_ADD("fdc:1", mc1502_floppies, "525qd", mc1502_fdc_device::floppy_formats) +MACHINE_CONFIG_END + +//------------------------------------------------- +// ROM( mc1502_fdc ) +//------------------------------------------------- + +ROM_START( mc1502_fdc ) +ROM_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor mc1502_fdc_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( mc1502_fdc ); +} + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *mc1502_fdc_device::device_rom_region() const +{ + return ROM_NAME( mc1502_fdc ); +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +TIMER_CALLBACK_MEMBER(mc1502_fdc_device::motor_callback) +{ + m_fdc->subdevice("0")->get_device()->mon_w(ASSERT_LINE); + m_fdc->subdevice("1")->get_device()->mon_w(ASSERT_LINE); + motor_on = 0; +} + +UINT8 mc1502_fdc_device::mc1502_wd17xx_aux_r() +{ + UINT8 data; + + data = 0; + + return data; +} + +void mc1502_fdc_device::mc1502_wd17xx_aux_w(UINT8 data) +{ + floppy_image_device *floppy0 = m_fdc->subdevice("0")->get_device(); + floppy_image_device *floppy1 = m_fdc->subdevice("1")->get_device(); + floppy_image_device *floppy = ((data & 0x10)?floppy1:floppy0); + + // master reset + if((data & 1) == 0) + m_fdc->reset(); + + m_fdc->set_floppy(floppy); + + // SIDE ONE + floppy->ss_w((data & 2)?1:0); + + // bits 2, 3 -- motor on (drive 0, 1) + floppy0->mon_w(!(data & 4)); + floppy1->mon_w(!(data & 8)); + + if (data & 12) { + motor_timer->adjust(attotime::from_msec( 3000 )); + motor_on = 1; + } + +} + +/* + * Accesses to this port block (halt the CPU until DRQ, INTRQ or MOTOR ON) + */ +UINT8 mc1502_fdc_device::mc1502_wd17xx_drq_r() +{ + cpu_device *maincpu = machine().device("maincpu"); + + if (!m_fdc->drq_r() && !m_fdc->intrq_r()) { + // fake cpu wait by resetting PC one insn back + maincpu->set_state_int(I8086_IP, maincpu->state_int(I8086_IP) - 1); + maincpu->set_input_line(INPUT_LINE_HALT, ASSERT_LINE); + } + + return m_fdc->drq_r(); +} + +UINT8 mc1502_fdc_device::mc1502_wd17xx_motor_r() +{ + return motor_on; +} + +WRITE_LINE_MEMBER( mc1502_fdc_device::mc1502_fdc_irq_drq ) +{ + cpu_device *maincpu = machine().device("maincpu"); + + if(state) + maincpu->set_input_line(INPUT_LINE_HALT, CLEAR_LINE); +} + +READ8_MEMBER( mc1502_fdc_device::mc1502_fdc_r ) +{ + UINT8 data = 0xff; + + switch( offset ) + { + case 0: data = mc1502_wd17xx_aux_r(); break; + case 8: data = mc1502_wd17xx_drq_r(); break; + case 10: data = mc1502_wd17xx_motor_r(); break; + } + + return data; +} + +READ8_MEMBER( mc1502_fdc_device::mc1502_fdcv2_r ) +{ + UINT8 data = 0xff; + + switch( offset ) + { + case 0: data = mc1502_wd17xx_aux_r(); break; + case 1: data = mc1502_wd17xx_motor_r(); break; + case 2: data = mc1502_wd17xx_drq_r(); break; + } + + return data; +} + +WRITE8_MEMBER( mc1502_fdc_device::mc1502_fdc_w ) +{ + switch( offset ) + { + case 0: mc1502_wd17xx_aux_w(data); break; + } +} + +//------------------------------------------------- +// mc1502_fdc_device - constructor +//------------------------------------------------- + +mc1502_fdc_device::mc1502_fdc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, MC1502_FDC, "MC-1502 floppy", tag, owner, clock, "mc1502_fdc", __FILE__), + device_isa8_card_interface( mconfig, *this ), + m_fdc(*this, "fdc") +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void mc1502_fdc_device::device_start() +{ + set_isa_device(); + + // BIOS 5.0-5.2x + m_isa->install_device(0x010c, 0x010f, 0, 0, + READ8_DEVICE_DELEGATE(m_fdc, fd1793_t, read), + WRITE8_DEVICE_DELEGATE(m_fdc, fd1793_t, write) ); + m_isa->install_device(0x0100, 0x010b, 0, 0, read8_delegate( FUNC(mc1502_fdc_device::mc1502_fdc_r), this ), write8_delegate( FUNC(mc1502_fdc_device::mc1502_fdc_w), this ) ); + + // BIOS 5.3x + m_isa->install_device(0x0048, 0x004b, 0, 0, + READ8_DEVICE_DELEGATE(m_fdc, fd1793_t, read), + WRITE8_DEVICE_DELEGATE(m_fdc, fd1793_t, write) ); + m_isa->install_device(0x004c, 0x004f, 0, 0, read8_delegate( FUNC(mc1502_fdc_device::mc1502_fdcv2_r), this ), write8_delegate( FUNC(mc1502_fdc_device::mc1502_fdc_w), this ) ); + + motor_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(mc1502_fdc_device::motor_callback),this)); + motor_on = 0; +} diff --git a/src/devices/bus/isa/mc1502_fdc.h b/src/devices/bus/isa/mc1502_fdc.h new file mode 100644 index 00000000000..344b4df9ff0 --- /dev/null +++ b/src/devices/bus/isa/mc1502_fdc.h @@ -0,0 +1,65 @@ +// license:BSD-3-Clause +// copyright-holders:Sergey Svishchev +/********************************************************************** + + Electronika MC 1502 FDC device + +**********************************************************************/ + +#pragma once + +#ifndef __MC1502_FDC__ +#define __MC1502_FDC__ + +#include "emu.h" + +#include "imagedev/flopdrv.h" +#include "isa.h" +#include "machine/wd_fdc.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class mc1502_fdc_device : public device_t, + public device_isa8_card_interface +{ +public: + // construction/destruction + mc1502_fdc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual const rom_entry *device_rom_region() const; + + DECLARE_FLOPPY_FORMATS( floppy_formats ); + TIMER_CALLBACK_MEMBER( motor_callback ); + + DECLARE_READ8_MEMBER(mc1502_fdc_r); + DECLARE_READ8_MEMBER(mc1502_fdcv2_r); + DECLARE_WRITE8_MEMBER(mc1502_fdc_w); + DECLARE_WRITE_LINE_MEMBER( mc1502_fdc_irq_drq ); + +protected: + // device-level overrides + virtual void device_start(); + +private: + required_device m_fdc; + int motor_on; + emu_timer *motor_timer; + +public: + void mc1502_wd17xx_aux_w(UINT8 data); + UINT8 mc1502_wd17xx_aux_r(); + UINT8 mc1502_wd17xx_drq_r(); + UINT8 mc1502_wd17xx_motor_r(); + +}; + + +// device type definition +extern const device_type MC1502_FDC; + + +#endif diff --git a/src/devices/bus/isa/mc1502_rom.c b/src/devices/bus/isa/mc1502_rom.c new file mode 100644 index 00000000000..9a12c5ec712 --- /dev/null +++ b/src/devices/bus/isa/mc1502_rom.c @@ -0,0 +1,71 @@ +// license:BSD-3-Clause +// copyright-holders:Sergey Svishchev +/********************************************************************** + + MC-1502 ROM cartridge device + +**********************************************************************/ + +#include "mc1502_rom.h" + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type MC1502_ROM = &device_creator; + + +//------------------------------------------------- +// ROM( mc1502_rom ) +//------------------------------------------------- + +ROM_START( mc1502_rom ) + ROM_REGION( 0x8000, "mc1502_rom", 0 ) + ROM_LOAD( "basic.rom", 0x00000, 0x8000, CRC(173d69fa) SHA1(003f872e12f00800e22ab6bbc009d36bfde67b9d)) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *mc1502_rom_device::device_rom_region() const +{ + return ROM_NAME( mc1502_rom ); +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// mc1502_rom_device - constructor +//------------------------------------------------- + +mc1502_rom_device::mc1502_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, MC1502_ROM, "MC-1502 ROM cart", tag, owner, clock, "mc1502_rom", __FILE__), + device_isa8_card_interface( mconfig, *this ) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void mc1502_rom_device::device_start() +{ + set_isa_device(); + m_isa->install_rom(this, 0xe8000, 0xeffff, 0, 0, "XXX", "mc1502_rom"); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void mc1502_rom_device::device_reset() +{ +} diff --git a/src/devices/bus/isa/mc1502_rom.h b/src/devices/bus/isa/mc1502_rom.h new file mode 100644 index 00000000000..9e426d93ab3 --- /dev/null +++ b/src/devices/bus/isa/mc1502_rom.h @@ -0,0 +1,42 @@ +// license:BSD-3-Clause +// copyright-holders:Sergey Svishchev +/********************************************************************** + + MC-1502 ROM cartridge device + +**********************************************************************/ + +#pragma once + +#ifndef __MC1502_ROM__ +#define __MC1502_ROM__ + +#include "emu.h" +#include "isa.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class mc1502_rom_device : public device_t, + public device_isa8_card_interface +{ +public: + // construction/destruction + mc1502_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); +}; + + +// device type definition +extern const device_type MC1502_ROM; + + +#endif diff --git a/src/devices/bus/isa/mda.c b/src/devices/bus/isa/mda.c new file mode 100644 index 00000000000..1d8991cab7a --- /dev/null +++ b/src/devices/bus/isa/mda.c @@ -0,0 +1,981 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol, Miodrag Milanovic +/*************************************************************************** + + Monochrome Display Adapter (MDA) section + +***************************************************************************/ + +#include "emu.h" +#include "mda.h" +#include "video/mc6845.h" +#include "machine/pc_lpt.h" + +#define MDA_SCREEN_NAME "mda_screen" +#define MDA_MC6845_NAME "mc6845_mda" + +/* + Hercules video card + */ +#define HERCULES_SCREEN_NAME "hercules_screen" +#define HERCULES_MC6845_NAME "mc6845_hercules" + +#define VERBOSE_MDA 0 /* MDA (Monochrome Display Adapter) */ + +#define MDA_CLOCK 16257000 + +#define MDA_LOG(N,M,A) \ + do { \ + if(VERBOSE_MDA>=N) \ + { \ + if( M ) \ + logerror("%11.6f: %-24s",machine().time().as_double(),(char*)M ); \ + logerror A; \ + } \ + } while (0) + +static const unsigned char mda_palette[4][3] = +{ + { 0x00,0x00,0x00 }, + { 0x00,0x55,0x00 }, + { 0x00,0xaa,0x00 }, + { 0x00,0xff,0x00 } +}; + +enum +{ + MDA_TEXT_INTEN = 0, + MDA_TEXT_BLINK, + HERCULES_GFX_BLINK, + MDA_LOWRES_TEXT_INTEN, + MDA_LOWRES_TEXT_BLINK +}; + +/* F4 Character Displayer */ +static const gfx_layout pc_16_charlayout = +{ + 8, 16, /* 8 x 16 characters */ + 256, /* 256 characters */ + 1, /* 1 bits per pixel */ + { 0 }, /* no bitplanes */ + /* x offsets */ + { 0, 1, 2, 3, 4, 5, 6, 7 }, + /* y offsets */ + { 0*8, 1*8, 2*8, 3*8, 4*8, 5*8, 6*8, 7*8, 2048*8, 2049*8, 2050*8, 2051*8, 2052*8, 2053*8, 2054*8, 2055*8 }, + 8*8 /* every char takes 2 x 8 bytes */ +}; + +static const gfx_layout pc_8_charlayout = +{ + 8, 8, /* 8 x 8 characters */ + 512, /* 512 characters */ + 1, /* 1 bits per pixel */ + { 0 }, /* no bitplanes */ + /* x offsets */ + { 0, 1, 2, 3, 4, 5, 6, 7 }, + /* y offsets */ + { 0*8, 1*8, 2*8, 3*8, 4*8, 5*8, 6*8, 7*8 }, + 8*8 /* every char takes 8 bytes */ +}; + +static GFXDECODE_START( pcmda ) + GFXDECODE_ENTRY( "gfx1", 0x0000, pc_16_charlayout, 1, 1 ) + GFXDECODE_ENTRY( "gfx1", 0x1000, pc_8_charlayout, 1, 1 ) +GFXDECODE_END + + +WRITE_LINE_MEMBER(isa8_mda_device::pc_cpu_line) +{ + m_isa->irq7_w(state); +} + + +MACHINE_CONFIG_FRAGMENT( pcvideo_mda ) + MCFG_SCREEN_ADD( MDA_SCREEN_NAME, RASTER) + MCFG_SCREEN_RAW_PARAMS(MDA_CLOCK, 882, 0, 720, 370, 0, 350 ) + MCFG_SCREEN_UPDATE_DEVICE( MDA_MC6845_NAME, mc6845_device, screen_update ) + + MCFG_PALETTE_ADD( "palette", 4 ) + + MCFG_MC6845_ADD(MDA_MC6845_NAME, MC6845, MDA_SCREEN_NAME, MDA_CLOCK/9) + MCFG_MC6845_SHOW_BORDER_AREA(false) + MCFG_MC6845_CHAR_WIDTH(9) + MCFG_MC6845_UPDATE_ROW_CB(isa8_mda_device, crtc_update_row) + MCFG_MC6845_OUT_HSYNC_CB(WRITELINE(isa8_mda_device, hsync_changed)) + MCFG_MC6845_OUT_VSYNC_CB(WRITELINE(isa8_mda_device, vsync_changed)) + + MCFG_GFXDECODE_ADD("gfxdecode", "palette", pcmda) + + MCFG_DEVICE_ADD("lpt", PC_LPT, 0) + MCFG_PC_LPT_IRQ_HANDLER(WRITELINE(isa8_mda_device, pc_cpu_line)) +MACHINE_CONFIG_END + +ROM_START( mda ) + /* IBM 1501981(CGA) and 1501985(MDA) Character rom */ + ROM_REGION(0x08100,"gfx1", 0) + ROM_LOAD("5788005.u33", 0x00000, 0x02000, CRC(0bf56d70) SHA1(c2a8b10808bf51a3c123ba3eb1e9dd608231916f)) /* "AMI 8412PI // 5788005 // (C) IBM CORP. 1981 // KOREA" */ +ROM_END + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type ISA8_MDA = &device_creator; + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor isa8_mda_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( pcvideo_mda ); +} + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *isa8_mda_device::device_rom_region() const +{ + return ROM_NAME( mda ); +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// isa8_mda_device - constructor +//------------------------------------------------- + +isa8_mda_device::isa8_mda_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, ISA8_MDA, "IBM Monochrome Display and Printer Adapter", tag, owner, clock, "isa_ibm_mda", __FILE__), + device_isa8_card_interface(mconfig, *this), + m_update_row_type(-1), + m_palette(*this, "palette") +{ +} + +isa8_mda_device::isa8_mda_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_isa8_card_interface(mconfig, *this), + m_update_row_type(-1), + m_palette(*this, "palette") +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void isa8_mda_device::device_start() +{ + if (m_palette != NULL && !m_palette->started()) + throw device_missing_dependencies(); + + set_isa_device(); + m_videoram.resize(0x1000); + m_isa->install_device(0x3b0, 0x3bf, 0, 0, read8_delegate( FUNC(isa8_mda_device::io_read), this ), write8_delegate( FUNC(isa8_mda_device::io_write), this ) ); + m_isa->install_bank(0xb0000, 0xb0fff, 0, 0x07000, "bank_mda", &m_videoram[0]); + + /* Initialise the mda palette */ + for(int i = 0; i < 4; i++) + m_palette->set_pen_color(i, rgb_t(mda_palette[i][0], mda_palette[i][1], mda_palette[i][2])); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void isa8_mda_device::device_reset() +{ + m_framecnt = 0; + m_mode_control = 0; + m_vsync = 0; + m_hsync = 0; + m_pixel = 0; + + m_chr_gen = memregion(subtag("gfx1").c_str())->base(); +} + +/*************************************************************************** + + Monochrome Display Adapter (MDA) section + +***************************************************************************/ + +/*************************************************************************** + Draw text mode with 80x25 characters (default) and intense background. + The character cell size is 9x15. Column 9 is column 8 repeated for + character codes 176 to 223. +***************************************************************************/ + +MC6845_UPDATE_ROW( isa8_mda_device::mda_text_inten_update_row ) +{ + const rgb_t *palette = m_palette->palette()->entry_list_raw(); + UINT32 *p = &bitmap.pix32(y); + UINT16 chr_base = ( ra & 0x08 ) ? 0x800 | ( ra & 0x07 ) : ra; + int i; + + if ( y == 0 ) MDA_LOG(1,"mda_text_inten_update_row",("\n")); + for ( i = 0; i < x_count; i++ ) + { + UINT16 offset = ( ( ma + i ) << 1 ) & 0x0FFF; + UINT8 chr = m_videoram[ offset ]; + UINT8 attr = m_videoram[ offset + 1 ]; + UINT8 data = m_chr_gen[ chr_base + chr * 8 ]; + UINT8 fg = ( attr & 0x08 ) ? 3 : 2; + UINT8 bg = 0; + + if ( ( attr & ~0x88 ) == 0 ) + { + data = 0x00; + } + + switch( attr ) + { + case 0x70: + bg = 2; + fg = 0; + break; + case 0x78: + bg = 2; + fg = 1; + break; + case 0xF0: + bg = 3; + fg = 0; + break; + case 0xF8: + bg = 3; + fg = 1; + break; + } + + if ( ( i == cursor_x && ( m_framecnt & 0x08 ) ) || ( attr & 0x07 ) == 0x01 ) + { + data = 0xFF; + } + + *p = palette[( data & 0x80 ) ? fg : bg]; p++; + *p = palette[( data & 0x40 ) ? fg : bg]; p++; + *p = palette[( data & 0x20 ) ? fg : bg]; p++; + *p = palette[( data & 0x10 ) ? fg : bg]; p++; + *p = palette[( data & 0x08 ) ? fg : bg]; p++; + *p = palette[( data & 0x04 ) ? fg : bg]; p++; + *p = palette[( data & 0x02 ) ? fg : bg]; p++; + *p = palette[( data & 0x01 ) ? fg : bg]; p++; + if ( ( chr & 0xE0 ) == 0xC0 ) + { + *p = palette[( data & 0x01 ) ? fg : bg]; p++; + } + else + { + *p = palette[bg]; p++; + } + } +} + + +/*************************************************************************** + Draw text mode with 80x25 characters (default) and blinking characters. + The character cell size is 9x15. Column 9 is column 8 repeated for + character codes 176 to 223. +***************************************************************************/ + +MC6845_UPDATE_ROW( isa8_mda_device::mda_text_blink_update_row ) +{ + const rgb_t *palette = m_palette->palette()->entry_list_raw(); + UINT32 *p = &bitmap.pix32(y); + UINT16 chr_base = ( ra & 0x08 ) ? 0x800 | ( ra & 0x07 ) : ra; + int i; + + if ( y == 0 ) MDA_LOG(1,"mda_text_blink_update_row",("\n")); + for ( i = 0; i < x_count; i++ ) + { + UINT16 offset = ( ( ma + i ) << 1 ) & 0x0FFF; + UINT8 chr = m_videoram[ offset ]; + UINT8 attr = m_videoram[ offset + 1 ]; + UINT8 data = m_chr_gen[ chr_base + chr * 8 ]; + UINT8 fg = ( attr & 0x08 ) ? 3 : 2; + UINT8 bg = 0; + + if ( ( attr & ~0x88 ) == 0 ) + { + data = 0x00; + } + + switch( attr ) + { + case 0x70: + case 0xF0: + bg = 2; + fg = 0; + break; + case 0x78: + case 0xF8: + bg = 2; + fg = 1; + break; + } + + if ( ( attr & 0x07 ) == 0x01 ) + { + data = 0xFF; + } + + if ( i == cursor_x ) + { + if ( m_framecnt & 0x08 ) + { + data = 0xFF; + } + } + else + { + if ( ( attr & 0x80 ) && ( m_framecnt & 0x10 ) ) + { + data = 0x00; + } + } + + *p = palette[( data & 0x80 ) ? fg : bg]; p++; + *p = palette[( data & 0x40 ) ? fg : bg]; p++; + *p = palette[( data & 0x20 ) ? fg : bg]; p++; + *p = palette[( data & 0x10 ) ? fg : bg]; p++; + *p = palette[( data & 0x08 ) ? fg : bg]; p++; + *p = palette[( data & 0x04 ) ? fg : bg]; p++; + *p = palette[( data & 0x02 ) ? fg : bg]; p++; + *p = palette[( data & 0x01 ) ? fg : bg]; p++; + if ( ( chr & 0xE0 ) == 0xC0 ) + { + *p = palette[( data & 0x01 ) ? fg : bg]; p++; + } + else + { + *p = palette[bg]; p++; + } + } +} + + +MC6845_UPDATE_ROW( isa8_mda_device::crtc_update_row ) +{ + if (m_update_row_type == -1) + return; + + switch (m_update_row_type) + { + case MDA_TEXT_INTEN: + mda_text_inten_update_row(bitmap, cliprect, ma, ra, y, x_count, cursor_x, de, hbp, vbp); + break; + case MDA_TEXT_BLINK: + mda_text_blink_update_row(bitmap, cliprect, ma, ra, y, x_count, cursor_x, de, hbp, vbp); + break; + } +} + + +MC6845_UPDATE_ROW( isa8_hercules_device::crtc_update_row ) +{ + if (m_update_row_type == -1) + return; + + switch (m_update_row_type) + { + case HERCULES_GFX_BLINK: + hercules_gfx_update_row(bitmap, cliprect, ma, ra, y, x_count, cursor_x, de, hbp, vbp); + break; + default: + isa8_mda_device::crtc_update_row(bitmap, cliprect, ma, ra, y, x_count, cursor_x, de, hbp, vbp); + break; + } +} + + +WRITE_LINE_MEMBER( isa8_mda_device::hsync_changed ) +{ + m_hsync = state ? 1 : 0; +} + + +WRITE_LINE_MEMBER( isa8_mda_device::vsync_changed ) +{ + m_vsync = state ? 0x80 : 0; + if ( state ) + { + m_framecnt++; + } +} + + +/* + * rW MDA mode control register (see #P138) + */ +WRITE8_MEMBER( isa8_mda_device::mode_control_w ) +{ + m_mode_control = data; + + switch( m_mode_control & 0x2a ) + { + case 0x08: + m_update_row_type = MDA_TEXT_INTEN; + break; + case 0x28: + m_update_row_type = MDA_TEXT_BLINK; + break; + default: + m_update_row_type = -1; + } +} + + +/* R- CRT status register (see #P139) + * (EGA/VGA) input status 1 register + * 7 HGC vertical sync in progress + * 6-4 adapter 000 hercules + * 001 hercules+ + * 101 hercules InColor + * else unknown + * 3 pixel stream (0 black, 1 white) + * 2-1 reserved + * 0 horizontal drive enable + */ +READ8_MEMBER( isa8_mda_device::status_r) +{ + // Faking pixel stream here + m_pixel++; + + return 0xF0 | (m_pixel & 0x08) | m_hsync; +} + + +/************************************************************************* + * + * MDA + * monochrome display adapter + * + *************************************************************************/ +WRITE8_MEMBER( isa8_mda_device::io_write) +{ + mc6845_device *mc6845 = subdevice(MDA_MC6845_NAME); + pc_lpt_device *lpt = subdevice("lpt"); + switch( offset ) + { + case 0: case 2: case 4: case 6: + mc6845->address_w( space, offset, data ); + break; + case 1: case 3: case 5: case 7: + mc6845->register_w( space, offset, data ); + break; + case 8: + mode_control_w(space, offset, data); + break; + case 12: case 13: case 14: + lpt->write(space, offset - 12, data); + break; + } +} + +READ8_MEMBER( isa8_mda_device::io_read) +{ + int data = 0xff; + mc6845_device *mc6845 = subdevice(MDA_MC6845_NAME); + pc_lpt_device *lpt = subdevice("lpt"); + switch( offset ) + { + case 0: case 2: case 4: case 6: + /* return last written mc6845 address value here? */ + break; + case 1: case 3: case 5: case 7: + data = mc6845->register_r( space, offset ); + break; + case 10: + data = status_r(space, offset); + break; + /* 12, 13, 14 are the LPT ports */ + case 12: case 13: case 14: + data = lpt->read(space, offset - 12); + break; + } + return data; +} + + +/*************************************************************************** + + Hercules Display Adapter section (re-uses parts from the MDA section) + +***************************************************************************/ + +/* +When the Hercules changes to graphics mode, the number of pixels per access and +clock divider should be changed. The currect mc6845 implementation does not +allow this. + +The divder/pixels per 6845 clock is 9 for text mode and 16 for graphics mode. +*/ + +static GFXDECODE_START( pcherc ) + GFXDECODE_ENTRY( "gfx1", 0x0000, pc_16_charlayout, 1, 1 ) +GFXDECODE_END + +MACHINE_CONFIG_FRAGMENT( pcvideo_hercules ) + MCFG_SCREEN_ADD( HERCULES_SCREEN_NAME, RASTER) + MCFG_SCREEN_RAW_PARAMS(MDA_CLOCK, 882, 0, 720, 370, 0, 350 ) + MCFG_SCREEN_UPDATE_DEVICE( HERCULES_MC6845_NAME, mc6845_device, screen_update ) + + MCFG_PALETTE_ADD( "palette", 4 ) + + MCFG_MC6845_ADD(HERCULES_MC6845_NAME, MC6845, HERCULES_SCREEN_NAME, MDA_CLOCK/9) + MCFG_MC6845_SHOW_BORDER_AREA(false) + MCFG_MC6845_CHAR_WIDTH(9) + MCFG_MC6845_UPDATE_ROW_CB(isa8_hercules_device, crtc_update_row) + MCFG_MC6845_OUT_HSYNC_CB(WRITELINE(isa8_mda_device, hsync_changed)) + MCFG_MC6845_OUT_VSYNC_CB(WRITELINE(isa8_mda_device, vsync_changed)) + + MCFG_GFXDECODE_ADD("gfxdecode", "palette", pcherc) + + MCFG_DEVICE_ADD("lpt", PC_LPT, 0) + MCFG_PC_LPT_IRQ_HANDLER(WRITELINE(isa8_mda_device, pc_cpu_line)) +MACHINE_CONFIG_END + +ROM_START( hercules ) + ROM_REGION(0x1000,"gfx1", 0) + ROM_LOAD("um2301.bin", 0x00000, 0x1000, CRC(0827bdac) SHA1(15f1aceeee8b31f0d860ff420643e3c7f29b5ffc)) +ROM_END + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type ISA8_HERCULES = &device_creator; + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor isa8_hercules_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( pcvideo_hercules ); +} + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *isa8_hercules_device::device_rom_region() const +{ + return ROM_NAME( hercules ); +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// isa8_hercules_device - constructor +//------------------------------------------------- + +isa8_hercules_device::isa8_hercules_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + isa8_mda_device(mconfig, ISA8_HERCULES, "Hercules Graphics Card", tag, owner, clock, "isa_hercules", __FILE__) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void isa8_hercules_device::device_start() +{ + if (m_palette != NULL && !m_palette->started()) + throw device_missing_dependencies(); + + m_videoram.resize(0x10000); + set_isa_device(); + m_isa->install_device(0x3b0, 0x3bf, 0, 0, read8_delegate( FUNC(isa8_hercules_device::io_read), this ), write8_delegate( FUNC(isa8_hercules_device::io_write), this ) ); + m_isa->install_bank(0xb0000, 0xbffff, 0, 0, "bank_hercules", &m_videoram[0]); + + /* Initialise the mda palette */ + for(int i = 0; i < (sizeof(mda_palette) / 3); i++) + m_palette->set_pen_color(i, mda_palette[i][0], mda_palette[i][1], mda_palette[i][2]); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void isa8_hercules_device::device_reset() +{ + isa8_mda_device::device_reset(); + m_configuration_switch = 0; + + m_chr_gen = memregion(subtag("gfx1").c_str())->base(); +} + +/*************************************************************************** + Draw graphics with 720x348 pixels (default); so called Hercules gfx. + The memory layout is divided into 4 banks where of size 0x2000. + Every bank holds data for every n'th scanline, 8 pixels per byte, + bit 7 being the leftmost. +***************************************************************************/ + +MC6845_UPDATE_ROW( isa8_hercules_device::hercules_gfx_update_row ) +{ + const rgb_t *palette = m_palette->palette()->entry_list_raw(); + UINT32 *p = &bitmap.pix32(y); + UINT16 gfx_base = ( ( m_mode_control & 0x80 ) ? 0x8000 : 0x0000 ) | ( ( ra & 0x03 ) << 13 ); + int i; + if ( y == 0 ) MDA_LOG(1,"hercules_gfx_update_row",("\n")); + for ( i = 0; i < x_count; i++ ) + { + UINT8 data = m_videoram[ gfx_base + ( ( ma + i ) << 1 ) ]; + + *p = palette[( data & 0x80 ) ? 2 : 0]; p++; + *p = palette[( data & 0x40 ) ? 2 : 0]; p++; + *p = palette[( data & 0x20 ) ? 2 : 0]; p++; + *p = palette[( data & 0x10 ) ? 2 : 0]; p++; + *p = palette[( data & 0x08 ) ? 2 : 0]; p++; + *p = palette[( data & 0x04 ) ? 2 : 0]; p++; + *p = palette[( data & 0x02 ) ? 2 : 0]; p++; + *p = palette[( data & 0x01 ) ? 2 : 0]; p++; + + data = m_videoram[ gfx_base + ( ( ma + i ) << 1 ) + 1 ]; + + *p = palette[( data & 0x80 ) ? 2 : 0]; p++; + *p = palette[( data & 0x40 ) ? 2 : 0]; p++; + *p = palette[( data & 0x20 ) ? 2 : 0]; p++; + *p = palette[( data & 0x10 ) ? 2 : 0]; p++; + *p = palette[( data & 0x08 ) ? 2 : 0]; p++; + *p = palette[( data & 0x04 ) ? 2 : 0]; p++; + *p = palette[( data & 0x02 ) ? 2 : 0]; p++; + *p = palette[( data & 0x01 ) ? 2 : 0]; p++; + } +} + + +WRITE8_MEMBER( isa8_hercules_device::mode_control_w ) +{ + mc6845_device *mc6845 = subdevice(HERCULES_MC6845_NAME); + + m_mode_control = data; + + switch( m_mode_control & 0x2a ) + { + case 0x08: + m_update_row_type = MDA_TEXT_INTEN; + break; + case 0x28: + m_update_row_type = MDA_TEXT_BLINK; + break; + case 0x0A: /* Hercules modes */ + case 0x2A: + m_update_row_type = HERCULES_GFX_BLINK; + break; + default: + m_update_row_type = -1; + } + + mc6845->set_clock( m_mode_control & 0x02 ? MDA_CLOCK / 16 : MDA_CLOCK / 9 ); + mc6845->set_hpixels_per_column( m_mode_control & 0x02 ? 16 : 9 ); +} + + +WRITE8_MEMBER( isa8_hercules_device::io_write ) +{ + mc6845_device *mc6845 = subdevice(HERCULES_MC6845_NAME); + pc_lpt_device *lpt = subdevice("lpt"); + switch( offset ) + { + case 0: case 2: case 4: case 6: + mc6845->address_w( space, offset, data ); + break; + case 1: case 3: case 5: case 7: + mc6845->register_w( space, offset, data ); + break; + case 8: + mode_control_w(space, offset, data); + break; + case 12: case 13: case 14: + lpt->write(space, offset - 12, data); + break; + case 15: + m_configuration_switch = data; + break; + } +} + + +/* R- CRT status register (see #P139) + * (EGA/VGA) input status 1 register + * 7 HGC vertical sync in progress + * 6-4 adapter 000 hercules + * 001 hercules+ + * 101 hercules InColor + * else unknown + * 3 pixel stream (0 black, 1 white) + * 2-1 reserved + * 0 horizontal drive enable + */ +READ8_MEMBER( isa8_hercules_device::status_r ) +{ + // Faking pixel stream here + m_pixel++; + + return m_vsync | ( m_pixel & 0x08 ) | m_hsync; +} + + +READ8_MEMBER( isa8_hercules_device::io_read ) +{ + int data = 0xff; + mc6845_device *mc6845 = subdevice(HERCULES_MC6845_NAME); + pc_lpt_device *lpt = subdevice("lpt"); + switch( offset ) + { + case 0: case 2: case 4: case 6: + /* return last written mc6845 address value here? */ + break; + case 1: case 3: case 5: case 7: + data = mc6845->register_r( space, offset ); + break; + case 10: + data = status_r(space, offset); + break; + /* 12, 13, 14 are the LPT ports */ + case 12: case 13: case 14: + data = lpt->read(space, offset - 12); + break; + } + return data; +} + +// XXX +MACHINE_CONFIG_FRAGMENT( pcvideo_ec1840_0002 ) + MCFG_SCREEN_ADD( MDA_SCREEN_NAME, RASTER) + MCFG_SCREEN_RAW_PARAMS(MDA_CLOCK, 792, 0, 640, 370, 0, 350 ) + MCFG_SCREEN_UPDATE_DEVICE( MDA_MC6845_NAME, mc6845_device, screen_update ) + + MCFG_PALETTE_ADD( "palette", 4 ) + + MCFG_MC6845_ADD( MDA_MC6845_NAME, MC6845, MDA_SCREEN_NAME, MDA_CLOCK/8) + MCFG_MC6845_SHOW_BORDER_AREA(false) + MCFG_MC6845_CHAR_WIDTH(8) + MCFG_MC6845_UPDATE_ROW_CB(isa8_mda_device, crtc_update_row) + MCFG_MC6845_OUT_HSYNC_CB(WRITELINE(isa8_mda_device, hsync_changed)) + MCFG_MC6845_OUT_VSYNC_CB(WRITELINE(isa8_mda_device, vsync_changed)) +MACHINE_CONFIG_END + +const device_type ISA8_EC1840_0002 = &device_creator; + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor isa8_ec1840_0002_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( pcvideo_ec1840_0002 ); +} + +//------------------------------------------------- +// isa8_ec1840_0002_device - constructor +//------------------------------------------------- + +isa8_ec1840_0002_device::isa8_ec1840_0002_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + isa8_mda_device( mconfig, ISA8_EC1840_0002, "EC 1840.0002 (MDA)", tag, owner, clock, "ec1840_0002", __FILE__) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void isa8_ec1840_0002_device::device_start() +{ + isa8_mda_device::device_start(); + + m_soft_chr_gen = auto_alloc_array(machine(), UINT8, 0x2000); + m_isa->install_bank(0xdc000, 0xddfff, 0, 0x2000, "bank_chargen", m_soft_chr_gen); +} + +void isa8_ec1840_0002_device::device_reset() +{ + isa8_mda_device::device_reset(); + + m_chr_gen = m_soft_chr_gen; +} + + +/*************************************************************************** + Draw text mode with 80x25 characters (default) and intense background. + The character cell size is 8x14. +***************************************************************************/ + +MC6845_UPDATE_ROW( isa8_ec1840_0002_device::mda_lowres_text_inten_update_row ) +{ + const rgb_t *palette = m_palette->palette()->entry_list_raw(); + UINT32 *p = &bitmap.pix32(y); + UINT16 chr_base = ra; + int i; + + if ( y == 0 ) MDA_LOG(1,"mda_lowres_text_inten_update_row",("\n")); + for ( i = 0; i < x_count; i++ ) + { + UINT16 offset = ( ( ma + i ) << 1 ) & 0x0FFF; + UINT8 chr = m_videoram[ offset ]; + UINT8 attr = m_videoram[ offset + 1 ]; + UINT8 data = m_chr_gen[ (chr_base + chr * 16) << 1 ]; + UINT8 fg = ( attr & 0x08 ) ? 3 : 2; + UINT8 bg = 0; + + if ( ( attr & ~0x88 ) == 0 ) + { + data = 0x00; + } + + switch( attr ) + { + case 0x70: + bg = 2; + fg = 0; + break; + case 0x78: + bg = 2; + fg = 1; + break; + case 0xF0: + bg = 3; + fg = 0; + break; + case 0xF8: + bg = 3; + fg = 1; + break; + } + + if ( ( i == cursor_x && ( m_framecnt & 0x08 ) ) || ( attr & 0x07 ) == 0x01 ) + { + data = 0xFF; + } + + *p = palette[( data & 0x80 ) ? fg : bg]; p++; + *p = palette[( data & 0x40 ) ? fg : bg]; p++; + *p = palette[( data & 0x20 ) ? fg : bg]; p++; + *p = palette[( data & 0x10 ) ? fg : bg]; p++; + *p = palette[( data & 0x08 ) ? fg : bg]; p++; + *p = palette[( data & 0x04 ) ? fg : bg]; p++; + *p = palette[( data & 0x02 ) ? fg : bg]; p++; + *p = palette[( data & 0x01 ) ? fg : bg]; p++; + } +} + + +/*************************************************************************** + Draw text mode with 80x25 characters (default) and blinking characters. + The character cell size is 8x14. +***************************************************************************/ + +MC6845_UPDATE_ROW( isa8_ec1840_0002_device::mda_lowres_text_blink_update_row ) +{ + const rgb_t *palette = m_palette->palette()->entry_list_raw(); + UINT32 *p = &bitmap.pix32(y); + UINT16 chr_base = ra; + int i; + + if ( y == 0 ) MDA_LOG(1,"mda_lowres_text_blink_update_row",("\n")); + for ( i = 0; i < x_count; i++ ) + { + UINT16 offset = ( ( ma + i ) << 1 ) & 0x0FFF; + UINT8 chr = m_videoram[ offset ]; + UINT8 attr = m_videoram[ offset + 1 ]; + UINT8 data = m_chr_gen[ (chr_base + chr * 16) << 1 ]; + UINT8 fg = ( attr & 0x08 ) ? 3 : 2; + UINT8 bg = 0; + + if ( ( attr & ~0x88 ) == 0 ) + { + data = 0x00; + } + + switch( attr ) + { + case 0x70: + case 0xF0: + bg = 2; + fg = 0; + break; + case 0x78: + case 0xF8: + bg = 2; + fg = 1; + break; + } + + if ( ( attr & 0x07 ) == 0x01 ) + { + data = 0xFF; + } + + if ( i == cursor_x ) + { + if ( m_framecnt & 0x08 ) + { + data = 0xFF; + } + } + else + { + if ( ( attr & 0x80 ) && ( m_framecnt & 0x10 ) ) + { + data = 0x00; + } + } + + *p = palette[( data & 0x80 ) ? fg : bg]; p++; + *p = palette[( data & 0x40 ) ? fg : bg]; p++; + *p = palette[( data & 0x20 ) ? fg : bg]; p++; + *p = palette[( data & 0x10 ) ? fg : bg]; p++; + *p = palette[( data & 0x08 ) ? fg : bg]; p++; + *p = palette[( data & 0x04 ) ? fg : bg]; p++; + *p = palette[( data & 0x02 ) ? fg : bg]; p++; + *p = palette[( data & 0x01 ) ? fg : bg]; p++; + } +} + +WRITE8_MEMBER( isa8_ec1840_0002_device::mode_control_w ) +{ + m_mode_control = data; + + switch( m_mode_control & 0x2a ) + { + case 0x08: + m_update_row_type = MDA_LOWRES_TEXT_INTEN; + break; + case 0x28: + m_update_row_type = MDA_LOWRES_TEXT_BLINK; + break; + default: + m_update_row_type = -1; + } +} + +MC6845_UPDATE_ROW( isa8_ec1840_0002_device::crtc_update_row ) +{ + if (m_update_row_type == -1) + return; + + switch (m_update_row_type) + { + case MDA_LOWRES_TEXT_INTEN: + mda_lowres_text_inten_update_row(bitmap, cliprect, ma, ra, y, x_count, cursor_x, de, hbp, vbp); + break; + case MDA_LOWRES_TEXT_BLINK: + mda_lowres_text_blink_update_row(bitmap, cliprect, ma, ra, y, x_count, cursor_x, de, hbp, vbp); + break; + } +} diff --git a/src/devices/bus/isa/mda.h b/src/devices/bus/isa/mda.h new file mode 100644 index 00000000000..8c62520308b --- /dev/null +++ b/src/devices/bus/isa/mda.h @@ -0,0 +1,132 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol, Miodrag Milanovic +#pragma once + +#ifndef __ISA_MDA_H__ +#define __ISA_MDA_H__ + +#include "emu.h" +#include "isa.h" +#include "video/mc6845.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> isa8_mda_device + +class isa8_mda_device : public device_t, + public device_isa8_card_interface +{ +public: + friend class isa8_hercules_device; + + // construction/destruction + isa8_mda_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + isa8_mda_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual const rom_entry *device_rom_region() const; + + DECLARE_WRITE_LINE_MEMBER(hsync_changed); + DECLARE_WRITE_LINE_MEMBER(vsync_changed); + virtual DECLARE_READ8_MEMBER(io_read); + virtual DECLARE_WRITE8_MEMBER(io_write); + virtual DECLARE_READ8_MEMBER(status_r); + virtual DECLARE_WRITE8_MEMBER(mode_control_w); + + WRITE_LINE_MEMBER(pc_cpu_line); + + virtual MC6845_UPDATE_ROW( crtc_update_row ); + MC6845_UPDATE_ROW( mda_text_inten_update_row ); + MC6845_UPDATE_ROW( mda_text_blink_update_row ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); +public: + int m_framecnt; + + UINT8 m_mode_control; + + int m_update_row_type; + UINT8 *m_chr_gen; + UINT8 m_vsync; + UINT8 m_hsync; + dynamic_buffer m_videoram; + UINT8 m_pixel; + required_device m_palette; +}; + + +// device type definition +extern const device_type ISA8_MDA; + +// ======================> isa8_hercules_device + +class isa8_hercules_device : + public isa8_mda_device +{ +public: + // construction/destruction + isa8_hercules_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual const rom_entry *device_rom_region() const; + + virtual DECLARE_READ8_MEMBER(io_read); + virtual DECLARE_WRITE8_MEMBER(io_write); + virtual DECLARE_READ8_MEMBER(status_r); + virtual DECLARE_WRITE8_MEMBER(mode_control_w); + + virtual MC6845_UPDATE_ROW( crtc_update_row ); + MC6845_UPDATE_ROW( hercules_gfx_update_row ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + +private: + // internal state +public: + UINT8 m_configuration_switch; //hercules +}; + + +// device type definition +extern const device_type ISA8_HERCULES; + +// ======================> isa8_ec1840_0002_device + +class isa8_ec1840_0002_device : + public isa8_mda_device +{ +public: + // construction/destruction + isa8_ec1840_0002_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + + virtual DECLARE_WRITE8_MEMBER(mode_control_w); + + virtual MC6845_UPDATE_ROW( crtc_update_row ); + MC6845_UPDATE_ROW( mda_lowres_text_inten_update_row ); + MC6845_UPDATE_ROW( mda_lowres_text_blink_update_row ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + +public: + UINT8 *m_soft_chr_gen; + +}; + +// device type definition +extern const device_type ISA8_EC1840_0002; + +#endif /* __ISA_MDA_H__ */ diff --git a/src/devices/bus/isa/mpu401.c b/src/devices/bus/isa/mpu401.c new file mode 100644 index 00000000000..420a753b750 --- /dev/null +++ b/src/devices/bus/isa/mpu401.c @@ -0,0 +1,93 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont,Kevin Horton +/*************************************************************************** + + MPU-401 MIDI device interface + + TODO: + - skeleton, doesn't do anything + +***************************************************************************/ + +#include "emu.h" +#include "mpu401.h" +#include "machine/pic8259.h" + +#define MPU_CORE_TAG "mpu401" + +MACHINE_CONFIG_FRAGMENT( isa8mpu401 ) + MCFG_MPU401_ADD(MPU_CORE_TAG, WRITELINE(isa8_mpu401_device, mpu_irq_out)) +MACHINE_CONFIG_END + +/* +DIP-SWs +1-2-3-4 + 0x200 + 1 0x210 + 1 0x220 +... +1 1 1 0x330 (default) +... +1 1 1 1 0x370 + +5-6-7-8 +1 irq2 (default) + 1 irq3 + 1 irq5 + 1 irq7 +*/ + +WRITE_LINE_MEMBER( isa8_mpu401_device::mpu_irq_out ) +{ +} + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type ISA8_MPU401 = &device_creator; + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor isa8_mpu401_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( isa8mpu401 ); +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// isa8_adlib_device - constructor +//------------------------------------------------- + +isa8_mpu401_device::isa8_mpu401_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, ISA8_MPU401, "Roland MPU-401 MIDI Interface", tag, owner, clock, "isa_mpu401", __FILE__), + device_isa8_card_interface( mconfig, *this ), + m_mpu401(*this, MPU_CORE_TAG) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void isa8_mpu401_device::device_start() +{ + set_isa_device(); + + m_isa->install_device(0x330, 0x0331, 0, 0, READ8_DEVICE_DELEGATE(m_mpu401, mpu401_device, mpu_r), WRITE8_DEVICE_DELEGATE(m_mpu401, mpu401_device, mpu_w)); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void isa8_mpu401_device::device_reset() +{ +} diff --git a/src/devices/bus/isa/mpu401.h b/src/devices/bus/isa/mpu401.h new file mode 100644 index 00000000000..b31bb3a2308 --- /dev/null +++ b/src/devices/bus/isa/mpu401.h @@ -0,0 +1,46 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont,Kevin Horton +#pragma once + +#ifndef __ISA_MPU401_H__ +#define __ISA_MPU401_H__ + +#include "emu.h" +#include "isa.h" +#include "machine/mpu401.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> isa8_mpu401_device + +class isa8_mpu401_device : + public device_t, + public device_isa8_card_interface +{ +public: + // construction/destruction + isa8_mpu401_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + required_device m_mpu401; + + // called back by the MPU401 core to set the IRQ line state + DECLARE_WRITE_LINE_MEMBER(mpu_irq_out); + + // optional information overrides +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual machine_config_constructor device_mconfig_additions() const; + +private: + // internal state +}; + + +// device type definition +extern const device_type ISA8_MPU401; + +#endif /* __ISA_MPU401_H__ */ diff --git a/src/devices/bus/isa/mufdc.c b/src/devices/bus/isa/mufdc.c new file mode 100644 index 00000000000..0a983dc7a2e --- /dev/null +++ b/src/devices/bus/isa/mufdc.c @@ -0,0 +1,203 @@ +// license:BSD-3-Clause +// copyright-holders:Dirk Best +/*************************************************************************** + + Multi Unique FDC + + 8-bit floppy controller, supports 4 drives with 360k, 720k, + 1.2MB or 1.44MB. It was sold under a few different names: + + - Ably-Tech FDC-344 + - Magitronic Multi Floppy Controller Card + - Micro-Q (same as FDC-344?) + - Modular Circuit Technology MCT-FDC-HD4 (not dumped) + +***************************************************************************/ + +#include "mufdc.h" +#include "formats/naslite_dsk.h" +#include "formats/pc_dsk.h" + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type ISA8_FDC344 = &device_creator; +const device_type ISA8_FDCMAG = &device_creator; + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +FLOPPY_FORMATS_MEMBER( mufdc_device::floppy_formats ) + FLOPPY_PC_FORMAT, + FLOPPY_NASLITE_FORMAT +FLOPPY_FORMATS_END + +static SLOT_INTERFACE_START( drives ) + SLOT_INTERFACE("525hd", FLOPPY_525_HD) + SLOT_INTERFACE("35hd", FLOPPY_35_HD) + SLOT_INTERFACE("525dd", FLOPPY_525_DD) + SLOT_INTERFACE("35dd", FLOPPY_35_DD) +SLOT_INTERFACE_END + +static MACHINE_CONFIG_FRAGMENT( mufdc_device ) + MCFG_MCS3201_ADD("fdc") + MCFG_MCS3201_INPUT_HANDLER(READ8(mufdc_device, fdc_input_r)) + MCFG_UPD765_INTRQ_CALLBACK(WRITELINE(mufdc_device, fdc_irq_w)) + MCFG_UPD765_DRQ_CALLBACK(WRITELINE(mufdc_device, fdc_drq_w)) + MCFG_FLOPPY_DRIVE_ADD("fdc:0", drives, "35hd", mufdc_device::floppy_formats) + MCFG_FLOPPY_DRIVE_ADD("fdc:1", drives, "35hd", mufdc_device::floppy_formats) + MCFG_FLOPPY_DRIVE_ADD("fdc:2", drives, NULL, mufdc_device::floppy_formats) + MCFG_FLOPPY_DRIVE_ADD("fdc:3", drives, NULL, mufdc_device::floppy_formats) +MACHINE_CONFIG_END + +machine_config_constructor mufdc_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( mufdc_device ); +} + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +static INPUT_PORTS_START( mufdc_device ) + PORT_START("configuration") + PORT_DIPNAME(0x03, 0x02, "FDC FDD 1") + PORT_DIPLOCATION("SW:1,2") + PORT_DIPSETTING(0x01, "360KB") + PORT_DIPSETTING(0x03, "720KB") + PORT_DIPSETTING(0x00, "1.2MB") + PORT_DIPSETTING(0x02, "1.44MB") + PORT_DIPNAME(0x0c, 0x08, "FDC FDD 2") + PORT_DIPLOCATION("SW:3,4") + PORT_DIPSETTING(0x04, "360KB") + PORT_DIPSETTING(0x0c, "720KB") + PORT_DIPSETTING(0x00, "1.2MB") + PORT_DIPSETTING(0x08, "1.44MB") + PORT_DIPNAME(0x30, 0x20, "FDC FDD 3") + PORT_DIPLOCATION("SW:5,6") + PORT_DIPSETTING(0x10, "360KB") + PORT_DIPSETTING(0x30, "720KB") + PORT_DIPSETTING(0x00, "1.2MB") + PORT_DIPSETTING(0x20, "1.44MB") + PORT_DIPNAME(0xc0, 0x80, "FDC FDD 4") + PORT_DIPLOCATION("SW:7,8") + PORT_DIPSETTING(0x40, "360KB") + PORT_DIPSETTING(0xc0, "720KB") + PORT_DIPSETTING(0x00, "1.2MB") + PORT_DIPSETTING(0x80, "1.44MB") +INPUT_PORTS_END + +ioport_constructor mufdc_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( mufdc_device ); +} + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +ROM_START( fdc344 ) + ROM_REGION(0x4000, "option", 0) + ROM_LOAD("fdc344_42.u2", 0x0000, 0x4000, CRC(3e02567c) SHA1(b639d92435ecf2a6d4aefd3576a6955028f6bde7)) +ROM_END + +const rom_entry *fdc344_device::device_rom_region() const +{ + return ROM_NAME( fdc344 ); +} + +ROM_START( fdcmag ) + ROM_REGION(0x2000, "option", 0) + ROM_LOAD("magitronic_40.u2", 0x0000, 0x2000, CRC(41a5371b) SHA1(9c4443169a0b104395404274470e62b8b65efcf4)) +ROM_END + +const rom_entry *fdcmag_device::device_rom_region() const +{ + return ROM_NAME( fdcmag ); +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// mufdc_device - constructor +//------------------------------------------------- + +mufdc_device::mufdc_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, UINT32 clock, const char *name, const char *shortname) : + device_t(mconfig, type, name, tag, owner, clock, shortname, __FILE__), + device_isa8_card_interface( mconfig, *this ), + m_fdc(*this, "fdc"), + m_config(*this, "configuration") +{ +} + +fdc344_device::fdc344_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + mufdc_device(mconfig, ISA8_FDC344, tag, owner, clock, "Ably-Tech FDC-344", "fdc344") +{ +} + +fdcmag_device::fdcmag_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + mufdc_device(mconfig, ISA8_FDCMAG, tag, owner, clock, "Magitronic Multi Floppy Controller Card", "fdcmag") +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void mufdc_device::device_start() +{ + set_isa_device(); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void mufdc_device::device_reset() +{ + m_isa->install_rom(this, 0xc8000, 0xc9fff, 0, 0, m_shortname.c_str(), "option"); + m_isa->install_device(0x3f0, 0x3f7, *m_fdc, &pc_fdc_interface::map); + m_isa->set_dma_channel(2, this, true); +} + + +//************************************************************************** +// FDC INTERFACE +//************************************************************************** + +READ8_MEMBER( mufdc_device::fdc_input_r ) +{ + return ~m_config->read(); +} + +WRITE_LINE_MEMBER( mufdc_device::fdc_irq_w ) +{ + m_isa->irq6_w(state ? ASSERT_LINE : CLEAR_LINE); +} + +WRITE_LINE_MEMBER( mufdc_device::fdc_drq_w ) +{ + m_isa->drq2_w(state ? ASSERT_LINE : CLEAR_LINE); +} + +UINT8 mufdc_device::dack_r(int line) +{ + return m_fdc->dma_r(); +} + +void mufdc_device::dack_w(int line, UINT8 data) +{ + return m_fdc->dma_w(data); +} + +void mufdc_device::eop_w(int state) +{ + m_fdc->tc_w(state == ASSERT_LINE); +} diff --git a/src/devices/bus/isa/mufdc.h b/src/devices/bus/isa/mufdc.h new file mode 100644 index 00000000000..bf33d8f4a6d --- /dev/null +++ b/src/devices/bus/isa/mufdc.h @@ -0,0 +1,94 @@ +// license:BSD-3-Clause +// copyright-holders:Dirk Best +/*************************************************************************** + + Multi Unique FDC + + 8-bit floppy controller, supports 4 drives with 360k, 720k, + 1.2MB or 1.44MB. It was sold under a few different names: + + - Ably-Tech FDC-344 + - Magitronic Multi Floppy Controller Card + - Micro-Q (same as FDC-344?) + - Modular Circuit Technology MCT-FDC-HD4 (not dumped) + +***************************************************************************/ + +#pragma once + +#ifndef __ISA_MUFDC_H__ +#define __ISA_MUFDC_H__ + +#include "emu.h" +#include "isa.h" +#include "imagedev/floppy.h" +#include "machine/upd765.h" + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> mufdc_device + +class mufdc_device : public device_t, + public device_isa8_card_interface +{ +public: + // construction/destruction + mufdc_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, UINT32 clock, const char *name, const char *shortname); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual ioport_constructor device_input_ports() const; + + DECLARE_FLOPPY_FORMATS( floppy_formats ); + + DECLARE_READ8_MEMBER( fdc_input_r ); + DECLARE_WRITE_LINE_MEMBER( fdc_irq_w ); + DECLARE_WRITE_LINE_MEMBER( fdc_drq_w ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_isa8_card_interface + virtual UINT8 dack_r(int line); + virtual void dack_w(int line, UINT8 data); + virtual void eop_w(int state); + +private: + required_device m_fdc; + required_ioport m_config; +}; + +class fdc344_device : public mufdc_device +{ +public: + // construction/destruction + fdc344_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual const rom_entry *device_rom_region() const; + +protected: + virtual void device_config_complete() { m_shortname = "fdc344"; } +}; + +class fdcmag_device : public mufdc_device +{ +public: + // construction/destruction + fdcmag_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual const rom_entry *device_rom_region() const; + +protected: + virtual void device_config_complete() { m_shortname = "fdcmag"; } +}; + +// device type definition +extern const device_type ISA8_FDC344; +extern const device_type ISA8_FDCMAG; + +#endif diff --git a/src/devices/bus/isa/ne1000.c b/src/devices/bus/isa/ne1000.c new file mode 100644 index 00000000000..a62d5e71f8f --- /dev/null +++ b/src/devices/bus/isa/ne1000.c @@ -0,0 +1,133 @@ +// license:BSD-3-Clause +// copyright-holders:Carl +#include "emu.h" +#include "ne1000.h" + +static MACHINE_CONFIG_FRAGMENT(ne1000_config) + MCFG_DEVICE_ADD("dp8390d", DP8390D, 0) + MCFG_DP8390D_IRQ_CB(WRITELINE(ne1000_device, ne1000_irq_w)) + MCFG_DP8390D_MEM_READ_CB(READ8(ne1000_device, ne1000_mem_read)) + MCFG_DP8390D_MEM_WRITE_CB(WRITE8(ne1000_device, ne1000_mem_write)) +MACHINE_CONFIG_END + +const device_type NE1000 = &device_creator; + +machine_config_constructor ne1000_device::device_mconfig_additions() const { + return MACHINE_CONFIG_NAME(ne1000_config); +} + +ne1000_device::ne1000_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, NE1000, "NE1000 Network Adapter", tag, owner, clock, "ne1000", __FILE__), + device_isa8_card_interface(mconfig, *this), + m_dp8390(*this, "dp8390d") { +} + +void ne1000_device::device_start() { + char mac[7]; + UINT32 num = rand(); + memset(m_prom, 0x57, 16); + sprintf(mac+2, "\x1b%c%c%c", (num >> 16) & 0xff, (num >> 8) & 0xff, num & 0xff); + mac[0] = 0; mac[1] = 0; // avoid gcc warning + memcpy(m_prom, mac, 6); + m_dp8390->set_mac(mac); + set_isa_device(); + m_isa->install_device(0x0300, 0x031f, 0, 0, read8_delegate(FUNC(ne1000_device::ne1000_port_r), this), write8_delegate(FUNC(ne1000_device::ne1000_port_w), this)); +} + +void ne1000_device::device_reset() { + memcpy(m_prom, m_dp8390->get_mac(), 6); + m_irq = ioport("CONFIG")->read() & 3; +} + +READ8_MEMBER(ne1000_device::ne1000_port_r) { + if(offset < 16) { + m_dp8390->dp8390_cs(CLEAR_LINE); + return m_dp8390->dp8390_r(space, offset, mem_mask); + } + switch(offset) { + case 16: + m_dp8390->dp8390_cs(ASSERT_LINE); + return m_dp8390->dp8390_r(space, offset, mem_mask); + case 31: + m_dp8390->dp8390_reset(CLEAR_LINE); + return 0; + default: + logerror("ne1000: invalid register read %02X\n", offset); + } + return 0; +} + +WRITE8_MEMBER(ne1000_device::ne1000_port_w) { + if(offset < 16) { + m_dp8390->dp8390_cs(CLEAR_LINE); + m_dp8390->dp8390_w(space, offset, data, mem_mask); + return; + } + switch(offset) { + case 16: + m_dp8390->dp8390_cs(ASSERT_LINE); + m_dp8390->dp8390_w(space, offset, data, mem_mask); + return; + case 31: + m_dp8390->dp8390_reset(ASSERT_LINE); + return; + default: + logerror("ne1000: invalid register write %02X\n", offset); + } + return; +} + +WRITE_LINE_MEMBER(ne1000_device::ne1000_irq_w) { + switch(m_irq) { + case 0: + m_isa->irq2_w(state); + break; + case 1: + m_isa->irq3_w(state); + break; + case 2: + m_isa->irq4_w(state); + break; + case 3: + m_isa->irq5_w(state); + break; + } +} + +READ8_MEMBER(ne1000_device::ne1000_mem_read) { + offset &= ~0xc000; // verify + if(offset < 16) return m_prom[offset]; + if((offset < (8*1024)) || (offset >= (16*1024))) { + logerror("ne1000: invalid memory read %04X\n", offset); + return 0xff; + } + return m_board_ram[offset - (8*1024)]; +} + +WRITE8_MEMBER(ne1000_device::ne1000_mem_write) { + offset &= ~0xc000; // verify + if((offset < (8*1024)) || (offset >= (16*1024))) { + logerror("ne1000: invalid memory write %04X\n", offset); + return; + } + m_board_ram[offset - (8*1024)] = data; +} + +static INPUT_PORTS_START( ne1000 ) + PORT_START("CONFIG") + PORT_CONFNAME(0x03, 0x01, "NE1000 IRQ jumper (W12-15)") + PORT_CONFSETTING( 0x00, "IRQ2/9") + PORT_CONFSETTING( 0x01, "IRQ3") + PORT_CONFSETTING( 0x02, "IRQ4") + PORT_CONFSETTING( 0x03, "IRQ5") + //PORT_CONFNAME(0x30, 0x00, "NE1000 IO port jumper (W9-10)") + //PORT_CONFSETTING( 0x00, "300") + //PORT_CONFSETTING( 0x10, "320") + //PORT_CONFSETTING( 0x20, "340") + //PORT_CONFSETTING( 0x30, "360") +INPUT_PORTS_END + +ioport_constructor ne1000_device::device_input_ports() const +{ + return INPUT_PORTS_NAME(ne1000); +} diff --git a/src/devices/bus/isa/ne1000.h b/src/devices/bus/isa/ne1000.h new file mode 100644 index 00000000000..c246c70d02f --- /dev/null +++ b/src/devices/bus/isa/ne1000.h @@ -0,0 +1,37 @@ +// license:BSD-3-Clause +// copyright-holders:Carl +#ifndef __NE1000_H__ +#define __NE1000_H__ + +// NE1000 is 8bit has 8KB ram; NE2000 is 16bit has 16KB ram + +#include "emu.h" +#include "isa.h" +#include "machine/dp8390.h" + +class ne1000_device: public device_t, + public device_isa8_card_interface +{ +public: + ne1000_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual machine_config_constructor device_mconfig_additions() const; + virtual ioport_constructor device_input_ports() const; + + void ne1000_irq_w(int state); + DECLARE_READ8_MEMBER(ne1000_mem_read); + DECLARE_WRITE8_MEMBER(ne1000_mem_write); + DECLARE_READ8_MEMBER(ne1000_port_r); + DECLARE_WRITE8_MEMBER(ne1000_port_w); +protected: + virtual void device_start(); + virtual void device_reset(); +private: + required_device m_dp8390; + UINT8 m_irq; + UINT8 m_board_ram[8*1024]; + UINT8 m_prom[16]; +}; + +extern const device_type NE1000; + +#endif diff --git a/src/devices/bus/isa/ne2000.c b/src/devices/bus/isa/ne2000.c new file mode 100644 index 00000000000..b635f8e736c --- /dev/null +++ b/src/devices/bus/isa/ne2000.c @@ -0,0 +1,144 @@ +// license:BSD-3-Clause +// copyright-holders:Carl +#include "emu.h" +#include "ne2000.h" + + +static MACHINE_CONFIG_FRAGMENT(ne2000_config) + MCFG_DEVICE_ADD("dp8390d", DP8390D, 0) + MCFG_DP8390D_IRQ_CB(WRITELINE(ne2000_device, ne2000_irq_w)) + MCFG_DP8390D_MEM_READ_CB(READ8(ne2000_device, ne2000_mem_read)) + MCFG_DP8390D_MEM_WRITE_CB(WRITE8(ne2000_device, ne2000_mem_write)) +MACHINE_CONFIG_END + +const device_type NE2000 = &device_creator; + +machine_config_constructor ne2000_device::device_mconfig_additions() const { + return MACHINE_CONFIG_NAME(ne2000_config); +} + +ne2000_device::ne2000_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, NE2000, "NE2000 Network Adapter", tag, owner, clock, "ne2000", __FILE__), + device_isa16_card_interface(mconfig, *this), + m_dp8390(*this, "dp8390d") { +} + +void ne2000_device::device_start() { + char mac[7]; + UINT32 num = rand(); + memset(m_prom, 0x57, 16); + sprintf(mac+2, "\x1b%c%c%c", (num >> 16) & 0xff, (num >> 8) & 0xff, num & 0xff); + mac[0] = 0; mac[1] = 0; // avoid gcc warning + memcpy(m_prom, mac, 6); + m_dp8390->set_mac(mac); + set_isa_device(); + m_isa->install16_device(0x0300, 0x031f, 0, 0, read16_delegate(FUNC(ne2000_device::ne2000_port_r), this), write16_delegate(FUNC(ne2000_device::ne2000_port_w), this)); +} + +void ne2000_device::device_reset() { + memcpy(m_prom, m_dp8390->get_mac(), 6); + m_irq = ioport("CONFIG")->read() & 3; +} + +READ16_MEMBER(ne2000_device::ne2000_port_r) { + offset <<= 1; + if(offset < 16) { + m_dp8390->dp8390_cs(CLEAR_LINE); + return m_dp8390->dp8390_r(space, offset, 0xff) | + m_dp8390->dp8390_r(space, offset+1, 0xff) << 8; + } + if(mem_mask == 0xff00) offset++; + switch(offset) { + case 16: + m_dp8390->dp8390_cs(ASSERT_LINE); + return m_dp8390->dp8390_r(space, offset, mem_mask); + case 31: + m_dp8390->dp8390_reset(CLEAR_LINE); + return 0; + default: + logerror("ne2000: invalid register read %02X\n", offset); + } + return 0; +} + +WRITE16_MEMBER(ne2000_device::ne2000_port_w) { + offset <<= 1; + if(offset < 16) { + m_dp8390->dp8390_cs(CLEAR_LINE); + if(mem_mask == 0xff00) { + data >>= 8; + offset++; + } + m_dp8390->dp8390_w(space, offset, data & 0xff, 0xff); + if(mem_mask == 0xffff) m_dp8390->dp8390_w(space, offset+1, data>>8, 0xff); + return; + } + if(mem_mask == 0xff00) offset++; + switch(offset) { + case 16: + m_dp8390->dp8390_cs(ASSERT_LINE); + m_dp8390->dp8390_w(space, offset, data, mem_mask); + return; + case 31: + m_dp8390->dp8390_reset(ASSERT_LINE); + return; + default: + logerror("ne2000: invalid register write %02X\n", offset); + } + return; +} + +WRITE_LINE_MEMBER(ne2000_device::ne2000_irq_w) { + switch(m_irq) { + case 0: + m_isa->irq2_w(state); + break; + case 1: + m_isa->irq3_w(state); + break; + case 2: + m_isa->irq4_w(state); + break; + case 3: + m_isa->irq5_w(state); + break; + } +} + +READ8_MEMBER(ne2000_device::ne2000_mem_read) { + offset &= ~0x8000; + if(offset < 32) return m_prom[offset>>1]; + if((offset < (16*1024)) || (offset >= (32*1024))) { + logerror("ne2000: invalid memory read %04X\n", offset); + return 0xff; + } + return m_board_ram[offset - (16*1024)]; +} + +WRITE8_MEMBER(ne2000_device::ne2000_mem_write) { + offset &= ~0x8000; + if((offset < (16*1024)) || (offset >= (32*1024))) { + logerror("ne2000: invalid memory write %04X\n", offset); + return; + } + m_board_ram[offset - (16*1024)] = data; +} + +static INPUT_PORTS_START( ne2000 ) + PORT_START("CONFIG") + PORT_CONFNAME(0x03, 0x01, "NE2000 IRQ jumper (W12-15)") + PORT_CONFSETTING( 0x00, "IRQ2/9") + PORT_CONFSETTING( 0x01, "IRQ3") + PORT_CONFSETTING( 0x02, "IRQ4") + PORT_CONFSETTING( 0x03, "IRQ5") + //PORT_CONFNAME(0x30, 0x00, "NE2000 IO port jumper (W9-10)") + //PORT_CONFSETTING( 0x00, "300") + //PORT_CONFSETTING( 0x10, "320") + //PORT_CONFSETTING( 0x20, "340") + //PORT_CONFSETTING( 0x30, "360") +INPUT_PORTS_END + +ioport_constructor ne2000_device::device_input_ports() const +{ + return INPUT_PORTS_NAME(ne2000); +} diff --git a/src/devices/bus/isa/ne2000.h b/src/devices/bus/isa/ne2000.h new file mode 100644 index 00000000000..76a271dadc0 --- /dev/null +++ b/src/devices/bus/isa/ne2000.h @@ -0,0 +1,35 @@ +// license:BSD-3-Clause +// copyright-holders:Carl +#ifndef __NE2000_H__ +#define __NE2000_H__ + +#include "emu.h" +#include "isa.h" +#include "machine/dp8390.h" + +class ne2000_device: public device_t, + public device_isa16_card_interface +{ +public: + ne2000_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual machine_config_constructor device_mconfig_additions() const; + virtual ioport_constructor device_input_ports() const; + + void ne2000_irq_w(int state); + DECLARE_READ8_MEMBER(ne2000_mem_read); + DECLARE_WRITE8_MEMBER(ne2000_mem_write); + DECLARE_READ16_MEMBER(ne2000_port_r); + DECLARE_WRITE16_MEMBER(ne2000_port_w); +protected: + virtual void device_start(); + virtual void device_reset(); +private: + required_device m_dp8390; + UINT8 m_irq; + UINT8 m_board_ram[16*1024]; + UINT8 m_prom[16]; +}; + +extern const device_type NE2000; + +#endif diff --git a/src/devices/bus/isa/num9rev.c b/src/devices/bus/isa/num9rev.c new file mode 100644 index 00000000000..8e2216654fd --- /dev/null +++ b/src/devices/bus/isa/num9rev.c @@ -0,0 +1,319 @@ +// license:BSD-3-Clause +// copyright-holders:Carl +// Number Nine Revolution 512x32/1024x8 +// TODO: for 1024x768 mode the 7220 is programmed for 512x768, how does that work? + +#include "emu.h" +#include "num9rev.h" + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type ISA8_NUM_9_REV = &device_creator; + +static ADDRESS_MAP_START( upd7220_map, AS_0, 16, isa8_number_9_rev_device ) + AM_RANGE(0x00000, 0x3ffff) AM_NOP +ADDRESS_MAP_END + +UPD7220_DISPLAY_PIXELS_MEMBER( isa8_number_9_rev_device::hgdc_display_pixels ) +{ + palette_t *pal = m_palette->palette(); + if(!m_1024) + { + rgb_t color(0); + UINT16 overlay; + if(((address << 3) + 0xc0016) > (1024*1024)) + return; + for(int i = 0; i < 16; i++) + { + UINT32 addr = (address << 3) + i; + overlay = m_ram[addr + 0xc0000] << 1; + overlay = m_overlay[overlay + ((m_mode & 8) ? 512 : 0)] | (m_overlay[overlay + 1 + ((m_mode & 8) ? 512 : 0)] << 8); + color.set_r(pal->entry_color(m_ram[addr] | ((overlay & 0xf) << 8)).r()); + color.set_g(pal->entry_color(m_ram[addr + 0x40000] | ((overlay & 0xf0) << 4)).g()); + color.set_b(pal->entry_color(m_ram[addr + 0x80000] | (overlay & 0xf00)).b()); + bitmap.pix32(y, x + i) = color; + } + } + else + { + if(((address << 3) + 16) > (1024*1024)) + return; + for(int i = 0; i < 16; i++) + bitmap.pix32(y, x + i) = pal->entry_color(m_ram[(address << 4) + i]); + } +} + +static MACHINE_CONFIG_FRAGMENT( num_9_rev ) + MCFG_SCREEN_ADD("screen", RASTER) + MCFG_SCREEN_SIZE(512, 448) + MCFG_SCREEN_VISIBLE_AREA(0, 512-1, 0, 448-1) + MCFG_SCREEN_REFRESH_RATE(60) + MCFG_SCREEN_UPDATE_DRIVER(isa8_number_9_rev_device, screen_update) + MCFG_PALETTE_ADD("palette", 4096) + + MCFG_DEVICE_ADD("upd7220", UPD7220, XTAL_4_433619MHz/2) // unknown clock + MCFG_DEVICE_ADDRESS_MAP(AS_0, upd7220_map) + MCFG_UPD7220_DISPLAY_PIXELS_CALLBACK_OWNER(isa8_number_9_rev_device, hgdc_display_pixels) + MCFG_VIDEO_SET_SCREEN("screen") +MACHINE_CONFIG_END + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor isa8_number_9_rev_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( num_9_rev ); +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// isa16_vga_device - constructor +//------------------------------------------------- + +isa8_number_9_rev_device::isa8_number_9_rev_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, ISA8_NUM_9_REV, "Number Nine Revolution 512x32/1024x8", tag, owner, clock, "number_9_rev", __FILE__), + device_isa8_card_interface(mconfig, *this), + m_upd7220(*this, "upd7220"), + m_palette(*this, "palette"), + m_ram(1024*1024), + m_overlay(1024) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void isa8_number_9_rev_device::device_start() +{ + set_isa_device(); + + m_isa->install_memory(0xc0000, 0xc0001, 0, 0, read8_delegate(FUNC(upd7220_device::read), (upd7220_device *)m_upd7220), write8_delegate(FUNC(upd7220_device::write), (upd7220_device *)m_upd7220)); + m_isa->install_memory(0xc0100, 0xc03ff, 0, 0, read8_delegate(FUNC(isa8_number_9_rev_device::pal8_r), this), write8_delegate(FUNC(isa8_number_9_rev_device::pal8_w), this)); + m_isa->install_memory(0xc0400, 0xc0401, 0, 0, read8_delegate(FUNC(isa8_number_9_rev_device::bank_r), this), write8_delegate(FUNC(isa8_number_9_rev_device::bank_w), this)); + m_isa->install_memory(0xc0500, 0xc06ff, 0, 0, read8_delegate(FUNC(isa8_number_9_rev_device::overlay_r), this), write8_delegate(FUNC(isa8_number_9_rev_device::overlay_w), this)); + m_isa->install_memory(0xc0700, 0xc070f, 0, 0, read8_delegate(FUNC(isa8_number_9_rev_device::ctrl_r), this), write8_delegate(FUNC(isa8_number_9_rev_device::ctrl_w), this)); + m_isa->install_memory(0xc1000, 0xc3fff, 0, 0, read8_delegate(FUNC(isa8_number_9_rev_device::pal12_r), this), write8_delegate(FUNC(isa8_number_9_rev_device::pal12_w), this)); + m_isa->install_memory(0xa0000, 0xaffff, 0, 0, read8_delegate(FUNC(isa8_number_9_rev_device::read8), this), write8_delegate(FUNC(isa8_number_9_rev_device::write8), this)); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void isa8_number_9_rev_device::device_reset() +{ + m_bank = 0; + m_mode = 0; + m_1024 = false; +} + +READ8_MEMBER(isa8_number_9_rev_device::read8) +{ + if((m_mode & 1) && !m_1024) + return m_ram[offset + ((m_mode & 0xc) << 14)]; + else if((m_mode & 4) && !m_1024) + { + UINT32 newoff = ((offset & 3) << 18) | (m_bank << 14) | ((offset >> 2) & 0x3fff); + return m_ram[newoff]; + } + else + return m_ram[offset + (m_bank << 16)]; +} + +WRITE8_MEMBER(isa8_number_9_rev_device::write8) +{ + if(m_1024 || ((m_mode & 6) == 0)) + m_ram[offset + (m_bank << 16)] = data; + else if((m_mode & 1) || ((m_mode & 6) == 2)) + { + UINT8 bank = m_bank; + if(m_mode & 1) + bank = (m_mode & 0xc) >> 2; + else + { + if(m_bank >= 12) + { + m_ram[offset + (m_bank << 16)] = data; + return; + } + bank &= 3; + } + + m_ram[offset + (bank << 16)] = data; + m_ram[offset + ((bank + 4) << 16)] = data; + m_ram[offset + ((bank + 8) << 16)] = data; + } + else if(m_mode & 4) + { + UINT32 newoff = ((offset & 3) << 18) | (m_bank << 14) | ((offset >> 2) & 0x3fff); + if((newoff >= 0xc0000) && ((m_mode & 6) == 6)) + return; + m_ram[newoff] = data; + } +} + +READ8_MEMBER(isa8_number_9_rev_device::pal8_r) +{ + offset += 0x100; + palette_t *pal = m_palette->palette(); + switch(offset & 0xf00) + { + case 0x100: + return pal->entry_color(offset).r(); + case 0x200: + return pal->entry_color(offset).g(); + case 0x300: + return pal->entry_color(offset).b(); + } + return 0; +} + +WRITE8_MEMBER(isa8_number_9_rev_device::pal8_w) +{ + offset += 0x100; + palette_t *pal = m_palette->palette(); + rgb_t pen = pal->entry_color(offset); + switch(offset & 0xf00) + { + case 0x100: + pen.set_r(data); + break; + case 0x200: + pen.set_g(data); + break; + case 0x300: + pen.set_b(data); + break; + } + pal->entry_set_color(offset, pen); +} + +READ8_MEMBER(isa8_number_9_rev_device::pal12_r) +{ + UINT16 color = offset & 0xfff; + palette_t *pal = m_palette->palette(); + switch(offset & 0xf000) + { + case 0x0000: + return pal->entry_color(color).r(); + case 0x1000: + return pal->entry_color(color).g(); + case 0x2000: + return pal->entry_color(color).b(); + } + return 0; +} + +WRITE8_MEMBER(isa8_number_9_rev_device::pal12_w) +{ + UINT16 color = offset & 0xfff; + palette_t *pal = m_palette->palette(); + rgb_t pen = pal->entry_color(color); + switch(offset & 0xf000) + { + case 0x0000: + pen.set_r(data); + break; + case 0x1000: + pen.set_g(data); + break; + case 0x2000: + pen.set_b(data); + break; + } + pal->entry_set_color(color, pen); +} + +READ8_MEMBER(isa8_number_9_rev_device::overlay_r) +{ + return m_overlay[offset + ((m_mode & 8) ? 512 : 0)]; +} +WRITE8_MEMBER(isa8_number_9_rev_device::overlay_w) +{ + m_overlay[offset + ((m_mode & 8) ? 512 : 0)] = data; +} + +READ8_MEMBER(isa8_number_9_rev_device::bank_r) +{ + return m_bank; +} + +WRITE8_MEMBER(isa8_number_9_rev_device::bank_w) +{ + m_bank = data & 0xf; +} + +READ8_MEMBER(isa8_number_9_rev_device::ctrl_r) +{ + switch(offset & 0xf) + { + case 0: + case 1: + case 2: + case 3: + // zoom, set to same value as 7220 external zoom factor + break; + case 4: + return (m_mode & 2) ? 0xff : 0; + case 5: + return (m_mode & 4) ? 0xff : 0; + case 6: + return (m_mode & 8) ? 0xff : 0; + case 15: + return (m_mode & 1) ? 0xff : 0; + } + return 0; +} + +WRITE8_MEMBER(isa8_number_9_rev_device::ctrl_w) +{ + switch(offset & 0xf) + { + case 0: + case 1: + case 2: + case 3: + // zoom + break; + case 4: + if(data & 0x80) + m_mode |= 2; + else + m_mode &= ~2; + break; + case 5: + if(data & 0x80) + m_mode |= 4; + else + m_mode &= ~4; + break; + case 6: + if(data & 0x80) + m_mode |= 8; + else + m_mode &= ~8; + break; + case 15: + if(data & 0x80) + m_mode |= 1; + else + m_mode &= ~1; + break; + } +} + +UINT32 isa8_number_9_rev_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + rectangle visarea = screen.visible_area(); + // try to support the 1024x8 or at least don't crash as there's no way to detect it + m_1024 = (visarea.width() * visarea.height()) > (512 * 512); + return m_upd7220->screen_update(screen, bitmap, cliprect); +} diff --git a/src/devices/bus/isa/num9rev.h b/src/devices/bus/isa/num9rev.h new file mode 100644 index 00000000000..44011ddb9af --- /dev/null +++ b/src/devices/bus/isa/num9rev.h @@ -0,0 +1,63 @@ +// license:BSD-3-Clause +// copyright-holders:Carl +#pragma once + +#ifndef __NUM9REV_H__ +#define __NUM9REV_H__ + +#include "emu.h" +#include "isa.h" +#include "video/upd7220.h" +#include "machine/bankdev.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> isa16_vga_device + +class isa8_number_9_rev_device : + public device_t, + public device_isa8_card_interface +{ +public: + // construction/destruction + isa8_number_9_rev_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + + UPD7220_DISPLAY_PIXELS_MEMBER(hgdc_display_pixels); + DECLARE_READ8_MEMBER(pal8_r); + DECLARE_WRITE8_MEMBER(pal8_w); + DECLARE_READ8_MEMBER(pal12_r); + DECLARE_WRITE8_MEMBER(pal12_w); + DECLARE_READ8_MEMBER(overlay_r); + DECLARE_WRITE8_MEMBER(overlay_w); + DECLARE_READ8_MEMBER(bank_r); + DECLARE_WRITE8_MEMBER(bank_w); + DECLARE_READ8_MEMBER(ctrl_r); + DECLARE_WRITE8_MEMBER(ctrl_w); + DECLARE_READ8_MEMBER(read8); + DECLARE_WRITE8_MEMBER(write8); + + UINT32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); +private: + required_device m_upd7220; + required_device m_palette; + dynamic_buffer m_ram; + dynamic_buffer m_overlay; + + UINT8 m_bank; + UINT8 m_mode; + bool m_1024; +}; + +// device type definition +extern const device_type ISA8_NUM_9_REV; + +#endif /* __NUM9REV_H__ */ diff --git a/src/devices/bus/isa/omti8621.c b/src/devices/bus/isa/omti8621.c new file mode 100644 index 00000000000..96b1214ff85 --- /dev/null +++ b/src/devices/bus/isa/omti8621.c @@ -0,0 +1,1382 @@ +// license:BSD-3-Clause +// copyright-holders:Hans Ostermeyer, R. Belmont +/* + * omti8621.c - SMS OMTI 8621 disk controller (for Apollo DN3x00) + * + * Created on: August 30, 2010 + * Author: Hans Ostermeyer + * + * Converted to ISA device by R. Belmont + * + * see also: + * * http://www.bitsavers.org/pdf/sms/pc/OMTI_AT_Controller_Series_Jan87.pdf + */ + +#define VERBOSE 0 + +static int verbose = VERBOSE; + +#include "omti8621.h" +#include "image.h" +#include "formats/pc_dsk.h" +#include "formats/naslite_dsk.h" +#include "formats/apollo_dsk.h" + +#define LOG(x) { logerror ("%s: ", cpu_context(this)); logerror x; logerror ("\n"); } +#define LOG1(x) { if (verbose > 0) LOG(x)} +#define LOG2(x) { if (verbose > 1) LOG(x)} +#define LOG3(x) { if (verbose > 2) LOG(x)} + +#define OMTI_DISK_SECTOR_SIZE 1056 + +#define OMTI_DISK_TYPE_155_MB 0x607 // Micropolis 1355 (170 MB Dtype = 607) +#define OMTI_DISK_TYPE_348_MB 0x604 // Maxtor EXT-4380-E (380 MB Dtype = 604) +#define OMTI_DISK_TYPE_DEFAULT OMTI_DISK_TYPE_348_MB // new disks will have this type (and size) + +#define OMTI_MAX_BLOCK_COUNT 32 + +#define OMTI_DISK0_TAG "omti_disk0" +#define OMTI_DISK1_TAG "omti_disk1" + +#define OMTI_FDC_TAG "omti_fdc" + +#define OMTI_CPU_REGION "omti_cpu" +#define OMTI_BIOS_REGION "omti_bios" + +// forward declaration of image class +extern const device_type OMTI_DISK; + +class omti_disk_image_device : public device_t, + public device_image_interface +{ +public: + // construction/destruction + omti_disk_image_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // image-level overrides + virtual iodevice_t image_type() const { return IO_HARDDISK; } + + virtual bool is_readable() const { return 1; } + virtual bool is_writeable() const { return 1; } + virtual bool is_creatable() const { return 1; } + virtual bool must_be_loaded() const { return 0; } + virtual bool is_reset_on_load() const { return 0; } + virtual const char *image_interface() const { return NULL; } + virtual const char *file_extensions() const { return "awd"; } + virtual const option_guide *create_option_guide() const { return NULL; } + + virtual bool call_create(int format_type, option_resolution *format_options); +protected: + // device-level overrides + virtual void device_config_complete(); + virtual void device_start(); + virtual void device_reset(); + + void omti_disk_config(UINT16 disk_type); +public: + UINT16 m_type; + UINT16 m_cylinders; + UINT16 m_heads; + UINT16 m_sectors; + UINT32 m_sectorbytes; + UINT32 m_sector_count; + + device_image_interface *m_image; + + // configuration data + UINT8 m_config_data[10]; + + // ESDI defect list data + UINT8 m_esdi_defect_list[256]; +}; + +/* + * I/O register offsets + */ + +#define OMTI_PORT_DATA_IN 0x00 /* read, 8-bit */ +#define OMTI_PORT_DATA_OUT 0x00 /* write, 8-bit */ +#define OMTI_PORT_STATUS 0x01 /* read, 8-bit */ +#define OMTI_PORT_RESET 0x01 /* write, 8-bit */ +#define OMTI_PORT_CONFIG 0x02 /* read, 8-bit */ +#define OMTI_PORT_SELECT 0x02 /* write, 8-bit */ +#define OMTI_PORT_MASK 0x03 /* write only, 8-bit */ + +// port status + +#define OMTI_STATUS_REQ 0x01 // Request (1 = request transfer of data via data in/out register) +#define OMTI_STATUS_IO 0x02 // In/Out (1 = direction of transfer is from controller to host) +#define OMTI_STATUS_CD 0x04 // Command/Data ( 1 = byte transfered is command or status byte) +#define OMTI_STATUS_BUSY 0x08 // Busy (0 = controller is idle, 1 = controller selected) +#define OMTI_STATUS_DREQ 0x10 // Data Request (0 = no DMA request, 1 = DMA cycle requested) +#define OMTI_STATUS_IREQ 0x20 // Interrupt Request (0 = no interrupt, 1 = command complete) +#define OMTI_STATUS_NU6 0x40 // not used +#define OMTI_STATUS_NU7 0x80 // not used + +#define OMTI_CONFIG_W23 0x01 // jumper W23 +#define OMTI_CONFIG_W22 0x02 // jumper W22 +#define OMTI_CONFIG_W21 0x04 // jumper W21 +#define OMTI_CONFIG_W20 0x08 // jumper W20 + +#define OMTI_MASK_DMAE 0x01 // DMA enable +#define OMTI_MASK_INTE 0x02 // Interrupt enable + +#define OMTI_COMMAND_STATUS_ERROR 0x02 // error bit +#define OMTI_COMMAND_STATUS_LUN 0x20 // drive 0 is 0 + +#define OMTI_SENSE_CODE_NO_ERROR 0x00 +#define OMTI_SENSE_CODE_DRIVE_NOT_READY 0x04 +#define OMTI_SENSE_CODE_ADDRESS_VALID 0x80 +#define OMTI_SENSE_CODE_SECTOR_NOT_FOUND 0x14 +#define OMTI_SENSE_CODE_ECC_ERROR 0x11 +#define OMTI_SENSE_CODE_BAD_TRACK 0x19 +#define OMTI_SENSE_CODE_ALTERNATE_TRACK 0x1C +#define OMTI_SENSE_CODE_INVALID_COMMAND 0x20 +#define OMTI_SENSE_CODE_ILLEGAL_ADDRESS 0x21 + +enum { + OMTI_STATE_RESET, + OMTI_STATE_IDLE, + OMTI_STATE_SELECTION, + OMTI_STATE_COMMAND, + OMTI_STATE_DATA, + OMTI_STATE_STATUS +}; + +// OMTI commands + +#define OMTI_CMD_TEST_DRIVE_READY 0x00 +#define OMTI_CMD_RECALIBRATE 0x01 + +#define OMTI_CMD_REQUEST_SENSE 0x03 +#define OMTI_CMD_FORMAT_DRIVEUNIT 0x04 +#define OMTI_CMD_READ_VERIFY 0x05 +#define OMTI_CMD_FORMAT_TRACK 0x06 +#define OMTI_CMD_FORMAT_BAD_TRACK 0x07 +#define OMTI_CMD_READ 0x08 + +#define OMTI_CMD_WRITE 0x0a +#define OMTI_CMD_SEEK 0x0b + +#define OMTI_CMD_READ_SECTOR_BUFFER 0x0e +#define OMTI_CMD_WRITE_SECTOR_BUFFER 0x0f + +#define OMTI_CMD_ASSIGN_ALTERNATE_TRACK 0x11 + +#define OMTI_CMD_READ_DATA_TO_BUFFER 0x1e +#define OMTI_CMD_WRITE_DATA_FROM_BUFFER 0x1f +#define OMTI_CMD_COPY 0x20 + +#define OMTI_CMD_READ_ESDI_DEFECT_LIST 0x37 + +#define OMTI_CMD_RAM_DIAGNOSTICS 0xe0 +#define OMTI_CMD_CONTROLLER_INT_DIAGNOSTIC 0xe4 +#define OMTI_CMD_READ_LONG 0xe5 +#define OMTI_CMD_WRITE_LONG 0xe6 + +#define OMTI_CMD_READ_CONFIGURATION 0xec +#define OMTI_CMD_INVALID_COMMAND 0xff + +/*************************************************************************** + cpu_context - return a string describing the current CPU context + ***************************************************************************/ + +static const char *cpu_context(const device_t *device) { + static char statebuf[64]; /* string buffer containing state description */ + + device_t *cpu = device->machine().firstcpu; + + /* if we have an executing CPU, output data */ + if (cpu != NULL) { + osd_ticks_t t = osd_ticks(); + int s = t / osd_ticks_per_second(); + int ms = (t % osd_ticks_per_second()) / 1000; + + sprintf(statebuf, "%d.%03d %s pc=%08x - %s", s, ms, cpu->tag(), + cpu->safe_pcbase(), device->tag()); + } else { + strcpy(statebuf, "(no context)"); + } + return statebuf; +} + +static SLOT_INTERFACE_START( pc_hd_floppies ) + SLOT_INTERFACE( "525hd", FLOPPY_525_HD ) + SLOT_INTERFACE( "35hd", FLOPPY_35_HD ) + SLOT_INTERFACE( "525dd", FLOPPY_525_DD ) + SLOT_INTERFACE( "35dd", FLOPPY_35_DD ) +SLOT_INTERFACE_END + +MACHINE_CONFIG_FRAGMENT( omti_disk ) + MCFG_DEVICE_ADD(OMTI_DISK0_TAG, OMTI_DISK, 0) + MCFG_DEVICE_ADD(OMTI_DISK1_TAG, OMTI_DISK, 0) + + MCFG_PC_FDC_AT_ADD(OMTI_FDC_TAG) + MCFG_PC_FDC_INTRQ_CALLBACK(WRITELINE(omti8621_device, fdc_irq_w)) + MCFG_PC_FDC_DRQ_CALLBACK(WRITELINE(omti8621_device, fdc_drq_w)) + MCFG_FLOPPY_DRIVE_ADD(OMTI_FDC_TAG":0", pc_hd_floppies, "525hd", omti8621_device::floppy_formats) + MCFG_FLOPPY_DRIVE_ADD(OMTI_FDC_TAG":1", pc_hd_floppies, "525hd", omti8621_device::floppy_formats) +MACHINE_CONFIG_END + +FLOPPY_FORMATS_MEMBER( omti8621_device::floppy_formats ) + FLOPPY_APOLLO_FORMAT, + FLOPPY_PC_FORMAT, + FLOPPY_NASLITE_FORMAT +FLOPPY_FORMATS_END + +// this card has two EPROMs: a program for the on-board Z8 CPU, +// and a PC BIOS to make the card bootable on a PC. +// we have the Z8 program, we still need the PC BIOS. +ROM_START( omti8621 ) + ROM_REGION(0x4000, OMTI_CPU_REGION, 0) // disassembles fine as Z8 code + ROM_LOAD( "omti_8621_102640-b.bin", 0x000000, 0x004000, CRC(e6f20dbb) SHA1(cf1990ad72eac6b296485410f5fa3309a0d6d078) ) + + ROM_REGION(0x1000, OMTI_BIOS_REGION, 0) + ROM_LOAD("omti_bios", 0x0000, 0x1000, NO_DUMP) +ROM_END + +static INPUT_PORTS_START( omti_port ) + PORT_START("IO_BASE") + PORT_DIPNAME( 0x07, 0x04, "ESDI I/O base") + PORT_DIPSETTING( 0x00, "0320h" ) + PORT_DIPSETTING( 0x01, "0324h" ) + PORT_DIPSETTING( 0x02, "0328h" ) + PORT_DIPSETTING( 0x03, "032Ch" ) + PORT_DIPSETTING( 0x04, "01A0h" ) + PORT_DIPSETTING( 0x05, "01A4h" ) + PORT_DIPSETTING( 0x06, "01A8h" ) + PORT_DIPSETTING( 0x07, "01ACh" ) + PORT_DIPNAME( 0x08, 0x00, "Floppy I/O base") + PORT_DIPSETTING( 0x00, "03F0h" ) + PORT_DIPSETTING( 0x01, "0370h" ) + + PORT_START("BIOS_OPTS") + PORT_DIPNAME( 0x01, 0x00, "BIOS control") + PORT_DIPSETTING( 0x00, "Disabled" ) + PORT_DIPSETTING( 0x01, "Enabled" ) + PORT_DIPNAME( 0x02, 0x00, "BIOS base") + PORT_DIPSETTING( 0x00, "C8000h" ) + PORT_DIPSETTING( 0x01, "CA000h" ) +INPUT_PORTS_END + +machine_config_constructor omti8621_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( omti_disk ); +} + +const rom_entry *omti8621_device::device_rom_region() const +{ + return ROM_NAME( omti8621 ); +} + +ioport_constructor omti8621_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( omti_port ); +} + +/*------------------------------------------------- + device start callback +-------------------------------------------------*/ + +void omti8621_device::device_start() +{ + set_isa_device(); + + m_installed = false; + + sector_buffer.resize(OMTI_DISK_SECTOR_SIZE*OMTI_MAX_BLOCK_COUNT); + + m_timer = timer_alloc(0, NULL); + + our_disks[0] = subdevice(OMTI_DISK0_TAG); + our_disks[1] = subdevice(OMTI_DISK1_TAG); +} + +/*------------------------------------------------- + device reset callback +-------------------------------------------------*/ + +void omti8621_device::device_reset() +{ + static const int io_bases[8] = { 0x320, 0x324, 0x328, 0x32c, 0x1a0, 0x1a4, 0x1a8, 0x1ac }; + + LOG2(("device_reset_omti8621")); + + // you can't read I/O ports in device_start() even if they're required_ioport<> in your class! + if (!m_installed) + { + int esdi_base = io_bases[m_iobase->read() & 7]; + + // install the ESDI ports + m_isa->install16_device(esdi_base, esdi_base + 7, 0, 0, read16_delegate(FUNC(omti8621_device::read), this), write16_delegate(FUNC(omti8621_device::write), this)); + + // and the onboard AT FDC ports + if (m_iobase->read() & 8) + { + m_isa->install_device(0x0370, 0x0377, *m_fdc, &pc_fdc_interface::map); + } + else + { + m_isa->install_device(0x03f0, 0x03f7, *m_fdc, &pc_fdc_interface::map); + } + + m_isa->set_dma_channel(2, this, TRUE); + + m_installed = true; + } + + set_jumper(our_disks[0]->m_type); + + // should go from reset to idle after 100 us + // state->omti_state = OMTI_STATE_RESET; + omti_state = OMTI_STATE_IDLE; + + status_port = OMTI_STATUS_NU6 | OMTI_STATUS_NU7; + config_port = ~jumper; + mask_port = 0; + + // default the sector data buffer with model and status information + // (i.e. set sector data buffer for cmd=0x0e READ SECTOR BUFFER) + + memset(§or_buffer[0], 0, OMTI_DISK_SECTOR_SIZE); + memcpy(§or_buffer[0], "8621VB.4060487xx", 0x10); + sector_buffer[0x10] = 0; // ROM Checksum error + sector_buffer[0x11] = 0; // Processor Register error + sector_buffer[0x12] = 0; // Buffer RAM error + sector_buffer[0x13] = 0; // Sequencer Register File error + sector_buffer[0x14] = 0xc0; // 32K buffer size + // TODO: add missing Default values for LUN 0, 1 and 3 + + command_length = 0; + command_index = 0; + command_status = 0; + + data_index = 0; + data_length = 0; + + clear_sense_data(); + + diskaddr_ecc_error = 0; + diskaddr_format_bad_track = 0; + alternate_track_address[0] = 0; + alternate_track_address[1] = 0; +} + +const device_type ISA16_OMTI8621 = &device_creator; + +omti8621_device::omti8621_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, ISA16_OMTI8621, "OMTI 8621 ESDI/floppy controller", tag, owner, clock, "omti8621", __FILE__), + device_isa16_card_interface(mconfig, *this), + m_fdc(*this, OMTI_FDC_TAG), + m_iobase(*this, "IO_BASE"), + m_biosopts(*this, "BIOS_OPTS") +{ +} + +//------------------------------------------------- +// device_config_complete - perform any +// operations now that the configuration is +// complete +//------------------------------------------------- + +void omti8621_device::device_config_complete() +{ +} + +/*------------------------------------------------- + set_interrupt - update the IRQ state + -------------------------------------------------*/ + +void omti8621_device::set_interrupt(enum line_state line_state) +{ + LOG2(("set_interrupt: status_port=%x, line_state %d", status_port, line_state)); + m_isa->irq14_w(line_state); +} + +void omti8621_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + set_interrupt(ASSERT_LINE); +} + +/*************************************************************************** + clear_sense_data - clear the sense data + ***************************************************************************/ + +void omti8621_device::clear_sense_data() { + LOG2(("clear_sense_data")); + memset(sense_data, 0, sizeof(sense_data)); +} + +/*************************************************************************** + set_sense_data - set the sense data from code and command descriptor block + ***************************************************************************/ + +void omti8621_device::set_sense_data(UINT8 code, const UINT8 * cdb) { + LOG2(("set_sense_data code=%x", code)); + sense_data[0]=code; + sense_data[1]=cdb[1]; + sense_data[2]=cdb[2]; + sense_data[3]=cdb[3]; +} + +/*************************************************************************** + set_configuration_data - set the configuration data for drive lun + ***************************************************************************/ + +void omti8621_device::set_configuration_data(UINT8 lun) { + LOG2(("set_configuration_data lun=%x", lun)); + + // initialize the configuration data + omti_disk_image_device *disk = our_disks[lun]; + + disk->m_config_data[0] = (disk->m_cylinders - 1) >> 8; // Number of Cylinders (MSB) + disk->m_config_data[1] = (disk->m_cylinders - 1) & 0xff; // Number of Cylinders (LSB) (-1) + disk->m_config_data[2] = disk->m_heads - 1; // Number of Heads (-1) + disk->m_config_data[3] = disk->m_sectors - 1; // Number of Sectors (-1) + disk->m_config_data[4] = 0x02; // Drive Configuration Word (MSB) + disk->m_config_data[5] = 0x44; // Drive Configuration Word (LSB) + disk->m_config_data[6] = 0x00; // ISG AFTER INDEX + disk->m_config_data[7] = 0x00; // PLO SYN Field (ID) + disk->m_config_data[8] = 0x00; // PLO SYN Field (DATA) + disk->m_config_data[9] = 0x00; // ISG AFTER SECTOR +} + +/*************************************************************************** + get_lun - get logical unit number from a command descriptor block (in bit 5) + ***************************************************************************/ + +UINT8 omti8621_device::get_lun(const UINT8 * cdb) +{ + return (cdb[1] & 0x20) >> 5; +} + +/*************************************************************************** + check_disk_address - check disk address, set sense data and return true for no error + ***************************************************************************/ + +UINT8 omti8621_device::check_disk_address(const UINT8 *cdb) +{ + UINT8 sense_code = OMTI_SENSE_CODE_NO_ERROR; + UINT8 lun = get_lun(cdb); + UINT16 head = cdb[1] & 0x1f; + UINT16 sector = cdb[2] & 0x3f; + UINT32 cylinder = cdb[3] + ((cdb[2] & 0xc0) << 2) + ((cdb[1] & 0x80) << 3); + UINT8 block_count = cdb[4]; + omti_disk_image_device *disk = our_disks[lun]; + + UINT32 disk_track = cylinder * disk->m_heads + head; + UINT32 disk_addr = (disk_track * disk->m_sectors) + sector; + + if (block_count > OMTI_MAX_BLOCK_COUNT) { + LOG(("########### check_disk_address: unexpected block count %x", block_count)); + sense_code = OMTI_SENSE_CODE_ILLEGAL_ADDRESS | OMTI_SENSE_CODE_ADDRESS_VALID; + } + + if (lun > OMTI_MAX_LUN) { + sense_code = OMTI_SENSE_CODE_DRIVE_NOT_READY; + } else if (!disk->m_image->exists()) { + sense_code = OMTI_SENSE_CODE_DRIVE_NOT_READY; + } else if (sector >= OMTI_MAX_BLOCK_COUNT) { + sense_code = OMTI_SENSE_CODE_ILLEGAL_ADDRESS | OMTI_SENSE_CODE_ADDRESS_VALID; + } else if (head >= disk->m_heads) { + sense_code = OMTI_SENSE_CODE_ILLEGAL_ADDRESS | OMTI_SENSE_CODE_ADDRESS_VALID; + } else if (cylinder >= disk->m_cylinders) { + sense_code = OMTI_SENSE_CODE_ILLEGAL_ADDRESS | OMTI_SENSE_CODE_ADDRESS_VALID; + } else if ( disk_track == diskaddr_format_bad_track && disk_track != 0) { + sense_code = OMTI_SENSE_CODE_BAD_TRACK; + } else if (disk_addr == diskaddr_ecc_error && disk_addr != 0) { + sense_code = OMTI_SENSE_CODE_ECC_ERROR; + } else if (disk_track == alternate_track_address[1] && disk_track != 0) { + sense_code = OMTI_SENSE_CODE_ALTERNATE_TRACK; + } + + if (sense_code == OMTI_SENSE_CODE_NO_ERROR) { + clear_sense_data(); + } else { + command_status |= OMTI_COMMAND_STATUS_ERROR; + set_sense_data(sense_code, cdb); + } + return sense_code == OMTI_SENSE_CODE_NO_ERROR; +} + +/*************************************************************************** + get_disk_track - get disk track from a command descriptor block + ***************************************************************************/ + +UINT32 omti8621_device::get_disk_track(const UINT8 * cdb) { + UINT8 lun = get_lun(cdb); + UINT16 head = cdb[1] & 0x1f; + UINT32 cylinder = cdb[3] + ((cdb[2] & 0xc0) << 2) + ((cdb[1] & 0x80) << 3); + return cylinder * our_disks[lun]->m_heads + head; +} + +/*************************************************************************** + get_disk_address - get disk address from a command descriptor block + ***************************************************************************/ + +UINT32 omti8621_device::get_disk_address(const UINT8 * cdb) { + UINT8 lun = get_lun(cdb); + UINT16 sector = cdb[2] & 0x3f; + return get_disk_track(cdb) * our_disks[lun]->m_sectors + sector; +} + +/*************************************************************************** + set_data_transfer - setup for data transfer from/to data + ***************************************************************************/ + +void omti8621_device::set_data_transfer(UINT8 *data, UINT16 length) +{ + // set controller for read data transfer + omti_state = OMTI_STATE_DATA; + status_port |= OMTI_STATUS_REQ | OMTI_STATUS_IO | OMTI_STATUS_BUSY; + status_port &= ~OMTI_STATUS_CD; + + data_buffer = data; + data_length = length; + data_index = 0; +} + +/*************************************************************************** + read_sectors_from_disk - read sectors starting at diskaddr into sector_buffer + ***************************************************************************/ + +void omti8621_device::read_sectors_from_disk(INT32 diskaddr, UINT8 count, UINT8 lun) +{ + UINT8 *data_buffer = §or_buffer[0]; + device_image_interface *image = our_disks[lun]->m_image; + + while (count-- > 0) { + LOG2(("read_sectors_from_disk lun=%d diskaddr=%x", lun, diskaddr)); + + image->fseek( diskaddr * OMTI_DISK_SECTOR_SIZE, SEEK_SET); + image->fread( data_buffer, OMTI_DISK_SECTOR_SIZE); + + diskaddr++; + data_buffer += OMTI_DISK_SECTOR_SIZE; + } +} + +/*************************************************************************** + write_sectors_to_disk - write sectors starting at diskaddr from sector_buffer + ***************************************************************************/ + +void omti8621_device::write_sectors_to_disk(INT32 diskaddr, UINT8 count, UINT8 lun) +{ + UINT8 *data_buffer = §or_buffer[0]; + device_image_interface *image = our_disks[lun]->m_image; + + while (count-- > 0) { + LOG2(("write_sectors_to_disk lun=%d diskaddr=%x", lun, diskaddr)); + + image->fseek( diskaddr * OMTI_DISK_SECTOR_SIZE, SEEK_SET); + image->fwrite( data_buffer, OMTI_DISK_SECTOR_SIZE); + + if (diskaddr == diskaddr_ecc_error) { + // reset previous ECC error + diskaddr_ecc_error = 0; + } + + diskaddr++; + data_buffer += OMTI_DISK_SECTOR_SIZE; + } +} + +/*************************************************************************** + copy_sectors - copy sectors + ***************************************************************************/ + +void omti8621_device::copy_sectors(INT32 dst_addr, INT32 src_addr, UINT8 count, UINT8 lun) +{ + device_image_interface *image = our_disks[lun]->m_image; + + LOG2(("copy_sectors lun=%d src_addr=%x dst_addr=%x count=%x", lun, src_addr, dst_addr, count)); + + while (count-- > 0) { + image->fseek( src_addr * OMTI_DISK_SECTOR_SIZE, SEEK_SET); + image->fread( §or_buffer[0], OMTI_DISK_SECTOR_SIZE); + + image->fseek( dst_addr * OMTI_DISK_SECTOR_SIZE, SEEK_SET); + image->fwrite( §or_buffer[0], OMTI_DISK_SECTOR_SIZE); + + if (dst_addr == diskaddr_ecc_error) { + // reset previous ECC error + diskaddr_ecc_error = 0; + } + + src_addr++; + dst_addr++; + } +} + +/*************************************************************************** + format track - format a track + ***************************************************************************/ + +void omti8621_device::format_track(const UINT8 * cdb) +{ + UINT8 lun = get_lun(cdb); + UINT32 disk_addr = get_disk_address(cdb); + UINT32 disk_track = get_disk_track(cdb); + + if (diskaddr_ecc_error == disk_addr) { + // reset previous ECC error + diskaddr_ecc_error = 0; + } + + if (diskaddr_format_bad_track == disk_track) { + // reset previous bad track formatting + diskaddr_format_bad_track = 0; + } + + if (alternate_track_address[0] == disk_track) { + // reset source of alternate track address + alternate_track_address[0] = 0; + } + + if (alternate_track_address[1] == disk_track) { + // reset alternate track address + alternate_track_address[1] = 0; + } + + if (check_disk_address(cdb) ) { + if ((cdb[5] & 0x40) == 0) { + memset(§or_buffer[0], 0x6C, OMTI_DISK_SECTOR_SIZE * our_disks[lun]->m_sectors); + } + write_sectors_to_disk(disk_addr, our_disks[lun]->m_sectors, lun); + } + +} + +/*************************************************************************** + set_esdi_defect_list - setup the (emty) ESDI defect list + ***************************************************************************/ + +void omti8621_device::set_esdi_defect_list(UINT8 lun, UINT8 head) +{ + omti_disk_image_device *disk = our_disks[lun]; + + memset(disk->m_esdi_defect_list, 0, sizeof(disk->m_esdi_defect_list)); + disk->m_esdi_defect_list[0] = 1; // month + disk->m_esdi_defect_list[1] = 1; // day + disk->m_esdi_defect_list[2] = 90; // year + disk->m_esdi_defect_list[3] = head; + memset(disk->m_esdi_defect_list+6, 0xff, 5); // end of defect list +} + +/*************************************************************************** + log_command - log command from a command descriptor block + ***************************************************************************/ + +void omti8621_device::log_command(const UINT8 cdb[], const UINT16 cdb_length) +{ + if (verbose > 0) { + int i; + logerror("%s: OMTI command ", cpu_context(this)); + switch (cdb[0]) { + case OMTI_CMD_TEST_DRIVE_READY: // 0x00 + logerror("Test Drive Ready"); + break; + case OMTI_CMD_RECALIBRATE: // 0x01 + logerror("Recalibrate"); + break; + case OMTI_CMD_REQUEST_SENSE: // 0x03 + logerror("Request Sense"); + break; + case OMTI_CMD_READ_VERIFY: // 0x05 + logerror("Read Verify"); + break; + case OMTI_CMD_FORMAT_TRACK: // 0x06 + logerror("Format Track"); + break; + case OMTI_CMD_FORMAT_BAD_TRACK: // 0x07 + logerror("Format Bad Track"); + break; + case OMTI_CMD_READ: // 0x08 + logerror("Read"); + break; + case OMTI_CMD_WRITE: // 0x0A + logerror("Write"); + break; + case OMTI_CMD_SEEK: // 0x0B + logerror("Seek"); + break; + case OMTI_CMD_READ_SECTOR_BUFFER: // 0x0E + logerror("Read Sector Buffer"); + break; + case OMTI_CMD_WRITE_SECTOR_BUFFER: // 0x0F + logerror("Write Sector Buffer"); + break; + case OMTI_CMD_ASSIGN_ALTERNATE_TRACK: // 0x11 + logerror("Assign Alternate Track"); + break; + case OMTI_CMD_READ_DATA_TO_BUFFER: // 0x1E + logerror("Read Data to Buffer"); + break; + case OMTI_CMD_WRITE_DATA_FROM_BUFFER: // 0x1F + logerror("Write Data from Buffer"); + break; + case OMTI_CMD_COPY: // 0x20 + logerror("Copy"); + break; + case OMTI_CMD_READ_ESDI_DEFECT_LIST: // 0x37 + logerror("Read ESDI Defect List"); + break; + case OMTI_CMD_RAM_DIAGNOSTICS: // 0xE0 + logerror("RAM. Diagnostic"); + break; + case OMTI_CMD_CONTROLLER_INT_DIAGNOSTIC: // 0xE4 + logerror("Controller Int. Diagnostic"); + break; + case OMTI_CMD_READ_LONG: // 0xE5 + logerror("Read Long"); + break; + case OMTI_CMD_WRITE_LONG: // 0xE6 + logerror("Write Long"); + break; + case OMTI_CMD_READ_CONFIGURATION: // 0xEC + logerror("Read Configuration"); + break; + case OMTI_CMD_INVALID_COMMAND: // 0xFF + logerror("Invalid Command"); + break; + default: + logerror("!!! Unexpected Command !!!"); + } +// logerror(" (%02x, length=%02x)", cdb[0], cdb_length); + for (i = 0; i < cdb_length; i++) { + logerror(" %02x", cdb[i]); + } + + switch (cdb[0]) { + case OMTI_CMD_READ_VERIFY: // 0x05 + case OMTI_CMD_READ: // 0x08 + case OMTI_CMD_WRITE: // 0x0a + case OMTI_CMD_SEEK: // 0x0b + case OMTI_CMD_READ_DATA_TO_BUFFER: // 0x1E + case OMTI_CMD_WRITE_DATA_FROM_BUFFER: // 0x1F + case OMTI_CMD_COPY: // 0x20 + logerror(" (diskaddr=%x count=%x)", get_disk_address(cdb), cdb[4]); + break; + } + logerror("\n"); + } +} + +/*************************************************************************** + log_data - log data in the common data buffer + ***************************************************************************/ + +void omti8621_device::log_data() +{ + if (verbose > 0) { + int i; + logerror("%s: OMTI data (length=%02x)", cpu_context(this), + data_length); + for (i = 0; i < data_length && i < OMTI_DISK_SECTOR_SIZE; i++) { + logerror(" %02x", data_buffer[i]); + } + + if (i < data_length) { + logerror(" ..."); + } + logerror("\n"); + } +} + +/*************************************************************************** + do_command + ***************************************************************************/ + +void omti8621_device::do_command(const UINT8 cdb[], const UINT16 cdb_length) +{ + UINT8 lun = get_lun(cdb); + omti_disk_image_device *disk = our_disks[lun]; + int command_duration = 0; // ms + + log_command( cdb, cdb_length); + + // default to read status and status is successful completion + omti_state = OMTI_STATE_STATUS; + status_port |= OMTI_STATUS_IO | OMTI_STATUS_CD; + command_status = lun ? OMTI_COMMAND_STATUS_LUN : 0; + + if (mask_port & OMTI_MASK_INTE) { + set_interrupt(CLEAR_LINE); + } + + if (!disk->m_image->exists()) { + command_status |= OMTI_COMMAND_STATUS_ERROR; // no such drive + } + + switch (cdb[0]) { + case OMTI_CMD_TEST_DRIVE_READY: // 0x00 + if (!disk->m_image->exists()) + { + set_sense_data(OMTI_SENSE_CODE_DRIVE_NOT_READY, cdb); + } + break; + + case OMTI_CMD_RECALIBRATE: // 0x01 + break; + + case OMTI_CMD_REQUEST_SENSE: // 0x03 + set_data_transfer(sense_data, sizeof(sense_data)); + break; + + case OMTI_CMD_READ_VERIFY: // 0x05 + check_disk_address(cdb); + break; + + case OMTI_CMD_FORMAT_TRACK: // 0x06 + format_track(cdb); + break; + + case OMTI_CMD_FORMAT_BAD_TRACK: // 0x07 + diskaddr_format_bad_track = get_disk_address(cdb); + break; + + case OMTI_CMD_READ: // 0x08 + if (check_disk_address(cdb)) { + // read data from controller + read_sectors_from_disk(get_disk_address(cdb), cdb[4], lun); + set_data_transfer(§or_buffer[0], OMTI_DISK_SECTOR_SIZE*cdb[4]); + } + break; + + case OMTI_CMD_WRITE: // 0x0A + log_data(); + if (check_disk_address(cdb)) { + write_sectors_to_disk(get_disk_address(cdb), cdb[4], lun); + } + break; + + case OMTI_CMD_SEEK: // 0x0B + check_disk_address(cdb); + break; + + case OMTI_CMD_READ_SECTOR_BUFFER: // 0x0E + set_data_transfer(§or_buffer[0], OMTI_DISK_SECTOR_SIZE*cdb[4]); + break; + + case OMTI_CMD_WRITE_SECTOR_BUFFER: // 0x0F + log_data(); + break; + + case OMTI_CMD_COPY: // 0x20 + if (check_disk_address(cdb) && check_disk_address(cdb+4)) { + // copy sectors + copy_sectors (get_disk_address(cdb+4), get_disk_address(cdb), cdb[4], lun); + } + break; + + case OMTI_CMD_READ_ESDI_DEFECT_LIST: // 0x37 + set_esdi_defect_list(get_lun(cdb), cdb[1] & 0x1f); + set_data_transfer(disk->m_esdi_defect_list, sizeof(disk->m_esdi_defect_list)); + break; + +#if 0 // this command seems unused by Domain/OS, and it's unclear what the intent of the code is (it makes some versions of GCC quite unhappy) + case OMTI_CMD_ASSIGN_ALTERNATE_TRACK: // 0x11 + log_data(); + alternate_track_address[0] = get_disk_track(cdb); + alternate_track_address[1] = get_disk_track(alternate_track_buffer-1); + break; +#endif + + case OMTI_CMD_READ_DATA_TO_BUFFER: // 0x1E + if (check_disk_address(cdb)) { + // read data from controller + read_sectors_from_disk (get_disk_address(cdb), cdb[4], lun); + // Domain/OS doesn't expect zero access time + command_duration += 1; // 1 ms is enough, average time would be 30 ms) + } + break; + + case OMTI_CMD_WRITE_DATA_FROM_BUFFER: // 0x1F + log_data(); + if (check_disk_address(cdb)) { + write_sectors_to_disk(get_disk_address(cdb), cdb[4], lun); + } + break; + + case OMTI_CMD_RAM_DIAGNOSTICS: // 0xE0 + break; + + case OMTI_CMD_CONTROLLER_INT_DIAGNOSTIC: // 0xE4 + break; + + case OMTI_CMD_READ_LONG: // 0xE5 + if (check_disk_address(cdb)) { + // read data from controller + read_sectors_from_disk(get_disk_address(cdb), cdb[4], lun); + set_data_transfer(§or_buffer[0], OMTI_DISK_SECTOR_SIZE+6); + } + break; + + case OMTI_CMD_WRITE_LONG: // 0xE6 + log_data(); + if (check_disk_address(cdb)) { + UINT32 diskaddr = get_disk_address(cdb); + write_sectors_to_disk(diskaddr, cdb[4], lun); + // this will spoil the ECC code + diskaddr_ecc_error = diskaddr; + } + break; + + case OMTI_CMD_READ_CONFIGURATION: // 0xEC + set_configuration_data(get_lun(cdb)); + set_data_transfer(disk->m_config_data, sizeof(disk->m_config_data)); + break; + + case OMTI_CMD_INVALID_COMMAND: // 0xFF + set_sense_data(OMTI_SENSE_CODE_INVALID_COMMAND, cdb); + command_status |= OMTI_COMMAND_STATUS_ERROR; + break; + + default: + LOG(("do_command: UNEXPECTED command %02x",cdb[0])); + set_sense_data(OMTI_SENSE_CODE_INVALID_COMMAND, cdb); + command_status |= OMTI_COMMAND_STATUS_ERROR; + break; + } + + if (mask_port & OMTI_MASK_INTE) { +// if (omti_state != OMTI_STATE_STATUS) { +// LOG(("do_command: UNEXPECTED omti_state %02x",omti_state)); +// } + status_port |= OMTI_STATUS_IREQ; + if (command_duration == 0) + { + set_interrupt(ASSERT_LINE); + } + else + { + // FIXME: should delay omti_state and status_port as well + m_timer->adjust(attotime::from_msec(command_duration), 0); + } + } +} + +/*************************************************************************** + get_command_length + ***************************************************************************/ + +UINT8 omti8621_device::get_command_length(UINT8 command_byte) +{ + return command_byte == OMTI_CMD_COPY ? 10 : 6; +} + +/*************************************************************************** + get_data + ***************************************************************************/ + +UINT16 omti8621_device::get_data() +{ + UINT16 data = 0xff; + if (data_index < data_length) { + data = data_buffer[data_index++]; + data |= data_buffer[data_index++] << 8; + if (data_index >= data_length) { + omti_state = OMTI_STATE_STATUS; + status_port |= OMTI_STATUS_IO | OMTI_STATUS_CD; + log_data(); + } + } else { + LOG(("UNEXPECTED reading OMTI 8621 data (buffer length exceeded)")); + } + return data; +} + +/*************************************************************************** + set_data + ***************************************************************************/ + +void omti8621_device::set_data(UINT16 data) +{ + if (data_index < data_length) { + data_buffer[data_index++] = data & 0xff; + data_buffer[data_index++] = data >> 8; + if (data_index >= data_length) { + do_command(command_buffer, command_index); + } + } else { + LOG(("UNEXPECTED writing OMTI 8621 data (buffer length exceeded)")); + } +} + +/*************************************************************************** + OMTI8621 Disk Controller-AT Registers +***************************************************************************/ + +WRITE16_MEMBER(omti8621_device::write) +{ + switch (mem_mask) + { + case 0x00ff: + write8(space, offset*2, data, mem_mask); + break; + + case 0xff00: + write8(space, offset*2+1, data>>8, mem_mask>>8); + break; + + default: + set_data(data); + break; + } +} + +WRITE8_MEMBER(omti8621_device::write8) +{ + switch (offset) + { + case OMTI_PORT_DATA_OUT: // 0x00 + switch (omti_state) { + case OMTI_STATE_COMMAND: + LOG2(("writing OMTI 8621 Command Register at offset %02x = %02x", offset, data)); + if (command_index == 0) { + command_length = get_command_length(data); + } + + if (command_index < command_length) { + command_buffer[command_index++] = data; + } else { + LOG(("UNEXPECTED writing OMTI 8621 Data Register at offset %02x = %02x (command length exceeded)", offset, data)); + } + + if (command_index == command_length) { + switch (command_buffer[0]) { + case OMTI_CMD_WRITE: // 0x0A + // TODO: check diskaddr + // Fall through + case OMTI_CMD_WRITE_SECTOR_BUFFER: // 0x0F + set_data_transfer(§or_buffer[0], + OMTI_DISK_SECTOR_SIZE * command_buffer[4]); + status_port &= ~OMTI_STATUS_IO; + break; + + case OMTI_CMD_ASSIGN_ALTERNATE_TRACK: // 0x11 + set_data_transfer(alternate_track_buffer, sizeof(alternate_track_buffer)); + status_port &= ~OMTI_STATUS_IO; + break; + + case OMTI_CMD_WRITE_LONG: // 0xE6 + // TODO: check diskaddr + set_data_transfer(§or_buffer[0], + (OMTI_DISK_SECTOR_SIZE +6) * command_buffer[4]); + status_port &= ~OMTI_STATUS_IO; + break; + + default: + do_command(command_buffer, command_index); + break; + } + } + break; + + case OMTI_STATE_DATA: + LOG(("UNEXPECTED: writing OMTI 8621 Data Register at offset %02x = %02x", offset, data)); + break; + + default: + LOG(("UNEXPECTED writing OMTI 8621 Data Register at offset %02x = %02x (omti state = %02x)", offset, data, omti_state)); + break; + } + break; + + case OMTI_PORT_RESET: // 0x01 + LOG2(("writing OMTI 8621 Reset Register at offset %02x = %02x", offset, data)); + device_reset(); + break; + + case OMTI_PORT_SELECT: // 0x02 + LOG2(("writing OMTI 8621 Select Register at offset %02x = %02x (omti state = %02x)", offset, data, omti_state)); + omti_state = OMTI_STATE_COMMAND; + + status_port |= OMTI_STATUS_BUSY | OMTI_STATUS_REQ | OMTI_STATUS_CD; + status_port &= ~OMTI_STATUS_IO; + + command_status = 0; + command_index = 0; + break; + + case OMTI_PORT_MASK: // 0x03 + LOG2(("writing OMTI 8621 Mask Register at offset %02x = %02x", offset, data)); + mask_port = data; + + if ((data & OMTI_MASK_INTE) == 0) { + status_port &= ~OMTI_STATUS_IREQ; + set_interrupt(CLEAR_LINE); + } + + if ((data & OMTI_MASK_DMAE) == 0) { + status_port &= ~OMTI_STATUS_DREQ; + } + break; + + default: + LOG(("UNEXPECTED writing OMTI 8621 Register at offset %02x = %02x", offset, data)); + break; + } +} + +READ16_MEMBER(omti8621_device::read) +{ + switch (mem_mask) + { + case 0x00ff: + return read8(space, offset*2, mem_mask); + case 0xff00: + return read8(space, offset*2+1, mem_mask >> 8) << 8; + default: + return get_data(); + } +} + +READ8_MEMBER(omti8621_device::read8) +{ + UINT8 data = 0xff; + static UINT8 last_data = 0xff; + + switch (offset) { + case OMTI_PORT_DATA_IN: // 0x00 + if (status_port & OMTI_STATUS_CD) + { + data = command_status; + switch (omti_state) + { + case OMTI_STATE_COMMAND: + LOG2(("reading OMTI 8621 Data Status Register 1 at offset %02x = %02x (omti state = %02x)", offset, data, omti_state)); + break; + case OMTI_STATE_STATUS: + omti_state = OMTI_STATE_IDLE; + status_port &= ~(OMTI_STATUS_BUSY | OMTI_STATUS_CD | OMTI_STATUS_IO | OMTI_STATUS_REQ); + LOG2(("reading OMTI 8621 Data Status Register 2 at offset %02x = %02x", offset, data)); + break; + default: + LOG(("UNEXPECTED reading OMTI 8621 Data Status Register 3 at offset %02x = %02x (omti state = %02x)", offset, data, omti_state)); + break; + } + } + else + { + LOG(("UNEXPECTED reading OMTI 8621 Data Register 4 at offset %02x = %02x (status bit C/D = 0)", offset, data)); + } + break; + + case OMTI_PORT_STATUS: // 0x01 + data = status_port; + // omit excessive logging + if (data != last_data) + { + LOG2(("reading OMTI 8621 Status Register 5 at offset %02x = %02x", offset, data)); +// last_data = data; + } + break; + + case OMTI_PORT_CONFIG: // 0x02 + data = config_port; + LOG2(("reading OMTI 8621 Configuration Register at offset %02x = %02x", offset, data)); + break; + + case OMTI_PORT_MASK: // 0x03 + data = mask_port ; + // win.dex will update the mask register with read-modify-write + // LOG2(("reading OMTI 8621 Mask Register at offset %02x = %02x (UNEXPECTED!)", offset, data)); + break; + + default: + LOG(("UNEXPECTED reading OMTI 8621 Register at offset %02x = %02x", offset, data)); + break; + } + + return data; +} + +void omti8621_device::set_verbose(int on_off) +{ + verbose = on_off == 0 ? 0 : VERBOSE > 1 ? VERBOSE : 1; +} + +/*************************************************************************** + get_sector - get sector diskaddr of logical unit lun into data_buffer + ***************************************************************************/ + +UINT32 omti8621_device::get_sector(INT32 diskaddr, UINT8 *data_buffer, UINT32 length, UINT8 lun) +{ + omti_disk_image_device *disk = our_disks[lun]; + + if (disk->m_image == NULL || !disk->m_image->exists()) + { + return 0; + } + else + { +// LOG1(("omti8621_get_sector %x on lun %d", diskaddr, lun)); + + // restrict length to size of 1 sector (i.e. 1024 Byte) + length = length < OMTI_DISK_SECTOR_SIZE ? length : OMTI_DISK_SECTOR_SIZE; + + disk->m_image->fseek(diskaddr * OMTI_DISK_SECTOR_SIZE, SEEK_SET); + disk->m_image->fread(data_buffer, length); + + return length; + } +} + + +/*************************************************************************** + omti_set_jumper - set OMI jumpers + ***************************************************************************/ + +void omti8621_device::set_jumper(UINT16 disk_type) +{ + LOG1(("set_jumper: disk type=%x", disk_type)); + + switch (disk_type) + { + case OMTI_DISK_TYPE_348_MB: // Maxtor 380 MB (348-MB FA formatted) + jumper = OMTI_CONFIG_W22 | OMTI_CONFIG_W23; + break; + + case OMTI_DISK_TYPE_155_MB: // Micropolis 170 MB (155-MB formatted) + default: + jumper = OMTI_CONFIG_W20; + break; + } +} + +// FDC uses the standard IRQ 6 / DMA 2, doesn't appear to be configurable +WRITE_LINE_MEMBER( omti8621_device::fdc_irq_w ) +{ + m_isa->irq6_w(state ? ASSERT_LINE : CLEAR_LINE); +} + +WRITE_LINE_MEMBER( omti8621_device::fdc_drq_w ) +{ + m_isa->drq2_w(state ? ASSERT_LINE : CLEAR_LINE); +} + +UINT8 omti8621_device::dack_r(int line) +{ + return m_fdc->dma_r(); +} + +void omti8621_device::dack_w(int line, UINT8 data) +{ + return m_fdc->dma_w(data); +} + +void omti8621_device::eop_w(int state) +{ + m_fdc->tc_w(state == ASSERT_LINE); +} + +//########################################################################## + +// device type definition +const device_type OMTI_DISK = &device_creator; + +omti_disk_image_device::omti_disk_image_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, OMTI_DISK, "OMTI8621 ESDI disk", tag, owner, clock, "omti_disk_image", __FILE__), + device_image_interface(mconfig, *this) +{ +} + +void omti_disk_image_device::device_config_complete() +{ + update_names(OMTI_DISK, "disk", "disk"); +} + + +/*************************************************************************** + omti_disk_config - configure disk parameters + ***************************************************************************/ + +void omti_disk_image_device::omti_disk_config(UINT16 disk_type) +{ + LOG1(("omti_disk_config: configuring disk with type %x", disk_type)); + + switch (disk_type) + { + case OMTI_DISK_TYPE_348_MB: // Maxtor 380 MB (348-MB FA formatted) + m_cylinders = 1223; + m_heads = 15; + m_sectors = 18; + break; + + case OMTI_DISK_TYPE_155_MB: // Micropolis 170 MB (155-MB formatted) + default: + m_cylinders = 1023; + m_heads = 8; + m_sectors = 18; + break; + } + + m_type = disk_type; + m_sectorbytes = OMTI_DISK_SECTOR_SIZE; + m_sector_count = m_cylinders * m_heads * m_sectors; +} + +/*------------------------------------------------- + device start callback +-------------------------------------------------*/ + +void omti_disk_image_device::device_start() +{ + m_image = this; + + if (m_image->image_core_file() == NULL) + { + LOG1(("device_start_omti_disk: no disk")); + } + else + { + LOG1(("device_start_omti_disk: with disk image %s",m_image->basename() )); + } + + // default disk type + omti_disk_config(OMTI_DISK_TYPE_DEFAULT); +} + +/*------------------------------------------------- + device reset callback +-------------------------------------------------*/ + +void omti_disk_image_device::device_reset() +{ + LOG1(("device_reset_omti_disk")); + + if (exists() && fseek(0, SEEK_END) == 0) + { + UINT32 disk_size = (UINT32)(ftell() / OMTI_DISK_SECTOR_SIZE); + UINT16 disk_type = disk_size >= 300000 ? OMTI_DISK_TYPE_348_MB : OMTI_DISK_TYPE_155_MB; + if (disk_type != m_type) { + LOG1(("device_reset_omti_disk: disk size=%d blocks, disk type=%x", disk_size, disk_type )); + omti_disk_config(disk_type); + } + } +} + +/*------------------------------------------------- + disk image create callback +-------------------------------------------------*/ + +bool omti_disk_image_device::call_create(int format_type, option_resolution *format_options) +{ + LOG(("device_create_omti_disk: creating OMTI Disk with %d blocks", m_sector_count)); + + int x; + unsigned char sectordata[OMTI_DISK_SECTOR_SIZE]; // empty block data + + + memset(sectordata, 0x55, sizeof(sectordata)); + for (x = 0; x < m_sector_count; x++) + { + if (fwrite(sectordata, OMTI_DISK_SECTOR_SIZE) + < OMTI_DISK_SECTOR_SIZE) + { + return IMAGE_INIT_FAIL; + } + } + return IMAGE_INIT_PASS; +} diff --git a/src/devices/bus/isa/omti8621.h b/src/devices/bus/isa/omti8621.h new file mode 100644 index 00000000000..1a49a8e3993 --- /dev/null +++ b/src/devices/bus/isa/omti8621.h @@ -0,0 +1,135 @@ +// license:BSD-3-Clause +// copyright-holders:Hans Ostermeyer,R. Belmont +/* + * omti8621.h - SMS OMTI 8621 disk controller + * + * Created on: August 30, 2010 + * Author: Hans Ostermeyer + * + * Converted to ISA device March 3, 2014 by R. Belmont + * + */ + +#pragma once + +#ifndef ISA_OMTI8621_H_ +#define ISA_OMTI8621_H_ + +#include "emu.h" +#include "isa.h" +#include "machine/pc_fdc.h" + +#define OMTI_MAX_LUN 1 +#define CDB_SIZE 10 + +/*************************************************************************** + FUNCTION PROTOTYPES + ***************************************************************************/ + +class omti_disk_image_device; + +/* ----- device interface ----- */ + +class omti8621_device : public device_t, public device_isa16_card_interface +{ +public: + omti8621_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + ~omti8621_device() {} + + DECLARE_READ16_MEMBER(read); + DECLARE_WRITE16_MEMBER(write); + + static void set_verbose(int on_off); + + // get sector diskaddr of logical unit lun into data_buffer + UINT32 get_sector(INT32 diskaddr, UINT8 *data_buffer, UINT32 length, UINT8 lun); + + required_device m_fdc; + required_ioport m_iobase; + required_ioport m_biosopts; + + DECLARE_WRITE_LINE_MEMBER( fdc_irq_w ); + DECLARE_WRITE_LINE_MEMBER( fdc_drq_w ); + DECLARE_FLOPPY_FORMATS( floppy_formats ); + +protected: + // device-level overrides + virtual void device_config_complete(); + virtual void device_start(); + virtual void device_reset(); + virtual const rom_entry *device_rom_region() const; + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + virtual machine_config_constructor device_mconfig_additions() const; + virtual ioport_constructor device_input_ports() const; + + virtual UINT8 dack_r(int line); + virtual void dack_w(int line, UINT8 data); + virtual void eop_w(int state); + + void set_interrupt(enum line_state line_state); + +private: + omti_disk_image_device *our_disks[OMTI_MAX_LUN+1]; + + UINT16 jumper; + + UINT8 omti_state; + + UINT8 status_port; + UINT8 config_port; + UINT8 mask_port; + + // command descriptor block + UINT8 command_buffer[CDB_SIZE]; + int command_length; + int command_index; + int command_status; + + // data buffer + dynamic_buffer sector_buffer; + UINT8 *data_buffer; + int data_length; + int data_index; + + // sense data + UINT8 sense_data[4]; + + // these are used only to satisfy dex + UINT32 diskaddr_ecc_error; + UINT32 diskaddr_format_bad_track; + UINT8 alternate_track_buffer[4]; + UINT32 alternate_track_address[2]; + + emu_timer *m_timer; + + bool m_installed; + + void clear_sense_data(); + void set_sense_data(UINT8 code, const UINT8 * cdb); + void set_configuration_data(UINT8 lun); + UINT8 get_lun(const UINT8 * cdb); + UINT8 check_disk_address(const UINT8 *cdb); + UINT32 get_disk_track(const UINT8 * cdb); + UINT32 get_disk_address(const UINT8 * cdb); + void set_data_transfer(UINT8 *data, UINT16 length); + void read_sectors_from_disk(INT32 diskaddr, UINT8 count, UINT8 lun); + void write_sectors_to_disk(INT32 diskaddr, UINT8 count, UINT8 lun); + void copy_sectors(INT32 dst_addr, INT32 src_addr, UINT8 count, UINT8 lun); + void format_track(const UINT8 * cdb); + void set_esdi_defect_list(UINT8 lun, UINT8 head); + void log_command(const UINT8 cdb[], const UINT16 cdb_length); + void log_data(); + void do_command(const UINT8 cdb[], const UINT16 cdb_length); + UINT8 get_command_length(UINT8 command_byte); + UINT16 get_data(); + void set_data(UINT16 data); + void set_jumper(UINT16 disk_type); + DECLARE_READ8_MEMBER(read8); + DECLARE_WRITE8_MEMBER(write8); +}; + +extern const device_type ISA16_OMTI8621; + +//############################################################### + +#endif /* OMTI8621_H_ */ diff --git a/src/devices/bus/isa/p1_fdc.c b/src/devices/bus/isa/p1_fdc.c new file mode 100644 index 00000000000..4ba01ed47da --- /dev/null +++ b/src/devices/bus/isa/p1_fdc.c @@ -0,0 +1,203 @@ +// license:BSD-3-Clause +// copyright-holders:Sergey Svishchev +/********************************************************************** + + Poisk-1 FDC device (model B504) + +**********************************************************************/ + +#include "p1_fdc.h" + +#include "cpu/i86/i86.h" +#include "formats/pc_dsk.h" + +#define VERBOSE_DBG 0 + +#define DBG_LOG(N,M,A) \ + do { \ + if(VERBOSE_DBG>=N) \ + { \ + if( M ) \ + logerror("%11.6f: %-24s",machine().time().as_double(),(char*)M ); \ + logerror A; \ + } \ + } while (0) + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type P1_FDC = &device_creator; + +FLOPPY_FORMATS_MEMBER( p1_fdc_device::floppy_formats ) + FLOPPY_PC_FORMAT +FLOPPY_FORMATS_END + +static SLOT_INTERFACE_START( poisk1_floppies ) + SLOT_INTERFACE( "525qd", FLOPPY_525_QD ) +SLOT_INTERFACE_END + +static MACHINE_CONFIG_FRAGMENT( fdc_b504 ) + MCFG_FD1793_ADD("fdc", XTAL_16MHz / 16) + MCFG_WD_FDC_INTRQ_CALLBACK(WRITELINE(p1_fdc_device, p1_fdc_irq_drq)) + MCFG_WD_FDC_DRQ_CALLBACK(WRITELINE(p1_fdc_device, p1_fdc_irq_drq)) + MCFG_FLOPPY_DRIVE_ADD("fdc:0", poisk1_floppies, "525qd", p1_fdc_device::floppy_formats) + MCFG_FLOPPY_DRIVE_ADD("fdc:1", poisk1_floppies, "525qd", p1_fdc_device::floppy_formats) +MACHINE_CONFIG_END + +//------------------------------------------------- +// ROM( p1_fdc ) +//------------------------------------------------- + +ROM_START( p1_fdc ) + ROM_REGION( 0x0800, "p1_fdc", 0 ) + ROM_DEFAULT_BIOS("a302") + ROM_SYSTEM_BIOS(0, "normal", "B504 standard ROM") + ROMX_LOAD( "b_ngmd_n.rf2", 0x00000, 0x0800, CRC(967e172a) SHA1(95117c40fd9f624fee08ccf37f615b16ff249688), ROM_BIOS(1)) + ROM_SYSTEM_BIOS(1, "a302", "v3.02") // Additional ROM BIOS v3.02 for DISKETTE service (c) Moscow 1991 + ROMX_LOAD( "b_ngmd_t.rf2", 0x00000, 0x0800, CRC(630010b1) SHA1(50876fe4f5f4f32a242faa70f9154574cd315ec4), ROM_BIOS(2)) + ROM_SYSTEM_BIOS(2, "ae304", "v3.04") // Additional enhanced ROM BIOS v3.04 for DISKETTE service (c) V.Rusakow Moscow 1992 + ROMX_LOAD( "p_fdd_nm.bin", 0x00000, 0x0800, CRC(0b7f867d) SHA1(9fe7e0ab2242e50394d1162cf1a619b6f2994bfb), ROM_BIOS(3)) + ROM_SYSTEM_BIOS(3, "ae308", "v3.08") // Additional enhanced ROM BIOS v3.08 for DISKETTE service (c) V.Rusakov Tarasovka 1992 + ROMX_LOAD( "p_fdd_my.bin", 0x00000, 0x0800, CRC(da5d0eaf) SHA1(b188ba856bd28e4964a88feb0b0b2ba7eb320efc), ROM_BIOS(4)) +ROM_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor p1_fdc_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( fdc_b504 ); +} + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *p1_fdc_device::device_rom_region() const +{ + return ROM_NAME( p1_fdc ); +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +UINT8 p1_fdc_device::p1_wd17xx_motor_r() +{ + DBG_LOG(1,"p1_fdc_motor_r",("R = $%02x\n", 0)); + // XXX always on for now + return 0; +} + +UINT8 p1_fdc_device::p1_wd17xx_aux_r() +{ + cpu_device *maincpu = machine().device("maincpu"); + + if (!m_fdc->drq_r() && !m_fdc->intrq_r()) { + // fake cpu wait by resetting PC one insn back + maincpu->set_state_int(I8086_IP, maincpu->state_int(I8086_IP) - 2); + maincpu->set_input_line(INPUT_LINE_HALT, ASSERT_LINE); + } + + return m_fdc->drq_r(); +} + +/* +; D0 - DRIVE SELECT 0 +; D1 - DRIVE SELECT 1 +; D2 - MOTOR ON 0 +; D3 - MOTOR ON 1 +; D4 - SIDE (HEAD) SELECT +; D5 - DOUBLE DENSITY +; D6 - FDC RESET +; D7 - NO USE +*/ +void p1_fdc_device::p1_wd17xx_aux_w(int data) +{ + DBG_LOG(1,"p1_fdc_aux_w",("W $%02x\n", data)); + + floppy_image_device *floppy0 = m_fdc->subdevice("0")->get_device(); + floppy_image_device *floppy1 = m_fdc->subdevice("1")->get_device(); + floppy_image_device *floppy = ((data & 2)?floppy1:floppy0); + + if(!BIT(data, 6)) + m_fdc->reset(); + + m_fdc->set_floppy(floppy); + + floppy->ss_w(BIT(data, 4)); + m_fdc->dden_w(BIT(data, 5)); + + floppy0->mon_w(!(data & 4)); + floppy1->mon_w(!(data & 8)); +} + +WRITE_LINE_MEMBER( p1_fdc_device::p1_fdc_irq_drq ) +{ + cpu_device *maincpu = machine().device("maincpu"); + + if(state) + maincpu->set_input_line(INPUT_LINE_HALT, CLEAR_LINE); +} + +READ8_MEMBER( p1_fdc_device::p1_fdc_r ) +{ + UINT8 data = 0xff; + + switch( offset ) + { + case 0: data = p1_wd17xx_aux_r(); break; + case 2: data = p1_wd17xx_motor_r(); break; + } + + return data; +} + +WRITE8_MEMBER( p1_fdc_device::p1_fdc_w ) +{ + switch( offset ) + { + case 0: p1_wd17xx_aux_w(data); break; + } +} + +//------------------------------------------------- +// p1_fdc_device - constructor +//------------------------------------------------- + +p1_fdc_device::p1_fdc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, P1_FDC, "Poisk-1 floppy B504", tag, owner, clock, "p1_fdc", __FILE__), + device_isa8_card_interface( mconfig, *this ), + m_fdc(*this, "fdc") +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void p1_fdc_device::device_start() +{ + set_isa_device(); + m_isa->install_rom(this, 0xe0000, 0xe07ff, 0, 0, "XXX", "p1_fdc"); + m_isa->install_device(0x00c0, 0x00c3, 0, 0, + READ8_DEVICE_DELEGATE(m_fdc, fd1793_t, read), + WRITE8_DEVICE_DELEGATE(m_fdc, fd1793_t, write) ); + m_isa->install_device(0x00c4, 0x00c7, 0, 0, read8_delegate( FUNC(p1_fdc_device::p1_fdc_r), this ), write8_delegate( FUNC(p1_fdc_device::p1_fdc_w), this ) ); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void p1_fdc_device::device_reset() +{ +} diff --git a/src/devices/bus/isa/p1_fdc.h b/src/devices/bus/isa/p1_fdc.h new file mode 100644 index 00000000000..810f7e4cba0 --- /dev/null +++ b/src/devices/bus/isa/p1_fdc.h @@ -0,0 +1,58 @@ +// license:BSD-3-Clause +// copyright-holders:Sergey Svishchev +/********************************************************************** + + Poisk-1 FDC device (model B504) + +**********************************************************************/ + +#pragma once + +#ifndef __P1_FDC__ +#define __P1_FDC__ + +#include "emu.h" + +#include "imagedev/flopdrv.h" +#include "isa.h" +#include "machine/wd_fdc.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class p1_fdc_device : public device_t, + public device_isa8_card_interface +{ +public: + // construction/destruction + p1_fdc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual const rom_entry *device_rom_region() const; + + DECLARE_FLOPPY_FORMATS( floppy_formats ); + DECLARE_READ8_MEMBER(p1_fdc_r); + DECLARE_WRITE8_MEMBER(p1_fdc_w); + DECLARE_WRITE_LINE_MEMBER( p1_fdc_irq_drq ); +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + +private: + required_device m_fdc; + +public: + void p1_wd17xx_aux_w(int data); + UINT8 p1_wd17xx_aux_r(); + UINT8 p1_wd17xx_motor_r(); +}; + + +// device type definition +extern const device_type P1_FDC; + + +#endif diff --git a/src/devices/bus/isa/p1_hdc.c b/src/devices/bus/isa/p1_hdc.c new file mode 100644 index 00000000000..eb8d68524eb --- /dev/null +++ b/src/devices/bus/isa/p1_hdc.c @@ -0,0 +1,146 @@ +// license:BSD-3-Clause +// copyright-holders:Sergey Svishchev +/********************************************************************** + + Poisk-1 HDC device (model B942) + +**********************************************************************/ + +#include "p1_hdc.h" + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define VERBOSE_DBG 1 + +#define DBG_LOG(N,M,A) \ + do { \ + if(VERBOSE_DBG>=N) \ + { \ + if( M ) \ + logerror("%11.6f: %-24s",machine().time().as_double(),(char*)M ); \ + logerror A; \ + } \ + } while (0) + +#define KM1809VG7_TAG "d17" + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type P1_HDC = &device_creator; + +static MACHINE_CONFIG_FRAGMENT( hdc_b942 ) + MCFG_DEVICE_ADD(KM1809VG7_TAG, WD2010, 5000000) // XXX clock? + MCFG_WD2010_IN_DRDY_CB(VCC) + MCFG_WD2010_IN_INDEX_CB(VCC) + MCFG_WD2010_IN_WF_CB(VCC) + MCFG_WD2010_IN_TK000_CB(VCC) + MCFG_WD2010_IN_SC_CB(VCC) + + MCFG_HARDDISK_ADD("hard0") + MCFG_HARDDISK_ADD("hard1") +MACHINE_CONFIG_END + + +//------------------------------------------------- +// ROM( p1_hdc ) +//------------------------------------------------- + +ROM_START( p1_hdc ) + ROM_REGION( 0x0800, "p1_hdc", 0 ) + ROM_DEFAULT_BIOS("v17") + ROM_SYSTEM_BIOS(0, "v11", "ver 1.1") // (c) S. Kovalenko, 1990 + ROMX_LOAD( "b_hd_v11.rf2", 0x00000, 0x0800, CRC(a19c39b2) SHA1(57faa56b320abf801fedbed578cf97d253e5b777), ROM_BIOS(1)) + ROM_SYSTEM_BIOS(1, "v12", "ver 1.2") // (c) S. Kovalenko, 1991 + ROMX_LOAD( "p_hdd_nm.bin", 0x00000, 0x0800, CRC(d5f8e4cc) SHA1(5b533642df30958539715f87a7f25b0d66dd0861), ROM_BIOS(2)) + ROM_SYSTEM_BIOS(2, "v14", "ver 1.4") // (c) `.lesnyh. , 1992 + ROMX_LOAD( "b942_5mb.bin", 0x00000, 0x0800, CRC(a3cfa240) SHA1(0b0aa1ce839a957153bfbbe70310480ca9fe21b6), ROM_BIOS(3)) + ROM_SYSTEM_BIOS(3, "v17", "ver 1.7") // (c) S. Kovalenko, 1992 + ROMX_LOAD( "b942_v17.rom", 0x00000, 0x0800, CRC(869672e3) SHA1(5cf2ae0ec1fa3edb3fe882c805da0bbc3ac21792), ROM_BIOS(4)) +ROM_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor p1_hdc_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( hdc_b942 ); +} + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *p1_hdc_device::device_rom_region() const +{ + return ROM_NAME( p1_hdc ); +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + + +READ8_MEMBER(p1_hdc_device::p1_HDC_r) +{ + UINT8 data = 0x00; + + switch (offset >> 8) { + case 8: data = m_hdc->read(space, offset & 255); + } + DBG_LOG(1,"hdc",("R $%04x == $%02x\n", offset, data)); + + return data; +} + +WRITE8_MEMBER(p1_hdc_device::p1_HDC_w) +{ + DBG_LOG(1,"hdc",("W $%04x <- $%02x\n", offset, data)); + switch (offset >> 8) { + case 8: m_hdc->write(space, offset & 255, data, 0); + } +} + +//------------------------------------------------- +// p1_hdc_device - constructor +//------------------------------------------------- + +p1_hdc_device::p1_hdc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, P1_HDC, "Poisk-1 MFM disk B942", tag, owner, clock, "p1_hdc", __FILE__), + device_isa8_card_interface( mconfig, *this ), + m_hdc(*this, KM1809VG7_TAG) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void p1_hdc_device::device_start() +{ + set_isa_device(); + m_isa->install_rom(this, 0xe2000, 0xe27ff, 0, 0, "XXX", "p1_hdc"); + m_isa->install_memory(0xd0000, 0xd0fff, 0, 0, + READ8_DELEGATE(p1_hdc_device, p1_HDC_r), + WRITE8_DELEGATE(p1_hdc_device, p1_HDC_w) ); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void p1_hdc_device::device_reset() +{ +} diff --git a/src/devices/bus/isa/p1_hdc.h b/src/devices/bus/isa/p1_hdc.h new file mode 100644 index 00000000000..f1a844b5edc --- /dev/null +++ b/src/devices/bus/isa/p1_hdc.h @@ -0,0 +1,55 @@ +// license:BSD-3-Clause +// copyright-holders:Sergey Svishchev +/********************************************************************** + + Poisk-1 HDC device (model B942) + +**********************************************************************/ + +#pragma once + +#ifndef __P1_HDC__ +#define __P1_HDC__ + +#include "emu.h" + +#include "imagedev/harddriv.h" +#include "isa.h" +#include "machine/wd2010.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class p1_hdc_device : public device_t, + public device_isa8_card_interface +{ +public: + // construction/destruction + p1_hdc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual const rom_entry *device_rom_region() const; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + +private: + required_device m_hdc; + + //UINT8 m_ram[0x800]; + +public: + DECLARE_READ8_MEMBER(p1_HDC_r); + DECLARE_WRITE8_MEMBER(p1_HDC_w); +}; + + +// device type definition +extern const device_type P1_HDC; + + +#endif diff --git a/src/devices/bus/isa/p1_rom.c b/src/devices/bus/isa/p1_rom.c new file mode 100644 index 00000000000..bd078972a04 --- /dev/null +++ b/src/devices/bus/isa/p1_rom.c @@ -0,0 +1,76 @@ +// license:BSD-3-Clause +// copyright-holders:Sergey Svishchev +/********************************************************************** + + Poisk-1 ROM cartridge device + +**********************************************************************/ + +#include "p1_rom.h" + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type P1_ROM = &device_creator; + + +//------------------------------------------------- +// ROM( p1_rom ) +//------------------------------------------------- + +ROM_START( p1_rom ) + ROM_REGION( 0x2000, "p1_rom", 0 ) + ROM_SYSTEM_BIOS(0, "ram", "Test 3 -- RAM test") + ROMX_LOAD( "p1_t_ram.rf4", 0x00000, 0x2000, CRC(e42f5a61) SHA1(ce2554eae8f0d2b6d482890dd198cf7e2d29c655), ROM_BIOS(1)) + ROM_SYSTEM_BIOS(1, "io", "Test 4 -- I/O test") + ROMX_LOAD( "p1_t_i_o.rf4", 0x00000, 0x2000, CRC(18a781de) SHA1(7267970ee27e3ea1d972bee8e74b17bac1051619), ROM_BIOS(2)) + ROM_SYSTEM_BIOS(2, "pls", "\"MB test\"") + ROMX_LOAD( "p1_t_pls.rf4", 0x00000, 0x2000, CRC(c8210ffb) SHA1(f2d1a6c90e4708bcc56186b2fb906fa852667084), ROM_BIOS(3)) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *p1_rom_device::device_rom_region() const +{ + return ROM_NAME( p1_rom ); +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// p1_rom_device - constructor +//------------------------------------------------- + +p1_rom_device::p1_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, P1_ROM, "Poisk-1 ROM cart", tag, owner, clock, "p1_rom", __FILE__), + device_isa8_card_interface( mconfig, *this ) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void p1_rom_device::device_start() +{ + set_isa_device(); + m_isa->install_rom(this, 0xc0000, 0xc1fff, 0, 0, "XXX", "p1_rom"); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void p1_rom_device::device_reset() +{ +} diff --git a/src/devices/bus/isa/p1_rom.h b/src/devices/bus/isa/p1_rom.h new file mode 100644 index 00000000000..7b5ddd79150 --- /dev/null +++ b/src/devices/bus/isa/p1_rom.h @@ -0,0 +1,42 @@ +// license:BSD-3-Clause +// copyright-holders:Sergey Svishchev +/********************************************************************** + + Poisk-1 ROM cartridge device + +**********************************************************************/ + +#pragma once + +#ifndef __P1_ROM__ +#define __P1_ROM__ + +#include "emu.h" +#include "isa.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class p1_rom_device : public device_t, + public device_isa8_card_interface +{ +public: + // construction/destruction + p1_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); +}; + + +// device type definition +extern const device_type P1_ROM; + + +#endif diff --git a/src/devices/bus/isa/pc1640_iga.c b/src/devices/bus/isa/pc1640_iga.c new file mode 100644 index 00000000000..127d90560b5 --- /dev/null +++ b/src/devices/bus/isa/pc1640_iga.c @@ -0,0 +1,115 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Amstrad PC1640 Integrated Graphics Adapter emulation + +********************************************************************** + + This display controller is integrated on the PC1640 motherboard + but wired to the ISA bus, and can be disabled with a DIP switch. + + WD Paradise PEGA 1A 38304B 2116-002 8745AAA JAPAN (84 pin PLCC) + + Single chip multimode EGA video controller with + integral 6845 CRTC. Provides 100% IBM EGA, CGA, + MDA, Hercules graphics and Plantronics COLORPLUS* + compatibility + +**********************************************************************/ + +#include "pc1640_iga.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define PEGA1A_TAG "ic910" +#define EGA_CRTC_NAME "crtc_ega_ega" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type ISA8_PC1640_IGA = &device_creator; + + +//------------------------------------------------- +// ROM( pc1640_iga ) +//------------------------------------------------- + +ROM_START( pc1640_iga ) + ROM_REGION16_LE( 0x8000, "iga", 0) + ROM_LOAD( "40100.ic913", 0x0000, 0x8000, CRC(d2d1f1ae) SHA1(98302006ee38a17c09bd75504cc18c0649174e33) ) // 8736 E +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *isa8_pc1640_iga_device::device_rom_region() const +{ + return ROM_NAME( pc1640_iga ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// isa8_pc1640_iga_device - constructor +//------------------------------------------------- + +isa8_pc1640_iga_device::isa8_pc1640_iga_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : isa8_ega_device(mconfig, ISA8_PC1640_IGA, "Amstrad PC1640 IGA", tag, owner, clock, "pc1640_iga", __FILE__) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void isa8_pc1640_iga_device::device_start() +{ + if (m_palette != NULL && !m_palette->started()) + throw device_missing_dependencies(); + + set_isa_device(); + + for (int i = 0; i < 64; i++ ) + { + UINT8 r = ( ( i & 0x04 ) ? 0xAA : 0x00 ) + ( ( i & 0x20 ) ? 0x55 : 0x00 ); + UINT8 g = ( ( i & 0x02 ) ? 0xAA : 0x00 ) + ( ( i & 0x10 ) ? 0x55 : 0x00 ); + UINT8 b = ( ( i & 0x01 ) ? 0xAA : 0x00 ) + ( ( i & 0x08 ) ? 0x55 : 0x00 ); + + m_palette->set_pen_color( i, r, g, b ); + } + + /* Install 256KB Video ram on our EGA card */ + m_vram = machine().memory().region_alloc(subtag("vram").c_str(), 256 * 1024, 1, ENDIANNESS_LITTLE); + + m_videoram = m_vram->base(); + m_plane[0] = m_videoram + 0x00000; + memset(m_plane[0], 0, sizeof(UINT8) * 0x10000); + m_plane[1] = m_videoram + 0x10000; + memset(m_plane[1], 0, sizeof(UINT8) * 0x10000); + m_plane[2] = m_videoram + 0x20000; + memset(m_plane[2], 0, sizeof(UINT8) * 0x10000); + m_plane[3] = m_videoram + 0x30000; + memset(m_plane[3], 0, sizeof(UINT8) * 0x10000); + + m_crtc_ega = subdevice(EGA_CRTC_NAME); + + m_isa->install_rom(this, 0xc0000, 0xc7fff, 0, 0, "ega", "iga"); + m_isa->install_device(0x3b0, 0x3bf, 0, 0, read8_delegate(FUNC(isa8_ega_device::pc_ega8_3b0_r), this), write8_delegate(FUNC(isa8_ega_device::pc_ega8_3b0_w), this)); + m_isa->install_device(0x3c0, 0x3cf, 0, 0, read8_delegate(FUNC(isa8_ega_device::pc_ega8_3c0_r), this), write8_delegate(FUNC(isa8_ega_device::pc_ega8_3c0_w), this)); + m_isa->install_device(0x3d0, 0x3df, 0, 0, read8_delegate(FUNC(isa8_ega_device::pc_ega8_3d0_r), this), write8_delegate(FUNC(isa8_ega_device::pc_ega8_3d0_w), this)); +} diff --git a/src/devices/bus/isa/pc1640_iga.h b/src/devices/bus/isa/pc1640_iga.h new file mode 100644 index 00000000000..3bb632528d4 --- /dev/null +++ b/src/devices/bus/isa/pc1640_iga.h @@ -0,0 +1,46 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Amstrad PC1640 Integrated Graphics Adapter emulation + +**********************************************************************/ + +#pragma once + +#ifndef __ISA8_PC1640_IGA__ +#define __ISA8_PC1640_IGA__ + +#include "emu.h" +#include "isa.h" +#include "ega.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> isa8_pc1640_iga_device + +class isa8_pc1640_iga_device : public isa8_ega_device +{ +public: + // construction/destruction + isa8_pc1640_iga_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + +protected: + // device-level overrides + virtual void device_start(); +}; + + +// device type definition +extern const device_type ISA8_PC1640_IGA; + + + +#endif diff --git a/src/devices/bus/isa/pds.c b/src/devices/bus/isa/pds.c new file mode 100644 index 00000000000..235e0acdd02 --- /dev/null +++ b/src/devices/bus/isa/pds.c @@ -0,0 +1,65 @@ +// license:BSD-3-Clause +// copyright-holders:Barry Rodewald +/* + * isa_pds.c - Programmers Development System 8-bit ISA card + * + * Used to connect up to two 8-bit systems to the PC, allowing the download of assembled code directly to the + * target 8-bit system (Spectrum, CPC, MSX, C64 and maybe the BBC?) + * + * The editor software require the ISA card to be present. + * + * The PC end hardware consists of an 8-bit ISA card containing an 8255 PPI hooked up to the two connectors on the + * back of the card. + * + * The 8-bit end hardware consists of an expansion device containing a Z80PIO. + * + * Created on: 31/01/2014 + */ + +#include "pds.h" + +const device_type ISA8_PDS = &device_creator; + +isa8_pds_device::isa8_pds_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, ISA8_PDS, "Programmers Development System", tag, owner, clock, "isa_pds", __FILE__), + device_isa8_card_interface( mconfig, *this ), + m_ppi(*this,"pds_ppi") +{ +} + + +READ8_MEMBER(isa8_pds_device::ppi_r) +{ + if(!(offset & 0x01)) + return m_ppi->read(space,offset/2); + return 0xff; +} + +WRITE8_MEMBER(isa8_pds_device::ppi_w) +{ + if(!(offset & 0x01)) + m_ppi->write(space,offset/2,data); +} + +void isa8_pds_device::device_start() +{ + set_isa_device(); + m_isa->install_device(0x0300, 0x0307, 0, 0, read8_delegate(FUNC(isa8_pds_device::ppi_r),this), write8_delegate(FUNC(isa8_pds_device::ppi_w),this) ); +} + +void isa8_pds_device::device_reset() +{ +} + +void isa8_pds_device::device_stop() +{ +} + +static MACHINE_CONFIG_FRAGMENT( pds_config ) + MCFG_DEVICE_ADD("pds_ppi", I8255, 0) +MACHINE_CONFIG_END + +machine_config_constructor isa8_pds_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( pds_config ); +} diff --git a/src/devices/bus/isa/pds.h b/src/devices/bus/isa/pds.h new file mode 100644 index 00000000000..d9d255cb19c --- /dev/null +++ b/src/devices/bus/isa/pds.h @@ -0,0 +1,40 @@ +// license:BSD-3-Clause +// copyright-holders:Barry Rodewald +/* + * isa_pds.h + * + * Created on: 31/01/2014 + */ + +#ifndef ISA_PDS_H_ +#define ISA_PDS_H_ + +#include "emu.h" +#include "isa.h" +#include "machine/i8255.h" + +class isa8_pds_device : + public device_t, + public device_isa8_card_interface +{ +public: + isa8_pds_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + DECLARE_READ8_MEMBER(ppi_r); + DECLARE_WRITE8_MEMBER(ppi_w); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + + required_device m_ppi; +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_stop(); + +}; + +extern const device_type ISA8_PDS; + +#endif /* ISA_PDS_H_ */ diff --git a/src/devices/bus/isa/pgc.c b/src/devices/bus/isa/pgc.c new file mode 100644 index 00000000000..ed191e070c3 --- /dev/null +++ b/src/devices/bus/isa/pgc.c @@ -0,0 +1,372 @@ +// license:BSD-3-Clause +// copyright-holders:Sergey Svishchev + +/*************************************************************************** + + IBM Professional Graphics Controller (PGC), skeleton driver. + + Designed for IBM by Vermont Microsystems. References: + + IBM Options and Adapters manual + http://www.minuszerodegrees.net/oa/OA%20-%20IBM%20Professional%20Graphics%20Controller.pdf + http://bitsavers.org/pdf/ibm/pc/cards/Technical_Reference_Options_and_Adapters_Volume_3.pdf + IBM Systems Journal white paper + http://wayback.archive.org/web/20061015235146/http://www.research.ibm.com/journal/sj/241/ibmsj2401D.pdf + John Elliott's page + http://www.seasip.info/VintagePC/pgc.html + + To do: + - memory map (restore ROM mapping on reset, ...) + - various VRAM write modes + - what's up with irq 3 (= vblank irq)? + - "test pin of the microprocessor samples the hsync pulse" + - CGA emulator + - bus state handling? + - VRAM address translator ROM? + +***************************************************************************/ + +#include "emu.h" + +//nclude "machine/ram.h" + +#include "pgc.h" + +#define VERBOSE_PGC 1 + +#define DBG_LOG(N,M,A) \ + do { \ + if(VERBOSE_PGC>=N) \ + { \ + if( M ) \ + logerror("%11.6f at %s: %-24s",machine().time().as_double(),machine().describe_context(),(char*)M ); \ + logerror A; \ + } \ + } while (0) + +#define PGC_SCREEN_NAME "pgc_screen" + +#define PGC_TOTAL_HORZ 820 +#define PGC_DISP_HORZ 640 +#define PGC_HORZ_START 80 + +#define PGC_TOTAL_VERT 508 +#define PGC_DISP_VERT 480 +#define PGC_VERT_START 10 + +/* + Prototypes +*/ + +ROM_START( pgc ) + ROM_REGION(0x100000, "maincpu", 0) + ROM_DEFAULT_BIOS("1985") + + ROM_SYSTEM_BIOS(0, "1984", "1984 firmware, P/N 6137322/3") + ROMX_LOAD("ibm_6137323_pgc_card_27256.bin", 0x00000, 0x8000, CRC(f564f342) SHA1(c5ef17fd1569043cb59f61faf828ea8b0ee95526), ROM_BIOS(1)) + ROMX_LOAD("ibm_6137322_pgc_card_27256.bin", 0x08000, 0x8000, CRC(5e6cc82f) SHA1(45b3ffb5a9c51986862f8d47b3e03dcaaf4073d5), ROM_BIOS(1)) + + ROM_SYSTEM_BIOS(1, "1985", "1985 firmware, P/N 59X7354/5") + ROMX_LOAD("pgc_u44.bin", 0x00000, 0x8000, CRC(71280241) SHA1(7042ccd4ebd03f576a256a433b8aa38d1b4fefa8), ROM_BIOS(2)) + ROMX_LOAD("pgc_u43.bin", 0x08000, 0x8000, CRC(923f5ea3) SHA1(2b2a55d64b20d3a613b00c51443105aa03eca5d6), ROM_BIOS(2)) + + ROM_REGION(0x800, "commarea", ROMREGION_ERASE00) + + ROM_REGION(0x1000, "chargen", 0) + ROM_LOAD("pgc_u27.bin", 0x0000, 0x1000, CRC(6be256cc) SHA1(deb1195886268dcddce10459911e020f7a9f74f7)) +ROM_END + +static INPUT_PORTS_START( pgc ) + PORT_START("DSW") +/* + PORT_DIPNAME( 0x01, 0x00, "CGA emulator") + PORT_DIPSETTING( 0x00, DEF_STR(No) ) + PORT_DIPSETTING( 0x01, DEF_STR(Yes) ) +*/ + PORT_DIPNAME( 0x02, 0x00, "Communication area") + PORT_DIPSETTING( 0x00, "C6000" ) + PORT_DIPSETTING( 0x02, "C6400" ) +INPUT_PORTS_END + +/* +write only + 30000 LUT WR O L + 30001 LUT WR I L + 32000 MODE WT L + 32001 NIBBLE WT L + 3200A ?? + 34000 FUNCTION WT L + 34001 STARTADD WT L + 36001 CURSOR WT L + +read only + 38000 LUT RD O L + 38001 LUT RD I L + 3C001 INIT L/INIT H +*/ + +static ADDRESS_MAP_START( pgc_map, AS_PROGRAM, 8, isa8_pgc_device ) + ADDRESS_MAP_UNMAP_HIGH + AM_RANGE(0x00000, 0x07fff) AM_ROM + AM_RANGE(0x08000, 0x0ffff) AM_ROM AM_REGION("maincpu", 0x8000) + AM_RANGE(0x10000, 0x1001f) AM_READWRITE(stateparam_r, stateparam_w) +// AM_RANGE(0x18000, 0x18fff) AM_RAM // ?? + AM_RANGE(0x28000, 0x287ff) AM_RAM AM_REGION("commarea", 0) AM_MIRROR(0x800) + AM_RANGE(0x3c000, 0x3c001) AM_READ(init_r) +// AM_RANGE(0x3e000, 0x3efff) AM_RAM // ?? + AM_RANGE(0xf8000, 0xfffff) AM_ROM AM_REGION("maincpu", 0x8000) +ADDRESS_MAP_END + +static ADDRESS_MAP_START( pgc_io, AS_IO, 8, isa8_pgc_device ) + ADDRESS_MAP_UNMAP_HIGH +ADDRESS_MAP_END + +static const gfx_layout pgc_charlayout = +{ + 8, 16, /* 8x16 pixels */ + 256, /* 256 characters */ + 1, /* 1 bits per pixel */ + { 0 }, /* no bitplanes */ + /* x offsets */ + { 0, 1, 2, 3, 4, 5, 6, 7 }, + /* y offsets */ + { 0*8, 1*8, 2*8, 3*8, 4*8, 5*8, 6*8, 7*8, 8*8, 9*8, 10*8, 11*8, 12*8, 13*8, 14*8, 15*8 }, + 8*16 /* every char takes 10 bytes */ +}; + +static GFXDECODE_START( pgc ) + GFXDECODE_REVERSEBITS("chargen", 0, pgc_charlayout, 0, 1) +GFXDECODE_END + +MACHINE_CONFIG_FRAGMENT( pcvideo_pgc ) + MCFG_CPU_ADD("maincpu", I8088, XTAL_24MHz/3) + MCFG_CPU_PROGRAM_MAP(pgc_map) + MCFG_CPU_IO_MAP(pgc_io) +#if 0 + MCFG_CPU_VBLANK_INT_DRIVER(PGC_SCREEN_NAME, isa8_pgc_device, vblank_irq) + MCFG_CPU_IRQ_ACKNOWLEDGE_DRIVER(isa8_pgc_device, irq_callback) +#endif + + MCFG_TIMER_DRIVER_ADD_PERIODIC("scantimer", isa8_pgc_device, scanline_callback, + attotime::from_hz(60*PGC_TOTAL_VERT)) + MCFG_TIMER_START_DELAY(attotime::from_hz(XTAL_50MHz/(2*PGC_HORZ_START))) + + MCFG_SCREEN_ADD(PGC_SCREEN_NAME, RASTER) + MCFG_SCREEN_RAW_PARAMS(XTAL_50MHz/2, + PGC_TOTAL_HORZ, PGC_HORZ_START, PGC_HORZ_START+PGC_DISP_HORZ, + PGC_TOTAL_VERT, PGC_VERT_START, PGC_VERT_START+PGC_DISP_VERT) + MCFG_SCREEN_UPDATE_DRIVER(isa8_pgc_device, screen_update) + MCFG_SCREEN_PALETTE("palette") + + MCFG_GFXDECODE_ADD("gfxdecode", "palette", pgc) + MCFG_PALETTE_ADD( "palette", 256 ) +MACHINE_CONFIG_END + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type ISA8_PGC = &device_creator; + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor isa8_pgc_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( pcvideo_pgc ); +} + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *isa8_pgc_device::device_rom_region() const +{ + return ROM_NAME( pgc ); +} + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor isa8_pgc_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( pgc ); +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// isa8_pgc_device - constructor +//------------------------------------------------- + +isa8_pgc_device::isa8_pgc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, ISA8_PGC, "IBM Professional Graphics Controller", tag, owner, clock, "isa_ibm_pgc", __FILE__), + device_isa8_card_interface(mconfig, *this), + m_cpu(*this, "maincpu"), + m_screen(*this, PGC_SCREEN_NAME), + m_palette(*this, "palette") +{ +} + +isa8_pgc_device::isa8_pgc_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_isa8_card_interface(mconfig, *this), + m_cpu(*this, "maincpu"), + m_screen(*this, PGC_SCREEN_NAME), + m_palette(*this, "palette") +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void isa8_pgc_device::device_start() +{ + address_space &space = m_cpu->space( AS_PROGRAM ); + int width = PGC_DISP_HORZ; + int height = PGC_DISP_VERT; + + if (m_palette != NULL && !m_palette->started()) + throw device_missing_dependencies(); + + set_isa_device(); + + for (int i = 0; i < 256; i++ ) + { + m_palette->set_pen_color( i, 0, 0, 0 ); + } + + m_bitmap = auto_bitmap_ind16_alloc(machine(), width, height); + m_bitmap->fill(0); + + m_vram = auto_alloc_array(machine(), UINT8, 0x78000); + space.install_readwrite_bank(0x80000, 0xf7fff, "vram"); + membank("vram")->set_base(m_vram); + + m_eram = auto_alloc_array(machine(), UINT8, 0x8000); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void isa8_pgc_device::device_reset() +{ + memset(m_stateparam, 0, sizeof(m_stateparam)); + memset(m_lut, 0, sizeof(m_lut)); + + m_commarea = memregion("commarea")->base(); + if (BIT(ioport("DSW")->read(), 1)) + m_isa->install_bank(0xc6400, 0xc67ff, 0, 0, "commarea", m_commarea); + else + m_isa->install_bank(0xc6000, 0xc63ff, 0, 0, "commarea", m_commarea); +#if 0 + address_space &space = m_cpu->space( AS_PROGRAM ); + + space.unmap_readwrite(0xf8000, 0xfffff); + space.install_rom(0xf8000, 0xfffff, + space.machine().root_device().memregion("maincpu")->base() + 0x8000); +#endif +} + +// + +INTERRUPT_GEN_MEMBER(isa8_pgc_device::vblank_irq) +{ + DBG_LOG(2,"irq",("vblank_irq\n")); + m_cpu->set_input_line(0, ASSERT_LINE); +} + +IRQ_CALLBACK_MEMBER(isa8_pgc_device::irq_callback) +{ + DBG_LOG(2,"irq",("irq_callback\n")); + m_cpu->set_input_line(0, CLEAR_LINE); + return 3; +} + +// memory handlers + +READ8_MEMBER( isa8_pgc_device::stateparam_r ) { + UINT8 ret; + + ret = m_stateparam[offset >> 1]; + if ((machine().debug_flags & DEBUG_FLAG_ENABLED) != 0) + { + DBG_LOG(1,"stateparam",("R @ %02x == %02x\n", offset, ret)); + } + return ret; +} + +WRITE8_MEMBER( isa8_pgc_device::stateparam_w ) { + if ((machine().debug_flags & DEBUG_FLAG_ENABLED) != 0) + { + DBG_LOG(1,"stateparam",("W @ %02x <- %02x\n", offset, data)); + } + m_stateparam[offset >> 1] = data; +} + +WRITE8_MEMBER( isa8_pgc_device::lut_w ) { + UINT8 o = (offset >> 1) * 3; + + if (offset & 1) { + m_lut[o + 2] = (data & 15) << 4; + m_palette->set_pen_color( offset >> 1, m_lut[o], m_lut[o + 1], m_lut[o + 2] ); + DBG_LOG(1,"lut",("W @ %02X <- %d %d %d\n", + offset >> 1, m_lut[o], m_lut[o + 1], m_lut[o + 2] )); + } else { + m_lut[o ] = data & 0xf0; + m_lut[o + 1] = (data & 15) << 4; + } +} + +READ8_MEMBER( isa8_pgc_device::init_r ) { + DBG_LOG(1,"INIT",("unmapping ROM\n")); + space.unmap_read(0xf8000, 0xfffff); + + DBG_LOG(1,"INIT",("mapping emulator RAM\n")); + space.install_readwrite_bank(0xf8000, 0xfffff, "eram"); + membank("eram")->set_base(m_eram); + + DBG_LOG(1,"INIT",("mapping LUT\n")); + space.install_write_handler(0xf8400, 0xf85ff, + write8_delegate(FUNC(isa8_pgc_device::lut_w), this)); + + return 0; // XXX ignored +} + +TIMER_DEVICE_CALLBACK_MEMBER(isa8_pgc_device::scanline_callback) +{ + UINT16 x, y = m_screen->vpos(); + UINT16 *p; + UINT8 *v; + + // XXX hpos shifts every frame -- fix + if (y == 0) DBG_LOG(2,"scanline_cb", + ("frame %d x %.4d y %.3d\n", + (int) m_screen->frame_number(), m_screen->hpos(), y)); + + if (y < PGC_VERT_START) return; + y -= PGC_VERT_START; + if (y >= PGC_DISP_VERT) return; + + // XXX address translation happens in hardware + v = &m_vram[y * 1024]; + p = &m_bitmap->pix16(y, 0); + + for (x = 0; x < PGC_DISP_HORZ; x++) { + *p++ = *v++; + } +} + +UINT32 isa8_pgc_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) +{ + copybitmap(bitmap, *m_bitmap, 0, 0, PGC_HORZ_START, PGC_VERT_START, cliprect); + return 0; +} diff --git a/src/devices/bus/isa/pgc.h b/src/devices/bus/isa/pgc.h new file mode 100644 index 00000000000..bb51fa9d177 --- /dev/null +++ b/src/devices/bus/isa/pgc.h @@ -0,0 +1,67 @@ +// license:BSD-3-Clause +// copyright-holders:Sergey Svishchev + +#pragma once + +#ifndef __ISA_PGC_H__ +#define __ISA_PGC_H__ + +#include "emu.h" + +#include "cpu/i86/i86.h" +#include "isa.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> isa8_pgc_device + +class isa8_pgc_device : + public device_t, + public device_isa8_card_interface +{ +public: + // construction/destruction + isa8_pgc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + isa8_pgc_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual const rom_entry *device_rom_region() const; + virtual ioport_constructor device_input_ports() const; + + UINT32 screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); + + TIMER_DEVICE_CALLBACK_MEMBER( scanline_callback ); + INTERRUPT_GEN_MEMBER(vblank_irq); + IRQ_CALLBACK_MEMBER(irq_callback); + + DECLARE_WRITE8_MEMBER( stateparam_w ); + DECLARE_READ8_MEMBER( stateparam_r ); + DECLARE_WRITE8_MEMBER( lut_w ); + DECLARE_READ8_MEMBER( init_r ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + +private: + required_device m_cpu; + required_device m_screen; + required_device m_palette; + + UINT8 *m_commarea; + UINT8 *m_vram; + UINT8 *m_eram; + UINT8 m_stateparam[16]; + UINT8 m_lut[256*3]; + bitmap_ind16 *m_bitmap; +}; + + +// device type definition +extern const device_type ISA8_PGC; + +#endif /* __ISA_PGC_H__ */ diff --git a/src/devices/bus/isa/s3virge.c b/src/devices/bus/isa/s3virge.c new file mode 100644 index 00000000000..965e47e50f0 --- /dev/null +++ b/src/devices/bus/isa/s3virge.c @@ -0,0 +1,776 @@ +// license:BSD-3-Clause +// copyright-holders:Barry Rodewald +/* + * s3virge.c + * + * Implementation of the S3 Virge series of video card + * + * Current status: + * - Working on getting VESA video modes working better - 800x600 and higher skip every other line at + * 8-bit depth, but are fine at 15/16-bit depth. + * - S3D is not implemented at all, so no 2D/3D acceleration yet. + */ + +#include "s3virge.h" + +#define CRTC_PORT_ADDR ((vga.miscellaneous_output&1)?0x3d0:0x3b0) +#define LOG_REG 1 + +const device_type S3VIRGE = &device_creator; +const device_type S3VIRGEDX = &device_creator; +const device_type S3VIRGEDX1 = &device_creator; + +s3virge_vga_device::s3virge_vga_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : s3_vga_device(mconfig, S3VIRGE, "S3 86C325", tag, owner, clock, "virge_vga", __FILE__) +{ +} + +s3virge_vga_device::s3virge_vga_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : s3_vga_device(mconfig, type, name, tag, owner, clock, shortname, source) +{ +} + +s3virgedx_vga_device::s3virgedx_vga_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : s3virge_vga_device(mconfig, S3VIRGEDX, "S3 86C375", tag, owner, clock, "virgedx_vga", __FILE__) +{ +} + +s3virgedx_vga_device::s3virgedx_vga_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : s3virge_vga_device(mconfig, type, name, tag, owner, clock, shortname, source) +{ +} + +s3virgedx_rev1_vga_device::s3virgedx_rev1_vga_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : s3virgedx_vga_device(mconfig, S3VIRGEDX1, "S3 86C375 (rev 1)", tag, owner, clock, "virgedx_r1", __FILE__) +{ +} + +void s3virge_vga_device::device_start() +{ + zero(); + + int x; + int i; + for (i = 0; i < 0x100; i++) + m_palette->set_pen_color(i, 0, 0, 0); + + // Avoid an infinite loop when displaying. 0 is not possible anyway. + vga.crtc.maximum_scan_line = 1; + + // copy over interfaces + vga.read_dipswitch = read8_delegate(); //read_dipswitch; + vga.svga_intf.seq_regcount = 0x1c; + vga.svga_intf.crtc_regcount = 0x19; + vga.svga_intf.vram_size = 0x400000; + vga.memory.resize(vga.svga_intf.vram_size); + memset(&vga.memory[0], 0, vga.svga_intf.vram_size); + save_item(vga.memory,"Video RAM"); + save_pointer(vga.crtc.data,"CRTC Registers",0x100); + save_pointer(vga.sequencer.data,"Sequencer Registers",0x100); + save_pointer(vga.attribute.data,"Attribute Registers", 0x15); + + m_vblank_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(vga_device::vblank_timer_cb),this)); + + memset(&s3, 0, sizeof(s3)); + // Initialise hardware graphics cursor colours, Windows 95 doesn't touch the registers for some reason + for(x=0;x<4;x++) + { + s3.cursor_fg[x] = 0xff; + s3.cursor_bg[x] = 0x00; + } + // set device ID + s3.id_high = 0x56; // CR2D + s3.id_low = 0x31; // CR2E + s3.revision = 0x00; // CR2F (value unknown) + s3.id_cr30 = 0xe1; // CR30 +} + +void s3virgedx_vga_device::device_start() +{ + s3virge_vga_device::device_start(); + + // set device ID + s3.id_high = 0x8a; // CR2D + s3.id_low = 0x01; // CR2E + s3.revision = 0x00; // CR2F (value unknown) + s3.id_cr30 = 0xe1; // CR30 +} + +void s3virgedx_rev1_vga_device::device_start() +{ + s3virge_vga_device::device_start(); + + // set device ID + s3.id_high = 0x8a; // CR2D + s3.id_low = 0x01; // CR2E + s3.revision = 0x01; // CR2F + s3.id_cr30 = 0xe1; // CR30 +} + +void s3virge_vga_device::device_reset() +{ + vga_device::device_reset(); + // Power-on strapping bits. Sampled at reset, but can be modified later. + // These are just assumed defaults. + s3.strapping = 0x000f0912; +} + +void s3virgedx_vga_device::device_reset() +{ + vga_device::device_reset(); + // Power-on strapping bits. Sampled at reset, but can be modified later. + // These are just assumed defaults. + s3.strapping = 0x000f0912; +} + +void s3virgedx_rev1_vga_device::device_reset() +{ + vga_device::device_reset(); + // Power-on strapping bits. Sampled at reset, but can be modified later. + // These are based on results from a Diamond Stealth 3D 2000 Pro (Virge/DX based) + // bits 8-15 are still unknown, S3ID doesn't show config register 2 (CR37) + s3.strapping = 0x0aff0912; +} + +UINT8 s3virge_vga_device::s3_crtc_reg_read(UINT8 index) +{ + UINT8 res; + + if(index <= 0x18) + res = crtc_reg_read(index); + else + { + switch(index) + { + case 0x2d: + res = s3.id_high; + break; + case 0x2e: + res = s3.id_low; + break; + case 0x2f: + res = s3.revision; + break; + case 0x30: // CR30 Chip ID/REV register + res = s3.id_cr30; + break; + case 0x31: + res = s3.memory_config; + break; + case 0x35: + res = s3.crt_reg_lock; + break; + case 0x36: // Configuration register 1 + res = s3.strapping & 0x000000ff; + break; + case 0x37: // Configuration register 2 + res = (s3.strapping & 0x0000ff00) >> 8; + break; + case 0x38: + res = s3.reg_lock1; + break; + case 0x39: + res = s3.reg_lock2; + break; + case 0x42: // CR42 Mode Control + res = s3.cr42 & 0x0f; // bit 5 set if interlaced, leave it unset for now. + break; + case 0x43: + res = s3.cr43; + break; + case 0x45: + res = s3.cursor_mode; + break; + case 0x46: + res = (s3.cursor_x & 0xff00) >> 8; + break; + case 0x47: + res = s3.cursor_x & 0x00ff; + break; + case 0x48: + res = (s3.cursor_y & 0xff00) >> 8; + break; + case 0x49: + res = s3.cursor_y & 0x00ff; + break; + case 0x4a: + res = s3.cursor_fg[s3.cursor_fg_ptr]; + s3.cursor_fg_ptr = 0; + break; + case 0x4b: + res = s3.cursor_bg[s3.cursor_bg_ptr]; + s3.cursor_bg_ptr = 0; + break; + case 0x4c: + res = (s3.cursor_start_addr & 0xff00) >> 8; + break; + case 0x4d: + res = s3.cursor_start_addr & 0x00ff; + break; + case 0x4e: + res = s3.cursor_pattern_x; + break; + case 0x4f: + res = s3.cursor_pattern_y; + break; + case 0x51: + res = (vga.crtc.start_addr_latch & 0x0c0000) >> 18; + res |= ((svga.bank_w & 0x30) >> 2); + break; + case 0x55: + res = s3.extended_dac_ctrl; + break; + case 0x5c: + // if VGA dot clock is set to 3 (misc reg bits 2-3), then selected dot clock is read, otherwise read VGA clock select + if((vga.miscellaneous_output & 0xc) == 0x0c) + res = s3.cr42 & 0x0f; + else + res = (vga.miscellaneous_output & 0xc) >> 2; + break; + case 0x67: + res = s3.ext_misc_ctrl_2; + break; + case 0x68: // Configuration register 3 + res = (s3.strapping & 0x00ff0000) >> 16; + break; + case 0x69: + res = vga.crtc.start_addr_latch >> 16; + break; + case 0x6a: + res = svga.bank_r & 0x7f; + break; + case 0x6f: // Configuration register 4 + res = (s3.strapping & 0xff000000) >> 24; + break; + default: + res = vga.crtc.data[index]; + //debugger_break(machine); + //printf("%02x\n",index); + break; + } + } + + return res; +} + +void s3virge_vga_device::s3_define_video_mode() +{ + int divisor = 1; + int xtal = (vga.miscellaneous_output & 0xc) ? XTAL_28_63636MHz : XTAL_25_1748MHz; + double freq; + + if((vga.miscellaneous_output & 0xc) == 0x0c) + { + // Dot clock is set via SR12 and SR13 + // DCLK calculation + freq = ((double)(s3.clk_pll_m+2) / (double)((s3.clk_pll_n+2)*(pow(2.0,s3.clk_pll_r)))) * 14.318; // clock between XIN and XOUT + xtal = freq * 1000000; + //printf("DCLK set to %dHz M=%i N=%i R=%i\n",xtal,s3.clk_pll_m,s3.clk_pll_n,s3.clk_pll_r); + } + + if((s3.ext_misc_ctrl_2) >> 4) + { + svga.rgb8_en = 0; + svga.rgb15_en = 0; + svga.rgb16_en = 0; + svga.rgb32_en = 0; + switch((s3.ext_misc_ctrl_2) >> 4) + { + case 0x01: svga.rgb8_en = 1; break; + case 0x03: svga.rgb15_en = 1; divisor = 2; break; + case 0x05: svga.rgb16_en = 1; divisor = 2; break; + case 0x0d: svga.rgb32_en = 1; divisor = 1; break; + default: fatalerror("TODO: s3 video mode not implemented %02x\n",((s3.ext_misc_ctrl_2) >> 4)); + } + } + else + { + svga.rgb8_en = (s3.cr3a & 0x10) >> 4; + svga.rgb15_en = 0; + svga.rgb16_en = 0; + svga.rgb32_en = 0; + } + if(s3.cr43 & 0x80) // Horizontal clock doubling (techincally, doubles horizontal CRT parameters) + divisor *= 2; + recompute_params_clock(divisor, xtal); +} + +void s3virge_vga_device::s3_crtc_reg_write(UINT8 index, UINT8 data) +{ + if(index <= 0x18) + { + crtc_reg_write(index,data); + s3_define_video_mode(); + } + else + { + switch(index) + { + case 0x31: // CR31 Memory Configuration Register + s3.memory_config = data; + vga.crtc.start_addr_latch &= ~0x30000; + vga.crtc.start_addr_latch |= ((data & 0x30) << 12); + s3_define_video_mode(); + break; + case 0x35: + if((s3.reg_lock1 & 0xc) != 8 || ((s3.reg_lock1 & 0xc0) == 0)) // lock register + return; + s3.crt_reg_lock = data; + svga.bank_w = data & 0xf; + svga.bank_r = svga.bank_w; + break; + case 0x36: + if(s3.reg_lock2 == 0xa5) + { + s3.strapping = (s3.strapping & 0xffffff00) | data; + logerror("CR36: Strapping data = %08x\n",s3.strapping); + } + break; + case 0x37: + if(s3.reg_lock2 == 0xa5) + { + s3.strapping = (s3.strapping & 0xffff00ff) | (data << 8); + logerror("CR37: Strapping data = %08x\n",s3.strapping); + } + break; + case 0x38: + s3.reg_lock1 = data; + break; + case 0x39: + /* TODO: reg lock mechanism */ + s3.reg_lock2 = data; + break; + case 0x3a: + s3.cr3a = data; + break; + case 0x40: + s3.enable_s3d = data & 0x01; // enable S3D registers + break; + case 0x42: + s3.cr42 = data; // bit 5 = interlace, bits 0-3 = dot clock (seems to be undocumented) + break; + case 0x43: + s3.cr43 = data; // bit 2 = bit 8 of offset register, but only if bits 4-5 of CR51 are 00h. + vga.crtc.offset = (vga.crtc.offset & 0x00ff) | ((data & 0x04) << 6); + s3_define_video_mode(); + break; +/* +3d4h index 45h (R/W): CR45 Hardware Graphics Cursor Mode +bit 0 HWGC ENB. Hardware Graphics Cursor Enable. Set to enable the + HardWare Cursor in VGA and enhanced modes. + 1 (911/24) Delay Timing for Pattern Data Fetch + 2 (801/5,928) Hardware Cursor Horizontal Stretch 2. If set the cursor + pixels are stretched horizontally to two bytes and items 0 and 1 of + the fore/background stacks in 3d4h index 4Ah/4Bh are used. + 3 (801/5,928) Hardware Cursor Horizontal Stretch 3. If set the cursor + pixels are stretched horizontally to three bytes and items 0,1 and + 2 of the fore/background stacks in 3d4h index 4Ah/4Bh are used. + 2-3 (805i,864/964) HWC-CSEL. Hardware Cursor Color Select. + 0: 4/8bit, 1: 15/16bt, 2: 24bit, 3: 32bit + Note: So far I've had better luck with: 0: 8/15/16bit, 1: 32bit?? + 4 (80x +) Hardware Cursor Right Storage. If set the cursor data is + stored in the last 256 bytes of 4 1Kyte lines (4bits/pixel) or the + last 512 bytes of 2 2Kbyte lines (8bits/pixel). Intended for + 1280x1024 modes where there are no free lines at the bottom. + 5 (928) Cursor Control Enable for Brooktree Bt485 DAC. If set and 3d4h + index 55h bit 5 is set the HC1 output becomes the ODF and the HC0 + output becomes the CDE + (964) BT485 ODF Selection for Bt485A RAMDAC. If set pin 185 (RS3 + /ODF) is the ODF output to a Bt485A compatible RamDAC (low for even + fields and high for odd fields), if clear pin185 is the RS3 output. + */ + case 0x45: + s3.cursor_mode = data; + break; +/* +3d4h index 46h M(R/W): CR46/7 Hardware Graphics Cursor Origin-X +bit 0-10 The HardWare Cursor X position. For 64k modes this value should be + twice the actual X co-ordinate. + */ + case 0x46: + s3.cursor_x = (s3.cursor_x & 0x00ff) | (data << 8); + break; + case 0x47: + s3.cursor_x = (s3.cursor_x & 0xff00) | data; + break; +/* +3d4h index 48h M(R/W): CR48/9 Hardware Graphics Cursor Origin-Y +bit 0-9 (911/24) The HardWare Cursor Y position. + 0-10 (80x +) The HardWare Cursor Y position. +Note: The position is activated when the high byte of the Y coordinate (index + 48h) is written, so this byte should be written last (not 911/924 ?) + */ + case 0x48: + s3.cursor_y = (s3.cursor_y & 0x00ff) | (data << 8); + break; + case 0x49: + s3.cursor_y = (s3.cursor_y & 0xff00) | data; + break; + +/* +3d4h index 4Ah (R/W): Hardware Graphics Cursor Foreground Stack (80x +) +bit 0-7 The Foreground Cursor color. Three bytes (4 for the 864/964) are + stacked here. When the Cursor Mode register (3d4h index 45h) is read + the stackpointer is reset. When a byte is written the byte is + written into the current top of stack and the stackpointer is + increased. The first byte written (item 0) is allways used, the + other two(3) only when Hardware Cursor Horizontal Stretch (3d4h + index 45h bit 2-3) is enabled. + */ + case 0x4a: + s3.cursor_fg[s3.cursor_fg_ptr++] = data; + s3.cursor_fg_ptr %= 4; + break; +/* +3d4h index 4Bh (R/W): Hardware Graphics Cursor Background Stack (80x +) +bit 0-7 The Background Cursor color. Three bytes (4 for the 864/964) are + stacked here. When the Cursor Mode register (3d4h index 45h) is read + the stackpointer is reset. When a byte is written the byte is + written into the current top of stack and the stackpointer is + increased. The first byte written (item 0) is allways used, the + other two(3) only when Hardware Cursor Horizontal Stretch (3d4h + index 45h bit 2-3) is enabled. + */ + case 0x4b: + s3.cursor_bg[s3.cursor_bg_ptr++] = data; + s3.cursor_bg_ptr %= 4; + break; +/* +3d4h index 4Ch M(R/W): CR4C/D Hardware Graphics Cursor Storage Start Address +bit 0-9 (911,924) HCS_STADR. Hardware Graphics Cursor Storage Start Address + 0-11 (80x,928) HWGC_STA. Hardware Graphics Cursor Storage Start Address + 0-12 (864,964) HWGC_STA. Hardware Graphics Cursor Storage Start Address + Address of the HardWare Cursor Map in units of 1024 bytes (256 bytes + for planar modes). The cursor map is a 64x64 bitmap with 2 bits (A + and B) per pixel. The map is stored as one word (16 bits) of bit A, + followed by one word with the corresponding 16 B bits. + The bits are interpreted as: + A B MS-Windows: X-11: + 0 0 Background Screen data + 0 1 Foreground Screen data + 1 0 Screen data Background + 1 1 Inverted screen Foreground + The Windows/X11 switch is only available for the 80x +. + (911/24) For 64k color modes the cursor is stored as one byte (8 + bits) of A bits, followed by the 8 B-bits, and each bit in the + cursor should be doubled to provide a consistent cursor image. + (801/5,928) For Hi/True color modes use the Horizontal Stretch bits + (3d4h index 45h bits 2 and 3). + */ + case 0x4c: + s3.cursor_start_addr = (s3.cursor_start_addr & 0x00ff) | (data << 8); + break; + case 0x4d: + s3.cursor_start_addr = (s3.cursor_start_addr & 0xff00) | data; + break; +/* +3d4h index 4Eh (R/W): CR4E HGC Pattern Disp Start X-Pixel Position +bit 0-5 Pattern Display Start X-Pixel Position. + */ + case 0x4e: + s3.cursor_pattern_x = data; + break; +/* +3d4h index 4Fh (R/W): CR4F HGC Pattern Disp Start Y-Pixel Position +bit 0-5 Pattern Display Start Y-Pixel Position. + */ + case 0x4f: + s3.cursor_pattern_y = data; + break; + case 0x51: + vga.crtc.start_addr_latch &= ~0xc0000; + vga.crtc.start_addr_latch |= ((data & 0x3) << 18); + svga.bank_w = (svga.bank_w & 0xcf) | ((data & 0x0c) << 2); + svga.bank_r = svga.bank_w; + if((data & 0x30) != 0x00) + vga.crtc.offset = (vga.crtc.offset & 0x00ff) | ((data & 0x30) << 4); + else + vga.crtc.offset = (vga.crtc.offset & 0x00ff) | ((s3.cr43 & 0x04) << 6); + s3_define_video_mode(); + break; + case 0x53: + s3.cr53 = data; + break; +/* +3d4h index 55h (R/W): Extended Video DAC Control Register (80x +) +bit 0-1 DAC Register Select Bits. Passed to the RS2 and RS3 pins on the + RAMDAC, allowing access to all 8 or 16 registers on advanced RAMDACs. + If this field is 0, 3d4h index 43h bit 1 is active. + 2 Enable General Input Port Read. If set DAC reads are disabled and the + STRD strobe for reading the General Input Port is enabled for reading + while DACRD is active, if clear DAC reads are enabled. + 3 (928) Enable External SID Operation if set. If set video data is + passed directly from the VRAMs to the DAC rather than through the + VGA chip + 4 Hardware Cursor MS/X11 Mode. If set the Hardware Cursor is in X11 + mode, if clear in MS-Windows mode + 5 (80x,928) Hardware Cursor External Operation Mode. If set the two + bits of cursor data ,is output on the HC[0-1] pins for the video DAC + The SENS pin becomes HC1 and the MID2 pin becomes HC0. + 6 ?? + 7 (80x,928) Disable PA Output. If set PA[0-7] and VCLK are tristated. + (864/964) TOFF VCLK. Tri-State Off VCLK Output. VCLK output tri + -stated if set + */ + case 0x55: + s3.extended_dac_ctrl = data; + break; +/* +3d4h index 5Dh (R/W): Extended Horizontal Overflow Register (80x +) +bit 0 Horizontal Total bit 8. Bit 8 of the Horizontal Total register (3d4h + index 0) + 1 Horizontal Display End bit 8. Bit 8 of the Horizontal Display End + register (3d4h index 1) + 2 Start Horizontal Blank bit 8. Bit 8 of the Horizontal Start Blanking + register (3d4h index 2). + 3 (864,964) EHB+64. End Horizontal Blank +64. If set the /BLANK pulse + is extended by 64 DCLKs. Note: Is this bit 6 of 3d4h index 3 or + does it really extend by 64 ? + 4 Start Horizontal Sync Position bit 8. Bit 8 of the Horizontal Start + Retrace register (3d4h index 4). + 5 (864,964) EHS+32. End Horizontal Sync +32. If set the HSYNC pulse + is extended by 32 DCLKs. Note: Is this bit 5 of 3d4h index 5 or + does it really extend by 32 ? + 6 (928,964) Data Transfer Position bit 8. Bit 8 of the Data Transfer + Position register (3d4h index 3Bh) + 7 (928,964) Bus-Grant Terminate Position bit 8. Bit 8 of the Bus Grant + Termination register (3d4h index 5Fh). +*/ + case 0x5d: + vga.crtc.horz_total = (vga.crtc.horz_total & 0xfeff) | ((data & 0x01) << 8); + vga.crtc.horz_disp_end = (vga.crtc.horz_disp_end & 0xfeff) | ((data & 0x02) << 7); + vga.crtc.horz_blank_start = (vga.crtc.horz_blank_start & 0xfeff) | ((data & 0x04) << 6); + vga.crtc.horz_blank_end = (vga.crtc.horz_blank_end & 0xffbf) | ((data & 0x08) << 3); + vga.crtc.horz_retrace_start = (vga.crtc.horz_retrace_start & 0xfeff) | ((data & 0x10) << 4); + vga.crtc.horz_retrace_end = (vga.crtc.horz_retrace_end & 0xffdf) | (data & 0x20); + s3_define_video_mode(); + break; +/* +3d4h index 5Eh (R/W): Extended Vertical Overflow Register (80x +) +bit 0 Vertical Total bit 10. Bit 10 of the Vertical Total register (3d4h + index 6). Bits 8 and 9 are in 3d4h index 7 bit 0 and 5. + 1 Vertical Display End bit 10. Bit 10 of the Vertical Display End + register (3d4h index 12h). Bits 8 and 9 are in 3d4h index 7 bit 1 + and 6 + 2 Start Vertical Blank bit 10. Bit 10 of the Vertical Start Blanking + register (3d4h index 15h). Bit 8 is in 3d4h index 7 bit 3 and bit 9 + in 3d4h index 9 bit 5 + 4 Vertical Retrace Start bit 10. Bit 10 of the Vertical Start Retrace + register (3d4h index 10h). Bits 8 and 9 are in 3d4h index 7 bit 2 + and 7. + 6 Line Compare Position bit 10. Bit 10 of the Line Compare register + (3d4h index 18h). Bit 8 is in 3d4h index 7 bit 4 and bit 9 in 3d4h + index 9 bit 6. + */ + case 0x5e: + vga.crtc.vert_total = (vga.crtc.vert_total & 0xfbff) | ((data & 0x01) << 10); + vga.crtc.vert_disp_end = (vga.crtc.vert_disp_end & 0xfbff) | ((data & 0x02) << 9); + vga.crtc.vert_blank_start = (vga.crtc.vert_blank_start & 0xfbff) | ((data & 0x04) << 8); + vga.crtc.vert_retrace_start = (vga.crtc.vert_retrace_start & 0xfbff) | ((data & 0x10) << 6); + vga.crtc.line_compare = (vga.crtc.line_compare & 0xfbff) | ((data & 0x40) << 4); + s3_define_video_mode(); + break; + case 0x67: + s3.ext_misc_ctrl_2 = data; + s3_define_video_mode(); + //printf("%02x X\n",data); + break; + case 0x68: + if(s3.reg_lock2 == 0xa5) + { + s3.strapping = (s3.strapping & 0xff00ffff) | (data << 16); + logerror("CR68: Strapping data = %08x\n",s3.strapping); + } + break; + case 0x69: + vga.crtc.start_addr_latch &= ~0x1f0000; + vga.crtc.start_addr_latch |= ((data & 0x1f) << 16); + s3_define_video_mode(); + break; + case 0x6a: + svga.bank_w = data & 0x3f; + svga.bank_r = svga.bank_w; + break; + case 0x6f: + if(s3.reg_lock2 == 0xa5) + { + s3.strapping = (s3.strapping & 0x00ffffff) | (data << 24); + logerror("CR6F: Strapping data = %08x\n",s3.strapping); + } + break; + default: + if(LOG_REG) logerror("S3: CR%02X write %02x\n",index,data); + break; + } + } +} + + +READ8_MEMBER(s3virge_vga_device::port_03b0_r) +{ + UINT8 res = 0xff; + + if (CRTC_PORT_ADDR == 0x3b0) + { + switch(offset) + { + case 5: + res = s3_crtc_reg_read(vga.crtc.index); + break; + default: + res = vga_device::port_03b0_r(space,offset,mem_mask); + break; + } + } + + return res; +} + +WRITE8_MEMBER(s3virge_vga_device::port_03b0_w) +{ + if (CRTC_PORT_ADDR == 0x3b0) + { + switch(offset) + { + case 5: + vga.crtc.data[vga.crtc.index] = data; + s3_crtc_reg_write(vga.crtc.index,data); + break; + default: + vga_device::port_03b0_w(space,offset,data,mem_mask); + break; + } + } +} + +READ8_MEMBER(s3virge_vga_device::port_03c0_r) +{ + UINT8 res; + + switch(offset) + { + default: + res = s3_vga_device::port_03c0_r(space,offset,mem_mask); + break; + } + + return res; +} + +WRITE8_MEMBER(s3virge_vga_device::port_03c0_w) +{ + switch(offset) + { + default: + s3_vga_device::port_03c0_w(space,offset,data,mem_mask); + break; + } +} + +READ8_MEMBER(s3virge_vga_device::port_03d0_r) +{ + UINT8 res = 0xff; + + if (CRTC_PORT_ADDR == 0x3d0) + { + switch(offset) + { + case 5: + res = s3_crtc_reg_read(vga.crtc.index); + break; + default: + res = vga_device::port_03d0_r(space,offset,mem_mask); + break; + } + } + + return res; +} + +WRITE8_MEMBER(s3virge_vga_device::port_03d0_w) +{ + if (CRTC_PORT_ADDR == 0x3d0) + { + switch(offset) + { + case 5: + vga.crtc.data[vga.crtc.index] = data; + s3_crtc_reg_write(vga.crtc.index,data); + break; + default: + vga_device::port_03d0_w(space,offset,data,mem_mask); + break; + } + } +} + +READ8_MEMBER(s3virge_vga_device::mem_r) +{ + if (svga.rgb8_en || svga.rgb15_en || svga.rgb16_en || svga.rgb32_en) + { + UINT8 data; + if(offset & 0x10000) + return 0; + data = 0xff; + if(vga.sequencer.data[4] & 0x8) + { + if(offset + (svga.bank_r*0x10000) < vga.svga_intf.vram_size) + data = vga.memory[offset + (svga.bank_r*0x10000)]; + } + else + { + int i; + + for(i=0;i<4;i++) + { + if(vga.sequencer.map_mask & 1 << i) + { + if(offset*4+i+(svga.bank_r*0x10000) < vga.svga_intf.vram_size) + data |= vga.memory[offset*4+i+(svga.bank_r*0x10000)]; + } + } + } + return data; + } + if((offset + (svga.bank_r*0x10000)) < vga.svga_intf.vram_size) + return vga_device::mem_r(space,offset,mem_mask); + else + return 0xff; +} + +WRITE8_MEMBER(s3virge_vga_device::mem_w) +{ + // bit 4 of CR53 enables memory-mapped I/O + if(s3.cr53 & 0x10) + { + // TODO + } + + if (svga.rgb8_en || svga.rgb15_en || svga.rgb16_en || svga.rgb32_en) + { + // printf("%08x %02x (%02x %02x) %02X\n",offset,data,vga.sequencer.map_mask,svga.bank_w,(vga.sequencer.data[4] & 0x08)); + if(offset & 0x10000) + return; + if(vga.sequencer.data[4] & 0x8) + { + if((offset + (svga.bank_w*0x10000)) < vga.svga_intf.vram_size) + vga.memory[(offset + (svga.bank_w*0x10000))] = data; + } + else + { + int i; + for(i=0;i<4;i++) + { + if(vga.sequencer.map_mask & 1 << i) + { + if((offset*4+i+(svga.bank_w*0x10000)) < vga.svga_intf.vram_size) + vga.memory[(offset*4+i+(svga.bank_w*0x10000))] = data; + } + } + } + return; + } + + if((offset + (svga.bank_w*0x10000)) < vga.svga_intf.vram_size) + vga_device::mem_w(space,offset,data,mem_mask); +} diff --git a/src/devices/bus/isa/s3virge.h b/src/devices/bus/isa/s3virge.h new file mode 100644 index 00000000000..44bed38689f --- /dev/null +++ b/src/devices/bus/isa/s3virge.h @@ -0,0 +1,82 @@ +// license:BSD-3-Clause +// copyright-holders:Barry Rodewald +/* + * s3virge.h + * + * S3 ViRGE 2D/3D video card + * + */ + +#ifndef S3VIRGE_H_ +#define S3VIRGE_H_ + +#include "emu.h" +#include "video/pc_vga.h" + +// ======================> s3virge_vga_device + +class s3virge_vga_device : public s3_vga_device +{ +public: + // construction/destruction + s3virge_vga_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + s3virge_vga_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + virtual READ8_MEMBER(port_03b0_r); + virtual WRITE8_MEMBER(port_03b0_w); + virtual READ8_MEMBER(port_03c0_r); + virtual WRITE8_MEMBER(port_03c0_w); + virtual READ8_MEMBER(port_03d0_r); + virtual WRITE8_MEMBER(port_03d0_w); + virtual READ8_MEMBER(mem_r); + virtual WRITE8_MEMBER(mem_w); + + ibm8514a_device* get_8514() { fatalerror("s3virge requested non-existant 8514/A device\n"); return NULL; } +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + +private: + virtual UINT8 s3_crtc_reg_read(UINT8 index); + virtual void s3_define_video_mode(void); + virtual void s3_crtc_reg_write(UINT8 index, UINT8 data); + // has no 8514/A device +}; + + +// ======================> s3virgedx_vga_device + +class s3virgedx_vga_device : public s3virge_vga_device +{ +public: + // construction/destruction + s3virgedx_vga_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + s3virgedx_vga_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); +}; + +// ======================> s3virgedx_vga_device + +class s3virgedx_rev1_vga_device : public s3virgedx_vga_device +{ +public: + // construction/destruction + s3virgedx_rev1_vga_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); +}; + +// device type definition +extern const device_type S3VIRGE; +extern const device_type S3VIRGEDX; +extern const device_type S3VIRGEDX1; + +#endif /* S3VIRGE_H_ */ diff --git a/src/devices/bus/isa/sb16.c b/src/devices/bus/isa/sb16.c new file mode 100644 index 00000000000..b39195c9557 --- /dev/null +++ b/src/devices/bus/isa/sb16.c @@ -0,0 +1,850 @@ +// license:BSD-3-Clause +// copyright-holders:Carl + +// Soundblaster 16 - LLE +// +// The mcu does host communication and control of the dma-dac unit +// TODO: UART is connected to MIDI port, mixer, adc + +#include "sb16.h" + +const device_type ISA16_SB16 = &device_creator; + +READ8_MEMBER( sb16_lle_device::dsp_data_r ) +{ + if(!space.debugger_access()) + m_data_in = false; + + return m_in_byte; +} + +WRITE8_MEMBER( sb16_lle_device::dsp_data_w ) +{ + m_data_out = true; + m_out_byte = data; +} + +READ8_MEMBER( sb16_lle_device::dac_ctrl_r ) +{ + return 0; +} + +WRITE8_MEMBER( sb16_lle_device::dac_ctrl_w ) +{ + /* port 0x05 + * bit0 - + * bit1 - ? + * bit2 - + * bit3 - + * bit4 - + * bit5 - ? + * bit6 - clear irq line? + * bit7 - + */ + if(data & 0x40) + { + m_cpu->set_input_line(MCS51_INT0_LINE, CLEAR_LINE); + m_cpu->set_input_line(MCS51_INT1_LINE, CLEAR_LINE); + } +} + +READ8_MEMBER( sb16_lle_device::adc_data_r ) +{ + return 0; +} + +WRITE8_MEMBER( sb16_lle_device::dac_data_w ) +{ + m_dacl->write_unsigned8(data); + m_dacr->write_unsigned8(data); +} + +READ8_MEMBER( sb16_lle_device::p1_r ) +{ + UINT8 ret = 0; + ret |= m_data_out << 0; + ret |= m_data_in << 1; + return ret; +} + +WRITE8_MEMBER( sb16_lle_device::p1_w ) +{ + /* port P1 + * bit0 - output byte ready + * bit1 - input byte ready + * bit2 - irq mask? + * bit3 - + * bit4 - ? + * bit5 - DRQ? + * bit6 - MIDI? + * bit7 - ? + */ +} + +READ8_MEMBER( sb16_lle_device::p2_r ) +{ + return 0; +} + +WRITE8_MEMBER( sb16_lle_device::p2_w ) +{ + /* port P2 + * bit0 - + * bit1 - + * bit2 - + * bit3 - + * bit4 - clock running? + * bit5 - ? + * bit6 - ? + * bit7 - ? + */ +} + +void sb16_lle_device::control_timer(bool start) +{ + if(start && m_freq) + { + double rate = (46615120.0/1024/256) * m_freq; + m_timer->adjust(attotime::from_hz(rate), 0, attotime::from_hz(rate)); + } + else + m_timer->adjust(attotime::never); +} + +WRITE8_MEMBER( sb16_lle_device::rate_w ) +{ + m_freq = data; + if(!(m_ctrl8 & 2) || !(m_ctrl16 & 2)) + control_timer(true); +} + +READ8_MEMBER( sb16_lle_device::dma8_r ) +{ + return m_dac_fifo[0].b[0]; +} + +WRITE8_MEMBER( sb16_lle_device::dma8_w ) +{ + m_adc_fifo[0].b[0] = data; + m_isa->drq1_w(0); +} + +READ8_MEMBER( sb16_lle_device::dma_stat_r ) +{ + /* port 0x06 + * bit0 - 8 bit complete + * bit1 - 16 bit complete + * bit2 - + * bit3 - + * bit4 - + * bit5 - + * bit6 - + * bit7 - + */ + UINT8 ret = (m_dma16_done << 1) | m_dma8_done; + return ret; +} + +READ8_MEMBER( sb16_lle_device::ctrl8_r ) +{ + return m_ctrl8; +} + +WRITE8_MEMBER( sb16_lle_device::ctrl8_w ) +{ + /* port 0x08 + * bit0 - ? + * bit1 - stop transfer + * bit2 - load counter + * bit3 - + * bit4 - + * bit5 - + * bit6 - ? + * bit7 - toggle for 8bit irq + */ + if(data & 4) + { + m_dma8_cnt = m_dma8_len; + m_dma8_done = false; + } + if(!(data & 2) || !(m_ctrl16 & 2)) + control_timer(true); + if(data & 2) + { + m_isa->drq1_w(0); + if(m_ctrl16 & 2) + control_timer(false); + } + else + m_isa->drq1_w(1); + + if(data & 0x80) + { + m_irq8 = true; + m_isa->irq5_w(ASSERT_LINE); + } + m_ctrl8 = data; +} + +READ8_MEMBER( sb16_lle_device::ctrl16_r ) +{ + return m_ctrl16; +} + +WRITE8_MEMBER( sb16_lle_device::ctrl16_w ) +{ + /* port 0x10 + * bit0 - + * bit1 - stop transfer + * bit2 - load counter + * bit3 - + * bit4 - + * bit5 - + * bit6 - + * bit7 - toggle for 16bit irq + */ + if(data & 4) + { + m_dma16_cnt = m_dma16_len; + m_dma16_done = false; + } + if(!(data & 2) || !(m_ctrl8 & 2)) + control_timer(true); + if(data & 2) + { + m_isa->drq5_w(0); + if(m_ctrl8 & 2) + control_timer(false); + } + else + m_isa->drq5_w(1); + + if(data & 0x80) + { + m_irq16 = true; + m_isa->irq5_w(ASSERT_LINE); + } + m_ctrl16 = data; +} + +READ8_MEMBER( sb16_lle_device::dac_fifo_ctrl_r ) +{ + return m_dac_fifo_ctrl; +} + +WRITE8_MEMBER( sb16_lle_device::dac_fifo_ctrl_w ) +{ + /* port 0x0E + * bit0 - reset fifo + * bit1 - ? + * bit2 - disable fifo + * bit3 - + * bit4 - + * bit5 - + * bit6 - + * bit7 - + */ + if(((m_dac_fifo_ctrl & 1) && !(data & 1)) || (data & 4)) + { + m_dac_fifo_head = 1; + m_dac_fifo_tail = 0; + m_dac_r = false; + m_dac_h = false; + } + m_dac_fifo_ctrl = data; +} + +READ8_MEMBER( sb16_lle_device::adc_fifo_ctrl_r ) +{ + return m_adc_fifo_ctrl; +} + +WRITE8_MEMBER( sb16_lle_device::adc_fifo_ctrl_w ) +{ + /* port 0x16 + * bit0 - reset fifo + * bit1 - ? + * bit2 - disable fifo + * bit3 - + * bit4 - + * bit5 - + * bit6 - + * bit7 - + */ + if(((m_adc_fifo_ctrl & 1) && !(data & 1)) || (data & 4)) + { + m_adc_fifo_head = 1; + m_adc_fifo_tail = 0; + m_adc_r = false; + m_adc_h = false; + } + m_adc_fifo_ctrl = data; +} + +READ8_MEMBER( sb16_lle_device::mode_r ) +{ + return m_mode; +} + +WRITE8_MEMBER( sb16_lle_device::mode_w ) +{ + /* port 0x04 + * bit0 - 1 -- dac 16, adc 8; 0 -- adc 16, dac 8 + * bit1 - int every sample + * bit2 - int dma complete + * bit3 - + * bit4 - 8 bit signed + * bit5 - 16 bit signed + * bit6 - 8 bit mono + * bit7 - 16 bit mono + */ + m_mode = data; +} + +READ8_MEMBER( sb16_lle_device::dma8_ready_r ) +{ + /* port 0x0F + * bit0 - + * bit1 - + * bit2 - + * bit3 - + * bit4 - + * bit5 - + * bit6 - byte ready in fifo + * bit7 - + */ + return ((m_dac_fifo_tail - m_dac_fifo_head) != 1) << 6; +} + +READ8_MEMBER( sb16_lle_device::adc_data_ready_r ) +{ + /* port 0x17 + * bit0 - + * bit1 - + * bit2 - + * bit3 - + * bit4 - + * bit5 - + * bit6 - + * bit7 - sample ready from adc + */ + return (m_mode & 1) ? 0x80 : 0; +} + +READ8_MEMBER( sb16_lle_device::dma8_cnt_lo_r ) +{ + return m_dma8_cnt & 0xff; +} + +READ8_MEMBER( sb16_lle_device::dma8_cnt_hi_r ) +{ + return m_dma8_cnt >> 8; +} + +WRITE8_MEMBER( sb16_lle_device::dma8_len_lo_w ) +{ + m_dma8_len = (m_dma8_len & 0xff00) | data; +} + +WRITE8_MEMBER( sb16_lle_device::dma8_len_hi_w ) +{ + m_dma8_len = (m_dma8_len & 0xff) | (data << 8); +} + +WRITE8_MEMBER( sb16_lle_device::dma16_len_lo_w ) +{ + m_dma16_len = (m_dma16_len & 0xff00) | data; +} + +WRITE8_MEMBER( sb16_lle_device::dma16_len_hi_w ) +{ + m_dma16_len = (m_dma16_len & 0xff) | (data << 8); +} + +ROM_START( sb16 ) + ROM_REGION( 0x2000, "sb16_cpu", 0 ) + ROM_LOAD("ct1741_v413[80c52].bin", 0x0000, 0x2000, CRC(5181892f) SHA1(5b42f1c34c4e9c8dbbdcffa0a36c178ca4f1aa77)) + + ROM_REGION(0x40, "xor_table", 0) + ROM_LOAD("ct1741_v413_xor.bin", 0x00, 0x40, CRC(5243d15a) SHA1(c7637c92828843f47e6e2f956af639b07aee4571)) +ROM_END + +static ADDRESS_MAP_START(sb16_io, AS_IO, 8, sb16_lle_device) + AM_RANGE(0x0000, 0x0000) AM_MIRROR(0xff00) AM_READWRITE(dsp_data_r, dsp_data_w) +// AM_RANGE(0x0001, 0x0001) // MIDI related? +// AM_RANGE(0x0002, 0x0002) + AM_RANGE(0x0004, 0x0004) AM_MIRROR(0xff00) AM_READWRITE(mode_r, mode_w) + AM_RANGE(0x0005, 0x0005) AM_MIRROR(0xff00) AM_READWRITE(dac_ctrl_r, dac_ctrl_w) + AM_RANGE(0x0006, 0x0006) AM_MIRROR(0xff00) AM_READ(dma_stat_r) +// AM_RANGE(0x0007, 0x0007) // unknown + AM_RANGE(0x0008, 0x0008) AM_MIRROR(0xff00) AM_READWRITE(ctrl8_r, ctrl8_w) + AM_RANGE(0x0009, 0x0009) AM_MIRROR(0xff00) AM_WRITE(rate_w) + AM_RANGE(0x000A, 0x000A) AM_MIRROR(0xff00) AM_READ(dma8_cnt_lo_r) + AM_RANGE(0x000B, 0x000B) AM_MIRROR(0xff00) AM_WRITE(dma8_len_lo_w) + AM_RANGE(0x000C, 0x000C) AM_MIRROR(0xff00) AM_WRITE(dma8_len_hi_w) + AM_RANGE(0x000D, 0x000D) AM_MIRROR(0xff00) AM_READ(dma8_cnt_hi_r) + AM_RANGE(0x000E, 0x000E) AM_MIRROR(0xff00) AM_READWRITE(dac_fifo_ctrl_r, dac_fifo_ctrl_w) + AM_RANGE(0x000F, 0x000F) AM_MIRROR(0xff00) AM_READ(dma8_ready_r) + AM_RANGE(0x0010, 0x0010) AM_MIRROR(0xff00) AM_READWRITE(ctrl16_r, ctrl16_w) + AM_RANGE(0x0013, 0x0013) AM_MIRROR(0xff00) AM_WRITE(dma16_len_lo_w) + AM_RANGE(0x0014, 0x0014) AM_MIRROR(0xff00) AM_WRITE(dma16_len_hi_w) + AM_RANGE(0x0016, 0x0016) AM_MIRROR(0xff00) AM_READWRITE(adc_fifo_ctrl_r, adc_fifo_ctrl_w) + AM_RANGE(0x0017, 0x0017) AM_MIRROR(0xff00) AM_READ(adc_data_ready_r) + AM_RANGE(0x0019, 0x0019) AM_MIRROR(0xff00) AM_WRITE(dac_data_w) + AM_RANGE(0x001B, 0x001B) AM_MIRROR(0xff00) AM_READ(adc_data_r) + AM_RANGE(0x001D, 0x001D) AM_MIRROR(0xff00) AM_WRITE(dma8_w) + AM_RANGE(0x001F, 0x001F) AM_MIRROR(0xff00) AM_READ(dma8_r) +// AM_RANGE(0x0080, 0x0080) // ASP comms +// AM_RANGE(0x0081, 0x0081) +// AM_RANGE(0x0082, 0x0082) + AM_RANGE(MCS51_PORT_P1, MCS51_PORT_P1) AM_READWRITE(p1_r, p1_w) + AM_RANGE(MCS51_PORT_P2, MCS51_PORT_P2) AM_READWRITE(p2_r, p2_w) +ADDRESS_MAP_END + +static MACHINE_CONFIG_FRAGMENT( sb16 ) + MCFG_CPU_ADD("sb16_cpu", I80C52, XTAL_24MHz) + MCFG_CPU_IO_MAP(sb16_io) + + MCFG_SPEAKER_STANDARD_STEREO("lspeaker", "rspeaker") + MCFG_SOUND_ADD("ymf262", YMF262, XTAL_14_31818MHz) + MCFG_SOUND_ROUTE(0, "lspeaker", 1.00) + MCFG_SOUND_ROUTE(1, "rspeaker", 1.00) + MCFG_SOUND_ROUTE(2, "lspeaker", 1.00) + MCFG_SOUND_ROUTE(3, "rspeaker", 1.00) + + MCFG_SOUND_ADD("dacl", DAC, 0) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "lspeaker", 1.00) + MCFG_SOUND_ADD("dacr", DAC, 0) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "rspeaker", 1.00) + + MCFG_PC_JOY_ADD("pc_joy") +MACHINE_CONFIG_END + +const rom_entry *sb16_lle_device::device_rom_region() const +{ + return ROM_NAME( sb16 ); +} + +machine_config_constructor sb16_lle_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( sb16 ); +} + +READ8_MEMBER( sb16_lle_device::host_data_r ) +{ + m_data_out = false; + return m_out_byte; +} + +WRITE8_MEMBER( sb16_lle_device::host_cmd_w ) +{ + m_data_in = true; + m_in_byte = data; +} + +UINT8 sb16_lle_device::dack_r(int line) +{ + UINT8 ret = m_adc_fifo[m_adc_fifo_tail].b[m_adc_h + (m_adc_r * 2)]; + + if(m_ctrl8 & 2) + return 0; + + if(!(m_mode & 1)) + { + m_adc_h = !m_adc_h; + if(m_adc_h) + return ret; + } + if((!(m_mode & 0x40) && (m_mode & 1)) || (!(m_mode & 0x80) && !(m_mode & 1))) + { + m_adc_r = !m_adc_r; + if(m_adc_r) + return ret; + } + + m_dma8_cnt--; + if(!m_dma8_cnt) + { + m_dma8_done = true; + if(m_mode & 4) + m_cpu->set_input_line(MCS51_INT1_LINE, ASSERT_LINE); + m_isa->drq1_w(0); + return ret; + } + + ++m_adc_fifo_tail %= 16; + + if(m_adc_fifo_ctrl & 4) + { + m_isa->drq1_w(0); + return ret; + } + + if(m_adc_fifo_head == ((m_adc_fifo_tail + 1) % 16)) + m_isa->drq1_w(0); + return ret; +} + +void sb16_lle_device::dack_w(int line, UINT8 data) +{ + if(m_ctrl8 & 2) + return; + + m_dac_fifo[m_dac_fifo_head].b[m_dac_h + (m_dac_r * 2)] = data; + + if(m_mode & 1) + { + m_dac_h = !m_dac_h; + if(m_dac_h) + return; + } + if((!(m_mode & 0x40) && !(m_mode & 1)) || (!(m_mode & 0x80) && (m_mode & 1))) + { + m_dac_r = !m_dac_r; + if(m_dac_r) + return; + } + + m_dma8_cnt--; + if(!m_dma8_cnt) + { + m_dma8_done = true; + if(m_mode & 4) + m_cpu->set_input_line(MCS51_INT1_LINE, ASSERT_LINE); + m_isa->drq1_w(0); + return; + } + + ++m_dac_fifo_head %= 16; + + if(m_dac_fifo_ctrl & 4) + { + m_isa->drq1_w(0); + return; + } + + if(m_dac_fifo_head == m_dac_fifo_tail) + m_isa->drq1_w(0); +} + +UINT16 sb16_lle_device::dack16_r(int line) +{ + UINT16 ret = m_adc_fifo[m_adc_fifo_tail].h[m_adc_r]; + + if(m_ctrl16 & 2) + return 0; + + if(!(m_mode & 0x80)) + { + m_adc_r = !m_adc_r; + if(m_adc_r) + return ret; + } + m_dma16_cnt--; + if(!m_dma16_cnt) + { + m_dma16_done = true; + if(m_mode & 4) + m_cpu->set_input_line(MCS51_INT1_LINE, ASSERT_LINE); + m_isa->drq5_w(0); + return ret; + } + ++m_adc_fifo_tail %= 16; + + if(m_adc_fifo_ctrl & 4) + { + m_isa->drq5_w(0); + return ret; + } + + if(m_adc_fifo_head == ((m_adc_fifo_tail + 1) % 16)) + m_isa->drq5_w(0); + return ret; +} + +void sb16_lle_device::dack16_w(int line, UINT16 data) +{ + if(m_ctrl16 & 2) + return; + + m_dac_fifo[m_dac_fifo_head].h[m_dac_r] = data; + + if(!(m_mode & 0x80)) + { + m_dac_r = !m_dac_r; + if(m_dac_r) + return; + } + m_dma16_cnt--; + if(!m_dma16_cnt) + { + m_dma16_done = true; + if(m_mode & 4) + m_cpu->set_input_line(MCS51_INT1_LINE, ASSERT_LINE); + m_isa->drq5_w(0); + return; + } + ++m_dac_fifo_head %= 16; + + if(m_dac_fifo_ctrl & 4) + { + m_isa->drq5_w(0); + return; + } + + if(m_dac_fifo_head == m_dac_fifo_tail) + m_isa->drq5_w(0); +} + +WRITE8_MEMBER( sb16_lle_device::dsp_reset_w ) +{ + if(data & 1) + { + device_reset(); + m_cpu->set_input_line(INPUT_LINE_RESET, PULSE_LINE); + } +} + +READ8_MEMBER( sb16_lle_device::dsp_wbuf_status_r ) +{ + if(offset) + return 0xff; + return m_data_in << 7; +} + +READ8_MEMBER( sb16_lle_device::dsp_rbuf_status_r ) +{ + if(offset) + { + m_irq16 = false; + m_isa->irq5_w((m_irq8 || m_irq16 || m_irq_midi) ? ASSERT_LINE : CLEAR_LINE); + return 0xff; + } + m_irq8 = false; + m_isa->irq5_w((m_irq8 || m_irq16 || m_irq_midi) ? ASSERT_LINE : CLEAR_LINE); + return m_data_out << 7; +} + +WRITE8_MEMBER( sb16_lle_device::invalid_w ) +{ + logerror("sb16: invalid port write\n"); +} + +READ8_MEMBER( sb16_lle_device::invalid_r ) +{ + logerror("sb16: invalid port read\n"); + return 0xff; +} + +// just using the old dummy mpu401 for now +READ8_MEMBER( sb16_lle_device::mpu401_r ) +{ + UINT8 res; + + m_irq_midi = false; + m_isa->irq5_w((m_irq8 || m_irq16 || m_irq_midi) ? ASSERT_LINE : CLEAR_LINE); + if(offset == 0) // data + { + res = m_mpu_byte; + m_mpu_byte = 0xff; + } + else // status + { + res = ((m_mpu_byte != 0xff)?0:0x80) | 0x3f; // bit 7 queue empty (DSR), bit 6 DRR (Data Receive Ready?) + } + + return res; +} + +WRITE8_MEMBER( sb16_lle_device::mpu401_w ) +{ + if(offset == 0) // data + { + logerror("SB MPU401:%02x %02x\n",offset,data); + } + else // command + { + logerror("SB MPU401:%02x %02x\n",offset,data); + + switch(data) + { + case 0xff: // reset + m_isa->irq5_w(ASSERT_LINE); + m_irq_midi = true; + m_mpu_byte = 0xfe; + break; + } + } + +} + +sb16_lle_device::sb16_lle_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, ISA16_SB16, "SoundBlaster 16 Audio Adapter LLE", tag, owner, clock, "sb16", __FILE__), + device_isa16_card_interface(mconfig, *this), + m_dacl(*this, "dacl"), + m_dacr(*this, "dacr"), + m_joy(*this, "pc_joy"), + m_cpu(*this, "sb16_cpu") +{ +} + +void sb16_lle_device::device_start() +{ + //address_space &space = m_cpu->space(AS_PROGRAM); + UINT8 *rom = memregion("sb16_cpu")->base(); + UINT8 *xor_table = memregion("xor_table")->base(); + + for(int i = 0; i < 0x2000; i++) + rom[i] = rom[i] ^ xor_table[i & 0x3f]; + + + ymf262_device *ymf262 = subdevice("ymf262"); + set_isa_device(); + + m_isa->install_device(0x0200, 0x0207, 0, 0, read8_delegate(FUNC(pc_joy_device::joy_port_r), subdevice("pc_joy")), write8_delegate(FUNC(pc_joy_device::joy_port_w), subdevice("pc_joy"))); + m_isa->install_device(0x0226, 0x0227, 0, 0, read8_delegate(FUNC(sb16_lle_device::invalid_r), this), write8_delegate(FUNC(sb16_lle_device::dsp_reset_w), this)); + m_isa->install_device(0x022a, 0x022b, 0, 0, read8_delegate(FUNC(sb16_lle_device::host_data_r), this), write8_delegate(FUNC(sb16_lle_device::invalid_w), this) ); + m_isa->install_device(0x022c, 0x022d, 0, 0, read8_delegate(FUNC(sb16_lle_device::dsp_wbuf_status_r), this), write8_delegate(FUNC(sb16_lle_device::host_cmd_w), this) ); + m_isa->install_device(0x022e, 0x022f, 0, 0, read8_delegate(FUNC(sb16_lle_device::dsp_rbuf_status_r), this), write8_delegate(FUNC(sb16_lle_device::invalid_w), this) ); + m_isa->install_device(0x0330, 0x0331, 0, 0, read8_delegate(FUNC(sb16_lle_device::mpu401_r), this), write8_delegate(FUNC(sb16_lle_device::mpu401_w), this)); + m_isa->install_device(0x0388, 0x0389, 0, 0, read8_delegate(FUNC(ymf262_device::read), ymf262), write8_delegate(FUNC(ymf262_device::write), ymf262)); + m_isa->install_device(0x0220, 0x0223, 0, 0, read8_delegate(FUNC(ymf262_device::read), ymf262), write8_delegate(FUNC(ymf262_device::write), ymf262)); + m_isa->install_device(0x0228, 0x0229, 0, 0, read8_delegate(FUNC(ymf262_device::read), ymf262), write8_delegate(FUNC(ymf262_device::write), ymf262)); + m_isa->set_dma_channel(1, this, FALSE); + m_isa->set_dma_channel(5, this, FALSE); + m_timer = timer_alloc(); +} + + +void sb16_lle_device::device_reset() +{ + m_isa->drq1_w(0); + m_isa->drq5_w(0); + m_isa->irq5_w(0); + m_data_out = false; + m_data_in = false; + m_freq = 0; + m_mode = 0; + m_dma8_len = m_dma16_len = 0; + m_dma8_cnt = m_dma16_cnt = 0; + m_ctrl8 = m_ctrl16 = 0; + m_dac_fifo_ctrl = m_adc_fifo_ctrl = 0; + m_adc_fifo_head = m_dac_fifo_head = 1; + m_adc_fifo_tail = m_dac_fifo_tail = 0; + m_dac_r = m_adc_r = false; + m_dac_h = m_adc_h = false; + m_irq8 = m_irq16 = m_irq_midi = false; + m_dma8_done = m_dma16_done = false; +} + +void sb16_lle_device::device_timer(emu_timer &timer, device_timer_id tid, int param, void *ptr) +{ + UINT16 dacl = 0, dacr = 0, adcl = 0, adcr = 0; + if(m_mode & 2) + { + // it might be possible to run the adc though dma simultaneously but the rom doesn't appear to permit it + if(!(m_ctrl8 & 2)) + m_cpu->set_input_line(MCS51_INT0_LINE, ASSERT_LINE); + return; + } + if(m_mode & 1) + { + switch(m_mode & 0xa0) // dac 16 + { + case 0x00: // unsigned stereo + dacl = (m_dac_fifo[m_dac_fifo_tail].h[0] - 0x8000); + dacr = (m_dac_fifo[m_dac_fifo_tail].h[1] - 0x8000); + break; + case 0x20: // signed stereo + dacl = m_dac_fifo[m_dac_fifo_tail].h[0]; + dacr = m_dac_fifo[m_dac_fifo_tail].h[1]; + break; + case 0x80: // unsigned mono + dacl = (m_dac_fifo[m_dac_fifo_tail].h[0] - 0x8000); + dacr = (m_dac_fifo[m_dac_fifo_tail].h[0] - 0x8000); + break; + case 0xa0: // signed mono + dacl = m_dac_fifo[m_dac_fifo_tail].h[0]; + dacr = m_dac_fifo[m_dac_fifo_tail].h[0]; + break; + } + switch(m_mode & 0x50) // adc 8; placeholder + { + case 0x00: // unsigned stereo + adcl = 0; + adcr = 0; + break; + case 0x10: // signed stereo + adcl = 0; + adcr = 0; + break; + case 0x40: // unsigned mono + adcl = 0; + adcr = 0; + break; + case 0x50: // signed mono + adcl = 0; + adcr = 0; + break; + } + } + else + { + switch(m_mode & 0x50) // dac 8 + { + case 0x00: // unsigned stereo + dacl = (m_dac_fifo[m_dac_fifo_tail].b[0] - 0x80) << 8; + dacr = (m_dac_fifo[m_dac_fifo_tail].b[2] - 0x80) << 8; + break; + case 0x10: // signed stereo + dacl = m_dac_fifo[m_dac_fifo_tail].b[0] << 8; + dacr = m_dac_fifo[m_dac_fifo_tail].b[2] << 8; + break; + case 0x40: // unsigned mono + dacl = (m_dac_fifo[m_dac_fifo_tail].b[0] - 0x80) << 8; + dacr = (m_dac_fifo[m_dac_fifo_tail].b[0] - 0x80) << 8; + break; + case 0x50: // signed mono + dacl = m_dac_fifo[m_dac_fifo_tail].b[0] << 8; + dacr = m_dac_fifo[m_dac_fifo_tail].b[0] << 8; + break; + } + switch(m_mode & 0xa0) // adc 16; placeholder + { + case 0x00: // unsigned stereo + adcl = 0; + adcr = 0; + break; + case 0x20: // signed stereo + adcl = 0; + adcr = 0; + break; + case 0x80: // unsigned mono + adcl = 0; + adcr = 0; + break; + case 0xa0: // signed mono + adcl = 0; + adcr = 0; + break; + } + } + m_dacr->write(dacr); + m_dacl->write(dacl); + + if(!(m_ctrl8 & 2)) + m_isa->drq1_w(1); + + if(!(m_ctrl16 & 2)) + m_isa->drq5_w(1); + + if((!(m_ctrl8 & 2) && !(m_mode & 1)) || (!(m_ctrl16 & 2) && (m_mode & 1))) + ++m_dac_fifo_tail %= 16; + + if((!(m_ctrl8 & 2) && (m_mode & 1)) || (!(m_ctrl16 & 2) && !(m_mode & 1))) + { + m_adc_fifo[m_adc_fifo_head].h[0] = adcl; + m_adc_fifo[m_adc_fifo_head].h[1] = adcr; + ++m_adc_fifo_head %= 16; + } +} diff --git a/src/devices/bus/isa/sb16.h b/src/devices/bus/isa/sb16.h new file mode 100644 index 00000000000..0236f97ea3f --- /dev/null +++ b/src/devices/bus/isa/sb16.h @@ -0,0 +1,120 @@ +// license:BSD-3-Clause +// copyright-holders:Carl + +#ifndef __SB16__ +#define __SB16__ + +#include "emu.h" +#include "isa.h" +#include "sound/dac.h" +#include "bus/pc_joy/pc_joy.h" +#include "cpu/mcs51/mcs51.h" +#include "sound/262intf.h" + +//********************************************************************* +// TYPE DEFINITIONS +//********************************************************************* + +// ====================> sb16_device + +class sb16_lle_device : public device_t, + public device_isa16_card_interface +{ +public: + // construction/destruction + sb16_lle_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + + required_device m_dacl; + required_device m_dacr; + required_device m_joy; + required_device m_cpu; + + READ8_MEMBER( mpu401_r ); + WRITE8_MEMBER( mpu401_w ); + + // mcu ports + DECLARE_READ8_MEMBER( dsp_data_r ); + DECLARE_WRITE8_MEMBER( dsp_data_w ); + DECLARE_READ8_MEMBER( p1_r ); + DECLARE_WRITE8_MEMBER( p1_w ); + DECLARE_READ8_MEMBER( p2_r ); + DECLARE_WRITE8_MEMBER( p2_w ); + DECLARE_WRITE8_MEMBER( rate_w ); + DECLARE_READ8_MEMBER( dma8_r ); + DECLARE_WRITE8_MEMBER( dma8_w ); + DECLARE_READ8_MEMBER( ctrl8_r ); + DECLARE_WRITE8_MEMBER( ctrl8_w ); + DECLARE_READ8_MEMBER( ctrl16_r ); + DECLARE_WRITE8_MEMBER( ctrl16_w ); + DECLARE_READ8_MEMBER( dac_ctrl_r ); + DECLARE_WRITE8_MEMBER( dac_ctrl_w ); + DECLARE_READ8_MEMBER( dac_fifo_ctrl_r ); + DECLARE_WRITE8_MEMBER( dac_fifo_ctrl_w ); + DECLARE_READ8_MEMBER( adc_fifo_ctrl_r ); + DECLARE_WRITE8_MEMBER( adc_fifo_ctrl_w ); + DECLARE_READ8_MEMBER( dma_stat_r ); + DECLARE_WRITE8_MEMBER( dac_data_w ); + DECLARE_READ8_MEMBER( adc_data_r ); + DECLARE_READ8_MEMBER( dma8_ready_r ); + DECLARE_READ8_MEMBER( adc_data_ready_r ); + DECLARE_READ8_MEMBER( dma8_cnt_lo_r ); + DECLARE_READ8_MEMBER( dma8_cnt_hi_r ); + DECLARE_WRITE8_MEMBER( dma8_len_lo_w ); + DECLARE_WRITE8_MEMBER( dma8_len_hi_w ); + DECLARE_WRITE8_MEMBER( dma16_len_lo_w ); + DECLARE_WRITE8_MEMBER( dma16_len_hi_w ); + DECLARE_READ8_MEMBER( mode_r ); + DECLARE_WRITE8_MEMBER( mode_w ); + + // host ports + DECLARE_READ8_MEMBER( host_data_r ); + DECLARE_WRITE8_MEMBER( host_cmd_w ); + DECLARE_WRITE8_MEMBER( dsp_reset_w ); + DECLARE_READ8_MEMBER( dsp_wbuf_status_r ); + DECLARE_READ8_MEMBER( dsp_rbuf_status_r ); + DECLARE_READ8_MEMBER( invalid_r ); + DECLARE_WRITE8_MEMBER( invalid_w ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + UINT8 dack_r(int line); + void dack_w(int line, UINT8 data); + UINT16 dack16_r(int line); + void dack16_w(int line, UINT16 data); +private: + void control_timer(bool start); + + // internal state + bool m_data_in; + UINT8 m_in_byte; + bool m_data_out; + UINT8 m_out_byte; + + UINT8 m_freq, m_mode, m_dac_fifo_ctrl, m_adc_fifo_ctrl, m_ctrl8, m_ctrl16, m_mpu_byte; + UINT16 m_dma8_len, m_dma16_len, m_dma8_cnt, m_dma16_cnt; + typedef union { + UINT32 w; + UINT16 h[2]; + UINT8 b[4]; + } samples; + samples m_adc_fifo[16], m_dac_fifo[16]; + int m_adc_fifo_head, m_adc_fifo_tail, m_dac_fifo_head, m_dac_fifo_tail; + bool m_adc_r, m_dac_r, m_adc_h, m_dac_h, m_irq8, m_irq16, m_irq_midi; + bool m_dma8_done, m_dma16_done; + + emu_timer *m_timer; +}; + +// device type definition + +extern const device_type ISA16_SB16; + +#endif diff --git a/src/devices/bus/isa/sblaster.c b/src/devices/bus/isa/sblaster.c new file mode 100644 index 00000000000..9b02d91b5c4 --- /dev/null +++ b/src/devices/bus/isa/sblaster.c @@ -0,0 +1,1682 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont, Miodrag Milanovic +/*************************************************************************** + + ISA 8/16 bit Creative Labs Sound Blaster Sound Card + + TODO: + - implement DAC + - DSP type is a MCS-51 family, it has an internal ROM that needs decapping; + - implement jumpers DIP-SWs; + +***************************************************************************/ + +#include "sblaster.h" +#include "sound/speaker.h" +#include "sound/262intf.h" +#include "sound/dac.h" +#include "machine/pic8259.h" + +/* + adlib (YM3812/OPL2 chip), part of many many soundcards (soundblaster) + soundblaster: YM3812 also accessible at 0x228/9 (address jumperable) + soundblaster pro version 1: 2 YM3812 chips + at 0x388 both accessed, + at 0x220/1 left?, 0x222/3 right? (jumperable) + soundblaster pro version 2: 1 OPL3 chip + + pro audio spectrum +: 2 OPL2 + pro audio spectrum 16: 1 OPL3 + + 2 x saa1099 chips + inherited from game blaster + also on sound blaster 1.0 + option on sound blaster 1.5 + + jumperable? normally 0x220 +*/ +#define ym3812_StdClock XTAL_3_579545MHz +#define ymf262_StdClock XTAL_14_31818MHz + +static const int m_cmd_fifo_length[256] = +{ +/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ + -1, -1, -1, -1, 1, 3, -1, -1, -1, -1, -1, -1, -1, -1, 2, 1, /* 0x */ + 2, -1, -1, -1, 3, -1, 3, 3, -1, -1, -1, -1, 1, -1, -1, 1, /* 1x */ + -1, -1, -1, -1, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 2x */ + 1, 1, -1, -1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, /* 3x */ + 2, 3, 3, -1, -1, -1, -1, -1, 3, -1, -1, -1, -1, -1, -1, -1, /* 4x */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 5x */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 6x */ + -1, -1, -1, -1, 3, 3, 3, 3, -1, -1, -1, -1, -1, 1, -1, 1, /* 7x */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 8x */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 9x */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* Ax */ + 4, -1, -1, -1, -1, -1, 4, -1, 4, -1, -1, -1, -1, -1, 4, -1, /* Bx */ + 4, -1, -1, -1, -1, -1, 4, -1, 4, -1, -1, -1, -1, -1, 4, -1, /* Cx */ + 1, 1, -1, 1, -1, 1, 1, -1, 1, 1, 1, -1, -1, -1, -1, -1, /* Dx */ + 2, 1, 2, 1, 2, -1, -1, -1, 1, -1, -1, -1, -1, -1, -1, -1, /* Ex */ + -1, -1, 1, -1, -1, -1, -1, -1, 1, -1, -1, -1, 1, -1, -1, -1 /* Fx */ +}; + +static const int protection_magic[4] = { 0x96, 0xa5, 0x69, 0x5a }; + +static MACHINE_CONFIG_FRAGMENT( sblaster1_0_config ) + MCFG_SPEAKER_STANDARD_STEREO("lspeaker", "rspeaker") + MCFG_SOUND_ADD("ym3812", YM3812, ym3812_StdClock) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "lspeaker", 3.00) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "rspeaker", 3.00) + MCFG_SAA1099_ADD("saa1099.1", 7159000) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "lspeaker", 0.50) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "rspeaker", 0.50) + MCFG_SAA1099_ADD("saa1099.2", 7159000) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "lspeaker", 0.50) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "rspeaker", 0.50) + + MCFG_SOUND_ADD("sbdacl", DAC, 0) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "lspeaker", 1.00) + MCFG_SOUND_ADD("sbdacr", DAC, 0) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "rspeaker", 1.00) + + MCFG_PC_JOY_ADD("pc_joy") + MCFG_MIDI_PORT_ADD("mdin", midiin_slot, "midiin") + MCFG_MIDI_RX_HANDLER(DEVWRITELINE(DEVICE_SELF, sb_device, midi_rx_w)) + + MCFG_MIDI_PORT_ADD("mdout", midiout_slot, "midiout") +MACHINE_CONFIG_END + +static MACHINE_CONFIG_FRAGMENT( sblaster1_5_config ) + MCFG_SPEAKER_STANDARD_STEREO("lspeaker", "rspeaker") + MCFG_SOUND_ADD("ym3812", YM3812, ym3812_StdClock) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "lspeaker", 1.00) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "rspeaker", 1.00) + /* no CM/S support (empty sockets) */ + + MCFG_SOUND_ADD("sbdacl", DAC, 0) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "lspeaker", 1.00) + MCFG_SOUND_ADD("sbdacr", DAC, 0) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "rspeaker", 1.00) + + MCFG_PC_JOY_ADD("pc_joy") + MCFG_MIDI_PORT_ADD("mdin", midiin_slot, "midiin") + MCFG_MIDI_RX_HANDLER(DEVWRITELINE(DEVICE_SELF, sb_device, midi_rx_w)) + + MCFG_MIDI_PORT_ADD("mdout", midiout_slot, "midiout") +MACHINE_CONFIG_END + +static MACHINE_CONFIG_FRAGMENT( sblaster_16_config ) + MCFG_SPEAKER_STANDARD_STEREO("lspeaker", "rspeaker") + MCFG_SOUND_ADD("ymf262", YMF262, ymf262_StdClock) + MCFG_SOUND_ROUTE(0, "lspeaker", 1.00) + MCFG_SOUND_ROUTE(1, "rspeaker", 1.00) + MCFG_SOUND_ROUTE(2, "lspeaker", 1.00) + MCFG_SOUND_ROUTE(3, "rspeaker", 1.00) + MCFG_SOUND_ADD("sbdacl", DAC, 0) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "lspeaker", 1.00) + MCFG_SOUND_ADD("sbdacr", DAC, 0) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "rspeaker", 1.00) + + MCFG_PC_JOY_ADD("pc_joy") + MCFG_MIDI_PORT_ADD("mdin", midiin_slot, "midiin") + MCFG_MIDI_RX_HANDLER(DEVWRITELINE(DEVICE_SELF, sb_device, midi_rx_w)) + + MCFG_MIDI_PORT_ADD("mdout", midiout_slot, "midiout") +MACHINE_CONFIG_END + +READ8_MEMBER( sb8_device::ym3812_16_r ) +{ + UINT8 retVal = 0xff; + switch(offset) + { + case 0 : retVal = m_ym3812->status_port_r( space, offset ); break; + } + return retVal; +} + +WRITE8_MEMBER( sb8_device::ym3812_16_w ) +{ + switch(offset) + { + case 0 : m_ym3812->control_port_w( space, offset, data ); break; + case 1 : m_ym3812->write_port_w( space, offset, data ); break; + } +} + +READ8_MEMBER( isa8_sblaster1_0_device::saa1099_16_r ) +{ + return 0xff; +} + +WRITE8_MEMBER( isa8_sblaster1_0_device::saa1099_1_16_w ) +{ + switch(offset) + { + case 0 : m_saa1099_1->data_w( space, offset, data ); break; + case 1 : m_saa1099_1->control_w( space, offset, data ); break; + } +} + +WRITE8_MEMBER( isa8_sblaster1_0_device::saa1099_2_16_w ) +{ + switch(offset) + { + case 0 : m_saa1099_2->data_w( space, offset, data ); break; + case 1 : m_saa1099_2->control_w( space, offset, data ); break; + } +} + +void sb_device::queue(UINT8 data) +{ + if (m_dsp.fifo_ptr < 15) + { + m_dsp.fifo[m_dsp.fifo_ptr] = data; + + m_dsp.fifo_ptr++; + } + else + { + // FIFO gets to la-la-land + //logerror("FIFO?\n"); + } +} + +void sb_device::queue_r(UINT8 data) +{ + m_dsp.rbuf_status |= 0x80; + + if (m_dsp.fifo_r_ptr < 52) + { + m_dsp.fifo_r[m_dsp.fifo_r_ptr] = data; + + m_dsp.fifo_r_ptr++; + } + else + { + // FIFO gets to la-la-land + //logerror("FIFO?\n"); + } +} + +UINT8 sb_device::dequeue_r() +{ + UINT8 data = m_dsp.fifo_r[0]; + + if (m_dsp.fifo_r_ptr > 0) + { + for (int i = 0; i < 51; i++) + m_dsp.fifo_r[i] = m_dsp.fifo_r[i + 1]; + + m_dsp.fifo_r[51] = 0; + + m_dsp.fifo_r_ptr--; + } + + if(m_dsp.fifo_r_ptr == 0) + m_dsp.rbuf_status &= ~0x80; + + return data; +} + + +READ8_MEMBER( sb_device::dsp_reset_r ) +{ +// printf("read DSP reset @ %x\n", offset); + if(offset) + return 0xff; + logerror("Soundblaster DSP Reset port undocumented read\n"); + return 0xff; +} + +WRITE8_MEMBER( sb_device::dsp_reset_w ) +{ +// printf("%02x to DSP reset @ %x\n", data, offset); + if(offset) + return; + + // a reset while in UART MIDI mode simply restores the previous + // operating state (page 5-3 of the Creative manual). + if (!m_uart_midi) + { + if(data == 0 && m_dsp.reset_latch == 1) + { + // reset routine + m_dsp.fifo_ptr = 0; + m_dsp.fifo_r_ptr = 0; + for(int i=0;i < 15; i++) + { + m_dsp.fifo[i] = 0; + m_dsp.fifo_r[i] = 0; + } + queue_r(0xaa); // reset OK ID + } + + m_dsp.reset_latch = data; + drq_w(0); + m_dsp.dma_autoinit = 0; + irq_w(0, IRQ_ALL); + m_timer->adjust(attotime::never, 0); + m_dsp.d_rptr = 0; + m_dsp.d_wptr = 0; + m_dsp.dma_throttled = false; + m_dsp.dma_timer_started = false; + } + + m_onebyte_midi = false; + m_uart_midi = false; + m_uart_irq = false; + m_mpu_midi = false; + m_tx_busy = false; + m_xmit_read = m_xmit_write = 0; + m_recv_read = m_recv_write = 0; + m_rx_waiting = m_tx_waiting = 0; + + //printf("%02x\n",data); +} + +READ8_MEMBER( sb_device::dsp_data_r ) +{ +// printf("read DSP data @ %x\n", offset); + if(offset) + return 0xff; + + if (m_uart_midi) + { + UINT8 rv = m_recvring[m_recv_read++]; + if (m_recv_read >= MIDI_RING_SIZE) + { + m_recv_read = 0; + } + + if (m_rx_waiting) + { + m_rx_waiting--; + } + + return rv; + } + + return dequeue_r(); +} + +WRITE8_MEMBER( sb_device::dsp_data_w ) +{ +// printf("%02x to DSP data @ %x\n", data, offset); + if(offset) + return; + logerror("Soundblaster DSP data port undocumented write\n"); +} + +READ8_MEMBER(sb_device::dsp_rbuf_status_r) +{ +// printf("read Rbufstat @ %x\n", offset); + + if(offset) + { + if(m_dsp.version > 0x0400) + irq_w(0, IRQ_DMA16); + return 0xff; + } + +// printf("Clear IRQ5\n"); + irq_w(0, IRQ_DMA8); // reading this port ACKs the card's IRQ, 8-bit dma only? + + // in either SB-MIDI mode, bit 7 indicates if a character is available + // to read. + if (m_uart_midi || m_onebyte_midi) + { + if (m_rx_waiting) + { + return 0x80; + } + + return 0x00; + } + + return m_dsp.rbuf_status; +} + +READ8_MEMBER(sb_device::dsp_wbuf_status_r) +{ +// printf("read Wbufstat @ %x\n", offset); + + if(offset) + return 0xff; + + // in either SB-MIDI mode, bit 7 indicates if there's space to write. + // set = buffer full + if (m_uart_midi || m_onebyte_midi) + { + if (m_tx_waiting >= MIDI_RING_SIZE) + { + return 0x80; + } + + return 0x00; + } + + return m_dsp.wbuf_status; +} + +WRITE8_MEMBER(sb_device::dsp_rbuf_status_w) +{ +// printf("%02x to Rbufstat @ %x\n", data, offset); + if(offset) + return; + + logerror("Soundblaster DSP Read Buffer status undocumented write\n"); +} + +void sb_device::process_fifo(UINT8 cmd) +{ + if (m_cmd_fifo_length[cmd] == -1) + { + logerror("SB: unemulated or undefined fifo command %02x\n",cmd); + m_dsp.fifo_ptr = 0; + } + else if(m_dsp.fifo_ptr == m_cmd_fifo_length[cmd]) + { + /* get FIFO params */ +// printf("SB FIFO command: %02x\n", cmd); + switch(cmd) + { + case 0x10: // Direct DAC + break; + + case 0x14: // 8-bit DMA, no autoinit + m_dsp.dma_length = (m_dsp.fifo[1] + (m_dsp.fifo[2]<<8)) + 1; +// printf("Start DMA (not autoinit, size = %x)\n", m_dsp.dma_length); + m_dsp.dma_transferred = 0; + m_dsp.dma_autoinit = 0; + m_dsp.dma_timer_started = false; + m_dsp.dma_throttled = false; + drq_w(1); + m_dsp.flags = 0; + break; + + case 0x17: // 2-bit ADPCM w/new reference + m_dsp.adpcm_new_ref = true; + m_dsp.adpcm_step = 0; + case 0x16: // 2-bit ADPCM + m_dsp.adpcm_count = 0; + m_dsp.dma_length = (m_dsp.fifo[1] + (m_dsp.fifo[2]<<8)) + 1; + m_dsp.dma_transferred = 0; + m_dsp.dma_autoinit = 0; + m_dsp.dma_timer_started = false; + m_dsp.dma_throttled = false; + drq_w(1); + m_dsp.flags = ADPCM2; + break; + + case 0x1c: // 8-bit DMA with autoinit + // printf("Start DMA (autoinit, size = %x)\n", m_dsp.dma_length); + m_dsp.dma_transferred = 0; + m_dsp.dma_autoinit = 1; + m_dsp.dma_timer_started = false; + m_dsp.dma_throttled = false; + drq_w(1); + m_dsp.flags = 0; + break; + + case 0x24: // 8-bit ADC DMA + m_dsp.adc_length = (m_dsp.fifo[1] + (m_dsp.fifo[2]<<8)) + 1; + // printf("Start DMA (not autoinit, size = %x)\n", m_dsp.adc_length); + m_dsp.adc_transferred = 0; + m_dsp.dma_autoinit = 0; + drq_w(1); + logerror("SB: ADC capture unimplemented\n"); + break; + + case 0x34: + m_uart_midi = true; + m_uart_irq = false; + break; + + case 0x35: + m_uart_midi = true; + m_uart_irq = true; + break; + + case 0x36: + case 0x37: // Enter UART mode + printf("timestamp MIDI mode not supported, contact MESSDEV!\n"); + break; + + case 0x38: // single-byte MIDI send + m_onebyte_midi = true; + break; + + case 0x40: // set time constant + m_dsp.frequency = (1000000 / (256 - m_dsp.fifo[1])); + //printf("Set time constant: %02x -> %d\n", m_dsp.fifo[1], m_dsp.frequency); + break; + + case 0x48: // set DMA block size (for auto-init) + m_dsp.dma_length = (m_dsp.fifo[1] + (m_dsp.fifo[2]<<8)) + 1; + break; + + case 0x75: // 4-bit ADPCM w/new reference + m_dsp.adpcm_new_ref = true; + m_dsp.adpcm_step = 0; + case 0x74: // 4-bit ADPCM + m_dsp.adpcm_count = 0; + m_dsp.dma_length = (m_dsp.fifo[1] + (m_dsp.fifo[2]<<8)) + 1; + m_dsp.dma_transferred = 0; + m_dsp.dma_autoinit = 0; + m_dsp.dma_timer_started = false; + m_dsp.dma_throttled = false; + drq_w(1); + m_dsp.flags = ADPCM4; + break; + + case 0x77: // 2.6-bit ADPCM w/new reference + m_dsp.adpcm_new_ref = true; + m_dsp.adpcm_step = 0; + case 0x76: // 2.6-bit ADPCM + m_dsp.adpcm_count = 0; + m_dsp.dma_length = (m_dsp.fifo[1] + (m_dsp.fifo[2]<<8)) + 1; + m_dsp.dma_transferred = 0; + m_dsp.dma_autoinit = 0; + m_dsp.dma_timer_started = false; + m_dsp.dma_throttled = false; + drq_w(1); + m_dsp.flags = ADPCM3; + break; + + case 0xd0: // halt 8-bit DMA + m_timer->adjust(attotime::never, 0); + drq_w(0); // drop DRQ + m_dsp.dma_throttled = false; + m_dsp.dma_timer_started = false; + break; + + case 0xd1: // speaker on + // ... + m_dsp.speaker_on = 1; + break; + + case 0xd3: // speaker off + // ... + m_dsp.speaker_on = 0; + break; + + case 0xd8: // speaker status + queue_r(m_dsp.speaker_on ? 0xff : 0x00); + break; + + case 0xe0: // get DSP identification + queue_r(m_dsp.fifo[1] ^ 0xff); + break; + + case 0xe1: // get DSP version + queue_r(m_dsp.version >> 8); + queue_r(m_dsp.version & 0xff); + break; + + case 0xe2: // DSP protection + m_dsp.prot_value += protection_magic[m_dsp.prot_count++] ^ m_dsp.fifo[1]; + m_dsp.prot_count &= 3; + m_dsp.adc_transferred = 0; + m_dsp.adc_length = 1; + m_dsp.wbuf_status = 0x80; + m_dsp.dma_no_irq = true; + m_dack_out = (UINT8)(m_dsp.prot_value & 0xff); + drq_w(1); + break; + + case 0xe4: // write test register + m_dsp.test_reg = m_dsp.fifo[1]; + break; + + case 0xe8: // read test register + queue_r(m_dsp.test_reg); + break; + + case 0xf2: // send PIC irq + irq_w(1, IRQ_DMA8); + break; + + case 0xf8: // ??? + logerror("SB: Unknown command write 0xf8\n"); + queue_r(0); + break; + default: + if(m_dsp.version >= 0x0201) // SB 2.0 + { + switch(cmd) + { + case 0x1f: // 2-bit autoinit ADPCM w/new reference + m_dsp.adpcm_new_ref = true; + m_dsp.adpcm_step = 0; + m_dsp.adpcm_count = 0; + m_dsp.dma_length = (m_dsp.fifo[1] + (m_dsp.fifo[2]<<8)) + 1; + m_dsp.dma_transferred = 0; + m_dsp.dma_autoinit = 1; + m_dsp.dma_timer_started = false; + m_dsp.dma_throttled = false; + drq_w(1); + m_dsp.flags = ADPCM2; + break; + case 0x7d: // 4-bit autoinit ADPCM w/new reference + m_dsp.adpcm_new_ref = true; + m_dsp.adpcm_step = 0; + m_dsp.adpcm_count = 0; + m_dsp.dma_length = (m_dsp.fifo[1] + (m_dsp.fifo[2]<<8)) + 1; + m_dsp.dma_transferred = 0; + m_dsp.dma_autoinit = 1; + m_dsp.dma_timer_started = false; + m_dsp.dma_throttled = false; + drq_w(1); + m_dsp.flags = ADPCM4; + break; + case 0x7f: // 2.6-bit autoinit ADPCM w/new reference + m_dsp.adpcm_new_ref = true; + m_dsp.adpcm_step = 0; + m_dsp.adpcm_count = 0; + m_dsp.dma_length = (m_dsp.fifo[1] + (m_dsp.fifo[2]<<8)) + 1; + m_dsp.dma_transferred = 0; + m_dsp.dma_autoinit = 1; + m_dsp.dma_timer_started = false; + m_dsp.dma_throttled = false; + drq_w(1); + m_dsp.flags = ADPCM3; + break; + case 0xda: // stop 8-bit autoinit + m_dsp.dma_autoinit = 0; + break; + } + } + if(m_dsp.version >= 0x0301) // SB Pro 2 + { + switch(cmd) + { + case 0xe3: // copyright notice, check if in pro 2 + const char* copyright = "NOT COPYRIGHT (C) CREATIVE TECHNOLOGY LTD, 1992."; + int j = strlen(copyright); + for(int k = 4; k <= j; k++) + queue_r(copyright[k]); + break; + } + } + if(m_dsp.version >= 0x0400) // SB16 + { + int mode; + switch(cmd) + { + case 0x0f: // read asp reg + queue_r(0); + case 0x0e: // write asp reg + case 0x02: // get asp version + case 0x04: // set asp mode register + case 0x05: // set asp codec param + logerror("SB16: unimplemented ASP command\n"); + break; + case 0x41: // set output sample rate + m_dsp.frequency = m_dsp.fifo[2] + (m_dsp.fifo[1] << 8); + break; + case 0x42: // set input sample rate + m_dsp.adc_freq = m_dsp.fifo[2] + (m_dsp.fifo[1] << 8); + break; + case 0xd5: // pause 16-bit dma + m_timer->adjust(attotime::never, 0); + drq16_w(0); // drop DRQ + m_dsp.dma_throttled = false; + m_dsp.dma_timer_started = false; + break; + case 0xd6: // resume 16-bit dma + logerror("SB: 16-bit dma resume\n"); + break; + case 0xd9: // stop 16-bit autoinit + m_dsp.dma_autoinit = 0; + break; + case 0xb0: + case 0xb6: + case 0xc0: + case 0xc6: + mode = m_dsp.fifo[1]; + m_dsp.flags = 0; + m_dsp.dma_length = (m_dsp.fifo[2] + (m_dsp.fifo[3]<<8)) + 1; + if((cmd & 0xf0) == 0xb0) + { + m_dsp.flags |= SIXTEENBIT; + m_dsp.dma_length <<= 1; + drq16_w(1); + } + else + drq_w(1); + if(cmd & 0x04) + m_dsp.dma_autoinit = 1; + if(mode & 0x10) + m_dsp.flags |= SIGNED; + if(mode & 0x20) + { + m_dsp.flags |= STEREO; + m_dsp.dma_length <<= 1; + } + m_dsp.dma_transferred = 0; + m_dsp.dma_timer_started = false; + m_dsp.dma_throttled = false; + break; + case 0xb8: + case 0xbe: + case 0xc8: + case 0xce: + mode = m_dsp.fifo[1]; + m_dsp.adc_length = (m_dsp.fifo[2] + (m_dsp.fifo[3]<<8)) + 1; + m_dsp.adc_transferred = 0; + if(cmd & 0x04) + m_dsp.dma_autoinit = 1; + if(mode & 0x20) + m_dsp.adc_length <<= 1; + if((cmd & 0xf0) == 0xb0) + { + m_dsp.adc_length <<= 1; + drq16_w(1); + } + else + drq_w(1); + logerror("SB: ADC capture unimplemented\n"); + break; + case 0xf3: // send PIC irq + irq_w(1, IRQ_DMA16); + break; + case 0xfc: + queue_r((((m_dsp.flags & SIXTEENBIT) && m_dsp.dma_autoinit) << 4) | ((!(m_dsp.flags & SIXTEENBIT) && m_dsp.dma_autoinit) << 2)); + break; + } + } + } + m_dsp.fifo_ptr = 0; + } +} + +WRITE8_MEMBER(sb_device::dsp_cmd_w) +{ +// printf("%02x to DSP command @ %x\n", data, offset); + + if(offset) + return; + + if (m_uart_midi || m_onebyte_midi) + { + xmit_char(data); + m_onebyte_midi = false; // clear onebyte (if this is uart, that's harmless) + return; + } + + queue(data); + + process_fifo(m_dsp.fifo[0]); +} + +void sb_device::adpcm_decode(UINT8 sample, int size) +{ + const UINT8 adpcm_2_table[] = {0, 1, 1, 3, 2, 6, 4, 12, 8, 24, 16, 48}; + const UINT8 step_2_table[] = {0, 2, 0, 4, 2, 6, 4, 8, 6, 10, 8, 10}; + + const UINT8 adpcm_3_table[] = {0, 1, 2, 3, 1, 3, 5, 7, + 2, 6, 10, 14, 4, 12, 20, 28, + 8, 24, 40, 56}; + const UINT8 step_3_table[] = {0, 0, 0, 4, 0, 4, 4, 8, + 4, 8, 8, 12, 8, 12, 12, 16, + 12, 16, 16, 16}; + + const UINT8 adpcm_4_table[] = {0, 1, 2, 3, 4, 5, 6, 7, + 1, 3, 5, 7, 9, 11, 13, 15, + 2, 6, 10, 14, 18, 22, 26, 30, + 4, 12, 20, 28, 36, 44, 52, 60}; + const UINT8 step_4_table[] = {0, 0, 0, 0, 0, 8, 8, 8, + 0, 8, 8, 8, 8, 16, 16, 16, + 8, 16, 16, 16, 16, 24, 24, 24, + 16, 24, 24, 24, 24, 24, 24, 24}; + + INT16 dec_sample = m_dsp.adpcm_ref; + UINT8 index; + switch(size) + { + case 2: + index = (sample & 1) | m_dsp.adpcm_step; + dec_sample += ((sample & 2)?-1:1) * adpcm_2_table[index]; + m_dsp.adpcm_step = step_2_table[index]; + break; + case 3: + index = (sample & 3) | m_dsp.adpcm_step; + dec_sample += ((sample & 4)?-1:1) * adpcm_3_table[index]; + m_dsp.adpcm_step = step_3_table[index]; + break; + case 4: + index = (sample & 7) | m_dsp.adpcm_step; + dec_sample += ((sample & 8)?-1:1) * adpcm_4_table[index]; + m_dsp.adpcm_step = step_4_table[index]; + break; + } + + if(dec_sample > 255) + dec_sample = 255; + else if(dec_sample < 0) + dec_sample = 0; + m_dsp.adpcm_ref = dec_sample; + m_dacl->write_unsigned8(m_dsp.adpcm_ref); + m_dacr->write_unsigned8(m_dsp.adpcm_ref); +} + +READ8_MEMBER( sb16_device::mpu401_r ) +{ + UINT8 res; + + irq_w(0, IRQ_MPU); + if(offset == 0) // data + { + res = m_recvring[m_recv_read++]; + if (m_recv_read >= MIDI_RING_SIZE) + { + m_recv_read = 0; + } + + if (m_rx_waiting) + { + m_rx_waiting--; + } + } + else // status + { + res = 0; + if (m_tx_waiting >= MIDI_RING_SIZE) + { + res |= 0x40; // tx full + } + if (m_rx_waiting == 0) + { + res |= 0x80; // rx empty + } + } + + return res; +} + +WRITE8_MEMBER( sb16_device::mpu401_w ) +{ + if(offset == 0) // data + { + logerror("SB MPU401:%02x %02x\n",offset,data); + if (m_mpu_midi) + { + xmit_char(data); + } + } + else // command + { + logerror("SB MPU401:%02x %02x\n",offset,data); + + switch(data) + { + case 0x3f: // enter MPU-401 UART mode + irq_w(1, IRQ_MPU); + m_recv_read = m_recv_write = 0; + m_xmit_read = m_xmit_write = m_tx_waiting = 0; + m_recvring[m_recv_write++] = 0xfe; + m_rx_waiting = 1; + m_mpu_midi = true; + break; + + case 0xff: // reset + irq_w(1, IRQ_MPU); + m_recv_read = m_recv_write = 0; + m_recvring[m_recv_write++] = 0xfe; + m_rx_waiting = 1; + m_mpu_midi = false; + break; + } + } + +} + +void sb16_device::mixer_set() +{ + ymf262_device *ymf = subdevice("ymf262"); + float lmain = m_mixer.main_vol[0]/248.0; + float rmain = m_mixer.main_vol[1]/248.0; + m_dacl->set_output_gain(ALL_OUTPUTS, lmain*(m_mixer.dac_vol[0]/248.0f)); + m_dacr->set_output_gain(ALL_OUTPUTS, rmain*(m_mixer.dac_vol[1]/248.0f)); + ymf->set_output_gain(0, lmain*(m_mixer.fm_vol[0]/248.0f)); + ymf->set_output_gain(1, rmain*(m_mixer.fm_vol[1]/248.0f)); + ymf->set_output_gain(2, lmain*(m_mixer.fm_vol[0]/248.0f)); + ymf->set_output_gain(3, rmain*(m_mixer.fm_vol[1]/248.0f)); +} + +void sb16_device::mixer_reset() +{ + m_mixer.status = 0x80; + m_mixer.main_vol[0] = 0xc0; + m_mixer.main_vol[1] = 0xc0; + m_mixer.dac_vol[0] = 0xc0; + m_mixer.dac_vol[1] = 0xc0; + m_mixer.fm_vol[0] = 0xc0; + m_mixer.fm_vol[1] = 0xc0; + m_mixer.cd_vol[0] = 0x00; + m_mixer.cd_vol[1] = 0x00; + m_mixer.line_vol[0] = 0x00; + m_mixer.line_vol[1] = 0x00; + m_mixer.mic_vol = 0x00; + m_mixer.pc_speaker_vol = 0x00; + m_mixer.output_ctl = 0x1f; + m_mixer.input_ctl[0] = 0x15; + m_mixer.input_ctl[1] = 0x0b; + m_mixer.input_gain[0] = 0x00; + m_mixer.input_gain[1] = 0x00; + m_mixer.output_gain[0] = 0x00; + m_mixer.output_gain[1] = 0x00; + m_mixer.agc = 0x00; + m_mixer.treble[0] = 0x80; + m_mixer.treble[1] = 0x80; + m_mixer.bass[0] = 0x80; + m_mixer.bass[1] = 0x80; + mixer_set(); +} + +READ8_MEMBER( sb16_device::mixer_r ) +{ + if(offset == 0) + return m_mixer.status; + return m_mixer.data; +} + +WRITE8_MEMBER( sb16_device::mixer_w ) +{ + if(offset == 0) + { + switch(data) + { + case 0x00: + mixer_reset(); + return; + case 0x01: + m_mixer.data = m_mixer.status; + break; + case 0x04: + m_mixer.data = (m_mixer.dac_vol[0] & 0xf0) | (m_mixer.dac_vol[1] >> 4); + break; + case 0x0a: + m_mixer.data = m_mixer.mic_vol >> 5; + break; + case 0x22: + m_mixer.data = (m_mixer.main_vol[0] & 0xf0) | (m_mixer.main_vol[1] >> 4); + break; + case 0x26: + m_mixer.data = (m_mixer.fm_vol[0] & 0xf0) | (m_mixer.fm_vol[1] >> 4); + break; + case 0x28: + m_mixer.data = (m_mixer.cd_vol[0] & 0xf0) | (m_mixer.cd_vol[1] >> 4); + break; + case 0x2e: + m_mixer.data = (m_mixer.line_vol[0] & 0xf0) | (m_mixer.line_vol[1] >> 4); + break; + case 0x30: + case 0x31: + m_mixer.data = m_mixer.main_vol[data & 1]; + break; + case 0x32: + case 0x33: + m_mixer.data = m_mixer.dac_vol[data & 1]; + break; + case 0x34: + case 0x35: + m_mixer.data = m_mixer.fm_vol[data & 1]; + break; + case 0x36: + case 0x37: + m_mixer.data = m_mixer.cd_vol[data & 1]; + break; + case 0x38: + case 0x39: + m_mixer.data = m_mixer.line_vol[data & 1]; + break; + case 0x3a: + m_mixer.data = m_mixer.mic_vol; + break; + case 0x3b: + m_mixer.data = m_mixer.pc_speaker_vol; + break; + case 0x3c: + m_mixer.data = m_mixer.output_ctl; + break; + case 0x3d: + case 0x3e: + m_mixer.data = m_mixer.input_ctl[(data + 1) & 1]; + break; + case 0x3f: + case 0x40: + m_mixer.data = m_mixer.input_gain[(data + 1) & 1]; + break; + case 0x41: + case 0x42: + m_mixer.data = m_mixer.output_gain[(data + 1) & 1]; + break; + case 0x43: + m_mixer.data = m_mixer.agc; + break; + case 0x44: + case 0x45: + m_mixer.data = m_mixer.treble[data & 1]; + break; + case 0x46: + case 0x47: + m_mixer.data = m_mixer.bass[data & 1]; + break; + case 0x80: + m_mixer.data = 0x12; // irq5 + break; + case 0x81: + m_mixer.data = 0x22; // dma1&5 + break; + case 0x82: + m_mixer.data = m_dsp.irq_active | 0x20; + break; + default: + logerror("SB: Unimplemented mixer index %02x\n", data); + m_mixer.status = data | 0x80; + m_mixer.data = 0x0a; + return; + } + m_mixer.status = data; + return; + } + switch(m_mixer.status) + { + case 0x04: + m_mixer.dac_vol[0] = (data & 0xf0) | 8; + m_mixer.dac_vol[1] = (data << 4) | 8; + break; + case 0x0a: + m_mixer.mic_vol = (data << 5) | 0x18; + break; + case 0x22: + m_mixer.main_vol[0] = (data & 0xf0) | 8; + m_mixer.main_vol[1] = (data << 4) | 8; + break; + case 0x26: + m_mixer.fm_vol[0] = (data & 0xf0) | 8; + m_mixer.fm_vol[1] = (data << 4) | 8; + break; + case 0x28: + m_mixer.cd_vol[0] = (data & 0xf0) | 8; + m_mixer.cd_vol[1] = (data << 4) | 8; + break; + case 0x2e: + m_mixer.line_vol[0] = (data & 0xf0) | 8; + m_mixer.line_vol[1] = (data << 4) | 8; + break; + case 0x30: + case 0x31: + m_mixer.main_vol[m_mixer.status & 1] = data & 0xf8; + break; + case 0x32: + case 0x33: + m_mixer.dac_vol[m_mixer.status & 1] = data & 0xf8; + break; + case 0x34: + case 0x35: + m_mixer.fm_vol[m_mixer.status & 1] = data & 0xf8; + break; + case 0x36: + case 0x37: + m_mixer.cd_vol[m_mixer.status & 1] = data & 0xf8; + break; + case 0x38: + case 0x39: + m_mixer.line_vol[m_mixer.status & 1] = data & 0xf8; + break; + case 0x3a: + m_mixer.mic_vol = data & 0xf8; + break; + case 0x3b: + m_mixer.pc_speaker_vol = data & 0xc0; + break; + case 0x3c: + m_mixer.output_ctl = data & 0x1f; + break; + case 0x3d: + case 0x3e: + m_mixer.input_ctl[(m_mixer.status + 1) & 1] = data & 0x7f; + break; + case 0x3f: + case 0x40: + m_mixer.input_gain[(m_mixer.status + 1) & 1] = data & 0xc0; + break; + case 0x41: + case 0x42: + m_mixer.output_gain[(m_mixer.status + 1) & 1] = data & 0xc0; + break; + case 0x43: + m_mixer.agc = data & 1; + break; + case 0x44: + case 0x45: + m_mixer.treble[m_mixer.status & 1] = data & 0xf0; + break; + case 0x46: + case 0x47: + m_mixer.bass[m_mixer.status & 1] = data & 0xf0; + break; + case 0x80: + case 0x81: + // don't support these yet + break; + default: + return; + } + m_mixer.data = data; + mixer_set(); + return; +} + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type ISA8_SOUND_BLASTER_1_0 = &device_creator; +const device_type ISA8_SOUND_BLASTER_1_5 = &device_creator; +const device_type ISA16_SOUND_BLASTER_16 = &device_creator; + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor isa8_sblaster1_0_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( sblaster1_0_config ); +} + +machine_config_constructor isa8_sblaster1_5_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( sblaster1_5_config ); +} + +machine_config_constructor isa16_sblaster16_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( sblaster_16_config ); +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +sb_device::sb_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, UINT32 clock, const char *name, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_serial_interface(mconfig, *this), + m_dacl(*this, "sbdacl"), + m_dacr(*this, "sbdacr"), + m_joy(*this, "pc_joy"), + m_mdout(*this, "mdout") +{ +} + +sb8_device::sb8_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, UINT32 clock, const char *name, const char *shortname, const char *source) : + sb_device(mconfig, type, tag, owner, clock, name, shortname, source), + device_isa8_card_interface(mconfig, *this), + m_ym3812(*this, "ym3812") +{ +} + +sb16_device::sb16_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, UINT32 clock, const char *name, const char *shortname, const char *source) : + sb_device(mconfig, type, tag, owner, clock, name, shortname, source), + device_isa16_card_interface(mconfig, *this) +{ +} + +//------------------------------------------------- +// isa8_sblaster_device - constructor +//------------------------------------------------- + +isa8_sblaster1_0_device::isa8_sblaster1_0_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + sb8_device(mconfig, ISA8_SOUND_BLASTER_1_0, tag, owner, clock, "Sound Blaster 1.0", "isa_sblaster1_0", __FILE__), + m_saa1099_1(*this, "saa1099.1"), + m_saa1099_2(*this, "saa1099.2") +{ +} + +isa8_sblaster1_5_device::isa8_sblaster1_5_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + sb8_device(mconfig, ISA8_SOUND_BLASTER_1_5, tag, owner, clock, "Sound Blaster 1.5", "isa_sblaster1_5", __FILE__) +{ +} + +isa16_sblaster16_device::isa16_sblaster16_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + sb16_device(mconfig, ISA16_SOUND_BLASTER_16, tag, owner, clock, "Sound Blaster 16", "isa_sblaster_16", __FILE__) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void sb8_device::device_start() +{ + m_isa->install_device(0x0200, 0x0207, 0, 0, read8_delegate(FUNC(pc_joy_device::joy_port_r), subdevice("pc_joy")), write8_delegate(FUNC(pc_joy_device::joy_port_w), subdevice("pc_joy"))); + m_isa->install_device(0x0226, 0x0227, 0, 0, read8_delegate(FUNC(sb_device::dsp_reset_r), this), write8_delegate(FUNC(sb_device::dsp_reset_w), this)); + m_isa->install_device(0x022a, 0x022b, 0, 0, read8_delegate(FUNC(sb_device::dsp_data_r), this), write8_delegate(FUNC(sb_device::dsp_data_w), this) ); + m_isa->install_device(0x022c, 0x022d, 0, 0, read8_delegate(FUNC(sb_device::dsp_wbuf_status_r), this), write8_delegate(FUNC(sb_device::dsp_cmd_w), this) ); + m_isa->install_device(0x022e, 0x022f, 0, 0, read8_delegate(FUNC(sb_device::dsp_rbuf_status_r), this), write8_delegate(FUNC(sb_device::dsp_rbuf_status_w), this) ); + if(m_dsp.version >= 0x0301) + { + ymf262_device *ymf262 = subdevice("ymf262"); + + m_isa->install_device(0x0388, 0x038b, 0, 0, read8_delegate(FUNC(ymf262_device::read), ymf262), write8_delegate(FUNC(ymf262_device::write), ymf262)); + m_isa->install_device(0x0220, 0x0223, 0, 0, read8_delegate(FUNC(ymf262_device::read), ymf262), write8_delegate(FUNC(ymf262_device::write), ymf262)); + m_isa->install_device(0x0228, 0x0229, 0, 0, read8_delegate(FUNC(ymf262_device::read), ymf262), write8_delegate(FUNC(ymf262_device::write), ymf262)); + } + else + { + m_isa->install_device(0x0388, 0x0389, 0, 0, read8_delegate( FUNC(sb8_device::ym3812_16_r), this ), write8_delegate( FUNC(sb8_device::ym3812_16_w), this ) ); + m_isa->install_device(0x0228, 0x0229, 0, 0, read8_delegate( FUNC(sb8_device::ym3812_16_r), this ), write8_delegate( FUNC(sb8_device::ym3812_16_w), this ) ); + } + + m_timer = timer_alloc(0, NULL); + + save_item(NAME(m_dack_out)); + save_item(NAME(m_onebyte_midi)); + save_item(NAME(m_uart_midi)); + save_item(NAME(m_uart_irq)); + save_item(NAME(m_mpu_midi)); + save_item(NAME(m_rx_waiting)); + save_item(NAME(m_tx_waiting)); + save_item(NAME(m_recvring)); + save_item(NAME(m_xmitring)); + save_item(NAME(m_xmit_read)); + save_item(NAME(m_xmit_write)); + save_item(NAME(m_recv_read)); + save_item(NAME(m_recv_write)); + save_item(NAME(m_tx_busy)); +} + +void isa8_sblaster1_0_device::device_start() +{ + set_isa_device(); + // 1.0 always has the SAA1099s for CMS back-compatibility + m_isa->install_device(0x0220, 0x0221, 0, 0, read8_delegate( FUNC(isa8_sblaster1_0_device::saa1099_16_r), this ), write8_delegate( FUNC(isa8_sblaster1_0_device::saa1099_1_16_w), this ) ); + m_isa->install_device(0x0222, 0x0223, 0, 0, read8_delegate( FUNC(isa8_sblaster1_0_device::saa1099_16_r), this ), write8_delegate( FUNC(isa8_sblaster1_0_device::saa1099_2_16_w), this ) ); + m_isa->set_dma_channel(1, this, FALSE); + m_dsp.version = 0x0105; + sb8_device::device_start(); +} + +void isa8_sblaster1_5_device::device_start() +{ + set_isa_device(); + /* 1.5 makes CM/S support optional (empty sockets, but they work if the user populates them!) */ + m_isa->set_dma_channel(1, this, FALSE); + m_dsp.version = 0x0200; + sb8_device::device_start(); +} + +void sb16_device::device_start() +{ + ymf262_device *ymf262 = subdevice("ymf262"); + + m_isa->install_device(0x0200, 0x0207, 0, 0, read8_delegate(FUNC(pc_joy_device::joy_port_r), subdevice("pc_joy")), write8_delegate(FUNC(pc_joy_device::joy_port_w), subdevice("pc_joy"))); + m_isa->install_device(0x0224, 0x0225, 0, 0, read8_delegate(FUNC(sb16_device::mixer_r), this), write8_delegate(FUNC(sb16_device::mixer_w), this)); + m_isa->install_device(0x0226, 0x0227, 0, 0, read8_delegate(FUNC(sb_device::dsp_reset_r), this), write8_delegate(FUNC(sb_device::dsp_reset_w), this)); + m_isa->install_device(0x022a, 0x022b, 0, 0, read8_delegate(FUNC(sb_device::dsp_data_r), this), write8_delegate(FUNC(sb_device::dsp_data_w), this) ); + m_isa->install_device(0x022c, 0x022d, 0, 0, read8_delegate(FUNC(sb_device::dsp_wbuf_status_r), this), write8_delegate(FUNC(sb_device::dsp_cmd_w), this) ); + m_isa->install_device(0x022e, 0x022f, 0, 0, read8_delegate(FUNC(sb_device::dsp_rbuf_status_r), this), write8_delegate(FUNC(sb_device::dsp_rbuf_status_w), this) ); + m_isa->install_device(0x0330, 0x0331, 0, 0, read8_delegate(FUNC(sb16_device::mpu401_r), this), write8_delegate(FUNC(sb16_device::mpu401_w), this)); + m_isa->install_device(0x0388, 0x038b, 0, 0, read8_delegate(FUNC(ymf262_device::read), ymf262), write8_delegate(FUNC(ymf262_device::write), ymf262)); + m_isa->install_device(0x0220, 0x0223, 0, 0, read8_delegate(FUNC(ymf262_device::read), ymf262), write8_delegate(FUNC(ymf262_device::write), ymf262)); + m_isa->install_device(0x0228, 0x0229, 0, 0, read8_delegate(FUNC(ymf262_device::read), ymf262), write8_delegate(FUNC(ymf262_device::write), ymf262)); + + m_timer = timer_alloc(0, NULL); + + save_item(NAME(m_mixer.data)); + save_item(NAME(m_mixer.status)); + save_item(NAME(m_mixer.main_vol)); + save_item(NAME(m_mixer.dac_vol)); + save_item(NAME(m_mixer.fm_vol)); + save_item(NAME(m_mixer.cd_vol)); + save_item(NAME(m_mixer.line_vol)); + save_item(NAME(m_mixer.mic_vol)); + save_item(NAME(m_mixer.pc_speaker_vol)); + save_item(NAME(m_mixer.output_ctl)); + save_item(NAME(m_mixer.input_ctl)); + save_item(NAME(m_mixer.input_gain)); + save_item(NAME(m_mixer.output_gain)); + save_item(NAME(m_mixer.agc)); + save_item(NAME(m_mixer.treble)); + save_item(NAME(m_mixer.bass)); +} + +void isa16_sblaster16_device::device_start() +{ + set_isa_device(); + m_isa->set_dma_channel(1, this, FALSE); + m_isa->set_dma_channel(5, this, FALSE); + m_dsp.version = 0x0405; // diagnose.exe rejects anything lower than 0x0402 + sb16_device::device_start(); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void sb_device::device_reset() +{ + m_dsp.prot_value = 0xaa; + m_dsp.prot_count = 0; + m_dack_out = 0; + m_dsp.fifo_ptr = 0; + m_dsp.fifo_r_ptr = 0; + m_dsp.wbuf_status = 0; + m_dsp.rbuf_status = 0; + m_dsp.frequency = 8000; // per stereo-fx + m_dsp.irq_active = 0; + m_dsp.dma_no_irq = false; + mixer_reset(); + + m_onebyte_midi = false; + m_uart_midi = false; + m_uart_irq = false; + m_mpu_midi = false; + m_tx_busy = false; + m_xmit_read = m_xmit_write = 0; + m_recv_read = m_recv_write = 0; + m_rx_waiting = m_tx_waiting = 0; + + // MIDI is 31250 baud, 8-N-1 + set_data_frame(1, 8, PARITY_NONE, STOP_BITS_1); + set_rate(31250); +} + +UINT8 sb_device::dack_r(int line) +{ + m_dsp.adc_transferred++; + if(m_dsp.adc_transferred >= m_dsp.adc_length) + { + drq_w(0); + + if (m_dsp.dma_autoinit) + { + m_dsp.adc_transferred = 0; + drq_w(1); + } + else + m_dsp.wbuf_status = 0; + if(!m_dsp.dma_no_irq) + irq_w(1, IRQ_DMA8); + else + m_dsp.dma_no_irq = false; + } + else + drq_w(1); + return m_dack_out; +} + +UINT16 sb16_device::dack16_r(int line) +{ + m_dsp.adc_transferred += 2; + if (m_dsp.adc_transferred >= m_dsp.adc_length) + { + drq16_w(0); + + if (m_dsp.dma_autoinit) + { + m_dsp.adc_transferred = 0; + drq16_w(1); + } + irq_w(1, IRQ_DMA16); + } + else + drq16_w(1); + return m_dack_out; +} + +void sb16_device::dack16_w(int line, UINT16 data) +{ + // set the transfer timer on the 1st byte + if (!m_dsp.dma_timer_started) + { + m_timer->adjust(attotime::from_hz((double)m_dsp.frequency), 0, attotime::from_hz((double)m_dsp.frequency)); + m_dsp.d_rptr = m_dsp.d_wptr = 0; + m_dsp.dma_timer_started = true; + } + + m_dsp.data[m_dsp.d_wptr++] = data & 0xff; + m_dsp.data[m_dsp.d_wptr++] = data >> 8; + m_dsp.d_wptr %= 128; + + if (m_dsp.d_wptr == m_dsp.d_rptr) + { +// printf("throttling DRQ\n"); + drq16_w(0); // drop DRQ here + m_dsp.dma_throttled = true; + } + + m_dsp.dma_transferred += 2; + if (m_dsp.dma_transferred >= m_dsp.dma_length) + { +// printf("DMA fill completed (%d out of %d)\n", m_dsp.dma_transferred, m_dsp.dma_length); + + drq16_w(0); // drop DRQ here + + if (m_dsp.dma_autoinit) + { +// printf("autoinit reset\n"); + m_dsp.dma_transferred = 0; + if (!m_dsp.dma_throttled) // if we're not throttled, re-raise DRQ right now + { + drq16_w(1); // raise DRQ again (page 3-15 of the Creative manual indicates auto-init will keep going until you stop it) + } + } + + irq_w(1, IRQ_DMA16); // raise IRQ as per the Creative manual + } +} + +/* TODO: this mustn't be instant! */ +void sb_device::dack_w(int line, UINT8 data) +{ +// printf("dack_w: line %x data %02x\n", line, data); +// if(data != 0x80) +// printf("%02x\n",data); + + // set the transfer timer on the 1st byte + if (!m_dsp.dma_timer_started) + { + m_timer->adjust(attotime::from_hz((double)m_dsp.frequency), 0, attotime::from_hz((double)m_dsp.frequency)); + m_dsp.d_rptr = m_dsp.d_wptr = 0; + m_dsp.dma_timer_started = true; + } + + m_dsp.data[m_dsp.d_wptr++] = data; + m_dsp.d_wptr %= 128; + + if (m_dsp.d_wptr == m_dsp.d_rptr) + { +// printf("throttling DRQ\n"); + drq_w(0); // drop DRQ here + m_dsp.dma_throttled = true; + } + + m_dsp.dma_transferred++; + if (m_dsp.dma_transferred >= m_dsp.dma_length) + { +// printf("DMA fill completed (%d out of %d)\n", m_dsp.dma_transferred, m_dsp.dma_length); + + drq_w(0); // drop DRQ here + + if (m_dsp.dma_autoinit) + { +// printf("autoinit reset\n"); + m_dsp.dma_transferred = 0; + if (!m_dsp.dma_throttled) // if we're not throttled, re-raise DRQ right now + { + drq_w(1); // raise DRQ again (page 3-15 of the Creative manual indicates auto-init will keep going until you stop it) + } + } + + irq_w(1, IRQ_DMA8); // raise IRQ as per the Creative manual + } +} + +void sb_device::device_timer(emu_timer &timer, device_timer_id tid, int param, void *ptr) +{ +// printf("DMA timer expire\n"); + if (tid) + { + device_serial_interface::device_timer(timer, tid, param, ptr); + return; + } + + UINT16 lsample, rsample; + switch (m_dsp.flags) { + case 0: // 8-bit unsigned mono + m_dacl->write_unsigned8(m_dsp.data[m_dsp.d_rptr]); + m_dacr->write_unsigned8(m_dsp.data[m_dsp.d_rptr]); + m_dsp.data[m_dsp.d_rptr++] = 0x80; + break; + case SIGNED: // 8-bit signed mono + m_dacl->write_unsigned8(m_dsp.data[m_dsp.d_rptr] + 128); + m_dacr->write_unsigned8(m_dsp.data[m_dsp.d_rptr] + 128); + m_dsp.data[m_dsp.d_rptr++] = 0x00; + break; + case STEREO: // 8-bit unsigned stereo + m_dacl->write_unsigned8(m_dsp.data[m_dsp.d_rptr]); + m_dsp.data[m_dsp.d_rptr++] = 0x80; + m_dacr->write_unsigned8(m_dsp.data[m_dsp.d_rptr]); + m_dsp.data[m_dsp.d_rptr++] = 0x80; + break; + case SIGNED | STEREO: // 8-bit signed stereo + m_dacl->write_unsigned8(m_dsp.data[m_dsp.d_rptr] + 128); + m_dsp.data[m_dsp.d_rptr++] = 0x00; + m_dacr->write_unsigned8(m_dsp.data[m_dsp.d_rptr] + 128); + m_dsp.data[m_dsp.d_rptr++] = 0x00; + break; + case SIXTEENBIT: // 16-bit unsigned mono + lsample = m_dsp.data[m_dsp.d_rptr] | (m_dsp.data[m_dsp.d_rptr+1] << 8); + m_dsp.data[m_dsp.d_rptr++] = 0x00; + m_dsp.data[m_dsp.d_rptr++] = 0x80; + m_dacl->write_unsigned16(lsample); + m_dacr->write_unsigned16(lsample); + break; + case SIXTEENBIT | SIGNED: // 16-bit signed mono + lsample = m_dsp.data[m_dsp.d_rptr] | (m_dsp.data[m_dsp.d_rptr+1] << 8); + m_dsp.data[m_dsp.d_rptr++] = 0x00; + m_dsp.data[m_dsp.d_rptr++] = 0x00; + m_dacl->write_unsigned16(lsample + 32768); + m_dacr->write_unsigned16(lsample + 32768); + break; + case SIXTEENBIT | STEREO: // 16-bit unsigned stereo + lsample = m_dsp.data[m_dsp.d_rptr] | (m_dsp.data[m_dsp.d_rptr+1] << 8); + m_dsp.data[m_dsp.d_rptr++] = 0x00; + m_dsp.data[m_dsp.d_rptr++] = 0x80; + m_dsp.d_rptr %= 128; + rsample = m_dsp.data[m_dsp.d_rptr] | (m_dsp.data[m_dsp.d_rptr+1] << 8); + m_dsp.data[m_dsp.d_rptr++] = 0x00; + m_dsp.data[m_dsp.d_rptr++] = 0x80; + m_dacl->write_unsigned16(lsample); + m_dacr->write_unsigned16(rsample); + break; + case SIXTEENBIT | SIGNED | STEREO: // 16-bit signed stereo + lsample = m_dsp.data[m_dsp.d_rptr] | (m_dsp.data[m_dsp.d_rptr+1] << 8); + m_dsp.data[m_dsp.d_rptr++] = 0x00; + m_dsp.data[m_dsp.d_rptr++] = 0x00; + m_dsp.d_rptr %= 128; + rsample = m_dsp.data[m_dsp.d_rptr] | (m_dsp.data[m_dsp.d_rptr+1] << 8); + m_dsp.data[m_dsp.d_rptr++] = 0x00; + m_dsp.data[m_dsp.d_rptr++] = 0x00; + m_dacl->write_unsigned16(lsample + 32768); + m_dacr->write_unsigned16(rsample + 32768); + break; + case ADPCM2: + if(m_dsp.adpcm_new_ref) + { + m_dsp.adpcm_ref = m_dsp.data[m_dsp.d_rptr++]; + m_dsp.adpcm_new_ref = false; + m_dacl->write_unsigned8(m_dsp.adpcm_ref); + m_dacr->write_unsigned8(m_dsp.adpcm_ref); + break; + } + lsample = m_dsp.data[m_dsp.d_rptr]; + switch(m_dsp.adpcm_count++) + { + case 0: + adpcm_decode(lsample >> 6, 2); + break; + case 1: + adpcm_decode((lsample >> 4) & 3, 2); + break; + case 2: + adpcm_decode((lsample >> 2) & 3, 2); + break; + case 3: + adpcm_decode(lsample & 3, 2); + m_dsp.data[m_dsp.d_rptr++] = 0x80; + m_dsp.adpcm_count = 0; + break; + } + break; + case ADPCM3: + if(m_dsp.adpcm_new_ref) + { + m_dsp.adpcm_ref = m_dsp.data[m_dsp.d_rptr++]; + m_dsp.adpcm_new_ref = false; + m_dacl->write_unsigned8(m_dsp.adpcm_ref); + m_dacr->write_unsigned8(m_dsp.adpcm_ref); + break; + } + lsample = m_dsp.data[m_dsp.d_rptr]; + switch(m_dsp.adpcm_count++) + { + case 0: + adpcm_decode(lsample >> 5, 3); + break; + case 1: + adpcm_decode((lsample >> 2) & 7, 3); + break; + case 2: + adpcm_decode(((lsample & 2) << 1) | (lsample & 1), 3); + m_dsp.data[m_dsp.d_rptr++] = 0x80; + m_dsp.adpcm_count = 0; + break; + } + break; + case ADPCM4: + if(m_dsp.adpcm_new_ref) + { + m_dsp.adpcm_ref = m_dsp.data[m_dsp.d_rptr++]; + m_dsp.adpcm_new_ref = false; + m_dacl->write_unsigned8(m_dsp.adpcm_ref); + m_dacr->write_unsigned8(m_dsp.adpcm_ref); + break; + } + lsample = m_dsp.data[m_dsp.d_rptr]; + switch(m_dsp.adpcm_count++) + { + case 0: + adpcm_decode(lsample >> 4, 4); + break; + case 1: + adpcm_decode(lsample & 15, 4); + m_dsp.data[m_dsp.d_rptr++] = 0x80; + m_dsp.adpcm_count = 0; + break; + } + break; + default: + logerror("SB: unimplemented sample type %x\n", m_dsp.flags); + } + m_dsp.d_rptr %= 128; + + if (m_dsp.dma_throttled) + { + if (m_dsp.d_rptr == m_dsp.d_wptr) + { +// printf("unthrottling DRQ\n"); + if(m_dsp.flags & SIXTEENBIT) // 16-bit audio through 8-bit dma? + drq16_w(1); + else + drq_w(1); // raise DRQ + m_dsp.dma_throttled = false; + } + } +} + +void sb_device::rcv_complete() // Rx completed receiving byte +{ + receive_register_extract(); + UINT8 data = get_received_char(); + + // in UART MIDI mode, we set the DMA8 IRQ on receiving a character + if (m_uart_midi) + { + m_recvring[m_recv_write++] = data; + if (m_recv_write >= MIDI_RING_SIZE) + { + m_recv_write = 0; + } + + if (m_recv_write != m_recv_read) + { + m_rx_waiting++; + } + if (m_uart_irq) + { + irq_w(1, IRQ_DMA8); + } + } +} + +void sb16_device::rcv_complete() // Rx completed receiving byte +{ + receive_register_extract(); + UINT8 data = get_received_char(); + + // for UART or MPU, add character to the receive queue + if (m_uart_midi || m_mpu_midi) + { + m_recvring[m_recv_write++] = data; + if (m_recv_write >= MIDI_RING_SIZE) + { + m_recv_write = 0; + } + + if (m_recv_write != m_recv_read) + { + m_rx_waiting++; + } + + if (m_uart_irq) + { + irq_w(1, IRQ_DMA8); + } + + if (m_mpu_midi) + { + irq_w(1, IRQ_MPU); + } + } +} + +void sb_device::tra_complete() // Tx completed sending byte +{ +// printf("Tx complete\n"); + // is there more waiting to send? + if (m_tx_waiting) + { + transmit_register_setup(m_xmitring[m_xmit_read++]); + if (m_xmit_read >= MIDI_RING_SIZE) + { + m_xmit_read = 0; + } + m_tx_waiting--; + } + else + { + m_tx_busy = false; + } +} + +void sb_device::tra_callback() // Tx send bit +{ + int bit = transmit_register_get_data_bit(); + m_mdout->write_txd(bit); +} + +void sb_device::xmit_char(UINT8 data) +{ +// printf("SB: xmit %02x\n", data); + + // if tx is busy it'll pick this up automatically when it completes + if (!m_tx_busy) + { + m_tx_busy = true; + transmit_register_setup(data); + } + else + { + // tx is busy, it'll pick this up next time + m_xmitring[m_xmit_write++] = data; + if (m_xmit_write >= MIDI_RING_SIZE) + { + m_xmit_write = 0; + } + m_tx_waiting++; + } +} diff --git a/src/devices/bus/isa/sblaster.h b/src/devices/bus/isa/sblaster.h new file mode 100644 index 00000000000..fc8be653fd1 --- /dev/null +++ b/src/devices/bus/isa/sblaster.h @@ -0,0 +1,258 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont, Miodrag Milanovic +#pragma once + +#ifndef __ISA_SOUND_BLASTER_H__ +#define __ISA_SOUND_BLASTER_H__ + +#include "bus/midi/midi.h" +#include "isa.h" +#include "sound/dac.h" +#include "bus/pc_joy/pc_joy.h" +#include "sound/3812intf.h" +#include "sound/saa1099.h" + +#define SIXTEENBIT 0x01 +#define STEREO 0x02 +#define SIGNED 0x04 +#define ADPCM2 0x08 +#define ADPCM3 0x10 +#define ADPCM4 0x20 + +#define IRQ_DMA8 0x01 +#define IRQ_DMA16 0x02 +#define IRQ_MPU 0x04 +#define IRQ_ALL 0xff + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +struct sb8_dsp_state +{ + UINT8 reset_latch; + UINT8 rbuf_status; + UINT8 wbuf_status; + UINT8 fifo[16],fifo_ptr; + UINT8 fifo_r[52],fifo_r_ptr; + UINT16 version; + UINT8 test_reg; + UINT8 speaker_on; + bool dma_no_irq; + UINT32 prot_count; + INT32 prot_value; + UINT32 frequency; + UINT32 adc_freq; + UINT32 dma_length, dma_transferred; + UINT32 adc_length, adc_transferred; + UINT8 dma_autoinit; + UINT8 data[128], d_wptr, d_rptr; + bool dma_timer_started; + bool dma_throttled; + UINT8 flags; + UINT8 irq_active; + bool adpcm_new_ref; + UINT8 adpcm_ref; + UINT8 adpcm_step; + UINT8 adpcm_count; +}; + +struct sb8_mixer +{ + UINT8 status; + UINT8 main_vol; + UINT8 dac_vol; + UINT8 fm_vol; + UINT8 mic_vol; + UINT8 in_filter; + UINT8 stereo_sel; + UINT8 cd_vol; + UINT8 line_vol; +}; + +struct sb16_mixer +{ + UINT8 data; + UINT8 status; + UINT8 main_vol[2]; + UINT8 dac_vol[2]; + UINT8 fm_vol[2]; + UINT8 cd_vol[2]; + UINT8 line_vol[2]; + UINT8 mic_vol; + UINT8 pc_speaker_vol; + UINT8 output_ctl; + UINT8 input_ctl[2]; + UINT8 input_gain[2]; + UINT8 output_gain[2]; + UINT8 agc; + UINT8 treble[2]; + UINT8 bass[2]; +}; + +// ======================> sb_device (parent) + +class sb_device : + public device_t, public device_serial_interface +{ +public: + // construction/destruction + sb_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, UINT32 clock, const char *name, const char *shortname, const char *source); + + required_device m_dacl; + required_device m_dacr; + required_device m_joy; + required_device m_mdout; + + void process_fifo(UINT8 cmd); + void queue(UINT8 data); + void queue_r(UINT8 data); + UINT8 dequeue_r(); + + DECLARE_READ8_MEMBER(dsp_reset_r); + DECLARE_WRITE8_MEMBER(dsp_reset_w); + DECLARE_READ8_MEMBER(dsp_data_r); + DECLARE_WRITE8_MEMBER(dsp_data_w); + DECLARE_READ8_MEMBER(dsp_rbuf_status_r); + DECLARE_READ8_MEMBER(dsp_wbuf_status_r); + DECLARE_WRITE8_MEMBER(dsp_rbuf_status_w); + DECLARE_WRITE8_MEMBER(dsp_cmd_w); + + DECLARE_WRITE_LINE_MEMBER( midi_rx_w ) { device_serial_interface::rx_w((UINT8)state); } + +protected: + // device-level overrides + virtual void device_reset(); + UINT8 dack_r(int line); + void dack_w(int line, UINT8 data); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + virtual void drq16_w(int state) { } + virtual void drq_w(int state) { } + virtual void irq_w(int state, int source) { } + virtual void mixer_reset() {} + void adpcm_decode(UINT8 sample, int size); + + // serial overrides + virtual void rcv_complete(); // Rx completed receiving byte + virtual void tra_complete(); // Tx completed sending byte + virtual void tra_callback(); // Tx send bit + + static const int MIDI_RING_SIZE = 2048; + + struct sb8_dsp_state m_dsp; + UINT8 m_dack_out; + void xmit_char(UINT8 data); + bool m_onebyte_midi, m_uart_midi, m_uart_irq, m_mpu_midi; + int m_rx_waiting, m_tx_waiting; + UINT8 m_recvring[MIDI_RING_SIZE]; + UINT8 m_xmitring[MIDI_RING_SIZE]; + int m_xmit_read, m_xmit_write; + int m_recv_read, m_recv_write; + bool m_tx_busy; + + emu_timer *m_timer; +}; + +class sb8_device : public sb_device, + public device_isa8_card_interface +{ +public: + // construction/destruction + sb8_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, UINT32 clock, const char *name, const char *shortname, const char *source); + + DECLARE_READ8_MEMBER(ym3812_16_r); + DECLARE_WRITE8_MEMBER(ym3812_16_w); +protected: + virtual void device_start(); + virtual void drq_w(int state) { m_isa->drq1_w(state); } + virtual void irq_w(int state, int source) { m_isa->irq5_w(state); } + virtual UINT8 dack_r(int line) { return sb_device::dack_r(line); } + virtual void dack_w(int line, UINT8 data) { sb_device::dack_w(line, data); } +private: + required_device m_ym3812; +}; + +class isa8_sblaster1_0_device : public sb8_device +{ +public: + // construction/destruction + isa8_sblaster1_0_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + + DECLARE_READ8_MEMBER(saa1099_16_r); + DECLARE_WRITE8_MEMBER(saa1099_1_16_w); + DECLARE_WRITE8_MEMBER(saa1099_2_16_w); +protected: + // device-level overrides + virtual void device_start(); +private: + // internal state + required_device m_saa1099_1; + required_device m_saa1099_2; + +}; + +class isa8_sblaster1_5_device : public sb8_device +{ +public: + // construction/destruction + isa8_sblaster1_5_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; +protected: + // device-level overrides + virtual void device_start(); +private: + // internal state +}; + +class sb16_device : public sb_device, + public device_isa16_card_interface +{ +public: + // construction/destruction + sb16_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, UINT32 clock, const char *name, const char *shortname, const char *source); + DECLARE_READ8_MEMBER(mpu401_r); + DECLARE_WRITE8_MEMBER(mpu401_w); + DECLARE_READ8_MEMBER(mixer_r); + DECLARE_WRITE8_MEMBER(mixer_w); +protected: + virtual void device_start(); + virtual UINT16 dack16_r(int line); + virtual UINT8 dack_r(int line) { return sb_device::dack_r(line); } + virtual void dack_w(int line, UINT8 data) { sb_device::dack_w(line, data); } + virtual void dack16_w(int line, UINT16 data); + virtual void drq16_w(int state) { m_isa->drq5_w(state); } + virtual void drq_w(int state) { m_isa->drq1_w(state); } + virtual void irq_w(int state, int source) { (state?m_dsp.irq_active|=source:m_dsp.irq_active&=~source); m_isa->irq5_w(m_dsp.irq_active != 0); } + virtual void mixer_reset(); + void mixer_set(); + virtual void rcv_complete(); // Rx completed receiving byte +private: + struct sb16_mixer m_mixer; +}; + +class isa16_sblaster16_device : public sb16_device +{ +public: + // construction/destruction + isa16_sblaster16_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; +protected: + // device-level overrides + virtual void device_start(); +private: + // internal state +}; + +// device type definition +extern const device_type ISA8_SOUND_BLASTER_1_0; +extern const device_type ISA8_SOUND_BLASTER_1_5; +extern const device_type ISA16_SOUND_BLASTER_16; + +#endif /* __ISA_SOUND_BLASTER_H__ */ diff --git a/src/devices/bus/isa/sc499.c b/src/devices/bus/isa/sc499.c new file mode 100644 index 00000000000..ea6969afe1a --- /dev/null +++ b/src/devices/bus/isa/sc499.c @@ -0,0 +1,1333 @@ +// license:BSD-3-Clause +// copyright-holders:Hans Ostermeyer, R. Belmont +/* + * sc499.c - ARCHIVE SC-499 cartridge tape controller (for Apollo DN3x00) + * Created on: April 17, 2011 + * Author: Hans Ostermeyer + * ISA conversion by R. Belmont + * + * see also: + * - http://www.bitsavers.org/pdf/apollo/002398-04_Domain_Engineering_Handbook_Rev4_Jan87.pdf + * - http://www.bitsavers.org/pdf/apollo/008778-03_DOMAIN_Series_3000_4000_Technical_Reference_Aug87.pdf + * - http://www.bitsavers.org/pdf/archive/20271-001_scorpPrDesc_Mar84.pdf + * - http://www.bitsavers.org/pdf/archive/SidewinderProdDescr.pdf + * + */ + +#include "sc499.h" +#include "formats/ioprocs.h" + +#define VERBOSE 0 + +static int verbose = VERBOSE; + +#define LOG(x) { logerror ("%s: ", cpu_context()); logerror x; logerror ("\n"); } +#define LOG1(x) { if (verbose > 0) LOG(x)} +#define LOG2(x) { if (verbose > 1) LOG(x)} +#define LOG3(x) { if (verbose > 2) LOG(x)} + +#define SC499_CTAPE_TAG "sc499_ctape" +extern const device_type SC499_CTAPE; + +static INPUT_PORTS_START( sc499_port ) + PORT_START("IO_BASE") + PORT_DIPNAME( 0x3f8, 0x200, "SC499 I/O base (jumpers A3-A9)") + PORT_DIPSETTING( 0x008, "008h" ) + PORT_DIPSETTING( 0x010, "010h" ) + PORT_DIPSETTING( 0x018, "018h" ) + PORT_DIPSETTING( 0x020, "020h" ) + PORT_DIPSETTING( 0x028, "028h" ) + PORT_DIPSETTING( 0x030, "030h" ) + PORT_DIPSETTING( 0x038, "038h" ) + PORT_DIPSETTING( 0x040, "040h" ) + PORT_DIPSETTING( 0x048, "048h" ) + PORT_DIPSETTING( 0x050, "050h" ) + PORT_DIPSETTING( 0x058, "058h" ) + PORT_DIPSETTING( 0x060, "060h" ) + PORT_DIPSETTING( 0x068, "068h" ) + PORT_DIPSETTING( 0x070, "070h" ) + PORT_DIPSETTING( 0x078, "078h" ) + PORT_DIPSETTING( 0x080, "080h" ) + PORT_DIPSETTING( 0x088, "088h" ) + PORT_DIPSETTING( 0x090, "090h" ) + PORT_DIPSETTING( 0x098, "098h" ) + PORT_DIPSETTING( 0x0a0, "0a0h" ) + PORT_DIPSETTING( 0x0a8, "0a8h" ) + PORT_DIPSETTING( 0x0b0, "0b0h" ) + PORT_DIPSETTING( 0x0b8, "0b8h" ) + PORT_DIPSETTING( 0x0c0, "0c0h" ) + PORT_DIPSETTING( 0x0c8, "0c8h" ) + PORT_DIPSETTING( 0x0d0, "0d0h" ) + PORT_DIPSETTING( 0x0d8, "0d8h" ) + PORT_DIPSETTING( 0x0e0, "0e0h" ) + PORT_DIPSETTING( 0x0e8, "0e8h" ) + PORT_DIPSETTING( 0x0f0, "0f0h" ) + PORT_DIPSETTING( 0x0f8, "0f8h" ) + PORT_DIPSETTING( 0x100, "0100h" ) + PORT_DIPSETTING( 0x108, "0108h" ) + PORT_DIPSETTING( 0x110, "0110h" ) + PORT_DIPSETTING( 0x118, "0118h" ) + PORT_DIPSETTING( 0x120, "0120h" ) + PORT_DIPSETTING( 0x128, "0128h" ) + PORT_DIPSETTING( 0x130, "0130h" ) + PORT_DIPSETTING( 0x138, "0138h" ) + PORT_DIPSETTING( 0x140, "0140h" ) + PORT_DIPSETTING( 0x148, "0148h" ) + PORT_DIPSETTING( 0x150, "0150h" ) + PORT_DIPSETTING( 0x158, "0158h" ) + PORT_DIPSETTING( 0x160, "0160h" ) + PORT_DIPSETTING( 0x168, "0168h" ) + PORT_DIPSETTING( 0x170, "0170h" ) + PORT_DIPSETTING( 0x178, "0178h" ) + PORT_DIPSETTING( 0x180, "0180h" ) + PORT_DIPSETTING( 0x188, "0188h" ) + PORT_DIPSETTING( 0x190, "0190h" ) + PORT_DIPSETTING( 0x198, "0198h" ) + PORT_DIPSETTING( 0x1a0, "01a0h" ) + PORT_DIPSETTING( 0x1a8, "01a8h" ) + PORT_DIPSETTING( 0x1b0, "01b0h" ) + PORT_DIPSETTING( 0x1b8, "01b8h" ) + PORT_DIPSETTING( 0x1c0, "01c0h" ) + PORT_DIPSETTING( 0x1c8, "01c8h" ) + PORT_DIPSETTING( 0x1d0, "01d0h" ) + PORT_DIPSETTING( 0x1d8, "01d8h" ) + PORT_DIPSETTING( 0x1e0, "01e0h" ) + PORT_DIPSETTING( 0x1e8, "01e8h" ) + PORT_DIPSETTING( 0x1f0, "01f0h" ) + PORT_DIPSETTING( 0x1f8, "01f8h" ) + PORT_DIPSETTING( 0x200, "0200h" ) + PORT_DIPSETTING( 0x208, "0208h" ) + PORT_DIPSETTING( 0x210, "0210h" ) + PORT_DIPSETTING( 0x218, "0218h" ) + PORT_DIPSETTING( 0x220, "0220h" ) + PORT_DIPSETTING( 0x228, "0228h" ) + PORT_DIPSETTING( 0x230, "0230h" ) + PORT_DIPSETTING( 0x238, "0238h" ) + PORT_DIPSETTING( 0x240, "0240h" ) + PORT_DIPSETTING( 0x248, "0248h" ) + PORT_DIPSETTING( 0x250, "0250h" ) + PORT_DIPSETTING( 0x258, "0258h" ) + PORT_DIPSETTING( 0x260, "0260h" ) + PORT_DIPSETTING( 0x268, "0268h" ) + PORT_DIPSETTING( 0x270, "0270h" ) + PORT_DIPSETTING( 0x278, "0278h" ) + PORT_DIPSETTING( 0x280, "0280h" ) + PORT_DIPSETTING( 0x288, "0288h" ) + PORT_DIPSETTING( 0x290, "0290h" ) + PORT_DIPSETTING( 0x298, "0298h" ) + PORT_DIPSETTING( 0x2a0, "02a0h" ) + PORT_DIPSETTING( 0x2a8, "02a8h" ) + PORT_DIPSETTING( 0x2b0, "02b0h" ) + PORT_DIPSETTING( 0x2b8, "02b8h" ) + PORT_DIPSETTING( 0x2c0, "02c0h" ) + PORT_DIPSETTING( 0x2c8, "02c8h" ) + PORT_DIPSETTING( 0x2d0, "02d0h" ) + PORT_DIPSETTING( 0x2d8, "02d8h" ) + PORT_DIPSETTING( 0x2e0, "02e0h" ) + PORT_DIPSETTING( 0x2e8, "02e8h" ) + PORT_DIPSETTING( 0x2f0, "02f0h" ) + PORT_DIPSETTING( 0x2f8, "02f8h" ) + PORT_DIPSETTING( 0x300, "0300h" ) + PORT_DIPSETTING( 0x308, "0308h" ) + PORT_DIPSETTING( 0x310, "0310h" ) + PORT_DIPSETTING( 0x318, "0318h" ) + PORT_DIPSETTING( 0x320, "0320h" ) + PORT_DIPSETTING( 0x328, "0328h" ) + PORT_DIPSETTING( 0x330, "0330h" ) + PORT_DIPSETTING( 0x338, "0338h" ) + PORT_DIPSETTING( 0x340, "0340h" ) + PORT_DIPSETTING( 0x348, "0348h" ) + PORT_DIPSETTING( 0x350, "0350h" ) + PORT_DIPSETTING( 0x358, "0358h" ) + PORT_DIPSETTING( 0x360, "0360h" ) + PORT_DIPSETTING( 0x368, "0368h" ) + PORT_DIPSETTING( 0x370, "0370h" ) + PORT_DIPSETTING( 0x378, "0378h" ) + PORT_DIPSETTING( 0x380, "0380h" ) + PORT_DIPSETTING( 0x388, "0388h" ) + PORT_DIPSETTING( 0x390, "0390h" ) + PORT_DIPSETTING( 0x398, "0398h" ) + PORT_DIPSETTING( 0x3a0, "03a0h" ) + PORT_DIPSETTING( 0x3a8, "03a8h" ) + PORT_DIPSETTING( 0x3b0, "03b0h" ) + PORT_DIPSETTING( 0x3b8, "03b8h" ) + PORT_DIPSETTING( 0x3c0, "03c0h" ) + PORT_DIPSETTING( 0x3c8, "03c8h" ) + PORT_DIPSETTING( 0x3d0, "03d0h" ) + PORT_DIPSETTING( 0x3d8, "03d8h" ) + PORT_DIPSETTING( 0x3e0, "03e0h" ) + PORT_DIPSETTING( 0x3e8, "03e8h" ) + PORT_DIPSETTING( 0x3f0, "03f0h" ) + PORT_DIPSETTING( 0x3f8, "03f8h" ) + + PORT_START("IRQ_DRQ") + PORT_DIPNAME( 0x07, 0x05, "SC499 IRQ (jumpers IRQ2-IRQ7)") + PORT_DIPSETTING( 0x02, "IRQ 2" ) + PORT_DIPSETTING( 0x03, "IRQ 3" ) + PORT_DIPSETTING( 0x04, "IRQ 4" ) + PORT_DIPSETTING( 0x05, "IRQ 5" ) + PORT_DIPSETTING( 0x06, "IRQ 6" ) + PORT_DIPSETTING( 0x07, "IRQ 7" ) + + PORT_DIPNAME( 0x30, 0x10, "SC499 DMA (jumpers DRQ1-DRQ3)") + PORT_DIPSETTING( 0x10, "DRQ 1" ) + PORT_DIPSETTING( 0x20, "DRQ 2" ) + PORT_DIPSETTING( 0x30, "DRQ 3" ) + +INPUT_PORTS_END + +MACHINE_CONFIG_FRAGMENT( sc499_ctape ) + MCFG_DEVICE_ADD(SC499_CTAPE_TAG, SC499_CTAPE, 0) +MACHINE_CONFIG_END + +machine_config_constructor sc499_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( sc499_ctape ); +} + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type ISA8_SC499 = &device_creator; + +//************************************************************************** +// CONSTANTS +//************************************************************************** + +// I/O register offsets + +#define SC499_PORT_DATA 0x00 // read data (status data) +#define SC499_PORT_COMMAND 0x00 // write command +#define SC499_PORT_STATUS 0x01 // read status +#define SC499_PORT_CONTROL 0x01 // write control +#define SC499_PORT_DMAGO 0x02 // write only, Start DMA +#define SC499_PORT_RSTDMA 0x03 // write only, Reset DMA + +// Tape Status Byte 0 (LSB) + +#define SC499_ST0 0x8000 // 0=> Status byte 0 +#define SC499_ST0_NOC 0x4000 // 1=> Cartridge not in place +#define SC499_ST0_USD 0x2000 // 1=> Unselected drive +#define SC499_ST0_WP 0x1000 // 1=> Write protected cartridge +#define SC499_ST0_EOM 0x0800 // 1=> End of media (EOM) +#define SC499_ST0_UDE 0x0400 // 1=> Unrecoverable data error +#define SC499_ST0_BNL 0x0200 // 1=> Bad block not located +#define SC499_ST0_FM 0x0100 // 1=> Filemark detected +#define SC499_ST0_MASK 0x7f00 + +// Tape Status Byte 1 (MSB) + +#define SC499_ST1 0x0080 // 1=> Status byte 1 +#define SC499_ST1_ILL 0x0040 // 1=> Illegal command +#define SC499_ST1_NOD 0x0020 // 1=> No data detected +#define SC499_ST1_MGN 0x0010 // 1=> Marginal block detected +#define SC499_ST1_BOM 0x0008 // 1=> Beginning of media (BOM) +#define SC499_ST1_BPE 0x0004 // 1=> Reserved for bus parity error +#define SC499_ST1_ERM 0x0002 // 1=> Reserved for end of recorded media +#define SC499_ST1_POR 0x0001 // 1=> Power on/reset occurred +#define SC499_ST1_MASK 0x007f + +#define SC499_ST_CLEAR_ALL ~(SC499_ST0_NOC | SC499_ST0_USD | SC499_ST0_WP | SC499_ST0_EOM | SC499_ST1_BOM) +#define SC499_ST_READ_ERROR (SC499_ST0_UDE | SC499_ST0_BNL | SC499_ST1_NOD) + +// Tape Status word + +//dc.w $EFFF,$C000 // 3a No cartridge +//dc.w $FFFF,$F000 // 39 No drive +//dc.w $FFFF,$8800 // 38 End of media +//dc.w $EFFF,$8488 // 37 Write abort +//dc.w $EFFF,$8400 // 36 Read error, bad blk xfer +//dc.w $EFFF,$8600 // 35 Read error, filler blk xfer +//dc.w $EFFF,$86A0 // 34 Read error, no data +//dc.w $EFFF,$8EA0 // 33 Read error, no data and EOM +//dc.w $EFE9,$86A8 // 32 Read error, no data and BOM +//dc.w $EFFF,$8100 // 31 Filemark read +//dc.w $0FF7,$00C0 // 30 Illegal command + +// Command Register (write) [50000 | 3FF9C00 ] + +#define SC499_CMD_SELECT 0x00 // Select +#define SC499_CMD_SEL_1 0x01 // select tape 1 +#define SC499_CMD_SEL_2 0x02 // select tape 2 +#define SC499_CMD_SEL_3 0x04 // select tape 3 +#define SC499_CMD_SEL_4 0x08 // select tape 4 +#define SC499_CMD_POSITION 0x20 // Position +#define SC499_CMD_REWIND 0x21 // rewind tape +#define SC499_CMD_ERASE 0x22 // erase tape +#define SC499_CMD_RETEN 0x24 // retension tape +#define SC499_CMD_WRITE_DATA 0x40 // Write Data +#define SC499_CMD_WRITE_FILEMARK 0x60 // Write File Mark +#define SC499_CMD_READ_DATA 0x80 // Read Data +#define SC499_CMD_READ_FILE_MARK 0xa0 // Read File Mark +#define SC499_CMD_READ_STATUS 0xc0 // Read Status +#define SC499_CMD_RESERVED 0xe0 // Reserved +#define SC499_CMD_NO_COMMAND 0xff // no command + +#define SC499_CMD_TYPE_MASK 0xe0 // command type mask +#define SC499_CMD_DATA_MASK 0x1f // command data mask + +// Status Register (read only) + +#define SC499_STAT_IRQ 0x80 // active high, Interrupt request flag ('or' of rdy and exc), and done if dni is set. +#define SC499_STAT_RDY 0x40 // active low, Ready from LSI chip. +#define SC499_STAT_EXC 0x20 // active low, Exception, from LSI chip. +#define SC499_STAT_DON 0x10 // active high, DMA done (from DMA logic) +#define SC499_STAT_DIR 0x08 // active high, Direction, indicates direction of bus is from controller to DN3000. + +// Control Register (write only) [50001 | 3FF9C01 ] + +// Note: All of these bits are cleared automatically when writing to SC499_PORT_RSTDMA. +// So SC499_CTR_IEN and SC499_CTR_DNI must be reprogrammed before the write to AR_START_DMA_PORT. + +#define SC499_CTR_RST 0x80 // 1=> Reset controller microprocessor. +#define SC499_CTR_REQ 0x40 // 1=> Request to LSI chip. +#define SC499_CTR_IEN 0x20 // 1=> Enables interrupts. +#define SC499_CTR_DNI 0x10 // 1=> Enables DONE int, dni = 0 masks DONE int + +// ctape device data + +#define SC499_CTAPE_BLOCK_SIZE 512 +#define SC499_CTAPE_MAX_BLOCK_COUNT (60*1024*1024/SC499_CTAPE_BLOCK_SIZE) + +// mean time to read one block from ctape (should be 5-6 msec) +#define SC499_CTAPE_READ_BLOCK_TIME 6 + +// Timer type +#define SC499_TIMER_1 1 +#define SC499_TIMER_2 2 +#define SC499_TIMER_3 3 +#define SC499_TIMER_4 4 +#define SC499_TIMER_5 5 +#define SC499_TIMER_6 6 +#define SC499_TIMER_7 7 + + +/*************************************************************************** + IMPLEMENTATION +***************************************************************************/ + +// device type definition +const device_type SC499 = &device_creator; + +//------------------------------------------------- +// sc499_device - constructor +//------------------------------------------------- + +sc499_device::sc499_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, SC499, "Archive SC-499", tag, owner, clock, "sc499", __FILE__), + device_isa8_card_interface(mconfig, *this), + m_iobase(*this, "IO_BASE"), + m_irqdrq(*this, "IRQ_DRQ"), + m_image(*this, SC499_CTAPE_TAG) +{ +} + +ioport_constructor sc499_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( sc499_port ); +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void sc499_device::device_start() +{ + set_isa_device(); + + LOG1(("start sc499")); + + m_timer = timer_alloc(0, NULL); + m_timer1 = timer_alloc(1, NULL); + + m_installed = false; + + if (m_image->image_core_file() == NULL) + { + LOG2(("start sc499: no cartridge tape")); + } + else + { + LOG2(("start sc499: cartridge tape image is %s", m_image->filename())); + } + + m_ctape_block_buffer.resize(SC499_CTAPE_BLOCK_SIZE); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void sc499_device::device_reset() +{ + m_data = 0; + m_command = SC499_CMD_NO_COMMAND; + m_status = SC499_STAT_RDY; // | SC499_STAT_EXC; + m_control = 0; + + m_first_block_hack = 1; + m_nasty_readahead = 0; + m_read_block_pending = 0; + + m_current_command = m_command; + + m_data_error_counter = 0; + m_underrun_counter = 0; + + m_image_length = 0; + + check_tape(); + + m_data_index = 0; + m_ctape_block_index = 0; + m_tape_pos = 0; + + irq_state = CLEAR_LINE; + dma_drq_state = CLEAR_LINE; + + if (!m_installed) + { + int base = m_iobase->read(); + + m_irq = m_irqdrq->read() & 7; + m_drq = m_irqdrq->read()>>4; + + m_isa->install_device(base, base+7, 0, 0, read8_delegate(FUNC(sc499_device::read), this), write8_delegate(FUNC(sc499_device::write), this)); + m_isa->set_dma_channel(m_drq, this, true); + + m_installed = true; + } +} + +/*------------------------------------------------- + cpu_context - return a string describing the current CPU context + -------------------------------------------------*/ + +const char *sc499_device::cpu_context() +{ + static char statebuf[64]; /* string buffer containing state description */ + + osd_ticks_t t = osd_ticks(); + int s = t / osd_ticks_per_second(); + int ms = (t % osd_ticks_per_second()) / 1000; + + sprintf(statebuf, "%d.%03d%s:", s, ms, tag()); + + return statebuf; +} + +/*------------------------------------------------- + tape_status_clear - clear bits in tape status + -------------------------------------------------*/ + +void sc499_device::tape_status_clear(UINT16 value) +{ + m_tape_status &= ~value; + tape_status_set(0); +} + +/*------------------------------------------------- + tape_status_set - set bits in tape status + -------------------------------------------------*/ + +void sc499_device::tape_status_set(UINT16 value) +{ + m_tape_status |= value; + m_tape_status &= ~(SC499_ST0 | SC499_ST1); + if (m_tape_status & SC499_ST0_MASK) + { + m_tape_status |= SC499_ST0; + } + if (m_tape_status & SC499_ST1_MASK) + { + m_tape_status |= SC499_ST1; + } +} + +/*------------------------------------------------- + check_tape - check tape + -------------------------------------------------*/ + +void sc499_device::check_tape() +{ + m_tape_status = 0; + m_is_writable = m_image->exists() && m_image->is_writeable(); + + if (m_image->exists()) + { + m_has_cartridge = 1; // we have a cartridge + tape_status_set(SC499_ST1_BOM); // Beginning of media (BOM) + if (!m_is_writable) + { + tape_status_set(SC499_ST0_WP); + } + + if (m_image_length != m_image->tapelen()) + { + // tape has changed, get new size + m_image_length = m_image->tapelen(); + m_ctape_block_count = (UINT32)((m_image_length + SC499_CTAPE_BLOCK_SIZE - 1) / SC499_CTAPE_BLOCK_SIZE); + } + + LOG1(("check_tape: tape image is %s with %d blocks", m_image->filename(), m_ctape_block_count)); + } + else + { + m_has_cartridge = 0; // we have no cartridge + tape_status_set(SC499_ST0_NOC); // Cartridge not in place + m_image_length = 0; + m_ctape_block_count = 0; + + LOG1(("check_tape: no cartridge tape")); + } +} + +/*------------------------------------------------- + timer_func - handle timer interrupts + -------------------------------------------------*/ + +void sc499_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + LOG2(("timer_func param=%d status=%x", param, m_status)); + + switch (param) + { + case SC499_TIMER_1: // set ready + m_status &= ~SC499_STAT_RDY; + if (m_control & SC499_CTR_IEN) + { + set_interrupt(ASSERT_LINE); + m_status |= SC499_STAT_IRQ; + } + break; + + case SC499_TIMER_2: // set exception, clear interrupt (?) + m_status &= ~SC499_STAT_EXC; + m_status &= ~SC499_STAT_IRQ; + break; + + case SC499_TIMER_3: // start dma to read data + set_dma_drq(ASSERT_LINE); + m_status |= SC499_STAT_RDY; + break; + + case SC499_TIMER_4: // ready to read next status byte + m_status &= ~SC499_STAT_RDY; + + switch (++m_data_index) + { + case 1: m_data = m_tape_status >> 8; break; + case 2: m_data = m_tape_status & 0xff; break; + case 3: m_data = m_data_error_counter >> 8; break; + case 4: m_data = m_data_error_counter & 0xff; break; + case 5: m_data = m_underrun_counter >> 8; break; + case 6: m_data = m_underrun_counter & 0xff; break; + default: + m_data_index=0; + m_command = SC499_CMD_NO_COMMAND; + m_current_command = m_command; + m_status &= ~SC499_STAT_DIR; + tape_status_clear(SC499_ST_CLEAR_ALL); + break; + } + + if (m_control & SC499_CTR_IEN) + { + set_interrupt(ASSERT_LINE); + m_status |= SC499_STAT_IRQ; + } + break; + + case SC499_TIMER_5: // read next data block for SC499_CMD_READ_DATA + case SC499_TIMER_6: // read next data block for SC499_CMD_READ_FILE_MARK + if (m_read_block_pending && (m_status & SC499_STAT_DIR)) + { + // handle data underruns in a loaded Apollo emulation + // the real ctape will stop, go back and restart reading if appropriate + if (++m_underrun_counter >= 5000) + { + // stop tape (after 30 seconds) - probably the DMA handshake failed. + m_timer1->adjust(attotime::never, param, attotime::never); + m_status &= ~SC499_STAT_EXC; + m_status &= ~SC499_STAT_DIR; + tape_status_clear(SC499_ST_CLEAR_ALL); + tape_status_set(SC499_ST_READ_ERROR); + + LOG(("timer_func param=%d status=%x tape_pos=%d - read data underrun aborted at %d", + param, m_status, m_tape_pos, m_underrun_counter)); + } + else + { + LOG2(("timer_func param=%d status=%x tape_pos=%d - read data underrun %d", + param, m_status, m_tape_pos, m_underrun_counter)); + } + break; + } + else if ( m_tape_pos > m_ctape_block_count || !(m_status & SC499_STAT_RDY)) + { + LOG1(("timer_func param=%d status=%x tape_pos=%d - end-of-tape or not ready", + param, m_status, m_tape_pos)); + m_timer1->adjust(attotime::never, param, attotime::never); + m_status &= ~SC499_STAT_EXC; + m_status &= ~SC499_STAT_DIR; + tape_status_clear(SC499_ST_CLEAR_ALL); + tape_status_set(SC499_ST_READ_ERROR); + } + else if (m_nasty_readahead > 0 ) + { + m_nasty_readahead = 0; + } + else + { + if (m_underrun_counter > 0) + { + LOG1(("timer_func param=%d status=%x tape_pos=%d - read data underrun ended at %d", + param, m_status, m_tape_pos, m_underrun_counter)); + } + + read_block(); + m_underrun_counter = 0; + if (block_is_filemark()) + { + m_timer1->adjust(attotime::never, param, attotime::never); + } + else if (m_current_command == SC499_CMD_READ_DATA) + { + m_read_block_pending = 1; + m_status &= ~SC499_STAT_RDY; + } + } + + if (m_control & SC499_CTR_IEN) + { + if (m_current_command == SC499_CMD_READ_DATA || (m_status & SC499_STAT_EXC) == 0) + { + set_interrupt(ASSERT_LINE); + m_status |= SC499_STAT_IRQ; + } + } + + break; + + case SC499_TIMER_7: // reset + // set exception + m_status &= ~SC499_STAT_EXC; + if (m_control & SC499_CTR_IEN) + { + set_interrupt(ASSERT_LINE); + m_status |= SC499_STAT_IRQ; + } + break; + + default: + LOG(("timer_func param=%d UNEXPECTED", param)); + m_timer->reset(); + break; + } + +} + +/*------------------------------------------------- + set_interrupt - set the IRQ state + -------------------------------------------------*/ + +void sc499_device::set_interrupt(enum line_state state) +{ + if (state != irq_state) + { + LOG2(("set_interrupt(%d)",state)); + switch (m_irq) + { + case 2: m_isa->irq2_w(state); break; + case 3: m_isa->irq3_w(state); break; + case 4: m_isa->irq4_w(state); break; + case 5: m_isa->irq5_w(state); break; + case 6: m_isa->irq6_w(state); break; + case 7: m_isa->irq7_w(state); break; + default: logerror("sc499: invalid IRQ %d\n", m_irq); break; + } + irq_state = state; + } +} + +/*------------------------------------------------- + set_dma_drq - set dma request output + -------------------------------------------------*/ + +void sc499_device::set_dma_drq(enum line_state state) +{ + if (state != dma_drq_state) + { + LOG2(("set_dma_drq(%d)",state)); + + switch (m_drq) + { + case 1: m_isa->drq1_w(state); break; + case 2: m_isa->drq2_w(state); break; + case 3: m_isa->drq3_w(state); break; + default: logerror("sc499: invalid DRQ %d\n", m_drq); break; + } + + dma_drq_state = state; + } +} + +// ------------------------------------- + +void sc499_device::log_command(UINT8 data) +{ + switch (data) + { + case SC499_CMD_SELECT: + case SC499_CMD_SEL_1: + case SC499_CMD_SEL_2: + case SC499_CMD_SEL_3: + case SC499_CMD_SEL_4: + LOG1(("write_command_port: %02x Select %x", data, data & 0x1f)); + break; + case SC499_CMD_REWIND: // rewind tape + LOG1(("write_command_port: %02x Rewind Tape", data)); + break; + case SC499_CMD_ERASE: // erase tape + LOG1(("write_command_port: %02x Erase Tape", data)); + break; + case SC499_CMD_RETEN: // retention tape + LOG1(("write_command_port: %02x Retention Tape", data)); + break; + case SC499_CMD_WRITE_DATA: + LOG1(("write_command_port: %02x Write Data %d ...", data, m_tape_pos)); + break; + case SC499_CMD_WRITE_FILEMARK: + LOG1(("write_command_port: %02x Write File Mark %d", data, m_tape_pos)); + break; + case SC499_CMD_READ_DATA: + LOG1(("write_command_port: %02x Read Data %d ...", data, m_tape_pos)); + break; + case SC499_CMD_READ_FILE_MARK: + LOG1(("write_command_port: %02x Read File Mark %d", data, m_tape_pos)); + break; + case SC499_CMD_READ_STATUS: + LOG1(("write_command_port: %02x Read Status (%04x %04x %04x)", data, + m_tape_status, m_data_error_counter, m_underrun_counter)); + break; + case SC499_CMD_RESERVED: // Reserved + default: + LOG(("write_command_port: %02x Unexpected Command!", data)); + break; + } +} + +void sc499_device::do_command(UINT8 data) +{ + m_status |= SC499_STAT_RDY; + m_status &= ~SC499_STAT_DON; + m_read_block_pending = 0; + + switch (data & SC499_CMD_TYPE_MASK) + { + case SC499_CMD_SELECT: + m_timer->adjust(attotime::from_usec(100), SC499_TIMER_1); + break; + + case SC499_CMD_POSITION: + switch (data) + { + case SC499_CMD_REWIND: // rewind tape + break; + case SC499_CMD_ERASE: // erase tape + // TODO: + break; + case SC499_CMD_RETEN: // retention tape + break; + } + m_first_block_hack = 0; + m_tape_pos = 0; + tape_status_clear(SC499_ST_CLEAR_ALL); + tape_status_set(SC499_ST1_BOM); + + m_timer->adjust(attotime::from_msec(500), SC499_TIMER_4); + break; + + case SC499_CMD_WRITE_DATA: + if (!m_is_writable) + { + m_status &= ~SC499_STAT_EXC; + } + m_timer->adjust(attotime::from_usec(100), SC499_TIMER_1); + break; + + case SC499_CMD_WRITE_FILEMARK: + if (!m_is_writable) + { + m_status &= ~SC499_STAT_EXC; + } + else + { + block_set_filemark(); + write_block(); + } + m_timer->adjust( attotime::from_msec(100), SC499_TIMER_1); + break; + + case SC499_CMD_READ_DATA: + m_status |= SC499_STAT_DIR; + // start reading blocks from tape + m_nasty_readahead = 0; + m_timer1->adjust( attotime::from_msec(200), SC499_TIMER_5, attotime::from_msec(SC499_CTAPE_READ_BLOCK_TIME)); + break; + + case SC499_CMD_READ_FILE_MARK: + if (m_current_command == SC499_CMD_READ_DATA) + { + // SC499_CMD_READ_DATA pending + m_status &= ~SC499_STAT_DIR; + LOG1(("do_command: Read data -> Read File Mark at %d", m_tape_pos)); + } + else + { + // start reading blocks from tape + m_timer1->adjust( attotime::from_msec(200), SC499_TIMER_6, attotime::from_msec(SC499_CTAPE_READ_BLOCK_TIME)); + } + break; + + case SC499_CMD_READ_STATUS: + m_status |= SC499_STAT_DIR; + m_status |= SC499_STAT_EXC; + + set_interrupt(CLEAR_LINE); + set_dma_drq(CLEAR_LINE); + m_timer1->adjust( attotime::never, SC499_TIMER_6, attotime::never); + + m_data_index = 0; + m_timer->adjust( attotime::from_usec(100), SC499_TIMER_4); + break; + + default: + tape_status_clear(SC499_ST_CLEAR_ALL); + tape_status_set(SC499_ST1 | SC499_ST1_ILL); + m_status &= ~SC499_STAT_EXC; + // Note: 100 usec is too fast for DN3000 + m_timer->adjust( attotime::from_usec(200), SC499_TIMER_1); + break; + } +} + +// ------------------------------------- + +void sc499_device::do_reset() +{ + LOG1(("do_reset: Reset controller microprocessor")); + + m_data = 0; + m_command = SC499_CMD_NO_COMMAND; + m_current_command = m_command; + m_status = ~(SC499_STAT_DIR | SC499_STAT_EXC); + m_control = 0; + + m_first_block_hack = 1; + m_nasty_readahead = 0; + m_read_block_pending = 0; + + if (m_has_cartridge) + { + tape_status_set(SC499_ST1_POR | SC499_ST1_BOM); + } + + m_tape_pos = 0; + m_data_error_counter = 0; + m_underrun_counter = 0; + + set_interrupt(CLEAR_LINE); + set_dma_drq(CLEAR_LINE); + + m_timer1->adjust( attotime::never, SC499_TIMER_6, attotime::never); +} + +// ------------------------------------- + +void sc499_device::write_command_port(UINT8 data) +{ + m_command = data; + log_command(data); +} + +UINT8 sc499_device::read_data_port() +{ + static UINT8 m_last_data = 0xff; + + // omit excessive logging + if (m_last_data != m_data) + { + LOG2(("read_data_port: %02x", m_data)); + m_last_data = m_data; + } + + if (m_control & SC499_CTR_IEN) + { + set_interrupt(CLEAR_LINE); + m_status &= ~SC499_STAT_IRQ; + } + + return m_data; +} + +void sc499_device::write_control_port( UINT8 data) +{ + LOG2(("write_control_port: %02x", data)); + + if ((data ^ m_control) & SC499_CTR_RST) + { + if (data & SC499_CTR_RST) + { + // SC499_CTR_RST has changed to 1 + do_reset(); + } + else + { + m_status |= SC499_STAT_EXC; + m_timer->adjust(attotime::from_msec(200), SC499_TIMER_7); + } + } + + if ((data ^ m_control) & SC499_CTR_REQ) + { + // Request to LSI chip has changed + if (data & SC499_CTR_REQ) + { + LOG3(("write_control_port: Request to LSI chip = On")); + + if (m_command == SC499_CMD_READ_STATUS) { + m_status |= SC499_STAT_EXC; + } + + if (m_command == SC499_CMD_READ_FILE_MARK && m_current_command == SC499_CMD_READ_DATA) + { + m_current_command= SC499_CMD_READ_FILE_MARK; + m_status &= ~SC499_STAT_DIR; + } + + if (!(m_status & SC499_STAT_DIR)) + { + // write command and command data + // (SC499_STAT_RDY follows SC499_CTR_REQ) + m_status &= ~SC499_STAT_RDY; + } + else + { + m_status |= SC499_STAT_RDY; + } + } + else + { + LOG2(("write_control_port: Request to LSI chip = Off (%d)", m_data_index)); + + if (!(m_status & SC499_STAT_DIR)) + { + do_command(m_command); + m_current_command = m_command; + } + else if (m_command == SC499_CMD_READ_STATUS) + { +// if (m_data_index > 0) + { + m_timer->adjust( attotime::from_usec(20), SC499_TIMER_4); + } + } + } + } + m_control = data; +} + +UINT8 sc499_device::read_status_port() +{ + static UINT8 m_last_status = 0xff; + + // omit excessive logging + if (m_last_status != m_status) + { + LOG2(("read_status_port: %02x", m_status)); + m_last_status = m_status; + } + + // reset pending interrupts + set_interrupt(CLEAR_LINE); + m_status &= ~SC499_STAT_IRQ; + + return m_last_status; +} + +// Start DMA (DMAGO). Any write to this register will cause DMAGO to be active. + +void sc499_device::write_dma_go( UINT8 data) +{ + LOG2(("write_dma_go: %02x", data)); + + m_status &= ~SC499_STAT_DON; + + switch (data) + { + case 0: + // delay set_dma_drq(ASSERT_LINE); + // Note: 200 usec may fail for MD LD; 400 usec may fail for RBAK_SHELL; 500 usec may fail for DN3000 + m_timer->adjust( attotime::from_msec(1), SC499_TIMER_3); + +// Note: proper sequence is: +// pc=3c4ad714 - ctape: write_dma_go: 00 +// pc=3c4ad718 - ctape: write_control_port: 30 +// pc=3c40ebda: apollo_dma_1_w: writing DMA Controller 1 at offset 02 = 00 +// pc=3c40ebe8: apollo_dma_1_w: writing DMA Controller 1 at offset 02 = 22 +// pc=3c40ebf4: apollo_dma_1_w: writing DMA Controller 1 at offset 0c = 00 +// pc=3c40ec04: apollo_dma_1_w: writing DMA Controller 1 at offset 03 = ff +// pc=3c40ec12: apollo_dma_1_w: writing DMA Controller 1 at offset 03 = 01 +// pc=3c40ec1e: apollo_dma_1_w: writing DMA Controller 1 at offset 0b = 45 +// pc=3c40ec2e: apollo_dma_1_w: writing DMA Controller 1 at offset 0a = 01 +// pc=3c41a154 - ctape: timer_func param=3 status=2f +// pc=3c41a154 - ctape: set_dma_drq(1) +// pc=3c41a154 - maincpu: apollo_dma_ctape_drq: state=1 +// pc=3c41a154 - ctape: dack_read: data[0]=55 status=6f +// pc=3c41a154: dma write byte at offset 17f9c00+200 = 55 +// pc=3c41a154: dma write byte at offset 17f9c00+2ff = 6d +// pc=3c41a154: dma write byte at offset 17f9c00+300 = 65 +// pc=3c41a154 - ctape: dack_read: data[511]=60 status=6f +// pc=3c41a154: dma write byte at offset 17f9c00+3ff = 60 +// pc=3c41a154 - dma8237_1: dma out eop state 00 +// pc=3c41a154 - ctape: set_tc_state: block=21 state=0 +// pc=3c41a154 - ctape: set_dma_drq(0) +// pc=3c41a154 - maincpu: apollo_dma_ctape_drq: state=0 +// pc=3c41a154 - dma8237_1: dma out eop state 01 +// pc=3c41a154 - ctape: set_tc_state: block=21 state=1 + + break; + } +} + +// Reset DMA (RSTDMA). Any write to this register will cause RSTDMA to be active. + +void sc499_device::write_dma_reset( UINT8 data) +{ + LOG2(("write_dma_reset: %02x", data)); + + m_status &= ~SC499_STAT_DON; + m_control = 0; +} + +WRITE8_MEMBER(sc499_device::write) +{ + switch (offset) + { + case SC499_PORT_COMMAND: // write command + write_command_port(data); + break; + case SC499_PORT_CONTROL: // write control + write_control_port(data); + break; + case SC499_PORT_DMAGO: // write only, Start DMA + write_dma_go(data); + break; + case SC499_PORT_RSTDMA: // write only, Reset DMA + write_dma_reset(data); + break; + default: + LOG(("writing sc499 Register at offset %02x = %02x", offset, data)); + break; + } +} + +READ8_MEMBER(sc499_device::read) +{ + UINT8 data = 0xff; + + switch (offset) + { + case SC499_PORT_DATA: // read data (status data) + data = read_data_port(); + break; + case SC499_PORT_STATUS: // read status + data=read_status_port(); +// set_interrupt(CLEAR_LINE); + break; + default: + LOG(("reading sc499 Register at offset %02x = %02x", offset, data)); + break; + } + + return data; +} + +void sc499_device::eop_w(int state) +{ + LOG2(("set_tc_state: block=%d state=%x", m_tape_pos-1, state)); + if (state == 0) + { + m_status |= SC499_STAT_DON; // 37ec + set_dma_drq(CLEAR_LINE); + + switch (m_current_command & SC499_CMD_TYPE_MASK) + { + case SC499_CMD_READ_DATA: + m_read_block_pending = 0; + break; + + case SC499_CMD_WRITE_DATA: + m_status &= ~SC499_STAT_RDY; + if ((m_control & SC499_CTR_IEN) && (m_control & SC499_CTR_DNI)) + { + set_interrupt(ASSERT_LINE); + m_status |= SC499_STAT_IRQ; + } + break; + } + } +} + +UINT8 sc499_device::dack_r(int line) +{ + UINT8 data = 0xff; + +// set_dma_drq(CLEAR_LINE); + + if (m_ctape_block_index >= SC499_CTAPE_BLOCK_SIZE) + { + LOG3(("dack_read: read_block")); + read_block(); + m_nasty_readahead++; + + if (block_is_filemark()) + { + set_dma_drq(CLEAR_LINE); + m_status &= ~SC499_STAT_EXC; + m_status &= ~SC499_STAT_DIR; + } + } + + data = m_ctape_block_buffer[m_ctape_block_index++]; + if (m_ctape_block_index < 2 || m_ctape_block_index > 511) + { + LOG2(("dack_read: data[%d]=%x status=%x", m_ctape_block_index-1, data, m_status)); + } + +// if (m_ctape_block_index < SC499_CTAPE_BLOCK_SIZE) +// { +// set_dma_drq(ASSERT_LINE); +// } + + return data; +} + +void sc499_device::dack_w(int line, UINT8 data) +{ + LOG3(("dack_write: data=%x", data)); + + if (m_ctape_block_index < SC499_CTAPE_BLOCK_SIZE) + { + m_ctape_block_buffer[m_ctape_block_index++] = data; + } + + if (m_ctape_block_index == SC499_CTAPE_BLOCK_SIZE) + { + LOG3(("dack_write: write_block")); + write_block(); + } +} + +/*------------------------------------------------- + log_block - log block data + -------------------------------------------------*/ + +void sc499_device::log_block(const char *text) +{ + int data_length = 16; + + if (verbose > 0) { + int i; + logerror("%s: %s %d -", cpu_context(), text, m_tape_pos); + for (i = 0; i < data_length && i < SC499_CTAPE_BLOCK_SIZE; i++) { + logerror(" %02x", m_ctape_block_buffer[i]); + } + + if (i < SC499_CTAPE_BLOCK_SIZE) { + logerror(" ..."); + } + + if (m_ctape_block_index > 0 && m_ctape_block_index != SC499_CTAPE_BLOCK_SIZE) + { + logerror(" block_index = %d !!!", m_ctape_block_index); + } + + logerror("\n"); + } +} + +/*------------------------------------------------- + read_block - read block from m_tape_pos to m_ctape_block_buffer + -------------------------------------------------*/ + +void sc499_device::read_block() +{ + UINT8 *tape; + + if (m_tape_pos == 0) + { + // check if tape has been replaced or removed + check_tape(); + } + + tape = m_image->read_block(m_tape_pos); + + if (tape == NULL) + { + // either there is no tape or m_tape_pos goes beyond end-of-tape + m_status &= ~SC499_STAT_EXC; + m_status &= ~SC499_STAT_DIR; + m_status &= ~SC499_STAT_DON; + tape_status_clear(SC499_ST_CLEAR_ALL); + tape_status_set(SC499_ST_READ_ERROR); + } + else + { + memcpy(&m_ctape_block_buffer[0], tape, SC499_CTAPE_BLOCK_SIZE); + + // if (verbose > 1 || m_tape_pos % 100 == 0) + { + log_block("read_block"); + } + + m_ctape_block_index = 0; + m_tape_pos++; + + if (m_first_block_hack) + { + // FIXME: we must read first block twice (in MD for 'di c' and 'ld' or 'ex ...') + // why is this necessary??? + m_tape_pos = 0; + LOG(("read_block - duplicating block %d", m_tape_pos)); + } + m_first_block_hack = 0; + + // we are no longer at Beginning of media (BOM) + tape_status_clear(SC499_ST1_BOM); + + if (block_is_filemark()) + { + m_status &= ~SC499_STAT_EXC; + m_status &= ~SC499_STAT_DIR; + tape_status_clear(SC499_ST_CLEAR_ALL); + tape_status_set(SC499_ST0_FM); + } + else + { + tape_status_clear(SC499_ST0_FM); + } + } + // if (m_tape_pos == 69400) verbose = 2; +} + +/*------------------------------------------------- + write_block - write block from m_ctape_block_buffer to m_tape_pos + -------------------------------------------------*/ + +void sc499_device::write_block() +{ + log_block("write_block"); + + if (m_tape_pos == 0) + { + // check if tape has been replaced or removed + check_tape(); + } + + m_image->write_block(m_tape_pos, &m_ctape_block_buffer[0]); + m_ctape_block_count = m_tape_pos; + m_ctape_block_index = 0; + m_tape_pos++; + + // we are no longer at Beginning of media (BOM) + tape_status_clear(SC499_ST1_BOM); +} + +/*------------------------------------------------- + block_is_filemark - returns 1 is current block buffer data is filemark + -------------------------------------------------*/ + +int sc499_device::block_is_filemark() +{ + static const UINT8 fm_pattern[] = {0xDE, 0xAF, 0xFA, 0xED}; + + int is_filemark = memcmp(&m_ctape_block_buffer[0], fm_pattern, 4) == 0 && + memcmp(&m_ctape_block_buffer[0], &m_ctape_block_buffer[4], SC499_CTAPE_BLOCK_SIZE-4) == 0; + + LOG3(("block_is_filemark for block %d = %d", m_tape_pos-1, is_filemark)); + return is_filemark; +} + +/*------------------------------------------------- + block_set_filemark - set current block buffer data to filemark + -------------------------------------------------*/ + +void sc499_device::block_set_filemark() +{ + static const UINT8 fm_pattern[] = {0xDE, 0xAF, 0xFA, 0xED}; + for (int i = 0; i < SC499_CTAPE_BLOCK_SIZE; i += 4) + { + memcpy(&m_ctape_block_buffer[i], fm_pattern, 4); + } +} + +//########################################################################## + +const device_type SC499_CTAPE = &device_creator; + +sc499_ctape_image_device::sc499_ctape_image_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, SC499_CTAPE, "Cartridge Tape", tag, owner, clock, "sc499_ctape", __FILE__), + device_image_interface(mconfig, *this) +{ +} + +void sc499_ctape_image_device::device_config_complete() +{ + update_names(SC499_CTAPE, "ctape", "ct"); +} + + +UINT8 *sc499_ctape_image_device::read_block(int block_num) +{ + // access beyond end of tape cart + if (m_ctape_data.size() <= (block_num + 1) * SC499_CTAPE_BLOCK_SIZE) + return NULL; + else + return &m_ctape_data[block_num * SC499_CTAPE_BLOCK_SIZE]; +} + +void sc499_ctape_image_device::write_block(int block_num, UINT8 *ptr) +{ + if (!(m_ctape_data.size() <= (block_num + 1) * SC499_CTAPE_BLOCK_SIZE)) + memcpy(&m_ctape_data[block_num * SC499_CTAPE_BLOCK_SIZE], ptr, SC499_CTAPE_BLOCK_SIZE); +} + +bool sc499_ctape_image_device::call_load() +{ + UINT32 size; + io_generic io; + io.file = (device_image_interface *)this; + io.procs = &image_ioprocs; + io.filler = 0xff; + + size = io_generic_size(&io); + m_ctape_data.resize(size); + + io_generic_read(&io, &m_ctape_data[0], 0, size); + + return IMAGE_INIT_PASS; +} + +void sc499_ctape_image_device::call_unload() +{ + m_ctape_data.resize(0); + // TODO: add save tape on exit? + //if (software_entry() == NULL) + //{ + // fseek(0, SEEK_SET); + // fwrite(m_ctape_data, m_ctape_data.size); + //} +} diff --git a/src/devices/bus/isa/sc499.h b/src/devices/bus/isa/sc499.h new file mode 100644 index 00000000000..a83b61564b8 --- /dev/null +++ b/src/devices/bus/isa/sc499.h @@ -0,0 +1,159 @@ +// license:BSD-3-Clause +// copyright-holders:Hans Ostermeyer, R. Belmont +/* + * sc499.h - Archive Cartridge tape controller SC-499 + * + * Created on: February 21, 2011 + * Author: Hans Ostermeyer + * + */ + +#pragma once + +#ifndef SC499_H_ +#define SC499_H_ + +#include "emu.h" +#include "bus/isa/isa.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> sc499_ctape_image_device + +class sc499_ctape_image_device : public device_t, public device_image_interface +{ +public: + // construction/destruction + sc499_ctape_image_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // image-level overrides + virtual bool call_load(); + virtual bool call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry) { return load_software(swlist, swname, start_entry); } + virtual void call_unload(); + virtual iodevice_t image_type() const { return IO_MAGTAPE; } + + virtual bool is_readable() const { return 1; } + virtual bool is_writeable() const { return 1; } + virtual bool is_creatable() const { return 1; } + virtual bool must_be_loaded() const { return 0; } + virtual bool is_reset_on_load() const { return 0; } + virtual const char *image_interface() const { return "sc499_cass"; } + virtual const char *file_extensions() const { return "act,ct"; } + virtual const option_guide *create_option_guide() const { return NULL; } + + UINT8 *read_block(int block_num); + void write_block(int block_num, UINT8 *ptr); + UINT64 tapelen() { return m_ctape_data.size(); } + +protected: + // device-level overrides + virtual void device_config_complete(); + virtual void device_start() { }; + + dynamic_buffer m_ctape_data; +}; + +// ======================> sc499_device + +class sc499_device: public device_t, public device_isa8_card_interface +{ +public: + // construction/destruction + sc499_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + int sc499_receive(const UINT8 data[], int length); + + required_ioport m_iobase; + required_ioport m_irqdrq; + +private: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + virtual machine_config_constructor device_mconfig_additions() const; + virtual ioport_constructor device_input_ports() const; + + // ISA overrides + virtual UINT8 dack_r(int line); + virtual void dack_w(int line,UINT8 data); + virtual void eop_w(int state); + + const char *cpu_context(); + + void tape_status_clear(UINT16 value); + void tape_status_set(UINT16 value); + + // device register I/O + DECLARE_READ8_MEMBER(read); + DECLARE_WRITE8_MEMBER(write); + + void check_tape(); + + void set_interrupt(enum line_state state); + + void log_command(UINT8 data); + void do_command(UINT8 data); + void do_reset(); + + void set_dma_drq(enum line_state state); + + void write_command_port( UINT8 data); + UINT8 read_data_port(); + void write_control_port( UINT8 data); + UINT8 read_status_port(); + void write_dma_go( UINT8 data); + void write_dma_reset( UINT8 data); + + void log_block(const char * text); + void read_block(); + void write_block(); + int block_is_filemark(); + void block_set_filemark(); + + UINT8 m_data; + UINT8 m_command; + UINT8 m_status; + UINT8 m_control; + + UINT8 m_has_cartridge; + UINT8 m_is_writable; + + UINT8 m_current_command; + + UINT8 m_first_block_hack; + UINT8 m_nasty_readahead; + UINT8 m_read_block_pending; + + UINT16 m_data_index; + + UINT16 m_tape_status; /* Drive exception flags */ + UINT16 m_data_error_counter; /* data error count: nr of blocks rewritten/soft read errors */ + UINT16 m_underrun_counter; /* underrun count: nr of times streaming was interrupted */ + + UINT32 m_tape_pos; + UINT32 m_ctape_block_count; + UINT32 m_ctape_block_index; + UINT64 m_image_length; + + dynamic_buffer m_ctape_block_buffer; + required_device m_image; + + enum line_state irq_state; + enum line_state dma_drq_state; + + emu_timer * m_timer; // timer to delay functions + emu_timer * m_timer1; // timer to delay functions + int m_timer_type; + int m_irq, m_drq; + + bool m_installed; +}; + + +// device type definition +extern const device_type ISA8_SC499; + +#endif /* SC499_H_ */ diff --git a/src/devices/bus/isa/side116.c b/src/devices/bus/isa/side116.c new file mode 100644 index 00000000000..2de8254ffe4 --- /dev/null +++ b/src/devices/bus/isa/side116.c @@ -0,0 +1,190 @@ +// license:BSD-3-Clause +// copyright-holders:Dirk Best +/*************************************************************************** + + Acculogic sIDE-1/16 + + IDE Disk Controller for IBM PC, XT and compatibles + +***************************************************************************/ + +#include "side116.h" + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type ISA8_SIDE116 = &device_creator; + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( side116 ) + MCFG_ATA_INTERFACE_ADD("ata", ata_devices, "hdd", NULL, false) + MCFG_ATA_INTERFACE_IRQ_HANDLER(WRITELINE(side116_device, ide_interrupt)) +MACHINE_CONFIG_END + +machine_config_constructor side116_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( side116 ); +} + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +static INPUT_PORTS_START( side116 ) + PORT_START("configuration") + PORT_DIPNAME(0x01, 0x00, "sIDE-1/16 ROM") + PORT_DIPLOCATION("JP:1") + PORT_DIPSETTING(0x00, "Enabled") + PORT_DIPSETTING(0x01, "Disabled") + PORT_DIPNAME(0x06, 0x00, "sIDE-1/16 ROM Address") + PORT_DIPLOCATION("JP:2,3") + PORT_DIPSETTING(0x00, "Range C800h") + PORT_DIPSETTING(0x04, "Range CC00h") + PORT_DIPSETTING(0x02, "Range D800h") + PORT_DIPSETTING(0x06, "Range DC00h") + PORT_DIPNAME(0x18, 0x10, "sIDE-1/16 IDE IRQ") + PORT_DIPLOCATION("JP:4,5") + PORT_DIPSETTING(0x10, "Level 5") + PORT_DIPSETTING(0x08, "Level 2") + PORT_DIPNAME(0x20, 0x20, "sIDE-1/16 IDE") + PORT_DIPLOCATION("JP:6") + PORT_DIPSETTING(0x00, "Disabled") + PORT_DIPSETTING(0x20, "Enabled") +INPUT_PORTS_END + +ioport_constructor side116_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( side116 ); +} + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +ROM_START( side116 ) + ROM_REGION(0x2000, "option", 0) + ROM_LOAD("bios12.u2", 0x0000, 0x2000, CRC(c202a0e6) SHA1(a5b130a6d17c972d6c378cb2cd8113a4039631fe)) +ROM_END + +const rom_entry *side116_device::device_rom_region() const +{ + return ROM_NAME( side116 ); +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// side116_device - constructor +//------------------------------------------------- + +side116_device::side116_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, ISA8_SIDE116, "Acculogic sIDE-1/16 IDE Disk Controller", tag, owner, clock, "side116", __FILE__), + device_isa8_card_interface( mconfig, *this ), + m_ata(*this, "ata"), + m_config(*this, "configuration"), + m_latch(0xff) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void side116_device::device_start() +{ + set_isa_device(); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void side116_device::device_reset() +{ + // install option rom + if ((m_config->read() & 0x01) == 0x00) + { + switch ((m_config->read() >> 1) & 0x03) + { + case 0: m_isa->install_rom(this, 0xc8000, 0xc9fff, 0, 0, "side116", "option"); break; + case 1: m_isa->install_rom(this, 0xd8000, 0xd9fff, 0, 0, "side116", "option"); break; + case 2: m_isa->install_rom(this, 0xcc000, 0xcdfff, 0, 0, "side116", "option"); break; + case 3: m_isa->install_rom(this, 0xdc000, 0xddfff, 0, 0, "side116", "option"); break; + } + } + + // install io access + if ((m_config->read() & 0x20) == 0x20) + m_isa->install_device(0x360, 0x36f, 0, 0, read8_delegate(FUNC(side116_device::read), this), write8_delegate(FUNC(side116_device::write), this)); +} + + +//************************************************************************** +// IDE INTERFACE +//************************************************************************** + +READ8_MEMBER( side116_device::read ) +{ + UINT8 data; + + if (offset == 0) + { + UINT16 ide_data = m_ata->read_cs0(space, 0, 0xffff); + data = ide_data & 0xff; + m_latch = ide_data >> 8; + } + else if (offset < 8) + { + data = m_ata->read_cs0(space, offset & 7, 0xff); + } + else if (offset == 8) + { + data = m_latch; + } + else + { + data = m_ata->read_cs1(space, offset & 7, 0xff); + } + + return data; +} + +WRITE8_MEMBER( side116_device::write ) +{ + if (offset == 0) + { + UINT16 ide_data = (m_latch << 8) | data; + m_ata->write_cs0(space, 0, ide_data, 0xffff); + } + else if (offset < 8) + { + m_ata->write_cs0(space, offset & 7, data, 0xff); + } + else if (offset == 8) + { + m_latch = data; + } + else + { + m_ata->write_cs1(space, offset & 7, data, 0xff); + } +} + +WRITE_LINE_MEMBER( side116_device::ide_interrupt ) +{ + UINT8 level = m_config->read() & 0x18; + + if (level == 0x08) + m_isa->irq2_w(state); + else if (level == 0x10) + m_isa->irq5_w(state); +} diff --git a/src/devices/bus/isa/side116.h b/src/devices/bus/isa/side116.h new file mode 100644 index 00000000000..43c7a003810 --- /dev/null +++ b/src/devices/bus/isa/side116.h @@ -0,0 +1,59 @@ +// license:BSD-3-Clause +// copyright-holders:Dirk Best +/*************************************************************************** + + Acculogic sIDE-1/16 + + IDE Disk Controller for IBM PC, XT and compatibles + +***************************************************************************/ + +#pragma once + +#ifndef __ISA_SIDE116_H__ +#define __ISA_SIDE116_H__ + +#include "emu.h" +#include "machine/ataintf.h" +#include "isa.h" + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> side116_device + +class side116_device : public device_t, + public device_isa8_card_interface +{ +public: + // construction/destruction + side116_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual ioport_constructor device_input_ports() const; + virtual const rom_entry *device_rom_region() const; + + DECLARE_READ8_MEMBER( read ); + DECLARE_WRITE8_MEMBER( write ); + DECLARE_WRITE_LINE_MEMBER( ide_interrupt ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_config_complete() { m_shortname = "side116"; } + +private: + required_device m_ata; + required_ioport m_config; + UINT8 m_latch; +}; + + +// device type definition +extern const device_type ISA8_SIDE116; + +#endif diff --git a/src/devices/bus/isa/ssi2001.c b/src/devices/bus/isa/ssi2001.c new file mode 100644 index 00000000000..4a77e870190 --- /dev/null +++ b/src/devices/bus/isa/ssi2001.c @@ -0,0 +1,39 @@ +// license:BSD-3-Clause +// copyright-holders:Carl +// Innovation SSI-2001 + +#include "ssi2001.h" + +const device_type ISA8_SSI2001 = &device_creator; + +static MACHINE_CONFIG_FRAGMENT( ssi2001 ) + MCFG_SPEAKER_STANDARD_MONO("mono") + MCFG_SOUND_ADD("sid6581", MOS6581, XTAL_14_31818MHz/16) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 1.00) + MCFG_PC_JOY_ADD("pc_joy") +MACHINE_CONFIG_END + +machine_config_constructor ssi2001_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( ssi2001 ); +} + +ssi2001_device::ssi2001_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, ISA8_SSI2001, "Innovation SSI-2001 Audio Adapter", tag, owner, clock, "ssi2001", __FILE__), + device_isa8_card_interface(mconfig, *this), + m_joy(*this, "pc_joy"), + m_sid(*this, "sid6581") +{ +} + +void ssi2001_device::device_start() +{ + set_isa_device(); + m_isa->install_device(0x0200, 0x0207, 0, 0, read8_delegate(FUNC(pc_joy_device::joy_port_r), subdevice("pc_joy")), write8_delegate(FUNC(pc_joy_device::joy_port_w), subdevice("pc_joy"))); + m_isa->install_device(0x0280, 0x029F, 0, 0, read8_delegate(FUNC(mos6581_device::read), subdevice("sid6581")), write8_delegate(FUNC(mos6581_device::write), subdevice("sid6581"))); +} + + +void ssi2001_device::device_reset() +{ +} diff --git a/src/devices/bus/isa/ssi2001.h b/src/devices/bus/isa/ssi2001.h new file mode 100644 index 00000000000..589adac9f0b --- /dev/null +++ b/src/devices/bus/isa/ssi2001.h @@ -0,0 +1,40 @@ +// license:BSD-3-Clause +// copyright-holders:Carl +#ifndef __SSI2001__ +#define __SSI2001__ + +#include "emu.h" +#include "isa.h" +#include "sound/mos6581.h" +#include "bus/pc_joy/pc_joy.h" + +//********************************************************************* +// TYPE DEFINITIONS +//********************************************************************* + +// ====================> ssi2001_device + +class ssi2001_device : public device_t, + public device_isa8_card_interface +{ +public: + // construction/destruction + ssi2001_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + + required_device m_joy; + required_device m_sid; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); +}; + +// device type definition + +extern const device_type ISA8_SSI2001; + +#endif diff --git a/src/devices/bus/isa/stereo_fx.c b/src/devices/bus/isa/stereo_fx.c new file mode 100644 index 00000000000..4c1f3a37a80 --- /dev/null +++ b/src/devices/bus/isa/stereo_fx.c @@ -0,0 +1,233 @@ +// license:BSD-3-Clause +// copyright-holders:Carl +// ATI Stereo F/X +// +// TODO: UART is connected to MIDI port + +#include "stereo_fx.h" + +const device_type ISA8_STEREO_FX = &device_creator; + +READ8_MEMBER( stereo_fx_device::dev_dsp_data_r ) +{ + m_data_in = false; + return m_in_byte; +} + +WRITE8_MEMBER( stereo_fx_device::dev_dsp_data_w ) +{ + m_data_out = true; + m_out_byte = data; +} + +// port 1 is the left DAC but is written and read bitwise during capture +READ8_MEMBER( stereo_fx_device::p1_r ) +{ + return 0x80; +} + +READ8_MEMBER( stereo_fx_device::p3_r ) +{ + UINT8 ret = 0; + + ret |= m_data_out << 2; // INT0 + ret |= m_data_in << 3; // INT1 + ret |= m_t0 << 4; // T0 + ret |= m_t1 << 5; // T1 + return ret; +} + +WRITE8_MEMBER( stereo_fx_device::p3_w ) +{ + m_t1 = (data & 0x20) >> 5; +} + +WRITE8_MEMBER( stereo_fx_device::dev_host_irq_w ) +{ + m_isa->irq5_w(1); +} + +WRITE8_MEMBER( stereo_fx_device::raise_drq_w ) +{ + m_isa->drq1_w(1); +} + +/* port 0x20 - in ROM (usually) stored in RAM 0x22 + * bit0 - + * bit1 - + * bit2 - + * bit3 - + * bit4 - + * bit5 - + * bit6 - + * bit7 - +*/ +WRITE8_MEMBER( stereo_fx_device::port20_w ) +{ + m_port20 = data; +} + +/* port 0x00 - in ROM (usually) stored in RAM 0x21 + * bit0 - bits 0-4 related to sample rate + * bit1 - are set to 0x09-0x1e + * bit2 - + * bit3 - + * bit4 - + * bit5 - + * bit6 - + * bit7 - +*/ +WRITE8_MEMBER( stereo_fx_device::port00_w ) +{ + m_port00 = data; +} + +ROM_START( stereo_fx ) + ROM_REGION( 0x8000, "stereo_fx_cpu", 0 ) + ROM_LOAD("ati_stereo_fx.bin", 0x0000, 0x8000, CRC(1bebffa6) SHA1(e66c2619a6c05199554b5702d67877ae3799d415)) +ROM_END + +static ADDRESS_MAP_START(stereo_fx_io, AS_IO, 8, stereo_fx_device) + AM_RANGE(0xFF00, 0xFF00) AM_WRITE(port00_w) + AM_RANGE(0xFF10, 0xFF10) AM_DEVWRITE("dacr", dac_device, write_unsigned8) + AM_RANGE(0xFF20, 0xFF20) AM_WRITE(port20_w) + //AM_RANGE(0xFF30, 0xFF30) AM_WRITE() // used only on reset and undocumented cmd 0xc4 + AM_RANGE(0xFF40, 0xFF40) AM_READWRITE(dev_dsp_data_r, dev_dsp_data_w) + AM_RANGE(0xFF50, 0xFF50) AM_WRITE(raise_drq_w) + AM_RANGE(0xFF60, 0xFF60) AM_WRITE(dev_host_irq_w) + AM_RANGE(MCS51_PORT_P1, MCS51_PORT_P1) AM_READ(p1_r) AM_DEVWRITE("dacl", dac_device, write_unsigned8) + AM_RANGE(MCS51_PORT_P3, MCS51_PORT_P3) AM_READWRITE(p3_r, p3_w) +ADDRESS_MAP_END + +static ADDRESS_MAP_START(stereo_fx_rom, AS_PROGRAM, 8, stereo_fx_device) + AM_RANGE(0x0000, 0x7fff) AM_ROM +ADDRESS_MAP_END + +static MACHINE_CONFIG_FRAGMENT( stereo_fx ) + MCFG_CPU_ADD("stereo_fx_cpu", I80C31, XTAL_30MHz) + MCFG_CPU_IO_MAP(stereo_fx_io) + MCFG_CPU_PROGRAM_MAP(stereo_fx_rom) + + MCFG_SPEAKER_STANDARD_STEREO("lspeaker", "rspeaker") + MCFG_SOUND_ADD("ym3812", YM3812, XTAL_3_579545MHz) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "lspeaker", 1.00) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "rspeaker", 1.00) + /* no CM/S support (empty sockets) */ + + MCFG_SOUND_ADD("dacl", DAC, 0) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "lspeaker", 1.00) + MCFG_SOUND_ADD("dacr", DAC, 0) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "rspeaker", 1.00) + + MCFG_PC_JOY_ADD("pc_joy") +MACHINE_CONFIG_END + +const rom_entry *stereo_fx_device::device_rom_region() const +{ + return ROM_NAME( stereo_fx ); +} + +machine_config_constructor stereo_fx_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( stereo_fx ); +} + +READ8_MEMBER( stereo_fx_device::dsp_data_r ) +{ + m_data_out = false; + return m_out_byte; +} + +WRITE8_MEMBER( stereo_fx_device::dsp_cmd_w ) +{ + m_data_in = true; + m_in_byte = data; +} + +UINT8 stereo_fx_device::dack_r(int line) +{ + m_data_out = false; + m_isa->drq1_w(0); + return m_out_byte; +} + +void stereo_fx_device::dack_w(int line, UINT8 data) +{ + m_data_in = true; + m_isa->drq1_w(0); + m_in_byte = data; +} + +WRITE8_MEMBER( stereo_fx_device::dsp_reset_w ) +{ + device_reset(); + m_cpu->set_input_line(INPUT_LINE_RESET, PULSE_LINE); +} + +READ8_MEMBER( stereo_fx_device::dsp_wbuf_status_r ) +{ + return m_data_in << 7; +} + +READ8_MEMBER( stereo_fx_device::dsp_rbuf_status_r ) +{ + m_isa->irq5_w(0); + return m_data_out << 7; +} + +WRITE8_MEMBER( stereo_fx_device::invalid_w ) +{ + logerror("stereo fx: invalid port write\n"); +} + +READ8_MEMBER( stereo_fx_device::invalid_r ) +{ + logerror("stereo fx: invalid port read\n"); + return 0xff; +} + +stereo_fx_device::stereo_fx_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, ISA8_STEREO_FX, "ATI Stereo F/X Audio Adapter", tag, owner, clock, "stereo_fx", __FILE__), + device_isa8_card_interface(mconfig, *this), + m_dacl(*this, "dacl"), + m_dacr(*this, "dacr"), + m_joy(*this, "pc_joy"), + m_cpu(*this, "stereo_fx_cpu") +{ + m_t1 = 0; +} + +void stereo_fx_device::device_start() +{ + ym3812_device *ym3812 = subdevice("ym3812"); + set_isa_device(); + + m_isa->install_device(0x0200, 0x0207, 0, 0, read8_delegate(FUNC(pc_joy_device::joy_port_r), subdevice("pc_joy")), write8_delegate(FUNC(pc_joy_device::joy_port_w), subdevice("pc_joy"))); + m_isa->install_device(0x0226, 0x0227, 0, 0, read8_delegate(FUNC(stereo_fx_device::invalid_r), this), write8_delegate(FUNC(stereo_fx_device::dsp_reset_w), this)); + m_isa->install_device(0x022a, 0x022b, 0, 0, read8_delegate(FUNC(stereo_fx_device::dsp_data_r), this), write8_delegate(FUNC(stereo_fx_device::invalid_w), this) ); + m_isa->install_device(0x022c, 0x022d, 0, 0, read8_delegate(FUNC(stereo_fx_device::dsp_wbuf_status_r), this), write8_delegate(FUNC(stereo_fx_device::dsp_cmd_w), this) ); + m_isa->install_device(0x022e, 0x022f, 0, 0, read8_delegate(FUNC(stereo_fx_device::dsp_rbuf_status_r), this), write8_delegate(FUNC(stereo_fx_device::invalid_w), this) ); + m_isa->install_device(0x0388, 0x0389, 0, 0, read8_delegate(FUNC(ym3812_device::read), ym3812), write8_delegate(FUNC(ym3812_device::write), ym3812)); + m_isa->install_device(0x0228, 0x0229, 0, 0, read8_delegate(FUNC(ym3812_device::read), ym3812), write8_delegate(FUNC(ym3812_device::write), ym3812)); + m_timer = timer_alloc(); + m_timer->adjust(attotime::from_hz(2000000), 0, attotime::from_hz(2000000)); + m_isa->set_dma_channel(1, this, FALSE); +} + + +void stereo_fx_device::device_reset() +{ + m_isa->drq1_w(0); + m_isa->irq5_w(0); + m_data_out = false; + m_data_in = false; + m_port20 = 0; + m_port00 = 0; + m_t0 = CLEAR_LINE; +} + +void stereo_fx_device::device_timer(emu_timer &timer, device_timer_id tid, int param, void *ptr) +{ + m_t0 = !m_t0; + m_cpu->set_input_line(MCS51_T0_LINE, m_t0); +} diff --git a/src/devices/bus/isa/stereo_fx.h b/src/devices/bus/isa/stereo_fx.h new file mode 100644 index 00000000000..d82367cfff9 --- /dev/null +++ b/src/devices/bus/isa/stereo_fx.h @@ -0,0 +1,81 @@ +// license:BSD-3-Clause +// copyright-holders:Carl +#ifndef __STEREO_FX__ +#define __STEREO_FX__ + +#include "emu.h" +#include "isa.h" +#include "sound/dac.h" +#include "bus/pc_joy/pc_joy.h" +#include "cpu/mcs51/mcs51.h" +#include "sound/3812intf.h" + +//********************************************************************* +// TYPE DEFINITIONS +//********************************************************************* + +// ====================> stereo_fx_device + +class stereo_fx_device : public device_t, + public device_isa8_card_interface +{ +public: + // construction/destruction + stereo_fx_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + + required_device m_dacl; + required_device m_dacr; + required_device m_joy; + required_device m_cpu; + + // mcu ports + DECLARE_READ8_MEMBER( dev_dsp_data_r ); + DECLARE_WRITE8_MEMBER( dev_dsp_data_w ); + DECLARE_READ8_MEMBER( p1_r ); + DECLARE_READ8_MEMBER( p3_r ); + DECLARE_WRITE8_MEMBER( p3_w ); + DECLARE_WRITE8_MEMBER( dev_host_irq_w ); + DECLARE_WRITE8_MEMBER( raise_drq_w ); + DECLARE_WRITE8_MEMBER( port20_w ); + DECLARE_WRITE8_MEMBER( port00_w ); + + // host ports + DECLARE_READ8_MEMBER( dsp_data_r ); + DECLARE_WRITE8_MEMBER( dsp_cmd_w ); + DECLARE_WRITE8_MEMBER( dsp_reset_w ); + DECLARE_READ8_MEMBER( dsp_wbuf_status_r ); + DECLARE_READ8_MEMBER( dsp_rbuf_status_r ); + DECLARE_READ8_MEMBER( invalid_r ); + DECLARE_WRITE8_MEMBER( invalid_w ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + UINT8 dack_r(int line); + void dack_w(int line, UINT8 data); +private: + // internal state + bool m_data_in; + UINT8 m_in_byte; + bool m_data_out; + UINT8 m_out_byte; + + UINT8 m_port20; + UINT8 m_port00; + emu_timer *m_timer; + UINT8 m_t0; + UINT8 m_t1; +}; + +// device type definition + +extern const device_type ISA8_STEREO_FX; + +#endif diff --git a/src/devices/bus/isa/svga_cirrus.c b/src/devices/bus/isa/svga_cirrus.c new file mode 100644 index 00000000000..bf6ff8842e0 --- /dev/null +++ b/src/devices/bus/isa/svga_cirrus.c @@ -0,0 +1,180 @@ +// license:BSD-3-Clause +// copyright-holders:Barry Rodewald +/*************************************************************************** + + ISA SVGA Cirrus Logic wrapper + +***************************************************************************/ + +#include "emu.h" +#include "svga_cirrus.h" + +ROM_START( dm_clgd5430 ) + ROM_REGION(0x8000,"dm_clgd5430", 0) + ROM_LOAD("speedstar_pro_se_v1.00.u2", 0x00000, 0x8000, CRC(ed79572c) SHA1(15131e2b2db7a34971083a250e4a21ab7bd64a9d) ) + ROM_IGNORE( 0x8000 ) +ROM_END + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type ISA16_SVGA_CIRRUS = &device_creator; +const device_type ISA16_SVGA_CIRRUS_GD542X = &device_creator; + +static MACHINE_CONFIG_FRAGMENT( vga_cirrus ) + MCFG_SCREEN_ADD("screen", RASTER) + MCFG_SCREEN_RAW_PARAMS(XTAL_25_1748MHz,900,0,640,526,0,480) + MCFG_SCREEN_UPDATE_DEVICE("vga", cirrus_gd5430_device, screen_update) + + MCFG_PALETTE_ADD("palette", 0x100) + + MCFG_DEVICE_ADD("vga", CIRRUS_GD5430, 0) +MACHINE_CONFIG_END + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor isa16_svga_cirrus_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( vga_cirrus ); +} + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *isa16_svga_cirrus_device::device_rom_region() const +{ + return ROM_NAME( dm_clgd5430 ); +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// isa16_vga_device - constructor +//------------------------------------------------- + +isa16_svga_cirrus_device::isa16_svga_cirrus_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, ISA16_SVGA_CIRRUS, "Diamond Speedstar Pro SE ISA Graphics Card (BIOS v1.00)", tag, owner, clock, "dm_clgd5430", __FILE__), + device_isa16_card_interface(mconfig, *this) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- +READ8_MEMBER(isa16_svga_cirrus_device::input_port_0_r ) { return 0xff; } //return space.machine().root_device().ioport("IN0")->read(); } + +void isa16_svga_cirrus_device::device_start() +{ + set_isa_device(); + + m_vga = subdevice("vga"); + + m_isa->install_rom(this, 0xc0000, 0xc7fff, 0, 0, "svga", "dm_clgd5430"); + + m_isa->install_device(0x03b0, 0x03bf, 0, 0, read8_delegate(FUNC(cirrus_gd5430_device::port_03b0_r),m_vga), write8_delegate(FUNC(cirrus_gd5430_device::port_03b0_w),m_vga)); + m_isa->install_device(0x03c0, 0x03cf, 0, 0, read8_delegate(FUNC(cirrus_gd5430_device::port_03c0_r),m_vga), write8_delegate(FUNC(cirrus_gd5430_device::port_03c0_w),m_vga)); + m_isa->install_device(0x03d0, 0x03df, 0, 0, read8_delegate(FUNC(cirrus_gd5430_device::port_03d0_r),m_vga), write8_delegate(FUNC(cirrus_gd5430_device::port_03d0_w),m_vga)); + + m_isa->install_memory(0xa0000, 0xbffff, 0, 0, read8_delegate(FUNC(cirrus_gd5430_device::mem_r),m_vga), write8_delegate(FUNC(cirrus_gd5430_device::mem_w),m_vga)); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void isa16_svga_cirrus_device::device_reset() +{ +} + + +/* + Generic CL-GD542x video card +*/ + +ROM_START( clgd542x ) + ROM_REGION(0x08000, "clgd542x", 0) + ROM_LOAD16_BYTE("techyosd-isa-bios-v1.2.u8", 0x00000, 0x04000, CRC(6adf7e71) SHA1(2b07d964cc7c2c0aa560625b7c12f38d4537d652) ) + ROM_CONTINUE( 0x00001, 0x04000 ) +ROM_END + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +static MACHINE_CONFIG_FRAGMENT( vga_cirrus_gd542x ) + MCFG_SCREEN_ADD("screen", RASTER) + MCFG_SCREEN_RAW_PARAMS(XTAL_25_1748MHz,900,0,640,526,0,480) + MCFG_SCREEN_UPDATE_DEVICE("vga", cirrus_gd5428_device, screen_update) + + MCFG_PALETTE_ADD("palette", 0x100) + + MCFG_DEVICE_ADD("vga", CIRRUS_GD5428, 0) +MACHINE_CONFIG_END + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor isa16_svga_cirrus_gd542x_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( vga_cirrus_gd542x ); +} + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *isa16_svga_cirrus_gd542x_device::device_rom_region() const +{ + return ROM_NAME( clgd542x ); +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// isa16_vga_device - constructor +//------------------------------------------------- + +isa16_svga_cirrus_gd542x_device::isa16_svga_cirrus_gd542x_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, ISA16_SVGA_CIRRUS_GD542X, "Generic Cirrus Logic GD542x Graphics Card (BIOS v1.20)", tag, owner, clock, "clgd542x", __FILE__), + device_isa16_card_interface(mconfig, *this) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- +READ8_MEMBER(isa16_svga_cirrus_gd542x_device::input_port_0_r ) { return 0xff; } //return space.machine().root_device().ioport("IN0")->read(); } + +void isa16_svga_cirrus_gd542x_device::device_start() +{ + set_isa_device(); + + m_vga = subdevice("vga"); + + m_isa->install_rom(this, 0xc0000, 0xc7fff, 0, 0, "svga", "clgd542x"); + + m_isa->install_device(0x03b0, 0x03bf, 0, 0, read8_delegate(FUNC(cirrus_gd5428_device::port_03b0_r),m_vga), write8_delegate(FUNC(cirrus_gd5428_device::port_03b0_w),m_vga)); + m_isa->install_device(0x03c0, 0x03cf, 0, 0, read8_delegate(FUNC(cirrus_gd5428_device::port_03c0_r),m_vga), write8_delegate(FUNC(cirrus_gd5428_device::port_03c0_w),m_vga)); + m_isa->install_device(0x03d0, 0x03df, 0, 0, read8_delegate(FUNC(cirrus_gd5428_device::port_03d0_r),m_vga), write8_delegate(FUNC(cirrus_gd5428_device::port_03d0_w),m_vga)); + + m_isa->install_memory(0xa0000, 0xbffff, 0, 0, read8_delegate(FUNC(cirrus_gd5428_device::mem_r),m_vga), write8_delegate(FUNC(cirrus_gd5428_device::mem_w),m_vga)); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void isa16_svga_cirrus_gd542x_device::device_reset() +{ +} diff --git a/src/devices/bus/isa/svga_cirrus.h b/src/devices/bus/isa/svga_cirrus.h new file mode 100644 index 00000000000..5259590bf7e --- /dev/null +++ b/src/devices/bus/isa/svga_cirrus.h @@ -0,0 +1,63 @@ +// license:BSD-3-Clause +// copyright-holders:Barry Rodewald +#pragma once + +#ifndef __ISA_SVGA_CIRRUS_H__ +#define __ISA_SVGA_CIRRUS_H__ + +#include "emu.h" +#include "isa.h" +#include "video/clgd542x.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class isa16_svga_cirrus_device : + public device_t, + public device_isa16_card_interface +{ +public: + // construction/destruction + isa16_svga_cirrus_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual const rom_entry *device_rom_region() const; + + DECLARE_READ8_MEMBER(input_port_0_r); +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); +private: + cirrus_gd5430_device *m_vga; +}; + +class isa16_svga_cirrus_gd542x_device : + public device_t, + public device_isa16_card_interface +{ +public: + // construction/destruction + isa16_svga_cirrus_gd542x_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual const rom_entry *device_rom_region() const; + + DECLARE_READ8_MEMBER(input_port_0_r); +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); +private: + cirrus_gd5428_device *m_vga; +}; + + +// device type definition +extern const device_type ISA16_SVGA_CIRRUS; +extern const device_type ISA16_SVGA_CIRRUS_GD542X; + +#endif /* __ISA_VGA_H__ */ diff --git a/src/devices/bus/isa/svga_s3.c b/src/devices/bus/isa/svga_s3.c new file mode 100644 index 00000000000..01ac8d3053a --- /dev/null +++ b/src/devices/bus/isa/svga_s3.c @@ -0,0 +1,392 @@ +// license:BSD-3-Clause +// copyright-holders:Barry Rodewald +/*************************************************************************** + + ISA SVGA S3 wrapper + +***************************************************************************/ + +#include "emu.h" +#include "svga_s3.h" + +ROM_START( s3_764 ) + ROM_REGION(0x8000,"s3_764", 0) + ROM_DEFAULT_BIOS("9fxv330") + + ROM_SYSTEM_BIOS( 0, "9fxv330", "PCI Number Nine 9FX Vision 330 2.03.10 (S3 Trio64)" ) + ROMX_LOAD("s3_764.bin", 0x00000, 0x8000, CRC(4f10aac7) SHA1(c77b3f11cc15679121314823588887dd547cd715), ROM_BIOS(1) ) + ROM_IGNORE( 0x8000 ) + + // The following are from Trio64V2/DX based cards + ROM_SYSTEM_BIOS( 1, "trio64v2", "PCI S3 86C765 v1.03-08N (S3 Trio64V2/DX)" ) + ROMX_LOAD("pci_9503-62_s3.bin", 0x00000, 0x8000, CRC(0e9d79d8) SHA1(274b5b98cc998f2783567000cdb12b14308bc290), ROM_BIOS(2) ) + + ROM_SYSTEM_BIOS( 2, "winner1k", "PCI Elsa Winner 1000/T2D 6.01.00 (S3 Trio64V2/DX)" ) + ROMX_LOAD("pci_elsa_winner_1000-t2d_6.01.00.bin", 0x00000, 0x8000, CRC(1c9532b8) SHA1(d27d60b9a3566aa42a01ad497046af16eaa2ed87), ROM_BIOS(3) ) + +ROM_END + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type ISA16_SVGA_S3 = &device_creator; + + +static MACHINE_CONFIG_FRAGMENT( vga_s3 ) + MCFG_SCREEN_ADD("screen", RASTER) + MCFG_SCREEN_RAW_PARAMS(XTAL_25_1748MHz,900,0,640,526,0,480) + MCFG_SCREEN_UPDATE_DEVICE("vga", s3_vga_device, screen_update) + + MCFG_PALETTE_ADD("palette", 0x100) + + MCFG_DEVICE_ADD("vga", S3_VGA, 0) +MACHINE_CONFIG_END + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor isa16_svga_s3_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( vga_s3 ); +} + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *isa16_svga_s3_device::device_rom_region() const +{ + return ROM_NAME( s3_764 ); +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// isa16_vga_device - constructor +//------------------------------------------------- + +isa16_svga_s3_device::isa16_svga_s3_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, ISA16_SVGA_S3, "Number Nine 9FX Vision 330 (S3 764) Graphics Card", tag, owner, clock, "s3_764", __FILE__), + device_isa16_card_interface(mconfig, *this) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- +READ8_MEMBER(isa16_svga_s3_device::input_port_0_r ) { return 0xff; } //return space.machine().root_device().ioport("IN0")->read(); } + +void isa16_svga_s3_device::device_start() +{ + set_isa_device(); + + m_vga = subdevice("vga"); + m_8514 = subdevice("vga:8514a"); + + m_isa->install_rom(this, 0xc0000, 0xc7fff, 0, 0, "svga", "s3_764"); + + m_isa->install_device(0x03b0, 0x03bf, 0, 0, read8_delegate(FUNC(s3_vga_device::port_03b0_r),m_vga), write8_delegate(FUNC(s3_vga_device::port_03b0_w),m_vga)); + m_isa->install_device(0x03c0, 0x03cf, 0, 0, read8_delegate(FUNC(s3_vga_device::port_03c0_r),m_vga), write8_delegate(FUNC(s3_vga_device::port_03c0_w),m_vga)); + m_isa->install_device(0x03d0, 0x03df, 0, 0, read8_delegate(FUNC(s3_vga_device::port_03d0_r),m_vga), write8_delegate(FUNC(s3_vga_device::port_03d0_w),m_vga)); + m_isa->install16_device(0x82e8, 0x82eb, 0, 0, read16_delegate(FUNC(ibm8514a_device::ibm8514_currenty_r),m_8514), write16_delegate(FUNC(ibm8514a_device::ibm8514_currenty_w),m_8514)); + m_isa->install16_device(0x86e8, 0x86eb, 0, 0, read16_delegate(FUNC(ibm8514a_device::ibm8514_currentx_r),m_8514), write16_delegate(FUNC(ibm8514a_device::ibm8514_currentx_w),m_8514)); + m_isa->install16_device(0x8ae8, 0x8aeb, 0, 0, read16_delegate(FUNC(ibm8514a_device::ibm8514_desty_r),m_8514), write16_delegate(FUNC(ibm8514a_device::ibm8514_desty_w),m_8514)); + m_isa->install16_device(0x8ee8, 0x8eeb, 0, 0, read16_delegate(FUNC(ibm8514a_device::ibm8514_destx_r),m_8514), write16_delegate(FUNC(ibm8514a_device::ibm8514_destx_w),m_8514)); + m_isa->install16_device(0x92e8, 0x92eb, 0, 0, read16_delegate(FUNC(ibm8514a_device::ibm8514_line_error_r),m_8514), write16_delegate(FUNC(ibm8514a_device::ibm8514_line_error_w),m_8514)); + m_isa->install16_device(0x96e8, 0x96eb, 0, 0, read16_delegate(FUNC(ibm8514a_device::ibm8514_width_r),m_8514), write16_delegate(FUNC(ibm8514a_device::ibm8514_width_w),m_8514)); + m_isa->install16_device(0x9ae8, 0x9aeb, 0, 0, read16_delegate(FUNC(ibm8514a_device::ibm8514_gpstatus_r),m_8514), write16_delegate(FUNC(ibm8514a_device::ibm8514_cmd_w),m_8514)); + m_isa->install16_device(0x9ee8, 0x9eeb, 0, 0, read16_delegate(FUNC(ibm8514a_device::ibm8514_ssv_r),m_8514), write16_delegate(FUNC(ibm8514a_device::ibm8514_ssv_w),m_8514)); + m_isa->install16_device(0xa2e8, 0xa2eb, 0, 0, read16_delegate(FUNC(ibm8514a_device::ibm8514_bgcolour_r),m_8514), write16_delegate(FUNC(ibm8514a_device::ibm8514_bgcolour_w),m_8514)); + m_isa->install16_device(0xa6e8, 0xa6eb, 0, 0, read16_delegate(FUNC(ibm8514a_device::ibm8514_fgcolour_r),m_8514), write16_delegate(FUNC(ibm8514a_device::ibm8514_fgcolour_w),m_8514)); + m_isa->install16_device(0xaae8, 0xaaeb, 0, 0, read16_delegate(FUNC(ibm8514a_device::ibm8514_write_mask_r),m_8514), write16_delegate(FUNC(ibm8514a_device::ibm8514_write_mask_w),m_8514)); + m_isa->install16_device(0xaee8, 0xaeeb, 0, 0, read16_delegate(FUNC(ibm8514a_device::ibm8514_read_mask_r),m_8514), write16_delegate(FUNC(ibm8514a_device::ibm8514_read_mask_w),m_8514)); + m_isa->install16_device(0xb6e8, 0xb6eb, 0, 0, read16_delegate(FUNC(ibm8514a_device::ibm8514_backmix_r),m_8514), write16_delegate(FUNC(ibm8514a_device::ibm8514_backmix_w),m_8514)); + m_isa->install16_device(0xbae8, 0xbaeb, 0, 0, read16_delegate(FUNC(ibm8514a_device::ibm8514_foremix_r),m_8514), write16_delegate(FUNC(ibm8514a_device::ibm8514_foremix_w),m_8514)); + m_isa->install16_device(0xbee8, 0xbeeb, 0, 0, read16_delegate(FUNC(ibm8514a_device::ibm8514_multifunc_r),m_8514), write16_delegate(FUNC(ibm8514a_device::ibm8514_multifunc_w),m_8514)); + m_isa->install16_device(0xe2e8, 0xe2eb, 0, 0, read16_delegate(FUNC(ibm8514a_device::ibm8514_pixel_xfer_r),m_8514), write16_delegate(FUNC(ibm8514a_device::ibm8514_pixel_xfer_w),m_8514)); + + m_isa->install_memory(0xa0000, 0xbffff, 0, 0, read8_delegate(FUNC(s3_vga_device::mem_r),m_vga), write8_delegate(FUNC(s3_vga_device::mem_w),m_vga)); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void isa16_svga_s3_device::device_reset() +{ +} + + +/* + * S3 Virge 2D/3D accelerator + */ + +ROM_START( s3virge ) + ROM_REGION(0x8000,"s3virge", 0) + ROM_DEFAULT_BIOS("virge") + + ROM_SYSTEM_BIOS( 0, "virge", "PCI S3 ViRGE v1.00-10" ) + ROMX_LOAD("pci_m-v_virge-4s3.bin", 0x00000, 0x8000, CRC(d0a0f1de) SHA1(b7b41081974762a199610219bdeab149b7c7143d), ROM_BIOS(1) ) + + ROM_SYSTEM_BIOS( 1, "virgeo", "PCI S3 ViRGE v1.00-05" ) + ROMX_LOAD("s3virge.bin", 0x00000, 0x8000, CRC(a7983a85) SHA1(e885371816d3237f7badd57ccd602cd863c9c9f8), ROM_BIOS(2) ) + ROM_IGNORE( 0x8000 ) +ROM_END + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type ISA16_S3VIRGE = &device_creator; + + +static MACHINE_CONFIG_FRAGMENT( vga_s3virge ) + MCFG_SCREEN_ADD("screen", RASTER) + MCFG_SCREEN_RAW_PARAMS(XTAL_25_1748MHz,900,0,640,526,0,480) + MCFG_SCREEN_UPDATE_DEVICE("vga", s3virge_vga_device, screen_update) + + MCFG_PALETTE_ADD("palette", 0x100) + + MCFG_DEVICE_ADD("vga", S3VIRGE, 0) +MACHINE_CONFIG_END + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor isa16_s3virge_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( vga_s3virge ); +} + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *isa16_s3virge_device::device_rom_region() const +{ + return ROM_NAME( s3virge ); +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// isa16_vga_device - constructor +//------------------------------------------------- + +isa16_s3virge_device::isa16_s3virge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, ISA16_S3VIRGE, "S3 ViRGE Graphics Card", tag, owner, clock, "s3virge", __FILE__), + device_isa16_card_interface(mconfig, *this) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- +READ8_MEMBER(isa16_s3virge_device::input_port_0_r ) { return 0xff; } //return space.machine().root_device().ioport("IN0")->read(); } + +void isa16_s3virge_device::device_start() +{ + set_isa_device(); + + m_vga = subdevice("vga"); + + m_isa->install_rom(this, 0xc0000, 0xc7fff, 0, 0, "svga", "s3virge"); + + m_isa->install_device(0x03b0, 0x03bf, 0, 0, read8_delegate(FUNC(s3virge_vga_device::port_03b0_r),m_vga), write8_delegate(FUNC(s3virge_vga_device::port_03b0_w),m_vga)); + m_isa->install_device(0x03c0, 0x03cf, 0, 0, read8_delegate(FUNC(s3virge_vga_device::port_03c0_r),m_vga), write8_delegate(FUNC(s3virge_vga_device::port_03c0_w),m_vga)); + m_isa->install_device(0x03d0, 0x03df, 0, 0, read8_delegate(FUNC(s3virge_vga_device::port_03d0_r),m_vga), write8_delegate(FUNC(s3virge_vga_device::port_03d0_w),m_vga)); + + m_isa->install_memory(0xa0000, 0xbffff, 0, 0, read8_delegate(FUNC(s3virge_vga_device::mem_r),m_vga), write8_delegate(FUNC(s3virge_vga_device::mem_w),m_vga)); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void isa16_s3virge_device::device_reset() +{ +} + +/* + * S3 ViRGE/DX + */ + +static MACHINE_CONFIG_FRAGMENT( vga_s3virgedx ) + MCFG_SCREEN_ADD("screen", RASTER) + MCFG_SCREEN_RAW_PARAMS(XTAL_25_1748MHz,900,0,640,526,0,480) + MCFG_SCREEN_UPDATE_DEVICE("vga", s3virgedx_vga_device, screen_update) + + MCFG_PALETTE_ADD("palette", 0x100) + + MCFG_DEVICE_ADD("vga", S3VIRGEDX, 0) +MACHINE_CONFIG_END + +ROM_START( s3virgedx ) + ROM_REGION(0x8000,"s3virgedx", 0) + ROM_LOAD("s3virgedx.bin", 0x00000, 0x8000, CRC(0da83bd3) SHA1(228a2d644e1732cb5a2eb1291608c7050cf39229) ) +ROM_END + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type ISA16_S3VIRGEDX = &device_creator; + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor isa16_s3virgedx_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( vga_s3virgedx ); +} + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *isa16_s3virgedx_device::device_rom_region() const +{ + return ROM_NAME( s3virgedx ); +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// isa16_vga_device - constructor +//------------------------------------------------- + +isa16_s3virgedx_device::isa16_s3virgedx_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, ISA16_S3VIRGEDX, "S3 ViRGE/DX Graphics Card", tag, owner, clock, "s3virgedx", __FILE__), + device_isa16_card_interface(mconfig, *this) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- +READ8_MEMBER(isa16_s3virgedx_device::input_port_0_r ) { return 0xff; } //return space.machine().root_device().ioport("IN0")->read(); } + +void isa16_s3virgedx_device::device_start() +{ + set_isa_device(); + + m_vga = subdevice("vga"); + + m_isa->install_rom(this, 0xc0000, 0xc7fff, 0, 0, "svga", "s3virgedx"); + + m_isa->install_device(0x03b0, 0x03bf, 0, 0, read8_delegate(FUNC(s3virge_vga_device::port_03b0_r),m_vga), write8_delegate(FUNC(s3virge_vga_device::port_03b0_w),m_vga)); + m_isa->install_device(0x03c0, 0x03cf, 0, 0, read8_delegate(FUNC(s3virge_vga_device::port_03c0_r),m_vga), write8_delegate(FUNC(s3virge_vga_device::port_03c0_w),m_vga)); + m_isa->install_device(0x03d0, 0x03df, 0, 0, read8_delegate(FUNC(s3virge_vga_device::port_03d0_r),m_vga), write8_delegate(FUNC(s3virge_vga_device::port_03d0_w),m_vga)); + + m_isa->install_memory(0xa0000, 0xbffff, 0, 0, read8_delegate(FUNC(s3virge_vga_device::mem_r),m_vga), write8_delegate(FUNC(s3virge_vga_device::mem_w),m_vga)); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void isa16_s3virgedx_device::device_reset() +{ +} + + +/* + * Diamond Stealth 3D 2000 Pro + */ + +static MACHINE_CONFIG_FRAGMENT( vga_stealth3d2kpro ) + MCFG_SCREEN_ADD("screen", RASTER) + MCFG_SCREEN_RAW_PARAMS(XTAL_25_1748MHz,900,0,640,526,0,480) + MCFG_SCREEN_UPDATE_DEVICE("vga", s3virgedx_rev1_vga_device, screen_update) + + MCFG_PALETTE_ADD("palette", 0x100) + + MCFG_DEVICE_ADD("vga", S3VIRGEDX1, 0) +MACHINE_CONFIG_END + +ROM_START( stealth3d2kpro ) + ROM_REGION(0x8000,"stealth3d", 0) + ROM_LOAD("virgedxdiamond.bin", 0x00000, 0x8000, CRC(58b0dcda) SHA1(b13ae6b04db6fc05a76d924ddf2efe150b823029) ) +ROM_END + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type ISA16_DMS3D2KPRO = &device_creator; + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor isa16_stealth3d2kpro_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( vga_stealth3d2kpro ); +} + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *isa16_stealth3d2kpro_device::device_rom_region() const +{ + return ROM_NAME( stealth3d2kpro ); +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// isa16_vga_device - constructor +//------------------------------------------------- + +isa16_stealth3d2kpro_device::isa16_stealth3d2kpro_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, ISA16_DMS3D2KPRO, "Diamond Stealth 3D 2000 Pro", tag, owner, clock, "dms3d2kp", __FILE__), + device_isa16_card_interface(mconfig, *this) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- +READ8_MEMBER(isa16_stealth3d2kpro_device::input_port_0_r ) { return 0xff; } //return space.machine().root_device().ioport("IN0")->read(); } + +void isa16_stealth3d2kpro_device::device_start() +{ + set_isa_device(); + + m_vga = subdevice("vga"); + + m_isa->install_rom(this, 0xc0000, 0xc7fff, 0, 0, "svga", "stealth3d"); + + m_isa->install_device(0x03b0, 0x03bf, 0, 0, read8_delegate(FUNC(s3virge_vga_device::port_03b0_r),m_vga), write8_delegate(FUNC(s3virge_vga_device::port_03b0_w),m_vga)); + m_isa->install_device(0x03c0, 0x03cf, 0, 0, read8_delegate(FUNC(s3virge_vga_device::port_03c0_r),m_vga), write8_delegate(FUNC(s3virge_vga_device::port_03c0_w),m_vga)); + m_isa->install_device(0x03d0, 0x03df, 0, 0, read8_delegate(FUNC(s3virge_vga_device::port_03d0_r),m_vga), write8_delegate(FUNC(s3virge_vga_device::port_03d0_w),m_vga)); + + m_isa->install_memory(0xa0000, 0xbffff, 0, 0, read8_delegate(FUNC(s3virge_vga_device::mem_r),m_vga), write8_delegate(FUNC(s3virge_vga_device::mem_w),m_vga)); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void isa16_stealth3d2kpro_device::device_reset() +{ +} diff --git a/src/devices/bus/isa/svga_s3.h b/src/devices/bus/isa/svga_s3.h new file mode 100644 index 00000000000..5e62d941fa3 --- /dev/null +++ b/src/devices/bus/isa/svga_s3.h @@ -0,0 +1,111 @@ +// license:BSD-3-Clause +// copyright-holders:Barry Rodewald +#pragma once + +#ifndef __ISA_SVGA_S3_H__ +#define __ISA_SVGA_S3_H__ + +#include "emu.h" +#include "isa.h" +#include "video/pc_vga.h" +#include "s3virge.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> isa16_vga_device + +class isa16_svga_s3_device : + public device_t, + public device_isa16_card_interface +{ +public: + // construction/destruction + isa16_svga_s3_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual const rom_entry *device_rom_region() const; + + DECLARE_READ8_MEMBER(input_port_0_r); +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); +private: + s3_vga_device *m_vga; + ibm8514a_device *m_8514; +}; + +class isa16_s3virge_device : + public device_t, + public device_isa16_card_interface +{ +public: + // construction/destruction + isa16_s3virge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual const rom_entry *device_rom_region() const; + + DECLARE_READ8_MEMBER(input_port_0_r); +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); +private: + s3virge_vga_device *m_vga; +}; + +class isa16_s3virgedx_device : + public device_t, + public device_isa16_card_interface +{ +public: + // construction/destruction + isa16_s3virgedx_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual const rom_entry *device_rom_region() const; + + DECLARE_READ8_MEMBER(input_port_0_r); +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); +private: + s3virgedx_vga_device *m_vga; +}; + +class isa16_stealth3d2kpro_device : + public device_t, + public device_isa16_card_interface +{ +public: + // construction/destruction + isa16_stealth3d2kpro_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual const rom_entry *device_rom_region() const; + + DECLARE_READ8_MEMBER(input_port_0_r); +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); +private: + s3virgedx_vga_device *m_vga; +}; + + +// device type definition +extern const device_type ISA16_SVGA_S3; +extern const device_type ISA16_S3VIRGE; +extern const device_type ISA16_S3VIRGEDX; +extern const device_type ISA16_DMS3D2KPRO; + +#endif /* __ISA_VGA_H__ */ diff --git a/src/devices/bus/isa/svga_trident.c b/src/devices/bus/isa/svga_trident.c new file mode 100644 index 00000000000..affbf97a6a5 --- /dev/null +++ b/src/devices/bus/isa/svga_trident.c @@ -0,0 +1,107 @@ +// license:BSD-3-Clause +// copyright-holders:Barry Rodewald +/* + * svga_trident.c + * + * Created on: 6/09/2014 + */ + +#include "emu.h" +#include "svga_trident.h" +#include "video/pc_vga.h" + + +ROM_START( tgui9680 ) + ROM_REGION( 0x8000, "tgui9680", 0 ) + ROM_LOAD16_BYTE( "trident_tgui9680_bios.bin", 0x0000, 0x4000, CRC(1eebde64) SHA1(67896a854d43a575037613b3506aea6dae5d6a19) ) + ROM_CONTINUE( 0x0001, 0x4000 ) +ROM_END + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type ISA16_SVGA_TGUI9680 = &device_creator; + + +static MACHINE_CONFIG_FRAGMENT( vga_trident ) + MCFG_SCREEN_ADD("screen", RASTER) + MCFG_SCREEN_RAW_PARAMS(XTAL_25_1748MHz,900,0,640,526,0,480) + MCFG_SCREEN_UPDATE_DEVICE("vga", trident_vga_device, screen_update) + + MCFG_PALETTE_ADD("palette", 0x100) + + MCFG_DEVICE_ADD("vga", TRIDENT_VGA, 0) +MACHINE_CONFIG_END + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor isa16_svga_tgui9680_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( vga_trident ); +} + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *isa16_svga_tgui9680_device::device_rom_region() const +{ + return ROM_NAME( tgui9680 ); +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// isa8_vga_device - constructor +//------------------------------------------------- + +isa16_svga_tgui9680_device::isa16_svga_tgui9680_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, ISA16_SVGA_TGUI9680, "Trident TGUI9680 Graphics Card (BIOS X5.5 (02) 02/13/96)", tag, owner, clock, "tgui9680", __FILE__), + device_isa16_card_interface(mconfig, *this) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- +READ8_MEMBER(isa16_svga_tgui9680_device::input_port_0_r ) { return 0xff; } //return space.machine().root_device().ioport("IN0")->read(); } + +void isa16_svga_tgui9680_device::device_start() +{ + set_isa_device(); + + m_vga = subdevice("vga"); + + m_isa->install_rom(this, 0xc0000, 0xc7fff, 0, 0, "tgui9680", "tgui9680"); + + m_isa->install_device(0x3b0, 0x3bf, 0, 0, read8_delegate(FUNC(trident_vga_device::port_03b0_r),m_vga), write8_delegate(FUNC(trident_vga_device::port_03b0_w),m_vga)); + m_isa->install_device(0x3c0, 0x3cf, 0, 0, read8_delegate(FUNC(trident_vga_device::port_03c0_r),m_vga), write8_delegate(FUNC(trident_vga_device::port_03c0_w),m_vga)); + m_isa->install_device(0x3d0, 0x3df, 0, 0, read8_delegate(FUNC(trident_vga_device::port_03d0_r),m_vga), write8_delegate(FUNC(trident_vga_device::port_03d0_w),m_vga)); + m_isa->install_device(0x43c4, 0x43cb, 0, 0, read8_delegate(FUNC(trident_vga_device::port_43c6_r),m_vga), write8_delegate(FUNC(trident_vga_device::port_43c6_w),m_vga)); + m_isa->install_device(0x83c4, 0x83cb, 0, 0, read8_delegate(FUNC(trident_vga_device::port_83c6_r),m_vga), write8_delegate(FUNC(trident_vga_device::port_83c6_w),m_vga)); + + m_isa->install_memory(0xa0000, 0xbffff, 0, 0, read8_delegate(FUNC(trident_vga_device::mem_r),m_vga), write8_delegate(FUNC(trident_vga_device::mem_w),m_vga)); + + // uncomment to test Windows 3.1 TGUI9440AGi driver +// m_isa->install_memory(0x4400000, 0x45fffff, 0, 0, read8_delegate(FUNC(trident_vga_device::vram_r),m_vga), write8_delegate(FUNC(trident_vga_device::vram_w),m_vga)); + + // win95 drivers +// m_isa->install_memory(0x4000000, 0x41fffff, 0, 0, read8_delegate(FUNC(trident_vga_device::vram_r),m_vga), write8_delegate(FUNC(trident_vga_device::vram_w),m_vga)); + + // acceleration ports + m_isa->install_device(0x2120, 0x21ff, 0, 0, read8_delegate(FUNC(trident_vga_device::accel_r),m_vga), write8_delegate(FUNC(trident_vga_device::accel_w),m_vga)); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void isa16_svga_tgui9680_device::device_reset() +{ +} diff --git a/src/devices/bus/isa/svga_trident.h b/src/devices/bus/isa/svga_trident.h new file mode 100644 index 00000000000..d5dde48d531 --- /dev/null +++ b/src/devices/bus/isa/svga_trident.h @@ -0,0 +1,49 @@ +// license:BSD-3-Clause +// copyright-holders:Barry Rodewald +/* + * svga_trident.h + * + * Created on: 6/09/2014 + */ + +#ifndef SVGA_TRIDENT_H_ +#define SVGA_TRIDENT_H_ + +#include "emu.h" +#include "isa.h" +#include "video/pc_vga.h" +#include "bus/isa/trident.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> isa16_vga_device + +class isa16_svga_tgui9680_device : + public device_t, + public device_isa16_card_interface +{ +public: + // construction/destruction + isa16_svga_tgui9680_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual const rom_entry *device_rom_region() const; + + DECLARE_READ8_MEMBER(input_port_0_r); +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); +private: + trident_vga_device *m_vga; +}; + + +// device type definition +extern const device_type ISA16_SVGA_TGUI9680; + + +#endif /* SVGA_TRIDENT_H_ */ diff --git a/src/devices/bus/isa/svga_tseng.c b/src/devices/bus/isa/svga_tseng.c new file mode 100644 index 00000000000..d1be1f4ec9b --- /dev/null +++ b/src/devices/bus/isa/svga_tseng.c @@ -0,0 +1,94 @@ +// license:BSD-3-Clause +// copyright-holders:Barry Rodewald +/*************************************************************************** + + ISA SVGA Tseng wrapper + +***************************************************************************/ + +#include "emu.h" +#include "svga_tseng.h" +#include "video/pc_vga.h" + +ROM_START( et4000 ) + ROM_REGION(0x8000,"et4000", 0) + ROM_LOAD("et4000.bin", 0x00000, 0x8000, CRC(f1e817a8) SHA1(945d405b0fb4b8f26830d495881f8587d90e5ef9) ) +ROM_END + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type ISA8_SVGA_ET4K = &device_creator; + + +static MACHINE_CONFIG_FRAGMENT( vga_tseng ) + MCFG_SCREEN_ADD("screen", RASTER) + MCFG_SCREEN_RAW_PARAMS(XTAL_25_1748MHz,900,0,640,526,0,480) + MCFG_SCREEN_UPDATE_DEVICE("vga", tseng_vga_device, screen_update) + + MCFG_PALETTE_ADD("palette", 0x100) + + MCFG_DEVICE_ADD("vga", TSENG_VGA, 0) +MACHINE_CONFIG_END + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor isa8_svga_et4k_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( vga_tseng ); +} + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *isa8_svga_et4k_device::device_rom_region() const +{ + return ROM_NAME( et4000 ); +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// isa8_vga_device - constructor +//------------------------------------------------- + +isa8_svga_et4k_device::isa8_svga_et4k_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, ISA8_SVGA_ET4K, "SVGA Tseng ET4000 Graphics Card", tag, owner, clock, "et4000", __FILE__), + device_isa8_card_interface(mconfig, *this) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- +READ8_MEMBER(isa8_svga_et4k_device::input_port_0_r ) { return 0xff; } //return space.machine().root_device().ioport("IN0")->read(); } + +void isa8_svga_et4k_device::device_start() +{ + set_isa_device(); + + m_vga = subdevice("vga"); + + m_isa->install_rom(this, 0xc0000, 0xc7fff, 0, 0, "et4000", "et4000"); + + m_isa->install_device(0x3b0, 0x3bf, 0, 0, read8_delegate(FUNC(tseng_vga_device::port_03b0_r),m_vga), write8_delegate(FUNC(tseng_vga_device::port_03b0_w),m_vga)); + m_isa->install_device(0x3c0, 0x3cf, 0, 0, read8_delegate(FUNC(tseng_vga_device::port_03c0_r),m_vga), write8_delegate(FUNC(tseng_vga_device::port_03c0_w),m_vga)); + m_isa->install_device(0x3d0, 0x3df, 0, 0, read8_delegate(FUNC(tseng_vga_device::port_03d0_r),m_vga), write8_delegate(FUNC(tseng_vga_device::port_03d0_w),m_vga)); + + m_isa->install_memory(0xa0000, 0xbffff, 0, 0, read8_delegate(FUNC(tseng_vga_device::mem_r),m_vga), write8_delegate(FUNC(tseng_vga_device::mem_w),m_vga)); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void isa8_svga_et4k_device::device_reset() +{ +} diff --git a/src/devices/bus/isa/svga_tseng.h b/src/devices/bus/isa/svga_tseng.h new file mode 100644 index 00000000000..23700089f0e --- /dev/null +++ b/src/devices/bus/isa/svga_tseng.h @@ -0,0 +1,43 @@ +// license:BSD-3-Clause +// copyright-holders:Barry Rodewald +#pragma once + +#ifndef __ISA_SVGA_ET4K_H__ +#define __ISA_SVGA_ET4K_H__ + +#include "emu.h" +#include "isa.h" +#include "video/pc_vga.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> isa8_vga_device + +class isa8_svga_et4k_device : + public device_t, + public device_isa8_card_interface +{ +public: + // construction/destruction + isa8_svga_et4k_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual const rom_entry *device_rom_region() const; + + DECLARE_READ8_MEMBER(input_port_0_r); +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); +private: + tseng_vga_device *m_vga; +}; + + +// device type definition +extern const device_type ISA8_SVGA_ET4K; + +#endif /* __ISA_SVGA_ET4K_H__ */ diff --git a/src/devices/bus/isa/trident.c b/src/devices/bus/isa/trident.c new file mode 100644 index 00000000000..03f646139be --- /dev/null +++ b/src/devices/bus/isa/trident.c @@ -0,0 +1,1612 @@ +// license:BSD-3-Clause +// copyright-holders:Barry Rodewald +/* + * trident.c + * + * Implementation of Trident VGA GUI accelerators + * + * + */ + +#include "emu.h" +#include "trident.h" +#include "debugger.h" + +const device_type TRIDENT_VGA = &device_creator; + +#define CRTC_PORT_ADDR ((vga.miscellaneous_output&1)?0x3d0:0x3b0) + +#define LOG (1) +#define LOG_ACCEL (1) + +trident_vga_device::trident_vga_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : svga_device(mconfig, TRIDENT_VGA, "Trident TGUI9680", tag, owner, clock, "trident_vga", __FILE__) +{ +} + +UINT8 trident_vga_device::READPIXEL8(INT16 x, INT16 y) +{ + return (vga.memory[((y & 0xfff)*offset() + (x & 0xfff)) % vga.svga_intf.vram_size]); +} + +UINT16 trident_vga_device::READPIXEL15(INT16 x, INT16 y) +{ + return (vga.memory[((y & 0xfff)*offset() + (x & 0xfff)*2) % vga.svga_intf.vram_size] | + (vga.memory[((y & 0xfff)*offset() + ((x & 0xfff)*2)+1) % vga.svga_intf.vram_size] << 8)); +} + +UINT16 trident_vga_device::READPIXEL16(INT16 x, INT16 y) +{ + return (vga.memory[((y & 0xfff)*offset() + (x & 0xfff)*2) % vga.svga_intf.vram_size] | + (vga.memory[((y & 0xfff)*offset() + ((x & 0xfff)*2)+1) % vga.svga_intf.vram_size] << 8)); +} + +UINT32 trident_vga_device::READPIXEL32(INT16 x, INT16 y) +{ + return (vga.memory[((y & 0xfff)*offset() + (x & 0xfff)*4) % vga.svga_intf.vram_size] | + (vga.memory[((y & 0xfff)*offset() + ((x & 0xfff)*4)+1) % vga.svga_intf.vram_size] << 8) | + (vga.memory[((y & 0xfff)*offset() + ((x & 0xfff)*4)+2) % vga.svga_intf.vram_size] << 16) | + (vga.memory[((y & 0xfff)*offset() + ((x & 0xfff)*4)+3) % vga.svga_intf.vram_size] << 24)); +} + +void trident_vga_device::WRITEPIXEL8(INT16 x, INT16 y, UINT8 data) +{ + if((x & 0xfff)> 8; + } +} + +void trident_vga_device::WRITEPIXEL16(INT16 x, INT16 y, UINT16 data) +{ + if((x & 0xfff)> 8; + } +} + +void trident_vga_device::WRITEPIXEL32(INT16 x, INT16 y, UINT32 data) +{ + if((x & 0xfff)> 8; + vga.memory[((y & 0xfff)*offset() + ((x & 0xfff)*4)+2) % vga.svga_intf.vram_size] = (data & 0x00ff0000) >> 16; + vga.memory[((y & 0xfff)*offset() + ((x & 0xfff)*4)+3) % vga.svga_intf.vram_size] = (data & 0xff000000) >> 24; + } +} + +UINT32 trident_vga_device::handle_rop(UINT32 src, UINT32 dst) +{ + switch(tri.accel_fmix) // TODO: better understand this register + { + case 0xf0: // PAT + case 0xcc: // SRC + break; // pass data through + case 0x00: // 0 + src = 0; + break; + case 0xff: // 1 + src = 0xffffffff; + break; + case 0x66: // XOR + case 0x5a: // XOR PAT + src = dst ^ src; + break; + case 0xb8: // PAT xor (SRC and (DST xor PAT)) (correct?) + src = src & (dst ^ src); + break; + } + return src; +} + +UINT32 trident_vga_device::READPIXEL(INT16 x,INT16 y) +{ + if(svga.rgb8_en) + return READPIXEL8(x,y) & 0xff; + if(svga.rgb15_en) + return READPIXEL15(x,y) & 0x7fff; + if(svga.rgb16_en) + return READPIXEL16(x,y) & 0xffff; + if(svga.rgb32_en) + return READPIXEL32(x,y); + return 0; // should never reach here +} + +void trident_vga_device::WRITEPIXEL(INT16 x,INT16 y, UINT32 data) +{ + if(svga.rgb8_en) + WRITEPIXEL8(x,y,(((data >> 8) & 0xff) | (data & 0xff))); // XFree86 3.3 sets bits 0-7 to 0 when using mono patterns, does it OR each byte? + if(svga.rgb15_en) + WRITEPIXEL15(x,y,data & 0x7fff); + if(svga.rgb16_en) + WRITEPIXEL16(x,y,data & 0xffff); + if(svga.rgb32_en) + WRITEPIXEL32(x,y,data); +} + + +void trident_vga_device::device_start() +{ + zero(); + + int i; + for (i = 0; i < 0x100; i++) + m_palette->set_pen_color(i, 0, 0, 0); + + // Avoid an infinite loop when displaying. 0 is not possible anyway. + vga.crtc.maximum_scan_line = 1; + + + // copy over interfaces + vga.read_dipswitch = read8_delegate(); //read_dipswitch; + vga.svga_intf.vram_size = 0x200000; + + vga.memory.resize(vga.svga_intf.vram_size); + memset(&vga.memory[0], 0, vga.svga_intf.vram_size); + save_item(NAME(vga.memory)); + save_pointer(vga.crtc.data,"CRTC Registers",0x100); + save_pointer(vga.sequencer.data,"Sequencer Registers",0x100); + save_pointer(vga.attribute.data,"Attribute Registers", 0x15); + save_pointer(tri.accel_pattern,"Pattern Data", 0x80); + save_pointer(tri.lutdac_reg,"LUTDAC registers", 0x100); + + m_vblank_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(vga_device::vblank_timer_cb),this)); + vga.svga_intf.seq_regcount = 0x0f; + vga.svga_intf.crtc_regcount = 0x60; + memset(&tri, 0, sizeof(tri)); +} + +void trident_vga_device::device_reset() +{ + svga_device::device_reset(); + svga.id = 0xd3; // 0xd3 identifies at TGUI9660XGi (set to 0xe3 to identify at TGUI9440AGi) + tri.revision = 0x01; // revision identifies as TGUI9680 + tri.new_mode = false; // start up in old mode + tri.dac_active = false; + tri.linear_active = false; + tri.mmio_active = false; + tri.sr0f = 0x6f; + tri.sr0c = 0x70; + tri.cr2a = 0x03; // set ISA interface? + tri.mem_clock = 0x2c6; // 50MHz default + tri.vid_clock = 0; + tri.port_3c3 = true; + tri.accel_busy = false; + tri.accel_memwrite_active = false; + // Windows 3.1 TGUI9440AGi drivers do not set the pointer colour registers? + tri.cursor_bg = 0x00000000; + tri.cursor_fg = 0xffffffff; +} + +UINT32 trident_vga_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + UINT8 cur_mode = 0; + + svga_device::screen_update(screen,bitmap,cliprect); + cur_mode = pc_vga_choosevideomode(); + + // draw hardware graphics cursor + if(tri.cursor_ctrl & 0x80) // if cursor is enabled + { + UINT32 src; + UINT32* dst; + UINT8 val; + int x,y; + UINT16 cx = tri.cursor_x & 0x0fff; + UINT16 cy = tri.cursor_y & 0x0fff; + UINT32 bg_col; + UINT32 fg_col; + UINT8 cursor_size = (tri.cursor_ctrl & 0x01) ? 64 : 32; + + if(cur_mode == SCREEN_OFF || cur_mode == TEXT_MODE || cur_mode == MONO_MODE || cur_mode == CGA_MODE || cur_mode == EGA_MODE) + return 0; // cursor only works in VGA or SVGA modes + + src = tri.cursor_loc * 1024; // start address is in units of 1024 bytes + + if(cur_mode == RGB16_MODE) + { + bg_col = tri.cursor_bg; + fg_col = tri.cursor_fg; + } + else /* TODO: other modes */ + { + bg_col = m_palette->pen(tri.cursor_bg & 0xff); + fg_col = m_palette->pen(tri.cursor_fg & 0xff); + } + + for(y=0;y> 7; + k = (tri.vid_clock & 0x1000) >> 12; + freq = ((double)(m+8) / (double)((n+2)*(pow(2.0,k)))) * 14.31818; // there is a 14.31818MHz clock on the board + + return freq * 1000000; +} + +void trident_vga_device::trident_define_video_mode() +{ + int divisor = 1; + int xtal; + + /* // clock select for TGUI9440CXi and earlier + switch(tri.clock) + { + case 0: + default: xtal = XTAL_25_1748MHz; break; + case 1: xtal = XTAL_28_63636MHz; break; + case 2: xtal = 44900000; break; + case 3: xtal = 36000000; break; + case 4: xtal = 57272000; break; + case 5: xtal = 65000000; break; + case 6: xtal = 50350000; break; + case 7: xtal = 40000000; break; + case 8: xtal = 88000000; break; + case 9: xtal = 98000000; break; + case 10: xtal = 118800000; break; + case 11: xtal = 108000000; break; + case 12: xtal = 72000000; break; + case 13: xtal = 77000000; break; + case 14: xtal = 80000000; break; + case 15: xtal = 75000000; break; + } + + switch((tri.sr0d_new & 0x06) >> 1) + { + case 0: + default: break; // no division + case 1: xtal = xtal / 2; break; + case 2: xtal = xtal / 4; break; + case 3: xtal = xtal / 1.5; break; + }*/ + + + // TGUI9440AGi/9660/9680/9682 programmable clock + switch((vga.miscellaneous_output & 0x0c) >> 2) + { + case 0: + default: xtal = XTAL_25_1748MHz; break; + case 1: xtal = XTAL_28_63636MHz; break; + case 2: xtal = calculate_clock(); break; + } + + if(tri.gc0f & 0x08) // 16 pixels per character clock + xtal = xtal / 2; + + if(tri.port_3db & 0x20) + xtal = xtal / 2; // correct? + + svga.rgb8_en = svga.rgb15_en = svga.rgb16_en = svga.rgb32_en = 0; + switch((tri.pixel_depth & 0x0c) >> 2) + { + case 0: + default: if(!(tri.pixel_depth & 0x10)) svga.rgb8_en = 1; break; + case 1: if((tri.dac & 0xf0) == 0x30) svga.rgb16_en = 1; else svga.rgb15_en = 1; break; + case 2: svga.rgb32_en = 1; break; + } + + recompute_params_clock(divisor, xtal); +} + +UINT8 trident_vga_device::trident_seq_reg_read(UINT8 index) +{ + UINT8 res; + + res = 0xff; + + if(index <= 0x04) + res = vga.sequencer.data[index]; + else + { + switch(index) + { + case 0x09: + res = tri.revision; + break; + case 0x0b: + res = svga.id; + tri.new_mode = true; + break; + case 0x0c: // Power Up Mode register 1 + res = tri.sr0c & 0xef; + if(tri.port_3c3) + res |= 0x10; + break; + case 0x0d: // Mode Control 2 + //res = svga.rgb15_en; + if(tri.new_mode) + res = tri.sr0d_new; + else + res = tri.sr0d_old; + break; + case 0x0e: // Mode Control 1 + if(tri.new_mode) + res = tri.sr0e_new; + else + res = tri.sr0e_old; + break; + case 0x0f: // Power Up Mode 2 + res = tri.sr0f; + break; + default: + res = vga.sequencer.data[index]; + if(!LOG) logerror("Trident: Sequencer index %02x read\n",index); + } + } + if(LOG) logerror("Trident SR%02X: read %02x\n",index,res); + return res; +} + +void trident_vga_device::trident_seq_reg_write(UINT8 index, UINT8 data) +{ + vga.sequencer.data[vga.sequencer.index] = data; + if(index <= 0x04) + { + seq_reg_write(vga.sequencer.index,data); + recompute_params(); + } + else + { + if(LOG) logerror("Trident SR%02X: %s mode write %02x\n",index,tri.new_mode ? "new" : "old",data); + switch(index) + { + case 0x0b: + tri.new_mode = false; + break; + case 0x0c: // Power Up Mode register 1 + if(data & 0x10) + tri.port_3c3 = true; // 'post port at 0x3c3' + else + tri.port_3c3 = false; // 'post port at 0x46e8' + tri.sr0c = data; + break; + case 0x0d: // Mode Control 2 + if(tri.new_mode) + { + tri.sr0d_new = data; + tri.clock = ((vga.miscellaneous_output & 0x0c) >> 2) | ((data & 0x01) << 2) | ((data & 0x40) >> 3); + trident_define_video_mode(); + } + else + tri.sr0d_old = data; + break; + case 0x0e: // Mode Control 1 + if(tri.new_mode) + { + tri.sr0e_new = data ^ 0x02; + svga.bank_w = (data & 0x3f) ^ 0x02; // bit 1 is inverted, used for card detection, it is not XORed on reading + if(!(tri.gc0f & 0x01)) + svga.bank_r = (data & 0x3f) ^ 0x02; + // TODO: handle planar modes, where bits 0 and 2 only are used + } + else + { + tri.sr0e_old = data; + svga.bank_w = data & 0x0e; + if(!(tri.gc0f & 0x01)) + svga.bank_r = data & 0x0e; + } + break; + case 0x0f: // Power Up Mode 2 + tri.sr0f = data; + break; + default: + if(!LOG) logerror("Trident: Sequencer index %02x read\n",index); + } + } +} + +UINT8 trident_vga_device::trident_crtc_reg_read(UINT8 index) +{ + UINT8 res = 0; + + if(index <= 0x18) + res = crtc_reg_read(index); + else + { + switch(index) + { + case 0x1e: + res = tri.cr1e; + break; + case 0x1f: + res = tri.cr1f; + break; + case 0x20: + res = tri.cr20; + break; + case 0x21: + res = tri.cr21; + break; + case 0x24: + if(vga.attribute.state != 0) + res |= 0x80; + break; + case 0x26: + res = vga.attribute.index; + break; + case 0x27: + res = (vga.crtc.start_addr & 0x60000) >> 17; + break; + case 0x29: + res = tri.cr29; + break; + case 0x2a: + res = tri.cr2a; + break; + case 0x38: + res = tri.pixel_depth; + break; + case 0x39: + res = tri.cr39; + break; + case 0x40: + res = (tri.cursor_x & 0x00ff); + break; + case 0x41: + res = (tri.cursor_x & 0xff00) >> 8; + break; + case 0x42: + res = (tri.cursor_y & 0x00ff); + break; + case 0x43: + res = (tri.cursor_y & 0xff00) >> 8; + break; + case 0x44: + res = (tri.cursor_loc & 0x00ff); + break; + case 0x45: + res = (tri.cursor_loc & 0xff00) >> 8; + break; + case 0x46: + res = tri.cursor_x_off; + break; + case 0x47: + res = tri.cursor_y_off; + break; + case 0x48: + res = (tri.cursor_fg & 0x000000ff); + break; + case 0x49: + res = (tri.cursor_fg & 0x0000ff00) >> 8; + break; + case 0x4a: + res = (tri.cursor_fg & 0x00ff0000) >> 16; + break; + case 0x4b: + res = (tri.cursor_fg & 0xff000000) >> 24; + break; + case 0x4c: + res = (tri.cursor_bg & 0x000000ff); + break; + case 0x4d: + res = (tri.cursor_bg & 0x0000ff00) >> 8; + break; + case 0x4e: + res = (tri.cursor_bg & 0x00ff0000) >> 16; + break; + case 0x4f: + res = (tri.cursor_bg & 0xff000000) >> 24; + break; + case 0x50: + res = tri.cursor_ctrl; + break; + default: + res = vga.crtc.data[index]; + if(!LOG) logerror("Trident: CRTC index %02x read\n",index); + break; + } + } + if(LOG) logerror("Trident CR%02X: read %02x\n",index,res); + return res; +} +void trident_vga_device::trident_crtc_reg_write(UINT8 index, UINT8 data) +{ + if(index <= 0x18) + { + crtc_reg_write(index,data); + trident_define_video_mode(); + } + else + { + if(LOG) logerror("Trident CR%02X: write %02x\n",index,data); + switch(index) + { + case 0x1e: // Module Testing Register + tri.cr1e = data; + vga.crtc.start_addr = (vga.crtc.start_addr & 0xfffeffff) | ((data & 0x20)<<11); + break; + case 0x1f: + tri.cr1f = data; // "Software Programming Register" written to by the BIOS + break; + case 0x20: // FIFO Control (old MMIO enable? no documentation of this register) + tri.cr20 = data; + break; + case 0x21: // Linear aperture + tri.cr21 = data; + tri.linear_address = ((data & 0xc0)<<18) | ((data & 0x0f)<<20); + tri.linear_active = data & 0x20; + if(tri.linear_active) + popmessage("Trident: Linear Aperture active - %08x, %s",tri.linear_address,(tri.cr21 & 0x10) ? "2MB" : "1MB" ); + break; + case 0x27: + vga.crtc.start_addr = (vga.crtc.start_addr & 0xfff9ffff) | ((data & 0x03)<<17); + break; + case 0x29: + tri.cr29 = data; + vga.crtc.offset = (vga.crtc.offset & 0xfeff) | ((data & 0x10)<<4); + break; + case 0x2a: + tri.cr2a = data; + break; + case 0x38: + // bit 0: 16 bit bus + // bits 2-3: pixel depth (1=15/16bit, 2=24/32bit, 0=anything else) + // bit 5: packed mode + tri.pixel_depth = data; + trident_define_video_mode(); + break; + case 0x39: + tri.cr39 = data; + tri.mmio_active = data & 0x01; + if(tri.mmio_active) + popmessage("Trident: MMIO activated"); + break; + case 0x40: + tri.cursor_x = (tri.cursor_x & 0xff00) | data; + break; + case 0x41: + tri.cursor_x = (tri.cursor_x & 0x00ff) | (data << 8); + break; + case 0x42: + tri.cursor_y = (tri.cursor_y & 0xff00) | data; + break; + case 0x43: + tri.cursor_y = (tri.cursor_y & 0x00ff) | (data << 8); + break; + case 0x44: + tri.cursor_loc = (tri.cursor_loc & 0xff00) | data; + break; + case 0x45: + tri.cursor_loc = (tri.cursor_loc & 0x00ff) | (data << 8); + break; + case 0x46: + tri.cursor_x_off = data; + break; + case 0x47: + tri.cursor_y_off = data; + break; + case 0x48: + tri.cursor_fg = (tri.cursor_fg & 0xffffff00) | data; + break; + case 0x49: + tri.cursor_fg = (tri.cursor_fg & 0xffff00ff) | (data << 8); + break; + case 0x4a: + tri.cursor_fg = (tri.cursor_fg & 0xff00ffff) | (data << 16); + break; + case 0x4b: + tri.cursor_fg = (tri.cursor_fg & 0x00ffffff) | (data << 24); + break; + case 0x4c: + tri.cursor_bg = (tri.cursor_bg & 0xffffff00) | data; + break; + case 0x4d: + tri.cursor_bg = (tri.cursor_bg & 0xffff00ff) | (data << 8); + break; + case 0x4e: + tri.cursor_bg = (tri.cursor_bg & 0xff00ffff) | (data << 16); + break; + case 0x4f: + tri.cursor_bg = (tri.cursor_bg & 0x00ffffff) | (data << 24); + break; + case 0x50: + tri.cursor_ctrl = data; + break; + default: + if(!LOG) logerror("Trident: 3D4 index %02x write %02x\n",index,data); + break; + } + } +} + +UINT8 trident_vga_device::trident_gc_reg_read(UINT8 index) +{ + UINT8 res; + + if(index <= 0x0d) + res = gc_reg_read(index); + else + { + switch(index) + { + case 0x0e: + res = tri.gc0e; + break; + case 0x0f: + res = tri.gc0f; + break; + case 0x2f: + res = tri.gc2f; + break; + default: + res = 0xff; + if(!LOG) logerror("Trident: Sequencer index %02x read\n",index); + break; + } + } + if(LOG) logerror("Trident GC%02X: read %02x\n",index,res); + return res; +} + +void trident_vga_device::trident_gc_reg_write(UINT8 index, UINT8 data) +{ + if(index <= 0x0d) + gc_reg_write(index,data); + else + { + if(LOG) logerror("Trident GC%02X: write %02x\n",index,data); + switch(index) + { + case 0x0e: // New Source Address Register (bit 1 is inverted here, also) + tri.gc0e = data ^ 0x02; + if(!(tri.gc0f & 0x04)) // if bank regs at 0x3d8/9 are not enabled + { + if(tri.gc0f & 0x01) // if bank regs are separated + svga.bank_r = (data & 0x1f) ^ 0x02; + } + break; + case 0x0f: + tri.gc0f = data; + trident_define_video_mode(); + break; + case 0x2f: // XFree86 refers to this register as "MiscIntContReg", setting bit 2, but gives no indication as to what it does + tri.gc2f = data; + break; + default: + if(!LOG) logerror("Trident: Unimplemented GC register %02x write %02x\n",index,data); + break; + } + } +} + +READ8_MEMBER(trident_vga_device::port_03c0_r) +{ + UINT8 res; + + switch(offset) + { + case 0x05: + res = trident_seq_reg_read(vga.sequencer.index); + break; + case 0x06: + tri.dac_count++; + if(tri.dac_count > 3) + tri.dac_active = true; + if(tri.dac_active) + res = tri.dac; + else + res = vga_device::port_03c0_r(space,offset,mem_mask); + break; + case 0x07: + case 0x08: + case 0x09: + tri.dac_active = false; + tri.dac_count = 0; + res = vga_device::port_03c0_r(space,offset,mem_mask); + break; + case 0x0f: + res = trident_gc_reg_read(vga.gc.index); + break; + default: + res = vga_device::port_03c0_r(space,offset,mem_mask); + break; + } + + return res; +} + +WRITE8_MEMBER(trident_vga_device::port_03c0_w) +{ + switch(offset) + { + case 0x05: + trident_seq_reg_write(vga.sequencer.index,data); + break; + case 0x06: + if(tri.dac_active) + { + tri.dac = data; // DAC command register + tri.dac_active = false; + tri.dac_count = 0; + trident_define_video_mode(); + } + else + vga_device::port_03c0_w(space,offset,data,mem_mask); + break; + case 0x07: + case 0x08: + case 0x09: + tri.dac_active = false; + tri.dac_count = 0; + vga_device::port_03c0_w(space,offset,data,mem_mask); + break; + case 0x0f: + trident_gc_reg_write(vga.gc.index,data); + break; + default: + vga_device::port_03c0_w(space,offset,data,mem_mask); + break; + } +} + + +READ8_MEMBER(trident_vga_device::port_03d0_r) +{ + UINT8 res = 0xff; + + if (CRTC_PORT_ADDR == 0x3d0) + { + switch(offset) + { + case 5: + res = trident_crtc_reg_read(vga.crtc.index); + break; + case 8: + if(tri.gc0f & 0x04) // if enabled + { + res = svga.bank_w & 0x3f; + } + else + res = 0xff; + break; + case 9: + if(tri.gc0f & 0x04) // if enabled + if(tri.gc0f & 0x01) // and if bank regs are separated + res = svga.bank_r & 0x3f; + else + res = 0xff; + else + res = 0xff; + break; + case 11: + res = tri.port_3db; + break; + default: + res = vga_device::port_03d0_r(space,offset,mem_mask); + break; + } + } + + return res; +} + +WRITE8_MEMBER(trident_vga_device::port_03d0_w) +{ + if (CRTC_PORT_ADDR == 0x3d0) + { + switch(offset) + { + case 5: + vga.crtc.data[vga.crtc.index] = data; + trident_crtc_reg_write(vga.crtc.index,data); + break; + case 8: + if(tri.gc0f & 0x04) // if enabled + { + svga.bank_w = data & 0x3f; + if(LOG) logerror("Trident: Write Bank set to %02x\n",data); + if(!(tri.gc0f & 0x01)) // if bank regs are not separated + { + svga.bank_r = data & 0x3f; // then this is also the read bank register + if(LOG) logerror("Trident: Read Bank set to %02x\n",data); + } + } + break; + case 9: + if(tri.gc0f & 0x04) // if enabled + { + if(tri.gc0f & 0x01) // and if bank regs are separated + { + svga.bank_r = data & 0x3f; + if(LOG) logerror("Trident: Read Bank set to %02x\n",data); + } + } + break; + case 11: + tri.port_3db = data; // no info on this port? Bit 5 appears to be a clock divider... + break; + default: + vga_device::port_03d0_w(space,offset,data,mem_mask); + break; + } + } +} + +READ8_MEMBER(trident_vga_device::port_43c6_r) +{ + UINT8 res = 0xff; + switch(offset) + { + case 2: + res = tri.mem_clock & 0xff; + break; + case 3: + res = tri.mem_clock >> 8; + break; + case 4: + res = tri.vid_clock & 0xff; + break; + case 5: + res = tri.vid_clock >> 8; + break; + } + return res; +} + +WRITE8_MEMBER(trident_vga_device::port_43c6_w) +{ + switch(offset) + { + case 2: + if(!(tri.sr0e_new & 0x02) && (tri.sr0e_new & 0x80)) + { + tri.mem_clock = (tri.mem_clock & 0xff00) | (data); + if(LOG) logerror("Trident: Memory clock write %04x\n",tri.mem_clock); + } + break; + case 3: + if(!(tri.sr0e_new & 0x02) && (tri.sr0e_new & 0x80)) + { + tri.mem_clock = (tri.mem_clock & 0x00ff) | (data << 8); + if(LOG) logerror("Trident: Memory clock write %04x\n",tri.mem_clock); + } + break; + case 4: + if(!(tri.sr0e_new & 0x02) && (tri.sr0e_new & 0x80)) + { + tri.vid_clock = (tri.vid_clock & 0xff00) | (data); + if(LOG) logerror("Trident: Video clock write %04x\n",tri.vid_clock); + } + break; + case 5: + if(!(tri.sr0e_new & 0x02) && (tri.sr0e_new & 0x80)) + { + tri.vid_clock = (tri.vid_clock & 0x00ff) | (data << 8); + if(LOG) logerror("Trident: Video clock write %04x\n",tri.vid_clock); + } + break; + } +} + +// Trident refers to these registers as a LUTDAC +// Not much else is known. XFree86 uses register 4 for something related to DPMS +READ8_MEMBER(trident_vga_device::port_83c6_r) +{ + UINT8 res = 0xff; + switch(offset) + { + case 2: + res = tri.lutdac_reg[tri.lutdac_index]; + if(LOG) logerror("Trident: LUTDAC reg read %02x\n",res); + break; + case 4: + res = tri.lutdac_index; + if(LOG) logerror("Trident: LUTDAC index read %02x\n",res); + break; + } + return res; +} + +WRITE8_MEMBER(trident_vga_device::port_83c6_w) +{ + switch(offset) + { + case 2: + if(LOG) logerror("Trident: LUTDAC reg write %02x\n",data); + tri.lutdac_reg[tri.lutdac_index] = data; + break; + case 4: + if(LOG) logerror("Trident: LUTDAC index write %02x\n",data); + tri.lutdac_index = data; + break; + } +} + +READ8_MEMBER(trident_vga_device::vram_r) +{ + if (tri.linear_active) + return vga.memory[offset % vga.svga_intf.vram_size]; + else + return 0xff; +} + +WRITE8_MEMBER(trident_vga_device::vram_w) +{ + if (tri.linear_active) + { + if(tri.accel_memwrite_active) + { + tri.accel_transfer = (tri.accel_transfer & (~(0x000000ff << (24-(8*(offset % 4)))))) | (data << (24-(8 * (offset % 4)))); + if(offset % 4 == 3) + accel_data_write(tri.accel_transfer); + return; + } + vga.memory[offset % vga.svga_intf.vram_size] = data; + } +} + +READ8_MEMBER(trident_vga_device::mem_r ) +{ + if((tri.cr20 & 0x10) && (offset >= 0x1ff00)) // correct for old MMIO? + { + return old_mmio_r(space,offset-0x1ff00); + } + + if (svga.rgb8_en || svga.rgb15_en || svga.rgb16_en || svga.rgb32_en) + { + int data; + + if(tri.new_mode) // 64k from 0xA0000-0xAFFFF + { + offset &= 0xffff; + data=vga.memory[(offset + (svga.bank_r*0x10000)) % vga.svga_intf.vram_size]; + } + else // 128k from 0xA0000-0xBFFFF + { + data=vga.memory[(offset + (svga.bank_r*0x10000)) % vga.svga_intf.vram_size]; + } + return data; + } + + return vga_device::mem_r(space,offset,mem_mask); +} + +WRITE8_MEMBER(trident_vga_device::mem_w) +{ + if((tri.cr20 & 0x10) && (offset >= 0x1ff00)) // correct for old MMIO? + { + old_mmio_w(space,offset-0x1ff00,data); + return; + } + + if(tri.accel_memwrite_active) + { + tri.accel_transfer = (tri.accel_transfer & (~(0x000000ff << (24-(8*(offset % 4)))))) | (data << (24-(8 * (offset % 4)))); + if(offset % 4 == 3) + accel_data_write(tri.accel_transfer); + return; + } + + if (svga.rgb8_en || svga.rgb15_en || svga.rgb16_en || svga.rgb32_en) + { + if(tri.new_mode) // 64k from 0xA0000-0xAFFFF + { + offset &= 0xffff; + vga.memory[(offset + (svga.bank_w*0x10000)) % vga.svga_intf.vram_size] = data; + } + else // 128k from 0xA0000-0xBFFFF + { + vga.memory[(offset + (svga.bank_w*0x10000)) % vga.svga_intf.vram_size] = data; + } + return; + } + + vga_device::mem_w(space,offset,data,mem_mask); +} + +// Old style MMIO (maps to 0xbff00) +void trident_vga_device::old_mmio_w(address_space& space, UINT32 offset, UINT8 data) +{ + if(offset >= 0x20) + accel_w(space,offset-0x20,data); +} + +UINT8 trident_vga_device::old_mmio_r(address_space& space, UINT32 offset) +{ + if(offset == 0x20) + { + if(tri.accel_busy) + return 0x20; + } + if(offset > 0x20) + return accel_r(space,offset-0x20); + else + return 0x00; +} + + +// 2D Acceleration functions (very WIP) + +// From XFree86 source: +/* +Graphics Engine for 9440/9660/9680 + +#define GER_STATUS 0x2120 +#define GE_BUSY 0x80 +#define GER_OPERMODE 0x2122 Byte for 9440, Word for 96xx +#define DST_ENABLE 0x200 // Destination Transparency +#define GER_COMMAND 0x2124 +#define GE_NOP 0x00 // No Operation +#define GE_BLT 0x01 // BitBLT ROP3 only +#define GE_BLT_ROP4 0x02 // BitBLT ROP4 (96xx only) +#define GE_SCANLINE 0x03 // Scan Line +#define GE_BRESLINE 0x04 // Bresenham Line +#define GE_SHVECTOR 0x05 // Short Vector +#define GE_FASTLINE 0x06 // Fast Line (96xx only) +#define GE_TRAPEZ 0x07 // Trapezoidal fill (96xx only) +#define GE_ELLIPSE 0x08 // Ellipse (96xx only) (RES) +#define GE_ELLIP_FILL 0x09 // Ellipse Fill (96xx only) (RES) +#define GER_FMIX 0x2127 +#define GER_DRAWFLAG 0x2128 // long +#define FASTMODE 1<<28 +#define STENCIL 0x8000 +#define SOLIDFILL 0x4000 +#define TRANS_ENABLE 0x1000 +#define TRANS_REVERSE 0x2000 +#define YMAJ 0x0400 +#define XNEG 0x0200 +#define YNEG 0x0100 +#define SRCMONO 0x0040 +#define PATMONO 0x0020 +#define SCR2SCR 0x0004 +#define PAT2SCR 0x0002 +#define GER_FCOLOUR 0x212C // Word for 9440, long for 96xx +#define GER_BCOLOUR 0x2130 // Word for 9440, long for 96xx +#define GER_PATLOC 0x2134 // Word +#define GER_DEST_XY 0x2138 +#define GER_DEST_X 0x2138 // Word +#define GER_DEST_Y 0x213A // Word +#define GER_SRC_XY 0x213C +#define GER_SRC_X 0x213C // Word +#define GER_SRC_Y 0x213E // Word +#define GER_DIM_XY 0x2140 +#define GER_DIM_X 0x2140 // Word +#define GER_DIM_Y 0x2142 // Word +#define GER_STYLE 0x2144 // Long +#define GER_CKEY 0x2168 // Long +#define GER_FPATCOL 0x2178 +#define GER_BPATCOL 0x217C +#define GER_PATTERN 0x2180 // from 0x2180 to 0x21FF + + Additional - Graphics Engine for 96xx +#define GER_SRCCLIP_XY 0x2148 +#define GER_SRCCLIP_X 0x2148 // Word +#define GER_SRCCLIP_Y 0x214A // Word +#define GER_DSTCLIP_XY 0x214C +#define GER_DSTCLIP_X 0x214C // Word +#define GER_DSTCLIP_Y 0x214E // Word +*/ + +READ8_MEMBER(trident_vga_device::accel_r) +{ + UINT8 res = 0xff; + + if(offset >= 0x60) + return tri.accel_pattern[(offset-0x60) % 0x80]; + + switch(offset) + { + case 0x00: // Status + if(tri.accel_busy) + res = 0x80; + else + res = 0x00; + break; + // Operation mode: + // bit 8: disable clipping if set + case 0x02: // Operation Mode + res = tri.accel_opermode & 0x00ff; + break; + case 0x03: + res = (tri.accel_opermode & 0xff00) >> 8; + break; + case 0x04: // Command register + res = tri.accel_command; + break; + case 0x07: // Foreground Mix? + res = tri.accel_fmix; + break; + default: + logerror("Trident: unimplemented acceleration register offset %02x read\n",offset); + } + return res; +} + +WRITE8_MEMBER(trident_vga_device::accel_w) +{ + if(offset >= 0x60) + { + tri.accel_pattern[(offset-0x60) % 0x80] = data; + return; + } + + switch(offset) + { + case 0x02: // Operation Mode + tri.accel_opermode = (tri.accel_opermode & 0xff00) | data; + if(LOG_ACCEL) logerror("Trident: Operation Mode set to %04x\n",tri.accel_opermode); + break; + case 0x03: + tri.accel_opermode = (tri.accel_opermode & 0x00ff) | (data << 8); + if(LOG_ACCEL) logerror("Trident: Operation Mode set to %04x\n",tri.accel_opermode); + break; + case 0x04: // Command register + tri.accel_command = data; + accel_command(); + break; + case 0x07: // Foreground Mix? + tri.accel_fmix = data; + if(LOG_ACCEL) logerror("Trident: FMIX set to %02x\n",data); + break; + case 0x08: // Draw flags + tri.accel_drawflags = (tri.accel_drawflags & 0xffffff00) | data; + if(LOG_ACCEL) logerror("Trident: Draw flags set to %08x\n",tri.accel_drawflags); + break; + case 0x09: + tri.accel_drawflags = (tri.accel_drawflags & 0xffff00ff) | (data << 8); + if(LOG_ACCEL) logerror("Trident: Draw flags set to %08x\n",tri.accel_drawflags); + break; + case 0x0a: + tri.accel_drawflags = (tri.accel_drawflags & 0xff00ffff) | (data << 16); + if(LOG_ACCEL) logerror("Trident: Draw flags set to %08x\n",tri.accel_drawflags); + break; + case 0x0b: + tri.accel_drawflags = (tri.accel_drawflags & 0x00ffffff) | (data << 24); + if(LOG_ACCEL) logerror("Trident: Draw flags set to %08x\n",tri.accel_drawflags); + break; + case 0x0c: // Foreground Colour + tri.accel_fgcolour = (tri.accel_fgcolour & 0xffffff00) | data; + if(LOG_ACCEL) logerror("Trident: Foreground Colour set to %08x\n",tri.accel_fgcolour); + break; + case 0x0d: + tri.accel_fgcolour = (tri.accel_fgcolour & 0xffff00ff) | (data << 8); + if(LOG_ACCEL) logerror("Trident: Foreground Colour set to %08x\n",tri.accel_fgcolour); + break; + case 0x0e: + tri.accel_fgcolour = (tri.accel_fgcolour & 0xff00ffff) | (data << 16); + if(LOG_ACCEL) logerror("Trident: Foreground Colour set to %08x\n",tri.accel_fgcolour); + break; + case 0x0f: + tri.accel_fgcolour = (tri.accel_fgcolour & 0x00ffffff) | (data << 24); + if(LOG_ACCEL) logerror("Trident: Foreground Colour set to %08x\n",tri.accel_fgcolour); + break; + case 0x10: // Background Colour + tri.accel_bgcolour = (tri.accel_bgcolour & 0xffffff00) | data; + if(LOG_ACCEL) logerror("Trident: Background Colour set to %08x\n",tri.accel_bgcolour); + break; + case 0x11: + tri.accel_bgcolour = (tri.accel_bgcolour & 0xffff00ff) | (data << 8); + if(LOG_ACCEL) logerror("Trident: Background Colour set to %08x\n",tri.accel_bgcolour); + break; + case 0x12: + tri.accel_bgcolour = (tri.accel_bgcolour & 0xff00ffff) | (data << 16); + if(LOG_ACCEL) logerror("Trident: Background Colour set to %08x\n",tri.accel_bgcolour); + break; + case 0x13: + tri.accel_bgcolour = (tri.accel_bgcolour & 0x00ffffff) | (data << 24); + if(LOG_ACCEL) logerror("Trident: Background Colour set to %08x\n",tri.accel_bgcolour); + break; + case 0x14: // Pattern Location + tri.accel_pattern_loc = (tri.accel_pattern_loc & 0xff00) | data; + if(LOG_ACCEL) logerror("Trident: Pattern Location set to %04x\n",tri.accel_pattern_loc); + break; + case 0x15: + tri.accel_pattern_loc = (tri.accel_pattern_loc & 0x00ff) | (data << 8); + if(LOG_ACCEL) logerror("Trident: Pattern Location set to %04x\n",tri.accel_pattern_loc); + break; + case 0x18: // Destination X + tri.accel_dest_x = (tri.accel_dest_x & 0xff00) | data; + if(LOG_ACCEL) logerror("Trident: Destination X set to %04x\n",tri.accel_dest_x); + break; + case 0x19: + tri.accel_dest_x = (tri.accel_dest_x & 0x00ff) | (data << 8); + if(LOG_ACCEL) logerror("Trident: Destination X set to %04x\n",tri.accel_dest_x); + break; + case 0x1a: // Destination Y + tri.accel_dest_y = (tri.accel_dest_y & 0xff00) | data; + if(LOG_ACCEL) logerror("Trident: Destination Y set to %04x\n",tri.accel_dest_y); + break; + case 0x1b: + tri.accel_dest_y = (tri.accel_dest_y & 0x00ff) | (data << 8); + if(LOG_ACCEL) logerror("Trident: Destination Y set to %04x\n",tri.accel_dest_y); + break; + case 0x1c: // Source X + tri.accel_source_x = (tri.accel_source_x & 0xff00) | data; + if(LOG_ACCEL) logerror("Trident: Source X set to %04x\n",tri.accel_source_x); + break; + case 0x1d: + tri.accel_source_x = (tri.accel_source_x & 0x00ff) | (data << 8); + if(LOG_ACCEL) logerror("Trident: Source X set to %04x\n",tri.accel_source_x); + break; + case 0x1e: // Source Y + tri.accel_source_y = (tri.accel_source_y & 0xff00) | data; + if(LOG_ACCEL) logerror("Trident: Source Y set to %04x\n",tri.accel_source_y); + break; + case 0x1f: + tri.accel_source_y = (tri.accel_source_y & 0x00ff) | (data << 8); + if(LOG_ACCEL) logerror("Trident: Source Y set to %04x\n",tri.accel_source_y); + break; + case 0x20: // Dimension(?) X + tri.accel_dim_x = (tri.accel_dim_x & 0xff00) | data; + if(LOG_ACCEL) logerror("Trident: Dimension X set to %04x\n",tri.accel_dim_x); + break; + case 0x21: + tri.accel_dim_x = (tri.accel_dim_x & 0x00ff) | (data << 8); + if(LOG_ACCEL) logerror("Trident: Dimension X set to %04x\n",tri.accel_dim_x); + break; + case 0x22: // Dimension(?) Y + tri.accel_dim_y = (tri.accel_dim_y & 0xff00) | data; + if(LOG_ACCEL) logerror("Trident: Dimension y set to %04x\n",tri.accel_dim_y); + break; + case 0x23: + tri.accel_dim_y = (tri.accel_dim_y & 0x00ff) | (data << 8); + if(LOG_ACCEL) logerror("Trident: Dimension y set to %04x\n",tri.accel_dim_y); + break; + case 0x24: // Style + tri.accel_style = (tri.accel_style & 0xffffff00) | data; + if(LOG_ACCEL) logerror("Trident: Style set to %08x\n",tri.accel_style); + break; + case 0x25: + tri.accel_style = (tri.accel_style & 0xffff00ff) | (data << 8); + if(LOG_ACCEL) logerror("Trident: Style set to %08x\n",tri.accel_style); + break; + case 0x26: + tri.accel_style = (tri.accel_style & 0xff00ffff) | (data << 16); + if(LOG_ACCEL) logerror("Trident: Style set to %08x\n",tri.accel_style); + break; + case 0x27: + tri.accel_style = (tri.accel_style & 0x00ffffff) | (data << 24); + if(LOG_ACCEL) logerror("Trident: Style set to %08x\n",tri.accel_style); + break; + case 0x28: // Source Clip X + tri.accel_source_x_clip = (tri.accel_source_x_clip & 0xff00) | data; + if(LOG_ACCEL) logerror("Trident: Source X Clip set to %04x\n",tri.accel_source_x_clip); + break; + case 0x29: + tri.accel_source_x_clip = (tri.accel_source_x_clip & 0x00ff) | (data << 8); + if(LOG_ACCEL) logerror("Trident: Source X Clip set to %04x\n",tri.accel_source_x_clip); + break; + case 0x2a: // Source Clip Y + tri.accel_source_y_clip = (tri.accel_source_y_clip & 0xff00) | data; + if(LOG_ACCEL) logerror("Trident: Source Y Clip set to %04x\n",tri.accel_source_y_clip); + break; + case 0x2b: + tri.accel_source_y_clip = (tri.accel_source_y_clip & 0x00ff) | (data << 8); + if(LOG_ACCEL) logerror("Trident: Source Y Clip set to %04x\n",tri.accel_source_y_clip); + break; + case 0x2c: // Destination Clip X + tri.accel_dest_x_clip = (tri.accel_dest_x_clip & 0xff00) | data; + if(LOG_ACCEL) logerror("Trident: Destination X Clip set to %04x\n",tri.accel_dest_x_clip); + break; + case 0x2d: + tri.accel_dest_x_clip = (tri.accel_dest_x_clip & 0x00ff) | (data << 8); + if(LOG_ACCEL) logerror("Trident: Destination X Clip set to %04x\n",tri.accel_dest_x_clip); + break; + case 0x2e: // Destination Clip Y + tri.accel_dest_y_clip = (tri.accel_dest_y_clip & 0xff00) | data; + if(LOG_ACCEL) logerror("Trident: Destination Y Clip set to %04x\n",tri.accel_dest_y_clip); + break; + case 0x2f: + tri.accel_dest_y_clip = (tri.accel_dest_y_clip & 0x00ff) | (data << 8); + if(LOG_ACCEL) logerror("Trident: Destination Y Clip set to %04x\n",tri.accel_dest_y_clip); + break; + case 0x48: // CKEY (Chromakey?) + tri.accel_ckey = (tri.accel_ckey & 0xffffff00) | data; + if(LOG_ACCEL) logerror("Trident: CKey set to %08x\n",tri.accel_ckey); + break; + case 0x49: + tri.accel_ckey = (tri.accel_ckey & 0xffff00ff) | (data << 8); + if(LOG_ACCEL) logerror("Trident: CKey set to %08x\n",tri.accel_ckey); + break; + case 0x4a: + tri.accel_ckey = (tri.accel_ckey & 0xff00ffff) | (data << 16); + if(LOG_ACCEL) logerror("Trident: CKey set to %08x\n",tri.accel_ckey); + break; + case 0x4b: + tri.accel_ckey = (tri.accel_ckey & 0x00ffffff) | (data << 24); + if(LOG_ACCEL) logerror("Trident: CKey set to %08x\n",tri.accel_ckey); + break; + case 0x58: // Foreground Pattern Colour + tri.accel_fg_pattern_colour = (tri.accel_fg_pattern_colour & 0xffffff00) | data; + if(LOG_ACCEL) logerror("Trident: FG Pattern Colour set to %08x\n",tri.accel_fg_pattern_colour); + break; + case 0x59: + tri.accel_fg_pattern_colour = (tri.accel_fg_pattern_colour & 0xffff00ff) | (data << 8); + if(LOG_ACCEL) logerror("Trident: FG Pattern Colour set to %08x\n",tri.accel_fg_pattern_colour); + break; + case 0x5a: + tri.accel_fg_pattern_colour = (tri.accel_fg_pattern_colour & 0xff00ffff) | (data << 16); + if(LOG_ACCEL) logerror("Trident: FG Pattern Colour set to %08x\n",tri.accel_fg_pattern_colour); + break; + case 0x5b: + tri.accel_fg_pattern_colour = (tri.accel_fg_pattern_colour & 0x00ffffff) | (data << 24); + if(LOG_ACCEL) logerror("Trident: FG Pattern Colour set to %08x\n",tri.accel_fg_pattern_colour); + break; + case 0x5c: // Background Pattern Colour + tri.accel_bg_pattern_colour = (tri.accel_bg_pattern_colour & 0xffffff00) | data; + if(LOG_ACCEL) logerror("Trident: BG Pattern Colour set to %08x\n",tri.accel_bg_pattern_colour); + break; + case 0x5d: + tri.accel_bg_pattern_colour = (tri.accel_bg_pattern_colour & 0xffff00ff) | (data << 8); + if(LOG_ACCEL) logerror("Trident: BG Pattern Colour set to %08x\n",tri.accel_bg_pattern_colour); + break; + case 0x5e: + tri.accel_bg_pattern_colour = (tri.accel_bg_pattern_colour & 0xff00ffff) | (data << 16); + if(LOG_ACCEL) logerror("Trident: BG Pattern Colour set to %08x\n",tri.accel_bg_pattern_colour); + break; + case 0x5f: + tri.accel_bg_pattern_colour = (tri.accel_bg_pattern_colour & 0x00ffffff) | (data << 24); + if(LOG_ACCEL) logerror("Trident: BG Pattern Colour set to %08x\n",tri.accel_bg_pattern_colour); + break; + default: + logerror("Trident: unimplemented acceleration register offset %02x write %02x\n",offset,data); + } +} + +void trident_vga_device::accel_command() +{ + switch(tri.accel_command) + { + case 0x00: + if(LOG) logerror("Trident: Command: NOP\n"); + break; + case 0x01: + if(LOG) logerror("Trident: Command: BitBLT ROP3 (Source %i,%i Dest %i,%i Size %i,%i)\n",tri.accel_source_x,tri.accel_source_y,tri.accel_dest_x,tri.accel_dest_y,tri.accel_dim_x,tri.accel_dim_y); + if(LOG) logerror("BitBLT: Drawflags = %08x FMIX = %02x\n",tri.accel_drawflags,tri.accel_fmix); + accel_bitblt(); + break; + case 0x02: + if(LOG) logerror("Trident: Command: BitBLT ROP4\n"); + break; + case 0x03: + if(LOG) logerror("Trident: Command: Scanline\n"); + break; + case 0x04: + if(LOG) logerror("Trident: Command: Bresenham Line (Source %i,%i Dest %i,%i Size %i,%i)\n",tri.accel_source_x,tri.accel_source_y,tri.accel_dest_x,tri.accel_dest_y,tri.accel_dim_x,tri.accel_dim_y); + if(LOG) logerror("BLine: Drawflags = %08x FMIX = %02x\n",tri.accel_drawflags,tri.accel_fmix); + accel_line(); + break; + case 0x05: + if(LOG) logerror("Trident: Command: Short Vector\n"); + break; + case 0x06: + if(LOG) logerror("Trident: Command: Fast Line\n"); + break; + case 0x07: + if(LOG) logerror("Trident: Command: Trapezoid Fill\n"); + break; + case 0x08: + if(LOG) logerror("Trident: Command: Ellipse\n"); + break; + case 0x09: + if(LOG) logerror("Trident: Command: Ellipse Fill\n"); + break; + default: + logerror("Trident: Unknown acceleration command %02x\n",tri.accel_command); + } +} + +void trident_vga_device::accel_bitblt() +{ + int x,y; + int sx,sy; + int xdir,ydir; + int xstart,xend,ystart,yend; + + if(tri.accel_drawflags & 0x0040) // TODO: handle PATMONO also + { + tri.accel_mem_x = tri.accel_dest_x; + tri.accel_mem_y = tri.accel_dest_y; + tri.accel_memwrite_active = true; + return; + } + + if(tri.accel_drawflags & 0x0200) + { + xdir = -1; + xstart = tri.accel_dest_x; + xend = tri.accel_dest_x-tri.accel_dim_x-1; + } + else + { + xdir = 1; + xstart = tri.accel_dest_x; + xend = tri.accel_dest_x+tri.accel_dim_x+1; + } + if(tri.accel_drawflags & 0x0100) + { + ydir = -1; + ystart = tri.accel_dest_y; + yend = tri.accel_dest_y-tri.accel_dim_y-1; + } + else + { + ydir = 1; + ystart = tri.accel_dest_y; + yend = tri.accel_dest_y+tri.accel_dim_y+1; + } + sy = tri.accel_source_y; + + for(y=ystart;y!=yend;y+=ydir,sy+=ydir) + { + sx = tri.accel_source_x; + for(x=xstart;x!=xend;x+=xdir,sx+=xdir) + { + if(tri.accel_drawflags & 0x4000) // Solid fill + { + WRITEPIXEL(x,y,tri.accel_fgcolour); + } + else + { + WRITEPIXEL(x,y,READPIXEL(sx,sy)); + } + } + } +} + +void trident_vga_device::accel_line() +{ + UINT32 col = tri.accel_fgcolour; +// TGUI_SRC_XY(dmin-dmaj,dmin); +// TGUI_DEST_XY(x,y); +// TGUI_DIM_XY(dmin+e,len); + INT16 dx = tri.accel_source_y - tri.accel_source_x; + INT16 dy = tri.accel_source_y; + INT16 err = tri.accel_dim_x + tri.accel_source_y; + int sx = (tri.accel_drawflags & 0x0200) ? -1 : 1; + int sy = (tri.accel_drawflags & 0x0100) ? -1 : 1; + int x,y,z; + + x = tri.accel_dest_x; + y = tri.accel_dest_y; + + WRITEPIXEL(x,y,col); + for(z=0;z 0) + { + if(tri.accel_drawflags & 0x0400) + x += sx; + else + y += sy; + WRITEPIXEL(x,y,col); + err += (dy-dx); + } + else + { + WRITEPIXEL(x,y,col); + err += dy; + } + } +} + +// feed data written to VRAM to an active BitBLT command +void trident_vga_device::accel_data_write(UINT32 data) +{ + int xdir = 1,ydir = 1; + + if(tri.accel_drawflags & 0x0200) // XNEG + xdir = -1; + if(tri.accel_drawflags & 0x0100) // YNEG + ydir = -1; + + for(int x=31;x>=0;x--) + { + if(tri.accel_mem_x <= tri.accel_dest_x+tri.accel_dim_x && tri.accel_mem_x >= tri.accel_dest_x-tri.accel_dim_x) + { + if(((data >> x) & 0x01) != 0) + WRITEPIXEL(tri.accel_mem_x,tri.accel_mem_y,tri.accel_fgcolour); + else + WRITEPIXEL(tri.accel_mem_x,tri.accel_mem_y,tri.accel_bgcolour); + } + tri.accel_mem_x+=xdir; + } + if(tri.accel_mem_x > tri.accel_dest_x+tri.accel_dim_x || tri.accel_mem_x < tri.accel_dest_x-tri.accel_dim_x) + { + tri.accel_mem_x = tri.accel_dest_x; + tri.accel_mem_y+=ydir; + if(tri.accel_mem_y > tri.accel_dest_y+tri.accel_dim_y || tri.accel_mem_y < tri.accel_dest_y-tri.accel_dim_y) + tri.accel_memwrite_active = false; // completed + } +} diff --git a/src/devices/bus/isa/trident.h b/src/devices/bus/isa/trident.h new file mode 100644 index 00000000000..e8c03a5254b --- /dev/null +++ b/src/devices/bus/isa/trident.h @@ -0,0 +1,153 @@ +// license:BSD-3-Clause +// copyright-holders:Barry Rodewald +/* + * trident.h + * + */ + +#ifndef TRIDENT_H_ +#define TRIDENT_H_ + +#include "video/pc_vga.h" + +// ======================> trident_vga_device + +class trident_vga_device : public svga_device +{ +public: + // construction/destruction + trident_vga_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual READ8_MEMBER(port_03c0_r); + virtual WRITE8_MEMBER(port_03c0_w); + virtual READ8_MEMBER(port_03d0_r); + virtual WRITE8_MEMBER(port_03d0_w); + DECLARE_READ8_MEMBER(port_83c6_r); + DECLARE_WRITE8_MEMBER(port_83c6_w); + DECLARE_READ8_MEMBER(port_43c6_r); + DECLARE_WRITE8_MEMBER(port_43c6_w); + DECLARE_READ8_MEMBER(vram_r); + DECLARE_WRITE8_MEMBER(vram_w); + virtual READ8_MEMBER(mem_r); + virtual WRITE8_MEMBER(mem_w); + virtual UINT16 offset(); + + DECLARE_READ8_MEMBER(accel_r); + DECLARE_WRITE8_MEMBER(accel_w); + + virtual UINT32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); + +protected: + virtual void device_start(); + virtual void device_reset(); + + struct + { + UINT8 sr0c; + UINT8 sr0d_old; + UINT8 sr0d_new; + UINT8 sr0e_old; + UINT8 sr0e_new; + UINT8 sr0f; + UINT8 gc0e; + UINT8 gc0f; + UINT8 gc2f; + UINT8 cr1e; + UINT8 cr1f; + UINT8 cr20; + UINT8 cr21; + UINT8 cr29; + UINT8 cr2a; + UINT8 cr39; + UINT8 dac; + UINT8 lutdac_reg[0x100]; + UINT8 lutdac_index; + bool new_mode; + bool port_3c3; + UINT8 port_3db; + UINT8 clock; + UINT8 pixel_depth; + UINT8 revision; + bool dac_active; + UINT8 dac_count; + UINT32 linear_address; + bool linear_active; + bool mmio_active; + UINT16 mem_clock; // I/O 0x43c6 + UINT16 vid_clock; // I/O 0x43c8 + UINT16 cursor_x; + UINT16 cursor_y; + UINT16 cursor_loc; + UINT8 cursor_x_off; + UINT8 cursor_y_off; + UINT32 cursor_fg; // colour + UINT32 cursor_bg; // colour + UINT8 cursor_ctrl; + + // 2D acceleration + UINT16 accel_opermode; + UINT8 accel_command; + UINT8 accel_fmix; + UINT32 accel_drawflags; + UINT32 accel_fgcolour; + UINT32 accel_bgcolour; + UINT16 accel_pattern_loc; + INT16 accel_source_x; + INT16 accel_source_y; + INT16 accel_dest_x; + INT16 accel_dest_y; + INT16 accel_dim_x; + INT16 accel_dim_y; + UINT32 accel_style; + UINT32 accel_ckey; + INT16 accel_source_x_clip; + INT16 accel_source_y_clip; + INT16 accel_dest_x_clip; + INT16 accel_dest_y_clip; + UINT32 accel_fg_pattern_colour; + UINT32 accel_bg_pattern_colour; + UINT8 accel_pattern[0x80]; + bool accel_busy; + bool accel_memwrite_active; // true when writing to VRAM will push data to an ongoing command (SRCMONO/PATMONO) + INT16 accel_mem_x; + INT16 accel_mem_y; + UINT32 accel_transfer; + } tri; +private: + UINT8 trident_seq_reg_read(UINT8 index); + void trident_seq_reg_write(UINT8 index, UINT8 data); + void trident_define_video_mode(); + UINT8 trident_crtc_reg_read(UINT8 index); + void trident_crtc_reg_write(UINT8 index, UINT8 data); + UINT8 trident_gc_reg_read(UINT8 index); + void trident_gc_reg_write(UINT8 index, UINT8 data); + + int calculate_clock(); + + // old style MMIO (0xBFF00) + void old_mmio_w(address_space& space, UINT32 offset, UINT8 data); + UINT8 old_mmio_r(address_space& space, UINT32 offset); + + // 2D acceleration + void accel_command(); + void accel_bitblt(); + void accel_line(); + void accel_data_write(UINT32 data); + UINT8 READPIXEL8(INT16 x, INT16 y); + UINT16 READPIXEL15(INT16 x, INT16 y); + UINT16 READPIXEL16(INT16 x, INT16 y); + UINT32 READPIXEL32(INT16 x, INT16 y); + void WRITEPIXEL8(INT16 x, INT16 y, UINT8 data); + void WRITEPIXEL15(INT16 x, INT16 y, UINT16 data); + void WRITEPIXEL16(INT16 x, INT16 y, UINT16 data); + void WRITEPIXEL32(INT16 x, INT16 y, UINT32 data); + UINT32 READPIXEL(INT16 x,INT16 y); + void WRITEPIXEL(INT16 x,INT16 y, UINT32 data); + UINT32 handle_rop(UINT32 src, UINT32 dst); +}; + + +// device type definition +extern const device_type TRIDENT_VGA; + +#endif /* TRIDENT_H_ */ diff --git a/src/devices/bus/isa/vga.c b/src/devices/bus/isa/vga.c new file mode 100644 index 00000000000..8b52309b31f --- /dev/null +++ b/src/devices/bus/isa/vga.c @@ -0,0 +1,84 @@ +// license:BSD-3-Clause +// copyright-holders:Barry Rodewald +/*************************************************************************** + + ISA VGA wrapper + +***************************************************************************/ + +#include "emu.h" +#include "vga.h" +#include "video/pc_vga.h" + +ROM_START( ibm_vga ) + ROM_REGION(0x8000,"ibm_vga", 0) + ROM_LOAD("ibm-vga.bin", 0x00000, 0x8000, BAD_DUMP CRC(74e3fadb) SHA1(dce6491424f1726203776dfae9a967a98a4ba7b5) ) +ROM_END + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type ISA8_VGA = &device_creator; + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor isa8_vga_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( pcvideo_vga ); +} + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *isa8_vga_device::device_rom_region() const +{ + return ROM_NAME( ibm_vga ); +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// isa8_vga_device - constructor +//------------------------------------------------- + +isa8_vga_device::isa8_vga_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, ISA8_VGA, "IBM VGA Graphics Card", tag, owner, clock, "ibm_vga", __FILE__), + device_isa8_card_interface(mconfig, *this) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- +READ8_MEMBER( isa8_vga_device::input_port_0_r ) { return 0xff; } //return space.machine().root_device().ioport("IN0")->read(); } + +void isa8_vga_device::device_start() +{ + set_isa_device(); + + m_vga = subdevice("vga"); + + m_isa->install_rom(this, 0xc0000, 0xc7fff, 0, 0, "ibm_vga", "ibm_vga"); + + m_isa->install_device(0x3b0, 0x3bf, 0, 0, read8_delegate(FUNC(vga_device::port_03b0_r),m_vga), write8_delegate(FUNC(vga_device::port_03b0_w),m_vga)); + m_isa->install_device(0x3c0, 0x3cf, 0, 0, read8_delegate(FUNC(vga_device::port_03c0_r),m_vga), write8_delegate(FUNC(vga_device::port_03c0_w),m_vga)); + m_isa->install_device(0x3d0, 0x3df, 0, 0, read8_delegate(FUNC(vga_device::port_03d0_r),m_vga), write8_delegate(FUNC(vga_device::port_03d0_w),m_vga)); + + m_isa->install_memory(0xa0000, 0xbffff, 0, 0, read8_delegate(FUNC(vga_device::mem_r),m_vga), write8_delegate(FUNC(vga_device::mem_w),m_vga)); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void isa8_vga_device::device_reset() +{ +} diff --git a/src/devices/bus/isa/vga.h b/src/devices/bus/isa/vga.h new file mode 100644 index 00000000000..4317592b33b --- /dev/null +++ b/src/devices/bus/isa/vga.h @@ -0,0 +1,43 @@ +// license:BSD-3-Clause +// copyright-holders:Barry Rodewald +#pragma once + +#ifndef __ISA_VGA_H__ +#define __ISA_VGA_H__ + +#include "emu.h" +#include "isa.h" +#include "video/pc_vga.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> isa8_vga_device + +class isa8_vga_device : + public device_t, + public device_isa8_card_interface +{ +public: + // construction/destruction + isa8_vga_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual const rom_entry *device_rom_region() const; + + DECLARE_READ8_MEMBER(input_port_0_r); +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); +private: + vga_device *m_vga; +}; + + +// device type definition +extern const device_type ISA8_VGA; + +#endif /* __ISA_VGA_H__ */ diff --git a/src/devices/bus/isa/vga_ati.c b/src/devices/bus/isa/vga_ati.c new file mode 100644 index 00000000000..dc6c9930ed2 --- /dev/null +++ b/src/devices/bus/isa/vga_ati.c @@ -0,0 +1,351 @@ +// license:BSD-3-Clause +// copyright-holders:Barry Rodewald +/* + * isa_vga_ati.c + * + * ATi Graphics Ultra ISA Video card + * - Uses ATi 28800-6 (VGA Wonder) and ATi 38800-1 (Mach8, 8514/A clone) + * + * ATi Graphics Ultra Pro ISA Video card + * - ATi 68800-3 (Mach32, combined VGA and 8514/A) + * + * ATi mach64 ISA Video card + * - ATi 88800 (Mach64, combined VGA and 8514/A) + * + * Created on: 9/09/2012 + */ + +#include "emu.h" +#include "vga_ati.h" +#include "mach32.h" +#include "video/pc_vga.h" + +ROM_START( gfxultra ) + ROM_REGION(0x8000,"gfxultra", 0) + ROM_LOAD("113-11504-002.bin", 0x00000, 0x8000, CRC(f498b36a) SHA1(117cfc972ce4645538ba7262222d8ff38bc2c58c) ) + ROM_IGNORE( 0x8000 ) +ROM_END + +ROM_START( gfxultrp ) + ROM_REGION(0x8000,"gfxultrapro", 0) + + ROM_DEFAULT_BIOS("isa") + + ROM_SYSTEM_BIOS( 0, "isa", "ISA BIOS 112-18900-100" ) + ROMX_LOAD("gfxultrapro.bin", 0x00000, 0x8000, CRC(4e5effd7) SHA1(84ad3abf7653e4734bf39f5d5c8b88e74527e8ce), ROM_BIOS(1) ) + + // We can separate out this BIOS once a proper VLB bus emulation is available + ROM_SYSTEM_BIOS( 1, "vlb", "VLB BIOS 113-19500-100" ) + ROMX_LOAD("gfxultrapro_vlb.bin", 0x00000, 0x8000, CRC(5018f71e) SHA1(61321dfecf1bcdd8043836fabbe41786dbf3001b), ROM_BIOS(2) ) +ROM_END + +ROM_START( mach64 ) + ROM_REGION(0x8000,"mach64", 0) + + ROM_SYSTEM_BIOS( 0, "isa", "ISA BIOS 112-28122-101" ) + ROMX_LOAD("mach64.bin", 0x00000, 0x8000, CRC(1300aa8f) SHA1(dfc7f817900f125b89b0bda16fcb205f066a47fc), ROM_BIOS(1) ) + + // We can separate out these BIOSes once a proper PCI and VLB bus emulation is available + ROM_SYSTEM_BIOS( 1, "vlb_d", "VLB DRAM BIOS 113-27803-102" ) + ROMX_LOAD("mach64_vlb_dram.bin", 0x00000, 0x8000, CRC(f2a24699) SHA1(580401a8bdfc379180a8d7d77305fc529b2a8374), ROM_BIOS(2) ) + + ROM_SYSTEM_BIOS( 2, "gfxultrapt_vlb", "ATi Graphics Pro Turbo VLB VRAM BIOS 113-26900-103" ) + ROMX_LOAD("mach64_vlb_vram.bin", 0x00000, 0x8000, CRC(47779d8f) SHA1(87b01b7a16d9c79dfc6c5aa8a39455c725d2e455), ROM_BIOS(3) ) + + ROM_SYSTEM_BIOS( 3, "pci", "PCI BIOS 113-25420-100" ) + ROMX_LOAD("pci_mach64__113-25420-100-1995.27c256.u1.bin", 0x00000, 0x8000, CRC(762596e8) SHA1(9544b073ac182ec2990e18f54afbb96d52db744a), ROM_BIOS(4) ) + + ROM_SYSTEM_BIOS( 4, "pci_v1", "PCI mach64 V1 BIOS 113-34404-104" ) + ROMX_LOAD("pci_mach64_v1_113-34404-104_1996.bin", 0x00000, 0x8000, CRC(c6a39c3f) SHA1(0f4cf9221179c675dafafde638bc00244b6feb63), ROM_BIOS(5) ) + ROM_IGNORE(0x8000) + +ROM_END + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type ISA16_VGA_GFXULTRA = &device_creator; +const device_type ISA16_SVGA_GFXULTRAPRO = &device_creator; +const device_type ISA16_SVGA_MACH64 = &device_creator; + +static MACHINE_CONFIG_FRAGMENT( vga_ati ) + MCFG_SCREEN_ADD("screen", RASTER) + MCFG_SCREEN_RAW_PARAMS(XTAL_25_1748MHz,900,0,640,526,0,480) + MCFG_SCREEN_UPDATE_DEVICE("vga", ati_vga_device, screen_update) + + MCFG_PALETTE_ADD("palette", 0x100) + + MCFG_DEVICE_ADD("vga", ATI_VGA, 0) +MACHINE_CONFIG_END + +static MACHINE_CONFIG_FRAGMENT( vga_mach32 ) + MCFG_SCREEN_ADD("screen", RASTER) + MCFG_SCREEN_RAW_PARAMS(XTAL_25_1748MHz,900,0,640,526,0,480) + MCFG_SCREEN_UPDATE_DEVICE("vga", mach32_device, screen_update) + + MCFG_PALETTE_ADD("palette", 0x100) + + MCFG_DEVICE_ADD("vga", ATIMACH32, 0) +MACHINE_CONFIG_END + +static MACHINE_CONFIG_FRAGMENT( vga_mach64 ) + MCFG_SCREEN_ADD("screen", RASTER) + MCFG_SCREEN_RAW_PARAMS(XTAL_25_1748MHz,900,0,640,526,0,480) + MCFG_SCREEN_UPDATE_DEVICE("vga", mach64_device, screen_update) + + MCFG_PALETTE_ADD("palette", 0x100) + + MCFG_DEVICE_ADD("vga", ATIMACH64, 0) +MACHINE_CONFIG_END + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor isa16_vga_gfxultra_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( vga_ati ); +} + +machine_config_constructor isa16_vga_gfxultrapro_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( vga_mach32 ); +} + +machine_config_constructor isa16_vga_mach64_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( vga_mach64 ); +} + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *isa16_vga_gfxultra_device::device_rom_region() const +{ + return ROM_NAME( gfxultra ); +} + +const rom_entry *isa16_vga_gfxultrapro_device::device_rom_region() const +{ + return ROM_NAME( gfxultrp ); +} + +const rom_entry *isa16_vga_mach64_device::device_rom_region() const +{ + return ROM_NAME( mach64 ); +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// isa8_vga_device - constructor +//------------------------------------------------- + +isa16_vga_gfxultra_device::isa16_vga_gfxultra_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, ISA16_VGA_GFXULTRA, "ATi Graphics Ultra Card", tag, owner, clock, "gfxultra", __FILE__), + device_isa16_card_interface(mconfig, *this) +{ +} + +isa16_vga_gfxultrapro_device::isa16_vga_gfxultrapro_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, ISA16_SVGA_GFXULTRAPRO, "ATi Graphics Ultra Pro Card", tag, owner, clock, "gfxultrp", __FILE__), + device_isa16_card_interface(mconfig, *this) +{ +} + +isa16_vga_mach64_device::isa16_vga_mach64_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, ISA16_SVGA_MACH64, "ATi mach64 Card", tag, owner, clock, "mach64", __FILE__), + device_isa16_card_interface(mconfig, *this) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- +READ8_MEMBER(isa16_vga_gfxultra_device::input_port_0_r ) { return 0xff; } //return space.machine().root_device().ioport("IN0")->read(); } +READ8_MEMBER(isa16_vga_gfxultrapro_device::input_port_0_r ) { return 0xff; } //return space.machine().root_device().ioport("IN0")->read(); } +READ8_MEMBER(isa16_vga_mach64_device::input_port_0_r ) { return 0xff; } //return space.machine().root_device().ioport("IN0")->read(); } + +void isa16_vga_gfxultra_device::device_start() +{ + set_isa_device(); + + m_vga = subdevice("vga"); + m_8514 = subdevice("vga:8514a"); + + m_isa->install_rom(this, 0xc0000, 0xc7fff, 0, 0, "vga", "gfxultra"); + + m_isa->install_device(0x1ce, 0x1cf, 0, 0, read8_delegate(FUNC(ati_vga_device::ati_port_ext_r),m_vga), write8_delegate(FUNC(ati_vga_device::ati_port_ext_w),m_vga)); + m_isa->install16_device(0x2e8, 0x2eb, 0, 0, read16_delegate(FUNC(mach8_device::ibm8514_status_r),m_8514), write16_delegate(FUNC(mach8_device::ibm8514_htotal_w),m_8514)); + m_isa->install_device(0x3b0, 0x3bf, 0, 0, read8_delegate(FUNC(ati_vga_device::port_03b0_r),m_vga), write8_delegate(FUNC(vga_device::port_03b0_w),m_vga)); + m_isa->install_device(0x3c0, 0x3cf, 0, 0, read8_delegate(FUNC(ati_vga_device::port_03c0_r),m_vga), write8_delegate(FUNC(vga_device::port_03c0_w),m_vga)); + m_isa->install_device(0x3d0, 0x3df, 0, 0, read8_delegate(FUNC(ati_vga_device::port_03d0_r),m_vga), write8_delegate(FUNC(vga_device::port_03d0_w),m_vga)); + m_isa->install16_device(0x12e8, 0x12eb, 0, 0, read16_delegate(FUNC(mach8_device::ibm8514_vtotal_r),m_8514), write16_delegate(FUNC(mach8_device::ibm8514_vtotal_w),m_8514)); + m_isa->install16_device(0x12ec, 0x12ef, 0, 0, read16_delegate(FUNC(mach8_device::mach8_config1_r),m_8514), write16_delegate()); + m_isa->install16_device(0x16e8, 0x16eb, 0, 0, read16_delegate(FUNC(mach8_device::ibm8514_vdisp_r),m_8514), write16_delegate(FUNC(mach8_device::ibm8514_vdisp_w),m_8514)); + m_isa->install16_device(0x16ec, 0x16ef, 0, 0, read16_delegate(FUNC(mach8_device::mach8_config2_r),m_8514), write16_delegate()); + m_isa->install16_device(0x1ae8, 0x1aeb, 0, 0, read16_delegate(FUNC(mach8_device::ibm8514_vsync_r),m_8514), write16_delegate(FUNC(mach8_device::ibm8514_vsync_w),m_8514)); + m_isa->install16_device(0x26e8, 0x26eb, 0, 0, read16_delegate(FUNC(mach8_device::ibm8514_htotal_r),m_8514),write16_delegate()); + m_isa->install16_device(0x2ee8, 0x2eeb, 0, 0, read16_delegate(FUNC(mach8_device::ibm8514_subcontrol_r),m_8514),write16_delegate()); + m_isa->install16_device(0x42e8, 0x42eb, 0, 0, read16_delegate(FUNC(mach8_device::ibm8514_substatus_r),m_8514), write16_delegate(FUNC(mach8_device::ibm8514_subcontrol_w),m_8514)); + m_isa->install16_device(0x52e8, 0x52eb, 0, 0, read16_delegate(FUNC(mach8_device::mach8_ec0_r),m_8514), write16_delegate(FUNC(mach8_device::mach8_ec0_w),m_8514)); + m_isa->install16_device(0x52ec, 0x52ef, 0, 0, read16_delegate(FUNC(mach8_device::mach8_scratch0_r),m_8514), write16_delegate(FUNC(mach8_device::mach8_scratch0_w),m_8514)); + m_isa->install16_device(0x56e8, 0x56eb, 0, 0, read16_delegate(FUNC(mach8_device::mach8_ec1_r),m_8514), write16_delegate(FUNC(mach8_device::mach8_ec1_w),m_8514)); + m_isa->install16_device(0x56ec, 0x56ef, 0, 0, read16_delegate(FUNC(mach8_device::mach8_scratch0_r),m_8514), write16_delegate(FUNC(mach8_device::mach8_scratch0_w),m_8514)); + m_isa->install16_device(0x5ae8, 0x5aeb, 0, 0, read16_delegate(FUNC(mach8_device::mach8_ec2_r),m_8514), write16_delegate(FUNC(mach8_device::mach8_ec2_w),m_8514)); + m_isa->install16_device(0x5ee8, 0x5eeb, 0, 0, read16_delegate(FUNC(mach8_device::mach8_ec3_r),m_8514), write16_delegate(FUNC(mach8_device::mach8_ec3_w),m_8514)); + m_isa->install16_device(0x82e8, 0x82eb, 0, 0, read16_delegate(FUNC(mach8_device::ibm8514_currenty_r),m_8514), write16_delegate(FUNC(mach8_device::ibm8514_currenty_w),m_8514)); + m_isa->install16_device(0x86e8, 0x86eb, 0, 0, read16_delegate(FUNC(mach8_device::ibm8514_currentx_r),m_8514), write16_delegate(FUNC(mach8_device::ibm8514_currentx_w),m_8514)); + m_isa->install16_device(0x8ae8, 0x8aeb, 0, 0, read16_delegate(FUNC(mach8_device::ibm8514_desty_r),m_8514), write16_delegate(FUNC(mach8_device::ibm8514_desty_w),m_8514)); + m_isa->install16_device(0x8ee8, 0x8eeb, 0, 0, read16_delegate(FUNC(mach8_device::ibm8514_destx_r),m_8514), write16_delegate(FUNC(mach8_device::ibm8514_destx_w),m_8514)); + m_isa->install16_device(0x92e8, 0x92eb, 0, 0, read16_delegate(FUNC(mach8_device::ibm8514_line_error_r),m_8514), write16_delegate(FUNC(mach8_device::ibm8514_line_error_w),m_8514)); + m_isa->install16_device(0x96e8, 0x96eb, 0, 0, read16_delegate(FUNC(mach8_device::ibm8514_width_r),m_8514), write16_delegate(FUNC(mach8_device::ibm8514_width_w),m_8514)); + m_isa->install16_device(0x96ec, 0x96ef, 0, 0, read16_delegate(FUNC(mach8_device::mach8_bresenham_count_r),m_8514), write16_delegate(FUNC(mach8_device::mach8_bresenham_count_w),m_8514)); + m_isa->install16_device(0x9ae8, 0x9aeb, 0, 0, read16_delegate(FUNC(mach8_device::ibm8514_gpstatus_r),m_8514), write16_delegate(FUNC(mach8_device::ibm8514_cmd_w),m_8514)); + m_isa->install16_device(0x9aec, 0x9aef, 0, 0, read16_delegate(FUNC(mach8_device::mach8_ext_fifo_r),m_8514), write16_delegate(FUNC(mach8_device::mach8_linedraw_index_w),m_8514)); + m_isa->install16_device(0x9ee8, 0x9eeb, 0, 0, read16_delegate(FUNC(mach8_device::ibm8514_ssv_r),m_8514), write16_delegate(FUNC(mach8_device::ibm8514_ssv_w),m_8514)); + m_isa->install16_device(0xa2e8, 0xa2eb, 0, 0, read16_delegate(FUNC(mach8_device::ibm8514_bgcolour_r),m_8514), write16_delegate(FUNC(mach8_device::ibm8514_bgcolour_w),m_8514)); + m_isa->install16_device(0xa6e8, 0xa6eb, 0, 0, read16_delegate(FUNC(mach8_device::ibm8514_fgcolour_r),m_8514), write16_delegate(FUNC(mach8_device::ibm8514_fgcolour_w),m_8514)); + m_isa->install16_device(0xaae8, 0xaaeb, 0, 0, read16_delegate(FUNC(ibm8514a_device::ibm8514_write_mask_r),m_8514), write16_delegate(FUNC(ibm8514a_device::ibm8514_write_mask_w),m_8514)); + m_isa->install16_device(0xaee8, 0xaeeb, 0, 0, read16_delegate(FUNC(ibm8514a_device::ibm8514_read_mask_r),m_8514), write16_delegate(FUNC(ibm8514a_device::ibm8514_read_mask_w),m_8514)); + m_isa->install16_device(0xb6e8, 0xb6eb, 0, 0, read16_delegate(FUNC(mach8_device::ibm8514_backmix_r),m_8514), write16_delegate(FUNC(mach8_device::ibm8514_backmix_w),m_8514)); + m_isa->install16_device(0xbae8, 0xbaeb, 0, 0, read16_delegate(FUNC(mach8_device::ibm8514_foremix_r),m_8514), write16_delegate(FUNC(mach8_device::ibm8514_foremix_w),m_8514)); + m_isa->install16_device(0xbee8, 0xbeeb, 0, 0, read16_delegate(FUNC(mach8_device::ibm8514_multifunc_r),m_8514), write16_delegate(FUNC(mach8_device::ibm8514_multifunc_w),m_8514)); + m_isa->install16_device(0xe2e8, 0xe2eb, 0, 0, read16_delegate(FUNC(mach8_device::ibm8514_pixel_xfer_r),m_8514), write16_delegate(FUNC(mach8_device::ibm8514_pixel_xfer_w),m_8514)); + m_isa->install16_device(0xdaec, 0xdaef, 0, 0, read16_delegate(FUNC(mach8_device::mach8_sourcex_r),m_8514), write16_delegate(FUNC(mach8_device::mach8_ext_leftscissor_w),m_8514)); + m_isa->install16_device(0xdeec, 0xdeef, 0, 0, read16_delegate(FUNC(mach8_device::mach8_sourcey_r),m_8514), write16_delegate(FUNC(mach8_device::mach8_ext_topscissor_w),m_8514)); + m_isa->install16_device(0xfeec, 0xfeef, 0, 0, read16_delegate(FUNC(mach8_device::mach8_linedraw_r),m_8514), write16_delegate(FUNC(mach8_device::mach8_linedraw_w),m_8514)); + + m_isa->install_memory(0xa0000, 0xbffff, 0, 0, read8_delegate(FUNC(ati_vga_device::mem_r),m_vga), write8_delegate(FUNC(ati_vga_device::mem_w),m_vga)); +} + +void isa16_vga_gfxultrapro_device::device_start() +{ + set_isa_device(); + + m_vga = subdevice("vga"); + + m_isa->install_rom(this, 0xc0000, 0xc7fff, 0, 0, "vga", "gfxultrapro"); + + m_isa->install_device(0x1ce, 0x1cf, 0, 0, read8_delegate(FUNC(mach32_device::ati_port_ext_r),m_vga), write8_delegate(FUNC(mach32_device::ati_port_ext_w),m_vga)); + m_isa->install16_device(0x2e8, 0x2eb, 0, 0, read16_delegate(FUNC(mach32_device::mach32_status_r),m_vga), write16_delegate(FUNC(mach32_device::ibm8514_htotal_w),m_vga)); + m_isa->install_device(0x3b0, 0x3bf, 0, 0, read8_delegate(FUNC(mach32_device::port_03b0_r),m_vga), write8_delegate(FUNC(mach32_device::port_03b0_w),m_vga)); + m_isa->install_device(0x3c0, 0x3cf, 0, 0, read8_delegate(FUNC(mach32_device::port_03c0_r),m_vga), write8_delegate(FUNC(mach32_device::port_03c0_w),m_vga)); + m_isa->install_device(0x3d0, 0x3df, 0, 0, read8_delegate(FUNC(mach32_device::port_03d0_r),m_vga), write8_delegate(FUNC(mach32_device::port_03d0_w),m_vga)); + m_isa->install16_device(0x12e8, 0x12eb, 0, 0, read16_delegate(FUNC(mach32_device::ibm8514_vtotal_r),m_vga), write16_delegate(FUNC(mach32_device::ibm8514_vtotal_w),m_vga)); + m_isa->install16_device(0x12ec, 0x12ef, 0, 0, read16_delegate(FUNC(mach32_device::mach8_config1_r),m_vga), write16_delegate()); + m_isa->install16_device(0x16e8, 0x16eb, 0, 0, read16_delegate(FUNC(mach32_device::ibm8514_vdisp_r),m_vga), write16_delegate(FUNC(mach32_device::ibm8514_vdisp_w),m_vga)); + m_isa->install16_device(0x16ec, 0x16ef, 0, 0, read16_delegate(FUNC(mach32_device::mach8_config2_r),m_vga), write16_delegate()); + m_isa->install16_device(0x1ae8, 0x1aeb, 0, 0, read16_delegate(FUNC(mach32_device::ibm8514_vsync_r),m_vga), write16_delegate(FUNC(mach32_device::ibm8514_vsync_w),m_vga)); + m_isa->install16_device(0x26e8, 0x26eb, 0, 0, read16_delegate(FUNC(mach32_device::ibm8514_htotal_r),m_vga),write16_delegate()); + m_isa->install16_device(0x2ee8, 0x2eeb, 0, 0, read16_delegate(FUNC(mach32_device::ibm8514_subcontrol_r),m_vga),write16_delegate()); + m_isa->install16_device(0x42e8, 0x42eb, 0, 0, read16_delegate(FUNC(mach32_device::ibm8514_substatus_r),m_vga), write16_delegate(FUNC(mach32_device::ibm8514_subcontrol_w),m_vga)); + m_isa->install16_device(0x42ec, 0x42ef, 0, 0, read16_delegate(FUNC(mach32_device::mach32_mem_boundary_r),m_vga), write16_delegate(FUNC(mach32_device::mach32_mem_boundary_w),m_vga)); + m_isa->install16_device(0x4aec, 0x4aef, 0, 0, read16_delegate(FUNC(mach32_device::mach8_clksel_r),m_vga), write16_delegate(FUNC(mach32_device::mach32_clksel_w),m_vga)); + m_isa->install16_device(0x52e8, 0x52eb, 0, 0, read16_delegate(FUNC(mach32_device::mach8_ec0_r),m_vga), write16_delegate(FUNC(mach32_device::mach8_ec0_w),m_vga)); + m_isa->install16_device(0x52ec, 0x52ef, 0, 0, read16_delegate(FUNC(mach32_device::mach8_scratch0_r),m_vga), write16_delegate(FUNC(mach32_device::mach8_scratch0_w),m_vga)); + m_isa->install16_device(0x56e8, 0x56eb, 0, 0, read16_delegate(FUNC(mach32_device::mach8_ec1_r),m_vga), write16_delegate(FUNC(mach32_device::mach8_ec1_w),m_vga)); + m_isa->install16_device(0x56ec, 0x56ef, 0, 0, read16_delegate(FUNC(mach32_device::mach8_scratch0_r),m_vga), write16_delegate(FUNC(mach32_device::mach8_scratch0_w),m_vga)); + m_isa->install16_device(0x5ae8, 0x5aeb, 0, 0, read16_delegate(FUNC(mach32_device::mach8_ec2_r),m_vga), write16_delegate(FUNC(mach32_device::mach8_ec2_w),m_vga)); + m_isa->install16_device(0x5ee8, 0x5eeb, 0, 0, read16_delegate(FUNC(mach32_device::mach8_ec3_r),m_vga), write16_delegate(FUNC(mach32_device::mach8_ec3_w),m_vga)); + m_isa->install16_device(0x82e8, 0x82eb, 0, 0, read16_delegate(FUNC(mach32_device::ibm8514_currenty_r),m_vga), write16_delegate(FUNC(mach32_device::ibm8514_currenty_w),m_vga)); + m_isa->install16_device(0x86e8, 0x86eb, 0, 0, read16_delegate(FUNC(mach32_device::ibm8514_currentx_r),m_vga), write16_delegate(FUNC(mach32_device::ibm8514_currentx_w),m_vga)); + m_isa->install16_device(0x8ae8, 0x8aeb, 0, 0, read16_delegate(FUNC(mach32_device::ibm8514_desty_r),m_vga), write16_delegate(FUNC(mach32_device::ibm8514_desty_w),m_vga)); + m_isa->install16_device(0x8ee8, 0x8eeb, 0, 0, read16_delegate(FUNC(mach32_device::ibm8514_destx_r),m_vga), write16_delegate(FUNC(mach32_device::ibm8514_destx_w),m_vga)); + m_isa->install16_device(0x92e8, 0x92eb, 0, 0, read16_delegate(FUNC(mach32_device::ibm8514_line_error_r),m_vga), write16_delegate(FUNC(mach32_device::ibm8514_line_error_w),m_vga)); + m_isa->install16_device(0x96e8, 0x96eb, 0, 0, read16_delegate(FUNC(mach32_device::ibm8514_width_r),m_vga), write16_delegate(FUNC(mach32_device::ibm8514_width_w),m_vga)); + m_isa->install16_device(0x96ec, 0x96ef, 0, 0, read16_delegate(FUNC(mach32_device::mach8_bresenham_count_r),m_vga), write16_delegate(FUNC(mach32_device::mach8_bresenham_count_w),m_vga)); + m_isa->install16_device(0x9ae8, 0x9aeb, 0, 0, read16_delegate(FUNC(mach32_device::ibm8514_gpstatus_r),m_vga), write16_delegate(FUNC(mach32_device::ibm8514_cmd_w),m_vga)); + m_isa->install16_device(0x9aec, 0x9aef, 0, 0, read16_delegate(FUNC(mach32_device::mach8_ext_fifo_r),m_vga), write16_delegate(FUNC(mach32_device::mach8_linedraw_index_w),m_vga)); + m_isa->install16_device(0x9ee8, 0x9eeb, 0, 0, read16_delegate(FUNC(mach32_device::ibm8514_ssv_r),m_vga), write16_delegate(FUNC(mach32_device::ibm8514_ssv_w),m_vga)); + m_isa->install16_device(0xa2e8, 0xa2eb, 0, 0, read16_delegate(FUNC(mach32_device::ibm8514_bgcolour_r),m_vga), write16_delegate(FUNC(mach32_device::ibm8514_bgcolour_w),m_vga)); + m_isa->install16_device(0xa6e8, 0xa6eb, 0, 0, read16_delegate(FUNC(mach32_device::ibm8514_fgcolour_r),m_vga), write16_delegate(FUNC(mach32_device::ibm8514_fgcolour_w),m_vga)); + m_isa->install16_device(0xaae8, 0xaaeb, 0, 0, read16_delegate(FUNC(mach32_device::ibm8514_write_mask_r),m_vga), write16_delegate(FUNC(mach32_device::ibm8514_write_mask_w),m_vga)); + m_isa->install16_device(0xaee8, 0xaeeb, 0, 0, read16_delegate(FUNC(mach32_device::ibm8514_read_mask_r),m_vga), write16_delegate(FUNC(mach32_device::ibm8514_read_mask_w),m_vga)); + m_isa->install16_device(0xb6e8, 0xb6eb, 0, 0, read16_delegate(FUNC(mach32_device::ibm8514_backmix_r),m_vga), write16_delegate(FUNC(mach32_device::ibm8514_backmix_w),m_vga)); + m_isa->install16_device(0xbae8, 0xbaeb, 0, 0, read16_delegate(FUNC(mach32_device::ibm8514_foremix_r),m_vga), write16_delegate(FUNC(mach32_device::ibm8514_foremix_w),m_vga)); + m_isa->install16_device(0xbee8, 0xbeeb, 0, 0, read16_delegate(FUNC(mach32_device::ibm8514_multifunc_r),m_vga), write16_delegate(FUNC(mach32_device::ibm8514_multifunc_w),m_vga)); + m_isa->install16_device(0xe2e8, 0xe2eb, 0, 0, read16_delegate(FUNC(mach32_device::ibm8514_pixel_xfer_r),m_vga), write16_delegate(FUNC(mach32_device::ibm8514_pixel_xfer_w),m_vga)); + m_isa->install16_device(0xdaec, 0xdaef, 0, 0, read16_delegate(FUNC(mach32_device::mach8_sourcex_r),m_vga), write16_delegate(FUNC(mach32_device::mach8_ext_leftscissor_w),m_vga)); + m_isa->install16_device(0xdeec, 0xdeef, 0, 0, read16_delegate(FUNC(mach32_device::mach8_sourcey_r),m_vga), write16_delegate(FUNC(mach32_device::mach8_ext_topscissor_w),m_vga)); + m_isa->install16_device(0xfaec, 0xfaef, 0, 0, read16_delegate(FUNC(mach32_device::mach32_chipid_r),m_vga), write16_delegate()); + m_isa->install16_device(0xfeec, 0xfeef, 0, 0, read16_delegate(FUNC(mach32_device::mach8_linedraw_r),m_vga), write16_delegate(FUNC(mach32_device::mach8_linedraw_w),m_vga)); + + m_isa->install_memory(0xa0000, 0xbffff, 0, 0, read8_delegate(FUNC(mach32_device::mem_r),m_vga), write8_delegate(FUNC(mach32_device::mem_w),m_vga)); +} + +void isa16_vga_mach64_device::device_start() +{ + set_isa_device(); + + m_vga = subdevice("vga"); + + m_isa->install_rom(this, 0xc0000, 0xc7fff, 0, 0, "vga", "mach64"); + + m_isa->install_device(0x1ce, 0x1cf, 0, 0, read8_delegate(FUNC(mach64_device::ati_port_ext_r),m_vga), write8_delegate(FUNC(mach64_device::ati_port_ext_w),m_vga)); + m_isa->install16_device(0x2e8, 0x2eb, 0, 0, read16_delegate(FUNC(mach64_device::mach32_status_r),m_vga), write16_delegate(FUNC(mach64_device::ibm8514_htotal_w),m_vga)); + m_isa->install_device(0x3b0, 0x3bf, 0, 0, read8_delegate(FUNC(mach64_device::port_03b0_r),m_vga), write8_delegate(FUNC(mach64_device::port_03b0_w),m_vga)); + m_isa->install_device(0x3c0, 0x3cf, 0, 0, read8_delegate(FUNC(mach64_device::port_03c0_r),m_vga), write8_delegate(FUNC(mach64_device::port_03c0_w),m_vga)); + m_isa->install_device(0x3d0, 0x3df, 0, 0, read8_delegate(FUNC(mach64_device::port_03d0_r),m_vga), write8_delegate(FUNC(mach64_device::port_03d0_w),m_vga)); + m_isa->install16_device(0x12e8, 0x12eb, 0, 0, read16_delegate(FUNC(mach64_device::ibm8514_vtotal_r),m_vga), write16_delegate(FUNC(mach64_device::ibm8514_vtotal_w),m_vga)); + m_isa->install16_device(0x12ec, 0x12ef, 0, 0, read16_delegate(FUNC(mach64_device::mach8_config1_r),m_vga), write16_delegate(FUNC(mach64_device::mach64_config1_w),m_vga)); + m_isa->install16_device(0x16e8, 0x16eb, 0, 0, read16_delegate(FUNC(mach64_device::ibm8514_vdisp_r),m_vga), write16_delegate(FUNC(mach64_device::ibm8514_vdisp_w),m_vga)); + m_isa->install16_device(0x16ec, 0x16ef, 0, 0, read16_delegate(FUNC(mach64_device::mach8_config2_r),m_vga), write16_delegate(FUNC(mach64_device::mach64_config2_w),m_vga)); + m_isa->install16_device(0x1ae8, 0x1aeb, 0, 0, read16_delegate(FUNC(mach64_device::ibm8514_vsync_r),m_vga), write16_delegate(FUNC(mach64_device::ibm8514_vsync_w),m_vga)); + m_isa->install16_device(0x26e8, 0x26eb, 0, 0, read16_delegate(FUNC(mach64_device::ibm8514_htotal_r),m_vga),write16_delegate()); + m_isa->install16_device(0x2ee8, 0x2eeb, 0, 0, read16_delegate(FUNC(mach64_device::ibm8514_subcontrol_r),m_vga),write16_delegate()); + m_isa->install16_device(0x42e8, 0x42eb, 0, 0, read16_delegate(FUNC(mach64_device::ibm8514_substatus_r),m_vga), write16_delegate(FUNC(mach64_device::ibm8514_subcontrol_w),m_vga)); + m_isa->install16_device(0x42ec, 0x42ef, 0, 0, read16_delegate(FUNC(mach64_device::mach32_mem_boundary_r),m_vga), write16_delegate(FUNC(mach64_device::mach32_mem_boundary_w),m_vga)); + m_isa->install16_device(0x4aec, 0x4aef, 0, 0, read16_delegate(FUNC(mach64_device::mach8_clksel_r),m_vga), write16_delegate(FUNC(mach64_device::mach32_clksel_w),m_vga)); + m_isa->install16_device(0x52e8, 0x52eb, 0, 0, read16_delegate(FUNC(mach64_device::mach8_ec0_r),m_vga), write16_delegate(FUNC(mach64_device::mach8_ec0_w),m_vga)); + m_isa->install16_device(0x52ec, 0x52ef, 0, 0, read16_delegate(FUNC(mach64_device::mach8_scratch0_r),m_vga), write16_delegate(FUNC(mach64_device::mach8_scratch0_w),m_vga)); + m_isa->install16_device(0x56e8, 0x56eb, 0, 0, read16_delegate(FUNC(mach64_device::mach8_ec1_r),m_vga), write16_delegate(FUNC(mach64_device::mach8_ec1_w),m_vga)); + m_isa->install16_device(0x56ec, 0x56ef, 0, 0, read16_delegate(FUNC(mach64_device::mach8_scratch0_r),m_vga), write16_delegate(FUNC(mach64_device::mach8_scratch0_w),m_vga)); + m_isa->install16_device(0x5ae8, 0x5aeb, 0, 0, read16_delegate(FUNC(mach64_device::mach8_ec2_r),m_vga), write16_delegate(FUNC(mach64_device::mach8_ec2_w),m_vga)); + m_isa->install16_device(0x5ee8, 0x5eeb, 0, 0, read16_delegate(FUNC(mach64_device::mach8_ec3_r),m_vga), write16_delegate(FUNC(mach64_device::mach8_ec3_w),m_vga)); + m_isa->install16_device(0x82e8, 0x82eb, 0, 0, read16_delegate(FUNC(mach64_device::ibm8514_currenty_r),m_vga), write16_delegate(FUNC(mach64_device::ibm8514_currenty_w),m_vga)); + m_isa->install16_device(0x86e8, 0x86eb, 0, 0, read16_delegate(FUNC(mach64_device::ibm8514_currentx_r),m_vga), write16_delegate(FUNC(mach64_device::ibm8514_currentx_w),m_vga)); + m_isa->install16_device(0x8ae8, 0x8aeb, 0, 0, read16_delegate(FUNC(mach64_device::ibm8514_desty_r),m_vga), write16_delegate(FUNC(mach64_device::ibm8514_desty_w),m_vga)); + m_isa->install16_device(0x8ee8, 0x8eeb, 0, 0, read16_delegate(FUNC(mach64_device::ibm8514_destx_r),m_vga), write16_delegate(FUNC(mach64_device::ibm8514_destx_w),m_vga)); + m_isa->install16_device(0x92e8, 0x92eb, 0, 0, read16_delegate(FUNC(mach64_device::ibm8514_line_error_r),m_vga), write16_delegate(FUNC(mach64_device::ibm8514_line_error_w),m_vga)); + m_isa->install16_device(0x96e8, 0x96eb, 0, 0, read16_delegate(FUNC(mach64_device::ibm8514_width_r),m_vga), write16_delegate(FUNC(mach64_device::ibm8514_width_w),m_vga)); + m_isa->install16_device(0x96ec, 0x96ef, 0, 0, read16_delegate(FUNC(mach64_device::mach8_bresenham_count_r),m_vga), write16_delegate(FUNC(mach64_device::mach8_bresenham_count_w),m_vga)); + m_isa->install16_device(0x9ae8, 0x9aeb, 0, 0, read16_delegate(FUNC(mach64_device::ibm8514_gpstatus_r),m_vga), write16_delegate(FUNC(mach64_device::ibm8514_cmd_w),m_vga)); + m_isa->install16_device(0x9aec, 0x9aef, 0, 0, read16_delegate(FUNC(mach64_device::mach8_ext_fifo_r),m_vga), write16_delegate(FUNC(mach64_device::mach8_linedraw_index_w),m_vga)); + m_isa->install16_device(0x9ee8, 0x9eeb, 0, 0, read16_delegate(FUNC(mach64_device::ibm8514_ssv_r),m_vga), write16_delegate(FUNC(mach64_device::ibm8514_ssv_w),m_vga)); + m_isa->install16_device(0xa2e8, 0xa2eb, 0, 0, read16_delegate(FUNC(mach64_device::ibm8514_bgcolour_r),m_vga), write16_delegate(FUNC(mach64_device::ibm8514_bgcolour_w),m_vga)); + m_isa->install16_device(0xa6e8, 0xa6eb, 0, 0, read16_delegate(FUNC(mach64_device::ibm8514_fgcolour_r),m_vga), write16_delegate(FUNC(mach64_device::ibm8514_fgcolour_w),m_vga)); + m_isa->install16_device(0xaae8, 0xaaeb, 0, 0, read16_delegate(FUNC(mach64_device::ibm8514_write_mask_r),m_vga), write16_delegate(FUNC(mach64_device::ibm8514_write_mask_w),m_vga)); + m_isa->install16_device(0xaee8, 0xaeeb, 0, 0, read16_delegate(FUNC(mach64_device::ibm8514_read_mask_r),m_vga), write16_delegate(FUNC(mach64_device::ibm8514_read_mask_w),m_vga)); + m_isa->install16_device(0xb6e8, 0xb6eb, 0, 0, read16_delegate(FUNC(mach64_device::ibm8514_backmix_r),m_vga), write16_delegate(FUNC(mach64_device::ibm8514_backmix_w),m_vga)); + m_isa->install16_device(0xbae8, 0xbaeb, 0, 0, read16_delegate(FUNC(mach64_device::ibm8514_foremix_r),m_vga), write16_delegate(FUNC(mach64_device::ibm8514_foremix_w),m_vga)); + m_isa->install16_device(0xbee8, 0xbeeb, 0, 0, read16_delegate(FUNC(mach64_device::ibm8514_multifunc_r),m_vga), write16_delegate(FUNC(mach64_device::ibm8514_multifunc_w),m_vga)); + m_isa->install16_device(0xe2e8, 0xe2eb, 0, 0, read16_delegate(FUNC(mach64_device::ibm8514_pixel_xfer_r),m_vga), write16_delegate(FUNC(mach64_device::ibm8514_pixel_xfer_w),m_vga)); + m_isa->install16_device(0xdaec, 0xdaef, 0, 0, read16_delegate(FUNC(mach64_device::mach8_sourcex_r),m_vga), write16_delegate(FUNC(mach64_device::mach8_ext_leftscissor_w),m_vga)); + m_isa->install16_device(0xdeec, 0xdeef, 0, 0, read16_delegate(FUNC(mach64_device::mach8_sourcey_r),m_vga), write16_delegate(FUNC(mach64_device::mach8_ext_topscissor_w),m_vga)); + m_isa->install16_device(0xfaec, 0xfaef, 0, 0, read16_delegate(FUNC(mach64_device::mach32_chipid_r),m_vga), write16_delegate()); + m_isa->install16_device(0xfeec, 0xfeef, 0, 0, read16_delegate(FUNC(mach64_device::mach8_linedraw_r),m_vga), write16_delegate(FUNC(mach64_device::mach8_linedraw_w),m_vga)); + + m_isa->install_memory(0xa0000, 0xbffff, 0, 0, read8_delegate(FUNC(mach64_device::mem_r),m_vga), write8_delegate(FUNC(mach64_device::mem_w),m_vga)); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void isa16_vga_gfxultra_device::device_reset() +{ +} + +void isa16_vga_gfxultrapro_device::device_reset() +{ +} + +void isa16_vga_mach64_device::device_reset() +{ +} diff --git a/src/devices/bus/isa/vga_ati.h b/src/devices/bus/isa/vga_ati.h new file mode 100644 index 00000000000..94c5167f1d5 --- /dev/null +++ b/src/devices/bus/isa/vga_ati.h @@ -0,0 +1,97 @@ +// license:BSD-3-Clause +// copyright-holders:Barry Rodewald +/* + * isa_vga_ati.h + * + * Header for ATi Graphics Ultra/Graphics Ultra Pro ISA video cards + * + * Created on: 9/09/2012 + */ +#pragma once + +#ifndef ISA_VGA_ATI_H_ +#define ISA_VGA_ATI_H_ + +#include "emu.h" +#include "isa.h" +#include "video/pc_vga.h" +#include "mach32.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> isa16_vga_device + +class isa16_vga_gfxultra_device : + public device_t, + public device_isa16_card_interface +{ +public: + // construction/destruction + isa16_vga_gfxultra_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual const rom_entry *device_rom_region() const; + + DECLARE_READ8_MEMBER(input_port_0_r); +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); +private: + ati_vga_device *m_vga; + mach8_device *m_8514; +}; + +class isa16_vga_gfxultrapro_device : + public device_t, + public device_isa16_card_interface +{ +public: + // construction/destruction + isa16_vga_gfxultrapro_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual const rom_entry *device_rom_region() const; + + DECLARE_READ8_MEMBER(input_port_0_r); +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); +private: + mach32_device *m_vga; +}; + +class isa16_vga_mach64_device : + public device_t, + public device_isa16_card_interface +{ +public: + // construction/destruction + isa16_vga_mach64_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual const rom_entry *device_rom_region() const; + + DECLARE_READ8_MEMBER(input_port_0_r); +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); +private: + mach64_device *m_vga; +}; + + +// device type definition +extern const device_type ISA16_VGA_GFXULTRA; +extern const device_type ISA16_SVGA_GFXULTRAPRO; +extern const device_type ISA16_SVGA_MACH64; + + +#endif /* ISA_VGA_ATI_H_ */ diff --git a/src/devices/bus/isa/wd1002a_wx1.c b/src/devices/bus/isa/wd1002a_wx1.c new file mode 100644 index 00000000000..29df9cec729 --- /dev/null +++ b/src/devices/bus/isa/wd1002a_wx1.c @@ -0,0 +1,70 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Western Digital WD1002A-WX1 Winchester Disk Controller emulation + +**********************************************************************/ + +#include "wd1002a_wx1.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type ISA8_WD1002A_WX1 = &device_creator; + + +//------------------------------------------------- +// ROM( wd1002a_wx1 ) +//------------------------------------------------- + +ROM_START( wd1002a_wx1 ) + ROM_REGION( 0x2000, "wd1002a_wx1", 0 ) + ROM_LOAD( "600693-001 type 5.u12", 0x0000, 0x2000, CRC(f3daf85f) SHA1(3bd29538832d3084cbddeec92593988772755283) ) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *isa8_wd1002a_wx1_device::device_rom_region() const +{ + return ROM_NAME( wd1002a_wx1 ); +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// isa8_wd1002a_wx1_device - constructor +//------------------------------------------------- + +isa8_wd1002a_wx1_device::isa8_wd1002a_wx1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, ISA8_WD1002A_WX1, "WD1002A-WX1", tag, owner, clock, "wd1002a_wx1", __FILE__), + device_isa8_card_interface( mconfig, *this ) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void isa8_wd1002a_wx1_device::device_start() +{ +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void isa8_wd1002a_wx1_device::device_reset() +{ +} diff --git a/src/devices/bus/isa/wd1002a_wx1.h b/src/devices/bus/isa/wd1002a_wx1.h new file mode 100644 index 00000000000..d328fb0f16b --- /dev/null +++ b/src/devices/bus/isa/wd1002a_wx1.h @@ -0,0 +1,46 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Western Digital WD1002A-WX1 Winchester Disk Controller emulation + +**********************************************************************/ + +#pragma once + +#ifndef __ISA_WD1002A_WX1__ +#define __ISA_WD1002A_WX1__ + +#include "emu.h" +#include "isa.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> isa16_ide_device + +class isa8_wd1002a_wx1_device : public device_t, + public device_isa8_card_interface +{ +public: + // construction/destruction + isa8_wd1002a_wx1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); +}; + + +// device type definition +extern const device_type ISA8_WD1002A_WX1; + + +#endif diff --git a/src/devices/bus/isa/wdxt_gen.c b/src/devices/bus/isa/wdxt_gen.c new file mode 100644 index 00000000000..abd262cd918 --- /dev/null +++ b/src/devices/bus/isa/wdxt_gen.c @@ -0,0 +1,376 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Western Digital WDXT-GEN ISA XT MFM Hard Disk Controller + +**********************************************************************/ + +/* + +PCB Layout +---------- + +ASSY 61-000222-00 + +|-------------------------------------------| +| CN2 CN1 | +| CN3 7406 TMM2016 | +| LS38 LS14 | +| MC3486 | +| WD1015 WD11C00 | +| 33.04MHz | +| MC3487 | +| WD2010 LS244 | +| WD10C20 | +| LS260 LS13 ROM | +| | +|---| |---| + |-----------------------------------| + +Notes: + All IC's shown. + + ROM - Toshiba TMM2464AP 8Kx8 ROM "3" + TMM2016 - Toshiba TMM2016BP-10 2Kx8 SRAM + WD1015 - Western Digital WD1015-PL-54-02 Buffer Manager Control Processor + WD11C00 - Western Digital WD11C00L-JT-17-02 PC/XT Host Interface Logic Device + WD10C20 - Western Digital WD10C20B-PH-05-05 Self-Adjusting Data Separator + WD2010 - Western Digital WD2010A-PL-05-02 Winchester Disk Controller + CN1 - 2x17 pin PCB header, control + CN2 - 2x10 pin PCB header, drive 0 data + CN3 - 2x10 pin PCB header, drive 1 data + +*/ + +#include "wdxt_gen.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define WD1015_TAG "u6" +#define WD11C00_17_TAG "u11" +#define WD2010A_TAG "u7" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type ISA8_WDXT_GEN = &device_creator; + + +//------------------------------------------------- +// ROM( wdxt_gen ) +//------------------------------------------------- + +ROM_START( wdxt_gen ) + ROM_REGION( 0x800, WD1015_TAG, 0 ) + ROM_LOAD( "wd1015-pl-54-02.u6", 0x000, 0x800, CRC(116e0608) SHA1(bcbd6b39c5a7e16e3bae9372b53d54d6761ba6bc) ) + + ROM_REGION( 0x2000, "hdc", 0 ) + ROM_LOAD( "3.u13", 0x0000, 0x2000, CRC(fbcb5f91) SHA1(8c22bd664177eb6126f3011eda8c5655fffe0ef2) ) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *wdxt_gen_device::device_rom_region() const +{ + return ROM_NAME( wdxt_gen ); +} + + +//------------------------------------------------- +// ADDRESS_MAP( wd1015_io ) +//------------------------------------------------- + +static ADDRESS_MAP_START( wd1015_io, AS_IO, 8, wdxt_gen_device ) + AM_RANGE(0x00, 0xff) AM_DEVREADWRITE(WD11C00_17_TAG, wd11c00_17_device, read, write) + AM_RANGE(MCS48_PORT_T0, MCS48_PORT_T0) AM_READ(wd1015_t0_r) + AM_RANGE(MCS48_PORT_T1, MCS48_PORT_T1) AM_READ(wd1015_t1_r) + AM_RANGE(MCS48_PORT_P1, MCS48_PORT_P1) AM_READWRITE(wd1015_p1_r, wd1015_p1_w) + AM_RANGE(MCS48_PORT_P2, MCS48_PORT_P2) AM_READWRITE(wd1015_p2_r, wd1015_p2_w) +ADDRESS_MAP_END + + +//------------------------------------------------- +// WD11C00_17_INTERFACE( host_intf ) +//------------------------------------------------- + +WRITE_LINE_MEMBER( wdxt_gen_device::irq5_w ) +{ + m_isa->irq5_w(state); +} + +WRITE_LINE_MEMBER( wdxt_gen_device::drq3_w ) +{ + m_isa->drq3_w(state); +} + +WRITE_LINE_MEMBER( wdxt_gen_device::mr_w ) +{ + if (state == ASSERT_LINE) + { + device_reset(); + } +} + +READ8_MEMBER( wdxt_gen_device::rd322_r ) +{ + return 0xff; +} + +READ8_MEMBER( wdxt_gen_device::ram_r ) +{ + return m_ram[offset]; +} + +WRITE8_MEMBER( wdxt_gen_device::ram_w ) +{ + m_ram[offset] = data; +} + +//------------------------------------------------- +// MACHINE_DRIVER( wdxt_gen ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( wdxt_gen ) + MCFG_CPU_ADD(WD1015_TAG, I8049, 5000000) + MCFG_CPU_IO_MAP(wd1015_io) + + MCFG_DEVICE_ADD(WD11C00_17_TAG, WD11C00_17, 5000000) + MCFG_WD11C00_17_OUT_IRQ5_CB(WRITELINE(wdxt_gen_device, irq5_w)) + MCFG_WD11C00_17_OUT_DRQ3_CB(WRITELINE(wdxt_gen_device, drq3_w)) + MCFG_WD11C00_17_OUT_MR_CB(WRITELINE(wdxt_gen_device, mr_w)) + MCFG_WD11C00_17_OUT_RA3_CB(INPUTLINE(WD1015_TAG, MCS48_INPUT_IRQ)) + MCFG_WD11C00_17_IN_RD322_CB(READ8(wdxt_gen_device, rd322_r)) + MCFG_WD11C00_17_IN_RAMCS_CB(READ8(wdxt_gen_device, ram_r)) + MCFG_WD11C00_17_OUT_RAMWR_CB(WRITE8(wdxt_gen_device, ram_w)) + MCFG_WD11C00_17_IN_CS1010_CB(DEVREAD8(WD2010A_TAG, wd2010_device, read)) + MCFG_WD11C00_17_OUT_CS1010_CB(DEVWRITE8(WD2010A_TAG, wd2010_device, write)) + MCFG_DEVICE_ADD(WD2010A_TAG, WD2010, 5000000) + MCFG_WD2010_OUT_BCR_CB(DEVWRITELINE(WD11C00_17_TAG, wd11c00_17_device, clct_w)) + MCFG_WD2010_IN_BCS_CB(DEVREAD8(WD11C00_17_TAG, wd11c00_17_device, read)) + MCFG_WD2010_OUT_BCS_CB(DEVWRITE8(WD11C00_17_TAG, wd11c00_17_device, write)) + MCFG_WD2010_IN_DRDY_CB(VCC) + MCFG_WD2010_IN_INDEX_CB(VCC) + MCFG_WD2010_IN_WF_CB(VCC) + MCFG_WD2010_IN_TK000_CB(VCC) + MCFG_WD2010_IN_SC_CB(VCC) + + MCFG_HARDDISK_ADD("hard0") + MCFG_HARDDISK_ADD("hard1") +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor wdxt_gen_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( wdxt_gen ); +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// wdxt_gen_device - constructor +//------------------------------------------------- + +wdxt_gen_device::wdxt_gen_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, ISA8_WDXT_GEN, "Western Digital WDXT-GEN (Amstrad PC1512/1640)", tag, owner, clock, "wdxt_gen", __FILE__), + device_isa8_card_interface(mconfig, *this), + m_maincpu(*this, WD1015_TAG), + m_host(*this, WD11C00_17_TAG), + m_hdc(*this, WD2010A_TAG) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void wdxt_gen_device::device_start() +{ + set_isa_device(); + m_isa->install_rom(this, 0xc8000, 0xc9fff, 0, 0, "hdc", "hdc"); + m_isa->install_device(0x0320, 0x0323, 0, 0, READ8_DEVICE_DELEGATE(m_host, wd11c00_17_device, io_r), WRITE8_DEVICE_DELEGATE(m_host, wd11c00_17_device, io_w)); + m_isa->set_dma_channel(3, this, FALSE); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void wdxt_gen_device::device_reset() +{ + m_maincpu->set_input_line(INPUT_LINE_RESET, ASSERT_LINE); + m_maincpu->set_input_line(INPUT_LINE_RESET, CLEAR_LINE); +} + + +//------------------------------------------------- +// dack_r - +//------------------------------------------------- + +UINT8 wdxt_gen_device::dack_r(int line) +{ + return m_host->dack_r(); +} + + +//------------------------------------------------- +// dack_w - +//------------------------------------------------- + +void wdxt_gen_device::dack_w(int line, UINT8 data) +{ + m_host->dack_w(data); +} + +//------------------------------------------------- +// wd1015_t0_r - +//------------------------------------------------- + +READ8_MEMBER( wdxt_gen_device::wd1015_t0_r ) +{ + return m_host->busy_r(); +} + + +//------------------------------------------------- +// wd1015_t1_r - +//------------------------------------------------- + +READ8_MEMBER( wdxt_gen_device::wd1015_t1_r ) +{ + return 0; // TODO +} + + +//------------------------------------------------- +// wd1015_p1_r - +//------------------------------------------------- + +READ8_MEMBER( wdxt_gen_device::wd1015_p1_r ) +{ + /* + + bit description + + P10 + P11 + P12 + P13 + P14 + P15 + P16 + P17 + + */ + + UINT8 data = 0; + + logerror("%s P1 read %02x\n", machine().describe_context(), data); + + return data; +} + + +//------------------------------------------------- +// wd1015_p1_w - +//------------------------------------------------- + +WRITE8_MEMBER( wdxt_gen_device::wd1015_p1_w ) +{ + /* + + bit description + + P10 HSEL0 + P11 HSEL1 + P12 HSEL2 + P13 _DSEL0 + P14 _DSEL1 + P15 + P16 IREQ + P17 _DIRIN + + */ + + logerror("%s P1 %02x\n", machine().describe_context(), data); + + m_host->ireq_w(BIT(data, 6)); +} + + +//------------------------------------------------- +// wd1015_p2_r - +//------------------------------------------------- + +READ8_MEMBER( wdxt_gen_device::wd1015_p2_r ) +{ + /* + + bit description + + P20 + P21 + P22 + P23 + P24 + P25 + P26 TK000 + P27 ECC NOT 0 + + */ + + UINT8 data = 0x40; + + data |= m_host->ecc_not_0_r() << 7; + + logerror("%s P2 read %02x\n", machine().describe_context(), data); + + return data; +} + + +//------------------------------------------------- +// wd1015_p2_w - +//------------------------------------------------- + +WRITE8_MEMBER( wdxt_gen_device::wd1015_p2_w ) +{ + /* + + bit description + + P20 STEP + P21 ? + P22 MODE? + P23 ? + P24 ? + P25 ? + P26 + P27 + + */ + + logerror("%s P2 %02x\n", machine().describe_context(), data); + + m_host->mode_w(BIT(data, 2)); +} diff --git a/src/devices/bus/isa/wdxt_gen.h b/src/devices/bus/isa/wdxt_gen.h new file mode 100644 index 00000000000..dae157cba89 --- /dev/null +++ b/src/devices/bus/isa/wdxt_gen.h @@ -0,0 +1,85 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Western Digital WDXT-GEN ISA XT MFM Hard Disk Controller + +********************************************************************** + + Emulated here is the variant supplied with Amstrad PC1512/1640, + which has a custom BIOS and is coupled with a Tandom TM262 HDD. + + chdman -createblankhd tandon_tm262.chd 615 4 17 512 + +**********************************************************************/ + +#pragma once + +#ifndef __ISA8_WDXT_GEN__ +#define __ISA8_WDXT_GEN__ + + +#include "emu.h" +#include "cpu/mcs48/mcs48.h" +#include "isa.h" +#include "machine/wd11c00_17.h" +#include "machine/wd2010.h" +#include "imagedev/harddriv.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> wdxt_gen_device + +class wdxt_gen_device : public device_t, + public device_isa8_card_interface +{ +public: + // construction/destruction + wdxt_gen_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual const rom_entry *device_rom_region() const; + + // not really public + DECLARE_WRITE_LINE_MEMBER( irq5_w ); + DECLARE_WRITE_LINE_MEMBER( drq3_w ); + DECLARE_WRITE_LINE_MEMBER( mr_w ); + DECLARE_READ8_MEMBER( rd322_r ); + DECLARE_READ8_MEMBER( ram_r ); + DECLARE_WRITE8_MEMBER( ram_w ); + DECLARE_READ8_MEMBER( wd1015_t0_r ); + DECLARE_READ8_MEMBER( wd1015_t1_r ); + DECLARE_READ8_MEMBER( wd1015_p1_r ); + DECLARE_WRITE8_MEMBER( wd1015_p1_w ); + DECLARE_READ8_MEMBER( wd1015_p2_r ); + DECLARE_WRITE8_MEMBER( wd1015_p2_w ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_isa8_card_interface + virtual UINT8 dack_r(int line); + virtual void dack_w(int line, UINT8 data); + +private: + required_device m_maincpu; + required_device m_host; + required_device m_hdc; + + UINT8 m_ram[0x800]; + + //UINT8 m_hdc_addr; +}; + + +// device type definition +extern const device_type ISA8_WDXT_GEN; + +#endif diff --git a/src/devices/bus/isa/xsu_cards.c b/src/devices/bus/isa/xsu_cards.c new file mode 100644 index 00000000000..1a24062a9d1 --- /dev/null +++ b/src/devices/bus/isa/xsu_cards.c @@ -0,0 +1,66 @@ +// license:BSD-3-Clause +// copyright-holders:Sergey Svishchev +/********************************************************************** + + ISA bus cards for ex-USSR PC clones + +**********************************************************************/ + +#include "isa_cards.h" +#include "xsu_cards.h" + +SLOT_INTERFACE_START( p1_isa8_cards ) + SLOT_INTERFACE("rom", P1_ROM) // B003 + SLOT_INTERFACE("fdc", P1_FDC) // B504 + SLOT_INTERFACE("hdc", P1_HDC) // B942 +/* + SLOT_INTERFACE("comlpt", P1_COMLPT) // B620 + SLOT_INTERFACE("joy", P1_JOY) // B621 + SLOT_INTERFACE("mouse", P1_MOUSE) // B943 + SLOT_INTERFACE("lan", P1_LAN) // B944 +*/ + SLOT_INTERFACE("pccom", ISA8_COM) + SLOT_INTERFACE("pclpt", ISA8_LPT) + SLOT_INTERFACE("xtide", ISA8_XTIDE) +SLOT_INTERFACE_END + +SLOT_INTERFACE_START( mc1502_isa8_cards ) + SLOT_INTERFACE("cga_mc1502", ISA8_CGA_MC1502) + + SLOT_INTERFACE("rom", MC1502_ROM) + SLOT_INTERFACE("fdc", MC1502_FDC) +/* + SLOT_INTERFACE("hdc", MC1502_HDC) +*/ + SLOT_INTERFACE("pccom", ISA8_COM) + SLOT_INTERFACE("pclpt", ISA8_LPT) + SLOT_INTERFACE("xtide", ISA8_XTIDE) +SLOT_INTERFACE_END + +SLOT_INTERFACE_START( ec184x_isa8_cards ) + SLOT_INTERFACE("ec1840.0002", ISA8_EC1840_0002) // MDA with downloadable font + SLOT_INTERFACE("ec1841.0002", ISA8_EC1841_0002) // CGA with downloadable font + SLOT_INTERFACE("ec1841.0003", ISA8_FDC_XT) +/* + SLOT_INTERFACE("ec1841.0010", ISA8_EC1841_0010) // 8089-based HDC + SLOT_INTERFACE("ec1841.0003", ISA8_EC1841_0003) // FDC + mouse port + SLOT_INTERFACE("ec1841.0004", ISA8_EC1841_0004) // BSC-like serial ports + parallel port +*/ + SLOT_INTERFACE("mda", ISA8_MDA) + SLOT_INTERFACE("hdc", ISA8_HDC_EC1841) + SLOT_INTERFACE("pccom", ISA8_COM) + SLOT_INTERFACE("pclpt", ISA8_LPT) + SLOT_INTERFACE("xtide", ISA8_XTIDE) +SLOT_INTERFACE_END + +SLOT_INTERFACE_START( iskr103x_isa8_cards ) + SLOT_INTERFACE("cga_iskr1030m", ISA8_CGA_ISKR1030M) + SLOT_INTERFACE("cga_iskr1031", ISA8_CGA_ISKR1031) +/**/ + SLOT_INTERFACE("fdc_xt", ISA8_FDC_XT) + SLOT_INTERFACE("mda", ISA8_MDA) + SLOT_INTERFACE("hdc", ISA8_HDC) + SLOT_INTERFACE("pccom", ISA8_COM) + SLOT_INTERFACE("pclpt", ISA8_LPT) + SLOT_INTERFACE("xtide", ISA8_XTIDE) +SLOT_INTERFACE_END diff --git a/src/devices/bus/isa/xsu_cards.h b/src/devices/bus/isa/xsu_cards.h new file mode 100644 index 00000000000..8ddd30f173d --- /dev/null +++ b/src/devices/bus/isa/xsu_cards.h @@ -0,0 +1,37 @@ +// license:BSD-3-Clause +// copyright-holders:Sergey Svishchev +/********************************************************************** + + ISA bus cards for ex-USSR PC clones + +**********************************************************************/ + +#pragma once + +#ifndef __XSU_CARDS_H__ +#define __XSU_CARDS_H__ + +#include "emu.h" + +#include "cga.h" +// storage +#include "mc1502_fdc.h" +#include "p1_fdc.h" +#include "p1_hdc.h" + +// misc +#include "mc1502_rom.h" +#include "p1_rom.h" + +// non-native +#include "com.h" +#include "xtide.h" +#include "lpt.h" + +// supported devices +SLOT_INTERFACE_EXTERN( p1_isa8_cards ); +SLOT_INTERFACE_EXTERN( mc1502_isa8_cards ); +SLOT_INTERFACE_EXTERN( ec184x_isa8_cards ); +SLOT_INTERFACE_EXTERN( iskr103x_isa8_cards ); + +#endif // __XSU_CARDS_H__ diff --git a/src/devices/bus/isa/xtide.c b/src/devices/bus/isa/xtide.c new file mode 100644 index 00000000000..bde729cc012 --- /dev/null +++ b/src/devices/bus/isa/xtide.c @@ -0,0 +1,333 @@ +// license:BSD-3-Clause +// copyright-holders:Phill Harvey-Smith +/*************************************************************************** + +The XT-IDE project is a Vintage Computer forum driven project to develop and manufacturer an 8-bit ISA IDE controller. +It allows any PC/XT class machine to use modern IDE hard drives or Compact Flash devices for long term storage. + +http://www.vintage-computer.com/vcforum/showwiki.php?title=XTIDE+project + +Card has jumpers for I/O base address, and ROM base address, the default +rom images being we'll emulate an I/O base of 0x300 and a ROM base of 0xC8000. + +If the I/O address is changed then you will need to use XTIDECFG to configure the ROM. +The opensource bios is available from : +http://code.google.com/p/xtideuniversalbios/ + +The data high register is connected to a pair of latches that have the MSB of +the 16 bit data word latched into so that 16 bit IO may be performmed, this +involves the following : + +A Data read will read the data register first, and obtain the bottom 8 bits +of the data word, the top 8 bits will be latched at the same time these are +then read from the latch to the processor. + +A data write will first write the top 8 bits to the latch, and then the bottom +8 bits to the normal data register, this will also transfer the top 8 bits to +the drive. + +A modded r1 has A0 & A3 swapped, AKA chuckmod, which puts the high & low bytes together. +This also affects the eeprom, so the BIOS would need to be shuffled (or the plain images flashed using XTIDECFG). + +IDE Register XTIDE rev 1 rev 2 or modded rev 1 +Data (XTIDE Data Low) 0 0 +Error (in), Features (out) 1 8 +Sector Count 2 2 +Sector Number, +LBA bits 0...7, +LBA48 bits 24...31 3 10 +Low Cylinder, +LBA bits 8...15, +LBA48 bits 32...39 4 4 +High Cylinder, +LBA bits 16...23, +LBA48 bits 40...47 5 12 +Drive and Head Select, +LBA28 bits 24...27 6 6 +Status (in), Command (out) 7 14 +XTIDE Data High 8 1 +Alternative Status (in), +Device Control (out) 14 7 + +***************************************************************************/ + + + +#include "xtide.h" + + +READ8_MEMBER( xtide_device::read ) +{ + UINT8 result; + + if (offset == 0) + { + UINT16 data16 = m_ata->read_cs0(space, offset & 7, 0xffff); + result = data16 & 0xff; + m_d8_d15_latch = data16 >> 8; + } + else if (offset < 8) + { + result = m_ata->read_cs0(space, offset & 7, 0xff); + } + else if (offset == 8) + { + result = m_d8_d15_latch; + } + else + { + result = m_ata->read_cs1(space, offset & 7, 0xff); + } + +// logerror("%s xtide_device::read: offset=%d, result=%2X\n",device->machine().describe_context(),offset,result); + + return result; +} + +WRITE8_MEMBER( xtide_device::write ) +{ +// logerror("%s xtide_device::write: offset=%d, data=%2X\n",device->machine().describe_context(),offset,data); + + if (offset == 0) + { + // Data register transfer low byte and latched high + UINT16 data16 = (m_d8_d15_latch << 8) | data; + m_ata->write_cs0(space, offset & 7, data16, 0xffff); + } + else if (offset < 8) + { + m_ata->write_cs0(space, offset & 7, data, 0xff); + } + else if (offset == 8) + { + m_d8_d15_latch = data; + } + else + { + m_ata->write_cs1(space, offset & 7, data, 0xff); + } +} + + +WRITE_LINE_MEMBER(xtide_device::ide_interrupt) +{ + switch (m_irq_number) + { + case 0x02: m_isa->irq2_w(state); break; + case 0x03: m_isa->irq3_w(state); break; + case 0x04: m_isa->irq4_w(state); break; + case 0x05: m_isa->irq5_w(state); break; + case 0x07: m_isa->irq7_w(state); break; + } +} + +static MACHINE_CONFIG_FRAGMENT( xtide_config ) + MCFG_ATA_INTERFACE_ADD("ata", ata_devices, "hdd", NULL, false) + MCFG_ATA_INTERFACE_IRQ_HANDLER(WRITELINE(xtide_device, ide_interrupt)) + + MCFG_EEPROM_2864_ADD("eeprom") +MACHINE_CONFIG_END + +static INPUT_PORTS_START( xtide_port ) + PORT_START("BIOS_BASE") + PORT_DIPNAME( 0x0F, 0x02, "XT-IDE ROM base segment") + PORT_DIPSETTING( 0x00, "C000" ) + PORT_DIPSETTING( 0x01, "C400" ) + PORT_DIPSETTING( 0x02, "C800" ) + PORT_DIPSETTING( 0x03, "CC00" ) + PORT_DIPSETTING( 0x04, "D000" ) + PORT_DIPSETTING( 0x05, "D400" ) + PORT_DIPSETTING( 0x06, "D800" ) + PORT_DIPSETTING( 0x07, "DC00" ) + PORT_DIPSETTING( 0x08, "E000" ) + PORT_DIPSETTING( 0x09, "E400" ) + PORT_DIPSETTING( 0x0A, "E800" ) + PORT_DIPSETTING( 0x0B, "EC00" ) + PORT_DIPSETTING( 0x0C, "F000" ) + PORT_DIPSETTING( 0x0D, "F400" ) + PORT_DIPSETTING( 0x0E, "F800" ) + PORT_DIPSETTING( 0x0F, "FC00" ) + + PORT_START("IO_ADDRESS") + PORT_DIPNAME( 0x0F, 0x08, "XT-IDE I/O address") + PORT_DIPSETTING( 0x00, "200" ) + PORT_DIPSETTING( 0x01, "220" ) + PORT_DIPSETTING( 0x02, "240" ) + PORT_DIPSETTING( 0x03, "260" ) + PORT_DIPSETTING( 0x04, "280" ) + PORT_DIPSETTING( 0x05, "2A0" ) + PORT_DIPSETTING( 0x06, "2C0" ) + PORT_DIPSETTING( 0x07, "2E0" ) + PORT_DIPSETTING( 0x08, "300" ) + PORT_DIPSETTING( 0x09, "320" ) + PORT_DIPSETTING( 0x0A, "340" ) + PORT_DIPSETTING( 0x0B, "360" ) + PORT_DIPSETTING( 0x0C, "380" ) + PORT_DIPSETTING( 0x0D, "3A0" ) + PORT_DIPSETTING( 0x0E, "3C0" ) + PORT_DIPSETTING( 0x0F, "3E0" ) + + PORT_START("IRQ") + PORT_DIPNAME( 0x07, 0x05, "XT-IDE IRQ") + PORT_DIPSETTING( 0x02, "IRQ 2" ) + PORT_DIPSETTING( 0x03, "IRQ 3" ) + PORT_DIPSETTING( 0x04, "IRQ 4" ) + PORT_DIPSETTING( 0x05, "IRQ 5" ) + PORT_DIPSETTING( 0x07, "IRQ 7" ) +INPUT_PORTS_END + +ROM_START( xtide ) + ROM_REGION(0x02000,"eeprom", 0) + + ROM_DEFAULT_BIOS("xub200b3xt") + + ROM_SYSTEM_BIOS( 0, "xtide_010", "Hargle's Bios v0.10" ) + ROMX_LOAD( "oprom.bin(v0.10)", 0x000000, 0x002000, CRC(56075ac2) SHA1(f55285a1ed8414c8ddf2364421552e0548cf548f), ROM_BIOS(1) ) + + ROM_SYSTEM_BIOS( 1, "xtide_011", "Hargle's Bios v0.11" ) + ROMX_LOAD( "oprom.bin(v0.11)", 0x000000, 0x002000, CRC(c5fee6c5) SHA1(cc3a015d8d36208d99de8500c962828d2daea939), ROM_BIOS(2) ) + + ROM_SYSTEM_BIOS( 2, "xub110xt", "XTIDE_Universal_BIOS_v1.1.0 (XT)" ) + ROMX_LOAD( "ide_xt.bin(v1.1.0)", 0x000000, 0x002000, CRC(d13f6ae7) SHA1(42c7e7cbf949af718abbd279e9a33680b8428400), ROM_BIOS(3) ) + + ROM_SYSTEM_BIOS( 3, "xub110xtp", "XTIDE_Universal_BIOS_v1.1.0 (XT 80186+)" ) + ROMX_LOAD( "ide_xtp.bin(v1.1.0)", 0x000000, 0x002000, CRC(4dd9124b) SHA1(af9e5742f57cccd16a580efcbda519314afd272d), ROM_BIOS(4) ) + + ROM_SYSTEM_BIOS( 4, "xub110at", "XTIDE_Universal_BIOS_v1.1.0 (AT)" ) + ROMX_LOAD( "ide_at.bin(v1.1.0)", 0x000000, 0x002000, CRC(673ebf69) SHA1(3960c0be39a787e740d14c8667fc09437bd56ff7), ROM_BIOS(5) ) + + ROM_SYSTEM_BIOS( 5, "xub111xt", "XTIDE_Universal_BIOS_v1.1.1 (XT)" ) + ROMX_LOAD( "ide_xt.bin(v1.1.1)", 0x000000, 0x002000, CRC(6c15f095) SHA1(007db7dc16ccbbd9d297e13b81dee4785ac9fa9b), ROM_BIOS(6) ) + + ROM_SYSTEM_BIOS( 6, "xub111xtp", "XTIDE_Universal_BIOS_v1.1.1 (XT 80186+)" ) + ROMX_LOAD( "ide_xtp.bin(v1.1.1)", 0x000000, 0x002000, CRC(3eb1210d) SHA1(1d2e1cd20d548f794c889cdcfa7ebf224d073052), ROM_BIOS(7) ) + + ROM_SYSTEM_BIOS( 7, "xub111at", "XTIDE_Universal_BIOS_v1.1.1 (AT)" ) + ROMX_LOAD( "ide_at.bin(v1.1.1)", 0x000000, 0x002000, CRC(c808b718) SHA1(215903c68784c886a3117662c735a84d203b7858), ROM_BIOS(8) ) + + ROM_SYSTEM_BIOS( 8, "xub113xt", "XTIDE_Universal_BIOS_v1.1.3 (XT)" ) + ROMX_LOAD( "ide_xt.bin(v1.1.3)", 0x000000, 0x002000, CRC(3158452f) SHA1(1363f370196a12c6770de5a76e8daf283b561625), ROM_BIOS(9) ) + + ROM_SYSTEM_BIOS( 9, "xub113xtp", "XTIDE_Universal_BIOS_v1.1.3 (XT 80186+)" ) + ROMX_LOAD( "ide_xtp.bin(v1.1.3)", 0x000000, 0x002000, CRC(d994fa2f) SHA1(68bdc24cc9878a09a77d6420b9565e51bb08e9b1), ROM_BIOS(10) ) + + ROM_SYSTEM_BIOS( 10, "xub113at", "XTIDE_Universal_BIOS_v1.1.3 (AT)" ) + ROMX_LOAD( "ide_at.bin(v1.1.3)", 0x000000, 0x002000, CRC(14ce1ced) SHA1(3eea39ffcb9a796c30f48d12ec8ff13572b3b9dc), ROM_BIOS(11) ) + + ROM_SYSTEM_BIOS( 11, "xub114xt", "XTIDE_Universal_BIOS_v1.1.4 (XT)" ) + ROMX_LOAD( "ide_xt.bin(v1.1.4)", 0x000000, 0x002000, CRC(c73d2dcc) SHA1(335a79be455ef856f2b0c7444fc0b1dfeccc649c), ROM_BIOS(12) ) + + ROM_SYSTEM_BIOS( 12, "xub114at", "XTIDE_Universal_BIOS_v1.1.4 (AT)" ) + ROMX_LOAD( "ide_at.bin(v1.1.4)", 0x000000, 0x002000, CRC(ebb3deda) SHA1(bcab1743e37f5c0a252d7b127b13e64d5c65baf3), ROM_BIOS(13) ) + + ROM_SYSTEM_BIOS( 13, "xub115xt", "XTIDE_Universal_BIOS_v1.1.5 (XT)" ) + ROMX_LOAD( "ide_xt.bin(v1.1.5)", 0x000000, 0x002000, CRC(33a7e0ee) SHA1(b610fd8ea31f5b0568b8b3f2c3ef682be4897a3d), ROM_BIOS(14) ) + + ROM_SYSTEM_BIOS( 14, "xub115xtp", "XTIDE_Universal_BIOS_v1.1.3 (XT 80186+)" ) + ROMX_LOAD( "ide_xtp.bin(v1.1.5)", 0x000000, 0x002000, CRC(44ad9ee9) SHA1(9cd275469703cadb85b6654c56e421a151324ac0), ROM_BIOS(15) ) + + ROM_SYSTEM_BIOS( 15, "xub115at", "XTIDE_Universal_BIOS_v1.1.5 (AT)" ) + ROMX_LOAD( "ide_at.bin(v1.1.5)", 0x000000, 0x002000, CRC(434286ce) SHA1(3fc07d174924e7c48b4758a7ba76ecd5362bd75b), ROM_BIOS(16) ) + + ROM_SYSTEM_BIOS( 16, "xub200b1xt", "XTIDE_Universal_BIOS_v2.0.0_beta1 (XT)" ) + ROMX_LOAD( "ide_xt.bin(v2.0.0_beta1)", 0x000000, 0x002000, CRC(379579e7) SHA1(da5ee7b9c43a55592fe909451d31a6766d0ab977), ROM_BIOS(17) ) + + ROM_SYSTEM_BIOS( 17, "xub200b1xtp", "XTIDE_Universal_BIOS_v2.0.0_beta1 (XT 80186+)" ) + ROMX_LOAD( "ide_xtp.bin(v2.0.0_beta1)", 0x000000, 0x002000, CRC(a887ed63) SHA1(fb33d9e8e8824f61a8d247610d7bd215b7e306b4), ROM_BIOS(18) ) + + ROM_SYSTEM_BIOS( 18, "xub200b1at", "XTIDE_Universal_BIOS_v2.0.0_beta1 (AT)" ) + ROMX_LOAD( "ide_at.bin(v2.0.0_beta1)", 0x000000, 0x002000, CRC(cd2d8791) SHA1(2f831e7701d181d719a777b63dbd61d87036ee21), ROM_BIOS(19) ) + + ROM_SYSTEM_BIOS( 19, "xub200b2xt", "XTIDE_Universal_BIOS_v2.0.0_beta2 (XT)" ) + ROMX_LOAD( "ide_xt.bin(v2.0.0_beta2)", 0x000000, 0x002000, CRC(61ae1143) SHA1(de5f04b71f2614a0c3db6ec01a5dc7546205100a), ROM_BIOS(20) ) + + ROM_SYSTEM_BIOS( 20, "xub200b2xtp", "XTIDE_Universal_BIOS_v2.0.0_beta2 (XT 80186+)" ) + ROMX_LOAD( "ide_xtp.bin(v2.0.0_beta2)", 0x000000, 0x002000, CRC(58883399) SHA1(582718d6dcd8a4367ee86da3201fb966dc4fffcd), ROM_BIOS(21) ) + + ROM_SYSTEM_BIOS( 21, "xub200b2at", "XTIDE_Universal_BIOS_v2.0.0_beta2 (AT)" ) + ROMX_LOAD( "ide_at.bin(v2.0.0_beta2)", 0x000000, 0x002000, CRC(33fe9336) SHA1(723de092af44e2b709b620f3b591ec12bdca53cd), ROM_BIOS(22) ) + + ROM_SYSTEM_BIOS( 22, "xub200b3xt", "XTIDE_Universal_BIOS_v2.0.0_beta3 (XT)" ) + ROMX_LOAD( "ide_xt.bin(v2.0.0_beta3)", 0x000000, 0x002000, CRC(0a8d4bb4) SHA1(509504c1c54842bcd24cdd318bcf6fb0ece09c33), ROM_BIOS(23) ) + + ROM_SYSTEM_BIOS( 23, "xub200b3xtp", "XTIDE_Universal_BIOS_v2.0.0_beta3 (XT 80186+)" ) + ROMX_LOAD( "ide_xtp.bin(v2.0.0_beta3)", 0x000000, 0x002000, CRC(a58658f8) SHA1(f3a4c1dfc8e2b56eeaf0e39aa192125bc05af626), ROM_BIOS(24) ) + + ROM_SYSTEM_BIOS( 24, "xub200b3at", "XTIDE_Universal_BIOS_v2.0.0_beta3 (AT)" ) + ROMX_LOAD( "ide_at.bin(v2.0.0_beta3)", 0x000000, 0x002000, CRC(fc228f41) SHA1(c0053710ebac15284e740889967d73a6657734c7), ROM_BIOS(25) ) +ROM_END + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type ISA8_XTIDE = &device_creator; + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor xtide_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( xtide_config ); +} + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor xtide_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( xtide_port ); +} + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *xtide_device::device_rom_region() const +{ + return ROM_NAME( xtide ); +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// xtide_device - constructor +//------------------------------------------------- + +xtide_device::xtide_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, ISA8_XTIDE, "XT-IDE Fixed Drive Adapter", tag, owner, clock, "isa8_xtide", __FILE__), + device_isa8_card_interface( mconfig, *this ), + m_ata(*this, "ata"), + m_eeprom(*this, "eeprom") +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void xtide_device::device_start() +{ + set_isa_device(); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void xtide_device::device_reset() +{ + int base_address = ((ioport("BIOS_BASE")->read() & 0x0F) * 16 * 1024) + 0xC0000; + int io_address = ((ioport("IO_ADDRESS")->read() & 0x0F) * 0x20) + 0x200; + m_irq_number = (ioport("IRQ")->read() & 0x07); + + m_isa->install_memory(base_address, base_address + 0x1fff, 0, 0, read8_delegate(FUNC(eeprom_parallel_28xx_device::read), &(*m_eeprom)), write8_delegate(FUNC(eeprom_parallel_28xx_device::write), &(*m_eeprom))); + m_isa->install_device(io_address, io_address + 0xf, 0, 0, read8_delegate(FUNC(xtide_device::read), this), write8_delegate(FUNC(xtide_device::write), this)); + + //logerror("xtide_device::device_reset(), bios_base=0x%5X to 0x%5X, I/O=0x%3X, IRQ=%d\n",base_address,base_address + (16*1024) -1 ,io_address,irq); +} diff --git a/src/devices/bus/isa/xtide.h b/src/devices/bus/isa/xtide.h new file mode 100644 index 00000000000..762be607ea3 --- /dev/null +++ b/src/devices/bus/isa/xtide.h @@ -0,0 +1,51 @@ +// license:BSD-3-Clause +// copyright-holders:Phill Harvey-Smith +#pragma once + +#ifndef __XTIDE_H__ +#define __XTIDE_H__ + +#include "emu.h" +#include "machine/ataintf.h" +#include "machine/eeprompar.h" +#include "isa.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class xtide_device : public device_t, + public device_isa8_card_interface +{ +public: + // construction/destruction + xtide_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual ioport_constructor device_input_ports() const; + virtual const rom_entry *device_rom_region() const; + + DECLARE_READ8_MEMBER(read); + DECLARE_WRITE8_MEMBER(write); + DECLARE_WRITE_LINE_MEMBER(ide_interrupt); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_config_complete() { m_shortname = "xtide"; } + +private: + required_device m_ata; + required_device m_eeprom; + + UINT8 m_irq_number; + UINT8 m_d8_d15_latch; +}; + + +// device type definition +extern const device_type ISA8_XTIDE; + +#endif /* __XTIDE__ */ diff --git a/src/devices/bus/isbx/compis_fdc.c b/src/devices/bus/isbx/compis_fdc.c new file mode 100644 index 00000000000..2718f57c78f --- /dev/null +++ b/src/devices/bus/isbx/compis_fdc.c @@ -0,0 +1,181 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + TeleNova Compis Floppy Disk Controller (119 106/1) emulation + +**********************************************************************/ + +#include "compis_fdc.h" + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define I8272_TAG "ic13" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type COMPIS_FDC = &device_creator; + + +//------------------------------------------------- +// floppy_format_type floppy_formats +//------------------------------------------------- + +WRITE_LINE_MEMBER( compis_fdc_device::fdc_irq ) +{ + m_slot->mintr1_w(state); +} + +WRITE_LINE_MEMBER( compis_fdc_device::fdc_drq ) +{ + m_slot->mdrqt_w(state); +} + +FLOPPY_FORMATS_MEMBER( compis_fdc_device::floppy_formats ) + FLOPPY_CPIS_FORMAT +FLOPPY_FORMATS_END + +static SLOT_INTERFACE_START( compis_floppies ) + SLOT_INTERFACE( "525qd", FLOPPY_525_QD ) +SLOT_INTERFACE_END + + +//------------------------------------------------- +// MACHINE_DRIVER( compis_fdc ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( compis_fdc ) + MCFG_I8272A_ADD(I8272_TAG, true) + MCFG_UPD765_INTRQ_CALLBACK(WRITELINE(compis_fdc_device, fdc_irq)) + MCFG_UPD765_DRQ_CALLBACK(WRITELINE(compis_fdc_device, fdc_drq)) + MCFG_FLOPPY_DRIVE_ADD(I8272_TAG":0", compis_floppies, "525qd", compis_fdc_device::floppy_formats) + MCFG_FLOPPY_DRIVE_ADD(I8272_TAG":1", compis_floppies, "525qd", compis_fdc_device::floppy_formats) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor compis_fdc_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( compis_fdc ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// compis_fdc_device - constructor +//------------------------------------------------- + +compis_fdc_device::compis_fdc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, COMPIS_FDC, "Compis FDC", tag, owner, clock, "compis_fdc", __FILE__), + device_isbx_card_interface(mconfig, *this), + m_fdc(*this, I8272_TAG), + m_floppy0(*this, I8272_TAG":0"), + m_floppy1(*this, I8272_TAG":1") +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void compis_fdc_device::device_start() +{ +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void compis_fdc_device::device_reset() +{ + m_fdc->reset(); +} + + +//------------------------------------------------- +// mcs0_r - chip select 0 read +//------------------------------------------------- + +UINT8 compis_fdc_device::mcs0_r(address_space &space, offs_t offset) +{ + UINT8 data = 0xff; + + switch (BIT(offset, 0)) + { + case 0: data = m_fdc->msr_r(space, 0); break; + case 1: data = m_fdc->fifo_r(space, 0); break; + } + + return data; +} + + +//------------------------------------------------- +// mcs0_w - chip select 0 write +//------------------------------------------------- + +void compis_fdc_device::mcs0_w(address_space &space, offs_t offset, UINT8 data) +{ + switch (BIT(offset, 0)) + { + case 1: m_fdc->fifo_w(space, 0, data); break; + } +} + + +//------------------------------------------------- +// mdack_r - DMA acknowledge read +//------------------------------------------------- + +UINT8 compis_fdc_device::mdack_r(address_space &space, offs_t offset) +{ + return m_fdc->dma_r(); +} + + +//------------------------------------------------- +// mdack_w - DMA acknowledge write +//------------------------------------------------- + +void compis_fdc_device::mdack_w(address_space &space, offs_t offset, UINT8 data) +{ + m_fdc->dma_w(data); +} + + +//------------------------------------------------- +// opt0_w - option 0 write +//------------------------------------------------- + +void compis_fdc_device::opt0_w(int state) +{ + m_fdc->tc_w(state); +} + + +//------------------------------------------------- +// opt1_w - option 1 write +//------------------------------------------------- + +void compis_fdc_device::opt1_w(int state) +{ + m_floppy0->get_device()->mon_w(state); + m_floppy1->get_device()->mon_w(state); +} diff --git a/src/devices/bus/isbx/compis_fdc.h b/src/devices/bus/isbx/compis_fdc.h new file mode 100644 index 00000000000..3ccd294a9f8 --- /dev/null +++ b/src/devices/bus/isbx/compis_fdc.h @@ -0,0 +1,65 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + TeleNova Compis Floppy Disk Controller (119 106/1) emulation + +**********************************************************************/ + +#pragma once + +#ifndef __COMPIS_FDC__ +#define __COMPIS_FDC__ + +#include "emu.h" +#include "isbx.h" +#include "formats/cpis_dsk.h" +#include "machine/upd765.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> compis_fdc_device + +class compis_fdc_device : public device_t, + public device_isbx_card_interface +{ +public: + // construction/destruction + compis_fdc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + + DECLARE_WRITE_LINE_MEMBER( fdc_irq ); + DECLARE_WRITE_LINE_MEMBER( fdc_drq ); + DECLARE_FLOPPY_FORMATS( floppy_formats ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_isbx_card_interface overrides + virtual UINT8 mcs0_r(address_space &space, offs_t offset); + virtual void mcs0_w(address_space &space, offs_t offset, UINT8 data); + virtual UINT8 mdack_r(address_space &space, offs_t offset); + virtual void mdack_w(address_space &space, offs_t offset, UINT8 data); + virtual void opt0_w(int state); + virtual void opt1_w(int state); + +private: + required_device m_fdc; + required_device m_floppy0; + required_device m_floppy1; +}; + + +// device type definition +extern const device_type COMPIS_FDC; + + +#endif diff --git a/src/devices/bus/isbx/isbc_218a.c b/src/devices/bus/isbx/isbc_218a.c new file mode 100644 index 00000000000..319fb66a38a --- /dev/null +++ b/src/devices/bus/isbx/isbc_218a.c @@ -0,0 +1,208 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + ISBX 218a with ISBC configuration + +**********************************************************************/ + +#include "isbc_218a.h" + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define I8272_TAG "u14" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type ISBC_218A = &device_creator; + + +//------------------------------------------------- +// floppy_format_type floppy_formats +//------------------------------------------------- + +WRITE_LINE_MEMBER( isbc_218a_device::fdc_irq ) +{ + m_slot->mintr1_w(state); +} + +WRITE_LINE_MEMBER( isbc_218a_device::fdc_drq ) +{ + m_slot->mdrqt_w(state); +} + +FLOPPY_FORMATS_MEMBER( isbc_218a_device::floppy_formats ) + FLOPPY_PC_FORMAT +FLOPPY_FORMATS_END + +static SLOT_INTERFACE_START( isbc_218a_floppies ) + SLOT_INTERFACE( "525dd", FLOPPY_525_DD ) +SLOT_INTERFACE_END + + +//------------------------------------------------- +// MACHINE_DRIVER( isbc_218a ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( isbc_218a ) + MCFG_I8272A_ADD(I8272_TAG, true) + MCFG_UPD765_INTRQ_CALLBACK(WRITELINE(isbc_218a_device, fdc_irq)) + MCFG_UPD765_DRQ_CALLBACK(WRITELINE(isbc_218a_device, fdc_drq)) + MCFG_FLOPPY_DRIVE_ADD(I8272_TAG":0", isbc_218a_floppies, "525dd", isbc_218a_device::floppy_formats) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor isbc_218a_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( isbc_218a ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// isbc_218a_device - constructor +//------------------------------------------------- + +isbc_218a_device::isbc_218a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, ISBC_218A, "ISBX 218a for ISBC", tag, owner, clock, "isbc_218a", __FILE__), + device_isbx_card_interface(mconfig, *this), + m_fdc(*this, I8272_TAG), + m_floppy0(*this, I8272_TAG":0") +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void isbc_218a_device::device_start() +{ +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void isbc_218a_device::device_reset() +{ + m_reset = false; + m_motor = false; +} + + +//------------------------------------------------- +// mcs0_r - chip select 0 read +//------------------------------------------------- + +UINT8 isbc_218a_device::mcs0_r(address_space &space, offs_t offset) +{ + UINT8 data = 0xff; + + switch (BIT(offset, 0)) + { + case 0: data = m_fdc->msr_r(space, 0); break; + case 1: data = m_fdc->fifo_r(space, 0); break; + } + + return data; +} + + +//------------------------------------------------- +// mcs0_w - chip select 0 write +//------------------------------------------------- + +void isbc_218a_device::mcs0_w(address_space &space, offs_t offset, UINT8 data) +{ + switch (BIT(offset, 0)) + { + case 1: m_fdc->fifo_w(space, 0, data); break; + } +} + + +//------------------------------------------------- +// mcs1_r - chip select 1 read +//------------------------------------------------- + +UINT8 isbc_218a_device::mcs1_r(address_space &space, offs_t offset) +{ + UINT8 data = 0xff; + + switch (offset) + { + case 4: data = m_motor; break; + } + + return data; +} + + +//------------------------------------------------- +// mcs1_w - chip select 1 write +//------------------------------------------------- + +void isbc_218a_device::mcs1_w(address_space &space, offs_t offset, UINT8 data) +{ + switch (offset) + { + case 2: + if((data & 1) && m_reset) + m_fdc->soft_reset(); + m_reset = (data & 1) ? false : true; + break; + case 4: + m_motor = data & 1; + m_floppy0->get_device()->mon_w(!(data & 1)); + break; + case 6: m_fdc->tc_w(data & 1); break; + } +} + + +//------------------------------------------------- +// mdack_r - DMA acknowledge read +//------------------------------------------------- + +UINT8 isbc_218a_device::mdack_r(address_space &space, offs_t offset) +{ + return m_fdc->dma_r(); +} + + +//------------------------------------------------- +// mdack_w - DMA acknowledge write +//------------------------------------------------- + +void isbc_218a_device::mdack_w(address_space &space, offs_t offset, UINT8 data) +{ + m_fdc->dma_w(data); +} + + +//------------------------------------------------- +// opt0_w - option 0 write +//------------------------------------------------- + +void isbc_218a_device::opt0_w(int state) +{ + m_fdc->tc_w(state); +} diff --git a/src/devices/bus/isbx/isbc_218a.h b/src/devices/bus/isbx/isbc_218a.h new file mode 100644 index 00000000000..8718c012696 --- /dev/null +++ b/src/devices/bus/isbx/isbc_218a.h @@ -0,0 +1,67 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + ISBX 218a with ISBC configuration + +**********************************************************************/ + +#pragma once + +#ifndef __ISBC_218A__ +#define __ISBC_218A__ + +#include "emu.h" +#include "isbx.h" +#include "formats/pc_dsk.h" +#include "machine/upd765.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> compis_fdc_device + +class isbc_218a_device : public device_t, + public device_isbx_card_interface +{ +public: + // construction/destruction + isbc_218a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + + DECLARE_WRITE_LINE_MEMBER( fdc_irq ); + DECLARE_WRITE_LINE_MEMBER( fdc_drq ); + DECLARE_FLOPPY_FORMATS( floppy_formats ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_isbx_card_interface overrides + virtual UINT8 mcs0_r(address_space &space, offs_t offset); + virtual void mcs0_w(address_space &space, offs_t offset, UINT8 data); + virtual UINT8 mcs1_r(address_space &space, offs_t offset); + virtual void mcs1_w(address_space &space, offs_t offset, UINT8 data); + virtual UINT8 mdack_r(address_space &space, offs_t offset); + virtual void mdack_w(address_space &space, offs_t offset, UINT8 data); + virtual void opt0_w(int state); + +private: + required_device m_fdc; + required_device m_floppy0; + + bool m_reset, m_motor; +}; + + +// device type definition +extern const device_type ISBC_218A; + + +#endif diff --git a/src/devices/bus/isbx/isbx.c b/src/devices/bus/isbx/isbx.c new file mode 100644 index 00000000000..09b7d84b6fd --- /dev/null +++ b/src/devices/bus/isbx/isbx.c @@ -0,0 +1,78 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Intel Multibus I/O Expansion Bus IEEE-P959 (iSBX) emulation + +**********************************************************************/ + +#include "isbx.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type ISBX_SLOT = &device_creator; + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// device_isbx_card_interface - constructor +//------------------------------------------------- + +device_isbx_card_interface::device_isbx_card_interface(const machine_config &mconfig, device_t &device) + : device_slot_card_interface(mconfig, device) +{ + m_slot = dynamic_cast(device.owner()); +} + + +//------------------------------------------------- +// isbx_slot_device - constructor +//------------------------------------------------- + +isbx_slot_device::isbx_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, ISBX_SLOT, "iSBX bus slot", tag, owner, clock, "isbx_slot", __FILE__), + device_slot_interface(mconfig, *this), + m_write_mintr0(*this), + m_write_mintr1(*this), + m_write_mdrqt(*this), + m_write_mwait(*this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void isbx_slot_device::device_start() +{ + m_card = dynamic_cast(get_card_device()); + + // resolve callbacks + m_write_mintr0.resolve_safe(); + m_write_mintr1.resolve_safe(); + m_write_mdrqt.resolve_safe(); + m_write_mwait.resolve_safe(); +} + + +//------------------------------------------------- +// SLOT_INTERFACE( isbx_cards ) +//------------------------------------------------- + +// slot devices +#include "compis_fdc.h" +#include "isbc_218a.h" + +SLOT_INTERFACE_START( isbx_cards ) + SLOT_INTERFACE("fdc", COMPIS_FDC) + SLOT_INTERFACE("fdc_218a", ISBC_218A) +SLOT_INTERFACE_END diff --git a/src/devices/bus/isbx/isbx.h b/src/devices/bus/isbx/isbx.h new file mode 100644 index 00000000000..5124b4fde60 --- /dev/null +++ b/src/devices/bus/isbx/isbx.h @@ -0,0 +1,155 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Intel Multibus I/O Expansion Bus IEEE-P959 (iSBX) emulation + +********************************************************************** + + +12V 1 2 -12V + GND 3 4 +5V + RESET 5 6 MCLK + MA2 7 8 MPST/ + MA1 9 10 reserved + MA0 11 12 MINTR1 + /IOWRT 13 14 MINTR0 + /IORD 15 16 MWAIT/ + GND 17 18 +5V + MD7 19 20 MCS1/ + MD6 21 22 MCS0/ + MD5 23 24 reserved + MD4 25 26 TDMA + MD3 27 28 OPT1 + MD2 29 30 OPT0 + MD1 31 32 MDACK/ + MD0 33 34 MDRQT + GND 35 36 +5V + MDE 37 38 MDF + MDC 39 40 MDD + MDA 41 42 MDB + MD8 43 44 MD9 + +**********************************************************************/ + +#pragma once + +#ifndef __ISBX_SLOT__ +#define __ISBX_SLOT__ + +#include "emu.h" + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_ISBX_SLOT_ADD(_tag, _clock, _slot_intf, _def_slot) \ + MCFG_DEVICE_ADD(_tag, ISBX_SLOT, _clock) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) + + +#define MCFG_ISBX_SLOT_MINTR0_CALLBACK(_mintr0) \ + downcast(device)->set_mintr0_callback(DEVCB_##_mintr0); + +#define MCFG_ISBX_SLOT_MINTR1_CALLBACK(_mintr1) \ + downcast(device)->set_mintr1_callback(DEVCB_##_mintr1); + +#define MCFG_ISBX_SLOT_MDRQT_CALLBACK(_mdrqt) \ + downcast(device)->set_mdrqt_callback(DEVCB_##_mdrqt); + +#define MCFG_ISBX_SLOT_MWAIT_CALLBACK(_mwait) \ + downcast(device)->set_mwait_callback(DEVCB_##_mwait); + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> device_isbx_card_interface + +class isbx_slot_device; + +class device_isbx_card_interface : public device_slot_card_interface +{ +public: + // construction/destruction + device_isbx_card_interface(const machine_config &mconfig, device_t &device); + + virtual UINT8 mcs0_r(address_space &space, offs_t offset) { return 0xff; } + virtual void mcs0_w(address_space &space, offs_t offset, UINT8 data) { } + virtual UINT8 mcs1_r(address_space &space, offs_t offset) { return 0xff; } + virtual void mcs1_w(address_space &space, offs_t offset, UINT8 data) { } + virtual UINT8 mdack_r(address_space &space, offs_t offset) { return 0xff; } + virtual void mdack_w(address_space &space, offs_t offset, UINT8 data) { } + virtual int opt0_r() { return 1; } + virtual void opt0_w(int state) { } + virtual int opt1_r() { return 1; } + virtual void opt1_w(int state) { } + virtual void tdma_w(int state) { } + virtual void mclk_w(int state) { } + +protected: + isbx_slot_device *m_slot; +}; + + +// ======================> isbx_slot_device + +class isbx_slot_device : public device_t, + public device_slot_interface +{ +public: + // construction/destruction + isbx_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + template void set_mintr0_callback(_mintr0 mintr0) { m_write_mintr0.set_callback(mintr0); } + template void set_mintr1_callback(_mintr1 mintr1) { m_write_mintr1.set_callback(mintr1); } + template void set_mdrqt_callback(_mdrqt mdrqt) { m_write_mdrqt.set_callback(mdrqt); } + template void set_mwait_callback(_mwait mwait) { m_write_mwait.set_callback(mwait); } + + // computer interface + DECLARE_READ8_MEMBER( mcs0_r ) { return m_card ? m_card->mcs0_r(space, offset) : 0xff; } + DECLARE_WRITE8_MEMBER( mcs0_w ) { if (m_card) m_card->mcs0_w(space, offset, data); } + DECLARE_READ8_MEMBER( mcs1_r ) { return m_card ? m_card->mcs1_r(space, offset) : 0xff; } + DECLARE_WRITE8_MEMBER( mcs1_w ) { if (m_card) m_card->mcs1_w(space, offset, data); } + DECLARE_READ8_MEMBER( mdack_r ) { return m_card ? m_card->mdack_r(space, offset) : 0xff; } + DECLARE_WRITE8_MEMBER( mdack_w ) { if (m_card) m_card->mdack_w(space, offset, data); } + DECLARE_READ_LINE_MEMBER( mpst_r ) { return m_card == NULL; } + DECLARE_READ_LINE_MEMBER( opt0_r ) { return m_card ? m_card->opt0_r() : 1; } + DECLARE_WRITE_LINE_MEMBER( opt0_w ) { if (m_card) m_card->opt0_w(state); } + DECLARE_READ_LINE_MEMBER( opt1_r ) { return m_card ? m_card->opt1_r() : 1; } + DECLARE_WRITE_LINE_MEMBER( opt1_w ) { if (m_card) m_card->opt1_w(state); } + DECLARE_WRITE_LINE_MEMBER( tdma_w ) { if (m_card) m_card->tdma_w(state); } + DECLARE_WRITE_LINE_MEMBER( mclk_w ) { if (m_card) m_card->mclk_w(state); } + + // card interface + DECLARE_WRITE_LINE_MEMBER( mintr0_w ) { m_write_mintr0(state); } + DECLARE_WRITE_LINE_MEMBER( mintr1_w ) { m_write_mintr1(state); } + DECLARE_WRITE_LINE_MEMBER( mdrqt_w ) { m_write_mdrqt(state); } + DECLARE_WRITE_LINE_MEMBER( mwait_w ) { m_write_mwait(state); } + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset() { if (m_card) get_card_device()->reset(); } + + devcb_write_line m_write_mintr0; + devcb_write_line m_write_mintr1; + devcb_write_line m_write_mdrqt; + devcb_write_line m_write_mwait; + + device_isbx_card_interface *m_card; +}; + + +// device type definition +extern const device_type ISBX_SLOT; + + +SLOT_INTERFACE_EXTERN( isbx_cards ); + + + +#endif diff --git a/src/devices/bus/kc/d002.c b/src/devices/bus/kc/d002.c new file mode 100644 index 00000000000..db93fbf582c --- /dev/null +++ b/src/devices/bus/kc/d002.c @@ -0,0 +1,230 @@ +// license:BSD-3-Clause +// copyright-holders:Sandro Ronco +/*************************************************************************** + + d002.c + + KC85 D002 Bus Driver emulation + +***************************************************************************/ + +#include "emu.h" +#include "d002.h" + +/*************************************************************************** + IMPLEMENTATION +***************************************************************************/ + +static INPUT_PORTS_START( kc_d002 ) + // device ID is selected using 4 jumpers on the board + // 0x00 and 0xf0 should not be used because they are + // reserved for base system and FDC the others + // 14 ID are theoretically usable. + PORT_START("ID") + PORT_DIPNAME( 0xf0, 0x10, "Device ID" ) + PORT_DIPSETTING( 0x00, "0x00" ) // reserved for base system + PORT_DIPSETTING( 0x10, "0x10" ) + PORT_DIPSETTING( 0x20, "0x20" ) + PORT_DIPSETTING( 0x30, "0x30" ) + PORT_DIPSETTING( 0x40, "0x40" ) + PORT_DIPSETTING( 0x50, "0x50" ) + PORT_DIPSETTING( 0x60, "0x60" ) + PORT_DIPSETTING( 0x70, "0x70" ) + PORT_DIPSETTING( 0x80, "0x80" ) + PORT_DIPSETTING( 0x90, "0x90" ) + PORT_DIPSETTING( 0xA0, "0xA0" ) + PORT_DIPSETTING( 0xB0, "0xB0" ) + PORT_DIPSETTING( 0xC0, "0xC0" ) + PORT_DIPSETTING( 0xD0, "0xD0" ) + PORT_DIPSETTING( 0xE0, "0xE0" ) + PORT_DIPSETTING( 0xF0, "0xF0" ) // reserved for FDC D004 +INPUT_PORTS_END + +// defined in drivers/kc.c +SLOT_INTERFACE_EXTERN(kc85_cart); +SLOT_INTERFACE_EXTERN(kc85_exp); + +WRITE_LINE_MEMBER(kc_d002_device::out_irq_w) +{ + m_slot->m_out_irq_cb(state); +} + +WRITE_LINE_MEMBER(kc_d002_device::out_nmi_w) +{ + m_slot->m_out_nmi_cb(state); +} + +WRITE_LINE_MEMBER(kc_d002_device::out_halt_w) +{ + m_slot->m_out_halt_cb(state); +} + +static MACHINE_CONFIG_FRAGMENT( kc_d002 ) + MCFG_DEVICE_ADD("m0", KCCART_SLOT, 0) + MCFG_DEVICE_SLOT_INTERFACE(kc85_cart, NULL, false) + MCFG_KCCART_SLOT_NEXT_SLOT("m4") + MCFG_KCCART_SLOT_OUT_IRQ_CB(WRITELINE(kc_d002_device, out_irq_w)) + MCFG_KCCART_SLOT_OUT_NMI_CB(WRITELINE(kc_d002_device, out_nmi_w)) + MCFG_KCCART_SLOT_OUT_HALT_CB(WRITELINE(kc_d002_device, out_halt_w)) + MCFG_DEVICE_ADD("m4", KCCART_SLOT, 0) + MCFG_DEVICE_SLOT_INTERFACE(kc85_cart, NULL, false) + MCFG_KCCART_SLOT_NEXT_SLOT("m8") + MCFG_KCCART_SLOT_OUT_IRQ_CB(WRITELINE(kc_d002_device, out_irq_w)) + MCFG_KCCART_SLOT_OUT_NMI_CB(WRITELINE(kc_d002_device, out_nmi_w)) + MCFG_KCCART_SLOT_OUT_HALT_CB(WRITELINE(kc_d002_device, out_halt_w)) + MCFG_DEVICE_ADD("m8", KCCART_SLOT, 0) + MCFG_DEVICE_SLOT_INTERFACE(kc85_cart, NULL, false) + MCFG_KCCART_SLOT_NEXT_SLOT("mc") + MCFG_KCCART_SLOT_OUT_IRQ_CB(WRITELINE(kc_d002_device, out_irq_w)) + MCFG_KCCART_SLOT_OUT_NMI_CB(WRITELINE(kc_d002_device, out_nmi_w)) + MCFG_KCCART_SLOT_OUT_HALT_CB(WRITELINE(kc_d002_device, out_halt_w)) + MCFG_DEVICE_ADD("mc", KCCART_SLOT, 0) + MCFG_DEVICE_SLOT_INTERFACE(kc85_cart, NULL, false) + MCFG_KCCART_SLOT_NEXT_SLOT("exp") + MCFG_KCCART_SLOT_OUT_IRQ_CB(WRITELINE(kc_d002_device, out_irq_w)) + MCFG_KCCART_SLOT_OUT_NMI_CB(WRITELINE(kc_d002_device, out_nmi_w)) + MCFG_KCCART_SLOT_OUT_HALT_CB(WRITELINE(kc_d002_device, out_halt_w)) + + // expansion interface + MCFG_DEVICE_ADD("exp", KCCART_SLOT, 0) + MCFG_DEVICE_SLOT_INTERFACE(kc85_exp, NULL, false) + MCFG_KCEXP_SLOT_NEXT_SLOT(NULL) + MCFG_KCEXP_SLOT_OUT_IRQ_CB(WRITELINE(kc_d002_device, out_irq_w)) + MCFG_KCEXP_SLOT_OUT_NMI_CB(WRITELINE(kc_d002_device, out_nmi_w)) + MCFG_KCEXP_SLOT_OUT_HALT_CB(WRITELINE(kc_d002_device, out_halt_w)) +MACHINE_CONFIG_END + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type KC_D002 = &device_creator; + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// kc_d002_device - constructor +//------------------------------------------------- + +kc_d002_device::kc_d002_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, KC_D002, "D002 Bus Driver", tag, owner, clock, "kc_d002", __FILE__), + device_kcexp_interface( mconfig, *this ) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void kc_d002_device::device_start() +{ + m_slot = dynamic_cast(owner()); + + m_expansions[0] = downcast(subdevice("m0")); + m_expansions[1] = downcast(subdevice("m4")); + m_expansions[2] = downcast(subdevice("m8")); + m_expansions[3] = downcast(subdevice("mc")); + m_expansions[4] = downcast(subdevice("exp")); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void kc_d002_device::device_reset() +{ +} + +//------------------------------------------------- +// device_mconfig_additions +//------------------------------------------------- + +machine_config_constructor kc_d002_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( kc_d002 ); +} + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor kc_d002_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( kc_d002 ); +} + +//------------------------------------------------- +// read +//------------------------------------------------- + +void kc_d002_device::read(offs_t offset, UINT8 &data) +{ + for (int i=0; i<5; i++) + m_expansions[i]->read(offset, data); +} + +//------------------------------------------------- +// write +//------------------------------------------------- + +void kc_d002_device::write(offs_t offset, UINT8 data) +{ + for (int i=0; i<5; i++) + m_expansions[i]->write(offset, data); +} + +//------------------------------------------------- +// IO read +//------------------------------------------------- + +void kc_d002_device::io_read(offs_t offset, UINT8 &data) +{ + if ((offset & 0xff) == 0x80) + { + UINT8 slot_id = (offset>>8) & 0xff; + + if ((slot_id & 0xf0) == ioport("ID")->read() && !(slot_id & 0x03)) + data = m_expansions[(slot_id>>2) & 3]->module_id_r(); + else + m_expansions[4]->io_read(offset, data); + } + else + { + for (int i=0; i<5; i++) + m_expansions[i]->io_read(offset, data); + } +} + +//------------------------------------------------- +// IO write +//------------------------------------------------- + +void kc_d002_device::io_write(offs_t offset, UINT8 data) +{ + if ((offset & 0xff) == 0x80) + { + UINT8 slot_id = (offset>>8) & 0xff; + + if ((slot_id & 0xf0) == ioport("ID")->read() && !(slot_id & 0x03)) + m_expansions[(slot_id>>2) & 3]->control_w(data); + else + m_expansions[4]->io_write(offset, data); + } + else + { + for (int i=0; i<5; i++) + m_expansions[i]->io_write(offset, data); + } + +} + +/*------------------------------------------------- + MEI line write +-------------------------------------------------*/ + +WRITE_LINE_MEMBER( kc_d002_device::mei_w ) +{ + m_expansions[0]->mei_w(state); +} diff --git a/src/devices/bus/kc/d002.h b/src/devices/bus/kc/d002.h new file mode 100644 index 00000000000..0f9ebe5f07e --- /dev/null +++ b/src/devices/bus/kc/d002.h @@ -0,0 +1,60 @@ +// license:BSD-3-Clause +// copyright-holders:Sandro Ronco +#pragma once + +#ifndef __KC_D002_H__ +#define __KC_D002_H__ + +#include "emu.h" +#include "kc.h" +#include "ram.h" +#include "rom.h" +#include "d004.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> kc_d002_device + +class kc_d002_device : + public device_t, + public device_kcexp_interface +{ +public: + // construction/destruction + kc_d002_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual ioport_constructor device_input_ports() const; + + // interface callbacks + DECLARE_WRITE_LINE_MEMBER( out_irq_w ); + DECLARE_WRITE_LINE_MEMBER( out_nmi_w ); + DECLARE_WRITE_LINE_MEMBER( out_halt_w ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // kcexp_interface overrides + virtual void read(offs_t offset, UINT8 &data); + virtual void write(offs_t offset, UINT8 data); + virtual void io_read(offs_t offset, UINT8 &data); + virtual void io_write(offs_t offset, UINT8 data); + virtual DECLARE_WRITE_LINE_MEMBER( mei_w ); + +private: + kcexp_slot_device *m_slot; + + // internal state + kcexp_slot_device *m_expansions[5]; +}; + + +// device type definition +extern const device_type KC_D002; + +#endif /* __KC_D002_H__ */ diff --git a/src/devices/bus/kc/d004.c b/src/devices/bus/kc/d004.c new file mode 100644 index 00000000000..de615403d69 --- /dev/null +++ b/src/devices/bus/kc/d004.c @@ -0,0 +1,514 @@ +// license:BSD-3-Clause +// copyright-holders:Sandro Ronco +/*************************************************************************** + + d004.c + + KC85 D004 Floppy Disk Interface + +***************************************************************************/ + +#include "emu.h" +#include "d004.h" +#include "formats/mfi_dsk.h" +#include "formats/kc85_dsk.h" + +#define Z80_TAG "disk" +#define Z80CTC_TAG "z80ctc" +#define UPD765_TAG "upd765" +#define ATA_TAG "ata" + +/*************************************************************************** + IMPLEMENTATION +***************************************************************************/ + +static ADDRESS_MAP_START(kc_d004_mem, AS_PROGRAM, 8, kc_d004_device) + AM_RANGE(0x0000, 0xfbff) AM_RAM + AM_RANGE(0xfc00, 0xffff) AM_RAM AM_SHARE("koppelram") +ADDRESS_MAP_END + +static ADDRESS_MAP_START(kc_d004_io, AS_IO, 8, kc_d004_device) + ADDRESS_MAP_UNMAP_HIGH + ADDRESS_MAP_GLOBAL_MASK(0xff) + AM_RANGE(0xf0, 0xf1) AM_DEVICE(UPD765_TAG, upd765a_device, map) + AM_RANGE(0xf2, 0xf3) AM_DEVREADWRITE(UPD765_TAG, upd765a_device, mdma_r, mdma_w) + AM_RANGE(0xf4, 0xf4) AM_READ(hw_input_gate_r) + AM_RANGE(0xf6, 0xf7) AM_WRITE(fdd_select_w) + AM_RANGE(0xf8, 0xf9) AM_WRITE(hw_terminal_count_w) + AM_RANGE(0xfc, 0xff) AM_DEVREADWRITE(Z80CTC_TAG, z80ctc_device, read, write) +ADDRESS_MAP_END + +static ADDRESS_MAP_START(kc_d004_gide_io, AS_IO, 8, kc_d004_gide_device) + ADDRESS_MAP_UNMAP_HIGH + AM_RANGE(0x00f0, 0x00f1) AM_MIRROR(0xff00) AM_DEVICE(UPD765_TAG, upd765a_device, map) + AM_RANGE(0x00f2, 0x00f3) AM_MIRROR(0xff00) AM_DEVREADWRITE(UPD765_TAG, upd765a_device, mdma_r, mdma_w) + AM_RANGE(0x00f4, 0x00f4) AM_MIRROR(0xff00) AM_READ(hw_input_gate_r) + AM_RANGE(0x00f6, 0x00f7) AM_MIRROR(0xff00) AM_WRITE(fdd_select_w) + AM_RANGE(0x00f8, 0x00f9) AM_MIRROR(0xff00) AM_WRITE(hw_terminal_count_w) + AM_RANGE(0x00fc, 0x00ff) AM_MIRROR(0xff00) AM_DEVREADWRITE(Z80CTC_TAG, z80ctc_device, read, write) + AM_RANGE(0x0000, 0xffff) AM_READWRITE(gide_r, gide_w) +ADDRESS_MAP_END + +FLOPPY_FORMATS_MEMBER( kc_d004_device::floppy_formats ) + FLOPPY_KC85_FORMAT +FLOPPY_FORMATS_END + +static SLOT_INTERFACE_START( kc_d004_floppies ) + SLOT_INTERFACE( "525qd", FLOPPY_525_QD ) +SLOT_INTERFACE_END + +static const z80_daisy_config kc_d004_daisy_chain[] = +{ + { Z80CTC_TAG }, + { NULL } +}; + +static MACHINE_CONFIG_FRAGMENT(kc_d004) + MCFG_CPU_ADD(Z80_TAG, Z80, XTAL_8MHz/2) + MCFG_CPU_PROGRAM_MAP(kc_d004_mem) + MCFG_CPU_IO_MAP(kc_d004_io) + MCFG_CPU_CONFIG(kc_d004_daisy_chain) + + MCFG_DEVICE_ADD(Z80CTC_TAG, Z80CTC, XTAL_8MHz/2) + MCFG_Z80CTC_INTR_CB(INPUTLINE(Z80_TAG, 0)) + MCFG_Z80CTC_ZC0_CB(DEVWRITELINE(Z80CTC_TAG, z80ctc_device, trg1)) + MCFG_Z80CTC_ZC1_CB(DEVWRITELINE(Z80CTC_TAG, z80ctc_device, trg2)) + MCFG_Z80CTC_ZC2_CB(DEVWRITELINE(Z80CTC_TAG, z80ctc_device, trg3)) + + MCFG_UPD765A_ADD(UPD765_TAG, false, false) + MCFG_UPD765_INTRQ_CALLBACK(WRITELINE(kc_d004_device, fdc_irq)) + MCFG_FLOPPY_DRIVE_ADD(UPD765_TAG ":0", kc_d004_floppies, "525qd", kc_d004_device::floppy_formats) + MCFG_FLOPPY_DRIVE_ADD(UPD765_TAG ":1", kc_d004_floppies, "525qd", kc_d004_device::floppy_formats) + MCFG_FLOPPY_DRIVE_ADD(UPD765_TAG ":2", kc_d004_floppies, "525qd", kc_d004_device::floppy_formats) + MCFG_FLOPPY_DRIVE_ADD(UPD765_TAG ":3", kc_d004_floppies, "525qd", kc_d004_device::floppy_formats) +MACHINE_CONFIG_END + +static MACHINE_CONFIG_FRAGMENT(kc_d004_gide) + MCFG_FRAGMENT_ADD(kc_d004) + + MCFG_CPU_MODIFY(Z80_TAG) + MCFG_CPU_IO_MAP(kc_d004_gide_io) + + MCFG_ATA_INTERFACE_ADD(ATA_TAG, ata_devices, "hdd", NULL, false) +MACHINE_CONFIG_END + + +ROM_START( kc_d004 ) + ROM_REGION(0x2000, Z80_TAG, 0) + ROM_LOAD_OPTIONAL("d004v20.bin", 0x0000, 0x2000, CRC(4f3494f1) SHA1(66f476de78fb474d9ac61c6eaffce3354fd66776)) +ROM_END + +ROM_START( kc_d004_gide ) + ROM_REGION(0x2000, Z80_TAG, 0) + ROM_SYSTEM_BIOS(0, "v33_4", "ver 3.3 (KC 85/4)") + ROMX_LOAD("d004v33_4.bin", 0x0000, 0x2000, CRC(1451efd7) SHA1(9db201af408adb02254094dc7aa7185bf5a7b9b1), ROM_BIOS(1) ) // KC85/4-5 + ROM_SYSTEM_BIOS(1, "v33_3", "ver 3.3 (KC 85/3)") + ROMX_LOAD( "d004v33_3.bin", 0x0000, 0x2000, CRC(945f3e4b) SHA1(cce5d9eea82582270660c8275336b15bf9906253), ROM_BIOS(2) ) // KC85/3 + ROM_SYSTEM_BIOS(2, "v30", "ver 3.0") + ROMX_LOAD("d004v30.bin", 0x0000, 0x2000, CRC(6fe0a283) SHA1(5582b2541a34a90c7a9516a6a222d4961fc54fcf), ROM_BIOS(3) ) // KC85/4-5 + ROM_SYSTEM_BIOS(3, "v31", "ver 3.1") + ROMX_LOAD("d004v31.bin", 0x0000, 0x2000, CRC(712547de) SHA1(38b3164dce23573375fc0237f348d9a699fc6f9f), ROM_BIOS(4) ) // KC85/4-5 + ROM_SYSTEM_BIOS(4, "v32", "ver 3.2") + ROMX_LOAD("d004v32.bin", 0x0000, 0x2000, CRC(9a3d3511) SHA1(8232adb5e5f0b25b52f9873cff14831da3a0398a), ROM_BIOS(5) ) // KC85/4-5 +ROM_END + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type KC_D004 = &device_creator; +const device_type KC_D004_GIDE = &device_creator; + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// kc_d004_device - constructor +//------------------------------------------------- + +kc_d004_device::kc_d004_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, KC_D004, "D004 Floppy Disk Interface", tag, owner, clock, "kc_d004", __FILE__), + device_kcexp_interface( mconfig, *this ), + m_cpu(*this, Z80_TAG), + m_fdc(*this, UPD765_TAG), + m_floppy0(*this, UPD765_TAG ":0"), + m_floppy1(*this, UPD765_TAG ":1"), + m_floppy2(*this, UPD765_TAG ":2"), + m_floppy3(*this, UPD765_TAG ":3"), + m_koppel_ram(*this, "koppelram") +{ +} + +kc_d004_device::kc_d004_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_kcexp_interface( mconfig, *this ), + m_cpu(*this, Z80_TAG), + m_fdc(*this, UPD765_TAG), + m_floppy0(*this, UPD765_TAG ":0"), + m_floppy1(*this, UPD765_TAG ":1"), + m_floppy2(*this, UPD765_TAG ":2"), + m_floppy3(*this, UPD765_TAG ":3"), + m_koppel_ram(*this, "koppelram") +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void kc_d004_device::device_start() +{ + m_rom = memregion(Z80_TAG)->base(); + + m_reset_timer = timer_alloc(TIMER_RESET); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void kc_d004_device::device_reset() +{ + m_rom_base = 0xc000; + m_enabled = m_connected = 0; + m_floppy = m_floppy0->get_device(); + + // hold cpu at reset + m_reset_timer->adjust(attotime::zero); +} + +//------------------------------------------------- +// device_mconfig_additions +//------------------------------------------------- + +machine_config_constructor kc_d004_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( kc_d004 ); +} + +//------------------------------------------------- +// device_rom_region +//------------------------------------------------- + +const rom_entry *kc_d004_device::device_rom_region() const +{ + return ROM_NAME( kc_d004 ); +} + +//------------------------------------------------- +// device_timer - handler timer events +//------------------------------------------------- + +void kc_d004_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch(id) + { + case TIMER_RESET: + m_cpu->set_input_line(INPUT_LINE_RESET, ASSERT_LINE); + break; + } +} + +/*------------------------------------------------- + set module status +-------------------------------------------------*/ + +void kc_d004_device::control_w(UINT8 data) +{ + m_enabled = BIT(data, 0); + m_connected = BIT(data, 2); + m_rom_base = (data & 0x20) ? 0xe000 : 0xc000; +} + +/*------------------------------------------------- + read +-------------------------------------------------*/ + +void kc_d004_device::read(offs_t offset, UINT8 &data) +{ + if (offset >= m_rom_base && offset < (m_rom_base + 0x2000) && m_enabled) + data = m_rom[offset & 0x1fff]; +} + +//------------------------------------------------- +// IO read +//------------------------------------------------- + +void kc_d004_device::io_read(offs_t offset, UINT8 &data) +{ + if ((offset & 0xff) == 0x80) + { + UINT8 slot_id = (offset>>8) & 0xff; + + if (slot_id == 0xfc) + data = module_id_r(); + } + else + { + if (m_connected) + { + switch(offset & 0xff) + { + case 0xf0: + case 0xf1: + case 0xf2: + case 0xf3: + data = m_koppel_ram[((offset & 0x03)<<8) | ((offset>>8) & 0xff)]; + break; + } + } + } +} + +//------------------------------------------------- +// IO write +//------------------------------------------------- + +void kc_d004_device::io_write(offs_t offset, UINT8 data) +{ + if ((offset & 0xff) == 0x80) + { + UINT8 slot_id = (offset>>8) & 0xff; + + if (slot_id == 0xfc) + control_w(data); + } + else + { + if (m_connected) + { + switch(offset & 0xff) + { + case 0xf0: + case 0xf1: + case 0xf2: + case 0xf3: + m_koppel_ram[((offset & 0x03)<<8) | ((offset>>8) & 0xff)] = data; + break; + case 0xf4: + if (data & 0x01) + m_cpu->set_input_line(INPUT_LINE_RESET, CLEAR_LINE); + + if (data & 0x02) + { + for (int i=0; i<0xfc00; i++) + m_cpu->space(AS_PROGRAM).write_byte(i, 0); + + m_cpu->set_input_line(INPUT_LINE_RESET, ASSERT_LINE); + } + + if (data & 0x04) + m_cpu->set_input_line(INPUT_LINE_RESET, HOLD_LINE); + + if (data & 0x08) + m_cpu->set_input_line(INPUT_LINE_NMI, HOLD_LINE); + + //printf("D004 CPU state: %x\n", data & 0x0f); + break; + } + } + } +} + +//************************************************************************** +// FDC emulation +//************************************************************************** + +READ8_MEMBER(kc_d004_device::hw_input_gate_r) +{ + /* + bit 7: DMA Request (DRQ from FDC) + bit 6: Interrupt (INT from FDC) + bit 5: Drive Ready + bit 4: Index pulse from disc + */ + + UINT8 hw_input_gate = 0x0f; + + if (m_floppy && !m_floppy->idx_r()) + hw_input_gate |= 0x10; + + if (m_floppy && !m_floppy->ready_r()) + hw_input_gate |= 0x20; + + if (!m_fdc->get_irq()) + hw_input_gate |= 0x40; + + if (!m_fdc->get_drq()) + hw_input_gate |= 0x80; + + return hw_input_gate; +} + +WRITE8_MEMBER(kc_d004_device::fdd_select_w) +{ + if (data & 0x01) + m_floppy = m_floppy0->get_device(); + else if (data & 0x02) + m_floppy = m_floppy1->get_device(); + else if (data & 0x04) + m_floppy = m_floppy2->get_device(); + else if (data & 0x08) + m_floppy = m_floppy3->get_device(); + else + m_floppy = NULL; + + if (m_floppy) + m_floppy->mon_w(0); + + m_fdc->set_floppy(m_floppy); +} + +WRITE8_MEMBER(kc_d004_device::hw_terminal_count_w) +{ + m_fdc->tc_w(true); +} + +WRITE_LINE_MEMBER(kc_d004_device::fdc_irq) +{ + if (state) + m_fdc->tc_w(false); +} + + + +//************************************************************************** +// D004 Floppy Disk + GIDE Interface +//************************************************************************** + +//------------------------------------------------- +// kc_d004_gide_device - constructor +//------------------------------------------------- + +kc_d004_gide_device::kc_d004_gide_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : kc_d004_device(mconfig, KC_D004, "D004 Floppy Disk + GIDE Interface", tag, owner, clock, "kc_d004gide", __FILE__), + m_ata(*this, ATA_TAG) +{ +} + +//------------------------------------------------- +// device_mconfig_additions +//------------------------------------------------- + +machine_config_constructor kc_d004_gide_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( kc_d004_gide ); +} + + +//------------------------------------------------- +// device_rom_region +//------------------------------------------------- + +const rom_entry *kc_d004_gide_device::device_rom_region() const +{ + return ROM_NAME( kc_d004_gide ); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void kc_d004_gide_device::device_reset() +{ + kc_d004_device::device_reset(); + + m_ata_data = 0; + m_lh = 0; +} + +//------------------------------------------------- +// GIDE read +//------------------------------------------------- + +READ8_MEMBER(kc_d004_gide_device::gide_r) +{ + UINT8 data = 0xff; + UINT8 io_addr = offset & 0x0f; + + if (io_addr == 0x05) + { + UINT8 rtc_addr = (offset >> 8) & 0x0f; + + // TODO RTC-72421 + logerror("GIDE %s read RTC 0x%02x\n", tag(), rtc_addr); + data = 0; + } + else + { + int ide_cs = (io_addr & 0x08) ? 0 : ((io_addr == 0x06 || io_addr == 0x07) ? 1 : -1); + + if (ide_cs != -1) + { + int data_shift = 0; + + if (io_addr == 0x08 && m_lh) + data_shift = 8; + + if (io_addr == 0x06 || io_addr == 0x07 || io_addr > 0x08 || (io_addr == 0x08 && !m_lh)) + { + if (ide_cs == 0 ) + { + m_ata_data = m_ata->read_cs0(space, io_addr & 0x07, 0xffff); + } + else + { + m_ata_data = m_ata->read_cs1(space, io_addr & 0x07, 0xffff); + } + } + + data = (m_ata_data >> data_shift) & 0xff; + } + + m_lh = (io_addr == 0x08) ? !m_lh : ((io_addr > 0x08) ? 0 : m_lh); + } + + return data; +} + +//------------------------------------------------- +// GIDE write +//------------------------------------------------- + +WRITE8_MEMBER(kc_d004_gide_device::gide_w) +{ + UINT8 io_addr = offset & 0x0f; + + if (io_addr == 0x05) + { + UINT8 rtc_addr = (offset >> 8) & 0x0f; + + // TODO RTC-72421 + logerror("GIDE %s wrire RTC 0x%02x 0x%02x\n", tag(), rtc_addr, data); + } + else + { + int ide_cs = (io_addr & 0x08) ? 0 : ((io_addr == 0x06 || io_addr == 0x07) ? 1 : -1); + + if (ide_cs != -1) + { + int data_shift = 0; + + if (io_addr == 0x08 && m_lh) + data_shift = 8; + + m_ata_data = (data << data_shift) | (m_ata_data & (0xff00 >> data_shift)); + + if (io_addr == 0x06 || io_addr == 0x07 || io_addr > 0x08 || (io_addr == 0x08 && m_lh)) + { + if (ide_cs == 0) + { + m_ata->write_cs0(space, io_addr & 0x07, m_ata_data, 0xffff); + } + else + { + m_ata->write_cs1(space, io_addr & 0x07, m_ata_data, 0xffff); + } + } + } + + m_lh = (io_addr == 0x08) ? !m_lh : ((io_addr > 0x08) ? 0 : m_lh); + } +} diff --git a/src/devices/bus/kc/d004.h b/src/devices/bus/kc/d004.h new file mode 100644 index 00000000000..79f45cba03a --- /dev/null +++ b/src/devices/bus/kc/d004.h @@ -0,0 +1,114 @@ +// license:BSD-3-Clause +// copyright-holders:Sandro Ronco +#pragma once + +#ifndef __KC_D004_H__ +#define __KC_D004_H__ + +#include "emu.h" +#include "kc.h" +#include "machine/z80ctc.h" +#include "cpu/z80/z80.h" +#include "machine/upd765.h" +#include "machine/ataintf.h" +#include "imagedev/harddriv.h" + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> kc_d004_device + +class kc_d004_device : + public device_t, + public device_kcexp_interface +{ +public: + // construction/destruction + kc_d004_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + kc_d004_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual const rom_entry *device_rom_region() const; + + DECLARE_FLOPPY_FORMATS( floppy_formats ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + // kcexp_interface overrides + virtual UINT8 module_id_r() { return 0xa7; } + virtual void control_w(UINT8 data); + virtual void read(offs_t offset, UINT8 &data); + virtual void io_read(offs_t offset, UINT8 &data); + virtual void io_write(offs_t offset, UINT8 data); + +public: + DECLARE_READ8_MEMBER(hw_input_gate_r); + DECLARE_WRITE8_MEMBER(fdd_select_w); + DECLARE_WRITE8_MEMBER(hw_terminal_count_w); + + DECLARE_WRITE_LINE_MEMBER( fdc_irq ); + +private: + static const device_timer_id TIMER_RESET = 0; + + required_device m_cpu; + required_device m_fdc; + required_device m_floppy0; + required_device m_floppy1; + required_device m_floppy2; + required_device m_floppy3; + required_shared_ptr m_koppel_ram; + + // internal state + emu_timer * m_reset_timer; + + UINT8 * m_rom; + //UINT8 m_hw_input_gate; + UINT16 m_rom_base; + UINT8 m_enabled; + UINT8 m_connected; + + floppy_image_device *m_floppy; +}; + + +// ======================> kc_d004_gide_device + +class kc_d004_gide_device : + public kc_d004_device +{ +public: + // construction/destruction + kc_d004_gide_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual const rom_entry *device_rom_region() const; + +protected: + // device-level overrides + virtual void device_reset(); + +public: + DECLARE_READ8_MEMBER(gide_r); + DECLARE_WRITE8_MEMBER(gide_w); + +private: + required_device m_ata; + + UINT16 m_ata_data; + int m_lh; +}; + +// device type definition +extern const device_type KC_D004; +extern const device_type KC_D004_GIDE; + +#endif /* __KC_D004_H__ */ diff --git a/src/devices/bus/kc/kc.c b/src/devices/bus/kc/kc.c new file mode 100644 index 00000000000..5ecc1b196b6 --- /dev/null +++ b/src/devices/bus/kc/kc.c @@ -0,0 +1,376 @@ +// license:BSD-3-Clause +// copyright-holders:Sandro Ronco +/********************************************************************* + + kc.c + + KC85_2/3/4/5 expansion slot emulation + +********************************************************************** + + GND 1 30 GND + GND 2 31 GND + NC 3 32 NC + DB7 4 33 DB6 + DB5 5 34 DB4 + DB3 6 35 DB2 + DB1 7 36 DB0 + /WR 8 37 /RD + /WREQ 9 38 /IORQ + IEO 10 39 NC + AB14 11 40 AB15 + AB12 12 41 AB13 + AB10 13 42 AB11 + AB8 14 43 AB9 + /WAIT 15 44 /RFSH + AB6 16 45 AB7 + AB4 17 46 AB5 + AB2 18 47 AB3 + AB0 19 48 AB1 + /RESET 20 49 /BUSRQ + TATK 21 50 GND + /M1 22 51 /HALT + /NMI 23 52 /INT + MEO 24 53 MEI + /ZI 25 54 /BI + /NC 26 55 /HELL + /BUSAK 27 56 NC + VCC 28 57 NC + NC 29 58 NC + + Slots are organized into a chain (MEI -> MEO) , the first module that + decode the address on bus, clear the MEO line for disable other modules + with less priority. + +************************************************************************ + + Known KC85 modules + + Name ID Control Emulated Description + + M001 EF ---- ---M no Digital IN/OUT + M002 DA ---- ---M no PIO 3 + M003 EE ---- ---M no V.24 + M005 ---- ---- no User + M006 FC AA-- ---M yes BASIC for KC85/2 (16KB ROM) + M007 ---- ---- no Adapter + M008 ---- ---- no Joystick + M009 ED ---- ---M no TLCM Spracheingabe/Datenkompr + M010 E7 ---- ---M no ADU 1 (4 analog inputs) + M011 F6 AA-- --WM yes 64KB RAM + M012 FB AAA- ---M yes Texor (8KB ROM) + M021 ---- ---- no Joystick + Centronics + M022 F4 AA-- --WM yes 16KB RAM + M024 F5 AA-- --WM no 32KB RAM + M025 F7 AAA- ---M no User PROM 8KB + M026 FB AAA- ---M yes FORTH (8KB ROM) + M027 FB AAA- ---M yes Development (8KB ROM) + M028 FB AA-- ---M no 16KB EPROM(2x U2764) + M029 E3 ---- ---M no DAU 1 (2 analog outputs) + M030 DB AAA- ---M no EPROMER 8KB EPROM + M032 79 A-SS SSWM yes 256KB segmented RAM (16 segments of 16KB) + M033 01 AA0S ---M yes Typestar (8KB x 2 ROM) + M034 7A ASSS SSWM yes 512KB segmented RAM (32 segments of 16KB) + M035 7B SSSS SSWM yes 1MB segmented RAM (64 segments of 16KB) + M036 78 A--S SSWM yes 128KB segmented RAM (8 segments of 16KB) + M040 F8 AA-- ---M no User PROM 8/16KB + M045 70 AASS ---M no User 32KB segmented ROM (4 segments of 8KB) + M046 71 AASS -S-M no User 64KB segmented ROM (8 segments of 8KB) + M047 72 AASS SS-M no User 128KB segmented ROM (16 segments of 8KB) + M048 73 SSSS SS-M no User 256KB segmented ROM (16 segments of 16KB) + M051 EC ---- ---- no Scanner Module + M052 FD ---- ---- no USB + NET (TCP/IP) + M053 EE ---- ---M no RS-232 + M061 ---- ---- no 3x E/A-Modul + M120 F0 AAA- --WM no 8KB CMOS-RAM + M122 F1 AA-- --WM no 16KB CMOS-RAM + M124 F2 AA-- --WM no 32KB CMOS-RAM + + D001 ---- ---- yes Basis Device + D002 ---- ---- yes Bus driver expansion + D003 ---- ---- no PROM programmer for KC-PROM Module + D004 A7 --A- -K-M yes Floppy Disk Interface + D005 ---- ---- no Komfort-Tastatur for KC85/4 + + + Control byte ID byte + A - Base Address 01 - Autostart modules + K - Power on/off 7x - Segmented memory + S - Active segment Dx/Ex - IN/OUT modules + W - Write enabled Fx - memory modules + M - Module enabled + + Info taken from: http://www.mpm-kc85.de/html/ModulListe.htm + +*********************************************************************/ + +#include "emu.h" +#include "kc.h" +#include "emuopts.h" + +#define LOG 0 + + +/*************************************************************************** + PARAMETERS +***************************************************************************/ + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type KCEXP_SLOT = &device_creator; +const device_type KCCART_SLOT = &device_creator; + + +//************************************************************************** +// KC85 Expansion Interface +//************************************************************************** + +//------------------------------------------------- +// device_kcexp_interface - constructor +//------------------------------------------------- + +device_kcexp_interface::device_kcexp_interface(const machine_config &mconfig, device_t &device) + : device_slot_card_interface(mconfig, device) +{ +} + + +//------------------------------------------------- +// ~device_kcexp_interface - destructor +//------------------------------------------------- + +device_kcexp_interface::~device_kcexp_interface() +{ +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// kcexp_slot_device - constructor +//------------------------------------------------- +kcexp_slot_device::kcexp_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, KCEXP_SLOT, "KC85 Expansion Slot", tag, owner, clock, "kcexp_slot", __FILE__), + device_slot_interface(mconfig, *this), + m_out_irq_cb(*this), + m_out_nmi_cb(*this), + m_out_halt_cb(*this) +{ +} + +kcexp_slot_device::kcexp_slot_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_slot_interface(mconfig, *this), + m_out_irq_cb(*this), + m_out_nmi_cb(*this), + m_out_halt_cb(*this) +{ +} + +void kcexp_slot_device::static_set_next_slot(device_t &device, const char *next_slot_tag) +{ + kcexp_slot_device &kc_slot = dynamic_cast(device); + + kc_slot.m_next_slot_tag = next_slot_tag; +} + +//------------------------------------------------- +// kcexp_slot_device - destructor +//------------------------------------------------- + +kcexp_slot_device::~kcexp_slot_device() +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void kcexp_slot_device::device_start() +{ + m_cart = dynamic_cast(get_card_device()); + m_next_slot = m_next_slot_tag ? owner()->subdevice(m_next_slot_tag) : NULL; + + // resolve callbacks + m_out_irq_cb.resolve_safe(); + m_out_nmi_cb.resolve_safe(); + m_out_halt_cb.resolve_safe(); +} + + +/*------------------------------------------------- + module id read +-------------------------------------------------*/ + +UINT8 kcexp_slot_device::module_id_r() +{ + UINT8 result = 0xff; + + if (m_cart) + result = m_cart->module_id_r(); + + return result; +} + +/*------------------------------------------------- + module control write +-------------------------------------------------*/ +void kcexp_slot_device::control_w(UINT8 data) +{ + if (m_cart) + m_cart->control_w(data); +} + +/*------------------------------------------------- + read +-------------------------------------------------*/ + +void kcexp_slot_device::read(offs_t offset, UINT8 &data) +{ + if (m_cart) + m_cart->read(offset, data); +} + + +/*------------------------------------------------- + write +-------------------------------------------------*/ + +void kcexp_slot_device::write(offs_t offset, UINT8 data) +{ + if (m_cart) + m_cart->write(offset, data); +} + +/*------------------------------------------------- + IO read +-------------------------------------------------*/ + +void kcexp_slot_device::io_read(offs_t offset, UINT8 &data) +{ + if (m_cart) + m_cart->io_read(offset, data); +} + + +/*------------------------------------------------- + IO write +-------------------------------------------------*/ + +void kcexp_slot_device::io_write(offs_t offset, UINT8 data) +{ + if (m_cart) + m_cart->io_write(offset, data); +} + +/*------------------------------------------------- + MEI line write +-------------------------------------------------*/ + +WRITE_LINE_MEMBER( kcexp_slot_device::mei_w ) +{ + if (LOG) logerror("KCEXP '%s': %s MEI line\n", tag(), state != CLEAR_LINE ? "ASSERT": "CLEAR"); + + if (m_cart) + m_cart->mei_w(state); +} + +/*------------------------------------------------- + MEO line write +-------------------------------------------------*/ + +WRITE_LINE_MEMBER( kcexp_slot_device::meo_w ) +{ + if (LOG) logerror("KCEXP '%s': %s MEO line\n", tag(), state != CLEAR_LINE ? "ASSERT": "CLEAR"); + + if (m_next_slot) + m_next_slot->mei_w(state); +} + + +//************************************************************************** +// KC85 Cartridges Interface +//************************************************************************** + +//------------------------------------------------- +// kccart_slot_device - constructor +//------------------------------------------------- +kccart_slot_device::kccart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + kcexp_slot_device(mconfig, KCCART_SLOT, "KC85 Cartridge Slot", tag, owner, clock, "kccart_slot", __FILE__), + device_image_interface(mconfig, *this) +{ +} + +//------------------------------------------------- +// kccart_slot_device - destructor +//------------------------------------------------- + +kccart_slot_device::~kccart_slot_device() +{ +} + +//------------------------------------------------- +// device_config_complete - perform any +// operations now that the configuration is +// complete +//------------------------------------------------- + +void kccart_slot_device::device_config_complete() +{ + // set brief and instance name + update_names(); +} + +/*------------------------------------------------- + call load +-------------------------------------------------*/ + +bool kccart_slot_device::call_load() +{ + if (m_cart) + { + offs_t read_length = 0; + UINT8 *cart_base = m_cart->get_cart_base(); + + if (cart_base != NULL) + { + if (software_entry() == NULL) + { + read_length = length(); + fread(m_cart->get_cart_base(), read_length); + } + else + { + read_length = get_software_region_length("rom"); + memcpy(m_cart->get_cart_base(), get_software_region("rom"), read_length); + } + } + else + return IMAGE_INIT_FAIL; + } + + return IMAGE_INIT_PASS; +} + +/*------------------------------------------------- + call softlist load +-------------------------------------------------*/ + +bool kccart_slot_device::call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry) +{ + load_software_part_region(*this, swlist, swname, start_entry ); + return TRUE; +} + +/*------------------------------------------------- + get default card software +-------------------------------------------------*/ + +void kccart_slot_device::get_default_card_software(std::string &result) +{ + software_get_default_slot(result, "standard"); +} diff --git a/src/devices/bus/kc/kc.h b/src/devices/bus/kc/kc.h new file mode 100644 index 00000000000..def77ffd955 --- /dev/null +++ b/src/devices/bus/kc/kc.h @@ -0,0 +1,152 @@ +// license:BSD-3-Clause +// copyright-holders:Sandro Ronco +/********************************************************************* + + kc.h + + KC85_2/3/4/5 expansion slot emulation + +*********************************************************************/ + +#ifndef __KCEXP_H__ +#define __KCEXP_H__ + +/*************************************************************************** + TYPE DEFINITIONS +***************************************************************************/ + +// ======================> device_kcexp_interface + +class device_kcexp_interface : public device_slot_card_interface +{ +public: + // construction/destruction + device_kcexp_interface(const machine_config &mconfig, device_t &device); + virtual ~device_kcexp_interface(); + + // reading and writing + virtual UINT8 module_id_r() { return 0xff; } + virtual void control_w(UINT8 data) { } + virtual void read(offs_t offset, UINT8 &data) { } + virtual void write(offs_t offset, UINT8 data) { } + virtual void io_read(offs_t offset, UINT8 &data) { } + virtual void io_write(offs_t offset, UINT8 data) { } + virtual UINT8* get_cart_base() { return NULL; } + virtual DECLARE_WRITE_LINE_MEMBER( mei_w ) { }; +}; + +// ======================> kcexp_slot_device + +class kcexp_slot_device : public device_t, + public device_slot_interface +{ +public: + // construction/destruction + kcexp_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + kcexp_slot_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + virtual ~kcexp_slot_device(); + + template static devcb_base &set_out_irq_callback(device_t &device, _Object object) { return downcast(device).m_out_irq_cb.set_callback(object); } + template static devcb_base &set_out_nmi_callback(device_t &device, _Object object) { return downcast(device).m_out_nmi_cb.set_callback(object); } + template static devcb_base &set_out_halt_callback(device_t &device, _Object object) { return downcast(device).m_out_halt_cb.set_callback(object); } + + // device-level overrides + virtual void device_start(); + + // inline configuration + static void static_set_next_slot(device_t &device, const char *next_module_tag); + + // reading and writing + virtual UINT8 module_id_r(); + virtual void control_w(UINT8 data); + virtual void read(offs_t offset, UINT8 &data); + virtual void write(offs_t offset, UINT8 data); + virtual void io_read(offs_t offset, UINT8 &data); + virtual void io_write(offs_t offset, UINT8 data); + virtual DECLARE_WRITE_LINE_MEMBER( mei_w ); + virtual DECLARE_WRITE_LINE_MEMBER( meo_w ); + + devcb_write_line m_out_irq_cb; + devcb_write_line m_out_nmi_cb; + devcb_write_line m_out_halt_cb; + + device_kcexp_interface* m_cart; + + const char* m_next_slot_tag; + kcexp_slot_device* m_next_slot; +}; + +// ======================> kccart_slot_device + +class kccart_slot_device : public kcexp_slot_device, + public device_image_interface +{ +public: + // construction/destruction + kccart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual ~kccart_slot_device(); + + // device-level overrides + virtual void device_config_complete(); + + // image-level overrides + virtual bool call_load(); + virtual bool call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry); + + virtual iodevice_t image_type() const { return IO_CARTSLOT; } + virtual bool is_readable() const { return 1; } + virtual bool is_writeable() const { return 0; } + virtual bool is_creatable() const { return 0; } + virtual bool must_be_loaded() const { return 0; } + virtual bool is_reset_on_load() const { return 1; } + virtual const char *image_interface() const { return "kc_cart"; } + virtual const char *file_extensions() const { return "bin"; } + virtual const option_guide *create_option_guide() const { return NULL; } + + // slot interface overrides + virtual void get_default_card_software(std::string &result); +}; + +// device type definition +extern const device_type KCEXP_SLOT; +extern const device_type KCCART_SLOT; + + +/*************************************************************************** + DEVICE CONFIGURATION MACROS +***************************************************************************/ + +#define MCFG_KCEXP_SLOT_OUT_IRQ_CB(_devcb) \ + devcb = &kcexp_slot_device::set_out_irq_callback(*device, DEVCB_##_devcb); + +#define MCFG_KCEXP_SLOT_OUT_NMI_CB(_devcb) \ + devcb = &kcexp_slot_device::set_out_nmi_callback(*device, DEVCB_##_devcb); + +#define MCFG_KCEXP_SLOT_OUT_HALT_CB(_devcb) \ + devcb = &kcexp_slot_device::set_out_halt_callback(*device, DEVCB_##_devcb); + +#define MCFG_KCEXP_SLOT_NEXT_SLOT(_next_slot_tag) \ + kcexp_slot_device::static_set_next_slot(*device, _next_slot_tag); + + +#define MCFG_KCCART_SLOT_OUT_IRQ_CB(_devcb) \ + devcb = &kccart_slot_device::set_out_irq_callback(*device, DEVCB_##_devcb); + +#define MCFG_KCCART_SLOT_OUT_NMI_CB(_devcb) \ + devcb = &kccart_slot_device::set_out_nmi_callback(*device, DEVCB_##_devcb); + +#define MCFG_KCCART_SLOT_OUT_HALT_CB(_devcb) \ + devcb = &kccart_slot_device::set_out_halt_callback(*device, DEVCB_##_devcb); + +#define MCFG_KCCART_SLOT_NEXT_SLOT(_next_slot_tag) \ + kccart_slot_device::static_set_next_slot(*device, _next_slot_tag); + +// #define MCFG_KC85_EXPANSION_ADD(_tag,_next_slot_tag,_config,_slot_intf,_def_slot) +// MCFG_DEVICE_ADD(_tag, KCEXP_SLOT, 0) +// MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) + +// #define MCFG_KC85_CARTRIDGE_ADD(_tag,_next_slot_tag,_config,_slot_intf,_def_slot) +// MCFG_DEVICE_ADD(_tag, KCCART_SLOT, 0) +// MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) + +#endif /* __KCEXP_H__ */ diff --git a/src/devices/bus/kc/ram.c b/src/devices/bus/kc/ram.c new file mode 100644 index 00000000000..1d747f4e53c --- /dev/null +++ b/src/devices/bus/kc/ram.c @@ -0,0 +1,449 @@ +// license:BSD-3-Clause +// copyright-holders:Sandro Ronco +/*************************************************************************** + + ram.c + + KC 85 RAM modules emulation + + Supported modules: + - M011 64KB RAM + - M022 16KB RAM + - M032 256KB segmented RAM + - M034 512KB segmented RAM + - M035 1MB segmented RAM + - M036 128KB segmented RAM + +***************************************************************************/ + +#include "emu.h" +#include "ram.h" + +/*************************************************************************** + IMPLEMENTATION +***************************************************************************/ + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type KC_M011 = &device_creator; +const device_type KC_M022 = &device_creator; +const device_type KC_M032 = &device_creator; +const device_type KC_M034 = &device_creator; +const device_type KC_M035 = &device_creator; +const device_type KC_M036 = &device_creator; + +//************************************************************************** +// M011 64KB RAM +//************************************************************************** + +//------------------------------------------------- +// kc_m011_device - constructor +//------------------------------------------------- + +kc_m011_device::kc_m011_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, KC_M011, "M011 64KB RAM", tag, owner, clock, "kc_m011", __FILE__), + device_kcexp_interface( mconfig, *this ) +{ +} + +kc_m011_device::kc_m011_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_kcexp_interface( mconfig, *this ) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void kc_m011_device::device_start() +{ + m_slot = dynamic_cast(owner()); + + m_ram = machine().memory().region_alloc(tag(), get_ram_size(), 1, ENDIANNESS_LITTLE)->base(); + memset(m_ram, 0, get_ram_size()); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void kc_m011_device::device_reset() +{ + m_enabled = 0; + m_write_enabled = 0; + m_base = 0; + m_segment = 0; + m_mei = 0; +} + +/*------------------------------------------------- + module control write +-------------------------------------------------*/ +void kc_m011_device::control_w(UINT8 data) +{ + if (m_mei) + { + m_enabled = BIT(data, 0); + m_write_enabled = BIT(data, 1); + m_base = (data & 0xc0) << 8; + } +} + +/*------------------------------------------------- + read +-------------------------------------------------*/ + +void kc_m011_device::read(offs_t offset, UINT8 &data) +{ + UINT32 addr = offset ^ m_base; + + if (addr < 0x10000 && m_enabled && m_mei) + { + data = m_ram[addr]; + + // clear the MEO line for disable other modules with less priority + m_slot->meo_w(CLEAR_LINE); + } +} + +/*------------------------------------------------- + write +-------------------------------------------------*/ + +void kc_m011_device::write(offs_t offset, UINT8 data) +{ + UINT32 addr = offset ^ m_base; + + if (addr < 0x10000 && m_enabled && m_mei) + { + if (m_write_enabled) + m_ram[addr] = data; + + // clear the MEO line for disable other modules with less priority + m_slot->meo_w(CLEAR_LINE); + } +} + +/*------------------------------------------------- + MEI line write +-------------------------------------------------*/ + +WRITE_LINE_MEMBER( kc_m011_device::mei_w ) +{ + m_mei = state; + + // update MEO line + m_slot->meo_w(state); +} + +//************************************************************************** +// M022 16KB RAM +//************************************************************************** + +//------------------------------------------------- +// kc_m022_device - constructor +//------------------------------------------------- + +kc_m022_device::kc_m022_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : kc_m011_device(mconfig, KC_M022, "M022 16KB RAM", tag, owner, clock, "kc_m022", __FILE__) +{ +} + +/*------------------------------------------------- + read +-------------------------------------------------*/ + +void kc_m022_device::read(offs_t offset, UINT8 &data) +{ + if (offset >= m_base && offset < (m_base + 0x4000) && m_enabled && m_mei) + { + data = m_ram[offset - m_base]; + + // clear the MEO line for disable other modules with less priority + m_slot->meo_w(CLEAR_LINE); + } +} + +/*------------------------------------------------- + write +-------------------------------------------------*/ + +void kc_m022_device::write(offs_t offset, UINT8 data) +{ + if (offset >= m_base && offset < (m_base + 0x4000) && m_enabled && m_mei) + { + if (m_write_enabled) + m_ram[offset - m_base] = data; + + // clear the MEO line for disable other modules with less priority + m_slot->meo_w(CLEAR_LINE); + } +} + + +//************************************************************************** +// M032 256KB segmented RAM +//************************************************************************** + +//------------------------------------------------- +// kc_m032_device - constructor +//------------------------------------------------- + +kc_m032_device::kc_m032_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : kc_m011_device(mconfig, KC_M032, "M032 256KB segmented RAM", tag, owner, clock, "kc_m032", __FILE__) +{ +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void kc_m032_device::device_reset() +{ + kc_m011_device::device_reset(); + m_base = 0x4000; +} + +/*------------------------------------------------- + module control write +-------------------------------------------------*/ +void kc_m032_device::control_w(UINT8 data) +{ + if (m_mei) + { + m_enabled = BIT(data, 0); + m_write_enabled = BIT(data, 1); + m_segment = (data>>2) & 0x0f; + m_base = (data & 0x80) ? 0x8000 : 0x4000; + } +} + +/*------------------------------------------------- + read +-------------------------------------------------*/ + +void kc_m032_device::read(offs_t offset, UINT8 &data) +{ + if (offset >= m_base && offset < (m_base + 0x4000) && m_enabled && m_mei) + { + data = m_ram[(offset - m_base) | (m_segment << 14)]; + + // clear the MEO line for disable other modules with less priority + m_slot->meo_w(CLEAR_LINE); + } +} + +/*------------------------------------------------- + write +-------------------------------------------------*/ + +void kc_m032_device::write(offs_t offset, UINT8 data) +{ + if (offset >= m_base && offset < (m_base + 0x4000) && m_enabled && m_mei) + { + if (m_write_enabled) + m_ram[(offset - m_base) | (m_segment << 14)] = data; + + // clear the MEO line for disable other modules with less priority + m_slot->meo_w(CLEAR_LINE); + } +} + + +//************************************************************************** +// M034 512KB segmented RAM +//************************************************************************** + +//------------------------------------------------- +// kc_m034_device - constructor +//------------------------------------------------- + +kc_m034_device::kc_m034_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : kc_m011_device(mconfig, KC_M034, "M034 512KB segmented RAM", tag, owner, clock, "kc_m034", __FILE__) +{ +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void kc_m034_device::device_reset() +{ + kc_m011_device::device_reset(); + m_base = 0x4000; +} + +/*------------------------------------------------- + module control write +-------------------------------------------------*/ +void kc_m034_device::control_w(UINT8 data) +{ + if (m_mei) + { + m_enabled = BIT(data, 0); + m_write_enabled = BIT(data, 1); + m_segment = (data>>2) & 0x1f; + m_base = (data & 0x80) ? 0x8000 : 0x4000; + } +} + +/*------------------------------------------------- + read +-------------------------------------------------*/ + +void kc_m034_device::read(offs_t offset, UINT8 &data) +{ + if (offset >= m_base && offset < (m_base + 0x4000) && m_enabled && m_mei) + { + data = m_ram[(offset - m_base) | (m_segment << 14)]; + + // clear the MEO line for disable other modules with less priority + m_slot->meo_w(CLEAR_LINE); + } +} + +/*------------------------------------------------- + write +-------------------------------------------------*/ + +void kc_m034_device::write(offs_t offset, UINT8 data) +{ + if (offset >= m_base && offset < (m_base + 0x4000) && m_enabled && m_mei) + { + if (m_write_enabled) + m_ram[(offset - m_base) | (m_segment << 14)] = data; + + // clear the MEO line for disable other modules with less priority + m_slot->meo_w(CLEAR_LINE); + } +} + + +//************************************************************************** +// M035 1MB segmented RAM +//************************************************************************** + +//------------------------------------------------- +// kc_m035_device - constructor +//------------------------------------------------- + +kc_m035_device::kc_m035_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : kc_m011_device(mconfig, KC_M035, "M035 1MB segmented RAM", tag, owner, clock, "kc_m035", __FILE__) +{ +} + +/*------------------------------------------------- + module control write +-------------------------------------------------*/ +void kc_m035_device::control_w(UINT8 data) +{ + if (m_mei) + { + m_enabled = BIT(data, 0); + m_write_enabled = BIT(data, 1); + m_segment = (data>>2) & 0x3f; + } +} + +/*------------------------------------------------- + read +-------------------------------------------------*/ + +void kc_m035_device::read(offs_t offset, UINT8 &data) +{ + if (offset >= 0x8000 && offset < 0xc000 && m_enabled & m_mei) + { + data = m_ram[(offset - 0x8000) | (m_segment << 14)]; + + // clear the MEO line for disable other modules with less priority + m_slot->meo_w(CLEAR_LINE); + } +} + +/*------------------------------------------------- + write +-------------------------------------------------*/ + +void kc_m035_device::write(offs_t offset, UINT8 data) +{ + if (offset >= 0x8000 && offset < 0xc000 && m_enabled && m_mei) + { + if (m_write_enabled) + m_ram[(offset-0x8000) | (m_segment << 14)] = data; + + // clear the MEO line for disable other modules with less priority + m_slot->meo_w(CLEAR_LINE); + } +} + + +//************************************************************************** +// M036 128KB segmented RAM +//************************************************************************** + +//------------------------------------------------- +// kc_m036_device - constructor +//------------------------------------------------- + +kc_m036_device::kc_m036_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : kc_m011_device(mconfig, KC_M036, "M036 128KB segmented RAM", tag, owner, clock, "kc_m036", __FILE__) +{ +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void kc_m036_device::device_reset() +{ + kc_m011_device::device_reset(); + m_base = 0x4000; +} + +/*------------------------------------------------- + module control write +-------------------------------------------------*/ +void kc_m036_device::control_w(UINT8 data) +{ + if (m_mei) + { + m_enabled = BIT(data, 0); + m_write_enabled = BIT(data, 1); + m_segment = (data>>2) & 0x07; + m_base = (data & 0x80) ? 0x8000 : 0x4000; + } +} + +/*------------------------------------------------- + read +-------------------------------------------------*/ + +void kc_m036_device::read(offs_t offset, UINT8 &data) +{ + if (offset >= m_base && offset < (m_base + 0x4000) && m_enabled && m_mei) + { + data = m_ram[(offset - m_base) | (m_segment << 14)]; + + // clear the MEO line for disable other modules with less priority + m_slot->meo_w(CLEAR_LINE); + } +} + +/*------------------------------------------------- + write +-------------------------------------------------*/ + +void kc_m036_device::write(offs_t offset, UINT8 data) +{ + if (offset >= m_base && offset < (m_base + 0x4000) && m_enabled && m_mei) + { + if (m_write_enabled) + m_ram[(offset - m_base) | (m_segment << 14)] = data; + + // clear the MEO line for disable other modules with less priority + m_slot->meo_w(CLEAR_LINE); + } +} diff --git a/src/devices/bus/kc/ram.h b/src/devices/bus/kc/ram.h new file mode 100644 index 00000000000..02eca67c909 --- /dev/null +++ b/src/devices/bus/kc/ram.h @@ -0,0 +1,180 @@ +// license:BSD-3-Clause +// copyright-holders:Sandro Ronco +#pragma once + +#ifndef __KC_RAM_H__ +#define __KC_RAM_H__ + +#include "emu.h" +#include "kc.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> kc_m011_device + +class kc_m011_device : + public device_t, + public device_kcexp_interface +{ +public: + // construction/destruction + kc_m011_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + kc_m011_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // kcexp_interface overrides + virtual UINT8 module_id_r() { return 0xf6; } + virtual void control_w(UINT8 data); + virtual void read(offs_t offset, UINT8 &data); + virtual void write(offs_t offset, UINT8 data); + virtual DECLARE_WRITE_LINE_MEMBER( mei_w ); + +protected: + kcexp_slot_device *m_slot; + + // internal state + int m_mei; // module enable line + UINT8 * m_ram; + UINT8 m_enabled; + UINT8 m_write_enabled; + UINT16 m_base; + UINT8 m_segment; + +private: + // internal helpers + virtual UINT32 get_ram_size() const { return 0x10000; } +}; + + +// ======================> kc_m022_device + +class kc_m022_device : + public kc_m011_device +{ +public: + // construction/destruction + kc_m022_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // kcexp_interface overrides + virtual UINT8 module_id_r() { return 0xf4; } + virtual void read(offs_t offset, UINT8 &ata); + virtual void write(offs_t offset, UINT8 data); + +private: + // internal helpers + virtual UINT32 get_ram_size() const { return 0x4000; } +}; + + +// ======================> kc_m032_device + +class kc_m032_device : + public kc_m011_device +{ +public: + // construction/destruction + kc_m032_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // device-level overrides + virtual void device_reset(); + + // kcexp_interface overrides + virtual UINT8 module_id_r() { return 0x79; } + virtual void control_w(UINT8 data); + virtual void read(offs_t offset, UINT8 &data); + virtual void write(offs_t offset, UINT8 data); + +private: + // internal helpers + virtual UINT32 get_ram_size() const { return 0x40000; } +}; + + +// ======================> kc_m034_device + +class kc_m034_device : + public kc_m011_device +{ +public: + // construction/destruction + kc_m034_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // device-level overrides + virtual void device_reset(); + + // kcexp_interface overrides + virtual UINT8 module_id_r() { return 0x7a; } + virtual void control_w(UINT8 data); + virtual void read(offs_t offset, UINT8 &data); + virtual void write(offs_t offset, UINT8 data); + +private: + // internal helpers + virtual UINT32 get_ram_size() const { return 0x80000; } +}; + + +// ======================> kc_m035_device + +class kc_m035_device : + public kc_m011_device +{ +public: + // construction/destruction + kc_m035_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // kcexp_interface overrides + virtual UINT8 module_id_r() { return 0x7b; } + virtual void control_w(UINT8 data); + virtual void read(offs_t offset, UINT8 &data); + virtual void write(offs_t offset, UINT8 data); + +private: + // internal helpers + virtual UINT32 get_ram_size() const { return 0x100000; } +}; + + +// ======================> kc_m036_device + +class kc_m036_device : + public kc_m011_device +{ +public: + // construction/destruction + kc_m036_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // device-level overrides + virtual void device_reset(); + + // kcexp_interface overrides + virtual UINT8 module_id_r() { return 0x78; } + virtual void control_w(UINT8 data); + virtual void read(offs_t offset, UINT8 &data); + virtual void write(offs_t offset, UINT8 data); + +private: + // internal helpers + virtual UINT32 get_ram_size() const { return 0x20000; } +}; + +// device type definition +extern const device_type KC_M011; +extern const device_type KC_M022; +extern const device_type KC_M032; +extern const device_type KC_M034; +extern const device_type KC_M035; +extern const device_type KC_M036; + +#endif /* __KC_RAM_H__ */ diff --git a/src/devices/bus/kc/rom.c b/src/devices/bus/kc/rom.c new file mode 100644 index 00000000000..3a80207dd7b --- /dev/null +++ b/src/devices/bus/kc/rom.c @@ -0,0 +1,230 @@ +// license:BSD-3-Clause +// copyright-holders:Sandro Ronco +/*************************************************************************** + + rom.c + + KC 85 ROM modules emulation + + Supported modules: + - Generic 8KB ROM module + - M006 BASIC + - M033 TypeStar + +***************************************************************************/ + +#include "emu.h" +#include "rom.h" + +#define REGION_TAG "rom" + +/*************************************************************************** + IMPLEMENTATION +***************************************************************************/ + +ROM_START( kc_rom ) + ROM_REGION(0x4000, REGION_TAG, ROMREGION_ERASEFF) +ROM_END + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type KC_STANDARD = &device_creator; +const device_type KC_M006 = &device_creator; +const device_type KC_M033 = &device_creator; + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// kc_8k_device - constructor +//------------------------------------------------- + +kc_8k_device::kc_8k_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, KC_STANDARD, "Standard", tag, owner, clock, "kc_8k", __FILE__), + device_kcexp_interface( mconfig, *this ) +{ +} + +kc_8k_device::kc_8k_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_kcexp_interface( mconfig, *this ) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void kc_8k_device::device_start() +{ + m_slot = dynamic_cast(owner()); + m_rom = memregion(REGION_TAG)->base(); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void kc_8k_device::device_reset() +{ + m_enabled = 0; + m_base = 0; + m_mei = 0; +} + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *kc_8k_device::device_rom_region() const +{ + return ROM_NAME( kc_rom ); +} + +/*------------------------------------------------- + get_cart_base +-------------------------------------------------*/ + +UINT8* kc_8k_device::get_cart_base() +{ + return m_rom; +} + +/*------------------------------------------------- + module control write +-------------------------------------------------*/ + +void kc_8k_device::control_w(UINT8 data) +{ + if (m_mei) + { + m_enabled = BIT(data, 0); + m_base = (data & 0xe0) << 8; + } +} + +/*------------------------------------------------- + read +-------------------------------------------------*/ + +void kc_8k_device::read(offs_t offset, UINT8 &data) +{ + if (offset >= m_base && offset < (m_base + 0x2000) && m_enabled && m_mei) + { + data = m_rom[offset - m_base]; + + // clear the MEO line for disable other modules with less priority + m_slot->meo_w(CLEAR_LINE); + } +} + +/*------------------------------------------------- + MEI line write +-------------------------------------------------*/ + +WRITE_LINE_MEMBER( kc_8k_device::mei_w ) +{ + m_mei = state; + + // update MEO line + m_slot->meo_w(state); +} + +//************************************************************************** +// M006 BASIC +//************************************************************************** + +//------------------------------------------------- +// kc_m006_device - constructor +//------------------------------------------------- + +kc_m006_device::kc_m006_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : kc_8k_device(mconfig, KC_M006, "M006 BASIC", tag, owner, clock, "kc_m006", __FILE__) +{ +} + +/*------------------------------------------------- + module control write +-------------------------------------------------*/ + +void kc_m006_device::control_w(UINT8 data) +{ + if (m_mei) + { + m_enabled = BIT(data, 0); + m_base = (data & 0xc0) << 8; + } +} + +/*------------------------------------------------- + read +-------------------------------------------------*/ + +void kc_m006_device::read(offs_t offset, UINT8 &data) +{ + if (offset >= m_base && offset < (m_base + 0x4000) && m_enabled) + { + data = m_rom[offset - m_base]; + + // clear the MEO line for disable other modules with less priority + m_slot->meo_w(CLEAR_LINE); + } +} + + +//************************************************************************** +// M033 TypeStar module +//************************************************************************** + +//------------------------------------------------- +// kc_m033_device - constructor +//------------------------------------------------- + +kc_m033_device::kc_m033_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : kc_8k_device(mconfig, KC_M033, "M033 TypeStar", tag, owner, clock, "kc_m033", __FILE__) +{ +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void kc_m033_device::device_reset() +{ + kc_8k_device::device_reset(); + + m_bank = 0; +} + +/*------------------------------------------------- + module control write +-------------------------------------------------*/ + +void kc_m033_device::control_w(UINT8 data) +{ + if (m_mei) + { + m_enabled = BIT(data, 0); + m_base = (data & 0xc0) << 8; + m_bank = BIT(data, 4); + } +} + +/*------------------------------------------------- + read +-------------------------------------------------*/ + +void kc_m033_device::read(offs_t offset, UINT8 &data) +{ + if (offset >= m_base && offset < (m_base + 0x2000) && m_enabled && m_mei) + { + data = m_rom[(offset - m_base) | (m_bank<<13)]; + + // clear the MEO line for disable other modules with less priority + m_slot->meo_w(CLEAR_LINE); + } +} diff --git a/src/devices/bus/kc/rom.h b/src/devices/bus/kc/rom.h new file mode 100644 index 00000000000..9cfa06eefab --- /dev/null +++ b/src/devices/bus/kc/rom.h @@ -0,0 +1,98 @@ +// license:BSD-3-Clause +// copyright-holders:Sandro Ronco +#pragma once + +#ifndef __KC_ROM_H__ +#define __KC_ROM_H__ + +#include "emu.h" +#include "kc.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> kc_8k_device + +class kc_8k_device : + public device_t, + public device_kcexp_interface +{ +public: + // construction/destruction + kc_8k_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + kc_8k_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + // optional information overrides + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual const rom_entry *device_rom_region() const; + + // kcexp_interface overrides + virtual UINT8 module_id_r() { return 0xfb; } + virtual void control_w(UINT8 data); + virtual void read(offs_t offset, UINT8 &data); + virtual UINT8* get_cart_base(); + virtual DECLARE_WRITE_LINE_MEMBER( mei_w ); + +protected: + kcexp_slot_device *m_slot; + + // internal state + int m_mei; // module enable line + UINT8 * m_rom; + UINT8 m_enabled; + UINT16 m_base; +}; + + +// ======================> kc_m006_device + +class kc_m006_device : + public kc_8k_device +{ +public: + // construction/destruction + kc_m006_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // kcexp_interface overrides + virtual UINT8 module_id_r() { return 0xfc; } + virtual void control_w(UINT8 data); + virtual void read(offs_t offset, UINT8 &data); +}; + + +// ======================> kc_m033_device + +class kc_m033_device : + public kc_8k_device +{ +public: + // construction/destruction + kc_m033_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // device-level overrides + virtual void device_reset(); + + // kcexp_interface overrides + virtual UINT8 module_id_r() { return 0x01; } + virtual void control_w(UINT8 data); + virtual void read(offs_t offset, UINT8 &data); + +private: + // internal state + UINT16 m_bank; +}; + + +// device type definition +extern const device_type KC_STANDARD; +extern const device_type KC_M006; +extern const device_type KC_M033; + +#endif /* __KC_ROM_H__ */ diff --git a/src/devices/bus/lpci/cirrus.c b/src/devices/bus/lpci/cirrus.c new file mode 100644 index 00000000000..61cea36a3e9 --- /dev/null +++ b/src/devices/bus/lpci/cirrus.c @@ -0,0 +1,164 @@ +// license:BSD-3-Clause +// copyright-holders:Miodrag Milanovic +/*************************************************************************** + + video/cirrus.c + + Cirrus SVGA card emulation (preliminary) + + Cirrus has the following additional registers that are not present in + conventional VGA: + + SEQ 06h: Unlock Cirrus registers; write 12h to unlock registers, + and read 12h back to confirm Cirrus presence. + SEQ 07h + bit 3-1: Pixel depth + 0x00 8 bpp + 0x02 16 bpp (double vert clock) + 0x04 24 bpp + 0x06 16 bpp + 0x08 32 bpp + bit 0: VGA/SVGA (0=VGA, 1=SVGA) + SEQ 0Fh + bit 7: Bankswitch enable + bits 4-3: Memory size + 0x00 256K + 0x08 512K + 0x10 1M + 0x18 2M + SEQ 12h: Hardware Cursor + + + + + GC 09h: Set 64k bank (bits 3-0 only) + GC 20h: Blit Width (bits 7-0) + GC 21h: Blit Width (bits 12-8) + GC 22h: Blit Height (bits 7-0) + GC 23h: Blit Height (bits 12-8) + GC 24h: Blit Destination Pitch (bits 7-0) + GC 25h: Blit Destination Pitch (bits 12-8) + GC 26h: Blit Source Pitch (bits 7-0) + GC 27h: Blit Source Pitch (bits 12-8) + GC 28h: Blit Destination Address (bits 7-0) + GC 29h: Blit Destination Address (bits 15-8) + GC 2Ah: Blit Destination Address (bits 21-16) + GC 2Ch: Blit Source Address (bits 7-0) + GC 2Dh: Blit Source Address (bits 15-8) + GC 2Eh: Blit Source Address (bits 21-16) + GC 2Fh: Blit Write Mask + GC 30h: Blit Mode + GC 31h: Blit Status + bit 7 - Autostart + bit 4 - FIFO Used + bit 2 - Blit Reset + bit 1 - Blit Started + bit 0 - Blit Busy + GC 32h: Raster Operation + GC 33h: Blit Mode Extension + GC 34h: Blit Transparent Color (bits 7-0) + GC 35h: Blit Transparent Color (bits 15-8) + GC 38h: Blit Transparent Color Mask (bits 7-0) + GC 39h: Blit Transparent Color Mask (bits 15-8) + +***************************************************************************/ + +#include "emu.h" +#include "cirrus.h" +#include "video/pc_vga.h" + +#define LOG_PCIACCESS 0 + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type CIRRUS = &device_creator; + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// cirrus_device - constructor +//------------------------------------------------- + +cirrus_device::cirrus_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, CIRRUS, "CIRRUS", tag, owner, clock, "cirrus", __FILE__), + pci_device_interface( mconfig, *this ) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void cirrus_device::device_start() +{ +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void cirrus_device::device_reset() +{ +} + +//------------------------------------------------- +// pci_read - implementation of PCI read +//------------------------------------------------- + +UINT32 cirrus_device::pci_read(pci_bus_device *pcibus, int function, int offset, UINT32 mem_mask) +{ + UINT32 result = 0; + + if (function == 0) + { + switch(offset) + { + case 0x00: /* vendor/device ID */ + result = 0x00A01013; + break; + + case 0x08: + result = 0x03000000; + break; + + case 0x10: + result = 0xD0000000; + break; + + default: + result = 0; + break; + } + } + + if (LOG_PCIACCESS) + logerror("cirrus5430_pci_read(): function=%d offset=0x%02X result=0x%04X\n", function, offset, result); + return result; +} + + +//------------------------------------------------- +// pci_write - implementation of PCI write +//------------------------------------------------- + +void cirrus_device::pci_write(pci_bus_device *pcibus, int function, int offset, UINT32 data, UINT32 mem_mask) +{ + if (LOG_PCIACCESS) + logerror("cirrus5430_pci_write(): function=%d offset=0x%02X data=0x%04X\n", function, offset, data); +} + +/************************************* + * + * Ports + * + *************************************/ + +WRITE8_MEMBER( cirrus_device::cirrus_42E8_w ) +{ + if (data & 0x80) + machine().device("vga")->reset(); +} diff --git a/src/devices/bus/lpci/cirrus.h b/src/devices/bus/lpci/cirrus.h new file mode 100644 index 00000000000..4de5fc32d74 --- /dev/null +++ b/src/devices/bus/lpci/cirrus.h @@ -0,0 +1,41 @@ +// license:BSD-3-Clause +// copyright-holders:Miodrag Milanovic +/*************************************************************************** + + video/cirrus.h + + Cirrus SVGA card emulation (preliminary) + +***************************************************************************/ + +#ifndef CIRRUS_H +#define CIRRUS_H + +#include "bus/lpci/pci.h" + +// ======================> cirrus_device + +class cirrus_device : public device_t, + public pci_device_interface +{ +public: + // construction/destruction + cirrus_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual UINT32 pci_read(pci_bus_device *pcibus, int function, int offset, UINT32 mem_mask); + virtual void pci_write(pci_bus_device *pcibus, int function, int offset, UINT32 data, UINT32 mem_mask); + + DECLARE_WRITE8_MEMBER( cirrus_42E8_w ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); +private: +}; + + +// device type definition +extern const device_type CIRRUS; + +#endif /* CIRRUS_H */ diff --git a/src/devices/bus/lpci/i82371ab.c b/src/devices/bus/lpci/i82371ab.c new file mode 100644 index 00000000000..9f5a9de2edd --- /dev/null +++ b/src/devices/bus/lpci/i82371ab.c @@ -0,0 +1,257 @@ +// license:BSD-3-Clause +// copyright-holders:Miodrag Milanovic +/*************************************************************************** + + Intel 82371AB PCI IDE ISA Xcelerator (PIIX4) + + Part of the Intel 430TX chipset + + - Integrated IDE Controller + - Enhanced DMA Controller based on two 82C37 + - Interrupt Controller based on two 82C59 + - Timers based on 82C54 + - USB + - SMBus + - Real Time Clock based on MC146818 + +***************************************************************************/ + +#include "emu.h" +#include "i82371ab.h" + +const device_type I82371AB = &device_creator; + + +i82371ab_device::i82371ab_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : southbridge_device(mconfig, I82371AB, "Intel 82371AB", tag, owner, clock, "i82371ab", __FILE__), + pci_device_interface( mconfig, *this ) +{ +} + +UINT32 i82371ab_device::pci_isa_r(device_t *busdevice, int offset, UINT32 mem_mask) +{ + UINT32 result = m_regs[0][offset] | + m_regs[0][offset+1] << 8 | + m_regs[0][offset+2] << 16| + m_regs[0][offset+3] << 24; + + logerror("i82371ab_pci_isa_r, offset = %02x, mem_mask = %08x\n", offset, mem_mask); + + return result; +} + +void i82371ab_device::pci_isa_w(device_t *busdevice, int offset, UINT32 data, UINT32 mem_mask) +{ + UINT32 cdata = 0; + int i; + COMBINE_DATA(&cdata); + + logerror("i82371ab_pci_isa_w, offset = %02x, data = %08x, mem_mask = %08x\n", offset, data, mem_mask); + + for(i = 0; i < 4; i++, offset++, cdata >>= 8) + { + switch (offset) + { + case 0x04: + /* clear reserved bits */ + m_regs[0][offset] = cdata & 0x05; + break; + case 0x06: + /* set new status */ + m_regs[0][offset] |= 0x80; + break; + case 0x07: + m_regs[0][offset] |= 0x02; + break; + } + } +} + +UINT32 i82371ab_device::pci_ide_r(device_t *busdevice, int offset, UINT32 mem_mask) +{ + UINT32 result = m_regs[1][offset] | + m_regs[1][offset+1] << 8 | + m_regs[1][offset+2] << 16| + m_regs[1][offset+3] << 24; + + logerror("i82371ab_pci_ide_r, offset = %02x, mem_mask = %08x\n", offset, mem_mask); + + return result; +} + +void i82371ab_device::pci_ide_w(device_t *busdevice, int offset, UINT32 data, UINT32 mem_mask) +{ + UINT32 cdata = 0; + int i; + COMBINE_DATA(&cdata); + + logerror("i82371ab_pci_isa_w, offset = %02x, data = %08x, mem_mask = %08x\n", offset, data, mem_mask); + + for(i = 0; i < 4; i++, offset++, cdata >>= 8) + { + switch (offset) + { + case 0x04: + /* clear reserved bits */ + m_regs[1][offset] = cdata & 0x05; + break; + case 0x06: + /* set new status */ + m_regs[1][offset] |= 0x80; + break; + case 0x07: + m_regs[1][offset] |= 0x02; + break; + } + } +} + +UINT32 i82371ab_device::pci_usb_r(device_t *busdevice, int offset, UINT32 mem_mask) +{ + UINT32 result = m_regs[2][offset] | + m_regs[2][offset+1] << 8 | + m_regs[2][offset+2] << 16| + m_regs[2][offset+3] << 24; + + logerror("i82371ab_pci_usb_r, offset = %02x, mem_mask = %08x\n", offset, mem_mask); + + return result; +} + +void i82371ab_device::pci_usb_w(device_t *busdevice, int offset, UINT32 data, UINT32 mem_mask) +{ + UINT32 cdata = 0; + int i; + COMBINE_DATA(&cdata); + + logerror("i82371ab_pci_isa_w, offset = %02x, data = %08x, mem_mask = %08x\n", offset, data, mem_mask); + + for(i = 0; i < 4; i++, offset++, cdata >>= 8) + { + switch (offset) + { + case 0x04: + /* clear reserved bits */ + m_regs[2][offset] = cdata & 0x05; + break; + case 0x06: + /* set new status */ + m_regs[2][offset] |= 0x80; + break; + case 0x07: + m_regs[2][offset] |= 0x02; + break; + } + } +} + +UINT32 i82371ab_device::pci_acpi_r(device_t *busdevice, int offset, UINT32 mem_mask) +{ + UINT32 result = m_regs[3][offset] | + m_regs[3][offset+1] << 8 | + m_regs[3][offset+2] << 16| + m_regs[3][offset+3] << 24; + + logerror("i82371ab_pci_acpi_r, offset = %02x, mem_mask = %08x\n", offset, mem_mask); + + return result; +} + +void i82371ab_device::pci_acpi_w(device_t *busdevice, int offset, UINT32 data, UINT32 mem_mask) +{ + UINT32 cdata = 0; + int i; + COMBINE_DATA(&cdata); + + logerror("i82371ab_pci_isa_w, offset = %02x, data = %08x, mem_mask = %08x\n", offset, data, mem_mask); + + for(i = 0; i < 4; i++, offset++, cdata >>= 8) + { + switch (offset) + { + case 0x04: + /* clear reserved bits */ + m_regs[3][offset] = cdata & 0x05; + break; + case 0x06: + /* set new status */ + m_regs[3][offset] |= 0x80; + break; + case 0x07: + m_regs[3][offset] |= 0x02; + break; + } + } +} + +UINT32 i82371ab_device::pci_read(pci_bus_device *pcibus, int function, int offset, UINT32 mem_mask) +{ + switch (function) + { + case 0: return pci_isa_r(pcibus, offset, mem_mask); + case 1: return pci_ide_r(pcibus, offset, mem_mask); + case 2: return pci_usb_r(pcibus, offset, mem_mask); + case 3: return pci_acpi_r(pcibus, offset, mem_mask); + } + + logerror("i82371ab_pci_read: read from undefined function %d\n", function); + + return 0; +} + +void i82371ab_device::pci_write(pci_bus_device *pcibus, int function, int offset, UINT32 data, UINT32 mem_mask) +{ + switch (function) + { + case 0: pci_isa_w(pcibus, offset, data, mem_mask); break; + case 1: pci_ide_w(pcibus, offset, data, mem_mask); break; + case 2: pci_usb_w(pcibus, offset, data, mem_mask); break; + case 3: pci_acpi_w(pcibus, offset, data, mem_mask); break; + } +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void i82371ab_device::device_start() +{ + southbridge_device::device_start(); + /* setup save states */ + save_item(NAME(m_regs)); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void i82371ab_device::device_reset() +{ + southbridge_device::device_reset(); + memset(m_regs, 0, sizeof(m_regs)); + UINT32 (*regs32)[64] = (UINT32 (*)[64])(m_regs); + + /* isa */ + regs32[0][0x00] = 0x71108086; + regs32[0][0x04] = 0x00000000; + regs32[0][0x08] = 0x06010000; + regs32[0][0x0c] = 0x00800000; + + /* ide */ + regs32[1][0x00] = 0x71118086; + regs32[1][0x04] = 0x02800000; + regs32[1][0x08] = 0x01018000; + regs32[1][0x0c] = 0x00000000; + + /* usb */ + regs32[2][0x00] = 0x71128086; + regs32[2][0x04] = 0x02800000; + regs32[2][0x08] = 0x0c030000; + regs32[2][0x0c] = 0x00000000; + + /* acpi */ + regs32[3][0x00] = 0x71138086; + regs32[3][0x04] = 0x02800000; + regs32[3][0x08] = 0x06800000; + regs32[3][0x0c] = 0x02800000; +} diff --git a/src/devices/bus/lpci/i82371ab.h b/src/devices/bus/lpci/i82371ab.h new file mode 100644 index 00000000000..a905404e14c --- /dev/null +++ b/src/devices/bus/lpci/i82371ab.h @@ -0,0 +1,53 @@ +// license:BSD-3-Clause +// copyright-holders:Miodrag Milanovic +/*************************************************************************** + + Intel 82371AB PCI IDE ISA Xcelerator (PIIX4) + + Part of the Intel 430TX chipset + +***************************************************************************/ + +#ifndef __I82371AB_H__ +#define __I82371AB_H__ + +#include "pci.h" +#include "southbridge.h" + +// ======================> i82371ab_device + +class i82371ab_device : public southbridge_device, + public pci_device_interface +{ +public: + // construction/destruction + i82371ab_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual UINT32 pci_read(pci_bus_device *pcibus, int function, int offset, UINT32 mem_mask); + virtual void pci_write(pci_bus_device *pcibus, int function, int offset, UINT32 data, UINT32 mem_mask); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + UINT32 pci_isa_r(device_t *busdevice, int offset, UINT32 mem_mask); + void pci_isa_w(device_t *busdevice, int offset, UINT32 data, UINT32 mem_mask); + + UINT32 pci_ide_r(device_t *busdevice, int offset, UINT32 mem_mask); + void pci_ide_w(device_t *busdevice, int offset, UINT32 data, UINT32 mem_mask); + + UINT32 pci_usb_r(device_t *busdevice, int offset, UINT32 mem_mask); + void pci_usb_w(device_t *busdevice, int offset, UINT32 data, UINT32 mem_mask); + + UINT32 pci_acpi_r(device_t *busdevice, int offset, UINT32 mem_mask); + void pci_acpi_w(device_t *busdevice, int offset, UINT32 data, UINT32 mem_mask); + +private: + UINT8 m_regs[4][0x100]; +}; + +// device type definition +extern const device_type I82371AB; + +#endif /* __I82371AB_H__ */ diff --git a/src/devices/bus/lpci/i82371sb.c b/src/devices/bus/lpci/i82371sb.c new file mode 100644 index 00000000000..de9cbc365e7 --- /dev/null +++ b/src/devices/bus/lpci/i82371sb.c @@ -0,0 +1,181 @@ +// license:BSD-3-Clause +// copyright-holders:Miodrag Milanovic +/*************************************************************************** + + Intel 82371SB PCI IDE ISA Xcelerator (PIIX3) + + Part of the Intel 430TX chipset + + - Integrated IDE Controller + - Enhanced DMA Controller based on two 82C37 + - Interrupt Controller based on two 82C59 + - Timers based on 82C54 + - USB + - SMBus + - Real Time Clock based on MC146818 + +***************************************************************************/ + +#include "emu.h" +#include "i82371sb.h" + + +/*************************************************************************** + IMPLEMENTATION +***************************************************************************/ + +const device_type I82371SB = &device_creator; + + +i82371sb_device::i82371sb_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : southbridge_device(mconfig, I82371SB, "Intel 82371SB", tag, owner, clock, "i82371sb", __FILE__), + pci_device_interface( mconfig, *this ) +{ +} + +UINT32 i82371sb_device::pci_isa_r(device_t *busdevice,int offset, UINT32 mem_mask) +{ + UINT32 result = m_regs[0][offset]; + + //logerror("i82371sb_pci_isa_r, offset = %02x, mem_mask = %08x\n", offset, mem_mask); + + return result; +} + +void i82371sb_device::pci_isa_w(device_t *busdevice, int offset, UINT32 data, UINT32 mem_mask) +{ + //logerror("i82371sb_pci_isa_w, offset = %02x, data = %08x, mem_mask = %08x\n", offset, data, mem_mask); + + switch (offset) + { + case 0x04: + COMBINE_DATA(&m_regs[0][offset]); + + /* clear reserved bits */ + m_regs[0][offset] &= 0x00000005; + + /* set new status */ + m_regs[0][offset] |= 0x02800000; + + break; + } +} + +UINT32 i82371sb_device::pci_ide_r(device_t *busdevice, int offset, UINT32 mem_mask) +{ + //logerror("i82371sb_pci_ide_r, offset = %02x, mem_mask = %08x\n", offset, mem_mask); + UINT32 result = m_regs[1][offset]; + return result; +} + +void i82371sb_device::pci_ide_w(device_t *busdevice, int offset, UINT32 data, UINT32 mem_mask) +{ + //logerror("i82371sb_pci_ide_w, offset = %02x, data = %08x, mem_mask = %08x\n", offset, data, mem_mask); + + switch (offset) + { + case 0x04: + COMBINE_DATA(&m_regs[1][offset]); + + /* clear reserved bits */ + m_regs[1][offset] &= 0x00000005; + + /* set new status */ + m_regs[1][offset] |= 0x02800000; + + break; + } +} + +UINT32 i82371sb_device::pci_usb_r(device_t *busdevice, int offset, UINT32 mem_mask) +{ + UINT32 result = m_regs[2][offset]; + + //logerror("i82371sb_pci_usb_r, offset = %02x, mem_mask = %08x\n", offset, mem_mask); + + return result; +} + +void i82371sb_device::pci_usb_w(device_t *busdevice, int offset, UINT32 data, UINT32 mem_mask) +{ + //logerror("i82371sb_pci_usb_w, offset = %02x, data = %08x, mem_mask = %08x\n", offset, data, mem_mask); + + switch (offset) + { + case 0x04: + COMBINE_DATA(&m_regs[2][offset]); + + /* clear reserved bits */ + m_regs[2][offset] &= 0x00000005; + + /* set new status */ + m_regs[2][offset] |= 0x02800000; + + break; + } +} + +UINT32 i82371sb_device::pci_read(pci_bus_device *pcibus, int function, int offset, UINT32 mem_mask) +{ + switch (function) + { + case 0: return pci_isa_r(pcibus, offset, mem_mask); + case 1: return pci_ide_r(pcibus, offset, mem_mask); + case 2: return pci_usb_r(pcibus, offset, mem_mask); + } + + //logerror("i82371sb_pci_read: read from undefined function %d\n", function); + + return 0; +} + +void i82371sb_device::pci_write(pci_bus_device *pcibus, int function, int offset, UINT32 data, UINT32 mem_mask) +{ + switch (function) + { + case 0: pci_isa_w(pcibus, offset, data, mem_mask); break; + case 1: pci_ide_w(pcibus, offset, data, mem_mask); break; + case 2: pci_usb_w(pcibus, offset, data, mem_mask); break; + } + //logerror("i82371sb_pci_write: write to undefined function %d\n", function); +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void i82371sb_device::device_start() +{ + southbridge_device::device_start(); + /* setup save states */ + save_item(NAME(m_regs)); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void i82371sb_device::device_reset() +{ + southbridge_device::device_reset(); + + memset(m_regs, 0, sizeof(m_regs)); + + /* isa */ + m_regs[0][0x00] = 0x70008086; + m_regs[0][0x04] = 0x00000000; + m_regs[0][0x08] = 0x06010000; + m_regs[0][0x0c] = 0x00800000; + + /* ide */ + m_regs[1][0x00] = 0x70108086; + m_regs[1][0x04] = 0x02800000; + m_regs[1][0x08] = 0x01018000; + m_regs[1][0x0c] = 0x00000000; + + /* usb */ + m_regs[2][0x00] = 0x70208086; + m_regs[2][0x04] = 0x02800000; + m_regs[2][0x08] = 0x0c030000; + m_regs[2][0x0c] = 0x00000000; +} diff --git a/src/devices/bus/lpci/i82371sb.h b/src/devices/bus/lpci/i82371sb.h new file mode 100644 index 00000000000..b8cac08edb9 --- /dev/null +++ b/src/devices/bus/lpci/i82371sb.h @@ -0,0 +1,50 @@ +// license:BSD-3-Clause +// copyright-holders:Miodrag Milanovic +/*************************************************************************** + + Intel 82371SB PCI IDE ISA Xcelerator (PIIX3) + + Part of the Intel 430TX chipset + +***************************************************************************/ + +#ifndef __I82371SB_H__ +#define __I82371SB_H__ + +#include "pci.h" +#include "southbridge.h" + +// ======================> i82371sb_device + +class i82371sb_device : public southbridge_device, + public pci_device_interface +{ +public: + // construction/destruction + i82371sb_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual UINT32 pci_read(pci_bus_device *pcibus, int function, int offset, UINT32 mem_mask); + virtual void pci_write(pci_bus_device *pcibus, int function, int offset, UINT32 data, UINT32 mem_mask); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + UINT32 pci_isa_r(device_t *busdevice, int offset, UINT32 mem_mask); + void pci_isa_w(device_t *busdevice, int offset, UINT32 data, UINT32 mem_mask); + + UINT32 pci_ide_r(device_t *busdevice, int offset, UINT32 mem_mask); + void pci_ide_w(device_t *busdevice, int offset, UINT32 data, UINT32 mem_mask); + + UINT32 pci_usb_r(device_t *busdevice, int offset, UINT32 mem_mask); + void pci_usb_w(device_t *busdevice, int offset, UINT32 data, UINT32 mem_mask); +private: + UINT32 m_regs[3][0x400/4]; +}; + +// device type definition +extern const device_type I82371SB; + + +#endif /* __I82371SB_H__ */ diff --git a/src/devices/bus/lpci/i82439tx.c b/src/devices/bus/lpci/i82439tx.c new file mode 100644 index 00000000000..108302045d9 --- /dev/null +++ b/src/devices/bus/lpci/i82439tx.c @@ -0,0 +1,312 @@ +// license:BSD-3-Clause +// copyright-holders:Miodrag Milanovic +/*************************************************************************** + + Intel 82439TX System Controller (MTXC) + +***************************************************************************/ + +#include "emu.h" +#include "i82439tx.h" + +/*************************************************************************** + IMPLEMENTATION +***************************************************************************/ + +const device_type I82439TX = &device_creator; + + +i82439tx_device::i82439tx_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : northbridge_device(mconfig, I82439TX, "Intel 82439TX", tag, owner, clock, "i82439tx", __FILE__), + pci_device_interface( mconfig, *this ), + m_cpu_tag( NULL ), + m_region_tag( NULL ) +{ +} + +void i82439tx_device::i82439tx_configure_memory(UINT8 val, offs_t begin, offs_t end) +{ + switch (val & 0x03) + { + case 0: + m_space->install_rom(begin, end, m_rom + (begin - 0xc0000)); + m_space->nop_write(begin, end); + break; + case 1: + m_space->install_rom(begin, end, m_bios_ram + (begin - 0xc0000) / 4); + m_space->nop_write(begin, end); + break; + case 2: + m_space->install_rom(begin, end, m_rom + (begin - 0xc0000)); + m_space->install_writeonly(begin, end, m_bios_ram + (begin - 0xc0000) / 4); + break; + case 3: + m_space->install_ram(begin, end, m_bios_ram + (begin - 0xc0000) / 4); + break; + } +} + + +/*************************************************************************** + PCI INTERFACE +***************************************************************************/ + +UINT32 i82439tx_device::pci_read(pci_bus_device *pcibus, int function, int offset, UINT32 mem_mask) +{ + UINT32 result = 0; + + if (function != 0) + return 0; + + switch(offset) + { + case 0x00: /* vendor/device ID */ + result = 0x71008086; + break; + + case 0x08: /* revision identification register and class code register*/ + result = 0x06000001; + break; + + case 0x04: /* PCI command register */ + case 0x0C: + case 0x10: /* reserved */ + case 0x14: /* reserved */ + case 0x18: /* reserved */ + case 0x1C: /* reserved */ + case 0x20: /* reserved */ + case 0x24: /* reserved */ + case 0x28: /* reserved */ + case 0x2C: /* reserved */ + case 0x30: /* reserved */ + case 0x34: /* reserved */ + case 0x38: /* reserved */ + case 0x3C: /* reserved */ + case 0x40: /* reserved */ + case 0x44: /* reserved */ + case 0x48: /* reserved */ + case 0x4C: /* reserved */ + case 0x50: + case 0x54: + case 0x58: + case 0x5C: + case 0x60: + case 0x64: + case 0x68: + case 0x6C: + case 0x70: + case 0x74: + case 0x78: + case 0x7C: + case 0x80: + case 0x84: + case 0x88: + case 0x8C: + case 0x90: + case 0x94: + case 0x98: + case 0x9C: + case 0xA0: + case 0xA4: + case 0xA8: + case 0xAC: + case 0xB0: + case 0xB4: + case 0xB8: + case 0xBC: + case 0xC0: + case 0xC4: + case 0xC8: + case 0xCC: + case 0xD0: + case 0xD4: + case 0xD8: + case 0xDC: + case 0xE0: + case 0xE4: + case 0xE8: + case 0xEC: + case 0xF0: + case 0xF4: + case 0xF8: + case 0xFC: + assert(((offset - 0x50) / 4) >= 0 && ((offset - 0x50) / 4) < ARRAY_LENGTH(m_regs)); + result = m_regs[(offset - 0x50) / 4]; + break; + + default: + fatalerror("i82439tx_pci_read(): Unexpected PCI read 0x%02X\n", offset); + } + return result; +} + +void i82439tx_device::pci_write(pci_bus_device *pcibus, int function, int offset, UINT32 data, UINT32 mem_mask) +{ + if (function != 0) + return; + + switch(offset) + { + case 0x00: /* vendor/device ID */ + case 0x10: /* reserved */ + case 0x14: /* reserved */ + case 0x18: /* reserved */ + case 0x1C: /* reserved */ + case 0x20: /* reserved */ + case 0x24: /* reserved */ + case 0x28: /* reserved */ + case 0x2C: /* reserved */ + case 0x30: /* reserved */ + case 0x3C: /* reserved */ + case 0x40: /* reserved */ + case 0x44: /* reserved */ + case 0x48: /* reserved */ + case 0x4C: /* reserved */ + /* read only */ + break; + + case 0x04: /* PCI command register */ + case 0x0C: + case 0x50: + case 0x54: + case 0x58: + case 0x5C: + case 0x60: + case 0x64: + case 0x68: + case 0x6C: + case 0x70: + case 0x74: + case 0x78: + case 0x7C: + case 0x80: + case 0x84: + case 0x88: + case 0x8C: + case 0x90: + case 0x94: + case 0x98: + case 0x9C: + case 0xA0: + case 0xA4: + case 0xA8: + case 0xAC: + case 0xB0: + case 0xB4: + case 0xB8: + case 0xBC: + case 0xC0: + case 0xC4: + case 0xC8: + case 0xCC: + case 0xD0: + case 0xD4: + case 0xD8: + case 0xDC: + case 0xE0: + case 0xE4: + case 0xE8: + case 0xEC: + case 0xF0: + case 0xF4: + case 0xF8: + case 0xFC: + switch(offset) + { + case 0x58: + if ((mem_mask & 0x0000f000)) + i82439tx_configure_memory(data >> 12, 0xf0000, 0xfffff); + if ((mem_mask & 0x000f0000)) + i82439tx_configure_memory(data >> 16, 0xc0000, 0xc3fff); + if ((mem_mask & 0x00f00000)) + i82439tx_configure_memory(data >> 20, 0xc4000, 0xc7fff); + if ((mem_mask & 0x0f000000)) + i82439tx_configure_memory(data >> 24, 0xc8000, 0xccfff); + if ((mem_mask & 0xf0000000)) + i82439tx_configure_memory(data >> 28, 0xcc000, 0xcffff); + break; + + case 0x5C: + if ((mem_mask & 0x0000000f)) + i82439tx_configure_memory(data >> 0, 0xd0000, 0xd3fff); + if ((mem_mask & 0x000000f0)) + i82439tx_configure_memory(data >> 4, 0xd4000, 0xd7fff); + if ((mem_mask & 0x00000f00)) + i82439tx_configure_memory(data >> 8, 0xd8000, 0xdbfff); + if ((mem_mask & 0x0000f000)) + i82439tx_configure_memory(data >> 12, 0xdc000, 0xdffff); + if ((mem_mask & 0x000f0000)) + i82439tx_configure_memory(data >> 16, 0xe0000, 0xe3fff); + if ((mem_mask & 0x00f00000)) + i82439tx_configure_memory(data >> 20, 0xe4000, 0xe7fff); + if ((mem_mask & 0x0f000000)) + i82439tx_configure_memory(data >> 24, 0xe8000, 0xecfff); + if ((mem_mask & 0xf0000000)) + i82439tx_configure_memory(data >> 28, 0xec000, 0xeffff); + break; + } + + assert(((offset - 0x50) / 4) >= 0 && ((offset - 0x50) / 4) < ARRAY_LENGTH(m_regs)); + COMBINE_DATA(&m_regs[(offset - 0x50) / 4]); + break; + + default: + fatalerror("i82439tx_pci_write(): Unexpected PCI write 0x%02X <-- 0x%08X\n", offset, data); + } +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void i82439tx_device::device_start() +{ + northbridge_device::device_start(); + /* get address space we are working on */ + device_t *cpu = machine().device(m_cpu_tag); + assert(cpu != NULL); + + m_space = &cpu->memory().space(AS_PROGRAM); + + /* get rom region */ + m_rom = machine().root_device().memregion(m_region_tag)->base(); + + /* setup save states */ + save_item(NAME(m_regs)); + save_item(NAME(m_bios_ram)); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void i82439tx_device::device_reset() +{ + northbridge_device::device_reset(); + /* setup initial values */ + m_regs[0x00] = 0x14020000; + m_regs[0x01] = 0x01520000; + m_regs[0x02] = 0x00000000; + m_regs[0x03] = 0x00000000; + m_regs[0x04] = 0x02020202; + m_regs[0x05] = 0x00000002; + m_regs[0x06] = 0x00000000; + m_regs[0x07] = 0x00000000; + + memset(m_bios_ram, 0, sizeof(m_bios_ram)); + + /* configure initial memory state */ + i82439tx_configure_memory(0, 0xf0000, 0xfffff); + i82439tx_configure_memory(0, 0xc0000, 0xc3fff); + i82439tx_configure_memory(0, 0xc4000, 0xc7fff); + i82439tx_configure_memory(0, 0xc8000, 0xccfff); + i82439tx_configure_memory(0, 0xcc000, 0xcffff); + i82439tx_configure_memory(0, 0xd0000, 0xd3fff); + i82439tx_configure_memory(0, 0xd4000, 0xd7fff); + i82439tx_configure_memory(0, 0xd8000, 0xdbfff); + i82439tx_configure_memory(0, 0xdc000, 0xdffff); + i82439tx_configure_memory(0, 0xe0000, 0xe3fff); + i82439tx_configure_memory(0, 0xe4000, 0xe7fff); + i82439tx_configure_memory(0, 0xe8000, 0xecfff); + i82439tx_configure_memory(0, 0xec000, 0xeffff); +} diff --git a/src/devices/bus/lpci/i82439tx.h b/src/devices/bus/lpci/i82439tx.h new file mode 100644 index 00000000000..d6ac36a372e --- /dev/null +++ b/src/devices/bus/lpci/i82439tx.h @@ -0,0 +1,59 @@ +// license:BSD-3-Clause +// copyright-holders:Miodrag Milanovic +/*************************************************************************** + + Intel 82439TX System Controller (MTXC) + + Part of the Intel 430TX chipset + +***************************************************************************/ + +#ifndef __I82439TX_H__ +#define __I82439TX_H__ + +#include "pci.h" +#include "northbridge.h" + +#define MCFG_I82439TX_CPU( _tag ) \ + i82439tx_device::static_set_cpu(*device, _tag); + +#define MCFG_I82439TX_REGION( _tag ) \ + i82439tx_device::static_set_region(*device, _tag); + +// ======================> i82439tx_device + +class i82439tx_device : public northbridge_device, + public pci_device_interface +{ +public: + // construction/destruction + i82439tx_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + static void static_set_cpu(device_t &device, const char *tag) { dynamic_cast(device).m_cpu_tag = tag; } + static void static_set_region(device_t &device, const char *tag) { dynamic_cast(device).m_region_tag = tag; } + + virtual UINT32 pci_read(pci_bus_device *pcibus, int function, int offset, UINT32 mem_mask); + virtual void pci_write(pci_bus_device *pcibus, int function, int offset, UINT32 data, UINT32 mem_mask); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + void i82439tx_configure_memory(UINT8 val, offs_t begin, offs_t end); + +private: + const char *m_cpu_tag; + const char *m_region_tag; + + address_space *m_space; + UINT8 *m_rom; + + UINT32 m_regs[8]; + UINT32 m_bios_ram[0x40000 / 4]; +}; + +// device type definition +extern const device_type I82439TX; + +#endif /* __I82439TX_H__ */ diff --git a/src/devices/bus/lpci/mpc105.c b/src/devices/bus/lpci/mpc105.c new file mode 100644 index 00000000000..cd1c88c9f88 --- /dev/null +++ b/src/devices/bus/lpci/mpc105.c @@ -0,0 +1,233 @@ +// license:BSD-3-Clause +// copyright-holders:Miodrag Milanovic +/*************************************************************************** + + mpc105.h + + Motorola MPC105 PCI bridge + +***************************************************************************/ + +#include "emu.h" +#include "mpc105.h" +#include "machine/ram.h" + +#define LOG_MPC105 0 + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type MPC105 = &device_creator; + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// mpc105_device - constructor +//------------------------------------------------- + +mpc105_device::mpc105_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, MPC105, "MPC105", tag, owner, clock, "mpc105", __FILE__), + pci_device_interface( mconfig, *this ), + m_cpu_tag(NULL), + m_bank_base_default(0) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void mpc105_device::device_start() +{ + m_maincpu = machine().device(m_cpu_tag); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void mpc105_device::device_reset() +{ + m_bank_base = m_bank_base_default; + m_bank_enable = 0; + memset(m_bank_registers,0,sizeof(m_bank_registers)); +} + +//------------------------------------------------- +// update_memory - MMU update +//------------------------------------------------- + +void mpc105_device::update_memory() +{ + int bank; + offs_t begin, end; + char bank_str[10]; + + if (LOG_MPC105) + logerror("mpc105_update_memory(machine): Updating memory (bank enable=0x%02X)\n", m_bank_enable); + + if (m_bank_base > 0) + { + address_space &space = m_maincpu->space(AS_PROGRAM); + + /* first clear everything out */ + space.nop_read(0x00000000, 0x3FFFFFFF); + space.nop_read(0x00000000, 0x3FFFFFFF); + } + + for (bank = 0; bank < MPC105_MEMORYBANK_COUNT; bank++) + { + if (m_bank_enable & (1 << bank)) + { + begin = (((m_bank_registers[(bank / 4) + 0] >> (bank % 4) * 8)) & 0xFF) << 20 + | (((m_bank_registers[(bank / 4) + 2] >> (bank % 4) * 8)) & 0x03) << 28; + + end = (((m_bank_registers[(bank / 4) + 4] >> (bank % 4) * 8)) & 0xFF) << 20 + | (((m_bank_registers[(bank / 4) + 6] >> (bank % 4) * 8)) & 0x03) << 28 + | 0x000FFFFF; + + end = MIN(end, begin + machine().device(RAM_TAG)->size() - 1); + + if ((begin + 0x100000) <= end) + { + if (LOG_MPC105) + logerror("\tbank #%d [%02d]: 0x%08X - 0x%08X [%p-%p]\n", bank, bank + m_bank_base, begin, end, machine().device(RAM_TAG)->pointer(), machine().device(RAM_TAG)->pointer() + (end - begin)); + + if (m_bank_base > 0) + { + sprintf(bank_str,"bank%d",bank + m_bank_base); + membank(bank_str)->set_base(machine().device(RAM_TAG)->pointer()); + } + } + } + } +} + +//------------------------------------------------- +// pci_read - implementation of PCI read +//------------------------------------------------- + +UINT32 mpc105_device::pci_read(pci_bus_device *pcibus, int function, int offset, UINT32 mem_mask) +{ + UINT32 result; + + if (function != 0) + return 0; + + switch(offset) + { + case 0x00: /* vendor/device ID */ + result = 0x00011057; + break; + + case 0x08: + result = 0x06000000; + break; + + case 0x80: /* memory starting address 1 */ + case 0x84: /* memory starting address 2 */ + case 0x88: /* extended memory starting address 1 */ + case 0x8C: /* extended memory starting address 2 */ + case 0x90: /* memory ending address 1 */ + case 0x94: /* memory ending address 2 */ + case 0x98: /* extended memory ending address 1 */ + case 0x9C: /* extended memory ending address 2 */ + result = m_bank_registers[(offset - 0x80) / 4]; + break; + + case 0xA0: /* memory enable */ + result = m_bank_enable; + break; + + case 0xA8: /* processor interface configuration 1 */ + /* TODO: Fix me! */ + switch(/*cpu_getactivecpu()*/0) + { + case 0: + result = 0xFF000010; + break; + + case 1: + result = 0xFF008010; + break; + + default: + fatalerror("Unknown CPU\n"); + } + break; + + case 0xAC: /* processor interface configuration 1 */ + result = 0x000C060C; + break; + + case 0xF0: /* memory control configuration 1 */ + result = 0xFF020000; + break; + case 0xF4: /* memory control configuration 2 */ + result = 0x00000003; + break; + case 0xF8: /* memory control configuration 3 */ + result = 0x00000000; + break; + case 0xFC: /* memory control configuration 4 */ + result = 0x00100000; + break; + + default: + result = 0; + break; + } + return result; +} + +//------------------------------------------------- +// pci_write - implementation of PCI write +//------------------------------------------------- + +void mpc105_device::pci_write(pci_bus_device *pcibus, int function, int offset, UINT32 data, UINT32 mem_mask) +{ + int i; + if (function != 0) + return; + + switch(offset) + { + case 0x80: /* memory starting address 1 */ + case 0x84: /* memory starting address 2 */ + case 0x88: /* extended memory starting address 1 */ + case 0x8C: /* extended memory starting address 2 */ + case 0x90: /* memory ending address 1 */ + case 0x94: /* memory ending address 2 */ + case 0x98: /* extended memory ending address 1 */ + case 0x9C: /* extended memory ending address 2 */ + i = (offset - 0x80) / 4; + if (m_bank_registers[i] != data) + { + m_bank_registers[i] = data; + update_memory(); + } + break; + + case 0xA0: /* memory enable */ + if (m_bank_enable != (UINT8) data) + { + m_bank_enable = (UINT8) data; + update_memory(); + } + break; + + case 0xF0: /* memory control configuration 1 */ + case 0xF4: /* memory control configuration 2 */ + case 0xF8: /* memory control configuration 3 */ + case 0xFC: /* memory control configuration 4 */ + break; + + case 0xA8: /* processor interface configuration 1 */ + //fatalerror("mpc105_pci_write(): Unexpected PCI write 0x%02X <-- 0x%08X\n", offset, data); + break; + } +} diff --git a/src/devices/bus/lpci/mpc105.h b/src/devices/bus/lpci/mpc105.h new file mode 100644 index 00000000000..404a891d446 --- /dev/null +++ b/src/devices/bus/lpci/mpc105.h @@ -0,0 +1,60 @@ +// license:BSD-3-Clause +// copyright-holders:Miodrag Milanovic +/*************************************************************************** + + mpc105.h + + Motorola MPC105 PCI bridge + +***************************************************************************/ + +#ifndef MPC105_H +#define MPC105_H + +#include "pci.h" + +#define MPC105_MEMORYBANK_COUNT 8 + +#define MCFG_MPC105_CPU( _tag ) \ + mpc105_device::static_set_cpu(*device, _tag); + +#define MCFG_MPC105_BANK_BASE_DEFAULT( bank_base_default ) \ + mpc105_device::static_set_bank_base_default(*device, bank_base_default); + +// ======================> mpc105_device + +class mpc105_device : public device_t, + public pci_device_interface +{ +public: + // construction/destruction + mpc105_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + static void static_set_cpu(device_t &device, const char *tag) { dynamic_cast(device).m_cpu_tag = tag; } + static void static_set_bank_base_default(device_t &device, int bank_base_default) { dynamic_cast(device).m_bank_base_default = bank_base_default; } + + virtual UINT32 pci_read(pci_bus_device *pcibus, int function, int offset, UINT32 mem_mask); + virtual void pci_write(pci_bus_device *pcibus, int function, int offset, UINT32 data, UINT32 mem_mask); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + void update_memory(); + +private: + const char *m_cpu_tag; + int m_bank_base_default; + int m_bank_base; + UINT8 m_bank_enable; + UINT32 m_bank_registers[8]; + + cpu_device* m_maincpu; +}; + + +// device type definition +extern const device_type MPC105; + +#endif /* MPC105_H */ diff --git a/src/devices/bus/lpci/northbridge.c b/src/devices/bus/lpci/northbridge.c new file mode 100644 index 00000000000..ec5a0a8582a --- /dev/null +++ b/src/devices/bus/lpci/northbridge.c @@ -0,0 +1,48 @@ +// license:BSD-3-Clause +// copyright-holders:Miodrag Milanovic +/*************************************************************************** + + Northbridge implementation + +***************************************************************************/ + +#include "emu.h" +#include "northbridge.h" + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +northbridge_device::northbridge_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + m_maincpu(*this, ":maincpu"), + m_ram(*this, ":" RAM_TAG) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void northbridge_device::device_start() +{ + address_space& space = machine().device(":maincpu")->memory().space(AS_PROGRAM); + + machine().root_device().membank("bank10")->set_base(m_ram->pointer()); + + if (m_ram->size() > 0x0a0000) + { + offs_t ram_limit = 0x100000 + m_ram->size() - 0x0a0000; + space.install_read_bank(0x100000, ram_limit - 1, "bank1"); + space.install_write_bank(0x100000, ram_limit - 1, "bank1"); + machine().root_device().membank("bank1")->set_base(m_ram->pointer() + 0xa0000); + } +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void northbridge_device::device_reset() +{ +} diff --git a/src/devices/bus/lpci/northbridge.h b/src/devices/bus/lpci/northbridge.h new file mode 100644 index 00000000000..f52f690ada2 --- /dev/null +++ b/src/devices/bus/lpci/northbridge.h @@ -0,0 +1,34 @@ +// license:BSD-3-Clause +// copyright-holders:Miodrag Milanovic +#pragma once + +#ifndef __NORTHBRIDGE_H__ +#define __NORTHBRIDGE_H__ + +#include "emu.h" + +#include "machine/ram.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> northbridge_device + +class northbridge_device : + public device_t +{ +public: + // construction/destruction + northbridge_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); +public: + required_device m_maincpu; + required_device m_ram; + +}; + +#endif /* __NORTHBRIDGE_H__ */ diff --git a/src/devices/bus/lpci/pci.c b/src/devices/bus/lpci/pci.c new file mode 100644 index 00000000000..13baf9e66a3 --- /dev/null +++ b/src/devices/bus/lpci/pci.c @@ -0,0 +1,334 @@ +// license:BSD-3-Clause +// copyright-holders:Miodrag Milanovic +/*************************************************************************** + + pci.c + + PCI bus + + The PCI bus is a 32-bit bus introduced by Intel, so it is little endian + + Control word: + bit 31: Enable bit + bits 30-24: Reserved + bits 23-16: PCI bus number + bits 15-11: PCI device number + bits 10- 8: PCI function number + bits 7- 0: Offset address + + Standard PCI registers: + 0x00 2 Vendor ID + 0x02 2 Device ID + 0x04 2 PCI Command + 0x06 2 PCI Status + 0x08 1 Revision ID + 0x09 1 Programming Interface + 0x0A 1 Subclass Code + 0x0B 1 Class Code + + Class Code/Subclass Code/Programming Interface + 0x00XXXX Pre-PCI 2.0 devices + 0x000000 Non-VGA device + 0x000101 VGA device + 0x01XXXX Storage Controller + 0x010000 SCSI + 0x0101XX IDE + 0x0102XX Floppy + 0x0103XX IPI + 0x0104XX RAID + 0x0180XX Other + 0x02XXXX Network Card + 0x020000 Ethernet + 0x020100 Tokenring + 0x020200 FDDI + 0x020300 ATM + 0x028000 Other + 0x03XXXX Display Controller + 0x030000 VGA + 0x030001 8514 Compatible + 0x030100 XGA + 0x038000 Other + 0x04XXXX Multimedia + 0x040000 Video + 0x040100 Audio + 0x048000 Other + 0x05XXXX Memory Controller + 0x050000 RAM + 0x050100 Flash + 0x058000 Other + 0x06XXXX Bridge + 0x060000 Host/PCI + 0x060100 PCI/ISA + 0x060200 PCI/EISA + 0x060300 PCI/Micro Channel + 0x060400 PCI/PCI + 0x060500 PCI/PCMCIA + 0x060600 PCI/NuBus + 0x060700 PCI/CardBus + 0x068000 Other + + Information on PCI vendors can be found at http://www.pcidatabase.com/ + +***************************************************************************/ + +#include "emu.h" +#include "pci.h" + +#define LOG_PCI 0 + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type PCI_BUS = &device_creator; + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// pci_bus_device - constructor +//------------------------------------------------- +pci_bus_device::pci_bus_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, PCI_BUS, "PCI Bus", tag, owner, clock, "pci_bus", __FILE__), + m_father(NULL) +{ + for (int i = 0; i < ARRAY_LENGTH(m_devtag); i++) { + m_devtag[i]= NULL; + } + m_siblings_count = 0; +} + +/*************************************************************************** + INLINE FUNCTIONS +***************************************************************************/ + +READ32_MEMBER( pci_bus_device::read ) +{ + UINT32 result = 0xffffffff; + int function, reg; + + offset %= 2; + + switch (offset) + { + case 0: + result = m_address; + break; + + case 1: + if (m_devicenum != -1) + { + if (m_busnumaddr->m_device[m_devicenum] != NULL) + { + function = (m_address >> 8) & 0x07; + reg = (m_address >> 0) & 0xfc; + result = m_busnumaddr->m_device[m_devicenum]->pci_read(m_busnumaddr, function, reg, mem_mask); + } + } + break; + } + + if (LOG_PCI) + logerror("read('%s'): offset=%d result=0x%08X\n", tag(), offset, result); + + return result; +} + + + +pci_bus_device *pci_bus_device::pci_search_bustree(int busnum, int devicenum, pci_bus_device *pcibus) +{ + int a; + pci_bus_device *ret; + + if (pcibus->m_busnum == busnum) + { + return pcibus; + } + for (a = 0; a < pcibus->m_siblings_count; a++) + { + ret = pci_search_bustree(busnum, devicenum, pcibus->m_siblings[a]); + if (ret != NULL) + return ret; + } + return NULL; +} + + + +WRITE32_MEMBER( pci_bus_device::write ) +{ + offset %= 2; + + if (LOG_PCI) + logerror("write('%s'): offset=%d data=0x%08X\n", tag(), offset, data); + + switch (offset) + { + case 0: + m_address = data; + + /* lookup current device */ + if (m_address & 0x80000000) + { + int busnum = (m_address >> 16) & 0xff; + int devicenum = (m_address >> 11) & 0x1f; + m_busnumaddr = pci_search_bustree(busnum, devicenum, this); + if (m_busnumaddr != NULL) + { + m_busnumber = busnum; + m_devicenum = devicenum; + } + else + m_devicenum = -1; + if (LOG_PCI) + logerror(" bus:%d device:%d\n", busnum, devicenum); + } + break; + + case 1: + if (m_devicenum != -1) + { + if (m_busnumaddr->m_device[m_devicenum] != NULL) + { + int function = (m_address >> 8) & 0x07; + int reg = (m_address >> 0) & 0xfc; + m_busnumaddr->m_device[m_devicenum]->pci_write(m_busnumaddr, function, reg, data, mem_mask); + } + if (LOG_PCI) + logerror(" function:%d register:%d\n", (m_address >> 8) & 0x07, (m_address >> 0) & 0xfc); + } + break; + } +} + + + +READ64_MEMBER(pci_bus_device::read_64be) +{ + UINT64 result = 0; + mem_mask = FLIPENDIAN_INT64(mem_mask); + if (ACCESSING_BITS_0_31) + result |= (UINT64)read(space, offset * 2 + 0, mem_mask >> 0) << 0; + if (ACCESSING_BITS_32_63) + result |= (UINT64)read(space, offset * 2 + 1, mem_mask >> 32) << 32; + return FLIPENDIAN_INT64(result); +} + +WRITE64_MEMBER(pci_bus_device::write_64be) +{ + data = FLIPENDIAN_INT64(data); + mem_mask = FLIPENDIAN_INT64(mem_mask); + if (ACCESSING_BITS_0_31) + write(space, offset * 2 + 0, data >> 0, mem_mask >> 0); + if (ACCESSING_BITS_32_63) + write(space, offset * 2 + 1, data >> 32, mem_mask >> 32); +} + + +void pci_bus_device::add_sibling(pci_bus_device *sibling, int busnum) +{ + m_siblings[m_siblings_count] = sibling; + m_siblings_busnum[m_siblings_count] = busnum; + m_siblings_count++; +} + + +//------------------------------------------------- +// device_post_load - handle updating after a +// restore +//------------------------------------------------- + +void pci_bus_device::device_post_load() +{ + if (m_devicenum != -1) + { + m_busnumaddr = pci_search_bustree(m_busnumber, m_devicenum, this); + } +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void pci_bus_device::device_start() +{ + /* store a pointer back to the device */ + m_devicenum = -1; + + char id[3]; + /* find all our devices */ + for (int i = 0; i < ARRAY_LENGTH(m_devtag); i++) + { + sprintf(id, "%d", i); + pci_connector *conn = downcast(subdevice(id)); + if (conn!=NULL) + m_device[i] = conn->get_device(); + else + m_device[i] = NULL; + } + + if (m_father != NULL) { + pci_bus_device *father = machine().device(m_father); + if (father) + father->add_sibling(this, m_busnum); + } + + /* register pci states */ + save_item(NAME(m_address)); + save_item(NAME(m_devicenum)); + save_item(NAME(m_busnum)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void pci_bus_device::device_reset() +{ + /* reset the drive state */ + m_devicenum = -1; + m_address = 0; +} + +//------------------------------------------------- +// pci_device_interface - constructor +//------------------------------------------------- + +pci_device_interface::pci_device_interface(const machine_config &mconfig, device_t &device) + : device_slot_card_interface(mconfig, device) +{ +} + +//------------------------------------------------- +// ~pci_device_interface - destructor +//------------------------------------------------- + +pci_device_interface::~pci_device_interface() +{ +} + + +const device_type PCI_CONNECTOR = &device_creator; + + +pci_connector::pci_connector(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, PCI_CONNECTOR, "PCI device connector abstraction", tag, owner, clock, "pci_connector", __FILE__), + device_slot_interface(mconfig, *this) +{ +} + +pci_connector::~pci_connector() +{ +} + +void pci_connector::device_start() +{ +} + +pci_device_interface *pci_connector::get_device() +{ + return dynamic_cast(get_card_device()); +} diff --git a/src/devices/bus/lpci/pci.h b/src/devices/bus/lpci/pci.h new file mode 100644 index 00000000000..87433ebdd6f --- /dev/null +++ b/src/devices/bus/lpci/pci.h @@ -0,0 +1,112 @@ +// license:BSD-3-Clause +// copyright-holders:Miodrag Milanovic +/*************************************************************************** + + pci.h + + PCI bus + +***************************************************************************/ + +#ifndef PCI_H +#define PCI_H + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** +class pci_bus_device; + +// ======================> pci_device_interface + +class pci_device_interface : public device_slot_card_interface +{ +public: + // construction/destruction + pci_device_interface(const machine_config &mconfig, device_t &device); + virtual ~pci_device_interface(); + + virtual UINT32 pci_read(pci_bus_device *pcibus, int function, int offset, UINT32 mem_mask) = 0; + virtual void pci_write(pci_bus_device *pcibus, int function, int offset, UINT32 data, UINT32 mem_mask) = 0; +private: +}; + +class pci_connector: public device_t, + public device_slot_interface +{ +public: + pci_connector(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual ~pci_connector(); + + pci_device_interface *get_device(); + +protected: + virtual void device_start(); +}; + +extern const device_type PCI_CONNECTOR; + +// ======================> pci_bus_device + +class pci_bus_device : public device_t +{ +public: + // construction/destruction + pci_bus_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + DECLARE_READ32_MEMBER( read ); + DECLARE_WRITE32_MEMBER( write ); + + DECLARE_READ64_MEMBER( read_64be ); + DECLARE_WRITE64_MEMBER( write_64be ); + + void set_busnum(int busnum) { m_busnum = busnum; } + void set_father(const char *father) { m_father = father; } + void set_device(int num, const char *tag) { + m_devtag[num] = tag; } + + pci_bus_device *pci_search_bustree(int busnum, int devicenum, pci_bus_device *pcibus); + void add_sibling(pci_bus_device *sibling, int busnum); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_post_load(); + +private: + UINT8 m_busnum; + + const char * m_devtag[32]; + pci_device_interface *m_device[32]; + + const char * m_father; + pci_bus_device * m_siblings[8]; + UINT8 m_siblings_busnum[8]; + int m_siblings_count; + + offs_t m_address; + INT8 m_devicenum; // device number we are addressing + INT8 m_busnumber; // pci bus number we are addressing + pci_bus_device * m_busnumaddr; // pci bus we are addressing +}; + +// device type definition +extern const device_type PCI_BUS; + + +/*************************************************************************** + DEVICE CONFIGURATION MACROS +***************************************************************************/ + +#define MCFG_PCI_BUS_ADD(_tag, _busnum) \ + MCFG_DEVICE_ADD(_tag, PCI_BUS, 0) \ + downcast(device)->set_busnum(_busnum); +#define MCFG_PCI_BUS_DEVICE(_tag, _slot_intf, _def_slot, _fixed) \ + MCFG_DEVICE_ADD(_tag, PCI_CONNECTOR, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, _fixed) + +#define MCFG_PCI_BUS_SIBLING(_father_tag) \ + downcast(device)->set_father(_father_tag); + + +#endif /* PCI_H */ diff --git a/src/devices/bus/lpci/southbridge.c b/src/devices/bus/lpci/southbridge.c new file mode 100644 index 00000000000..b051d29a73a --- /dev/null +++ b/src/devices/bus/lpci/southbridge.c @@ -0,0 +1,490 @@ +// license:BSD-3-Clause +// copyright-holders:Miodrag Milanovic +/*************************************************************************** + + Southbridge implementation + +***************************************************************************/ + +#include "emu.h" +#include "cpu/i386/i386.h" +#include "southbridge.h" +#include "bus/pc_kbd/keyboards.h" + + +static SLOT_INTERFACE_START(pc_isa_onboard) + SLOT_INTERFACE("comat", ISA8_COM_AT) + SLOT_INTERFACE("lpt", ISA8_LPT) + SLOT_INTERFACE("fdcsmc", ISA8_FDC_SMC) +SLOT_INTERFACE_END + +static MACHINE_CONFIG_FRAGMENT( southbridge ) + MCFG_DEVICE_ADD("pit8254", PIT8254, 0) + MCFG_PIT8253_CLK0(4772720/4) /* heartbeat IRQ */ + MCFG_PIT8253_OUT0_HANDLER(WRITELINE(southbridge_device, at_pit8254_out0_changed)) + MCFG_PIT8253_CLK1(4772720/4) /* dram refresh */ + MCFG_PIT8253_OUT1_HANDLER(WRITELINE(southbridge_device, at_pit8254_out1_changed)) + MCFG_PIT8253_CLK2(4772720/4) /* pio port c pin 4, and speaker polling enough */ + MCFG_PIT8253_OUT2_HANDLER(WRITELINE(southbridge_device, at_pit8254_out2_changed)) + + MCFG_DEVICE_ADD( "dma8237_1", AM9517A, XTAL_14_31818MHz/3 ) + MCFG_I8237_OUT_HREQ_CB(DEVWRITELINE("dma8237_2", am9517a_device, dreq0_w)) + MCFG_I8237_OUT_EOP_CB(WRITELINE(southbridge_device, at_dma8237_out_eop)) + MCFG_I8237_IN_MEMR_CB(READ8(southbridge_device, pc_dma_read_byte)) + MCFG_I8237_OUT_MEMW_CB(WRITE8(southbridge_device, pc_dma_write_byte)) + MCFG_I8237_IN_IOR_0_CB(READ8(southbridge_device, pc_dma8237_0_dack_r)) + MCFG_I8237_IN_IOR_1_CB(READ8(southbridge_device, pc_dma8237_1_dack_r)) + MCFG_I8237_IN_IOR_2_CB(READ8(southbridge_device, pc_dma8237_2_dack_r)) + MCFG_I8237_IN_IOR_3_CB(READ8(southbridge_device, pc_dma8237_3_dack_r)) + MCFG_I8237_OUT_IOW_0_CB(WRITE8(southbridge_device, pc_dma8237_0_dack_w)) + MCFG_I8237_OUT_IOW_1_CB(WRITE8(southbridge_device, pc_dma8237_1_dack_w)) + MCFG_I8237_OUT_IOW_2_CB(WRITE8(southbridge_device, pc_dma8237_2_dack_w)) + MCFG_I8237_OUT_IOW_3_CB(WRITE8(southbridge_device, pc_dma8237_3_dack_w)) + MCFG_I8237_OUT_DACK_0_CB(WRITELINE(southbridge_device, pc_dack0_w)) + MCFG_I8237_OUT_DACK_1_CB(WRITELINE(southbridge_device, pc_dack1_w)) + MCFG_I8237_OUT_DACK_2_CB(WRITELINE(southbridge_device, pc_dack2_w)) + MCFG_I8237_OUT_DACK_3_CB(WRITELINE(southbridge_device, pc_dack3_w)) + + MCFG_DEVICE_ADD( "dma8237_2", AM9517A, XTAL_14_31818MHz/3 ) + MCFG_I8237_OUT_HREQ_CB(WRITELINE(southbridge_device, pc_dma_hrq_changed)) + MCFG_I8237_IN_MEMR_CB(READ8(southbridge_device, pc_dma_read_word)) + MCFG_I8237_OUT_MEMW_CB(WRITE8(southbridge_device, pc_dma_write_word)) + MCFG_I8237_IN_IOR_1_CB(READ8(southbridge_device, pc_dma8237_5_dack_r)) + MCFG_I8237_IN_IOR_2_CB(READ8(southbridge_device, pc_dma8237_6_dack_r)) + MCFG_I8237_IN_IOR_3_CB(READ8(southbridge_device, pc_dma8237_7_dack_r)) + MCFG_I8237_OUT_IOW_1_CB(WRITE8(southbridge_device, pc_dma8237_5_dack_w)) + MCFG_I8237_OUT_IOW_2_CB(WRITE8(southbridge_device, pc_dma8237_6_dack_w)) + MCFG_I8237_OUT_IOW_3_CB(WRITE8(southbridge_device, pc_dma8237_7_dack_w)) + MCFG_I8237_OUT_DACK_0_CB(WRITELINE(southbridge_device, pc_dack4_w)) + MCFG_I8237_OUT_DACK_1_CB(WRITELINE(southbridge_device, pc_dack5_w)) + MCFG_I8237_OUT_DACK_2_CB(WRITELINE(southbridge_device, pc_dack6_w)) + MCFG_I8237_OUT_DACK_3_CB(WRITELINE(southbridge_device, pc_dack7_w)) + + MCFG_PIC8259_ADD( "pic8259_master", INPUTLINE(":maincpu", 0), VCC, READ8(southbridge_device, get_slave_ack) ) + MCFG_PIC8259_ADD( "pic8259_slave", DEVWRITELINE("pic8259_master", pic8259_device, ir2_w), GND, NULL ) + + MCFG_DEVICE_ADD("keybc", AT_KEYBOARD_CONTROLLER, XTAL_12MHz) + MCFG_AT_KEYBOARD_CONTROLLER_SYSTEM_RESET_CB(INPUTLINE(":maincpu", INPUT_LINE_RESET)) + MCFG_AT_KEYBOARD_CONTROLLER_GATE_A20_CB(INPUTLINE(":maincpu", INPUT_LINE_A20)) + MCFG_AT_KEYBOARD_CONTROLLER_INPUT_BUFFER_FULL_CB(DEVWRITELINE("pic8259_master", pic8259_device, ir1_w)) + MCFG_AT_KEYBOARD_CONTROLLER_KEYBOARD_CLOCK_CB(DEVWRITELINE("pc_kbdc", pc_kbdc_device, clock_write_from_mb)) + MCFG_AT_KEYBOARD_CONTROLLER_KEYBOARD_DATA_CB(DEVWRITELINE("pc_kbdc", pc_kbdc_device, data_write_from_mb)) + MCFG_DEVICE_ADD("pc_kbdc", PC_KBDC, 0) + MCFG_PC_KBDC_OUT_CLOCK_CB(DEVWRITELINE("keybc", at_keyboard_controller_device, keyboard_clock_w)) + MCFG_PC_KBDC_OUT_DATA_CB(DEVWRITELINE("keybc", at_keyboard_controller_device, keyboard_data_w)) + MCFG_PC_KBDC_SLOT_ADD("pc_kbdc", "kbd", pc_at_keyboards, STR_KBD_MICROSOFT_NATURAL) + + MCFG_DS12885_ADD("rtc") + MCFG_MC146818_IRQ_HANDLER(DEVWRITELINE("pic8259_slave", pic8259_device, ir0_w)) + MCFG_MC146818_CENTURY_INDEX(0x32) + + MCFG_BUS_MASTER_IDE_CONTROLLER_ADD("ide", ata_devices, "hdd", NULL, false) + MCFG_ATA_INTERFACE_IRQ_HANDLER(DEVWRITELINE("pic8259_slave", pic8259_device, ir6_w)) + MCFG_BUS_MASTER_IDE_CONTROLLER_SPACE(":maincpu", AS_PROGRAM) + + MCFG_BUS_MASTER_IDE_CONTROLLER_ADD("ide2", ata_devices, "cdrom", NULL, false) + MCFG_ATA_INTERFACE_IRQ_HANDLER(DEVWRITELINE("pic8259_slave", pic8259_device, ir7_w)) + MCFG_BUS_MASTER_IDE_CONTROLLER_SPACE(":maincpu", AS_PROGRAM) + + /* sound hardware */ + MCFG_SPEAKER_STANDARD_MONO("mono") + MCFG_SOUND_ADD("speaker", SPEAKER_SOUND, 0) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.50) + + MCFG_DEVICE_ADD("isabus", ISA16, 0) + MCFG_ISA16_CPU(":maincpu") + MCFG_ISA_OUT_IRQ2_CB(DEVWRITELINE("pic8259_slave", pic8259_device, ir2_w)) // in place of irq 2 on at irq 9 is used + MCFG_ISA_OUT_IRQ3_CB(DEVWRITELINE("pic8259_master", pic8259_device, ir3_w)) + MCFG_ISA_OUT_IRQ4_CB(DEVWRITELINE("pic8259_master", pic8259_device, ir4_w)) + MCFG_ISA_OUT_IRQ5_CB(DEVWRITELINE("pic8259_master", pic8259_device, ir5_w)) + MCFG_ISA_OUT_IRQ6_CB(DEVWRITELINE("pic8259_master", pic8259_device, ir6_w)) + MCFG_ISA_OUT_IRQ7_CB(DEVWRITELINE("pic8259_master", pic8259_device, ir7_w)) + MCFG_ISA_OUT_IRQ10_CB(DEVWRITELINE("pic8259_slave", pic8259_device, ir3_w)) + MCFG_ISA_OUT_IRQ11_CB(DEVWRITELINE("pic8259_slave", pic8259_device, ir4_w)) + MCFG_ISA_OUT_IRQ12_CB(DEVWRITELINE("pic8259_slave", pic8259_device, ir5_w)) + MCFG_ISA_OUT_IRQ14_CB(DEVWRITELINE("pic8259_slave", pic8259_device, ir6_w)) + MCFG_ISA_OUT_IRQ15_CB(DEVWRITELINE("pic8259_slave", pic8259_device, ir7_w)) + MCFG_ISA_OUT_DRQ0_CB(DEVWRITELINE("dma8237_1", am9517a_device, dreq0_w)) + MCFG_ISA_OUT_DRQ1_CB(DEVWRITELINE("dma8237_1", am9517a_device, dreq1_w)) + MCFG_ISA_OUT_DRQ2_CB(DEVWRITELINE("dma8237_1", am9517a_device, dreq2_w)) + MCFG_ISA_OUT_DRQ3_CB(DEVWRITELINE("dma8237_1", am9517a_device, dreq3_w)) + MCFG_ISA_OUT_DRQ5_CB(DEVWRITELINE("dma8237_2", am9517a_device, dreq1_w)) + MCFG_ISA_OUT_DRQ6_CB(DEVWRITELINE("dma8237_2", am9517a_device, dreq2_w)) + MCFG_ISA_OUT_DRQ7_CB(DEVWRITELINE("dma8237_2", am9517a_device, dreq3_w)) + // on board devices + MCFG_ISA16_SLOT_ADD("isabus","board1", pc_isa_onboard, "fdcsmc", true) + MCFG_ISA16_SLOT_ADD("isabus","board2", pc_isa_onboard, "comat", true) + MCFG_ISA16_SLOT_ADD("isabus","board3", pc_isa_onboard, "lpt", true) +MACHINE_CONFIG_END + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor southbridge_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( southbridge ); +} + +southbridge_device::southbridge_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + m_maincpu(*this, ":maincpu"), + m_pic8259_master(*this, "pic8259_master"), + m_pic8259_slave(*this, "pic8259_slave"), + m_dma8237_1(*this, "dma8237_1"), + m_dma8237_2(*this, "dma8237_2"), + m_pit8254(*this, "pit8254"), + m_keybc(*this, "keybc"), + m_isabus(*this, "isabus"), + m_speaker(*this, "speaker"), + m_ds12885(*this, "rtc"), + m_pc_kbdc(*this, "pc_kbdc"), + m_ide(*this, "ide"), + m_ide2(*this, "ide2") +{ +} +/********************************************************** + * + * Init functions + * + **********************************************************/ + +/// HACK: the memory system cannot cope with mixing the 8 bit device map from the fdc with a 32 bit handler +READ8_MEMBER(southbridge_device::ide_read_cs1_r) +{ + return m_ide->read_cs1(space, 1, (UINT32) 0xff0000) >> 16; +} + +WRITE8_MEMBER(southbridge_device::ide_write_cs1_w) +{ + m_ide->write_cs1(space, 1, (UINT32) data << 16, (UINT32) 0xff0000); +} + +READ8_MEMBER(southbridge_device::ide2_read_cs1_r) +{ + return m_ide2->read_cs1(space, 1, (UINT32) 0xff0000) >> 16; +} + +WRITE8_MEMBER(southbridge_device::ide2_write_cs1_w) +{ + m_ide2->write_cs1(space, 1, (UINT32) data << 16, (UINT32) 0xff0000); +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void southbridge_device::device_start() +{ + address_space& spaceio = machine().device(":maincpu")->memory().space(AS_IO); + + spaceio.install_readwrite_handler(0x0000, 0x001f, read8_delegate(FUNC(am9517a_device::read),&(*m_dma8237_1)), write8_delegate(FUNC(am9517a_device::write),&(*m_dma8237_1)), 0xffffffff); + spaceio.install_readwrite_handler(0x0020, 0x003f, read8_delegate(FUNC(pic8259_device::read),&(*m_pic8259_master)), write8_delegate(FUNC(pic8259_device::write),&(*m_pic8259_master)), 0xffffffff); + spaceio.install_readwrite_handler(0x0040, 0x005f, read8_delegate(FUNC(pit8254_device::read),&(*m_pit8254)), write8_delegate(FUNC(pit8254_device::write),&(*m_pit8254)), 0xffffffff); + spaceio.install_readwrite_handler(0x0060, 0x0063, read8_delegate(FUNC(southbridge_device::at_keybc_r),this), write8_delegate(FUNC(southbridge_device::at_keybc_w),this), 0xffffffff); + spaceio.install_readwrite_handler(0x0064, 0x0067, read8_delegate(FUNC(at_keyboard_controller_device::status_r),&(*m_keybc)), write8_delegate(FUNC(at_keyboard_controller_device::command_w),&(*m_keybc)), 0xffffffff); + spaceio.install_readwrite_handler(0x0070, 0x007f, read8_delegate(FUNC(ds12885_device::read),&(*m_ds12885)), write8_delegate(FUNC(ds12885_device::write),&(*m_ds12885)), 0xffffffff); + spaceio.install_readwrite_handler(0x0080, 0x009f, read8_delegate(FUNC(southbridge_device::at_page8_r),this), write8_delegate(FUNC(southbridge_device::at_page8_w),this), 0xffffffff); + spaceio.install_readwrite_handler(0x00a0, 0x00bf, read8_delegate(FUNC(pic8259_device::read),&(*m_pic8259_slave)), write8_delegate(FUNC(pic8259_device::write),&(*m_pic8259_slave)), 0xffffffff); + spaceio.install_readwrite_handler(0x00c0, 0x00df, read8_delegate(FUNC(southbridge_device::at_dma8237_2_r),this), write8_delegate(FUNC(southbridge_device::at_dma8237_2_w),this), 0xffffffff); + spaceio.install_readwrite_handler(0x0170, 0x0177, read32_delegate(FUNC(bus_master_ide_controller_device::read_cs0),&(*m_ide2)), write32_delegate(FUNC(bus_master_ide_controller_device::write_cs0), &(*m_ide2)),0xffffffff); + spaceio.install_readwrite_handler(0x01f0, 0x01f7, read32_delegate(FUNC(bus_master_ide_controller_device::read_cs0),&(*m_ide)), write32_delegate(FUNC(bus_master_ide_controller_device::write_cs0), &(*m_ide)),0xffffffff); +// HACK: this works if you take out the (non working) fdc +// spaceio.install_readwrite_handler(0x0370, 0x0377, read32_delegate(FUNC(bus_master_ide_controller_device::read_cs1),&(*m_ide2)), write32_delegate(FUNC(bus_master_ide_controller_device::write_cs1), &(*m_ide2)),0xffffffff); +// spaceio.install_readwrite_handler(0x03f0, 0x03f7, read32_delegate(FUNC(bus_master_ide_controller_device::read_cs1),&(*m_ide)), write32_delegate(FUNC(bus_master_ide_controller_device::write_cs1), &(*m_ide)),0xffffffff); + spaceio.install_readwrite_handler(0x0374, 0x0377, read8_delegate(FUNC(southbridge_device::ide2_read_cs1_r),this), write8_delegate(FUNC(southbridge_device::ide2_write_cs1_w), this),0xff0000); + spaceio.install_readwrite_handler(0x03f4, 0x03f7, read8_delegate(FUNC(southbridge_device::ide_read_cs1_r),this), write8_delegate(FUNC(southbridge_device::ide_write_cs1_w), this),0xff0000); + spaceio.nop_readwrite(0x00e0, 0x00ef); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void southbridge_device::device_reset() +{ + m_at_spkrdata = 0; + m_pit_out2 = 1; + m_dma_channel = -1; + m_cur_eop = false; + m_nmi_enabled = 0; + m_refresh = false; +} + + +/************************************************************* + * + * pic8259 configuration + * + *************************************************************/ +READ8_MEMBER( southbridge_device::get_slave_ack ) +{ + if (offset==2) // IRQ = 2 + return m_pic8259_slave->acknowledge(); + + return 0x00; +} + +/************************************************************************* + * + * PC Speaker related + * + *************************************************************************/ + +void southbridge_device::at_speaker_set_spkrdata(UINT8 data) +{ + m_at_spkrdata = data ? 1 : 0; + m_speaker->level_w(m_at_spkrdata & m_pit_out2); +} + + + +/************************************************************* + * + * pit8254 configuration + * + *************************************************************/ + +WRITE_LINE_MEMBER( southbridge_device::at_pit8254_out0_changed ) +{ + if (m_pic8259_master) + m_pic8259_master->ir0_w(state); +} + +WRITE_LINE_MEMBER( southbridge_device::at_pit8254_out1_changed ) +{ + if(state) + m_refresh = !m_refresh; +} + +WRITE_LINE_MEMBER( southbridge_device::at_pit8254_out2_changed ) +{ + m_pit_out2 = state ? 1 : 0; + m_speaker->level_w(m_at_spkrdata & m_pit_out2); +} + +/************************************************************************* + * + * PC DMA stuff + * + *************************************************************************/ + +READ8_MEMBER( southbridge_device::at_page8_r ) +{ + UINT8 data = m_at_pages[offset % 0x10]; + + switch(offset % 8) + { + case 1: + data = m_dma_offset[BIT(offset, 3)][2]; + break; + case 2: + data = m_dma_offset[BIT(offset, 3)][3]; + break; + case 3: + data = m_dma_offset[BIT(offset, 3)][1]; + break; + case 7: + data = m_dma_offset[BIT(offset, 3)][0]; + break; + } + return data; +} + + +WRITE8_MEMBER( southbridge_device::at_page8_w ) +{ + m_at_pages[offset % 0x10] = data; + + switch(offset % 8) + { + case 1: + m_dma_offset[BIT(offset, 3)][2] = data; + break; + case 2: + m_dma_offset[BIT(offset, 3)][3] = data; + break; + case 3: + m_dma_offset[BIT(offset, 3)][1] = data; + break; + case 7: + m_dma_offset[BIT(offset, 3)][0] = data; + break; + } +} + + +WRITE_LINE_MEMBER( southbridge_device::pc_dma_hrq_changed ) +{ + m_maincpu->set_input_line(INPUT_LINE_HALT, state ? ASSERT_LINE : CLEAR_LINE); + + /* Assert HLDA */ + m_dma8237_2->hack_w( state ); +} + +READ8_MEMBER(southbridge_device::pc_dma_read_byte) +{ + address_space& prog_space = m_maincpu->space(AS_PROGRAM); // get the right address space + if(m_dma_channel == -1) + return 0xff; + UINT8 result; + offs_t page_offset = (((offs_t) m_dma_offset[0][m_dma_channel]) << 16) & 0xFF0000; + + result = prog_space.read_byte(page_offset + offset); + return result; +} + + +WRITE8_MEMBER(southbridge_device::pc_dma_write_byte) +{ + address_space& prog_space = m_maincpu->space(AS_PROGRAM); // get the right address space + if(m_dma_channel == -1) + return; + offs_t page_offset = (((offs_t) m_dma_offset[0][m_dma_channel]) << 16) & 0xFF0000; + + prog_space.write_byte(page_offset + offset, data); +} + + +READ8_MEMBER(southbridge_device::pc_dma_read_word) +{ + address_space& prog_space = m_maincpu->space(AS_PROGRAM); // get the right address space + if(m_dma_channel == -1) + return 0xff; + UINT16 result; + offs_t page_offset = (((offs_t) m_dma_offset[1][m_dma_channel & 3]) << 16) & 0xFE0000; + + result = prog_space.read_word(page_offset + ( offset << 1 ) ); + m_dma_high_byte = result & 0xFF00; + + return result & 0xFF; +} + + +WRITE8_MEMBER(southbridge_device::pc_dma_write_word) +{ + address_space& prog_space = m_maincpu->space(AS_PROGRAM); // get the right address space + if(m_dma_channel == -1) + return; + offs_t page_offset = (((offs_t) m_dma_offset[1][m_dma_channel & 3]) << 16) & 0xFE0000; + + prog_space.write_word(page_offset + ( offset << 1 ), m_dma_high_byte | data); +} + + +READ8_MEMBER( southbridge_device::pc_dma8237_0_dack_r ) { return m_isabus->dack_r(0); } +READ8_MEMBER( southbridge_device::pc_dma8237_1_dack_r ) { return m_isabus->dack_r(1); } +READ8_MEMBER( southbridge_device::pc_dma8237_2_dack_r ) { return m_isabus->dack_r(2); } +READ8_MEMBER( southbridge_device::pc_dma8237_3_dack_r ) { return m_isabus->dack_r(3); } +READ8_MEMBER( southbridge_device::pc_dma8237_5_dack_r ) { return m_isabus->dack_r(5); } +READ8_MEMBER( southbridge_device::pc_dma8237_6_dack_r ) { return m_isabus->dack_r(6); } +READ8_MEMBER( southbridge_device::pc_dma8237_7_dack_r ) { return m_isabus->dack_r(7); } + + +WRITE8_MEMBER( southbridge_device::pc_dma8237_0_dack_w ){ m_isabus->dack_w(0, data); } +WRITE8_MEMBER( southbridge_device::pc_dma8237_1_dack_w ){ m_isabus->dack_w(1, data); } +WRITE8_MEMBER( southbridge_device::pc_dma8237_2_dack_w ){ m_isabus->dack_w(2, data); } +WRITE8_MEMBER( southbridge_device::pc_dma8237_3_dack_w ){ m_isabus->dack_w(3, data); } +WRITE8_MEMBER( southbridge_device::pc_dma8237_5_dack_w ){ m_isabus->dack_w(5, data); } +WRITE8_MEMBER( southbridge_device::pc_dma8237_6_dack_w ){ m_isabus->dack_w(6, data); } +WRITE8_MEMBER( southbridge_device::pc_dma8237_7_dack_w ){ m_isabus->dack_w(7, data); } + +WRITE_LINE_MEMBER( southbridge_device::at_dma8237_out_eop ) +{ + m_cur_eop = state == ASSERT_LINE; + if(m_dma_channel != -1) + m_isabus->eop_w(m_dma_channel, m_cur_eop ? ASSERT_LINE : CLEAR_LINE ); +} + +void southbridge_device::pc_select_dma_channel(int channel, bool state) +{ + if(!state) { + m_dma_channel = channel; + if(m_cur_eop) + m_isabus->eop_w(channel, ASSERT_LINE ); + + } else if(m_dma_channel == channel) { + m_dma_channel = -1; + if(m_cur_eop) + m_isabus->eop_w(channel, CLEAR_LINE ); + } +} + + +WRITE_LINE_MEMBER( southbridge_device::pc_dack0_w ) { pc_select_dma_channel(0, state); } +WRITE_LINE_MEMBER( southbridge_device::pc_dack1_w ) { pc_select_dma_channel(1, state); } +WRITE_LINE_MEMBER( southbridge_device::pc_dack2_w ) { pc_select_dma_channel(2, state); } +WRITE_LINE_MEMBER( southbridge_device::pc_dack3_w ) { pc_select_dma_channel(3, state); } +WRITE_LINE_MEMBER( southbridge_device::pc_dack4_w ) { m_dma8237_1->hack_w( state ? 0 : 1); } // it's inverted +WRITE_LINE_MEMBER( southbridge_device::pc_dack5_w ) { pc_select_dma_channel(5, state); } +WRITE_LINE_MEMBER( southbridge_device::pc_dack6_w ) { pc_select_dma_channel(6, state); } +WRITE_LINE_MEMBER( southbridge_device::pc_dack7_w ) { pc_select_dma_channel(7, state); } + +READ8_MEMBER( southbridge_device::at_portb_r ) +{ + UINT8 data = m_at_speaker; + data &= ~0xd0; /* AT BIOS don't likes this being set */ + + /* 0x10 is the dram refresh line bit on the 5170, just a timer here, 15.085us. */ + data |= m_refresh ? 0x10 : 0; + + if (m_pit_out2) + data |= 0x20; + else + data &= ~0x20; /* ps2m30 wants this */ + + return data; +} + +WRITE8_MEMBER( southbridge_device::at_portb_w ) +{ + m_at_speaker = data; + m_pit8254->write_gate2(BIT(data, 0)); + at_speaker_set_spkrdata( BIT(data, 1)); + m_channel_check = BIT(data, 3); + m_isabus->set_nmi_state((m_nmi_enabled==0) && (m_channel_check==0)); +} + +READ8_MEMBER( southbridge_device::at_dma8237_2_r ) +{ + return m_dma8237_2->read( space, offset / 2); +} + +WRITE8_MEMBER( southbridge_device::at_dma8237_2_w ) +{ + m_dma8237_2->write( space, offset / 2, data); +} + +READ8_MEMBER( southbridge_device::at_keybc_r ) +{ + switch (offset) + { + case 0: return m_keybc->data_r(space, 0); + case 1: return at_portb_r(space, 0); + } + + return 0xff; +} + +WRITE8_MEMBER( southbridge_device::at_keybc_w ) +{ + switch (offset) + { + case 0: m_keybc->data_w(space, 0, data); break; + case 1: at_portb_w(space, 0, data); break; + } +} + + +WRITE8_MEMBER( southbridge_device::write_rtc ) +{ + if (offset==0) { + m_nmi_enabled = BIT(data,7); + m_isabus->set_nmi_state((m_nmi_enabled==0) && (m_channel_check==0)); + m_ds12885->write(space,0,data); + } + else { + m_ds12885->write(space,offset,data); + } +} diff --git a/src/devices/bus/lpci/southbridge.h b/src/devices/bus/lpci/southbridge.h new file mode 100644 index 00000000000..aaf8bc973e3 --- /dev/null +++ b/src/devices/bus/lpci/southbridge.h @@ -0,0 +1,131 @@ +// license:BSD-3-Clause +// copyright-holders:Miodrag Milanovic +#pragma once + +#ifndef __SOUTHBRIDGE_H__ +#define __SOUTHBRIDGE_H__ + +#include "emu.h" + +#include "machine/ins8250.h" +#include "machine/ds128x.h" +#include "machine/pic8259.h" +#include "machine/pit8253.h" + +#include "machine/ataintf.h" +#include "machine/at_keybc.h" + +#include "imagedev/harddriv.h" +#include "pci.h" + +#include "sound/dac.h" +#include "sound/speaker.h" +#include "machine/ram.h" +#include "machine/nvram.h" +#include "bus/isa/isa.h" +#include "bus/isa/isa_cards.h" + +#include "machine/pc_lpt.h" +#include "bus/pc_kbd/pc_kbdc.h" + +#include "machine/am9517a.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> southbridge_device + +class southbridge_device : + public device_t +{ +public: + // construction/destruction + southbridge_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); +public: + + required_device m_maincpu; + required_device m_pic8259_master; + required_device m_pic8259_slave; + required_device m_dma8237_1; + required_device m_dma8237_2; + required_device m_pit8254; + required_device m_keybc; + required_device m_isabus; + required_device m_speaker; + required_device m_ds12885; + required_device m_pc_kbdc; + required_device m_ide; + required_device m_ide2; + DECLARE_READ8_MEMBER(at_page8_r); + DECLARE_WRITE8_MEMBER(at_page8_w); + DECLARE_READ8_MEMBER(at_portb_r); + DECLARE_WRITE8_MEMBER(at_portb_w); + DECLARE_READ8_MEMBER(get_slave_ack); + DECLARE_WRITE_LINE_MEMBER(at_pit8254_out0_changed); + DECLARE_WRITE_LINE_MEMBER(at_pit8254_out1_changed); + DECLARE_WRITE_LINE_MEMBER(at_pit8254_out2_changed); + DECLARE_WRITE_LINE_MEMBER(pc_dma_hrq_changed); + DECLARE_READ8_MEMBER(pc_dma8237_0_dack_r); + DECLARE_READ8_MEMBER(pc_dma8237_1_dack_r); + DECLARE_READ8_MEMBER(pc_dma8237_2_dack_r); + DECLARE_READ8_MEMBER(pc_dma8237_3_dack_r); + DECLARE_READ8_MEMBER(pc_dma8237_5_dack_r); + DECLARE_READ8_MEMBER(pc_dma8237_6_dack_r); + DECLARE_READ8_MEMBER(pc_dma8237_7_dack_r); + DECLARE_WRITE8_MEMBER(pc_dma8237_0_dack_w); + DECLARE_WRITE8_MEMBER(pc_dma8237_1_dack_w); + DECLARE_WRITE8_MEMBER(pc_dma8237_2_dack_w); + DECLARE_WRITE8_MEMBER(pc_dma8237_3_dack_w); + DECLARE_WRITE8_MEMBER(pc_dma8237_5_dack_w); + DECLARE_WRITE8_MEMBER(pc_dma8237_6_dack_w); + DECLARE_WRITE8_MEMBER(pc_dma8237_7_dack_w); + DECLARE_WRITE_LINE_MEMBER(at_dma8237_out_eop); + DECLARE_WRITE_LINE_MEMBER(pc_dack0_w); + DECLARE_WRITE_LINE_MEMBER(pc_dack1_w); + DECLARE_WRITE_LINE_MEMBER(pc_dack2_w); + DECLARE_WRITE_LINE_MEMBER(pc_dack3_w); + DECLARE_WRITE_LINE_MEMBER(pc_dack4_w); + DECLARE_WRITE_LINE_MEMBER(pc_dack5_w); + DECLARE_WRITE_LINE_MEMBER(pc_dack6_w); + DECLARE_WRITE_LINE_MEMBER(pc_dack7_w); + DECLARE_READ8_MEMBER(ide_read_cs1_r); + DECLARE_WRITE8_MEMBER(ide_write_cs1_w); + DECLARE_READ8_MEMBER(ide2_read_cs1_r); + DECLARE_WRITE8_MEMBER(ide2_write_cs1_w); + DECLARE_READ8_MEMBER(at_dma8237_2_r); + DECLARE_WRITE8_MEMBER(at_dma8237_2_w); + DECLARE_READ8_MEMBER(at_keybc_r); + DECLARE_WRITE8_MEMBER(at_keybc_w); + DECLARE_WRITE8_MEMBER(write_rtc); + DECLARE_READ8_MEMBER(pc_dma_read_byte); + DECLARE_WRITE8_MEMBER(pc_dma_write_byte); + DECLARE_READ8_MEMBER(pc_dma_read_word); + DECLARE_WRITE8_MEMBER(pc_dma_write_word); +protected: + UINT8 m_at_spkrdata; + UINT8 m_pit_out2; + int m_dma_channel; + bool m_cur_eop; + UINT8 m_dma_offset[2][4]; + UINT8 m_at_pages[0x10]; + UINT16 m_dma_high_byte; + UINT8 m_at_speaker; + bool m_refresh; + void at_speaker_set_spkrdata(UINT8 data); + + UINT8 m_channel_check; + UINT8 m_nmi_enabled; + + void pc_select_dma_channel(int channel, bool state); +}; + +#endif /* __SOUTHBRIDGE_H__ */ diff --git a/src/devices/bus/macpds/macpds.c b/src/devices/bus/macpds/macpds.c new file mode 100644 index 00000000000..0a2cf2477e9 --- /dev/null +++ b/src/devices/bus/macpds/macpds.c @@ -0,0 +1,198 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/*************************************************************************** + + macpds.c - Mac 68000 PDS implementation (SE, Portable) + + by R. Belmont + +***************************************************************************/ + +#include "emu.h" +#include "emuopts.h" +#include "macpds.h" + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type MACPDS_SLOT = &device_creator; + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// macpds_slot_device - constructor +//------------------------------------------------- +macpds_slot_device::macpds_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, MACPDS_SLOT, "Mac 68000 Processor-Direct Slot", tag, owner, clock, "macpds_slot", __FILE__), + device_slot_interface(mconfig, *this) +{ +} + +macpds_slot_device::macpds_slot_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_slot_interface(mconfig, *this) +{ +} + +void macpds_slot_device::static_set_macpds_slot(device_t &device, const char *tag, const char *slottag) +{ + macpds_slot_device &macpds_card = dynamic_cast(device); + macpds_card.m_macpds_tag = tag; + macpds_card.m_macpds_slottag = slottag; +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void macpds_slot_device::device_start() +{ + device_macpds_card_interface *dev = dynamic_cast(get_card_device()); + + if (dev) device_macpds_card_interface::static_set_macpds_tag(*dev, m_macpds_tag, m_macpds_slottag); +} + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type MACPDS = &device_creator; + +void macpds_device::static_set_cputag(device_t &device, const char *tag) +{ + macpds_device &macpds = downcast(device); + macpds.m_cputag = tag; +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// macpds_device - constructor +//------------------------------------------------- + +macpds_device::macpds_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, MACPDS, "MACPDS", tag, owner, clock, "macpds", __FILE__) +{ +} + +macpds_device::macpds_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source) +{ +} +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void macpds_device::device_start() +{ + m_maincpu = machine().device(m_cputag); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void macpds_device::device_reset() +{ +} + +void macpds_device::add_macpds_card(device_macpds_card_interface *card) +{ + m_device_list.append(*card); +} + +void macpds_device::install_device(offs_t start, offs_t end, read8_delegate rhandler, write8_delegate whandler, UINT32 mask) +{ + m_maincpu = machine().device(m_cputag); + m_maincpu->space(AS_PROGRAM).install_readwrite_handler(start, end, rhandler, whandler, mask); +} + +void macpds_device::install_device(offs_t start, offs_t end, read16_delegate rhandler, write16_delegate whandler, UINT32 mask) +{ + m_maincpu = machine().device(m_cputag); + m_maincpu->space(AS_PROGRAM).install_readwrite_handler(start, end, rhandler, whandler, mask); +} + +void macpds_device::install_bank(offs_t start, offs_t end, offs_t mask, offs_t mirror, const char *tag, UINT8 *data) +{ +// printf("install_bank: %s @ %x->%x mask %x mirror %x\n", tag, start, end, mask, mirror); + m_maincpu = machine().device(m_cputag); + address_space &space = m_maincpu->space(AS_PROGRAM); + space.install_readwrite_bank(start, end, mask, mirror, tag ); + machine().root_device().membank(tag)->set_base(data); +} + +void macpds_device::set_irq_line(int line, int state) +{ + m_maincpu->set_input_line(line, state); +} + +//************************************************************************** +// DEVICE CONFIG MACPDS CARD INTERFACE +//************************************************************************** + + +//************************************************************************** +// DEVICE MACPDS CARD INTERFACE +//************************************************************************** + +//------------------------------------------------- +// device_macpds_card_interface - constructor +//------------------------------------------------- + +device_macpds_card_interface::device_macpds_card_interface(const machine_config &mconfig, device_t &device) + : device_slot_card_interface(mconfig, device), + m_macpds(NULL), + m_macpds_tag(NULL) +{ +} + + +//------------------------------------------------- +// ~device_macpds_card_interface - destructor +//------------------------------------------------- + +device_macpds_card_interface::~device_macpds_card_interface() +{ +} + +void device_macpds_card_interface::static_set_macpds_tag(device_t &device, const char *tag, const char *slottag) +{ + device_macpds_card_interface &macpds_card = dynamic_cast(device); + macpds_card.m_macpds_tag = tag; + macpds_card.m_macpds_slottag = slottag; +} + +void device_macpds_card_interface::set_macpds_device() +{ + m_macpds = dynamic_cast(device().machine().device(m_macpds_tag)); + m_macpds->add_macpds_card(this); +} + +void device_macpds_card_interface::install_bank(offs_t start, offs_t end, offs_t mask, offs_t mirror, const char *tag, UINT8 *data) +{ + char bank[256]; + + // append an underscore and the slot name to the bank so it's guaranteed unique + strcpy(bank, tag); + strcat(bank, "_"); + strcat(bank, m_macpds_slottag); + + m_macpds->install_bank(start, end, mask, mirror, bank, data); +} + +void device_macpds_card_interface::install_rom(device_t *dev, const char *romregion, UINT32 addr) +{ + UINT8 *rom = device().machine().root_device().memregion(dev->subtag(romregion).c_str())->base(); + UINT32 romlen = device().machine().root_device().memregion(dev->subtag(romregion).c_str())->bytes(); + char bankname[128]; + sprintf(bankname, "rom_%x", addr); + + m_macpds->install_bank(addr, addr+romlen-1, 0, 0, bankname, rom); +} diff --git a/src/devices/bus/macpds/macpds.h b/src/devices/bus/macpds/macpds.h new file mode 100644 index 00000000000..90c136e73bb --- /dev/null +++ b/src/devices/bus/macpds/macpds.h @@ -0,0 +1,133 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/*************************************************************************** + + macpds.h - Mac 68000 PDS implementation (SE, Portable) + + by R. Belmont + +***************************************************************************/ + +#pragma once + +#ifndef __MACPDS_H__ +#define __MACPDS_H__ + +#include "emu.h" + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_MACPDS_BUS_ADD(_tag, _cputag) \ + MCFG_DEVICE_ADD(_tag, MACPDS, 0) \ + macpds_device::static_set_cputag(*device, _cputag); + +#define MCFG_MACPDS_SLOT_ADD(_nbtag, _tag, _slot_intf, _def_slot) \ + MCFG_DEVICE_ADD(_tag, MACPDS_SLOT, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) \ + macpds_slot_device::static_set_macpds_slot(*device, _nbtag, _tag); + +#define MCFG_MACPDS_SLOT_REMOVE(_tag) \ + MCFG_DEVICE_REMOVE(_tag) + +#define MCFG_MACPDS_ONBOARD_ADD(_nbtag, _tag, _dev_type, _def_inp) \ + MCFG_DEVICE_ADD(_tag, _dev_type, 0) \ + MCFG_DEVICE_INPUT_DEFAULTS(_def_inp) \ + device_macpds_card_interface::static_set_macpds_tag(*device, _nbtag, _tag); + +#define MCFG_MACPDS_BUS_REMOVE(_tag) \ + MCFG_DEVICE_REMOVE(_tag) + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class macpds_device; + +class macpds_slot_device : public device_t, + public device_slot_interface +{ +public: + // construction/destruction + macpds_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + macpds_slot_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + // device-level overrides + virtual void device_start(); + + // inline configuration + static void static_set_macpds_slot(device_t &device, const char *tag, const char *slottag); +protected: + // configuration + const char *m_macpds_tag, *m_macpds_slottag; +}; + +// device type definition +extern const device_type MACPDS_SLOT; + + +class device_macpds_card_interface; + +// ======================> macpds_device +class macpds_device : public device_t +{ +public: + // construction/destruction + macpds_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + macpds_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + // inline configuration + static void static_set_cputag(device_t &device, const char *tag); + + void add_macpds_card(device_macpds_card_interface *card); + void install_device(offs_t start, offs_t end, read8_delegate rhandler, write8_delegate whandler, UINT32 mask=0xffffffff); + void install_device(offs_t start, offs_t end, read16_delegate rhandler, write16_delegate whandler, UINT32 mask=0xffffffff); + void install_bank(offs_t start, offs_t end, offs_t mask, offs_t mirror, const char *tag, UINT8 *data); + void set_irq_line(int line, int state); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // internal state + cpu_device *m_maincpu; + + simple_list m_device_list; + const char *m_cputag; +}; + + +// device type definition +extern const device_type MACPDS; + +// ======================> device_macpds_card_interface + +// class representing interface-specific live macpds card +class device_macpds_card_interface : public device_slot_card_interface +{ + friend class macpds_device; +public: + // construction/destruction + device_macpds_card_interface(const machine_config &mconfig, device_t &device); + virtual ~device_macpds_card_interface(); + + device_macpds_card_interface *next() const { return m_next; } + + void set_macpds_device(); + + // helper functions for card devices + void install_declaration_rom(device_t *dev, const char *romregion, bool mirror_all_mb = false, bool reverse_rom = false); + void install_bank(offs_t start, offs_t end, offs_t mask, offs_t mirror, const char *tag, UINT8 *data); + void install_rom(device_t *dev, const char *romregion, UINT32 addr); + + // inline configuration + static void static_set_macpds_tag(device_t &device, const char *tag, const char *slottag); +public: + macpds_device *m_macpds; + const char *m_macpds_tag, *m_macpds_slottag; + device_macpds_card_interface *m_next; +}; + +#endif /* __MACPDS_H__ */ diff --git a/src/devices/bus/macpds/pds_tpdfpd.c b/src/devices/bus/macpds/pds_tpdfpd.c new file mode 100644 index 00000000000..a9e7c36c067 --- /dev/null +++ b/src/devices/bus/macpds/pds_tpdfpd.c @@ -0,0 +1,238 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont + +/*************************************************************************** + + Radius Full Page Display card for the Mac SE, assy # 632-0022-A1 + + EPROMs are marked + "(c) 1991 Radius TPD/FPD-ASIC U6 297-0204-A V 4.1 256K" and "U7" with + all other text the same. + + The SE PDS does not auto-configure like NuBus; cards have to snoop the 68k + address bus and claim spots the motherboard logic doesn't want. + + This card claims these address ranges: + 770000-77000F: Bt9014 RAMDAC + C00000-C0FFFF: EPROM + C10000 : read to ack vblank IRQ 2 (returns bit 7 = 0 for vblank active) + C20000 : read to enable vblank IRQ 2 + C40000-C7FFFF: 256k VRAM + F80000-F8FFFF: EPROM mirror (the SE ROM looks for signatures and jump tables in this region) + + TODO: + * suppress SE built-in screen (it stops working after OS boot with this card installed) & make our screen 3:4 + * investigate if there's also a two-page display mode as the rom labels imply; 256K is + far too much for just 1024x880 but would fit double that nicely. + * later ROM versions provide System 7 compatibility; our current dump is good only + up to 6.0.8. (We have 4.1; the last version is 4.4). + +***************************************************************************/ + +#include "emu.h" +#include "pds_tpdfpd.h" +#include "cpu/m68000/m68000.h" + +#define SEDISPLAY_SCREEN_NAME "fpd_screen" +#define SEDISPLAY_ROM_REGION "fpd_rom" + +#define VRAM_SIZE (256*1024) // PCB has a jumper for 1MByte; may require different EPROMs + +MACHINE_CONFIG_FRAGMENT( sedisplay ) + MCFG_SCREEN_ADD( SEDISPLAY_SCREEN_NAME, RASTER) + MCFG_SCREEN_UPDATE_DEVICE(DEVICE_SELF, macpds_sedisplay_device, screen_update) + MCFG_SCREEN_SIZE(1280, 960) + MCFG_SCREEN_REFRESH_RATE(70) + MCFG_SCREEN_VISIBLE_AREA(0, 640-1, 0, 870-1) +MACHINE_CONFIG_END + +ROM_START( sedisplay ) + ROM_REGION(0x10000, SEDISPLAY_ROM_REGION, ROMREGION_16BIT|ROMREGION_BE) + ROM_LOAD16_BYTE( "tfd_fpd-asic_u6_297-0205-a_v4_1", 0x0000, 0x8000, CRC(fd363f45) SHA1(3c4c596654647ee6ce1880de329aa675d298dc26) ) + ROM_LOAD16_BYTE( "tfd_fpd-asic_u7_297-0205-a_v4_1", 0x0001, 0x8000, CRC(5872451a) SHA1(4673d9f341766c49ff1264b7819916e28a20518f) ) +ROM_END + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type PDS_SEDISPLAY = &device_creator; + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor macpds_sedisplay_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( sedisplay ); +} + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *macpds_sedisplay_device::device_rom_region() const +{ + return ROM_NAME( sedisplay ); +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// macpds_sedisplay_device - constructor +//------------------------------------------------- + +macpds_sedisplay_device::macpds_sedisplay_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, PDS_SEDISPLAY, "Radius SE Full Page Display", tag, owner, clock, "pds_sefp", __FILE__), + device_video_interface(mconfig, *this), + device_macpds_card_interface(mconfig, *this) +{ + m_assembled_tag = std::string(tag).append(":").append(SEDISPLAY_SCREEN_NAME); + m_screen_tag = m_assembled_tag.c_str(); +} + +macpds_sedisplay_device::macpds_sedisplay_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_video_interface(mconfig, *this), + device_macpds_card_interface(mconfig, *this) +{ + m_assembled_tag = std::string(tag).append(":").append(SEDISPLAY_SCREEN_NAME); + m_screen_tag = m_assembled_tag.c_str(); +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void macpds_sedisplay_device::device_start() +{ + set_macpds_device(); + + install_rom(this, SEDISPLAY_ROM_REGION, 0xc00000); + install_rom(this, SEDISPLAY_ROM_REGION, 0xf80000); + + m_vram = auto_alloc_array(machine(), UINT8, VRAM_SIZE); + + static const char bankname[] = { "radpds_ram" }; + m_macpds->install_bank(0xc40000, 0xc40000+VRAM_SIZE-1, 0, 0, bankname, m_vram); + + m_macpds->install_device(0x770000, 0x77000f, read16_delegate(FUNC(macpds_sedisplay_device::ramdac_r), this), write16_delegate(FUNC(macpds_sedisplay_device::ramdac_w), this)); + m_macpds->install_device(0xc10000, 0xc2ffff, read16_delegate(FUNC(macpds_sedisplay_device::sedisplay_r), this), write16_delegate(FUNC(macpds_sedisplay_device::sedisplay_w), this)); + + m_timer = timer_alloc(0, NULL); + m_timer->adjust(m_screen->time_until_pos(879, 0), 0); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void macpds_sedisplay_device::device_reset() +{ + m_count = 0; + m_clutoffs = 0; + m_vbl_disable = 1; + memset(m_vram, 0, VRAM_SIZE); + memset(m_palette, 0, sizeof(m_palette)); + + m_palette[0] = rgb_t(0, 0, 0); + m_palette[1] = rgb_t(255, 255, 255); +} + + +void macpds_sedisplay_device::device_timer(emu_timer &timer, device_timer_id tid, int param, void *ptr) +{ + if (!m_vbl_disable) + { + m_macpds->set_irq_line(M68K_IRQ_2, ASSERT_LINE); + } + + m_timer->adjust(m_screen->time_until_pos(879, 0), 0); +} + +/*************************************************************************** + + CB264 section + +***************************************************************************/ + +UINT32 macpds_sedisplay_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + UINT32 *scanline; + int x, y; + UINT8 pixels, *vram; + + vram = m_vram; + + for (y = 0; y < 870; y++) + { + scanline = &bitmap.pix32(y); + for (x = 0; x < 640/8; x++) + { + pixels = vram[(y * (1024/8)) + (x^1)]; + + *scanline++ = m_palette[((pixels>>7)&0x1)^1]; + *scanline++ = m_palette[((pixels>>6)&0x1)^1]; + *scanline++ = m_palette[((pixels>>5)&0x1)^1]; + *scanline++ = m_palette[((pixels>>4)&0x1)^1]; + *scanline++ = m_palette[((pixels>>3)&0x1)^1]; + *scanline++ = m_palette[((pixels>>2)&0x1)^1]; + *scanline++ = m_palette[((pixels>>1)&0x1)^1]; + *scanline++ = m_palette[(pixels&1)^1]; + } + } + + return 0; +} + +WRITE16_MEMBER( macpds_sedisplay_device::sedisplay_w ) +{ +} + +READ16_MEMBER( macpds_sedisplay_device::sedisplay_r ) +{ + if (offset == 0) // ack vbl + { + m_macpds->set_irq_line(M68K_IRQ_2, CLEAR_LINE); + } + else if (offset == 0x8000) // enable vbl + { + m_vbl_disable = 0; + } + + return 0; +} + +WRITE16_MEMBER( macpds_sedisplay_device::ramdac_w ) +{ + switch (offset) + { + case 4: + m_clutoffs = data>>8; + break; + + case 5: + m_colors[m_count++] = data>>4; // they only fill in the lower nibble + + if (m_count == 3) + { // only the green channel drives the output + m_palette[m_clutoffs] = rgb_t(m_colors[1], m_colors[1], m_colors[1]); + m_clutoffs++; + m_count = 0; + } + break; + + default: +// printf("RAMDAC: %x to %x (mask %04x)\n", data, offset, mem_mask); + break; + } +} + +READ16_MEMBER( macpds_sedisplay_device::ramdac_r ) +{ + return 0; +} diff --git a/src/devices/bus/macpds/pds_tpdfpd.h b/src/devices/bus/macpds/pds_tpdfpd.h new file mode 100644 index 00000000000..126af9887a1 --- /dev/null +++ b/src/devices/bus/macpds/pds_tpdfpd.h @@ -0,0 +1,55 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +#pragma once + +#ifndef __PDS_SEDISPLAY_H__ +#define __PDS_SEDISPLAY_H__ + +#include "emu.h" +#include "macpds.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> macpds_sedisplay_device + +class macpds_sedisplay_device : + public device_t, + public device_video_interface, + public device_macpds_card_interface +{ +public: + // construction/destruction + macpds_sedisplay_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + macpds_sedisplay_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual const rom_entry *device_rom_region() const; + + UINT32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + DECLARE_READ16_MEMBER(sedisplay_r); + DECLARE_WRITE16_MEMBER(sedisplay_w); + DECLARE_READ16_MEMBER(ramdac_r); + DECLARE_WRITE16_MEMBER(ramdac_w); + +public: + UINT8 *m_vram; + UINT32 m_vbl_disable; + UINT32 m_palette[256], m_colors[3], m_count, m_clutoffs; + emu_timer *m_timer; + std::string m_assembled_tag; +}; + + +// device type definition +extern const device_type PDS_SEDISPLAY; + +#endif /* __MACPDS_SEDISPLAY_H__ */ diff --git a/src/devices/bus/megadrive/eeprom.c b/src/devices/bus/megadrive/eeprom.c new file mode 100644 index 00000000000..e0a72f3a939 --- /dev/null +++ b/src/devices/bus/megadrive/eeprom.c @@ -0,0 +1,376 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + MegaDrive / Genesis cart+EEPROM emulation + + + TODO: proper EEPROM emulation, still not worked on (just hooked up the I2C device) + + + i2c games mapping table: + + game name | SDA_IN | SDA_OUT | SCL | SIZE_MASK | PAGE_MASK | + ----------------------------------|------------|------------|------------|----------------|-----------| + NBA Jam | 0x200001-0 | 0x200001-0 | 0x200001-1 | 0x00ff (24C02) | 0x03 | xx + NBA Jam TE | 0x200001-0 | 0x200001-0 | 0x200000-0 | 0x00ff (24C02) | 0x03 | xx + NBA Jam TE (32x) | 0x200001-0 | 0x200001-0 | 0x200000-0 | 0x00ff (24C02) | 0x03 | + NFL Quarterback Club | 0x200001-0 | 0x200001-0 | 0x200000-0 | 0x00ff (24C02) | 0x03 | xx + NFL Quarterback Club 96 | 0x200001-0 | 0x200001-0 | 0x200000-0 | 0x07ff (24C16) | 0x07 | xx + College Slam | 0x200001-0 | 0x200001-0 | 0x200000-0 | 0x1fff (24C64) | 0x07 | xx + Frank Thomas Big Hurt Baseball | 0x200001-0 | 0x200001-0 | 0x200000-0 | 0x1fff (24C64) | 0x07 | xx + NHLPA Hockey 93 | 0x200001-7 | 0x200001-7 | 0x200001-6 | 0x007f (24C01) | 0x03 | xx + Rings of Power | 0x200001-7 | 0x200001-7 | 0x200001-6 | 0x007f (24C01) | 0x03 | xx + Evander Holyfield's Boxing | 0x200001-0 | 0x200001-0 | 0x200001-1 | 0x007f (24C01) | 0x03 | xx + Greatest Heavyweights of the Ring | 0x200001-0 | 0x200001-0 | 0x200001-1 | 0x007f (24C01) | 0x03 | xx + Wonder Boy V | 0x200001-0 | 0x200001-0 | 0x200001-1 | 0x007f (24C01) | 0x03 | xx + Sports Talk Baseball | 0x200001-0 | 0x200001-0 | 0x200001-1 | 0x007f (24C01) | 0x03 | xx + Megaman - the Wily Wars | 0x200001-0 | 0x200001-0 | 0x200001-1 | 0x007f (24C01) | 0x03 | xx ** + Micro Machines 2 | 0x380001-7 | 0x300000-0*| 0x300000-1*| 0x03ff (24C08) | 0x0f | + Micro Machines Military | 0x380001-7 | 0x300000-0*| 0x300000-1*| 0x03ff (24C08) | 0x0f | + Micro Machines 96 | 0x380001-7 | 0x300000-0*| 0x300000-1*| 0x07ff (24C16) | 0x0f | + Brian Lara Cricket 96 | 0x380001-7 | 0x300000-0*| 0x300000-1*| 0x1fff (24C64) | 0x??* | + ----------------------------------|------------|------------|------------|----------------|-----------| + + * Notes: check these + ** original Rockman Mega World (J) set uses normal backup RAM + + + Micro Machines 2, Micro Machines Military, Micro Machines 96 are emulated in md_jcart + +***********************************************************************************************************/ + + + +#include "emu.h" +#include "eeprom.h" + + +//------------------------------------------------- +// md_rom_device - constructor +//------------------------------------------------- + +const device_type MD_STD_EEPROM = &device_creator; +const device_type MD_EEPROM_NBAJAM = &device_creator; +const device_type MD_EEPROM_NBAJAMTE = &device_creator; +const device_type MD_EEPROM_NFLQB = &device_creator; +const device_type MD_EEPROM_CSLAM = &device_creator; +const device_type MD_EEPROM_NHLPA = &device_creator; +const device_type MD_EEPROM_BLARA = &device_creator; + + +md_std_eeprom_device::md_std_eeprom_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_md_cart_interface( mconfig, *this ), + m_i2cmem(*this, "i2cmem") +{ +} + +md_std_eeprom_device::md_std_eeprom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, MD_STD_EEPROM, "MD Standard cart + EEPROM", tag, owner, clock, "md_std_eeprom", __FILE__), + device_md_cart_interface( mconfig, *this ), + m_i2cmem(*this, "i2cmem") +{ +} + +md_eeprom_nbajam_device::md_eeprom_nbajam_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : md_std_eeprom_device(mconfig, MD_EEPROM_NBAJAM, "MD NBA Jam", tag, owner, clock, "md_eeprom_nbajam", __FILE__) +{ +} + +md_eeprom_nbajamte_device::md_eeprom_nbajamte_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : md_std_eeprom_device(mconfig, MD_EEPROM_NBAJAMTE, "MD NBA Jam TE (and a few more)", tag, owner, clock, "md_eeprom_nbajamte", __FILE__) +{ +} + +md_eeprom_cslam_device::md_eeprom_cslam_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : md_std_eeprom_device(mconfig, MD_EEPROM_CSLAM, "MD College Slam", tag, owner, clock, "md_eeprom_cslam", __FILE__) +{ +} + +md_eeprom_nflqb_device::md_eeprom_nflqb_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : md_std_eeprom_device(mconfig, MD_EEPROM_NFLQB, "MD NFL Quarterback 96", tag, owner, clock, "md_eeprom_nflqb", __FILE__) +{ +} + +md_eeprom_nhlpa_device::md_eeprom_nhlpa_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : md_std_eeprom_device(mconfig, MD_EEPROM_NHLPA, "MD NHLPA 93", tag, owner, clock, "md_eeprom_nhlpa", __FILE__) +{ +} + +md_eeprom_blara_device::md_eeprom_blara_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : md_std_eeprom_device(mconfig, MD_EEPROM_BLARA, "MD Brian Lara", tag, owner, clock, "md_eeprom_blara", __FILE__) +{ +} + + +//------------------------------------------------- +// SERIAL I2C DEVICE +//------------------------------------------------- + + +// MD_STD_EEPROM & MD_EEPROM_NHLPA +MACHINE_CONFIG_FRAGMENT( md_i2c_24c01 ) + MCFG_24C01_ADD("i2cmem") +MACHINE_CONFIG_END + +// MD_EEPROM_NBAJAM & MD_EEPROM_NBAJAMTE +MACHINE_CONFIG_FRAGMENT( md_i2c_24c02 ) + MCFG_24C02_ADD("i2cmem") +MACHINE_CONFIG_END + +// MD_EEPROM_NFLQB +MACHINE_CONFIG_FRAGMENT( md_i2c_24c16 ) + MCFG_24C16_ADD("i2cmem") +MACHINE_CONFIG_END + +// MD_EEPROM_CSLAM & MD_EEPROM_BLARA +MACHINE_CONFIG_FRAGMENT( md_i2c_24c64 ) + MCFG_24C64_ADD("i2cmem") +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor md_std_eeprom_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( md_i2c_24c01 ); +} + +machine_config_constructor md_eeprom_nbajam_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( md_i2c_24c02 ); +} + +machine_config_constructor md_eeprom_nbajamte_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( md_i2c_24c02 ); +} + +machine_config_constructor md_eeprom_cslam_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( md_i2c_24c64 ); +} + +machine_config_constructor md_eeprom_nflqb_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( md_i2c_24c16 ); +} + +machine_config_constructor md_eeprom_nhlpa_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( md_i2c_24c01 ); +} + +machine_config_constructor md_eeprom_blara_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( md_i2c_24c64 ); +} + + +void md_std_eeprom_device::device_start() +{ + save_item(NAME(m_i2c_mem)); + save_item(NAME(m_i2c_clk)); +} + +void md_std_eeprom_device::device_reset() +{ + m_i2c_mem = 0; + m_i2c_clk = 0; +} + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +/*------------------------------------------------- + CART + EEPROM + -------------------------------------------------*/ + +READ16_MEMBER(md_std_eeprom_device::read) +{ + if (offset == 0x200000/2) + { + return m_i2cmem->read_sda(); + } + if (offset < 0x400000/2) + return m_rom[MD_ADDR(offset)]; + else + return 0xffff; +} + +WRITE16_MEMBER(md_std_eeprom_device::write) +{ + if (offset == 0x200000/2) + { + m_i2c_clk = BIT(data, 1); + m_i2c_mem = BIT(data, 0); + m_i2cmem->write_scl(m_i2c_clk); + m_i2cmem->write_sda(m_i2c_mem); + } +} + +READ16_MEMBER(md_eeprom_nbajam_device::read) +{ + if (offset == 0x200000/2) + { +// m_i2c_mem = m_i2cmem->read_sda(); + return m_i2cmem->read_sda(); + } + if (offset < 0x400000/2) + return m_rom[MD_ADDR(offset)]; + else + return 0xffff; +} + +WRITE16_MEMBER(md_eeprom_nbajam_device::write) +{ + if (offset == 0x200000/2) + { + m_i2c_clk = BIT(data, 1); + m_i2c_mem = BIT(data, 0); + m_i2cmem->write_scl(m_i2c_clk); + m_i2cmem->write_sda(m_i2c_mem); + } +} + +READ16_MEMBER(md_eeprom_nbajamte_device::read) +{ + if (offset == 0x200000/2) + { +// m_i2c_mem = m_i2cmem->read_sda(); + return m_i2cmem->read_sda(); + } + if (offset < 0x400000/2) + return m_rom[MD_ADDR(offset)]; + else + return 0xffff; +} + +WRITE16_MEMBER(md_eeprom_nbajamte_device::write) +{ + if (offset == 0x200000/2) + { + if(ACCESSING_BITS_8_15) + { + m_i2c_clk = BIT(data, 8); + m_i2cmem->write_scl(m_i2c_clk); + } + + if(ACCESSING_BITS_0_7) + { + m_i2c_mem = BIT(data, 0); + m_i2cmem->write_sda(m_i2c_mem); + } + } +} + +// same as NBAJAMTE above... derived class? +READ16_MEMBER(md_eeprom_cslam_device::read) +{ + if (offset == 0x200000/2) + { +// m_i2c_mem = m_i2cmem->read_sda(); + return m_i2cmem->read_sda(); + } + if (offset < 0x400000/2) + return m_rom[MD_ADDR(offset)]; + else + return 0xffff; +} + +WRITE16_MEMBER(md_eeprom_cslam_device::write) +{ + if (offset == 0x200000/2) + { + if(ACCESSING_BITS_8_15) + { + m_i2c_clk = BIT(data, 8); + m_i2cmem->write_scl(m_i2c_clk); + } + + if(ACCESSING_BITS_0_7) + { + m_i2c_mem = BIT(data, 0); + m_i2cmem->write_sda(m_i2c_mem); + } + } +} + +// same as NBAJAMTE above... derived class? +READ16_MEMBER(md_eeprom_nflqb_device::read) +{ + if (offset == 0x200000/2) + { +// m_i2c_mem = i2cmem_sda_read(m_i2cmem); + return m_i2cmem->read_sda(); + } + if (offset < 0x400000/2) + return m_rom[MD_ADDR(offset)]; + else + return 0xffff; +} + +WRITE16_MEMBER(md_eeprom_nflqb_device::write) +{ + if (offset == 0x200000/2) + { + m_i2c_clk = BIT(data, 8); + m_i2c_mem = BIT(data, 0); + m_i2cmem->write_scl(m_i2c_clk); + m_i2cmem->write_sda(m_i2c_mem); + } +} + +READ16_MEMBER(md_eeprom_nhlpa_device::read) +{ + if (offset == 0x200000/2) + { +// m_i2c_mem = m_i2cmem->read_sda(); + return (m_i2cmem->read_sda() & 1) << 7; + } + if (offset < 0x400000/2) + return m_rom[MD_ADDR(offset)]; + else + return 0xffff; +} + +WRITE16_MEMBER(md_eeprom_nhlpa_device::write) +{ + if (offset == 0x200000/2) + { + m_i2c_clk = BIT(data, 6); + m_i2c_mem = BIT(data, 7); + m_i2cmem->write_scl(m_i2c_clk); + m_i2cmem->write_sda(m_i2c_mem); + } +} + +READ16_MEMBER(md_eeprom_blara_device::read) +{ + if (offset == 0x380000/2) + { +// m_i2c_mem = m_i2cmem->read_sda(); + return (m_i2cmem->read_sda() & 1) << 7; + } + if (offset < 0x400000/2) + return m_rom[MD_ADDR(offset)]; + else + return 0xffff; +} + +WRITE16_MEMBER(md_eeprom_blara_device::write) +{ + if (offset == 0x380000/2) + { + m_i2c_clk = BIT(data, 9); + m_i2c_mem = BIT(data, 8); + m_i2cmem->write_scl(m_i2c_clk); + m_i2cmem->write_sda(m_i2c_mem); + } +} diff --git a/src/devices/bus/megadrive/eeprom.h b/src/devices/bus/megadrive/eeprom.h new file mode 100644 index 00000000000..a7916e628bf --- /dev/null +++ b/src/devices/bus/megadrive/eeprom.h @@ -0,0 +1,143 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __MD_EEPROM_H +#define __MD_EEPROM_H + +#include "md_slot.h" +#include "machine/i2cmem.h" + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> md_std_eeprom_device + +class md_std_eeprom_device : public device_t, + public device_md_cart_interface +{ +public: + // construction/destruction + md_std_eeprom_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + md_std_eeprom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual machine_config_constructor device_mconfig_additions() const; + + // reading and writing + virtual DECLARE_READ16_MEMBER(read); + virtual DECLARE_WRITE16_MEMBER(write); + + required_device m_i2cmem; + UINT8 m_i2c_mem, m_i2c_clk; +}; + +// ======================> md_eeprom_nbajam_device + +class md_eeprom_nbajam_device : public md_std_eeprom_device +{ +public: + // construction/destruction + md_eeprom_nbajam_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual machine_config_constructor device_mconfig_additions() const; + + // reading and writing + virtual DECLARE_READ16_MEMBER(read); + virtual DECLARE_WRITE16_MEMBER(write); +}; + +// ======================> md_eeprom_nbajamte_device + +class md_eeprom_nbajamte_device : public md_std_eeprom_device +{ +public: + // construction/destruction + md_eeprom_nbajamte_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual machine_config_constructor device_mconfig_additions() const; + + // reading and writing + virtual DECLARE_READ16_MEMBER(read); + virtual DECLARE_WRITE16_MEMBER(write); +}; + +// ======================> md_eeprom_cslam_device (same read/write as nbajamte, but different I2C type) + +class md_eeprom_cslam_device : public md_std_eeprom_device +{ +public: + // construction/destruction + md_eeprom_cslam_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual machine_config_constructor device_mconfig_additions() const; + + // reading and writing + virtual DECLARE_READ16_MEMBER(read); + virtual DECLARE_WRITE16_MEMBER(write); +}; + +// ======================> md_eeprom_nflqb_device (same read/write as nbajamte, but different I2C type) + +class md_eeprom_nflqb_device : public md_std_eeprom_device +{ +public: + // construction/destruction + md_eeprom_nflqb_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual machine_config_constructor device_mconfig_additions() const; + + // reading and writing + virtual DECLARE_READ16_MEMBER(read); + virtual DECLARE_WRITE16_MEMBER(write); +}; + +// ======================> md_eeprom_nhlpa_device + +class md_eeprom_nhlpa_device : public md_std_eeprom_device +{ +public: + // construction/destruction + md_eeprom_nhlpa_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual machine_config_constructor device_mconfig_additions() const; + + // reading and writing + virtual DECLARE_READ16_MEMBER(read); + virtual DECLARE_WRITE16_MEMBER(write); +}; + +// ======================> md_eeprom_blara_device (same read/write as codemast, but different I2C type) + +class md_eeprom_blara_device : public md_std_eeprom_device +{ +public: + // construction/destruction + md_eeprom_blara_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual machine_config_constructor device_mconfig_additions() const; + + // reading and writing + virtual DECLARE_READ16_MEMBER(read); + virtual DECLARE_WRITE16_MEMBER(write); +}; + + +// device type definition +extern const device_type MD_STD_EEPROM; +extern const device_type MD_EEPROM_NBAJAM; +extern const device_type MD_EEPROM_NBAJAMTE; +extern const device_type MD_EEPROM_CSLAM; +extern const device_type MD_EEPROM_NFLQB; +extern const device_type MD_EEPROM_NHLPA; +extern const device_type MD_EEPROM_BLARA; + +#endif diff --git a/src/devices/bus/megadrive/ggenie.c b/src/devices/bus/megadrive/ggenie.c new file mode 100644 index 00000000000..1c75febc54b --- /dev/null +++ b/src/devices/bus/megadrive/ggenie.c @@ -0,0 +1,185 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + Game Genie pass-thorugh cart emulation + + + based on Charles MacDonald's docs: http://cgfm2.emuviews.com/txt/genie.txt + + + There is an interesting difference between Rev.0 and Rev.A + After the codes has been entered, the former just performs + a last write to the MODE register (m_gg_regs[0]) which both + sets the enable bits for the 6 available cheats (in the low + 8 bits) and locks the GG so that later reads goes to the + piggyback cart. The latter revision, instead, performs the + same operations in two subsequent 8bit writes, accessing + separately the low and high bits of the register. + + ***********************************************************************************************************/ + +#include "emu.h" +#include "ggenie.h" +#include "rom.h" + + +//------------------------------------------------- +// md_rom_device - constructor +//------------------------------------------------- + +const device_type MD_ROM_GAMEGENIE = &device_creator; + + +md_rom_ggenie_device::md_rom_ggenie_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, MD_ROM_GAMEGENIE, "MD Game Genie", tag, owner, clock, "md_ggenie", __FILE__), + device_md_cart_interface( mconfig, *this ), + m_exp(*this, "subslot") +{ +} + + +void md_rom_ggenie_device::device_start() +{ + save_item(NAME(m_gg_bypass)); + save_item(NAME(m_reg_enable)); + save_item(NAME(m_gg_regs)); + save_item(NAME(m_gg_addr)); + save_item(NAME(m_gg_data)); +} + +void md_rom_ggenie_device::device_reset() +{ + m_gg_bypass = 0; + m_reg_enable = 0; + memset(m_gg_regs, 0, sizeof(m_gg_regs)); + memset(m_gg_addr, 0, sizeof(m_gg_addr)); + memset(m_gg_data, 0, sizeof(m_gg_data)); +} + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +READ16_MEMBER(md_rom_ggenie_device::read) +{ + if (!m_gg_bypass || !m_exp->m_cart) + { + if (m_reg_enable) + return m_gg_regs[offset & 0x1f]; + else + return m_rom[MD_ADDR(offset)]; + } + + if (m_exp->m_cart) + { + if (offset == m_gg_addr[0]/2 && BIT(m_gg_regs[0], 0)) + return m_gg_data[0]; + else if (offset == m_gg_addr[1]/2 && BIT(m_gg_regs[0], 1)) + return m_gg_data[1]; + else if (offset == m_gg_addr[2]/2 && BIT(m_gg_regs[0], 2)) + return m_gg_data[2]; + else if (offset == m_gg_addr[3]/2 && BIT(m_gg_regs[0], 3)) + return m_gg_data[3]; + else if (offset == m_gg_addr[4]/2 && BIT(m_gg_regs[0], 4)) + return m_gg_data[4]; + else if (offset == m_gg_addr[5]/2 && BIT(m_gg_regs[0], 5)) + return m_gg_data[5]; + else + return m_exp->m_cart->read(space, offset); + } + else + return 0xffff; +} + +WRITE16_MEMBER(md_rom_ggenie_device::write) +{ + if (offset >= 0x40/2) + return; + + if (ACCESSING_BITS_0_7) + m_gg_regs[offset] = (m_gg_regs[offset] & 0xff00) | (data & 0x00ff); + + if (ACCESSING_BITS_8_15) + m_gg_regs[offset] = (m_gg_regs[offset] & 0x00ff) | (data & 0xff00); + + //printf("write to 0x%X, data 0x%X\n", offset, data); + + // MODE + if (offset == 0) + { + // bit10 set = read goes to piggyback cart + if (data & 0x400) + m_gg_bypass = 1; + // bit10 unset = read goes to Game Genie ASIC/ROM + else + { + m_gg_bypass = 0; + + // bit9 set = read goes to ASIC registers + if (data & 0x200) + m_reg_enable = 1; + // bit9 unset = read goes to GG ROM + else + m_reg_enable = 0; + } + + // LOCK bit + if (data & 0x100) + { + // addresses + m_gg_addr[0] = ((m_gg_regs[2] & 0x3f) << 16) | m_gg_regs[3]; + m_gg_addr[1] = ((m_gg_regs[5] & 0x3f) << 16) | m_gg_regs[6]; + m_gg_addr[2] = ((m_gg_regs[8] & 0x3f) << 16) | m_gg_regs[9]; + m_gg_addr[3] = ((m_gg_regs[11] & 0x3f) << 16) | m_gg_regs[12]; + m_gg_addr[4] = ((m_gg_regs[14] & 0x3f) << 16) | m_gg_regs[15]; + m_gg_addr[5] = ((m_gg_regs[17] & 0x3f) << 16) | m_gg_regs[18]; + + // data + m_gg_data[0] = m_gg_regs[4]; + m_gg_data[1] = m_gg_regs[7]; + m_gg_data[2] = m_gg_regs[10]; + m_gg_data[3] = m_gg_regs[13]; + m_gg_data[4] = m_gg_regs[16]; + m_gg_data[5] = m_gg_regs[19]; + + //printf("mode %X\n", data); + //for (int i = 0; i < 6; i++) + // printf("addr %d = 0x%X - data 0x%X\n", i, m_gg_addr[i], m_gg_data[i]); + } + } + else if (offset == 1) + { + // RESET + m_gg_regs[1] |= 1; + } +} + +//------------------------------------------------- +// MACHINE_CONFIG_FRAGMENT( ggenie_slot ) +//------------------------------------------------- + +static SLOT_INTERFACE_START(ggenie_sub_cart) + SLOT_INTERFACE_INTERNAL("rom", MD_STD_ROM) + SLOT_INTERFACE_INTERNAL("rom_svp", MD_STD_ROM) + SLOT_INTERFACE_INTERNAL("rom_sram", MD_ROM_SRAM) + SLOT_INTERFACE_INTERNAL("rom_sramsafe", MD_ROM_SRAM) + SLOT_INTERFACE_INTERNAL("rom_fram", MD_ROM_FRAM) +SLOT_INTERFACE_END + +static MACHINE_CONFIG_FRAGMENT( ggenie_slot ) + MCFG_MD_CARTRIDGE_ADD("subslot", ggenie_sub_cart, NULL) + MCFG_MD_CARTRIDGE_NOT_MANDATORY +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor md_rom_ggenie_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( ggenie_slot ); +} diff --git a/src/devices/bus/megadrive/ggenie.h b/src/devices/bus/megadrive/ggenie.h new file mode 100644 index 00000000000..010ace73441 --- /dev/null +++ b/src/devices/bus/megadrive/ggenie.h @@ -0,0 +1,40 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __MD_GGENIE_H +#define __MD_GGENIE_H + +#include "md_slot.h" + + +// ======================> md_rom_ggenie_device + +class md_rom_ggenie_device : public device_t, + public device_md_cart_interface +{ +public: + // construction/destruction + md_rom_ggenie_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual machine_config_constructor device_mconfig_additions() const; + + // reading and writing + virtual DECLARE_READ16_MEMBER(read); + virtual DECLARE_WRITE16_MEMBER(write); + +private: + required_device m_exp; + UINT16 m_gg_regs[0x20]; + int m_gg_bypass; + int m_reg_enable; + UINT16 m_gg_addr[6]; + UINT16 m_gg_data[6]; +}; + + +// device type definition +extern const device_type MD_ROM_GAMEGENIE; + +#endif diff --git a/src/devices/bus/megadrive/jcart.c b/src/devices/bus/megadrive/jcart.c new file mode 100644 index 00000000000..6e45c2481f6 --- /dev/null +++ b/src/devices/bus/megadrive/jcart.c @@ -0,0 +1,257 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + MegaDrive / Genesis J-Cart (+SEPROM) emulation + + + Emulation based on earlier researches by ElBarto + + + i2c games mapping table: + + game name | SDA_IN | SDA_OUT | SCL | SIZE_MASK | PAGE_MASK | + ----------------------------------|------------|------------|------------|----------------|-----------| + Micro Machines 2 | 0x380001-7 | 0x300000-0*| 0x300000-1*| 0x03ff (24C08) | 0x0f | + Micro Machines Military | 0x380001-7 | 0x300000-0*| 0x300000-1*| 0x03ff (24C08) | 0x0f | + Micro Machines 96 | 0x380001-7 | 0x300000-0*| 0x300000-1*| 0x07ff (24C16) | 0x0f | + ----------------------------------|------------|------------|------------|----------------|-----------| + + * Notes: check these + + + TODO: proper SEPROM emulation, still not worked on (just hooked up the I2C device) + +***********************************************************************************************************/ + + + +#include "emu.h" +#include "jcart.h" + + +//------------------------------------------------- +// md_rom_device - constructor +//------------------------------------------------- + +const device_type MD_JCART = &device_creator; +const device_type MD_SEPROM_CODEMAST = &device_creator; +const device_type MD_SEPROM_MM96 = &device_creator; + +// Sampras, Super Skidmarks? +md_jcart_device::md_jcart_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_md_cart_interface( mconfig, *this ), + m_jcart3(*this, "JCART3"), + m_jcart4(*this, "JCART4") +{ +} + +md_jcart_device::md_jcart_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, MD_JCART, "MD J-Cart games", tag, owner, clock, "md_jcart", __FILE__), + device_md_cart_interface( mconfig, *this ), + m_jcart3(*this, "JCART3"), + m_jcart4(*this, "JCART4") +{ +} + +// Micro Machines 2, Micro Machines Military +md_seprom_codemast_device::md_seprom_codemast_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : md_jcart_device(mconfig, type, name, tag, owner, clock, shortname, source), + m_i2cmem(*this, "i2cmem") +{ +} + +md_seprom_codemast_device::md_seprom_codemast_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : md_jcart_device(mconfig, MD_SEPROM_CODEMAST, "MD J-Cart games + SEPROM", tag, owner, clock, "md_seprom_codemast", __FILE__), + m_i2cmem(*this, "i2cmem") +{ +} + +// Micro Machines 96 +md_seprom_mm96_device::md_seprom_mm96_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : md_seprom_codemast_device(mconfig, MD_SEPROM_MM96, "MD Micro Machine 96", tag, owner, clock, "md_seprom_mm96", __FILE__) +{ +} + + +//------------------------------------------------- +// SERIAL I2C DEVICE +//------------------------------------------------- + +// MD_SEPROM_CODEMAST +MACHINE_CONFIG_FRAGMENT( md_i2c_24c08 ) + MCFG_24C08_ADD("i2cmem") +MACHINE_CONFIG_END + +// MD_SEPROM_MM96 +MACHINE_CONFIG_FRAGMENT( md_i2c_24c16a ) + MCFG_24C16A_ADD("i2cmem") +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor md_seprom_codemast_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( md_i2c_24c08 ); +} + +machine_config_constructor md_seprom_mm96_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( md_i2c_24c16a ); +} + + +static INPUT_PORTS_START( jcart_ipt ) + + PORT_START("JCART3") /* Joypad 3 on J-Cart (3 button + start) */ + PORT_BIT( 0x0001, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_8WAY PORT_PLAYER(3) + PORT_BIT( 0x0002, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_8WAY PORT_PLAYER(3) + PORT_BIT( 0x0004, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_8WAY PORT_PLAYER(3) + PORT_BIT( 0x0008, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_8WAY PORT_PLAYER(3) + PORT_BIT( 0x0010, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(3) PORT_NAME("P3 B") + PORT_BIT( 0x0020, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_PLAYER(3) PORT_NAME("P3 C") + PORT_BIT( 0x0040, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(3) PORT_NAME("P3 A") + PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_START ) PORT_PLAYER(3) + + PORT_START("JCART4") /* Joypad 4 on J-Cart (3 button + start) */ + PORT_BIT( 0x0001, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_8WAY PORT_PLAYER(4) + PORT_BIT( 0x0002, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_8WAY PORT_PLAYER(4) + PORT_BIT( 0x0004, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_8WAY PORT_PLAYER(4) + PORT_BIT( 0x0008, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_8WAY PORT_PLAYER(4) + PORT_BIT( 0x0010, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(4) PORT_NAME("P4 B") + PORT_BIT( 0x0020, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_PLAYER(4) PORT_NAME("P4 C") + PORT_BIT( 0x0040, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(4) PORT_NAME("P4 A") + PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_START ) PORT_PLAYER(4) + +INPUT_PORTS_END + +ioport_constructor md_jcart_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( jcart_ipt ); +} + + +void md_jcart_device::device_start() +{ + save_item(NAME(m_jcart_io_data)); +} + +void md_jcart_device::device_reset() +{ + m_jcart_io_data[0] = 0; + m_jcart_io_data[1] = 0; +} + +void md_seprom_codemast_device::device_start() +{ + save_item(NAME(m_i2c_mem)); + save_item(NAME(m_i2c_clk)); + save_item(NAME(m_jcart_io_data)); +} + +void md_seprom_codemast_device::device_reset() +{ + m_i2c_mem = 0; + m_i2c_clk = 0; + m_jcart_io_data[0] = 0; + m_jcart_io_data[1] = 0; +} + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +/*------------------------------------------------- + J-CART ONLY (Pete Sampras Tennis) + -------------------------------------------------*/ + +READ16_MEMBER(md_jcart_device::read) +{ + if (offset == 0x38fffe/2) + { + UINT8 joy[2]; + + if (m_jcart_io_data[0] & 0x40) + { + joy[0] = m_jcart3->read_safe(0); + joy[1] = m_jcart4->read_safe(0); + return (m_jcart_io_data[0] & 0x40) | joy[0] | (joy[1] << 8); + } + else + { + joy[0] = ((m_jcart3->read_safe(0) & 0xc0) >> 2) | (m_jcart3->read_safe(0) & 0x03); + joy[1] = ((m_jcart4->read_safe(0) & 0xc0) >> 2) | (m_jcart4->read_safe(0) & 0x03); + return (m_jcart_io_data[0] & 0x40) | joy[0] | (joy[1] << 8); + } + } + if (offset < 0x400000/2) + return m_rom[MD_ADDR(offset)]; + else + return 0xffff; +} + +WRITE16_MEMBER(md_jcart_device::write) +{ + if (offset == 0x38fffe/2) + { + m_jcart_io_data[0] = (data & 1) << 6; + m_jcart_io_data[1] = (data & 1) << 6; + } +} + +/*------------------------------------------------- + J-CART + SEPROM + -------------------------------------------------*/ + +READ16_MEMBER(md_seprom_codemast_device::read) +{ + if (offset == 0x380000/2) + { + m_i2c_mem = m_i2cmem->read_sda(); + return (m_i2c_mem & 1) << 7; + } + if (offset == 0x38fffe/2) + { + UINT8 joy[2]; + + if (m_jcart_io_data[0] & 0x40) + { + joy[0] = m_jcart3->read_safe(0); + joy[1] = m_jcart4->read_safe(0); + return (m_jcart_io_data[0] & 0x40) | joy[0] | (joy[1] << 8); + } + else + { + joy[0] = ((m_jcart3->read_safe(0) & 0xc0) >> 2) | (m_jcart3->read_safe(0) & 0x03); + joy[1] = ((m_jcart4->read_safe(0) & 0xc0) >> 2) | (m_jcart4->read_safe(0) & 0x03); + return (m_jcart_io_data[0] & 0x40) | joy[0] | (joy[1] << 8); + } + } + if (offset < 0x400000/2) + return m_rom[MD_ADDR(offset)]; + else + return 0xffff; +} + +WRITE16_MEMBER(md_seprom_codemast_device::write) +{ + if (offset == 0x380000/2) + { + m_i2c_clk = BIT(data, 9); + m_i2c_mem = BIT(data, 8); + m_i2cmem->write_scl(m_i2c_clk); + m_i2cmem->write_sda(m_i2c_mem); + } + if (offset == 0x38fffe/2) + { + m_jcart_io_data[0] = (data & 1) << 6; + m_jcart_io_data[1] = (data & 1) << 6; + } +} diff --git a/src/devices/bus/megadrive/jcart.h b/src/devices/bus/megadrive/jcart.h new file mode 100644 index 00000000000..c59f3af7572 --- /dev/null +++ b/src/devices/bus/megadrive/jcart.h @@ -0,0 +1,84 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __MD_JCART_H +#define __MD_JCART_H + +#include "md_slot.h" +#include "machine/i2cmem.h" + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> md_jcart_device + +class md_jcart_device : public device_t, + public device_md_cart_interface +{ +public: + // construction/destruction + md_jcart_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + md_jcart_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual ioport_constructor device_input_ports() const; + + // reading and writing + virtual DECLARE_READ16_MEMBER(read); + virtual DECLARE_WRITE16_MEMBER(write); + + required_ioport m_jcart3; + required_ioport m_jcart4; + +private: + UINT8 m_jcart_io_data[2]; +}; + +// ======================> md_seprom_codemast_device + +class md_seprom_codemast_device : public md_jcart_device +{ +public: + // construction/destruction + md_seprom_codemast_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + md_seprom_codemast_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual machine_config_constructor device_mconfig_additions() const; + + // reading and writing + virtual DECLARE_READ16_MEMBER(read); + virtual DECLARE_WRITE16_MEMBER(write); + + required_device m_i2cmem; + +private: + UINT8 m_jcart_io_data[2]; + UINT8 m_i2c_mem, m_i2c_clk; +}; + +// ======================> md_seprom_mm96_device (same read/write as codemast, but different I2C type) + +class md_seprom_mm96_device : public md_seprom_codemast_device +{ +public: + // construction/destruction + md_seprom_mm96_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual machine_config_constructor device_mconfig_additions() const; +}; + + + +// device type definition +extern const device_type MD_JCART; +extern const device_type MD_SEPROM_CODEMAST; +extern const device_type MD_SEPROM_MM96; + +#endif diff --git a/src/devices/bus/megadrive/md_carts.c b/src/devices/bus/megadrive/md_carts.c new file mode 100644 index 00000000000..698060c6014 --- /dev/null +++ b/src/devices/bus/megadrive/md_carts.c @@ -0,0 +1,71 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/********************************************************************** + + Megadrive carts + +**********************************************************************/ + +#include "md_carts.h" + +SLOT_INTERFACE_START(md_cart) + SLOT_INTERFACE_INTERNAL("rom", MD_STD_ROM) + SLOT_INTERFACE_INTERNAL("rom_svp", MD_ROM_SVP) + SLOT_INTERFACE_INTERNAL("rom_sk", MD_ROM_SK) +// NVRAM handling + SLOT_INTERFACE_INTERNAL("rom_sram", MD_ROM_SRAM) + SLOT_INTERFACE_INTERNAL("rom_sramsafe", MD_ROM_SRAM) + SLOT_INTERFACE_INTERNAL("rom_fram", MD_ROM_FRAM) + SLOT_INTERFACE_INTERNAL("rom_hardbl95", MD_ROM_SRAM) + SLOT_INTERFACE_INTERNAL("rom_xinqig", MD_ROM_SRAM) + SLOT_INTERFACE_INTERNAL("rom_beggarp", MD_ROM_BEGGARP) + SLOT_INTERFACE_INTERNAL("rom_wukong", MD_ROM_WUKONG) +// EEPROM handling (not supported fully yet) + SLOT_INTERFACE_INTERNAL("rom_eeprom", MD_STD_EEPROM) + SLOT_INTERFACE_INTERNAL("rom_nbajam", MD_EEPROM_NBAJAM) + SLOT_INTERFACE_INTERNAL("rom_nbajamte", MD_EEPROM_NBAJAMTE) + SLOT_INTERFACE_INTERNAL("rom_nflqb96", MD_EEPROM_NFLQB) + SLOT_INTERFACE_INTERNAL("rom_cslam", MD_EEPROM_CSLAM) + SLOT_INTERFACE_INTERNAL("rom_nhlpa", MD_EEPROM_NHLPA) + SLOT_INTERFACE_INTERNAL("rom_blara", MD_EEPROM_BLARA) +// J-Cart controller (Sampras Tennis) + SLOT_INTERFACE_INTERNAL("rom_jcart", MD_JCART) +// J-Cart controller + EEPROM handling (not supported fully yet) + SLOT_INTERFACE_INTERNAL("rom_codemast", MD_SEPROM_CODEMAST) + SLOT_INTERFACE_INTERNAL("rom_mm96", MD_SEPROM_MM96) +// STM95 EEPROM + SLOT_INTERFACE_INTERNAL("rom_stm95", MD_EEPROM_STM95) +// CodeMasters 2-in-1 (reset based) + SLOT_INTERFACE_INTERNAL("rom_cm2in1", MD_ROM_CM2IN1) +// Game Genie + SLOT_INTERFACE_INTERNAL("rom_ggenie", MD_ROM_GAMEGENIE) +// unique bankswitch + SLOT_INTERFACE_INTERNAL("rom_ssf2", MD_ROM_SSF2) + SLOT_INTERFACE_INTERNAL("rom_radica", MD_ROM_RADICA) +// pirate mappers (protection and/or bankswitch) + SLOT_INTERFACE_INTERNAL("rom_16mj2", MD_ROM_16MJ2) + SLOT_INTERFACE_INTERNAL("rom_bugs", MD_ROM_BUGSLIFE) + SLOT_INTERFACE_INTERNAL("rom_chinf3", MD_ROM_CHINF3) + SLOT_INTERFACE_INTERNAL("rom_elfwor", MD_ROM_ELFWOR) + SLOT_INTERFACE_INTERNAL("rom_yasech", MD_ROM_YASECH) + SLOT_INTERFACE_INTERNAL("rom_kof98", MD_ROM_KOF98) + SLOT_INTERFACE_INTERNAL("rom_kof99", MD_ROM_KOF99) + SLOT_INTERFACE_INTERNAL("rom_lion2", MD_ROM_LION2) + SLOT_INTERFACE_INTERNAL("rom_lion3", MD_ROM_LION3) + SLOT_INTERFACE_INTERNAL("rom_mcpir", MD_ROM_MCPIR) + SLOT_INTERFACE_INTERNAL("rom_mjlov", MD_ROM_MJLOV) + SLOT_INTERFACE_INTERNAL("rom_pokea", MD_ROM_POKEA) + SLOT_INTERFACE_INTERNAL("rom_pokestad", MD_ROM_POKESTAD) + SLOT_INTERFACE_INTERNAL("rom_realtec", MD_ROM_REALTEC) + SLOT_INTERFACE_INTERNAL("rom_redcl", MD_ROM_REDCL) + SLOT_INTERFACE_INTERNAL("rom_rx3", MD_ROM_RX3) + SLOT_INTERFACE_INTERNAL("rom_sbubl", MD_ROM_SBUBL) + SLOT_INTERFACE_INTERNAL("rom_smb", MD_ROM_SMB) + SLOT_INTERFACE_INTERNAL("rom_smb2", MD_ROM_SMB2) + SLOT_INTERFACE_INTERNAL("rom_smw64", MD_ROM_SMW64) + SLOT_INTERFACE_INTERNAL("rom_smouse", MD_ROM_SMOUSE) + SLOT_INTERFACE_INTERNAL("rom_soulb", MD_ROM_SOULB) + SLOT_INTERFACE_INTERNAL("rom_squir", MD_ROM_SQUIR) + SLOT_INTERFACE_INTERNAL("rom_tekkensp", MD_ROM_TEKKENSP) + SLOT_INTERFACE_INTERNAL("rom_topf", MD_ROM_TOPF) +SLOT_INTERFACE_END diff --git a/src/devices/bus/megadrive/md_carts.h b/src/devices/bus/megadrive/md_carts.h new file mode 100644 index 00000000000..b9ab25d146b --- /dev/null +++ b/src/devices/bus/megadrive/md_carts.h @@ -0,0 +1,27 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/********************************************************************** + + Megadrive carts + +**********************************************************************/ + +#pragma once + +#ifndef __MD_CARTS_H__ +#define __MD_CARTS_H__ + +#include "emu.h" + +#include "rom.h" +#include "svp.h" +#include "sk.h" +#include "ggenie.h" +#include "eeprom.h" +#include "jcart.h" +#include "stm95.h" + +// supported devices +SLOT_INTERFACE_EXTERN(md_cart); + +#endif // __MD_CARTS_H__ diff --git a/src/devices/bus/megadrive/md_slot.c b/src/devices/bus/megadrive/md_slot.c new file mode 100644 index 00000000000..6caa7df817f --- /dev/null +++ b/src/devices/bus/megadrive/md_slot.c @@ -0,0 +1,1099 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli,Cowering +/*********************************************************************************************************** + + + MegaDrive cart emulation + (through slot devices) + + The driver exposes address ranges + 0x000000-0x7fffff to read/write (typically cart data, possibly banked, and some protection) + 0x130000-0x1300ff to read_a13/write_a13 (typically SRAM toggling or protection) + 0x150000-0x1500ff to read_a15/write_a15 (for SVP registers, not converted yet to slots) + + currently available slot devices: + md_rom: standard carts + carts with NVRAM (SRAM/FRAM) + pirate carts with protection & bankswitch + md_eeprom: carts + I2C EEPROM (EEPROM device hooked up only, support to be completed) + md_jcart: Codemasters J-Cart & J-Cart+SEPROM (again, EEPROM device hooked up only, support to be completed) + md_sk: Sonic & Knuckles pass-thorugh cart (enables a second slot to mount any other cart) + md_stm95: cart + STM95 EEPROM (e.g. Pier Solar) + + + Cart Mirroring (based Eke's research) + + MD Cartridge area is mapped to $000000-$3fffff: when accessing ROM, 68k address lines A1 to A21 can be + used by the internal cartridge hardware to decode full 4MB address range. + Depending on ROM total size and additional decoding hardware, some address lines might be ignored, + resulting in ROM mirroring. + + Cartridges typically use either 8-bits (x2) or 16-bits (x1, x2) Mask ROM chips, each chip size is a + factor of 2 bytes. + When one chip ROM1 of size 2^N is present, it is generally mirrored each 2^N bytes so that read access + to cart area sees the sequence ROM1,ROM1,ROM1,... (up to 4MB) + When two chips ROM1 & ROM2 are present and the whole size is 2^N, then the block ROM1+ROM2 is mirrored + in the cart area, and reads see the sequence ROM1+ROM2,ROM1+ROM2,... (up to 4MB) + When two chips ROM1 & ROM2 are present and the whole size is not 2^N (e.g. because ROM1 and ROM2 have + different sizes), then the area between the end of ROM2 and next power 2^N is generally ignored, and + reads see the sequence ROM1,ROM2,XXXX,ROM1,ROM2,XXXX... (up to 4MB) + + At loading time we first compute first power 2^N larger than cart size (see get_padded_size function), + we allocate such a size for ROM and we fill of 0xff the area between end of dump and 2^N. + Then we handle mirroring by creating a rom_bank_map[] (see rom_map_setup function) which points each + access in 0x000000-0x400000 to the correct 64K ROM bank. + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "md_slot.h" + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type MD_CART_SLOT = &device_creator; +const device_type PICO_CART_SLOT = &device_creator; +const device_type COPERA_CART_SLOT = &device_creator; + +//************************************************************************** +// MD cartridges Interface +//************************************************************************** + +//------------------------------------------------- +// device_md_cart_interface - constructor +//------------------------------------------------- + +device_md_cart_interface::device_md_cart_interface(const machine_config &mconfig, device_t &device) + : device_slot_card_interface(mconfig, device), + m_rom(NULL), + m_rom_size(0) +{ +} + + +//------------------------------------------------- +// ~device_md_cart_interface - destructor +//------------------------------------------------- + +device_md_cart_interface::~device_md_cart_interface() +{ +} + +//------------------------------------------------- +// rom_alloc - alloc the space for the cart +//------------------------------------------------- + +void device_md_cart_interface::rom_alloc(size_t size, const char *tag) +{ + if (m_rom == NULL) + { + m_rom = (UINT16 *)device().machine().memory().region_alloc(std::string(tag).append(MDSLOT_ROM_REGION_TAG).c_str(), size, 2, ENDIANNESS_LITTLE)->base(); + m_rom_size = size; + } +} + + +//------------------------------------------------- +// nvram_alloc - alloc the space for the nvram +//------------------------------------------------- + +void device_md_cart_interface::nvram_alloc(size_t size) +{ + m_nvram.resize(size/sizeof(UINT16)); +} + +//------------------------------------------------- +// rom_map_setup - setup map of rom banks in 64K +// blocks, so to simplify ROM mirroring +//------------------------------------------------- + +void device_md_cart_interface::rom_map_setup(UINT32 size) +{ + int i; + // setup the rom_bank_map array to faster ROM read + for (i = 0; i < size / 0x10000; i++) + rom_bank_map[i] = i; + + // fill up remaining blocks with mirrors + while (i % 64) + { + int j = 0, repeat_banks; + while ((i % (64 >> j)) && j < 7) + j++; + repeat_banks = i % (64 >> (j - 1)); + for (int k = 0; k < repeat_banks; k++) + rom_bank_map[i + k] = rom_bank_map[i + k - repeat_banks]; + i += repeat_banks; + } + +// check bank map! +// for (i = 0; i < 64; i++) +// { +// printf("bank %3d = %3d\t", i, rom_bank_map[i]); +// if ((i%8) == 7) +// printf("\n"); +// } +} + +//------------------------------------------------- +// get_padded_size +//------------------------------------------------- + +UINT32 device_md_cart_interface::get_padded_size(UINT32 size) +{ + UINT32 pad_size = 0x10000; + while (size > pad_size) + pad_size <<= 1; + + if (pad_size < 0x800000 && size < pad_size) + return pad_size; + else + return size; +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// base_md_cart_slot_device - constructor +//------------------------------------------------- +base_md_cart_slot_device::base_md_cart_slot_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_image_interface(mconfig, *this), + device_slot_interface(mconfig, *this), + m_type(SEGA_STD), + m_must_be_loaded(1) +{ +} + +md_cart_slot_device::md_cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + base_md_cart_slot_device(mconfig, MD_CART_SLOT, "MD Cartridge Slot", tag, owner, clock, "md_cart_slot", __FILE__) +{ +} + +pico_cart_slot_device::pico_cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + base_md_cart_slot_device(mconfig, PICO_CART_SLOT, "Pico Cartridge Slot", tag, owner, clock, "pico_cart_slot", __FILE__) +{ +} + +copera_cart_slot_device::copera_cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + base_md_cart_slot_device(mconfig, COPERA_CART_SLOT, "Copera Cartridge Slot", tag, owner, clock, "copera_cart_slot", __FILE__) +{ +} + +//------------------------------------------------- +// base_md_cart_slot_device - destructor +//------------------------------------------------- + +base_md_cart_slot_device::~base_md_cart_slot_device() +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void base_md_cart_slot_device::device_start() +{ + m_cart = dynamic_cast(get_card_device()); +} + +//------------------------------------------------- +// device_config_complete - perform any +// operations now that the configuration is +// complete +//------------------------------------------------- + +void base_md_cart_slot_device::device_config_complete() +{ + // set brief and instance name + update_names(); +} + + +//------------------------------------------------- +// MD PCB +//------------------------------------------------- + + +struct md_slot +{ + int pcb_id; + const char *slot_option; +}; + +// Here, we take the feature attribute from .xml (i.e. the PCB name) and we assign a unique ID to it +static const md_slot slot_list[] = +{ + { SEGA_SK, "rom_sk" }, + { SEGA_SVP, "rom_svp"}, + + { SEGA_SRAM, "rom_sram" }, + { SEGA_FRAM, "rom_fram" }, + { HARDBALL95, "rom_hardbl95" }, + { XINQIG, "rom_xinqig"}, + { BEGGARP, "rom_beggarp"}, + { WUKONG, "rom_wukong"}, + + { SEGA_EEPROM, "rom_eeprom" }, + { NBA_JAM, "rom_nbajam" }, + { NBA_JAM_TE, "rom_nbajamte" }, + { NFL_QB_96, "rom_nflqb" }, + { C_SLAM, "rom_cslam" }, + { EA_NHLPA, "rom_nhlpa" }, + { BRIAN_LARA, "rom_blara" }, + + { CM_JCART, "rom_jcart" }, + { CODE_MASTERS, "rom_codemast" }, + { CM_MM96, "rom_mm96" }, + + { PSOLAR, "rom_stm95"}, + + { SSF2, "rom_ssf2" }, + { CM_2IN1, "rom_cm2in1" }, + { RADICA, "rom_radica" }, +// { GAME_KANDUME, "rom_gkand" }, // what's needed by this? + + { TILESMJ2, "rom_16mj2" }, + { BUGSLIFE, "rom_bugs" }, + { CHINFIGHT3, "rom_chinf3" }, + { ELFWOR, "rom_elfwor" }, + { KAIJU, "rom_pokestad" }, + { KOF98, "rom_kof98" }, + { KOF99, "rom_kof99" }, + { LIONK2, "rom_lion2" }, + { LIONK3, "rom_lion3" }, + { MC_PIRATE, "rom_mcpir" }, + { MJLOVER, "rom_mjlov" }, + { POKEMONA, "rom_pokea" }, + { REALTEC, "rom_realtec" }, + { REDCL_EN, "rom_redcl" }, + { REDCLIFF, "rom_redcl" }, + { ROCKMANX3, "rom_rx3" }, + { SBUBBOB, "rom_sbubl" }, + { SMB, "rom_smb" }, + { SMB2, "rom_smb2" }, + { SMW64, "rom_smw64" }, + { SMOUSE, "rom_smouse" }, + { SOULBLAD, "rom_soulblad" }, + { SQUIRRELK, "rom_squir" }, + { TEKKENSP, "rom_tekkesp" }, + { TOPFIGHTER, "rom_topf" }, + + { SEGA_SRAM_FULLPATH, "rom_sram" }, + { SEGA_SRAM_FALLBACK, "rom_sramsafe" } +}; + +static int md_get_pcb_id(const char *slot) +{ + for (int i = 0; i < ARRAY_LENGTH(slot_list); i++) + { + if (!core_stricmp(slot_list[i].slot_option, slot)) + return slot_list[i].pcb_id; + } + + return SEGA_STD; +} + +static const char *md_get_slot(int type) +{ + for (int i = 0; i < ARRAY_LENGTH(slot_list); i++) + { + if (slot_list[i].pcb_id == type) + return slot_list[i].slot_option; + } + + return "rom"; +} + + +/*------------------------------------------------- + SRAM handling + -------------------------------------------------*/ + +/*------------------------------------------------- + call load + -------------------------------------------------*/ + + +bool base_md_cart_slot_device::call_load() +{ + if (m_cart) + { + m_type = SEGA_STD; + int res; + + // STEP 1: load the file image and keep a copy for later banking + // STEP 2: identify the cart type + // The two steps are carried out differently if we are loading from a list or not + if (software_entry() == NULL) + res = load_nonlist(); + else + res = load_list(); + + //printf("cart type: %d\n", m_type); + + if (res == IMAGE_INIT_PASS) + { + //speed-up rom access from SVP add-on, if present + if (m_type == SEGA_SVP) + m_cart->set_bank_to_rom("cart_svp", 0x800/2); + + // STEP 3: install memory handlers for this type of cart + setup_custom_mappers(); + + // STEP 4: take care of SRAM. + setup_nvram(); + + if (m_cart->get_nvram_size()) + battery_load(m_cart->get_nvram_base(), m_cart->get_nvram_size(), 0xff); + + file_logging((UINT8 *)m_cart->get_rom_base(), m_cart->get_rom_size(), m_cart->get_nvram_size()); + } + + return res; + } + + return IMAGE_INIT_PASS; +} + + +int base_md_cart_slot_device::load_list() +{ + UINT16 *ROM; + UINT32 length = get_software_region_length("rom"); + const char *slot_name; + + // if cart size is not (2^n * 64K), the system will see anyway that size so we need to alloc a bit more space + length = m_cart->get_padded_size(length); + + m_cart->rom_alloc(length, tag()); + ROM = m_cart->get_rom_base(); + memcpy((UINT8 *)ROM, get_software_region("rom"), get_software_region_length("rom")); + + // if we allocated a ROM larger that the file (e.g. due to uneven cart size), set remaining space to 0xff + if (length > get_software_region_length("rom")) + memset(ROM + get_software_region_length("rom")/2, 0xffff, (length - get_software_region_length("rom"))/2); + + if ((slot_name = get_feature("slot")) == NULL) + m_type = SEGA_STD; + else + m_type = md_get_pcb_id(slot_name); + + // handle mirroring of ROM, unless it's SSF2 or Pier Solar + if (m_type != SSF2 && m_type != PSOLAR && m_type != CM_2IN1) + m_cart->rom_map_setup(length); + + return IMAGE_INIT_PASS; +} + + +/************************************* + * Helper function: Detect SMD file + *************************************/ + +/* code taken directly from GoodGEN by Cowering */ +static int genesis_is_SMD(unsigned char *buf, unsigned int len) +{ + if (len > 0x2081 && buf[0x2080] == 'S' && buf[0x80] == 'E' && buf[0x2081] == 'G' && buf[0x81] == 'A') + return 1; + + /* aq quiz */ + if (len > (0xf0 + 8) && !strncmp("UZ(-01 ", (const char *) &buf[0xf0], 8)) + return 1; + + /* Phelios USA redump */ + /* target earth */ + /* klax (namcot) */ + if (len > 0x2081 && buf[0x2080] == ' ' && buf[0x0080] == 'S' && buf[0x2081] == 'E' && buf[0x0081] == 'G') + return 1; + + /* jap baseball 94 */ + if (len > (0xf0 + 9) && !strncmp("OL R-AEAL", (const char *) &buf[0xf0], 9)) + return 1; + + /* devilish Mahjong Tower */ + if (len > (0xf3 + 11) && !strncmp("optrEtranet", (const char *) &buf[0xf3], 11)) + return 1; + + /* golden axe 2 beta */ + if (len > 0x0103 && buf[0x0100] == 0x3c && buf[0x0101] == 0 && buf[0x0102] == 0 && buf[0x0103] == 0x3c) + return 1; + + /* omega race */ + if (len > (0x90 + 8) && !strncmp("OEARC ", (const char *) &buf[0x90], 8)) + return 1; + + /* budokan beta */ + if ((len >= 0x6708 + 8) && !strncmp(" NTEBDKN", (const char *) &buf[0x6708], 8)) + return 1; + + /* cdx pro 1.8 bios */ + if (len > (0x2c0 + 7) && !strncmp("so fCXP", (const char *) &buf[0x2c0], 7)) + return 1; + + /* ishido (hacked) */ + if (len > (0x90 + 8) && !strncmp("sio-Wyo ", (const char *) &buf[0x0090], 8)) + return 1; + + /* onslaught */ + if (len > (0x88 + 8) && !strncmp("SS CAL ", (const char *) &buf[0x0088], 8)) + return 1; + + /* tram terror pirate */ + if ((len >= 0x3648 + 8) && !strncmp("SG NEPIE", (const char *) &buf[0x3648], 8)) + return 1; + + /* breath of fire 3 chinese */ + if (len > 0xa && buf[0x0007] == 0x1c && buf[0x0008] == 0x0a && buf[0x0009] == 0xb8 && buf[0x000a] == 0x0a) + return 1; + + /*tetris pirate */ + if ((len >= 0x1cbe + 5) && !strncmp("@TTI>", (const char *) &buf[0x1cbe], 5)) + return 1; + + return 0; +} + +/************************************* + * Loading a cart image *not* from + * softlist + *************************************/ + +int base_md_cart_slot_device::load_nonlist() +{ + unsigned char *ROM; + bool is_smd, is_md; + UINT32 tmplen = length(), offset, len; + dynamic_buffer tmpROM(tmplen); + + // STEP 1: store a (possibly headered) copy of the file and determine its type (SMD? MD? BIN?) + fread(&tmpROM[0], tmplen); + is_smd = genesis_is_SMD(&tmpROM[0x200], tmplen - 0x200); + is_md = (tmpROM[0x80] == 'E') && (tmpROM[0x81] == 'A') && (tmpROM[0x82] == 'M' || tmpROM[0x82] == 'G'); + + // take header into account, if any + offset = is_smd ? 0x200 : 0; + + // STEP 2: allocate space for the real copy of the game + // if cart size is not (2^n * 64K), the system will see anyway that size so we need to alloc a bit more space + len = m_cart->get_padded_size(tmplen - offset); + + // this contains an hack for SSF2: its current bankswitch code needs larger rom space to work + m_cart->rom_alloc((len == 0x500000) ? 0x900000 : len, tag()); + + // STEP 3: copy the game data in the appropriate way + ROM = (unsigned char *)m_cart->get_rom_base(); + + if (is_smd) + { + osd_printf_debug("SMD!\n"); + + for (int ptr = 0; ptr < (tmplen - 0x200) / 0x2000; ptr += 2) + { + for (int x = 0; x < 0x2000; x++) + { + ROM[ptr * 0x2000 + x * 2 + 0] = tmpROM[0x200 + ((ptr + 1) * 0x2000) + x]; + ROM[ptr * 0x2000 + x * 2 + 1] = tmpROM[0x200 + ((ptr + 0) * 0x2000) + x]; + } + } + } + else if (is_md) + { + osd_printf_debug("MD!\n"); + + for (int ptr = 0; ptr < tmplen; ptr += 2) + { + ROM[ptr] = tmpROM[(tmplen >> 1) + (ptr >> 1)]; + ROM[ptr + 1] = tmpROM[(ptr >> 1)]; + } + } + else + { + osd_printf_debug("BIN!\n"); + + fseek(0, SEEK_SET); + fread(ROM, len); + } + + // if we allocated a ROM larger that the file (e.g. due to uneven cart size), set remaining space to 0xff + if (len > (tmplen - offset)) + memset(m_cart->get_rom_base() + (tmplen - offset)/2, 0xffff, (len - tmplen + offset)/2); + + + // STEP 4: determine the cart type (to deal with sram/eeprom & pirate mappers) + m_type = get_cart_type(ROM, len); + + // handle mirroring of ROM, unless it's SSF2 or Pier Solar + if (m_type != SSF2 && m_type != PSOLAR) + m_cart->rom_map_setup(len); + + +// CPU needs to access ROM as a ROM_REGION16_BE, so we need to compensate on LE machines +#ifdef LSB_FIRST + unsigned char fliptemp; + for (int ptr = 0; ptr < len; ptr += 2) + { + fliptemp = ROM[ptr]; + ROM[ptr] = ROM[ptr+1]; + ROM[ptr+1] = fliptemp; + } +#endif + + return IMAGE_INIT_PASS; +} + +/*------------------------------------------------- + call_unload + -------------------------------------------------*/ + +void base_md_cart_slot_device::call_unload() +{ + if (m_cart && m_cart->get_nvram_base() && m_cart->get_nvram_size()) + battery_save(m_cart->get_nvram_base(), m_cart->get_nvram_size()); +} + + +void base_md_cart_slot_device::setup_custom_mappers() +{ + UINT16 *ROM16 = m_cart->get_rom_base(); + + switch (m_type) + { + case SSF2: + // copy the image in 0x400000-0x900000 and keep the beginning for bankswitch + for (int x = 0x500000/2; x > 0; x--) + ROM16[x + 0x400000/2 - 1] = ROM16[x - 1]; + for (int x = 0; x < 0x400000/2; x++) + ROM16[x] = ROM16[x + 0x400000/2]; + break; + case REDCL_EN: + // decrypt + for (int x = 0; x < 0x200000/2; x++) + ROM16[x] = ROM16[x + 2] ^ 0x4040; + break; + } +} + +void base_md_cart_slot_device::setup_nvram() +{ + UINT8 *ROM = (UINT8 *)m_cart->get_rom_base(); + m_cart->m_nvram_readonly = 0; + m_cart->m_nvram_active = 0; + m_cart->m_nvram_handlers_installed = 0; + + /* install SRAM & i2c handlers for the specific type of cart */ + switch (m_type) + { + // These types only come from fullpath loading + case SEGA_SRAM_FULLPATH: + m_cart->m_nvram_start = (ROM[0x1b5] << 24 | ROM[0x1b4] << 16 | ROM[0x1b7] << 8 | ROM[0x1b6]); + m_cart->m_nvram_end = (ROM[0x1b9] << 24 | ROM[0x1b8] << 16 | ROM[0x1bb] << 8 | ROM[0x1ba]); + logerror("SRAM detected from header: starting location %X - SRAM Length %X\n", m_cart->m_nvram_start, m_cart->m_nvram_end - m_cart->m_nvram_start + 1); + + // We assume at most 64k of SRAM. is this correct? + if ((m_cart->m_nvram_start > m_cart->m_nvram_end) || ((m_cart->m_nvram_end - m_cart->m_nvram_start) >= 0x10000)) + m_cart->m_nvram_end = m_cart->m_nvram_start + 0xffff; + + if (m_cart->m_nvram_start & 1) + m_cart->m_nvram_start -= 1; + + if (!(m_cart->m_nvram_end & 1)) + m_cart->m_nvram_end += 1; + + m_cart->nvram_alloc(m_cart->m_nvram_end - m_cart->m_nvram_start + 1); + if (m_cart->m_rom_size <= m_cart->m_nvram_start) + m_cart->m_nvram_active = 1; + m_cart->m_nvram_handlers_installed = 1; + // don't trust too much header? + m_cart->m_nvram_start &= 0x3fffff; + m_cart->m_nvram_end &= 0x3fffff; + break; + case SEGA_SRAM_FALLBACK: + m_cart->m_nvram_start = 0x200000; + m_cart->m_nvram_end = m_cart->m_nvram_start + 0xffff; + logerror("No SRAM detected from header, using fallback SRAM in case this is a broken header\n"); + + m_cart->nvram_alloc(m_cart->m_nvram_end - m_cart->m_nvram_start + 1); + if (m_cart->m_rom_size <= m_cart->m_nvram_start) + m_cart->m_nvram_active = 1; + break; + + // These types only come from softlist loading + case SEGA_SRAM: + m_cart->m_nvram_start = 0x200000; + m_cart->m_nvram_end = m_cart->m_nvram_start + get_software_region_length("sram") - 1; + m_cart->nvram_alloc(m_cart->m_nvram_end - m_cart->m_nvram_start + 1); + if (m_cart->m_rom_size <= m_cart->m_nvram_start) + m_cart->m_nvram_active = 1; + m_cart->m_nvram_handlers_installed = 1; + break; + case SEGA_FRAM: + m_cart->m_nvram_start = 0x200000; + m_cart->m_nvram_end = m_cart->m_nvram_start + get_software_region_length("fram") - 1; + m_cart->nvram_alloc(m_cart->m_nvram_end - m_cart->m_nvram_start + 1); + m_cart->m_nvram_active = 1; + m_cart->m_nvram_handlers_installed = 1; + break; + + // These types might come from both (pending proper id routines) + case HARDBALL95: + m_cart->m_nvram_start = 0x300000; + m_cart->m_nvram_end = m_cart->m_nvram_start + get_software_region_length("sram") - 1; + m_cart->nvram_alloc(m_cart->m_nvram_end - m_cart->m_nvram_start + 1); + m_cart->m_nvram_active = 1; + m_cart->m_nvram_handlers_installed = 1; + break; + case XINQIG: + m_cart->m_nvram_start = 0x400000; + m_cart->m_nvram_end = m_cart->m_nvram_start + 0xffff; + m_cart->nvram_alloc(m_cart->m_nvram_end - m_cart->m_nvram_start + 1); + m_cart->m_nvram_active = 1; + m_cart->m_nvram_handlers_installed = 1; + break; + case BEGGARP: + m_cart->m_nvram_start = 0x400000; + m_cart->m_nvram_end = m_cart->m_nvram_start + 0xffff; + m_cart->nvram_alloc(0x8000); // 32K mirrored + m_cart->m_nvram_active = 1; + break; + case WUKONG: + m_cart->m_nvram_start = 0x3c0000; + m_cart->m_nvram_end = m_cart->m_nvram_start + 0x3fff; + m_cart->nvram_alloc(m_cart->m_nvram_end - m_cart->m_nvram_start + 1); + m_cart->m_nvram_active = 1; + break; + } +} + + + +/*------------------------------------------------- + call softlist load + -------------------------------------------------*/ + +bool base_md_cart_slot_device::call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry) +{ + load_software_part_region(*this, swlist, swname, start_entry); + return TRUE; +} + +int base_md_cart_slot_device::get_cart_type(UINT8 *ROM, UINT32 len) +{ + int type = SEGA_STD; + + /* Detect carts which need additional handlers */ + static const unsigned char smouse_sig[] = { 0x4d, 0xf9, 0x00, 0x40, 0x00, 0x02 }, + mjlover_sig[] = { 0x13, 0xf9, 0x00, 0x40, 0x00, 0x00 }, // move.b ($400000).l,($FFFF0C).l (partial) + squir_sig[] = { 0x26, 0x79, 0x00, 0xff, 0x00, 0xfa }, + bugsl_sig[] = { 0x20, 0x12, 0x13, 0xc0, 0x00, 0xff }, + sbub_sig[] = { 0x0c, 0x39, 0x00, 0x55, 0x00, 0x40 }, // cmpi.b #$55,($400000).l + lk3_sig[] = { 0x0c, 0x01, 0x00, 0x30, 0x66, 0xe4 }, + sdk_sig[] = { 0x48, 0xe7, 0xff, 0xfe, 0x52, 0x79 }, + redcliff_sig[] = { 0x10, 0x39, 0x00, 0x40, 0x00, 0x04 }, // move.b ($400004).l,d0 + redcl_en_sig[] = { 0x50, 0x79, 0x40, 0x00, 0x40, 0x44 }, // move.b ($400004).l,d0 + smb_sig[] = { 0x20, 0x4d, 0x41, 0x52, 0x49, 0x4f }, + smb2_sig[] = { 0x4e, 0xb9, 0x00, 0x0f, 0x25, 0x84 }, + kaiju_sig[] = { 0x19, 0x7c, 0x00, 0x01, 0x00, 0x00 }, + chifi3_sig[] = { 0xb6, 0x16, 0x66, 0x00, 0x00, 0x4a }, + lionk2_sig[] = { 0x26, 0x79, 0x00, 0xff, 0x00, 0xf4 }, + rx3_sig[] = { 0x66, 0x00, 0x00, 0x0e, 0x30, 0x3c }, + kof98_sig[] = { 0x9b, 0xfc, 0x00, 0x00, 0x4a, 0x00 }, + s15in1_sig[] = { 0x22, 0x3c, 0x00, 0xa1, 0x30, 0x00 }, + kof99_sig[] = { 0x20, 0x3c, 0x30, 0x00, 0x00, 0xa1 }, // move.l #$300000A1,d0 + radica_sig[] = { 0x4e, 0xd0, 0x30, 0x39, 0x00, 0xa1 }, // jmp (a0) move.w ($a130xx),d0 + soulb_sig[] = { 0x33, 0xfc, 0x00, 0x0c, 0x00, 0xff }, // move.w #$C,($FF020A).l (what happens if check fails) + s19in1_sig[] = { 0x13, 0xc0, 0x00, 0xa1, 0x30, 0x38 }, + rockman_sig[] = { 0xea, 0x80 }; + + switch (len) + { + case 0x80000: + if (!memcmp(&ROM[0x08c8], smouse_sig, sizeof(smouse_sig))) + type = SMOUSE; + + if (!memcmp((char *)&ROM[0x7e30e], "SEGA", 4) || + !memcmp((char *)&ROM[0x7e100], "SEGA", 4) || + !memcmp((char *)&ROM[0x7e1e6], "SEGA", 4)) + type = REALTEC; + + if (!memcmp((char *)&ROM[0x0180], "GM T-50396", 10)) // NHLPA Hockey 93 + type = EA_NHLPA; + + if (!memcmp((char *)&ROM[0x0180], "GM MK-1215", 10)) // Evander Holyfield + type = SEGA_EEPROM; + break; + + case 0xc0000: + + if (!memcmp((char *)&ROM[0x0180], "GM G-4060 ", 8)) // Wonder Boy V + type = SEGA_EEPROM; + break; + + case 0x100000: + if (!memcmp(&ROM[0x01b24], mjlover_sig, sizeof(mjlover_sig))) + type = MJLOVER; + + if (!memcmp(&ROM[0x03b4], squir_sig, sizeof(squir_sig))) + type = SQUIRRELK; + + if (!memcmp(&ROM[0xee0d0], bugsl_sig, sizeof(bugsl_sig))) + type = BUGSLIFE; + + if (!memcmp((char *)&ROM[0x0172], "GAME : ELF WOR", 14)) + type = ELFWOR; + + if (!memcmp(&ROM[0x123e4], sbub_sig, sizeof(sbub_sig))) + type = SBUBBOB; + + if (!memcmp((char *)&ROM[0x0180], "GM T-50176", 10)) // Rings of Power + type = EA_NHLPA; + + if (!memcmp((char *)&ROM[0x0180], "MK 00001211-00", 14)) // Sports Talk Baseball + type = SEGA_EEPROM; + + if (!memcmp((char *)&ROM[0x0180], "GM T-120096-", 12)) // Micro Machines 2 + type = CODE_MASTERS; + + if (!memcmp((char *)&ROM[0x0180], "GM T-120146-", 12)) // Brian Lara Cricket 96 / Shane Wayne Cricket 96 + type = BRIAN_LARA; + + if (!memcmp((char *)&ROM[0x0190], "OJKRPTBVFCA ", 0x10)) // Micro Machines '96 / Military TODO: better way to recognize these? + type = CODE_MASTERS; + break; + + case 0x200000: + if (!memcmp(&ROM[0x18c6], lk3_sig, sizeof(lk3_sig))) + type = LIONK3; + + if (!memcmp(&ROM[0x220], sdk_sig, sizeof(sdk_sig))) + type = LIONK3; + + if (!memcmp(&ROM[0xce560], redcliff_sig, sizeof(redcliff_sig))) + type = REDCLIFF; + + if (!memcmp(&ROM[0xc8cb0], smb_sig, sizeof(smb_sig))) + type = SMB; + + if (!memcmp(&ROM[0xf24d6], smb2_sig, sizeof(smb2_sig))) + type = SMB2; + + if (!memcmp(&ROM[0x674e], kaiju_sig, sizeof(kaiju_sig))) + type = KAIJU; + + if (!memcmp(&ROM[0x1780], chifi3_sig, sizeof(chifi3_sig))) + type = CHINFIGHT3; + + if (!memcmp(&ROM[0x03c2], lionk2_sig, sizeof(lionk2_sig))) + type = LIONK2; + + if (!memcmp(&ROM[0xc8b90], rx3_sig, sizeof(rx3_sig))) + type = ROCKMANX3; + + if (!memcmp(&ROM[0x56ae2], kof98_sig, sizeof(kof98_sig))) + type = KOF98; + + if (!memcmp(&ROM[0x17bb2], s15in1_sig, sizeof(s15in1_sig))) + type = MC_PIRATE; + + if (!memcmp((char *)&ROM[0x0180], "GM T-081326 ", 12)) // NBA Jam + type = NBA_JAM; + + if (!memcmp((char *)&ROM[0x0180], "GM MK-1228", 10)) // Greatest Heavyweight of the Ring + type = SEGA_EEPROM; + + if ((!memcmp((char *)&ROM[0x0180], "GM T-12046", 10)) || // Mega Man + (!memcmp((char *)&ROM[0x0180], "GM T-12053", 10) && !memcmp(&ROM[0x18e], rockman_sig, sizeof(rockman_sig)))) // / Rock Man (EEPROM version) + type = SEGA_EEPROM; + + if (!memcmp((char *)&ROM[0x0150], "Virtua Racing", 13)) + type = SEGA_SVP; + + break; + + case 0x200005: + if (!memcmp(&ROM[0xce564], redcl_en_sig, sizeof(redcliff_sig))) + type = REDCL_EN; + break; + + case 0x300000: + if (!memcmp(&ROM[0x220], sdk_sig, sizeof(sdk_sig))) + type = LIONK3; + + if (!memcmp(&ROM[0x1fd0d2], kof99_sig, sizeof(kof99_sig))) + type = KOF99; + + if (!memcmp((char *)&ROM[0x0180], "GM T-81406", 10)) // NBA Jam TE + type = NBA_JAM_TE; + + if (!memcmp((char *)&ROM[0x0180], "GM T-081276 ", 12)) // NFL Quarterback Club + type = NBA_JAM_TE; + + break; + + case 0x400000: + if (!memcmp(&ROM[0x3c031c], radica_sig, sizeof(radica_sig)) || + !memcmp(&ROM[0x3f031c], radica_sig, sizeof(radica_sig))) // ssf+gng + radica vol1 + type = RADICA; + + if (!memcmp(&ROM[0x028460], soulb_sig, sizeof(soulb_sig))) + type = SOULBLAD; + + if (!memcmp(&ROM[0x1e700], s19in1_sig, sizeof(s19in1_sig))) + type = MC_PIRATE; + + if (!memcmp((char *)&ROM[0x0180], "GM T-081586-", 12)) // NFL Quarterback Club 96 + type = NFL_QB_96; + + if (!memcmp((char *)&ROM[0x0180], "GM T-081576 ", 12)) // College Slam + type = C_SLAM; + + if (!memcmp((char *)&ROM[0x0180], "GM T-81476", 10)) // Big Hurt Baseball + type = C_SLAM; + + break; + + case 0x500000: + if (!memcmp((char *)&ROM[0x0120], "SUPER STREET FIGHTER2 ", 22)) + type = SSF2; + break; + + case 0x800000: + if (!memcmp((char *)&ROM[0x0180], "GM T-574023-", 12)) // Pier Solar + type = PSOLAR; + break; + + default: + break; + } + + //check for SRAM among the general carts + if (type == SEGA_STD) + { + // If the cart is not of a special type, we check the header for SRAM. + if (ROM[0x1b1] == 'A' && ROM[0x1b0] == 'R') + { + UINT32 start = (ROM[0x1b4] << 24 | ROM[0x1b5] << 16 | ROM[0x1b6] << 8 | ROM[0x1b7]); + UINT32 end = (ROM[0x1b8] << 24 | ROM[0x1b9] << 16 | ROM[0x1ba] << 8 | ROM[0x1bb]); + // For some games using serial EEPROM, difference between SRAM end to start is 0 or 1. + // Carts with EEPROM should have been already detected above, but better safe than sorry + if (end - start < 2) + type = SEGA_EEPROM; + else + type = SEGA_SRAM_FULLPATH; + } + else + { + // Unfortunately, there are ROMs without correct info in the header, + // Hence, when loading from fullpath we do the SRAM mapping anyway... + // but treat it in a custom way + type = SEGA_SRAM_FALLBACK; + } + } + + return type; +} +/*------------------------------------------------- + get default card software + -------------------------------------------------*/ + +void base_md_cart_slot_device::get_default_card_software(std::string &result) +{ + if (open_image_file(mconfig().options())) + { + const char *slot_string = "rom"; + UINT32 len = core_fsize(m_file), offset = 0; + dynamic_buffer rom(len); + int type; + + core_fread(m_file, &rom[0], len); + + if (genesis_is_SMD(&rom[0x200], len - 0x200)) + offset = 0x200; + + type = get_cart_type(&rom[offset], len - offset); + slot_string = md_get_slot(type); + + clear(); + + result.assign(slot_string); + } + else + software_get_default_slot(result, "rom"); +} + + + +/*------------------------------------------------- + read + -------------------------------------------------*/ + +READ16_MEMBER(base_md_cart_slot_device::read) +{ + if (m_cart) + return m_cart->read(space, offset, mem_mask); + else + return 0xffff; +} + +READ16_MEMBER(base_md_cart_slot_device::read_a13) +{ + if (m_cart) + return m_cart->read_a13(space, offset, mem_mask); + else + return 0xffff; +} + +READ16_MEMBER(base_md_cart_slot_device::read_a15) +{ + if (m_cart) + return m_cart->read_a15(space, offset, mem_mask); + else + return 0xffff; +} + + +/*------------------------------------------------- + write + -------------------------------------------------*/ + +WRITE16_MEMBER(base_md_cart_slot_device::write) +{ + if (m_cart) + m_cart->write(space, offset, data, mem_mask); +} + +WRITE16_MEMBER(base_md_cart_slot_device::write_a13) +{ + if (m_cart) + m_cart->write_a13(space, offset, data, mem_mask); +} + +WRITE16_MEMBER(base_md_cart_slot_device::write_a15) +{ + if (m_cart) + m_cart->write_a15(space, offset, data, mem_mask); +} + +/*------------------------------------------------- + Image loading logging + -------------------------------------------------*/ + +void base_md_cart_slot_device::file_logging(UINT8 *ROM8, UINT32 rom_len, UINT32 nvram_len) +{ + char console[16], copyright[16], domestic_name[48], overseas_name[48]; + char serial[14], io[16], modem[12], memo[40], country[16]; + UINT32 rom_start, rom_end, ram_start, ram_end, sram_start = 0, sram_end = 0; + UINT16 checksum, csum = 0; + bool valid_sram = FALSE, is_pico = FALSE; + std::string ctrl(""), reg(""); + + // LOG FILE DETAILS + logerror("FILE DETAILS\n"); + logerror("============\n"); + logerror("Name: %s\n", basename()); + logerror("File Size: 0x%08x\n", (software_entry() == NULL) ? (int)length() : (int)get_software_region_length("rom")); + logerror("Detected type: %s\n", md_get_slot(m_type)); + logerror("ROM (Allocated) Size: 0x%X\n", rom_len); + logerror("NVRAM: %s\n", nvram_len ? "Yes" : "No"); + if (nvram_len) + logerror("NVRAM (Allocated) Size: 0x%X\n", nvram_len); + logerror("\n" ); + + + // LOG HEADER DETAILS + if (rom_len < 0x200) + return; + + for (int i = 0; i < 16; i++) + console[i] = ROM8[0x100 + (i ^ 1)]; + if (!strncmp("SEGA PICO", console, 9)) + is_pico = TRUE; + for (int i = 0; i < 16; i++) + copyright[i] = ROM8[0x110 + (i ^ 1)]; + for (int i = 0; i < 48; i++) + domestic_name[i] = ROM8[0x120 + (i ^ 1)]; + for (int i = 0; i < 48; i++) + overseas_name[i] = ROM8[0x150 + (i ^ 1)]; + for (int i = 0; i < 14; i++) + serial[i] = ROM8[0x180 + (i ^ 1)]; + + checksum = ROM8[0x18e] | (ROM8[0x18f] << 8); + + for (int i = 0; i < 16; i++) + { + io[i] = ROM8[0x190 + (i ^ 1)]; + if (io[i] == 'J') + ctrl.append(" - Joypad 3 buttons [J]\n"); + if (io[i] == '6') + ctrl.append(" - Joypad 6 buttons [6]\n"); + } + + rom_start = (ROM8[0x1a1] << 24 | ROM8[0x1a0] << 16 | ROM8[0x1a3] << 8 | ROM8[0x1a2]); + rom_end = (ROM8[0x1a5] << 24 | ROM8[0x1a4] << 16 | ROM8[0x1a7] << 8 | ROM8[0x1a6]); + ram_start = (ROM8[0x1a9] << 24 | ROM8[0x1a8] << 16 | ROM8[0x1ab] << 8 | ROM8[0x1aa]);; + ram_end = (ROM8[0x1ad] << 24 | ROM8[0x1ac] << 16 | ROM8[0x1af] << 8 | ROM8[0x1ae]);; + if (ROM8[0x1b1] == 'R' && ROM8[0x1b0] == 'A') + { + valid_sram = TRUE; + sram_start = (ROM8[0x1b5] << 24 | ROM8[0x1b4] << 16 | ROM8[0x1b7] << 8 | ROM8[0x1b6]); + sram_end = (ROM8[0x1b9] << 24 | ROM8[0x1b8] << 16 | ROM8[0x1bb] << 8 | ROM8[0x1ba]); + } + + for (int i = 0; i < 12; i++) + modem[i] = ROM8[0x1bc + (i ^ 1)]; + for (int i = 0; i < 40; i++) + memo[i] = ROM8[0x1c8 + (i ^ 1)]; + for (int i = 0; i < 16; i++) + { + country[i] = ROM8[0x1f0 + (i ^ 1)]; + if (country[i] == 'J') + reg.append(" - Japan [J]\n"); + if (country[i] == 'U') + reg.append(" - USA [U]\n"); + if (country[i] == 'E') + reg.append(" - Europe [E]\n"); + } + + // compute cart checksum to compare with expected one + for (int i = 0x200; i < (rom_end + 1) && i < rom_len; i += 2) + { + csum += (ROM8[i] | (ROM8[i + 1] << 8)); + csum &= 0xffff; + } + + logerror("INTERNAL HEADER\n"); + logerror("===============\n"); + logerror("Console: %.16s\n", console); + logerror("Copyright String: %.16s\n", copyright); + logerror(" - Manufacturer: %.4s\n", copyright + 3); // TODO: convert code to manufacturer name! + logerror(" - Date: %.8s\n", copyright + 8); + logerror("Name (domestic): %.48s\n", domestic_name); + logerror("Name (overseas): %.48s\n", overseas_name); + logerror("Serial String: %.14s\n", serial); + if (!is_pico) + { + logerror(" - Type: %.2s (%s)\n", serial, !strncmp("GM", serial, 2) ? "Game" : "Unknown"); + logerror(" - Serial Code: %.8s\n", serial + 3); + logerror(" - Revision: %.2s\n", serial + 12); + } + logerror("Checksum: %X\n", checksum); + logerror(" - Calculated Checksum: %X\n", csum); + logerror("Supported I/O Devices: %.16s\n%s", io, ctrl.c_str()); + logerror("Modem: %.12s\n", modem); + logerror("Memo: %.40s\n", memo); + logerror("Country: %.16s\n%s", country, reg.c_str()); + logerror("ROM Start: 0x%.8X\n", rom_start); + logerror("ROM End: 0x%.8X\n", rom_end); + logerror("RAM Start: 0x%.8X\n", ram_start); + logerror("RAM End: 0x%.8X\n", ram_end); + logerror("SRAM detected from header: %s\n", valid_sram ? "Yes" : "No"); + if (valid_sram) + { + logerror("SRAM Start: 0x%.8X\n", sram_start); + logerror("SRAM End: 0x%.8X\n", sram_end); + } +} diff --git a/src/devices/bus/megadrive/md_slot.h b/src/devices/bus/megadrive/md_slot.h new file mode 100644 index 00000000000..e7cf7e43c3b --- /dev/null +++ b/src/devices/bus/megadrive/md_slot.h @@ -0,0 +1,262 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __MD_SLOT_H +#define __MD_SLOT_H + +/*************************************************************************** + TYPE DEFINITIONS + ***************************************************************************/ + +#define MD_ADDR(a) (rom_bank_map[((a << 1) / 0x10000) & 0x3f] * 0x10000 + ((a << 1) & 0xffff))/2 + +/* PCB */ +enum +{ + SEGA_STD = 0, + + // Cart + Slot Expansion + SEGA_SK, /* Sonic & Knuckles pass-through cart */ + + // Cart + SVP + SEGA_SVP, /* Virtua Racing */ + + // Cart + NVRAM + SEGA_SRAM, SEGA_FRAM, + HARDBALL95, /* Hardball 95 uses different sram start address */ + XINQIG, /* Xin Qigai Wangzi uses different sram start address and has no valid header */ + BEGGARP, /* Beggar Prince uses different sram start address + bankswitch tricks */ + WUKONG, /* Legend of Wukong uses different sram start address + bankswitch trick for last 128K of ROM */ + + // EEPROM + SEGA_EEPROM, /* Wonder Boy V / Evander Holyfield's Boxing / Greatest Heavyweights of the Ring / Sports Talk Baseball / Megaman */ + NBA_JAM, /* NBA Jam */ + NBA_JAM_TE, /* NBA Jam TE / NFL Quarterback Club */ + NFL_QB_96, /* NFL Quarterback Club '96 */ + C_SLAM, /* College Slam / Frank Thomas Big Hurt Baseball */ + EA_NHLPA, /* NHLPA Hockey 93 / Rings of Power */ + BRIAN_LARA, /* Brian Lara Cricket 96 */ + PSOLAR, /* Pier Solar (STM95 EEPROM) */ + + // J-Cart + CM_JCART, /* Pete Sampras Tennis */ + CODE_MASTERS, /* Micro Machines 2 / Military (J-Cart + SEPROM) */ + CM_MM96, /* Micro Machines 96 (J-Cart + SEPROM, diff I2C model) */ + + // Various + SSF2, /* Super Street Fighter 2 */ + CM_2IN1, /* CodeMasters 2in1 : Psycho Pinball + Micro Machines */ + GAME_KANDUME, /* Game no Kandume Otokuyou */ + RADICA, /* Radica TV games.. these probably should be a separate driver since they are a separate 'console' */ + + TILESMJ2, /* 16 Mahjong Tiles II */ + BUGSLIFE, /* A Bug's Life */ + CHINFIGHT3, /* Chinese Fighters 3 */ + ELFWOR, /* Linghuan Daoshi Super Magician */ + KAIJU, /* Pokemon Stadium */ + KOF98, /* King of Fighters '98 */ + KOF99, /* King of Fighters '99 */ + LIONK2, /* Lion King 2 */ + LIONK3, /* Lion King 3, Super Donkey Kong 99, Super King Kong 99 */ + MC_PIRATE, /* Super 19 in 1, Super 15 in 1, 12 in 1 and a few more multicarts */ + MJLOVER, /* Mahjong Lover */ + POKEMONA, /* Pocket Monster Alt Protection */ + REALTEC, /* Whac a Critter/Mallet legend, Defend the Earth, Funnyworld/Ballonboy */ + REDCLIFF, /* Romance of the Three Kingdoms - Battle of Red Cliffs, already decoded from .mdx format */ + REDCL_EN, /* The encoded version... */ + ROCKMANX3, /* Rockman X3 */ + SBUBBOB, /* Super Bubble Bobble */ + SMB, /* Super Mario Bros. */ + SMB2, /* Super Mario Bros. 2 */ + SMW64, /* Super Mario World 64 */ + SMOUSE, /* Smart Mouse */ + SOULBLAD, /* Soul Blade */ + SQUIRRELK, /* Squirrel King */ + TEKKENSP, /* Tekken Special */ + TOPFIGHTER, /* Top Fighter 2000 MK VIII */ + + // when loading from fullpath, we need to treat SRAM in custom way + SEGA_SRAM_FULLPATH, + SEGA_SRAM_FALLBACK +}; + + +// ======================> device_md_cart_interface + +class device_md_cart_interface : public device_slot_card_interface +{ +public: + // construction/destruction + device_md_cart_interface(const machine_config &mconfig, device_t &device); + virtual ~device_md_cart_interface(); + + // reading and writing + virtual DECLARE_READ16_MEMBER(read) { return 0xffff; } + virtual DECLARE_WRITE16_MEMBER(write) {} + virtual DECLARE_READ16_MEMBER(read_a13) { return 0xffff; } + virtual DECLARE_WRITE16_MEMBER(write_a13) {} + virtual DECLARE_READ16_MEMBER(read_a15) { return 0xffff; } + virtual DECLARE_WRITE16_MEMBER(write_a15) {} + + virtual int read_test() { return 0; } // used by Virtua Racing test + + /* this probably should do more, like make Genesis V2 'die' if the SEGA string is not written promptly */ + virtual DECLARE_WRITE16_MEMBER(write_tmss_bank) { logerror("Write to TMSS bank: offset %x data %x\n", 0xa14000 + (offset << 1), data); }; + + virtual void rom_alloc(size_t size, const char *tag); + virtual void nvram_alloc(size_t size); + virtual UINT16* get_rom_base() { return m_rom; }; + virtual UINT16* get_nvram_base() { return &m_nvram[0]; }; + virtual UINT32 get_rom_size() { return m_rom_size; }; + virtual UINT32 get_nvram_size() { return m_nvram.size()*sizeof(UINT16); }; + virtual void set_bank_to_rom(const char *banktag, UINT32 offset) {}; + + void save_nvram() { device().save_item(NAME(m_nvram)); } + + void rom_map_setup(UINT32 size); + UINT32 get_padded_size(UINT32 size); + + int m_nvram_start, m_nvram_end; + int m_nvram_active, m_nvram_readonly; + + // when loading from fullpath, we create NVRAM even if not set in the header + // however in this case we access it only if the game turn it on + // the variable below is basically needed to track this... + int m_nvram_handlers_installed; + + // internal state + UINT16 *m_rom; + UINT32 m_rom_size; + std::vector m_nvram; + + UINT8 rom_bank_map[128]; // 64K chunks of rom +}; + + +// ======================> base_md_cart_slot_device + +class base_md_cart_slot_device : public device_t, + public device_image_interface, + public device_slot_interface +{ +public: + // construction/destruction + base_md_cart_slot_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + virtual ~base_md_cart_slot_device(); + + // device-level overrides + virtual void device_start(); + virtual void device_config_complete(); + + // image-level overrides + virtual bool call_load(); + virtual void call_unload(); + virtual bool call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry); + + virtual iodevice_t image_type() const { return IO_CARTSLOT; } + virtual bool is_readable() const { return 1; } + virtual bool is_writeable() const { return 0; } + virtual bool is_creatable() const { return 0; } + virtual bool must_be_loaded() const { return m_must_be_loaded; } + virtual bool is_reset_on_load() const { return 1; } + virtual const option_guide *create_option_guide() const { return NULL; } + + // slot interface overrides + virtual void get_default_card_software(std::string &result); + + int get_type() { return m_type; } + + int load_list(); + int load_nonlist(); + int get_cart_type(UINT8 *ROM, UINT32 len); + + void setup_custom_mappers(); + void setup_nvram(); + void set_must_be_loaded(bool _must_be_loaded) { m_must_be_loaded = _must_be_loaded; } + void file_logging(UINT8 *ROM, UINT32 rom_len, UINT32 nvram_len); + + void save_nvram() { if (m_cart && m_cart->get_nvram_size()) m_cart->save_nvram(); } + + // reading and writing + virtual DECLARE_READ16_MEMBER(read); + virtual DECLARE_WRITE16_MEMBER(write); + virtual DECLARE_READ16_MEMBER(read_a13); + virtual DECLARE_WRITE16_MEMBER(write_a13); + virtual DECLARE_READ16_MEMBER(read_a15); + virtual DECLARE_WRITE16_MEMBER(write_a15); + virtual DECLARE_WRITE16_MEMBER(write_tmss_bank) { if (m_cart) m_cart->write_tmss_bank(space, offset, data, mem_mask); }; + + virtual int read_test() { if (m_cart) return m_cart->read_test(); else return 0; } // used by Virtua Racing test + +// TODO: this only needs to be public because megasvp copies rom into memory region, so we need to rework that code... +//private: + + int m_type; + device_md_cart_interface* m_cart; + bool m_must_be_loaded; +}; + +// ======================> md_cart_slot_device + +class md_cart_slot_device : public base_md_cart_slot_device +{ +public: + // construction/destruction + md_cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual const char *image_interface() const { return "megadriv_cart"; } + virtual const char *file_extensions() const { return "smd,bin,md,gen"; } +}; + +// ======================> pico_cart_slot_device + +class pico_cart_slot_device : public base_md_cart_slot_device +{ +public: + // construction/destruction + pico_cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual const char *image_interface() const { return "pico_cart"; } + virtual const char *file_extensions() const { return "bin,md"; } +}; + +// ======================> copera_cart_slot_device + +class copera_cart_slot_device : public base_md_cart_slot_device +{ +public: + // construction/destruction + copera_cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual const char *image_interface() const { return "copera_cart"; } + virtual const char *file_extensions() const { return "bin,md"; } +}; + + +// device type definition +extern const device_type MD_CART_SLOT; +extern const device_type PICO_CART_SLOT; +extern const device_type COPERA_CART_SLOT; + + +/*************************************************************************** + DEVICE CONFIGURATION MACROS + ***************************************************************************/ + +#define MDSLOT_ROM_REGION_TAG ":cart:rom" + +#define MCFG_MD_CARTRIDGE_ADD(_tag,_slot_intf,_def_slot) \ + MCFG_DEVICE_ADD(_tag, MD_CART_SLOT, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) + +#define MCFG_PICO_CARTRIDGE_ADD(_tag,_slot_intf,_def_slot) \ + MCFG_DEVICE_ADD(_tag, PICO_CART_SLOT, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) + +#define MCFG_COPERA_CARTRIDGE_ADD(_tag,_slot_intf,_def_slot) \ + MCFG_DEVICE_ADD(_tag, COPERA_CART_SLOT, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) + + + +#define MCFG_MD_CARTRIDGE_NOT_MANDATORY \ + static_cast(device)->set_must_be_loaded(FALSE); + + +#endif diff --git a/src/devices/bus/megadrive/rom.c b/src/devices/bus/megadrive/rom.c new file mode 100644 index 00000000000..bc81477cc09 --- /dev/null +++ b/src/devices/bus/megadrive/rom.c @@ -0,0 +1,1422 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + MegaDrive / Genesis cart emulation + + + Here we emulate bankswitch / protection / NVRAM found on generic carts with no additional hardware + + + Emulation of the pirate carts is heavily indebted to the reverse engineering efforts made + by David Haywood (for HazeMD) and by EkeEke (for genplus-gx) + + ***********************************************************************************************************/ + +#include "emu.h" +#include "rom.h" +#include "cpu/m68000/m68000.h" + + +//------------------------------------------------- +// md_rom_device - constructor +//------------------------------------------------- + +// BASE CARTS + NVRAM +const device_type MD_STD_ROM = &device_creator; +const device_type MD_ROM_SRAM = &device_creator; +const device_type MD_ROM_FRAM = &device_creator; + +// BASE CARTS + BANKSWITCH AT RESET +const device_type MD_ROM_CM2IN1 = &device_creator; + +// BASE CARTS + PROTECTION / BANKSWITCH +const device_type MD_ROM_SSF2 = &device_creator; +const device_type MD_ROM_BUGSLIFE = &device_creator; +const device_type MD_ROM_SMOUSE = &device_creator; +const device_type MD_ROM_SMW64 = &device_creator; +const device_type MD_ROM_SMB = &device_creator; +const device_type MD_ROM_SMB2 = &device_creator; +const device_type MD_ROM_SBUBL = &device_creator; +const device_type MD_ROM_RX3 = &device_creator; +const device_type MD_ROM_MJLOV = &device_creator; +const device_type MD_ROM_KOF98 = &device_creator; +const device_type MD_ROM_KOF99 = &device_creator; +const device_type MD_ROM_SOULB = &device_creator; +const device_type MD_ROM_CHINF3 = &device_creator; +const device_type MD_ROM_16MJ2 = &device_creator; +const device_type MD_ROM_ELFWOR = &device_creator; +const device_type MD_ROM_YASECH = &device_creator; +const device_type MD_ROM_LION2 = &device_creator; +const device_type MD_ROM_LION3 = &device_creator; +const device_type MD_ROM_MCPIR = &device_creator; +const device_type MD_ROM_POKEA = &device_creator; +const device_type MD_ROM_POKESTAD = &device_creator; +const device_type MD_ROM_REALTEC = &device_creator; +const device_type MD_ROM_REDCL = &device_creator; +const device_type MD_ROM_SQUIR = &device_creator; +const device_type MD_ROM_TEKKENSP = &device_creator; +const device_type MD_ROM_TOPF = &device_creator; +const device_type MD_ROM_RADICA = &device_creator; +const device_type MD_ROM_BEGGARP = &device_creator; +const device_type MD_ROM_WUKONG = &device_creator; + + +md_std_rom_device::md_std_rom_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_md_cart_interface( mconfig, *this ) +{ +} + +md_std_rom_device::md_std_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, MD_STD_ROM, "MD Standard cart", tag, owner, clock, "md_std_rom", __FILE__), + device_md_cart_interface( mconfig, *this ) +{ +} + +md_rom_sram_device::md_rom_sram_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : md_std_rom_device(mconfig, MD_ROM_SRAM, "MD Standard cart + SRAM", tag, owner, clock, "md_rom_sram", __FILE__) +{ +} + +md_rom_fram_device::md_rom_fram_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : md_std_rom_device(mconfig, MD_ROM_FRAM, "MD Standard cart + FRAM", tag, owner, clock, "md_rom_fram", __FILE__) +{ +} + +md_rom_ssf2_device::md_rom_ssf2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : md_std_rom_device(mconfig, MD_ROM_SSF2, "MD Super SF2", tag, owner, clock, "md_rom_ssf2", __FILE__) +{ +} + +md_rom_cm2in1_device::md_rom_cm2in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : md_std_rom_device(mconfig, MD_ROM_CM2IN1, "MD Codemasters 2in1", tag, owner, clock, "md_rom_cm2in1", __FILE__) +{ +} + +md_rom_mcpirate_device::md_rom_mcpirate_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : md_std_rom_device(mconfig, MD_ROM_MCPIR, "MD Pirate Multicarts (Various)", tag, owner, clock, "md_rom_mcpirate", __FILE__) +{ +} + +md_rom_bugslife_device::md_rom_bugslife_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : md_std_rom_device(mconfig, MD_ROM_BUGSLIFE, "MD A Bug's Life", tag, owner, clock, "md_rom_bugslife", __FILE__) +{ +} + +md_rom_smouse_device::md_rom_smouse_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : md_std_rom_device(mconfig, MD_ROM_SMOUSE, "MD Huan Le Tao Qi Shu / Smart Mouse", tag, owner, clock, "md_rom_smouse", __FILE__) +{ +} + +md_rom_smb_device::md_rom_smb_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : md_std_rom_device(mconfig, MD_ROM_SMB, "MD Super Mario Bros.", tag, owner, clock, "md_rom_smb", __FILE__) +{ +} + +md_rom_smb2_device::md_rom_smb2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : md_std_rom_device(mconfig, MD_ROM_SMB2, "MD Super Mario Bros. 2", tag, owner, clock, "md_rom_smb2", __FILE__) +{ +} + +md_rom_smw64_device::md_rom_smw64_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : md_std_rom_device(mconfig, MD_ROM_SMW64, "MD Super Mario World 64", tag, owner, clock, "md_rom_smw64", __FILE__) +{ +} + +md_rom_sbubl_device::md_rom_sbubl_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : md_std_rom_device(mconfig, MD_ROM_SBUBL, "MD Super Bubble Bobble", tag, owner, clock, "md_rom_sbubl", __FILE__) +{ +} + +md_rom_rx3_device::md_rom_rx3_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : md_std_rom_device(mconfig, MD_ROM_RX3, "MD Rockman X3", tag, owner, clock, "md_rom_rx3", __FILE__) +{ +} + +md_rom_mjlov_device::md_rom_mjlov_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : md_std_rom_device(mconfig, MD_ROM_MJLOV, "MD Ma Jiang Qing Ren / Mahjong Lover", tag, owner, clock, "md_rom_mjlov", __FILE__) +{ +} + +md_rom_kof98_device::md_rom_kof98_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : md_std_rom_device(mconfig, MD_ROM_KOF98, "MD KOF 98", tag, owner, clock, "md_rom_kof98", __FILE__) +{ +} + +md_rom_kof99_device::md_rom_kof99_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : md_std_rom_device(mconfig, MD_ROM_KOF99, "MD KOF 99 (and others)", tag, owner, clock, "md_rom_kof99", __FILE__) +{ +} + +md_rom_soulb_device::md_rom_soulb_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : md_std_rom_device(mconfig, MD_ROM_SOULB, "MD Soul Blade", tag, owner, clock, "md_rom_soulb", __FILE__) +{ +} + +md_rom_chinf3_device::md_rom_chinf3_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : md_std_rom_device(mconfig, MD_ROM_CHINF3, "MD Chinese Fighter 3", tag, owner, clock, "md_rom_chinf3", __FILE__) +{ +} + +md_rom_16mj2_device::md_rom_16mj2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : md_std_rom_device(mconfig, MD_ROM_16MJ2, "MD 16 Mahjong Tiles II", tag, owner, clock, "md_rom_16mj2", __FILE__) +{ +} + +md_rom_elfwor_device::md_rom_elfwor_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : md_std_rom_device(mconfig, MD_ROM_ELFWOR, "MD Linghuan Daoshi Super Magician / Elf Wor", tag, owner, clock, "md_rom_elfwor", __FILE__) +{ +} + +md_rom_yasech_device::md_rom_yasech_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : md_std_rom_device(mconfig, MD_ROM_YASECH, "MD Ya Se Chuan Shuo", tag, owner, clock, "md_rom_yasech", __FILE__) +{ +} + +md_rom_lion2_device::md_rom_lion2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : md_std_rom_device(mconfig, MD_ROM_LION2, "MD Lion King 2", tag, owner, clock, "md_rom_lion2", __FILE__) +{ +} + +md_rom_lion3_device::md_rom_lion3_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : md_std_rom_device(mconfig, MD_ROM_LION3, "MD Lion King 3", tag, owner, clock, "md_rom_lion3", __FILE__) +{ +} + +md_rom_pokea_device::md_rom_pokea_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : md_std_rom_device(mconfig, MD_ROM_POKEA, "MD Pokemon (Alt Protection)", tag, owner, clock, "md_rom_pokea", __FILE__) +{ +} + +md_rom_pokestad_device::md_rom_pokestad_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : md_std_rom_device(mconfig, MD_ROM_POKESTAD, "MD Pokemon Stadium", tag, owner, clock, "md_rom_pokestad", __FILE__) +{ +} + +md_rom_realtec_device::md_rom_realtec_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : md_std_rom_device(mconfig, MD_ROM_REALTEC, "MD Realtec", tag, owner, clock, "md_rom_realtec", __FILE__) +{ +} + +md_rom_redcl_device::md_rom_redcl_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : md_std_rom_device(mconfig, MD_ROM_REDCL, "MD Redcliff", tag, owner, clock, "md_rom_redcl", __FILE__) +{ +} + +md_rom_squir_device::md_rom_squir_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : md_std_rom_device(mconfig, MD_ROM_SQUIR, "MD Squirrel King", tag, owner, clock, "md_rom_squir", __FILE__) +{ +} + +md_rom_tekkensp_device::md_rom_tekkensp_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : md_std_rom_device(mconfig, MD_ROM_TEKKENSP, "MD Tekken Special", tag, owner, clock, "md_rom_tekkensp", __FILE__) +{ +} + +md_rom_topf_device::md_rom_topf_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : md_std_rom_device(mconfig, MD_ROM_TOPF, "MD Top Fighter", tag, owner, clock, "md_rom_topf", __FILE__) +{ +} + +md_rom_radica_device::md_rom_radica_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : md_std_rom_device(mconfig, MD_ROM_RADICA, "MD Radica TV games", tag, owner, clock, "md_rom_radica", __FILE__) +{ +} + +md_rom_beggarp_device::md_rom_beggarp_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : md_std_rom_device(mconfig, MD_ROM_BEGGARP, "MD Beggar Prince", tag, owner, clock, "md_rom_beggarp", __FILE__) +{ +} + +md_rom_wukong_device::md_rom_wukong_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : md_std_rom_device(mconfig, MD_ROM_WUKONG, "MD Legend of Wukong", tag, owner, clock, "md_rom_wukong", __FILE__) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void md_rom_ssf2_device::device_start() +{ + save_item(NAME(m_bank)); + save_item(NAME(m_lastoff)); + save_item(NAME(m_lastdata)); +} + +void md_rom_ssf2_device::device_reset() +{ + for (int i = 0; i < 7; i++) + m_bank[i] = i; + m_lastoff = -1; + m_lastdata = -1; +} + +void md_rom_cm2in1_device::device_start() +{ + m_base = -1; + save_item(NAME(m_base)); +} + +void md_rom_cm2in1_device::device_reset() +{ + m_base++; + m_base &= 1; +} + +void md_rom_mcpirate_device::device_start() +{ + save_item(NAME(m_bank)); +} + +void md_rom_mcpirate_device::device_reset() +{ + m_bank = 0; +} + +void md_rom_chinf3_device::device_start() +{ + m_bank = 0; + save_item(NAME(m_bank)); +} + +void md_rom_chinf3_device::device_reset() +{ +} + +void md_rom_lion2_device::device_start() +{ + save_item(NAME(m_prot1_data)); + save_item(NAME(m_prot2_data)); +} + +void md_rom_lion2_device::device_reset() +{ + m_prot1_data = 0; + m_prot2_data = 0; +} + +void md_rom_lion3_device::device_start() +{ + save_item(NAME(m_reg)); + save_item(NAME(m_bank)); +} + +void md_rom_lion3_device::device_reset() +{ + m_reg[0] = 0; + m_reg[1] = 0; + m_reg[2] = 0; + m_bank = 0; +} + +void md_rom_pokestad_device::device_start() +{ + save_item(NAME(m_bank)); +} + +void md_rom_pokestad_device::device_reset() +{ + m_bank = 0; +} + +void md_rom_realtec_device::device_start() +{ + save_item(NAME(m_bank_addr)); + save_item(NAME(m_bank_size)); + save_item(NAME(m_old_bank_addr)); +} + +void md_rom_realtec_device::device_reset() +{ + m_bank_addr = 0; + m_bank_size = 0; + m_old_bank_addr = -1; +} + +void md_rom_squir_device::device_start() +{ + save_item(NAME(m_latch)); +} + +void md_rom_squir_device::device_reset() +{ + m_latch = 0; +} + +void md_rom_smw64_device::device_start() +{ + save_item(NAME(m_latch0)); + save_item(NAME(m_latch1)); + save_item(NAME(m_reg)); + save_item(NAME(m_ctrl)); +} + +void md_rom_smw64_device::device_reset() +{ + m_latch0 = 0xf; + m_latch1 = 0xf; + memset(m_reg, 0, sizeof(m_reg)); + memset(m_ctrl, 0, sizeof(m_ctrl)); +} + +void md_rom_tekkensp_device::device_start() +{ + save_item(NAME(m_reg)); +} + +void md_rom_tekkensp_device::device_reset() +{ + m_reg = 0; +} + +void md_rom_topf_device::device_start() +{ + save_item(NAME(m_latch)); + save_item(NAME(m_bank)); +} + +void md_rom_topf_device::device_reset() +{ + m_latch = 0; + m_bank[0] = m_bank[1] = m_bank[2] = 0; +} + +void md_rom_radica_device::device_start() +{ + save_item(NAME(m_bank)); +} + +void md_rom_radica_device::device_reset() +{ + m_bank = 0; +} + +void md_rom_beggarp_device::device_start() +{ + save_item(NAME(m_mode)); + save_item(NAME(m_lock)); +} + +void md_rom_beggarp_device::device_reset() +{ + m_mode = 0; + m_lock = 0; +} + +void md_rom_wukong_device::device_start() +{ + save_item(NAME(m_mode)); +} + +void md_rom_wukong_device::device_reset() +{ + m_mode = 0; +} + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +/*------------------------------------------------- + CART + SRAM + -------------------------------------------------*/ + +READ16_MEMBER(md_rom_sram_device::read) +{ + // since a lot of generic carts ends up here if loaded from fullpath + // we access nvram only if m_nvram_handlers_installed has been turned on + if (m_nvram_handlers_installed) + { + if (offset >= m_nvram_start/2 && offset <= m_nvram_end/2 && m_nvram_active) + return m_nvram[offset - m_nvram_start/2]; + } + if (offset < 0x400000/2) + return m_rom[MD_ADDR(offset)]; + else + return 0xffff; +} + +WRITE16_MEMBER(md_rom_sram_device::write) +{ + // since a lot of generic carts ends up here if loaded from fullpath + // we access nvram only if m_nvram_handlers_installed has been turned on + if (m_nvram_handlers_installed) + { + if (offset >= m_nvram_start/2 && offset <= m_nvram_end/2 && m_nvram_active && !m_nvram_readonly) + m_nvram[offset - m_nvram_start/2] = data; + } +} + +WRITE16_MEMBER(md_rom_sram_device::write_a13) +{ + if (offset == 0xf0/2) + { + /* unsure if this is actually supposed to toggle or just switch on? yet to encounter game that uses this */ + m_nvram_active = BIT(data, 0); + m_nvram_readonly = BIT(data, 1); + + // since a lot of generic carts ends up here if loaded from fullpath + // we turn on nvram (with m_nvram_handlers_installed) only if they toggle it on by writing here! + if (m_nvram_active && !m_nvram_handlers_installed) + m_nvram_handlers_installed = 1; + } +} + +/*------------------------------------------------- + CART + FRAM [almost same as SRAM... merge common parts?] + -------------------------------------------------*/ + +READ16_MEMBER(md_rom_fram_device::read) +{ + if (offset >= m_nvram_start/2 && offset <= m_nvram_end/2 && m_nvram_active) + return m_nvram[offset - m_nvram_start/2]; + if (offset < 0x400000/2) + return m_rom[MD_ADDR(offset)]; + else + return 0xffff; +} + +WRITE16_MEMBER(md_rom_fram_device::write) +{ + if (offset >= m_nvram_start/2 && offset <= m_nvram_end/2 && m_nvram_active) + m_nvram[offset - m_nvram_start/2] = data; +} + +WRITE16_MEMBER(md_rom_fram_device::write_a13) +{ + if (offset == 0xf0/2) + m_nvram_active = BIT(data, 0); +} + + +READ16_MEMBER(md_rom_fram_device::read_a13) +{ + if (offset == 0xf0/2) + return m_nvram_active; + else + return 0xffff; +} + +/*------------------------------------------------- + SUPER STREET FIGHTERS 2 + -------------------------------------------------*/ + +READ16_MEMBER(md_rom_ssf2_device::read) +{ + if (offset < 0x400000/2) + return m_rom[offset]; + else + return 0xffff; +} + +// I'm not very fond of the code below... +WRITE16_MEMBER(md_rom_ssf2_device::write_a13) +{ + if (offset >= 0xf0/2) + { + offset -= 0xf0/2; + if ((m_lastoff != offset) || (m_lastdata != data)) + { + m_lastoff = offset; + m_lastdata = data; + if (offset) // bank 0 is not modified + { + UINT16 *ROM = get_rom_base(); + m_bank[offset] = data & 0xf; + memcpy(ROM + offset * 0x080000/2, ROM + 0x400000/2 + (m_bank[offset] * 0x080000)/2, 0x080000); + } + } + } +} + +/*------------------------------------------------- + CODEMASTERS 2 IN 1 (RESET BASED) + -------------------------------------------------*/ + +#define MD_ADDR_CM2IN1(a) (m_base == 0 ? ((a << 1) & 0x1fffff)/2 : (((a << 1) & 0x1fffff) + 0x200000)/2) + +READ16_MEMBER(md_rom_cm2in1_device::read) +{ + if (offset < 0x400000/2) + return m_rom[MD_ADDR_CM2IN1(offset)]; + else + return 0xffff; +} + + +/*------------------------------------------------- + PIRATE MULTICARTS + -------------------------------------------------*/ + +READ16_MEMBER(md_rom_mcpirate_device::read) +{ + if (offset < 0x400000/2) + return m_rom[(((m_bank * 0x10000) + (offset << 1)) & (m_rom_size - 1))/2]; + else + return read(space, offset - 0x400000/2, 0xffff); +} + +WRITE16_MEMBER(md_rom_mcpirate_device::write_a13) +{ + offset <<= 1; + if (offset < 0x40) + m_bank = offset; +} + +/*------------------------------------------------- + A BUG'S LIFE + -------------------------------------------------*/ + +READ16_MEMBER(md_rom_bugslife_device::read_a13) +{ + if (offset == 0x00/2) return 0x28; + if (offset == 0x02/2) return 0x01; + if (offset == 0x3e/2) return 0x1f; + else return 0xffff; +} + +/*------------------------------------------------- + CHINESE FIGHTER 3 + -------------------------------------------------*/ + +READ16_MEMBER(md_rom_chinf3_device::read) +{ + if (offset < 0x100000/2) + { + if (!m_bank) + return m_rom[offset & 0xfffff/2]; + else + return m_rom[(offset & 0xffff/2) + (m_bank * 0x10000)/2]; + } + + // PROTECTION in 0x400000 - 0x4fffff + /* not 100% correct, there may be some relationship between the reads here + and the writes made at the start of the game.. */ + if (offset >= 0x400000/2 && offset < 0x500000/2) + { + UINT32 retdat = 0; + /* + 04dc10 chifi3, prot_r? 2800 + 04cefa chifi3, prot_r? 65262 + */ + if (space.machine().device("maincpu")->safe_pc() == 0x01782) // makes 'VS' screen appear + { + retdat = space.machine().device("maincpu")->state().state_int(M68K_D3) & 0xff; + retdat <<= 8; + return retdat; + } + else if (space.machine().device("maincpu")->safe_pc() == 0x1c24) // background gfx etc. + { + retdat = space.machine().device("maincpu")->state().state_int(M68K_D3) & 0xff; + retdat <<= 8; + return retdat; + } + else if (space.machine().device("maincpu")->safe_pc() == 0x10c4a) // unknown + { + return space.machine().rand(); + } + else if (space.machine().device("maincpu")->safe_pc() == 0x10c50) // unknown + { + return space.machine().rand(); + } + else if (space.machine().device("maincpu")->safe_pc() == 0x10c52) // relates to the game speed.. + { + retdat = space.machine().device("maincpu")->state().state_int(M68K_D4) & 0xff; + retdat <<= 8; + return retdat; + } + else if (space.machine().device("maincpu")->safe_pc() == 0x061ae) + { + retdat = space.machine().device("maincpu")->state().state_int(M68K_D3) & 0xff; + retdat <<= 8; + return retdat; + } + else if (space.machine().device("maincpu")->safe_pc() == 0x061b0) + { + retdat = space.machine().device("maincpu")->state().state_int(M68K_D3) & 0xff; + retdat <<= 8; + return retdat; + } + else + { + logerror("%06x chifi3, prot_r? %04x\n", space.machine().device("maincpu")->safe_pc(), offset); + } + return 0; + } + + // non-protection accesses + if (offset < 0x400000/2) + return m_rom[MD_ADDR(offset)]; + else + return 0xffff; +} + +WRITE16_MEMBER(md_rom_chinf3_device::write) +{ + if (offset >= 0x600000/2 && offset < 0x700000/2) + { + if (data == 0xf100) // *hit player + m_bank = 1; + else if (data == 0xd700) // title screen.. + m_bank = 7; + else if (data == 0xd300) // character hits floor + m_bank = 3; + else if (data == 0x0000) + m_bank = 0; + else + logerror("%06x chifi3, bankw? %04x %04x\n", space.device().safe_pc(), offset, data); + } +} + +/*------------------------------------------------- + 16 MAHJONG II + -------------------------------------------------*/ + +READ16_MEMBER(md_rom_16mj2_device::read) +{ + if (offset == 0x400004/2) return 0xc900; + + // non-protection accesses + if (offset < 0x400000/2) + return m_rom[MD_ADDR(offset)]; + else + return 0xffff; +} + +/*------------------------------------------------- + LINGHUAN DAOSHI SUPER MAGICIAN / ELF WOR + -------------------------------------------------*/ + +READ16_MEMBER(md_rom_elfwor_device::read) +{ + // It returns (0x55 @ 0x400000 OR 0xc9 @ 0x400004) AND (0x0f @ 0x400002 OR 0x18 @ 0x400006). + // It is probably best to add handlers for all 4 addresses + if (offset == 0x400000/2) return 0x5500; + if (offset == 0x400002/2) return 0x0f00; + if (offset == 0x400004/2) return 0xc900; + if (offset == 0x400006/2) return 0x1800; + + // non-protection accesses + if (offset < 0x400000/2) + return m_rom[MD_ADDR(offset)]; + else + return 0xffff; +} + +/*------------------------------------------------- + HUAN LE TAO QI SHU / SMART MOUSE + -------------------------------------------------*/ + +READ16_MEMBER(md_rom_smouse_device::read) +{ + if (offset == 0x400000/2) return 0x5500; + if (offset == 0x400002/2) return 0x0f00; + if (offset == 0x400004/2) return 0xaa00; + if (offset == 0x400006/2) return 0xf000; + + // non-protection accesses + if (offset < 0x400000/2) + return m_rom[MD_ADDR(offset)]; + else + return 0xffff; +} + +/*------------------------------------------------- + YA SE CHUAN SHUO + -------------------------------------------------*/ + +READ16_MEMBER(md_rom_yasech_device::read) +{ + if (offset == 0x400000/2) return 0x6300; + if (offset == 0x400002/2) return 0x9800; + if (offset == 0x400004/2) return 0xc900; + if (offset == 0x400006/2) return 0x1800; + + // non-protection accesses + if (offset < 0x400000/2) + return m_rom[MD_ADDR(offset)]; + else + return 0xffff; +} + +/*------------------------------------------------- + KOF98 + -------------------------------------------------*/ + +READ16_MEMBER(md_rom_kof98_device::read) +{ + if (offset == 0x480000/2) return 0xaa00; + if (offset == 0x4800e0/2) return 0xaa00; + if (offset == 0x4824a0/2) return 0xaa00; + if (offset == 0x488880/2) return 0xaa00; + if (offset == 0x4a8820/2) return 0x0a00; + if (offset == 0x4f8820/2) return 0x0000; + + // non-protection accesses + if (offset < 0x400000/2) + return m_rom[MD_ADDR(offset)]; + else + return 0xffff; +} + +/*------------------------------------------------- + KOF 99 + -------------------------------------------------*/ + +READ16_MEMBER(md_rom_kof99_device::read_a13) +{ + if (offset == 0x00/2) return 0x00; // startup protection check, chinese message if != 0 + if (offset == 0x02/2) return 0x01; // write 02 to a13002.. shift right 1? + if (offset == 0x3e/2) return 0x1f; // write 3e to a1303e.. shift right 1? + else return 0xffff; +} + +/*------------------------------------------------- + LION KING 2 + -------------------------------------------------*/ + +READ16_MEMBER(md_rom_lion2_device::read) +{ + if (offset == 0x400002/2) return m_prot1_data; + if (offset == 0x400006/2) return m_prot2_data; + + // non-protection accesses + if (offset < 0x400000/2) + return m_rom[MD_ADDR(offset)]; + else + return 0xffff; +} + +WRITE16_MEMBER(md_rom_lion2_device::write) +{ + if (offset == 0x400000/2) m_prot1_data = data; + if (offset == 0x400004/2) m_prot2_data = data; +} + +/*------------------------------------------------- + LION KING 3 + -------------------------------------------------*/ + +#define MD_LION3_ADDR(a) (((offset << 1) | (m_bank << 15)) & (m_rom_size - 1))/2 + +READ16_MEMBER(md_rom_lion3_device::read) +{ + if (offset < 0x100000/2) + return m_rom[MD_LION3_ADDR(offset)]; + else if (offset >= 0x600000/2 && offset < 0x700000/2) + { + switch (offset & 0x7) + { + case 0: + return m_reg[0]; + case 1: + return m_reg[1]; + case 2: + return m_reg[2]; + default: + logerror("protection read, unknown offset %x\n", offset & 0x7); + break; + } + return 0; + } + + if (offset < 0x400000/2) + return m_rom[MD_ADDR(offset)]; + else + return 0xffff; +} + +WRITE16_MEMBER(md_rom_lion3_device::write) +{ + if (offset >= 0x600000/2 && offset < 0x700000/2) + { +// printf("protection write, offset %d data %d\n", offset & 0x7, data); + switch (offset & 0x7) + { + case 0x0: + m_reg[0] = data & 0xff; + break; + case 0x1: + m_reg[1] = data & 0xff; + break; + default: + logerror("protection write, unknown offset %d\n", offset & 0x7); + break; + } + + // update m_reg[2] + switch (m_reg[1] & 3) + { + case 0x0: + m_reg[2] = (m_reg[0] << 1); + break; + case 0x1: + m_reg[2] = (m_reg[0] >> 1); + break; + case 0x2: + m_reg[2] = (m_reg[0] >> 4) | ((m_reg[0] & 0x0f) << 4); + break; + case 0x3: + default: + m_reg[2] = (BIT(m_reg[0], 7) << 0) + | (BIT(m_reg[0], 6) << 1) + | (BIT(m_reg[0], 5) << 2) + | (BIT(m_reg[0], 4) << 3) + | (BIT(m_reg[0], 3) << 4) + | (BIT(m_reg[0], 2) << 5) + | (BIT(m_reg[0], 1) << 6) + | (BIT(m_reg[0], 0) << 7); + break; + } + + } + if (offset >= 0x700000/2) + m_bank = data & 0xff; +} + +/*------------------------------------------------- + MA JIANG QING REN / MAHJONG LOVER + -------------------------------------------------*/ + +READ16_MEMBER(md_rom_mjlov_device::read) +{ + if (offset == 0x400000/2) return 0x9000; + if (offset == 0x401000/2) return 0xd300; + + // non-protection accesses + if (offset < 0x400000/2) + return m_rom[MD_ADDR(offset)]; + else + return 0xffff; +} + + +/*------------------------------------------------- + SUPER BUBBLE BOBBLE MD + -------------------------------------------------*/ + +READ16_MEMBER(md_rom_sbubl_device::read) +{ + if (offset == 0x400000/2) return 0x5500; + if (offset == 0x400002/2) return 0x0f00; + + // non-protection accesses + if (offset < 0x400000/2) + return m_rom[MD_ADDR(offset)]; + else + return 0xffff; +} + +/*------------------------------------------------- + SOUL BLADE + -------------------------------------------------*/ + +READ16_MEMBER(md_rom_soulb_device::read) +{ + if (offset == 0x400002/2) return 0x9800; + if (offset == 0x400004/2) return 0xc900; + if (offset == 0x400006/2) return 0xf000; + + // non-protection accesses + if (offset < 0x400000/2) + return m_rom[MD_ADDR(offset)]; + else + return 0xffff; +} + +/*------------------------------------------------- + POKEMON STADIUM / KAIJU + -------------------------------------------------*/ + +#define MD_POKESTAD_ADDR(a) (((offset << 1) | (m_bank << 15)) & (m_rom_size - 1))/2 + +READ16_MEMBER(md_rom_pokestad_device::read) +{ + if (offset < 0x100000/2) + return m_rom[MD_POKESTAD_ADDR(offset)]; + + // non-protection accesses + if (offset < 0x400000/2) + return m_rom[MD_ADDR(offset)]; + else + return 0xffff; +} + +WRITE16_MEMBER(md_rom_pokestad_device::write) +{ + if (offset >= 0x700000/2 && offset < 0x800000/2) + m_bank = data & 0x7f; +} + +/*------------------------------------------------- + POKEMON ALT + -------------------------------------------------*/ + +READ16_MEMBER(md_rom_pokea_device::read_a13) +{ + if (offset == 0x00/2) return 0x14; + if (offset == 0x02/2) return 0x01; + if (offset == 0x3e/2) return 0x1f; + else return 0xffff; +} + +/*------------------------------------------------- + REALTEC + -------------------------------------------------*/ + +READ16_MEMBER(md_rom_realtec_device::read) +{ + if (offset < (m_bank_size * 0x20000)) // two banks of same (variable) size at the bottom of the rom + return m_rom[MD_ADDR((offset + (m_bank_addr * 0x20000)/2))]; + return m_rom[MD_ADDR(((offset & 0x1fff/2) + 0x7e000/2))]; // otherwise it accesses the final 8k of the image +} + +WRITE16_MEMBER(md_rom_realtec_device::write) +{ + if (offset == 0x400000/2) + { + m_old_bank_addr = m_bank_addr; + m_bank_addr = (m_bank_addr & 0x7) | ((data >> 9) & 0x7) << 3; + } + if (offset == 0x402000/2) + { + m_bank_addr = 0; + m_bank_size = (data >> 8) & 0x1f; + } + if (offset == 0x404000/2) + { + m_old_bank_addr = m_bank_addr; + m_bank_addr = (m_bank_addr & 0xf8) | ((data >> 8) & 0x3); + } +} + +/*------------------------------------------------- + RED CLIFF + -------------------------------------------------*/ + +READ16_MEMBER(md_rom_redcl_device::read) +{ + if (offset == 0x400000/2) return 0x55 << 8; + if (offset == 0x400004/2) return -0x56 << 8; + + // non-protection accesses + if (offset < 0x400000/2) + return m_rom[MD_ADDR(offset)]; + else + return 0xffff; +} + +/*------------------------------------------------- + ROCKMAN X3 + -------------------------------------------------*/ + +READ16_MEMBER(md_rom_rx3_device::read_a13) +{ + if (offset == 0) + return 0x0c; + else + return 0xffff; +} + +/*------------------------------------------------- + SQUIRREL KING + -------------------------------------------------*/ + +READ16_MEMBER(md_rom_squir_device::read) +{ + if ((offset >= 0x400000/2) && (offset < 0x400008/2)) + return m_latch; + + // non-protection accesses + if (offset < 0x400000/2) + return m_rom[MD_ADDR(offset)]; + else + return 0xffff; +} + +WRITE16_MEMBER(md_rom_squir_device::write) +{ + if (offset >= 0x400000/2 && offset < 0x400008/2) + m_latch = data; +} + +/*------------------------------------------------- + SUPER MARIO BROS + -------------------------------------------------*/ + +READ16_MEMBER(md_rom_smb_device::read_a13) +{ + if (offset == 0) + return 0x0c; + else + return 0xffff; +} + +/*------------------------------------------------- + SUPER MARIO BROS 2 + -------------------------------------------------*/ + +READ16_MEMBER(md_rom_smb2_device::read_a13) +{ + if (offset == 0) + return 0x0a; + else + return 0xffff; +} + +/*------------------------------------------------- + SUPER MARIO WORLD 64 + -------------------------------------------------*/ + +READ16_MEMBER(md_rom_smw64_device::read) +{ + // 0x000000-0x0fffff: lower 512KB ROM (up to 0x07ffff) + mirror + // 0x600000-0x6fffff: internal hardware (up to 0x67ffff) + mirror + // Namely, + // * 60xxx = bank1 of the upper 512KB ROM + // * 61xxx = bank2 of the upper 512KB ROM + // * 62xxx = alternate 4KB chunks of 0x0000 ~ 0xffff + // * 63xxx = same as 62xxx + // * 64xxx = returns 0x0000 + // * 65xxx = same as 64xxx + // * 66xxx = CTRL/DATA + // * 67xxx = CTRL/DATA + if (offset < 0x100000/2) + return m_rom[offset & 0x3ffff]; + + if ((offset >= 0x600000/2) && (offset < 0x610000/2)) + return m_rom[(m_latch0 * 0x10000)/2 + (offset & 0x7fff)]; + if ((offset >= 0x610000/2) && (offset < 0x620000/2)) + return m_rom[(m_latch1 * 0x10000)/2 + (offset & 0x7fff)]; + + if ((offset >= 0x620000/2) && (offset < 0x640000/2)) + return (offset & 0x1000/2) ? 0x0000 : 0xffff; + if ((offset >= 0x640000/2) && (offset < 0x660000/2)) + return 0x0000; + + if ((offset >= 0x660000/2) && (offset < 0x670000/2)) + { + offset &= 7; + switch (offset) + { + case 0x0: + case 0x2: + case 0x4: + return m_reg[offset/2]; // DATA1, DATA2, DATA3 + case 0x1: + case 0x3: + case 0x5: + return m_reg[offset/2] + 1; // DATA1+1, DATA2+1, DATA3+1 + case 0x6: + return m_reg[2] + 2; // DATA3+2 + case 0x7: + return m_reg[2] + 3; // DATA3+3 + } + } + if ((offset >= 0x670000/2) && (offset < 0x680000/2)) + { + UINT16 data = (m_ctrl[1] & 0x80) ? ((m_ctrl[2] & 0x40) ? (m_reg[4] & m_reg[5]) : (m_reg[4] ^ 0xff)) : 0x0000; + if (offset & 0x1) // odd offset, return lower 7 bits of the above + return data & 0x7f; + else // even offset, return whole data above, but also update the regs if CTRL3 has 0x80 set + { + if (m_ctrl[2] & 0x80) // update regs if CTRL3 has bit7 set + { + if (m_ctrl[2] & 0x20) + m_reg[2] = (m_reg[5] << 2) & 0xfc; // DATA3 + else + m_reg[0] = ((m_reg[4] << 1) ^ m_reg[3]) & 0xfe; // DATA1 + } + return data; + } + } + return 0xffff; +} + +WRITE16_MEMBER(md_rom_smw64_device::write) +{ + // 0x600000-0x6fffff: internal hardware (up to 0x67ffff) + mirror + // Namely, + // * 62xxx/63xxx = unknown/unmapped + // * 65xxx/66xxx = unknown/unmapped + // * remaining ranges = CTRL/DATA + if ((offset >= 0x600000/2) && (offset < 0x610000/2)) + { + if (offset & 1) + { + if ((m_ctrl[0] & 7) == 0) + m_reg[0] = ((m_reg[0] ^ m_reg[3]) ^ data) & 0xfe; // DATA1 + if ((m_ctrl[0] & 7) == 1) + m_reg[1] = data & 0xfe; // DATA2 + if ((m_ctrl[0] & 7) == 7) + m_latch1 = 8 + ((data & 0x1c) >> 2); // ROM BANKSWITCH $61 + m_reg[3] = data; // DATA4 + } + else + m_ctrl[0] = data; // CTRL1 + } + if ((offset >= 0x610000/2) && (offset < 0x620000/2)) + { + if (offset & 1) + m_ctrl[1] = data; // CTRL2 + } + if ((offset >= 0x640000/2) && (offset < 0x650000/2)) + { + if (offset & 1) + m_reg[5] = data; // DATA6 + else + m_reg[4] = data; // DATA5 + } + if ((offset >= 0x670000/2) && (offset < 0x680000/2)) + { + if (!(offset & 1)) + { + m_ctrl[2] = data; // CTRL3 + if (m_ctrl[1] & 0x80) + m_latch0 = 8 + ((data & 0x1c) >> 2); // ROM BANKSWITCH $60 + } + } +} + +/*------------------------------------------------- + TEKKEN SPECIAL + -------------------------------------------------*/ + +READ16_MEMBER(md_rom_tekkensp_device::read) +{ + if (offset < 0x400000/2) + return m_rom[MD_ADDR(offset)]; + else if ((offset & 0x07) == 1 && m_reg) + return (m_reg - 1) << 8; + else + return 0xffff; +} + +WRITE16_MEMBER(md_rom_tekkensp_device::write) +{ + if (offset < 0x400000/2) + return; + + // thanks to EkeEke for the documentation + switch (offset & 0x07) + { + case 0x00: + // data output reset ? (game writes $FF before & after protection check) + m_reg = 0; + break; + case 0x01: + // read only ? + break; + case 0x06: + // data output mode bit 0 ? (game writes $01) + break; + case 0x07: + // data output mode bit 1 ? (never written by game) + break; + default: + if (data & 0x100) // data input (only connected to D0 ?) + { + // 4-bit hardware register ($400004 corresponds to bit0, $400006 to bit1, etc) + int shift = (offset - 2) & 3; + m_reg |= (1 << shift); + } + break; + } +} + +/*------------------------------------------------- + TOP FIGHTER + -------------------------------------------------*/ + +READ16_MEMBER(md_rom_topf_device::read) +{ + //cpu #0 (PC=0004CBAE): unmapped program memory word read from 006A35D4 & 00FF -- wants regD7 + if (offset == 0x645b44/2) + { + //cpu #0 (PC=0004DE00): unmapped program memory word write to 00689B80 = 004A & 00FF + //cpu #0 (PC=0004DE08): unmapped program memory word write to 00 = 00B5 & 00FF + //cpu #0 (PC=0004DE0C): unmapped program memory word read from 00645B44 & 00FF + + return 0x9f;//0x25; + } + if (offset == 0x6bd294/2) + { + /* + cpu #0 (PC=00177192): unmapped program memory word write to 006BD240 = 00A8 & 00FF + cpu #0 (PC=0017719A): unmapped program memory word write to 006BD2D2 = 0098 & 00FF + cpu #0 (PC=001771A2): unmapped program memory word read from 006BD294 & 00FF + */ + + if (space.device().safe_pc()==0x1771a2) return 0x50; + else + { + m_latch++; + logerror("%06x topfig_6BD294_r %04x\n",space.device().safe_pc(), m_latch); + return m_latch; + } + } + if (offset == 0x6f5344/2) + { + if (space.device().safe_pc()==0x4C94E) + return space.machine().device("maincpu")->state().state_int((M68K_D0)) & 0xff; + else + { + m_latch++; + logerror("%06x topfig_6F5344_r %04x\n", space.device().safe_pc(), m_latch); + return m_latch; + } + } + + if (offset >= 0x20000/2 && offset < 0x28000/2) + return m_rom[offset + (m_bank[0] * 0x188000)/2]; + + if (offset >= 0x58000/2 && offset < 0x60000/2) + return m_rom[offset + (m_bank[1] * 0x20000)/2]; + + if (offset >= 0x60000/2 && offset < 0x68000/2) + return m_rom[offset + (m_bank[2] * 0x110000)/2]; + + // non-protection accesses + if (offset < 0x400000/2) + return m_rom[MD_ADDR(offset)]; + else + return 0xffff; +} + +WRITE16_MEMBER(md_rom_topf_device::write) +{ + if (offset >= 0x700000/2 && offset < 0x800000/2) + { + if (data == 0x002a) + m_bank[2] = 1; // == 0x2e*0x8000?! + else if (data==0x0035) // characters ingame + m_bank[0] = 1; // == 0x35*0x8000 + else if (data==0x000f) // special moves + m_bank[1] = 1; // == 0xf*0x8000 + else if (data==0x0000) + { + m_bank[0] = 0; + m_bank[1] = 0; + m_bank[2] = 0; + } + else + logerror("%06x offset %06x, data %04x\n", space.device().safe_pc(), offset, data); + } +} + +/*------------------------------------------------- + RADICA TV GAMES [to be split...] + -------------------------------------------------*/ + +READ16_MEMBER(md_rom_radica_device::read) +{ + return m_rom[(((m_bank * 0x10000) + (offset << 1)) & (m_rom_size - 1))/2]; +} + +READ16_MEMBER(md_rom_radica_device::read_a13) +{ + if (offset < 0x80) + m_bank = offset & 0x3f; + return 0; +} + +/*------------------------------------------------- + BEGGAR PRINCE + This game uses cart which is the same as SEGA_SRAM + + bankswitch mechanism for first 256KB of the image: + depending on bit7 of the value written at 0xe00/2, + accesses to 0x00000-0x3ffff go to the first 256KB + of ROM, or to the second to last 256KB chunk (usually + mapped to 0x380000-0x3bffff). SRAM is mapped at + the end of ROM. + -------------------------------------------------*/ + +READ16_MEMBER(md_rom_beggarp_device::read) +{ + if (offset >= m_nvram_start/2 && offset <= m_nvram_end/2 && m_nvram_active) + return m_nvram[offset & 0x3fff]; + + if (offset < 0x040000/2) + return m_mode ? m_rom[offset + 0x380000/2] : m_rom[offset]; + else if (offset < 0x400000/2) + return m_rom[offset & 0x1fffff]; + + return 0xffff; +} + +WRITE16_MEMBER(md_rom_beggarp_device::write) +{ + if (offset >= 0x0e00/2 && offset < 0x0f00/2) + m_mode = BIT(data, 7); + + if (offset >= m_nvram_start/2 && offset <= m_nvram_end/2 && m_nvram_active && !m_nvram_readonly) + m_nvram[offset & 0x3fff] = data; +} + +WRITE16_MEMBER(md_rom_beggarp_device::write_a13) +{ + if (offset == 0xf0/2) + { + /* unsure if this is actually supposed to toggle or just switch on? yet to encounter game that uses this */ + m_nvram_active = BIT(data, 0); + m_nvram_readonly = BIT(data, 1); + + // since a lot of generic carts ends up here if loaded from fullpath + // we turn on nvram (with m_nvram_handlers_installed) only if they toggle it on by writing here! + if (m_nvram_active) + m_nvram_handlers_installed = 1; + } +} + +/*------------------------------------------------- + LEGEND OF WUKONG + This game uses cart which is the same as SEGA_SRAM + + bankswitch mechanism for last 128KB of the image: + first 2MB of ROM is loaded in 0-0x200000 and + mirrored in 0x200000-0x400000, but depending on + bit7 of the value written at 0xe00/2 accesses to + 0x200000-0x21ffff go either to the "physical" address + (i.e. last 128K of ROM) or to the "memory" address + (i.e. mirror of first 128K) + -------------------------------------------------*/ + +READ16_MEMBER(md_rom_wukong_device::read) +{ + if (offset >= m_nvram_start/2 && offset <= m_nvram_end/2 && m_nvram_active) + return m_nvram[offset - m_nvram_start/2]; + + // here can access both last 128K of the ROM and the first 128K, depending of bit7 of m_mode + if (offset >= 0x200000/2 && offset < 0x220000/2) + return !m_mode ? m_rom[offset] : m_rom[offset & 0xffff]; + else if (offset < 0x400000/2) + return m_rom[offset & 0xfffff]; + else + return 0xffff; +} + +WRITE16_MEMBER(md_rom_wukong_device::write) +{ + if (offset < 0x100000/2) // it actually writes to 0xe00/2 + m_mode = BIT(data, 7); + + if (offset >= m_nvram_start/2 && offset <= m_nvram_end/2 && m_nvram_active && !m_nvram_readonly) + m_nvram[offset - m_nvram_start/2] = data; +} + +WRITE16_MEMBER(md_rom_wukong_device::write_a13) +{ + if (offset == 0xf0/2) + { + /* unsure if this is actually supposed to toggle or just switch on? yet to encounter game that uses this */ + m_nvram_active = BIT(data, 0); + m_nvram_readonly = BIT(data, 1); + + // since a lot of generic carts ends up here if loaded from fullpath + // we turn on nvram (with m_nvram_handlers_installed) only if they toggle it on by writing here! + if (m_nvram_active) + m_nvram_handlers_installed = 1; + } +} diff --git a/src/devices/bus/megadrive/rom.h b/src/devices/bus/megadrive/rom.h new file mode 100644 index 00000000000..1ecc693606e --- /dev/null +++ b/src/devices/bus/megadrive/rom.h @@ -0,0 +1,585 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __MD_ROM_H +#define __MD_ROM_H + +#include "md_slot.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> md_std_rom_device + +class md_std_rom_device : public device_t, + public device_md_cart_interface +{ +public: + // construction/destruction + md_std_rom_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + md_std_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start() {}; + + // reading and writing + virtual DECLARE_READ16_MEMBER(read) { if (offset < 0x400000/2) return m_rom[MD_ADDR(offset)]; else return 0xffff; }; + virtual DECLARE_WRITE16_MEMBER(write) { }; +}; + +// ======================> md_rom_sram_device + +class md_rom_sram_device : public md_std_rom_device +{ +public: + // construction/destruction + md_rom_sram_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // reading and writing + virtual DECLARE_READ16_MEMBER(read); + virtual DECLARE_WRITE16_MEMBER(write); + virtual DECLARE_WRITE16_MEMBER(write_a13); +}; + +// ======================> md_rom_fram_device + +class md_rom_fram_device : public md_std_rom_device +{ +public: + // construction/destruction + md_rom_fram_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // reading and writing + virtual DECLARE_READ16_MEMBER(read); + virtual DECLARE_WRITE16_MEMBER(write); + virtual DECLARE_READ16_MEMBER(read_a13); + virtual DECLARE_WRITE16_MEMBER(write_a13); +}; + +// ======================> md_rom_ssf2_device + +class md_rom_ssf2_device : public md_std_rom_device +{ +public: + // construction/destruction + md_rom_ssf2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // reading and writing + virtual DECLARE_READ16_MEMBER(read); + virtual DECLARE_WRITE16_MEMBER(write_a13); + +private: + UINT8 m_bank[16]; + int m_lastoff, m_lastdata; +}; + +// ======================> md_rom_cm2in1_device + +class md_rom_cm2in1_device : public md_std_rom_device +{ +public: + // construction/destruction + md_rom_cm2in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // reading and writing + virtual DECLARE_READ16_MEMBER(read); + +private: + int m_base; +}; + + +// ======================> md_rom_mcpirate_device + +class md_rom_mcpirate_device : public md_std_rom_device +{ +public: + // construction/destruction + md_rom_mcpirate_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // reading and writing + virtual DECLARE_READ16_MEMBER(read); + virtual DECLARE_WRITE16_MEMBER(write_a13); + +private: + UINT8 m_bank; +}; + + +// ======================> md_rom_bugslife_device + +class md_rom_bugslife_device : public md_std_rom_device +{ +public: + // construction/destruction + md_rom_bugslife_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // reading and writing + virtual DECLARE_READ16_MEMBER(read_a13); +}; + +// ======================> md_rom_chinf3_device + +class md_rom_chinf3_device : public md_std_rom_device +{ +public: + // construction/destruction + md_rom_chinf3_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // reading and writing + virtual DECLARE_READ16_MEMBER(read); + virtual DECLARE_WRITE16_MEMBER(write); + +private: + int m_bank; +}; + +// ======================> md_rom_16mj2_device + +class md_rom_16mj2_device : public md_std_rom_device +{ +public: + // construction/destruction + md_rom_16mj2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // reading and writing + virtual DECLARE_READ16_MEMBER(read); +}; + +// ======================> md_rom_elfwor_device + +class md_rom_elfwor_device : public md_std_rom_device +{ +public: + // construction/destruction + md_rom_elfwor_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // reading and writing + virtual DECLARE_READ16_MEMBER(read); +}; + +// ======================> md_rom_yasech_device + +class md_rom_yasech_device : public md_std_rom_device +{ +public: + // construction/destruction + md_rom_yasech_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // reading and writing + virtual DECLARE_READ16_MEMBER(read); +}; + +// ======================> md_rom_kof98_device + +class md_rom_kof98_device : public md_std_rom_device +{ +public: + // construction/destruction + md_rom_kof98_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // reading and writing + virtual DECLARE_READ16_MEMBER(read); +}; + +// ======================> md_rom_kof99_device + +class md_rom_kof99_device : public md_std_rom_device +{ +public: + // construction/destruction + md_rom_kof99_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // reading and writing + virtual DECLARE_READ16_MEMBER(read_a13); +}; + +// ======================> md_rom_lion2_device + +class md_rom_lion2_device : public md_std_rom_device +{ +public: + // construction/destruction + md_rom_lion2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // reading and writing + virtual DECLARE_READ16_MEMBER(read); + virtual DECLARE_WRITE16_MEMBER(write); + +private: + UINT16 m_prot1_data, m_prot2_data; +}; + +// ======================> md_rom_lion3_device + +class md_rom_lion3_device : public md_std_rom_device +{ +public: + // construction/destruction + md_rom_lion3_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // reading and writing + virtual DECLARE_READ16_MEMBER(read); + virtual DECLARE_WRITE16_MEMBER(write); + +private: + UINT8 m_reg[3]; + UINT16 m_bank; +}; + +// ======================> md_rom_mjlov_device + +class md_rom_mjlov_device : public md_std_rom_device +{ +public: + // construction/destruction + md_rom_mjlov_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // reading and writing + virtual DECLARE_READ16_MEMBER(read); +}; + +// ======================> md_rom_pokea_device + +class md_rom_pokea_device : public md_std_rom_device +{ +public: + // construction/destruction + md_rom_pokea_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // reading and writing + virtual DECLARE_READ16_MEMBER(read_a13); +}; + +// ======================> md_rom_pokestad_device + +class md_rom_pokestad_device : public md_std_rom_device +{ +public: + // construction/destruction + md_rom_pokestad_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // reading and writing + virtual DECLARE_READ16_MEMBER(read); + virtual DECLARE_WRITE16_MEMBER(write); + +private: + UINT8 m_bank; +}; + +// ======================> md_rom_realtec_device + +class md_rom_realtec_device : public md_std_rom_device +{ +public: + // construction/destruction + md_rom_realtec_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // reading and writing + virtual DECLARE_READ16_MEMBER(read); + virtual DECLARE_WRITE16_MEMBER(write); + +private: + UINT16 m_bank_addr, m_bank_size, m_old_bank_addr; +}; + +// ======================> md_rom_redcl_device + +class md_rom_redcl_device : public md_std_rom_device +{ +public: + // construction/destruction + md_rom_redcl_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // reading and writing + virtual DECLARE_READ16_MEMBER(read); +}; + +// ======================> md_rom_rx3_device + +class md_rom_rx3_device : public md_std_rom_device +{ +public: + // construction/destruction + md_rom_rx3_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // reading and writing + virtual DECLARE_READ16_MEMBER(read_a13); +}; + +// ======================> md_rom_sbubl_device + +class md_rom_sbubl_device : public md_std_rom_device +{ +public: + // construction/destruction + md_rom_sbubl_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // reading and writing + virtual DECLARE_READ16_MEMBER(read); +}; + +// ======================> md_rom_smb_device + +class md_rom_smb_device : public md_std_rom_device +{ +public: + // construction/destruction + md_rom_smb_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // reading and writing + virtual DECLARE_READ16_MEMBER(read_a13); +}; + +// ======================> md_rom_smb2_device + +class md_rom_smb2_device : public md_std_rom_device +{ +public: + // construction/destruction + md_rom_smb2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // reading and writing + virtual DECLARE_READ16_MEMBER(read_a13); +}; + +// ======================> md_rom_smw64_device + +class md_rom_smw64_device : public md_std_rom_device +{ +public: + // construction/destruction + md_rom_smw64_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // reading and writing + virtual DECLARE_READ16_MEMBER(read); + virtual DECLARE_WRITE16_MEMBER(write); + +private: + UINT32 m_latch0, m_latch1; + UINT16 m_reg[6]; + UINT16 m_ctrl[3]; +}; + +// ======================> md_rom_smouse_device + +class md_rom_smouse_device : public md_std_rom_device +{ +public: + // construction/destruction + md_rom_smouse_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // reading and writing + virtual DECLARE_READ16_MEMBER(read); +}; + + +// ======================> md_rom_soulb_device + +class md_rom_soulb_device : public md_std_rom_device +{ +public: + // construction/destruction + md_rom_soulb_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // reading and writing + virtual DECLARE_READ16_MEMBER(read); +}; + +// ======================> md_rom_squir_device + +class md_rom_squir_device : public md_std_rom_device +{ +public: + // construction/destruction + md_rom_squir_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // reading and writing + virtual DECLARE_READ16_MEMBER(read); + virtual DECLARE_WRITE16_MEMBER(write); + +private: + UINT16 m_latch; +}; + +// ======================> md_rom_tekkensp_device + +class md_rom_tekkensp_device : public md_std_rom_device +{ +public: + // construction/destruction + md_rom_tekkensp_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // reading and writing + virtual DECLARE_READ16_MEMBER(read); + virtual DECLARE_WRITE16_MEMBER(write); + +private: + UINT16 m_reg; +}; + +// ======================> md_rom_topf_device + +class md_rom_topf_device : public md_std_rom_device +{ +public: + // construction/destruction + md_rom_topf_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // reading and writing + virtual DECLARE_READ16_MEMBER(read); + virtual DECLARE_WRITE16_MEMBER(write); + +private: + UINT16 m_latch; + UINT8 m_bank[3]; +}; + +// ======================> md_rom_radica_device + +class md_rom_radica_device : public md_std_rom_device +{ +public: + // construction/destruction + md_rom_radica_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // reading and writing + virtual DECLARE_READ16_MEMBER(read); + virtual DECLARE_READ16_MEMBER(read_a13); + +private: + UINT8 m_bank; +}; + +// ======================> md_rom_beggarp_device + +class md_rom_beggarp_device : public md_std_rom_device +{ +public: + // construction/destruction + md_rom_beggarp_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // reading and writing + virtual DECLARE_READ16_MEMBER(read); + virtual DECLARE_WRITE16_MEMBER(write); + virtual DECLARE_WRITE16_MEMBER(write_a13); + +private: + UINT8 m_mode, m_lock; +}; + +// ======================> md_rom_wukong_device + +class md_rom_wukong_device : public md_std_rom_device +{ +public: + // construction/destruction + md_rom_wukong_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // reading and writing + virtual DECLARE_READ16_MEMBER(read); + virtual DECLARE_WRITE16_MEMBER(write); + virtual DECLARE_WRITE16_MEMBER(write_a13); + +private: + UINT8 m_mode; +}; + + + +// device type definition +extern const device_type MD_STD_ROM; +extern const device_type MD_ROM_SRAM; +extern const device_type MD_ROM_FRAM; +extern const device_type MD_ROM_CM2IN1; +extern const device_type MD_ROM_16MJ2; +extern const device_type MD_ROM_BUGSLIFE; +extern const device_type MD_ROM_CHINF3; +extern const device_type MD_ROM_ELFWOR; +extern const device_type MD_ROM_YASECH; +extern const device_type MD_ROM_KOF98; +extern const device_type MD_ROM_KOF99; +extern const device_type MD_ROM_LION2; +extern const device_type MD_ROM_LION3; +extern const device_type MD_ROM_MCPIR; +extern const device_type MD_ROM_MJLOV; +extern const device_type MD_ROM_POKEA; +extern const device_type MD_ROM_POKESTAD; +extern const device_type MD_ROM_REALTEC; +extern const device_type MD_ROM_REDCL; +extern const device_type MD_ROM_RX3; +extern const device_type MD_ROM_SBUBL; +extern const device_type MD_ROM_SMB; +extern const device_type MD_ROM_SMB2; +extern const device_type MD_ROM_SMW64; +extern const device_type MD_ROM_SMOUSE; +extern const device_type MD_ROM_SOULB; +extern const device_type MD_ROM_SSF2; +extern const device_type MD_ROM_SQUIR; +extern const device_type MD_ROM_TEKKENSP; +extern const device_type MD_ROM_TOPF; +extern const device_type MD_ROM_RADICA; +extern const device_type MD_ROM_BEGGARP; +extern const device_type MD_ROM_WUKONG; + +#endif diff --git a/src/devices/bus/megadrive/sk.c b/src/devices/bus/megadrive/sk.c new file mode 100644 index 00000000000..8c10826f685 --- /dev/null +++ b/src/devices/bus/megadrive/sk.c @@ -0,0 +1,95 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + Sonic & Knuckles pass-thorugh cart emulation + + + TODO: currently we only support loading of base carts with no bankswitch or protection... + shall we support other as well? + + + ***********************************************************************************************************/ + + + + +#include "emu.h" +#include "sk.h" +#include "rom.h" + + +//------------------------------------------------- +// md_rom_device - constructor +//------------------------------------------------- + +const device_type MD_ROM_SK = &device_creator; + + +md_rom_sk_device::md_rom_sk_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_md_cart_interface( mconfig, *this ), + m_exp(*this, "subslot") +{ +} + +md_rom_sk_device::md_rom_sk_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, MD_ROM_SK, "MD Sonic & Knuckles", tag, owner, clock, "md_rom_sk", __FILE__), + device_md_cart_interface( mconfig, *this ), + m_exp(*this, "subslot") +{ +} + + +void md_rom_sk_device::device_start() +{ +} + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +READ16_MEMBER(md_rom_sk_device::read) +{ + if (m_exp->m_cart != NULL && m_exp->m_cart->get_rom_base() != NULL && offset >= 0x200000/2 && offset < (0x200000 + m_exp->m_cart->get_rom_size())/2) + return m_exp->m_cart->m_rom[offset - 0x200000/2]; + if (offset < 0x400000/2) + return m_rom[MD_ADDR(offset)]; + else + return 0xffff; +} + +WRITE16_MEMBER(md_rom_sk_device::write) +{ +// should there be anything here? +} + +//------------------------------------------------- +// MACHINE_CONFIG_FRAGMENT( sk_slot ) +//------------------------------------------------- + +static SLOT_INTERFACE_START(sk_sub_cart) + SLOT_INTERFACE_INTERNAL("rom", MD_STD_ROM) + SLOT_INTERFACE_INTERNAL("rom_svp", MD_STD_ROM) + SLOT_INTERFACE_INTERNAL("rom_sram", MD_ROM_SRAM) + SLOT_INTERFACE_INTERNAL("rom_sramsafe", MD_ROM_SRAM) + SLOT_INTERFACE_INTERNAL("rom_fram", MD_ROM_FRAM) +// add all types?? +SLOT_INTERFACE_END + +static MACHINE_CONFIG_FRAGMENT( sk_slot ) + MCFG_MD_CARTRIDGE_ADD("subslot", sk_sub_cart, NULL) + MCFG_MD_CARTRIDGE_NOT_MANDATORY +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor md_rom_sk_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( sk_slot ); +} diff --git a/src/devices/bus/megadrive/sk.h b/src/devices/bus/megadrive/sk.h new file mode 100644 index 00000000000..4ad52056066 --- /dev/null +++ b/src/devices/bus/megadrive/sk.h @@ -0,0 +1,35 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __MD_SK_H +#define __MD_SK_H + +#include "md_slot.h" + + +// ======================> md_rom_sk_device + +class md_rom_sk_device : public device_t, + public device_md_cart_interface +{ +public: + // construction/destruction + md_rom_sk_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + md_rom_sk_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual machine_config_constructor device_mconfig_additions() const; + + // reading and writing + virtual DECLARE_READ16_MEMBER(read); + virtual DECLARE_WRITE16_MEMBER(write); + +private: + required_device m_exp; +}; + + +// device type definition +extern const device_type MD_ROM_SK; + +#endif diff --git a/src/devices/bus/megadrive/stm95.c b/src/devices/bus/megadrive/stm95.c new file mode 100644 index 00000000000..67c367425a6 --- /dev/null +++ b/src/devices/bus/megadrive/stm95.c @@ -0,0 +1,265 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli, MetalliC +/*************************************************************************** + + + MegaDrive / Genesis Cart + STM95 EEPROM device + + + TO DO: split STM95 to a separate device... + +***************************************************************************/ + + +#include "emu.h" +#include "stm95.h" + + +stm95_eeprom_device::stm95_eeprom_device(running_machine &machine, UINT8 *eeprom) : + stm_state(IDLE), + stream_pos(0), + m_machine(machine) +{ + eeprom_data = eeprom; + m_machine.save().save_item(latch, "STM95/latch"); + m_machine.save().save_item(reset_line, "STM95/reset_line"); + m_machine.save().save_item(sck_line, "STM95/sck_line"); + m_machine.save().save_item(WEL, "STM95/WEL"); + m_machine.save().save_item(stream_pos, "STM95/stream_pos"); + m_machine.save().save_item(stream_data, "STM95/stream_data"); + m_machine.save().save_item(eeprom_addr, "STM95/eeprom_addr"); +} + +void stm95_eeprom_device::set_cs_line(int state) +{ + reset_line = state; + if (reset_line != CLEAR_LINE) + { + stream_pos = 0; + stm_state = IDLE; + } +} + +void stm95_eeprom_device::set_si_line(int state) +{ + latch = state; +} + +int stm95_eeprom_device::get_so_line(void) +{ + if (stm_state == READING || stm_state == CMD_RDSR) + return (stream_data >> 8) & 1; + else + return 0; +} + +void stm95_eeprom_device::set_sck_line(int state) +{ + if (reset_line == CLEAR_LINE) + { + if (state == ASSERT_LINE && sck_line == CLEAR_LINE) + { + switch (stm_state) + { + case IDLE: + stream_data = (stream_data << 1) | (latch ? 1 : 0); + stream_pos++; + if (stream_pos == 8) + { + stream_pos = 0; + //printf("STM95 EEPROM: got cmd %02X\n", stream_data&0xff); + switch(stream_data & 0xff) + { + case 0x01: // write status register + if (WEL != 0) + stm_state = CMD_WRSR; + WEL = 0; + break; + case 0x02: // write + if (WEL != 0) + stm_state = CMD_WRITE; + stream_data = 0; + WEL = 0; + break; + case 0x03: // read + stm_state = M95320_CMD_READ; + stream_data = 0; + break; + case 0x04: // write disable + WEL = 0; + break; + case 0x05: // read status register + stm_state = CMD_RDSR; + stream_data = WEL<<1; + break; + case 0x06: // write enable + WEL = 1; + break; + default: + logerror("STM95 EEPROM: unknown cmd %02X\n", stream_data&0xff); + } + } + break; + case CMD_WRSR: + stream_pos++; // just skip, don't care block protection + if (stream_pos == 8) + { + stm_state = IDLE; + stream_pos = 0; + } + break; + case CMD_RDSR: + stream_data = stream_data<<1; + stream_pos++; + if (stream_pos == 8) + { + stm_state = IDLE; + stream_pos = 0; + } + break; + case M95320_CMD_READ: + stream_data = (stream_data << 1) | (latch ? 1 : 0); + stream_pos++; + if (stream_pos == 16) + { + eeprom_addr = stream_data & (M95320_SIZE - 1); + stream_data = eeprom_data[eeprom_addr]; + stm_state = READING; + stream_pos = 0; + } + break; + case READING: + stream_data = stream_data<<1; + stream_pos++; + if (stream_pos == 8) + { + if (++eeprom_addr == M95320_SIZE) + eeprom_addr = 0; + stream_data |= eeprom_data[eeprom_addr]; + stream_pos = 0; + } + break; + case CMD_WRITE: + stream_data = (stream_data << 1) | (latch ? 1 : 0); + stream_pos++; + if (stream_pos == 16) + { + eeprom_addr = stream_data & (M95320_SIZE - 1); + stm_state = WRITING; + stream_pos = 0; + } + break; + case WRITING: + stream_data = (stream_data << 1) | (latch ? 1 : 0); + stream_pos++; + if (stream_pos == 8) + { + eeprom_data[eeprom_addr] = stream_data; + if (++eeprom_addr == M95320_SIZE) + eeprom_addr = 0; + stream_pos = 0; + } + break; + } + } + } + sck_line = state; +} + + + +//------------------------------------------------- +// md_rom_device - constructor +//------------------------------------------------- + +const device_type MD_EEPROM_STM95 = &device_creator; + + +md_eeprom_stm95_device::md_eeprom_stm95_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_md_cart_interface( mconfig, *this ) +{ +} + +md_eeprom_stm95_device::md_eeprom_stm95_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, MD_EEPROM_STM95, "MD Cart + EEPROM STM95", tag, owner, clock, "md_eeprom_stm95", __FILE__), + device_md_cart_interface( mconfig, *this ) +{ +} + + +void md_eeprom_stm95_device::device_start() +{ + nvram_alloc(M95320_SIZE); + m_stm95.reset(global_alloc(stm95_eeprom_device(machine(), (UINT8*)get_nvram_base()))); + + save_item(NAME(m_rdcnt)); + save_item(NAME(m_bank)); +} + +void md_eeprom_stm95_device::device_reset() +{ + m_rdcnt = 0; + m_bank[0] = 0; + m_bank[1] = 0; + m_bank[2] = 0; +} + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +READ16_MEMBER(md_eeprom_stm95_device::read) +{ + if (offset == 0x0015e6/2 || offset == 0x0015e8/2) + { + // ugly hack until we don't know much about game protection + // first 3 reads from 15e6 return 0x00000010, then normal 0x00018010 value for crc check + UINT16 res; + offset -= 0x0015e6/2; + logerror("read 0x15e6 %d\n", m_rdcnt); + if (m_rdcnt < 6) + { + m_rdcnt++; + res = offset ? 0x10 : 0; + } + else + res = offset ? 0x8010 : 0x0001; + return res; + } + if (offset < 0x280000/2) + return m_rom[offset]; + else // last 0x180000 are bankswitched + { + UINT8 bank = (offset - 0x280000/2) >> 18; + return m_rom[(offset & 0x7ffff/2) + (m_bank[bank] * 0x80000)/2]; + } +} + +READ16_MEMBER(md_eeprom_stm95_device::read_a13) +{ + if (offset == 0x0a/2) + { + return m_stm95->get_so_line() & 1; + } + return 0xffff; +} + +WRITE16_MEMBER(md_eeprom_stm95_device::write_a13) +{ + if (offset == 0x00/2) + { + logerror("A13001 write %02x\n", data); + } + else if (offset < 0x08/2) + { + m_bank[offset - 1] = data & 0x0f; + } + else if (offset < 0x0a/2) + { + m_stm95->set_si_line(BIT(data, 0)); + m_stm95->set_sck_line(BIT(data, 1)); + m_stm95->set_halt_line(BIT(data, 2)); + m_stm95->set_cs_line(BIT(data, 3)); + } +} diff --git a/src/devices/bus/megadrive/stm95.h b/src/devices/bus/megadrive/stm95.h new file mode 100644 index 00000000000..39e40770019 --- /dev/null +++ b/src/devices/bus/megadrive/stm95.h @@ -0,0 +1,86 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli, MetalliC +#ifndef __MD_STM95_H +#define __MD_STM95_H + +#include "md_slot.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +/* ST M95320 32Kbit serial EEPROM implementation */ +// TO DO: STM95 should be made a separate EEPROM device and this should be merged with md_eeprom.c! + +#define M95320_SIZE 0x1000 + +enum STMSTATE +{ + IDLE = 0, + CMD_WRSR, + CMD_RDSR, + M95320_CMD_READ, + CMD_WRITE, + READING, + WRITING +}; + +class stm95_eeprom_device +{ +public: + stm95_eeprom_device(running_machine &machine, UINT8 *eeprom); + running_machine &machine() const { return m_machine; } + + UINT8 *eeprom_data; + void set_cs_line(int); + void set_halt_line(int state) {}; // not implemented + void set_si_line(int); + void set_sck_line(int state); + int get_so_line(void); + +protected: + int latch; + int reset_line; + int sck_line; + int WEL; + + STMSTATE stm_state; + int stream_pos; + int stream_data; + int eeprom_addr; + + running_machine& m_machine; +}; + + +// ======================> md_eeprom_stm95_device + +class md_eeprom_stm95_device : public device_t, + public device_md_cart_interface +{ +public: + // construction/destruction + md_eeprom_stm95_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + md_eeprom_stm95_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // reading and writing + virtual DECLARE_READ16_MEMBER(read); + virtual DECLARE_READ16_MEMBER(read_a13); + virtual DECLARE_WRITE16_MEMBER(write_a13); + +private: + UINT8 m_bank[3]; + int m_rdcnt; + + auto_pointer m_stm95; +}; + + +// device type definition +extern const device_type MD_EEPROM_STM95; + +#endif diff --git a/src/devices/bus/megadrive/svp.c b/src/devices/bus/megadrive/svp.c new file mode 100644 index 00000000000..324c5302a33 --- /dev/null +++ b/src/devices/bus/megadrive/svp.c @@ -0,0 +1,472 @@ +// license:??? +// copyright-holders:Fabio Priuli,Pierpaolo Prazzoli,Grazvydas Ignotas +/****************************************** SVP related *****************************************/ + +/* + * Emulator of memory controller in SVP chip + * + * Copyright 2008, Grazvydas Ignotas + * based on RE work by Tasco Deluxe + * + * SSP1601 EXT registers are mapped as I/O ports due to their function + * (they are interfaced through external bus), and are named as follows + * (these are unofficial names, official ones are unknown): + * EXT0: PM0 - programmable register 0 + * EXT1: PM1 - ... 1 + * EXT2: PM2 - ... 2 + * EXT3: XST - external status. Can also act as PM. + * EXT4: PM4 - ... 4 + * EXT5: (unused) + * EXT6: PMC - programmable memory register control (PMAC). + * EXT7: AL - although internal to SSP1601, it still causes bus access + * + * Depending on GPO bits in status register, PM0, PM1, PM2 and XST can act as + * external status registers, os as programmable memory registers. PM4 always + * acts as PM register (independent on GPO bits). + */ + + +#include "emu.h" +#include "svp.h" + + +//------------------------------------------------- +// md_rom_device - constructor +//------------------------------------------------- + +const device_type MD_ROM_SVP = &device_creator; + +md_rom_svp_device::md_rom_svp_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_md_cart_interface( mconfig, *this ), + m_svp(*this, "svp"), + m_test_ipt(*this, "MEMORY_TEST") +{ +} + +md_rom_svp_device::md_rom_svp_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, MD_ROM_SVP, "MD Virtua Racing", tag, owner, clock, "md_rom_svp", __FILE__), + device_md_cart_interface( mconfig, *this ), + m_svp(*this, "svp"), + m_test_ipt(*this, "MEMORY_TEST") +{ +} + + +#define SSP_PMC_HAVE_ADDR 1 // address written to PMAC, waiting for mode +#define SSP_PMC_SET 2 // PMAC is set, PMx can be programmed + +#define MASTER_CLOCK_NTSC 53693175 + +// HELPERS + +INLINE int get_inc(int mode) +{ + int inc = (mode >> 11) & 7; + if (inc != 0) { + if (inc != 7) inc--; + inc = 1 << inc; // 0 1 2 4 8 16 32 128 + if (mode & 0x8000) inc = -inc; // decrement mode + } + return inc; +} + +INLINE void overwrite_write(UINT16 *dst, UINT16 d) +{ + if (d & 0xf000) { *dst &= ~0xf000; *dst |= d & 0xf000; } + if (d & 0x0f00) { *dst &= ~0x0f00; *dst |= d & 0x0f00; } + if (d & 0x00f0) { *dst &= ~0x00f0; *dst |= d & 0x00f0; } + if (d & 0x000f) { *dst &= ~0x000f; *dst |= d & 0x000f; } +} + + + +UINT32 md_rom_svp_device::pm_io(int reg, int write, UINT32 d) +{ + if (m_emu_status & SSP_PMC_SET) + { + if (write) + m_pmac_write[reg] = m_pmc.d; + else + m_pmac_read[reg] = m_pmc.d; + + m_emu_status &= ~SSP_PMC_SET; + return 0; + } + + // just in case + if (m_emu_status & SSP_PMC_HAVE_ADDR) + m_emu_status &= ~SSP_PMC_HAVE_ADDR; + + if (reg == 4 || (m_svp->state().state_int(SSP_ST) & 0x60)) + { +#define CADDR ((((mode<<16)&0x7f0000)|addr)<<1) + UINT16 *dram = (UINT16 *)m_dram; + if (write) + { + int mode = m_pmac_write[reg] >> 16; + int addr = m_pmac_write[reg] & 0xffff; + + if ((mode & 0x43ff) == 0x0018) // DRAM + { + int inc = get_inc(mode); + if (mode & 0x0400) + overwrite_write(&dram[addr], d); + else + dram[addr] = d; + m_pmac_write[reg] += inc; + } + else if ((mode & 0xfbff) == 0x4018) // DRAM, cell inc + { + if (mode & 0x0400) + overwrite_write(&dram[addr], d); + else + dram[addr] = d; + m_pmac_write[reg] += (addr & 1) ? 31 : 1; + } + else if ((mode & 0x47ff) == 0x001c) // IRAM + { + int inc = get_inc(mode); + ((UINT16 *)m_iram)[addr & 0x3ff] = d; + m_pmac_write[reg] += inc; + } + else + { + logerror("ssp FIXME: PM%i unhandled write mode %04x, [%06x] %04x\n", + reg, mode, CADDR, d); + } + } + else + { + int mode = m_pmac_read[reg] >> 16; + int addr = m_pmac_read[reg] & 0xffff; + if ((mode & 0xfff0) == 0x0800) // ROM, inc 1, verified to be correct + { + UINT16 *ROM = (UINT16 *)get_rom_base(); + m_pmac_read[reg] += 1; + d = ROM[addr | ((mode & 0xf) << 16)]; + } + else if ((mode & 0x47ff) == 0x0018) // DRAM + { + int inc = get_inc(mode); + d = dram[addr]; + m_pmac_read[reg] += inc; + } + else + { + logerror("ssp FIXME: PM%i unhandled read mode %04x, [%06x]\n", + reg, mode, CADDR); + d = 0; + } + } + + // PMC value corresponds to last PMR accessed (not sure). + if (write) + m_pmc.d = m_pmac_write[reg]; + else + m_pmc.d = m_pmac_read[reg]; + + return d; + } + + return (UINT32)-1; +} + +READ16_MEMBER( md_rom_svp_device::read_pm0 ) +{ + UINT32 d = pm_io(0, 0, 0); + if (d != (UINT32)-1) + return d; + d = m_xst2; + m_xst2 &= ~2; // ? + return d; +} + +WRITE16_MEMBER( md_rom_svp_device::write_pm0 ) +{ + UINT32 r = pm_io(0, 1, data); + if (r != (UINT32)-1) + return; + m_xst2 = data; // ? +} + +READ16_MEMBER( md_rom_svp_device::read_pm1 ) +{ + UINT32 r = pm_io(1, 0, 0); + if (r != (UINT32)-1) + return r; + logerror("svp: PM1 acces in non PM mode?\n"); + return 0; +} + +WRITE16_MEMBER( md_rom_svp_device::write_pm1 ) +{ + UINT32 r = pm_io(1, 1, data); + if (r != (UINT32)-1) + return; + logerror("svp: PM1 acces in non PM mode?\n"); +} + +READ16_MEMBER( md_rom_svp_device::read_pm2 ) +{ + UINT32 r = pm_io(2, 0, 0); + if (r != (UINT32)-1) + return r; + logerror("svp: PM2 acces in non PM mode?\n"); + return 0; +} + +WRITE16_MEMBER( md_rom_svp_device::write_pm2 ) +{ + UINT32 r = pm_io(2, 1, data); + if (r != (UINT32)-1) + return; + logerror("svp: PM2 acces in non PM mode?\n"); +} + +READ16_MEMBER( md_rom_svp_device::read_xst ) +{ + UINT32 d = pm_io(3, 0, 0); + if (d != (UINT32)-1) + return d; + return m_xst; +} + +WRITE16_MEMBER( md_rom_svp_device::write_xst ) +{ + UINT32 r = pm_io(3, 1, data); + if (r != (UINT32)-1) + return; + m_xst2 |= 1; + m_xst = data; +} + +READ16_MEMBER( md_rom_svp_device::read_pm4 ) +{ + return pm_io(4, 0, 0); +} + +WRITE16_MEMBER( md_rom_svp_device::write_pm4 ) +{ + pm_io(4, 1, data); +} + +READ16_MEMBER( md_rom_svp_device::read_pmc ) +{ + if (m_emu_status & SSP_PMC_HAVE_ADDR) + { + m_emu_status |= SSP_PMC_SET; + m_emu_status &= ~SSP_PMC_HAVE_ADDR; + return ((m_pmc.w.l << 4) & 0xfff0) | ((m_pmc.w.l >> 4) & 0xf); + } + else + { + m_emu_status |= SSP_PMC_HAVE_ADDR; + return m_pmc.w.l; + } +} + +WRITE16_MEMBER( md_rom_svp_device::write_pmc ) +{ + if (m_emu_status & SSP_PMC_HAVE_ADDR) + { + m_emu_status |= SSP_PMC_SET; + m_emu_status &= ~SSP_PMC_HAVE_ADDR; + m_pmc.w.h = data; + } + else + { + m_emu_status |= SSP_PMC_HAVE_ADDR; + m_pmc.w.l = data; + } +} + +READ16_MEMBER( md_rom_svp_device::read_al ) +{ + m_emu_status &= ~(SSP_PMC_SET | SSP_PMC_HAVE_ADDR); + return 0; +} + +WRITE16_MEMBER( md_rom_svp_device::write_al ) +{ +} + + +READ16_MEMBER( md_rom_svp_device::rom_read1 ) +{ + UINT16 *IRAM = (UINT16 *)m_iram; + return IRAM[offset]; +} + +READ16_MEMBER( md_rom_svp_device::rom_read2 ) +{ + return m_rom[offset + 0x800/2]; +} + +int md_rom_svp_device::read_test() +{ + return m_test_ipt->read(); +} + + +static INPUT_PORTS_START( md_svp ) + PORT_START("MEMORY_TEST") /* special memtest mode */ + PORT_CONFNAME( 0x01, 0x00, "SVP Test" ) + PORT_CONFSETTING( 0x00, DEF_STR( Off ) ) + PORT_CONFSETTING( 0x01, DEF_STR( On ) ) +INPUT_PORTS_END + +//------------------------------------------------- +// ADDRESS_MAP( svp_ssp_map ) +//------------------------------------------------- + +ADDRESS_MAP_START( md_svp_ssp_map, AS_PROGRAM, 16, md_rom_svp_device ) +// AM_RANGE(0x0000, 0x03ff) AM_READ(rom_read1) +// AM_RANGE(0x0400, 0xffff) AM_READ(rom_read2) + AM_RANGE(0x0000, 0x03ff) AM_ROMBANK("iram_svp") + AM_RANGE(0x0400, 0xffff) AM_ROMBANK("cart_svp") +ADDRESS_MAP_END + +//------------------------------------------------- +// ADDRESS_MAP( svp_ext_map ) +//------------------------------------------------- + +ADDRESS_MAP_START( md_svp_ext_map, AS_IO, 16, md_rom_svp_device ) + ADDRESS_MAP_GLOBAL_MASK(0xf) + AM_RANGE(0*2, 0*2+1) AM_READWRITE(read_pm0, write_pm0) + AM_RANGE(1*2, 1*2+1) AM_READWRITE(read_pm1, write_pm1) + AM_RANGE(2*2, 2*2+1) AM_READWRITE(read_pm2, write_pm2) + AM_RANGE(3*2, 3*2+1) AM_READWRITE(read_xst, write_xst) + AM_RANGE(4*2, 4*2+1) AM_READWRITE(read_pm4, write_pm4) + AM_RANGE(6*2, 6*2+1) AM_READWRITE(read_pmc, write_pmc) + AM_RANGE(7*2, 7*2+1) AM_READWRITE(read_al, write_al) +ADDRESS_MAP_END + +//------------------------------------------------- +// MACHINE_DRIVER( md_svp ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( md_svp ) + MCFG_CPU_ADD("svp", SSP1601, MASTER_CLOCK_NTSC / 7 * 3) /* ~23 MHz (guessed) */ + MCFG_CPU_PROGRAM_MAP(md_svp_ssp_map) + MCFG_CPU_IO_MAP(md_svp_ext_map) +MACHINE_CONFIG_END + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor md_rom_svp_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( md_svp ); +} + +ioport_constructor md_rom_svp_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( md_svp ); +} + + +void md_rom_svp_device::set_bank_to_rom(const char *banktag, UINT32 offset) +{ + if (membank(banktag)) + membank(banktag)->set_base(m_rom + offset); +} + + +void md_rom_svp_device::device_start() +{ + memset(m_pmac_read, 0, ARRAY_LENGTH(m_pmac_read)); + memset(m_pmac_write, 0, ARRAY_LENGTH(m_pmac_write)); + m_pmc.d = 0; + m_pmc.w.l = 0; + m_pmc.w.h = 0; + m_emu_status = 0; + m_xst = 0; + m_xst2 = 0; + + // SVP stuff + this->membank("iram_svp")->set_base(m_iram); + // the other bank, "cart_svp", is setup at call_load + + save_item(NAME(m_pmac_read)); + save_item(NAME(m_pmac_write)); + save_item(NAME(m_emu_status)); + save_item(NAME(m_xst)); + save_item(NAME(m_xst2)); + save_item(NAME(m_pmc.d)); + save_item(NAME(m_pmc.w.l)); + save_item(NAME(m_pmc.w.h)); + save_item(NAME(m_dram)); + save_item(NAME(m_iram)); +} + +READ16_MEMBER(md_rom_svp_device::read) +{ + UINT16 *DRAM = (UINT16 *)m_dram; + + if (offset >= 0x300000/2 && offset < 0x320000/2) + { + return DRAM[offset - 0x300000/2]; + } + else if (offset >= 0x390000/2 && offset < 0x3a0000/2) + { + // this is rewritten 68k test code + UINT32 a1 = offset - 0x390000/2; + a1 = (a1 & 0x7001) | ((a1 & 0x3e) << 6) | ((a1 & 0xfc0) >> 5); + return DRAM[a1]; + } + else if (offset >= 0x3a0000/2 && offset < 0x3b0000/2) + { + // this is rewritten 68k test code + UINT32 a1 = offset - 0x3a0000/2; + a1 = (a1 & 0x7801) | ((a1 & 0x1e) << 6) | ((a1 & 0x7e0) >> 4); + return DRAM[a1]; + } + if (offset < 0x200000/2) + return m_rom[offset]; + else + { + printf("read out of bound\n"); + return 0xffff; + } +} + +WRITE16_MEMBER(md_rom_svp_device::write) +{ + if (offset >= 0x300000/2 && offset < 0x320000/2) + { + UINT32 a1 = offset - 0x300000/2; + UINT16 *DRAM = (UINT16 *)m_dram; + DRAM[a1] = data; + } +} + +READ16_MEMBER(md_rom_svp_device::read_a15) +{ + UINT32 d; + switch (offset) + { + // 0xa15000, 0xa15002 + case 0: + case 1: return m_xst; + // 0xa15004 + case 2: d = m_xst2; m_xst2 &= ~1; return d; + default: logerror("unhandled SVP reg read @ %x\n", offset << 1); + } + return 0; +} + +WRITE16_MEMBER(md_rom_svp_device::write_a15) +{ + switch (offset) + { + // 0xa15000, 0xa15002 + case 0: + case 1: m_xst = data; m_xst2 |= 2; break; + // 0xa15006 + case 3: break; // possibly halts SSP1601 + default: logerror("unhandled SVP reg write %04x @ %x\n", data, offset << 1); + } +} diff --git a/src/devices/bus/megadrive/svp.h b/src/devices/bus/megadrive/svp.h new file mode 100644 index 00000000000..0f128240a86 --- /dev/null +++ b/src/devices/bus/megadrive/svp.h @@ -0,0 +1,75 @@ +// license:??? +// copyright-holders:Fabio Priuli,Pierpaolo Prazzoli,Grazvydas Ignotas +#ifndef __MD_SVP_H +#define __MD_SVP_H + +#include "md_slot.h" +#include "cpu/ssp1601/ssp1601.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> md_rom_svp_device + +class md_rom_svp_device : public device_t, + public device_md_cart_interface +{ +public: + // construction/destruction + md_rom_svp_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + md_rom_svp_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +//protected: + // device-level overrides + virtual void device_start(); + virtual machine_config_constructor device_mconfig_additions() const; + virtual ioport_constructor device_input_ports() const; + virtual void set_bank_to_rom(const char *banktag, UINT32 offset); + + required_device m_svp; + required_ioport m_test_ipt; + + // reading and writing + virtual DECLARE_READ16_MEMBER(read); + virtual DECLARE_WRITE16_MEMBER(write); + virtual DECLARE_READ16_MEMBER(read_a15); + virtual DECLARE_WRITE16_MEMBER(write_a15); + + virtual int read_test(); + + virtual DECLARE_READ16_MEMBER(rom_read1); + virtual DECLARE_READ16_MEMBER(rom_read2); + + virtual DECLARE_READ16_MEMBER(read_pm0); + virtual DECLARE_READ16_MEMBER(read_pm1); + virtual DECLARE_READ16_MEMBER(read_pm2); + virtual DECLARE_READ16_MEMBER(read_pm4); + virtual DECLARE_READ16_MEMBER(read_xst); + virtual DECLARE_READ16_MEMBER(read_pmc); + virtual DECLARE_READ16_MEMBER(read_al); + virtual DECLARE_WRITE16_MEMBER(write_pm0); + virtual DECLARE_WRITE16_MEMBER(write_pm1); + virtual DECLARE_WRITE16_MEMBER(write_pm2); + virtual DECLARE_WRITE16_MEMBER(write_pm4); + virtual DECLARE_WRITE16_MEMBER(write_xst); + virtual DECLARE_WRITE16_MEMBER(write_pmc); + virtual DECLARE_WRITE16_MEMBER(write_al); + + UINT32 pm_io(int reg, int write, UINT32 d); + + UINT32 m_pmac_read[6]; // read modes/addrs for PM0-PM5 + UINT32 m_pmac_write[6]; // write ... + PAIR m_pmc; + UINT32 m_emu_status; + UINT16 m_xst; // external status, mapped at a15000 and a15002 on 68k side. + UINT16 m_xst2; // status of XST (bit1 set when 68k writes to XST) + UINT8 m_iram[0x800]; // IRAM (0-0x7ff) + UINT8 m_dram[0x20000]; // [0x20000]; +}; + + +// device type definition +extern const device_type MD_ROM_SVP; + +#endif diff --git a/src/devices/bus/midi/midi.c b/src/devices/bus/midi/midi.c new file mode 100644 index 00000000000..3c77b4ca227 --- /dev/null +++ b/src/devices/bus/midi/midi.c @@ -0,0 +1,55 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +#include "midi.h" + +const device_type MIDI_PORT = &device_creator; + +midi_port_device::midi_port_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, MIDI_PORT, "Midi Port", tag, owner, clock, "midi_port", __FILE__), + device_slot_interface(mconfig, *this), + m_rxd_handler(*this), + m_dev(NULL) +{ +} + +midi_port_device::~midi_port_device() +{ +} + +void midi_port_device::device_config_complete() +{ + m_dev = dynamic_cast(get_card_device()); +} + +void midi_port_device::device_start() +{ + m_rxd_handler.resolve_safe(); +} + +WRITE_LINE_MEMBER( midi_port_device::write_txd ) +{ + if(m_dev) + m_dev->input_txd(state); +} + +device_midi_port_interface::device_midi_port_interface(const machine_config &mconfig, device_t &device) + : device_slot_card_interface(mconfig, device) +{ + m_port = dynamic_cast(device.owner()); +} + +device_midi_port_interface::~device_midi_port_interface() +{ +} + +#include "bus/midi/midiinport.h" + +SLOT_INTERFACE_START(midiin_slot) + SLOT_INTERFACE("midiin", MIDIIN_PORT) +SLOT_INTERFACE_END + +#include "bus/midi/midioutport.h" + +SLOT_INTERFACE_START(midiout_slot) + SLOT_INTERFACE("midiout", MIDIOUT_PORT) +SLOT_INTERFACE_END diff --git a/src/devices/bus/midi/midi.h b/src/devices/bus/midi/midi.h new file mode 100644 index 00000000000..2013e625f91 --- /dev/null +++ b/src/devices/bus/midi/midi.h @@ -0,0 +1,65 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +#ifndef __BUS_MIDI_H__ +#define __BUS_MIDI_H__ + +#include "emu.h" + +#define MCFG_MIDI_PORT_ADD(_tag, _slot_intf, _def_slot) \ + MCFG_DEVICE_ADD(_tag, MIDI_PORT, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) + +#define MCFG_MIDI_RX_HANDLER(_devcb) \ + devcb = &midi_port_device::set_rx_handler(*device, DEVCB_##_devcb); + +class device_midi_port_interface; + +class midi_port_device : public device_t, + public device_slot_interface +{ + friend class device_midi_port_interface; + +public: + midi_port_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual ~midi_port_device(); + + // static configuration helpers + template static devcb_base &set_rx_handler(device_t &device, _Object object) { return downcast(device).m_rxd_handler.set_callback(object); } + + DECLARE_WRITE_LINE_MEMBER( write_txd ); + + DECLARE_READ_LINE_MEMBER( rx_r ) { return m_rxd; } + +protected: + virtual void device_start(); + virtual void device_config_complete(); + + int m_rxd; + + devcb_write_line m_rxd_handler; + +private: + device_midi_port_interface *m_dev; +}; + +class device_midi_port_interface : public device_slot_card_interface +{ + friend class midi_port_device; + +public: + device_midi_port_interface(const machine_config &mconfig, device_t &device); + virtual ~device_midi_port_interface(); + + virtual DECLARE_WRITE_LINE_MEMBER( input_txd ) {} + DECLARE_WRITE_LINE_MEMBER( output_rxd ) { m_port->m_rxd = state; m_port->m_rxd_handler(state); } + +protected: + midi_port_device *m_port; +}; + +extern const device_type MIDI_PORT; + +SLOT_INTERFACE_EXTERN(midiin_slot); +SLOT_INTERFACE_EXTERN(midiout_slot); + +#endif diff --git a/src/devices/bus/midi/midiinport.c b/src/devices/bus/midi/midiinport.c new file mode 100644 index 00000000000..13632219c03 --- /dev/null +++ b/src/devices/bus/midi/midiinport.c @@ -0,0 +1,30 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/********************************************************************* + + midiinport.c + + MIDI In serial port - glues the image device to the pluggable serial port + +*********************************************************************/ + +#include "midiinport.h" + +const device_type MIDIIN_PORT = &device_creator; + +midiin_port_device::midiin_port_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, MIDIIN_PORT, "MIDI In port", tag, owner, clock, "midiin_port", __FILE__), + device_midi_port_interface(mconfig, *this), + m_midiin(*this, "midiinimg") +{ +} + +static MACHINE_CONFIG_FRAGMENT(midiin_port_config) + MCFG_DEVICE_ADD("midiinimg", MIDIIN, 0) + MCFG_MIDIIN_INPUT_CB(WRITELINE(midiin_port_device, read)) +MACHINE_CONFIG_END + +machine_config_constructor midiin_port_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME(midiin_port_config); +} diff --git a/src/devices/bus/midi/midiinport.h b/src/devices/bus/midi/midiinport.h new file mode 100644 index 00000000000..5c95257f0e5 --- /dev/null +++ b/src/devices/bus/midi/midiinport.h @@ -0,0 +1,36 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/********************************************************************* + + midiinport.h + + MIDI In port - glues the image device to the pluggable midi port + +*********************************************************************/ + +#ifndef _MIDIINPORT_H_ +#define _MIDIINPORT_H_ + +#include "midi.h" +#include "imagedev/midiin.h" + +class midiin_port_device : public device_t, + public device_midi_port_interface +{ +public: + midiin_port_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + DECLARE_WRITE_LINE_MEMBER( read ) { output_rxd(state); } + +protected: + virtual machine_config_constructor device_mconfig_additions() const; + virtual void device_start() { m_owner = dynamic_cast(owner()); } + virtual void device_reset() { } + +private: + required_device m_midiin; +}; + +extern const device_type MIDIIN_PORT; + +#endif diff --git a/src/devices/bus/midi/midioutport.c b/src/devices/bus/midi/midioutport.c new file mode 100644 index 00000000000..6ba39d6ee57 --- /dev/null +++ b/src/devices/bus/midi/midioutport.c @@ -0,0 +1,29 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/********************************************************************* + + midioutport.c + + MIDI Out serial port - glues the image device to the pluggable serial port + +*********************************************************************/ + +#include "midioutport.h" + +const device_type MIDIOUT_PORT = &device_creator; + +midiout_port_device::midiout_port_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, MIDIOUT_PORT, "MIDI Out port", tag, owner, clock, "midiout_port", __FILE__), + device_midi_port_interface(mconfig, *this), + m_midiout(*this, "midioutimg") +{ +} + +static MACHINE_CONFIG_FRAGMENT(midiout_port_config) + MCFG_MIDIOUT_ADD("midioutimg") +MACHINE_CONFIG_END + +machine_config_constructor midiout_port_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME(midiout_port_config); +} diff --git a/src/devices/bus/midi/midioutport.h b/src/devices/bus/midi/midioutport.h new file mode 100644 index 00000000000..3c0de35cb08 --- /dev/null +++ b/src/devices/bus/midi/midioutport.h @@ -0,0 +1,36 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/********************************************************************* + + midioutport.h + + MIDI Out port - glues the image device to the pluggable midi port + +*********************************************************************/ + +#ifndef _MIDIOUTPORT_H_ +#define _MIDIOUTPORT_H_ + +#include "midi.h" +#include "imagedev/midiout.h" + +class midiout_port_device : public device_t, + public device_midi_port_interface +{ +public: + midiout_port_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual machine_config_constructor device_mconfig_additions() const; + + virtual DECLARE_WRITE_LINE_MEMBER( input_txd ) { if (started()) m_midiout->tx(state); } + +protected: + virtual void device_start() { } + virtual void device_reset() { } + +private: + required_device m_midiout; +}; + +extern const device_type MIDIOUT_PORT; + +#endif diff --git a/src/devices/bus/msx_cart/arc.c b/src/devices/bus/msx_cart/arc.c new file mode 100644 index 00000000000..a64f321af14 --- /dev/null +++ b/src/devices/bus/msx_cart/arc.c @@ -0,0 +1,64 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +#include "emu.h" +#include "arc.h" + + +const device_type MSX_CART_ARC = &device_creator; + + +msx_cart_arc::msx_cart_arc(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, MSX_CART_ARC, "MSX Cartridge - Arc", tag, owner, clock, "msx_cart_arc", __FILE__) + , msx_cart_interface(mconfig, *this) + , m_7f(0) +{ +} + + +void msx_cart_arc::device_start() +{ + // Install IO read/write handlers + address_space &space = machine().device("maincpu")->space(AS_IO); + space.install_write_handler(0x7f, 0x7f, write8_delegate(FUNC(msx_cart_arc::io_7f_w), this)); + space.install_read_handler(0x7f, 0x7f, read8_delegate(FUNC(msx_cart_arc::io_7f_r), this)); +} + + +void msx_cart_arc::device_reset() +{ + m_7f = 0; +} + + +void msx_cart_arc::initialize_cartridge() +{ + if (get_rom_size() != 0x8000) + { + fatalerror("arc: Invalid ROM size\n"); + } +} + + +READ8_MEMBER(msx_cart_arc::read_cart) +{ + if (offset >= 0x4000 && offset < 0xc000) + { + return get_rom_base()[offset - 0x4000]; + } + return 0xff; +} + + +WRITE8_MEMBER(msx_cart_arc::io_7f_w) +{ + if (data == 0x35) + { + m_7f++; + } +} + + +READ8_MEMBER(msx_cart_arc::io_7f_r) +{ + return ((m_7f & 0x03) == 0x03) ? 0xda : 0xff; +} diff --git a/src/devices/bus/msx_cart/arc.h b/src/devices/bus/msx_cart/arc.h new file mode 100644 index 00000000000..57e96c5a925 --- /dev/null +++ b/src/devices/bus/msx_cart/arc.h @@ -0,0 +1,34 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +#ifndef __MSX_CART_ARC_H +#define __MSX_CART_ARC_H + +#include "bus/msx_cart/cartridge.h" + + +extern const device_type MSX_CART_ARC; + + +class msx_cart_arc : public device_t + , public msx_cart_interface +{ +public: + msx_cart_arc(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + virtual void initialize_cartridge(); + + virtual DECLARE_READ8_MEMBER(read_cart); + + DECLARE_WRITE8_MEMBER(io_7f_w); + DECLARE_READ8_MEMBER(io_7f_r); + +private: + UINT8 m_7f; +}; + + +#endif diff --git a/src/devices/bus/msx_cart/ascii.c b/src/devices/bus/msx_cart/ascii.c new file mode 100644 index 00000000000..cb3aebf0d4d --- /dev/null +++ b/src/devices/bus/msx_cart/ascii.c @@ -0,0 +1,535 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +#include "emu.h" +#include "ascii.h" + + +const device_type MSX_CART_ASCII8 = &device_creator; +const device_type MSX_CART_ASCII16 = &device_creator; +const device_type MSX_CART_ASCII8_SRAM = &device_creator; +const device_type MSX_CART_ASCII16_SRAM = &device_creator; +const device_type MSX_CART_MSXWRITE = &device_creator; + + +msx_cart_ascii8::msx_cart_ascii8(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, MSX_CART_ASCII8, "MSX Cartridge - ASCII8", tag, owner, clock, "msx_cart_ascii8", __FILE__) + , msx_cart_interface(mconfig, *this) + , m_bank_mask(0) +{ + for (int i = 0; i < 4; i++) + { + m_selected_bank[i] = 0; + m_bank_base[i] = NULL; + } +} + + +void msx_cart_ascii8::device_start() +{ + save_item(NAME(m_selected_bank)); + + machine().save().register_postload(save_prepost_delegate(FUNC(msx_cart_ascii8::restore_banks), this)); +} + + +void msx_cart_ascii8::restore_banks() +{ + for (int i = 0; i < 4; i++) + { + m_bank_base[i] = get_rom_base() + (m_selected_bank[i] & m_bank_mask ) * 0x2000; + } +} + + +void msx_cart_ascii8::device_reset() +{ + for (int i = 0; i < 4; i++) + { + m_selected_bank[i] = 0; + } +} + + +void msx_cart_ascii8::initialize_cartridge() +{ + UINT32 size = get_rom_size(); + + if ( size > 256 * 0x2000 ) + { + fatalerror("ascii8: ROM is too big\n"); + } + + UINT16 banks = size / 0x2000; + + if (size != banks * 0x2000 || (~(banks - 1) % banks)) + { + fatalerror("ascii8: Invalid ROM size\n"); + } + + m_bank_mask = banks - 1; + + restore_banks(); +} + + +READ8_MEMBER(msx_cart_ascii8::read_cart) +{ + if ( offset >= 0x4000 && offset < 0xC000 ) + { + return m_bank_base[(offset - 0x4000) >> 13][offset & 0x1fff]; + } + return 0xff; +} + + +WRITE8_MEMBER(msx_cart_ascii8::write_cart) +{ + if (offset >= 0x6000 && offset < 0x8000) + { + UINT8 bank = (offset / 0x800) & 0x03; + + m_selected_bank[bank] = data; + m_bank_base[bank] = get_rom_base() + (m_selected_bank[bank] & m_bank_mask ) * 0x2000; + } +} + + + +msx_cart_ascii16::msx_cart_ascii16(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, MSX_CART_ASCII16, "MSX Cartridge - ASCII16", tag, owner, clock, "msx_cart_ascii16", __FILE__) + , msx_cart_interface(mconfig, *this) + , m_bank_mask(0) +{ + for (int i = 0; i < 2; i++) + { + m_selected_bank[i] = 0; + m_bank_base[i] = NULL; + } +} + + +void msx_cart_ascii16::device_start() +{ + save_item(NAME(m_selected_bank)); + + machine().save().register_postload(save_prepost_delegate(FUNC(msx_cart_ascii16::restore_banks), this)); +} + + +void msx_cart_ascii16::restore_banks() +{ + for (int i = 0; i < 2; i++) + { + m_bank_base[i] = get_rom_base() + (m_selected_bank[i] & m_bank_mask) * 0x4000; + } +} + + +void msx_cart_ascii16::device_reset() +{ + for (int i = 0; i < 2; i++) + { + m_selected_bank[i] = 0; + } +} + + +void msx_cart_ascii16::initialize_cartridge() +{ + UINT32 size = get_rom_size(); + + if ( size > 256 * 0x4000 ) + { + fatalerror("ascii16: ROM is too big\n"); + } + + UINT16 banks = size / 0x4000; + + if (size != banks * 0x4000 || (~(banks - 1) % banks)) + { + fatalerror("ascii16: Invalid ROM size\n"); + } + + m_bank_mask = banks - 1; + + restore_banks(); +} + + +READ8_MEMBER(msx_cart_ascii16::read_cart) +{ + if ( offset >= 0x4000 && offset < 0xC000 ) + { + return m_bank_base[offset >> 15][offset & 0x3fff]; + } + return 0xff; +} + + +WRITE8_MEMBER(msx_cart_ascii16::write_cart) +{ + if (offset >= 0x6000 && offset < 0x6800) + { + m_selected_bank[0] = data; + m_bank_base[0] = get_rom_base() + (m_selected_bank[0] & m_bank_mask) * 0x4000; + } + + if (offset >= 0x7000 && offset < 0x7800) + { + m_selected_bank[1] = data; + m_bank_base[1] = get_rom_base() + (m_selected_bank[1] & m_bank_mask) * 0x4000; + } +} + + + + + +msx_cart_ascii8_sram::msx_cart_ascii8_sram(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, MSX_CART_ASCII8_SRAM, "MSX Cartridge - ASCII8 w/SRAM", tag, owner, clock, "msx_cart_ascii8_sram", __FILE__) + , msx_cart_interface(mconfig, *this) + , m_bank_mask(0) + , m_sram_select_mask(0) +{ + for (int i = 0; i < 4; i++) + { + m_selected_bank[i] = 0; + m_bank_base[i] = NULL; + } +} + + +void msx_cart_ascii8_sram::device_start() +{ + save_item(NAME(m_selected_bank)); + + machine().save().register_postload(save_prepost_delegate(FUNC(msx_cart_ascii8_sram::restore_banks), this)); +} + + +void msx_cart_ascii8_sram::setup_bank(UINT8 bank) +{ + if (m_selected_bank[bank] & ~(m_sram_select_mask | m_bank_mask)) + { + // Nothing is mapped + m_bank_base[bank] = NULL; + } + else if (m_selected_bank[bank] & m_sram_select_mask) + { + // SRAM is selected + m_bank_base[bank] = get_sram_base(); + } + else + { + m_bank_base[bank] = get_rom_base() + (m_selected_bank[bank] & m_bank_mask ) * 0x2000; + } +} + + +void msx_cart_ascii8_sram::restore_banks() +{ + for (int i = 0; i < 4; i++) + { + setup_bank(i); + } +} + + +void msx_cart_ascii8_sram::device_reset() +{ + for (int i = 0; i < 4; i++) + { + m_selected_bank[i] = 0; + } +} + + +void msx_cart_ascii8_sram::initialize_cartridge() +{ + UINT32 size = get_rom_size(); + + if ( size > 128 * 0x2000 ) + { + fatalerror("ascii8_sram: ROM is too big\n"); + } + + UINT16 banks = size / 0x2000; + + if (size != banks * 0x2000 || (~(banks - 1) % banks)) + { + fatalerror("ascii8_sram: Invalid ROM size\n"); + } + + if (get_sram_size() != 0x2000) + { + fatalerror("ascii8_sram: Unsupported SRAM size\n"); + } + + m_bank_mask = banks - 1; + m_sram_select_mask = banks; + + restore_banks(); +} + + +READ8_MEMBER(msx_cart_ascii8_sram::read_cart) +{ + if ( offset >= 0x4000 && offset < 0xC000 ) + { + UINT8 *bank_base = m_bank_base[(offset - 0x4000) >> 13]; + + if (bank_base != NULL) + { + return bank_base[offset & 0x1fff]; + } + } + return 0xff; +} + + +WRITE8_MEMBER(msx_cart_ascii8_sram::write_cart) +{ + if (offset >= 0x6000 && offset < 0x8000) + { + UINT8 bank = (offset / 0x800) & 0x03; + + m_selected_bank[bank] = data; + setup_bank(bank); + } + else if (offset >= 0x8000 && offset < 0xc000) + { + UINT8 bank = (offset & 0x2000) ? 3 : 2; + + if ((m_selected_bank[bank] & m_sram_select_mask) && !(m_selected_bank[bank] & ~(m_sram_select_mask | m_bank_mask))) + { + // Write to SRAM + m_bank_base[bank][offset & 0x1fff] = data; + } + } +} + + + +msx_cart_ascii16_sram::msx_cart_ascii16_sram(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, MSX_CART_ASCII16_SRAM, "MSX Cartridge - ASCII16 w/SRAM", tag, owner, clock, "msx_cart_ascii16_sram", __FILE__) + , msx_cart_interface(mconfig, *this) + , m_bank_mask(0) + , m_sram_select_mask(0) +{ + for (int i = 0; i < 2; i++) + { + m_selected_bank[i] = 0; + m_bank_base[i] = NULL; + } +} + + +void msx_cart_ascii16_sram::device_start() +{ + save_item(NAME(m_selected_bank)); + + machine().save().register_postload(save_prepost_delegate(FUNC(msx_cart_ascii16_sram::restore_banks), this)); +} + + +void msx_cart_ascii16_sram::setup_bank(UINT8 bank) +{ + if (m_selected_bank[bank] & ~(m_sram_select_mask | m_bank_mask)) + { + // Nothing is mapped + m_bank_base[bank] = NULL; + } + else if (m_selected_bank[bank] & m_sram_select_mask) + { + // SRAM is selected + m_bank_base[bank] = get_sram_base(); + } + else + { + m_bank_base[bank] = get_rom_base() + (m_selected_bank[bank] & m_bank_mask) * 0x4000; + } +} + + +void msx_cart_ascii16_sram::restore_banks() +{ + for (int i = 0; i < 2; i++) + { + setup_bank(i); + } +} + + +void msx_cart_ascii16_sram::device_reset() +{ + for (int i = 0; i < 2; i++) + { + m_selected_bank[i] = 0; + } +} + + +void msx_cart_ascii16_sram::initialize_cartridge() +{ + UINT32 size = get_rom_size(); + + if ( size > 128 * 0x4000 ) + { + fatalerror("ascii16_sram: ROM is too big\n"); + } + + UINT16 banks = size / 0x4000; + + if (size != banks * 0x4000 || (~(banks - 1) % banks)) + { + fatalerror("ascii16_sram: Invalid ROM size\n"); + } + + if (get_sram_size() != 0x800) + { + fatalerror("ascii16_sram: Unsupported SRAM size\n"); + } + + m_bank_mask = banks - 1; + m_sram_select_mask = banks; + + restore_banks(); +} + + +READ8_MEMBER(msx_cart_ascii16_sram::read_cart) +{ + if ( offset >= 0x4000 && offset < 0xC000 ) + { + UINT8 bank = offset >> 15; + + if (m_bank_base[bank] != NULL) + { + if (m_selected_bank[bank] & m_sram_select_mask) + { + return m_bank_base[bank][offset & 0x7ff]; + } + else + { + return m_bank_base[bank][offset & 0x3fff]; + } + } + } + return 0xff; +} + + +WRITE8_MEMBER(msx_cart_ascii16_sram::write_cart) +{ + if (offset >= 0x6000 && offset < 0x6800) + { + m_selected_bank[0] = data; + setup_bank(0); + } + + if (offset >= 0x7000 && offset < 0x7800) + { + m_selected_bank[1] = data; + setup_bank(1); + } + + if (offset >= 0x8000 && offset < 0xc000) + { + if ((m_selected_bank[1] & m_sram_select_mask) && !(m_selected_bank[1] & ~(m_sram_select_mask | m_bank_mask))) + { + // Write to SRAM + m_bank_base[1][offset & 0x7ff] = data; + } + } +} + + + +msx_cart_msxwrite::msx_cart_msxwrite(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, MSX_CART_MSXWRITE, "MSX Cartridge - MSXWRITE", tag, owner, clock, "msx_cart_msxwrite", __FILE__) + , msx_cart_interface(mconfig, *this) + , m_bank_mask(0) +{ + for (int i = 0; i < 2; i++) + { + m_selected_bank[i] = 0; + m_bank_base[i] = NULL; + } +} + + +void msx_cart_msxwrite::device_start() +{ + save_item(NAME(m_selected_bank)); + + machine().save().register_postload(save_prepost_delegate(FUNC(msx_cart_msxwrite::restore_banks), this)); +} + + +void msx_cart_msxwrite::restore_banks() +{ + for (int i = 0; i < 2; i++) + { + m_bank_base[i] = get_rom_base() + (m_selected_bank[i] & m_bank_mask) * 0x4000; + } +} + + +void msx_cart_msxwrite::device_reset() +{ + for (int i = 0; i < 2; i++) + { + m_selected_bank[i] = 0; + } +} + + +void msx_cart_msxwrite::initialize_cartridge() +{ + UINT32 size = get_rom_size(); + + if ( size > 256 * 0x4000 ) + { + fatalerror("msxwrite: ROM is too big\n"); + } + + UINT16 banks = size / 0x4000; + + if (size != banks * 0x4000 || (~(banks - 1) % banks)) + { + fatalerror("msxwrite: Invalid ROM size\n"); + } + + m_bank_mask = banks - 1; + + restore_banks(); +} + + +READ8_MEMBER(msx_cart_msxwrite::read_cart) +{ + if ( offset >= 0x4000 && offset < 0xC000 ) + { + return m_bank_base[offset >> 15][offset & 0x3fff]; + } + return 0xff; +} + + +WRITE8_MEMBER(msx_cart_msxwrite::write_cart) +{ + // The rom writes to 6fff and 7fff for banking, unknown whether + // other locations also trigger banking. + switch (offset) + { + case 0x6fff: + m_selected_bank[0] = data; + m_bank_base[0] = get_rom_base() + (m_selected_bank[0] & m_bank_mask) * 0x4000; + break; + + case 0x7fff: + m_selected_bank[1] = data; + m_bank_base[1] = get_rom_base() + (m_selected_bank[1] & m_bank_mask) * 0x4000; + break; + } +} diff --git a/src/devices/bus/msx_cart/ascii.h b/src/devices/bus/msx_cart/ascii.h new file mode 100644 index 00000000000..e23ce939e31 --- /dev/null +++ b/src/devices/bus/msx_cart/ascii.h @@ -0,0 +1,141 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +#ifndef __MSX_CART_ASCII_H +#define __MSX_CART_ASCII_H + +#include "bus/msx_cart/cartridge.h" + + +extern const device_type MSX_CART_ASCII8; +extern const device_type MSX_CART_ASCII16; +extern const device_type MSX_CART_ASCII8_SRAM; +extern const device_type MSX_CART_ASCII16_SRAM; +extern const device_type MSX_CART_MSXWRITE; + + +class msx_cart_ascii8 : public device_t + , public msx_cart_interface +{ +public: + msx_cart_ascii8(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + virtual void initialize_cartridge(); + + virtual DECLARE_READ8_MEMBER(read_cart); + virtual DECLARE_WRITE8_MEMBER(write_cart); + + void restore_banks(); + +private: + UINT8 m_bank_mask; + UINT8 m_selected_bank[4]; + UINT8 *m_bank_base[4]; +}; + + +class msx_cart_ascii16 : public device_t + , public msx_cart_interface +{ +public: + msx_cart_ascii16(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + virtual void initialize_cartridge(); + + virtual DECLARE_READ8_MEMBER(read_cart); + virtual DECLARE_WRITE8_MEMBER(write_cart); + + void restore_banks(); + +private: + UINT8 m_bank_mask; + UINT8 m_selected_bank[2]; + UINT8 *m_bank_base[2]; +}; + + +class msx_cart_ascii8_sram : public device_t + , public msx_cart_interface +{ +public: + msx_cart_ascii8_sram(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + virtual void initialize_cartridge(); + + virtual DECLARE_READ8_MEMBER(read_cart); + virtual DECLARE_WRITE8_MEMBER(write_cart); + + void restore_banks(); + +private: + UINT8 m_bank_mask; + UINT8 m_selected_bank[4]; + UINT8 *m_bank_base[4]; + UINT8 m_sram_select_mask; + + void setup_bank(UINT8 bank); +}; + + +class msx_cart_ascii16_sram : public device_t + , public msx_cart_interface +{ +public: + msx_cart_ascii16_sram(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + virtual void initialize_cartridge(); + + virtual DECLARE_READ8_MEMBER(read_cart); + virtual DECLARE_WRITE8_MEMBER(write_cart); + + void restore_banks(); + +private: + UINT8 m_bank_mask; + UINT8 m_selected_bank[2]; + UINT8 *m_bank_base[2]; + UINT8 m_sram_select_mask; + + void setup_bank(UINT8 bank); +}; + + +class msx_cart_msxwrite : public device_t + , public msx_cart_interface +{ +public: + msx_cart_msxwrite(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + virtual void initialize_cartridge(); + + virtual DECLARE_READ8_MEMBER(read_cart); + virtual DECLARE_WRITE8_MEMBER(write_cart); + + void restore_banks(); + +private: + UINT8 m_bank_mask; + UINT8 m_selected_bank[2]; + UINT8 *m_bank_base[2]; +}; + +#endif diff --git a/src/devices/bus/msx_cart/bm_012.c b/src/devices/bus/msx_cart/bm_012.c new file mode 100644 index 00000000000..89430da93f2 --- /dev/null +++ b/src/devices/bus/msx_cart/bm_012.c @@ -0,0 +1,112 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +/*********************************************************************************** + +Emulation for the MSX BM-012 Midi cartridge that was sold together with Midisaurus. + +TODO: +- hook up all the other signals for the CTC, SIO +- which type of SIO hookup is used? tmpz84c015af supports SIO/0, SIO/1, and SIO/2 +- since the SIO signals are not hooked up, the midi in/thru/out ports are also not + implemented yet. Channel A seems to be used for sending midi data. +- proper irq handling taking the irq priority into account is not implemented +- the hookup between 2 PIOs is educated guess work; it could be incorrect + +***********************************************************************************/ + +#include "emu.h" +#include "bm_012.h" +#include "cpu/z80/z80.h" + + +const device_type MSX_CART_BM_012 = &device_creator; + + +msx_cart_bm_012::msx_cart_bm_012(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, MSX_CART_BM_012, "MSX Cartridge - BM-012", tag, owner, clock, "msx_cart_bm_012", __FILE__) + , msx_cart_interface(mconfig, *this) + , m_tmpz84c015af(*this, "tmpz84c015af") + , m_bm012_pio(*this, "bm012_pio") + , m_mdthru(*this, "mdthru") +{ +} + + +static ADDRESS_MAP_START( bm_012_memory_map, AS_PROGRAM, 8, msx_cart_bm_012 ) + AM_RANGE(0x0000, 0x7fff) AM_ROM + AM_RANGE(0xe000, 0xffff) AM_RAM +ADDRESS_MAP_END + + +static MACHINE_CONFIG_FRAGMENT( msx_cart_bm_012 ) + // 12MHz XTAL @ X1 + // Toshiba TMPZ84C015AF-6 (@U5) components: + // - Z80 + // - CTC + // - SIO + // - PIO + // - CGC + // - WDT + MCFG_CPU_ADD("tmpz84c015af", TMPZ84C015, XTAL_12MHz/2) /* 6 MHz */ + MCFG_CPU_PROGRAM_MAP(bm_012_memory_map) + // PIO callbacks + MCFG_TMPZ84C015_IN_PA_CB(DEVREAD8("bm012_pio", z80pio_device, pa_r)) + MCFG_TMPZ84C015_OUT_PA_CB(DEVWRITE8("bm012_pio", z80pio_device, pa_w)) + MCFG_TMPZ84C015_IN_PB_CB(DEVREAD8("bm012_pio", z80pio_device, pb_r)) + MCFG_TMPZ84C015_OUT_PB_CB(DEVWRITE8("bm012_pio", z80pio_device, pb_w)) + MCFG_TMPZ84C015_OUT_BRDY_CB(DEVWRITELINE("bm012_pio", z80pio_device, strobe_b)) + // SIO callbacks + MCFG_TMPZ84C015_OUT_TXDA_CB(DEVWRITELINE("mdout", midi_port_device, write_txd)) + + // Sony CXK5864BSP-10L (8KB ram) + // Sharp LH0081A Z80A-PIO-0 - For communicating between the MSX and the TMP + MCFG_DEVICE_ADD("bm012_pio", Z80PIO, XTAL_3_579545MHz) // ????? + MCFG_Z80PIO_OUT_PA_CB(DEVWRITE8("tmpz84c015af", tmpz84c015_device, pa_w)) + MCFG_Z80PIO_IN_PA_CB(DEVREAD8("tmpz84c015af", tmpz84c015_device, pa_r)) + MCFG_Z80PIO_OUT_PB_CB(DEVWRITE8("tmpz84c015af", tmpz84c015_device, pb_w)) + MCFG_Z80PIO_IN_PB_CB(DEVREAD8("tmpz84c015af", tmpz84c015_device, pb_r)) + MCFG_Z80PIO_OUT_BRDY_CB(DEVWRITELINE("tmpz84c015af", tmpz84c015_device, strobe_b)) + + // MIDI ports + MCFG_MIDI_PORT_ADD("mdin", midiin_slot, "midiin") + MCFG_MIDI_RX_HANDLER(WRITELINE(msx_cart_bm_012, midi_in)) + + MCFG_MIDI_PORT_ADD("mdthru", midiout_slot, "midiout") + + MCFG_MIDI_PORT_ADD("mdout", midiout_slot, "midiout") +MACHINE_CONFIG_END + + +machine_config_constructor msx_cart_bm_012::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( msx_cart_bm_012 ); +} + + +ROM_START( msx_cart_bm_012 ) + ROM_REGION(0x8000, "tmpz84c015af", 0) + // The rom chip at U4 is a 27256, but it contains the same 8KB duplicated 4 times + ROM_LOAD("midi_v1.00.u4", 0x0, 0x8000, CRC(840c9e74) SHA1(6d07637ad3a61b509221ed4650eed18442371010)) +ROM_END + + +const rom_entry *msx_cart_bm_012::device_rom_region() const +{ + return ROM_NAME( msx_cart_bm_012 ); +} + + +void msx_cart_bm_012::device_start() +{ + // Install IO read/write handlers + address_space &space = machine().device("maincpu")->space(AS_IO); + space.install_write_handler(0x70, 0x73, write8_delegate(FUNC(z80pio_device::write_alt), m_bm012_pio.target())); + space.install_read_handler(0x70, 0x73, read8_delegate(FUNC(z80pio_device::read_alt), m_bm012_pio.target())); +} + + +WRITE_LINE_MEMBER(msx_cart_bm_012::midi_in) +{ + m_mdthru->write_txd(state); + m_tmpz84c015af->rxb_w(state); +} diff --git a/src/devices/bus/msx_cart/bm_012.h b/src/devices/bus/msx_cart/bm_012.h new file mode 100644 index 00000000000..ce0ad337777 --- /dev/null +++ b/src/devices/bus/msx_cart/bm_012.h @@ -0,0 +1,34 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +#ifndef __MSX_CART_BM_012_H +#define __MSX_CART_BM_012_H + +#include "bus/msx_cart/cartridge.h" +#include "cpu/z80/tmpz84c015.h" +#include "bus/midi/midi.h" + + +extern const device_type MSX_CART_BM_012; + + +class msx_cart_bm_012 : public device_t + , public msx_cart_interface +{ +public: + msx_cart_bm_012(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual const rom_entry *device_rom_region() const; + virtual void device_start(); + + DECLARE_WRITE_LINE_MEMBER(midi_in); + +private: + required_device m_tmpz84c015af; + required_device m_bm012_pio; + required_device m_mdthru; +}; + + +#endif diff --git a/src/devices/bus/msx_cart/cartridge.c b/src/devices/bus/msx_cart/cartridge.c new file mode 100644 index 00000000000..7f990101a08 --- /dev/null +++ b/src/devices/bus/msx_cart/cartridge.c @@ -0,0 +1,109 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol + +#include "emu.h" +#include "cartridge.h" +#include "arc.h" +#include "ascii.h" +#include "bm_012.h" +#include "crossblaim.h" +#include "disk.h" +#include "dooly.h" +#include "fmpac.h" +#include "fs_sr022.h" +#include "halnote.h" +#include "hfox.h" +#include "holy_quran.h" +#include "konami.h" +#include "korean.h" +#include "majutsushi.h" +#include "moonsound.h" +#include "msx_audio.h" +#include "msxdos2.h" +#include "nomapper.h" +#include "rtype.h" +#include "superloderunner.h" +#include "super_swangi.h" +#include "yamaha.h" + + +SLOT_INTERFACE_START(msx_cart) + SLOT_INTERFACE_INTERNAL("nomapper", MSX_CART_NOMAPPER) + SLOT_INTERFACE_INTERNAL("msxdos2", MSX_CART_MSXDOS2) + SLOT_INTERFACE_INTERNAL("konami_scc", MSX_CART_KONAMI_SCC) + SLOT_INTERFACE_INTERNAL("konami", MSX_CART_KONAMI) + SLOT_INTERFACE_INTERNAL("ascii8", MSX_CART_ASCII8) + SLOT_INTERFACE_INTERNAL("ascii16", MSX_CART_ASCII16) + SLOT_INTERFACE_INTERNAL("gamemaster2", MSX_CART_GAMEMASTER2) + SLOT_INTERFACE_INTERNAL("ascii8_sram", MSX_CART_ASCII8_SRAM) + SLOT_INTERFACE_INTERNAL("ascii16_sram", MSX_CART_ASCII16_SRAM) + SLOT_INTERFACE_INTERNAL("rtype", MSX_CART_RTYPE) + SLOT_INTERFACE_INTERNAL("majutsushi", MSX_CART_MAJUTSUSHI) + SLOT_INTERFACE_INTERNAL("fmpac", MSX_CART_FMPAC) + SLOT_INTERFACE_INTERNAL("fs_sr022", MSX_CART_FS_SR022) + SLOT_INTERFACE_INTERNAL("superloderunner", MSX_CART_SUPERLODERUNNER) + SLOT_INTERFACE_INTERNAL("synthesizer", MSX_CART_SYNTHESIZER) + SLOT_INTERFACE_INTERNAL("cross_blaim", MSX_CART_CROSSBLAIM) + SLOT_INTERFACE_INTERNAL("korean_80in1", MSX_CART_KOREAN_80IN1) + SLOT_INTERFACE_INTERNAL("korean_90in1", MSX_CART_KOREAN_90IN1) + SLOT_INTERFACE_INTERNAL("korean_126in1", MSX_CART_KOREAN_126IN1) + SLOT_INTERFACE_INTERNAL("msxwrite", MSX_CART_MSXWRITE) + SLOT_INTERFACE_INTERNAL("sound_snatcher", MSX_CART_SOUND_SNATCHER) + SLOT_INTERFACE_INTERNAL("sound_sdsnatch", MSX_CART_SOUND_SDSNATCHER) + SLOT_INTERFACE_INTERNAL("msxaud_hxmu900", MSX_CART_MSX_AUDIO_HXMU900) + SLOT_INTERFACE_INTERNAL("msxaud_fsca1", MSX_CART_MSX_AUDIO_FSCA1) + SLOT_INTERFACE_INTERNAL("msxaud_nms1205", MSX_CART_MSX_AUDIO_NMS1205) + SLOT_INTERFACE_INTERNAL("super_swangi", MSX_CART_SUPER_SWANGI) + SLOT_INTERFACE_INTERNAL("hfox", MSX_CART_HFOX) + SLOT_INTERFACE_INTERNAL("keyboard_master", MSX_CART_KEYBOARD_MASTER) + SLOT_INTERFACE_INTERNAL("holy_quran", MSX_CART_HOLY_QURAN) + SLOT_INTERFACE_INTERNAL("dooly", MSX_CART_DOOLY) + SLOT_INTERFACE_INTERNAL("halnote", MSX_CART_HALNOTE) + SLOT_INTERFACE_INTERNAL("arc", MSX_CART_ARC) + SLOT_INTERFACE_INTERNAL("disk_vy0010", MSX_CART_VY0010) + SLOT_INTERFACE_INTERNAL("disk_fsfd1", MSX_CART_FSFD1) + SLOT_INTERFACE_INTERNAL("disk_fsfd1a", MSX_CART_FSFD1A) + SLOT_INTERFACE_INTERNAL("disk_fscf351", MSX_CART_FSCF351) + SLOT_INTERFACE("bm_012", MSX_CART_BM_012) + SLOT_INTERFACE("moonsound", MSX_CART_MOONSOUND) +SLOT_INTERFACE_END + + +msx_cart_interface::msx_cart_interface(const machine_config &mconfig, device_t &device) + : device_slot_card_interface(mconfig, device) + , m_out_irq_cb(*this) +{ +} + +void msx_cart_interface::rom_alloc(UINT32 size) +{ + m_rom.resize(size); + memset(&m_rom[0], 0xff, size); +} + +void msx_cart_interface::rom_vlm5030_alloc(UINT32 size) +{ + m_rom_vlm5030.resize(size); + memset(&m_rom_vlm5030[0], 0xff, size); +} + +void msx_cart_interface::ram_alloc(UINT32 size) +{ + m_ram.resize(size); + memset(&m_ram[0], 0x00, size); +} + +void msx_cart_interface::sram_alloc(UINT32 size) +{ + m_sram.resize(size); + memset(&m_sram[0], 0x00, size); +} + + +// Several yamaha machines had 60 pin expansion slots. The pinouts of these slots was +// exactly the same as the regular 50 pin cartridge slots. The lowest 10 pins are simply +// not connected. +SLOT_INTERFACE_START(msx_yamaha_60pin) + SLOT_INTERFACE("sfg01", MSX_CART_SFG01) + SLOT_INTERFACE("sfg05", MSX_CART_SFG05) +SLOT_INTERFACE_END diff --git a/src/devices/bus/msx_cart/cartridge.h b/src/devices/bus/msx_cart/cartridge.h new file mode 100644 index 00000000000..6deb2140dea --- /dev/null +++ b/src/devices/bus/msx_cart/cartridge.h @@ -0,0 +1,52 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +#ifndef __MSX_CART_CARTRIDGE_H +#define __MSX_CART_CARTRIDGE_H + + +SLOT_INTERFACE_EXTERN(msx_cart); +SLOT_INTERFACE_EXTERN(msx_yamaha_60pin); // 60 pin expansion slots as found in yamaha machines + + +class msx_cart_interface : public device_slot_card_interface +{ +public: + msx_cart_interface(const machine_config &mconfig, device_t &device); + + template void set_out_irq_cb(_Object object) { m_out_irq_cb.set_callback(object); m_out_irq_cb.resolve_safe(); } + + // This is called after loading cartridge contents and allows the cartridge + // implementation to perform some additional initialization based on the + // cartridge contents. + virtual void initialize_cartridge() {} + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_cart) { return 0xff; } + virtual DECLARE_WRITE8_MEMBER(write_cart) {} + + // ROM/RAM/SRAM management + // Mainly used by the cartridge slot when loading images + void rom_alloc(UINT32 size); + void ram_alloc(UINT32 size); + void rom_vlm5030_alloc(UINT32 size); + void sram_alloc(UINT32 size); + + UINT8* get_rom_base() { return &m_rom[0]; } + UINT8* get_rom_vlm5030_base() { return &m_rom_vlm5030[0]; } + UINT8* get_ram_base() { return &m_ram[0]; } + UINT8* get_sram_base() { return &m_sram[0]; } + UINT32 get_rom_size() { return m_rom.size(); } + UINT32 get_rom_vlm5030_size() { return m_rom_vlm5030.size(); } + UINT32 get_ram_size() { return m_ram.size(); } + UINT32 get_sram_size() { return m_sram.size(); } + +protected: + dynamic_buffer m_rom; + dynamic_buffer m_ram; + dynamic_buffer m_rom_vlm5030; + dynamic_buffer m_sram; + devcb_write_line m_out_irq_cb; +}; + + +#endif diff --git a/src/devices/bus/msx_cart/crossblaim.c b/src/devices/bus/msx_cart/crossblaim.c new file mode 100644 index 00000000000..2b2edece1f3 --- /dev/null +++ b/src/devices/bus/msx_cart/crossblaim.c @@ -0,0 +1,82 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +#include "emu.h" +#include "crossblaim.h" + +const device_type MSX_CART_CROSSBLAIM = &device_creator; + + +msx_cart_crossblaim::msx_cart_crossblaim(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, MSX_CART_CROSSBLAIM, "MSX Cartridge - Cross Blaim", tag, owner, clock, "msx_cart_crossblaim", __FILE__) + , msx_cart_interface(mconfig, *this) + , m_selected_bank(1) +{ + for (int i = 0; i < 4; i++) + { + m_bank_base[i] = NULL; + } +} + + +void msx_cart_crossblaim::device_start() +{ + save_item(NAME(m_selected_bank)); + + machine().save().register_postload(save_prepost_delegate(FUNC(msx_cart_crossblaim::restore_banks), this)); +} + + +void msx_cart_crossblaim::setup_bank() +{ + m_bank_base[0] = ( m_selected_bank & 2 ) ? NULL : get_rom_base() + ( m_selected_bank & 0x03 ) * 0x4000; + m_bank_base[2] = get_rom_base() + ( m_selected_bank & 0x03 ) * 0x4000; + m_bank_base[3] = ( m_selected_bank & 2 ) ? NULL : get_rom_base() + ( m_selected_bank & 0x03 ) * 0x4000; +} + + +void msx_cart_crossblaim::restore_banks() +{ + m_bank_base[1] = get_rom_base(); + setup_bank(); +} + + +void msx_cart_crossblaim::device_reset() +{ + m_selected_bank = 1; +} + + +void msx_cart_crossblaim::initialize_cartridge() +{ + if (get_rom_size() != 0x10000) + { + fatalerror("crossblaim: Invalid ROM size\n"); + } + + restore_banks(); +} + + +READ8_MEMBER(msx_cart_crossblaim::read_cart) +{ + UINT8 *bank_base = m_bank_base[offset >> 14]; + + if (bank_base != NULL) + { + return bank_base[offset & 0x3fff]; + } + + return 0xff; +} + + +WRITE8_MEMBER(msx_cart_crossblaim::write_cart) +{ + m_selected_bank = data & 3; + if (m_selected_bank == 0) + { + m_selected_bank = 1; + } + setup_bank(); +} diff --git a/src/devices/bus/msx_cart/crossblaim.h b/src/devices/bus/msx_cart/crossblaim.h new file mode 100644 index 00000000000..b94a3cc6e59 --- /dev/null +++ b/src/devices/bus/msx_cart/crossblaim.h @@ -0,0 +1,37 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +#ifndef __MSX_CART_CROSSBLAIM_H +#define __MSX_CART_CROSSBLAIM_H + +#include "bus/msx_cart/cartridge.h" + + +extern const device_type MSX_CART_CROSSBLAIM; + + +class msx_cart_crossblaim : public device_t + , public msx_cart_interface +{ +public: + msx_cart_crossblaim(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + virtual void initialize_cartridge(); + + virtual DECLARE_READ8_MEMBER(read_cart); + virtual DECLARE_WRITE8_MEMBER(write_cart); + + void restore_banks(); + +private: + UINT8 m_selected_bank; + UINT8 *m_bank_base[4]; + + void setup_bank(); +}; + + +#endif diff --git a/src/devices/bus/msx_cart/disk.c b/src/devices/bus/msx_cart/disk.c new file mode 100644 index 00000000000..64bc061ba35 --- /dev/null +++ b/src/devices/bus/msx_cart/disk.c @@ -0,0 +1,628 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +/***************************************************************************** + * + * MSX Floopy drive interface add-on cartridges + * + * Currently supported: + * - National FS-CF351 + FS-FD351 - MB8877A - DSDD 3.5" Floppy drive + interface + * - Panasonic FS-FD1 - WD2793? - DSDD 3.5" Floppy drive + interface + * - Panasonic FS-FD1A - TC8566F - DSDD 3.5" Floppy drive with builtin interface + * - Rom label reads: "FDC BIOS V1.0 / COPYRIGHT MEI / 1987 DASFD1AA1" + * - Philips VY-0010 (Interface cartridge + 1 3.5" SS floppy drive) + * + * Not supported yet: + * - Canon VF-100 - DSDD 3.5" Floppy drive + interface + 1 floppy disk containing MSX-DOS + * - Talent DPF-550/5 - WD1772 - DSDD 5.25" Floppy drive (360KB) plus interface (manufactured by Daewoo) + * - Rom label markings: MSX DISK / DPF 555D + * + * Drive only: + * - Philps VY-0011 - 3.5" SSDD Floppy drive + * - Talent DPF-560 - DSDD 5.25" Floppy drive + * + * To be investigated: + * - AVT DPF-500 - WD1772? - DD 5.25" Floppy drive + interface + 1 floppy disk containing MSX-DOS + * - Daewoo CPF-350C - DD 3.5" Floppy drive + * - Daewoo CPF-360C - DD 3.5" Floppy drive + * - Daewoo MPF-550 - DSDD 5.25" Floppy drive + interface + * = Daewoo MPF-560 - DSDD 5.25" Floppy drive + * - DMX Interface para drive - Interface + 1 floppy disk containg MSX-DOS 1.0 + * - Fenner FD-300 - DSDD 3.5" Floppy drive + * - Fenner FD-400 - Floppy interface for FD-300 + * - Hitachi MPF-310CH - DSDD Floppy drive + * - hitachi MPC-310CH - Interface for MPF-310CH + * - JVC HC-F303 - Floppy drive + * - Mitsubishi ML-30FD - DSDD 3.5" Floppy drive + * - Mitsubishi ML-30DC - Floppy interface + * - Philips NMS-1200 - Floppy interface + * - Philips NMS-9111 - 3.5" Floppy drive + * - Philips NMS-9113 - 3.5" Floppy drive + * - Sakir AFD-01 - SSDD 3.5" Floppy drive + * - Sanyo MFD-001 - 360KB 5.25" Floppy drive + interface? + * - Sanyo MFD-002 - 360KB 5.25" Floppy drive (2nd drive for MFD-001?) + * - Sanyo MFD-25FD - DSDD 3.5" Floppy drive + * - Sanyo MFD-35 - SSDD 3.5" Floppy drive + interface + * - Sharp Epcom HB-3600 - WD2793 - Floppy interface Intended to be used with HB-6000 (5.25" SS? drive), Brazil + * - Sold as part of HB-3600 + HB-6000 bundle according to wikipedia + * - Sharp Epcom HB-6000 - 360KB 5.25" drive + * - Sony HBD-100 - SSDD 3.5" Floppy drivbe + * - Sony HBD-20W - DSDD 3.5" Floppy drive + * - Sony HBD-30X/30W - DSDD 3.5" drive + * - Sony HBD-50 - SSDD 3.5" drive (drive only?) + * - Sony HBD-F1 (interface only?) - WD2793 - 3.5" DSDD drive?? + * - Sony HBX-30 (interface only, meant for 30W) - WD2793 + * - Sony WS2793-02 - WD2793? - Interface for HBD-50 + * - Spectravideo SVI-213 - MB8877A - Floppy interface for SVI-707 + * - Spectravideo SVI-707 - MB8877A - 5.25" SSDD? drive (320KB) - There seem to be 2 ROMs on the PCB, apparently one is for MSX and one is for CP/M operation? + * - See https://plus.google.com/photos/115644813183575095400/albums/5223347091895442113?banner=pwa + * - Spectravideo SVI-717 - Interface for 2 drives? + * - Spectravideo SVI-787 - SSDD 3.5" Floppy drive + * - Spectravideo SVI-801 - Interface + * - Toshiba HX-F100 - Floppy drive + * - Toshiba HX-F101 - SSDD 3.5" Floppy drive + interface + * - Yamaha FD-01 - SSDD 3.5" Floppy drive + * - Yamaha FD-03 - DSDD 3.5" Floppy drive + * - Yamaha FD-05 - DSDD 3.5" Floppy drive + * - Other models: + * - ACVS 3.5" Floppy drive interface + * - Tradeco floppy interface + * - Angeisa 3.5" Floppy drive + * - Angeisa 5.25" 360KB Floppy drive + * - Angeisa 5.25" 720KB Floppy drive + * - Angeisa floppy drive interface + * - Datagame floppy drive interface + * - Digital Design DSDD 3.5" Floppy drive + * - Digital Design 5.25" 360KB Floppy drive + * - Digital Design 5.25" 720KB Floppy drive + * - Digital Design floppy drive interface + * - DMX 3.5" Floppy drive + * - DMX floppy drive interface + * - Liftron 3.5" Floppy drive + * - Liftron floppy drive interface + * - Microsol DRX-180 5.25" Floppy drive FS + * - Microsol DRX-360 5.25" Floppy drive FD + * - Microsol DRX-720 5.25" Floppy drive 80 track (720KB) + * - Microsol CDX-1 floppy interface + * - Microsol CDX-2 floppy interface + * - Racidata 3.5" Floppy drive + * - Racidata 5.25" Floppy drive + * - Racidata floppy interface + * - Sileman Triton-s 3.5" FS Floppy drive + * - Sileman Triton-d 3.5" FD Floppy drive + * - Talent TPF-723 5.25" Floppy drive + * - Talent TPF-725 5.25" Flpppy drive + * - Technohead Leopard 3.5" Floppy drive + * - Technohead Leopard 5.25" Floppy drive + * - Technohead floppy interface + * - More?? + * + * Several model references found in Vitropedia (ISBN 9781409212774) + * + ****************************************************************************/ + +#include "emu.h" +#include "disk.h" +#include "formats/msx_dsk.h" + + +const device_type MSX_CART_VY0010 = &device_creator; +const device_type MSX_CART_FSFD1 = &device_creator; +const device_type MSX_CART_FSFD1A = &device_creator; +const device_type MSX_CART_FSCF351 = &device_creator; + + +FLOPPY_FORMATS_MEMBER( msx_cart_disk::floppy_formats ) + FLOPPY_MSX_FORMAT +FLOPPY_FORMATS_END + + +static SLOT_INTERFACE_START( msx_floppies ) + SLOT_INTERFACE( "35dd", FLOPPY_35_DD ) + SLOT_INTERFACE( "35ssdd", FLOPPY_35_SSDD ) +SLOT_INTERFACE_END + + +msx_cart_disk::msx_cart_disk(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname) + : device_t(mconfig, type, name, tag, owner, clock, shortname, __FILE__) + , msx_cart_interface(mconfig, *this) + , m_floppy0(*this, "fdc:0") + , m_floppy1(*this, "fdc:1") + , m_floppy(NULL) +{ +} + + +msx_cart_disk_wd::msx_cart_disk_wd(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname) + : msx_cart_disk(mconfig, type, name, tag, owner, clock, shortname) + , m_fdc(*this, "fdc") +{ +} + + +msx_cart_disk_type1::msx_cart_disk_type1(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname) + : msx_cart_disk_wd(mconfig, type, name, tag, owner, clock, shortname) + , m_control(0) +{ +} + + +msx_cart_disk_type2::msx_cart_disk_type2(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname) + : msx_cart_disk_wd(mconfig, type, name, tag, owner, clock, shortname) + , m_control(0) +{ +} + + +msx_cart_vy0010::msx_cart_vy0010(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : msx_cart_disk_type1(mconfig, MSX_CART_VY0010, "MSX Cartridge - VY0010", tag, owner, clock, "msx_cart_vy0010") +{ +} + + +msx_cart_fsfd1::msx_cart_fsfd1(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : msx_cart_disk_type1(mconfig, MSX_CART_FSFD1, "MSX Cartridge - FS-FD1", tag, owner, clock, "msx_cart_fsfd1") +{ +} + + +msx_cart_fscf351::msx_cart_fscf351(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : msx_cart_disk_type2(mconfig, MSX_CART_FSCF351, "MSX Cartridge - FS-CF351", tag, owner, clock, "msx_cart_fscf351") +{ +} + + +msx_cart_disk_tc8566::msx_cart_disk_tc8566(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname) + : msx_cart_disk(mconfig, type, name, tag, owner, clock, shortname) + , m_fdc(*this, "fdc") +{ +} + + +msx_cart_fsfd1a::msx_cart_fsfd1a(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : msx_cart_disk_tc8566(mconfig, MSX_CART_FSFD1A, "MSX Cartridge - FS-FD1A", tag, owner, clock, "msx_cart_fsfd1a") +{ +} + + +void msx_cart_disk::initialize_cartridge() +{ + if ( get_rom_size() != 0x4000 ) + { + fatalerror("msx_cart_disk: Invalid ROM size\n"); + } +} + + +static MACHINE_CONFIG_FRAGMENT( vy0010 ) + // From VY-0010 schematic: + // HLT pulled high + // SSO/-ENMF + -DDEN + ENP + -5/8 - pulled low + // READY inverted in VY-0010 cartridge and pulled low on VY-0010/VY-0011 floppy drive + MCFG_WD2793_ADD("fdc", XTAL_4MHz / 4) + MCFG_WD_FDC_FORCE_READY + + // Single sided 3.5" floppy drive + MCFG_FLOPPY_DRIVE_ADD("fdc:0", msx_floppies, "35ssdd", msx_cart_disk::floppy_formats) + + // Attach software lists + // We do not know in what kind of machine the user has inserted the floppy interface + // so we list all msx floppy software lists. + // + MCFG_SOFTWARE_LIST_ADD("flop_list","msx2_flop") + MCFG_SOFTWARE_LIST_COMPATIBLE_ADD("msx1_flop_list","msx1_flop") +MACHINE_CONFIG_END + + +machine_config_constructor msx_cart_vy0010::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( vy0010 ); +} + + +static MACHINE_CONFIG_FRAGMENT( fsfd1 ) + MCFG_WD2793_ADD("fdc", XTAL_4MHz / 4) + + // Double sided 3.5" floppy drive + MCFG_FLOPPY_DRIVE_ADD("fdc:0", msx_floppies, "35dd", msx_cart_disk::floppy_formats) + + // Attach software lists + // We do not know in what kind of machine the user has inserted the floppy interface + // so we list all msx floppy software lists. + // + MCFG_SOFTWARE_LIST_ADD("flop_list","msx2_flop") + MCFG_SOFTWARE_LIST_COMPATIBLE_ADD("msx1_flop_list","msx1_flop") +MACHINE_CONFIG_END + + +machine_config_constructor msx_cart_fsfd1::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( fsfd1 ); +} + + +static MACHINE_CONFIG_FRAGMENT( fsfd1a ) + MCFG_TC8566AF_ADD("fdc") + + // Double sided 3.5" floppy drive + MCFG_FLOPPY_DRIVE_ADD("fdc:0", msx_floppies, "35dd", msx_cart_disk::floppy_formats) + + // Attach software lists + // We do not know in what kind of machine the user has inserted the floppy interface + // so we list all msx floppy software lists. + // + MCFG_SOFTWARE_LIST_ADD("flop_list","msx2_flop") + MCFG_SOFTWARE_LIST_COMPATIBLE_ADD("msx1_flop_list","msx1_flop") +MACHINE_CONFIG_END + + +machine_config_constructor msx_cart_fsfd1a::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( fsfd1a ); +} + + +static MACHINE_CONFIG_FRAGMENT( fscf351 ) + MCFG_MB8877_ADD("fdc", XTAL_4MHz / 4) + MCFG_WD_FDC_FORCE_READY + + // Double sided 3.5" floppy drive + MCFG_FLOPPY_DRIVE_ADD("fdc:0", msx_floppies, "35dd", msx_cart_disk::floppy_formats) + + // Attach software lists + // We do not know in what kind of machine the user has inserted the floppy interface + // so we list all msx floppy software lists. + // + MCFG_SOFTWARE_LIST_ADD("flop_list","msx2_flop") + MCFG_SOFTWARE_LIST_COMPATIBLE_ADD("msx1_flop_list","msx1_flop") +MACHINE_CONFIG_END + + +machine_config_constructor msx_cart_fscf351::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( fscf351 ); +} + + +void msx_cart_disk_type1::device_start() +{ + save_item(NAME(m_side_control)); + save_item(NAME(m_control)); + + machine().save().register_postload(save_prepost_delegate(FUNC(msx_cart_disk_type1::post_load), this)); +} + + +void msx_cart_disk_type1::post_load() +{ + UINT8 data = m_control; + + // To make sure the FDD busy led status gets set correctly + m_control ^= 0x40; + + set_control(data); +} + + +void msx_cart_disk_type1::set_control(UINT8 data) +{ + UINT8 old_m_control = m_control; + + m_control = data; + + switch (m_control & 0x03) + { + case 0: + case 2: + m_floppy = m_floppy0 ? m_floppy0->get_device() : NULL; + break; + + case 1: + m_floppy = m_floppy1 ? m_floppy1->get_device() : NULL; + break; + + default: + m_floppy = NULL; + break; + } + + if (m_floppy) + { + m_floppy->mon_w((m_control & 0x80) ? 0 : 1); + m_floppy->ss_w(m_side_control & 0x01); + } + + m_fdc->set_floppy(m_floppy); + + if ((old_m_control ^ m_control) & 0x40) + { + set_led_status(machine(), 0, !(m_control & 0x40)); + } +} + + +void msx_cart_disk_type1::set_side_control(UINT8 data) +{ + m_side_control = data; + + if (m_floppy) + { + m_floppy->ss_w(m_side_control & 0x01); + } +} + + +void msx_cart_disk_type1::device_reset() +{ + m_fdc->dden_w(false); +} + + +READ8_MEMBER(msx_cart_disk_type1::read_cart) +{ + switch (offset) + { + case 0x7ff8: + case 0xbff8: + return m_fdc->status_r(); + + case 0x7ff9: + case 0xbff9: + return m_fdc->track_r(); + + case 0x7ffa: + case 0xbffa: + return m_fdc->sector_r(); + + case 0x7ffb: + case 0xbffb: + return m_fdc->data_r(); + + case 0x7ffc: + case 0xbffc: + return 0xfe | (m_side_control & 0x01); + + case 0x7ffd: + case 0xbffd: + return ( m_control & 0x83 ) | 0x78; + + case 0x7fff: + case 0xbfff: + return 0x3f | (m_fdc->intrq_r() ? 0 : 0x40) | (m_fdc->drq_r() ? 0 : 0x80); + } + + if (offset >= 0x4000 && offset < 0x8000) + { + return get_rom_base()[offset & 0x3fff]; + } + return 0xff; +} + + +WRITE8_MEMBER(msx_cart_disk_type1::write_cart) +{ + switch (offset) + { + case 0x7ff8: + case 0xbff8: + m_fdc->cmd_w(data); + break; + + case 0x7ff9: + case 0xbff9: + m_fdc->track_w(data); + break; + + case 0x7ffa: + case 0xbffa: + m_fdc->sector_w(data); + break; + + case 0x7ffb: + case 0xbffb: + m_fdc->data_w(data); + break; + + case 0x7ffc: + case 0xbffc: + set_side_control(data); + break; + + case 0x7ffd: + case 0xbffd: + set_control(data); + break; + + default: + logerror("msx_cart_disk_type1::write_cart: Unmapped write writing %02x to %04x\n", data, offset); + break; + } +} + + +void msx_cart_disk_type2::device_start() +{ + save_item(NAME(m_control)); + + machine().save().register_postload(save_prepost_delegate(FUNC(msx_cart_disk_type2::post_load), this)); +} + + +void msx_cart_disk_type2::device_reset() +{ + m_fdc->dden_w(false); +} + + +void msx_cart_disk_type2::post_load() +{ + UINT8 data = m_control; + + // To make sure the FDD busy led status gets set correctly + m_control ^= 0x40; + + set_control(data); +} + + +void msx_cart_disk_type2::set_control(UINT8 data) +{ + UINT8 old_m_control = m_control; + + m_control = data; + + switch (m_control & 3) + { + case 1: + m_floppy = m_floppy0 ? m_floppy0->get_device() : NULL; + break; + + case 2: + m_floppy = m_floppy1 ? m_floppy1->get_device() : NULL; + break; + + default: + m_floppy = NULL; + break; + } + + if (m_floppy) + { + m_floppy->mon_w((m_control & 0x08) ? 0 : 1); + m_floppy->ss_w((m_control & 0x04) ? 1 : 0); + } + + m_fdc->set_floppy(m_floppy); + + if ((old_m_control ^ m_control) & 0x40) + { + set_led_status(machine(), 0, !(m_control & 0x40)); + } +} + + +READ8_MEMBER(msx_cart_disk_type2::read_cart) +{ + switch (offset) + { + case 0x7fb8: + case 0xbfb8: + return m_fdc->status_r(); + + case 0x7fb9: + case 0xbfb9: + return m_fdc->track_r(); + + case 0x7fba: + case 0xbfba: + return m_fdc->sector_r(); + + case 0x7fbb: + case 0xbfbb: + return m_fdc->data_r(); + + case 0x7fbc: + case 0xbfbc: + return 0x3f | (m_fdc->drq_r() ? 0 : 0x40) | (m_fdc->intrq_r() ? 0x80 : 0); + } + + if (offset >= 0x4000 && offset < 0x8000) + { + return get_rom_base()[offset & 0x3fff]; + } + return 0xff; +} + + +WRITE8_MEMBER(msx_cart_disk_type2::write_cart) +{ + switch (offset) + { + case 0x7fb8: + case 0xbfb8: + m_fdc->cmd_w(data); + break; + + case 0x7fb9: + case 0xbfb9: + m_fdc->track_w(data); + break; + + case 0x7fba: + case 0xbfba: + m_fdc->sector_w(data); + break; + + case 0x7fbb: + case 0xbfbb: + m_fdc->data_w(data); + break; + + case 0x7fbc: + case 0xbfbc: + set_control(data); + break; + + default: + logerror("msx_cart_disk_type2::write_cart: Unmapped write writing %02x to %04x\n", data, offset); + break; + } +} + + + + +void msx_cart_fsfd1a::device_start() +{ +} + + +void msx_cart_fsfd1a::device_reset() +{ +} + + +READ8_MEMBER(msx_cart_fsfd1a::read_cart) +{ + switch (offset) + { + case 0x7ffa: + case 0xbffa: + return m_fdc->msr_r(space, 4); + + case 0x7ffb: + case 0xbffb: + return m_fdc->fifo_r(space, 5); + } + + if (offset >= 0x4000 && offset < 0x8000) + { + return get_rom_base()[offset & 0x3fff]; + } + return 0xff; +} + + +WRITE8_MEMBER(msx_cart_fsfd1a::write_cart) +{ + switch (offset) + { + case 0x7ff8: + case 0xbff8: + m_fdc->dor_w(space, 2, data); + break; + + case 0x7ff9: + case 0xbff9: + m_fdc->cr1_w(space, 3, data); + break; + + case 0x7ffb: + case 0xbffb: + m_fdc->fifo_w(space, 5, data); + break; + + default: + logerror("msx_cart_fsfd1a::write_cart: Unmapped write writing %02x to %04x\n", data, offset); + break; + } +} diff --git a/src/devices/bus/msx_cart/disk.h b/src/devices/bus/msx_cart/disk.h new file mode 100644 index 00000000000..efe48e28255 --- /dev/null +++ b/src/devices/bus/msx_cart/disk.h @@ -0,0 +1,145 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +#ifndef __MSX_CART_DISK_H +#define __MSX_CART_DISK_H + +#include "bus/msx_cart/cartridge.h" +#include "machine/wd_fdc.h" +#include "machine/upd765.h" +#include "imagedev/flopdrv.h" +#include "imagedev/floppy.h" + + +extern const device_type MSX_CART_VY0010; +extern const device_type MSX_CART_FSFD1; +extern const device_type MSX_CART_FSFD1A; +extern const device_type MSX_CART_FSCF351; + + +class msx_cart_disk : public device_t + , public msx_cart_interface +{ +public: + msx_cart_disk(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname); + + virtual void initialize_cartridge(); + + DECLARE_FLOPPY_FORMATS(floppy_formats); + +protected: + required_device m_floppy0; + optional_device m_floppy1; + floppy_image_device *m_floppy; +}; + + +class msx_cart_disk_wd : public msx_cart_disk +{ +public: + msx_cart_disk_wd(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname); + +protected: + required_device m_fdc; +}; + + +class msx_cart_disk_type1 : public msx_cart_disk_wd +{ +public: + msx_cart_disk_type1(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + virtual DECLARE_READ8_MEMBER(read_cart); + virtual DECLARE_WRITE8_MEMBER(write_cart); + + void post_load(); + +protected: + UINT8 m_side_control; + UINT8 m_control; + + void set_side_control(UINT8 data); + void set_control(UINT8 data); +}; + + +class msx_cart_disk_type2 : public msx_cart_disk_wd +{ +public: + msx_cart_disk_type2(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + virtual DECLARE_READ8_MEMBER(read_cart); + virtual DECLARE_WRITE8_MEMBER(write_cart); + + void post_load(); + +protected: + UINT8 m_control; + + void set_control(UINT8 data); +}; + + +class msx_cart_vy0010 : public msx_cart_disk_type1 +{ +public: + msx_cart_vy0010(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual machine_config_constructor device_mconfig_additions() const; +}; + + +class msx_cart_fsfd1 : public msx_cart_disk_type1 +{ +public: + msx_cart_fsfd1(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual machine_config_constructor device_mconfig_additions() const; +}; + + +class msx_cart_fscf351 : public msx_cart_disk_type2 +{ +public: + msx_cart_fscf351(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual machine_config_constructor device_mconfig_additions() const; +}; + + +class msx_cart_disk_tc8566 : public msx_cart_disk +{ +public: + msx_cart_disk_tc8566(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname); + +protected: + required_device m_fdc; +}; + + +class msx_cart_fsfd1a : public msx_cart_disk_tc8566 +{ +public: + msx_cart_fsfd1a(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual machine_config_constructor device_mconfig_additions() const; + + virtual DECLARE_READ8_MEMBER(read_cart); + virtual DECLARE_WRITE8_MEMBER(write_cart); + +private: + +}; + + +#endif diff --git a/src/devices/bus/msx_cart/dooly.c b/src/devices/bus/msx_cart/dooly.c new file mode 100644 index 00000000000..95f2748b04a --- /dev/null +++ b/src/devices/bus/msx_cart/dooly.c @@ -0,0 +1,67 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +#include "emu.h" +#include "dooly.h" + + +const device_type MSX_CART_DOOLY = &device_creator; + + +msx_cart_dooly::msx_cart_dooly(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, MSX_CART_DOOLY, "MSX Cartridge - Dooly", tag, owner, clock, "msx_cart_dooly", __FILE__) + , msx_cart_interface(mconfig, *this) + , m_prot(0) +{ +} + + +void msx_cart_dooly::device_start() +{ + save_item(NAME(m_prot)); +} + + +void msx_cart_dooly::device_reset() +{ + m_prot = 0; +} + + +void msx_cart_dooly::initialize_cartridge() +{ + if (get_rom_size() != 0x8000) + { + fatalerror("dooly: Invalid ROM size\n"); + } +} + + +READ8_MEMBER(msx_cart_dooly::read_cart) +{ + if (offset >= 0x4000 && offset < 0xc000) + { + UINT8 data = get_rom_base()[offset - 0x4000]; + + switch (m_prot) + { + case 0x04: + data = BITSWAP8(data, 7, 6, 5, 4, 3, 1, 0, 2); + break; + } + return data; + } + return 0xff; +} + + +WRITE8_MEMBER(msx_cart_dooly::write_cart) +{ + if (offset >= 0x4000 && offset < 0xc000) + { + m_prot = data & 0x07; + if (m_prot != 0 && m_prot != 4) + { + logerror("msx_cart_dooly: unhandled write %02x to %04x\n", data, offset); + } + } +} diff --git a/src/devices/bus/msx_cart/dooly.h b/src/devices/bus/msx_cart/dooly.h new file mode 100644 index 00000000000..45ba9343fd4 --- /dev/null +++ b/src/devices/bus/msx_cart/dooly.h @@ -0,0 +1,32 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +#ifndef __MSX_CART_DOOLY_H +#define __MSX_CART_DOOLY_H + +#include "bus/msx_cart/cartridge.h" + + +extern const device_type MSX_CART_DOOLY; + + +class msx_cart_dooly : public device_t + , public msx_cart_interface +{ +public: + msx_cart_dooly(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + virtual void initialize_cartridge(); + + virtual DECLARE_READ8_MEMBER(read_cart); + virtual DECLARE_WRITE8_MEMBER(write_cart); + +private: + UINT8 m_prot; +}; + + +#endif diff --git a/src/devices/bus/msx_cart/fmpac.c b/src/devices/bus/msx_cart/fmpac.c new file mode 100644 index 00000000000..c4222094c1a --- /dev/null +++ b/src/devices/bus/msx_cart/fmpac.c @@ -0,0 +1,173 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +/********************************************************************************** + +When backing up the SRAM from an FM-PAC the file seems to be prefixed +with: PAC2 BACKUP DATA. We only store the raw sram contents. + +**********************************************************************************/ + +#include "emu.h" +#include "fmpac.h" + +const device_type MSX_CART_FMPAC = &device_creator; + + +msx_cart_fmpac::msx_cart_fmpac(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, MSX_CART_FMPAC, "MSX Cartridge - FM-PAC", tag, owner, clock, "msx_cart_fmpac", __FILE__) + , msx_cart_interface(mconfig, *this) + , m_ym2413(*this, "ym2413") + , m_selected_bank(0) + , m_bank_base(NULL) + , m_sram_active(false) + , m_opll_active(false) + , m_1ffe(0) + , m_1fff(0) + , m_7ff6(0) +{ +} + + +static MACHINE_CONFIG_FRAGMENT( fmpac ) + // This is actually incorrect. The sound output is passed back into the MSX machine where it is mixed internally and output through the system 'speaker'. + MCFG_SPEAKER_STANDARD_MONO("mono") + MCFG_SOUND_ADD("ym2413", YM2413, XTAL_10_738635MHz/3) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.40) +MACHINE_CONFIG_END + + +machine_config_constructor msx_cart_fmpac::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( fmpac ); +} + + +void msx_cart_fmpac::device_start() +{ + save_item(NAME(m_selected_bank)); + save_item(NAME(m_sram_active)); + save_item(NAME(m_opll_active)); + save_item(NAME(m_1ffe)); + save_item(NAME(m_1fff)); + save_item(NAME(m_7ff6)); + + machine().save().register_postload(save_prepost_delegate(FUNC(msx_cart_fmpac::restore_banks), this)); + + // Install IO read/write handlers + address_space &space = machine().device("maincpu")->space(AS_IO); + space.install_write_handler(0x7c, 0x7d, write8_delegate(FUNC(msx_cart_fmpac::write_ym2413), this)); +} + + +void msx_cart_fmpac::restore_banks() +{ + m_bank_base = get_rom_base() + ( m_selected_bank & 0x03 ) * 0x4000; +} + + +void msx_cart_fmpac::device_reset() +{ + m_selected_bank = 0; + m_sram_active = false; + m_opll_active = false; + m_1ffe = 0; + m_1fff = 0; + m_7ff6 = 0; +} + + +void msx_cart_fmpac::initialize_cartridge() +{ + if ( get_rom_size() != 0x10000 ) + { + fatalerror("fmpac: Invalid ROM size\n"); + } + + if ( get_sram_size() != 0x2000 ) + { + fatalerror("fmpac: Invalid SRAM size\n"); + } + + restore_banks(); +} + + +READ8_MEMBER(msx_cart_fmpac::read_cart) +{ + if (offset >= 0x4000 && offset < 0x8000) + { + if (offset == 0x7ff6) + { + return m_7ff6; + } + if (offset == 0x7ff7) + { + return m_selected_bank & 0x03; + } + if (m_sram_active) + { + if (offset & 0x2000) + { + return 0xff; + } + return get_sram_base()[offset & 0x1fff]; + } + else + { + return m_bank_base[offset & 0x3fff]; + } + } + return 0xff; +} + + +WRITE8_MEMBER(msx_cart_fmpac::write_cart) +{ + if (offset >= 0x4000 && offset < 0x6000) + { + if (m_sram_active) + { + get_sram_base()[offset & 0x1fff] = data; + } + if (offset == 0x5ffe) + { + m_1ffe = data; + } + if (offset == 0x5fff) + { + m_1fff = data; + } + m_sram_active = (m_1ffe == 0x4d) && (m_1fff == 0x69); + } + + switch (offset) + { + case 0x7ff4: + case 0x7ff5: + if (m_opll_active) + { + m_ym2413->write(space, offset & 1, data); + } + break; + + case 0x7ff6: + m_7ff6 = data & 0x11; + m_opll_active = (m_7ff6 & 0x01); + break; + + case 0x7ff7: + m_selected_bank = data; + restore_banks(); + break; + } + +} + + +WRITE8_MEMBER(msx_cart_fmpac::write_ym2413) +{ + if (m_opll_active) + { + m_ym2413->write(space, offset & 1, data); + } +} diff --git a/src/devices/bus/msx_cart/fmpac.h b/src/devices/bus/msx_cart/fmpac.h new file mode 100644 index 00000000000..610f3b99038 --- /dev/null +++ b/src/devices/bus/msx_cart/fmpac.h @@ -0,0 +1,46 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +#ifndef __MSX_CART_FMPAC_H +#define __MSX_CART_FMPAC_H + +#include "bus/msx_cart/cartridge.h" +#include "sound/2413intf.h" + + +extern const device_type MSX_CART_FMPAC; + + +class msx_cart_fmpac : public device_t + , public msx_cart_interface +{ +public: + msx_cart_fmpac(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual machine_config_constructor device_mconfig_additions() const; + + virtual void initialize_cartridge(); + + virtual DECLARE_READ8_MEMBER(read_cart); + virtual DECLARE_WRITE8_MEMBER(write_cart); + + void restore_banks(); + + DECLARE_WRITE8_MEMBER(write_ym2413); + +private: + required_device m_ym2413; + + UINT8 m_selected_bank; + UINT8 *m_bank_base; + bool m_sram_active; + bool m_opll_active; + UINT8 m_1ffe; + UINT8 m_1fff; + UINT8 m_7ff6; +}; + + +#endif diff --git a/src/devices/bus/msx_cart/fs_sr022.c b/src/devices/bus/msx_cart/fs_sr022.c new file mode 100644 index 00000000000..c3aee7b9b81 --- /dev/null +++ b/src/devices/bus/msx_cart/fs_sr022.c @@ -0,0 +1,71 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +#include "emu.h" +#include "fs_sr022.h" + + +const device_type MSX_CART_FS_SR022 = &device_creator; + + +msx_cart_fs_sr022::msx_cart_fs_sr022(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, MSX_CART_FS_SR022, "MSX Cartridge - FS-SR022", tag, owner, clock, "msx_cart_fs_sr022", __FILE__) + , msx_cart_interface(mconfig, *this) + , m_bunsetsu_rom(NULL) + , m_bunsetsu_address(0) +{ +} + + +void msx_cart_fs_sr022::device_start() +{ + save_item(NAME(m_bunsetsu_address)); +} + + +void msx_cart_fs_sr022::device_reset() +{ + m_bunsetsu_address = 0; +} + + +void msx_cart_fs_sr022::initialize_cartridge() +{ + if (get_rom_size() != 0x40000) + { + fatalerror("fs_sr022: Invalid ROM size\n"); + } + m_bunsetsu_rom = get_rom_base() + 0x20000; +} + + +READ8_MEMBER(msx_cart_fs_sr022::read_cart) +{ + if (offset >= 0x4000 && offset < 0xc000) + { + if (offset == 0xbfff) { + return m_bunsetsu_rom[m_bunsetsu_address++ & 0x1ffff]; + } + + return get_rom_base()[offset - 0x4000]; + } + return 0xff; +} + + +WRITE8_MEMBER(msx_cart_fs_sr022::write_cart) +{ + switch (offset) + { + case 0xbffc: + m_bunsetsu_address = (m_bunsetsu_address & 0xffff00) | data; + break; + + case 0xbffd: + m_bunsetsu_address = (m_bunsetsu_address & 0xff00ff) | (data << 8); + break; + + case 0xbffe: + m_bunsetsu_address = (m_bunsetsu_address & 0x00ffff) | (data << 16); + break; + } +} diff --git a/src/devices/bus/msx_cart/fs_sr022.h b/src/devices/bus/msx_cart/fs_sr022.h new file mode 100644 index 00000000000..edae6296beb --- /dev/null +++ b/src/devices/bus/msx_cart/fs_sr022.h @@ -0,0 +1,33 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +#ifndef __MSX_CART_FS_SR022_H +#define __MSX_CART_FS_SR022_H + +#include "bus/msx_cart/cartridge.h" + + +extern const device_type MSX_CART_FS_SR022; + + +class msx_cart_fs_sr022 : public device_t + , public msx_cart_interface +{ +public: + msx_cart_fs_sr022(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + virtual void initialize_cartridge(); + + virtual DECLARE_READ8_MEMBER(read_cart); + virtual DECLARE_WRITE8_MEMBER(write_cart); + +private: + const UINT8 *m_bunsetsu_rom; + UINT32 m_bunsetsu_address; +}; + + +#endif diff --git a/src/devices/bus/msx_cart/halnote.c b/src/devices/bus/msx_cart/halnote.c new file mode 100644 index 00000000000..35b0582b241 --- /dev/null +++ b/src/devices/bus/msx_cart/halnote.c @@ -0,0 +1,159 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +#include "emu.h" +#include "halnote.h" + + +const device_type MSX_CART_HALNOTE = &device_creator; + + +msx_cart_halnote::msx_cart_halnote(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, MSX_CART_HALNOTE, "MSX Cartridge - Halnote", tag, owner, clock, "msx_cart_halnote", __FILE__) + , msx_cart_interface(mconfig, *this) +{ + for (int i = 0; i < 8; i++) + { + m_selected_bank[i] = 0; + m_bank_base[i] = NULL; + } +} + + +void msx_cart_halnote::device_start() +{ + save_item(NAME(m_selected_bank)); + + machine().save().register_postload(save_prepost_delegate(FUNC(msx_cart_halnote::restore_banks), this)); +} + + +void msx_cart_halnote::map_bank(int bank) +{ + if (bank < 2) + { + return; + } + + // Special banks + if (bank == 6 || bank == 7) + { + m_bank_base[bank] = get_rom_base() + 0x80000 + (m_selected_bank[bank] * 0x800); + return; + } + + m_bank_base[bank] = get_rom_base() + ((m_selected_bank[bank] * 0x2000) & 0xFFFFF); + if (bank == 2) + { + if (m_selected_bank[bank] & 0x80) + { + m_bank_base[0] = get_sram_base(); + m_bank_base[1] = get_sram_base() + 0x2000; + } + else + { + m_bank_base[0] = NULL; + m_bank_base[1] = NULL; + } + } +} + + +void msx_cart_halnote::restore_banks() +{ + for (int i = 0; i < 8; i++) + { + map_bank(i); + } +} + + +void msx_cart_halnote::device_reset() +{ + for (int i = 0; i < 8; i++) + { + m_selected_bank[i] = 0; + } +} + + +void msx_cart_halnote::initialize_cartridge() +{ + if (get_rom_size() != 0x100000) + { + fatalerror("halnote: Invalid ROM size\n"); + } + + restore_banks(); +} + + +READ8_MEMBER(msx_cart_halnote::read_cart) +{ + if (offset >= 0xc000) + { + return 0xFF; + } + + if ((offset & 0xf000) == 0x7000 && (m_selected_bank[3] & 0x80)) + { + return m_bank_base[6 + ((offset >> 11) & 0x01)][offset & 0x7ff]; + } + + const UINT8 *mem = m_bank_base[offset >> 13]; + + if (mem) + { + return mem[offset & 0x1fff]; + } + return 0xff; +} + + +WRITE8_MEMBER(msx_cart_halnote::write_cart) +{ + if (offset < 0x4000) + { + if (m_bank_base[0] != NULL) + { + m_sram[offset & 0x3fff] = data; + return; + } + } + + switch (offset) + { + case 0x4FFF: + m_selected_bank[2] = data; + map_bank(2); + break; + + case 0x6FFF: // 6000-7FFF + m_selected_bank[3] = data; + map_bank(3); + break; + + case 0x77FF: + m_selected_bank[6] = data; + map_bank(6); + break; + + case 0x7FFF: + m_selected_bank[7] = data; + map_bank(7); + break; + + case 0x8FFF: + m_selected_bank[4] = data; + map_bank(4); + break; + + case 0xAFFF: + m_selected_bank[5] = data; + map_bank(5); + break; + + default: + logerror("msx_cart_halnote: Unhandled write %02x to %04x\n", data, offset); + break; + } +} diff --git a/src/devices/bus/msx_cart/halnote.h b/src/devices/bus/msx_cart/halnote.h new file mode 100644 index 00000000000..8020219a77d --- /dev/null +++ b/src/devices/bus/msx_cart/halnote.h @@ -0,0 +1,37 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +#ifndef __MSX_CART_HALNOTE_H +#define __MSX_CART_HALNOTE_H + +#include "bus/msx_cart/cartridge.h" + + +extern const device_type MSX_CART_HALNOTE; + + +class msx_cart_halnote : public device_t + , public msx_cart_interface +{ +public: + msx_cart_halnote(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + virtual void initialize_cartridge(); + + virtual DECLARE_READ8_MEMBER(read_cart); + virtual DECLARE_WRITE8_MEMBER(write_cart); + + void restore_banks(); + +private: + UINT8 m_selected_bank[8]; + UINT8 *m_bank_base[8]; + + void map_bank(int bank); +}; + + +#endif diff --git a/src/devices/bus/msx_cart/hfox.c b/src/devices/bus/msx_cart/hfox.c new file mode 100644 index 00000000000..8cf349c403d --- /dev/null +++ b/src/devices/bus/msx_cart/hfox.c @@ -0,0 +1,79 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +#include "emu.h" +#include "hfox.h" + + +const device_type MSX_CART_HFOX = &device_creator; + + +msx_cart_hfox::msx_cart_hfox(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, MSX_CART_HFOX, "MSX Cartridge - Harry Fox", tag, owner, clock, "msx_cart_hfox", __FILE__) + , msx_cart_interface(mconfig, *this) +{ + m_selected_bank[0] = m_selected_bank[1] = 0; + m_bank_base[0] = m_bank_base[1] = NULL; +} + + +void msx_cart_hfox::device_start() +{ + save_item(NAME(m_selected_bank)); + + machine().save().register_postload(save_prepost_delegate(FUNC(msx_cart_hfox::restore_banks), this)); +} + + +void msx_cart_hfox::restore_banks() +{ + m_bank_base[0] = get_rom_base() + ((m_selected_bank[0] & 0x01) * 0x8000); + m_bank_base[1] = get_rom_base() + ((m_selected_bank[1] & 0x01) * 0x8000) + 0x4000; +} + + +void msx_cart_hfox::device_reset() +{ + m_selected_bank[0] = m_selected_bank[1] = 0; +} + + +void msx_cart_hfox::initialize_cartridge() +{ + if (get_rom_size() < 0x10000) + { + fatalerror("rtype: Invalid ROM size\n"); + } + + restore_banks(); +} + + +READ8_MEMBER(msx_cart_hfox::read_cart) +{ + if (offset >= 0x4000 && offset < 0xc000) + { + return m_bank_base[offset >> 15][offset & 0x3fff]; + } + return 0xff; +} + + +WRITE8_MEMBER(msx_cart_hfox::write_cart) +{ + switch (offset) + { + case 0x6000: + m_selected_bank[0] = data; + restore_banks(); + break; + + case 0x7000: + m_selected_bank[1] = data; + restore_banks(); + break; + + default: + logerror("msx_cart_hfox: unhandled write %02x to %04x\n", data, offset); + break; + } +} diff --git a/src/devices/bus/msx_cart/hfox.h b/src/devices/bus/msx_cart/hfox.h new file mode 100644 index 00000000000..c3a17d365c5 --- /dev/null +++ b/src/devices/bus/msx_cart/hfox.h @@ -0,0 +1,35 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +#ifndef __MSX_CART_HFOX_H +#define __MSX_CART_HFOX_H + +#include "bus/msx_cart/cartridge.h" + + +extern const device_type MSX_CART_HFOX; + + +class msx_cart_hfox : public device_t + , public msx_cart_interface +{ +public: + msx_cart_hfox(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + virtual void initialize_cartridge(); + + virtual DECLARE_READ8_MEMBER(read_cart); + virtual DECLARE_WRITE8_MEMBER(write_cart); + + void restore_banks(); + +private: + UINT8 m_selected_bank[2]; + UINT8 *m_bank_base[2]; +}; + + +#endif diff --git a/src/devices/bus/msx_cart/holy_quran.c b/src/devices/bus/msx_cart/holy_quran.c new file mode 100644 index 00000000000..cb9d0b850a7 --- /dev/null +++ b/src/devices/bus/msx_cart/holy_quran.c @@ -0,0 +1,119 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +#include "emu.h" +#include "holy_quran.h" + + +const device_type MSX_CART_HOLY_QURAN = &device_creator; + + +msx_cart_holy_quran::msx_cart_holy_quran(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, MSX_CART_HOLY_QURAN, "MSX Cartridge - Holy Quran", tag, owner, clock, "msx_cart_holy_quran", __FILE__) + , msx_cart_interface(mconfig, *this) + , m_decrypt(false) +{ + for (int i = 0; i < 4; i++) + { + m_selected_bank[i] = 0; + m_bank_base[i] = NULL; + } + + /* protection uses a simple rotation on databus, some lines inverted: + D0 D4 D4 D5 + D1 ~ D3 D5 ~ D2 + D2 ~ D6 D6 D7 + D3 ~ D0 D7 D1 */ + for (int i=0; i < 0x100; i++) + { + m_lookup_prot[i] = (((i << 4) & 0x50) | ((i >> 3) & 5) | ((i << 1) & 0xa0) | ((i << 2) & 8) | ((i >> 6) & 2)) ^ 0x4d; + } +} + + +void msx_cart_holy_quran::device_start() +{ + save_item(NAME(m_selected_bank)); + save_item(NAME(m_decrypt)); + + machine().save().register_postload(save_prepost_delegate(FUNC(msx_cart_holy_quran::restore_banks), this)); +} + + +void msx_cart_holy_quran::restore_banks() +{ + m_bank_base[0] = get_rom_base() + (m_selected_bank[0] & 0x7f) * 0x2000; + m_bank_base[1] = get_rom_base() + (m_selected_bank[1] & 0x7f) * 0x2000; + m_bank_base[2] = get_rom_base() + (m_selected_bank[2] & 0x7f) * 0x2000; + m_bank_base[3] = get_rom_base() + (m_selected_bank[3] & 0x7f) * 0x2000; +} + + +void msx_cart_holy_quran::device_reset() +{ + for (int i = 0; i < 4; i++) + { + m_selected_bank[i] = 0; + } +} + + +void msx_cart_holy_quran::initialize_cartridge() +{ + if (get_rom_size() != 0x100000) + { + fatalerror("holy_quran: Invalid ROM size\n"); + } + + restore_banks(); +} + + +READ8_MEMBER(msx_cart_holy_quran::read_cart) +{ + if (offset >= 0x4000 && offset < 0xc000) + { + UINT8 data = m_bank_base[(offset - 0x4000) >> 13][offset & 0x1fff]; + + if (m_decrypt) + { + return m_lookup_prot[data]; + } + + // The decryption should actually start working after the first M1 cycle executing something + // from the cartridge. + if (offset == ((m_rom[3] << 8) | m_rom[2]) && !space.debugger_access()) + { + m_decrypt = true; + } + + return data; + } + return 0xff; +} + + +WRITE8_MEMBER(msx_cart_holy_quran::write_cart) +{ + switch (offset) + { + case 0x5000: + m_selected_bank[0] = data; + restore_banks(); + break; + case 0x5400: + m_selected_bank[1] = data; + restore_banks(); + break; + case 0x5800: + m_selected_bank[2] = data; + restore_banks(); + break; + case 0x5c00: + m_selected_bank[3] = data; + restore_banks(); + break; + default: + logerror("msx_cart_holy_quran: unhandled write %02x to %04x\n", data, offset); + break; + } +} diff --git a/src/devices/bus/msx_cart/holy_quran.h b/src/devices/bus/msx_cart/holy_quran.h new file mode 100644 index 00000000000..e6c949f1eac --- /dev/null +++ b/src/devices/bus/msx_cart/holy_quran.h @@ -0,0 +1,37 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +#ifndef __MSX_CART_HOLY_QURAN_H +#define __MSX_CART_HOLY_QURAN_H + +#include "bus/msx_cart/cartridge.h" + + +extern const device_type MSX_CART_HOLY_QURAN; + + +class msx_cart_holy_quran : public device_t + , public msx_cart_interface +{ +public: + msx_cart_holy_quran(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + virtual void initialize_cartridge(); + + virtual DECLARE_READ8_MEMBER(read_cart); + virtual DECLARE_WRITE8_MEMBER(write_cart); + + void restore_banks(); + +private: + UINT8 m_lookup_prot[256]; + UINT8 m_selected_bank[4]; + UINT8 *m_bank_base[4]; + bool m_decrypt; +}; + + +#endif diff --git a/src/devices/bus/msx_cart/konami.c b/src/devices/bus/msx_cart/konami.c new file mode 100644 index 00000000000..c0beb8da357 --- /dev/null +++ b/src/devices/bus/msx_cart/konami.c @@ -0,0 +1,937 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +#include "emu.h" +#include "konami.h" + +const device_type MSX_CART_KONAMI = &device_creator; +const device_type MSX_CART_KONAMI_SCC = &device_creator; +const device_type MSX_CART_GAMEMASTER2 = &device_creator; +const device_type MSX_CART_SYNTHESIZER = &device_creator; +const device_type MSX_CART_SOUND_SNATCHER = &device_creator; +const device_type MSX_CART_SOUND_SDSNATCHER = &device_creator; +const device_type MSX_CART_KEYBOARD_MASTER = &device_creator; + + +msx_cart_konami::msx_cart_konami(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, MSX_CART_KONAMI, "MSX Cartridge - KONAMI", tag, owner, clock, "msx_cart_konami", __FILE__) + , msx_cart_interface(mconfig, *this) + , m_bank_mask(0) +{ + for (int i = 0; i < 4; i++) + { + m_selected_bank[i] = i; + } + for (int i = 0; i < 8; i++) + { + m_bank_base[i] = NULL; + } +} + + +void msx_cart_konami::device_start() +{ + save_item(NAME(m_selected_bank)); + + machine().save().register_postload(save_prepost_delegate(FUNC(msx_cart_konami::restore_banks), this)); +} + + +void msx_cart_konami::restore_banks() +{ + m_bank_base[0] = get_rom_base() + ( m_selected_bank[0] & m_bank_mask ) * 0x2000; + m_bank_base[1] = get_rom_base() + ( m_selected_bank[1] & m_bank_mask ) * 0x2000; + m_bank_base[2] = get_rom_base() + ( m_selected_bank[0] & m_bank_mask ) * 0x2000; + m_bank_base[3] = get_rom_base() + ( m_selected_bank[1] & m_bank_mask ) * 0x2000; + m_bank_base[4] = get_rom_base() + ( m_selected_bank[2] & m_bank_mask ) * 0x2000; + m_bank_base[5] = get_rom_base() + ( m_selected_bank[3] & m_bank_mask ) * 0x2000; + m_bank_base[6] = get_rom_base() + ( m_selected_bank[2] & m_bank_mask ) * 0x2000; + m_bank_base[7] = get_rom_base() + ( m_selected_bank[3] & m_bank_mask ) * 0x2000; +} + + +void msx_cart_konami::device_reset() +{ + for (int i = 0; i < 4; i++) + { + m_selected_bank[i] = i; + } +} + + +void msx_cart_konami::initialize_cartridge() +{ + UINT32 size = get_rom_size(); + + if ( get_rom_size() > 256 * 0x2000 ) + { + fatalerror("konami: ROM is too big\n"); + } + + UINT16 banks = size / 0x2000; + + if (size != banks * 0x2000 || (~(banks - 1) % banks)) + { + fatalerror("konami: Invalid ROM size\n"); + } + + m_bank_mask = banks - 1; + + restore_banks(); +} + + +READ8_MEMBER(msx_cart_konami::read_cart) +{ + return m_bank_base[offset >> 13][offset & 0x1fff]; +} + + +WRITE8_MEMBER(msx_cart_konami::write_cart) +{ + switch (offset & 0xe000) + { + case 0x4000: + m_selected_bank[0] = data; + m_bank_base[0] = get_rom_base() + ( m_selected_bank[0] & m_bank_mask ) * 0x2000; + m_bank_base[2] = get_rom_base() + ( m_selected_bank[0] & m_bank_mask ) * 0x2000; + break; + + case 0x6000: + m_selected_bank[1] = data; + m_bank_base[1] = get_rom_base() + ( m_selected_bank[1] & m_bank_mask ) * 0x2000; + m_bank_base[3] = get_rom_base() + ( m_selected_bank[1] & m_bank_mask ) * 0x2000; + break; + + case 0x8000: + m_selected_bank[2] = data; + m_bank_base[4] = get_rom_base() + ( m_selected_bank[2] & m_bank_mask ) * 0x2000; + m_bank_base[6] = get_rom_base() + ( m_selected_bank[2] & m_bank_mask ) * 0x2000; + break; + + case 0xa000: + m_selected_bank[3] = data; + m_bank_base[5] = get_rom_base() + ( m_selected_bank[3] & m_bank_mask ) * 0x2000; + m_bank_base[7] = get_rom_base() + ( m_selected_bank[3] & m_bank_mask ) * 0x2000; + break; + } +} + + + + +msx_cart_konami_scc::msx_cart_konami_scc(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, MSX_CART_KONAMI_SCC, "MSX Cartridge - KONAMI+SCC", tag, owner, clock, "msx_cart_konami_scc", __FILE__) + , msx_cart_interface(mconfig, *this) + , m_k051649(*this, "k051649") + , m_bank_mask(0) + , m_scc_active(false) +{ + for (int i = 0; i < 4; i++) + { + m_selected_bank[i] = i; + } + for (int i = 0; i < 8; i++) + { + m_bank_base[i] = NULL; + } +} + + +static MACHINE_CONFIG_FRAGMENT( konami_scc ) + // This is actually incorrect. The sound output is passed back into the MSX machine where it is mixed internally and output through the system 'speaker'. + MCFG_SPEAKER_STANDARD_MONO("mono") + MCFG_SOUND_ADD("k051649", K051649, XTAL_10_738635MHz/3/2) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.15) +MACHINE_CONFIG_END + + +machine_config_constructor msx_cart_konami_scc::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( konami_scc ); +} + + +void msx_cart_konami_scc::device_start() +{ + save_item(NAME(m_selected_bank)); + save_item(NAME(m_scc_active)); + + machine().save().register_postload(save_prepost_delegate(FUNC(msx_cart_konami_scc::restore_banks), this)); +} + + +void msx_cart_konami_scc::restore_banks() +{ + m_bank_base[0] = get_rom_base() + ( m_selected_bank[2] & m_bank_mask ) * 0x2000; + m_bank_base[1] = get_rom_base() + ( m_selected_bank[3] & m_bank_mask ) * 0x2000; + m_bank_base[2] = get_rom_base() + ( m_selected_bank[0] & m_bank_mask ) * 0x2000; + m_bank_base[3] = get_rom_base() + ( m_selected_bank[1] & m_bank_mask ) * 0x2000; + m_bank_base[4] = get_rom_base() + ( m_selected_bank[2] & m_bank_mask ) * 0x2000; + m_bank_base[5] = get_rom_base() + ( m_selected_bank[3] & m_bank_mask ) * 0x2000; + m_bank_base[6] = get_rom_base() + ( m_selected_bank[0] & m_bank_mask ) * 0x2000; + m_bank_base[7] = get_rom_base() + ( m_selected_bank[1] & m_bank_mask ) * 0x2000; +} + + +void msx_cart_konami_scc::device_reset() +{ + for (int i = 0; i < 4; i++) + { + m_selected_bank[i] = i; + } + m_scc_active = false; +} + + +void msx_cart_konami_scc::initialize_cartridge() +{ + UINT32 size = get_rom_size(); + + if ( get_rom_size() > 256 * 0x2000 ) + { + fatalerror("konami_scc: ROM is too big\n"); + } + + UINT16 banks = size / 0x2000; + + if (size != banks * 0x2000 || (~(banks - 1) % banks)) + { + fatalerror("konami_scc: Invalid ROM size\n"); + } + + m_bank_mask = banks - 1; + + restore_banks(); +} + + +READ8_MEMBER(msx_cart_konami_scc::read_cart) +{ + if ( m_scc_active && offset >= 0x9800 && offset < 0xa000 ) + { + if (offset & 0x80) + { + if ((offset & 0xff) >= 0xe0) + { + return m_k051649->k051649_test_r(space, offset & 0xff); + } + return 0xff; + } + else + { + return m_k051649->k051649_waveform_r(space, offset & 0x7f); + } + } + + return m_bank_base[offset >> 13][offset & 0x1fff]; +} + + +WRITE8_MEMBER(msx_cart_konami_scc::write_cart) +{ + switch (offset & 0xf800) + { + case 0x5000: + m_selected_bank[0] = data; + m_bank_base[2] = get_rom_base() + ( m_selected_bank[0] & m_bank_mask ) * 0x2000; + m_bank_base[6] = get_rom_base() + ( m_selected_bank[0] & m_bank_mask ) * 0x2000; + break; + + case 0x7000: + m_selected_bank[1] = data; + m_bank_base[3] = get_rom_base() + ( m_selected_bank[1] & m_bank_mask ) * 0x2000; + m_bank_base[7] = get_rom_base() + ( m_selected_bank[1] & m_bank_mask ) * 0x2000; + break; + + case 0x9000: + m_selected_bank[2] = data; + m_scc_active = ( ( data & 0x3f ) == 0x3f ); + m_bank_base[0] = get_rom_base() + ( m_selected_bank[2] & m_bank_mask ) * 0x2000; + m_bank_base[4] = get_rom_base() + ( m_selected_bank[2] & m_bank_mask ) * 0x2000; + break; + + case 0x9800: + if ( m_scc_active ) + { + offset &= 0xff; + + if (offset < 0x80) + { + m_k051649->k051649_waveform_w(space, offset, data); + } + else if (offset < 0xa0) + { + offset &= 0x0f; + if (offset < 0x0a) + { + m_k051649->k051649_frequency_w(space, offset, data); + } + else if (offset < 0x0f) + { + m_k051649->k051649_volume_w(space, offset - 0xa, data); + } + else + { + m_k051649->k051649_keyonoff_w(space, 0, data); + } + } + else if (offset >= 0xe0) + { + m_k051649->k051649_test_w(space, offset, data); + } + } + break; + + case 0xb000: + m_selected_bank[3] = data; + m_bank_base[1] = get_rom_base() + ( m_selected_bank[3] & m_bank_mask ) * 0x2000; + m_bank_base[5] = get_rom_base() + ( m_selected_bank[3] & m_bank_mask ) * 0x2000; + break; + } +} + + + + + + +msx_cart_gamemaster2::msx_cart_gamemaster2(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, MSX_CART_GAMEMASTER2, "MSX Cartridge - GAMEMASTER2", tag, owner, clock, "msx_cart_gamemaster2", __FILE__) + , msx_cart_interface(mconfig, *this) +{ + for (int i = 0; i < 3; i++) + { + m_selected_bank[i] = 0; + } + for (int i = 0; i < 8; i++) + { + m_bank_base[i] = NULL; + } +} + + +void msx_cart_gamemaster2::device_start() +{ + save_item(NAME(m_selected_bank)); + + machine().save().register_postload(save_prepost_delegate(FUNC(msx_cart_gamemaster2::restore_banks), this)); +} + + +void msx_cart_gamemaster2::setup_bank(UINT8 bank) +{ + switch (bank) + { + case 0: + if (m_selected_bank[0] & 0x10) + { + m_bank_base[1] = get_sram_base() + ((m_selected_bank[0] & 0x20) ? 0x1000 : 0); + m_bank_base[3] = get_sram_base() + ((m_selected_bank[0] & 0x20) ? 0x1000 : 0); + } + else + { + m_bank_base[1] = get_rom_base() + ( m_selected_bank[0] & 0x0f ) * 0x2000; + m_bank_base[3] = get_rom_base() + ( m_selected_bank[0] & 0x0f ) * 0x2000; + } + break; + + case 1: + if (m_selected_bank[1] & 0x10) + { + m_bank_base[4] = get_sram_base() + ((m_selected_bank[1] & 0x20) ? 0x1000 : 0); + m_bank_base[6] = get_sram_base() + ((m_selected_bank[1] & 0x20) ? 0x1000 : 0); + } + else + { + m_bank_base[4] = get_rom_base() + ( m_selected_bank[1] & 0x0f ) * 0x2000; + m_bank_base[6] = get_rom_base() + ( m_selected_bank[1] & 0x0f ) * 0x2000; + } + break; + + case 2: + if (m_selected_bank[2] & 0x10) + { + m_bank_base[5] = get_sram_base() + ((m_selected_bank[2] & 0x20) ? 0x1000 : 0); + m_bank_base[7] = get_sram_base() + ((m_selected_bank[2] & 0x20) ? 0x1000 : 0); + } + else + { + m_bank_base[5] = get_rom_base() + ( m_selected_bank[2] & 0x0f ) * 0x2000; + m_bank_base[7] = get_rom_base() + ( m_selected_bank[2] & 0x0f ) * 0x2000; + } + break; + } +} + + +void msx_cart_gamemaster2::restore_banks() +{ + m_bank_base[0] = get_rom_base(); + m_bank_base[2] = get_rom_base(); + setup_bank(0); + setup_bank(1); + setup_bank(2); +} + + +void msx_cart_gamemaster2::device_reset() +{ + for (int i = 0; i < 3; i++) + { + m_selected_bank[i] = i + 1; + } +} + + +void msx_cart_gamemaster2::initialize_cartridge() +{ + if ( get_rom_size() != 0x20000 ) + { + fatalerror("gamemaster2: Invalid ROM size\n"); + } + + if (get_sram_size() != 0x2000) + { + fatalerror("gamemaster2: Invalid SRAM size\n"); + } + + restore_banks(); +} + + +READ8_MEMBER(msx_cart_gamemaster2::read_cart) +{ + UINT8 bank = offset >> 13; + + switch (bank) + { + case 1: + case 3: + if (m_selected_bank[0] & 0x10) + { + return m_bank_base[bank][offset & 0x0fff]; + } + break; + + case 4: + case 6: + if (m_selected_bank[1] & 0x10) + { + return m_bank_base[bank][offset & 0x0fff]; + } + break; + + case 5: + case 7: + if (m_selected_bank[2] & 0x10) + { + return m_bank_base[bank][offset & 0x0fff]; + } + break; + } + return m_bank_base[bank][offset & 0x1fff]; +} + + +WRITE8_MEMBER(msx_cart_gamemaster2::write_cart) +{ + switch (offset & 0xf000) + { + case 0x6000: + m_selected_bank[0] = data; + setup_bank(0); + break; + + case 0x8000: + m_selected_bank[1] = data; + setup_bank(1); + break; + + case 0xa000: + m_selected_bank[2] = data; + setup_bank(2); + break; + + case 0xb000: + if (m_selected_bank[2] & 0x10) + { + m_bank_base[5][offset & 0x0fff] = data; + } + break; + } +} + + + + + +msx_cart_synthesizer::msx_cart_synthesizer(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, MSX_CART_SYNTHESIZER, "MSX Cartridge - Synthesizer", tag, owner, clock, "msx_cart_synthesizer", __FILE__) + , msx_cart_interface(mconfig, *this) + , m_bank_base(NULL) + , m_dac(*this, "dac") +{ +} + + +static MACHINE_CONFIG_FRAGMENT( synthesizer ) + // This is actually incorrect. The sound output is passed back into the MSX machine where it is mixed internally and output through the system 'speaker'. + MCFG_SPEAKER_STANDARD_MONO("mono") + MCFG_SOUND_ADD("dac", DAC, 0) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.20) +MACHINE_CONFIG_END + + +machine_config_constructor msx_cart_synthesizer::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( synthesizer ); +} + + +void msx_cart_synthesizer::device_start() +{ +} + + +void msx_cart_synthesizer::initialize_cartridge() +{ + if ( get_rom_size() != 0x8000 ) + { + fatalerror("synthesizer: Invalid ROM size\n"); + } + + m_bank_base = get_rom_base(); +} + + +READ8_MEMBER(msx_cart_synthesizer::read_cart) +{ + if (offset >= 0x4000 && offset < 0xc000 ) + { + return m_bank_base[offset - 0x4000]; + } + return 0xff; +} + + +WRITE8_MEMBER(msx_cart_synthesizer::write_cart) +{ + if ((offset & 0xc010) == 0x4000) + { + m_dac->write_unsigned8(data); + } +} + + + + +msx_cart_konami_sound::msx_cart_konami_sound(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source) + , msx_cart_interface(mconfig, *this) + , m_k052539(*this, "k052539") + , m_scc_active(false) + , m_sccplus_active(false) + , m_scc_mode(0) +{ + for (int i = 0; i < 4; i++) + { + m_selected_bank[i] = 0; + } + for (int i = 0; i < 8; i++) + { + m_bank_base[i] = NULL; + } + for (int i = 0; i < 16; i++) + { + m_ram_bank[i] = NULL; + } + for (int i = 0; i < 4; i++) + { + m_ram_enabled[i] = false; + } +} + + +static MACHINE_CONFIG_FRAGMENT( konami_sound ) + // This is actually incorrect. The sound output is passed back into the MSX machine where it is mixed internally and output through the system 'speaker'. + MCFG_SPEAKER_STANDARD_MONO("mono") + MCFG_SOUND_ADD("k052539", K051649, XTAL_10_738635MHz/3/2) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.15) +MACHINE_CONFIG_END + + +machine_config_constructor msx_cart_konami_sound::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( konami_sound ); +} + + +void msx_cart_konami_sound::device_start() +{ + save_item(NAME(m_selected_bank)); + save_item(NAME(m_scc_active)); + save_item(NAME(m_sccplus_active)); + save_item(NAME(m_ram_enabled)); + + machine().save().register_postload(save_prepost_delegate(FUNC(msx_cart_konami_sound::restore_banks), this)); +} + + +void msx_cart_konami_sound::restore_banks() +{ + for (int i = 0; i < 4; i++) + { + setup_bank(i); + } +} + + +void msx_cart_konami_sound::setup_bank(UINT8 bank) +{ + switch (bank) + { + case 0: + m_bank_base[2] = m_ram_bank[m_selected_bank[0] & 0x0f]; + m_bank_base[6] = m_ram_bank[m_selected_bank[0] & 0x0f]; + break; + + case 1: + m_bank_base[3] = m_ram_bank[m_selected_bank[1] & 0x0f]; + m_bank_base[7] = m_ram_bank[m_selected_bank[1] & 0x0f]; + break; + + case 2: + m_bank_base[0] = m_ram_bank[m_selected_bank[2] & 0x0f]; + m_bank_base[4] = m_ram_bank[m_selected_bank[2] & 0x0f]; + break; + + case 3: + m_bank_base[1] = m_ram_bank[m_selected_bank[3] & 0x0f]; + m_bank_base[5] = m_ram_bank[m_selected_bank[3] & 0x0f]; + break; + } +} + + +void msx_cart_konami_sound::device_reset() +{ + for (int i = 0; i < 4; i++) + { + m_selected_bank[i] = i; + m_ram_enabled[i] = false; + } + m_scc_active = false; + m_sccplus_active = false; +} + + +void msx_cart_konami_sound::initialize_cartridge() +{ + restore_banks(); +} + + +READ8_MEMBER(msx_cart_konami_sound::read_cart) +{ + if ( m_scc_active && offset >= 0x9800 && offset < 0x9fe0 ) + { + offset &= 0xff; + if (offset < 0x80) + { + return m_k052539->k051649_waveform_r(space, offset); + } + if (offset < 0xa0) + { + return 0xff; + } + if (offset < 0xc0) + { + return m_k052539->k051649_waveform_r(space, offset & 0x9f); + } + if (offset < 0xe0) + { + return m_k052539->k051649_test_r(space, offset & 0xff); + } + return 0xff; + } + else if ( m_sccplus_active && offset >= 0xb800 && offset < 0xbfe0) + { + offset &= 0xff; + + if (offset < 0xa0) + { + return m_k052539->k052539_waveform_r(space, offset); + } + if (offset >= 0xc0 && offset < 0xe0) + { + return m_k052539->k051649_test_r(space, offset); + } + return 0xff; + } + + UINT8 *base = m_bank_base[offset >> 13]; + + if (base != NULL) + { + return base[offset & 0x1fff]; + } + return 0xff; +} + + +WRITE8_MEMBER(msx_cart_konami_sound::write_cart) +{ + switch (offset & 0xe000) + { + case 0x4000: + if (m_ram_enabled[0] && m_bank_base[2] != NULL) + { + m_bank_base[2][offset & 0x1fff] = data; + } + if ((offset & 0x1800) == 0x1000) + { + m_selected_bank[0] = data; + setup_bank(0); + } + break; + + case 0x6000: + if (m_ram_enabled[1] && m_bank_base[3] != NULL) + { + m_bank_base[3][offset & 0x1fff] = data; + } + if ((offset & 0x1800) == 0x1000) + { + m_selected_bank[1] = data; + setup_bank(1); + } + break; + + case 0x8000: + if (m_ram_enabled[2] && m_bank_base[0] != NULL) + { + m_bank_base[0][offset & 0x1fff] = data; + } + switch (offset & 0x1800) + { + case 0x1000: // 0x9000-0x97ff + m_selected_bank[2] = data; + m_scc_active = ( ( data & 0x3f ) == 0x3f ); + setup_bank(2); + break; + + case 0x1800: // 0x9800-0x9fff + if ( m_scc_active ) + { + offset &= 0xff; + + if (offset < 0x80) + { + m_k052539->k051649_waveform_w(space, offset, data); + } + else if (offset < 0xa0) + { + offset &= 0x0f; + if (offset < 0x0a) + { + m_k052539->k051649_frequency_w(space, offset, data); + } + else if (offset < 0x0f) + { + m_k052539->k051649_volume_w(space, offset - 0xa, data); + } + else + { + m_k052539->k051649_keyonoff_w(space, 0, data); + } + } + else if (offset >= 0xe0) + { + m_k052539->k051649_test_w(space, offset, data); + } + } + break; + } + break; + + case 0xa000: + if (m_ram_enabled[3] && m_bank_base[1] != NULL) + { + m_bank_base[1][offset & 0x1fff] = data; + } + switch (offset & 0x1800) + { + // 0xb000-0xb7ff + case 0x1000: + m_selected_bank[3] = data; + setup_bank(3); + break; + + // 0xb800-0xbfff + case 0x1800: + if ((offset & 0x7fe) == 0x7fe) + { + // 0xbffe-0xbfff + /* write to mode register */ + m_scc_mode = data; + + m_ram_enabled[0] = ((m_scc_mode & 0x10) || (m_scc_mode & 0x01)); + m_ram_enabled[1] = ((m_scc_mode & 0x10) || (m_scc_mode & 0x02)); + m_ram_enabled[2] = ((m_scc_mode & 0x10) || ((m_scc_mode & 0x04) && (m_scc_mode & 0x20))); + m_ram_enabled[3] = (m_scc_mode & 0x10); + + m_scc_active = ((m_selected_bank[2] & 0x3f) == 0x3f) && !(m_scc_mode & 0x20); + m_sccplus_active = (m_selected_bank[3] & 0x80) && (m_scc_mode & 0x20); + } + else + { + if (m_sccplus_active) + { + offset &= 0xff; + if (offset < 0xa0) + { + m_k052539->k052539_waveform_w(space, offset, data); + } + else if (offset < 0xc0) + { + offset &= 0x0f; + if (offset < 0x0a) + { + m_k052539->k051649_frequency_w(space, offset, data); + } + else if (offset < 0x0f) + { + m_k052539->k051649_volume_w(space, offset - 0x0a, data); + } + else if (offset == 0x0f) + { + m_k052539->k051649_keyonoff_w(space, 0, data); + } + } + else if (offset < 0xe0) + { + m_k052539->k051649_test_w(space, offset, data); + } + } + } + break; + } + break; + } +} + + +msx_cart_konami_sound_snatcher::msx_cart_konami_sound_snatcher(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : msx_cart_konami_sound(mconfig, MSX_CART_SOUND_SNATCHER, "MSX Cartridge - Sound Snatcher", tag, owner, clock, "msx_cart_sound_snatcher", __FILE__) +{ +} + + +void msx_cart_konami_sound_snatcher::initialize_cartridge() +{ + msx_cart_konami_sound::initialize_cartridge(); + + if (get_ram_size() != 0x10000) + { + fatalerror("sound_snatcher: Invalid RAM size\n"); + } + + // The Snatcher Sound cartridge has 64KB RAM available by selecting ram banks 0-7 + + for (int i = 0; i < 8; i++) + { + m_ram_bank[i] = get_ram_base() + i * 0x2000; + } +} + + +msx_cart_konami_sound_sdsnatcher::msx_cart_konami_sound_sdsnatcher(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : msx_cart_konami_sound(mconfig, MSX_CART_SOUND_SDSNATCHER, "MSX Cartridge - Sound SD Snatcher", tag, owner, clock, "msx_cart_sound_sdsnatcher", __FILE__) +{ +} + + +void msx_cart_konami_sound_sdsnatcher::initialize_cartridge() +{ + msx_cart_konami_sound::initialize_cartridge(); + + if (get_ram_size() != 0x10000) + { + fatalerror("sound_sdsnatcher: Invalid RAM size\n"); + } + + // The SD Snatcher Sound cartrdige has 64KB RAM available by selecting ram banks 8-15 + + for (int i = 0; i < 8; i++) + { + m_ram_bank[8+i] = get_ram_base() + i * 0x2000; + } + +} + + + +msx_cart_keyboard_master::msx_cart_keyboard_master(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, MSX_CART_KEYBOARD_MASTER, "MSX Cartridge - Keyboard Master", tag, owner, clock, "msx_cart_keyboard_master", __FILE__) + , msx_cart_interface(mconfig, *this) + , m_vlm5030(*this, "vlm5030") +{ +} + + +static MACHINE_CONFIG_FRAGMENT( msx_cart_keyboard_master ) + // This is actually incorrect. The sound output is passed back into the MSX machine where it is mixed internally and output through the system 'speaker'. + MCFG_SPEAKER_STANDARD_MONO("mono") + MCFG_SOUND_ADD("vlm5030", VLM5030, XTAL_3_579545MHz) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.40) +MACHINE_CONFIG_END + + +machine_config_constructor msx_cart_keyboard_master::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( msx_cart_keyboard_master ); +} + + +void msx_cart_keyboard_master::device_start() +{ + // Install IO read/write handlers + address_space &space = machine().device("maincpu")->space(AS_IO); + space.install_write_handler(0x00, 0x00, write8_delegate(FUNC(vlm5030_device::data_w), m_vlm5030.target())); + space.install_write_handler(0x20, 0x20, write8_delegate(FUNC(msx_cart_keyboard_master::io_20_w), this)); + space.install_read_handler(0x00, 0x00, read8_delegate(FUNC(msx_cart_keyboard_master::io_00_r), this)); +} + + +void msx_cart_keyboard_master::initialize_cartridge() +{ + if (get_rom_size() != 0x4000) + { + fatalerror("keyboard_master: Invalid ROM size\n"); + } + m_vlm5030->set_rom(&m_rom_vlm5030[0]); +} + + +READ8_MEMBER(msx_cart_keyboard_master::read_cart) +{ + if (offset >= 0x4000 && offset < 0x8000) + { + return m_rom[offset & 0x3fff]; + } + return 0xff; +} + + +WRITE8_MEMBER(msx_cart_keyboard_master::io_20_w) +{ + m_vlm5030->rst((data & 0x01) ? 1 : 0); + m_vlm5030->vcu((data & 0x04) ? 1 : 0); + m_vlm5030->st((data & 0x02) ? 1 : 0); +} + + +READ8_MEMBER(msx_cart_keyboard_master::io_00_r) +{ + return m_vlm5030->bsy() ? 0x10 : 0x00; +} diff --git a/src/devices/bus/msx_cart/konami.h b/src/devices/bus/msx_cart/konami.h new file mode 100644 index 00000000000..1fd982610e8 --- /dev/null +++ b/src/devices/bus/msx_cart/konami.h @@ -0,0 +1,197 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +#ifndef __MSX_CART_KONAMI_H +#define __MSX_CART_KONAMI_H + +#include "bus/msx_cart/cartridge.h" +#include "sound/k051649.h" +#include "sound/vlm5030.h" +#include "sound/dac.h" + + +extern const device_type MSX_CART_KONAMI; +extern const device_type MSX_CART_KONAMI_SCC; +extern const device_type MSX_CART_GAMEMASTER2; +extern const device_type MSX_CART_SYNTHESIZER; +extern const device_type MSX_CART_SOUND_SNATCHER; +extern const device_type MSX_CART_SOUND_SDSNATCHER; +extern const device_type MSX_CART_KEYBOARD_MASTER; + + +class msx_cart_konami : public device_t + , public msx_cart_interface +{ +public: + msx_cart_konami(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + virtual void initialize_cartridge(); + + virtual DECLARE_READ8_MEMBER(read_cart); + virtual DECLARE_WRITE8_MEMBER(write_cart); + + void restore_banks(); + +private: + UINT8 m_bank_mask; + UINT8 m_selected_bank[4]; + UINT8 *m_bank_base[8]; +}; + + +class msx_cart_konami_scc : public device_t + , public msx_cart_interface +{ +public: + msx_cart_konami_scc(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual machine_config_constructor device_mconfig_additions() const; + + virtual void initialize_cartridge(); + + virtual DECLARE_READ8_MEMBER(read_cart); + virtual DECLARE_WRITE8_MEMBER(write_cart); + + void restore_banks(); + +private: + required_device m_k051649; + + UINT8 m_bank_mask; + UINT8 m_selected_bank[4]; + UINT8 *m_bank_base[8]; + bool m_scc_active; +}; + + +class msx_cart_gamemaster2 : public device_t + , public msx_cart_interface +{ +public: + msx_cart_gamemaster2(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + virtual void initialize_cartridge(); + + virtual DECLARE_READ8_MEMBER(read_cart); + virtual DECLARE_WRITE8_MEMBER(write_cart); + + void restore_banks(); + +private: + UINT8 m_selected_bank[3]; + UINT8 *m_bank_base[8]; + + void setup_bank(UINT8 bank); +}; + + +class msx_cart_synthesizer : public device_t + , public msx_cart_interface +{ +public: + msx_cart_synthesizer(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual machine_config_constructor device_mconfig_additions() const; + + virtual void initialize_cartridge(); + + virtual DECLARE_READ8_MEMBER(read_cart); + virtual DECLARE_WRITE8_MEMBER(write_cart); + +private: + UINT8 *m_bank_base; + required_device m_dac; +}; + + +class msx_cart_konami_sound : public device_t + , public msx_cart_interface +{ +public: + msx_cart_konami_sound(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual machine_config_constructor device_mconfig_additions() const; + + virtual void initialize_cartridge(); + + virtual DECLARE_READ8_MEMBER(read_cart); + virtual DECLARE_WRITE8_MEMBER(write_cart); + + void restore_banks(); + +protected: + UINT8 *m_ram_bank[16]; + +private: + // This is actually a K052539 + required_device m_k052539; + + UINT8 m_selected_bank[4]; + UINT8 *m_bank_base[8]; + bool m_scc_active; + bool m_sccplus_active; + bool m_ram_enabled[4]; + UINT8 m_scc_mode; + + void setup_bank(UINT8 bank); +}; + + +class msx_cart_konami_sound_snatcher : public msx_cart_konami_sound +{ +public: + msx_cart_konami_sound_snatcher(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual void initialize_cartridge(); +}; + + +class msx_cart_konami_sound_sdsnatcher : public msx_cart_konami_sound +{ +public: + msx_cart_konami_sound_sdsnatcher(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual void initialize_cartridge(); +}; + + + +class msx_cart_keyboard_master : public device_t + , public msx_cart_interface +{ +public: + msx_cart_keyboard_master(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual void device_start(); + + virtual void initialize_cartridge(); + + virtual DECLARE_READ8_MEMBER(read_cart); + + DECLARE_WRITE8_MEMBER(io_20_w); + DECLARE_READ8_MEMBER(io_00_r); + +private: + required_device m_vlm5030; +}; + + + +#endif diff --git a/src/devices/bus/msx_cart/korean.c b/src/devices/bus/msx_cart/korean.c new file mode 100644 index 00000000000..58cdd0d5985 --- /dev/null +++ b/src/devices/bus/msx_cart/korean.c @@ -0,0 +1,298 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +#include "emu.h" +#include "korean.h" + +const device_type MSX_CART_KOREAN_80IN1 = &device_creator; +const device_type MSX_CART_KOREAN_90IN1 = &device_creator; +const device_type MSX_CART_KOREAN_126IN1 = &device_creator; + + +msx_cart_korean_80in1::msx_cart_korean_80in1(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, MSX_CART_KOREAN_80IN1, "MSX Cartridge - Korean 80-in-1", tag, owner, clock, "msx_cart_korean_80in1", __FILE__) + , msx_cart_interface(mconfig, *this) + , m_bank_mask(0) +{ + for (int i = 0; i < 4; i++) + { + m_selected_bank[i] = i; + m_bank_base[i] = NULL; + } +} + + +void msx_cart_korean_80in1::device_start() +{ + save_item(NAME(m_selected_bank)); + + machine().save().register_postload(save_prepost_delegate(FUNC(msx_cart_korean_80in1::restore_banks), this)); +} + + +void msx_cart_korean_80in1::setup_bank(UINT8 bank) +{ + m_bank_base[bank] = get_rom_base() + ( m_selected_bank[bank] & m_bank_mask ) * 0x2000; +} + + +void msx_cart_korean_80in1::restore_banks() +{ + for (int i = 0; i < 4; i++) + { + setup_bank(i); + } +} + + +void msx_cart_korean_80in1::device_reset() +{ + for (int i = 0; i < 4; i++) + { + m_selected_bank[i] = i; + } +} + + +void msx_cart_korean_80in1::initialize_cartridge() +{ + UINT32 size = get_rom_size(); + + if ( size > 256 * 0x2000 ) + { + fatalerror("korean_80in1: ROM is too big\n"); + } + + UINT16 banks = size / 0x2000; + + if (size != banks * 0x2000 || (~(banks - 1) % banks)) + { + fatalerror("korean_80in1: Invalid ROM size\n"); + } + + m_bank_mask = banks - 1; + + restore_banks(); +} + + +READ8_MEMBER(msx_cart_korean_80in1::read_cart) +{ + if (offset >= 0x4000 && offset < 0xc000) + { + return m_bank_base[(offset - 0x4000) >> 13][offset & 0x1fff]; + } + + return 0xff; +} + + +WRITE8_MEMBER(msx_cart_korean_80in1::write_cart) +{ + if (offset >= 0x4000 && offset < 0x4004) + { + UINT8 bank = offset & 3; + + m_selected_bank[bank] = data; + setup_bank(bank); + } +} + + + + + +msx_cart_korean_90in1::msx_cart_korean_90in1(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, MSX_CART_KOREAN_90IN1, "MSX Cartridge - Korean 90-in-1", tag, owner, clock, "msx_cart_korean_90in1", __FILE__) + , msx_cart_interface(mconfig, *this) + , m_bank_mask(0) + , m_selected_bank(0) +{ + for (int i = 0; i < 4; i++) + { + m_bank_base[i] = NULL; + } +} + + +void msx_cart_korean_90in1::device_start() +{ + save_item(NAME(m_selected_bank)); + + machine().save().register_postload(save_prepost_delegate(FUNC(msx_cart_korean_90in1::restore_banks), this)); + + // Install IO read/write handlers + address_space &space = machine().device("maincpu")->space(AS_IO); + space.install_write_handler(0x77, 0x77, write8_delegate(FUNC(msx_cart_korean_90in1::banking), this)); +} + + +void msx_cart_korean_90in1::restore_banks() +{ + UINT8 *base = get_rom_base(); + + switch (m_selected_bank & 0xc0) + { + case 0x80: + base += (m_selected_bank & 0x3e & m_bank_mask) * 0x4000; + m_bank_base[0] = base; + m_bank_base[1] = base + 0x2000; + m_bank_base[2] = base + 0x4000; + m_bank_base[3] = base + 0x6000; + break; + + case 0xc0: + base += (m_selected_bank & m_bank_mask) * 0x4000; + m_bank_base[0] = base; + m_bank_base[1] = base + 0x2000; + m_bank_base[2] = base + 0x2000; + m_bank_base[3] = base; + break; + + default: + base += (m_selected_bank & m_bank_mask) * 0x4000; + m_bank_base[0] = base; + m_bank_base[1] = base + 0x2000; + m_bank_base[2] = base; + m_bank_base[3] = base + 0x2000; + break; + } +} + + +void msx_cart_korean_90in1::device_reset() +{ + m_selected_bank = 0; +} + + +void msx_cart_korean_90in1::initialize_cartridge() +{ + UINT32 size = get_rom_size(); + + if ( size > 64 * 0x4000 ) + { + fatalerror("korean_90in1: ROM is too big\n"); + } + + UINT16 banks = size / 0x4000; + + if (size != banks * 0x4000 || (~(banks - 1) % banks)) + { + fatalerror("korean_90in1: Invalid ROM size\n"); + } + + m_bank_mask = banks - 1; + + restore_banks(); +} + + +READ8_MEMBER(msx_cart_korean_90in1::read_cart) +{ + if (offset >= 0x4000 && offset < 0xc000) + { + return m_bank_base[(offset - 0x4000) >> 13][offset & 0x1fff]; + } + + return 0xff; +} + + +WRITE8_MEMBER(msx_cart_korean_90in1::banking) +{ + m_selected_bank = data; + restore_banks(); +} + + + + + +msx_cart_korean_126in1::msx_cart_korean_126in1(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, MSX_CART_KOREAN_126IN1, "MSX Cartridge - Korean 126-in-1", tag, owner, clock, "msx_cart_korean_126in1", __FILE__) + , msx_cart_interface(mconfig, *this) + , m_bank_mask(0) +{ + for (int i = 0; i < 2; i++) + { + m_selected_bank[i] = i; + m_bank_base[i] = NULL; + } +} + + +void msx_cart_korean_126in1::device_start() +{ + save_item(NAME(m_selected_bank)); + + machine().save().register_postload(save_prepost_delegate(FUNC(msx_cart_korean_126in1::restore_banks), this)); +} + + +void msx_cart_korean_126in1::setup_bank(UINT8 bank) +{ + m_bank_base[bank] = get_rom_base() + ( m_selected_bank[bank] & m_bank_mask ) * 0x4000; +} + + +void msx_cart_korean_126in1::restore_banks() +{ + for (int i = 0; i < 2; i++) + { + setup_bank(i); + } +} + + +void msx_cart_korean_126in1::device_reset() +{ + for (int i = 0; i < 2; i++) + { + m_selected_bank[i] = i; + } +} + + +void msx_cart_korean_126in1::initialize_cartridge() +{ + UINT32 size = get_rom_size(); + + if ( size > 256 * 0x4000 ) + { + fatalerror("korean_126in1: ROM is too big\n"); + } + + UINT16 banks = size / 0x4000; + + if (size != banks * 0x4000 || (~(banks - 1) % banks)) + { + fatalerror("korean_126in1: Invalid ROM size\n"); + } + + m_bank_mask = banks - 1; + + restore_banks(); +} + + +READ8_MEMBER(msx_cart_korean_126in1::read_cart) +{ + if (offset >= 0x4000 && offset < 0xc000) + { + return m_bank_base[offset >> 15][offset & 0x3fff]; + } + + return 0xff; +} + + +WRITE8_MEMBER(msx_cart_korean_126in1::write_cart) +{ + if (offset >= 0x4000 && offset < 0x4002) + { + UINT8 bank = offset & 1; + + m_selected_bank[bank] = data; + setup_bank(bank); + } +} diff --git a/src/devices/bus/msx_cart/korean.h b/src/devices/bus/msx_cart/korean.h new file mode 100644 index 00000000000..83dc84680f1 --- /dev/null +++ b/src/devices/bus/msx_cart/korean.h @@ -0,0 +1,91 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +#ifndef __MSX_CART_KOREAN_H +#define __MSX_CART_KOREAN_H + +#include "bus/msx_cart/cartridge.h" + + +extern const device_type MSX_CART_KOREAN_80IN1; +extern const device_type MSX_CART_KOREAN_90IN1; +extern const device_type MSX_CART_KOREAN_126IN1; + + +class msx_cart_korean_80in1 : public device_t + , public msx_cart_interface +{ +public: + msx_cart_korean_80in1(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + virtual void initialize_cartridge(); + + virtual DECLARE_READ8_MEMBER(read_cart); + virtual DECLARE_WRITE8_MEMBER(write_cart); + + void restore_banks(); + +private: + UINT8 m_bank_mask; + UINT8 m_selected_bank[4]; + UINT8 *m_bank_base[4]; + + void setup_bank(UINT8 bank); +}; + + +class msx_cart_korean_90in1 : public device_t + , public msx_cart_interface +{ +public: + msx_cart_korean_90in1(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + virtual void initialize_cartridge(); + + virtual DECLARE_READ8_MEMBER(read_cart); + + DECLARE_WRITE8_MEMBER(banking); + + void restore_banks(); + +private: + UINT8 m_bank_mask; + UINT8 m_selected_bank; + UINT8 *m_bank_base[4]; +}; + + +class msx_cart_korean_126in1 : public device_t + , public msx_cart_interface +{ +public: + msx_cart_korean_126in1(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + virtual void initialize_cartridge(); + + virtual DECLARE_READ8_MEMBER(read_cart); + virtual DECLARE_WRITE8_MEMBER(write_cart); + + void restore_banks(); + +private: + UINT8 m_bank_mask; + UINT8 m_selected_bank[2]; + UINT8 *m_bank_base[2]; + + void setup_bank(UINT8 bank); +}; + + +#endif diff --git a/src/devices/bus/msx_cart/majutsushi.c b/src/devices/bus/msx_cart/majutsushi.c new file mode 100644 index 00000000000..6c9c16e7319 --- /dev/null +++ b/src/devices/bus/msx_cart/majutsushi.c @@ -0,0 +1,115 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +#include "emu.h" +#include "majutsushi.h" + +const device_type MSX_CART_MAJUTSUSHI = &device_creator; + + +msx_cart_majutsushi::msx_cart_majutsushi(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, MSX_CART_MAJUTSUSHI, "MSX Cartridge - Majutsushi", tag, owner, clock, "msx_cart_majutsushi", __FILE__) + , msx_cart_interface(mconfig, *this) + , m_dac(*this, "dac") +{ + for (int i = 0; i < 4; i++) + { + m_selected_bank[i] = 0; + } + for (int i = 0; i < 8; i++) + { + m_bank_base[i] = NULL; + } +} + + +static MACHINE_CONFIG_FRAGMENT( majutsushi ) + // This is actually incorrect. The sound output is passed back into the MSX machine where it is mixed internally and output through the system 'speaker'. + MCFG_SPEAKER_STANDARD_MONO("mono") + MCFG_SOUND_ADD("dac", DAC, 0) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.10) +MACHINE_CONFIG_END + + +machine_config_constructor msx_cart_majutsushi::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( majutsushi ); +} + + +void msx_cart_majutsushi::device_start() +{ + save_item(NAME(m_selected_bank)); + + machine().save().register_postload(save_prepost_delegate(FUNC(msx_cart_majutsushi::restore_banks), this)); +} + + +void msx_cart_majutsushi::restore_banks() +{ + m_bank_base[0] = get_rom_base() + ( m_selected_bank[0] & 0x0f ) * 0x2000; + m_bank_base[1] = get_rom_base() + ( m_selected_bank[1] & 0x0f ) * 0x2000; + m_bank_base[2] = get_rom_base() + ( m_selected_bank[0] & 0x0f ) * 0x2000; + m_bank_base[3] = get_rom_base() + ( m_selected_bank[1] & 0x0f ) * 0x2000; + m_bank_base[4] = get_rom_base() + ( m_selected_bank[2] & 0x0f ) * 0x2000; + m_bank_base[5] = get_rom_base() + ( m_selected_bank[3] & 0x0f ) * 0x2000; + m_bank_base[6] = get_rom_base() + ( m_selected_bank[2] & 0x0f ) * 0x2000; + m_bank_base[7] = get_rom_base() + ( m_selected_bank[3] & 0x0f ) * 0x2000; +} + + +void msx_cart_majutsushi::device_reset() +{ + for (int i = 0; i < 4; i++) + { + m_selected_bank[i] = i; + } +} + + +void msx_cart_majutsushi::initialize_cartridge() +{ + if ( get_rom_size() != 0x20000 ) + { + fatalerror("majutsushi: Invalid ROM size\n"); + } + + restore_banks(); +} + + +READ8_MEMBER(msx_cart_majutsushi::read_cart) +{ + return m_bank_base[offset >> 13][offset & 0x1fff]; +} + + +WRITE8_MEMBER(msx_cart_majutsushi::write_cart) +{ + switch (offset & 0xe000) + { + case 0x4000: + if (offset & 0x1000) + { + m_dac->write_unsigned8(data); + } + break; + + case 0x6000: + m_selected_bank[1] = data & 0x0f; + m_bank_base[1] = get_rom_base() + m_selected_bank[1] * 0x2000; + m_bank_base[3] = get_rom_base() + m_selected_bank[1] * 0x2000; + break; + + case 0x8000: + m_selected_bank[2] = data & 0x0f; + m_bank_base[4] = get_rom_base() + m_selected_bank[2] * 0x2000; + m_bank_base[6] = get_rom_base() + m_selected_bank[2] * 0x2000; + break; + + case 0xa000: + m_selected_bank[3] = data & 0x0f; + m_bank_base[5] = get_rom_base() + m_selected_bank[3] * 0x2000; + m_bank_base[7] = get_rom_base() + m_selected_bank[3] * 0x2000; + break; + } +} diff --git a/src/devices/bus/msx_cart/majutsushi.h b/src/devices/bus/msx_cart/majutsushi.h new file mode 100644 index 00000000000..aadbc8a8b5d --- /dev/null +++ b/src/devices/bus/msx_cart/majutsushi.h @@ -0,0 +1,39 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +#ifndef __MSX_CART_MAJUTSUSHI_H +#define __MSX_CART_MAJUTSUSHI_H + +#include "bus/msx_cart/cartridge.h" +#include "sound/dac.h" + + +extern const device_type MSX_CART_MAJUTSUSHI; + + +class msx_cart_majutsushi : public device_t + , public msx_cart_interface +{ +public: + msx_cart_majutsushi(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual machine_config_constructor device_mconfig_additions() const; + + virtual void initialize_cartridge(); + + virtual DECLARE_READ8_MEMBER(read_cart); + virtual DECLARE_WRITE8_MEMBER(write_cart); + + void restore_banks(); + +private: + required_device m_dac; + + UINT8 m_selected_bank[4]; + UINT8 *m_bank_base[8]; +}; + + +#endif diff --git a/src/devices/bus/msx_cart/moonsound.c b/src/devices/bus/msx_cart/moonsound.c new file mode 100644 index 00000000000..cdae9385815 --- /dev/null +++ b/src/devices/bus/msx_cart/moonsound.c @@ -0,0 +1,126 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +/********************************************************************************** + +TODO: +- Properly hook up correct SRAM sizes for different moonsound compatible + cartridges. (Original moonsound has 128KB SRAM) + +**********************************************************************************/ + +#include "emu.h" +#include "moonsound.h" + + +#define VERBOSE 0 +#define LOG(x) do { if (VERBOSE) logerror x; } while (0) + + +const device_type MSX_CART_MOONSOUND = &device_creator; + + +msx_cart_moonsound::msx_cart_moonsound(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, MSX_CART_MOONSOUND, "MSX Cartridge - MoonSound", tag, owner, clock, "msx_moonsound", __FILE__) + , msx_cart_interface(mconfig, *this) + , m_ymf278b(*this, "ymf278b") +{ +} + + +static ADDRESS_MAP_START( ymf278b_map, AS_0, 8, msx_cart_moonsound ) + AM_RANGE(0x000000, 0x1fffff) AM_ROM + AM_RANGE(0x200000, 0x3fffff) AM_RAM // 2MB sram for testing +ADDRESS_MAP_END + + +static MACHINE_CONFIG_FRAGMENT( moonsound ) + // The moonsound cartridge has a separate stereo output. + MCFG_SPEAKER_STANDARD_STEREO("lspeaker", "rspeaker") + MCFG_SOUND_ADD("ymf278b", YMF278B, YMF278B_STD_CLOCK) + MCFG_DEVICE_ADDRESS_MAP(AS_0, ymf278b_map) + MCFG_YMF278B_IRQ_HANDLER(WRITELINE(msx_cart_moonsound,irq_w)) + MCFG_SOUND_ROUTE(0, "lspeaker", 0.50) + MCFG_SOUND_ROUTE(1, "rspeaker", 0.50) + MCFG_SOUND_ROUTE(2, "lspeaker", 0.40) + MCFG_SOUND_ROUTE(3, "rspeaker", 0.40) + MCFG_SOUND_ROUTE(4, "lspeaker", 0.40) + MCFG_SOUND_ROUTE(5, "rspeaker", 0.40) +MACHINE_CONFIG_END + + +machine_config_constructor msx_cart_moonsound::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( moonsound ); +} + + +ROM_START( msx_cart_moonsound ) + ROM_REGION(0x400000, "ymf278b", 0) + ROM_LOAD("yrw801.rom", 0x0, 0x200000, CRC(2a9d8d43) SHA1(32760893ce06dbe3930627755ba065cc3d8ec6ca)) +ROM_END + + +const rom_entry *msx_cart_moonsound::device_rom_region() const +{ + return ROM_NAME( msx_cart_moonsound ); +} + + +void msx_cart_moonsound::device_start() +{ + m_out_irq_cb.resolve_safe(); + + // Install IO read/write handlers + address_space &space = machine().device("maincpu")->space(AS_IO); + space.install_readwrite_handler(0x7e, 0x7f, read8_delegate(FUNC(msx_cart_moonsound::read_ymf278b_pcm), this), write8_delegate(FUNC(msx_cart_moonsound::write_ymf278b_pcm), this)); + space.install_readwrite_handler(0xc4, 0xc7, read8_delegate(FUNC(msx_cart_moonsound::read_ymf278b_fm), this), write8_delegate(FUNC(msx_cart_moonsound::write_ymf278b_fm), this)); + space.install_read_handler(0xc0, 0xc0, read8_delegate(FUNC(msx_cart_moonsound::read_c0), this)); +} + + +void msx_cart_moonsound::device_reset() +{ +} + + +WRITE_LINE_MEMBER(msx_cart_moonsound::irq_w) +{ + LOG(("moonsound: irq state %d\n", state)); + m_out_irq_cb(state); +} + + +WRITE8_MEMBER(msx_cart_moonsound::write_ymf278b_fm) +{ + LOG(("moonsound: write 0x%02x, data 0x%02x\n", 0xc4 + offset, data)); + m_ymf278b->write(space, offset, data); +} + + +READ8_MEMBER(msx_cart_moonsound::read_ymf278b_fm) +{ + LOG(("moonsound: read 0x%02x\n", 0xc4 + offset)); + return m_ymf278b->read(space, offset); +} + + +WRITE8_MEMBER(msx_cart_moonsound::write_ymf278b_pcm) +{ + LOG(("moonsound: write 0x%02x, data 0x%02x\n", 0x7e + offset, data)); + m_ymf278b->write(space, 4 + offset, data); +} + + +READ8_MEMBER(msx_cart_moonsound::read_ymf278b_pcm) +{ + LOG(("moonsound: read 0x%02x\n", 0x7e + offset)); + return m_ymf278b->read(space, 4 + offset); +} + + +// For detecting presence of moonsound cartridge +READ8_MEMBER(msx_cart_moonsound::read_c0) +{ + LOG(("moonsound: read 0xc0\n")); + return 0x00; +} diff --git a/src/devices/bus/msx_cart/moonsound.h b/src/devices/bus/msx_cart/moonsound.h new file mode 100644 index 00000000000..e09aa0e58d2 --- /dev/null +++ b/src/devices/bus/msx_cart/moonsound.h @@ -0,0 +1,37 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +#ifndef __MSX_CART_MOONSOUND_H +#define __MSX_CART_MOONSOUND_H + +#include "bus/msx_cart/cartridge.h" +#include "sound/ymf278b.h" + + +extern const device_type MSX_CART_MOONSOUND; + + +class msx_cart_moonsound : public device_t + , public msx_cart_interface +{ +public: + msx_cart_moonsound(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual machine_config_constructor device_mconfig_additions() const; + virtual const rom_entry *device_rom_region() const; + + DECLARE_WRITE8_MEMBER(write_ymf278b_fm); + DECLARE_READ8_MEMBER(read_ymf278b_fm); + DECLARE_WRITE8_MEMBER(write_ymf278b_pcm); + DECLARE_READ8_MEMBER(read_ymf278b_pcm); + DECLARE_READ8_MEMBER(read_c0); + DECLARE_WRITE_LINE_MEMBER(irq_w); + +private: + required_device m_ymf278b; +}; + + +#endif diff --git a/src/devices/bus/msx_cart/msx_audio.c b/src/devices/bus/msx_cart/msx_audio.c new file mode 100644 index 00000000000..640dbc02b07 --- /dev/null +++ b/src/devices/bus/msx_cart/msx_audio.c @@ -0,0 +1,389 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +/********************************************************************************** + +Emulation of the different MSX-AUDIO devices: + +- Panasonic FS-CA1 + - Y8950 + - 4KB ram + - Connector for Toshiba HX-MU901 keyboard + +- Toshiba HX-MU900 + - Y8950 + - No midi ports + - No ram + - Connector for Toshiba HX-MU901 keyboard + +- Philips NMS-1205 + - Y8950 + - Midi ports + - 32KB sample ram + - Connector for Philips NMS-1160 keyboard + + +The keyboards: +- Toshiba HX-MU901 + - 49 keys: 4 full octaves + high C + - ENTER key + - SELECT key + - multi sensor (?) + +- Philips NMS-1160 + - 61 keys: 5 full octaves + high C + - Different wiring, so incompatible with the other keyboards + +- Panasonic YK-20 + - 49 keys: 4 full octaves + high C + + +TODO: +- Test MIDI in/out/through +- Sample RAM, doesn't seem to get written to +- Test NMS-1160 keyboard +- HX-MU901: ENTER/SELECT keys and multi sensors +- NMS1160: Test the keyboard +- NMS1205: Add DAC +- NMS1205/FSCA1: Add muting of dac and y8950 based on io config writes. + + +For testing the sample ram (playback of a cuckoo sound, the volume of the sound is quite low): +- Disable firmware on the fs-ca1 +- Execute the following basic commands: + - CALL AUDIO + - CALL COPY PCM(#1,0) + - CALL PLAY PCM(0) + +See also http://www.mccm.hetlab.tk/millennium/milc/gc/topic_26.htm (dutch) +and/or http://ngs.no.coocan.jp/doc/wiki.cgi/datapack?page=4.2+MSX-AUDIO+%B3%C8%C4%A5BASIC (japanese) + + +**********************************************************************************/ + +#include "emu.h" +#include "msx_audio.h" +#include "bus/msx_cart/msx_audio_kb.h" + + +const device_type MSX_CART_MSX_AUDIO_HXMU900 = &device_creator; +const device_type MSX_CART_MSX_AUDIO_NMS1205 = &device_creator; +const device_type MSX_CART_MSX_AUDIO_FSCA1 = &device_creator; + + +msx_cart_msx_audio_hxmu900::msx_cart_msx_audio_hxmu900(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, MSX_CART_MSX_AUDIO_HXMU900, "MSX Cartridge - MSX-AUDIO HX-MU900", tag, owner, clock, "msx_audio_hxmu900", __FILE__) + , msx_cart_interface(mconfig, *this) + , m_y8950(*this, "y8950") +{ +} + + +static MACHINE_CONFIG_FRAGMENT( msx_audio_hxmu900 ) + // This is actually incorrect. The sound output is passed back into the MSX machine where it is mixed internally and output through the system 'speaker'. + MCFG_SPEAKER_STANDARD_MONO("mono") + MCFG_SOUND_ADD("y8950", Y8950, XTAL_3_579545MHz) // Not verified + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.40) + MCFG_Y8950_KEYBOARD_WRITE_HANDLER(DEVWRITE8("kbdc", msx_audio_kbdc_port_device, write)) + MCFG_Y8950_KEYBOARD_READ_HANDLER(DEVREAD8("kbdc", msx_audio_kbdc_port_device, read)) + + MCFG_MSX_AUDIO_KBDC_PORT_ADD("kbdc", msx_audio_keyboards, NULL) +MACHINE_CONFIG_END + + +machine_config_constructor msx_cart_msx_audio_hxmu900::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( msx_audio_hxmu900 ); +} + + +void msx_cart_msx_audio_hxmu900::device_start() +{ + // Install IO read/write handlers + address_space &space = machine().device("maincpu")->space(AS_IO); + space.install_write_handler(0xc0, 0xc1, write8_delegate(FUNC(y8950_device::write), m_y8950.target())); + space.install_read_handler(0xc0, 0xc1, read8_delegate(FUNC(y8950_device::read), m_y8950.target())); +} + + +void msx_cart_msx_audio_hxmu900::initialize_cartridge() +{ + if (get_rom_size() < 0x8000) + { + fatalerror("msx_audio: Invalid ROM size\n"); + } +} + + +READ8_MEMBER(msx_cart_msx_audio_hxmu900::read_cart) +{ + if (offset >= 0x4000 && offset < 0xC000) + { + return m_rom[offset - 0x4000]; + } + return 0xff; +} + + + + + +msx_cart_msx_audio_nms1205::msx_cart_msx_audio_nms1205(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, MSX_CART_MSX_AUDIO_NMS1205, "MSX Cartridge - MSX-AUDIO NMS-1205", tag, owner, clock, "msx_audio_nms1205", __FILE__) + , msx_cart_interface(mconfig, *this) + , m_y8950(*this, "y8950") + , m_acia6850(*this, "acia6850") + , m_mdout(*this, "mdout") + , m_mdthru(*this, "mdthru") +{ +} + + +static MACHINE_CONFIG_FRAGMENT( msx_audio_nms1205 ) + // This is actually incorrect. The sound output is passed back into the MSX machine where it is mixed internally and output through the system 'speaker'. + // At the same time the sound is also output on two output on the nms1205 cartridge itself + MCFG_SPEAKER_STANDARD_MONO("mono") + MCFG_SOUND_ADD("y8950", Y8950, XTAL_3_579545MHz) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.40) + MCFG_Y8950_KEYBOARD_WRITE_HANDLER(DEVWRITE8("kbdc", msx_audio_kbdc_port_device, write)) + MCFG_Y8950_KEYBOARD_READ_HANDLER(DEVREAD8("kbdc", msx_audio_kbdc_port_device, read)) + MCFG_Y8950_IRQ_HANDLER(WRITELINE(msx_cart_msx_audio_nms1205, irq_write)) + + MCFG_MSX_AUDIO_KBDC_PORT_ADD("kbdc", msx_audio_keyboards, NULL) + + // There is a 2 MHz crystal on the PCB, the 6850 TX and RX clocks are derived from it + MCFG_DEVICE_ADD("acia6850", ACIA6850, 0) + MCFG_ACIA6850_TXD_HANDLER(DEVWRITELINE("mdout", midi_port_device, write_txd)) + + MCFG_MIDI_PORT_ADD("mdin", midiin_slot, "midiin") + MCFG_MIDI_RX_HANDLER(WRITELINE(msx_cart_msx_audio_nms1205, midi_in)) + + MCFG_MIDI_PORT_ADD("mdthru", midiout_slot, "midiout") + + MCFG_MIDI_PORT_ADD("mdout", midiout_slot, "midiout") +MACHINE_CONFIG_END + + +machine_config_constructor msx_cart_msx_audio_nms1205::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( msx_audio_nms1205 ); +} + + +ROM_START( msx_nms1205 ) + ROM_REGION(0x8000, "y8950", ROMREGION_ERASE00) +ROM_END + + +const rom_entry *msx_cart_msx_audio_nms1205::device_rom_region() const +{ + return ROM_NAME( msx_nms1205 ); +} + + +WRITE_LINE_MEMBER(msx_cart_msx_audio_nms1205::irq_write) +{ + // Trigger IRQ on the maincpu + // The 8950 seems to trigger an irq on reset, this causes an infinite loop of continuously triggering + // the MSX's interrupt handler. The 8950 irq will never be cleared the nms1205's irq handler hook hasn't + // been installed yet. +// m_out_irq_cb(state); +} + + +WRITE_LINE_MEMBER(msx_cart_msx_audio_nms1205::midi_in) +{ + // MIDI in signals is sent to both the 6850 and the MIDI thru output port + m_acia6850->write_rxd(state); + m_mdthru->write_txd(state); +} + + +void msx_cart_msx_audio_nms1205::device_start() +{ + // Install IO read/write handlers + address_space &space = machine().device("maincpu")->space(AS_IO); + space.install_write_handler(0xc0, 0xc1, write8_delegate(FUNC(y8950_device::write), m_y8950.target())); + space.install_read_handler(0xc0, 0xc1, read8_delegate(FUNC(y8950_device::read), m_y8950.target())); + space.install_write_handler(0x00, 0x00, write8_delegate(FUNC(acia6850_device::control_w), m_acia6850.target())); + space.install_write_handler(0x01, 0x01, write8_delegate(FUNC(acia6850_device::data_w), m_acia6850.target())); + space.install_read_handler(0x04,0x04, read8_delegate(FUNC(acia6850_device::status_r), m_acia6850.target())); + space.install_read_handler(0x05,0x05, read8_delegate(FUNC(acia6850_device::data_r), m_acia6850.target())); +} + + +void msx_cart_msx_audio_nms1205::initialize_cartridge() +{ + if (get_rom_size() < 0x8000) + { + fatalerror("msx_audio: Invalid ROM size\n"); + } +} + + +READ8_MEMBER(msx_cart_msx_audio_nms1205::read_cart) +{ + if (offset >= 0x4000 && offset < 0xC000) + { + return m_rom[offset - 0x4000]; + } + return 0xff; +} + + + + + + + +msx_cart_msx_audio_fsca1::msx_cart_msx_audio_fsca1(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, MSX_CART_MSX_AUDIO_FSCA1, "MSX Cartridge - MSX-AUDIO FS-CA1", tag, owner, clock, "msx_audio_fsca1", __FILE__) + , msx_cart_interface(mconfig, *this) + , m_y8950(*this, "y8950") + , m_io_config(*this, "CONFIG") + , m_region_y8950(*this, "y8950") + , m_7ffe(0) + , m_7fff(0) +{ +} + + +static MACHINE_CONFIG_FRAGMENT( msx_audio_fsca1 ) + // This is actually incorrect. The sound output is passed back into the MSX machine where it is mixed internally and output through the system 'speaker'. + MCFG_SPEAKER_STANDARD_MONO("mono") + MCFG_SOUND_ADD("y8950", Y8950, XTAL_3_579545MHz) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.40) + MCFG_Y8950_KEYBOARD_WRITE_HANDLER(DEVWRITE8("kbdc", msx_audio_kbdc_port_device, write)) + MCFG_Y8950_KEYBOARD_READ_HANDLER(DEVREAD8("kbdc", msx_audio_kbdc_port_device, read)) + MCFG_Y8950_IO_READ_HANDLER(READ8(msx_cart_msx_audio_fsca1, y8950_io_r)) + MCFG_Y8950_IO_WRITE_HANDLER(WRITE8(msx_cart_msx_audio_fsca1, y8950_io_w)) + + MCFG_MSX_AUDIO_KBDC_PORT_ADD("kbdc", msx_audio_keyboards, NULL) +MACHINE_CONFIG_END + + +machine_config_constructor msx_cart_msx_audio_fsca1::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( msx_audio_fsca1 ); +} + + +static INPUT_PORTS_START( msx_audio_fsca1 ) + PORT_START("CONFIG") + PORT_CONFNAME( 0x04, 0x04, "FS-CA1 Firmware switch") + PORT_CONFSETTING( 0x04, "On" ) + PORT_CONFSETTING( 0x00, "Off" ) + PORT_BIT(0xFB, IP_ACTIVE_HIGH, IPT_UNKNOWN) +INPUT_PORTS_END + + +ioport_constructor msx_cart_msx_audio_fsca1::device_input_ports() const +{ + return INPUT_PORTS_NAME( msx_audio_fsca1 ); +} + + +ROM_START( msx_fsca1 ) + ROM_REGION(0x8000, "y8950", ROMREGION_ERASE00) +ROM_END + + +const rom_entry *msx_cart_msx_audio_fsca1::device_rom_region() const +{ + return ROM_NAME( msx_fsca1 ); +} + + +void msx_cart_msx_audio_fsca1::device_start() +{ + // Install IO read/write handlers + address_space &space = machine().device("maincpu")->space(AS_IO); + space.install_write_handler(0xc0, 0xc3, write8_delegate(FUNC(msx_cart_msx_audio_fsca1::write_y8950), this)); + space.install_read_handler(0xc0, 0xc3, read8_delegate(FUNC(msx_cart_msx_audio_fsca1::read_y8950), this)); +} + + +void msx_cart_msx_audio_fsca1::initialize_cartridge() +{ + if (get_rom_size() < 0x20000) + { + fatalerror("msx_audio_fsca1: Invalid ROM size\n"); + } +} + + +READ8_MEMBER(msx_cart_msx_audio_fsca1::read_cart) +{ + if (m_7ffe == 0 && (offset & 0xB000) == 0x3000) + { + return m_sram[offset & 0xfff]; + } + return m_rom[((m_7ffe & 0x03) << 15) | (offset & 0x7fff)]; +} + + +WRITE8_MEMBER(msx_cart_msx_audio_fsca1::write_cart) +{ + if (offset == 0x7ffe) + { + m_7ffe = data; + return; + } + + if (offset == 0x7fff) + { + m_7fff = data; + return; + } + + if (m_7ffe == 0 && (offset & 0xb000) == 0x3000) + { + m_sram[offset & 0xfff] = data; + return; + } + + logerror("msx_cart_msx_audio_fsca1: Unhandled write %02x to %04x\n", data, offset); +} + + +WRITE8_MEMBER(msx_cart_msx_audio_fsca1::write_y8950) +{ + if (offset & 2) + { + if (m_7fff & 0x02) + { + m_y8950->write(space, offset, data); + } + } + else + { + if (m_7fff & 0x01) + { + m_y8950->write(space, offset, data); + } + } +} + + +READ8_MEMBER(msx_cart_msx_audio_fsca1::read_y8950) +{ + if (offset & 2) + { + return (m_7fff & 0x02) ? m_y8950->read(space, offset) : 0xff; + } + else + { + return (m_7fff & 0x01) ? m_y8950->read(space, offset) : 0xff; + } +} + + +WRITE8_MEMBER(msx_cart_msx_audio_fsca1::y8950_io_w) +{ + logerror("msx_fsca1::y8950_io_w: %02x\n", data); +} + + +READ8_MEMBER(msx_cart_msx_audio_fsca1::y8950_io_r) +{ + return m_io_config->read(); +} diff --git a/src/devices/bus/msx_cart/msx_audio.h b/src/devices/bus/msx_cart/msx_audio.h new file mode 100644 index 00000000000..f62462e29a5 --- /dev/null +++ b/src/devices/bus/msx_cart/msx_audio.h @@ -0,0 +1,93 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +#ifndef __MSX_CART_MSX_AUDIO_H +#define __MSX_CART_MSX_AUDIO_H + +#include "bus/msx_cart/cartridge.h" +#include "sound/8950intf.h" +#include "machine/6850acia.h" +#include "bus/midi/midi.h" + + +extern const device_type MSX_CART_MSX_AUDIO_NMS1205; +extern const device_type MSX_CART_MSX_AUDIO_HXMU900; +extern const device_type MSX_CART_MSX_AUDIO_FSCA1; + + +class msx_cart_msx_audio_hxmu900 : public device_t + , public msx_cart_interface +{ +public: + msx_cart_msx_audio_hxmu900(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual machine_config_constructor device_mconfig_additions() const; + + virtual void initialize_cartridge(); + + virtual DECLARE_READ8_MEMBER(read_cart); + +private: + required_device m_y8950; +}; + + +class msx_cart_msx_audio_nms1205 : public device_t + , public msx_cart_interface +{ +public: + msx_cart_msx_audio_nms1205(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual machine_config_constructor device_mconfig_additions() const; + virtual const rom_entry *device_rom_region() const; + + virtual void initialize_cartridge(); + + virtual DECLARE_READ8_MEMBER(read_cart); + + DECLARE_WRITE_LINE_MEMBER(midi_in); + DECLARE_WRITE_LINE_MEMBER(irq_write); + +private: + required_device m_y8950; + required_device m_acia6850; + required_device m_mdout; + required_device m_mdthru; +}; + + +class msx_cart_msx_audio_fsca1 : public device_t + , public msx_cart_interface +{ +public: + msx_cart_msx_audio_fsca1(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual machine_config_constructor device_mconfig_additions() const; + virtual ioport_constructor device_input_ports() const; + virtual const rom_entry *device_rom_region() const; + + virtual void initialize_cartridge(); + + virtual DECLARE_READ8_MEMBER(read_cart); + virtual DECLARE_WRITE8_MEMBER(write_cart); + + DECLARE_WRITE8_MEMBER(write_y8950); + DECLARE_READ8_MEMBER(read_y8950); + + DECLARE_WRITE8_MEMBER(y8950_io_w); + DECLARE_READ8_MEMBER(y8950_io_r); + +private: + required_device m_y8950; + required_ioport m_io_config; + required_memory_region m_region_y8950; + UINT8 m_7ffe; + UINT8 m_7fff; +}; + +#endif diff --git a/src/devices/bus/msx_cart/msx_audio_kb.c b/src/devices/bus/msx_cart/msx_audio_kb.c new file mode 100644 index 00000000000..eb6ca123c39 --- /dev/null +++ b/src/devices/bus/msx_cart/msx_audio_kb.c @@ -0,0 +1,313 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +#include "emu.h" +#include "msx_audio_kb.h" + + +const device_type MSX_AUDIO_KBDC_PORT = &device_creator; + + +msx_audio_kbdc_port_device::msx_audio_kbdc_port_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, MSX_AUDIO_KBDC_PORT, "MSX Audio keyboard connector port", tag, owner, clock, "msx_audio_kbdc_port", __FILE__) + , device_slot_interface(mconfig, *this) +{ +} + + +void msx_audio_kbdc_port_device::device_start() +{ + m_keyboard = dynamic_cast(get_card_device()); +} + + +WRITE8_MEMBER(msx_audio_kbdc_port_device::write) +{ + if (m_keyboard) + { + m_keyboard->write(space, offset, data); + } +} + + +READ8_MEMBER(msx_audio_kbdc_port_device::read) +{ + if (m_keyboard) + { + return m_keyboard->read(space, offset); + } + return 0xff; +} + + +extern const device_type MSX_AUDIO_KB_HXMU901; +extern const device_type MSX_AUDIO_KB_NMS1160; + + +class msx_hxmu901 : public device_t + , public msx_audio_kb_port_interface +{ +public: + msx_hxmu901(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, MSX_AUDIO_KB_HXMU901, "Toshiba HXMU901", tag, owner, clock, "hxmu901", __FILE__) + , msx_audio_kb_port_interface(mconfig, *this) + , m_row(0) + , m_keyboard(*this, "KEY") + { }; + + virtual ioport_constructor device_input_ports() const; + + virtual DECLARE_READ8_MEMBER(read) + { + UINT8 result = 0xff; + + for (int i = 0; i < 8; i++) + { + if (BIT(m_row,i)) + { + result &= m_keyboard[i]->read(); + } + } + return result; + } + + virtual DECLARE_WRITE8_MEMBER(write) + { + m_row = data; + } + +protected: + virtual void device_start() { } + +private: + UINT8 m_row; + required_ioport_array<8> m_keyboard; +}; + + +static INPUT_PORTS_START( hxmu901) + PORT_START("KEY.0") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("C#1") + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("D1") + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("D#1") + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_UNKNOWN) // Multi sensor related? + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("E1") + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("F1") + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("F#1") + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("C1") + + PORT_START("KEY.1") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("G1") + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("G#1") + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("A1") + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_UNKNOWN) // Multi sensor related? + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("A#1") + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("B1") + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("C2") + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_UNUSED) + + PORT_START("KEY.2") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("C#2") + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("D2") + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("D#2") + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_UNKNOWN) // Multi sensor related? + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("E2") + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("F2") + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("F#2") + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_UNUSED) + + PORT_START("KEY.3") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("G2") + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("G#2") + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("A2") + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_UNKNOWN) // Multi sensor related? + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("A#2") + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("B2") + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("C3") + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_UNUSED) + + PORT_START("KEY.4") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("C#3") + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("D3") + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("D#3") + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_UNKNOWN) // Multi sensor related? + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("E3") + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("F3") + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("F#3") + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_UNUSED) + + PORT_START("KEY.5") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("G3") + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("G#3") + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("A3") + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_UNKNOWN) // Multi sensor related? + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("A#3") + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("B3") + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("C4") + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_UNUSED) + + PORT_START("KEY.6") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("C#4") + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("D4") + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("D#4") + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_UNKNOWN) // Multi sensor related? + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("E4") + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("F4") + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("F#4") + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_UNUSED) + + PORT_START("KEY.7") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("G4") + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("G#4") + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("A4") + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_UNKNOWN) // Multi sensor related? + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("A#4") + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("B4") + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("C5") + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_UNUSED) +INPUT_PORTS_END + + +ioport_constructor msx_hxmu901::device_input_ports() const +{ + return INPUT_PORTS_NAME( hxmu901 ); +} + + +class msx_nms1160 : public device_t + , public msx_audio_kb_port_interface +{ +public: + msx_nms1160(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, MSX_AUDIO_KB_NMS1160, "Philips NMS-1160", tag, owner, clock, "nms1160", __FILE__) + , msx_audio_kb_port_interface(mconfig, *this) + , m_row(0) + , m_keyboard(*this, "KEY") + { }; + + virtual ioport_constructor device_input_ports() const; + + virtual DECLARE_READ8_MEMBER(read) + { + UINT8 result = 0xff; + + for (int i = 0; i < 8; i++) + { + if (BIT(m_row,i)) + { + result &= m_keyboard[i]->read(); + } + } + return result; + } + + virtual DECLARE_WRITE8_MEMBER(write) + { + logerror("msx_nms1160::write %02x\n", data); + m_row = data; + } + +protected: + virtual void device_start() { } + +private: + UINT8 m_row; + required_ioport_array<8> m_keyboard; +}; + + +static INPUT_PORTS_START( nms1160 ) + PORT_START("KEY.0") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("C1") + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("C#1") + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("D1") + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("D#1") + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("E1") + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("F1") + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("F#1") + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("G1") + + PORT_START("KEY.1") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("G#1") + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("A1") + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("A#1") + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("B1") + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("C2") + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("C#2") + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("D2") + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("D#2") + + PORT_START("KEY.2") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("E2") + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("F2") + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("F#2") + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("G2") + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("G#2") + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("A2") + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("A#2") + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("B2") + + PORT_START("KEY.3") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("C3") + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("C#3") + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("D3") + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("D#3") + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("E3") + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("F3") + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("F#3") + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("G3") + + PORT_START("KEY.4") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("G#3") + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("A3") + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("A#3") + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("B3") + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("C4") + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("C#4") + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("D4") + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("D#4") + + PORT_START("KEY.5") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("E4") + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("F4") + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("F#4") + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("G4") + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("G#4") + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("A4") + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("A#4") + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("B4") + + PORT_START("KEY.6") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("C5") + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("C#5") + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("D5") + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("D#5") + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("E5") + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("F5") + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("F#5") + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("G5") + + PORT_START("KEY.7") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("G#5") + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("A5") + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("A#5") + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("B5") + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("C6") + PORT_BIT(0xe0, IP_ACTIVE_LOW, IPT_UNUSED) +INPUT_PORTS_END + + +ioport_constructor msx_nms1160::device_input_ports() const +{ + return INPUT_PORTS_NAME( nms1160 ); +} + + + +const device_type MSX_AUDIO_KB_HXMU901 = &device_creator; +const device_type MSX_AUDIO_KB_NMS1160 = &device_creator; + + +SLOT_INTERFACE_START( msx_audio_keyboards ) + SLOT_INTERFACE("hxmu901", MSX_AUDIO_KB_HXMU901) + SLOT_INTERFACE("nms1160", MSX_AUDIO_KB_NMS1160) +SLOT_INTERFACE_END diff --git a/src/devices/bus/msx_cart/msx_audio_kb.h b/src/devices/bus/msx_cart/msx_audio_kb.h new file mode 100644 index 00000000000..db09bf64dd9 --- /dev/null +++ b/src/devices/bus/msx_cart/msx_audio_kb.h @@ -0,0 +1,49 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +#ifndef __MSX_AUDIO_KB_H__ +#define __MSX_AUDIO_KB_H__ + + +extern const device_type MSX_AUDIO_KBDC_PORT; + + +#define MCFG_MSX_AUDIO_KBDC_PORT_ADD(_tag, _slot_intf, _def_slot) \ + MCFG_DEVICE_ADD(_tag, MSX_AUDIO_KBDC_PORT, 0 ) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) + + +class msx_audio_kb_port_interface : public device_slot_card_interface +{ +public: + // construction/destruction + msx_audio_kb_port_interface(const machine_config &mconfig, device_t &device) + : device_slot_card_interface(mconfig, device) + { }; + + virtual DECLARE_READ8_MEMBER(read) { return 0xff; }; + virtual DECLARE_WRITE8_MEMBER(write) { }; +}; + + +class msx_audio_kbdc_port_device : public device_t, + public device_slot_interface +{ +public: + // construction/destruction + msx_audio_kbdc_port_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + + // Physical connection simply consists of 8 input and 8 output lines split across 2 connectors + DECLARE_WRITE8_MEMBER(write); + DECLARE_READ8_MEMBER(read); + + msx_audio_kb_port_interface *m_keyboard; +}; + + +SLOT_INTERFACE_EXTERN( msx_audio_keyboards ); + + +#endif diff --git a/src/devices/bus/msx_cart/msxdos2.c b/src/devices/bus/msx_cart/msxdos2.c new file mode 100644 index 00000000000..b3c127a10cb --- /dev/null +++ b/src/devices/bus/msx_cart/msxdos2.c @@ -0,0 +1,67 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +#include "emu.h" +#include "msxdos2.h" + +const device_type MSX_CART_MSXDOS2 = &device_creator; + + +msx_cart_msxdos2::msx_cart_msxdos2(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, MSX_CART_MSXDOS2, "MSX Cartridge - MSXDOS2", tag, owner, clock, "msx_cart_msxdos2", __FILE__) + , msx_cart_interface(mconfig, *this) + , m_selected_bank(0) + , m_bank_base(NULL) +{ +} + + +void msx_cart_msxdos2::device_start() +{ + save_item(NAME(m_selected_bank)); + + machine().save().register_postload(save_prepost_delegate(FUNC(msx_cart_msxdos2::restore_banks), this)); +} + + +void msx_cart_msxdos2::restore_banks() +{ + m_bank_base = get_rom_base() + ( m_selected_bank & 0x03 ) * 0x4000; +} + + +void msx_cart_msxdos2::device_reset() +{ + m_selected_bank = 0; +} + + +void msx_cart_msxdos2::initialize_cartridge() +{ + if (get_rom_size() != 0x10000) + { + fatalerror("msxdos2: Invalid ROM size\n"); + } + + restore_banks(); +} + + +READ8_MEMBER(msx_cart_msxdos2::read_cart) +{ + if (offset >= 0x4000 && offset < 0x8000) + { + return m_bank_base[offset & 0x3fff]; + } + + return 0xff; +} + + +WRITE8_MEMBER(msx_cart_msxdos2::write_cart) +{ + if (offset == 0x6000) + { + m_selected_bank = data; + restore_banks(); + } +} diff --git a/src/devices/bus/msx_cart/msxdos2.h b/src/devices/bus/msx_cart/msxdos2.h new file mode 100644 index 00000000000..1209b102372 --- /dev/null +++ b/src/devices/bus/msx_cart/msxdos2.h @@ -0,0 +1,35 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +#ifndef __MSX_CART_MSXDOS2_H +#define __MSX_CART_MSXDOS2_H + +#include "bus/msx_cart/cartridge.h" + + +extern const device_type MSX_CART_MSXDOS2; + + +class msx_cart_msxdos2 : public device_t + , public msx_cart_interface +{ +public: + msx_cart_msxdos2(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + virtual void initialize_cartridge(); + + virtual DECLARE_READ8_MEMBER(read_cart); + virtual DECLARE_WRITE8_MEMBER(write_cart); + + void restore_banks(); + +private: + UINT8 m_selected_bank; + UINT8 *m_bank_base; +}; + + +#endif diff --git a/src/devices/bus/msx_cart/nomapper.c b/src/devices/bus/msx_cart/nomapper.c new file mode 100644 index 00000000000..922649d5c1f --- /dev/null +++ b/src/devices/bus/msx_cart/nomapper.c @@ -0,0 +1,94 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol + +#include "emu.h" +#include "nomapper.h" + +const device_type MSX_CART_NOMAPPER = &device_creator; + + +msx_cart_nomapper::msx_cart_nomapper(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, MSX_CART_NOMAPPER, "MSX Cartridge - ROM", tag, owner, clock, "msx_cart_nomapper", __FILE__) + , msx_cart_interface(mconfig, *this) + , m_start_address(0) + , m_end_address(0) +{ +} + +void msx_cart_nomapper::device_start() +{ +} + +void msx_cart_nomapper::initialize_cartridge() +{ + UINT32 size = get_rom_size(); + UINT8 *rom = get_rom_base(); + + // determine start address + // default to $4000 + m_start_address = 0x4000; + + switch (size) + { + /* 8KB/16KB */ + case 0x2000: case 0x4000: + { + UINT16 start = rom[3] << 8 | rom[2]; + + // start address of $0000: call address in the $4000 region: $4000, else $8000 + if (start == 0) + { + if ((rom[5] & 0xc0) == 0x40) + m_start_address = 0x4000; + else + m_start_address = 0x8000; + } + + // start address in the $8000 region: $8000, else default + else if ((start & 0xc000) == 0x8000) + m_start_address = 0x8000; + + break; + } + + /* 32KB */ + case 0x8000: + // take default, check when no "AB" at $0000, but "AB" at $4000 + if (rom[0] != 'A' && rom[1] != 'B' && rom[0x4000] == 'A' && rom[0x4001] == 'B') + { + UINT16 start = rom[0x4003] << 8 | rom[0x4002]; + + // start address of $0000 and call address in the $4000 region, or start address outside the $8000 region: $0000, else default + if ((start == 0 && (rom[0x4005] & 0xc0) == 0x40) || start < 0x8000 || start >= 0xc000) + m_start_address = 0; + } + + break; + + /* 48KB */ + case 0xc000: + // "AB" at $0000, but no "AB" at $4000, not "AB": $0000 + if (rom[0] == 'A' && rom[1] == 'B' && rom[0x4000] != 'A' && rom[0x4001] != 'B') + m_start_address = 0x4000; + else + m_start_address = 0; + + break; + + /* 64KB */ + default: + m_start_address = 0; + break; + } + + m_end_address = MIN(m_start_address + size, 0x10000); +} + +READ8_MEMBER(msx_cart_nomapper::read_cart) +{ + if ( offset >= m_start_address && offset < m_end_address ) + { + return get_rom_base()[offset - m_start_address]; + } + return 0xff; +} diff --git a/src/devices/bus/msx_cart/nomapper.h b/src/devices/bus/msx_cart/nomapper.h new file mode 100644 index 00000000000..b0c197d2545 --- /dev/null +++ b/src/devices/bus/msx_cart/nomapper.h @@ -0,0 +1,30 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +#ifndef __MSX_CART_NOMAPPER_H +#define __MSX_CART_NOMAPPER_H + +#include "bus/msx_cart/cartridge.h" + + +extern const device_type MSX_CART_NOMAPPER; + + +class msx_cart_nomapper : public device_t + , public msx_cart_interface +{ +public: + msx_cart_nomapper(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + + virtual void initialize_cartridge(); + + virtual DECLARE_READ8_MEMBER(read_cart); + +private: + UINT32 m_start_address; + UINT32 m_end_address; +}; + +#endif diff --git a/src/devices/bus/msx_cart/rtype.c b/src/devices/bus/msx_cart/rtype.c new file mode 100644 index 00000000000..e09a57894d7 --- /dev/null +++ b/src/devices/bus/msx_cart/rtype.c @@ -0,0 +1,78 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +#include "emu.h" +#include "rtype.h" + +const device_type MSX_CART_RTYPE = &device_creator; + + +msx_cart_rtype::msx_cart_rtype(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, MSX_CART_RTYPE, "MSX Cartridge - R-Type", tag, owner, clock, "msx_cart_rtype", __FILE__) + , msx_cart_interface(mconfig, *this) + , m_selected_bank(0) +{ + for (int i = 0; i < 2; i++) + { + m_bank_base[i] = NULL; + } +} + + +void msx_cart_rtype::device_start() +{ + save_item(NAME(m_selected_bank)); + + machine().save().register_postload(save_prepost_delegate(FUNC(msx_cart_rtype::restore_banks), this)); +} + + +void msx_cart_rtype::restore_banks() +{ + m_bank_base[0] = get_rom_base() + 15 * 0x4000; + if (m_selected_bank & 0x10) + { + m_selected_bank &= 0x17; + } + m_bank_base[1] = get_rom_base() + m_selected_bank * 0x4000; +} + + +void msx_cart_rtype::device_reset() +{ + m_selected_bank = 15; +} + + +void msx_cart_rtype::initialize_cartridge() +{ + if ( get_rom_size() != 0x80000 && get_rom_size() != 0x60000 ) + { + fatalerror("rtype: Invalid ROM size\n"); + } + + restore_banks(); +} + + +READ8_MEMBER(msx_cart_rtype::read_cart) +{ + if (offset >= 0x4000 && offset < 0xc000) + { + return m_bank_base[offset >> 15][offset & 0x3fff]; + } + return 0xff; +} + + +WRITE8_MEMBER(msx_cart_rtype::write_cart) +{ + if (offset >= 0x7000 && offset < 0x8000) + { + m_selected_bank = data & 0x1f; + if (m_selected_bank & 0x10) + { + m_selected_bank &= 0x17; + } + m_bank_base[1] = get_rom_base() + m_selected_bank * 0x4000; + } +} diff --git a/src/devices/bus/msx_cart/rtype.h b/src/devices/bus/msx_cart/rtype.h new file mode 100644 index 00000000000..e6bfec30de8 --- /dev/null +++ b/src/devices/bus/msx_cart/rtype.h @@ -0,0 +1,35 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +#ifndef __MSX_CART_RTYPE_H +#define __MSX_CART_RTYPE_H + +#include "bus/msx_cart/cartridge.h" + + +extern const device_type MSX_CART_RTYPE; + + +class msx_cart_rtype : public device_t + , public msx_cart_interface +{ +public: + msx_cart_rtype(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + virtual void initialize_cartridge(); + + virtual DECLARE_READ8_MEMBER(read_cart); + virtual DECLARE_WRITE8_MEMBER(write_cart); + + void restore_banks(); + +private: + UINT8 m_selected_bank; + UINT8 *m_bank_base[2]; +}; + + +#endif diff --git a/src/devices/bus/msx_cart/super_swangi.c b/src/devices/bus/msx_cart/super_swangi.c new file mode 100644 index 00000000000..61dffe0d567 --- /dev/null +++ b/src/devices/bus/msx_cart/super_swangi.c @@ -0,0 +1,72 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +#include "emu.h" +#include "super_swangi.h" + + +const device_type MSX_CART_SUPER_SWANGI = &device_creator; + + +msx_cart_super_swangi::msx_cart_super_swangi(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, MSX_CART_SUPER_SWANGI, "MSX Cartridge - Super Swangi", tag, owner, clock, "msx_cart_super_swangi", __FILE__) + , msx_cart_interface(mconfig, *this) + , m_selected_bank(0) +{ + m_bank_base[0] = m_bank_base[1] = NULL; +} + + +void msx_cart_super_swangi::device_start() +{ + save_item(NAME(m_selected_bank)); + + machine().save().register_postload(save_prepost_delegate(FUNC(msx_cart_super_swangi::restore_banks), this)); +} + + +void msx_cart_super_swangi::restore_banks() +{ + m_bank_base[0] = get_rom_base(); + m_bank_base[1] = get_rom_base() + (((m_selected_bank >> 1) * 0x4000) & 0xffff); +} + + +void msx_cart_super_swangi::device_reset() +{ + m_selected_bank = 0; +} + + +void msx_cart_super_swangi::initialize_cartridge() +{ + if (get_rom_size() < 0x10000) + { + fatalerror("rtype: Invalid ROM size\n"); + } + + restore_banks(); +} + + +READ8_MEMBER(msx_cart_super_swangi::read_cart) +{ + if (offset >= 0x4000 && offset < 0xc000) + { + return m_bank_base[offset >> 15][offset & 0x3fff]; + } + return 0xff; +} + + +WRITE8_MEMBER(msx_cart_super_swangi::write_cart) +{ + if (offset == 0x8000) + { + m_selected_bank = data; + restore_banks(); + } + else + { + logerror("msx_cart_super_swangi: unhandled write %02x to %04x\n", data, offset); + } +} diff --git a/src/devices/bus/msx_cart/super_swangi.h b/src/devices/bus/msx_cart/super_swangi.h new file mode 100644 index 00000000000..a71bf7fe250 --- /dev/null +++ b/src/devices/bus/msx_cart/super_swangi.h @@ -0,0 +1,35 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +#ifndef __MSX_CART_SUPER_SWANGI_H +#define __MSX_CART_SUPER_SWANGI_H + +#include "bus/msx_cart/cartridge.h" + + +extern const device_type MSX_CART_SUPER_SWANGI; + + +class msx_cart_super_swangi : public device_t + , public msx_cart_interface +{ +public: + msx_cart_super_swangi(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + virtual void initialize_cartridge(); + + virtual DECLARE_READ8_MEMBER(read_cart); + virtual DECLARE_WRITE8_MEMBER(write_cart); + + void restore_banks(); + +private: + UINT8 m_selected_bank; + UINT8 *m_bank_base[2]; +}; + + +#endif diff --git a/src/devices/bus/msx_cart/superloderunner.c b/src/devices/bus/msx_cart/superloderunner.c new file mode 100644 index 00000000000..c8bd6f6c973 --- /dev/null +++ b/src/devices/bus/msx_cart/superloderunner.c @@ -0,0 +1,62 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +#include "emu.h" +#include "superloderunner.h" + +const device_type MSX_CART_SUPERLODERUNNER = &device_creator; + + +msx_cart_superloderunner::msx_cart_superloderunner(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, MSX_CART_SUPERLODERUNNER, "MSX Cartridge - Super Lode Runner", tag, owner, clock, "msx_cart_superloderunner", __FILE__) + , msx_cart_interface(mconfig, *this) + , m_selected_bank(0) + , m_bank_base(NULL) +{ +} + + +void msx_cart_superloderunner::device_start() +{ + save_item(NAME(m_selected_bank)); + + machine().save().register_postload(save_prepost_delegate(FUNC(msx_cart_superloderunner::restore_banks), this)); + + // Install evil memory write handler + address_space &space = machine().device("maincpu")->space(AS_PROGRAM); + space.install_write_handler(0x0000, 0x0000, write8_delegate(FUNC(msx_cart_superloderunner::banking), this)); +} + + +void msx_cart_superloderunner::restore_banks() +{ + m_bank_base = get_rom_base() + (m_selected_bank & 0x0f) * 0x4000; +} + + +void msx_cart_superloderunner::initialize_cartridge() +{ + if (get_rom_size() != 0x20000) + { + fatalerror("superloderunner: Invalid ROM size\n"); + } + + restore_banks(); +} + + +READ8_MEMBER(msx_cart_superloderunner::read_cart) +{ + if (offset >= 0x8000 && offset < 0xc000) + { + return m_bank_base[offset & 0x3fff]; + } + + return 0xff; +} + + +WRITE8_MEMBER(msx_cart_superloderunner::banking) +{ + m_selected_bank = data; + restore_banks(); +} diff --git a/src/devices/bus/msx_cart/superloderunner.h b/src/devices/bus/msx_cart/superloderunner.h new file mode 100644 index 00000000000..f3737081b98 --- /dev/null +++ b/src/devices/bus/msx_cart/superloderunner.h @@ -0,0 +1,35 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +#ifndef __MSX_CART_SUPERLODERUNNER_H +#define __MSX_CART_SUPERLODERUNNER_H + +#include "bus/msx_cart/cartridge.h" + + +extern const device_type MSX_CART_SUPERLODERUNNER; + + +class msx_cart_superloderunner : public device_t + , public msx_cart_interface +{ +public: + msx_cart_superloderunner(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + + virtual void initialize_cartridge(); + + virtual DECLARE_READ8_MEMBER(read_cart); + + DECLARE_WRITE8_MEMBER(banking); + + void restore_banks(); + +private: + UINT8 m_selected_bank; + UINT8 *m_bank_base; +}; + + +#endif diff --git a/src/devices/bus/msx_cart/yamaha.c b/src/devices/bus/msx_cart/yamaha.c new file mode 100644 index 00000000000..b78ec43fb9f --- /dev/null +++ b/src/devices/bus/msx_cart/yamaha.c @@ -0,0 +1,205 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +/************************************************************************** + +Yamaha SFG01/SFG05 emulation + +TODO: +- Use a real YM2164 implementation for SFG05 + +**************************************************************************/ + +#include "emu.h" +#include "yamaha.h" +#include "bus/midi/midi.h" + + +const device_type MSX_CART_SFG01 = &device_creator; +const device_type MSX_CART_SFG05 = &device_creator; + + +msx_cart_sfg::msx_cart_sfg(const machine_config &mconfig, const device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname) + : device_t(mconfig, type, name, tag, owner, clock, shortname, __FILE__) + , msx_cart_interface(mconfig, *this) + , m_region_sfg(*this, "sfg") + , m_ym2151(*this, "ym2151") + , m_kbdc(*this, "kbdc") + , m_ym2148(*this, "ym2148") + , m_ym2151_irq_state(CLEAR_LINE) + , m_ym2148_irq_state(CLEAR_LINE) + , m_rom_mask(0) +{ +} + + +msx_cart_sfg01::msx_cart_sfg01(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : msx_cart_sfg(mconfig, MSX_CART_SFG01, "MSX Cartridge - SFG01", tag, owner, clock, "msx_cart_sfg01") +{ +} + + +msx_cart_sfg05::msx_cart_sfg05(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : msx_cart_sfg(mconfig, MSX_CART_SFG05, "MSX Cartridge - SFG05", tag, owner, clock, "msx_cart_sfg05") +{ +} + + +static MACHINE_CONFIG_FRAGMENT( msx_sfg ) + // YM2151 (OPM) + // YM3012 (DAC) + // YM2148 (MKS) + + MCFG_SPEAKER_STANDARD_STEREO("lspeaker", "rspeaker") + MCFG_YM2151_ADD("ym2151", XTAL_3_579545MHz) // The SFG01 uses a YM2151, the SFG05 uses a YM2164, input clock comes from the main cpu frequency + MCFG_YM2151_IRQ_HANDLER(WRITELINE(msx_cart_sfg, ym2151_irq_w)) + MCFG_SOUND_ROUTE(0, "lspeaker", 0.80) + MCFG_SOUND_ROUTE(1, "rspeaker", 0.80) + + MCFG_DEVICE_ADD("ym2148", YM2148, XTAL_4MHz) + MCFG_YM2148_TXD_HANDLER(DEVWRITELINE("mdout", midi_port_device, write_txd)) + MCFG_YM2148_PORT_WRITE_HANDLER(DEVWRITE8("kbdc", msx_audio_kbdc_port_device, write)) + MCFG_YM2148_PORT_READ_HANDLER(DEVREAD8("kbdc", msx_audio_kbdc_port_device, read)) + MCFG_YM2148_IRQ_HANDLER(WRITELINE(msx_cart_sfg,ym2148_irq_w)) + + MCFG_MSX_AUDIO_KBDC_PORT_ADD("kbdc", msx_audio_keyboards, NULL) + + MCFG_MIDI_PORT_ADD("mdout", midiout_slot, "midiout") + + MCFG_MIDI_PORT_ADD("mdin", midiin_slot, "midiin") + MCFG_MIDI_RX_HANDLER(DEVWRITELINE("ym2148", ym2148_device, write_rxd)) +MACHINE_CONFIG_END + + +machine_config_constructor msx_cart_sfg::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( msx_sfg ); +} + + +ROM_START( msx_sfg01 ) + ROM_REGION(0x4000, "sfg", 0) + ROM_LOAD("sfg01.rom", 0x0, 0x4000, CRC(0995fb36) SHA1(434651305f92aa770a89e40b81125fb22d91603d)) +ROM_END + + +const rom_entry *msx_cart_sfg01::device_rom_region() const +{ + return ROM_NAME( msx_sfg01 ); +} + + +ROM_START( msx_sfg05 ) + ROM_REGION(0x8000, "sfg", 0) + ROM_LOAD("sfg05.rom", 0x0, 0x8000, CRC(2425c279) SHA1(d956167e234f60ad916120437120f86fc8c3c321)) +ROM_END + + +const rom_entry *msx_cart_sfg05::device_rom_region() const +{ + return ROM_NAME( msx_sfg05 ); +} + + +void msx_cart_sfg::device_start() +{ + // Set rom mask + m_rom_mask = m_region_sfg->bytes() - 1; + + // This should probably moved up in the bus/slot hierarchy for the msx driver + cpu_device *maincpu = machine().device("maincpu"); + device_execute_interface::static_set_irq_acknowledge_callback(*maincpu, device_irq_acknowledge_delegate(FUNC(msx_cart_sfg::irq_callback),this)); +} + + +IRQ_CALLBACK_MEMBER(msx_cart_sfg::irq_callback) +{ + return m_ym2148->get_irq_vector(); +} + + +WRITE_LINE_MEMBER(msx_cart_sfg::ym2151_irq_w) +{ + m_ym2151_irq_state = state ? ASSERT_LINE : CLEAR_LINE; + check_irq(); +} + + +WRITE_LINE_MEMBER(msx_cart_sfg::ym2148_irq_w) +{ + m_ym2148_irq_state = state ? ASSERT_LINE : CLEAR_LINE; + check_irq(); +} + + +void msx_cart_sfg::check_irq() +{ + if (m_ym2151_irq_state != CLEAR_LINE || m_ym2148_irq_state != CLEAR_LINE) + { + m_out_irq_cb(ASSERT_LINE); + } + else + { + m_out_irq_cb(CLEAR_LINE); + } +} + + +READ8_MEMBER(msx_cart_sfg::read_cart) +{ + switch (offset & 0x3fff) + { + case 0x3ff0: // YM-2151 status read + case 0x3ff1: // YM-2151 status read mirror? + return m_ym2151->status_r(space, 0); + + case 0x3ff2: // YM-2148 keyboard column read + case 0x3ff3: // YM-2148 -- + case 0x3ff4: // YM-2148 -- + case 0x3ff5: // YM-2148 MIDI UART data read register + case 0x3ff6: // YM-2148 MIDI UART status register + // ------x- - 1 = received a byte/receive buffer full? + // -------x - 1 = ready to send next byte/send buffer empty? + return m_ym2148->read(space, offset & 7); + } + + if (offset < 0x8000) + { + return m_region_sfg->u8(offset & m_rom_mask); + } + + return 0xff; +} + + +WRITE8_MEMBER(msx_cart_sfg::write_cart) +{ + switch (offset & 0x3fff) + { + case 0x3ff0: // YM-2151 register + m_ym2151->register_w(space, 0, data); + break; + + case 0x3ff1: // YM-2151 data + m_ym2151->data_w(space, 0, data); + break; + + case 0x3ff2: // YM-2148 write keyboard row + case 0x3ff3: // YM-2148 MIDI IRQ vector + case 0x3ff4: // YM-2148 External IRQ vector + case 0x3ff5: // YM-2148 MIDI UART data write register + case 0x3ff6: // YM-2148 MIDI UART command register + // On startup the sfg01 writes 0x80 + // followed by 0x05. + // Other write seen in the code: 0x15 + // + // x------- - 1 = reset + // -----x-- - 1 = enable receiving / sending midi data + // -------x - 1 = enable receiving / sending midi data + m_ym2148->write(space, offset & 7, data); + break; + + default: + logerror("msx_cart_sfg::write_cart: write %02x to %04x\n", data, offset); + break; + } +} diff --git a/src/devices/bus/msx_cart/yamaha.h b/src/devices/bus/msx_cart/yamaha.h new file mode 100644 index 00000000000..c186ad52e16 --- /dev/null +++ b/src/devices/bus/msx_cart/yamaha.h @@ -0,0 +1,64 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +#ifndef __MSX_CART_YAMAHA_H +#define __MSX_CART_YAMAHA_H + +#include "bus/msx_cart/cartridge.h" +#include "sound/2151intf.h" +#include "bus/msx_cart/msx_audio_kb.h" +#include "machine/ym2148.h" + + +extern const device_type MSX_CART_SFG01; +extern const device_type MSX_CART_SFG05; + + +class msx_cart_sfg : public device_t + , public msx_cart_interface +{ +public: + msx_cart_sfg(const machine_config &mconfig, const device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname); + + // device-level overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual void device_start(); + + virtual DECLARE_READ8_MEMBER(read_cart); + virtual DECLARE_WRITE8_MEMBER(write_cart); + + DECLARE_WRITE_LINE_MEMBER(ym2151_irq_w); + DECLARE_WRITE_LINE_MEMBER(ym2148_irq_w); + + IRQ_CALLBACK_MEMBER(irq_callback); + +private: + required_memory_region m_region_sfg; + required_device m_ym2151; + required_device m_kbdc; + required_device m_ym2148; + int m_ym2151_irq_state; + int m_ym2148_irq_state; + UINT32 m_rom_mask; + + void check_irq(); +}; + + +class msx_cart_sfg01 : public msx_cart_sfg +{ +public: + msx_cart_sfg01(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual const rom_entry *device_rom_region() const; +}; + + +class msx_cart_sfg05 : public msx_cart_sfg +{ +public: + msx_cart_sfg05(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual const rom_entry *device_rom_region() const; +}; + +#endif diff --git a/src/devices/bus/msx_slot/bunsetsu.c b/src/devices/bus/msx_slot/bunsetsu.c new file mode 100644 index 00000000000..b8c1e7b4471 --- /dev/null +++ b/src/devices/bus/msx_slot/bunsetsu.c @@ -0,0 +1,78 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +/* + Emulation for the bunsetsu internal firmware mapper found in a number of MSX machines +*/ + +#include "emu.h" +#include "bunsetsu.h" + + +const device_type MSX_SLOT_BUNSETSU = &device_creator; + + +msx_slot_bunsetsu_device::msx_slot_bunsetsu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : msx_slot_rom_device(mconfig, MSX_SLOT_BUNSETSU, "MSX Internal BUNSETSU", tag, owner, clock, "msx_slot_bunsetsu", __FILE__) + , m_bunsetsu_region(NULL) + , m_bunsetsu_region_tag(NULL) + , m_bunsetsu_address(0) +{ +} + + +void msx_slot_bunsetsu_device::device_start() +{ + msx_slot_rom_device::device_start(); + + if (m_bunsetsu_region_tag == NULL) + { + fatalerror("msx_slot_bunsetsu_device: no bunsetsu region tag specified\n"); + } + + m_bunsetsu_region = owner()->memregion(m_bunsetsu_region_tag); + + if (m_bunsetsu_region == NULL) + { + fatalerror("msx_slot_bunsetsu_device: Unable to find region with tag '%s'\n", m_bunsetsu_region_tag); + } + + if (m_bunsetsu_region->bytes() != 0x20000) + { + fatalerror("msx_slot_bunsetsu_device: Bunsetsu region must be 0x20000 bytes.\n"); + } +} + + +void msx_slot_bunsetsu_device::device_reset() +{ + m_bunsetsu_address = 0; +} + + +READ8_MEMBER(msx_slot_bunsetsu_device::read) +{ + if (offset == 0xbfff) + { + return m_bunsetsu_region->u8(m_bunsetsu_address++ & 0x1ffff); + } + return msx_slot_rom_device::read(space, offset); +} + + +WRITE8_MEMBER(msx_slot_bunsetsu_device::write) +{ + switch (offset) + { + case 0xbffc: + m_bunsetsu_address = (m_bunsetsu_address & 0xffff00) | data; + break; + + case 0xbffd: + m_bunsetsu_address = (m_bunsetsu_address & 0xff00ff) | (data << 8); + break; + + case 0xbffe: + m_bunsetsu_address = (m_bunsetsu_address & 0x00ffff) | (data << 16); + break; + } +} diff --git a/src/devices/bus/msx_slot/bunsetsu.h b/src/devices/bus/msx_slot/bunsetsu.h new file mode 100644 index 00000000000..4da57dc565b --- /dev/null +++ b/src/devices/bus/msx_slot/bunsetsu.h @@ -0,0 +1,38 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +#ifndef __MSX_SLOT_BUNSETSU_H +#define __MSX_SLOT_BUNSETSU_H + +#include "bus/msx_slot/slot.h" +#include "bus/msx_slot/rom.h" + + +extern const device_type MSX_SLOT_BUNSETSU; + + +#define MCFG_MSX_SLOT_BUNSETSU_ADD(_tag, _startpage, _numpages, _region, _offset, _bunsetsu_region_tag) \ + MCFG_MSX_INTERNAL_SLOT_ADD(_tag, MSX_SLOT_BUNSETSU, _startpage, _numpages) \ + msx_slot_rom_device::set_rom_start(*device, _region, _offset); \ + msx_slot_bunsetsu_device::set_bunsetsu_region_tag(*device, _bunsetsu_region_tag); +class msx_slot_bunsetsu_device : public msx_slot_rom_device +{ +public: + msx_slot_bunsetsu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // static configuration helpers + static void set_bunsetsu_region_tag(device_t &device, const char *tag) { dynamic_cast(device).m_bunsetsu_region_tag = tag; } + + virtual void device_start(); + virtual void device_reset(); + + virtual DECLARE_READ8_MEMBER(read); + virtual DECLARE_WRITE8_MEMBER(write); + +private: + memory_region *m_bunsetsu_region; + const char *m_bunsetsu_region_tag; + UINT32 m_bunsetsu_address; +}; + + +#endif diff --git a/src/devices/bus/msx_slot/cartridge.c b/src/devices/bus/msx_slot/cartridge.c new file mode 100644 index 00000000000..a7d79be1a51 --- /dev/null +++ b/src/devices/bus/msx_slot/cartridge.c @@ -0,0 +1,382 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +#include "emu.h" +#include "bus/msx_slot/cartridge.h" +#include "hashfile.h" + + +enum +{ + NOMAPPER = 0, + ASCII8, + ASCII8_SRAM, + ASCII16, + ASCII16_SRAM, + CROSSBLAIM, + GAMEMASTER2, + KOREAN_80IN1, + KOREAN_90IN1, + KOREAN_126IN1, + FMPAC, + RTYPE, + KONAMI, + KONAMI_SCC, + SUPERLODERUNNER, + MAJUTSUSHI, + DISK_ROM, + SYNTHESIZER, + MSXDOS2 +}; + + +const device_type MSX_SLOT_CARTRIDGE = &device_creator; +const device_type MSX_SLOT_YAMAHA_EXPANSION = &device_creator; + + +msx_slot_cartridge_device::msx_slot_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, MSX_SLOT_CARTRIDGE, "MSX Cartridge slot", tag, owner, clock, "msx_slot_cartridge", __FILE__) + , device_image_interface(mconfig, *this) + , device_slot_interface(mconfig, *this) + , msx_internal_slot_interface() + , m_irq_handler(*this) + , m_cartridge(NULL) +{ +} + + +msx_slot_cartridge_device::msx_slot_cartridge_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source) + , device_image_interface(mconfig, *this) + , device_slot_interface(mconfig, *this) + , msx_internal_slot_interface() + , m_irq_handler(*this) + , m_cartridge(NULL) +{ +} + + +static const struct +{ + int pcb_id; + const char *slot_option; +} slot_list[] = +{ + { NOMAPPER, "nomapper" }, + { ASCII8, "ascii8" }, + { ASCII8_SRAM, "ascii8_sram" }, + { ASCII16, "ascii16" }, + { ASCII16_SRAM, "ascii16_sram" }, + { CROSSBLAIM, "cross_blaim" }, + { GAMEMASTER2, "gamemaster2" }, + { KOREAN_80IN1, "korean_80in1" }, + { KOREAN_90IN1, "korean_90in1" }, + { KOREAN_126IN1, "korean_126in1" }, + { FMPAC, "fmpac" }, + { RTYPE, "rtype" }, + { KONAMI, "konami" }, + { KONAMI_SCC, "konami_scc" }, + { SUPERLODERUNNER, "superloderunner" }, + { MAJUTSUSHI, "majutsushi" }, + { DISK_ROM, "disk_rom" }, + { SYNTHESIZER, "synthesizer" }, + { MSXDOS2, "msxdos2" } +}; + + +static const char *msx_cart_get_slot_option(int type) +{ + for (int i = 0; i < ARRAY_LENGTH(slot_list); i++) + { + if (slot_list[i].pcb_id == type) + return slot_list[i].slot_option; + } + + return slot_list[0].slot_option; +} + + +void msx_slot_cartridge_device::device_start() +{ + m_irq_handler.resolve_safe(); + m_cartridge = dynamic_cast(get_card_device()); +} + + +bool msx_slot_cartridge_device::call_load() +{ + if ( m_cartridge ) + { + if ( software_entry() ) + { + UINT32 length; + + // Allocate and copy rom contents + length = get_software_region_length("rom"); + m_cartridge->rom_alloc( length ); + if (length > 0) + { + UINT8 *rom_base = m_cartridge->get_rom_base(); + memcpy(rom_base, get_software_region("rom"), length); + } + + // Allocate and copy vlm5030 rom contents + length = get_software_region_length("vlm5030"); + m_cartridge->rom_vlm5030_alloc(length); + if (length > 0) + { + UINT8 *rom_base = m_cartridge->get_rom_vlm5030_base(); + memcpy(rom_base, get_software_region("vlm5030"), length); + } + + // Allocate ram + length = get_software_region_length("ram"); + m_cartridge->ram_alloc( length ); + + // Allocate sram + length = get_software_region_length("sram"); + m_cartridge->sram_alloc( length ); + } + else + { + UINT32 length = this->length(); + + // determine how much space to allocate + UINT32 length_aligned = 0x10000; + + if (length <= 0x2000) + length_aligned = 0x2000; + else if (length <= 0x4000) + length_aligned = 0x4000; + else if (length <= 0x8000) + length_aligned = 0x8000; + else if (length <= 0xc000) + length_aligned = 0xc000; + else + { + while (length_aligned < length ) + length_aligned *= 2; + } + + m_cartridge->rom_alloc(length_aligned); + m_cartridge->ram_alloc(0); + m_cartridge->sram_alloc(0); + + if (fread(m_cartridge->get_rom_base(), length) != length) + { + seterror(IMAGE_ERROR_UNSPECIFIED, "Unable to fully read file"); + return IMAGE_INIT_FAIL; + } + + // Check if there's some mapper related + std::string extrainfo; + if (hashfile_extrainfo(*this, extrainfo)) + { + } + } + + m_cartridge->set_out_irq_cb(DEVCB_WRITELINE(msx_slot_cartridge_device, irq_out)); + m_cartridge->initialize_cartridge(); + + if (m_cartridge->get_sram_size() > 0) + { + battery_load(m_cartridge->get_sram_base(), m_cartridge->get_sram_size(), 0x00); + } + } + return IMAGE_INIT_PASS; +} + + +void msx_slot_cartridge_device::call_unload() +{ + if (m_cartridge) + { + if (m_cartridge->get_sram_size() > 0) + { + battery_save(m_cartridge->get_sram_base(), m_cartridge->get_sram_size()); + } + } +} + + +bool msx_slot_cartridge_device::call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry) +{ + load_software_part_region(*this, swlist, swname, start_entry); + return true; +} + + +WRITE_LINE_MEMBER(msx_slot_cartridge_device::irq_out) +{ + m_irq_handler(state); +} + + +int msx_slot_cartridge_device::get_cart_type(UINT8 *rom, UINT32 length) +{ + if (length < 0x2000) + { + return -1; + } + + if (length < 0x10000) + { + return NOMAPPER; + } + + if ( (rom[0x10] == 'Y') && (rom[0x11] == 'Z') && (length > 0x18000) ) + { + return GAMEMASTER2; + } + + int kon4 = 0, kon5 = 0, asc8 = 0, asc16 = 0; + + for (int i=0; i < length-3; i++) + { + if (rom[i] == 0x32 && rom[i+1] == 0) + { + switch (rom[i+2]) + { + case 0x60: + case 0x70: + asc16++; + asc8++; + break; + + case 0x68: + case 0x78: + asc8++; + asc16--; + break; + } + + switch (rom[i+2]) + { + case 0x60: + case 0x80: + case 0xa0: + kon4++; + break; + + case 0x50: + case 0x70: + case 0x90: + case 0xb0: + kon5++; + break; + } + } + } + + if (MAX (kon4, kon5) > MAX (asc8, asc16) ) + { + return (kon5 > kon4) ? KONAMI_SCC : KONAMI; + } + else + { + return (asc8 > asc16) ? ASCII8 : ASCII16; + } +} + + +void msx_slot_cartridge_device::get_default_card_software(std::string &result) +{ + if (open_image_file(mconfig().options())) + { + const char *slot_string = "nomapper"; + UINT32 length = core_fsize(m_file); + dynamic_buffer rom(length); + int type = NOMAPPER; + + // Check if there's some mapper related information in the hashfiles + std::string extrainfo; + if (hashfile_extrainfo(*this, extrainfo)) + { + int extrainfo_type = -1; + if (1 == sscanf(extrainfo.c_str(), "%d", &extrainfo_type)) + { + static const struct { int extrainfo; int mapper; } extrainfo_map[] = { + //{ 0, NOMAPPER }, + { 1, MSXDOS2 }, + { 2, KONAMI_SCC }, + { 3, KONAMI }, + { 4, ASCII8 }, + { 5, ASCII16 }, + { 6, GAMEMASTER2 }, + { 7, ASCII8_SRAM }, + { 8, ASCII16_SRAM }, + { 9, RTYPE }, + { 10, MAJUTSUSHI }, + { 11, FMPAC }, + { 12, SUPERLODERUNNER }, + { 13, SYNTHESIZER }, + { 14, CROSSBLAIM }, + { 15, DISK_ROM }, + { 16, KOREAN_80IN1 }, + { 17, KOREAN_126IN1 } + }; + + for (int i = 0; i < ARRAY_LENGTH(extrainfo_map); i++) + { + if (extrainfo_map[i].extrainfo == extrainfo_type) + { + type = extrainfo_map[i].mapper; + } + } + } + } + + if (type == NOMAPPER) + { + // Not identified through hashfile, try automatic detection + core_fread(m_file, &rom[0], length); + type = get_cart_type(&rom[0], length); + } + + if (type > NOMAPPER) + { + slot_string = msx_cart_get_slot_option(type); + } + + result.assign(slot_string); + return; + } + software_get_default_slot(result, "nomapper"); +} + + +READ8_MEMBER(msx_slot_cartridge_device::read) +{ + if ( m_cartridge ) + { + return m_cartridge->read_cart(space, offset); + } + return 0xFF; +} + + +WRITE8_MEMBER(msx_slot_cartridge_device::write) +{ + if ( m_cartridge ) + { + m_cartridge->write_cart(space, offset, data); + } +} + + + + +msx_slot_yamaha_expansion_device::msx_slot_yamaha_expansion_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : msx_slot_cartridge_device(mconfig, MSX_SLOT_YAMAHA_EXPANSION, "MSX Yamaha Expansion slot", tag, owner, clock, "msx_slot_yamaha_expansion", __FILE__) +{ +} + + +void msx_slot_yamaha_expansion_device::device_start() +{ + m_irq_handler.resolve_safe(); + m_cartridge = dynamic_cast(get_card_device()); + if (m_cartridge) + { + m_cartridge->set_out_irq_cb(DEVCB_WRITELINE(msx_slot_cartridge_device, irq_out)); + } +} diff --git a/src/devices/bus/msx_slot/cartridge.h b/src/devices/bus/msx_slot/cartridge.h new file mode 100644 index 00000000000..865faad0f0f --- /dev/null +++ b/src/devices/bus/msx_slot/cartridge.h @@ -0,0 +1,87 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +#ifndef __MSX_SLOT_CARTRIDGE_H +#define __MSX_SLOT_CARTRIDGE_H + +#include "slot.h" +#include "bus/msx_cart/cartridge.h" + + +extern const device_type MSX_SLOT_CARTRIDGE; +extern const device_type MSX_SLOT_YAMAHA_EXPANSION; + + +#define MCFG_MSX_SLOT_CARTRIDGE_ADD(_tag, _devcb) \ + MCFG_DEVICE_ADD(_tag, MSX_SLOT_CARTRIDGE, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(msx_cart, NULL, false) \ + devcb = &msx_slot_cartridge_device::set_irq_handler(*device, DEVCB_##_devcb); + + +#define MCFG_MSX_SLOT_YAMAHA_EXPANSION_ADD(_tag, _devcb, _default) \ + MCFG_DEVICE_ADD(_tag, MSX_SLOT_YAMAHA_EXPANSION, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(msx_yamaha_60pin, _default, false) \ + devcb = &msx_slot_cartridge_device::set_irq_handler(*device, DEVCB_##_devcb); + + +class msx_slot_cartridge_device : public device_t + , public device_image_interface + , public device_slot_interface + , public msx_internal_slot_interface +{ +public: + // construction/destruction + msx_slot_cartridge_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + msx_slot_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // static configuration helpers + template static devcb_base &set_irq_handler(device_t &device, _Object object) { return downcast(device).m_irq_handler.set_callback(object); } + + // device-level overrides + virtual void device_start(); + virtual void device_config_complete() { update_names(MSX_SLOT_CARTRIDGE, "cartridge", "cart"); } + + // image-level overrides + virtual bool call_load(); + virtual void call_unload(); + virtual bool call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry); + virtual iodevice_t image_type() const { return IO_CARTSLOT; } + virtual bool is_readable() const { return true; } + virtual bool is_writeable() const { return false; } + virtual bool is_creatable() const { return false; } + virtual bool must_be_loaded() const { return false; } + virtual bool is_reset_on_load() const { return true; } + virtual const option_guide *create_option_guide() const { return NULL; } + virtual const char *image_interface() const { return "msx_cart"; } + virtual const char *file_extensions() const { return "mx1,bin,rom"; } + + // slot interface overrides + virtual void get_default_card_software(std::string &result); + + // msx_internal_slot-level overrides + virtual DECLARE_READ8_MEMBER(read); + virtual DECLARE_WRITE8_MEMBER(write); + + DECLARE_WRITE_LINE_MEMBER(irq_out); + +protected: + devcb_write_line m_irq_handler; + msx_cart_interface *m_cartridge; + + int get_cart_type(UINT8 *rom, UINT32 length); +}; + + +class msx_slot_yamaha_expansion_device : public msx_slot_cartridge_device +{ +public: + // construction/destruction + msx_slot_yamaha_expansion_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual void device_start(); + virtual void device_config_complete() { update_names(MSX_SLOT_YAMAHA_EXPANSION, "cartridge60pin", "cart60p"); } + + virtual const char *image_interface() const { return "msx_yamaha_60pin"; } +}; + + +#endif diff --git a/src/devices/bus/msx_slot/disk.c b/src/devices/bus/msx_slot/disk.c new file mode 100644 index 00000000000..799f05b9337 --- /dev/null +++ b/src/devices/bus/msx_slot/disk.c @@ -0,0 +1,813 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +/* +From: erbo@xs4all.nl (erik de boer) + +sony and philips have used (almost) the same design +and this is the memory layout +but it is not a msx standard ! + +WD1793 or wd2793 registers + +address + +7FF8H read status register + write command register +7FF9H r/w track register (r/o on NMS 8245 and Sony) +7FFAH r/w sector register (r/o on NMS 8245 and Sony) +7FFBH r/w data register + + +hardware registers + +address + +7FFCH r/w bit 0 side select +7FFDH r/w b7>M-on , b6>in-use , b1>ds1 , b0>ds0 (all neg. logic) +7FFEH not used +7FFFH read b7>drq , b6>intrq + +set on 7FFDH bit 2 always to 0 (some use it as disk change reset) + +*/ + +#include "emu.h" +#include "disk.h" + + +const device_type MSX_SLOT_DISK1 = &device_creator; +const device_type MSX_SLOT_DISK2 = &device_creator; +const device_type MSX_SLOT_DISK3 = &device_creator; +const device_type MSX_SLOT_DISK4 = &device_creator; +const device_type MSX_SLOT_DISK5 = &device_creator; +const device_type MSX_SLOT_DISK6 = &device_creator; + + +msx_slot_disk_device::msx_slot_disk_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : msx_slot_rom_device(mconfig, type, name, tag, owner, clock, shortname, source) + , m_floppy0(NULL) + , m_floppy1(NULL) + , m_floppy2(NULL) + , m_floppy3(NULL) + , m_floppy(NULL) + , m_fdc_tag(NULL) + , m_floppy0_tag(NULL) + , m_floppy1_tag(NULL) + , m_floppy2_tag(NULL) + , m_floppy3_tag(NULL) +{ +} + + +void msx_slot_disk_device::device_start() +{ + msx_slot_rom_device::device_start(); + + if (m_fdc_tag == NULL) + { + fatalerror("msx_slot_disk_device: no FDC tag specified\n"); + } + + m_floppy0 = m_floppy0_tag ? owner()->subdevice(m_floppy0_tag) : NULL; + m_floppy1 = m_floppy1_tag ? owner()->subdevice(m_floppy1_tag) : NULL; + m_floppy2 = m_floppy2_tag ? owner()->subdevice(m_floppy2_tag) : NULL; + m_floppy3 = m_floppy3_tag ? owner()->subdevice(m_floppy3_tag) : NULL; + + if (m_floppy0 == NULL && m_floppy1 == NULL) + { + logerror("msx_slot_disk_device: Warning: both floppy0 and floppy1 were not found\n"); + } +} + + +msx_slot_wd_disk_device::msx_slot_wd_disk_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : msx_slot_disk_device(mconfig, type, name, tag, owner, clock, shortname, source) + , m_fdc(NULL) +{ +} + + +void msx_slot_wd_disk_device::device_start() +{ + msx_slot_disk_device::device_start(); + + m_fdc = owner()->subdevice(m_fdc_tag); + + if (m_fdc == NULL) + { + fatalerror("msx_slot_wd_disk_device: Unable to find FDC with tag '%s'\n", m_fdc_tag); + } +} + + +msx_slot_tc8566_disk_device::msx_slot_tc8566_disk_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : msx_slot_disk_device(mconfig, type, name, tag, owner, clock, shortname, source) + , m_fdc(NULL) +{ +} + + +void msx_slot_tc8566_disk_device::device_start() +{ + msx_slot_disk_device::device_start(); + + m_fdc = owner()->subdevice(m_fdc_tag); + + if (m_fdc == NULL) + { + fatalerror("msx_slot_tc8566_disk_device: Unable to find FDC with tag '%s'\n", m_fdc_tag); + } +} + + + +msx_slot_disk1_device::msx_slot_disk1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : msx_slot_wd_disk_device(mconfig, MSX_SLOT_DISK1, "MSX Internal floppy type 1", tag, owner, clock, "msx_slot_disk1", __FILE__) + , m_side_control(0) + , m_control(0) +{ +} + + +void msx_slot_disk1_device::device_start() +{ + msx_slot_wd_disk_device::device_start(); + + save_item(NAME(m_side_control)); + save_item(NAME(m_control)); + + machine().save().register_postload(save_prepost_delegate(FUNC(msx_slot_disk1_device::post_load), this)); +} + + +void msx_slot_disk1_device::device_reset() +{ + m_fdc->dden_w(false); +} + + +void msx_slot_disk1_device::post_load() +{ + UINT8 data = m_control; + + // To make sure the FDD busy led status gets set correctly + m_control ^= 0x40; + + set_control(data); +} + + +void msx_slot_disk1_device::set_side_control(UINT8 data) +{ + m_side_control = data; + + if (m_floppy) + { + m_floppy->ss_w(m_side_control & 0x01); + } +} + + +void msx_slot_disk1_device::set_control(UINT8 data) +{ + UINT8 old_m_control = m_control; + + m_control = data; + + switch (m_control & 0x03) + { + case 0: + case 2: + m_floppy = m_floppy0 ? m_floppy0->get_device() : NULL; + break; + + case 1: + m_floppy = m_floppy1 ? m_floppy1->get_device() : NULL; + break; + + default: + m_floppy = NULL; + break; + } + + if (m_floppy) + { + m_floppy->mon_w((m_control & 0x80) ? 0 : 1); + m_floppy->ss_w(m_side_control & 0x01); + } + + m_fdc->set_floppy(m_floppy); + + if ((old_m_control ^ m_control) & 0x40) + { + set_led_status(machine(), 0, !(m_control & 0x40)); + } +} + + +READ8_MEMBER(msx_slot_disk1_device::read) +{ + switch (offset) + { + case 0x7ff8: + case 0xbff8: + return m_fdc->status_r(); + + case 0x7ff9: + case 0xbff9: + return m_fdc->track_r(); + + case 0x7ffa: + case 0xbffa: + return m_fdc->sector_r(); + + case 0x7ffb: + case 0xbffb: + return m_fdc->data_r(); + + case 0x7ffc: + case 0xbffc: + return 0xfe | (m_side_control & 0x01); + + case 0x7ffd: + case 0xbffd: + return ( m_control & 0x83 ) | 0x78; + + case 0x7fff: + case 0xbfff: + return 0x3f | (m_fdc->intrq_r() ? 0 : 0x40) | (m_fdc->drq_r() ? 0 : 0x80); + } + + return msx_slot_rom_device::read(space, offset); +} + + +WRITE8_MEMBER(msx_slot_disk1_device::write) +{ + switch (offset) + { + case 0x7ff8: + case 0xbff8: + m_fdc->cmd_w(data); + break; + + case 0x7ff9: + case 0xbff9: + m_fdc->track_w(data); + break; + + case 0x7ffa: + case 0xbffa: + m_fdc->sector_w(data); + break; + + case 0x7ffb: + case 0xbffb: + m_fdc->data_w(data); + break; + + case 0x7ffc: + case 0xbffc: + set_side_control(data); + break; + + case 0x7ffd: + case 0xbffd: + set_control(data); + break; + + default: + logerror("msx_slot_disk1_device::write: Unmapped write writing %02x to %04x\n", data, offset); + break; + + } +} + + +msx_slot_disk2_device::msx_slot_disk2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : msx_slot_wd_disk_device(mconfig, MSX_SLOT_DISK2, "MSX Internal floppy type 2", tag, owner, clock, "msx_slot_disk2", __FILE__) + , m_control(0) +{ +} + + +void msx_slot_disk2_device::device_start() +{ + msx_slot_wd_disk_device::device_start(); + + save_item(NAME(m_control)); + + machine().save().register_postload(save_prepost_delegate(FUNC(msx_slot_disk2_device::post_load), this)); +} + + +void msx_slot_disk2_device::device_reset() +{ + m_fdc->dden_w(false); +} + + +void msx_slot_disk2_device::post_load() +{ + UINT8 data = m_control; + + // To make sure the FDD busy led status gets set correctly + m_control ^= 0x40; + + set_control(data); +} + + +void msx_slot_disk2_device::set_control(UINT8 data) +{ + UINT8 old_m_control = m_control; + + m_control = data; + + switch (m_control & 3) + { + case 1: + m_floppy = m_floppy0 ? m_floppy0->get_device() : NULL; + break; + + case 2: + m_floppy = m_floppy1 ? m_floppy1->get_device() : NULL; + break; + + default: + m_floppy = NULL; + break; + } + + if (m_floppy) + { + m_floppy->mon_w((m_control & 0x08) ? 0 : 1); + m_floppy->ss_w((m_control & 0x04) ? 1 : 0); + } + + m_fdc->set_floppy(m_floppy); + + if ((old_m_control ^ m_control) & 0x40) + { + set_led_status(machine(), 0, !(m_control & 0x40)); + } +} + + +READ8_MEMBER(msx_slot_disk2_device::read) +{ + switch (offset) + { + case 0x7fb8: + case 0xbfb8: + return m_fdc->status_r(); + + case 0x7fb9: + case 0xbfb9: + return m_fdc->track_r(); + + case 0x7fba: + case 0xbfba: + return m_fdc->sector_r(); + + case 0x7fbb: + case 0xbfbb: + return m_fdc->data_r(); + + case 0x7fbc: + case 0xbfbc: + return 0x3f | (m_fdc->drq_r() ? 0 : 0x40) | (m_fdc->intrq_r() ? 0x80 : 0); + } + + return msx_slot_rom_device::read(space, offset); +} + + +WRITE8_MEMBER(msx_slot_disk2_device::write) +{ + switch (offset) + { + case 0x7fb8: + case 0xbfb8: + m_fdc->cmd_w(data); + break; + + case 0x7fb9: + case 0xbfb9: + m_fdc->track_w(data); + break; + + case 0x7fba: + case 0xbfba: + m_fdc->sector_w(data); + break; + + case 0x7fbb: + case 0xbfbb: + m_fdc->data_w(data); + break; + + case 0x7fbc: + case 0xbfbc: + set_control(data); + break; + + default: + logerror("msx_slot_disk2_device::write: Unmapped write writing %02x to %04x\n", data, offset); + break; + } +} + + + + + + +msx_slot_disk3_device::msx_slot_disk3_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : msx_slot_tc8566_disk_device(mconfig, MSX_SLOT_DISK3, "MSX Internal floppy type 3", tag, owner, clock, "msx_slot_disk3", __FILE__) +{ +} + + +WRITE8_MEMBER(msx_slot_disk3_device::write) +{ + switch (offset) + { + case 0x7ff8: // CR0 : 0 - 0 - MEN1 - MEN0 - 0 - -FRST - 0 - DSA + m_fdc->dor_w(space, 2, data); + break; + + case 0x7ff9: // CR1 : 0 - 0 - C4E - C4 - SBME - SBM - TCE - FDCTC + m_fdc->cr1_w(space, 3, data); + break; + + case 0x7ffb: // Data Register + m_fdc->fifo_w(space, 5, data); + break; + + default: + logerror("msx_slot_disk3_device::write: Unmapped write writing %02x to %04x\n", data, offset); + break; + } +} + + +READ8_MEMBER(msx_slot_disk3_device::read) +{ + switch (offset) + { + case 0x7ffa: // Status Register + return m_fdc->msr_r(space, 4); + case 0x7ffb: // Data Register + return m_fdc->fifo_r(space, 5); + } + + return msx_slot_rom_device::read(space, offset); +} + + + + + +msx_slot_disk4_device::msx_slot_disk4_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : msx_slot_tc8566_disk_device(mconfig, MSX_SLOT_DISK4, "MSX Internal floppy type 4", tag, owner, clock, "msx_slot_disk4", __FILE__) +{ +} + + +WRITE8_MEMBER(msx_slot_disk4_device::write) +{ + switch (offset) + { + case 0x7ff1: // FDD : x - x - MC1 - MC0 - x - x - x - x + break; + + case 0x7ff2: // CR0 : 0 - 0 - MEN1 - MEN0 - 0 - -FRST - 0 - DSA + m_fdc->dor_w(space, 2, data); + break; + + case 0x7ff3: // CR1 : 0 - 0 - C4E - C4 - SBME - SBM - TCE - FDCTC + m_fdc->cr1_w(space, 3, data); + break; + + case 0x7ff5: // Data Register + m_fdc->fifo_w(space, 5, data); + break; + + default: + logerror("msx_slot_disk4_device::write: Unmapped write writing %02x to %04x\n", data, offset); + break; + } +} + + +READ8_MEMBER(msx_slot_disk4_device::read) +{ + switch (offset) + { + case 0x7ff1: // FDD : x - x - MC1 - MC0 - x - x - x - x + logerror("msx_slot_disk4_device::write: Unmapped read from Media Change register\n"); + break; + + case 0x7ff4: // Status Register + return m_fdc->msr_r(space, 4); + case 0x7ff5: // Data Register + return m_fdc->fifo_r(space, 5); + } + + return msx_slot_rom_device::read(space, offset); +} + + + + +msx_slot_disk5_device::msx_slot_disk5_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : msx_slot_wd_disk_device(mconfig, MSX_SLOT_DISK5, "MSX Internal floppy type 5", tag, owner, clock, "msx_slot_disk5", __FILE__) + , m_control(0) +{ +} + + +void msx_slot_disk5_device::device_start() +{ + msx_slot_wd_disk_device::device_start(); + + save_item(NAME(m_control)); + + machine().save().register_postload(save_prepost_delegate(FUNC(msx_slot_disk5_device::post_load), this)); + + // Install IO read/write handlers + address_space &space = machine().device("maincpu")->space(AS_IO); + space.install_write_handler(0xd0, 0xd4, write8_delegate(FUNC(msx_slot_disk5_device::io_write), this)); + space.install_read_handler(0xd0, 0xd4, read8_delegate(FUNC(msx_slot_disk5_device::io_read), this)); +} + + +void msx_slot_disk5_device::device_reset() +{ + m_fdc->dden_w(false); +} + + +void msx_slot_disk5_device::post_load() +{ + set_control(m_control); +} + + +void msx_slot_disk5_device::set_control(UINT8 control) +{ + m_control = control; + + switch (m_control & 0x0f) + { + case 0x01: + m_floppy = m_floppy0 ? m_floppy0->get_device() : NULL; + break; + + case 0x02: + m_floppy = m_floppy1 ? m_floppy1->get_device() : NULL; + break; + + case 0x04: + m_floppy = m_floppy2 ? m_floppy2->get_device() : NULL; + break; + + case 0x08: + m_floppy = m_floppy3 ? m_floppy3->get_device() : NULL; + break; + + default: + m_floppy = NULL; + break; + } + + if (m_floppy) + { + m_floppy->mon_w((m_control & 0x20) ? 0 : 1); + m_floppy->ss_w((m_control & 0x10) ? 1 : 0); + } + + m_fdc->set_floppy(m_floppy); +} + + +READ8_MEMBER(msx_slot_disk5_device::io_read) +{ + switch (offset) + { + case 0x00: + return m_fdc->status_r(); + + case 0x01: + return m_fdc->track_r(); + + case 0x02: + return m_fdc->sector_r(); + + case 0x03: + return m_fdc->data_r(); + + case 0x04: + return 0x3f | (m_fdc->drq_r() ? 0 : 0x40) | (m_fdc->intrq_r() ? 0x80 : 0); + } + + return 0xff; +} + + +WRITE8_MEMBER(msx_slot_disk5_device::io_write) +{ + switch (offset) + { + case 0x00: + m_fdc->cmd_w(data); + break; + + case 0x01: + m_fdc->track_w(data); + break; + + case 0x02: + m_fdc->sector_w(data); + break; + + case 0x03: + m_fdc->data_w(data); + break; + + case 0x04: + set_control(data); + break; + } +} + + + +msx_slot_disk6_device::msx_slot_disk6_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : msx_slot_wd_disk_device(mconfig, MSX_SLOT_DISK6, "MSX Internal floppy type 6", tag, owner, clock, "msx_slot_disk6", __FILE__) + , m_side_motor(0) + , m_drive_select0(0) + , m_drive_select1(0) +{ +} + + +void msx_slot_disk6_device::device_start() +{ + msx_slot_wd_disk_device::device_start(); + + save_item(NAME(m_side_motor)); + save_item(NAME(m_drive_select0)); + save_item(NAME(m_drive_select1)); + + machine().save().register_postload(save_prepost_delegate(FUNC(msx_slot_disk6_device::post_load), this)); +} + + +void msx_slot_disk6_device::device_reset() +{ + m_fdc->dden_w(false); +} + + +void msx_slot_disk6_device::post_load() +{ + select_drive(); +} + + +void msx_slot_disk6_device::select_drive() +{ + if (m_drive_select1) + { + m_floppy = m_floppy1 ? m_floppy1->get_device() : NULL; + if (!m_floppy) + { + m_drive_select1 = 0; + } + } + + if (m_drive_select0) + { + m_floppy = m_floppy0 ? m_floppy0->get_device() : NULL; + if (!m_floppy) + { + m_drive_select0 = 0; + } + } + + m_fdc->set_floppy(m_floppy); + + set_side_motor(); +} + + +void msx_slot_disk6_device::set_side_motor() +{ + if (m_floppy) + { + m_floppy->mon_w((m_side_motor & 0x02) ? 0 : 1); + m_floppy->ss_w(m_side_motor & 0x01); + } +} + + +READ8_MEMBER(msx_slot_disk6_device::read) +{ + switch (offset) + { + case 0x7ff0: // status? + case 0x7ff8: + return m_fdc->status_r(); + + case 0x7ff1: // track? + case 0x7ff9: + return m_fdc->track_r(); + + case 0x7ff2: // sector? + case 0x7ffa: + return m_fdc->sector_r(); + + case 0x7ff3: // data? + case 0x7ffb: + return m_fdc->data_r(); + + case 0x7ff4: + case 0x7ffc: + // bit 0 = side control + // bit 1 = motor control + return 0xfc | m_side_motor; + break; + + // This reads back a 1 in bit 0 if drive0 is present and selected + case 0x7ff5: + case 0x7ffd: + return 0xfe | m_drive_select0; + + // This reads back a 1 in bit 0 if drive1 is present and selected + case 0x7ff6: + case 0x7ffe: + return 0xfe | m_drive_select1; + + case 0x7ff7: + case 0x7fff: + return 0x3f | (m_fdc->intrq_r() ? 0 : 0x40) | (m_fdc->drq_r() ? 0 : 0x80); + } + + return msx_slot_rom_device::read(space, offset); +} + + +WRITE8_MEMBER(msx_slot_disk6_device::write) +{ + switch (offset) + { + case 0x7ff0: // cmd? + case 0x7ff8: + m_fdc->cmd_w(data); + break; + + case 0x7ff1: // track? + case 0x7ff9: + m_fdc->track_w(data); + break; + + case 0x7ff2: // sector? + case 0x7ffa: + m_fdc->sector_w(data); + break; + + case 0x7ff3: // data? + case 0x7ffb: + m_fdc->data_w(data); + break; + + // Side and motort control + // bit 0 = side select + // bit 1 = motor on/off + case 0x7ff4: + case 0x7ffc: + m_side_motor = data; + set_side_motor(); + break; + + // bit 0 - select drive 0 + case 0x7ff5: + case 0x7ffd: + m_drive_select0 = data; + select_drive(); + break; + + // bit 1 - select drive 1 + case 0x7ff6: + case 0x7ffe: + m_drive_select1 = data; + select_drive(); + break; + + default: + logerror("msx_slot_disk6_device::write: Unmapped write writing %02x to %04x\n", data, offset); + break; + } +} diff --git a/src/devices/bus/msx_slot/disk.h b/src/devices/bus/msx_slot/disk.h new file mode 100644 index 00000000000..34de73f69e9 --- /dev/null +++ b/src/devices/bus/msx_slot/disk.h @@ -0,0 +1,231 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +#ifndef __MSX_SLOT_DISK_H +#define __MSX_SLOT_DISK_H + +#include "bus/msx_slot/slot.h" +#include "bus/msx_slot/rom.h" +#include "machine/wd_fdc.h" +#include "machine/upd765.h" +#include "imagedev/flopdrv.h" +#include "imagedev/floppy.h" + + +/* WD FDC accessed through 7ffx */ +extern const device_type MSX_SLOT_DISK1; +/* WD FDC accessed through 7fbx */ +extern const device_type MSX_SLOT_DISK2; +/* TC8566 accessed through 7ff8-7fff */ +extern const device_type MSX_SLOT_DISK3; +/* TC8566 accessed through 7ff0-7ff7 (used in Turob-R, untested) */ +extern const device_type MSX_SLOT_DISK4; +/* WD FDC accessed through i/o ports 0xd0-0xd4 */ +extern const device_type MSX_SLOT_DISK5; +/* WD FDC accessed through 7ff0-7ff? (used in Toshiba HX34) */ +extern const device_type MSX_SLOT_DISK6; + + +#define MCFG_MSX_SLOT_DISK1_ADD(_tag, _startpage, _numpages, _region, _offset, _fdc_tag, _floppy0_tag, _floppy1_tag) \ + MCFG_MSX_INTERNAL_SLOT_ADD(_tag, MSX_SLOT_DISK1, _startpage, _numpages) \ + msx_slot_rom_device::set_rom_start(*device, _region, _offset); \ + msx_slot_disk_device::set_fdc_tag(*device, _fdc_tag); \ + msx_slot_disk_device::set_floppy0_tag(*device, _floppy0_tag); \ + msx_slot_disk_device::set_floppy1_tag(*device, _floppy1_tag); + +#define MCFG_MSX_SLOT_DISK2_ADD(_tag, _startpage, _numpages, _region, _offset, _fdc_tag, _floppy0_tag, _floppy1_tag) \ + MCFG_MSX_INTERNAL_SLOT_ADD(_tag, MSX_SLOT_DISK2, _startpage, _numpages) \ + msx_slot_rom_device::set_rom_start(*device, _region, _offset); \ + msx_slot_disk_device::set_fdc_tag(*device, _fdc_tag); \ + msx_slot_disk_device::set_floppy0_tag(*device, _floppy0_tag); \ + msx_slot_disk_device::set_floppy1_tag(*device, _floppy1_tag); + +#define MCFG_MSX_SLOT_DISK3_ADD(_tag, _startpage, _numpages, _region, _offset, _fdc_tag, _floppy0_tag, _floppy1_tag) \ + MCFG_MSX_INTERNAL_SLOT_ADD(_tag, MSX_SLOT_DISK3, _startpage, _numpages) \ + msx_slot_rom_device::set_rom_start(*device, _region, _offset); \ + msx_slot_disk_device::set_fdc_tag(*device, _fdc_tag); \ + msx_slot_disk_device::set_floppy0_tag(*device, _floppy0_tag); \ + msx_slot_disk_device::set_floppy1_tag(*device, _floppy1_tag); + +#define MCFG_MSX_SLOT_DISK4_ADD(_tag, _startpage, _numpages, _region, _offset, _fdc_tag, _floppy0_tag, _floppy1_tag) \ + MCFG_MSX_INTERNAL_SLOT_ADD(_tag, MSX_SLOT_DISK4, _startpage, _numpages) \ + msx_slot_rom_device::set_rom_start(*device, _region, _offset); \ + msx_slot_disk_device::set_fdc_tag(*device, _fdc_tag); \ + msx_slot_disk_device::set_floppy0_tag(*device, _floppy0_tag); \ + msx_slot_disk_device::set_floppy1_tag(*device, _floppy1_tag); + +#define MCFG_MSX_SLOT_DISK5_ADD(_tag, _startpage, _numpages, _region, _offset, _fdc_tag, _floppy0_tag, _floppy1_tag, _floppy2_tag, _floppy3_tag) \ + MCFG_MSX_INTERNAL_SLOT_ADD(_tag, MSX_SLOT_DISK5, _startpage, _numpages) \ + msx_slot_rom_device::set_rom_start(*device, _region, _offset); \ + msx_slot_disk_device::set_fdc_tag(*device, _fdc_tag); \ + msx_slot_disk_device::set_floppy0_tag(*device, _floppy0_tag); \ + msx_slot_disk_device::set_floppy1_tag(*device, _floppy1_tag); \ + msx_slot_disk_device::set_floppy2_tag(*device, _floppy2_tag); \ + msx_slot_disk_device::set_floppy3_tag(*device, _floppy3_tag); + +#define MCFG_MSX_SLOT_DISK6_ADD(_tag, _startpage, _numpages, _region, _offset, _fdc_tag, _floppy0_tag, _floppy1_tag) \ + MCFG_MSX_INTERNAL_SLOT_ADD(_tag, MSX_SLOT_DISK6, _startpage, _numpages) \ + msx_slot_rom_device::set_rom_start(*device, _region, _offset); \ + msx_slot_disk_device::set_fdc_tag(*device, _fdc_tag); \ + msx_slot_disk_device::set_floppy0_tag(*device, _floppy0_tag); \ + msx_slot_disk_device::set_floppy1_tag(*device, _floppy1_tag); + + +class msx_slot_disk_device : public msx_slot_rom_device +{ +public: + msx_slot_disk_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + virtual void device_start(); + + // static configuration helpers + static void set_fdc_tag(device_t &device, const char *tag) { dynamic_cast(device).m_fdc_tag = tag; } + static void set_floppy0_tag(device_t &device, const char *tag) { dynamic_cast(device).m_floppy0_tag = tag; } + static void set_floppy1_tag(device_t &device, const char *tag) { dynamic_cast(device).m_floppy1_tag = tag; } + static void set_floppy2_tag(device_t &device, const char *tag) { dynamic_cast(device).m_floppy2_tag = tag; } + static void set_floppy3_tag(device_t &device, const char *tag) { dynamic_cast(device).m_floppy3_tag = tag; } + +protected: + floppy_connector *m_floppy0; + floppy_connector *m_floppy1; + floppy_connector *m_floppy2; + floppy_connector *m_floppy3; + floppy_image_device *m_floppy; + + const char *m_fdc_tag; + const char *m_floppy0_tag; + const char *m_floppy1_tag; + const char *m_floppy2_tag; + const char *m_floppy3_tag; +}; + + +class msx_slot_wd_disk_device : public msx_slot_disk_device +{ +public: + msx_slot_wd_disk_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + virtual void device_start(); + +protected: + wd_fdc_analog_t *m_fdc; +}; + + +class msx_slot_tc8566_disk_device : public msx_slot_disk_device +{ +public: + msx_slot_tc8566_disk_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + virtual void device_start(); + +protected: + tc8566af_device *m_fdc; +}; + + +class msx_slot_disk1_device : public msx_slot_wd_disk_device +{ +public: + msx_slot_disk1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual void device_start(); + virtual void device_reset(); + + virtual DECLARE_READ8_MEMBER(read); + virtual DECLARE_WRITE8_MEMBER(write); + + void post_load(); + +private: + UINT8 m_side_control; + UINT8 m_control; + + void set_control(UINT8 data); + void set_side_control(UINT8 data); +}; + + +class msx_slot_disk2_device : public msx_slot_wd_disk_device +{ +public: + msx_slot_disk2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual void device_start(); + virtual void device_reset(); + + virtual DECLARE_READ8_MEMBER(read); + virtual DECLARE_WRITE8_MEMBER(write); + + void post_load(); + +private: + UINT8 m_control; + + void set_control(UINT8 data); +}; + + +class msx_slot_disk3_device : public msx_slot_tc8566_disk_device +{ +public: + msx_slot_disk3_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual DECLARE_READ8_MEMBER(read); + virtual DECLARE_WRITE8_MEMBER(write); +}; + + +class msx_slot_disk4_device : public msx_slot_tc8566_disk_device +{ +public: + msx_slot_disk4_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual DECLARE_READ8_MEMBER(read); + virtual DECLARE_WRITE8_MEMBER(write); +}; + + +class msx_slot_disk5_device : public msx_slot_wd_disk_device +{ +public: + msx_slot_disk5_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual void device_start(); + virtual void device_reset(); + + DECLARE_READ8_MEMBER(io_read); + DECLARE_WRITE8_MEMBER(io_write); + + void post_load(); + +private: + UINT8 m_control; + + void set_control(UINT8 control); +}; + + +class msx_slot_disk6_device : public msx_slot_wd_disk_device +{ +public: + msx_slot_disk6_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual void device_start(); + virtual void device_reset(); + + virtual DECLARE_READ8_MEMBER(read); + virtual DECLARE_WRITE8_MEMBER(write); + + void post_load(); + +private: + UINT8 m_side_motor; + UINT8 m_drive_select0; + UINT8 m_drive_select1; + + void set_side_motor(); + void select_drive(); +}; + + +#endif diff --git a/src/devices/bus/msx_slot/fs4600.c b/src/devices/bus/msx_slot/fs4600.c new file mode 100644 index 00000000000..f6ad2b8c892 --- /dev/null +++ b/src/devices/bus/msx_slot/fs4600.c @@ -0,0 +1,163 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +/* + Emulation for the internal firmware mapper in the National FS-4600. +*/ + +#include "emu.h" +#include "fs4600.h" + + +const device_type MSX_SLOT_FS4600 = &device_creator; + + +msx_slot_fs4600_device::msx_slot_fs4600_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, MSX_SLOT_FS4600, "MSX Internal FS4600 Firmware", tag, owner, clock, "msx_slot_fs4600", __FILE__) + , msx_internal_slot_interface() + , m_nvram(*this, "nvram") + , m_region(NULL) + , m_region_offset(0) + , m_rom(NULL) + , m_sram_address(0) + , m_control(0) +{ + for (int i = 0; i < 4; i++) + { + m_selected_bank[i] = 0; + m_bank_base[i] = 0; + } + memset(m_sram, 0, sizeof(m_sram)); +} + + +static MACHINE_CONFIG_FRAGMENT( fs4600 ) + MCFG_NVRAM_ADD_0FILL("nvram") +MACHINE_CONFIG_END + + +machine_config_constructor msx_slot_fs4600_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( fs4600 ); +} + + +void msx_slot_fs4600_device::set_rom_start(device_t &device, const char *region, UINT32 offset) +{ + msx_slot_fs4600_device &dev = downcast(device); + + dev.m_region = region; + dev.m_region_offset = offset; +} + + +void msx_slot_fs4600_device::device_start() +{ + assert(m_region != NULL ); + + memory_region *m_rom_region = owner()->memregion(m_region); + + // Sanity checks + if (m_rom_region == NULL ) + { + fatalerror("Rom slot '%s': Unable to find memory region '%s'\n", tag(), m_region); + } + if (m_rom_region->bytes() < m_region_offset + 0x100000) + { + fatalerror("Memory region '%s' is too small for the FS4600 firmware\n", m_region); + } + + m_rom = m_rom_region->base() + m_region_offset; + m_nvram->set_base(m_sram, 0x1000); + + save_item(NAME(m_selected_bank)); + save_item(NAME(m_sram_address)); + save_item(NAME(m_control)); + + machine().save().register_postload(save_prepost_delegate(FUNC(msx_slot_fs4600_device::restore_banks), this)); + + restore_banks(); +} + + +void msx_slot_fs4600_device::restore_banks() +{ + for (int i = 0; i < 4; i++) + { + m_bank_base[i] = m_rom + ( ( m_selected_bank[i] * 0x4000 ) & 0x0fffff ); + } +} + + +READ8_MEMBER(msx_slot_fs4600_device::read) +{ + if ((m_control & 0x02) && ((offset & 0x3fff) == 0x3ffd)) + { + return m_sram[m_sram_address++ & 0xfff]; + } + if ((m_control & 0x04) && (offset& 0x7ff8) == 0x7ff0) + { + return m_selected_bank[(offset >> 1) & 0x03]; + } + return m_bank_base[offset >> 14][offset & 0x3fff]; +} + + +WRITE8_MEMBER(msx_slot_fs4600_device::write) +{ + if (offset == 0x7ff9) + { + m_control = data; + } + else + { + if (m_control & 0x02) + { + switch (offset & 0x3fff) + { + case 0x3ffa: + m_sram_address = (m_sram_address & 0x00ffff) | (data << 16); + break; + + case 0x3ffb: + m_sram_address = (m_sram_address & 0xff00ff) | (data << 8); + break; + + case 0x3ffc: + m_sram_address = (m_sram_address & 0xffff00) | data; + break; + + case 0x3ffd: + m_sram[m_sram_address++ & 0xfff] = data; + break; + + default: + logerror("msx_slot_fs4600: Unhandled write %02x to %04x\n", data, offset); + break; + } + } + else + { + switch (offset) + { + case 0x6000: + m_selected_bank[1] = data; + m_bank_base[1] = m_rom + ( ( m_selected_bank[1] * 0x4000 ) & 0x0fffff ); + break; + + case 0x6400: + m_selected_bank[0] = data; + m_bank_base[0] = m_rom + ( ( m_selected_bank[0] * 0x4000 ) & 0x0fffff ); + break; + + case 0x7000: + m_selected_bank[2] = data; + m_bank_base[2] = m_rom + ( ( m_selected_bank[2] * 0x4000 ) & 0x0fffff ); + break; + + default: + logerror("msx_slot_fs4600: Unhandled write %02x to %04x\n", data, offset);; + break; + } + } + } +} diff --git a/src/devices/bus/msx_slot/fs4600.h b/src/devices/bus/msx_slot/fs4600.h new file mode 100644 index 00000000000..c383ba49e30 --- /dev/null +++ b/src/devices/bus/msx_slot/fs4600.h @@ -0,0 +1,47 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +#ifndef __MSX_SLOT_FS4600_H +#define __MSX_SLOT_FS4600_H + +#include "slot.h" +#include "machine/nvram.h" + + +extern const device_type MSX_SLOT_FS4600; + + +#define MCFG_MSX_SLOT_FS4600_ADD(_tag, _startpage, _numpages, _region, _offset) \ + MCFG_MSX_INTERNAL_SLOT_ADD(_tag, MSX_SLOT_FS4600, _startpage, _numpages) \ + msx_slot_fs4600_device::set_rom_start(*device, _region, _offset); + +class msx_slot_fs4600_device : public device_t, + public msx_internal_slot_interface +{ +public: + msx_slot_fs4600_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // static configuration helpers + static void set_rom_start(device_t &device, const char *region, UINT32 offset); + + virtual void device_start(); + virtual machine_config_constructor device_mconfig_additions() const; + + virtual DECLARE_READ8_MEMBER(read); + virtual DECLARE_WRITE8_MEMBER(write); + + void restore_banks(); + +private: + required_device m_nvram; + const char *m_region; + UINT32 m_region_offset; + const UINT8 *m_rom; + UINT8 m_selected_bank[4]; + const UINT8 *m_bank_base[4]; + UINT32 m_sram_address; + UINT8 m_sram[0x1000]; + UINT8 m_control; +}; + + +#endif diff --git a/src/devices/bus/msx_slot/music.c b/src/devices/bus/msx_slot/music.c new file mode 100644 index 00000000000..5c7d0905427 --- /dev/null +++ b/src/devices/bus/msx_slot/music.c @@ -0,0 +1,49 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +#include "emu.h" +#include "music.h" + + +const device_type MSX_SLOT_MUSIC = &device_creator; + + +msx_slot_music_device::msx_slot_music_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : msx_slot_rom_device(mconfig, MSX_SLOT_MUSIC, "MSX Internal MSX-MUSIC", tag, owner, clock, "msx_slot_music", __FILE__) + , m_ym2413(NULL) + , m_ym2413_tag(NULL) +{ +} + + +void msx_slot_music_device::device_start() +{ + msx_slot_rom_device::device_start(); + + if (m_ym2413_tag == NULL) + { + fatalerror("msx_slot_music_device: no YM2413 tag specified\n"); + } + + m_ym2413 = owner()->subdevice(m_ym2413_tag); + + if (m_ym2413 == NULL) + { + fatalerror("msx_slot_ym2413_device: Unable to find YM2413 with tag '%s'\n", m_ym2413_tag); + } + + // Install IO read/write handlers + address_space &space = machine().device("maincpu")->space(AS_IO); + space.install_write_handler(0x7c, 0x7d, write8_delegate(FUNC(msx_slot_music_device::write_ym2413), this)); +} + + +READ8_MEMBER(msx_slot_music_device::read) +{ + return msx_slot_rom_device::read(space, offset); +} + + +WRITE8_MEMBER(msx_slot_music_device::write_ym2413) +{ + m_ym2413->write(space, offset & 1, data); +} diff --git a/src/devices/bus/msx_slot/music.h b/src/devices/bus/msx_slot/music.h new file mode 100644 index 00000000000..8cbefb4bc0c --- /dev/null +++ b/src/devices/bus/msx_slot/music.h @@ -0,0 +1,39 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +#ifndef __MSX_SLOT_MUSIC_H +#define __MSX_SLOT_MUSIC_H + + +#include "bus/msx_slot/slot.h" +#include "bus/msx_slot/rom.h" +#include "sound/2413intf.h" + + +extern const device_type MSX_SLOT_MUSIC; + + +#define MCFG_MSX_SLOT_MUSIC_ADD(_tag, _startpage, _numpages, _region, _offset, _ym2413_tag) \ + MCFG_MSX_INTERNAL_SLOT_ADD(_tag, MSX_SLOT_MUSIC, _startpage, _numpages) \ + msx_slot_rom_device::set_rom_start(*device, _region, _offset); \ + msx_slot_music_device::set_ym2413_tag(*device, _ym2413_tag); +class msx_slot_music_device : public msx_slot_rom_device +{ +public: + msx_slot_music_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // static configuration helpers + static void set_ym2413_tag(device_t &device, const char *tag) { dynamic_cast(device).m_ym2413_tag = tag; } + + virtual void device_start(); + + virtual DECLARE_READ8_MEMBER(read); + + DECLARE_WRITE8_MEMBER(write_ym2413); + +private: + ym2413_device *m_ym2413; + const char *m_ym2413_tag; +}; + + +#endif diff --git a/src/devices/bus/msx_slot/panasonic08.c b/src/devices/bus/msx_slot/panasonic08.c new file mode 100644 index 00000000000..df78f76a27b --- /dev/null +++ b/src/devices/bus/msx_slot/panasonic08.c @@ -0,0 +1,182 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +/* + + Emulation of the firmware mapper as found in Panasonic FS-A1WX andFS-A1WSX machines. + +Todo: +- Anything besides the basic mapping +- SRAM? +*/ + +#include "emu.h" +#include "panasonic08.h" + + +const device_type MSX_SLOT_PANASONIC08 = &device_creator; + + +msx_slot_panasonic08_device::msx_slot_panasonic08_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, MSX_SLOT_PANASONIC08, "MSX Internal Panasonic08", tag, owner, clock, "msx_slot_panasonic08", __FILE__) + , msx_internal_slot_interface() + , m_nvram(*this, "nvram") + , m_region(NULL) + , m_region_offset(0) + , m_rom(NULL) + , m_control(0) +{ + for (int i = 0; i < 8; i++) + { + m_selected_bank[i] = 0; + m_bank_base[i] = 0; + } +} + + +static MACHINE_CONFIG_FRAGMENT( panasonic08 ) + MCFG_NVRAM_ADD_0FILL("nvram") +MACHINE_CONFIG_END + + +machine_config_constructor msx_slot_panasonic08_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( panasonic08 ); +} + + +void msx_slot_panasonic08_device::set_rom_start(device_t &device, const char *region, UINT32 offset) +{ + msx_slot_panasonic08_device &dev = downcast(device); + + dev.m_region = region; + dev.m_region_offset = offset; +} + + +void msx_slot_panasonic08_device::device_start() +{ + assert(m_region != NULL ); + + memory_region *m_rom_region = owner()->memregion(m_region); + + // Sanity checks + if (m_rom_region == NULL ) + { + fatalerror("Rom slot '%s': Unable to find memory region '%s'\n", tag(), m_region); + } + if (m_rom_region->bytes() < m_region_offset + 0x200000) + { + fatalerror("Memory region '%s' is too small for the FS4600 firmware\n", m_region); + } + + m_sram.resize(0x4000); + + m_nvram->set_base(&m_sram[0], 0x4000); + + m_rom = m_rom_region->base() + m_region_offset; + + save_item(NAME(m_selected_bank)); + save_item(NAME(m_control)); + + machine().save().register_postload(save_prepost_delegate(FUNC(msx_slot_panasonic08_device::restore_banks), this)); + + restore_banks(); +} + + +void msx_slot_panasonic08_device::map_bank(int bank) +{ + if (m_selected_bank[bank] >= 0x80 && m_selected_bank[bank] < 0x84) // Are these banks were sram is present? Mirroring? + { + logerror("panasonic08: mapping bank %d to sram\n", bank); + m_bank_base[bank] = &m_sram[((m_selected_bank[bank] & 0x7f) * 0x2000) & 0x3fff]; + } + else + { + m_bank_base[bank] = m_rom + ( ( m_selected_bank[bank] * 0x2000 ) & 0x1fffff ); + } +} + + +void msx_slot_panasonic08_device::restore_banks() +{ + for (int i = 0; i < 8; i++) + { + map_bank(i); + } +} + + +READ8_MEMBER(msx_slot_panasonic08_device::read) +{ + if (m_control & 0x04) + { + // 7ff0 - 6000 + // 7ff1 - 6400 + // 7ff2 - 6800 + // 7ff3 - 6c00 + // 7ff4 - 7000 + // 7ff5 - 7800 + if (offset >= 0x7ff0 && offset < 0x7ff6) // maybe 7ff8 would make more sense here?? + { + return m_selected_bank[offset - 0x7ff0]; + } + } + return m_bank_base[offset >> 13][offset & 0x1fff]; +} + + +WRITE8_MEMBER(msx_slot_panasonic08_device::write) +{ + if ((offset & 0xc000) == 0x8000 || (offset & 0xc000) == 0x0000) + { + UINT8 bank = m_selected_bank[offset >> 13]; + if (bank >= 0x80 && bank < 0x84) // Are these banks were sram is present? Mirroring? + { + logerror("msx_slot_panasonic08: writing %02x to sram %04x, bank = %02x\n", data, offset & 0x1fff, bank); + m_sram[((bank & 0x01) * 0x2000) + (offset & 0x1fff)] = data; + } + return; + } + + switch (offset) + { + case 0x6000: /* Switched 0x0000-0x1FFF */ + m_selected_bank[0] = data; + map_bank(0); + break; + + case 0x6400: /* Switches 0x2000-0x3FFF */ + m_selected_bank[1] = data; + map_bank(1); + break; + + case 0x6800: /* Switches 0x4000-0x5FFF */ + m_selected_bank[2] = data; + map_bank(2); + break; + + case 0x6c00: /* Switches 0x6000-0x7FFF */ + m_selected_bank[3] = data; + map_bank(3); + break; + + case 0x7000: /* Switches 0x8000-0x9FFF */ + m_selected_bank[4] = data; + map_bank(4); + break; + + case 0x7800: /* Switches 0xA000-0xBFFF */ + m_selected_bank[5] = data; + map_bank(5); + break; + + case 0x7ff9: + m_control = data; + break; + + default: + logerror("msx_slot_panasonic08: Unhandled write %02x to %04x\n", data, offset); + break; + } +} diff --git a/src/devices/bus/msx_slot/panasonic08.h b/src/devices/bus/msx_slot/panasonic08.h new file mode 100644 index 00000000000..c9be040678f --- /dev/null +++ b/src/devices/bus/msx_slot/panasonic08.h @@ -0,0 +1,48 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +#ifndef __MSX_SLOT_PANASONIC08_H +#define __MSX_SLOT_PANASONIC08_H + +#include "slot.h" +#include "machine/nvram.h" + + +extern const device_type MSX_SLOT_PANASONIC08; + + +#define MCFG_MSX_SLOT_PANASONIC08_ADD(_tag, _startpage, _numpages, _region, _offset) \ + MCFG_MSX_INTERNAL_SLOT_ADD(_tag, MSX_SLOT_PANASONIC08, _startpage, _numpages) \ + msx_slot_panasonic08_device::set_rom_start(*device, _region, _offset); + +class msx_slot_panasonic08_device : public device_t, + public msx_internal_slot_interface +{ +public: + msx_slot_panasonic08_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // static configuration helpers + static void set_rom_start(device_t &device, const char *region, UINT32 offset); + + virtual void device_start(); + virtual machine_config_constructor device_mconfig_additions() const; + + virtual DECLARE_READ8_MEMBER(read); + virtual DECLARE_WRITE8_MEMBER(write); + + void restore_banks(); + +private: + required_device m_nvram; + const char *m_region; + UINT32 m_region_offset; + const UINT8 *m_rom; + UINT8 m_selected_bank[8]; + const UINT8 *m_bank_base[8]; + UINT8 m_control; + dynamic_buffer m_sram; + + void map_bank(int bank); +}; + + +#endif diff --git a/src/devices/bus/msx_slot/ram.c b/src/devices/bus/msx_slot/ram.c new file mode 100644 index 00000000000..cb07422358a --- /dev/null +++ b/src/devices/bus/msx_slot/ram.c @@ -0,0 +1,36 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol + +#include "emu.h" +#include "ram.h" + +const device_type MSX_SLOT_RAM = &device_creator; + +msx_slot_ram_device::msx_slot_ram_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, MSX_SLOT_RAM, "MSX Internal RAM", tag, owner, clock, "msx_slot_ram", __FILE__) + , msx_internal_slot_interface() +{ +} + +void msx_slot_ram_device::device_start() +{ + m_ram.resize(m_size); + save_item(NAME(m_ram)); +} + +READ8_MEMBER(msx_slot_ram_device::read) +{ + if ( offset >= m_start_address && offset < m_end_address ) + { + return m_ram[ offset - m_start_address ]; + } + return 0xFF; +} + +WRITE8_MEMBER(msx_slot_ram_device::write) +{ + if ( offset >= m_start_address && offset < m_end_address ) + { + m_ram[offset - m_start_address] = data; + } +} diff --git a/src/devices/bus/msx_slot/ram.h b/src/devices/bus/msx_slot/ram.h new file mode 100644 index 00000000000..1b85ee8ac5d --- /dev/null +++ b/src/devices/bus/msx_slot/ram.h @@ -0,0 +1,36 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +#ifndef __MSX_SLOT_RAM_H +#define __MSX_SLOT_RAM_H + +#include "slot.h" + +#define MCFG_MSX_SLOT_RAM_ADD(_tag, _startpage, _numpages) \ + MCFG_MSX_INTERNAL_SLOT_ADD(_tag, MSX_SLOT_RAM, _startpage, _numpages) + +#define MCFG_MSX_SLOT_RAM_8KB \ + msx_slot_ram_device::force_start_address(*device, 0xe000); + + +class msx_slot_ram_device : public device_t, + public msx_internal_slot_interface +{ +public: + msx_slot_ram_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + static void force_start_address(device_t &device, UINT16 start) { downcast(device).m_start_address = start; } + + virtual void device_start(); + + virtual DECLARE_READ8_MEMBER(read); + virtual DECLARE_WRITE8_MEMBER(write); + +private: + std::vector m_ram; +}; + + +extern const device_type MSX_SLOT_RAM; + + +#endif diff --git a/src/devices/bus/msx_slot/ram_mm.c b/src/devices/bus/msx_slot/ram_mm.c new file mode 100644 index 00000000000..4d70fff80bc --- /dev/null +++ b/src/devices/bus/msx_slot/ram_mm.c @@ -0,0 +1,80 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +#include "emu.h" +#include "ram_mm.h" + +const device_type MSX_SLOT_RAM_MM = &device_creator; + +msx_slot_ram_mm_device::msx_slot_ram_mm_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, MSX_SLOT_RAM_MM, "MSX Internal Memory Mapped RAM", tag, owner, clock, "msx_slot_ram_mm", __FILE__) + , msx_internal_slot_interface() + , m_total_size(0) + , m_bank_mask(0) + , m_ramio_set_bits(0) +{ +} + +void msx_slot_ram_mm_device::device_start() +{ + // Valid mapper sizes are 64KB, 128KB, 256KB, 512KB, 1MB, 2MB, and 4MB */ + switch (m_total_size) + { + case 64*1024: m_bank_mask = 0x03; break; + case 128*1024: m_bank_mask = 0x07; break; + case 256*1024: m_bank_mask = 0x0F; break; + case 512*1024: m_bank_mask = 0x1F; break; + case 1024*1024: m_bank_mask = 0x3F; break; + case 2048*1024: m_bank_mask = 0x7F; break; + case 4096*1024: m_bank_mask = 0xFF; break; + default: fatalerror("Invalid memory mapper size specified\n"); + } + + m_ram.resize(m_total_size); + + for ( int i = 0; i < 4; i++ ) + { + m_bank_selected[i] = 3 -i; + m_bank_base[i] = &m_ram[0x4000 * m_bank_selected[i]]; + } + + save_item(NAME(m_ram)); + save_item(NAME(m_bank_selected)); + + machine().save().register_postload(save_prepost_delegate(FUNC(msx_slot_ram_mm_device::restore_banks), this)); + + // Install IO read/write handlers + address_space &space = machine().device("maincpu")->space(AS_IO); + space.install_read_handler(0xFC, 0xFF, read8_delegate(FUNC(msx_slot_ram_mm_device::read_mapper_bank), this)); + space.install_write_handler(0xFC, 0xFF, write8_delegate(FUNC(msx_slot_ram_mm_device::write_mapper_bank), this)); +} + +void msx_slot_ram_mm_device::restore_banks() +{ + for ( int i = 0; i < 3; i++ ) + { + m_bank_base[i] = &m_ram[0x4000 * ( m_bank_selected[i] & m_bank_mask )]; + } +} + +READ8_MEMBER(msx_slot_ram_mm_device::read) +{ + return m_bank_base[offset >> 14][offset & 0x3fff]; +} + +WRITE8_MEMBER(msx_slot_ram_mm_device::write) +{ + m_bank_base[offset >> 14][offset & 0x3fff] = data; +} + +READ8_MEMBER(msx_slot_ram_mm_device::read_mapper_bank) +{ + return m_bank_selected[offset & 3] | m_ramio_set_bits; +} + +WRITE8_MEMBER(msx_slot_ram_mm_device::write_mapper_bank) +{ + offset &= 3; + + m_bank_selected[offset] = data; + m_bank_base[offset] = &m_ram[0x4000 * ( m_bank_selected[offset] & m_bank_mask )]; +} diff --git a/src/devices/bus/msx_slot/ram_mm.h b/src/devices/bus/msx_slot/ram_mm.h new file mode 100644 index 00000000000..59eb7f18e89 --- /dev/null +++ b/src/devices/bus/msx_slot/ram_mm.h @@ -0,0 +1,45 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +#ifndef __MSX_SLOT_RAM_MM_H +#define __MSX_SLOT_RAM_MM_H + +#include "slot.h" + +#define MCFG_MSX_SLOT_RAM_MM_ADD(_tag, _total_size) \ + MCFG_MSX_INTERNAL_SLOT_ADD(_tag, MSX_SLOT_RAM_MM, 0, 4) \ + msx_slot_ram_mm_device::set_total_size(*device, _total_size); + +#define MCFG_MSX_SLOT_RAMM_SET_RAMIO_BITS(_ramio_set_bits) \ + msx_slot_ram_mm_device::set_ramio_set_bits(*device, _ramio_set_bits); + +class msx_slot_ram_mm_device : public device_t + , public msx_internal_slot_interface +{ +public: + msx_slot_ram_mm_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + static void set_total_size(device_t &device, UINT32 total_size) { dynamic_cast(device).m_total_size = total_size; } + static void set_ramio_set_bits(device_t &device, UINT8 ramio_set_bits) { dynamic_cast(device).m_ramio_set_bits = ramio_set_bits; } + + virtual void device_start(); + + virtual DECLARE_READ8_MEMBER(read); + virtual DECLARE_WRITE8_MEMBER(write); + + DECLARE_READ8_MEMBER(read_mapper_bank); + DECLARE_WRITE8_MEMBER(write_mapper_bank); + + void restore_banks(); + +private: + std::vector m_ram; + UINT32 m_total_size; + UINT8 m_bank_mask; + UINT8 m_bank_selected[4]; + UINT8 *m_bank_base[4]; + UINT8 m_ramio_set_bits; +}; + +extern const device_type MSX_SLOT_RAM_MM; + +#endif diff --git a/src/devices/bus/msx_slot/rom.c b/src/devices/bus/msx_slot/rom.c new file mode 100644 index 00000000000..609201f60d1 --- /dev/null +++ b/src/devices/bus/msx_slot/rom.c @@ -0,0 +1,66 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +#include "emu.h" +#include "rom.h" + + +const device_type MSX_SLOT_ROM = &device_creator; + + +msx_slot_rom_device::msx_slot_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, MSX_SLOT_ROM, "MSX Internal ROM", tag, owner, clock, "msx_slot_rom", __FILE__) + , msx_internal_slot_interface() + , m_region(NULL) + , m_region_offset(0) + , m_rom(NULL) +{ +} + + +msx_slot_rom_device::msx_slot_rom_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source) + , msx_internal_slot_interface() + , m_region(NULL) + , m_region_offset(0) + , m_rom(NULL) +{ +} + + +void msx_slot_rom_device::set_rom_start(device_t &device, const char *region, UINT32 offset) +{ + msx_slot_rom_device &dev = downcast(device); + + dev.m_region = region; + dev.m_region_offset = offset; +} + + +void msx_slot_rom_device::device_start() +{ + assert(m_region != NULL ); + + memory_region *m_rom_region = owner()->memregion(m_region); + + // Sanity checks + if (m_rom_region == NULL ) + { + fatalerror("Rom slot '%s': Unable to find memory region '%s'\n", tag(), m_region); + } + if (m_rom_region->bytes() < m_region_offset + m_size) + { + fatalerror("Memory region '%s' is too small for rom slot '%s'\n", m_region, tag()); + } + + m_rom = m_rom_region->base() + m_region_offset; +} + + +READ8_MEMBER(msx_slot_rom_device::read) +{ + if ( offset >= m_start_address && offset < m_end_address ) + { + return m_rom[ offset - m_start_address ]; + } + return 0xFF; +} diff --git a/src/devices/bus/msx_slot/rom.h b/src/devices/bus/msx_slot/rom.h new file mode 100644 index 00000000000..6317d28f3c0 --- /dev/null +++ b/src/devices/bus/msx_slot/rom.h @@ -0,0 +1,34 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +#ifndef __MSX_SLOT_ROM_H +#define __MSX_SLOT_ROM_H + +#include "slot.h" + +#define MCFG_MSX_SLOT_ROM_ADD(_tag, _startpage, _numpages, _region, _offset) \ + MCFG_MSX_INTERNAL_SLOT_ADD(_tag, MSX_SLOT_ROM, _startpage, _numpages) \ + msx_slot_rom_device::set_rom_start(*device, _region, _offset); + +class msx_slot_rom_device : public device_t, + public msx_internal_slot_interface +{ +public: + msx_slot_rom_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + msx_slot_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // static configuration helpers + static void set_rom_start(device_t &device, const char *region, UINT32 offset); + + virtual void device_start(); + + virtual DECLARE_READ8_MEMBER(read); + +private: + const char *m_region; + UINT32 m_region_offset; + const UINT8 *m_rom; +}; + +extern const device_type MSX_SLOT_ROM; + +#endif diff --git a/src/devices/bus/msx_slot/slot.c b/src/devices/bus/msx_slot/slot.c new file mode 100644 index 00000000000..db8e8f89ae7 --- /dev/null +++ b/src/devices/bus/msx_slot/slot.c @@ -0,0 +1,36 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +/*********************************************************************************************************** + + MSX (logical) internal slot interfacing + +The MSX standard uses logically defined slots, subslots, and pages to access rom and optional components +in a system. There are no physical slots inside the system. A piece of rom/component can occur in multiple +pages; and multiple pieces of rom/ram/components can occur in a single slot. + +***********************************************************************************************************/ + +#include "emu.h" +#include "slot.h" + +msx_internal_slot_interface::msx_internal_slot_interface() + : m_start_address(0) + , m_size(0) + , m_end_address(0) +{ +} + +void msx_internal_slot_interface::set_start_address(device_t &device, UINT32 start_address) +{ + msx_internal_slot_interface &dev = dynamic_cast(device); + dev.m_start_address = start_address; + dev.m_end_address = dev.m_start_address + dev.m_size; +} + +void msx_internal_slot_interface::set_size(device_t &device, UINT32 size) +{ + msx_internal_slot_interface &dev = dynamic_cast(device); + + dev.m_size = size; + dev.m_end_address = dev.m_start_address + dev.m_size; +} diff --git a/src/devices/bus/msx_slot/slot.h b/src/devices/bus/msx_slot/slot.h new file mode 100644 index 00000000000..fe5a540a19e --- /dev/null +++ b/src/devices/bus/msx_slot/slot.h @@ -0,0 +1,39 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +/*********************************************************************************************************** + + MSX (logical) internal slot/page interfacing + +The MSX standard uses logically defined slots, subslots, and pages to access rom and optional components +in a system. There are no physical slots inside the system. A piece of rom/component can occur in multiple +pages; and multiple pieces of rom/ram/components can occur in a single slot. + +***********************************************************************************************************/ + +#ifndef __MSX_SLOT_SLOT_H +#define __MSX_SLOT_SLOT_H + +#define MCFG_MSX_INTERNAL_SLOT_ADD(_tag, _type, _startpage, _numpages) \ + MCFG_DEVICE_ADD(_tag, _type, 0) \ + msx_internal_slot_interface::set_start_address(*device, _startpage * 0x4000); \ + msx_internal_slot_interface::set_size(*device, _numpages * 0x4000); + +class msx_internal_slot_interface +{ +public: + msx_internal_slot_interface(); + + // static configuration helpers + static void set_start_address(device_t &device, UINT32 start_address); + static void set_size(device_t &device, UINT32 size); + + virtual DECLARE_READ8_MEMBER(read) { return 0xFF; } + virtual DECLARE_WRITE8_MEMBER(write) { } + +protected: + UINT32 m_start_address; + UINT32 m_size; + UINT32 m_end_address; +}; + +#endif diff --git a/src/devices/bus/msx_slot/sony08.c b/src/devices/bus/msx_slot/sony08.c new file mode 100644 index 00000000000..66a5f733e2d --- /dev/null +++ b/src/devices/bus/msx_slot/sony08.c @@ -0,0 +1,190 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +/* + + Emulation of the firmware mapper as found in Sony HB-F1XDJ and HB-F1XV machines. + +*/ + +#include "emu.h" +#include "sony08.h" + + +const device_type MSX_SLOT_SONY08 = &device_creator; + + +msx_slot_sony08_device::msx_slot_sony08_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, MSX_SLOT_SONY08, "MSX Internal SONY08", tag, owner, clock, "msx_slot_sony08", __FILE__) + , msx_internal_slot_interface() + , m_nvram(*this, "nvram") + , m_region(NULL) + , m_region_offset(0) + , m_rom(NULL) +{ + for (int i = 0; i < 8; i++) + { + m_selected_bank[i] = 0; + m_bank_base[i] = NULL; + } + memset(m_sram, 0, sizeof(m_sram)); +} + + +static MACHINE_CONFIG_FRAGMENT( sony08 ) + MCFG_NVRAM_ADD_0FILL("nvram") +MACHINE_CONFIG_END + + +machine_config_constructor msx_slot_sony08_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( sony08 ); +} + + +void msx_slot_sony08_device::set_rom_start(device_t &device, const char *region, UINT32 offset) +{ + msx_slot_sony08_device &dev = downcast(device); + + dev.m_region = region; + dev.m_region_offset = offset; +} + + +void msx_slot_sony08_device::device_start() +{ + assert(m_region != NULL ); + + memory_region *m_rom_region = owner()->memregion(m_region); + + // Sanity checks + if (m_rom_region == NULL ) + { + fatalerror("Rom slot '%s': Unable to find memory region '%s'\n", tag(), m_region); + } + if (m_rom_region->bytes() < m_region_offset + 0x100000) + { + fatalerror("Memory region '%s' is too small for the SONY08 firmware\n", m_region); + } + + m_rom = m_rom_region->base() + m_region_offset; + + m_nvram->set_base(m_sram, 0x4000); + + save_item(NAME(m_selected_bank)); + + machine().save().register_postload(save_prepost_delegate(FUNC(msx_slot_sony08_device::restore_banks), this)); + + restore_banks(); +} + + +void msx_slot_sony08_device::map_bank(int bank) +{ + if (bank < 2) + { + return; + } + + // Special banks + if (bank == 6 || bank == 7) + { + m_bank_base[bank] = m_rom + 0x80000 + (m_selected_bank[bank] * 0x800); + return; + } + + m_bank_base[bank] = m_rom + ((m_selected_bank[bank] * 0x2000) & 0xFFFFF); + if (bank == 2) + { + if (m_selected_bank[bank] & 0x80) + { + m_bank_base[0] = m_sram; + m_bank_base[1] = m_sram + 0x2000; + } + else + { + m_bank_base[0] = NULL; + m_bank_base[1] = NULL; + } + } +} + + +void msx_slot_sony08_device::restore_banks() +{ + for (int i = 0; i < 8; i++) + { + map_bank(i); + } +} + + +READ8_MEMBER(msx_slot_sony08_device::read) +{ + if (offset >= 0xc000) + { + return 0xFF; + } + + if ((offset & 0xf000) == 0x7000 && (m_selected_bank[3] & 0x80)) + { + return m_bank_base[6 + ((offset >> 11) & 0x01)][offset & 0x7ff]; + } + + const UINT8 *mem = m_bank_base[offset >> 13]; + + if (mem) + { + return mem[offset & 0x1fff]; + } + return 0xFF; +} + + +WRITE8_MEMBER(msx_slot_sony08_device::write) +{ + if (offset < 0x4000) + { + if (m_bank_base[0] != NULL) + { + m_sram[offset & 0x3fff] = data; + return; + } + } + + switch (offset) + { + case 0x4FFF: + m_selected_bank[2] = data; + map_bank(2); + break; + + case 0x6FFF: // 6000-7FFF + m_selected_bank[3] = data; + map_bank(3); + break; + + case 0x77FF: + m_selected_bank[6] = data; + map_bank(6); + break; + + case 0x7FFF: + m_selected_bank[7] = data; + map_bank(7); + break; + + case 0x8FFF: + m_selected_bank[4] = data; + map_bank(4); + break; + + case 0xAFFF: + m_selected_bank[5] = data; + map_bank(5); + break; + + default: + logerror("Unhandled write %02x to %04x\n", data, offset); + break; + } +} diff --git a/src/devices/bus/msx_slot/sony08.h b/src/devices/bus/msx_slot/sony08.h new file mode 100644 index 00000000000..28798f9bc06 --- /dev/null +++ b/src/devices/bus/msx_slot/sony08.h @@ -0,0 +1,47 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +#ifndef __MSX_SLOT_SONY08_H +#define __MSX_SLOT_SONY08_H + +#include "slot.h" +#include "machine/nvram.h" + + +extern const device_type MSX_SLOT_SONY08; + + +#define MCFG_MSX_SLOT_SONY08_ADD(_tag, _startpage, _numpages, _region, _offset) \ + MCFG_MSX_INTERNAL_SLOT_ADD(_tag, MSX_SLOT_SONY08, _startpage, _numpages) \ + msx_slot_sony08_device::set_rom_start(*device, _region, _offset); + +class msx_slot_sony08_device : public device_t, + public msx_internal_slot_interface +{ +public: + msx_slot_sony08_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // static configuration helpers + static void set_rom_start(device_t &device, const char *region, UINT32 offset); + + virtual void device_start(); + virtual machine_config_constructor device_mconfig_additions() const; + + virtual DECLARE_READ8_MEMBER(read); + virtual DECLARE_WRITE8_MEMBER(write); + + void restore_banks(); + +private: + required_device m_nvram; + const char *m_region; + UINT32 m_region_offset; + const UINT8 *m_rom; + UINT8 m_selected_bank[8]; + const UINT8 *m_bank_base[8]; + UINT8 m_sram[0x4000]; + + void map_bank(int bank); +}; + + +#endif diff --git a/src/devices/bus/nasbus/avc.c b/src/devices/bus/nasbus/avc.c new file mode 100644 index 00000000000..8960a19573f --- /dev/null +++ b/src/devices/bus/nasbus/avc.c @@ -0,0 +1,164 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best +/*************************************************************************** + + Nascom Advanced Video Card + +***************************************************************************/ + +#include "avc.h" + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type NASCOM_AVC = &device_creator; + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( nascom_avc ) + MCFG_SCREEN_ADD("screen", RASTER) + MCFG_SCREEN_RAW_PARAMS(16250000, 1024, 0, 768, 320, 0, 256) + MCFG_SCREEN_UPDATE_DEVICE("mc6845", mc6845_device, screen_update) + + MCFG_PALETTE_ADD_3BIT_RGB("palette") + + MCFG_MC6845_ADD("mc6845", MC6845, "screen", XTAL_16MHz / 8) + MCFG_MC6845_SHOW_BORDER_AREA(false) + MCFG_MC6845_CHAR_WIDTH(6) + MCFG_MC6845_UPDATE_ROW_CB(nascom_avc_device, crtc_update_row) +MACHINE_CONFIG_END + +machine_config_constructor nascom_avc_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( nascom_avc ); +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// nascom_avc_device - constructor +//------------------------------------------------- + +nascom_avc_device::nascom_avc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, NASCOM_AVC, "Nascom Advanced Video Card", tag, owner, clock, "nascom_avc", __FILE__), + device_nasbus_card_interface(mconfig, *this), + m_crtc(*this, "mc6845"), + m_palette(*this, "palette"), + m_control(0x80) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void nascom_avc_device::device_start() +{ + // allocate memory + m_r_ram.resize(0x4000); + m_g_ram.resize(0x4000); + m_b_ram.resize(0x4000); + + save_item(NAME(m_r_ram)); + save_item(NAME(m_g_ram)); + save_item(NAME(m_b_ram)); + save_item(NAME(m_control)); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void nascom_avc_device::device_reset() +{ + m_nasbus->m_io->install_write_handler(0xb0, 0xb0, write8_delegate(FUNC(mc6845_device::address_w), m_crtc.target())); + m_nasbus->m_io->install_readwrite_handler(0xb1, 0xb1, read8_delegate(FUNC(mc6845_device::register_r), m_crtc.target()), write8_delegate(FUNC(mc6845_device::register_w), m_crtc.target())); + m_nasbus->m_io->install_write_handler(0xb2, 0xb2, write8_delegate(FUNC(nascom_avc_device::control_w), this)); +} + + +//************************************************************************** +// IMPLEMENTATION +//************************************************************************** + +MC6845_UPDATE_ROW( nascom_avc_device::crtc_update_row ) +{ + offs_t base_addr = (ma << 1 | ra << 6) + 2; // y * 64 + 2 + + for (int x = 0; x < x_count * 6; x++) + { + // addr of source byte + offs_t addr = base_addr + (x / 16); + + // msb first + int bl = 7 - ((x / 2) & 7); + int bh = 7 - ((x / 1) & 7); + + int r, g, b; + + // double density) + if (BIT(m_control, 3)) + { + // red disabled, blue low density, red/green combined to green + r = 0; + b = BIT(m_b_ram[addr], bl); + g = (x & 8) ? BIT(m_r_ram[addr], bh) : BIT(m_g_ram[addr], bh); + } + else + { + // rgb color + r = BIT(m_r_ram[addr], bl); + g = BIT(m_g_ram[addr], bl); + b = BIT(m_b_ram[addr], bl); + } + + // plot the pixel + bitmap.pix32(y, x) = m_palette->pen_color((b << 2) | (g << 1) | (r << 0)); + } +} + +WRITE8_MEMBER( nascom_avc_device::control_w ) +{ + logerror("nascom_avc_device::control_w: 0x%02x\n", data); + + // page video ram in? + if (((m_control & 0x07) == 0) && (data & 0x07)) + { + m_nasbus->ram_disable_w(0); + m_nasbus->m_program->install_readwrite_handler(0x8000, 0xbfff, read8_delegate(FUNC(nascom_avc_device::vram_r), this), write8_delegate(FUNC(nascom_avc_device::vram_w), this)); + } + else if ((data & 0x07) == 0) + { + m_nasbus->m_program->unmap_readwrite(0x8000, 0xbfff); + m_nasbus->ram_disable_w(1); + } + + m_control = data; +} + +READ8_MEMBER( nascom_avc_device::vram_r ) +{ + // manual says only one plane can be read, i assume this is the order + if (BIT(m_control, 0)) return m_r_ram[offset]; + if (BIT(m_control, 1)) return m_g_ram[offset]; + if (BIT(m_control, 2)) return m_b_ram[offset]; + + // should never happen + return 0xff; +} + +WRITE8_MEMBER( nascom_avc_device::vram_w ) +{ + // all planes can be written at the same time + if (BIT(m_control, 0)) m_r_ram[offset] = data; + if (BIT(m_control, 1)) m_g_ram[offset] = data; + if (BIT(m_control, 2)) m_b_ram[offset] = data; +} diff --git a/src/devices/bus/nasbus/avc.h b/src/devices/bus/nasbus/avc.h new file mode 100644 index 00000000000..754781fc70e --- /dev/null +++ b/src/devices/bus/nasbus/avc.h @@ -0,0 +1,56 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best +/*************************************************************************** + + Nascom Advanced Video Card + +***************************************************************************/ + +#pragma once + +#ifndef __NASBUS_AVC_H__ +#define __NASBUS_AVC_H__ + +#include "emu.h" +#include "nasbus.h" +#include "video/mc6845.h" + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> nascom_avc_device + +class nascom_avc_device : public device_t, public device_nasbus_card_interface +{ +public: + // construction/destruction + nascom_avc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + MC6845_UPDATE_ROW(crtc_update_row); + DECLARE_WRITE8_MEMBER(control_w); + + READ8_MEMBER(vram_r); + WRITE8_MEMBER(vram_w); + +protected: + virtual machine_config_constructor device_mconfig_additions() const; + virtual void device_start(); + virtual void device_reset(); + +private: + required_device m_crtc; + required_device m_palette; + + std::vector m_r_ram; + std::vector m_g_ram; + std::vector m_b_ram; + + UINT8 m_control; +}; + +// device type definition +extern const device_type NASCOM_AVC; + +#endif // __NASBUS_AVC_H__ diff --git a/src/devices/bus/nasbus/cards.c b/src/devices/bus/nasbus/cards.c new file mode 100644 index 00000000000..913c17d8759 --- /dev/null +++ b/src/devices/bus/nasbus/cards.c @@ -0,0 +1,14 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best +/*************************************************************************** + + Nascom NASBUS Slot Devices + +***************************************************************************/ + +#include "cards.h" + +SLOT_INTERFACE_START( nasbus_slot_cards ) + SLOT_INTERFACE("avc", NASCOM_AVC) + SLOT_INTERFACE("floppy", NASCOM_FDC) +SLOT_INTERFACE_END diff --git a/src/devices/bus/nasbus/cards.h b/src/devices/bus/nasbus/cards.h new file mode 100644 index 00000000000..f0e5fac912b --- /dev/null +++ b/src/devices/bus/nasbus/cards.h @@ -0,0 +1,21 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best +/*************************************************************************** + + Nascom NASBUS Slot Devices + +***************************************************************************/ + +#pragma once + +#ifndef __NASBUS_CARDS_H__ +#define __NASBUS_CARDS_H__ + +#include "emu.h" + +#include "avc.h" +#include "floppy.h" + +SLOT_INTERFACE_EXTERN( nasbus_slot_cards ); + +#endif // __NASBUS_CARDS_H__ diff --git a/src/devices/bus/nasbus/floppy.c b/src/devices/bus/nasbus/floppy.c new file mode 100644 index 00000000000..cf68765a0ae --- /dev/null +++ b/src/devices/bus/nasbus/floppy.c @@ -0,0 +1,209 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best +/*************************************************************************** + + Nascom NASBUS Floppy Disc Controller + +***************************************************************************/ + +#include "floppy.h" +#include "formats/nascom_dsk.h" + + +//************************************************************************** +// CONSTANTS/MACROS +//************************************************************************** + +#define VERBOSE 1 +#define VERBOSE_STATUS 0 + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type NASCOM_FDC = &device_creator; + +FLOPPY_FORMATS_MEMBER( nascom_fdc_device::floppy_formats ) + FLOPPY_NASCOM_FORMAT +FLOPPY_FORMATS_END + +static SLOT_INTERFACE_START( nascom_floppies ) + SLOT_INTERFACE("55e", TEAC_FD_55E) + SLOT_INTERFACE("55f", TEAC_FD_55F) +SLOT_INTERFACE_END + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( nascom_fdc ) + MCFG_FD1793_ADD("fd1793", XTAL_16MHz / 4 / 4) + + MCFG_FLOPPY_DRIVE_ADD("fd1793:0", nascom_floppies, "55f", nascom_fdc_device::floppy_formats) + MCFG_FLOPPY_DRIVE_ADD("fd1793:1", nascom_floppies, "55f", nascom_fdc_device::floppy_formats) + MCFG_FLOPPY_DRIVE_ADD("fd1793:2", nascom_floppies, NULL, nascom_fdc_device::floppy_formats) + MCFG_FLOPPY_DRIVE_ADD("fd1793:3", nascom_floppies, NULL, nascom_fdc_device::floppy_formats) + + MCFG_SOFTWARE_LIST_ADD("floppy_list", "nascom_flop") +MACHINE_CONFIG_END + +machine_config_constructor nascom_fdc_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( nascom_fdc ); +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// wordpro_device - constructor +//------------------------------------------------- + +nascom_fdc_device::nascom_fdc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, NASCOM_FDC, "Nascom Floppy Disc Controller", tag, owner, clock, "nascom_fdc", __FILE__), + device_nasbus_card_interface(mconfig, *this), + m_fdc(*this, "fd1793"), + m_floppy0(*this, "fd1793:0"), + m_floppy1(*this, "fd1793:1"), + m_floppy2(*this, "fd1793:2"), + m_floppy3(*this, "fd1793:3"), + m_floppy(NULL), + m_motor(NULL), + m_select(0) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void nascom_fdc_device::device_start() +{ + // timer to turn off the drive motor line + m_motor = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(nascom_fdc_device::motor_off), this)); + + save_item(NAME(m_select)); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void nascom_fdc_device::device_reset() +{ + m_nasbus->m_io->install_readwrite_handler(0xe0, 0xe3, read8_delegate(FUNC(fd1793_t::read), m_fdc.target()), write8_delegate(FUNC(fd1793_t::write), m_fdc.target())); + m_nasbus->m_io->install_readwrite_handler(0xe4, 0xe4, read8_delegate(FUNC(nascom_fdc_device::select_r), this), write8_delegate(FUNC(nascom_fdc_device::select_w), this)); + m_nasbus->m_io->install_read_handler(0xe5, 0xe5, read8_delegate(FUNC(nascom_fdc_device::status_r), this)); +} + +//------------------------------------------------- +// device_reset_after_children - device-specific reset after children +//------------------------------------------------- + +void nascom_fdc_device::device_reset_after_children() +{ + // sanity check + if (m_floppy0->get_device() && m_floppy1->get_device()) + if (m_floppy0->get_device()->get_sides() != m_floppy1->get_device()->get_sides()) + fatalerror("Floppy drive 0 and 1 need to be of the same type.\n"); + + if (m_floppy2->get_device() && m_floppy3->get_device()) + if (m_floppy2->get_device()->get_sides() != m_floppy3->get_device()->get_sides()) + fatalerror("Floppy drive 2 and 3 need to be of the same type.\n"); +} + + +//************************************************************************** +// IMPLEMENTATION +//************************************************************************** + +TIMER_CALLBACK_MEMBER( nascom_fdc_device::motor_off ) +{ + if (m_floppy0->get_device()) + m_floppy0->get_device()->mon_w(1); + + if (m_floppy1->get_device()) + m_floppy1->get_device()->mon_w(1); + + if (m_floppy2->get_device()) + m_floppy2->get_device()->mon_w(1); + + if (m_floppy3->get_device()) + m_floppy3->get_device()->mon_w(1); +} + +READ8_MEMBER( nascom_fdc_device::select_r ) +{ + m_select |= (0x80 | 0x20); + + // double sided drive for drive 0/1? + if (m_floppy0->get_device() && (m_floppy0->get_device()->get_sides() == 2)) + m_select &= ~0x20; + + if (m_floppy1->get_device() && (m_floppy1->get_device()->get_sides() == 2)) + m_select &= ~0x20; + + // double sided drive for drive 2/3? + if (m_floppy2->get_device() && (m_floppy2->get_device()->get_sides() == 2)) + m_select &= ~0x80; + + if (m_floppy3->get_device() && (m_floppy3->get_device()->get_sides() == 2)) + m_select &= ~0x80; + + if (VERBOSE) + logerror("nascom_fdc_device::select_r: 0x%02x\n", m_select); + + return m_select; +} + +WRITE8_MEMBER( nascom_fdc_device::select_w ) +{ + if (VERBOSE) + logerror("nascom_fdc_device::select_w: 0x%02x\n", data); + + m_floppy = NULL; + + if (BIT(data, 0)) m_floppy = m_floppy0->get_device(); + if (BIT(data, 1)) m_floppy = m_floppy1->get_device(); + if (BIT(data, 2)) m_floppy = m_floppy2->get_device(); + if (BIT(data, 3)) m_floppy = m_floppy3->get_device(); + + m_fdc->set_floppy(m_floppy); + + if (m_floppy) + { + m_floppy->ss_w(BIT(data, 4)); + m_floppy->mon_w(!BIT(data, 5)); + + // motor gets turned off again after 10 seconds + m_motor->adjust(attotime::from_seconds(10), 0); + } + + m_fdc->dden_w(BIT(data, 6)); + + m_select = data; +} + +READ8_MEMBER( nascom_fdc_device::status_r ) +{ + UINT8 data = 0; + + data |= m_fdc->intrq_r() << 0; + + // if a floppy is selected, get its ready state, otherwise just set non-ready + if (m_floppy) + data |= m_floppy->ready_r() << 1; + else + data |= 1 << 1; + + data |= m_fdc->drq_r() << 7; + + if (VERBOSE_STATUS) + logerror("nascom_fdc_device::status_r: 0x%02x\n", data); + + return data; +} diff --git a/src/devices/bus/nasbus/floppy.h b/src/devices/bus/nasbus/floppy.h new file mode 100644 index 00000000000..9315bb92df1 --- /dev/null +++ b/src/devices/bus/nasbus/floppy.h @@ -0,0 +1,61 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best +/*************************************************************************** + + Nascom NASBUS Floppy Disc Controller + +***************************************************************************/ + +#pragma once + +#ifndef __NASBUS_FLOPPY_H__ +#define __NASBUS_FLOPPY_H__ + +#include "emu.h" +#include "nasbus.h" +#include "machine/wd_fdc.h" + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> nascom_fdc_device + +class nascom_fdc_device : public device_t, public device_nasbus_card_interface +{ +public: + // construction/destruction + nascom_fdc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + DECLARE_READ8_MEMBER(select_r); + DECLARE_WRITE8_MEMBER(select_w); + DECLARE_READ8_MEMBER(status_r); + + DECLARE_FLOPPY_FORMATS(floppy_formats); + +protected: + virtual machine_config_constructor device_mconfig_additions() const; + virtual void device_start(); + virtual void device_reset(); + virtual void device_reset_after_children(); + +private: + TIMER_CALLBACK_MEMBER(motor_off); + + required_device m_fdc; + required_device m_floppy0; + required_device m_floppy1; + required_device m_floppy2; + required_device m_floppy3; + + floppy_image_device *m_floppy; + emu_timer *m_motor; + + UINT8 m_select; +}; + +// device type definition +extern const device_type NASCOM_FDC; + +#endif // __NASBUS_FLOPPY_H__ diff --git a/src/devices/bus/nasbus/nasbus.c b/src/devices/bus/nasbus/nasbus.c new file mode 100644 index 00000000000..739ef9decdf --- /dev/null +++ b/src/devices/bus/nasbus/nasbus.c @@ -0,0 +1,165 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best +/*************************************************************************** + + Nascom NASBUS + + 77-pin slot + +***************************************************************************/ + +#include "nasbus.h" + + +//************************************************************************** +// NASBUS SLOT DEVICE +//************************************************************************** + +const device_type NASBUS_SLOT = &device_creator; + +//------------------------------------------------- +// nasbus_slot_device - constructor +//------------------------------------------------- + +nasbus_slot_device::nasbus_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, NASBUS_SLOT, "NASBUS Slot", tag, owner, clock, "nasbus_slot", __FILE__), + device_slot_interface(mconfig, *this), + m_nasbus_tag(NULL) +{ +} + +nasbus_slot_device::nasbus_slot_device(const machine_config &mconfig, device_type type, const char *name, + const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_slot_interface(mconfig, *this), + m_nasbus_tag(NULL) +{ +} + +void nasbus_slot_device::set_nasbus_slot(device_t &device, device_t *owner, const char *nasbus_tag) +{ + nasbus_slot_device &nasbus_card = dynamic_cast(device); + nasbus_card.m_owner = owner; + nasbus_card.m_nasbus_tag = nasbus_tag; +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void nasbus_slot_device::device_start() +{ + device_nasbus_card_interface *dev = dynamic_cast(get_card_device()); + + if (dev) + { + nasbus_device *m_nasbus = downcast(m_owner->subdevice(m_nasbus_tag)); + m_nasbus->add_card(dev); + } +} + + +//************************************************************************** +// NASBUS DEVICE +//************************************************************************** + +const device_type NASBUS = &device_creator; + +//------------------------------------------------- +// nasbus_device - constructor +//------------------------------------------------- + +nasbus_device::nasbus_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, NASBUS_SLOT, "NASBUS Backplane", tag, owner, clock, "nasbus", __FILE__), + m_program(NULL), + m_io(NULL), + m_ram_disable_handler(*this) +{ +} + +//------------------------------------------------- +// nasbus_device - destructor +//------------------------------------------------- + +nasbus_device::~nasbus_device() +{ + m_dev.detach_all(); +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void nasbus_device::device_start() +{ + // resolve callbacks + m_ram_disable_handler.resolve_safe(); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void nasbus_device::device_reset() +{ +} + +//------------------------------------------------- +// add_card - add new card to our bus +//------------------------------------------------- + +void nasbus_device::add_card(device_nasbus_card_interface *card) +{ + card->set_nasbus_device(this); + m_dev.append(*card); +} + +//------------------------------------------------- +// set_program_space - set address space we are attached to +//------------------------------------------------- + +void nasbus_device::set_program_space(address_space *program) +{ + m_program = program; +} + +//------------------------------------------------- +// set_io_space - set address space we are attached to +//------------------------------------------------- + +void nasbus_device::set_io_space(address_space *io) +{ + m_io = io; +} + +// callbacks from slot device to the host +WRITE_LINE_MEMBER( nasbus_device::ram_disable_w ) { m_ram_disable_handler(state); } + + +//************************************************************************** +// CARTRIDGE INTERFACE +//************************************************************************** + +//------------------------------------------------- +// device_nasbus_card_interface - constructor +//------------------------------------------------- + +device_nasbus_card_interface::device_nasbus_card_interface(const machine_config &mconfig, device_t &device) : + device_slot_card_interface(mconfig, device), + m_next(NULL), + m_nasbus(NULL) +{ +} + +//------------------------------------------------- +// ~device_nasbus_card_interface - destructor +//------------------------------------------------- + +device_nasbus_card_interface::~device_nasbus_card_interface() +{ +} + +void device_nasbus_card_interface::set_nasbus_device(nasbus_device *nasbus) +{ + m_nasbus = nasbus; +} diff --git a/src/devices/bus/nasbus/nasbus.h b/src/devices/bus/nasbus/nasbus.h new file mode 100644 index 00000000000..f7766bc0426 --- /dev/null +++ b/src/devices/bus/nasbus/nasbus.h @@ -0,0 +1,210 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best +/*************************************************************************** + + Nascom NASBUS + + 77-pin slot + + 1 0V + 2 0V + 3 0V + 4 0V + 5 Clock + 6 (spare) + 7 (spare) + 8 (spare) + 9 /RAM DISABLE + 10 /RESET SWITCH + 11 /NASCOM MEM + 12 /NASCOM IO + 13 /DBDR + 14 /RESET + 15 /HALT + 16 /BAI + 17 /BAO + 18 /BUSRQ + 19 IEI + 20 IEO + 21 (reserved for /NMI) + 22 /INT + 23 /WAIT + 24 /RFSH + 25 /MI + 26 /IORQ + 27 /MREQ + 28 /WR + 29 /RD + 30 A0 + 31 A1 + 32 A2 + 33 A3 + 34 A4 + 35 A5 + 36 A6 + 37 A7 + 38 A8 + 39 A9 + 40 A10 + 41 A11 + 42 A12 + 43 A13 + 44 A14 + 45 A15 + 46 (reserved) + 47 (reserved) + 48 (reserved) + 49 (reserved) + 50 D0 + 51 D1 + 52 D2 + 53 D3 + 54 D4 + 55 D5 + 56 D6 + 57 D7 + 58 (reserved) + 59 (reserved) + 60 (reserved) + 61 (reserved) + 62 (reserved) + 63 (reserved) + 64 (reserved) + 65 (reserved) + 66 (unused) + 67 (unused) + 68 -5V + 69 -5V + 70 -12V + 71 -12V + 72 Keyway + 73 +12V + 74 +12V + 75 +5V + 76 +5V + 77 +5V + 78 +5V + +***************************************************************************/ + +#pragma once + +#ifndef __NASBUS_H__ +#define __NASBUS_H__ + +#include "emu.h" + + +//************************************************************************** +// CONSTANTS / MACROS +//************************************************************************** + +#define NASBUS_TAG "nasbus" + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_NASBUS_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, NASBUS, 0) + +#define MCFG_NASBUS_SLOT_ADD(_tag, _slot_intf, _def_slot) \ + MCFG_DEVICE_ADD(_tag, NASBUS_SLOT, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) \ + nasbus_slot_device::set_nasbus_slot(*device, owner, NASBUS_TAG); + +#define MCFG_NASBUS_RAM_DISABLE_HANDLER(_devcb) \ + devcb = &nasbus_device::set_ram_disable_handler(*device, DEVCB_##_devcb); + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// forward declaration +class device_nasbus_card_interface; + +// ======================> nasbus_slot_device + +class nasbus_slot_device : public device_t, public device_slot_interface +{ +public: + // construction/destruction + nasbus_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + nasbus_slot_device(const machine_config &mconfig, device_type type, const char *name, + const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + // device-level overrides + virtual void device_start(); + + // inline configuration + static void set_nasbus_slot(device_t &device, device_t *owner, const char *nasbus_tag); + +protected: + // configuration + const char *m_nasbus_tag; +}; + +// device type definition +extern const device_type NASBUS_SLOT; + +// ======================> nasbus_device + +class nasbus_device : public device_t +{ +public: + // construction/destruction + nasbus_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual ~nasbus_device(); + + template static devcb_base &set_ram_disable_handler(device_t &device, _Object object) + { return downcast(device).m_ram_disable_handler.set_callback(object); } + + void add_card(device_nasbus_card_interface *card); + + void set_program_space(address_space *program); + void set_io_space(address_space *io); + + // from cards + DECLARE_WRITE_LINE_MEMBER( ram_disable_w ); + + address_space *m_program; + address_space *m_io; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + +private: + simple_list m_dev; + + devcb_write_line m_ram_disable_handler; +}; + +// device type definition +extern const device_type NASBUS; + +// ======================> device_nasbus_interface + +class device_nasbus_card_interface : public device_slot_card_interface +{ +public: + // construction/destruction + device_nasbus_card_interface(const machine_config &mconfig, device_t &device); + virtual ~device_nasbus_card_interface(); + + void set_nasbus_device(nasbus_device *nasbus); + + device_nasbus_card_interface *next() const { return m_next; } + device_nasbus_card_interface *m_next; + +protected: + nasbus_device *m_nasbus; +}; + +// include here so drivers don't need to +#include "cards.h" + +#endif // __NASBUS_H__ diff --git a/src/devices/bus/neogeo/banked_cart.c b/src/devices/bus/neogeo/banked_cart.c new file mode 100644 index 00000000000..9d0e1f06cad --- /dev/null +++ b/src/devices/bus/neogeo/banked_cart.c @@ -0,0 +1,107 @@ +// license:BSD-3-Clause +// copyright-holders:S. Smith,David Haywood +#include "emu.h" +#include "banked_cart.h" + + + +extern const device_type NEOGEO_BANKED_CART = &device_creator; + + +neogeo_banked_cart_device::neogeo_banked_cart_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, NEOGEO_BANKED_CART, "NeoGeo Banked Cartridge", tag, owner, clock, "neogeo_banked_cart", __FILE__), + m_bank_cartridge(0), + m_region(0) + +{ +} + +void neogeo_banked_cart_device::postload() +{ + _set_main_cpu_bank_address(); +} + +void neogeo_banked_cart_device::device_start() +{ + save_item(NAME(m_main_cpu_bank_address)); + machine().save().register_postload(save_prepost_delegate(FUNC(neogeo_banked_cart_device::postload), this)); +} + +void neogeo_banked_cart_device::device_reset() +{ +} + + + + + + +/************************************* + * + * Main CPU banking + * + *************************************/ + +void neogeo_banked_cart_device::_set_main_cpu_bank_address(void) +{ + if (!m_region) + printf("region is null\n"); + + if (!m_bank_cartridge) + printf("bank_cartridge is null\n"); + + if (m_region && m_bank_cartridge) m_bank_cartridge->set_base(m_region + m_main_cpu_bank_address); +} + + +void neogeo_banked_cart_device::neogeo_set_main_cpu_bank_address( UINT32 bank_address ) +{ +// if (LOG_MAIN_CPU_BANKING) logerror("MAIN CPU PC %06x: neogeo_set_main_cpu_bank_address %06x\n", m_maincpu->pc(), bank_address); + + m_main_cpu_bank_address = bank_address; + + _set_main_cpu_bank_address(); +} + + +WRITE16_MEMBER(neogeo_banked_cart_device::main_cpu_bank_select_w) +{ + UINT32 bank_address; + UINT32 len = m_region_size; + + if ((len <= 0x100000) && (data & 0x07)) + logerror("PC %06x: warning: bankswitch to %02x but no banks available\n", space.device().safe_pc(), data); + else + { + bank_address = ((data & 0x07) + 1) * 0x100000; + + if (bank_address >= len) + { + logerror("PC %06x: warning: bankswitch to empty bank %02x\n", space.device().safe_pc(), data); + bank_address = 0x100000; + } + + neogeo_set_main_cpu_bank_address(bank_address); + } +} + +void neogeo_banked_cart_device::init_banks(void) +{ + /* set initial main CPU bank */ + if (m_region_size > 0x100000) + neogeo_set_main_cpu_bank_address(0x100000); + else + neogeo_set_main_cpu_bank_address(0x000000); +} + +void neogeo_banked_cart_device::install_banks(running_machine& machine, cpu_device* maincpu, UINT8* region, UINT32 region_size) +{ + maincpu->space(AS_PROGRAM).install_read_bank(0x200000, 0x2fffff, 0, 0, "cartridge"); + maincpu->space(AS_PROGRAM).install_write_handler(0x2ffff0, 0x2fffff, write16_delegate(FUNC(neogeo_banked_cart_device::main_cpu_bank_select_w),this)); + + m_bank_cartridge = machine.root_device().membank("cartridge"); + m_region = region; + m_region_size = region_size; + + init_banks(); +} diff --git a/src/devices/bus/neogeo/banked_cart.h b/src/devices/bus/neogeo/banked_cart.h new file mode 100644 index 00000000000..f81b8f5b9c9 --- /dev/null +++ b/src/devices/bus/neogeo/banked_cart.h @@ -0,0 +1,46 @@ +// license:BSD-3-Clause +// copyright-holders:S. Smith,David Haywood + + +#pragma once + +#ifndef __NEOGEO_BANKED_CART__ +#define __NEOGEO_BANKED_CART__ + +extern const device_type NEOGEO_BANKED_CART; + +#define MCFG_NEOGEO_BANKED_CART_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, NEOGEO_BANKED_CART, 0) + + +class neogeo_banked_cart_device : public device_t +{ +public: + // construction/destruction + neogeo_banked_cart_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + memory_bank* m_bank_cartridge; + UINT32 m_main_cpu_bank_address; + UINT8* m_region; + UINT32 m_region_size; + + + void install_banks(running_machine& machine, cpu_device* maincpu, UINT8* region, UINT32 region_size); + WRITE16_MEMBER(main_cpu_bank_select_w); + void neogeo_set_main_cpu_bank_address(UINT32 bank_address); + void _set_main_cpu_bank_address(); + void init_banks(void); + +protected: + virtual void device_start(); + virtual void device_reset(); + void postload(); + + + +private: + + +}; + +#endif diff --git a/src/devices/bus/neogeo/bootleg_cart.c b/src/devices/bus/neogeo/bootleg_cart.c new file mode 100644 index 00000000000..45a4563f88d --- /dev/null +++ b/src/devices/bus/neogeo/bootleg_cart.c @@ -0,0 +1,378 @@ +// license:BSD-3-Clause +// copyright-holders:S. Smith,David Haywood +/*********************************************************************************************************** + + NEOGEO ROM cart emulation + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "bootleg_cart.h" + + +//------------------------------------------------- +// neogeo_bootleg_cart - constructor +//------------------------------------------------- + +const device_type NEOGEO_BOOTLEG_CART = &device_creator; + + +neogeo_bootleg_cart::neogeo_bootleg_cart(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT16 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_neogeo_cart_interface(mconfig, *this), + m_banked_cart(*this, "banked_cart"), + m_bootleg_prot(*this, "bootleg_prot") + +{ +} + +neogeo_bootleg_cart::neogeo_bootleg_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT16 clock) + : device_t(mconfig, NEOGEO_BOOTLEG_CART, "NEOGEO Bootleg Cart", tag, owner, clock, "neogeo_rom", __FILE__), + device_neogeo_cart_interface(mconfig, *this), + m_banked_cart(*this, "banked_cart"), + m_bootleg_prot(*this, "bootleg_prot") +{ +} + + +//------------------------------------------------- +// mapper specific start/reset +//------------------------------------------------- + +void neogeo_bootleg_cart::device_start() +{ +} + +void neogeo_bootleg_cart::device_reset() +{ +} + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +READ16_MEMBER(neogeo_bootleg_cart::read_rom) +{ + return m_rom[offset]; +} + +static MACHINE_CONFIG_FRAGMENT( bootleg_cart ) + MCFG_NEOGEO_BANKED_CART_ADD("banked_cart") + MCFG_NGBOOTLEG_PROT_ADD("bootleg_prot") +MACHINE_CONFIG_END + +machine_config_constructor neogeo_bootleg_cart::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( bootleg_cart ); +} + + + +/* Individual cartridge types (mirror DRIVER_INIT functionality) */ + + +/************************************************* + garoubl +**************************************************/ + +const device_type NEOGEO_BOOTLEG_GAROUBL_CART = &device_creator; + +neogeo_bootleg_garoubl_cart::neogeo_bootleg_garoubl_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : neogeo_bootleg_cart(mconfig, NEOGEO_BOOTLEG_GAROUBL_CART, "NEOGEO BOOT garoubl Cart", tag, owner, clock, "boot_garoubl_cart", __FILE__) {} + +void neogeo_bootleg_garoubl_cart::activate_cart(ACTIVATE_CART_PARAMS) +{ + m_banked_cart->install_banks(machine, maincpu, cpuregion, cpuregion_size); + +} + +void neogeo_bootleg_garoubl_cart::decrypt_all(DECRYPT_ALL_PARAMS) +{ + m_bootleg_prot->neogeo_bootleg_sx_decrypt(fix_region, fix_region_size,2); + m_bootleg_prot->neogeo_bootleg_cx_decrypt(spr_region, spr_region_size); +} + +/************************************************* + cthd2003 +**************************************************/ + +const device_type NEOGEO_BOOTLEG_CTHD2003_CART = &device_creator; + +neogeo_bootleg_cthd2003_cart::neogeo_bootleg_cthd2003_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : neogeo_bootleg_cart(mconfig, NEOGEO_BOOTLEG_CTHD2003_CART, "NEOGEO BOOT cthd2003 Cart", tag, owner, clock, "boot_cthd2003_cart", __FILE__) {} + +void neogeo_bootleg_cthd2003_cart::activate_cart(ACTIVATE_CART_PARAMS) +{ + m_banked_cart->install_banks(machine, maincpu, cpuregion, cpuregion_size); + m_bootleg_prot->patch_cthd2003(maincpu,m_banked_cart, cpuregion, cpuregion_size); +} + +void neogeo_bootleg_cthd2003_cart::decrypt_all(DECRYPT_ALL_PARAMS) +{ + m_bootleg_prot->decrypt_cthd2003(spr_region, spr_region_size, audiocpu_region, audio_region_size, fix_region, fix_region_size); +} + +/******/ + +const device_type NEOGEO_BOOTLEG_CT2K3SP_CART = &device_creator; + +neogeo_bootleg_ct2k3sp_cart::neogeo_bootleg_ct2k3sp_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : neogeo_bootleg_cart(mconfig, NEOGEO_BOOTLEG_CT2K3SP_CART, "NEOGEO BOOT ct2k3sp Cart", tag, owner, clock, "boot_ct2k3sp_cart", __FILE__) {} + +void neogeo_bootleg_ct2k3sp_cart::activate_cart(ACTIVATE_CART_PARAMS) +{ + m_banked_cart->install_banks(machine, maincpu, cpuregion, cpuregion_size); + m_bootleg_prot->patch_cthd2003(maincpu,m_banked_cart, cpuregion, cpuregion_size); +} + +void neogeo_bootleg_ct2k3sp_cart::decrypt_all(DECRYPT_ALL_PARAMS) +{ + m_bootleg_prot->decrypt_ct2k3sp(spr_region, spr_region_size, audiocpu_region, audio_region_size, fix_region, fix_region_size); +} + +/******/ + +const device_type NEOGEO_BOOTLEG_CT2K3SA_CART = &device_creator; + +neogeo_bootleg_ct2k3sa_cart::neogeo_bootleg_ct2k3sa_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : neogeo_bootleg_cart(mconfig, NEOGEO_BOOTLEG_CT2K3SA_CART, "NEOGEO BOOT ct2k3sa Cart", tag, owner, clock, "boot_ct2k3sa_cart", __FILE__) {} + +void neogeo_bootleg_ct2k3sa_cart::activate_cart(ACTIVATE_CART_PARAMS) +{ + m_banked_cart->install_banks(machine, maincpu, cpuregion, cpuregion_size); +} + +void neogeo_bootleg_ct2k3sa_cart::decrypt_all(DECRYPT_ALL_PARAMS) +{ + m_bootleg_prot->decrypt_ct2k3sa(spr_region, spr_region_size, audiocpu_region, audio_region_size); + m_bootleg_prot->patch_ct2k3sa(cpuregion, cpuregion_size); +} + +/************************************************* + kf10thep +**************************************************/ + +const device_type NEOGEO_BOOTLEG_KF10THEP_CART = &device_creator; + +neogeo_bootleg_kf10thep_cart::neogeo_bootleg_kf10thep_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : neogeo_bootleg_cart(mconfig, NEOGEO_BOOTLEG_KF10THEP_CART, "NEOGEO BOOT kf10thep Cart", tag, owner, clock, "boot_kf10thep_cart", __FILE__) {} + +void neogeo_bootleg_kf10thep_cart::activate_cart(ACTIVATE_CART_PARAMS) +{ + m_banked_cart->install_banks(machine, maincpu, cpuregion, cpuregion_size); + +} + +void neogeo_bootleg_kf10thep_cart::decrypt_all(DECRYPT_ALL_PARAMS) +{ + m_bootleg_prot->kf10thep_px_decrypt(cpuregion, cpuregion_size); + m_bootleg_prot->neogeo_bootleg_sx_decrypt(fix_region,fix_region_size,1); +} + + +/************************************************* + kf2k5uni +**************************************************/ + +const device_type NEOGEO_BOOTLEG_KF2K5UNI_CART = &device_creator; + +neogeo_bootleg_kf2k5uni_cart::neogeo_bootleg_kf2k5uni_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : neogeo_bootleg_cart(mconfig, NEOGEO_BOOTLEG_KF2K5UNI_CART, "NEOGEO BOOT kf2k5uni Cart", tag, owner, clock, "boot_kf2k5uni_cart", __FILE__) {} + +void neogeo_bootleg_kf2k5uni_cart::activate_cart(ACTIVATE_CART_PARAMS) +{ + m_banked_cart->install_banks(machine, maincpu, cpuregion, cpuregion_size); + +} + +void neogeo_bootleg_kf2k5uni_cart::decrypt_all(DECRYPT_ALL_PARAMS) +{ + m_bootleg_prot->decrypt_kf2k5uni(cpuregion,cpuregion_size, audiocpu_region, audio_region_size, fix_region, fix_region_size); +} + + +/************************************************* + kf2k4se +**************************************************/ + +const device_type NEOGEO_BOOTLEG_KF2K4SE_CART = &device_creator; + +neogeo_bootleg_kf2k4se_cart::neogeo_bootleg_kf2k4se_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : neogeo_bootleg_cart(mconfig, NEOGEO_BOOTLEG_KF2K4SE_CART, "NEOGEO BOOT kf2k4se Cart", tag, owner, clock, "boot_kf2k4se_cart", __FILE__) {} + +void neogeo_bootleg_kf2k4se_cart::activate_cart(ACTIVATE_CART_PARAMS) +{ + m_banked_cart->install_banks(machine, maincpu, cpuregion, cpuregion_size); + +} + +void neogeo_bootleg_kf2k4se_cart::decrypt_all(DECRYPT_ALL_PARAMS) +{ + m_bootleg_prot->decrypt_kof2k4se_68k(cpuregion, cpuregion_size); +} + + + +/************************************************* + svcplus +**************************************************/ + +const device_type NEOGEO_BOOTLEG_SVCPLUS_CART = &device_creator; + +neogeo_bootleg_svcplus_cart::neogeo_bootleg_svcplus_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : neogeo_bootleg_cart(mconfig, NEOGEO_BOOTLEG_SVCPLUS_CART, "NEOGEO BOOT svcplus Cart", tag, owner, clock, "boot_svcplus_cart", __FILE__) {} + +void neogeo_bootleg_svcplus_cart::activate_cart(ACTIVATE_CART_PARAMS) +{ + m_banked_cart->install_banks(machine, maincpu, cpuregion, cpuregion_size); + +} + +void neogeo_bootleg_svcplus_cart::decrypt_all(DECRYPT_ALL_PARAMS) +{ + m_bootleg_prot->svcplus_px_decrypt(cpuregion, cpuregion_size); + m_bootleg_prot->svcboot_cx_decrypt(spr_region, spr_region_size); + m_bootleg_prot->neogeo_bootleg_sx_decrypt(fix_region, fix_region_size, 1); + m_bootleg_prot->svcplus_px_hack(cpuregion, cpuregion_size); +} + + +/************************************************* + svcplusaa +**************************************************/ + +const device_type NEOGEO_BOOTLEG_SVCPLUSA_CART = &device_creator; + +neogeo_bootleg_svcplusa_cart::neogeo_bootleg_svcplusa_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : neogeo_bootleg_cart(mconfig, NEOGEO_BOOTLEG_SVCPLUSA_CART, "NEOGEO BOOT svcplusa Cart", tag, owner, clock, "boot_svcplusa_cart", __FILE__) {} + +void neogeo_bootleg_svcplusa_cart::activate_cart(ACTIVATE_CART_PARAMS) +{ + m_banked_cart->install_banks(machine, maincpu, cpuregion, cpuregion_size); + +} + +void neogeo_bootleg_svcplusa_cart::decrypt_all(DECRYPT_ALL_PARAMS) +{ + m_bootleg_prot->svcplusa_px_decrypt(cpuregion, cpuregion_size); + m_bootleg_prot->svcboot_cx_decrypt(spr_region, spr_region_size); + m_bootleg_prot->svcplus_px_hack(cpuregion, cpuregion_size); +} + +/************************************************* + samsho5b +**************************************************/ + +const device_type NEOGEO_BOOTLEG_SAMSHO5B_CART = &device_creator; + +neogeo_bootleg_samsho5b_cart::neogeo_bootleg_samsho5b_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : neogeo_bootleg_cart(mconfig, NEOGEO_BOOTLEG_SAMSHO5B_CART, "NEOGEO BOOT samsho5b Cart", tag, owner, clock, "boot_samsho5b_cart", __FILE__) {} + +void neogeo_bootleg_samsho5b_cart::activate_cart(ACTIVATE_CART_PARAMS) +{ + m_banked_cart->install_banks(machine, maincpu, cpuregion, cpuregion_size); + +} + +void neogeo_bootleg_samsho5b_cart::decrypt_all(DECRYPT_ALL_PARAMS) +{ + m_bootleg_prot->samsho5b_px_decrypt(cpuregion, cpuregion_size); + m_bootleg_prot->samsho5b_vx_decrypt(ym_region, ym_region_size); + m_bootleg_prot->neogeo_bootleg_sx_decrypt(fix_region, fix_region_size,1); + m_bootleg_prot->neogeo_bootleg_cx_decrypt(spr_region, spr_region_size); +} + + +/************************************************* + kof97oro +**************************************************/ + +const device_type NEOGEO_BOOTLEG_KOF97ORO_CART = &device_creator; + +neogeo_bootleg_kof97oro_cart::neogeo_bootleg_kof97oro_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : neogeo_bootleg_cart(mconfig, NEOGEO_BOOTLEG_KOF97ORO_CART, "NEOGEO BOOT kof97oro Cart", tag, owner, clock, "boot_kof97oro_cart", __FILE__) {} + +void neogeo_bootleg_kof97oro_cart::activate_cart(ACTIVATE_CART_PARAMS) +{ + m_banked_cart->install_banks(machine, maincpu, cpuregion, cpuregion_size); + +} + +void neogeo_bootleg_kof97oro_cart::decrypt_all(DECRYPT_ALL_PARAMS) +{ + m_bootleg_prot->kof97oro_px_decode(cpuregion, cpuregion_size); + m_bootleg_prot->neogeo_bootleg_sx_decrypt(fix_region, fix_region_size,1); + m_bootleg_prot->neogeo_bootleg_cx_decrypt(spr_region, spr_region_size); +} + + +/************************************************* + lans2004 +**************************************************/ + +const device_type NEOGEO_BOOTLEG_LANS2004_CART = &device_creator; + +neogeo_bootleg_lans2004_cart::neogeo_bootleg_lans2004_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : neogeo_bootleg_cart(mconfig, NEOGEO_BOOTLEG_LANS2004_CART, "NEOGEO BOOT lans2004 Cart", tag, owner, clock, "boot_lans2004_cart", __FILE__) {} + +void neogeo_bootleg_lans2004_cart::activate_cart(ACTIVATE_CART_PARAMS) +{ + m_banked_cart->install_banks(machine, maincpu, cpuregion, cpuregion_size); + +} + +void neogeo_bootleg_lans2004_cart::decrypt_all(DECRYPT_ALL_PARAMS) +{ + m_bootleg_prot->lans2004_decrypt_68k(cpuregion, cpuregion_size); + m_bootleg_prot->lans2004_vx_decrypt(ym_region, ym_region_size); + m_bootleg_prot->neogeo_bootleg_sx_decrypt(fix_region, fix_region_size,1); + m_bootleg_prot->neogeo_bootleg_cx_decrypt(spr_region, spr_region_size); +} + + +/************************************************* + kof10th +**************************************************/ + +const device_type NEOGEO_BOOTLEG_KOF10TH_CART = &device_creator; + +neogeo_bootleg_kof10th_cart::neogeo_bootleg_kof10th_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : neogeo_bootleg_cart(mconfig, NEOGEO_BOOTLEG_KOF10TH_CART, "NEOGEO BOOT kof10th Cart", tag, owner, clock, "boot_kof10th_cart", __FILE__) {} + +void neogeo_bootleg_kof10th_cart::activate_cart(ACTIVATE_CART_PARAMS) +{ + m_banked_cart->install_banks(machine, maincpu, cpuregion, cpuregion_size); + m_bootleg_prot->install_kof10th_protection(maincpu,m_banked_cart, cpuregion, cpuregion_size, fixedregion, fixedregion_size); + +} + +void neogeo_bootleg_kof10th_cart::decrypt_all(DECRYPT_ALL_PARAMS) +{ + m_bootleg_prot->decrypt_kof10th(cpuregion, cpuregion_size); +} + + + +/************************************************* + kog +**************************************************/ + +const device_type NEOGEO_BOOTLEG_KOG_CART = &device_creator; + +neogeo_bootleg_kog_cart::neogeo_bootleg_kog_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : neogeo_bootleg_cart(mconfig, NEOGEO_BOOTLEG_KOG_CART, "NEOGEO BOOT kog Cart", tag, owner, clock, "boot_kog_cart", __FILE__), + m_kog_prot(*this, "kog_prot") +{} + +static MACHINE_CONFIG_FRAGMENT( kog_bootleg_cart ) + MCFG_NEOGEO_BANKED_CART_ADD("banked_cart") + MCFG_NGBOOTLEG_PROT_ADD("bootleg_prot") + MCFG_KOG_PROT_ADD("kog_prot") +MACHINE_CONFIG_END + +machine_config_constructor neogeo_bootleg_kog_cart::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( kog_bootleg_cart ); +} + + +void neogeo_bootleg_kog_cart::activate_cart(ACTIVATE_CART_PARAMS) +{ + m_banked_cart->install_banks(machine, maincpu, cpuregion, cpuregion_size); + m_kog_prot->kog_install_protection(maincpu); +} + +void neogeo_bootleg_kog_cart::decrypt_all(DECRYPT_ALL_PARAMS) +{ + m_kog_prot->kog_px_decrypt(cpuregion, cpuregion_size); + m_bootleg_prot->neogeo_bootleg_sx_decrypt(fix_region, fix_region_size,1); + m_bootleg_prot->neogeo_bootleg_cx_decrypt(spr_region, spr_region_size); +} diff --git a/src/devices/bus/neogeo/bootleg_cart.h b/src/devices/bus/neogeo/bootleg_cart.h new file mode 100644 index 00000000000..a3932c25df8 --- /dev/null +++ b/src/devices/bus/neogeo/bootleg_cart.h @@ -0,0 +1,250 @@ +// license:BSD-3-Clause +// copyright-holders:S. Smith,David Haywood +#ifndef __NEOGEO_BOOTLEG_CART_H +#define __NEOGEO_BOOTLEG_CART_H + +#include "neogeo_slot.h" +#include "banked_cart.h" +#include "sma_prot.h" +#include "bootleg_prot.h" +#include "kog_prot.h" + +// ======================> neogeo_bootleg_cart + +class neogeo_bootleg_cart : public device_t, + public device_neogeo_cart_interface +{ +public: + // construction/destruction + neogeo_bootleg_cart(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT16 clock, const char *shortname, const char *source); + neogeo_bootleg_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT16 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual machine_config_constructor device_mconfig_additions() const; + + // reading and writing + virtual DECLARE_READ16_MEMBER(read_rom); + + virtual void activate_cart(ACTIVATE_CART_PARAMS) {} + virtual void decrypt_all(DECRYPT_ALL_PARAMS) {} + virtual int get_fixed_bank_type(void) { return 0; } + + required_device m_banked_cart; + required_device m_bootleg_prot; +}; + + + +// device type definition +extern const device_type NEOGEO_BOOTLEG_CART; + + +/************************************************* + GAROUBL +**************************************************/ + +class neogeo_bootleg_garoubl_cart : public neogeo_bootleg_cart +{ +public: + neogeo_bootleg_garoubl_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + void activate_cart(ACTIVATE_CART_PARAMS); + virtual void decrypt_all(DECRYPT_ALL_PARAMS); + virtual int get_fixed_bank_type(void) { return 0; } +}; +extern const device_type NEOGEO_BOOTLEG_GAROUBL_CART; + + +/************************************************* + CTHD2003 +**************************************************/ + +class neogeo_bootleg_cthd2003_cart : public neogeo_bootleg_cart +{ +public: + neogeo_bootleg_cthd2003_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + void activate_cart(ACTIVATE_CART_PARAMS); + virtual void decrypt_all(DECRYPT_ALL_PARAMS); + virtual int get_fixed_bank_type(void) { return 0; } +}; +extern const device_type NEOGEO_BOOTLEG_CTHD2003_CART; + +class neogeo_bootleg_ct2k3sp_cart : public neogeo_bootleg_cart +{ +public: + neogeo_bootleg_ct2k3sp_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + void activate_cart(ACTIVATE_CART_PARAMS); + virtual void decrypt_all(DECRYPT_ALL_PARAMS); + virtual int get_fixed_bank_type(void) { return 0; } +}; +extern const device_type NEOGEO_BOOTLEG_CT2K3SP_CART; + +class neogeo_bootleg_ct2k3sa_cart : public neogeo_bootleg_cart +{ +public: + neogeo_bootleg_ct2k3sa_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + void activate_cart(ACTIVATE_CART_PARAMS); + virtual void decrypt_all(DECRYPT_ALL_PARAMS); + virtual int get_fixed_bank_type(void) { return 0; } +}; +extern const device_type NEOGEO_BOOTLEG_CT2K3SA_CART; + + +/************************************************* + KF10THEP +**************************************************/ + +class neogeo_bootleg_kf10thep_cart : public neogeo_bootleg_cart +{ +public: + neogeo_bootleg_kf10thep_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + void activate_cart(ACTIVATE_CART_PARAMS); + virtual void decrypt_all(DECRYPT_ALL_PARAMS); + virtual int get_fixed_bank_type(void) { return 0; } +}; +extern const device_type NEOGEO_BOOTLEG_KF10THEP_CART; + + +/************************************************* + KF2K5UNI +**************************************************/ + +class neogeo_bootleg_kf2k5uni_cart : public neogeo_bootleg_cart +{ +public: + neogeo_bootleg_kf2k5uni_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + void activate_cart(ACTIVATE_CART_PARAMS); + virtual void decrypt_all(DECRYPT_ALL_PARAMS); + virtual int get_fixed_bank_type(void) { return 0; } +}; +extern const device_type NEOGEO_BOOTLEG_KF2K5UNI_CART; + +/************************************************* + KF2K4SE +**************************************************/ + +class neogeo_bootleg_kf2k4se_cart : public neogeo_bootleg_cart +{ +public: + neogeo_bootleg_kf2k4se_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + void activate_cart(ACTIVATE_CART_PARAMS); + virtual void decrypt_all(DECRYPT_ALL_PARAMS); + virtual int get_fixed_bank_type(void) { return 0; } +}; +extern const device_type NEOGEO_BOOTLEG_KF2K4SE_CART; + + +/************************************************* + SVCPLUS +**************************************************/ + +class neogeo_bootleg_svcplus_cart : public neogeo_bootleg_cart +{ +public: + neogeo_bootleg_svcplus_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + void activate_cart(ACTIVATE_CART_PARAMS); + virtual void decrypt_all(DECRYPT_ALL_PARAMS); + virtual int get_fixed_bank_type(void) { return 0; } +}; +extern const device_type NEOGEO_BOOTLEG_SVCPLUS_CART; + +/************************************************* + SVCPLUSA +**************************************************/ + +class neogeo_bootleg_svcplusa_cart : public neogeo_bootleg_cart +{ +public: + neogeo_bootleg_svcplusa_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + void activate_cart(ACTIVATE_CART_PARAMS); + virtual void decrypt_all(DECRYPT_ALL_PARAMS); + virtual int get_fixed_bank_type(void) { return 0; } +}; +extern const device_type NEOGEO_BOOTLEG_SVCPLUSA_CART; + +/************************************************* + SAMSHO5B +**************************************************/ + +class neogeo_bootleg_samsho5b_cart : public neogeo_bootleg_cart +{ +public: + neogeo_bootleg_samsho5b_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + void activate_cart(ACTIVATE_CART_PARAMS); + virtual void decrypt_all(DECRYPT_ALL_PARAMS); + virtual int get_fixed_bank_type(void) { return 0; } +}; +extern const device_type NEOGEO_BOOTLEG_SAMSHO5B_CART; + + +/************************************************* + KOF97ORO +**************************************************/ + +class neogeo_bootleg_kof97oro_cart : public neogeo_bootleg_cart +{ +public: + neogeo_bootleg_kof97oro_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + void activate_cart(ACTIVATE_CART_PARAMS); + virtual void decrypt_all(DECRYPT_ALL_PARAMS); + virtual int get_fixed_bank_type(void) { return 0; } +}; +extern const device_type NEOGEO_BOOTLEG_KOF97ORO_CART; + + +/************************************************* + LANS2004 +**************************************************/ + +class neogeo_bootleg_lans2004_cart : public neogeo_bootleg_cart +{ +public: + neogeo_bootleg_lans2004_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + void activate_cart(ACTIVATE_CART_PARAMS); + virtual void decrypt_all(DECRYPT_ALL_PARAMS); + virtual int get_fixed_bank_type(void) { return 0; } +}; +extern const device_type NEOGEO_BOOTLEG_LANS2004_CART; + +/************************************************* + KOF10TH +**************************************************/ + +class neogeo_bootleg_kof10th_cart : public neogeo_bootleg_cart +{ +public: + neogeo_bootleg_kof10th_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + void activate_cart(ACTIVATE_CART_PARAMS); + virtual void decrypt_all(DECRYPT_ALL_PARAMS); + virtual int get_fixed_bank_type(void) { return 0; } +}; +extern const device_type NEOGEO_BOOTLEG_KOF10TH_CART; + + + +/************************************************* + KOG +**************************************************/ + +class neogeo_bootleg_kog_cart : public neogeo_bootleg_cart +{ +public: + neogeo_bootleg_kog_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + void activate_cart(ACTIVATE_CART_PARAMS); + virtual void decrypt_all(DECRYPT_ALL_PARAMS); + virtual int get_fixed_bank_type(void) { return 0; } + + virtual machine_config_constructor device_mconfig_additions() const; + + required_device m_kog_prot; +}; +extern const device_type NEOGEO_BOOTLEG_KOG_CART; + + + + + + + +#endif diff --git a/src/devices/bus/neogeo/bootleg_hybrid_cart.c b/src/devices/bus/neogeo/bootleg_hybrid_cart.c new file mode 100644 index 00000000000..5d677c8cc74 --- /dev/null +++ b/src/devices/bus/neogeo/bootleg_hybrid_cart.c @@ -0,0 +1,319 @@ +// license:BSD-3-Clause +// copyright-holders:S. Smith,David Haywood +/*********************************************************************************************************** + + NEOGEO ROM cart emulation + + these are bootlegs using a mix of reimplemented original features, could be further sorted + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "bootleg_hybrid_cart.h" + + +//------------------------------------------------- +// neogeo_bootleg_hybrid_hybrid_cart - constructor +//------------------------------------------------- + +const device_type NEOGEO_BOOTLEG_HYBRID_HYBRID_CART = &device_creator; + + +neogeo_bootleg_hybrid_hybrid_cart::neogeo_bootleg_hybrid_hybrid_cart(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT16 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_neogeo_cart_interface(mconfig, *this), + m_banked_cart(*this, "banked_cart"), + m_bootleg_prot(*this, "bootleg_prot"), + m_cmc_prot(*this, "cmc_prot"), + m_pcm2_prot(*this, "pcm2_prot"), + m_kof2002_prot(*this, "kof2002_prot"), + m_pvc_prot(*this, "pvc_prot") +{ +} + +neogeo_bootleg_hybrid_hybrid_cart::neogeo_bootleg_hybrid_hybrid_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT16 clock) + : device_t(mconfig, NEOGEO_BOOTLEG_HYBRID_HYBRID_CART, "NEOGEO SMA Cart", tag, owner, clock, "neogeo_rom", __FILE__), + device_neogeo_cart_interface(mconfig, *this), + m_banked_cart(*this, "banked_cart"), + m_bootleg_prot(*this, "bootleg_prot"), + m_cmc_prot(*this, "cmc_prot"), + m_pcm2_prot(*this, "pcm2_prot"), + m_kof2002_prot(*this, "kof2002_prot"), + m_pvc_prot(*this, "pvc_prot") + +{ +} + + +//------------------------------------------------- +// mapper specific start/reset +//------------------------------------------------- + +void neogeo_bootleg_hybrid_hybrid_cart::device_start() +{ +} + +void neogeo_bootleg_hybrid_hybrid_cart::device_reset() +{ +} + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +READ16_MEMBER(neogeo_bootleg_hybrid_hybrid_cart::read_rom) +{ + return m_rom[offset]; +} + +static MACHINE_CONFIG_FRAGMENT( bootleg_hybrid_cart ) + MCFG_NEOGEO_BANKED_CART_ADD("banked_cart") + MCFG_NGBOOTLEG_PROT_ADD("bootleg_prot") + MCFG_CMC_PROT_ADD("cmc_prot") + MCFG_PCM2_PROT_ADD("pcm2_prot") + MCFG_KOF2002_PROT_ADD("kof2002_prot") + MCFG_PVC_PROT_ADD("pvc_prot") +MACHINE_CONFIG_END + +machine_config_constructor neogeo_bootleg_hybrid_hybrid_cart::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( bootleg_hybrid_cart ); +} + + + +/* Individual cartridge types (mirror DRIVER_INIT functionality) */ + + +/************************************************* + mslug3b6 +**************************************************/ + +const device_type NEOGEO_BOOTLEG_HYBRID_MSLUG3B6_CART = &device_creator; + +neogeo_bootleg_hybrid_mslug3b6_cart::neogeo_bootleg_hybrid_mslug3b6_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : neogeo_bootleg_hybrid_hybrid_cart(mconfig, NEOGEO_BOOTLEG_HYBRID_MSLUG3B6_CART, "NEOGEO BOOT mslug3b6 Cart", tag, owner, clock, "boot_mslug3b6_cart", __FILE__) {} + +void neogeo_bootleg_hybrid_mslug3b6_cart::activate_cart(ACTIVATE_CART_PARAMS) +{ + m_banked_cart->install_banks(machine, maincpu, cpuregion, cpuregion_size); + +} + +void neogeo_bootleg_hybrid_mslug3b6_cart::decrypt_all(DECRYPT_ALL_PARAMS) +{ + m_bootleg_prot->neogeo_bootleg_sx_decrypt(fix_region, fix_region_size,2); + m_cmc_prot->cmc42_neogeo_gfx_decrypt(spr_region, spr_region_size, fix_region, fix_region_size, MSLUG3_GFX_KEY); +} + +/************************************************* + kof2002b +**************************************************/ + +const device_type NEOGEO_BOOTLEG_HYBRID_KOF2002B_CART = &device_creator; + +neogeo_bootleg_hybrid_kof2002b_cart::neogeo_bootleg_hybrid_kof2002b_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : neogeo_bootleg_hybrid_hybrid_cart(mconfig, NEOGEO_BOOTLEG_HYBRID_KOF2002B_CART, "NEOGEO BOOT kof2002b Cart", tag, owner, clock, "boot_kof2002b_cart", __FILE__) {} + +void neogeo_bootleg_hybrid_kof2002b_cart::activate_cart(ACTIVATE_CART_PARAMS) +{ + m_banked_cart->install_banks(machine, maincpu, cpuregion, cpuregion_size); + +} + +void neogeo_bootleg_hybrid_kof2002b_cart::decrypt_all(DECRYPT_ALL_PARAMS) +{ + m_kof2002_prot->kof2002_decrypt_68k(cpuregion, cpuregion_size); + m_pcm2_prot->neo_pcm2_swap(ym_region, ym_region_size, 0); + m_cmc_prot->neogeo_cmc50_m1_decrypt(audiocrypt_region, audiocrypt_region_size, audiocpu_region, audio_region_size); + m_bootleg_prot->kof2002b_gfx_decrypt(spr_region,0x4000000); + m_bootleg_prot->kof2002b_gfx_decrypt(fix_region,0x20000); +} + +/***/ + +const device_type NEOGEO_BOOTLEG_HYBRID_KF2K2MP_CART = &device_creator; + +neogeo_bootleg_hybrid_kf2k2mp_cart::neogeo_bootleg_hybrid_kf2k2mp_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : neogeo_bootleg_hybrid_hybrid_cart(mconfig, NEOGEO_BOOTLEG_HYBRID_KF2K2MP_CART, "NEOGEO BOOT kf2k2mp Cart", tag, owner, clock, "boot_kf2k2mp_cart", __FILE__) {} + +void neogeo_bootleg_hybrid_kf2k2mp_cart::activate_cart(ACTIVATE_CART_PARAMS) +{ + m_banked_cart->install_banks(machine, maincpu, cpuregion, cpuregion_size); + +} + +void neogeo_bootleg_hybrid_kf2k2mp_cart::decrypt_all(DECRYPT_ALL_PARAMS) +{ + m_bootleg_prot->kf2k2mp_decrypt(cpuregion, cpuregion_size); + m_pcm2_prot->neo_pcm2_swap(ym_region, ym_region_size, 0); + m_cmc_prot->neogeo_cmc50_m1_decrypt(audiocrypt_region, audiocrypt_region_size, audiocpu_region, audio_region_size); + m_bootleg_prot->neogeo_bootleg_sx_decrypt(fix_region, fix_region_size,2); + m_cmc_prot->cmc50_neogeo_gfx_decrypt(spr_region, spr_region_size, fix_region, fix_region_size, KOF2002_GFX_KEY); +} + +/***/ + +const device_type NEOGEO_BOOTLEG_HYBRID_KF2K2MP2_CART = &device_creator; + +neogeo_bootleg_hybrid_kf2k2mp2_cart::neogeo_bootleg_hybrid_kf2k2mp2_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : neogeo_bootleg_hybrid_hybrid_cart(mconfig, NEOGEO_BOOTLEG_HYBRID_KF2K2MP2_CART, "NEOGEO BOOT kf2k2mp2 Cart", tag, owner, clock, "boot_kf2k2mp2_cart", __FILE__) {} + +void neogeo_bootleg_hybrid_kf2k2mp2_cart::activate_cart(ACTIVATE_CART_PARAMS) +{ + m_banked_cart->install_banks(machine, maincpu, cpuregion, cpuregion_size); + +} + +void neogeo_bootleg_hybrid_kf2k2mp2_cart::decrypt_all(DECRYPT_ALL_PARAMS) +{ + m_bootleg_prot->kf2k2mp2_px_decrypt(cpuregion, cpuregion_size); + m_pcm2_prot->neo_pcm2_swap(ym_region, ym_region_size, 0); + m_cmc_prot->neogeo_cmc50_m1_decrypt(audiocrypt_region, audiocrypt_region_size, audiocpu_region, audio_region_size); + m_bootleg_prot->neogeo_bootleg_sx_decrypt(fix_region, fix_region_size,1); + m_cmc_prot->cmc50_neogeo_gfx_decrypt(spr_region, spr_region_size, fix_region, fix_region_size, KOF2002_GFX_KEY); +} + +/************************************************* + matrimbl +**************************************************/ + +const device_type NEOGEO_BOOTLEG_HYBRID_MATRIMBL_CART = &device_creator; + +neogeo_bootleg_hybrid_matrimbl_cart::neogeo_bootleg_hybrid_matrimbl_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : neogeo_bootleg_hybrid_hybrid_cart(mconfig, NEOGEO_BOOTLEG_HYBRID_MATRIMBL_CART, "NEOGEO BOOT matrimbl Cart", tag, owner, clock, "boot_matrimbl_cart", __FILE__) {} + +void neogeo_bootleg_hybrid_matrimbl_cart::activate_cart(ACTIVATE_CART_PARAMS) +{ + m_banked_cart->install_banks(machine, maincpu, cpuregion, cpuregion_size); + +} + +void neogeo_bootleg_hybrid_matrimbl_cart::decrypt_all(DECRYPT_ALL_PARAMS) +{ + m_kof2002_prot->matrim_decrypt_68k(cpuregion, cpuregion_size); + m_bootleg_prot->matrimbl_decrypt(spr_region, spr_region_size, audiocpu_region,audio_region_size); + m_cmc_prot->neogeo_sfix_decrypt(spr_region, spr_region_size, fix_region, fix_region_size); /* required for text layer */ +} + +/************************************************* + ms5plus +**************************************************/ + +const device_type NEOGEO_BOOTLEG_HYBRID_MS5PLUS_CART = &device_creator; + +neogeo_bootleg_hybrid_ms5plus_cart::neogeo_bootleg_hybrid_ms5plus_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : neogeo_bootleg_hybrid_hybrid_cart(mconfig, NEOGEO_BOOTLEG_HYBRID_MS5PLUS_CART, "NEOGEO BOOT ms5plus Cart", tag, owner, clock, "boot_ms5plus_cart", __FILE__) {} + +void neogeo_bootleg_hybrid_ms5plus_cart::activate_cart(ACTIVATE_CART_PARAMS) +{ + m_banked_cart->install_banks(machine, maincpu, cpuregion, cpuregion_size); + m_bootleg_prot->install_ms5plus_protection(maincpu,m_banked_cart); +} + +void neogeo_bootleg_hybrid_ms5plus_cart::decrypt_all(DECRYPT_ALL_PARAMS) +{ + m_cmc_prot->cmc50_neogeo_gfx_decrypt(spr_region, spr_region_size, fix_region, fix_region_size, MSLUG5_GFX_KEY); + m_pcm2_prot->neo_pcm2_swap(ym_region, ym_region_size, 2); + m_bootleg_prot->neogeo_bootleg_sx_decrypt(fix_region, fix_region_size,1); + m_cmc_prot->neogeo_cmc50_m1_decrypt(audiocrypt_region, audiocrypt_region_size, audiocpu_region,audio_region_size); +} + +/************************************************* + svcboot +**************************************************/ + +const device_type NEOGEO_BOOTLEG_HYBRID_SVCBOOT_CART = &device_creator; + +neogeo_bootleg_hybrid_svcboot_cart::neogeo_bootleg_hybrid_svcboot_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : neogeo_bootleg_hybrid_hybrid_cart(mconfig, NEOGEO_BOOTLEG_HYBRID_SVCBOOT_CART, "NEOGEO BOOT svcboot Cart", tag, owner, clock, "boot_svcboot_cart", __FILE__) {} + +void neogeo_bootleg_hybrid_svcboot_cart::activate_cart(ACTIVATE_CART_PARAMS) +{ + m_banked_cart->install_banks(machine, maincpu, cpuregion, cpuregion_size); + m_pvc_prot->install_pvc_protection(maincpu,m_banked_cart); +} + +void neogeo_bootleg_hybrid_svcboot_cart::decrypt_all(DECRYPT_ALL_PARAMS) +{ + m_bootleg_prot->svcboot_px_decrypt(cpuregion, cpuregion_size); + m_bootleg_prot->svcboot_cx_decrypt(spr_region, spr_region_size); +} + +/***/ + +const device_type NEOGEO_BOOTLEG_HYBRID_SVCSPLUS_CART = &device_creator; + +neogeo_bootleg_hybrid_svcsplus_cart::neogeo_bootleg_hybrid_svcsplus_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : neogeo_bootleg_hybrid_hybrid_cart(mconfig, NEOGEO_BOOTLEG_HYBRID_SVCSPLUS_CART, "NEOGEO BOOT svcsplus Cart", tag, owner, clock, "boot_svcsplus_cart", __FILE__) {} + +void neogeo_bootleg_hybrid_svcsplus_cart::activate_cart(ACTIVATE_CART_PARAMS) +{ + m_banked_cart->install_banks(machine, maincpu, cpuregion, cpuregion_size); + m_pvc_prot->install_pvc_protection(maincpu,m_banked_cart); + +} + +void neogeo_bootleg_hybrid_svcsplus_cart::decrypt_all(DECRYPT_ALL_PARAMS) +{ + m_bootleg_prot->svcsplus_px_decrypt(cpuregion, cpuregion_size); + m_bootleg_prot->neogeo_bootleg_sx_decrypt(fix_region, fix_region_size,2); + m_bootleg_prot->svcboot_cx_decrypt(spr_region, spr_region_size); + m_bootleg_prot->svcsplus_px_hack(cpuregion, cpuregion_size); +} + + +/************************************************* + kf2k3bl +**************************************************/ + +const device_type NEOGEO_BOOTLEG_HYBRID_KF2K3BL_CART = &device_creator; + +neogeo_bootleg_hybrid_kf2k3bl_cart::neogeo_bootleg_hybrid_kf2k3bl_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : neogeo_bootleg_hybrid_hybrid_cart(mconfig, NEOGEO_BOOTLEG_HYBRID_KF2K3BL_CART, "NEOGEO BOOT kf2k3bl Cart", tag, owner, clock, "boot_kf2k3bl_cart", __FILE__) {} + +void neogeo_bootleg_hybrid_kf2k3bl_cart::activate_cart(ACTIVATE_CART_PARAMS) +{ + m_banked_cart->install_banks(machine, maincpu, cpuregion, cpuregion_size); + m_bootleg_prot->kf2k3bl_install_protection(maincpu,m_banked_cart, cpuregion, cpuregion_size); + +} + +void neogeo_bootleg_hybrid_kf2k3bl_cart::decrypt_all(DECRYPT_ALL_PARAMS) +{ + m_cmc_prot->cmc50_neogeo_gfx_decrypt(spr_region, spr_region_size, fix_region, fix_region_size, KOF2003_GFX_KEY); + m_pcm2_prot->neo_pcm2_swap(ym_region, ym_region_size, 5); + m_bootleg_prot->neogeo_bootleg_sx_decrypt(fix_region, fix_region_size,1); + +} + +const device_type NEOGEO_BOOTLEG_HYBRID_KF2K3PL_CART = &device_creator; + +neogeo_bootleg_hybrid_kf2k3pl_cart::neogeo_bootleg_hybrid_kf2k3pl_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : neogeo_bootleg_hybrid_hybrid_cart(mconfig, NEOGEO_BOOTLEG_HYBRID_KF2K3PL_CART, "NEOGEO BOOT kf2k3pl Cart", tag, owner, clock, "boot_kf2k3pl_cart", __FILE__) {} + +void neogeo_bootleg_hybrid_kf2k3pl_cart::activate_cart(ACTIVATE_CART_PARAMS) +{ + m_banked_cart->install_banks(machine, maincpu, cpuregion, cpuregion_size); + m_bootleg_prot->kf2k3pl_install_protection(maincpu,m_banked_cart, cpuregion, cpuregion_size); +} + +void neogeo_bootleg_hybrid_kf2k3pl_cart::decrypt_all(DECRYPT_ALL_PARAMS) +{ + m_cmc_prot->cmc50_neogeo_gfx_decrypt(spr_region, spr_region_size, fix_region, fix_region_size, KOF2003_GFX_KEY); + m_pcm2_prot->neo_pcm2_swap(ym_region, ym_region_size, 5); + m_bootleg_prot->kf2k3pl_px_decrypt(cpuregion, cpuregion_size); + m_bootleg_prot->neogeo_bootleg_sx_decrypt(fix_region, fix_region_size,1); +} + + +const device_type NEOGEO_BOOTLEG_HYBRID_KF2K3UPL_CART = &device_creator; + +neogeo_bootleg_hybrid_kf2k3upl_cart::neogeo_bootleg_hybrid_kf2k3upl_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : neogeo_bootleg_hybrid_hybrid_cart(mconfig, NEOGEO_BOOTLEG_HYBRID_KF2K3UPL_CART, "NEOGEO BOOT kf2k3upl Cart", tag, owner, clock, "boot_kf2k3upl_cart", __FILE__) {} + +void neogeo_bootleg_hybrid_kf2k3upl_cart::activate_cart(ACTIVATE_CART_PARAMS) +{ + m_banked_cart->install_banks(machine, maincpu, cpuregion, cpuregion_size); + m_bootleg_prot->kf2k3bl_install_protection(maincpu,m_banked_cart, cpuregion, cpuregion_size); + +} + +void neogeo_bootleg_hybrid_kf2k3upl_cart::decrypt_all(DECRYPT_ALL_PARAMS) +{ + m_cmc_prot->cmc50_neogeo_gfx_decrypt(spr_region, spr_region_size, fix_region, fix_region_size, KOF2003_GFX_KEY); + m_pcm2_prot->neo_pcm2_swap(ym_region, ym_region_size, 5); + m_bootleg_prot->kf2k3upl_px_decrypt(cpuregion, cpuregion_size); + m_bootleg_prot->neogeo_bootleg_sx_decrypt(fix_region, fix_region_size,2); +} diff --git a/src/devices/bus/neogeo/bootleg_hybrid_cart.h b/src/devices/bus/neogeo/bootleg_hybrid_cart.h new file mode 100644 index 00000000000..ace1886e840 --- /dev/null +++ b/src/devices/bus/neogeo/bootleg_hybrid_cart.h @@ -0,0 +1,192 @@ +// license:BSD-3-Clause +// copyright-holders:S. Smith,David Haywood +#ifndef __NEOGEO_BOOTLEG_HYBRID_HYBRID_CART_H +#define __NEOGEO_BOOTLEG_HYBRID_HYBRID_CART_H + +#include "neogeo_slot.h" +#include "banked_cart.h" +#include "bootleg_prot.h" +#include "pcm2_prot.h" +#include "cmc_prot.h" +#include "kof2002_prot.h" +#include "pvc_prot.h" + +// ======================> neogeo_bootleg_hybrid_hybrid_cart + +class neogeo_bootleg_hybrid_hybrid_cart : public device_t, + public device_neogeo_cart_interface +{ +public: + // construction/destruction + neogeo_bootleg_hybrid_hybrid_cart(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT16 clock, const char *shortname, const char *source); + neogeo_bootleg_hybrid_hybrid_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT16 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual machine_config_constructor device_mconfig_additions() const; + + // reading and writing + virtual DECLARE_READ16_MEMBER(read_rom); + + virtual void activate_cart(ACTIVATE_CART_PARAMS) {} + virtual void decrypt_all(DECRYPT_ALL_PARAMS) {} + virtual int get_fixed_bank_type(void) { return 0; } + + required_device m_banked_cart; + required_device m_bootleg_prot; + required_device m_cmc_prot; + required_device m_pcm2_prot; + required_device m_kof2002_prot; + required_device m_pvc_prot; +}; + + + +// device type definition +extern const device_type NEOGEO_BOOTLEG_HYBRID_HYBRID_CART; + + + +/************************************************* + MSLUG3B6 +**************************************************/ + +class neogeo_bootleg_hybrid_mslug3b6_cart : public neogeo_bootleg_hybrid_hybrid_cart +{ +public: + neogeo_bootleg_hybrid_mslug3b6_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + void activate_cart(ACTIVATE_CART_PARAMS); + virtual void decrypt_all(DECRYPT_ALL_PARAMS); + virtual int get_fixed_bank_type(void) { return 0; } +}; +extern const device_type NEOGEO_BOOTLEG_HYBRID_MSLUG3B6_CART; + + +/************************************************* + KOF2002B +**************************************************/ + +class neogeo_bootleg_hybrid_kof2002b_cart : public neogeo_bootleg_hybrid_hybrid_cart +{ +public: + neogeo_bootleg_hybrid_kof2002b_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + void activate_cart(ACTIVATE_CART_PARAMS); + virtual void decrypt_all(DECRYPT_ALL_PARAMS); + virtual int get_fixed_bank_type(void) { return 0; } +}; +extern const device_type NEOGEO_BOOTLEG_HYBRID_KOF2002B_CART; + +class neogeo_bootleg_hybrid_kf2k2mp_cart : public neogeo_bootleg_hybrid_hybrid_cart +{ +public: + neogeo_bootleg_hybrid_kf2k2mp_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + void activate_cart(ACTIVATE_CART_PARAMS); + virtual void decrypt_all(DECRYPT_ALL_PARAMS); + virtual int get_fixed_bank_type(void) { return 0; } +}; +extern const device_type NEOGEO_BOOTLEG_HYBRID_KF2K2MP_CART; + +class neogeo_bootleg_hybrid_kf2k2mp2_cart : public neogeo_bootleg_hybrid_hybrid_cart +{ +public: + neogeo_bootleg_hybrid_kf2k2mp2_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + void activate_cart(ACTIVATE_CART_PARAMS); + virtual void decrypt_all(DECRYPT_ALL_PARAMS); + virtual int get_fixed_bank_type(void) { return 0; } +}; +extern const device_type NEOGEO_BOOTLEG_HYBRID_KF2K2MP2_CART; + + +/************************************************* + MATRIMBL +**************************************************/ + +class neogeo_bootleg_hybrid_matrimbl_cart : public neogeo_bootleg_hybrid_hybrid_cart +{ +public: + neogeo_bootleg_hybrid_matrimbl_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + void activate_cart(ACTIVATE_CART_PARAMS); + virtual void decrypt_all(DECRYPT_ALL_PARAMS); + virtual int get_fixed_bank_type(void) { return 2; } +}; +extern const device_type NEOGEO_BOOTLEG_HYBRID_MATRIMBL_CART; + +/************************************************* + MS5PLUS +**************************************************/ + +class neogeo_bootleg_hybrid_ms5plus_cart : public neogeo_bootleg_hybrid_hybrid_cart +{ +public: + neogeo_bootleg_hybrid_ms5plus_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + void activate_cart(ACTIVATE_CART_PARAMS); + virtual void decrypt_all(DECRYPT_ALL_PARAMS); + virtual int get_fixed_bank_type(void) { return 1; } +}; +extern const device_type NEOGEO_BOOTLEG_HYBRID_MS5PLUS_CART; + +/************************************************* + SVCBOOT +**************************************************/ + +class neogeo_bootleg_hybrid_svcboot_cart : public neogeo_bootleg_hybrid_hybrid_cart +{ +public: + neogeo_bootleg_hybrid_svcboot_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + void activate_cart(ACTIVATE_CART_PARAMS); + virtual void decrypt_all(DECRYPT_ALL_PARAMS); + virtual int get_fixed_bank_type(void) { return 0; } +}; +extern const device_type NEOGEO_BOOTLEG_HYBRID_SVCBOOT_CART; + +class neogeo_bootleg_hybrid_svcsplus_cart : public neogeo_bootleg_hybrid_hybrid_cart +{ +public: + neogeo_bootleg_hybrid_svcsplus_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + void activate_cart(ACTIVATE_CART_PARAMS); + virtual void decrypt_all(DECRYPT_ALL_PARAMS); + virtual int get_fixed_bank_type(void) { return 0; } +}; +extern const device_type NEOGEO_BOOTLEG_HYBRID_SVCSPLUS_CART; + + + +/************************************************* + KF2K3BL +**************************************************/ + +class neogeo_bootleg_hybrid_kf2k3bl_cart : public neogeo_bootleg_hybrid_hybrid_cart +{ +public: + neogeo_bootleg_hybrid_kf2k3bl_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + void activate_cart(ACTIVATE_CART_PARAMS); + virtual void decrypt_all(DECRYPT_ALL_PARAMS); + virtual int get_fixed_bank_type(void) { return 0; } +}; +extern const device_type NEOGEO_BOOTLEG_HYBRID_KF2K3BL_CART; + +class neogeo_bootleg_hybrid_kf2k3pl_cart : public neogeo_bootleg_hybrid_hybrid_cart +{ +public: + neogeo_bootleg_hybrid_kf2k3pl_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + void activate_cart(ACTIVATE_CART_PARAMS); + virtual void decrypt_all(DECRYPT_ALL_PARAMS); + virtual int get_fixed_bank_type(void) { return 0; } +}; +extern const device_type NEOGEO_BOOTLEG_HYBRID_KF2K3PL_CART; + + +class neogeo_bootleg_hybrid_kf2k3upl_cart : public neogeo_bootleg_hybrid_hybrid_cart +{ +public: + neogeo_bootleg_hybrid_kf2k3upl_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + void activate_cart(ACTIVATE_CART_PARAMS); + virtual void decrypt_all(DECRYPT_ALL_PARAMS); + virtual int get_fixed_bank_type(void) { return 0; } +}; +extern const device_type NEOGEO_BOOTLEG_HYBRID_KF2K3UPL_CART; + + + +#endif diff --git a/src/devices/bus/neogeo/bootleg_prot.c b/src/devices/bus/neogeo/bootleg_prot.c new file mode 100644 index 00000000000..aa5ad7da084 --- /dev/null +++ b/src/devices/bus/neogeo/bootleg_prot.c @@ -0,0 +1,1066 @@ +// license:BSD-3-Clause +// copyright-holders:S. Smith,David Haywood + +#include "emu.h" +#include "bootleg_prot.h" + + + +extern const device_type NGBOOTLEG_PROT = &device_creator; + + +ngbootleg_prot_device::ngbootleg_prot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, NGBOOTLEG_PROT, "NeoGeo Protection (Bootleg)", tag, owner, clock, "ngbootleg_prot", __FILE__) +{ +} + + +void ngbootleg_prot_device::device_start() +{ + memset(m_cartridge_ram, 0x00, 0x2000); + + save_item(NAME(m_cartridge_ram)); +} + +void ngbootleg_prot_device::device_reset() +{ +} + + + +/*************************************************************************** + + Neo-Geo hardware encryption and protection used on bootleg cartridges + + Many of the NeoGeo bootlegs use their own form of encryption and + protection, presumably to make them harder for other bootleggers to + copy. This encryption often involves non-trivial scrambling of the + program roms and the games are protected using an Altera chip which + provides some kind of rom overlay, patching parts of the code. + The graphics roms are usually scrambled in a different way to the + official SNK cartridges too. + +***************************************************************************/ + +#include "emu.h" +#include "includes/neogeo.h" + + +/* General Bootleg Functions - used by more than 1 game */ + + +void ngbootleg_prot_device::neogeo_bootleg_cx_decrypt(UINT8*sprrom, UINT32 sprrom_size) +{ + int i; + int cx_size = sprrom_size; + UINT8 *rom = sprrom; + dynamic_buffer buf( cx_size ); + + memcpy( &buf[0], rom, cx_size ); + + for( i = 0; i < cx_size / 0x40; i++ ){ + memcpy( &rom[ i * 0x40 ], &buf[ (i ^ 1) * 0x40 ], 0x40 ); + } +} + + +void ngbootleg_prot_device::neogeo_bootleg_sx_decrypt(UINT8* fixed, UINT32 fixed_size, int value ) +{ + int sx_size = fixed_size; + UINT8 *rom = fixed; + int i; + + if (value == 1) + { + dynamic_buffer buf( sx_size ); + memcpy( &buf[0], rom, sx_size ); + + for( i = 0; i < sx_size; i += 0x10 ) + { + memcpy( &rom[ i ], &buf[ i + 8 ], 8 ); + memcpy( &rom[ i + 8 ], &buf[ i ], 8 ); + } + } + else if (value == 2) + { + for( i = 0; i < sx_size; i++ ) + rom[ i ] = BITSWAP8( rom[ i ], 7, 6, 0, 4, 3, 2, 1, 5 ); + } +} + + + +/* The King of Fighters '97 Oroshi Plus 2003 (bootleg) */ + +void ngbootleg_prot_device::kof97oro_px_decode(UINT8* cpurom, UINT32 cpurom_size) +{ + int i; + std::vector tmp( 0x500000 ); + UINT16 *src = (UINT16*)cpurom; + + for (i = 0; i < 0x500000/2; i++) { + tmp[i] = src[i ^ 0x7ffef]; + } + + memcpy (src, &tmp[0], 0x500000); +} + + +/* The King of Fighters 10th Anniversary (The King of Fighters 2002 bootleg) */ + + +/* this uses RAM based tiles for the text layer, however the implementation + is incomplete, at the moment the S data is copied from the program rom on + start-up instead */ + +void ngbootleg_prot_device::kof10thBankswitch(address_space &space, UINT16 nBank) +{ + UINT32 bank = 0x100000 + ((nBank & 7) << 20); + if (bank >= 0x700000) + bank = 0x100000; + m_bankdev->neogeo_set_main_cpu_bank_address(bank); +} + +READ16_MEMBER( ngbootleg_prot_device::kof10th_RAMB_r ) +{ + return m_cartridge_ram[offset]; +} + +READ16_MEMBER(ngbootleg_prot_device::kof10th_RAM2_r) +{ +// printf("kof10th_RAM2_r\n"); + return m_cartridge_ram2[offset]; +} + +WRITE16_MEMBER( ngbootleg_prot_device::kof10th_custom_w ) +{ + if (!m_cartridge_ram[0xFFE]) { // Write to RAM bank A + //UINT16 *prom = (UINT16*)m_mainrom; + COMBINE_DATA(&m_cartridge_ram2[(0x00000/2) + (offset & 0xFFFF)]); + } else { // Write S data on-the-fly + UINT8 *srom = m_fixedrom; + srom[offset] = BITSWAP8(data,7,6,0,4,3,2,1,5); + } +} + +WRITE16_MEMBER( ngbootleg_prot_device::kof10th_bankswitch_w ) +{ + if (offset >= 0x5F000) { + if (offset == 0x5FFF8) { // Standard bankswitch + kof10thBankswitch(space, data); + } else if (offset == 0x5FFFC && m_cartridge_ram[0xFFC] != data) { // Special bankswitch + UINT8 *src = m_mainrom; + memcpy (src + 0x10000, src + ((data & 1) ? 0x810000 : 0x710000), 0xcffff); + } + COMBINE_DATA(&m_cartridge_ram[offset & 0xFFF]); + } +} + +void ngbootleg_prot_device::install_kof10th_protection (cpu_device* maincpu, neogeo_banked_cart_device* bankdev, UINT8* cpurom, UINT32 cpurom_size, UINT8* fixedrom, UINT32 fixedrom_size) +{ + m_mainrom = cpurom; + m_fixedrom = fixedrom; + m_bankdev = bankdev; + + maincpu->space(AS_PROGRAM).install_read_handler(0x0e0000, 0x0fffff, read16_delegate(FUNC(ngbootleg_prot_device::kof10th_RAM2_r),this)); + + maincpu->space(AS_PROGRAM).install_read_handler(0x2fe000, 0x2fffff, read16_delegate(FUNC(ngbootleg_prot_device::kof10th_RAMB_r),this)); + maincpu->space(AS_PROGRAM).install_write_handler(0x200000, 0x23ffff, write16_delegate(FUNC(ngbootleg_prot_device::kof10th_custom_w),this)); + maincpu->space(AS_PROGRAM).install_write_handler(0x240000, 0x2fffff, write16_delegate(FUNC(ngbootleg_prot_device::kof10th_bankswitch_w),this)); + memcpy(m_cartridge_ram2, cpurom + 0xe0000, 0x20000); + +} + +void ngbootleg_prot_device::decrypt_kof10th(UINT8* cpurom, UINT32 cpurom_size) +{ + int i, j; + dynamic_buffer dst(0x900000); + UINT8 *src = cpurom; + + memcpy(&dst[0x000000], src + 0x700000, 0x100000); // Correct (Verified in Uni-bios) + memcpy(&dst[0x100000], src + 0x000000, 0x800000); + + for (i = 0; i < 0x900000; i++) { + j = BITSWAP24(i,23,22,21,20,19,18,17,16,15,14,13,12,11,2,9,8,7,1,5,4,3,10,6,0); + src[j] = dst[i]; + } + + // Altera protection chip patches these over P ROM + ((UINT16*)src)[0x0124/2] = 0x000d; // Enables XOR for RAM moves, forces SoftDIPs, and USA region + ((UINT16*)src)[0x0126/2] = 0xf7a8; + + ((UINT16*)src)[0x8bf4/2] = 0x4ef9; // Run code to change "S" data + ((UINT16*)src)[0x8bf6/2] = 0x000d; + ((UINT16*)src)[0x8bf8/2] = 0xf980; + +} + + +/* The King of Fighters 10th Anniversary Extra Plus (The King of Fighters 2002 bootleg) */ + + +void ngbootleg_prot_device::kf10thep_px_decrypt(UINT8* cpurom, UINT32 cpurom_size) +{ + UINT16 *rom = (UINT16*)cpurom; + std::vector buf(0x100000/2); + + memcpy(&buf[0x000000/2], &rom[0x060000/2], 0x20000); + memcpy(&buf[0x020000/2], &rom[0x100000/2], 0x20000); + memcpy(&buf[0x040000/2], &rom[0x0e0000/2], 0x20000); + memcpy(&buf[0x060000/2], &rom[0x180000/2], 0x20000); + memcpy(&buf[0x080000/2], &rom[0x020000/2], 0x20000); + memcpy(&buf[0x0a0000/2], &rom[0x140000/2], 0x20000); + memcpy(&buf[0x0c0000/2], &rom[0x0c0000/2], 0x20000); + memcpy(&buf[0x0e0000/2], &rom[0x1a0000/2], 0x20000); + memcpy(&buf[0x0002e0/2], &rom[0x0402e0/2], 0x6a); // copy banked code to a new memory region + memcpy(&buf[0x0f92bc/2], &rom[0x0492bc/2], 0xb9e); // copy banked code to a new memory region + memcpy(rom, &buf[0], 0x100000); + + for (int i = 0xf92bc/2; i < 0xf9e58/2; i++) + { + if (rom[i+0] == 0x4eb9 && rom[i+1] == 0x0000) rom[i+1] = 0x000F; // correct JSR in moved code + if (rom[i+0] == 0x4ef9 && rom[i+1] == 0x0000) rom[i+1] = 0x000F; // correct JMP in moved code + } + rom[0x00342/2] = 0x000f; + + memmove(&rom[0x100000/2], &rom[0x200000/2], 0x600000); +} + + +/* The King of Fighters 10th Anniversary 2005 Unique (The King of Fighters 2002 bootleg) */ + + +void ngbootleg_prot_device::kf2k5uni_px_decrypt(UINT8* cpurom, UINT32 cpurom_size) +{ + int i, j, ofst; + UINT8 *src = cpurom; + UINT8 dst[0x80]; + + for (i = 0; i < 0x800000; i+=0x80) + { + for (j = 0; j < 0x80; j+=2) + { + ofst = BITSWAP8(j, 0, 3, 4, 5, 6, 1, 2, 7); + memcpy(&dst[j], src + i + ofst, 2); + } + memcpy(src + i, &dst[0], 0x80); + } + + memcpy(src, src + 0x600000, 0x100000); // Seems to be the same as kof10th +} + +void ngbootleg_prot_device::kf2k5uni_sx_decrypt(UINT8* fixedrom, UINT32 fixedrom_size) +{ + int i; + UINT8 *srom = fixedrom; + + for (i = 0; i < 0x20000; i++) + srom[i] = BITSWAP8(srom[i], 4, 5, 6, 7, 0, 1, 2, 3); +} + +void ngbootleg_prot_device::kf2k5uni_mx_decrypt(UINT8* audiorom, UINT32 audiorom_size) +{ + int i; + UINT8 *mrom = audiorom; + + for (i = 0; i < 0x30000; i++) + mrom[i] = BITSWAP8(mrom[i], 4, 5, 6, 7, 0, 1, 2, 3); +} + +void ngbootleg_prot_device::decrypt_kf2k5uni(UINT8* cpurom, UINT32 cpurom_size, UINT8* audiorom, UINT32 audiorom_size, UINT8* fixedrom, UINT32 fixedrom_size) +{ + kf2k5uni_px_decrypt(cpurom, cpurom_size); + kf2k5uni_sx_decrypt(fixedrom, fixedrom_size); + kf2k5uni_mx_decrypt(audiorom, audiorom_size); +} + + +/* The King of Fighters 2002 (bootleg) */ + + +void ngbootleg_prot_device::kof2002b_gfx_decrypt(UINT8 *src, int size) +{ + int i, j; + static const UINT8 t[ 8 ][ 6 ] = + { + { 0, 8, 7, 6, 2, 1 }, + { 1, 0, 8, 7, 6, 2 }, + { 2, 1, 0, 8, 7, 6 }, + { 6, 2, 1, 0, 8, 7 }, + { 7, 6, 2, 1, 0, 8 }, + { 0, 1, 2, 6, 7, 8 }, + { 2, 1, 0, 6, 7, 8 }, + { 8, 0, 7, 6, 2, 1 }, + }; + + dynamic_buffer dst( 0x10000 ); + + for ( i = 0; i < size; i+=0x10000 ) + { + memcpy( &dst[0], src+i, 0x10000 ); + + for ( j = 0; j < 0x200; j++ ) + { + int n = (j & 0x38) >> 3; + int ofst = BITSWAP16(j, 15, 14, 13, 12, 11, 10, 9, t[n][0], t[n][1], t[n][2], 5, 4, 3, t[n][3], t[n][4], t[n][5]); + memcpy( src+i+ofst*128, &dst[j*128], 128 ); + } + } +} + + +/* The King of Fighters 2002 Magic Plus (bootleg) */ + + +void ngbootleg_prot_device::kf2k2mp_decrypt(UINT8* cpurom, UINT32 cpurom_size) +{ + int i,j; + + UINT8 *src = cpurom; + UINT8 dst[0x80]; + + memmove(src, src + 0x300000, 0x500000); + + for (i = 0; i < 0x800000; i+=0x80) + { + for (j = 0; j < 0x80 / 2; j++) + { + int ofst = BITSWAP8( j, 6, 7, 2, 3, 4, 5, 0, 1 ); + memcpy(dst + j * 2, src + i + ofst * 2, 2); + } + memcpy(src + i, dst, 0x80); + } +} + + +/* The King of Fighters 2002 Magic Plus II (bootleg) */ + + +void ngbootleg_prot_device::kf2k2mp2_px_decrypt(UINT8* cpurom, UINT32 cpurom_size) +{ + UINT8 *src = cpurom; + dynamic_buffer dst(0x600000); + + memcpy (&dst[0x000000], &src[0x1C0000], 0x040000); + memcpy (&dst[0x040000], &src[0x140000], 0x080000); + memcpy (&dst[0x0C0000], &src[0x100000], 0x040000); + memcpy (&dst[0x100000], &src[0x200000], 0x400000); + memcpy (&src[0x000000], &dst[0x000000], 0x600000); +} + + +/* Crouching Tiger Hidden Dragon 2003 (bootleg of King of Fighters 2001) */ + + +/* descrambling information from razoola */ +void ngbootleg_prot_device::cthd2003_neogeo_gfx_address_fix_do(UINT8* sprrom, UINT32 sprrom_size, int start, int end, int bit3shift, int bit2shift, int bit1shift, int bit0shift) +{ + int i,j; + int tilesize=128; + + dynamic_buffer rom(16*tilesize); // 16 tiles buffer + UINT8* realrom = sprrom + start*tilesize; + + for (i = 0; i < (end-start)/16; i++) { + for (j = 0; j < 16; j++) { + int offset = (((j&1)>>0)<>1)<>2)<>3)<neogeo_set_main_cpu_bank_address(bankaddress); + } +} + +void ngbootleg_prot_device::patch_cthd2003(cpu_device* maincpu, neogeo_banked_cart_device* bankdev, UINT8* cpurom, UINT32 cpurom_size) +{ + /* patches thanks to razoola */ + int i; + UINT16 *mem16 = (UINT16 *)cpurom; + + /* special ROM banking handler */ + maincpu->space(AS_PROGRAM).install_write_handler(0x2ffff0, 0x2fffff, write16_delegate(FUNC(ngbootleg_prot_device::cthd2003_bankswitch_w),this)); + m_bankdev = bankdev; + + // theres still a problem on the character select screen but it seems to be related to cpu core timing issues, + // overclocking the 68k prevents it. + + // fix garbage on s1 layer over everything + mem16[0xf415a/2] = 0x4ef9; + mem16[0xf415c/2] = 0x000f; + mem16[0xf415e/2] = 0x4cf2; + // Fix corruption in attract mode before title screen + for (i=0x1ae290/2;i < 0x1ae8d0/2; i=i+1) + { + mem16[i] = 0x0000; + } + + // Fix for title page + for (i=0x1f8ef0/2;i < 0x1fa1f0/2; i=i+2) + { + mem16[i] -= 0x7000; + mem16[i+1] -= 0x0010; + } + + // Fix for green dots on title page + for (i=0xac500/2;i < 0xac520/2; i=i+1) + { + mem16[i] = 0xFFFF; + } + // Fix for blanks as screen change level end clear + mem16[0x991d0/2] = 0xdd03; + mem16[0x99306/2] = 0xdd03; + mem16[0x99354/2] = 0xdd03; + mem16[0x9943e/2] = 0xdd03; +} + + +/* Crouching Tiger Hidden Dragon 2003 Super Plus (bootleg of King of Fighters 2001) */ + + +void ngbootleg_prot_device::ct2k3sp_sx_decrypt( UINT8* fixedrom, UINT32 fixedrom_size ) +{ + int rom_size = fixedrom_size; + UINT8 *rom = fixedrom; + dynamic_buffer buf( rom_size ); + int i; + int ofst; + + memcpy( &buf[0], rom, rom_size ); + + for( i = 0; i < rom_size; i++ ){ + ofst = BITSWAP24( (i & 0x1ffff), 23, 22, 21, 20, 19, 18, 17, 3, + 0, 1, 4, 2, 13, 14, 16, 15, + 5, 6, 11, 10, 9, 8, 7, 12 ); + + ofst += (i >> 17) << 17; + + rom[ i ] = buf[ ofst ]; + } + + memcpy( &buf[0], rom, rom_size ); + + memcpy( &rom[ 0x08000 ], &buf[ 0x10000 ], 0x8000 ); + memcpy( &rom[ 0x10000 ], &buf[ 0x08000 ], 0x8000 ); + memcpy( &rom[ 0x28000 ], &buf[ 0x30000 ], 0x8000 ); + memcpy( &rom[ 0x30000 ], &buf[ 0x28000 ], 0x8000 ); +} + +void ngbootleg_prot_device::decrypt_ct2k3sp(UINT8* sprrom, UINT32 sprrom_size, UINT8* audiorom, UINT32 audiorom_size, UINT8* fixedrom, UINT32 fixedrom_size) +{ + UINT8 *romdata = audiorom+0x10000; + dynamic_buffer tmp(8*128*128); + memcpy(&tmp[8*0*128], romdata+8*0*128, 8*32*128); + memcpy(&tmp[8*32*128], romdata+8*64*128, 8*32*128); + memcpy(&tmp[8*64*128], romdata+8*32*128, 8*32*128); + memcpy(&tmp[8*96*128], romdata+8*96*128, 8*32*128); + memcpy(romdata, &tmp[0], 8*128*128); + + memcpy(romdata-0x10000,romdata,0x10000); + ct2k3sp_sx_decrypt(fixedrom, fixedrom_size); + cthd2003_c(sprrom,sprrom_size,0); +} + + +/* Crouching Tiger Hidden Dragon 2003 Super Plus alternate (bootleg of King of Fighters 2001) */ + + +void ngbootleg_prot_device::decrypt_ct2k3sa(UINT8* sprrom, UINT32 sprrom_size, UINT8* audiorom, UINT32 audiorom_size ) +{ + UINT8 *romdata = audiorom+0x10000; + dynamic_buffer tmp(8*128*128); + memcpy(&tmp[8*0*128], romdata+8*0*128, 8*32*128); + memcpy(&tmp[8*32*128], romdata+8*64*128, 8*32*128); + memcpy(&tmp[8*64*128], romdata+8*32*128, 8*32*128); + memcpy(&tmp[8*96*128], romdata+8*96*128, 8*32*128); + memcpy(romdata, &tmp[0], 8*128*128); + + memcpy(romdata-0x10000,romdata,0x10000); + cthd2003_c(sprrom,sprrom_size, 0); +} + +void ngbootleg_prot_device::patch_ct2k3sa(UINT8* cpurom, UINT32 cpurom_size) +{ + /* patches thanks to razoola - same as for cthd2003*/ + int i; + UINT16 *mem16 = (UINT16 *)cpurom; + + // theres still a problem on the character select screen but it seems to be related to cpu core timing issues, + // overclocking the 68k prevents it. + + // fix garbage on s1 layer over everything + mem16[0xf415a/2] = 0x4ef9; + mem16[0xf415c/2] = 0x000f; + mem16[0xf415e/2] = 0x4cf2; + + // Fix corruption in attract mode before title screen + for (i=0x1ae290/2;i < 0x1ae8d0/2; i=i+1) + { + mem16[i] = 0x0000; + } + + // Fix for title page + for (i=0x1f8ef0/2;i < 0x1fa1f0/2; i=i+2) + { + mem16[i] -= 0x7000; + mem16[i+1] -= 0x0010; + } + + // Fix for green dots on title page + for (i=0xac500/2;i < 0xac520/2; i=i+1) + { + mem16[i] = 0xFFFF; + } + // Fix for blanks as screen change level end clear + mem16[0x991d0/2] = 0xdd03; + mem16[0x99306/2] = 0xdd03; + mem16[0x99354/2] = 0xdd03; + mem16[0x9943e/2] = 0xdd03; +} + + +/* King of Fighters Special Edition 2004 (bootleg of King of Fighters 2002) */ + + +void ngbootleg_prot_device::decrypt_kof2k4se_68k(UINT8* cpurom, UINT32 cpurom_size) +{ + UINT8 *src = cpurom+0x100000; + dynamic_buffer dst(0x400000); + int i; + static const int sec[] = {0x300000,0x200000,0x100000,0x000000}; + memcpy(&dst[0],src,0x400000); + + for(i = 0; i < 4; ++i) + { + memcpy(src+i*0x100000,&dst[sec[i]],0x100000); + } +} + + +/* Lansquenet 2004 (Shock Troopers - 2nd Squad bootleg) */ + + +void ngbootleg_prot_device::lans2004_vx_decrypt(UINT8* ymsndrom, UINT32 ymsndrom_size) +{ + int i; + UINT8 *rom = ymsndrom; + for (i = 0; i < 0xA00000; i++) + rom[i] = BITSWAP8(rom[i], 0, 1, 5, 4, 3, 2, 6, 7); +} + +void ngbootleg_prot_device::lans2004_decrypt_68k(UINT8* cpurom, UINT32 cpurom_size) +{ + /* Descrambling P ROMs - Thanks to Razoola for the info */ + int i; + UINT8 *src = cpurom; + UINT16 *rom = (UINT16*)cpurom; + + { + static const int sec[] = { 0x3, 0x8, 0x7, 0xC, 0x1, 0xA, 0x6, 0xD }; + dynamic_buffer dst(0x600000); + + for (i = 0; i < 8; i++) + memcpy (&dst[i * 0x20000], src + sec[i] * 0x20000, 0x20000); + + memcpy (&dst[0x0BBB00], src + 0x045B00, 0x001710); + memcpy (&dst[0x02FFF0], src + 0x1A92BE, 0x000010); + memcpy (&dst[0x100000], src + 0x200000, 0x400000); + memcpy (src, &dst[0], 0x600000); + } + + for (i = 0xBBB00/2; i < 0xBE000/2; i++) { + if ((((rom[i]&0xFFBF)==0x4EB9) || ((rom[i]&0xFFBF)==0x43B9)) && (rom[i+1]==0x0000)) { + rom[i + 1] = 0x000B; + rom[i + 2] += 0x6000; + } + } + + /* Patched by protection chip (Altera) ? */ + rom[0x2D15C/2] = 0x000B; + rom[0x2D15E/2] = 0xBB00; + rom[0x2D1E4/2] = 0x6002; + rom[0x2EA7E/2] = 0x6002; + rom[0xBBCD0/2] = 0x6002; + rom[0xBBDF2/2] = 0x6002; + rom[0xBBE42/2] = 0x6002; +} + + +/* Metal Slug 5 Plus (bootleg) */ + + +READ16_MEMBER( ngbootleg_prot_device::mslug5_prot_r ) +{ + logerror("PC %06x: access protected\n",space.device().safe_pc()); + return 0xa0; +} + +WRITE16_MEMBER( ngbootleg_prot_device::ms5plus_bankswitch_w ) +{ + int bankaddress; + logerror("offset: %06x PC %06x: set banking %04x\n",offset,space.device().safe_pc(),data); + if ((offset == 0)&&(data == 0xa0)) + { + bankaddress=0xa0; + m_bankdev->neogeo_set_main_cpu_bank_address(bankaddress); + logerror("offset: %06x PC %06x: set banking %04x\n\n",offset,space.device().safe_pc(),bankaddress); + } + else if(offset == 2) + { + data=data>>4; + //data=data&7; + bankaddress=data*0x100000; + m_bankdev->neogeo_set_main_cpu_bank_address(bankaddress); + logerror("offset: %06x PC %06x: set banking %04x\n\n",offset,space.device().safe_pc(),bankaddress); + } +} + +void ngbootleg_prot_device::install_ms5plus_protection(cpu_device* maincpu, neogeo_banked_cart_device* bankdev) +{ + // special ROM banking handler / additional protection + maincpu->space(AS_PROGRAM).install_readwrite_handler(0x2ffff0, 0x2fffff,read16_delegate(FUNC(ngbootleg_prot_device::mslug5_prot_r),this), write16_delegate(FUNC(ngbootleg_prot_device::ms5plus_bankswitch_w),this)); + m_bankdev = bankdev; + +} + + +/* SNK vs. CAPCOM SVC CHAOS (bootleg) */ + + +void ngbootleg_prot_device::svcboot_px_decrypt(UINT8* cpurom, UINT32 cpurom_size) +{ + static const UINT8 sec[] = { + 0x06, 0x07, 0x01, 0x02, 0x03, 0x04, 0x05, 0x00 + }; + int i; + int size = cpurom_size; + UINT8 *src = cpurom; + dynamic_buffer dst( size ); + int ofst; + for( i = 0; i < size / 0x100000; i++ ){ + memcpy( &dst[ i * 0x100000 ], &src[ sec[ i ] * 0x100000 ], 0x100000 ); + } + for( i = 0; i < size / 2; i++ ){ + ofst = BITSWAP8( (i & 0x0000ff), 7, 6, 1, 0, 3, 2, 5, 4 ); + ofst += (i & 0xffff00); + memcpy( &src[ i * 2 ], &dst[ ofst * 2 ], 0x02 ); + } +} + +void ngbootleg_prot_device::svcboot_cx_decrypt(UINT8*sprrom, UINT32 sprrom_size) +{ + static const UINT8 idx_tbl[ 0x10 ] = { + 0, 1, 0, 1, 2, 3, 2, 3, 3, 4, 3, 4, 4, 5, 4, 5, + }; + static const UINT8 bitswap4_tbl[ 6 ][ 4 ] = { + { 3, 0, 1, 2 }, + { 2, 3, 0, 1 }, + { 1, 2, 3, 0 }, + { 0, 1, 2, 3 }, + { 3, 2, 1, 0 }, + { 3, 0, 2, 1 }, + }; + int i; + int size = sprrom_size; + UINT8 *src = sprrom; + dynamic_buffer dst( size ); + int ofst; + memcpy( &dst[0], src, size ); + for( i = 0; i < size / 0x80; i++ ){ + int idx = idx_tbl[ (i & 0xf00) >> 8 ]; + int bit0 = bitswap4_tbl[ idx ][ 0 ]; + int bit1 = bitswap4_tbl[ idx ][ 1 ]; + int bit2 = bitswap4_tbl[ idx ][ 2 ]; + int bit3 = bitswap4_tbl[ idx ][ 3 ]; + ofst = BITSWAP8( (i & 0x0000ff), 7, 6, 5, 4, bit3, bit2, bit1, bit0 ); + ofst += (i & 0xfffff00); + memcpy( &src[ i * 0x80 ], &dst[ ofst * 0x80 ], 0x80 ); + } +} + + +/* SNK vs. CAPCOM SVC CHAOS Plus (bootleg set 1) */ + + +void ngbootleg_prot_device::svcplus_px_decrypt(UINT8* cpurom, UINT32 cpurom_size) +{ + static const int sec[] = { + 0x00, 0x03, 0x02, 0x05, 0x04, 0x01 + }; + int size = cpurom_size; + UINT8 *src = cpurom; + dynamic_buffer dst( size ); + int i; + int ofst; + memcpy( &dst[0], src, size ); + for( i = 0; i < size / 2; i++ ){ + ofst = BITSWAP24( (i & 0xfffff), 0x17, 0x16, 0x15, 0x14, 0x13, 0x00, 0x01, 0x02, + 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, + 0x07, 0x06, 0x05, 0x04, 0x03, 0x10, 0x11, 0x12 ); + ofst ^= 0x0f0007; + ofst += (i & 0xff00000); + memcpy( &src[ i * 0x02 ], &dst[ ofst * 0x02 ], 0x02 ); + } + memcpy( &dst[0], src, size ); + for( i = 0; i < 6; i++ ){ + memcpy( &src[ i * 0x100000 ], &dst[ sec[ i ] * 0x100000 ], 0x100000 ); + } +} + +void ngbootleg_prot_device::svcplus_px_hack(UINT8* cpurom, UINT32 cpurom_size) +{ + /* patched by the protection chip? */ + UINT16 *mem16 = (UINT16 *)cpurom; + mem16[0x0f8016/2] = 0x33c1; +} + + +/* SNK vs. CAPCOM SVC CHAOS Plus (bootleg set 2) */ + + +void ngbootleg_prot_device::svcplusa_px_decrypt(UINT8* cpurom, UINT32 cpurom_size) +{ + int i; + static const int sec[] = { + 0x01, 0x02, 0x03, 0x04, 0x05, 0x00 + }; + int size = cpurom_size; + UINT8 *src = cpurom; + dynamic_buffer dst( size ); + memcpy( &dst[0], src, size ); + for( i = 0; i < 6; i++ ){ + memcpy( &src[ i * 0x100000 ], &dst[ sec[ i ] * 0x100000 ], 0x100000 ); + } +} + + +/* SNK vs. CAPCOM SVC CHAOS Super Plus (bootleg) */ + + +void ngbootleg_prot_device::svcsplus_px_decrypt(UINT8* cpurom, UINT32 cpurom_size) +{ + static const int sec[] = { + 0x06, 0x07, 0x01, 0x02, 0x03, 0x04, 0x05, 0x00 + }; + int size = cpurom_size; + UINT8 *src = cpurom; + dynamic_buffer dst( size ); + int i; + int ofst; + memcpy( &dst[0], src, size ); + for( i = 0; i < size / 2; i++ ){ + ofst = BITSWAP16( (i & 0x007fff), 0x0f, 0x00, 0x08, 0x09, 0x0b, 0x0a, 0x0c, 0x0d, + 0x04, 0x03, 0x01, 0x07, 0x06, 0x02, 0x05, 0x0e ); + + ofst += (i & 0x078000); + ofst += sec[ (i & 0xf80000) >> 19 ] << 19; + memcpy( &src[ i * 2 ], &dst[ ofst * 2 ], 0x02 ); + } +} + +void ngbootleg_prot_device::svcsplus_px_hack(UINT8* cpurom, UINT32 cpurom_size) +{ + /* patched by the protection chip? */ + UINT16 *mem16 = (UINT16 *)cpurom; + mem16[0x9e90/2] = 0x000f; + mem16[0x9e92/2] = 0xc9c0; + mem16[0xa10c/2] = 0x4eb9; + mem16[0xa10e/2] = 0x000e; + mem16[0xa110/2] = 0x9750; +} + + +/* The King of Fighters 2003 (bootleg set 1) */ + + +READ16_MEMBER( ngbootleg_prot_device::kof2003_r) +{ + return m_cartridge_ram[offset]; +} + +READ16_MEMBER(ngbootleg_prot_device::kof2003_overlay_r) // hack? +{ + return kof2k3_overlay; +} + +WRITE16_MEMBER( ngbootleg_prot_device::kof2003_w ) +{ + data = COMBINE_DATA(&m_cartridge_ram[offset]); + if (offset == 0x1ff0/2 || offset == 0x1ff2/2) { + UINT8* cr = (UINT8 *)m_cartridge_ram; + UINT32 address = (cr[BYTE_XOR_LE(0x1ff3)]<<16)|(cr[BYTE_XOR_LE(0x1ff2)]<<8)|cr[BYTE_XOR_LE(0x1ff1)]; + UINT8 prt = cr[BYTE_XOR_LE(0x1ff2)]; + + cr[BYTE_XOR_LE(0x1ff0)] = 0xa0; + cr[BYTE_XOR_LE(0x1ff1)] &= 0xfe; + cr[BYTE_XOR_LE(0x1ff3)] &= 0x7f; + m_bankdev->neogeo_set_main_cpu_bank_address(address+0x100000); + + kof2k3_overlay = (prt & 0x00ff) | (kof2k3_overlay & 0xff00); + } +} + +WRITE16_MEMBER( ngbootleg_prot_device::kof2003p_w ) +{ + data = COMBINE_DATA(&m_cartridge_ram[offset]); + if (offset == 0x1ff0/2 || offset == 0x1ff2/2) { + UINT8* cr = (UINT8 *)m_cartridge_ram; + UINT32 address = (cr[BYTE_XOR_LE(0x1ff3)]<<16)|(cr[BYTE_XOR_LE(0x1ff2)]<<8)|cr[BYTE_XOR_LE(0x1ff0)]; + UINT8 prt = cr[BYTE_XOR_LE(0x1ff2)]; + + cr[BYTE_XOR_LE(0x1ff0)] &= 0xfe; + cr[BYTE_XOR_LE(0x1ff3)] &= 0x7f; + m_bankdev->neogeo_set_main_cpu_bank_address(address+0x100000); + + kof2k3_overlay = (prt & 0x00ff) | (kof2k3_overlay & 0xff00); + } +} + +void ngbootleg_prot_device::kf2k3bl_px_decrypt(UINT8* cpurom, UINT32 cpurom_size) +{ + int i; + static const UINT8 sec[] = { + 0x07, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 + }; + + int rom_size = 0x800000; + UINT8 *rom = cpurom; + dynamic_buffer buf( rom_size ); + memcpy( &buf[0], rom, rom_size ); + + for( i = 0; i < rom_size / 0x100000; i++ ){ + memcpy( &rom[ i * 0x100000 ], &buf[ sec[ i ] * 0x100000 ], 0x100000 ); + } +} + +void ngbootleg_prot_device::kf2k3bl_install_protection(cpu_device* maincpu, neogeo_banked_cart_device* bankdev, UINT8* cpurom, UINT32 cpurom_size) +{ + m_mainrom = cpurom; + + maincpu->space(AS_PROGRAM).install_read_handler(0x58196, 0x58197, read16_delegate(FUNC(ngbootleg_prot_device::kof2003_overlay_r),this) ); + + maincpu->space(AS_PROGRAM).install_readwrite_handler(0x2fe000, 0x2fffff, read16_delegate(FUNC(ngbootleg_prot_device::kof2003_r),this), write16_delegate(FUNC(ngbootleg_prot_device::kof2003_w),this) ); + m_bankdev = bankdev; + +} + + +/* The King of Fighters 2004 Plus / Hero (The King of Fighters 2003 bootleg) */ + + +void ngbootleg_prot_device::kf2k3pl_px_decrypt(UINT8* cpurom, UINT32 cpurom_size) +{ + std::vector tmp(0x100000/2); + UINT16*rom16 = (UINT16*)cpurom; + int j; + int i; + + for (i = 0;i < 0x700000/2;i+=0x100000/2) + { + memcpy(&tmp[0],&rom16[i],0x100000); + for (j = 0;j < 0x100000/2;j++) + rom16[i+j] = tmp[BITSWAP24(j,23,22,21,20,19,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18)]; + } + + /* patched by Altera protection chip on PCB */ + rom16[0xf38ac/2] = 0x4e75; + + kof2k3_overlay = rom16[0x58196 / 2]; +} + +void ngbootleg_prot_device::kf2k3pl_install_protection(cpu_device* maincpu, neogeo_banked_cart_device* bankdev, UINT8* cpurom, UINT32 cpurom_size) +{ + m_mainrom = cpurom; + maincpu->space(AS_PROGRAM).install_readwrite_handler(0x2fe000, 0x2fffff, read16_delegate(FUNC(ngbootleg_prot_device::kof2003_r),this), write16_delegate(FUNC(ngbootleg_prot_device::kof2003p_w),this) ); + m_bankdev = bankdev; +} + + +/* The King of Fighters 2004 Ultra Plus (The King of Fighters 2003 bootleg) */ + + +void ngbootleg_prot_device::kf2k3upl_px_decrypt(UINT8* cpurom, UINT32 cpurom_size) +{ + { + UINT8 *src = cpurom; + memmove(src+0x100000, src, 0x600000); + memmove(src, src+0x700000, 0x100000); + } + + { + int ofst; + int i; + UINT8 *rom = cpurom + 0xfe000; + UINT8 *buf = cpurom + 0xd0610; + + for( i = 0; i < 0x2000 / 2; i++ ){ + ofst = (i & 0xff00) + BITSWAP8( (i & 0x00ff), 7, 6, 0, 4, 3, 2, 1, 5 ); + memcpy( &rom[ i * 2 ], &buf[ ofst * 2 ], 2 ); + } + } + + UINT16*rom16 = (UINT16*)cpurom; + kof2k3_overlay = rom16[0x58196 / 2]; + + +} + + +/* Samurai Shodown V / Samurai Spirits Zero (bootleg) */ + + +void ngbootleg_prot_device::samsho5b_px_decrypt(UINT8* cpurom, UINT32 cpurom_size) +{ + int px_size = cpurom_size; + UINT8 *rom = cpurom; + dynamic_buffer buf( px_size ); + int ofst; + int i; + + memcpy( &buf[0], rom, px_size ); + + for( i = 0; i < px_size / 2; i++ ){ + ofst = BITSWAP8( (i & 0x000ff), 7, 6, 5, 4, 3, 0, 1, 2 ); + ofst += (i & 0xfffff00); + ofst ^= 0x060005; + + memcpy( &rom[ i * 2 ], &buf[ ofst * 2 ], 0x02 ); + } + + memcpy( &buf[0], rom, px_size ); + + memcpy( &rom[ 0x000000 ], &buf[ 0x700000 ], 0x100000 ); + memcpy( &rom[ 0x100000 ], &buf[ 0x000000 ], 0x700000 ); +} + + +void ngbootleg_prot_device::samsho5b_vx_decrypt(UINT8* ymsndrom, UINT32 ymsndrom_size) +{ + int vx_size = ymsndrom_size; + UINT8 *rom = ymsndrom; + int i; + + for( i = 0; i < vx_size; i++ ) + rom[ i ] = BITSWAP8( rom[ i ], 0, 1, 5, 4, 3, 2, 6, 7 ); +} + + +/* Matrimelee / Shin Gouketsuji Ichizoku Toukon (bootleg) */ + + +#define MATRIMBLZ80( i ) ( i^(BITSWAP8(i&0x3,4,3,1,2,0,7,6,5)<<8) ) + +void ngbootleg_prot_device::matrimbl_decrypt(UINT8* sprrom, UINT32 sprrom_size, UINT8* audiorom, UINT32 audiorom_size) +{ + /* decrypt Z80 */ + UINT8 *rom = audiorom+0x10000; + dynamic_buffer buf( 0x20000 ); + int i, j=0; + memcpy( &buf[0], rom, 0x20000 ); + for( i=0x00000; i<0x20000; i++ ) + { + if ( i&0x10000 ) + { + if ( i&0x800 ) + { + j=MATRIMBLZ80( i ); + j=j^0x10000; + } + else + { + j=MATRIMBLZ80(( i^0x01 )); + } + } + else + { + if ( i&0x800 ) + { + j=MATRIMBLZ80(( i^0x01 )); + j=j^0x10000; + } + else + { + j=MATRIMBLZ80( i ); + } + } + rom[ j ]=buf[ i ]; + } + memcpy( rom-0x10000, rom, 0x10000 ); + + /* decrypt gfx */ + cthd2003_c(sprrom,sprrom_size, 0 ); +} diff --git a/src/devices/bus/neogeo/bootleg_prot.h b/src/devices/bus/neogeo/bootleg_prot.h new file mode 100644 index 00000000000..6ad1f257845 --- /dev/null +++ b/src/devices/bus/neogeo/bootleg_prot.h @@ -0,0 +1,98 @@ +// license:BSD-3-Clause +// copyright-holders:S. Smith,David Haywood + +#pragma once + +#include "banked_cart.h" + +#ifndef __NGBOOTLEG_PROT__ +#define __NGBOOTLEG_PROT__ + +extern const device_type NGBOOTLEG_PROT; + +#define MCFG_NGBOOTLEG_PROT_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, NGBOOTLEG_PROT, 0) + + +class ngbootleg_prot_device : public device_t +{ +public: + // construction/destruction + ngbootleg_prot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + void neogeo_bootleg_cx_decrypt(UINT8*sprrom, UINT32 sprrom_size); + void neogeo_bootleg_sx_decrypt(UINT8* fixed, UINT32 fixed_size, int value); + void kof97oro_px_decode(UINT8* cpurom, UINT32 cpurom_size); + void kof10thBankswitch(address_space &space, UINT16 nBank); + DECLARE_READ16_MEMBER(kof10th_RAM2_r); + DECLARE_READ16_MEMBER(kof10th_RAMB_r); + DECLARE_WRITE16_MEMBER(kof10th_custom_w); + DECLARE_WRITE16_MEMBER(kof10th_bankswitch_w); + void install_kof10th_protection(cpu_device* maincpu, neogeo_banked_cart_device* bankdev, UINT8* cpurom, UINT32 cpurom_size, UINT8* fixedrom, UINT32 fixedrom_size); + void decrypt_kof10th(UINT8* cpurom, UINT32 cpurom_size); + void kf10thep_px_decrypt(UINT8* cpurom, UINT32 cpurom_size); + void kf2k5uni_px_decrypt(UINT8* cpurom, UINT32 cpurom_size); + void kf2k5uni_sx_decrypt(UINT8* fixedrom, UINT32 fixedrom_size); + void kf2k5uni_mx_decrypt(UINT8* audiorom, UINT32 audiorom_size); + void decrypt_kf2k5uni(UINT8* cpurom, UINT32 cpurom_size, UINT8* audiorom, UINT32 audiorom_size, UINT8* fixedrom, UINT32 fixedrom_size); + void kof2002b_gfx_decrypt(UINT8 *src, int size); + void kf2k2mp_decrypt(UINT8* cpurom, UINT32 cpurom_size); + void kf2k2mp2_px_decrypt(UINT8* cpurom, UINT32 cpurom_size); + void cthd2003_neogeo_gfx_address_fix_do(UINT8* sprrom, UINT32 sprrom_size, int start, int end, int bit3shift, int bit2shift, int bit1shift, int bit0shift); + void cthd2003_neogeo_gfx_address_fix(UINT8* sprrom, UINT32 sprrom_size, int start, int end); + void cthd2003_c(UINT8* sprrom, UINT32 sprrom_size, int pow); + void decrypt_cthd2003(UINT8* sprrom, UINT32 sprrom_size, UINT8* audiorom, UINT32 audiorom_size, UINT8* fixedrom, UINT32 fixedrom_size); + DECLARE_WRITE16_MEMBER(cthd2003_bankswitch_w); + void patch_cthd2003(cpu_device* maincpu, neogeo_banked_cart_device* bankdev, UINT8* cpurom, UINT32 cpurom_size); + void ct2k3sp_sx_decrypt(UINT8* fixedrom, UINT32 fixedrom_size); + void decrypt_ct2k3sp(UINT8* sprrom, UINT32 sprrom_size, UINT8* audiorom, UINT32 audiorom_size, UINT8* fixedrom, UINT32 fixedrom_size); + void decrypt_ct2k3sa(UINT8* sprrom, UINT32 sprrom_size, UINT8* audiorom, UINT32 audiorom_size); + void patch_ct2k3sa(UINT8* cpurom, UINT32 cpurom_size); + void decrypt_kof2k4se_68k(UINT8* cpurom, UINT32 cpurom_size); + void lans2004_vx_decrypt(UINT8* ymsndrom, UINT32 ymsndrom_size); + void lans2004_decrypt_68k(UINT8* cpurom, UINT32 cpurom_size); + DECLARE_READ16_MEMBER(mslug5_prot_r); + DECLARE_WRITE16_MEMBER(ms5plus_bankswitch_w); + void install_ms5plus_protection(cpu_device* maincpu, neogeo_banked_cart_device* bankdev); + void svcboot_px_decrypt(UINT8* cpurom, UINT32 cpurom_size); + void svcboot_cx_decrypt(UINT8*sprrom, UINT32 sprrom_size); + void svcplus_px_decrypt(UINT8* cpurom, UINT32 cpurom_size); + void svcplus_px_hack(UINT8* cpurom, UINT32 cpurom_size); + void svcplusa_px_decrypt(UINT8* cpurom, UINT32 cpurom_size); + void svcsplus_px_decrypt(UINT8* cpurom, UINT32 cpurom_size); + void svcsplus_px_hack(UINT8* cpurom, UINT32 cpurom_size); + DECLARE_READ16_MEMBER(kof2003_r); + DECLARE_WRITE16_MEMBER(kof2003_w); + DECLARE_WRITE16_MEMBER(kof2003p_w); + DECLARE_READ16_MEMBER(kof2003_overlay_r); + void kf2k3bl_px_decrypt(UINT8* cpurom, UINT32 cpurom_size); + void kf2k3bl_install_protection(cpu_device* maincpu, neogeo_banked_cart_device* bankdev, UINT8* cpurom, UINT32 cpurom_size); + void kf2k3pl_px_decrypt(UINT8* cpurom, UINT32 cpurom_size); + void kf2k3pl_install_protection(cpu_device* maincpu, neogeo_banked_cart_device* bankdev, UINT8* cpurom, UINT32 cpurom_size); + UINT16 kof2k3_overlay; + + void kf2k3upl_px_decrypt(UINT8* cpurom, UINT32 cpurom_size); + void samsho5b_px_decrypt(UINT8* cpurom, UINT32 cpurom_size); + void samsho5b_vx_decrypt(UINT8* ymsndrom, UINT32 ymsndrom_size); + void matrimbl_decrypt(UINT8* sprrom, UINT32 sprrom_size, UINT8* audiorom, UINT32 audiorom_size); + + UINT16 m_cartridge_ram[0x1000]; // bootlegs + + // for kof10th + UINT8* m_mainrom; + UINT8* m_fixedrom; + neogeo_banked_cart_device* m_bankdev; + UINT16 m_cartridge_ram2[0x10000]; + +protected: + virtual void device_start(); + virtual void device_reset(); + + + +private: + + +}; + +#endif diff --git a/src/devices/bus/neogeo/cmc_cart.c b/src/devices/bus/neogeo/cmc_cart.c new file mode 100644 index 00000000000..c528366b717 --- /dev/null +++ b/src/devices/bus/neogeo/cmc_cart.c @@ -0,0 +1,223 @@ +// license:BSD-3-Clause +// copyright-holders:S. Smith,David Haywood +/*********************************************************************************************************** + + NEOGEO ROM cart emulation + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "cmc_cart.h" + + +//------------------------------------------------- +// neogeo_cmc_cart - constructor +//------------------------------------------------- + +const device_type NEOGEO_CMC_CART = &device_creator; + + +neogeo_cmc_cart::neogeo_cmc_cart(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT16 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_neogeo_cart_interface(mconfig, *this), + m_banked_cart(*this, "banked_cart"), + m_cmc_prot(*this, "cmc_prot") + +{ +} + +neogeo_cmc_cart::neogeo_cmc_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT16 clock) + : device_t(mconfig, NEOGEO_CMC_CART, "NEOGEO SMA Cart", tag, owner, clock, "neogeo_rom", __FILE__), + device_neogeo_cart_interface(mconfig, *this), + m_banked_cart(*this, "banked_cart"), + m_cmc_prot(*this, "cmc_prot") +{ +} + + +//------------------------------------------------- +// mapper specific start/reset +//------------------------------------------------- + +void neogeo_cmc_cart::device_start() +{ +} + +void neogeo_cmc_cart::device_reset() +{ +} + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +READ16_MEMBER(neogeo_cmc_cart::read_rom) +{ + return m_rom[offset]; +} + +static MACHINE_CONFIG_FRAGMENT( cmc_cart ) + MCFG_NEOGEO_BANKED_CART_ADD("banked_cart") + MCFG_CMC_PROT_ADD("cmc_prot") +MACHINE_CONFIG_END + +machine_config_constructor neogeo_cmc_cart::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( cmc_cart ); +} + + + +/* Individual cartridge types (mirror DRIVER_INIT functionality) */ + +/************************************************* + Zupapa +**************************************************/ + +const device_type NEOGEO_CMC_ZUPAPA_CART = &device_creator; + +neogeo_cmc_zupapa_cart::neogeo_cmc_zupapa_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : neogeo_cmc_cart(mconfig, NEOGEO_CMC_ZUPAPA_CART, "NEOGEO CMC zupapa Cart", tag, owner, clock, "cmc_zupapa_cart", __FILE__) {} + +void neogeo_cmc_zupapa_cart::decrypt_all(DECRYPT_ALL_PARAMS) +{ + m_cmc_prot->kof99_neogeo_gfx_decrypt(spr_region, spr_region_size, fix_region, fix_region_size, ZUPAPA_GFX_KEY); +} + + +/************************************************* + Zupapa +**************************************************/ + +const device_type NEOGEO_CMC_MSLUG3H_CART = &device_creator; + +neogeo_cmc_mslug3h_cart::neogeo_cmc_mslug3h_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : neogeo_cmc_cart(mconfig, NEOGEO_CMC_MSLUG3H_CART, "NEOGEO CMC mslug3h Cart", tag, owner, clock, "cmc_mslug3h_cart", __FILE__) {} + +void neogeo_cmc_mslug3h_cart::decrypt_all(DECRYPT_ALL_PARAMS) +{ + m_cmc_prot->kof99_neogeo_gfx_decrypt(spr_region, spr_region_size, fix_region, fix_region_size, MSLUG3_GFX_KEY); +} + + +/************************************************* + Ganryu +**************************************************/ + +const device_type NEOGEO_CMC_GANRYU_CART = &device_creator; + +neogeo_cmc_ganryu_cart::neogeo_cmc_ganryu_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : neogeo_cmc_cart(mconfig, NEOGEO_CMC_GANRYU_CART, "NEOGEO CMC ganryu Cart", tag, owner, clock, "cmc_ganryu_cart", __FILE__) {} + +void neogeo_cmc_ganryu_cart::decrypt_all(DECRYPT_ALL_PARAMS) +{ + m_cmc_prot->kof99_neogeo_gfx_decrypt(spr_region, spr_region_size, fix_region, fix_region_size, GANRYU_GFX_KEY); +} + + +/************************************************* + S1945P +**************************************************/ + +const device_type NEOGEO_CMC_S1945P_CART = &device_creator; + +neogeo_cmc_s1945p_cart::neogeo_cmc_s1945p_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : neogeo_cmc_cart(mconfig, NEOGEO_CMC_S1945P_CART, "NEOGEO CMC s1945p Cart", tag, owner, clock, "cmc_s1945p_cart", __FILE__) {} + +void neogeo_cmc_s1945p_cart::decrypt_all(DECRYPT_ALL_PARAMS) +{ + m_cmc_prot->kof99_neogeo_gfx_decrypt(spr_region, spr_region_size, fix_region, fix_region_size, S1945P_GFX_KEY); +} + +/************************************************* + PREISLE2 +**************************************************/ + +const device_type NEOGEO_CMC_PREISLE2_CART = &device_creator; + +neogeo_cmc_preisle2_cart::neogeo_cmc_preisle2_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : neogeo_cmc_cart(mconfig, NEOGEO_CMC_PREISLE2_CART, "NEOGEO CMC preisle2 Cart", tag, owner, clock, "cmc_preisle2_cart", __FILE__) {} + +void neogeo_cmc_preisle2_cart::decrypt_all(DECRYPT_ALL_PARAMS) +{ + m_cmc_prot->kof99_neogeo_gfx_decrypt(spr_region, spr_region_size, fix_region, fix_region_size, PREISLE2_GFX_KEY); +} + +/************************************************* + BANGBEAD +**************************************************/ + +const device_type NEOGEO_CMC_BANGBEAD_CART = &device_creator; + +neogeo_cmc_bangbead_cart::neogeo_cmc_bangbead_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : neogeo_cmc_cart(mconfig, NEOGEO_CMC_BANGBEAD_CART, "NEOGEO CMC bangbead Cart", tag, owner, clock, "cmc_bangbead_cart", __FILE__) {} + +void neogeo_cmc_bangbead_cart::decrypt_all(DECRYPT_ALL_PARAMS) +{ + m_cmc_prot->kof99_neogeo_gfx_decrypt(spr_region, spr_region_size, fix_region, fix_region_size, BANGBEAD_GFX_KEY); +} + +/************************************************* + NITD +**************************************************/ + +const device_type NEOGEO_CMC_NITD_CART = &device_creator; + +neogeo_cmc_nitd_cart::neogeo_cmc_nitd_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : neogeo_cmc_cart(mconfig, NEOGEO_CMC_NITD_CART, "NEOGEO CMC nitd Cart", tag, owner, clock, "cmc_nitd_cart", __FILE__) {} + +void neogeo_cmc_nitd_cart::decrypt_all(DECRYPT_ALL_PARAMS) +{ + m_cmc_prot->kof99_neogeo_gfx_decrypt(spr_region, spr_region_size, fix_region, fix_region_size, NITD_GFX_KEY); +} + + +/************************************************* + SENGOKU3 +**************************************************/ + +const device_type NEOGEO_CMC_SENGOKU3_CART = &device_creator; + +neogeo_cmc_sengoku3_cart::neogeo_cmc_sengoku3_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : neogeo_cmc_cart(mconfig, NEOGEO_CMC_SENGOKU3_CART, "NEOGEO CMC sengoku3 Cart", tag, owner, clock, "cmc_sengoku3_cart", __FILE__) {} + +void neogeo_cmc_sengoku3_cart::decrypt_all(DECRYPT_ALL_PARAMS) +{ + m_cmc_prot->kof99_neogeo_gfx_decrypt(spr_region, spr_region_size, fix_region, fix_region_size, SENGOKU3_GFX_KEY); +} + +/************************************************* + KOF99K +**************************************************/ + +const device_type NEOGEO_CMC_KOF99K_CART = &device_creator; + +neogeo_cmc_kof99k_cart::neogeo_cmc_kof99k_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : neogeo_cmc_cart(mconfig, NEOGEO_CMC_KOF99K_CART, "NEOGEO CMC kof99k Cart", tag, owner, clock, "cmc_kof99k_cart", __FILE__) {} + +void neogeo_cmc_kof99k_cart::decrypt_all(DECRYPT_ALL_PARAMS) +{ + m_cmc_prot->kof99_neogeo_gfx_decrypt(spr_region, spr_region_size, fix_region, fix_region_size, KOF99_GFX_KEY); +} + + +/************************************************* + KOF2001 +**************************************************/ + +const device_type NEOGEO_CMC_KOF2001_CART = &device_creator; + +neogeo_cmc_kof2001_cart::neogeo_cmc_kof2001_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : neogeo_cmc_cart(mconfig, NEOGEO_CMC_KOF2001_CART, "NEOGEO CMC kof2001 Cart", tag, owner, clock, "cmc_kof2001_cart", __FILE__) {} + +void neogeo_cmc_kof2001_cart::decrypt_all(DECRYPT_ALL_PARAMS) +{ + m_cmc_prot->neogeo_cmc50_m1_decrypt(audiocrypt_region, audiocrypt_region_size, audiocpu_region, audio_region_size); + m_cmc_prot->kof2000_neogeo_gfx_decrypt(spr_region, spr_region_size, fix_region, fix_region_size, KOF2001_GFX_KEY); +} + +/************************************************* + KOF2000N +**************************************************/ + +const device_type NEOGEO_CMC_KOF2000N_CART = &device_creator; + +neogeo_cmc_kof2000n_cart::neogeo_cmc_kof2000n_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : neogeo_cmc_cart(mconfig, NEOGEO_CMC_KOF2000N_CART, "NEOGEO CMC kof2000n Cart", tag, owner, clock, "cmc_kof2000n_cart", __FILE__) {} + +void neogeo_cmc_kof2000n_cart::decrypt_all(DECRYPT_ALL_PARAMS) +{ + m_cmc_prot->neogeo_cmc50_m1_decrypt(audiocrypt_region, audiocrypt_region_size, audiocpu_region, audio_region_size); + m_cmc_prot->kof2000_neogeo_gfx_decrypt(spr_region, spr_region_size, fix_region, fix_region_size, KOF2000_GFX_KEY); +} diff --git a/src/devices/bus/neogeo/cmc_cart.h b/src/devices/bus/neogeo/cmc_cart.h new file mode 100644 index 00000000000..2e07e29c93f --- /dev/null +++ b/src/devices/bus/neogeo/cmc_cart.h @@ -0,0 +1,191 @@ +// license:BSD-3-Clause +// copyright-holders:S. Smith,David Haywood +#ifndef __NEOGEO_CMC_CART_H +#define __NEOGEO_CMC_CART_H + +#include "neogeo_slot.h" +#include "banked_cart.h" +#include "sma_prot.h" +#include "cmc_prot.h" + +// ======================> neogeo_cmc_cart + +class neogeo_cmc_cart : public device_t, + public device_neogeo_cart_interface +{ +public: + // construction/destruction + neogeo_cmc_cart(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT16 clock, const char *shortname, const char *source); + neogeo_cmc_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT16 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual machine_config_constructor device_mconfig_additions() const; + + // reading and writing + virtual DECLARE_READ16_MEMBER(read_rom); + + virtual void activate_cart(ACTIVATE_CART_PARAMS) { m_banked_cart->install_banks(machine, maincpu, cpuregion, cpuregion_size); } + virtual void decrypt_all(DECRYPT_ALL_PARAMS) {} + virtual int get_fixed_bank_type(void) { return 0; } + + required_device m_banked_cart; + required_device m_cmc_prot; +}; + + + +// device type definition +extern const device_type NEOGEO_CMC_CART; + + +/************************************************* + ZUPAPA +**************************************************/ + +class neogeo_cmc_zupapa_cart : public neogeo_cmc_cart +{ +public: + neogeo_cmc_zupapa_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual void decrypt_all(DECRYPT_ALL_PARAMS); + virtual int get_fixed_bank_type(void) { return 1; } +}; +extern const device_type NEOGEO_CMC_ZUPAPA_CART; + +/************************************************* + MSLUG3H +**************************************************/ + +class neogeo_cmc_mslug3h_cart : public neogeo_cmc_cart +{ +public: + neogeo_cmc_mslug3h_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual void decrypt_all(DECRYPT_ALL_PARAMS); + virtual int get_fixed_bank_type(void) { return 1; } +}; +extern const device_type NEOGEO_CMC_MSLUG3H_CART; + + +/************************************************* + GANRYU +**************************************************/ + +class neogeo_cmc_ganryu_cart : public neogeo_cmc_cart +{ +public: + neogeo_cmc_ganryu_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual void decrypt_all(DECRYPT_ALL_PARAMS); + virtual int get_fixed_bank_type(void) { return 1; } +}; +extern const device_type NEOGEO_CMC_GANRYU_CART; + +/************************************************* + S1945P +**************************************************/ + +class neogeo_cmc_s1945p_cart : public neogeo_cmc_cart +{ +public: + neogeo_cmc_s1945p_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual void decrypt_all(DECRYPT_ALL_PARAMS); + virtual int get_fixed_bank_type(void) { return 1; } +}; +extern const device_type NEOGEO_CMC_S1945P_CART; + + +/************************************************* + PREISLE2 +**************************************************/ + +class neogeo_cmc_preisle2_cart : public neogeo_cmc_cart +{ +public: + neogeo_cmc_preisle2_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual void decrypt_all(DECRYPT_ALL_PARAMS); + virtual int get_fixed_bank_type(void) { return 1; } +}; +extern const device_type NEOGEO_CMC_PREISLE2_CART; + +/************************************************* + BANGBEAD +**************************************************/ + +class neogeo_cmc_bangbead_cart : public neogeo_cmc_cart +{ +public: + neogeo_cmc_bangbead_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual void decrypt_all(DECRYPT_ALL_PARAMS); + virtual int get_fixed_bank_type(void) { return 1; } +}; +extern const device_type NEOGEO_CMC_BANGBEAD_CART; + + +/************************************************* + NITD +**************************************************/ + +class neogeo_cmc_nitd_cart : public neogeo_cmc_cart +{ +public: + neogeo_cmc_nitd_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual void decrypt_all(DECRYPT_ALL_PARAMS); + virtual int get_fixed_bank_type(void) { return 1; } +}; +extern const device_type NEOGEO_CMC_NITD_CART; + +/************************************************* + SENGOKU3 +**************************************************/ + +class neogeo_cmc_sengoku3_cart : public neogeo_cmc_cart +{ +public: + neogeo_cmc_sengoku3_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual void decrypt_all(DECRYPT_ALL_PARAMS); + virtual int get_fixed_bank_type(void) { return 1; } +}; +extern const device_type NEOGEO_CMC_SENGOKU3_CART; + +/************************************************* + KOF99K +**************************************************/ + +class neogeo_cmc_kof99k_cart : public neogeo_cmc_cart +{ +public: + neogeo_cmc_kof99k_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual void decrypt_all(DECRYPT_ALL_PARAMS); + virtual int get_fixed_bank_type(void) { return 1; } +}; +extern const device_type NEOGEO_CMC_KOF99K_CART; + +/************************************************* + KOF2001 +**************************************************/ + +class neogeo_cmc_kof2001_cart : public neogeo_cmc_cart +{ +public: + neogeo_cmc_kof2001_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual void decrypt_all(DECRYPT_ALL_PARAMS); + virtual int get_fixed_bank_type(void) { return 1; } +}; +extern const device_type NEOGEO_CMC_KOF2001_CART; + +/************************************************* + KOF2000N +**************************************************/ + +class neogeo_cmc_kof2000n_cart : public neogeo_cmc_cart +{ +public: + neogeo_cmc_kof2000n_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual void decrypt_all(DECRYPT_ALL_PARAMS); + virtual int get_fixed_bank_type(void) { return 2; } +}; +extern const device_type NEOGEO_CMC_KOF2000N_CART; + + + +#endif diff --git a/src/devices/bus/neogeo/cmc_prot.c b/src/devices/bus/neogeo/cmc_prot.c new file mode 100644 index 00000000000..f4ccc1ecada --- /dev/null +++ b/src/devices/bus/neogeo/cmc_prot.c @@ -0,0 +1,789 @@ +// license:BSD-3-Clause +// copyright-holders:S. Smith,David Haywood + +#include "emu.h" +#include "cmc_prot.h" + + + +extern const device_type CMC_PROT = &device_creator; + + +cmc_prot_device::cmc_prot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, CMC_PROT, "NeoGeo Protection (CMC)", tag, owner, clock, "cmc_prot", __FILE__) +{ +} + + +void cmc_prot_device::device_start() +{ +} + +void cmc_prot_device::device_reset() +{ +} + + + + + + + +/*************************************************************************** + +NeoGeo 'C' ROM encryption + +Starting with KOF99, all NeoGeo games have encrypted graphics. Additionally +to that, the data for the front text layer, which was previously stored in +a separate ROM, is stored at the end of the tile data. + +The encryption is one of the nastiest implementation of a XOR scheme ever +seen, involving 9 seemingly uncorrelated 256-byte tables. All known games use +the same tables except KOF2000 and MS4 which use a different set. + +The 32 data bits of every longword are decrypted in a single step (one byte at +a time), but the values to use for the xor are determined in a convoluted way. +It's actually so convoluted that it's too difficult to describe - please refer +to the source below. +Suffice to say that bytes are handled in couples (0&3 and 1&2), and the two xor +values are taken from three tables, the indexes inside the tables depending on +bits 0-7 and 8-15 of the address, in one case further xored through the table +used in step 5) below. Additionally, the bytes in a couple can be swapped, +depending either on bit 8 of the address, or on bit 16 xored with the table +used in step 4) below. + +The 24 address bits are encrypted in five steps. Each step xors 8 bits with a +value taken from a different table; the index inside the table depends on 8 +other bits. +0) xor bits 0-7 with a fixed value that changes from game to game +1) xor bits 8-15 depending on bits 16-23 +2) xor bits 8-15 depending on bits 0-7 +3) xor bits 16-23 depending on bits 0-7 +4) xor bits 16-23 depending on bits 8-15 +5) xor bits 0-7 depending on bits 8-15 + +Each step acts on the current value, so e.g. step 4) uses bits 8-15 as modified +by step 2). + +[Note: the table used in step 1) is currently incomplete due to lack of data to +analyze] + + +There are two major weaknesses in this encryption algorithm, that exposed it to +a known plaintext attack. + +The first weakness is that the data xor depends on the address inside the +encrypted ROM instead that on the decrypted address; together with the high +concentration of 0x00 and 0xFF in the decrypted data (more than 60% of the +total), this exposed easily recognizable patterns in the encrypted data, which +could be exploited with some simple statistical checks. The deviousness of the +xor scheme was the major difficulty. + +The second weakness is that the address scrambling works on 32-bit words. Since +there are a large number of 32-bit values that appear only once in the whole +encrypted ROM space, this means that once the xor layer was broken, a large +table of encrypted-decrypted address correspondencies could be built and +analyzed, quickly leading to the algorithm. + +***************************************************************************/ + +static const UINT8 kof99_type0_t03[256] = +{ + 0xfb, 0x86, 0x9d, 0xf1, 0xbf, 0x80, 0xd5, 0x43, 0xab, 0xb3, 0x9f, 0x6a, 0x33, 0xd9, 0xdb, 0xb6, + 0x66, 0x08, 0x69, 0x88, 0xcc, 0xb7, 0xde, 0x49, 0x97, 0x64, 0x1f, 0xa6, 0xc0, 0x2f, 0x52, 0x42, + 0x44, 0x5a, 0xf2, 0x28, 0x98, 0x87, 0x96, 0x8a, 0x83, 0x0b, 0x03, 0x61, 0x71, 0x99, 0x6b, 0xb5, + 0x1a, 0x8e, 0xfe, 0x04, 0xe1, 0xf7, 0x7d, 0xdd, 0xed, 0xca, 0x37, 0xfc, 0xef, 0x39, 0x72, 0xda, + 0xb8, 0xbe, 0xee, 0x7f, 0xe5, 0x31, 0x78, 0xf3, 0x91, 0x9a, 0xd2, 0x11, 0x19, 0xb9, 0x09, 0x4c, + 0xfd, 0x6d, 0x2a, 0x4d, 0x65, 0xa1, 0x89, 0xc7, 0x75, 0x50, 0x21, 0xfa, 0x16, 0x00, 0xe9, 0x12, + 0x74, 0x2b, 0x1e, 0x4f, 0x14, 0x01, 0x70, 0x3a, 0x4e, 0x3f, 0xf5, 0xf4, 0x1d, 0x3d, 0x15, 0x27, + 0xa7, 0xff, 0x45, 0xe0, 0x6e, 0xf9, 0x54, 0xc8, 0x48, 0xad, 0xa5, 0x0a, 0xf6, 0x2d, 0x2c, 0xe2, + 0x68, 0x67, 0xd6, 0x85, 0xb4, 0xc3, 0x34, 0xbc, 0x62, 0xd3, 0x5f, 0x84, 0x06, 0x5b, 0x0d, 0x95, + 0xea, 0x5e, 0x9e, 0xd4, 0xeb, 0x90, 0x7a, 0x05, 0x81, 0x57, 0xe8, 0x60, 0x2e, 0x20, 0x25, 0x7c, + 0x46, 0x0c, 0x93, 0xcb, 0xbd, 0x17, 0x7e, 0xec, 0x79, 0xb2, 0xc2, 0x22, 0x41, 0xb1, 0x10, 0xac, + 0xa8, 0xbb, 0x9b, 0x82, 0x4b, 0x9c, 0x8b, 0x07, 0x47, 0x35, 0x24, 0x56, 0x8d, 0xaf, 0xe6, 0x26, + 0x40, 0x38, 0xc4, 0x5d, 0x1b, 0xc5, 0xd1, 0x0f, 0x6c, 0x7b, 0xb0, 0xe3, 0xa3, 0x23, 0x6f, 0x58, + 0xc1, 0xba, 0xcf, 0xd7, 0xa2, 0xe7, 0xd0, 0x63, 0x5c, 0xf8, 0x73, 0xa0, 0x13, 0xdc, 0x29, 0xcd, + 0xc9, 0x76, 0xae, 0x8f, 0xe4, 0x59, 0x30, 0xaa, 0x94, 0x1c, 0x3c, 0x0e, 0x55, 0x92, 0x77, 0x32, + 0xc6, 0xce, 0x18, 0x36, 0xdf, 0xa9, 0x8c, 0xd8, 0xa4, 0xf0, 0x3b, 0x51, 0x4a, 0x02, 0x3e, 0x53, +}; + + +static const UINT8 kof99_type0_t12[256] = +{ + 0x1f, 0xac, 0x4d, 0xcd, 0xca, 0x70, 0x02, 0x6b, 0x18, 0x40, 0x62, 0xb2, 0x3f, 0x9b, 0x5b, 0xef, + 0x69, 0x68, 0x71, 0x3b, 0xcb, 0xd4, 0x30, 0xbc, 0x47, 0x72, 0x74, 0x5e, 0x84, 0x4c, 0x1b, 0xdb, + 0x6a, 0x35, 0x1d, 0xf5, 0xa1, 0xb3, 0x87, 0x5d, 0x57, 0x28, 0x2f, 0xc4, 0xfd, 0x24, 0x26, 0x36, + 0xad, 0xbe, 0x61, 0x63, 0x73, 0xaa, 0x82, 0xee, 0x29, 0xd0, 0xdf, 0x8c, 0x15, 0xb5, 0x96, 0xf3, + 0xdd, 0x7e, 0x3a, 0x37, 0x58, 0x7f, 0x0c, 0xfc, 0x0b, 0x07, 0xe8, 0xf7, 0xf4, 0x14, 0xb8, 0x81, + 0xb6, 0xd7, 0x1e, 0xc8, 0x85, 0xe6, 0x9d, 0x33, 0x60, 0xc5, 0x95, 0xd5, 0x55, 0x00, 0xa3, 0xb7, + 0x7d, 0x50, 0x0d, 0xd2, 0xc1, 0x12, 0xe5, 0xed, 0xd8, 0xa4, 0x9c, 0x8f, 0x2a, 0x4f, 0xa8, 0x01, + 0x52, 0x83, 0x65, 0xea, 0x9a, 0x6c, 0x44, 0x4a, 0xe2, 0xa5, 0x2b, 0x46, 0xe1, 0x34, 0x25, 0xf8, + 0xc3, 0xda, 0xc7, 0x6e, 0x48, 0x38, 0x7c, 0x78, 0x06, 0x53, 0x64, 0x16, 0x98, 0x3c, 0x91, 0x42, + 0x39, 0xcc, 0xb0, 0xf1, 0xeb, 0x13, 0xbb, 0x05, 0x32, 0x86, 0x0e, 0xa2, 0x0a, 0x9e, 0xfa, 0x66, + 0x54, 0x8e, 0xd3, 0xe7, 0x19, 0x20, 0x77, 0xec, 0xff, 0xbd, 0x6d, 0x43, 0x23, 0x03, 0xab, 0x75, + 0x3d, 0xcf, 0xd1, 0xde, 0x92, 0x31, 0xa7, 0x45, 0x4b, 0xc2, 0x97, 0xf9, 0x7a, 0x88, 0xd9, 0x1c, + 0xe9, 0xe4, 0x10, 0xc9, 0x22, 0x2d, 0x90, 0x76, 0x17, 0x79, 0x04, 0x51, 0x1a, 0x5a, 0x5f, 0x2c, + 0x21, 0x6f, 0x3e, 0xe0, 0xf0, 0xbf, 0xd6, 0x94, 0x0f, 0x80, 0x11, 0xa0, 0x5c, 0xa9, 0x49, 0x2e, + 0xce, 0xaf, 0xa6, 0x9f, 0x7b, 0x99, 0xb9, 0xb4, 0xe3, 0xfb, 0xf6, 0x27, 0xf2, 0x93, 0xfe, 0x08, + 0x67, 0xae, 0x09, 0x89, 0xdc, 0x4e, 0xc6, 0xc0, 0x8a, 0xb1, 0x59, 0x8b, 0x41, 0x56, 0x8d, 0xba, +}; + + +static const UINT8 kof99_type1_t03[256] = +{ + 0xa9, 0x17, 0xaf, 0x0d, 0x34, 0x6e, 0x53, 0xb6, 0x7f, 0x58, 0xe9, 0x14, 0x5f, 0x55, 0xdb, 0xd4, + 0x42, 0x80, 0x99, 0x59, 0xa8, 0x3a, 0x57, 0x5d, 0xd5, 0x6f, 0x4c, 0x68, 0x35, 0x46, 0xa6, 0xe7, + 0x7b, 0x71, 0xe0, 0x93, 0xa2, 0x1f, 0x64, 0x21, 0xe3, 0xb1, 0x98, 0x26, 0xab, 0xad, 0xee, 0xe5, + 0xbb, 0xd9, 0x1e, 0x2e, 0x95, 0x36, 0xef, 0x23, 0x79, 0x45, 0x04, 0xed, 0x13, 0x1d, 0xf4, 0x85, + 0x96, 0xec, 0xc2, 0x32, 0xaa, 0x7c, 0x15, 0xd8, 0xda, 0x92, 0x90, 0x9d, 0xb7, 0x56, 0x6a, 0x66, + 0x41, 0xfc, 0x00, 0xf6, 0x50, 0x24, 0xcf, 0xfb, 0x11, 0xfe, 0x82, 0x48, 0x9b, 0x27, 0x1b, 0x67, + 0x4e, 0x84, 0x69, 0x97, 0x6d, 0x8c, 0xd2, 0xba, 0x74, 0xf9, 0x8f, 0xa5, 0x54, 0x5c, 0xcd, 0x73, + 0x07, 0xd1, 0x01, 0x09, 0xf1, 0x19, 0x3b, 0x5e, 0x87, 0x30, 0x76, 0xcc, 0xc0, 0x5a, 0xa7, 0x49, + 0x22, 0xfa, 0x16, 0x02, 0xdf, 0xa4, 0xff, 0xb3, 0x75, 0x33, 0xbd, 0x88, 0x2f, 0xcb, 0x2a, 0x44, + 0xb8, 0xbf, 0x1c, 0x0f, 0x81, 0x10, 0x43, 0xb4, 0xc8, 0x7e, 0x9a, 0x25, 0xea, 0x83, 0x4b, 0x38, + 0x7a, 0xd7, 0x3d, 0x1a, 0x4f, 0x62, 0x51, 0xc9, 0x47, 0x0e, 0xce, 0x3f, 0xc7, 0x4d, 0x2c, 0xa1, + 0x86, 0xb9, 0xc5, 0xca, 0xdd, 0x6b, 0x70, 0x6c, 0x91, 0x9c, 0xbe, 0x0a, 0x9f, 0xf5, 0x94, 0xbc, + 0x18, 0x2b, 0x60, 0x20, 0x29, 0xf7, 0xf2, 0x28, 0xc4, 0xa0, 0x0b, 0x65, 0xde, 0x8d, 0x78, 0x12, + 0x3e, 0xd0, 0x77, 0x08, 0x8b, 0xae, 0x05, 0x31, 0x3c, 0xd6, 0xa3, 0x89, 0x06, 0xdc, 0x52, 0x72, + 0xb0, 0xb5, 0x37, 0xd3, 0xc3, 0x8a, 0xc6, 0xf0, 0xc1, 0x61, 0xfd, 0x4a, 0x5b, 0x7d, 0x9e, 0xf3, + 0x63, 0x40, 0x2d, 0xe8, 0xb2, 0xe6, 0x39, 0x03, 0xeb, 0x8e, 0xe1, 0x0c, 0xe4, 0xe2, 0xf8, 0xac, +}; + + +static const UINT8 kof99_type1_t12[256] = +{ + 0xea, 0xe6, 0x5e, 0xa7, 0x8e, 0xac, 0x34, 0x03, 0x30, 0x97, 0x52, 0x53, 0x76, 0xf2, 0x62, 0x0b, + 0x0a, 0xfc, 0x94, 0xb8, 0x67, 0x36, 0x11, 0xbc, 0xae, 0xca, 0xfa, 0x15, 0x04, 0x2b, 0x17, 0xc4, + 0x3e, 0x5b, 0x59, 0x01, 0x57, 0xe2, 0xba, 0xb7, 0xd1, 0x3f, 0xf0, 0x6a, 0x9c, 0x2a, 0xcb, 0xa9, + 0xe3, 0x2c, 0xc0, 0x0f, 0x46, 0x91, 0x8a, 0xd0, 0x98, 0xc5, 0xa6, 0x1b, 0x96, 0x29, 0x12, 0x09, + 0x63, 0xed, 0xe0, 0xa2, 0x86, 0x77, 0xbe, 0xe5, 0x65, 0xdb, 0xbd, 0x50, 0xb3, 0x9d, 0x1a, 0x4e, + 0x79, 0x0c, 0x00, 0x43, 0xdf, 0x3d, 0x54, 0x33, 0x8f, 0x89, 0xa8, 0x7b, 0xf9, 0xd5, 0x27, 0x82, + 0xbb, 0xc2, 0x8c, 0x47, 0x88, 0x6b, 0xb4, 0xc3, 0xf8, 0xaa, 0x06, 0x1e, 0x83, 0x7d, 0x05, 0x78, + 0x85, 0xf6, 0x6e, 0x2e, 0xec, 0x5a, 0x31, 0x45, 0x38, 0x14, 0x16, 0x8b, 0x02, 0xe4, 0x4f, 0xb0, + 0xbf, 0xab, 0xa4, 0x9e, 0x48, 0x60, 0x19, 0x35, 0x08, 0xde, 0xdd, 0x66, 0x90, 0x51, 0xcc, 0xa3, + 0xaf, 0x70, 0x9b, 0x75, 0x95, 0x49, 0x6c, 0x64, 0x72, 0x7e, 0x44, 0xa0, 0x73, 0x25, 0x68, 0x55, + 0x1f, 0x40, 0x7a, 0x74, 0x0e, 0x8d, 0xdc, 0x1c, 0x71, 0xc8, 0xcf, 0xd7, 0xe8, 0xce, 0xeb, 0x32, + 0x3a, 0xee, 0x07, 0x61, 0x4d, 0xfe, 0x5c, 0x7c, 0x56, 0x2f, 0x2d, 0x5f, 0x6f, 0x9f, 0x81, 0x22, + 0x58, 0x4b, 0xad, 0xda, 0xb9, 0x10, 0x18, 0x23, 0xe1, 0xf3, 0x6d, 0xe7, 0xe9, 0x28, 0xd6, 0xd8, + 0xf4, 0x4c, 0x39, 0x21, 0xb2, 0x84, 0xc1, 0x24, 0x26, 0xf1, 0x93, 0x37, 0xc6, 0x4a, 0xcd, 0x20, + 0xc9, 0xd9, 0xc7, 0xb1, 0xff, 0x99, 0xd4, 0x5d, 0xb5, 0xa1, 0x87, 0x0d, 0x69, 0x92, 0x13, 0x80, + 0xd2, 0xd3, 0xfd, 0x1d, 0xf5, 0x3b, 0xa5, 0x7f, 0xef, 0x9a, 0xb6, 0x42, 0xfb, 0x3c, 0xf7, 0x41, +}; + + +/* underlined values are wrong (not enough evidence, FF fill in kof99 and garou) */ +/* they correspond to tiles 7d000-7efff */ +static const UINT8 kof99_address_8_15_xor1[256] = +{ + 0x00, 0xb1, 0x1e, 0xc5, 0x3d, 0x40, 0x45, 0x5e, 0xf2, 0xf8, 0x04, 0x63, 0x36, 0x87, 0x88, 0xbf, + 0xab, 0xcc, 0x78, 0x08, 0xdd, 0x20, 0xd4, 0x35, 0x09, 0x8e, 0x44, 0xae, 0x33, 0xa9, 0x9e, 0xcd, + 0xb3, 0xe5, 0xad, 0x41, 0xda, 0xbe, 0xf4, 0x16, 0x57, 0x2e, 0x53, 0x67, 0xaf, 0xdb, 0x8a, 0xd8, + 0x34, 0x17, 0x3c, 0x01, 0x55, 0x73, 0xcf, 0xe3, 0xe8, 0xc7, 0x0d, 0xe9, 0xa3, 0x13, 0x0c, 0xf6, + 0x90, 0x4e, 0xfb, 0x97, 0x6d, 0x5f, 0xa8, 0x71, 0x11, 0xfc, 0xd1, 0x95, 0x81, 0xba, 0x8c, 0x1b, + 0x39, 0xfe, 0xa2, 0x15, 0xa6, 0x52, 0x4d, 0x5b, 0x59, 0xa5, 0xe0, 0x96, 0xd9, 0x8f, 0x7b, 0xed, + 0x29, 0xd3, 0x1f, 0x0e, 0xec, 0x23, 0x0f, 0xb8, 0x6c, 0x6f, 0x7d, 0x18, 0x46, 0xd6, 0xe4, 0xb5, + 0x9a, 0x79, 0x02, 0xf5, 0x03, 0xc0, 0x60, 0x66, 0x5c, 0x2f, 0x76, 0x85, 0x9d, 0x54, 0x1a, 0x6a, + 0x28, 0xce, 0x7f, 0x7c, 0x91, 0x99, 0x4c, 0x83, 0x3e, 0xb4, 0x1d, 0x05, 0xc1, 0xc3, 0xd7, 0x47, + 0xde, 0xbc, 0x62, 0x6e, 0x86, 0x14, 0x80, 0x77, 0xeb, 0xf3, 0x07, 0x31, 0x56, 0xd2, 0xc2, 0xc6, + 0x6b, 0xdc, 0xfd, 0x22, 0x92, 0xf0, 0x06, 0x51, 0x2d, 0x38, 0xe6, 0xa0, 0x25, 0xdf, 0xd5, 0x2c, + 0x1c, 0x94, 0x12, 0x9c, 0xb0, 0x9b, 0xc4, 0x0b, 0xc8, 0xd0, 0xf7, 0x30, 0xcb, 0x27, 0xfa, 0x7a, + 0x10, 0x61, 0xaa, 0xa4, 0x70, 0xb7, 0x2a, 0x5a, 0xc9, 0xf1, 0x0a, 0x49, 0x65, 0xee, 0x69, 0x4b, + 0x3a, 0x8d, 0x32, 0x5d, 0x68, 0xb9, 0x9f, 0x75, 0x19, 0x3f, 0xac, 0x37, 0x4f, 0xe7, 0x93, 0x89, + 0x7e, 0x4a, 0x3b, 0xea, 0x74, 0x72, 0x43, 0xbd, 0x24, 0xef, 0xb6, 0xff, 0x64, 0x58, 0x84, 0x8b, + 0xa7, 0xbb, 0xb2, 0xe1, 0x26, 0x2b, 0x50, 0xca, 0x21, 0xf9, 0x98, 0xa1, 0xe2, 0x42, 0x82, 0x48, +// ^^^^ ^^^^ ^^^^ ^^^^ +}; + + +static const UINT8 kof99_address_8_15_xor2[256] = +{ + 0x9b, 0x9d, 0xc1, 0x3d, 0xa9, 0xb8, 0xf4, 0x6f, 0xf6, 0x25, 0xc7, 0x47, 0xd5, 0x97, 0xdf, 0x6b, + 0xeb, 0x90, 0xa4, 0xb2, 0x5d, 0xf5, 0x66, 0xb0, 0xb9, 0x8b, 0x93, 0x64, 0xec, 0x7b, 0x65, 0x8c, + 0xf1, 0x43, 0x42, 0x6e, 0x45, 0x9f, 0xb3, 0x35, 0x06, 0x71, 0x96, 0xdb, 0xa0, 0xfb, 0x0b, 0x3a, + 0x1f, 0xf8, 0x8e, 0x69, 0xcd, 0x26, 0xab, 0x86, 0xa2, 0x0c, 0xbd, 0x63, 0xa5, 0x7a, 0xe7, 0x6a, + 0x5f, 0x18, 0x9e, 0xbf, 0xad, 0x55, 0xb1, 0x1c, 0x5c, 0x03, 0x30, 0xc6, 0x37, 0x20, 0xe3, 0xc9, + 0x52, 0xe8, 0xee, 0x4f, 0x01, 0x70, 0xc4, 0x77, 0x29, 0x2a, 0xba, 0x53, 0x12, 0x04, 0x7d, 0xaf, + 0x33, 0x8f, 0xa8, 0x4d, 0xaa, 0x5b, 0xb4, 0x0f, 0x92, 0xbb, 0xed, 0xe1, 0x2f, 0x50, 0x6c, 0xd2, + 0x2c, 0x95, 0xd9, 0xf9, 0x98, 0xc3, 0x76, 0x4c, 0xf2, 0xe4, 0xe5, 0x2b, 0xef, 0x9c, 0x49, 0xb6, + 0x31, 0x3b, 0xbc, 0xa1, 0xca, 0xde, 0x62, 0x74, 0xea, 0x81, 0x00, 0xdd, 0xa6, 0x46, 0x88, 0x3f, + 0x39, 0xd6, 0x23, 0x54, 0x24, 0x4a, 0xd8, 0xdc, 0xd7, 0xd1, 0xcc, 0xbe, 0x57, 0x7c, 0xda, 0x44, + 0x61, 0xce, 0xd3, 0xd4, 0xe9, 0x28, 0x80, 0xe0, 0x56, 0x8a, 0x09, 0x05, 0x9a, 0x89, 0x1b, 0xf7, + 0xf3, 0x99, 0x6d, 0x5e, 0x48, 0x91, 0xc0, 0xd0, 0xc5, 0x79, 0x78, 0x41, 0x59, 0x21, 0x2e, 0xff, + 0xc2, 0x4b, 0x38, 0x83, 0x32, 0xe6, 0xe2, 0x7f, 0x1e, 0x17, 0x58, 0x1d, 0x1a, 0xfa, 0x85, 0x82, + 0x94, 0xc8, 0x72, 0x7e, 0xb7, 0xac, 0x0e, 0xfc, 0xfd, 0x16, 0x27, 0x75, 0x8d, 0xcb, 0x08, 0xfe, + 0x0a, 0x02, 0x0d, 0x36, 0x11, 0x22, 0x84, 0x40, 0x34, 0x3e, 0x2d, 0x68, 0x5a, 0xa7, 0x67, 0xae, + 0x87, 0x07, 0x10, 0x60, 0x14, 0x73, 0x3c, 0x51, 0x19, 0xa3, 0xb5, 0xcf, 0x13, 0xf0, 0x15, 0x4e, +}; + + +static const UINT8 kof99_address_16_23_xor1[256] = +{ + 0x00, 0x5f, 0x03, 0x52, 0xce, 0xe3, 0x7d, 0x8f, 0x6b, 0xf8, 0x20, 0xde, 0x7b, 0x7e, 0x39, 0xbe, + 0xf5, 0x94, 0x18, 0x78, 0x80, 0xc9, 0x7f, 0x7a, 0x3e, 0x63, 0xf2, 0xe0, 0x4e, 0xf7, 0x87, 0x27, + 0x69, 0x6c, 0xa4, 0x1d, 0x85, 0x5b, 0xe6, 0x44, 0x25, 0x0c, 0x98, 0xc7, 0x01, 0x02, 0xa3, 0x26, + 0x09, 0x38, 0xdb, 0xc3, 0x1e, 0xcf, 0x23, 0x45, 0x68, 0x76, 0xd6, 0x22, 0x5d, 0x5a, 0xae, 0x16, + 0x9f, 0xa2, 0xb5, 0xcd, 0x81, 0xea, 0x5e, 0xb8, 0xb9, 0x9d, 0x9c, 0x1a, 0x0f, 0xff, 0xe1, 0xe7, + 0x74, 0xaa, 0xd4, 0xaf, 0xfc, 0xc6, 0x33, 0x29, 0x5c, 0xab, 0x95, 0xf0, 0x19, 0x47, 0x59, 0x67, + 0xf3, 0x96, 0x60, 0x1f, 0x62, 0x92, 0xbd, 0x89, 0xee, 0x28, 0x13, 0x06, 0xfe, 0xfa, 0x32, 0x6d, + 0x57, 0x3c, 0x54, 0x50, 0x2c, 0x58, 0x49, 0xfb, 0x17, 0xcc, 0xef, 0xb2, 0xb4, 0xf9, 0x07, 0x70, + 0xc5, 0xa9, 0xdf, 0xd5, 0x3b, 0x86, 0x2b, 0x0d, 0x6e, 0x4d, 0x0a, 0x90, 0x43, 0x31, 0xc1, 0xf6, + 0x88, 0x0b, 0xda, 0x53, 0x14, 0xdc, 0x75, 0x8e, 0xb0, 0xeb, 0x99, 0x46, 0xa1, 0x15, 0x71, 0xc8, + 0xe9, 0x3f, 0x4a, 0xd9, 0x73, 0xe5, 0x7c, 0x30, 0x77, 0xd3, 0xb3, 0x4b, 0x37, 0x72, 0xc2, 0x04, + 0x97, 0x08, 0x36, 0xb1, 0x3a, 0x61, 0xec, 0xe2, 0x1c, 0x9a, 0x8b, 0xd1, 0x1b, 0x2e, 0x9e, 0x8a, + 0xd8, 0x41, 0xe4, 0xc4, 0x40, 0x2f, 0xad, 0xc0, 0xb6, 0x84, 0x51, 0x66, 0xbb, 0x12, 0xe8, 0xdd, + 0xcb, 0xbc, 0x6f, 0xd0, 0x11, 0x83, 0x56, 0x4c, 0xca, 0xbf, 0x05, 0x10, 0xd7, 0xba, 0xfd, 0xed, + 0x8c, 0x0e, 0x4f, 0x3d, 0x35, 0x91, 0xb7, 0xac, 0x34, 0x64, 0x2a, 0xf1, 0x79, 0x6a, 0x9b, 0x2d, + 0x65, 0xf4, 0x42, 0xa0, 0x8d, 0xa7, 0x48, 0x55, 0x21, 0x93, 0x24, 0xd2, 0xa6, 0xa5, 0xa8, 0x82, +}; + + +static const UINT8 kof99_address_16_23_xor2[256] = +{ + 0x29, 0x97, 0x1a, 0x2c, 0x0b, 0x94, 0x3e, 0x75, 0x01, 0x0d, 0x1b, 0xe1, 0x4d, 0x38, 0x39, 0x8f, + 0xe7, 0xd0, 0x60, 0x90, 0xb2, 0x0f, 0xbb, 0x70, 0x1f, 0xe6, 0x5b, 0x87, 0xb4, 0x43, 0xfd, 0xf5, + 0xf6, 0xf9, 0xad, 0xc0, 0x98, 0x17, 0x9f, 0x91, 0x15, 0x51, 0x55, 0x64, 0x6c, 0x18, 0x61, 0x0e, + 0xd9, 0x93, 0xab, 0xd6, 0x24, 0x2f, 0x6a, 0x3a, 0x22, 0xb1, 0x4f, 0xaa, 0x23, 0x48, 0xed, 0xb9, + 0x88, 0x8b, 0xa3, 0x6b, 0x26, 0x4c, 0xe8, 0x2d, 0x1c, 0x99, 0xbd, 0x5c, 0x58, 0x08, 0x50, 0xf2, + 0x2a, 0x62, 0xc1, 0x72, 0x66, 0x04, 0x10, 0x37, 0x6e, 0xfc, 0x44, 0xa9, 0xdf, 0xd4, 0x20, 0xdd, + 0xee, 0x41, 0xdb, 0x73, 0xde, 0x54, 0xec, 0xc9, 0xf3, 0x4b, 0x2e, 0xae, 0x5a, 0x4a, 0x5e, 0x47, + 0x07, 0x2b, 0x76, 0xa4, 0xe3, 0x28, 0xfe, 0xb0, 0xf0, 0x02, 0x06, 0xd1, 0xaf, 0x42, 0xc2, 0xa5, + 0xe0, 0x67, 0xbf, 0x16, 0x8e, 0x35, 0xce, 0x8a, 0xe5, 0x3d, 0x7b, 0x96, 0xd7, 0x79, 0x52, 0x1e, + 0xa1, 0xfb, 0x9b, 0xbe, 0x21, 0x9c, 0xe9, 0x56, 0x14, 0x7f, 0xa0, 0xe4, 0xc3, 0xc4, 0x46, 0xea, + 0xf7, 0xd2, 0x1d, 0x31, 0x0a, 0x5f, 0xeb, 0xa2, 0x68, 0x8d, 0xb5, 0xc5, 0x74, 0x0c, 0xdc, 0x82, + 0x80, 0x09, 0x19, 0x95, 0x71, 0x9a, 0x11, 0x57, 0x77, 0x4e, 0xc6, 0xff, 0x12, 0x03, 0xa7, 0xc7, + 0xf4, 0xc8, 0xb6, 0x7a, 0x59, 0x36, 0x3c, 0x53, 0xe2, 0x69, 0x8c, 0x25, 0x05, 0x45, 0x63, 0xf8, + 0x34, 0x89, 0x33, 0x3f, 0x85, 0x27, 0xbc, 0x65, 0xfa, 0xa8, 0x6d, 0x84, 0x5d, 0xba, 0x40, 0x32, + 0x30, 0xef, 0x83, 0x13, 0xa6, 0x78, 0xcc, 0x81, 0x9e, 0xda, 0xca, 0xd3, 0x7e, 0x9d, 0x6f, 0xcd, + 0xb7, 0xb3, 0xd8, 0xcf, 0x3b, 0x00, 0x92, 0xb8, 0x86, 0xac, 0x49, 0x7c, 0xf1, 0xd5, 0xcb, 0x7d, +}; + + +static const UINT8 kof99_address_0_7_xor[256] = +{ + 0x74, 0xad, 0x5d, 0x1d, 0x9e, 0xc3, 0xfa, 0x4e, 0xf7, 0xdb, 0xca, 0xa2, 0x64, 0x36, 0x56, 0x0c, + 0x4f, 0xcf, 0x43, 0x66, 0x1e, 0x91, 0xe3, 0xa5, 0x58, 0xc2, 0xc1, 0xd4, 0xb9, 0xdd, 0x76, 0x16, + 0xce, 0x61, 0x75, 0x01, 0x2b, 0x22, 0x38, 0x55, 0x50, 0xef, 0x6c, 0x99, 0x05, 0xe9, 0xe8, 0xe0, + 0x2d, 0xa4, 0x4b, 0x4a, 0x42, 0xae, 0xba, 0x8c, 0x6f, 0x93, 0x14, 0xbd, 0x71, 0x21, 0xb0, 0x02, + 0x15, 0xc4, 0xe6, 0x60, 0xd7, 0x44, 0xfd, 0x85, 0x7e, 0x78, 0x8f, 0x00, 0x81, 0xf1, 0xa7, 0x3b, + 0xa0, 0x10, 0xf4, 0x9f, 0x39, 0x88, 0x35, 0x62, 0xcb, 0x19, 0x31, 0x11, 0x51, 0xfb, 0x2a, 0x20, + 0x45, 0xd3, 0x7d, 0x92, 0x1b, 0xf2, 0x09, 0x0d, 0x97, 0xa9, 0xb5, 0x3c, 0xee, 0x5c, 0xaf, 0x7b, + 0xd2, 0x3a, 0x49, 0x8e, 0xb6, 0xcd, 0xd9, 0xde, 0x8a, 0x29, 0x6e, 0xd8, 0x0b, 0xe1, 0x69, 0x87, + 0x1a, 0x96, 0x18, 0xcc, 0xdf, 0xe7, 0xc5, 0xc7, 0xf8, 0x52, 0xc9, 0xf0, 0xb7, 0xe5, 0x33, 0xda, + 0x67, 0x9d, 0xa3, 0x03, 0x0e, 0x72, 0x26, 0x79, 0xe2, 0xb8, 0xfc, 0xaa, 0xfe, 0xb4, 0x86, 0xc8, + 0xd1, 0xbc, 0x12, 0x08, 0x77, 0xeb, 0x40, 0x8d, 0x04, 0x25, 0x4d, 0x5a, 0x6a, 0x7a, 0x2e, 0x41, + 0x65, 0x1c, 0x13, 0x94, 0xb2, 0x63, 0x28, 0x59, 0x5e, 0x9a, 0x30, 0x07, 0xc6, 0xbf, 0x17, 0xf5, + 0x0f, 0x89, 0xf3, 0x1f, 0xea, 0x6d, 0xb3, 0xc0, 0x70, 0x47, 0xf9, 0x53, 0xf6, 0xd6, 0x54, 0xed, + 0x6b, 0x4c, 0xe4, 0x8b, 0x83, 0x24, 0x90, 0xb1, 0x7c, 0xbb, 0x73, 0xab, 0xd5, 0x2f, 0x5f, 0xec, + 0x9c, 0x2c, 0xa8, 0x34, 0x46, 0x37, 0x27, 0xa1, 0x0a, 0x06, 0x80, 0x68, 0x82, 0x32, 0x84, 0xff, + 0x48, 0xac, 0x7f, 0x3f, 0x95, 0xdc, 0x98, 0x9b, 0xbe, 0x23, 0x57, 0x3e, 0x5b, 0xd0, 0x3d, 0xa6, +}; + + +static const UINT8 kof2000_type0_t03[256] = +{ + 0x10, 0x61, 0xf1, 0x78, 0x85, 0x52, 0x68, 0xe3, 0x12, 0x0d, 0xfa, 0xf0, 0xc9, 0x36, 0x5e, 0x3d, + 0xf9, 0xa6, 0x01, 0x2e, 0xc7, 0x84, 0xea, 0x2b, 0x6d, 0x14, 0x38, 0x4f, 0x55, 0x1c, 0x9d, 0xa7, + 0x7a, 0xc6, 0xf8, 0x9a, 0xe6, 0x42, 0xb5, 0xed, 0x7d, 0x3a, 0xb1, 0x05, 0x43, 0x4a, 0x22, 0xfd, + 0xac, 0xa4, 0x31, 0xc3, 0x32, 0x76, 0x95, 0x9e, 0x7e, 0x88, 0x8e, 0xa2, 0x97, 0x18, 0xbe, 0x2a, + 0xf5, 0xd6, 0xca, 0xcc, 0x72, 0x3b, 0x87, 0x6c, 0xde, 0x75, 0xd7, 0x21, 0xcb, 0x0b, 0xdd, 0xe7, + 0xe1, 0x65, 0xaa, 0xb9, 0x44, 0xfb, 0x66, 0x15, 0x1a, 0x3c, 0x98, 0xcf, 0x8a, 0xdf, 0x37, 0xa5, + 0x2f, 0x67, 0xd2, 0x83, 0xb6, 0x6b, 0xfc, 0xe0, 0xb4, 0x7c, 0x08, 0xdc, 0x93, 0x30, 0xab, 0xe4, + 0x19, 0xc2, 0x8b, 0xeb, 0xa0, 0x0a, 0xc8, 0x03, 0xc0, 0x4b, 0x64, 0x71, 0x86, 0x9c, 0x9b, 0x16, + 0x79, 0xff, 0x70, 0x09, 0x8c, 0xd0, 0xf6, 0x53, 0x07, 0x73, 0xd4, 0x89, 0xb3, 0x00, 0xe9, 0xfe, + 0xec, 0x8f, 0xbc, 0xb2, 0x1e, 0x5d, 0x11, 0x35, 0xa9, 0x06, 0x59, 0x9f, 0xc1, 0xd3, 0x7b, 0xf2, + 0xc5, 0x77, 0x4e, 0x39, 0x20, 0xd5, 0x6a, 0x82, 0xda, 0x45, 0xf3, 0x33, 0x81, 0x23, 0xba, 0xe2, + 0x1d, 0x5f, 0x5c, 0x51, 0x49, 0xae, 0x8d, 0xc4, 0xa8, 0xf7, 0x1f, 0x0f, 0x34, 0x28, 0xa1, 0xd9, + 0x27, 0xd8, 0x4c, 0x2c, 0xbf, 0x91, 0x3e, 0x69, 0x57, 0x41, 0x25, 0x0c, 0x5a, 0x90, 0x92, 0xb0, + 0x63, 0x6f, 0x40, 0xaf, 0x74, 0xb8, 0x2d, 0x80, 0xbb, 0x46, 0x94, 0xe5, 0x29, 0xee, 0xb7, 0x1b, + 0x96, 0xad, 0x13, 0x0e, 0x58, 0x99, 0x60, 0x4d, 0x17, 0x26, 0xce, 0xe8, 0xdb, 0xef, 0x24, 0xa3, + 0x6e, 0x7f, 0x54, 0x3f, 0x02, 0xd1, 0x5b, 0x50, 0x56, 0x48, 0xf4, 0xbd, 0x62, 0x47, 0x04, 0xcd, +}; + + +static const UINT8 kof2000_type0_t12[256] = +{ + 0xf4, 0x28, 0xb4, 0x8f, 0xfa, 0xeb, 0x8e, 0x54, 0x2b, 0x49, 0xd1, 0x76, 0x71, 0x47, 0x8b, 0x57, + 0x92, 0x85, 0x7c, 0xb8, 0x5c, 0x22, 0xf9, 0x26, 0xbc, 0x5b, 0x6d, 0x67, 0xae, 0x5f, 0x6f, 0xf5, + 0x9f, 0x48, 0x66, 0x40, 0x0d, 0x11, 0x4e, 0xb2, 0x6b, 0x35, 0x15, 0x0f, 0x18, 0x25, 0x1d, 0xba, + 0xd3, 0x69, 0x79, 0xec, 0xa8, 0x8c, 0xc9, 0x7f, 0x4b, 0xdb, 0x51, 0xaf, 0xca, 0xe2, 0xb3, 0x81, + 0x12, 0x5e, 0x7e, 0x38, 0xc8, 0x95, 0x01, 0xff, 0xfd, 0xfb, 0xf2, 0x74, 0x62, 0x14, 0xa5, 0x98, + 0xa6, 0xda, 0x80, 0x53, 0xe8, 0x56, 0xac, 0x1b, 0x52, 0xd0, 0xf1, 0x45, 0x42, 0xb6, 0x1a, 0x4a, + 0x3a, 0x99, 0xfc, 0xd2, 0x9c, 0xcf, 0x31, 0x2d, 0xdd, 0x86, 0x2f, 0x29, 0xe1, 0x03, 0x19, 0xa2, + 0x41, 0x33, 0x83, 0x90, 0xc1, 0xbf, 0x0b, 0x08, 0x3d, 0xd8, 0x8d, 0x6c, 0x39, 0xa0, 0xe3, 0x55, + 0x02, 0x50, 0x46, 0xe6, 0xc3, 0x82, 0x36, 0x13, 0x75, 0xab, 0x27, 0xd7, 0x1f, 0x0a, 0xd4, 0x89, + 0x59, 0x4f, 0xc0, 0x5d, 0xc6, 0xf7, 0x88, 0xbd, 0x3c, 0x00, 0xef, 0xcd, 0x05, 0x1c, 0xaa, 0x9b, + 0xed, 0x7a, 0x61, 0x17, 0x93, 0xfe, 0x23, 0xb9, 0xf3, 0x68, 0x78, 0xf6, 0x5a, 0x7b, 0xe0, 0xe4, + 0xa3, 0xee, 0x16, 0x72, 0xc7, 0x3b, 0x8a, 0x37, 0x2a, 0x70, 0xa9, 0x2c, 0x21, 0xf8, 0x24, 0x09, + 0xce, 0x20, 0x9e, 0x06, 0x87, 0xc5, 0x04, 0x64, 0x43, 0x7d, 0x4d, 0x10, 0xd6, 0xa4, 0x94, 0x4c, + 0x60, 0xde, 0xdf, 0x58, 0xb1, 0x44, 0x3f, 0xb0, 0xd9, 0xe5, 0xcb, 0xbb, 0xbe, 0xea, 0x07, 0x34, + 0x73, 0x6a, 0x77, 0xf0, 0x9d, 0x0c, 0x2e, 0x0e, 0x91, 0x9a, 0xcc, 0xc2, 0xb7, 0x63, 0x97, 0xd5, + 0xdc, 0xc4, 0x32, 0xe7, 0x84, 0x3e, 0x30, 0xa1, 0x1e, 0xb5, 0x6e, 0x65, 0xe9, 0xad, 0xa7, 0x96, +}; + + +static const UINT8 kof2000_type1_t03[256] = +{ + 0x9a, 0x2f, 0xcc, 0x4e, 0x40, 0x69, 0xac, 0xca, 0xa5, 0x7b, 0x0a, 0x61, 0x91, 0x0d, 0x55, 0x74, + 0xcd, 0x8b, 0x0b, 0x80, 0x09, 0x5e, 0x38, 0xc7, 0xda, 0xbf, 0xf5, 0x37, 0x23, 0x31, 0x33, 0xe9, + 0xae, 0x87, 0xe5, 0xfa, 0x6e, 0x5c, 0xad, 0xf4, 0x76, 0x62, 0x9f, 0x2e, 0x01, 0xe2, 0xf6, 0x47, + 0x8c, 0x7c, 0xaa, 0x98, 0xb5, 0x92, 0x51, 0xec, 0x5f, 0x07, 0x5d, 0x6f, 0x16, 0xa1, 0x1d, 0xa9, + 0x48, 0x45, 0xf0, 0x6a, 0x9c, 0x1e, 0x11, 0xa0, 0x06, 0x46, 0xd5, 0xf1, 0x73, 0xed, 0x94, 0xf7, + 0xc3, 0x57, 0x1b, 0xe0, 0x97, 0xb1, 0xa4, 0xa7, 0x24, 0xe7, 0x2b, 0x05, 0x5b, 0x34, 0x0c, 0xb8, + 0x0f, 0x9b, 0xc8, 0x4d, 0x5a, 0xa6, 0x86, 0x3e, 0x14, 0x29, 0x84, 0x58, 0x90, 0xdb, 0x2d, 0x54, + 0x9d, 0x82, 0xd4, 0x7d, 0xc6, 0x67, 0x41, 0x89, 0xc1, 0x13, 0xb0, 0x9e, 0x81, 0x6d, 0xa8, 0x59, + 0xbd, 0x39, 0x8e, 0xe6, 0x25, 0x8f, 0xd9, 0xa2, 0xe4, 0x53, 0xc5, 0x72, 0x7e, 0x36, 0x4a, 0x4f, + 0x52, 0xc2, 0x22, 0x2a, 0xce, 0x3c, 0x21, 0x2c, 0x00, 0xd7, 0x75, 0x8a, 0x27, 0xee, 0x43, 0xfe, + 0xcb, 0x6b, 0xb9, 0xa3, 0x78, 0xb7, 0x85, 0x02, 0x20, 0xd0, 0x83, 0xc4, 0x12, 0xf9, 0xfd, 0xd8, + 0x79, 0x64, 0x3a, 0x49, 0x03, 0xb4, 0xc0, 0xf2, 0xdf, 0x15, 0x93, 0x08, 0x35, 0xff, 0x70, 0xdd, + 0x28, 0x6c, 0x0e, 0x04, 0xde, 0x7a, 0x65, 0xd2, 0xab, 0x42, 0x95, 0xe1, 0x3f, 0x3b, 0x7f, 0x66, + 0xd1, 0x8d, 0xe3, 0xbb, 0x1c, 0xfc, 0x77, 0x1a, 0x88, 0x18, 0x19, 0x68, 0x1f, 0x56, 0xd6, 0xe8, + 0xb6, 0xbc, 0xd3, 0xea, 0x3d, 0x26, 0xb3, 0xc9, 0x44, 0xdc, 0xf3, 0x32, 0x30, 0xef, 0x96, 0x4c, + 0xaf, 0x17, 0xf8, 0xfb, 0x60, 0x50, 0xeb, 0x4b, 0x99, 0x63, 0xba, 0xb2, 0x71, 0xcf, 0x10, 0xbe, +}; + + +static const UINT8 kof2000_type1_t12[256] = +{ + 0xda, 0xa7, 0xd6, 0x6e, 0x2f, 0x5e, 0xf0, 0x3f, 0xa4, 0xce, 0xd3, 0xfd, 0x46, 0x2a, 0xac, 0xc9, + 0xbe, 0xeb, 0x9f, 0xd5, 0x3c, 0x61, 0x96, 0x11, 0xd0, 0x38, 0xca, 0x06, 0xed, 0x1b, 0x65, 0xe7, + 0x23, 0xdd, 0xd9, 0x05, 0xbf, 0x5b, 0x5d, 0xa5, 0x95, 0x00, 0xec, 0xf1, 0x01, 0xa9, 0xa6, 0xfc, + 0xbb, 0x54, 0xe3, 0x2e, 0x92, 0x58, 0x0a, 0x7b, 0xb6, 0xcc, 0xb1, 0x5f, 0x14, 0x35, 0x72, 0xff, + 0xe6, 0x52, 0xd7, 0x8c, 0xf3, 0x43, 0xaf, 0x9c, 0xc0, 0x4f, 0x0c, 0x42, 0x8e, 0xef, 0x80, 0xcd, + 0x1d, 0x7e, 0x88, 0x3b, 0x98, 0xa1, 0xad, 0xe4, 0x9d, 0x8d, 0x2b, 0x56, 0xb5, 0x50, 0xdf, 0x66, + 0x6d, 0xd4, 0x60, 0x09, 0xe1, 0xee, 0x4a, 0x47, 0xf9, 0xfe, 0x73, 0x07, 0x89, 0xa8, 0x39, 0xea, + 0x82, 0x9e, 0xcf, 0x26, 0xb2, 0x4e, 0xc3, 0x59, 0xf2, 0x3d, 0x9a, 0xb0, 0x69, 0xf7, 0xbc, 0x34, + 0xe5, 0x36, 0x22, 0xfb, 0x57, 0x71, 0x99, 0x6c, 0x83, 0x30, 0x55, 0xc2, 0xbd, 0xf4, 0x77, 0xe9, + 0x76, 0x97, 0xa0, 0xe0, 0xb9, 0x86, 0x6b, 0xa3, 0x84, 0x67, 0x1a, 0x70, 0x02, 0x5a, 0x41, 0x5c, + 0x25, 0x81, 0xaa, 0x28, 0x78, 0x4b, 0xc6, 0x64, 0x53, 0x16, 0x4d, 0x8b, 0x20, 0x93, 0xae, 0x0f, + 0x94, 0x2c, 0x3a, 0xc7, 0x62, 0xe8, 0xc4, 0xdb, 0x04, 0xc5, 0xfa, 0x29, 0x48, 0xd1, 0x08, 0x24, + 0x0d, 0xe2, 0xd8, 0x10, 0xb4, 0x91, 0x8a, 0x13, 0x0e, 0xdc, 0xd2, 0x79, 0xb8, 0xf8, 0xba, 0x2d, + 0xcb, 0xf5, 0x7d, 0x37, 0x51, 0x40, 0x31, 0xa2, 0x0b, 0x18, 0x63, 0x7f, 0xb3, 0xab, 0x9b, 0x87, + 0xf6, 0x90, 0xde, 0xc8, 0x27, 0x45, 0x7c, 0x1c, 0x85, 0x68, 0x33, 0x19, 0x03, 0x75, 0x15, 0x7a, + 0x1f, 0x49, 0x8f, 0x4c, 0xc1, 0x44, 0x17, 0x12, 0x6f, 0x32, 0xb7, 0x3e, 0x74, 0x1e, 0x21, 0x6a, +}; + + +static const UINT8 kof2000_address_8_15_xor1[256] = +{ + 0xfc, 0x9b, 0x1c, 0x35, 0x72, 0x53, 0xd6, 0x7d, 0x84, 0xa4, 0xc5, 0x93, 0x7b, 0xe7, 0x47, 0xd5, + 0x24, 0xa2, 0xfa, 0x19, 0x0c, 0xb1, 0x8c, 0xb9, 0x9d, 0xd8, 0x59, 0x4f, 0x3c, 0xb2, 0x78, 0x4a, + 0x2a, 0x96, 0x9a, 0xf1, 0x1f, 0x22, 0xa8, 0x5b, 0x67, 0xa3, 0x0f, 0x00, 0xfb, 0xdf, 0xeb, 0x0a, + 0x57, 0xb8, 0x25, 0xd7, 0xf0, 0x6b, 0x0b, 0x31, 0x95, 0x23, 0x2d, 0x5c, 0x27, 0xc7, 0xf4, 0x55, + 0x1a, 0xf7, 0x74, 0xbe, 0xd3, 0xac, 0x3d, 0xc1, 0x7f, 0xbd, 0x28, 0x01, 0x10, 0xe5, 0x09, 0x37, + 0x1e, 0x58, 0xaf, 0x17, 0xf2, 0x16, 0x30, 0x92, 0x36, 0x68, 0xe6, 0xd4, 0xea, 0xb7, 0x75, 0x54, + 0x77, 0x41, 0xb4, 0x8d, 0xe0, 0xf3, 0x51, 0x03, 0xa9, 0xe8, 0x66, 0xab, 0x29, 0xa5, 0xed, 0xcb, + 0xd1, 0xaa, 0xf5, 0xdb, 0x4c, 0x42, 0x97, 0x8a, 0xae, 0xc9, 0x6e, 0x04, 0x33, 0x85, 0xdd, 0x2b, + 0x6f, 0xef, 0x12, 0x21, 0x7a, 0xa1, 0x5a, 0x91, 0xc8, 0xcc, 0xc0, 0xa7, 0x60, 0x3e, 0x56, 0x2f, + 0xe4, 0x71, 0x99, 0xc2, 0xa0, 0x45, 0x80, 0x65, 0xbb, 0x87, 0x69, 0x81, 0x73, 0xca, 0xf6, 0x46, + 0x43, 0xda, 0x26, 0x7e, 0x8f, 0xe1, 0x8b, 0xfd, 0x50, 0x79, 0xba, 0xc6, 0x63, 0x4b, 0xb3, 0x8e, + 0x34, 0xe2, 0x48, 0x14, 0xcd, 0xe3, 0xc4, 0x05, 0x13, 0x40, 0x06, 0x6c, 0x88, 0xb0, 0xe9, 0x1b, + 0x4d, 0xf8, 0x76, 0x02, 0x44, 0x94, 0xcf, 0x32, 0xfe, 0xce, 0x3b, 0x5d, 0x2c, 0x89, 0x5f, 0xdc, + 0xd2, 0x9c, 0x6a, 0xec, 0x18, 0x6d, 0x0e, 0x86, 0xff, 0x5e, 0x9e, 0xee, 0x11, 0xd0, 0x49, 0x52, + 0x4e, 0x61, 0x90, 0x0d, 0xc3, 0x39, 0x15, 0x83, 0xb5, 0x62, 0x3f, 0x70, 0x7c, 0xad, 0x20, 0xbf, + 0x2e, 0x08, 0x1d, 0xf9, 0xb6, 0xa6, 0x64, 0x07, 0x82, 0x38, 0x98, 0x3a, 0x9f, 0xde, 0xbc, 0xd9, +}; + + +static const UINT8 kof2000_address_8_15_xor2[256] = +{ + 0x00, 0xbe, 0x06, 0x5a, 0xfa, 0x42, 0x15, 0xf2, 0x3f, 0x0a, 0x84, 0x93, 0x4e, 0x78, 0x3b, 0x89, + 0x32, 0x98, 0xa2, 0x87, 0x73, 0xdd, 0x26, 0xe5, 0x05, 0x71, 0x08, 0x6e, 0x9b, 0xe0, 0xdf, 0x9e, + 0xfc, 0x83, 0x81, 0xef, 0xb2, 0xc0, 0xc3, 0xbf, 0xa7, 0x6d, 0x1b, 0x95, 0xed, 0xb9, 0x3e, 0x13, + 0xb0, 0x47, 0x9c, 0x7a, 0x24, 0x41, 0x68, 0xd0, 0x36, 0x0b, 0xb5, 0xc2, 0x67, 0xf7, 0x54, 0x92, + 0x1e, 0x44, 0x86, 0x2b, 0x94, 0xcc, 0xba, 0x23, 0x0d, 0xca, 0x6b, 0x4c, 0x2a, 0x9a, 0x2d, 0x8b, + 0xe3, 0x52, 0x29, 0xf0, 0x21, 0xbd, 0xbb, 0x1f, 0xa3, 0xab, 0xf8, 0x46, 0xb7, 0x45, 0x82, 0x5e, + 0xdb, 0x07, 0x5d, 0xe9, 0x9d, 0x1a, 0x48, 0xce, 0x91, 0x12, 0xd4, 0xee, 0xa9, 0x39, 0xf1, 0x18, + 0x2c, 0x22, 0x8a, 0x7e, 0x34, 0x4a, 0x8c, 0xc1, 0x14, 0xf3, 0x20, 0x35, 0xd9, 0x96, 0x33, 0x77, + 0x9f, 0x76, 0x7c, 0x90, 0xc6, 0xd5, 0xa1, 0x5b, 0xac, 0x75, 0xc7, 0x0c, 0xb3, 0x17, 0xd6, 0x99, + 0x56, 0xa6, 0x3d, 0x1d, 0xb1, 0x2e, 0xd8, 0xbc, 0x2f, 0xde, 0x60, 0x55, 0x6c, 0x40, 0xcd, 0x43, + 0xff, 0xad, 0x38, 0x79, 0x51, 0xc8, 0x0e, 0x5f, 0xc4, 0x66, 0xcb, 0xa8, 0x7d, 0xa4, 0x3a, 0xea, + 0x27, 0x7b, 0x70, 0x8e, 0x5c, 0x19, 0x0f, 0x80, 0x6f, 0x8f, 0x10, 0xf9, 0x49, 0x85, 0x69, 0x7f, + 0xeb, 0x1c, 0x01, 0x65, 0x37, 0xa5, 0x28, 0xe4, 0x6a, 0x03, 0x04, 0xd1, 0x31, 0x11, 0x30, 0xfb, + 0x88, 0x97, 0xd3, 0xf6, 0xc5, 0x4d, 0xf5, 0x3c, 0xe8, 0x61, 0xdc, 0xd2, 0xb4, 0xb8, 0xa0, 0xae, + 0x16, 0x25, 0x02, 0x09, 0xfe, 0xcf, 0x53, 0x63, 0xaf, 0x59, 0xf4, 0xe1, 0xec, 0xd7, 0xe7, 0x50, + 0xe2, 0xc9, 0xaa, 0x4b, 0x8d, 0x4f, 0xe6, 0x64, 0xda, 0x74, 0xb6, 0x72, 0x57, 0x62, 0xfd, 0x58, +}; + + +static const UINT8 kof2000_address_16_23_xor1[256] = +{ + 0x45, 0x9f, 0x6e, 0x2f, 0x28, 0xbc, 0x5e, 0x6d, 0xda, 0xb5, 0x0d, 0xb8, 0xc0, 0x8e, 0xa2, 0x32, + 0xee, 0xcd, 0x8d, 0x48, 0x8c, 0x27, 0x14, 0xeb, 0x65, 0xd7, 0xf2, 0x93, 0x99, 0x90, 0x91, 0xfc, + 0x5f, 0xcb, 0xfa, 0x75, 0x3f, 0x26, 0xde, 0x72, 0x33, 0x39, 0xc7, 0x1f, 0x88, 0x79, 0x73, 0xab, + 0x4e, 0x36, 0x5d, 0x44, 0xd2, 0x41, 0xa0, 0x7e, 0xa7, 0x8b, 0xa6, 0xbf, 0x03, 0xd8, 0x86, 0xdc, + 0x2c, 0xaa, 0x70, 0x3d, 0x46, 0x07, 0x80, 0x58, 0x0b, 0x2b, 0xe2, 0xf0, 0xb1, 0xfe, 0x42, 0xf3, + 0xe9, 0xa3, 0x85, 0x78, 0xc3, 0xd0, 0x5a, 0xdb, 0x1a, 0xfb, 0x9d, 0x8a, 0xa5, 0x12, 0x0e, 0x54, + 0x8f, 0xc5, 0x6c, 0xae, 0x25, 0x5b, 0x4b, 0x17, 0x02, 0x9c, 0x4a, 0x24, 0x40, 0xe5, 0x9e, 0x22, + 0xc6, 0x49, 0x62, 0xb6, 0x6b, 0xbb, 0xa8, 0xcc, 0xe8, 0x81, 0x50, 0x47, 0xc8, 0xbe, 0x5c, 0xa4, + 0xd6, 0x94, 0x4f, 0x7b, 0x9a, 0xcf, 0xe4, 0x59, 0x7a, 0xa1, 0xea, 0x31, 0x37, 0x13, 0x2d, 0xaf, + 0x21, 0x69, 0x19, 0x1d, 0x6f, 0x16, 0x98, 0x1e, 0x08, 0xe3, 0xb2, 0x4d, 0x9b, 0x7f, 0xa9, 0x77, + 0xed, 0xbd, 0xd4, 0xd9, 0x34, 0xd3, 0xca, 0x09, 0x18, 0x60, 0xc9, 0x6a, 0x01, 0xf4, 0xf6, 0x64, + 0xb4, 0x3a, 0x15, 0xac, 0x89, 0x52, 0x68, 0x71, 0xe7, 0x82, 0xc1, 0x0c, 0x92, 0xf7, 0x30, 0xe6, + 0x1c, 0x3e, 0x0f, 0x0a, 0x67, 0x35, 0xba, 0x61, 0xdd, 0x29, 0xc2, 0xf8, 0x97, 0x95, 0xb7, 0x3b, + 0xe0, 0xce, 0xf9, 0xd5, 0x06, 0x76, 0xb3, 0x05, 0x4c, 0x04, 0x84, 0x3c, 0x87, 0x23, 0x63, 0x7c, + 0x53, 0x56, 0xe1, 0x7d, 0x96, 0x1b, 0xd1, 0xec, 0x2a, 0x66, 0xf1, 0x11, 0x10, 0xff, 0x43, 0x2e, + 0xdf, 0x83, 0x74, 0xf5, 0x38, 0x20, 0xfd, 0xad, 0xc4, 0xb9, 0x55, 0x51, 0xb0, 0xef, 0x00, 0x57, +}; + + +static const UINT8 kof2000_address_16_23_xor2[256] = +{ + 0x00, 0xb8, 0xf0, 0x34, 0xca, 0x21, 0x3c, 0xf9, 0x01, 0x8e, 0x75, 0x70, 0xec, 0x13, 0x27, 0x96, + 0xf4, 0x5b, 0x88, 0x1f, 0xeb, 0x4a, 0x7d, 0x9d, 0xbe, 0x02, 0x14, 0xaf, 0xa2, 0x06, 0xc6, 0xdb, + 0x35, 0x6b, 0x74, 0x45, 0x7b, 0x29, 0xd2, 0xfe, 0xb6, 0x15, 0xd0, 0x8a, 0xa9, 0x2d, 0x19, 0xf6, + 0x5e, 0x5a, 0x90, 0xe9, 0x11, 0x33, 0xc2, 0x47, 0x37, 0x4c, 0x4f, 0x59, 0xc3, 0x04, 0x57, 0x1d, + 0xf2, 0x63, 0x6d, 0x6e, 0x31, 0x95, 0xcb, 0x3e, 0x67, 0xb2, 0xe3, 0x98, 0xed, 0x8d, 0xe6, 0xfb, + 0xf8, 0xba, 0x5d, 0xd4, 0x2a, 0xf5, 0x3b, 0x82, 0x05, 0x16, 0x44, 0xef, 0x4d, 0xe7, 0x93, 0xda, + 0x9f, 0xbb, 0x61, 0xc9, 0x53, 0xbd, 0x76, 0x78, 0x52, 0x36, 0x0c, 0x66, 0xc1, 0x10, 0xdd, 0x7a, + 0x84, 0x69, 0xcd, 0xfd, 0x58, 0x0d, 0x6c, 0x89, 0x68, 0xad, 0x3a, 0xb0, 0x4b, 0x46, 0xc5, 0x03, + 0xb4, 0xf7, 0x30, 0x8c, 0x4e, 0x60, 0x73, 0xa1, 0x8b, 0xb1, 0x62, 0xcc, 0xd1, 0x08, 0xfc, 0x77, + 0x7e, 0xcf, 0x56, 0x51, 0x07, 0xa6, 0x80, 0x92, 0xdc, 0x0b, 0xa4, 0xc7, 0xe8, 0xe1, 0xb5, 0x71, + 0xea, 0xb3, 0x2f, 0x94, 0x18, 0xe2, 0x3d, 0x49, 0x65, 0xaa, 0xf1, 0x91, 0xc8, 0x99, 0x55, 0x79, + 0x86, 0xa7, 0x26, 0xa0, 0xac, 0x5f, 0xce, 0x6a, 0x5c, 0xf3, 0x87, 0x8f, 0x12, 0x1c, 0xd8, 0xe4, + 0x9b, 0x64, 0x2e, 0x1e, 0xd7, 0xc0, 0x17, 0xbc, 0xa3, 0xa8, 0x9a, 0x0e, 0x25, 0x40, 0x41, 0x50, + 0xb9, 0xbf, 0x28, 0xdf, 0x32, 0x54, 0x9e, 0x48, 0xd5, 0x2b, 0x42, 0xfa, 0x9c, 0x7f, 0xd3, 0x85, + 0x43, 0xde, 0x81, 0x0f, 0x24, 0xc4, 0x38, 0xae, 0x83, 0x1b, 0x6f, 0x7c, 0xe5, 0xff, 0x1a, 0xd9, + 0x3f, 0xb7, 0x22, 0x97, 0x09, 0xe0, 0xa5, 0x20, 0x23, 0x2c, 0x72, 0xd6, 0x39, 0xab, 0x0a, 0xee, +}; + + +static const UINT8 kof2000_address_0_7_xor[256] = +{ + 0x26, 0x48, 0x06, 0x9b, 0x21, 0xa9, 0x1b, 0x76, 0xc9, 0xf8, 0xb4, 0x67, 0xe4, 0xff, 0x99, 0xf7, + 0x15, 0x9e, 0x62, 0x00, 0x72, 0x4d, 0xa0, 0x4f, 0x02, 0xf1, 0xea, 0xef, 0x0b, 0xf3, 0xeb, 0xa6, + 0x93, 0x78, 0x6f, 0x7c, 0xda, 0xd4, 0x7b, 0x05, 0xe9, 0xc6, 0xd6, 0xdb, 0x50, 0xce, 0xd2, 0x01, + 0xb5, 0xe8, 0xe0, 0x2a, 0x08, 0x1a, 0xb8, 0xe3, 0xf9, 0xb1, 0xf4, 0x8b, 0x39, 0x2d, 0x85, 0x9c, + 0x55, 0x73, 0x63, 0x40, 0x38, 0x96, 0xdc, 0xa3, 0xa2, 0xa1, 0x25, 0x66, 0x6d, 0x56, 0x8e, 0x10, + 0x0f, 0x31, 0x1c, 0xf5, 0x28, 0x77, 0x0a, 0xd1, 0x75, 0x34, 0xa4, 0xfe, 0x7d, 0x07, 0x51, 0x79, + 0x41, 0x90, 0x22, 0x35, 0x12, 0xbb, 0xc4, 0xca, 0xb2, 0x1f, 0xcb, 0xc8, 0xac, 0xdd, 0xd0, 0x0d, + 0xfc, 0xc5, 0x9d, 0x14, 0xbc, 0x83, 0xd9, 0x58, 0xc2, 0x30, 0x9a, 0x6a, 0xc0, 0x0c, 0xad, 0xf6, + 0x5d, 0x74, 0x7f, 0x2f, 0xbd, 0x1d, 0x47, 0xd5, 0xe6, 0x89, 0xcf, 0xb7, 0xd3, 0x59, 0x36, 0x98, + 0xf0, 0xfb, 0x3c, 0xf2, 0x3f, 0xa7, 0x18, 0x82, 0x42, 0x5c, 0xab, 0xba, 0xde, 0x52, 0x09, 0x91, + 0xaa, 0x61, 0xec, 0xd7, 0x95, 0x23, 0xcd, 0x80, 0xa5, 0x68, 0x60, 0x27, 0x71, 0xe1, 0x2c, 0x2e, + 0x8d, 0x2b, 0x57, 0x65, 0xbf, 0xc1, 0x19, 0xc7, 0x49, 0x64, 0x88, 0x4a, 0xcc, 0x20, 0x4e, 0xd8, + 0x3b, 0x4c, 0x13, 0x5f, 0x9f, 0xbe, 0x5e, 0x6e, 0xfd, 0xe2, 0xfa, 0x54, 0x37, 0x0e, 0x16, 0x7a, + 0x6c, 0x33, 0xb3, 0x70, 0x84, 0x7e, 0xc3, 0x04, 0xb0, 0xae, 0xb9, 0x81, 0x03, 0x29, 0xdf, 0x46, + 0xe5, 0x69, 0xe7, 0x24, 0x92, 0x5a, 0x4b, 0x5b, 0x94, 0x11, 0x3a, 0x3d, 0x87, 0xed, 0x97, 0xb6, + 0x32, 0x3e, 0x45, 0xaf, 0x1e, 0x43, 0x44, 0x8c, 0x53, 0x86, 0x6b, 0xee, 0xa8, 0x8a, 0x8f, 0x17, +}; + + + +void cmc_prot_device::decrypt(UINT8 *r0, UINT8 *r1, + UINT8 c0, UINT8 c1, + const UINT8 *table0hi, + const UINT8 *table0lo, + const UINT8 *table1, + int base, + int invert) +{ + UINT8 tmp,xor0,xor1; + + tmp = table1[(base & 0xff) ^ address_0_7_xor[(base >> 8) & 0xff]]; + xor0 = (table0hi[(base >> 8) & 0xff] & 0xfe) | (tmp & 0x01); + xor1 = (tmp & 0xfe) | (table0lo[(base >> 8) & 0xff] & 0x01); + + if (invert) + { + *r0 = c1 ^ xor0; + *r1 = c0 ^ xor1; + } + else + { + *r0 = c0 ^ xor0; + *r1 = c1 ^ xor1; + } +} + + +void cmc_prot_device::neogeo_gfx_decrypt(UINT8* rom, UINT32 rom_size, int extra_xor) +{ + int rpos; + + + dynamic_buffer buf(rom_size); + + // Data xor + for (rpos = 0;rpos < rom_size/4;rpos++) + { + decrypt(&buf[4*rpos+0], &buf[4*rpos+3], rom[4*rpos+0], rom[4*rpos+3], type0_t03, type0_t12, type1_t03, rpos, (rpos>>8) & 1); + decrypt(&buf[4*rpos+1], &buf[4*rpos+2], rom[4*rpos+1], rom[4*rpos+2], type0_t12, type0_t03, type1_t12, rpos, ((rpos>>16) ^ address_16_23_xor2[(rpos>>8) & 0xff]) & 1); + } + + // Address xor + for (rpos = 0;rpos < rom_size/4;rpos++) + { + int baser; + + baser = rpos; + + baser ^= extra_xor; + + baser ^= address_8_15_xor1[(baser >> 16) & 0xff] << 8; + baser ^= address_8_15_xor2[baser & 0xff] << 8; + baser ^= address_16_23_xor1[baser & 0xff] << 16; + baser ^= address_16_23_xor2[(baser >> 8) & 0xff] << 16; + baser ^= address_0_7_xor[(baser >> 8) & 0xff]; + + + if (rom_size == 0x3000000) /* special handling for preisle2 */ + { + if (rpos < 0x2000000/4) + baser &= (0x2000000/4)-1; + else + baser = 0x2000000/4 + (baser & ((0x1000000/4)-1)); + } + else if (rom_size == 0x6000000) /* special handling for kf2k3pcb */ + { + if (rpos < 0x4000000/4) + baser &= (0x4000000/4)-1; + else + baser = 0x4000000/4 + (baser & ((0x1000000/4)-1)); + } + else /* Clamp to the real rom size */ + baser &= (rom_size/4)-1; + + rom[4*rpos+0] = buf[4*baser+0]; + rom[4*rpos+1] = buf[4*baser+1]; + rom[4*rpos+2] = buf[4*baser+2]; + rom[4*rpos+3] = buf[4*baser+3]; + } +} + + +/* the S data comes from the end of the C data */ +void cmc_prot_device::neogeo_sfix_decrypt(UINT8* rom, UINT32 rom_size, UINT8* fixed, UINT32 fixed_size) +{ + int i; + int tx_size = fixed_size; + UINT8 *src = rom+rom_size-tx_size; + UINT8 *dst = fixed; + + for (i = 0;i < tx_size;i++) + dst[i] = src[(i & ~0x1f) + ((i & 7) << 2) + ((~i & 8) >> 2) + ((i & 0x10) >> 4)]; +} + + +/* CMC42 protection chip */ +void cmc_prot_device::kof99_neogeo_gfx_decrypt(UINT8* rom, UINT32 rom_size, UINT8* fixed, UINT32 fixed_size, int extra_xor) +{ + type0_t03 = kof99_type0_t03; + type0_t12 = kof99_type0_t12; + type1_t03 = kof99_type1_t03; + type1_t12 = kof99_type1_t12; + address_8_15_xor1 = kof99_address_8_15_xor1; + address_8_15_xor2 = kof99_address_8_15_xor2; + address_16_23_xor1 = kof99_address_16_23_xor1; + address_16_23_xor2 = kof99_address_16_23_xor2; + address_0_7_xor = kof99_address_0_7_xor; + neogeo_gfx_decrypt(rom, rom_size, extra_xor); + neogeo_sfix_decrypt(rom, rom_size, fixed, fixed_size); +} + + +/* CMC50 protection chip */ +void cmc_prot_device::kof2000_neogeo_gfx_decrypt(UINT8* rom, UINT32 rom_size, UINT8* fixed, UINT32 fixed_size, int extra_xor) +{ + type0_t03 = kof2000_type0_t03; + type0_t12 = kof2000_type0_t12; + type1_t03 = kof2000_type1_t03; + type1_t12 = kof2000_type1_t12; + address_8_15_xor1 = kof2000_address_8_15_xor1; + address_8_15_xor2 = kof2000_address_8_15_xor2; + address_16_23_xor1 = kof2000_address_16_23_xor1; + address_16_23_xor2 = kof2000_address_16_23_xor2; + address_0_7_xor = kof2000_address_0_7_xor; + neogeo_gfx_decrypt(rom, rom_size, extra_xor); + neogeo_sfix_decrypt(rom, rom_size, fixed, fixed_size); +} + + +/* CMC42 protection chip */ +void cmc_prot_device::cmc42_neogeo_gfx_decrypt(UINT8* rom, UINT32 rom_size, UINT8* fixed, UINT32 fixed_size, int extra_xor) +{ + type0_t03 = kof99_type0_t03; + type0_t12 = kof99_type0_t12; + type1_t03 = kof99_type1_t03; + type1_t12 = kof99_type1_t12; + address_8_15_xor1 = kof99_address_8_15_xor1; + address_8_15_xor2 = kof99_address_8_15_xor2; + address_16_23_xor1 = kof99_address_16_23_xor1; + address_16_23_xor2 = kof99_address_16_23_xor2; + address_0_7_xor = kof99_address_0_7_xor; + neogeo_gfx_decrypt(rom, rom_size, extra_xor); +} + + +/* CMC50 protection chip */ +void cmc_prot_device::cmc50_neogeo_gfx_decrypt(UINT8* rom, UINT32 rom_size, UINT8* fixed, UINT32 fixed_size, int extra_xor) +{ + type0_t03 = kof2000_type0_t03; + type0_t12 = kof2000_type0_t12; + type1_t03 = kof2000_type1_t03; + type1_t12 = kof2000_type1_t12; + address_8_15_xor1 = kof2000_address_8_15_xor1; + address_8_15_xor2 = kof2000_address_8_15_xor2; + address_16_23_xor1 = kof2000_address_16_23_xor1; + address_16_23_xor2 = kof2000_address_16_23_xor2; + address_0_7_xor = kof2000_address_0_7_xor; + neogeo_gfx_decrypt(rom, rom_size, extra_xor); +} + + + +/*************************************************************************** + +NeoGeo 'M' ROM encryption + CMC50 protection chip + +***************************************************************************/ + + +static const UINT8 m1_address_8_15_xor[256] = +{ + 0x0a, 0x72, 0xb7, 0xaf, 0x67, 0xde, 0x1d, 0xb1, 0x78, 0xc4, 0x4f, 0xb5, 0x4b, 0x18, 0x76, 0xdd, + 0x11, 0xe2, 0x36, 0xa1, 0x82, 0x03, 0x98, 0xa0, 0x10, 0x5f, 0x3f, 0xd6, 0x1f, 0x90, 0x6a, 0x0b, + 0x70, 0xe0, 0x64, 0xcb, 0x9f, 0x38, 0x8b, 0x53, 0x04, 0xca, 0xf8, 0xd0, 0x07, 0x68, 0x56, 0x32, + 0xae, 0x1c, 0x2e, 0x48, 0x63, 0x92, 0x9a, 0x9c, 0x44, 0x85, 0x41, 0x40, 0x09, 0xc0, 0xc8, 0xbf, + 0xea, 0xbb, 0xf7, 0x2d, 0x99, 0x21, 0xf6, 0xba, 0x15, 0xce, 0xab, 0xb0, 0x2a, 0x60, 0xbc, 0xf1, + 0xf0, 0x9e, 0xd5, 0x97, 0xd8, 0x4e, 0x14, 0x9d, 0x42, 0x4d, 0x2c, 0x5c, 0x2b, 0xa6, 0xe1, 0xa7, + 0xef, 0x25, 0x33, 0x7a, 0xeb, 0xe7, 0x1b, 0x6d, 0x4c, 0x52, 0x26, 0x62, 0xb6, 0x35, 0xbe, 0x80, + 0x01, 0xbd, 0xfd, 0x37, 0xf9, 0x47, 0x55, 0x71, 0xb4, 0xf2, 0xff, 0x27, 0xfa, 0x23, 0xc9, 0x83, + 0x17, 0x39, 0x13, 0x0d, 0xc7, 0x86, 0x16, 0xec, 0x49, 0x6f, 0xfe, 0x34, 0x05, 0x8f, 0x00, 0xe6, + 0xa4, 0xda, 0x7b, 0xc1, 0xf3, 0xf4, 0xd9, 0x75, 0x28, 0x66, 0x87, 0xa8, 0x45, 0x6c, 0x20, 0xe9, + 0x77, 0x93, 0x7e, 0x3c, 0x1e, 0x74, 0xf5, 0x8c, 0x3e, 0x94, 0xd4, 0xc2, 0x5a, 0x06, 0x0e, 0xe8, + 0x3d, 0xa9, 0xb2, 0xe3, 0xe4, 0x22, 0xcf, 0x24, 0x8e, 0x6b, 0x8a, 0x8d, 0x84, 0x4a, 0xd2, 0x91, + 0x88, 0x79, 0x57, 0xa5, 0x0f, 0xcd, 0xb9, 0xac, 0x3b, 0xaa, 0xb3, 0xd1, 0xee, 0x31, 0x81, 0x7c, + 0xd7, 0x89, 0xd3, 0x96, 0x43, 0xc5, 0xc6, 0xc3, 0x69, 0x7f, 0x46, 0xdf, 0x30, 0x5b, 0x6e, 0xe5, + 0x08, 0x95, 0x9b, 0xfb, 0xb8, 0x58, 0x0c, 0x61, 0x50, 0x5d, 0x3a, 0xa2, 0x29, 0x12, 0xfc, 0x51, + 0x7d, 0x1a, 0x02, 0x65, 0x54, 0x5e, 0x19, 0xcc, 0xdc, 0xdb, 0x73, 0xed, 0xad, 0x59, 0x2f, 0xa3, +}; + +static const UINT8 m1_address_0_7_xor[256] = +{ + 0xf4, 0xbc, 0x02, 0xf7, 0x2c, 0x3d, 0xe8, 0xd9, 0x50, 0x62, 0xec, 0xbd, 0x53, 0x73, 0x79, 0x61, + 0x00, 0x34, 0xcf, 0xa2, 0x63, 0x28, 0x90, 0xaf, 0x44, 0x3b, 0xc5, 0x8d, 0x3a, 0x46, 0x07, 0x70, + 0x66, 0xbe, 0xd8, 0x8b, 0xe9, 0xa0, 0x4b, 0x98, 0xdc, 0xdf, 0xe2, 0x16, 0x74, 0xf1, 0x37, 0xf5, + 0xb7, 0x21, 0x81, 0x01, 0x1c, 0x1b, 0x94, 0x36, 0x09, 0xa1, 0x4a, 0x91, 0x30, 0x92, 0x9b, 0x9a, + 0x29, 0xb1, 0x38, 0x4d, 0x55, 0xf2, 0x56, 0x18, 0x24, 0x47, 0x9d, 0x3f, 0x80, 0x1f, 0x22, 0xa4, + 0x11, 0x54, 0x84, 0x0d, 0x25, 0x48, 0xee, 0xc6, 0x59, 0x15, 0x03, 0x7a, 0xfd, 0x6c, 0xc3, 0x33, + 0x5b, 0xc4, 0x7b, 0x5a, 0x05, 0x7f, 0xa6, 0x40, 0xa9, 0x5d, 0x41, 0x8a, 0x96, 0x52, 0xd3, 0xf0, + 0xab, 0x72, 0x10, 0x88, 0x6f, 0x95, 0x7c, 0xa8, 0xcd, 0x9c, 0x5f, 0x32, 0xae, 0x85, 0x39, 0xac, + 0xe5, 0xd7, 0xfb, 0xd4, 0x08, 0x23, 0x19, 0x65, 0x6b, 0xa7, 0x93, 0xbb, 0x2b, 0xbf, 0xb8, 0x35, + 0xd0, 0x06, 0x26, 0x68, 0x3e, 0xdd, 0xb9, 0x69, 0x2a, 0xb2, 0xde, 0x87, 0x45, 0x58, 0xff, 0x3c, + 0x9e, 0x7d, 0xda, 0xed, 0x49, 0x8c, 0x14, 0x8e, 0x75, 0x2f, 0xe0, 0x6e, 0x78, 0x6d, 0x20, 0xd2, + 0xfa, 0x2d, 0x51, 0xcc, 0xc7, 0xe7, 0x1d, 0x27, 0x97, 0xfc, 0x31, 0xdb, 0xf8, 0x42, 0xe3, 0x99, + 0x5e, 0x83, 0x0e, 0xb4, 0x2e, 0xf6, 0xc0, 0x0c, 0x4c, 0x57, 0xb6, 0x64, 0x0a, 0x17, 0xa3, 0xc1, + 0x77, 0x12, 0xfe, 0xe6, 0x8f, 0x13, 0x71, 0xe4, 0xf9, 0xad, 0x9f, 0xce, 0xd5, 0x89, 0x7e, 0x0f, + 0xc2, 0x86, 0xf3, 0x67, 0xba, 0x60, 0x43, 0xc9, 0x04, 0xb3, 0xb0, 0x1e, 0xb5, 0xc8, 0xeb, 0xa5, + 0x76, 0xea, 0x5c, 0x82, 0x1a, 0x4f, 0xaa, 0xca, 0xe1, 0x0b, 0x4e, 0xcb, 0x6a, 0xef, 0xd1, 0xd6, +}; + + +/* The CMC50 hardware does a checksum of the first 64kb of the M1 rom, + ,and uses this checksum as the basis of the key with which to decrypt + the rom */ + +UINT16 cmc_prot_device::generate_cs16(UINT8 *rom, int size) +{ + UINT16 cs16; + int i; + cs16 = 0x0000; + for (i=0;i>16)&7; + aux = address&0xffff; + + aux ^= BITSWAP16(key,12,0,2,4,8,15,7,13,10,1,3,6,11,9,14,5); + aux = BITSWAP16(aux, + p1[block][15],p1[block][14],p1[block][13],p1[block][12], + p1[block][11],p1[block][10],p1[block][9],p1[block][8], + p1[block][7],p1[block][6],p1[block][5],p1[block][4], + p1[block][3],p1[block][2],p1[block][1],p1[block][0]); + aux ^= m1_address_0_7_xor[(aux>>8)&0xff]; + aux ^= m1_address_8_15_xor[aux&0xff]<<8; + aux = BITSWAP16(aux, 7,15,14,6,5,13,12,4,11,3,10,2,9,1,8,0); + + return (block<<16)|aux; +} + + +void cmc_prot_device::neogeo_cmc50_m1_decrypt(UINT8* romcrypt, UINT32 romcrypt_size, UINT8* romaudio, UINT32 romaudio_size) +{ + UINT8* rom = romcrypt; + size_t rom_size = 0x80000; + UINT8* rom2 = romaudio; + + dynamic_buffer buffer(rom_size); + + UINT32 i; + + UINT16 key=generate_cs16(rom,0x10000); + + //printf("key %04x\n",key); + + for (i=0; i; + + +neogeo_fatfury2_cart::neogeo_fatfury2_cart(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT16 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_neogeo_cart_interface( mconfig, *this ), + m_banked_cart(*this, "banked_cart"), + m_fatfury2_prot(*this, "fatfury2_prot") +{ +} + +neogeo_fatfury2_cart::neogeo_fatfury2_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT16 clock) + : device_t(mconfig, NEOGEO_FATFURY2_CART, "NEOGEO Fatal Fury 2 Cart", tag, owner, clock, "neogeo_rom", __FILE__), + device_neogeo_cart_interface( mconfig, *this ), + m_banked_cart(*this, "banked_cart"), + m_fatfury2_prot(*this, "fatfury2_prot") +{ +} + + +//------------------------------------------------- +// mapper specific start/reset +//------------------------------------------------- + +void neogeo_fatfury2_cart::device_start() +{ +} + +void neogeo_fatfury2_cart::device_reset() +{ +} + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +READ16_MEMBER(neogeo_fatfury2_cart::read_rom) +{ + return m_rom[offset]; +} + +static MACHINE_CONFIG_FRAGMENT( fatfury2_cart ) + MCFG_NEOGEO_BANKED_CART_ADD("banked_cart") + MCFG_FATFURY2_PROT_ADD("fatfury2_prot") + +MACHINE_CONFIG_END + +machine_config_constructor neogeo_fatfury2_cart::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( fatfury2_cart ); +} + +void neogeo_fatfury2_cart::activate_cart(ACTIVATE_CART_PARAMS) +{ + m_banked_cart->install_banks(machine, maincpu, cpuregion, cpuregion_size); + m_fatfury2_prot->fatfury2_install_protection(maincpu, m_banked_cart); +} diff --git a/src/devices/bus/neogeo/fatfury2_cart.h b/src/devices/bus/neogeo/fatfury2_cart.h new file mode 100644 index 00000000000..1356d130bf9 --- /dev/null +++ b/src/devices/bus/neogeo/fatfury2_cart.h @@ -0,0 +1,41 @@ +// license:BSD-3-Clause +// copyright-holders:S. Smith,David Haywood +#ifndef __NEOGEO_FATFURY2_CART_H +#define __NEOGEO_FATFURY2_CART_H + +#include "neogeo_slot.h" +#include "banked_cart.h" +#include "fatfury2_prot.h" + +// ======================> neogeo_fatfury2_cart + +class neogeo_fatfury2_cart : public device_t, + public device_neogeo_cart_interface +{ +public: + // construction/destruction + neogeo_fatfury2_cart(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT16 clock, const char *shortname, const char *source); + neogeo_fatfury2_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT16 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual machine_config_constructor device_mconfig_additions() const; + + // reading and writing + virtual DECLARE_READ16_MEMBER(read_rom); + + virtual void activate_cart(ACTIVATE_CART_PARAMS); + + required_device m_banked_cart; + required_device m_fatfury2_prot; + +}; + + + +// device type definition +extern const device_type NEOGEO_FATFURY2_CART; + + +#endif diff --git a/src/devices/bus/neogeo/fatfury2_prot.c b/src/devices/bus/neogeo/fatfury2_prot.c new file mode 100644 index 00000000000..07e483dbc44 --- /dev/null +++ b/src/devices/bus/neogeo/fatfury2_prot.c @@ -0,0 +1,110 @@ +// license:BSD-3-Clause +// copyright-holders:S. Smith,David Haywood + +#include "emu.h" +#include "fatfury2_prot.h" + + + +extern const device_type FATFURY2_PROT = &device_creator; + + +fatfury2_prot_device::fatfury2_prot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, FATFURY2_PROT, "NeoGeo Protection (Fatal Fury 2)", tag, owner, clock, "fatfury2_prot", __FILE__) +{ +} + + +void fatfury2_prot_device::device_start() +{ + save_item(NAME(m_fatfury2_prot_data)); +} + +void fatfury2_prot_device::device_reset() +{ +} + + + +/************************ Fatal Fury 2 *************************/ + +READ16_MEMBER( fatfury2_prot_device::fatfury2_protection_16_r ) +{ + UINT16 res = m_fatfury2_prot_data >> 24; + + switch (offset) + { + case 0x55550/2: + case 0xffff0/2: + case 0x00000/2: + case 0xff000/2: + case 0x36000/2: + case 0x36008/2: + return res; + + case 0x36004/2: + case 0x3600c/2: + return ((res & 0xf0) >> 4) | ((res & 0x0f) << 4); + + default: + logerror("unknown protection read at pc %06x, offset %08x\n", space.device().safe_pc(), offset << 1); + return 0; + } +} + + +WRITE16_MEMBER( fatfury2_prot_device::fatfury2_protection_16_w ) +{ + switch (offset) + { + case 0x11112/2: /* data == 0x1111; expects 0xff000000 back */ + m_fatfury2_prot_data = 0xff000000; + break; + + case 0x33332/2: /* data == 0x3333; expects 0x0000ffff back */ + m_fatfury2_prot_data = 0x0000ffff; + break; + + case 0x44442/2: /* data == 0x4444; expects 0x00ff0000 back */ + m_fatfury2_prot_data = 0x00ff0000; + break; + + case 0x55552/2: /* data == 0x5555; read back from 55550, ffff0, 00000, ff000 */ + m_fatfury2_prot_data = 0xff00ff00; + break; + + case 0x56782/2: /* data == 0x1234; read back from 36000 *or* 36004 */ + m_fatfury2_prot_data = 0xf05a3601; + break; + + case 0x42812/2: /* data == 0x1824; read back from 36008 *or* 3600c */ + m_fatfury2_prot_data = 0x81422418; + break; + + case 0x55550/2: + case 0xffff0/2: + case 0xff000/2: + case 0x36000/2: + case 0x36004/2: + case 0x36008/2: + case 0x3600c/2: + m_fatfury2_prot_data <<= 8; + break; + + default: + logerror("unknown protection write at pc %06x, offset %08x, data %02x\n", space.device().safe_pc(), offset, data); + break; + } +} + + +void fatfury2_prot_device::fatfury2_install_protection(cpu_device* maincpu, neogeo_banked_cart_device* bankdev) +{ + /* the protection involves reading and writing addresses in the */ + /* 0x2xxxxx range. There are several checks all around the code. */ + maincpu->space(AS_PROGRAM).install_readwrite_handler(0x200000, 0x2fffff, read16_delegate(FUNC(fatfury2_prot_device::fatfury2_protection_16_r),this), write16_delegate(FUNC(fatfury2_prot_device::fatfury2_protection_16_w),this)); + m_bankdev = bankdev; + + m_fatfury2_prot_data = 0; + +} diff --git a/src/devices/bus/neogeo/fatfury2_prot.h b/src/devices/bus/neogeo/fatfury2_prot.h new file mode 100644 index 00000000000..2abe9c92da6 --- /dev/null +++ b/src/devices/bus/neogeo/fatfury2_prot.h @@ -0,0 +1,42 @@ +// license:BSD-3-Clause +// copyright-holders:S. Smith,David Haywood + +#pragma once + +#ifndef __FATFURY2_PROT__ +#define __FATFURY2_PROT__ + +#include "banked_cart.h" + +extern const device_type FATFURY2_PROT; + +#define MCFG_FATFURY2_PROT_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, FATFURY2_PROT, 0) + + +class fatfury2_prot_device : public device_t +{ +public: + // construction/destruction + fatfury2_prot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + DECLARE_READ16_MEMBER( fatfury2_protection_16_r ); + DECLARE_WRITE16_MEMBER( fatfury2_protection_16_w ); + void fatfury2_install_protection(cpu_device* maincpu, neogeo_banked_cart_device* bankdev); + + + neogeo_banked_cart_device* m_bankdev; + UINT32 m_fatfury2_prot_data; + +protected: + virtual void device_start(); + virtual void device_reset(); + + + +private: + + +}; + +#endif diff --git a/src/devices/bus/neogeo/kof2002_cart.c b/src/devices/bus/neogeo/kof2002_cart.c new file mode 100644 index 00000000000..9726bd34b4b --- /dev/null +++ b/src/devices/bus/neogeo/kof2002_cart.c @@ -0,0 +1,157 @@ +// license:BSD-3-Clause +// copyright-holders:S. Smith,David Haywood +/*********************************************************************************************************** + + NEOGEO ROM cart emulation + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "kof2002_cart.h" + + +//------------------------------------------------- +// neogeo_kof2002_cart - constructor +//------------------------------------------------- + +const device_type NEOGEO_KOF2002_CART = &device_creator; + + +neogeo_kof2002_cart::neogeo_kof2002_cart(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT16 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_neogeo_cart_interface(mconfig, *this), + m_banked_cart(*this, "banked_cart"), + m_cmc_prot(*this, "cmc_prot"), + m_pcm2_prot(*this, "pcm2_prot"), + m_kof2002_prot(*this, "kof2002_prot") +{ +} + +neogeo_kof2002_cart::neogeo_kof2002_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT16 clock) + : device_t(mconfig, NEOGEO_KOF2002_CART, "NEOGEO KOF2002 Cart", tag, owner, clock, "neogeo_rom", __FILE__), + device_neogeo_cart_interface(mconfig, *this), + m_banked_cart(*this, "banked_cart"), + m_cmc_prot(*this, "cmc_prot"), + m_pcm2_prot(*this, "pcm2_prot"), + m_kof2002_prot(*this, "kof2002_prot") +{ +} + + +//------------------------------------------------- +// mapper specific start/reset +//------------------------------------------------- + +void neogeo_kof2002_cart::device_start() +{ +} + +void neogeo_kof2002_cart::device_reset() +{ +} + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +READ16_MEMBER(neogeo_kof2002_cart::read_rom) +{ + return m_rom[offset]; +} + +static MACHINE_CONFIG_FRAGMENT( kof2002_cart ) + MCFG_NEOGEO_BANKED_CART_ADD("banked_cart") + MCFG_CMC_PROT_ADD("cmc_prot") + MCFG_PCM2_PROT_ADD("pcm2_prot") + MCFG_KOF2002_PROT_ADD("kof2002_prot") +MACHINE_CONFIG_END + +machine_config_constructor neogeo_kof2002_cart::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( kof2002_cart ); +} + + + +/* Individual cartridge types (mirror DRIVER_INIT functionality) */ + +/************************************************* + KOF2002 +**************************************************/ + +const device_type NEOGEO_KOF2002_KOF2002_CART = &device_creator; + +neogeo_kof2002_kof2002_cart::neogeo_kof2002_kof2002_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : neogeo_kof2002_cart(mconfig, NEOGEO_KOF2002_KOF2002_CART, "NEOGEO Kof2002-type kof2002 Cart", tag, owner, clock, "k2k_k2k_cart", __FILE__) {} + +void neogeo_kof2002_kof2002_cart::decrypt_all(DECRYPT_ALL_PARAMS) +{ + m_kof2002_prot->kof2002_decrypt_68k(cpuregion, cpuregion_size); + m_cmc_prot->neogeo_cmc50_m1_decrypt(audiocrypt_region, audiocrypt_region_size, audiocpu_region, audio_region_size); + m_cmc_prot->kof2000_neogeo_gfx_decrypt(spr_region, spr_region_size, fix_region, fix_region_size, KOF2002_GFX_KEY); + m_pcm2_prot->neo_pcm2_swap(ym_region, ym_region_size, 0); + +} + +const device_type NEOGEO_KOF2002_KF2K2PLS_CART = &device_creator; + +neogeo_kof2002_kf2k2pls_cart::neogeo_kof2002_kf2k2pls_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : neogeo_kof2002_cart(mconfig, NEOGEO_KOF2002_KF2K2PLS_CART, "NEOGEO Kof2002-type kof2002plus Cart", tag, owner, clock, "k2k_k2kpls_cart", __FILE__) {} + +void neogeo_kof2002_kf2k2pls_cart::decrypt_all(DECRYPT_ALL_PARAMS) +{ + m_kof2002_prot->kof2002_decrypt_68k(cpuregion, cpuregion_size); + m_cmc_prot->cmc50_neogeo_gfx_decrypt(spr_region, spr_region_size, fix_region, fix_region_size, KOF2002_GFX_KEY); + m_cmc_prot->neogeo_cmc50_m1_decrypt(audiocrypt_region, audiocrypt_region_size, audiocpu_region,audio_region_size); + m_pcm2_prot->neo_pcm2_swap(ym_region, ym_region_size, 0); +} + + +/************************************************* + MATRIM +**************************************************/ + +const device_type NEOGEO_KOF2002_MATRIM_CART = &device_creator; + +neogeo_kof2002_matrim_cart::neogeo_kof2002_matrim_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : neogeo_kof2002_cart(mconfig, NEOGEO_KOF2002_MATRIM_CART, "NEOGEO Kof2002-type matrim Cart", tag, owner, clock, "k2k_matrim_cart", __FILE__) {} + +void neogeo_kof2002_matrim_cart::decrypt_all(DECRYPT_ALL_PARAMS) +{ + m_kof2002_prot->matrim_decrypt_68k(cpuregion, cpuregion_size); + m_cmc_prot->neogeo_cmc50_m1_decrypt(audiocrypt_region, audiocrypt_region_size, audiocpu_region, audio_region_size); + m_cmc_prot->kof2000_neogeo_gfx_decrypt(spr_region, spr_region_size, fix_region, fix_region_size, MATRIM_GFX_KEY); + m_pcm2_prot->neo_pcm2_swap(ym_region, ym_region_size, 1); + +} + +/************************************************* + SAMSHO5 +**************************************************/ + +const device_type NEOGEO_KOF2002_SAMSHO5_CART = &device_creator; + +neogeo_kof2002_samsho5_cart::neogeo_kof2002_samsho5_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : neogeo_kof2002_cart(mconfig, NEOGEO_KOF2002_SAMSHO5_CART, "NEOGEO Kof2002-type Samsho5 Cart", tag, owner, clock, "k2k_ss5_cart", __FILE__) {} + +void neogeo_kof2002_samsho5_cart::decrypt_all(DECRYPT_ALL_PARAMS) +{ + m_kof2002_prot->samsho5_decrypt_68k(cpuregion, cpuregion_size); + m_cmc_prot->neogeo_cmc50_m1_decrypt(audiocrypt_region, audiocrypt_region_size, audiocpu_region, audio_region_size); + m_cmc_prot->kof2000_neogeo_gfx_decrypt(spr_region, spr_region_size, fix_region, fix_region_size, SAMSHO5_GFX_KEY); + m_pcm2_prot->neo_pcm2_swap(ym_region, ym_region_size, 4); +} + +/************************************************* + SAMSHO5SP +**************************************************/ + +const device_type NEOGEO_KOF2002_SAMSHO5SP_CART = &device_creator; + +neogeo_kof2002_samsho5sp_cart::neogeo_kof2002_samsho5sp_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : neogeo_kof2002_cart(mconfig, NEOGEO_KOF2002_SAMSHO5SP_CART, "NEOGEO Kof2002-type Samsho5sp Cart", tag, owner, clock, "k2k_ss5s_cart", __FILE__) {} + +void neogeo_kof2002_samsho5sp_cart::decrypt_all(DECRYPT_ALL_PARAMS) +{ + m_kof2002_prot->samsh5sp_decrypt_68k(cpuregion, cpuregion_size); + m_cmc_prot->neogeo_cmc50_m1_decrypt(audiocrypt_region, audiocrypt_region_size, audiocpu_region, audio_region_size); + m_cmc_prot->kof2000_neogeo_gfx_decrypt(spr_region, spr_region_size, fix_region, fix_region_size, SAMSHO5SP_GFX_KEY); + m_pcm2_prot->neo_pcm2_swap(ym_region, ym_region_size, 6); +} diff --git a/src/devices/bus/neogeo/kof2002_cart.h b/src/devices/bus/neogeo/kof2002_cart.h new file mode 100644 index 00000000000..7d995c88adc --- /dev/null +++ b/src/devices/bus/neogeo/kof2002_cart.h @@ -0,0 +1,111 @@ +// license:BSD-3-Clause +// copyright-holders:S. Smith,David Haywood +#ifndef __NEOGEO_KOF2002_CART_H +#define __NEOGEO_KOF2002_CART_H + +#include "neogeo_slot.h" +#include "banked_cart.h" +#include "pcm2_prot.h" +#include "cmc_prot.h" +#include "kof2002_prot.h" + +// ======================> neogeo_kof2002_cart + +class neogeo_kof2002_cart : public device_t, + public device_neogeo_cart_interface +{ +public: + // construction/destruction + neogeo_kof2002_cart(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT16 clock, const char *shortname, const char *source); + neogeo_kof2002_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT16 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual machine_config_constructor device_mconfig_additions() const; + + // reading and writing + virtual DECLARE_READ16_MEMBER(read_rom); + + virtual void activate_cart(ACTIVATE_CART_PARAMS) { m_banked_cart->install_banks(machine, maincpu, cpuregion, cpuregion_size); } + virtual void decrypt_all(DECRYPT_ALL_PARAMS) {} + virtual int get_fixed_bank_type(void) { return 0; } + + required_device m_banked_cart; + required_device m_cmc_prot; + required_device m_pcm2_prot; + required_device m_kof2002_prot; + +}; + + + +// device type definition +extern const device_type NEOGEO_KOF2002_CART; + + +/************************************************* + KOF2002 +**************************************************/ + +class neogeo_kof2002_kof2002_cart : public neogeo_kof2002_cart +{ +public: + neogeo_kof2002_kof2002_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual void decrypt_all(DECRYPT_ALL_PARAMS); + virtual int get_fixed_bank_type(void) { return 0; } +}; +extern const device_type NEOGEO_KOF2002_KOF2002_CART; + +class neogeo_kof2002_kf2k2pls_cart : public neogeo_kof2002_cart +{ +public: + neogeo_kof2002_kf2k2pls_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual void decrypt_all(DECRYPT_ALL_PARAMS); + virtual int get_fixed_bank_type(void) { return 0; } +}; +extern const device_type NEOGEO_KOF2002_KF2K2PLS_CART; + + + +/************************************************* + MATRIM +**************************************************/ + +class neogeo_kof2002_matrim_cart : public neogeo_kof2002_cart +{ +public: + neogeo_kof2002_matrim_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual void decrypt_all(DECRYPT_ALL_PARAMS); + virtual int get_fixed_bank_type(void) { return 2; } +}; +extern const device_type NEOGEO_KOF2002_MATRIM_CART; + +/************************************************* + SAMSHO5 +**************************************************/ + +class neogeo_kof2002_samsho5_cart : public neogeo_kof2002_cart +{ +public: + neogeo_kof2002_samsho5_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual void decrypt_all(DECRYPT_ALL_PARAMS); + virtual int get_fixed_bank_type(void) { return 1; } +}; +extern const device_type NEOGEO_KOF2002_SAMSHO5_CART; + +/************************************************* + SAMSHO5SP +**************************************************/ + +class neogeo_kof2002_samsho5sp_cart : public neogeo_kof2002_cart +{ +public: + neogeo_kof2002_samsho5sp_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual void decrypt_all(DECRYPT_ALL_PARAMS); + virtual int get_fixed_bank_type(void) { return 1; } +}; +extern const device_type NEOGEO_KOF2002_SAMSHO5SP_CART; + + +#endif diff --git a/src/devices/bus/neogeo/kof2002_prot.c b/src/devices/bus/neogeo/kof2002_prot.c new file mode 100644 index 00000000000..f234602a0c2 --- /dev/null +++ b/src/devices/bus/neogeo/kof2002_prot.c @@ -0,0 +1,83 @@ +// license:BSD-3-Clause +// copyright-holders:S. Smith,David Haywood + +#include "emu.h" +#include "kof2002_prot.h" + + + +extern const device_type KOF2002_PROT = &device_creator; + + +kof2002_prot_device::kof2002_prot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, KOF2002_PROT, "NeoGeo Protection (KOF2002)", tag, owner, clock, "kof2002_prot", __FILE__) +{ +} + + +void kof2002_prot_device::device_start() +{ +} + +void kof2002_prot_device::device_reset() +{ +} + + +/* kof2002, matrim, samsho5, samsh5sp have some simple block swapping */ +void kof2002_prot_device::kof2002_decrypt_68k(UINT8* cpurom, UINT32 cpurom_size) +{ + int i; + static const int sec[]={0x100000,0x280000,0x300000,0x180000,0x000000,0x380000,0x200000,0x080000}; + UINT8 *src = cpurom+0x100000; + dynamic_buffer dst(0x400000); + memcpy( &dst[0], src, 0x400000 ); + for( i=0; i<8; ++i ) + { + memcpy( src+i*0x80000, &dst[sec[i]], 0x80000 ); + } +} + + +void kof2002_prot_device::matrim_decrypt_68k(UINT8* cpurom, UINT32 cpurom_size) +{ + int i; + static const int sec[]={0x100000,0x280000,0x300000,0x180000,0x000000,0x380000,0x200000,0x080000}; + UINT8 *src = cpurom+0x100000; + dynamic_buffer dst(0x400000); + memcpy( &dst[0], src, 0x400000); + for( i=0; i<8; ++i ) + { + memcpy( src+i*0x80000, &dst[sec[i]], 0x80000 ); + } +} + + +void kof2002_prot_device::samsho5_decrypt_68k(UINT8* cpurom, UINT32 cpurom_size) +{ + int i; + static const int sec[]={0x000000,0x080000,0x700000,0x680000,0x500000,0x180000,0x200000,0x480000,0x300000,0x780000,0x600000,0x280000,0x100000,0x580000,0x400000,0x380000}; + UINT8 *src = cpurom; + dynamic_buffer dst(0x800000); + + memcpy( &dst[0], src, 0x800000 ); + for( i=0; i<16; ++i ) + { + memcpy( src+i*0x80000, &dst[sec[i]], 0x80000 ); + } +} + + +void kof2002_prot_device::samsh5sp_decrypt_68k(UINT8* cpurom, UINT32 cpurom_size) +{ + int i; + static const int sec[]={0x000000,0x080000,0x500000,0x480000,0x600000,0x580000,0x700000,0x280000,0x100000,0x680000,0x400000,0x780000,0x200000,0x380000,0x300000,0x180000}; + UINT8 *src = cpurom; + dynamic_buffer dst(0x800000); + + memcpy( &dst[0], src, 0x800000 ); + for( i=0; i<16; ++i ) + { + memcpy( src+i*0x80000, &dst[sec[i]], 0x80000 ); + } +} diff --git a/src/devices/bus/neogeo/kof2002_prot.h b/src/devices/bus/neogeo/kof2002_prot.h new file mode 100644 index 00000000000..b0abde55809 --- /dev/null +++ b/src/devices/bus/neogeo/kof2002_prot.h @@ -0,0 +1,38 @@ +// license:BSD-3-Clause +// copyright-holders:S. Smith,David Haywood + + +#pragma once + +#ifndef __KOF2002_PROT__ +#define __KOF2002_PROT__ + +extern const device_type KOF2002_PROT; + +#define MCFG_KOF2002_PROT_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, KOF2002_PROT, 0) + + +class kof2002_prot_device : public device_t +{ +public: + // construction/destruction + kof2002_prot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + void kof2002_decrypt_68k(UINT8* cpurom, UINT32 cpurom_size); + void matrim_decrypt_68k(UINT8* cpurom, UINT32 cpurom_size); + void samsho5_decrypt_68k(UINT8* cpurom, UINT32 cpurom_size); + void samsh5sp_decrypt_68k(UINT8* cpurom, UINT32 cpurom_size); + +protected: + virtual void device_start(); + virtual void device_reset(); + + + +private: + + +}; + +#endif diff --git a/src/devices/bus/neogeo/kof98_cart.c b/src/devices/bus/neogeo/kof98_cart.c new file mode 100644 index 00000000000..6314522e4ff --- /dev/null +++ b/src/devices/bus/neogeo/kof98_cart.c @@ -0,0 +1,80 @@ +// license:BSD-3-Clause +// copyright-holders:S. Smith,David Haywood +/*********************************************************************************************************** + + NEOGEO ROM cart emulation + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "kof98_cart.h" + + +//------------------------------------------------- +// neogeo_kof98_cart - constructor +//------------------------------------------------- + +const device_type NEOGEO_KOF98_CART = &device_creator; + + +neogeo_kof98_cart::neogeo_kof98_cart(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT16 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_neogeo_cart_interface( mconfig, *this ), + m_banked_cart(*this, "banked_cart"), + m_kof98_prot(*this, "kof98_prot") +{ +} + +neogeo_kof98_cart::neogeo_kof98_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT16 clock) + : device_t(mconfig, NEOGEO_KOF98_CART, "NEOGEO KOF98 Cart", tag, owner, clock, "neogeo_rom", __FILE__), + device_neogeo_cart_interface( mconfig, *this ), + m_banked_cart(*this, "banked_cart"), + m_kof98_prot(*this, "kof98_prot") +{ +} + + +//------------------------------------------------- +// mapper specific start/reset +//------------------------------------------------- + +void neogeo_kof98_cart::device_start() +{ +} + +void neogeo_kof98_cart::device_reset() +{ +} + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +READ16_MEMBER(neogeo_kof98_cart::read_rom) +{ + return m_rom[offset]; +} + +static MACHINE_CONFIG_FRAGMENT( kof98_cart ) + MCFG_NEOGEO_BANKED_CART_ADD("banked_cart") + MCFG_KOF98_PROT_ADD("kof98_prot") + +MACHINE_CONFIG_END + +machine_config_constructor neogeo_kof98_cart::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( kof98_cart ); +} + +void neogeo_kof98_cart::decrypt_all(DECRYPT_ALL_PARAMS) +{ + m_kof98_prot->kof98_decrypt_68k(cpuregion, cpuregion_size); +} + +void neogeo_kof98_cart::activate_cart(ACTIVATE_CART_PARAMS) +{ + m_banked_cart->install_banks(machine, maincpu, cpuregion, cpuregion_size); + m_kof98_prot->install_kof98_protection(maincpu); +} diff --git a/src/devices/bus/neogeo/kof98_cart.h b/src/devices/bus/neogeo/kof98_cart.h new file mode 100644 index 00000000000..f0054d8c4bd --- /dev/null +++ b/src/devices/bus/neogeo/kof98_cart.h @@ -0,0 +1,41 @@ +// license:BSD-3-Clause +// copyright-holders:S. Smith,David Haywood +#ifndef __NEOGEO_KOF98_CART_H +#define __NEOGEO_KOF98_CART_H + +#include "neogeo_slot.h" +#include "banked_cart.h" +#include "kof98_prot.h" + +// ======================> neogeo_kof98_cart + +class neogeo_kof98_cart : public device_t, + public device_neogeo_cart_interface +{ +public: + // construction/destruction + neogeo_kof98_cart(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT16 clock, const char *shortname, const char *source); + neogeo_kof98_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT16 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual machine_config_constructor device_mconfig_additions() const; + + // reading and writing + virtual DECLARE_READ16_MEMBER(read_rom); + virtual void decrypt_all(DECRYPT_ALL_PARAMS); + virtual void activate_cart(ACTIVATE_CART_PARAMS); + + required_device m_banked_cart; + required_device m_kof98_prot; + +}; + + + +// device type definition +extern const device_type NEOGEO_KOF98_CART; + + +#endif diff --git a/src/devices/bus/neogeo/kof98_prot.c b/src/devices/bus/neogeo/kof98_prot.c new file mode 100644 index 00000000000..fefe7c190d3 --- /dev/null +++ b/src/devices/bus/neogeo/kof98_prot.c @@ -0,0 +1,141 @@ +// license:BSD-3-Clause +// copyright-holders:S. Smith,David Haywood + + +#include "emu.h" +#include "kof98_prot.h" + + + +extern const device_type KOF98_PROT = &device_creator; + + +kof98_prot_device::kof98_prot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, KOF98_PROT, "NeoGeo Protection (KOF98)", tag, owner, clock, "kof98_prot", __FILE__) +{ +} + + +void kof98_prot_device::device_start() +{ +} + +void kof98_prot_device::device_reset() +{ + kof98_prot_state = 0; +} + + +/* Kof98 uses an early encryption, quite different from the others */ +void kof98_prot_device::kof98_decrypt_68k(UINT8* cpurom, UINT32 cpurom_size) +{ + UINT8 *src = cpurom; + dynamic_buffer dst(0x200000); + int i, j, k; + static const UINT32 sec[]={0x000000,0x100000,0x000004,0x100004,0x10000a,0x00000a,0x10000e,0x00000e}; + static const UINT32 pos[]={0x000,0x004,0x00a,0x00e}; + + memcpy( &dst[0], src, 0x200000); + for( i=0x800; i<0x100000; i+=0x200 ) + { + for( j=0; j<0x100; j+=0x10 ) + { + for( k=0; k<16; k+=2) + { + memcpy( &src[i+j+k], &dst[ i+j+sec[k/2]+0x100 ], 2 ); + memcpy( &src[i+j+k+0x100], &dst[ i+j+sec[k/2] ], 2 ); + } + if( i >= 0x080000 && i < 0x0c0000) + { + for( k=0; k<4; k++ ) + { + memcpy( &src[i+j+pos[k]], &dst[i+j+pos[k]], 2 ); + memcpy( &src[i+j+pos[k]+0x100], &dst[i+j+pos[k]+0x100], 2 ); + } + } + else if( i >= 0x0c0000 ) + { + for( k=0; k<4; k++ ) + { + memcpy( &src[i+j+pos[k]], &dst[i+j+pos[k]+0x100], 2 ); + memcpy( &src[i+j+pos[k]+0x100], &dst[i+j+pos[k]], 2 ); + } + } + } + memcpy( &src[i+0x000000], &dst[i+0x000000], 2 ); + memcpy( &src[i+0x000002], &dst[i+0x100000], 2 ); + memcpy( &src[i+0x000100], &dst[i+0x000100], 2 ); + memcpy( &src[i+0x000102], &dst[i+0x100100], 2 ); + } + memmove( &src[0x100000], &src[0x200000], 0x400000 ); + + UINT16* mem16 = (UINT16*)cpurom; + m_default_rom[0] = mem16[0x100 / 2]; + m_default_rom[1] = mem16[0x102 / 2]; + + +} + + +/************************ King of Fighters 98******************* + The encrypted set has a rom overlay feature, checked at + various points in the game. + Boards used: NEO-MVS PROGSF1 (1998.6.17) / NEO-MVS PROGSF1E (1998.6.18) + The boards have an ALTERA chip (EPM7128SQC100-15) which is tied to 242-P1 +***************************************************************/ + +READ16_MEMBER(kof98_prot_device::kof98_prot_r) +{ + if (kof98_prot_state == 1) + { + if (!offset) + return 0x00c2; + else + return 0x00fd; + } + if (kof98_prot_state == 2) + { + if (!offset) + return 0x4e45; + else + return 0x4f2d; + } + + if (!offset) + return m_default_rom[0]; + else + return m_default_rom[1]; + + // never executed + //return 0xffff; +} + +WRITE16_MEMBER( kof98_prot_device::kof98_prot_w ) +{ + /* info from razoola */ + switch (data) + { + case 0x0090: + logerror ("%06x kof98 - protection 0x0090x\n", space.device().safe_pc()); + kof98_prot_state = 1; + break; + + case 0x00f0: + logerror ("%06x kof98 - protection 0x00f0x\n", space.device().safe_pc()); + kof98_prot_state = 2; + break; + + default: // 00aa is written, but not needed? + logerror ("%06x kof98 - unknown protection write %04x\n", space.device().safe_pc(), data); + break; + } +} + + +void kof98_prot_device::install_kof98_protection(cpu_device* maincpu) +{ + /* when 0x20aaaa contains 0x0090 (word) then 0x100 (normally the neogeo header) should return 0x00c200fd worked out using real hw */ + maincpu->space(AS_PROGRAM).install_read_handler(0x00100, 0x00103, read16_delegate(FUNC(kof98_prot_device::kof98_prot_r),this)); + + maincpu->space(AS_PROGRAM).install_write_handler(0x20aaaa, 0x20aaab, write16_delegate(FUNC(kof98_prot_device::kof98_prot_w),this)); +} diff --git a/src/devices/bus/neogeo/kof98_prot.h b/src/devices/bus/neogeo/kof98_prot.h new file mode 100644 index 00000000000..bdd634cbb04 --- /dev/null +++ b/src/devices/bus/neogeo/kof98_prot.h @@ -0,0 +1,40 @@ +// license:BSD-3-Clause +// copyright-holders:S. Smith,David Haywood + + +#pragma once + +#ifndef __KOF98_PROT__ +#define __KOF98_PROT__ + +extern const device_type KOF98_PROT; + +#define MCFG_KOF98_PROT_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, KOF98_PROT, 0) + + +class kof98_prot_device : public device_t +{ +public: + // construction/destruction + kof98_prot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + void kof98_decrypt_68k(UINT8* cpurom, UINT32 cpurom_size); + void install_kof98_protection(cpu_device* maincpu); + DECLARE_WRITE16_MEMBER(kof98_prot_w); + DECLARE_READ16_MEMBER(kof98_prot_r); + int kof98_prot_state; + UINT16 m_default_rom[2]; + +protected: + virtual void device_start(); + virtual void device_reset(); + + + +private: + + +}; + +#endif diff --git a/src/devices/bus/neogeo/kog_prot.c b/src/devices/bus/neogeo/kog_prot.c new file mode 100644 index 00000000000..d3caaff3e15 --- /dev/null +++ b/src/devices/bus/neogeo/kog_prot.c @@ -0,0 +1,118 @@ +// license:BSD-3-Clause +// copyright-holders:S. Smith,David Haywood +#include "emu.h" +#include "kog_prot.h" + + + +extern const device_type KOG_PROT = &device_creator; + + +kog_prot_device::kog_prot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, KOG_PROT, "NeoGeo Protection (King of Gladiator)", tag, owner, clock, "kog_prot", __FILE__), + m_jumper(*this, "JUMPER") +{ +} + + +void kog_prot_device::device_start() +{ +} + +void kog_prot_device::device_reset() +{ +} + +READ16_MEMBER(kog_prot_device::read_jumper) +{ + return ioport("JUMPER")->read(); +} + +void kog_prot_device::kog_install_protection(cpu_device* maincpu) +{ + /* overlay cartridge ROM */ + maincpu->space(AS_PROGRAM).install_read_handler(0x0ffffe, 0x0fffff, read16_delegate(FUNC(kog_prot_device::read_jumper), this)); +} + + +/* The King of Gladiator (The King of Fighters '97 bootleg) */ + + +/* The protection patching here may be incomplete + Thanks to Razoola for the info */ + +void kog_prot_device::kog_px_decrypt(UINT8* cpurom, UINT32 cpurom_size) +{ + /* the protection chip does some *very* strange things to the rom */ + UINT8 *src = cpurom; + dynamic_buffer dst( 0x600000 ); + UINT16 *rom = (UINT16 *)cpurom; + int i; + static const int sec[] = { 0x3, 0x8, 0x7, 0xC, 0x1, 0xA, 0x6, 0xD }; + + for (i = 0; i < 8; i++){ + memcpy (&dst[i * 0x20000], src + sec[i] * 0x20000, 0x20000); + } + + memcpy (&dst[0x0007A6], src + 0x0407A6, 0x000006); + memcpy (&dst[0x0007C6], src + 0x0407C6, 0x000006); + memcpy (&dst[0x0007E6], src + 0x0407E6, 0x000006); + memcpy (&dst[0x090000], src + 0x040000, 0x004000); + memcpy (&dst[0x100000], src + 0x200000, 0x400000); + memcpy (src, &dst[0], 0x600000); + + for (i = 0x90000/2; i < 0x94000/2; i++){ + if (((rom[i]&0xFFBF) == 0x4EB9 || rom[i] == 0x43F9) && !rom[i + 1]) + rom[i + 1] = 0x0009; + + if (rom[i] == 0x4EB8) + rom[i] = 0x6100; + } + + rom[0x007A8/2] = 0x0009; + rom[0x007C8/2] = 0x0009; + rom[0x007E8/2] = 0x0009; + rom[0x93408/2] = 0xF168; + rom[0x9340C/2] = 0xFB7A; + rom[0x924AC/2] = 0x0009; + rom[0x9251C/2] = 0x0009; + rom[0x93966/2] = 0xFFDA; + rom[0x93974/2] = 0xFFCC; + rom[0x93982/2] = 0xFFBE; + rom[0x93990/2] = 0xFFB0; + rom[0x9399E/2] = 0xFFA2; + rom[0x939AC/2] = 0xFF94; + rom[0x939BA/2] = 0xFF86; + rom[0x939C8/2] = 0xFF78; + rom[0x939D4/2] = 0xFA5C; + rom[0x939E0/2] = 0xFA50; + rom[0x939EC/2] = 0xFA44; + rom[0x939F8/2] = 0xFA38; + rom[0x93A04/2] = 0xFA2C; + rom[0x93A10/2] = 0xFA20; + rom[0x93A1C/2] = 0xFA14; + rom[0x93A28/2] = 0xFA08; + rom[0x93A34/2] = 0xF9FC; + rom[0x93A40/2] = 0xF9F0; + rom[0x93A4C/2] = 0xFD14; + rom[0x93A58/2] = 0xFD08; + rom[0x93A66/2] = 0xF9CA; + rom[0x93A72/2] = 0xF9BE; + +} + + +static INPUT_PORTS_START( kog ) + /* a jumper on the pcb overlays a ROM address, very strange but that's how it works. */ + PORT_START("JUMPER") + PORT_DIPNAME( 0x0001, 0x0001, "Title Language" ) PORT_DIPLOCATION("CART-JUMPER:1") + PORT_DIPSETTING( 0x0001, DEF_STR( English ) ) + PORT_DIPSETTING( 0x0000, "Non-English" ) + PORT_BIT( 0x00fe, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0xff00, IP_ACTIVE_LOW, IPT_UNUSED ) +INPUT_PORTS_END + +ioport_constructor kog_prot_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( kog ); +} diff --git a/src/devices/bus/neogeo/kog_prot.h b/src/devices/bus/neogeo/kog_prot.h new file mode 100644 index 00000000000..c14b6d919d0 --- /dev/null +++ b/src/devices/bus/neogeo/kog_prot.h @@ -0,0 +1,40 @@ +// license:BSD-3-Clause +// copyright-holders:S. Smith,David Haywood + + +#pragma once + +#ifndef __KOG_PROT__ +#define __KOG_PROT__ + +extern const device_type KOG_PROT; + +#define MCFG_KOG_PROT_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, KOG_PROT, 0) + + +class kog_prot_device : public device_t +{ +public: + // construction/destruction + kog_prot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + void kog_install_protection(cpu_device* maincpu); + void kog_px_decrypt(UINT8* cpurom, UINT32 cpurom_size); + READ16_MEMBER(read_jumper); + + required_ioport m_jumper; + +protected: + virtual void device_start(); + virtual void device_reset(); + virtual ioport_constructor device_input_ports() const; + + + +private: + + +}; + +#endif diff --git a/src/devices/bus/neogeo/mslugx_cart.c b/src/devices/bus/neogeo/mslugx_cart.c new file mode 100644 index 00000000000..d6bd6388864 --- /dev/null +++ b/src/devices/bus/neogeo/mslugx_cart.c @@ -0,0 +1,75 @@ +// license:BSD-3-Clause +// copyright-holders:S. Smith,David Haywood +/*********************************************************************************************************** + + NEOGEO ROM cart emulation + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "mslugx_cart.h" + + +//------------------------------------------------- +// neogeo_mslugx_cart - constructor +//------------------------------------------------- + +const device_type NEOGEO_MSLUGX_CART = &device_creator; + + +neogeo_mslugx_cart::neogeo_mslugx_cart(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT16 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_neogeo_cart_interface( mconfig, *this ), + m_banked_cart(*this, "banked_cart"), + m_mslugx_prot(*this, "mslugx_prot") +{ +} + +neogeo_mslugx_cart::neogeo_mslugx_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT16 clock) + : device_t(mconfig, NEOGEO_MSLUGX_CART, "NEOGEO Metal Slug X Cart", tag, owner, clock, "neogeo_rom", __FILE__), + device_neogeo_cart_interface( mconfig, *this ), + m_banked_cart(*this, "banked_cart"), + m_mslugx_prot(*this, "mslugx_prot") +{ +} + + +//------------------------------------------------- +// mapper specific start/reset +//------------------------------------------------- + +void neogeo_mslugx_cart::device_start() +{ +} + +void neogeo_mslugx_cart::device_reset() +{ +} + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +READ16_MEMBER(neogeo_mslugx_cart::read_rom) +{ + return m_rom[offset]; +} + +static MACHINE_CONFIG_FRAGMENT( mslugx_cart ) + MCFG_NEOGEO_BANKED_CART_ADD("banked_cart") + MCFG_MSLUGX_PROT_ADD("mslugx_prot") + +MACHINE_CONFIG_END + +machine_config_constructor neogeo_mslugx_cart::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( mslugx_cart ); +} + +void neogeo_mslugx_cart::activate_cart(ACTIVATE_CART_PARAMS) +{ + m_banked_cart->install_banks(machine, maincpu, cpuregion, cpuregion_size); + m_mslugx_prot->mslugx_install_protection(maincpu); +} diff --git a/src/devices/bus/neogeo/mslugx_cart.h b/src/devices/bus/neogeo/mslugx_cart.h new file mode 100644 index 00000000000..70d25d2338a --- /dev/null +++ b/src/devices/bus/neogeo/mslugx_cart.h @@ -0,0 +1,41 @@ +// license:BSD-3-Clause +// copyright-holders:S. Smith,David Haywood +#ifndef __NEOGEO_MSLUGX_CART_H +#define __NEOGEO_MSLUGX_CART_H + +#include "neogeo_slot.h" +#include "banked_cart.h" +#include "mslugx_prot.h" + +// ======================> neogeo_mslugx_cart + +class neogeo_mslugx_cart : public device_t, + public device_neogeo_cart_interface +{ +public: + // construction/destruction + neogeo_mslugx_cart(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT16 clock, const char *shortname, const char *source); + neogeo_mslugx_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT16 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual machine_config_constructor device_mconfig_additions() const; + + // reading and writing + virtual DECLARE_READ16_MEMBER(read_rom); + + virtual void activate_cart(ACTIVATE_CART_PARAMS); + + required_device m_banked_cart; + required_device m_mslugx_prot; + +}; + + + +// device type definition +extern const device_type NEOGEO_MSLUGX_CART; + + +#endif diff --git a/src/devices/bus/neogeo/mslugx_prot.c b/src/devices/bus/neogeo/mslugx_prot.c new file mode 100644 index 00000000000..567f308414c --- /dev/null +++ b/src/devices/bus/neogeo/mslugx_prot.c @@ -0,0 +1,95 @@ +// license:BSD-3-Clause +// copyright-holders:S. Smith,David Haywood +#include "emu.h" +#include "mslugx_prot.h" + + + +extern const device_type MSLUGX_PROT = &device_creator; + + +mslugx_prot_device::mslugx_prot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, MSLUGX_PROT, "NeoGeo Protection (Metal Slug X)", tag, owner, clock, "mslugx_prot", __FILE__) +{ +} + + +void mslugx_prot_device::device_start() +{ + save_item(NAME(m_mslugx_command)); + save_item(NAME(m_mslugx_counter)); +} + +void mslugx_prot_device::device_reset() +{ +} + + + + +/************************ Metal Slug X ************************* + Board used: NEO-MVS PROGEOP (1999.2.2) + The board has an ALTERA chip (EPM7128SQC100-15) which is tied to 250-P1 + Also found is a QFP144 chip labeled with 0103 - function unknown +***************************************************************/ + +WRITE16_MEMBER( mslugx_prot_device::mslugx_protection_16_w ) +{ + switch (offset) + { + case 0x0/2: // start new read? + m_mslugx_command = 0; + break; + + case 0x2/2: // command? These are pulsed with data and then 0 + case 0x4/2: + m_mslugx_command |= data; + break; + + case 0x6/2: // finished? + break; + + case 0xa/2: // init? + m_mslugx_counter = 0; + m_mslugx_command = 0; + break; + + default: + logerror("unknown protection write at pc %06x, offset %08x, data %02x\n", space.device().safe_pc(), offset << 1, data); + break; + } +} + + +READ16_MEMBER( mslugx_prot_device::mslugx_protection_16_r ) +{ + UINT16 res = 0; + + switch (m_mslugx_command) + { + case 0x0001: { // $3bdc(?) and $3c30 (Register D7) + res = (space.read_byte(0xdedd2 + ((m_mslugx_counter >> 3) & 0xfff)) >> (~m_mslugx_counter & 0x07)) & 1; + m_mslugx_counter++; + } + break; + + case 0x0fff: { // All other accesses (Register D2) + INT32 select = space.read_word(0x10f00a) - 1; // How should this be calculated? + res = (space.read_byte(0xdedd2 + ((select >> 3) & 0x0fff)) >> (~select & 0x07)) & 1; + } + break; + + default: + logerror("unknown protection read at pc %06x, offset %08x\n", space.device().safe_pc(), offset << 1); + break; + } + + return res; +} + + +void mslugx_prot_device::mslugx_install_protection(cpu_device* maincpu) +{ + maincpu->space(AS_PROGRAM).install_readwrite_handler(0x2fffe0, 0x2fffef, read16_delegate(FUNC(mslugx_prot_device::mslugx_protection_16_r),this), write16_delegate(FUNC(mslugx_prot_device::mslugx_protection_16_w),this)); + +} diff --git a/src/devices/bus/neogeo/mslugx_prot.h b/src/devices/bus/neogeo/mslugx_prot.h new file mode 100644 index 00000000000..dabd8425503 --- /dev/null +++ b/src/devices/bus/neogeo/mslugx_prot.h @@ -0,0 +1,41 @@ +// license:BSD-3-Clause +// copyright-holders:S. Smith,David Haywood + + +#pragma once + +#ifndef __MSLUGX_PROT__ +#define __MSLUGX_PROT__ + +extern const device_type MSLUGX_PROT; + +#define MCFG_MSLUGX_PROT_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, MSLUGX_PROT, 0) + + +class mslugx_prot_device : public device_t +{ +public: + // construction/destruction + mslugx_prot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + + DECLARE_WRITE16_MEMBER( mslugx_protection_16_w ); + DECLARE_READ16_MEMBER( mslugx_protection_16_r ); + void mslugx_install_protection(cpu_device* maincpu); + + UINT16 m_mslugx_counter; + UINT16 m_mslugx_command; + +protected: + virtual void device_start(); + virtual void device_reset(); + + + +private: + + +}; + +#endif diff --git a/src/devices/bus/neogeo/neogeo_carts.c b/src/devices/bus/neogeo/neogeo_carts.c new file mode 100644 index 00000000000..8f9d62037b4 --- /dev/null +++ b/src/devices/bus/neogeo/neogeo_carts.c @@ -0,0 +1,97 @@ +// license:BSD-3-Clause +// copyright-holders:S. Smith,David Haywood + /********************************************************************** + +**********************************************************************/ + +#include "neogeo_carts.h" + +SLOT_INTERFACE_START(neogeo_cart) + /* Standard cart with banking */ + SLOT_INTERFACE_INTERNAL("rom", NEOGEO_ROM) + + /* Custom MslugX protection*/ + SLOT_INTERFACE_INTERNAL("rom_mslugx", NEOGEO_MSLUGX_CART) + /* Custom Fatal Fury 2 protection */ + SLOT_INTERFACE_INTERNAL("rom_fatfur2", NEOGEO_FATFURY2_CART) + /* Custom KOF98 protection */ + SLOT_INTERFACE_INTERNAL("rom_kof98", NEOGEO_KOF98_CART) + + /* These use SMA for prg + CMC42 for gfx */ + SLOT_INTERFACE_INTERNAL("rom_sma", NEOGEO_SMA_CART) + SLOT_INTERFACE_INTERNAL("rom_sma_kof99", NEOGEO_SMA_KOF99_CART) + SLOT_INTERFACE_INTERNAL("rom_sma_garou", NEOGEO_SMA_GAROU_CART) + SLOT_INTERFACE_INTERNAL("rom_sma_garouh", NEOGEO_SMA_GAROUH_CART) + SLOT_INTERFACE_INTERNAL("rom_sma_mslug3", NEOGEO_SMA_MSLUG3_CART) + /* These use SMA for prg + CMC50 for gfx (& audiocpu) */ + SLOT_INTERFACE_INTERNAL("rom_sma_kof2000", NEOGEO_SMA_KOF2000_CART) + /* only CMC42 for gfx */ + SLOT_INTERFACE_INTERNAL("rom_cmc_zupapa", NEOGEO_CMC_ZUPAPA_CART) + SLOT_INTERFACE_INTERNAL("rom_cmc_mslug3h", NEOGEO_CMC_MSLUG3H_CART) + SLOT_INTERFACE_INTERNAL("rom_cmc_ganryu", NEOGEO_CMC_GANRYU_CART) + SLOT_INTERFACE_INTERNAL("rom_cmc_s1945p", NEOGEO_CMC_S1945P_CART) + SLOT_INTERFACE_INTERNAL("r_cmc_preisle2", NEOGEO_CMC_PREISLE2_CART) + SLOT_INTERFACE_INTERNAL("r_cmc_bangbead", NEOGEO_CMC_BANGBEAD_CART) + SLOT_INTERFACE_INTERNAL("rom_cmc_nitd", NEOGEO_CMC_NITD_CART) + SLOT_INTERFACE_INTERNAL("r_cmc_sengoku3", NEOGEO_CMC_SENGOKU3_CART) + SLOT_INTERFACE_INTERNAL("r_cmc_kof99k", NEOGEO_CMC_KOF99K_CART) + /* only CMC50 for gfx (& audiocpu) */ + SLOT_INTERFACE_INTERNAL("r_cmc_kof2001", NEOGEO_CMC_KOF2001_CART) + SLOT_INTERFACE_INTERNAL("r_cmc_kof2000n", NEOGEO_CMC_KOF2000N_CART) + /* CMC50 for gfx (& audiocpu) + NEOPCM2 for YM scramble */ + SLOT_INTERFACE_INTERNAL("r_pc2_mslug4", NEOGEO_PCM2_MSLUG4_CART) + SLOT_INTERFACE_INTERNAL("r_pc2_rotd", NEOGEO_PCM2_ROTD_CART) + SLOT_INTERFACE_INTERNAL("r_pc2_pnyaa", NEOGEO_PCM2_PNYAA_CART) + SLOT_INTERFACE_INTERNAL("r_ms4plus", NEOGEO_PCM2_MS4PLUS_CART) // regular encryption but external S1 rom + + /* CMC50 for gfx (& audiocpu) + NEOPCM2 for YM scramble + additonal prg scramble */ + SLOT_INTERFACE_INTERNAL("r_k2_kof2002", NEOGEO_KOF2002_KOF2002_CART) + SLOT_INTERFACE_INTERNAL("r_k2_matrim", NEOGEO_KOF2002_MATRIM_CART) + SLOT_INTERFACE_INTERNAL("r_k2_samsh5", NEOGEO_KOF2002_SAMSHO5_CART) + SLOT_INTERFACE_INTERNAL("r_k2_sams5s", NEOGEO_KOF2002_SAMSHO5SP_CART) + SLOT_INTERFACE_INTERNAL("r_kf2k2pls", NEOGEO_KOF2002_KF2K2PLS_CART) // regular encryption but external S1 rom + + /* CMC50 for gfx (& audiocpu) + NEOPCM2 for YM scramble + PVC protection/encryption */ + SLOT_INTERFACE_INTERNAL("r_pv_mslug5", NEOGEO_PVC_MSLUG5_CART) + SLOT_INTERFACE_INTERNAL("r_pv_svc", NEOGEO_PVC_SVC_CART) + SLOT_INTERFACE_INTERNAL("r_pv_kf2k3", NEOGEO_PVC_KOF2003_CART) + SLOT_INTERFACE_INTERNAL("r_pv_kf2k3h", NEOGEO_PVC_KOF2003H_CART) + + /* 100% bootleg logic */ + SLOT_INTERFACE_INTERNAL("r_garoubl", NEOGEO_BOOTLEG_GAROUBL_CART) + SLOT_INTERFACE_INTERNAL("r_cthd2003", NEOGEO_BOOTLEG_CTHD2003_CART) + SLOT_INTERFACE_INTERNAL("r_cthd2003sp", NEOGEO_BOOTLEG_CT2K3SP_CART) + SLOT_INTERFACE_INTERNAL("r_cthd2003sa", NEOGEO_BOOTLEG_CT2K3SA_CART) + SLOT_INTERFACE_INTERNAL("r_kf10thep", NEOGEO_BOOTLEG_KF10THEP_CART) + SLOT_INTERFACE_INTERNAL("r_kf2k5uni", NEOGEO_BOOTLEG_KF2K5UNI_CART) + SLOT_INTERFACE_INTERNAL("r_kf2k4se", NEOGEO_BOOTLEG_KF2K4SE_CART) + SLOT_INTERFACE_INTERNAL("r_svcplus", NEOGEO_BOOTLEG_SVCPLUS_CART) + SLOT_INTERFACE_INTERNAL("r_svcplusa", NEOGEO_BOOTLEG_SVCPLUSA_CART) + SLOT_INTERFACE_INTERNAL("r_samsho5b", NEOGEO_BOOTLEG_SAMSHO5B_CART) + SLOT_INTERFACE_INTERNAL("r_kof97oro", NEOGEO_BOOTLEG_KOF97ORO_CART) // missing from softlist? + SLOT_INTERFACE_INTERNAL("r_lans2004", NEOGEO_BOOTLEG_LANS2004_CART) + SLOT_INTERFACE_INTERNAL("r_kof10th", NEOGEO_BOOTLEG_KOF10TH_CART) + SLOT_INTERFACE_INTERNAL("r_kog", NEOGEO_BOOTLEG_KOG_CART) + + /* mixed original and bootleg logic */ + SLOT_INTERFACE_INTERNAL("r_mslug3b6", NEOGEO_BOOTLEG_HYBRID_MSLUG3B6_CART) + SLOT_INTERFACE_INTERNAL("r_kof2002b", NEOGEO_BOOTLEG_HYBRID_KOF2002B_CART) + SLOT_INTERFACE_INTERNAL("r_kf2k2mp", NEOGEO_BOOTLEG_HYBRID_KF2K2MP_CART) + SLOT_INTERFACE_INTERNAL("r_kf2k2mp2", NEOGEO_BOOTLEG_HYBRID_KF2K2MP2_CART) + + SLOT_INTERFACE_INTERNAL("r_matrimbl", NEOGEO_BOOTLEG_HYBRID_MATRIMBL_CART) + SLOT_INTERFACE_INTERNAL("r_ms5plus", NEOGEO_BOOTLEG_HYBRID_MS5PLUS_CART) + SLOT_INTERFACE_INTERNAL("r_svcboot", NEOGEO_BOOTLEG_HYBRID_SVCBOOT_CART) + SLOT_INTERFACE_INTERNAL("r_svcsplus", NEOGEO_BOOTLEG_HYBRID_SVCSPLUS_CART) + + SLOT_INTERFACE_INTERNAL("r_kf2k3bl", NEOGEO_BOOTLEG_HYBRID_KF2K3BL_CART) + SLOT_INTERFACE_INTERNAL("r_kf2k3pl", NEOGEO_BOOTLEG_HYBRID_KF2K3PL_CART) + SLOT_INTERFACE_INTERNAL("r_kf2k3upl", NEOGEO_BOOTLEG_HYBRID_KF2K3UPL_CART) + + + + + + + +SLOT_INTERFACE_END diff --git a/src/devices/bus/neogeo/neogeo_carts.h b/src/devices/bus/neogeo/neogeo_carts.h new file mode 100644 index 00000000000..f6925b96e98 --- /dev/null +++ b/src/devices/bus/neogeo/neogeo_carts.h @@ -0,0 +1,30 @@ +// license:BSD-3-Clause +// copyright-holders:S. Smith,David Haywood +/********************************************************************** + +**********************************************************************/ + +#pragma once + +#ifndef __NEOGEO_CARTS_H__ +#define __NEOGEO_CARTS_H__ + +#include "emu.h" + +#include "rom.h" +#include "banked_cart.h" +#include "mslugx_cart.h" +#include "sma_cart.h" +#include "cmc_cart.h" +#include "pcm2_cart.h" +#include "kof2002_cart.h" +#include "pvc_cart.h" +#include "fatfury2_cart.h" +#include "kof98_cart.h" +#include "bootleg_cart.h" +#include "bootleg_hybrid_cart.h" + +// supported devices +SLOT_INTERFACE_EXTERN(neogeo_cart); + +#endif // __NEOGEO_CARTS_H__ diff --git a/src/devices/bus/neogeo/neogeo_helper.c b/src/devices/bus/neogeo/neogeo_helper.c new file mode 100644 index 00000000000..fdbd9ba7203 --- /dev/null +++ b/src/devices/bus/neogeo/neogeo_helper.c @@ -0,0 +1,66 @@ +// license:BSD-3-Clause +// copyright-holders:S. Smith,David Haywood + +#include "emu.h" +#include "neogeo_helper.h" + +static UINT32 get_region_mask(UINT8* rgn, UINT32 rgn_size) +{ + UINT32 mask; + UINT32 len; + UINT32 bit; + + mask = 0xffffffff; + + len = rgn_size; + + for (bit = 0x80000000; bit != 0; bit >>= 1) + { + if ((len * 2 - 1) & bit) + break; + + mask >>= 1; + } + + return mask; +} + +UINT32 neogeohelper_optimize_sprite_data(std::vector &spritegfx, UINT8* region_sprites, UINT32 region_sprites_size) +{ + /* convert the sprite graphics data into a format that + allows faster blitting */ + UINT8 *src; + UINT8 *dest; + + UINT32 mask = get_region_mask(region_sprites, region_sprites_size); + + spritegfx.resize(mask + 1); + UINT32 spritegfx_address_mask = mask; + + src = region_sprites; + dest = &spritegfx[0]; + + for (unsigned i = 0; i < region_sprites_size; i += 0x80, src += 0x80) + { + for (unsigned y = 0; y < 0x10; y++) + { + for (unsigned x = 0; x < 8; x++) + { + *(dest++) = (((src[0x43 | (y << 2)] >> x) & 0x01) << 3) | + (((src[0x41 | (y << 2)] >> x) & 0x01) << 2) | + (((src[0x42 | (y << 2)] >> x) & 0x01) << 1) | + (((src[0x40 | (y << 2)] >> x) & 0x01) << 0); + } + + for (unsigned x = 0; x < 8; x++) + { + *(dest++) = (((src[0x03 | (y << 2)] >> x) & 0x01) << 3) | + (((src[0x01 | (y << 2)] >> x) & 0x01) << 2) | + (((src[0x02 | (y << 2)] >> x) & 0x01) << 1) | + (((src[0x00 | (y << 2)] >> x) & 0x01) << 0); + } + } + } + + return spritegfx_address_mask; +} diff --git a/src/devices/bus/neogeo/neogeo_helper.h b/src/devices/bus/neogeo/neogeo_helper.h new file mode 100644 index 00000000000..3d125f7fd62 --- /dev/null +++ b/src/devices/bus/neogeo/neogeo_helper.h @@ -0,0 +1,4 @@ +// license:BSD-3-Clause +// copyright-holders:S. Smith,David Haywood + +extern UINT32 neogeohelper_optimize_sprite_data(std::vector &spritegfx, UINT8* region_sprites, UINT32 region_sprites_size); diff --git a/src/devices/bus/neogeo/neogeo_intf.c b/src/devices/bus/neogeo/neogeo_intf.c new file mode 100644 index 00000000000..92f7ba5be19 --- /dev/null +++ b/src/devices/bus/neogeo/neogeo_intf.c @@ -0,0 +1,33 @@ +// license:BSD-3-Clause +// copyright-holders:S. Smith,David Haywood + +#include "emu.h" +#include "neogeo_intf.h" + +//------------------------------------------------- +// device_neogeo_cart_interface - constructor +//------------------------------------------------- + +device_neogeo_cart_interface::device_neogeo_cart_interface(const machine_config &mconfig, device_t &device) + : device_slot_card_interface(mconfig, device) + /* + m_rom(NULL), + m_fixed(NULL), + m_sprites(NULL), + m_sprites_optimized(NULL), + m_audio(NULL), + m_ym(NULL), + m_ymdelta(NULL), + m_audiocrypt(NULL) + */ +{ +} + + +//------------------------------------------------- +// ~device_neogeo_cart_interface - destructor +//------------------------------------------------- + +device_neogeo_cart_interface::~device_neogeo_cart_interface() +{ +} diff --git a/src/devices/bus/neogeo/neogeo_intf.h b/src/devices/bus/neogeo/neogeo_intf.h new file mode 100644 index 00000000000..5c6947ff52d --- /dev/null +++ b/src/devices/bus/neogeo/neogeo_intf.h @@ -0,0 +1,78 @@ +// license:BSD-3-Clause +// copyright-holders:S. Smith,David Haywood + +#ifndef __NEOGEO_INTF_H +#define __NEOGEO_INTF_H + +// ======================> device_neogeo_cart_interface + +#define DECRYPT_ALL_PARAMS \ + UINT8* cpuregion, UINT32 cpuregion_size,UINT8* spr_region, UINT32 spr_region_size,UINT8* fix_region, UINT32 fix_region_size,UINT8* ym_region, UINT32 ym_region_size,UINT8* ymdelta_region, UINT32 ymdelta_region_size,UINT8* audiocpu_region, UINT32 audio_region_size, UINT8* audiocrypt_region, UINT32 audiocrypt_region_size + +#define ACTIVATE_CART_PARAMS \ + running_machine& machine, cpu_device* maincpu, UINT8* cpuregion, UINT32 cpuregion_size, UINT8* fixedregion, UINT32 fixedregion_size + +class device_neogeo_cart_interface : public device_slot_card_interface +{ +public: + // construction/destruction + device_neogeo_cart_interface(const machine_config &mconfig, device_t &device); + virtual ~device_neogeo_cart_interface(); + + // reading from ROM + virtual DECLARE_READ16_MEMBER(read_rom) { return 0xffff; } + virtual void activate_cart(ACTIVATE_CART_PARAMS) { }; + virtual void decrypt_all(DECRYPT_ALL_PARAMS) { }; + virtual int get_fixed_bank_type(void) { return 0; } + + void rom_alloc(UINT32 size) { m_rom.resize(size/sizeof(UINT16)); } + UINT16* get_rom_base() { return &m_rom[0]; } + UINT32 get_rom_size() { return m_rom.size()*sizeof(UINT16); } + + void fixed_alloc(UINT32 size) { m_fixed.resize(size); } + UINT8* get_fixed_base() { return &m_fixed[0]; } + UINT32 get_fixed_size() { return m_fixed.size(); } + + void audio_alloc(UINT32 size) { m_audio.resize(size); } + UINT8* get_audio_base() { return &m_audio[0]; } + UINT32 get_audio_size() { return m_audio.size(); } + + void audiocrypt_alloc(UINT32 size) { m_audiocrypt.resize(size); } + UINT8* get_audiocrypt_base() { return &m_audiocrypt[0]; } + UINT32 get_audiocrypt_size() { return m_audiocrypt.size(); } + + void sprites_alloc(UINT32 size) { m_sprites.resize(size); } + UINT8* get_sprites_base() { return &m_sprites[0]; } + UINT32 get_sprites_size() { return m_sprites.size(); } + UINT8* get_sprites_optimized() { return &m_sprites_optimized[0]; } + UINT32 get_sprites_addrmask() { return m_sprite_gfx_address_mask; } + std::vector& get_sprites_optimized_arr() { return m_sprites_optimized; } + + void ym_alloc(UINT32 size) { m_ym.resize(size); } + UINT8* get_ym_base() { return &m_ym[0]; } + UINT32 get_ym_size() { return m_ym.size(); } + + void ymdelta_alloc(UINT32 size) { m_ymdelta.resize(size); } + UINT8* get_ymdelta_base() { return &m_ymdelta[0]; } + UINT32 get_ymdelta_size() { return m_ymdelta.size(); } + + std::vector m_rom; + std::vector m_fixed; + std::vector m_sprites; + std::vector m_sprites_optimized; + std::vector m_audio; + std::vector m_ym; + std::vector m_ymdelta; + + UINT32 m_sprite_gfx_address_mask; + + + +protected: + // internal state + std::vector m_audiocrypt; + + +}; + +#endif diff --git a/src/devices/bus/neogeo/neogeo_slot.c b/src/devices/bus/neogeo/neogeo_slot.c new file mode 100644 index 00000000000..0c8fa80887e --- /dev/null +++ b/src/devices/bus/neogeo/neogeo_slot.c @@ -0,0 +1,222 @@ +// license:BSD-3-Clause +// copyright-holders:S. Smith,David Haywood +/*********************************************************************************************************** + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "neogeo_slot.h" + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type NEOGEO_CART_SLOT = &device_creator; + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// neogeo_cart_slot_device - constructor +//------------------------------------------------- +neogeo_cart_slot_device::neogeo_cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT16 clock) : + device_t(mconfig, NEOGEO_CART_SLOT, "NeoGeo Cartridge Slot", tag, owner, clock, "neogeo_cart_slot", __FILE__), + device_image_interface(mconfig, *this), + device_slot_interface(mconfig, *this), + m_cart(0) +{ +} + + +//------------------------------------------------- +// neogeo_cart_slot_device - destructor +//------------------------------------------------- + +neogeo_cart_slot_device::~neogeo_cart_slot_device() +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void neogeo_cart_slot_device::device_start() +{ + m_cart = dynamic_cast(get_card_device()); +} + +//------------------------------------------------- +// device_config_complete - perform any +// operations now that the configuration is +// complete +//------------------------------------------------- + +void neogeo_cart_slot_device::device_config_complete() +{ + // set brief and instance name + update_names(); +} + + + +/*------------------------------------------------- + call load + -------------------------------------------------*/ + + +bool neogeo_cart_slot_device::call_load() +{ + if (m_cart) + { + UINT16 *ROM; + UINT8* ROM8; + UINT32 len; + + if (software_entry() != NULL) + { + // create memory regions + len = get_software_region_length("maincpu"); + m_cart->rom_alloc(len); ROM = m_cart->get_rom_base(); + memcpy(ROM, get_software_region("maincpu"), len); + + len = get_software_region_length("fixed"); + m_cart->fixed_alloc(len); ROM8 = m_cart->get_fixed_base(); + memcpy(ROM8, get_software_region("fixed"), len); + + if (get_software_region("audiocpu") != NULL) + { + len = get_software_region_length("audiocpu"); + m_cart->audio_alloc(len + 0x10000); ROM8 = m_cart->get_audio_base(); + memcpy(ROM8, get_software_region("audiocpu"), len); + memcpy(ROM8 + 0x10000, get_software_region("audiocpu"), len); // avoid reloading in XML, should just improve banking instead tho? + } + + len = get_software_region_length("ymsnd"); + m_cart->ym_alloc(len); ROM8 = m_cart->get_ym_base(); + memcpy(ROM8, get_software_region("ymsnd"), len); + + if (get_software_region("ymsnd.deltat") != NULL) + { + len = get_software_region_length("ymsnd.deltat"); + m_cart->ymdelta_alloc(len); ROM8 = m_cart->get_ymdelta_base(); + memcpy(ROM8, get_software_region("ymsnd.deltat"), len); + } + else + { + // ensure there is no delta-t region + } + + + len = get_software_region_length("sprites"); + m_cart->sprites_alloc(len); ROM8 = m_cart->get_sprites_base(); + memcpy(ROM8, get_software_region("sprites"), len); + + if (get_software_region("audiocrypt") != NULL) // encrypted Z80 code + { + len = get_software_region_length("audiocrypt"); + m_cart->audiocrypt_alloc(len); ROM8 = m_cart->get_audiocrypt_base(); + memcpy(ROM8, get_software_region("audiocrypt"), len); + // allocate the audiocpu region to decrypt data into + m_cart->audio_alloc(len + 0x10000); + } + + m_cart->decrypt_all( + (UINT8*)m_cart->get_rom_base(), m_cart->get_rom_size(), + m_cart->get_sprites_base(), m_cart->get_sprites_size(), + m_cart->get_fixed_base(), m_cart->get_fixed_size(), + m_cart->get_ym_base(), m_cart->get_ym_size(), + m_cart->get_ymdelta_base(), m_cart->get_ymdelta_size(), + m_cart->get_audio_base(), m_cart->get_audio_size(), + m_cart->get_audiocrypt_base(), m_cart->get_audiocrypt_size()); + + + // create optimized sprite cache + m_cart->m_sprite_gfx_address_mask = neogeohelper_optimize_sprite_data(m_cart->get_sprites_optimized_arr(), m_cart->get_sprites_base(), m_cart->get_sprites_size()); + + + return IMAGE_INIT_PASS; + } + } + + return IMAGE_INIT_PASS; +} + +void neogeo_cart_slot_device::setup_memory_banks(running_machine &machine) +{ + UINT16* base16 = get_rom_base(); + UINT32 size = get_rom_size(); + machine.memory().region_free(":maincpu"); + machine.memory().region_alloc(":maincpu",size,2, ENDIANNESS_BIG); + memcpy(memregion(":maincpu")->base(),(UINT8*)base16,size); + + UINT8* base = get_audio_base(); + size = get_audio_size(); + machine.memory().region_free(":audiocpu"); + machine.memory().region_alloc(":audiocpu",size,1, ENDIANNESS_LITTLE); + memcpy(memregion(":audiocpu")->base(),base,size); + + + base = get_ym_base(); + size = get_ym_size(); + + machine.memory().region_free(":ymsnd"); + machine.memory().region_alloc(":ymsnd",size,1, ENDIANNESS_LITTLE); + memcpy(memregion(":ymsnd")->base(),base,size); + + + base = get_ymdelta_base(); + size = get_ymdelta_size(); + machine.memory().region_free(":ymsnd.deltat"); + + if(base) + { + machine.memory().region_alloc(":ymsnd.deltat",size,1, ENDIANNESS_LITTLE); + memcpy(memregion(":ymsnd.deltat")->base(),base,size); + } + + +} + +/*------------------------------------------------- + call_unload + -------------------------------------------------*/ + +void neogeo_cart_slot_device::call_unload() +{ +} + +/*------------------------------------------------- + call softlist load + -------------------------------------------------*/ + +bool neogeo_cart_slot_device::call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry) +{ + load_software_part_region(*this, swlist, swname, start_entry ); + return TRUE; +} + + +/*------------------------------------------------- + get default card software + -------------------------------------------------*/ + +void neogeo_cart_slot_device::get_default_card_software(std::string &result) +{ + software_get_default_slot(result, "rom"); +} + +/*------------------------------------------------- + read + -------------------------------------------------*/ + +READ16_MEMBER(neogeo_cart_slot_device::read_rom) +{ + if (m_cart) + return m_cart->read_rom(space, offset, mem_mask); + else + return 0xffff; +} diff --git a/src/devices/bus/neogeo/neogeo_slot.h b/src/devices/bus/neogeo/neogeo_slot.h new file mode 100644 index 00000000000..3020a7045a9 --- /dev/null +++ b/src/devices/bus/neogeo/neogeo_slot.h @@ -0,0 +1,87 @@ +// license:BSD-3-Clause +// copyright-holders:S. Smith,David Haywood +#ifndef __NEOGEO_SLOT_H +#define __NEOGEO_SLOT_H + +#include "neogeo_intf.h" +#include "neogeo_helper.h" + +/*************************************************************************** + TYPE DEFINITIONS + ***************************************************************************/ + +// ======================> neogeo_cart_slot_device + +class neogeo_cart_slot_device : public device_t, + public device_image_interface, + public device_slot_interface +{ +public: + // construction/destruction + neogeo_cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT16 clock); + virtual ~neogeo_cart_slot_device(); + + // device-level overrides + virtual void device_start(); + virtual void device_config_complete(); + + // image-level overrides + virtual bool call_load(); + virtual void call_unload(); + virtual bool call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry); + + virtual iodevice_t image_type() const { return IO_CARTSLOT; } + virtual bool is_readable() const { return 1; } + virtual bool is_writeable() const { return 0; } + virtual bool is_creatable() const { return 0; } + virtual bool must_be_loaded() const { return 0; } + virtual bool is_reset_on_load() const { return 1; } + virtual const option_guide *create_option_guide() const { return NULL; } + virtual const char *image_interface() const { return "neo_cart"; } + virtual const char *file_extensions() const { return "bin"; } + + // slot interface overrides + virtual void get_default_card_software(std::string &result); + + // reading and writing + virtual DECLARE_READ16_MEMBER(read_rom); + + UINT16* get_rom_base() { if (m_cart) { return m_cart->get_rom_base(); } else { return 0; } } + UINT32 get_rom_size() { if (m_cart) { return m_cart->get_rom_size(); } else { return 0; } } + UINT8* get_fixed_base() { if (m_cart) { return m_cart->get_fixed_base(); } else { return 0; } } + UINT32 get_fixed_size() { if (m_cart) { return m_cart->get_fixed_size(); } else { return 0; } } + UINT8* get_sprites_base() { if (m_cart) { return m_cart->get_sprites_base(); } else { return 0; } } + UINT32 get_sprites_size() { if (m_cart) { return m_cart->get_sprites_size(); } else { return 0; } } + UINT8* get_sprites_optimized() { if (m_cart) { return m_cart->get_sprites_optimized(); } else { return 0; } } + UINT32 get_sprites_addrmask() { if (m_cart) { return m_cart->get_sprites_addrmask(); } else { return 0; } } + UINT8* get_audio_base() { if (m_cart) { return m_cart->get_audio_base(); } else { return 0; } } + UINT32 get_audio_size() { if (m_cart) { return m_cart->get_audio_size(); } else { return 0; } } + UINT8* get_ym_base() { if (m_cart) { return m_cart->get_ym_base(); } else { return 0; } } + UINT32 get_ym_size() { if (m_cart) { return m_cart->get_ym_size(); } else { return 0; } } + UINT8* get_ymdelta_base() { if (m_cart) { return m_cart->get_ymdelta_base(); } else { return 0; } } + UINT32 get_ymdelta_size() { if (m_cart) { return m_cart->get_ymdelta_size(); } else { return 0; } } + int get_fixed_bank_type(void) { if (m_cart) { return m_cart->get_fixed_bank_type(); } else { return 0; } } + + void activate_cart(ACTIVATE_CART_PARAMS) { if (m_cart) m_cart->activate_cart(machine, maincpu, cpuregion, cpuregion_size, fixedregion, fixedregion_size); } + void setup_memory_banks(running_machine &machine); + + +private: + device_neogeo_cart_interface* m_cart; +}; + + +// device type definition +extern const device_type NEOGEO_CART_SLOT; + + +/*************************************************************************** + DEVICE CONFIGURATION MACROS + ***************************************************************************/ + +#define MCFG_NEOGEO_CARTRIDGE_ADD(_tag,_slot_intf,_def_slot) \ + MCFG_DEVICE_ADD(_tag, NEOGEO_CART_SLOT, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) + + +#endif diff --git a/src/devices/bus/neogeo/pcm2_cart.c b/src/devices/bus/neogeo/pcm2_cart.c new file mode 100644 index 00000000000..04eede0ebe9 --- /dev/null +++ b/src/devices/bus/neogeo/pcm2_cart.c @@ -0,0 +1,135 @@ +// license:BSD-3-Clause +// copyright-holders:S. Smith,David Haywood +/*********************************************************************************************************** + + NEOGEO ROM cart emulation + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "pcm2_cart.h" + + +//------------------------------------------------- +// neogeo_pcm2_cart - constructor +//------------------------------------------------- + +const device_type NEOGEO_PCM2_CART = &device_creator; + + +neogeo_pcm2_cart::neogeo_pcm2_cart(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT16 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_neogeo_cart_interface(mconfig, *this), + m_banked_cart(*this, "banked_cart"), + m_cmc_prot(*this, "cmc_prot"), + m_pcm2_prot(*this, "pcm2_prot") +{ +} + +neogeo_pcm2_cart::neogeo_pcm2_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT16 clock) + : device_t(mconfig, NEOGEO_PCM2_CART, "NEOGEO PCM2 Cart", tag, owner, clock, "neogeo_rom", __FILE__), + device_neogeo_cart_interface(mconfig, *this), + m_banked_cart(*this, "banked_cart"), + m_cmc_prot(*this, "cmc_prot"), + m_pcm2_prot(*this, "pcm2_prot") +{ +} + + +//------------------------------------------------- +// mapper specific start/reset +//------------------------------------------------- + +void neogeo_pcm2_cart::device_start() +{ +} + +void neogeo_pcm2_cart::device_reset() +{ +} + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +READ16_MEMBER(neogeo_pcm2_cart::read_rom) +{ + return m_rom[offset]; +} + +static MACHINE_CONFIG_FRAGMENT( pcm2_cart ) + MCFG_NEOGEO_BANKED_CART_ADD("banked_cart") + MCFG_CMC_PROT_ADD("cmc_prot") + MCFG_PCM2_PROT_ADD("pcm2_prot") +MACHINE_CONFIG_END + +machine_config_constructor neogeo_pcm2_cart::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( pcm2_cart ); +} + + + +/* Individual cartridge types (mirror DRIVER_INIT functionality) */ + +/************************************************* + MSLUG4 +**************************************************/ + +const device_type NEOGEO_PCM2_MSLUG4_CART = &device_creator; + +neogeo_pcm2_mslug4_cart::neogeo_pcm2_mslug4_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : neogeo_pcm2_cart(mconfig, NEOGEO_PCM2_MSLUG4_CART, "NEOGEO PCM2 mslug4 Cart", tag, owner, clock, "p2_mslug4_cart", __FILE__) {} + +void neogeo_pcm2_mslug4_cart::decrypt_all(DECRYPT_ALL_PARAMS) +{ + m_cmc_prot->neogeo_cmc50_m1_decrypt(audiocrypt_region, audiocrypt_region_size, audiocpu_region, audio_region_size); + m_cmc_prot->kof2000_neogeo_gfx_decrypt(spr_region, spr_region_size, fix_region, fix_region_size, MSLUG4_GFX_KEY); + m_pcm2_prot->neo_pcm2_snk_1999(ym_region, ym_region_size, 8); + +} + + +const device_type NEOGEO_PCM2_MS4PLUS_CART = &device_creator; + +neogeo_pcm2_ms4plus_cart::neogeo_pcm2_ms4plus_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : neogeo_pcm2_cart(mconfig, NEOGEO_PCM2_MS4PLUS_CART, "NEOGEO PCM2 ms4plus Cart", tag, owner, clock, "p2_ms4plus_cart", __FILE__) {} + +void neogeo_pcm2_ms4plus_cart::decrypt_all(DECRYPT_ALL_PARAMS) +{ + m_cmc_prot->cmc50_neogeo_gfx_decrypt(spr_region, spr_region_size, fix_region, fix_region_size, MSLUG4_GFX_KEY); + m_cmc_prot->neogeo_cmc50_m1_decrypt(audiocrypt_region, audiocrypt_region_size, audiocpu_region,audio_region_size); + m_pcm2_prot->neo_pcm2_snk_1999(ym_region, ym_region_size, 8); +} + + +/************************************************* + ROTD +**************************************************/ + +const device_type NEOGEO_PCM2_ROTD_CART = &device_creator; + +neogeo_pcm2_rotd_cart::neogeo_pcm2_rotd_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : neogeo_pcm2_cart(mconfig, NEOGEO_PCM2_ROTD_CART, "NEOGEO PCM2 rotd Cart", tag, owner, clock, "p2_rotd_cart", __FILE__) {} + +void neogeo_pcm2_rotd_cart::decrypt_all(DECRYPT_ALL_PARAMS) +{ + m_cmc_prot->neogeo_cmc50_m1_decrypt(audiocrypt_region, audiocrypt_region_size, audiocpu_region, audio_region_size); + m_cmc_prot->kof2000_neogeo_gfx_decrypt(spr_region, spr_region_size, fix_region, fix_region_size, ROTD_GFX_KEY); + m_pcm2_prot->neo_pcm2_snk_1999(ym_region, ym_region_size, 16); + +} + +/************************************************* + PNYAA +**************************************************/ + +const device_type NEOGEO_PCM2_PNYAA_CART = &device_creator; + +neogeo_pcm2_pnyaa_cart::neogeo_pcm2_pnyaa_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : neogeo_pcm2_cart(mconfig, NEOGEO_PCM2_PNYAA_CART, "NEOGEO PCM2 pnyaa Cart", tag, owner, clock, "p2_pnyaa_cart", __FILE__) {} + +void neogeo_pcm2_pnyaa_cart::decrypt_all(DECRYPT_ALL_PARAMS) +{ + m_cmc_prot->neogeo_cmc50_m1_decrypt(audiocrypt_region, audiocrypt_region_size, audiocpu_region, audio_region_size); + m_cmc_prot->kof2000_neogeo_gfx_decrypt(spr_region, spr_region_size, fix_region, fix_region_size, PNYAA_GFX_KEY); + m_pcm2_prot->neo_pcm2_snk_1999(ym_region, ym_region_size, 4); +} diff --git a/src/devices/bus/neogeo/pcm2_cart.h b/src/devices/bus/neogeo/pcm2_cart.h new file mode 100644 index 00000000000..5cbb31656fc --- /dev/null +++ b/src/devices/bus/neogeo/pcm2_cart.h @@ -0,0 +1,98 @@ +// license:BSD-3-Clause +// copyright-holders:S. Smith,David Haywood +#ifndef __NEOGEO_PCM2_CART_H +#define __NEOGEO_PCM2_CART_H + +#include "neogeo_slot.h" +#include "banked_cart.h" +#include "pcm2_prot.h" +#include "cmc_prot.h" + +// ======================> neogeo_pcm2_cart + +class neogeo_pcm2_cart : public device_t, + public device_neogeo_cart_interface +{ +public: + // construction/destruction + neogeo_pcm2_cart(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT16 clock, const char *shortname, const char *source); + neogeo_pcm2_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT16 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual machine_config_constructor device_mconfig_additions() const; + + // reading and writing + virtual DECLARE_READ16_MEMBER(read_rom); + + virtual void activate_cart(ACTIVATE_CART_PARAMS) { m_banked_cart->install_banks(machine, maincpu, cpuregion, cpuregion_size); } + virtual void decrypt_all(DECRYPT_ALL_PARAMS) {} + virtual int get_fixed_bank_type(void) { return 0; } + + required_device m_banked_cart; + required_device m_cmc_prot; + required_device m_pcm2_prot; +}; + + + +// device type definition +extern const device_type NEOGEO_PCM2_CART; + + +/************************************************* + MSLUG4 +**************************************************/ + +class neogeo_pcm2_mslug4_cart : public neogeo_pcm2_cart +{ +public: + neogeo_pcm2_mslug4_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual void decrypt_all(DECRYPT_ALL_PARAMS); + virtual int get_fixed_bank_type(void) { return 1; } +}; +extern const device_type NEOGEO_PCM2_MSLUG4_CART; + +class neogeo_pcm2_ms4plus_cart : public neogeo_pcm2_cart +{ +public: + neogeo_pcm2_ms4plus_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual void decrypt_all(DECRYPT_ALL_PARAMS); + virtual int get_fixed_bank_type(void) { return 0; } +}; +extern const device_type NEOGEO_PCM2_MS4PLUS_CART; + + + +/************************************************* + ROTD +**************************************************/ + +class neogeo_pcm2_rotd_cart : public neogeo_pcm2_cart +{ +public: + neogeo_pcm2_rotd_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual void decrypt_all(DECRYPT_ALL_PARAMS); + virtual int get_fixed_bank_type(void) { return 1; } +}; +extern const device_type NEOGEO_PCM2_ROTD_CART; + + +/************************************************* + PNYAA +**************************************************/ + +class neogeo_pcm2_pnyaa_cart : public neogeo_pcm2_cart +{ +public: + neogeo_pcm2_pnyaa_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual void decrypt_all(DECRYPT_ALL_PARAMS); + virtual int get_fixed_bank_type(void) { return 1; } +}; +extern const device_type NEOGEO_PCM2_PNYAA_CART; + + + + +#endif diff --git a/src/devices/bus/neogeo/pcm2_prot.c b/src/devices/bus/neogeo/pcm2_prot.c new file mode 100644 index 00000000000..6ee156712e9 --- /dev/null +++ b/src/devices/bus/neogeo/pcm2_prot.c @@ -0,0 +1,88 @@ +// license:BSD-3-Clause +// copyright-holders:S. Smith,David Haywood + + +#include "emu.h" +#include "pcm2_prot.h" + + + +extern const device_type PCM2_PROT = &device_creator; + + +pcm2_prot_device::pcm2_prot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, PCM2_PROT, "NeoGeo Protection (NEOPCM2)", tag, owner, clock, "pcm2_prot", __FILE__) +{ +} + + +void pcm2_prot_device::device_start() +{ +} + +void pcm2_prot_device::device_reset() +{ +} + +/*************************************************************************** + +NeoGeo 'V' (PCM) ROM encryption + NEOPCM2 chip + +***************************************************************************/ + +/* Neo-Pcm2 Drivers for Encrypted V Roms */ +void pcm2_prot_device::neo_pcm2_snk_1999(UINT8* ymrom, UINT32 ymsize, int value) +{ /* thanks to Elsemi for the NEO-PCM2 info */ + UINT16 *rom = (UINT16 *)ymrom; + int size = ymsize; + int i, j; + + if( rom != NULL ) + { /* swap address lines on the whole ROMs */ + std::vector buffer(value / 2); + + for( i = 0; i < size / 2; i += ( value / 2 ) ) + { + memcpy( &buffer[0], &rom[ i ], value ); + for( j = 0; j < (value / 2); j++ ) + { + rom[ i + j ] = buffer[ j ^ (value/4) ]; + } + } + } +} + + +/* the later PCM2 games have additional scrambling */ +void pcm2_prot_device::neo_pcm2_swap(UINT8* ymrom, UINT32 ymsize, int value) +{ + static const UINT32 addrs[7][2]={ + {0x000000,0xa5000}, + {0xffce20,0x01000}, + {0xfe2cf6,0x4e001}, + {0xffac28,0xc2000}, + {0xfeb2c0,0x0a000}, + {0xff14ea,0xa7001}, + {0xffb440,0x02000}}; + static const UINT8 xordata[7][8]={ + {0xf9,0xe0,0x5d,0xf3,0xea,0x92,0xbe,0xef}, + {0xc4,0x83,0xa8,0x5f,0x21,0x27,0x64,0xaf}, + {0xc3,0xfd,0x81,0xac,0x6d,0xe7,0xbf,0x9e}, + {0xc3,0xfd,0x81,0xac,0x6d,0xe7,0xbf,0x9e}, + {0xcb,0x29,0x7d,0x43,0xd2,0x3a,0xc2,0xb4}, + {0x4b,0xa4,0x63,0x46,0xf0,0x91,0xea,0x62}, + {0x4b,0xa4,0x63,0x46,0xf0,0x91,0xea,0x62}}; + + dynamic_buffer buf(0x1000000); + int i, j, d; + UINT8* src = ymrom; + memcpy(&buf[0],src,0x1000000); + for (i=0;i<0x1000000;i++) + { + j=BITSWAP24(i,23,22,21,20,19,18,17,0,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,16); + j=j^addrs[value][1]; + d=((i+addrs[value][0])&0xffffff); + src[j]=buf[d]^xordata[value][j&0x7]; + } +} diff --git a/src/devices/bus/neogeo/pcm2_prot.h b/src/devices/bus/neogeo/pcm2_prot.h new file mode 100644 index 00000000000..7920b745970 --- /dev/null +++ b/src/devices/bus/neogeo/pcm2_prot.h @@ -0,0 +1,36 @@ +// license:BSD-3-Clause +// copyright-holders:S. Smith,David Haywood + + +#pragma once + +#ifndef __PCM2_PROT__ +#define __PCM2_PROT__ + +extern const device_type PCM2_PROT; + +#define MCFG_PCM2_PROT_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, PCM2_PROT, 0) + + +class pcm2_prot_device : public device_t +{ +public: + // construction/destruction + pcm2_prot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + void neo_pcm2_snk_1999(UINT8* ymrom, UINT32 ymsize, int value); + void neo_pcm2_swap(UINT8* ymrom, UINT32 ymsize, int value); + +protected: + virtual void device_start(); + virtual void device_reset(); + + + +private: + + +}; + +#endif diff --git a/src/devices/bus/neogeo/pvc_cart.c b/src/devices/bus/neogeo/pvc_cart.c new file mode 100644 index 00000000000..ee587724b7f --- /dev/null +++ b/src/devices/bus/neogeo/pvc_cart.c @@ -0,0 +1,139 @@ +// license:BSD-3-Clause +// copyright-holders:S. Smith,David Haywood +/*********************************************************************************************************** + + NEOGEO ROM cart emulation + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "pvc_cart.h" + + +//------------------------------------------------- +// neogeo_pvc_cart - constructor +//------------------------------------------------- + +const device_type NEOGEO_PVC_CART = &device_creator; + + +neogeo_pvc_cart::neogeo_pvc_cart(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT16 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_neogeo_cart_interface(mconfig, *this), + m_banked_cart(*this, "banked_cart"), + m_cmc_prot(*this, "cmc_prot"), + m_pcm2_prot(*this, "pcm2_prot"), + m_pvc_prot(*this, "pvc_prot") +{ +} + +neogeo_pvc_cart::neogeo_pvc_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT16 clock) + : device_t(mconfig, NEOGEO_PVC_CART, "NEOGEO PCM2 Cart", tag, owner, clock, "neogeo_rom", __FILE__), + device_neogeo_cart_interface(mconfig, *this), + m_banked_cart(*this, "banked_cart"), + m_cmc_prot(*this, "cmc_prot"), + m_pcm2_prot(*this, "pcm2_prot"), + m_pvc_prot(*this, "pvc_prot") +{ +} + + +//------------------------------------------------- +// mapper specific start/reset +//------------------------------------------------- + +void neogeo_pvc_cart::device_start() +{ +} + +void neogeo_pvc_cart::device_reset() +{ +} + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +READ16_MEMBER(neogeo_pvc_cart::read_rom) +{ + return m_rom[offset]; +} + +static MACHINE_CONFIG_FRAGMENT( pvc_cart ) + MCFG_NEOGEO_BANKED_CART_ADD("banked_cart") + MCFG_CMC_PROT_ADD("cmc_prot") + MCFG_PCM2_PROT_ADD("pcm2_prot") + MCFG_PVC_PROT_ADD("pvc_prot") +MACHINE_CONFIG_END + +machine_config_constructor neogeo_pvc_cart::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( pvc_cart ); +} + + + +/* Individual cartridge types (mirror DRIVER_INIT functionality) */ + +/************************************************* + MSLUG5 +**************************************************/ + +const device_type NEOGEO_PVC_MSLUG5_CART = &device_creator; + +neogeo_pvc_mslug5_cart::neogeo_pvc_mslug5_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : neogeo_pvc_cart(mconfig, NEOGEO_PVC_MSLUG5_CART, "NEOGEO PCM2 mslug5 Cart", tag, owner, clock, "p2_mslug5_cart", __FILE__) {} + +void neogeo_pvc_mslug5_cart::decrypt_all(DECRYPT_ALL_PARAMS) +{ + m_pvc_prot->mslug5_decrypt_68k(cpuregion, cpuregion_size); + m_pcm2_prot->neo_pcm2_swap(ym_region, ym_region_size, 2); + m_cmc_prot->neogeo_cmc50_m1_decrypt(audiocrypt_region, audiocrypt_region_size, audiocpu_region, audio_region_size); + m_cmc_prot->kof2000_neogeo_gfx_decrypt(spr_region, spr_region_size, fix_region, fix_region_size, MSLUG5_GFX_KEY); +} + +/************************************************* + SVC +**************************************************/ + +const device_type NEOGEO_PVC_SVC_CART = &device_creator; + +neogeo_pvc_svc_cart::neogeo_pvc_svc_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : neogeo_pvc_cart(mconfig, NEOGEO_PVC_SVC_CART, "NEOGEO PCM2 svc Cart", tag, owner, clock, "p2_svc_cart", __FILE__) {} + +void neogeo_pvc_svc_cart::decrypt_all(DECRYPT_ALL_PARAMS) +{ + m_pvc_prot->svc_px_decrypt(cpuregion, cpuregion_size); + m_pcm2_prot->neo_pcm2_swap(ym_region, ym_region_size, 3); + m_cmc_prot->neogeo_cmc50_m1_decrypt(audiocrypt_region, audiocrypt_region_size, audiocpu_region, audio_region_size); + m_cmc_prot->kof2000_neogeo_gfx_decrypt(spr_region, spr_region_size, fix_region, fix_region_size, SVC_GFX_KEY); +} + + +/************************************************* + KOF2003 +**************************************************/ + +const device_type NEOGEO_PVC_KOF2003_CART = &device_creator; + +neogeo_pvc_kof2003_cart::neogeo_pvc_kof2003_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : neogeo_pvc_cart(mconfig, NEOGEO_PVC_KOF2003_CART, "NEOGEO PCM2 kof2003 Cart", tag, owner, clock, "p2_kof2003_cart", __FILE__) {} + +void neogeo_pvc_kof2003_cart::decrypt_all(DECRYPT_ALL_PARAMS) +{ + m_pvc_prot->kof2003_decrypt_68k(cpuregion, cpuregion_size); + m_pcm2_prot->neo_pcm2_swap(ym_region, ym_region_size, 5); + m_cmc_prot->neogeo_cmc50_m1_decrypt(audiocrypt_region, audiocrypt_region_size, audiocpu_region, audio_region_size); + m_cmc_prot->kof2000_neogeo_gfx_decrypt(spr_region, spr_region_size, fix_region, fix_region_size, KOF2003_GFX_KEY); +} + +const device_type NEOGEO_PVC_KOF2003H_CART = &device_creator; + +neogeo_pvc_kof2003h_cart::neogeo_pvc_kof2003h_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : neogeo_pvc_cart(mconfig, NEOGEO_PVC_KOF2003H_CART, "NEOGEO PCM2 kof2003h Cart", tag, owner, clock, "p2_kof2003h_cart", __FILE__) {} + +void neogeo_pvc_kof2003h_cart::decrypt_all(DECRYPT_ALL_PARAMS) +{ + m_pvc_prot->kof2003h_decrypt_68k(cpuregion, cpuregion_size); + m_pcm2_prot->neo_pcm2_swap(ym_region, ym_region_size, 5); + m_cmc_prot->neogeo_cmc50_m1_decrypt(audiocrypt_region, audiocrypt_region_size, audiocpu_region, audio_region_size); + m_cmc_prot->kof2000_neogeo_gfx_decrypt(spr_region, spr_region_size, fix_region, fix_region_size, KOF2003_GFX_KEY); +} diff --git a/src/devices/bus/neogeo/pvc_cart.h b/src/devices/bus/neogeo/pvc_cart.h new file mode 100644 index 00000000000..e3e409081c4 --- /dev/null +++ b/src/devices/bus/neogeo/pvc_cart.h @@ -0,0 +1,108 @@ +// license:BSD-3-Clause +// copyright-holders:S. Smith,David Haywood +#ifndef __NEOGEO_PVC_CART_H +#define __NEOGEO_PVC_CART_H + +#include "neogeo_slot.h" +#include "banked_cart.h" +#include "pcm2_prot.h" +#include "cmc_prot.h" +#include "pvc_prot.h" + +// ======================> neogeo_pvc_cart + +class neogeo_pvc_cart : public device_t, + public device_neogeo_cart_interface +{ +public: + // construction/destruction + neogeo_pvc_cart(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT16 clock, const char *shortname, const char *source); + neogeo_pvc_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT16 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual machine_config_constructor device_mconfig_additions() const; + + // reading and writing + virtual DECLARE_READ16_MEMBER(read_rom); + + virtual void activate_cart(ACTIVATE_CART_PARAMS) + { + m_banked_cart->install_banks(machine, maincpu, cpuregion, cpuregion_size); + m_pvc_prot->install_pvc_protection(maincpu,m_banked_cart); + } + + virtual void decrypt_all(DECRYPT_ALL_PARAMS) {} + virtual int get_fixed_bank_type(void) { return 0; } + + required_device m_banked_cart; + required_device m_cmc_prot; + required_device m_pcm2_prot; + required_device m_pvc_prot; + +}; + + + +// device type definition +extern const device_type NEOGEO_PVC_CART; + + +/************************************************* + MSLUG5 +**************************************************/ + +class neogeo_pvc_mslug5_cart : public neogeo_pvc_cart +{ +public: + neogeo_pvc_mslug5_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual void decrypt_all(DECRYPT_ALL_PARAMS); + virtual int get_fixed_bank_type(void) { return 1; } +}; +extern const device_type NEOGEO_PVC_MSLUG5_CART; + +/************************************************* + SVC +**************************************************/ + +class neogeo_pvc_svc_cart : public neogeo_pvc_cart +{ +public: + neogeo_pvc_svc_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual void decrypt_all(DECRYPT_ALL_PARAMS); + virtual int get_fixed_bank_type(void) { return 2; } +}; +extern const device_type NEOGEO_PVC_SVC_CART; + + +/************************************************* + KOF2003 +**************************************************/ + +class neogeo_pvc_kof2003_cart : public neogeo_pvc_cart +{ +public: + neogeo_pvc_kof2003_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual void decrypt_all(DECRYPT_ALL_PARAMS); + virtual int get_fixed_bank_type(void) { return 2; } +}; +extern const device_type NEOGEO_PVC_KOF2003_CART; + + +/************************************************* + KOF2003H +**************************************************/ + +class neogeo_pvc_kof2003h_cart : public neogeo_pvc_cart +{ +public: + neogeo_pvc_kof2003h_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual void decrypt_all(DECRYPT_ALL_PARAMS); + virtual int get_fixed_bank_type(void) { return 2; } +}; +extern const device_type NEOGEO_PVC_KOF2003H_CART; + + + +#endif diff --git a/src/devices/bus/neogeo/pvc_prot.c b/src/devices/bus/neogeo/pvc_prot.c new file mode 100644 index 00000000000..95b8cfeb770 --- /dev/null +++ b/src/devices/bus/neogeo/pvc_prot.c @@ -0,0 +1,316 @@ +// license:BSD-3-Clause +// copyright-holders:S. Smith,David Haywood + + +#include "emu.h" +#include "pvc_prot.h" + + + +extern const device_type PVC_PROT = &device_creator; + + +pvc_prot_device::pvc_prot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, PVC_PROT, "NeoGeo Protection (PVC)", tag, owner, clock, "pvc_prot", __FILE__) +{ +} + + +void pvc_prot_device::device_start() +{ + save_item(NAME(m_cartridge_ram)); +} + +void pvc_prot_device::device_reset() +{ +} + + + + +/************************ PVC Protection *********************** + mslug5, svcchaos, kof2003 +***************************************************************/ + +void pvc_prot_device::pvc_write_unpack_color() +{ + UINT16 pen = m_cartridge_ram[0xff0]; + + UINT8 b = ((pen & 0x000f) << 1) | ((pen & 0x1000) >> 12); + UINT8 g = ((pen & 0x00f0) >> 3) | ((pen & 0x2000) >> 13); + UINT8 r = ((pen & 0x0f00) >> 7) | ((pen & 0x4000) >> 14); + UINT8 s = (pen & 0x8000) >> 15; + + m_cartridge_ram[0xff1] = (g << 8) | b; + m_cartridge_ram[0xff2] = (s << 8) | r; +} + + +void pvc_prot_device::pvc_write_pack_color() +{ + UINT16 gb = m_cartridge_ram[0xff4]; + UINT16 sr = m_cartridge_ram[0xff5]; + + m_cartridge_ram[0xff6] = ((gb & 0x001e) >> 1) | + ((gb & 0x1e00) >> 5) | + ((sr & 0x001e) << 7) | + ((gb & 0x0001) << 12) | + ((gb & 0x0100) << 5) | + ((sr & 0x0001) << 14) | + ((sr & 0x0100) << 7); +} + + +void pvc_prot_device::pvc_write_bankswitch( address_space &space ) +{ + UINT32 bankaddress; + + bankaddress = ((m_cartridge_ram[0xff8] >> 8)|(m_cartridge_ram[0xff9] << 8)); + m_cartridge_ram[0xff8] = (m_cartridge_ram[0xff8] & 0xfe00) | 0x00a0; + m_cartridge_ram[0xff9] &= 0x7fff; + m_bankdev->neogeo_set_main_cpu_bank_address(bankaddress + 0x100000); +} + + +READ16_MEMBER( pvc_prot_device::pvc_prot_r ) +{ + return m_cartridge_ram[offset]; +} + + +WRITE16_MEMBER( pvc_prot_device::pvc_prot_w ) +{ + COMBINE_DATA(&m_cartridge_ram[offset] ); + if (offset == 0xff0) + pvc_write_unpack_color(); + else if(offset >= 0xff4 && offset <= 0xff5) + pvc_write_pack_color(); + else if(offset >= 0xff8) + pvc_write_bankswitch(space); +} + + +void pvc_prot_device::install_pvc_protection(cpu_device* maincpu, neogeo_banked_cart_device* bankdev) +{ + m_bankdev = bankdev; + maincpu->space(AS_PROGRAM).install_readwrite_handler(0x2fe000, 0x2fffff, read16_delegate(FUNC(pvc_prot_device::pvc_prot_r),this), write16_delegate(FUNC(pvc_prot_device::pvc_prot_w),this)); +} + + + + +/* kf2k3pcb, kof2003, kof2003h, mslug5 and svc have updated P rom scramble */ +void pvc_prot_device::mslug5_decrypt_68k(UINT8* rom, UINT32 size) +{ + static const UINT8 xor1[ 0x20 ] = { 0xc2, 0x4b, 0x74, 0xfd, 0x0b, 0x34, 0xeb, 0xd7, 0x10, 0x6d, 0xf9, 0xce, 0x5d, 0xd5, 0x61, 0x29, 0xf5, 0xbe, 0x0d, 0x82, 0x72, 0x45, 0x0f, 0x24, 0xb3, 0x34, 0x1b, 0x99, 0xea, 0x09, 0xf3, 0x03 }; + static const UINT8 xor2[ 0x20 ] = { 0x36, 0x09, 0xb0, 0x64, 0x95, 0x0f, 0x90, 0x42, 0x6e, 0x0f, 0x30, 0xf6, 0xe5, 0x08, 0x30, 0x64, 0x08, 0x04, 0x00, 0x2f, 0x72, 0x09, 0xa0, 0x13, 0xc9, 0x0b, 0xa0, 0x3e, 0xc2, 0x00, 0x40, 0x2b }; + int i; + int ofst; + int rom_size = 0x800000; + dynamic_buffer buf( rom_size ); + + for( i = 0; i < 0x100000; i++ ) + { + rom[ i ] ^= xor1[ (BYTE_XOR_LE(i) % 0x20) ]; + } + for( i = 0x100000; i < 0x800000; i++ ) + { + rom[ i ] ^= xor2[ (BYTE_XOR_LE(i) % 0x20) ]; + } + + for( i = 0x100000; i < 0x0800000; i += 4 ) + { + UINT16 rom16; + rom16 = rom[BYTE_XOR_LE(i+1)] | rom[BYTE_XOR_LE(i+2)]<<8; + rom16 = BITSWAP16( rom16, 15, 14, 13, 12, 10, 11, 8, 9, 6, 7, 4, 5, 3, 2, 1, 0 ); + rom[BYTE_XOR_LE(i+1)] = rom16&0xff; + rom[BYTE_XOR_LE(i+2)] = rom16>>8; + } + memcpy( &buf[0], rom, rom_size ); + for( i = 0; i < 0x0100000 / 0x10000; i++ ) + { + ofst = (i & 0xf0) + BITSWAP8( (i & 0x0f), 7, 6, 5, 4, 1, 0, 3, 2 ); + memcpy( &rom[ i * 0x10000 ], &buf[ ofst * 0x10000 ], 0x10000 ); + } + for( i = 0x100000; i < 0x800000; i += 0x100 ) + { + ofst = (i & 0xf000ff) + ((i & 0x000f00) ^ 0x00700) + (BITSWAP8( ((i & 0x0ff000) >> 12), 5, 4, 7, 6, 1, 0, 3, 2 ) << 12); + memcpy( &rom[ i ], &buf[ ofst ], 0x100 ); + } + memcpy( &buf[0], rom, rom_size ); + memcpy( &rom[ 0x100000 ], &buf[ 0x700000 ], 0x100000 ); + memcpy( &rom[ 0x200000 ], &buf[ 0x100000 ], 0x600000 ); +} + + +void pvc_prot_device::svc_px_decrypt(UINT8* rom, UINT32 size) +{ + static const UINT8 xor1[ 0x20 ] = { 0x3b, 0x6a, 0xf7, 0xb7, 0xe8, 0xa9, 0x20, 0x99, 0x9f, 0x39, 0x34, 0x0c, 0xc3, 0x9a, 0xa5, 0xc8, 0xb8, 0x18, 0xce, 0x56, 0x94, 0x44, 0xe3, 0x7a, 0xf7, 0xdd, 0x42, 0xf0, 0x18, 0x60, 0x92, 0x9f }; + static const UINT8 xor2[ 0x20 ] = { 0x69, 0x0b, 0x60, 0xd6, 0x4f, 0x01, 0x40, 0x1a, 0x9f, 0x0b, 0xf0, 0x75, 0x58, 0x0e, 0x60, 0xb4, 0x14, 0x04, 0x20, 0xe4, 0xb9, 0x0d, 0x10, 0x89, 0xeb, 0x07, 0x30, 0x90, 0x50, 0x0e, 0x20, 0x26 }; + int i; + int ofst; + int rom_size = 0x800000; + dynamic_buffer buf( rom_size ); + + for( i = 0; i < 0x100000; i++ ) + { + rom[ i ] ^= xor1[ (BYTE_XOR_LE(i) % 0x20) ]; + } + for( i = 0x100000; i < 0x800000; i++ ) + { + rom[ i ] ^= xor2[ (BYTE_XOR_LE(i) % 0x20) ]; + } + + for( i = 0x100000; i < 0x0800000; i += 4 ) + { + UINT16 rom16; + rom16 = rom[BYTE_XOR_LE(i+1)] | rom[BYTE_XOR_LE(i+2)]<<8; + rom16 = BITSWAP16( rom16, 15, 14, 13, 12, 10, 11, 8, 9, 6, 7, 4, 5, 3, 2, 1, 0 ); + rom[BYTE_XOR_LE(i+1)] = rom16&0xff; + rom[BYTE_XOR_LE(i+2)] = rom16>>8; + } + memcpy( &buf[0], rom, rom_size ); + for( i = 0; i < 0x0100000 / 0x10000; i++ ) + { + ofst = (i & 0xf0) + BITSWAP8( (i & 0x0f), 7, 6, 5, 4, 2, 3, 0, 1 ); + memcpy( &rom[ i * 0x10000 ], &buf[ ofst * 0x10000 ], 0x10000 ); + } + for( i = 0x100000; i < 0x800000; i += 0x100 ) + { + ofst = (i & 0xf000ff) + ((i & 0x000f00) ^ 0x00a00) + (BITSWAP8( ((i & 0x0ff000) >> 12), 4, 5, 6, 7, 1, 0, 3, 2 ) << 12); + memcpy( &rom[ i ], &buf[ ofst ], 0x100 ); + } + memcpy( &buf[0], rom, rom_size ); + memcpy( &rom[ 0x100000 ], &buf[ 0x700000 ], 0x100000 ); + memcpy( &rom[ 0x200000 ], &buf[ 0x100000 ], 0x600000 ); +} + + +void pvc_prot_device::kf2k3pcb_decrypt_68k(UINT8* rom, UINT32 size) +{ + static const UINT8 xor2[ 0x20 ] = { 0xb4, 0x0f, 0x40, 0x6c, 0x38, 0x07, 0xd0, 0x3f, 0x53, 0x08, 0x80, 0xaa, 0xbe, 0x07, 0xc0, 0xfa, 0xd0, 0x08, 0x10, 0xd2, 0xf1, 0x03, 0x70, 0x7e, 0x87, 0x0b, 0x40, 0xf6, 0x2a, 0x0a, 0xe0, 0xf9 }; + int i; + int ofst; + int rom_size = 0x900000; + dynamic_buffer buf( rom_size ); + + for (i = 0; i < 0x100000; i++) + { + rom[ 0x800000 + i ] ^= rom[ 0x100002 | i ]; + } + for( i = 0x100000; i < 0x800000; i++ ) + { + rom[ i ] ^= xor2[ (BYTE_XOR_LE(i) % 0x20) ]; + } + for( i = 0x100000; i < 0x800000; i += 4 ) + { + UINT16 rom16; + rom16 = rom[BYTE_XOR_LE(i+1)] | rom[BYTE_XOR_LE(i+2)]<<8; + rom16 = BITSWAP16( rom16, 15, 14, 13, 12, 4, 5, 6, 7, 8, 9, 10, 11, 3, 2, 1, 0 ); + rom[BYTE_XOR_LE(i+1)] = rom16&0xff; + rom[BYTE_XOR_LE(i+2)] = rom16>>8; + } + for( i = 0; i < 0x0100000 / 0x10000; i++ ) + { + ofst = (i & 0xf0) + BITSWAP8( (i & 0x0f), 7, 6, 5, 4, 1, 0, 3, 2 ); + memcpy( &buf[ i * 0x10000 ], &rom[ ofst * 0x10000 ], 0x10000 ); + } + for( i = 0x100000; i < 0x900000; i += 0x100 ) + { + ofst = (i & 0xf000ff) + ((i & 0x000f00) ^ 0x00300) + (BITSWAP8( ((i & 0x0ff000) >> 12), 4, 5, 6, 7, 1, 0, 3, 2 ) << 12); + memcpy( &buf[ i ], &rom[ ofst ], 0x100 ); + } + memcpy (&rom[0x000000], &buf[0x000000], 0x100000); + memcpy (&rom[0x100000], &buf[0x800000], 0x100000); + memcpy (&rom[0x200000], &buf[0x100000], 0x700000); +} + + +void pvc_prot_device::kof2003_decrypt_68k(UINT8* rom, UINT32 size) +{ + static const UINT8 xor1[0x20] = { 0x3b, 0x6a, 0xf7, 0xb7, 0xe8, 0xa9, 0x20, 0x99, 0x9f, 0x39, 0x34, 0x0c, 0xc3, 0x9a, 0xa5, 0xc8, 0xb8, 0x18, 0xce, 0x56, 0x94, 0x44, 0xe3, 0x7a, 0xf7, 0xdd, 0x42, 0xf0, 0x18, 0x60, 0x92, 0x9f }; + static const UINT8 xor2[0x20] = { 0x2f, 0x02, 0x60, 0xbb, 0x77, 0x01, 0x30, 0x08, 0xd8, 0x01, 0xa0, 0xdf, 0x37, 0x0a, 0xf0, 0x65, 0x28, 0x03, 0xd0, 0x23, 0xd3, 0x03, 0x70, 0x42, 0xbb, 0x06, 0xf0, 0x28, 0xba, 0x0f, 0xf0, 0x7a }; + int i; + int ofst; + int rom_size = 0x900000; + dynamic_buffer buf( rom_size ); + + for (i = 0; i < 0x100000; i++) + { + rom[ 0x800000 + i ] ^= rom[ 0x100002 | i ]; + } + for( i = 0; i < 0x100000; i++) + { + rom[ i ] ^= xor1[ (BYTE_XOR_LE(i) % 0x20) ]; + } + for( i = 0x100000; i < 0x800000; i++) + { + rom[ i ] ^= xor2[ (BYTE_XOR_LE(i) % 0x20) ]; + } + for( i = 0x100000; i < 0x800000; i += 4) + { + UINT16 rom16; + rom16 = rom[BYTE_XOR_LE(i+1)] | rom[BYTE_XOR_LE(i+2)]<<8; + rom16 = BITSWAP16( rom16, 15, 14, 13, 12, 5, 4, 7, 6, 9, 8, 11, 10, 3, 2, 1, 0 ); + rom[BYTE_XOR_LE(i+1)] = rom16&0xff; + rom[BYTE_XOR_LE(i+2)] = rom16>>8; + } + for( i = 0; i < 0x0100000 / 0x10000; i++ ) + { + ofst = (i & 0xf0) + BITSWAP8((i & 0x0f), 7, 6, 5, 4, 0, 1, 2, 3); + memcpy( &buf[ i * 0x10000 ], &rom[ ofst * 0x10000 ], 0x10000 ); + } + for( i = 0x100000; i < 0x900000; i += 0x100) + { + ofst = (i & 0xf000ff) + ((i & 0x000f00) ^ 0x00800) + (BITSWAP8( ((i & 0x0ff000) >> 12), 4, 5, 6, 7, 1, 0, 3, 2 ) << 12); + memcpy( &buf[ i ], &rom[ ofst ], 0x100 ); + } + memcpy (&rom[0x000000], &buf[0x000000], 0x100000); + memcpy (&rom[0x100000], &buf[0x800000], 0x100000); + memcpy (&rom[0x200000], &buf[0x100000], 0x700000); +} + + +void pvc_prot_device::kof2003h_decrypt_68k(UINT8* rom, UINT32 size) +{ + static const UINT8 xor1[0x20] = { 0xc2, 0x4b, 0x74, 0xfd, 0x0b, 0x34, 0xeb, 0xd7, 0x10, 0x6d, 0xf9, 0xce, 0x5d, 0xd5, 0x61, 0x29, 0xf5, 0xbe, 0x0d, 0x82, 0x72, 0x45, 0x0f, 0x24, 0xb3, 0x34, 0x1b, 0x99, 0xea, 0x09, 0xf3, 0x03 }; + static const UINT8 xor2[0x20] = { 0x2b, 0x09, 0xd0, 0x7f, 0x51, 0x0b, 0x10, 0x4c, 0x5b, 0x07, 0x70, 0x9d, 0x3e, 0x0b, 0xb0, 0xb6, 0x54, 0x09, 0xe0, 0xcc, 0x3d, 0x0d, 0x80, 0x99, 0x87, 0x03, 0x90, 0x82, 0xfe, 0x04, 0x20, 0x18 }; + int i; + int ofst; + int rom_size = 0x900000; + dynamic_buffer buf( rom_size ); + + for (i = 0; i < 0x100000; i++) + { + rom[ 0x800000 + i ] ^= rom[ 0x100002 | i ]; + } + for( i = 0; i < 0x100000; i++) + { + rom[ i ] ^= xor1[ (BYTE_XOR_LE(i) % 0x20) ]; + } + for( i = 0x100000; i < 0x800000; i++) + { + rom[ i ] ^= xor2[ (BYTE_XOR_LE(i) % 0x20) ]; + } + for( i = 0x100000; i < 0x800000; i += 4) + { + UINT16 rom16; + rom16 = rom[BYTE_XOR_LE(i+1)] | rom[BYTE_XOR_LE(i+2)]<<8; + rom16 = BITSWAP16( rom16, 15, 14, 13, 12, 10, 11, 8, 9, 6, 7, 4, 5, 3, 2, 1, 0 ); + rom[BYTE_XOR_LE(i+1)] = rom16&0xff; + rom[BYTE_XOR_LE(i+2)] = rom16>>8; + } + for( i = 0; i < 0x0100000 / 0x10000; i++ ) + { + ofst = (i & 0xf0) + BITSWAP8((i & 0x0f), 7, 6, 5, 4, 1, 0, 3, 2); + memcpy( &buf[ i * 0x10000 ], &rom[ ofst * 0x10000 ], 0x10000 ); + } + for( i = 0x100000; i < 0x900000; i += 0x100) + { + ofst = (i & 0xf000ff) + ((i & 0x000f00) ^ 0x00400) + (BITSWAP8( ((i & 0x0ff000) >> 12), 6, 7, 4, 5, 0, 1, 2, 3 ) << 12); + memcpy( &buf[ i ], &rom[ ofst ], 0x100 ); + } + memcpy (&rom[0x000000], &buf[0x000000], 0x100000); + memcpy (&rom[0x100000], &buf[0x800000], 0x100000); + memcpy (&rom[0x200000], &buf[0x100000], 0x700000); +} diff --git a/src/devices/bus/neogeo/pvc_prot.h b/src/devices/bus/neogeo/pvc_prot.h new file mode 100644 index 00000000000..794783cc4dd --- /dev/null +++ b/src/devices/bus/neogeo/pvc_prot.h @@ -0,0 +1,50 @@ +// license:BSD-3-Clause +// copyright-holders:S. Smith,David Haywood + +#pragma once + +#include "banked_cart.h" + +#ifndef __PVC_PROT__ +#define __PVC_PROT__ + +extern const device_type PVC_PROT; + +#define MCFG_PVC_PROT_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, PVC_PROT, 0) + + +class pvc_prot_device : public device_t +{ +public: + // construction/destruction + pvc_prot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + void pvc_write_unpack_color(); + void pvc_write_pack_color(); + void pvc_write_bankswitch(address_space &space); + DECLARE_READ16_MEMBER(pvc_prot_r); + DECLARE_WRITE16_MEMBER(pvc_prot_w); + void install_pvc_protection(cpu_device* maincpu, neogeo_banked_cart_device* bankdev); + neogeo_banked_cart_device* m_bankdev; + + UINT16 m_cartridge_ram[0x1000]; + + void mslug5_decrypt_68k(UINT8* rom, UINT32 size); + void svc_px_decrypt(UINT8* rom, UINT32 size); + void kf2k3pcb_decrypt_68k(UINT8* rom, UINT32 size); + void kof2003_decrypt_68k(UINT8* rom, UINT32 size); + void kof2003h_decrypt_68k(UINT8* rom, UINT32 size); + +protected: + virtual void device_start(); + virtual void device_reset(); + + + +private: + + +}; + +#endif diff --git a/src/devices/bus/neogeo/rom.c b/src/devices/bus/neogeo/rom.c new file mode 100644 index 00000000000..085e68edec2 --- /dev/null +++ b/src/devices/bus/neogeo/rom.c @@ -0,0 +1,70 @@ +// license:BSD-3-Clause +// copyright-holders:S. Smith,David Haywood +/*********************************************************************************************************** + + NEOGEO ROM cart emulation + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "rom.h" + + +//------------------------------------------------- +// neogeo_rom_device - constructor +//------------------------------------------------- + +const device_type NEOGEO_ROM = &device_creator; + + +neogeo_rom_device::neogeo_rom_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT16 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_neogeo_cart_interface( mconfig, *this ), + m_banked_cart(*this, "banked_cart") +{ +} + +neogeo_rom_device::neogeo_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT16 clock) + : device_t(mconfig, NEOGEO_ROM, "NEOGEO ROM Carts", tag, owner, clock, "neogeo_rom", __FILE__), + device_neogeo_cart_interface( mconfig, *this ), + m_banked_cart(*this, "banked_cart") +{ +} + + +//------------------------------------------------- +// mapper specific start/reset +//------------------------------------------------- + +void neogeo_rom_device::device_start() +{ +} + +void neogeo_rom_device::device_reset() +{ +} + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +READ16_MEMBER(neogeo_rom_device::read_rom) +{ + return m_rom[offset]; +} + +static MACHINE_CONFIG_FRAGMENT( banked_cart ) + MCFG_NEOGEO_BANKED_CART_ADD("banked_cart") +MACHINE_CONFIG_END + +machine_config_constructor neogeo_rom_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( banked_cart ); +} + +void neogeo_rom_device::activate_cart(ACTIVATE_CART_PARAMS) +{ + m_banked_cart->install_banks(machine, maincpu, cpuregion, cpuregion_size); +} diff --git a/src/devices/bus/neogeo/rom.h b/src/devices/bus/neogeo/rom.h new file mode 100644 index 00000000000..9394a7ec5bd --- /dev/null +++ b/src/devices/bus/neogeo/rom.h @@ -0,0 +1,38 @@ +// license:BSD-3-Clause +// copyright-holders:S. Smith,David Haywood +#ifndef __NEOGEO_ROM_H +#define __NEOGEO_ROM_H + +#include "neogeo_slot.h" +#include "banked_cart.h" + +// ======================> neogeo_rom_device + +class neogeo_rom_device : public device_t, + public device_neogeo_cart_interface +{ +public: + // construction/destruction + neogeo_rom_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT16 clock, const char *shortname, const char *source); + neogeo_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT16 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual machine_config_constructor device_mconfig_additions() const; + + // reading and writing + virtual DECLARE_READ16_MEMBER(read_rom); + + virtual void activate_cart(ACTIVATE_CART_PARAMS); + + required_device m_banked_cart; +}; + + + +// device type definition +extern const device_type NEOGEO_ROM; + + +#endif diff --git a/src/devices/bus/neogeo/sbp_prot.c b/src/devices/bus/neogeo/sbp_prot.c new file mode 100644 index 00000000000..a286bbbb88e --- /dev/null +++ b/src/devices/bus/neogeo/sbp_prot.c @@ -0,0 +1,86 @@ +// license:BSD-3-Clause +// copyright-holders:S. Smith,David Haywood + + +#include "emu.h" +#include "sbp_prot.h" + + + +extern const device_type SBP_PROT = &device_creator; + + +sbp_prot_device::sbp_prot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, SBP_PROT, "NeoGeo Protection (Super Bubble Pop)", tag, owner, clock, "sbp_prot", __FILE__) +{ +} + + +void sbp_prot_device::device_start() +{ +} + +void sbp_prot_device::device_reset() +{ +} + + + +READ16_MEMBER( sbp_prot_device::sbp_lowerrom_r ) +{ + UINT16* rom = (UINT16*)m_mainrom; + UINT16 origdata = rom[(offset+(0x200/2))]; + UINT16 data = BITSWAP16(origdata, 11,10,9,8,15,14,13,12,3,2,1,0,7,6,5,4); + int realoffset = 0x200+(offset*2); + logerror("sbp_lowerrom_r offset %08x data %04x\n", realoffset, data ); + + // there is actually data in the rom here already, maybe we should just return it 'as is' + if (realoffset==0xd5e) return origdata; + + return data; +} + +WRITE16_MEMBER( sbp_prot_device::sbp_lowerrom_w ) +{ + int realoffset = 0x200+(offset*2); + + // the actual data written is just pulled from the end of the rom, and unused space + // maybe this is just some kind of watchdog for the protection device and it doesn't + // matter? + if (realoffset == 0x1080) + { + if (data==0x4e75) + { + return; + } + else if (data==0xffff) + { + return; + } + } + + printf("sbp_lowerrom_w offset %08x data %04x\n", realoffset, data ); +} + + +void sbp_prot_device::sbp_install_protection(cpu_device* maincpu, UINT8* cpurom, UINT32 cpurom_size) +{ + m_mainrom = cpurom; + + // there seems to be a protection device living around here.. + // if you nibble swap the data in the rom the game will boot + // there are also writes to 0x1080.. + // + // other stuff going on as well tho, the main overlay is still missing, and p1 inputs don't work + maincpu->space(AS_PROGRAM).install_read_handler(0x00200, 0x001fff, read16_delegate(FUNC(sbp_prot_device::sbp_lowerrom_r), this)); + maincpu->space(AS_PROGRAM).install_write_handler(0x00200, 0x001fff, write16_delegate(FUNC(sbp_prot_device::sbp_lowerrom_w), this)); + + /* the game code clears the text overlay used ingame immediately after writing it.. why? protection? sloppy code that the hw ignores? imperfect emulation? */ + { + UINT16* rom = (UINT16*)cpurom; + + rom[0x2a6f8 / 2] = 0x4e71; + rom[0x2a6fa / 2] = 0x4e71; + rom[0x2a6fc / 2] = 0x4e71; + } +} diff --git a/src/devices/bus/neogeo/sbp_prot.h b/src/devices/bus/neogeo/sbp_prot.h new file mode 100644 index 00000000000..7aa5ebb67da --- /dev/null +++ b/src/devices/bus/neogeo/sbp_prot.h @@ -0,0 +1,40 @@ +// license:BSD-3-Clause +// copyright-holders:S. Smith,David Haywood + + +#pragma once + +#ifndef __SBP_PROT__ +#define __SBP_PROT__ + +extern const device_type SBP_PROT; + +#define MCFG_SBP_PROT_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, SBP_PROT, 0) + + +class sbp_prot_device : public device_t +{ +public: + // construction/destruction + sbp_prot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + + UINT8* m_mainrom; + + void sbp_install_protection(cpu_device* maincpu, UINT8* cpurom, UINT32 cpurom_size); + DECLARE_WRITE16_MEMBER(sbp_lowerrom_w); + DECLARE_READ16_MEMBER(sbp_lowerrom_r); + +protected: + virtual void device_start(); + virtual void device_reset(); + + + +private: + + +}; + +#endif diff --git a/src/devices/bus/neogeo/sma_cart.c b/src/devices/bus/neogeo/sma_cart.c new file mode 100644 index 00000000000..61e07b962f3 --- /dev/null +++ b/src/devices/bus/neogeo/sma_cart.c @@ -0,0 +1,177 @@ +// license:BSD-3-Clause +// copyright-holders:S. Smith,David Haywood +/*********************************************************************************************************** + + NEOGEO ROM cart emulation + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "sma_cart.h" + + +//------------------------------------------------- +// neogeo_sma_cart - constructor +//------------------------------------------------- + +const device_type NEOGEO_SMA_CART = &device_creator; + + +neogeo_sma_cart::neogeo_sma_cart(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT16 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_neogeo_cart_interface(mconfig, *this), + m_banked_cart(*this, "banked_cart"), + m_sma_prot(*this, "sma_prot"), + m_cmc_prot(*this, "cmc_prot") + +{ +} + +neogeo_sma_cart::neogeo_sma_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT16 clock) + : device_t(mconfig, NEOGEO_SMA_CART, "NEOGEO SMA Cart", tag, owner, clock, "neogeo_rom", __FILE__), + device_neogeo_cart_interface(mconfig, *this), + m_banked_cart(*this, "banked_cart"), + m_sma_prot(*this, "sma_prot"), + m_cmc_prot(*this, "cmc_prot") +{ +} + + +//------------------------------------------------- +// mapper specific start/reset +//------------------------------------------------- + +void neogeo_sma_cart::device_start() +{ +} + +void neogeo_sma_cart::device_reset() +{ +} + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +READ16_MEMBER(neogeo_sma_cart::read_rom) +{ + return m_rom[offset]; +} + +static MACHINE_CONFIG_FRAGMENT( sma_cart ) + MCFG_NEOGEO_BANKED_CART_ADD("banked_cart") + MCFG_SMA_PROT_ADD("sma_prot") + MCFG_CMC_PROT_ADD("cmc_prot") +MACHINE_CONFIG_END + +machine_config_constructor neogeo_sma_cart::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( sma_cart ); +} + + + +/* Individual cartridge types (mirror DRIVER_INIT functionality) */ + +/************************************************* + KOF 99 +**************************************************/ + +const device_type NEOGEO_SMA_KOF99_CART = &device_creator; + +neogeo_sma_kof99_cart::neogeo_sma_kof99_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : neogeo_sma_cart(mconfig, NEOGEO_SMA_KOF99_CART, "NEOGEO SMA Kof99 Cart", tag, owner, clock, "sma_kof99_cart", __FILE__) {} + +void neogeo_sma_kof99_cart::decrypt_all(DECRYPT_ALL_PARAMS) +{ + m_sma_prot->kof99_decrypt_68k(cpuregion); + m_cmc_prot->kof99_neogeo_gfx_decrypt(spr_region, spr_region_size, fix_region, fix_region_size, KOF99_GFX_KEY); +} + +void neogeo_sma_kof99_cart::activate_cart(ACTIVATE_CART_PARAMS) +{ + m_banked_cart->install_banks(machine, maincpu, cpuregion, cpuregion_size); + m_sma_prot->kof99_install_protection(maincpu, m_banked_cart); +} + + + + +/************************************************* + Garou +**************************************************/ + +const device_type NEOGEO_SMA_GAROU_CART = &device_creator; + +neogeo_sma_garou_cart::neogeo_sma_garou_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : neogeo_sma_cart(mconfig, NEOGEO_SMA_GAROU_CART, "NEOGEO SMA Garou Cart", tag, owner, clock, "sma_garou_cart", __FILE__) {} + +void neogeo_sma_garou_cart::decrypt_all(DECRYPT_ALL_PARAMS) +{ + m_sma_prot->garou_decrypt_68k(cpuregion); + m_cmc_prot->kof99_neogeo_gfx_decrypt(spr_region, spr_region_size, fix_region, fix_region_size, GAROU_GFX_KEY); +} + +void neogeo_sma_garou_cart::activate_cart(ACTIVATE_CART_PARAMS) +{ + m_banked_cart->install_banks(machine, maincpu, cpuregion, cpuregion_size); + m_sma_prot->garou_install_protection(maincpu, m_banked_cart); +} + +const device_type NEOGEO_SMA_GAROUH_CART = &device_creator; + +neogeo_sma_garouh_cart::neogeo_sma_garouh_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : neogeo_sma_cart(mconfig, NEOGEO_SMA_GAROU_CART, "NEOGEO SMA Garou (alt) Cart", tag, owner, clock, "sma_garouh_cart", __FILE__) {} + +void neogeo_sma_garouh_cart::decrypt_all(DECRYPT_ALL_PARAMS) +{ + m_sma_prot->garouh_decrypt_68k(cpuregion); + m_cmc_prot->kof99_neogeo_gfx_decrypt(spr_region, spr_region_size, fix_region, fix_region_size, GAROU_GFX_KEY); +} + +void neogeo_sma_garouh_cart::activate_cart(ACTIVATE_CART_PARAMS) +{ + m_banked_cart->install_banks(machine, maincpu, cpuregion, cpuregion_size); + m_sma_prot->garouh_install_protection(maincpu, m_banked_cart); +} + + +/************************************************* + Metal Slug 3 +**************************************************/ + +const device_type NEOGEO_SMA_MSLUG3_CART = &device_creator; + +neogeo_sma_mslug3_cart::neogeo_sma_mslug3_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : neogeo_sma_cart(mconfig, NEOGEO_SMA_MSLUG3_CART, "NEOGEO SMA Mslug3 Cart", tag, owner, clock, "sma_mslug3_cart", __FILE__) {} + +void neogeo_sma_mslug3_cart::decrypt_all(DECRYPT_ALL_PARAMS) +{ + m_sma_prot->mslug3_decrypt_68k(cpuregion); + m_cmc_prot->kof99_neogeo_gfx_decrypt(spr_region, spr_region_size, fix_region, fix_region_size, MSLUG3_GFX_KEY); +} + +void neogeo_sma_mslug3_cart::activate_cart(ACTIVATE_CART_PARAMS) +{ + m_banked_cart->install_banks(machine, maincpu, cpuregion, cpuregion_size); + m_sma_prot->mslug3_install_protection(maincpu, m_banked_cart); +} + +/************************************************* + KOF2000 +**************************************************/ + +const device_type NEOGEO_SMA_KOF2000_CART = &device_creator; + +neogeo_sma_kof2000_cart::neogeo_sma_kof2000_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : neogeo_sma_cart(mconfig, NEOGEO_SMA_KOF2000_CART, "NEOGEO SMA KOF2000 Cart", tag, owner, clock, "sma_kof2000_cart", __FILE__) {} + +void neogeo_sma_kof2000_cart::decrypt_all(DECRYPT_ALL_PARAMS) +{ + m_sma_prot->kof2000_decrypt_68k(cpuregion); + m_cmc_prot->neogeo_cmc50_m1_decrypt(audiocrypt_region, audiocrypt_region_size, audiocpu_region, audio_region_size); + m_cmc_prot->kof2000_neogeo_gfx_decrypt(spr_region, spr_region_size, fix_region, fix_region_size, KOF2000_GFX_KEY); +} + +void neogeo_sma_kof2000_cart::activate_cart(ACTIVATE_CART_PARAMS) +{ + m_banked_cart->install_banks(machine, maincpu, cpuregion, cpuregion_size); + m_sma_prot->kof2000_install_protection(maincpu, m_banked_cart); +} diff --git a/src/devices/bus/neogeo/sma_cart.h b/src/devices/bus/neogeo/sma_cart.h new file mode 100644 index 00000000000..d0b0fb64432 --- /dev/null +++ b/src/devices/bus/neogeo/sma_cart.h @@ -0,0 +1,112 @@ +// license:BSD-3-Clause +// copyright-holders:S. Smith,David Haywood +#ifndef __NEOGEO_SMA_CART_H +#define __NEOGEO_SMA_CART_H + +#include "neogeo_slot.h" +#include "banked_cart.h" +#include "sma_prot.h" +#include "cmc_prot.h" + +// ======================> neogeo_sma_cart + +class neogeo_sma_cart : public device_t, + public device_neogeo_cart_interface +{ +public: + // construction/destruction + neogeo_sma_cart(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT16 clock, const char *shortname, const char *source); + neogeo_sma_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT16 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual machine_config_constructor device_mconfig_additions() const; + + // reading and writing + virtual DECLARE_READ16_MEMBER(read_rom); + + virtual void activate_cart(ACTIVATE_CART_PARAMS) {} + virtual void decrypt_all(DECRYPT_ALL_PARAMS) {} + virtual int get_fixed_bank_type(void) { return 0; } + + required_device m_banked_cart; + required_device m_sma_prot; + required_device m_cmc_prot; +}; + + + +// device type definition +extern const device_type NEOGEO_SMA_CART; + + +/************************************************* + KOF 99 +**************************************************/ + +class neogeo_sma_kof99_cart : public neogeo_sma_cart +{ +public: + neogeo_sma_kof99_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual void activate_cart(ACTIVATE_CART_PARAMS); + virtual void decrypt_all(DECRYPT_ALL_PARAMS); + virtual int get_fixed_bank_type(void) { return 1; } +}; +extern const device_type NEOGEO_SMA_KOF99_CART; + +/************************************************* + Garou +**************************************************/ + +class neogeo_sma_garou_cart : public neogeo_sma_cart +{ +public: + neogeo_sma_garou_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual void activate_cart(ACTIVATE_CART_PARAMS); + virtual void decrypt_all(DECRYPT_ALL_PARAMS); + virtual int get_fixed_bank_type(void) { return 1; } +}; +extern const device_type NEOGEO_SMA_GAROU_CART; + +class neogeo_sma_garouh_cart : public neogeo_sma_cart +{ +public: + neogeo_sma_garouh_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual void activate_cart(ACTIVATE_CART_PARAMS); + virtual void decrypt_all(DECRYPT_ALL_PARAMS); + virtual int get_fixed_bank_type(void) { return 1; } +}; +extern const device_type NEOGEO_SMA_GAROUH_CART; + +/************************************************* + Metal Slug 3 +**************************************************/ + +class neogeo_sma_mslug3_cart : public neogeo_sma_cart +{ +public: + neogeo_sma_mslug3_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual void activate_cart(ACTIVATE_CART_PARAMS); + virtual void decrypt_all(DECRYPT_ALL_PARAMS); + virtual int get_fixed_bank_type(void) { return 1; } +}; +extern const device_type NEOGEO_SMA_MSLUG3_CART; + + +/************************************************* + KOF2000 +**************************************************/ + +class neogeo_sma_kof2000_cart : public neogeo_sma_cart +{ +public: + neogeo_sma_kof2000_cart(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual void activate_cart(ACTIVATE_CART_PARAMS); + virtual void decrypt_all(DECRYPT_ALL_PARAMS); + virtual int get_fixed_bank_type(void) { return 2; } +}; +extern const device_type NEOGEO_SMA_KOF2000_CART; + + +#endif diff --git a/src/devices/bus/neogeo/sma_prot.c b/src/devices/bus/neogeo/sma_prot.c new file mode 100644 index 00000000000..5fe723375a0 --- /dev/null +++ b/src/devices/bus/neogeo/sma_prot.c @@ -0,0 +1,462 @@ +// license:BSD-3-Clause +// copyright-holders:S. Smith,David Haywood +#include "emu.h" +#include "sma_prot.h" + + + +extern const device_type SMA_PROT = &device_creator; + + +sma_prot_device::sma_prot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, SMA_PROT, "NeoGeo SMA Cartridge", tag, owner, clock, "sma_prot", __FILE__) +{ +} + + +void sma_prot_device::device_start() +{ + save_item(NAME(m_sma_rng)); +} + +void sma_prot_device::device_reset() +{ + reset_sma_rng(); +} + + + + + +/************************ SMA Protection************************ + thanks to Razoola +***************************************************************/ + +WRITE16_MEMBER( sma_prot_device::kof99_bankswitch_w ) +{ + int bankaddress; + static const int bankoffset[64] = + { + 0x000000, 0x100000, 0x200000, 0x300000, + 0x3cc000, 0x4cc000, 0x3f2000, 0x4f2000, + 0x407800, 0x507800, 0x40d000, 0x50d000, + 0x417800, 0x517800, 0x420800, 0x520800, + 0x424800, 0x524800, 0x429000, 0x529000, + 0x42e800, 0x52e800, 0x431800, 0x531800, + 0x54d000, 0x551000, 0x567000, 0x592800, + 0x588800, 0x581800, 0x599800, 0x594800, + 0x598000, /* rest not used? */ + }; + + /* unscramble bank number */ + data = + (((data>>14)&1)<<0)+ + (((data>> 6)&1)<<1)+ + (((data>> 8)&1)<<2)+ + (((data>>10)&1)<<3)+ + (((data>>12)&1)<<4)+ + (((data>> 5)&1)<<5); + + bankaddress = 0x100000 + bankoffset[data]; + m_bankdev->neogeo_set_main_cpu_bank_address(bankaddress); +} + + +WRITE16_MEMBER( sma_prot_device::garou_bankswitch_w ) +{ + /* thanks to Razoola and Mr K for the info */ + int bankaddress; + static const int bankoffset[64] = + { + 0x000000, 0x100000, 0x200000, 0x300000, // 00 + 0x280000, 0x380000, 0x2d0000, 0x3d0000, // 04 + 0x2f0000, 0x3f0000, 0x400000, 0x500000, // 08 + 0x420000, 0x520000, 0x440000, 0x540000, // 12 + 0x498000, 0x598000, 0x4a0000, 0x5a0000, // 16 + 0x4a8000, 0x5a8000, 0x4b0000, 0x5b0000, // 20 + 0x4b8000, 0x5b8000, 0x4c0000, 0x5c0000, // 24 + 0x4c8000, 0x5c8000, 0x4d0000, 0x5d0000, // 28 + 0x458000, 0x558000, 0x460000, 0x560000, // 32 + 0x468000, 0x568000, 0x470000, 0x570000, // 36 + 0x478000, 0x578000, 0x480000, 0x580000, // 40 + 0x488000, 0x588000, 0x490000, 0x590000, // 44 + 0x5d0000, 0x5d8000, 0x5e0000, 0x5e8000, // 48 + 0x5f0000, 0x5f8000, 0x600000, /* rest not used? */ + }; + + /* unscramble bank number */ + data = + (((data>> 5)&1)<<0)+ + (((data>> 9)&1)<<1)+ + (((data>> 7)&1)<<2)+ + (((data>> 6)&1)<<3)+ + (((data>>14)&1)<<4)+ + (((data>>12)&1)<<5); + + bankaddress = 0x100000 + bankoffset[data]; + m_bankdev->neogeo_set_main_cpu_bank_address(bankaddress); +} + + +WRITE16_MEMBER( sma_prot_device::garouh_bankswitch_w ) +{ + /* thanks to Razoola and Mr K for the info */ + int bankaddress; + static const int bankoffset[64] = + { + 0x000000, 0x100000, 0x200000, 0x300000, // 00 + 0x280000, 0x380000, 0x2d0000, 0x3d0000, // 04 + 0x2c8000, 0x3c8000, 0x400000, 0x500000, // 08 + 0x420000, 0x520000, 0x440000, 0x540000, // 12 + 0x598000, 0x698000, 0x5a0000, 0x6a0000, // 16 + 0x5a8000, 0x6a8000, 0x5b0000, 0x6b0000, // 20 + 0x5b8000, 0x6b8000, 0x5c0000, 0x6c0000, // 24 + 0x5c8000, 0x6c8000, 0x5d0000, 0x6d0000, // 28 + 0x458000, 0x558000, 0x460000, 0x560000, // 32 + 0x468000, 0x568000, 0x470000, 0x570000, // 36 + 0x478000, 0x578000, 0x480000, 0x580000, // 40 + 0x488000, 0x588000, 0x490000, 0x590000, // 44 + 0x5d8000, 0x6d8000, 0x5e0000, 0x6e0000, // 48 + 0x5e8000, 0x6e8000, 0x6e8000, 0x000000, // 52 + 0x000000, 0x000000, 0x000000, 0x000000, // 56 + 0x000000, 0x000000, 0x000000, 0x000000, // 60 + }; + + /* unscramble bank number */ + data = + (((data>> 4)&1)<<0)+ + (((data>> 8)&1)<<1)+ + (((data>>14)&1)<<2)+ + (((data>> 2)&1)<<3)+ + (((data>>11)&1)<<4)+ + (((data>>13)&1)<<5); + + bankaddress = 0x100000 + bankoffset[data]; + m_bankdev->neogeo_set_main_cpu_bank_address(bankaddress); +} + + +WRITE16_MEMBER( sma_prot_device::mslug3_bankswitch_w ) +{ + /* thanks to Razoola and Mr K for the info */ + int bankaddress; + static const int bankoffset[64] = + { + 0x000000, 0x020000, 0x040000, 0x060000, // 00 + 0x070000, 0x090000, 0x0b0000, 0x0d0000, // 04 + 0x0e0000, 0x0f0000, 0x120000, 0x130000, // 08 + 0x140000, 0x150000, 0x180000, 0x190000, // 12 + 0x1a0000, 0x1b0000, 0x1e0000, 0x1f0000, // 16 + 0x200000, 0x210000, 0x240000, 0x250000, // 20 + 0x260000, 0x270000, 0x2a0000, 0x2b0000, // 24 + 0x2c0000, 0x2d0000, 0x300000, 0x310000, // 28 + 0x320000, 0x330000, 0x360000, 0x370000, // 32 + 0x380000, 0x390000, 0x3c0000, 0x3d0000, // 36 + 0x400000, 0x410000, 0x440000, 0x450000, // 40 + 0x460000, 0x470000, 0x4a0000, 0x4b0000, // 44 + 0x4c0000, /* rest not used? */ + }; + + /* unscramble bank number */ + data = + (((data>>14)&1)<<0)+ + (((data>>12)&1)<<1)+ + (((data>>15)&1)<<2)+ + (((data>> 6)&1)<<3)+ + (((data>> 3)&1)<<4)+ + (((data>> 9)&1)<<5); + + bankaddress = 0x100000 + bankoffset[data]; + m_bankdev->neogeo_set_main_cpu_bank_address(bankaddress); +} + + +WRITE16_MEMBER( sma_prot_device::kof2000_bankswitch_w ) +{ + /* thanks to Razoola and Mr K for the info */ + int bankaddress; + static const int bankoffset[64] = + { + 0x000000, 0x100000, 0x200000, 0x300000, // 00 + 0x3f7800, 0x4f7800, 0x3ff800, 0x4ff800, // 04 + 0x407800, 0x507800, 0x40f800, 0x50f800, // 08 + 0x416800, 0x516800, 0x41d800, 0x51d800, // 12 + 0x424000, 0x524000, 0x523800, 0x623800, // 16 + 0x526000, 0x626000, 0x528000, 0x628000, // 20 + 0x52a000, 0x62a000, 0x52b800, 0x62b800, // 24 + 0x52d000, 0x62d000, 0x52e800, 0x62e800, // 28 + 0x618000, 0x619000, 0x61a000, 0x61a800, // 32 + }; + + /* unscramble bank number */ + data = + (((data>>15)&1)<<0)+ + (((data>>14)&1)<<1)+ + (((data>> 7)&1)<<2)+ + (((data>> 3)&1)<<3)+ + (((data>>10)&1)<<4)+ + (((data>> 5)&1)<<5); + + bankaddress = 0x100000 + bankoffset[data]; + m_bankdev->neogeo_set_main_cpu_bank_address(bankaddress); +} + + +READ16_MEMBER( sma_prot_device::prot_9a37_r ) +{ + return 0x9a37; +} + + +/* information about the sma random number generator provided by razoola */ +/* this RNG is correct for KOF99, other games might be different */ + +READ16_MEMBER( sma_prot_device::sma_random_r ) +{ + UINT16 old = m_sma_rng; + + UINT16 newbit = ((m_sma_rng >> 2) ^ + (m_sma_rng >> 3) ^ + (m_sma_rng >> 5) ^ + (m_sma_rng >> 6) ^ + (m_sma_rng >> 7) ^ + (m_sma_rng >>11) ^ + (m_sma_rng >>12) ^ + (m_sma_rng >>15)) & 1; + + m_sma_rng = (m_sma_rng << 1) | newbit; + + return old; +} + + +void sma_prot_device::reset_sma_rng() +{ + m_sma_rng = 0x2345; +} + + +void sma_prot_device::sma_install_random_read_handler(cpu_device* maincpu, int addr1, int addr2 ) +{ + maincpu->space(AS_PROGRAM).install_read_handler(addr1, addr1 + 1, read16_delegate(FUNC(sma_prot_device::sma_random_r),this)); + maincpu->space(AS_PROGRAM).install_read_handler(addr2, addr2 + 1, read16_delegate(FUNC(sma_prot_device::sma_random_r),this)); +} + + +void sma_prot_device::kof99_install_protection(cpu_device* maincpu, neogeo_banked_cart_device* bankdev) +{ + maincpu->space(AS_PROGRAM).install_write_handler(0x2ffff0, 0x2ffff1, write16_delegate(FUNC(sma_prot_device::kof99_bankswitch_w),this)); + maincpu->space(AS_PROGRAM).install_read_handler(0x2fe446, 0x2fe447, read16_delegate(FUNC(sma_prot_device::prot_9a37_r),this)); + m_bankdev = bankdev; + + sma_install_random_read_handler(maincpu, 0x2ffff8, 0x2ffffa); +} + + +void sma_prot_device::garou_install_protection(cpu_device* maincpu, neogeo_banked_cart_device* bankdev) +{ + maincpu->space(AS_PROGRAM).install_write_handler(0x2fffc0, 0x2fffc1, write16_delegate(FUNC(sma_prot_device::garou_bankswitch_w),this)); + maincpu->space(AS_PROGRAM).install_read_handler(0x2fe446, 0x2fe447, read16_delegate(FUNC(sma_prot_device::prot_9a37_r),this)); + m_bankdev = bankdev; + + sma_install_random_read_handler(maincpu, 0x2fffcc, 0x2ffff0); +} + + +void sma_prot_device::garouh_install_protection(cpu_device* maincpu, neogeo_banked_cart_device* bankdev) +{ + maincpu->space(AS_PROGRAM).install_write_handler(0x2fffc0, 0x2fffc1, write16_delegate(FUNC(sma_prot_device::garouh_bankswitch_w),this)); + maincpu->space(AS_PROGRAM).install_read_handler(0x2fe446, 0x2fe447, read16_delegate(FUNC(sma_prot_device::prot_9a37_r),this)); + m_bankdev = bankdev; + + sma_install_random_read_handler(maincpu, 0x2fffcc, 0x2ffff0); +} + + +void sma_prot_device::mslug3_install_protection(cpu_device* maincpu, neogeo_banked_cart_device* bankdev) +{ + maincpu->space(AS_PROGRAM).install_write_handler(0x2fffe4, 0x2fffe5, write16_delegate(FUNC(sma_prot_device::mslug3_bankswitch_w),this)); + maincpu->space(AS_PROGRAM).install_read_handler(0x2fe446, 0x2fe447, read16_delegate(FUNC(sma_prot_device::prot_9a37_r),this)); + m_bankdev = bankdev; + +// sma_install_random_read_handler(maincpu, 0x2ffff8, 0x2ffffa); +} + + +void sma_prot_device::kof2000_install_protection(cpu_device* maincpu, neogeo_banked_cart_device* bankdev) +{ + maincpu->space(AS_PROGRAM).install_write_handler(0x2fffec, 0x2fffed, write16_delegate(FUNC(sma_prot_device::kof2000_bankswitch_w),this)); + maincpu->space(AS_PROGRAM).install_read_handler(0x2fe446, 0x2fe447, read16_delegate(FUNC(sma_prot_device::prot_9a37_r),this)); + m_bankdev = bankdev; + + sma_install_random_read_handler(maincpu, 0x2fffd8, 0x2fffda); +} + + + +/* kof99, garou, garouh, mslug3 and kof2000 have and SMA chip which contains program code and decrypts the 68k roms */ +void sma_prot_device::kof99_decrypt_68k(UINT8* base) +{ + UINT16 *rom; + int i,j; + + rom = (UINT16 *)(base + 0x100000); + /* swap data lines on the whole ROMs */ + for (i = 0;i < 0x800000/2;i++) + { + rom[i] = BITSWAP16(rom[i],13,7,3,0,9,4,5,6,1,12,8,14,10,11,2,15); + } + + /* swap address lines for the banked part */ + for (i = 0;i < 0x600000/2;i+=0x800/2) + { + UINT16 buffer[0x800/2]; + memcpy(buffer,&rom[i],0x800); + for (j = 0;j < 0x800/2;j++) + { + rom[i+j] = buffer[BITSWAP24(j,23,22,21,20,19,18,17,16,15,14,13,12,11,10,6,2,4,9,8,3,1,7,0,5)]; + } + } + + /* swap address lines & relocate fixed part */ + rom = (UINT16 *)base; + for (i = 0;i < 0x0c0000/2;i++) + { + rom[i] = rom[0x700000/2 + BITSWAP24(i,23,22,21,20,19,18,11,6,14,17,16,5,8,10,12,0,4,3,2,7,9,15,13,1)]; + } +} + + +void sma_prot_device::garou_decrypt_68k(UINT8* base) +{ + UINT16 *rom; + int i,j; + + /* thanks to Razoola and Mr K for the info */ + rom = (UINT16 *)(base + 0x100000); + /* swap data lines on the whole ROMs */ + for (i = 0;i < 0x800000/2;i++) + { + rom[i] = BITSWAP16(rom[i],13,12,14,10,8,2,3,1,5,9,11,4,15,0,6,7); + } + + /* swap address lines & relocate fixed part */ + rom = (UINT16 *)base; + for (i = 0;i < 0x0c0000/2;i++) + { + rom[i] = rom[0x710000/2 + BITSWAP24(i,23,22,21,20,19,18,4,5,16,14,7,9,6,13,17,15,3,1,2,12,11,8,10,0)]; + } + + /* swap address lines for the banked part */ + rom = (UINT16 *)(base + 0x100000); + for (i = 0;i < 0x800000/2;i+=0x8000/2) + { + UINT16 buffer[0x8000/2]; + memcpy(buffer,&rom[i],0x8000); + for (j = 0;j < 0x8000/2;j++) + { + rom[i+j] = buffer[BITSWAP24(j,23,22,21,20,19,18,17,16,15,14,9,4,8,3,13,6,2,7,0,12,1,11,10,5)]; + } + } +} + + +void sma_prot_device::garouh_decrypt_68k(UINT8* base) +{ + UINT16 *rom; + int i,j; + + /* thanks to Razoola and Mr K for the info */ + rom = (UINT16 *)(base + 0x100000); + /* swap data lines on the whole ROMs */ + for (i = 0;i < 0x800000/2;i++) + { + rom[i] = BITSWAP16(rom[i],14,5,1,11,7,4,10,15,3,12,8,13,0,2,9,6); + } + + /* swap address lines & relocate fixed part */ + rom = (UINT16 *)base; + for (i = 0;i < 0x0c0000/2;i++) + { + rom[i] = rom[0x7f8000/2 + BITSWAP24(i,23,22,21,20,19,18,5,16,11,2,6,7,17,3,12,8,14,4,0,9,1,10,15,13)]; + } + + /* swap address lines for the banked part */ + rom = (UINT16 *)(base + 0x100000); + for (i = 0;i < 0x800000/2;i+=0x8000/2) + { + UINT16 buffer[0x8000/2]; + memcpy(buffer,&rom[i],0x8000); + for (j = 0;j < 0x8000/2;j++) + { + rom[i+j] = buffer[BITSWAP24(j,23,22,21,20,19,18,17,16,15,14,12,8,1,7,11,3,13,10,6,9,5,4,0,2)]; + } + } +} + + +void sma_prot_device::mslug3_decrypt_68k(UINT8* base) +{ + UINT16 *rom; + int i,j; + + /* thanks to Razoola and Mr K for the info */ + rom = (UINT16 *)(base + 0x100000); + /* swap data lines on the whole ROMs */ + for (i = 0;i < 0x800000/2;i++) + { + rom[i] = BITSWAP16(rom[i],4,11,14,3,1,13,0,7,2,8,12,15,10,9,5,6); + } + + /* swap address lines & relocate fixed part */ + rom = (UINT16 *)base; + for (i = 0;i < 0x0c0000/2;i++) + { + rom[i] = rom[0x5d0000/2 + BITSWAP24(i,23,22,21,20,19,18,15,2,1,13,3,0,9,6,16,4,11,5,7,12,17,14,10,8)]; + } + + /* swap address lines for the banked part */ + rom = (UINT16 *)(base + 0x100000); + for (i = 0;i < 0x800000/2;i+=0x10000/2) + { + UINT16 buffer[0x10000/2]; + memcpy(buffer,&rom[i],0x10000); + for (j = 0;j < 0x10000/2;j++) + { + rom[i+j] = buffer[BITSWAP24(j,23,22,21,20,19,18,17,16,15,2,11,0,14,6,4,13,8,9,3,10,7,5,12,1)]; + } + } +} + + +void sma_prot_device::kof2000_decrypt_68k(UINT8* base) +{ + UINT16 *rom; + int i,j; + + /* thanks to Razoola and Mr K for the info */ + rom = (UINT16 *)(base + 0x100000); + /* swap data lines on the whole ROMs */ + for (i = 0;i < 0x800000/2;i++) + { + rom[i] = BITSWAP16(rom[i],12,8,11,3,15,14,7,0,10,13,6,5,9,2,1,4); + } + + /* swap address lines for the banked part */ + for (i = 0;i < 0x63a000/2;i+=0x800/2) + { + UINT16 buffer[0x800/2]; + memcpy(buffer,&rom[i],0x800); + for (j = 0;j < 0x800/2;j++) + { + rom[i+j] = buffer[BITSWAP24(j,23,22,21,20,19,18,17,16,15,14,13,12,11,10,4,1,3,8,6,2,7,0,9,5)]; + } + } + + /* swap address lines & relocate fixed part */ + rom = (UINT16 *)base; + for (i = 0;i < 0x0c0000/2;i++) + { + rom[i] = rom[0x73a000/2 + BITSWAP24(i,23,22,21,20,19,18,8,4,15,13,3,14,16,2,6,17,7,12,10,0,5,11,1,9)]; + } +} diff --git a/src/devices/bus/neogeo/sma_prot.h b/src/devices/bus/neogeo/sma_prot.h new file mode 100644 index 00000000000..271e1248f4d --- /dev/null +++ b/src/devices/bus/neogeo/sma_prot.h @@ -0,0 +1,58 @@ +// license:BSD-3-Clause +// copyright-holders:S. Smith,David Haywood + + +#pragma once + +#include "banked_cart.h" + +#ifndef __SMA_PROT__ +#define __SMA_PROT__ + +extern const device_type SMA_PROT; + +#define MCFG_SMA_PROT_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, SMA_PROT, 0) + + +class sma_prot_device : public device_t +{ +public: + // construction/destruction + sma_prot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + + DECLARE_WRITE16_MEMBER( kof99_bankswitch_w ); + DECLARE_WRITE16_MEMBER( garou_bankswitch_w ); + DECLARE_WRITE16_MEMBER( garouh_bankswitch_w ); + DECLARE_WRITE16_MEMBER( mslug3_bankswitch_w ); + DECLARE_WRITE16_MEMBER( kof2000_bankswitch_w ); + DECLARE_READ16_MEMBER( prot_9a37_r ); + DECLARE_READ16_MEMBER( sma_random_r ); + void reset_sma_rng(); + void sma_install_random_read_handler(cpu_device* maincpu, int addr1, int addr2 ); + void kof99_install_protection(cpu_device* maincpu, neogeo_banked_cart_device* bankdev); + void garou_install_protection(cpu_device* maincpu, neogeo_banked_cart_device* bankdev); + void garouh_install_protection(cpu_device* maincpu, neogeo_banked_cart_device* bankdev); + void mslug3_install_protection(cpu_device* maincpu, neogeo_banked_cart_device* bankdev); + void kof2000_install_protection(cpu_device* maincpu, neogeo_banked_cart_device* bankdev); + neogeo_banked_cart_device* m_bankdev; + void kof99_decrypt_68k(UINT8* base); + void garou_decrypt_68k(UINT8* base); + void garouh_decrypt_68k(UINT8* base); + void mslug3_decrypt_68k(UINT8* base); + void kof2000_decrypt_68k(UINT8* base); + + UINT16 m_sma_rng; +protected: + virtual void device_start(); + virtual void device_reset(); + + + +private: + + +}; + +#endif diff --git a/src/devices/bus/nes/2a03pur.c b/src/devices/bus/nes/2a03pur.c new file mode 100644 index 00000000000..d7c807b63f2 --- /dev/null +++ b/src/devices/bus/nes/2a03pur.c @@ -0,0 +1,109 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + NES/Famicom cartridge emulation for 2A03 Puritans Album + + + Here we emulate the PCB designed by infiniteneslives and + rainwarrior for this homebew multicart [mapper 30?] + The main difference of this PCB compared to others is that it + uses 4k PRG banks! + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "2a03pur.h" + + +#ifdef NES_PCB_DEBUG +#define VERBOSE 1 +#else +#define VERBOSE 0 +#endif + +#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) + + +//------------------------------------------------- +// constructor +//------------------------------------------------- + +const device_type NES_2A03PURITANS = &device_creator; + + +nes_2a03pur_device::nes_2a03pur_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_2A03PURITANS, "NES Cart 2A03 Puritans Album PCB", tag, owner, clock, "nes_2a03pur", __FILE__) +{ +} + + + +void nes_2a03pur_device::device_start() +{ + common_start(); + save_item(NAME(m_reg)); + memset(m_reg, 0x00, sizeof(m_reg)); + m_reg[7] = 0xff; +} + +void nes_2a03pur_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + chr8(0, m_chr_source); + // register content is not touched by reset +} + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +/*------------------------------------------------- + + Board 2A03 Puritans Album + + In MESS: supported. + + This mapper supports up to 1MB of PRG-ROM, in 4k + banks located at $8000, $9000, $A000, $B000, $C000, + $D000, $E000, and $F000. Each bank is selected by n + 8-bit register at $5FF8, $5FF9, $5FFA, $5FFB, $5FFC, + $5FFD, $5FFE, and $5FFF, respectively, just like NSF + banking. These registers are mirrored across the + entire $5000-$5FFF region (the register is selected + by the low 3 bits), but it is recommended to use the + original addresses. The mirroring is merely a + convenience for the hardware implementation. + + The 8kb CHR region may be RAM or ROM. This project + uses CHR-RAM, and the board used by infiniteneslives + for this project may only support CHR-RAM. + + At power-on, the mapper automatically sets all bits + in the $5FFF bank register, placing the highest bank + in $F000. This occurs on power-on but not on reset, + so any bank that is mapped to $F000 after power-on + should contain a valid reset vector. + + At present, the project uses iNES mapper 30 to + designate this mapper. No mapper number has been + officially reserved yet. + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_2a03pur_device::write_l) +{ + LOG_MMC(("2a03 puritans write_l, offset: %04x, data: %02x\n", offset, data)); + offset += 0x100; + if (offset >= 0x1000) + m_reg[offset & 7] = data; +} + +READ8_MEMBER(nes_2a03pur_device::read_h) +{ + LOG_MMC(("2a03 puritans read_h, offset: %04x\n", offset)); + + return m_prg[(m_reg[(offset >> 12) & 7] * 0x1000) + (offset & 0x0fff)]; +} diff --git a/src/devices/bus/nes/2a03pur.h b/src/devices/bus/nes/2a03pur.h new file mode 100644 index 00000000000..c0d80f67bd1 --- /dev/null +++ b/src/devices/bus/nes/2a03pur.h @@ -0,0 +1,33 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __NES_2A03PUR_H +#define __NES_2A03PUR_H + +#include "nxrom.h" + + +// ======================> nes_racermate_device + +class nes_2a03pur_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_2a03pur_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_READ8_MEMBER(read_h); + virtual DECLARE_WRITE8_MEMBER(write_l); + + virtual void pcb_reset(); + +private: + UINT8 m_reg[8]; +}; + + + +// device type definition +extern const device_type NES_2A03PURITANS; + +#endif diff --git a/src/devices/bus/nes/act53.c b/src/devices/bus/nes/act53.c new file mode 100644 index 00000000000..a09244b3a85 --- /dev/null +++ b/src/devices/bus/nes/act53.c @@ -0,0 +1,206 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + NES/Famicom cartridge emulation for Action 53 + + + Here we emulate the Multi-Discrete PCB designed by Tepples for + this homebew multicart [mapper 28] + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "act53.h" + + +#ifdef NES_PCB_DEBUG +#define VERBOSE 1 +#else +#define VERBOSE 0 +#endif + +#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) + + +//------------------------------------------------- +// constructor +//------------------------------------------------- + +const device_type NES_ACTION53 = &device_creator; + + +nes_action53_device::nes_action53_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_ACTION53, "NES Cart Action 53 PCB", tag, owner, clock, "nes_action53", __FILE__) +{ +} + + + +void nes_action53_device::device_start() +{ + common_start(); + save_item(NAME(m_sel)); + save_item(NAME(m_reg)); + m_reg[0] = 0x00; + m_reg[1] = 0x0f; + m_reg[2] = 0x00; + m_reg[3] = 0x3f; +} + +void nes_action53_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + // register content is not touched by reset + update_prg(); +} + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +/*------------------------------------------------- + + Board ACTION 53 + + In MESS: *VERY* preliminary support. + + This board uses 4 registers (reg is selected by writes to 0x5xxx) + Info from nesdev wiki + + R:$00: [...M ..CC] + C = CHR Reg + M = Mirroring + This bit overwrites bit 0 of R:$80, but only if bit 1 of + R:$80 is clear + + R:$01: [...M PPPP] + P = PRG Reg + M = Mirroring + This bit overwrites bit 0 of R:$80, but only if bit 1 of + R:$80 is clear + + R:$80: [..GG PSMM] + G = Game Size (0=32K, 1=64K, 2=128K, 3=256K) + P = PRG Size (0=32k mode, 1=16k mode) + S = Slot select: + 0 = $C000 swappable, $8000 fixed to bottom of 32K outer bank + 1 = $8000 swappable, $C000 fixed to top of 32K outer bank + This bit is ignored when 'P' is clear (32k mode) + M = Mirroring control: + %00 = 1ScA + %01 = 1ScB + %10 = Vert + %11 = Horz + + R:$81: [..BB BBBB] + Outer PRG Reg + + + -------------------------------------------------*/ + +void nes_action53_device::update_prg() +{ + UINT8 prg_lo = 0, prg_hi = 0, helper = 0; + UINT8 out = (m_reg[3] & 0x3f) << 1; // Outer PRG reg + UINT8 size = (m_reg[2] & 0x30) >> 4; // Game size + UINT8 mask = (1 << (size + 1)) - 1; // Bits to be taken from PRG reg + + if (!BIT(m_reg[2], 3)) + { + helper = (out & ~mask) | ((m_reg[1] << 1) & mask); + //32K mode + prg_lo = (helper & 0xfe); + prg_hi = (helper | 0x01); + } + else + { + helper = (out & ~mask) | (m_reg[1] & mask); + if (BIT(m_reg[2], 2)) + { + //16K mode with fixed HI + prg_lo = helper; + prg_hi = (out | 0x01); + } + else + { + //16K mode with fixed LO + prg_lo = (out & 0xfe); + prg_hi = helper; + } + } + +// printf("banks : 0x%2X - 0x%2X\n", prg_lo, prg_hi); + prg16_89ab(prg_lo); + prg16_cdef(prg_hi); +} + +void nes_action53_device::update_mirr() +{ + switch (m_reg[2] & 0x03) + { + case 0: + set_nt_mirroring(PPU_MIRROR_LOW); + break; + case 1: + set_nt_mirroring(PPU_MIRROR_HIGH); + break; + case 2: + set_nt_mirroring(PPU_MIRROR_VERT); + break; + case 3: + set_nt_mirroring(PPU_MIRROR_HORZ); + break; + } +} + +WRITE8_MEMBER(nes_action53_device::write_l) +{ + LOG_MMC(("action 53 write_l, offset: %04x, data: %02x\n", offset, data)); + offset += 0x100; + if (offset >= 0x1000) + m_sel = BIT(data, 0) | (BIT(data, 7) << 1); +} + + +WRITE8_MEMBER(nes_action53_device::write_h) +{ + LOG_MMC(("action 53 write_h, offset: %04x, data: %02x\n", offset, data)); + + if (m_reg[m_sel] != data) + { + m_reg[m_sel] = data; + + switch (m_sel) + { + case 0: + if (!BIT(m_reg[2],1)) + { + m_reg[2] &= 0xfe; + m_reg[2] |= BIT(data,4); + update_mirr(); + } + chr8(m_reg[0] & 0x03, m_chr_source); + break; + case 1: + if (!BIT(m_reg[2],1)) + { + m_reg[2] &= 0xfe; + m_reg[2] |= BIT(data,4); + update_mirr(); + } + update_prg(); + break; + case 2: + update_prg(); + update_mirr(); + break; + case 3: + update_prg(); + break; + } + } +} diff --git a/src/devices/bus/nes/act53.h b/src/devices/bus/nes/act53.h new file mode 100644 index 00000000000..c870d600102 --- /dev/null +++ b/src/devices/bus/nes/act53.h @@ -0,0 +1,38 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __NES_ACTION53_H +#define __NES_ACTION53_H + +#include "nxrom.h" + + +// ======================> nes_racermate_device + +class nes_action53_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_action53_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_l); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); + +private: + void update_prg(); + void update_mirr(); + UINT8 m_sel; + UINT8 m_reg[4]; +}; + + + + + +// device type definition +extern const device_type NES_ACTION53; + +#endif diff --git a/src/devices/bus/nes/aladdin.c b/src/devices/bus/nes/aladdin.c new file mode 100644 index 00000000000..67749cbe12d --- /dev/null +++ b/src/devices/bus/nes/aladdin.c @@ -0,0 +1,339 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + NES/Famicom cartridge emulation for Camerica/Codemasters Aladdin Deck Enhancer pass-through cart + + + Here we emulate the following PCBs + + * Camerica ALGNV11 [mapper 71] + * Camerica ALGQV11 [mapper 232] + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "aladdin.h" + + +#ifdef NES_PCB_DEBUG +#define VERBOSE 1 +#else +#define VERBOSE 0 +#endif + +#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) + + + +//---------------------------------- +// +// Aladdin Cartslot implementation +// +//---------------------------------- + +//------------------------------------------------- +// sub-cart interface +//------------------------------------------------- + +aladdin_cart_interface::aladdin_cart_interface(const machine_config &mconfig, device_t &device) + : device_slot_card_interface(mconfig, device), + m_rom(NULL), + m_rom_size(0), + m_rom_mask(0xff) +{ +} + +aladdin_cart_interface::~aladdin_cart_interface() +{ +} + +READ8_MEMBER(aladdin_cart_interface::read) +{ + if (offset < 0x4000) + return m_rom[(m_lobank * 0x4000) + (offset & 0x3fff)]; + else + return m_rom[(m_hibank * 0x4000) + (offset & 0x3fff)]; +} + +//------------------------------------------------- +// sub-cart slot device +//------------------------------------------------- + +const device_type NES_ALADDIN_SLOT = &device_creator; + +nes_aladdin_slot_device::nes_aladdin_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, NES_ALADDIN_SLOT, "NES Aladdin Deck Enhancer Cartridge Slot", tag, owner, clock, "nes_ade_slot", __FILE__), + device_image_interface(mconfig, *this), + device_slot_interface(mconfig, *this) +{ +} + +nes_aladdin_slot_device::~nes_aladdin_slot_device() +{ +} + + +void nes_aladdin_slot_device::device_start() +{ + m_cart = dynamic_cast(get_card_device()); +} + +READ8_MEMBER(nes_aladdin_slot_device::read) +{ + if (m_cart) + return m_cart->read(space, offset, mem_mask); + + return 0xff; +} + +// 128K for Dizzy The Adventurer, 256K for the others +bool nes_aladdin_slot_device::call_load() +{ + if (m_cart) + { + UINT8 *ROM = m_cart->get_cart_base(); + UINT32 size = 0; + + if (!ROM) + return IMAGE_INIT_FAIL; + + if (software_entry() == NULL) + { + if (length() != 0x20010 && length() != 0x40010) + return IMAGE_INIT_FAIL; + + UINT8 temp[0x40010]; + size = length() - 0x10; + fread(&temp, length()); + memcpy(ROM, temp + 0x10, size); + + // double check that iNES files are really mapper 71 or 232 + { + UINT8 mapper = (temp[6] & 0xf0) >> 4; + mapper |= temp[7] & 0xf0; + if (mapper != 71 && mapper != 232) + return IMAGE_INIT_FAIL; + } + } + else + { + if (get_software_region_length("rom") != 0x20000 && get_software_region_length("rom") != 0x40000) + return IMAGE_INIT_FAIL; + + size = get_software_region_length("rom"); + memcpy(ROM, get_software_region("rom"), size); + } + + m_cart->set_cart_size(size); + } + + return IMAGE_INIT_PASS; +} + + +bool nes_aladdin_slot_device::call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry) +{ + load_software_part_region(*this, swlist, swname, start_entry ); + return TRUE; +} + +void nes_aladdin_slot_device::get_default_card_software(std::string &result) +{ + if (open_image_file(mconfig().options())) + { + const char *slot_string = "algn"; + UINT32 len = core_fsize(m_file); + dynamic_buffer rom(len); + UINT8 mapper; + + core_fread(m_file, &rom[0], len); + + mapper = (rom[6] & 0xf0) >> 4; + mapper |= rom[7] & 0xf0; + +// if (mapper == 71) +// slot_string = "algn"; + if (mapper == 232) + slot_string = "algq"; + + clear(); + + result.assign(slot_string); + } + else + software_get_default_slot(result, "algn"); +} + + +//---------------------------------- +// +// Aladdin Minicart implementation +// +//---------------------------------- + +ROM_START( ade_rom ) + ROM_REGION(0x40000, "aderom", ROMREGION_ERASEFF) +ROM_END + +const device_type NES_ALGN_ROM = &device_creator; +const device_type NES_ALGQ_ROM = &device_creator; + +nes_algn_rom_device::nes_algn_rom_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + aladdin_cart_interface( mconfig, *this ) +{ +} + +nes_algn_rom_device::nes_algn_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, NES_ALGN_ROM, "NES Aladdin Deck Enhancer ALGN ROM", tag, owner, clock, "nes_algn_rom", __FILE__), + aladdin_cart_interface( mconfig, *this ) +{ +} + +nes_algq_rom_device::nes_algq_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_algn_rom_device(mconfig, NES_ALGQ_ROM, "NES Aladdin Deck Enhancer ALGQ ROM", tag, owner, clock, "nes_algq_rom", __FILE__) +{ +} + +void nes_algn_rom_device::device_start() +{ + m_rom = (UINT8*)memregion("aderom")->base(); + save_item(NAME(m_lobank)); +} + +void nes_algn_rom_device::device_reset() +{ + m_lobank = 0; + m_hibank = 0x0f & m_rom_mask; +} + +void nes_algq_rom_device::device_start() +{ + m_rom = (UINT8*)memregion("aderom")->base(); + save_item(NAME(m_lobank)); + save_item(NAME(m_hibank)); + save_item(NAME(m_bank_base)); +} + +void nes_algq_rom_device::device_reset() +{ + m_lobank = 0; + m_hibank = 3; + m_bank_base = 0; +} + +const rom_entry *nes_algn_rom_device::device_rom_region() const +{ + return ROM_NAME( ade_rom ); +} + +UINT8 *nes_algn_rom_device::get_cart_base() +{ + return m_rom; +} + +void nes_algn_rom_device::write_prg(UINT32 offset, UINT8 data) +{ + // m_hibank is fixed to the last available bank! + if (offset >= 0x4000) + m_lobank = data & m_rom_mask; +} + +void nes_algq_rom_device::write_prg(UINT32 offset, UINT8 data) +{ + // here hibank & lobank variables are used differently + // m_bank_base = 64K block + // m_lobank = 16K page inside the block + // m_hibank = 3rd page inside the block + if (offset < 0x4000) + { + m_bank_base = ((data >> 3) & 3) << 2; + m_lobank = m_bank_base | (m_lobank & 3); + m_hibank = m_bank_base | 3; + } + else + m_lobank = m_bank_base | (data & 3); +} + + +//----------------------------------------------- +// +// Camerica/Codemasters Aladdin passthru +// implementation +// +//----------------------------------------------- + +const device_type NES_ALADDIN = &device_creator; + +nes_aladdin_device::nes_aladdin_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_ALADDIN, "NES Cart Camerica Aladdin PCB", tag, owner, clock, "nes_aladdin", __FILE__), + m_subslot(*this, "ade_slot") +{ +} + + +void nes_aladdin_device::device_start() +{ + common_start(); +} + +void nes_aladdin_device::pcb_reset() +{ + prg32(0xff); + chr8(0, CHRRAM); +} + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +/*------------------------------------------------- + + Camerica/Codemasters Aladdin Deck Enhancer + + iNES: mapper 71 & 232 + + In MESS: Supported (but timing issues in some games) + + -------------------------------------------------*/ + +READ8_MEMBER(nes_aladdin_device::read_h) +{ + LOG_MMC(("aladdin read_h, offset: %04x\n", offset)); + // this shall be the proper code, but it's a bit slower, so we access directly the subcart below + //return m_subslot->read(space, offset, mem_mask); + + if (m_subslot->m_cart) + return m_subslot->m_cart->read(space, offset, mem_mask); + else // this is "fake" in the sense that we fill CPU space with 0xff if no Aladdin cart is loaded + return hi_access_rom(offset); +} + +WRITE8_MEMBER(nes_aladdin_device::write_h) +{ + LOG_MMC(("aladdin write_h, offset: %04x, data: %02x\n", offset, data)); + m_subslot->write_prg(offset, data); +} + +//------------------------------------------------- +// CART SLOT +//------------------------------------------------- + +static SLOT_INTERFACE_START(ade_cart) + SLOT_INTERFACE_INTERNAL("algn", NES_ALGN_ROM) + SLOT_INTERFACE_INTERNAL("algq", NES_ALGQ_ROM) +SLOT_INTERFACE_END + + +MACHINE_CONFIG_FRAGMENT( camerica_aladdin ) + MCFG_ALADDIN_MINICART_ADD("ade_slot", ade_cart) +MACHINE_CONFIG_END + +machine_config_constructor nes_aladdin_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( camerica_aladdin ); +} diff --git a/src/devices/bus/nes/aladdin.h b/src/devices/bus/nes/aladdin.h new file mode 100644 index 00000000000..18bcf988a1b --- /dev/null +++ b/src/devices/bus/nes/aladdin.h @@ -0,0 +1,167 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __NES_ALADDIN_H +#define __NES_ALADDIN_H + +#include "nxrom.h" + + +//---------------------------------- +// +// Aladdin Cartslot implementation +// +//---------------------------------- + +// ======================> aladdin_cart_interface + +class aladdin_cart_interface : public device_slot_card_interface +{ +public: + // construction/destruction + aladdin_cart_interface(const machine_config &mconfig, device_t &device); + virtual ~aladdin_cart_interface(); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read); + + UINT8 *get_cart_base() { return m_rom; } + void set_cart_size(UINT32 size) { m_rom_size = size; m_rom_mask = (size / 0x4000) - 1; } + virtual void write_prg(UINT32 offset, UINT8 data) { } + +protected: + // internal state + UINT8 *m_rom; + UINT32 m_rom_size; + UINT8 m_lobank, m_hibank, m_rom_mask; +}; + +// ======================> nes_aladdin_slot_device + +class nes_aladdin_slot_device : public device_t, + public device_image_interface, + public device_slot_interface +{ +public: + // construction/destruction + nes_aladdin_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual ~nes_aladdin_slot_device(); + + // device-level overrides + virtual void device_start(); + virtual void device_config_complete() { update_names(); } + + // image-level overrides + virtual bool call_load(); + virtual bool call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry); + + virtual iodevice_t image_type() const { return IO_CARTSLOT; } + virtual bool is_readable() const { return 1; } + virtual bool is_writeable() const { return 0; } + virtual bool is_creatable() const { return 0; } + virtual bool must_be_loaded() const { return 0; } + virtual bool is_reset_on_load() const { return 1; } + virtual const char *image_interface() const { return "ade_cart"; } + virtual const char *file_extensions() const { return "nes,bin"; } + virtual const option_guide *create_option_guide() const { return NULL; } + + // slot interface overrides + virtual void get_default_card_software(std::string &result); + + virtual DECLARE_READ8_MEMBER(read); + void write_prg(UINT32 offset, UINT8 data) { if (m_cart) m_cart->write_prg(offset, data); } + + aladdin_cart_interface* m_cart; +}; + +// device type definition +extern const device_type NES_ALADDIN_SLOT; + + +#define MCFG_ALADDIN_MINICART_ADD(_tag, _slot_intf) \ + MCFG_DEVICE_ADD(_tag, NES_ALADDIN_SLOT, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, NULL, false) + + +//---------------------------------- +// +// Aladdin Minicart implementation +// +//---------------------------------- + +// ======================> nes_algn_rom_device + +class nes_algn_rom_device : public device_t, + public aladdin_cart_interface +{ +public: + // construction/destruction + nes_algn_rom_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + nes_algn_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual UINT8* get_cart_base(); + virtual void write_prg(UINT32 offset, UINT8 data); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); +}; + + +// ======================> nes_algq_rom_device + +class nes_algq_rom_device : public nes_algn_rom_device +{ +public: + // construction/destruction + nes_algq_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual void write_prg(UINT32 offset, UINT8 data); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + UINT8 m_bank_base; +}; + +// device type definition +extern const device_type NES_ALGN_ROM; +extern const device_type NES_ALGQ_ROM; + + +//----------------------------------------------- +// +// Codemasters Aladdin passthru implementation +// +//----------------------------------------------- + +// ======================> nes_aladdin_device + +class nes_aladdin_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_aladdin_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual machine_config_constructor device_mconfig_additions() const; + virtual DECLARE_READ8_MEMBER(read_h); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); + +protected: + required_device m_subslot; +}; + + +// device type definition +extern const device_type NES_ALADDIN; + +#endif diff --git a/src/devices/bus/nes/ave.c b/src/devices/bus/nes/ave.c new file mode 100644 index 00000000000..bc24f1294a5 --- /dev/null +++ b/src/devices/bus/nes/ave.c @@ -0,0 +1,214 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + NES/Famicom cartridge emulation for AVE PCBs + + + Here we emulate the following PCBs + + * AVE Nina-001 [mapper 34] + * AVE Nina-006/Nina-003/MB-91 [mapper 79] + * AVE Maxi 15 [mapper 234] + + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "ave.h" + + +#ifdef NES_PCB_DEBUG +#define VERBOSE 1 +#else +#define VERBOSE 0 +#endif + +#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) + + +//------------------------------------------------- +// constructor +//------------------------------------------------- + +const device_type NES_NINA001 = &device_creator; +const device_type NES_NINA006 = &device_creator; +const device_type NES_MAXI15 = &device_creator; + + +nes_nina001_device::nes_nina001_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_NINA001, "NES Cart AVE Nina-001 PCB", tag, owner, clock, "nes_nina001", __FILE__) +{ +} + +nes_nina006_device::nes_nina006_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_NINA006, "NES Cart AVE Nina-006 PCB", tag, owner, clock, "nes_nina006", __FILE__) +{ +} + +nes_maxi15_device::nes_maxi15_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_MAXI15, "NES Cart AVE Maxi 15 PCB", tag, owner, clock, "nes_maxi15", __FILE__) +{ +} + + + + +void nes_nina001_device::device_start() +{ + common_start(); +} + +void nes_nina001_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); +} + +void nes_nina006_device::device_start() +{ + common_start(); +} + +void nes_nina006_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); +} + + +void nes_maxi15_device::device_start() +{ + common_start(); + save_item(NAME(m_bank)); + save_item(NAME(m_reg)); +} + +void nes_maxi15_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); + set_nt_mirroring(PPU_MIRROR_VERT); + + m_reg = 0; + m_bank = 0; +} + + + + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +/*------------------------------------------------- + + AVE NINA-001 board emulation + + iNES: mapper 34 + + Notice that in this board the bankswitch regs + overlaps WRAM, so that writes to the regs are + then readable back in WRAM (WRAM is tested by + Impossible Mission II at start) + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_nina001_device::write_m) +{ + LOG_MMC(("nina-001 write_m, offset: %04x, data: %02x\n", offset, data)); + + switch (offset) + { + case 0x1ffd: + prg32(data); + break; + case 0x1ffe: + chr4_0(data, CHRROM); + break; + case 0x1fff: + chr4_4(data, CHRROM); + break; + } + + m_prgram[offset] = data; +} + +/*------------------------------------------------- + + AVE NINA-003, NINA-006 and MB-91 boards emulation + + Games: Krazy Kreatures, Poke Block, Puzzle, Pyramid, + Solitaire, Ultimate League Soccer + + iNES: mapper 79 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_nina006_device::write_l) +{ + LOG_MMC(("nina-006 write_l, offset: %04x, data: %02x\n", offset, data)); + + if (!(offset & 0x0100)) + { + prg32(data >> 3); + chr8(data & 7, CHRROM); + } +} + +/*------------------------------------------------- + + AVE Maxi 15 boards emulation + + Games: Maxi 15 + + iNES: mapper 234 + + In MESS: Partially Supported. + + -------------------------------------------------*/ + +void nes_maxi15_device::update_banks() +{ + if (m_bank & 0x40) + { + prg32((m_bank & 0x0e) | (m_reg & 1)); + chr8(((m_bank & 0x0e) << 2) | ((m_reg >> 4) & 7), m_chr_source); + } + else + { + prg32(m_bank & 0x0f); + chr8(((m_bank & 0x0f) << 2) | ((m_reg >> 4) & 3), m_chr_source); + } +} + +READ8_MEMBER(nes_maxi15_device::read_h) +{ + LOG_MMC(("Maxi 15 read_h, offset: %04x\n", offset)); + + if (offset >= 0x7f80 && offset < 0x7fa0) + { + m_bank = hi_access_rom(offset); + set_nt_mirroring(BIT(m_bank, 7) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + update_banks(); + return m_bank; + } + if (offset >= 0x7fe8 && offset < 0x7ff8) + { + m_reg = hi_access_rom(offset); + update_banks(); + return m_reg; + } + + return hi_access_rom(offset); +} diff --git a/src/devices/bus/nes/ave.h b/src/devices/bus/nes/ave.h new file mode 100644 index 00000000000..9d35c3eb623 --- /dev/null +++ b/src/devices/bus/nes/ave.h @@ -0,0 +1,69 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __NES_AVE_H +#define __NES_AVE_H + +#include "nxrom.h" + + +// ======================> nes_nina001_device + +class nes_nina001_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_nina001_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_m); + + virtual void pcb_reset(); +}; + + +// ======================> nes_nina006_device + +class nes_nina006_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_nina006_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_l); + + virtual void pcb_reset(); +}; + + +// ======================> nes_maxi15_device + +class nes_maxi15_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_maxi15_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_READ8_MEMBER(read_h); + + virtual void pcb_reset(); + +private: + void update_banks(); + UINT8 m_reg, m_bank; +}; + + + + + +// device type definition +extern const device_type NES_NINA001; +extern const device_type NES_NINA006; +extern const device_type NES_MAXI15; + +#endif diff --git a/src/devices/bus/nes/bandai.c b/src/devices/bus/nes/bandai.c new file mode 100644 index 00000000000..4aa54055969 --- /dev/null +++ b/src/devices/bus/nes/bandai.c @@ -0,0 +1,479 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + NES/Famicom cartridge emulation for Bandai PCBs + + + Here we emulate the following PCBs + + * Bandai FCG [mapper 16] (older design, regs are only accessed in 0x6000-0x7fff range) + * Bandai LZ93D50 [mapper 16] (this extends FCG by solving issues when writing to 0x8000-0xffff) + * Bandai LZ93D50 + 24C01 EEPROM [mapper 159] + * Bandai LZ93D50 + 24C02 EEPROM [mapper 16] + * Bandai Famicom Jump 2 (aka LZ93D50 + SRAM) [mapper 153] + * Bandai Oeka Kids [mapper 96] + + * Bandai Datach Joint ROM System [mapper 157] is emulated in a separate source file + to implement also the subslot, but the PCB is basically a Bandai LZ93D50 + 24C02 EEPROM + pcb with added barcode reader and subslot + + * Bandai Karaoke Studio [mapper 188] is emulated in a separate source file + to implement also the subslot and the mic inputs + + + TODO: + - investigate why EEPROM does not work + - add support to the PPU for the code necessary to Oeka Kids games (also needed by UNL-DANCE2000 PCB) + - check the cause for the flickering in Famicom Jump 2 + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "bandai.h" + +#include "cpu/m6502/m6502.h" + +#ifdef NES_PCB_DEBUG +#define VERBOSE 1 +#else +#define VERBOSE 0 +#endif + +#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) + + + +//------------------------------------------------- +// constructor +//------------------------------------------------- + +const device_type NES_OEKAKIDS = &device_creator; +const device_type NES_FCG = &device_creator; +const device_type NES_LZ93D50 = &device_creator; +const device_type NES_LZ93D50_24C01 = &device_creator; +const device_type NES_LZ93D50_24C02 = &device_creator; +const device_type NES_FJUMP2 = &device_creator; + + +nes_oekakids_device::nes_oekakids_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_OEKAKIDS, "NES Cart Bandai Oeka Kids PCB", tag, owner, clock, "nes_oeka", __FILE__) +{ +} + +nes_fcg_device::nes_fcg_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : nes_nrom_device(mconfig, type, name, tag, owner, clock, shortname, source) +{ +} + +nes_fcg_device::nes_fcg_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_FCG, "NES Cart Bandai FCG PCB", tag, owner, clock, "nes_fcg", __FILE__) +{ +} + +nes_lz93d50_device::nes_lz93d50_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : nes_fcg_device(mconfig, type, name, tag, owner, clock, shortname, source) +{ +} + +nes_lz93d50_device::nes_lz93d50_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_fcg_device(mconfig, NES_LZ93D50, "NES Cart Bandai LZ93D50 PCB", tag, owner, clock, "nes_lz93d50", __FILE__) +{ +} + +nes_lz93d50_24c01_device::nes_lz93d50_24c01_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : nes_lz93d50_device(mconfig, type, name, tag, owner, clock, shortname, source), + m_i2cmem(*this, "i2cmem") +{ +} + +nes_lz93d50_24c01_device::nes_lz93d50_24c01_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_lz93d50_device(mconfig, NES_LZ93D50_24C01, "NES Cart Bandai LZ93D50 + 24C01 PCB", tag, owner, clock, "nes_lz93d50_ep1", __FILE__), + m_i2cmem(*this, "i2cmem") +{ +} + +nes_lz93d50_24c02_device::nes_lz93d50_24c02_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_lz93d50_24c01_device(mconfig, NES_LZ93D50_24C02, "NES Cart Bandai LZ93D50 + 24C02 PCB", tag, owner, clock, "nes_lz93d50_ep2", __FILE__) +{ +} + +nes_fjump2_device::nes_fjump2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_lz93d50_device(mconfig, NES_FJUMP2, "NES Cart Bandai Famicom Jump II PCB", tag, owner, clock, "nes_fjump2", __FILE__) +{ +} + + + +void nes_oekakids_device::device_start() +{ + common_start(); + save_item(NAME(m_latch)); + save_item(NAME(m_reg)); +} + +void nes_oekakids_device::pcb_reset() +{ + prg32(0); + chr4_0(0, CHRRAM); + chr4_4(3, CHRRAM); + set_nt_mirroring(PPU_MIRROR_LOW); + m_latch = 0; + m_reg = 0; +} + +void nes_fcg_device::device_start() +{ + common_start(); + irq_timer = timer_alloc(TIMER_IRQ); + irq_timer->adjust(attotime::zero, 0, machine().device("maincpu")->cycles_to_attotime(1)); + + save_item(NAME(m_irq_enable)); + save_item(NAME(m_irq_count)); +} + +void nes_fcg_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); + + m_irq_enable = 0; + m_irq_count = 0; +} + +void nes_lz93d50_24c01_device::device_start() +{ + common_start(); + irq_timer = timer_alloc(TIMER_IRQ); + irq_timer->adjust(attotime::zero, 0, machine().device("maincpu")->cycles_to_attotime(1)); + + save_item(NAME(m_irq_enable)); + save_item(NAME(m_irq_count)); + save_item(NAME(m_i2c_dir)); +} + +void nes_lz93d50_24c01_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); + + m_irq_enable = 0; + m_irq_count = 0; + m_i2c_dir = 0; +} + +void nes_fjump2_device::device_start() +{ + common_start(); + irq_timer = timer_alloc(TIMER_IRQ); + irq_timer->adjust(attotime::zero, 0, machine().device("maincpu")->cycles_to_attotime(1)); + + save_item(NAME(m_reg)); +} + +void nes_fjump2_device::pcb_reset() +{ + chr8(0, CHRRAM); + memset(m_reg, 0, sizeof(m_reg)); + set_prg(); + + m_irq_enable = 0; +} + + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +/*------------------------------------------------- + + Bandai Oeka Kids board emulation + + Games: Oeka Kids - Anpanman no Hiragana Daisuki, Oeka + Kids - Anpanman to Oekaki Shiyou!! + + This board can swap CHR whenever a PPU address line is + changed and we still do not emulate this. + + iNES: mapper 96 + + In MESS: Preliminary Support. + + -------------------------------------------------*/ + + +WRITE8_MEMBER(nes_oekakids_device::nt_w) +{ + int page = ((offset & 0xc00) >> 10); + +#if 0 + if (!(offset & 0x1000) && (offset & 0x3ff) < 0x3c0) + { + m_latch = (offset & 0x300) >> 8; + chr4_0(m_reg | m_latch, CHRRAM); + } +#endif + + m_nt_access[page][offset & 0x3ff] = data; +} + +READ8_MEMBER(nes_oekakids_device::nt_r) +{ + int page = ((offset & 0xc00) >> 10); + +#if 0 + if (!(offset & 0x1000) && (offset & 0x3ff) < 0x3c0) + { + m_latch = (offset & 0x300) >> 8; + chr4_0(m_reg | m_latch, CHRRAM); + } +#endif + + return m_nt_access[page][offset & 0x3ff]; +} + +void nes_oekakids_device::update_chr() +{ + chr4_0(m_reg | m_latch, CHRRAM); + chr4_4(m_reg | 0x03, CHRRAM); +} + +// this only monitors accesses to $2007 while we would need to monitor accesses to $2006... +void nes_oekakids_device::ppu_latch(offs_t offset) +{ +#if 0 + if ((offset & 0x3000) == 0x2000) + { + m_latch = (offset & 0x300) >> 8; + update_chr(); + } +#endif +} + +WRITE8_MEMBER(nes_oekakids_device::write_h) +{ + LOG_MMC(("oeka kids write_h, offset: %04x, data: %02x\n", offset, data)); + + prg32(data & 0x03); + m_reg = data & 0x04; + update_chr(); +} + +/*------------------------------------------------- + + Bandai FCG / LZ93D50 boards emulation + + There are several variants: plain board with or without SRAM, + board + 24C01 EEPROM, board + 24C02 EEPROM, board + Barcode + Reader (DATACH). + We currently only emulate the base hardware. + + Games: Crayon Shin-Chan - Ora to Poi Poi, Dragon Ball Z Gaiden, + Dragon Ball Z II & III, Rokudenashi Blues, SD Gundam + Gaiden - KGM2, Dragon Ball Z, Magical Taruruuto-kun, SD Gundam + Gaiden [with EEPROM], Dragon Ball, Dragon Ball 3, Famicom Jump, + Famicom Jump II [no EEPROM], Datach Games + + At the moment, we don't support EEPROM I/O + + iNES: mappers 16, 153 (see below), 157 & 159 + + In MESS: Supported + + -------------------------------------------------*/ + +void nes_fcg_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + if (id == TIMER_IRQ) + { + if (m_irq_enable) + { + // 16bit counter, IRQ fired when the counter goes from 1 to 0 + // after firing, the counter is *not* reloaded, but next clock + // counter wraps around from 0 to 0xffff + if (!m_irq_count) + m_irq_count = 0xffff; + else + m_irq_count--; + + if (!m_irq_count) + { + m_maincpu->set_input_line(M6502_IRQ_LINE, ASSERT_LINE); + m_irq_enable = 0; + } + } + } +} + +WRITE8_MEMBER(nes_fcg_device::fcg_write) +{ + LOG_MMC(("lz93d50_write, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x0f) + { + case 0: case 1: case 2: case 3: + case 4: case 5: case 6: case 7: + chr1_x(offset & 0x07, data, m_chr_source); + break; + case 8: + prg16_89ab(data); + break; + case 9: + switch (data & 0x03) + { + case 0: set_nt_mirroring(PPU_MIRROR_VERT); break; + case 1: set_nt_mirroring(PPU_MIRROR_HORZ); break; + case 2: set_nt_mirroring(PPU_MIRROR_LOW); break; + case 3: set_nt_mirroring(PPU_MIRROR_HIGH); break; + } + break; + case 0x0a: + m_irq_enable = data & 0x01; + m_maincpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE); + break; + case 0x0b: + m_irq_count = (m_irq_count & 0xff00) | data; + break; + case 0x0c: + m_irq_count = (m_irq_count & 0x00ff) | (data << 8); + break; + default: + logerror("lz93d50_write uncaught write, offset: %04x, data: %02x\n", offset, data); + break; + } +} + +WRITE8_MEMBER(nes_fcg_device::write_m) +{ + LOG_MMC(("lz93d50 write_m, offset: %04x, data: %02x\n", offset, data)); + + if (m_battery.empty() && m_prgram.empty()) + fcg_write(space, offset & 0x0f, data, mem_mask); + else if (!m_battery.empty()) + m_battery[offset] = data; + else + m_prgram[offset] = data; +} + +// FCG board does not access regs in 0x8000-0xffff space! +// only later design lz93d50 (and its variants do)! + +WRITE8_MEMBER(nes_lz93d50_24c01_device::write_h) +{ + LOG_MMC(("lz93d50_24c01 write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x0f) + { + case 0x0d: + m_i2cmem->write_scl(BIT(data, 5)); + m_i2cmem->write_sda(BIT(data, 6)); + m_i2c_dir = BIT(data, 7); + break; + default: + fcg_write(space, offset & 0x0f, data, mem_mask); + break; + } +} + +READ8_MEMBER(nes_lz93d50_24c01_device::read_m) +{ + LOG_MMC(("lz93d50 EEPROM read, offset: %04x\n", offset)); + if (m_i2c_dir) + return (m_i2cmem->read_sda() & 1) << 4; + else + return 0; +} + +//------------------------------------------------- +// SERIAL I2C DEVICE +//------------------------------------------------- + +MACHINE_CONFIG_FRAGMENT( bandai_i2c_24c01 ) + MCFG_24C01_ADD("i2cmem") +MACHINE_CONFIG_END + +machine_config_constructor nes_lz93d50_24c01_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( bandai_i2c_24c01 ); +} + + +MACHINE_CONFIG_FRAGMENT( bandai_i2c_24c02 ) + MCFG_24C02_ADD("i2cmem") +MACHINE_CONFIG_END + +machine_config_constructor nes_lz93d50_24c02_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( bandai_i2c_24c02 ); +} + + +/*------------------------------------------------- + + Bandai BANDAI-JUMP2 boards emulation + + This is a variant of LZ93D50, with SRAM and no EEPROM + The board is only used by Famicom Jump II, which + has no CHR and 512K of PRG, so it is not completely + clear if the CHR regs of LZ93D50 (i.e. offset & 0xf < 8) + would switch also CHR or if they are only used to select + upper 256K of PRG + + iNES: mappers 153 + + In MESS: Supported + + -------------------------------------------------*/ + +void nes_fjump2_device::set_prg() +{ + UINT8 prg_base = 0; + + for (int i = 0; i < 4; i++) + prg_base |= (m_reg[i] << 4); + + prg16_89ab(prg_base | m_reg[4]); + prg16_cdef(prg_base | 0x0f); +} + +READ8_MEMBER(nes_fjump2_device::read_m) +{ + LOG_MMC(("fjump2 read_m, offset: %04x\n", offset)); + return m_battery[offset & (m_battery.size() - 1)]; +} + +WRITE8_MEMBER(nes_fjump2_device::write_m) +{ + LOG_MMC(("fjump2 write_m, offset: %04x, data: %02x\n", offset, data)); + m_battery[offset & (m_battery.size() - 1)] = data; +} + +WRITE8_MEMBER(nes_fjump2_device::write_h) +{ + LOG_MMC(("fjump2 write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x0f) + { + case 0: case 1: case 2: case 3: + m_reg[offset & 0x0f] = BIT(data,0); + set_prg(); + break; + case 4: case 5: case 6: case 7: + // these have been verified to be disabled in this board + break; + case 8: + m_reg[4] = data & 0x0f; + set_prg(); + break; + default: + fcg_write(space, offset & 0x0f, data, mem_mask); + break; + } +} diff --git a/src/devices/bus/nes/bandai.h b/src/devices/bus/nes/bandai.h new file mode 100644 index 00000000000..ae19589be37 --- /dev/null +++ b/src/devices/bus/nes/bandai.h @@ -0,0 +1,141 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __NES_BANDAI_H +#define __NES_BANDAI_H + +#include "nxrom.h" +#include "machine/i2cmem.h" + + +// ======================> nes_oekakids_device + +class nes_oekakids_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_oekakids_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_h); + virtual DECLARE_READ8_MEMBER(nt_r); + virtual DECLARE_WRITE8_MEMBER(nt_w); + + virtual void pcb_reset(); + + virtual void ppu_latch(offs_t offset); + + // TODO: add oeka kids controller emulation +protected: + void update_chr(); + UINT8 m_reg, m_latch; +}; + + +// ======================> nes_fcg_device + +class nes_fcg_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_fcg_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + nes_fcg_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + virtual DECLARE_WRITE8_MEMBER(fcg_write); + virtual DECLARE_WRITE8_MEMBER(write_m); + + virtual void pcb_reset(); + +protected: + UINT16 m_irq_count; + int m_irq_enable; + + static const device_timer_id TIMER_IRQ = 0; + emu_timer *irq_timer; +}; + + +// ======================> nes_lz93d50_device + +class nes_lz93d50_device : public nes_fcg_device +{ +public: + // construction/destruction + nes_lz93d50_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + nes_lz93d50_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual DECLARE_WRITE8_MEMBER(write_h) { fcg_write(space, offset, data, mem_mask); } +}; + + +// ======================> nes_lz93d50_24c01_device + +class nes_lz93d50_24c01_device : public nes_lz93d50_device +{ +public: + // construction/destruction + nes_lz93d50_24c01_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + nes_lz93d50_24c01_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual machine_config_constructor device_mconfig_additions() const; + virtual DECLARE_READ8_MEMBER(read_m); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); + + // TODO: fix EEPROM I/O emulation + required_device m_i2cmem; + UINT8 m_i2c_dir; +}; + + +// ======================> nes_lz93d50_24c02_device + +class nes_lz93d50_24c02_device : public nes_lz93d50_24c01_device +{ +public: + // construction/destruction + nes_lz93d50_24c02_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual machine_config_constructor device_mconfig_additions() const; +}; + + +// ======================> nes_fjump2_device + +class nes_fjump2_device : public nes_lz93d50_device +{ +public: + // construction/destruction + nes_fjump2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_READ8_MEMBER(read_m); + virtual DECLARE_WRITE8_MEMBER(write_m); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); + +protected: + void set_prg(); + UINT8 m_reg[5]; +}; + + +// device type definition +extern const device_type NES_OEKAKIDS; +extern const device_type NES_FCG; +extern const device_type NES_LZ93D50; +extern const device_type NES_LZ93D50_24C01; +extern const device_type NES_LZ93D50_24C02; +extern const device_type NES_FJUMP2; + +#endif diff --git a/src/devices/bus/nes/benshieng.c b/src/devices/bus/nes/benshieng.c new file mode 100644 index 00000000000..b96c75e6297 --- /dev/null +++ b/src/devices/bus/nes/benshieng.c @@ -0,0 +1,105 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + NES/Famicom cartridge emulation for Benshieng PCBs + + + Here we emulate the following PCBs used by Benshieng multigame carts series + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "benshieng.h" + + +#ifdef NES_PCB_DEBUG +#define VERBOSE 1 +#else +#define VERBOSE 0 +#endif + +#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) + + +//------------------------------------------------- +// constructor +//------------------------------------------------- + +const device_type NES_BENSHIENG = &device_creator; + + +nes_benshieng_device::nes_benshieng_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_BENSHIENG, "NES Cart Benshieng PCB", tag, owner, clock, "nes_benshieng", __FILE__) +{ +} + + + + +void nes_benshieng_device::device_start() +{ + common_start(); + save_item(NAME(m_dipsetting)); + save_item(NAME(m_mmc_prg_bank)); + save_item(NAME(m_mmc_vrom_bank)); +} + +void nes_benshieng_device::pcb_reset() +{ + m_dipsetting = 0; + + m_mmc_prg_bank[0] = 0xff; + m_mmc_prg_bank[1] = 0xff; + m_mmc_prg_bank[2] = 0xff; + m_mmc_prg_bank[3] = 0xff; + memset(m_mmc_vrom_bank, 0, sizeof(m_mmc_vrom_bank)); + update_banks(); +} + + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +/*------------------------------------------------- + + BMC-BS-5 + + Games: a few 4 in 1 multicarts + + -------------------------------------------------*/ + +void nes_benshieng_device::update_banks() +{ + prg8_89(m_mmc_prg_bank[0]); + prg8_ab(m_mmc_prg_bank[1]); + prg8_cd(m_mmc_prg_bank[2]); + prg8_ef(m_mmc_prg_bank[3]); + chr2_0(m_mmc_vrom_bank[0], CHRROM); + chr2_2(m_mmc_vrom_bank[1], CHRROM); + chr2_4(m_mmc_vrom_bank[2], CHRROM); + chr2_6(m_mmc_vrom_bank[3], CHRROM); +} + +WRITE8_MEMBER(nes_benshieng_device::write_h) +{ + UINT8 helper = (offset & 0xc00) >> 10; + LOG_MMC(("benshieng write_h, offset: %04x, data: %02x\n", offset, data)); +// m_mmc_dipsetting = ioport("CARTDIPS")->read(); + + switch (offset & 0x7000) + { + case 0x0000: + m_mmc_vrom_bank[helper] = offset & 0x1f; + break; + case 0x2000: + if (BIT(offset, m_dipsetting + 4)) // mmc_dipsetting is always zero atm, given we have no way to add cart-based DIPs + m_mmc_prg_bank[helper] = offset & 0x0f; + break; + } + update_banks(); +} diff --git a/src/devices/bus/nes/benshieng.h b/src/devices/bus/nes/benshieng.h new file mode 100644 index 00000000000..2a042a432e4 --- /dev/null +++ b/src/devices/bus/nes/benshieng.h @@ -0,0 +1,34 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __NES_BENSHIENG_H +#define __NES_BENSHIENG_H + +#include "nxrom.h" + + +// ======================> nes_benshieng_device + +class nes_benshieng_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_benshieng_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); + +private: + void update_banks(); + UINT8 m_dipsetting; + UINT8 m_mmc_prg_bank[4]; + UINT8 m_mmc_vrom_bank[4]; +}; + + +// device type definition +extern const device_type NES_BENSHIENG; + +#endif diff --git a/src/devices/bus/nes/bootleg.c b/src/devices/bus/nes/bootleg.c new file mode 100644 index 00000000000..23b13b51711 --- /dev/null +++ b/src/devices/bus/nes/bootleg.c @@ -0,0 +1,1635 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + NES/Famicom cartridge emulation for Bootleg PCBs + + + Here we emulate the PCBs used in FDS2NES conversions which are common in the Taiwanese & HK markets + Notice that many of these have unusual PRG sizes (32KB+8KB, 32KB+24KB) partially mapped in the WRAM + area, or WRAM overlapping the usual PRG area, so that we often skip the usual bankswitching mechanisms + in favor of direct handling of the PRG accesses + + TODO: + - review all PCBs and fix the starting banks (which are often the main problem of not working games) + - investigate pcbs listed in FCEUmm but with apparently no dumps available (LE05 and LH53) + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "bootleg.h" + +#include "cpu/m6502/m6502.h" +#include "video/ppu2c0x.h" // this has to be included so that IRQ functions can access PPU_BOTTOM_VISIBLE_SCANLINE + + +#ifdef NES_PCB_DEBUG +#define VERBOSE 1 +#else +#define VERBOSE 0 +#endif + +#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) + + +//------------------------------------------------- +// constructor +//------------------------------------------------- + +const device_type NES_AX5705 = &device_creator; +const device_type NES_SC127 = &device_creator; +const device_type NES_MARIOBABY = &device_creator; +const device_type NES_ASN = &device_creator; +const device_type NES_SMB3PIRATE = &device_creator; +const device_type NES_BTL_DNINJA = &device_creator; +const device_type NES_WHIRLWIND_2706 = &device_creator; +const device_type NES_SMB2J = &device_creator; +const device_type NES_SMB2JA = &device_creator; +const device_type NES_SMB2JB = &device_creator; +const device_type NES_09034A = &device_creator; +const device_type NES_TOBIDASE = &device_creator; +const device_type NES_LH32 = &device_creator; +const device_type NES_LH10 = &device_creator; +const device_type NES_LH53 = &device_creator; +const device_type NES_2708 = &device_creator; +const device_type NES_AC08 = &device_creator; +const device_type NES_UNL_BB = &device_creator; +const device_type NES_MMALEE = &device_creator; +const device_type NES_SHUIGUAN = &device_creator; + + +nes_ax5705_device::nes_ax5705_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_AX5705, "NES Cart AX5705 PCB", tag, owner, clock, "nes_ax5705", __FILE__) +{ +} + +nes_sc127_device::nes_sc127_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_SC127, "NES Cart SC-127 PCB", tag, owner, clock, "nes_sc127", __FILE__) +{ +} + +nes_mbaby_device::nes_mbaby_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_MARIOBABY, "NES Cart Mario Baby Bootleg PCB", tag, owner, clock, "nes_mbaby", __FILE__) +{ +} + +nes_asn_device::nes_asn_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_ASN, "NES Cart Ai Senshi Nicol Bootleg PCB", tag, owner, clock, "nes_asn", __FILE__) +{ +} + +nes_smb3p_device::nes_smb3p_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_SMB3PIRATE, "NES Cart Super Mario Bros. 3 Pirate PCB", tag, owner, clock, "nes_smb3p", __FILE__) +{ +} + +nes_btl_dn_device::nes_btl_dn_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_BTL_DNINJA, "NES Cart DragonNinja Pirate PCB", tag, owner, clock, "nes_btl_dn", __FILE__) +{ +} + +nes_whirl2706_device::nes_whirl2706_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_WHIRLWIND_2706, "NES Cart Whirlwind 2706 PCB", tag, owner, clock, "nes_whirl2706", __FILE__) +{ +} + +nes_smb2j_device::nes_smb2j_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_SMB2J, "NES Cart Super Mario Bros. 2 Jpn PCB", tag, owner, clock, "nes_smb2j", __FILE__) +{ +} + +nes_smb2ja_device::nes_smb2ja_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_SMB2JA, "NES Cart Super Mario Bros. 2 Jpn (Alt) PCB", tag, owner, clock, "nes_smb2ja", __FILE__) +{ +} + +nes_smb2jb_device::nes_smb2jb_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_SMB2JB, "NES Cart Super Mario Bros. 2 Jpn (Alt 2) PCB", tag, owner, clock, "nes_smb2jb", __FILE__) +{ +} + +nes_09034a_device::nes_09034a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_09034A, "NES Cart 09-034A PCB", tag, owner, clock, "nes_09034a", __FILE__) +{ +} + +nes_tobidase_device::nes_tobidase_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_TOBIDASE, "NES Cart Tobidase Daisakusen Pirate PCB", tag, owner, clock, "nes_tobidase", __FILE__) +{ +} + +nes_lh32_device::nes_lh32_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_LH32, "NES Cart LH-32 Pirate PCB", tag, owner, clock, "nes_lh32", __FILE__) +{ +} + +nes_lh10_device::nes_lh10_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_LH10, "NES Cart LH-10 Pirate PCB", tag, owner, clock, "nes_lh10", __FILE__) +{ +} + +nes_lh53_device::nes_lh53_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_LH53, "NES Cart LH-53 Pirate PCB", tag, owner, clock, "nes_lh53", __FILE__) +{ +} + +nes_2708_device::nes_2708_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_2708, "NES Cart BTL-2708 Pirate PCB", tag, owner, clock, "nes_2708", __FILE__) +{ +} + +nes_ac08_device::nes_ac08_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_AC08, "NES Cart AC08 Pirate PCB", tag, owner, clock, "nes_ac08", __FILE__) +{ +} + +nes_unl_bb_device::nes_unl_bb_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_UNL_BB, "NES Cart FDS+CHR Pirate PCB", tag, owner, clock, "nes_unl_bb", __FILE__) +{ +} + +nes_mmalee_device::nes_mmalee_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_MMALEE, "NES Cart Super Mario Bros. Malee 2 Pirate PCB", tag, owner, clock, "nes_mmalee", __FILE__) +{ +} + +nes_shuiguan_device::nes_shuiguan_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_SHUIGUAN, "NES Cart Shui Guan Pipe Pirate PCB", tag, owner, clock, "nes_shuiguan", __FILE__) +{ +} + + + + +void nes_ax5705_device::device_start() +{ + common_start(); + save_item(NAME(m_mmc_prg_bank)); + save_item(NAME(m_mmc_vrom_bank)); +} + +void nes_ax5705_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + chr8(0, m_chr_source); + + m_mmc_prg_bank[0] = 0; + m_mmc_prg_bank[1] = 1; + prg8_89(m_mmc_prg_bank[0]); + prg8_ab(m_mmc_prg_bank[1]); + prg8_cd(0xfe); + prg8_ef(0xff); + + memset(m_mmc_vrom_bank, 0, sizeof(m_mmc_vrom_bank)); +} + +void nes_sc127_device::device_start() +{ + common_start(); + save_item(NAME(m_irq_enable)); + save_item(NAME(m_irq_count)); +} + +void nes_sc127_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0xff); + chr8(0, m_chr_source); + + m_irq_enable = 0; + m_irq_count = 0; +} + +void nes_mbaby_device::device_start() +{ + common_start(); + irq_timer = timer_alloc(TIMER_IRQ); + irq_timer->reset(); + timer_freq = machine().device("maincpu")->cycles_to_attotime(24576); + + save_item(NAME(m_irq_enable)); + save_item(NAME(m_latch)); +} + +void nes_mbaby_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32((m_prg_chunks - 1) >> 1); + chr8(0, m_chr_source); + + m_irq_enable = 0; + m_latch = 0; +} + +void nes_asn_device::device_start() +{ + common_start(); + save_item(NAME(m_latch)); +} + +void nes_asn_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32((m_prg_chunks - 1) >> 1); + chr8(0, m_chr_source); + + m_latch = 0; +} + +void nes_smb3p_device::device_start() +{ + common_start(); + irq_timer = timer_alloc(TIMER_IRQ); + irq_timer->adjust(attotime::zero, 0, machine().device("maincpu")->cycles_to_attotime(1)); + + save_item(NAME(m_irq_enable)); + save_item(NAME(m_irq_count)); +} + +void nes_smb3p_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg8_89((m_prg_chunks << 1) - 1); + prg8_ab(0); + prg8_cd(0); + prg8_ef((m_prg_chunks << 1) - 1); + chr8(0, m_chr_source); + + m_irq_enable = 0; + m_irq_count = 0; +} + +void nes_btl_dn_device::device_start() +{ + common_start(); + save_item(NAME(m_irq_count)); +} + +void nes_btl_dn_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); + + m_irq_count = 0; +} + +void nes_whirl2706_device::device_start() +{ + common_start(); + save_item(NAME(m_latch)); +} + +void nes_whirl2706_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0xff); + chr8(0, m_chr_source); + + m_latch = 0; +} + +void nes_smb2j_device::device_start() +{ + common_start(); + irq_timer = timer_alloc(TIMER_IRQ); + irq_timer->adjust(attotime::zero, 0, machine().device("maincpu")->cycles_to_attotime(1)); + + save_item(NAME(m_irq_enable)); + save_item(NAME(m_irq_count)); +} + +void nes_smb2j_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + chr8(0, m_chr_source); + prg8_89(1); + prg8_ab(0); + prg8_cd(0); + prg8_ef(9); + + m_irq_enable = 0; + m_irq_count = 0; +} + +void nes_smb2ja_device::device_start() +{ + common_start(); + irq_timer = timer_alloc(TIMER_IRQ); + irq_timer->adjust(attotime::zero, 0, machine().device("maincpu")->cycles_to_attotime(1)); + + save_item(NAME(m_irq_enable)); + save_item(NAME(m_irq_count)); +} + +void nes_smb2ja_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg8_89(0xfc); + prg8_ab(0xfd); + prg8_cd(0xfe); + prg8_ef(0xff); + chr8(0, m_chr_source); + + m_irq_enable = 0; + m_irq_count = 0; +} + +void nes_smb2jb_device::device_start() +{ + common_start(); + irq_timer = timer_alloc(TIMER_IRQ); + irq_timer->adjust(attotime::zero, 0, machine().device("maincpu")->cycles_to_attotime(1)); + + save_item(NAME(m_irq_enable)); + save_item(NAME(m_irq_count)); +} + +void nes_smb2jb_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg8_89(0x08); + prg8_ab(0x09); + prg8_cd(0); + prg8_ef(0x0b); + chr8(0, m_chr_source); + + m_irq_enable = 0; + m_irq_count = 0; +} + +void nes_09034a_device::device_start() +{ + common_start(); + save_item(NAME(m_reg)); +} + +void nes_09034a_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); + m_reg = 0; +} + +void nes_tobidase_device::device_start() +{ + common_start(); + save_item(NAME(m_latch)); +} + +void nes_tobidase_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(2); + chr8(0, m_chr_source); + + m_latch = 0; +} + +void nes_lh32_device::device_start() +{ + common_start(); + save_item(NAME(m_latch)); +} + +void nes_lh32_device::pcb_reset() +{ + chr8(0, CHRRAM); + + prg32((m_prg_chunks - 1) >> 1); + // 0xc000-0xdfff reads/writes WRAM + m_latch = 0xf; +} + +void nes_lh10_device::device_start() +{ + common_start(); + save_item(NAME(m_latch)); + save_item(NAME(m_reg)); +} + +void nes_lh10_device::pcb_reset() +{ + chr8(0, CHRRAM); + + prg8_89(0); + prg8_ab(0); + // 0xc000-0xdfff reads/writes WRAM + prg8_ef(0xff); + memset(m_reg, 0, sizeof(m_reg)); + m_latch = 0; +} + +void nes_lh53_device::device_start() +{ + common_start(); + irq_timer = timer_alloc(TIMER_IRQ); + irq_timer->adjust(attotime::zero, 0, machine().device("maincpu")->cycles_to_attotime(1)); + + save_item(NAME(m_irq_enable)); + save_item(NAME(m_irq_count)); + save_item(NAME(m_reg)); +} + +void nes_lh53_device::pcb_reset() +{ + chr8(0, CHRRAM); + + prg8_89(0xc); + prg8_ab(0xd); // last 2K are overlayed by WRAM + prg8_cd(0xe); // first 6K are overlayed by WRAM + prg8_ef(0xf); + m_reg = 0; + m_irq_count = 0; + m_irq_enable = 0; +} + +void nes_2708_device::device_start() +{ + common_start(); + save_item(NAME(m_reg)); +} + +void nes_2708_device::pcb_reset() +{ + chr8(0, CHRRAM); + + prg32(7); + // the upper PRG banks never change, but there are 8K of WRAM overlayed to the ROM area based on reg1 + m_reg[0] = 0; + m_reg[1] = 0; +} + +void nes_ac08_device::device_start() +{ + common_start(); + save_item(NAME(m_latch)); +} + +void nes_ac08_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + chr8(0, m_chr_source); + prg32(0xff); + m_latch = 0xff; +} + +void nes_unl_bb_device::device_start() +{ + common_start(); + save_item(NAME(m_reg)); +} + +void nes_unl_bb_device::pcb_reset() +{ + chr8(0, CHRROM); + prg32(0xff); + // the upper PRG banks never change, but there are 8K of WRAM overlayed to the ROM area based on reg1 + m_reg[0] = 0xff; + m_reg[1] = 0; +} + +void nes_mmalee_device::device_start() +{ + common_start(); +} + +void nes_mmalee_device::pcb_reset() +{ + chr8(0, CHRROM); + prg32(0); +} + +void nes_shuiguan_device::device_start() +{ + common_start(); + irq_timer = timer_alloc(TIMER_IRQ); + // always running and checking for IRQ every 114 cycles? or resetting every frame? + irq_timer->adjust(attotime::zero, 0, machine().device("maincpu")->cycles_to_attotime(114)); + + save_item(NAME(m_irq_enable)); + save_item(NAME(m_irq_count)); + save_item(NAME(m_mmc_vrom_bank)); +} + +void nes_shuiguan_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32((m_prg_chunks << 1) - 1); + chr8(0, m_chr_source); + + m_irq_enable = 0; + m_irq_count = 0; + memset(m_mmc_vrom_bank, 0, sizeof(m_mmc_vrom_bank)); +} + + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +/*------------------------------------------------- + + Board UNL-AX5705 + + Games: Super Mario Bros. Pocker Mali (Crayon Shin-chan pirate hack) + + In MESS: Supported + + -------------------------------------------------*/ + +void nes_ax5705_device::set_prg() +{ + prg8_89(m_mmc_prg_bank[0]); + prg8_ab(m_mmc_prg_bank[1]); +} + +WRITE8_MEMBER(nes_ax5705_device::write_h) +{ + UINT8 bank; + LOG_MMC(("ax5705 write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x700f) + { + case 0x0000: + m_mmc_prg_bank[0] = (data & 0x05) | ((data & 0x08) >> 2) | ((data & 0x02) << 2); + set_prg(); + break; + case 0x0008: + set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + break; + case 0x2000: + m_mmc_prg_bank[1] = (data & 0x05) | ((data & 0x08) >> 2) | ((data & 0x02) << 2); + set_prg(); + break; + /* CHR banks 0, 1, 4, 5 */ + case 0x2008: + case 0x200a: + case 0x4008: + case 0x400a: + bank = ((offset & 0x4000) ? 4 : 0) + ((offset & 0x0002) ? 1 : 0); + m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & 0xf0) | (data & 0x0f); + chr1_x(bank, m_mmc_vrom_bank[bank], CHRROM); + break; + case 0x2009: + case 0x200b: + case 0x4009: + case 0x400b: + bank = ((offset & 0x4000) ? 4 : 0) + ((offset & 0x0002) ? 1 : 0); + m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & 0x0f) | ((data & 0x04) << 3) | ((data & 0x02) << 5) | ((data & 0x09) << 4); + chr1_x(bank, m_mmc_vrom_bank[bank], CHRROM); + break; + /* CHR banks 2, 3, 6, 7 */ + case 0x4000: + case 0x4002: + case 0x6000: + case 0x6002: + bank = 2 + ((offset & 0x2000) ? 4 : 0) + ((offset & 0x0002) ? 1 : 0); + m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & 0xf0) | (data & 0x0f); + chr1_x(bank, m_mmc_vrom_bank[bank], CHRROM); + break; + case 0x4001: + case 0x4003: + case 0x6001: + case 0x6003: + bank = 2 + ((offset & 0x2000) ? 4 : 0) + ((offset & 0x0002) ? 1 : 0); + m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & 0x0f) | ((data & 0x04) << 3) | ((data & 0x02) << 5) | ((data & 0x09) << 4); + chr1_x(bank, m_mmc_vrom_bank[bank], CHRROM); + break; + } +} + +/*------------------------------------------------- + + SC-127 Board + + Games: Wario World II (Kirby Hack) + + iNES: mapper 35 + + In MESS: Supported + + -------------------------------------------------*/ + +void nes_sc127_device::hblank_irq(int scanline, int vblank, int blanked) +{ + if (scanline < PPU_BOTTOM_VISIBLE_SCANLINE && m_irq_enable) + { + m_irq_count--; + + if (!blanked && (m_irq_count == 0)) + { + LOG_MMC(("irq fired, scanline: %d (MAME %d, beam pos: %d)\n", scanline, + machine().first_screen()->vpos(), machine().first_screen()->hpos())); + m_maincpu->set_input_line(M6502_IRQ_LINE, HOLD_LINE); + m_irq_enable = 0; + } + } +} + +WRITE8_MEMBER(nes_sc127_device::write_h) +{ + LOG_MMC(("sc127 write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset) + { + case 0x0000: + prg8_89(data); + break; + case 0x0001: + prg8_ab(data); + break; + case 0x0002: +// m_mmc_prg_bank[offset & 0x02] = data; + prg8_cd(data); + break; + case 0x1000: + case 0x1001: + case 0x1002: + case 0x1003: + case 0x1004: + case 0x1005: + case 0x1006: + case 0x1007: +// m_mmc_vrom_bank[offset & 0x07] = data; + chr1_x(offset & 0x07, data, CHRROM); + break; + case 0x4002: + m_irq_enable = 0; + break; + case 0x4003: + m_irq_enable = 1; + break; + case 0x4005: + m_irq_count = data; + break; + case 0x5001: + set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + break; + } +} + +/*------------------------------------------------- + + BTL-MARIOBABY + + Games: Mario Baby, Ai Senshi Nicol + + iNES: mapper 42 + + In MESS: Supported. + + -------------------------------------------------*/ + +void nes_mbaby_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + if (id == TIMER_IRQ) + { + m_maincpu->set_input_line(M6502_IRQ_LINE, HOLD_LINE); + irq_timer->adjust(attotime::never); + } +} + +WRITE8_MEMBER(nes_mbaby_device::write_h) +{ + LOG_MMC(("Mario Baby write_h, offset: %04x, data: %02x\n", offset, data)); + + if (offset >= 0x7000) + { + switch (offset & 0x03) + { + case 0x00: + m_latch = data; + break; + case 0x01: + set_nt_mirroring(BIT(data, 3) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + break; + case 0x02: + /* Check if IRQ is being enabled */ + if (!m_irq_enable && (data & 0x02)) + { + m_irq_enable = 1; + irq_timer->adjust(timer_freq); + } + if (!(data & 0x02)) + { + m_irq_enable = 0; + irq_timer->adjust(attotime::never); + } + break; + } + } +} + +READ8_MEMBER(nes_mbaby_device::read_m) +{ + LOG_MMC(("Mario Baby read_m, offset: %04x\n", offset)); + return m_prg[(m_latch * 0x2000) + (offset & 0x1fff)]; +} + +/*------------------------------------------------- + + BTL-AISENSHINICOL + + Games: Ai Senshi Nicol + + iNES: mapper 42 with no IRQ and no NT, but CHR switch + + In MESS: Partially Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_asn_device::write_h) +{ + LOG_MMC(("Ai Senshi Nicol write_h, offset: %04x, data: %02x\n", offset, data)); + + if (offset == 0x0000) + chr8(data, CHRROM); + + if (offset == 0x7000) + m_latch = data; +} + +READ8_MEMBER(nes_asn_device::read_m) +{ + LOG_MMC(("Ai Senshi Nicol read_m, offset: %04x\n", offset)); + return m_prg[((m_latch * 0x2000) + (offset & 0x1fff)) & (m_prg_size - 1)]; +} + + +/*------------------------------------------------- + + BTL-SMB3 + + Games: Super Mario Bros. 3 Pirate + + iNES: mapper 106 + + In MESS: Supported. + + -------------------------------------------------*/ + +void nes_smb3p_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + if (id == TIMER_IRQ) + { + if (m_irq_enable) + { + if (m_irq_count == 0xffff) + { + m_maincpu->set_input_line(M6502_IRQ_LINE, HOLD_LINE); + m_irq_enable = 0; + } + else + m_irq_count++; + } + } +} + +WRITE8_MEMBER(nes_smb3p_device::write_h) +{ + LOG_MMC(("btl_smb3_w, offset: %04x, data: %02x\n", offset, data)); + switch (offset & 0x0f) + { + case 0x00: + case 0x02: + chr1_x(offset & 0x07, data & 0xfe, CHRROM); + break; + case 0x01: + case 0x03: + chr1_x(offset & 0x07, data | 0x01, CHRROM); + break; + case 0x04: case 0x05: + case 0x06: case 0x07: + chr1_x(offset & 0x07, data, CHRROM); + break; + case 0x08: + prg8_89(data | 0x10); + break; + case 0x09: + prg8_ab(data); + break; + case 0x0a: + prg8_cd(data); + break; + case 0x0b: + prg8_ef(data | 0x10); + break; + case 0x0c: + set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + break; + case 0x0d: + m_irq_count = 0; + m_irq_enable = 0; + break; + case 0x0e: + m_irq_count = (m_irq_count & 0xff00) | data; + break; + case 0x0f: + m_irq_count = (m_irq_count & 0x00ff) | (data << 8); + m_irq_enable = 1; + break; + } +} + +/*------------------------------------------------- + + BTL-DRAGONNINJA + + Games: Dragon Ninja (Bootleg), Super Mario Bros. 8 + + iNES: mapper 222 + + In MESS: Unsupported. + + -------------------------------------------------*/ + +/* Scanline based IRQ ? */ +void nes_btl_dn_device::hblank_irq(int scanline, int vblank, int blanked ) +{ + if (!m_irq_count || ++m_irq_count < 240) + return; + + m_irq_count = 0; + m_maincpu->set_input_line(M6502_IRQ_LINE, HOLD_LINE); +} + +WRITE8_MEMBER(nes_btl_dn_device::write_h) +{ + UINT8 bank; + LOG_MMC(("btl_dn write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x7003) + { + case 0x0000: + prg8_89(data); + break; + case 0x1000: + set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + break; + case 0x2000: + prg8_ab(data); + break; + case 0x3000: + case 0x3002: + case 0x4000: + case 0x4002: + case 0x5000: + case 0x5002: + case 0x6000: + case 0x6002: + bank = ((offset & 0x7000) - 0x3000) / 0x0800 + ((offset & 0x0002) >> 1); + chr1_x(bank, data, CHRROM); + break; + case 0x7000: + m_irq_count = data; + break; + } +} + +/*------------------------------------------------- + + BOOTLEG FC VERSIONS OF FDS GAMES + + -------------------------------------------------*/ + +/*------------------------------------------------- + + WHIRLWIND-2706 + + Games: Meikyuu Jiin Dababa (FDS conversion) and a few + others + + This PCB maps PRG in 0x6000-0x7fff + + iNES: mapper 108 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_whirl2706_device::write_h) +{ + LOG_MMC(("whirl2706 write_h, offset: %04x, data: %02x\n", offset, data)); + m_latch = data; +} + +READ8_MEMBER(nes_whirl2706_device::read_m) +{ + LOG_MMC(("whirl2706 read_m, offset: %04x\n", offset)); + return m_prg[(m_latch * 0x2000 + (offset & 0x1fff)) & (m_prg_size - 1)]; +} + +/*------------------------------------------------- + + Bootleg Board SMB2J + + Games: Super Mario Bros. 2 Pirate (LF36) + + iNES: mapper 43 + + In MESS: Supported. + + -------------------------------------------------*/ + +void nes_smb2j_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + if (id == TIMER_IRQ) + { + if (m_irq_enable) + { + if (m_irq_count == 0xfff) + { + m_maincpu->set_input_line(M6502_IRQ_LINE, HOLD_LINE); + m_irq_enable = 0; + m_irq_count = 0; + } + else + m_irq_count++; + } + } +} + +WRITE8_MEMBER(nes_smb2j_device::write_l) +{ + LOG_MMC(("smb2j write_l, offset: %04x, data: %02x\n", offset, data)); + offset += 0x100; + + if (offset == 0x122) // $4122 + m_irq_enable = data & 3; // maybe also m_irq_count = 0?!? +} + +WRITE8_MEMBER(nes_smb2j_device::write_h) +{ + LOG_MMC(("smb2j write_h, offset: %04x, data: %02x\n", offset, data)); + + if (offset == 0x122) // $8122 too? + m_irq_enable = data & 3; +} + +WRITE8_MEMBER(nes_smb2j_device::write_ex) +{ + LOG_MMC(("smb2j write_ex, offset: %04x, data: %02x\n", offset, data)); + + if (offset == 2) + { + int temp = 0; + + // According to hardware tests + if (data & 1) + temp = 3; + else + temp = 4 + ((data & 7) >> 1); + + prg8_cd(temp); + } +} + +READ8_MEMBER(nes_smb2j_device::read_l) +{ + LOG_MMC(("smb2j read_l, offset: %04x\n", offset)); + offset += 0x100; + + if (offset >= 0x1000) + return m_prg[0x10000 + (offset & 0x0fff)]; + + return m_open_bus; // open bus +} + +READ8_MEMBER(nes_smb2j_device::read_m) +{ + LOG_MMC(("smb2j read_m, offset: %04x\n", offset)); + return m_prg[0x4000 + offset]; +} + +/*------------------------------------------------- + + BTL-SMB2A + + Games: Super Mario Bros. 2 Pirate (Jpn version of SMB2) + + iNES: mapper 40 + + In MESS: Supported. + + -------------------------------------------------*/ + +void nes_smb2ja_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + if (id == TIMER_IRQ) + { + if (m_irq_enable) + { + if (m_irq_count == 0xfff) + { + m_maincpu->set_input_line(M6502_IRQ_LINE, HOLD_LINE); + m_irq_enable = 0; + m_irq_count = 0; + } + else + m_irq_count++; + } + } +} + +WRITE8_MEMBER(nes_smb2ja_device::write_h) +{ + LOG_MMC(("smb2ja write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x6000) + { + case 0x0000: + m_irq_enable = 0; + m_irq_count = 0; + break; + case 0x2000: + m_irq_enable = 1; + break; + case 0x6000: + prg8_cd(data); + break; + } +} + +READ8_MEMBER(nes_smb2ja_device::read_m) +{ + LOG_MMC(("smb2ja read_m, offset: %04x\n", offset)); + return m_prg[(0xfe * 0x2000 + (offset & 0x1fff)) & (m_prg_size - 1)]; +} + +/*------------------------------------------------- + + BTL-SMB2B + + Games: Super Mario Bros. 2 Pirate (Jpn version of SMB2) + + This was marked as Alt. Levels. is it true? + + iNES: mapper 50 + + In MESS: Partially Supported. + + -------------------------------------------------*/ + +void nes_smb2jb_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + if (id == TIMER_IRQ) + { + if (m_irq_enable) + { + if (m_irq_count == 0xfff) + { + m_maincpu->set_input_line(M6502_IRQ_LINE, HOLD_LINE); + m_irq_enable = 0; + m_irq_count = 0; + } + else + m_irq_count++; + } + } +} + +WRITE8_MEMBER(nes_smb2jb_device::write_l) +{ + UINT8 prg; + LOG_MMC(("smb2jb write_l, offset: %04x, data: %02x\n", offset, data)); + offset += 0x100; + + switch (offset & 0x1e0) + { + case 0x020: + case 0x0a0: + prg = (data & 0x08) | ((data & 0x06) >> 1) | ((data & 0x01) << 2); + prg8_cd(prg); + break; + case 0x120: + case 0x1a0: + m_irq_enable = data & 0x01; + break; + } +} + +READ8_MEMBER(nes_smb2jb_device::read_m) +{ + LOG_MMC(("smb2jb read_m, offset: %04x\n", offset)); + return m_prg[((0x0f * 0x2000) + (offset & 0x1fff)) & (m_prg_size - 1)]; +} + +/* This goes to 0x4020-0x403f & 0x40a0-0x40bf */ +WRITE8_MEMBER(nes_smb2jb_device::write_ex) +{ + UINT8 prg; + LOG_MMC(("smb2jb write_ex, offset: %04x, data: %02x\n", offset, data)); + + if ((offset < 0x20) || (offset >= 0x80 && offset < 0xa0)) + { + prg = (data & 0x08) | ((data & 0x06) >> 1) | ((data & 0x01) << 2); + prg8_cd(prg); + } +} + +/*------------------------------------------------- + + (UNL-)09-034A + + Games: Zanac FDS conversion with two PRG chips and + no CHRROM and Volleyball FDS conversion with two PRG + chips and CHRROM. + Originally dumps were marked as UNL-SMB2J pcb + + iNES: + + In MESS: Partially Supported. Need to emulate IRQ + (needed by smb2 conversion?) + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_09034a_device::write_ex) +{ + LOG_MMC(("09-034a write_ex, offset: %04x, data: %02x\n", offset, data)); + + if (offset == 7) // $4027 + m_reg = data & 1; +} + +READ8_MEMBER(nes_09034a_device::read_m) +{ + LOG_MMC(("09-034a read_m, offset: %04x\n", offset)); + // in 0x6000-0x7fff is mapped the 2nd PRG chip which starts after 32K (hence the +4) + return m_prg[((m_reg + 4) * 0x2000) + offset]; +} + +/*------------------------------------------------- + + Bootleg Board used for FDS conversion + + Games: Tobidase Daisakusen (FDS conversion) + + This PCB maps PRG in 0x6000-0x7fff + + iNES: mapper 120 + + In MESS: Partially Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_tobidase_device::write_l) +{ + LOG_MMC(("tobidase write_h, offset: %04x, data: %02x\n", offset, data)); + offset += 0x4100; + + if ((offset & 0x63c0) == 0x41c0) + m_latch = data & 0x0f; +} + +READ8_MEMBER(nes_tobidase_device::read_m) +{ + LOG_MMC(("tobidase read_m, offset: %04x\n", offset)); + if (m_latch >= 0x0c) + m_latch -= 4; + return m_prg[(m_latch * 0x2000) + (offset & 0x1fff)]; +} + +/*------------------------------------------------- + + UNL-LH32 + + Games: Monty no Doki Doki Daidassou (FDS conversion) + + This PCB maps WRAM in 0xc000-0xdfff and PRG in 0x6000-0x7fff + + iNES: + + In MESS: Supported. + +-------------------------------------------------*/ + +READ8_MEMBER(nes_lh32_device::read_m) +{ + LOG_MMC(("lh32 read_m, offset: %04x\n", offset)); + return m_prg[(m_latch * 0x2000) + (offset & 0x1fff)]; +} + +READ8_MEMBER(nes_lh32_device::read_h) +{ + LOG_MMC(("lh32 read_h, offset: %04x\n", offset)); + + if (offset >= 0x4000 && offset < 0x6000) + return m_prgram[offset & 0x1fff]; + + return hi_access_rom(offset); +} + +WRITE8_MEMBER(nes_lh32_device::write_m) +{ + LOG_MMC(("lh32 write_m, offset: %04x, data: %02x\n", offset, data)); + + if (offset == 0) // 0x6000 only? + { +// printf("write %x\n", data); + m_latch = data & 0xf; + } +} + +WRITE8_MEMBER(nes_lh32_device::write_h) +{ + LOG_MMC(("lh32 write_h, offset: %04x, data: %02x\n", offset, data)); + + if (offset >= 0x4000 && offset < 0x6000) + m_prgram[offset & 0x1fff] = data; +} + +/*------------------------------------------------- + + UNL-LH10 + + Games: Fuuun Shaolin Kyo (FDS conversion) + + This PCB maps WRAM in 0xc000-0xdfff and PRG in 0x6000-0x7fff + This is very similar to KS7037 (not sure which conversion + uses that one) + + iNES: + + In MESS: Supported. + + -------------------------------------------------*/ + +void nes_lh10_device::update_prg() +{ + prg8_89(m_reg[6]); + prg8_ab(m_reg[7]); +} + +READ8_MEMBER(nes_lh10_device::read_m) +{ + LOG_MMC(("lh10 read_m, offset: %04x\n", offset)); + return m_prg[(0x0e * 0x2000) + (offset & 0x1fff)]; +} + +READ8_MEMBER(nes_lh10_device::read_h) +{ + LOG_MMC(("lh10 read_h, offset: %04x\n", offset)); + + if (offset >= 0x4000 && offset < 0x6000) + return m_prgram[offset & 0x1fff]; + + return hi_access_rom(offset); +} + +WRITE8_MEMBER(nes_lh10_device::write_h) +{ + LOG_MMC(("lh10 write_h, offset: %04x, data: %02x\n", offset, data)); + + if (offset >= 0x4000 && offset < 0x6000) + m_prgram[offset & 0x1fff] = data; + + else + { + switch (offset & 0x6001) + { + case 0x0000: + m_latch = data & 7; + break; + case 0x0001: + m_reg[m_latch] = data; + update_prg(); + break; + } + } +} + +/*------------------------------------------------- + + UNL-LH53 + + Games: Nazo no Murasamejou (FDS conversion) + + This PCB maps WRAM (w/battery) in 0xb800-0xd7ff and + PRG in 0x6000-0x7fff + + iNES: + + In MESS: Preliminar Support only. + + -------------------------------------------------*/ + +void nes_lh53_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + if (id == TIMER_IRQ) + { + if (m_irq_enable) + { + m_irq_count++; + if (m_irq_count > 7560)//value from FCEUMM... + { + m_irq_count = 0; + m_maincpu->set_input_line(M6502_IRQ_LINE, ASSERT_LINE); + } + } + } +} + +READ8_MEMBER(nes_lh53_device::read_m) +{ + LOG_MMC(("lh53 read_m, offset: %04x\n", offset)); + return m_prg[(m_reg * 0x2000) + (offset & 0x1fff)]; +} + +READ8_MEMBER(nes_lh53_device::read_h) +{ + LOG_MMC(("lh53 read_h, offset: %04x\n", offset)); + + if (offset >= 0x3800 && offset < 0x5800) + return m_battery[offset & 0x1fff]; + + return hi_access_rom(offset); +} + +WRITE8_MEMBER(nes_lh53_device::write_h) +{ + LOG_MMC(("lh53 write_h, offset: %04x, data: %02x\n", offset, data)); + + if (offset >= 0x3800 && offset < 0x5800) + m_battery[offset & 0x1fff] = data; + + else + { + switch (offset & 0x7000) + { + case 0x6000: + m_irq_enable = BIT(data, 1); + m_irq_count = 0; + if (!m_irq_enable) + m_maincpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE); + break; + case 0x7000: + m_reg = data & 0x0f; + break; + } + } +} + +/*------------------------------------------------- + + BTL-2708 + + Games: Doki Doki Panic (FDS conversion) + + iNES: mapper 103? + + This board has a very unique setup, with 8KB of WRAM + in 0x6000-0x7fff and other 8KB of WRAM in 0xb800-0xd7ff + which can be switched in 2KB chunks (we attempt to + emulate this by intercepting reads in that area before + they get to the PRG banks...) + + In MESS: Supported. + + -------------------------------------------------*/ + +READ8_MEMBER(nes_2708_device::read_m) +{ + LOG_MMC(("btl-2708 read_m, offset: %04x\n", offset)); + if (!m_reg[1]) + return m_prgram[offset]; // lower 8K of WRAM + else + return m_prg[(m_reg[0] * 0x2000) + (offset & 0x1fff)]; +} + +WRITE8_MEMBER(nes_2708_device::write_m) +{ + LOG_MMC(("btl-2708 write_m, offset: %04x, data: %02x\n", offset, data)); +// if (!m_reg[1]) + m_prgram[offset] = data; // lower 8K of WRAM +} + +READ8_MEMBER(nes_2708_device::read_h) +{ + LOG_MMC(("btl-2708 read_h, offset: %04x\n", offset)); + + if (offset >= 0x3800 && offset < 0x5800 && !m_reg[1]) + return m_prgram[0x2000 + ((offset - 0x3800) & 0x1fff)]; // higher 8K of WRAM + + return hi_access_rom(offset); +} + +WRITE8_MEMBER(nes_2708_device::write_h) +{ + LOG_MMC(("btl-2708 write_h, offset: %04x, data: %02x\n", offset, data)); + + if (offset >= 0x3800 && offset < 0x5800/* && !m_reg[1]*/) + m_prgram[0x2000 + ((offset - 0x3800) & 0x1fff)] = data; // higher 8K of WRAM + + switch (offset & 0x7000) + { + case 0x0000: + m_reg[0] = data & 0x0f; // PRG bank in 0x6000-0x7fff + break; + case 0x6000: + set_nt_mirroring(BIT(data, 3) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + break; + case 0x7000: + m_reg[1] = BIT(data, 4); // bit4 enables the two WRAM banks + break; + } +} + +/*------------------------------------------------- + + UNL-AC08 + + Games: Green Beret (FDS conversions) + + iNES: + + This board has two PRG chips. The first (128K) is + connected to 0x6000-0x7fff and switches among the + 16x8K banks; the second (32K) is fixed in 0x8000-0xffff + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_ac08_device::write_ex) +{ + LOG_MMC(("AC-08 write_ex, offset: %04x, data: %02x\n", offset, data)); + if (offset == 5) // $4025 + set_nt_mirroring(!BIT(data, 3) ? PPU_MIRROR_VERT : PPU_MIRROR_HORZ); +} + +READ8_MEMBER(nes_ac08_device::read_m) +{ + LOG_MMC(("AC-08 read_m, offset: %04x\n", offset)); + return m_prg[(m_latch * 0x2000) + (offset & 0x1fff)]; +} + +WRITE8_MEMBER(nes_ac08_device::write_h) +{ + LOG_MMC(("AC-08 write_h, offset: %04x, data: %02x\n", offset, data)); + + if (offset == 1) + m_latch = (data >> 1) & 0x0f; + else + m_latch = data & 0x0f; // apparently there also is a Castlevania FDS conversion using same board with different banking lines +} + +/*------------------------------------------------- + + UNL-BB + + Games: Bubble Bobble and other FDS conversions with CHRROM! + + iNES: + + + In MESS: Supported. + + -------------------------------------------------*/ + +READ8_MEMBER(nes_unl_bb_device::read_m) +{ + LOG_MMC(("unl-bb read_m, offset: %04x\n", offset)); + return m_prg[(((m_reg[0] & 3 & m_prg_mask) * 0x2000) + (offset & 0x1fff))]; +} + +WRITE8_MEMBER(nes_unl_bb_device::write_h) +{ + LOG_MMC(("unl-bb write_h, offset: %04x, data: %02x\n", offset, data)); + + if (!(offset & 0x1000)) + { + m_reg[0] = data; + m_reg[1] = data; + } + else + m_reg[1] = data & 1; // Pro Wrestling uses this + + chr8(m_reg[1] & 3, m_chr_source); +} + +/*------------------------------------------------- + + BTL-MARIO1-MALEE2 (aka Genius Merio Bros) + + Games: Super Mario Bros Malee 2 + + iNES: + + This PCB has two PRG chips (32K+2K) + one CHR chip (8K) + + 2KB of WRAM + The second PRG chip (2K) is connected at 0x6000-0x6800 + while WRAM is at 0x7000-0x7800 + + In MESS: Supported. + + -------------------------------------------------*/ + +READ8_MEMBER(nes_mmalee_device::read_m) +{ + LOG_MMC(("mmalee read_m, offset: %04x\n", offset)); + + if (offset < 0x0800) + return m_prg[0x8000 + offset]; + else if (!m_prgram.empty() && offset >= 0x1000 && offset < 0x1800) // WRAM only in these 2K + return m_prgram[offset & 0x7ff]; + + return ((offset + 0x6000) & 0xff00) >> 8; +} + +WRITE8_MEMBER(nes_mmalee_device::write_m) +{ + LOG_MMC(("mmalee write_m, offset: %04x, data: %02x\n", offset, data)); + + if (!m_prgram.empty() && offset >= 0x1000 && offset < 0x1800) // WRAM only in these 2K + m_prgram[offset & 0x7ff] = data; +} + +/*------------------------------------------------- + + BTL-SHUIGUANPIPE + + Games: Shui Guan Pipe (Gimmick Pirate) + + iNES: + + In MESS: Supported, but there are glitches (PPU or IRQ?) + + -------------------------------------------------*/ + +// timer always running and checking IRQ every 114 CPU cycles? +void nes_shuiguan_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + if (id == TIMER_IRQ) + { + m_irq_count++; + m_irq_count &= 0xff; + + if (m_irq_enable && !m_irq_count) + m_maincpu->set_input_line(M6502_IRQ_LINE, HOLD_LINE); + } +} + +WRITE8_MEMBER(nes_shuiguan_device::write_h) +{ + int bank; + LOG_MMC(("shuiguan write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x7000) + { + case 0x0000: + if (offset & 0x800 && !(offset & 0x0c)) // 0x8800-0x8803 + N*0x10 + prg8_89(data); + break; + case 0x1000: + if (offset & 0x800 && !(offset & 0x0c)) // 0x9800-0x9803 + N*0x10 + { + switch (data & 0x03) + { + case 0: set_nt_mirroring(PPU_MIRROR_VERT); break; + case 1: set_nt_mirroring(PPU_MIRROR_HORZ); break; + case 2: set_nt_mirroring(PPU_MIRROR_LOW); break; + case 3: set_nt_mirroring(PPU_MIRROR_HIGH); break; + } + } + break; + case 0x2000: + if (!(offset & 0x800) && !(offset & 0x0c)) // 0xa000-0xa003 + N*0x10 + prg8_cd(data); + if (offset & 0x800 && !(offset & 0x0c)) // 0xa800-0xa803 + N*0x10 + prg8_ab(data); + break; + case 0x3000: + case 0x4000: + case 0x5000: + case 0x6000: + bank = (((offset + 0x1000) >> 11) | (offset >> 3)) & 0x07; + if (offset & 4) + m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & 0x0f) | ((data & 0x0f) << 4); + else + m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & 0xf0) | ((data & 0x0f) << 0); + chr1_x(bank, m_mmc_vrom_bank[bank], m_chr_source); + break; + case 0x7000: + switch (offset & 0x0c) + { + case 0x00: m_irq_count = (m_irq_count & 0xf0) | ((data & 0x0f) << 0); break; + case 0x04: m_irq_count = (m_irq_count & 0x0f) | ((data & 0x0f) << 4); break; + case 0x08: m_irq_enable= data; break; + case 0x0c: break; + } + break; + } +} + +READ8_MEMBER(nes_shuiguan_device::read_m) +{ + // always first bank?? + LOG_MMC(("shuiguan read_m, offset: %04x\n", offset)); + return m_prg[offset & 0x1fff]; +} diff --git a/src/devices/bus/nes/bootleg.h b/src/devices/bus/nes/bootleg.h new file mode 100644 index 00000000000..d261ba23c31 --- /dev/null +++ b/src/devices/bus/nes/bootleg.h @@ -0,0 +1,480 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __NES_BTL_H +#define __NES_BTL_H + +#include "nxrom.h" + + +// ======================> nes_ax5705_device + +class nes_ax5705_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_ax5705_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); + +private: + void set_prg(); + UINT8 m_mmc_prg_bank[2]; + UINT8 m_mmc_vrom_bank[8]; +}; + + +// ======================> nes_sc127_device + +class nes_sc127_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_sc127_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void hblank_irq(int scanline, int vblank, int blanked); + virtual void pcb_reset(); + +private: + UINT16 m_irq_count; + int m_irq_enable; +}; + + +// ======================> nes_mbaby_device + +class nes_mbaby_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_mbaby_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + virtual DECLARE_READ8_MEMBER(read_m); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); + +private: + UINT8 m_latch; + int m_irq_enable; + + static const device_timer_id TIMER_IRQ = 0; + emu_timer *irq_timer; + attotime timer_freq; +}; + + +// ======================> nes_asn_device + +class nes_asn_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_asn_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_READ8_MEMBER(read_m); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); + +private: + UINT8 m_latch; +}; + + +// ======================> nes_smb3p_device + +class nes_smb3p_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_smb3p_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); + +private: + UINT16 m_irq_count; + int m_irq_enable; + + static const device_timer_id TIMER_IRQ = 0; + emu_timer *irq_timer; +}; + + +// ======================> nes_btl_dn_device + +class nes_btl_dn_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_btl_dn_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void hblank_irq(int scanline, int vblank, int blanked); + virtual void pcb_reset(); + +private: + UINT16 m_irq_count; +}; + + +// ======================> nes_whirl2706_device + +class nes_whirl2706_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_whirl2706_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_READ8_MEMBER(read_m); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); + +private: + UINT8 m_latch; +}; + + +// ======================> nes_smb2j_device + +class nes_smb2j_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_smb2j_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + virtual DECLARE_READ8_MEMBER(read_l); + virtual DECLARE_READ8_MEMBER(read_m); + virtual DECLARE_WRITE8_MEMBER(write_ex); + virtual DECLARE_WRITE8_MEMBER(write_l); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); + +private: + UINT16 m_irq_count; + int m_irq_enable; + + static const device_timer_id TIMER_IRQ = 0; + emu_timer *irq_timer; +}; + + +// ======================> nes_smb2ja_device + +class nes_smb2ja_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_smb2ja_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + virtual DECLARE_READ8_MEMBER(read_m); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); + +private: + UINT16 m_irq_count; + int m_irq_enable; + + static const device_timer_id TIMER_IRQ = 0; + emu_timer *irq_timer; +}; + + +// ======================> nes_smb2jb_device + +class nes_smb2jb_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_smb2jb_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + virtual DECLARE_READ8_MEMBER(read_m); + virtual DECLARE_WRITE8_MEMBER(write_l); + virtual DECLARE_WRITE8_MEMBER(write_ex); + + virtual void pcb_reset(); + +private: + UINT16 m_irq_count; + int m_irq_enable; + + static const device_timer_id TIMER_IRQ = 0; + emu_timer *irq_timer; +}; + + +// ======================> nes_09034a_device + +class nes_09034a_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_09034a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_ex); + virtual DECLARE_READ8_MEMBER(read_m); + + virtual void pcb_reset(); + +private: + UINT8 m_reg; +}; + + +// ======================> nes_tobidase_device + +class nes_tobidase_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_tobidase_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_READ8_MEMBER(read_m); + virtual DECLARE_WRITE8_MEMBER(write_l); + + virtual void pcb_reset(); + +private: + UINT8 m_latch; +}; + + +// ======================> nes_lh32_device + +class nes_lh32_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_lh32_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_READ8_MEMBER(read_m); + virtual DECLARE_READ8_MEMBER(read_h); + virtual DECLARE_WRITE8_MEMBER(write_m); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); + +private: + UINT8 m_latch; +}; + + +// ======================> nes_lh10_device + +class nes_lh10_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_lh10_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_READ8_MEMBER(read_h); + virtual DECLARE_READ8_MEMBER(read_m); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); + +private: + void update_prg(); + UINT8 m_latch; + UINT8 m_reg[8]; +}; + + +// ======================> nes_lh53_device + +class nes_lh53_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_lh53_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + virtual DECLARE_READ8_MEMBER(read_m); + virtual DECLARE_READ8_MEMBER(read_h); + virtual DECLARE_WRITE8_MEMBER(write_m) {} + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); + +private: + UINT16 m_irq_count; + int m_irq_enable; + UINT8 m_reg; + + static const device_timer_id TIMER_IRQ = 0; + emu_timer *irq_timer; + attotime timer_freq; +}; + + +// ======================> nes_2708_device + +class nes_2708_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_2708_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_READ8_MEMBER(read_m); + virtual DECLARE_READ8_MEMBER(read_h); + virtual DECLARE_WRITE8_MEMBER(write_m); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); + +private: + UINT8 m_reg[2]; +}; + +// ======================> nes_ac08_device + +class nes_ac08_device : public nes_nrom_device +{ +public: + // nes_ac08_device/destruction + nes_ac08_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_READ8_MEMBER(read_m); + virtual DECLARE_WRITE8_MEMBER(write_ex); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); + +private: + UINT8 m_latch; +}; + +// ======================> nes_unl_bb_device + +class nes_unl_bb_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_unl_bb_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_READ8_MEMBER(read_m); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); + +private: + UINT8 m_reg[2]; +}; + +// ======================> nes_mmalee_device + +class nes_mmalee_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_mmalee_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_READ8_MEMBER(read_m); + virtual DECLARE_WRITE8_MEMBER(write_m); + + virtual void pcb_reset(); +}; + +// ======================> nes_shuiguan_device + +class nes_shuiguan_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_shuiguan_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + virtual DECLARE_READ8_MEMBER(read_m); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); + +private: + UINT16 m_irq_count; + int m_irq_enable; + UINT8 m_mmc_vrom_bank[8]; + + static const device_timer_id TIMER_IRQ = 0; + emu_timer *irq_timer; +}; + + + +// device type definition +extern const device_type NES_AX5705; +extern const device_type NES_SC127; +extern const device_type NES_MARIOBABY; +extern const device_type NES_ASN; +extern const device_type NES_SMB3PIRATE; +extern const device_type NES_BTL_DNINJA; +extern const device_type NES_WHIRLWIND_2706; +extern const device_type NES_SMB2J; +extern const device_type NES_SMB2JA; +extern const device_type NES_SMB2JB; +extern const device_type NES_09034A; +extern const device_type NES_TOBIDASE; +extern const device_type NES_LH32; +extern const device_type NES_LH10; +extern const device_type NES_LH53; +extern const device_type NES_2708; +extern const device_type NES_AC08; +extern const device_type NES_UNL_BB; +extern const device_type NES_MMALEE; +extern const device_type NES_SHUIGUAN; + + +#endif diff --git a/src/devices/bus/nes/camerica.c b/src/devices/bus/nes/camerica.c new file mode 100644 index 00000000000..61c41dd7867 --- /dev/null +++ b/src/devices/bus/nes/camerica.c @@ -0,0 +1,225 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + NES/Famicom cartridge emulation for Camerica/Codemasters PCBs + + + Here we emulate the following PCBs + + * Camerica BF9093, BF9097, BF909X [mapper 71, two variants] + * Camerica BF9096 Boards [mapper 232] + * Camerica Golden Five [mapper 104] + + Aladdin Deck Enhancer pass-thru cart and the corresponding minicarts + (ALGNV11 & ALGQV11 PCBs) are emulated in a separate source file. + + + TODO: + - check what causes flickering from PPU in Fire Hawk, Poogie and Big Nose (same PPU issue as Back to + Future 2&3?) + - not all the Golden Five games work. investigate! + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "camerica.h" + + +#ifdef NES_PCB_DEBUG +#define VERBOSE 1 +#else +#define VERBOSE 0 +#endif + +#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) + + +//------------------------------------------------- +// constructor +//------------------------------------------------- + +const device_type NES_BF9093 = &device_creator; +const device_type NES_BF9096 = &device_creator; +const device_type NES_GOLDEN5 = &device_creator; + + +nes_bf9093_device::nes_bf9093_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_BF9093, "NES Cart Camerica BF9093 PCB", tag, owner, clock, "nes_bf9093", __FILE__) +{ +} + +nes_bf9096_device::nes_bf9096_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_BF9096, "NES Cart Camerica BF9096 PCB", tag, owner, clock, "nes_bf9096", __FILE__) +{ +} + +nes_golden5_device::nes_golden5_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_GOLDEN5, "NES Cart Camerica Golden 5 PCB", tag, owner, clock, "nes_golden5", __FILE__) +{ +} + + + + +void nes_bf9093_device::device_start() +{ + common_start(); +} + +void nes_bf9093_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0xff); + chr8(0, m_chr_source); +} + +void nes_bf9096_device::device_start() +{ + common_start(); + save_item(NAME(m_latch)); + save_item(NAME(m_bank_base)); +} + +void nes_bf9096_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + chr8(0, m_chr_source); + + m_latch = 0x00; + m_bank_base = 0x0c; + prg16_89ab(m_bank_base | m_latch); + prg16_cdef(m_bank_base | 3); +} + +void nes_golden5_device::device_start() +{ + common_start(); + save_item(NAME(m_latch)); +} + +void nes_golden5_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + chr8(0, m_chr_source); + + m_latch = 0x00; + m_bank_base = 0x00; + prg16_89ab(m_bank_base | m_latch); + prg16_cdef(m_bank_base | 0x0f); +} + + + + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +/*------------------------------------------------- + + Camerica Boards (BF9093, BF9097, BF909X, ALGNV11) + + Games: Linus Spacehead's Cosmic Crusade, Micro Machines, + Mig-29, Stunt Kids + + To emulate NT mirroring for BF9097 board (missing in BF9093) + we use crc_hack, however Fire Hawk is broken (but without + mirroring there would be no helicopter graphics). + + iNES: mapper 71 + + In MESS: Partially Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_bf9093_device::write_h) +{ + LOG_MMC(("bf9093 write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x7000) + { + case 0x0000: + case 0x1000: + if (m_pcb_ctrl_mirror) + set_nt_mirroring(BIT(data, 4) ? PPU_MIRROR_HIGH : PPU_MIRROR_LOW); + break; + case 0x4000: + case 0x5000: + case 0x6000: + case 0x7000: + prg16_89ab(data); + break; + } +} + +/*------------------------------------------------- + + Camerica BF9096 & ALGQV11 Boards + + Games: Quattro Adventure, Quattro Arcade, Quattro Sports + + Writes to 0x8000-0xbfff set prg block to (data&0x18)>>1, + writes to 0xc000-0xffff set prg page to data&3. selected + prg are: prg16_89ab = block|page, prg_cdef = 3|page. + For more info on the hardware to bypass the NES lockout, see + Kevtris' Camerica Mappers documentation. + + iNES: mapper 232 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_bf9096_device::write_h) +{ + LOG_MMC(("bf9096 write_h, offset: %04x, data: %02x\n", offset, data)); + + if (offset < 0x4000) + { + m_bank_base = ((data >> 3) & 3) << 2; + prg16_89ab(m_bank_base | m_latch); + prg16_cdef(m_bank_base | 3); + } + else + { + m_latch = data & 3; + prg16_89ab(m_bank_base | m_latch); + } +} + +/*------------------------------------------------- + + Camerica Golden Five board + + Games: Pegasus 5 in 1 + + iNES: mapper 104 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_golden5_device::write_h) +{ + LOG_MMC(("golden5 write_h, offset: %04x, data: %02x\n", offset, data)); + + if (offset < 0x4000) + { + if (data & 0x08) + { + m_bank_base = (data & 0x07) << 4; + prg16_89ab(m_bank_base | m_latch); + prg16_cdef(m_bank_base | 0x0f); + } + + } + else + { + m_latch = data & 0x0f; + prg16_89ab(m_bank_base | m_latch); + } +} diff --git a/src/devices/bus/nes/camerica.h b/src/devices/bus/nes/camerica.h new file mode 100644 index 00000000000..7c91bda1f91 --- /dev/null +++ b/src/devices/bus/nes/camerica.h @@ -0,0 +1,72 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __NES_CAMERICA_H +#define __NES_CAMERICA_H + +#include "nxrom.h" + + +// ======================> nes_bf9093_device + +class nes_bf9093_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_bf9093_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); +}; + + +// ======================> nes_bf9096_device + +class nes_bf9096_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_bf9096_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_h); + virtual DECLARE_WRITE8_MEMBER(write_m) { write_h(space, offset, data, mem_mask); } + + virtual void pcb_reset(); + +private: + UINT8 m_bank_base, m_latch; +}; + + +// ======================> nes_golden5_device + +class nes_golden5_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_golden5_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); + +private: + UINT8 m_bank_base, m_latch; +}; + + + + + +// device type definition +extern const device_type NES_BF9093; +extern const device_type NES_BF9096; +extern const device_type NES_GOLDEN5; + +#endif diff --git a/src/devices/bus/nes/cne.c b/src/devices/bus/nes/cne.c new file mode 100644 index 00000000000..76dc0a999f2 --- /dev/null +++ b/src/devices/bus/nes/cne.c @@ -0,0 +1,220 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + NES/Famicom cartridge emulation for C&E PCBs + + + Here we emulate the following PCBs + + * C&E Decathlon [mapper 244] + * C&E Feng Shen Bang [mapper 246] + * C&E Sheng Huo Lie Zhuan [mapper 240] + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "cne.h" + + +#ifdef NES_PCB_DEBUG +#define VERBOSE 1 +#else +#define VERBOSE 0 +#endif + +#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) + + +//------------------------------------------------- +// constructor +//------------------------------------------------- + +const device_type NES_CNE_DECATHL = &device_creator; +const device_type NES_CNE_FSB = &device_creator; +const device_type NES_CNE_SHLZ = &device_creator; + + +nes_cne_decathl_device::nes_cne_decathl_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_CNE_DECATHL, "NES Cart C&E Decathlon PCB", tag, owner, clock, "nes_cne_deca", __FILE__) +{ +} + +nes_cne_fsb_device::nes_cne_fsb_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_CNE_FSB, "NES Cart C&E Feng Shen Bang PCB", tag, owner, clock, "nes_cne_fsb", __FILE__) +{ +} + +nes_cne_shlz_device::nes_cne_shlz_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_CNE_SHLZ, "NES Cart C&E Sheng Huo Lie Zhuan PCB", tag, owner, clock, "nes_cne_shlz", __FILE__) +{ +} + + + +void nes_cne_decathl_device::device_start() +{ + common_start(); +} + +void nes_cne_decathl_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); +} + +void nes_cne_fsb_device::device_start() +{ + common_start(); +} + +void nes_cne_fsb_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0xff); + chr8(0, m_chr_source); +} + +void nes_cne_shlz_device::device_start() +{ + common_start(); +} + +void nes_cne_shlz_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); +} + + + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +/*------------------------------------------------- + + C & E Bootleg Board for Decathlon + + Games: Decathlon + + Pretty simple mapper: writes to 0x8065-0x80a4 set prg32 to + offset & 3; writes to 0x80a5-0x80e4 set chr8 to offset & 7 + + iNES: mapper 244 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_cne_decathl_device::write_h) +{ + LOG_MMC(("cne_decathl_w, offset: %04x, data: %02x\n", offset, data)); + + if (offset < 0x0065) + return; + if (offset < 0x00a5) + { + prg32((offset - 0x0065) & 0x03); + return; + } + if (offset < 0x00e5) + { + chr8((offset - 0x00a5) & 0x07, CHRROM); + } +} + +/*------------------------------------------------- + + C & E Bootleg Board for Fong Shen Bang + + Games: Fong Shen Bang - Zhu Lu Zhi Zhan + + Simple mapper: writes to 0x6000-0x67ff set PRG and CHR banks. + Namely, 0x6000->0x6003 select resp. prg8_89, prg8_ab, prg8_cd + and prg8_ef. 0x6004->0x6007 select resp. crh2_0, chr2_2, + chr2_4 and chr2_6. In 0x6800-0x7fff lies WRAM. Battery backed? + + iNES: mapper 246 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_cne_fsb_device::write_m) +{ + LOG_MMC(("cne_fsb write_m, offset: %04x, data: %02x\n", offset, data)); + + if (offset < 0x0800) + { + switch (offset & 0x0007) + { + case 0x0000: + prg8_89(data); + break; + case 0x0001: + prg8_ab(data); + break; + case 0x0002: + prg8_cd(data); + break; + case 0x0003: + prg8_ef(data); + break; + case 0x0004: + chr2_0(data, CHRROM); + break; + case 0x0005: + chr2_2(data, CHRROM); + break; + case 0x0006: + chr2_4(data, CHRROM); + break; + case 0x0007: + chr2_6(data, CHRROM); + break; + } + } + else + m_battery[offset] = data; +} + +READ8_MEMBER(nes_cne_fsb_device::read_m) +{ + LOG_MMC(("cne_fsb read_m, offset: %04x\n", offset)); + + if (offset >= 0x0800) + return m_battery[offset]; + + return 0xff; +} + +/*------------------------------------------------- + + C & E Bootleg Board for Sheng Huo Lie Zhuan + + Games: Jing Ke Xin Zhuan, Sheng Huo Lie Zhuan + + Simple Mapper: writes to 0x4020-0x5fff sets prg32 to + data>>4 and chr8 to data&f. We currently do not map + writes to 0x4020-0x40ff (to do: verify if this produces + issues) + + iNES: mapper 240 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_cne_shlz_device::write_l) +{ + LOG_MMC(("cne_shlz write_l, offset: %04x, data: %02x\n", offset, data)); + + prg32(data >> 4); + chr8(data & 0x0f, CHRROM); +} diff --git a/src/devices/bus/nes/cne.h b/src/devices/bus/nes/cne.h new file mode 100644 index 00000000000..d00ef06f5cc --- /dev/null +++ b/src/devices/bus/nes/cne.h @@ -0,0 +1,66 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __NES_CNE_H +#define __NES_CNE_H + +#include "nxrom.h" + + +// ======================> nes_cne_decathl_device + +class nes_cne_decathl_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_cne_decathl_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); +}; + + +// ======================> nes_cne_fsb_device + +class nes_cne_fsb_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_cne_fsb_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_READ8_MEMBER(read_m); + virtual DECLARE_WRITE8_MEMBER(write_m); + + virtual void pcb_reset(); +}; + + +// ======================> nes_cne_shlz_device + +class nes_cne_shlz_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_cne_shlz_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_l); + + virtual void pcb_reset(); +}; + + + + + +// device type definition +extern const device_type NES_CNE_DECATHL; +extern const device_type NES_CNE_FSB; +extern const device_type NES_CNE_SHLZ; + +#endif diff --git a/src/devices/bus/nes/cony.c b/src/devices/bus/nes/cony.c new file mode 100644 index 00000000000..a64063ebc8a --- /dev/null +++ b/src/devices/bus/nes/cony.c @@ -0,0 +1,397 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + NES/Famicom cartridge emulation for Cony/Yoko PCBs + + + Here we emulate the following PCBs + + * UNL-CONY [mapper 83] + * UNL-YOKO + + TODO: fix glitches and emulate properly the variants + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "cony.h" + +#include "cpu/m6502/m6502.h" + + +#ifdef NES_PCB_DEBUG +#define VERBOSE 1 +#else +#define VERBOSE 0 +#endif + +#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) + + +//------------------------------------------------- +// constructor +//------------------------------------------------- + +const device_type NES_CONY = &device_creator; +const device_type NES_YOKO = &device_creator; + + +nes_cony_device::nes_cony_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : nes_nrom_device(mconfig, type, name, tag, owner, clock, shortname, source) +{ +} + +nes_cony_device::nes_cony_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_CONY, "NES Cart Cony PCB", tag, owner, clock, "nes_cony", __FILE__) +{ +} + +nes_yoko_device::nes_yoko_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_cony_device(mconfig, NES_YOKO, "NES Cart Yoko PCB", tag, owner, clock, "nes_yoko", __FILE__) +{ +} + + + + +void nes_cony_device::device_start() +{ + common_start(); + irq_timer = timer_alloc(TIMER_IRQ); + irq_timer->adjust(attotime::zero, 0, machine().device("maincpu")->cycles_to_attotime(1)); + + save_item(NAME(m_irq_enable)); + save_item(NAME(m_irq_count)); + + save_item(NAME(m_low_reg)); + save_item(NAME(m_reg)); + save_item(NAME(m_extra1)); + save_item(NAME(m_latch1)); + save_item(NAME(m_latch2)); +} + +void nes_cony_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg8_cd(0x1e); + prg8_ef(0x1f); + chr8(0, m_chr_source); + + m_irq_enable = 0; + m_irq_count = 0; + + m_latch1 = 0; + m_latch2 = 0; + m_extra1 = 0; + + memset(m_low_reg, 0, sizeof(m_low_reg)); + memset(m_reg, 0, sizeof(m_reg)); + m_reg[9] = 0x0f; +} + +void nes_yoko_device::device_start() +{ + common_start(); + irq_timer = timer_alloc(TIMER_IRQ); + irq_timer->adjust(attotime::zero, 0, machine().device("maincpu")->cycles_to_attotime(1)); + + save_item(NAME(m_irq_enable)); + save_item(NAME(m_irq_count)); + + save_item(NAME(m_low_reg)); + save_item(NAME(m_reg)); + save_item(NAME(m_extra1)); + save_item(NAME(m_extra2)); + save_item(NAME(m_latch1)); + save_item(NAME(m_latch2)); +} + +void nes_yoko_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg8_cd(0x1e); + prg8_ef(0x1f); + chr8(0, m_chr_source); + + m_irq_enable = 0; + m_irq_count = 0; + + m_latch1 = 0; + m_latch2 = 0; + m_extra1 = 0; + m_extra2 = 0; + + memset(m_low_reg, 0, sizeof(m_low_reg)); + memset(m_reg, 0, sizeof(m_reg)); + m_reg[9] = 0x0f; +} + + + + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +/*------------------------------------------------- + + Cony Bootleg Board + + Games: Dragon Ball Party, Fatal Fury 2, Street Blaster II + Pro, World Heroes 2 + + iNES: mapper 83 + + In MESS: Supported. + + -------------------------------------------------*/ + +void nes_cony_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + if (id == TIMER_IRQ) + { + if (m_irq_enable) + { + if (!m_irq_count) + { + m_maincpu->set_input_line(M6502_IRQ_LINE, HOLD_LINE); + m_irq_enable = 0; + m_irq_count = 0xffff; + } + else + m_irq_count--; + } + } +} + +WRITE8_MEMBER(nes_cony_device::write_l) +{ + LOG_MMC(("cony write_l, offset: %04x, data: %02x\n", offset, data)); + + if (offset >= 0x1000 && offset < 0x1103) // from 0x5100-0x51ff + m_low_reg[offset & 0x03] = data; +} + +READ8_MEMBER(nes_cony_device::read_l) +{ + LOG_MMC(("cony read_l, offset: %04x\n", offset)); + + if (offset == 0x0f00) // 0x5000 + { + // read dipswitch bit! - currently unimplemented + } + if (offset >= 0x1000 && offset < 0x1103) // from 0x5100-0x51ff + return m_low_reg[offset & 0x03]; + else + return 0x00; +} + +void nes_cony_device::set_prg() +{ + prg16_89ab(m_reg[8] & 0x3f); + prg16_cdef((m_reg[8] & 0x30) | 0x0f); +} + +void nes_cony_device::set_chr() +{ + // FIXME: here we emulate at least 3 different boards!!! + // one board switches 1k VROM banks only + // one writes to 0x8000 and then switches 2k VROM banks only + // one writes to 0x831n (n=2,3,4,5) and then switches 2k VROM banks only + // we should split them and possibly document the proper behavior of each variant + if (m_latch1 && !m_latch2) + { + chr2_0(m_reg[0], CHRROM); + chr2_2(m_reg[1], CHRROM); + chr2_4(m_reg[6], CHRROM); + chr2_6(m_reg[7], CHRROM); + } + else + { + chr1_0(m_reg[0] | ((m_reg[8] & 0x30) << 4), CHRROM); + chr1_1(m_reg[1] | ((m_reg[8] & 0x30) << 4), CHRROM); + chr1_2(m_reg[2] | ((m_reg[8] & 0x30) << 4), CHRROM); + chr1_3(m_reg[3] | ((m_reg[8] & 0x30) << 4), CHRROM); + chr1_4(m_reg[4] | ((m_reg[8] & 0x30) << 4), CHRROM); + chr1_5(m_reg[5] | ((m_reg[8] & 0x30) << 4), CHRROM); + chr1_6(m_reg[6] | ((m_reg[8] & 0x30) << 4), CHRROM); + chr1_7(m_reg[7] | ((m_reg[8] & 0x30) << 4), CHRROM); + } +} + +WRITE8_MEMBER(nes_cony_device::write_h) +{ + LOG_MMC(("cony write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset) + { + case 0x0000: + m_latch1 = 1; + case 0x3000: + case 0x30ff: + case 0x31ff: + m_reg[8] = data; + set_prg(); + set_chr(); + break; + case 0x0100: + m_extra1 = data & 0x80; + switch (data & 0x03) + { + case 0: + set_nt_mirroring(PPU_MIRROR_VERT); + break; + case 1: + set_nt_mirroring(PPU_MIRROR_HORZ); + break; + case 2: + set_nt_mirroring(PPU_MIRROR_LOW); + break; + case 3: + set_nt_mirroring(PPU_MIRROR_HIGH); + break; + } + break; + case 0x0200: + m_irq_count = (m_irq_count & 0xff00) | data; + break; + case 0x0201: + m_irq_enable = m_extra1; + m_irq_count = (data << 8) | (m_irq_count & 0xff); + break; + case 0x0300: + prg8_89(data); + break; + case 0x0301: + prg8_ab(data); + break; + case 0x0302: + prg8_cd(data); + break; + case 0x0312: + case 0x0313: + case 0x0314: + case 0x0315: + m_latch2 = 1; + case 0x0310: + case 0x0311: + case 0x0316: + case 0x0317: + m_reg[offset - 0x0310] = data; + set_chr(); + break; + case 0x0318: + m_reg[9] = data; // unused? + set_prg(); + break; + } +} + +/*------------------------------------------------- + + Yoko Bootleg Board + + Games: Mortal Kombat II, Master Figther VI' + + + Very similar to Cony board + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_yoko_device::write_l) +{ + LOG_MMC(("yoko write_l, offset: %04x, data: %02x\n", offset, data)); + + if (offset >= 0x1300) // from 0x5400 + m_low_reg[offset & 0x03] = data; +} + +READ8_MEMBER(nes_yoko_device::read_l) +{ + LOG_MMC(("yoko read_l, offset: %04x\n", offset)); + + if (offset >= 0x0f00 && offset < 0x1300) // 0x5000 + { + // read dipswitch bit! - currently unimplemented + } + if (offset >= 0x1300) // from 0x5400 + return m_low_reg[offset & 0x03]; + else + return 0x00; +} + +void nes_yoko_device::set_prg() +{ + if (m_extra1 & 0x10) + { + int base = (m_extra2 & 0x08) << 1; + prg8_89(base | (m_reg[0] & 0x0f)); + prg8_ab(base | (m_reg[1] & 0x0f)); + prg8_cd(base | (m_reg[2] & 0x0f)); + prg8_ef(base | 0x0f); + } + else if (m_extra1 & 0x08) + prg32(m_extra2 >> 1); + else + { + prg16_89ab(m_extra2); + prg16_cdef(0xff); + } +} + +void nes_yoko_device::set_chr() +{ + chr2_0(m_reg[4], CHRROM); + chr2_2(m_reg[5], CHRROM); + chr2_4(m_reg[6], CHRROM); + chr2_6(m_reg[7], CHRROM); +} + +WRITE8_MEMBER(nes_yoko_device::write_h) +{ + LOG_MMC(("yoko write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x0c17) + { + case 0x0000: + m_extra2 = data; + set_prg(); + break; + case 0x400: + m_extra1 = data; + if (data & 1) + set_nt_mirroring(PPU_MIRROR_HORZ); + else + set_nt_mirroring(PPU_MIRROR_VERT); + set_prg(); + break; + case 0x0800: + m_irq_count = (m_irq_count & 0xff00) | data; + break; + case 0x0801: + m_irq_enable = m_extra1 & 0x80; + m_irq_count = (data << 8) | (m_irq_count & 0xff); + break; + case 0x0c00: + case 0x0c01: + case 0x0c02: + m_reg[offset & 3] = data; + set_prg(); + break; + case 0x0c10: + case 0x0c11: + case 0x0c16: + case 0x0c17: + m_reg[4 + (offset & 3)] = data; + set_chr(); + break; + } +} diff --git a/src/devices/bus/nes/cony.h b/src/devices/bus/nes/cony.h new file mode 100644 index 00000000000..e97cfdee81d --- /dev/null +++ b/src/devices/bus/nes/cony.h @@ -0,0 +1,75 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __NES_CONY_H +#define __NES_CONY_H + +#include "nxrom.h" + + +// ======================> nes_cony_device + +class nes_cony_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_cony_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + nes_cony_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + virtual DECLARE_READ8_MEMBER(read_l); + virtual DECLARE_WRITE8_MEMBER(write_l); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); + +protected: + virtual void set_prg(); + virtual void set_chr(); + + UINT16 m_irq_count; + int m_irq_enable; + + static const device_timer_id TIMER_IRQ = 0; + emu_timer *irq_timer; + + UINT8 m_latch1, m_latch2; + UINT8 m_low_reg[4]; + UINT8 m_reg[10]; + UINT8 m_extra1; +}; + + +// ======================> nes_yoko_device + +class nes_yoko_device : public nes_cony_device +{ +public: + // construction/destruction + nes_yoko_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_READ8_MEMBER(read_l); + virtual DECLARE_WRITE8_MEMBER(write_l); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); + +private: + virtual void set_prg(); + virtual void set_chr(); + + UINT8 m_extra2; +}; + + + + + +// device type definition +extern const device_type NES_CONY; +extern const device_type NES_YOKO; + +#endif diff --git a/src/devices/bus/nes/datach.c b/src/devices/bus/nes/datach.c new file mode 100644 index 00000000000..1bf562976ed --- /dev/null +++ b/src/devices/bus/nes/datach.c @@ -0,0 +1,420 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + NES/Famicom cartridge emulation for Bandai Datach PCBs + + + Here we emulate the Bandai Datach Joint ROM System [mapper 157]. + The base unit features: a Bandai LZ93D50 + 24C02 EEPROM PCB + + barcode reader + subslot for PRG cart + + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "datach.h" +#include "cpu/m6502/m6502.h" + +#ifdef NES_PCB_DEBUG +#define VERBOSE 1 +#else +#define VERBOSE 0 +#endif + +#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) + +#define EEPROM_INTERNAL 0 +#define EEPROM_EXTERNAL 1 + + +#define TEST_EEPROM 0 + +//-------------------------------- +// +// Datach Cartslot implementation +// +//-------------------------------- + +//------------------------------------------------- +// sub-cart interface +//------------------------------------------------- + +datach_cart_interface::datach_cart_interface(const machine_config &mconfig, device_t &device) + : device_slot_card_interface(mconfig, device), + m_i2cmem(*this, "i2cmem"), + m_rom(NULL) +{ +} + +datach_cart_interface::~datach_cart_interface() +{ +} + +READ8_MEMBER(datach_cart_interface::read) +{ + if (offset < 0x4000) + return m_rom[(m_bank * 0x4000) + (offset & 0x3fff)]; + else + return m_rom[(0x0f * 0x4000) + (offset & 0x3fff)]; +} + +//------------------------------------------------- +// sub-cart slot device +//------------------------------------------------- + +const device_type NES_DATACH_SLOT = &device_creator; + +nes_datach_slot_device::nes_datach_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, NES_DATACH_SLOT, "NES Datach Cartridge Slot", tag, owner, clock, "nes_datach_slot", __FILE__), + device_image_interface(mconfig, *this), + device_slot_interface(mconfig, *this) +{ +} + +nes_datach_slot_device::~nes_datach_slot_device() +{ +} + + +void nes_datach_slot_device::device_start() +{ + m_cart = dynamic_cast(get_card_device()); +} + +READ8_MEMBER(nes_datach_slot_device::read) +{ + if (m_cart) + return m_cart->read(space, offset, mem_mask); + + return 0xff; +} + +bool nes_datach_slot_device::call_load() +{ + if (m_cart) + { + UINT8 *ROM = m_cart->get_cart_base(); + + if (!ROM) + return IMAGE_INIT_FAIL; + + // Existing Datach carts are all 256K, so we only load files of this size + if (software_entry() == NULL) + { + if (length() != 0x40000 && length() != 0x40010) + return IMAGE_INIT_FAIL; + + int shift = length() - 0x40000; + UINT8 temp[0x40010]; + fread(&temp, length()); + memcpy(ROM, temp + shift, 0x40000); + + // double check that iNES files are really mapper 157 + // (or 16, since some older .nes files marked Datach as mapper 16) + if (length() == 0x40010) + { + UINT8 mapper = (temp[6] & 0xf0) >> 4; + mapper |= temp[7] & 0xf0; + if (mapper != 157 && mapper != 16) + { + return IMAGE_INIT_FAIL; + } + } + } + else + { + if (get_software_region_length("rom") != 0x40000) + return IMAGE_INIT_FAIL; + + memcpy(ROM, get_software_region("rom"), 0x40000); + } + } + + return IMAGE_INIT_PASS; +} + + +bool nes_datach_slot_device::call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry) +{ + load_software_part_region(*this, swlist, swname, start_entry ); + return TRUE; +} + +void nes_datach_slot_device::get_default_card_software(std::string &result) +{ + // any way to detect the game with X24C01? + software_get_default_slot(result, "datach_rom"); +} + + +//-------------------------------- +// +// Datach Minicart implementation +// +// Two kinds of PCB exist +// * ROM only, used by most games +// * ROM + X24C01 EEPROM, used by +// Battle Rush +// +//-------------------------------- + +ROM_START( datach_rom ) + ROM_REGION(0x40000, "datachrom", ROMREGION_ERASEFF) +ROM_END + +const device_type NES_DATACH_ROM = &device_creator; +const device_type NES_DATACH_24C01 = &device_creator; + +nes_datach_rom_device::nes_datach_rom_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + datach_cart_interface( mconfig, *this ) +{ +} + +nes_datach_rom_device::nes_datach_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, NES_DATACH_ROM, "NES Datach ROM", tag, owner, clock, "nes_datach_rom", __FILE__), + datach_cart_interface( mconfig, *this ) +{ +} + +nes_datach_24c01_device::nes_datach_24c01_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_datach_rom_device(mconfig, NES_DATACH_24C01, "NES Datach + 24C01 PCB", tag, owner, clock, "nes_datach_ep1", __FILE__) +{ +} + + +void nes_datach_rom_device::device_start() +{ + m_rom = (UINT8*)memregion("datachrom")->base(); + save_item(NAME(m_bank)); +} + +void nes_datach_rom_device::device_reset() +{ + m_bank = 0; +} + +const rom_entry *nes_datach_rom_device::device_rom_region() const +{ + return ROM_NAME( datach_rom ); +} + +UINT8 *nes_datach_rom_device::get_cart_base() +{ + return m_rom; +} + + +MACHINE_CONFIG_FRAGMENT( subcart_i2c_24c01 ) + MCFG_24C01_ADD("i2cmem") +MACHINE_CONFIG_END + +machine_config_constructor nes_datach_24c01_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( subcart_i2c_24c01 ); +} + + +//--------------------------------- +// +// Datach Base Unit implementation +// +//--------------------------------- + +const device_type NES_DATACH = &device_creator; + + +nes_datach_device::nes_datach_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_lz93d50_device(mconfig, NES_DATACH, "NES Cart Bandai Datach PCB", tag, owner, clock, "nes_datach", __FILE__), + m_i2cmem(*this, "i2cmem"), + m_reader(*this, "datach"), + m_subslot(*this, "datach_slot") +{ +} + + +void nes_datach_device::device_start() +{ + common_start(); + irq_timer = timer_alloc(TIMER_IRQ); + serial_timer = timer_alloc(TIMER_SERIAL); + irq_timer->adjust(attotime::zero, 0, machine().device("maincpu")->cycles_to_attotime(1)); + serial_timer->adjust(attotime::zero, 0, machine().device("maincpu")->cycles_to_attotime(1000)); + + save_item(NAME(m_irq_enable)); + save_item(NAME(m_irq_count)); + save_item(NAME(m_datach_latch)); +} + +void nes_datach_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); + + m_irq_enable = 0; + m_irq_count = 0; + m_datach_latch = 0; + m_i2c_in_use = EEPROM_INTERNAL; +} + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +/*------------------------------------------------- + + Bandai LZ93D50 + Datach barcode reader emulation + + Games: Datach Games + + iNES: mappers 157 + + In MESS: Supported + + TODO: Datach carts should actually be handled + separately! Original carts were minicarts to be + inserted in a smaller slot of the Barcode reader + FC cart. The Barcode reader acts as a passthrough + but it has no internal ROM (it does not work if + you don't have any minicart inserted) + + TODO2: This class should be derived from the + LZ93D50 + X24C02 class, since the main board + has this EEPROM. Moreover, Datach - Battle Rush + has a second X24C01 EEPROM that we don't emulate yet... + + -------------------------------------------------*/ + + +READ8_MEMBER(nes_datach_device::read_m) +{ + LOG_MMC(("Datach read_m, offset: %04x\n", offset)); + UINT8 i2c_val = 0; +#if TEST_EEPROM + if (m_i2c_dir) + { + if (m_i2c_in_use == EEPROM_INTERNAL) + i2c_val = (m_i2cmem->read_sda() & 1) << 4; + if (m_i2c_in_use == EEPROM_EXTERNAL && m_subslot->m_cart && m_subslot->m_cart->m_i2cmem) + i2c_val = (m_subslot->m_cart->m_i2cmem->read_sda() & 1) << 4; + } +#endif + return m_datach_latch | i2c_val; +} + + +READ8_MEMBER(nes_datach_device::read_h) +{ + LOG_MMC(("Datach read_h, offset: %04x\n", offset)); + // this shall be the proper code, but it's a bit slower, so we access directly the subcart below + //return m_subslot->read(space, offset, mem_mask); + + if (m_subslot->m_cart) + return m_subslot->m_cart->read(space, offset, mem_mask); + else // this is "fake" in the sense that we fill CPU space with 0xff if no Datach cart is loaded + return hi_access_rom(offset); +} + +WRITE8_MEMBER(nes_datach_device::write_h) +{ + LOG_MMC(("Datach write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x0f) + { + case 0: case 1: case 2: case 3: + case 4: case 5: case 6: case 7: + // these don't switch CHR bank (if you try this, both Battle Rush and SD Gundam Wars will have glitches!) + // bit3 goes to SCL of the external EEPROM (and we use write=1 to enable reading from this EEPROM) + // docs from naruko don't specify the bit, our choice comes from observation of writes performed by Battle Rush +#if TEST_EEPROM + if (m_subslot->m_cart && m_subslot->m_cart->m_i2cmem) + { + if (BIT(data, 3)) + m_i2c_in_use = EEPROM_EXTERNAL; + m_subslot->m_cart->m_i2cmem->write_scl(BIT(data, 3)); + } +#endif + break; + case 0x08: + m_subslot->write_prg_bank(data & 0x0f); + break; + case 0x0d: +#if TEST_EEPROM + // bit7, select SDA direction LZ93D50P -> EEPROM or EEPROM -> LZ93D50P + m_i2c_dir = BIT(data, 7); + + // bit6 goes to SDA line, which is in common with the 2nd EEPROM, if present + m_i2cmem->write_sda(BIT(data, 6)); + if (m_subslot->m_cart && m_subslot->m_cart->m_i2cmem) + m_subslot->m_cart->m_i2cmem->write_sda(BIT(data, 6)); + + // bit5 goes to SCL of the internal EEPROM (and we use write=1 to enable reading from this EEPROM) + if (BIT(data, 5)) + m_i2c_in_use = EEPROM_INTERNAL; + m_i2cmem->write_scl(BIT(data, 5)); +#endif + break; + default: + fcg_write(space, offset & 0x0f, data, mem_mask); + break; + } +} + +//------------------------------------------------- +// BARCODE READER + CART SLOT + X24C02 +//------------------------------------------------- + +static SLOT_INTERFACE_START(datach_cart) + SLOT_INTERFACE_INTERNAL("datach_rom", NES_DATACH_ROM) + SLOT_INTERFACE_INTERNAL("datach_ep1", NES_DATACH_24C01) +SLOT_INTERFACE_END + + +MACHINE_CONFIG_FRAGMENT( bandai_datach ) + MCFG_BARCODE_READER_ADD("datach") + MCFG_DATACH_MINICART_ADD("datach_slot", datach_cart) + MCFG_24C02_ADD("i2cmem") +MACHINE_CONFIG_END + +machine_config_constructor nes_datach_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( bandai_datach ); +} + + +//------------------------------------------------- +// device_timer - handler timer events +//------------------------------------------------- + +void nes_datach_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + if (id == TIMER_IRQ) + { + if (m_irq_enable) + { + // 16bit counter, IRQ fired when the counter goes from 1 to 0 + // after firing, the counter is *not* reloaded, but next clock + // counter wraps around from 0 to 0xffff + if (!m_irq_count) + m_irq_count = 0xffff; + else + m_irq_count--; + + if (!m_irq_count) + { + m_maincpu->set_input_line(M6502_IRQ_LINE, ASSERT_LINE); + m_irq_enable = 0; + } + } + } + if (id == TIMER_SERIAL) + { + m_datach_latch = (m_reader->read_pixel() << 3); + } +} diff --git a/src/devices/bus/nes/datach.h b/src/devices/bus/nes/datach.h new file mode 100644 index 00000000000..b804c079a6f --- /dev/null +++ b/src/devices/bus/nes/datach.h @@ -0,0 +1,170 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __NES_DATACH_H +#define __NES_DATACH_H + +#include "bandai.h" +#include "machine/i2cmem.h" +#include "machine/bcreader.h" + +//-------------------------------- +// +// Datach Cartslot implementation +// +//-------------------------------- + +// ======================> datach_cart_interface + +class datach_cart_interface : public device_slot_card_interface +{ +public: + // construction/destruction + datach_cart_interface(const machine_config &mconfig, device_t &device); + virtual ~datach_cart_interface(); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read); + + UINT8 *get_cart_base() { return m_rom; } + void write_prg_bank(UINT8 bank) { m_bank = bank; } + + optional_device m_i2cmem; + +protected: + // internal state + UINT8 *m_rom; + // ROM is accessed via two 16K banks, but only the first one can be switched + UINT8 m_bank; +}; + +// ======================> nes_datach_slot_device + +class nes_datach_slot_device : public device_t, + public device_image_interface, + public device_slot_interface +{ +public: + // construction/destruction + nes_datach_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual ~nes_datach_slot_device(); + + // device-level overrides + virtual void device_start(); + virtual void device_config_complete() { update_names(); } + + // image-level overrides + virtual bool call_load(); + virtual bool call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry); + + virtual iodevice_t image_type() const { return IO_CARTSLOT; } + virtual bool is_readable() const { return 1; } + virtual bool is_writeable() const { return 0; } + virtual bool is_creatable() const { return 0; } + virtual bool must_be_loaded() const { return 0; } + virtual bool is_reset_on_load() const { return 1; } + virtual const char *image_interface() const { return "datach_cart"; } + virtual const char *file_extensions() const { return "nes,bin"; } + virtual const option_guide *create_option_guide() const { return NULL; } + + // slot interface overrides + virtual void get_default_card_software(std::string &result); + + virtual DECLARE_READ8_MEMBER(read); + void write_prg_bank(UINT8 bank) { if (m_cart) m_cart->write_prg_bank(bank); } + + datach_cart_interface* m_cart; +}; + +// device type definition +extern const device_type NES_DATACH_SLOT; + + +#define MCFG_DATACH_MINICART_ADD(_tag, _slot_intf) \ + MCFG_DEVICE_ADD(_tag, NES_DATACH_SLOT, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, NULL, false) + + +//-------------------------------- +// +// Datach Minicart implementation +// +//-------------------------------- + +// ======================> nes_datach_rom_device + +class nes_datach_rom_device : public device_t, + public datach_cart_interface +{ +public: + // construction/destruction + nes_datach_rom_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + nes_datach_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual UINT8* get_cart_base(); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); +}; + +// ======================> nes_datach_24c01_device + +class nes_datach_24c01_device : public nes_datach_rom_device +{ +public: + // construction/destruction + nes_datach_24c01_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; +}; + +// device type definition +extern const device_type NES_DATACH_ROM; +extern const device_type NES_DATACH_24C01; + + +//--------------------------------- +// +// Datach Base Unit implementation +// +//--------------------------------- + +// ======================> nes_datach_device + +class nes_datach_device : public nes_lz93d50_device +{ +public: + // construction/destruction + nes_datach_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + virtual machine_config_constructor device_mconfig_additions() const; + virtual DECLARE_READ8_MEMBER(read_m); + virtual DECLARE_READ8_MEMBER(read_h); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); + +protected: + UINT8 m_datach_latch; + required_device m_i2cmem; + required_device m_reader; + required_device m_subslot; + UINT8 m_i2c_dir; + UINT8 m_i2c_in_use; + + static const device_timer_id TIMER_SERIAL = 1; + emu_timer *serial_timer; +}; + + +// device type definition +extern const device_type NES_DATACH; + +#endif diff --git a/src/devices/bus/nes/discrete.c b/src/devices/bus/nes/discrete.c new file mode 100644 index 00000000000..e0109a84d94 --- /dev/null +++ b/src/devices/bus/nes/discrete.c @@ -0,0 +1,209 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + NES/Famicom cartridge emulation for PCBs mostly based on discrete components + + Here we emulate the following PCBs + + * PCB with IC 74x161x161x32 [mapper 70 & 152] + * PCB with IC 74x139x74 [mapper 87] + * PCB with IC 74x377 [mapper 11] + * PCB with IC 74x161x138 [mapper 38] + + TODO: + - Investigating missing inputs in Crime Busters + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "discrete.h" + + +#ifdef NES_PCB_DEBUG +#define VERBOSE 1 +#else +#define VERBOSE 0 +#endif + +#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) + + +//------------------------------------------------- +// constructor +//------------------------------------------------- + +const device_type NES_74X161X161X32 = &device_creator; +const device_type NES_74X139X74 = &device_creator; +const device_type NES_74X377 = &device_creator; +const device_type NES_74X161X138 = &device_creator; + + +nes_74x161x161x32_device::nes_74x161x161x32_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_74X161X161X32, "NES Cart Discrete Logic (74*161/161/32) PCB", tag, owner, clock, "nes_74x161", __FILE__) +{ +} + +nes_74x139x74_device::nes_74x139x74_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_74X139X74, "NES Cart Discrete Logic (74*139/74) PCB", tag, owner, clock, "nes_74x139", __FILE__) +{ +} + +nes_74x377_device::nes_74x377_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_74X377, "NES Cart Discrete Logic (74*377) PCB", tag, owner, clock, "nes_74x377", __FILE__) +{ +} + +nes_74x161x138_device::nes_74x161x138_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_74X161X138, "NES Cart Discrete Logic (74*161/138) PCB", tag, owner, clock, "nes_bitcorp_dis", __FILE__) +{ +} + + + + +void nes_74x161x161x32_device::device_start() +{ + common_start(); +} + +void nes_74x161x161x32_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); +} + +void nes_74x139x74_device::device_start() +{ + common_start(); +} + +void nes_74x139x74_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); +} + +void nes_74x377_device::device_start() +{ + common_start(); +} + +void nes_74x377_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); +} + +void nes_74x161x138_device::device_start() +{ + common_start(); +} + +void nes_74x161x138_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); +} + + + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +/*------------------------------------------------- + + Discrete Logic board IC 74x161x161x32 + + There are two variants (one with hardwired mirroring, the + other with a mirroring control), making necessary two distinct + mappers & pcb_id + + iNES: mappers 70 & 152 + + -------------------------------------------------*/ + +// there are two 'variants' depending on hardwired or mapper ctrl mirroring +WRITE8_MEMBER(nes_74x161x161x32_device::write_h) +{ + LOG_MMC(("74x161x161x32 write_h, offset: %04x, data: %02x\n", offset, data)); + + // this pcb is subject to bus conflict + data = account_bus_conflict(offset, data); + + if (m_pcb_ctrl_mirror) + set_nt_mirroring(BIT(data, 7) ? PPU_MIRROR_HIGH : PPU_MIRROR_LOW); + chr8(data, CHRROM); + prg16_89ab(data >> 4); +} + +/*------------------------------------------------- + + Discrete Logic board IC 74x139x74 by Konami & Jaleco + + iNES: mapper 87 + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_74x139x74_device::write_m) +{ + LOG_MMC(("74x139x74 write_m, offset: %04x, data: %02x\n", offset, data)); + + chr8(((data & 0x02) >> 1) | ((data & 0x01) << 1), CHRROM); +} + +/*------------------------------------------------- + + Discrete Logic board IC 74x377 by Color Dreams / Nina-007 emulation + + Games: many Color Dreams and Wisdom Tree titles + + iNES: mapper 11 + + In MESS: Supported + + Note: bit2 & bit3 are actually related to CIC lockout + defeating, and real Color Dreams titles use only + bit0 & bit1 for PRG switching. Our usage allows for support + of extended PRG games (e.g. homebrew) + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_74x377_device::write_h) +{ + LOG_MMC(("74x377 write_h, offset: %04x, data: %02x\n", offset, data)); + + // this pcb is subject to bus conflict, but not the prototype of Secret Scout, which actually breaks in case of conflict... + data = account_bus_conflict(offset, data); + + chr8(data >> 4, m_chr_source); + prg32(data & 0x0f); +} + +/*------------------------------------------------- + + Discrete Logic board IC 74x161x138 + + Games: Crime Busters + + iNES: mapper 38 + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_74x161x138_device::write_m) +{ + LOG_MMC(("74x161x138 write_m, offset: %04x, data: %02x\n", offset, data)); + + chr8(data >> 2, CHRROM); + prg32(data); +} diff --git a/src/devices/bus/nes/discrete.h b/src/devices/bus/nes/discrete.h new file mode 100644 index 00000000000..1fb615c38f2 --- /dev/null +++ b/src/devices/bus/nes/discrete.h @@ -0,0 +1,80 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __NES_DISCRETE_H +#define __NES_DISCRETE_H + +#include "nxrom.h" + + +// ======================> nes_74x161x161x32_device + +class nes_74x161x161x32_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_74x161x161x32_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); +}; + + +// ======================> nes_74x139x74_device + +class nes_74x139x74_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_74x139x74_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_m); + + virtual void pcb_reset(); +}; + + +// ======================> nes_74x377_device + +class nes_74x377_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_74x377_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); +}; + + +// ======================> nes_74x161x138_device + +class nes_74x161x138_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_74x161x138_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_m); + + virtual void pcb_reset(); +}; + + + +// device type definition +extern const device_type NES_74X161X161X32; +extern const device_type NES_74X139X74; +extern const device_type NES_74X377; +extern const device_type NES_74X161X138; + +#endif diff --git a/src/devices/bus/nes/disksys.c b/src/devices/bus/nes/disksys.c new file mode 100644 index 00000000000..45cb275e9de --- /dev/null +++ b/src/devices/bus/nes/disksys.c @@ -0,0 +1,431 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + NES/Famicom cartridge emulation for Disk System expansion + + + Here we emulate the RAM expansion + Disk Drive which form the + Famicom Disk System. + + Based on info from NESDev wiki ( http://wiki.nesdev.com/w/index.php/Family_Computer_Disk_System ) + + TODO: + - convert floppy drive + fds format to modern code! + - add sound bits + - stop IRQ from using HOLD_LINE + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "disksys.h" +#include "cpu/m6502/m6502.h" +#include "imagedev/flopdrv.h" +#include "formats/nes_dsk.h" + +#ifdef NES_PCB_DEBUG + #define VERBOSE 1 +#else + #define VERBOSE 0 +#endif + +#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) + + +//----------------------------------------------- +// +// Disk drive implementation +// +//----------------------------------------------- + +static const floppy_interface nes_floppy_interface = +{ + FLOPPY_STANDARD_5_25_DSHD, + LEGACY_FLOPPY_OPTIONS_NAME(nes_only), + "floppy_5_25" +}; + +static MACHINE_CONFIG_FRAGMENT( nes_disksys ) + MCFG_LEGACY_FLOPPY_DRIVE_ADD(FLOPPY_0, nes_floppy_interface) +MACHINE_CONFIG_END + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor nes_disksys_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( nes_disksys ); +} + + + +ROM_START( disksys ) + ROM_REGION(0x2000, "drive", 0) + ROM_SYSTEM_BIOS( 0, "2c33a-01a", "Famicom Disk System Bios") + ROMX_LOAD( "rp2c33a-01a.bin", 0x0000, 0x2000, CRC(5e607dcf) SHA1(57fe1bdee955bb48d357e463ccbf129496930b62), ROM_BIOS(1)) // newer, Nintendo logo has no shadow + ROM_SYSTEM_BIOS( 1, "2c33-01", "Famicom Disk System Bios, older") + ROMX_LOAD( "rp2c33-01.bin", 0x0000, 0x2000, CRC(1c7ae5d5) SHA1(af5af53f66982e749643fdf8b2acbb7d4d3ed229), ROM_BIOS(2)) // older, Nintendo logo has shadow +ROM_END + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *nes_disksys_device::device_rom_region() const +{ + return ROM_NAME( disksys ); +} + + +void nes_disksys_device::load_proc(device_image_interface &image) +{ + nes_disksys_device *disk_sys = static_cast(image.device().owner()); + disk_sys->load_disk(image); +} + +void nes_disksys_device::unload_proc(device_image_interface &image) +{ + nes_disksys_device *disk_sys = static_cast(image.device().owner()); + disk_sys->unload_disk(image); +} + + +//------------------------------------------------ +// +// RAM expansion cart implementation +// +//------------------------------------------------ + +const device_type NES_DISKSYS = &device_creator; + + +nes_disksys_device::nes_disksys_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_DISKSYS, "FC RAM Expansion + Disk System PCB", tag, owner, clock, "fc_disksys", __FILE__), + m_fds_data(NULL), + m_disk(*this, FLOPPY_0), + m_fds_sides(0) +{ +} + + +void nes_disksys_device::device_start() +{ + common_start(); + + m_2c33_rom = (UINT8*)memregion("drive")->base(); + + m_disk->floppy_install_load_proc(nes_disksys_device::load_proc); + m_disk->floppy_install_unload_proc(nes_disksys_device::unload_proc); + + irq_timer = timer_alloc(TIMER_IRQ); + irq_timer->adjust(attotime::zero, 0, machine().device("maincpu")->cycles_to_attotime(1)); + + save_item(NAME(m_fds_motor_on)); + save_item(NAME(m_fds_door_closed)); + save_item(NAME(m_fds_current_side)); + save_item(NAME(m_fds_head_position)); + save_item(NAME(m_fds_status0)); + save_item(NAME(m_read_mode)); + save_item(NAME(m_drive_ready)); + save_item(NAME(m_irq_enable)); + save_item(NAME(m_irq_transfer)); + save_item(NAME(m_irq_count)); + save_item(NAME(m_irq_count_latch)); + + save_item(NAME(m_fds_last_side)); + save_item(NAME(m_fds_count)); +} + +void nes_disksys_device::pcb_reset() +{ + // read accesses in 0x6000-0xffff are always handled by + // cutom code below, so no need to setup the prg... + chr8(0, CHRRAM); + set_nt_mirroring(PPU_MIRROR_VERT); + + m_fds_motor_on = 0; + m_fds_door_closed = 0; + m_fds_current_side = 1; + m_fds_head_position = 0; + m_fds_status0 = 0; + m_read_mode = 0; + m_drive_ready = 0; + m_irq_count = 0; + m_irq_count_latch = 0; + m_irq_enable = 0; + m_irq_transfer = 0; + + m_fds_count = 0; + m_fds_last_side = 0; +} + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +/*------------------------------------------------- + + RAM is in 0x6000-0xdfff (32K) + ROM is in 0xe000-0xffff (8K) + + registers + disk drive are accessed in + 0x4020-0x403f (read_ex/write_ex below) + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_disksys_device::write_h) +{ + LOG_MMC(("Famicom Disk System write_h, offset %04x, data: %02x\n", offset, data)); + + if (offset < 0x6000) + m_prgram[offset + 0x2000] = data; +} + +READ8_MEMBER(nes_disksys_device::read_h) +{ + LOG_MMC(("Famicom Disk System read_h, offset: %04x\n", offset)); + + if (offset < 0x6000) + return m_prgram[offset + 0x2000]; + else + return m_2c33_rom[offset & 0x1fff]; +} + +WRITE8_MEMBER(nes_disksys_device::write_m) +{ + LOG_MMC(("Famicom Disk System write_m, offset: %04x, data: %02x\n", offset, data)); + m_prgram[offset] = data; +} + +READ8_MEMBER(nes_disksys_device::read_m) +{ + LOG_MMC(("Famicom Disk System read_m, offset: %04x\n", offset)); + return m_prgram[offset]; +} + +void nes_disksys_device::hblank_irq(int scanline, int vblank, int blanked) +{ + if (m_irq_transfer) + m_maincpu->set_input_line(M6502_IRQ_LINE, HOLD_LINE); +} + +WRITE8_MEMBER(nes_disksys_device::write_ex) +{ + LOG_MMC(("Famicom Disk System write_ex, offset: %04x, data: %02x\n", offset, data)); + + if (offset >= 0x20 && offset < 0x60) + { + // wavetable + } + + switch (offset) + { + case 0x00: + m_irq_count_latch = (m_irq_count_latch & 0xff00) | data; + break; + case 0x01: + m_irq_count_latch = (m_irq_count_latch & 0x00ff) | (data << 8); + break; + case 0x02: + m_irq_count = m_irq_count_latch; + m_irq_enable = BIT(data, 1); + break; + case 0x03: + // bit0 - Enable disk I/O registers + // bit1 - Enable sound I/O registers + break; + case 0x04: + // write data out to disk + // TEST! + if (m_fds_data && m_fds_current_side && !m_read_mode) + m_fds_data[(m_fds_current_side - 1) * 65500 + m_fds_head_position++] = data; + break; + case 0x05: + // $4025 - FDS Control + // bit0 - Drive Motor Control (0: Stop motor; 1: Turn on motor) + // bit1 - Transfer Reset (Set 1 to reset transfer timing to the initial state) + // bit2 - Read / Write mode (0: write; 1: read) + // bit3 - Mirroring (0: horizontal; 1: vertical) + // bit4 - CRC control (set during CRC calculation of transfer) + // bit5 - Always set to '1' + // bit6 - Read/Write Start (Set to 1 when the drive becomes ready for read/write) + // bit7 - Interrupt Transfer (0: Transfer without using IRQ; 1: Enable IRQ when + // the drive becomes ready) + m_fds_motor_on = BIT(data, 0); + + if (BIT(data, 1)) + m_fds_head_position = 0; + + if (!(data & 0x40) && m_drive_ready && m_fds_head_position > 2) + m_fds_head_position -= 2; // ??? is this some sort of compensation?? + + m_read_mode = BIT(data, 2); + set_nt_mirroring(BIT(data, 3) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + m_drive_ready = data & 0x40; + m_irq_transfer = BIT(data, 7); + break; + case 0x06: + // external connector + break; + case 0x60: // $4080 - Volume envelope - read through $4090 + case 0x62: // $4082 - Frequency low + case 0x63: // $4083 - Frequency high + case 0x64: // $4084 - Mod envelope - read through $4092 + case 0x65: // $4085 - Mod counter + case 0x66: // $4086 - Mod frequency low + case 0x67: // $4087 - Mod frequency high + case 0x68: // $4088 - Mod table write + case 0x69: // $4089 - Wave write / master volume + case 0x6a: // $408a - Envelope speed + break; + } +} + +READ8_MEMBER(nes_disksys_device::read_ex) +{ + LOG_MMC(("Famicom Disk System read_ex, offset: %04x\n", offset)); + UINT8 ret = 0x00; + + if (offset >= 0x20 && offset < 0x60) + { + // wavetable + } + + switch (offset) + { + case 0x10: + // $4030 - disk status 0 + // bit0 - Timer Interrupt (1: an IRQ occurred) + // bit1 - Byte transfer flag (Set to 1 every time 8 bits have been transfered between + // the RAM adaptor & disk drive through $4024/$4031; Reset to 0 when $4024, + // $4031, or $4030 has been serviced) + // bit4 - CRC control (0: CRC passed; 1: CRC error) + // bit6 - End of Head (1 when disk head is on the most inner track) + // bit7 - Disk Data Read/Write Enable (1 when disk is readable/writable) + ret = m_fds_status0 | 0x80; + // clear the disk IRQ detect flag + m_fds_status0 &= ~0x01; + break; + case 0x11: + // $4031 - data latch + // don't read data if disk is unloaded + if (!m_fds_data) + ret = 0; + else if (m_fds_current_side && m_read_mode) + { + ret = m_fds_data[(m_fds_current_side - 1) * 65500 + m_fds_head_position++]; + if (m_fds_head_position == 65500) + { + printf("end of disk reached!\n"); + m_fds_status0 |= 0x40; + m_fds_head_position -= 2; + } + } + else + ret = 0; + break; + case 0x12: + // $4032 - disk status 1: + // bit0 - Disk flag (0: Disk inserted; 1: Disk not inserted) + // bit1 - Ready flag (0: Disk ready; 1: Disk not ready) + // bit2 - Protect flag (0: Not write protected; 1: Write protected or disk ejected) + if (!m_fds_data) + ret = 1; + else if (m_fds_last_side != m_fds_current_side) + { + // If we've switched disks, report "no disk" for a few reads + ret = 1; + m_fds_count++; + if (m_fds_count == 50) + { + m_fds_last_side = m_fds_current_side; + m_fds_count = 0; + } + } + else + ret = (m_fds_current_side == 0) ? 1 : 0; // 0 if a disk is inserted + break; + case 0x13: + // $4033 - external connector (bits 0-6) + battery status (bit 7) + ret = 0x80; + break; + case 0x70: // $4090 - Volume gain - write through $4080 + case 0x72: // $4092 - Mod gain - read through $4084 + default: + ret = 0x00; + break; + } + + return ret; +} + +//------------------------------------------------- +// device_timer - handler timer events +//------------------------------------------------- + +void nes_disksys_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + if (id == TIMER_IRQ) + { + if (m_irq_enable && m_irq_count) + { + m_irq_count--; + if (!m_irq_count) + { + m_maincpu->set_input_line(M6502_IRQ_LINE, HOLD_LINE); + m_irq_enable = 0; + m_fds_status0 |= 0x01; + m_irq_count_latch = 0; // used in Kaettekita Mario Bros + } + } + } +} + + +// Hacky helper to allow user to switch disk side with a simple key + +void nes_disksys_device::disk_flip_side() +{ + m_fds_current_side++; + if (m_fds_current_side > m_fds_sides) + m_fds_current_side = 0; + + if (m_fds_current_side == 0) + popmessage("No disk inserted."); + else + popmessage("Disk set to side %d", m_fds_current_side); +} + + + +// Disk Loading / Unloading + +void nes_disksys_device::load_disk(device_image_interface &image) +{ + int header = 0; + m_fds_sides = 0; + + if (image.length() % 65500) + header = 0x10; + + m_fds_sides = (image.length() - header) / 65500; + + if (!m_fds_data) + m_fds_data = auto_alloc_array(machine(), UINT8, m_fds_sides * 65500); + + // if there is an header, skip it + image.fseek(header, SEEK_SET); + image.fread(m_fds_data, 65500 * m_fds_sides); + return; +} + +void nes_disksys_device::unload_disk(device_image_interface &image) +{ + /* TODO: should write out changes here as well */ + m_fds_sides = 0; +} diff --git a/src/devices/bus/nes/disksys.h b/src/devices/bus/nes/disksys.h new file mode 100644 index 00000000000..dcb2bd75c0c --- /dev/null +++ b/src/devices/bus/nes/disksys.h @@ -0,0 +1,71 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __NES_DISKSYS_H +#define __NES_DISKSYS_H + +#include "nxrom.h" +#include "imagedev/flopdrv.h" + + +// ======================> nes_disksys_device + +class nes_disksys_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_disksys_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual machine_config_constructor device_mconfig_additions() const; + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + virtual const rom_entry *device_rom_region() const; + + virtual DECLARE_READ8_MEMBER(read_ex); + virtual DECLARE_READ8_MEMBER(read_m); + virtual DECLARE_READ8_MEMBER(read_h); + virtual DECLARE_WRITE8_MEMBER(write_ex); + virtual DECLARE_WRITE8_MEMBER(write_m); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void disk_flip_side(); + + virtual void hblank_irq(int scanline, int vblank, int blanked); + virtual void pcb_reset(); + + static void load_proc(device_image_interface &image); + static void unload_proc(device_image_interface &image); + +private: + UINT8 *m_2c33_rom; + UINT8 *m_fds_data; // here, we store a copy of the disk + required_device m_disk; + + static const device_timer_id TIMER_IRQ = 0; + emu_timer *irq_timer; + + void load_disk(device_image_interface &image); + void unload_disk(device_image_interface &image); + + UINT16 m_irq_count, m_irq_count_latch; + int m_irq_enable, m_irq_transfer; + + UINT8 m_fds_motor_on; + UINT8 m_fds_door_closed; + UINT8 m_fds_current_side; + UINT32 m_fds_head_position; + UINT8 m_fds_status0; + UINT8 m_read_mode; + UINT8 m_drive_ready; + + UINT8 m_fds_sides; + int m_fds_last_side; + int m_fds_count; +}; + + + +// device type definition +extern const device_type NES_DISKSYS; + +#endif diff --git a/src/devices/bus/nes/event.c b/src/devices/bus/nes/event.c new file mode 100644 index 00000000000..4059b107a24 --- /dev/null +++ b/src/devices/bus/nes/event.c @@ -0,0 +1,239 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + NES/Famicom cartridge emulation for Nintendo NES-EVENT PCB + + + Here we emulate the following PCBs + + * Nintendo NES-EVENT [mapper 105] + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "event.h" + +#include "cpu/m6502/m6502.h" + + +#ifdef NES_PCB_DEBUG +#define VERBOSE 1 +#else +#define VERBOSE 0 +#endif + +#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) + + +//------------------------------------------------- +// constructor +//------------------------------------------------- + +const device_type NES_EVENT = &device_creator; + + +nes_event_device::nes_event_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_sxrom_device(mconfig, NES_EVENT, "NES Cart Event PCB", tag, owner, clock, "nes_event", __FILE__), + m_dsw(*this, "DIPSW") +{ +} + + +void nes_event_device::device_start() +{ + common_start(); + event_timer = timer_alloc(TIMER_EVENT); + event_timer->adjust(attotime::never); + timer_freq = machine().device("maincpu")->cycles_to_attotime(1); + + save_item(NAME(m_latch)); + save_item(NAME(m_count)); + save_item(NAME(m_reg)); + save_item(NAME(m_reg_write_enable)); + save_item(NAME(m_nwc_init)); + + save_item(NAME(m_timer_count)); + save_item(NAME(m_timer_on)); + save_item(NAME(m_timer_enabled)); +} + +void nes_event_device::pcb_reset() +{ + m_latch = 0; + m_count = 0; + m_reg[0] = 0x0f; + m_reg[1] = m_reg[2] = m_reg[3] = 0; + m_reg_write_enable = 1; + m_nwc_init = 2; + + set_nt_mirroring(PPU_MIRROR_HORZ); + chr8(0, CHRRAM); + prg32(0); + m_timer_count = 0; + m_timer_enabled = 0; + m_timer_on = 0; +} + + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +/*------------------------------------------------- + + Event PCB + + Games: Nintento World Championships + + MMC-1 variant with repurposed register at $a000 and a + lot of discrete components + + iNES: mapper 105 + + In MESS: Supported. + + -------------------------------------------------*/ + +void nes_event_device::set_chr() +{ + // no CHR switching, there are only 8KB VRAM from the cart +} + +void nes_event_device::set_prg() +{ +// printf("enter with %d and reg1 0x%x - reg3 0x%x\n", m_nwc_init, m_reg[1], m_reg[3]); + // reg[1] is different from base MMC-1! + // bit 0 is ignored, bit1/bit3 are used for PRG switch, bit4 is used for the timer + UINT8 temp = (m_reg[1] >> 1) & 7; + + // initially PRG is fixed, until bit4 of reg1 is set to 1 and then to 0 + switch (m_nwc_init) + { + case 2: + if (m_reg[1] & 0x10) m_nwc_init--; + return; + case 1: + if (~m_reg[1] & 0x10) m_nwc_init--; + return; + } + + if (temp < 4) + prg32(temp); + else + { + // else PRG works similarly to base MMC-1, but only acts on the higher 128KB (2nd PRG ROM) + switch (m_reg[0] & 0x0c) + { + case 0x00: + case 0x04: + prg32(0x04 | ((m_reg[3] >> 1) & 0x03)); + break; + case 0x08: + prg16_89ab(0x08 | 0x00); + prg16_cdef(0x08 | (m_reg[3] & 0x07)); + break; + case 0x0c: + prg16_89ab(0x08 | (m_reg[3] & 0x07)); + prg16_cdef(0x08 | 0x07); + break; + } + } + + // after the init procedure above, bit4 of m_reg[1] is used to init IRQ, by setting and then clearing the bit + // however, there are (bankswitch related?) writes with bit4 cleared before the one 'enabling' the timer, so + // we need the additional m_timer_enabled variable, to avoid starting the timer before its time... + if (m_reg[1] & 0x10) + { + m_timer_enabled = 1; + m_maincpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE); + } + else + { + if (!m_timer_on && m_timer_enabled) + { + m_timer_count = 0x20000000 | ((m_dsw->read() & 0x0f) << 25); + event_timer->adjust(attotime::zero, 0, timer_freq); + m_timer_on = 1; + } + } +} + +void nes_event_device::update_regs(int reg) +{ + switch (reg) + { + case 0: + switch (m_reg[0] & 0x03) + { + case 0: set_nt_mirroring(PPU_MIRROR_LOW); break; + case 1: set_nt_mirroring(PPU_MIRROR_HIGH); break; + case 2: set_nt_mirroring(PPU_MIRROR_VERT); break; + case 3: set_nt_mirroring(PPU_MIRROR_HORZ); break; + } + set_prg(); + break; + case 1: + set_prg(); + break; + case 2: + set_chr(); + break; + case 3: + set_prg(); + break; + } +} + +//------------------------------------------------- +// Dipswicth +//------------------------------------------------- + +static INPUT_PORTS_START( nwc_dsw ) + PORT_START("DIPSW") + PORT_DIPNAME( 0x0f, 0x04, "Timer" ) PORT_DIPLOCATION("SW:!1,!2,!3,!4") + PORT_DIPSETTING( 0x00, "5:00.4" ) + PORT_DIPSETTING( 0x01, "5:19.2" ) + PORT_DIPSETTING( 0x02, "5:38.0" ) + PORT_DIPSETTING( 0x03, "5:56.7" ) + PORT_DIPSETTING( 0x04, "6:15.5" ) + PORT_DIPSETTING( 0x05, "6:34.3" ) + PORT_DIPSETTING( 0x06, "6:53.1" ) + PORT_DIPSETTING( 0x07, "7:11.9" ) + PORT_DIPSETTING( 0x08, "7:30.6" ) + PORT_DIPSETTING( 0x09, "7:49.4" ) + PORT_DIPSETTING( 0x0a, "8:08.2" ) + PORT_DIPSETTING( 0x0b, "8:27.0" ) + PORT_DIPSETTING( 0x0c, "8:45.8" ) + PORT_DIPSETTING( 0x0d, "9:04.5" ) + PORT_DIPSETTING( 0x0e, "9:23.3" ) + PORT_DIPSETTING( 0x0f, "9:42.1" ) +INPUT_PORTS_END + + + +ioport_constructor nes_event_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( nwc_dsw ); +} + + +//------------------------------------------------- +// device_timer - handler timer events +//------------------------------------------------- + +void nes_event_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + if (id == TIMER_EVENT) + { + m_timer_count--; + if (!m_timer_count) + { + m_maincpu->set_input_line(M6502_IRQ_LINE, HOLD_LINE); + event_timer->reset(); + } + } +} diff --git a/src/devices/bus/nes/event.h b/src/devices/bus/nes/event.h new file mode 100644 index 00000000000..31076cec074 --- /dev/null +++ b/src/devices/bus/nes/event.h @@ -0,0 +1,44 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __NES_EVENT_H +#define __NES_EVENT_H + +#include "mmc1.h" + + +// ======================> nes_event_device + +class nes_event_device : public nes_sxrom_device +{ +public: + // construction/destruction + nes_event_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + virtual ioport_constructor device_input_ports() const; + virtual void update_regs(int reg); + + required_ioport m_dsw; + + virtual void pcb_reset(); + +protected: + virtual void set_prg(); + virtual void set_chr(); + int m_nwc_init; + + static const device_timer_id TIMER_EVENT = 0; + emu_timer *event_timer; + attotime timer_freq; + + UINT32 m_timer_count; + int m_timer_on, m_timer_enabled; +}; + + +// device type definition +extern const device_type NES_EVENT; + +#endif diff --git a/src/devices/bus/nes/ggenie.c b/src/devices/bus/nes/ggenie.c new file mode 100644 index 00000000000..f9320a5fbee --- /dev/null +++ b/src/devices/bus/nes/ggenie.c @@ -0,0 +1,274 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + NES/Famicom cartridge emulation for Galoob Game Genie PCBs + + + Here we emulate the following PCBs + + * Galoob Game Genie, passthrough hacking cart + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "ggenie.h" +#include "includes/nes.h" + + +#ifdef NES_PCB_DEBUG +#define VERBOSE 1 +#else +#define VERBOSE 0 +#endif + +#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) + + +//------------------------------------------------- +// constructor +//------------------------------------------------- + +const device_type NES_GGENIE = &device_creator; + + +nes_ggenie_device::nes_ggenie_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_GGENIE, "NES Cart Game Genie PCB", tag, owner, clock, "nes_ggenie", __FILE__), + m_ggslot(*this, "gg_slot") +{ +} + + +void nes_ggenie_device::device_start() +{ + common_start(); + save_item(NAME(m_gg_bypass)); +} + +void nes_ggenie_device::pcb_start(running_machine &machine, UINT8 *ciram_ptr, bool cart_mounted) +{ + device_nes_cart_interface::pcb_start(machine, ciram_ptr, cart_mounted); + if (m_ggslot->m_cart) + m_ggslot->pcb_start(m_ciram); +} + +void nes_ggenie_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); + + set_nt_mirroring(PPU_MIRROR_LOW); + m_gg_bypass = 0; + + if (m_ggslot->m_cart) + m_ggslot->m_cart->pcb_reset(); +} + + + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +/*------------------------------------------------- + + Game Genie board emulation + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_ggenie_device::write_h) +{ +// LOG_MMC(("axrom write_h, offset: %04x, data: %02x\n", offset, data)); + if (!m_gg_bypass) + { + // From blargg: Codes are written to $8001-800C, starting at $800C and going down to $8001. + // Next, two values are written to $8000. The first specify the kind of codes which have + // been inserted, the second write to $8000 is always zero (all 8 bits). + // This probably disables the boot ROM (the code is executing from RAM at this point). + // Once done, the code jumps to ($FFFC) to begin the game. + // All 12 bytes from $8001-800C are written regardless of how many codes are inserted. + // The value written to $8000 is the only clue as to what codes are actually valid and which + // ones have compare values. + if (offset) + { + int code; + offset -= 1; + code = (offset & 0xc) >> 2; + if (code == 3) + return; // how did we end up here? the GG is not expected to write to $800d-800f! + + switch (offset & 3) + { + case 0: + m_gg_addr[code] |= (data & 0x7f) << 8; + break; + case 1: + m_gg_addr[code] = data; + break; + case 2: + m_gg_comp[code] = data; + break; + case 3: + m_gg_repl[code] = data; + break; + } + return; + } + + if (offset == 0 && data == 0) + { + m_gg_bypass = 1; + m_maincpu->set_pc(0xfffc); + } + else + { + // bit 0 is always set (GG enable?) + m_gg_is_comp[0] = BIT(data, 1); + m_gg_is_comp[1] = BIT(data, 2); + m_gg_is_comp[2] = BIT(data, 3); + m_gg_disable[0] = BIT(data, 4); + m_gg_disable[1] = BIT(data, 5); + m_gg_disable[2] = BIT(data, 6); + // bit 7 is always clear + logerror("Game Genie Summary:\n"); + for (int i = 0; i < 3; i++) + { + logerror("Code %d: %s\n", i, m_gg_disable[i] ? "No" : "Yes"); + if (!m_gg_disable[i]) + { + logerror("\tAddr: 0x%X\n", m_gg_addr[i]); + logerror("\tValue: 0x%X\n", m_gg_repl[i]); + if (m_gg_is_comp[i]) + logerror("\t if equals: 0x%X\n", m_gg_comp[i]); + + } + } + } + } + else + m_ggslot->write_h(space, offset, data, mem_mask); +} + +WRITE8_MEMBER(nes_ggenie_device::write_m) +{ + if (m_gg_bypass && m_ggslot) + m_ggslot->write_m(space, offset, data, mem_mask); +} + +WRITE8_MEMBER(nes_ggenie_device::write_l) +{ + if (m_gg_bypass && m_ggslot) + m_ggslot->write_l(space, offset, data, mem_mask); +} + +READ8_MEMBER(nes_ggenie_device::read_h) +{ + if (m_gg_bypass && m_ggslot->m_cart) + { + UINT8 rom_value = m_ggslot->m_cart->hi_access_rom(offset); + + // check if GG code has to act on this address + for (int i = 0; i < 3; i++) + { + if (!m_gg_disable[i] && offset == m_gg_addr[i]) + { + if (!m_gg_is_comp[i] || (m_gg_is_comp[i] && m_gg_comp[i] == rom_value)) + return m_gg_repl[i]; + } + } + + return rom_value; + } + return hi_access_rom(offset); +} + +READ8_MEMBER(nes_ggenie_device::read_m) +{ + if (m_gg_bypass && m_ggslot->m_cart) + return m_ggslot->m_cart->read_m(space, offset, mem_mask); + + return 0xff; +} + +READ8_MEMBER(nes_ggenie_device::read_l) +{ + if (m_gg_bypass && m_ggslot->m_cart) + return m_ggslot->m_cart->read_l(space, offset, mem_mask); + + return 0xff; +} + +WRITE8_MEMBER(nes_ggenie_device::chr_w) +{ + int bank = offset >> 10; + + if (m_gg_bypass && m_ggslot->m_cart) + { + m_ggslot->m_cart->chr_w(space, offset, data, mem_mask); + return; + } + + if (m_chr_src[bank] == CHRRAM) + m_chr_access[bank][offset & 0x3ff] = data; +} + +READ8_MEMBER(nes_ggenie_device::chr_r) +{ + int bank = offset >> 10; + + if (m_gg_bypass && m_ggslot->m_cart) + return m_ggslot->m_cart->chr_r(space, offset, mem_mask); + + return m_chr_access[bank][offset & 0x3ff]; +} + + +WRITE8_MEMBER(nes_ggenie_device::nt_w) +{ + int page = ((offset & 0xc00) >> 10); + + if (m_gg_bypass && m_ggslot->m_cart) + { + m_ggslot->m_cart->nt_w(space, offset, data, mem_mask); + return; + } + + if (!m_nt_writable[page]) + return; + + m_nt_access[page][offset & 0x3ff] = data; +} + +READ8_MEMBER(nes_ggenie_device::nt_r) +{ + int page = ((offset & 0xc00) >> 10); + + if (m_gg_bypass && m_ggslot->m_cart) + return m_ggslot->m_cart->nt_r(space, offset, mem_mask); + + return m_nt_access[page][offset & 0x3ff]; +} + +//------------------------------------------------- +// MACHINE_CONFIG_FRAGMENT( sub_slot ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( sub_slot ) + MCFG_NES_CARTRIDGE_ADD("gg_slot", nes_cart, NULL) + MCFG_NES_CARTRIDGE_NOT_MANDATORY +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor nes_ggenie_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( sub_slot ); +} diff --git a/src/devices/bus/nes/ggenie.h b/src/devices/bus/nes/ggenie.h new file mode 100644 index 00000000000..e4620e59e09 --- /dev/null +++ b/src/devices/bus/nes/ggenie.h @@ -0,0 +1,58 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __NES_GGENIE_H +#define __NES_GGENIE_H + +#include "nxrom.h" + + +// ======================> nes_ggenie_device + +class nes_ggenie_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_ggenie_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_READ8_MEMBER(read_l); + virtual DECLARE_READ8_MEMBER(read_m); + virtual DECLARE_READ8_MEMBER(read_h); + virtual DECLARE_WRITE8_MEMBER(write_l); + virtual DECLARE_WRITE8_MEMBER(write_m); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual DECLARE_READ8_MEMBER(chr_r); + virtual DECLARE_WRITE8_MEMBER(chr_w); + virtual DECLARE_READ8_MEMBER(nt_r); + virtual DECLARE_WRITE8_MEMBER(nt_w); + + void hblank_irq(int scanline, int vblank, int blanked) { if (m_gg_bypass && m_ggslot->m_cart) m_ggslot->m_cart->hblank_irq(scanline, vblank, blanked); } + void scanline_irq(int scanline, int vblank, int blanked) { if (m_gg_bypass && m_ggslot->m_cart) m_ggslot->m_cart->scanline_irq(scanline, vblank, blanked); } + void ppu_latch(offs_t offset) { if (m_gg_bypass && m_ggslot->m_cart) m_ggslot->m_cart->ppu_latch(offset); } + + virtual machine_config_constructor device_mconfig_additions() const; + + virtual void pcb_reset(); + virtual void pcb_start(running_machine &machine, UINT8 *ciram_ptr, bool cart_mounted); + +private: + // emulate the Game Genie! + required_device m_ggslot; + + int m_gg_bypass; + // GG codes + UINT16 m_gg_addr[3]; + UINT8 m_gg_repl[3]; + UINT8 m_gg_comp[3]; + int m_gg_disable[3]; + int m_gg_is_comp[3]; +}; + + + +// device type definition +extern const device_type NES_GGENIE; + +#endif diff --git a/src/devices/bus/nes/henggedianzi.c b/src/devices/bus/nes/henggedianzi.c new file mode 100644 index 00000000000..5cda60e6938 --- /dev/null +++ b/src/devices/bus/nes/henggedianzi.c @@ -0,0 +1,278 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + NES/Famicom cartridge emulation for Henggedianzi PCBs + + + Here we emulate the following PCBs + + * Henggedianzi Super Rich [mapper 177] + * Henggedianzi Xing He Zhan Shi [mapper 179] + * Henggedianzi Shen Hua Jian Yun III + + + TODO: + - investigate relation with some TXC & Waixing boards + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "henggedianzi.h" + +#include "cpu/m6502/m6502.h" + + +#ifdef NES_PCB_DEBUG +#define VERBOSE 1 +#else +#define VERBOSE 0 +#endif + +#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) + + +//------------------------------------------------- +// constructor +//------------------------------------------------- + +const device_type NES_HENGG_SRICH = &device_creator; +const device_type NES_HENGG_XHZS = &device_creator; +const device_type NES_HENGG_SHJY3 = &device_creator; + + +nes_hengg_srich_device::nes_hengg_srich_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_HENGG_SRICH, "NES Cart Henggedianzi Super Rich PCB", tag, owner, clock, "nes_hengg_srich", __FILE__) +{ +} + +nes_hengg_xhzs_device::nes_hengg_xhzs_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_HENGG_XHZS, "NES Cart Henggedianzi Xing He Zhan Shi PCB", tag, owner, clock, "nes_hengg_xhzs", __FILE__) +{ +} + +nes_hengg_shjy3_device::nes_hengg_shjy3_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_HENGG_SHJY3, "NES Cart Henggedianzi Shen Hua Jian Yun III PCB", tag, owner, clock, "nes_hengg_shjy3", __FILE__) +{ +} + + + + +void nes_hengg_srich_device::device_start() +{ + common_start(); +} + +void nes_hengg_srich_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); +} + +void nes_hengg_xhzs_device::device_start() +{ + common_start(); +} + +void nes_hengg_xhzs_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); +} + +void nes_hengg_shjy3_device::device_start() +{ + common_start(); + save_item(NAME(m_irq_count)); + save_item(NAME(m_irq_count_latch)); + save_item(NAME(m_irq_enable)); + save_item(NAME(m_chr_mode)); + save_item(NAME(m_mmc_prg_bank)); + save_item(NAME(m_mmc_vrom_bank)); + save_item(NAME(m_mmc_extra_bank)); +} + +void nes_hengg_shjy3_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); + + m_irq_enable = 0; + m_irq_count = m_irq_count_latch = 0; + + m_chr_mode = 0; + memset(m_mmc_prg_bank, 0, sizeof(m_mmc_prg_bank)); + memset(m_mmc_vrom_bank, 0, sizeof(m_mmc_vrom_bank)); + memset(m_mmc_extra_bank, 0, sizeof(m_mmc_extra_bank)); +} + + + + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +/*------------------------------------------------- + + Bootleg Board by Henggedianzi + + Games: Mei Guo Fu Hao, Shang Gu Shen Jian , Wang Zi Fu + Chou Ji + + Writes to 0x8000-0xffff set prg32. Moreover, data&0x20 sets + NT mirroring. + + iNES: mapper 177 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_hengg_srich_device::write_h) +{ + LOG_MMC(("hengg_srich write_h, offset: %04x, data: %02x\n", offset, data)); + + prg32(data); + set_nt_mirroring(BIT(data, 5) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); +} + +/*------------------------------------------------- + + Bootleg Board by Henggedianzi + + Games: Xing He Zhan Shi + + Writes to 0x5000-0x5fff set prg32 banks, writes to 0x8000- + 0xffff set NT mirroring + + Note: NEStopia marks this as Xjzb, but Xing Ji Zheng Ba + (Phantasy Star?) runs on the other Henggedianzi board + Is there an alt dump of Xing Ji Zheng Ba using this? + + iNES: mapper 179 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_hengg_xhzs_device::write_l) +{ + LOG_MMC(("hengg_xhzs write_l, offset: %04x, data: %02x\n", offset, data)); + offset += 0x4100; + + if (offset & 0x5000) + prg32(data >> 1); +} + +WRITE8_MEMBER(nes_hengg_xhzs_device::write_h) +{ + LOG_MMC(("hengg_xhzs write_h, offset: %04x, data: %02x\n", offset, data)); + + set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); +} + +/*------------------------------------------------- + + UNL-SHJY3 + + -------------------------------------------------*/ + +/* I think the IRQ should only get fired if enough CPU cycles have passed, but we don't implement (yet) this part */ +void nes_hengg_shjy3_device::hblank_irq(int scanline, int vblank, int blanked) +{ + if (m_irq_enable & 0x02) + { + if (m_irq_count == 0xff) + { + m_irq_count = m_irq_count_latch; + m_irq_enable = m_irq_enable | ((m_irq_enable & 0x01) << 1); + m_maincpu->set_input_line(M6502_IRQ_LINE, HOLD_LINE); + } + else + m_irq_count++; + } +} + +void nes_hengg_shjy3_device::update_banks() +{ + prg8_89(m_mmc_prg_bank[0]); + prg8_ab(m_mmc_prg_bank[1]); + + for (int i = 0; i < 8; i++) + { + UINT8 chr_bank = m_mmc_vrom_bank[i] | (m_mmc_extra_bank[i] << 4); + if (m_mmc_vrom_bank[i] == 0xc8) + { + m_chr_mode = 0; + continue; + } + else if (m_mmc_vrom_bank[i] == 0x88) + { + m_chr_mode = 1; + continue; + } + if ((m_mmc_vrom_bank[i] == 4 || m_mmc_vrom_bank[i] == 5) && !m_chr_mode) + chr1_x(i, chr_bank & 1, CHRRAM); + else + chr1_x(i, chr_bank, CHRROM); + } +} + +WRITE8_MEMBER(nes_hengg_shjy3_device::write_h) +{ + LOG_MMC(("shjy3 write_h, offset: %04x, data: %02x\n", offset, data)); + + if (offset >= 0x3000 && offset <= 0x600c) + { + UINT8 shift = offset & 4; + UINT8 mmc_helper = ((offset & 8) | (offset >> 8)) >> 3; + mmc_helper += 2; + mmc_helper &= 7; + + m_mmc_vrom_bank[mmc_helper] = (m_mmc_vrom_bank[mmc_helper] & (0xf0 >> shift)) | ((data & 0x0f) << shift); + if (shift) + m_mmc_extra_bank[mmc_helper] = data >> 4; + } + else + { + switch (offset) + { + case 0x0010: + m_mmc_prg_bank[0] = data; + break; + case 0x2010: + m_mmc_prg_bank[1] = data; + break; + case 0x1400: + switch (data & 0x03) + { + case 0: set_nt_mirroring(PPU_MIRROR_VERT); break; + case 1: set_nt_mirroring(PPU_MIRROR_HORZ); break; + case 2: set_nt_mirroring(PPU_MIRROR_LOW); break; + case 3: set_nt_mirroring(PPU_MIRROR_HIGH); break; + } + break; + case 0x7000: + m_irq_count_latch = (m_irq_count_latch & 0xf0) | (data & 0x0f); + break; + case 0x7004: + m_irq_count_latch = (m_irq_count_latch & 0x0f) | ((data & 0x0f) << 4); + break; + case 0x7008: + m_irq_enable = data & 0x03; + if (m_irq_enable & 0x02) + m_irq_count = m_irq_count_latch; + break; + } + } + update_banks(); +} diff --git a/src/devices/bus/nes/henggedianzi.h b/src/devices/bus/nes/henggedianzi.h new file mode 100644 index 00000000000..a229ddbda4a --- /dev/null +++ b/src/devices/bus/nes/henggedianzi.h @@ -0,0 +1,78 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __NES_HENGGEDIANZI_H +#define __NES_HENGGEDIANZI_H + +#include "nxrom.h" + + +// ======================> nes_hengg_srich_device + +class nes_hengg_srich_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_hengg_srich_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); +}; + + +// ======================> nes_hengg_xhzs_device + +class nes_hengg_xhzs_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_hengg_xhzs_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_l); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); +}; + + +// ======================> nes_hengg_shjy3_device + +class nes_hengg_shjy3_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_hengg_shjy3_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void hblank_irq(int scanline, int vblank, int blanked); + virtual void pcb_reset(); + +private: + void update_banks(); + + UINT16 m_irq_count, m_irq_count_latch; + int m_irq_enable; + + int m_chr_mode; + UINT8 m_mmc_prg_bank[2]; + UINT8 m_mmc_vrom_bank[8]; + UINT8 m_mmc_extra_bank[8]; +}; + + + + + +// device type definition +extern const device_type NES_HENGG_SRICH; +extern const device_type NES_HENGG_XHZS; +extern const device_type NES_HENGG_SHJY3; + +#endif diff --git a/src/devices/bus/nes/hes.c b/src/devices/bus/nes/hes.c new file mode 100644 index 00000000000..ddfda0590d8 --- /dev/null +++ b/src/devices/bus/nes/hes.c @@ -0,0 +1,87 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + NES/Famicom cartridge emulation for HES PCBs + + + Here we emulate the HES PCBs (both the one with hardwired mirroring and the one with mapper-controlled + mirroring used by HES 6 in 1) [mapper 113] + + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "hes.h" + + +#ifdef NES_PCB_DEBUG +#define VERBOSE 1 +#else +#define VERBOSE 0 +#endif + +#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) + + +//------------------------------------------------- +// constructor +//------------------------------------------------- + +const device_type NES_HES = &device_creator; + + +nes_hes_device::nes_hes_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_HES, "NES Cart HES PCB", tag, owner, clock, "nes_hes", __FILE__) +{ +} + + +void nes_hes_device::device_start() +{ + common_start(); +} + +void nes_hes_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); +} + + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +/*------------------------------------------------- + + Bootleg Board by HES (also used by others) + + Games: AV Hanafuda Club, AV Soccer, Papillon, Sidewinder, + Total Funpack + + Actually, two variant: one for HES 6-in-1 with mirroring control + and one for AV Soccer and others with hardwired mirroring + + iNES: mapper 113 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_hes_device::write_l) +{ + LOG_MMC(("hes write_l, offset: %04x, data: %02x\n", offset, data)); + + if (!(offset & 0x100)) + { + prg32((data & 0x38) >> 3); + chr8((data & 0x07) | ((data & 0x40) >> 3), CHRROM); + if (m_pcb_ctrl_mirror) + set_nt_mirroring(BIT(data, 7) ? PPU_MIRROR_VERT : PPU_MIRROR_HORZ); + } +} diff --git a/src/devices/bus/nes/hes.h b/src/devices/bus/nes/hes.h new file mode 100644 index 00000000000..6a895a8ec1e --- /dev/null +++ b/src/devices/bus/nes/hes.h @@ -0,0 +1,28 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __NES_HES_H +#define __NES_HES_H + +#include "nxrom.h" + + +// ======================> nes_hes_device + +class nes_hes_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_hes_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_l); + + virtual void pcb_reset(); +}; + + +// device type definition +extern const device_type NES_HES; + +#endif diff --git a/src/devices/bus/nes/hosenkan.c b/src/devices/bus/nes/hosenkan.c new file mode 100644 index 00000000000..fae439ac903 --- /dev/null +++ b/src/devices/bus/nes/hosenkan.c @@ -0,0 +1,155 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + NES/Famicom cartridge emulation for Hosenkan PCBs + + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "hosenkan.h" + +#include "cpu/m6502/m6502.h" +#include "video/ppu2c0x.h" // this has to be included so that IRQ functions can access PPU_BOTTOM_VISIBLE_SCANLINE + + +#ifdef NES_PCB_DEBUG +#define VERBOSE 1 +#else +#define VERBOSE 0 +#endif + +#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) + + +//------------------------------------------------- +// constructor +//------------------------------------------------- + +const device_type NES_HOSENKAN = &device_creator; + + +nes_hosenkan_device::nes_hosenkan_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_HOSENKAN, "NES Cart HOSENKAN PCB", tag, owner, clock, "nes_hosenkan", __FILE__) +{ +} + + + + +void nes_hosenkan_device::device_start() +{ + common_start(); + save_item(NAME(m_irq_enable)); + save_item(NAME(m_irq_count)); + save_item(NAME(m_irq_count_latch)); + save_item(NAME(m_irq_clear)); + save_item(NAME(m_latch)); +} + +void nes_hosenkan_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32((m_prg_chunks - 1) >> 1); + chr8(0, m_chr_source); + + m_latch = 0; + m_irq_enable = 0; + m_irq_count = m_irq_count_latch = 0; + m_irq_clear = 0; +} + + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +/*------------------------------------------------- + + Bootleg Board by Hosenkan + + Games: Pocahontas, Super Donkey Kong + + iNES: mapper 182 + + In MESS: Supported. + + -------------------------------------------------*/ + +// same as MMC3! +void nes_hosenkan_device::hblank_irq( int scanline, int vblank, int blanked ) +{ + if (scanline < PPU_BOTTOM_VISIBLE_SCANLINE) + { + int prior_count = m_irq_count; + if ((m_irq_count == 0) || m_irq_clear) + m_irq_count = m_irq_count_latch; + else + m_irq_count--; + + if (m_irq_enable && !blanked && (m_irq_count == 0) && (prior_count || m_irq_clear)) + { + LOG_MMC(("irq fired, scanline: %d (MAME %d, beam pos: %d)\n", scanline, + machine().first_screen()->vpos(), machine().first_screen()->hpos())); + m_maincpu->set_input_line(M6502_IRQ_LINE, HOLD_LINE); + } + } + m_irq_clear = 0; +} + +WRITE8_MEMBER(nes_hosenkan_device::write_h) +{ + LOG_MMC(("hosenkan write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x7003) + { + case 0x0001: + set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + break; + case 0x2000: + m_latch = data; + break; + case 0x4000: + switch (m_latch) + { + case 0: + chr2_0(data >> 1, CHRROM); + break; + case 1: + chr1_5(data, CHRROM); + break; + case 2: + chr2_2(data >> 1, CHRROM); + break; + case 3: + chr1_7(data, CHRROM); + break; + case 4: + prg8_89(data); + break; + case 5: + prg8_ab(data); + break; + case 6: + chr1_4(data, CHRROM); + break; + case 7: + chr1_6(data, CHRROM); + break; + } + break; + case 0x6003: + if (data) + { + m_irq_count = data; + m_irq_enable = 1; + } + else + m_irq_enable = 0; + break; + } +} diff --git a/src/devices/bus/nes/hosenkan.h b/src/devices/bus/nes/hosenkan.h new file mode 100644 index 00000000000..f775a513adb --- /dev/null +++ b/src/devices/bus/nes/hosenkan.h @@ -0,0 +1,39 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __NES_HOSENKAN_H +#define __NES_HOSENKAN_H + +#include "nxrom.h" + + +// ======================> nes_hosenkan_device + +class nes_hosenkan_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_hosenkan_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_h); + + + virtual void hblank_irq(int scanline, int vblank, int blanked); + virtual void pcb_reset(); + +private: + UINT16 m_irq_count, m_irq_count_latch; + UINT8 m_irq_clear; + int m_irq_enable; + + UINT8 m_latch; +}; + + + +// device type definition +extern const device_type NES_HOSENKAN; + + +#endif diff --git a/src/devices/bus/nes/irem.c b/src/devices/bus/nes/irem.c new file mode 100644 index 00000000000..43f5bab1d7d --- /dev/null +++ b/src/devices/bus/nes/irem.c @@ -0,0 +1,352 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + NES/Famicom cartridge emulation for IREM PCBs + + + Here we emulate the following PCBs + + * IREM LROG017 [mapper 77] + * IREM Holy Diver [mapper 78] + * IREM TAM-S1 [mapper 97] + * IREM G101 [mapper 32] + * IREM H3001 [mapper 65] + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "irem.h" + +#include "cpu/m6502/m6502.h" + +#ifdef NES_PCB_DEBUG +#define VERBOSE 1 +#else +#define VERBOSE 0 +#endif + +#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) + + +//------------------------------------------------- +// constructor +//------------------------------------------------- + +const device_type NES_LROG017 = &device_creator; +const device_type NES_HOLYDIVR = &device_creator; +const device_type NES_TAM_S1 = &device_creator; +const device_type NES_G101 = &device_creator; +const device_type NES_H3001 = &device_creator; + + +nes_lrog017_device::nes_lrog017_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_LROG017, "NES Cart Irem Discrete 74*161/161/21/138 PCB", tag, owner, clock, "nes_lrog017", __FILE__) +{ +} + +nes_holydivr_device::nes_holydivr_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_HOLYDIVR, "NES Cart Irem Holy Diver PCB", tag, owner, clock, "nes_holydivr", __FILE__) +{ +} + +nes_tam_s1_device::nes_tam_s1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_TAM_S1, "NES Cart Irem TAM-S1 PCB", tag, owner, clock, "nes_tam_s1", __FILE__) +{ +} + +nes_g101_device::nes_g101_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_G101, "NES Cart Irem G-101 PCB", tag, owner, clock, "nes_g101", __FILE__) +{ +} + +nes_h3001_device::nes_h3001_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_H3001, "NES Cart Irem H-3001 PCB", tag, owner, clock, "nes_h3001", __FILE__) +{ +} + + + + +void nes_lrog017_device::device_start() +{ + common_start(); +} + +void nes_lrog017_device::pcb_reset() +{ + prg32(0); + chr2_0(0, CHRROM); + chr2_2(0, CHRRAM); + chr2_4(1, CHRRAM); + chr2_6(2, CHRRAM); +} + +void nes_holydivr_device::device_start() +{ + common_start(); +} + +void nes_holydivr_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); +} + +void nes_tam_s1_device::device_start() +{ + common_start(); +} + +void nes_tam_s1_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(m_prg_chunks - 1); + prg16_cdef(0); + chr8(0, m_chr_source); +} + +void nes_g101_device::device_start() +{ + common_start(); + save_item(NAME(m_latch)); +} + +void nes_g101_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); + + m_latch = 0; +} + +void nes_h3001_device::device_start() +{ + common_start(); + irq_timer = timer_alloc(TIMER_IRQ); + irq_timer->adjust(attotime::zero, 0, machine().device("maincpu")->cycles_to_attotime(1)); + + save_item(NAME(m_irq_enable)); + save_item(NAME(m_irq_count)); + save_item(NAME(m_irq_count_latch)); +} + +void nes_h3001_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); + + m_irq_enable = 0; + m_irq_count = 0; + m_irq_count_latch = 0; +} + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +/*------------------------------------------------- + + Irem LROG017 - Discrete board emulation (74*161/161/21/138) + + Games: Napoleon Senki + + iNES: mapper 77 + + This board should use 2KB of CHRRAM as NTRAM, instead + of using directly 4-screen mirroring, but for the + moment we cheat in this way... + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_lrog017_device::write_h) +{ + LOG_MMC(("lrog017 write_h, offset: %04x, data: %02x\n", offset, data)); + + // this pcb is subject to bus conflict + data = account_bus_conflict(offset, data); + + prg32(data); + chr2_0((data >> 4), CHRROM); +} + +/*------------------------------------------------- + + Irem Holy Diver board emulation + + iNES: mapper 78 (shared with JF-16) + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_holydivr_device::write_h) +{ + LOG_MMC(("holy diver write_h, offset: %04x, data: %02x\n", offset, data)); + + // this pcb is subject to bus conflict + data = account_bus_conflict(offset, data); + + set_nt_mirroring(BIT(data, 3) ? PPU_MIRROR_VERT : PPU_MIRROR_HORZ); + chr8(data >> 4, CHRROM); + prg16_89ab(data); +} + +/*------------------------------------------------- + + Irem TAM-S1 board emulation + + Games: Kaiketsu Yanchamaru + + iNES: mapper 97 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_tam_s1_device::write_h) +{ + LOG_MMC(("tam s1 write_h, offset: %04x, data: %02x\n", offset, data)); + + if (offset < 0x4000) + { + // this pcb is subject to bus conflict + data = account_bus_conflict(offset, data); + + set_nt_mirroring(BIT(data, 7) ? PPU_MIRROR_VERT : PPU_MIRROR_HORZ); + prg16_cdef(data); + } +} + +/*------------------------------------------------- + + Irem G-101 board emulation + + Major League uses hardwired mirroring + + iNES: mapper 32 + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_g101_device::write_h) +{ + LOG_MMC(("g101 write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x7000) + { + case 0x0000: + if (m_latch) + { + prg8_89(0xfe); + prg8_cd(data & 0x1f); + } + else + { + prg8_89(data & 0x1f); + prg8_cd(0xfe); + } + break; + case 0x1000: + m_latch = BIT(data, 1); + if (m_pcb_ctrl_mirror) + set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + break; + case 0x2000: + prg8_ab(data & 0x1f); + break; + case 0x3000: + chr1_x(offset & 0x07, data & 0x7f, CHRROM); + break; + } +} + +/*------------------------------------------------- + + Irem H-3001 board emulation + + Games: Daiku no Gen San 2 - Akage no Dan no Gyakushuu, + Kaiketsu Yanchamaru 3, Spartan X 2 + + iNES: mapper 65 + + In MESS: Supported. + + -------------------------------------------------*/ + + +void nes_h3001_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + if (id == TIMER_IRQ) + { + if (m_irq_enable) + { + // 16bit counter, IRQ fired when the counter reaches 0 + // after firing, the counter is *not* reloaded and does not wrap + if (m_irq_count > 0) + m_irq_count--; + + if (!m_irq_count) + { + m_maincpu->set_input_line(M6502_IRQ_LINE, ASSERT_LINE); + m_irq_enable = 0; + } + } + } +} + +WRITE8_MEMBER(nes_h3001_device::write_h) +{ + LOG_MMC(("h3001 write_h, offset %04x, data: %02x\n", offset, data)); + + switch (offset & 0x7fff) + { + case 0x0000: + prg8_89(data); + break; + + case 0x1001: + set_nt_mirroring(BIT(data, 7) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + break; + + case 0x1003: + m_irq_enable = data & 0x80; + m_maincpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE); + break; + + case 0x1004: + m_irq_count = m_irq_count_latch; + m_maincpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE); + break; + + case 0x1005: + m_irq_count_latch = (m_irq_count_latch & 0x00ff) | (data << 8); + break; + + case 0x1006: + m_irq_count_latch = (m_irq_count_latch & 0xff00) | data; + break; + + case 0x2000: + prg8_ab(data); + break; + + case 0x3000: case 0x3001: case 0x3002: case 0x3003: + case 0x3004: case 0x3005: case 0x3006: case 0x3007: + chr1_x(offset & 0x07, data, CHRROM); + break; + + case 0x4000: + prg8_cd(data); + break; + + default: + break; + } +} diff --git a/src/devices/bus/nes/irem.h b/src/devices/bus/nes/irem.h new file mode 100644 index 00000000000..5c7924b4e7d --- /dev/null +++ b/src/devices/bus/nes/irem.h @@ -0,0 +1,108 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __NES_IREM_H +#define __NES_IREM_H + +#include "nxrom.h" + + +// ======================> nes_lrog017_device + +class nes_lrog017_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_lrog017_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); +}; + + +// ======================> nes_holydivr_device + +class nes_holydivr_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_holydivr_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); +}; + + +// ======================> nes_tam_s1_device + +class nes_tam_s1_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_tam_s1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); +}; + + +// ======================> nes_g101_device + +class nes_g101_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_g101_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); + +protected: + UINT8 m_latch; +}; + + +// ======================> nes_h3001_device + +class nes_h3001_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_h3001_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); + +protected: + UINT16 m_irq_count, m_irq_count_latch; + int m_irq_enable; + + static const device_timer_id TIMER_IRQ = 0; + emu_timer *irq_timer; +}; + + + +// device type definition +extern const device_type NES_LROG017; +extern const device_type NES_HOLYDIVR; +extern const device_type NES_TAM_S1; +extern const device_type NES_G101; +extern const device_type NES_H3001; + +#endif diff --git a/src/devices/bus/nes/jaleco.c b/src/devices/bus/nes/jaleco.c new file mode 100644 index 00000000000..28df5250118 --- /dev/null +++ b/src/devices/bus/nes/jaleco.c @@ -0,0 +1,886 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + NES/Famicom cartridge emulation for Jaleco PCBs + + + Here we emulate the following PCBs + + * Jaleco JF-11 [mapper 140] + * Jaleco JF-13 [mapper 86] + * Jaleco JF-16 [mapper 78] + * Jaleco JF-17 [mapper 72] + its variant with samples + * Jaleco JF-19 [mapper 92] + its variant with samples + * Jaleco SS88006 [mapper 18] + its variant(s) with samples + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "jaleco.h" + +#include "cpu/m6502/m6502.h" +#include "sound/samples.h" + +#ifdef NES_PCB_DEBUG +#define VERBOSE 1 +#else +#define VERBOSE 0 +#endif + +#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) + + +//------------------------------------------------- +// constructor +//------------------------------------------------- + +const device_type NES_JF11 = &device_creator; +const device_type NES_JF16 = &device_creator; +const device_type NES_JF17 = &device_creator; +const device_type NES_JF19 = &device_creator; +const device_type NES_SS88006 = &device_creator; +const device_type NES_JF13 = &device_creator; +const device_type NES_JF17_ADPCM = &device_creator; +const device_type NES_JF19_ADPCM = &device_creator; +const device_type NES_JF23 = &device_creator; +const device_type NES_JF24 = &device_creator; +const device_type NES_JF29 = &device_creator; +const device_type NES_JF33 = &device_creator; + + +nes_jf11_device::nes_jf11_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_JF11, "NES Cart Jaleco JF-11 PCB", tag, owner, clock, "nes_jf11", __FILE__) +{ +} + +nes_jf13_device::nes_jf13_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_JF13, "NES Cart Jaleco JF-13 PCB", tag, owner, clock, "nes_jf13", __FILE__), + m_samples(*this, "samples") +{ +} + +nes_jf16_device::nes_jf16_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_JF16, "NES Cart Jaleco JF-16 PCB", tag, owner, clock, "nes_jf16", __FILE__) +{ +} + +nes_jf17_device::nes_jf17_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : nes_nrom_device(mconfig, type, name, tag, owner, clock, shortname, source) +{ +} + +nes_jf17_device::nes_jf17_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_JF17, "NES Cart Jaleco JF-17 PCB", tag, owner, clock, "nes_jf17", __FILE__) +{ +} + +nes_jf17_adpcm_device::nes_jf17_adpcm_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_jf17_device(mconfig, NES_JF17_ADPCM, "NES Cart Jaleco JF-17 + ADPCM (Moero!! Pro Tennis) PCB", tag, owner, clock, "nes_jf17_pcm", __FILE__), + m_samples(*this, "samples") +{ +} + +nes_jf19_device::nes_jf19_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : nes_nrom_device(mconfig, type, name, tag, owner, clock, shortname, source) +{ +} + +nes_jf19_device::nes_jf19_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_JF19, "NES Cart Jaleco JF-19 (Moero!! Pro Soccer) PCB", tag, owner, clock, "nes_jf19", __FILE__) +{ +} + +nes_jf19_adpcm_device::nes_jf19_adpcm_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_jf19_device(mconfig, NES_JF19_ADPCM, "NES Cart Jaleco JF-19 + ADPCM (Moero!! Pro Yakyuu 88) PCB", tag, owner, clock, "nes_jf19_pcm", __FILE__), + m_samples(*this, "samples") +{ +} + +nes_ss88006_device::nes_ss88006_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : nes_nrom_device(mconfig, type, name, tag, owner, clock, shortname, source) +{ +} + +nes_ss88006_device::nes_ss88006_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_SS88006, "NES Cart Jaleco SS88006 PCB", tag, owner, clock, "nes_ss88006", __FILE__) +{ +} + +nes_ss88006_adpcm_device::nes_ss88006_adpcm_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : nes_ss88006_device(mconfig, type, name, tag, owner, clock, shortname, source) +{ +} + +nes_jf23_device::nes_jf23_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_ss88006_adpcm_device(mconfig, NES_JF23, "NES Cart Jaleco Shin Moero Pro Yakyuu PCB", tag, owner, clock, "nes_jf23", __FILE__), + m_samples(*this, "samples") +{ +} + +nes_jf24_device::nes_jf24_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_ss88006_adpcm_device(mconfig, NES_JF24, "NES Cart Jaleco Terao no Dosukoi Oozumou PCB", tag, owner, clock, "nes_jf24", __FILE__), + m_samples(*this, "samples") +{ +} + +nes_jf29_device::nes_jf29_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_ss88006_adpcm_device(mconfig, NES_JF29, "NES Cart Jaleco Moe Pro! '90 PCB", tag, owner, clock, "nes_jf29", __FILE__), + m_samples(*this, "samples") +{ +} + +nes_jf33_device::nes_jf33_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_ss88006_adpcm_device(mconfig, NES_JF33, "NES Cart Jaleco Moe Pro! Saikyou-hen PCB", tag, owner, clock, "nes_jf33", __FILE__), + m_samples(*this, "samples") +{ +} + + + +void nes_jf11_device::device_start() +{ + common_start(); +} + +void nes_jf11_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); +} + +void nes_jf13_device::device_start() +{ + common_start(); +} + +void nes_jf13_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); +} + +void nes_jf16_device::device_start() +{ + common_start(); +} + +void nes_jf16_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); +} + +void nes_jf17_device::device_start() +{ + common_start(); + save_item(NAME(m_latch)); +} + +void nes_jf17_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); + m_latch = 0; +} + +void nes_jf19_device::device_start() +{ + common_start(); +} + +void nes_jf19_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); +} + +void nes_ss88006_device::device_start() +{ + common_start(); + irq_timer = timer_alloc(TIMER_IRQ); + irq_timer->adjust(attotime::zero, 0, machine().device("maincpu")->cycles_to_attotime(1)); + + save_item(NAME(m_mmc_prg_bank)); + save_item(NAME(m_mmc_vrom_bank)); + save_item(NAME(m_irq_enable)); + save_item(NAME(m_irq_count)); + save_item(NAME(m_irq_count_latch)); + save_item(NAME(m_irq_mode)); + save_item(NAME(m_latch)); +} + +void nes_ss88006_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); + + memset(m_mmc_prg_bank, 0, sizeof(m_mmc_prg_bank)); + memset(m_mmc_vrom_bank, 0, sizeof(m_mmc_vrom_bank)); + m_irq_enable = 0; + m_irq_mode = 0; + m_irq_count = 0; + m_irq_count_latch = 0; + m_latch = 0; +} + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +/*------------------------------------------------- + + Jaleco JF-11, JF-12 & JF-14 boards emulation + + Games: Bio Senshi Dan, Mississippi Satsujin Jiken + + iNES: mapper 140 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_jf11_device::write_m) +{ + LOG_MMC(("jf11 write_m, offset: %04x, data: %02x\n", offset, data)); + chr8(data, CHRROM); + prg32(data >> 4); +} + +/*------------------------------------------------- + + Jaleco JF-13 board emulation + + Games: Moero Pro Yakyuu + + Note: we don't emulate the additional sound hardware. + + iNES: mapper 86 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_jf13_device::write_m) +{ + LOG_MMC(("jf13 write_m, offset: %04x, data: %02x\n", offset, data)); + + if (offset < 0x1000) + { + prg32((data >> 4) & 0x03); + chr8(((data >> 4) & 0x04) | (data & 0x03), CHRROM); + } + else + { +// printf("sample write: offset: %04x, data: %02x\n", offset, data); + if (data & 0x20) + m_samples->start(data & 0x0f, data & 0x0f); + else + m_samples->stop_all(); + } +} + +/*------------------------------------------------- + + Jaleco JF-16 board emulation + + iNES: mapper 78 (shared with a diff Irem board) + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_jf16_device::write_h) +{ + LOG_MMC(("jf16 write_h, offset: %04x, data: %02x\n", offset, data)); + + // this pcb is subject to bus conflict + data = account_bus_conflict(offset, data); + + set_nt_mirroring(BIT(data, 3) ? PPU_MIRROR_HIGH : PPU_MIRROR_LOW); + chr8(data >> 4, CHRROM); + prg16_89ab(data); +} + + +/*------------------------------------------------- + + Jaleco JF-17 boards emulation + + Note: we don't emulate the additional sound hardware + for Moero!! Pro Tennis + + Games: Moero!! Juudou Warriors, Moero!! Pro Tennis, Pinball + Quest Jpn + + iNES: mapper 72 + + In MESS: Supported, see below for the Moero Pro Tennis + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_jf17_device::write_h) +{ + LOG_MMC(("jf17 write_h, offset: %04x, data: %02x\n", offset, data)); + + // this pcb is subject to bus conflict + data = account_bus_conflict(offset, data); + + if (BIT(m_latch, 7) && !BIT(data, 7)) + prg16_89ab(m_latch & 0x07); + if (BIT(m_latch, 6) && !BIT(data, 6)) + chr8(m_latch & 0x0f, CHRROM); + + m_latch = data; +} + +WRITE8_MEMBER(nes_jf17_adpcm_device::write_h) +{ + LOG_MMC(("jf17 + ADPCM write_h, offset: %04x, data: %02x\n", offset, data)); + + // this pcb is subject to bus conflict + data = account_bus_conflict(offset, data); + + if (BIT(m_latch, 7) && !BIT(data, 7)) + prg16_89ab(m_latch & 0x07); + if (BIT(m_latch, 6) && !BIT(data, 6)) + chr8(m_latch & 0x0f, CHRROM); + if (BIT(data, 5) && !BIT(data,4)) + { +// printf("sample write: offset: %04x, data: %02x\n", offset, data); + m_samples->start(offset & 0x1f, offset & 0x1f); + } + + m_latch = data; +} + +/*------------------------------------------------- + + Jaleco JF-19 boards emulation + + Note: we don't emulate the additional sound hardware. + + Games: Moero Pro Soccer, Moero Pro Yakyuu '88 + + iNES: mapper 92 + + In MESS: Supported, see below for the Moero Pro Yakyuu '88 + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_jf19_device::write_h) +{ + LOG_MMC(("jf19 write_h, offset: %04x, data: %02x\n", offset, data)); + + // this pcb is subject to bus conflict + data = account_bus_conflict(offset, data); + + if (BIT(data, 7)) + prg16_cdef(data & 0x0f); + if (BIT(data, 6)) + chr8(data & 0x0f, CHRROM); +} + +WRITE8_MEMBER(nes_jf19_adpcm_device::write_h) +{ + LOG_MMC(("jf19 + ADPCM write_h, offset: %04x, data: %02x\n", offset, data)); + + // this pcb is subject to bus conflict + data = account_bus_conflict(offset, data); + + if (BIT(data, 7)) + prg16_cdef(data & 0x0f); + if (BIT(data, 6)) + chr8(data & 0x0f, CHRROM); + if (BIT(data, 5) && !BIT(data,4)) + { +// printf("sample write: offset: %04x, data: %02x\n", offset, data); + m_samples->start(offset & 0x1f, offset & 0x1f); + } +} + +/*------------------------------------------------- + + Jaleco SS88006 board emulation, aka JF-27, JF-29, JF-30, ..., + JF-38, JF-40, JF-41 + + Games: Lord of King, Magic John, Moe Pro '90, Ninja Jajamaru, + Pizza Pop, Plasma Ball + + iNES: mapper 18 + + In MESS: Supported, see below for the games with samples + + -------------------------------------------------*/ + +void nes_ss88006_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + if (id == TIMER_IRQ) + { + if (m_irq_enable) + { + if (m_irq_mode & 0x08) // 4bits counter + { + if (!(m_irq_count & 0x000f)) + { + m_maincpu->set_input_line(M6502_IRQ_LINE, ASSERT_LINE); + m_irq_count = (m_irq_count & 0xfff0) | 0x000f; + } + else + m_irq_count = (m_irq_count & 0xfff0) | ((m_irq_count & 0x000f) - 1); + } + else if (m_irq_mode & 0x04) // 8bits counter + { + if (!(m_irq_count & 0x00ff)) + { + m_maincpu->set_input_line(M6502_IRQ_LINE, ASSERT_LINE); + m_irq_count = (m_irq_count & 0xff00) | 0x00ff; + } + else + m_irq_count = (m_irq_count & 0xff00) | ((m_irq_count & 0x00ff) - 1); + } + else if (m_irq_mode & 0x02) // 12bits counter + { + if (!(m_irq_count & 0x0fff)) + { + m_maincpu->set_input_line(M6502_IRQ_LINE, ASSERT_LINE); + m_irq_count = (m_irq_count & 0xf000) | 0x0fff; + } + else + m_irq_count = (m_irq_count & 0xf000) | ((m_irq_count & 0x0fff) - 1); + } + else // 16bits counter + { + if (!m_irq_count) + { + m_maincpu->set_input_line(M6502_IRQ_LINE, ASSERT_LINE); + m_irq_count = 0xffff; + } + else + m_irq_count = m_irq_count - 1; + } + } + } +} + +WRITE8_MEMBER(nes_ss88006_device::ss88006_write) +{ + UINT8 bank; + LOG_MMC(("ss88006 write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x7003) + { + case 0x0000: + m_mmc_prg_bank[0] = (m_mmc_prg_bank[0] & 0xf0) | (data & 0x0f); + prg8_89(m_mmc_prg_bank[0]); + break; + case 0x0001: + m_mmc_prg_bank[0] = (m_mmc_prg_bank[0] & 0x0f) | (data << 4); + prg8_89(m_mmc_prg_bank[0]); + break; + case 0x0002: + m_mmc_prg_bank[1] = (m_mmc_prg_bank[1] & 0xf0) | (data & 0x0f); + prg8_ab(m_mmc_prg_bank[1]); + break; + case 0x0003: + m_mmc_prg_bank[1] = (m_mmc_prg_bank[1] & 0x0f) | (data << 4); + prg8_ab(m_mmc_prg_bank[1]); + break; + case 0x1000: + m_mmc_prg_bank[2] = (m_mmc_prg_bank[2] & 0xf0) | (data & 0x0f); + prg8_cd(m_mmc_prg_bank[2]); + break; + case 0x1001: + m_mmc_prg_bank[2] = (m_mmc_prg_bank[2] & 0x0f) | (data << 4); + prg8_cd(m_mmc_prg_bank[2]); + break; + + /* $9002, 3 (1002, 3) uncaught = Jaleco Baseball writes 0 */ + /* believe it's related to battery-backed ram enable/disable */ + + case 0x2000: case 0x2001: case 0x2002: case 0x2003: + case 0x3000: case 0x3001: case 0x3002: case 0x3003: + case 0x4000: case 0x4001: case 0x4002: case 0x4003: + case 0x5000: case 0x5001: case 0x5002: case 0x5003: + bank = ((offset & 0x7000) - 0x2000) / 0x0800 + ((offset & 0x0002) >> 1); + if (offset & 0x0001) + m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & 0x0f) | ((data & 0x0f)<< 4); + else + m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & 0xf0) | (data & 0x0f); + + chr1_x(bank, m_mmc_vrom_bank[bank], CHRROM); + break; + + case 0x6000: + m_irq_count_latch = (m_irq_count_latch & 0xfff0) | (data & 0x0f); + break; + case 0x6001: + m_irq_count_latch = (m_irq_count_latch & 0xff0f) | ((data & 0x0f) << 4); + break; + case 0x6002: + m_irq_count_latch = (m_irq_count_latch & 0xf0ff) | ((data & 0x0f) << 8); + break; + case 0x6003: + m_irq_count_latch = (m_irq_count_latch & 0x0fff) | ((data & 0x0f) << 12); + break; + case 0x7000: + m_irq_count = m_irq_count_latch; + m_maincpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE); + break; + case 0x7001: + m_irq_enable = data & 0x01; + m_irq_mode = data & 0x0e; + m_maincpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE); + break; + + case 0x7002: + switch (data & 0x03) + { + case 0: set_nt_mirroring(PPU_MIRROR_HORZ); break; + case 1: set_nt_mirroring(PPU_MIRROR_VERT); break; + case 2: set_nt_mirroring(PPU_MIRROR_LOW); break; + case 3: set_nt_mirroring(PPU_MIRROR_HIGH); break; + } + break; + + default: + logerror("Jaleco SS88006 uncaught write, addr: %04x, value: %02x\n", offset + 0x8000, data); + break; + } +} + + +// bits2-bits6 are sample number, bit1 is setup/enable/disable +// program first write sample # + bit1 set to 'init' the sample +// then it writes sample # + bit1 clear to 'start' the sample +void nes_ss88006_adpcm_device::ss88006_adpcm_write(address_space &space, offs_t offset, UINT8 data, samples_device *dev) +{ + LOG_MMC(("ss88006 write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x7003) + { + case 0x7003: + if ((m_latch & 0x7c) == (data & 0x7c)) + { +// printf("sample write: data: %02x\n", data); + if ((m_latch & 2) && !(data & 2)) + dev->start((data >> 2) & 0x1f, (data >> 2) & 0x1f); + } + m_latch = data; + break; + + default: + ss88006_write(space, offset, data); + break; + } +} + +/********************************************************** + + Boards with external samples + (due to undumpable UPD7755C/UPD7756C) + + JF-13 (Moero!! Pro Yakyuu) / iNES mapper 86 + JF-17 (Moero!! Pro Tennis) / iNES mapper 72 + ADPCM + JF-19 (Moero!! Pro Yakyuu '88 - Kettei Ban) / iNES mapper 92 + ADPCM + JF-23 (Shin Moero Pro Yakyuu) / iNES mapper 18 + ADPCM + JF-24 (Terao no Dosukoi Oozumou) / iNES mapper 18 + ADPCM + JF-29 (Moe Pro 90) / iNES mapper 18 + ADPCM + JF-33 (Moe Pro Saikyou-hen) / iNES mapper 18 + ADPCM + + +***********************************************************/ + +static const char *const jf13_sample_names[] = +{ + "*moepro", + "00", // strike + "01", // ball + "02", // time + "03", // out + "04", // safe + "05", // foul + "06", // (catcher obtains the ball) + "07", // you're out + "08", // play ball + "09", // ball four + "10", // home run + "11", // new pitcher + "12", // ouch (pitcher hits batter) + "13", // ?? + "14", // (bat hits the ball) + "15", // (crowd) + 0 +}; + +static const char *const jf17_sample_names[] = +{ + "*mptennis", + "00", // NOT EXISTING? + "01", // NOT EXISTING? + "02", // "love" (points) + "03", // 15 (points) + "04", // 30 (points) + "05", // 40 (points) + "06", // advantage + "07", // (advantage) server + "08", // (advantage) receiver + "09", // all (equal points) + "10", // deuce + "11", // game + "12", // (racket hits ball) + "13", // (crowd?) + "14", // fault + "15", // net + "16", // out + "17", // ?? + "18", // (ball hits player) + "19", // NOT EXISTING? + 0 +}; + +static const char *const jf19_sample_names[] = +{ + "*moepro88", + "00", // out + "01", // safe + "02", // foul + "03", // fair + "04", // strike + "05", // ball + "06", // time + "07", // batter out + "08", // ball four + "09", // home run + "10", // play ball + "11", // new pitcher + "12", // pinch-hit + "13", // (hit by pitch) + "14", // (bat hits the ball) + "15", // (bunt) + "16", // NOT EXISTING? + "17", // (catcher obtains the ball) + "18", // (pitcher obtains the ball) + "19", // (crowd) + 0 +}; + +static const char *const jf23_sample_names[] = +{ + "*smoepro", + "00", // out + "01", // safe + "02", // foul + "03", // NOT EXISTING? + "04", // strike + "05", // ball + "06", // time + "07", // batter out + "08", // ball four + "09", // home run + "10", // play ball + "11", // new pitcher + "12", // pinch-hit + "13", // (hit by pitch) + "14", // (bat hits the ball) + "15", // (bunt) + "16", // (catcher obtains the ball) + "17", // fair + "18", // (catcher obtains the ball, alt) + "19", // (crowd) + 0 +}; + +static const char *const jf24_sample_names[] = +{ + "*terao", + "00", // (tree beating sound) + "01", // Hakkyoyoi + "02", // Nokotta + "03", // Matta Nashi + "04", // Nokotta Nokotta + "05", // Matta Arimasen + 0 +}; + +static const char *const jf29_sample_names[] = +{ + "*moepro90", + "00", // out + "01", // safe + "02", // foul + "03", // Not existing? + "04", // strike + "05", // ball + "06", // time + "07", // batter out + "08", // ball four + "09", // home run + "10", // play ball + "11", // new pitcher + "12", // pinch-hit + "13", // (hit by pitch) + "14", // (bat hits the ball) + "15", // (bunt) + "16", // (catcher obtains the ball, alt) + "17", // (catcher obtains the ball) + "18", // (catcher obtains the ball, alt 2) + "19", // (crowd) + 0 +}; + +static const char *const jf33_sample_names[] = +{ + "*mpsaikyo", + "00", // out + "01", // safe + "02", // foul + "03", // ??? + "04", // strike + "05", // ball + "06", // time + "07", // batter out + "08", // ball four + "09", // home run + "10", // play ball + "11", // new pitcher + "12", // pinch-hit + "13", // (hit by pitch) + "14", // (bat hits the ball) + "15", // (bunt) + "16", // (catcher obtains the ball) + "17", // (catcher obtains the ball, alt) + "18", // ?? + "19", // (crowd) + 0 +}; + +//------------------------------------------------- +// MACHINE_DRIVER +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( jf13 ) + + // additional sound hardware + MCFG_SPEAKER_STANDARD_MONO("addon") + + MCFG_SOUND_ADD("samples", SAMPLES, 0) + MCFG_SAMPLES_CHANNELS(16) + MCFG_SAMPLES_NAMES(jf13_sample_names) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "addon", 0.50) +MACHINE_CONFIG_END + +static MACHINE_CONFIG_FRAGMENT( jf17 ) + + // additional sound hardware + MCFG_SPEAKER_STANDARD_MONO("addon") + + MCFG_SOUND_ADD("samples", SAMPLES, 0) + MCFG_SAMPLES_CHANNELS(20) + MCFG_SAMPLES_NAMES(jf17_sample_names) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "addon", 0.50) +MACHINE_CONFIG_END + +static MACHINE_CONFIG_FRAGMENT( jf19 ) + + // additional sound hardware + MCFG_SPEAKER_STANDARD_MONO("addon") + + MCFG_SOUND_ADD("samples", SAMPLES, 0) + MCFG_SAMPLES_CHANNELS(20) + MCFG_SAMPLES_NAMES(jf19_sample_names) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "addon", 0.50) +MACHINE_CONFIG_END + +static MACHINE_CONFIG_FRAGMENT( jf23 ) + + // additional sound hardware + MCFG_SPEAKER_STANDARD_MONO("addon") + + MCFG_SOUND_ADD("samples", SAMPLES, 0) + MCFG_SAMPLES_CHANNELS(20) + MCFG_SAMPLES_NAMES(jf23_sample_names) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "addon", 0.50) +MACHINE_CONFIG_END + +static MACHINE_CONFIG_FRAGMENT( jf24 ) + + // additional sound hardware + MCFG_SPEAKER_STANDARD_MONO("addon") + + MCFG_SOUND_ADD("samples", SAMPLES, 0) + MCFG_SAMPLES_CHANNELS(6) + MCFG_SAMPLES_NAMES(jf24_sample_names) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "addon", 0.50) +MACHINE_CONFIG_END + +static MACHINE_CONFIG_FRAGMENT( jf29 ) + + // additional sound hardware + MCFG_SPEAKER_STANDARD_MONO("addon") + + MCFG_SOUND_ADD("samples", SAMPLES, 0) + MCFG_SAMPLES_CHANNELS(20) + MCFG_SAMPLES_NAMES(jf29_sample_names) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "addon", 0.50) +MACHINE_CONFIG_END + +static MACHINE_CONFIG_FRAGMENT( jf33 ) + + // additional sound hardware + MCFG_SPEAKER_STANDARD_MONO("addon") + + MCFG_SOUND_ADD("samples", SAMPLES, 0) + MCFG_SAMPLES_CHANNELS(20) + MCFG_SAMPLES_NAMES(jf33_sample_names) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "addon", 0.50) +MACHINE_CONFIG_END + +//------------------------------------------------- +// machine_config_additions +//------------------------------------------------- + +machine_config_constructor nes_jf13_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( jf13 ); +} + +machine_config_constructor nes_jf17_adpcm_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( jf17 ); +} + +machine_config_constructor nes_jf19_adpcm_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( jf19 ); +} + +machine_config_constructor nes_jf23_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( jf23 ); +} + +machine_config_constructor nes_jf24_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( jf24 ); +} + +machine_config_constructor nes_jf29_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( jf29 ); +} + +machine_config_constructor nes_jf33_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( jf33 ); +} diff --git a/src/devices/bus/nes/jaleco.h b/src/devices/bus/nes/jaleco.h new file mode 100644 index 00000000000..facea12b75f --- /dev/null +++ b/src/devices/bus/nes/jaleco.h @@ -0,0 +1,256 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __NES_JALECO_H +#define __NES_JALECO_H + +#include "nxrom.h" +#include "sound/samples.h" + + +// ======================> nes_jf11_device + +class nes_jf11_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_jf11_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_m); + + virtual void pcb_reset(); +}; + + +// ======================> nes_jf13_device + +class nes_jf13_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_jf13_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual machine_config_constructor device_mconfig_additions() const; + virtual DECLARE_WRITE8_MEMBER(write_m); + + virtual void pcb_reset(); + +private: + required_device m_samples; +}; + + +// ======================> nes_jf16_device + +class nes_jf16_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_jf16_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); +}; + + +// ======================> nes_jf17_device + +class nes_jf17_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_jf17_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + nes_jf17_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); + +protected: + UINT8 m_latch; +}; + + +// ======================> nes_jf17_adpcm_device + +class nes_jf17_adpcm_device : public nes_jf17_device +{ +public: + // construction/destruction + nes_jf17_adpcm_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual machine_config_constructor device_mconfig_additions() const; + virtual DECLARE_WRITE8_MEMBER(write_h); + +private: + required_device m_samples; +}; + + +// ======================> nes_jf19_device + +class nes_jf19_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_jf19_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + nes_jf19_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); +}; + + +// ======================> nes_jf19_adpcm_device + +class nes_jf19_adpcm_device : public nes_jf19_device +{ +public: + // construction/destruction + nes_jf19_adpcm_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual machine_config_constructor device_mconfig_additions() const; + virtual DECLARE_WRITE8_MEMBER(write_h); + +private: + required_device m_samples; +}; + + +// ======================> nes_ss88006_device + +class nes_ss88006_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_ss88006_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + nes_ss88006_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + virtual DECLARE_WRITE8_MEMBER(ss88006_write); + virtual DECLARE_WRITE8_MEMBER(write_h) { ss88006_write(space, offset, data, mem_mask); } + + virtual void pcb_reset(); + +protected: + UINT16 m_irq_count, m_irq_count_latch; + UINT8 m_irq_mode; + int m_irq_enable; + + static const device_timer_id TIMER_IRQ = 0; + emu_timer *irq_timer; + + UINT8 m_mmc_prg_bank[3]; + UINT8 m_mmc_vrom_bank[8]; + + UINT8 m_latch; // used for samples, in derived classes +}; + + +// ======================> nes_ss88006_adpcm_device + +class nes_ss88006_adpcm_device : public nes_ss88006_device +{ +public: + // construction/destruction + nes_ss88006_adpcm_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + // device-level overrides + void ss88006_adpcm_write(address_space &space, offs_t offset, UINT8 data, samples_device *dev); +}; + + +// ======================> nes_jf23_device + +class nes_jf23_device : public nes_ss88006_adpcm_device +{ +public: + // construction/destruction + nes_jf23_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual machine_config_constructor device_mconfig_additions() const; + +private: + required_device m_samples; + virtual DECLARE_WRITE8_MEMBER(write_h) { ss88006_adpcm_write(space, offset, data, m_samples); } +}; + + +// ======================> nes_jf24_device + +class nes_jf24_device : public nes_ss88006_adpcm_device +{ +public: + // construction/destruction + nes_jf24_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual machine_config_constructor device_mconfig_additions() const; + +private: + required_device m_samples; + virtual DECLARE_WRITE8_MEMBER(write_h) { ss88006_adpcm_write(space, offset, data, m_samples); } +}; + + +// ======================> nes_jf29_device + +class nes_jf29_device : public nes_ss88006_adpcm_device +{ +public: + // construction/destruction + nes_jf29_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual machine_config_constructor device_mconfig_additions() const; + +private: + required_device m_samples; + virtual DECLARE_WRITE8_MEMBER(write_h) { ss88006_adpcm_write(space, offset, data, m_samples); } +}; + + +// ======================> nes_jf33_device + +class nes_jf33_device : public nes_ss88006_adpcm_device +{ +public: + // construction/destruction + nes_jf33_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual machine_config_constructor device_mconfig_additions() const; + +private: + required_device m_samples; + virtual DECLARE_WRITE8_MEMBER(write_h) { ss88006_adpcm_write(space, offset, data, m_samples); } +}; + + + + +// device type definition +extern const device_type NES_JF11; +extern const device_type NES_JF13; +extern const device_type NES_JF16; +extern const device_type NES_JF17; +extern const device_type NES_JF17_ADPCM; +extern const device_type NES_JF19; +extern const device_type NES_JF19_ADPCM; +extern const device_type NES_SS88006; +extern const device_type NES_JF23; +extern const device_type NES_JF24; +extern const device_type NES_JF29; +extern const device_type NES_JF33; + +#endif diff --git a/src/devices/bus/nes/jy.c b/src/devices/bus/nes/jy.c new file mode 100644 index 00000000000..31358e2ab16 --- /dev/null +++ b/src/devices/bus/nes/jy.c @@ -0,0 +1,589 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + NES/Famicom cartridge emulation for JY Company + + + Here we emulate multiple PCBs by JY Company with weird IRQ mechanisms [mappers 90, 209, 211] + + TODO: long list... + - add dipswitches + - revamp IRQ system + * scanline/hblank irq should fire 8 times per line (currently not possible) + * implement CPU write IRQ (used by any games?) + * possibly implementing 'funky' IRQ mode (unused?) + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "jy.h" + +#include "cpu/m6502/m6502.h" +#include "video/ppu2c0x.h" // this has to be included so that IRQ functions can access PPU_BOTTOM_VISIBLE_SCANLINE + +#ifdef NES_PCB_DEBUG +#define VERBOSE 1 +#else +#define VERBOSE 0 +#endif + +#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) + + +//------------------------------------------------- +// constructor +//------------------------------------------------- + +const device_type NES_JY_TYPEA = &device_creator; +const device_type NES_JY_TYPEB = &device_creator; +const device_type NES_JY_TYPEC = &device_creator; + + +nes_jy_typea_device::nes_jy_typea_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : nes_nrom_device(mconfig, type, name, tag, owner, clock, shortname, source) +{ +} + +nes_jy_typea_device::nes_jy_typea_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_JY_TYPEA, "NES Cart JY Company Type A PCB", tag, owner, clock, "nes_jya", __FILE__) +{ +} + +nes_jy_typeb_device::nes_jy_typeb_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : nes_jy_typea_device(mconfig, type, name, tag, owner, clock, shortname, source) +{ +} + +nes_jy_typeb_device::nes_jy_typeb_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_jy_typea_device(mconfig, NES_JY_TYPEB, "NES Cart JY Company Type B PCB", tag, owner, clock, "nes_jyb", __FILE__) +{ +} + +nes_jy_typec_device::nes_jy_typec_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_jy_typeb_device(mconfig, NES_JY_TYPEC, "NES Cart JY Company Type C PCB", tag, owner, clock, "nes_jyc", __FILE__) +{ +} + + + + +void nes_jy_typea_device::device_start() +{ + common_start(); + irq_timer = timer_alloc(TIMER_IRQ); + irq_timer->reset(); + timer_freq = machine().device("maincpu")->cycles_to_attotime(1); + + save_item(NAME(m_mul)); + save_item(NAME(m_latch)); + save_item(NAME(m_mmc_prg_bank)); + save_item(NAME(m_mmc_nt_bank)); + save_item(NAME(m_mmc_vrom_bank)); + save_item(NAME(m_reg)); + save_item(NAME(m_chr_latch)); + save_item(NAME(m_bank_6000)); + + save_item(NAME(m_irq_prescale)); + save_item(NAME(m_irq_prescale_mask)); + save_item(NAME(m_irq_mode)); + save_item(NAME(m_irq_count)); + save_item(NAME(m_irq_flip)); + save_item(NAME(m_irq_enable)); + save_item(NAME(m_irq_up)); + save_item(NAME(m_irq_down)); +} + +void nes_jy_typea_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); + + // 0x5000-0x5fff + m_mul[0] = 0; + m_mul[1] = 0; + m_latch = 0; + + // 0x8000-0xffff + memset(m_mmc_prg_bank, 0xff, sizeof(m_mmc_prg_bank)); + memset(m_mmc_nt_bank, 0, sizeof(m_mmc_nt_bank)); + memset(m_mmc_vrom_bank, 0xffff, sizeof(m_mmc_vrom_bank)); + memset(m_reg, 0, sizeof(m_reg)); + m_chr_latch[0] = 0; + m_chr_latch[1] = 4; + m_bank_6000 = 0; + + update_prg(); + update_chr(); + update_mirror(); + + m_irq_mode = 0; + m_irq_count = 0; + m_irq_prescale = 0; + m_irq_prescale_mask = 0xff; + m_irq_flip = 0; + m_irq_enable = 0; + m_irq_up = 0; + m_irq_down = 0; +} + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +/*------------------------------------------------- + + JY Company Type A board emulation + + iNES: mapper 90 + + -------------------------------------------------*/ + + +READ8_MEMBER(nes_jy_typea_device::nt_r) +{ + int page = ((offset & 0xc00) >> 10); + irq_clock(0, 2); + return m_nt_access[page][offset & 0x3ff]; +} + +READ8_MEMBER(nes_jy_typea_device::chr_r) +{ + int bank = offset >> 10; + irq_clock(0, 2); + return m_chr_access[bank][offset & 0x3ff]; +} + +void nes_jy_typea_device::irq_clock(int mode, int blanked) +{ + bool clock = FALSE, fire = FALSE; + + if (m_irq_mode != mode) + return; + + // no counter changes if both Up/Down are set or clear + if ((m_irq_down && m_irq_up) || (!m_irq_down && !m_irq_up)) + return; + + // update prescaler + if (m_irq_down) + { + if ((m_irq_prescale & m_irq_prescale_mask) == 0) + { + clock = TRUE; + m_irq_prescale = (m_irq_prescale_mask == 7) ? ((m_irq_prescale & 0xf8) | 7) : 0xff; + } + else + m_irq_prescale = (m_irq_prescale_mask == 7) ? ((m_irq_prescale & 0xf8) | ((m_irq_prescale - 1) & m_irq_prescale_mask)) : (m_irq_prescale - 1); + } + + if (m_irq_up) + { + if ((m_irq_prescale & m_irq_prescale_mask) == m_irq_prescale_mask) + { + clock = TRUE; + m_irq_prescale = (m_irq_prescale_mask == 7) ? (m_irq_prescale & 0xf8) : 0; + } + else + m_irq_prescale = (m_irq_prescale_mask == 7) ? ((m_irq_prescale & 0xf8) | ((m_irq_prescale + 1) & m_irq_prescale_mask)) : (m_irq_prescale + 1); + } + + // if prescaler wraps, update count + if (clock) + { + if (m_irq_down) + { + if (m_irq_count == 0) + { + fire = TRUE; + m_irq_count = 0xff; + } + else + m_irq_count--; + } + + if (m_irq_up) + { + if (m_irq_count == 0xff) + { + fire = TRUE; + m_irq_count = 0; + } + else + m_irq_count++; + } + + + // if count wraps, check if IRQ is enabled + if (fire && m_irq_enable && !blanked) + m_maincpu->set_input_line(M6502_IRQ_LINE, ASSERT_LINE); + + } +} + +void nes_jy_typea_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + if (id == TIMER_IRQ) + { + irq_clock(0, 0); + } +} + +void nes_jy_typea_device::scanline_irq(int scanline, int vblank, int blanked) +{ + if (scanline < PPU_BOTTOM_VISIBLE_SCANLINE) + irq_clock(blanked, 1); +} + + +// 0x5000-0x5fff : sort of protection? +READ8_MEMBER(nes_jy_typea_device::read_l) +{ + LOG_MMC(("JY Company write_m, offset: %04x\n", offset)); + offset += 0x100; + + if (offset >= 0x1000 && offset < 0x1800) + { + // bit6/bit7 DSW read + return m_open_bus & 0x3f; + } + + if (offset >= 0x1800) + { + if ((offset & 7) == 0) + return (m_mul[0] * m_mul[1]) & 0xff; + if ((offset & 7) == 1) + return ((m_mul[0] * m_mul[1]) >> 8) & 0xff; + if ((offset & 7) == 3) + return m_latch; + } + + return m_open_bus; // open bus +} + +WRITE8_MEMBER(nes_jy_typea_device::write_l) +{ + LOG_MMC(("JY Company write_m, offset: %04x, data: %02x\n", offset, data)); + offset += 0x100; + + if (offset >= 0x1800) + { + if ((offset & 7) == 0) + m_mul[0] = data; + if ((offset & 7) == 1) + m_mul[1] = data; + if ((offset & 7) == 3) + m_latch = data; + } +} + +// 0x6000-0x7fff : WRAM or open bus +READ8_MEMBER(nes_jy_typea_device::read_m) +{ + LOG_MMC(("JY Company write_m, offset: %04x\n", offset)); + + if (m_reg[0] & 0x80) + return m_prg[(m_bank_6000 & m_prg_mask) * 0x2000 + (offset & 0x1fff)]; + + return m_open_bus; // open bus +} + + +inline UINT8 nes_jy_typea_device::unscramble(UINT8 bank) +{ + return BITSWAP8(bank & 0x7f,7,0,1,2,3,4,5,6); +} + +void nes_jy_typea_device::update_prg() +{ + UINT8 exPrg = (m_reg[3] & 0x06) << 5; + UINT8 last = (m_reg[0] & 0x04) ? m_mmc_prg_bank[3] : 0x3f; + + switch (m_reg[0] & 0x03) + { + case 0: // 32KB + prg32((last & 0x0f) | (exPrg >> 2)); + m_bank_6000 = (((m_mmc_prg_bank[3] * 4) + 3) & 0x3f) | (exPrg >> 2); + break; + + case 1: // 16KB + prg16_89ab((m_mmc_prg_bank[1] & 0x1f) | (exPrg >> 1)); + prg16_cdef((last & 0x1f) | (exPrg >> 1)); + m_bank_6000 = (((m_mmc_prg_bank[3] * 2) + 1) & 0x1f) | (exPrg >> 1); + break; + + case 2: // 8KB + prg8_89(m_mmc_prg_bank[0] | exPrg); + prg8_ab(m_mmc_prg_bank[1] | exPrg); + prg8_cd(m_mmc_prg_bank[2] | exPrg); + prg8_ef(last | exPrg); + m_bank_6000 = m_mmc_prg_bank[3] | exPrg; + break; + + case 3: // 8KB Alt + prg8_89((unscramble(m_mmc_prg_bank[0]) & 0x3f) | exPrg); + prg8_ab((unscramble(m_mmc_prg_bank[1]) & 0x3f) | exPrg); + prg8_cd((unscramble(m_mmc_prg_bank[2]) & 0x3f) | exPrg); + if (m_reg[0] & 0x04) + prg8_ef((unscramble(m_mmc_prg_bank[3]) & 0x3f) | exPrg); + else + prg8_ef((unscramble(last) & 0x3f) | exPrg); + m_bank_6000 = (unscramble(m_mmc_prg_bank[3]) & 0x3f) | exPrg; + break; + } +} + +void nes_jy_typea_device::update_chr() +{ + // in 1KB & 2KB mode, PPU 0x800-0xfff always mirrors 0x000-0x7ff (0x1800-0x1fff not affected) + int chr_mirror_mode = BIT(m_reg[3], 7) << 1; + + // Case (m_reg[3] & 0x20 == 0) + // Block mode enabled: in this case lower bits select a 256KB page inside CHRROM + // and the low bytes of m_mmc_vrom_bank select the banks inside such a page + + // docs suggest m_reg[3] & 0x1f for chr_page below, + // but 45 in 1 (JY-120A) menu requires to use this (from NEStopia) + UINT8 chr_page = (m_reg[3] & 1) | ((m_reg[3] & 0x18) >> 2); + UINT32 extra_chr_base = BIT(m_reg[3], 5) ? 0 : (chr_page * 0x100); + UINT32 extra_chr_mask = BIT(m_reg[3], 5) ? 0xffffff : 0xff; + + switch (m_reg[0] & 0x18) + { + case 0x00: // 8KB + extra_chr_base >>= 3; + extra_chr_mask >>= 3; + chr8(extra_chr_base | (m_mmc_vrom_bank[0] & extra_chr_mask), m_chr_source); + break; + + case 0x08: // 4KB + extra_chr_base >>= 2; + extra_chr_mask >>= 2; + // Type A & B games have fixed m_chr_latch[0] = 0 and m_chr_latch[1] = 4 + // Type C games can change them at each CHR access! + chr4_0(extra_chr_base | (m_mmc_vrom_bank[m_chr_latch[0]] & extra_chr_mask), m_chr_source); + chr4_4(extra_chr_base | (m_mmc_vrom_bank[m_chr_latch[1]] & extra_chr_mask), m_chr_source); + break; + + case 0x10: // 2KB + extra_chr_base >>= 1; + extra_chr_mask >>= 1; + chr2_0(extra_chr_base | (m_mmc_vrom_bank[0] & extra_chr_mask), m_chr_source); + chr2_2(extra_chr_base | (m_mmc_vrom_bank[2 ^ chr_mirror_mode] & extra_chr_mask), m_chr_source); + chr2_4(extra_chr_base | (m_mmc_vrom_bank[4] & extra_chr_mask), m_chr_source); + chr2_6(extra_chr_base | (m_mmc_vrom_bank[6] & extra_chr_mask), m_chr_source); + break; + + case 0x18: // 1KB + chr1_0(extra_chr_base | (m_mmc_vrom_bank[0] & extra_chr_mask), m_chr_source); + chr1_1(extra_chr_base | (m_mmc_vrom_bank[1] & extra_chr_mask), m_chr_source); + chr1_2(extra_chr_base | (m_mmc_vrom_bank[2 ^ chr_mirror_mode] & extra_chr_mask), m_chr_source); + chr1_3(extra_chr_base | (m_mmc_vrom_bank[3 ^ chr_mirror_mode] & extra_chr_mask), m_chr_source); + chr1_4(extra_chr_base | (m_mmc_vrom_bank[4] & extra_chr_mask), m_chr_source); + chr1_5(extra_chr_base | (m_mmc_vrom_bank[5] & extra_chr_mask), m_chr_source); + chr1_6(extra_chr_base | (m_mmc_vrom_bank[6] & extra_chr_mask), m_chr_source); + chr1_7(extra_chr_base | (m_mmc_vrom_bank[7] & extra_chr_mask), m_chr_source); + break; + } +} + +void nes_jy_typea_device::update_mirror_typea() +{ + switch (m_reg[1] & 3) + { + case 0: set_nt_mirroring(PPU_MIRROR_VERT); break; + case 1: set_nt_mirroring(PPU_MIRROR_HORZ); break; + case 2: set_nt_mirroring(PPU_MIRROR_LOW); break; + case 3: set_nt_mirroring(PPU_MIRROR_HIGH); break; + } +} + +void nes_jy_typea_device::update_banks(int reg) +{ + switch (reg & 3) + { + case 0: + update_prg(); + update_chr(); + update_mirror(); + break; + case 1: + update_mirror(); + break; + case 2: + update_mirror(); + break; + case 3: + update_prg(); + update_chr(); + break; + } +} + + +WRITE8_MEMBER(nes_jy_typea_device::write_h) +{ + LOG_MMC(("JY Company write_m, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x7000) + { + case 0x0000: + offset &= 3; + data &= 0x3f; + if (m_mmc_prg_bank[offset] != data) + { + m_mmc_prg_bank[offset] = data; + update_prg(); + } + break; + case 0x1000: + offset &= 7; + if ((m_mmc_vrom_bank[offset] & 0xff) != data) + { + m_mmc_vrom_bank[offset] = (m_mmc_vrom_bank[offset] & 0xff00) | data; + update_chr(); + } + break; + case 0x2000: + offset &= 7; + if ((m_mmc_vrom_bank[offset] & 0xff00) != (data << 8)) + { + m_mmc_vrom_bank[offset] = (m_mmc_vrom_bank[offset] & 0x00ff) | (data << 8); + update_chr(); + } + break; + case 0x3000: + if (!(offset & 4)) + { + offset &= 3; + m_mmc_nt_bank[offset] = (m_mmc_nt_bank[offset] & 0xff00) | data; + } + else + { + offset &= 3; + m_mmc_nt_bank[offset] = (m_mmc_nt_bank[offset] & 0x00ff) | data << 8; + } + update_mirror(); + break; + case 0x4000: + switch (offset & 7) + { + case 0: + if (BIT(data, 0)) + m_irq_enable = 1; + else + { + m_maincpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE); + m_irq_enable = 0; + } + break; + case 1: + m_irq_mode = data & 3; + m_irq_prescale_mask = (data & 4) ? 0x07 : 0xff; + m_irq_down = data & 0x80; + m_irq_up = data & 0x40; + if (m_irq_mode == 0) + irq_timer->adjust(attotime::zero, 0, timer_freq); + else + irq_timer->adjust(attotime::never); + break; + case 2: + m_maincpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE); + m_irq_enable = 0; + break; + case 3: + m_irq_enable = 1; + break; + case 4: + m_irq_prescale = data ^ m_irq_flip; + break; + case 5: + m_irq_count = data ^ m_irq_flip; + break; + case 6: + m_irq_flip = data; + break; + case 7: + // this is used for the 'funky' IRQ mode, not implemented yet + break; + } + break; + case 0x5000: + if (m_reg[offset & 3] != data) + { + m_reg[offset & 3] = data; + update_banks(offset & 3); + } + break; + } +} + +/*------------------------------------------------- + + JY Company Type B board emulation + + iNES: mapper 211 + + The mirroring system is a lot more complex in this + board + + -------------------------------------------------*/ + +void nes_jy_typeb_device::update_mirror_typeb() +{ + for (int i = 0; i < 4; i++) + { + if (BIT(m_reg[0], 6)) // CHRROM + set_nt_page(i, VROM, m_mmc_nt_bank[i], 0); + else // might be either CHRROM or CIRAM + { + // CHRROM is only used if bit 7 of the NT Reg does not match bit7 of reg[2]. + if ((m_mmc_nt_bank[i] ^ m_reg[2]) & 0x80) + set_nt_page(i, VROM, m_mmc_nt_bank[i], 0); + else + set_nt_page(i, CIRAM, m_mmc_nt_bank[i] & 1, 1); + } + } +} + +/*------------------------------------------------- + + JY Company Type C board emulation + + iNES: mapper 209 + + These board can switch between the Type A and the + Type B mirroring + + -------------------------------------------------*/ + +void nes_jy_typec_device::update_mirror_typec() +{ + if (BIT(m_reg[0], 5)) + update_mirror_typeb(); + else + update_mirror_typea(); +} + +READ8_MEMBER(nes_jy_typec_device::chr_r) +{ + int bank = offset >> 10; + + irq_clock(0, 2); + switch (offset & 0xff0) + { + case 0xfd0: + m_chr_latch[BIT(offset, 12)] = (bank & 0x4); + update_chr(); + break; + case 0xfe0: + m_chr_latch[BIT(offset, 12)] = (bank & 0x4) | 0x2; + update_chr(); + break; + } + return m_chr_access[bank][offset & 0x3ff]; +} diff --git a/src/devices/bus/nes/jy.h b/src/devices/bus/nes/jy.h new file mode 100644 index 00000000000..f2441654d57 --- /dev/null +++ b/src/devices/bus/nes/jy.h @@ -0,0 +1,104 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __NES_JY_H +#define __NES_JY_H + +#include "nxrom.h" + + +// ======================> nes_jy_typea_device + +class nes_jy_typea_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_jy_typea_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + nes_jy_typea_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + virtual DECLARE_READ8_MEMBER(read_l); + virtual DECLARE_READ8_MEMBER(read_m); + virtual DECLARE_WRITE8_MEMBER(write_l); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual DECLARE_READ8_MEMBER(chr_r); + virtual DECLARE_READ8_MEMBER(nt_r); + + virtual void scanline_irq(int scanline, int vblank, int blanked); + virtual void pcb_reset(); + +protected: + void irq_clock(int blanked, int mode); + void update_banks(int reg); + void update_prg(); + void update_chr(); + void update_mirror_typea(); + virtual void update_mirror() { update_mirror_typea(); } + inline UINT8 unscramble(UINT8 bank); + + UINT8 m_mul[2]; + UINT8 m_latch; + UINT8 m_reg[4]; + UINT8 m_chr_latch[2]; // type C uses a more complex CHR 4K mode, and these vars are only changed for those games + UINT8 m_mmc_prg_bank[4]; + UINT16 m_mmc_nt_bank[4]; + UINT16 m_mmc_vrom_bank[8]; + UINT16 m_extra_chr_bank; + UINT16 m_extra_chr_mask; + int m_bank_6000; + + UINT8 m_irq_mode; + UINT8 m_irq_count; + UINT8 m_irq_prescale; + UINT8 m_irq_prescale_mask; + UINT8 m_irq_flip; + int m_irq_enable; + int m_irq_up, m_irq_down; + + static const device_timer_id TIMER_IRQ = 0; + emu_timer *irq_timer; + attotime timer_freq; +}; + + +// ======================> nes_jy_typeb_device + +class nes_jy_typeb_device : public nes_jy_typea_device +{ +public: + // construction/destruction + nes_jy_typeb_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + nes_jy_typeb_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + void update_mirror_typeb(); + virtual void update_mirror() { update_mirror_typeb(); } +}; + +// ======================> nes_jy_typec_device + +class nes_jy_typec_device : public nes_jy_typeb_device +{ +public: + // construction/destruction + nes_jy_typec_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual DECLARE_READ8_MEMBER(chr_r); + +protected: + void update_mirror_typec(); + virtual void update_mirror() { update_mirror_typec(); } +}; + + + + + +// device type definition +extern const device_type NES_JY_TYPEA; +extern const device_type NES_JY_TYPEB; +extern const device_type NES_JY_TYPEC; + +#endif diff --git a/src/devices/bus/nes/kaiser.c b/src/devices/bus/nes/kaiser.c new file mode 100644 index 00000000000..1c7d7bced0a --- /dev/null +++ b/src/devices/bus/nes/kaiser.c @@ -0,0 +1,588 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + NES/Famicom cartridge emulation for Kaiser PCBs + + + Here we emulate the following Kaiser bootleg PCBs + + * Kaiser KS202 + * Kaiser KS7012 + * Kaiser KS7013B + * Kaiser KS7017 + * Kaiser KS7022 + * Kaiser KS7032 + * Kaiser KS7058 + + The Kaiser KS7057 bootleg board is emulated in nes_mmc3_clones.c + + + TODO: + - FCEUmm lists more Kaiser PCBs: + * KS7030 (for Yume Koujou Doki Doki Panic by Kaiser?) + * KS7037 + but there seem to be no available dumps... + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "kaiser.h" + +#include "cpu/m6502/m6502.h" + + +#ifdef NES_PCB_DEBUG +#define VERBOSE 1 +#else +#define VERBOSE 0 +#endif + +#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) + + +//------------------------------------------------- +// constructor +//------------------------------------------------- + +const device_type NES_KS7058 = &device_creator; +const device_type NES_KS7022 = &device_creator; +const device_type NES_KS7032 = &device_creator; +const device_type NES_KS202 = &device_creator; +const device_type NES_KS7017 = &device_creator; +const device_type NES_KS7012 = &device_creator; +const device_type NES_KS7013B = &device_creator; +const device_type NES_KS7031 = &device_creator; + + +nes_ks7058_device::nes_ks7058_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_KS7058, "NES Cart Kaiser KS-7058 PCB", tag, owner, clock, "nes_ks7058", __FILE__) +{ +} + +nes_ks7022_device::nes_ks7022_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_KS7022, "NES Cart Kaiser KS-7022 PCB", tag, owner, clock, "nes_ks7022", __FILE__) +{ +} + +nes_ks7032_device::nes_ks7032_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : nes_nrom_device(mconfig, type, name, tag, owner, clock, shortname, source) +{ +} + +nes_ks7032_device::nes_ks7032_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_KS7032, "NES Cart Kaiser KS-7032 PCB", tag, owner, clock, "nes_ks7032", __FILE__) +{ +} + +nes_ks202_device::nes_ks202_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_ks7032_device(mconfig, NES_KS202, "NES Cart Kaiser KS-202 PCB", tag, owner, clock, "nes_ks202", __FILE__) +{ +} + +nes_ks7017_device::nes_ks7017_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_KS7017, "NES Cart Kaiser KS-7017 PCB", tag, owner, clock, "nes_ks7017", __FILE__) +{ +} + +nes_ks7012_device::nes_ks7012_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_KS7012, "NES Cart Kaiser KS-7012 PCB", tag, owner, clock, "nes_ks7012", __FILE__) +{ +} + +nes_ks7013b_device::nes_ks7013b_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_KS7013B, "NES Cart Kaiser KS-7013B PCB", tag, owner, clock, "nes_ks7013b", __FILE__) +{ +} + +nes_ks7031_device::nes_ks7031_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_KS7031, "NES Cart Kaiser KS-7031 PCB", tag, owner, clock, "nes_ks7031", __FILE__) +{ +} + + + + +void nes_ks7058_device::device_start() +{ + common_start(); +} + +void nes_ks7058_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); +} + +void nes_ks7022_device::device_start() +{ + common_start(); + save_item(NAME(m_latch)); +} + +void nes_ks7022_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); + + m_latch = 0; +} + +void nes_ks7032_device::device_start() +{ + common_start(); + irq_timer = timer_alloc(TIMER_IRQ); + irq_timer->adjust(attotime::zero, 0, machine().device("maincpu")->cycles_to_attotime(1)); + + save_item(NAME(m_latch)); + save_item(NAME(m_irq_enable)); + save_item(NAME(m_irq_count)); + save_item(NAME(m_reg)); +} + +void nes_ks7032_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); + + m_latch = 0; + m_irq_enable = 0; + m_irq_count = 0; + memset(m_reg, 0, sizeof(m_reg)); + prg_update(); +} + +void nes_ks7017_device::device_start() +{ + common_start(); + irq_timer = timer_alloc(TIMER_IRQ); + irq_timer->adjust(attotime::zero, 0, machine().device("maincpu")->cycles_to_attotime(1)); + + save_item(NAME(m_latch)); + save_item(NAME(m_irq_enable)); + save_item(NAME(m_irq_count)); + save_item(NAME(m_irq_status)); +} + +void nes_ks7017_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(2); + chr8(0, m_chr_source); + + m_latch = 0; + m_irq_enable = 0; + m_irq_count = 0; + m_irq_status = 0; +} + +void nes_ks7012_device::device_start() +{ + common_start(); +} + +void nes_ks7012_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0xff); + chr8(0, m_chr_source); +} + +void nes_ks7013b_device::device_start() +{ + common_start(); +} + +void nes_ks7013b_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); +} + +void nes_ks7031_device::device_start() +{ + common_start(); + save_item(NAME(m_reg)); +} + +void nes_ks7031_device::pcb_reset() +{ + prg32(0); // not really used... + chr8(0, CHRRAM); + + m_reg[0] = 0; + m_reg[1] = 0; + m_reg[2] = 0; + m_reg[3] = 0; +} + + + + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +/*------------------------------------------------- + + Kaiser Board KS7058 + + Games: Tui Do Woo Ma Jeung + + Writes to 0xf000-0xffff set 4k chr banks. Namely, if + offset&0x80 is 0 the lower 4k are set, if it is 1 the + upper 4k are set. + + iNES: mapper 171 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_ks7058_device::write_h) +{ + LOG_MMC(("ks7058 write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x7080) + { + case 0x7000: + chr4_0(data, CHRROM); + break; + case 0x7080: + chr4_4(data, CHRROM); + break; + } +} + +/*------------------------------------------------- + + Kaiser Board KS7022 + + Games: 15 in 1 + + iNES: mapper 175 + + In MESS: Supported? + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_ks7022_device::write_h) +{ + LOG_MMC(("ks7022 write_h, offset: %04x, data: %02x\n", offset, data)); + + if (offset == 0) + set_nt_mirroring(BIT(data, 2) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + + if (offset == 0x2000) + m_latch = data & 0x0f; +} + +READ8_MEMBER(nes_ks7022_device::read_h) +{ + LOG_MMC(("ks7022 read_h, offset: %04x\n", offset)); + + if (offset == 0x7ffc) + { + chr8(m_latch, CHRROM); + prg16_89ab(m_latch); + prg16_cdef(m_latch); + } + + return hi_access_rom(offset); +} + +/*------------------------------------------------- + + Kaiser Board KS7032 + + Games: A few FDS conversions like Bubble Bobble + or SMB2 + + iNES: + + TODO: available dumps do not seem to use WRAM... + yet m_reg[4] should switch WRAM bank... investigate! + + In MESS: Supported? + + -------------------------------------------------*/ + +void nes_ks7032_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + if (id == TIMER_IRQ) + { + if (m_irq_enable) + { + if (m_irq_count == 0xffff) + { + m_irq_enable = 0; + m_irq_count = 0; + m_maincpu->set_input_line(M6502_IRQ_LINE, HOLD_LINE); + } + else + m_irq_count++; + } + } +} + +void nes_ks7032_device::prg_update() +{ + prg8_89(m_reg[1]); + prg8_ab(m_reg[2]); + prg8_cd(m_reg[3]); +} + +WRITE8_MEMBER(nes_ks7032_device::ks7032_write) +{ + LOG_MMC(("ks7032_write, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x7000) + { + case 0x0000: + m_irq_count = (m_irq_count & 0xfff0) | (data & 0x0f); + break; + case 0x1000: + m_irq_count = (m_irq_count & 0xff0f) | ((data & 0x0f) << 4); + break; + case 0x2000: + m_irq_count = (m_irq_count & 0xf0ff) | ((data & 0x0f) << 8); + break; + case 0x3000: + m_irq_count = (m_irq_count & 0x0fff) | ((data & 0x0f) << 12); + break; + case 0x4000: + m_irq_enable = 1; + break; + case 0x6000: + m_latch = data & 0x07; + break; + case 0x7000: + m_reg[m_latch] = data; + prg_update(); + break; + } +} + +READ8_MEMBER(nes_ks7032_device::read_m) +{ + LOG_MMC(("ks7032 read_m, offset: %04x\n", offset)); + return m_prg[((m_reg[4] * 0x2000) + (offset & 0x1fff)) & (m_prg_size - 1)]; +} + +/*------------------------------------------------- + + Kaiser Board KS202 + + Games: Super Mario Bros. 3 (Pirate, Alt) + + iNES: + + In MESS: Supported? + + -------------------------------------------------*/ + + +WRITE8_MEMBER(nes_ks202_device::write_h) +{ + LOG_MMC(("ks202 write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x7000) + { + case 0x7000: + m_reg[m_latch] = data; + prg_update(); + switch (offset & 0xc00) + { + case 0x800: + set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_VERT : PPU_MIRROR_HORZ); + break; + case 0xc00: + chr1_x(offset & 0x07, data, CHRROM); + break; + } + break; + default: + ks7032_write(space, offset, data, mem_mask); + break; + } +} + +READ8_MEMBER(nes_ks202_device::read_m) +{ + LOG_MMC(("ks202 read_m, offset: %04x\n", offset)); + return m_prgram[offset & 0x1fff]; +} + +/*------------------------------------------------- + + Kaiser Board KS7017 + + Games: Almana no Kiseki FDS conversion + + iNES: + + In MESS: Supported. + + -------------------------------------------------*/ + +void nes_ks7017_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + if (id == TIMER_IRQ) + { + if (m_irq_enable) + { + if (!m_irq_count) + { + m_maincpu->set_input_line(M6502_IRQ_LINE, HOLD_LINE); + m_irq_enable = 0; + m_irq_status |= 0x01; + } + else + m_irq_count--; + } + } +} + +WRITE8_MEMBER(nes_ks7017_device::write_l) +{ + LOG_MMC(("ks7017 write_l, offset: %04x, data: %02x\n", offset, data)); + + offset += 0x100; + + if (offset >= 0xa00 && offset < 0xb00) + m_latch = ((offset >> 2) & 0x03) | ((offset >> 4) & 0x04); + + if (offset >= 0x1100 && offset < 0x1200) + prg16_89ab(m_latch); +} + +WRITE8_MEMBER(nes_ks7017_device::write_ex) +{ + LOG_MMC(("ks7017 write_ex, offset: %04x, data: %02x\n", offset, data)); + offset += 0x20; + + if (offset == 0x0020) // 0x4020 + m_irq_count = (m_irq_count & 0xff00) | data; + + if (offset == 0x0021) // 0x4021 + { + m_irq_count = (m_irq_count & 0x00ff) | (data << 8); + m_irq_enable = 1; + } + + if (offset == 0x0025) // 0x4025 + set_nt_mirroring(BIT(data, 3) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); +} + +READ8_MEMBER(nes_ks7017_device::read_ex) +{ + LOG_MMC(("ks7017 read_ex, offset: %04x\n", offset)); + offset += 0x20; + + if (offset == 0x0030) // 0x4030 + { + int temp = m_irq_status; + m_irq_status &= ~0x01; + return temp; + } + + return m_open_bus; // open bus +} + +/*------------------------------------------------- + + Kaiser Board KS7012 + + Games: Zanac FDS Conversion + + iNES: + + In MESS: Not working + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_ks7012_device::write_h) +{ + LOG_MMC(("ks7012 write_h, offset: %04x, data: %02x\n", offset, data)); + + if (offset == 0x60a0) + prg32(0); + if (offset == 0x6e36) + prg32(1); +} + + +/*------------------------------------------------- + + Kaiser Board KS7013B + + Games: Highway Star FDS Conversion + + iNES: + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_ks7013b_device::write_m) +{ + LOG_MMC(("ks7013b write_l, offset: %04x, data: %02x\n", offset, data)); + prg16_89ab(data); +} + +WRITE8_MEMBER(nes_ks7013b_device::write_h) +{ + LOG_MMC(("ks7013b write_h, offset: %04x, data: %02x\n", offset, data)); + set_nt_mirroring((data & 1) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); +} + + +/*------------------------------------------------- + + Kaiser Board KS7031 + + Games: Dracula II FDS Conversion + + This board is quite weird. It handles 2K PRG chunks + and the chip contains chunks in reverse order, so + that the first 2K are actually loaded at the top + of the 0x8000-0xffff region. Main bank is fixed, while + the 8K mapped at 0x6000-0x7fff varies with reg writes. + + TODO: understand how SRAM is handled... + + iNES: + + In MESS: Supported. + + -------------------------------------------------*/ + +READ8_MEMBER(nes_ks7031_device::read_m) +{ +// LOG_MMC(("ks7031 read_m, offset: %04x\n", offset)); + return m_prg[(m_reg[(offset >> 11) & 3] * 0x0800) + (offset & 0x7ff)]; +} + +READ8_MEMBER(nes_ks7031_device::read_h) +{ + // here the first 32K are accessed, but in 16x2K blocks loaded in reverse order + int accessed_2k = (offset >> 11) & 0x0f; + return m_prg[((0x0f - accessed_2k) * 0x0800) + (offset & 0x7ff)]; +} + +WRITE8_MEMBER(nes_ks7031_device::write_h) +{ + LOG_MMC(("ks7031 write_h, offset: %04x, data: %02x\n", offset, data)); + m_reg[(offset >> 11) & 3] = data & 0x3f; +} diff --git a/src/devices/bus/nes/kaiser.h b/src/devices/bus/nes/kaiser.h new file mode 100644 index 00000000000..b00f410ba05 --- /dev/null +++ b/src/devices/bus/nes/kaiser.h @@ -0,0 +1,184 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __NES_KAISER_H +#define __NES_KAISER_H + +#include "nxrom.h" + + +// ======================> nes_ks7058_device + +class nes_ks7058_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_ks7058_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); +}; + + +// ======================> nes_ks7022_device + +class nes_ks7022_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_ks7022_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_READ8_MEMBER(read_h); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); + +private: + UINT8 m_latch; +}; + + +// ======================> nes_ks7032_device + +class nes_ks7032_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_ks7032_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + nes_ks7032_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + virtual DECLARE_READ8_MEMBER(read_m); + virtual DECLARE_WRITE8_MEMBER(ks7032_write); + virtual DECLARE_WRITE8_MEMBER(write_h) { ks7032_write(space, offset, data, mem_mask); } + + virtual void pcb_reset(); + +protected: + void prg_update(); + + UINT8 m_latch; + UINT8 m_reg[8]; + + UINT16 m_irq_count; + int m_irq_enable; + + static const device_timer_id TIMER_IRQ = 0; + emu_timer *irq_timer; +}; + + +// ======================> nes_ks202_device + +class nes_ks202_device : public nes_ks7032_device +{ +public: + // construction/destruction + nes_ks202_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual DECLARE_READ8_MEMBER(read_m); + virtual DECLARE_WRITE8_MEMBER(write_h); +}; + + +// ======================> nes_ks7017_device + +class nes_ks7017_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_ks7017_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + virtual DECLARE_READ8_MEMBER(read_ex); + virtual DECLARE_WRITE8_MEMBER(write_ex); + virtual DECLARE_WRITE8_MEMBER(write_l); + + virtual void pcb_reset(); + +private: + UINT8 m_latch; + + UINT16 m_irq_count; + UINT8 m_irq_status; + int m_irq_enable; + + static const device_timer_id TIMER_IRQ = 0; + emu_timer *irq_timer; +}; + + +// ======================> nes_ks7012_device + +class nes_ks7012_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_ks7012_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); +}; + +// ======================> nes_ks7013b_device + +class nes_ks7013b_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_ks7013b_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_m); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); +}; + + +// ======================> nes_ks7031_device + +class nes_ks7031_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_ks7031_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_READ8_MEMBER(read_m); + virtual DECLARE_READ8_MEMBER(read_h); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); + +private: + UINT8 m_reg[4]; +}; + + + +// device type definition +extern const device_type NES_KS7058; +extern const device_type NES_KS7022; +extern const device_type NES_KS7032; +extern const device_type NES_KS202; +extern const device_type NES_KS7017; +extern const device_type NES_KS7012; +extern const device_type NES_KS7013B; +extern const device_type NES_KS7031; + +#endif diff --git a/src/devices/bus/nes/karastudio.c b/src/devices/bus/nes/karastudio.c new file mode 100644 index 00000000000..002bdf6eea3 --- /dev/null +++ b/src/devices/bus/nes/karastudio.c @@ -0,0 +1,309 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + NES/Famicom cartridge emulation for Bandai Karaoke Studio + + + Here we emulate the following PCBs Bandai Karaoke Studio [mapper 188] + + The Karaoke Studio cart consist of a large connector which fits the FC cart slot, with a microphone + connected. The game data is in the connector itself. The microphone has two buttons on it, and the + game uses these only to navigate through the menus (the two buttons are not read through the controller + port, which is not accessible from the cart, but from $6000-$7fff). Part of the connector body can be + removed to be replaced by an expansion cart containing new songs (we emulate this by adding a -cart2 slot). + + + TODO: + - verify expansion slot emulation for the Senyou Cassettes: + not much documentation exists about the expansion carts (except for few paragraphs + at Enri's FC webpage), so I implemented it based on "common sense" + * expansion carts do not contain the required game data => main PRG must be in the main cart + so to remain connected even when an expansion is inserted (differently from Datach, where + the base unit contains no PRG) + * bankswicth writes with bit3=0 (to access expansion) when no expansion is present should do + nothing + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "karastudio.h" + +#ifdef NES_PCB_DEBUG +#define VERBOSE 1 +#else +#define VERBOSE 0 +#endif + +#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) + + +//----------------------------------------- +// +// Karaoke Studio Cartslot implementation +// +//----------------------------------------- + +//------------------------------------------------- +// sub-cart interface +//------------------------------------------------- + +kstudio_cart_interface::kstudio_cart_interface(const machine_config &mconfig, device_t &device) + : device_slot_card_interface(mconfig, device), + m_rom(NULL) +{ +} + +kstudio_cart_interface::~kstudio_cart_interface() +{ +} + +READ8_MEMBER(kstudio_cart_interface::read) +{ + return m_rom[(m_bank * 0x4000) + (offset & 0x3fff)]; +} + +//------------------------------------------------- +// sub-cart slot device +//------------------------------------------------- + +const device_type NES_KSEXPANSION_SLOT = &device_creator; + +nes_kstudio_slot_device::nes_kstudio_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, NES_KSEXPANSION_SLOT, "NES Karaoke Studio Expansion Slot", tag, owner, clock, "nes_ks_slot", __FILE__), + device_image_interface(mconfig, *this), + device_slot_interface(mconfig, *this) +{ +} + +nes_kstudio_slot_device::~nes_kstudio_slot_device() +{ +} + + +void nes_kstudio_slot_device::device_start() +{ + m_cart = dynamic_cast(get_card_device()); +} + +READ8_MEMBER(nes_kstudio_slot_device::read) +{ + if (m_cart) + return m_cart->read(space, offset, mem_mask); + + return 0xff; +} + +bool nes_kstudio_slot_device::call_load() +{ + if (m_cart) + { + UINT8 *ROM = m_cart->get_cart_base(); + + if (!ROM) + return IMAGE_INIT_FAIL; + + // Existing exapnsion carts are all 128K, so we only load files of this size + if (software_entry() == NULL) + { + if (length() != 0x20000) + return IMAGE_INIT_FAIL; + + fread(&ROM, 0x20000); + } + else + { + if (get_software_region_length("rom") != 0x20000) + return IMAGE_INIT_FAIL; + + memcpy(ROM, get_software_region("rom"), 0x20000); + } + } + + return IMAGE_INIT_PASS; +} + + +bool nes_kstudio_slot_device::call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry) +{ + load_software_part_region(*this, swlist, swname, start_entry ); + return TRUE; +} + +void nes_kstudio_slot_device::get_default_card_software(std::string &result) +{ + software_get_default_slot(result, "ks_exp"); +} + + +//----------------------------------------------- +// +// Karaoke Studio Expansion cart implementation +// +//----------------------------------------------- + +ROM_START( ks_exp_rom ) + ROM_REGION(0x20000, "exrom", ROMREGION_ERASEFF) +ROM_END + +const device_type NES_KSEXPANSION_ROM = &device_creator; + +nes_kstudio_rom_device::nes_kstudio_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, NES_KSEXPANSION_ROM, "NES Karaoke Studio Expansion ROM", tag, owner, clock, "nes_ks_rom", __FILE__), + kstudio_cart_interface( mconfig, *this ) +{ +} + +void nes_kstudio_rom_device::device_start() +{ + m_rom = (UINT8*)memregion("exrom")->base(); + save_item(NAME(m_bank)); +} + +void nes_kstudio_rom_device::device_reset() +{ + m_bank = 0; +} + +const rom_entry *nes_kstudio_rom_device::device_rom_region() const +{ + return ROM_NAME( ks_exp_rom ); +} + +UINT8 *nes_kstudio_rom_device::get_cart_base() +{ + return m_rom; +} + + +//------------------------------------------ +// +// Karaoke Studio Base Cart implementation +// +//------------------------------------------ + +const device_type NES_KARAOKESTUDIO = &device_creator; + + +nes_karaokestudio_device::nes_karaokestudio_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_KARAOKESTUDIO, "NES Cart Bandai Karaoke Studio PCB", tag, owner, clock, "nes_karaoke", __FILE__), + m_subslot(*this, "exp_slot"), + m_mic_ipt(*this, "MIC") +{ +} + + +void nes_karaokestudio_device::device_start() +{ + common_start(); + save_item(NAME(m_exp_active)); +} + +void nes_karaokestudio_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef((m_prg_chunks - 1) ^ 0x08); + chr8(0, m_chr_source); + m_exp_active = 0; +} + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +/*------------------------------------------------- + + Bandai Karaoke Studio board emulation + + Games: Karaoke Studio + expansion carts with + additional songs + + Note: we currently do not emulate properly the + expansion slot + + iNES: mapper 188 + + -------------------------------------------------*/ + +READ8_MEMBER(nes_karaokestudio_device::read_m) +{ + LOG_MMC(("karaoke studio read_m, offset: %04x\n", offset)); + return m_mic_ipt->read(); +} + +READ8_MEMBER(nes_karaokestudio_device::read_h) +{ + LOG_MMC(("karaoke studio read_h, offset: %04x\n", offset)); + // this shall be the proper code, but it's a bit slower, so we access directly the subcart below + //return m_subslot->read(space, offset, mem_mask); + + // access expansion cart only if all of the followings are verified + // * we are in $8000-$bfff range + // * there has been a bankswitch write to map the expansion to such range + // * there actually is an expansion cart mounted + if (offset < 0x4000 && m_exp_active && m_subslot->m_cart) + return m_subslot->m_cart->read(space, offset, mem_mask); + else + return hi_access_rom(offset); +} + +WRITE8_MEMBER(nes_karaokestudio_device::write_h) +{ + LOG_MMC(("karaoke studio write_h, offset: %04x, data: %02x\n", offset, data)); + // bit3 1 = M ROM (main unit), 0=E ROM (expansion) + // HACK(?): currently it is not clear how the unit acknowledges the presence of the expansion + // cart (when expansion is present, code keeps switching both from the expansion rom and from + // the main ROM) + // my guess is that writes with bit3=0 and no expansion just do nothing, but it shall be verified + + if (offset >= 04000) + { + if (BIT(data, 3)) + { + m_exp_active = 0; + prg16_89ab(data & 7); + } + else // expansion cart + { + m_exp_active = 1; + m_subslot->write_prg_bank(data & 7); + } + } +} + + +static INPUT_PORTS_START( karaoke_mic ) + PORT_START("MIC") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_NAME("A (Mic Select)") PORT_CODE(KEYCODE_X) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("B (Mic Start)") PORT_CODE(KEYCODE_Z) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_BUTTON3 ) PORT_NAME("Microphone (?)") PORT_CODE(KEYCODE_C) + PORT_BIT( 0xf8, IP_ACTIVE_HIGH, IPT_UNUSED ) +INPUT_PORTS_END + +ioport_constructor nes_karaokestudio_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( karaoke_mic ); +} + + +//------------------------------------------------- +// CART SLOT +//------------------------------------------------- + +static SLOT_INTERFACE_START(karaoke_studio_cart) + SLOT_INTERFACE_INTERNAL("ks_exp", NES_KSEXPANSION_ROM) +SLOT_INTERFACE_END + + +MACHINE_CONFIG_FRAGMENT( karaoke_studio ) + MCFG_KSTUDIO_MINICART_ADD("exp_slot", karaoke_studio_cart) +MACHINE_CONFIG_END + +machine_config_constructor nes_karaokestudio_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( karaoke_studio ); +} diff --git a/src/devices/bus/nes/karastudio.h b/src/devices/bus/nes/karastudio.h new file mode 100644 index 00000000000..b0b671e0034 --- /dev/null +++ b/src/devices/bus/nes/karastudio.h @@ -0,0 +1,147 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __NES_KARASTUDIO_H +#define __NES_KARASTUDIO_H + +#include "nxrom.h" + + +//----------------------------------------- +// +// Karaoke Studio Cartslot implementation +// +//----------------------------------------- + +// ======================> kstudio_cart_interface + +class kstudio_cart_interface : public device_slot_card_interface +{ +public: + // construction/destruction + kstudio_cart_interface(const machine_config &mconfig, device_t &device); + virtual ~kstudio_cart_interface(); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read); + + UINT8 *get_cart_base() { return m_rom; } + void write_prg_bank(UINT8 bank) { m_bank = bank; } + +protected: + // internal state + UINT8 *m_rom; + // ROM is accessed via two 16K banks, but only the first one can be switched + UINT8 m_bank; +}; + +// ======================> nes_kstudio_slot_device + +class nes_kstudio_slot_device : public device_t, + public device_image_interface, + public device_slot_interface +{ +public: + // construction/destruction + nes_kstudio_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual ~nes_kstudio_slot_device(); + + // device-level overrides + virtual void device_start(); + virtual void device_config_complete() { update_names(); } + + // image-level overrides + virtual bool call_load(); + virtual bool call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry); + + virtual iodevice_t image_type() const { return IO_CARTSLOT; } + virtual bool is_readable() const { return 1; } + virtual bool is_writeable() const { return 0; } + virtual bool is_creatable() const { return 0; } + virtual bool must_be_loaded() const { return 0; } + virtual bool is_reset_on_load() const { return 1; } + virtual const char *image_interface() const { return "ks_cart"; } + virtual const char *file_extensions() const { return "bin"; } + virtual const option_guide *create_option_guide() const { return NULL; } + + // slot interface overrides + virtual void get_default_card_software(std::string &result); + + virtual DECLARE_READ8_MEMBER(read); + void write_prg_bank(UINT8 bank) { if (m_cart) m_cart->write_prg_bank(bank); } + + kstudio_cart_interface* m_cart; +}; + +// device type definition +extern const device_type NES_KSEXPANSION_SLOT; + + +#define MCFG_KSTUDIO_MINICART_ADD(_tag, _slot_intf) \ + MCFG_DEVICE_ADD(_tag, NES_KSEXPANSION_SLOT, 0) \ +MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, NULL, false) + + +//----------------------------------------------- +// +// Karaoke Studio Expansion cart implementation +// +//----------------------------------------------- + +// ======================> nes_kstudio_rom_device + +class nes_kstudio_rom_device : public device_t, + public kstudio_cart_interface +{ +public: + // construction/destruction + nes_kstudio_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual UINT8* get_cart_base(); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); +}; + +// device type definition +extern const device_type NES_KSEXPANSION_ROM; + + +//------------------------------------------- +// +// Karaoke Studio Base Cart implementation +// +//------------------------------------------- + +// ======================> nes_karaokestudio_device + +class nes_karaokestudio_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_karaokestudio_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual ioport_constructor device_input_ports() const; + virtual machine_config_constructor device_mconfig_additions() const; + virtual DECLARE_READ8_MEMBER(read_m); + virtual DECLARE_READ8_MEMBER(read_h); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); + +protected: + int m_exp_active; + required_device m_subslot; + required_ioport m_mic_ipt; +}; + + +// device type definition +extern const device_type NES_KARAOKESTUDIO; + +#endif diff --git a/src/devices/bus/nes/konami.c b/src/devices/bus/nes/konami.c new file mode 100644 index 00000000000..4cd4f1fd872 --- /dev/null +++ b/src/devices/bus/nes/konami.c @@ -0,0 +1,787 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + NES/Famicom cartridge emulation for Konami PCBs + + + Here we emulate the following PCBs (multiple mappers needed due to different wirings in the pcbs + causing different addresses to be used for bankswitch & irq) + + * Konami VRC-1 [mapper 75] + * Konami VRC-2 [mapper 22,23,25] + * Konami VRC-3 [mapper 73] + * Konami VRC-4 [mapper 21,23,25] + * Konami VRC-6 [mapper 24,26] + * Konami VRC-7 [mapper 85] + + + TODO: + - improve IRQ (CPU mode not currently emulated) + - add VRC-6 sound features + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "konami.h" + +#include "cpu/m6502/m6502.h" + +#ifdef NES_PCB_DEBUG +#define VERBOSE 1 +#else +#define VERBOSE 0 +#endif + +#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) + +#define N2A03_DEFAULTCLOCK (21477272.724 / 12) + +//------------------------------------------------- +// constructor +//------------------------------------------------- + +const device_type NES_VRC1 = &device_creator; +const device_type NES_VRC2 = &device_creator; +const device_type NES_VRC3 = &device_creator; +const device_type NES_VRC4 = &device_creator; +const device_type NES_VRC6 = &device_creator; +const device_type NES_VRC7 = &device_creator; + + +nes_konami_vrc1_device::nes_konami_vrc1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_VRC1, "NES Cart Konami VRC-1 PCB", tag, owner, clock, "nes_vrc1", __FILE__) +{ +} + +nes_konami_vrc2_device::nes_konami_vrc2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_VRC2, "NES Cart Konami VRC-2 PCB", tag, owner, clock, "nes_vrc2", __FILE__) +{ +} + +nes_konami_vrc3_device::nes_konami_vrc3_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_VRC3, "NES Cart Konami VRC-3 PCB", tag, owner, clock, "nes_vrc3", __FILE__) +{ +} + +nes_konami_vrc4_device::nes_konami_vrc4_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : nes_nrom_device(mconfig, type, name, tag, owner, clock, shortname, source) +{ +} + +nes_konami_vrc4_device::nes_konami_vrc4_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_VRC4, "NES Cart Konami VRC-4 PCB", tag, owner, clock, "nes_vrc4", __FILE__) +{ +} + +nes_konami_vrc6_device::nes_konami_vrc6_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_konami_vrc4_device(mconfig, NES_VRC6, "NES Cart Konami VRC-6 PCB", tag, owner, clock, "nes_vrc6", __FILE__), + m_vrc6snd(*this, "vrc6snd") +{ +} + +nes_konami_vrc7_device::nes_konami_vrc7_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_konami_vrc4_device(mconfig, NES_VRC7, "NES Cart Konami VRC-7 PCB", tag, owner, clock, "nes_vrc7", __FILE__), + m_ym2413(*this, "ym") +{ +} + + + +void nes_konami_vrc1_device::device_start() +{ + common_start(); + save_item(NAME(m_mmc_vrom_bank)); +} + +void nes_konami_vrc1_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); + + memset(m_mmc_vrom_bank, 0, sizeof(m_mmc_vrom_bank)); +} + +void nes_konami_vrc2_device::device_start() +{ + common_start(); + save_item(NAME(m_mmc_vrom_bank)); + save_item(NAME(m_latch)); +} + +void nes_konami_vrc2_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); + + m_latch = 0; + memset(m_mmc_vrom_bank, 0, sizeof(m_mmc_vrom_bank)); +} + +void nes_konami_vrc3_device::device_start() +{ + common_start(); + irq_timer = timer_alloc(TIMER_IRQ); + irq_timer->adjust(attotime::zero, 0, machine().device("maincpu")->cycles_to_attotime(1)); + + save_item(NAME(m_irq_mode)); + save_item(NAME(m_irq_enable)); + save_item(NAME(m_irq_enable_latch)); + save_item(NAME(m_irq_count)); + save_item(NAME(m_irq_count_latch)); +} + +void nes_konami_vrc3_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); + + m_irq_mode = 0; + m_irq_enable = 0; + m_irq_enable_latch = 0; + m_irq_count = 0; + m_irq_count_latch = 0; +} + + +void nes_konami_vrc4_device::device_start() +{ + common_start(); + irq_timer = timer_alloc(TIMER_IRQ); + irq_timer->adjust(attotime::zero, 0, machine().device("maincpu")->cycles_to_attotime(1)); + + save_item(NAME(m_irq_mode)); + save_item(NAME(m_irq_prescale)); + save_item(NAME(m_irq_enable)); + save_item(NAME(m_irq_enable_latch)); + save_item(NAME(m_irq_count)); + save_item(NAME(m_irq_count_latch)); + save_item(NAME(m_latch)); + save_item(NAME(m_mmc_prg_bank)); + save_item(NAME(m_mmc_vrom_bank)); +} + +void nes_konami_vrc4_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); + + m_irq_mode = 0; + m_irq_prescale = 341; + m_irq_enable = 0; + m_irq_enable_latch = 0; + m_irq_count = 0; + m_irq_count_latch = 0; + + m_latch = 0; + m_mmc_prg_bank = 0; + memset(m_mmc_vrom_bank, 0, sizeof(m_mmc_vrom_bank)); +} + +void nes_konami_vrc6_device::device_start() +{ + nes_konami_vrc4_device::device_start(); +} + +void nes_konami_vrc7_device::device_start() +{ + common_start(); + irq_timer = timer_alloc(TIMER_IRQ); + irq_timer->adjust(attotime::zero, 0, machine().device("maincpu")->cycles_to_attotime(1)); + + save_item(NAME(m_irq_mode)); + save_item(NAME(m_irq_prescale)); + save_item(NAME(m_irq_enable)); + save_item(NAME(m_irq_enable_latch)); + save_item(NAME(m_irq_count)); + save_item(NAME(m_irq_count_latch)); +} + +void nes_konami_vrc7_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg8_89(0); + prg8_ab(0); + prg8_cd(0); + prg8_ef(0xff); + chr8(0, m_chr_source); + + m_irq_mode = 0; + m_irq_prescale = 341; + m_irq_enable = 0; + m_irq_enable_latch = 0; + m_irq_count = 0; + m_irq_count_latch = 0; +} + + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +/*------------------------------------------------- + + Konami VRC1 and Jaleco JF20, JF22 + + Games: Exciting Boxing, Ganbare Goemon!, Tetsuwan Atom + + iNES: mapper 75 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_konami_vrc1_device::write_h) +{ + LOG_MMC(("VRC-1 write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x7000) + { + case 0x0000: + prg8_89(data); + break; + case 0x2000: + prg8_ab(data); + break; + case 0x4000: + prg8_cd(data); + break; + case 0x1000: + set_nt_mirroring((data & 0x01) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + m_mmc_vrom_bank[0] = (m_mmc_vrom_bank[0] & 0x0f) | ((data & 0x02) << 3); + m_mmc_vrom_bank[1] = (m_mmc_vrom_bank[1] & 0x0f) | ((data & 0x04) << 2); + chr4_0(m_mmc_vrom_bank[0], CHRROM); + chr4_4(m_mmc_vrom_bank[1], CHRROM); + break; + case 0x6000: + m_mmc_vrom_bank[0] = (m_mmc_vrom_bank[0] & 0x10) | (data & 0x0f); + chr4_0(m_mmc_vrom_bank[0], CHRROM); + break; + case 0x7000: + m_mmc_vrom_bank[1] = (m_mmc_vrom_bank[1] & 0x10) | (data & 0x0f); + chr4_4(m_mmc_vrom_bank[1], CHRROM); + break; + } +} + +/*------------------------------------------------- + + Konami VRC-2 + + In MESS: Supported. + + -------------------------------------------------*/ + +READ8_MEMBER(nes_konami_vrc2_device::read_m) +{ + LOG_MMC(("VRC-2 read_m, offset: %04x\n", offset)); + + if (!m_battery.empty()) + return m_battery[offset & (m_battery.size() - 1)]; + else if (!m_prgram.empty()) + return m_prgram[offset & (m_prgram.size() - 1)]; + else // sort of protection? it returns open bus in $7000-$7fff and (open bus & 0xfe) | m_latch in $6000-$6fff + return (offset < 0x1000) ? ((m_open_bus & 0xfe) | (m_latch & 1)) : m_open_bus; +} + +WRITE8_MEMBER(nes_konami_vrc2_device::write_m) +{ + LOG_MMC(("VRC-2 write_m, offset: %04x, data: %02x\n", offset, data)); + + if (!m_battery.empty()) + m_battery[offset & (m_battery.size() - 1)] = data; + else if (!m_prgram.empty()) + m_prgram[offset & (m_prgram.size() - 1)] = data; + else if (offset < 0x1000) + m_latch = data; +} + +WRITE8_MEMBER(nes_konami_vrc2_device::write_h) +{ + UINT8 bank, shift, mask; + UINT16 add_lines = ((offset << (9 - m_vrc_ls_prg_a)) & 0x200) | ((offset << (8 - m_vrc_ls_prg_b)) & 0x100); + LOG_MMC(("VRC-2 write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x7000) + { + case 0x0000: + prg8_89(data); + break; + case 0x2000: + prg8_ab(data); + break; + case 0x1000: + switch (data & 0x03) + { + case 0x00: set_nt_mirroring(PPU_MIRROR_VERT); break; + case 0x01: set_nt_mirroring(PPU_MIRROR_HORZ); break; + case 0x02: set_nt_mirroring(PPU_MIRROR_LOW); break; + case 0x03: set_nt_mirroring(PPU_MIRROR_HIGH); break; + } + break; + case 0x3000: + case 0x4000: + case 0x5000: + case 0x6000: + bank = ((offset & 0x7000) - 0x3000) / 0x0800 + BIT(add_lines, 9); + shift = BIT(add_lines, 8) * 4; + mask = (0xf0 >> shift); + m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & mask) | (((data >> m_vrc_ls_chr) & 0x0f) << shift); + chr1_x(bank, m_mmc_vrom_bank[bank], CHRROM); + break; + default: + logerror("VRC-2 write_h uncaught write, addr: %04x value: %02x\n", offset + 0x8000, data); + break; + } +} + +/*------------------------------------------------- + + Konami VRC3 + + Games: Salamander + + iNES: mapper 73 + + In MESS: Supported. + + -------------------------------------------------*/ + +void nes_konami_vrc3_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + if (id == TIMER_IRQ) + { + if (m_irq_enable) + { + if (m_irq_mode) // 8bits mode + { + if ((m_irq_count & 0x00ff) == 0xff) + { + m_maincpu->set_input_line(M6502_IRQ_LINE, ASSERT_LINE); + m_irq_count = m_irq_count_latch; + } + else + m_irq_count = (m_irq_count & 0xff00) | ((m_irq_count & 0x00ff) + 1); + } + else // 16bits mode + { + if (m_irq_count == 0xffff) + { + m_maincpu->set_input_line(M6502_IRQ_LINE, ASSERT_LINE); + m_irq_count = m_irq_count_latch; + } + else + m_irq_count++; + } + } + } +} + +WRITE8_MEMBER(nes_konami_vrc3_device::write_h) +{ + LOG_MMC(("VRC-3 write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x7000) + { + case 0x0000: + m_irq_count_latch = (m_irq_count_latch & 0xfff0) | ((data & 0x0f) << 0); + break; + case 0x1000: + m_irq_count_latch = (m_irq_count_latch & 0xff0f) | ((data & 0x0f) << 4); + break; + case 0x2000: + m_irq_count_latch = (m_irq_count_latch & 0xf0ff) | ((data & 0x0f) << 8); + break; + case 0x3000: + m_irq_count_latch = (m_irq_count_latch & 0x0fff) | ((data & 0x0f) << 12); + break; + case 0x4000: + m_irq_mode = data & 0x04; + m_irq_enable = data & 0x02; + m_irq_enable_latch = data & 0x01; + if (data & 0x02) + m_irq_count = m_irq_count_latch; + m_maincpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE); + break; + case 0x5000: + m_irq_enable = m_irq_enable_latch; + m_maincpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE); + break; + case 0x7000: + prg16_89ab(data); + break; + default: + logerror("VRC-3 write_h uncaught write, offset %04x, data: %02x\n", offset, data); + break; + } +} + +/*------------------------------------------------- + + Konami VRC-4 + + In MESS: Supported + + -------------------------------------------------*/ + +void nes_konami_vrc4_device::irq_tick() +{ + if (m_irq_count == 0xff) + { + m_irq_count = m_irq_count_latch; + m_maincpu->set_input_line(M6502_IRQ_LINE, ASSERT_LINE); + } + else + m_irq_count++; +} + +void nes_konami_vrc4_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + if (id == TIMER_IRQ) + { + if (m_irq_enable) + { + if (m_irq_mode) // cycle mode + irq_tick(); + else // scanline mode + { + // A prescaler divides the passing CPU cycles by 114, 114, then 113 (and repeats that order). + // This approximates 113+2/3 CPU cycles, which is one NTSC scanline. + // Since this is a CPU-based IRQ, though, it is triggered also during non visible scanlines... + if (m_irq_prescale < 3) + { + m_irq_prescale += 341; + irq_tick(); + } + + m_irq_prescale -= 3; + } + } + } +} + +void nes_konami_vrc4_device::set_prg() +{ + if (m_latch & 0x02) + { + prg8_89(0xfe); + prg8_cd(m_mmc_prg_bank); + } + else + { + prg8_89(m_mmc_prg_bank); + prg8_cd(0xfe); + } +} + +WRITE8_MEMBER(nes_konami_vrc4_device::write_h) +{ + UINT8 bank, shift, mask; + UINT16 add_lines = ((offset << (9 - m_vrc_ls_prg_a)) & 0x200) | ((offset << (8 - m_vrc_ls_prg_b)) & 0x100); + LOG_MMC(("VRC-4 write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x7000) + { + case 0x0000: + m_mmc_prg_bank = data; + set_prg(); + break; + case 0x2000: + prg8_ab(data); + break; + case 0x1000: + if (add_lines & 0x200) + { + m_latch = data & 0x02; + set_prg(); + } + else + { + switch (data & 0x03) + { + case 0x00: set_nt_mirroring(PPU_MIRROR_VERT); break; + case 0x01: set_nt_mirroring(PPU_MIRROR_HORZ); break; + case 0x02: set_nt_mirroring(PPU_MIRROR_LOW); break; + case 0x03: set_nt_mirroring(PPU_MIRROR_HIGH); break; + } + } + break; + case 0x3000: + case 0x4000: + case 0x5000: + case 0x6000: + bank = ((offset & 0x7000) - 0x3000) / 0x0800 + BIT(add_lines, 9); + shift = BIT(add_lines, 8) * 4; + mask = (0xf0 >> shift); + m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & mask) | ((data & 0x0f) << shift); + chr1_x(bank, m_mmc_vrom_bank[bank], CHRROM); + break; + case 0x7000: + switch (add_lines) + { + case 0x000: + m_irq_count_latch = (m_irq_count_latch & 0xf0) | (data & 0x0f); + break; + case 0x100: + m_irq_count_latch = (m_irq_count_latch & 0x0f) | ((data & 0x0f) << 4); + break; + case 0x200: + m_irq_mode = data & 0x04; + m_irq_enable = data & 0x02; + m_irq_enable_latch = data & 0x01; + if (data & 0x02) + m_irq_count = m_irq_count_latch; + m_maincpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE); + break; + case 0x300: + m_irq_enable = m_irq_enable_latch; + m_maincpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE); + break; + } + break; + default: + logerror("VRC-4 write_h uncaught write, addr: %04x value: %02x\n", ((offset & 0x7000) | add_lines) + 0x8000, data); + break; + } +} + +/*------------------------------------------------- + + Konami VRC-6 + + In MESS: Supported. It also uses konami_irq (there are IRQ + issues though: see Akumajou Densetsu intro). + + TODO: Add sound capabilities support! + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_konami_vrc6_device::write_h) +{ + UINT8 bank; + UINT16 add_lines = ((offset << (9 - m_vrc_ls_prg_a)) & 0x200) | ((offset << (8 - m_vrc_ls_prg_b)) & 0x100); + LOG_MMC(("VRC-6 write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x7000) + { + case 0x0000: + prg16_89ab(data); + break; + case 0x4000: + prg8_cd(data); + break; + case 0x1000: // pulse 1 & global control + m_vrc6snd->write(space, add_lines>>8, data); + break; + case 0x2000: // pulse 2 + m_vrc6snd->write(space, (add_lines>>8) | 0x100, data); + break; + case 0x3000: + if (add_lines == 0x300) + { + switch (data & 0x0c) + { + case 0x00: set_nt_mirroring(PPU_MIRROR_VERT); break; + case 0x04: set_nt_mirroring(PPU_MIRROR_HORZ); break; + case 0x08: set_nt_mirroring(PPU_MIRROR_LOW); break; + case 0x0c: set_nt_mirroring(PPU_MIRROR_HIGH); break; + } + } + else // saw + m_vrc6snd->write(space, (add_lines>>8) | 0x200, data); + break; + case 0x5000: + case 0x6000: + bank = ((offset & 0x7000) - 0x5000) / 0x0400 + ((add_lines & 0x0300) >> 8); + chr1_x(bank, data, CHRROM); + break; + case 0x7000: + switch (add_lines) + { + case 0x000: + m_irq_count_latch = data; + break; + case 0x100: + m_irq_mode = data & 0x04; + m_irq_enable = data & 0x02; + m_irq_enable_latch = data & 0x01; + if (data & 0x02) + m_irq_count = m_irq_count_latch; + m_maincpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE); + break; + case 0x200: + m_irq_enable = m_irq_enable_latch; + m_maincpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE); + break; + default: + logerror("VRC-6 write_h uncaught write, addr: %04x value: %02x\n", ((offset & 0x7000) | add_lines) + 0x8000, data); + break; + } + break; + default: + logerror("VRC-6 write_h uncaught write, addr: %04x value: %02x\n", ((offset & 0x7000) | add_lines) + 0x8000, data); + break; + } +} + +static MACHINE_CONFIG_FRAGMENT( vrc6 ) + + // additional sound hardware + MCFG_SPEAKER_STANDARD_MONO("addon") + + MCFG_SOUND_ADD("vrc6snd", VRC6, N2A03_DEFAULTCLOCK) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "addon", 0.5) +MACHINE_CONFIG_END + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor nes_konami_vrc6_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( vrc6 ); +} + +/*------------------------------------------------- + + Konami VRC7 + + Games: Lagrange Point, Tiny Toon Adventures 2 + + iNES: mapper 85 + + In MESS: Supported. It also uses konami_irq. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_konami_vrc7_device::write_h) +{ + UINT8 bank; + LOG_MMC(("VRC-7 write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x7038) + { + case 0x0000: + prg8_89(data); + break; + case 0x0008: + case 0x0010: + case 0x0018: + prg8_ab(data); + break; + + case 0x1000: + prg8_cd(data); + break; + + case 0x1010: + case 0x1018: + m_ym2413->register_port_w(space, 0, data); + break; + case 0x1030: + case 0x1038: + m_ym2413->data_port_w(space, 0, data); + break; + + case 0x2000: + case 0x2008: + case 0x2010: + case 0x2018: + case 0x3000: + case 0x3008: + case 0x3010: + case 0x3018: + case 0x4000: + case 0x4008: + case 0x4010: + case 0x4018: + case 0x5000: + case 0x5008: + case 0x5010: + case 0x5018: + bank = ((offset & 0x7000) - 0x2000) / 0x0800 + ((offset & 0x0018) ? 1 : 0); + chr1_x(bank, data, m_chr_source); + break; + + case 0x6000: + switch (data & 0x03) + { + case 0x00: set_nt_mirroring(PPU_MIRROR_VERT); break; + case 0x01: set_nt_mirroring(PPU_MIRROR_HORZ); break; + case 0x02: set_nt_mirroring(PPU_MIRROR_LOW); break; + case 0x03: set_nt_mirroring(PPU_MIRROR_HIGH); break; + } + break; + case 0x6008: case 0x6010: case 0x6018: + m_irq_count_latch = data; + break; + case 0x7000: + m_irq_mode = data & 0x04; + m_irq_enable = data & 0x02; + m_irq_enable_latch = data & 0x01; + if (data & 0x02) + m_irq_count = m_irq_count_latch; + m_maincpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE); + break; + case 0x7008: case 0x7010: case 0x7018: + m_irq_enable = m_irq_enable_latch; + m_maincpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE); + break; + + default: + logerror("VRC-7 write_h uncaught write, addr: %04x value: %02x\n", offset + 0x8000, data); + break; + } +} + + +//------------------------------------------------- +// MACHINE_DRIVER( vrc7 ) +//------------------------------------------------- + +// From NESdev wiki: The VRC7, in addition to being a mapper chip, also produces 6 channels of +// 2-operator FM Synthesis Audio. It is a derivative of the Yamaha YM2413 OPLL, implementing a +// subset of its features and containing a custom fixed patch set. +// The synthesis core is related to the Yamaha YM2413 OPLL: +// - Register layout is the same. +// - VRC7 has 6 channels, OPLL has 9. +// - VRC7 has no rhythm channels, OPLL does (the last 3 channels are either FM or Rhythm on OPLL). +// - VRC7 built-in instruments are not the same as OPLL instruments. +// - VRC7 has no readily-accessible status register, under normal circumstances it is write-only; +// OPLL has an undocumented, 2-bit 'internal state' register. +// - VRC7 has an internal state output pin (may be serial version of the 2 bit internal state register) +// and has one output pin for audio, multiplexed for all 6 channels; OPLL has two output pins, one for +// FM and one for Rhythm, and has no special status pin. + +// FIXME: we currently emulate this as a base YM2413! + +static MACHINE_CONFIG_FRAGMENT( vrc7 ) + + // additional sound hardware + MCFG_SPEAKER_STANDARD_MONO("addon") + + MCFG_SOUND_ADD("ym", YM2413, N2A03_DEFAULTCLOCK) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "addon", 0.5) +MACHINE_CONFIG_END + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor nes_konami_vrc7_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( vrc7 ); +} diff --git a/src/devices/bus/nes/konami.h b/src/devices/bus/nes/konami.h new file mode 100644 index 00000000000..0ecece270fd --- /dev/null +++ b/src/devices/bus/nes/konami.h @@ -0,0 +1,155 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __NES_KONAMI_H +#define __NES_KONAMI_H + +#include "nxrom.h" +#include "sound/vrc6.h" +#include "sound/2413intf.h" + + +// ======================> nes_konami_vrc1_device + +class nes_konami_vrc1_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_konami_vrc1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); + +private: + UINT8 m_mmc_vrom_bank[2]; +}; + + +// ======================> nes_konami_vrc2_device + +class nes_konami_vrc2_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_konami_vrc2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_READ8_MEMBER(read_m); + virtual DECLARE_WRITE8_MEMBER(write_m); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); + +private: + UINT8 m_mmc_vrom_bank[8]; + UINT8 m_latch; +}; + + +// ======================> nes_konami_vrc3_device + +class nes_konami_vrc3_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_konami_vrc3_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); + +private: + UINT16 m_irq_count, m_irq_count_latch; + int m_irq_enable, m_irq_enable_latch; + int m_irq_mode; + + static const device_timer_id TIMER_IRQ = 0; + emu_timer *irq_timer; +}; + + +// ======================> nes_konami_vrc4_device + +class nes_konami_vrc4_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_konami_vrc4_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + nes_konami_vrc4_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); + +protected: + void set_prg(); + UINT8 m_mmc_vrom_bank[8]; + UINT8 m_latch, m_mmc_prg_bank; + + void irq_tick(); + UINT16 m_irq_count, m_irq_count_latch; + int m_irq_enable, m_irq_enable_latch; + int m_irq_mode; + int m_irq_prescale; + + static const device_timer_id TIMER_IRQ = 0; + emu_timer *irq_timer; +}; + + +// ======================> nes_konami_vrc6_device + +class nes_konami_vrc6_device : public nes_konami_vrc4_device +{ +public: + // construction/destruction + nes_konami_vrc6_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual machine_config_constructor device_mconfig_additions() const; + virtual DECLARE_WRITE8_MEMBER(write_h); + + required_device m_vrc6snd; +}; + + +// ======================> nes_konami_vrc7_device + +class nes_konami_vrc7_device : public nes_konami_vrc4_device +{ +public: + // construction/destruction + nes_konami_vrc7_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual machine_config_constructor device_mconfig_additions() const; + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); + +private: + required_device m_ym2413; +}; + + + +// device type definition +extern const device_type NES_VRC1; +extern const device_type NES_VRC2; +extern const device_type NES_VRC3; +extern const device_type NES_VRC4; +extern const device_type NES_VRC6; +extern const device_type NES_VRC7; + +#endif diff --git a/src/devices/bus/nes/legacy.c b/src/devices/bus/nes/legacy.c new file mode 100644 index 00000000000..3a452fd2f39 --- /dev/null +++ b/src/devices/bus/nes/legacy.c @@ -0,0 +1,311 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + NES/Famicom cartridge emulation for FFE PCBs + + + Here we emulate the mappers used by available Far Front East copier hacked games [mappers 6, 8, 17] + + TODO: + - investigate IRQ mechanism (current code is broken) + - replace this with proper copier emulation, using disk images... + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "legacy.h" + +#include "cpu/m6502/m6502.h" + + +#ifdef NES_PCB_DEBUG +#define VERBOSE 1 +#else +#define VERBOSE 0 +#endif + +#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) + + +//------------------------------------------------- +// constructor +//------------------------------------------------- + +const device_type NES_FFE3 = &device_creator; +const device_type NES_FFE4 = &device_creator; +const device_type NES_FFE8 = &device_creator; + + +nes_ffe3_device::nes_ffe3_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_FFE3, "NES Cart FFE-3 PCB", tag, owner, clock, "nes_ff3", __FILE__) +{ +} + +nes_ffe4_device::nes_ffe4_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : nes_nrom_device(mconfig, type, name, tag, owner, clock, shortname, source) +{ +} + +nes_ffe4_device::nes_ffe4_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_FFE4, "NES Cart FFE-4 PCB", tag, owner, clock, "nes_ff4", __FILE__) +{ +} + +nes_ffe8_device::nes_ffe8_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_ffe4_device(mconfig, NES_FFE8, "NES Cart FFE-8 PCB", tag, owner, clock, "nes_ff8", __FILE__) +{ +} + + + +void nes_ffe3_device::device_start() +{ + common_start(); +} + +void nes_ffe3_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); +} + + +void nes_ffe4_device::device_start() +{ + common_start(); + irq_timer = timer_alloc(TIMER_IRQ); + irq_timer->adjust(attotime::zero, 0, machine().device("maincpu")->cycles_to_attotime(1)); + + save_item(NAME(m_exram)); + save_item(NAME(m_exram_enabled)); + save_item(NAME(m_exram_bank)); + + save_item(NAME(m_irq_enable)); + save_item(NAME(m_irq_count)); + save_item(NAME(m_latch)); +} + +void nes_ffe4_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(7); + chr8(0, m_chr_source); + + m_exram_enabled = 0; + m_exram_bank = 0; + + m_latch = 0; + m_irq_enable = 0; + m_irq_count = 0; +} + + +void nes_ffe8_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(0xff); + chr8(0, m_chr_source); + + // extra vram is not used by this board, so these will remain always zero + m_exram_enabled = 0; + m_exram_bank = 0; + + m_latch = 0; + m_irq_enable = 0; + m_irq_count = 0; +} + + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +/*------------------------------------------------- + + Mapper 8 + + Known Boards: FFE3 Copier Board + Games: Hacked versions of games + + In MESS: Supported? (I have no games to test this) + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_ffe3_device::write_h) +{ + LOG_MMC(("mapper8 write_h, offset: %04x, data: %02x\n", offset, data)); + + chr8(data & 0x07, CHRROM); + prg16_89ab(data >> 3); +} + +/*------------------------------------------------- + + Mapper 6 + + Known Boards: FFE4 Copier Board + Games: Hacked versions of games + + In MESS: Supported? Not sure if we could also have ExRAM or not... + However, priority is pretty low for this mapper. + + -------------------------------------------------*/ + +void nes_ffe4_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + if (id == TIMER_IRQ) + { + if (m_irq_enable) + { + if (m_irq_count == 0xffff) + { + m_maincpu->set_input_line(M6502_IRQ_LINE, ASSERT_LINE); + m_irq_count = 0; + m_irq_enable = 0; + } + else + m_irq_count++; + } + } +} + +WRITE8_MEMBER(nes_ffe4_device::write_l) +{ + LOG_MMC(("mapper6 write_l, offset: %04x, data: %02x\n", offset, data)); + + switch (offset) + { + case 0x1fe: + m_latch = data & 0x80; + set_nt_mirroring(BIT(data, 4) ? PPU_MIRROR_HIGH : PPU_MIRROR_LOW); + break; + case 0x1ff: + set_nt_mirroring(BIT(data, 4) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + break; + + case 0x401: + m_irq_enable = 0; + m_maincpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE); + break; + case 0x402: + m_irq_count = (m_irq_count & 0xff00) | data; + break; + case 0x403: + m_irq_enable = 1; + m_irq_count = (m_irq_count & 0x00ff) | (data << 8); + break; + } +} + +WRITE8_MEMBER(nes_ffe4_device::chr_w) +{ + int bank = offset >> 10; + if (m_exram_enabled) + m_exram[(m_exram_bank * 0x2000) + (bank * 0x400) + (offset & 0x3ff)] = data; + + if (m_chr_src[bank] == CHRRAM) + m_chr_access[bank][offset & 0x3ff] = data; +} + +READ8_MEMBER(nes_ffe4_device::chr_r) +{ + int bank = offset >> 10; + if (m_exram_enabled) + return m_exram[(m_exram_bank * 0x2000) + (bank * 0x400) + (offset & 0x3ff)]; + + return m_chr_access[bank][offset & 0x3ff]; +} + + +WRITE8_MEMBER(nes_ffe4_device::write_h) +{ + LOG_MMC(("mapper6 write_h, offset: %04x, data: %02x\n", offset, data)); + + if (!m_latch) // when in "FFE mode" we are forced to use CHRRAM/EXRAM bank? + { + prg16_89ab(data >> 2); + + // This part is not fully documented, so we proceed a bit blindly... + if ((data & 0x03) == 0) + { + m_exram_enabled = 0; + chr8(0, CHRRAM); + } + else + { + m_exram_enabled = 1; + m_exram_bank = data & 0x03; + } + } + else // otherwise, we use CHRROM (shall we check if it's present?) + chr8(data, CHRROM); +} + +/*------------------------------------------------- + + Mapper 17 + + Known Boards: FFE8 Copier Board + Games: Hacked versions of games + + In MESS: Partially Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_ffe8_device::write_l) +{ + LOG_MMC(("mapper17 write_l, offset: %04x, data: %02x\n", offset, data)); + + switch (offset) + { + case 0x1fe: + set_nt_mirroring(BIT(data, 4) ? PPU_MIRROR_HIGH : PPU_MIRROR_LOW); + break; + case 0x1ff: + set_nt_mirroring(BIT(data, 4) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + break; + + case 0x401: + m_irq_enable = 0; + m_maincpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE); + break; + case 0x402: + m_irq_count = (m_irq_count & 0xff00) | data; + break; + case 0x403: + m_irq_enable = 1; + m_irq_count = (m_irq_count & 0x00ff) | (data << 8); + break; + + case 0x404: + prg8_89(data); + break; + case 0x405: + prg8_ab(data); + break; + case 0x406: + prg8_cd(data); + break; + case 0x407: + prg8_ef(data); + break; + + case 0x410: + case 0x411: + case 0x412: + case 0x413: + case 0x414: + case 0x415: + case 0x416: + case 0x417: + chr1_x(offset & 7, data, CHRROM); + break; + } +} diff --git a/src/devices/bus/nes/legacy.h b/src/devices/bus/nes/legacy.h new file mode 100644 index 00000000000..4b4667ab61b --- /dev/null +++ b/src/devices/bus/nes/legacy.h @@ -0,0 +1,81 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __NES_LEGACY_H +#define __NES_LEGACY_H + +#include "nxrom.h" + + +// ======================> nes_ffe3_device + +class nes_ffe3_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_ffe3_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); +}; + + +// ======================> nes_ffe4_device + +class nes_ffe4_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_ffe4_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + nes_ffe4_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + virtual DECLARE_WRITE8_MEMBER(write_l); + virtual DECLARE_WRITE8_MEMBER(write_h); + virtual DECLARE_READ8_MEMBER(chr_r); + virtual DECLARE_WRITE8_MEMBER(chr_w); + + virtual void pcb_reset(); + +protected: + UINT16 m_irq_count; + int m_irq_enable; + + static const device_timer_id TIMER_IRQ = 0; + emu_timer *irq_timer; + + UINT8 m_latch; + int m_exram_enabled; + int m_exram_bank; + UINT8 m_exram[0x8000]; +}; + + +// ======================> nes_ffe8_device + +class nes_ffe8_device : public nes_ffe4_device +{ +public: + // construction/destruction + nes_ffe8_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual DECLARE_WRITE8_MEMBER(write_l); + virtual DECLARE_WRITE8_MEMBER(write_h) {} + + virtual void pcb_reset(); +}; + + + +// device type definition +extern const device_type NES_FFE3; +extern const device_type NES_FFE4; +extern const device_type NES_FFE8; + + +#endif diff --git a/src/devices/bus/nes/mmc1.c b/src/devices/bus/nes/mmc1.c new file mode 100644 index 00000000000..ff31250ee19 --- /dev/null +++ b/src/devices/bus/nes/mmc1.c @@ -0,0 +1,374 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + NES/Famicom cartridge emulation for Nintendo MMC-1 PCBs + + + Here we emulate the Nintendo SxROM / MMC-1 PCBs + older variants without WRAM protect bit + + Known issues on specific mappers: + + * 001 Yoshi flashes in-game. + * 001 Back to the Future have heavily corrupted graphics (since forever). + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "mmc1.h" + +#ifdef NES_PCB_DEBUG +#define VERBOSE 1 +#else +#define VERBOSE 0 +#endif + +#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) + + +//------------------------------------------------- +// constructor +//------------------------------------------------- + +const device_type NES_SXROM = &device_creator; +const device_type NES_SOROM = &device_creator; +const device_type NES_SXROM_A = &device_creator; +const device_type NES_SOROM_A = &device_creator; + + + +nes_sxrom_device::nes_sxrom_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : nes_nrom_device(mconfig, type, name, tag, owner, clock, shortname, source) +{ +} + +nes_sxrom_device::nes_sxrom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_SXROM, "NES Cart SxROM (MMC-1) PCB", tag, owner, clock, "nes_sxrom", __FILE__) +{ +} + +nes_sorom_device::nes_sorom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_sxrom_device(mconfig, NES_SOROM, "NES Cart SOROM (MMC-1) PCB", tag, owner, clock, "nes_sorom", __FILE__) +{ +} + +nes_sxrom_a_device::nes_sxrom_a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_sxrom_device(mconfig, NES_SXROM_A, "NES Cart SxROM (MMC-1A) PCB", tag, owner, clock, "nes_sxrom_a", __FILE__) +{ +} + +nes_sorom_a_device::nes_sorom_a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_sxrom_device(mconfig, NES_SOROM_A, "NES Cart SOROM (MMC-1A) PCB", tag, owner, clock, "nes_sorom_a", __FILE__) +{ +} + + + +void nes_sxrom_device::device_start() +{ + common_start(); + save_item(NAME(m_latch)); + save_item(NAME(m_count)); + save_item(NAME(m_reg)); + save_item(NAME(m_reg_write_enable)); +} + +void nes_sxrom_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + + m_latch = 0; + m_count = 0; + m_reg[0] = 0x0f; + m_reg[1] = m_reg[2] = m_reg[3] = 0; + m_reg_write_enable = 1; + + set_nt_mirroring(PPU_MIRROR_HORZ); + set_chr(); + set_prg(); +} + +void nes_sorom_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + + m_latch = 0; + m_count = 0; + m_reg[0] = 0x0f; + m_reg[1] = m_reg[2] = m_reg[3] = 0; + m_reg_write_enable = 1; + + set_nt_mirroring(PPU_MIRROR_HORZ); + set_chr(); + set_prg(); +} + +void nes_sorom_a_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + + m_latch = 0; + m_count = 0; + m_reg[0] = 0x0f; + m_reg[1] = m_reg[2] = m_reg[3] = 0; + m_reg_write_enable = 1; + + set_nt_mirroring(PPU_MIRROR_HORZ); + set_chr(); + set_prg(); +} + + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + + +/*------------------------------------------------- + + SxROM (MMC1 based) board emulation + + iNES: mapper 1 (and 155 for the MMC1A variant which does not + have WRAM disable bit) + + -------------------------------------------------*/ + +TIMER_CALLBACK_MEMBER( nes_sxrom_device::resync_callback ) +{ + m_reg_write_enable = 1; +} + + +void nes_sxrom_device::set_prg() +{ + UINT8 prg_mode, prg_offset; + + prg_mode = m_reg[0] & 0x0c; + /* prg_mode&0x8 determines bank size: 32k (if 0) or 16k (if 1)? when in 16k mode, + prg_mode&0x4 determines which half of the PRG space we can swap: if it is 4, + m_reg[3] sets banks at 0x8000; if it is 0, m_reg[3] sets banks at 0xc000. */ + + prg_offset = m_reg[1] & 0x10; + /* In principle, m_reg[2]&0x10 might affect "extended" banks as well, when chr_mode=1. + However, quoting Disch's docs: When in 4k CHR mode, 0x10 in both $A000 and $C000 *must* be + set to the same value, or else pages will constantly be swapped as graphics render! + Hence, we use only m_reg[1]&0x10 for prg_offset */ + + switch (prg_mode) + { + case 0x00: + case 0x04: +// printf("PRG 32 bank %d \n", (prg_offset + m_reg[3]) >> 1); + prg32((prg_offset + m_reg[3]) >> 1); + break; + case 0x08: +// printf("PRG 16 bank %d (high) \n", prg_offset + m_reg[3]); + prg16_89ab(prg_offset + 0); + prg16_cdef(prg_offset + m_reg[3]); + break; + case 0x0c: +// printf("PRG 16 bank %d (low) \n", prg_offset + m_reg[3]); + prg16_89ab(prg_offset + m_reg[3]); + prg16_cdef(prg_offset + 0x0f); + break; + } +} + +void nes_sxrom_device::set_chr() +{ + UINT8 chr_mode = BIT(m_reg[0], 4); + + if (chr_mode) + { + chr4_0(m_reg[1] & 0x1f, m_chr_source); + chr4_4(m_reg[2] & 0x1f, m_chr_source); + } + else + chr8((m_reg[1] & 0x1f) >> 1, m_chr_source); +} + +// this allows for easier implementation of the NES-EVENT board used for Nintento World Championships +void nes_sxrom_device::update_regs(int reg) +{ + switch (reg) + { + case 0: + switch (m_reg[0] & 0x03) + { + case 0: set_nt_mirroring(PPU_MIRROR_LOW); break; + case 1: set_nt_mirroring(PPU_MIRROR_HIGH); break; + case 2: set_nt_mirroring(PPU_MIRROR_VERT); break; + case 3: set_nt_mirroring(PPU_MIRROR_HORZ); break; + } + set_chr(); + set_prg(); + break; + case 1: + set_chr(); + set_prg(); + break; + case 2: + set_chr(); + break; + case 3: + set_prg(); + break; + } +} + +WRITE8_MEMBER( nes_sxrom_device::write_h ) +{ + LOG_MMC(("sxrom write_h, offset: %04x, data: %02x\n", offset, data)); + + // There is only one latch and shift counter, shared amongst the 4 regs (testcase: Space Shuttle) + + /* here we would need to add an if(cpu_cycles_passed>1) test, and + if requirement is not met simply return without writing anything. + Some games (AD&D Hillsfar, Bill & Ted Excellent Adventure, Cosmic + Wars, Rocket Ranger, Sesame Street 123 and Snow Brothers) rely on + this behavior!! */ + if (!m_reg_write_enable) + return; + else + { + m_reg_write_enable = 0; + machine().scheduler().synchronize(timer_expired_delegate(FUNC(nes_sxrom_device::resync_callback),this)); + } + + if (data & 0x80) + { + m_count = 0; + m_latch = 0; + + // Set reg at 0x8000 to size 16k and lower half swap - needed for Robocop 3, Dynowars + m_reg[0] |= 0x0c; + set_prg(); + return; + } + + if (m_count < 5) + { + if (m_count == 0) m_latch = 0; + m_latch >>= 1; + m_latch |= (data & 0x01) ? 0x10 : 0x00; + m_count++; + } + + if (m_count == 5) + { + m_reg[(offset & 0x6000) >> 13] = m_latch; + update_regs((offset & 0x6000) >> 13); + m_count = 0; + } +} + +WRITE8_MEMBER(nes_sxrom_device::write_m) +{ + UINT8 bank = (m_reg[1] >> 2) & 3; + LOG_MMC(("sxrom write_m, offset: %04x, data: %02x\n", offset, data)); + + if (!BIT(m_reg[3], 4)) // WRAM enabled + { + if (!m_battery.empty()) + m_battery[((bank * 0x2000) + offset) & (m_battery.size() - 1)] = data; + if (!m_prgram.empty()) + m_prgram[((bank * 0x2000) + offset) & (m_prgram.size() - 1)] = data; + } +} + +READ8_MEMBER(nes_sxrom_device::read_m) +{ + UINT8 bank = (m_reg[1] >> 2) & 3; + LOG_MMC(("sxrom read_m, offset: %04x\n", offset)); + + if (!BIT(m_reg[3], 4)) // WRAM enabled + { + if (!m_battery.empty()) + return m_battery[((bank * 0x2000) + offset) & (m_battery.size() - 1)]; + if (!m_prgram.empty()) + return m_prgram[((bank * 0x2000) + offset) & (m_prgram.size() - 1)]; + } + + return m_open_bus; // open bus +} + +// SOROM has two RAM banks, the first is not battery backed up, the second is. +WRITE8_MEMBER(nes_sorom_device::write_m) +{ + UINT8 type = BIT(m_reg[0], 4) ? BIT(m_reg[1], 4) : BIT(m_reg[1], 3); + LOG_MMC(("sorom write_m, offset: %04x, data: %02x\n", offset, data)); + + if (!BIT(m_reg[3], 4)) // WRAM enabled + { + if (type) + m_battery[offset & (m_battery.size() - 1)] = data; + else + m_prgram[offset & (m_prgram.size() - 1)] = data; + } +} + +READ8_MEMBER(nes_sorom_device::read_m) +{ + UINT8 type = BIT(m_reg[0], 4) ? BIT(m_reg[1], 4) : BIT(m_reg[1], 3); + LOG_MMC(("sorom read_m, offset: %04x\n", offset)); + + if (!BIT(m_reg[3], 4)) // WRAM enabled + { + if (type) + return m_battery[offset & (m_battery.size() - 1)]; + else + return m_prgram[offset & (m_prgram.size() - 1)]; + } + + return m_open_bus; // open bus +} + +// MMC1A boards have no wram enable/disable bit +WRITE8_MEMBER(nes_sxrom_a_device::write_m) +{ + UINT8 bank = (m_reg[1] >> 2) & 3; + LOG_MMC(("sxrom_a write_m, offset: %04x, data: %02x\n", offset, data)); + + if (!m_battery.empty()) + m_battery[((bank * 0x2000) + offset) & (m_battery.size() - 1)] = data; + if (!m_prgram.empty()) + m_prgram[((bank * 0x2000) + offset) & (m_prgram.size() - 1)] = data; +} + +READ8_MEMBER(nes_sxrom_a_device::read_m) +{ + UINT8 bank = (m_reg[1] >> 2) & 3; + LOG_MMC(("sxrom_a read_m, offset: %04x\n", offset)); + + if (!m_battery.empty()) + return m_battery[((bank * 0x2000) + offset) & (m_battery.size() - 1)]; + if (!m_prgram.empty()) + return m_prgram[((bank * 0x2000) + offset) & (m_prgram.size() - 1)]; + + return m_open_bus; // open bus +} + +WRITE8_MEMBER(nes_sorom_a_device::write_m) +{ + UINT8 type = BIT(m_reg[0], 4) ? BIT(m_reg[1], 4) : BIT(m_reg[1], 3); + LOG_MMC(("sorom_a write_m, offset: %04x, data: %02x\n", offset, data)); + + if (type) + m_battery[offset & (m_battery.size() - 1)] = data; + else + m_prgram[offset & (m_prgram.size() - 1)] = data; +} + +READ8_MEMBER(nes_sorom_a_device::read_m) +{ + UINT8 type = BIT(m_reg[0], 4) ? BIT(m_reg[1], 4) : BIT(m_reg[1], 3); + LOG_MMC(("sorom_a read_m, offset: %04x\n", offset)); + + if (type) + return m_battery[offset & (m_battery.size() - 1)]; + else + return m_prgram[offset & (m_prgram.size() - 1)]; +} diff --git a/src/devices/bus/nes/mmc1.h b/src/devices/bus/nes/mmc1.h new file mode 100644 index 00000000000..05e25c46818 --- /dev/null +++ b/src/devices/bus/nes/mmc1.h @@ -0,0 +1,82 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __NES_MMC1_H +#define __NES_MMC1_H + +#include "nxrom.h" + + +// ======================> nes_sxrom_device + +class nes_sxrom_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_sxrom_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + nes_sxrom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_READ8_MEMBER(read_m); + virtual DECLARE_WRITE8_MEMBER(write_m); + virtual DECLARE_WRITE8_MEMBER(write_h); + virtual void update_regs(int reg); // this is needed to simplify NES-EVENT pcb implementation, which handle differently some regs! + + virtual void pcb_reset(); + +protected: + TIMER_CALLBACK_MEMBER(resync_callback); + virtual void set_prg(); + virtual void set_chr(); + + UINT8 m_reg[4]; + int m_reg_write_enable; + int m_latch; + int m_count; +}; + +class nes_sorom_device : public nes_sxrom_device +{ +public: + // construction/destruction + nes_sorom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual DECLARE_READ8_MEMBER(read_m); + virtual DECLARE_WRITE8_MEMBER(write_m); + + virtual void pcb_reset(); +}; + +class nes_sxrom_a_device : public nes_sxrom_device +{ +public: + // construction/destruction + nes_sxrom_a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual DECLARE_READ8_MEMBER(read_m); + virtual DECLARE_WRITE8_MEMBER(write_m); +}; + +class nes_sorom_a_device : public nes_sxrom_device +{ +public: + // construction/destruction + nes_sorom_a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual DECLARE_READ8_MEMBER(read_m); + virtual DECLARE_WRITE8_MEMBER(write_m); + + virtual void pcb_reset(); +}; + + + + +// device type definition +extern const device_type NES_SXROM; +extern const device_type NES_SOROM; +extern const device_type NES_SXROM_A; +extern const device_type NES_SOROM_A; + + +#endif diff --git a/src/devices/bus/nes/mmc2.c b/src/devices/bus/nes/mmc2.c new file mode 100644 index 00000000000..b9ef5402a00 --- /dev/null +++ b/src/devices/bus/nes/mmc2.c @@ -0,0 +1,198 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + NES/Famicom cartridge emulation for Nintendo MMC-2 & MMC-4 PCBs + + + Here we emulate the Nintendo PxROM and FxROM PCBs [mapper 9 & 10] + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "mmc2.h" + + +#ifdef NES_PCB_DEBUG +#define VERBOSE 1 +#else +#define VERBOSE 0 +#endif + +#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) + + +//------------------------------------------------- +// constructor +//------------------------------------------------- + +const device_type NES_PXROM = &device_creator; +const device_type NES_FXROM = &device_creator; + + +nes_pxrom_device::nes_pxrom_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : nes_nrom_device(mconfig, type, name, tag, owner, clock, shortname, source) +{ +} + +nes_pxrom_device::nes_pxrom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_PXROM, "NES Cart PxROM (MMC-2) PCB", tag, owner, clock, "nes_pxrom", __FILE__) +{ +} + +nes_fxrom_device::nes_fxrom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_pxrom_device(mconfig, NES_FXROM, "NES Cart FxROM (MMC-4) PCB", tag, owner, clock, "nes_fxrom", __FILE__) +{ +} + + + + +void nes_pxrom_device::device_start() +{ + common_start(); + save_item(NAME(m_latch1)); + save_item(NAME(m_latch2)); + save_item(NAME(m_reg)); +} + +void nes_pxrom_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg8_89(0); + prg8_ab((m_prg_chunks << 1) - 3); + prg8_cd((m_prg_chunks << 1) - 2); + prg8_ef((m_prg_chunks << 1) - 1); + chr8(0, m_chr_source); + + m_reg[0] = m_reg[2] = 0; + m_reg[1] = m_reg[3] = 0; + m_latch1 = m_latch2 = 0xfe; +} + +void nes_fxrom_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); + + m_reg[0] = m_reg[2] = 0; + m_reg[1] = m_reg[3] = 0; + m_latch1 = m_latch2 = 0xfe; +} + + + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +/*------------------------------------------------- + + PxROM (MMC2 based) board emulation + + Games: Punch Out!!, Mike Tyson's Punch Out!! + + iNES: mapper 9 + + In MESS: Supported + + -------------------------------------------------*/ + +void nes_pxrom_device::ppu_latch(offs_t offset) +{ + if ((offset & 0x3ff0) == 0x0fd0) + { + LOG_MMC(("mmc2 vrom latch switch (bank 0 low): %02x\n", m_reg[0])); + m_latch1 = 0xfd; + chr4_0(m_reg[0], CHRROM); + } + else if ((offset & 0x3ff0) == 0x0fe0) + { + LOG_MMC(("mmc2 vrom latch switch (bank 0 high): %02x\n", m_reg[1])); + m_latch1 = 0xfe; + chr4_0(m_reg[1], CHRROM); + } + else if ((offset & 0x3ff0) == 0x1fd0) + { + LOG_MMC(("mmc2 vrom latch switch (bank 1 low): %02x\n", m_reg[2])); + m_latch2 = 0xfd; + chr4_4(m_reg[2], CHRROM); + } + else if ((offset & 0x3ff0) == 0x1fe0) + { + LOG_MMC(("mmc2 vrom latch switch (bank 0 high): %02x\n", m_reg[3])); + m_latch2 = 0xfe; + chr4_4(m_reg[3], CHRROM); + } +} + +WRITE8_MEMBER( nes_pxrom_device::pxrom_write ) +{ + LOG_MMC(("pxrom write_h, offset: %04x, data: %02x\n", offset, data)); + switch (offset & 0x7000) + { + case 0x2000: + prg8_89(data); + break; + case 0x3000: + m_reg[0] = data; + if (m_latch1 == 0xfd) + chr4_0(m_reg[0], CHRROM); + break; + case 0x4000: + m_reg[1] = data; + if (m_latch1 == 0xfe) + chr4_0(m_reg[1], CHRROM); + break; + case 0x5000: + m_reg[2] = data; + if (m_latch2 == 0xfd) + chr4_4(m_reg[2], CHRROM); + break; + case 0x6000: + m_reg[3] = data; + if (m_latch2 == 0xfe) + chr4_4(m_reg[3], CHRROM); + break; + case 0x7000: + set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + break; + default: + LOG_MMC(("MMC2 uncaught w: %04x:%02x\n", offset, data)); + break; + } +} + +/*------------------------------------------------- + + FxROM (MMC4 based) board emulation + + Games: Famicom Wars, Fire Emblem, Fire Emblem Gaiden + + This is a small hardware variants of MMC2 (additional + prg bankswitch line) + + iNES: mapper 10 + + In MESS: Supported + + -------------------------------------------------*/ + +WRITE8_MEMBER( nes_fxrom_device::write_h ) +{ + LOG_MMC(("fxrom write_h, offset: %04x, data: %02x\n", offset, data)); + switch (offset & 0x7000) + { + case 0x2000: + prg16_89ab(data); + break; + default: + pxrom_write(space, offset, data, mem_mask); + break; + } +} diff --git a/src/devices/bus/nes/mmc2.h b/src/devices/bus/nes/mmc2.h new file mode 100644 index 00000000000..205fcf7a1d4 --- /dev/null +++ b/src/devices/bus/nes/mmc2.h @@ -0,0 +1,54 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __NES_MMC2_H +#define __NES_MMC2_H + +#include "nxrom.h" + + +// ======================> nes_pxrom_device + +class nes_pxrom_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_pxrom_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + nes_pxrom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(pxrom_write); + virtual DECLARE_WRITE8_MEMBER(write_h) { pxrom_write(space, offset, data, mem_mask); } + + virtual void ppu_latch(offs_t offset); + virtual void pcb_reset(); + +protected: + UINT8 m_reg[4]; + int m_latch1, m_latch2; +}; + + +// ======================> nes_fxrom_device + +class nes_fxrom_device : public nes_pxrom_device +{ +public: + // construction/destruction + nes_fxrom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); +}; + + + + + +// device type definition +extern const device_type NES_PXROM; +extern const device_type NES_FXROM; + +#endif diff --git a/src/devices/bus/nes/mmc3.c b/src/devices/bus/nes/mmc3.c new file mode 100644 index 00000000000..8e81fac286f --- /dev/null +++ b/src/devices/bus/nes/mmc3.c @@ -0,0 +1,560 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + NES/Famicom cartridge emulation for Nintendo MMC-3 & MMC-6 PCBs + + + Here we emulate the following PCBs + + * Nintendo TxROM, aka MMC-3 [mapper 4] + * Nintendo HKROM, aka MMC-6 [mapper 4] + * Nintendo TxSROM [mapper 118] + * Nintendo TQROM [mapper 119] + * Nintendo NES-QJ [mapper 47] + * Nintendo PAL-ZZ [mapper 37] + + + Known issues on specific mappers: + + * 004 Mendel Palace has never worked properly + * 004 Ninja Gaiden 2 has flashing bg graphics in the second level + * 119 Pin Bot has glitches when the ball is in the upper half of the screen + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "mmc3.h" + +#include "cpu/m6502/m6502.h" +#include "video/ppu2c0x.h" // this has to be included so that IRQ functions can access PPU_BOTTOM_VISIBLE_SCANLINE + + +#ifdef NES_PCB_DEBUG +#define VERBOSE 1 +#else +#define VERBOSE 0 +#endif + +#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) + + +//------------------------------------------------- +// constructor +//------------------------------------------------- + +const device_type NES_TXROM = &device_creator; +const device_type NES_HKROM = &device_creator; +const device_type NES_TXSROM = &device_creator; +const device_type NES_TQROM = &device_creator; +const device_type NES_QJ_PCB = &device_creator; +const device_type NES_ZZ_PCB = &device_creator; + + +nes_txrom_device::nes_txrom_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : nes_nrom_device(mconfig, type, name, tag, owner, clock, shortname, source) +{ +} + +nes_txrom_device::nes_txrom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_TXROM, "NES Cart TxROM (MMC-3) PCB", tag, owner, clock, "nes_txrom", __FILE__) +{ +} + +nes_hkrom_device::nes_hkrom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_txrom_device(mconfig, NES_HKROM, "NES Cart HKROM (MMC-6) PCB", tag, owner, clock, "nes_hkrom", __FILE__) +{ +} + +nes_txsrom_device::nes_txsrom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_txrom_device(mconfig, NES_TXSROM, "NES Cart TxSROM PCB", tag, owner, clock, "nes_txsrom", __FILE__) +{ +} + +nes_tqrom_device::nes_tqrom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_txrom_device(mconfig, NES_TQROM, "NES Cart TQROM PCB", tag, owner, clock, "nes_tqrom", __FILE__) +{ +} + +nes_qj_device::nes_qj_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_txrom_device(mconfig, NES_QJ_PCB, "NES Cart NES-QJ PCB", tag, owner, clock, "nes_qj", __FILE__) +{ +} + +nes_zz_device::nes_zz_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_txrom_device(mconfig, NES_ZZ_PCB, "NES Cart PAL-ZZ PCB", tag, owner, clock, "nes_zz", __FILE__) +{ +} + + + +void nes_txrom_device::mmc3_start() +{ + common_start(); + save_item(NAME(m_mmc_prg_bank)); + save_item(NAME(m_mmc_vrom_bank)); + save_item(NAME(m_latch)); + save_item(NAME(m_wram_protect)); + save_item(NAME(m_prg_base)); + save_item(NAME(m_prg_mask)); + save_item(NAME(m_chr_base)); + save_item(NAME(m_chr_mask)); + save_item(NAME(m_alt_irq)); + save_item(NAME(m_irq_enable)); + save_item(NAME(m_irq_count)); + save_item(NAME(m_irq_count_latch)); + save_item(NAME(m_irq_clear)); +} + +void nes_txrom_device::mmc3_common_initialize( int prg_mask, int chr_mask, int irq_type ) +{ + m_mmc_prg_bank[0] = m_mmc_prg_bank[2] = 0xffe; // m_mmc_prg_bank[2] & m_mmc_prg_bank[3] remain always the same in most MMC3 variants + m_mmc_prg_bank[1] = m_mmc_prg_bank[3] = 0xfff; // but some pirate clone mappers change them after writing certain registers + memset(m_mmc_vrom_bank, 0, sizeof(m_mmc_vrom_bank)); + + m_latch = 0; + m_wram_protect = 0x80; + + m_prg_base = m_chr_base = 0; + m_prg_mask = prg_mask; + m_chr_mask = chr_mask; + + m_alt_irq = irq_type; // later MMC3 boards seem to use MMC6-type IRQ... more investigations are in progress at NESDev... + m_irq_enable = 0; + m_irq_count = m_irq_count_latch = 0; + m_irq_clear = 0; + + set_prg(m_prg_base, m_prg_mask); + set_chr(m_chr_source, m_chr_base, m_chr_mask); +} + + +void nes_txrom_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + // 4-screen mirroring is taken care in pcb_start, if needed... + mmc3_common_initialize(0xff, 0xff, 0); +} + + +void nes_hkrom_device::device_start() +{ + mmc3_start(); + save_item(NAME(m_mmc6_reg)); + save_item(NAME(m_wram_enable)); + + save_item(NAME(m_mmc6_ram)); + + m_mapper_sram_size = 0x400; + m_mapper_sram = m_mmc6_ram; +} + +void nes_hkrom_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + mmc3_common_initialize(0xff, 0xff, 1); + m_mmc6_reg = 0xf0; + m_wram_enable = 0; +} + + +void nes_qj_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + mmc3_common_initialize(0x0f, 0x7f, 0); +} + + +void nes_zz_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + mmc3_common_initialize(0x07, 0x7f, 0); +} + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +/*------------------------------------------------- + + TxROM (MMC3 based) board emulation + + iNES: mapper 4 + + -------------------------------------------------*/ + +/* Here, IRQ counter decrements every scanline. */ +void nes_txrom_device::hblank_irq(int scanline, int vblank, int blanked) +{ + if (scanline < PPU_BOTTOM_VISIBLE_SCANLINE) + { + int prior_count = m_irq_count; + if ((m_irq_count == 0) || m_irq_clear) + m_irq_count = m_irq_count_latch; + else + m_irq_count--; + + if (m_irq_enable && !blanked && (m_irq_count == 0) && (prior_count || m_irq_clear /*|| !m_mmc3_alt_irq*/)) // according to blargg the latter should be present as well, but it breaks Rampart and Joe & Mac US: they probably use the alt irq! + { + LOG_MMC(("irq fired, scanline: %d (MAME %d, beam pos: %d)\n", scanline, + machine().first_screen()->vpos(), machine().first_screen()->hpos())); + m_maincpu->set_input_line(M6502_IRQ_LINE, ASSERT_LINE); + } + } + m_irq_clear = 0; +} + +// base MMC3 simply calls prg8_x +void nes_txrom_device::prg_cb( int start, int bank ) +{ + prg8_x(start, bank); +} + +// base MMC3 simply calls chr1_x +void nes_txrom_device::chr_cb( int start, int bank, int source ) +{ + chr1_x(start, bank, source); +} + + +void nes_txrom_device::set_prg( int prg_base, int prg_mask ) +{ + UINT8 prg_flip = (m_latch & 0x40) ? 2 : 0; + + prg_cb(0, prg_base | (m_mmc_prg_bank[0 ^ prg_flip] & prg_mask)); + prg_cb(1, prg_base | (m_mmc_prg_bank[1] & prg_mask)); + prg_cb(2, prg_base | (m_mmc_prg_bank[2 ^ prg_flip] & prg_mask)); + prg_cb(3, prg_base | (m_mmc_prg_bank[3] & prg_mask)); +} + +void nes_txrom_device::set_chr( UINT8 chr, int chr_base, int chr_mask ) +{ + UINT8 chr_page = (m_latch & 0x80) >> 5; + + chr_cb(chr_page ^ 0, chr_base | ((m_mmc_vrom_bank[0] & ~0x01) & chr_mask), chr); + chr_cb(chr_page ^ 1, chr_base | ((m_mmc_vrom_bank[0] | 0x01) & chr_mask), chr); + chr_cb(chr_page ^ 2, chr_base | ((m_mmc_vrom_bank[1] & ~0x01) & chr_mask), chr); + chr_cb(chr_page ^ 3, chr_base | ((m_mmc_vrom_bank[1] | 0x01) & chr_mask), chr); + chr_cb(chr_page ^ 4, chr_base | (m_mmc_vrom_bank[2] & chr_mask), chr); + chr_cb(chr_page ^ 5, chr_base | (m_mmc_vrom_bank[3] & chr_mask), chr); + chr_cb(chr_page ^ 6, chr_base | (m_mmc_vrom_bank[4] & chr_mask), chr); + chr_cb(chr_page ^ 7, chr_base | (m_mmc_vrom_bank[5] & chr_mask), chr); +} + +WRITE8_MEMBER(nes_txrom_device::txrom_write) +{ + UINT8 mmc_helper, cmd; + + LOG_MMC(("txrom_write, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x6001) + { + case 0x0000: + mmc_helper = m_latch ^ data; + m_latch = data; + + // Has PRG Mode changed? + if (mmc_helper & 0x40) + set_prg(m_prg_base, m_prg_mask); + + // Has CHR Mode changed? + if (mmc_helper & 0x80) + set_chr(m_chr_source, m_chr_base, m_chr_mask); + break; + + case 0x0001: + cmd = m_latch & 0x07; + switch (cmd) + { + case 0: case 1: // these do not need to be separated: we take care of them in set_chr! + case 2: case 3: case 4: case 5: + m_mmc_vrom_bank[cmd] = data; + set_chr(m_chr_source, m_chr_base, m_chr_mask); + break; + case 6: + case 7: + m_mmc_prg_bank[cmd - 6] = data; + set_prg(m_prg_base, m_prg_mask); + break; + } + break; + + case 0x2000: + set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + break; + + case 0x2001: + m_wram_protect = data; + break; + + case 0x4000: + m_irq_count_latch = data; + break; + + case 0x4001: + m_irq_count = 0; + break; + + case 0x6000: + m_irq_enable = 0; + m_maincpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE); + break; + + case 0x6001: + m_irq_enable = 1; + break; + + default: + logerror("txrom_write uncaught: %04x value: %02x\n", offset + 0x8000, data); + break; + } +} + +WRITE8_MEMBER(nes_txrom_device::write_m) +{ + LOG_MMC(("txrom write_m, offset: %04x, data: %02x\n", offset, data)); + + if (BIT(m_wram_protect, 7) && !BIT(m_wram_protect, 6)) + { + if (!m_battery.empty()) + m_battery[offset & (m_battery.size() - 1)] = data; + if (!m_prgram.empty()) + m_prgram[offset & (m_prgram.size() - 1)] = data; + } +} + +READ8_MEMBER(nes_txrom_device::read_m) +{ + LOG_MMC(("txrom read_m, offset: %04x\n", offset)); + + if (BIT(m_wram_protect, 7)) + { + if (!m_battery.empty()) + return m_battery[offset & (m_battery.size() - 1)]; + if (!m_prgram.empty()) + return m_prgram[offset & (m_prgram.size() - 1)]; + } + + return m_open_bus; // open bus +} + + +/*------------------------------------------------- + + HKROM (MMC6 based) board emulation + + iNES: mapper 4 + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_hkrom_device::write_m) +{ + UINT8 write_hi, write_lo; + LOG_MMC(("hkrom write_m, offset: %04x, data: %02x\n", offset, data)); + + if (offset < 0x1000) + return; + + // banks can be written only if both read & write is enabled! + write_hi = ((m_mmc6_reg & 0xc0) == 0xc0); + write_lo = ((m_mmc6_reg & 0x30) == 0x30); + + if (BIT(offset, 9) && write_hi) // access to upper half of 1k + m_mmc6_ram[offset & 0x3ff] = data; + + if (!BIT(offset, 9) && write_lo) // access to lower half of 1k + m_mmc6_ram[offset & 0x3ff] = data; +} + +READ8_MEMBER(nes_hkrom_device::read_m) +{ + LOG_MMC(("hkrom read_m, offset: %04x\n", offset)); + + if (offset < 0x1000) + return m_open_bus; // open bus + + if (!(m_mmc6_reg & 0xa0)) + return m_open_bus; // open bus + + if (BIT(offset, 9) && BIT(m_mmc6_reg, 7)) // access to upper half of 1k when upper read is enabled + return m_mmc6_ram[offset & 0x3ff]; + + if (!BIT(offset, 9) && BIT(m_mmc6_reg, 5)) // access to lower half of 1k when lower read is enabled + return m_mmc6_ram[offset & 0x3ff]; + + // If only one bank is enabled for reading, the other reads back as zero + return 0x00; +} + +WRITE8_MEMBER(nes_hkrom_device::write_h) +{ + UINT8 mmc6_helper; + LOG_MMC(("hkrom write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x6001) + { + case 0x0000: + mmc6_helper = m_latch ^ data; + m_latch = data; + + if (!m_wram_enable && BIT(data, 5)) // if WRAM is disabled and has to be enabled, write + m_wram_enable = BIT(data, 5); // (once WRAM has been enabled, it cannot be disabled without resetting the game) + + // Has PRG Mode changed? + if (BIT(mmc6_helper, 6)) + set_prg(m_prg_base, m_prg_mask); + + // Has CHR Mode changed? + if (BIT(mmc6_helper, 7)) + set_chr(m_chr_source, m_chr_base, m_chr_mask); + break; + + case 0x2001: + if (m_wram_enable) + m_mmc6_reg = data; + break; + + case 0x4001: + m_irq_count = 0; + m_irq_clear = 1; + break; + + default: + txrom_write(space, offset, data, mem_mask); + break; + } +} + +/*------------------------------------------------- + + TxSROM (MMC3 based) board emulation + + Games: Armadillo, Play Action Football, Pro Hockey, RPG + Jinsei Game, Y's 3 + + iNES: mapper 118 + + In MESS: Supported. It also uses mmc3_irq. + + -------------------------------------------------*/ + +void nes_txsrom_device::set_mirror() +{ + if (m_latch & 0x80) + { + set_nt_page(0, CIRAM, BIT(m_mmc_vrom_bank[2],7), 1); + set_nt_page(1, CIRAM, BIT(m_mmc_vrom_bank[3],7), 1); + set_nt_page(2, CIRAM, BIT(m_mmc_vrom_bank[4],7), 1); + set_nt_page(3, CIRAM, BIT(m_mmc_vrom_bank[5],7), 1); + } + else + { + set_nt_page(0, CIRAM, BIT(m_mmc_vrom_bank[0],7), 1); + set_nt_page(1, CIRAM, BIT(m_mmc_vrom_bank[0],7), 1); + set_nt_page(2, CIRAM, BIT(m_mmc_vrom_bank[1],7), 1); + set_nt_page(3, CIRAM, BIT(m_mmc_vrom_bank[1],7), 1); + } +} + +void nes_txsrom_device::chr_cb( int start, int bank, int source ) +{ + set_mirror(); // we could probably update only for one (e.g. the first) call, to slightly optimize the code + chr1_x(start, bank, source); +} + +WRITE8_MEMBER(nes_txsrom_device::write_h) +{ + LOG_MMC(("txsrom write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x6001) + { + case 0x2000: + break; + + default: + txrom_write(space, offset, data, mem_mask); + break; + } +} + +/*------------------------------------------------- + + TQROM (MMC3 based) board emulation + + Games: Pin Bot, High Speed + + iNES: mapper 119 + + In MESS: Supported. It also uses mmc3_irq. + + -------------------------------------------------*/ + +void nes_tqrom_device::set_chr( UINT8 chr, int chr_base, int chr_mask ) +{ + UINT8 chr_page = (m_latch & 0x80) >> 5; + UINT8 src[6], mask[6]; + + // TQROM ignores the source, base and mask set by the MMC3 and determines them based on vrom bank bits + for (int i = 0; i < 6; i++) + { + src[i] = (m_mmc_vrom_bank[i] & 0x40) ? CHRRAM : CHRROM; + mask[i] = (m_mmc_vrom_bank[i] & 0x40) ? 0x07 : 0x3f; + } + + chr1_x(chr_page ^ 0, ((m_mmc_vrom_bank[0] & ~0x01) & mask[0]), src[0]); + chr1_x(chr_page ^ 1, ((m_mmc_vrom_bank[0] | 0x01) & mask[0]), src[0]); + chr1_x(chr_page ^ 2, ((m_mmc_vrom_bank[1] & ~0x01) & mask[1]), src[1]); + chr1_x(chr_page ^ 3, ((m_mmc_vrom_bank[1] | 0x01) & mask[1]), src[1]); + chr1_x(chr_page ^ 4, (m_mmc_vrom_bank[2] & mask[2]), src[2]); + chr1_x(chr_page ^ 5, (m_mmc_vrom_bank[3] & mask[3]), src[3]); + chr1_x(chr_page ^ 6, (m_mmc_vrom_bank[4] & mask[4]), src[4]); + chr1_x(chr_page ^ 7, (m_mmc_vrom_bank[5] & mask[5]), src[5]); +} + + +/*------------------------------------------------- + + NES-QJ board (MMC3 variant for US 2-in-1 Nintendo cart + Super Spike V'Ball + Nintendo World Cup) + + iNES: mapper 47 + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_qj_device::write_m) +{ + LOG_MMC(("qj write_m, offset: %04x, data: %02x\n", offset, data)); + + m_prg_base = BIT(data, 0) << 4; + m_prg_mask = 0x0f; + m_chr_base = BIT(data, 0) << 7; + m_chr_mask = 0x7f; + set_prg(m_prg_base, m_prg_mask); + set_chr(m_chr_source, m_chr_base, m_chr_mask); +} + + +/*------------------------------------------------- + + PAL-ZZ board (MMC3 variant for European 3-in-1 Nintendo cart + Super Mario Bros. + Tetris + Nintendo World Cup) + + iNES: mapper 37 + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_zz_device::write_m) +{ + UINT8 mmc_helper = data & 0x07; + LOG_MMC(("zz write_m, offset: %04x, data: %02x\n", offset, data)); + + m_prg_base = (BIT(mmc_helper, 2) << 4) | (((mmc_helper & 0x03) == 0x03) ? 0x08 : 0); + m_prg_mask = (mmc_helper << 1) | 0x07; + m_chr_base = BIT(mmc_helper, 2) << 7; + m_chr_mask = 0x7f; + set_prg(m_prg_base, m_prg_mask); + set_chr(m_chr_source, m_chr_base, m_chr_mask); +} diff --git a/src/devices/bus/nes/mmc3.h b/src/devices/bus/nes/mmc3.h new file mode 100644 index 00000000000..ace03588bb4 --- /dev/null +++ b/src/devices/bus/nes/mmc3.h @@ -0,0 +1,146 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __NES_MMC3_H +#define __NES_MMC3_H + +#include "nxrom.h" + + +// ======================> nes_txrom_device + +class nes_txrom_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_txrom_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + nes_txrom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start() { mmc3_start(); } + virtual DECLARE_READ8_MEMBER(read_m); + virtual DECLARE_WRITE8_MEMBER(write_m); + virtual DECLARE_WRITE8_MEMBER(txrom_write); + virtual DECLARE_WRITE8_MEMBER(write_h) { txrom_write(space, offset, data, mem_mask); } + virtual void prg_cb(int start, int bank); + virtual void chr_cb(int start, int bank, int source); + + virtual void hblank_irq(int scanline, int vblank, int blanked); + virtual void pcb_reset(); + +protected: + virtual void set_prg(int prg_base, int prg_mask); + virtual void set_chr(UINT8 chr, int chr_base, int chr_mask); + void mmc3_start(); + void mmc3_common_initialize(int prg_mask, int chr_mask, int IRQ_type); + + // are there MMC3 clones which need more regs? + UINT16 m_mmc_prg_bank[4]; + UINT16 m_mmc_vrom_bank[8]; // a few clones need more than the 6 banks used by base MMC3 (e.g. waixing_g) + + int m_prg_base, m_prg_mask; // MMC3 based multigame carts select a block of banks by using these (and then act like normal MMC3), + int m_chr_base, m_chr_mask; // while MMC3 and clones (mapper 118 & 119) simply set them as 0 and 0xff resp. + + int m_latch; + int m_wram_protect; + int m_alt_irq; + + UINT16 m_irq_count, m_irq_count_latch; + UINT8 m_irq_clear; + int m_irq_enable; +}; + + +// ======================> nes_hkrom_device + +class nes_hkrom_device : public nes_txrom_device +{ +public: + // construction/destruction + nes_hkrom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_READ8_MEMBER(read_m); + virtual DECLARE_WRITE8_MEMBER(write_m); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); + +protected: + int m_wram_enable; + UINT8 m_mmc6_reg; + + // MMC-6 contains 1K of internal ram, battery backed up + UINT8 m_mmc6_ram[0x400]; +}; + + +// ======================> nes_txsrom_device + +class nes_txsrom_device : public nes_txrom_device +{ +public: + // construction/destruction + nes_txsrom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual DECLARE_WRITE8_MEMBER(write_h); + virtual void chr_cb(int start, int bank, int source); + +protected: + void set_mirror(); +}; + + +// ======================> nes_tqrom_device + +class nes_tqrom_device : public nes_txrom_device +{ +public: + // construction/destruction + nes_tqrom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual void set_chr( UINT8 chr, int chr_base, int chr_mask ); +}; + + +// ======================> nes_qj_device + +class nes_qj_device : public nes_txrom_device +{ +public: + // construction/destruction + nes_qj_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual DECLARE_WRITE8_MEMBER(write_m); + virtual void pcb_reset(); +}; + + +// ======================> nes_zz_device + +class nes_zz_device : public nes_txrom_device +{ +public: + // construction/destruction + nes_zz_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual DECLARE_WRITE8_MEMBER(write_m); + virtual void pcb_reset(); +}; + + + + +// device type definition +extern const device_type NES_TXROM; +extern const device_type NES_HKROM; +extern const device_type NES_TXSROM; +extern const device_type NES_TQROM; +extern const device_type NES_QJ_PCB; +extern const device_type NES_ZZ_PCB; + +#endif diff --git a/src/devices/bus/nes/mmc3_clones.c b/src/devices/bus/nes/mmc3_clones.c new file mode 100644 index 00000000000..4a806d0fde2 --- /dev/null +++ b/src/devices/bus/nes/mmc3_clones.c @@ -0,0 +1,2588 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + NES/Famicom cartridge emulation for MMC-3 clone PCBs + + + Here we emulate several pirate PCBs based on MMC-3 boards + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "mmc3_clones.h" + + +#ifdef NES_PCB_DEBUG +#define VERBOSE 1 +#else +#define VERBOSE 0 +#endif + +#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) + + +//------------------------------------------------- +// constructor +//------------------------------------------------- + +const device_type NES_NITRA = &device_creator; +const device_type NES_KS7057 = &device_creator; +const device_type NES_SBROS11 = &device_creator; +const device_type NES_MALISB = &device_creator; +const device_type NES_FAMILY4646 = &device_creator; +const device_type NES_PIKAY2K = &device_creator; +const device_type NES_8237 = &device_creator; +const device_type NES_SG_LIONK = &device_creator; +const device_type NES_SG_BOOG = &device_creator; +const device_type NES_KASING = &device_creator; +const device_type NES_KAY = &device_creator; +const device_type NES_H2288 = &device_creator; +const device_type NES_6035052 = &device_creator; +const device_type NES_TXC_TW = &device_creator; +const device_type NES_KOF97 = &device_creator; +const device_type NES_KOF96 = &device_creator; +const device_type NES_SF3 = &device_creator; +const device_type NES_GOUDER = &device_creator; +const device_type NES_SA9602B = &device_creator; +const device_type NES_SACHEN_SHERO = &device_creator; +//const device_type NES_A9746 = &device_creator; + +const device_type NES_FK23C = &device_creator; +const device_type NES_FK23CA = &device_creator; +const device_type NES_S24IN1SC03 = &device_creator; +const device_type NES_BMC_15IN1 = &device_creator; +const device_type NES_BMC_SBIG7 = &device_creator; +const device_type NES_BMC_HIK8 = &device_creator; +const device_type NES_BMC_HIK4 = &device_creator; +const device_type NES_BMC_MARIO7IN1 = &device_creator; +const device_type NES_BMC_GOLD7IN1 = &device_creator; +const device_type NES_BMC_GC6IN1 = &device_creator; +const device_type NES_BMC_411120C = &device_creator; +const device_type NES_BMC_830118C = &device_creator; +const device_type NES_PJOY84 = &device_creator; + + +nes_nitra_device::nes_nitra_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_txrom_device(mconfig, NES_NITRA, "NES Cart Nitra PCB", tag, owner, clock, "nes_nitra", __FILE__) +{ +} + +nes_ks7057_device::nes_ks7057_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_txrom_device(mconfig, NES_KS7057, "NES Cart KS-7057 PCB", tag, owner, clock, "nes_ks7057", __FILE__) +{ +} + +nes_sbros11_device::nes_sbros11_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_txrom_device(mconfig, NES_SBROS11, "NES Cart SMB 11 PCB", tag, owner, clock, "nes_smb11", __FILE__) +{ +} + +nes_malisb_device::nes_malisb_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_txrom_device(mconfig, NES_MALISB, "NES Cart Mali Spash Bomb PCB", tag, owner, clock, "nes_malisb", __FILE__) +{ +} + +nes_family4646_device::nes_family4646_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_txrom_device(mconfig, NES_FAMILY4646, "NES Cart BMC-FAMILY-4646 PCB", tag, owner, clock, "nes_family4646", __FILE__) +{ +} + +nes_pikay2k_device::nes_pikay2k_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_txrom_device(mconfig, NES_PIKAY2K, "NES Cart PIKACHU Y2K PCB", tag, owner, clock, "nes_pikay2k", __FILE__) +{ +} + +nes_8237_device::nes_8237_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_txrom_device(mconfig, NES_8237, "NES Cart UNL-8237 PCB", tag, owner, clock, "nes_8237", __FILE__) +{ +} + +nes_sglionk_device::nes_sglionk_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_txrom_device(mconfig, NES_SG_LIONK, "NES Cart SuperGame Lion King PCB", tag, owner, clock, "nes_sglionk", __FILE__) +{ +} + +nes_sgboog_device::nes_sgboog_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_txrom_device(mconfig, NES_SG_BOOG, "NES Cart SuperGame BoogerMan PCB", tag, owner, clock, "nes_sgbooger", __FILE__) +{ +} + +nes_kasing_device::nes_kasing_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_txrom_device(mconfig, NES_KASING, "NES Cart Kasing PCB", tag, owner, clock, "nes_kasing", __FILE__) +{ +} + +nes_kay_device::nes_kay_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_txrom_device(mconfig, NES_KAY, "NES Cart KAY PCB", tag, owner, clock, "nes_kay", __FILE__) +{ +} + +nes_h2288_device::nes_h2288_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_txrom_device(mconfig, NES_H2288, "NES Cart H-2288 PCB", tag, owner, clock, "nes_h2288", __FILE__) +{ +} + +nes_6035052_device::nes_6035052_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_txrom_device(mconfig, NES_6035052, "NES Cart UNL-603-5052 PCB", tag, owner, clock, "nes_6035052", __FILE__) +{ +} + +nes_txc_tw_device::nes_txc_tw_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_txrom_device(mconfig, NES_TXC_TW, "NES Cart TXC Thunder Warrior PCB", tag, owner, clock, "nes_txc_tw", __FILE__) +{ +} + +nes_kof97_device::nes_kof97_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_txrom_device(mconfig, NES_KOF97, "NES Cart KOF 97 PCB", tag, owner, clock, "nes_kof97", __FILE__) +{ +} + +nes_kof96_device::nes_kof96_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_txrom_device(mconfig, NES_KOF96, "NES Cart KOF 96 PCB", tag, owner, clock, "nes_kof96", __FILE__) +{ +} + +nes_sf3_device::nes_sf3_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_txrom_device(mconfig, NES_SF3, "NES Cart Super Fighter III PCB", tag, owner, clock, "nes_sf3", __FILE__) +{ +} + +nes_gouder_device::nes_gouder_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_txrom_device(mconfig, NES_GOUDER, "NES Cart Gouder PCB", tag, owner, clock, "nes_gouder", __FILE__) +{ +} + +nes_sa9602b_device::nes_sa9602b_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_txrom_device(mconfig, NES_SA9602B, "NES Cart SA-9602B PCB", tag, owner, clock, "nes_sa9602b", __FILE__) +{ +} + +nes_sachen_shero_device::nes_sachen_shero_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_txrom_device(mconfig, NES_SACHEN_SHERO, "NES Cart Street Hero PCB", tag, owner, clock, "nes_shero", __FILE__) +{ +} + +//nes_a9746_device::nes_a9746_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) +// : nes_txrom_device(mconfig, NES_A9746, "NES Cart A-9746 PCB", tag, owner, clock, "nes_bmc_a9746", __FILE__) +//{ +//} + +nes_fk23c_device::nes_fk23c_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : nes_txrom_device(mconfig, type, name, tag, owner, clock, shortname, source) +{ +} + +nes_fk23c_device::nes_fk23c_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_txrom_device(mconfig, NES_FK23C, "NES Cart FK23C PCB", tag, owner, clock, "nes_fk23c", __FILE__) +{ +} + +nes_fk23ca_device::nes_fk23ca_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_fk23c_device(mconfig, NES_FK23CA, "NES Cart FK23CA PCB", tag, owner, clock, "nes_fk23ca", __FILE__) +{ +} + +nes_s24in1sc03_device::nes_s24in1sc03_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_txrom_device(mconfig, NES_S24IN1SC03, "NES Cart Super 24 in 1 SC-03 PCB", tag, owner, clock, "nes_s24in1c03", __FILE__) +{ +} + +nes_bmc_15in1_device::nes_bmc_15in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_txrom_device(mconfig, NES_BMC_15IN1, "NES Cart BMC 15 in 1 PCB", tag, owner, clock, "nes_bmc_15in1", __FILE__) +{ +} + +nes_bmc_sbig7_device::nes_bmc_sbig7_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_txrom_device(mconfig, NES_BMC_SBIG7, "NES Cart BMC Super BIG 7 in 1 PCB", tag, owner, clock, "nes_bmc_sbit7", __FILE__) +{ +} + +nes_bmc_hik8_device::nes_bmc_hik8_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_txrom_device(mconfig, NES_BMC_HIK8, "NES Cart BMC Super HIK 8 in 1 PCB", tag, owner, clock, "nes_bmc_hik8", __FILE__) +{ +} + +nes_bmc_hik4_device::nes_bmc_hik4_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_txrom_device(mconfig, NES_BMC_HIK4, "NES Cart BMC Super HIK 4 in 1 PCB", tag, owner, clock, "nes_bmc_hik4", __FILE__) +{ +} + +nes_bmc_mario7in1_device::nes_bmc_mario7in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_txrom_device(mconfig, NES_BMC_MARIO7IN1, "NES Cart BMC Mario 7 in 1 PCB", tag, owner, clock, "nes_bmc_mario7in1", __FILE__) +{ +} + +nes_bmc_gold7in1_device::nes_bmc_gold7in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_txrom_device(mconfig, NES_BMC_GOLD7IN1, "NES Cart BMC Golden 7 in 1 PCB", tag, owner, clock, "nes_bmc_gold7in1", __FILE__) +{ +} + +nes_bmc_gc6in1_device::nes_bmc_gc6in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_txrom_device(mconfig, NES_BMC_GC6IN1, "NES Cart BMC Golden Card 6 in 1 PCB", tag, owner, clock, "nes_bmc_gc6in1", __FILE__) +{ +} + +nes_bmc_411120c_device::nes_bmc_411120c_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_txrom_device(mconfig, NES_BMC_411120C, "NES Cart BMC 411120C PCB", tag, owner, clock, "nes_bmc_411120c", __FILE__) +{ +} + +nes_bmc_830118c_device::nes_bmc_830118c_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_txrom_device(mconfig, NES_BMC_830118C, "NES Cart BMC 830118C PCB", tag, owner, clock, "nes_bmc_830118c", __FILE__) +{ +} + +nes_pjoy84_device::nes_pjoy84_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_txrom_device(mconfig, NES_PJOY84, "NES Cart Powerjoy 84 PCB", tag, owner, clock, "nes_pjoy84", __FILE__) +{ +} + + + +void nes_family4646_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + mmc3_common_initialize(0x1f, 0xff, 0); +} + +void nes_pikay2k_device::device_start() +{ + mmc3_start(); + save_item(NAME(m_reg)); +} + +void nes_pikay2k_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + + m_reg[0] = 0xff; + m_reg[1] = 0; + mmc3_common_initialize(0xff, 0xff, 0); +} + +void nes_8237_device::device_start() +{ + mmc3_start(); + save_item(NAME(m_reg)); + save_item(NAME(m_cd_enable)); +} + +void nes_8237_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + + m_reg[0] = 0; + m_reg[1] = 0; + m_reg[2] = 0; + m_cd_enable = 0; + mmc3_common_initialize(0xff, 0xff, 0); +} + +void nes_sglionk_device::device_start() +{ + mmc3_start(); + save_item(NAME(m_reg)); + save_item(NAME(m_reg_enabled)); +} + +void nes_sglionk_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + + m_reg = m_reg_enabled = 0; + mmc3_common_initialize(0xff, 0xff, 0); +} + +void nes_sgboog_device::device_start() +{ + mmc3_start(); + save_item(NAME(m_reg)); + save_item(NAME(m_mode)); +} + +void nes_sgboog_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + + m_mode = 0x04; + m_reg[0] = 0x00; + m_reg[1] = 0xff; + m_reg[2] = 0; + mmc3_common_initialize(0x1f, 0xff, 0); + set_prg(m_prg_base, m_prg_mask); + set_chr(m_chr_source, m_chr_base, m_chr_mask); +} + +void nes_kasing_device::device_start() +{ + mmc3_start(); + save_item(NAME(m_reg)); +} + +void nes_kasing_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + + m_reg = 0; + mmc3_common_initialize(0xff, 0xff, 0); +} + + +void nes_kay_device::device_start() +{ + mmc3_start(); + save_item(NAME(m_low_reg)); + save_item(NAME(m_reg)); +} + +void nes_kay_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + + memset(m_reg, 0, sizeof(m_reg)); + m_low_reg = 0; + mmc3_common_initialize(0xff, 0xff, 0); +} + + +void nes_h2288_device::device_start() +{ + mmc3_start(); + save_item(NAME(m_reg)); +} + +void nes_h2288_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + + m_reg[0] = 0; + m_reg[1] = 0; + mmc3_common_initialize(0xff, 0xff, 0); +} + +void nes_6035052_device::device_start() +{ + mmc3_start(); + save_item(NAME(m_prot)); +} + +void nes_6035052_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + mmc3_common_initialize(0xff, 0xff, 0); + + m_prot = 0; +} + +void nes_kof96_device::device_start() +{ + mmc3_start(); + save_item(NAME(m_reg)); +} + +void nes_kof96_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + memset(m_reg, 0, sizeof(m_reg)); + mmc3_common_initialize(0xff, 0xff, 0); +} + +void nes_gouder_device::device_start() +{ + mmc3_start(); + save_item(NAME(m_reg)); +} + +void nes_gouder_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + memset(m_reg, 0, sizeof(m_reg)); + mmc3_common_initialize(0xff, 0xff, 0); +} + +void nes_sa9602b_device::device_start() +{ + mmc3_start(); + save_item(NAME(m_reg)); + save_item(NAME(m_prg_chip)); +} + +void nes_sa9602b_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + + m_reg = 0; + m_prg_chip = 0; + mmc3_common_initialize(0x1ff, 0xff, 0); // 1.5MB of PRG-ROM, no CHR-ROM but 32K CHR-RAM +} + +void nes_sachen_shero_device::device_start() +{ + mmc3_start(); + save_item(NAME(m_reg)); +} + +void nes_sachen_shero_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + + m_reg = 0; + mmc3_common_initialize(0xff, 0x1ff, 0); +} + +void nes_fk23c_device::device_start() +{ + mmc3_start(); + save_item(NAME(m_reg)); + save_item(NAME(m_mmc_cmd1)); +} + +void nes_fk23c_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + + m_mmc_cmd1 = 0; + m_reg[0] = 4; + m_reg[1] = 0xff; + m_reg[2] = m_reg[3] = 0; + m_reg[4] = m_reg[5] = m_reg[6] = m_reg[7] = 0xff; + mmc3_common_initialize(0xff, 0xff, 0); + fk23c_set_prg(); + fk23c_set_chr(); + +} + +void nes_fk23ca_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + + m_mmc_cmd1 = 0; + m_reg[0] = m_reg[1] = m_reg[2] = m_reg[3] = 0; + m_reg[4] = m_reg[5] = m_reg[6] = m_reg[7] = 0xff; + mmc3_common_initialize(0xff, 0xff, 0); + fk23c_set_prg(); + fk23c_set_chr(); +} + +void nes_s24in1sc03_device::device_start() +{ + mmc3_start(); + save_item(NAME(m_reg)); +} + +void nes_s24in1sc03_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + + m_reg[0] = 0x24; + m_reg[1] = 0x9f; + m_reg[2] = 0; + mmc3_common_initialize(0xff, 0xff, 0); +} + +void nes_bmc_15in1_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + + mmc3_common_initialize(0x1f, 0xff, 0); + m_prg_base = 0x10; // this board has a diff prg_base + set_prg(m_prg_base, m_prg_mask); +} + +void nes_bmc_sbig7_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + mmc3_common_initialize(0x0f, 0x7f, 0); +} + +void nes_bmc_hik8_device::device_start() +{ + mmc3_start(); + save_item(NAME(m_reg)); + save_item(NAME(m_count)); +} + +void nes_bmc_hik8_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + + m_count = 0; + memset(m_reg, 0, sizeof(m_reg)); + mmc3_common_initialize(0x3f, 0xff, 0); +} + +void nes_bmc_hik4_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + mmc3_common_initialize(0x0f, 0x7f, 0); +} + +void nes_bmc_mario7in1_device::device_start() +{ + mmc3_start(); + save_item(NAME(m_reg_written)); +} + +void nes_bmc_mario7in1_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + + m_reg_written = 0; + mmc3_common_initialize(0x1f, 0xff, 0); +} + +void nes_bmc_gold7in1_device::device_start() +{ + mmc3_start(); + save_item(NAME(m_reg_written)); +} + +void nes_bmc_gold7in1_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + + m_reg_written = 0; + mmc3_common_initialize(0x1f, 0xff, 0); +} + +void nes_bmc_gc6in1_device::device_start() +{ + mmc3_start(); + save_item(NAME(m_reg)); +} + +void nes_bmc_gc6in1_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + + m_reg[0] = 0x00; + m_reg[1] = 0xff; + m_reg[2] = 0x03; + m_reg[3] = 0; + mmc3_common_initialize(0xff, 0xff, 0); + set_prg(m_prg_base, m_prg_mask); + set_chr(m_chr_source, m_chr_base, m_chr_mask); +} + +void nes_bmc_411120c_device::device_start() +{ + mmc3_start(); + save_item(NAME(m_reg)); +} + +void nes_bmc_411120c_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + + m_reg = 0; + mmc3_common_initialize(0x7f, 0x7f, 0); +} + +void nes_bmc_830118c_device::device_start() +{ + mmc3_start(); + save_item(NAME(m_reg)); +} + +void nes_bmc_830118c_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + + m_reg = 0; + mmc3_common_initialize(0x7f, 0x7f, 0); +} + +void nes_pjoy84_device::device_start() +{ + mmc3_start(); + save_item(NAME(m_reg)); +} + +void nes_pjoy84_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + + memset(m_reg, 0, sizeof(m_reg)); + set_base_mask(); + mmc3_common_initialize(m_prg_mask, m_chr_mask, 0); +} + + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +/*------------------------------------------------- + + Bootleg Board by Nitra + + Games: Time Diver Avenger + + This acts basically like a MMC3 with different use of write + address. + + iNES: mapper 250 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_nitra_device::write_h) +{ + LOG_MMC(("nitra write_h, offset: %04x, data: %02x\n", offset, data)); + + txrom_write(space, (offset & 0x6000) | ((offset & 0x400) >> 10), offset & 0xff, mem_mask); +} + +/*------------------------------------------------- + + Board UNL-KS7057 + + Games: Street Fighter VI / Fight Street VI + + MMC3 clone (identical, but for switched address lines) + + In MESS: Supported + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_ks7057_device::write_h) +{ + LOG_MMC(("ks7057 write_h, offset: %04x, data: %02x\n", offset, data)); + + offset = (BIT(offset, 0) << 1) | BIT(offset, 1) | (offset & ~0x03); + txrom_write(space, offset, data, mem_mask); +} + +/*------------------------------------------------- + + BTL-SUPERBROS11 + + Games: Super Mario Bros. 11, Super Mario Bros. 17 + + This acts basically like a MMC3 with different use of write + address. + + iNES: mapper 196 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_sbros11_device::write_h) +{ + LOG_MMC(("smb11 write_h, offset: %04x, data: %02x\n", offset, data)); + + txrom_write(space, (offset & 0x6000) | ((offset & 0x04) >> 2), data, mem_mask); +} + +/*------------------------------------------------- + + UNL-MALISB + + Games: Super Mali Bros Splash Bomb + + This is very similar to mapper 196, but with additional + data bit swap. + + In MESS: Supported. + + -------------------------------------------------*/ + +void nes_malisb_device::prg_cb(int start, int bank) +{ + bank = (bank & 3) | ((bank & 8) >> 1) | ((bank & 4) << 1); + prg8_x(start, bank); +} + +void nes_malisb_device::chr_cb(int start, int bank, int source) +{ + bank = (bank & 0xdd) | ((bank & 0x20) >> 4) | ((bank & 2) << 4); + chr1_x(start, bank, source); +} + +WRITE8_MEMBER(nes_malisb_device::write_h) +{ + LOG_MMC(("malisb write_h, offset: %04x, data: %02x\n", offset, data)); + + if (offset > 0x4000) + txrom_write(space, (offset & 0xfffe) | ((offset & 0x04) >> 2) | ((offset & 0x08) >> 3), data, mem_mask); + else + txrom_write(space, (offset & 0xfffe) | ((offset & 0x08) >> 3), data, mem_mask); +} + +/*------------------------------------------------- + + BMC-FAMILY-4646B + + Known Boards: Unknown Multigame Bootleg Board (4646B) + Games: 2 in 1 - Family Kid & Aladdin 4 + + MMC3 clone + + iNES: mapper 134 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_family4646_device::write_m) +{ + LOG_MMC(("family4646 write_m, offset: %04x, data: %02x\n", offset, data)); + + if (offset == 0x01) + { + m_prg_base = (data & 0x02) << 4; + m_prg_mask = 0x1f; + m_chr_base = (data & 0x20) << 3; + m_chr_mask = 0xff; + set_prg(m_prg_base, m_prg_mask); + set_chr(m_chr_source, m_chr_base, m_chr_mask); + } +} + +/*------------------------------------------------- + + BTL-PIKACHUY2K + + Games: Pikachu Y2k + + iNES: mapper 254 + + In MESS: + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_pikay2k_device::write_h) +{ + LOG_MMC(("pikay2k write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x6001) + { + case 0x2001: + m_reg[1] = data; + break; + + case 0x2000: + m_reg[0] = 0; + default: + txrom_write(space, offset, data, mem_mask); + break; + } +} + +// strange WRAM usage: it is protected at start, and gets unprotected after the first write to 0xa000 +WRITE8_MEMBER(nes_pikay2k_device::write_m) +{ + LOG_MMC(("pikay2k write_m, offset: %04x, data: %02x\n", offset, data)); + + m_prgram[offset & 0x1fff] = data; +} + +READ8_MEMBER(nes_pikay2k_device::read_m) +{ + LOG_MMC(("pikay2k read_m, offset: %04x\n", offset)); + + return m_prgram[offset & 0x1fff] ^ (m_reg[0] & m_reg[1]); +} + +/*------------------------------------------------- + + Board UNL-8237 + + Games: Pocahontas 2 + + MMC3 clone + + In MESS: Supported + + -------------------------------------------------*/ + +void nes_8237_device::prg_cb(int start, int bank) +{ + if (!(m_reg[0] & 0x80)) + prg8_x(start, bank); +} + +void nes_8237_device::chr_cb(int start, int bank, int source) +{ + bank |= ((m_reg[1] << 6) & 0x100); + chr1_x(start, bank, source); +} + +WRITE8_MEMBER(nes_8237_device::write_l) +{ + LOG_MMC(("unl_8237 write_l, offset: %04x, data: %02x\n", offset, data)); + offset += 0x100; + + if (offset == 0x1000) + { + m_reg[0] = data; + if (m_reg[0] & 0x80) + { + if (m_reg[0] & 0x20) + prg32((m_reg[0] & 0x0f) >> 1); + else + { + prg16_89ab(m_reg[0] & 0x1f); + prg16_cdef(m_reg[0] & 0x1f); + } + } + else + set_prg(m_prg_base, m_prg_mask); + } + + if (offset == 0x1001) + { + m_reg[1] = data; + set_chr(m_chr_source, m_chr_base, m_chr_mask); + } + + if (offset == 0x1007) + { + m_reg[2] = data & 0x07; // this selects different permutations for addresses and regs (to be implemented) + } +} + +WRITE8_MEMBER(nes_8237_device::write_h) +{ + static const UINT8 conv_table[8] = {0, 2, 6, 1, 7, 3, 4, 5}; + LOG_MMC(("unl_8237 write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x7000) + { + case 0x0000: + case 0x1000: + set_nt_mirroring((data | (data >> 7)) & 0x01 ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + break; + + case 0x2000: + case 0x3000: + m_cd_enable = 1; + data = (data & 0xc0) | conv_table[data & 0x07]; + txrom_write(space, 0x0000, data, mem_mask); + break; + + case 0x4000: + case 0x5000: + if (m_cd_enable) + { + m_cd_enable = 0; + txrom_write(space, 0x0001, data, mem_mask); + } + break; + + case 0x6000: + break; + + case 0x7000: + txrom_write(space, 0x6001, data, mem_mask); + txrom_write(space, 0x4000, data, mem_mask); + txrom_write(space, 0x4001, data, mem_mask); + break; + } +} + +/*------------------------------------------------- + + Bootleg Board by Super Game + + Games: The Lion King + + MMC3 clone. + + iNES: mapper 114 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_sglionk_device::write_m) +{ + LOG_MMC(("sglionk write_m, offset: %04x, data: %02x\n", offset, data)); + + m_reg = data; + + if (m_reg & 0x80) + { + prg16_89ab(data & 0x1f); + prg16_cdef(data & 0x1f); + } + else + set_prg(m_prg_base, m_prg_mask); + +} + +WRITE8_MEMBER(nes_sglionk_device::write_h) +{ + static const UINT8 conv_table[8] = {0, 3, 1, 5, 6, 7, 2, 4}; + LOG_MMC(("sglionk write_h, offset: %04x, data: %02x\n", offset, data)); + + if (offset < 0x6000) + { + switch (offset & 0x6000) + { + case 0x0000: + set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + break; + case 0x2000: + m_reg_enabled = 1; + data = (data & 0xc0) | conv_table[data & 0x07]; + txrom_write(space, 0x0000, data, mem_mask); + break; + case 0x4000: + if (m_reg_enabled && (m_reg & 0x80) == 0) + { + m_reg_enabled = 0; + txrom_write(space, 0x0001, data, mem_mask); + } + break; + } + } + else + { + switch (offset & 0x03) + { + case 0x02: + txrom_write(space, 0x6000, data, mem_mask); + break; + case 0x03: + txrom_write(space, 0x6001, data, mem_mask); + txrom_write(space, 0x4000, data, mem_mask); + txrom_write(space, 0x4001, data, mem_mask); + break; + } + } +} + +/*------------------------------------------------- + + Bootleg Board by Super Game + + Games: Boogerman, Mortal Kombat III + + MMC3 clone. Also, it probably needs a hack to support both + variants (Boogerman & MK3). + + iNES: mapper 215 + + In MESS: Preliminary support. + + -------------------------------------------------*/ + +void nes_sgboog_device::prg_cb(int start, int bank) +{ + if (!(m_reg[0] & 0x80)) // if this is != 0 we should never even arrive here + { + if (m_reg[1] & 0x08) + bank = (bank & 0x1f) | 0x20; + else + bank = (bank & 0x0f) | (m_reg[1] & 0x10); + + prg8_x(start, bank); + } +} + +void nes_sgboog_device::chr_cb(int start, int bank, int source) +{ + if ((m_reg[1] & 0x04)) + bank |= 0x100; + else + bank = (bank & 0x7f) | ((m_reg[1] & 0x10) << 3); + + chr1_x(start, bank, source); +} + +void nes_sgboog_device::set_prg(int prg_base, int prg_mask) +{ + if (m_reg[0] & 0x80) + { + prg16_89ab((m_reg[0] & 0xf0) | (m_reg[1] & 0x10)); + prg16_cdef((m_reg[0] & 0xf0) | (m_reg[1] & 0x10)); + } + else + { + // here standard MMC3 bankswitch + UINT8 prg_flip = (m_latch & 0x40) ? 2 : 0; + + prg_cb(0, prg_base | (m_mmc_prg_bank[0 ^ prg_flip] & prg_mask)); + prg_cb(1, prg_base | (m_mmc_prg_bank[1] & prg_mask)); + prg_cb(2, prg_base | (m_mmc_prg_bank[2 ^ prg_flip] & prg_mask)); + prg_cb(3, prg_base | (m_mmc_prg_bank[3] & prg_mask)); + } +} + +WRITE8_MEMBER(nes_sgboog_device::write_l) +{ + LOG_MMC(("sgboog write_l, offset: %04x, data: %02x\n", offset, data)); + offset += 0x100; + + if (offset == 0x1000) + { + m_reg[0] = data; + set_prg(m_prg_base, m_prg_mask); + } + else if (offset == 0x1001) + { + m_reg[1] = data; + set_chr(m_chr_source, m_chr_base, m_chr_mask); + } + else if (offset == 0x1007) + { + m_latch = 0; + m_mode = data; + set_prg(m_prg_base, m_prg_mask); + set_chr(m_chr_source, m_chr_base, m_chr_mask); + } +} + +WRITE8_MEMBER(nes_sgboog_device::write_m) +{ + LOG_MMC(("sgboog write_m, offset: %04x, data: %02x\n", offset, data)); + + if (offset == 0x0000) + { + m_reg[0] = data; + set_prg(m_prg_base, m_prg_mask); + } + else if (offset == 0x0001) + { + m_reg[1] = data; + set_chr(m_chr_source, m_chr_base, m_chr_mask); + } + else if (offset == 0x0007) + { + m_latch = 0; + m_mode = data; + set_prg(m_prg_base, m_prg_mask); + set_chr(m_chr_source, m_chr_base, m_chr_mask); + } +} + +WRITE8_MEMBER(nes_sgboog_device::write_h) +{ + static const UINT8 conv_table[8] = {0,2,5,3,6,1,7,4}; + LOG_MMC(("sgboog write_h, offset: %04x, data: %02x\n", offset, data)); + + if (m_mode) + { + switch (offset & 0x6001) + { + case 0x0000: + break; + + case 0x0001: + if (m_reg[2] && ((m_reg[0] & 0x80) == 0 || (m_latch & 0x07) < 6)) // if we use the prg16 banks and cmd=6,7 DON'T enter! + { + m_reg[2] = 0; + txrom_write(space, 0x0001, data, mem_mask); + } + break; + + case 0x2000: + data = (data & 0xc0) | conv_table[data & 0x07]; + m_reg[2] = 1; + txrom_write(space, 0x0000, data, mem_mask); + break; + + case 0x4000: + set_nt_mirroring(((data >> 7) | data) & 0x01 ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + break; + + case 0x4001: + txrom_write(space, 0x6001, data, mem_mask); + break; + + case 0x6001: + txrom_write(space, 0x4000, data, mem_mask); + txrom_write(space, 0x4001, data, mem_mask); + break; + + default: + txrom_write(space, offset, data, mem_mask); + break; + } + } + else + txrom_write(space, offset, data, mem_mask); +} + +/*------------------------------------------------- + + Bootleg Board by Kasing + + Games: AV Jiu Ji Mahjong, Bao Qing Tian, Thunderbolt 2, + Shisen Mahjong 2 + + MMC3 clone + + iNES: mapper 115 + + In MESS: Supported + + -------------------------------------------------*/ + +void nes_kasing_device::prg_cb(int start, int bank) +{ + if (BIT(m_reg, 7)) + prg32(m_reg >> 1); + else + prg8_x(start, bank); +} + +WRITE8_MEMBER(nes_kasing_device::write_m) +{ + LOG_MMC(("kasing write_m, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x01) + { + case 0x00: + m_reg = data; + set_prg(m_prg_base, m_prg_mask); + break; + case 0x01: + m_chr_base = (data & 0x01) ? 0x100 : 0x000; + set_chr(m_chr_source, m_chr_base, m_chr_mask); + break; + } +} + +/*------------------------------------------------- + + Bootleg Board by Kay (for Panda Prince) + + Games: The Panda Prince, Sonic 3d Blast 6, SFZ2 '97, YuYu '97 + (and its title hack MK6), UMK3, Super Lion King 2 + + MMC3 clone. This is basically KOF96 board + protection + + iNES: mapper 121 + + In MESS: Most game works, with some graphical issues. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_kay_device::write_l) +{ + LOG_MMC(("kay write_l, offset: %04x, data: %02x\n", offset, data)); + offset += 0x100; + + if (offset >= 0x1000) + { + switch (data & 0x03) + { + case 0x00: + case 0x01: + m_low_reg = 0x83; + break; + case 0x02: + m_low_reg = 0x42; + break; + case 0x03: + m_low_reg = 0x00; + break; + } + } +} + +READ8_MEMBER(nes_kay_device::read_l) +{ + LOG_MMC(("kay read_l, offset: %04x\n", offset)); + offset += 0x100; + + if (offset >= 0x1000) + return m_low_reg; + else + return 0xff; +} + +void nes_kay_device::update_regs() +{ + switch (m_reg[5] & 0x3f) + { + case 0x20: + case 0x29: + case 0x2b: + case 0x3f: + m_reg[7] = 1; + m_reg[1] = m_reg[6]; + break; + case 0x26: + m_reg[7] = 0; + m_reg[1] = m_reg[6]; + break; + case 0x2c: + m_reg[7] = 1; + if (m_reg[6]) + m_reg[1] = m_reg[6]; + break; + + case 0x28: + m_reg[7] = 0; + m_reg[2] = m_reg[6]; + break; + + case 0x2a: + m_reg[7] = 0; + m_reg[3] = m_reg[6]; + break; + + case 0x2f: + break; + + default: + m_reg[5] = 0; + break; + } +} + +void nes_kay_device::prg_cb(int start, int bank) +{ + if (m_reg[5] & 0x3f) + { + prg8_x(start, bank & 0x3f); + prg8_ef(m_reg[1]); + prg8_cd(m_reg[2]); + prg8_ab(m_reg[3]); + } + else + prg8_x(start, bank & 0x3f); +} + +void nes_kay_device::chr_cb(int start, int bank, int source) +{ + UINT8 chr_page = (m_latch & 0x80) >> 5; + + if ((start & 0x04) == chr_page) + bank |= 0x100; + + chr1_x(start, bank, source); +} + +WRITE8_MEMBER(nes_kay_device::write_h) +{ + LOG_MMC(("kay write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x6003) + { + case 0x0000: + txrom_write(space, offset, data, mem_mask); + set_prg(m_prg_base, m_prg_mask); + break; + + case 0x0001: + m_reg[6] = (BIT(data, 0) << 5) | (BIT(data, 1) << 4) | (BIT(data, 2) << 3) + | (BIT(data, 3) << 2) | (BIT(data, 4) << 1) | BIT(data, 5); + if (!m_reg[7]) + update_regs(); + txrom_write(space, offset, data, mem_mask); + set_prg(m_prg_base, m_prg_mask); + break; + + case 0x0003: + m_reg[5] = data; + update_regs(); + txrom_write(space, 0x0000, data, mem_mask); + set_prg(m_prg_base, m_prg_mask); + break; + + default: + txrom_write(space, offset, data, mem_mask); + break; + } +} + +/*------------------------------------------------- + + UNL-H2288 + + -------------------------------------------------*/ + +void nes_h2288_device::prg_cb(int start, int bank) +{ + if (!(m_reg[0] & 0x40)) + prg8_x(start, bank); +} + +WRITE8_MEMBER(nes_h2288_device::write_l) +{ + LOG_MMC(("h2288 write_l, offset: %04x, data: %02x\n", offset, data)); + offset += 0x100; + + if (offset >= 0x1800) + { + m_reg[offset & 1] = data; + if (m_reg[0] & 0x40) + { + UINT8 helper1 = (m_reg[0] & 0x05) | ((m_reg[0] >> 2) & 0x0a); + UINT8 helper2 = BIT(m_reg[0], 1); + prg16_89ab(helper1 & ~helper2); + prg16_cdef(helper1 | helper2); + } + else + set_prg(m_prg_base, m_prg_mask); + } +} + +READ8_MEMBER(nes_h2288_device::read_l) +{ + LOG_MMC(("h2288 read_l, offset: %04x\n", offset)); + offset += 0x100; + + if (offset >= 0x1000) + { + int helper = offset >> 8; + if (offset & 1) + return helper | 0x01; + else + return helper ^ 0x01; + } + + return 0; +} + +WRITE8_MEMBER(nes_h2288_device::write_h) +{ + static const UINT8 conv_table[8] = {0, 3, 1, 5, 6, 7, 2, 4}; + LOG_MMC(("h2288 write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x6001) + { + case 0x0000: + txrom_write(space, 0x0000, (data & 0xc0) | conv_table[data & 0x07], mem_mask); + break; + + default: + txrom_write(space, offset, data, mem_mask); + break; + } +} + +/*------------------------------------------------- + + UNL-603-5052 + + MMC3 + protection access in 0x4020 - 0x7fff + + in MESS: Partial support + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_6035052_device::write_ex) +{ + LOG_MMC(("6035052 write_ex, offset: %04x, data: %02x\n", offset, data)); + m_prot = data & 0x03; + if (m_prot == 1) + m_prot = 2; +} + +READ8_MEMBER(nes_6035052_device::read_ex) +{ + LOG_MMC(("6035052 read_ex, offset: %04x\n", offset)); + return m_prot; +} + +/*------------------------------------------------- + + Bootleg Board 'Thunder Warrior' by TXC + + Games: Master Fighter II, Master Fighter 3, Thunder Warrior + + MMC3 clone + + iNES: mapper 189 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_txc_tw_device::write_l) +{ + LOG_MMC(("txc_tw write_l, offset: %04x, data: %02x\n", offset, data)); + + prg32((data >> 4) | data); +} + +/* writes to 0x8000-0xffff are like MMC3 but no PRG bankswitch (beacuse it is handled by low writes) */ +void nes_txc_tw_device::prg_cb(int start, int bank) +{ + return; +} + +/*------------------------------------------------- + + Board UNL-KOF97 + + Games: King of Fighters 97 (Rex Soft) + + MMC3 clone + + In MESS: Not working + + -------------------------------------------------*/ + +inline UINT8 kof97_unscramble( UINT8 data ) +{ + return ((data >> 1) & 0x01) | ((data >> 4) & 0x02) | ((data << 2) & 0x04) | ((data >> 0) & 0xd8) | ((data << 3) & 0x20); +} + +WRITE8_MEMBER(nes_kof97_device::write_h) +{ + LOG_MMC(("kof97 write_h, offset: %04x, data: %02x\n", offset, data)); + + /* Addresses 0x9000, 0xa000, 0xd000 & 0xf000 behaves differently than MMC3 */ + if (offset == 0x1000) + txrom_write(space, 0x0001, kof97_unscramble(data), mem_mask); + else if (offset == 0x2000) + txrom_write(space, 0x0000, kof97_unscramble(data), mem_mask); + else if (offset == 0x5000) + txrom_write(space, 0x4001, kof97_unscramble(data), mem_mask); + else if (offset == 0x7000) + txrom_write(space, 0x6001, kof97_unscramble(data), mem_mask); + /* Other addresses behaves like MMC3, up to unscrambling data */ + else + txrom_write(space, offset, kof97_unscramble(data), mem_mask); +} + +/*------------------------------------------------- + + Bootleg Board for KOF96 + + Games: The King of Fighters 96, Sonic 3D Blast 6, Street + Fighter Zero 2 + + MMC3 clone + + iNES: mapper 187 + + In MESS: Preliminary Support. + + -------------------------------------------------*/ + +void nes_kof96_device::prg_cb(int start, int bank) +{ + if (!(m_reg[0] & 0x80)) + prg8_x(start, bank); +} + +void nes_kof96_device::chr_cb(int start, int bank, int source) +{ + UINT8 chr_page = (m_latch & 0x80) >> 5; + + if ((start & 0x04) == chr_page) + bank |= 0x100; + + chr1_x(start, bank, source); +} + +WRITE8_MEMBER(nes_kof96_device::write_l) +{ + UINT8 new_bank; + LOG_MMC(("kof96 write_l, offset: %04x, data: %02x\n", offset, data)); + offset += 0x100; + + if (offset == 0x1000) + { + m_reg[0] = data; + + if (m_reg[0] & 0x80) + { + new_bank = (m_reg[0] & 0x1f); + + if (m_reg[0] & 0x20) + prg32(new_bank >> 2); + else + { + prg16_89ab(new_bank); + prg16_cdef(new_bank); + } + } + else + set_prg(m_prg_base, m_prg_mask); + } + + if (offset >= 0x1000) + { + switch (data & 0x03) + { + case 0x00: + case 0x01: + m_reg[1] = 0x83; + break; + case 0x02: + m_reg[1] = 0x42; + break; + case 0x03: + m_reg[1] = 0x00; + break; + } + + } + + if (!m_reg[3] && offset > 0x1000) + { + m_reg[3] = 1; + space.write_byte(0x4017, 0x40); + } +} + +READ8_MEMBER(nes_kof96_device::read_l) +{ + LOG_MMC(("kof96 read_l, offset: %04x\n", offset)); + offset += 0x100; + + if (!(offset < 0x1000)) + return m_reg[1]; + else + return 0; +} + +WRITE8_MEMBER(nes_kof96_device::write_h) +{ + LOG_MMC(("kof96 write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x6003) + { + case 0x0000: + m_reg[2] = 1; + txrom_write(space, 0x0000, data, mem_mask); + break; + + case 0x0001: + if (m_reg[2]) + txrom_write(space, 0x0001, data, mem_mask); + break; + + case 0x0002: + break; + + case 0x0003: + m_reg[2] = 0; + + if (data == 0x28) + prg8_cd(0x17); + else if (data == 0x2a) + prg8_ab(0x0f); + break; + + default: + txrom_write(space, offset, data, mem_mask); + break; + } +} + +/*------------------------------------------------- + + Bootleg Board for Super Fighter III + + MMC3 clone + + iNES: mapper 197 + + In MESS: Supported. + + -------------------------------------------------*/ + +void nes_sf3_device::set_chr(UINT8 chr_source, int chr_base, int chr_mask) +{ + chr4_0(chr_base | ((m_mmc_vrom_bank[0] >> 1) & chr_mask), chr_source); + chr2_4(chr_base | (m_mmc_vrom_bank[1] & chr_mask), chr_source); + chr2_6(chr_base | (m_mmc_vrom_bank[2] & chr_mask), chr_source); +} + +WRITE8_MEMBER(nes_sf3_device::write_h) +{ + UINT8 cmd; + LOG_MMC(("sf3 write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x6001) + { + case 0x0001: + cmd = m_latch & 0x07; + switch (cmd) + { + case 0: case 2: case 4: + m_mmc_vrom_bank[cmd >> 1] = data; + set_chr(m_chr_source, m_chr_base, m_chr_mask); + break; + case 6: + case 7: + m_mmc_prg_bank[cmd - 6] = data; + set_prg(m_prg_base, m_prg_mask); + break; + } + break; + + default: + txrom_write(space, offset, data, mem_mask); + break; + } +} + +/*------------------------------------------------- + + Bootleg Board 37017 (?) by Gouder + + Games: Street Fighter IV + + MMC3 clone. It also requires reads from 0x5000-0x7fff. + + iNES: mapper 208 + + In MESS: Preliminary Support. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_gouder_device::write_l) +{ + static const UINT8 conv_table[256] = + { + 0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x49,0x19,0x09,0x59,0x49,0x19,0x09, + 0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x51,0x41,0x11,0x01,0x51,0x41,0x11,0x01, + 0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x49,0x19,0x09,0x59,0x49,0x19,0x09, + 0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x51,0x41,0x11,0x01,0x51,0x41,0x11,0x01, + 0x00,0x10,0x40,0x50,0x00,0x10,0x40,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x08,0x18,0x48,0x58,0x08,0x18,0x48,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x10,0x40,0x50,0x00,0x10,0x40,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x08,0x18,0x48,0x58,0x08,0x18,0x48,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x58,0x48,0x18,0x08,0x58,0x48,0x18,0x08, + 0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x50,0x40,0x10,0x00,0x50,0x40,0x10,0x00, + 0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x58,0x48,0x18,0x08,0x58,0x48,0x18,0x08, + 0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x50,0x40,0x10,0x00,0x50,0x40,0x10,0x00, + 0x01,0x11,0x41,0x51,0x01,0x11,0x41,0x51,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x09,0x19,0x49,0x59,0x09,0x19,0x49,0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x11,0x41,0x51,0x01,0x11,0x41,0x51,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x09,0x19,0x49,0x59,0x09,0x19,0x49,0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 + }; + + LOG_MMC(("gouder write_l, offset: %04x, data: %02x\n", offset, data)); + + if (!(offset < 0x1700)) + m_reg[offset & 0x03] = data ^ conv_table[m_reg[4]]; + else if (!(offset < 0xf00)) + m_reg[4] = data; + else if (!(offset < 0x700)) + prg32(((data >> 3) & 0x02) | (data & 0x01)); +} + +READ8_MEMBER(nes_gouder_device::read_l) +{ + LOG_MMC(("gouder read_l, offset: %04x\n", offset)); + + if (!(offset < 0x1700)) + return m_reg[offset & 0x03]; + + return 0x00; +} + +/* writes to 0x8000-0xffff are like MMC3 but no PRG bankswitch (beacuse it is handled by low writes) */ +void nes_gouder_device::prg_cb(int start, int bank) +{ + return; +} + + +/*------------------------------------------------- + + UNL-SA-9602B + + Sachen boards used for a chinese port of Princess Maker (?) + + in MESS: Very Preliminary support, based on Cah4e3 + code in FCEUMM + + -------------------------------------------------*/ + +void nes_sa9602b_device::prg_cb(int start, int bank) +{ + if (m_prg_chip == 3) + { + printf("Accessing PRG beyond end of ROM!\n"); + m_prg_chip = 2; // assume that the higher PRG chip is mirrored twice + } + prg8_x(start, (m_prg_chip * 0x40) | (bank & 0x3f)); + + if (m_latch & 0x40) + prg8_89(0x3e); + else + prg8_cd(0x3e); + + prg8_ef(0x3f); +// printf("start %d, bank %d\n", start, bank); +} + + +WRITE8_MEMBER( nes_sa9602b_device::write_h ) +{ + LOG_MMC(("sa9602b write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x6001) + { + case 0x0000: + m_reg = data; + break; + case 0x0001: + if ((m_reg & 7) < 6) + m_prg_chip = (data & 0xc0) >> 6; + set_prg(0, m_prg_mask); + break; + } + + txrom_write(space, offset, data, mem_mask); +} + +/*------------------------------------------------- + + UNL-SHERO + + Sachen boards used for Street Heroes + + in MESS: Very Preliminary support + + -------------------------------------------------*/ + + +void nes_sachen_shero_device::chr_cb( int start, int bank, int source ) +{ + int shift = start < 2 ? 5 : + start < 4 ? 6 : + start < 6 ? 8 : 7; + if (!BIT(m_reg, 6)) + chr1_x(start, ((m_reg << shift) & 0x100) | bank, source); +} + + +WRITE8_MEMBER( nes_sachen_shero_device::write_l ) +{ + LOG_MMC(("shero write_l, offset: %04x, data: %02x\n", offset, data)); + offset += 0x4100; + + if (offset == 0x4100) + { + m_reg = data; + if (BIT(m_reg, 6)) + chr8(0, CHRRAM); + else + set_chr(m_chr_source, m_chr_base, m_chr_mask); + } +} + +READ8_MEMBER( nes_sachen_shero_device::read_l ) +{ + LOG_MMC(("shero read_l, offset: %04x\n", offset)); + offset += 0x4100; + + if (offset == 0x4100) + { + // DSW read! + } + return m_open_bus; // open bus +} + + + +/*------------------------------------------------- + + MULTIGAME CARTS BASED ON MMC3 + + -------------------------------------------------*/ + + /*------------------------------------------------- + + Board BMC-FK23C + + MMC3 clone + + In MESS: partially supported (still to sort initial banking + for many games) + + -------------------------------------------------*/ + +#if 0 +// alt version... +void nes_fk23c_device::prg_cb(int start, int bank) +{ + if (((m_reg[0] & 0x07) - 3) > 1 && (!(m_reg[3] & 0x02) || start < 2)) + { + if (m_reg[0] & 0x03) + bank = (bank & (0x3f >> (m_reg[0] & 0x03))) | (m_reg[1] << 1); + + prg8_x(start, bank); + } +} + +void nes_fk23c_device::chr_cb(int start, int bank, int source) +{ + if (!(m_reg[0] & 0x40) && (!(m_reg[3] & 0x02) || (start != 1 && start != 3))) + chr1_x(start, ((m_reg[2] & 0x7f) << 3) | bank, source); +} + +#endif + +void nes_fk23c_device::prg_cb(int start, int bank) +{ + UINT8 mask = (0x3f >> (m_reg[0] & 0x03)); + + if ((m_reg[0] & 0x07) < 3) + { + if (!(m_reg[0] & 0x03)) + bank = (bank & mask) | ((m_reg[1] & (0x7f ^ mask)) << 1); + + prg8_x(start, bank); + } +} + +void nes_fk23c_device::chr_cb(int start, int bank, int source) +{ + if (!(m_reg[0] & 0x40) && (!(m_reg[3] & 0x02) || (start != 1 && start != 3))) + chr1_x(start, ((m_reg[2] & 0x7f) << 3) | bank, source); +} + +void nes_fk23c_device::fk23c_set_prg() +{ + if ((m_reg[0] & 0x07) == 4) + prg32((m_reg[1] & 0x7f) >> 1); + else if ((m_reg[0] & 0x07) == 3) + { + prg16_89ab(m_reg[1] & 0x7f); + prg16_cdef(m_reg[1] & 0x7f); + } + else + { + if (m_reg[3] & 0x02) + { + prg8_cd(m_reg[4]); + prg8_ef(m_reg[5]); + } + else + set_prg(m_prg_base, m_prg_mask); + } +} + +void nes_fk23c_device::fk23c_set_chr() +{ + if (m_reg[0] & 0x40) + chr8(m_reg[2] | m_mmc_cmd1, m_chr_source); + else + { + if (m_reg[3] & 0x02) + { + int base = (m_reg[2] & 0x7f) << 3; + chr1_x(1, base | m_reg[6], m_chr_source); + chr1_x(3, base | m_reg[7], m_chr_source); + } + else + set_chr(m_chr_source, m_chr_base, m_chr_mask); + } +} + +WRITE8_MEMBER(nes_fk23c_device::write_l) +{ + LOG_MMC(("fk23c write_l, offset: %04x, data: %02x\n", offset, data)); + offset += 0x100; + + if (offset >= 0x1000) + { + if (offset & (1 << 4)) // here it should be (4 + m_mmc_dipsetting) + { + m_reg[offset & 0x03] = data; + + fk23c_set_prg(); + fk23c_set_chr(); + } + } +} + +WRITE8_MEMBER(nes_fk23c_device::write_h) +{ + LOG_MMC(("fk23c write_h, offset: %04x, data: %02x\n", offset, data)); + + if (m_reg[0] & 0x40) + { + if (m_reg[0] & 0x30) + m_mmc_cmd1 = 0; + else + { + m_mmc_cmd1 = data & 0x03; + fk23c_set_chr(); + } + } + else + { + switch (offset & 0x6001) + { + case 0x0001: + if ((m_reg[3] & 0x02) && (m_latch & 0x08)) + { + m_reg[4 | (m_latch & 0x03)] = data; + fk23c_set_prg(); + fk23c_set_chr(); + } + else + txrom_write(space, offset, data, mem_mask); + break; + + case 0x2000: + set_nt_mirroring(data ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + break; + + default: + txrom_write(space, offset, data, mem_mask); + break; + } + } +} + +/*------------------------------------------------- + + Board BMC-SUPER24IN1SC03 + + Games: Super 24-in-1 + + In MESS: Partially Supported + + -------------------------------------------------*/ + +void nes_s24in1sc03_device::prg_cb(int start, int bank) +{ + static const UINT8 masks[8] = {0x3f, 0x1f, 0x0f, 0x01, 0x03, 0x00, 0x00, 0x00}; + int prg_base = m_reg[1] << 1; + int prg_mask = masks[m_reg[0] & 0x07]; + + bank = prg_base | (bank & prg_mask); + prg8_x(start, bank); +} + +void nes_s24in1sc03_device::chr_cb(int start, int bank, int source) +{ + UINT8 chr = BIT(m_reg[0], 5) ? CHRRAM : CHRROM; + int chr_base = (m_reg[2] << 3) & 0xf00; + + chr1_x(start, chr_base | bank, chr); +} + +WRITE8_MEMBER(nes_s24in1sc03_device::write_l) +{ + LOG_MMC(("s24in1sc03 write_l, offset: %04x, data: %02x\n", offset, data)); + offset += 0x100; + + if (offset == 0x1ff0) + { + m_reg[0] = data; + set_chr(m_chr_source, m_chr_base, m_chr_mask); + set_prg(m_prg_base, m_prg_mask); + } + + if (offset == 0x1ff1) + { + m_reg[1] = data; + set_prg(m_prg_base, m_prg_mask); + } + + if (offset == 0x1ff2) + { + m_reg[2] = data; + set_chr(m_chr_source, m_chr_base, m_chr_mask); + } +} + +/*------------------------------------------------- + + BMC-15IN1 + + Unknown Bootleg Multigame Board + Games: 3 in 1, 15 in 1 + + iNES: mapper 205, MMC3 clone + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_bmc_15in1_device::write_m) +{ + LOG_MMC(("bmc_15in1 write_m, offset: %04x, data: %02x\n", offset, data)); + + if (offset & 0x0800) + { + m_prg_base = (data & 0x03) << 4; + m_prg_mask = (data & 0x02) ? 0x0f : 0x1f; + m_chr_base = (data & 0x03) << 7; + m_chr_mask = (data & 0x02) ? 0x7f : 0xff; + set_prg(m_prg_base, m_prg_mask); + set_chr(m_chr_source, m_chr_base, m_chr_mask); + } +} + +/*------------------------------------------------- + + BMC-SUPERBIG-7IN1 + + Known Boards: Unknown Multigame Bootleg Board + Games: Kunio 8 in 1, Super Big 7 in 1 + + iNES: mapper 44 + + In MESS: Supported. It also uses mmc3_irq. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_bmc_sbig7_device::write_h) +{ + UINT8 page; + LOG_MMC(("bmc_sbig7 write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x6001) + { + case 0x2001: /* $a001 - Select 128K ROM/VROM base (0..5) or last 256K ROM/VRAM base (6) */ + page = (data & 0x07); + if (page > 6) + page = 6; + + m_prg_base = page << 4; + m_prg_mask = (page > 5) ? 0x1f : 0x0f; + m_chr_base = page << 7; + m_chr_mask = (page > 5) ? 0xff : 0x7f; + set_prg(m_prg_base, m_prg_mask); + set_chr(m_chr_source, m_chr_base, m_chr_mask); + break; + + default: + txrom_write(space, offset, data, mem_mask); + break; + } +} + +/*------------------------------------------------- + + BMC-HIK8IN1 + + Known Boards: Unknown Multigame Bootleg Board + Games: Street Fighter V, various multigame carts + + iNES: mapper 45 + + In MESS: Supported. It also uses mmc3_irq. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_bmc_hik8_device::write_m) +{ + LOG_MMC(("bmc_hik8 write_m, offset: %04x, data: %02x\n", offset, data)); + + /* This bit is the "register lock". Once register are locked, writes go to WRAM + and there is no way to unlock them (except by resetting the machine) */ + if ((m_reg[3] & 0x40) && !m_prgram.empty()) + m_prgram[offset] = data; + else + { + m_reg[m_count] = data; + m_count = (m_count + 1) & 0x03; + + if (!m_count) + { + LOG_MMC(("bmc_hik8 write_m, command completed %02x %02x %02x %02x\n", m_reg[3], + m_reg[2], m_reg[1], m_reg[0])); + + m_prg_base = m_reg[1]; + m_prg_mask = 0x3f ^ (m_reg[3] & 0x3f); + m_chr_base = ((m_reg[2] & 0xf0) << 4) | m_reg[0]; + if (BIT(m_reg[2], 3)) + m_chr_mask = (1 << ((m_reg[2] & 7) + 1)) - 1; + else if (m_reg[2]) + m_chr_mask = 0; + else + m_chr_mask = 0xff; // i.e. we use the vrom_bank with no masking + + set_prg(m_prg_base, m_prg_mask); + set_chr(m_chr_source, m_chr_base, m_chr_mask); + } + } +} + +/*------------------------------------------------- + + BMC-SUPERHIK-4IN1 + + Known Boards: Unknown Multigame Bootleg Board + Games: Super HIK 4 in 1 + + iNES: mapper 49 + + In MESS: Supported. It also uses mmc3_irq. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_bmc_hik4_device::write_m) +{ + LOG_MMC(("bmc_hik4 write_m, offset: %04x, data: %02x\n", offset, data)); + + /* mid writes only work when WRAM is enabled. not sure if I should + change the condition to m_mmc_latch2==0x80 (i.e. what is the effect of + the read-only bit?) */ + if (m_wram_protect & 0x80) + { + if (data & 0x01) /* if this is 0, then we have 32k PRG blocks */ + { + m_prg_base = (data & 0xc0) >> 2; + m_prg_mask = 0x0f; + set_prg(m_prg_base, m_prg_mask); + } + else + prg32((data & 0x30) >> 4); + + m_chr_base = (data & 0xc0) << 1; + m_chr_mask = 0x7f; + set_chr(m_chr_source, m_chr_base, m_chr_mask); + } +} + +/*------------------------------------------------- + + BMC-MARIOPARTY-7IN1 + + Known Boards: Unknown Multigame Bootleg Board + Games: Mario 7 in 1 + + MMC3 clone + + iNES: mapper 52 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_bmc_mario7in1_device::write_m) +{ + UINT8 helper1, helper2; + LOG_MMC(("bmc_mario7in1 write_m, offset: %04x, data: %02x\n", offset, data)); + + /* mid writes only work when WRAM is enabled. not sure if I should + change the condition to m_map52_reg_written == 0x80 (i.e. what is the effect of + the read-only bit?) and it only can happen once! */ + if ((m_wram_protect & 0x80) && !m_reg_written) + { + helper1 = (data & 0x08); + helper2 = (data & 0x40); + + m_prg_base = helper1 ? ((data & 0x07) << 4) : ((data & 0x06) << 4); + m_prg_mask = helper1 ? 0x0f : 0x1f; + m_chr_base = ((data & 0x20) << 4) | ((data & 0x04) << 6) | (helper2 ? ((data & 0x10) << 3) : 0); + m_chr_mask = helper2 ? 0x7f : 0xff; + set_prg(m_prg_base, m_prg_mask); + set_chr(m_chr_source, m_chr_base, m_chr_mask); + + m_reg_written = 1; + } + else + m_prgram[offset] = data; +} + +/*------------------------------------------------- + + BMC-GOLD-7IN1 + + Known Boards: Unknown Multigame Bootleg Board + Games: Super HIK Gold 7 in 1, Golden 7 in 1 and many more + + MMC3 clone, same as BMC-MARIOPARTY-7IN1 but with switched CHR + bank lines + + iNES: mapper 52 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_bmc_gold7in1_device::write_m) +{ + UINT8 helper1, helper2; + LOG_MMC(("bmc_gold7in1 write_m, offset: %04x, data: %02x\n", offset, data)); + + if ((m_wram_protect & 0x80) && !m_reg_written) + { + helper1 = (data & 0x08); + helper2 = (data & 0x40); + + m_prg_base = helper1 ? ((data & 0x07) << 4) : ((data & 0x06) << 4); + m_prg_mask = helper1 ? 0x0f : 0x1f; + m_chr_base = ((data & 0x20) << 3) | ((data & 0x04) << 7) | (helper2 ? ((data & 0x10) << 3) : 0); + m_chr_mask = helper2 ? 0x7f : 0xff; + set_prg(m_prg_base, m_prg_mask); + set_chr(m_chr_source, m_chr_base, m_chr_mask); + + m_reg_written = BIT(data, 7); // mc_2hikg & mc_s3nt3 write here multiple time + } + else + m_prgram[offset] = data; +} + +/*------------------------------------------------- + + BMC-GOLDENCARD-6IN1 + + Known Boards: Unknown Bootleg Multigame Board + Games: Golden Card 6 in 1 + + MMC3 clone + + iNES: mapper 217 + + In MESS: Supported. + + -------------------------------------------------*/ + +void nes_bmc_gc6in1_device::prg_cb(int start, int bank) +{ + if (m_reg[1] & 0x08) + bank &= 0x1f; + else + { + bank &= 0x0f; + bank |= m_reg[1] & 0x10; + } + + prg8_x(start, bank | ((m_reg[1] & 0x03) << 5)); +} + +void nes_bmc_gc6in1_device::chr_cb(int start, int bank, int source) +{ + if (!(m_reg[1] & 0x08)) + bank = ((m_reg[1] & 0x10) << 3) | (bank & 0x7f); + + + bank |= ((m_reg[1] << 6) & 0x100); + chr1_x(start, ((m_reg[1] & 0x03) << 8) | bank, source); +} + +WRITE8_MEMBER(nes_bmc_gc6in1_device::write_l) +{ + UINT8 bank; + LOG_MMC(("bmc_gc6in1 write_l, offset: %04x, data: %02x\n", offset, data)); + offset += 0x100; + + if (offset == 0x1000) + { + m_reg[0] = data; + if (data & 0x80) + { + bank = (data & 0x0f) | ((m_reg[1] & 0x03) << 4); + prg16_89ab(bank); + prg16_cdef(bank); + } + else + set_prg(m_prg_base, m_prg_mask); + } + else if (offset == 0x1001) + { + m_reg[1] = data; + set_prg(m_prg_base, m_prg_mask); + } + else if (offset == 0x1007) + { + m_reg[2] = data; + } +} + +WRITE8_MEMBER(nes_bmc_gc6in1_device::write_h) +{ + UINT8 cmd; + static const UINT8 conv_table[8] = {0, 6, 3, 7, 5, 2, 4, 1}; + LOG_MMC(("bmc_gc6in1 write_h, offset: %04x, data: %02x\n", offset, data)); + + if (!m_reg[2]) + { + // in this case we act like MMC3, only with alt prg/chr handlers + txrom_write(space, offset, data, mem_mask); + } + else + { + switch (offset & 0x6001) + { + case 0x0000: + txrom_write(space, 0x4000, data, mem_mask); + break; + + case 0x0001: + data = (data & 0xc0) | conv_table[data & 0x07]; + m_reg[3] = 1; + txrom_write(space, 0x0000, data, mem_mask); + break; + + case 0x2000: + cmd = m_latch & 0x07; + if (m_reg[3]) + { + m_reg[3] = 0; + switch (cmd) + { + case 0: case 1: // these do not need to be separated: we take care of them in set_chr! + case 2: case 3: case 4: case 5: + m_mmc_vrom_bank[cmd] = data; + set_chr(m_chr_source, m_chr_base, m_chr_mask); + break; + case 6: + case 7: + m_mmc_prg_bank[cmd - 6] = data; + set_prg(m_prg_base, m_prg_mask); + break; + } + } + break; + + + case 0x2001: + set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + break; + + default: + txrom_write(space, offset, data, mem_mask); + break; + } + } +} + +/*------------------------------------------------- + + BMC-411120C + + + MMC3 clone + + + In MESS: Very Preliminary Support + + -------------------------------------------------*/ + +void nes_bmc_411120c_device::prg_cb(int start, int bank) +{ + if (m_reg & 8) // & 0xc when DSW change (diff menu?) + prg32(((m_reg >> 4) & 3) | 0x0c); + else + prg8_x(start, (bank & 0x0f) | ((m_reg & 0x03) << 4)); +} + +void nes_bmc_411120c_device::chr_cb(int start, int bank, int source) +{ + chr1_x(start, bank | ((m_reg & 3) << 7), source); +} + +WRITE8_MEMBER(nes_bmc_411120c_device::write_m) +{ + LOG_MMC(("bmc_411120c write_m, offset: %04x, data: %02x\n", offset, data)); + + m_reg = data; + set_prg(m_prg_base, m_prg_mask); + set_chr(m_chr_source, m_chr_base, m_chr_mask); +} + +/*------------------------------------------------- + + BMC-830118C + + + MMC3 clone + + + In MESS: Very Preliminary Support + + -------------------------------------------------*/ + +void nes_bmc_830118c_device::prg_cb(int start, int bank) +{ + if ((m_reg & 0x0c) != 0x0c) + prg8_x(start, (bank & 0x0f) | ((m_reg & 0x0c) << 2)); + else + { + if (start == 0) + { + prg8_89((bank & 0x0f) | ((m_reg & 0x0c) << 2)); + prg8_ab((bank & 0x0f) | 0x20); + } + else if (start == 2) + { + prg8_cd((bank & 0x0f) | ((m_reg & 0x0c) << 2)); + prg8_ef((bank & 0x0f) | 0x20); + } + } +} + +void nes_bmc_830118c_device::chr_cb(int start, int bank, int source) +{ + chr1_x(start, (bank & 0x7f) | ((m_reg & 0x0c) << 5), source); +} + +WRITE8_MEMBER(nes_bmc_830118c_device::write_m) +{ + LOG_MMC(("bmc_830118c write_m, offset: %04x, data: %02x\n", offset, data)); + + if (offset >= 0x800 && offset < 0x900) + { + m_reg = data; + set_prg(m_prg_base, m_prg_mask); + set_chr(m_chr_source, m_chr_base, m_chr_mask); + } +} + +/*------------------------------------------------- + + BMC-POWERJOY + + -------------------------------------------------*/ + +void nes_pjoy84_device::prg_cb(int start, int bank) +{ + UINT8 flip = (m_latch & 0x40) ? 2 : 0; + + if (!(m_reg[3] & 0x03)) + prg8_x(start, bank); + else if (start == flip) + { + if ((m_reg[3] & 0x03) == 0x03) + prg32(bank >> 2); + else + { + prg16_89ab(bank >> 1); + prg16_cdef(bank >> 1); + } + } +} + +void nes_pjoy84_device::chr_cb(int start, int bank, int source) +{ + if (!(m_reg[3] & 0x10)) + chr1_x(start, bank, source); +} + +inline void nes_pjoy84_device::set_base_mask() +{ + m_prg_base = ((m_reg[0] & (0x06 | BIT(m_reg[0], 6))) << 4) | + (BIT(m_reg[0], 4) << 7); + + m_chr_base = ((~m_reg[0] << 0) & 0x080 & m_reg[2]) | + ((m_reg[0] << 4) & 0x080 & m_reg[0]) | + ((m_reg[0] << 3) & 0x100) | + ((m_reg[0] << 5) & 0x200); + + m_prg_mask = BIT(m_reg[0], 6) ? 0x0f : 0x1f; + m_chr_mask = BIT(m_reg[0], 7) ? 0x7f : 0xff; +} + +WRITE8_MEMBER(nes_pjoy84_device::write_m) +{ + LOG_MMC(("pjoy84 write_m, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x03) + { + case 0x00: + case 0x03: + if (m_reg[3] & 0x80) + return; // else we act as if offset & 3 = 1,2 + case 0x01: + case 0x02: + m_reg[offset & 0x03] = data; + set_base_mask(); + if (m_reg[3] & 0x10) + chr8((m_chr_base >> 3) | (m_reg[2] & 0x0f), m_chr_source); + else + set_chr(m_chr_source, m_chr_base, m_chr_mask); + set_prg(m_prg_base, m_prg_mask); + break; + } +} + +#ifdef UNUSED_FUNCTION +/*------------------------------------------------- + + UNL-A9746 + + + MMC3 clone + + + Preliminary emulation based on Cah4e3's code + No dump is available (yet) for this. + + -------------------------------------------------*/ + +void nes_a9746_device::device_start() +{ + mmc3_start(); + save_item(NAME(m_reg)); +} + +void nes_a9746_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + + m_reg[0] = 0; + m_reg[1] = 0; + m_reg[2] = 0; + mmc3_common_initialize(0x7f, 0xff, 0); +} + +void nes_a9746_device::update_banks(UINT8 value) +{ + UINT8 bank = BITSWAP8(value & 0x3c,7,6,0,1,2,3,4,5); + + switch (m_reg[0]) + { + case 0x26: prg8_89(bank); break; + case 0x25: prg8_ab(bank); break; + case 0x24: prg8_cd(bank); break; + case 0x23: prg8_ef(bank); break; + } + + switch (m_reg[1]) + { + case 0x08: case 0x0a: case 0x0c: case 0x0e: + case 0x10: case 0x12: case 0x14: case 0x16: + case 0x18: case 0x1a: case 0x1c: case 0x1e: + m_reg[2] = (value << 4); + break; + case 0x09: chr1_0(m_reg[2] | (value >> 1), m_chr_source); break; + case 0x0b: chr1_1(m_reg[2] | (value >> 1) | 1, m_chr_source); break; + case 0x0d: chr1_2(m_reg[2] | (value >> 1), m_chr_source); break; + case 0x0f: chr1_3(m_reg[2] | (value >> 1) | 1, m_chr_source); break; + case 0x11: chr1_4(m_reg[2] | (value >> 1), m_chr_source); break; + case 0x15: chr1_5(m_reg[2] | (value >> 1), m_chr_source); break; + case 0x19: chr1_6(m_reg[2] | (value >> 1), m_chr_source); break; + case 0x1d: chr1_7(m_reg[2] | (value >> 1), m_chr_source); break; + } +} + +WRITE8_MEMBER(nes_a9746_device::write_h) +{ + LOG_MMC(("unl_a9746 write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x6003) + { + case 0x0000: + m_reg[1] = data; + m_reg[0] = 0; + break; + case 0x0001: + update_banks(data); + break; + case 0x0002: + m_reg[0] = data; + m_reg[1] = 0; + break; + + case 0x0003: + case 0x2000: + case 0x2001: + case 0x2002: + case 0x2003: + break; + + default: + txrom_write(space, offset, data, mem_mask); + break; + } +} +#endif diff --git a/src/devices/bus/nes/mmc3_clones.h b/src/devices/bus/nes/mmc3_clones.h new file mode 100644 index 00000000000..9445395889d --- /dev/null +++ b/src/devices/bus/nes/mmc3_clones.h @@ -0,0 +1,697 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __NES_MMC3_CLONES_H +#define __NES_MMC3_CLONES_H + +#include "mmc3.h" + + +// ======================> nes_nitra_device + +class nes_nitra_device : public nes_txrom_device +{ +public: + // construction/destruction + nes_nitra_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual DECLARE_WRITE8_MEMBER(write_h); +}; + + +// ======================> nes_ks7057_device + +class nes_ks7057_device : public nes_txrom_device +{ +public: + // construction/destruction + nes_ks7057_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual DECLARE_WRITE8_MEMBER(write_h); +}; + + +// ======================> nes_sbros11_device + +class nes_sbros11_device : public nes_txrom_device +{ +public: + // construction/destruction + nes_sbros11_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual DECLARE_WRITE8_MEMBER(write_h); +}; + + +// ======================> nes_malisb_device + +class nes_malisb_device : public nes_txrom_device +{ +public: + // construction/destruction + nes_malisb_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual DECLARE_WRITE8_MEMBER(write_h); + virtual void prg_cb(int start, int bank); + virtual void chr_cb(int start, int bank, int source); +}; + + +// ======================> nes_family4646_device + +class nes_family4646_device : public nes_txrom_device +{ +public: + // construction/destruction + nes_family4646_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual DECLARE_WRITE8_MEMBER(write_m); + + virtual void pcb_reset(); +}; + + +// ======================> nes_pikay2k_device + +class nes_pikay2k_device : public nes_txrom_device +{ +public: + // construction/destruction + nes_pikay2k_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_READ8_MEMBER(read_m); + virtual DECLARE_WRITE8_MEMBER(write_m); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); + +private: + UINT8 m_reg[2]; +}; + + +// ======================> nes_8237_device + +class nes_8237_device : public nes_txrom_device +{ +public: + // construction/destruction + nes_8237_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_l); + virtual DECLARE_WRITE8_MEMBER(write_h); + virtual void prg_cb(int start, int bank); + virtual void chr_cb(int start, int bank, int source); + + virtual void pcb_reset(); + +private: + UINT8 m_reg[3]; + int m_cd_enable; +}; + + +// ======================> nes_sglionk_device + +class nes_sglionk_device : public nes_txrom_device +{ +public: + // construction/destruction + nes_sglionk_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_m); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); + +private: + UINT8 m_reg; + int m_reg_enabled; +}; + + +// ======================> nes_sgboog_device + +class nes_sgboog_device : public nes_txrom_device +{ +public: + // construction/destruction + nes_sgboog_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_l); + virtual DECLARE_WRITE8_MEMBER(write_m); + virtual DECLARE_WRITE8_MEMBER(write_h); + virtual void prg_cb(int start, int bank); + virtual void chr_cb(int start, int bank, int source); + + virtual void pcb_reset(); + +private: + virtual void set_prg(int prg_base, int prg_mask); + UINT8 m_reg[3]; + UINT8 m_mode; +}; + + +// ======================> nes_kasing_device + +class nes_kasing_device : public nes_txrom_device +{ +public: + // construction/destruction + nes_kasing_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_m); + virtual void prg_cb(int start, int bank); + + virtual void pcb_reset(); + +private: + UINT8 m_reg; +}; + + +// ======================> nes_kay_device + +class nes_kay_device : public nes_txrom_device +{ +public: + // construction/destruction + nes_kay_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_READ8_MEMBER(read_l); + virtual DECLARE_WRITE8_MEMBER(write_l); + virtual DECLARE_WRITE8_MEMBER(write_h); + virtual void prg_cb(int start, int bank); + virtual void chr_cb(int start, int bank, int source); + + virtual void pcb_reset(); + +private: + void update_regs(); + UINT8 m_reg[8]; + UINT8 m_low_reg; +}; + + +// ======================> nes_h2288_device + +class nes_h2288_device : public nes_txrom_device +{ +public: + // construction/destruction + nes_h2288_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_READ8_MEMBER(read_l); + virtual DECLARE_WRITE8_MEMBER(write_l); + virtual DECLARE_WRITE8_MEMBER(write_h); + virtual void prg_cb(int start, int bank); + + virtual void pcb_reset(); + +private: + UINT8 m_reg[2]; // reg 1 is unused? +}; + + +// ======================> nes_6035052_device + +class nes_6035052_device : public nes_txrom_device +{ +public: + // construction/destruction + nes_6035052_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_READ8_MEMBER(read_ex); + virtual DECLARE_WRITE8_MEMBER(write_ex); + virtual DECLARE_READ8_MEMBER(read_l) { return read_ex(space, offset, mem_mask); } + virtual DECLARE_READ8_MEMBER(read_m) { return read_ex(space, offset, mem_mask); } + virtual DECLARE_WRITE8_MEMBER(write_l) { write_ex(space, offset, data, mem_mask); } + virtual DECLARE_WRITE8_MEMBER(write_m) { write_ex(space, offset, data, mem_mask); } + + virtual void pcb_reset(); + +private: + UINT8 m_prot; +}; + + +// ======================> nes_txc_tw_device + +class nes_txc_tw_device : public nes_txrom_device +{ +public: + // construction/destruction + nes_txc_tw_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual DECLARE_WRITE8_MEMBER(write_l); + virtual DECLARE_WRITE8_MEMBER(write_m) { write_l(space, offset & 0xff, data, mem_mask); } // offset does not really count for this mapper } + virtual void prg_cb(int start, int bank); +}; + + +// ======================> nes_kof97_device + +class nes_kof97_device : public nes_txrom_device +{ +public: + // construction/destruction + nes_kof97_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual DECLARE_WRITE8_MEMBER(write_h); +}; + + +// ======================> nes_kof96_device + +class nes_kof96_device : public nes_txrom_device +{ +public: + // construction/destruction + nes_kof96_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_READ8_MEMBER(read_l); + virtual DECLARE_WRITE8_MEMBER(write_l); + virtual DECLARE_WRITE8_MEMBER(write_h); // offset does not really count for this mapper + virtual void prg_cb(int start, int bank); + virtual void chr_cb(int start, int bank, int source); + + virtual void pcb_reset(); + +private: + UINT8 m_reg[4]; +}; + + +// ======================> nes_sf3_device + +class nes_sf3_device : public nes_txrom_device +{ +public: + // construction/destruction + nes_sf3_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual DECLARE_WRITE8_MEMBER(write_h); + +protected: + virtual void set_chr(UINT8 chr, int chr_base, int chr_mask); +}; + + +// ======================> nes_gouder_device + +class nes_gouder_device : public nes_txrom_device +{ +public: + // construction/destruction + nes_gouder_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_READ8_MEMBER(read_l); + virtual DECLARE_WRITE8_MEMBER(write_l); + virtual void prg_cb(int start, int bank); + + virtual void pcb_reset(); + +private: + UINT8 m_reg[5]; +}; + + +// ======================> nes_sa9602b_device + +class nes_sa9602b_device : public nes_txrom_device +{ +public: + // construction/destruction + nes_sa9602b_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_h); + virtual void prg_cb(int start, int bank); + + virtual void pcb_reset(); + +private: + UINT8 m_reg; + int m_prg_chip; +}; + + +// ======================> nes_sachen_shero_device + +class nes_sachen_shero_device : public nes_txrom_device +{ +public: + // construction/destruction + nes_sachen_shero_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_READ8_MEMBER(read_l); + virtual DECLARE_WRITE8_MEMBER(write_l); + virtual void chr_cb(int start, int bank, int source); + + virtual void pcb_reset(); + +private: + UINT8 m_reg; +}; + +#ifdef UNUSED_FUNCTION +// ======================> nes_a9746_device + +class nes_a9746_device : public nes_txrom_device +{ +public: + // construction/destruction + nes_a9746_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); + +private: + void update_banks(UINT8 value); + UINT8 m_reg[3]; +}; +#endif + + +// ======================> nes_fk23c_device + +class nes_fk23c_device : public nes_txrom_device +{ +public: + // construction/destruction + nes_fk23c_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + nes_fk23c_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_l); + virtual DECLARE_WRITE8_MEMBER(write_h); + virtual void prg_cb(int start, int bank); + virtual void chr_cb(int start, int bank, int source); + + virtual void pcb_reset(); + +protected: + void fk23c_set_prg(); + void fk23c_set_chr(); + UINT8 m_reg[8]; + UINT8 m_mmc_cmd1; +}; + + +// ======================> nes_fk23ca_device + +class nes_fk23ca_device : public nes_fk23c_device +{ +public: + // construction/destruction + nes_fk23ca_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual void pcb_reset(); +}; + + +// ======================> nes_s24in1sc03_device + +class nes_s24in1sc03_device : public nes_txrom_device +{ +public: + // construction/destruction + nes_s24in1sc03_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_l); + virtual void prg_cb(int start, int bank); + virtual void chr_cb(int start, int bank, int source); + + virtual void pcb_reset(); + +private: + UINT8 m_reg[3]; +}; + + +// ======================> nes_bmc_15in1_device + +class nes_bmc_15in1_device : public nes_txrom_device +{ +public: + // construction/destruction + nes_bmc_15in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual DECLARE_WRITE8_MEMBER(write_m); + + virtual void pcb_reset(); +}; + + +// ======================> nes_bmc_sbig7_device + +class nes_bmc_sbig7_device : public nes_txrom_device +{ +public: + // construction/destruction + nes_bmc_sbig7_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); +}; + + +// ======================> nes_bmc_hik8_device + +class nes_bmc_hik8_device : public nes_txrom_device +{ +public: + // construction/destruction + nes_bmc_hik8_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_m); + + virtual void pcb_reset(); + +private: + UINT8 m_reg[4]; + UINT8 m_count; +}; + + +// ======================> nes_bmc_hik4_device + +class nes_bmc_hik4_device : public nes_txrom_device +{ +public: + // construction/destruction + nes_bmc_hik4_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual DECLARE_WRITE8_MEMBER(write_m); + + virtual void pcb_reset(); +}; + + +// ======================> nes_bmc_mario7in1_device + +class nes_bmc_mario7in1_device : public nes_txrom_device +{ +public: + // construction/destruction + nes_bmc_mario7in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_m); + + virtual void pcb_reset(); + +private: + UINT8 m_reg_written; +}; + + +// ======================> nes_bmc_gold7in1_device + +class nes_bmc_gold7in1_device : public nes_txrom_device +{ +public: + // construction/destruction + nes_bmc_gold7in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_m); + + virtual void pcb_reset(); + +private: + UINT8 m_reg_written; +}; + + +// ======================> nes_bmc_gc6in1_device + +class nes_bmc_gc6in1_device : public nes_txrom_device +{ +public: + // construction/destruction + nes_bmc_gc6in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_l); + virtual DECLARE_WRITE8_MEMBER(write_h); + virtual void prg_cb(int start, int bank); + virtual void chr_cb(int start, int bank, int source); + + virtual void pcb_reset(); + +private: + UINT8 m_reg[4]; +}; + + +// ======================> nes_bmc_411120c_device + +class nes_bmc_411120c_device : public nes_txrom_device +{ +public: + // construction/destruction + nes_bmc_411120c_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_m); + virtual void prg_cb(int start, int bank); + virtual void chr_cb(int start, int bank, int source); + + virtual void pcb_reset(); + +private: + UINT8 m_reg; +}; + + +// ======================> nes_bmc_830118c_device + +class nes_bmc_830118c_device : public nes_txrom_device +{ +public: + // construction/destruction + nes_bmc_830118c_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_m); + virtual void prg_cb(int start, int bank); + virtual void chr_cb(int start, int bank, int source); + + virtual void pcb_reset(); + +private: + UINT8 m_reg; +}; + + +// ======================> nes_pjoy84_device + +class nes_pjoy84_device : public nes_txrom_device +{ +public: + // construction/destruction + nes_pjoy84_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_m); + virtual void prg_cb(int start, int bank); + virtual void chr_cb(int start, int bank, int source); + + virtual void pcb_reset(); + +private: + inline void set_base_mask(); + UINT8 m_reg[4]; +}; + + + + +// device type definition +extern const device_type NES_NITRA; +extern const device_type NES_KS7057; +extern const device_type NES_SBROS11; +extern const device_type NES_MALISB; +extern const device_type NES_FAMILY4646; +extern const device_type NES_PIKAY2K; +extern const device_type NES_8237; +extern const device_type NES_SG_LIONK; +extern const device_type NES_SG_BOOG; +extern const device_type NES_KASING; +extern const device_type NES_KAY; +extern const device_type NES_H2288; +extern const device_type NES_6035052; +extern const device_type NES_TXC_TW; +extern const device_type NES_KOF97; +extern const device_type NES_KOF96; +extern const device_type NES_SF3; +extern const device_type NES_GOUDER; +extern const device_type NES_SA9602B; +extern const device_type NES_SACHEN_SHERO; +extern const device_type NES_A9746; + +extern const device_type NES_FK23C; +extern const device_type NES_FK23CA; +extern const device_type NES_S24IN1SC03; +extern const device_type NES_BMC_15IN1; +extern const device_type NES_BMC_SBIG7; +extern const device_type NES_BMC_HIK8; +extern const device_type NES_BMC_HIK4; +extern const device_type NES_BMC_MARIO7IN1; +extern const device_type NES_BMC_GOLD7IN1; +extern const device_type NES_BMC_GC6IN1; +extern const device_type NES_BMC_411120C; +extern const device_type NES_BMC_830118C; +extern const device_type NES_PJOY84; + +#endif diff --git a/src/devices/bus/nes/mmc5.c b/src/devices/bus/nes/mmc5.c new file mode 100644 index 00000000000..26149c48e50 --- /dev/null +++ b/src/devices/bus/nes/mmc5.c @@ -0,0 +1,679 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + NES/Famicom cartridge emulation for Nintendo MMC-5 / ExROM + + + Here we emulate the Nintendo MMC-5 / ExROM PCBs [mapper 5] + + + TODO: + - improve PPU code in order to support the two sets of registers used by MMC5 + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "mmc5.h" + +#include "cpu/m6502/m6502.h" +#include "video/ppu2c0x.h" // this has to be included so that IRQ functions can access PPU_BOTTOM_VISIBLE_SCANLINE +#include "sound/nes_apu.h" // temp hack to pass the additional sound regs to APU... + + +#ifdef NES_PCB_DEBUG +#define VERBOSE 1 +#else +#define VERBOSE 0 +#endif + +#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) + + +#define LAST_CHR_REG_A 0 +#define LAST_CHR_REG_B 1 + +static const int m_mmc5_attrib[4] = {0x00, 0x55, 0xaa, 0xff}; + +//------------------------------------------------- +// constructor +//------------------------------------------------- + +const device_type NES_EXROM = &device_creator; + + +nes_exrom_device::nes_exrom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_EXROM, "NES Cart ExROM (MMC-5) PCB", tag, owner, clock, "nes_exrom", __FILE__) +{ +} + + +void nes_exrom_device::device_start() +{ + common_start(); + save_item(NAME(m_irq_count)); + save_item(NAME(m_irq_status)); + save_item(NAME(m_irq_enable)); + save_item(NAME(m_mult1)); + save_item(NAME(m_mult2)); + save_item(NAME(m_vrom_page_a)); + save_item(NAME(m_vrom_page_b)); + save_item(NAME(m_floodtile)); + save_item(NAME(m_floodattr)); + save_item(NAME(m_prg_mode)); + save_item(NAME(m_chr_mode)); + save_item(NAME(m_wram_base)); + save_item(NAME(m_wram_protect_1)); + save_item(NAME(m_wram_protect_2)); + save_item(NAME(m_vrom_bank)); + save_item(NAME(m_last_chr)); + save_item(NAME(m_ex1_chr)); + save_item(NAME(m_split_chr)); + save_item(NAME(m_prg_regs)); + save_item(NAME(m_prg_ram_mapped)); + save_item(NAME(m_ex1_bank)); + save_item(NAME(m_high_chr)); + save_item(NAME(m_split_scr)); + save_item(NAME(m_split_rev)); + save_item(NAME(m_split_ctrl)); + save_item(NAME(m_split_yst)); + save_item(NAME(m_split_bank)); + save_item(NAME(m_vcount)); + save_item(NAME(m_exram)); + save_item(NAME(m_ram_hi_banks)); + +} + +void nes_exrom_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(m_prg_chunks - 2); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); + + m_irq_count = 0; + m_irq_status = 0; + m_irq_enable = 0; + + m_mult1 = m_mult2 = 0; + m_vrom_page_a = m_vrom_page_b = 0; + + m_floodtile = m_floodattr = 0; + + m_prg_mode = 3; + m_chr_mode = 0; + m_wram_base = 0; + m_wram_protect_1 = 0; + m_wram_protect_2 = 0; + m_high_chr = 0; + m_split_scr = 0; + m_split_rev = 0; + m_split_ctrl = 0; + m_split_yst = 0; + m_split_bank = 0; + m_last_chr = LAST_CHR_REG_A; + m_ex1_chr = 0; + m_split_chr = 0; + m_ex1_bank = 0; + m_vcount = 0; + + for (int i = 0; i < 12; i++) + m_vrom_bank[i] = 0x3ff; + + m_prg_regs[0] = 0xfc; + m_prg_regs[1] = 0xfd; + m_prg_regs[2] = 0xfe; + m_prg_regs[3] = 0xff; + m_prg_ram_mapped[0] = 0; + m_prg_ram_mapped[1] = 0; + m_prg_ram_mapped[2] = 0; + m_prg_ram_mapped[3] = 0; + + m_ram_hi_banks[0] = 0; + m_ram_hi_banks[1] = 0; + m_ram_hi_banks[2] = 0; + m_ram_hi_banks[3] = 0; +} + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +/*------------------------------------------------- + + ExROM (MMC5 based) board emulation + + Games: Castlevania III, Just Breed, many Koei titles + + iNES: mapper 5 + + MESS status: Partially supported + + -------------------------------------------------*/ + +void nes_exrom_device::update_prg() +{ + int bank0, bank1, bank2, bank3; + + switch (m_prg_mode) + { + case 0: // 32k banks + bank3 = m_prg_regs[3] >> 2; + prg32(bank3); + break; + + case 1: // 16k banks + bank1 = m_prg_regs[1] >> 1; + bank3 = m_prg_regs[3] >> 1; + + if (m_prg_ram_mapped[1]) + { + m_ram_hi_banks[0] = ((bank1 << 1) & 0x07); + m_ram_hi_banks[1] = ((bank1 << 1) & 0x07) | 1; + } + else + prg16_89ab(bank1); + + prg16_cdef(bank3); + break; + + case 2: // 16k-8k banks + bank1 = m_prg_regs[1] >> 1; + bank2 = m_prg_regs[2]; + bank3 = m_prg_regs[3]; + + if (m_prg_ram_mapped[1]) + { + m_ram_hi_banks[0] = ((bank1 << 1) & 0x07); + m_ram_hi_banks[1] = ((bank1 << 1) & 0x07) | 1; + } + else + prg16_89ab(bank1); + + if (m_prg_ram_mapped[2]) + m_ram_hi_banks[2] = (bank2 & 0x07); + else + prg8_cd(bank2); + + prg8_ef(bank3); + break; + + case 3: // 8k banks + bank0 = m_prg_regs[0]; + bank1 = m_prg_regs[1]; + bank2 = m_prg_regs[2]; + bank3 = m_prg_regs[3]; + + if (m_prg_ram_mapped[0]) + m_ram_hi_banks[0] = (bank0 & 0x07); + else + prg8_89(bank0); + + if (m_prg_ram_mapped[1]) + m_ram_hi_banks[1] = (bank1 & 0x07); + else + prg8_ab(bank1); + + if (m_prg_ram_mapped[2]) + m_ram_hi_banks[2] = (bank2 & 0x07); + else + prg8_cd(bank2); + + prg8_ef(bank3); + break; + } +} + +void nes_exrom_device::hblank_irq(int scanline, int vblank, int blanked ) +{ + m_vcount = scanline; + + if (scanline == m_irq_count) + { + if (m_irq_enable) + m_maincpu->set_input_line(M6502_IRQ_LINE, ASSERT_LINE); + + m_irq_status = 0xff; + } + + // "In Frame" flag + if (scanline == 0) + m_irq_status |= 0x40; + else if (scanline > PPU_BOTTOM_VISIBLE_SCANLINE) + m_irq_status &= ~0x40; +} + + +void nes_exrom_device::set_mirror(int page, int src) +{ + switch (src) + { + case 0: + set_nt_page(page, CIRAM, 0, 1); + break; + case 1: + set_nt_page(page, CIRAM, 1, 1); + break; + case 2: + set_nt_page(page, EXRAM, 0, 1); + break; + case 3: + set_nt_page(page, MMC5FILL, 0, 0); + break; + default: + fatalerror("This should never happen\n"); + } +} + +inline bool nes_exrom_device::in_split() +{ + ppu2c0x_device *ppu = machine().device("ppu"); + int tile = ppu->get_tilenum(); + + if (tile < 34) + { + if (!m_split_rev && tile < m_split_ctrl) + return TRUE; + if (m_split_rev && tile >= m_split_ctrl) + return TRUE; + } + return FALSE; +} + +READ8_MEMBER(nes_exrom_device::nt_r) +{ + int page = ((offset & 0xc00) >> 10); + + switch (m_nt_src[page]) + { + case MMC5FILL: + if ((offset & 0x3ff) >= 0x3c0) + return m_floodattr; + return m_floodtile; + + case EXRAM: + // to investigate: can split screen affect this too? + if (!BIT(m_exram_control, 1)) + return m_exram[offset & 0x3ff]; + else + return 0x00; + + case CIRAM: + default: + // Uchuu Keibitai SDF uses extensively split screen for its intro, + // but it does not work yet + if (m_split_scr && !(m_exram_control & 0x02) && in_split()) + { + ppu2c0x_device *ppu = machine().device("ppu"); + int tile = ppu->get_tilenum(); + + if ((offset & 0x3ff) >= 0x3c0) + { + int pos = (((m_split_yst + m_vcount) & ~0x1f) | (tile & 0x1f)) >> 2; + return m_exram[0x3c0 | pos]; + } + else + { + int pos = (((m_split_yst + m_vcount) & 0xf8) << 2) | (tile & 0x1f); + return m_exram[pos]; + } + } + + if (m_exram_control == 1) + { + if ((offset & 0x3ff) >= 0x3c0) + return m_mmc5_attrib[(m_exram[offset & 0x3ff] >> 6) & 0x03]; + else // in this case, we write Ex1 CHR bank, but then access NT normally! + { + m_ex1_chr = 1; + m_ex1_bank = (m_exram[offset & 0x3ff] & 0x3f) | (m_high_chr << 6); + } + } + return m_nt_access[page][offset & 0x3ff]; + } +} + +WRITE8_MEMBER(nes_exrom_device::nt_w) +{ + int page = ((offset & 0xc00) >> 10); + + if (!m_nt_writable[page]) + return; + + switch (m_nt_src[page]) + { + case EXRAM: + m_exram[offset & 0x3ff] = data; + break; + + case CIRAM: + default: + m_nt_access[page][offset & 0x3ff] = data; + break; + } +} + +inline UINT8 nes_exrom_device::base_chr_r(int bank, UINT32 offset) +{ + UINT32 helper = 0; + + switch (m_chr_mode) + { + case 0: + if (bank < 8) + helper = ((m_vrom_bank[bank | 7] & 0xff) * 0x2000) + (offset & 0x1fff); + else + helper = ((m_vrom_bank[bank | 3] & 0xff) * 0x2000) + (offset & 0xfff); + break; + case 1: + helper = ((m_vrom_bank[bank | 3] & 0xff) * 0x1000) + (offset & 0xfff); + break; + case 2: + helper = (m_vrom_bank[bank | 1] * 0x800) + (offset & 0x7ff); + break; + case 3: + helper = (m_vrom_bank[bank] * 0x400) + (offset & 0x3ff); + break; + } + + return m_vrom[helper & (m_vrom_size - 1)]; +} + +inline UINT8 nes_exrom_device::split_chr_r(UINT32 offset) +{ + UINT32 helper = (m_split_bank * 0x1000) + (offset & 0x3f8) + (m_split_yst & 7); + return m_vrom[helper & (m_vrom_size - 1)]; +} + +inline UINT8 nes_exrom_device::bg_ex1_chr_r(UINT32 offset) +{ + UINT32 helper = (m_ex1_bank * 0x1000) + (offset & 0xfff); + return m_vrom[helper & (m_vrom_size - 1)]; +} + +READ8_MEMBER(nes_exrom_device::chr_r) +{ + int bank = offset >> 10; + ppu2c0x_device *ppu = machine().device("ppu"); + + // Extended Attribute Mode (Ex1) does affect BG drawing even for 8x16 sprites (JustBreed uses it extensively!) + // However, if a game enables Ex1 but does not write a new m_ex1_bank, I'm not sure here we get the correct behavior + if (m_exram_control == 1 && ppu->get_draw_phase() == PPU_DRAW_BG && m_ex1_chr) + return bg_ex1_chr_r(offset & 0xfff); + + if (m_split_scr && !(m_exram_control & 0x02) && in_split() && ppu->get_draw_phase() == PPU_DRAW_BG && m_split_chr) + return split_chr_r(offset & 0xfff); + + if (ppu->is_sprite_8x16()) + { + if (ppu->get_draw_phase() == PPU_DRAW_OAM) + return base_chr_r(bank & 7, offset & 0x1fff); + + if (ppu->get_draw_phase() == PPU_DRAW_BG) + return base_chr_r((bank & 3) + 8, offset & 0x1fff); + } + + if (m_last_chr == LAST_CHR_REG_A) + return base_chr_r(bank & 7, offset & 0x1fff); + else + return base_chr_r((bank & 3) + 8, offset & 0x1fff); +} + + +READ8_MEMBER(nes_exrom_device::read_l) +{ + int value; + LOG_MMC(("exrom read_l, offset: %04x\n", offset)); + offset += 0x100; + + if ((offset >= 0x1c00) && (offset <= 0x1fff)) + { + // EXRAM + if (BIT(m_exram_control, 1)) // Modes 2,3 = read + return m_exram[offset - 0x1c00]; + else + return m_open_bus; // Modes 0,1 = open bus + } + + switch (offset) + { + case 0x1204: + value = m_irq_status; + m_irq_status &= ~0x80; + m_maincpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE); + return value; + + case 0x1205: + return (m_mult1 * m_mult2) & 0xff; + case 0x1206: + return ((m_mult1 * m_mult2) & 0xff00) >> 8; + + default: + logerror("MMC5 uncaught read, offset: %04x\n", offset + 0x4100); + return m_open_bus; + } +} + + +WRITE8_MEMBER(nes_exrom_device::write_l) +{ + LOG_MMC(("exrom write_l, offset: %04x, data: %02x\n", offset, data)); + offset += 0x100; + + if ((offset >= 0x1000) && (offset <= 0x1015)) + { + // SOUND + nesapu_device *m_sound = machine().device("nessound"); + m_sound->write(space, offset & 0x1f, data); + return; + } + + if ((offset >= 0x1c00) && (offset <= 0x1fff)) + { + // EXRAM + if (m_exram_control == 0x02) // Mode 2 = write data + m_exram[offset - 0x1c00] = data; + else if (m_exram_control != 0x03) // Modes 0,1 = write data in frame / write 0 otherwise + { + if (m_irq_status & 0x40) + m_exram[offset - 0x1c00] = data; + else + m_exram[offset - 0x1c00] = 0x00; + } + // Mode 3 = read only + return; + } + + switch (offset) + { + case 0x1100: + m_prg_mode = data & 0x03; + update_prg(); + //LOG_MMC(("MMC5 rom bank mode: %02x\n", data)); + break; + + case 0x1101: + m_chr_mode = data & 0x03; + m_ex1_chr = 0; + m_split_chr = 0; + //LOG_MMC(("MMC5 vrom bank mode: %02x\n", data)); + break; + + case 0x1102: + m_wram_protect_1 = data & 0x03; + LOG_MMC(("MMC5 vram protect 1: %02x\n", data)); + break; + case 0x1103: + m_wram_protect_2 = data & 0x03; + LOG_MMC(("MMC5 vram protect 2: %02x\n", data)); + break; + + case 0x1104: // Extra VRAM (EXRAM) + m_exram_control = data & 0x03; + LOG_MMC(("MMC5 exram control: %02x\n", data)); + break; + + case 0x1105: + set_mirror(0, (data & 0x03) >> 0); + set_mirror(1, (data & 0x0c) >> 2); + set_mirror(2, (data & 0x30) >> 4); + set_mirror(3, (data & 0xc0) >> 6); + break; + + case 0x1106: + m_floodtile = data; + break; + + case 0x1107: + m_floodattr = m_mmc5_attrib[data & 3]; + break; + + case 0x1113: + LOG_MMC(("MMC5 mid RAM bank select: %02x\n", data & 0x07)); + m_wram_base = data & 0x07; + break; + + + case 0x1114: + case 0x1115: + case 0x1116: + case 0x1117: + m_prg_regs[offset & 3] = data & 0x7f; + m_prg_ram_mapped[offset & 3] = !BIT(data, 7); // m_prg_ram_mapped[3] is not used, in fact! + update_prg(); + break; + + case 0x1120: + case 0x1121: + case 0x1122: + case 0x1123: + case 0x1124: + case 0x1125: + case 0x1126: + case 0x1127: + m_vrom_bank[offset & 0x07] = data | (m_high_chr << 8); + m_last_chr = LAST_CHR_REG_A; + m_ex1_chr = 0; + m_split_chr = 0; + break; + + case 0x1128: + case 0x1129: + case 0x112a: + case 0x112b: + m_vrom_bank[offset & 0x0f] = data | (m_high_chr << 8); + m_last_chr = LAST_CHR_REG_B; + m_ex1_chr = 0; + m_split_chr = 0; + break; + + case 0x1130: + m_high_chr = data & 0x03; + m_ex1_chr = 0; + m_split_chr = 0; + break; + + + case 0x1200: + // in EX2 and EX3 modes, no split screen + m_split_scr = BIT(data, 7); + m_split_rev = BIT(data, 6); + m_split_ctrl = data & 0x1f; + break; + + case 0x1201: + m_split_yst = (data >= 240) ? data - 16 : data; + break; + + case 0x1202: + m_split_bank = data; + m_split_chr = 1; + break; + + case 0x1203: + m_irq_count = data; + LOG_MMC(("MMC5 irq scanline: %d\n", m_irq_count)); + break; + case 0x1204: + m_irq_enable = data & 0x80; + LOG_MMC(("MMC5 irq enable: %02x\n", data)); + break; + case 0x1205: + m_mult1 = data; + break; + case 0x1206: + m_mult2 = data; + break; + + default: + logerror("MMC5 uncaught write, offset: %04x, data: %02x\n", offset + 0x4100, data); + break; + } +} + +// 3bits are used to access the "WRAM" banks +// bit3 select the chip (2 of them can be accessed, each up to 32KB) +// bit1 & bit2 select the 8KB banks inside the chip +// same mechanism is used also when "WRAM" is mapped in higher banks +READ8_MEMBER(nes_exrom_device::read_m) +{ + LOG_MMC(("exrom read_m, offset: %04x\n", offset)); + if (!m_battery.empty() && !m_prgram.empty()) // 2 chips present: first is BWRAM, second is WRAM + { + if (m_wram_base & 0x04) + return m_prgram[(offset + (m_wram_base & 0x03) * 0x2000) & (m_prgram.size() - 1)]; + else + return m_battery[(offset + (m_wram_base & 0x03) * 0x2000) & (m_battery.size() - 1)]; + } + else if (!m_prgram.empty()) // 1 chip, WRAM + return m_prgram[(offset + (m_wram_base & 0x03) * 0x2000) & (m_prgram.size() - 1)]; + else if (!m_battery.empty()) // 1 chip, BWRAM + return m_battery[(offset + (m_wram_base & 0x03) * 0x2000) & (m_battery.size() - 1)]; + else + return m_open_bus; +} + +WRITE8_MEMBER(nes_exrom_device::write_m) +{ + LOG_MMC(("exrom write_m, offset: %04x, data: %02x\n", offset, data)); + if (m_wram_protect_1 != 0x02 || m_wram_protect_2 != 0x01) + return; + + if (!m_battery.empty() && m_wram_base < 4) + m_battery[(offset + m_wram_base * 0x2000) & (m_battery.size() - 1)] = data; + else if (!m_prgram.empty()) + m_prgram[(offset + (m_wram_base & 0x03) * 0x2000) & (m_prgram.size() - 1)] = data; +} + +// some games (e.g. Bandit Kings of Ancient China) write to PRG-RAM through 0x8000-0xdfff +READ8_MEMBER(nes_exrom_device::read_h) +{ + LOG_MMC(("exrom read_h, offset: %04x\n", offset)); + int bank = offset / 0x2000; + + if (bank < 3 && offset >= bank * 0x2000 && offset < (bank + 1) * 0x2000 && m_prg_ram_mapped[bank]) + { + if (!m_battery.empty() && m_ram_hi_banks[bank] < 4) + return m_battery[((m_ram_hi_banks[bank] * 0x2000) + (offset & 0x1fff)) & (m_battery.size() - 1)]; + else if (!m_prgram.empty()) + return m_prgram[(((m_ram_hi_banks[bank] & 3) * 0x2000) + (offset & 0x1fff)) & (m_prgram.size() - 1)]; + } + + return hi_access_rom(offset); +} + +WRITE8_MEMBER(nes_exrom_device::write_h) +{ + LOG_MMC(("exrom write_h, offset: %04x, data: %02x\n", offset, data)); + int bank = offset / 0x2000; + if (m_wram_protect_1 != 0x02 || m_wram_protect_2 != 0x01 || bank == 3 || !m_prg_ram_mapped[bank]) + return; + + if (!m_battery.empty() && m_ram_hi_banks[bank] < 4) + m_battery[((m_ram_hi_banks[bank] * 0x2000) + (offset & 0x1fff)) & (m_battery.size() - 1)] = data; + else if (!m_prgram.empty()) + m_prgram[(((m_ram_hi_banks[bank] & 3) * 0x2000) + (offset & 0x1fff)) & (m_prgram.size() - 1)] = data; +} diff --git a/src/devices/bus/nes/mmc5.h b/src/devices/bus/nes/mmc5.h new file mode 100644 index 00000000000..46fe19af7a8 --- /dev/null +++ b/src/devices/bus/nes/mmc5.h @@ -0,0 +1,94 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __NES_MMC5_H +#define __NES_MMC5_H + +#include "nxrom.h" + + +// ======================> nes_exrom_device + +class nes_exrom_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_exrom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_READ8_MEMBER(read_l); + virtual DECLARE_READ8_MEMBER(read_m); + virtual DECLARE_READ8_MEMBER(read_h); + virtual DECLARE_WRITE8_MEMBER(write_l); + virtual DECLARE_WRITE8_MEMBER(write_m); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual DECLARE_READ8_MEMBER(chr_r); + virtual DECLARE_READ8_MEMBER(nt_r); + virtual DECLARE_WRITE8_MEMBER(nt_w); + + virtual void hblank_irq(int scanline, int vblank, int blanked); + virtual void pcb_reset(); + +protected: + void set_mirror(int page, int src); + void update_render_mode(); + void update_prg(); + + inline UINT8 base_chr_r(int bank, UINT32 offset); + inline UINT8 split_chr_r(UINT32 offset); + inline UINT8 bg_ex1_chr_r(UINT32 offset); + inline bool in_split(); + + UINT16 m_irq_count; + UINT8 m_irq_status; + int m_irq_enable; + + int m_mult1, m_mult2; + + int m_mmc5_scanline; + int m_vrom_page_a; + int m_vrom_page_b; + UINT16 m_vrom_bank[12]; // MMC5 has 10bit wide VROM regs! + + int m_floodtile; + int m_floodattr; + + int m_prg_mode; // $5100 + int m_chr_mode; // $5101 + int m_wram_protect_1; // $5102 + int m_wram_protect_2; // $5103 + int m_exram_control; // $5104 + int m_wram_base; // $5113 + + UINT8 m_last_chr; + UINT8 m_ex1_chr; + UINT8 m_split_chr; + UINT8 m_prg_regs[4]; + UINT8 m_prg_ram_mapped[4]; + + UINT8 m_ex1_bank; + + UINT8 m_high_chr; // $5130 + + UINT8 m_split_scr; // $5200 + UINT8 m_split_rev; // $5200 + UINT8 m_split_ctrl; // $5200 + UINT8 m_split_yst; // $5201 + UINT8 m_split_bank; // $5202 + int m_vcount; + + // MMC-5 contains 1K of internal ram + UINT8 m_exram[0x400]; + + UINT8 m_ram_hi_banks[4]; + + // int m_nes_vram_sprite[8]; +}; + + + +// device type definition +extern const device_type NES_EXROM; + +#endif diff --git a/src/devices/bus/nes/multigame.c b/src/devices/bus/nes/multigame.c new file mode 100644 index 00000000000..ba65c3d0e7c --- /dev/null +++ b/src/devices/bus/nes/multigame.c @@ -0,0 +1,2602 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + NES/Famicom cartridge emulation for Multigame Carts PCBs + + + Here we emulate several PCBs used in multigame pirate carts (not MMC-3 based) + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "multigame.h" + + +#ifdef NES_PCB_DEBUG +#define VERBOSE 1 +#else +#define VERBOSE 0 +#endif + +#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) + + +//------------------------------------------------- +// constructor +//------------------------------------------------- + +const device_type NES_ACTION52 = &device_creator; +const device_type NES_CALTRON6IN1 = &device_creator; +const device_type NES_RUMBLESTATION = &device_creator; +const device_type NES_SVISION16 = &device_creator; +const device_type NES_N625092 = &device_creator; +const device_type NES_A65AS = &device_creator; +const device_type NES_T262 = &device_creator; +const device_type NES_NOVEL1 = &device_creator; +const device_type NES_NOVEL2 = &device_creator; +const device_type NES_STUDYNGAME = &device_creator; +const device_type NES_SUPERGUN20IN1 = &device_creator; +const device_type NES_VT5201 = &device_creator; +const device_type NES_810544C = &device_creator; +const device_type NES_NTD03 = &device_creator; +const device_type NES_BMC_GB63 = &device_creator; +const device_type NES_BMC_GKA = &device_creator; +const device_type NES_BMC_GKB = &device_creator; +const device_type NES_BMC_WS = &device_creator; +const device_type NES_BMC_11160 = &device_creator; +const device_type NES_BMC_G146 = &device_creator; +const device_type NES_BMC_8157 = &device_creator; +const device_type NES_BMC_HIK300 = &device_creator; +const device_type NES_BMC_S700 = &device_creator; +const device_type NES_BMC_BALL11 = &device_creator; +const device_type NES_BMC_22GAMES = &device_creator; +const device_type NES_BMC_64Y2K = &device_creator; +const device_type NES_BMC_12IN1 = &device_creator; +const device_type NES_BMC_20IN1 = &device_creator; +const device_type NES_BMC_21IN1 = &device_creator; +const device_type NES_BMC_31IN1 = &device_creator; +const device_type NES_BMC_35IN1 = &device_creator; +const device_type NES_BMC_36IN1 = &device_creator; +const device_type NES_BMC_64IN1 = &device_creator; +const device_type NES_BMC_70IN1 = &device_creator; +const device_type NES_BMC_72IN1 = &device_creator; +const device_type NES_BMC_76IN1 = &device_creator; +const device_type NES_BMC_110IN1 = &device_creator; +const device_type NES_BMC_150IN1 = &device_creator; +const device_type NES_BMC_190IN1 = &device_creator; +const device_type NES_BMC_800IN1 = &device_creator; +const device_type NES_BMC_1200IN1 = &device_creator; +const device_type NES_BMC_GOLD150 = &device_creator; +const device_type NES_BMC_GOLD260 = &device_creator; +const device_type NES_BMC_CH001 = &device_creator; +const device_type NES_BMC_SUPER22 = &device_creator; +const device_type NES_BMC_4IN1RESET = &device_creator; +const device_type NES_BMC_42IN1RESET = &device_creator; + + +nes_action52_device::nes_action52_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_ACTION52, "NES Cart Action 52 PCB", tag, owner, clock, "nes_action52", __FILE__) +{ +} + +nes_caltron_device::nes_caltron_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_CALTRON6IN1, "NES Cart Caltron 6 in 1 PCB", tag, owner, clock, "nes_caltron", __FILE__) +{ +} + +nes_rumblestat_device::nes_rumblestat_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_RUMBLESTATION, "NES Cart Rumblestation PCB", tag, owner, clock, "nes_rumblestat", __FILE__) +{ +} + +nes_svision16_device::nes_svision16_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_SVISION16, "NES Cart Supervision 16 in 1 PCB", tag, owner, clock, "nes_svision16", __FILE__) +{ +} + +nes_n625092_device::nes_n625092_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_N625092, "NES Cart N625092 PCB", tag, owner, clock, "nes_n625092", __FILE__) +{ +} + +nes_a65as_device::nes_a65as_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_A65AS, "NES Cart A65AS PCB", tag, owner, clock, "nes_a65as", __FILE__) +{ +} + +nes_t262_device::nes_t262_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_T262, "NES Cart T-262 PCB", tag, owner, clock, "nes_t262", __FILE__) +{ +} + +nes_novel1_device::nes_novel1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_NOVEL1, "NES Cart Novel Diamond Type 1 PCB", tag, owner, clock, "nes_novel1", __FILE__) +{ +} + +nes_novel2_device::nes_novel2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_NOVEL2, "NES Cart Novel Diamond Type 2 PCB", tag, owner, clock, "nes_novel2", __FILE__) +{ +} + +nes_studyngame_device::nes_studyngame_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_STUDYNGAME, "NES Cart Study n Game PCB", tag, owner, clock, "nes_studyngame", __FILE__) +{ +} + +nes_sgun20in1_device::nes_sgun20in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_SUPERGUN20IN1, "NES Cart Supergun 20 in 1 PCB", tag, owner, clock, "nes_sgun20in1", __FILE__) +{ +} + +nes_vt5201_device::nes_vt5201_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_VT5201, "NES Cart VT5201 PCB", tag, owner, clock, "nes_vt5201", __FILE__) +{ +} + +nes_810544c_device::nes_810544c_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_810544C, "NES Cart 810544-C-A1 PCB", tag, owner, clock, "nes_810544c", __FILE__) +{ +} + +nes_ntd03_device::nes_ntd03_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_NTD03, "NES Cart NTD-03 PCB", tag, owner, clock, "nes_ntd03", __FILE__) +{ +} + +nes_bmc_gb63_device::nes_bmc_gb63_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_BMC_GB63, "NES Cart BMC Ghostbusters 63 in 1 PCB", tag, owner, clock, "nes_bmc_gb63", __FILE__) +{ +} + +nes_bmc_gka_device::nes_bmc_gka_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_BMC_GKA, "NES Cart BMC GK-A PCB", tag, owner, clock, "nes_bmc_gka", __FILE__) +{ +} + +nes_bmc_gkb_device::nes_bmc_gkb_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_BMC_GKB, "NES Cart BMC GK-B PCB", tag, owner, clock, "nes_bmc_gkb", __FILE__) +{ +} + +nes_bmc_ws_device::nes_bmc_ws_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_BMC_WS, "NES Cart BMC WS PCB", tag, owner, clock, "nes_bmc_ws", __FILE__) +{ +} + +nes_bmc_11160_device::nes_bmc_11160_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_BMC_11160, "NES Cart BMC-11160 PCB", tag, owner, clock, "nes_bmc_11160", __FILE__) +{ +} + +nes_bmc_g146_device::nes_bmc_g146_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_BMC_G146, "NES Cart BMC-G-146 PCB", tag, owner, clock, "nes_bmc_g146", __FILE__) +{ +} + +nes_bmc_8157_device::nes_bmc_8157_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_BMC_8157, "NES Cart BMC-8157 PCB", tag, owner, clock, "nes_bmc_8157", __FILE__) +{ +} + +nes_bmc_hik300_device::nes_bmc_hik300_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_BMC_HIK300, "NES Cart BMC HIK 300 in 1 PCB", tag, owner, clock, "nes_bmc_hik300", __FILE__) +{ +} + +nes_bmc_s700_device::nes_bmc_s700_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_BMC_S700, "NES Cart BMC Super 700 in 1 PCB", tag, owner, clock, "nes_bmc_s700", __FILE__) +{ +} + +nes_bmc_ball11_device::nes_bmc_ball11_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_BMC_BALL11, "NES Cart BMC Ball 11 in 1 PCB", tag, owner, clock, "nes_bmc_ball11", __FILE__) +{ +} + +nes_bmc_22games_device::nes_bmc_22games_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_BMC_22GAMES, "NES Cart BMC 22 Games PCB", tag, owner, clock, "nes_bmc_22games", __FILE__) +{ +} + +nes_bmc_64y2k_device::nes_bmc_64y2k_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_BMC_64Y2K, "NES Cart BMC 64 in 1 Y2K PCB", tag, owner, clock, "nes_bmc_64y2k", __FILE__) +{ +} + +nes_bmc_12in1_device::nes_bmc_12in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_BMC_12IN1, "NES Cart BMC 12 in 1 PCB", tag, owner, clock, "nes_bmc_12in1", __FILE__) +{ +} + +nes_bmc_20in1_device::nes_bmc_20in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_BMC_20IN1, "NES Cart BMC 20 in 1 PCB", tag, owner, clock, "nes_bmc_20in1", __FILE__) +{ +} + +nes_bmc_21in1_device::nes_bmc_21in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_BMC_21IN1, "NES Cart BMC 21 in 1 PCB", tag, owner, clock, "nes_bmc_21in1", __FILE__) +{ +} + +nes_bmc_31in1_device::nes_bmc_31in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_BMC_31IN1, "NES Cart BMC 31 in 1 PCB", tag, owner, clock, "nes_bmc_31in1", __FILE__) +{ +} + +nes_bmc_35in1_device::nes_bmc_35in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_BMC_35IN1, "NES Cart BMC 35 in 1 PCB", tag, owner, clock, "nes_bmc_35in1", __FILE__) +{ +} + +nes_bmc_36in1_device::nes_bmc_36in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_BMC_36IN1, "NES Cart BMC 36 in 1 PCB", tag, owner, clock, "nes_bmc_36in1", __FILE__) +{ +} + +nes_bmc_64in1_device::nes_bmc_64in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_BMC_64IN1, "NES Cart BMC 64 in 1 PCB", tag, owner, clock, "nes_bmc_64in1", __FILE__) +{ +} + +nes_bmc_70in1_device::nes_bmc_70in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_BMC_70IN1, "NES Cart BMC 70 in 1 PCB", tag, owner, clock, "nes_bmc_70in1", __FILE__) +{ +} + +nes_bmc_72in1_device::nes_bmc_72in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_BMC_72IN1, "NES Cart BMC 72 in 1 PCB", tag, owner, clock, "nes_bmc_72in1", __FILE__) +{ +} + +nes_bmc_76in1_device::nes_bmc_76in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_BMC_76IN1, "NES Cart BMC 76 in 1 PCB", tag, owner, clock, "nes_bmc_76in1", __FILE__) +{ +} + +nes_bmc_110in1_device::nes_bmc_110in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_BMC_110IN1, "NES Cart BMC 110 in 1 PCB", tag, owner, clock, "nes_bmc_110in1", __FILE__) +{ +} + +nes_bmc_150in1_device::nes_bmc_150in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_BMC_150IN1, "NES Cart BMC 150 in 1 PCB", tag, owner, clock, "nes_bmc_150in1", __FILE__) +{ +} + +nes_bmc_190in1_device::nes_bmc_190in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_BMC_190IN1, "NES Cart BMC 190 in 1 PCB", tag, owner, clock, "nes_bmc_190in1", __FILE__) +{ +} + +nes_bmc_800in1_device::nes_bmc_800in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_BMC_800IN1, "NES Cart BMC 800 in 1 PCB", tag, owner, clock, "nes_bmc_800in1", __FILE__) +{ +} + +nes_bmc_1200in1_device::nes_bmc_1200in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_BMC_1200IN1, "NES Cart BMC 1200 in 1 PCB", tag, owner, clock, "nes_bmc_1200in1", __FILE__) +{ +} + +nes_bmc_gold150_device::nes_bmc_gold150_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_BMC_GOLD150, "NES Cart BMC Golden 150 in 1 PCB", tag, owner, clock, "nes_bmc_gold150", __FILE__) +{ +} + +nes_bmc_gold260_device::nes_bmc_gold260_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_BMC_GOLD260, "NES Cart BMC Golden 260 in 1 PCB", tag, owner, clock, "nes_bmc_gold260", __FILE__) +{ +} + +nes_bmc_ch001_device::nes_bmc_ch001_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_BMC_CH001, "NES Cart BMC CH-001 PCB", tag, owner, clock, "nes_bmc_ch001", __FILE__) +{ +} + +nes_bmc_super22_device::nes_bmc_super22_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_BMC_SUPER22, "NES Cart BMC Super 22 Games PCB", tag, owner, clock, "nes_bmc_super22", __FILE__) +{ +} + +nes_bmc_4in1reset_device::nes_bmc_4in1reset_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_BMC_4IN1RESET, "NES Cart BMC 4 in 1 (Reset Based) PCB", tag, owner, clock, "nes_bmc_4in1reset", __FILE__) +{ +} + +nes_bmc_42in1reset_device::nes_bmc_42in1reset_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_BMC_42IN1RESET, "NES Cart BMC 42 in 1 (Reset Based) PCB", tag, owner, clock, "nes_bmc_42in1reset", __FILE__) +{ +} + + + + +void nes_action52_device::device_start() +{ + common_start(); +} + +void nes_action52_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); +} + +void nes_caltron_device::device_start() +{ + common_start(); + save_item(NAME(m_latch)); +} + +void nes_caltron_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); + + m_latch = 0; +} + +void nes_rumblestat_device::device_start() +{ + common_start(); + save_item(NAME(m_prg)); + save_item(NAME(m_chr)); +} + +void nes_rumblestat_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); + + m_prg = 0; + m_chr = 0; +} + +void nes_svision16_device::device_start() +{ + common_start(); + save_item(NAME(m_latch1)); + save_item(NAME(m_latch2)); +} + +void nes_svision16_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); + + m_latch1 = 0; + m_latch2 = 0; +} + +void nes_n625092_device::device_start() +{ + common_start(); + save_item(NAME(m_latch1)); + save_item(NAME(m_latch2)); +} + +void nes_n625092_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(0); + chr8(0, m_chr_source); + + m_latch1 = 0; + m_latch2 = 0; +} + +void nes_a65as_device::device_start() +{ + common_start(); +} + +void nes_a65as_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(7); + set_nt_mirroring(PPU_MIRROR_VERT); + chr8(0, m_chr_source); +} + +void nes_t262_device::device_start() +{ + common_start(); + save_item(NAME(m_latch1)); + save_item(NAME(m_latch2)); +} + +void nes_t262_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(7); + chr8(0, m_chr_source); + + m_latch1 = 0; + m_latch2 = 0; +} + +void nes_novel1_device::device_start() +{ + common_start(); +} + +void nes_novel1_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); + set_nt_mirroring(PPU_MIRROR_VERT); +} + +void nes_novel2_device::device_start() +{ + common_start(); +} + +void nes_novel2_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); +} + +void nes_studyngame_device::device_start() +{ + common_start(); +} + +void nes_studyngame_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); +} + +void nes_sgun20in1_device::device_start() +{ + common_start(); +} + +void nes_sgun20in1_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(0); + chr8(0, m_chr_source); +} + +void nes_vt5201_device::device_start() +{ + common_start(); + save_item(NAME(m_latch)); + save_item(NAME(m_dipsetting)); +} + +void nes_vt5201_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); + + m_latch = 0; + m_dipsetting = 0; +} + +void nes_810544c_device::device_start() +{ + common_start(); +} + +void nes_810544c_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(0); + chr8(0, m_chr_source); + set_nt_mirroring(PPU_MIRROR_VERT); +} + +void nes_ntd03_device::device_start() +{ + common_start(); +} + +void nes_ntd03_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); +} + +void nes_bmc_gb63_device::device_start() +{ + common_start(); + save_item(NAME(m_latch)); + save_item(NAME(m_dipsetting)); + save_item(NAME(m_reg)); + save_item(NAME(m_vram_disable)); +} + +void nes_bmc_gb63_device::pcb_reset() +{ + prg16_89ab(0); + prg16_cdef(0xfff); + chr8(0, CHRRAM); + + m_latch = 0; + m_dipsetting = 0; + m_reg[0] = 0; + m_reg[1] = 0; + update_banks(); + m_vram_disable = 0; +} + +void nes_bmc_gka_device::device_start() +{ + common_start(); + save_item(NAME(m_latch1)); + save_item(NAME(m_latch2)); +} + +void nes_bmc_gka_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(0); + chr8(0, m_chr_source); + + m_latch1 = 0; + m_latch2 = 0; +} + +void nes_bmc_gkb_device::device_start() +{ + common_start(); +} + +void nes_bmc_gkb_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); +} + +void nes_bmc_ws_device::device_start() +{ + common_start(); + save_item(NAME(m_latch)); +} + +void nes_bmc_ws_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); + + m_latch = 0; +} + +void nes_bmc_11160_device::device_start() +{ + common_start(); +} + +void nes_bmc_11160_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); +} + +void nes_bmc_g146_device::device_start() +{ + common_start(); +} + +void nes_bmc_g146_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); +} + +void nes_bmc_8157_device::device_start() +{ + common_start(); +} + +void nes_bmc_8157_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); +} + +void nes_bmc_hik300_device::device_start() +{ + common_start(); +} + +void nes_bmc_hik300_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0xff); + chr8(0xff, CHRROM); +} + +void nes_bmc_s700_device::device_start() +{ + common_start(); +} + +void nes_bmc_s700_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); +} + +void nes_bmc_ball11_device::device_start() +{ + common_start(); + save_item(NAME(m_reg)); +} + +void nes_bmc_ball11_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); + + m_reg[0] = 1; + m_reg[1] = 0; + set_banks(); +} + +void nes_bmc_22games_device::device_start() +{ + common_start(); +} + +void nes_bmc_22games_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(7); + chr8(0, m_chr_source); +} + +void nes_bmc_64y2k_device::device_start() +{ + common_start(); + save_item(NAME(m_reg)); +} + +void nes_bmc_64y2k_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + chr8(0, m_chr_source); + + m_reg[0] = 0x80; + m_reg[1] = 0x43; + m_reg[2] = m_reg[3] = 0; + set_prg(); + set_nt_mirroring(PPU_MIRROR_VERT); +} + +void nes_bmc_12in1_device::device_start() +{ + common_start(); + save_item(NAME(m_reg)); +} + +void nes_bmc_12in1_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); + m_reg[0] = 0; + m_reg[1] = 0; + m_reg[2] = 0; + update_banks(); +} + +void nes_bmc_20in1_device::device_start() +{ + common_start(); +} + +void nes_bmc_20in1_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); + set_nt_mirroring(PPU_MIRROR_VERT); +} + +void nes_bmc_21in1_device::device_start() +{ + common_start(); +} + +void nes_bmc_21in1_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); +} + +void nes_bmc_31in1_device::device_start() +{ + common_start(); +} + +void nes_bmc_31in1_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(1); + chr8(0, m_chr_source); +} + +void nes_bmc_35in1_device::device_start() +{ + common_start(); +} + +void nes_bmc_35in1_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(0); + chr8(0, m_chr_source); +} + +void nes_bmc_36in1_device::device_start() +{ + common_start(); +} + +void nes_bmc_36in1_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(m_prg_chunks - 1); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); +} + +void nes_bmc_64in1_device::device_start() +{ + common_start(); +} + +void nes_bmc_64in1_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(0); + chr8(0, m_chr_source); +} + +void nes_bmc_70in1_device::device_start() +{ + common_start(); + save_item(NAME(m_reg)); + save_item(NAME(m_mode)); +} + +void nes_bmc_70in1_device::pcb_reset() +{ + prg16_89ab(m_prg_chunks - 1); + prg16_cdef(m_prg_chunks - 1); + chr8(0, CHRROM); + m_reg[0] = 0; + m_reg[1] = 0; + m_mode = 0; +} + +void nes_bmc_72in1_device::device_start() +{ + common_start(); +} + +void nes_bmc_72in1_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); +} + +void nes_bmc_76in1_device::device_start() +{ + common_start(); + save_item(NAME(m_latch1)); + save_item(NAME(m_latch2)); +} + +void nes_bmc_76in1_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); + + m_latch1 = 0; + m_latch2 = 0; +} + +void nes_bmc_110in1_device::device_start() +{ + common_start(); +} + +void nes_bmc_110in1_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(1); + chr8(0, m_chr_source); + set_nt_mirroring(PPU_MIRROR_VERT); +} + +void nes_bmc_150in1_device::device_start() +{ + common_start(); +} + +void nes_bmc_150in1_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(0); + chr8(0, m_chr_source); +} + +void nes_bmc_190in1_device::device_start() +{ + common_start(); +} + +void nes_bmc_190in1_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(0); + chr8(0, m_chr_source); +} + +void nes_bmc_800in1_device::device_start() +{ + common_start(); + save_item(NAME(m_reg)); + save_item(NAME(m_mode)); +} + +void nes_bmc_800in1_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(m_prg_chunks - 1); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); + m_reg[0] = 0; + m_reg[1] = 0; + m_mode = 0; +} + +void nes_bmc_1200in1_device::device_start() +{ + common_start(); + save_item(NAME(m_vram_protect)); +} + +void nes_bmc_1200in1_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(0); + chr8(0, m_chr_source); + m_vram_protect = 0; +} + +void nes_bmc_gold150_device::device_start() +{ + common_start(); + save_item(NAME(m_latch)); +} + +void nes_bmc_gold150_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); + + m_latch = 0; +} + +void nes_bmc_gold260_device::device_start() +{ + common_start(); +} + +void nes_bmc_gold260_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); +} + +void nes_bmc_ch001_device::device_start() +{ + common_start(); + save_item(NAME(m_latch)); +} + +void nes_bmc_ch001_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); + + m_latch = 0; +} + +void nes_bmc_super22_device::device_start() +{ + common_start(); +} + +void nes_bmc_super22_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); +} + + +// This PCB is fully emulated here :) +void nes_bmc_4in1reset_device::device_start() +{ + common_start(); + m_latch = -1; + save_item(NAME(m_latch)); +} + +void nes_bmc_4in1reset_device::pcb_reset() +{ + m_latch++; + m_latch &= 3; + chr8(m_latch, CHRROM); + prg16_89ab(m_latch); + prg16_cdef(m_latch); +} + + +void nes_bmc_42in1reset_device::device_start() +{ + common_start(); + m_latch = -1; + save_item(NAME(m_reg)); +} + +void nes_bmc_42in1reset_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + m_latch++; + m_latch &= 1; + chr8(0, m_chr_source); + prg32(m_latch << 4); + + m_reg[0] = 0; + m_reg[1] = 0; +} + + + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +/*------------------------------------------------- + + Active Entertainment Action 52 board emulation + + iNES: mapper 228 + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_action52_device::write_h) +{ + UINT8 pmode = offset & 0x20; + int pbank = (offset & 0x1fc0) >> 6; + int cbank = (data & 0x03) | ((offset & 0x0f) << 2); + LOG_MMC(("ae_act52_w, offset: %04x, data: %02x\n", offset, data)); + + set_nt_mirroring(BIT(offset, 13) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + + chr8(cbank, CHRROM); + + if (pmode) + { + prg16_89ab(pbank); + prg16_cdef(pbank); + } + else + prg32(pbank >> 1); +} + +/*------------------------------------------------- + + Caltron 6 in 1 Board + + Games: 6 in 1 by Caltron + + iNES: mapper 41 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_caltron_device::write_m) +{ + LOG_MMC(("caltron write_m, offset: %04x, data: %02x\n", offset, data)); + + m_latch = offset & 0xff; + set_nt_mirroring(BIT(data, 5) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + prg32(offset & 0x07); +} + +WRITE8_MEMBER(nes_caltron_device::write_h) +{ + LOG_MMC(("caltron write_h, offset: %04x, data: %02x\n", offset, data)); + + if (m_latch & 0x04) + chr8(((m_latch & 0x18) >> 1) | (data & 0x03), CHRROM); +} + +/*------------------------------------------------- + + Rumblestation Board + + Games: Rumblestation 15 in 1 + + iNES: mapper 46 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_rumblestat_device::write_m) +{ + LOG_MMC(("rumblestation write_m, offset: %04x, data: %02x\n", offset, data)); + + m_prg = (m_prg & 0x01) | ((data & 0x0f) << 1); + m_chr = (m_chr & 0x07) | ((data & 0xf0) >> 1); + prg32(m_prg); + chr8(m_chr, CHRROM); +} + +WRITE8_MEMBER(nes_rumblestat_device::write_h) +{ + LOG_MMC(("rumblestation write_h, offset: %04x, data: %02x\n", offset, data)); + + // this pcb is subject to bus conflict + data = account_bus_conflict(offset, data); + + m_prg = (m_prg & ~0x01) | (data & 0x01); + m_chr = (m_chr & ~0x07) | ((data & 0x70) >> 4); + prg32(m_prg); + chr8(m_chr, CHRROM); +} + +/*------------------------------------------------- + + Supervision 16 in 1 Board + + Games: Supervision 16 in 1 + + iNES: mapper 53 + + In MESS: Partially Supported. (the dump contains 32KB of + EEPROM which is not currently handled well) + + -------------------------------------------------*/ + +void nes_svision16_device::update_prg() +{ + int base = (m_latch1 & 0x0f) << 3; + if (m_latch1 & 0x10) + { + prg16_89ab((base | (m_latch2 & 7)) + 2); // +2 due to the eeprom + prg16_cdef((base | 0x07) + 2); // +2 due to the eeprom + } + else + { + prg16_89ab(0); + prg16_cdef(1); + } + +} + +READ8_MEMBER(nes_svision16_device::read_m) +{ + int bank = (((m_latch1 & 0x0f) << 4) | 0x0f) + 4 ; // +4 due to the eeprom + LOG_MMC(("svision16 read_m, offset: %04x\n", offset)); + return m_prg[((bank * 0x2000) + (offset & 0x1fff)) & m_prg_mask]; +} + +WRITE8_MEMBER(nes_svision16_device::write_m) +{ + LOG_MMC(("svision16 write_m, offset: %04x, data: %02x\n", offset, data)); + + m_latch1 = data; + update_prg(); + set_nt_mirroring(BIT(data, 5) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); +} + +WRITE8_MEMBER(nes_svision16_device::write_h) +{ + LOG_MMC(("svision16 write_h, offset: %04x, data: %02x\n", offset, data)); + m_latch2 = data; + update_prg(); +} + +/*------------------------------------------------- + + Bootleg Board N625092 + + Games: 400 in 1, 700 in 1, 1000 in 1 + + iNES: mapper 221 + + In MESS: Supported. + + -------------------------------------------------*/ + +void nes_n625092_device::set_prg(UINT8 reg1, UINT8 reg2) +{ + UINT8 helper1, helper2; + + helper1 = !(reg1 & 0x01) ? reg2 : (reg1 & 0x80) ? reg2 : (reg2 & 0x06) | 0x00; + helper2 = !(reg1 & 0x01) ? reg2 : (reg1 & 0x80) ? 0x07 : (reg2 & 0x06) | 0x01; + + prg16_89ab(helper1 | ((reg1 & 0x70) >> 1)); + prg16_cdef(helper2 | ((reg1 & 0x70) >> 1)); +} + +WRITE8_MEMBER(nes_n625092_device::write_h) +{ + LOG_MMC(("n625092 write_h, offset: %04x, data: %02x\n", offset, data)); + + if (offset < 0x4000) + { + set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + offset = (offset >> 1) & 0xff; + + if (m_latch1 != offset) + { + m_latch1 = offset; + set_prg(m_latch1, m_latch2); + } + } + else + { + offset &= 0x07; + + if (m_latch2 != offset) + { + m_latch2 = offset; + set_prg(m_latch1, m_latch2); + } + } +} + + +/*------------------------------------------------- + + Board BMC-A65AS + + Games: 3-in-1 (N068) + + In MESS: Supported + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_a65as_device::write_h) +{ + UINT8 helper = (data & 0x30) >> 1; + LOG_MMC(("a65as write_h, offset: %04x, data: %02x\n", offset, data)); + + if (data & 0x80) + set_nt_mirroring(BIT(data, 5) ? PPU_MIRROR_HIGH : PPU_MIRROR_LOW); + else + set_nt_mirroring(BIT(data, 3) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + + if (data & 0x40) + prg32(data >> 1); + else + { + prg16_89ab(helper | (data & 0x07)); + prg16_cdef(helper | 0x07); + } +} + +/*------------------------------------------------- + + Board BMC-T-262 + + Games: 4-in-1 (D-010), 8-in-1 (A-020) + + In MESS: Supported + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_t262_device::write_h) +{ + UINT8 mmc_helper; + LOG_MMC(("t262 write_h, offset: %04x, data: %02x\n", offset, data)); + + if (m_latch2 || offset == 0) + { + m_latch1 = (m_latch1 & 0x38) | (data & 0x07); + prg16_89ab(m_latch1); + } + else + { + m_latch2 = 1; + set_nt_mirroring(BIT(data, 1) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + mmc_helper = ((offset >> 3) & 0x20) | ((offset >> 2) & 0x18); + m_latch1 = mmc_helper | (m_latch1 & 0x07); + prg16_89ab(m_latch1); + prg16_cdef(mmc_helper | 0x07); + } +} + + +/*------------------------------------------------- + + BMC-NOVELDIAMOND and BMC-999999in1 + + Unknown Bootleg Multigame Board + Games: I only found 'Novel Diamond 999999-in-1.unf' using + this mapper (hence the code is used for BMC_NOVELDIAMOND + board). The code is included here in case a mapper 54 + dump arises. + + iNES: mappers 54 and 213 + + In MESS: Partial Support. + + -------------------------------------------------*/ + +// Are this correct or should they work the same? +WRITE8_MEMBER(nes_novel1_device::write_h) +{ + LOG_MMC(("novel1 write_h, offset: %04x, data: %02x\n", offset, data)); + + prg32(offset & 0x03); + chr8(offset & 0x07, CHRROM); +} + +WRITE8_MEMBER(nes_novel2_device::write_h) +{ + LOG_MMC(("novel2 write_h, offset: %04x, data: %02x\n", offset, data)); + + prg32(offset >> 1); + chr8(offset >> 3, CHRROM); +} + + +/*------------------------------------------------- + + Board UNL-STUDYNGAME + + Games: Study n Game 32 in 1 + + iNES: mapper 39 + + In MESS: Partially Supported (problems with PRG bankswitch, + only keyboard exercise work). + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_studyngame_device::write_h) +{ + LOG_MMC(("studyngame write_h, offset: %04x, data: %02x\n", offset, data)); + prg32(data); +} + +/*------------------------------------------------- + + BMC-SUPERGUN-20IN1 + + Unknown Bootleg Multigame Board + Games: Super Gun 20 in 1 + + iNES: mapper 214 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_sgun20in1_device::write_h) +{ + LOG_MMC(("supergun20in1 write_h, offset: %04x, data: %02x\n", offset, data)); + + prg16_89ab(offset >> 2); + prg16_cdef(offset >> 2); + chr8(offset, CHRROM); +} + +/*------------------------------------------------- + + BMC-VT5201 + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_vt5201_device::write_h) +{ + LOG_MMC(("vt5201 wirte_h, offset: %04x, data: %02x\n", offset, data)); + + m_latch = BIT(offset, 8); + + // not sure about this mirroring bit!! + // without it TN 95 in 1 has glitches in Lunar Ball; with it TN 95 in 1 has glitches in Galaxian! + set_nt_mirroring(BIT(data, 3) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + if (BIT(offset, 7)) + { + prg16_89ab((offset >> 4) & 0x07); + prg16_cdef((offset >> 4) & 0x07); + } + else + prg32((offset >> 5) & 0x03); + chr8(offset, CHRROM); +} + +READ8_MEMBER(nes_vt5201_device::read_h) +{ + LOG_MMC(("bmc_vt5201 read_h, offset: %04x\n", offset)); + // m_dipsetting = ioport("CARTDIPS")->read(); + + if (m_latch) + return m_dipsetting; // cart mode, depending on the Dip Switches (always zero atm, given we have no way to add cart-based DIPs) + else + return hi_access_rom(offset); +} + +/*------------------------------------------------- + + BMC-810544-C-A1 + + Games: 200-in-1 Elfland + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_810544c_device::write_h) +{ + UINT8 bank = (offset >> 7); + LOG_MMC(("810544 write_h, offset: %04x, data: %02x\n", offset, data)); + + if (!BIT(offset, 6)) + { + prg16_89ab((bank << 1) | BIT(offset, 5)); + prg16_cdef((bank << 1) | BIT(offset, 5)); + } + else + prg32(bank); + + set_nt_mirroring(BIT(offset, 4) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + + chr8(offset & 0x0f, CHRROM); +} + +/*------------------------------------------------- + + BMC-NTD-03 + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_ntd03_device::write_h) +{ + UINT8 pbank = (offset >> 10) & 0x1e; + UINT8 cbank = ((offset & 0x300) >> 5) | (offset & 0x07); + LOG_MMC(("ntd03 write_h, offset: %04x, data: %02x\n", offset, data)); + + if (BIT(offset, 7)) + { + prg16_89ab(pbank | BIT(offset, 6)); + prg16_cdef(pbank | BIT(offset, 6)); + } + else + prg32(pbank >> 1); + + set_nt_mirroring(BIT(offset, 10) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + + chr8(cbank, CHRROM); +} + +/*------------------------------------------------- + + BMC-GHOSTBUSTERS63IN1 + + in MESS: only preliminar support + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_bmc_gb63_device::chr_w) +{ + int bank = offset >> 10; + + if (!m_vram_disable) + m_chr_access[bank][offset & 0x3ff] = data; +} + +void nes_bmc_gb63_device::update_banks() +{ + set_nt_mirroring(BIT(m_reg[0], 6) ? PPU_MIRROR_VERT : PPU_MIRROR_HORZ); + + if (BIT(m_reg[0], 5)) + { + prg16_89ab(m_reg[0] & 0x1f); + prg16_cdef(m_reg[0] & 0x1f); + } + else + prg32((m_reg[0] & 0x1f) >> 1); + +// according to FCEUMM source, the game should be able to disable the VRAM, but this stops the game from working +// maybe the VRAM disable does not work at start? +// m_vram_disable = BIT(m_reg[1], 1) ? 0 : 1; +} + +WRITE8_MEMBER(nes_bmc_gb63_device::write_h) +{ + LOG_MMC(("bmc_gb63 write_h, offset: %04x, data: %02x\n", offset, data)); + + m_reg[offset & 1] = data; + m_latch = BIT(m_reg[0], 7) | (BIT(m_reg[1], 0) << 1); + update_banks(); +} + +READ8_MEMBER(nes_bmc_gb63_device::read_h) +{ + LOG_MMC(("bmc_gb63 read_h, offset: %04x\n", offset)); + // m_dipsetting = ioport("CARTDIPS")->read(); + + if (m_latch == 1) + return m_open_bus; // open bus + else + return hi_access_rom(offset); +} + + +/*------------------------------------------------- + + Board BMC-GKA + + Unknown Bootleg Multigame Board + Games: 6 in 1, 54 in 1, 106 in 1 + + iNES: mapper 57 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_bmc_gka_device::write_h) +{ + LOG_MMC(("bmc_gka write_h, offset: %04x, data: %02x\n", offset, data)); + + if (offset & 0x0800) + m_latch2 = data; + else + m_latch1 = data; + + if (m_latch2 & 0x80) + prg32(2 | (m_latch2 >> 6)); + else + { + prg16_89ab((m_latch2 >> 5) & 0x03); + prg16_cdef((m_latch2 >> 5) & 0x03); + } + + set_nt_mirroring((m_latch2 & 0x08) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + + chr8((m_latch1 & 0x03) | (m_latch2 & 0x07) | ((m_latch2 & 0x10) >> 1), CHRROM); +} + + +/*------------------------------------------------- + + Board BMC-GKB + + Unknown Bootleg Multigame Board + Games: 68 in 1, 73 in 1, 98 in 1 + + iNES: mapper 58 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_bmc_gkb_device::write_h) +{ + UINT8 bank = (offset & 0x40) ? 0 : 1; + LOG_MMC(("bmc_gkb write_h, offset: %04x, data: %02x\n", offset, data)); + + prg16_89ab(offset & ~bank); + prg16_cdef(offset | bank); + chr8(offset >> 3, m_chr_source); + set_nt_mirroring(BIT(data, 7) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); +} + +/*------------------------------------------------- + + Board BMC-WS + + Games: Super 40-in-1 + + In MESS: Partially Supported (some games, like Galaxian, have + issues) + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_bmc_ws_device::write_m) +{ + UINT8 mmc_helper; + LOG_MMC(("bmc_ws write_m, offset: %04x, data: %02x\n", offset, data)); + + if (offset < 0x1000) + { + switch (offset & 0x01) + { + case 0: + if (!m_latch) + { + m_latch = data & 0x20; + set_nt_mirroring(BIT(data, 4) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + mmc_helper = (~data & 0x08) >> 3; + prg16_89ab(data & ~mmc_helper); + prg16_cdef(data | mmc_helper); + } + break; + case 1: + if (!m_latch) + chr8(data, CHRROM); + break; + } + } +} + +/*------------------------------------------------- + + Board BMC-11160 (by TXC?) + + Games: 6 in 1 (MGC-023) + + In MESS: Partially Supported + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_bmc_11160_device::write_h) +{ + LOG_MMC(("bmc_11160 write_h, offset: %04x, data: %02x\n", offset, data)); + + prg32((data & 0x70) >> 4); + chr8(((data & 0x70) >> 2) | (data & 3), m_chr_source); + set_nt_mirroring(BIT(data, 7) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); +} + +/*------------------------------------------------- + + Board BMC-G-146 + + Games: 1994 Super HIK 14 in 1 (G-136) + + In MESS: Partially Supported + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_bmc_g146_device::write_h) +{ + LOG_MMC(("bmc_g146 write_h, offset: %04x, data: %02x\n", offset, data)); + + if (offset & 0x800) + { + // UNROM mode + int helper = offset & BIT(offset, 6); + prg16_89ab((offset & 0x1f) | helper); + prg16_cdef((offset & 0x18) | 7); + } + else if (offset & 0x40) + { + // 16KB mode + prg16_89ab(offset & 0x1f); + prg16_cdef(offset & 0x1f); + } + else + prg32((offset & 0x1f) >> 4); + + set_nt_mirroring(!BIT(offset, 7) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); +} + +/*------------------------------------------------- + + Board BMC-8157 + + Games: 4 in 1 1993 (CK-001) + + In MESS: Partially Supported + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_bmc_8157_device::write_h) +{ + LOG_MMC(("bmc_8157 write_h, offset: %04x, data: %02x\n", offset, data)); + + prg16_89ab((offset >> 2) & 0x1f); + if (offset & 0x200) + prg16_cdef(offset & 0x1f); + else + prg16_cdef((offset & 0x18) | 7); + + set_nt_mirroring(!BIT(offset, 1) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); +} + +READ8_MEMBER(nes_bmc_8157_device::read_h) +{ + LOG_MMC(("bmc_8157 read_h, offset: %04x\n", offset)); + // m_dipsetting = ioport("CARTDIPS")->read(); + +// UINT8 val = hi_access_rom(offset); +// return val | m_noise; // the first write_h sets m_noise=0xff or 0 depending on dsw + + return hi_access_rom(offset); +} + + +/*------------------------------------------------- + + BMC-SUPERHIK_300IN1 + + Unknown Bootleg Multigame Board + Games: 100000 in 1, Super HIK 300 in 1, 1997 in 1 + + iNES: mapper 212 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_bmc_hik300_device::write_h) +{ + LOG_MMC(("bmc_hik300 write_h, offset: %04x, data: %02x\n", offset, data)); + + set_nt_mirroring(BIT(data, 3) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + chr8(offset, CHRROM); + + if (offset < 0x4000) + { + prg16_89ab(offset); + prg16_cdef(offset); + } + else + prg32(offset >> 1); +} + +/*------------------------------------------------- + + BMC-SUPER-700IN1 + + Unknown Bootleg Multigame Board + Games: Super 700 in 1 + + iNES: mapper 62 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_bmc_s700_device::write_h) +{ + LOG_MMC(("bmc_s700 write_h, offset :%04x, data: %02x\n", offset, data)); + + chr8(((offset & 0x1f) << 2) | (data & 0x03), CHRROM); + + if (offset & 0x20) + { + prg16_89ab((offset & 0x40) | ((offset >> 8) & 0x3f)); + prg16_cdef((offset & 0x40) | ((offset >> 8) & 0x3f)); + } + else + { + prg32(((offset & 0x40) | ((offset >> 8) & 0x3f)) >> 1); + } + + set_nt_mirroring(BIT(data, 7) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); +} + +/*------------------------------------------------- + + BMC-BALLGAMES-11IN1 + + Known Boards: Unknown Multigame Bootleg Board + Games: 11 in 1 Ball Games + + iNES: mapper 51 + + In MESS: Partially Supported. + + -------------------------------------------------*/ + +void nes_bmc_ball11_device::set_banks() +{ + set_nt_mirroring((m_reg[0] == 3) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + + if (m_reg[0] & 0x01) + { + prg32(m_reg[1]); + } + else + { + prg16_89ab((m_reg[1] << 1) | (m_reg[0] >> 1)); + prg16_cdef((m_reg[1] << 1) | 0x07); + } +} + +WRITE8_MEMBER(nes_bmc_ball11_device::write_m) +{ + LOG_MMC(("bmc_ball11 write_m, offset: %04x, data: %02x\n", offset, data)); + + m_reg[0] = ((data >> 1) & 0x01) | ((data >> 3) & 0x02); + set_banks(); +} + +WRITE8_MEMBER(nes_bmc_ball11_device::write_h) +{ + LOG_MMC(("bmc_ball11 write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x6000) + { + case 0x4000: // here we also update reg[0] upper bit + m_reg[0] = (m_reg[0] & 0x01) | ((data >> 3) & 0x02); + case 0x0000: + case 0x2000: + case 0x6000: + m_reg[1] = data & 0x0f; + set_banks(); + break; + } +} + +/*------------------------------------------------- + + BMC-22GAMES + + Unknown Bootleg Multigame Board + Games: 22 in 1 + + iNES: mapper 230 + + In MESS: Partially Supported. It would need a reset + to work (not possible yet) + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_bmc_22games_device::write_h) +{ + LOG_MMC(("bmc_22games write_h, offset: %04x, data: %02x\n", offset, data)); + + if (1) // this should flip at reset + { + prg16_89ab(data & 0x07); + } + else + { + if (data & 0x20) + { + prg16_89ab((data & 0x1f) + 8); + prg16_cdef((data & 0x1f) + 8); + } + else + { + prg16_89ab((data & 0x1f) + 8); + prg16_cdef((data & 0x1f) + 9); + } + set_nt_mirroring(BIT(data, 6) ? PPU_MIRROR_VERT : PPU_MIRROR_HORZ); + } +} + +/*------------------------------------------------- + + Board BMC-64IN1NOREPEAT + + Games: 64-in-1 Y2K + + In MESS: Supported + + -------------------------------------------------*/ + +void nes_bmc_64y2k_device::set_prg() +{ + UINT8 helper1 = (m_reg[1] & 0x1f); + UINT8 helper2 = (helper1 << 1) | ((m_reg[1] & 0x40) >> 6); + + if (m_reg[0] & 0x80) + { + if (m_reg[1] & 0x80) + prg32(helper1); + else + { + prg16_89ab(helper2); + prg16_cdef(helper2); + } + } + else + prg16_cdef(helper2); +} + +WRITE8_MEMBER(nes_bmc_64y2k_device::write_l) +{ + LOG_MMC(("bmc64y2k write_l, offset: %04x, data: %02x\n", offset, data)); + offset += 0x100; + + switch (offset) + { + case 0x1000: + case 0x1001: + case 0x1002: + case 0x1003: + m_reg[offset & 0x03] = data; + set_prg(); + chr8(((m_reg[0] >> 1) & 0x03) | (m_reg[2] << 2), CHRROM); + break; + } + if (offset == 0x1000) /* write to reg[0] also sets mirroring */ + set_nt_mirroring(BIT(data, 5) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); +} + +WRITE8_MEMBER(nes_bmc_64y2k_device::write_h) +{ + LOG_MMC(("bmc64y2k write_h, offset: %04x, data: %02x\n", offset, data)); + + m_reg[3] = data; // reg[3] is currently unused?!? +} + +/*------------------------------------------------- + + BMC-12IN1 + + Unknown Bootleg Multigame Board + Games: + + iNES: + + In MESS: Supported. + + -------------------------------------------------*/ + +void nes_bmc_12in1_device::update_banks() +{ + int bank = (m_reg[2] & 3) << 3; + + chr4_0((m_reg[0] >> 3) | (bank << 2), m_chr_source); + chr4_4((m_reg[1] >> 3) | (bank << 2), m_chr_source); + + if (m_reg[2] & 8) + prg32(((m_reg[0] & 7) >> 1) | bank); + else + { + prg16_89ab((m_reg[0] & 7) | bank); + prg16_cdef(7 | bank); + } + + set_nt_mirroring(BIT(m_reg[2], 2) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); +} + +WRITE8_MEMBER(nes_bmc_12in1_device::write_h) +{ + LOG_MMC(("bmc_12in1 write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x6000) + { + case 0x2000: m_reg[0] = data; break; + case 0x4000: m_reg[1] = data; break; + case 0x6000: m_reg[2] = data; break; + } + update_banks(); +} + +/*------------------------------------------------- + + BMC-20IN1 + + Unknown Bootleg Multigame Board + Games: 20 in 1 + + iNES: mapper 231 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_bmc_20in1_device::write_h) +{ + LOG_MMC(("bmc_20in1 write_h, offset: %04x, data: %02x\n", offset, data)); + + set_nt_mirroring(BIT(data, 7) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + + prg16_89ab((offset & 0x1e)); + prg16_cdef((offset & 0x1e) | ((offset & 0x20) ? 1 : 0)); +} + +/*------------------------------------------------- + + BMC-21IN1 + + Unknown Bootleg Multigame Board + Games: 8 in 1, 21 in 1 + + iNES: mapper 201 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_bmc_21in1_device::write_h) +{ + LOG_MMC(("bmc_21in1 write_h, offset: %04x, data: %02x\n", offset, data)); + + prg32(offset & 0x03); + chr8(offset & 0x03, CHRROM); +} + +/*------------------------------------------------- + + BMC-31IN1 + + Unknown Bootleg Multigame Board + Games: 31 in 1 + + iNES: mapper 229 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_bmc_31in1_device::write_h) +{ + LOG_MMC(("bmc_31in1 write_h, offset: %04x, data: %02x\n", offset, data)); + + set_nt_mirroring(BIT(data, 5) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + chr8(offset, CHRROM); + + if ((offset & 0x1e) == 0) + { + prg16_89ab(0); + prg16_89ab(1); + } + else + { + prg16_89ab(offset & 0x1f); + prg16_89ab(offset & 0x1f); + } +} + +/*------------------------------------------------- + + BMC-35IN1 + + Unknown Bootleg Multigame Board + Games: 35 in 1 + + iNES: mapper 203 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_bmc_35in1_device::write_h) +{ + LOG_MMC(("bmc_35in1 write_h, offset: %04x, data: %02x\n", offset, data)); + + prg16_89ab((data >> 2) & 0x03); + prg16_cdef((data >> 2) & 0x03); + chr8(data & 0x03, CHRROM); +} + +/*------------------------------------------------- + + BMC-36IN1 + + Unknown Bootleg Multigame Board + Games: 36 in 1, 1200 in 1 + + iNES: mapper 200 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_bmc_36in1_device::write_h) +{ + LOG_MMC(("bmc_36in1 write_h, offset: %04x, data: %02x\n", offset, data)); + + prg16_89ab(offset & 0x07); + prg16_cdef(offset & 0x07); + chr8(offset & 0x07, CHRROM); + + set_nt_mirroring(BIT(data, 3) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); +} + +/*------------------------------------------------- + + BMC-64IN1 + + Unknown Bootleg Multigame Board + Games: 64 in 1 + + iNES: mapper 204 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_bmc_64in1_device::write_h) +{ + int bank = (offset >> 1) & (offset >> 2) & 0x01; + + LOG_MMC(("bmc_64in1 write_h, offset: %04x, data: %02x\n", offset, data)); + + prg16_89ab(offset & ~bank); + prg16_cdef(offset | bank); + chr8(offset & ~bank, CHRROM); + + set_nt_mirroring(BIT(data, 4) ? PPU_MIRROR_HORZ: PPU_MIRROR_VERT); +} + +/*------------------------------------------------- + + BMC-70IN1 + + Unknown Bootleg Multigame Board + Games: + + iNES: mapper + + This is same hardware as BMC-800IN1 below, but this + cart has CHR and slightly diff bankswitch. + DSW not emulated yet. + + In MESS: Preliminary Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_bmc_70in1_device::write_h) +{ + LOG_MMC(("bmc70in1 write_h, offset: %04x, data: %02x\n", offset, data)); + + if (offset < 0x4000) + { + set_nt_mirroring(BIT(offset, 5) ? PPU_MIRROR_HORZ: PPU_MIRROR_VERT); + chr8(offset & 7, CHRROM); + } + else + { + switch (offset & 0x30) + { + case 0x00: m_mode = 0x0; m_reg[0] = (m_reg[0] & 0x38) | (offset & 0x7); m_reg[1] = m_reg[0] | 0x7; break; + case 0x10: m_mode = 0x1; m_reg[0] = (m_reg[0] & 0x38) | (offset & 0x7); m_reg[1] = m_reg[0] | 0x7; break; + case 0x20: m_mode = 0x0; m_reg[0] = (m_reg[0] & 0x38) | (offset & 0x6); m_reg[1] = m_reg[0] | 0x1; break; + case 0x30: m_mode = 0x0; m_reg[0] = (m_reg[0] & 0x38) | (offset & 0x7); m_reg[1] = m_reg[0] | 0x0; break; + } + prg16_89ab(m_reg[0]); + prg16_cdef(m_reg[1]); + } +} + +READ8_MEMBER(nes_bmc_70in1_device::read_h) +{ + LOG_MMC(("bmc70in1 read_h, offset: %04x\n", offset)); + + if (m_mode) + offset = (offset & 0x7ff0) | m_mode; + + return hi_access_rom(offset); +} + +/*------------------------------------------------- + + BMC-72IN1 + + Unknown Bootleg Multigame Board + Games: 72 in 1, 115 in 1 and other multigame carts + + iNES: mapper 225 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_bmc_72in1_device::write_h) +{ + int hi_bank = offset & 0x40; + int size_16 = offset & 0x1000; + int bank = (offset & 0xf80) >> 7; + + LOG_MMC(("bmc_72in1 write_h, offset: %04x, data: %02x\n", offset, data)); + + chr8(offset, CHRROM); + set_nt_mirroring((offset & 0x2000) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + if (size_16) + { + bank <<= 1; + if (hi_bank) + bank ++; + + prg16_89ab(bank); + prg16_cdef(bank); + } + else + prg32(bank); +} + +/*------------------------------------------------- + + BMC-76IN1 + + Unknown Bootleg Multigame Board + Games: 76 in 1, Super 42 in 1 + + iNES: mapper 226 + + In MESS: Supported. + + -------------------------------------------------*/ + +// does this work for super42in1 as well?!? +WRITE8_MEMBER(nes_bmc_76in1_device::write_h) +{ + int hi_bank; + int size_16; + int bank; + + LOG_MMC(("bmc_76in1 write_h, offset: %04x, data: %02x\n", offset, data)); + + if (offset & 0x01) + m_latch2 = data; + else + m_latch1 = data; + + set_nt_mirroring(BIT(m_latch1, 6) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + + hi_bank = m_latch1 & 0x01; + size_16 = m_latch1 & 0x20; + bank = ((m_latch1 & 0x1e) >> 1) | ((m_latch1 & 0x80) >> 3) | ((m_latch2 & 0x01) << 5); + + if (size_16) + { + bank <<= 1; + if (hi_bank) + bank ++; + + prg16_89ab(bank); + prg16_cdef(bank); + } + else + prg32(bank); +} + +/*------------------------------------------------- + + BMC-110IN1 + + Known Boards: Unknown Bootleg Board + Games: 110 in 1 + + iNES: mapper 255 + + In MESS: Preliminary support. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_bmc_110in1_device::write_h) +{ + UINT8 helper1 = (offset >> 12) ? 0 : 1; + UINT8 helper2 = ((offset >> 8) & 0x40) | ((offset >> 6) & 0x3f); + + LOG_MMC(("bmc_110in1 write_h, offset: %04x, data: %02x\n", offset, data)); + + set_nt_mirroring((offset & 0x2000) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + prg16_89ab(helper1 & ~helper2); + prg16_cdef(helper1 | helper2); + chr8(((offset >> 8) & 0x40) | (offset & 0x3f), CHRROM); +} + + +/*------------------------------------------------- + + BMC-150IN1 + + Unknown Bootleg Multigame Board + Games: 150 in 1 + + iNES: mapper 202 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_bmc_150in1_device::write_h) +{ + int bank = (offset >> 1) & 0x07; + + LOG_MMC(("bmc_150in1 write_h, offset: %04x, data: %02x\n", offset, data)); + + prg16_89ab(bank); + prg16_cdef(bank + (((bank & 0x06) == 0x06) ? 1 : 0)); + chr8(bank, CHRROM); + + set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_HORZ: PPU_MIRROR_VERT); +} + + +/*------------------------------------------------- + + Board BMC-190IN1 + + Games: 190-in-1 + + In MESS: Supported + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_bmc_190in1_device::write_h) +{ + LOG_MMC(("bmc190in1 write_h, offset: %04x, data: %02x\n", offset, data)); + + set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + offset >>= 2; + prg16_89ab(offset); + prg16_cdef(offset); + chr8(offset, CHRROM); +} + +/*------------------------------------------------- + + BMC-800IN1 + + Unknown Bootleg Multigame Board + Games: + + iNES: mapper + + DSW not emulated yet. + + In MESS: Preliminary Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_bmc_800in1_device::write_h) +{ + LOG_MMC(("bmc800in1 write_h, offset: %04x, data: %02x\n", offset, data)); + + if (offset < 0x4000) + { + set_nt_mirroring(BIT(offset, 5) ? PPU_MIRROR_HORZ: PPU_MIRROR_VERT); + + m_reg[0] = (m_reg[0]) | ((offset << 3) & 0x38); + m_reg[1] = (m_reg[1]) | ((offset << 3) & 0x38); + } + else + { + switch (offset & 0x30) + { + case 0x00: m_mode = 0x0; m_reg[0] = (m_reg[0] & 0x38) | (offset & 0x7); m_reg[1] = m_reg[0] | 0x7; break; + case 0x10: m_mode = 0x1; m_reg[0] = (m_reg[0] & 0x38) | (offset & 0x7); m_reg[1] = m_reg[0] | 0x7; break; + case 0x20: m_mode = 0x0; m_reg[0] = (m_reg[0] & 0x38) | (offset & 0x6); m_reg[1] = m_reg[0] | 0x1; break; + case 0x30: m_mode = 0x0; m_reg[0] = (m_reg[0] & 0x38) | (offset & 0x7); m_reg[1] = m_reg[0] | 0x0; break; + } + } + prg16_89ab(m_reg[0]); + prg16_cdef(m_reg[1]); +} + +READ8_MEMBER(nes_bmc_800in1_device::read_h) +{ + LOG_MMC(("bmc800in1 read_h, offset: %04x\n", offset)); + + if (m_mode) + offset = (offset & 0x7ff0) | m_mode; + + return hi_access_rom(offset); +} + +/*------------------------------------------------- + + BMC-1200IN1 + + Unknown Bootleg Multigame Board + Games: 1200 in 1, 295 in 1, 76 in 1 + + iNES: mapper 227 + + In MESS: Preliminary Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_bmc_1200in1_device::chr_w) +{ + int bank = offset >> 10; + + if (!m_vram_protect) + m_chr_access[bank][offset & 0x3ff] = data; +} + + +WRITE8_MEMBER(nes_bmc_1200in1_device::write_h) +{ + int bank = ((offset >> 2) & 0x1f) | ((offset & 0x0100) >> 3); + + LOG_MMC(("bmc_1200in1 write_h, offset: %04x, data: %02x\n", offset, data)); + + if (offset & 0x80) + { +// m_vram_protect = 1; + prg16_89ab(bank); + prg16_cdef(bank + (offset & 1)); + } + else + { + int low_mask = (offset & 1) ? 0x3e : 0xff; + +// m_vram_protect = 0; + if (!BIT(offset, 9)) + { + prg16_89ab(bank & low_mask); + prg16_cdef(bank & 0x38); + } + else + { + prg16_89ab(bank & low_mask); + prg16_cdef(bank | 0x07); + } + } + + set_nt_mirroring(BIT(offset, 1) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); +} + + +/*------------------------------------------------- + + BMC-GOLDEN260IN1 + + Unknown Bootleg Multigame Board + Games: + + iNES: mapper 235 + + In MESS: Preliminary Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_bmc_gold260_device::write_h) +{ + int bank = (offset & 0x1f) | ((offset & 0x0300) >> 3); + LOG_MMC(("bmc_gold260 write_h, offset: %04x, data: %02x\n", offset, data)); + + if (offset & 0x400) + set_nt_mirroring(PPU_MIRROR_LOW); + else + set_nt_mirroring(BIT(offset, 13) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + + if (offset & 0x800) + { + bank = (bank << 1) | BIT(offset, 12); + prg16_89ab(bank); + prg16_cdef(bank); + } + else + prg32(bank); +} + + +/*------------------------------------------------- + + BMC-GOLDEN150IN1 + + Unknown Bootleg Multigame Board + Games: + + iNES: mapper 235 + + Same as the above + open bus in 0x8000-0xffff when + enabled + + In MESS: Preliminary Supported. + + -------------------------------------------------*/ + + +WRITE8_MEMBER(nes_bmc_gold150_device::write_h) +{ + int bank = (offset & 0x1f) | ((offset & 0x0200) >> 4); + LOG_MMC(("bmc_gold150 write_h, offset: %04x, data: %02x\n", offset, data)); + + m_latch = (offset & 0x0100); + + if (offset & 0x400) + set_nt_mirroring(PPU_MIRROR_LOW); + else + set_nt_mirroring(BIT(offset, 13) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + + if (offset & 0x800) + { + bank = (bank << 1) | BIT(offset, 12); + prg16_89ab(bank); + prg16_cdef(bank); + } + else + prg32(bank); +} + +READ8_MEMBER(nes_bmc_gold150_device::read_h) +{ + LOG_MMC(("bmc_gold150 read_h, offset: %04x\n", offset)); + + if (m_latch) // open bus + return m_open_bus; + else + return hi_access_rom(offset); +} + + +/*------------------------------------------------- + + BMC-POWERFUL-255 + + Unknown Bootleg Multigame Board + Games: + + iNES: mapper 63 + + + In MESS: Preliminary Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_bmc_ch001_device::write_h) +{ + int bank = ((offset >> 1) & 0x1fc); + LOG_MMC(("bmc_ch001 write_h, offset: %04x, data: %02x\n", offset, data)); + + m_latch = ((offset & 0x300) == 0x300); + set_nt_mirroring(BIT(offset, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + + if (offset & 2) + { + prg8_89(bank + 0); + prg8_ab(bank + 1); + prg8_cd(bank + 2); + prg8_ef(bank + 3); + } + else + { + bank |= (offset & 4) >> 1; + prg8_89(bank + 0); + prg8_ab(bank + 1); + prg8_cd(bank + 0); + prg8_ef(bank + 1); + } + + if (offset & 0x800) // in this case, the last 8KB bank is switched differently... + prg8_ef((offset & 0x07c ) | ((offset & 0x6) ? 0x3 : 0x1)); +} + +READ8_MEMBER(nes_bmc_ch001_device::read_h) +{ + LOG_MMC(("bmc_ch001 read_h, offset: %04x\n", offset)); + + if (m_latch && offset < 0x4000) // open bus + return m_open_bus; + else + return hi_access_rom(offset); +} + +/*------------------------------------------------- + + BMC-SUPER22GAMES + + Unknown Bootleg Multigame Board + Games: + + iNES: + + is there a dsw to access the higher banks above 0x20? + + In MESS: Preliminary Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_bmc_super22_device::write_h) +{ + LOG_MMC(("bmc_super22 write_h, offset: %04x, data: %02x\n", offset, data)); + + if (data & 0x20) + { + prg16_89ab(data & 0x1f); + prg16_cdef(data & 0x1f); + } + else + prg32((data & 0x1f) >> 1); + + switch (data & 0xc0) + { + case 0x00: set_nt_mirroring(PPU_MIRROR_LOW); break; + case 0x40: set_nt_mirroring(PPU_MIRROR_VERT); break; + case 0x80: set_nt_mirroring(PPU_MIRROR_HORZ); break; + case 0xc0: set_nt_mirroring(PPU_MIRROR_HIGH); break; + } +} + + +/*------------------------------------------------- + + BMC-RESETBASED4IN1 + + Unknown Bootleg Multigame Board + + Games: + + iNES: + + No need to use handlers. At reset the banks change + and so does the game. + + In MESS: Preliminary Supported. + + -------------------------------------------------*/ + +/*------------------------------------------------- + + BMC-42IN1RESETBASED + + Unknown Bootleg Multigame Board + + Games: + + iNES: + + In MESS: Preliminary Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_bmc_42in1reset_device::write_h) +{ + int bank; + LOG_MMC(("bmc_42in1reset write_h, offset: %04x, data: %02x\n", offset, data)); + + m_reg[offset & 1] = data; + bank = (m_reg[0] & 0x1f) | (m_latch << 5) | ((m_reg[1] & 1) << 6); + + if (!(m_reg[0] & 0x20)) + prg32(bank >> 1); + else + { + prg16_89ab(bank); + prg16_cdef(bank); + } + + set_nt_mirroring(BIT(offset, 6) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + +} diff --git a/src/devices/bus/nes/multigame.h b/src/devices/bus/nes/multigame.h new file mode 100644 index 00000000000..dbc824dfd54 --- /dev/null +++ b/src/devices/bus/nes/multigame.h @@ -0,0 +1,894 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __NES_MULTIGAME_H +#define __NES_MULTIGAME_H + +#include "nxrom.h" + + +// ======================> nes_action52_device + +class nes_action52_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_action52_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); +}; + + +// ======================> nes_caltron_device + +class nes_caltron_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_caltron_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_m); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); + +private: + UINT8 m_latch; +}; + + +// ======================> nes_rumblestat_device + +class nes_rumblestat_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_rumblestat_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_m); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); + +private: + UINT8 m_prg, m_chr; +}; + + +// ======================> nes_svision16_device + +class nes_svision16_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_svision16_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_READ8_MEMBER(read_m); + virtual DECLARE_WRITE8_MEMBER(write_m); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); + +private: + void update_prg(); + UINT8 m_latch1, m_latch2; +}; + + +// ======================> nes_n625092_device + +class nes_n625092_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_n625092_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); + +private: + void set_prg(UINT8 reg1, UINT8 reg2); + UINT8 m_latch1, m_latch2; +}; + + +// ======================> nes_a65as_device + +class nes_a65as_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_a65as_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); +}; + + +// ======================> nes_t262_device + +class nes_t262_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_t262_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); + +private: + UINT8 m_latch1, m_latch2; +}; + + +// ======================> nes_novel1_device + +class nes_novel1_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_novel1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); +}; + + +// ======================> nes_novel2_device + +class nes_novel2_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_novel2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); +}; + + +// ======================> nes_studyngame_device + +class nes_studyngame_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_studyngame_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); +}; + + +// ======================> nes_sgun20in1_device + +class nes_sgun20in1_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_sgun20in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); +}; + + +// ======================> nes_vt5201_device + +class nes_vt5201_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_vt5201_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_READ8_MEMBER(read_h); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); + +private: + UINT8 m_latch, m_dipsetting; +}; + + +// ======================> nes_810544c_device + +class nes_810544c_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_810544c_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); +}; + + +// ======================> nes_ntd03_device + +class nes_ntd03_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_ntd03_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); +}; + + +// ======================> nes_bmc_gb63_device + +class nes_bmc_gb63_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_bmc_gb63_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_READ8_MEMBER(read_h); + virtual DECLARE_WRITE8_MEMBER(write_h); + virtual DECLARE_WRITE8_MEMBER(chr_w); + + virtual void pcb_reset(); + +private: + void update_banks(); + UINT8 m_latch, m_dipsetting; + UINT8 m_reg[2]; + int m_vram_disable; +}; + +// ======================> nes_bmc_gka_device + +class nes_bmc_gka_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_bmc_gka_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); + +private: + UINT8 m_latch1, m_latch2; +}; + + +// ======================> nes_bmc_gkb_device + +class nes_bmc_gkb_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_bmc_gkb_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); +}; + + +// ======================> nes_bmc_ws_device + +class nes_bmc_ws_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_bmc_ws_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_m); + + virtual void pcb_reset(); + +private: + UINT8 m_latch; +}; + + +// ======================> nes_bmc_11160_device + +class nes_bmc_11160_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_bmc_11160_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); +}; + + +// ======================> nes_bmc_g146_device + +class nes_bmc_g146_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_bmc_g146_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); +}; + + +// ======================> nes_bmc_8157_device + +class nes_bmc_8157_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_bmc_8157_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_READ8_MEMBER(read_h); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); +}; + + +// ======================> nes_bmc_hik300_device + +class nes_bmc_hik300_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_bmc_hik300_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); +}; + + +// ======================> nes_bmc_s700_device + +class nes_bmc_s700_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_bmc_s700_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); +}; + + +// ======================> nes_bmc_ball11_device + +class nes_bmc_ball11_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_bmc_ball11_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_m); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); + +private: + void set_banks(); + UINT8 m_reg[2]; +}; + + +// ======================> nes_bmc_22games_device + +class nes_bmc_22games_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_bmc_22games_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); +}; + + +// ======================> nes_bmc_64y2k_device + +class nes_bmc_64y2k_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_bmc_64y2k_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_l); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); + +private: + void set_prg(); + UINT8 m_reg[4]; +}; + + +// ======================> nes_bmc_12in1_device + +class nes_bmc_12in1_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_bmc_12in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); + +private: + void update_banks(); + UINT8 m_reg[3]; +}; + + +// ======================> nes_bmc_20in1_device + +class nes_bmc_20in1_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_bmc_20in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); +}; + + +// ======================> nes_bmc_21in1_device + +class nes_bmc_21in1_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_bmc_21in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); +}; + + +// ======================> nes_bmc_31in1_device + +class nes_bmc_31in1_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_bmc_31in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); +}; + + +// ======================> nes_bmc_35in1_device + +class nes_bmc_35in1_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_bmc_35in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); +}; + + +// ======================> nes_bmc_36in1_device + +class nes_bmc_36in1_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_bmc_36in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); +}; + + +// ======================> nes_bmc_64in1_device + +class nes_bmc_64in1_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_bmc_64in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); +}; + + +// ======================> nes_bmc_70in1_device + +class nes_bmc_70in1_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_bmc_70in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_READ8_MEMBER(read_h); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); + +private: + UINT8 m_mode; + UINT8 m_reg[2]; +}; + + +// ======================> nes_bmc_72in1_device + +class nes_bmc_72in1_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_bmc_72in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); +}; + + +// ======================> nes_bmc_76in1_device + +class nes_bmc_76in1_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_bmc_76in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); + +private: + UINT8 m_latch1, m_latch2; +}; + + +// ======================> nes_bmc_110in1_device + +class nes_bmc_110in1_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_bmc_110in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); +}; + + +// ======================> nes_bmc_150in1_device + +class nes_bmc_150in1_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_bmc_150in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); +}; + + +// ======================> nes_bmc_190in1_device + +class nes_bmc_190in1_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_bmc_190in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); +}; + + +// ======================> nes_bmc_800in1_device + +class nes_bmc_800in1_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_bmc_800in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_READ8_MEMBER(read_h); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); + +private: + UINT8 m_mode; + UINT8 m_reg[2]; +}; + + +// ======================> nes_bmc_1200in1_device + +class nes_bmc_1200in1_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_bmc_1200in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_h); + virtual DECLARE_WRITE8_MEMBER(chr_w); + + virtual void pcb_reset(); + +private: + UINT8 m_vram_protect; +}; + + +// ======================> nes_bmc_gold150_device + +class nes_bmc_gold150_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_bmc_gold150_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_READ8_MEMBER(read_h); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); + +private: + UINT8 m_latch; +}; + + +// ======================> nes_bmc_gold260_device + +class nes_bmc_gold260_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_bmc_gold260_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); +}; + + +// ======================> nes_bmc_ch001_device + +class nes_bmc_ch001_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_bmc_ch001_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_READ8_MEMBER(read_h); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); + +private: + UINT8 m_latch; +}; + + +// ======================> nes_bmc_super22_device + +class nes_bmc_super22_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_bmc_super22_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); +}; + + +// ======================> nes_bmc_4in1reset_device + +class nes_bmc_4in1reset_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_bmc_4in1reset_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void pcb_reset(); + +private: + int m_latch; +}; + +// ======================> nes_bmc_42in1reset_device + +class nes_bmc_42in1reset_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_bmc_42in1reset_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); + +private: + int m_latch; + UINT8 m_reg[2]; +}; + + + +// device type definition +extern const device_type NES_ACTION52; +extern const device_type NES_CALTRON6IN1; +extern const device_type NES_RUMBLESTATION; +extern const device_type NES_SVISION16; +extern const device_type NES_N625092; +extern const device_type NES_A65AS; +extern const device_type NES_T262; +extern const device_type NES_NOVEL1; +extern const device_type NES_NOVEL2; +extern const device_type NES_STUDYNGAME; +extern const device_type NES_SUPERGUN20IN1; +extern const device_type NES_VT5201; +extern const device_type NES_810544C; +extern const device_type NES_NTD03; +extern const device_type NES_BMC_GB63; +extern const device_type NES_BMC_GKA; +extern const device_type NES_BMC_GKB; +extern const device_type NES_BMC_WS; +extern const device_type NES_BMC_11160; +extern const device_type NES_BMC_G146; +extern const device_type NES_BMC_8157; +extern const device_type NES_BMC_HIK300; +extern const device_type NES_BMC_S700; +extern const device_type NES_BMC_BALL11; +extern const device_type NES_BMC_22GAMES; +extern const device_type NES_BMC_64Y2K; +extern const device_type NES_BMC_12IN1; +extern const device_type NES_BMC_20IN1; +extern const device_type NES_BMC_21IN1; +extern const device_type NES_BMC_31IN1; +extern const device_type NES_BMC_35IN1; +extern const device_type NES_BMC_36IN1; +extern const device_type NES_BMC_64IN1; +extern const device_type NES_BMC_70IN1; +extern const device_type NES_BMC_72IN1; +extern const device_type NES_BMC_76IN1; +extern const device_type NES_BMC_110IN1; +extern const device_type NES_BMC_150IN1; +extern const device_type NES_BMC_190IN1; +extern const device_type NES_BMC_800IN1; +extern const device_type NES_BMC_1200IN1; +extern const device_type NES_BMC_GOLD150; +extern const device_type NES_BMC_GOLD260; +extern const device_type NES_BMC_CH001; +extern const device_type NES_BMC_SUPER22; +extern const device_type NES_BMC_4IN1RESET; +extern const device_type NES_BMC_42IN1RESET; + + +#endif diff --git a/src/devices/bus/nes/namcot.c b/src/devices/bus/nes/namcot.c new file mode 100644 index 00000000000..236effc4a24 --- /dev/null +++ b/src/devices/bus/nes/namcot.c @@ -0,0 +1,688 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + NES/Famicom cartridge emulation for Namcot PCBs + + + Here we emulate the following PCBs + + * Namcot 3433 & 3443 (aka DxROM) [mapper 88, 204, 154] + * Namcot 3446 [mapper 76] + * Namcot 3425 [mapper 95] + * Namcot 163 [mapper 19] + * Namcot 175 [mapper 210] + * Namcot 340 [mapper 210] + + TODO: + - add sound feature of Namcot-163 + - Quinty is not working (same issue of Mendel Palace on TxROM boards, of course) + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "namcot.h" +#include "ui/ui.h" + +#include "cpu/m6502/m6502.h" + +#ifdef NES_PCB_DEBUG +#define VERBOSE 1 +#else +#define VERBOSE 0 +#endif + +#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) + + +//------------------------------------------------- +// constructor +//------------------------------------------------- + +const device_type NES_NAMCOT3433 = &device_creator; +const device_type NES_NAMCOT3446 = &device_creator; +const device_type NES_NAMCOT3425 = &device_creator; +const device_type NES_NAMCOT175 = &device_creator; +const device_type NES_NAMCOT340 = &device_creator; +const device_type NES_NAMCOT163 = &device_creator; + + +nes_namcot3433_device::nes_namcot3433_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : nes_nrom_device(mconfig, type, name, tag, owner, clock, shortname, source) +{ +} + +nes_namcot3433_device::nes_namcot3433_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_NAMCOT3433, "NES Cart Namcot 3433 & 3443 / DxROM PCB", tag, owner, clock, "nes_namcot3433", __FILE__) +{ +} + +nes_namcot3446_device::nes_namcot3446_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_NAMCOT3446, "NES Cart Namcot 3446 PCB", tag, owner, clock, "nes_namcot3446", __FILE__) +{ +} + +nes_namcot3425_device::nes_namcot3425_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_NAMCOT3425, "NES Cart Namcot 3425 PCB", tag, owner, clock, "nes_namcot3425", __FILE__) +{ +} + +nes_namcot340_device::nes_namcot340_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : nes_nrom_device(mconfig, type, name, tag, owner, clock, shortname, source) +{ +} + +nes_namcot340_device::nes_namcot340_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_NAMCOT175, "NES Cart Namcot 340 PCB", tag, owner, clock, "nes_namcot340", __FILE__) +{ +} + +nes_namcot175_device::nes_namcot175_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_namcot340_device(mconfig, NES_NAMCOT340, "NES Cart Namcot 175 PCB", tag, owner, clock, "nes_namcot175", __FILE__) +{ +} + +nes_namcot163_device::nes_namcot163_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_namcot340_device(mconfig, NES_NAMCOT163, "NES Cart Namcot 163 PCB", tag, owner, clock, "nes_namcot163", __FILE__) +{ +} + + + +void nes_namcot3433_device::device_start() +{ + common_start(); + save_item(NAME(m_latch)); +} + +void nes_namcot3433_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(m_prg_chunks - 2); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); + + m_latch = 0; +} + +void nes_namcot3446_device::device_start() +{ + common_start(); + save_item(NAME(m_latch)); +} + +void nes_namcot3446_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); + + m_latch = 0; +} + +void nes_namcot3425_device::device_start() +{ + common_start(); + save_item(NAME(m_latch)); + save_item(NAME(m_reg)); +} + +void nes_namcot3425_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); + + m_latch = 0; + memset(m_reg, 0, sizeof(m_reg)); +} + +void nes_namcot340_device::device_start() +{ + common_start(); + irq_timer = timer_alloc(TIMER_IRQ); + irq_timer->adjust(attotime::zero, 0, machine().device("maincpu")->cycles_to_attotime(1)); + + save_item(NAME(m_irq_enable)); + save_item(NAME(m_irq_count)); + save_item(NAME(m_n163_ram)); + + m_mapper_sram_size = 0x2000; + m_mapper_sram = m_n163_ram; +} + +void nes_namcot340_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); + set_nt_mirroring(PPU_MIRROR_VERT); + + m_irq_enable = 0; + m_irq_count = 0; +} + +void nes_namcot175_device::device_start() +{ + common_start(); + irq_timer = timer_alloc(TIMER_IRQ); + irq_timer->adjust(attotime::zero, 0, machine().device("maincpu")->cycles_to_attotime(1)); + + save_item(NAME(m_irq_enable)); + save_item(NAME(m_irq_count)); + save_item(NAME(m_wram_protect)); + save_item(NAME(m_n163_ram)); + + m_mapper_sram_size = 0x2000; + m_mapper_sram = m_n163_ram; +} + +void nes_namcot175_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); + set_nt_mirroring(PPU_MIRROR_VERT); + + m_irq_enable = 0; + m_irq_count = 0; + m_wram_protect = 0; +} + +void nes_namcot163_device::device_start() +{ + common_start(); + irq_timer = timer_alloc(TIMER_IRQ); + irq_timer->adjust(attotime::zero, 0, machine().device("maincpu")->cycles_to_attotime(1)); + + save_item(NAME(m_irq_enable)); + save_item(NAME(m_irq_count)); + save_item(NAME(m_wram_protect)); + save_item(NAME(m_latch)); + save_item(NAME(m_chr_bank)); + save_item(NAME(m_n163_ram)); + + m_mapper_sram_size = 0x2000; + m_mapper_sram = m_n163_ram; +} + +void nes_namcot163_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); + set_nt_mirroring(PPU_MIRROR_VERT); + + m_irq_enable = 0; + m_irq_count = 0; + m_wram_protect = 0; + m_latch = 0; + m_chr_bank = 0; +} + + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +/*------------------------------------------------- + + DxROM & Namcot 3433 - 3443 - 3453 board emulation + + Games: Dragon Spirit - Aratanaru Densetsu, Namcot Mahjong, Quinty, + Devilman + + These are the same board, but DRROM (and Tengen 800004) have + 4-screen mirroring + + iNES: mappers 88, 206 (same as 88 but possibly 4-screen mirroring), + and 154 (same as 88 but with additional mirroring control) + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_namcot3433_device::dxrom_write) +{ + LOG_MMC(("dxrom_write, offset: %04x, data: %02x\n", offset, data)); + + if (!(offset & 1) && m_pcb_ctrl_mirror) + set_nt_mirroring(BIT(data, 6) ? PPU_MIRROR_HIGH : PPU_MIRROR_LOW); + + if (offset >= 0x2000) + return; + + switch (offset & 1) + { + case 1: + switch (m_latch & 0x07) + { + case 0: chr2_0(data >> 1, CHRROM); break; + case 1: chr2_2(data >> 1, CHRROM); break; + case 2: chr1_4(data | 0x40, CHRROM); break; + case 3: chr1_5(data | 0x40, CHRROM); break; + case 4: chr1_6(data | 0x40, CHRROM); break; + case 5: chr1_7(data | 0x40, CHRROM); break; + case 6: prg8_89(data); break; + case 7: prg8_ab(data); break; + } + break; + case 0: + m_latch = data; + break; + } +} + + +/*------------------------------------------------- + + Namcot 3446 board emulation + + Games: Digital Devil Monogatari - Megami Tensei + + These are similar Namcot 34x3, but different bankswitch capabilities + + iNES: mapper 76 + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_namcot3446_device::write_h) +{ + LOG_MMC(("namcot3446 write_h, offset: %04x, data: %02x\n", offset, data)); + + // NEStopia does not have this! + if (offset >= 0x2000) + { + if (!(offset & 1)) + set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + return; + } + + switch (offset & 1) + { + case 1: + switch (m_latch & 0x07) + { + case 2: chr2_0(data, CHRROM); break; + case 3: chr2_2(data, CHRROM); break; + case 4: chr2_4(data, CHRROM); break; + case 5: chr2_6(data, CHRROM); break; + case 6: BIT(m_latch, 6) ? prg8_cd(data) : prg8_89(data); break; + case 7: prg8_ab(data); break; + } + break; + case 0: + m_latch = data; + break; + } +} + +/*------------------------------------------------- + + Namcot 3425 board emulation + + Games: Dragon Buster + + These are similar Namcot 34x3, but with NT mirroring (two + different modes) + + iNES: mapper 95 + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_namcot3425_device::write_h) +{ + UINT8 mode; + LOG_MMC(("namcot3425 write_h, offset: %04x, data: %02x\n", offset, data)); + if (offset >= 0x2000) + return; + + switch (offset & 1) + { + case 1: + mode = m_latch & 0x07; + switch (mode) + { + case 0: chr2_0(data >> 1, CHRROM); break; + case 1: chr2_2(data >> 1, CHRROM); break; + case 2: + case 3: + case 4: + case 5: + chr1_x(2 + mode, data, CHRROM); + m_reg[mode - 2] = BIT(data, 5); + if (!BIT(m_latch, 7)) + { + set_nt_page(0, CIRAM, m_reg[0], 1); + set_nt_page(1, CIRAM, m_reg[1], 1); + set_nt_page(2, CIRAM, m_reg[2], 1); + set_nt_page(3, CIRAM, m_reg[3], 1); + } + else + set_nt_mirroring(PPU_MIRROR_HORZ); + break; + case 6: prg8_89(data); break; + case 7: prg8_ab(data); break; + } + break; + case 0: + m_latch = data; + break; + } +} + +/*------------------------------------------------- + + Namcot-340 board emulation + + Games: Famista '92, '93 & '94, Top Striker, + Wagyan Land 2 & 3 + + This (and Namcot-175 below) is a cut-down version + of the Namcot-163 chip, without the sound capabilities. + They also cannot use NTRAM as VRAM and differ for + the mirroring handling + + iNES: mapper 210 + + In MESS: Supported + + -------------------------------------------------*/ + +void nes_namcot340_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + if (id == TIMER_IRQ) + { + if (m_irq_enable) + { + if (m_irq_count == 0x7fff) // counter does not wrap to 0! + m_maincpu->set_input_line(M6502_IRQ_LINE, ASSERT_LINE); + else + m_irq_count++; + } + } +} + +WRITE8_MEMBER(nes_namcot340_device::n340_lowrite) +{ + LOG_MMC(("n340_lowrite, offset: %04x, data: %02x\n", offset, data)); + offset += 0x100; + + switch (offset & 0x1800) + { + case 0x1000: /* low byte of IRQ */ + m_irq_count = (m_irq_count & 0x7f00) | data; + m_maincpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE); + break; + case 0x1800: /* high byte of IRQ, IRQ enable in high bit */ + m_irq_count = (m_irq_count & 0xff) | ((data & 0x7f) << 8); + m_irq_enable = data & 0x80; + m_maincpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE); + break; + } +} + +READ8_MEMBER(nes_namcot340_device::n340_loread) +{ + LOG_MMC(("n340_loread, offset: %04x\n", offset)); + offset += 0x100; + + switch (offset & 0x1800) + { + case 0x1000: + return m_irq_count & 0xff; + m_maincpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE); + case 0x1800: + return (m_irq_count >> 8) & 0xff; + m_maincpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE); + default: + return 0x00; + } +} + +WRITE8_MEMBER(nes_namcot340_device::n340_hiwrite) +{ + LOG_MMC(("n340_hiwrite, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x7800) + { + case 0x0000: case 0x0800: + case 0x1000: case 0x1800: + case 0x2000: case 0x2800: + case 0x3000: case 0x3800: + chr1_x(offset / 0x800, data, CHRROM); + break; + case 0x4000: + // no cart found with wram, so it is not clear if this could work as in Namcot-175... + break; + case 0x6000: + switch (data & 0xc0) + { + case 0x00: + set_nt_mirroring(PPU_MIRROR_LOW); + break; + case 0x40: + set_nt_mirroring(PPU_MIRROR_VERT); + break; + case 0x80: + set_nt_mirroring(PPU_MIRROR_HIGH); + break; + case 0xc0: + set_nt_mirroring(PPU_MIRROR_HORZ); + break; + } + prg8_89(data & 0x3f); + break; + case 0x6800: + prg8_ab(data & 0x3f); + break; + case 0x7000: + prg8_cd(data & 0x3f); + break; + } +} + + +/*------------------------------------------------- + + Namcot-175 board emulation + + Games: Chibi Maruko-chan, Family Circuit '91, + Famista '91 + + This (and Namcot-340 above) is a cut-down version + of the Namcot-163 chip, without the sound capabilities. + They also cannot use NTRAM as VRAM and differ for + the mirroring handling + + iNES: mapper 210 + + In MESS: Supported + + -------------------------------------------------*/ + +READ8_MEMBER(nes_namcot175_device::read_m) +{ + // the only game supporting this is Family Circuit '91, and it has 2KB of battery + // but it's mirrored up to 8KB (see Sprint Race -> Back Up menu breakage if not) + if (!m_battery.empty() && !m_wram_protect) + return m_battery[offset & (m_battery.size() - 1)]; + + return m_open_bus; // open bus +} + +WRITE8_MEMBER(nes_namcot175_device::write_m) +{ + // the only game supporting this is Family Circuit '91, and it has 2KB of battery + // but it's mirrored up to 8KB (see Sprint Race -> Back Up menu breakage if not) + if (!m_battery.empty() && !m_wram_protect) + m_battery[offset & (m_battery.size() - 1)] = data; +} + +WRITE8_MEMBER(nes_namcot175_device::write_h) +{ + LOG_MMC(("namcot175 write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x7800) + { + case 0x4000: + m_wram_protect = data & 1; + break; + case 0x6000: + prg8_89(data & 0x3f); + break; + default: + n340_hiwrite(space, offset, data, mem_mask); + break; + } +} + +/*------------------------------------------------- + + Namcot-163 board emulation + + Games: Battle Fleet, Famista '90, Megami Tensei II, + Juvei Quest, etc. + + Compared to Namcot-175 here we have mapper controlled + mirroring, NTRAM mapping to VRAM and additional + sound hw inside the chip (currently unemulated) and + some internal RAM. + + iNES: mapper 19 + + In MESS: Supported (with no emulation of the + sound component) + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_namcot163_device::chr_w) +{ + int bank = offset >> 10; + + if (!(m_latch & 0x40) && m_chr_bank >= 0xe0) + { + // CIRAM!!! + machine().ui().popup_time(10, "CIRAM mapped to VRAM. Please contact MAMEDevs."); + + if (!m_nt_writable[bank & 0x03]) + return; + m_nt_access[bank & 0x03][offset & 0x3ff] = data; + } + // or ROM, so no write +} + +READ8_MEMBER(nes_namcot163_device::chr_r) +{ + int bank = offset >> 10; + if (!(m_latch & 0x40) && m_chr_bank >= 0xe0) + { + // CIRAM!!! + machine().ui().popup_time(10, "CIRAM mapped to VRAM. Please contact MAMEDevs."); + return m_nt_access[bank & 0x03][offset & 0x3ff]; + } + // or ROM, accessed as usual + return m_chr_access[bank][offset & 0x3ff]; +} + + +READ8_MEMBER(nes_namcot163_device::read_m) +{ + if (!m_battery.empty() && offset < m_battery.size()) + return m_battery[offset & (m_battery.size() - 1)]; + + return m_open_bus; // open bus +} + +WRITE8_MEMBER(nes_namcot163_device::write_m) +{ + // the pcb can separately protect each 2KB chunk of the external wram from writes + int bank = (offset & 0x1800) >> 11; + if (!m_battery.empty() && !BIT(m_wram_protect, bank)) + m_battery[offset & (m_battery.size() - 1)] = data; +} + +WRITE8_MEMBER(nes_namcot163_device::write_l) +{ + LOG_MMC(("namcot163 write_l, offset: %04x, data: %02x\n", offset, data)); + offset += 0x100; + + switch (offset & 0x1800) + { + case 0x0800: + LOG_MMC(("Namcot-163 sound reg write, data: %02x\n", data)); + break; + default: + n340_lowrite(space, offset, data, mem_mask); + break; + } +} + +READ8_MEMBER(nes_namcot163_device::read_l) +{ + LOG_MMC(("namcot163 read_l, offset: %04x\n", offset)); + offset += 0x100; + + switch (offset & 0x1800) + { + case 0x0800: + LOG_MMC(("Namcot-163 sound reg read\n")); + return 0; + default: + return n340_loread(space, offset, mem_mask); + } +} + +void nes_namcot163_device::set_mirror(UINT8 page, UINT8 data) +{ + if (data < 0xe0) + set_nt_page(page, VROM, data, 0); + else + set_nt_page(page, CIRAM, data & 0x01, 1); +} + +WRITE8_MEMBER(nes_namcot163_device::write_h) +{ + int page; + LOG_MMC(("namcot163 write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x7800) + { + case 0x0000: case 0x0800: + case 0x1000: case 0x1800: + case 0x2000: case 0x2800: + case 0x3000: case 0x3800: + m_chr_bank = data; + chr1_x(offset / 0x800, m_chr_bank, CHRROM); + break; + case 0x4000: + case 0x4800: + case 0x5000: + case 0x5800: + page = (offset & 0x1800) >> 11; + set_mirror(page, data); + break; + case 0x6000: + // TODO: data & 40 (or data & c0) disable sound if set + prg8_89(data & 0x3f); + break; + case 0x6800: + m_latch = data & 0xc0; + prg8_ab(data & 0x3f); + break; + case 0x7800: + // the lower 4 bits work *BOTH* as WRAM write protect *AND* as sound address! + m_wram_protect = data & 0x0f; + LOG_MMC(("Namcot-163 sound address write, data: %02x\n", data)); + break; + default: + n340_hiwrite(space, offset, data, mem_mask); + break; + } +} diff --git a/src/devices/bus/nes/namcot.h b/src/devices/bus/nes/namcot.h new file mode 100644 index 00000000000..268347068b9 --- /dev/null +++ b/src/devices/bus/nes/namcot.h @@ -0,0 +1,163 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __NES_NAMCOT_H +#define __NES_NAMCOT_H + +#include "nxrom.h" + + +// ======================> nes_namcot3433_device + +class nes_namcot3433_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_namcot3433_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + nes_namcot3433_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(dxrom_write); + virtual DECLARE_WRITE8_MEMBER(write_h) { dxrom_write(space, offset, data, mem_mask); } + + virtual void pcb_reset(); + +private: + UINT8 m_latch; +}; + + +// ======================> nes_namcot3446_device + +class nes_namcot3446_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_namcot3446_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); + +private: + UINT8 m_latch; +}; + + +// ======================> nes_namcot3425_device + +class nes_namcot3425_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_namcot3425_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); + +private: + UINT8 m_latch; + UINT8 m_reg[4]; +}; + + +// ======================> nes_namcot340_device + +class nes_namcot340_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_namcot340_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + nes_namcot340_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + virtual DECLARE_READ8_MEMBER(n340_loread); + virtual DECLARE_WRITE8_MEMBER(n340_lowrite); + virtual DECLARE_WRITE8_MEMBER(n340_hiwrite); + virtual DECLARE_READ8_MEMBER(read_l) { return n340_loread(space, offset, mem_mask); } + virtual DECLARE_WRITE8_MEMBER(write_l) { n340_lowrite(space, offset, data, mem_mask); } + virtual DECLARE_WRITE8_MEMBER(write_h) { n340_hiwrite(space, offset, data, mem_mask); } + + virtual void pcb_reset(); + +protected: + UINT16 m_irq_count; + int m_irq_enable; + + static const device_timer_id TIMER_IRQ = 0; + emu_timer *irq_timer; + + // Namcot-163 chip contains 8K of internal ram, possibly battery backed up (not emulated yet) + // was it also present in 175 & 340 chips? + UINT8 m_n163_ram[0x2000]; +}; + + +// ======================> nes_namcot175_device + +class nes_namcot175_device : public nes_namcot340_device +{ +public: + // construction/destruction + nes_namcot175_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_READ8_MEMBER(read_m); + virtual DECLARE_WRITE8_MEMBER(write_m); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); + +private: + UINT8 m_wram_protect; +}; + + +// ======================> nes_namcot163_device + +class nes_namcot163_device : public nes_namcot340_device +{ +public: + // construction/destruction + nes_namcot163_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_READ8_MEMBER(read_l); + virtual DECLARE_READ8_MEMBER(read_m); + virtual DECLARE_WRITE8_MEMBER(write_l); + virtual DECLARE_WRITE8_MEMBER(write_m); + virtual DECLARE_WRITE8_MEMBER(write_h); + + // we have to overwrite these to allow CIRAM to be used for VRAM, even if it's not clear which game(s) use this + virtual DECLARE_READ8_MEMBER(chr_r); + virtual DECLARE_WRITE8_MEMBER(chr_w); + + virtual void pcb_reset(); + +private: + void set_mirror(UINT8 page, UINT8 data); + + UINT8 m_wram_protect, m_latch, m_chr_bank; + // TODO: add emulation of the sound part of the chip +}; + + + +// device type definition +extern const device_type NES_NAMCOT3433; +extern const device_type NES_NAMCOT3446; +extern const device_type NES_NAMCOT3425; +extern const device_type NES_NAMCOT175; +extern const device_type NES_NAMCOT340; +extern const device_type NES_NAMCOT163; + +#endif diff --git a/src/devices/bus/nes/nanjing.c b/src/devices/bus/nes/nanjing.c new file mode 100644 index 00000000000..4d0fc022520 --- /dev/null +++ b/src/devices/bus/nes/nanjing.c @@ -0,0 +1,175 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + NES/Famicom cartridge emulation for Nanjing PCBs + + TODO: + - Emulate the variants often assigned to mapper 162/164 (and investigate connection with Waixing FS-304)! + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "nanjing.h" + +#include "video/ppu2c0x.h" + + +#ifdef NES_PCB_DEBUG +#define VERBOSE 1 +#else +#define VERBOSE 0 +#endif + +#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) + + +//------------------------------------------------- +// constructor +//------------------------------------------------- + +const device_type NES_NANJING = &device_creator; + + +nes_nanjing_device::nes_nanjing_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_NANJING, "NES Cart Nanjing PCB", tag, owner, clock, "nes_nanjing", __FILE__) +{ +} + + + + +void nes_nanjing_device::device_start() +{ + common_start(); + save_item(NAME(m_count)); + save_item(NAME(m_latch1)); + save_item(NAME(m_latch2)); + save_item(NAME(m_reg)); +} + +void nes_nanjing_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(m_prg_chunks - 2); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); + + m_count = 0xff; + m_latch1 = 0; + m_latch2 = 0; + m_reg[0] = 0xff; + m_reg[1] = 0; +} + + + + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +/*------------------------------------------------- + + Bootleg Board by Nanjing + + Games: A lot of pirate originals + + iNES: mapper 163 + + In MESS: Unsupported. + + -------------------------------------------------*/ + +void nes_nanjing_device::hblank_irq(int scanline, int vblank, int blanked) +{ + if (BIT(m_reg[0], 7)) + { + if (scanline == 127) + { + chr4_0(1, CHRRAM); + chr4_4(1, CHRRAM); + } + + if (scanline == 239) + { + chr4_0(0, CHRRAM); + chr4_4(0, CHRRAM); + } + } + +} + +WRITE8_MEMBER(nes_nanjing_device::write_l) +{ + LOG_MMC(("nanjing write_l, offset: %04x, data: %02x\n", offset, data)); + + offset += 0x100; + + if (offset < 0x1000) + return; + + if (offset == 0x1100) // 0x5100 + { + if (data == 6) + prg32(3); + return; + } + + if (offset == 0x1101) // 0x5101 + { + UINT8 temp = m_count; + m_count = data; + + if (temp & !data) + m_latch2 ^= 0xff; + } + + switch (offset & 0x300) + { + case 0x000: + case 0x200: + m_reg[BIT(offset, 9)] = data; + if (!BIT(m_reg[0], 7) && machine().device("ppu")->get_current_scanline() <= 127) + chr8(0, CHRRAM); + break; + case 0x300: + m_latch1 = data; + break; + } + + prg32((m_reg[0] & 0x0f) | ((m_reg[1] & 0x0f) << 4)); +} + +READ8_MEMBER(nes_nanjing_device::read_l) +{ + UINT8 value = 0; + LOG_MMC(("nanjing read_l, offset: %04x\n", offset)); + + offset += 0x100; + + if (offset < 0x1000) + return 0; + + switch (offset & 0x700) + { + case 0x100: + value = m_latch1; + break; + case 0x500: + value = m_latch2 & m_latch1; + break; + case 0x000: + case 0x200: + case 0x300: + case 0x400: + case 0x600: + case 0x700: + value = 4; + break; + } + return value; +} diff --git a/src/devices/bus/nes/nanjing.h b/src/devices/bus/nes/nanjing.h new file mode 100644 index 00000000000..40fb8c2e714 --- /dev/null +++ b/src/devices/bus/nes/nanjing.h @@ -0,0 +1,38 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __NES_NANJING_H +#define __NES_NANJING_H + +#include "nxrom.h" + + +// ======================> nes_nanjing_device + +class nes_nanjing_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_nanjing_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_READ8_MEMBER(read_l); + virtual DECLARE_WRITE8_MEMBER(write_l); + + virtual void hblank_irq(int scanline, int vblank, int blanked); + virtual void pcb_reset(); + +private: + UINT8 m_count; + UINT8 m_reg[2]; + UINT8 m_latch1, m_latch2; +}; + + + + + +// device type definition +extern const device_type NES_NANJING; + +#endif diff --git a/src/devices/bus/nes/nes_carts.c b/src/devices/bus/nes/nes_carts.c new file mode 100644 index 00000000000..6acac2fc6e7 --- /dev/null +++ b/src/devices/bus/nes/nes_carts.c @@ -0,0 +1,366 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/********************************************************************** + + NES carts + +**********************************************************************/ + +#include "nes_carts.h" + +SLOT_INTERFACE_START(nes_cart) +// HROM, NROM, RROM, SROM & STROM + SLOT_INTERFACE_INTERNAL("nrom", NES_NROM) +// Nintendo Family BASIC pcb (NROM + 2K or 4K WRAM) + SLOT_INTERFACE_INTERNAL("hvc_basic", NES_FCBASIC) +// Extended NROM-368 board (NROM with 46K PRG) + SLOT_INTERFACE_INTERNAL("nrom368", NES_NROM368) +// Game Genie + SLOT_INTERFACE_INTERNAL("nrom_gg", NES_GGENIE) +// UNROM/UOROM + SLOT_INTERFACE_INTERNAL("uxrom", NES_UXROM) + SLOT_INTERFACE_INTERNAL("unrom_cc", NES_UXROM_CC) +// CNROM + SLOT_INTERFACE_INTERNAL("cnrom", NES_CNROM) +// Bandai PT-554 (CNROM boards + special audio chip, used by Aerobics Studio) + SLOT_INTERFACE_INTERNAL("bandai_pt554", NES_BANDAI_PT554) +// CPROM + SLOT_INTERFACE_INTERNAL("cprom", NES_CPROM) +// AMROM, ANROM, AOROM + SLOT_INTERFACE_INTERNAL("axrom", NES_AXROM) +// PxROM + SLOT_INTERFACE_INTERNAL("pxrom", NES_PXROM) +// FxROM + SLOT_INTERFACE_INTERNAL("fxrom", NES_FXROM) +// BNROM + SLOT_INTERFACE_INTERNAL("bnrom", NES_BXROM) +// GNROM & MHROM + SLOT_INTERFACE_INTERNAL("gxrom", NES_GXROM) +// UN1ROM + SLOT_INTERFACE_INTERNAL("un1rom", NES_UN1ROM) +// SxROM + SLOT_INTERFACE_INTERNAL("sxrom", NES_SXROM) + SLOT_INTERFACE_INTERNAL("sorom", NES_SOROM) + SLOT_INTERFACE_INTERNAL("sxrom_a", NES_SXROM_A) // in MMC1-A PRG RAM is always enabled + SLOT_INTERFACE_INTERNAL("sorom_a", NES_SOROM_A) // in MMC1-A PRG RAM is always enabled +// TxROM + SLOT_INTERFACE_INTERNAL("txrom", NES_TXROM) +// HKROM + SLOT_INTERFACE_INTERNAL("hkrom", NES_HKROM) +// TQROM + SLOT_INTERFACE_INTERNAL("tqrom", NES_TQROM) +// TxSROM + SLOT_INTERFACE_INTERNAL("txsrom", NES_TXSROM) +// ExROM + SLOT_INTERFACE_INTERNAL("exrom", NES_EXROM) +// RAM expansion + Disk System add-on + SLOT_INTERFACE_INTERNAL("disksys", NES_DISKSYS) +// Nintendo Custom boards + SLOT_INTERFACE_INTERNAL("pal_zz", NES_ZZ_PCB) + SLOT_INTERFACE_INTERNAL("nes_qj", NES_QJ_PCB) + SLOT_INTERFACE_INTERNAL("nes_event", NES_EVENT) +// Discrete Components boards +// IC_74x139x74 + SLOT_INTERFACE_INTERNAL("discrete_74x139", NES_74X139X74) +// IC_74x377 + SLOT_INTERFACE_INTERNAL("discrete_74x377", NES_74X377) +// Discrete board IC_74x161x161x32 + SLOT_INTERFACE_INTERNAL("discrete_74x161", NES_74X161X161X32) +// Discrete board IC_74x161x138 + SLOT_INTERFACE_INTERNAL("bitcorp_dis", NES_74X161X138) +// Bandai boards + SLOT_INTERFACE_INTERNAL("lz93d50", NES_LZ93D50) + SLOT_INTERFACE_INTERNAL("lz93d50_ep1", NES_LZ93D50_24C01) + SLOT_INTERFACE_INTERNAL("lz93d50_ep2", NES_LZ93D50_24C02) + SLOT_INTERFACE_INTERNAL("fcg", NES_FCG) + SLOT_INTERFACE_INTERNAL("fjump2", NES_FJUMP2) + SLOT_INTERFACE_INTERNAL("datach", NES_DATACH) + SLOT_INTERFACE_INTERNAL("karastudio", NES_KARAOKESTUDIO) + SLOT_INTERFACE_INTERNAL("oekakids", NES_OEKAKIDS) +// Irem boards + SLOT_INTERFACE_INTERNAL("g101", NES_G101) + SLOT_INTERFACE_INTERNAL("lrog017", NES_LROG017) + SLOT_INTERFACE_INTERNAL("h3001", NES_H3001) + SLOT_INTERFACE_INTERNAL("holydivr", NES_HOLYDIVR) + SLOT_INTERFACE_INTERNAL("tam_s1", NES_TAM_S1) +// Jaleco boards + SLOT_INTERFACE_INTERNAL("jf11", NES_JF11) + SLOT_INTERFACE_INTERNAL("jf13", NES_JF13) + SLOT_INTERFACE_INTERNAL("jf16", NES_JF16) + SLOT_INTERFACE_INTERNAL("jf17", NES_JF17) + SLOT_INTERFACE_INTERNAL("jf17pcm", NES_JF17_ADPCM) + SLOT_INTERFACE_INTERNAL("jf19", NES_JF19) + SLOT_INTERFACE_INTERNAL("jf19pcm", NES_JF19_ADPCM) + SLOT_INTERFACE_INTERNAL("ss88006", NES_SS88006) + SLOT_INTERFACE_INTERNAL("jf23", NES_JF23) + SLOT_INTERFACE_INTERNAL("jf24", NES_JF24) + SLOT_INTERFACE_INTERNAL("jf29", NES_JF29) + SLOT_INTERFACE_INTERNAL("jf33", NES_JF33) +// Konami boards + SLOT_INTERFACE_INTERNAL("vrc1", NES_VRC1) + SLOT_INTERFACE_INTERNAL("vrc2", NES_VRC2) + SLOT_INTERFACE_INTERNAL("vrc3", NES_VRC3) + SLOT_INTERFACE_INTERNAL("vrc4", NES_VRC4) + SLOT_INTERFACE_INTERNAL("vrc6", NES_VRC6) + SLOT_INTERFACE_INTERNAL("vrc7", NES_VRC7) +// Namcot boards + SLOT_INTERFACE_INTERNAL("namcot_163", NES_NAMCOT163) + SLOT_INTERFACE_INTERNAL("namcot_175", NES_NAMCOT175) + SLOT_INTERFACE_INTERNAL("namcot_340", NES_NAMCOT340) + SLOT_INTERFACE_INTERNAL("namcot_3433", NES_NAMCOT3433) // DxROM is a Nintendo board for US versions of the 3433/3443 games + SLOT_INTERFACE_INTERNAL("namcot_3425", NES_NAMCOT3425) + SLOT_INTERFACE_INTERNAL("namcot_3446", NES_NAMCOT3446) +// Sunsoft boards + SLOT_INTERFACE_INTERNAL("sunsoft1", NES_SUNSOFT_1) + SLOT_INTERFACE_INTERNAL("sunsoft2", NES_SUNSOFT_2) + SLOT_INTERFACE_INTERNAL("sunsoft3", NES_SUNSOFT_3) + SLOT_INTERFACE_INTERNAL("sunsoft4", NES_SUNSOFT_4) + SLOT_INTERFACE_INTERNAL("sunsoft_dcs", NES_SUNSOFT_DCS) + SLOT_INTERFACE_INTERNAL("sunsoft_fme7", NES_SUNSOFT_FME7) // JxROM is a Nintendo board for US versions of the Sunsoft FME7 games + SLOT_INTERFACE_INTERNAL("sunsoft5a", NES_SUNSOFT_5) + SLOT_INTERFACE_INTERNAL("sunsoft5b", NES_SUNSOFT_5) +// Taito boards + SLOT_INTERFACE_INTERNAL("tc0190fmc", NES_TC0190FMC) + SLOT_INTERFACE_INTERNAL("tc0190fmcp", NES_TC0190FMC_PAL16R4) + SLOT_INTERFACE_INTERNAL("tc0350fmr", NES_TC0190FMC) + SLOT_INTERFACE_INTERNAL("x1_005", NES_X1_005) // two variants exist, depending on pin17 & pin31 connections + SLOT_INTERFACE_INTERNAL("x1_017", NES_X1_017) +// Misc pirate boards (by AVE, Camerica, C&E, Nanjing, NTDEC, JY Company, Sachen, Tengen, TXC, Waixing, Henggendianzi, etc.) + SLOT_INTERFACE_INTERNAL("nina001", NES_NINA001) + SLOT_INTERFACE_INTERNAL("nina006", NES_NINA006) + SLOT_INTERFACE_INTERNAL("bf9093", NES_BF9093) + SLOT_INTERFACE_INTERNAL("bf9096", NES_BF9096) + SLOT_INTERFACE_INTERNAL("goldenfive", NES_GOLDEN5) + SLOT_INTERFACE_INTERNAL("ade", NES_ALADDIN) + SLOT_INTERFACE_INTERNAL("cne_decathl", NES_CNE_DECATHL) + SLOT_INTERFACE_INTERNAL("cne_fsb", NES_CNE_FSB) + SLOT_INTERFACE_INTERNAL("cne_shlz", NES_CNE_SHLZ) + SLOT_INTERFACE_INTERNAL("nanjing", NES_NANJING) // mapper 163 + SLOT_INTERFACE_INTERNAL("ntdec_asder", NES_NTDEC_ASDER) // mapper 112 + SLOT_INTERFACE_INTERNAL("ntdec_fh", NES_NTDEC_FH) // mapper 193 + SLOT_INTERFACE_INTERNAL("jyc_a", NES_JY_TYPEA) // mapper 90 + SLOT_INTERFACE_INTERNAL("jyc_b", NES_JY_TYPEB) // mapper 211 + SLOT_INTERFACE_INTERNAL("jyc_c", NES_JY_TYPEC) // mapper 209 + SLOT_INTERFACE_INTERNAL("sa009", NES_SACHEN_SA009) + SLOT_INTERFACE_INTERNAL("sa0036", NES_SACHEN_SA0036) + SLOT_INTERFACE_INTERNAL("sa0037", NES_SACHEN_SA0037) + SLOT_INTERFACE_INTERNAL("sa72007", NES_SACHEN_SA72007) + SLOT_INTERFACE_INTERNAL("sa72008", NES_SACHEN_SA72008) + SLOT_INTERFACE_INTERNAL("tca01", NES_SACHEN_TCA01) + SLOT_INTERFACE_INTERNAL("s8259a", NES_SACHEN_8259A) + SLOT_INTERFACE_INTERNAL("s8259b", NES_SACHEN_8259B) + SLOT_INTERFACE_INTERNAL("s8259c", NES_SACHEN_8259C) + SLOT_INTERFACE_INTERNAL("s8259d", NES_SACHEN_8259D) + SLOT_INTERFACE_INTERNAL("s74x374", NES_SACHEN_74X374) + SLOT_INTERFACE_INTERNAL("s74x374a", NES_SACHEN_74X374_ALT) /* FIXME: Made up boards some different handling */ + SLOT_INTERFACE_INTERNAL("tcu01", NES_SACHEN_TCU01) + SLOT_INTERFACE_INTERNAL("tcu02", NES_SACHEN_TCU02) + SLOT_INTERFACE_INTERNAL("tengen_800008", NES_TENGEN_800008) /* FIXME: Is this the same as CNROM? */ + SLOT_INTERFACE_INTERNAL("tengen_800032", NES_TENGEN_800032) + SLOT_INTERFACE_INTERNAL("tengen_800037", NES_TENGEN_800037) + SLOT_INTERFACE_INTERNAL("txc_22211", NES_TXC_22211) + SLOT_INTERFACE_INTERNAL("txc_dumarc", NES_TXC_DUMARACING) + SLOT_INTERFACE_INTERNAL("txc_mjblock", NES_TXC_MJBLOCK) + SLOT_INTERFACE_INTERNAL("txc_strikew", NES_TXC_STRIKEW) + SLOT_INTERFACE_INTERNAL("txc_commandos", NES_TXC_COMMANDOS) + SLOT_INTERFACE_INTERNAL("waixing_a", NES_WAIXING_A) + SLOT_INTERFACE_INTERNAL("waixing_a1", NES_WAIXING_A1) /* FIXME: Made up boards the different CHRRAM banks (see Ji Jia Zhan Shi) */ + SLOT_INTERFACE_INTERNAL("waixing_b", NES_WAIXING_B) + SLOT_INTERFACE_INTERNAL("waixing_c", NES_WAIXING_C) + SLOT_INTERFACE_INTERNAL("waixing_d", NES_WAIXING_D) + SLOT_INTERFACE_INTERNAL("waixing_e", NES_WAIXING_E) + SLOT_INTERFACE_INTERNAL("waixing_f", NES_WAIXING_F) + SLOT_INTERFACE_INTERNAL("waixing_g", NES_WAIXING_G) + SLOT_INTERFACE_INTERNAL("waixing_h", NES_WAIXING_H) + SLOT_INTERFACE_INTERNAL("waixing_h1", NES_WAIXING_H1) /* FIXME: Made up boards the different WRAM protect banks (see Shen Mi Jin San Jiao) */ + SLOT_INTERFACE_INTERNAL("waixing_i", NES_WAIXING_I) + SLOT_INTERFACE_INTERNAL("waixing_j", NES_WAIXING_J) + SLOT_INTERFACE_INTERNAL("waixing_sgz", NES_WAIXING_SGZ) + SLOT_INTERFACE_INTERNAL("waixing_sgzlz", NES_WAIXING_SGZLZ) + SLOT_INTERFACE_INTERNAL("waixing_sec", NES_WAIXING_SEC) + SLOT_INTERFACE_INTERNAL("waixing_ffv", NES_WAIXING_FFV) + SLOT_INTERFACE_INTERNAL("waixing_wxzs", NES_WAIXING_WXZS) + SLOT_INTERFACE_INTERNAL("waixing_wxzs2", NES_WAIXING_WXZS2) + SLOT_INTERFACE_INTERNAL("waixing_dq8", NES_WAIXING_DQ8) + SLOT_INTERFACE_INTERNAL("waixing_sh2", NES_WAIXING_SH2) + SLOT_INTERFACE_INTERNAL("fs304", NES_WAIXING_FS304) // used in Zelda 3 by Waixing + SLOT_INTERFACE_INTERNAL("cony", NES_CONY) + SLOT_INTERFACE_INTERNAL("yoko", NES_YOKO) + SLOT_INTERFACE_INTERNAL("hengg_srich", NES_HENGG_SRICH) + SLOT_INTERFACE_INTERNAL("hengg_xhzs", NES_HENGG_XHZS) + SLOT_INTERFACE_INTERNAL("hengg_shjy3", NES_HENGG_SHJY3) // mapper 253 + SLOT_INTERFACE_INTERNAL("hes", NES_HES) + SLOT_INTERFACE_INTERNAL("hosenkan", NES_HOSENKAN) + SLOT_INTERFACE_INTERNAL("ks7058", NES_KS7058) + SLOT_INTERFACE_INTERNAL("ks202", NES_KS202) // mapper 56 + SLOT_INTERFACE_INTERNAL("ks7022", NES_KS7022)// mapper 175 + SLOT_INTERFACE_INTERNAL("ks7017", NES_KS7017) + SLOT_INTERFACE_INTERNAL("ks7032", NES_KS7032) // mapper 142 + SLOT_INTERFACE_INTERNAL("ks7012", NES_KS7012) // used in Zanac (FDS Conversion) + SLOT_INTERFACE_INTERNAL("ks7013b", NES_KS7013B) // used in Highway Star (FDS Conversion) + SLOT_INTERFACE_INTERNAL("ks7031", NES_KS7031) // used in Dracula II (FDS Conversion) + SLOT_INTERFACE_INTERNAL("gs2015", NES_GS2015) + SLOT_INTERFACE_INTERNAL("gs2004", NES_GS2004) + SLOT_INTERFACE_INTERNAL("gs2013", NES_GS2013) + SLOT_INTERFACE_INTERNAL("tf9in1", NES_TF9IN1) + SLOT_INTERFACE_INTERNAL("3dblock", NES_3DBLOCK) // NROM + IRQ? + SLOT_INTERFACE_INTERNAL("racermate", NES_RACERMATE) // mapper 168 + SLOT_INTERFACE_INTERNAL("agci_50282", NES_AGCI_50282) + SLOT_INTERFACE_INTERNAL("dreamtech01", NES_DREAMTECH01) + SLOT_INTERFACE_INTERNAL("fukutake", NES_FUKUTAKE) + SLOT_INTERFACE_INTERNAL("futuremedia", NES_FUTUREMEDIA) + SLOT_INTERFACE_INTERNAL("magicseries", NES_MAGSERIES) + SLOT_INTERFACE_INTERNAL("daou_306", NES_DAOU306) + SLOT_INTERFACE_INTERNAL("subor0", NES_SUBOR0) + SLOT_INTERFACE_INTERNAL("subor1", NES_SUBOR1) + SLOT_INTERFACE_INTERNAL("cc21", NES_CC21) + SLOT_INTERFACE_INTERNAL("xiaozy", NES_XIAOZY) + SLOT_INTERFACE_INTERNAL("edu2k", NES_EDU2K) + SLOT_INTERFACE_INTERNAL("t230", NES_T230) + SLOT_INTERFACE_INTERNAL("mk2", NES_MK2) + SLOT_INTERFACE_INTERNAL("unl_whero", NES_WHERO) // mapper 27 + SLOT_INTERFACE_INTERNAL("unl_43272", NES_43272) // used in Gaau Hok Gwong Cheung + SLOT_INTERFACE_INTERNAL("tf1201", NES_TF1201) + SLOT_INTERFACE_INTERNAL("unl_cfight", NES_CITYFIGHT) // used by City Fighter IV +// misc bootleg boards + SLOT_INTERFACE_INTERNAL("ax5705", NES_AX5705) + SLOT_INTERFACE_INTERNAL("sc127", NES_SC127) + SLOT_INTERFACE_INTERNAL("mariobaby", NES_MARIOBABY) + SLOT_INTERFACE_INTERNAL("asnicol", NES_ASN) + SLOT_INTERFACE_INTERNAL("smb3pirate", NES_SMB3PIRATE) + SLOT_INTERFACE_INTERNAL("btl_dninja", NES_BTL_DNINJA) + SLOT_INTERFACE_INTERNAL("whirl2706", NES_WHIRLWIND_2706) + SLOT_INTERFACE_INTERNAL("smb2j", NES_SMB2J) + SLOT_INTERFACE_INTERNAL("smb2ja", NES_SMB2JA) + SLOT_INTERFACE_INTERNAL("smb2jb", NES_SMB2JB) + SLOT_INTERFACE_INTERNAL("09034a", NES_09034A) + SLOT_INTERFACE_INTERNAL("tobidase", NES_TOBIDASE) // mapper 120 + SLOT_INTERFACE_INTERNAL("mmalee2", NES_MMALEE) // mapper 55? + SLOT_INTERFACE_INTERNAL("unl_2708", NES_2708) // mapper 103 + SLOT_INTERFACE_INTERNAL("unl_lh32", NES_LH32) // used by Monty no Doki Doki Daidassou FDS conversion + SLOT_INTERFACE_INTERNAL("unl_lh10", NES_LH10) // used in Fuuun Shaolin Kyo (FDS Conversion) + SLOT_INTERFACE_INTERNAL("unl_lh53", NES_LH53) // used in Nazo no Murasamejou (FDS Conversion) + SLOT_INTERFACE_INTERNAL("unl_ac08", NES_AC08) // used by Green Beret FDS conversion + SLOT_INTERFACE_INTERNAL("unl_bb", NES_UNL_BB) // used by a few FDS conversions + SLOT_INTERFACE_INTERNAL("sgpipe", NES_SHUIGUAN) // mapper 183 +// misc MMC3 clone boards + SLOT_INTERFACE_INTERNAL("dbz5", NES_REX_DBZ5) + SLOT_INTERFACE_INTERNAL("sl1632", NES_REX_SL1632) + SLOT_INTERFACE_INTERNAL("somari", NES_SOMARI) // mapper 116 + SLOT_INTERFACE_INTERNAL("nitra", NES_NITRA) + SLOT_INTERFACE_INTERNAL("ks7057", NES_KS7057) // mapper 196 alt (for Street Fighter VI / Fight Street VI) + SLOT_INTERFACE_INTERNAL("sbros11", NES_SBROS11) + SLOT_INTERFACE_INTERNAL("unl_malisb", NES_MALISB) // used by Super Mali Splash Bomb + SLOT_INTERFACE_INTERNAL("family4646", NES_FAMILY4646) + SLOT_INTERFACE_INTERNAL("pikay2k", NES_PIKAY2K) // mapper 254 + SLOT_INTERFACE_INTERNAL("8237", NES_8237) + SLOT_INTERFACE_INTERNAL("8237a", NES_NROM) // UNSUPPORTED + SLOT_INTERFACE_INTERNAL("sg_lionk", NES_SG_LIONK) + SLOT_INTERFACE_INTERNAL("sg_boog", NES_SG_BOOG) + SLOT_INTERFACE_INTERNAL("kasing", NES_KASING) + SLOT_INTERFACE_INTERNAL("kay", NES_KAY) + SLOT_INTERFACE_INTERNAL("h2288", NES_H2288) + SLOT_INTERFACE_INTERNAL("unl_6035052", NES_6035052) // mapper 238? + SLOT_INTERFACE_INTERNAL("txc_tw", NES_TXC_TW) + SLOT_INTERFACE_INTERNAL("kof97", NES_KOF97) + SLOT_INTERFACE_INTERNAL("kof96", NES_KOF96) + SLOT_INTERFACE_INTERNAL("sfight3", NES_SF3) + SLOT_INTERFACE_INTERNAL("gouder", NES_GOUDER) + SLOT_INTERFACE_INTERNAL("sa9602b", NES_SA9602B) + SLOT_INTERFACE_INTERNAL("unl_shero", NES_SACHEN_SHERO) +// misc multigame cart boards + SLOT_INTERFACE_INTERNAL("benshieng", NES_BENSHIENG) + SLOT_INTERFACE_INTERNAL("action52", NES_ACTION52) + SLOT_INTERFACE_INTERNAL("caltron6in1", NES_CALTRON6IN1) + SLOT_INTERFACE_INTERNAL("maxi15", NES_MAXI15) // mapper 234 + SLOT_INTERFACE_INTERNAL("rumblestation", NES_RUMBLESTATION) // mapper 46 + SLOT_INTERFACE_INTERNAL("svision16", NES_SVISION16) // mapper 53 + SLOT_INTERFACE_INTERNAL("n625092", NES_N625092) + SLOT_INTERFACE_INTERNAL("a65as", NES_A65AS) + SLOT_INTERFACE_INTERNAL("t262", NES_T262) + SLOT_INTERFACE_INTERNAL("novel1", NES_NOVEL1) + SLOT_INTERFACE_INTERNAL("novel2", NES_NOVEL2) // mapper 213... same as BMC-NOVELDIAMOND9999999IN1 board? + SLOT_INTERFACE_INTERNAL("studyngame", NES_STUDYNGAME) // mapper 39 + SLOT_INTERFACE_INTERNAL("sgun20in1", NES_SUPERGUN20IN1) + SLOT_INTERFACE_INTERNAL("bmc_vt5201", NES_VT5201) // mapper 60 otherwise + SLOT_INTERFACE_INTERNAL("bmc_d1038", NES_VT5201) // mapper 60? + SLOT_INTERFACE_INTERNAL("810544c", NES_810544C) + SLOT_INTERFACE_INTERNAL("ntd03", NES_NTD03) + SLOT_INTERFACE_INTERNAL("bmc_gb63", NES_BMC_GB63) + SLOT_INTERFACE_INTERNAL("bmc_gka", NES_BMC_GKA) + SLOT_INTERFACE_INTERNAL("bmc_gkb", NES_BMC_GKB) + SLOT_INTERFACE_INTERNAL("bmc_ws", NES_BMC_WS) + SLOT_INTERFACE_INTERNAL("bmc_g146", NES_BMC_G146) + SLOT_INTERFACE_INTERNAL("bmc_11160", NES_BMC_11160) + SLOT_INTERFACE_INTERNAL("bmc_8157", NES_BMC_8157) + SLOT_INTERFACE_INTERNAL("bmc_hik300", NES_BMC_HIK300) + SLOT_INTERFACE_INTERNAL("bmc_s700", NES_BMC_S700) + SLOT_INTERFACE_INTERNAL("bmc_ball11", NES_BMC_BALL11) + SLOT_INTERFACE_INTERNAL("bmc_22games", NES_BMC_22GAMES) + SLOT_INTERFACE_INTERNAL("bmc_64y2k", NES_BMC_64Y2K) + SLOT_INTERFACE_INTERNAL("bmc_12in1", NES_BMC_12IN1) + SLOT_INTERFACE_INTERNAL("bmc_20in1", NES_BMC_20IN1) + SLOT_INTERFACE_INTERNAL("bmc_21in1", NES_BMC_21IN1) + SLOT_INTERFACE_INTERNAL("bmc_31in1", NES_BMC_31IN1) + SLOT_INTERFACE_INTERNAL("bmc_35in1", NES_BMC_35IN1) + SLOT_INTERFACE_INTERNAL("bmc_36in1", NES_BMC_36IN1) + SLOT_INTERFACE_INTERNAL("bmc_64in1", NES_BMC_64IN1) + SLOT_INTERFACE_INTERNAL("bmc_70in1", NES_BMC_70IN1) // mapper 236? + SLOT_INTERFACE_INTERNAL("bmc_72in1", NES_BMC_72IN1) + SLOT_INTERFACE_INTERNAL("bmc_76in1", NES_BMC_76IN1) + SLOT_INTERFACE_INTERNAL("bmc_s42in1", NES_BMC_76IN1) + SLOT_INTERFACE_INTERNAL("bmc_110in1", NES_BMC_110IN1) + SLOT_INTERFACE_INTERNAL("bmc_150in1", NES_BMC_150IN1) + SLOT_INTERFACE_INTERNAL("bmc_190in1", NES_BMC_190IN1) + SLOT_INTERFACE_INTERNAL("bmc_800in1", NES_BMC_800IN1) // mapper 236? + SLOT_INTERFACE_INTERNAL("bmc_1200in1", NES_BMC_1200IN1) + SLOT_INTERFACE_INTERNAL("bmc_gold150", NES_BMC_GOLD150) // mapper 235 with 2M PRG + SLOT_INTERFACE_INTERNAL("bmc_gold260", NES_BMC_GOLD260) // mapper 235 with 4M PRG + SLOT_INTERFACE_INTERNAL("bmc_power255", NES_BMC_CH001) // mapper 63? + SLOT_INTERFACE_INTERNAL("bmc_s22games", NES_BMC_SUPER22) // mapper 233 + SLOT_INTERFACE_INTERNAL("bmc_reset4", NES_BMC_4IN1RESET) // mapper 60 with 64k prg and 32k chr + SLOT_INTERFACE_INTERNAL("bmc_reset42", NES_BMC_42IN1RESET) // mapper 60? or 226? or 233? +// misc multigame cart MMC3 clone boards + SLOT_INTERFACE_INTERNAL("fk23c", NES_FK23C) + SLOT_INTERFACE_INTERNAL("fk23ca", NES_FK23CA) + SLOT_INTERFACE_INTERNAL("s24in1c03", NES_S24IN1SC03) + SLOT_INTERFACE_INTERNAL("bmc_15in1", NES_BMC_15IN1) + SLOT_INTERFACE_INTERNAL("bmc_sbig7in1", NES_BMC_SBIG7) + SLOT_INTERFACE_INTERNAL("bmc_hik8in1", NES_BMC_HIK8) + SLOT_INTERFACE_INTERNAL("bmc_hik4in1", NES_BMC_HIK4) + SLOT_INTERFACE_INTERNAL("bmc_mario7in1", NES_BMC_MARIO7IN1) + SLOT_INTERFACE_INTERNAL("bmc_gold7in1", NES_BMC_GOLD7IN1) + SLOT_INTERFACE_INTERNAL("bmc_gc6in1", NES_BMC_GC6IN1) + SLOT_INTERFACE_INTERNAL("bmc_411120c", NES_BMC_411120C) + SLOT_INTERFACE_INTERNAL("bmc_830118c", NES_BMC_830118C) + SLOT_INTERFACE_INTERNAL("pjoy84", NES_PJOY84) + SLOT_INTERFACE_INTERNAL("nocash_nochr", NES_NOCHR) + SLOT_INTERFACE_INTERNAL("nes_action53", NES_ACTION53) + SLOT_INTERFACE_INTERNAL("nes_2a03pur", NES_2A03PURITANS) +// other unsupported... + SLOT_INTERFACE_INTERNAL("ninjaryu", NES_NROM) // mapper 111 - UNSUPPORTED + SLOT_INTERFACE_INTERNAL("unl_dance", NES_NROM) // UNSUPPORTED + SLOT_INTERFACE_INTERNAL("onebus", NES_NROM) // UNSUPPORTED + SLOT_INTERFACE_INTERNAL("dance2k", NES_NROM) // UNSUPPORTED + SLOT_INTERFACE_INTERNAL("pec586", NES_NROM) // UNSUPPORTED +// are there dumps of games with these boards? + SLOT_INTERFACE_INTERNAL("bmc_hik_kof", NES_NROM) // mapper 251 - UNSUPPORTED + SLOT_INTERFACE_INTERNAL("bmc_13in1jy110", NES_NROM) // [mentioned in FCEUMM source - we need more info] - UNSUPPORTED + SLOT_INTERFACE_INTERNAL("bmc_gk_192", NES_NROM) // [mentioned in FCEUMM source - we need more info] - UNSUPPORTED + SLOT_INTERFACE_INTERNAL("konami_qtai", NES_NROM) // [mentioned in FCEUMM source - we need more info] - UNSUPPORTED + SLOT_INTERFACE_INTERNAL("unl_3d_block", NES_NROM) // [mentioned in FCEUMM source - we need more info] - UNSUPPORTED + SLOT_INTERFACE_INTERNAL("unl_c_n22m", NES_NROM) // [mentioned in FCEUMM source - we need more info] - UNSUPPORTED + SLOT_INTERFACE_INTERNAL("a9746", NES_NROM) // mapper 219 - UNSUPPORTED (no dump available) +// legacy boards for FFE copier mappers (are there images available to fix/improve emulation?) + SLOT_INTERFACE_INTERNAL("ffe3", NES_FFE3) + SLOT_INTERFACE_INTERNAL("ffe4", NES_FFE4) + SLOT_INTERFACE_INTERNAL("ffe8", NES_FFE8) + SLOT_INTERFACE_INTERNAL("test", NES_NROM) +// + SLOT_INTERFACE_INTERNAL("unknown", NES_NROM) // a few pirate dumps uses the wrong mapper... +SLOT_INTERFACE_END + +SLOT_INTERFACE_START(disksys_only) + // RAM expansion + Disk System add-on + SLOT_INTERFACE("disksys", NES_DISKSYS) +SLOT_INTERFACE_END diff --git a/src/devices/bus/nes/nes_carts.h b/src/devices/bus/nes/nes_carts.h new file mode 100644 index 00000000000..144d7aa0a8e --- /dev/null +++ b/src/devices/bus/nes/nes_carts.h @@ -0,0 +1,73 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/********************************************************************** + + NES carts + +**********************************************************************/ + +#pragma once + +#ifndef __NES_CARTS_H__ +#define __NES_CARTS_H__ + +#include "emu.h" + +// official PCBs +#include "nxrom.h" +#include "mmc1.h" +#include "mmc2.h" +#include "mmc3.h" +#include "mmc5.h" +#include "bandai.h" +#include "datach.h" +#include "discrete.h" +#include "disksys.h" +#include "event.h" +#include "irem.h" +#include "jaleco.h" +#include "karastudio.h" +#include "konami.h" +#include "namcot.h" +#include "pt554.h" +#include "sunsoft.h" +#include "sunsoft_dcs.h" +#include "taito.h" +// unlicensed/bootleg/pirate PCBs +#include "2a03pur.h" +#include "act53.h" +#include "aladdin.h" +#include "ave.h" +#include "benshieng.h" +#include "camerica.h" +#include "cne.h" +#include "cony.h" +#include "ggenie.h" +#include "hes.h" +#include "henggedianzi.h" +#include "hosenkan.h" +#include "jy.h" +#include "kaiser.h" +#include "legacy.h" +#include "nanjing.h" +#include "ntdec.h" +#include "racermate.h" +#include "rcm.h" +#include "rexsoft.h" +#include "sachen.h" +#include "somari.h" +#include "tengen.h" +#include "txc.h" +#include "waixing.h" +// misc unlicensed/bootleg/pirate PCBs +#include "bootleg.h" +#include "multigame.h" +#include "pirate.h" +#include "mmc3_clones.h" + + +// supported devices +SLOT_INTERFACE_EXTERN(nes_cart); +SLOT_INTERFACE_EXTERN(disksys_only); + +#endif // __NES_CARTS_H__ diff --git a/src/devices/bus/nes/nes_ines.inc b/src/devices/bus/nes/nes_ines.inc new file mode 100644 index 00000000000..ceb9581b82f --- /dev/null +++ b/src/devices/bus/nes/nes_ines.inc @@ -0,0 +1,939 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/***************************************************************************************** + + NES MMC Emulation + + Support for iNES Mappers + +****************************************************************************************/ + + +/* Set to generate prg & chr files when the cart is loaded */ +#define SPLIT_PRG 0 +#define SPLIT_CHR 0 + + +/************************************************************* + + mmc_list + + Supported mappers and corresponding pcb id + + *************************************************************/ + +struct nes_mmc +{ + int iNesMapper; /* iNES Mapper # */ + int pcb_id; +}; + + +static const nes_mmc mmc_list[] = +{ +/* INES DESC LOW_W, LOW_R, MED_W, HIGH_W, PPU_latch, scanline CB, hblank CB */ + { 0, STD_NROM }, + { 1, STD_SXROM }, + { 2, STD_UXROM }, + { 3, STD_CNROM }, + { 4, STD_TXROM }, + { 5, STD_EXROM }, + { 6, FFE4_BOARD }, + { 7, STD_AXROM }, + { 8, FFE3_BOARD }, + { 9, STD_PXROM }, + { 10, STD_FXROM }, + { 11, DIS_74X377 }, + { 12, REXSOFT_DBZ5 }, + { 13, STD_CPROM }, + { 14, REXSOFT_SL1632 }, + { 15, WAIXING_WXZS2 }, + { 16, BANDAI_LZ93EX2 }, // with 24c02 + { 17, FFE8_BOARD }, + { 18, JALECO_SS88006 }, + { 19, NAMCOT_163 }, + { 21, KONAMI_VRC4 }, + { 22, KONAMI_VRC2 }, + { 23, KONAMI_VRC2 }, + { 24, KONAMI_VRC6 }, + { 25, KONAMI_VRC4 }, + { 26, KONAMI_VRC6 }, + { 27, UNL_WORLDHERO }, // 27 World Hero board - Unsupported + { 28, BTL_ACTION53 }, // 28 - Multi-discrete PCB designed by Tepples for Action 53 + // 29 Unused + // 30 UNROM 512 + Flash, currently unsupported + { 31, BTL_2A03_PURITANS }, // 31 - PCB designed by infinitelives & rainwarrior for 2A03 Puritans Album + { 32, IREM_G101 }, + { 33, TAITO_TC0190FMC }, + { 34, STD_BXROM }, + { 35, UNL_SC127 }, + { 36, TXC_STRIKEW }, + { 37, PAL_ZZ }, + { 38, DIS_74X161X138 }, + { 39, UNL_STUDYNGAME }, + { 40, BTL_SMB2JA }, + { 41, CALTRON_6IN1 }, + { 42, BTL_MARIOBABY }, // ai senshi nicole too, changed by crc_hack + { 43, UNL_SMB2J }, + { 44, BMC_SUPERBIG_7IN1 }, + { 45, BMC_HIK8IN1 }, + { 46, RUMBLESTATION_BOARD }, + { 47, NES_QJ }, + { 48, TAITO_TC0190FMCP }, + { 49, BMC_SUPERHIK_4IN1 }, + { 50, BTL_SMB2JB }, + { 51, BMC_BALLGAMES_11IN1 }, + { 52, BMC_GOLD_7IN1 }, + { 53, SVISION16_BOARD }, + { 54, BMC_NOVEL1 }, + // 55 Genius SMB - No info (nor images) available + { 56, KAISER_KS202 }, + { 57, BMC_GKA }, + { 58, BMC_GKB }, + // 59 Unused + // 60 4-in-1, 35-in-1 Reset based + { 61, RCM_TF9IN1 }, + { 62, BMC_SUPER_700IN1 }, + { 63, BMC_CH001 }, // Powerful 255 + { 64, TENGEN_800032 }, + { 65, IREM_H3001 }, + { 66, STD_GXROM }, + { 67, SUNSOFT_3 }, + { 68, SUNSOFT_DCS }, + { 69, SUNSOFT_FME7 }, + { 70, DIS_74X161X161X32 }, + { 71, CAMERICA_BF9093 }, + { 72, JALECO_JF17 }, + { 73, KONAMI_VRC3 }, + { 74, WAIXING_TYPE_A }, + { 75, KONAMI_VRC1 }, + { 76, NAMCOT_3446 }, + { 77, IREM_LROG017 }, + { 78, IREM_HOLYDIVR }, + { 79, AVE_NINA06 }, + { 80, TAITO_X1_005 }, + // 81 Unused + { 82, TAITO_X1_017 }, + { 83, CONY_BOARD }, + // 84 Pasofami hacked images? + { 85, KONAMI_VRC7 }, + { 86, JALECO_JF13 }, + { 87, DIS_74X139X74 }, + { 88, NAMCOT_34X3 }, + { 89, SUNSOFT_2 }, + { 90, JYCOMPANY_A }, + { 91, UNL_MK2 }, + { 92, JALECO_JF19 }, + { 93, SUNSOFT_2 }, + { 94, STD_UN1ROM }, + { 95, NAMCOT_3425 }, + { 96, BANDAI_OEKAKIDS }, + { 97, IREM_TAM_S1 }, + // 98 Unused + // 99 VS. system - Not going to be implemented (use MAME instead) + // 100 images hacked to work with nesticle? + // 101 Unused (Urusei Yatsura had been assigned to this mapper, but it's Mapper 87) + // 102 Unused + { 103, UNL_2708 }, // 103 Bootleg cart 2708 (Doki Doki Panic - FDS Conversion) - Unsupported + { 104, CAMERICA_GOLDENFIVE }, + { 105, STD_EVENT }, + { 106, BTL_SMB3 }, + { 107, MAGICSERIES_MD }, + { 108, WHIRLWIND_2706 }, + // 109 Unused + // 110 Unused + // 111 Ninja Ryuukenden Chinese? - Unsupported + { 112, NTDEC_ASDER }, + { 113, HES_BOARD }, + { 114, SUPERGAME_LIONKING }, + { 115, KASING_BOARD }, + { 116, SOMARI_SL12 }, + { 117, FUTUREMEDIA_BOARD }, + { 118, STD_TXSROM }, + { 119, STD_TQROM }, + { 120, BTL_TOBIDASE }, + { 121, KAY_BOARD }, + // 122 Unused + { 123, UNL_H2288 }, + // 124 Unused + // 125 Unused + { 126, BMC_PJOY84 }, + // 127 Unused + // 128 Unused + // 129 Unused + // 130 Unused + // 131 Unused + { 132, TXC_22211 }, + { 133, SACHEN_SA72008 }, + { 134, BMC_FAMILY_4646 }, + // 135 Unused + { 136, SACHEN_TCU02 }, + { 137, SACHEN_8259D }, + { 138, SACHEN_8259B }, + { 139, SACHEN_8259C }, + { 140, JALECO_JF11 }, + { 141, SACHEN_8259A }, + { 142, KAISER_KS7032}, + { 143, SACHEN_TCA01 }, + { 144, AGCI_50282 }, + { 145, SACHEN_SA72007 }, + { 146, AVE_NINA06 }, // basically same as Mapper 79 (Nina006) + { 147, SACHEN_TCU01 }, + { 148, SACHEN_SA0037 }, + { 149, SACHEN_SA0036 }, + { 150, SACHEN_74LS374 }, + // 151 VS. system by Konami - Not going to be implemented (use MAME instead) + { 152, DIS_74X161X161X32 }, + { 153, BANDAI_LZ93 }, + { 154, NAMCOT_34X3 }, + { 155, STD_SXROM_A }, // diff compared to MMC1 concern WRAM + { 156, OPENCORP_DAOU306 }, + { 157, BANDAI_DATACH }, // Datach Reader games -> must go in the Datach subslot + { 158, TENGEN_800037 }, + { 159, BANDAI_LZ93EX1 }, // with 24c01 + { 160, SACHEN_SA009 }, + // 161 Unused + { 162, WAIXING_FS304}, // not confirmed, but a lot of chinese releases use it like this... + { 163, NANJING_BOARD}, + { 164, WAIXING_FFV }, + { 165, WAIXING_SH2 }, + { 166, SUBOR_TYPE1 }, + { 167, SUBOR_TYPE0 }, + { 168, UNL_RACERMATE }, + // 169 Unused + // 170 Fujiya + { 171, KAISER_KS7058 }, + { 172, TXC_DUMARACING }, + { 173, TXC_MJBLOCK }, + // 174 Unused + { 175, KAISER_KS7022}, + { 176, UNL_XIAOZY }, + { 177, HENGG_SRICH }, + { 178, WAIXING_SGZLZ }, + { 179, HENGG_XHZS }, + { 180, UXROM_CC }, + // 181 Unused + { 182, HOSENKAN_BOARD }, + { 183, BTL_SHUIGUAN }, + { 184, SUNSOFT_1 }, + { 185, STD_CNROM }, + { 186, FUKUTAKE_BOARD }, + { 187, UNL_KOF96 }, + { 188, BANDAI_KARAOKE }, + { 189, TXC_TW }, + // 190 Unused + { 191, WAIXING_TYPE_B }, + { 192, WAIXING_TYPE_C }, + { 193, NTDEC_FIGHTINGHERO }, + { 194, WAIXING_TYPE_D }, + { 195, WAIXING_TYPE_E }, + { 196, BTL_SBROS11 }, + { 197, UNL_SF3 }, + { 198, WAIXING_TYPE_F }, + { 199, WAIXING_TYPE_G }, + { 200, BMC_36IN1 }, + { 201, BMC_21IN1 }, + { 202, BMC_150IN1 }, + { 203, BMC_35IN1 }, + { 204, BMC_64IN1 }, + { 205, BMC_15IN1 }, + { 206, NAMCOT_34X3 }, + { 207, TAITO_X1_005 }, + { 208, GOUDER_37017 }, + { 209, JYCOMPANY_C }, + { 210, NAMCOT_175 }, + { 211, JYCOMPANY_B }, + { 212, BMC_SUPERHIK_300IN1 }, + { 213, BMC_NOVEL2 }, + { 214, BMC_SUPERGUN_20IN1 }, + { 215, SUPERGAME_BOOGERMAN }, + { 216, RCM_GS2015 }, + { 217, BMC_GOLDENCARD_6IN1 }, + { 218, NOCASH_NOCHR }, + // 219 UNL-A9746 (according to Cah4e3's code, no dump available (yet) + // 220 Unused + { 221, UNL_N625092 }, + { 222, BTL_DRAGONNINJA }, + { 223, WAIXING_TYPE_I }, // (according to NEStopia source, it's MMC3 with more WRAM) + { 224, WAIXING_TYPE_J }, // (according to NEStopia source, it's MMC3 with more WRAM) + { 225, BMC_72IN1 }, + { 226, BMC_76IN1 }, + { 227, BMC_1200IN1 }, + { 228, ACTENT_ACT52 }, + { 229, BMC_31IN1 }, + { 230, BMC_22GAMES }, + { 231, BMC_20IN1 }, + { 232, CAMERICA_BF9096 }, + { 233, BMC_SUPER22 }, + { 234, AVE_MAXI15 }, + { 235, BMC_GOLD150 }, // 235 Golden Game x-in-1 - Unsupported + // 236 Game 800-in-1 - Unsupported + // 237 Unused + { 238, UNL_603_5052 }, + // 239 Unused + { 240, CNE_SHLZ }, + { 241, TXC_COMMANDOS }, + { 242, WAIXING_WXZS }, + { 243, SACHEN_74LS374_ALT }, + { 244, CNE_DECATHLON }, + { 245, WAIXING_TYPE_H }, + { 246, CNE_FSB }, + // 247 Unused + // 248 Unused + { 249, WAIXING_SECURITY }, + { 250, NITRA_TDA }, + // 251 Shen Hua Jian Yun III?? - Unsupported + { 252, WAIXING_SGZ }, + // 253 Super 8-in-1 99 King Fighter?? - Unsupported + { 254, BTL_PIKACHUY2K }, + { 255, BMC_110IN1 }, +}; + +const nes_mmc *nes_mapper_lookup( int mapper ) +{ + int i; + + for (i = 0; i < ARRAY_LENGTH(mmc_list); i++) + { + if (mmc_list[i].iNesMapper == mapper) + return &mmc_list[i]; + } + + return NULL; +} + +#if 0 +int nes_get_mmc_id( running_machine &machine, int mapper ) +{ + const nes_mmc *mmc = nes_mapper_lookup(mapper); + + if (mmc == NULL) + fatalerror("Unimplemented Mapper %d\n", mapper); + + return mmc->pcb_id; +} +#endif + +/************************************************************* + + ines_mapr_setup + + setup the board specific pcb_id for a given mapper + + *************************************************************/ + +void ines_mapr_setup( int mapper, int *pcb_id ) +{ + const nes_mmc *mmc = nes_mapper_lookup(mapper); + if (mmc == NULL) + fatalerror("Unimplemented Mapper %d\n", mapper); + + *pcb_id = mmc->pcb_id; +} + +/************************************************************* + + call_load_ines + + *************************************************************/ + +void nes_cart_slot_device::call_load_ines() +{ + UINT32 vram_size = 0, prgram_size = 0, battery_size = 0, mapper_sram_size = 0; + UINT32 prg_size, vrom_size; + UINT8 header[0x10]; + UINT8 mapper, submapper = 0, local_options; + bool ines20 = FALSE, prg16k; + std::string mapinfo; + int pcb_id = 0, mapint1 = 0, mapint2 = 0, mapint3 = 0, mapint4 = 0; + int crc_hack = 0; + bool bus_conflict = FALSE; + + // read out the header + fseek(0, SEEK_SET); + fread(&header, 0x10); + + // SETUP step 1: getting PRG, VROM, VRAM sizes + prg16k = (header[4] == 1); + prg_size = prg16k ? 2 * 0x4000 : header[4] * 0x4000; + vrom_size = header[5] * 0x2000; + vram_size = 0x4000; + + // SETUP step 2: getting PCB and other settings + mapper = (header[6] & 0xf0) >> 4; + local_options = header[6] & 0x0f; + + switch (header[7] & 0xc) + { + case 0x4: + case 0xc: + // probably the header got corrupted: don't trust upper bits for mapper + break; + + case 0x8: // it's iNES 2.0 format + ines20 = TRUE; + case 0x0: + default: + mapper |= header[7] & 0xf0; + break; + } + + // use info from nes.hsi if available! + if (hashfile_extrainfo(*this, mapinfo)) + { + if (4 == sscanf(mapinfo.c_str(),"%d %d %d %d", &mapint1, &mapint2, &mapint3, &mapint4)) + { + /* image is present in nes.hsi: overwrite the header settings with these */ + mapper = mapint1; + local_options = mapint2 & 0x0f; + crc_hack = (mapint2 & 0xf0) >> 4; // this is used to differentiate among variants of the same Mapper (see below) + prg16k = (mapint3 == 1); + prg_size = prg16k ? 2 * 0x4000 : mapint3 * 0x4000; + vrom_size = mapint4 * 0x2000; + logerror("NES.HSI info: %d %d %d %d\n", mapint1, mapint2, mapint3, mapint4); + } + else + { + logerror("NES: [%s], Invalid mapinfo found\n", mapinfo.c_str()); + } + } + else + { + logerror("NES: No extrainfo found\n"); + } + + // use extended iNES2.0 info if available! + if (ines20) + { + mapper |= (header[8] & 0x0f) << 8; + // read submappers (based on 20140116 specs) + submapper = (header[8] & 0xf0 >> 8); + prg_size += ((header[9] & 0x0f) << 8) * 0x4000; + vrom_size += ((header[9] & 0xf0) << 4) * 0x2000; + } + ines_mapr_setup(mapper, &pcb_id); + + // handle submappers + if (submapper) + { + // 001: MMC1 + if (mapper == 1 && submapper == 3) + pcb_id = STD_SXROM_A; + else if (mapper == 1 && submapper == 5) + logerror("Unimplemented iNES2.0 submapper: SEROM/SHROM/SH1ROM.\n"); + // 002, 003, 007: UxROM, CNROM, AxROM + else if (mapper == 2 && submapper == 2) + bus_conflict = TRUE; + else if (mapper == 3 && submapper == 2) + bus_conflict = TRUE; + else if (mapper == 7 && submapper == 2) + bus_conflict = TRUE; + // 021, 023, 025: VRC4 / VRC2 + else if (mapper == 21 || mapper == 23 || mapper == 25) + { + // 021, 023, 025: VRC4 + int line_1 = submapper & 0x07; + int line_2 = (submapper & 0x08) ? line_1 + 1 : line_1 - 1; + if (line_2 >= 0 && line_2 <= 7) + { + pcb_id = KONAMI_VRC4; + m_cart->set_vrc_lines(line_1, line_2, 0); + } + else if (submapper == 15) + { + pcb_id = KONAMI_VRC2; + m_cart->set_vrc_lines(1, 0, 0); + } + } + // 032: Irem G101 + else if (mapper == 32 && submapper == 1) + { + m_cart->set_mirroring(PPU_MIRROR_HIGH); // Major League has hardwired mirroring + } + // iNES Mapper 034 + else if (mapper == 34 && submapper == 1) + { + pcb_id = AVE_NINA01; // Mapper 34 is used for 2 diff boards + } + // iNES Mapper 068 / Sunsoft 4 + else if (mapper == 68 && submapper == 1) + { + submapper = 0; + logerror("Unimplemented iNES2.0 submapper: SUNSOFT-DCS.\n"); + } + // iNES Mapper 071 + else if (mapper == 71 && submapper == 1) + { + m_cart->set_pcb_ctrl_mirror(TRUE); // Mapper 71 is used for 2 diff boards + } + // iNES Mapper 078 + else if (mapper == 78) + { + if (submapper == 1) + pcb_id = JALECO_JF16; // Mapper 78 is used for 2 diff boards + else if (submapper == 3) + pcb_id = IREM_HOLYDIVR; + } + // iNES Mapper 185 + else if (mapper == 185) + { + int ce_state = (submapper & 0x0c) >> 2; + m_cart->set_ce(0x03, ce_state); + } + // iNES Mapper 232 + else if (mapper == 210 && submapper == 1) + { + submapper = 0; + logerror("Unimplemented iNES2.0 submapper: CAMERICA-BF9096.\n"); + } + else if (submapper) + { + submapper = 0; + logerror("Undocumented iNES2.0 submapper, please report it to the MESS boards!\n"); + } + } + + // SETUP step 3: storing the info needed for emulation + m_pcb_id = pcb_id; + m_cart->set_mirroring(BIT(local_options, 0) ? PPU_MIRROR_VERT : PPU_MIRROR_HORZ); + if (BIT(local_options, 1)) + battery_size = NES_BATTERY_SIZE; // with original iNES format we can only support 8K WRAM battery + m_cart->set_trainer(BIT(local_options, 2) ? TRUE : FALSE); + m_cart->set_four_screen_vram(BIT(local_options, 3) ? TRUE : FALSE); + + if (ines20) + { + // PRGRAM/BWRAM (not fully supported, also due to lack of 2.0 files) + if ((header[10] & 0x0f) > 0) + prgram_size = 0x80 << ((header[10] & 0x0f) - 1); + if ((header[10] & 0xf0) > 0) + battery_size = 0x80 << (((header[10] & 0xf0) >> 4) - 1); + // VRAM + vram_size = 0; + if ((header[11] & 0x0f) > 0) + vram_size = 0x80 << ((header[11] & 0x0f) - 1); + if ((header[11] & 0xf0) > 0) + vram_size |= 0x80 << (((header[11] & 0xf0) >> 4) - 1); + // header[11] & 0xf0 is the size of battery backed VRAM, found so far in Racermate II only and not supported yet + } + else + { + // PRGRAM size is 8k for most games, but pirate carts often use different sizes, + // so its size has been added recently to the iNES format spec, but almost no image uses it + prgram_size = header[8] ? header[8] * 0x2000 : 0x2000; + } + + // a few mappers correspond to multiple PCBs, so we need a few additional checks and tweaks + switch (m_pcb_id) + { + case STD_NROM: + if (prg_size == 3 * 0x4000) // NROM368 are padded with 2k empty data at start to accomplish with iNES standard + { + m_pcb_id = STD_NROM368; + fseek(0x810, SEEK_SET); + prg_size = 0xb800; + } + break; + + case NOCASH_NOCHR: + // this mapper uses mirroring flags differently + m_cart->set_four_screen_vram(FALSE); + switch (local_options & 0x09) + { + case 0x00: + m_cart->set_mirroring(PPU_MIRROR_HORZ); + break; + case 0x01: + m_cart->set_mirroring(PPU_MIRROR_VERT); + break; + case 0x08: + m_cart->set_mirroring(PPU_MIRROR_LOW); + break; + case 0x09: + m_cart->set_mirroring(PPU_MIRROR_HIGH); + break; + } + break; + + case STD_CNROM: + if (mapper == 185 && !submapper) + { + switch (crc_hack) + { + case 0x0: // pin26: CE, pin27: CE (B-Wings, Bird Week) + m_cart->set_ce(0x03, 0x03); + break; + case 0x4: // pin26: CE, pin27: /CE (Mighty Bomb Jack, Spy Vs. Spy) + m_cart->set_ce(0x03, 0x01); + break; + case 0x8: // pin26: /CE, pin27: CE (Sansu 1, 2, 3 Nen, Othello) + m_cart->set_ce(0x03, 0x02); + break; + case 0xc: // pin26: /CE, pin27: /CE (Seicross v2.0) + m_cart->set_ce(0x03, 0x00); + break; + } + } + break; + + case KONAMI_VRC2: + if (mapper == 22) + m_cart->set_vrc_lines(0, 1, 1); + if (mapper == 23 && !crc_hack && !submapper) + m_cart->set_vrc_lines(1, 0, 0); + if (mapper == 23 && crc_hack && !submapper) + { + // here there are also Akumajou Special, Crisis Force, Parodius da!, Tiny Toons which are VRC-4 + m_cart->set_vrc_lines(3, 2, 0); + m_pcb_id = KONAMI_VRC4; // this allows for konami_irq to be installed at reset + } + break; + + case KONAMI_VRC4: + if (mapper == 21 && !submapper) // Wai Wai World 2 & Ganbare Goemon Gaiden 2 (the latter with crc_hack) + m_cart->set_vrc_lines(crc_hack ? 7 : 2, crc_hack ? 6 : 1, 0); + if (mapper == 25 && !submapper) // here there is also Ganbare Goemon Gaiden which is VRC-2 + m_cart->set_vrc_lines(crc_hack ? 2 : 0, crc_hack ? 3 : 1, 0); + break; + + case KONAMI_VRC6: + if (mapper == 24) + m_cart->set_vrc_lines(1, 0, 0); + if (mapper == 26) + m_cart->set_vrc_lines(0, 1, 0); + break; + + case IREM_G101: + if (crc_hack && !submapper) + m_cart->set_mirroring(PPU_MIRROR_HIGH); // Major League has hardwired mirroring + else if (!submapper) + m_cart->set_pcb_ctrl_mirror(TRUE); + break; + + case DIS_74X161X161X32: + if (mapper == 70) + m_cart->set_mirroring(PPU_MIRROR_VERT); // only hardwired mirroring makes different mappers 70 & 152 + else + m_cart->set_pcb_ctrl_mirror(TRUE); + break; + + case SUNSOFT_2: + if (mapper == 93) + m_cart->set_mirroring(PPU_MIRROR_VERT); // only hardwired mirroring makes different mappers 89 & 93 + else + m_cart->set_pcb_ctrl_mirror(TRUE); + break; + + case HES_BOARD: + if (crc_hack) + m_cart->set_pcb_ctrl_mirror(TRUE); // Mapper 113 is used for 2 diff boards + break; + + case CAMERICA_BF9093: + if (crc_hack && !submapper) + m_cart->set_pcb_ctrl_mirror(TRUE); // Mapper 71 is used for 2 diff boards + break; + + case STD_BXROM: + if (crc_hack && !submapper) + m_pcb_id = AVE_NINA01; // Mapper 34 is used for 2 diff boards + break; + + case BANDAI_LZ93: + if (crc_hack) + m_pcb_id = BANDAI_FJUMP2; // Mapper 153 is used for 2 diff boards + break; + + case IREM_HOLYDIVR: + if (crc_hack && !submapper) + m_pcb_id = JALECO_JF16; // Mapper 78 is used for 2 diff boards + break; + + case WAIXING_WXZS: + if (crc_hack) + m_pcb_id = WAIXING_DQ8; // Mapper 242 is used for 2 diff boards + break; + + case BMC_GOLD_7IN1: + if (crc_hack) + m_pcb_id = BMC_MARIOPARTY_7IN1; // Mapper 52 is used for 2 diff boards + break; + + case BTL_MARIOBABY: + if (crc_hack) + m_pcb_id = BTL_AISENSHINICOL; // Mapper 42 is used for 2 diff boards + break; + + case TAITO_X1_017: + mapper_sram_size = m_cart->get_mapper_sram_size(); + break; + + case TAITO_X1_005: + if (mapper == 207) + m_cart->set_x1_005_alt(TRUE); + mapper_sram_size = m_cart->get_mapper_sram_size(); + break; + + case NAMCOT_163: + mapper_sram_size = m_cart->get_mapper_sram_size(); + break; + //FIXME: we also have to fix Action 52 PRG loading somewhere... + + case BANDAI_DATACH: + fatalerror("Bandai Datach games have to be mounted in the Datach subslot!\n"); + break; + } + + // Finally turn off bus conflict emulation, because the pirate variants of the boards are bus conflict free and games would glitch + m_cart->set_bus_conflict(bus_conflict); + + // SETUP step 4: logging what we have found + if (!ines20) + { + logerror("Loaded game in iNES format:\n"); + logerror("-- Mapper %d\n", mapper); + logerror("-- PRG 0x%x (%d x 16k chunks)\n", prg_size, prg_size / 0x4000); + logerror("-- VROM 0x%x (%d x 8k chunks)\n", vrom_size, vrom_size / 0x2000); + logerror("-- VRAM 0x%x (%d x 8k chunks)\n", vram_size, vram_size / 0x2000); + logerror("-- Mirroring %s\n", BIT(header[6], 0) ? "Vertical" : "Horizontal"); + if (battery_size) + logerror("-- Battery found\n"); + if (m_cart->get_trainer()) + logerror("-- Trainer found\n"); + if (m_cart->get_four_screen_vram()) + logerror("-- 4-screen VRAM\n"); + logerror("-- TV System: %s\n", ((header[10] & 3) == 0) ? "NTSC" : (header[10] & 1) ? "Both NTSC and PAL" : "PAL"); + } + else + { + logerror("Loaded game in Extended iNES format:\n"); + logerror("-- Mapper: %d\n", mapper); + logerror("-- Submapper: %d\n", (header[8] & 0xf0) >> 4); + logerror("-- PRG 0x%x (%d x 16k chunks)\n", prg_size, prg_size / 0x4000); + logerror("-- VROM 0x%x (%d x 8k chunks)\n", vrom_size, vrom_size / 0x2000); + logerror("-- VRAM 0x%x (%d x 8k chunks)\n", vram_size, vram_size / 0x2000); + logerror("-- PRG NVWRAM: %d\n", (header[10] & 0xf0) >> 4); + logerror("-- PRG WRAM: %d\n", header[10] & 0x0f); + logerror("-- CHR NVWRAM: %d\n", (header[11] & 0xf0) >> 4); + logerror("-- CHR WRAM: %d\n", header[11] & 0x0f); + logerror("-- TV System: %s\n", (header[12] & 2) ? "Both NTSC and PAL" : (header[12] & 1) ? "PAL" : "NTSC"); + } + + // SETUP step 5: allocate pointers for PRG/VROM + if (prg_size) + m_cart->prg_alloc(prg_size, tag()); + if (vrom_size) + m_cart->vrom_alloc(vrom_size, tag()); + + // if there is a trainer, skip it for the moment + if (m_cart->get_trainer()) + fseek(0x210, SEEK_SET); + + // SETUP step 6: at last load the data! + // Read in the program chunks + if (prg16k) + { + fread(m_cart->get_prg_base(), 0x4000); + memcpy(m_cart->get_prg_base() + 0x4000, m_cart->get_prg_base(), 0x4000); + } + else + fread(m_cart->get_prg_base(), m_cart->get_prg_size()); +#if SPLIT_PRG + { + FILE *prgout; + char outname[255]; + + sprintf(outname, "%s.prg", filename()); + prgout = fopen(outname, "wb"); + if (prgout) + { + fwrite(m_cart->get_prg_base(), 1, 0x4000 * m_cart->get_prg_size(), prgout); + osd_printf_error("Created PRG chunk\n"); + } + + fclose(prgout); + } +#endif + + // Read in any chr chunks + if (m_cart->get_vrom_size()) + fread(m_cart->get_vrom_base(), m_cart->get_vrom_size()); + +#if SPLIT_CHR + if (state->m_chr_chunks > 0) + { + FILE *chrout; + char outname[255]; + + sprintf(outname, "%s.chr", filename()); + chrout= fopen(outname, "wb"); + if (chrout) + { + fwrite(m_cart->get_vrom_base(), 1, m_cart->get_vrom_size(), chrout); + osd_printf_error("Created CHR chunk\n"); + } + fclose(chrout); + } +#endif + + // SETUP steps 7: allocate the remaining pointer, when needed + if (vram_size) + m_cart->vram_alloc(vram_size); + if (prgram_size || m_cart->get_trainer()) + { + if (prgram_size) + m_cart->prgram_alloc(prgram_size); + else + m_cart->prgram_alloc(0x2000); + if (m_cart->get_trainer()) + { + fseek(0x10, SEEK_SET); + fread(m_cart->get_prgram_base() + 0x1000, 0x200); + } + } + + + // Attempt to load a battery file for this ROM + // A few boards have internal RAM with a battery (MMC6, Taito X1-005 & X1-017, etc.) + if (battery_size || mapper_sram_size) + { + UINT32 tot_size = battery_size + mapper_sram_size; + dynamic_buffer temp_nvram(tot_size); + battery_load(&temp_nvram[0], tot_size, 0x00); + if (battery_size) + { + //printf("here %d\n", battery_size); + m_cart->battery_alloc(battery_size); + memcpy(m_cart->get_battery_base(), &temp_nvram[0], battery_size); + } + if (mapper_sram_size) + memcpy(m_cart->get_mapper_sram_base(), &temp_nvram[battery_size], m_cart->get_mapper_sram_size()); + } +} + +const char * nes_cart_slot_device::get_default_card_ines(UINT8 *ROM, UINT32 len) +{ + UINT8 mapper, submapper = 0; + bool ines20 = FALSE; + std::string mapinfo; + int pcb_id = 0, mapint1 = 0, mapint2 = 0, mapint3 = 0, mapint4 = 0; + int crc_hack = 0; + + mapper = (ROM[6] & 0xf0) >> 4; + + switch (ROM[7] & 0xc) + { + case 0x4: + case 0xc: + // probably the header got corrupted: don't trust upper bits for mapper + break; + + case 0x8: // it's iNES 2.0 format + ines20 = TRUE; + case 0x0: + default: + mapper |= ROM[7] & 0xf0; + break; + } + + // use info from nes.hsi if available! + if (hashfile_extrainfo(*this, mapinfo)) + { + if (4 == sscanf(mapinfo.c_str(),"%d %d %d %d", &mapint1, &mapint2, &mapint3, &mapint4)) + { + /* image is present in nes.hsi: overwrite the header settings with these */ + mapper = mapint1; + crc_hack = (mapint2 & 0xf0) >> 4; // this is used to differentiate among variants of the same Mapper (see below) + } + } + + // use extended iNES2.0 info if available! + if (ines20) + { + mapper |= (ROM[8] & 0x0f) << 8; + // read submappers (based on 20140116 specs) + submapper = (ROM[8] & 0xf0 >> 8); + } + + ines_mapr_setup(mapper, &pcb_id); + + // handle submappers + if (submapper) + { + // 001: MMC1 + if (mapper == 1 && submapper == 3) + pcb_id = STD_SXROM_A; + else if (mapper == 1 && submapper == 5) + logerror("Unimplemented iNES2.0 submapper: SEROM/SHROM/SH1ROM.\n"); + // 021, 023, 025: VRC4 / VRC2 + else if (mapper == 21 || mapper == 23 || mapper == 25) + { + // 021, 023, 025: VRC4 + int line_1 = submapper & 0x07; + int line_2 = (submapper & 0x08) ? line_1 + 1 : line_1 - 1; + if (line_2 >= 0 && line_2 <= 7) + pcb_id = KONAMI_VRC4; + else if (submapper == 15) + pcb_id = KONAMI_VRC2; + } + // iNES Mapper 034 + else if (mapper == 34 && submapper == 1) + { + pcb_id = AVE_NINA01; // Mapper 34 is used for 2 diff boards + } + // iNES Mapper 078 + else if (mapper == 78) + { + if (submapper == 1) + pcb_id = JALECO_JF16; // Mapper 78 is used for 2 diff boards + else if (submapper == 3) + pcb_id = IREM_HOLYDIVR; + } + } + + // solve mapper conflicts + switch (pcb_id) + { + case STD_NROM: + if (ROM[4] == 3) + pcb_id = STD_NROM368; + break; + + case KONAMI_VRC2: + if (mapper == 23 && crc_hack && !submapper) + pcb_id = KONAMI_VRC4; // this allows for konami_irq to be installed at reset + break; + + case STD_BXROM: + if (crc_hack && !submapper) + pcb_id = AVE_NINA01; // Mapper 34 is used for 2 diff boards + break; + + case BANDAI_LZ93: + if (crc_hack) + pcb_id = BANDAI_FJUMP2; // Mapper 153 is used for 2 diff boards + break; + + case IREM_HOLYDIVR: + if (crc_hack && !submapper) + pcb_id = JALECO_JF16; // Mapper 78 is used for 2 diff boards + break; + + case WAIXING_WXZS: + if (crc_hack) + pcb_id = WAIXING_DQ8; // Mapper 242 is used for 2 diff boards + break; + + case BMC_GOLD_7IN1: + if (crc_hack) + pcb_id = BMC_MARIOPARTY_7IN1; // Mapper 52 is used for 2 diff boards + break; + + case BTL_MARIOBABY: + if (crc_hack) + pcb_id = BTL_AISENSHINICOL; // Mapper 42 is used for 2 diff boards + break; + } + + return nes_get_slot(pcb_id); +} diff --git a/src/devices/bus/nes/nes_pcb.inc b/src/devices/bus/nes/nes_pcb.inc new file mode 100644 index 00000000000..57cdf3d498c --- /dev/null +++ b/src/devices/bus/nes/nes_pcb.inc @@ -0,0 +1,609 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/***************************************************************************************** + + NES Cart PCBs Emulation + +****************************************************************************************/ + +struct nes_pcb +{ + const char *slot_opt; + int pcb_id; +}; + +// Here, we take the feature attribute from .xml (i.e. the PCB name) and we assign a unique ID to it +static const nes_pcb pcb_list[] = +{ + { "nrom", STD_NROM }, + { "hvc_basic", HVC_FAMBASIC }, + { "nrom368", STD_NROM368 }, + { "nrom_gg", GG_NROM }, + { "uxrom", STD_UXROM }, + { "unrom_cc", UXROM_CC }, + { "cnrom", STD_CNROM }, + { "bandai_pt554", BANDAI_PT554 }, + { "cprom", STD_CPROM }, + { "axrom", STD_AXROM }, + { "pxrom", STD_PXROM }, + { "fxrom", STD_FXROM }, + { "bnrom", STD_BXROM }, + { "gxrom", STD_GXROM }, + { "un1rom", STD_UN1ROM }, + { "sxrom", STD_SXROM }, + { "sorom", STD_SOROM }, + { "sxrom_a", STD_SXROM_A }, + { "sorom_a", STD_SOROM_A }, + { "txrom", STD_TXROM }, + { "hkrom", STD_HKROM }, + { "tqrom", STD_TQROM }, + { "txsrom", STD_TXSROM }, + { "exrom", STD_EXROM }, + { "disksys", STD_DISKSYS }, + { "pal_zz", PAL_ZZ }, + { "nes_qj", NES_QJ }, + { "nes_event", STD_EVENT }, + { "discrete_74x139", DIS_74X139X74 }, + { "discrete_74x377", DIS_74X377 }, + { "discrete_74x161", DIS_74X161X161X32 }, + { "bitcorp_dis", DIS_74X161X138 }, + { "lz93d50", BANDAI_LZ93 }, + { "lz93d50_ep1", BANDAI_LZ93EX1 }, + { "lz93d50_ep2", BANDAI_LZ93EX2 }, + { "fcg", BANDAI_FCG }, + { "fjump2", BANDAI_FJUMP2 }, + { "datach", BANDAI_DATACH }, + { "karastudio", BANDAI_KARAOKE }, + { "oekakids", BANDAI_OEKAKIDS }, + { "g101", IREM_G101 }, + { "lrog017", IREM_LROG017 }, + { "h3001", IREM_H3001 }, + { "holydivr", IREM_HOLYDIVR }, + { "tam_s1", IREM_TAM_S1 }, + { "jf11", JALECO_JF11 }, + { "jf13", JALECO_JF13 }, + { "jf16", JALECO_JF16 }, + { "jf17", JALECO_JF17 }, + { "jf17pcm", JALECO_JF17_ADPCM }, + { "jf19", JALECO_JF19 }, + { "jf19pcm", JALECO_JF19_ADPCM }, + { "ss88006", JALECO_SS88006 }, + { "jf23", JALECO_JF23 }, + { "jf24", JALECO_JF24 }, + { "jf29", JALECO_JF29 }, + { "jf33", JALECO_JF33 }, + { "vrc1", KONAMI_VRC1 }, + { "vrc2", KONAMI_VRC2 }, + { "vrc3", KONAMI_VRC3 }, + { "vrc4", KONAMI_VRC4 }, + { "vrc6", KONAMI_VRC6 }, + { "vrc7", KONAMI_VRC7 }, + { "namcot_163", NAMCOT_163 }, + { "namcot_175", NAMCOT_175 }, + { "namcot_340", NAMCOT_340 }, + { "namcot_3433", NAMCOT_34X3 }, // DxROM is a Nintendo board for US versions of the 3433/3443 games + { "namcot_3425", NAMCOT_3425 }, + { "namcot_3446", NAMCOT_3446 }, + { "sunsoft1", SUNSOFT_1 }, + { "sunsoft2", SUNSOFT_2 }, + { "sunsoft3", SUNSOFT_3 }, + { "sunsoft4", SUNSOFT_4 }, + { "sunsoft_dcs", SUNSOFT_DCS }, + { "sunsoft_fme7", SUNSOFT_FME7 }, // JxROM is a Nintendo board for US versions of the Sunsoft FME7 games + { "sunsoft5a", SUNSOFT_FME7 }, + { "sunsoft5b", SUNSOFT_5 }, + { "tc0190fmc", TAITO_TC0190FMC }, + { "tc0190fmcp", TAITO_TC0190FMCP }, + { "tc0350fmr", TAITO_TC0190FMC }, + { "x1_005", TAITO_X1_005 }, // two variants exist, depending on pin17 & pin31 connections + { "x1_017", TAITO_X1_017 }, + { "nina001", AVE_NINA01 }, + { "nina006", AVE_NINA06 }, + { "maxi15", AVE_MAXI15 }, + { "bf9093", CAMERICA_BF9093 }, + { "bf9096", CAMERICA_BF9096 }, + { "goldenfive", CAMERICA_GOLDENFIVE }, + { "ade" , CAMERICA_ALADDIN }, + { "cne_decathl", CNE_DECATHLON }, + { "cne_fsb", CNE_FSB }, + { "cne_shlz", CNE_SHLZ }, + { "nanjing", NANJING_BOARD }, // mapper 163 + { "ntdec_asder", NTDEC_ASDER }, // mapper 112 + { "ntdec_fh", NTDEC_FIGHTINGHERO }, // mapper 193 + { "sa009", SACHEN_SA009 }, + { "sa0036", SACHEN_SA0036 }, + { "sa0037", SACHEN_SA0037 }, + { "sa72007", SACHEN_SA72007 }, + { "sa72008", SACHEN_SA72008 }, + { "tca01", SACHEN_TCA01 }, + { "s8259a", SACHEN_8259A }, + { "s8259b", SACHEN_8259B }, + { "s8259c", SACHEN_8259C }, + { "s8259d", SACHEN_8259D }, + { "s74x374", SACHEN_74LS374 }, + { "s74x374a", SACHEN_74LS374_ALT }, /* FIXME: Made up boards some different handling */ + { "tcu01", SACHEN_TCU01 }, + { "tcu02", SACHEN_TCU02 }, + { "sa9602b", SACHEN_SA9602B }, + { "tengen_800008", TENGEN_800008 }, /* FIXME: Is this the same as mapper 3? */ + { "tengen_800032", TENGEN_800032 }, + { "tengen_800037", TENGEN_800037 }, + { "txc_22211", TXC_22211 }, + { "txc_dumarc", TXC_DUMARACING }, + { "txc_mjblock", TXC_MJBLOCK }, + { "txc_strikew", TXC_STRIKEW }, + { "txc_commandos", TXC_COMMANDOS }, + { "waixing_a", WAIXING_TYPE_A }, + { "waixing_a1", WAIXING_TYPE_A1 }, /* FIXME: Made up boards the different CHRRAM banks (see Ji Jia Zhan Shi }, */ + { "waixing_b", WAIXING_TYPE_B }, + { "waixing_c", WAIXING_TYPE_C }, + { "waixing_d", WAIXING_TYPE_D }, + { "waixing_e", WAIXING_TYPE_E }, + { "waixing_f", WAIXING_TYPE_F }, + { "waixing_g", WAIXING_TYPE_G }, + { "waixing_h", WAIXING_TYPE_H }, + { "waixing_h1", WAIXING_TYPE_H1 }, + { "waixing_i", WAIXING_TYPE_I }, + { "waixing_j", WAIXING_TYPE_J }, + { "waixing_sgz", WAIXING_SGZ }, + { "waixing_sgzlz", WAIXING_SGZLZ }, + { "waixing_sec", WAIXING_SECURITY }, + { "waixing_ffv", WAIXING_FFV }, + { "waixing_wxzs", WAIXING_WXZS }, + { "waixing_wxzs2", WAIXING_WXZS2 }, + { "waixing_dq8", WAIXING_DQ8 }, + { "waixing_sh2", WAIXING_SH2 }, + { "fs304", WAIXING_FS304 }, // used in Zelda 3 by Waixing + { "cony", CONY_BOARD }, + { "yoko", YOKO_BOARD }, + { "hengg_srich", HENGG_SRICH }, + { "hengg_xhzs", HENGG_XHZS }, + { "hengg_shjy3", HENGG_SHJY3 }, // mapper 253 + { "hes", HES_BOARD }, + { "hosenkan", HOSENKAN_BOARD }, + { "ks7058", KAISER_KS7058 }, + { "ks202", KAISER_KS202 }, // mapper 56 + { "ks7022", KAISER_KS7022 }, // mapper 175 + { "ks7017", KAISER_KS7017 }, + { "ks7032", KAISER_KS7032 }, // mapper 142 + { "ks7031", KAISER_KS7031 }, // used in Dracula II (FDS Conversion) + { "ks7012", KAISER_KS7012 }, // used in Zanac (FDS Conversion) + { "ks7013b", KAISER_KS7013B }, // used in Highway Star (FDS Conversion) + { "gs2015", RCM_GS2015 }, + { "gs2004", RCM_GS2004 }, + { "gs2013", RCM_GS2013 }, + { "tf9in1", RCM_TF9IN1 }, + { "3dblock", RCM_3DBLOCK }, // NROM + IRQ? + { "racermate", UNL_RACERMATE }, // mapper 168 + { "agci_50282", AGCI_50282 }, + { "dreamtech01", DREAMTECH_BOARD }, + { "fukutake", FUKUTAKE_BOARD }, + { "futuremedia", FUTUREMEDIA_BOARD }, + { "magicseries", MAGICSERIES_MD }, + { "daou_306", OPENCORP_DAOU306 }, + { "subor0", SUBOR_TYPE0 }, + { "subor1", SUBOR_TYPE1 }, + { "cc21", UNL_CC21 }, + { "xiaozy", UNL_XIAOZY }, + { "edu2k", UNL_EDU2K }, + { "t230", UNL_T230 }, + { "mk2", UNL_MK2 }, + // misc bootleg boards + { "ax5705", UNL_AX5705 }, + { "sc127", UNL_SC127 }, + { "mariobaby", BTL_MARIOBABY }, + { "asnicol", BTL_AISENSHINICOL }, + { "smb3pirate", BTL_SMB3 }, + { "btl_dninja", BTL_DRAGONNINJA }, + { "whirl2706", WHIRLWIND_2706 }, + { "smb2j", UNL_SMB2J }, + { "smb2ja", BTL_SMB2JA }, + { "smb2jb", BTL_SMB2JB }, + { "09034a", BTL_09034A }, + { "tobidase", BTL_TOBIDASE }, // mapper 120 + { "dbz5", REXSOFT_DBZ5 }, + { "sl1632", REXSOFT_SL1632 }, + { "somari", SOMARI_SL12 }, // mapper 116 + { "nitra", NITRA_TDA }, + { "ks7057", UNL_KS7057 }, // mapper 196 alt (for Street Fighter VI / Fight Street VI }, + { "sbros11", BTL_SBROS11 }, + { "family4646", BMC_FAMILY_4646 }, + { "pikay2k", BTL_PIKACHUY2K }, // mapper 254 + { "8237", UNL_8237 }, + { "sg_lionk", SUPERGAME_LIONKING }, + { "sg_boog", SUPERGAME_BOOGERMAN }, + { "kasing", KASING_BOARD }, + { "kay", KAY_BOARD }, + { "h2288", UNL_H2288 }, + { "unl_6035052", UNL_603_5052 }, // mapper 238? + { "txc_tw", TXC_TW }, + { "kof97", UNL_KOF97 }, + { "kof96", UNL_KOF96 }, + { "sfight3", UNL_SF3 }, + { "gouder", GOUDER_37017 }, + { "benshieng", BMC_BENSHIENG }, + { "action52", ACTENT_ACT52 }, + { "caltron6in1", CALTRON_6IN1 }, + { "rumblestation", RUMBLESTATION_BOARD }, // mapper 46 + { "svision16", SVISION16_BOARD }, + { "n625092", UNL_N625092 }, + { "a65as", BMC_A65AS }, + { "t262", BMC_T262 }, + { "novel1", BMC_NOVEL1 }, + { "novel2", BMC_NOVEL2 }, // mapper 213... same as BMC-NOVELDIAMOND9999999IN1 board? + { "studyngame", UNL_STUDYNGAME }, // mapper 39 + { "sgun20in1", BMC_SUPERGUN_20IN1 }, + { "bmc_vt5201", BMC_VT5201 }, // mapper 60 otherwise + { "bmc_d1038", BMC_VT5201 }, // mapper 60? + { "810544c", BMC_810544 }, + { "ntd03", BMC_NTD_03 }, + { "bmc_gb63", BMC_G63IN1 }, + { "bmc_gka", BMC_GKA }, + { "bmc_gkb", BMC_GKB }, + { "bmc_ws", BMC_WS }, + { "bmc_hik300", BMC_SUPERHIK_300IN1 }, + { "bmc_s700", BMC_SUPER_700IN1 }, + { "bmc_ball11", BMC_BALLGAMES_11IN1 }, + { "bmc_22games", BMC_22GAMES }, + { "bmc_64y2k", BMC_64IN1NR }, + { "bmc_12in1", BMC_12IN1 }, + { "bmc_20in1", BMC_20IN1 }, + { "bmc_21in1", BMC_21IN1 }, + { "bmc_31in1", BMC_31IN1 }, + { "bmc_35in1", BMC_35IN1 }, + { "bmc_36in1", BMC_36IN1 }, + { "bmc_64in1", BMC_64IN1 }, + { "bmc_70in1", BMC_70IN1 }, + { "bmc_72in1", BMC_72IN1 }, + { "bmc_76in1", BMC_76IN1 }, + { "bmc_s42in1", BMC_76IN1 }, + { "bmc_110in1", BMC_110IN1 }, + { "bmc_150in1", BMC_150IN1 }, + { "bmc_190in1", BMC_190IN1 }, + { "bmc_800in1", BMC_800IN1 }, + { "bmc_1200in1", BMC_1200IN1 }, + { "bmc_8157", BMC_8157 }, + { "bmc_g146", BMC_G146 }, + { "bmc_11160", BMC_11160 }, + { "fk23c", BMC_FK23C }, + { "fk23ca", BMC_FK23CA }, + { "s24in1c03", BMC_S24IN1SC03 }, + { "bmc_15in1", BMC_15IN1 }, + { "bmc_sbig7in1", BMC_SUPERBIG_7IN1 }, + { "bmc_hik8in1", BMC_HIK8IN1 }, + { "bmc_hik4in1", BMC_SUPERHIK_4IN1 }, + { "bmc_mario7in1", BMC_MARIOPARTY_7IN1 }, + { "bmc_gold7in1", BMC_GOLD_7IN1 }, + { "bmc_gc6in1", BMC_GOLDENCARD_6IN1 }, + { "bmc_411120c", BMC_411120C }, + { "bmc_830118c", BMC_830118C }, + { "pjoy84", BMC_PJOY84 }, + { "bmc_gold150", BMC_GOLD150 }, + { "bmc_gold260", BMC_GOLD260 }, + { "bmc_power255", BMC_CH001 }, + { "bmc_s22games", BMC_SUPER22 }, + { "bmc_reset4", BMC_4IN1RESET }, + { "bmc_reset42", BMC_42IN1RESET }, + { "jyc_a", JYCOMPANY_A }, + { "jyc_b", JYCOMPANY_B }, + { "jyc_c", JYCOMPANY_C }, + { "tek90", JYCOMPANY_A }, + { "sa9602b", SACHEN_SA9602B }, + { "unl_shero", SACHEN_SHERO }, + { "mmalee2", UNL_MMALEE }, + { "unl_2708", UNL_2708 }, + { "unl_lh10", UNL_LH10 }, + { "unl_lh32", UNL_LH32 }, + { "unl_lh53", UNL_LH53 }, + { "unl_ac08", UNL_AC08 }, + { "unl_bb", UNL_BB }, + { "unl_malisb", UNL_MALISB }, + { "sgpipe", BTL_SHUIGUAN }, + { "unl_whero", UNL_WORLDHERO }, + { "unl_43272", UNL_43272 }, + { "tf1201", UNL_TF1201 }, + { "unl_cfight", UNL_CITYFIGHT }, + { "nocash_nochr", NOCASH_NOCHR }, + { "nes_action53", BTL_ACTION53 }, + { "nes_2a03pur", BTL_2A03_PURITANS }, + { "ffe3", FFE3_BOARD }, + { "ffe4", FFE4_BOARD }, + { "ffe8", FFE8_BOARD }, + { "8237a", UNSUPPORTED_BOARD }, + { "ninjaryu", UNSUPPORTED_BOARD }, + { "unl_dance", UNSUPPORTED_BOARD }, + { "bmc_hik_kof", UNSUPPORTED_BOARD }, + { "onebus", UNSUPPORTED_BOARD }, + { "coolboy", UNSUPPORTED_BOARD }, + { "btl_900218", UNSUPPORTED_BOARD }, // pirate The Lord of King, to be emulated soon + { "a9746", UNSUPPORTED_BOARD }, + { "dance2k", UNSUPPORTED_BOARD }, + { "pec586", UNSUPPORTED_BOARD }, + { "test", TEST_BOARD }, + { "unknown", UNKNOWN_BOARD } // a few pirate dumps uses the wrong mapper... +}; + +static const nes_pcb *nes_pcb_lookup( const char *slot ) +{ + for (int i = 0; i < ARRAY_LENGTH(pcb_list); i++) + { + if (!core_stricmp(pcb_list[i].slot_opt, slot)) + return &pcb_list[i]; + } + return NULL; +} + +static const nes_pcb *nes_id_lookup( int id ) +{ + for (int i = 0; i < ARRAY_LENGTH(pcb_list); i++) + { + if (pcb_list[i].pcb_id == id) + return &pcb_list[i]; + } + return NULL; +} + +int nes_cart_slot_device::nes_get_pcb_id( const char *slot ) +{ + const nes_pcb *pcb = nes_pcb_lookup(slot); + + if (pcb == NULL) + fatalerror("Unimplemented PCB type %s\n", slot); + + return pcb->pcb_id; +} + + +const char * nes_cart_slot_device::nes_get_slot( int pcb_id ) +{ + const nes_pcb *pcb = nes_id_lookup(pcb_id); + + if (pcb == NULL) + fatalerror("Unimplemented PCB ID %d\n", pcb_id); + + return pcb->slot_opt; +} + + +/************************************************************* + + nes_pcb_reset + + Resets the mmc bankswitch areas to their defaults. + It returns a value "err" that indicates if it was + successful. Possible values for err are: + + 0 = success + 1 = no pcb found + 2 = pcb not supported + + *************************************************************/ + +struct nes_cart_lines +{ + const char *tag; + int line; +}; + +static const struct nes_cart_lines nes_cart_lines_table[] = +{ + { "PRG A0", 0 }, + { "PRG A1", 1 }, + { "PRG A2", 2 }, + { "PRG A3", 3 }, + { "PRG A4", 4 }, + { "PRG A5", 5 }, + { "PRG A6", 6 }, + { "PRG A7", 7 }, + { "CHR A10", 10 }, + { "CHR A11", 11 }, + { "CHR A12", 12 }, + { "CHR A13", 13 }, + { "CHR A14", 14 }, + { "CHR A15", 15 }, + { "CHR A16", 16 }, + { "CHR A17", 17 }, + { "NC", 127 }, + { 0 } +}; + +static int nes_cart_get_line( const char *feature ) +{ + const struct nes_cart_lines *nes_line = &nes_cart_lines_table[0]; + + if (feature == NULL) + return 128; + + while (nes_line->tag) + { + if (strcmp(nes_line->tag, feature) == 0) + break; + + nes_line++; + } + + return nes_line->line; +} + +void nes_cart_slot_device::call_load_pcb() +{ + UINT32 vram_size = 0, prgram_size = 0, battery_size = 0, mapper_sram_size = 0; + // SETUP step 1: getting PRG, VROM, VRAM sizes + UINT32 prg_size = get_software_region_length("prg"); + UINT32 vrom_size = get_software_region_length("chr"); + vram_size = get_software_region_length("vram"); + vram_size += get_software_region_length("vram2"); + + // validate the xml fields + if (!prg_size) + fatalerror("No PRG entry for this software! Please check if the xml list got corrupted\n"); + if (prg_size < 0x8000) + fatalerror("PRG entry is too small! Please check if the xml list got corrupted\n"); + + // SETUP step 2: getting PCB and other settings + if (get_feature("slot")) + m_pcb_id = nes_get_pcb_id(get_feature("slot")); + else + m_pcb_id = NO_BOARD; + + // SETUP step 3: storing the info needed for emulation + if (get_software_region("bwram") != NULL) + battery_size = get_software_region_length("bwram"); + + if (get_software_region("wram") != NULL) + prgram_size = get_software_region_length("wram"); + + if (get_feature("mirroring")) + { + const char *mirroring = get_feature("mirroring"); + if (!strcmp(mirroring, "horizontal")) + m_cart->set_mirroring(PPU_MIRROR_HORZ); + if (!strcmp(mirroring, "vertical")) + m_cart->set_mirroring(PPU_MIRROR_VERT); + if (!strcmp(mirroring, "high")) + m_cart->set_mirroring(PPU_MIRROR_HIGH); + if (!strcmp(mirroring, "low")) + m_cart->set_mirroring(PPU_MIRROR_LOW); + if (!strcmp(mirroring, "4screen")) + { + // A few boards uses 4-screen mirroring: Gauntlet (DDROM or TRR1ROM or Tengen 800004), + // Rad Racer II (TVROM), and Napoleon Senki (IREM LROG017 with 74*161/161/21/138) + m_cart->set_four_screen_vram(TRUE); + m_cart->set_mirroring(PPU_MIRROR_4SCREEN); + } + if (!strcmp(mirroring, "pcb_controlled")) + { + // A few boards have variants with hardcoded mirroring and variants with mapper + // controlled mirroring. We use a variable to avoid the need of dupe devices. + // See e.g. HES 6-in-1 vs other HES games, Irem Major League vs other G-101 games, + // Sunsoft-2 Shanghai vs Mito Koumon, Camerica BF9093 games vs BF9097 games, etc. + // Boards where all games control mirroring do not make real use of this. + m_cart->set_pcb_ctrl_mirror(TRUE); + } + } + + /* Check for pins in specific boards which require them */ + if (m_pcb_id == STD_CNROM) + { + int mask = 0, state = 0; + + if (get_feature("chr-pin26") != NULL) + { + mask |= 0x01; + state |= !strcmp(get_feature("chr-pin26"), "CE") ? 0x01 : 0; + } + if (get_feature("chr-pin27") != NULL) + { + mask |= 0x02; + state |= !strcmp(get_feature("chr-pin27"), "CE") ? 0x02 : 0; + } + + m_cart->set_ce(mask, state); + } + + if (m_pcb_id == TAITO_X1_005 && get_feature("x1-pin17") != NULL && get_feature("x1-pin31") != NULL) + { + if (!strcmp(get_feature("x1-pin17"), "CIRAM A10") && !strcmp(get_feature("x1-pin31"), "NC")) + m_cart->set_x1_005_alt(TRUE); + } + + if (m_pcb_id == KONAMI_VRC2) + { + m_cart->set_vrc_lines(nes_cart_get_line(get_feature("vrc2-pin3")), + nes_cart_get_line(get_feature("vrc2-pin4")), + (nes_cart_get_line(get_feature("vrc2-pin21")) != 10) ? 1 : 0); +// osd_printf_error("VRC-2, pin3: A%d, pin4: A%d, pin21: %d\n", nes_cart_get_line(get_feature("vrc2-pin3")), nes_cart_get_line(get_feature("vrc2-pin4")), +// nes_cart_get_line(get_feature("vrc2-pin21"))); + } + + if (m_pcb_id == KONAMI_VRC4) + { + m_cart->set_vrc_lines(nes_cart_get_line(get_feature("vrc4-pin3")), + nes_cart_get_line(get_feature("vrc4-pin4")), + 0); +// osd_printf_error("VRC-4, pin3: A%d, pin4: A%d\n", nes_cart_get_line(get_feature("vrc4-pin3"), nes_cart_get_line(get_feature("vrc4-pin4")); + } + + if (m_pcb_id == KONAMI_VRC6) + { + m_cart->set_vrc_lines(nes_cart_get_line(get_feature("vrc6-pin9")), + nes_cart_get_line(get_feature("vrc6-pin10")), + 0); +// osd_printf_error("VRC-6, pin9: A%d, pin10: A%d\n", nes_cart_get_line(get_feature("vrc6-pin9"), nes_cart_get_line(get_feature("vrc6-pin10")); + } + + if (m_pcb_id == STD_HKROM || m_pcb_id == TAITO_X1_017) + mapper_sram_size = m_cart->get_mapper_sram_size(); + + if (m_pcb_id == TAITO_X1_005 || m_pcb_id == NAMCOT_163) + { + if (get_feature("batt")) + mapper_sram_size = m_cart->get_mapper_sram_size(); + } + + + // pirate variants of boards with bus conflict are often not suffering from it + // and actually games glitch if bus conflict is emulated... + if (get_feature("bus_conflict") && !strcmp(get_feature("bus_conflict"), "no")) + m_cart->set_bus_conflict(FALSE); + + + // SETUP step 4: logging what we have found + logerror("Loaded game from softlist:\n"); + logerror("-- PCB: %s", get_feature("pcb")); + if (m_pcb_id == UNSUPPORTED_BOARD) + logerror(" (currently not supported by MESS)"); + logerror("\n-- PRG 0x%x (%d x 16k chunks)\n", prg_size, prg_size / 0x4000); + logerror("-- VROM 0x%x (%d x 8k chunks)\n", vrom_size, vrom_size / 0x2000); + logerror("-- VRAM 0x%x (%d x 8k chunks)\n", vram_size, vram_size / 0x2000); + logerror("-- PRG NVWRAM: %d\n", battery_size + mapper_sram_size); + logerror("-- PRG WRAM: %d\n", prgram_size); + + // SETUP steps 5/6: allocate pointers for PRG/VROM and load the data! + m_cart->prg_alloc(prg_size, tag()); + memcpy(m_cart->get_prg_base(), get_software_region("prg"), prg_size); + if (vrom_size) + { + m_cart->vrom_alloc(vrom_size, tag()); + memcpy(m_cart->get_vrom_base(), get_software_region("chr"), vrom_size); + } + + // SETUP steps 7: allocate the remaining pointer, when needed + if (vram_size) + m_cart->vram_alloc(vram_size); + if (prgram_size) + m_cart->prgram_alloc(prgram_size); + + // also nes_smb2j_device needs WRAM initialized to 0xff? check! + if (m_pcb_id == UNL_SMB2J) + memset(m_cart->get_prgram_base(), 0xff, prgram_size); + + // Attempt to load a battery file for this ROM + // A few boards have internal RAM with a battery (MMC6, Taito X1-005 & X1-017, etc.) + if (battery_size || mapper_sram_size) + { + UINT32 tot_size = battery_size + mapper_sram_size; + dynamic_buffer temp_nvram(tot_size); + + // some games relies on specific battery patterns to work + // (e.g. Silva Saga does not work with SRAM fully initialized to 0x00) + // and we use the info from xml here to prepare a default NVRAM + dynamic_buffer default_nvram(tot_size); + if (battery_size) + memcpy(&default_nvram[0], get_software_region("bwram"), battery_size); + if (mapper_sram_size) + memset(&default_nvram[battery_size], 0, mapper_sram_size); + + // load battery (using default if no battery exists) + battery_load(&temp_nvram[0], tot_size, &default_nvram[0]); + + // copy battery into PCB arrays + if (battery_size) + { + m_cart->battery_alloc(battery_size); + memcpy(m_cart->get_battery_base(), &temp_nvram[0], battery_size); + } + if (mapper_sram_size) + memcpy(m_cart->get_mapper_sram_base(), &temp_nvram[battery_size], mapper_sram_size); + } +} diff --git a/src/devices/bus/nes/nes_slot.c b/src/devices/bus/nes/nes_slot.c new file mode 100644 index 00000000000..ec1b1f5f4af --- /dev/null +++ b/src/devices/bus/nes/nes_slot.c @@ -0,0 +1,1053 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + Nintendo NES/FC cart emulation + (through slot devices) + + The driver exposes address ranges + 0x4100-0x5fff to read_l/write_l + 0x6000-0x7fff to read_m/write_m (here are *usually* installed NVRAM & WRAM, if any) + 0x8000-0xffff to write_h (reads are directed to 4 x 8K PRG banks) + Default implementations of these handlers are available here, to be rewritten by PCB-specific ones when needed. + + Additional handlers are available, but have to be manually installed at machine_start + * read_ex/write_ex for address range 0x4020-0x40ff + * read_h for address range 0x8000-0xffff when a cart does some protection or address scramble before reading ROM + + PPU exposes address ranges + 0x0000-0x1fff to chr_r/chr_w + 0x2000-0x3eff to nt_r/nt_w + Default implementations of these handlers are available here, to be rewritten by PCB-specific ones when needed. + + Plus a few of latch functions are available: ppu_latch (see MMC2), hblank_irq and scanline_irq (see e.g. MMC3), + but these might be subject to future changes when the PPU is revisited. + + Notes: + - Differently from later systems (like SNES or MD), it is uncommon to find PRG ROMs of NES games which are not a + power of 2K, so we do not perform any mirroring by default. + A bunch of pcb types, though, come with 1.5MB of PRG (some Waixing translations) or with multiple PRG chips + having peculiar size (32K + 16K, 32K + 8K, 32K + 2K). Hence, if such a configuration is detected, we provide + a m_prg_bank_map array to handle internally PRG mirroring up to the next power of 2K, as long as the size is + a multiple of 8K (i.e. the unit chunk for standard PRG). + For the case of PRG chips which are not-multiple of 8K (e.g. UNL-MARIO2-MALEE pcb), the handling has to be + handled in the pcb-specific code! + - Our open bus emulation is very sketchy, by simply returning the higher 8bits of the accessed address. This seems + enough for most games (only two sets have issues with this). A slightly better implementation is almost ready + to fix these two remaining cases, but I plan to revisit the whole implementation in an accurate way at a later + stage + - Bus conflict is implemented based on latest tests by Blargg. There is some uncertainty about AxROM behavior + (some AOROM pcbs suffers from bus conflict, some do not... since no AOROM game is known to glitch due to lack + of bus conflict it seems safe to emulate the board without bus conflict, but eventually it would be good to + differentiate the real variants) + + + Many information about the mappers/pcbs come from the wonderful doc written by Disch. + Current info (when used) are based on v0.6.1 of his docs. + You can find the latest version of the doc at http://www.romhacking.net/docs/362/ + + A lot of details have been based on the researches carried on at NesDev forums (by Blargg, Quietust and many more) + and collected on the NesDev Wiki http://wiki.nesdev.com/ + + Particular thanks go to + - Martin Freij for his work on NEStopia + - Cah4e3 for his efforts on FCEUMM and the reverse engineering of pirate boards + - BootGod, lidnariq and naruko for the PCB tests which made possible + + + ***********************************************************************************************************/ + +/***************************************************************************************** + + A few Mappers suffer of hardware conflict: original dumpers have used the same mapper number for more than + a kind of boards. In these cases (and only in these cases) we exploit nes.hsi to set up accordingly + emulation. Games which requires this hack are the following: + * 032 - Major League needs hardwired mirroring (missing windows and glitched field in top view, otherwise) + * 034 - Impossible Mission II is not like BxROM games (it writes to 0x7ffd-0x7fff, instead of 0x8000). It is still + unplayable though (see above) + * 071 - Fire Hawk is different from other Camerica games (no hardwired mirroring). Without crc_hack no helicopter graphics + * 078 - Cosmo Carrier needs a different mirroring than Holy Diver + * 113 - HES 6-in-1 requires mirroring (check Bookyman playfield), while other games break with this (check AV Soccer) + * 153 - Famicom Jump II uses a different board (or the same in a very different way) + * 242 - DQ8 has no mirroring (missing graphics is due to other reasons though) + + crc_hacks have been added also to handle a few wiring settings which would require submappers: + * CHR protection pins for mapper 185 + * VRC-2, VRC-4 and VRC-6 line wiring + + Remember that the MMC # does not equal the mapper #. In particular, Mapper 4 is + in fact MMC3, Mapper 9 is MMC2 and Mapper 10 is MMC4. Makes perfect sense, right? + + ****************************************************************************************/ + + +#include "emu.h" +#include "hashfile.h" +#include "nes_slot.h" + +#define NES_BATTERY_SIZE 0x2000 + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type NES_CART_SLOT = &device_creator; + + +//************************************************************************** +// NES cartridges Interface +//************************************************************************** + +//------------------------------------------------- +// device_nes_cart_interface - constructor +//------------------------------------------------- + +device_nes_cart_interface::device_nes_cart_interface(const machine_config &mconfig, device_t &device) + : device_slot_card_interface(mconfig, device), + m_prg(NULL), + m_vrom(NULL), + m_ciram(NULL), + m_prg_size(0), + m_vrom_size(0), + m_mapper_sram(NULL), + m_mapper_sram_size(0), + m_ce_mask(0), + m_ce_state(0), + m_vrc_ls_prg_a(0), + m_vrc_ls_prg_b(0), + m_vrc_ls_chr(0), + m_mirroring(PPU_MIRROR_NONE), + m_pcb_ctrl_mirror(FALSE), + m_four_screen_vram(FALSE), + m_has_trainer(FALSE), + m_x1_005_alt_mirroring(FALSE), + m_bus_conflict(TRUE), + m_open_bus(0), + m_prg_chunks(0), + m_prg_mask(0xffff), + m_chr_source(CHRRAM), + m_vrom_chunks(0), + m_vram_chunks(0) +{ +} + + +//------------------------------------------------- +// ~device_nes_cart_interface - destructor +//------------------------------------------------- + +device_nes_cart_interface::~device_nes_cart_interface() +{ +} + +//------------------------------------------------- +// pointer allocators +//------------------------------------------------- + +void device_nes_cart_interface::prg_alloc(size_t size, const char *tag) +{ + if (m_prg == NULL) + { + m_prg = device().machine().memory().region_alloc(std::string(tag).append(NESSLOT_PRGROM_REGION_TAG).c_str(), size, 1, ENDIANNESS_LITTLE)->base(); + m_prg_size = size; + m_prg_chunks = size / 0x4000; + if (size % 0x2000) + { + // A few pirate carts have PRG made of 32K + 2K or some weird similar config + // in this case we treat the banking as if this 'extra' PRG is not present and + // the pcb code has to handle it by accessing directly m_prg! + printf("Warning! The loaded PRG has size not a multiple of 8KB (0x%X)\n", (UINT32)size); + m_prg_chunks--; + } + + m_prg_mask = ((m_prg_chunks << 1) - 1); + +// printf("first mask %x!\n", m_prg_mask); + if ((m_prg_chunks << 1) & m_prg_mask) + { + int mask_bits = 0, temp = (m_prg_chunks << 1), mapsize; + // contrary to what happens with later systems, like e.g. SNES or MD, + // only half a dozen of NES carts have PRG which is not a power of 2 + // so we use this bank_map only as an exception +// printf("uneven rom!\n"); + + // 1. redefine mask as (next power of 2)-1 + for (; temp; ) + { + mask_bits++; + temp >>= 1; + } + m_prg_mask = (1 << mask_bits) - 1; +// printf("new mask %x!\n", m_prg_mask); + mapsize = (1 << mask_bits)/2; + + // 2. create a bank_map for banks in the range mask/2 -> mask + m_prg_bank_map.resize(mapsize); + + // 3. fill the bank_map accounting for mirrors + int j; + for (j = mapsize; j < (m_prg_chunks << 1); j++) + m_prg_bank_map[j - mapsize] = j; + + while (j % mapsize) + { + int k = 0, repeat_banks; + while ((j % (mapsize >> k)) && k < mask_bits) + k++; + repeat_banks = j % (mapsize >> (k - 1)); + for (int l = 0; l < repeat_banks; l++) + m_prg_bank_map[(j - mapsize) + l] = m_prg_bank_map[(j - mapsize) + l - repeat_banks]; + j += repeat_banks; + } + + // check bank map! +// for (int i = 0; i < mapsize; i++) +// { +// printf("bank %3d = %3d\t", i, m_prg_bank_map[i]); +// if ((i%8) == 7) +// printf("\n"); +// } + } + } +} + +void device_nes_cart_interface::vrom_alloc(size_t size, const char *tag) +{ + if (m_vrom == NULL) + { + std::string tempstring(tag); + tempstring.append(NESSLOT_CHRROM_REGION_TAG); + m_vrom = device().machine().memory().region_alloc(tempstring.c_str(), size, 1, ENDIANNESS_LITTLE)->base(); + m_vrom_size = size; + m_vrom_chunks = size / 0x2000; + } +} + +void device_nes_cart_interface::prgram_alloc(size_t size) +{ + m_prgram.resize(size); +} + +void device_nes_cart_interface::vram_alloc(size_t size) +{ + m_vram.resize(size); + m_vram_chunks = size / 0x2000; +} + +void device_nes_cart_interface::battery_alloc(size_t size) +{ + m_battery.resize(size); +} + + +//------------------------------------------------- +// PRG helpers +//------------------------------------------------- + +inline int device_nes_cart_interface::prg_8k_bank_num(int bank_8k) +{ + if (m_prg_mask == ((m_prg_chunks << 1) - 1)) + return bank_8k & m_prg_mask; + + // only a few pirate games (less than a dozen) have PRG which is not power of 2 + // so we treat it here separately, rather than forcing all games to use m_prg_bank_map + + // case 1: if we are accessing a bank before the end of the image, just return that bank + if (bank_8k < ((m_prg_chunks << 1) - 1)) + return bank_8k; + + // case 2: otherwise return a mirror using the bank_map! +// UINT8 temp = bank_8k; + bank_8k &= m_prg_mask; + bank_8k -= (m_prg_mask/2 + 1); +// printf("bank: accessed %x (top: %x), returned %x\n", temp, (m_prg_chunks << 1) - 1, m_prg_bank_map[bank_8k]); + return m_prg_bank_map[bank_8k]; +} + +inline void device_nes_cart_interface::update_prg_banks(int prg_bank_start, int prg_bank_end) +{ + for (int prg_bank = prg_bank_start; prg_bank <= prg_bank_end; prg_bank++) + { + assert(prg_bank >= 0); + assert(prg_bank < ARRAY_LENGTH(m_prg_bank)); + assert(prg_bank < ARRAY_LENGTH(m_prg_bank_mem)); + + m_prg_bank_mem[prg_bank]->set_entry(m_prg_bank[prg_bank]); + } +} + +void device_nes_cart_interface::prg32(int bank) +{ + /* if there is only 16k PRG, return */ + if (!(m_prg_chunks >> 1)) + return; + + /* assumes that bank references a 32k chunk */ + bank = prg_8k_bank_num(bank * 4); + + m_prg_bank[0] = bank + 0; + m_prg_bank[1] = bank + 1; + m_prg_bank[2] = bank + 2; + m_prg_bank[3] = bank + 3; + update_prg_banks(0, 3); +} + +void device_nes_cart_interface::prg16_89ab(int bank) +{ + /* assumes that bank references a 16k chunk */ + bank = prg_8k_bank_num(bank * 2); + + m_prg_bank[0] = bank + 0; + m_prg_bank[1] = bank + 1; + update_prg_banks(0, 1); +} + +void device_nes_cart_interface::prg16_cdef(int bank) +{ + /* assumes that bank references a 16k chunk */ + bank = prg_8k_bank_num(bank * 2); + + m_prg_bank[2] = bank + 0; + m_prg_bank[3] = bank + 1; + update_prg_banks(2, 3); +} + +void device_nes_cart_interface::prg8_89(int bank) +{ + /* assumes that bank references an 8k chunk */ + bank = prg_8k_bank_num(bank); + + m_prg_bank[0] = bank; + update_prg_banks(0, 0); +} + +void device_nes_cart_interface::prg8_ab(int bank) +{ + /* assumes that bank references an 8k chunk */ + bank = prg_8k_bank_num(bank); + + m_prg_bank[1] = bank; + update_prg_banks(1, 1); +} + +void device_nes_cart_interface::prg8_cd(int bank) +{ + /* assumes that bank references an 8k chunk */ + bank = prg_8k_bank_num(bank); + + m_prg_bank[2] = bank; + update_prg_banks(2, 2); +} + +void device_nes_cart_interface::prg8_ef(int bank) +{ + /* assumes that bank references an 8k chunk */ + bank = prg_8k_bank_num(bank); + + m_prg_bank[3] = bank; + update_prg_banks(3, 3); +} + +/* We also define an additional helper to map 8k PRG-ROM to one of the banks (passed as parameter) */ +void device_nes_cart_interface::prg8_x(int start, int bank) +{ + assert(start < 4); + + /* assumes that bank references an 8k chunk */ + bank = prg_8k_bank_num(bank); + + m_prg_bank[start] = bank; + update_prg_banks(start, start); +} + +//------------------------------------------------- +// CHR helpers +//------------------------------------------------- + +inline void device_nes_cart_interface::chr_sanity_check( int source ) +{ + if (source == CHRRAM && m_vram.empty()) + fatalerror("CHRRAM bankswitch with no VRAM\n"); + + if (source == CHRROM && m_vrom == NULL) + fatalerror("CHRROM bankswitch with no VROM\n"); +} + +void device_nes_cart_interface::chr8(int bank, int source) +{ + chr_sanity_check(source); + + if (source == CHRRAM) + { + bank &= (m_vram_chunks - 1); + for (int i = 0; i < 8; i++) + { + m_chr_src[i] = source; + m_chr_orig[i] = (bank * 0x2000) + (i * 0x400); // for save state uses! + m_chr_access[i] = &m_vram[m_chr_orig[i]]; + } + } + else + { + bank &= (m_vrom_chunks - 1); + for (int i = 0; i < 8; i++) + { + m_chr_src[i] = source; + m_chr_orig[i] = (bank * 0x2000) + (i * 0x400); // for save state uses! + m_chr_access[i] = &m_vrom[m_chr_orig[i]]; + } + } +} + +void device_nes_cart_interface::chr4_x(int start, int bank, int source) +{ + chr_sanity_check(source); + + if (source == CHRRAM) + { + bank &= ((m_vram_chunks << 1) - 1); + for (int i = 0; i < 4; i++) + { + m_chr_src[i + start] = source; + m_chr_orig[i + start] = (bank * 0x1000) + (i * 0x400); // for save state uses! + m_chr_access[i + start] = &m_vram[m_chr_orig[i + start]]; + } + } + else + { + bank &= ((m_vrom_chunks << 1) - 1); + for (int i = 0; i < 4; i++) + { + m_chr_src[i + start] = source; + m_chr_orig[i + start] = (bank * 0x1000) + (i * 0x400); // for save state uses! + m_chr_access[i + start] = &m_vrom[m_chr_orig[i + start]]; + } + } +} + +void device_nes_cart_interface::chr2_x(int start, int bank, int source) +{ + chr_sanity_check(source); + + if (source == CHRRAM) + { + bank &= ((m_vram_chunks << 2) - 1); + for (int i = 0; i < 2; i++) + { + m_chr_src[i + start] = source; + m_chr_orig[i + start] = (bank * 0x800) + (i * 0x400); // for save state uses! + m_chr_access[i + start] = &m_vram[m_chr_orig[i + start]]; + } + } + else + { + bank &= ((m_vrom_chunks << 2) - 1); + for (int i = 0; i < 2; i++) + { + m_chr_src[i + start] = source; + m_chr_orig[i + start] = (bank * 0x800) + (i * 0x400); // for save state uses! + m_chr_access[i + start] = &m_vrom[m_chr_orig[i + start]]; + } + } +} + +void device_nes_cart_interface::chr1_x(int start, int bank, int source) +{ + chr_sanity_check(source); + + if (source == CHRRAM) + { + bank &= ((m_vram_chunks << 3) - 1); + m_chr_src[start] = source; + m_chr_orig[start] = (bank * 0x400); // for save state uses! + m_chr_access[start] = &m_vram[m_chr_orig[start]]; + } + else + { + bank &= ((m_vrom_chunks << 3) - 1); + m_chr_src[start] = source; + m_chr_orig[start] = (bank * 0x400); // for save state uses! + m_chr_access[start] = &m_vrom[m_chr_orig[start]]; + } +} + +//------------------------------------------------- +// NT & Mirroring helpers +//------------------------------------------------- + +void device_nes_cart_interface::set_nt_page(int page, int source, int bank, int writable) +{ + UINT8* base_ptr; + + switch (source) + { + case CART_NTRAM: + base_ptr = &m_ext_ntram[0]; + break; + case VROM: + bank &= ((m_vrom_chunks << 3) - 1); + base_ptr = m_vrom; + break; + case EXRAM: + case MMC5FILL: + base_ptr = NULL; + break; + case CIRAM: + default: + base_ptr = m_ciram; + break; + } + + page &= 3; /* mask down to the 4 logical pages */ + m_nt_src[page] = source; + + if (base_ptr) + { + m_nt_orig[page] = bank * 0x400; + m_nt_access[page] = base_ptr + m_nt_orig[page]; + } + + m_nt_writable[page] = writable; +} + +void device_nes_cart_interface::set_nt_mirroring(int mirroring) +{ + /* setup our videomem handlers based on mirroring */ + switch (mirroring) + { + case PPU_MIRROR_VERT: + set_nt_page(0, CIRAM, 0, 1); + set_nt_page(1, CIRAM, 1, 1); + set_nt_page(2, CIRAM, 0, 1); + set_nt_page(3, CIRAM, 1, 1); + break; + + case PPU_MIRROR_HORZ: + set_nt_page(0, CIRAM, 0, 1); + set_nt_page(1, CIRAM, 0, 1); + set_nt_page(2, CIRAM, 1, 1); + set_nt_page(3, CIRAM, 1, 1); + break; + + case PPU_MIRROR_HIGH: + set_nt_page(0, CIRAM, 1, 1); + set_nt_page(1, CIRAM, 1, 1); + set_nt_page(2, CIRAM, 1, 1); + set_nt_page(3, CIRAM, 1, 1); + break; + + case PPU_MIRROR_LOW: + set_nt_page(0, CIRAM, 0, 1); + set_nt_page(1, CIRAM, 0, 1); + set_nt_page(2, CIRAM, 0, 1); + set_nt_page(3, CIRAM, 0, 1); + break; + + case PPU_MIRROR_4SCREEN: + if (m_ext_ntram.empty()) fatalerror("4-screen mirroring without on-cart NTRAM!\n"); + set_nt_page(0, CART_NTRAM, 0, 1); + set_nt_page(1, CART_NTRAM, 1, 1); + set_nt_page(2, CART_NTRAM, 2, 1); + set_nt_page(3, CART_NTRAM, 3, 1); + break; + + case PPU_MIRROR_NONE: + default: + set_nt_page(0, CIRAM, 0, 1); + set_nt_page(1, CIRAM, 0, 1); + set_nt_page(2, CIRAM, 1, 1); + set_nt_page(3, CIRAM, 1, 1); + break; + } +} + +//------------------------------------------------- +// Other helpers +//------------------------------------------------- + +// Helper function for the few mappers reading from 0x8000-0xffff for protection +// so that they can access the ROM after the protection handling (which overwrites +// the memory banks) +UINT8 device_nes_cart_interface::hi_access_rom(UINT32 offset) +{ + int bank = (offset & 0x6000) >> 13; + return m_prg[m_prg_bank[bank] * 0x2000 + (offset & 0x1fff)]; +} + +// Helper function for the few mappers subject to bus conflict at write. +// Tests by blargg showed that in many of the boards suffering of CPU/ROM +// conflicts the behaviour can be accurately emulated by writing not the +// original data, but data & rom[offset] +UINT8 device_nes_cart_interface::account_bus_conflict(UINT32 offset, UINT8 data) +{ + // pirate variants of boards subject to bus conflict are often not subject to it + // so we allow to set m_bus_conflict to FALSE at loading time when necessary + if (m_bus_conflict) + return data & hi_access_rom(offset); + else + return data; +} + + +//------------------------------------------------- +// PPU accessors +//------------------------------------------------- + +WRITE8_MEMBER(device_nes_cart_interface::chr_w) +{ + int bank = offset >> 10; + + if (m_chr_src[bank] == CHRRAM) + m_chr_access[bank][offset & 0x3ff] = data; +} + +READ8_MEMBER(device_nes_cart_interface::chr_r) +{ + int bank = offset >> 10; + return m_chr_access[bank][offset & 0x3ff]; +} + + +WRITE8_MEMBER(device_nes_cart_interface::nt_w) +{ + int page = ((offset & 0xc00) >> 10); + + if (!m_nt_writable[page]) + return; + + m_nt_access[page][offset & 0x3ff] = data; +} + +READ8_MEMBER(device_nes_cart_interface::nt_r) +{ + int page = ((offset & 0xc00) >> 10); + return m_nt_access[page][offset & 0x3ff]; +} + + +//------------------------------------------------- +// Base memory accessors (emulating open bus +// behaviour and/or WRAM accesses) +// Open bus emulation is defective, but it should +// be enough for the few cases known to rely on +// this (more in the comments at the top of the +// source) +//------------------------------------------------- + +READ8_MEMBER(device_nes_cart_interface::read_l) +{ + return m_open_bus; +} + +READ8_MEMBER(device_nes_cart_interface::read_m) +{ + if (!m_battery.empty()) + return m_battery[offset & (m_battery.size() - 1)]; + if (!m_prgram.empty()) + return m_prgram[offset & (m_prgram.size() - 1)]; + + return m_open_bus; +} + +WRITE8_MEMBER(device_nes_cart_interface::write_l) +{ +} + +WRITE8_MEMBER(device_nes_cart_interface::write_m) +{ + if (!m_battery.empty()) + m_battery[offset & (m_battery.size() - 1)] = data; + if (!m_prgram.empty()) + m_prgram[offset & (m_prgram.size() - 1)] = data; +} + +WRITE8_MEMBER(device_nes_cart_interface::write_h) +{ +} + + +void device_nes_cart_interface::pcb_start(running_machine &machine, UINT8 *ciram_ptr, bool cart_mounted) +{ + // HACK: to reduce tagmap lookups for PPU-related IRQs, we add a hook to the + // main NES CPU here, even if it does not belong to this device. + m_maincpu = machine.device("maincpu"); + + if (cart_mounted) // disksys expansion can arrive here without the memory banks! + { + // Setup PRG + m_prg_bank_mem[0] = machine.root_device().membank("prg0"); + m_prg_bank_mem[1] = machine.root_device().membank("prg1"); + m_prg_bank_mem[2] = machine.root_device().membank("prg2"); + m_prg_bank_mem[3] = machine.root_device().membank("prg3"); + for (int i = 0; i < 4; i++) + { + if (m_prg_bank_mem[i]) + { + m_prg_bank_mem[i]->configure_entries(0, m_prg_size / 0x2000, m_prg, 0x2000); + m_prg_bank_mem[i]->set_entry(i); + m_prg_bank[i] = i; + } + } + } + + // Setup CHR (VRAM can be present also without PRG rom) + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + chr8(0, m_chr_source); + + // Setup NT + m_ciram = ciram_ptr; + + if (m_four_screen_vram) + { + m_ext_ntram.resize(0x2000); + device().save_item(NAME(m_ext_ntram)); + } + + // at loading time we have configured m_mirroring, now setup NT pages + set_nt_mirroring(m_mirroring); + + // save the on-cart RAM pointers + if (!m_prgram.empty()) + device().save_item(NAME(m_prgram)); + if (!m_vram.empty()) + device().save_item(NAME(m_vram)); + if (!m_battery.empty()) + device().save_item(NAME(m_battery)); +} + +void device_nes_cart_interface::pcb_reg_postload(running_machine &machine) +{ + machine.save().register_postload(save_prepost_delegate(FUNC(device_nes_cart_interface::nes_banks_restore), this)); +} + +void device_nes_cart_interface::nes_banks_restore() +{ + for (int i = 0; i < 4; i++) + m_prg_bank_mem[i]->set_entry(m_prg_bank[i]); + + for (int i = 0; i < 8; i++) + chr1_x(i, m_chr_orig[i] / 0x400, m_chr_src[i]); + + for (int i = 0; i < 4; i++) + set_nt_page(i, m_nt_src[i], m_nt_orig[i] / 0x400, m_nt_writable[i]); +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// nes_cart_slot_device - constructor +//------------------------------------------------- +nes_cart_slot_device::nes_cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, NES_CART_SLOT, "NES Cartridge Slot", tag, owner, clock, "nes_cart_slot", __FILE__), + device_image_interface(mconfig, *this), + device_slot_interface(mconfig, *this), + m_crc_hack(0), + m_pcb_id(NO_BOARD), + m_must_be_loaded(1) +{ +} + +//------------------------------------------------- +// nes_cart_slot_device - destructor +//------------------------------------------------- + +nes_cart_slot_device::~nes_cart_slot_device() +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void nes_cart_slot_device::device_start() +{ + m_cart = dynamic_cast(get_card_device()); +} + +//------------------------------------------------- +// device_config_complete - perform any +// operations now that the configuration is +// complete +//------------------------------------------------- + +void nes_cart_slot_device::device_config_complete() +{ + // set brief and instance name + update_names(); +} + + +void nes_cart_slot_device::pcb_start(UINT8 *ciram_ptr) +{ + if (m_cart) + m_cart->pcb_start(machine(), ciram_ptr, exists()); +} + +void nes_cart_slot_device::pcb_reset() +{ + if (m_cart) + m_cart->pcb_reset(); +} + +/*------------------------------------------------- + call load + -------------------------------------------------*/ + + +/*------------------------------------------------- + + Load from xml list and identify the required slot device + + -------------------------------------------------*/ + +/* Include emulation of NES PCBs for softlist */ +#include "nes_pcb.inc" + + +/*------------------------------------------------- + + Load .unf files (UNIF boards) and identify the required slot device + + -------------------------------------------------*/ + +/* Include emulation of UNIF Boards for .unf files */ +#include "nes_unif.inc" + + +/*------------------------------------------------- + + Load .nes files (iNES mappers) and identify the required slot devices + + -------------------------------------------------*/ + +/* Include emulation of iNES Mappers for .nes files */ +#include "nes_ines.inc" + + +bool nes_cart_slot_device::call_load() +{ + if (m_cart) + { + if (software_entry() == NULL) + { + char magic[4]; + + /* Check first 4 bytes of the image to decide if it is UNIF or iNES */ + /* Unfortunately, many .unf files have been released as .nes, so we cannot rely on extensions only */ + fread(magic, 4); + + if ((magic[0] == 'N') && (magic[1] == 'E') && (magic[2] == 'S')) /* If header starts with 'NES' it is iNES */ + { + if (length() <= 0x10) + { + logerror("%s only contains the iNES header and no data.\n", filename()); + return IMAGE_INIT_FAIL; + } + + call_load_ines(); + } + else if ((magic[0] == 'U') && (magic[1] == 'N') && (magic[2] == 'I') && (magic[3] == 'F')) /* If header starts with 'UNIF' it is UNIF */ + { + if (length() <= 0x20) + { + logerror("%s only contains the UNIF header and no data.\n", filename()); + return IMAGE_INIT_FAIL; + } + + call_load_unif(); + } + else + { + logerror("%s is NOT a file in either iNES or UNIF format.\n", filename()); + return IMAGE_INIT_FAIL; + } + } + else + call_load_pcb(); + } + + return IMAGE_INIT_PASS; +} + + +/*------------------------------------------------- + call_unload + -------------------------------------------------*/ + +void nes_cart_slot_device::call_unload() +{ + if (m_cart) + { + if (m_cart->get_battery_size() || m_cart->get_mapper_sram_size()) + { + UINT32 tot_size = m_cart->get_battery_size() + m_cart->get_mapper_sram_size(); + dynamic_buffer temp_nvram(tot_size); + if (m_cart->get_battery_size()) + memcpy(&temp_nvram[0], m_cart->get_battery_base(), m_cart->get_battery_size()); + if (m_cart->get_mapper_sram_size()) + memcpy(&temp_nvram[m_cart->get_battery_size()], m_cart->get_mapper_sram_base(), m_cart->get_mapper_sram_size()); + + battery_save(&temp_nvram[0], tot_size); + } + } +} + + +/*------------------------------------------------- + call softlist load + -------------------------------------------------*/ + +bool nes_cart_slot_device::call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry) +{ + load_software_part_region(*this, swlist, swname, start_entry); + return TRUE; +} + +/*------------------------------------------------- + get default card software + -------------------------------------------------*/ + +void nes_cart_slot_device::get_default_card_software(std::string &result) +{ + if (open_image_file(mconfig().options())) + { + const char *slot_string = "nrom"; + UINT32 len = core_fsize(m_file); + dynamic_buffer rom(len); + + core_fread(m_file, &rom[0], len); + + if ((rom[0] == 'N') && (rom[1] == 'E') && (rom[2] == 'S')) + slot_string = get_default_card_ines(&rom[0], len); + + if ((rom[0] == 'U') && (rom[1] == 'N') && (rom[2] == 'I') && (rom[3] == 'F')) + slot_string = get_default_card_unif(&rom[0], len); + + clear(); + + result.assign(slot_string); + } + else + software_get_default_slot(result, "nrom"); +} + + +/*------------------------------------------------- + read + -------------------------------------------------*/ + +READ8_MEMBER(nes_cart_slot_device::read_l) +{ + if (m_cart) + { + UINT8 val = m_cart->read_l(space, offset); + // update open bus + m_cart->set_open_bus(((offset + 0x4100) & 0xff00) >> 8); + return val; + } + else + return 0xff; +} + +READ8_MEMBER(nes_cart_slot_device::read_m) +{ + if (m_cart) + { + UINT8 val = m_cart->read_m(space, offset); + // update open bus + m_cart->set_open_bus(((offset + 0x6000) & 0xff00) >> 8); + return val; + } + else + return 0xff; +} + +READ8_MEMBER(nes_cart_slot_device::read_h) +{ + if (m_cart) + { + UINT8 val = m_cart->read_h(space, offset); + // update open bus + m_cart->set_open_bus(((offset + 0x8000) & 0xff00) >> 8); + return val; + } + else + return 0xff; +} + +READ8_MEMBER(nes_cart_slot_device::read_ex) +{ + if (m_cart) + { + UINT8 val = m_cart->read_ex(space, offset); + // update open bus + m_cart->set_open_bus(((offset + 0x4020) & 0xff00) >> 8); + return val; + } + else + return 0xff; +} + + +/*------------------------------------------------- + write + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_cart_slot_device::write_l) +{ + if (m_cart) + { + m_cart->write_l(space, offset, data); + // update open bus + m_cart->set_open_bus(((offset + 0x4100) & 0xff00) >> 8); + } +} + +WRITE8_MEMBER(nes_cart_slot_device::write_m) +{ + if (m_cart) + { + m_cart->write_m(space, offset, data); + // update open bus + m_cart->set_open_bus(((offset + 0x6000) & 0xff00) >> 8); + } +} + +WRITE8_MEMBER(nes_cart_slot_device::write_h) +{ + if (m_cart) + { + m_cart->write_h(space, offset, data); + // update open bus + m_cart->set_open_bus(((offset + 0x8000) & 0xff00) >> 8); + } +} + +WRITE8_MEMBER(nes_cart_slot_device::write_ex) +{ + if (m_cart) + { + m_cart->write_ex(space, offset, data); + // update open bus + m_cart->set_open_bus(((offset + 0x4020) & 0xff00) >> 8); + } +} + + +//------------------------------------------------- +// partial hash function to be used by +// device_image_partialhash_func +//------------------------------------------------- + +void nes_partialhash(hash_collection &dest, const unsigned char *data, + unsigned long length, const char *functions) +{ + if (length <= 16) + return; + dest.compute(&data[16], length - 16, functions); +} diff --git a/src/devices/bus/nes/nes_slot.h b/src/devices/bus/nes/nes_slot.h new file mode 100644 index 00000000000..f959465af33 --- /dev/null +++ b/src/devices/bus/nes/nes_slot.h @@ -0,0 +1,430 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __NES_SLOT_H__ +#define __NES_SLOT_H__ + +/*************************************************************************** + TYPE DEFINITIONS + ***************************************************************************/ + +// uncomment this for *very* verbose logging of most cart accesses +//#define NES_PCB_DEBUG + +/* Boards */ +enum +{ + STD_NROM = 0, + STD_AXROM, STD_AMROM, STD_BXROM, + STD_CNROM, STD_CPROM, + STD_EXROM, STD_FXROM, STD_GXROM, + STD_HKROM, STD_PXROM, + STD_SXROM, STD_TXROM, STD_TXSROM, + STD_TKROM, STD_TQROM, + STD_UXROM, STD_UN1ROM, UXROM_CC, + HVC_FAMBASIC, NES_QJ, PAL_ZZ, STD_EVENT, + STD_SXROM_A, STD_SOROM, STD_SOROM_A, + STD_DISKSYS, + STD_NROM368,//homebrew extension of NROM! + /* Discrete components boards (by various manufacturer) */ + DIS_74X161X138, DIS_74X139X74, + DIS_74X377, DIS_74X161X161X32, + /* Active Enterprises */ + ACTENT_ACT52, + /* AGCI */ + AGCI_50282, + /* AVE */ + AVE_NINA01, AVE_NINA06, AVE_MAXI15, + /* Bandai */ + BANDAI_FJUMP2, BANDAI_PT554, + BANDAI_DATACH, BANDAI_KARAOKE, BANDAI_OEKAKIDS, + BANDAI_FCG, BANDAI_LZ93, BANDAI_LZ93EX1, BANDAI_LZ93EX2, + /* Caltron */ + CALTRON_6IN1, + /* Camerica */ + CAMERICA_BF9093, CAMERICA_BF9096, CAMERICA_ALADDIN, + CAMERICA_GOLDENFIVE, GG_NROM, + /* Dreamtech */ + DREAMTECH_BOARD, + /* Irem */ + IREM_G101, IREM_H3001, IREM_LROG017, + IREM_TAM_S1, IREM_HOLYDIVR, + /* Jaleco */ + JALECO_SS88006, JALECO_JF11, JALECO_JF13, + JALECO_JF16, JALECO_JF17, JALECO_JF17_ADPCM, + JALECO_JF19, JALECO_JF19_ADPCM, JALECO_JF23, + JALECO_JF24, JALECO_JF29, JALECO_JF33, + /* Konami */ + KONAMI_VRC1, KONAMI_VRC2, KONAMI_VRC3, + KONAMI_VRC4, KONAMI_VRC6, KONAMI_VRC7, + /* Namcot */ + NAMCOT_163, NAMCOT_175, NAMCOT_340, + NAMCOT_3425, NAMCOT_34X3, NAMCOT_3446, + /* NTDEC */ + NTDEC_ASDER, NTDEC_FIGHTINGHERO, + /* Rex Soft */ + REXSOFT_SL1632, REXSOFT_DBZ5, + /* Sachen */ + SACHEN_8259A, SACHEN_8259B, SACHEN_8259C, SACHEN_8259D, + SACHEN_SA009, SACHEN_SA0036, SACHEN_SA0037, + SACHEN_SA72007, SACHEN_SA72008, SACHEN_TCA01, + SACHEN_TCU01, SACHEN_TCU02, SACHEN_SA9602B, + SACHEN_74LS374, SACHEN_74LS374_ALT, SACHEN_SHERO, + /* Sunsoft */ + SUNSOFT_1, SUNSOFT_2, SUNSOFT_3, SUNSOFT_4, + SUNSOFT_DCS, SUNSOFT_5, SUNSOFT_FME7, + /* Taito */ + TAITO_TC0190FMC, TAITO_TC0190FMCP, + TAITO_X1_005, TAITO_X1_017, + /* Tengen */ + TENGEN_800008, TENGEN_800032, TENGEN_800037, + /* TXC */ + TXC_22211, TXC_DUMARACING, TXC_MJBLOCK, + TXC_COMMANDOS, TXC_TW, TXC_STRIKEW, + /* Multigame Carts */ + BMC_64IN1NR, BMC_190IN1, BMC_A65AS, + BMC_HIK8IN1, BMC_NOVEL1, BMC_NOVEL2, BMC_S24IN1SC03, BMC_T262, + BMC_WS, BMC_SUPERBIG_7IN1, BMC_SUPERHIK_4IN1, BMC_BALLGAMES_11IN1, + BMC_MARIOPARTY_7IN1, BMC_GOLD_7IN1, BMC_SUPER_700IN1, BMC_FAMILY_4646, + BMC_36IN1, BMC_21IN1, BMC_150IN1, BMC_35IN1, BMC_64IN1, + BMC_15IN1, BMC_SUPERHIK_300IN1, BMC_SUPERGUN_20IN1, + BMC_GOLDENCARD_6IN1, BMC_72IN1, BMC_SUPER_42IN1, BMC_76IN1, + BMC_31IN1, BMC_22GAMES, BMC_20IN1, BMC_110IN1, + BMC_70IN1, BMC_800IN1, BMC_1200IN1, + BMC_GKA, BMC_GKB, BMC_VT5201, BMC_BENSHIENG, BMC_810544, + BMC_NTD_03, BMC_G63IN1, BMC_FK23C, BMC_FK23CA, BMC_PJOY84, + BMC_POWERFUL_255, BMC_11160, BMC_G146, BMC_8157, BMC_830118C, + BMC_411120C, BMC_GOLD150, BMC_GOLD260, BMC_CH001, BMC_SUPER22, + BMC_12IN1, BMC_4IN1RESET, BMC_42IN1RESET, + /* Unlicensed */ + UNL_8237, UNL_CC21, UNL_AX5705, UNL_KOF97, UNL_KS7057, + UNL_N625092, UNL_SC127, UNL_SMB2J, UNL_T230, UNL_MMALEE, + UNL_UXROM, UNL_MK2, UNL_XIAOZY, UNL_KOF96, + UNL_SF3, UNL_RACERMATE, UNL_EDU2K, UNL_LH53, UNL_LH32, UNL_LH10, + UNL_STUDYNGAME, UNL_603_5052, UNL_H2288, UNL_2708, + UNL_MALISB, UNL_BB, UNL_AC08, UNL_A9746, UNL_WORLDHERO, + UNL_43272, UNL_TF1201, UNL_CITYFIGHT, + /* Bootleg boards */ + BTL_SMB2JA, BTL_MARIOBABY, BTL_AISENSHINICOL, BTL_TOBIDASE, + BTL_SMB2JB, BTL_09034A, BTL_SMB3, BTL_SBROS11, BTL_DRAGONNINJA, + BTL_PIKACHUY2K, BTL_SHUIGUAN, + /* Misc: these are needed to convert mappers to boards, I will sort them later */ + OPENCORP_DAOU306, HES_BOARD, SVISION16_BOARD, RUMBLESTATION_BOARD, JYCOMPANY_A, JYCOMPANY_B, JYCOMPANY_C, + MAGICSERIES_MD, KASING_BOARD, FUTUREMEDIA_BOARD, FUKUTAKE_BOARD, SOMARI_SL12, + HENGG_SRICH, HENGG_XHZS, HENGG_SHJY3, SUBOR_TYPE0, SUBOR_TYPE1, + KAISER_KS7058, KAISER_KS7032, KAISER_KS7022, KAISER_KS7017, + KAISER_KS7012, KAISER_KS7013B, KAISER_KS202, KAISER_KS7031, + CNE_DECATHLON, CNE_FSB, CNE_SHLZ, CONY_BOARD, YOKO_BOARD, + RCM_GS2015, RCM_GS2004, RCM_GS2013, RCM_TF9IN1, RCM_3DBLOCK, + WAIXING_TYPE_A, WAIXING_TYPE_A1, WAIXING_TYPE_B, WAIXING_TYPE_C, WAIXING_TYPE_D, + WAIXING_TYPE_E, WAIXING_TYPE_F, WAIXING_TYPE_G, WAIXING_TYPE_H, WAIXING_TYPE_H1, + WAIXING_TYPE_I, WAIXING_TYPE_J, WAIXING_FS304, + WAIXING_SGZLZ, WAIXING_SGZ, WAIXING_WXZS, WAIXING_SECURITY, WAIXING_SH2, + WAIXING_DQ8, WAIXING_FFV, WAIXING_WXZS2, SUPERGAME_LIONKING, SUPERGAME_BOOGERMAN, + KAY_BOARD, HOSENKAN_BOARD, NITRA_TDA, GOUDER_37017, NANJING_BOARD, + WHIRLWIND_2706, + NOCASH_NOCHR, // homebrew PCB design which uses NTRAM for CHRRAM + BTL_ACTION53, // homebrew PCB for homebrew multicarts + BTL_2A03_PURITANS, // homebrew PCB + /* FFE boards, for mappers 6, 8, 17 */ + FFE3_BOARD, FFE4_BOARD, FFE8_BOARD, TEST_BOARD, + /* Unsupported (for place-holder boards, with no working emulation) & no-board (at init) */ + UNSUPPORTED_BOARD, UNKNOWN_BOARD, NO_BOARD +}; + + +#define CHRROM 0 +#define CHRRAM 1 + + +#define CIRAM 0 +#define VROM 1 +#define EXRAM 2 +#define MMC5FILL 3 +#define CART_NTRAM 4 + + +#define PPU_MIRROR_NONE 0 +#define PPU_MIRROR_VERT 1 +#define PPU_MIRROR_HORZ 2 +#define PPU_MIRROR_HIGH 3 +#define PPU_MIRROR_LOW 4 +#define PPU_MIRROR_4SCREEN 5 + + +// ======================> device_nes_cart_interface + +class device_nes_cart_interface : public device_slot_card_interface +{ +public: + // construction/destruction + device_nes_cart_interface(const machine_config &mconfig, device_t &device); + virtual ~device_nes_cart_interface(); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_l); + virtual DECLARE_READ8_MEMBER(read_m); + virtual DECLARE_READ8_MEMBER(read_h) { return 0xff; } + virtual DECLARE_READ8_MEMBER(read_ex) { return 0xff; } + virtual DECLARE_WRITE8_MEMBER(write_l); + virtual DECLARE_WRITE8_MEMBER(write_m); + virtual DECLARE_WRITE8_MEMBER(write_h); + virtual DECLARE_WRITE8_MEMBER(write_ex) { } + + virtual DECLARE_READ8_MEMBER(chr_r); + virtual DECLARE_WRITE8_MEMBER(chr_w); + virtual DECLARE_READ8_MEMBER(nt_r); + virtual DECLARE_WRITE8_MEMBER(nt_w); + + // hack until disk system is made modern! + virtual void disk_flip_side() { } + + void prg_alloc(size_t size, const char *tag); + void vrom_alloc(size_t size, const char *tag); + void prgram_alloc(size_t size); + void vram_alloc(size_t size); + void battery_alloc(size_t size); + + int get_mirroring() { return m_mirroring; } + void set_mirroring(int val) { m_mirroring = val; } + bool get_pcb_ctrl_mirror() { return m_pcb_ctrl_mirror; } + void set_pcb_ctrl_mirror(bool val) { m_pcb_ctrl_mirror = val; } + bool get_four_screen_vram() { return m_four_screen_vram; } + void set_four_screen_vram(bool val) { m_four_screen_vram = val; } + bool get_trainer() { return m_has_trainer; } + void set_trainer(bool val) { m_has_trainer = val; } + + void set_ce(int mask, int state) { m_ce_mask = mask; m_ce_state = state; } + void set_vrc_lines(int PRG_A, int PRG_B, int CHR) { m_vrc_ls_prg_a = PRG_A; m_vrc_ls_prg_b = PRG_B; m_vrc_ls_chr = CHR; } + void set_x1_005_alt(bool val) { m_x1_005_alt_mirroring = val; } + void set_bus_conflict(bool val) { m_bus_conflict = val; } + void set_open_bus(UINT8 val) { m_open_bus = val; } + + UINT8* get_prg_base() { return m_prg; } + UINT8* get_prgram_base() { return &m_prgram[0]; } + UINT8* get_vrom_base() { return m_vrom; } + UINT8* get_vram_base() { return &m_vram[0]; } + UINT8* get_battery_base() { return &m_battery[0]; } + UINT8* get_mapper_sram_base() { return m_mapper_sram; } + + UINT32 get_prg_size() { return m_prg_size; } + UINT32 get_prgram_size() { return m_prgram.size(); } + UINT32 get_vrom_size() { return m_vrom_size; } + UINT32 get_vram_size() { return m_vram.size(); } + UINT32 get_battery_size() { return m_battery.size(); } + UINT32 get_mapper_sram_size() { return m_mapper_sram_size; } + + virtual void ppu_latch(offs_t offset) {} + virtual void hblank_irq(int scanline, int vblank, int blanked) {} + virtual void scanline_irq(int scanline, int vblank, int blanked) {} + + virtual void pcb_reset() {} // many pcb expect specific PRG/CHR banking at start + virtual void pcb_start(running_machine &machine, UINT8 *ciram_ptr, bool cart_mounted); + void pcb_reg_postload(running_machine &machine); + void nes_banks_restore(); + + UINT8 hi_access_rom(UINT32 offset); // helper ROM access for a bunch of PCB reading 0x8000-0xffff for protection too + UINT8 account_bus_conflict(UINT32 offset, UINT8 data); + +protected: + + // internal state + UINT8 *m_prg; + UINT8 *m_vrom; + UINT8 *m_ciram; + dynamic_buffer m_prgram; + dynamic_buffer m_vram; + dynamic_buffer m_battery; + UINT32 m_prg_size; + UINT32 m_vrom_size; + + // HACK: to reduce tagmap lookups for PPU-related IRQs, we add a hook to the + // main NES CPU here, even if it does not belong to this device. + cpu_device *m_maincpu; + + // these are specific of some boards but must be accessible from the driver + // E.g. additional save ram for HKROM, X1-005 & X1-017 boards, or ExRAM for MMC5 + UINT8 *m_mapper_sram; + dynamic_buffer m_ext_ntram; + UINT32 m_mapper_sram_size; + + int m_ce_mask; + int m_ce_state; + int m_vrc_ls_prg_a; + int m_vrc_ls_prg_b; + int m_vrc_ls_chr; + + int m_mirroring; + bool m_pcb_ctrl_mirror, m_four_screen_vram, m_has_trainer; + bool m_x1_005_alt_mirroring; // temp hack for two kind of mirroring in Taito X1-005 boards (to be replaced with pin checking) + bool m_bus_conflict; + UINT8 m_open_bus; + + // PRG + inline int prg_8k_bank_num(int bank); + inline void update_prg_banks(int prg_bank_start, int prg_bank_end); + memory_bank *m_prg_bank_mem[4]; + int m_prg_bank[4]; + UINT32 m_prg_chunks; + UINT32 m_prg_mask; + + // PRG helpers + void prg32(int bank); + void prg16_89ab(int bank); + void prg16_cdef(int bank); + void prg8_89(int bank); + void prg8_ab(int bank); + void prg8_cd(int bank); + void prg8_ef(int bank); + void prg8_x(int start, int bank); + + + // CHR + int m_chr_source; // global source for the 8 VROM banks + inline void chr_sanity_check(int source); + + //these were previously called chr_map. they are a quick banking structure, + //because some of these change multiple times per scanline! + int m_chr_src[8]; //defines source of base pointer + int m_chr_orig[8]; //defines offset of 0x400 byte segment at base pointer + UINT8 *m_chr_access[8]; //source translated + origin -> valid pointer! + + UINT32 m_vrom_chunks; + UINT32 m_vram_chunks; + + // CHR helpers + void chr8(int bank, int source); + void chr4_x(int start, int bank, int source); + void chr4_0(int bank, int source){ chr4_x(0, bank, source); }; + void chr4_4(int bank, int source){ chr4_x(4, bank, source); }; + void chr2_x(int start, int bank, int source); + void chr2_0(int bank, int source) { chr2_x(0, bank, source); }; + void chr2_2(int bank, int source) { chr2_x(2, bank, source); }; + void chr2_4(int bank, int source) { chr2_x(4, bank, source); }; + void chr2_6(int bank, int source) { chr2_x(6, bank, source); }; + void chr1_x(int start, int bank, int source); + void chr1_0(int bank, int source) { chr1_x(0, bank, source); }; + void chr1_1(int bank, int source) { chr1_x(1, bank, source); }; + void chr1_2(int bank, int source) { chr1_x(2, bank, source); }; + void chr1_3(int bank, int source) { chr1_x(3, bank, source); }; + void chr1_4(int bank, int source) { chr1_x(4, bank, source); }; + void chr1_5(int bank, int source) { chr1_x(5, bank, source); }; + void chr1_6(int bank, int source) { chr1_x(6, bank, source); }; + void chr1_7(int bank, int source) { chr1_x(7, bank, source); }; + + + // NameTable & Mirroring + //these were previously called nt_page. they are a quick banking structure for a maximum of 4K of RAM/ROM/ExRAM + int m_nt_src[4]; + int m_nt_orig[4]; + int m_nt_writable[4]; + UINT8 *m_nt_access[4]; //quick banking structure for a maximum of 4K of RAM/ROM/ExRAM + + void set_nt_page(int page, int source, int bank, int writable); + void set_nt_mirroring(int mirroring); + + std::vector m_prg_bank_map; +}; + +void nes_partialhash(hash_collection &dest, const unsigned char *data, unsigned long length, const char *functions); + +// ======================> nes_cart_slot_device + +class nes_cart_slot_device : public device_t, + public device_image_interface, + public device_slot_interface +{ +public: + // construction/destruction + nes_cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual ~nes_cart_slot_device(); + + // device-level overrides + virtual void device_start(); + virtual void device_config_complete(); + + // image-level overrides + virtual bool call_load(); + virtual void call_unload(); + virtual bool call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry); + + void call_load_ines(); + void call_load_unif(); + void call_load_pcb(); + + virtual iodevice_t image_type() const { return IO_CARTSLOT; } + virtual bool is_readable() const { return 1; } + virtual bool is_writeable() const { return 0; } + virtual bool is_creatable() const { return 0; } + virtual bool must_be_loaded() const { return m_must_be_loaded; } + virtual bool is_reset_on_load() const { return 1; } + virtual const char *image_interface() const { return "nes_cart"; } + virtual const char *file_extensions() const { return "nes,unf,unif"; } + virtual const option_guide *create_option_guide() const { return NULL; } + virtual device_image_partialhash_func get_partial_hash() const { return &nes_partialhash; } + + // slot interface overrides + virtual void get_default_card_software(std::string &result); + const char * get_default_card_ines(UINT8 *ROM, UINT32 len); + const char * get_default_card_unif(UINT8 *ROM, UINT32 len); + const char * nes_get_slot(int pcb_id); + int nes_get_pcb_id(const char *slot); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_l); + virtual DECLARE_READ8_MEMBER(read_m); + virtual DECLARE_READ8_MEMBER(read_h); + virtual DECLARE_READ8_MEMBER(read_ex); + virtual DECLARE_WRITE8_MEMBER(write_l); + virtual DECLARE_WRITE8_MEMBER(write_m); + virtual DECLARE_WRITE8_MEMBER(write_h); + virtual DECLARE_WRITE8_MEMBER(write_ex); + + // hack until disk system is made modern! + virtual void disk_flip_side() { if (m_cart) m_cart->disk_flip_side(); } + + int get_pcb_id() { return m_pcb_id; }; + + void pcb_start(UINT8 *ciram_ptr); + void pcb_reset(); + + // temporarily here + int m_crc_hack; + + int get_crc_hack() { return m_crc_hack; }; + + void set_must_be_loaded(bool _must_be_loaded) { m_must_be_loaded = _must_be_loaded; } + + //private: + + device_nes_cart_interface* m_cart; + int m_pcb_id; + bool m_must_be_loaded; +}; + +// device type definition +extern const device_type NES_CART_SLOT; + + +/*************************************************************************** + DEVICE CONFIGURATION MACROS + ***************************************************************************/ + +#define NESSLOT_PRGROM_REGION_TAG ":cart:prg_rom" +#define NESSLOT_CHRROM_REGION_TAG ":cart:chr_rom" + + +#define MCFG_NES_CARTRIDGE_ADD(_tag, _slot_intf, _def_slot) \ + MCFG_DEVICE_ADD(_tag, NES_CART_SLOT, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) + +#define MCFG_NES_CARTRIDGE_NOT_MANDATORY \ + static_cast(device)->set_must_be_loaded(FALSE); + + +// Hacky configuration to add a slot with fixed disksys interface +#define MCFG_DISKSYS_ADD(_tag, _slot_intf, _def_slot) \ + MCFG_DEVICE_ADD(_tag, NES_CART_SLOT, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, true) \ + MCFG_NES_CARTRIDGE_NOT_MANDATORY + +#endif diff --git a/src/devices/bus/nes/nes_unif.inc b/src/devices/bus/nes/nes_unif.inc new file mode 100644 index 00000000000..b501c590159 --- /dev/null +++ b/src/devices/bus/nes/nes_unif.inc @@ -0,0 +1,575 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/***************************************************************************************** + + NES MMC Emulation - UNIF boards + + Very preliminary support for UNIF boards + + TODO: + - properly support WRAM, etc. + +****************************************************************************************/ + + +/* Set to generate prg & chr files when the cart is loaded */ +#define SPLIT_PRG 0 +#define SPLIT_CHR 0 + + +/************************************************************* + + unif_list + + Supported UNIF boards and corresponding handlers + + *************************************************************/ + + +struct unif +{ + const char *board; /* UNIF board */ + + int nvwram; + int wram; + int chrram; + int board_idx; +}; + + +/* CHRRAM sizes */ +enum +{ + CHRRAM_0 = 0, + CHRRAM_1, + CHRRAM_2, + CHRRAM_4, + CHRRAM_6, + CHRRAM_8, + CHRRAM_16, + CHRRAM_32 +}; + +static const unif unif_list[] = +{ +/* UNIF NVW WRAM CRAM IDX*/ + { "DREAMTECH01", 0, 0, CHRRAM_8, DREAMTECH_BOARD}, //UNIF only! + { "NES-ANROM", 0, 0, CHRRAM_8, STD_AXROM}, + { "NES-AOROM", 0, 0, CHRRAM_8, STD_AXROM}, + { "NES-CNROM", 0, 0, CHRRAM_0, STD_CNROM}, + { "NES-NROM", 0, 0, CHRRAM_0, STD_NROM}, + { "NES-NROM-128", 0, 0, CHRRAM_0, STD_NROM}, + { "NES-NROM-256", 0, 0, CHRRAM_0, STD_NROM}, + { "NES-NTBROM", 8, 0, CHRRAM_0, SUNSOFT_DCS}, + { "NES-SLROM", 0, 0, CHRRAM_0, STD_SXROM}, + { "NES-TBROM", 0, 0, CHRRAM_0, STD_TXROM}, + { "NES-TFROM", 0, 0, CHRRAM_0, STD_TXROM}, + { "NES-TKROM", 8, 0, CHRRAM_0, STD_TXROM}, + { "NES-TLROM", 0, 0, CHRRAM_0, STD_TXROM}, + { "NES-UOROM", 0, 0, CHRRAM_8, STD_UXROM}, + { "UNL-22211", 0, 0, CHRRAM_0, TXC_22211}, + // mapper 172 & 173 are variant of this one... no UNIF? + { "UNL-KOF97", 0, 0, CHRRAM_0, UNL_KOF97}, + { "UNL-SA-NROM", 0, 0, CHRRAM_0, SACHEN_TCA01}, + { "UNL-VRC7", 0, 0, CHRRAM_0, KONAMI_VRC7}, + { "UNL-T-230", 0, 0, CHRRAM_8, UNL_T230}, + { "UNL-CC-21", 0, 0, CHRRAM_0, UNL_CC21}, + { "UNL-AX5705", 0, 0, CHRRAM_0, UNL_AX5705}, + { "UNL-SMB2J", 8, 8, CHRRAM_0, UNL_SMB2J}, + { "UNL-8237", 0, 0, CHRRAM_0, UNL_8237}, + { "UNL-SL1632", 0, 0, CHRRAM_0, REXSOFT_SL1632}, + { "UNL-SACHEN-74LS374N", 0, 0, CHRRAM_0, SACHEN_74LS374}, + // mapper 243 variant exists! how to distinguish?!? mapper243_l_w, NULL, NULL, NULL, NULL, NULL, NULL (also uses NT_VERT!) + { "UNL-TC-U01-1.5M", 0, 0, CHRRAM_0, SACHEN_TCU01}, + { "UNL-SACHEN-8259C", 0, 0, CHRRAM_0, SACHEN_8259C}, + { "UNL-SA-016-1M", 0, 0, CHRRAM_0, AVE_NINA06}, // actually this is Mapper 146, but works like 79! + { "UNL-SACHEN-8259D", 0, 0, CHRRAM_0, SACHEN_8259D}, + { "UNL-SA-72007", 0, 0, CHRRAM_0, SACHEN_SA72007}, + { "UNL-SA-72008", 0, 0, CHRRAM_0, SACHEN_SA72008}, + { "UNL-SA-0037", 0, 0, CHRRAM_0, SACHEN_SA0037}, + { "UNL-SA-0036", 0, 0, CHRRAM_0, SACHEN_SA0036}, + { "UNL-SA-9602B", 0, 0, CHRRAM_0, SACHEN_SA9602B}, + { "UNL-SACHEN-8259A", 0, 0, CHRRAM_0, SACHEN_8259A}, + { "UNL-SACHEN-8259B", 0, 0, CHRRAM_0, SACHEN_8259B}, + { "BMC-190IN1", 0, 0, CHRRAM_0, BMC_190IN1}, + { "BMC-64IN1NOREPEAT", 0, 0, CHRRAM_0, BMC_64IN1NR}, //UNIF only! + { "BMC-A65AS", 0, 0, CHRRAM_8, BMC_A65AS}, //UNIF only! + { "BMC-GS-2004", 0, 0, CHRRAM_8, RCM_GS2004}, //UNIF only! + { "BMC-GS-2013", 0, 0, CHRRAM_8, RCM_GS2013}, //UNIF only! + { "BMC-NOVELDIAMOND9999999IN1", 0, 0, CHRRAM_0, BMC_NOVEL1}, + { "BMC-SUPER24IN1SC03", 8, 0, CHRRAM_8, BMC_S24IN1SC03}, + { "BMC-SUPERHIK8IN1", 8, 0, CHRRAM_0, BMC_HIK8IN1}, + { "BMC-T-262", 0, 0, CHRRAM_8, BMC_T262}, //UNIF only! + { "BMC-WS", 0, 0, CHRRAM_0, BMC_WS}, //UNIF only! + { "BMC-N625092", 0, 0, CHRRAM_0, UNL_N625092}, + // below are boards which are not yet supported, but are used by some UNIF files. they are here as a reminder to what is missing to be added + { "UNL-TEK90", 0, 0, CHRRAM_0, JYCOMPANY_A}, // JY Company A (is TEK90 the real PCB name?) + { "UNL-KS7017", 0, 0, CHRRAM_0, KAISER_KS7017}, + { "UNL-KS7032", 0, 0, CHRRAM_0, KAISER_KS7032}, // mapper 142 + { "UNL-603-5052", 0, 0, CHRRAM_0, UNL_603_5052}, // mapper 238? + { "UNL-EDU2000", 32, 0, CHRRAM_8, UNL_EDU2K}, + { "UNL-H2288", 0, 0, CHRRAM_0, UNL_H2288}, // mapper 123 + { "UNL-SHERO", 0, 0, CHRRAM_8, SACHEN_SHERO}, + { "UNL-YOKO", 0, 0, CHRRAM_0, YOKO_BOARD}, // similar to mapper 83, but not the same + { "UNL-FS304", 0, 8, CHRRAM_8, WAIXING_FS304}, // used in Zelda 3 by Waixing + { "UNL-43272", 0, 0, CHRRAM_0, UNL_43272}, // used in Gaau Hok Gwong Cheung + { "BTL-MARIO1-MALEE2", 0, 0, CHRRAM_0, UNL_MMALEE}, // mapper 55? + { "BMC-FK23C", 0, 0, CHRRAM_0, BMC_FK23C}, + { "BMC-FK23CA", 0, 0, CHRRAM_0, BMC_FK23CA}, + { "BMC-GHOSTBUSTERS63IN1", 0, 0, CHRRAM_8, BMC_G63IN1 }, + { "BMC-BS-5", 0, 0, CHRRAM_0, BMC_BENSHIENG}, + { "BMC-810544-C-A1", 0, 0, CHRRAM_0, BMC_810544}, + { "BMC-411120-C", 0, 0, CHRRAM_0, BMC_411120C}, + { "BMC-8157", 0, 0, CHRRAM_8, BMC_8157}, + { "BMC-830118C", 0, 0, CHRRAM_0, BMC_830118C}, + { "BMC-D1038", 0, 0, CHRRAM_0, BMC_VT5201}, // mapper 60? + { "BMC-SUPERVISION16IN1", 0, 0, CHRRAM_0, SVISION16_BOARD}, // mapper 53 + { "BMC-NTD-03", 0, 0, CHRRAM_0, BMC_NTD_03}, + { "UNL-AC08", 0, 0, CHRRAM_0, UNL_AC08}, + { "UNL-BB", 0, 0, CHRRAM_0, UNL_BB}, + { "UNL-LH32", 0, 0, CHRRAM_0, UNL_LH32}, + { "UNL-LH53", 0, 0, CHRRAM_0, UNL_LH53}, + { "BMC-G-146", 0, 0, CHRRAM_0, BMC_G146}, + { "BMC-11160", 0, 0, CHRRAM_0, BMC_11160}, + { "UNL-MALISB", 0, 0, CHRRAM_0, UNL_MALISB}, + { "UNL-TF1201", 0, 0, CHRRAM_0, UNL_TF1201}, + { "BMC-12-IN-1", 0, 0, CHRRAM_0, UNSUPPORTED_BOARD}, + { "BMC-70IN1", 0, 0, CHRRAM_0, UNSUPPORTED_BOARD}, // mapper 236? + { "BMC-70IN1B", 0, 0, CHRRAM_0, UNSUPPORTED_BOARD}, // mapper 236? + { "BMC-42IN1RESETSWITCH", 0, 0, CHRRAM_0, UNSUPPORTED_BOARD}, // mapper 60? + { "PEC-586", 0, 0, CHRRAM_0, UNSUPPORTED_BOARD}, + { "UNL-DANCE", 0, 0, CHRRAM_0, UNSUPPORTED_BOARD}, + { "UNL-DRIPGAME", 0, 0, CHRRAM_0, UNSUPPORTED_BOARD}, // [by Quietust - we need more info] + { "UNL-CITYFIGHT", 0, 0, CHRRAM_0, UNSUPPORTED_BOARD}, + { "UNL-OneBus", 0, 0, CHRRAM_0, UNSUPPORTED_BOARD}, + { "UNL-DANCE2000", 0, 0, CHRRAM_0, UNSUPPORTED_BOARD} +}; + +const unif *nes_unif_lookup( const char *board ) +{ + int i; + for (i = 0; i < ARRAY_LENGTH(unif_list); i++) + { + if (!core_stricmp(unif_list[i].board, board)) + return &unif_list[i]; + } + return NULL; +} + +/************************************************************* + + unif_mapr_setup + + setup the board specific variables (wram, nvwram, pcb_id etc.) + for a given board (after reading the MAPR chunk of the UNIF file) + + *************************************************************/ + +void unif_mapr_setup( const char *board, int *pcb_id, int *battery, int *prgram, int *vram_chunks ) +{ + const unif *unif_board = nes_unif_lookup(board); + if (unif_board == NULL) + fatalerror("Unknown UNIF board %s.\n", board); + + *pcb_id = unif_board->board_idx; + *battery = unif_board->nvwram; // we should implement battery banks based on the size of this... + *prgram = unif_board->wram; // we should implement WRAM banks based on the size of this... + + if (unif_board->chrram <= CHRRAM_8) + *vram_chunks = 1; + else if (unif_board->chrram == CHRRAM_16) + *vram_chunks = 2; + else if (unif_board->chrram == CHRRAM_32) + *vram_chunks = 4; +} + + +/************************************************************* + + call_load_unif + + *************************************************************/ + +void nes_cart_slot_device::call_load_unif() +{ + UINT32 vram_size = 0, prgram_size = 0, battery_size = 0, mapper_sram_size = 0; + // SETUP step 1: running through the file and getting PRG, VROM sizes + UINT32 unif_ver = 0, chunk_length = 0, read_length = 0x20; + UINT32 prg_start = 0, chr_start = 0; + UINT32 size = length(), prg_size = 0, vrom_size = 0; + UINT8 buffer[4], mirror = 0; + char magic2[4]; + char unif_mapr[32]; // here we should store MAPR chunks + bool mapr_chunk_found = FALSE, small_prg = FALSE; + + // allocate space to temporarily store PRG & CHR banks + dynamic_buffer temp_prg(256 * 0x4000); + dynamic_buffer temp_chr(256 * 0x2000); + UINT8 temp_byte = 0; + + fseek(4, SEEK_SET); + fread(&buffer, 4); + unif_ver = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); + logerror("Loaded game in UNIF format, version %d\n", unif_ver); + + do + { + fseek(read_length, SEEK_SET); + + memset(magic2, '\0', sizeof(magic2)); + fread(&magic2, 4); + + /* We first run through the whole image to find a [MAPR] chunk. This is needed + because, unfortunately, the MAPR chunk is not always the first chunk (see + Super 24-in-1). When such a chunk is found, we set mapr_chunk_found=1 and + we go back to load other chunks! */ + if (!mapr_chunk_found) + { + if ((magic2[0] == 'M') && (magic2[1] == 'A') && (magic2[2] == 'P') && (magic2[3] == 'R')) + { + mapr_chunk_found = TRUE; + logerror("[MAPR] chunk found: "); + fread(&buffer, 4); + chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); + + if (chunk_length <= 0x20) + fread(&unif_mapr, chunk_length); + logerror("%s\n", unif_mapr); + + /* now that we found the MAPR chunk, we can go back to load other chunks */ + fseek(0x20, SEEK_SET); + read_length = 0x20; + } + else + { + logerror("Skip this chunk. We need a [MAPR] chunk before anything else.\n"); + fread(&buffer, 4); + chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); + + read_length += (chunk_length + 8); + } + } + else + { + /* What kind of chunk do we have here? */ + if ((magic2[0] == 'M') && (magic2[1] == 'A') && (magic2[2] == 'P') && (magic2[3] == 'R')) + { + /* The [MAPR] chunk has already been read, so we skip it */ + /* TO DO: it would be nice to check if more than one MAPR chunk is present */ + logerror("[MAPR] chunk found (in the 2nd run). Already loaded.\n"); + fread(&buffer, 4); + chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); + + read_length += (chunk_length + 8); + } + else if ((magic2[0] == 'R') && (magic2[1] == 'E') && (magic2[2] == 'A') && (magic2[3] == 'D')) + { + logerror("[READ] chunk found. No support yet.\n"); + fread(&buffer, 4); + chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); + + read_length += (chunk_length + 8); + } + else if ((magic2[0] == 'N') && (magic2[1] == 'A') && (magic2[2] == 'M') && (magic2[3] == 'E')) + { + logerror("[NAME] chunk found. No support yet.\n"); + fread(&buffer, 4); + chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); + + read_length += (chunk_length + 8); + } + else if ((magic2[0] == 'W') && (magic2[1] == 'R') && (magic2[2] == 'T') && (magic2[3] == 'R')) + { + logerror("[WRTR] chunk found. No support yet.\n"); + fread(&buffer, 4); + chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); + + read_length += (chunk_length + 8); + } + else if ((magic2[0] == 'T') && (magic2[1] == 'V') && (magic2[2] == 'C') && (magic2[3] == 'I')) + { + logerror("[TVCI] chunk found.\n"); + fread(&buffer, 4); + chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); + + fread(&temp_byte, 1); + logerror("Television Standard : %s\n", (temp_byte == 0) ? "NTSC" : (temp_byte == 1) ? "PAL" : "Does not matter"); + + read_length += (chunk_length + 8); + } + else if ((magic2[0] == 'T') && (magic2[1] == 'V') && (magic2[2] == 'S') && (magic2[3] == 'C')) // is this the same as TVCI?? + { + logerror("[TVSC] chunk found. No support yet.\n"); + fread(&buffer, 4); + chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); + + read_length += (chunk_length + 8); + } + else if ((magic2[0] == 'D') && (magic2[1] == 'I') && (magic2[2] == 'N') && (magic2[3] == 'F')) + { + logerror("[DINF] chunk found. No support yet.\n"); + fread(&buffer, 4); + chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); + + read_length += (chunk_length + 8); + } + else if ((magic2[0] == 'C') && (magic2[1] == 'T') && (magic2[2] == 'R') && (magic2[3] == 'L')) + { + logerror("[CTRL] chunk found. No support yet.\n"); + fread(&buffer, 4); + chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); + + read_length += (chunk_length + 8); + } + else if ((magic2[0] == 'B') && (magic2[1] == 'A') && (magic2[2] == 'T') && (magic2[3] == 'R')) + { + logerror("[BATR] chunk found. No support yet.\n"); + fread(&buffer, 4); + chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); + + read_length += (chunk_length + 8); + } + else if ((magic2[0] == 'V') && (magic2[1] == 'R') && (magic2[2] == 'O') && (magic2[3] == 'R')) + { + logerror("[VROR] chunk found. No support yet.\n"); + fread(&buffer, 4); + chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); + + read_length += (chunk_length + 8); + } + else if ((magic2[0] == 'M') && (magic2[1] == 'I') && (magic2[2] == 'R') && (magic2[3] == 'R')) + { + logerror("[MIRR] chunk found.\n"); + fread(&buffer, 4); + chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); + + fread(&mirror, 1); + + read_length += (chunk_length + 8); + } + else if ((magic2[0] == 'P') && (magic2[1] == 'C') && (magic2[2] == 'K')) + { + logerror("[PCK%c] chunk found. No support yet.\n", magic2[3]); + fread(&buffer, 4); + chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); + + read_length += (chunk_length + 8); + } + else if ((magic2[0] == 'C') && (magic2[1] == 'C') && (magic2[2] == 'K')) + { + logerror("[CCK%c] chunk found. No support yet.\n", magic2[3]); + fread(&buffer, 4); + chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); + + read_length += (chunk_length + 8); + } + else if ((magic2[0] == 'P') && (magic2[1] == 'R') && (magic2[2] == 'G')) + { + logerror("[PRG%c] chunk found. ", magic2[3]); + fread(&buffer, 4); + chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); + prg_size += chunk_length; + + if (chunk_length / 0x4000) + logerror("It consists of %d 16K-blocks.\n", chunk_length / 0x4000); + else + { + small_prg = TRUE; + logerror("This chunk is smaller than 16K: the emulation might have issues. Please report this file to the MESS forums.\n"); + } + + /* Read in the program chunks */ + fread(&temp_prg[prg_start], chunk_length); + + prg_start += chunk_length; + read_length += (chunk_length + 8); + } + else if ((magic2[0] == 'C') && (magic2[1] == 'H') && (magic2[2] == 'R')) + { + logerror("[CHR%c] chunk found. ", magic2[3]); + fread(&buffer, 4); + chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24); + vrom_size += chunk_length; + + logerror("It consists of %d 8K-blocks.\n", chunk_length / 0x2000); + + /* Read in the vrom chunks */ + fread(&temp_chr[chr_start], chunk_length); + + chr_start += chunk_length; + read_length += (chunk_length + 8); + } + else + { + logerror("Unsupported UNIF chunk or corrupted header. Please report the problem at MESS Board.\n"); + read_length = size; + } + } + } while (size > read_length); + + if (!mapr_chunk_found) + { + fatalerror("UNIF should have a [MAPR] chunk to work. Check if your image has been corrupted\n"); + } + + if (!prg_start) + { + fatalerror("No PRG found. Please report the problem at MESS Board.\n"); + } + + // SETUP step 2: getting PCB and other settings + int pcb_id = 0, battery = 0, prgram = 0, vram_chunks = 0; + unif_mapr_setup(unif_mapr, &pcb_id, &battery, &prgram, &vram_chunks); + + // SETUP step 3: storing the info needed for emulation + m_pcb_id = pcb_id; + if (battery) + battery_size = NES_BATTERY_SIZE; // we should allow for smaller battery! + prgram_size = prgram * 0x2000; + vram_size = vram_chunks * 0x2000; + + m_cart->set_four_screen_vram(FALSE); + switch (mirror) + { + case 0: // Horizontal Mirroring (Hard Wired) + m_cart->set_mirroring(PPU_MIRROR_HORZ); + break; + case 1: // Vertical Mirroring (Hard Wired) + m_cart->set_mirroring(PPU_MIRROR_VERT); + break; + case 2: // Mirror All Pages From $2000 (Hard Wired) + m_cart->set_mirroring(PPU_MIRROR_LOW); + break; + case 3: // Mirror All Pages From $2400 (Hard Wired) + m_cart->set_mirroring(PPU_MIRROR_HIGH); + break; + case 4: // Four Screens of VRAM (Hard Wired) + m_cart->set_four_screen_vram(TRUE); + m_cart->set_mirroring(PPU_MIRROR_4SCREEN); + break; + case 5: // Mirroring Controlled By Mapper Hardware + logerror("Mirroring handled by the board hardware.\n"); + // default to horizontal at start + m_cart->set_mirroring(PPU_MIRROR_HORZ); + break; + default: + logerror("Undocumented mirroring value.\n"); + // default to horizontal + m_cart->set_mirroring(PPU_MIRROR_HORZ); + break; + } + + // SETUP step 4: logging what we have found + logerror("-- Board %s\n", unif_mapr); + logerror("-- PRG 0x%x (%d x 16k chunks)\n", prg_size, prg_size / 0x4000); + logerror("-- VROM 0x%x (%d x 8k chunks)\n", vrom_size, vrom_size / 0x2000); + logerror("-- VRAM 0x%x (%d x 8k chunks)\n", vram_size, vram_size / 0x2000); + + // SETUP steps 5/6: allocate pointers for PRG/VROM and load the data! + if (prg_size == 0x4000) + { + m_cart->prg_alloc(0x8000, tag()); + memcpy(m_cart->get_prg_base(), &temp_prg[0], 0x4000); + memcpy(m_cart->get_prg_base() + 0x4000, m_cart->get_prg_base(), 0x4000); + } + else + { + m_cart->prg_alloc(prg_size, tag()); + memcpy(m_cart->get_prg_base(), &temp_prg[0], prg_size); + } + + if (small_prg) // This is not supported yet, so warn users about this + osd_printf_error("Loaded UNIF file with non-16k PRG chunk. This is not supported in MESS yet."); + + if (vrom_size) + { + m_cart->vrom_alloc(vrom_size, tag()); + memcpy(m_cart->get_vrom_base(), &temp_chr[0], vrom_size); + } + +#if SPLIT_PRG + { + FILE *prgout; + char outname[255]; + + sprintf(outname, "%s.prg", filename()); + prgout = fopen(outname, "wb"); + if (prgout) + { + fwrite(m_cart->get_prg_base(), 1, 0x4000 * m_cart->get_prg_size(), prgout); + osd_printf_error("Created PRG chunk\n"); + } + + fclose(prgout); + } +#endif + +#if SPLIT_CHR + if (state->m_chr_chunks > 0) + { + FILE *chrout; + char outname[255]; + + sprintf(outname, "%s.chr", filename()); + chrout= fopen(outname, "wb"); + if (chrout) + { + fwrite(m_cart->get_vrom_base(), 1, m_cart->get_vrom_size(), chrout); + osd_printf_error("Created CHR chunk\n"); + } + fclose(chrout); + } +#endif + // SETUP steps 7: allocate the remaining pointer, when needed + if (vram_size) + m_cart->vram_alloc(vram_size); + if (prgram_size) + m_cart->prgram_alloc(prgram_size); + + // Attempt to load a battery file for this ROM + // A few boards have internal RAM with a battery (MMC6, Taito X1-005 & X1-017, etc.) + if (battery_size || mapper_sram_size) + { + UINT32 tot_size = battery_size + mapper_sram_size; + dynamic_buffer temp_nvram(tot_size); + battery_load(&temp_nvram[0], tot_size, 0x00); + if (battery_size) + { + m_cart->battery_alloc(battery_size); + memcpy(m_cart->get_battery_base(), &temp_nvram[0], battery_size); + } + if (mapper_sram_size) + memcpy(m_cart->get_mapper_sram_base(), &temp_nvram[battery_size], mapper_sram_size); + } + + logerror("UNIF support is only very preliminary.\n"); +} + +const char * nes_cart_slot_device::get_default_card_unif(UINT8 *ROM, UINT32 len) +{ + UINT32 chunk_length = 0, read_length = 0x20; + int pcb_id = 0, battery = 0, prgram = 0, vram_chunks = 0; + char unif_mapr[32]; + + do + { + if ((ROM[read_length + 0] == 'M') && (ROM[read_length + 1] == 'A') && (ROM[read_length + 2] == 'P') && (ROM[read_length + 3] == 'R')) + { + chunk_length = ROM[read_length + 4] | (ROM[read_length + 5] << 8) | (ROM[read_length + 6] << 16) | (ROM[read_length + 7] << 24); + + if (chunk_length <= 0x20) + memcpy(unif_mapr, ROM + read_length + 8, chunk_length); + + read_length += (chunk_length + 8); + } + else + { + chunk_length = ROM[read_length + 4] | (ROM[read_length + 5] << 8) | (ROM[read_length + 6] << 16) | (ROM[read_length + 7] << 24); + read_length += (chunk_length + 8); + } + } while (len > read_length); + + unif_mapr_setup(unif_mapr, &pcb_id, &battery, &prgram, &vram_chunks); + + return nes_get_slot(pcb_id); +} diff --git a/src/devices/bus/nes/ntdec.c b/src/devices/bus/nes/ntdec.c new file mode 100644 index 00000000000..4dd7e56a842 --- /dev/null +++ b/src/devices/bus/nes/ntdec.c @@ -0,0 +1,186 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + NES/Famicom cartridge emulation for NTDEC PCBs + + + Here we emulate the following PCBs + + * NTDEC ASDER [mapper 112] + * NTDEC Fighting Hero [mapper 193] + + TODO: + - why is Master Shooter not working? + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "ntdec.h" + + +#ifdef NES_PCB_DEBUG +#define VERBOSE 1 +#else +#define VERBOSE 0 +#endif + +#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) + + +//------------------------------------------------- +// constructor +//------------------------------------------------- + +const device_type NES_NTDEC_ASDER = &device_creator; +const device_type NES_NTDEC_FH = &device_creator; + + +nes_ntdec_asder_device::nes_ntdec_asder_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_NTDEC_ASDER, "NES Cart NTDEC Asder PCB", tag, owner, clock, "nes_ntdec_asder", __FILE__) +{ +} + +nes_ntdec_fh_device::nes_ntdec_fh_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_NTDEC_FH, "NES Cart NTDEC Fighting Hero PCB", tag, owner, clock, "nes_ntdec_fh", __FILE__) +{ +} + + + + +void nes_ntdec_asder_device::device_start() +{ + common_start(); + save_item(NAME(m_latch)); +} + +void nes_ntdec_asder_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); + + m_latch = 0; +} + +void nes_ntdec_fh_device::device_start() +{ + common_start(); +} + +void nes_ntdec_fh_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32((m_prg_chunks - 1) >> 1); + chr8(0, m_chr_source); + set_nt_mirroring(PPU_MIRROR_VERT); +} + + + + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +/*------------------------------------------------- + + NTDEC ASDER Bootleg Board + + Games: Cobra Mission, Fighting Hero III, Huang Di, Master + Shooter + + iNES: mapper 112 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_ntdec_asder_device::write_h) +{ + LOG_MMC(("ntdec_asder write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset) + { + case 0x0000: + m_latch = data & 0x07; + break; + case 0x2000: + switch (m_latch) + { + case 0: + prg8_89(data); + break; + case 1: + prg8_ab(data); + break; + case 2: + data &= 0xfe; + chr1_0(data, CHRROM); + chr1_1(data + 1, CHRROM); + break; + case 3: + data &= 0xfe; + chr1_2(data, CHRROM); + chr1_3(data + 1, CHRROM); + break; + case 4: + chr1_4(data, CHRROM); + break; + case 5: + chr1_5(data, CHRROM); + break; + case 6: + chr1_6(data, CHRROM); + break; + case 7: + chr1_7(data, CHRROM); + break; + } + break; + case 0x6000: + set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + break; + } +} + +/*------------------------------------------------- + + Bootleg Board by NTDEC for Fighting Hero + + Games: Fighting Hero + + Very simple mapper: writes to 0x6000-0x7fff swap PRG and + CHR banks. + + iNES: mapper 193 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_ntdec_fh_device::write_m) +{ + LOG_MMC(("ntdec_fh write_m, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x03) + { + case 0: + chr4_0(data >> 2, CHRROM); + break; + case 1: + chr2_4(data >> 1, CHRROM); + break; + case 2: + chr2_6(data >> 1 , CHRROM); + break; + case 3: + prg8_89(data); + break; + } +} diff --git a/src/devices/bus/nes/ntdec.h b/src/devices/bus/nes/ntdec.h new file mode 100644 index 00000000000..00712eecf1c --- /dev/null +++ b/src/devices/bus/nes/ntdec.h @@ -0,0 +1,51 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __NES_NTDEC_H +#define __NES_NTDEC_H + +#include "nxrom.h" + + +// ======================> nes_ntdec_asder_device + +class nes_ntdec_asder_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_ntdec_asder_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); + +private: + UINT8 m_latch; +}; + + +// ======================> nes_ntdec_fh_device + +class nes_ntdec_fh_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_ntdec_fh_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_m); + + virtual void pcb_reset(); +}; + + + + + +// device type definition +extern const device_type NES_NTDEC_ASDER; +extern const device_type NES_NTDEC_FH; + +#endif diff --git a/src/devices/bus/nes/nxrom.c b/src/devices/bus/nes/nxrom.c new file mode 100644 index 00000000000..431d384e7f1 --- /dev/null +++ b/src/devices/bus/nes/nxrom.c @@ -0,0 +1,583 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + NES/Famicom cartridge emulation for Nintendo xxROM PCBs + + + Here we emulate the following PCBs + + * Nintendo NROM [mapper 0] + * Nintendo AxROM [mapper 7] + * Nintendo BxROM [mapper 34] + * Nintendo CNROM [mapper 3 & 185] + * Nintendo CPROM [mapper 13] + * Nintendo GxROM/MxROM [mapper 66] + * Nintendo UxROM [mapper 2] + Crazy Climbers variant [mapper 180] + * Nintendo UN1ROM [mapper 94] + + Known issues on specific mappers: + + * 000 F1 Race requires more precise PPU timing. It currently has plenty of 1-line glitches. + * 003 Firehouse Rescue has flashing graphics (same PPU issue as Back to the Future 2 & 3?) + * 007 Marble Madness has small graphics corruptions + * 034 Titanic 1912 (pirate BxROM) has missing gfx (same PPU issue of many Waixing titles almost for sure) + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "nxrom.h" + +#include "sound/samples.h" + +#ifdef NES_PCB_DEBUG +#define VERBOSE 1 +#else +#define VERBOSE 0 +#endif + +#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) + + +//------------------------------------------------- +// constructor +//------------------------------------------------- + +const device_type NES_NROM = &device_creator; +const device_type NES_NROM368 = &device_creator; +const device_type NES_FCBASIC = &device_creator; +const device_type NES_AXROM = &device_creator; +const device_type NES_BXROM = &device_creator; +const device_type NES_CNROM = &device_creator; +const device_type NES_CPROM = &device_creator; +const device_type NES_GXROM = &device_creator; +const device_type NES_UXROM = &device_creator; +const device_type NES_UXROM_CC = &device_creator; +const device_type NES_UN1ROM = &device_creator; +const device_type NES_NOCHR = &device_creator; + + +nes_nrom_device::nes_nrom_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_nes_cart_interface( mconfig, *this ) +{ +} + +nes_nrom_device::nes_nrom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, NES_NROM, "NES Cart NROM PCB", tag, owner, clock, "nes_nrom", __FILE__), + device_nes_cart_interface( mconfig, *this ) +{ +} + +nes_nrom368_device::nes_nrom368_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_NROM368, "NES Cart NROM-368 PCB", tag, owner, clock, "nes_nrom368", __FILE__) +{ +} + +nes_fcbasic_device::nes_fcbasic_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_FCBASIC, "NES Cart Famicom BASIC PCB", tag, owner, clock, "nes_fcbasic", __FILE__) +{ +} + +nes_axrom_device::nes_axrom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_AXROM, "NES Cart AxROM PCB", tag, owner, clock, "nes_axrom", __FILE__) +{ +} + +nes_bxrom_device::nes_bxrom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_BXROM, "NES Cart BxROM PCB", tag, owner, clock, "nes_bxrom", __FILE__) +{ +} + +nes_cnrom_device::nes_cnrom_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : nes_nrom_device(mconfig, type, name, tag, owner, clock, shortname, source) +{ +} + +nes_cnrom_device::nes_cnrom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_CNROM, "NES Cart CNROM PCB", tag, owner, clock, "nes_cnrom", __FILE__) +{ +} + +nes_cprom_device::nes_cprom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_CPROM, "NES Cart CPROM PCB", tag, owner, clock, "nes_cprom", __FILE__) +{ +} + +nes_gxrom_device::nes_gxrom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_GXROM, "NES Cart GxROM PCB", tag, owner, clock, "nes_gxrom", __FILE__) +{ +} + +nes_uxrom_device::nes_uxrom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_UXROM, "NES Cart UxROM PCB", tag, owner, clock, "nes_uxrom", __FILE__) +{ +} + +nes_uxrom_cc_device::nes_uxrom_cc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_UXROM_CC, "NES Cart UNROM M5 PCB (Crazy Climber)", tag, owner, clock, "nes_uxrom_cc", __FILE__) +{ +} + +nes_un1rom_device::nes_un1rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_UN1ROM, "NES Cart UN1ROM PCB", tag, owner, clock, "nes_un1rom", __FILE__) +{ +} + +nes_nochr_device::nes_nochr_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_NOCHR, "NES Cart NoCash NOCHR PCB", tag, owner, clock, "nes_nochr", __FILE__) +{ +} + + +void nes_nrom_device::common_start() +{ + // PRG + save_item(NAME(m_prg_bank)); + + // CHR + save_item(NAME(m_chr_source)); + save_item(NAME(m_chr_src)); + save_item(NAME(m_chr_orig)); + + // NT + save_item(NAME(m_mirroring)); + save_item(NAME(m_nt_src)); + save_item(NAME(m_nt_orig)); + save_item(NAME(m_nt_writable)); + + // open bus + save_item(NAME(m_open_bus)); +} + +void nes_nrom_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); +} + +void nes_axrom_device::device_start() +{ + common_start(); +} + +void nes_axrom_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); + + set_nt_mirroring(PPU_MIRROR_LOW); +} + +void nes_bxrom_device::device_start() +{ + common_start(); +} + +void nes_bxrom_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); +} + +void nes_cnrom_device::device_start() +{ + common_start(); + save_item(NAME(m_chr_open_bus)); +} + +void nes_cnrom_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); + + m_chr_open_bus = 0; +} + +void nes_cprom_device::device_start() +{ + common_start(); +} + +void nes_cprom_device::pcb_reset() +{ + m_chr_source = CHRRAM; + prg32(0); + chr4_0(0, m_chr_source); + chr4_4(0, m_chr_source); +} + +void nes_gxrom_device::device_start() +{ + common_start(); +} + +void nes_gxrom_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); +} + +void nes_uxrom_device::device_start() +{ + common_start(); +} + +void nes_uxrom_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); +} + +void nes_uxrom_cc_device::device_start() +{ + common_start(); +} + +void nes_uxrom_cc_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); +} + +void nes_un1rom_device::device_start() +{ + common_start(); +} + +void nes_un1rom_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); +} + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +/*------------------------------------------------- + + NROM board emulation + + Games: Mario Bros., Super Mario Bros., Tennis and most of + the first generation games + + iNES: mapper 0 + + In MESS: Supported, no need of specific handlers or IRQ + + -------------------------------------------------*/ + +/*------------------------------------------------- + + NROM-368 board emulation + + iNES: mapper 0 with 3xPRG banks + This is an homebrew extension to map linearly 46KB + or PRG in boards with no PRG bankswitch logic + + In MESS: Supported + + -------------------------------------------------*/ + +READ8_MEMBER(nes_nrom368_device::read_l) +{ + LOG_MMC(("nrom368 read_l, offset: %04x\n", offset)); + offset += 0x100; + if (offset >= 0x800) + return m_prg[offset - 0x800]; + else + return m_open_bus; +} + +READ8_MEMBER(nes_nrom368_device::read_m) +{ + LOG_MMC(("nrom368 read_m, offset: %04x\n", offset)); + return m_prg[0x1800 + (offset & 0x1fff)]; +} + +READ8_MEMBER(nes_nrom368_device::read_h) +{ + LOG_MMC(("nrom368 read_h, offset: %04x\n", offset)); + return m_prg[0x3800 + (offset & 0x7fff)]; +} + +/*------------------------------------------------- + + AxROM board emulation + + Games: Arch Rivals, Battletoads, Cabal, Commando, Solstice + + writes to 0x8000-0xffff change PRG banks + sets mirroring + + AMROM has bus conflict + AOROM has generally bus conflict too, but some later pcbs + added some discrete component to disable ROM and avoid + conflicts. No AOROM games is known to glitch due to lack of + bus conflict, so it seems safe to emulate AOROM + without bus conflict. + + iNES: mapper 7 + + In MESS: Supported + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_axrom_device::write_h) +{ + LOG_MMC(("axrom write_h, offset: %04x, data: %02x\n", offset, data)); + + // this pcb is subject to bus conflict + data = account_bus_conflict(offset, data); + + set_nt_mirroring(BIT(data, 4) ? PPU_MIRROR_HIGH : PPU_MIRROR_LOW); + prg32(data); +} + +/*------------------------------------------------- + + BxROM board emulation + + writes to 0x8000-0xffff change PRG banks + + iNES: mapper 34 + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_bxrom_device::write_h) +{ + /* This portion of the mapper is nearly identical to Mapper 7, except no one-screen mirroring */ + /* Deadly Towers is really a BxROM game - the demo screens look wrong using mapper 7. */ + LOG_MMC(("bxrom write_h, offset: %04x, data: %02x\n", offset, data)); + + // this pcb is subject to bus conflict, but the same is not true for some pirate variants + data = account_bus_conflict(offset, data); + + prg32(data); +} + +/*------------------------------------------------- + + CNROM board emulation + + Games: B-Wings, Mighty Bomb Jack, Seicross, Spy vs. Spy, + Adventure Island, Flipull, Friday 13th, GeGeGe no + Kitarou, Ghostbusters, Gradius, Hokuto no Ken, Milon's + Secret Castle + + writes to 0x8000-0xffff change CHR 8K banks + + missing BC? + + iNES: mappers 3 & 185 (the latter for games using Pins as + protection) + + Notice that BANDAI_PT554 board (Aerobics Studio) uses very + similar hardware but with an additional sound chip which + gets writes to 0x6000 (currently unemulated in MESS) + + In MESS: Supported + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_cnrom_device::write_h) +{ + LOG_MMC(("cxrom write_h, offset: %04x, data: %02x\n", offset, data)); + + // this pcb is subject to bus conflict, but the same is not true for some pirate variants + data = account_bus_conflict(offset, data); + + if (m_ce_mask) + { + //printf("mask %x state %x\n", m_ce_mask, m_ce_state); + chr8(data & ~m_ce_mask, CHRROM); + + if ((data & m_ce_mask) == m_ce_state) + m_chr_open_bus = 0; + else + m_chr_open_bus = 1; + } + else + chr8(data, CHRROM); +} + +READ8_MEMBER(nes_cnrom_device::chr_r) +{ + int bank = offset >> 10; + + // a few CNROM boards contained copy protection schemes through + // suitably configured diodes, so that subsequent CHR reads can + // give actual VROM content or open bus values. + // For most boards, chr_open_bus remains always zero. + if (m_chr_open_bus) + return m_open_bus; + + return m_chr_access[bank][offset & 0x3ff]; +} + + +/*------------------------------------------------- + + CPROM board emulation + + Games: Videomation + + writes to 0x8000-0xffff change CHR 4K lower banks + + iNES: mapper 13 + + In MESS: Supported + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_cprom_device::write_h) +{ + LOG_MMC(("cprom write_h, offset: %04x, data: %02x\n", offset, data)); + + // this pcb is subject to bus conflict + data = account_bus_conflict(offset, data); + + chr4_4(data, CHRRAM); +} + + +/*------------------------------------------------- + + GxROM/MxROM board emulation + + writes to 0x8000-0xffff change PRG and CHR banks + + iNES: mapper 66 + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_gxrom_device::write_h) +{ + LOG_MMC(("gxrom write_h, offset %04x, data: %02x\n", offset, data)); + + // this pcb is subject to bus conflict + data = account_bus_conflict(offset, data); + + prg32((data & 0xf0) >> 4); + chr8(data & 0x0f, CHRROM); +} + +/*------------------------------------------------- + + UxROM board emulation + + Games: Castlevania, Dragon Quest II, Duck Tales, MegaMan, + Metal Gear + + writes to 0x8000-0xffff change PRG 16K lower banks + + iNES: mapper 2 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_uxrom_device::write_h) +{ + LOG_MMC(("uxrom write_h, offset: %04x, data: %02x\n", offset, data)); + + // this pcb is subject to bus conflict + data = account_bus_conflict(offset, data); + + prg16_89ab(data); +} + +/*------------------------------------------------- + + Nihon Bussan UNROM M5 + + Games: Crazy Climber Jpn + + Very simple mapper: prg16_89ab is always set to bank 0, + while prg16_cdef is set by writes to 0x8000-0xffff. The game + uses a custom controller. + + iNES: mapper 180 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_uxrom_cc_device::write_h) +{ + LOG_MMC(("uxrom_cc write_h, offset: %04x, data: %02x\n", offset, data)); + + prg16_cdef(data); +} + +/*------------------------------------------------- + + UN1ROM board emulation + + Games: Senjou no Okami + + writes to 0x8000-0xffff change PRG 16K lower banks + + iNES: mapper 94 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_un1rom_device::write_h) +{ + LOG_MMC(("un1rom write_h, offset: %04x, data: %02x\n", offset, data)); + + // this pcb is subject to bus conflict + data = account_bus_conflict(offset, data); + + prg16_89ab(data >> 2); +} + +/*------------------------------------------------- + + NoCash NOCHR board emulation + + This is an homebrew PCB design on a single chip + (+possibly CIC) which uses the NTRAM as CHRRAM! + + iNES: mapper 218 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_nochr_device::chr_w) +{ + int mirr = get_mirroring(); + if (mirr == PPU_MIRROR_HIGH) + m_ciram[(offset & 0x3ff) + 0x000] = data; + else if (mirr == PPU_MIRROR_LOW) + m_ciram[(offset & 0x3ff) + 0x400] = data; + else + m_ciram[offset & 0x7ff] = data; // not sure here, since there is no software to test... +} + +READ8_MEMBER(nes_nochr_device::chr_r) +{ + int mirr = get_mirroring(); + if (mirr == PPU_MIRROR_HIGH) + return m_ciram[(offset & 0x3ff) + 0x000]; + else if (mirr == PPU_MIRROR_LOW) + return m_ciram[(offset & 0x3ff) + 0x400]; + else + return m_ciram[offset & 0x7ff]; // not sure here, since there is no software to test... +} diff --git a/src/devices/bus/nes/nxrom.h b/src/devices/bus/nes/nxrom.h new file mode 100644 index 00000000000..fe105be0189 --- /dev/null +++ b/src/devices/bus/nes/nxrom.h @@ -0,0 +1,216 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __NES_MMCX_H +#define __NES_MMCX_H + +#include "nes_slot.h" +#include "sound/samples.h" + + +// ======================> nes_nrom_device + +class nes_nrom_device : public device_t, + public device_nes_cart_interface +{ +public: + // construction/destruction + nes_nrom_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + nes_nrom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual void device_start() { common_start(); } + + virtual void pcb_reset(); + + void common_start(); +}; + + +// ======================> nes_nrom368_device + +class nes_nrom368_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_nrom368_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual DECLARE_READ8_MEMBER(read_l); + virtual DECLARE_READ8_MEMBER(read_m); + virtual DECLARE_READ8_MEMBER(read_h); +}; + + +// ======================> nes_fcbasic_device + +class nes_fcbasic_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_fcbasic_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // emulate the additional WRAM +}; + + +// ======================> nes_axrom_device + +class nes_axrom_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_axrom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); +}; + + +// ======================> nes_bxrom_device + +class nes_bxrom_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_bxrom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); +}; + + +// ======================> nes_cnrom_device + +class nes_cnrom_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_cnrom_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + nes_cnrom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_READ8_MEMBER(chr_r); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); + +private: + UINT8 m_chr_open_bus; +}; + + +// ======================> nes_cprom_device + +class nes_cprom_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_cprom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); +}; + + +// ======================> nes_gxrom_device + +class nes_gxrom_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_gxrom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); +}; + + +// ======================> nes_uxrom_device + +class nes_uxrom_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_uxrom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); +}; + + +// ======================> nes_uxrom_cc_device + +class nes_uxrom_cc_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_uxrom_cc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); +}; + + +// ======================> nes_un1rom_device + +class nes_un1rom_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_un1rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); +}; + + +// ======================> nes_nochr_device + +class nes_nochr_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_nochr_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual DECLARE_READ8_MEMBER(chr_r); + virtual DECLARE_WRITE8_MEMBER(chr_w); +}; + + + +// device type definition +extern const device_type NES_NROM; +extern const device_type NES_NROM368; +extern const device_type NES_FCBASIC; +extern const device_type NES_AXROM; +extern const device_type NES_BXROM; +extern const device_type NES_CNROM; +extern const device_type NES_CPROM; +extern const device_type NES_GXROM; +extern const device_type NES_UXROM; +extern const device_type NES_UXROM_CC; +extern const device_type NES_UN1ROM; +extern const device_type NES_NOCHR; + +#endif diff --git a/src/devices/bus/nes/pirate.c b/src/devices/bus/nes/pirate.c new file mode 100644 index 00000000000..557831ed144 --- /dev/null +++ b/src/devices/bus/nes/pirate.c @@ -0,0 +1,1387 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + NES/Famicom cartridge emulation for pirate cart PCBs + + + Here we emulate the various PCBs used by Asian & Korean pirate games + + TODO: + - Are the scrolling glitches (check status bar) in Magic Dragon correct? FWIW, NEStopia behaves similarly + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "pirate.h" + +#include "cpu/m6502/m6502.h" +#include "video/ppu2c0x.h" // this has to be included so that IRQ functions can access PPU_BOTTOM_VISIBLE_SCANLINE + + +#ifdef NES_PCB_DEBUG +#define VERBOSE 1 +#else +#define VERBOSE 0 +#endif + +#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) + + +//------------------------------------------------- +// constructor +//------------------------------------------------- + +const device_type NES_AGCI_50282 = &device_creator; +const device_type NES_DREAMTECH01 = &device_creator; +const device_type NES_FUKUTAKE = &device_creator; +const device_type NES_FUTUREMEDIA = &device_creator; +const device_type NES_MAGSERIES = &device_creator; +const device_type NES_DAOU306 = &device_creator; +const device_type NES_SUBOR0 = &device_creator; +const device_type NES_SUBOR1 = &device_creator; +const device_type NES_CC21 = &device_creator; +const device_type NES_XIAOZY = &device_creator; +const device_type NES_EDU2K = &device_creator; +const device_type NES_T230 = &device_creator; +const device_type NES_MK2 = &device_creator; +const device_type NES_WHERO = &device_creator; +const device_type NES_43272 = &device_creator; +const device_type NES_TF1201 = &device_creator; +const device_type NES_CITYFIGHT = &device_creator; + + +nes_agci_device::nes_agci_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_AGCI_50282, "NES Cart AGCI 50282 PCB", tag, owner, clock, "nes_agci50282", __FILE__) +{ +} + +nes_dreamtech_device::nes_dreamtech_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_DREAMTECH01, "NES Cart Dreamtech01 PCB", tag, owner, clock, "nes_dreamtech", __FILE__) +{ +} + +nes_fukutake_device::nes_fukutake_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_FUKUTAKE, "NES Cart Fukutake Study Box PCB", tag, owner, clock, "nes_fukutake", __FILE__) +{ +} + +nes_futuremedia_device::nes_futuremedia_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_FUTUREMEDIA, "NES Cart FutureMedia PCB", tag, owner, clock, "nes_futuremedia", __FILE__) +{ +} + +nes_magseries_device::nes_magseries_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_MAGSERIES, "NES Cart Magical Series PCB", tag, owner, clock, "nes_magseries", __FILE__) +{ +} + +nes_daou306_device::nes_daou306_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_DAOU306, "NES Cart Daou 306 PCB", tag, owner, clock, "nes_daou306", __FILE__) +{ +} + +nes_subor0_device::nes_subor0_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_SUBOR0, "NES Cart Subor Type 0 PCB", tag, owner, clock, "nes_subor0", __FILE__) +{ +} + +nes_subor1_device::nes_subor1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_SUBOR1, "NES Cart Subor Type 1 PCB", tag, owner, clock, "nes_subor1", __FILE__) +{ +} + +nes_cc21_device::nes_cc21_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_CC21, "NES Cart CC-21 PCB", tag, owner, clock, "nes_cc21", __FILE__) +{ +} + +nes_xiaozy_device::nes_xiaozy_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_XIAOZY, "NES Cart Xiao Zhuan Yuan PCB", tag, owner, clock, "nes_xiaozy", __FILE__) +{ +} + +nes_edu2k_device::nes_edu2k_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_EDU2K, "NES Cart Educational Computer 2000 PCB", tag, owner, clock, "nes_edu2k", __FILE__) +{ +} + +nes_t230_device::nes_t230_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_T230, "NES Cart T-230 PCB", tag, owner, clock, "nes_t230", __FILE__) +{ +} + +nes_mk2_device::nes_mk2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_MK2, "NES Cart Mortal Kombat 2 PCB", tag, owner, clock, "nes_mk2", __FILE__) +{ +} + +nes_whero_device::nes_whero_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_WHERO, "NES Cart World Heroes PCB", tag, owner, clock, "nes_whero", __FILE__) +{ +} + +nes_43272_device::nes_43272_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_43272, "NES Cart UNL-43272 PCB", tag, owner, clock, "nes_43272", __FILE__) +{ +} + +nes_tf1201_device::nes_tf1201_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_TF1201, "NES Cart UNL-TF1201 PCB", tag, owner, clock, "nes_tf1201", __FILE__) +{ +} + +nes_cityfight_device::nes_cityfight_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_TF1201, "NES Cart City Fighter PCB", tag, owner, clock, "nes_cityfight", __FILE__) +{ +} + + + + +void nes_agci_device::device_start() +{ + common_start(); +} + +void nes_agci_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); +} + +void nes_dreamtech_device::device_start() +{ + common_start(); +} + +void nes_dreamtech_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(8); + chr8(0, m_chr_source); +} + +void nes_fukutake_device::device_start() +{ + common_start(); + save_item(NAME(m_latch)); + + // 2816 (?) bytes of RAM + save_item(NAME(m_ram)); +} + +void nes_fukutake_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(0); + chr8(0, m_chr_source); + + m_latch = 0; +} + +void nes_futuremedia_device::device_start() +{ + common_start(); + save_item(NAME(m_irq_clear)); + save_item(NAME(m_irq_enable)); + save_item(NAME(m_irq_count)); + save_item(NAME(m_irq_count_latch)); +} + +void nes_futuremedia_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); + + m_irq_clear = 0; + m_irq_enable = 0; + m_irq_count = m_irq_count_latch = 0; +} + +void nes_magseries_device::device_start() +{ + common_start(); +} + +void nes_magseries_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); +} + +void nes_daou306_device::device_start() +{ + common_start(); + save_item(NAME(m_reg)); +} + +void nes_daou306_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(m_prg_chunks - 2); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); + set_nt_mirroring(PPU_MIRROR_LOW); + + memset(m_reg, 0, sizeof(m_reg)); +} + +void nes_subor0_device::device_start() +{ + common_start(); + save_item(NAME(m_reg)); +} + +void nes_subor0_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(0x20); + chr8(0, m_chr_source); + + memset(m_reg, 0, sizeof(m_reg)); +} + +void nes_subor1_device::device_start() +{ + common_start(); + save_item(NAME(m_reg)); +} + +void nes_subor1_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(0x07); + chr8(0, m_chr_source); + + memset(m_reg, 0, sizeof(m_reg)); +} + +void nes_cc21_device::device_start() +{ + common_start(); +} + +void nes_cc21_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); +} + +void nes_xiaozy_device::device_start() +{ + common_start(); +} + +void nes_xiaozy_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32((m_prg_chunks - 1) >> 1); + chr8(0, m_chr_source); +} + +void nes_edu2k_device::device_start() +{ + common_start(); + save_item(NAME(m_latch)); +} + +void nes_edu2k_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); + + m_latch = 0; +} + +void nes_t230_device::device_start() +{ + common_start(); + save_item(NAME(m_irq_mode)); + save_item(NAME(m_irq_enable)); + save_item(NAME(m_irq_enable_latch)); + save_item(NAME(m_irq_count)); + save_item(NAME(m_irq_count_latch)); + save_item(NAME(m_mmc_vrom_bank)); +} + +void nes_t230_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); + + m_irq_mode = 0; + m_irq_enable = m_irq_enable_latch = 0; + m_irq_count = m_irq_count_latch = 0; + + memset(m_mmc_vrom_bank, 0, sizeof(m_mmc_vrom_bank)); +} + +void nes_mk2_device::device_start() +{ + common_start(); + save_item(NAME(m_irq_clear)); + save_item(NAME(m_irq_enable)); + save_item(NAME(m_irq_count)); + save_item(NAME(m_irq_count_latch)); +} + +void nes_mk2_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(m_prg_chunks - 1); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); + set_nt_mirroring(PPU_MIRROR_VERT); + + m_irq_clear = 0; + m_irq_enable = 0; + m_irq_count = m_irq_count_latch = 0; +} + + +void nes_whero_device::device_start() +{ + common_start(); + save_item(NAME(m_irq_enable)); + save_item(NAME(m_irq_enable_latch)); + save_item(NAME(m_irq_count)); + save_item(NAME(m_irq_count_latch)); + save_item(NAME(m_reg)); + save_item(NAME(m_mmc_vrom_bank)); +} + +void nes_whero_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(m_prg_chunks - 1); + chr8(0x100, m_chr_source); + + m_irq_enable = 0; + m_irq_enable_latch = 0; + m_irq_count = 0; + m_irq_count_latch = 0; + + m_reg = 0; + memset(m_mmc_vrom_bank, 0, sizeof(m_mmc_vrom_bank)); +} + +void nes_43272_device::device_start() +{ + common_start(); + save_item(NAME(m_latch)); +} + +void nes_43272_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32((m_prg_chunks - 1) >> 1); + chr8(0, m_chr_source); + + m_latch = 0x81; +} + +void nes_tf1201_device::device_start() +{ + common_start(); + save_item(NAME(m_prg)); + save_item(NAME(m_swap)); + save_item(NAME(m_irq_enable)); + save_item(NAME(m_irq_enable_latch)); + save_item(NAME(m_irq_count)); + save_item(NAME(m_mmc_vrom_bank)); +} + +void nes_tf1201_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); + + memset(m_mmc_vrom_bank, 0, sizeof(m_mmc_vrom_bank)); + m_prg = 0; + m_swap = 0; + m_irq_enable = 0; + m_irq_enable_latch = 0; + m_irq_count = 0; +} + +void nes_cityfight_device::device_start() +{ + common_start(); + irq_timer = timer_alloc(TIMER_IRQ); + irq_timer->adjust(attotime::zero, 0, machine().device("maincpu")->cycles_to_attotime(1)); + + save_item(NAME(m_prg_reg)); + save_item(NAME(m_prg_mode)); + save_item(NAME(m_irq_enable)); + save_item(NAME(m_irq_count)); + save_item(NAME(m_mmc_vrom_bank)); +} + +void nes_cityfight_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); + + memset(m_mmc_vrom_bank, 0, sizeof(m_mmc_vrom_bank)); + m_prg_reg = 0; + m_prg_mode = 0; + m_irq_enable = 0; + m_irq_count = 0; +} + + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +/*------------------------------------------------- + + AGCI 50282 bootleg board emulation + + Games: Death Race + + iNES: mapper 144 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_agci_device::write_h) +{ + LOG_MMC(("agci write_h, offset: %04x, data: %02x\n", offset, data)); + + // this pcb is subject to bus conflict + UINT8 temp = account_bus_conflict(offset, 0xff); + data = (data & temp) | (temp & 1); + + chr8(data >> 4, CHRROM); + prg32(data); +} + +/*------------------------------------------------- + + Board DREAMTECH01 + + Games: Korean Igo + + In MESS: Supported + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_dreamtech_device::write_l) +{ + LOG_MMC(("dreamtech write_l, offset: %04x, data: %02x\n", offset, data)); + offset += 0x100; + + if (offset == 0x1020) /* 0x5020 */ + prg16_89ab(data); +} + +/*------------------------------------------------- + + Bootleg Board by Fukutake + + Games: Study Box + + iNES: mapper 186 + + In MESS: Unsupported. + + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_fukutake_device::write_l) +{ + LOG_MMC(("fukutake write_l, offset: %04x, data: %02x\n", offset, data)); + offset += 0x100; + + if (offset >= 0x200 && offset < 0x400) + { + if (offset & 1) + prg16_89ab(data); + else + m_latch = data >> 6; + } + else if (offset >= 0x400 && offset < 0xf00) + m_ram[offset - 0x400] = data; +} + +READ8_MEMBER(nes_fukutake_device::read_l) +{ + LOG_MMC(("fukutake read_l, offset: %04x\n", offset)); + offset += 0x100; + + if (offset >= 0x200 && offset < 0x400) + { + if (offset == 0x200 || offset == 0x201 || offset == 0x203) + return 0x00; + else if (offset == 0x202) + return 0x40; + else + return 0xff; + } + else if (offset >= 0x400 && offset < 0xf00) + return m_ram[offset - 0x400]; + + return 0; +} + +WRITE8_MEMBER(nes_fukutake_device::write_m) +{ + LOG_MMC(("fukutake write_m, offset: %04x, data: %02x\n", offset, data)); + m_prgram[((m_latch * 0x2000) + offset) & (m_prgram.size() - 1)] = data; +} + +READ8_MEMBER(nes_fukutake_device::read_m) +{ + LOG_MMC(("fukutake read_m, offset: %04x\n", offset)); + return m_prgram[((m_latch * 0x2000) + offset) & (m_prgram.size() - 1)]; +} + +/*------------------------------------------------- + + Bootleg Board by Future Media + + Games: Crayon Shin-chan (C), San Guo Zhi 4 - Chi Bi Feng Yun + + iNES: mapper 117 + + In MESS: Unsupported. + + -------------------------------------------------*/ + +void nes_futuremedia_device::hblank_irq(int scanline, int vblank, int blanked) +{ + // if (scanline < PPU_BOTTOM_VISIBLE_SCANLINE) + { + if (m_irq_enable && m_irq_count) + { + m_irq_count--; + if (!m_irq_count) + m_maincpu->set_input_line(M6502_IRQ_LINE, HOLD_LINE); + } + } +} + +WRITE8_MEMBER(nes_futuremedia_device::write_h) +{ + LOG_MMC(("futuremedia write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset) + { + case 0x0000: + prg8_89(data); + break; + case 0x0001: + prg8_ab(data); + break; + case 0x0002: + prg8_cd(data); + break; + case 0x0003: + prg8_ef(data); + break; + case 0x2000: + case 0x2001: + case 0x2002: + case 0x2003: + case 0x2004: + case 0x2005: + case 0x2006: + case 0x2007: + chr1_x(offset & 0x07, data, CHRROM); + break; + + case 0x5000: + set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + break; + + case 0x4001: + m_irq_count_latch = data; + break; + case 0x4002: + // IRQ cleared + break; + case 0x4003: + m_irq_count = m_irq_count_latch; + break; + case 0x6000: + m_irq_enable = data & 0x01; + break; + } +} + +/*------------------------------------------------- + + Bootleg Board by Magic Series + + Games: Magic Dragon + + Very simple mapper: writes to 0x8000-0xffff set prg32 and chr8 + banks + + iNES: mapper 107 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_magseries_device::write_h) +{ + LOG_MMC(("magseries write_h, offset: %04x, data: %02x\n", offset, data)); + + prg32(data >> 1); + chr8(data, CHRROM); +} + +/*------------------------------------------------- + + Open Corp DAOU306 board + + Games: Metal Force (K) + + iNES: mapper 156 + + In MESS: Supported. + + Notes: Metal Force and Buzz & Waldog only use the first 4 + regs and no mirroring. Janggun ui Adeul uses all features + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_daou306_device::write_h) +{ + LOG_MMC(("daou306 write_h, offset: %04x, data: %02x\n", offset, data)); + int reg = BIT(offset, 2) ? 8 : 0; + + switch (offset) + { + case 0x4000: + case 0x4004: + m_reg[reg + 0] = data; + chr1_0(m_reg[0] | (m_reg[8] << 8), CHRROM); + break; + case 0x4001: + case 0x4005: + m_reg[reg + 1] = data; + chr1_1(m_reg[1] | (m_reg[9] << 8), CHRROM); + break; + case 0x4002: + case 0x4006: + m_reg[reg + 2] = data; + chr1_2(m_reg[2] | (m_reg[10] << 8), CHRROM); + break; + case 0x4003: + case 0x4007: + m_reg[reg + 3] = data; + chr1_3(m_reg[3] | (m_reg[11] << 8), CHRROM); + break; + case 0x4008: + case 0x400c: + m_reg[reg + 4] = data; + chr1_4(m_reg[4] | (m_reg[12] << 8), CHRROM); + break; + case 0x4009: + case 0x400d: + m_reg[reg + 5] = data; + chr1_5(m_reg[5] | (m_reg[13] << 8), CHRROM); + break; + case 0x400a: + case 0x400e: + m_reg[reg + 6] = data; + chr1_6(m_reg[6] | (m_reg[14] << 8), CHRROM); + break; + case 0x400b: + case 0x400f: + m_reg[reg + 7] = data; + chr1_7(m_reg[7] | (m_reg[15] << 8), CHRROM); + break; + case 0x4010: + prg16_89ab(data); + break; + case 0x4014: + if (data & 1) + set_nt_mirroring(PPU_MIRROR_HORZ); + else + set_nt_mirroring(PPU_MIRROR_VERT); + break; + } +} + +/*------------------------------------------------- + + Subor bootleg board Type 0 + + iNES: mapper 167 + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_subor0_device::write_h) +{ + UINT8 subor_helper1, subor_helper2; + LOG_MMC(("subor0 write_h, offset: %04x, data: %02x\n", offset, data)); + + m_reg[(offset >> 13) & 0x03] = data; + subor_helper1 = ((m_reg[0] ^ m_reg[1]) << 1) & 0x20; + subor_helper2 = ((m_reg[2] ^ m_reg[3]) << 0) & 0x1f; + + if (m_reg[1] & 0x08) + { + subor_helper1 += subor_helper2 & 0xfe; + subor_helper2 = subor_helper1; + subor_helper1 += 1; + } + else if (m_reg[1] & 0x04) + { + subor_helper2 += subor_helper1; + subor_helper1 = 0x1f; + } + else + { + subor_helper1 += subor_helper2; + subor_helper2 = 0x20; + } + + prg16_89ab(subor_helper1); + prg16_cdef(subor_helper2); +} + +/*------------------------------------------------- + + Subor bootleg board Type 1 + + iNES: mapper 166 + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_subor1_device::write_h) +{ + UINT8 subor_helper1, subor_helper2; + LOG_MMC(("subor1 write_h, offset: %04x, data: %02x\n", offset, data)); + + m_reg[(offset >> 13) & 0x03] = data; + subor_helper1 = ((m_reg[0] ^ m_reg[1]) << 1) & 0x20; + subor_helper2 = ((m_reg[2] ^ m_reg[3]) << 0) & 0x1f; + + if (m_reg[1] & 0x08) + { + subor_helper1 += subor_helper2 & 0xfe; + subor_helper2 = subor_helper1; + subor_helper2 += 1; + } + else if (m_reg[1] & 0x04) + { + subor_helper2 += subor_helper1; + subor_helper1 = 0x1f; + } + else + { + subor_helper1 += subor_helper2; + subor_helper2 = 0x07; + } + + prg16_89ab(subor_helper1); + prg16_cdef(subor_helper2); +} + +/*------------------------------------------------- + + Board UNL-CC-21 + + Games: Mi Hun Che + + In MESS: Supported + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_cc21_device::write_h) +{ + LOG_MMC(("cc21 write_h, offset: %04x, data: %02x\n", offset, data)); + + set_nt_mirroring(BIT(offset, 1) ? PPU_MIRROR_HIGH : PPU_MIRROR_LOW); + chr8((offset & 0x01), CHRROM); +} + +/*------------------------------------------------- + + Bootleg Board for Xiao Zhuan Yuan + + Games: Shu Qi Yu - Zhi Li Xiao Zhuan Yuan + + Very simple mapper: writes to 0x5ff1 set prg32 (to data>>1), + while writes to 0x5ff2 set chr8 + + iNES: mapper 176 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_xiaozy_device::write_l) +{ + LOG_MMC(("xiaozy write_l, offset: %04x, data: %02x\n", offset, data)); + + switch (offset) + { + case 0x1ef1: /* 0x5ff1 */ + prg32(data >> 1); + break; + case 0x1ef2: /* 0x5ff2 */ + chr8(data, CHRROM); + break; + } +} + +/*------------------------------------------------- + + UNL-EDU2000 + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_edu2k_device::write_h) +{ + LOG_MMC(("edu2k write_h, offset: %04x, data: %02x\n", offset, data)); + + prg32(data & 0x1f); + m_latch = (data & 0xc0) >> 6; +} + +WRITE8_MEMBER(nes_edu2k_device::write_m) +{ + LOG_MMC(("edu2k write_m, offset: %04x, data: %02x\n", offset, data)); + m_prgram[((m_latch * 0x2000) + offset) & (m_prgram.size() - 1)] = data; +} + +READ8_MEMBER(nes_edu2k_device::read_m) +{ + LOG_MMC(("edu2k read_m, offset: %04x\n", offset)); + return m_prgram[((m_latch * 0x2000) + offset) & (m_prgram.size() - 1)]; +} + +/*------------------------------------------------- + + Board UNL-T-230 + + Games: Dragon Ball Z IV (Unl) + + This mapper appears to be similar to Konami VRC-2 + but the game has no VROM and only 1 VRAM bank, so we + completely skip the chr bankswitch. If other games + using the same board and using CHR should surface, + we need to investigate this... + + In MESS: Supported + + -------------------------------------------------*/ + +// Identical to Konami IRQ +void nes_t230_device::hblank_irq(int scanline, int vblank, int blanked) +{ + /* Increment & check the IRQ scanline counter */ + if (m_irq_enable && (++m_irq_count == 0x100)) + { + m_irq_count = m_irq_count_latch; + m_irq_enable = m_irq_enable_latch; + m_maincpu->set_input_line(M6502_IRQ_LINE, HOLD_LINE); + } +} + +WRITE8_MEMBER(nes_t230_device::write_h) +{ + LOG_MMC(("t230 write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x700c) + { + case 0x0000: + break; + case 0x2000: + prg16_89ab(data); + break; + case 0x1000: + case 0x1004: + case 0x1008: + case 0x100c: + switch (data & 0x03) + { + case 0x00: set_nt_mirroring(PPU_MIRROR_VERT); break; + case 0x01: set_nt_mirroring(PPU_MIRROR_HORZ); break; + case 0x02: set_nt_mirroring(PPU_MIRROR_LOW); break; + case 0x03: set_nt_mirroring(PPU_MIRROR_HIGH); break; + } + break; + + case 0x7000: + m_irq_count_latch &= ~0x0f; + m_irq_count_latch |= data & 0x0f; + break; + case 0x7004: + m_irq_count_latch &= ~0xf0; + m_irq_count_latch |= (data << 4) & 0xf0; + break; + case 0x7008: + m_irq_mode = data & 0x04; // currently not implemented: 0 = prescaler mode / 1 = CPU mode + m_irq_enable = data & 0x02; + m_irq_enable_latch = data & 0x01; + if (data & 0x02) + m_irq_count = m_irq_count_latch; + break; + + default: + logerror("unl_t230_w uncaught offset: %04x value: %02x\n", offset, data); + break; + } +} + +/*------------------------------------------------- + + Bootleg Board for MK2 + + Games: Mortal Kombat II, Street Fighter III, Super Mario + Kart Rider + + This board uses an IRQ system very similar to MMC3. We indeed + use mapper4_irq, but there is some small glitch! + + iNES: mapper 91 + + In MESS: Supported. + + -------------------------------------------------*/ + +// Same IRQ as MMC3 +void nes_mk2_device::hblank_irq( int scanline, int vblank, int blanked ) +{ + if (scanline < PPU_BOTTOM_VISIBLE_SCANLINE) + { + int prior_count = m_irq_count; + if ((m_irq_count == 0) || m_irq_clear) + m_irq_count = m_irq_count_latch; + else + m_irq_count--; + + if (m_irq_enable && !blanked && (m_irq_count == 0) && (prior_count || m_irq_clear)) + { + LOG_MMC(("irq fired, scanline: %d (MAME %d, beam pos: %d)\n", scanline, + machine().first_screen()->vpos(), machine().first_screen()->hpos())); + m_maincpu->set_input_line(M6502_IRQ_LINE, HOLD_LINE); + } + } + m_irq_clear = 0; +} + +WRITE8_MEMBER(nes_mk2_device::write_m) +{ + LOG_MMC(("mk2 write_m, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x1000) + { + case 0x0000: + switch (offset & 0x03) + { + case 0x00: chr2_0(data, CHRROM); break; + case 0x01: chr2_2(data, CHRROM); break; + case 0x02: chr2_4(data, CHRROM); break; + case 0x03: chr2_6(data, CHRROM); break; + } + break; + case 0x1000: + switch (offset & 0x03) + { + case 0x00: prg8_89(data); break; + case 0x01: prg8_ab(data); break; + case 0x02: m_irq_enable = 0; m_irq_count = 0; break; + case 0x03: m_irq_enable = 1; m_irq_count = 7; break; + } + break; + default: + logerror("mk2 write_m, uncaught addr: %04x value: %02x\n", offset + 0x6000, data); + break; + } +} + + +/*------------------------------------------------- + + UNL-WOLRDHERO board emulation + + + iNES: + + -------------------------------------------------*/ + +// Same as Konami VRC IRQ... +void nes_whero_device::hblank_irq(int scanline, int vblank, int blanked) +{ + /* Increment & check the IRQ scanline counter */ + if (m_irq_enable && (++m_irq_count == 0x100)) + { + m_irq_count = m_irq_count_latch; + m_irq_enable = m_irq_enable_latch; + m_maincpu->set_input_line(M6502_IRQ_LINE, HOLD_LINE); + } +} + +WRITE8_MEMBER(nes_whero_device::write_h) +{ + int bank, shift, mask1, mask2; + LOG_MMC(("World Hero write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x70c3) + { + case 0x0000: + if (!m_reg) + prg8_89(data); + else + prg8_cd(data); + break; + + case 0x1000: + switch (data & 0x03) + { + case 0x00: set_nt_mirroring(PPU_MIRROR_VERT); break; + case 0x01: set_nt_mirroring(PPU_MIRROR_HORZ); break; + case 0x02: set_nt_mirroring(PPU_MIRROR_LOW); break; + case 0x03: set_nt_mirroring(PPU_MIRROR_HIGH); break; + } + break; + + case 0x1002: + case 0x1080: + if (m_reg != (data & 2)) + { + m_reg = data & 2; + // swap banks! + prg8_89(m_prg_bank[2]); + prg8_cd(m_prg_bank[0]); + } + break; + + case 0x2000: + prg8_ab(data); + break; + + case 0x3000: case 0x3001: case 0x3002: case 0x3003: + case 0x4000: case 0x4001: case 0x4002: case 0x4003: + case 0x5000: case 0x5001: case 0x5002: case 0x5003: + case 0x6000: case 0x6001: case 0x6002: case 0x6003: + bank = ((offset & 0x7000) - 0x3000) / 0x0800 + BIT(offset, 1); + shift = (offset & 1) << 2; + mask1 = shift ? 0x00f : 0xff0; + mask2 = shift ? 0xff0 : 0x00f; + m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & mask1) | ((data << shift) & mask2); + chr1_x(bank, m_mmc_vrom_bank[bank], CHRROM); + break; + + case 0x7000: + m_irq_count_latch = (m_irq_count_latch & 0xf0) | (data & 0x0f); + break; + + case 0x7001: + m_irq_count_latch = (m_irq_count_latch & 0x0f) | ((data & 0x0f) << 4); + break; + + case 0x7002: + // m_irq_mode = data & 0x04; // currently not implemented: 0 = prescaler mode / 1 = CPU mode + m_irq_enable = data & 0x02; + m_irq_enable_latch = data & 0x01; + if (data & 0x02) + m_irq_count = m_irq_count_latch; + break; + + case 0x7003: + m_irq_enable = m_irq_enable_latch; + break; + } +} + + +/*------------------------------------------------- + + UNL-43272 + + Games: Gaau Hok Gwong Cheung + + In MESS: Preliminary Supported + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_43272_device::write_h) +{ + LOG_MMC(("unl_43272 write_h, offset: %04x, data: %02x\n", offset, data)); + + if ((m_latch & 0x81) == 0x81) + prg32((m_latch & 0x38) >> 3); + + m_latch = offset & 0xffff; +} + + +READ8_MEMBER(nes_43272_device::read_h) +{ + UINT8 mask = (m_latch & 0x400) ? 0xfe : 0xff; + LOG_MMC(("unl_43272 read_h, offset: %04x\n", offset)); + + return hi_access_rom(offset & mask); +} + + +/*------------------------------------------------- + + UNL-TF1201 + + Games: + + In MESS: Preliminary Supported + + -------------------------------------------------*/ + +void nes_tf1201_device::hblank_irq(int scanline, int vblank, int blanked) +{ + if (m_irq_enable_latch != m_irq_enable && scanline < 240) + m_irq_count -= 8; + + if (m_irq_enable) + { + m_irq_count++; + if ((m_irq_count & 0xff) == 238) + m_maincpu->set_input_line(M6502_IRQ_LINE, HOLD_LINE); + } +} + +void nes_tf1201_device::update_prg() +{ + prg8_89(m_swap ? 0xff : m_prg); + prg8_cd(m_swap ? m_prg : 0xff ); +} + +WRITE8_MEMBER(nes_tf1201_device::write_h) +{ + int bank; + LOG_MMC(("unl_tf1201 write_h, offset: %04x, data: %02x\n", offset, data)); + + offset = (offset & 0x7003) | ((offset & 0x0c) >> 2); // nestopia does not OR here... + + switch (offset & 0x7003) + { + case 0x0000: + m_prg = data; + update_prg(); + break; + case 0x1000: + set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + break; + case 0x1001: + m_swap = data & 0x03; + update_prg(); + break; + case 0x2000: + prg8_ab(data); + break; + case 0x3000: case 0x3001: case 0x3002: case 0x3003: + case 0x4000: case 0x4001: case 0x4002: case 0x4003: + case 0x5000: case 0x5001: case 0x5002: case 0x5003: + case 0x6000: case 0x6001: case 0x6002: case 0x6003: + bank = (((offset - 0x3000) >> 11) | (offset & 0x1)) & 0x7; + if (offset & 2) + m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & 0x0f) | ((data & 0x0f) << 4); + else + m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & 0xf0) | ((data & 0x0f) << 0); + chr1_x(bank, m_mmc_vrom_bank[bank], m_chr_source); + break; + case 0x7000: + m_irq_count = (m_irq_count & 0xf0) | (data & 0x0f); + break; + case 0x7001: + case 0x7003: + m_irq_enable_latch = m_irq_enable; + m_irq_enable = BIT(data, 1); + break; + case 0x7002: + m_irq_count = (m_irq_count & 0x0f) | ((data & 0x0f) << 4); + break; + } +} + + +/*------------------------------------------------- + + UNL-CITYFIGHT + + Games: + + Additional audio register not emulated yet! + + In MESS: Preliminary Supported + + -------------------------------------------------*/ + +void nes_cityfight_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + if (id == TIMER_IRQ) + { + if (m_irq_enable) + { + if (!m_irq_count) + { + m_maincpu->set_input_line(M6502_IRQ_LINE, HOLD_LINE); + m_irq_count = 0xffff; + } + else + m_irq_count--; + } + } +} + +void nes_cityfight_device::update_prg() +{ + prg32(m_prg_reg >> 2); + if (!m_prg_mode) + prg8_cd(m_prg_reg); +} + +WRITE8_MEMBER(nes_cityfight_device::write_h) +{ + int bank; + LOG_MMC(("unl_cityfight write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x700c) + { + case 0x1000: + switch (data & 0x03) + { + case 0x00: set_nt_mirroring(PPU_MIRROR_VERT); break; + case 0x01: set_nt_mirroring(PPU_MIRROR_HORZ); break; + case 0x02: set_nt_mirroring(PPU_MIRROR_LOW); break; + case 0x03: set_nt_mirroring(PPU_MIRROR_HIGH); break; + } + m_prg_reg = data & 0xc; + break; + case 0x1004: + case 0x1008: + case 0x100c: + if (offset & 0x800) + LOG_MMC(("Extended Audio write, data %x!", data & 0x0f));//pcmwrite(0x4011, (V & 0xf) << 3); + else + m_prg_reg = data & 0xc; + break; + + + case 0x2000: case 0x2004: case 0x2008: case 0x200c: + bank = 2 + BIT(offset, 3); + if (offset & 4) + m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & 0x0f) | ((data & 0x0f) << 4); + else + m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & 0xf0) | ((data & 0x0f) << 0); + chr1_x(bank, m_mmc_vrom_bank[bank], m_chr_source); + break; + case 0x3000: case 0x3004: case 0x3008: case 0x300c: + bank = 4 + BIT(offset, 3); + if (offset & 4) + m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & 0x0f) | ((data & 0x0f) << 4); + else + m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & 0xf0) | ((data & 0x0f) << 0); + chr1_x(bank, m_mmc_vrom_bank[bank], m_chr_source); + break; + case 0x5000: case 0x5004: case 0x5008: case 0x500c: + bank = 0 + BIT(offset, 3); + if (offset & 4) + m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & 0x0f) | ((data & 0x0f) << 4); + else + m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & 0xf0) | ((data & 0x0f) << 0); + chr1_x(bank, m_mmc_vrom_bank[bank], m_chr_source); + break; + case 0x6000: case 0x6004: case 0x6008: case 0x600c: + bank = 6 + BIT(offset, 3); + if (offset & 4) + m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & 0x0f) | ((data & 0x0f) << 4); + else + m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & 0xf0) | ((data & 0x0f) << 0); + chr1_x(bank, m_mmc_vrom_bank[bank], m_chr_source); + break; + + case 0x4000: + case 0x4004: + case 0x4008: + case 0x400c: + m_prg_mode = data & 1; + + case 0x7000: + m_irq_count = (m_irq_count & 0x1e0) | ((data & 0x0f) << 1); + break; + case 0x7004: + m_irq_count = (m_irq_count & 0x1e) | ((data & 0x0f) << 5); + break; + case 0x7008: + m_irq_enable = BIT(data, 1); + break; + } +} + + +#ifdef UNUSED_FUNCTION +/*------------------------------------------------- + + FUJIYA Board - mapper 170 according to NEStopia + + Is this possibly for the Fujiya Famikase series + of educational titles? Is there any dump around? + + -------------------------------------------------*/ + +void nes_fujiya_device::device_start() +{ + common_start(); + save_item(NAME(m_latch)); +} + +void nes_fujiya_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(0); + chr8(0, m_chr_source); + + m_latch = 0; +} + +WRITE8_MEMBER(nes_fujiya_device::write_m) +{ + LOG_MMC(("fujiya write_m, offset: %04x, data: %02x\n", offset, data)); + offset += 0x6000; + + if (offset == 0x6502 || offset == 0x7000) + m_latch = (data & 0x40) << 1; +} + +READ8_MEMBER(nes_fujiya_device::read_m) +{ + LOG_MMC(("fujiya read_m, offset: %04x\n", offset)); + offset += 0x6000; + + if (offset == 0x7001 || offset == 0x7777) + return m_latch | ((offset >> 8) & 0x7f); + + return m_open_bus; // open bus +} +#endif diff --git a/src/devices/bus/nes/pirate.h b/src/devices/bus/nes/pirate.h new file mode 100644 index 00000000000..f11c53ced0d --- /dev/null +++ b/src/devices/bus/nes/pirate.h @@ -0,0 +1,399 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __NES_PIR_H +#define __NES_PIR_H + +#include "nxrom.h" + + +// ======================> nes_agci_device + +class nes_agci_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_agci_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); +}; + + +// ======================> nes_dreamtech_device + +class nes_dreamtech_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_dreamtech_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_l); + + virtual void pcb_reset(); +}; + + +// ======================> nes_fukutake_device + +class nes_fukutake_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_fukutake_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_READ8_MEMBER(read_l); + virtual DECLARE_READ8_MEMBER(read_m); + virtual DECLARE_WRITE8_MEMBER(write_l); + virtual DECLARE_WRITE8_MEMBER(write_m); + + virtual void pcb_reset(); + +private: + UINT8 m_latch; + UINT8 m_ram[0xb00]; +}; + + +// ======================> nes_futuremedia_device + +class nes_futuremedia_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_futuremedia_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void hblank_irq(int scanline, int vblank, int blanked); + virtual void pcb_reset(); + +private: + UINT16 m_irq_count, m_irq_count_latch; + UINT8 m_irq_clear; + int m_irq_enable; +}; + + +// ======================> nes_magseries_device + +class nes_magseries_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_magseries_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); +}; + + +// ======================> nes_daou306_device + +class nes_daou306_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_daou306_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); + +private: + UINT8 m_reg[16]; +}; + + +// ======================> nes_subor0_device + +class nes_subor0_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_subor0_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); + +private: + UINT8 m_reg[4]; +}; + + +// ======================> nes_subor1_device + +class nes_subor1_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_subor1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); + +private: + UINT8 m_reg[4]; +}; + + +// ======================> nes_cc21_device + +class nes_cc21_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_cc21_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); +}; + + +// ======================> nes_xiaozy_device + +class nes_xiaozy_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_xiaozy_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_l); + + virtual void pcb_reset(); +}; + + +// ======================> nes_edu2k_device + +class nes_edu2k_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_edu2k_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_READ8_MEMBER(read_m); + virtual DECLARE_WRITE8_MEMBER(write_m); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); + +private: + UINT8 m_latch; +}; + + +// ======================> nes_t230_device + +class nes_t230_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_t230_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void hblank_irq(int scanline, int vblank, int blanked); + virtual void pcb_reset(); + +private: + UINT16 m_irq_count, m_irq_count_latch; + UINT8 m_irq_mode; + int m_irq_enable, m_irq_enable_latch; + + UINT8 m_mmc_vrom_bank[8]; +}; + + +// ======================> nes_mk2_device + +class nes_mk2_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_mk2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_m); + + virtual void hblank_irq(int scanline, int vblank, int blanked); + virtual void pcb_reset(); + +private: + UINT16 m_irq_count, m_irq_count_latch; + UINT8 m_irq_clear; + int m_irq_enable; +}; + + +// ======================> nes_whero_device + +class nes_whero_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_whero_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void hblank_irq(int scanline, int vblank, int blanked); + virtual void pcb_reset(); + +private: + UINT8 m_reg; + UINT8 m_mmc_vrom_bank[8]; + + UINT16 m_irq_count, m_irq_count_latch; + int m_irq_enable, m_irq_enable_latch; +// int m_irq_mode; +}; + + +// ======================> nes_43272_device + +class nes_43272_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_43272_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_READ8_MEMBER(read_h); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); + +private: + UINT16 m_latch; +}; + + +// ======================> nes_tf1201_device + +class nes_tf1201_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_tf1201_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void hblank_irq(int scanline, int vblank, int blanked); + virtual void pcb_reset(); + +private: + void update_prg(); + UINT8 m_prg, m_swap; + UINT16 m_irq_count; + int m_irq_enable, m_irq_enable_latch; + + UINT8 m_mmc_vrom_bank[8]; +}; + + +// ======================> nes_cityfight_device + +class nes_cityfight_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_cityfight_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); + +private: + void update_prg(); + UINT8 m_prg_reg, m_prg_mode; + UINT16 m_irq_count; + int m_irq_enable; + + static const device_timer_id TIMER_IRQ = 0; + emu_timer *irq_timer; + + UINT8 m_mmc_vrom_bank[8]; +}; + + + +#ifdef UNUSED_FUNCTION +// ======================> nes_fujiya_device + +class nes_fujiya_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_fujiya_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(read_m); + virtual DECLARE_WRITE8_MEMBER(write_m); + + virtual void pcb_reset(); + +private: + UINT8 m_latch; +}; +#endif + + +// device type definition +extern const device_type NES_AGCI_50282; +extern const device_type NES_DREAMTECH01; +extern const device_type NES_FUKUTAKE; +extern const device_type NES_FUTUREMEDIA; +extern const device_type NES_MAGSERIES; +extern const device_type NES_DAOU306; +extern const device_type NES_SUBOR0; +extern const device_type NES_SUBOR1; +extern const device_type NES_CC21; +extern const device_type NES_XIAOZY; +extern const device_type NES_EDU2K; +extern const device_type NES_T230; +extern const device_type NES_MK2; +extern const device_type NES_WHERO; +extern const device_type NES_43272; +extern const device_type NES_TF1201; +extern const device_type NES_CITYFIGHT; +extern const device_type NES_FUJIYA; + +#endif diff --git a/src/devices/bus/nes/pt554.c b/src/devices/bus/nes/pt554.c new file mode 100644 index 00000000000..4f6e843d8d1 --- /dev/null +++ b/src/devices/bus/nes/pt554.c @@ -0,0 +1,107 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + NES/Famicom cartridge emulation for Bandai PT-554 PCBs + + + Here we emulate the following Bandai PT-554 PCB (a CNROM PCB + LPC / PARCOR speech synthesis chip) + + TODO: + - emulate the mat controller + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "pt554.h" + + +#ifdef NES_PCB_DEBUG +#define VERBOSE 1 +#else +#define VERBOSE 0 +#endif + +#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) + + +//------------------------------------------------- +// constructor +//------------------------------------------------- + +const device_type NES_BANDAI_PT554 = &device_creator; + + +nes_bandai_pt554_device::nes_bandai_pt554_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_cnrom_device(mconfig, NES_BANDAI_PT554, "NES Cart Bandai PT-554 PCB", tag, owner, clock, "nes_bandai_pt554", __FILE__), + m_samples(*this, "samples") +{ +} + + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +/*------------------------------------------------- + + Bandai PT-554 board emulation + + This is used by Aerobics Studio. It is basically a CNROM board + with an Mitsubishi M50805 LPC / PARCOR speech synthesis chip + with internal tables stored in ROM which have not yet been dumped. + + iNES: mapper 3? + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_bandai_pt554_device::write_m) +{ + LOG_MMC(("Bandai PT-554 Sound write, data: %02x\n", data)); + + if (!BIT(data, 6)) + m_samples->start(data & 0x07, data & 0x07); + else + m_samples->stop(data & 0x07); +} + +static const char *const pt554_sample_names[] = +{ + "*ftaerobi", + "00", + "01", + "02", + "03", + "04", + "05", + "06", + "07", + 0 +}; + +//------------------------------------------------- +// MACHINE_DRIVER +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( pt554 ) + + // additional sound hardware + MCFG_SPEAKER_STANDARD_MONO("addon") + + MCFG_SOUND_ADD("samples", SAMPLES, 0) + MCFG_SAMPLES_CHANNELS(8) + MCFG_SAMPLES_NAMES(pt554_sample_names) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "addon", 0.50) +MACHINE_CONFIG_END + +//------------------------------------------------- +// machine_config_additions +//------------------------------------------------- + +machine_config_constructor nes_bandai_pt554_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( pt554 ); +} diff --git a/src/devices/bus/nes/pt554.h b/src/devices/bus/nes/pt554.h new file mode 100644 index 00000000000..0d0bd7b60f4 --- /dev/null +++ b/src/devices/bus/nes/pt554.h @@ -0,0 +1,31 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __NES_PT554_H +#define __NES_PT554_H + +#include "nxrom.h" + + +// ======================> nes_bandai_pt554_device + +class nes_bandai_pt554_device : public nes_cnrom_device +{ +public: + // construction/destruction + nes_bandai_pt554_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual DECLARE_WRITE8_MEMBER(write_m); + +private: + required_device m_samples; +}; + + + + +// device type definition +extern const device_type NES_BANDAI_PT554; + +#endif diff --git a/src/devices/bus/nes/racermate.c b/src/devices/bus/nes/racermate.c new file mode 100644 index 00000000000..6989c2254cb --- /dev/null +++ b/src/devices/bus/nes/racermate.c @@ -0,0 +1,92 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + NES/Famicom cartridge emulation for RacerMate PCBs + + + Here we emulate the UNL-RACERMATE PCB [mapper 168] + + TODO: + - save VRAM + - emulate the bike controller? + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "racermate.h" + + +#ifdef NES_PCB_DEBUG +#define VERBOSE 1 +#else +#define VERBOSE 0 +#endif + +#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) + + +//------------------------------------------------- +// constructor +//------------------------------------------------- + +const device_type NES_RACERMATE = &device_creator; + + +nes_racermate_device::nes_racermate_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_RACERMATE, "NES Cart Racermate PCB", tag, owner, clock, "nes_racermate", __FILE__) +{ +} + + + +void nes_racermate_device::device_start() +{ + common_start(); + save_item(NAME(m_latch)); +} + +void nes_racermate_device::pcb_reset() +{ +// m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(m_prg_chunks - 1); + chr4_0(0, CHRRAM); + chr4_4(0, CHRRAM); + + m_latch = 0; +} + + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +/*------------------------------------------------- + + Board UNL-RACERMATE + + In MESS: *VERY* preliminary support. Also, it seems that this + board saves to battery the CHRRAM!!! + + -------------------------------------------------*/ + +void nes_racermate_device::update_banks() +{ + chr4_4(m_latch & 0x0f, m_chr_source); + prg16_89ab(m_latch >> 6); +} + +WRITE8_MEMBER(nes_racermate_device::write_h) +{ + LOG_MMC(("racermate write_h, offset: %04x, data: %02x\n", offset, data)); + + if (offset == 0x3000) + { + m_latch = data; + update_banks(); + } +} diff --git a/src/devices/bus/nes/racermate.h b/src/devices/bus/nes/racermate.h new file mode 100644 index 00000000000..209c2f56601 --- /dev/null +++ b/src/devices/bus/nes/racermate.h @@ -0,0 +1,35 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __NES_RACERMATE_H +#define __NES_RACERMATE_H + +#include "nxrom.h" + + +// ======================> nes_racermate_device + +class nes_racermate_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_racermate_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); + +private: + void update_banks(); + UINT8 m_latch; +}; + + + + + +// device type definition +extern const device_type NES_RACERMATE; + +#endif diff --git a/src/devices/bus/nes/rcm.c b/src/devices/bus/nes/rcm.c new file mode 100644 index 00000000000..28ec6e8277e --- /dev/null +++ b/src/devices/bus/nes/rcm.c @@ -0,0 +1,303 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + NES/Famicom cartridge emulation for RCM PCBs + + + Here we emulate the following PCBs + + * RCM GS2015 [mapper 216] + * RCM GS2004 + * RCM GS2013 + * RCM Tetris Family 9in1 [mapper 61] + * RCM 3D Block + + TODO: + - investigate why 3D Block does not work + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "rcm.h" + +#include "cpu/m6502/m6502.h" + + +#ifdef NES_PCB_DEBUG +#define VERBOSE 1 +#else +#define VERBOSE 0 +#endif + +#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) + + +//------------------------------------------------- +// constructor +//------------------------------------------------- + +const device_type NES_GS2015 = &device_creator; +const device_type NES_GS2004 = &device_creator; +const device_type NES_GS2013 = &device_creator; +const device_type NES_TF9IN1 = &device_creator; +const device_type NES_3DBLOCK = &device_creator; + + +nes_gs2015_device::nes_gs2015_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_GS2015, "NES Cart RCM GS-2015 PCB", tag, owner, clock, "nes_gs2015", __FILE__) +{ +} + +nes_gs2004_device::nes_gs2004_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_GS2004, "NES Cart RCM GS-2004 PCB", tag, owner, clock, "nes_gs2004", __FILE__) +{ +} + +nes_gs2013_device::nes_gs2013_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_GS2013, "NES Cart RCM GS-2013 PCB", tag, owner, clock, "nes_gs2013", __FILE__) +{ +} + +nes_tf9_device::nes_tf9_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_TF9IN1, "NES Cart RCM Tetris Family 9 in 1 PCB", tag, owner, clock, "nes_tetrisfam", __FILE__) +{ +} + +nes_3dblock_device::nes_3dblock_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_3DBLOCK, "NES Cart RCM 3D Block PCB", tag, owner, clock, "nes_3dblock", __FILE__) +{ +} + + + + +void nes_gs2015_device::device_start() +{ + common_start(); +} + +void nes_gs2015_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); +} + +void nes_gs2004_device::device_start() +{ + common_start(); +} + +void nes_gs2004_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0xff); + chr8(0, m_chr_source); +} + +void nes_gs2013_device::device_start() +{ + common_start(); +} + +void nes_gs2013_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0xff); + chr8(0, m_chr_source); +} + +void nes_tf9_device::device_start() +{ + common_start(); +} + +void nes_tf9_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); +} + +void nes_3dblock_device::device_start() +{ + common_start(); + save_item(NAME(m_reg)); + save_item(NAME(m_irq_count)); +} + +void nes_3dblock_device::pcb_reset() +{ + prg32(0); + chr8(0, CHRRAM); + m_reg[0] = 0; + m_reg[1] = 0; + m_reg[2] = 0; + m_reg[3] = 0; + m_irq_count = 0; +} + + + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +/*------------------------------------------------- + + RCM GS2015 Board + + Games: Bonza, Magic Jewelry 2 + + Very simple mapper: writes to 0x8000-0xffff sets prg32 + to offset and chr8 to offset>>1 (when chrrom is present) + + iNES: mapper 216 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_gs2015_device::write_h) +{ + LOG_MMC(("gs2015 write_h, offset: %04x, data: %02x\n", offset, data)); + + prg32(offset); + chr8(offset >> 1, m_chr_source); +} + +READ8_MEMBER(nes_gs2015_device::read_m) +{ + LOG_MMC(("gs2015 read_m, offset: %04x\n", offset)); + return 0; // Videopoker Bonza needs this (sort of protection? or related to inputs?) +} + +/*------------------------------------------------- + + Board BMC-GS2004 + + Games: Tetris Family 6-in-1 + + In MESS: Preliminary Support. It also misses WRAM handling + (we need reads from 0x6000-0x7fff) + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_gs2004_device::write_h) +{ + LOG_MMC(("gs2004 write_h, offset: %04x, data: %02x\n", offset, data)); + + prg32(data); +} + +/*------------------------------------------------- + + Board BMC-GS2013 + + Games: Tetris Family 12-in-1 + + In MESS: Preliminary Support. It also misses WRAM handling + (we need reads from 0x6000-0x7fff) + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_gs2013_device::write_h) +{ + LOG_MMC(("gs2013 write_h, offset: %04x, data: %02x\n", offset, data)); + + if (data & 0x08) + prg32(data & 0x09); + else + prg32(data & 0x07); +} + +/*------------------------------------------------- + + Bootleg Board by RCM for Tetris Family + + Games: Tetris Family 9 in 1, 20 in 1 + + Simple Mapper: prg/chr/nt are swapped depending on the offset + of writes in 0x8000-0xffff. offset&0x80 set NT mirroring, + when (offset&0x30) is 0,3 prg32 is set; when it is 1,2 + two 16k prg banks are set. See below for the values used in + these banks. + + iNES: mapper 61 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_tf9_device::write_h) +{ + LOG_MMC(("tetrisfam write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x30) + { + case 0x00: + case 0x30: + prg32(offset & 0x0f); + break; + case 0x10: + case 0x20: + prg16_89ab(((offset & 0x0f) << 1) | ((offset & 0x20) >> 4)); + prg16_cdef(((offset & 0x0f) << 1) | ((offset & 0x20) >> 4)); + break; + } + set_nt_mirroring(BIT(data, 7) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); +} + +/*------------------------------------------------- + + Bootleg Board by RCM for 3-D Block + + Games: 3-D Block Hwang Shinwei version + + iNES: + + In MESS: Very Preliminary Support. What is the purpose + of the writes to $4800-$4900-$4a00? These writes + also happens on the RCM version, which however works + (probably an unused leftover code in that version) + + FCEUmm suggests it might be IRQ related, but + it does not seem to help much... + + -------------------------------------------------*/ + +void nes_3dblock_device::hblank_irq(int scanline, int vblank, int blanked) +{ + if (m_irq_count) + { + m_irq_count--; + if (!m_irq_count) + m_maincpu->set_input_line(M6502_IRQ_LINE, HOLD_LINE); + } +} + +WRITE8_MEMBER(nes_3dblock_device::write_l) +{ + LOG_MMC(("3dblock write_l, offset: %04x, data: %02x\n", offset, data)); + offset += 0x100; + + switch (offset) + { + case 0x800: // $4800 + m_reg[0] = data; + break; + case 0x900: // $4900 + m_reg[1] = data; + break; + case 0xa00: // $4a00 + m_reg[2] = data; + break; + case 0xe00: // $4e00 + m_reg[3] = data; m_irq_count = 0x10; + break; + } +} diff --git a/src/devices/bus/nes/rcm.h b/src/devices/bus/nes/rcm.h new file mode 100644 index 00000000000..4a5c05b6aa9 --- /dev/null +++ b/src/devices/bus/nes/rcm.h @@ -0,0 +1,105 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __NES_RCM_H +#define __NES_RCM_H + +#include "nxrom.h" + + +// ======================> nes_gs2015_device + +class nes_gs2015_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_gs2015_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_READ8_MEMBER(read_l) { return read_m(space, offset, mem_mask); } + virtual DECLARE_READ8_MEMBER(read_m); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); +}; + + +// ======================> nes_gs2004_device + +class nes_gs2004_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_gs2004_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); +}; + + +// ======================> nes_gs2013_device + +class nes_gs2013_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_gs2013_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); +}; + + +// ======================> nes_tf9_device + +class nes_tf9_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_tf9_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); +}; + + +// ======================> nes_3dblock_device + +class nes_3dblock_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_3dblock_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_l); + + virtual void hblank_irq(int scanline, int vblank, int blanked); + virtual void pcb_reset(); + +private: + UINT8 m_reg[4]; + UINT8 m_irq_count; +}; + + + + +// device type definition +extern const device_type NES_GS2015; +extern const device_type NES_GS2004; +extern const device_type NES_GS2013; +extern const device_type NES_TF9IN1; +extern const device_type NES_3DBLOCK; + +#endif diff --git a/src/devices/bus/nes/rexsoft.c b/src/devices/bus/nes/rexsoft.c new file mode 100644 index 00000000000..c0e261dc5fa --- /dev/null +++ b/src/devices/bus/nes/rexsoft.c @@ -0,0 +1,262 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + NES/Famicom cartridge emulation for Rex Soft PCBs + + + Here we emulate the following PCBs + + * Rex Soft DragonBall Z V [mapper 12] + * Rex Soft SL-1632 [mapper 14] + + TODO: + - fix 0x6000-0x7fff accesses, write_m/read_m + - check glitches in SL-1632 + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "rexsoft.h" + + +#ifdef NES_PCB_DEBUG +#define VERBOSE 1 +#else +#define VERBOSE 0 +#endif + +#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) + + +//------------------------------------------------- +// constructor +//------------------------------------------------- + +const device_type NES_REX_DBZ5 = &device_creator; +const device_type NES_REX_SL1632 = &device_creator; + + +nes_rex_dbz5_device::nes_rex_dbz5_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_txrom_device(mconfig, NES_REX_DBZ5, "NES Cart Rex Soft DragonBall Z V PCB", tag, owner, clock, "nes_rex_dbz5", __FILE__) +{ +} + +nes_rex_sl1632_device::nes_rex_sl1632_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_txrom_device(mconfig, NES_REX_SL1632, "NES Cart Rex Soft SL-1632 PCB", tag, owner, clock, "nes_rex_sl1632", __FILE__) +{ +} + + + + +void nes_rex_dbz5_device::device_start() +{ + mmc3_start(); + save_item(NAME(m_extra)); +} + +void nes_rex_dbz5_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + m_extra = 0; + mmc3_common_initialize(0xff, 0xff, 0); +} + +void nes_rex_sl1632_device::device_start() +{ + mmc3_start(); + save_item(NAME(m_mode)); + save_item(NAME(m_mirror)); + save_item(NAME(m_extra_bank)); +} + +void nes_rex_sl1632_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + + m_mode = 0; + m_mirror = 0; + memset(m_extra_bank, 0, sizeof(m_extra_bank)); + m_extra_bank[2] = 0xfe; + m_extra_bank[3] = 0xff; + mmc3_common_initialize(0xff, 0xff, 0); +} + + + + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +/*------------------------------------------------- + + Bootleg Board by Rex Soft + + Games: Dragon Ball Z 5, Dragon Ball Z Super + + MMC3 clone. Writes to 0x4100-0x5fff (or from 0x4020?) + possibly select higher VROM pages (to allow up to + 512 banks instead of 256 only): bit0 selects the + higher pages for PPU banks 0-3 (0x0000-0x0fff), while + bit4 selects the higher pages for PPU banks 4-7 (0x1000-0x1fff) + + iNES: mapper 12 + + In MESS: Supported + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_rex_dbz5_device::write_l) +{ + LOG_MMC(("rex_dbz write_l, offset: %04x, data: %02x\n", offset, data)); + + m_extra = data; + set_chr(m_chr_source, m_chr_base, m_chr_mask); +} + +/* we would need to use this read handler in 0x6000-0x7fff as well */ +READ8_MEMBER(nes_rex_dbz5_device::read_l) +{ + LOG_MMC(("rex_dbz read_l, offset: %04x\n", offset)); + return 0x01; +} + +void nes_rex_dbz5_device::chr_cb(int start, int bank, int source) +{ + int shift = (start < 4) ? 8 : 4; + + bank |= ((m_extra << shift) & 0x100); + chr1_x(start, bank, source); +} + +/*------------------------------------------------- + + Rex Soft SL1632 Board + + Games: Samurai Spirits + + MMC3 clone + + iNES: mapper 14 + + In MESS: Supported + + -------------------------------------------------*/ + +void nes_rex_sl1632_device::set_prg(int prg_base, int prg_mask) +{ + if (m_mode & 0x02) + { + // here standard MMC3 bankswitch + UINT8 prg_flip = (m_latch & 0x40) ? 2 : 0; + + prg_cb(0, prg_base | (m_mmc_prg_bank[0 ^ prg_flip] & prg_mask)); + prg_cb(1, prg_base | (m_mmc_prg_bank[1] & prg_mask)); + prg_cb(2, prg_base | (m_mmc_prg_bank[2 ^ prg_flip] & prg_mask)); + prg_cb(3, prg_base | (m_mmc_prg_bank[3] & prg_mask)); + } + else + { + prg8_89(m_extra_bank[0]); + prg8_ab(m_extra_bank[1]); + prg8_cd(m_extra_bank[2]); + prg8_ef(m_extra_bank[3]); + } +} + +void nes_rex_sl1632_device::set_chr(UINT8 chr, int chr_base, int chr_mask) +{ + static const UINT8 conv_table[8] = {5, 5, 5, 5, 3, 3, 1, 1}; + UINT8 chr_page = (m_latch & 0x80) >> 5; + UINT8 bank[8]; + UINT8 chr_base2[8]; + + if (m_mode & 0x02) + { + for (int i = 0; i < 8; i++) + { + // since the mapper acts on 1K CHR chunks, we have 8 banks which use the 6 m_mmc_vrom_bank from MMC3 base class + if (i < 4) + bank[i] = ((m_mmc_vrom_bank[i / 2] & 0xfe) | (i & 1)); + else + bank[i] = m_mmc_vrom_bank[i - 2]; + chr_base2[i] = chr_base | ((m_mode << conv_table[i]) & 0x100); + } + } + else + { + for (int i = 0; i < 8; i++) + { + bank[i] = m_extra_bank[i + 4]; // first 4 m_extra_banks are PRG + chr_base2[i] = chr_base; + } + } + + chr1_x(chr_page ^ 0, chr_base2[0] | (bank[0] & chr_mask), chr); + chr1_x(chr_page ^ 1, chr_base2[1] | (bank[1] & chr_mask), chr); + chr1_x(chr_page ^ 2, chr_base2[2] | (bank[2] & chr_mask), chr); + chr1_x(chr_page ^ 3, chr_base2[3] | (bank[3] & chr_mask), chr); + chr1_x(chr_page ^ 4, chr_base2[4] | (bank[4] & chr_mask), chr); + chr1_x(chr_page ^ 5, chr_base2[5] | (bank[5] & chr_mask), chr); + chr1_x(chr_page ^ 6, chr_base2[6] | (bank[6] & chr_mask), chr); + chr1_x(chr_page ^ 7, chr_base2[7] | (bank[7] & chr_mask), chr); +} + +WRITE8_MEMBER(nes_rex_sl1632_device::write_h) +{ + UINT8 helper1, helper2; + LOG_MMC(("rex_sl1632 write_h, offset: %04x, data: %02x\n", offset, data)); + + if (offset == 0x2131) + { + m_mode = data; + set_prg(m_prg_base, m_prg_mask); + set_chr(m_chr_source, m_chr_base, m_chr_mask); + + if (!(m_mode & 0x02)) + set_nt_mirroring(BIT(m_mirror, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + } + + if (m_mode & 0x02) + { + switch (offset & 0x6001) + { + case 0x2000: + set_nt_mirroring(BIT(m_mirror, 0) ? PPU_MIRROR_VERT : PPU_MIRROR_HORZ); + break; + + default: + txrom_write(space, offset, data, mem_mask); + break; + } + } + else if (offset >= 0x3000 && offset <= 0x6003) + { + helper1 = (offset & 0x01) << 2; + offset = ((offset & 0x02) | (offset >> 10)) >> 1; + helper2 = ((offset + 2) & 0x07) + 4; // '+4' because first 4 m_extra_banks are for PRG! + m_extra_bank[helper2] = (m_extra_bank[helper2] & (0xf0 >> helper1)) | ((data & 0x0f) << helper1); + set_chr(m_chr_source, m_chr_base, m_chr_mask); + } + else + { + switch (offset & 0x7003) + { + case 0x0000: + case 0x2000: + m_extra_bank[offset >> 13] = data; + set_prg(m_prg_base, m_prg_mask); + break; + + case 0x1000: + m_mirror = data; + set_nt_mirroring(BIT(m_mirror, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + break; + } + } +} diff --git a/src/devices/bus/nes/rexsoft.h b/src/devices/bus/nes/rexsoft.h new file mode 100644 index 00000000000..81527759574 --- /dev/null +++ b/src/devices/bus/nes/rexsoft.h @@ -0,0 +1,61 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __NES_REXSOFT_H +#define __NES_REXSOFT_H + +#include "mmc3.h" + + +// ======================> nes_rex_dbz5_device + +class nes_rex_dbz5_device : public nes_txrom_device +{ +public: + // construction/destruction + nes_rex_dbz5_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_READ8_MEMBER(read_l); + virtual DECLARE_READ8_MEMBER(read_m) { return read_l(space, offset, mem_mask); } + virtual DECLARE_WRITE8_MEMBER(write_l); + virtual void chr_cb( int start, int bank, int source ); + + virtual void pcb_reset(); + +private: + UINT8 m_extra; +}; + + +// ======================> nes_rex_sl1632_device + +class nes_rex_sl1632_device : public nes_txrom_device +{ +public: + // construction/destruction + nes_rex_sl1632_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); + +protected: + virtual void set_prg(int prg_base, int prg_mask); + virtual void set_chr(UINT8 chr, int chr_base, int chr_mask); + + UINT8 m_mode, m_mirror; + UINT8 m_extra_bank[12]; +}; + + + + + +// device type definition +extern const device_type NES_REX_DBZ5; +extern const device_type NES_REX_SL1632; + +#endif diff --git a/src/devices/bus/nes/sachen.c b/src/devices/bus/nes/sachen.c new file mode 100644 index 00000000000..87edbc6a700 --- /dev/null +++ b/src/devices/bus/nes/sachen.c @@ -0,0 +1,695 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + NES/Famicom cartridge emulation for Sachen PCBs + + + Here we emulate the following PCBs + + * Sachen SA-009 [mapper 160] + * Sachen SA-0036 [mapper 148] + * Sachen SA-0037 [mapper 149] + * Sachen SA-72007 [mapper 145] + * Sachen SA-72008 [mapper 133] + * Sachen TCA-01 [mapper 143] + * Sachen TCU-01 [mapper 147] + * Sachen TCU-02 [mapper 136] + * Sachen Discrete PCBs [mapper 150 & 243] + * Sachen 8259 [mapper 141 (A), 138 (B), 139 (C), 137 (D)] + + Known issues on specific mappers: + + * 133 Qi Wang starts with corrupted graphics (ingame seems better) + + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "sachen.h" + + +#ifdef NES_PCB_DEBUG +#define VERBOSE 1 +#else +#define VERBOSE 0 +#endif + +#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) + + +//------------------------------------------------- +// constructor +//------------------------------------------------- + +const device_type NES_SACHEN_SA009 = &device_creator; +const device_type NES_SACHEN_SA0036 = &device_creator; +const device_type NES_SACHEN_SA0037 = &device_creator; +const device_type NES_SACHEN_SA72007 = &device_creator; +const device_type NES_SACHEN_SA72008 = &device_creator; +const device_type NES_SACHEN_TCA01 = &device_creator; +const device_type NES_SACHEN_TCU01 = &device_creator; +const device_type NES_SACHEN_TCU02 = &device_creator; +const device_type NES_SACHEN_74X374 = &device_creator; +const device_type NES_SACHEN_74X374_ALT = &device_creator; +const device_type NES_SACHEN_8259A = &device_creator; +const device_type NES_SACHEN_8259B = &device_creator; +const device_type NES_SACHEN_8259C = &device_creator; +const device_type NES_SACHEN_8259D = &device_creator; + + +nes_sachen_sa009_device::nes_sachen_sa009_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_SACHEN_SA009, "NES Cart Sachen SA009 PCB", tag, owner, clock, "nes_sa009", __FILE__) +{ +} + +nes_sachen_sa0036_device::nes_sachen_sa0036_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_SACHEN_SA0036, "NES Cart Sachen sa0036 PCB", tag, owner, clock, "nes_sa0036", __FILE__) +{ +} + +nes_sachen_sa0037_device::nes_sachen_sa0037_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_SACHEN_SA0037, "NES Cart Sachen sa0037 PCB", tag, owner, clock, "nes_sa0037", __FILE__) +{ +} + +nes_sachen_sa72007_device::nes_sachen_sa72007_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_SACHEN_SA72007, "NES Cart Sachen SA72007 PCB", tag, owner, clock, "nes_sa72007", __FILE__) +{ +} + +nes_sachen_sa72008_device::nes_sachen_sa72008_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_SACHEN_SA72008, "NES Cart Sachen SA72008 PCB", tag, owner, clock, "nes_sa72008", __FILE__) +{ +} + +nes_sachen_tca01_device::nes_sachen_tca01_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_SACHEN_TCA01, "NES Cart Sachen TCA-01 PCB", tag, owner, clock, "nes_tca01", __FILE__) +{ +} + +nes_sachen_tcu01_device::nes_sachen_tcu01_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_SACHEN_TCU01, "NES Cart Sachen TCU-01 PCB", tag, owner, clock, "nes_tcu01", __FILE__) +{ +} + +nes_sachen_tcu02_device::nes_sachen_tcu02_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_SACHEN_TCU02, "NES Cart Sachen TCU-02 PCB", tag, owner, clock, "nes_tcu02", __FILE__) +{ +} + +nes_sachen_74x374_device::nes_sachen_74x374_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : nes_nrom_device(mconfig, type, name, tag, owner, clock, shortname, source) +{ +} + +nes_sachen_74x374_device::nes_sachen_74x374_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_SACHEN_74X374, "NES Cart Sachen 74*374 PCB", tag, owner, clock, "nes_s74x34", __FILE__) +{ +} + +nes_sachen_74x374_alt_device::nes_sachen_74x374_alt_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_sachen_74x374_device(mconfig, NES_SACHEN_74X374_ALT, "NES Cart Sachen 74*374 Alt PCB", tag, owner, clock, "nes_s74x34a", __FILE__) +{ +} + +nes_sachen_8259a_device::nes_sachen_8259a_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : nes_sachen_74x374_device(mconfig, type, name, tag, owner, clock, shortname, source) +{ +} + +nes_sachen_8259a_device::nes_sachen_8259a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_sachen_74x374_device(mconfig, NES_SACHEN_8259A, "NES Cart Sachen 8259A PCB", tag, owner, clock, "nes_s8259a", __FILE__) +{ +} + +nes_sachen_8259b_device::nes_sachen_8259b_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_sachen_8259a_device(mconfig, NES_SACHEN_8259B, "NES Cart Sachen 8259B PCB", tag, owner, clock, "nes_s8259b", __FILE__) +{ +} + +nes_sachen_8259c_device::nes_sachen_8259c_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_sachen_8259a_device(mconfig, NES_SACHEN_8259C, "NES Cart Sachen 8259C PCB", tag, owner, clock, "nes_s8259c", __FILE__) +{ +} + +nes_sachen_8259d_device::nes_sachen_8259d_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_sachen_8259a_device(mconfig, NES_SACHEN_8259D, "NES Cart Sachen 8259D PCB", tag, owner, clock, "nes_s8259d", __FILE__) +{ +} + + + + +void nes_sachen_sa009_device::device_start() +{ + common_start(); +} + +void nes_sachen_sa009_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); +} + +void nes_sachen_sa0036_device::device_start() +{ + common_start(); +} + +void nes_sachen_sa0036_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); +} + +void nes_sachen_sa0037_device::device_start() +{ + common_start(); +} + +void nes_sachen_sa0037_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); +} + +void nes_sachen_sa72007_device::device_start() +{ + common_start(); +} + +void nes_sachen_sa72007_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); +} + +void nes_sachen_sa72008_device::device_start() +{ + common_start(); +} + +void nes_sachen_sa72008_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); +} + +void nes_sachen_tca01_device::device_start() +{ + common_start(); +} + +void nes_sachen_tca01_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(1); + chr8(0, m_chr_source); +} + +void nes_sachen_tcu01_device::device_start() +{ + common_start(); +} + +void nes_sachen_tcu01_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); +} + +void nes_sachen_tcu02_device::device_start() +{ + common_start(); + save_item(NAME(m_latch)); +} + +void nes_sachen_tcu02_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); + + m_latch = 0; +} + +void nes_sachen_74x374_device::device_start() +{ + common_start(); + save_item(NAME(m_latch)); + save_item(NAME(m_mmc_vrom_bank)); +} + +void nes_sachen_74x374_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); + + m_latch = 0; + m_mmc_vrom_bank = 0; +} + +void nes_sachen_8259a_device::device_start() +{ + common_start(); + save_item(NAME(m_latch)); + save_item(NAME(m_reg)); +} + +void nes_sachen_8259a_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); + set_nt_mirroring(PPU_MIRROR_VERT); + + m_latch = 0; + memset(m_reg, 0, sizeof(m_reg)); +} + +void nes_sachen_8259d_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(m_vrom_chunks - 1, CHRROM); + set_nt_mirroring(PPU_MIRROR_VERT); + + m_latch = 0; + memset(m_reg, 0, sizeof(m_reg)); +} + + + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +/*------------------------------------------------- + + Sachen SA009 bootleg boards + + Games: Pipe 5 + + iNES: mapper 160 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_sachen_sa009_device::write_l) +{ + LOG_MMC(("SA009 write_l, offset: %04x, data: %02x\n", offset, data)); + + chr8(data, m_chr_source); +} + +/*------------------------------------------------- + + Sachen SA0036 bootleg boards + + Games: Taiwan Mahjong 16 + + iNES: mapper 149 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_sachen_sa0036_device::write_h) +{ + LOG_MMC(("sa0036 write_h, offset: %04x, data: %02x\n", offset, data)); + + chr8(data >> 7, CHRROM); +} + +/*------------------------------------------------- + + Sachen SA0037 bootleg boards + + Games: Mahjong World, Shisen Mahjong + + iNES: mapper 148 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_sachen_sa0037_device::write_h) +{ + LOG_MMC(("sa0037 write_h, offset: %04x, data: %02x\n", offset, data)); + + // this pcb is subject to bus conflict + data = account_bus_conflict(offset, data); + + prg32(data >> 3); + chr8(data, CHRROM); +} + +/*------------------------------------------------- + + Sachen SA72007 bootleg boards + + Games: Sidewinder + + iNES: mapper 145 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_sachen_sa72007_device::write_l) +{ + LOG_MMC(("SA72007 write_l, offset: %04x, data: %02x\n", offset, data)); + + /* only if we are at 0x4100 + k * 0x200, but 0x4100 is offset = 0 */ + if (!(offset & 0x100)) + chr8(data >> 7, CHRROM); +} + +/*------------------------------------------------- + + Sachen SA72008 bootleg boards + + Games: Jovial Race, Qi Wang + + iNES: mapper 133 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_sachen_sa72008_device::write_l) +{ + LOG_MMC(("SA72008 write_l, offset: %04x, data: %02x\n", offset, data)); + + prg32(data >> 2); + chr8(data, CHRROM); +} + +/*------------------------------------------------- + + Sachen TCA-01 bootleg boards + + iNES: mapper 143 + + Games: Dancing Blocks, Magic Mathematic + + In MESS: Supported. + + -------------------------------------------------*/ + +READ8_MEMBER(nes_sachen_tca01_device::read_l) +{ + LOG_MMC(("TCA-01 read_l, offset: %04x\n", offset)); + + /* the address is read only if we are at 0x4100 + k * 0x200, but 0x4100 is offset = 0 */ + if (!(offset & 0x100)) + return (~offset & 0x3f) | 0x40; + else + return 0x00; +} + +/*------------------------------------------------- + + Sachen TCU-01 bootleg boards + + Games: Challenge of the Dragon, Chinese Kungfu + + iNES: mapper 147 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_sachen_tcu01_device::write_l) +{ + LOG_MMC(("TCU-01 write_l, offset: %04x, data: %02x\n", offset, data)); + + if ((offset & 0x103) == 0x002) + { + prg32(((data >> 6) & 0x02) | ((data >> 2) & 0x01)); + chr8(data >> 3, CHRROM); + } +} + +/*------------------------------------------------- + + Sachen TCU-02 bootleg boards + + Games: Wei Lai Xiao Zi + + iNES: mapper 136 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_sachen_tcu02_device::write_l) +{ + LOG_MMC(("TCU-02 write_l, offset: %04x, data: %02x\n", offset, data)); + + if ((offset & 0x103) == 0x002) + { + m_latch = (data & 0x30) | ((data + 3) & 0x0f); + chr8(m_latch, CHRROM); + } +} + +READ8_MEMBER(nes_sachen_tcu02_device::read_l) +{ + LOG_MMC(("TCU-02 read_l, offset: %04x\n", offset)); + + if ((offset & 0x103) == 0x000) + return m_latch | 0x40; + else + return 0x00; +} + +/*------------------------------------------------- + + Sachen 74x374 bootleg boards + + Games: Chess Academy, Chinese Checkers Jpn, Mahjong Academy, + Olympic IQ, Poker II, Tasac [150], Poker III [243] + + iNES: mappers 150 & 243 + + -------------------------------------------------*/ + +void nes_sachen_74x374_device::set_mirror(UINT8 nt) // also used by mappers 137, 138, 139, 141 +{ + switch (nt) + { + case 0: + case 1: + set_nt_mirroring(nt ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + break; + case 2: + set_nt_page(0, CIRAM, 0, 1); + set_nt_page(1, CIRAM, 1, 1); + set_nt_page(2, CIRAM, 1, 1); + set_nt_page(3, CIRAM, 1, 1); + break; + case 3: + set_nt_mirroring(PPU_MIRROR_LOW); + break; + default: + LOG_MMC(("Mapper set NT to invalid value %02x", nt)); + break; + } +} + + +WRITE8_MEMBER(nes_sachen_74x374_device::write_l) +{ + LOG_MMC(("Sachen 74*374 write_l, offset: %04x, data: %02x\n", offset, data)); + + /* write happens only if we are at 0x4100 + k * 0x200, but 0x4100 is offset = 0 */ + if (!(offset & 0x100)) + { + if (!(offset & 0x01)) + m_latch = data & 0x07; + else + { + switch (m_latch) + { + case 0x02: + m_mmc_vrom_bank = (m_mmc_vrom_bank & ~0x08) | ((data << 3) & 0x08); + chr8(m_mmc_vrom_bank, CHRROM); + prg32(data & 0x01); + break; + case 0x04: + m_mmc_vrom_bank = (m_mmc_vrom_bank & ~0x04) | ((data << 2) & 0x04); + chr8(m_mmc_vrom_bank, CHRROM); + break; + case 0x05: + prg32(data & 0x07); + break; + case 0x06: + m_mmc_vrom_bank = (m_mmc_vrom_bank & ~0x03) | ((data << 0) & 0x03); + chr8(m_mmc_vrom_bank, CHRROM); + break; + case 0x07: + set_mirror((data >> 1) & 0x03); + break; + default: + break; + } + } + } +} + +READ8_MEMBER(nes_sachen_74x374_device::read_l) +{ + LOG_MMC(("Sachen 74*374 read_l, offset: %04x", offset)); + + /* read happens only if we are at 0x4100 + k * 0x200, but 0x4100 is offset = 0 */ + if (!(offset & 0x100)) + return (~m_latch & 0x3f) /* ^ dips*/; // we would need to check the Dips here + else + return 0; +} + +WRITE8_MEMBER(nes_sachen_74x374_alt_device::write_l) +{ + LOG_MMC(("Sachen 74*374 Alt write_l, offset: %04x, data: %02x\n", offset, data)); + + /* write happens only if we are at 0x4100 + k * 0x200, but 0x4100 is offset = 0 */ + if (!(offset & 0x100)) + { + if (!(offset & 0x01)) + m_latch = data; + else + { + switch (m_latch & 0x07) + { + case 0x00: + prg32(0); + chr8(3, CHRROM); + break; + case 0x02: + m_mmc_vrom_bank = (m_mmc_vrom_bank & ~0x08) | ((data << 3) & 0x08); + chr8(m_mmc_vrom_bank, CHRROM); + break; + case 0x04: + m_mmc_vrom_bank = (m_mmc_vrom_bank & ~0x01) | ((data << 0) & 0x01); + chr8(m_mmc_vrom_bank, CHRROM); + break; + case 0x05: + prg32(data & 0x01); + break; + case 0x06: + m_mmc_vrom_bank = (m_mmc_vrom_bank & ~0x06) | ((data << 1) & 0x06); + chr8(m_mmc_vrom_bank, CHRROM); + break; + case 0x07: + set_mirror(BIT(data, 0)); + break; + default: + break; + } + } + } +} + +/*------------------------------------------------- + + Sachen S8259 bootleg boards + + iNES: mapper 141 (A), 138 (B), 139 (C), 137 (D) + + -------------------------------------------------*/ + +void nes_sachen_8259a_device::chr_update() +{ + UINT8 bank_helper1 = m_reg[7] & 0x01; + UINT8 bank_helper2 = (m_reg[4] & 0x07) << 3; + + if (m_chr_source == CHRROM) + { + chr2_0(((m_reg[bank_helper1 ? 0 : 0] & 0x07) | bank_helper2) << 1 | 0, CHRROM); + chr2_2(((m_reg[bank_helper1 ? 0 : 1] & 0x07) | bank_helper2) << 1 | 1, CHRROM); + chr2_4(((m_reg[bank_helper1 ? 0 : 2] & 0x07) | bank_helper2) << 1 | 0, CHRROM); + chr2_6(((m_reg[bank_helper1 ? 0 : 3] & 0x07) | bank_helper2) << 1 | 1, CHRROM); + } +} + +WRITE8_MEMBER(nes_sachen_8259a_device::write_l) +{ + LOG_MMC(("Sachen 8259 write_l, offset: %04x, data: %02x\n", offset, data)); + + /* write happens only if we are at 0x4100 + k * 0x200, but 0x4100 is offset = 0 */ + if (!(offset & 0x100)) + { + if (!(offset & 0x01)) + m_latch = data & 0x07; + else + { + m_reg[m_latch] = data; + + switch (m_latch) + { + case 0x05: + prg32(data); + break; + case 0x07: + set_mirror(BIT(data, 0) ? 0 : (data >> 1) & 0x03); + break; + default: + chr_update(); + break; + } + } + } +} + +void nes_sachen_8259b_device::chr_update() +{ + UINT8 bank_helper1 = m_reg[7] & 0x01; + UINT8 bank_helper2 = (m_reg[4] & 0x07) << 3; + + if (m_chr_source == CHRROM) + { + chr2_0(((m_reg[bank_helper1 ? 0 : 0] & 0x07) | bank_helper2), CHRROM); + chr2_2(((m_reg[bank_helper1 ? 0 : 1] & 0x07) | bank_helper2), CHRROM); + chr2_4(((m_reg[bank_helper1 ? 0 : 2] & 0x07) | bank_helper2), CHRROM); + chr2_6(((m_reg[bank_helper1 ? 0 : 3] & 0x07) | bank_helper2), CHRROM); + } +} + +void nes_sachen_8259c_device::chr_update() +{ + UINT8 bank_helper1 = m_reg[7] & 0x01; + UINT8 bank_helper2 = (m_reg[4] & 0x07) << 3; + + if (m_chr_source == CHRROM) + { + chr2_0(((m_reg[bank_helper1 ? 0 : 0] & 0x07) | bank_helper2) << 2 | 0, CHRROM); + chr2_2(((m_reg[bank_helper1 ? 0 : 1] & 0x07) | bank_helper2) << 2 | 1, CHRROM); + chr2_4(((m_reg[bank_helper1 ? 0 : 2] & 0x07) | bank_helper2) << 2 | 2, CHRROM); + chr2_6(((m_reg[bank_helper1 ? 0 : 3] & 0x07) | bank_helper2) << 2 | 3, CHRROM); + } +} + +void nes_sachen_8259d_device::chr_update() +{ + if (m_chr_source == CHRROM) + { + chr1_0((m_reg[0] & 0x07), CHRROM); + chr1_1((m_reg[1] & 0x07) | (m_reg[4] << 4 & 0x10), CHRROM); + chr1_2((m_reg[2] & 0x07) | (m_reg[4] << 3 & 0x10), CHRROM); + chr1_3((m_reg[3] & 0x07) | (m_reg[4] << 2 & 0x10) | (m_reg[6] << 3 & 0x08), CHRROM); + } +} diff --git a/src/devices/bus/nes/sachen.h b/src/devices/bus/nes/sachen.h new file mode 100644 index 00000000000..d6604578d3a --- /dev/null +++ b/src/devices/bus/nes/sachen.h @@ -0,0 +1,261 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __NES_SACHEN_H +#define __NES_SACHEN_H + +#include "nxrom.h" + + +// ======================> nes_sachen_sa009_device + +class nes_sachen_sa009_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_sachen_sa009_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_l); + + virtual void pcb_reset(); +}; + + +// ======================> nes_sachen_sa0036_device + +class nes_sachen_sa0036_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_sachen_sa0036_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); +}; + + +// ======================> nes_sachen_sa0037_device + +class nes_sachen_sa0037_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_sachen_sa0037_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); +}; + + +// ======================> nes_sachen_sa72007_device + +class nes_sachen_sa72007_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_sachen_sa72007_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_l); + + virtual void pcb_reset(); +}; + + +// ======================> nes_sachen_sa72008_device + +class nes_sachen_sa72008_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_sachen_sa72008_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_l); + + virtual void pcb_reset(); +}; + + +// ======================> nes_sachen_tca01_device + +class nes_sachen_tca01_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_sachen_tca01_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_READ8_MEMBER(read_l); + + virtual void pcb_reset(); +}; + + +// ======================> nes_sachen_tcu01_device + +class nes_sachen_tcu01_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_sachen_tcu01_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_l); + virtual DECLARE_WRITE8_MEMBER(write_m) { write_l(space, (offset + 0x100) & 0xfff, data, mem_mask); } + virtual DECLARE_WRITE8_MEMBER(write_h) { write_l(space, (offset + 0x100) & 0xfff, data, mem_mask); } + + virtual void pcb_reset(); +}; + + +// ======================> nes_sachen_tcu02_device + +class nes_sachen_tcu02_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_sachen_tcu02_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_READ8_MEMBER(read_l); + virtual DECLARE_WRITE8_MEMBER(write_l); + + virtual void pcb_reset(); + +private: + UINT8 m_latch; +}; + + +// ======================> nes_sachen_74x374_device + +class nes_sachen_74x374_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_sachen_74x374_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + nes_sachen_74x374_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_READ8_MEMBER(read_l); + virtual DECLARE_WRITE8_MEMBER(write_l); + + virtual void pcb_reset(); + +protected: + void set_mirror(UINT8 nt); + UINT8 m_latch, m_mmc_vrom_bank; +}; + + +// ======================> nes_sachen_74x374_alt_device + +class nes_sachen_74x374_alt_device : public nes_sachen_74x374_device +{ +public: + // construction/destruction + nes_sachen_74x374_alt_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual DECLARE_READ8_MEMBER(read_l) { return 0xff; } // no read_l here + virtual DECLARE_WRITE8_MEMBER(write_l); +}; + + +// ======================> nes_sachen_8259a_device + +class nes_sachen_8259a_device : public nes_sachen_74x374_device +{ +public: + // construction/destruction + nes_sachen_8259a_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + nes_sachen_8259a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_l); + virtual DECLARE_WRITE8_MEMBER(write_m) { write_l(space, (offset + 0x100) & 0xfff, data, mem_mask); } + + virtual void pcb_reset(); + +protected: + virtual void chr_update(); + UINT8 m_reg[8]; +}; + + +// ======================> nes_sachen_8259b_device + +class nes_sachen_8259b_device : public nes_sachen_8259a_device +{ +public: + // construction/destruction + nes_sachen_8259b_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual void chr_update(); +}; + + +// ======================> nes_sachen_8259c_device + +class nes_sachen_8259c_device : public nes_sachen_8259a_device +{ +public: + // construction/destruction + nes_sachen_8259c_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual void chr_update(); +}; + + +// ======================> nes_sachen_8259d_device + +class nes_sachen_8259d_device : public nes_sachen_8259a_device +{ +public: + // construction/destruction + nes_sachen_8259d_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual void pcb_reset(); + +protected: + virtual void chr_update(); +}; + + + + + +// device type definition +extern const device_type NES_SACHEN_SA009; +extern const device_type NES_SACHEN_SA0036; +extern const device_type NES_SACHEN_SA0037; +extern const device_type NES_SACHEN_SA72007; +extern const device_type NES_SACHEN_SA72008; +extern const device_type NES_SACHEN_TCA01; +extern const device_type NES_SACHEN_TCU01; +extern const device_type NES_SACHEN_TCU02; +extern const device_type NES_SACHEN_74X374; +extern const device_type NES_SACHEN_74X374_ALT; +extern const device_type NES_SACHEN_8259A; +extern const device_type NES_SACHEN_8259B; +extern const device_type NES_SACHEN_8259C; +extern const device_type NES_SACHEN_8259D; + +#endif diff --git a/src/devices/bus/nes/somari.c b/src/devices/bus/nes/somari.c new file mode 100644 index 00000000000..634aad58b68 --- /dev/null +++ b/src/devices/bus/nes/somari.c @@ -0,0 +1,421 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + NES/Famicom cartridge emulation for Somari Team PCBs + + + Here we emulate the Somari Team PCBs [mapper 116] + + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "somari.h" + +#include "cpu/m6502/m6502.h" + + +#ifdef NES_PCB_DEBUG +#define VERBOSE 1 +#else +#define VERBOSE 0 +#endif + +#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) + +#define SOMARI_VRC2_MODE 0 +#define SOMARI_MMC3_MODE 1 +#define SOMARI_MMC1_MODE 2 +#define SOMARI_MMC1_MODE_AGAIN 3 + + +//------------------------------------------------- +// constructor +//------------------------------------------------- + +const device_type NES_SOMARI = &device_creator; + + +nes_somari_device::nes_somari_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_txrom_device(mconfig, NES_SOMARI, "NES Cart Team Somari PCB", tag, owner, clock, "nes_somari", __FILE__) +{ +} + + + +void nes_somari_device::device_start() +{ + common_start(); + save_item(NAME(m_board_mode)); + + // MMC3 + save_item(NAME(m_mmc_prg_bank)); + save_item(NAME(m_mmc_vrom_bank)); + save_item(NAME(m_latch)); + save_item(NAME(m_prg_base)); + save_item(NAME(m_prg_mask)); + save_item(NAME(m_chr_base)); + save_item(NAME(m_chr_mask)); + save_item(NAME(m_mmc3_mirror_reg)); + + save_item(NAME(m_irq_enable)); + save_item(NAME(m_irq_count)); + save_item(NAME(m_irq_count_latch)); + save_item(NAME(m_irq_clear)); + + // MMC1 + save_item(NAME(m_count)); + save_item(NAME(m_mmc1_latch)); + save_item(NAME(m_mmc1_reg)); + + // VRC2 + save_item(NAME(m_vrc_prg_bank)); + save_item(NAME(m_vrc_vrom_bank)); + save_item(NAME(m_vrc_mirror_reg)); +} + +void nes_somari_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); + + m_board_mode = 2; // mode + + // MMC3 + m_prg_base = m_chr_base = 0; + m_prg_mask = 0xff; + m_chr_mask = 0xff; + m_latch = 0; + m_mmc_prg_bank[0] = 0x3c; + m_mmc_prg_bank[1] = 0x3d; + m_mmc_prg_bank[2] = 0x3e; + m_mmc_prg_bank[3] = 0x3f; + m_mmc_vrom_bank[0] = 0x00; + m_mmc_vrom_bank[1] = 0x01; + m_mmc_vrom_bank[2] = 0x04; + m_mmc_vrom_bank[3] = 0x05; + m_mmc_vrom_bank[4] = 0x06; + m_mmc_vrom_bank[5] = 0x07; + m_mmc3_mirror_reg = 0; + + m_alt_irq = 0; + m_irq_enable = 0; + m_irq_count = m_irq_count_latch = 0; + m_irq_clear = 0; + + // MMC1 regs + m_count = 0; + m_mmc1_latch = 0; + m_mmc1_reg[0] = 0x0c; + m_mmc1_reg[1] = 0x00; + m_mmc1_reg[2] = 0x00; + m_mmc1_reg[3] = 0x00; + + // VRC2 regs + m_vrc_prg_bank[0] = 0x00; + m_vrc_prg_bank[1] = 0x01; + for (int i = 0; i < 8; ++i) + m_vrc_vrom_bank[i] = i; + bank_update_switchmode(); + m_vrc_mirror_reg = 0; +} + + + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +/*------------------------------------------------- + + SOMERI TEAM + + iNES: mapper 116 + + + Emulation note about regs in MESS: currently, + - m_mmc_prg_bank[n] for n=0,...,3 represent the MMC3 PRG banks (inherited from base class) + - m_mmc_vrom_bank[n] for n=0,...,5 represent the MMC3 CHR banks (inherited from base class) + + - m_mmc1_reg[n] for n=0,1,2,3 represent the MMC1 regs + - m_count and m_mmc1_latch are additional variables for MMC1 (notice that MMC3 uses a diff m_latch!) + + - m_vrc_prg_bank[n] for n=0,1 represent the VRC2 PRG banks + - m_vrc_vrom_bank[n] for n=0,...,7 represent the VRC2 CHR banks + + + In MESS: Preliminary support + + -------------------------------------------------*/ + +// MMC1 Mode emulation +WRITE8_MEMBER(nes_somari_device::mmc1_w) +{ + assert(m_board_mode == 2); + + if (data & 0x80) + { + m_count = 0; + m_mmc1_latch = 0; + + m_mmc1_reg[0] |= 0x0c; + update_prg(); + return; + } + + if (m_count < 5) + { + if (m_count == 0) m_mmc1_latch = 0; + m_mmc1_latch >>= 1; + m_mmc1_latch |= (data & 0x01) ? 0x10 : 0x00; + m_count++; + } + + if (m_count == 5) + { + m_mmc1_reg[(offset & 0x6000) >> 13] = m_mmc1_latch; + update_mirror(); + update_prg(); + update_chr(); + + m_count = 0; + } +} + +// MMC3 Mode emulation +WRITE8_MEMBER(nes_somari_device::mmc3_w) +{ + UINT8 mmc_helper, cmd; + + assert(m_board_mode == 1); + + switch (offset & 0x6001) + { + case 0x0000: + mmc_helper = m_latch ^ data; + m_latch = data; + + if (mmc_helper & 0x40) + update_prg(); + + if (mmc_helper & 0x80) + update_chr(); + break; + + case 0x0001: + cmd = m_latch & 0x07; + switch (cmd) + { + case 0: case 1: + case 2: case 3: case 4: case 5: + m_mmc_vrom_bank[cmd] = data; + update_chr(); + break; + case 6: + case 7: + m_mmc_prg_bank[cmd - 6] = data & 0x3f; + update_prg(); + break; + } + break; + + case 0x2000: + m_mmc3_mirror_reg = data & 1; + update_mirror(); + break; + case 0x2001: break; + case 0x4000: m_irq_count_latch = data; break; + case 0x4001: m_irq_count = 0; break; + case 0x6000: m_irq_enable = 0; m_maincpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE); break; + case 0x6001: m_irq_enable = 1; break; + } +} + +// VRC2 Mode emulation +WRITE8_MEMBER(nes_somari_device::vrc2_w) +{ + UINT8 bank, shift; + + assert(m_board_mode == 0); + + switch (offset & 0x7000) + { + case 0x0000: + m_vrc_prg_bank[0] = data & 0x1f; + update_prg(); + break; + + case 0x1000: + m_vrc_mirror_reg = data & 1; + update_mirror(); + break; + + case 0x2000: + m_vrc_prg_bank[1] = data & 0x1f; + update_prg(); + break; + + case 0x3000: + case 0x4000: + case 0x5000: + case 0x6000: + // this makes no sense for vrc2 and breaks somari, but it's ok for garousp!! + bank = ((offset & 0x7000) - 0x3000) / 0x0800 + BIT(offset, 1); + shift = BIT(offset, 2) * 4; + data = (data & 0x0f) << shift; + m_vrc_vrom_bank[bank] = data; + + update_chr(); + break; + } +} + + +void nes_somari_device::update_prg() +{ + switch (m_board_mode) + { + case SOMARI_VRC2_MODE: + prg8_89(m_vrc_prg_bank[0]); + prg8_ab(m_vrc_prg_bank[1]); + prg8_cd(0x3e); + prg8_ef(0x3f); + break; + case SOMARI_MMC3_MODE: + { + UINT8 prg_flip = (m_latch & 0x40) ? 2 : 0; + prg8_x(0, m_mmc_prg_bank[0 ^ prg_flip]); + prg8_x(1, m_mmc_prg_bank[1]); + prg8_x(2, m_mmc_prg_bank[2 ^ prg_flip]); + prg8_x(3, m_mmc_prg_bank[3]); + } + break; + case SOMARI_MMC1_MODE: +// case SOMARI_MMC1_MODE_AGAIN: + { + UINT8 prg_offset = m_mmc1_reg[1] & 0x10; + + switch (m_mmc1_reg[0] & 0x0c) + { + case 0x00: + case 0x04: + prg32((prg_offset + m_mmc1_reg[3]) >> 1); + break; + case 0x08: + prg16_89ab(prg_offset + 0); + prg16_cdef(prg_offset + m_mmc1_reg[3]); + break; + case 0x0c: + prg16_89ab(prg_offset + m_mmc1_reg[3]); + prg16_cdef(prg_offset + 0x0f); + break; + } + } + break; + } +} + +void nes_somari_device::update_chr() +{ + switch (m_board_mode) + { + case SOMARI_VRC2_MODE: + for (int i = 0; i < 8; i++) + chr1_x(i, m_chr_base | m_vrc_vrom_bank[i], CHRROM); + break; + case SOMARI_MMC3_MODE: + { + UINT8 chr_page = (m_latch & 0x80) >> 5; + chr1_x(chr_page ^ 0, m_chr_base | ((m_mmc_vrom_bank[0] & ~0x01)), CHRROM); + chr1_x(chr_page ^ 1, m_chr_base | ((m_mmc_vrom_bank[0] | 0x01)), CHRROM); + chr1_x(chr_page ^ 2, m_chr_base | ((m_mmc_vrom_bank[1] & ~0x01)), CHRROM); + chr1_x(chr_page ^ 3, m_chr_base | ((m_mmc_vrom_bank[1] | 0x01)), CHRROM); + chr1_x(chr_page ^ 4, m_chr_base | (m_mmc_vrom_bank[2]), CHRROM); + chr1_x(chr_page ^ 5, m_chr_base | (m_mmc_vrom_bank[3]), CHRROM); + chr1_x(chr_page ^ 6, m_chr_base | (m_mmc_vrom_bank[4]), CHRROM); + chr1_x(chr_page ^ 7, m_chr_base | (m_mmc_vrom_bank[5]), CHRROM); + } + break; + case SOMARI_MMC1_MODE: +// case SOMARI_MMC1_MODE_AGAIN: + if (BIT(m_mmc1_reg[0], 4)) + { + chr4_0(m_mmc1_reg[1] & 0x1f, CHRROM); + chr4_4(m_mmc1_reg[2] & 0x1f, CHRROM); + } + else + chr8((m_mmc1_reg[1] & 0x1f) >> 1, CHRROM); + break; + } +} + +void nes_somari_device::update_mirror() +{ + switch (m_board_mode) + { + case SOMARI_VRC2_MODE: + set_nt_mirroring(m_vrc_mirror_reg ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + break; + case SOMARI_MMC3_MODE: + set_nt_mirroring(m_mmc3_mirror_reg ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + break; + case SOMARI_MMC1_MODE: +// case SOMARI_MMC1_MODE_AGAIN: + switch (m_mmc1_reg[0] & 0x03) + { + case 0x00: set_nt_mirroring(PPU_MIRROR_LOW); break; + case 0x01: set_nt_mirroring(PPU_MIRROR_HIGH); break; + case 0x02: set_nt_mirroring(PPU_MIRROR_VERT); break; + case 0x03: set_nt_mirroring(PPU_MIRROR_HORZ); break; + } + break; + } +} + + +WRITE8_MEMBER(nes_somari_device::write_h) +{ + LOG_MMC(("somari write_h, mode %d, offset: %04x, data: %02x\n", m_board_mode, offset, data)); + + switch (m_board_mode) + { + case SOMARI_VRC2_MODE: vrc2_w(space, offset, data, mem_mask); break; + case SOMARI_MMC3_MODE: mmc3_w(space, offset, data, mem_mask); break; + case SOMARI_MMC1_MODE: mmc1_w(space, offset, data, mem_mask); break; + } +} + +void nes_somari_device::bank_update_switchmode() +{ + switch (m_board_mode) + { + case SOMARI_VRC2_MODE: + break; + case SOMARI_MMC3_MODE: + break; + case SOMARI_MMC1_MODE: + break; + } + update_mirror(); + update_prg(); + update_chr(); +} + +WRITE8_MEMBER(nes_somari_device::write_m) +{ + LOG_MMC(("somari write_m, offset: %04x, data: %02x\n", offset, data)); + + if (offset & 0x100) + { + m_board_mode = data & 0x03; + m_chr_base = ((m_board_mode & 0x04) << 6); + if (m_board_mode != 1) + m_irq_enable = 0; + bank_update_switchmode(); + } +} diff --git a/src/devices/bus/nes/somari.h b/src/devices/bus/nes/somari.h new file mode 100644 index 00000000000..726df0a4926 --- /dev/null +++ b/src/devices/bus/nes/somari.h @@ -0,0 +1,54 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __NES_SOMARI_H +#define __NES_SOMARI_H + +#include "mmc3.h" + + +// ======================> nes_somari_device + +class nes_somari_device : public nes_txrom_device +{ +public: + // construction/destruction + nes_somari_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_l) { write_m(space, offset + 0x100, data, mem_mask); } + virtual DECLARE_WRITE8_MEMBER(write_m); + virtual DECLARE_WRITE8_MEMBER(mmc1_w); + virtual DECLARE_WRITE8_MEMBER(mmc3_w); + virtual DECLARE_WRITE8_MEMBER(vrc2_w); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); +private: + void update_prg(); + void update_chr(); + void update_mirror(); + void bank_update_switchmode(); + + UINT8 m_board_mode; + + // MMC3 - inherited from txrom + UINT8 m_mmc3_mirror_reg; + + // MMC1 + UINT8 m_count; + UINT8 m_mmc1_latch; + UINT8 m_mmc1_reg[4]; + + // VRC2 + UINT8 m_vrc_prg_bank[2]; + UINT8 m_vrc_vrom_bank[8]; + UINT8 m_vrc_mirror_reg; +}; + + + +// device type definition +extern const device_type NES_SOMARI; + +#endif diff --git a/src/devices/bus/nes/sunsoft.c b/src/devices/bus/nes/sunsoft.c new file mode 100644 index 00000000000..48d95c05727 --- /dev/null +++ b/src/devices/bus/nes/sunsoft.c @@ -0,0 +1,628 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + NES/Famicom cartridge emulation for Sunsoft PCBs + + + Here we emulate the following PCBs + + * Sunsoft-1 [mapper 184] + * Sunsoft-2 [mapper 89 & 93] + * Sunsoft-3 [mapper 67] + * Sunsoft-4 [mapper 68] + * Sunsoft FME7 & Sunsoft-5A [mapper 69] + * Sunsoft-5B [mapper 69] + + TODO: + - check 1-line glitches due to IRQ in Sunsoft-3 + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "sunsoft.h" + +#include "cpu/m6502/m6502.h" +#include "sound/ay8910.h" + +#ifdef NES_PCB_DEBUG +#define VERBOSE 1 +#else +#define VERBOSE 0 +#endif + +#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) + + +//------------------------------------------------- +// constructor +//------------------------------------------------- + +const device_type NES_SUNSOFT_1 = &device_creator; +const device_type NES_SUNSOFT_2 = &device_creator; +const device_type NES_SUNSOFT_3 = &device_creator; +const device_type NES_SUNSOFT_4 = &device_creator; +const device_type NES_SUNSOFT_FME7 = &device_creator; +const device_type NES_SUNSOFT_5 = &device_creator; + + +nes_sunsoft_1_device::nes_sunsoft_1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_SUNSOFT_1, "NES Cart Sunsoft 1 PCB", tag, owner, clock, "nes_sun1", __FILE__) +{ +} + +nes_sunsoft_2_device::nes_sunsoft_2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_SUNSOFT_2, "NES Cart Sunsoft 2 PCB", tag, owner, clock, "nes_sun2", __FILE__) +{ +} + +nes_sunsoft_3_device::nes_sunsoft_3_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_SUNSOFT_3, "NES Cart Sunsoft 3 PCB", tag, owner, clock, "nes_sun3", __FILE__) +{ +} + +nes_sunsoft_4_device::nes_sunsoft_4_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : nes_nrom_device(mconfig, type, name, tag, owner, clock, shortname, source) +{ +} + +nes_sunsoft_4_device::nes_sunsoft_4_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_SUNSOFT_4, "NES Cart Sunsoft 4 PCB", tag, owner, clock, "nes_sun4", __FILE__) +{ +} + +nes_sunsoft_fme7_device::nes_sunsoft_fme7_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : nes_nrom_device(mconfig, type, name, tag, owner, clock, shortname, source) +{ +} + +nes_sunsoft_fme7_device::nes_sunsoft_fme7_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_SUNSOFT_4, "NES Cart Sunsoft FME7 PCB", tag, owner, clock, "nes_fme7", __FILE__) +{ +} + +nes_sunsoft_5_device::nes_sunsoft_5_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_sunsoft_fme7_device(mconfig, NES_SUNSOFT_5, "NES Cart Sunsoft 5A/5B PCB", tag, owner, clock, "nes_sun5", __FILE__), + m_ym2149(*this, "ay") +{ +} + + +void nes_sunsoft_1_device::device_start() +{ + common_start(); +} + +void nes_sunsoft_1_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); +} + +void nes_sunsoft_2_device::device_start() +{ + common_start(); +} + +void nes_sunsoft_2_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); + if (m_pcb_ctrl_mirror) + set_nt_mirroring(PPU_MIRROR_LOW); +} + +void nes_sunsoft_3_device::device_start() +{ + common_start(); + irq_timer = timer_alloc(TIMER_IRQ); + irq_timer->adjust(attotime::zero, 0, machine().device("maincpu")->cycles_to_attotime(1)); + + save_item(NAME(m_irq_enable)); + save_item(NAME(m_irq_toggle)); + save_item(NAME(m_irq_count)); +} + +void nes_sunsoft_3_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); + m_irq_toggle = 0; + m_irq_count = 0; + m_irq_enable = 0; +} + +void nes_sunsoft_4_device::device_start() +{ + common_start(); + save_item(NAME(m_latch1)); + save_item(NAME(m_latch2)); + save_item(NAME(m_reg)); + save_item(NAME(m_wram_enable)); +} + +void nes_sunsoft_4_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); + + m_reg = 0; + m_latch1 = 0; + m_latch2 = 0; + m_wram_enable = 0; +} + +void nes_sunsoft_fme7_device::device_start() +{ + common_start(); + irq_timer = timer_alloc(TIMER_IRQ); + // this has to be hardcoded because some some scanline code only suits NTSC... it will be fixed with PPU rewrite + irq_timer->adjust(attotime::zero, 0, attotime::from_hz((21477272.724 / 12))); +// irq_timer->adjust(attotime::zero, 0, machine().device("maincpu")->cycles_to_attotime(1)); + + save_item(NAME(m_wram_bank)); + save_item(NAME(m_latch)); + save_item(NAME(m_irq_enable)); + save_item(NAME(m_irq_count)); +} + +void nes_sunsoft_fme7_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); + + m_wram_bank = 0; + + m_latch = 0; + m_irq_enable = 0; + m_irq_count = 0; +} + + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +/*------------------------------------------------- + + Sunsoft-1 board emulation + + Games: Atlantis no Nazo, Kanshakudama Nage Kantarou no + Toukaidou Gojuusan Tsugi, Wing of Madoola, Fantasy Zone + + iNES: mapper 184 (Fantasy Zone uses this board with no + CHRROM, and the register switches PRG banks) + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_sunsoft_1_device::write_m) +{ + LOG_MMC(("Sunsoft 1 write_m, offset: %04x, data: %02x\n", offset, data)); + + if (m_vrom_chunks) + { + chr4_0(data & 0x0f, CHRROM); + chr4_4(data >> 4, CHRROM); + } + else + prg16_89ab(data & 0x0f); +} + +/*------------------------------------------------- + + Sunsoft-2 board emulation + + The two games using this board have incompatible mirroring + wiring, making necessary two distinct mappers + + iNES: mapper 89 & 93 + + -------------------------------------------------*/ + +// there are two 'variants' depending on hardwired or mapper ctrl mirroring + +WRITE8_MEMBER(nes_sunsoft_2_device::write_h) +{ + UINT8 helper = (data & 0x07) | ((data & 0x80) ? 0x08 : 0x00); + LOG_MMC(("Sunsoft 2 write_h, offset: %04x, data: %02x\n", offset, data)); + + // this pcb is subject to bus conflict + data = account_bus_conflict(offset, data); + + if (m_pcb_ctrl_mirror) + set_nt_mirroring(BIT(data, 3) ? PPU_MIRROR_HIGH : PPU_MIRROR_LOW); + + if (m_vrom_chunks) + chr8(helper, CHRROM); + + prg16_89ab(data >> 4); +} + +/*------------------------------------------------- + + Sunsoft-3 board emulation + + The two games using this board have incompatible mirroring + wiring, making necessary two distinct mappers & pcb_id + + iNES: mapper 67 + + -------------------------------------------------*/ + + +void nes_sunsoft_3_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + if (id == TIMER_IRQ) + { + if (m_irq_enable) + { + if (!m_irq_count) + { + m_maincpu->set_input_line(M6502_IRQ_LINE, ASSERT_LINE); + m_irq_count = 0xffff; + m_irq_enable = 0; + } + else + m_irq_count--; + } + } +} + +WRITE8_MEMBER(nes_sunsoft_3_device::write_h) +{ + LOG_MMC(("Sunsoft 3 write_h, offset %04x, data: %02x\n", offset, data)); + + switch (offset & 0x7800) + { + case 0x0800: + chr2_0(data, CHRROM); + break; + case 0x1800: + chr2_2(data, CHRROM); + break; + case 0x2800: + chr2_4(data, CHRROM); + break; + case 0x3800: + chr2_6(data, CHRROM); + break; + case 0x4000: + case 0x4800: + m_irq_toggle ^= 1; + if (m_irq_toggle) + m_irq_count = (m_irq_count & 0x00ff) | (data << 8); + else + m_irq_count = (m_irq_count & 0xff00) | data; + break; + case 0x5800: + m_irq_enable = BIT(data, 4); + m_irq_toggle = 0; + m_maincpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE); + break; + case 0x6800: + switch (data & 3) + { + case 0x00: set_nt_mirroring(PPU_MIRROR_VERT); break; + case 0x01: set_nt_mirroring(PPU_MIRROR_HORZ); break; + case 0x02: set_nt_mirroring(PPU_MIRROR_LOW); break; + case 0x03: set_nt_mirroring(PPU_MIRROR_HIGH); break; + } + break; + case 0x7800: + prg16_89ab(data); + break; + default: + LOG_MMC(("Sunsoft 3 write_h uncaught write, offset: %04x, data: %02x\n", offset, data)); + break; + } +} + +/*------------------------------------------------- + + Sunsoft-4 board emulation + + Games: AfterBurner & Maharaja + + iNES: mapper 68 + + -------------------------------------------------*/ + +void nes_sunsoft_4_device::sun4_mirror( int mirror, int mirr0, int mirr1 ) +{ + switch (mirror) + { + case 0x00: + set_nt_mirroring(PPU_MIRROR_VERT); + break; + case 0x01: + set_nt_mirroring(PPU_MIRROR_HORZ); + break; + case 0x02: + set_nt_mirroring(PPU_MIRROR_LOW); + break; + case 0x03: + set_nt_mirroring(PPU_MIRROR_HIGH); + break; + case 0x10: + set_nt_page(0, VROM, mirr0 | 0x80, 0); + set_nt_page(1, VROM, mirr1 | 0x80, 0); + set_nt_page(2, VROM, mirr0 | 0x80, 0); + set_nt_page(3, VROM, mirr1 | 0x80, 0); + break; + case 0x11: + set_nt_page(0, VROM, mirr0 | 0x80, 0); + set_nt_page(1, VROM, mirr0 | 0x80, 0); + set_nt_page(2, VROM, mirr1 | 0x80, 0); + set_nt_page(3, VROM, mirr1 | 0x80, 0); + break; + case 0x12: + set_nt_page(0, VROM, mirr0 | 0x80, 0); + set_nt_page(1, VROM, mirr0 | 0x80, 0); + set_nt_page(2, VROM, mirr0 | 0x80, 0); + set_nt_page(3, VROM, mirr0 | 0x80, 0); + break; + case 0x13: + set_nt_page(0, VROM, mirr1 | 0x80, 0); + set_nt_page(1, VROM, mirr1 | 0x80, 0); + set_nt_page(2, VROM, mirr1 | 0x80, 0); + set_nt_page(3, VROM, mirr1 | 0x80, 0); + break; + } +} + +WRITE8_MEMBER(nes_sunsoft_4_device::sun4_write) +{ + LOG_MMC(("Sunsoft 4 write_h, offset %04x, data: %02x\n", offset, data)); + + switch (offset & 0x7000) + { + case 0x0000: + chr2_0(data, CHRROM); + break; + case 0x1000: + chr2_2(data, CHRROM); + break; + case 0x2000: + chr2_4(data, CHRROM); + break; + case 0x3000: + chr2_6(data, CHRROM); + break; + case 0x4000: + m_latch1 = data & 0x7f; + sun4_mirror(m_reg, m_latch1, m_latch2); + break; + case 0x5000: + m_latch2 = data & 0x7f; + sun4_mirror(m_reg, m_latch1, m_latch2); + break; + case 0x6000: + m_reg = data & 0x13; + sun4_mirror(m_reg, m_latch1, m_latch2); + break; + case 0x7000: + prg16_89ab(data & 0x0f); + m_wram_enable = BIT(data, 4); + break; + default: + LOG_MMC(("Sunsoft 4 write_h uncaught write, offset: %04x, data: %02x\n", offset, data)); + break; + } +} + +WRITE8_MEMBER(nes_sunsoft_4_device::write_m) +{ + LOG_MMC(("Sunsoft 4 write_m, offset: %04x, data: %02x\n", offset, data)); + + if (!m_battery.empty() && m_wram_enable) + m_battery[offset & (m_battery.size() - 1)] = data; + if (!m_prgram.empty() && m_wram_enable) + m_prgram[offset & (m_prgram.size() - 1)] = data; +} + +READ8_MEMBER(nes_sunsoft_4_device::read_m) +{ + LOG_MMC(("Sunsoft 4 read_m, offset: %04x\n", offset)); + + if (!m_battery.empty() && m_wram_enable) + return m_battery[offset & (m_battery.size() - 1)]; + if (!m_prgram.empty() && m_wram_enable) + return m_prgram[offset & (m_prgram.size() - 1)]; + + return m_open_bus; // open bus +} + +/*------------------------------------------------- + + JxROM & Sunsoft 5A / 5B / FME7 board emulation + + Notice that Sunsoft-5B = FME7 + sound chip (the latter being + currently unemulated in MESS) + + iNES: mapper 69 + + -------------------------------------------------*/ + +void nes_sunsoft_fme7_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + if (id == TIMER_IRQ) + { + if ((m_irq_enable & 0x80)) // bit7, counter decrement + { + if (!m_irq_count) + { + m_irq_count = 0xffff; + if (m_irq_enable & 0x01) // bit0, trigger enable + m_maincpu->set_input_line(M6502_IRQ_LINE, ASSERT_LINE); + } + else + m_irq_count--; + } + } +} + +WRITE8_MEMBER(nes_sunsoft_fme7_device::fme7_write) +{ + LOG_MMC(("fme7_write, offset %04x, data: %02x\n", offset, data)); + + switch (offset & 0x6000) + { + case 0x0000: + m_latch = data & 0x0f; + break; + + case 0x2000: + switch (m_latch) + { + case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: + chr1_x(m_latch, data, CHRROM); + break; + + case 8: + m_wram_bank = data; + break; + case 9: + prg8_89(data); + break; + case 0x0a: + prg8_ab(data); + break; + case 0x0b: + prg8_cd(data); + break; + case 0x0c: + switch (data & 0x03) + { + case 0x00: set_nt_mirroring(PPU_MIRROR_VERT); break; + case 0x01: set_nt_mirroring(PPU_MIRROR_HORZ); break; + case 0x02: set_nt_mirroring(PPU_MIRROR_LOW); break; + case 0x03: set_nt_mirroring(PPU_MIRROR_HIGH); break; + } + break; + case 0x0d: + m_irq_enable = data; + if (!(m_irq_enable & 1)) + m_maincpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE); + break; + case 0x0e: + m_irq_count = (m_irq_count & 0xff00) | data; + break; + case 0x0f: + m_irq_count = (m_irq_count & 0x00ff) | (data << 8); + break; + } + break; + + default: + logerror("Sunsoft FME7 write_h uncaught %04x value: %02x\n", offset + 0x8000, data); + break; + } +} + +WRITE8_MEMBER(nes_sunsoft_fme7_device::write_m) +{ + UINT8 bank = m_wram_bank & 0x3f; + LOG_MMC(("Sunsoft FME7 write_m, offset: %04x, data: %02x\n", offset, data)); + + if (!(m_wram_bank & 0x40)) // is PRG ROM, no write + return; + else if (m_wram_bank & 0x80) // is PRG RAM + { + if (!m_battery.empty()) + m_battery[((bank * 0x2000) + offset) & (m_battery.size() - 1)] = data; + if (!m_prgram.empty()) + m_prgram[((bank * 0x2000) + offset) & (m_prgram.size() - 1)] = data; + } +} + +READ8_MEMBER(nes_sunsoft_fme7_device::read_m) +{ + UINT8 bank = m_wram_bank & 0x3f; + LOG_MMC(("Sunsoft FME7 read_m, offset: %04x\n", offset)); + + if (!(m_wram_bank & 0x40)) // is PRG ROM + return m_prg[((bank * 0x2000) + offset) & (m_prg_size - 1)]; + else if (m_wram_bank & 0x80) // is PRG RAM + { + if (!m_battery.empty()) + return m_battery[((bank * 0x2000) + offset) & (m_battery.size() - 1)]; + if (!m_prgram.empty()) + return m_prgram[((bank * 0x2000) + offset) & (m_prgram.size() - 1)]; + } + + return m_open_bus; // open bus +} + + +/*------------------------------------------------- + + Sunsoft 5B board emulation (FME7 + Sound) + + Games: Gimmick! + + iNES: mapper 69 + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_sunsoft_5_device::write_h) +{ + LOG_MMC(("sunsoft 5 write_h, offset %04x, data: %02x\n", offset, data)); + + switch (offset & 0x6000) + { + case 0x4000: + m_ym2149->address_w(space, 0, data & 0x0f); + break; + case 0x6000: + m_ym2149->data_w(space, 0, data); + break; + default: + fme7_write(space, offset, data, mem_mask); + break; + } +} + +//------------------------------------------------- +// MACHINE_DRIVER( sun_5b ) +//------------------------------------------------- + +// From NESdev wiki: The 5B's audio is driven by the CPU clock (1.78977267 MHz), +// but like the NES's APU, the YM2149F has an optional clock divider which +// halves the internal clock speed. By comparison of the produced pitches +// in Gimmick! with the register values used, it appears that the 5B is a +// YM2149F operating in this mode. To use an AY-3-8910 as a substitute, +// you would need an external divider to reduce the clock speed by half. + +#define SUN5_NTSC_CLOCK (21477272.724 / 12) + +static MACHINE_CONFIG_FRAGMENT( sun_5b ) + + // additional sound hardware + MCFG_SPEAKER_STANDARD_MONO("addon") + + MCFG_SOUND_ADD("ay", YM2149, SUN5_NTSC_CLOCK/2) // divide by 2 for the internal divider + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "addon", 0.50) +MACHINE_CONFIG_END + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor nes_sunsoft_5_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( sun_5b ); +} diff --git a/src/devices/bus/nes/sunsoft.h b/src/devices/bus/nes/sunsoft.h new file mode 100644 index 00000000000..53ea24adeae --- /dev/null +++ b/src/devices/bus/nes/sunsoft.h @@ -0,0 +1,147 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __NES_SUNSOFT_H +#define __NES_SUNSOFT_H + +#include "nxrom.h" +#include "sound/ay8910.h" + + +// ======================> nes_sunsoft_1_device + +class nes_sunsoft_1_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_sunsoft_1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_m); + + virtual void pcb_reset(); +}; + + +// ======================> nes_sunsoft_2_device + +class nes_sunsoft_2_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_sunsoft_2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); +}; + + +// ======================> nes_sunsoft_3_device + +class nes_sunsoft_3_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_sunsoft_3_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); + +private: + UINT16 m_irq_count; + int m_irq_enable, m_irq_toggle; + + static const device_timer_id TIMER_IRQ = 0; + emu_timer *irq_timer; +}; + + +// ======================> nes_sunsoft_4_device + +class nes_sunsoft_4_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_sunsoft_4_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + nes_sunsoft_4_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_READ8_MEMBER(read_m); + virtual DECLARE_WRITE8_MEMBER(write_m); + virtual DECLARE_WRITE8_MEMBER(sun4_write); + virtual DECLARE_WRITE8_MEMBER(write_h) { sun4_write(space, offset, data, mem_mask); } + + virtual void pcb_reset(); + +protected: + void sun4_mirror(int mirror, int mirr0, int mirr1); + int m_reg, m_latch1, m_latch2, m_wram_enable; +}; + +// ======================> nes_sunsoft_fme7_device + +class nes_sunsoft_fme7_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_sunsoft_fme7_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + nes_sunsoft_fme7_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + virtual DECLARE_READ8_MEMBER(read_m); + virtual DECLARE_WRITE8_MEMBER(write_m); + virtual DECLARE_WRITE8_MEMBER(fme7_write); + virtual DECLARE_WRITE8_MEMBER(write_h) { fme7_write(space, offset, data, mem_mask); } + + virtual void pcb_reset(); + +private: + UINT16 m_irq_count; + int m_irq_enable; + + static const device_timer_id TIMER_IRQ = 0; + emu_timer *irq_timer; + + UINT8 m_latch; + UINT8 m_wram_bank; +}; + + +// ======================> nes_sunsoft_5_device + +class nes_sunsoft_5_device : public nes_sunsoft_fme7_device +{ +public: + // construction/destruction + nes_sunsoft_5_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual machine_config_constructor device_mconfig_additions() const; + + virtual DECLARE_WRITE8_MEMBER(write_h); + +private: + required_device m_ym2149; +}; + + + + +// device type definition +extern const device_type NES_SUNSOFT_1; +extern const device_type NES_SUNSOFT_2; +extern const device_type NES_SUNSOFT_3; +extern const device_type NES_SUNSOFT_4; +extern const device_type NES_SUNSOFT_FME7; +extern const device_type NES_SUNSOFT_5; + +#endif diff --git a/src/devices/bus/nes/sunsoft_dcs.c b/src/devices/bus/nes/sunsoft_dcs.c new file mode 100644 index 00000000000..c7de9fd3040 --- /dev/null +++ b/src/devices/bus/nes/sunsoft_dcs.c @@ -0,0 +1,315 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + NES/Famicom cartridge emulation for Sunsoft DCS PCBs + + + Here we emulate the Sunsoft Dual Cassette System (DCS) PCB used by Nantettate!! Baseball + subslot + + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "sunsoft_dcs.h" + +#ifdef NES_PCB_DEBUG +#define VERBOSE 1 +#else +#define VERBOSE 0 +#endif + +#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) + + +//----------------------------------------------- +// +// Nantettate!! Baseball Cartslot implementation +// +//----------------------------------------------- + +//------------------------------------------------- +// sub-cart interface +//------------------------------------------------- + +ntb_cart_interface::ntb_cart_interface(const machine_config &mconfig, device_t &device) + : device_slot_card_interface(mconfig, device), + m_rom(NULL) +{ +} + +ntb_cart_interface::~ntb_cart_interface() +{ +} + +//------------------------------------------------- +// sub-cart slot device +//------------------------------------------------- + +const device_type NES_NTB_SLOT = &device_creator; + +nes_ntb_slot_device::nes_ntb_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, NES_NTB_SLOT, "NES NTB Cartridge Slot", tag, owner, clock, "nes_ntb_slot", __FILE__), + device_image_interface(mconfig, *this), + device_slot_interface(mconfig, *this) +{ +} + +nes_ntb_slot_device::~nes_ntb_slot_device() +{ +} + + +void nes_ntb_slot_device::device_start() +{ + m_cart = dynamic_cast(get_card_device()); +} + +READ8_MEMBER(nes_ntb_slot_device::read) +{ + if (m_cart) + return m_cart->read(space, offset, mem_mask); + + return 0xff; +} + + +bool nes_ntb_slot_device::call_load() +{ + if (m_cart) + { + UINT8 *ROM = m_cart->get_cart_base(); + + if (!ROM) + return IMAGE_INIT_FAIL; + + if (software_entry() == NULL) + { + if (length() != 0x4000) + return IMAGE_INIT_FAIL; + + fread(&ROM, 0x4000); + } + else + { + if (get_software_region_length("rom") != 0x4000) + return IMAGE_INIT_FAIL; + + memcpy(ROM, get_software_region("rom"), 0x4000); + } + } + + return IMAGE_INIT_PASS; +} + + +bool nes_ntb_slot_device::call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry) +{ + load_software_part_region(*this, swlist, swname, start_entry ); + return TRUE; +} + +void nes_ntb_slot_device::get_default_card_software(std::string &result) +{ + software_get_default_slot(result, "ntbrom"); +} + +//----------------------------------------------- +// +// Nantettate!! Baseball Minicart implementation +// +//----------------------------------------------- + +ROM_START( ntb_rom ) + ROM_REGION(0x4000, "ntbrom", ROMREGION_ERASEFF) +ROM_END + +const device_type NES_NTB_ROM = &device_creator; + +nes_ntb_rom_device::nes_ntb_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, NES_NTB_ROM, "NES NTB ROM", tag, owner, clock, "nes_ntbrom", __FILE__), + ntb_cart_interface( mconfig, *this ) +{ +} + +void nes_ntb_rom_device::device_start() +{ + m_rom = (UINT8*)memregion("ntbrom")->base(); +} + +const rom_entry *nes_ntb_rom_device::device_rom_region() const +{ + return ROM_NAME( ntb_rom ); +} + +UINT8 *nes_ntb_rom_device::get_cart_base() +{ + return m_rom; +} + + + +//------------------------------------------------ +// +// Nantettate!! Baseball base cart implementation +// a.k.a. Sunsoft Dual Cassette System +// (variant of Sunsoft-4 PCB) +// +//------------------------------------------------ + +const device_type NES_SUNSOFT_DCS = &device_creator; + + +nes_sunsoft_dcs_device::nes_sunsoft_dcs_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_sunsoft_4_device(mconfig, NES_SUNSOFT_DCS, "NES Cart Sunsoft DCS PCB", tag, owner, clock, "nes_dcs", __FILE__), + m_subslot(*this, "ntb_slot") +{ +} + + +void nes_sunsoft_dcs_device::device_start() +{ + common_start(); + ntb_enable_timer = timer_alloc(TIMER_PROTECT); + ntb_enable_timer->reset(); + timer_freq = machine().device("maincpu")->cycles_to_attotime(107520); + + save_item(NAME(m_latch1)); + save_item(NAME(m_latch2)); + save_item(NAME(m_reg)); + save_item(NAME(m_wram_enable)); + save_item(NAME(m_exrom_enable)); + save_item(NAME(m_timer_on)); +} + +void nes_sunsoft_dcs_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); + + m_reg = 0; + m_latch1 = 0; + m_latch2 = 0; + m_wram_enable = 0; + m_exrom_enable = 0; + m_timer_on = 0; +} + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +/*------------------------------------------------- + + Sunsoft-DCS board emulation + + Games: Nantettatte!! Baseball + + This board feature a subslot to load minicart containing + updated data? + + iNES: mapper 68 + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_sunsoft_dcs_device::write_h) +{ + LOG_MMC(("Sunsoft DCS write_h, offset %04x, data: %02x\n", offset, data)); + + switch (offset & 0x7000) + { + case 0x7000: + prg16_89ab(data & 0x07); + m_exrom_enable = !BIT(data, 3); + m_wram_enable = BIT(data, 4); + break; + default: + sun4_write(space, offset, data, mem_mask); + break; + } +} + +READ8_MEMBER(nes_sunsoft_dcs_device::read_h) +{ + LOG_MMC(("Sunsoft DCS read_h, offset: %04x\n", offset)); + + if (m_exrom_enable && m_subslot->m_cart && offset < 0x4000) + { + if (m_timer_on) + return m_subslot->m_cart->read(space, offset, mem_mask); + else + return m_open_bus; // after the timer is off, this returns open bus... + } + else + return hi_access_rom(offset); +} + +WRITE8_MEMBER(nes_sunsoft_dcs_device::write_m) +{ + LOG_MMC(("Sunsoft DCS write_m, offset: %04x, data: %02x\n", offset, data)); + + if (!m_battery.empty() && m_wram_enable) + m_battery[offset & (m_battery.size() - 1)] = data; + if (!m_prgram.empty() && m_wram_enable) + m_prgram[offset & (m_prgram.size() - 1)] = data; + if (!m_wram_enable && !m_timer_on) + { + m_timer_on = 1; + // start NTB-ROM timer + ntb_enable_timer->adjust(timer_freq); + } +} + +READ8_MEMBER(nes_sunsoft_dcs_device::read_m) +{ + LOG_MMC(("Sunsoft DCS read_m, offset: %04x\n", offset)); + + if (!m_battery.empty() && m_wram_enable) + return m_battery[offset & (m_battery.size() - 1)]; + if (!m_prgram.empty() && m_wram_enable) + return m_prgram[offset & (m_prgram.size() - 1)]; + + return m_open_bus; // open bus +} + +//------------------------------------------------- +// MACHINE_CONFIG_FRAGMENT( sub_slot ) +//------------------------------------------------- + +static SLOT_INTERFACE_START(ntb_cart) + SLOT_INTERFACE_INTERNAL("ntbrom", NES_NTB_ROM) +SLOT_INTERFACE_END + +static MACHINE_CONFIG_FRAGMENT( sub_slot ) + MCFG_NTB_MINICART_ADD("ntb_slot", ntb_cart) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor nes_sunsoft_dcs_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( sub_slot ); +} + + +//------------------------------------------------- +// device_timer - handler timer events +//------------------------------------------------- + +void nes_sunsoft_dcs_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + if (id == TIMER_PROTECT) + { + m_timer_on = 0; + ntb_enable_timer->reset(); + } +} diff --git a/src/devices/bus/nes/sunsoft_dcs.h b/src/devices/bus/nes/sunsoft_dcs.h new file mode 100644 index 00000000000..67fcaf83b1e --- /dev/null +++ b/src/devices/bus/nes/sunsoft_dcs.h @@ -0,0 +1,150 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __NES_SUNSOFT_DCS_H +#define __NES_SUNSOFT_DCS_H + +#include "sunsoft.h" + + +//----------------------------------------------- +// +// Nantettate!! Baseball Cartslot implementation +// +//----------------------------------------------- + +// ======================> ntb_cart_interface + +class ntb_cart_interface : public device_slot_card_interface +{ +public: + // construction/destruction + ntb_cart_interface(const machine_config &mconfig, device_t &device); + virtual ~ntb_cart_interface(); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read) { return m_rom[offset]; } + + UINT8 *get_cart_base() { return m_rom; } + +protected: + // internal state + UINT8 *m_rom; +}; + +// ======================> nes_ntb_slot_device + +class nes_ntb_slot_device : public device_t, + public device_image_interface, + public device_slot_interface +{ +public: + // construction/destruction + nes_ntb_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual ~nes_ntb_slot_device(); + + // device-level overrides + virtual void device_start(); + virtual void device_config_complete() { update_names(); } + + // image-level overrides + virtual bool call_load(); + virtual bool call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry); + + virtual iodevice_t image_type() const { return IO_CARTSLOT; } + virtual bool is_readable() const { return 1; } + virtual bool is_writeable() const { return 0; } + virtual bool is_creatable() const { return 0; } + virtual bool must_be_loaded() const { return 0; } + virtual bool is_reset_on_load() const { return 1; } + virtual const char *image_interface() const { return "ntb_cart"; } + virtual const char *file_extensions() const { return "bin"; } + virtual const option_guide *create_option_guide() const { return NULL; } + + // slot interface overrides + virtual void get_default_card_software(std::string &result); + + virtual DECLARE_READ8_MEMBER(read); + + ntb_cart_interface* m_cart; +}; + +// device type definition +extern const device_type NES_NTB_SLOT; + + +#define MCFG_NTB_MINICART_ADD(_tag, _slot_intf) \ + MCFG_DEVICE_ADD(_tag, NES_NTB_SLOT, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, NULL, false) + + +//----------------------------------------------- +// +// Nantettate!! Baseball Minicart implementation +// +//----------------------------------------------- + +// ======================> nes_ntb_rom_device + +class nes_ntb_rom_device : public device_t, + public ntb_cart_interface +{ +public: + // construction/destruction + nes_ntb_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual UINT8* get_cart_base(); + +protected: + // device-level overrides + virtual void device_start(); +}; + +// device type definition +extern const device_type NES_NTB_ROM; + + + +//------------------------------------------------ +// +// Nantettate!! Baseball base cart implementation +// a.k.a. Sunsoft Dual Cassette System +// (variant of Sunsoft-4 PCB) +// +//------------------------------------------------ + +// ======================> nes_sunsoft_dcs_device + +class nes_sunsoft_dcs_device : public nes_sunsoft_4_device +{ +public: + // construction/destruction + nes_sunsoft_dcs_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual machine_config_constructor device_mconfig_additions() const; + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + virtual DECLARE_READ8_MEMBER(read_m); + virtual DECLARE_READ8_MEMBER(read_h); + virtual DECLARE_WRITE8_MEMBER(write_m); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); + +private: + int m_timer_on, m_exrom_enable; + required_device m_subslot; + + static const device_timer_id TIMER_PROTECT = 0; + emu_timer *ntb_enable_timer; + attotime timer_freq; +}; + + + +// device type definition +extern const device_type NES_SUNSOFT_DCS; + +#endif diff --git a/src/devices/bus/nes/taito.c b/src/devices/bus/nes/taito.c new file mode 100644 index 00000000000..2338d91ee25 --- /dev/null +++ b/src/devices/bus/nes/taito.c @@ -0,0 +1,470 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + NES/Famicom cartridge emulation for Taito PCBs + + + Here we emulate the following PCBs + + * Taito TC0190FMC/TC0190FMR [mapper 33] + * Taito TC0190FMC+PAL16R4 [mapper 48] + * Taito X1-005 [mapper 80, 207] + * Taito X1-017 [mapper 82] + + TODO: + - Akira does not work. Investigate why! + - Don Doko Don 2 freezes when you get to the first boss + + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "taito.h" + +#include "cpu/m6502/m6502.h" +#include "video/ppu2c0x.h" // this has to be included so that IRQ functions can access PPU_BOTTOM_VISIBLE_SCANLINE + + +#ifdef NES_PCB_DEBUG +#define VERBOSE 1 +#else +#define VERBOSE 0 +#endif + +#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) + + +//------------------------------------------------- +// constructor +//------------------------------------------------- + +const device_type NES_TC0190FMC = &device_creator; +const device_type NES_TC0190FMC_PAL16R4 = &device_creator; +const device_type NES_X1_005 = &device_creator; +const device_type NES_X1_017 = &device_creator; + + +nes_tc0190fmc_device::nes_tc0190fmc_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : nes_nrom_device(mconfig, type, name, tag, owner, clock, shortname, source) +{ +} + +nes_tc0190fmc_device::nes_tc0190fmc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_TC0190FMC, "NES Cart Taito TC0190FMC PCB", tag, owner, clock, "nes_tc0190fmc", __FILE__) +{ +} + +nes_tc0190fmc_pal16r4_device::nes_tc0190fmc_pal16r4_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_tc0190fmc_device(mconfig, NES_TC0190FMC_PAL16R4, "NES Cart Taito TC0190FMC + PAL16R4 PCB", tag, owner, clock, "nes_tc0190pal", __FILE__) +{ +} + +nes_x1_005_device::nes_x1_005_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_X1_005, "NES Cart Taito X1-005 PCB", tag, owner, clock, "nes_x1_005", __FILE__) +{ +} + +nes_x1_017_device::nes_x1_017_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_X1_017, "NES Cart Taito X1-017 PCB", tag, owner, clock, "nes_x1_017", __FILE__) +{ +} + + + +void nes_tc0190fmc_device::device_start() +{ + common_start(); +} + +void nes_tc0190fmc_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); +} + +void nes_tc0190fmc_pal16r4_device::device_start() +{ + common_start(); + save_item(NAME(m_irq_enable)); + save_item(NAME(m_irq_count)); + save_item(NAME(m_irq_count_latch)); +} + +void nes_tc0190fmc_pal16r4_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); + + m_irq_enable = 0; + m_irq_count = 0; + m_irq_count_latch = 0; +} + +void nes_x1_005_device::device_start() +{ + common_start(); + save_item(NAME(m_latch)); + + save_item(NAME(m_x1_005_ram)); + + m_mapper_sram_size = 0x80; + m_mapper_sram = m_x1_005_ram; +} + +void nes_x1_005_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); + + m_latch = 0; +} + +void nes_x1_017_device::device_start() +{ + common_start(); + save_item(NAME(m_latch)); + save_item(NAME(m_reg)); + save_item(NAME(m_mmc_vrom_bank)); + + save_item(NAME(m_x1_017_ram)); + + m_mapper_sram_size = 0x1400; + m_mapper_sram = m_x1_017_ram; +} + +void nes_x1_017_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); + + m_latch = 0; + memset(m_reg, 0, sizeof(m_reg)); + memset(m_mmc_vrom_bank, 0, sizeof(m_mmc_vrom_bank)); +} + + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +/*------------------------------------------------- + + Taito TC0190FMC board emulation + + Games: Akira, Bakushou!! Jinsei Gekijou, Don Doko Don, + Insector X, Operation Wolf, Power Blazer, Takeshi no + Sengoku Fuuunji + + iNES: mapper 33 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_tc0190fmc_device::tc0190fmc_write) +{ + LOG_MMC(("tc0190fmc_write, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x7003) + { + case 0x0000: + set_nt_mirroring(BIT(data, 6) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + prg8_89(data); + break; + case 0x0001: + prg8_ab(data); + break; + case 0x0002: + chr2_0(data, CHRROM); + break; + case 0x0003: + chr2_2(data, CHRROM); + break; + case 0x2000: + chr1_4(data, CHRROM); + break; + case 0x2001: + chr1_5(data, CHRROM); + break; + case 0x2002: + chr1_6(data, CHRROM); + break; + case 0x2003: + chr1_7(data, CHRROM); + break; + } +} + +/*------------------------------------------------- + + Taito TC0190FMC + PAL16R4 board emulation + + Games: Bakushou!! Jinsei Gekijou 3, Bubble Bobble 2, + Captain Saver, Don Doko Don 2, Flintstones, Jetsons + + This is basically Mapper 33 + IRQ. Notably, IRQ works the + same as MMC3 irq, BUT latch values are "inverted" (XOR'ed + with 0xff) and there is a little delay (not implemented yet) + We simply use MMC3 IRQ and XOR the value written in the + register 0xc000 below + + iNES: mapper 48 + + In MESS: Supported. + + -------------------------------------------------*/ + +void nes_tc0190fmc_pal16r4_device::hblank_irq( int scanline, int vblank, int blanked ) +{ + if (scanline < PPU_BOTTOM_VISIBLE_SCANLINE) + { + int prior_count = m_irq_count; + if (m_irq_count == 0) + m_irq_count = m_irq_count_latch; + else + m_irq_count--; + + if (m_irq_enable && !blanked && (m_irq_count == 0) && prior_count) + m_maincpu->set_input_line(M6502_IRQ_LINE, ASSERT_LINE); + } +} + +WRITE8_MEMBER(nes_tc0190fmc_pal16r4_device::write_h) +{ + LOG_MMC(("tc0190fmc pal16r4 write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x7003) + { + case 0x0000: + prg8_89(data); + break; + case 0x0001: + case 0x0002: + case 0x0003: + case 0x2000: + case 0x2001: + case 0x2002: + case 0x2003: + tc0190fmc_write(space, offset, data, mem_mask); + break; + case 0x4000: + m_irq_count_latch = (0x100 - data) & 0xff; + break; + case 0x4001: + m_irq_count = m_irq_count_latch; + break; + case 0x4002: + m_irq_enable = 1; + break; + case 0x4003: + m_irq_enable = 0; + m_maincpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE); + break; + case 0x6000: + set_nt_mirroring(BIT(data, 6) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + break; + } +} + +/*------------------------------------------------- + + Taito X1-005 board emulation + + Actually, Fudou Myouou Den uses a variant of the board with + CIRAM, making necessary two distinct mappers & pcb_id. + + Also, we miss to emulate the security check at 0x7ef8 / 0x7ef9 + and the 0x80 ram! + + iNES: mappers 80 & 207 + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_x1_005_device::write_m) +{ + LOG_MMC(("x1_005 write_m, offset: %04x, data: %02x\n", offset, data)); + + switch (offset) + { + case 0x1ef0: + chr2_0((data & 0x7f) >> 1, CHRROM); + if (m_x1_005_alt_mirroring) + { + set_nt_page(0, CIRAM, (data & 0x80) ? 1 : 0, 1); + set_nt_page(1, CIRAM, (data & 0x80) ? 1 : 0, 1); + } + break; + case 0x1ef1: + chr2_2((data & 0x7f) >> 1, CHRROM); + if (m_x1_005_alt_mirroring) + { + set_nt_page(2, CIRAM, (data & 0x80) ? 1 : 0, 1); + set_nt_page(3, CIRAM, (data & 0x80) ? 1 : 0, 1); + } + break; + case 0x1ef2: + chr1_4(data, CHRROM); + break; + case 0x1ef3: + chr1_5(data, CHRROM); + break; + case 0x1ef4: + chr1_6(data, CHRROM); + break; + case 0x1ef5: + chr1_7(data, CHRROM); + break; + case 0x1ef6: + case 0x1ef7: + if (!m_x1_005_alt_mirroring) + set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_VERT : PPU_MIRROR_HORZ); + break; + case 0x1ef8: + case 0x1ef9: + m_latch = data; + break; + case 0x1efa: + case 0x1efb: + prg8_89(data); + break; + case 0x1efc: + case 0x1efd: + prg8_ab(data); + break; + case 0x1efe: + case 0x1eff: + prg8_cd(data); + break; + default: + logerror("mapper80_m_w uncaught addr: %04x, value: %02x\n", offset + 0x6000, data); + break; + } + + if (offset >= 0x1f00 && m_latch == 0xa3) + m_x1_005_ram[offset & 0x7f] = data; +} + +READ8_MEMBER(nes_x1_005_device::read_m) +{ + LOG_MMC(("x1_005 read_m, offset: %04x\n", offset)); + + if (offset >= 0x1f00 && m_latch == 0xa3) + return m_x1_005_ram[offset & 0x7f]; + + return m_open_bus; // open bus +} + +/*------------------------------------------------- + + Taito X1-017 board emulation + + We miss to emulate the security check at 0x6000-0x73ff + and the ram! + + Games: Kyuukyoku Harikiri Koushien, Kyuukyoku Harikiri + Stadium, SD Keiji - Blader + + iNES: mapper 82 + + In MESS: Supported. + + -------------------------------------------------*/ + +void nes_x1_017_device::set_chr() +{ + if (m_latch) + { + chr2_4(m_mmc_vrom_bank[0] >> 1, CHRROM); + chr2_6(m_mmc_vrom_bank[1] >> 1, CHRROM); + } + else + { + chr2_0(m_mmc_vrom_bank[0] >> 1, CHRROM); + chr2_2(m_mmc_vrom_bank[1] >> 1, CHRROM); + } + chr1_x(4 ^ m_latch, m_mmc_vrom_bank[2], CHRROM); + chr1_x(5 ^ m_latch, m_mmc_vrom_bank[3], CHRROM); + chr1_x(6 ^ m_latch, m_mmc_vrom_bank[4], CHRROM); + chr1_x(7 ^ m_latch, m_mmc_vrom_bank[5], CHRROM); +} + +WRITE8_MEMBER(nes_x1_017_device::write_m) +{ + LOG_MMC(("x1017 write_m, offset: %04x, data: %02x\n", offset, data)); + + switch (offset) + { + case 0x1ef0: + case 0x1ef1: + case 0x1ef2: + case 0x1ef3: + case 0x1ef4: + case 0x1ef5: + if (m_mmc_vrom_bank[offset & 0x07] != data) + { + m_mmc_vrom_bank[offset & 0x07] = data; + set_chr(); + } + break; + case 0x1ef6: + set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_VERT : PPU_MIRROR_HORZ); + if (m_latch != ((data & 0x02) << 1)) + { + m_latch = ((data & 0x02) << 1); + set_chr(); + } + break; + case 0x1ef7: + case 0x1ef8: + case 0x1ef9: + m_reg[(offset & 0x0f) - 7] = data; + break; + case 0x1efa: + prg8_89(data >> 2); + break; + case 0x1efb: + prg8_ab(data >> 2); + break; + case 0x1efc: + prg8_cd(data >> 2); + break; + default: + logerror("x1017_m_w uncaught write, addr: %04x, value: %02x\n", offset + 0x6000, data); + break; + } + + // 2+2+1 KB of Internal RAM can be independently enabled/disabled! + if (offset < 0x0800 && m_reg[0] == 0xca) + m_x1_017_ram[0x0000 + (offset & 0x7ff)] = data; + if (offset < 0x1000 && m_reg[1] == 0x69) + m_x1_017_ram[0x0800 + (offset & 0x7ff)] = data; + if (offset < 0x1400 && m_reg[2] == 0x84) + m_x1_017_ram[0x1000 + (offset & 0x3ff)] = data; +} + +READ8_MEMBER(nes_x1_017_device::read_m) +{ + LOG_MMC(("x1017 read_m, offset: %04x\n", offset)); + + // 2+2+1 KB of Internal RAM can be independently enabled/disabled! + if (offset < 0x0800 && m_reg[0] == 0xca) + return m_x1_017_ram[0x0000 + (offset & 0x7ff)]; + if (offset < 0x1000 && m_reg[1] == 0x69) + return m_x1_017_ram[0x0800 + (offset & 0x7ff)]; + if (offset < 0x1400 && m_reg[2] == 0x84) + return m_x1_017_ram[0x1000 + (offset & 0x3ff)]; + + return m_open_bus; // open bus +} diff --git a/src/devices/bus/nes/taito.h b/src/devices/bus/nes/taito.h new file mode 100644 index 00000000000..9f2b57ca512 --- /dev/null +++ b/src/devices/bus/nes/taito.h @@ -0,0 +1,104 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __NES_TAITO_H +#define __NES_TAITO_H + +#include "nxrom.h" + + +// ======================> nes_tc0190fmc_device + +class nes_tc0190fmc_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_tc0190fmc_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + nes_tc0190fmc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(tc0190fmc_write); + virtual DECLARE_WRITE8_MEMBER(write_h) { tc0190fmc_write(space, offset, data, mem_mask); } + + virtual void pcb_reset(); +}; + + +// ======================> nes_tc0190fmc_pal16r4_device + +class nes_tc0190fmc_pal16r4_device : public nes_tc0190fmc_device +{ +public: + // construction/destruction + nes_tc0190fmc_pal16r4_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void hblank_irq(int scanline, int vblank, int blanked); + virtual void pcb_reset(); + +private: + UINT16 m_irq_count, m_irq_count_latch; + int m_irq_enable; +}; + + +// ======================> nes_x1_005_device + +class nes_x1_005_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_x1_005_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_READ8_MEMBER(read_m); + virtual DECLARE_WRITE8_MEMBER(write_m); + + virtual void pcb_reset(); + +private: + UINT8 m_latch; + // Taito X1-005 chip contains 80 bytes of internal ram, possibly battery backed up + UINT8 m_x1_005_ram[0x80]; +}; + + +// ======================> nes_x1_017_device + +class nes_x1_017_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_x1_017_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_READ8_MEMBER(read_m); + virtual DECLARE_WRITE8_MEMBER(write_m); + + virtual void pcb_reset(); + +private: + void set_chr(); + UINT8 m_latch; + UINT8 m_reg[3]; //mapper ram protect + UINT8 m_mmc_vrom_bank[6]; + // Taito X1-017 chip contains 5K of internal ram, battery backed up + UINT8 m_x1_017_ram[0x1400]; +}; + + + + +// device type definition +extern const device_type NES_TC0190FMC; +extern const device_type NES_TC0190FMC_PAL16R4; +extern const device_type NES_X1_005; +extern const device_type NES_X1_017; + + +#endif diff --git a/src/devices/bus/nes/tengen.c b/src/devices/bus/nes/tengen.c new file mode 100644 index 00000000000..555b0da3f35 --- /dev/null +++ b/src/devices/bus/nes/tengen.c @@ -0,0 +1,376 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + NES/Famicom cartridge emulation for Tengen PCBs + + + Here we emulate the following PCBs + + * Tengen 800008 + * Tengen 800032 [mapper 64] + * Tengen 800037 [mapper 158] + + TODO: + - emulated the IRQ delay in 800032 (possibly reason of Skull & Crossbones not working?) + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "tengen.h" + +#include "cpu/m6502/m6502.h" +#include "video/ppu2c0x.h" // this has to be included so that IRQ functions can access PPU_BOTTOM_VISIBLE_SCANLINE + + +#ifdef NES_PCB_DEBUG +#define VERBOSE 1 +#else +#define VERBOSE 0 +#endif + +#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) + + +//------------------------------------------------- +// constructor +//------------------------------------------------- + +const device_type NES_TENGEN_800008 = &device_creator; +const device_type NES_TENGEN_800032 = &device_creator; +const device_type NES_TENGEN_800037 = &device_creator; + + +nes_tengen008_device::nes_tengen008_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_TENGEN_800008, "NES Cart Tengen 800008 PCB", tag, owner, clock, "nes_tengen008", __FILE__) +{ +} + +nes_tengen032_device::nes_tengen032_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : nes_nrom_device(mconfig, type, name, tag, owner, clock, shortname, source) +{ +} + +nes_tengen032_device::nes_tengen032_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_TENGEN_800032, "NES Cart Tengen 800032 PCB", tag, owner, clock, "nes_tengen032", __FILE__) +{ +} + +nes_tengen037_device::nes_tengen037_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_tengen032_device(mconfig, NES_TENGEN_800037, "NES Cart Tengen 800037 PCB", tag, owner, clock, "nes_tengen037", __FILE__) +{ +} + + + + +void nes_tengen008_device::device_start() +{ + common_start(); +} + +void nes_tengen008_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); +} + +void nes_tengen032_device::device_start() +{ + common_start(); + irq_timer = timer_alloc(TIMER_IRQ); + irq_timer->reset(); + timer_freq = machine().device("maincpu")->cycles_to_attotime(4); + + save_item(NAME(m_mmc_prg_bank)); + save_item(NAME(m_mmc_vrom_bank)); + save_item(NAME(m_latch)); + + save_item(NAME(m_irq_mode)); + save_item(NAME(m_irq_reset)); + save_item(NAME(m_irq_enable)); + save_item(NAME(m_irq_count)); + save_item(NAME(m_irq_count_latch)); +} + +void nes_tengen032_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(m_prg_chunks - 1); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); + memset(m_mmc_prg_bank, 0, sizeof(m_mmc_prg_bank)); + memset(m_mmc_vrom_bank, 0, sizeof(m_mmc_vrom_bank)); + + m_latch = 0; + m_irq_mode = 0; + m_irq_reset = 0; + m_irq_enable = 0; + m_irq_count = m_irq_count_latch = 0; +} + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +/*------------------------------------------------- + + Tengen 800008 Board + + iNES: mapper 3? + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_tengen008_device::write_h) +{ + LOG_MMC(("tengen008 write_h, offset: %04x, data: %02x\n", offset, data)); + + // this pcb is subject to bus conflict + data = account_bus_conflict(offset, data); + + prg32(data >> 3); + chr8(data, CHRROM); +} + +/*------------------------------------------------- + + Tengen 800032 Board + + Games: Klax, Road Runner, Rolling Thunder, Shinobi, Skulls + & Crossbones, Xybots + + This is very similar to MMC-3 (or more probably to the + Namcot predecessor of MMC-3), but with more registers + and with an alternative IRQ mode + + iNES: mapper 64 + + In MESS: Partially Supported (there should be a small + delay between the IRQ and its execution, but that is not + emulated yet: this is possibly the problem with Skulls + & Crossbones) + + -------------------------------------------------*/ + +inline void nes_tengen032_device::irq_clock(int blanked) +{ + // From NESdev wiki: Regardless of the mode used to clock the counter, every time the counter is clocked, + // the following actions occur: + // - If Reset reg ($C001) was written to after previous clock, reload IRQ counter with IRQ Reload + 1 + // - Otherwise, if IRQ Counter is 0, reload IRQ counter with IRQ Reload value + // - Otherwise, first decrement IRQ counter by 1, then if IRQ counter is now 0 and IRQs are enabled, + // trigger IRQ + if (m_irq_reset) + { + m_irq_reset = 0; + m_irq_count = m_irq_count_latch + 1; + } + else if (!m_irq_count) + m_irq_count = m_irq_count_latch; + + m_irq_count--; + if (m_irq_enable && !blanked && !m_irq_count) + m_maincpu->set_input_line(M6502_IRQ_LINE, ASSERT_LINE); +} + +// we use the HBLANK IRQ latch from PPU for the scanline based IRQ mode +// and a timer for the cycle based IRQ mode, which both call irq_clock + +void nes_tengen032_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + if (id == TIMER_IRQ) + { + irq_clock(0); + } +} + + +void nes_tengen032_device::hblank_irq(int scanline, int vblank, int blanked) +{ + if (!m_irq_mode) // we are in scanline mode! + { + if (scanline < PPU_BOTTOM_VISIBLE_SCANLINE) + { + irq_clock(blanked); + } + } +} + +void nes_tengen032_device::set_prg() +{ + UINT8 prg_mode = m_latch & 0x40; + + prg8_89(m_mmc_prg_bank[prg_mode ? 2: 0]); + prg8_ab(m_mmc_prg_bank[prg_mode ? 0: 1]); + prg8_cd(m_mmc_prg_bank[prg_mode ? 1: 2]); +} + +void nes_tengen032_device::chr_cb(int start, int bank, int source) +{ + chr1_x(start, bank, source); +} + +void nes_tengen032_device::set_chr() +{ + UINT8 chr_page = (m_latch & 0x80) >> 5; + + if (m_latch & 0x20) + { + chr_cb(0 ^ chr_page, m_mmc_vrom_bank[0], CHRROM); + chr_cb(1 ^ chr_page, m_mmc_vrom_bank[6], CHRROM); + chr_cb(2 ^ chr_page, m_mmc_vrom_bank[1], CHRROM); + chr_cb(3 ^ chr_page, m_mmc_vrom_bank[7], CHRROM); + } + else + { + chr_cb(0 ^ chr_page, m_mmc_vrom_bank[0] & ~0x01, CHRROM); + chr_cb(1 ^ chr_page, m_mmc_vrom_bank[0] | 0x01, CHRROM); + chr_cb(2 ^ chr_page, m_mmc_vrom_bank[1] & ~0x01, CHRROM); + chr_cb(3 ^ chr_page, m_mmc_vrom_bank[1] | 0x01, CHRROM); + } + + chr_cb(4 ^ chr_page, m_mmc_vrom_bank[2], CHRROM); + chr_cb(5 ^ chr_page, m_mmc_vrom_bank[3], CHRROM); + chr_cb(6 ^ chr_page, m_mmc_vrom_bank[4], CHRROM); + chr_cb(7 ^ chr_page, m_mmc_vrom_bank[5], CHRROM); +} + +WRITE8_MEMBER(nes_tengen032_device::tengen032_write) +{ + UINT8 helper, cmd; + LOG_MMC(("tengen032_write, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x6001) + { + case 0x0000: + helper = m_latch ^ data; + m_latch = data; + + // Has PRG Mode changed? + if (helper & 0x40) + set_prg(); + + // Has CHR Mode changed? + if (helper & 0xa0) + set_chr(); + break; + + case 0x0001: + cmd = m_latch & 0x0f; + switch (cmd) + { + case 0: case 1: + case 2: case 3: + case 4: case 5: + m_mmc_vrom_bank[cmd] = data; + set_chr(); + break; + case 6: case 7: + m_mmc_prg_bank[cmd - 6] = data; + set_prg(); + break; + case 8: case 9: + m_mmc_vrom_bank[cmd - 2] = data; + set_chr(); + break; + case 0x0f: + m_mmc_prg_bank[2] = data; + set_prg(); + break; + } + break; + + case 0x2000: + set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + break; + + case 0x4000: + m_irq_count_latch = data; + break; + + case 0x4001: /* $c001 - IRQ scanline latch */ + m_irq_mode = data & 0x01; + if (m_irq_mode) + irq_timer->adjust(attotime::zero, 0, timer_freq); + else + irq_timer->adjust(attotime::never); + m_irq_reset = 1; + break; + + case 0x6000: + m_irq_enable = 0; + m_maincpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE); + break; + + case 0x6001: + m_irq_enable = 1; + break; + + default: + LOG_MMC(("Tengen 800032 write. addr: %04x value: %02x\n", offset + 0x8000, data)); + break; + } +} + +/*------------------------------------------------- + + Tengen 800037 Board + + Games: Alien Syndrome + + Same as above (mapper chip RAMBO-1) but CHR A17 output + is connected to CIRAM A10, so this differs from 800032 + exactly in the same way as TLSROM differs from plain + MMC-3 + + iNES: mapper 158 + + In MESS: Supported. + + -------------------------------------------------*/ + +void nes_tengen037_device::set_mirror() +{ + if (m_latch & 0x80) + { + set_nt_page(0, CIRAM, BIT(m_mmc_vrom_bank[2],7), 1); + set_nt_page(1, CIRAM, BIT(m_mmc_vrom_bank[3],7), 1); + set_nt_page(2, CIRAM, BIT(m_mmc_vrom_bank[4],7), 1); + set_nt_page(3, CIRAM, BIT(m_mmc_vrom_bank[5],7), 1); + } + else + { + set_nt_page(0, CIRAM, BIT(m_mmc_vrom_bank[0],7), 1); + set_nt_page(1, CIRAM, BIT(m_mmc_vrom_bank[0],7), 1); + set_nt_page(2, CIRAM, BIT(m_mmc_vrom_bank[1],7), 1); + set_nt_page(3, CIRAM, BIT(m_mmc_vrom_bank[1],7), 1); + } +} + +void nes_tengen037_device::chr_cb( int start, int bank, int source ) +{ + set_mirror(); // we could probably update only for one (e.g. the first) call, to slightly optimize the code + chr1_x(start, bank, source); +} + + +WRITE8_MEMBER(nes_tengen037_device::write_h) +{ + LOG_MMC(("tengen037 write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x6001) + { + case 0x2000: + break; + + default: + tengen032_write(space, offset, data, mem_mask); + break; + } +} diff --git a/src/devices/bus/nes/tengen.h b/src/devices/bus/nes/tengen.h new file mode 100644 index 00000000000..8732e6e1321 --- /dev/null +++ b/src/devices/bus/nes/tengen.h @@ -0,0 +1,88 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __NES_TENGEN_H +#define __NES_TENGEN_H + +#include "nxrom.h" + + +// ======================> nes_tengen008_device + +class nes_tengen008_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_tengen008_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); +}; + + +// ======================> nes_tengen032_device + +class nes_tengen032_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_tengen032_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + nes_tengen032_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + virtual DECLARE_WRITE8_MEMBER(tengen032_write); + virtual DECLARE_WRITE8_MEMBER(write_h) { tengen032_write(space, offset, data, mem_mask); } + virtual void chr_cb(int start, int bank, int source); + + virtual void hblank_irq(int scanline, int vblank, int blanked); + virtual void pcb_reset(); + +protected: + void set_prg(); + void set_chr(); + void irq_clock(int blanked); + + UINT16 m_irq_count, m_irq_count_latch; + UINT8 m_irq_mode, m_irq_reset; + int m_irq_enable; + + UINT8 m_latch; + UINT8 m_mmc_prg_bank[3]; + UINT8 m_mmc_vrom_bank[8]; + + static const device_timer_id TIMER_IRQ = 0; + emu_timer *irq_timer; + attotime timer_freq; +}; + + +// ======================> nes_tengen037_device + +class nes_tengen037_device : public nes_tengen032_device +{ +public: + // construction/destruction + nes_tengen037_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual DECLARE_WRITE8_MEMBER(write_h); + virtual void chr_cb(int start, int bank, int source); + +protected: + void set_mirror(); +}; + + + + + +// device type definition +extern const device_type NES_TENGEN_800008; +extern const device_type NES_TENGEN_800032; +extern const device_type NES_TENGEN_800037; + +#endif diff --git a/src/devices/bus/nes/txc.c b/src/devices/bus/nes/txc.c new file mode 100644 index 00000000000..ae36ece75ee --- /dev/null +++ b/src/devices/bus/nes/txc.c @@ -0,0 +1,268 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + NES/Famicom cartridge emulation for TXC PCBs + + Here we emulate the following PCBs + + * TXC 22111 [mapper 132] + * TXC Du Ma Racing [mapper 172] + * TXC Mahjong Block [mapper 172] + * TXC Strike Wolf [mapper 36] + * TXC Commandos (and many more) [mapper 241] + + TODO: + - Does Commandos indeed use this board? + + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "txc.h" + + +#ifdef NES_PCB_DEBUG +#define VERBOSE 1 +#else +#define VERBOSE 0 +#endif + +#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) + + +//------------------------------------------------- +// constructor +//------------------------------------------------- + +const device_type NES_TXC_22211 = &device_creator; +const device_type NES_TXC_DUMARACING = &device_creator; +const device_type NES_TXC_MJBLOCK = &device_creator; +const device_type NES_TXC_STRIKEW = &device_creator; +const device_type NES_TXC_COMMANDOS = &device_creator; + + +nes_txc_22211_device::nes_txc_22211_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : nes_nrom_device(mconfig, type, name, tag, owner, clock, shortname, source) +{ +} + +nes_txc_22211_device::nes_txc_22211_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_TXC_22211, "NES Cart TXC 22211 PCB", tag, owner, clock, "nes_txc_22211", __FILE__) +{ +} + +nes_txc_dumarc_device::nes_txc_dumarc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_txc_22211_device(mconfig, NES_TXC_DUMARACING, "NES Cart TXC Du Ma Racing PCB", tag, owner, clock, "nes_dumarc", __FILE__) +{ +} + +nes_txc_mjblock_device::nes_txc_mjblock_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_txc_22211_device(mconfig, NES_TXC_MJBLOCK, "NES Cart TXC Mahjong Block PCB", tag, owner, clock, "nes_mjblock", __FILE__) +{ +} + +nes_txc_strikew_device::nes_txc_strikew_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_TXC_STRIKEW, "NES Cart Strike Wolf PCB", tag, owner, clock, "nes_txc_strikew", __FILE__) +{ +} + +nes_txc_commandos_device::nes_txc_commandos_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_TXC_COMMANDOS, "NES Cart Commandos (and others) PCB", tag, owner, clock, "nes_txc_comm", __FILE__) +{ +} + + + + +void nes_txc_22211_device::device_start() +{ + common_start(); + save_item(NAME(m_reg)); +} + +void nes_txc_22211_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); + m_reg[0] = m_reg[1] = m_reg[2] = m_reg[3] = 0; +} + +void nes_txc_strikew_device::device_start() +{ + common_start(); +} + +void nes_txc_strikew_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); +} + +void nes_txc_commandos_device::device_start() +{ + common_start(); +} + +void nes_txc_commandos_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); +} + + + + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +/*------------------------------------------------- + + Bootleg Board 22211 by TXC (Type A) + + Games: Creatom + + Info from NEStopia: this mapper features write to four + registers (0x4100-0x4103). The third one is used to select + PRG and CHR banks. + + iNES: mapper 132 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_txc_22211_device::write_l) +{ + LOG_MMC(("TXC 22111 write_l, offset: %04x, data: %02x\n", offset, data)); + + if (offset < 4) + m_reg[offset & 0x03] = data; +} + +READ8_MEMBER(nes_txc_22211_device::read_l) +{ + LOG_MMC(("TXC 22111 read_l, offset: %04x\n", offset)); + + if (offset == 0x0000) + return (m_reg[1] ^ m_reg[2]) | 0x40; + else + return 0x00; +} + +WRITE8_MEMBER(nes_txc_22211_device::write_h) +{ + LOG_MMC(("TXC 22111 write_h, offset: %04x, data: %02x\n", offset, data)); + + prg32(m_reg[2] >> 2); + chr8(m_reg[2], CHRROM); +} + +/*------------------------------------------------- + + Bootleg Board 22211 by TXC (Type B) + + Games: 1991 Du Ma Racing + + This mapper is basically the same as Type A. Only difference is + in the way CHR banks are selected (see below) + + iNES: mapper 172 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_txc_dumarc_device::write_h) +{ + LOG_MMC(("TXC Du Ma Racing write_h, offset: %04x, data: %02x\n", offset, data)); + + prg32(m_reg[2] >> 2); + chr8((((data ^ m_reg[2]) >> 3) & 0x02) | (((data ^ m_reg[2]) >> 5) & 0x01), CHRROM); +} + +/*------------------------------------------------- + + Bootleg Board 22211 by TXC (Type C) + + Games: Mahjong Block, Xiao Ma Li + + This mapper is basically the same as 132 too. Only difference is + in 0x4100 reads which expect also bit 0 to be set + + iNES: mapper 172 + + In MESS: Supported. + + -------------------------------------------------*/ + +READ8_MEMBER(nes_txc_mjblock_device::read_l) +{ + LOG_MMC(("TXC mjblock read_l, offset: %04x\n", offset)); + + if (offset == 0x0000) + return (m_reg[1] ^ m_reg[2]) | 0x41; + else + return 0x00; +} + +/*------------------------------------------------- + + Bootleg Board 'Strike Wolf' by TXC + + Games: Strike Wolf and Policeman + + iNES: mapper 36 + + In MESS: Partially Supported (Policeman has glitches) + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_txc_strikew_device::write_h) +{ + LOG_MMC(("TXC Strike Wolf write_h, offset: %04x, data: %02x\n", offset, data)); + + // this pcb is subject to bus conflict + data = account_bus_conflict(offset, data); + + if ((offset >= 0x400) && (offset < 0x7fff)) + { + prg32(data >> 4); + chr8(data & 0x0f, CHRROM); + } +} + +/*------------------------------------------------- + + Bootleg Board MXMDHTWO by TXC + + Games: Commandos, Journey to the West, Ma Bu Mi Zhen & + Qu Wei Cheng Yu Wu, Si Lu Chuan Qi + + Simple Mapper: writes to 0x8000-0xffff sets the prg32 bank. + Not sure if returning 0x50 for reads in 0x4100-0x5000 is correct. + + iNES: mapper 241 + + In MESS: Supported. + + -------------------------------------------------*/ + +READ8_MEMBER(nes_txc_commandos_device::read_l) +{ + return 0x50; +} + +WRITE8_MEMBER(nes_txc_commandos_device::write_h) +{ + LOG_MMC(("TXC Commandos write_h, offset: %04x, data: %02x\n", offset, data)); + + prg32(data); +} diff --git a/src/devices/bus/nes/txc.h b/src/devices/bus/nes/txc.h new file mode 100644 index 00000000000..e71e6fde249 --- /dev/null +++ b/src/devices/bus/nes/txc.h @@ -0,0 +1,99 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __NES_TXC_H +#define __NES_TXC_H + +#include "nxrom.h" + + +// ======================> nes_txc_22211_device + +class nes_txc_22211_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_txc_22211_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + nes_txc_22211_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_READ8_MEMBER(read_l); + virtual DECLARE_WRITE8_MEMBER(write_l); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); + +protected: + UINT8 m_reg[4]; +}; + + +// ======================> nes_txc_dumarac_device + +class nes_txc_dumarc_device : public nes_txc_22211_device +{ +public: + // construction/destruction + nes_txc_dumarc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual DECLARE_WRITE8_MEMBER(write_h); +}; + + +// ======================> nes_txc_mjblock_device + +class nes_txc_mjblock_device : public nes_txc_22211_device +{ +public: + // construction/destruction + nes_txc_mjblock_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual DECLARE_READ8_MEMBER(read_l); +}; + + +// ======================> nes_txc_strikew_device + +class nes_txc_strikew_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_txc_strikew_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); +}; + + +// ======================> nes_txc_commandos_device + +class nes_txc_commandos_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_txc_commandos_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_READ8_MEMBER(read_l); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); +}; + + + + +// device type definition +extern const device_type NES_TXC_22211; +extern const device_type NES_TXC_DUMARACING; +extern const device_type NES_TXC_MJBLOCK; +extern const device_type NES_TXC_STRIKEW; +extern const device_type NES_TXC_COMMANDOS; + +#endif diff --git a/src/devices/bus/nes/waixing.c b/src/devices/bus/nes/waixing.c new file mode 100644 index 00000000000..8a223a8e295 --- /dev/null +++ b/src/devices/bus/nes/waixing.c @@ -0,0 +1,1244 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + NES/Famicom cartridge emulation for Waixing PCBs + + Here we emulate the various PCBs used by Waixing for its games + + TODO: + - investigate the PPU issues causing some games not to have sprites (e.g. some games using mappers 15, 164, + 242, 249) + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "waixing.h" + +#include "cpu/m6502/m6502.h" + + +#ifdef NES_PCB_DEBUG +#define VERBOSE 1 +#else +#define VERBOSE 0 +#endif + +#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0) + + +//------------------------------------------------- +// constructor +//------------------------------------------------- + +const device_type NES_WAIXING_A = &device_creator; +const device_type NES_WAIXING_A1 = &device_creator; +const device_type NES_WAIXING_B = &device_creator; +const device_type NES_WAIXING_C = &device_creator; +const device_type NES_WAIXING_D = &device_creator; +const device_type NES_WAIXING_E = &device_creator; +const device_type NES_WAIXING_F = &device_creator; +const device_type NES_WAIXING_G = &device_creator; +const device_type NES_WAIXING_H = &device_creator; +const device_type NES_WAIXING_H1 = &device_creator; +const device_type NES_WAIXING_I = &device_creator; +const device_type NES_WAIXING_J = &device_creator; +const device_type NES_WAIXING_SH2 = &device_creator; +const device_type NES_WAIXING_SEC = &device_creator; +const device_type NES_WAIXING_SGZ = &device_creator; +const device_type NES_WAIXING_SGZLZ = &device_creator; +const device_type NES_WAIXING_FFV = &device_creator; +const device_type NES_WAIXING_WXZS = &device_creator; +const device_type NES_WAIXING_DQ8 = &device_creator; +const device_type NES_WAIXING_WXZS2 = &device_creator; +const device_type NES_WAIXING_FS304 = &device_creator; + + +nes_waixing_a_device::nes_waixing_a_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : nes_txrom_device(mconfig, type, name, tag, owner, clock, shortname, source) +{ +} + +nes_waixing_a_device::nes_waixing_a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_txrom_device(mconfig, NES_WAIXING_A, "NES Cart Waixing Type A PCB", tag, owner, clock, "nes_waixing_a", __FILE__) +{ +} + +nes_waixing_a1_device::nes_waixing_a1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_waixing_a_device(mconfig, NES_WAIXING_A1, "NES Cart Waixing Type A (Alt) PCB", tag, owner, clock, "nes_waixing_a1", __FILE__) +{ +} + +nes_waixing_b_device::nes_waixing_b_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_waixing_a_device(mconfig, NES_WAIXING_B, "NES Cart Waixing Type B PCB", tag, owner, clock, "nes_waixing_b", __FILE__) +{ +} + +nes_waixing_c_device::nes_waixing_c_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_waixing_a_device(mconfig, NES_WAIXING_C, "NES Cart Waixing Type C PCB", tag, owner, clock, "nes_waixing_c", __FILE__) +{ +} + +nes_waixing_d_device::nes_waixing_d_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_waixing_a_device(mconfig, NES_WAIXING_D, "NES Cart Waixing Type D PCB", tag, owner, clock, "nes_waixing_d", __FILE__) +{ +} + +nes_waixing_e_device::nes_waixing_e_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_waixing_a_device(mconfig, NES_WAIXING_E, "NES Cart Waixing Type E PCB", tag, owner, clock, "nes_waixing_e", __FILE__) +{ +} + +nes_waixing_f_device::nes_waixing_f_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_waixing_a_device(mconfig, NES_WAIXING_F, "NES Cart Waixing Type F PCB", tag, owner, clock, "nes_waixing_f", __FILE__) +{ +} + +nes_waixing_g_device::nes_waixing_g_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_waixing_a_device(mconfig, NES_WAIXING_G, "NES Cart Waixing Type G PCB", tag, owner, clock, "nes_waixing_g", __FILE__) +{ +} + +nes_waixing_h_device::nes_waixing_h_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : nes_txrom_device(mconfig, type, name, tag, owner, clock, shortname, source) +{ +} + +nes_waixing_h_device::nes_waixing_h_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_txrom_device(mconfig, NES_WAIXING_H, "NES Cart Waixing Type H PCB", tag, owner, clock, "nes_waixing_h", __FILE__) +{ +} + +nes_waixing_h1_device::nes_waixing_h1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_waixing_h_device(mconfig, NES_WAIXING_H1, "NES Cart Waixing Type H (Alt) PCB", tag, owner, clock, "nes_waixing_h1", __FILE__) +{ +} + +nes_waixing_i_device::nes_waixing_i_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_waixing_a_device(mconfig, NES_WAIXING_I, "NES Cart Waixing Type I PCB", tag, owner, clock, "nes_waixing_i", __FILE__) +{ +} + +nes_waixing_j_device::nes_waixing_j_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_waixing_a_device(mconfig, NES_WAIXING_J, "NES Cart Waixing Type J PCB", tag, owner, clock, "nes_waixing_j", __FILE__) +{ +} + +nes_waixing_sh2_device::nes_waixing_sh2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_txrom_device(mconfig, NES_WAIXING_SH2, "NES Cart Waixing SH2 PCB", tag, owner, clock, "nes_waixing_sh2", __FILE__) +{ +} + +nes_waixing_sec_device::nes_waixing_sec_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_txrom_device(mconfig, NES_WAIXING_SEC, "NES Cart Waixing Security Chip PCB", tag, owner, clock, "nes_waixing_sec", __FILE__) +{ +} + +nes_waixing_sgz_device::nes_waixing_sgz_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_WAIXING_SGZ, "NES Cart Waixing San Guo Zhi PCB", tag, owner, clock, "nes_waixing_sgz", __FILE__) +{ +} + +nes_waixing_sgzlz_device::nes_waixing_sgzlz_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_WAIXING_SGZLZ, "NES Cart Waixing San Guo Zhong Lie Zhuan PCB", tag, owner, clock, "nes_waixing_sgzlz", __FILE__) +{ +} + +nes_waixing_ffv_device::nes_waixing_ffv_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_WAIXING_FFV, "NES Cart Waixing Final Fantasy V PCB", tag, owner, clock, "nes_waixing_ffv", __FILE__) +{ +} + +nes_waixing_wxzs_device::nes_waixing_wxzs_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_WAIXING_WXZS, "NES Cart Waixing Wai Xing Zhan Shi PCB", tag, owner, clock, "nes_waixing_wxzs", __FILE__) +{ +} + +nes_waixing_dq8_device::nes_waixing_dq8_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_WAIXING_DQ8, "NES Cart Waixing Dragon Quest VIII PCB", tag, owner, clock, "nes_waixing_dq8", __FILE__) +{ +} + +nes_waixing_wxzs2_device::nes_waixing_wxzs2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_WAIXING_WXZS2, "NES Cart Waixing Wai Xing Zhan Shi 2 PCB", tag, owner, clock, "nes_waixing_wxzs2", __FILE__) +{ +} + +nes_waixing_fs304_device::nes_waixing_fs304_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nes_nrom_device(mconfig, NES_WAIXING_FS304, "NES Cart Waixing FS-304 PCB", tag, owner, clock, "nes_waixing_fs304", __FILE__) +{ +} + + +void nes_waixing_a_device::device_start() +{ + mmc3_start(); + save_item(NAME(mapper_ram)); +} + +void nes_waixing_a_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + mmc3_common_initialize(0xff, 0xff, 0); + + memset(mapper_ram, 0, sizeof(mapper_ram)); +} + +void nes_waixing_f_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + mmc3_common_initialize(0xff, 0xff, 0); + + memset(mapper_ram, 0, sizeof(mapper_ram)); + m_mmc_prg_bank[0] = 0x00; + m_mmc_prg_bank[1] = 0x01; + m_mmc_prg_bank[2] = 0x4e; + m_mmc_prg_bank[3] = 0x4f; + set_prg(m_prg_base, m_prg_mask); +} + +void nes_waixing_g_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + mmc3_common_initialize(0xff, 0xff, 0); + + memset(mapper_ram, 0, sizeof(mapper_ram)); + m_mmc_prg_bank[0] = 0x00; + m_mmc_prg_bank[1] = 0x01; + m_mmc_prg_bank[2] = 0x3e; + m_mmc_prg_bank[3] = 0x3f; + m_mmc_vrom_bank[0] = 0x00; + m_mmc_vrom_bank[1] = 0x02; + m_mmc_vrom_bank[2] = 0x04; + m_mmc_vrom_bank[3] = 0x05; + m_mmc_vrom_bank[4] = 0x06; + m_mmc_vrom_bank[5] = 0x07; + m_mmc_vrom_bank[6] = 0x01; + m_mmc_vrom_bank[7] = 0x03; + set_prg(m_prg_base, m_prg_mask); + set_chr(m_chr_source, m_chr_base, m_chr_mask); +} + +void nes_waixing_j_device::device_start() +{ + mmc3_start(); + save_item(NAME(m_reg)); +} + +void nes_waixing_j_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + + m_reg[0] = 0x01; + m_reg[1] = 0x02; + m_reg[2] = 0x7e; + m_reg[3] = 0x7f; + mmc3_common_initialize(0xff, 0xff, 0); + set_prg(m_prg_base, m_prg_mask); +} + +void nes_waixing_sh2_device::device_start() +{ + mmc3_start(); + save_item(NAME(m_reg)); +} + +void nes_waixing_sh2_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + + m_reg[0] = m_reg[1] = 0; + mmc3_common_initialize(0xff, 0xff, 0); +} + +void nes_waixing_sec_device::device_start() +{ + mmc3_start(); + save_item(NAME(m_reg)); +} + +void nes_waixing_sec_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + + m_reg = 0; + mmc3_common_initialize(0xff, 0xff, 0); +} + +void nes_waixing_sgz_device::device_start() +{ + common_start(); + save_item(NAME(m_irq_enable)); + save_item(NAME(m_irq_enable_latch)); + save_item(NAME(m_irq_count)); + save_item(NAME(m_irq_count_latch)); + save_item(NAME(m_mmc_vrom_bank)); +} + +void nes_waixing_sgz_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(m_prg_chunks - 1); + chr8(0, m_chr_source); + + m_irq_enable = 0; + m_irq_enable_latch = 0; + m_irq_count = 0; + m_irq_count_latch = 0; + + memset(m_mmc_vrom_bank, 0, sizeof(m_mmc_vrom_bank)); +} + +void nes_waixing_sgzlz_device::device_start() +{ + common_start(); + save_item(NAME(m_latch)); +} + +void nes_waixing_sgzlz_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); + + m_latch = 0; +} + +void nes_waixing_ffv_device::device_start() +{ + common_start(); + save_item(NAME(m_reg)); +} + +void nes_waixing_ffv_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg16_89ab(0); + prg16_cdef(0x1f); + chr8(0, m_chr_source); + + m_reg[0] = m_reg[1] = 0; +} + +void nes_waixing_wxzs_device::device_start() +{ + common_start(); +} + +void nes_waixing_wxzs_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); +} + +void nes_waixing_dq8_device::device_start() +{ + common_start(); +} + +void nes_waixing_dq8_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); +} + +void nes_waixing_wxzs2_device::device_start() +{ + common_start(); +} + +void nes_waixing_wxzs2_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); + set_nt_mirroring(PPU_MIRROR_VERT); +} + +void nes_waixing_fs304_device::device_start() +{ + common_start(); + save_item(NAME(m_reg)); +} + +void nes_waixing_fs304_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + prg32(0); + chr8(0, m_chr_source); + + memset(m_reg, 0x00, sizeof(m_reg)); +} + + + + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +/*------------------------------------------------- + + Waixing Board Type A + + Games: Columbus - Ougon no Yoake (C), Ji Jia Zhan Shi, + Jia A Fung Yun, Wei Luo Chuan Qi + + This mapper is quite similar to MMC3, but with two differences: + mirroring is not the same, and when VROM banks 8,9 are accessed + they point to CHRRAM and not CHRROM. + + iNES: mapper 74 + + In MESS: Supported + + -------------------------------------------------*/ + +/* MIRROR_LOW and MIRROR_HIGH are swapped! */ +void nes_waixing_a_device::set_mirror(UINT8 nt) +{ + switch (nt) + { + case 0: + case 1: + set_nt_mirroring(nt ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + break; + case 2: + set_nt_mirroring(PPU_MIRROR_LOW); + break; + case 3: + set_nt_mirroring(PPU_MIRROR_HIGH); + break; + default: + LOG_MMC(("Mapper set NT to invalid value %02x", nt)); + break; + } +} + +/* Luo Ke Ren X only works with this */ +void nes_waixing_a_device::chr_cb(int start, int bank, int source) +{ + int chr_src = (bank <= 9) ? CHRRAM : CHRROM; + chr1_x(start, bank, chr_src); +} + +/* Ji Jia Zhan Shi only works with this */ +void nes_waixing_a1_device::chr_cb(int start, int bank, int source) +{ + int chr_src = ((bank == 8) || (bank == 9)) ? CHRRAM : CHRROM; + chr1_x(start, bank, chr_src); +} + +WRITE8_MEMBER(nes_waixing_a_device::waixing_write) +{ + LOG_MMC(("waixing_write, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x6001) + { + case 0x2000: + set_mirror(data); //maybe data & 0x03? + break; + + case 0x2001: + break; + + default: + txrom_write(space, offset, data, mem_mask); + break; + } +} + +READ8_MEMBER(nes_waixing_a_device::read_l) +{ + LOG_MMC(("waixing read_l, offset: %04x\n", offset)); + offset += 0x100; + if (offset >= 0x1000 && offset < 0x1400) + return mapper_ram[offset & 0x3ff]; + else + return 0xff; +} + +WRITE8_MEMBER(nes_waixing_a_device::write_l) +{ + LOG_MMC(("waixing write_l, offset: %04x, data: %02x\n", offset, data)); + offset += 0x100; + if (offset >= 0x1000 && offset < 0x1400) + mapper_ram[offset & 0x3ff] = data; +} + + +/*------------------------------------------------- + + Waixing Board Type B + + Games: Sugoro Quest (C) + + MMC3 clone. This is a minor modification of Mapper 74, + in the sense that it is the same board except for the + CHRRAM pages. + + iNES: mapper 191 + + In MESS: Supported. + + -------------------------------------------------*/ + +void nes_waixing_b_device::chr_cb(int start, int bank, int source) +{ + int chr_src = BIT(bank, 7) ? CHRRAM : CHRROM; + chr1_x(start, bank, chr_src); +} + +/*------------------------------------------------- + + Waixing Board Type C + + Games: Ying Lie Qun Xia Zhuan, Young Chivalry + + MMC3 clone. This is a minor modification of Mapper 74, + in the sense that it is the same board except for the + CHRRAM pages. + + iNES: mapper 192 + + In MESS: Supported. + + -------------------------------------------------*/ + +void nes_waixing_c_device::chr_cb(int start, int bank, int source) +{ + int chr_src = ((bank == 0x08) || (bank == 0x09) || (bank == 0x0a) || (bank == 0x0b)) ? CHRRAM : CHRROM; + chr1_x(start, bank, chr_src); +} + +/*------------------------------------------------- + + Waixing Board Type D + + Games: Super Robot Taisen (C) + + MMC3 clone. This is a minor modification of Mapper 74, + in the sense that it is the same board except for the + CHRRAM pages. + + iNES: mapper 194 + + In MESS: Supported. + + -------------------------------------------------*/ + +void nes_waixing_d_device::chr_cb(int start, int bank, int source) +{ + int chr_src = (bank < 0x02) ? CHRRAM : CHRROM; + chr1_x(start, bank, chr_src); +} + +/*------------------------------------------------- + + Waixing Board Type E + + Games: Captain Tsubasa Vol. II (C), Chaos World, God + Slayer (C), Zu Qiu Xiao Jiang + + MMC3 clone. This is a minor modification of Mapper 74, + in the sense that it is the same board except for the + CHRRAM pages. + + iNES: mapper 195 + + In MESS: Supported. + + -------------------------------------------------*/ + +void nes_waixing_e_device::chr_cb(int start, int bank, int source) +{ + int chr_src = (bank < 0x04) ? CHRRAM : CHRROM; + chr1_x(start, bank, chr_src); +} + + +/*------------------------------------------------- + + Waixing Board Type F + + Games: Tenchi wo Kurau II (C) + + MMC3 clone. + + iNES: mapper 198 + + In MESS: Preliminary support. + + -------------------------------------------------*/ + +void nes_waixing_f_device::chr_cb(int start, int bank, int source) +{ + chr1_x(start, bank, CHRRAM); +} + +void nes_waixing_f_device::prg_cb(int start, int bank) +{ +// if (bank > 0x3f) +// bank = 0x40 | (bank & 0xf); + prg8_x(start, bank); +} + +void nes_waixing_f_device::set_prg( int prg_base, int prg_mask ) +{ + UINT8 prg_flip = (m_latch & 0x40) ? 2 : 0; + + prg_cb(0, m_mmc_prg_bank[0 ^ prg_flip]); + prg_cb(1, m_mmc_prg_bank[1]); + prg_cb(2, m_mmc_prg_bank[2 ^ prg_flip]); + prg_cb(3, m_mmc_prg_bank[3]); +} + +WRITE8_MEMBER(nes_waixing_f_device::write_h) +{ + UINT8 cmd; + LOG_MMC(("waixing_f write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x6001) + { + case 0x0001: + cmd = m_latch & 0x07; + switch (cmd) + { + case 0: case 1: // these do not need to be separated: we take care of them in set_chr! + case 2: case 3: case 4: case 5: + m_mmc_vrom_bank[cmd] = data; + set_chr(m_chr_source, m_chr_base, m_chr_mask); + break; + case 6: + case 7: + case 8: + case 9: + m_mmc_prg_bank[cmd - 6] = data; + //printf("prg bank %d value %x\n", cmd - 6, data); + set_prg(m_prg_base, m_prg_mask); + break; + } + break; + + case 0x2001: + break; + + default: + waixing_write(space, offset, data, mem_mask); + break; + } +} + +/*------------------------------------------------- + + Waixing Board Type G + + Games: San Guo Zhi 2, Dragon Ball Z Gaiden (C), Dragon + Ball Z II (C) + + MMC3 clone, capable of switching all 4 PRG banks + + iNES: mapper 199 + + In MESS: Supported. + + -------------------------------------------------*/ + +void nes_waixing_g_device::chr_cb(int start, int bank, int source) +{ + int chr_src = (bank < 0x08) ? CHRRAM : CHRROM; + chr1_x(start, bank, chr_src); +} + +void nes_waixing_g_device::set_chr(UINT8 chr, int chr_base, int chr_mask) +{ + UINT8 chr_page = (m_latch & 0x80) >> 5; + + chr_cb(chr_page ^ 0, chr_base | (m_mmc_vrom_bank[0] & chr_mask), chr); + chr_cb(chr_page ^ 1, chr_base | (m_mmc_vrom_bank[6] & chr_mask), chr); + chr_cb(chr_page ^ 2, chr_base | (m_mmc_vrom_bank[1] & chr_mask), chr); + chr_cb(chr_page ^ 3, chr_base | (m_mmc_vrom_bank[7] & chr_mask), chr); + chr_cb(chr_page ^ 4, chr_base | (m_mmc_vrom_bank[2] & chr_mask), chr); + chr_cb(chr_page ^ 5, chr_base | (m_mmc_vrom_bank[3] & chr_mask), chr); + chr_cb(chr_page ^ 6, chr_base | (m_mmc_vrom_bank[4] & chr_mask), chr); + chr_cb(chr_page ^ 7, chr_base | (m_mmc_vrom_bank[5] & chr_mask), chr); +} + +WRITE8_MEMBER(nes_waixing_g_device::write_h) +{ + UINT8 cmd; + LOG_MMC(("waixing_g write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x6001) + { + case 0x0001: + cmd = m_latch & 0x0f; + switch (cmd) + { + case 0: case 1: + case 2: case 3: case 4: case 5: + m_mmc_vrom_bank[cmd] = data; + set_chr(m_chr_source, m_chr_base, m_chr_mask); + break; + case 6: + case 7: + case 8: + case 9: + m_mmc_prg_bank[cmd - 6] = data; + set_prg(m_prg_base, m_prg_mask); + break; + case 0x0a: case 0x0b: + m_mmc_vrom_bank[cmd - 4] = data; + set_chr(m_chr_source, m_chr_base, m_chr_mask); + break; + } + break; + + default: + waixing_write(space, offset, data, mem_mask); + break; + } +} + +/*------------------------------------------------- + + Waixing Board Type H + + Games: Ying Xiong Yuan Yi Jing Chuan Qi, Yong Zhe Dou E + Long - Dragon Quest VII + + MMC3 clone. More info to come. + + Notice that Chinese Zelda translation stops working if + WRAM protect bit is ignored (i.e. if writes to 0x2001 + are skipped)! OTOH, Chinese Monster Maker 1/2 translations + and Zheng Ba ShiJi stop working if WRAM protect is + accounted. So we split the board into two subtypes + + iNES: mapper 245 + + In MESS: Supported. + + -------------------------------------------------*/ + +void nes_waixing_h_device::chr_cb(int start, int bank, int source) +{ + if (source == CHRROM) + chr1_x(start, bank, source); +} + +WRITE8_MEMBER(nes_waixing_h_device::write_h) +{ + UINT8 cmd; + LOG_MMC(("waixing_h write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x6001) + { + case 0x0001: + cmd = m_latch & 0x07; + switch (cmd) + { + case 0: // in this case we set prg_base in addition to m_mmc_vrom_bank! + m_prg_base = (data << 5) & 0x40; + m_prg_mask = 0x3f; + set_prg(m_prg_base, m_prg_mask); + case 1: + case 2: case 3: case 4: case 5: + m_mmc_vrom_bank[cmd] = data; + set_chr(m_chr_source, m_chr_base, m_chr_mask); + break; + case 6: + case 7: + m_mmc_prg_bank[cmd - 6] = data; + set_prg(m_prg_base, m_prg_mask); + break; + case 0x0a: case 0x0b: // CHR switches in 1K banks only, and bank1 & bank3 are controlled by these + m_mmc_vrom_bank[cmd - 4] = data; + set_chr(m_chr_source, m_chr_base, m_chr_mask); + break; + } + break; + + case 0x2001: + break; + + default: + txrom_write(space, offset, data, mem_mask); + break; + } +} + +WRITE8_MEMBER(nes_waixing_h1_device::write_h) +{ + UINT8 cmd; + LOG_MMC(("waixing_h1 write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x6001) + { + case 0x0001: + cmd = m_latch & 0x07; + switch (cmd) + { + case 0: // in this case we set prg_base in addition to m_mmc_vrom_bank! + m_prg_base = (data << 5) & 0x40; + m_prg_mask = 0x3f; + set_prg(m_prg_base, m_prg_mask); + case 1: + case 2: case 3: case 4: case 5: + m_mmc_vrom_bank[cmd] = data; + set_chr(m_chr_source, m_chr_base, m_chr_mask); + break; + case 6: + case 7: + m_mmc_prg_bank[cmd - 6] = data; + set_prg(m_prg_base, m_prg_mask); + break; + case 0x0a: case 0x0b: // CHR switches in 1K banks only, and bank1 & bank3 are controlled by these + m_mmc_vrom_bank[cmd - 4] = data; + set_chr(m_chr_source, m_chr_base, m_chr_mask); + break; + } + break; + + default: + txrom_write(space, offset, data, mem_mask); + break; + } +} + +/*------------------------------------------------- + + Waixing Board Type J + + Games: Final Fantasy III (C) + + MMC3 clone. + + In MESS: Preliminary support. + + -------------------------------------------------*/ + +void nes_waixing_j_device::set_prg( int prg_base, int prg_mask ) +{ + UINT8 prg_flip = (m_latch & 0x40) ? 2 : 0; + + prg_cb(0, m_reg[0 ^ prg_flip]); + prg_cb(1, m_reg[1]); + prg_cb(2, m_reg[2 ^ prg_flip]); + prg_cb(3, m_reg[3]); +} + +WRITE8_MEMBER(nes_waixing_j_device::write_h) +{ + UINT8 cmd; + LOG_MMC(("waixing_f write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x6001) + { + case 0x0001: + cmd = m_latch & 0x07; + switch (cmd) + { + case 0: case 1: // these do not need to be separated: we take care of them in set_chr! + case 2: case 3: case 4: case 5: + m_mmc_vrom_bank[cmd] = data; + set_chr(m_chr_source, m_chr_base, m_chr_mask); + break; + case 6: + case 7: + case 8: + case 9: + m_reg[cmd - 6] = data; + set_prg(m_prg_base, m_prg_mask); + break; + } + break; + +// case 0x2001: +// break; + + default: + waixing_write(space, offset, data, mem_mask); + break; + } +} + +/*------------------------------------------------- + + Waixing SH2 Board + + Games: Fire Emblem (C) and Fire Emblem Gaiden (C) + + MMC3 clone with different access to CHR + + iNES: mapper 165 + + In MESS: Partially Supported. + + -------------------------------------------------*/ + +void nes_waixing_sh2_device::chr_cb(int start, int bank, int source) +{ + chr4_0(m_reg[0], m_reg[0] ? CHRRAM : CHRROM); + chr4_4(m_reg[1], m_reg[1] ? CHRRAM : CHRROM); +} + +READ8_MEMBER(nes_waixing_sh2_device::chr_r) +{ + int bank = offset >> 10; + UINT8 val = m_chr_access[bank][offset & 0x3ff]; // this would be usual return value + int chr_helper; + + switch (offset & 0xff8) + { + case 0xfd0: chr_helper = (bank & 0x4) | 0x0; break; + case 0xfe8: chr_helper = (bank & 0x4) | 0x2; break; + default: return val; + } + + m_reg[offset >> 12] = chr_helper; + if (offset & 0x1000) + chr4_4(m_reg[1], m_reg[1] ? CHRRAM : CHRROM); + else + chr4_0(m_reg[0], m_reg[0] ? CHRRAM : CHRROM); + + return val; +} + +/*------------------------------------------------- + + Waixing Board with Security Chip + + Games: Duo Bao Xiao Ying Hao - Guang Ming yu An Hei Chuan Shuo, + Myth Struggle, San Shi Liu Ji, Shui Hu Zhuan + + MMC3 clone + + iNES: mapper 249 + + In MESS: Partially Supported. + + -------------------------------------------------*/ + +void nes_waixing_sec_device::prg_cb(int start, int bank) +{ + if (m_reg) + bank = BITSWAP8(bank & 0x1f,7,6,5,2,1,3,4,0); + + prg8_x(start, bank); +} + +void nes_waixing_sec_device::chr_cb(int start, int bank, int source) +{ + if (m_reg) + bank = BITSWAP8(bank, 5,4,2,6,7,3,1,0); + + chr1_x(start, bank, source); +} + +WRITE8_MEMBER(nes_waixing_sec_device::write_l) +{ + LOG_MMC(("waixing_sec write_l, offset: %04x, data: %02x\n", offset, data)); + offset += 0x100; + + if (offset == 0x1000) + { + m_reg = data & 0x02; + set_prg(m_prg_base, m_prg_mask); + set_chr(m_chr_source, m_chr_base, m_chr_mask); + } +} + +/*------------------------------------------------- + + Waixing San Guo Zhi Board + + Games: San Guo Zhi + + This board uses Konami IRQ + + iNES: mapper 252 + + In MESS: Unsupported. + + -------------------------------------------------*/ + +// same as Konami IRQ +void nes_waixing_sgz_device::hblank_irq(int scanline, int vblank, int blanked) +{ + /* Increment & check the IRQ scanline counter */ + if (m_irq_enable && (++m_irq_count == 0x100)) + { + m_irq_count = m_irq_count_latch; + m_irq_enable = m_irq_enable_latch; + m_maincpu->set_input_line(M6502_IRQ_LINE, HOLD_LINE); + } +} + +WRITE8_MEMBER(nes_waixing_sgz_device::write_h) +{ + UINT8 helper, bank; + LOG_MMC(("waixing_sgz write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x7000) + { + case 0x0000: + prg8_89(data); + break; + case 0x2000: + prg8_ab(data); + break; + case 0x3000: + case 0x4000: + case 0x5000: + case 0x6000: + bank = ((offset & 0x7000) - 0x3000) / 0x0800 + ((offset & 0x0008) >> 3); + helper = offset & 0x04; + if (helper) + m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & 0x0f) | ((data & 0x0f) << 4); + else + m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & 0xf0) | (data & 0x0f); + chr1_x(bank, m_mmc_vrom_bank[bank], CHRROM); + break; + case 0x7000: + switch (offset & 0x0c) + { + case 0x00: + m_irq_count_latch = (m_irq_count_latch & 0xf0) | (data & 0x0f); + break; + case 0x04: + m_irq_count_latch = (m_irq_count_latch & 0x0f) | ((data & 0x0f) << 4); + break; + case 0x08: + m_irq_enable = data & 0x02; + m_irq_count_latch = data & 0x01; + if (data & 0x02) + m_irq_count = m_irq_count_latch; + break; + case 0x0c: + m_irq_enable = m_irq_enable_latch; + break; + } + break; + } +} + + +/*------------------------------------------------- + + Waixing San Guo Zhong Lie Zhuan Board + + Games: Fan Kong Jing Ying, San Guo Zhong Lie Zhuan, Xing + Ji Zheng Ba + + iNES: mapper 178 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_waixing_sgzlz_device::write_l) +{ + LOG_MMC(("waixing_sgzlz write_l, offset: %04x, data: %02x\n", offset, data)); + + switch (offset) + { + case 0x700: + set_nt_mirroring(data ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + break; + case 0x701: + m_latch = (m_latch & 0x0c) | ((data >> 1) & 0x03); + prg32(m_latch); + break; + case 0x702: + m_latch = (m_latch & 0x03) | ((data << 2) & 0x0c); + break; + } +} + +/*------------------------------------------------- + + Waixing Final Fantasy V Board + + Games: Darkseed, Digital Dragon, Final Fantasy V, Pocket + Monster Red + + iNES: mapper 164 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_waixing_ffv_device::write_l) +{ + UINT8 helper; + LOG_MMC(("waixing_ffv write_l, offset: %04x, data: %02x\n", offset, data)); + offset += 0x100; /* the checks work better on addresses */ + + if ((offset & 0x1200) == 0x1000) + { + m_reg[BIT(offset, 8)] = data; + helper = BIT(m_reg[1], 0) << 5; + switch (m_reg[0] & 0x70) + { + case 0x00: + case 0x20: + case 0x40: + case 0x60: + prg16_89ab(helper | ((m_reg[0] >> 1) & 0x10) | (m_reg[0] & 0x0f)); + prg16_cdef(helper & 0x1f); + break; + case 0x50: + prg32((helper >> 1) | (m_reg[0] & 0x0f)); + break; + case 0x70: + prg16_89ab(helper | ((m_reg[0] << 1) & 0x10) | (m_reg[0] & 0x0f)); + prg16_cdef(helper & 0x1f); + break; + } + } +} + +/*------------------------------------------------- + + Waixing Zhan Shi Board + + Games: Wai Xing Zhan Shi + + Simple mapper: writes to 0x8000-0xffff sets prg32 banks to + (offset>>3)&f. written data&3 sets the mirroring (with + switched high/low compared to the standard one). + + A crc check is required to support Dragon Quest VIII (which + uses a slightly different board) + + iNES: mapper 242 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_waixing_wxzs_device::write_h) +{ + LOG_MMC(("waixing_zs write_h, offset: %04x, data: %02x\n", offset, data)); + + prg32(offset >> 3); + + switch (data & 0x03) + { + case 0: set_nt_mirroring(PPU_MIRROR_VERT); break; + case 1: set_nt_mirroring(PPU_MIRROR_HORZ); break; + case 2: set_nt_mirroring(PPU_MIRROR_LOW); break; + case 3: set_nt_mirroring(PPU_MIRROR_HIGH); break; + } +} + +/*------------------------------------------------- + + Waixing Dragon Quest VIII Board + + Games: Dragon Quest VIII + + Simple mapper: writes to 0x8000-0xffff sets prg32 banks to + (offset>>3)&f. + + iNES: mapper 242 + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_waixing_dq8_device::write_h) +{ + LOG_MMC(("waixing_dq8 write_h, offset: %04x, data: %02x\n", offset, data)); + + prg32(offset >> 3); +} + + +/*------------------------------------------------- + + Waixing WXZS2 / PS2 board + + Games: Wai Xing Zhan Shi 2 (aka Phantasy Star 2), + Bao Xiao Tien Guo, Bio Hazard, Pokemon Gold, Subor (R) + + iNES: mapper 15 + + In MESS: Supported + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_waixing_wxzs2_device::write_h) +{ + UINT8 flip = (data & 0x80) >> 7; + UINT8 helper = (data & 0x7f) << 1; + + LOG_MMC(("waixing_wxzs2 write_h, offset: %04x, data: %02x\n", offset, data)); + + set_nt_mirroring(BIT(data, 6) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + + switch (offset & 0x0fff) + { + case 0x000: + prg8_89((helper + 0) ^ flip); + prg8_ab((helper + 1) ^ flip); + prg8_cd((helper + 2) ^ flip); + prg8_ef((helper + 3) ^ flip); + break; + case 0x001: + helper |= flip; + prg8_89(helper); + prg8_ab(helper + 1); + prg8_cd(helper + 1); + prg8_ef(helper + 1); + break; + case 0x002: + helper |= flip; + prg8_89(helper); + prg8_ab(helper); + prg8_cd(helper); + prg8_ef(helper); + break; + case 0x003: + helper |= flip; + prg8_89(helper); + prg8_ab(helper + 1); + prg8_cd(helper); + prg8_ef(helper + 1); + break; + } +} + +/*------------------------------------------------- + + Board UNL-FS304 + + Games: A Link to the Past by Waixing + + iNES: mapper 162? (only found in UNIF format) + + In MESS: Supported. + + -------------------------------------------------*/ + +WRITE8_MEMBER(nes_waixing_fs304_device::write_l) +{ + LOG_MMC(("fs304 write_l, offset: %04x, data: %02x\n", offset, data)); + int bank; + offset += 0x100; + + if (offset >= 0x1000) + { + m_reg[(offset >> 8) & 3] = data; + bank = ((m_reg[2] & 0x0f) << 4) | BIT(m_reg[1], 1) | (m_reg[0] & 0x0e); + prg32(bank); + chr8(0, CHRRAM); + } +} diff --git a/src/devices/bus/nes/waixing.h b/src/devices/bus/nes/waixing.h new file mode 100644 index 00000000000..42220c5523d --- /dev/null +++ b/src/devices/bus/nes/waixing.h @@ -0,0 +1,396 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __NES_WAIXING_H +#define __NES_WAIXING_H + +#include "mmc3.h" + + +// ======================> nes_waixing_a_device + +class nes_waixing_a_device : public nes_txrom_device +{ +public: + // construction/destruction + nes_waixing_a_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + nes_waixing_a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_READ8_MEMBER(read_l); + virtual DECLARE_WRITE8_MEMBER(write_l); + virtual DECLARE_WRITE8_MEMBER(waixing_write); + virtual DECLARE_WRITE8_MEMBER(write_h) { waixing_write(space, offset, data, mem_mask); } + virtual void chr_cb(int start, int bank, int source); + + virtual void pcb_reset(); + +protected: + void set_mirror(UINT8 nt); + UINT8 mapper_ram[0x400]; +}; + + +// ======================> nes_waixing_a1_device + +class nes_waixing_a1_device : public nes_waixing_a_device +{ +public: + // construction/destruction + nes_waixing_a1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual void chr_cb(int start, int bank, int source); +}; + + +// ======================> nes_waixing_b_device + +class nes_waixing_b_device : public nes_waixing_a_device +{ +public: + // construction/destruction + nes_waixing_b_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void chr_cb(int start, int bank, int source); +}; + + +// ======================> nes_waixing_c_device + +class nes_waixing_c_device : public nes_waixing_a_device +{ +public: + // construction/destruction + nes_waixing_c_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void chr_cb(int start, int bank, int source); +}; + + +// ======================> nes_waixing_d_device + +class nes_waixing_d_device : public nes_waixing_a_device +{ +public: + // construction/destruction + nes_waixing_d_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void chr_cb(int start, int bank, int source); +}; + + +// ======================> nes_waixing_e_device + +class nes_waixing_e_device : public nes_waixing_a_device +{ +public: + // construction/destruction + nes_waixing_e_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void chr_cb(int start, int bank, int source); +}; + + +// ======================> nes_waixing_f_device + +class nes_waixing_f_device : public nes_waixing_a_device +{ +public: + // construction/destruction + nes_waixing_f_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual DECLARE_WRITE8_MEMBER(write_h); + virtual void prg_cb(int start, int bank); + virtual void chr_cb(int start, int bank, int source); + + virtual void pcb_reset(); +private: + virtual void set_prg(int prg_base, int prg_mask); +}; + + +// ======================> nes_waixing_g_device + +class nes_waixing_g_device : public nes_waixing_a_device +{ +public: + // construction/destruction + nes_waixing_g_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual DECLARE_WRITE8_MEMBER(write_h); + virtual void chr_cb(int start, int bank, int source); + + virtual void pcb_reset(); + +protected: + virtual void set_chr(UINT8 chr, int chr_base, int chr_mask); +}; + + +// ======================> nes_waixing_h_device + +class nes_waixing_h_device : public nes_txrom_device +{ +public: + // construction/destruction + nes_waixing_h_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + nes_waixing_h_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual DECLARE_WRITE8_MEMBER(write_h); + virtual void chr_cb(int start, int bank, int source); + + // This PCB does not have 1K of internal RAM, so it's not derived from nes_waixing_a_device!! +}; + + +// ======================> nes_waixing_h1_device + +class nes_waixing_h1_device : public nes_waixing_h_device +{ +public: + // construction/destruction + nes_waixing_h1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual DECLARE_WRITE8_MEMBER(write_h); + + // This variant does not ignore the wram protect! +}; + + +// ======================> nes_waixing_i_device + +class nes_waixing_i_device : public nes_waixing_a_device +{ +public: + // construction/destruction + nes_waixing_i_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // still to emulate this variant +}; + + +// ======================> nes_waixing_j_device + +class nes_waixing_j_device : public nes_waixing_a_device +{ +public: + // construction/destruction + nes_waixing_j_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); + +protected: + virtual void set_prg(int prg_base, int prg_mask); + UINT8 m_reg[4]; +}; + + +// ======================> nes_waixing_sh2_device + +class nes_waixing_sh2_device : public nes_txrom_device +{ +public: + // construction/destruction + nes_waixing_sh2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_READ8_MEMBER(chr_r); + virtual void chr_cb(int start, int bank, int source); + + virtual void pcb_reset(); + +protected: + UINT8 m_reg[2]; +}; + + +// ======================> nes_waixing_sec_device + +class nes_waixing_sec_device : public nes_txrom_device +{ +public: + // construction/destruction + nes_waixing_sec_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_l); + virtual void prg_cb(int start, int bank); + virtual void chr_cb(int start, int bank, int source); + + virtual void pcb_reset(); + +protected: + UINT8 m_reg; +}; + + +// ======================> nes_waixing_sgz_device + +class nes_waixing_sgz_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_waixing_sgz_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void hblank_irq(int scanline, int vblank, int blanked); + virtual void pcb_reset(); + +protected: + UINT16 m_irq_count, m_irq_count_latch; + int m_irq_enable, m_irq_enable_latch; + + UINT8 m_mmc_vrom_bank[8]; +}; + + +// ======================> nes_waixing_sgzlz_device + +class nes_waixing_sgzlz_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_waixing_sgzlz_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_l); + + virtual void pcb_reset(); + +protected: + UINT8 m_latch; +}; + + +// ======================> nes_waixing_ffv_device + +class nes_waixing_ffv_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_waixing_ffv_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_l); + + virtual void pcb_reset(); + +protected: + UINT8 m_reg[2]; +}; + + +// ======================> nes_waixing_wxzs_device + +class nes_waixing_wxzs_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_waixing_wxzs_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); +}; + + +// ======================> nes_waixing_dq8_device + +class nes_waixing_dq8_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_waixing_dq8_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); +}; + + +// ======================> nes_waixing_wxzs2_device + +class nes_waixing_wxzs2_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_waixing_wxzs2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_h); + + virtual void pcb_reset(); +}; + + +// ======================> nes_waixing_fs304_device + +class nes_waixing_fs304_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_waixing_fs304_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual DECLARE_WRITE8_MEMBER(write_l); + + virtual void pcb_reset(); + +protected: + UINT8 m_reg[4]; +}; + + + + + +// device type definition +extern const device_type NES_WAIXING_A; +extern const device_type NES_WAIXING_A1; +extern const device_type NES_WAIXING_B; +extern const device_type NES_WAIXING_C; +extern const device_type NES_WAIXING_D; +extern const device_type NES_WAIXING_E; +extern const device_type NES_WAIXING_F; +extern const device_type NES_WAIXING_G; +extern const device_type NES_WAIXING_H; +extern const device_type NES_WAIXING_H1; +extern const device_type NES_WAIXING_I; +extern const device_type NES_WAIXING_J; +extern const device_type NES_WAIXING_SH2; +extern const device_type NES_WAIXING_SEC; +extern const device_type NES_WAIXING_SGZ; +extern const device_type NES_WAIXING_SGZLZ; +extern const device_type NES_WAIXING_FFV; +extern const device_type NES_WAIXING_WXZS; +extern const device_type NES_WAIXING_DQ8; +extern const device_type NES_WAIXING_WXZS2; +extern const device_type NES_WAIXING_FS304; + + +#endif diff --git a/src/devices/bus/nes_ctrl/4score.c b/src/devices/bus/nes_ctrl/4score.c new file mode 100644 index 00000000000..867af2669b1 --- /dev/null +++ b/src/devices/bus/nes_ctrl/4score.c @@ -0,0 +1,189 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/********************************************************************** + + Nintendo Entertainment System Four Score Adapter + + + TODO: current implementation is a HACK, due to limitations of the + slot system! + A real Four Score would be connected to both the controller ports of + the NES, but current core cannot emulate something like this until + devices can live their own life and being connected to other devices + at request. + In current implementation the device has to be mounted separately in + the two ports and each enables 2 inputs (this is more or less as hacky + as the non-slot previous one, where the 4 ports were always available + to the emulated system, but it's not a great consolation :( ) + Two subdevices are currently used so to warn the user that the first + one gives P1+P3 inputs and the second one gives P2+P4 inputs. + For the same reason, we don't currently emulate the 2P/4P switch, + since we could at best have two switches to disable the second player + inputs. + + Note: Two Pads are hardcoded in inputs below, instead of acting as + passthrough for 2 standard joypad devices, in order to show in the + internal UI that they belong to P1+P3 and P2+P4, otherwise they would + be listed as P1+P2 and P3+P4 respectively. This *HAS* to be changed + once the slot support in the code has improved (4 standard joypads + shall be attached to the unit!) + +**********************************************************************/ + +#include "4score.h" + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type NES_4SCORE_P1P3 = &device_creator; +const device_type NES_4SCORE_P2P4 = &device_creator; + + +static INPUT_PORTS_START( nes_4score_p1p3 ) + PORT_START("PAD1") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_NAME("A") PORT_PLAYER(1) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("B") PORT_PLAYER(1) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_SELECT ) PORT_PLAYER(1) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_START ) PORT_PLAYER(1) + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP ) PORT_PLAYER(1) + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN ) PORT_PLAYER(1) + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT ) PORT_PLAYER(1) + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(1) + + PORT_START("PAD3") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_NAME("A") PORT_PLAYER(3) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("B") PORT_PLAYER(3) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_SELECT ) PORT_PLAYER(3) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_START ) PORT_PLAYER(3) + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP ) PORT_PLAYER(3) + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN ) PORT_PLAYER(3) + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT ) PORT_PLAYER(3) + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(3) +INPUT_PORTS_END + + +static INPUT_PORTS_START( nes_4score_p2p4 ) + PORT_START("PAD2") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_NAME("A") PORT_PLAYER(2) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("B") PORT_PLAYER(2) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_SELECT ) PORT_PLAYER(2) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_START ) PORT_PLAYER(2) + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP ) PORT_PLAYER(2) + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN ) PORT_PLAYER(2) + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT ) PORT_PLAYER(2) + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(2) + + PORT_START("PAD4") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_NAME("A") PORT_PLAYER(4) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("B") PORT_PLAYER(4) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_SELECT ) PORT_PLAYER(4) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_START ) PORT_PLAYER(4) + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP ) PORT_PLAYER(4) + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN ) PORT_PLAYER(4) + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT ) PORT_PLAYER(4) + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(4) +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor nes_4score_p1p3_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( nes_4score_p1p3 ); +} + +ioport_constructor nes_4score_p2p4_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( nes_4score_p2p4 ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// nes_4score_device - constructor +//------------------------------------------------- + +nes_4score_device::nes_4score_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_nes_control_port_interface(mconfig, *this) +{ +} + +nes_4score_p1p3_device::nes_4score_p1p3_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + nes_4score_device(mconfig, NES_4SCORE_P1P3, "Nintendo Four Score Adapter P1/P3", tag, owner, clock, "nes_4score_p1p3", __FILE__), + m_joypad1(*this, "PAD1"), + m_joypad3(*this, "PAD3") +{ +} + +nes_4score_p2p4_device::nes_4score_p2p4_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + nes_4score_device(mconfig, NES_4SCORE_P2P4, "Nintendo Four Score Adapter P2/P4", tag, owner, clock, "nes_4score_p2p4", __FILE__), + m_joypad2(*this, "PAD2"), + m_joypad4(*this, "PAD4") +{ +} + + +//------------------------------------------------- +// device_start +//------------------------------------------------- + +void nes_4score_device::device_start() +{ + save_item(NAME(m_latch)); +} + + +//------------------------------------------------- +// device_reset +//------------------------------------------------- + +void nes_4score_device::device_reset() +{ + m_latch = 0; +} + + +//------------------------------------------------- +// read +//------------------------------------------------- + +UINT8 nes_4score_device::read_bit0() +{ + UINT8 ret = m_latch & 1; + m_latch >>= 1; + return ret; +} + +//------------------------------------------------- +// write +//------------------------------------------------- + +void nes_4score_p1p3_device::write(UINT8 data) +{ + if (data & 0x01) + return; + + // P3 & P4 inputs in NES Four Score are read serially with P1 & P2 + m_latch = m_joypad1->read(); + m_latch |= (m_joypad3->read() << 8); // pad 3 + m_latch |= (0x08 << 16); // signature +} + +void nes_4score_p2p4_device::write(UINT8 data) +{ + if (data & 0x01) + return; + + // P3 & P4 inputs in NES Four Score are read serially with P1 & P2 + m_latch = m_joypad2->read(); + m_latch |= (m_joypad4->read() << 8); // pad 4 + m_latch |= (0x04 << 16); // signature +} diff --git a/src/devices/bus/nes_ctrl/4score.h b/src/devices/bus/nes_ctrl/4score.h new file mode 100644 index 00000000000..f4f17174957 --- /dev/null +++ b/src/devices/bus/nes_ctrl/4score.h @@ -0,0 +1,84 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/********************************************************************** + + Nintendo Entertainment System Four Score Adapter + +**********************************************************************/ + +#pragma once + +#ifndef __NES_FOURSCORE__ +#define __NES_FOURSCORE__ + + +#include "emu.h" +#include "ctrl.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> nes_4score_device + +class nes_4score_device : public device_t, + public device_nes_control_port_interface +{ +public: + // construction/destruction + nes_4score_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + virtual UINT8 read_bit0(); + +protected: + UINT32 m_latch; +}; + +// ======================> nes_4score_p1p3_device + +class nes_4score_p1p3_device : public nes_4score_device +{ +public: + // construction/destruction + nes_4score_p1p3_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual ioport_constructor device_input_ports() const; + +protected: + virtual void write(UINT8 data); + +private: + required_ioport m_joypad1; + required_ioport m_joypad3; +}; + +// ======================> nes_4score_p2p4_device + +class nes_4score_p2p4_device : public nes_4score_device +{ +public: + // construction/destruction + nes_4score_p2p4_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual ioport_constructor device_input_ports() const; + +protected: + virtual void write(UINT8 data); + +private: + required_ioport m_joypad2; + required_ioport m_joypad4; +}; + + +// device type definition +extern const device_type NES_4SCORE_P1P3; +extern const device_type NES_4SCORE_P2P4; + + +#endif diff --git a/src/devices/bus/nes_ctrl/arkpaddle.c b/src/devices/bus/nes_ctrl/arkpaddle.c new file mode 100644 index 00000000000..897c35da000 --- /dev/null +++ b/src/devices/bus/nes_ctrl/arkpaddle.c @@ -0,0 +1,130 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/********************************************************************** + + Nintendo Family Computer & Entertainment System - + Arkanoid Paddle input device + +**********************************************************************/ + +#include "arkpaddle.h" + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type NES_ARKPADDLE = &device_creator; +const device_type NES_ARKPADDLE_FC = &device_creator; + + +static INPUT_PORTS_START( arkanoid_paddle ) + PORT_START("PADDLE") + PORT_BIT( 0xff, 0x7f, IPT_PADDLE) PORT_SENSITIVITY(25) PORT_KEYDELTA(25) PORT_CENTERDELTA(0) PORT_MINMAX(0x62,0xf2) + PORT_START("BUTTON") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_BUTTON1) PORT_NAME("Paddle button") +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor nes_vaus_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( arkanoid_paddle ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// nes_vaus_device - constructor +//------------------------------------------------- + +nes_vaus_device::nes_vaus_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_nes_control_port_interface(mconfig, *this), + m_paddle(*this, "PADDLE"), + m_button(*this, "BUTTON") +{ +} + +nes_vaus_device::nes_vaus_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, NES_ARKPADDLE, "NES Arkanoid Vaus Controller", tag, owner, clock, "nes_vaus", __FILE__), + device_nes_control_port_interface(mconfig, *this), + m_paddle(*this, "PADDLE"), + m_button(*this, "BUTTON") +{ +} + +nes_vausfc_device::nes_vausfc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + nes_vaus_device(mconfig, NES_ARKPADDLE_FC, "FC Arkanoid Vaus Controller", tag, owner, clock, "nes_vausfc", __FILE__) +{ +} + + +//------------------------------------------------- +// device_start +//------------------------------------------------- + +void nes_vaus_device::device_start() +{ + save_item(NAME(m_latch)); + save_item(NAME(m_start_conv)); +} + + +//------------------------------------------------- +// device_reset +//------------------------------------------------- + +void nes_vaus_device::device_reset() +{ + m_latch = 0; + m_start_conv = 0; +} + + +//------------------------------------------------- +// read +//------------------------------------------------- + +UINT8 nes_vaus_device::read_bit34() +{ + UINT8 ret = (m_button->read() << 3); + ret |= (m_latch & 0x80) >> 3; + m_latch <<= 1; + m_latch &= 0xff; + return ret; +} + +UINT8 nes_vausfc_device::read_exp(offs_t offset) +{ + UINT8 ret = 0; + if (offset == 0) //$4016 + ret = m_button->read() << 1; + else //$4017 + { + ret = (m_latch & 0x80) >> 6; + m_latch <<= 1; + m_latch &= 0xff; + } + return ret; +} + +//------------------------------------------------- +// write +//------------------------------------------------- + +void nes_vaus_device::write(UINT8 data) +{ + int old = m_start_conv; + + if (data == 0 && old == 1) + m_latch = (UINT8) (m_paddle->read() ^ 0xff); + + m_start_conv = data; +} diff --git a/src/devices/bus/nes_ctrl/arkpaddle.h b/src/devices/bus/nes_ctrl/arkpaddle.h new file mode 100644 index 00000000000..84fe327b7d4 --- /dev/null +++ b/src/devices/bus/nes_ctrl/arkpaddle.h @@ -0,0 +1,70 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/********************************************************************** + + Nintendo Family Computer & Entertainment System - + Arkanoid Paddle input device + +**********************************************************************/ + +#pragma once + +#ifndef __NES_ARKPADDLE__ +#define __NES_ARKPADDLE__ + + +#include "emu.h" +#include "ctrl.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> nes_vaus_device + +class nes_vaus_device : public device_t, + public device_nes_control_port_interface +{ +public: + // construction/destruction + nes_vaus_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + nes_vaus_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual ioport_constructor device_input_ports() const; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + virtual UINT8 read_bit34(); + virtual void write(UINT8 data); + + required_ioport m_paddle; + required_ioport m_button; + UINT8 m_start_conv; + UINT32 m_latch; +}; + + +// ======================> nes_vaus_device + +class nes_vausfc_device : public nes_vaus_device +{ +public: + // construction/destruction + nes_vausfc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual UINT8 read_bit34() { return 0; } + virtual UINT8 read_exp(offs_t offset); +}; + + +// device type definition +extern const device_type NES_ARKPADDLE; +extern const device_type NES_ARKPADDLE_FC; + + +#endif diff --git a/src/devices/bus/nes_ctrl/bcbattle.c b/src/devices/bus/nes_ctrl/bcbattle.c new file mode 100644 index 00000000000..96b0a5bda86 --- /dev/null +++ b/src/devices/bus/nes_ctrl/bcbattle.c @@ -0,0 +1,183 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/********************************************************************** + + Nintendo Family Computer - Epoch Barcode Battler + + TODO: this should be actually emulated as a standalone system with + a few 7segments LEDs, once we get a dump of its BIOS + At the moment we only emulated the connection with a Famicom + +**********************************************************************/ + +#include "bcbattle.h" + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type NES_BARCODE_BATTLER = &device_creator; + + +MACHINE_CONFIG_FRAGMENT( nes_battler ) + MCFG_BARCODE_READER_ADD("battler") +MACHINE_CONFIG_END + +machine_config_constructor nes_bcbattle_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( nes_battler ); +} + + +//------------------------------------------------- +// device_timer - handler timer events +//------------------------------------------------- + +// This part is the hacky replacement for the real Barcode unit [shared with SNES implementation]: +// code periodically checks whether a new code has been scanned and it moves it to the +// m_current_barcode array +void nes_bcbattle_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + if (id == TIMER_BATTLER) + { + int old = m_new_code; + // has something new been scanned? + if (old < m_reader->get_pending_code()) + { + if (m_reader->get_byte_length() == 13) + { + for (int i = 0; i < 13; i++) + m_current_barcode[i] = m_reader->read_code() + '0'; + } + else if (m_reader->get_byte_length() == 8) + { + for (int i = 0; i < 5; i++) + m_current_barcode[i] = 0x20; + for (int i = 5; i < 13; i++) + m_current_barcode[i] = m_reader->read_code() + '0'; + } + // read one more, to reset the internal byte counter + m_reader->read_code(); + + // the string "SUNSOFT" is accepted as well by Barcode World + m_current_barcode[13] = 'E'; + m_current_barcode[14] = 'P'; + m_current_barcode[15] = 'O'; + m_current_barcode[16] = 'C'; + m_current_barcode[17] = 'H'; + m_current_barcode[18] = 0x0d; + m_current_barcode[19] = 0x0a; + m_pending_code = 1; + } + m_new_code = m_reader->get_pending_code(); + } +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// nes_bcbattle_device - constructor +//------------------------------------------------- + +nes_bcbattle_device::nes_bcbattle_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, NES_BARCODE_BATTLER, "Epoch Barcode Battler (FC)", tag, owner, clock, "nes_bcbattle", __FILE__), + device_nes_control_port_interface(mconfig, *this), + m_reader(*this, "battler") +{ +} + + +//------------------------------------------------- +// device_start +//------------------------------------------------- + +void nes_bcbattle_device::device_start() +{ + // lacking emulation of the standalone Barcode Battler, we refresh periodically the input from the reader + // proper emulation would have the standalone unit acknowledging that a new barcode has been scanned + // and sending the proper serial bits, instead of our read_current_bit() function! + battler_timer = timer_alloc(TIMER_BATTLER); + battler_timer->adjust(attotime::zero, 0, machine().device("maincpu")->cycles_to_attotime(1000)); + + save_item(NAME(m_current_barcode)); + save_item(NAME(m_new_code)); + save_item(NAME(m_pending_code)); + save_item(NAME(m_transmitting)); + save_item(NAME(m_cur_bit)); + save_item(NAME(m_cur_byte)); +} + + +//------------------------------------------------- +// device_reset +//------------------------------------------------- + +void nes_bcbattle_device::device_reset() +{ + m_pending_code = 0; + m_new_code = 0; + m_transmitting = 0; + m_cur_bit = 0; + m_cur_byte = 0; + memset(m_current_barcode, 0, ARRAY_LENGTH(m_current_barcode)); +} + + +//------------------------------------------------- +// read +//------------------------------------------------- + +int nes_bcbattle_device::read_current_bit() +{ + if (m_pending_code && !m_transmitting) + { + // we start with 1 + m_transmitting = 1; + m_cur_byte = 0; + m_cur_bit = 0; + return 1; + } + + if (m_transmitting) + { + if (m_cur_bit == 0) + { + m_cur_bit++; + return 1; + } + if (m_cur_bit < 9) + { + int bit = (BIT(m_current_barcode[m_cur_byte], m_cur_bit - 1)) ^ 1; + m_cur_bit++; + return bit; + } + if (m_cur_bit == 9) + { + m_cur_bit = 0; + //printf("%X ", m_current_barcode[m_cur_byte]); + m_cur_byte++; + if (m_cur_byte == 20) + { + m_cur_byte = 0; + m_transmitting = 0; + m_pending_code = 0; + } + return 0; + } + } + + return 0; +} + +UINT8 nes_bcbattle_device::read_exp(offs_t offset) +{ + UINT8 ret = 0; + if (offset == 1) //$4017 + { + ret |= read_current_bit() << 2; + } + + return ret; +} diff --git a/src/devices/bus/nes_ctrl/bcbattle.h b/src/devices/bus/nes_ctrl/bcbattle.h new file mode 100644 index 00000000000..c68d0bc669b --- /dev/null +++ b/src/devices/bus/nes_ctrl/bcbattle.h @@ -0,0 +1,53 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/********************************************************************** + + Nintendo Family Computer - Epoch Barcode Battler + +**********************************************************************/ + +#pragma once + +#ifndef __NES_BCBATTLE__ +#define __NES_BCBATTLE__ + + +#include "emu.h" +#include "ctrl.h" +#include "machine/bcreader.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> nes_bcbattle_device + +class nes_bcbattle_device : public device_t, + public device_nes_control_port_interface +{ +public: + // construction/destruction + nes_bcbattle_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + virtual machine_config_constructor device_mconfig_additions() const; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + virtual UINT8 read_exp(offs_t offset); + int read_current_bit(); + + static const device_timer_id TIMER_BATTLER = 1; + required_device m_reader; + UINT8 m_current_barcode[20]; + int m_pending_code, m_new_code, m_transmitting, m_cur_bit, m_cur_byte; + emu_timer *battler_timer; +}; + +// device type definition +extern const device_type NES_BARCODE_BATTLER; + +#endif diff --git a/src/devices/bus/nes_ctrl/ctrl.c b/src/devices/bus/nes_ctrl/ctrl.c new file mode 100644 index 00000000000..d128b1cfb5e --- /dev/null +++ b/src/devices/bus/nes_ctrl/ctrl.c @@ -0,0 +1,207 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/********************************************************************** + + Nintendo Family Computer & Entertainment System controller ports + and Family Computer expansion port emulation + + Here we emulate in fact 3 different kind of ports, which are + connected to different bis of memory locations $4016 and $4017: + - NES controller ports: these are hooked to bit 0,3,4 of the + corresponding address ($4016 for port1, $4017 for port2) + - FC controller ports: these are only hooked to bit 0 of the + corresponding address (so that e.g. a NES Zapper could not + be connected to a later FC AV model, because its inputs + would not be detected) + - FC expansion port: this is hooked to bits 0-4 of both addresses + To make things a little bit more complex, old FC models have the + controller hardwired to the unit, and the P2 controllers are + directly hooked also to one of the expansion port lines (namely, + microphone inputs from P2 go to $4016 bit 2) + + Even if the controller port and the expansion port are + physically different (the FC expansion is a 15pin port, while + the controller ports are 7pin), we emulate them as variants of a + common device, exposing the following handlers: + - read_bit0: for bit0 reads, which are typically used for serial + inputs from controllers + - read_bit34: for bit3,4 reading, expected to be at the correct + offset (but we don't currently check for read_bit34 & 0xf8==0) + - read_exp: for reads going through the expansion, with a offset + parameter to decide whether we are reading from $4016 and $4017 + - write: to acknowledge writes to $4016 + + The driver emulation will take care to only call the correct + handlers they have hooks for: Basic usage is that the expansion + port calls read_exp, FC ctrl ports call read_bit0, and NES ctrl + ports call both read_bit0 and read_bit34. However, to cope with + the original FC microphone, we will have the second controller + port calling read_exp too. + +**********************************************************************/ + +#include "ctrl.h" +// slot devices +#include "4score.h" +#include "arkpaddle.h" +#include "bcbattle.h" +#include "ftrainer.h" +#include "fckeybrd.h" +#include "hori.h" +#include "joypad.h" +#include "konamihs.h" +#include "miracle.h" +#include "mjpanel.h" +#include "pachinko.h" +#include "partytap.h" +#include "powerpad.h" +#include "suborkey.h" +#include "zapper.h" + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type NES_CONTROL_PORT = &device_creator; + + + +//************************************************************************** +// CARD INTERFACE +//************************************************************************** + +//------------------------------------------------- +// device_nes_control_port_interface - constructor +//------------------------------------------------- + +device_nes_control_port_interface::device_nes_control_port_interface(const machine_config &mconfig, device_t &device) : + device_slot_card_interface(mconfig, device) +{ + m_port = dynamic_cast(device.owner()); +} + + +//------------------------------------------------- +// ~device_nes_control_port_interface - destructor +//------------------------------------------------- + +device_nes_control_port_interface::~device_nes_control_port_interface() +{ +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// nes_control_port_device - constructor +//------------------------------------------------- + +nes_control_port_device::nes_control_port_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, NES_CONTROL_PORT, "Nintendo NES/FC control port", tag, owner, clock, "nes_control_port", __FILE__), + device_slot_interface(mconfig, *this) +{ +} + + +//------------------------------------------------- +// nes_control_port_device - destructor +//------------------------------------------------- + +nes_control_port_device::~nes_control_port_device() +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void nes_control_port_device::device_start() +{ + m_device = dynamic_cast(get_card_device()); + m_brightpixel_cb.bind_relative_to(*owner()); +} + + +UINT8 nes_control_port_device::read_bit0() +{ + UINT8 data = 0; + if (m_device) + data = m_device->read_bit0(); + return data; +} + +UINT8 nes_control_port_device::read_bit34() +{ + UINT8 data = 0; + if (m_device) + data = m_device->read_bit34(); + return data; +} + +UINT8 nes_control_port_device::read_exp(offs_t offset) +{ + UINT8 data = 0; + if (m_device) + data = m_device->read_exp(offset); + return data; +} + +void nes_control_port_device::write(UINT8 data) +{ + if (m_device) + m_device->write(data); +} + + + +//------------------------------------------------- +// SLOT_INTERFACE( nes_control_port_devices ) +//------------------------------------------------- + +SLOT_INTERFACE_START( nes_control_port1_devices ) + SLOT_INTERFACE("joypad", NES_JOYPAD) + SLOT_INTERFACE("zapper", NES_ZAPPER) + SLOT_INTERFACE("4score_p1p3", NES_4SCORE_P1P3) + SLOT_INTERFACE("miracle_piano", NES_MIRACLE) +SLOT_INTERFACE_END + +SLOT_INTERFACE_START( nes_control_port2_devices ) + SLOT_INTERFACE("joypad", NES_JOYPAD) + SLOT_INTERFACE("zapper", NES_ZAPPER) + SLOT_INTERFACE("vaus", NES_ARKPADDLE) + SLOT_INTERFACE("powerpad", NES_POWERPAD) + SLOT_INTERFACE("4score_p2p4", NES_4SCORE_P2P4) +SLOT_INTERFACE_END + +SLOT_INTERFACE_START( fc_control_port1_devices ) + SLOT_INTERFACE("joypad", NES_JOYPAD) + SLOT_INTERFACE("ccpad_left", NES_CCPAD_LEFT) +SLOT_INTERFACE_END + +SLOT_INTERFACE_START( fc_control_port2_devices ) + SLOT_INTERFACE("joypad", NES_JOYPAD) + SLOT_INTERFACE("joypad_old", NES_FCPAD_P2) + SLOT_INTERFACE("ccpad_right", NES_CCPAD_RIGHT) +SLOT_INTERFACE_END + +SLOT_INTERFACE_START( fc_expansion_devices ) + SLOT_INTERFACE("joypad", NES_JOYPAD) + SLOT_INTERFACE("arcstick", NES_ARCSTICK) + SLOT_INTERFACE("fc_keyboard", NES_FCKEYBOARD) + SLOT_INTERFACE("zapper", NES_ZAPPER) + SLOT_INTERFACE("vaus", NES_ARKPADDLE_FC) + SLOT_INTERFACE("family_trainer", NES_FTRAINER) + SLOT_INTERFACE("konamihs", NES_KONAMIHS) + SLOT_INTERFACE("mj_panel", NES_MJPANEL) + SLOT_INTERFACE("pachinko", NES_PACHINKO) + SLOT_INTERFACE("partytap", NES_PARTYTAP) + SLOT_INTERFACE("hori_twin", NES_HORITWIN) + SLOT_INTERFACE("hori_4p", NES_HORI4P) + SLOT_INTERFACE("barcode_battler", NES_BARCODE_BATTLER) + SLOT_INTERFACE("subor_keyboard", NES_SUBORKEYBOARD) +SLOT_INTERFACE_END diff --git a/src/devices/bus/nes_ctrl/ctrl.h b/src/devices/bus/nes_ctrl/ctrl.h new file mode 100644 index 00000000000..1c682c0491b --- /dev/null +++ b/src/devices/bus/nes_ctrl/ctrl.h @@ -0,0 +1,103 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/********************************************************************** + + Nintendo Family Computer & Entertainment System controller port + emulation + +********************************************************************** + + +**********************************************************************/ + +#pragma once + +#ifndef __NES_CONTROL_PORT__ +#define __NES_CONTROL_PORT__ + +#include "emu.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class nes_control_port_device; + +// ======================> device_nes_control_port_interface + +class device_nes_control_port_interface : public device_slot_card_interface +{ +public: + // construction/destruction + device_nes_control_port_interface(const machine_config &mconfig, device_t &device); + virtual ~device_nes_control_port_interface(); + + virtual UINT8 read_bit0() { return 0; }; + virtual UINT8 read_bit34() { return 0; }; + virtual UINT8 read_exp(offs_t offset) { return 0; }; + virtual void write(UINT8 data) { }; + +protected: + nes_control_port_device *m_port; +}; + + +typedef device_delegate nesctrl_brightpixel_delegate; +#define NESCTRL_BRIGHTPIXEL_CB(name) bool name(int x, int y) + + +// ======================> nes_control_port_device + +class nes_control_port_device : public device_t, + public device_slot_interface +{ +public: + // construction/destruction + nes_control_port_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual ~nes_control_port_device(); + + static void set_brightpixel_callback(device_t &device, nesctrl_brightpixel_delegate callback) { downcast(device).m_brightpixel_cb = callback; } + + UINT8 read_bit0(); + UINT8 read_bit34(); + UINT8 read_exp(offs_t offset); + void write(UINT8 data); + + nesctrl_brightpixel_delegate m_brightpixel_cb; + +protected: + // device-level overrides + virtual void device_start(); + device_nes_control_port_interface *m_device; +}; + + +// device type definition +extern const device_type NES_CONTROL_PORT; + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_NES_CONTROL_PORT_ADD(_tag, _slot_intf, _def_slot) \ + MCFG_DEVICE_ADD(_tag, NES_CONTROL_PORT, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) + +// currently this is emulated as a control port... +#define MCFG_FC_EXPANSION_PORT_ADD(_tag, _slot_intf, _def_slot) \ + MCFG_DEVICE_ADD(_tag, NES_CONTROL_PORT, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) + +#define MCFG_NESCTRL_BRIGHTPIXEL_CB(_class, _method) \ + nes_control_port_device::set_brightpixel_callback(*device, nesctrl_brightpixel_delegate(&_class::_method, #_class "::" #_method, downcast<_class *>(owner))); + + +SLOT_INTERFACE_EXTERN( nes_control_port1_devices ); +SLOT_INTERFACE_EXTERN( nes_control_port2_devices ); +SLOT_INTERFACE_EXTERN( fc_control_port1_devices ); +SLOT_INTERFACE_EXTERN( fc_control_port2_devices ); +SLOT_INTERFACE_EXTERN( fc_expansion_devices ); + + +#endif diff --git a/src/devices/bus/nes_ctrl/fckeybrd.c b/src/devices/bus/nes_ctrl/fckeybrd.c new file mode 100644 index 00000000000..946fb072e53 --- /dev/null +++ b/src/devices/bus/nes_ctrl/fckeybrd.c @@ -0,0 +1,231 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/********************************************************************** + + Nintendo Family Computer Keyboard Component + +**********************************************************************/ + +#include "fckeybrd.h" + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type NES_FCKEYBOARD = &device_creator; + + +static INPUT_PORTS_START( fc_keyboard ) + PORT_START("FCKEY.0") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F8) PORT_CHAR(UCHAR_MAMEKEY(F8)) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_ENTER) PORT_CHAR(13) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_CLOSEBRACE) PORT_CHAR('[') + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_BACKSLASH) PORT_CHAR(']') + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Kana") + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_RSHIFT) + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_BACKSLASH2) PORT_CHAR('\\') + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Stop") PORT_CODE(KEYCODE_BACKSPACE) + + PORT_START("FCKEY.1") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F7) PORT_CHAR(UCHAR_MAMEKEY(F7)) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_OPENBRACE) PORT_CHAR('@') + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_COLON) PORT_CHAR(':') + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_QUOTE) PORT_CHAR(';') + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CHAR('_') + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CHAR('/') + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_MINUS) PORT_CHAR('-') + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_EQUALS) PORT_CHAR('^') + + PORT_START("FCKEY.2") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F6) PORT_CHAR(UCHAR_MAMEKEY(F6)) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_O) PORT_CHAR('O') + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_L) PORT_CHAR('L') + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_K) PORT_CHAR('K') + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_STOP) PORT_CHAR('.') + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_COMMA) PORT_CHAR(',') + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_P) PORT_CHAR('P') + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_0) PORT_CHAR('0') + + PORT_START("FCKEY.3") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F5) PORT_CHAR(UCHAR_MAMEKEY(F5)) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_I) PORT_CHAR('I') + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_U) PORT_CHAR('U') + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_J) PORT_CHAR('J') + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_M) PORT_CHAR('M') + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_N) PORT_CHAR('N') + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_9) PORT_CHAR('9') + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_8) PORT_CHAR('8') + + PORT_START("FCKEY.4") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F4) PORT_CHAR(UCHAR_MAMEKEY(F4)) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Y) PORT_CHAR('Y') + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_G) PORT_CHAR('G') + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_H) PORT_CHAR('H') + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_B) PORT_CHAR('B') + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_V) PORT_CHAR('V') + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_7) PORT_CHAR('7') + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_6) PORT_CHAR('6') + + PORT_START("FCKEY.5") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F3) PORT_CHAR(UCHAR_MAMEKEY(F3)) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_T) PORT_CHAR('T') + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_R) PORT_CHAR('R') + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_D) PORT_CHAR('D') + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F) PORT_CHAR('F') + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_C) PORT_CHAR('C') + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_5) PORT_CHAR('5') + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_4) PORT_CHAR('4') + + PORT_START("FCKEY.6") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F2) PORT_CHAR(UCHAR_MAMEKEY(F2)) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_W) PORT_CHAR('W') + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_S) PORT_CHAR('S') + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_A) PORT_CHAR('A') + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_X) PORT_CHAR('X') + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Z) PORT_CHAR('Z') + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_E) PORT_CHAR('E') + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_3) PORT_CHAR('3') + + PORT_START("FCKEY.7") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F1) PORT_CHAR(UCHAR_MAMEKEY(F1)) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_TAB) PORT_CHAR(UCHAR_MAMEKEY(ESC)) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Q) PORT_CHAR('Q') + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_LCONTROL) PORT_CHAR(UCHAR_SHIFT_2) + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_LSHIFT) PORT_CHAR(UCHAR_SHIFT_1) + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Grph") PORT_CODE(KEYCODE_LALT) + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_1) PORT_CHAR('1') + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_2) PORT_CHAR('2') + + PORT_START("FCKEY.8") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Clr") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_UP) PORT_CHAR(UCHAR_MAMEKEY(UP)) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_RIGHT) PORT_CHAR(UCHAR_MAMEKEY(RIGHT)) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_LEFT) PORT_CHAR(UCHAR_MAMEKEY(LEFT)) + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_DOWN) PORT_CHAR(UCHAR_MAMEKEY(DOWN)) + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_SPACE) PORT_CHAR(' ') + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Del") PORT_CODE(KEYCODE_DEL) + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Ins") PORT_CODE(KEYCODE_INSERT) +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor nes_fckeybrd_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( fc_keyboard ); +} + + +static MACHINE_CONFIG_FRAGMENT( fc_keyboard ) + MCFG_CASSETTE_ADD("tape") + MCFG_CASSETTE_DEFAULT_STATE(CASSETTE_STOPPED | CASSETTE_MOTOR_ENABLED | CASSETTE_SPEAKER_ENABLED) + MCFG_CASSETTE_INTERFACE("fc_cass") +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor nes_fckeybrd_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( fc_keyboard ); +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// nes_fckeybrd_device - constructor +//------------------------------------------------- + +nes_fckeybrd_device::nes_fckeybrd_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, NES_FCKEYBOARD, "Nintendo Family Computer Keyboard Component", tag, owner, clock, "nes_fckeybrd", __FILE__), + device_nes_control_port_interface(mconfig, *this), + m_cassette(*this, "tape"), + m_kbd(*this, "FCKEY") +{ +} + + +//------------------------------------------------- +// device_start +//------------------------------------------------- + +void nes_fckeybrd_device::device_start() +{ + save_item(NAME(m_fck_scan)); + save_item(NAME(m_fck_mode)); +} + + +//------------------------------------------------- +// device_reset +//------------------------------------------------- + +void nes_fckeybrd_device::device_reset() +{ + m_fck_scan = 0; + m_fck_mode = 0; +} + + +//------------------------------------------------- +// read +//------------------------------------------------- + +UINT8 nes_fckeybrd_device::read_exp(offs_t offset) +{ + UINT8 ret = 0; + if (offset == 0) //$4016 + { + // FC Keyboard: tape input + if ((m_cassette->get_state() & CASSETTE_MASK_UISTATE) == CASSETTE_PLAY) + { + double level = m_cassette->input(); + if (level < 0) + ret |= 0x00; + else + ret |= 0x02; + } + } + else //$4017 + { + // FC Keyboard: rows of the keyboard matrix are read 4-bits at time and returned as bit1->bit4 + if (m_fck_scan < 9) + ret |= ~(((m_kbd[m_fck_scan]->read() >> (m_fck_mode * 4)) & 0x0f) << 1) & 0x1e; + else + ret |= 0x1e; + } + + return ret; +} + +//------------------------------------------------- +// write +//------------------------------------------------- + +void nes_fckeybrd_device::write(UINT8 data) +{ + // tape output (not fully tested) + if ((m_cassette->get_state() & CASSETTE_MASK_UISTATE) == CASSETTE_RECORD) + m_cassette->output(((data & 0x07) == 0x07) ? +1.0 : -1.0); + + if (BIT(data, 2)) // keyboard active + { + UINT8 out = BIT(data, 1); // scan + + if (m_fck_mode && !out && ++m_fck_scan > 9) + m_fck_scan = 0; + + m_fck_mode = out; // access lower or upper 4 bits + + if (BIT(data, 0)) // reset + m_fck_scan = 0; + } +} diff --git a/src/devices/bus/nes_ctrl/fckeybrd.h b/src/devices/bus/nes_ctrl/fckeybrd.h new file mode 100644 index 00000000000..594c3bcae8e --- /dev/null +++ b/src/devices/bus/nes_ctrl/fckeybrd.h @@ -0,0 +1,54 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/********************************************************************** + + Nintendo Family Computer Keyboard Component + +**********************************************************************/ + +#pragma once + +#ifndef __NES_FCKEYBRD__ +#define __NES_FCKEYBRD__ + + +#include "emu.h" +#include "ctrl.h" +#include "imagedev/cassette.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> nes_fckeybrd_device + +class nes_fckeybrd_device : public device_t, + public device_nes_control_port_interface +{ +public: + // construction/destruction + nes_fckeybrd_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual ioport_constructor device_input_ports() const; + virtual machine_config_constructor device_mconfig_additions() const; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + virtual UINT8 read_exp(offs_t offset); + virtual void write(UINT8 data); + +private: + required_device m_cassette; + required_ioport_array<9> m_kbd; + UINT8 m_fck_scan, m_fck_mode; +}; + + +// device type definition +extern const device_type NES_FCKEYBOARD; + + +#endif diff --git a/src/devices/bus/nes_ctrl/ftrainer.c b/src/devices/bus/nes_ctrl/ftrainer.c new file mode 100644 index 00000000000..491cc59539e --- /dev/null +++ b/src/devices/bus/nes_ctrl/ftrainer.c @@ -0,0 +1,153 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/********************************************************************** + + Nintendo Family Computer - Bandai Family Trainer Mat + +**********************************************************************/ + +#include "ftrainer.h" + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type NES_FTRAINER = &device_creator; + + +static INPUT_PORTS_START( nes_joypad ) + PORT_START("LAYOUT") + PORT_CONFNAME( 0x01, 0x00, "Family Trainer Button Layout") + PORT_CONFSETTING( 0x00, "Side A" ) + PORT_CONFSETTING( 0x01, "Side B" ) + + // difference between the two sides is that we mirror the key mapping to match the real pad layout! + PORT_START("FT_COL.0") + // side A layout + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_UNUSED ) PORT_CONDITION("LAYOUT", 0x01, EQUALS, 0x00) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Family Trainer Mid1") PORT_CODE(KEYCODE_J) PORT_CONDITION("LAYOUT", 0x01, EQUALS, 0x00) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_UNUSED ) PORT_CONDITION("LAYOUT", 0x01, EQUALS, 0x00) + // side B layout + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Family Trainer 12") PORT_CODE(KEYCODE_M) PORT_CONDITION("LAYOUT", 0x01, EQUALS, 0x01) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Family Trainer 8") PORT_CODE(KEYCODE_J) PORT_CONDITION("LAYOUT", 0x01, EQUALS, 0x01) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Family Trainer 4") PORT_CODE(KEYCODE_U) PORT_CONDITION("LAYOUT", 0x01, EQUALS, 0x01) + + PORT_START("FT_COL.1") + // side A layout + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Family Trainer Low1") PORT_CODE(KEYCODE_N) PORT_CONDITION("LAYOUT", 0x01, EQUALS, 0x00) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Family Trainer Mid2") PORT_CODE(KEYCODE_H) PORT_CONDITION("LAYOUT", 0x01, EQUALS, 0x00) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Family Trainer Top1") PORT_CODE(KEYCODE_Y) PORT_CONDITION("LAYOUT", 0x01, EQUALS, 0x00) + // side B layout + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Family Trainer 11") PORT_CODE(KEYCODE_N) PORT_CONDITION("LAYOUT", 0x01, EQUALS, 0x01) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Family Trainer 7") PORT_CODE(KEYCODE_H) PORT_CONDITION("LAYOUT", 0x01, EQUALS, 0x01) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Family Trainer 3") PORT_CODE(KEYCODE_Y) PORT_CONDITION("LAYOUT", 0x01, EQUALS, 0x01) + + PORT_START("FT_COL.2") + // side A layout + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Family Trainer Low2") PORT_CODE(KEYCODE_B) PORT_CONDITION("LAYOUT", 0x01, EQUALS, 0x00) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Family Trainer Mid3") PORT_CODE(KEYCODE_G) PORT_CONDITION("LAYOUT", 0x01, EQUALS, 0x00) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Family Trainer Top2") PORT_CODE(KEYCODE_T) PORT_CONDITION("LAYOUT", 0x01, EQUALS, 0x00) + // side B layout + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Family Trainer 10") PORT_CODE(KEYCODE_B) PORT_CONDITION("LAYOUT", 0x01, EQUALS, 0x01) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Family Trainer 6") PORT_CODE(KEYCODE_G) PORT_CONDITION("LAYOUT", 0x01, EQUALS, 0x01) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Family Trainer 2") PORT_CODE(KEYCODE_T) PORT_CONDITION("LAYOUT", 0x01, EQUALS, 0x01) + + PORT_START("FT_COL.3") + // side A layout + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_UNUSED ) PORT_CONDITION("LAYOUT", 0x01, EQUALS, 0x00) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Family Trainer Mid4") PORT_CODE(KEYCODE_F) PORT_CONDITION("LAYOUT", 0x01, EQUALS, 0x00) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_UNUSED ) PORT_CONDITION("LAYOUT", 0x01, EQUALS, 0x00) + // side B layout + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Family Trainer 9") PORT_CODE(KEYCODE_V) PORT_CONDITION("LAYOUT", 0x01, EQUALS, 0x01) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Family Trainer 5") PORT_CODE(KEYCODE_F) PORT_CONDITION("LAYOUT", 0x01, EQUALS, 0x01) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Family Trainer 1") PORT_CODE(KEYCODE_R) PORT_CONDITION("LAYOUT", 0x01, EQUALS, 0x01) +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor nes_ftrainer_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( nes_joypad ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// nes_ftrainer_device - constructor +//------------------------------------------------- + +nes_ftrainer_device::nes_ftrainer_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, NES_FTRAINER, "Bandai Family Trainer", tag, owner, clock, "nes_famtrain", __FILE__), + device_nes_control_port_interface(mconfig, *this), + m_trainer(*this, "FT_COL") +{ +} + + +//------------------------------------------------- +// device_start +//------------------------------------------------- + +void nes_ftrainer_device::device_start() +{ + save_item(NAME(m_row_scan)); +} + + +//------------------------------------------------- +// device_reset +//------------------------------------------------- + +void nes_ftrainer_device::device_reset() +{ + m_row_scan = 0; +} + + +//------------------------------------------------- +// read +//------------------------------------------------- + +UINT8 nes_ftrainer_device::read_exp(offs_t offset) +{ + UINT8 ret = 0; + if (offset == 1) //$4017 + { + if (!BIT(m_row_scan, 0)) + { + // read low line: buttons 9,10,11,12 + for (int i = 0; i < 4; i++) + ret |= ((m_trainer[i]->read() & 0x01) << (1 + i)); + } + else if (!BIT(m_row_scan, 1)) + { + // read mid line: buttons 5,6,7,8 + for (int i = 0; i < 4; i++) + ret |= ((m_trainer[i]->read() & 0x02) << (1 + i)); + } + else if (!BIT(m_row_scan, 2)) + { + // read high line: buttons 1,2,3,4 + for (int i = 0; i < 4; i++) + ret |= ((m_trainer[i]->read() & 0x04) << (1 + i)); + } + } + return ret; +} + +//------------------------------------------------- +// write +//------------------------------------------------- + +void nes_ftrainer_device::write(UINT8 data) +{ + // select row to scan + m_row_scan = data & 0x07; +} diff --git a/src/devices/bus/nes_ctrl/ftrainer.h b/src/devices/bus/nes_ctrl/ftrainer.h new file mode 100644 index 00000000000..bc546295c8f --- /dev/null +++ b/src/devices/bus/nes_ctrl/ftrainer.h @@ -0,0 +1,51 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/********************************************************************** + + Nintendo Family Computer - Bandai Family Trainer Mat + +**********************************************************************/ + +#pragma once + +#ifndef __NES_FTRAINER__ +#define __NES_FTRAINER__ + + +#include "emu.h" +#include "ctrl.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> nes_ftrainer_device + +class nes_ftrainer_device : public device_t, + public device_nes_control_port_interface +{ +public: + // construction/destruction + nes_ftrainer_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual ioport_constructor device_input_ports() const; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + virtual UINT8 read_exp(offs_t offset); + virtual void write(UINT8 data); + +private: + required_ioport_array<4> m_trainer; + UINT8 m_row_scan; +}; + + +// device type definition +extern const device_type NES_FTRAINER; + + +#endif diff --git a/src/devices/bus/nes_ctrl/hori.c b/src/devices/bus/nes_ctrl/hori.c new file mode 100644 index 00000000000..cecf1f05dbc --- /dev/null +++ b/src/devices/bus/nes_ctrl/hori.c @@ -0,0 +1,168 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/********************************************************************** + + Nintendo Family Computer Hori Twin (and 4P?) adapters + + Emulation of the 4Players adapter is quite pointless: if 2P mode + (default mode) it behaves like a Hori Twin adapter, in 4P mode + it has P1 and P2 inputs overwriting the inputs coming from the + main controllers (possibly creating a bit of confusion, since + you get 6 sets of inputs with only 4 acknowledged by the running + system). + For the moment we keep it available for documentation purposes. + + TODO: find out confirmation whether in 2P mode, inputs from joypads + connected to the 4players adapter are really seen as P3 and P4 inputs. + it seems the most reasonable setup (so that users with only 2 + external pads can use the adapter in 4P games), but one never knows... + +**********************************************************************/ + +#include "hori.h" +#include "joypad.h" + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type NES_HORITWIN = &device_creator; +const device_type NES_HORI4P = &device_creator; + + +static INPUT_PORTS_START( nes_hori4p ) + PORT_START("CONFIG") + PORT_CONFNAME( 0x01, 0x00, "4 Players / 2 Players") + PORT_CONFSETTING( 0x00, "2 Players" ) + PORT_CONFSETTING( 0x01, "4 Players" ) +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor nes_hori4p_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( nes_hori4p ); +} + + +static SLOT_INTERFACE_START( hori_adapter ) + SLOT_INTERFACE("joypad", NES_JOYPAD) +SLOT_INTERFACE_END + +static MACHINE_CONFIG_FRAGMENT( horitwin ) + MCFG_FC_EXPANSION_PORT_ADD("port1", hori_adapter, "joypad") + MCFG_FC_EXPANSION_PORT_ADD("port2", hori_adapter, "joypad") +MACHINE_CONFIG_END + +static MACHINE_CONFIG_FRAGMENT( hori4p ) + MCFG_FC_EXPANSION_PORT_ADD("port1", hori_adapter, "joypad") + MCFG_FC_EXPANSION_PORT_ADD("port2", hori_adapter, "joypad") + MCFG_FC_EXPANSION_PORT_ADD("port3", hori_adapter, "joypad") + MCFG_FC_EXPANSION_PORT_ADD("port4", hori_adapter, "joypad") +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor nes_horitwin_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( horitwin ); +} + +machine_config_constructor nes_hori4p_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( hori4p ); +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// nes_horitwin_device - constructor +//------------------------------------------------- + +nes_horitwin_device::nes_horitwin_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, NES_HORITWIN, "Hori Twin Adapter", tag, owner, clock, "nes_horitwin", __FILE__), + device_nes_control_port_interface(mconfig, *this), + m_port1(*this, "port1"), + m_port2(*this, "port2") +{ +} + +nes_hori4p_device::nes_hori4p_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, NES_HORI4P, "Hori 4P Adapter", tag, owner, clock, "nes_hori4p", __FILE__), + device_nes_control_port_interface(mconfig, *this), + m_port1(*this, "port1"), + m_port2(*this, "port2"), + m_port3(*this, "port3"), + m_port4(*this, "port4"), + m_cfg(*this, "CONFIG") +{ +} + + +//------------------------------------------------- +// read +//------------------------------------------------- + +UINT8 nes_horitwin_device::read_exp(offs_t offset) +{ + UINT8 ret = 0; + if (offset == 0) //$4016 + ret |= (m_port1->read_bit0() << 1); + else //$4017 + ret |= (m_port2->read_bit0() << 1); + return ret; +} + +UINT8 nes_hori4p_device::read_exp(offs_t offset) +{ + UINT8 ret = 0; + if (m_cfg->read() == 0) // 2P + { + if (offset == 0) //$4016 + ret |= (m_port1->read_bit0() << 1); + else //$4017 + ret |= (m_port2->read_bit0() << 1); + } + else // 4P + { + if (offset == 0) //$4016 + { + ret |= (m_port1->read_bit0() << 0); + ret |= (m_port3->read_bit0() << 1); + } + else //$4017 + { + ret |= (m_port2->read_bit0() << 0); + ret |= (m_port4->read_bit0() << 1); + } + } + return ret; +} + +//------------------------------------------------- +// write +//------------------------------------------------- + +void nes_horitwin_device::write(UINT8 data) +{ + m_port1->write(data); + m_port2->write(data); +} + +void nes_hori4p_device::write(UINT8 data) +{ + m_port1->write(data); + m_port2->write(data); + m_port3->write(data); + m_port4->write(data); +} diff --git a/src/devices/bus/nes_ctrl/hori.h b/src/devices/bus/nes_ctrl/hori.h new file mode 100644 index 00000000000..8df4fd892ee --- /dev/null +++ b/src/devices/bus/nes_ctrl/hori.h @@ -0,0 +1,78 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/********************************************************************** + + Nintendo Family Computer Hori Twin (and 4P?) adapters + +**********************************************************************/ + +#pragma once + +#ifndef __NES_HORI__ +#define __NES_HORI__ + + +#include "emu.h" +#include "ctrl.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> nes_horitwin_device + +class nes_horitwin_device : public device_t, + public device_nes_control_port_interface +{ +public: + // construction/destruction + nes_horitwin_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual machine_config_constructor device_mconfig_additions() const; + +protected: + // device-level overrides + virtual void device_start() {} + + virtual UINT8 read_exp(offs_t offset); + virtual void write(UINT8 data); + +private: + required_device m_port1; + required_device m_port2; +}; + +// ======================> nes_hori4p_device + +class nes_hori4p_device : public device_t, + public device_nes_control_port_interface +{ +public: + // construction/destruction + nes_hori4p_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual ioport_constructor device_input_ports() const; + virtual machine_config_constructor device_mconfig_additions() const; + +protected: + // device-level overrides + virtual void device_start() {} + + virtual UINT8 read_exp(offs_t offset); + virtual void write(UINT8 data); + +private: + required_device m_port1; + required_device m_port2; + required_device m_port3; + required_device m_port4; + required_ioport m_cfg; +}; + + +// device type definition +extern const device_type NES_HORITWIN; +extern const device_type NES_HORI4P; + + +#endif diff --git a/src/devices/bus/nes_ctrl/joypad.c b/src/devices/bus/nes_ctrl/joypad.c new file mode 100644 index 00000000000..efe17fb8a62 --- /dev/null +++ b/src/devices/bus/nes_ctrl/joypad.c @@ -0,0 +1,315 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/********************************************************************** + + Nintendo Family Computer & Entertainment System Joypads + + The original Famicom had two hardwired controller, with the second + controller slightly different from the first one: it featured no + Start nor Select buttons, but had a built-in microphone (with + very limited capabilities, since it basically only detected two + states: something blowing into it / nothing blowing into it) for + some games to react to users "talking" into it + + Crazy Climber Pads are not really a kind of separate controllers, + but just a couple of small sticks to be put on top of d-pads of + the regular controllers. Users should then control the game by + using both controllers, turned 90 degrees, as a couple of dual + sticks like in the arcade control panel. However, we emulate them + separately so to map the controls to a friendlier default. + + The Arcade Stick we emulate is a controller (apparently manufactured + by Hori, but possibly licensed by Nintendo, since it use the official + logo and brand) which fits into the expansion port and allows to + daisy chain a second controller to the first one, to play 4players + game (an image of such connection is shown e.g. in Nekketsu Koukou + Dodgeball Bu manual) + +**********************************************************************/ + +#include "joypad.h" + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type NES_JOYPAD = &device_creator; +const device_type NES_FCPAD_P2 = &device_creator; +const device_type NES_CCPAD_LEFT = &device_creator; +const device_type NES_CCPAD_RIGHT = &device_creator; +const device_type NES_ARCSTICK = &device_creator; + + +static INPUT_PORTS_START( nes_joypad ) + PORT_START("JOYPAD") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_NAME("A") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("B") + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_SELECT ) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_START ) + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP ) PORT_8WAY + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN ) PORT_8WAY + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT ) PORT_8WAY + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT ) PORT_8WAY +INPUT_PORTS_END + +static INPUT_PORTS_START( nes_fcpad_p2 ) + PORT_START("JOYPAD") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_NAME("A") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("B") + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_SELECT ) PORT_NAME("Microphone") + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP ) PORT_8WAY + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN ) PORT_8WAY + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT ) PORT_8WAY + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT ) PORT_8WAY +INPUT_PORTS_END + +static INPUT_PORTS_START( nes_ccpad_left ) + PORT_START("JOYPAD") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_SELECT ) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_START ) + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_JOYSTICKLEFT_RIGHT ) PORT_8WAY + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_JOYSTICKLEFT_LEFT ) PORT_8WAY + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_JOYSTICKLEFT_UP ) PORT_8WAY + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_JOYSTICKLEFT_DOWN ) PORT_8WAY +INPUT_PORTS_END + +static INPUT_PORTS_START( nes_ccpad_right ) + PORT_START("JOYPAD") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_JOYSTICKRIGHT_RIGHT ) PORT_8WAY + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_JOYSTICKRIGHT_LEFT ) PORT_8WAY + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_JOYSTICKRIGHT_UP ) PORT_8WAY + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_JOYSTICKRIGHT_DOWN ) PORT_8WAY +INPUT_PORTS_END + +static INPUT_PORTS_START( nes_arcstick ) + PORT_START("CONFIG") + PORT_CONFNAME( 0x01, 0x01, "4 Way / 8 Way Joystick") + PORT_CONFSETTING( 0x00, "4 Way" ) + PORT_CONFSETTING( 0x01, "8 Way" ) + PORT_CONFNAME( 0x02, 0x00, "Player ID") + PORT_CONFSETTING( 0x00, "Player I" ) + PORT_CONFSETTING( 0x02, "Player II" ) + + PORT_START("JOYPAD") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_NAME("A") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("B") + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_SELECT ) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_START ) + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP ) PORT_8WAY PORT_CONDITION("CONFIG", 0x01, EQUALS, 0x01) + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN ) PORT_8WAY PORT_CONDITION("CONFIG", 0x01, EQUALS, 0x01) + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT ) PORT_8WAY PORT_CONDITION("CONFIG", 0x01, EQUALS, 0x01) + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT ) PORT_8WAY PORT_CONDITION("CONFIG", 0x01, EQUALS, 0x01) + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP ) PORT_4WAY PORT_CONDITION("CONFIG", 0x01, EQUALS, 0x00) + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN ) PORT_4WAY PORT_CONDITION("CONFIG", 0x01, EQUALS, 0x00) + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT ) PORT_4WAY PORT_CONDITION("CONFIG", 0x01, EQUALS, 0x00) + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT ) PORT_4WAY PORT_CONDITION("CONFIG", 0x01, EQUALS, 0x00) +INPUT_PORTS_END + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor nes_joypad_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( nes_joypad ); +} + +ioport_constructor nes_fcpad2_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( nes_fcpad_p2 ); +} + +ioport_constructor nes_ccpadl_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( nes_ccpad_left ); +} + +ioport_constructor nes_ccpadr_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( nes_ccpad_right ); +} + +ioport_constructor nes_arcstick_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( nes_arcstick ); +} + + + +static SLOT_INTERFACE_START( arcstick_daisy ) + SLOT_INTERFACE("arcstick", NES_ARCSTICK) +SLOT_INTERFACE_END + +static MACHINE_CONFIG_FRAGMENT( arcstick ) + // expansion port to allow daisy chaining + MCFG_FC_EXPANSION_PORT_ADD("subexp", arcstick_daisy, NULL) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor nes_arcstick_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( arcstick ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// nes_joypad_device - constructor +//------------------------------------------------- + +nes_joypad_device::nes_joypad_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_nes_control_port_interface(mconfig, *this), + m_joypad(*this, "JOYPAD") +{ +} + +nes_joypad_device::nes_joypad_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, NES_JOYPAD, "Nintendo NES / FC Control Pad", tag, owner, clock, "nes_joypad", __FILE__), + device_nes_control_port_interface(mconfig, *this), + m_joypad(*this, "JOYPAD") +{ +} + +nes_fcpad2_device::nes_fcpad2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + nes_joypad_device(mconfig, NES_FCPAD_P2, "Nintendo Family Computer P2 Pad", tag, owner, clock, "nes_fcpad2", __FILE__) +{ +} + +nes_ccpadl_device::nes_ccpadl_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + nes_joypad_device(mconfig, NES_CCPAD_LEFT, "FC Crazy Climber Left Pad", tag, owner, clock, "nes_ccpadl", __FILE__) +{ +} + +nes_ccpadr_device::nes_ccpadr_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + nes_joypad_device(mconfig, NES_CCPAD_RIGHT, "FC Crazy Climber Right Pad", tag, owner, clock, "nes_ccpadr", __FILE__) +{ +} + +nes_arcstick_device::nes_arcstick_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + nes_joypad_device(mconfig, NES_ARCSTICK, "Nintendo Family Computer Arcade Stick", tag, owner, clock, "nes_arcstick", __FILE__), + m_daisychain(*this, "subexp"), + m_cfg(*this, "CONFIG") +{ +} + + +//------------------------------------------------- +// device_start +//------------------------------------------------- + +void nes_joypad_device::device_start() +{ + save_item(NAME(m_latch)); +} + + +//------------------------------------------------- +// device_reset +//------------------------------------------------- + +void nes_joypad_device::device_reset() +{ + m_latch = 0; +} + + +//------------------------------------------------- +// read +//------------------------------------------------- + +UINT8 nes_joypad_device::read_bit0() +{ + UINT8 ret = m_latch & 1; + m_latch >>= 1; + return ret; +} + +UINT8 nes_fcpad2_device::read_exp(offs_t offset) +{ + UINT8 ret = 0; + if (!offset) // microphone input + ret |= m_joypad->read() & 0x04; + + return ret; +} + +// NOTE: I haven't found any documentation about what happens when +// users connect two arcade stick both set as P1 or P2 in config. +// does the FC only acknowledge the first one, or do they conflict +// with each other? currently, we only support the following setup: +// if the first pad is set as P1, the daisy chained pad is checked +// for P2 only, and vice versa. +UINT8 nes_arcstick_device::read_exp(offs_t offset) +{ + UINT8 ret = 0; + if (offset == 0) //$4016 + { + if ((m_cfg->read() & 2) == 0) // we are P1 input + { + ret |= (m_latch & 1) << 1; + m_latch >>= 1; + } + else + ret |= m_daisychain->read_exp(0); + } + else //$4017 + { + if ((m_cfg->read() & 2) == 2) // we are P2 input + { + ret |= (m_latch & 1) << 1; + m_latch >>= 1; + } + else + ret |= m_daisychain->read_exp(1); + } + + return ret; +} + +//------------------------------------------------- +// write +//------------------------------------------------- + +void nes_joypad_device::write(UINT8 data) +{ + if (data & 0x01) + return; + + m_latch = m_joypad->read(); +} + +void nes_fcpad2_device::write(UINT8 data) +{ + if (data & 0x01) + return; + + // microphone is hooked to expansion bits, not to the controller bit + m_latch = m_joypad->read() & ~0x04; +} + +void nes_arcstick_device::write(UINT8 data) +{ + m_daisychain->write(data); + + if (data & 0x01) + return; + + m_latch = m_joypad->read(); +} diff --git a/src/devices/bus/nes_ctrl/joypad.h b/src/devices/bus/nes_ctrl/joypad.h new file mode 100644 index 00000000000..87966386e8d --- /dev/null +++ b/src/devices/bus/nes_ctrl/joypad.h @@ -0,0 +1,111 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/********************************************************************** + + Nintendo Family Computer & Entertainment System Joypads + +**********************************************************************/ + +#pragma once + +#ifndef __NES_JOYPAD__ +#define __NES_JOYPAD__ + + +#include "emu.h" +#include "ctrl.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> nes_joypad_device + +class nes_joypad_device : public device_t, + public device_nes_control_port_interface +{ +public: + // construction/destruction + nes_joypad_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + nes_joypad_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual ioport_constructor device_input_ports() const; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + virtual UINT8 read_bit0(); + virtual void write(UINT8 data); + + required_ioport m_joypad; + UINT32 m_latch; +}; + +// ======================> nes_fcpad2_device + +class nes_fcpad2_device : public nes_joypad_device +{ +public: + // construction/destruction + nes_fcpad2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual ioport_constructor device_input_ports() const; + +protected: + virtual UINT8 read_exp(offs_t offset); + virtual void write(UINT8 data); +}; + +// ======================> nes_ccpadl_device + +class nes_ccpadl_device : public nes_joypad_device +{ +public: + // construction/destruction + nes_ccpadl_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual ioport_constructor device_input_ports() const; +}; + +// ======================> nes_ccpadr_device + +class nes_ccpadr_device : public nes_joypad_device +{ +public: + // construction/destruction + nes_ccpadr_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual ioport_constructor device_input_ports() const; +}; + +// ======================> nes_arcstick_device + +class nes_arcstick_device : public nes_joypad_device +{ +public: + // construction/destruction + nes_arcstick_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual ioport_constructor device_input_ports() const; + virtual machine_config_constructor device_mconfig_additions() const; + +protected: + virtual UINT8 read_bit0() { return 0; } + virtual UINT8 read_exp(offs_t offset); + virtual void write(UINT8 data); + + required_device m_daisychain; + required_ioport m_cfg; +}; + + +// device type definition +extern const device_type NES_JOYPAD; +extern const device_type NES_FCPAD_P2; +extern const device_type NES_CCPAD_LEFT; +extern const device_type NES_CCPAD_RIGHT; +extern const device_type NES_ARCSTICK; + +#endif diff --git a/src/devices/bus/nes_ctrl/konamihs.c b/src/devices/bus/nes_ctrl/konamihs.c new file mode 100644 index 00000000000..33be8576788 --- /dev/null +++ b/src/devices/bus/nes_ctrl/konamihs.c @@ -0,0 +1,101 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/********************************************************************** + + Nintendo Family Computer Konami Hyper Shot Controllers + +**********************************************************************/ + +#include "konamihs.h" + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type NES_KONAMIHS = &device_creator; + + +static INPUT_PORTS_START( nes_konamihs ) + PORT_START("P1") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_NAME("PI Run") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("PI Jump") + + PORT_START("P2") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_NAME("PII Run") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("PII Jump") +INPUT_PORTS_END + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor nes_konamihs_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( nes_konamihs ); +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// nes_konamihs_device - constructor +//------------------------------------------------- + +nes_konamihs_device::nes_konamihs_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, NES_KONAMIHS, "Konami Hyper Shot Controller", tag, owner, clock, "nes_konamihs", __FILE__), + device_nes_control_port_interface(mconfig, *this), + m_ipt_p1(*this, "P1"), + m_ipt_p2(*this, "P2") +{ +} + + +//------------------------------------------------- +// device_start +//------------------------------------------------- + +void nes_konamihs_device::device_start() +{ + save_item(NAME(m_latch_p1)); + save_item(NAME(m_latch_p2)); +} + + +//------------------------------------------------- +// device_reset +//------------------------------------------------- + +void nes_konamihs_device::device_reset() +{ + m_latch_p1 = 0; + m_latch_p2 = 0; +} + + +//------------------------------------------------- +// read +//------------------------------------------------- + +UINT8 nes_konamihs_device::read_exp(offs_t offset) +{ + UINT8 ret = 0; + if (offset == 1) //$4017 + { + ret |= m_latch_p1 << 1; + ret |= m_latch_p2 << 3; + } + return ret; +} + +//------------------------------------------------- +// write +//------------------------------------------------- + +void nes_konamihs_device::write(UINT8 data) +{ + if ((data & 0x02) == 0) + m_latch_p1 = m_ipt_p1->read(); + if ((data & 0x04) == 0) + m_latch_p2 = m_ipt_p2->read(); +} diff --git a/src/devices/bus/nes_ctrl/konamihs.h b/src/devices/bus/nes_ctrl/konamihs.h new file mode 100644 index 00000000000..d2ec5b92b2a --- /dev/null +++ b/src/devices/bus/nes_ctrl/konamihs.h @@ -0,0 +1,49 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/********************************************************************** + + Nintendo Family Computer Konami Hyper Shot Controllers + +**********************************************************************/ + +#pragma once + +#ifndef __NES_KONAMIHS__ +#define __NES_KONAMIHS__ + + +#include "emu.h" +#include "ctrl.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> nes_konamihs_device + +class nes_konamihs_device : public device_t, + public device_nes_control_port_interface +{ +public: + // construction/destruction + nes_konamihs_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual ioport_constructor device_input_ports() const; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + virtual UINT8 read_exp(offs_t offset); + virtual void write(UINT8 data); + + required_ioport m_ipt_p1; + required_ioport m_ipt_p2; + UINT32 m_latch_p1, m_latch_p2; +}; + +// device type definition +extern const device_type NES_KONAMIHS; + +#endif diff --git a/src/devices/bus/nes_ctrl/miracle.c b/src/devices/bus/nes_ctrl/miracle.c new file mode 100644 index 00000000000..bcfc6fbadac --- /dev/null +++ b/src/devices/bus/nes_ctrl/miracle.c @@ -0,0 +1,283 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/********************************************************************** + + Nintendo Entertainment System - Miracle Piano Keyboard + + TODO: MIDI input, output is now working. + +**********************************************************************/ + +#include "miracle.h" + +#define MIRACLE_MIDI_WAITING 0 +#define MIRACLE_MIDI_RECEIVE 1 // receive byte from piano +#define MIRACLE_MIDI_SEND 2 // send byte to piano + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type NES_MIRACLE = &device_creator; + + +MACHINE_CONFIG_FRAGMENT( nes_miracle ) + MCFG_MIDI_PORT_ADD("mdin", midiin_slot, "midiin") + MCFG_MIDI_RX_HANDLER(WRITELINE(nes_miracle_device, rx_w)) + + MCFG_MIDI_PORT_ADD("mdout", midiout_slot, "midiout") +MACHINE_CONFIG_END + +machine_config_constructor nes_miracle_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( nes_miracle ); +} + + +//------------------------------------------------- +// device_timer - handler timer events +//------------------------------------------------- + +void nes_miracle_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + if (id == TIMER_STROBE_ON) + { + m_strobe_clock++; + } + else + { + device_serial_interface::device_timer(timer, id, param, ptr); + } +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// nes_miracle_device - constructor +//------------------------------------------------- + +nes_miracle_device::nes_miracle_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, NES_MIRACLE, "Miracle Piano Controller", tag, owner, clock, "nes_miracle", __FILE__), + device_serial_interface(mconfig, *this), + device_nes_control_port_interface(mconfig, *this), + m_midiin(*this, "mdin"), + m_midiout(*this, "mdout") +{ +} + + +//------------------------------------------------- +// device_start +//------------------------------------------------- + +void nes_miracle_device::device_start() +{ + strobe_timer = timer_alloc(TIMER_STROBE_ON); + strobe_timer->adjust(attotime::never); + save_item(NAME(m_strobe_on)); + save_item(NAME(m_sent_bits)); + save_item(NAME(m_strobe_clock)); + save_item(NAME(m_midi_mode)); +} + + +//------------------------------------------------- +// device_reset +//------------------------------------------------- + +void nes_miracle_device::device_reset() +{ + m_strobe_on = 0; + m_sent_bits = 0; + m_strobe_clock = 0; + m_midi_mode = MIRACLE_MIDI_WAITING; + + // set standard MIDI parameters + set_data_frame(1, 8, PARITY_NONE, STOP_BITS_1); + set_rcv_rate(31250); + set_tra_rate(31250); + + m_xmit_read = m_xmit_write = 0; + m_recv_read = m_recv_write = 0; + m_read_status = m_status_bit = false; + m_tx_busy = false; +} + + +//------------------------------------------------- +// read +//------------------------------------------------- + +UINT8 nes_miracle_device::read_bit0() +{ + UINT8 ret = 0; + + if (m_midi_mode == MIRACLE_MIDI_RECEIVE) + { + if (m_status_bit) + { + m_status_bit = false; + ret = (m_read_status) ? 1 : 0; + } + else + { + ret = (m_data_sent & 0x80) ? 0 : 1; + m_data_sent <<= 1; + } + } + + return ret; +} + +//------------------------------------------------- +// write +//------------------------------------------------- + +// c4fc = start of recv routine +// c53a = start of send routine + +void nes_miracle_device::write(UINT8 data) +{ +// printf("write: %d (%d %02x %d)\n", data & 1, m_sent_bits, m_data_sent, m_midi_mode); + + if (m_midi_mode == MIRACLE_MIDI_SEND) + { + //NES writes (data & 1) to Miracle Piano! + // 1st write is data present flag (1=data present) + // next 8 writes are actual data bits (with ^1) + m_sent_bits++; + m_data_sent <<= 1; + m_data_sent |= (data & 1); + // then we go back to waiting + if (m_sent_bits == 8) + { +// printf("xmit MIDI byte %02x\n", m_data_sent); + xmit_char(m_data_sent); + m_midi_mode = MIRACLE_MIDI_WAITING; + m_sent_bits = 0; + } + + return; + } + + if (data == 1 && !m_strobe_on) + { + strobe_timer->adjust(attotime::zero, 0, machine().device("maincpu")->cycles_to_attotime(1)); + m_strobe_on = 1; + return; + } + + if (m_strobe_on) + { + // was timer running? + if (m_strobe_clock > 0) + { +// printf("got strobe at %d clocks\n", m_strobe_clock); + + if (m_strobe_clock < 66 && data == 0) + { + // short delay is receive mode + m_midi_mode = MIRACLE_MIDI_RECEIVE; + strobe_timer->reset(); + m_strobe_on = 0; + m_strobe_clock = 0; + + m_status_bit = true; + if (m_recv_read != m_recv_write) + { +// printf("Getting %02x from Miracle[%d]\n", m_recvring[m_recv_read], m_recv_read); + m_data_sent = m_recvring[m_recv_read++]; + if (m_recv_read >= RECV_RING_SIZE) + { + m_recv_read = 0; + } + m_read_status = true; + } + else + { + m_read_status = false; +// printf("Miracle has no data\n"); + } + return; + } + else if (m_strobe_clock >= 66) + { + // more than 66 clocks since strobe on write means send mode + m_midi_mode = MIRACLE_MIDI_SEND; + strobe_timer->reset(); + m_strobe_on = 0; + m_strobe_clock = 0; + m_sent_bits = 1; + m_data_sent <<= 1; + m_data_sent |= (data & 1); + return; + } + } + + if (m_midi_mode == MIRACLE_MIDI_SEND && data == 0) + { + // strobe off after the end of a byte + m_midi_mode = MIRACLE_MIDI_WAITING; + } + } +} + +void nes_miracle_device::rcv_complete() // Rx completed receiving byte +{ + receive_register_extract(); + UINT8 rcv = get_received_char(); + +// printf("Got %02x -> [%d]\n", rcv, m_recv_write); + m_recvring[m_recv_write++] = rcv; + if (m_recv_write >= RECV_RING_SIZE) + { + m_recv_write = 0; + } +} + +void nes_miracle_device::tra_complete() // Tx completed sending byte +{ + // is there more waiting to send? + if (m_xmit_read != m_xmit_write) + { + transmit_register_setup(m_xmitring[m_xmit_read++]); + if (m_xmit_read >= XMIT_RING_SIZE) + { + m_xmit_read = 0; + } + } + else + { + m_tx_busy = false; + } +} + +void nes_miracle_device::tra_callback() // Tx send bit +{ + UINT8 bit = transmit_register_get_data_bit(); + + // send this to midi out + m_midiout->write_txd(bit); +} + +void nes_miracle_device::xmit_char(UINT8 data) +{ + // if tx is busy it'll pick this up automatically when it completes + // if not, send now! + if (!m_tx_busy) + { + m_tx_busy = true; + transmit_register_setup(data); + } + else + { + // tx is busy, it'll pick this up next time + m_xmitring[m_xmit_write++] = data; + if (m_xmit_write >= XMIT_RING_SIZE) + { + m_xmit_write = 0; + } + } +} diff --git a/src/devices/bus/nes_ctrl/miracle.h b/src/devices/bus/nes_ctrl/miracle.h new file mode 100644 index 00000000000..ee68cf7f357 --- /dev/null +++ b/src/devices/bus/nes_ctrl/miracle.h @@ -0,0 +1,71 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/********************************************************************** + + Nintendo Entertainment System - Miracle Piano Keyboard + +**********************************************************************/ + +#pragma once + +#ifndef __NES_MIRACLE__ +#define __NES_MIRACLE__ + + +#include "emu.h" +#include "ctrl.h" +#include "bus/midi/midi.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> nes_miracle_device + +class nes_miracle_device : public device_t, + public device_serial_interface, + public device_nes_control_port_interface +{ +public: + static const int XMIT_RING_SIZE = 64; + static const int RECV_RING_SIZE = 64; + + // construction/destruction + nes_miracle_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + virtual machine_config_constructor device_mconfig_additions() const; + + // serial overrides + virtual void rcv_complete(); // Rx completed receiving byte + virtual void tra_complete(); // Tx completed sending byte + virtual void tra_callback(); // Tx send bit + + void xmit_char(UINT8 data); + + required_device m_midiin, m_midiout; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + virtual UINT8 read_bit0(); + virtual void write(UINT8 data); + + static const device_timer_id TIMER_STROBE_ON = 0; + emu_timer *strobe_timer; + + int m_strobe_on, m_midi_mode, m_sent_bits; + UINT32 m_strobe_clock; + UINT8 m_data_sent; + UINT8 m_xmitring[XMIT_RING_SIZE], m_recvring[RECV_RING_SIZE]; + int m_xmit_read, m_xmit_write; + int m_recv_read, m_recv_write; + bool m_tx_busy, m_read_status, m_status_bit; +}; + +// device type definition +extern const device_type NES_MIRACLE; + +#endif diff --git a/src/devices/bus/nes_ctrl/mjpanel.c b/src/devices/bus/nes_ctrl/mjpanel.c new file mode 100644 index 00000000000..cb37aeb1c2a --- /dev/null +++ b/src/devices/bus/nes_ctrl/mjpanel.c @@ -0,0 +1,131 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/********************************************************************** + + Nintendo Family Computer Mahjong Panel + +**********************************************************************/ + +#include "mjpanel.h" + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type NES_MJPANEL = &device_creator; + + +static INPUT_PORTS_START( nes_mjpanel ) + PORT_START("MJPANEL.0") + PORT_BIT( 0xff, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("MJPANEL.1") + PORT_BIT( 0x03, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_MAHJONG_N ) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_MAHJONG_M ) + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_MAHJONG_L ) + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_MAHJONG_K ) + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_MAHJONG_J ) + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_MAHJONG_I ) + + PORT_START("MJPANEL.2") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_MAHJONG_H ) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_MAHJONG_G ) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_MAHJONG_F ) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_MAHJONG_E ) + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_MAHJONG_D ) + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_MAHJONG_C ) + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_MAHJONG_B ) + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_MAHJONG_A ) + + PORT_START("MJPANEL.3") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_MAHJONG_RON ) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_MAHJONG_REACH ) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_MAHJONG_CHI ) + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_MAHJONG_PON ) + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_MAHJONG_KAN ) + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_SELECT ) PORT_NAME("Mahjong Select") + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_START ) PORT_NAME("Mahjong Start") +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor nes_mjpanel_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( nes_mjpanel ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// nes_mjpanel_device - constructor +//------------------------------------------------- + +nes_mjpanel_device::nes_mjpanel_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, NES_MJPANEL, "Famicom Mahjong Panel", tag, owner, clock, "nes_mjpanel", __FILE__), + device_nes_control_port_interface(mconfig, *this), + m_panel(*this, "MJPANEL") +{ +} + + +//------------------------------------------------- +// device_start +//------------------------------------------------- + +void nes_mjpanel_device::device_start() +{ + save_item(NAME(m_latch)); +} + + +//------------------------------------------------- +// device_reset +//------------------------------------------------- + +void nes_mjpanel_device::device_reset() +{ + m_latch = 0; +} + + +//------------------------------------------------- +// read +//------------------------------------------------- + +UINT8 nes_mjpanel_device::read_exp(offs_t offset) +{ + UINT8 ret = 0; + if (offset) + { + ret = (m_latch & 1) << 1; + m_latch >>= 1; + } + else + logerror("Error: Mahjong panel read from $4016\n"); + + return ret; +} + +//------------------------------------------------- +// write +//------------------------------------------------- + +void nes_mjpanel_device::write(UINT8 data) +{ + if (data & 0x01) + return; + + if (data & 0xf8) + logerror("Error: Mahjong panel read with mux data %02x\n", (data & 0xfe)); + else + m_latch = m_panel[(data & 0xfe) >> 1]->read(); +} diff --git a/src/devices/bus/nes_ctrl/mjpanel.h b/src/devices/bus/nes_ctrl/mjpanel.h new file mode 100644 index 00000000000..e48ee792a80 --- /dev/null +++ b/src/devices/bus/nes_ctrl/mjpanel.h @@ -0,0 +1,51 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/********************************************************************** + + Nintendo Family Computer Mahjong Panel + +**********************************************************************/ + +#pragma once + +#ifndef __NES_MJPANEL__ +#define __NES_MJPANEL__ + + +#include "emu.h" +#include "ctrl.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> nes_mjpanel_device + +class nes_mjpanel_device : public device_t, + public device_nes_control_port_interface +{ +public: + // construction/destruction + nes_mjpanel_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual ioport_constructor device_input_ports() const; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + virtual UINT8 read_exp(offs_t offset); + virtual void write(UINT8 data); + +private: + required_ioport_array<4> m_panel; + UINT32 m_latch; +}; + + +// device type definition +extern const device_type NES_MJPANEL; + + +#endif diff --git a/src/devices/bus/nes_ctrl/pachinko.c b/src/devices/bus/nes_ctrl/pachinko.c new file mode 100644 index 00000000000..8c61cf00c14 --- /dev/null +++ b/src/devices/bus/nes_ctrl/pachinko.c @@ -0,0 +1,107 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/********************************************************************** + + Nintendo Family Computer Pachinko Controller + +**********************************************************************/ + +#include "pachinko.h" + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type NES_PACHINKO = &device_creator; + + +static INPUT_PORTS_START( nes_pachinko ) + PORT_START("JOYPAD") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_NAME("A") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("B") + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_SELECT ) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_START ) + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP ) PORT_8WAY + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN ) PORT_8WAY + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT ) PORT_8WAY + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT ) PORT_8WAY + + PORT_START("TRIGGER") + PORT_BIT( 0xff, 0, IPT_PEDAL ) PORT_MINMAX(0, 0x63) PORT_SENSITIVITY(25) PORT_KEYDELTA(20) +INPUT_PORTS_END + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor nes_pachinko_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( nes_pachinko ); +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// nes_pachinko_device - constructor +//------------------------------------------------- + +nes_pachinko_device::nes_pachinko_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, NES_PACHINKO, "Famicom Pachinko Controller", tag, owner, clock, "nes_pachinko", __FILE__), + device_nes_control_port_interface(mconfig, *this), + m_joypad(*this, "JOYPAD"), + m_trigger(*this, "TRIGGER") +{ +} + + +//------------------------------------------------- +// device_start +//------------------------------------------------- + +void nes_pachinko_device::device_start() +{ + save_item(NAME(m_latch)); +} + + +//------------------------------------------------- +// device_reset +//------------------------------------------------- + +void nes_pachinko_device::device_reset() +{ + m_latch = 0; +} + + +//------------------------------------------------- +// read +//------------------------------------------------- + +UINT8 nes_pachinko_device::read_exp(offs_t offset) +{ + UINT8 ret = 0; + // this controller behaves like a standard P3 joypad, with longer stream of inputs + if (offset == 0) //$4016 + { + ret |= (m_latch & 1) << 1; + m_latch >>= 1; + } + return ret; +} + +//------------------------------------------------- +// write +//------------------------------------------------- + +void nes_pachinko_device::write(UINT8 data) +{ + if (data & 0x01) + return; + + m_latch = m_joypad->read(); + m_latch |= ((m_trigger->read() ^ 0xff) & 0xff) << 8; + m_latch |= 0xff0000; +} diff --git a/src/devices/bus/nes_ctrl/pachinko.h b/src/devices/bus/nes_ctrl/pachinko.h new file mode 100644 index 00000000000..8d01ce6983d --- /dev/null +++ b/src/devices/bus/nes_ctrl/pachinko.h @@ -0,0 +1,49 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/********************************************************************** + + Nintendo Family Computer Pachinko Controller + +**********************************************************************/ + +#pragma once + +#ifndef __NES_PACHINKO__ +#define __NES_PACHINKO__ + + +#include "emu.h" +#include "ctrl.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> nes_pachinko_device + +class nes_pachinko_device : public device_t, + public device_nes_control_port_interface +{ +public: + // construction/destruction + nes_pachinko_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual ioport_constructor device_input_ports() const; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + virtual UINT8 read_exp(offs_t offset); + virtual void write(UINT8 data); + + required_ioport m_joypad; + required_ioport m_trigger; + UINT32 m_latch; +}; + +// device type definition +extern const device_type NES_PACHINKO; + +#endif diff --git a/src/devices/bus/nes_ctrl/partytap.c b/src/devices/bus/nes_ctrl/partytap.c new file mode 100644 index 00000000000..3338a443423 --- /dev/null +++ b/src/devices/bus/nes_ctrl/partytap.c @@ -0,0 +1,107 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/********************************************************************** + + Nintendo Family Computer Yonezawa / PartyRoom 21 Party Tap Controller + +**********************************************************************/ + +#include "partytap.h" + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type NES_PARTYTAP = &device_creator; + + +static INPUT_PORTS_START( nes_partytap ) + PORT_START("INPUTS") + PORT_BIT( 0x03, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("P1 Button") PORT_CODE(KEYCODE_Z) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("P2 Button") PORT_CODE(KEYCODE_X) + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("P3 Button") PORT_CODE(KEYCODE_C) + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("P4 Button") PORT_CODE(KEYCODE_V) + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("P5 Button") PORT_CODE(KEYCODE_B) + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("P6 Button") PORT_CODE(KEYCODE_N) +INPUT_PORTS_END + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor nes_partytap_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( nes_partytap ); +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// nes_partytap_device - constructor +//------------------------------------------------- + +nes_partytap_device::nes_partytap_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, NES_PARTYTAP, "Yonezawa Party Tap Controller", tag, owner, clock, "nes_partytap", __FILE__), + device_nes_control_port_interface(mconfig, *this), + m_inputs(*this, "INPUTS") +{ +} + + +//------------------------------------------------- +// device_start +//------------------------------------------------- + +void nes_partytap_device::device_start() +{ + save_item(NAME(m_latch)); + save_item(NAME(m_mode)); +} + + +//------------------------------------------------- +// device_reset +//------------------------------------------------- + +void nes_partytap_device::device_reset() +{ + m_mode = 0xe0; + m_latch = 0; +} + + +//------------------------------------------------- +// read +//------------------------------------------------- + +UINT8 nes_partytap_device::read_exp(offs_t offset) +{ + UINT8 ret = 0; + if (offset == 1) //$4017 + { + ret |= m_latch & 0x1c; + m_latch >>= 3; + // append mode bits + m_latch |= m_mode; + } + return ret; +} + +//------------------------------------------------- +// write +//------------------------------------------------- + +void nes_partytap_device::write(UINT8 data) +{ + // inputs are read in two chunks of 3 bits, before the second one is read bit2 is written here + // probably a mechanism for the game to detect which group of inputs is being read + m_mode = BIT(data, 2) ? 0xa0 : 0xe0; + + if (data & 0x01) + return; + + m_latch = m_inputs->read(); +} diff --git a/src/devices/bus/nes_ctrl/partytap.h b/src/devices/bus/nes_ctrl/partytap.h new file mode 100644 index 00000000000..3fc29c19445 --- /dev/null +++ b/src/devices/bus/nes_ctrl/partytap.h @@ -0,0 +1,49 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/********************************************************************** + + Nintendo Family Computer Yonezawa / PartyRoom 21 Party Tap Controller + +**********************************************************************/ + +#pragma once + +#ifndef __NES_PARTYTAP__ +#define __NES_PARTYTAP__ + + +#include "emu.h" +#include "ctrl.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> nes_partytap_device + +class nes_partytap_device : public device_t, + public device_nes_control_port_interface +{ +public: + // construction/destruction + nes_partytap_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual ioport_constructor device_input_ports() const; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + virtual UINT8 read_exp(offs_t offset); + virtual void write(UINT8 data); + + required_ioport m_inputs; + UINT8 m_mode; + UINT32 m_latch; +}; + +// device type definition +extern const device_type NES_PARTYTAP; + +#endif diff --git a/src/devices/bus/nes_ctrl/powerpad.c b/src/devices/bus/nes_ctrl/powerpad.c new file mode 100644 index 00000000000..569695d97ca --- /dev/null +++ b/src/devices/bus/nes_ctrl/powerpad.c @@ -0,0 +1,135 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/********************************************************************** + + Nintendo Entertainment System - Bandai Power Pad + +**********************************************************************/ + +#include "powerpad.h" + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type NES_POWERPAD = &device_creator; + + +static INPUT_PORTS_START( nes_powerpad ) + PORT_START("LAYOUT") + PORT_CONFNAME( 0x01, 0x00, "Power Pad Button Layout") + PORT_CONFSETTING( 0x00, "Side A" ) + PORT_CONFSETTING( 0x01, "Side B" ) + + // difference between the two sides is that we mirror the key mapping to match the real pad layout! + PORT_START("POWERPAD1") + // side A layout + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("PowerPad Top1") PORT_CODE(KEYCODE_Y) PORT_CONDITION("LAYOUT", 0x01, EQUALS, 0x00) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_UNUSED ) PORT_CONDITION("LAYOUT", 0x01, EQUALS, 0x00) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("PowerPad Mid1") PORT_CODE(KEYCODE_J) PORT_CONDITION("LAYOUT", 0x01, EQUALS, 0x00) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_UNUSED ) PORT_CONDITION("LAYOUT", 0x01, EQUALS, 0x00) + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("PowerPad Mid2") PORT_CODE(KEYCODE_H) PORT_CONDITION("LAYOUT", 0x01, EQUALS, 0x00) + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("PowerPad Low1") PORT_CODE(KEYCODE_N) PORT_CONDITION("LAYOUT", 0x01, EQUALS, 0x00) + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("PowerPad Low2") PORT_CODE(KEYCODE_B) PORT_CONDITION("LAYOUT", 0x01, EQUALS, 0x00) + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("PowerPad Mid3") PORT_CODE(KEYCODE_G) PORT_CONDITION("LAYOUT", 0x01, EQUALS, 0x00) + // side B layout + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("PowerPad 2") PORT_CODE(KEYCODE_T) PORT_CONDITION("LAYOUT", 0x01, EQUALS, 0x01) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("PowerPad 1") PORT_CODE(KEYCODE_R) PORT_CONDITION("LAYOUT", 0x01, EQUALS, 0x01) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("PowerPad 5") PORT_CODE(KEYCODE_F) PORT_CONDITION("LAYOUT", 0x01, EQUALS, 0x01) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("PowerPad 9") PORT_CODE(KEYCODE_V) PORT_CONDITION("LAYOUT", 0x01, EQUALS, 0x01) + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("PowerPad 6") PORT_CODE(KEYCODE_G) PORT_CONDITION("LAYOUT", 0x01, EQUALS, 0x01) + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("PowerPad 10") PORT_CODE(KEYCODE_B) PORT_CONDITION("LAYOUT", 0x01, EQUALS, 0x01) + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("PowerPad 11") PORT_CODE(KEYCODE_N) PORT_CONDITION("LAYOUT", 0x01, EQUALS, 0x01) + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("PowerPad 7") PORT_CODE(KEYCODE_H) PORT_CONDITION("LAYOUT", 0x01, EQUALS, 0x01) + + PORT_START("POWERPAD2") + // side A layout + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_UNUSED ) PORT_CONDITION("LAYOUT", 0x01, EQUALS, 0x00) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("PowerPad Top2") PORT_CODE(KEYCODE_T) PORT_CONDITION("LAYOUT", 0x01, EQUALS, 0x00) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_UNUSED ) PORT_CONDITION("LAYOUT", 0x01, EQUALS, 0x00) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("PowerPad Mid4") PORT_CODE(KEYCODE_F) PORT_CONDITION("LAYOUT", 0x01, EQUALS, 0x00) + PORT_BIT( 0xf0, IP_ACTIVE_HIGH, IPT_UNUSED ) PORT_CONDITION("LAYOUT", 0x01, EQUALS, 0x00) + // side B layout + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("PowerPad 4") PORT_CODE(KEYCODE_U) PORT_CONDITION("LAYOUT", 0x01, EQUALS, 0x01) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("PowerPad 3") PORT_CODE(KEYCODE_Y) PORT_CONDITION("LAYOUT", 0x01, EQUALS, 0x01) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("PowerPad 12") PORT_CODE(KEYCODE_M) PORT_CONDITION("LAYOUT", 0x01, EQUALS, 0x01) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("PowerPad 8") PORT_CODE(KEYCODE_J) PORT_CONDITION("LAYOUT", 0x01, EQUALS, 0x01) + PORT_BIT( 0xf0, IP_ACTIVE_HIGH, IPT_UNUSED ) PORT_CONDITION("LAYOUT", 0x01, EQUALS, 0x01) +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor nes_powerpad_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( nes_powerpad ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// nes_powerpad_device - constructor +//------------------------------------------------- + +nes_powerpad_device::nes_powerpad_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, NES_POWERPAD, "Bandai Power Pad", tag, owner, clock, "nes_powerpad", __FILE__), + device_nes_control_port_interface(mconfig, *this), + m_ipt1(*this, "POWERPAD1"), + m_ipt2(*this, "POWERPAD2") +{ +} + + +//------------------------------------------------- +// device_start +//------------------------------------------------- + +void nes_powerpad_device::device_start() +{ + save_item(NAME(m_latch)); +} + + +//------------------------------------------------- +// device_reset +//------------------------------------------------- + +void nes_powerpad_device::device_reset() +{ + m_latch[0] = 0; + m_latch[1] = 0; +} + + +//------------------------------------------------- +// read +//------------------------------------------------- + +UINT8 nes_powerpad_device::read_bit34() +{ + UINT8 ret = 0; + ret |= (m_latch[0] & 0x01) << 3; + ret |= (m_latch[1] & 0x01) << 4; + m_latch[0] >>= 1; + m_latch[1] >>= 1; + return ret; +} + +//------------------------------------------------- +// write +//------------------------------------------------- + +void nes_powerpad_device::write(UINT8 data) +{ + if (data & 0x01) + return; + + m_latch[0] = m_ipt1->read(); + m_latch[1] = m_ipt2->read() | 0xf0; +} diff --git a/src/devices/bus/nes_ctrl/powerpad.h b/src/devices/bus/nes_ctrl/powerpad.h new file mode 100644 index 00000000000..47463a9055c --- /dev/null +++ b/src/devices/bus/nes_ctrl/powerpad.h @@ -0,0 +1,52 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/********************************************************************** + + Nintendo Entertainment System - Bandai Power Pad + +**********************************************************************/ + +#pragma once + +#ifndef __NES_POWERPAD__ +#define __NES_POWERPAD__ + + +#include "emu.h" +#include "ctrl.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> nes_powerpad_device + +class nes_powerpad_device : public device_t, + public device_nes_control_port_interface +{ +public: + // construction/destruction + nes_powerpad_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual ioport_constructor device_input_ports() const; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + virtual UINT8 read_bit34(); + virtual void write(UINT8 data); + +private: + required_ioport m_ipt1; + required_ioport m_ipt2; + UINT32 m_latch[2]; +}; + + +// device type definition +extern const device_type NES_POWERPAD; + + +#endif diff --git a/src/devices/bus/nes_ctrl/suborkey.c b/src/devices/bus/nes_ctrl/suborkey.c new file mode 100644 index 00000000000..8c6e6be7b3c --- /dev/null +++ b/src/devices/bus/nes_ctrl/suborkey.c @@ -0,0 +1,229 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/********************************************************************** + + Nintendo Family Computer Subor Keyboard (used by some Famiclones) + +**********************************************************************/ + +#include "suborkey.h" + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type NES_SUBORKEYBOARD = &device_creator; + + +static INPUT_PORTS_START( fc_suborkey ) + PORT_START("SUBOR.0") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_4) PORT_CHAR('4') + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_G) PORT_CHAR('G') + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F) PORT_CHAR('F') + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_C) PORT_CHAR('C') + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F2) PORT_CHAR(UCHAR_MAMEKEY(F2)) + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_E) PORT_CHAR('E') + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_5) PORT_CHAR('5') + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_V) PORT_CHAR('V') + + PORT_START("SUBOR.1") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_2) PORT_CHAR('2') + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_D) PORT_CHAR('D') + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_S) PORT_CHAR('S') + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_END) PORT_CHAR(UCHAR_MAMEKEY(END)) + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F1) PORT_CHAR(UCHAR_MAMEKEY(F1)) + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_W) PORT_CHAR('W') + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_3) PORT_CHAR('3') + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_X) PORT_CHAR('X') + + PORT_START("SUBOR.2") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_INSERT) PORT_CHAR(UCHAR_MAMEKEY(INSERT)) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_BACKSPACE) PORT_CHAR(8) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("NEXT") + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_RIGHT) PORT_CHAR(UCHAR_MAMEKEY(RIGHT)) + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F8) PORT_CHAR(UCHAR_MAMEKEY(F8)) + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("PRIOR") + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_DEL) PORT_CHAR(UCHAR_MAMEKEY(DEL)) + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_HOME) PORT_CHAR(UCHAR_MAMEKEY(HOME)) + + PORT_START("SUBOR.3") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_9) PORT_CHAR('9') + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_I) PORT_CHAR('I') + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_L) PORT_CHAR('L') + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_COMMA) PORT_CHAR(',') + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F5) PORT_CHAR(UCHAR_MAMEKEY(F5)) + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_O) PORT_CHAR('O') + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_0) PORT_CHAR('0') + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_STOP) PORT_CHAR('.') + + PORT_START("SUBOR.4") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_CLOSEBRACE) PORT_CHAR(']') + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_ENTER) PORT_CHAR(13) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_UP) PORT_CHAR(UCHAR_MAMEKEY(UP)) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_LEFT) PORT_CHAR(UCHAR_MAMEKEY(LEFT)) + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F7) PORT_CHAR(UCHAR_MAMEKEY(F7)) + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_OPENBRACE) PORT_CHAR('[') + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_BACKSLASH) PORT_CHAR('\\') + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_DOWN) PORT_CHAR(UCHAR_MAMEKEY(DOWN)) + + PORT_START("SUBOR.5") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Q) PORT_CHAR('Q') + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_CAPSLOCK) PORT_CHAR(UCHAR_MAMEKEY(CAPSLOCK)) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Z) PORT_CHAR('Z') + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_TAB) PORT_CHAR('\t') + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_ESC) PORT_CHAR(UCHAR_MAMEKEY(ESC)) + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_A) PORT_CHAR('A') + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_1) PORT_CHAR('1') + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_LCONTROL) PORT_CHAR(UCHAR_SHIFT_2) + + PORT_START("SUBOR.6") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_7) PORT_CHAR('7') + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Y) PORT_CHAR('Y') + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_K) PORT_CHAR('K') + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_M) PORT_CHAR('M') + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F4) PORT_CHAR(UCHAR_MAMEKEY(F4)) + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_U) PORT_CHAR('U') + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_8) PORT_CHAR('8') + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_J) PORT_CHAR('J') + + PORT_START("SUBOR.7") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_MINUS) PORT_CHAR('-') + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_COLON) PORT_CHAR(':') + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_QUOTE) PORT_CHAR('\'') + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_SLASH) PORT_CHAR('/') + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F6) PORT_CHAR(UCHAR_MAMEKEY(F6)) + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_P) PORT_CHAR('P') + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_EQUALS) PORT_CHAR('=') + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_LSHIFT) PORT_CHAR(UCHAR_SHIFT_1) + + PORT_START("SUBOR.8") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_T) PORT_CHAR('T') + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_H) PORT_CHAR('H') + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_N) PORT_CHAR('N') + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_SPACE) PORT_CHAR(' ') + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F3) PORT_CHAR(UCHAR_MAMEKEY(F3)) + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_R) PORT_CHAR('R') + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_6) PORT_CHAR('6') + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_B) PORT_CHAR('B') + + PORT_START("SUBOR.9") + PORT_BIT( 0xff, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("SUBOR.10") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("LMENU") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_4_PAD) PORT_CHAR(UCHAR_MAMEKEY(4_PAD)) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_7_PAD) PORT_CHAR(UCHAR_MAMEKEY(7_PAD)) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F11) PORT_CHAR(UCHAR_MAMEKEY(F11)) + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F12) PORT_CHAR(UCHAR_MAMEKEY(F12)) + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_1_PAD) PORT_CHAR(UCHAR_MAMEKEY(1_PAD)) + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_2_PAD) PORT_CHAR(UCHAR_MAMEKEY(2_PAD)) + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_8_PAD) PORT_CHAR(UCHAR_MAMEKEY(8_PAD)) + + PORT_START("SUBOR.11") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_MINUS_PAD)PORT_CHAR(UCHAR_MAMEKEY(MINUS_PAD)) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_PLUS_PAD) PORT_CHAR(UCHAR_MAMEKEY(PLUS_PAD)) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_ASTERISK) PORT_CHAR(UCHAR_MAMEKEY(ASTERISK)) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_9_PAD) PORT_CHAR(UCHAR_MAMEKEY(9_PAD)) + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F10) PORT_CHAR(UCHAR_MAMEKEY(F10)) + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_5_PAD) PORT_CHAR(UCHAR_MAMEKEY(5_PAD)) + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_SLASH_PAD)PORT_CHAR(UCHAR_MAMEKEY(SLASH_PAD)) + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_NUMLOCK) PORT_CHAR(UCHAR_MAMEKEY(NUMLOCK)) + + PORT_START("SUBOR.12") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_TILDE) PORT_CHAR('`') + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_6_PAD) PORT_CHAR(UCHAR_MAMEKEY(6_PAD)) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("PAUSE") + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("SPACE2") + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F9) PORT_CHAR(UCHAR_MAMEKEY(F9)) + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_3_PAD) PORT_CHAR(UCHAR_MAMEKEY(3_PAD)) + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Keypad .") PORT_CODE(KEYCODE_DEL_PAD) + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_0_PAD) PORT_CHAR(UCHAR_MAMEKEY(0_PAD)) +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor nes_suborkey_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( fc_suborkey ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// nes_suborkey_device - constructor +//------------------------------------------------- + +nes_suborkey_device::nes_suborkey_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, NES_SUBORKEYBOARD, "Subor FC Keyboard", tag, owner, clock, "nes_suborkey", __FILE__), + device_nes_control_port_interface(mconfig, *this), + m_kbd(*this, "SUBOR") +{ +} + + +//------------------------------------------------- +// device_start +//------------------------------------------------- + +void nes_suborkey_device::device_start() +{ + save_item(NAME(m_fck_scan)); + save_item(NAME(m_fck_mode)); +} + + +//------------------------------------------------- +// device_reset +//------------------------------------------------- + +void nes_suborkey_device::device_reset() +{ + m_fck_scan = 0; + m_fck_mode = 0; +} + + +//------------------------------------------------- +// read +//------------------------------------------------- + +UINT8 nes_suborkey_device::read_exp(offs_t offset) +{ + UINT8 ret = 0; + if (offset == 1) //$4017 + { + // Subor Keyboard: rows of the keyboard matrix are read 4-bits at time and returned as bit1->bit4 + if (m_fck_scan < 13) + ret |= ~(((m_kbd[m_fck_scan]->read() >> (m_fck_mode * 4)) & 0x0f) << 1) & 0x1e; + else + ret |= 0x1e; + } + + return ret; +} + +//------------------------------------------------- +// write +//------------------------------------------------- + +void nes_suborkey_device::write(UINT8 data) +{ + if (BIT(data, 2)) // keyboard active + { + UINT8 out = BIT(data, 1); // scan + if (m_fck_mode && !out && ++m_fck_scan > 12) + m_fck_scan = 0; + + m_fck_mode = out; // access lower or upper 4 bits + + if (BIT(data, 0)) // reset + m_fck_scan = 0; + } +} diff --git a/src/devices/bus/nes_ctrl/suborkey.h b/src/devices/bus/nes_ctrl/suborkey.h new file mode 100644 index 00000000000..21f804da6f0 --- /dev/null +++ b/src/devices/bus/nes_ctrl/suborkey.h @@ -0,0 +1,51 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/********************************************************************** + + Nintendo Family Computer Subor Keyboard (used by some Famiclones) + +**********************************************************************/ + +#pragma once + +#ifndef __NES_SUBORKEY__ +#define __NES_SUBORKEY__ + + +#include "emu.h" +#include "ctrl.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> nes_suborkey_device + +class nes_suborkey_device : public device_t, + public device_nes_control_port_interface +{ +public: + // construction/destruction + nes_suborkey_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual ioport_constructor device_input_ports() const; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + virtual UINT8 read_exp(offs_t offset); + virtual void write(UINT8 data); + +private: + required_ioport_array<13> m_kbd; + UINT8 m_fck_scan, m_fck_mode; +}; + + +// device type definition +extern const device_type NES_SUBORKEYBOARD; + + +#endif diff --git a/src/devices/bus/nes_ctrl/zapper.c b/src/devices/bus/nes_ctrl/zapper.c new file mode 100644 index 00000000000..422b9664f5e --- /dev/null +++ b/src/devices/bus/nes_ctrl/zapper.c @@ -0,0 +1,96 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/********************************************************************** + + Nintendo Family Computer & Entertainment System Zapper Lightgun + +**********************************************************************/ + +#include "zapper.h" + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type NES_ZAPPER = &device_creator; + + +static INPUT_PORTS_START( nes_zapper ) + PORT_START("ZAPPER_X") + PORT_BIT( 0xff, 0x80, IPT_LIGHTGUN_X) PORT_CROSSHAIR(X, 1.0, 0.0, 0) PORT_SENSITIVITY(70) PORT_KEYDELTA(30) PORT_MINMAX(0,255) + PORT_START("ZAPPER_Y") + PORT_BIT( 0xff, 0x80, IPT_LIGHTGUN_Y) PORT_CROSSHAIR(Y, 1.0, 0.0, 0) PORT_SENSITIVITY(50) PORT_KEYDELTA(30) PORT_MINMAX(0,255) + PORT_START("ZAPPER_T") + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_BUTTON1) PORT_NAME("Lightgun Trigger") +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor nes_zapper_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( nes_zapper ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// nes_zapper_device - constructor +//------------------------------------------------- + +nes_zapper_device::nes_zapper_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, NES_ZAPPER, "Nintendo Zapper Lightgun", tag, owner, clock, "nes_zapper", __FILE__), + device_nes_control_port_interface(mconfig, *this), + m_lightx(*this, "ZAPPER_X"), + m_lighty(*this, "ZAPPER_Y"), + m_trigger(*this, "ZAPPER_T") +{ +} + + +//------------------------------------------------- +// device_start +//------------------------------------------------- + +void nes_zapper_device::device_start() +{ +} + + +//------------------------------------------------- +// device_reset +//------------------------------------------------- + +void nes_zapper_device::device_reset() +{ +} + + +//------------------------------------------------- +// read +//------------------------------------------------- + +UINT8 nes_zapper_device::read_bit34() +{ + UINT8 ret = m_trigger->read(); + if (!m_port->m_brightpixel_cb.isnull() && + m_port->m_brightpixel_cb(m_lightx->read(), m_lighty->read())) + ret &= ~0x08; // sprite hit + else + ret |= 0x08; // no sprite hit + return ret; +} + +UINT8 nes_zapper_device::read_exp(offs_t offset) +{ + UINT8 ret = 0; + if (offset == 1) // $4017 + ret |= nes_zapper_device::read_bit34(); + return ret; +} diff --git a/src/devices/bus/nes_ctrl/zapper.h b/src/devices/bus/nes_ctrl/zapper.h new file mode 100644 index 00000000000..ca4b1eb40fd --- /dev/null +++ b/src/devices/bus/nes_ctrl/zapper.h @@ -0,0 +1,52 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/********************************************************************** + + Nintendo Family Computer & Entertainment System Zapper Lightgun + +**********************************************************************/ + +#pragma once + +#ifndef __NES_ZAPPER__ +#define __NES_ZAPPER__ + + +#include "emu.h" +#include "ctrl.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> nes_zapper_device + +class nes_zapper_device : public device_t, + public device_nes_control_port_interface +{ +public: + // construction/destruction + nes_zapper_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual ioport_constructor device_input_ports() const; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + virtual UINT8 read_bit34(); + virtual UINT8 read_exp(offs_t offset); + +private: + required_ioport m_lightx; + required_ioport m_lighty; + required_ioport m_trigger; +}; + + +// device type definition +extern const device_type NES_ZAPPER; + + +#endif diff --git a/src/devices/bus/nubus/nubus.c b/src/devices/bus/nubus/nubus.c new file mode 100644 index 00000000000..5d6548289ec --- /dev/null +++ b/src/devices/bus/nubus/nubus.c @@ -0,0 +1,475 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/*************************************************************************** + + nubus.c - NuBus bus and card emulation + + by R. Belmont, based heavily on Miodrag Milanovic's ISA8/16 implementation + +***************************************************************************/ + +#include "emu.h" +#include "emuopts.h" +#include "nubus.h" + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type NUBUS_SLOT = &device_creator; + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// nubus_slot_device - constructor +//------------------------------------------------- +nubus_slot_device::nubus_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, NUBUS_SLOT, "NUBUS_SLOT", tag, owner, clock, "nubus_slot", __FILE__), + device_slot_interface(mconfig, *this) +{ +} + +nubus_slot_device::nubus_slot_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_slot_interface(mconfig, *this) +{ +} + +void nubus_slot_device::static_set_nubus_slot(device_t &device, const char *tag, const char *slottag) +{ + nubus_slot_device &nubus_card = dynamic_cast(device); + nubus_card.m_nubus_tag = tag; + nubus_card.m_nubus_slottag = slottag; +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void nubus_slot_device::device_start() +{ + device_nubus_card_interface *dev = dynamic_cast(get_card_device()); + + if (dev) device_nubus_card_interface::static_set_nubus_tag(*dev, m_nubus_tag, m_nubus_slottag); +} + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type NUBUS = &device_creator; + +void nubus_device::static_set_cputag(device_t &device, const char *tag) +{ + nubus_device &nubus = downcast(device); + nubus.m_cputag = tag; +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// nubus_device - constructor +//------------------------------------------------- + +nubus_device::nubus_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, NUBUS, "NUBUS", tag, owner, clock, "nubus", __FILE__), + m_out_irq9_cb(*this), + m_out_irqa_cb(*this), + m_out_irqb_cb(*this), + m_out_irqc_cb(*this), + m_out_irqd_cb(*this), + m_out_irqe_cb(*this) +{ +} + +nubus_device::nubus_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + m_out_irq9_cb(*this), + m_out_irqa_cb(*this), + m_out_irqb_cb(*this), + m_out_irqc_cb(*this), + m_out_irqd_cb(*this), + m_out_irqe_cb(*this) +{ +} +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void nubus_device::device_start() +{ + m_maincpu = machine().device(m_cputag); + // resolve callbacks + m_out_irq9_cb.resolve_safe(); + m_out_irqa_cb.resolve_safe(); + m_out_irqb_cb.resolve_safe(); + m_out_irqc_cb.resolve_safe(); + m_out_irqd_cb.resolve_safe(); + m_out_irqe_cb.resolve_safe(); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void nubus_device::device_reset() +{ +} + +void nubus_device::add_nubus_card(device_nubus_card_interface *card) +{ + m_device_list.append(*card); +} + +void nubus_device::install_device(offs_t start, offs_t end, read8_delegate rhandler, write8_delegate whandler, UINT32 mask) +{ + m_maincpu = machine().device(m_cputag); + int buswidth = m_maincpu->space_config(AS_PROGRAM)->m_databus_width; + switch(buswidth) + { + case 32: + m_maincpu->space(AS_PROGRAM).install_readwrite_handler(start, end, rhandler, whandler, mask); + break; + case 64: + m_maincpu->space(AS_PROGRAM).install_readwrite_handler(start, end, rhandler, whandler, ((UINT64)mask<<32)|mask); + break; + default: + fatalerror("NUBUS: Bus width %d not supported\n", buswidth); + } +} + +void nubus_device::install_device(offs_t start, offs_t end, read16_delegate rhandler, write16_delegate whandler, UINT32 mask) +{ + m_maincpu = machine().device(m_cputag); + int buswidth = m_maincpu->space_config(AS_PROGRAM)->m_databus_width; + switch(buswidth) + { + case 32: + m_maincpu->space(AS_PROGRAM).install_readwrite_handler(start, end, rhandler, whandler, mask); + break; + case 64: + m_maincpu->space(AS_PROGRAM).install_readwrite_handler(start, end, rhandler, whandler, ((UINT64)mask<<32)|mask); + break; + default: + fatalerror("NUBUS: Bus width %d not supported\n", buswidth); + } +} + +void nubus_device::install_device(offs_t start, offs_t end, read32_delegate rhandler, write32_delegate whandler, UINT32 mask) +{ + m_maincpu = machine().device(m_cputag); + int buswidth = m_maincpu->space_config(AS_PROGRAM)->m_databus_width; + switch(buswidth) + { + case 32: + m_maincpu->space(AS_PROGRAM).install_readwrite_handler(start, end, rhandler, whandler, mask); + break; + case 64: + m_maincpu->space(AS_PROGRAM).install_readwrite_handler(start, end, rhandler, whandler, ((UINT64)mask<<32)|mask); + break; + default: + fatalerror("NUBUS: Bus width %d not supported\n", buswidth); + } +} + +void nubus_device::install_readonly_device(offs_t start, offs_t end, read32_delegate rhandler, UINT32 mask) +{ + m_maincpu = machine().device(m_cputag); + int buswidth = m_maincpu->space_config(AS_PROGRAM)->m_databus_width; + switch(buswidth) + { + case 32: + m_maincpu->space(AS_PROGRAM).install_read_handler(start, end, rhandler, mask); + break; + case 64: + m_maincpu->space(AS_PROGRAM).install_read_handler(start, end, rhandler, ((UINT64)mask<<32)|mask); + break; + default: + fatalerror("NUBUS: Bus width %d not supported\n", buswidth); + } +} + +void nubus_device::install_writeonly_device(offs_t start, offs_t end, write32_delegate whandler, UINT32 mask) +{ + m_maincpu = machine().device(m_cputag); + int buswidth = m_maincpu->space_config(AS_PROGRAM)->m_databus_width; + switch(buswidth) + { + case 32: + m_maincpu->space(AS_PROGRAM).install_write_handler(start, end, whandler, mask); + break; + case 64: + m_maincpu->space(AS_PROGRAM).install_write_handler(start, end, whandler, ((UINT64)mask<<32)|mask); + break; + default: + fatalerror("NUBUS: Bus width %d not supported\n", buswidth); + } +} + +void nubus_device::install_bank(offs_t start, offs_t end, offs_t mask, offs_t mirror, const char *tag, UINT8 *data) +{ +// printf("install_bank: %s @ %x->%x mask %x mirror %x\n", tag, start, end, mask, mirror); + m_maincpu = machine().device(m_cputag); + address_space &space = m_maincpu->space(AS_PROGRAM); + space.install_readwrite_bank(start, end, mask, mirror, tag ); + machine().root_device().membank(tag)->set_base(data); +} + +void nubus_device::set_irq_line(int slot, int state) +{ + switch (slot) + { + case 0x9: irq9_w(state); break; + case 0xa: irqa_w(state); break; + case 0xb: irqb_w(state); break; + case 0xc: irqc_w(state); break; + case 0xd: irqd_w(state); break; + case 0xe: irqe_w(state); break; + } +} + +// interrupt request from nubus card +WRITE_LINE_MEMBER( nubus_device::irq9_w ) { m_out_irq9_cb(state); } +WRITE_LINE_MEMBER( nubus_device::irqa_w ) { m_out_irqa_cb(state); } +WRITE_LINE_MEMBER( nubus_device::irqb_w ) { m_out_irqb_cb(state); } +WRITE_LINE_MEMBER( nubus_device::irqc_w ) { m_out_irqc_cb(state); } +WRITE_LINE_MEMBER( nubus_device::irqd_w ) { m_out_irqd_cb(state); } +WRITE_LINE_MEMBER( nubus_device::irqe_w ) { m_out_irqe_cb(state); } + +//************************************************************************** +// DEVICE CONFIG NUBUS CARD INTERFACE +//************************************************************************** + + +//************************************************************************** +// DEVICE NUBUS CARD INTERFACE +//************************************************************************** + +//------------------------------------------------- +// device_nubus_card_interface - constructor +//------------------------------------------------- + +device_nubus_card_interface::device_nubus_card_interface(const machine_config &mconfig, device_t &device) + : device_slot_card_interface(mconfig, device), + m_nubus(NULL), + m_nubus_tag(NULL) +{ +} + + +//------------------------------------------------- +// ~device_nubus_card_interface - destructor +//------------------------------------------------- + +device_nubus_card_interface::~device_nubus_card_interface() +{ +} + +void device_nubus_card_interface::static_set_nubus_tag(device_t &device, const char *tag, const char *slottag) +{ + device_nubus_card_interface &nubus_card = dynamic_cast(device); + nubus_card.m_nubus_tag = tag; + nubus_card.m_nubus_slottag = slottag; +} + +void device_nubus_card_interface::set_nubus_device() +{ + if (!strncmp(m_nubus_slottag, "pds030", 6)) + { + m_slot = 0x9; // '030 PDS slots phantom slot as NuBus slots $9, $A, and $B + } + else if (!strncmp(m_nubus_slottag, "lcpds", 6)) + { + m_slot = 0xe; // LC PDS slots phantom slot as NuBus slot $E + } + else + { + // extract the slot number from the last digit of the slot tag + int tlen = strlen(m_nubus_slottag); + + if (m_nubus_slottag[tlen-1] == '9') + { + m_slot = (m_nubus_slottag[tlen-1] - '9') + 9; + } + else + { + m_slot = (m_nubus_slottag[tlen-1] - 'a') + 0xa; + } + } + + if (m_slot < 9 || m_slot > 0xe) + { + fatalerror("Slot %x out of range for Apple NuBus\n", m_slot); + } + + m_nubus = dynamic_cast(device().machine().device(m_nubus_tag)); + m_nubus->add_nubus_card(this); +} + +void device_nubus_card_interface::install_bank(offs_t start, offs_t end, offs_t mask, offs_t mirror, const char *tag, UINT8 *data) +{ + char bank[256]; + + // append an underscore and the slot name to the bank so it's guaranteed unique + strcpy(bank, tag); + strcat(bank, "_"); + strcat(bank, m_nubus_slottag); + + m_nubus->install_bank(start, end, mask, mirror, bank, data); +} + +void device_nubus_card_interface::install_declaration_rom(device_t *dev, const char *romregion, bool mirror_all_mb, bool reverse_rom) +{ + bool inverted = false; + + UINT8 *rom = device().machine().root_device().memregion(dev->subtag(romregion).c_str())->base(); + UINT32 romlen = device().machine().root_device().memregion(dev->subtag(romregion).c_str())->bytes(); + +// printf("ROM length is %x, last bytes are %02x %02x\n", romlen, rom[romlen-2], rom[romlen-1]); + + if (reverse_rom) + { + UINT8 temp; + UINT32 endptr = romlen-1; + + for (UINT32 idx = 0; idx < romlen / 2; idx++) + { + temp = rom[idx]; + rom[idx] = rom[endptr]; + rom[endptr] = temp; + endptr--; + } + } + + UINT8 byteLanes = rom[romlen-1]; + // check if all bits are inverted + if (rom[romlen-2] == 0xff) + { + byteLanes ^= 0xff; + inverted = true; + } + + #if 0 + FILE *f; + f = fopen("romout.bin", "wb"); + fwrite(rom, romlen, 1, f); + fclose(f); + #endif + + switch (byteLanes) + { + case 0x0f: // easy case: all 4 lanes (still must scramble for 32-bit BE bus though) + m_declaration_rom.resize(romlen); + for (int i = 0; i < romlen; i++) + { + m_declaration_rom[BYTE4_XOR_BE(i)] = rom[i]; + } + break; + + case 0xe1: // lane 0 only + m_declaration_rom.resize(romlen*4); + memset(&m_declaration_rom[0], 0, romlen*4); + for (int i = 0; i < romlen; i++) + { + m_declaration_rom[BYTE4_XOR_BE(i*4)] = rom[i]; + } + romlen *= 4; + break; + + case 0xd2: // lane 1 only + m_declaration_rom.resize(romlen*4); + memset(&m_declaration_rom[0], 0, romlen*4); + for (int i = 0; i < romlen; i++) + { + m_declaration_rom[BYTE4_XOR_BE((i*4)+1)] = rom[i]; + } + romlen *= 4; + break; + + case 0xb4: // lane 2 only + m_declaration_rom.resize(romlen*4); + memset(&m_declaration_rom[0], 0, romlen*4); + for (int i = 0; i < romlen; i++) + { + m_declaration_rom[BYTE4_XOR_BE((i*4)+2)] = rom[i]; + } + romlen *= 4; + break; + + case 0x78: // lane 3 only + m_declaration_rom.resize(romlen*4); + memset(&m_declaration_rom[0], 0, romlen*4); + for (int i = 0; i < romlen; i++) + { + m_declaration_rom[BYTE4_XOR_BE((i*4)+3)] = rom[i]; + } + romlen *= 4; + break; + + case 0xc3: // lanes 0, 1 + m_declaration_rom.resize(romlen*2); + memset(&m_declaration_rom[0], 0, romlen*4); + for (int i = 0; i < romlen/2; i++) + { + m_declaration_rom[BYTE4_XOR_BE((i*4)+0)] = rom[(i*2)]; + m_declaration_rom[BYTE4_XOR_BE((i*4)+1)] = rom[(i*2)+1]; + } + romlen *= 2; + break; + + case 0xa5: // lanes 0, 2 + m_declaration_rom.resize(romlen*2); + memset(&m_declaration_rom[0], 0, romlen*4); + for (int i = 0; i < romlen/2; i++) + { + m_declaration_rom[BYTE4_XOR_BE((i*4)+0)] = rom[(i*2)]; + m_declaration_rom[BYTE4_XOR_BE((i*4)+2)] = rom[(i*2)+1]; + } + romlen *= 2; + break; + + case 0x3c: // lanes 2,3 + m_declaration_rom.resize(romlen*2); + memset(&m_declaration_rom[0], 0, romlen*4); + for (int i = 0; i < romlen/2; i++) + { + m_declaration_rom[BYTE4_XOR_BE((i*4)+2)] = rom[(i*2)]; + m_declaration_rom[BYTE4_XOR_BE((i*4)+3)] = rom[(i*2)+1]; + } + romlen *= 2; + break; + + default: + fatalerror("NuBus: unhandled byteLanes value %02x\n", byteLanes); + } + + // the slot manager can supposedly handle inverted ROMs by itself, but let's do it for it anyway + if (inverted) + { + for (int i = 0; i < romlen; i++) + { + m_declaration_rom[i] ^= 0xff; + } + } + + // now install the ROM + UINT32 addr = get_slotspace() + 0x01000000; + char bankname[128]; + strcpy(bankname, "rom_"); + strcat(bankname, m_nubus_slottag); + addr -= romlen; +// printf("Installing ROM at %x, length %x\n", addr, romlen); + if (mirror_all_mb) // mirror the declaration ROM across all 16 megs of the slot space + { + m_nubus->install_bank(addr, addr+romlen-1, 0, 0x00f00000, bankname, &m_declaration_rom[0]); + } + else + { + m_nubus->install_bank(addr, addr+romlen-1, 0, 0, bankname, &m_declaration_rom[0]); + } +} diff --git a/src/devices/bus/nubus/nubus.h b/src/devices/bus/nubus/nubus.h new file mode 100644 index 00000000000..72bee5f7b84 --- /dev/null +++ b/src/devices/bus/nubus/nubus.h @@ -0,0 +1,177 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/*************************************************************************** + + nubus.h - NuBus bus and card emulation + + by R. Belmont, based heavily on Miodrag Milanovic's ISA8/16 implementation + +***************************************************************************/ + +#pragma once + +#ifndef __NUBUS_H__ +#define __NUBUS_H__ + +#include "emu.h" + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_NUBUS_CPU(_cputag) \ + nubus_device::static_set_cputag(*device, _cputag); + +#define MCFG_NUBUS_OUT_IRQ9_CB(_devcb) \ + devcb = &nubus_device::set_out_irq9_callback(*device, DEVCB_##_devcb); + +#define MCFG_NUBUS_OUT_IRQA_CB(_devcb) \ + devcb = &nubus_device::set_out_irqa_callback(*device, DEVCB_##_devcb); + +#define MCFG_NUBUS_OUT_IRQB_CB(_devcb) \ + devcb = &nubus_device::set_out_irqb_callback(*device, DEVCB_##_devcb); + +#define MCFG_NUBUS_OUT_IRQC_CB(_devcb) \ + devcb = &nubus_device::set_out_irqc_callback(*device, DEVCB_##_devcb); + +#define MCFG_NUBUS_OUT_IRQD_CB(_devcb) \ + devcb = &nubus_device::set_out_irqd_callback(*device, DEVCB_##_devcb); + +#define MCFG_NUBUS_OUT_IRQE_CB(_devcb) \ + devcb = &nubus_device::set_out_irqe_callback(*device, DEVCB_##_devcb); + +#define MCFG_NUBUS_SLOT_ADD(_nbtag, _tag, _slot_intf, _def_slot) \ + MCFG_DEVICE_ADD(_tag, NUBUS_SLOT, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) \ + nubus_slot_device::static_set_nubus_slot(*device, _nbtag, _tag); +#define MCFG_NUBUS_SLOT_REMOVE(_tag) \ + MCFG_DEVICE_REMOVE(_tag) + +#define MCFG_NUBUS_ONBOARD_ADD(_nbtag, _tag, _dev_type, _def_inp) \ + MCFG_DEVICE_ADD(_tag, _dev_type, 0) \ + MCFG_DEVICE_INPUT_DEFAULTS(_def_inp) \ + device_nubus_card_interface::static_set_nubus_tag(*device, _nbtag, _tag); + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class nubus_device; + +class nubus_slot_device : public device_t, + public device_slot_interface +{ +public: + // construction/destruction + nubus_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + nubus_slot_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + // device-level overrides + virtual void device_start(); + + // inline configuration + static void static_set_nubus_slot(device_t &device, const char *tag, const char *slottag); +protected: + // configuration + const char *m_nubus_tag, *m_nubus_slottag; +}; + +// device type definition +extern const device_type NUBUS_SLOT; + + +class device_nubus_card_interface; +// ======================> nubus_device +class nubus_device : public device_t +{ +public: + // construction/destruction + nubus_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + nubus_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + ~nubus_device() { m_device_list.detach_all(); } + + // inline configuration + static void static_set_cputag(device_t &device, const char *tag); + template static devcb_base &set_out_irq9_callback(device_t &device, _Object object) { return downcast(device).m_out_irq9_cb.set_callback(object); } + template static devcb_base &set_out_irqa_callback(device_t &device, _Object object) { return downcast(device).m_out_irqa_cb.set_callback(object); } + template static devcb_base &set_out_irqb_callback(device_t &device, _Object object) { return downcast(device).m_out_irqb_cb.set_callback(object); } + template static devcb_base &set_out_irqc_callback(device_t &device, _Object object) { return downcast(device).m_out_irqc_cb.set_callback(object); } + template static devcb_base &set_out_irqd_callback(device_t &device, _Object object) { return downcast(device).m_out_irqd_cb.set_callback(object); } + template static devcb_base &set_out_irqe_callback(device_t &device, _Object object) { return downcast(device).m_out_irqe_cb.set_callback(object); } + + void add_nubus_card(device_nubus_card_interface *card); + void install_device(offs_t start, offs_t end, read8_delegate rhandler, write8_delegate whandler, UINT32 mask=0xffffffff); + void install_device(offs_t start, offs_t end, read16_delegate rhandler, write16_delegate whandler, UINT32 mask=0xffffffff); + void install_device(offs_t start, offs_t end, read32_delegate rhandler, write32_delegate whandler, UINT32 mask=0xffffffff); + void install_readonly_device(offs_t start, offs_t end, read32_delegate rhandler, UINT32 mask=0xffffffff); + void install_writeonly_device(offs_t start, offs_t end, write32_delegate whandler, UINT32 mask=0xffffffff); + void install_bank(offs_t start, offs_t end, offs_t mask, offs_t mirror, const char *tag, UINT8 *data); + void set_irq_line(int slot, int state); + + DECLARE_WRITE_LINE_MEMBER( irq9_w ); + DECLARE_WRITE_LINE_MEMBER( irqa_w ); + DECLARE_WRITE_LINE_MEMBER( irqb_w ); + DECLARE_WRITE_LINE_MEMBER( irqc_w ); + DECLARE_WRITE_LINE_MEMBER( irqd_w ); + DECLARE_WRITE_LINE_MEMBER( irqe_w ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // internal state + cpu_device *m_maincpu; + + devcb_write_line m_out_irq9_cb; + devcb_write_line m_out_irqa_cb; + devcb_write_line m_out_irqb_cb; + devcb_write_line m_out_irqc_cb; + devcb_write_line m_out_irqd_cb; + devcb_write_line m_out_irqe_cb; + + simple_list m_device_list; + const char *m_cputag; +}; + + +// device type definition +extern const device_type NUBUS; + +// ======================> device_nubus_card_interface + +// class representing interface-specific live nubus card +class device_nubus_card_interface : public device_slot_card_interface +{ + friend class nubus_device; +public: + // construction/destruction + device_nubus_card_interface(const machine_config &mconfig, device_t &device); + virtual ~device_nubus_card_interface(); + + device_nubus_card_interface *next() const { return m_next; } + + void set_nubus_device(); + + // helper functions for card devices + void install_declaration_rom(device_t *dev, const char *romregion, bool mirror_all_mb = false, bool reverse_rom = false); + void install_bank(offs_t start, offs_t end, offs_t mask, offs_t mirror, const char *tag, UINT8 *data); + + UINT32 get_slotspace() { return 0xf0000000 | (m_slot<<24); } + UINT32 get_super_slotspace() { return m_slot<<28; } + + void raise_slot_irq() { m_nubus->set_irq_line(m_slot, ASSERT_LINE); } + void lower_slot_irq() { m_nubus->set_irq_line(m_slot, CLEAR_LINE); } + + // inline configuration + static void static_set_nubus_tag(device_t &device, const char *tag, const char *slottag); +public: + nubus_device *m_nubus; + const char *m_nubus_tag, *m_nubus_slottag; + int m_slot; + device_nubus_card_interface *m_next; + dynamic_buffer m_declaration_rom; +}; + +#endif /* __NUBUS_H__ */ diff --git a/src/devices/bus/nubus/nubus_48gc.c b/src/devices/bus/nubus/nubus_48gc.c new file mode 100644 index 00000000000..213cf0a0753 --- /dev/null +++ b/src/devices/bus/nubus/nubus_48gc.c @@ -0,0 +1,369 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/*************************************************************************** + + Apple 4*8 Graphics Card (model 630-0400) emulation + Apple 8*24 Graphics Card emulation (cards have the same framebuffer chip + w/different ROMs and RAMDACs, apparently) + +***************************************************************************/ + +#include "emu.h" +#include "nubus_48gc.h" + +#define VRAM_SIZE (0x200000) // 2 megs, maxed out + +#define GC48_SCREEN_NAME "48gc_screen" +#define GC48_ROM_REGION "48gc_rom" + +MACHINE_CONFIG_FRAGMENT( macvideo_48gc ) + MCFG_SCREEN_ADD( GC48_SCREEN_NAME, RASTER) + MCFG_SCREEN_UPDATE_DEVICE(DEVICE_SELF, jmfb_device, screen_update) + MCFG_SCREEN_RAW_PARAMS(25175000, 800, 0, 640, 525, 0, 480) +// MCFG_SCREEN_SIZE(1152, 870) +// MCFG_SCREEN_VISIBLE_AREA(0, 1152-1, 0, 870-1) +// MCFG_SCREEN_REFRESH_RATE(75) +// MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(1260)) +MACHINE_CONFIG_END + +ROM_START( gc48 ) + ROM_REGION(0x8000, GC48_ROM_REGION, 0) + ROM_LOAD( "3410801.bin", 0x0000, 0x8000, CRC(e283da91) SHA1(4ae21d6d7bbaa6fc7aa301bee2b791ed33b1dcf9) ) +ROM_END + +ROM_START( gc824 ) + ROM_REGION(0x8000, GC48_ROM_REGION, 0) + ROM_LOAD( "3410868.bin", 0x000000, 0x008000, CRC(57f925fa) SHA1(4d3c0632711b7b31c8e0c5cfdd7ec1904f178336) ) +ROM_END + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type NUBUS_48GC = &device_creator; +const device_type NUBUS_824GC = &device_creator; + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor jmfb_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( macvideo_48gc ); +} + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *jmfb_device::device_rom_region() const +{ + return ROM_NAME( gc48 ); +} + +const rom_entry *nubus_824gc_device::device_rom_region() const +{ + return ROM_NAME( gc824 ); +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// jmfb_device - constructor +//------------------------------------------------- + +jmfb_device::jmfb_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_video_interface(mconfig, *this), + device_nubus_card_interface(mconfig, *this) +{ + m_assembled_tag = std::string(tag).append(":").append(GC48_SCREEN_NAME); + m_screen_tag = m_assembled_tag.c_str(); +} + +nubus_48gc_device::nubus_48gc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + jmfb_device(mconfig, NUBUS_48GC, "Apple 4*8 video card", tag, owner, clock, "nb_48gc", __FILE__) +{ + m_is824 = false; +} + +nubus_824gc_device::nubus_824gc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + jmfb_device(mconfig, NUBUS_824GC, "Apple 8*24 video card", tag, owner, clock, "nb_824gc", __FILE__) +{ + m_is824 = true; +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void jmfb_device::device_start() +{ + UINT32 slotspace; + + // set_nubus_device makes m_slot valid + set_nubus_device(); + install_declaration_rom(this, GC48_ROM_REGION); + + slotspace = get_slotspace(); + +// printf("[JMFB %p] slotspace = %x\n", this, slotspace); + + m_vram.resize(VRAM_SIZE); + install_bank(slotspace, slotspace+VRAM_SIZE-1, 0, 0, "bank_48gc", &m_vram[0]); + + m_nubus->install_device(slotspace+0x200000, slotspace+0x2003ff, read32_delegate(FUNC(jmfb_device::mac_48gc_r), this), write32_delegate(FUNC(jmfb_device::mac_48gc_w), this)); + + m_timer = timer_alloc(0, NULL); + m_screen = NULL; // can we look this up now? +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void jmfb_device::device_reset() +{ + m_toggle = 0; + m_clutoffs = 0; + m_count = 0; + m_vbl_disable = 1; + m_stride = 80; + m_base = 0; + m_xres = 640; + m_yres = 480; + m_mode = 0; + memset(&m_vram[0], 0, VRAM_SIZE); + memset(m_palette, 0, sizeof(m_palette)); +} + +/*************************************************************************** + + Apple 4*8 Graphics Card section + +***************************************************************************/ + +void jmfb_device::device_timer(emu_timer &timer, device_timer_id tid, int param, void *ptr) +{ + if (!m_vbl_disable) + { + raise_slot_irq(); + } + + m_timer->adjust(m_screen->time_until_pos(479, 0), 0); +} + +UINT32 jmfb_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + UINT32 *scanline, *base; + int x, y; + UINT8 *vram8 = &m_vram[0]; + UINT8 pixels; + + // first time? kick off the VBL timer + if (!m_screen) + { + m_screen = &screen; + m_timer->adjust(m_screen->time_until_pos(479, 0), 0); + } + + vram8 += 0xa00; + + switch (m_mode) + { + case 0: // 1bpp + for (y = 0; y < m_yres; y++) + { + scanline = &bitmap.pix32(y); + for (x = 0; x < m_xres/8; x++) + { + pixels = vram8[(y * m_stride) + (BYTE4_XOR_BE(x))]; + + *scanline++ = m_palette[(pixels>>7)&1]; + *scanline++ = m_palette[(pixels>>6)&1]; + *scanline++ = m_palette[(pixels>>5)&1]; + *scanline++ = m_palette[(pixels>>4)&1]; + *scanline++ = m_palette[(pixels>>3)&1]; + *scanline++ = m_palette[(pixels>>2)&1]; + *scanline++ = m_palette[(pixels>>1)&1]; + *scanline++ = m_palette[pixels&1]; + } + } + break; + + case 1: // 2bpp + for (y = 0; y < m_yres; y++) + { + scanline = &bitmap.pix32(y); + for (x = 0; x < m_xres/4; x++) + { + pixels = vram8[(y * m_stride) + (BYTE4_XOR_BE(x))]; + + *scanline++ = m_palette[(pixels>>6)&0x3]; + *scanline++ = m_palette[(pixels>>4)&0x3]; + *scanline++ = m_palette[(pixels>>2)&0x3]; + *scanline++ = m_palette[pixels&3]; + } + } + break; + + case 2: // 4 bpp + for (y = 0; y < m_yres; y++) + { + scanline = &bitmap.pix32(y); + + for (x = 0; x < m_xres/2; x++) + { + pixels = vram8[(y * m_stride) + (BYTE4_XOR_BE(x))]; + + *scanline++ = m_palette[(pixels>>4)&0xf]; + *scanline++ = m_palette[pixels&0xf]; + } + } + break; + + case 3: // 8 bpp + for (y = 0; y < m_yres; y++) + { + scanline = &bitmap.pix32(y); + + for (x = 0; x < m_xres; x++) + { + pixels = vram8[(y * m_stride) + (BYTE4_XOR_BE(x))]; + *scanline++ = m_palette[pixels]; + } + } + break; + + case 4: // 24 bpp + for (y = 0; y < m_yres; y++) + { + scanline = &bitmap.pix32(y); + base = (UINT32 *)&m_vram[y * m_stride]; + for (x = 0; x < m_xres; x++) + { + *scanline++ = *base++; + } + } + break; + } + + return 0; +} + +WRITE32_MEMBER( jmfb_device::mac_48gc_w ) +{ + COMBINE_DATA(&m_registers[offset&0xff]); + + switch (offset) + { + case 0x8/4: // base +// printf("%x to base\n", data); + m_base = (data*2)<<4; + break; + + case 0xc/4: // stride +// printf("%x to stride\n", data); + // this value is in DWORDs for 1-8 bpp and, uhh, strange for 24bpp + if (m_mode < 4) + { + m_stride = data*4; + } + else + { + m_stride = (data*32)/3; + } + break; + + case 0x200/4: // DAC control +// printf("%08x to DAC control\n", data); + if (m_is824) + { + m_clutoffs = data&0xff; + } + else + { + m_clutoffs = data>>24; + } + m_count = 0; + break; + + case 0x204/4: // DAC data + if (m_is824) + { + m_colors[m_count++] = data&0xff; + } + else + { + m_colors[m_count++] = data>>24; + } + + if (m_count == 3) + { +// printf("RAMDAC: color %d = %02x %02x %02x\n", m_clutoffs, m_colors[0], m_colors[1], m_colors[2]); + m_palette[m_clutoffs] = rgb_t(m_colors[0], m_colors[1], m_colors[2]); + m_clutoffs++; + m_count = 0; + } + break; + + case 0x208/4: // mode control + m_mode = (data>>3)&3; + if (m_mode == 3) // this can be 8 or 24 bpp + { + // check pixel format for 24bpp + if (m_is824) + { + if (data & 2) + { + m_mode = 4; // 24bpp + } + } + else + { + if (((data>>5)&3) == 0) + { + m_mode = 4; // 24bpp + } + } + } +// printf("%02x to mode (m_mode = %d)\n", data, m_mode); + break; + + case 0x13c/4: // bit 1 = VBL disable (1=no interrupts) + m_vbl_disable = (data & 2) ? 1 : 0; + break; + + case 0x148/4: // write 1 here to clear interrupt + if (data == 1) + { + lower_slot_irq(); + } + break; + + default: + break; + } +} + +READ32_MEMBER( jmfb_device::mac_48gc_r ) +{ +// printf("48gc_r: @ %x, mask %08x [PC=%x]\n", offset, mem_mask, m_maincpu->safe_pc()); + + switch (offset) + { + case 0: + return 0x0c00; // sense 13" RGB for now +// return 0x0000; // sense "RGB Kong" monitor + + case 0x1c0/4: + m_toggle ^= 0xffffffff; + return m_toggle; + } + + return 0; +} diff --git a/src/devices/bus/nubus/nubus_48gc.h b/src/devices/bus/nubus/nubus_48gc.h new file mode 100644 index 00000000000..85384ace70f --- /dev/null +++ b/src/devices/bus/nubus/nubus_48gc.h @@ -0,0 +1,70 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +#pragma once + +#ifndef __NUBUS_48GC_H__ +#define __NUBUS_48GC_H__ + +#include "emu.h" +#include "nubus.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> jmfb_device + +class jmfb_device : + public device_t, + public device_video_interface, + public device_nubus_card_interface +{ +public: + // construction/destruction + jmfb_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual const rom_entry *device_rom_region() const; + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + UINT32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); + + screen_device *m_screen; + emu_timer *m_timer; +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + DECLARE_READ32_MEMBER(mac_48gc_r); + DECLARE_WRITE32_MEMBER(mac_48gc_w); + +public: + dynamic_buffer m_vram; + UINT32 m_mode, m_vbl_disable, m_toggle, m_stride, m_base; + UINT32 m_palette[256], m_colors[3], m_count, m_clutoffs; + UINT32 m_registers[0x100]; + int m_xres, m_yres; + bool m_is824; + std::string m_assembled_tag; +}; + +class nubus_48gc_device : public jmfb_device +{ +public: + nubus_48gc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class nubus_824gc_device : public jmfb_device +{ +public: + nubus_824gc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual const rom_entry *device_rom_region() const; +}; + +// device type definition +extern const device_type NUBUS_48GC; +extern const device_type NUBUS_824GC; + +#endif /* __NUBUS_48GC_H__ */ diff --git a/src/devices/bus/nubus/nubus_asntmc3b.c b/src/devices/bus/nubus/nubus_asntmc3b.c new file mode 100644 index 00000000000..1d911055e11 --- /dev/null +++ b/src/devices/bus/nubus/nubus_asntmc3b.c @@ -0,0 +1,210 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/*************************************************************************** + + Asante MC3NB NuBus Ethernet card (DP83902) + Apple NuBus Ethernet Card (DP8390) + + Based on National Semiconductor DP8390 family chips + + FssD0000 - 64k RAM buffer (used as DP83902 DMA target) + FssE0000 - DP83902 registers + +***************************************************************************/ + +#include "emu.h" +#include "nubus_asntmc3b.h" + +#define MAC8390_ROM_REGION "asntm3b_rom" +#define MAC8390_839X "dp83902" + + +MACHINE_CONFIG_FRAGMENT( asntm3b ) + MCFG_DEVICE_ADD(MAC8390_839X, DP8390D, 0) + MCFG_DP8390D_IRQ_CB(WRITELINE(nubus_mac8390_device, dp_irq_w)) + MCFG_DP8390D_MEM_READ_CB(READ8(nubus_mac8390_device, dp_mem_read)) + MCFG_DP8390D_MEM_WRITE_CB(WRITE8(nubus_mac8390_device, dp_mem_write)) +MACHINE_CONFIG_END + +ROM_START( asntm3nb ) + ROM_REGION(0x4000, MAC8390_ROM_REGION, 0) + ROM_LOAD( "asante_mc3b.bin", 0x000000, 0x004000, CRC(4f86d451) SHA1(d0a41df667e6b51fbc63f9251d593f4fc49104ba) ) +ROM_END + +ROM_START( appleenet ) + ROM_REGION(0x4000, MAC8390_ROM_REGION, 0) + ROM_LOAD( "aenet1", 0x000000, 0x004000, CRC(e3ae8c26) SHA1(01ddc15ee84b17128203cb812f29bac6b20fd642) ) +ROM_END + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type NUBUS_ASNTMC3NB = &device_creator; +const device_type NUBUS_APPLEENET = &device_creator; + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor nubus_mac8390_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( asntm3b ); +} + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *nubus_mac8390_device::device_rom_region() const +{ + return ROM_NAME( asntm3nb ); +} + +const rom_entry *nubus_appleenet_device::device_rom_region() const +{ + return ROM_NAME( appleenet ); +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// nubus_mac8390_device - constructor +//------------------------------------------------- + +nubus_mac8390_device::nubus_mac8390_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, NUBUS_ASNTMC3NB, name, tag, owner, clock, shortname, source), + device_nubus_card_interface(mconfig, *this), + m_dp83902(*this, MAC8390_839X) +{ +} + +nubus_asntmc3nb_device::nubus_asntmc3nb_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + nubus_mac8390_device(mconfig, NUBUS_ASNTMC3NB, "Asante MC3NB Ethernet card", tag, owner, clock, "nb_amc3b", __FILE__) +{ +} + +nubus_appleenet_device::nubus_appleenet_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + nubus_mac8390_device(mconfig, NUBUS_APPLEENET, "Apple NuBus Ethernet card", tag, owner, clock, "nb_aenet", __FILE__) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void nubus_mac8390_device::device_start() +{ + UINT32 slotspace; + char mac[7]; + UINT32 num = rand(); + memset(m_prom, 0x57, 16); + sprintf(mac+2, "\x1b%c%c%c", (num >> 16) & 0xff, (num >> 8) & 0xff, num & 0xff); + mac[0] = mac[1] = 0; // avoid gcc warning + memcpy(m_prom, mac, 6); + m_dp83902->set_mac(mac); + // set_nubus_device makes m_slot valid + set_nubus_device(); + install_declaration_rom(this, MAC8390_ROM_REGION, true); + + slotspace = get_slotspace(); + +// printf("[ASNTMC3NB %p] slotspace = %x\n", this, slotspace); + + // TODO: move 24-bit mirroring down into nubus.c + UINT32 ofs_24bit = m_slot<<20; + m_nubus->install_device(slotspace+0xd0000, slotspace+0xdffff, read8_delegate(FUNC(nubus_mac8390_device::asntm3b_ram_r), this), write8_delegate(FUNC(nubus_mac8390_device::asntm3b_ram_w), this)); + m_nubus->install_device(slotspace+0xe0000, slotspace+0xe003f, read32_delegate(FUNC(nubus_mac8390_device::en_r), this), write32_delegate(FUNC(nubus_mac8390_device::en_w), this)); + m_nubus->install_device(slotspace+0xd0000+ofs_24bit, slotspace+0xdffff+ofs_24bit, read8_delegate(FUNC(nubus_mac8390_device::asntm3b_ram_r), this), write8_delegate(FUNC(nubus_mac8390_device::asntm3b_ram_w), this)); + m_nubus->install_device(slotspace+0xe0000+ofs_24bit, slotspace+0xe003f+ofs_24bit, read32_delegate(FUNC(nubus_mac8390_device::en_r), this), write32_delegate(FUNC(nubus_mac8390_device::en_w), this)); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void nubus_mac8390_device::device_reset() +{ + m_dp83902->dp8390_reset(0); + m_dp83902->dp8390_cs(0); + memcpy(m_prom, m_dp83902->get_mac(), 6); +} + +WRITE8_MEMBER( nubus_mac8390_device::asntm3b_ram_w ) +{ +// printf("MC3NB: CPU wrote %02x to RAM @ %x\n", data, offset); + m_ram[offset] = data; +} + +READ8_MEMBER( nubus_mac8390_device::asntm3b_ram_r ) +{ +// printf("MC3NB: CPU read %02x @ RAM %x\n", m_ram[offset], offset); + return m_ram[offset]; +} + +WRITE32_MEMBER( nubus_mac8390_device::en_w ) +{ + if (mem_mask == 0xff000000) + { +// printf("%02x to 8390 @ %x\n", data>>24, 0xf-offset); + m_dp83902->dp8390_w(space, 0xf-offset, data>>24); + } + else if (mem_mask == 0xffff0000) + { + m_dp83902->dp8390_cs(1); + m_dp83902->dp8390_w(space, 0xf-offset, data>>16); + m_dp83902->dp8390_cs(0); + } + else + { + fatalerror("asntmc3nb: write %08x to DP83902 @ %x with unhandled mask %08x (PC=%x)\n", data, offset, mem_mask, space.device().safe_pc()); + } +} + +READ32_MEMBER( nubus_mac8390_device::en_r ) +{ + if (mem_mask == 0xff000000) + { + return (m_dp83902->dp8390_r(space, 0xf-offset)<<24); + } + else if (mem_mask == 0xffff0000) + { + m_dp83902->dp8390_cs(1); + return (m_dp83902->dp8390_r(space, 0xf-offset)<<16); + m_dp83902->dp8390_cs(0); + } + else + { + fatalerror("asntmc3nb: read DP83902 @ %x with unhandled mask %08x (PC=%x)\n", offset, mem_mask, space.device().safe_pc()); + } + + return 0; +} + +WRITE_LINE_MEMBER( nubus_mac8390_device::dp_irq_w ) +{ + if (state) + { + raise_slot_irq(); + } + else + { + lower_slot_irq(); + } +} + +READ8_MEMBER( nubus_mac8390_device::dp_mem_read ) +{ +// printf("MC3NB: 8390 read RAM @ %x = %02x\n", offset, m_ram[offset]); + return m_ram[offset]; +} + +WRITE8_MEMBER( nubus_mac8390_device::dp_mem_write ) +{ +// printf("MC3NB: 8390 wrote %02x to RAM @ %x\n", data, offset); + m_ram[offset] = data; +} diff --git a/src/devices/bus/nubus/nubus_asntmc3b.h b/src/devices/bus/nubus/nubus_asntmc3b.h new file mode 100644 index 00000000000..fd5851a61df --- /dev/null +++ b/src/devices/bus/nubus/nubus_asntmc3b.h @@ -0,0 +1,68 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +#pragma once + +#ifndef __NUBUS_ASNTMC3B_H__ +#define __NUBUS_ASNTMC3B_H__ + +#include "emu.h" +#include "nubus.h" +#include "machine/dp8390.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> nubus_mac8390_device + +class nubus_mac8390_device : + public device_t, + public device_nubus_card_interface +{ +public: + // construction/destruction + nubus_mac8390_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual const rom_entry *device_rom_region() const; + + void dp_irq_w(int state); + DECLARE_READ8_MEMBER(dp_mem_read); + DECLARE_WRITE8_MEMBER(dp_mem_write); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + DECLARE_READ8_MEMBER(asntm3b_ram_r); + DECLARE_WRITE8_MEMBER(asntm3b_ram_w); + DECLARE_READ32_MEMBER(en_r); + DECLARE_WRITE32_MEMBER(en_w); + + required_device m_dp83902; + +private: + UINT8 m_ram[0x20000]; + UINT8 m_prom[16]; +}; + +class nubus_asntmc3nb_device : public nubus_mac8390_device +{ +public: + nubus_asntmc3nb_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class nubus_appleenet_device : public nubus_mac8390_device +{ +public: + nubus_appleenet_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual const rom_entry *device_rom_region() const; +}; + +// device type definition +extern const device_type NUBUS_ASNTMC3NB; +extern const device_type NUBUS_APPLEENET; + +#endif /* __NUBUS_ASNTMC3B_H__ */ diff --git a/src/devices/bus/nubus/nubus_cb264.c b/src/devices/bus/nubus/nubus_cb264.c new file mode 100644 index 00000000000..2e4febed481 --- /dev/null +++ b/src/devices/bus/nubus/nubus_cb264.c @@ -0,0 +1,300 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/*************************************************************************** + + RasterOps ColorBoard 264 NuBus video card emulation + + fixed resolution 640x480 NuBus video card, 1/4/8/16/24 bit color + 1.5? MB of VRAM (tests up to 0x1fffff), Bt473 RAMDAC, and two custom gate arrays. + + 0xfsff6004 is color depth: 0 for 1bpp, 1 for 2bpp, 2 for 4bpp, 3 for 8bpp, 4 for 24bpp + 0xfsff6014 is VBL ack: write 1 to ack + 0xfsff603c is VBL disable: write 1 to disable, 0 to enable + +***************************************************************************/ + +#include "emu.h" +#include "nubus_cb264.h" + +#define CB264_SCREEN_NAME "cb264_screen" +#define CB264_ROM_REGION "cb264_rom" + +#define VRAM_SIZE (0x200000) // 2 megs, maxed out + +MACHINE_CONFIG_FRAGMENT( cb264 ) + MCFG_SCREEN_ADD( CB264_SCREEN_NAME, RASTER) + MCFG_SCREEN_UPDATE_DEVICE(DEVICE_SELF, nubus_cb264_device, screen_update) + MCFG_SCREEN_RAW_PARAMS(25175000, 800, 0, 640, 525, 0, 480) + MCFG_SCREEN_SIZE(1024,768) + MCFG_SCREEN_VISIBLE_AREA(0, 640-1, 0, 480-1) +MACHINE_CONFIG_END + +ROM_START( cb264 ) + ROM_REGION(0x4000, CB264_ROM_REGION, 0) + ROM_LOAD16_BYTE( "264-1915.bin", 0x000000, 0x002000, CRC(26c19ee5) SHA1(2b2853d04cc6b0258e85eccd23ebfd4f4f63a084) ) + ROM_LOAD16_BYTE( "264-1914.bin", 0x000001, 0x002000, CRC(d5fbd5ad) SHA1(98d35ed3fb0bca4a9bee1cdb2af0d3f22b379386) ) +ROM_END + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type NUBUS_CB264 = &device_creator; + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor nubus_cb264_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( cb264 ); +} + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *nubus_cb264_device::device_rom_region() const +{ + return ROM_NAME( cb264 ); +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// nubus_cb264_device - constructor +//------------------------------------------------- + +nubus_cb264_device::nubus_cb264_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, NUBUS_CB264, "RasterOps ColorBoard 264 video card", tag, owner, clock, "nb_cb264", __FILE__), + device_nubus_card_interface(mconfig, *this) +{ +} + +nubus_cb264_device::nubus_cb264_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_nubus_card_interface(mconfig, *this) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void nubus_cb264_device::device_start() +{ + UINT32 slotspace; + + // set_nubus_device makes m_slot valid + set_nubus_device(); + install_declaration_rom(this, CB264_ROM_REGION); + + slotspace = get_slotspace(); + +// printf("[cb264 %p] slotspace = %x\n", this, slotspace); + + m_vram.resize(VRAM_SIZE); + install_bank(slotspace, slotspace+VRAM_SIZE-1, 0, 0, "bank_cb264", &m_vram[0]); + + m_nubus->install_device(slotspace+0xff6000, slotspace+0xff60ff, read32_delegate(FUNC(nubus_cb264_device::cb264_r), this), write32_delegate(FUNC(nubus_cb264_device::cb264_w), this)); + m_nubus->install_device(slotspace+0xff7000, slotspace+0xff70ff, read32_delegate(FUNC(nubus_cb264_device::cb264_ramdac_r), this), write32_delegate(FUNC(nubus_cb264_device::cb264_ramdac_w), this)); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void nubus_cb264_device::device_reset() +{ + m_cb264_toggle = 0; + m_count = 0; + m_clutoffs = 0; + m_cb264_vbl_disable = 1; + m_cb264_mode = 0; + memset(&m_vram[0], 0, VRAM_SIZE); + memset(m_palette, 0, sizeof(m_palette)); +} + +/*************************************************************************** + + ColorBoard 264 section + +***************************************************************************/ + +UINT32 nubus_cb264_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + UINT32 *scanline, *base; + int x, y; + UINT8 pixels; + + if (!m_cb264_vbl_disable) + { + raise_slot_irq(); + } + + switch (m_cb264_mode) + { + case 0: // 1 bpp + for (y = 0; y < 480; y++) + { + scanline = &bitmap.pix32(y); + for (x = 0; x < 640/8; x++) + { + pixels = m_vram[(y * 1024) + (BYTE4_XOR_BE(x))]; + + *scanline++ = m_palette[pixels&0x80]; + *scanline++ = m_palette[(pixels<<1)&0x80]; + *scanline++ = m_palette[(pixels<<2)&0x80]; + *scanline++ = m_palette[(pixels<<3)&0x80]; + *scanline++ = m_palette[(pixels<<4)&0x80]; + *scanline++ = m_palette[(pixels<<5)&0x80]; + *scanline++ = m_palette[(pixels<<6)&0x80]; + *scanline++ = m_palette[(pixels<<7)&0x80]; + } + } + break; + + case 1: // 2 bpp (3f/7f/bf/ff) + for (y = 0; y < 480; y++) + { + scanline = &bitmap.pix32(y); + for (x = 0; x < 640/4; x++) + { + pixels = m_vram[(y * 1024) + (BYTE4_XOR_BE(x))]; + + *scanline++ = m_palette[pixels&0xc0]; + *scanline++ = m_palette[(pixels<<2)&0xc0]; + *scanline++ = m_palette[(pixels<<4)&0xc0]; + *scanline++ = m_palette[(pixels<<6)&0xc0]; + } + } + break; + + case 2: // 4 bpp + for (y = 0; y < 480; y++) + { + scanline = &bitmap.pix32(y); + + for (x = 0; x < 640/2; x++) + { + pixels = m_vram[(y * 1024) + (BYTE4_XOR_BE(x))]; + + *scanline++ = m_palette[pixels&0xf0]; + *scanline++ = m_palette[(pixels<<4)&0xf0]; + } + } + break; + + case 3: // 8 bpp + for (y = 0; y < 480; y++) + { + scanline = &bitmap.pix32(y); + + for (x = 0; x < 640; x++) + { + pixels = m_vram[(y * 1024) + (BYTE4_XOR_BE(x))]; + *scanline++ = m_palette[pixels]; + } + } + break; + + case 4: // 24 bpp + case 7: // ??? + { + UINT32 *vram32 = (UINT32 *)&m_vram[0]; + + for (y = 0; y < 480; y++) + { + scanline = &bitmap.pix32(y); + base = &vram32[y * 1024]; + for (x = 0; x < 640; x++) + { + *scanline++ = *base++; + } + } + } + break; + + default: + fatalerror("cb264: unknown video mode %d\n", m_cb264_mode); + } + + return 0; +} + +WRITE32_MEMBER( nubus_cb264_device::cb264_w ) +{ + switch (offset) + { + case 0x4/4: // 0 = 1 bpp, 1 = 2bpp, 2 = 4bpp, 3 = 8bpp, 4 = 24bpp + m_cb264_mode = data; + break; + + case 0x14/4: // VBL ack + lower_slot_irq(); + break; + + case 0x3c/4: // VBL disable + m_cb264_vbl_disable = data; + break; + + default: +// printf("cb264_w: %x to reg %x (mask %x PC %x)\n", data, offset*4, mem_mask, space.device().safe_pc()); + break; + } +} + +READ32_MEMBER( nubus_cb264_device::cb264_r ) +{ + switch (offset) + { + case 0x0c/4: + case 0x28/4: + break; + + case 0x34/4: + m_cb264_toggle ^= 1; + return m_cb264_toggle; // bit 0 is vblank? + + default: + logerror("cb264_r: reg %x (mask %x PC %x)\n", offset*4, mem_mask, space.device().safe_pc()); + break; + } + + return 0; +} + +WRITE32_MEMBER( nubus_cb264_device::cb264_ramdac_w ) +{ + switch (offset) + { + case 0: + m_clutoffs = data>>24; + m_count = 0; + break; + + case 1: + m_colors[m_count++] = data>>24; + + if (m_count == 3) + { + m_palette[m_clutoffs] = rgb_t(m_colors[0], m_colors[1], m_colors[2]); + m_clutoffs++; + m_count = 0; + } + break; + + default: +// printf("%x to unknown RAMDAC register @ %x\n", data, offset); + break; + } +} + +READ32_MEMBER( nubus_cb264_device::cb264_ramdac_r ) +{ + return 0; +} diff --git a/src/devices/bus/nubus/nubus_cb264.h b/src/devices/bus/nubus/nubus_cb264.h new file mode 100644 index 00000000000..633bf0f4962 --- /dev/null +++ b/src/devices/bus/nubus/nubus_cb264.h @@ -0,0 +1,51 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +#pragma once + +#ifndef __NUBUS_CB264_H__ +#define __NUBUS_CB264_H__ + +#include "emu.h" +#include "nubus.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> nubus_cb264_device + +class nubus_cb264_device : + public device_t, + public device_nubus_card_interface +{ +public: + // construction/destruction + nubus_cb264_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + nubus_cb264_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual const rom_entry *device_rom_region() const; + + UINT32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + DECLARE_READ32_MEMBER(cb264_r); + DECLARE_WRITE32_MEMBER(cb264_w); + DECLARE_READ32_MEMBER(cb264_ramdac_r); + DECLARE_WRITE32_MEMBER(cb264_ramdac_w); + +public: + dynamic_buffer m_vram; + UINT32 m_cb264_mode, m_cb264_vbl_disable, m_cb264_toggle; + UINT32 m_palette[256], m_colors[3], m_count, m_clutoffs; +}; + + +// device type definition +extern const device_type NUBUS_CB264; + +#endif /* __NUBUS_CB264_H__ */ diff --git a/src/devices/bus/nubus/nubus_image.c b/src/devices/bus/nubus/nubus_image.c new file mode 100644 index 00000000000..6b929c98270 --- /dev/null +++ b/src/devices/bus/nubus/nubus_image.c @@ -0,0 +1,388 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/*************************************************************************** + + nubus_image.c - synthetic NuBus card to allow reading/writing "raw" + HFS images, including floppy images (DD and HD) and vMac/Basilisk HDD + volumes up to 256 MB in size. + +***************************************************************************/ + +#include "emu.h" +#include "nubus_image.h" +#include "osdcore.h" + +#define IMAGE_ROM_REGION "image_rom" +#define IMAGE_DISK0_TAG "nb_disk" + +#define MESSIMG_DISK_SECTOR_SIZE (512) + +// on big-endian, these are NOPs. (TODO: hey, where did WORDS_BIGENDIAN go since the GENie transition?!) +#if defined(__ppc__) || defined (__PPC__) || defined(__ppc64__) || defined(__PPC64__) +static UINT32 ni_htonl(UINT32 x) { return x; } +static UINT32 ni_ntohl(UINT32 x) { return x; } +#else +static UINT32 ni_htonl(UINT32 x) { return FLIPENDIAN_INT32(x); } +static UINT32 ni_ntohl(UINT32 x) { return FLIPENDIAN_INT32(x); } +#endif + + +// messimg_disk_image_device + +class messimg_disk_image_device : public device_t, + public device_image_interface +{ +public: + // construction/destruction + messimg_disk_image_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // image-level overrides + virtual iodevice_t image_type() const { return IO_QUICKLOAD; } + + virtual bool is_readable() const { return 1; } + virtual bool is_writeable() const { return 1; } + virtual bool is_creatable() const { return 0; } + virtual bool must_be_loaded() const { return 0; } + virtual bool is_reset_on_load() const { return 0; } + virtual const char *image_interface() const { return NULL; } + virtual const char *file_extensions() const { return "img"; } + virtual const option_guide *create_option_guide() const { return NULL; } + + virtual bool call_load(); + virtual void call_unload(); + + protected: + // device-level overrides + virtual void device_config_complete(); + virtual void device_start(); + virtual void device_reset(); +public: + UINT32 m_size; + UINT8 *m_data; + bool m_ejected; +}; + + +// device type definition +extern const device_type MESSIMG_DISK; + +const device_type MESSIMG_DISK = &device_creator; + +messimg_disk_image_device::messimg_disk_image_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, MESSIMG_DISK, "Mac image", tag, owner, clock, "messimg_disk_image", __FILE__), + device_image_interface(mconfig, *this) +{ +} + +void messimg_disk_image_device::device_config_complete() +{ + update_names(MESSIMG_DISK, "disk", "disk"); +} + + +/*------------------------------------------------- + device start callback +-------------------------------------------------*/ + +void messimg_disk_image_device::device_start() +{ + m_data = (UINT8 *)NULL; + + if (exists() && fseek(0, SEEK_END) == 0) + { + m_size = (UINT32)ftell(); + } +} + +bool messimg_disk_image_device::call_load() +{ + fseek(0, SEEK_END); + m_size = (UINT32)ftell(); + if (m_size > (256*1024*1024)) + { + printf("Mac image too large: must be 256MB or less!\n"); + m_size = 0; + return IMAGE_INIT_FAIL; + } + + m_data = (UINT8 *)auto_alloc_array_clear(machine(), UINT32, m_size/sizeof(UINT32)); + fseek(0, SEEK_SET); + fread(m_data, m_size); + m_ejected = false; + + return IMAGE_INIT_PASS; +} + +void messimg_disk_image_device::call_unload() +{ + // TODO: track dirty sectors and only write those + fseek(0, SEEK_SET); + fwrite(m_data, m_size); + m_size = 0; + //free(m_data); +} + +/*------------------------------------------------- + device reset callback +-------------------------------------------------*/ + +void messimg_disk_image_device::device_reset() +{ +} + +MACHINE_CONFIG_FRAGMENT( image ) + MCFG_DEVICE_ADD(IMAGE_DISK0_TAG, MESSIMG_DISK, 0) +MACHINE_CONFIG_END + +ROM_START( image ) + ROM_REGION(0x2000, IMAGE_ROM_REGION, 0) + ROM_LOAD( "nb_fake.bin", 0x000000, 0x002000, CRC(9264bac5) SHA1(540c2ce3c90382b2da6e1e21182cdf8fc3f0c930) ) +ROM_END + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type NUBUS_IMAGE = &device_creator; + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor nubus_image_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( image ); +} + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *nubus_image_device::device_rom_region() const +{ + return ROM_NAME( image ); +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// nubus_image_device - constructor +//------------------------------------------------- + +nubus_image_device::nubus_image_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, NUBUS_IMAGE, "Disk Image Pseudo-Card", tag, owner, clock, "nb_image", __FILE__), + device_nubus_card_interface(mconfig, *this) +{ +} + +nubus_image_device::nubus_image_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_nubus_card_interface(mconfig, *this) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void nubus_image_device::device_start() +{ + UINT32 slotspace; + UINT32 superslotspace; + + // set_nubus_device makes m_slot valid + set_nubus_device(); + install_declaration_rom(this, IMAGE_ROM_REGION); + + slotspace = get_slotspace(); + superslotspace = get_super_slotspace(); + +// printf("[image %p] slotspace = %x, super = %x\n", this, slotspace, superslotspace); + + m_nubus->install_device(slotspace, slotspace+3, read32_delegate(FUNC(nubus_image_device::image_r), this), write32_delegate(FUNC(nubus_image_device::image_w), this)); + m_nubus->install_device(slotspace+4, slotspace+7, read32_delegate(FUNC(nubus_image_device::image_status_r), this), write32_delegate(FUNC(nubus_image_device::image_status_w), this)); + m_nubus->install_device(slotspace+8, slotspace+11, read32_delegate(FUNC(nubus_image_device::file_cmd_r), this), write32_delegate(FUNC(nubus_image_device::file_cmd_w), this)); + m_nubus->install_device(slotspace+12, slotspace+15, read32_delegate(FUNC(nubus_image_device::file_data_r), this), write32_delegate(FUNC(nubus_image_device::file_data_w), this)); + m_nubus->install_device(slotspace+16, slotspace+19, read32_delegate(FUNC(nubus_image_device::file_len_r), this), write32_delegate(FUNC(nubus_image_device::file_len_w), this)); + m_nubus->install_device(slotspace+20, slotspace+147, read32_delegate(FUNC(nubus_image_device::file_name_r), this), write32_delegate(FUNC(nubus_image_device::file_name_w), this)); + m_nubus->install_device(superslotspace, superslotspace+((256*1024*1024)-1), read32_delegate(FUNC(nubus_image_device::image_super_r), this), write32_delegate(FUNC(nubus_image_device::image_super_w), this)); + + m_image = subdevice(IMAGE_DISK0_TAG); + + filectx.curdir[0] = '.'; + filectx.curdir[1] = '\0'; + filectx.dirp = NULL; + filectx.fd = NULL; +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void nubus_image_device::device_reset() +{ +} + +WRITE32_MEMBER( nubus_image_device::image_status_w ) +{ + m_image->m_ejected = true; +} + +READ32_MEMBER( nubus_image_device::image_status_r ) +{ + if(m_image->m_ejected) { + return 0; + } + + if(m_image->m_size) { + return 1; + } + return 0; +} + +WRITE32_MEMBER( nubus_image_device::image_w ) +{ +} + +READ32_MEMBER( nubus_image_device::image_r ) +{ + return m_image->m_size; +} + +WRITE32_MEMBER( nubus_image_device::image_super_w ) +{ + UINT32 *image = (UINT32*)m_image->m_data; + data = ((data & 0xff) << 24) | ((data & 0xff00) << 8) | ((data & 0xff0000) >> 8) | ((data & 0xff000000) >> 24); + mem_mask = ((mem_mask & 0xff) << 24) | ((mem_mask & 0xff00) << 8) | ((mem_mask & 0xff0000) >> 8) | ((mem_mask & 0xff000000) >> 24); + + COMBINE_DATA(&image[offset]); +} + +READ32_MEMBER( nubus_image_device::image_super_r ) +{ + UINT32 *image = (UINT32*)m_image->m_data; + UINT32 data = image[offset]; + return ((data & 0xff) << 24) | ((data & 0xff00) << 8) | ((data & 0xff0000) >> 8) | ((data & 0xff000000) >> 24); +} + +WRITE32_MEMBER( nubus_image_device::file_cmd_w ) +{ + const osd_directory_entry *dp = NULL; + char fullpath[1024]; + UINT64 filesize; + +// data = ((data & 0xff) << 24) | ((data & 0xff00) << 8) | ((data & 0xff0000) >> 8) | ((data & 0xff000000) >> 24); + filectx.curcmd = data; + switch(data) { + case kFileCmdGetDir: + strcpy((char*)filectx.filename, (char*)filectx.curdir); + break; + case kFileCmdSetDir: + if ((filectx.filename[0] == '/') || (filectx.filename[0] == '$')) { + strcpy((char*)filectx.curdir, (char*)filectx.filename); + } else { + strcat((char*)filectx.curdir, "/"); + strcat((char*)filectx.curdir, (char*)filectx.filename); + } + break; + case kFileCmdGetFirstListing: + if(filectx.dirp) osd_closedir(filectx.dirp); + filectx.dirp = osd_opendir((const char *)filectx.curdir); + case kFileCmdGetNextListing: + if (filectx.dirp) { + dp = osd_readdir(filectx.dirp); + if(dp) { + strncpy((char*)filectx.filename, dp->name, sizeof(filectx.filename)); + } else { + memset(filectx.filename, 0, sizeof(filectx.filename)); + } + } + else { + memset(filectx.filename, 0, sizeof(filectx.filename)); + } + break; + case kFileCmdGetFile: + memset(fullpath, 0, sizeof(fullpath)); + strcpy(fullpath, (const char *)filectx.curdir); + strcat(fullpath, "/"); + strcat(fullpath, (const char*)filectx.filename); + if(osd_open((const char*)fullpath, OPEN_FLAG_READ, &filectx.fd, &filectx.filelen) != FILERR_NONE) printf("Error opening %s\n", fullpath); + filectx.bytecount = 0; + break; + case kFileCmdPutFile: + memset(fullpath, 0, sizeof(fullpath)); + strcpy(fullpath, (const char *)filectx.curdir); + strcat(fullpath, "/"); + strcat(fullpath, (const char*)filectx.filename); + if(osd_open((const char*)fullpath, OPEN_FLAG_WRITE|OPEN_FLAG_CREATE, &filectx.fd, &filesize) != FILERR_NONE) printf("Error opening %s\n", fullpath); + filectx.bytecount = 0; + break; + } +} + +READ32_MEMBER( nubus_image_device::file_cmd_r ) +{ + return 0; +} + +WRITE32_MEMBER( nubus_image_device::file_data_w ) +{ + UINT32 count = 4; + UINT32 actualcount = 0; + + data = ((data & 0xff) << 24) | ((data & 0xff00) << 8) | ((data & 0xff0000) >> 8) | ((data & 0xff000000) >> 24); + if(filectx.fd != NULL) { + //data = ni_ntohl(data); + if((filectx.bytecount + count) > filectx.filelen) count = filectx.filelen - filectx.bytecount; + osd_write(filectx.fd, &data, filectx.bytecount, count, &actualcount); + filectx.bytecount += actualcount; + + if(filectx.bytecount >= filectx.filelen) { + osd_close(filectx.fd); + filectx.fd = NULL; + } + } +} + +READ32_MEMBER( nubus_image_device::file_data_r ) +{ + if(filectx.fd != NULL) { + UINT32 ret; + UINT32 actual = 0; + osd_read(filectx.fd, &ret, filectx.bytecount, sizeof(ret), &actual); + filectx.bytecount += actual; + if(actual < sizeof(ret)) { + osd_close(filectx.fd); + filectx.fd = NULL; + } + return ni_htonl(ret); + } + return 0; +} + +WRITE32_MEMBER( nubus_image_device::file_len_w ) +{ + data = ((data & 0xff) << 24) | ((data & 0xff00) << 8) | ((data & 0xff0000) >> 8) | ((data & 0xff000000) >> 24); + filectx.filelen = ni_ntohl(data); +} + +READ32_MEMBER( nubus_image_device::file_len_r ) +{ + return filectx.filelen; +} + +WRITE32_MEMBER( nubus_image_device::file_name_w ) +{ + ((UINT32*)(filectx.filename))[offset] = ni_ntohl(data); +} + +READ32_MEMBER( nubus_image_device::file_name_r ) +{ + UINT32 ret; + ret = ni_htonl(((UINT32*)(filectx.filename))[offset]); + return ret; +} diff --git a/src/devices/bus/nubus/nubus_image.h b/src/devices/bus/nubus/nubus_image.h new file mode 100644 index 00000000000..cbd68d1ae51 --- /dev/null +++ b/src/devices/bus/nubus/nubus_image.h @@ -0,0 +1,80 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +#pragma once + +#ifndef __NUBUS_IMAGE_H__ +#define __NUBUS_IMAGE_H__ + +#include "emu.h" +#include "nubus.h" +#include "osdcore.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** +class messimg_disk_image_device; + +struct nbfilectx { + UINT32 curcmd; + UINT8 filename[128]; + UINT8 curdir[1024]; + osd_directory *dirp; + osd_file *fd; + UINT64 filelen; + UINT32 bytecount; +}; + +// ======================> nubus_image_device + +class nubus_image_device : + public device_t, + public device_nubus_card_interface +{ +public: + // construction/destruction + nubus_image_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + nubus_image_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual const rom_entry *device_rom_region() const; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + DECLARE_READ32_MEMBER(image_status_r); + DECLARE_WRITE32_MEMBER(image_status_w); + DECLARE_READ32_MEMBER(image_r); + DECLARE_WRITE32_MEMBER(image_w); + DECLARE_READ32_MEMBER(image_super_r); + DECLARE_WRITE32_MEMBER(image_super_w); + DECLARE_READ32_MEMBER(file_cmd_r); + DECLARE_WRITE32_MEMBER(file_cmd_w); + DECLARE_READ32_MEMBER(file_data_r); + DECLARE_WRITE32_MEMBER(file_data_w); + DECLARE_READ32_MEMBER(file_len_r); + DECLARE_WRITE32_MEMBER(file_len_w); + DECLARE_READ32_MEMBER(file_name_r); + DECLARE_WRITE32_MEMBER(file_name_w); + +public: + messimg_disk_image_device *m_image; + struct nbfilectx filectx; +}; + + +// device type definition +extern const device_type NUBUS_IMAGE; + +enum { + kFileCmdGetDir = 1, + kFileCmdSetDir, + kFileCmdGetFirstListing, + kFileCmdGetNextListing, + kFileCmdGetFile, + kFileCmdPutFile +}; + +#endif /* __NUBUS_IMAGE_H__ */ diff --git a/src/devices/bus/nubus/nubus_m2hires.c b/src/devices/bus/nubus/nubus_m2hires.c new file mode 100644 index 00000000000..7a2d1a8ffdf --- /dev/null +++ b/src/devices/bus/nubus/nubus_m2hires.c @@ -0,0 +1,314 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/*************************************************************************** + + Apple Hi-Resolution Video Card emulation + + RAMDAC: control at Fs0940e0, data at Fs0940e4 + Fs090010 bit 16 is vbl status, bit 17 must be "1" for proper operation + Fs08000x are the control registers + +***************************************************************************/ + +#include "emu.h" +#include "nubus_m2hires.h" + +#define M2HIRES_SCREEN_NAME "m2hires_screen" +#define M2HIRES_ROM_REGION "m2hires_rom" + +#define VRAM_SIZE (0x80000) // 512k max + +MACHINE_CONFIG_FRAGMENT( m2hires ) + MCFG_SCREEN_ADD( M2HIRES_SCREEN_NAME, RASTER) + MCFG_SCREEN_UPDATE_DEVICE(DEVICE_SELF, nubus_m2hires_device, screen_update) + MCFG_SCREEN_RAW_PARAMS(25175000, 800, 0, 640, 525, 0, 480) + MCFG_SCREEN_SIZE(1024,768) + MCFG_SCREEN_VISIBLE_AREA(0, 640-1, 0, 480-1) +MACHINE_CONFIG_END + +ROM_START( m2hires ) + ROM_REGION(0x2000, M2HIRES_ROM_REGION, 0) + ROM_LOAD( "341-0660.bin", 0x0000, 0x2000, CRC(ea6f7913) SHA1(37c59f38ae34021d0cb86c2e76a598b7e6077c0d) ) +ROM_END + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type NUBUS_M2HIRES = &device_creator; + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor nubus_m2hires_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( m2hires ); +} + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *nubus_m2hires_device::device_rom_region() const +{ + return ROM_NAME( m2hires ); +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// nubus_m2hires_device - constructor +//------------------------------------------------- + +nubus_m2hires_device::nubus_m2hires_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, NUBUS_M2HIRES, "Macintosh II Hi-Resolution video card", tag, owner, clock, "nb_m2hr", __FILE__), + device_video_interface(mconfig, *this), + device_nubus_card_interface(mconfig, *this) +{ + m_assembled_tag = std::string(tag).append(":").append(M2HIRES_SCREEN_NAME); + m_screen_tag = m_assembled_tag.c_str(); +} + +nubus_m2hires_device::nubus_m2hires_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_video_interface(mconfig, *this), + device_nubus_card_interface(mconfig, *this) +{ + m_assembled_tag = std::string(tag).append(":").append(M2HIRES_SCREEN_NAME); + m_screen_tag = m_assembled_tag.c_str(); +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void nubus_m2hires_device::device_start() +{ + UINT32 slotspace; + + // set_nubus_device makes m_slot valid + set_nubus_device(); + install_declaration_rom(this, M2HIRES_ROM_REGION, true); + + slotspace = get_slotspace(); + +// printf("[m2hires %p] slotspace = %x\n", this, slotspace); + + m_vram.resize(VRAM_SIZE); + m_vram32 = (UINT32 *)&m_vram[0]; + + m_nubus->install_device(slotspace, slotspace+VRAM_SIZE-1, read32_delegate(FUNC(nubus_m2hires_device::vram_r), this), write32_delegate(FUNC(nubus_m2hires_device::vram_w), this)); + m_nubus->install_device(slotspace+0x900000, slotspace+VRAM_SIZE-1+0x900000, read32_delegate(FUNC(nubus_m2hires_device::vram_r), this), write32_delegate(FUNC(nubus_m2hires_device::vram_w), this)); + m_nubus->install_device(slotspace+0x80000, slotspace+0xeffff, read32_delegate(FUNC(nubus_m2hires_device::m2hires_r), this), write32_delegate(FUNC(nubus_m2hires_device::m2hires_w), this)); + + m_timer = timer_alloc(0, NULL); + m_timer->adjust(m_screen->time_until_pos(479, 0), 0); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void nubus_m2hires_device::device_reset() +{ + m_count = 0; + m_clutoffs = 0; + m_vbl_disable = 1; + m_mode = 0; + memset(&m_vram[0], 0, VRAM_SIZE); + memset(m_palette, 0, sizeof(m_palette)); + + m_palette[0] = rgb_t(255, 255, 255); + m_palette[0x80] = rgb_t(0, 0, 0); +} + + +void nubus_m2hires_device::device_timer(emu_timer &timer, device_timer_id tid, int param, void *ptr) +{ + if (!m_vbl_disable) + { + raise_slot_irq(); + } + + m_timer->adjust(m_screen->time_until_pos(479, 0), 0); +} + +/*************************************************************************** + + Spectrum 24 PDQ section + +***************************************************************************/ + +UINT32 nubus_m2hires_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + UINT32 *scanline; + int x, y; + UINT8 pixels, *vram; + + vram = &m_vram[0x20]; + + switch (m_mode) + { + case 0: // 1 bpp? + for (y = 0; y < 480; y++) + { + scanline = &bitmap.pix32(y); + for (x = 0; x < 640/8; x++) + { + pixels = vram[(y * 128) + (BYTE4_XOR_BE(x))]; + + *scanline++ = m_palette[((pixels>>7)&0x1)]; + *scanline++ = m_palette[((pixels>>6)&0x1)]; + *scanline++ = m_palette[((pixels>>5)&0x1)]; + *scanline++ = m_palette[((pixels>>4)&0x1)]; + *scanline++ = m_palette[((pixels>>3)&0x1)]; + *scanline++ = m_palette[((pixels>>2)&0x1)]; + *scanline++ = m_palette[((pixels>>1)&0x1)]; + *scanline++ = m_palette[(pixels&1)]; + } + } + break; + + case 1: // 2 bpp + for (y = 0; y < 480; y++) + { + scanline = &bitmap.pix32(y); + for (x = 0; x < 640/4; x++) + { + pixels = vram[(y * 256) + (BYTE4_XOR_BE(x))]; + + *scanline++ = m_palette[((pixels>>6)&3)]; + *scanline++ = m_palette[((pixels>>4)&3)]; + *scanline++ = m_palette[((pixels>>2)&3)]; + *scanline++ = m_palette[(pixels&3)]; + } + } + break; + + case 2: // 4 bpp + for (y = 0; y < 480; y++) + { + scanline = &bitmap.pix32(y); + + for (x = 0; x < 640/2; x++) + { + pixels = vram[(y * 512) + (BYTE4_XOR_BE(x))]; + + *scanline++ = m_palette[((pixels&0xf0)>>4)]; + *scanline++ = m_palette[(pixels&0xf)]; + } + } + break; + + case 3: // 8 bpp + for (y = 0; y < 480; y++) + { + scanline = &bitmap.pix32(y); + + for (x = 0; x < 640; x++) + { + pixels = vram[(y * 1024) + (BYTE4_XOR_BE(x))]; + *scanline++ = m_palette[pixels]; + } + } + break; + + default: + fatalerror("m2hires: unknown video mode %d\n", m_mode); + } + return 0; +} + +WRITE32_MEMBER( nubus_m2hires_device::m2hires_w ) +{ + data ^= 0xffffffff; + + switch (offset) + { + case 1: // mode + switch (data) + { + case 0x20000000: + m_mode = 0; + break; + + case 0x40000000: + m_mode = 1; + break; + + case 0x80000000: + m_mode = 2; + break; + + case 0x00010000: + m_mode = 3; + break; + } + break; + + case 0x5038: // DAC control +// printf("%08x to DAC control (PC=%x)\n", data, space.device().safe_pc()); + m_clutoffs = (data>>24)&0xff; + break; + + case 0x5039: // DAC data + m_colors[m_count++] = (data>>24) & 0xff; + + if (m_count == 3) + { +// printf("RAMDAC: color %d = %02x %02x %02x (PC=%x)\n", m_clutoffs, m_colors[0], m_colors[1], m_colors[2], space.device().safe_pc() ); + m_palette[m_clutoffs] = rgb_t(m_colors[0], m_colors[1], m_colors[2]); + m_clutoffs++; + if (m_clutoffs > 255) + { + m_clutoffs = 0; + } + m_count = 0; + } + break; + + case 0x8000: // enable and ack VBL + m_vbl_disable = 0; + lower_slot_irq(); + break; + + case 0x8001: // disable VBL + m_vbl_disable = 1; + break; + + default: +// printf("m2hires_w: %08x @ %x, mask %08x (PC=%x)\n", data, offset, mem_mask, space.device().safe_pc()); + break; + } +} + +READ32_MEMBER( nubus_m2hires_device::m2hires_r ) +{ + if (offset == 0x10010/4) + { + m_toggle ^= (1<<16); + return m_toggle | (1<<17); // bit 17 indicates a 4/8bpp capable ASIC apparently; the firmware won't enter those modes otherwise (although they show in the list) + } +/* else + { + printf("m2hires_r: @ %x, mask %08x (PC=%x)\n", offset, mem_mask, space.device().safe_pc()); + }*/ + + return 0; +} + +WRITE32_MEMBER( nubus_m2hires_device::vram_w ) +{ + data ^= 0xffffffff; + COMBINE_DATA(&m_vram32[offset]); +} + +READ32_MEMBER( nubus_m2hires_device::vram_r ) +{ + return m_vram32[offset] ^ 0xffffffff; +} diff --git a/src/devices/bus/nubus/nubus_m2hires.h b/src/devices/bus/nubus/nubus_m2hires.h new file mode 100644 index 00000000000..b47db82b0a6 --- /dev/null +++ b/src/devices/bus/nubus/nubus_m2hires.h @@ -0,0 +1,56 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +#pragma once + +#ifndef __NUBUS_M2HIRES_H__ +#define __NUBUS_M2HIRES_H__ + +#include "emu.h" +#include "nubus.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> nubus_m2hires_device + +class nubus_m2hires_device : + public device_t, + public device_video_interface, + public device_nubus_card_interface +{ +public: + // construction/destruction + nubus_m2hires_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + nubus_m2hires_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual const rom_entry *device_rom_region() const; + + UINT32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + DECLARE_READ32_MEMBER(m2hires_r); + DECLARE_WRITE32_MEMBER(m2hires_w); + DECLARE_READ32_MEMBER(vram_r); + DECLARE_WRITE32_MEMBER(vram_w); + +public: + dynamic_buffer m_vram; + UINT32 *m_vram32; + UINT32 m_mode, m_vbl_disable, m_toggle; + UINT32 m_palette[256], m_colors[3], m_count, m_clutoffs; + emu_timer *m_timer; + std::string m_assembled_tag; +}; + + +// device type definition +extern const device_type NUBUS_M2HIRES; + +#endif /* __NUBUS_M2HIRES_H__ */ diff --git a/src/devices/bus/nubus/nubus_m2video.c b/src/devices/bus/nubus/nubus_m2video.c new file mode 100644 index 00000000000..edf0b90abbb --- /dev/null +++ b/src/devices/bus/nubus/nubus_m2video.c @@ -0,0 +1,314 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/*************************************************************************** + + Apple Macintosh II Video Card (630-0153) emulation + + Video ASIC is "TFB" 344-0001 + RAMDAC is Bt453: control at Fs09001C, data at Fs090018 + Fs08000x is general framebuffer control (video mode at 0) + Fs0D0000 bit 0 is VBL status + +***************************************************************************/ + +#include "emu.h" +#include "nubus_m2video.h" + +#define M2VIDEO_SCREEN_NAME "m2video_screen" +#define M2VIDEO_ROM_REGION "m2video_rom" + +#define VRAM_SIZE (0x80000) // 512k max + +MACHINE_CONFIG_FRAGMENT( m2video ) + MCFG_SCREEN_ADD(M2VIDEO_SCREEN_NAME, RASTER) + MCFG_SCREEN_UPDATE_DEVICE(DEVICE_SELF, nubus_m2video_device, screen_update) + MCFG_SCREEN_RAW_PARAMS(25175000, 800, 0, 640, 525, 0, 480) + MCFG_SCREEN_SIZE(1024,768) + MCFG_SCREEN_VISIBLE_AREA(0, 640-1, 0, 480-1) +MACHINE_CONFIG_END + +ROM_START( m2video ) + ROM_REGION(0x1000, M2VIDEO_ROM_REGION, 0) + ROM_LOAD( "342-0008-a.bin", 0x000000, 0x001000, CRC(bf50850d) SHA1(abe85d8a882bb2b8187a28bd6707fc2f5d77eedd) ) +ROM_END + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type NUBUS_M2VIDEO = &device_creator; + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor nubus_m2video_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( m2video ); +} + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *nubus_m2video_device::device_rom_region() const +{ + return ROM_NAME( m2video ); +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// nubus_m2video_device - constructor +//------------------------------------------------- + +nubus_m2video_device::nubus_m2video_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, NUBUS_M2VIDEO, "Macintosh II Video Card", tag, owner, clock, "nb_m2vc", __FILE__), + device_video_interface(mconfig, *this), + device_nubus_card_interface(mconfig, *this) +{ + m_assembled_tag = std::string(tag).append(":").append(M2VIDEO_SCREEN_NAME); + m_screen_tag = m_assembled_tag.c_str(); +} + +nubus_m2video_device::nubus_m2video_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_video_interface(mconfig, *this), + device_nubus_card_interface(mconfig, *this) +{ + m_assembled_tag = std::string(tag).append(":").append(M2VIDEO_SCREEN_NAME); + m_screen_tag = m_assembled_tag.c_str(); +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void nubus_m2video_device::device_start() +{ + UINT32 slotspace; + + // set_nubus_device makes m_slot valid + set_nubus_device(); + install_declaration_rom(this, M2VIDEO_ROM_REGION, true, true); + + slotspace = get_slotspace(); + +// printf("[m2video %p] slotspace = %x\n", this, slotspace); + + m_vram.resize(VRAM_SIZE); + m_vram32 = (UINT32 *)&m_vram[0]; + + m_nubus->install_device(slotspace, slotspace+VRAM_SIZE-1, read32_delegate(FUNC(nubus_m2video_device::vram_r), this), write32_delegate(FUNC(nubus_m2video_device::vram_w), this)); + m_nubus->install_device(slotspace+0x900000, slotspace+VRAM_SIZE-1+0x900000, read32_delegate(FUNC(nubus_m2video_device::vram_r), this), write32_delegate(FUNC(nubus_m2video_device::vram_w), this)); + m_nubus->install_device(slotspace+0x80000, slotspace+0xeffff, read32_delegate(FUNC(nubus_m2video_device::m2video_r), this), write32_delegate(FUNC(nubus_m2video_device::m2video_w), this)); + + m_timer = timer_alloc(0, NULL); + m_timer->adjust(m_screen->time_until_pos(479, 0), 0); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void nubus_m2video_device::device_reset() +{ + m_count = 0; + m_clutoffs = 0; + m_vbl_disable = 1; + m_mode = 0; + memset(&m_vram[0], 0, VRAM_SIZE); + memset(m_palette, 0, sizeof(m_palette)); + + m_palette[0] = rgb_t(255, 255, 255); + m_palette[0x80] = rgb_t(0, 0, 0); +} + + +void nubus_m2video_device::device_timer(emu_timer &timer, device_timer_id tid, int param, void *ptr) +{ + if (!m_vbl_disable) + { + raise_slot_irq(); + } + + m_timer->adjust(m_screen->time_until_pos(479, 0), 0); +} + +/*************************************************************************** + + "TFB" section + +***************************************************************************/ + +UINT32 nubus_m2video_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + UINT32 *scanline; + int x, y; + UINT8 pixels, *vram; + + vram = &m_vram[0x20]; + + switch (m_mode) + { + case 0: // 1 bpp? + for (y = 0; y < 480; y++) + { + scanline = &bitmap.pix32(y); + for (x = 0; x < 640/8; x++) + { + pixels = vram[(y * 128) + (BYTE4_XOR_BE(x))]; + + *scanline++ = m_palette[(pixels&0x80)]; + *scanline++ = m_palette[((pixels<<1)&0x80)]; + *scanline++ = m_palette[((pixels<<2)&0x80)]; + *scanline++ = m_palette[((pixels<<3)&0x80)]; + *scanline++ = m_palette[((pixels<<4)&0x80)]; + *scanline++ = m_palette[((pixels<<5)&0x80)]; + *scanline++ = m_palette[((pixels<<6)&0x80)]; + *scanline++ = m_palette[((pixels<<7)&0x80)]; + } + } + break; + + case 1: // 2 bpp + for (y = 0; y < 480; y++) + { + scanline = &bitmap.pix32(y); + for (x = 0; x < 640/4; x++) + { + pixels = vram[(y * 256) + (BYTE4_XOR_BE(x))]; + + *scanline++ = m_palette[(pixels&0xc0)]; + *scanline++ = m_palette[((pixels<<2)&0xc0)]; + *scanline++ = m_palette[((pixels<<4)&0xc0)]; + *scanline++ = m_palette[((pixels<<6)&0xc0)]; + } + } + break; + + case 2: // 4 bpp + for (y = 0; y < 480; y++) + { + scanline = &bitmap.pix32(y); + + for (x = 0; x < 640/2; x++) + { + pixels = vram[(y * 512) + (BYTE4_XOR_BE(x))]; + + *scanline++ = m_palette[(pixels&0xf0)]; + *scanline++ = m_palette[((pixels&0x0f)<<4)]; + } + } + break; + + case 3: // 8 bpp + for (y = 0; y < 480; y++) + { + scanline = &bitmap.pix32(y); + + for (x = 0; x < 640; x++) + { + pixels = vram[(y * 1024) + (BYTE4_XOR_BE(x))]; + *scanline++ = m_palette[pixels]; + } + } + break; + + default: + fatalerror("m2video: unknown video mode %d\n", m_mode); + } + return 0; +} + +WRITE32_MEMBER( nubus_m2video_device::m2video_w ) +{ + data ^= 0xffffffff; + switch (offset) + { + case 0: // mode + switch (data & 0xff000000) + { + case 0x20000000: + m_mode = 0; + break; + + case 0x40000000: + m_mode = 1; + break; + + case 0x80000000: + m_mode = 2; + break; + + case 0x00000000: + m_mode = 3; + break; + } + break; + + case 0x4007: // DAC control +// printf("%08x to DAC control (PC=%x)\n", data, space.device().safe_pc()); + m_clutoffs = (data>>24)&0xff; + break; + + case 0x4006: // DAC data + m_colors[m_count++] = (data>>24) & 0xff; + + if (m_count == 3) + { +// printf("RAMDAC: color %02x = %02x %02x %02x (PC=%x)\n", m_clutoffs, m_colors[0], m_colors[1], m_colors[2], space.device().safe_pc() ); + m_palette[m_clutoffs] = rgb_t(m_colors[0], m_colors[1], m_colors[2]); + m_clutoffs++; + if (m_clutoffs > 255) + { + m_clutoffs = 0; + } + m_count = 0; + } + break; + + case 0x8000: // enable and ack VBL + m_vbl_disable = 0; + lower_slot_irq(); + break; + + case 0x8001: // disable VBL + m_vbl_disable = 1; + break; + + default: +// printf("m2video_w: %08x @ %x, mask %08x (PC=%x)\n", data, offset, mem_mask, space.device().safe_pc()); + break; + } +} + +READ32_MEMBER( nubus_m2video_device::m2video_r ) +{ + if (offset == 0x50000/4) // bit 0 is VBL status + { + m_toggle ^= 1; + return m_toggle; + } + else + { +// printf("m2video_r: @ %x, mask %08x (PC=%x)\n", offset, mem_mask, space.device().safe_pc()); + } + + return 0; +} + +WRITE32_MEMBER( nubus_m2video_device::vram_w ) +{ + data ^= 0xffffffff; + COMBINE_DATA(&m_vram32[offset]); +} + +READ32_MEMBER( nubus_m2video_device::vram_r ) +{ + return m_vram32[offset] ^ 0xffffffff; +} diff --git a/src/devices/bus/nubus/nubus_m2video.h b/src/devices/bus/nubus/nubus_m2video.h new file mode 100644 index 00000000000..211482c4c97 --- /dev/null +++ b/src/devices/bus/nubus/nubus_m2video.h @@ -0,0 +1,56 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +#pragma once + +#ifndef __NUBUS_M2VIDEO_H__ +#define __NUBUS_M2VIDEO_H__ + +#include "emu.h" +#include "nubus.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> nubus_m2video_device + +class nubus_m2video_device : + public device_t, + public device_video_interface, + public device_nubus_card_interface +{ +public: + // construction/destruction + nubus_m2video_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + nubus_m2video_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual const rom_entry *device_rom_region() const; + + UINT32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + DECLARE_READ32_MEMBER(m2video_r); + DECLARE_WRITE32_MEMBER(m2video_w); + DECLARE_READ32_MEMBER(vram_r); + DECLARE_WRITE32_MEMBER(vram_w); + +public: + dynamic_buffer m_vram; + UINT32 *m_vram32; + UINT32 m_mode, m_vbl_disable, m_toggle; + UINT32 m_palette[256], m_colors[3], m_count, m_clutoffs; + emu_timer *m_timer; + std::string m_assembled_tag; +}; + + +// device type definition +extern const device_type NUBUS_M2VIDEO; + +#endif /* __NUBUS_M2VIDEO_H__ */ diff --git a/src/devices/bus/nubus/nubus_radiustpd.c b/src/devices/bus/nubus/nubus_radiustpd.c new file mode 100644 index 00000000000..3b30fc4a384 --- /dev/null +++ b/src/devices/bus/nubus/nubus_radiustpd.c @@ -0,0 +1,214 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/*************************************************************************** + + Radius Two Page Display (1280x960?) + + Fsx8000a = DAC data + Fsx8000e = DAC control + Fsx00000 = VRAM (offset 0x200, stride 0x1b0) + +***************************************************************************/ + +#include "emu.h" +#include "nubus_radiustpd.h" + +#define RADIUSTPD_SCREEN_NAME "tpd_screen" +#define RADIUSTPD_ROM_REGION "tpd_rom" + +#define VRAM_SIZE (0x40000) // 256k. 1152x880 1 bit per pixel fits nicely. + +MACHINE_CONFIG_FRAGMENT( radiustpd ) + MCFG_SCREEN_ADD( RADIUSTPD_SCREEN_NAME, RASTER) + MCFG_SCREEN_UPDATE_DEVICE(DEVICE_SELF, nubus_radiustpd_device, screen_update) + MCFG_SCREEN_SIZE(1280, 960) + MCFG_SCREEN_REFRESH_RATE(70) + MCFG_SCREEN_VISIBLE_AREA(0, 1152-1, 0, 880-1) +MACHINE_CONFIG_END + +ROM_START( radiustpd ) + ROM_REGION(0x8000, RADIUSTPD_ROM_REGION, 0) + ROM_LOAD( "tpd_v22.bin", 0x0000, 0x8000, CRC(7dc5ed05) SHA1(4abb64e49201e966c17a255a94b670564b229934) ) +ROM_END + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type NUBUS_RADIUSTPD = &device_creator; + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor nubus_radiustpd_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( radiustpd ); +} + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *nubus_radiustpd_device::device_rom_region() const +{ + return ROM_NAME( radiustpd ); +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// nubus_radiustpd_device - constructor +//------------------------------------------------- + +nubus_radiustpd_device::nubus_radiustpd_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, NUBUS_RADIUSTPD, "Radius Two Page Display video card", tag, owner, clock, "nb_rtpd", __FILE__), + device_video_interface(mconfig, *this), + device_nubus_card_interface(mconfig, *this) +{ + m_assembled_tag = std::string(tag).append(":").append(RADIUSTPD_SCREEN_NAME); + m_screen_tag = m_assembled_tag.c_str(); +} + +nubus_radiustpd_device::nubus_radiustpd_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_video_interface(mconfig, *this), + device_nubus_card_interface(mconfig, *this) +{ + m_assembled_tag = std::string(tag).append(":").append(RADIUSTPD_SCREEN_NAME); + m_screen_tag = m_assembled_tag.c_str(); +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void nubus_radiustpd_device::device_start() +{ + UINT32 slotspace; + + // set_nubus_device makes m_slot valid + set_nubus_device(); + install_declaration_rom(this, RADIUSTPD_ROM_REGION, true, true); + + slotspace = get_slotspace(); + + printf("[radiustpd %p] slotspace = %x\n", (void *)this, slotspace); + + m_vram.resize(VRAM_SIZE); + m_vram32 = (UINT32 *)&m_vram[0]; + + m_nubus->install_device(slotspace, slotspace+VRAM_SIZE-1, read32_delegate(FUNC(nubus_radiustpd_device::vram_r), this), write32_delegate(FUNC(nubus_radiustpd_device::vram_w), this)); + m_nubus->install_device(slotspace+0x900000, slotspace+VRAM_SIZE-1+0x900000, read32_delegate(FUNC(nubus_radiustpd_device::vram_r), this), write32_delegate(FUNC(nubus_radiustpd_device::vram_w), this)); + m_nubus->install_device(slotspace+0x80000, slotspace+0xeffff, read32_delegate(FUNC(nubus_radiustpd_device::radiustpd_r), this), write32_delegate(FUNC(nubus_radiustpd_device::radiustpd_w), this)); + m_nubus->install_device(slotspace+0x980000, slotspace+0x9effff, read32_delegate(FUNC(nubus_radiustpd_device::radiustpd_r), this), write32_delegate(FUNC(nubus_radiustpd_device::radiustpd_w), this)); + + m_timer = timer_alloc(0, NULL); + m_timer->adjust(m_screen->time_until_pos(479, 0), 0); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void nubus_radiustpd_device::device_reset() +{ + m_count = 0; + m_clutoffs = 0; + m_vbl_disable = 1; + m_mode = 0; + memset(&m_vram[0], 0, VRAM_SIZE); + memset(m_palette, 0, sizeof(m_palette)); + + m_palette[1] = rgb_t(255, 255, 255); + m_palette[0] = rgb_t(0, 0, 0); +} + + +void nubus_radiustpd_device::device_timer(emu_timer &timer, device_timer_id tid, int param, void *ptr) +{ + if (!m_vbl_disable) + { + raise_slot_irq(); + } + + m_timer->adjust(m_screen->time_until_pos(479, 0), 0); +} + +/*************************************************************************** + + Two Page Display section + +***************************************************************************/ + +UINT32 nubus_radiustpd_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + UINT32 *scanline; + int x, y; + UINT8 pixels, *vram; + + vram = &m_vram[0x200]; + + for (y = 0; y < 880; y++) + { + scanline = &bitmap.pix32(y); + for (x = 0; x < 1152/8; x++) + { + pixels = vram[(y * (1152/8)) + (BYTE4_XOR_BE(x))]; + + *scanline++ = m_palette[((pixels>>7)&0x1)]; + *scanline++ = m_palette[((pixels>>6)&0x1)]; + *scanline++ = m_palette[((pixels>>5)&0x1)]; + *scanline++ = m_palette[((pixels>>4)&0x1)]; + *scanline++ = m_palette[((pixels>>3)&0x1)]; + *scanline++ = m_palette[((pixels>>2)&0x1)]; + *scanline++ = m_palette[((pixels>>1)&0x1)]; + *scanline++ = m_palette[(pixels&1)]; + } + } + + return 0; +} + +WRITE32_MEMBER( nubus_radiustpd_device::radiustpd_w ) +{ +// printf("TPD: write %08x to %x, mask %08x\n", data, offset, mem_mask); +} + +READ32_MEMBER( nubus_radiustpd_device::radiustpd_r ) +{ +// printf("TPD: read @ %x, mask %08x\n", offset, mem_mask); + + if (offset == 0) + { + lower_slot_irq(); + m_vbl_disable = true; + } + + if (offset == 0x8000) + { + m_vbl_disable = false; + } + + if (offset == 0x18000) + { + return 0xffffffff; + } + + return 0; +} + +WRITE32_MEMBER( nubus_radiustpd_device::vram_w ) +{ + data ^= 0xffffffff; + COMBINE_DATA(&m_vram32[offset]); +} + +READ32_MEMBER( nubus_radiustpd_device::vram_r ) +{ + return m_vram32[offset] ^ 0xffffffff; +} diff --git a/src/devices/bus/nubus/nubus_radiustpd.h b/src/devices/bus/nubus/nubus_radiustpd.h new file mode 100644 index 00000000000..eb12fdaf0ae --- /dev/null +++ b/src/devices/bus/nubus/nubus_radiustpd.h @@ -0,0 +1,56 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +#pragma once + +#ifndef __NUBUS_RADIUSTPD_H__ +#define __NUBUS_RADIUSTPD_H__ + +#include "emu.h" +#include "nubus.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> nubus_radiustpd_device + +class nubus_radiustpd_device : + public device_t, + public device_video_interface, + public device_nubus_card_interface +{ +public: + // construction/destruction + nubus_radiustpd_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + nubus_radiustpd_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual const rom_entry *device_rom_region() const; + + UINT32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + DECLARE_READ32_MEMBER(radiustpd_r); + DECLARE_WRITE32_MEMBER(radiustpd_w); + DECLARE_READ32_MEMBER(vram_r); + DECLARE_WRITE32_MEMBER(vram_w); + +public: + dynamic_buffer m_vram; + UINT32 *m_vram32; + UINT32 m_mode, m_vbl_disable, m_toggle; + UINT32 m_palette[256], m_colors[3], m_count, m_clutoffs; + emu_timer *m_timer; + std::string m_assembled_tag; +}; + + +// device type definition +extern const device_type NUBUS_RADIUSTPD; + +#endif /* __NUBUS_RADIUSTPD_H__ */ diff --git a/src/devices/bus/nubus/nubus_spec8.c b/src/devices/bus/nubus/nubus_spec8.c new file mode 100644 index 00000000000..b72fc2d676f --- /dev/null +++ b/src/devices/bus/nubus/nubus_spec8.c @@ -0,0 +1,355 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/*************************************************************************** + + SuperMac Spectrum/8 Series III video card + + There is no sign of acceleration or blitting in any mode, and the acceleration + code from the Spectrum PDQ ROM is absent on this one. + + On first boot / with clean PRAM, press SPACE repeatedly when it shows the frame + that fills the entire screen. If you get it wrong, delete PRAM and try again. + +***************************************************************************/ + +#include "emu.h" +#include "nubus_spec8.h" + +#define SPEC8S3_SCREEN_NAME "spec8s3_screen" +#define SPEC8S3_ROM_REGION "spec8s3_rom" + +#define VRAM_SIZE (0xc0000) // 768k of VRAM for 1024x768 @ 8 bit + +MACHINE_CONFIG_FRAGMENT( spec8s3 ) + MCFG_SCREEN_ADD( SPEC8S3_SCREEN_NAME, RASTER) + MCFG_SCREEN_UPDATE_DEVICE(DEVICE_SELF, nubus_spec8s3_device, screen_update) + MCFG_SCREEN_RAW_PARAMS(25175000, 800, 0, 640, 525, 0, 480) + MCFG_SCREEN_SIZE(1024,768) + MCFG_SCREEN_VISIBLE_AREA(0, 1024-1, 0, 768-1) +MACHINE_CONFIG_END + +ROM_START( spec8s3 ) + ROM_REGION(0x8000, SPEC8S3_ROM_REGION, 0) + ROM_LOAD( "1003067-0001d.11b.bin", 0x000000, 0x008000, CRC(12188e2b) SHA1(6552d40364eae99b449842a79843d8c0114c4c70) ) +ROM_END + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type NUBUS_SPEC8S3 = &device_creator; + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor nubus_spec8s3_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( spec8s3 ); +} + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *nubus_spec8s3_device::device_rom_region() const +{ + return ROM_NAME( spec8s3 ); +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// nubus_spec8s3_device - constructor +//------------------------------------------------- + +nubus_spec8s3_device::nubus_spec8s3_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, NUBUS_SPEC8S3, "SuperMac Spectrum/8 Series III video card", tag, owner, clock, "nb_sp8s3", __FILE__), + device_video_interface(mconfig, *this), + device_nubus_card_interface(mconfig, *this) +{ + m_assembled_tag = std::string(tag).append(":").append(SPEC8S3_SCREEN_NAME); + m_screen_tag = m_assembled_tag.c_str(); +} + +nubus_spec8s3_device::nubus_spec8s3_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_video_interface(mconfig, *this), + device_nubus_card_interface(mconfig, *this) +{ + m_assembled_tag = std::string(tag).append(":").append(SPEC8S3_SCREEN_NAME); + m_screen_tag = m_assembled_tag.c_str(); +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void nubus_spec8s3_device::device_start() +{ + UINT32 slotspace; + + // set_nubus_device makes m_slot valid + set_nubus_device(); + install_declaration_rom(this, SPEC8S3_ROM_REGION); + + slotspace = get_slotspace(); + +// printf("[SPEC8S3 %p] slotspace = %x\n", this, slotspace); + + m_vram.resize(VRAM_SIZE); + m_vram32 = (UINT32 *)&m_vram[0]; + m_nubus->install_device(slotspace, slotspace+VRAM_SIZE-1, read32_delegate(FUNC(nubus_spec8s3_device::vram_r), this), write32_delegate(FUNC(nubus_spec8s3_device::vram_w), this)); + m_nubus->install_device(slotspace+0x900000, slotspace+VRAM_SIZE-1+0x900000, read32_delegate(FUNC(nubus_spec8s3_device::vram_r), this), write32_delegate(FUNC(nubus_spec8s3_device::vram_w), this)); + m_nubus->install_device(slotspace+0xd0000, slotspace+0xfffff, read32_delegate(FUNC(nubus_spec8s3_device::spec8s3_r), this), write32_delegate(FUNC(nubus_spec8s3_device::spec8s3_w), this)); + + m_timer = timer_alloc(0, NULL); + m_timer->adjust(m_screen->time_until_pos(767, 0), 0); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void nubus_spec8s3_device::device_reset() +{ + m_count = 0; + m_clutoffs = 0; + m_vbl_disable = 1; + m_mode = 0; + m_vbl_pending = false; + m_parameter = 0; + memset(&m_vram[0], 0, VRAM_SIZE); + memset(m_palette, 0, sizeof(m_palette)); + + m_palette[0] = rgb_t(255, 255, 255); + m_palette[1] = rgb_t(0, 0, 0); +} + + +void nubus_spec8s3_device::device_timer(emu_timer &timer, device_timer_id tid, int param, void *ptr) +{ + if (!m_vbl_disable) + { + raise_slot_irq(); + m_vbl_pending = true; + } + + m_timer->adjust(m_screen->time_until_pos(767, 0), 0); +} + +/*************************************************************************** + + Spectrum 24 PDQ section + +***************************************************************************/ + +UINT32 nubus_spec8s3_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + UINT32 *scanline; + int x, y; + UINT8 pixels, *vram; + + vram = &m_vram[0x400]; + + switch (m_mode) + { + case 0: // 1 bpp + for (y = 0; y < 768; y++) + { + scanline = &bitmap.pix32(y); + for (x = 0; x < 1024/8; x++) + { + pixels = vram[(y * 512) + (BYTE4_XOR_BE(x))]; + + *scanline++ = m_palette[pixels&0x80]; + *scanline++ = m_palette[(pixels<<1)&0x80]; + *scanline++ = m_palette[(pixels<<2)&0x80]; + *scanline++ = m_palette[(pixels<<3)&0x80]; + *scanline++ = m_palette[(pixels<<4)&0x80]; + *scanline++ = m_palette[(pixels<<5)&0x80]; + *scanline++ = m_palette[(pixels<<6)&0x80]; + *scanline++ = m_palette[(pixels<<7)&0x80]; + } + } + break; + + case 1: // 2 bpp + for (y = 0; y < 768; y++) + { + scanline = &bitmap.pix32(y); + for (x = 0; x < 1024/4; x++) + { + pixels = vram[(y * 512) + (BYTE4_XOR_BE(x))]; + + *scanline++ = m_palette[pixels&0xc0]; + *scanline++ = m_palette[(pixels<<2)&0xc0]; + *scanline++ = m_palette[(pixels<<4)&0xc0]; + *scanline++ = m_palette[(pixels<<6)&0xc0]; + } + } + break; + + case 2: // 4 bpp + for (y = 0; y < 768; y++) + { + scanline = &bitmap.pix32(y); + + for (x = 0; x < 1024/2; x++) + { + pixels = vram[(y * 512) + (BYTE4_XOR_BE(x))]; + + *scanline++ = m_palette[pixels&0xf0]; + *scanline++ = m_palette[(pixels<<4)&0xf0]; + } + } + break; + + case 3: // 8 bpp + for (y = 0; y < 768; y++) + { + scanline = &bitmap.pix32(y); + + for (x = 0; x < 1024; x++) + { + pixels = vram[(y * 1024) + (BYTE4_XOR_BE(x))]; + *scanline++ = m_palette[pixels]; + } + } + break; + + default: + fatalerror("spec8s3: unknown video mode %d\n", m_mode); + } + return 0; +} + +WRITE32_MEMBER( nubus_spec8s3_device::spec8s3_w ) +{ + switch (offset) + { + case 0x385c: // IRQ enable + if (data & 0x10) + { + m_vbl_disable = 1; + lower_slot_irq(); + m_vbl_pending = false; + } + else + { + m_vbl_disable = 0; + } + break; + + case 0x385e: + break; + + case 0x386e: + break; + + case 0x3a00: + m_clutoffs = (data & 0xff) ^ 0xff; + break; + + case 0x3a01: +// printf("%08x to color (%08x invert)\n", data, data ^ 0xffffffff); + m_colors[m_count++] = (data & 0xff) ^ 0xff; + + if (m_count == 3) + { + int actual_color = BITSWAP8(m_clutoffs, 0, 1, 2, 3, 4, 5, 6, 7); + +// printf("RAMDAC: color %d = %02x %02x %02x (PC=%x)\n", actual_color, m_colors[0], m_colors[1], m_colors[2], space.device().safe_pc() ); + m_palette[actual_color] = rgb_t(m_colors[0], m_colors[1], m_colors[2]); + m_clutoffs++; + if (m_clutoffs > 255) + { + m_clutoffs = 0; + } + m_count = 0; + } + break; + + case 0x3c00: + if ((m_parameter == 2) && (data != 0xffffffff)) + { + data &= 0xff; +// printf("%x to mode\n", data); + switch (data) + { + case 0x5f: + m_mode = 0; + break; + + case 0x5e: + m_mode = 1; + break; + + case 0x5d: + m_mode = 2; + break; + + case 0x5c: + m_mode = 3; + break; + } + } + m_parameter++; + break; + + case 0x3e02: + if (data == 1) + { + m_parameter = 0; + } + break; + + default: +// if (offset >= 0x3800) printf("spec8s3_w: %08x @ %x (mask %08x PC=%x)\n", data, offset, mem_mask, space.device().safe_pc()); + break; + } +} + +READ32_MEMBER( nubus_spec8s3_device::spec8s3_r ) +{ + switch (offset) + { + case 0x3826: + case 0x382e: + return 0xff; + + case 0x3824: + case 0x382c: + return (0xa^0xffffffff); + + case 0x385c: + if (m_vbl_pending) + { + return 0x8; + } + return 0; + + case 0x385e: + return 0; + + default: +// if (offset >= 0x3800) printf("spec8s3_r: @ %x (mask %08x PC=%x)\n", offset, mem_mask, space.device().safe_pc()); + break; + } + return 0; +} + +WRITE32_MEMBER( nubus_spec8s3_device::vram_w ) +{ + data ^= 0xffffffff; + COMBINE_DATA(&m_vram32[offset]); +} + +READ32_MEMBER( nubus_spec8s3_device::vram_r ) +{ + return m_vram32[offset] ^ 0xffffffff; +} diff --git a/src/devices/bus/nubus/nubus_spec8.h b/src/devices/bus/nubus/nubus_spec8.h new file mode 100644 index 00000000000..ed04f1598e8 --- /dev/null +++ b/src/devices/bus/nubus/nubus_spec8.h @@ -0,0 +1,64 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +#pragma once + +#ifndef __NUBUS_SPEC8S3_H__ +#define __NUBUS_SPEC8S3_H__ + +#include "emu.h" +#include "nubus.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> nubus_spec8s3_device + +class nubus_spec8s3_device : + public device_t, + public device_video_interface, + public device_nubus_card_interface +{ +public: + // construction/destruction + nubus_spec8s3_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + nubus_spec8s3_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual const rom_entry *device_rom_region() const; + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + UINT32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + DECLARE_READ32_MEMBER(spec8s3_r); + DECLARE_WRITE32_MEMBER(spec8s3_w); + DECLARE_READ32_MEMBER(vram_r); + DECLARE_WRITE32_MEMBER(vram_w); + +public: + dynamic_buffer m_vram; + UINT32 *m_vram32; + UINT32 m_mode, m_vbl_disable; + UINT32 m_palette[256], m_colors[3], m_count, m_clutoffs; + emu_timer *m_timer; + std::string m_assembled_tag; + +private: + //UINT32 m_7xxxxx_regs[0x100000/4]; + //int m_width, m_height, m_patofsx, m_patofsy; + //UINT32 m_vram_addr, m_vram_src; + //UINT8 m_fillbytes[256]; + bool m_vbl_pending; + int m_parameter; +}; + + +// device type definition +extern const device_type NUBUS_SPEC8S3; + +#endif /* __NUBUS_SPEC8S3_H__ */ diff --git a/src/devices/bus/nubus/nubus_specpdq.c b/src/devices/bus/nubus/nubus_specpdq.c new file mode 100644 index 00000000000..9971454feac --- /dev/null +++ b/src/devices/bus/nubus/nubus_specpdq.c @@ -0,0 +1,490 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/*************************************************************************** + + SuperMac Spectrum PDQ video card + + Accelerated only in 256 color mode. Accleration is not yet emulated + properly (pattern fill works but has glitches). Use in B&W or 16 colors + for full functionality right now. + + blitter info: + + ctrl 1 = ? + ctrl 2 = low 3 bits of Y position in bits 3-5, low 3 bits of X position in bits 0-2 + ctrl 3 = width + ctrl 4 = height + ctrl 5 = ? + ctrl 6 = VRAM offset * 4 + ctrl 7 = command/execute (00000002 for pattern fill, 00000100 for copy) + + Busy flag at Fs800000 (bit 8) + + There is 256 bytes of pattern RAM arranged as 32 pixels horizontally by 8 + vertically. + +***************************************************************************/ + +#include "emu.h" +#include "nubus_specpdq.h" + +#define SPECPDQ_SCREEN_NAME "specpdq_screen" +#define SPECPDQ_ROM_REGION "specpdq_rom" + +#define VRAM_SIZE (0x400000) + +MACHINE_CONFIG_FRAGMENT( specpdq ) + MCFG_SCREEN_ADD( SPECPDQ_SCREEN_NAME, RASTER) + MCFG_SCREEN_UPDATE_DEVICE(DEVICE_SELF, nubus_specpdq_device, screen_update) + MCFG_SCREEN_RAW_PARAMS(25175000, 800, 0, 640, 525, 0, 480) + MCFG_SCREEN_SIZE(1280,1024) + MCFG_SCREEN_VISIBLE_AREA(0, 1152-1, 0, 844-1) + + MCFG_PALETTE_ADD("palette", 256) +MACHINE_CONFIG_END + +ROM_START( specpdq ) + ROM_REGION(0x10000, SPECPDQ_ROM_REGION, 0) + ROM_LOAD( "specpdq.bin", 0x000000, 0x010000, CRC(82a35f78) SHA1(9511c2df47140f4279196d3b8836b53429879dd9) ) +ROM_END + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type NUBUS_SPECPDQ = &device_creator; + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor nubus_specpdq_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( specpdq ); +} + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *nubus_specpdq_device::device_rom_region() const +{ + return ROM_NAME( specpdq ); +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// nubus_specpdq_device - constructor +//------------------------------------------------- + +nubus_specpdq_device::nubus_specpdq_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, NUBUS_SPECPDQ, "SuperMac Spectrum PDQ video card", tag, owner, clock, "nb_spdq", __FILE__), + device_video_interface(mconfig, *this), + device_nubus_card_interface(mconfig, *this), + m_palette(*this, "palette") +{ + m_assembled_tag = std::string(tag).append(":").append(SPECPDQ_SCREEN_NAME); + m_screen_tag = m_assembled_tag.c_str(); +} + +nubus_specpdq_device::nubus_specpdq_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_video_interface(mconfig, *this), + device_nubus_card_interface(mconfig, *this), + m_palette(*this, "palette") +{ + m_assembled_tag = std::string(tag).append(":").append(SPECPDQ_SCREEN_NAME); + m_screen_tag = m_assembled_tag.c_str(); +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void nubus_specpdq_device::device_start() +{ + UINT32 slotspace; + + // set_nubus_device makes m_slot valid + set_nubus_device(); + install_declaration_rom(this, SPECPDQ_ROM_REGION); + + slotspace = get_slotspace(); + +// printf("[specpdq %p] slotspace = %x\n", this, slotspace); + + m_vram.resize(VRAM_SIZE); + m_vram32 = (UINT32 *)&m_vram[0]; + m_nubus->install_device(slotspace, slotspace+VRAM_SIZE-1, read32_delegate(FUNC(nubus_specpdq_device::vram_r), this), write32_delegate(FUNC(nubus_specpdq_device::vram_w), this)); + m_nubus->install_device(slotspace+0x400000, slotspace+0xfbffff, read32_delegate(FUNC(nubus_specpdq_device::specpdq_r), this), write32_delegate(FUNC(nubus_specpdq_device::specpdq_w), this)); + + m_timer = timer_alloc(0, NULL); + m_timer->adjust(m_screen->time_until_pos(843, 0), 0); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void nubus_specpdq_device::device_reset() +{ + m_count = 0; + m_clutoffs = 0; + m_vbl_disable = 1; + m_mode = 0; + memset(&m_vram[0], 0, VRAM_SIZE); + memset(m_palette_val, 0, sizeof(m_palette_val)); + + m_palette_val[0] = rgb_t(255, 255, 255); + m_palette_val[0x80] = rgb_t(0, 0, 0); +} + + +void nubus_specpdq_device::device_timer(emu_timer &timer, device_timer_id tid, int param, void *ptr) +{ + if (!m_vbl_disable) + { + raise_slot_irq(); + } + + m_timer->adjust(m_screen->time_until_pos(843, 0), 0); +} + +/*************************************************************************** + + Spectrum 24 PDQ section + +***************************************************************************/ + +UINT32 nubus_specpdq_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + UINT32 *scanline; + int x, y; + UINT8 pixels, *vram; + + // first time? kick off the VBL timer + vram = &m_vram[0x9000]; + + switch (m_mode) + { + case 0: // 1 bpp + for (y = 0; y < 844; y++) + { + scanline = &bitmap.pix32(y); + for (x = 0; x < 1152/8; x++) + { + pixels = vram[(y * 512) + (BYTE4_XOR_BE(x))]; + + *scanline++ = m_palette_val[(pixels&0x80)]; + *scanline++ = m_palette_val[((pixels<<1)&0x80)]; + *scanline++ = m_palette_val[((pixels<<2)&0x80)]; + *scanline++ = m_palette_val[((pixels<<3)&0x80)]; + *scanline++ = m_palette_val[((pixels<<4)&0x80)]; + *scanline++ = m_palette_val[((pixels<<5)&0x80)]; + *scanline++ = m_palette_val[((pixels<<6)&0x80)]; + *scanline++ = m_palette_val[((pixels<<7)&0x80)]; + } + } + break; + + case 1: // 2 bpp + for (y = 0; y < 844; y++) + { + scanline = &bitmap.pix32(y); + for (x = 0; x < 1152/4; x++) + { + pixels = vram[(y * 512) + (BYTE4_XOR_BE(x))]; + + *scanline++ = m_palette_val[(pixels&0xc0)]; + *scanline++ = m_palette_val[((pixels<<2)&0xc0)]; + *scanline++ = m_palette_val[((pixels<<4)&0xc0)]; + *scanline++ = m_palette_val[((pixels<<6)&0xc0)]; + } + } + break; + + case 2: // 4 bpp + for (y = 0; y < 844; y++) + { + scanline = &bitmap.pix32(y); + + for (x = 0; x < 1152/2; x++) + { + pixels = vram[(y * 1024) + (BYTE4_XOR_BE(x))]; + + *scanline++ = m_palette_val[(pixels&0xf0)]; + *scanline++ = m_palette_val[((pixels<<4)&0xf0)]; + } + } + break; + + case 3: // 8 bpp + for (y = 0; y < 844; y++) + { + scanline = &bitmap.pix32(y); + + for (x = 0; x < 1152; x++) + { + pixels = vram[(y * 1152) + (BYTE4_XOR_BE(x))]; + *scanline++ = m_palette_val[pixels]; + } + } + break; + + default: + fatalerror("specpdq: unknown video mode %d\n", m_mode); + } + return 0; +} + +WRITE32_MEMBER( nubus_specpdq_device::specpdq_w ) +{ + if (offset >= 0xc0000 && offset < 0x100000) + { + COMBINE_DATA(&m_7xxxxx_regs[offset-0xc0000]); + } + + switch (offset) + { + case 0xc0054: // mode 1 +// printf("%x to mode1\n", data); + break; + + case 0xc005c: // interrupt control + if (!(data & 0x8000)) + { + m_vbl_disable = 1; + } + else + { + m_vbl_disable = 0; + lower_slot_irq(); + } + break; + + case 0xc005e: // not sure, interrupt related? + break; + + case 0xc007a: +// printf("%x to mode2\n", data); + + switch (data) + { + case 0xff7fffff: + m_mode = 0; + break; + + case 0xfeffffff: + m_mode = 2; + break; + + case 0xfedfffff: + m_mode = 3; + break; + } + +// printf("m_mode = %d\n", m_mode); + break; + + case 0x120000: // DAC address +// printf("%08x to DAC control (PC=%x)\n", data, space.device().safe_pc()); + m_clutoffs = ((data>>8)&0xff)^0xff; + break; + + case 0x120001: // DAC data + m_colors[m_count++] = ((data>>8)&0xff)^0xff; + + if (m_count == 3) + { +// printf("RAMDAC: color %d = %02x %02x %02x (PC=%x)\n", m_clutoffs, m_colors[0], m_colors[1], m_colors[2], space.device().safe_pc() ); + m_palette->set_pen_color(m_clutoffs, rgb_t(m_colors[0], m_colors[1], m_colors[2])); + m_palette_val[m_clutoffs] = rgb_t(m_colors[0], m_colors[1], m_colors[2]); + m_clutoffs++; + if (m_clutoffs > 255) + { + m_clutoffs = 0; + } + m_count = 0; + } + break; + + // blitter texture? pattern? 256 pixels worth at 8bpp + case 0x181000: + case 0x181001: + case 0x181002: + case 0x181003: + case 0x181004: + case 0x181005: + case 0x181006: + case 0x181007: + case 0x181008: + case 0x181009: + case 0x18100a: + case 0x18100b: + case 0x18100c: + case 0x18100d: + case 0x18100e: + case 0x18100f: + case 0x181010: + case 0x181011: + case 0x181012: + case 0x181013: + case 0x181014: + case 0x181015: + case 0x181016: + case 0x181017: + case 0x181018: + case 0x181019: + case 0x18101a: + case 0x18101b: + case 0x18101c: + case 0x18101d: + case 0x18101e: + case 0x18101f: + case 0x181020: + case 0x181021: + case 0x181022: + case 0x181023: + case 0x181024: + case 0x181025: + case 0x181026: + case 0x181027: + case 0x181028: + case 0x181029: + case 0x18102a: + case 0x18102b: + case 0x18102c: + case 0x18102d: + case 0x18102e: + case 0x18102f: + case 0x181030: + case 0x181031: + case 0x181032: + case 0x181033: + case 0x181034: + case 0x181035: + case 0x181036: + case 0x181037: + case 0x181038: + case 0x181039: + case 0x18103a: + case 0x18103b: + case 0x18103c: + case 0x18103d: + case 0x18103e: + case 0x18103f: +// printf("Pattern %08x @ %x\n", data ^ 0xffffffff, offset); + m_fillbytes[((offset&0x3f)*4)] = ((data>>24) & 0xff) ^ 0xff; + m_fillbytes[((offset&0x3f)*4)+1] = ((data>>16) & 0xff) ^ 0xff; + m_fillbytes[((offset&0x3f)*4)+2] = ((data>>8) & 0xff) ^ 0xff; + m_fillbytes[((offset&0x3f)*4)+3] = (data& 0xff) ^ 0xff; + break; + + // blitter control + case 0x182006: +// printf("%08x (%d) to blitter ctrl 1 (PC=%x)\n", data^0xffffffff, data^0xffffffff, space.device().safe_pc()); + break; + + case 0x182008: +// printf("%08x (%d) to blitter ctrl 2 (PC=%x)\n", data^0xffffffff, data^0xffffffff, space.device().safe_pc()); + m_patofsx = (data ^ 0xffffffff) & 7; + m_patofsy = ((data ^ 0xffffffff)>>3) & 7; + break; + + case 0x18200e: +// printf("%08x (%d) to blitter ctrl 3 (PC=%x)\n", data^0xffffffff, data^0xffffffff, space.device().safe_pc()); + m_width = data ^ 0xffffffff; + break; + + case 0x18200b: +// printf("%08x (%d) to blitter ctrl 4 (PC=%x)\n", data^0xffffffff, data^0xffffffff, space.device().safe_pc()); + m_height = (data ^ 0xffffffff) & 0xffff; + break; + + case 0x18200a: + data ^= 0xffffffff; +// printf("%08x to blitter ctrl 5 (PC=%x)\n", data, space.device().safe_pc()); + m_vram_src = data>>2; + break; + + case 0x182009: + data ^= 0xffffffff; +// printf("%08x to blitter ctrl 6 (PC=%x)\n", data, space.device().safe_pc()); + m_vram_addr = data>>2; + break; + + case 0x182007: + data ^= 0xffffffff; +// printf("%08x to blitter ctrl 7 (PC=%x)\n", data, space.device().safe_pc()); + + // fill rectangle + if (data == 2) + { + int x, y; + UINT8 *vram = &m_vram[m_vram_addr + m_patofsx]; // m_vram_addr is missing the low 2 bits, we add them back here + +// printf("Fill rectangle with %02x %02x %02x %02x, width %d height %d\n", m_fillbytes[0], m_fillbytes[1], m_fillbytes[2], m_fillbytes[3], m_width, m_height); + + for (y = 0; y < m_height; y++) + { + for (x = 0; x < m_width; x++) + { + vram[(y * 1152)+x] = m_fillbytes[((m_patofsx + x) & 0x1f)+(((m_patofsy + y) & 0x7)*32)]; + } + } + } + else if ((data == 0x101) || (data == 0x100)) + { + int x, y; + UINT8 *vram = &m_vram[m_vram_addr]; + UINT8 *vramsrc = &m_vram[m_vram_src]; + +// printf("Copy rectangle, width %d height %d src %x dst %x\n", m_width, m_height, m_vram_addr, m_vram_src); + + for (y = 0; y < m_height; y++) + { + for (x = 0; x < m_width; x++) + { + vram[(y * 1152)+x] = vramsrc[(y * 1152)+x]; + } + } + } + else + { + printf("Unknown blitter command %08x\n", data); + } + break; + + default: +// printf("specpdq_w: %08x @ %x (mask %08x PC=%x)\n", data^0xffffffff, offset, mem_mask, space.device().safe_pc()); + break; + } +} + +READ32_MEMBER( nubus_specpdq_device::specpdq_r ) +{ +// if (offset != 0xc005c && offset != 0xc005e) printf("specpdq_r: @ %x (mask %08x PC=%x)\n", offset, mem_mask, space.device().safe_pc()); + + if (offset >= 0xc0000 && offset < 0x100000) + { + return m_7xxxxx_regs[offset-0xc0000]; + } + + return 0; +} + +WRITE32_MEMBER( nubus_specpdq_device::vram_w ) +{ + data ^= 0xffffffff; + COMBINE_DATA(&m_vram32[offset]); +} + +READ32_MEMBER( nubus_specpdq_device::vram_r ) +{ + return m_vram32[offset] ^ 0xffffffff; +} diff --git a/src/devices/bus/nubus/nubus_specpdq.h b/src/devices/bus/nubus/nubus_specpdq.h new file mode 100644 index 00000000000..fb956743197 --- /dev/null +++ b/src/devices/bus/nubus/nubus_specpdq.h @@ -0,0 +1,63 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +#pragma once + +#ifndef __NUBUS_SPECPDQ_H__ +#define __NUBUS_SPECPDQ_H__ + +#include "emu.h" +#include "nubus.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> nubus_specpdq_device + +class nubus_specpdq_device : + public device_t, + public device_video_interface, + public device_nubus_card_interface +{ +public: + // construction/destruction + nubus_specpdq_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + nubus_specpdq_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual const rom_entry *device_rom_region() const; + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + UINT32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + DECLARE_READ32_MEMBER(specpdq_r); + DECLARE_WRITE32_MEMBER(specpdq_w); + DECLARE_READ32_MEMBER(vram_r); + DECLARE_WRITE32_MEMBER(vram_w); + +public: + dynamic_buffer m_vram; + UINT32 *m_vram32; + UINT32 m_mode, m_vbl_disable; + UINT32 m_palette_val[256], m_colors[3], m_count, m_clutoffs; + emu_timer *m_timer; + std::string m_assembled_tag; + +private: + UINT32 m_7xxxxx_regs[0x100000/4]; + int m_width, m_height, m_patofsx, m_patofsy; + UINT32 m_vram_addr, m_vram_src; + UINT8 m_fillbytes[256]; + required_device m_palette; +}; + + +// device type definition +extern const device_type NUBUS_SPECPDQ; + +#endif /* __NUBUS_SPECPDQ_H__ */ diff --git a/src/devices/bus/nubus/nubus_vikbw.c b/src/devices/bus/nubus/nubus_vikbw.c new file mode 100644 index 00000000000..52e30c0ca92 --- /dev/null +++ b/src/devices/bus/nubus/nubus_vikbw.c @@ -0,0 +1,174 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/*************************************************************************** + + Viking 1024x768 fixed-resolution monochrome board + + VRAM from Fs040000 to Fs0517FF + Read from Fs000000 enables VBL, write to Fs000000 disables VBL + Write to Fs080000 acks VBL + +***************************************************************************/ + +#include "emu.h" +#include "nubus_vikbw.h" + +#define VIKBW_SCREEN_NAME "vikbw_screen" +#define VIKBW_ROM_REGION "vikbw_rom" + +#define VRAM_SIZE (0x18000) // 1024x768 @ 1bpp is 98,304 bytes (0x18000) + +MACHINE_CONFIG_FRAGMENT( vikbw ) + MCFG_SCREEN_ADD( VIKBW_SCREEN_NAME, RASTER) + MCFG_SCREEN_UPDATE_DEVICE(DEVICE_SELF, nubus_vikbw_device, screen_update) + MCFG_SCREEN_SIZE(1024,768) + MCFG_SCREEN_VISIBLE_AREA(0, 1024-1, 0, 768-1) + MCFG_SCREEN_REFRESH_RATE(70) +MACHINE_CONFIG_END + +ROM_START( vikbw ) + ROM_REGION(0x2000, VIKBW_ROM_REGION, 0) + ROM_LOAD( "viking.bin", 0x000000, 0x002000, CRC(92cf04d1) SHA1(d08349edfc82a0bd5ea848e053e1712092308f74) ) +ROM_END + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type NUBUS_VIKBW = &device_creator; + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor nubus_vikbw_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( vikbw ); +} + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *nubus_vikbw_device::device_rom_region() const +{ + return ROM_NAME( vikbw ); +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// nubus_vikbw_device - constructor +//------------------------------------------------- + +nubus_vikbw_device::nubus_vikbw_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, NUBUS_VIKBW, "Moniterm Viking video card", tag, owner, clock, "nb_vikbw", __FILE__), + device_nubus_card_interface(mconfig, *this) +{ +} + +nubus_vikbw_device::nubus_vikbw_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_nubus_card_interface(mconfig, *this) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void nubus_vikbw_device::device_start() +{ + UINT32 slotspace; + + // set_nubus_device makes m_slot valid + set_nubus_device(); + install_declaration_rom(this, VIKBW_ROM_REGION, true); + + slotspace = get_slotspace(); + +// printf("[vikbw %p] slotspace = %x\n", this, slotspace); + + m_vram.resize(VRAM_SIZE); + install_bank(slotspace+0x40000, slotspace+0x40000+VRAM_SIZE-1, 0, 0, "bank_vikbw", &m_vram[0]); + install_bank(slotspace+0x940000, slotspace+0x940000+VRAM_SIZE-1, 0, 0, "bank_vikbw2", &m_vram[0]); + + m_nubus->install_device(slotspace, slotspace+3, read32_delegate(FUNC(nubus_vikbw_device::viking_enable_r), this), write32_delegate(FUNC(nubus_vikbw_device::viking_disable_w), this)); + m_nubus->install_device(slotspace+0x80000, slotspace+0x80000+3, read32_delegate(FUNC(nubus_vikbw_device::viking_ack_r), this), write32_delegate(FUNC(nubus_vikbw_device::viking_ack_w), this)); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void nubus_vikbw_device::device_reset() +{ + m_vbl_disable = 1; + memset(&m_vram[0], 0, VRAM_SIZE); + + m_palette[0] = rgb_t(255, 255, 255); + m_palette[1] = rgb_t(0, 0, 0); +} + +/*************************************************************************** + + Viking 1024x768 B&W card section + +***************************************************************************/ + +UINT32 nubus_vikbw_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + UINT32 *scanline; + int x, y; + UINT8 pixels; + + if (!m_vbl_disable) + { + raise_slot_irq(); + } + + for (y = 0; y < 768; y++) + { + scanline = &bitmap.pix32(y); + for (x = 0; x < 1024/8; x++) + { + pixels = m_vram[(y * 128) + (BYTE4_XOR_BE(x))]; + + *scanline++ = m_palette[(pixels>>7)&1]; + *scanline++ = m_palette[(pixels>>6)&1]; + *scanline++ = m_palette[(pixels>>5)&1]; + *scanline++ = m_palette[(pixels>>4)&1]; + *scanline++ = m_palette[(pixels>>3)&1]; + *scanline++ = m_palette[(pixels>>2)&1]; + *scanline++ = m_palette[(pixels>>1)&1]; + *scanline++ = m_palette[(pixels&1)]; + } + } + + return 0; +} + +WRITE32_MEMBER( nubus_vikbw_device::viking_ack_w ) +{ + lower_slot_irq(); +} + +READ32_MEMBER( nubus_vikbw_device::viking_ack_r ) +{ + return 0; +} + +WRITE32_MEMBER( nubus_vikbw_device::viking_disable_w ) +{ + m_vbl_disable = 1; +} + +READ32_MEMBER( nubus_vikbw_device::viking_enable_r ) +{ + m_vbl_disable = 0; + return 0; +} diff --git a/src/devices/bus/nubus/nubus_vikbw.h b/src/devices/bus/nubus/nubus_vikbw.h new file mode 100644 index 00000000000..8ddc5aaf50f --- /dev/null +++ b/src/devices/bus/nubus/nubus_vikbw.h @@ -0,0 +1,50 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +#pragma once + +#ifndef __NUBUS_VIKBW_H__ +#define __NUBUS_VIKBW_H__ + +#include "emu.h" +#include "nubus.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> nubus_vikbw_device + +class nubus_vikbw_device : + public device_t, + public device_nubus_card_interface +{ +public: + // construction/destruction + nubus_vikbw_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + nubus_vikbw_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual const rom_entry *device_rom_region() const; + + UINT32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + DECLARE_READ32_MEMBER(viking_ack_r); + DECLARE_WRITE32_MEMBER(viking_ack_w); + DECLARE_READ32_MEMBER(viking_enable_r); + DECLARE_WRITE32_MEMBER(viking_disable_w); + +public: + dynamic_buffer m_vram; + UINT32 m_vbl_disable, m_palette[2]; +}; + + +// device type definition +extern const device_type NUBUS_VIKBW; + +#endif /* __NUBUS_VIKBW_H__ */ diff --git a/src/devices/bus/nubus/nubus_wsportrait.c b/src/devices/bus/nubus/nubus_wsportrait.c new file mode 100644 index 00000000000..3f00160ba40 --- /dev/null +++ b/src/devices/bus/nubus/nubus_wsportrait.c @@ -0,0 +1,310 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/*************************************************************************** + + Apple model 820-5037-C "Macintosh II Portrait Video Card" + PCB is marked "Workstation/Portrait Card" + 640x870, 1, 2 or 4bpp grayscale + + Fs0900e0 = DAC control + Fs0900e4 = DAC data + Fs0A0000 = enable / ack VBL IRQ + Fs0A0004 = disable VBL IRQ + +***************************************************************************/ + +#include "emu.h" +#include "nubus_wsportrait.h" + +#define WSPORTRAIT_SCREEN_NAME "wsport_screen" +#define WSPORTRAIT_ROM_REGION "wsport_rom" + +#define VRAM_SIZE (0x80000) // 512k max + +MACHINE_CONFIG_FRAGMENT( wsportrait ) + MCFG_SCREEN_ADD( WSPORTRAIT_SCREEN_NAME, RASTER) + MCFG_SCREEN_UPDATE_DEVICE(DEVICE_SELF, nubus_wsportrait_device, screen_update) + MCFG_SCREEN_SIZE(1024,960) + MCFG_SCREEN_REFRESH_RATE(75.0) + MCFG_SCREEN_VISIBLE_AREA(0, 640-1, 0, 870-1) +MACHINE_CONFIG_END + +ROM_START( wsportrait ) + ROM_REGION(0x1000, WSPORTRAIT_ROM_REGION, 0) + ROM_LOAD( "341-0732.bin", 0x000000, 0x001000, CRC(ddc35b78) SHA1(ce2bf2374bb994c17962dba8f3d11bc1260e2644) ) +ROM_END + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type NUBUS_WSPORTRAIT = &device_creator; + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor nubus_wsportrait_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( wsportrait ); +} + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *nubus_wsportrait_device::device_rom_region() const +{ + return ROM_NAME( wsportrait ); +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// nubus_wsportrait_device - constructor +//------------------------------------------------- + +nubus_wsportrait_device::nubus_wsportrait_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, NUBUS_WSPORTRAIT, "Macintosh II Portrait Video Card", tag, owner, clock, "nb_wspt", __FILE__), + device_video_interface(mconfig, *this), + device_nubus_card_interface(mconfig, *this) +{ + m_assembled_tag = std::string(tag).append(":").append(WSPORTRAIT_SCREEN_NAME); + m_screen_tag = m_assembled_tag.c_str(); +} + +nubus_wsportrait_device::nubus_wsportrait_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_video_interface(mconfig, *this), + device_nubus_card_interface(mconfig, *this) +{ + m_assembled_tag = std::string(tag).append(":").append(WSPORTRAIT_SCREEN_NAME); + m_screen_tag = m_assembled_tag.c_str(); +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void nubus_wsportrait_device::device_start() +{ + UINT32 slotspace; + + // set_nubus_device makes m_slot valid + set_nubus_device(); + install_declaration_rom(this, WSPORTRAIT_ROM_REGION, true); + + slotspace = get_slotspace(); + + printf("[wsportrait %p] slotspace = %x\n", (void *)this, slotspace); + + m_vram.resize(VRAM_SIZE); + m_vram32 = (UINT32 *)&m_vram[0]; + + m_nubus->install_device(slotspace, slotspace+VRAM_SIZE-1, read32_delegate(FUNC(nubus_wsportrait_device::vram_r), this), write32_delegate(FUNC(nubus_wsportrait_device::vram_w), this)); + m_nubus->install_device(slotspace+0x900000, slotspace+0x900000+VRAM_SIZE-1, read32_delegate(FUNC(nubus_wsportrait_device::vram_r), this), write32_delegate(FUNC(nubus_wsportrait_device::vram_w), this)); + m_nubus->install_device(slotspace+0x80000, slotspace+0xeffff, read32_delegate(FUNC(nubus_wsportrait_device::wsportrait_r), this), write32_delegate(FUNC(nubus_wsportrait_device::wsportrait_w), this)); + + m_timer = timer_alloc(0, NULL); + m_timer->adjust(m_screen->time_until_pos(869, 0), 0); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void nubus_wsportrait_device::device_reset() +{ + m_count = 0; + m_clutoffs = 0; + m_vbl_disable = 1; + m_mode = 0; + memset(&m_vram[0], 0, VRAM_SIZE); + memset(m_palette, 0, sizeof(m_palette)); +} + + +void nubus_wsportrait_device::device_timer(emu_timer &timer, device_timer_id tid, int param, void *ptr) +{ + if (!m_vbl_disable) + { + raise_slot_irq(); + } + + m_timer->adjust(m_screen->time_until_pos(869, 0), 0); +} + +/*************************************************************************** + + Workstation/Portrait emulation + +***************************************************************************/ + +UINT32 nubus_wsportrait_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + UINT32 *scanline; + int x, y; + UINT8 pixels, *vram; + + // first time? kick off the VBL timer + vram = &m_vram[0x80]; + + switch (m_mode) + { + case 0: // 1 bpp? + for (y = 0; y < 870; y++) + { + scanline = &bitmap.pix32(y); + for (x = 0; x < 640/8; x++) + { + pixels = vram[(y * 128) + (BYTE4_XOR_BE(x))]; + + *scanline++ = m_palette[((pixels>>7)&0x1)]; + *scanline++ = m_palette[((pixels>>6)&0x1)]; + *scanline++ = m_palette[((pixels>>5)&0x1)]; + *scanline++ = m_palette[((pixels>>4)&0x1)]; + *scanline++ = m_palette[((pixels>>3)&0x1)]; + *scanline++ = m_palette[((pixels>>2)&0x1)]; + *scanline++ = m_palette[((pixels>>1)&0x1)]; + *scanline++ = m_palette[(pixels&1)]; + } + } + break; + + case 1: // 2 bpp + for (y = 0; y < 480; y++) + { + scanline = &bitmap.pix32(y); + for (x = 0; x < 640/4; x++) + { + pixels = vram[(y * 256) + (BYTE4_XOR_BE(x))]; + + *scanline++ = m_palette[((pixels>>6)&3)]; + *scanline++ = m_palette[((pixels>>4)&3)]; + *scanline++ = m_palette[((pixels>>2)&3)]; + *scanline++ = m_palette[(pixels&3)]; + } + } + break; + + case 2: // 4 bpp + for (y = 0; y < 480; y++) + { + scanline = &bitmap.pix32(y); + + for (x = 0; x < 640/2; x++) + { + pixels = vram[(y * 512) + (BYTE4_XOR_BE(x))]; + + *scanline++ = m_palette[((pixels&0xf0)>>4)]; + *scanline++ = m_palette[(pixels&0xf)]; + } + } + break; + + default: + fatalerror("wsportrait: unknown video mode %d\n", m_mode); + } + return 0; +} + +WRITE32_MEMBER( nubus_wsportrait_device::wsportrait_w ) +{ + data ^= 0xffffffff; +// if (offset != 0x8000) printf("wsportrait: Write %08x @ %x, mask %08x\n", data, offset, mem_mask); + + switch (offset) + { + case 1: // mode control +// printf("%08x to mode 1\n", data); + switch (data & 0xff000000) + { + case 0x20000000: + case 0x24000000: + m_mode = 0; + break; + + case 0x40000000: + m_mode = 1; + break; + + case 0x50000000: + case 0x80000000: + m_mode = 2; + break; + } + break; + + case 0x4038: // DAC control + m_clutoffs = (data>>24)&0xff; + break; + + case 0x4039: // DAC data - only 4 bits per component! + m_colors[m_count] = (data>>24) & 0x0f; + m_colors[m_count] |= (m_colors[m_count]<<4); + m_count++; + + if (m_count == 3) + { +// printf("RAMDAC: color %d = %02x %02x %02x (PC=%x)\n", m_clutoffs, m_colors[0], m_colors[1], m_colors[2], space.device().safe_pc() ); + m_palette[m_clutoffs] = rgb_t(m_colors[2], m_colors[2], m_colors[2]); + m_clutoffs++; + if (m_clutoffs > 255) + { + m_clutoffs = 0; + } + m_count = 0; + } + break; + + case 0x8000: + lower_slot_irq(); + m_vbl_disable = false; + break; + + case 0x8001: + m_vbl_disable = true; + break; + } +} + +READ32_MEMBER( nubus_wsportrait_device::wsportrait_r ) +{ +// printf("wsportrait: Read @ %x, mask %08x\n", offset, mem_mask); + + /* + monitor types + + 0x0 = invalid + 0x2 = invalid + 0x4 = color: 640x870 1bpp, 640x480 2bpp and 4bpp + 0x6 = 1bpp 640x384? and sets weird mode controls + 0x8 = really odd (bitplaned?) + 0xa = invalid + 0xc = 640x480 grayscale + 0xe = same as 0x6 + */ + + switch (offset) + { + case 0x4004: + m_toggle ^= 0x00010000; + return m_toggle | 0xfffc0000; // bit 0 = vbl status, bits 1-3 = monitor type + } + return 0; +} + +WRITE32_MEMBER( nubus_wsportrait_device::vram_w ) +{ + data ^= 0xffffffff; + COMBINE_DATA(&m_vram32[offset]); +} + +READ32_MEMBER( nubus_wsportrait_device::vram_r ) +{ + return m_vram32[offset] ^ 0xffffffff; +} diff --git a/src/devices/bus/nubus/nubus_wsportrait.h b/src/devices/bus/nubus/nubus_wsportrait.h new file mode 100644 index 00000000000..a677daea6cc --- /dev/null +++ b/src/devices/bus/nubus/nubus_wsportrait.h @@ -0,0 +1,56 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +#pragma once + +#ifndef __NUBUS_WSPORTRAIT_H__ +#define __NUBUS_WSPORTRAIT_H__ + +#include "emu.h" +#include "nubus.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> nubus_wsportrait_device + +class nubus_wsportrait_device : + public device_t, + public device_video_interface, + public device_nubus_card_interface +{ +public: + // construction/destruction + nubus_wsportrait_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + nubus_wsportrait_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual const rom_entry *device_rom_region() const; + + UINT32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + DECLARE_READ32_MEMBER(wsportrait_r); + DECLARE_WRITE32_MEMBER(wsportrait_w); + DECLARE_READ32_MEMBER(vram_r); + DECLARE_WRITE32_MEMBER(vram_w); + +public: + dynamic_buffer m_vram; + UINT32 *m_vram32; + UINT32 m_mode, m_vbl_disable, m_toggle; + UINT32 m_palette[256], m_colors[3], m_count, m_clutoffs; + emu_timer *m_timer; + std::string m_assembled_tag; +}; + + +// device type definition +extern const device_type NUBUS_WSPORTRAIT; + +#endif /* __NUBUS_M2HIRES_H__ */ diff --git a/src/devices/bus/nubus/pds30_30hr.c b/src/devices/bus/nubus/pds30_30hr.c new file mode 100644 index 00000000000..1d1af85f5ba --- /dev/null +++ b/src/devices/bus/nubus/pds30_30hr.c @@ -0,0 +1,319 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/*************************************************************************** + + Micron/XCEED Technologies Color 30HR + + Fs800000 - Mode A + FsA00000 - Mode B + FsC00000 - RAMDAC write offset + FsC00004 - RAMDAC write data + FsC00008 - RAMDAC write mask + FsC0000C - RAMDAC read offset + +***************************************************************************/ + +#include "emu.h" +#include "pds30_30hr.h" + +#define XCEED30HR_SCREEN_NAME "x30hr_screen" +#define XCEED30HR_ROM_REGION "x30hr_rom" + +#define VRAM_SIZE (0x100000) // 1 MB VRAM - max mode is 1024x768 @ 8bpp + +MACHINE_CONFIG_FRAGMENT( xceed30hr ) + MCFG_SCREEN_ADD( XCEED30HR_SCREEN_NAME, RASTER) + MCFG_SCREEN_UPDATE_DEVICE(DEVICE_SELF, nubus_xceed30hr_device, screen_update) + MCFG_SCREEN_RAW_PARAMS(25175000, 800, 0, 640, 525, 0, 480) + MCFG_SCREEN_SIZE(1024,768) + MCFG_SCREEN_VISIBLE_AREA(0, 640-1, 0, 480-1) +MACHINE_CONFIG_END + +ROM_START( xceed30hr ) + ROM_REGION(0x8000, XCEED30HR_ROM_REGION, 0) + ROM_LOAD( "369c.rom", 0x000000, 0x008000, CRC(b22f0a89) SHA1(be34c8604b8a1ae9c9f3b0b90faba9a1a64a5855) ) +ROM_END + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type PDS030_XCEED30HR = &device_creator; + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor nubus_xceed30hr_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( xceed30hr ); +} + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *nubus_xceed30hr_device::device_rom_region() const +{ + return ROM_NAME( xceed30hr ); +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// nubus_xceed30hr_device - constructor +//------------------------------------------------- + +nubus_xceed30hr_device::nubus_xceed30hr_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, PDS030_XCEED30HR, "Micron/XCEED Technology Color 30HR", tag, owner, clock, "pd3_30hr", __FILE__), + device_video_interface(mconfig, *this), + device_nubus_card_interface(mconfig, *this) +{ + m_assembled_tag = std::string(tag).append(":").append(XCEED30HR_SCREEN_NAME); + m_screen_tag = m_assembled_tag.c_str(); +} + +nubus_xceed30hr_device::nubus_xceed30hr_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_video_interface(mconfig, *this), + device_nubus_card_interface(mconfig, *this) +{ + m_assembled_tag = std::string(tag).append(":").append(XCEED30HR_SCREEN_NAME); + m_screen_tag = m_assembled_tag.c_str(); +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void nubus_xceed30hr_device::device_start() +{ + UINT32 slotspace; + + // set_nubus_device makes m_slot valid + set_nubus_device(); + install_declaration_rom(this, XCEED30HR_ROM_REGION); + + slotspace = get_slotspace(); + +// printf("[xceed30hr %p] slotspace = %x\n", this, slotspace); + + m_vram.resize(VRAM_SIZE); + m_vram32 = (UINT32 *)&m_vram[0]; + + m_nubus->install_device(slotspace, slotspace+VRAM_SIZE-1, read32_delegate(FUNC(nubus_xceed30hr_device::vram_r), this), write32_delegate(FUNC(nubus_xceed30hr_device::vram_w), this)); + m_nubus->install_device(slotspace+0x800000, slotspace+0xefffff, read32_delegate(FUNC(nubus_xceed30hr_device::xceed30hr_r), this), write32_delegate(FUNC(nubus_xceed30hr_device::xceed30hr_w), this)); + + m_timer = timer_alloc(0, NULL); + m_timer->adjust(m_screen->time_until_pos(479, 0), 0); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void nubus_xceed30hr_device::device_reset() +{ + m_count = 0; + m_clutoffs = 0; + m_vbl_disable = 1; + m_mode = 0; + memset(&m_vram[0], 0, VRAM_SIZE); + memset(m_palette, 0, sizeof(m_palette)); + + m_palette[0] = rgb_t(255, 255, 255); + m_palette[0x80] = rgb_t(0, 0, 0); +} + + +void nubus_xceed30hr_device::device_timer(emu_timer &timer, device_timer_id tid, int param, void *ptr) +{ + if (!m_vbl_disable) + { + raise_slot_irq(); + } + + m_timer->adjust(m_screen->time_until_pos(479, 0), 0); +} + +/*************************************************************************** + + CB264 section + +***************************************************************************/ + +UINT32 nubus_xceed30hr_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + UINT32 *scanline; + int x, y; + UINT8 pixels, *vram; + + vram = &m_vram[1024]; + + switch (m_mode) + { + case 0: // 1 bpp? + for (y = 0; y < 480; y++) + { + scanline = &bitmap.pix32(y); + for (x = 0; x < 640/8; x++) + { + pixels = vram[(y * 1024) + (BYTE4_XOR_BE(x))]; + + *scanline++ = m_palette[(pixels>>7)&1]; + *scanline++ = m_palette[(pixels>>6)&1]; + *scanline++ = m_palette[(pixels>>5)&1]; + *scanline++ = m_palette[(pixels>>4)&1]; + *scanline++ = m_palette[(pixels>>3)&1]; + *scanline++ = m_palette[(pixels>>2)&1]; + *scanline++ = m_palette[(pixels>>1)&1]; + *scanline++ = m_palette[pixels&1]; + } + } + break; + + case 1: // 2 bpp + for (y = 0; y < 480; y++) + { + scanline = &bitmap.pix32(y); + for (x = 0; x < 640/4; x++) + { + pixels = vram[(y * 1024) + (BYTE4_XOR_BE(x))]; + + *scanline++ = m_palette[((pixels>>6)&3)]; + *scanline++ = m_palette[((pixels>>4)&3)]; + *scanline++ = m_palette[((pixels>>2)&3)]; + *scanline++ = m_palette[(pixels&3)]; + } + } + break; + + case 2: // 4 bpp + for (y = 0; y < 480; y++) + { + scanline = &bitmap.pix32(y); + + for (x = 0; x < 640/2; x++) + { + pixels = vram[(y * 1024) + (BYTE4_XOR_BE(x))]; + + *scanline++ = m_palette[(pixels>>4)]; + *scanline++ = m_palette[(pixels&0xf)]; + } + } + break; + + case 3: // 8 bpp + for (y = 0; y < 480; y++) + { + scanline = &bitmap.pix32(y); + + for (x = 0; x < 640; x++) + { + pixels = vram[(y * 1024) + (BYTE4_XOR_BE(x))]; + *scanline++ = m_palette[pixels]; + } + } + break; + + default: + fatalerror("xceed30hr: unknown video mode %d\n", m_mode); + } + return 0; +} + +WRITE32_MEMBER( nubus_xceed30hr_device::xceed30hr_w ) +{ + switch (offset) + { + case 0x80000: // mode + switch (data & 0xff000000) + { + case 0xfc000000: + m_mode = 0; + break; + + case 0xfd000000: + m_mode = 1; + break; + + case 0xfe000000: + m_mode = 2; + break; + + case 0xff000000: + m_mode = 3; + break; + } + break; + + case 0x80005: // ack VBL + lower_slot_irq(); + break; + + case 0x100000: +// printf("%08x to DAC control (PC=%x)\n", data, space.device().safe_pc()); + m_clutoffs = (data&0xff); + m_count = 0; + break; + + case 0x100001: +// printf("%08x to DAC data (PC=%x)\n", data, space.device().safe_pc()); + m_colors[m_count++] = (data & 0xff); + + if (m_count == 3) + { +// printf("RAMDAC: color %02x = %02x %02x %02x (PC=%x)\n", m_clutoffs, m_colors[0], m_colors[1], m_colors[2], space.device().safe_pc() ); + m_palette[m_clutoffs] = rgb_t(m_colors[0], m_colors[1], m_colors[2]); + m_clutoffs++; + if (m_clutoffs > 255) + { + m_clutoffs = 0; + } + m_count = 0; + } + break; + + case 0x100002: // VBL control + if (data & 0x06000000) + { + m_vbl_disable = 0; + lower_slot_irq(); + } + else + { + m_vbl_disable = 1; + } + break; + + default: +// printf("xceed30hr_w: %08x @ %x, mask %08x (PC=%x)\n", data, offset, mem_mask, space.device().safe_pc()); + break; + } +} + +READ32_MEMBER( nubus_xceed30hr_device::xceed30hr_r ) +{ +// printf("xceed30hr_r: @ %x, mask %08x [PC=%x]\n", offset, mem_mask, machine().device("maincpu")->safe_pc()); + if (offset == 0x80008) + { + m_toggle ^= 0x80; + return m_toggle; + } + + return 0; +} + +WRITE32_MEMBER( nubus_xceed30hr_device::vram_w ) +{ + COMBINE_DATA(&m_vram32[offset]); +} + +READ32_MEMBER( nubus_xceed30hr_device::vram_r ) +{ + return m_vram32[offset]; +} diff --git a/src/devices/bus/nubus/pds30_30hr.h b/src/devices/bus/nubus/pds30_30hr.h new file mode 100644 index 00000000000..9366a555285 --- /dev/null +++ b/src/devices/bus/nubus/pds30_30hr.h @@ -0,0 +1,56 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +#pragma once + +#ifndef __NUBUS_XCEED30HR_H__ +#define __NUBUS_XCEED30HR_H__ + +#include "emu.h" +#include "nubus.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> nubus_xceed30hr_device + +class nubus_xceed30hr_device : + public device_t, + public device_video_interface, + public device_nubus_card_interface +{ +public: + // construction/destruction + nubus_xceed30hr_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + nubus_xceed30hr_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual const rom_entry *device_rom_region() const; + + UINT32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + DECLARE_READ32_MEMBER(xceed30hr_r); + DECLARE_WRITE32_MEMBER(xceed30hr_w); + DECLARE_READ32_MEMBER(vram_r); + DECLARE_WRITE32_MEMBER(vram_w); + +public: + dynamic_buffer m_vram; + UINT32 *m_vram32; + UINT32 m_mode, m_vbl_disable, m_toggle; + UINT32 m_palette[256], m_colors[3], m_count, m_clutoffs; + emu_timer *m_timer; + std::string m_assembled_tag; +}; + + +// device type definition +extern const device_type PDS030_XCEED30HR; + +#endif /* __NUBUS_XCEED30HR_H__ */ diff --git a/src/devices/bus/nubus/pds30_cb264.c b/src/devices/bus/nubus/pds30_cb264.c new file mode 100644 index 00000000000..21eafd10935 --- /dev/null +++ b/src/devices/bus/nubus/pds30_cb264.c @@ -0,0 +1,324 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/*************************************************************************** + + RasterOps ColorBoard 264/SE30 video card emulation + +***************************************************************************/ + +#include "emu.h" +#include "pds30_cb264.h" + +#define CB264SE30_SCREEN_NAME "cb264_screen" +#define CB264SE30_ROM_REGION "cb264_rom" + +#define VRAM_SIZE (0x200000) + +MACHINE_CONFIG_FRAGMENT( cb264se30 ) + MCFG_SCREEN_ADD( CB264SE30_SCREEN_NAME, RASTER) + MCFG_SCREEN_UPDATE_DEVICE(DEVICE_SELF, nubus_cb264se30_device, screen_update) + MCFG_SCREEN_RAW_PARAMS(25175000, 800, 0, 640, 525, 0, 480) + MCFG_SCREEN_SIZE(1024,768) + MCFG_SCREEN_VISIBLE_AREA(0, 640-1, 0, 480-1) +MACHINE_CONFIG_END + +ROM_START( cb264se30 ) + ROM_REGION(0x8000, CB264SE30_ROM_REGION, 0) + ROM_LOAD( "0002-2019_10-02-90.bin", 0x000000, 0x008000, CRC(5b5b2fab) SHA1(0584deb38b402718f2abef456b0035b34fddb473) ) // EPROM label "264/30 V1.3 0002-2019 10/02/90" +ROM_END + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type PDS030_CB264SE30 = &device_creator; + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor nubus_cb264se30_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( cb264se30 ); +} + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *nubus_cb264se30_device::device_rom_region() const +{ + return ROM_NAME( cb264se30 ); +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// nubus_cb264se30_device - constructor +//------------------------------------------------- + +nubus_cb264se30_device::nubus_cb264se30_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, PDS030_CB264SE30, "RasterOps Colorboard 264/SE30", tag, owner, clock, "pd3_c264", __FILE__), + device_video_interface(mconfig, *this), + device_nubus_card_interface(mconfig, *this) +{ + m_assembled_tag = std::string(tag).append(":").append(CB264SE30_SCREEN_NAME); + m_screen_tag = m_assembled_tag.c_str(); +} + +nubus_cb264se30_device::nubus_cb264se30_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_video_interface(mconfig, *this), + device_nubus_card_interface(mconfig, *this) +{ + m_assembled_tag = std::string(tag).append(":").append(CB264SE30_SCREEN_NAME); + m_screen_tag = m_assembled_tag.c_str(); +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void nubus_cb264se30_device::device_start() +{ + UINT32 slotspace; + + // set_nubus_device makes m_slot valid + set_nubus_device(); + install_declaration_rom(this, CB264SE30_ROM_REGION); + + slotspace = get_slotspace(); + +// printf("[cb264se30 %p] slotspace = %x\n", this, slotspace); + + m_vram.resize(VRAM_SIZE); + m_vram32 = (UINT32 *)&m_vram[0]; + + m_nubus->install_device(slotspace, slotspace+VRAM_SIZE-1, read32_delegate(FUNC(nubus_cb264se30_device::vram_r), this), write32_delegate(FUNC(nubus_cb264se30_device::vram_w), this)); + m_nubus->install_device(slotspace+0xf00000, slotspace+0xfeffff, read32_delegate(FUNC(nubus_cb264se30_device::cb264se30_r), this), write32_delegate(FUNC(nubus_cb264se30_device::cb264se30_w), this)); + + m_timer = timer_alloc(0, NULL); + m_timer->adjust(m_screen->time_until_pos(479, 0), 0); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void nubus_cb264se30_device::device_reset() +{ + m_count = 0; + m_clutoffs = 0; + m_vbl_disable = 1; + m_mode = 4; + memset(&m_vram[0], 0, VRAM_SIZE); + memset(m_palette, 0, sizeof(m_palette)); + + m_palette[0] = rgb_t(255, 255, 255); + m_palette[0x80] = rgb_t(0, 0, 0); +} + + +void nubus_cb264se30_device::device_timer(emu_timer &timer, device_timer_id tid, int param, void *ptr) +{ + if (!m_vbl_disable) + { + raise_slot_irq(); + } + + m_timer->adjust(m_screen->time_until_pos(479, 0), 0); +} + +/*************************************************************************** + + CB264 section + +***************************************************************************/ + +UINT32 nubus_cb264se30_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + UINT32 *scanline; + int x, y; + UINT8 pixels, *vram; + + vram = &m_vram[8*1024]; + + switch (m_mode) + { + case 0: // 1 bpp? + for (y = 0; y < 480; y++) + { + scanline = &bitmap.pix32(y); + for (x = 0; x < 640/8; x++) + { + pixels = vram[(y * 1024) + (BYTE4_XOR_BE(x))]; + + *scanline++ = m_palette[(pixels&0x80)]; + *scanline++ = m_palette[((pixels<<1)&0x80)]; + *scanline++ = m_palette[((pixels<<2)&0x80)]; + *scanline++ = m_palette[((pixels<<3)&0x80)]; + *scanline++ = m_palette[((pixels<<4)&0x80)]; + *scanline++ = m_palette[((pixels<<5)&0x80)]; + *scanline++ = m_palette[((pixels<<6)&0x80)]; + *scanline++ = m_palette[((pixels<<7)&0x80)]; + } + } + break; + + case 1: // 2 bpp + for (y = 0; y < 480; y++) + { + scanline = &bitmap.pix32(y); + for (x = 0; x < 640/4; x++) + { + pixels = vram[(y * 1024) + (BYTE4_XOR_BE(x))]; + + *scanline++ = m_palette[(pixels&0xc0)]; + *scanline++ = m_palette[((pixels<<2)&0xc0)]; + *scanline++ = m_palette[((pixels<<4)&0xc0)]; + *scanline++ = m_palette[((pixels<<6)&0xc0)]; + } + } + break; + + case 2: // 4 bpp + for (y = 0; y < 480; y++) + { + scanline = &bitmap.pix32(y); + + for (x = 0; x < 640/2; x++) + { + pixels = vram[(y * 1024) + (BYTE4_XOR_BE(x))]; + + *scanline++ = m_palette[(pixels&0xf0)]; + *scanline++ = m_palette[((pixels&0x0f)<<4)]; + } + } + break; + + case 3: // 8 bpp + for (y = 0; y < 480; y++) + { + scanline = &bitmap.pix32(y); + + for (x = 0; x < 640; x++) + { + pixels = vram[(y * 1024) + (BYTE4_XOR_BE(x))]; + *scanline++ = m_palette[pixels]; + } + } + break; + + case 4: // 24 bpp + { + UINT32 *vram32 = (UINT32 *)&m_vram[0]; + UINT32 *base; + + for (y = 0; y < 480; y++) + { + scanline = &bitmap.pix32(y); + base = &vram32[y * 1024]; + for (x = 0; x < 640; x++) + { + *scanline++ = *base++; + } + } + } + break; + + default: + fatalerror("cb264se30: unknown video mode %d\n", m_mode); + } + return 0; +} + +WRITE32_MEMBER( nubus_cb264se30_device::cb264se30_w ) +{ + switch (offset) + { + case 0x38003: // mode +// if (data != 0x08000000) printf("%08x to mode\n", data); + switch (data & 0xff000000) + { + case 0x38000000: + m_mode = 0; + break; + + case 0x39000000: + m_mode = 1; + break; + + case 0x3a000000: + m_mode = 2; + break; + + case 0x3b000000: + m_mode = 3; + break; + + case 0x3f000000: + m_mode = 4; + break; + } + break; + + case 0x38000: + if (mem_mask == 0xff000000) + { + // printf("%08x to DAC control (PC=%x)\n", data, space.device().safe_pc()); + m_clutoffs = (data>>24)&0xff; + } + else if (mem_mask == 0x0000ff00) + { + m_colors[m_count++] = (data>>8) & 0xff; + + if (m_count == 3) + { +// printf("RAMDAC: color %02x = %02x %02x %02x (PC=%x)\n", m_clutoffs, m_colors[0], m_colors[1], m_colors[2], space.device().safe_pc() ); + m_palette[m_clutoffs] = rgb_t(m_colors[0], m_colors[1], m_colors[2]); + m_clutoffs++; + if (m_clutoffs > 255) + { + m_clutoffs = 0; + } + m_count = 0; + } + } + break; + + case 0x2c017: // VBL control + if (data & 0x06000000) + { + m_vbl_disable = 0; + lower_slot_irq(); + } + else + { + m_vbl_disable = 1; + } + break; + + default: +// printf("cb264se30_w: %08x @ %x, mask %08x (PC=%x)\n", data, offset, mem_mask, space.device().safe_pc()); + break; + } +} + +READ32_MEMBER( nubus_cb264se30_device::cb264se30_r ) +{ + return 0; +} + +WRITE32_MEMBER( nubus_cb264se30_device::vram_w ) +{ + COMBINE_DATA(&m_vram32[offset]); +} + +READ32_MEMBER( nubus_cb264se30_device::vram_r ) +{ + return m_vram32[offset]; +} diff --git a/src/devices/bus/nubus/pds30_cb264.h b/src/devices/bus/nubus/pds30_cb264.h new file mode 100644 index 00000000000..d1f7839ab45 --- /dev/null +++ b/src/devices/bus/nubus/pds30_cb264.h @@ -0,0 +1,56 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +#pragma once + +#ifndef __NUBUS_CB264SE30_H__ +#define __NUBUS_CB264SE30_H__ + +#include "emu.h" +#include "nubus.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> nubus_cb264se30_device + +class nubus_cb264se30_device : + public device_t, + public device_video_interface, + public device_nubus_card_interface +{ +public: + // construction/destruction + nubus_cb264se30_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + nubus_cb264se30_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual const rom_entry *device_rom_region() const; + + UINT32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + DECLARE_READ32_MEMBER(cb264se30_r); + DECLARE_WRITE32_MEMBER(cb264se30_w); + DECLARE_READ32_MEMBER(vram_r); + DECLARE_WRITE32_MEMBER(vram_w); + +public: + dynamic_buffer m_vram; + UINT32 *m_vram32; + UINT32 m_mode, m_vbl_disable, m_toggle; + UINT32 m_palette[256], m_colors[3], m_count, m_clutoffs; + emu_timer *m_timer; + std::string m_assembled_tag; +}; + + +// device type definition +extern const device_type PDS030_CB264SE30; + +#endif /* __NUBUS_CB264SE30_H__ */ diff --git a/src/devices/bus/nubus/pds30_mc30.c b/src/devices/bus/nubus/pds30_mc30.c new file mode 100644 index 00000000000..ddc063bbb8f --- /dev/null +++ b/src/devices/bus/nubus/pds30_mc30.c @@ -0,0 +1,336 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/*************************************************************************** + + Micron/XCEED Technologies MacroColor 30 + + Similar to the 30HR, but registers are rearranged and 24bpp support + was added. + +***************************************************************************/ + +#include "emu.h" +#include "pds30_mc30.h" + +#define XCEEDMC30_SCREEN_NAME "x30hr_screen" +#define XCEEDMC30_ROM_REGION "x30hr_rom" + +#define VRAM_SIZE (0x200000) // 16 42C4256 256Kx4 VRAMs on the board = 2MB + +MACHINE_CONFIG_FRAGMENT( xceedmc30 ) + MCFG_SCREEN_ADD( XCEEDMC30_SCREEN_NAME, RASTER) + MCFG_SCREEN_UPDATE_DEVICE(DEVICE_SELF, nubus_xceedmc30_device, screen_update) + MCFG_SCREEN_RAW_PARAMS(25175000, 800, 0, 640, 525, 0, 480) + MCFG_SCREEN_SIZE(1024,768) + MCFG_SCREEN_VISIBLE_AREA(0, 640-1, 0, 480-1) +MACHINE_CONFIG_END + +ROM_START( xceedmc30 ) + ROM_REGION(0x8000, XCEEDMC30_ROM_REGION, 0) + ROM_LOAD( "0390.bin", 0x000000, 0x008000, CRC(adea7a18) SHA1(9141eb1a0e5061e0409d65a89b4eaeb119ee4ffb) ) +ROM_END + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type PDS030_XCEEDMC30 = &device_creator; + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor nubus_xceedmc30_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( xceedmc30 ); +} + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *nubus_xceedmc30_device::device_rom_region() const +{ + return ROM_NAME( xceedmc30 ); +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// nubus_xceedmc30_device - constructor +//------------------------------------------------- + +nubus_xceedmc30_device::nubus_xceedmc30_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, PDS030_XCEEDMC30, "Micron/XCEED Technology MacroColor 30", tag, owner, clock, "pd3_mclr", __FILE__), + device_video_interface(mconfig, *this), + device_nubus_card_interface(mconfig, *this) +{ + m_assembled_tag = std::string(tag).append(":").append(XCEEDMC30_SCREEN_NAME); + m_screen_tag = m_assembled_tag.c_str(); +} + +nubus_xceedmc30_device::nubus_xceedmc30_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_video_interface(mconfig, *this), + device_nubus_card_interface(mconfig, *this) +{ + m_assembled_tag = std::string(tag).append(":").append(XCEEDMC30_SCREEN_NAME); + m_screen_tag = m_assembled_tag.c_str(); +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void nubus_xceedmc30_device::device_start() +{ + UINT32 slotspace; + + // set_nubus_device makes m_slot valid + set_nubus_device(); + install_declaration_rom(this, XCEEDMC30_ROM_REGION); + + slotspace = get_slotspace(); + +// printf("[xceedmc30 %p] slotspace = %x\n", this, slotspace); + + m_vram.resize(VRAM_SIZE); + m_vram32 = (UINT32 *)&m_vram[0]; + + m_nubus->install_device(slotspace, slotspace+VRAM_SIZE-1, read32_delegate(FUNC(nubus_xceedmc30_device::vram_r), this), write32_delegate(FUNC(nubus_xceedmc30_device::vram_w), this)); + m_nubus->install_device(slotspace+0x800000, slotspace+0xefffff, read32_delegate(FUNC(nubus_xceedmc30_device::xceedmc30_r), this), write32_delegate(FUNC(nubus_xceedmc30_device::xceedmc30_w), this)); + + m_timer = timer_alloc(0, NULL); + m_timer->adjust(m_screen->time_until_pos(479, 0), 0); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void nubus_xceedmc30_device::device_reset() +{ + m_count = 0; + m_clutoffs = 0; + m_vbl_disable = 1; + m_mode = 0; + memset(&m_vram[0], 0, VRAM_SIZE); + memset(m_palette, 0, sizeof(m_palette)); + + m_palette[0] = rgb_t(255, 255, 255); + m_palette[0x80] = rgb_t(0, 0, 0); +} + + +void nubus_xceedmc30_device::device_timer(emu_timer &timer, device_timer_id tid, int param, void *ptr) +{ + if (!m_vbl_disable) + { + raise_slot_irq(); + } + + m_timer->adjust(m_screen->time_until_pos(479, 0), 0); +} + +/*************************************************************************** + + CB264 section + +***************************************************************************/ + +UINT32 nubus_xceedmc30_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + UINT32 *scanline; + int x, y; + UINT8 pixels, *vram; + + vram = &m_vram[4*1024]; + + switch (m_mode) + { + case 0: // 1 bpp? + for (y = 0; y < 480; y++) + { + scanline = &bitmap.pix32(y); + for (x = 0; x < 640/8; x++) + { + pixels = vram[(y * 1024) + (BYTE4_XOR_BE(x))]; + + *scanline++ = m_palette[(pixels>>7)&1]; + *scanline++ = m_palette[(pixels>>6)&1]; + *scanline++ = m_palette[(pixels>>5)&1]; + *scanline++ = m_palette[(pixels>>4)&1]; + *scanline++ = m_palette[(pixels>>3)&1]; + *scanline++ = m_palette[(pixels>>2)&1]; + *scanline++ = m_palette[(pixels>>1)&1]; + *scanline++ = m_palette[pixels&1]; + } + } + break; + + case 1: // 2 bpp + for (y = 0; y < 480; y++) + { + scanline = &bitmap.pix32(y); + for (x = 0; x < 640/4; x++) + { + pixels = vram[(y * 1024) + (BYTE4_XOR_BE(x))]; + + *scanline++ = m_palette[((pixels>>6)&3)]; + *scanline++ = m_palette[((pixels>>4)&3)]; + *scanline++ = m_palette[((pixels>>2)&3)]; + *scanline++ = m_palette[(pixels&3)]; + } + } + break; + + case 2: // 4 bpp + for (y = 0; y < 480; y++) + { + scanline = &bitmap.pix32(y); + + for (x = 0; x < 640/2; x++) + { + pixels = vram[(y * 1024) + (BYTE4_XOR_BE(x))]; + + *scanline++ = m_palette[(pixels>>4)]; + *scanline++ = m_palette[(pixels&0xf)]; + } + } + break; + + case 3: // 8 bpp + for (y = 0; y < 480; y++) + { + scanline = &bitmap.pix32(y); + + for (x = 0; x < 640; x++) + { + pixels = vram[(y * 1024) + (BYTE4_XOR_BE(x))]; + *scanline++ = m_palette[pixels]; + } + } + break; + + case 4: // 24 bpp + { + UINT32 *vram32 = (UINT32 *)vram; + UINT32 *base; + + for (y = 0; y < 480; y++) + { + scanline = &bitmap.pix32(y); + base = &vram32[y * 1024]; + for (x = 0; x < 640; x++) + { + *scanline++ = *base++; + } + } + } + break; + + default: + fatalerror("xceedmc30: unknown video mode %d\n", m_mode); + } + return 0; +} + +WRITE32_MEMBER( nubus_xceedmc30_device::xceedmc30_w ) +{ + switch (offset) + { + case 0x80000: // mode + switch (data & 0xff000000) + { + case 0xfb000000: + m_mode = 0; + break; + + case 0xfa000000: + m_mode = 1; + break; + + case 0xf9000000: + m_mode = 2; + break; + + case 0xf8000000: + m_mode = 3; + break; + + case 0xff000000: + m_mode = 4; + break; + } + break; + + case 0x80005: // ack VBL + lower_slot_irq(); + break; + + case 0x100000: +// printf("%08x to DAC control (PC=%x)\n", data, space.device().safe_pc()); + m_clutoffs = (data&0xff); + m_count = 0; + break; + + case 0x100001: +// printf("%08x to DAC data (PC=%x)\n", data, space.device().safe_pc()); + m_colors[m_count++] = ((data>>24) & 0xff); + + if (m_count == 3) + { +// printf("RAMDAC: color %02x = %02x %02x %02x (PC=%x)\n", m_clutoffs, m_colors[0], m_colors[1], m_colors[2], space.device().safe_pc() ); + m_palette[m_clutoffs] = rgb_t(m_colors[0], m_colors[1], m_colors[2]); + m_clutoffs++; + if (m_clutoffs > 255) + { + m_clutoffs = 0; + } + m_count = 0; + } + break; + + case 0x80002: // VBL control + if (data == 0xdcef0000) + { + m_vbl_disable = 0; + lower_slot_irq(); + } + else + { + m_vbl_disable = 1; + } + break; + + default: +// printf("xceedmc30_w: %08x @ %x, mask %08x (PC=%x)\n", data, offset, mem_mask, space.device().safe_pc()); + break; + } +} + +READ32_MEMBER( nubus_xceedmc30_device::xceedmc30_r ) +{ +// printf("xceedmc30_r: @ %x, mask %08x [PC=%x]\n", offset, mem_mask, machine().device("maincpu")->safe_pc()); + if (offset == 0x80008) + { + m_toggle ^= 0x04; + return m_toggle; + } + + return 0; +} + +WRITE32_MEMBER( nubus_xceedmc30_device::vram_w ) +{ + COMBINE_DATA(&m_vram32[offset]); +} + +READ32_MEMBER( nubus_xceedmc30_device::vram_r ) +{ + return m_vram32[offset]; +} diff --git a/src/devices/bus/nubus/pds30_mc30.h b/src/devices/bus/nubus/pds30_mc30.h new file mode 100644 index 00000000000..b7b7276df9f --- /dev/null +++ b/src/devices/bus/nubus/pds30_mc30.h @@ -0,0 +1,56 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +#pragma once + +#ifndef __NUBUS_XCEEDMC30_H__ +#define __NUBUS_XCEEDMC30_H__ + +#include "emu.h" +#include "nubus.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> nubus_xceedmc30_device + +class nubus_xceedmc30_device : + public device_t, + public device_video_interface, + public device_nubus_card_interface +{ +public: + // construction/destruction + nubus_xceedmc30_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + nubus_xceedmc30_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual const rom_entry *device_rom_region() const; + + UINT32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + DECLARE_READ32_MEMBER(xceedmc30_r); + DECLARE_WRITE32_MEMBER(xceedmc30_w); + DECLARE_READ32_MEMBER(vram_r); + DECLARE_WRITE32_MEMBER(vram_w); + +public: + dynamic_buffer m_vram; + UINT32 *m_vram32; + UINT32 m_mode, m_vbl_disable, m_toggle; + UINT32 m_palette[256], m_colors[3], m_count, m_clutoffs; + emu_timer *m_timer; + std::string m_assembled_tag; +}; + + +// device type definition +extern const device_type PDS030_XCEEDMC30; + +#endif /* __NUBUS_XCEEDMC30_H__ */ diff --git a/src/devices/bus/nubus/pds30_procolor816.c b/src/devices/bus/nubus/pds30_procolor816.c new file mode 100644 index 00000000000..4150a2c91b0 --- /dev/null +++ b/src/devices/bus/nubus/pds30_procolor816.c @@ -0,0 +1,350 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/*************************************************************************** + + Lapis ProColor Server 8*16 video card + + FsFF6001: DAC color # (seems to have the data bits perfectly reversed) + FsFF6003: DAC color write (not bitswapped) + FsFF6017: Mode (13 = 1bpp, 17 = 2bpp, 1b = 4bpp, 1e = 8bpp, 0a = 15bpp) + FsFF7000: Bit 2 is VBL IRQ enable/ack + FsFF7001: Bit 0 is VBL status + +***************************************************************************/ + +#include "emu.h" +#include "pds30_procolor816.h" + +#define PROCOLOR816_SCREEN_NAME "cb264_screen" +#define PROCOLOR816_ROM_REGION "cb264_rom" + +#define VRAM_SIZE (0x200000) // 2 megs? + +MACHINE_CONFIG_FRAGMENT( procolor816 ) + MCFG_SCREEN_ADD( PROCOLOR816_SCREEN_NAME, RASTER) + MCFG_SCREEN_UPDATE_DEVICE(DEVICE_SELF, nubus_procolor816_device, screen_update) + MCFG_SCREEN_RAW_PARAMS(25175000, 800, 0, 640, 525, 0, 480) + MCFG_SCREEN_SIZE(1024,768) + MCFG_SCREEN_VISIBLE_AREA(0, 640-1, 0, 480-1) +MACHINE_CONFIG_END + +ROM_START( procolor816 ) + ROM_REGION(0x8000, PROCOLOR816_ROM_REGION, 0) + ROM_LOAD( "procolor_ver60590.bin", 0x000000, 0x008000, CRC(ebef6168) SHA1(e41ecc7d12fc13bc74f9223ca02920e8a7eb072b) ) +ROM_END + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type PDS030_PROCOLOR816 = &device_creator; + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor nubus_procolor816_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( procolor816 ); +} + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *nubus_procolor816_device::device_rom_region() const +{ + return ROM_NAME( procolor816 ); +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// nubus_procolor816_device - constructor +//------------------------------------------------- + +nubus_procolor816_device::nubus_procolor816_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, PDS030_PROCOLOR816, "Lapis ProColor Server 8*16", tag, owner, clock, "pd3_pc16", __FILE__), + device_video_interface(mconfig, *this), + device_nubus_card_interface(mconfig, *this) +{ + m_assembled_tag = std::string(tag).append(":").append(PROCOLOR816_SCREEN_NAME); + m_screen_tag = m_assembled_tag.c_str(); +} + +nubus_procolor816_device::nubus_procolor816_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_video_interface(mconfig, *this), + device_nubus_card_interface(mconfig, *this) +{ + m_assembled_tag = std::string(tag).append(":").append(PROCOLOR816_SCREEN_NAME); + m_screen_tag = m_assembled_tag.c_str(); +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void nubus_procolor816_device::device_start() +{ + UINT32 slotspace; + + // set_nubus_device makes m_slot valid + set_nubus_device(); + install_declaration_rom(this, PROCOLOR816_ROM_REGION); + + slotspace = get_slotspace(); + +// printf("[procolor816 %p] slotspace = %x\n", this, slotspace); + + m_vram.resize(VRAM_SIZE); + m_vram32 = (UINT32 *)&m_vram[0]; + + m_nubus->install_device(slotspace, slotspace+VRAM_SIZE-1, read32_delegate(FUNC(nubus_procolor816_device::vram_r), this), write32_delegate(FUNC(nubus_procolor816_device::vram_w), this)); + m_nubus->install_device(slotspace+0x900000, slotspace+VRAM_SIZE-1+0x900000, read32_delegate(FUNC(nubus_procolor816_device::vram_r), this), write32_delegate(FUNC(nubus_procolor816_device::vram_w), this)); + m_nubus->install_device(slotspace+0xf00000, slotspace+0xff7fff, read32_delegate(FUNC(nubus_procolor816_device::procolor816_r), this), write32_delegate(FUNC(nubus_procolor816_device::procolor816_w), this)); + + m_timer = timer_alloc(0, NULL); + m_timer->adjust(m_screen->time_until_pos(479, 0), 0); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void nubus_procolor816_device::device_reset() +{ + m_count = 0; + m_clutoffs = 0; + m_vbl_disable = 1; + m_mode = 3; + memset(&m_vram[0], 0, VRAM_SIZE); + memset(m_palette, 0, sizeof(m_palette)); + + m_palette[0] = rgb_t(255, 255, 255); + m_palette[0x80] = rgb_t(0, 0, 0); +} + + +void nubus_procolor816_device::device_timer(emu_timer &timer, device_timer_id tid, int param, void *ptr) +{ + if (!m_vbl_disable) + { + raise_slot_irq(); + } + + m_timer->adjust(m_screen->time_until_pos(479, 0), 0); +} + +/*************************************************************************** + + CB264 section + +***************************************************************************/ + +UINT32 nubus_procolor816_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + UINT32 *scanline; + int x, y; + UINT8 pixels, *vram; + + vram = &m_vram[4]; + + switch (m_mode) + { + case 0: // 1 bpp? + for (y = 0; y < 480; y++) + { + scanline = &bitmap.pix32(y); + for (x = 0; x < 640/8; x++) + { + pixels = vram[(y * 640/8) + (BYTE4_XOR_BE(x))]; + + *scanline++ = m_palette[(pixels&0x80)]; + *scanline++ = m_palette[((pixels<<1)&0x80)]; + *scanline++ = m_palette[((pixels<<2)&0x80)]; + *scanline++ = m_palette[((pixels<<3)&0x80)]; + *scanline++ = m_palette[((pixels<<4)&0x80)]; + *scanline++ = m_palette[((pixels<<5)&0x80)]; + *scanline++ = m_palette[((pixels<<6)&0x80)]; + *scanline++ = m_palette[((pixels<<7)&0x80)]; + } + } + break; + + case 1: // 2 bpp + for (y = 0; y < 480; y++) + { + scanline = &bitmap.pix32(y); + for (x = 0; x < 640/4; x++) + { + pixels = vram[(y * 640/4) + (BYTE4_XOR_BE(x))]; + + *scanline++ = m_palette[(pixels&0xc0)]; + *scanline++ = m_palette[((pixels<<2)&0xc0)]; + *scanline++ = m_palette[((pixels<<4)&0xc0)]; + *scanline++ = m_palette[((pixels<<6)&0xc0)]; + } + } + break; + + case 2: // 4 bpp + for (y = 0; y < 480; y++) + { + scanline = &bitmap.pix32(y); + + for (x = 0; x < 640/2; x++) + { + pixels = vram[(y * 640/2) + (BYTE4_XOR_BE(x))]; + + *scanline++ = m_palette[(pixels&0xf0)]; + *scanline++ = m_palette[((pixels&0x0f)<<4)]; + } + } + break; + + case 3: // 8 bpp + for (y = 0; y < 480; y++) + { + scanline = &bitmap.pix32(y); + + for (x = 0; x < 640; x++) + { + pixels = vram[(y * 640) + (BYTE4_XOR_BE(x))]; + *scanline++ = m_palette[pixels]; + } + } + break; + + case 4: // 15 bpp + { + UINT16 *vram16 = (UINT16 *)&m_vram[0]; + UINT16 pixels; + + for (y = 0; y < 480; y++) + { + scanline = &bitmap.pix32(y); + for (x = 0; x < 640; x++) + { + pixels = vram16[(y * 640) + (x^1)]; + *scanline++ = rgb_t(((pixels>>10) & 0x1f)<<3, ((pixels>>5) & 0x1f)<<3, (pixels & 0x1f)<<3); + } + } + } + break; + + default: + fatalerror("procolor816: unknown video mode %d\n", m_mode); + } + return 0; +} + +WRITE32_MEMBER( nubus_procolor816_device::procolor816_w ) +{ + switch (offset) + { + case 0x3d805: // mode + if (mem_mask == 0xff) + { + switch (data & 0xff) + { + case 0x13: + m_mode = 0; + break; + + case 0x17: + m_mode = 1; + break; + + case 0x1b: + m_mode = 2; + break; + + case 0x1e: + m_mode = 3; + break; + + case 0x0a: + m_mode = 4; + break; + } + } + break; + + case 0x3d800: + if (mem_mask == 0x00ff0000) + { + // printf("%08x to DAC control (PC=%x)\n", data, space.device().safe_pc()); + m_clutoffs = BITSWAP8((data>>16)&0xff, 0, 1, 2, 3, 4, 5, 6, 7); + } + else if (mem_mask == 0x000000ff) + { + m_colors[m_count++] = (data & 0xff); + + if (m_count == 3) + { +// printf("RAMDAC: color %02x = %02x %02x %02x (PC=%x)\n", m_clutoffs, m_colors[0], m_colors[1], m_colors[2], space.device().safe_pc() ); + m_palette[m_clutoffs] = rgb_t(m_colors[0], m_colors[1], m_colors[2]); + m_clutoffs++; + if (m_clutoffs > 255) + { + m_clutoffs = 0; + } + m_count = 0; + } + } + break; + + case 0x3dc00: // VBL control + if (mem_mask == 0xff000000) + { + if (data & 0x04000000) + { + m_vbl_disable = 0; + lower_slot_irq(); + } + else + { + m_vbl_disable = 1; + } + } + break; + + default: +// printf("procolor816_w: %08x @ %x, mask %08x (PC=%x)\n", data, offset, mem_mask, space.device().safe_pc()); + break; + } +} + +READ32_MEMBER( nubus_procolor816_device::procolor816_r ) +{ + if (offset == 0x3dc00) + { + m_toggle ^= 0xffffffff; + return m_toggle; + } + else if (offset == 0x3d807) + { + return 0; + } + else + { +// printf("procolor816_r: @ %x, mask %08x [PC=%x]\n", offset, mem_mask, machine().device("maincpu")->safe_pc()); + } + + return 0; +} + +WRITE32_MEMBER( nubus_procolor816_device::vram_w ) +{ + COMBINE_DATA(&m_vram32[offset]); +} + +READ32_MEMBER( nubus_procolor816_device::vram_r ) +{ + return m_vram32[offset]; +} diff --git a/src/devices/bus/nubus/pds30_procolor816.h b/src/devices/bus/nubus/pds30_procolor816.h new file mode 100644 index 00000000000..65bf9d9e76f --- /dev/null +++ b/src/devices/bus/nubus/pds30_procolor816.h @@ -0,0 +1,56 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +#pragma once + +#ifndef __NUBUS_PROCOLOR816_H__ +#define __NUBUS_PROCOLOR816_H__ + +#include "emu.h" +#include "nubus.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> nubus_procolor816_device + +class nubus_procolor816_device : + public device_t, + public device_video_interface, + public device_nubus_card_interface +{ +public: + // construction/destruction + nubus_procolor816_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + nubus_procolor816_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual const rom_entry *device_rom_region() const; + + UINT32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + DECLARE_READ32_MEMBER(procolor816_r); + DECLARE_WRITE32_MEMBER(procolor816_w); + DECLARE_READ32_MEMBER(vram_r); + DECLARE_WRITE32_MEMBER(vram_w); + +public: + dynamic_buffer m_vram; + UINT32 *m_vram32; + UINT32 m_mode, m_vbl_disable, m_toggle; + UINT32 m_palette[256], m_colors[3], m_count, m_clutoffs; + emu_timer *m_timer; + std::string m_assembled_tag; +}; + + +// device type definition +extern const device_type PDS030_PROCOLOR816; + +#endif /* __NUBUS_PROCOLOR816_H__ */ diff --git a/src/devices/bus/nubus/pds30_sigmalview.c b/src/devices/bus/nubus/pds30_sigmalview.c new file mode 100644 index 00000000000..32028fd6824 --- /dev/null +++ b/src/devices/bus/nubus/pds30_sigmalview.c @@ -0,0 +1,216 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/*************************************************************************** + + Sigma Designs L-View card + +***************************************************************************/ + +#include "emu.h" +#include "pds30_sigmalview.h" + +#define LVIEW_SCREEN_NAME "lview_screen" +#define LVIEW_ROM_REGION "lview_rom" + +#define VRAM_SIZE (0x80000) // 512K? + +MACHINE_CONFIG_FRAGMENT( lview ) + MCFG_SCREEN_ADD( LVIEW_SCREEN_NAME, RASTER) + MCFG_SCREEN_UPDATE_DEVICE(DEVICE_SELF, nubus_lview_device, screen_update) + MCFG_SCREEN_SIZE(832,600) + MCFG_SCREEN_REFRESH_RATE(70) + MCFG_SCREEN_VISIBLE_AREA(0, 832-1, 0, 600-1) +MACHINE_CONFIG_END + +ROM_START( lview ) + ROM_REGION(0x4000, LVIEW_ROM_REGION, 0) + ROM_LOAD( "lv_asi_4_00.bin", 0x000000, 0x004000, CRC(b806f875) SHA1(1e58593b1a8720193d1651b0d8a0d43e4e47563d) ) +ROM_END + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type PDS030_LVIEW = &device_creator; + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor nubus_lview_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( lview ); +} + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *nubus_lview_device::device_rom_region() const +{ + return ROM_NAME( lview ); +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// nubus_lview_device - constructor +//------------------------------------------------- + +nubus_lview_device::nubus_lview_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, PDS030_LVIEW, "Sigma Designs L-View", tag, owner, clock, "pd3_lviw", __FILE__), + device_video_interface(mconfig, *this), + device_nubus_card_interface(mconfig, *this) +{ + m_assembled_tag = std::string(tag).append(":").append(LVIEW_SCREEN_NAME); + m_screen_tag = m_assembled_tag.c_str(); +} + +nubus_lview_device::nubus_lview_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_video_interface(mconfig, *this), + device_nubus_card_interface(mconfig, *this) +{ + m_assembled_tag = std::string(tag).append(":").append(LVIEW_SCREEN_NAME); + m_screen_tag = m_assembled_tag.c_str(); +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void nubus_lview_device::device_start() +{ + UINT32 slotspace; + + // set_nubus_device makes m_slot valid + set_nubus_device(); + install_declaration_rom(this, LVIEW_ROM_REGION); + + slotspace = get_slotspace(); + +// printf("[lview %p] slotspace = %x\n", this, slotspace); + + m_vram.resize(VRAM_SIZE); + m_vram32 = (UINT32 *)&m_vram[0]; + + m_nubus->install_device(slotspace, slotspace+VRAM_SIZE-1, read32_delegate(FUNC(nubus_lview_device::vram_r), this), write32_delegate(FUNC(nubus_lview_device::vram_w), this)); + m_nubus->install_device(slotspace+0x900000, slotspace+VRAM_SIZE-1+0x900000, read32_delegate(FUNC(nubus_lview_device::vram_r), this), write32_delegate(FUNC(nubus_lview_device::vram_w), this)); + m_nubus->install_device(slotspace+0xb0000, slotspace+0xbffff, read32_delegate(FUNC(nubus_lview_device::lview_r), this), write32_delegate(FUNC(nubus_lview_device::lview_w), this)); + + m_timer = timer_alloc(0, NULL); + m_timer->adjust(m_screen->time_until_pos(599, 0), 0); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void nubus_lview_device::device_reset() +{ + m_vbl_disable = 1; + m_protstate = 0; + memset(&m_vram[0], 0, VRAM_SIZE); + memset(m_palette, 0, sizeof(m_palette)); + + m_palette[0] = rgb_t(255, 255, 255); + m_palette[0x80] = rgb_t(0, 0, 0); +} + + +void nubus_lview_device::device_timer(emu_timer &timer, device_timer_id tid, int param, void *ptr) +{ + if (!m_vbl_disable) + { + raise_slot_irq(); + } + + m_timer->adjust(m_screen->time_until_pos(599, 0), 0); +} + +/*************************************************************************** + + CB264 section + +***************************************************************************/ + +UINT32 nubus_lview_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + UINT32 *scanline; + int x, y; + UINT8 pixels, *vram; + + vram = &m_vram[0x20]; + + for (y = 0; y < 600; y++) + { + scanline = &bitmap.pix32(y); + for (x = 0; x < 832/8; x++) + { + pixels = vram[(y * (832/8)) + (BYTE4_XOR_BE(x))]; + + *scanline++ = m_palette[(pixels&0x80)]; + *scanline++ = m_palette[((pixels<<1)&0x80)]; + *scanline++ = m_palette[((pixels<<2)&0x80)]; + *scanline++ = m_palette[((pixels<<3)&0x80)]; + *scanline++ = m_palette[((pixels<<4)&0x80)]; + *scanline++ = m_palette[((pixels<<5)&0x80)]; + *scanline++ = m_palette[((pixels<<6)&0x80)]; + *scanline++ = m_palette[((pixels<<7)&0x80)]; + } + } + + return 0; +} + +READ32_MEMBER( nubus_lview_device::lview_r ) +{ + UINT32 rv = 0; + +// printf("prot_r: @ %x, mask %08x [PC=%x state %d]\n", offset, mem_mask, machine().device("maincpu")->safe_pc(), m_protstate); + + if ((m_protstate == 1) || (m_protstate == 10) || (machine().device("maincpu")->safe_pc() == 0x5aac)) + { + rv = 0x02020202; + } + + if (m_protstate == 8) + { + rv = 0x01010101; + } + + m_protstate++; + return rv; +} + +WRITE32_MEMBER( nubus_lview_device::lview_w ) +{ +// if (offset != 0x7a && offset != 0x3ffb) printf("prot_w: %08x @ %x, mask %08x (PC=%x)\n", data, offset, mem_mask, space.device().safe_pc()); + + if (offset == 0x7a) + { + if (data == 1) + { + m_vbl_disable = 0; + lower_slot_irq(); + } + else + { + m_vbl_disable = 1; + } + } +} + +WRITE32_MEMBER( nubus_lview_device::vram_w ) +{ + COMBINE_DATA(&m_vram32[offset]); +} + +READ32_MEMBER( nubus_lview_device::vram_r ) +{ + return m_vram32[offset]; +} diff --git a/src/devices/bus/nubus/pds30_sigmalview.h b/src/devices/bus/nubus/pds30_sigmalview.h new file mode 100644 index 00000000000..62530e412b1 --- /dev/null +++ b/src/devices/bus/nubus/pds30_sigmalview.h @@ -0,0 +1,57 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +#pragma once + +#ifndef __NUBUS_LVIEW_H__ +#define __NUBUS_LVIEW_H__ + +#include "emu.h" +#include "nubus.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> nubus_lview_device + +class nubus_lview_device : + public device_t, + public device_video_interface, + public device_nubus_card_interface +{ +public: + // construction/destruction + nubus_lview_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + nubus_lview_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual const rom_entry *device_rom_region() const; + + UINT32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + DECLARE_READ32_MEMBER(lview_r); + DECLARE_WRITE32_MEMBER(lview_w); + DECLARE_READ32_MEMBER(vram_r); + DECLARE_WRITE32_MEMBER(vram_w); + +public: + dynamic_buffer m_vram; + UINT32 *m_vram32; + UINT32 m_vbl_disable, m_toggle; + UINT32 m_palette[256]; + emu_timer *m_timer; + int m_protstate; + std::string m_assembled_tag; +}; + + +// device type definition +extern const device_type PDS030_LVIEW; + +#endif /* __NUBUS_LVIEW_H__ */ diff --git a/src/devices/bus/odyssey2/chess.c b/src/devices/bus/odyssey2/chess.c new file mode 100644 index 00000000000..8885733923c --- /dev/null +++ b/src/devices/bus/odyssey2/chess.c @@ -0,0 +1,60 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + Videopac Chess Module emulation + + TODO: + - this code is just a stub... hence, almost everything is still to do! + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "chess.h" + + +//------------------------------------------------- +// o2_chess_device - constructor +//------------------------------------------------- + +const device_type O2_ROM_CHESS = &device_creator; + + +o2_chess_device::o2_chess_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : o2_rom_device(mconfig, O2_ROM_CHESS, "Odyssey 2 BASIC Carts", tag, owner, clock, "o2_chess", __FILE__), + m_cpu(*this, "subcpu") +{ +} + + +//------------------------------------------------- +// MACHINE_CONFIG_FRAGMENT( o2chess ) +//------------------------------------------------- + +static ADDRESS_MAP_START(chess_mem, AS_PROGRAM, 8, o2_chess_device) + AM_RANGE(0x0000, 0x07ff) AM_READ(read_rom04) +ADDRESS_MAP_END + +static ADDRESS_MAP_START(chess_io, AS_IO, 8, o2_chess_device) + ADDRESS_MAP_UNMAP_HIGH + ADDRESS_MAP_GLOBAL_MASK(0xff) +ADDRESS_MAP_END + +static MACHINE_CONFIG_FRAGMENT( o2chess ) + MCFG_CPU_ADD("subcpu", NSC800, XTAL_4MHz) + MCFG_CPU_PROGRAM_MAP(chess_mem) + MCFG_CPU_IO_MAP(chess_io) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor o2_chess_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( o2chess ); +} diff --git a/src/devices/bus/odyssey2/chess.h b/src/devices/bus/odyssey2/chess.h new file mode 100644 index 00000000000..8604c317924 --- /dev/null +++ b/src/devices/bus/odyssey2/chess.h @@ -0,0 +1,32 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __O2_CHESS_H +#define __O2_CHESS_H + +#include "slot.h" +#include "rom.h" +#include "cpu/z80/z80.h" + + +// ======================> o2_chess_device + +class o2_chess_device : public o2_rom_device +{ + virtual machine_config_constructor device_mconfig_additions() const; +// virtual const rom_entry *device_rom_region() const; + +public: + // construction/destruction + o2_chess_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +private: + required_device m_cpu; +}; + + + +// device type definition +extern const device_type O2_ROM_CHESS; + + +#endif diff --git a/src/devices/bus/odyssey2/rom.c b/src/devices/bus/odyssey2/rom.c new file mode 100644 index 00000000000..2e364e59b9c --- /dev/null +++ b/src/devices/bus/odyssey2/rom.c @@ -0,0 +1,96 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + Magnavox Odyssey cart emulation + + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "rom.h" + + +//------------------------------------------------- +// o2_rom_device - constructor +//------------------------------------------------- + +const device_type O2_ROM_STD = &device_creator; +const device_type O2_ROM_12K = &device_creator; +const device_type O2_ROM_16K = &device_creator; + + +o2_rom_device::o2_rom_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_o2_cart_interface( mconfig, *this ) +{ +} + +o2_rom_device::o2_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, O2_ROM_STD, "Odyssey 2 Standard Carts", tag, owner, clock, "o2_rom", __FILE__), + device_o2_cart_interface( mconfig, *this ) +{ +} + +o2_rom12_device::o2_rom12_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : o2_rom_device(mconfig, O2_ROM_12K, "Odyssey 2 12K Carts", tag, owner, clock, "o2_rom12", __FILE__) +{ +} + +o2_rom16_device::o2_rom16_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : o2_rom_device(mconfig, O2_ROM_16K, "Odyssey 2 16K Carts", tag, owner, clock, "o2_rom16", __FILE__) +{ +} + + +//------------------------------------------------- +// device_start/device_reset - device-specific startup +//------------------------------------------------- + +void o2_rom_device::device_start() +{ + save_item(NAME(m_bank_base)); +} + +void o2_rom_device::device_reset() +{ + m_bank_base = 0; +} + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +void o2_rom_device::write_bank(int bank) +{ + m_bank_base = bank; +} + +READ8_MEMBER(o2_rom_device::read_rom04) +{ + return m_rom[(offset + (m_bank_base & 0x03) * 0x800) & (m_rom_size - 1)]; +} +READ8_MEMBER(o2_rom_device::read_rom0c) +{ + return m_rom[(offset + (m_bank_base & 0x03) * 0x800) & (m_rom_size - 1)]; +} + +READ8_MEMBER(o2_rom12_device::read_rom04) +{ + return m_rom[offset + (m_bank_base & 0x03) * 0xc00]; +} +READ8_MEMBER(o2_rom12_device::read_rom0c) +{ + return m_rom[offset + 0x800 + (m_bank_base & 0x03) * 0xc00]; +} + +READ8_MEMBER(o2_rom16_device::read_rom04) +{ + return m_rom[offset + 0x400 + (m_bank_base & 0x03) * 0x1000]; +} +READ8_MEMBER(o2_rom16_device::read_rom0c) +{ + return m_rom[offset + 0xc00 + (m_bank_base & 0x03) * 0x1000]; +} diff --git a/src/devices/bus/odyssey2/rom.h b/src/devices/bus/odyssey2/rom.h new file mode 100644 index 00000000000..18bfa63c4b4 --- /dev/null +++ b/src/devices/bus/odyssey2/rom.h @@ -0,0 +1,67 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __O2_ROM_H +#define __O2_ROM_H + +#include "slot.h" + + +// ======================> o2_rom_device + +class o2_rom_device : public device_t, + public device_o2_cart_interface +{ +public: + // construction/destruction + o2_rom_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + o2_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_rom04); + virtual DECLARE_READ8_MEMBER(read_rom0c); + + virtual void write_bank(int bank); + +protected: + int m_bank_base; +}; + +// ======================> o2_rom12_device + +class o2_rom12_device : public o2_rom_device +{ +public: + // construction/destruction + o2_rom12_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_rom04); + virtual DECLARE_READ8_MEMBER(read_rom0c); +}; + +// ======================> o2_rom16_device + +class o2_rom16_device : public o2_rom_device +{ +public: + // construction/destruction + o2_rom16_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_rom04); + virtual DECLARE_READ8_MEMBER(read_rom0c); +}; + + + +// device type definition +extern const device_type O2_ROM_STD; +extern const device_type O2_ROM_12K; +extern const device_type O2_ROM_16K; + + +#endif diff --git a/src/devices/bus/odyssey2/slot.c b/src/devices/bus/odyssey2/slot.c new file mode 100644 index 00000000000..72262afe7ac --- /dev/null +++ b/src/devices/bus/odyssey2/slot.c @@ -0,0 +1,278 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + Magnavox Odyssey 2 cart emulation + (through slot devices) + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "slot.h" + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type O2_CART_SLOT = &device_creator; + +//************************************************************************** +// Odyssey 2 Cartridges Interface +//************************************************************************** + +//------------------------------------------------- +// device_o2_cart_interface - constructor +//------------------------------------------------- + +device_o2_cart_interface::device_o2_cart_interface(const machine_config &mconfig, device_t &device) + : device_slot_card_interface(mconfig, device), + m_rom(NULL), + m_rom_size(0) +{ +} + + +//------------------------------------------------- +// ~device_o2_cart_interface - destructor +//------------------------------------------------- + +device_o2_cart_interface::~device_o2_cart_interface() +{ +} + +//------------------------------------------------- +// rom_alloc - alloc the space for the cart +//------------------------------------------------- + +void device_o2_cart_interface::rom_alloc(UINT32 size, const char *tag) +{ + if (m_rom == NULL) + { + m_rom = device().machine().memory().region_alloc(std::string(tag).append(O2SLOT_ROM_REGION_TAG).c_str(), size, 1, ENDIANNESS_LITTLE)->base(); + m_rom_size = size; + } +} + + +//------------------------------------------------- +// ram_alloc - alloc the space for the ram +//------------------------------------------------- + +void device_o2_cart_interface::ram_alloc(UINT32 size) +{ + m_ram.resize(size); +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// o2_cart_slot_device - constructor +//------------------------------------------------- +o2_cart_slot_device::o2_cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, O2_CART_SLOT, "Odyssey 2 Cartridge Slot", tag, owner, clock, "o2_cart_slot", __FILE__), + device_image_interface(mconfig, *this), + device_slot_interface(mconfig, *this), + m_type(O2_STD) +{ +} + + +//------------------------------------------------- +// o2_cart_slot_device - destructor +//------------------------------------------------- + +o2_cart_slot_device::~o2_cart_slot_device() +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void o2_cart_slot_device::device_start() +{ + m_cart = dynamic_cast(get_card_device()); +} + +//------------------------------------------------- +// device_config_complete - perform any +// operations now that the configuration is +// complete +//------------------------------------------------- + +void o2_cart_slot_device::device_config_complete() +{ + // set brief and instance name + update_names(); +} + + +//------------------------------------------------- +// O2 PCB +//------------------------------------------------- + +struct o2_slot +{ + int pcb_id; + const char *slot_option; +}; + +// Here, we take the feature attribute from .xml (i.e. the PCB name) and we assign a unique ID to it +static const o2_slot slot_list[] = +{ + { O2_STD, "o2_rom" }, + { O2_ROM12, "o2_rom12" }, + { O2_ROM16, "o2_rom16" }, + { O2_CHESS, "o2_chess" }, + { O2_VOICE, "o2_voice" } +}; + +static int o2_get_pcb_id(const char *slot) +{ + for (int i = 0; i < ARRAY_LENGTH(slot_list); i++) + { + if (!core_stricmp(slot_list[i].slot_option, slot)) + return slot_list[i].pcb_id; + } + + return 0; +} + +static const char *o2_get_slot(int type) +{ + for (int i = 0; i < ARRAY_LENGTH(slot_list); i++) + { + if (slot_list[i].pcb_id == type) + return slot_list[i].slot_option; + } + + return "o2_rom"; +} + + +/*------------------------------------------------- + call load + -------------------------------------------------*/ + +bool o2_cart_slot_device::call_load() +{ + if (m_cart) + { + UINT32 size = (software_entry() == NULL) ? length() : get_software_region_length("rom"); + m_cart->rom_alloc(size, tag()); + + if (software_entry() == NULL) + fread(m_cart->get_rom_base(), size); + else + memcpy(m_cart->get_rom_base(), get_software_region("rom"), size); + + if (software_entry() == NULL) + { + m_type = O2_STD; + if (size == 12288) + m_type = O2_ROM12; + if (size == 16384) + m_type = O2_ROM16; + } + else + { + const char *pcb_name = get_feature("slot"); + if (pcb_name) + m_type = o2_get_pcb_id(pcb_name); + } + + //printf("Type: %s\n", o2_get_slot(m_type)); + + return IMAGE_INIT_PASS; + } + + return IMAGE_INIT_PASS; +} + + +/*------------------------------------------------- + call softlist load + -------------------------------------------------*/ + +bool o2_cart_slot_device::call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry) +{ + load_software_part_region(*this, swlist, swname, start_entry); + return TRUE; +} + + +/*------------------------------------------------- + get default card software + -------------------------------------------------*/ + +void o2_cart_slot_device::get_default_card_software(std::string &result) +{ + if (open_image_file(mconfig().options())) + { + const char *slot_string = "o2_rom"; + UINT32 size = core_fsize(m_file); + int type = O2_STD; + + if (size == 12288) + type = O2_ROM12; + if (size == 16384) + type = O2_ROM16; + + slot_string = o2_get_slot(type); + + //printf("type: %s\n", slot_string); + clear(); + + result.assign(slot_string); + return; + } + + software_get_default_slot(result, "o2_rom"); +} + +/*------------------------------------------------- + read_rom** + -------------------------------------------------*/ + +READ8_MEMBER(o2_cart_slot_device::read_rom04) +{ + if (m_cart) + return m_cart->read_rom04(space, offset); + else + return 0xff; +} + +READ8_MEMBER(o2_cart_slot_device::read_rom0c) +{ + if (m_cart) + return m_cart->read_rom0c(space, offset); + else + return 0xff; +} + +/*------------------------------------------------- + io_write + -------------------------------------------------*/ + +WRITE8_MEMBER(o2_cart_slot_device::io_write) +{ + if (m_cart) + m_cart->io_write(space, offset, data); +} + + +#include "bus/odyssey2/rom.h" +#include "bus/odyssey2/chess.h" +#include "bus/odyssey2/voice.h" + +SLOT_INTERFACE_START(o2_cart) + SLOT_INTERFACE_INTERNAL("o2_rom", O2_ROM_STD) + SLOT_INTERFACE_INTERNAL("o2_rom12", O2_ROM_12K) + SLOT_INTERFACE_INTERNAL("o2_rom16", O2_ROM_16K) + SLOT_INTERFACE_INTERNAL("o2_chess", O2_ROM_CHESS) + SLOT_INTERFACE_INTERNAL("o2_voice", O2_ROM_VOICE) +SLOT_INTERFACE_END diff --git a/src/devices/bus/odyssey2/slot.h b/src/devices/bus/odyssey2/slot.h new file mode 100644 index 00000000000..a5cebb9ed0d --- /dev/null +++ b/src/devices/bus/odyssey2/slot.h @@ -0,0 +1,121 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __O2_SLOT_H +#define __O2_SLOT_H + +/*************************************************************************** + TYPE DEFINITIONS + ***************************************************************************/ + + +/* PCB */ +enum +{ + O2_STD = 0, + O2_ROM12, + O2_ROM16, + O2_CHESS, + O2_VOICE +}; + + +// ======================> device_o2_cart_interface + +class device_o2_cart_interface : public device_slot_card_interface +{ +public: + // construction/destruction + device_o2_cart_interface(const machine_config &mconfig, device_t &device); + virtual ~device_o2_cart_interface(); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_rom04) { return 0xff; } + virtual DECLARE_READ8_MEMBER(read_rom0c) { return 0xff; } + virtual void write_bank(int bank) {} + + virtual DECLARE_WRITE8_MEMBER(io_write) {} + virtual DECLARE_READ8_MEMBER(t0_read) { return 0; } + + void rom_alloc(UINT32 size, const char *tag); + void ram_alloc(UINT32 size); + UINT8* get_rom_base() { return m_rom; } + UINT8* get_ram_base() { return &m_ram[0]; } + UINT32 get_rom_size() { return m_rom_size; } + UINT32 get_ram_size() { return m_ram.size(); } + +protected: + // internal state + UINT8 *m_rom; + UINT32 m_rom_size; + dynamic_buffer m_ram; +}; + + +// ======================> o2_cart_slot_device + +class o2_cart_slot_device : public device_t, + public device_image_interface, + public device_slot_interface +{ +public: + // construction/destruction + o2_cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual ~o2_cart_slot_device(); + + // device-level overrides + virtual void device_start(); + virtual void device_config_complete(); + + // image-level overrides + virtual bool call_load(); + virtual void call_unload() {} + virtual bool call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry); + + int get_type() { return m_type; } + + virtual iodevice_t image_type() const { return IO_CARTSLOT; } + virtual bool is_readable() const { return 1; } + virtual bool is_writeable() const { return 0; } + virtual bool is_creatable() const { return 0; } + virtual bool must_be_loaded() const { return 0; } + virtual bool is_reset_on_load() const { return 1; } + virtual const option_guide *create_option_guide() const { return NULL; } + virtual const char *image_interface() const { return "odyssey_cart"; } + virtual const char *file_extensions() const { return "bin,rom"; } + + // slot interface overrides + virtual void get_default_card_software(std::string &result); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_rom04); + virtual DECLARE_READ8_MEMBER(read_rom0c); + virtual DECLARE_WRITE8_MEMBER(io_write); + virtual DECLARE_READ8_MEMBER(t0_read) { if (m_cart) return m_cart->t0_read(space, offset); else return 0; } + + virtual void write_bank(int bank) { if (m_cart) m_cart->write_bank(bank); } + +protected: + + int m_type; + device_o2_cart_interface* m_cart; +}; + + + +// device type definition +extern const device_type O2_CART_SLOT; + + +/*************************************************************************** + DEVICE CONFIGURATION MACROS + ***************************************************************************/ + +#define O2SLOT_ROM_REGION_TAG ":cart:rom" + +#define MCFG_O2_CARTRIDGE_ADD(_tag,_slot_intf,_def_slot) \ + MCFG_DEVICE_ADD(_tag, O2_CART_SLOT, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) + +SLOT_INTERFACE_EXTERN(o2_cart); + +#endif diff --git a/src/devices/bus/odyssey2/voice.c b/src/devices/bus/odyssey2/voice.c new file mode 100644 index 00000000000..e94b3bd1432 --- /dev/null +++ b/src/devices/bus/odyssey2/voice.c @@ -0,0 +1,103 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + Magnavox The Voice emulation + + TODO: + - load speech ROM from softlist + - move external speech rom for S.I.D. the Spellbinder into the softlist entry + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "voice.h" + + +//------------------------------------------------- +// o2_voice_device - constructor +//------------------------------------------------- + +const device_type O2_ROM_VOICE = &device_creator; + + +o2_voice_device::o2_voice_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : o2_rom_device(mconfig, O2_ROM_VOICE, "Odyssey 2 The Voice Passthrough Cart", tag, owner, clock, "o2_voice", __FILE__), + m_speech(*this, "sp0256_speech"), + m_subslot(*this, "subslot"), + m_lrq_state(0) +{ +} + + +void o2_voice_device::device_start() +{ + save_item(NAME(m_lrq_state)); +} + +//------------------------------------------------- +// MACHINE_CONFIG_FRAGMENT( sub_slot ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( o2voice ) + MCFG_SPEAKER_STANDARD_MONO("mono") + + MCFG_SOUND_ADD("sp0256_speech", SP0256, 3120000) + MCFG_SP0256_DATA_REQUEST_CB(WRITELINE(o2_voice_device, lrq_callback)) + // The Voice uses a speaker with its own volume control so the relative volumes to use are subjective, these sound good + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 1.00) + + MCFG_O2_CARTRIDGE_ADD("subslot", o2_cart, NULL) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor o2_voice_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( o2voice ); +} + + +ROM_START( o2voice ) + ROM_REGION( 0x10000, "sp0256_speech", 0 ) + // SP0256B-019 Speech chip w/2KiB mask rom + ROM_LOAD( "sp0256b-019.bin", 0x1000, 0x0800, CRC(4bb43724) SHA1(49f5326ad45392dc96c89d1d4e089a20bd21e609) ) + + /* A note about "The Voice": Two versions of "The Voice" exist: + * An earlier version with eight 2KiB speech roms, spr016-??? through spr016-??? on a small daughterboard + + * A later version with one 16KiB speech rom, spr128-003, mounted directly on the mainboard + The rom contents of these two versions are EXACTLY the same. + Both versions have an sp0256b-019 speech chip, which has 2KiB of its own internal speech data + Thanks to kevtris for this info. - LN + */ + + // External 16KiB speech ROM (spr128-003) from "The Voice" + ROM_LOAD( "spr128-003.bin", 0x4000, 0x4000, CRC(509367b5) SHA1(0f31f46bc02e9272885779a6dd7102c78b18895b) ) + // Additional External 16KiB speech ROM (spr128-004) from S.I.D. the Spellbinder + ROM_LOAD( "spr128-004.bin", 0x8000, 0x4000, CRC(e79dfb75) SHA1(37f33d79ffd1739d7c2f226b010a1eac28d74ca0) ) +ROM_END + +const rom_entry *o2_voice_device::device_rom_region() const +{ + return ROM_NAME( o2voice ); +} + +WRITE_LINE_MEMBER(o2_voice_device::lrq_callback) +{ + m_lrq_state = state; +} + +WRITE8_MEMBER(o2_voice_device::io_write) +{ + if (data & 0x20) + m_speech->ald_w(space, 0, offset & 0x7f); + else + m_speech->reset(); +} diff --git a/src/devices/bus/odyssey2/voice.h b/src/devices/bus/odyssey2/voice.h new file mode 100644 index 00000000000..71fb77b067c --- /dev/null +++ b/src/devices/bus/odyssey2/voice.h @@ -0,0 +1,50 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __O2_VOICE_H +#define __O2_VOICE_H + +#include "slot.h" +#include "rom.h" +#include "sound/sp0256.h" + + +// ======================> o2_voice_device + +class o2_voice_device : public o2_rom_device +{ +public: + // construction/destruction + o2_voice_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset() {} + + virtual machine_config_constructor device_mconfig_additions() const; + virtual const rom_entry *device_rom_region() const; + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_rom04) { if (m_subslot->exists()) return m_subslot->read_rom04(space, offset); else return 0xff; } + virtual DECLARE_READ8_MEMBER(read_rom0c) { if (m_subslot->exists()) return m_subslot->read_rom0c(space, offset); else return 0xff; } + + virtual void write_bank(int bank) { if (m_subslot->exists()) m_subslot->write_bank(bank); } + + DECLARE_WRITE_LINE_MEMBER(lrq_callback); + DECLARE_WRITE8_MEMBER(io_write); + DECLARE_READ8_MEMBER(t0_read) { return m_speech->lrq_r() ? 0 : 1; } + +private: + required_device m_speech; + required_device m_subslot; + + int m_lrq_state; +}; + + + + +// device type definition +extern const device_type O2_ROM_VOICE; + + +#endif diff --git a/src/devices/bus/oricext/jasmin.c b/src/devices/bus/oricext/jasmin.c new file mode 100644 index 00000000000..c8fd1d81081 --- /dev/null +++ b/src/devices/bus/oricext/jasmin.c @@ -0,0 +1,174 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +#include "jasmin.h" +#include "formats/oric_dsk.h" + +const device_type JASMIN = &device_creator; + +ROM_START( jasmin ) + ROM_REGION( 0x800, "jasmin", 0 ) + ROM_LOAD("jasmin.rom", 0, 0x800, CRC(37220e89) SHA1(70e59b8abd67092f050462abc6cb5271e4c15f01) ) +ROM_END + +FLOPPY_FORMATS_MEMBER( jasmin_device::floppy_formats ) + FLOPPY_ORIC_DSK_FORMAT +FLOPPY_FORMATS_END + +static SLOT_INTERFACE_START( jasmin_floppies ) + SLOT_INTERFACE( "3dsdd", FLOPPY_3_DSDD ) +SLOT_INTERFACE_END + +static MACHINE_CONFIG_FRAGMENT( jasmin ) + MCFG_WD1770_ADD("fdc", XTAL_8MHz) + MCFG_WD_FDC_DRQ_CALLBACK(WRITELINE(oricext_device, irq_w)) + + MCFG_FLOPPY_DRIVE_ADD("fdc:0", jasmin_floppies, "3dsdd", jasmin_device::floppy_formats) + MCFG_FLOPPY_DRIVE_ADD("fdc:1", jasmin_floppies, NULL, jasmin_device::floppy_formats) + MCFG_FLOPPY_DRIVE_ADD("fdc:2", jasmin_floppies, NULL, jasmin_device::floppy_formats) + MCFG_FLOPPY_DRIVE_ADD("fdc:3", jasmin_floppies, NULL, jasmin_device::floppy_formats) +MACHINE_CONFIG_END + +INPUT_PORTS_START( jasmin ) + PORT_START("JASMIN") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Boot") PORT_CODE(KEYCODE_F1) PORT_CHAR(UCHAR_MAMEKEY(F1)) PORT_CHANGED_MEMBER(DEVICE_SELF, jasmin_device, boot_pressed, 0) +INPUT_PORTS_END + +DEVICE_ADDRESS_MAP_START(map, 8, jasmin_device) + AM_RANGE(0x3f4, 0x3f7) AM_DEVREADWRITE("fdc", wd1770_t, read, write) + AM_RANGE(0x3f8, 0x3f8) AM_WRITE(side_sel_w) + AM_RANGE(0x3f9, 0x3f9) AM_WRITE(fdc_reset_w) + AM_RANGE(0x3fa, 0x3fa) AM_WRITE(ram_access_w) + AM_RANGE(0x3fb, 0x3fb) AM_WRITE(rom_access_w) + AM_RANGE(0x3fc, 0x3ff) AM_WRITE(select_w) +ADDRESS_MAP_END + +jasmin_device::jasmin_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + oricext_device(mconfig, JASMIN, "Jasmin floppy drive interface", tag, owner, clock, "jasmin", __FILE__), + fdc(*this, "fdc") +{ +} + +jasmin_device::~jasmin_device() +{ +} + +void jasmin_device::device_start() +{ + oricext_device::device_start(); + jasmin_rom = device().machine().root_device().memregion(this->subtag("jasmin").c_str())->base(); + cpu->space(AS_PROGRAM).install_device(0x0000, 0xffff, *this, &jasmin_device::map); + + for(int i=0; i<4; i++) { + char name[32]; + sprintf(name, "fdc:%d", i); + floppies[i] = subdevice(name)->get_device(); + } +} + +void jasmin_device::device_reset() +{ + side_sel = fdc_reset = ram_access = rom_access = false; + select[0] = select[1] = select[2] = select[3] = false; + remap(); + cur_floppy = NULL; + fdc->set_floppy(NULL); +} + +const rom_entry *jasmin_device::device_rom_region() const +{ + return ROM_NAME( jasmin ); +} + +machine_config_constructor jasmin_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( jasmin ); +} + +ioport_constructor jasmin_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( jasmin ); +} + +void jasmin_device::remap() +{ + if(rom_access) { + if(ram_access) { + bank_c000_r->set_base(ram+0xc000); + bank_e000_r->set_base(ram+0xe000); + bank_f800_r->set_base(jasmin_rom); + bank_c000_w->set_base(ram+0xc000); + bank_e000_w->set_base(ram+0xe000); + bank_f800_w->set_base(junk_write); + } else { + bank_c000_r->set_base(junk_read); + bank_e000_r->set_base(junk_read); + bank_f800_r->set_base(jasmin_rom); + bank_c000_w->set_base(junk_write); + bank_e000_w->set_base(junk_write); + bank_f800_w->set_base(junk_write); + } + } else { + if(ram_access) { + bank_c000_r->set_base(ram+0xc000); + bank_e000_r->set_base(ram+0xe000); + bank_f800_r->set_base(ram+0xf800); + bank_c000_w->set_base(ram+0xc000); + bank_e000_w->set_base(ram+0xe000); + bank_f800_w->set_base(ram+0xf800); + } else { + bank_c000_r->set_base(rom+0x0000); + bank_e000_r->set_base(rom+0x2000); + bank_f800_r->set_base(rom+0x3800); + bank_c000_w->set_base(junk_write); + bank_e000_w->set_base(junk_write); + bank_f800_w->set_base(junk_write); + } + } +} + +INPUT_CHANGED_MEMBER(jasmin_device::boot_pressed) +{ + if(newval) { + rom_access = true; + remap(); + cpu->reset(); + } +} + +WRITE8_MEMBER(jasmin_device::side_sel_w) +{ + side_sel = data & 1; + if(cur_floppy) + cur_floppy->ss_w(side_sel); +} + +WRITE8_MEMBER(jasmin_device::fdc_reset_w) +{ + if((data & 1) != fdc_reset) + fdc->soft_reset(); + fdc_reset = data & 1; +} + +WRITE8_MEMBER(jasmin_device::ram_access_w) +{ + ram_access = data & 1; + remap(); +} + +WRITE8_MEMBER(jasmin_device::rom_access_w) +{ + rom_access = data & 1; + remap(); +} + +WRITE8_MEMBER(jasmin_device::select_w) +{ + select[offset] = data & 1; + cur_floppy = NULL; + for(int i=0; i != 4; i++) + if(select[i]) { + cur_floppy = floppies[i]; + break; + } + fdc->set_floppy(cur_floppy); +} diff --git a/src/devices/bus/oricext/jasmin.h b/src/devices/bus/oricext/jasmin.h new file mode 100644 index 00000000000..8dae60eedbf --- /dev/null +++ b/src/devices/bus/oricext/jasmin.h @@ -0,0 +1,43 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +#ifndef __JASMIN_H__ +#define __JASMIN_H__ + +#include "oricext.h" +#include "imagedev/floppy.h" +#include "machine/wd_fdc.h" + +extern const device_type JASMIN; + +class jasmin_device : public oricext_device +{ +public: + jasmin_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual ~jasmin_device(); + + DECLARE_FLOPPY_FORMATS(floppy_formats); + DECLARE_ADDRESS_MAP(map, 8); + DECLARE_INPUT_CHANGED_MEMBER(boot_pressed); + DECLARE_WRITE8_MEMBER(side_sel_w); + DECLARE_WRITE8_MEMBER(fdc_reset_w); + DECLARE_WRITE8_MEMBER(ram_access_w); + DECLARE_WRITE8_MEMBER(rom_access_w); + DECLARE_WRITE8_MEMBER(select_w); + +protected: + required_device fdc; + + bool side_sel, fdc_reset, ram_access, rom_access, select[4]; + UINT8 *jasmin_rom; + floppy_image_device *cur_floppy, *floppies[4]; + + virtual void device_start(); + virtual void device_reset(); + const rom_entry *device_rom_region() const; + machine_config_constructor device_mconfig_additions() const; + virtual ioport_constructor device_input_ports() const; + + void remap(); +}; + +#endif diff --git a/src/devices/bus/oricext/microdisc.c b/src/devices/bus/oricext/microdisc.c new file mode 100644 index 00000000000..c66adfa555a --- /dev/null +++ b/src/devices/bus/oricext/microdisc.c @@ -0,0 +1,152 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +#include "microdisc.h" +#include "formats/oric_dsk.h" + +const device_type MICRODISC = &device_creator; + +ROM_START( microdisc ) + ROM_REGION( 0x2000, "microdisc", 0 ) + ROM_LOAD ("microdis.rom", 0, 0x02000, CRC(a9664a9c) SHA1(0d2ef6e67322f48f4b7e08d8bbe68827e2074561) ) +ROM_END + +FLOPPY_FORMATS_MEMBER( microdisc_device::floppy_formats ) + FLOPPY_ORIC_DSK_FORMAT +FLOPPY_FORMATS_END + +static SLOT_INTERFACE_START( microdisc_floppies ) + SLOT_INTERFACE( "3dsdd", FLOPPY_3_DSDD ) +SLOT_INTERFACE_END + +static MACHINE_CONFIG_FRAGMENT( microdisc ) + MCFG_FD1793_ADD("fdc", XTAL_8MHz/8) + MCFG_WD_FDC_INTRQ_CALLBACK(WRITELINE(microdisc_device, fdc_irq_w)) + MCFG_WD_FDC_DRQ_CALLBACK(WRITELINE(microdisc_device, fdc_drq_w)) + MCFG_WD_FDC_HLD_CALLBACK(WRITELINE(microdisc_device, fdc_hld_w)) + MCFG_WD_FDC_FORCE_READY + + MCFG_FLOPPY_DRIVE_ADD("fdc:0", microdisc_floppies, "3dsdd", microdisc_device::floppy_formats) + MCFG_FLOPPY_DRIVE_ADD("fdc:1", microdisc_floppies, NULL, microdisc_device::floppy_formats) + MCFG_FLOPPY_DRIVE_ADD("fdc:2", microdisc_floppies, NULL, microdisc_device::floppy_formats) + MCFG_FLOPPY_DRIVE_ADD("fdc:3", microdisc_floppies, NULL, microdisc_device::floppy_formats) +MACHINE_CONFIG_END + +DEVICE_ADDRESS_MAP_START(map, 8, microdisc_device) + AM_RANGE(0x310, 0x313) AM_DEVREADWRITE("fdc", fd1793_t, read, write) + AM_RANGE(0x314, 0x314) AM_READWRITE(port_314_r, port_314_w) + AM_RANGE(0x318, 0x318) AM_READ(port_318_r) +ADDRESS_MAP_END + +microdisc_device::microdisc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + oricext_device(mconfig, MICRODISC, "Microdisc floppy drive interface", tag, owner, clock, "microdisc", __FILE__), + fdc(*this, "fdc") +{ +} + +microdisc_device::~microdisc_device() +{ +} + +void microdisc_device::device_start() +{ + oricext_device::device_start(); + microdisc_rom = device().machine().root_device().memregion(this->subtag("microdisc").c_str())->base(); + cpu->space(AS_PROGRAM).install_device(0x0000, 0xffff, *this, µdisc_device::map); + + for(int i=0; i<4; i++) { + char name[32]; + sprintf(name, "fdc:%d", i); + floppies[i] = subdevice(name)->get_device(); + } + intrq_state = drq_state = hld_state = false; +} + +void microdisc_device::device_reset() +{ + port_314 = 0x00; + irq_w(false); + remap(); + fdc->set_floppy(floppies[0]); + + // The bootstrap checksums part of the high ram and if the sum is + // 0 it goes wrong. + ram[0xe000] = 0x42; +} + +const rom_entry *microdisc_device::device_rom_region() const +{ + return ROM_NAME( microdisc ); +} + +machine_config_constructor microdisc_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( microdisc ); +} + +void microdisc_device::remap() +{ + if(port_314 & P_ROMDIS) { + bank_c000_r->set_base(rom+0x0000); + bank_e000_r->set_base(rom+0x2000); + bank_f800_r->set_base(rom+0x3800); + bank_c000_w->set_base(junk_write); + bank_e000_w->set_base(junk_write); + bank_f800_w->set_base(junk_write); + } else { + bank_c000_r->set_base(ram+0xc000); + bank_c000_w->set_base(ram+0xc000); + if(port_314 & P_EPROM) { + bank_e000_r->set_base(ram+0xe000); + bank_f800_r->set_base(ram+0xf800); + bank_e000_w->set_base(ram+0xe000); + bank_f800_w->set_base(ram+0xf800); + } else { + bank_e000_r->set_base(microdisc_rom+0x0000); + bank_f800_r->set_base(microdisc_rom+0x1800); + bank_e000_w->set_base(junk_write); + bank_f800_w->set_base(junk_write); + } + } +} + +WRITE8_MEMBER(microdisc_device::port_314_w) +{ + port_314 = data; + remap(); + floppy_image_device *floppy = floppies[(port_314 >> 5) & 3]; + fdc->set_floppy(floppy); + fdc->dden_w(port_314 & P_DDEN); + if(floppy) { + floppy->ss_w(port_314 & P_SS ? 1 : 0); + floppy->mon_w(0); + } + irq_w(intrq_state && (port_314 & P_IRQEN)); +} + +READ8_MEMBER(microdisc_device::port_314_r) +{ + return (intrq_state && (port_314 & P_IRQEN)) ? 0x7f : 0xff; +} + +READ8_MEMBER(microdisc_device::port_318_r) +{ + return drq_state ? 0x7f : 0xff; +} + +WRITE_LINE_MEMBER(microdisc_device::fdc_irq_w) +{ + intrq_state = state; + irq_w(intrq_state && (port_314 & P_IRQEN)); +} + +WRITE_LINE_MEMBER(microdisc_device::fdc_drq_w) +{ + drq_state = state; +} + +WRITE_LINE_MEMBER(microdisc_device::fdc_hld_w) +{ + logerror("hld %d\n", state); + hld_state = state; + floppies[(port_314 >> 5) & 3]->mon_w(!hld_state); +} diff --git a/src/devices/bus/oricext/microdisc.h b/src/devices/bus/oricext/microdisc.h new file mode 100644 index 00000000000..bf790c4af52 --- /dev/null +++ b/src/devices/bus/oricext/microdisc.h @@ -0,0 +1,54 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +#ifndef __MICRODISC_H__ +#define __MICRODISC_H__ + +#include "oricext.h" +#include "imagedev/floppy.h" +#include "machine/wd_fdc.h" + +extern const device_type MICRODISC; + +class microdisc_device : public oricext_device +{ +public: + microdisc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual ~microdisc_device(); + + DECLARE_FLOPPY_FORMATS(floppy_formats); + DECLARE_ADDRESS_MAP(map, 8); + DECLARE_WRITE8_MEMBER(port_314_w); + DECLARE_READ8_MEMBER(port_314_r); + DECLARE_READ8_MEMBER(port_318_r); + + DECLARE_WRITE_LINE_MEMBER(fdc_irq_w); + DECLARE_WRITE_LINE_MEMBER(fdc_drq_w); + DECLARE_WRITE_LINE_MEMBER(fdc_hld_w); + +protected: + enum { + P_IRQEN = 0x01, + P_ROMDIS = 0x02, + P_DDS = 0x04, + P_DDEN = 0x08, + P_SS = 0x10, + P_DRIVE = 0x60, + P_EPROM = 0x80 + }; + + required_device fdc; + + UINT8 *microdisc_rom; + floppy_image_device *floppies[4]; + UINT8 port_314; + bool intrq_state, drq_state, hld_state; + + virtual void device_start(); + virtual void device_reset(); + const rom_entry *device_rom_region() const; + machine_config_constructor device_mconfig_additions() const; + + void remap(); +}; + +#endif diff --git a/src/devices/bus/oricext/oricext.c b/src/devices/bus/oricext/oricext.c new file mode 100644 index 00000000000..e13b5c5f245 --- /dev/null +++ b/src/devices/bus/oricext/oricext.c @@ -0,0 +1,78 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +#include "oricext.h" +#include "jasmin.h" +#include "microdisc.h" + +const device_type ORICEXT_CONNECTOR = &device_creator; + +oricext_connector::oricext_connector(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, ORICEXT_CONNECTOR, "ORIC extension connector", tag, owner, clock, "oricext_connector", __FILE__), + device_slot_interface(mconfig, *this), + irq_handler(*this) +{ +} + +oricext_connector::~oricext_connector() +{ +} + +void oricext_connector::set_cputag(const char *tag) +{ + cputag = tag; +} + +void oricext_connector::device_start() +{ + irq_handler.resolve_safe(); +} + +void oricext_connector::irq_w(int state) +{ + irq_handler(state); +} + +void oricext_connector::device_config_complete() +{ + oricext_device *dev = dynamic_cast(get_card_device()); + if(dev) + dev->set_cputag(cputag); +} + +oricext_device::oricext_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_slot_card_interface(mconfig, *this) +{ +} + +void oricext_device::set_cputag(const char *tag) +{ + cputag = tag; +} + +void oricext_device::device_start() +{ + cpu = machine().device(cputag); + connector = downcast(owner()); + bank_c000_r = membank(":bank_c000_r"); + bank_e000_r = membank(":bank_e000_r"); + bank_f800_r = membank(":bank_f800_r"); + bank_c000_w = membank(":bank_c000_w"); + bank_e000_w = membank(":bank_e000_w"); + bank_f800_w = membank(":bank_f800_w"); + rom = (UINT8 *)machine().root_device().memregion(cputag)->base(); + ram = (UINT8 *)memshare(":ram")->ptr(); + + memset(junk_read, 0xff, sizeof(junk_read)); + memset(junk_write, 0x00, sizeof(junk_write)); +} + +WRITE_LINE_MEMBER(oricext_device::irq_w) +{ + connector->irq_w(state); +} + +SLOT_INTERFACE_START(oricext_intf) + SLOT_INTERFACE("jasmin", JASMIN) + SLOT_INTERFACE("microdisc", MICRODISC) +SLOT_INTERFACE_END diff --git a/src/devices/bus/oricext/oricext.h b/src/devices/bus/oricext/oricext.h new file mode 100644 index 00000000000..4eeb7766aea --- /dev/null +++ b/src/devices/bus/oricext/oricext.h @@ -0,0 +1,65 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +/*************************************************************************** + + oric.h - Oric 1/Atmos extension port + +***************************************************************************/ + +#ifndef __ORICEXT_H__ +#define __ORICEXT_H__ + +#include "emu.h" +#include "cpu/m6502/m6502.h" + +#define MCFG_ORICEXT_ADD(_tag, _slot_intf, _def_slot, _cputag, _irq) \ + MCFG_DEVICE_ADD(_tag, ORICEXT_CONNECTOR, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) \ + downcast(device)->set_cputag(_cputag); \ + devcb = &oricext_connector::set_irq_handler(*device, DEVCB_##_irq); + + +class oricext_device; + +class oricext_connector: public device_t, + public device_slot_interface +{ +public: + oricext_connector(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual ~oricext_connector(); + + void set_cputag(const char *tag); + template static devcb_base &set_irq_handler(device_t &device, _Object object) { return downcast(device).irq_handler.set_callback(object); } + void irq_w(int state); + +protected: + devcb_write_line irq_handler; + const char *cputag; + virtual void device_start(); + virtual void device_config_complete(); +}; + +class oricext_device : public device_t, + public device_slot_card_interface +{ +public: + oricext_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + void set_cputag(const char *tag); + DECLARE_WRITE_LINE_MEMBER(irq_w); + +protected: + const char *cputag; + m6502_device *cpu; + oricext_connector *connector; + memory_bank *bank_c000_r, *bank_e000_r, *bank_f800_r, *bank_c000_w, *bank_e000_w, *bank_f800_w; + UINT8 *rom, *ram; + UINT8 junk_read[8192], junk_write[8192]; + + virtual void device_start(); +}; + +extern const device_type ORICEXT_CONNECTOR; +SLOT_INTERFACE_EXTERN( oricext_intf ); + +#endif /* __ORICEXT_H__ */ diff --git a/src/devices/bus/pc_joy/pc_joy.c b/src/devices/bus/pc_joy/pc_joy.c new file mode 100644 index 00000000000..99c3f5c1957 --- /dev/null +++ b/src/devices/bus/pc_joy/pc_joy.c @@ -0,0 +1,93 @@ +// license:BSD-3-Clause +// copyright-holders:Carl +/************************************************************************* + * + * pc_joy.h + * + * joystick port + * + *************************************************************************/ + +#include "pc_joy.h" +#include "pc_joy_sw.h" + +const device_type PC_JOY = &device_creator; + +pc_joy_device::pc_joy_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, PC_JOY, "PC joystick port", tag, owner, clock, "pc_joy", __FILE__), + device_slot_interface(mconfig, *this) +{ +} + +READ8_MEMBER ( pc_joy_device::joy_port_r ) +{ + int delta = ((machine().time() - m_stime) * 256 * 1000).seconds(); + + if(!m_dev) + return 0xf0; + + return (m_dev->btn() << 4) | (m_dev->y2(delta) << 3) | (m_dev->x2(delta) << 2) | (m_dev->y1(delta) << 1) | m_dev->x1(delta); +} + +WRITE8_MEMBER ( pc_joy_device::joy_port_w ) +{ + m_stime = machine().time(); + m_dev->port_write(); +} + +void pc_joy_device::device_config_complete() +{ + m_dev = dynamic_cast(get_card_device()); +} + +device_pc_joy_interface::device_pc_joy_interface(const machine_config &mconfig, device_t &device) : + device_slot_card_interface(mconfig, device) +{ +} + +device_pc_joy_interface::~device_pc_joy_interface() +{ +} + +static INPUT_PORTS_START( pc_joystick ) + PORT_START("btn") + PORT_BIT( 0x1, IP_ACTIVE_LOW, IPT_BUTTON1) PORT_NAME("Joystick 1 Button 1") + PORT_BIT( 0x2, IP_ACTIVE_LOW, IPT_BUTTON2) PORT_NAME("Joystick 1 Button 2") + PORT_BIT( 0x4, IP_ACTIVE_LOW, IPT_BUTTON1) PORT_NAME("Joystick 2 Button 1") PORT_CODE(JOYCODE_BUTTON1) PORT_PLAYER(2) + PORT_BIT( 0x8, IP_ACTIVE_LOW, IPT_BUTTON2) PORT_NAME("Joystick 2 Button 2") PORT_CODE(JOYCODE_BUTTON2) PORT_PLAYER(2) + + PORT_START("x1") + PORT_BIT(0xff,0x80,IPT_AD_STICK_X) PORT_SENSITIVITY(100) PORT_KEYDELTA(1) PORT_MINMAX(1,0xff) PORT_CODE_DEC(KEYCODE_LEFT) PORT_CODE_INC(KEYCODE_RIGHT) PORT_CODE_DEC(JOYCODE_X_LEFT_SWITCH) PORT_CODE_INC(JOYCODE_X_RIGHT_SWITCH) + + PORT_START("y1") + PORT_BIT(0xff,0x80,IPT_AD_STICK_Y) PORT_SENSITIVITY(100) PORT_KEYDELTA(1) PORT_MINMAX(1,0xff) PORT_CODE_DEC(KEYCODE_UP) PORT_CODE_INC(KEYCODE_DOWN) PORT_CODE_DEC(JOYCODE_Y_UP_SWITCH) PORT_CODE_INC(JOYCODE_Y_DOWN_SWITCH) + + PORT_START("x2") + PORT_BIT(0xff,0x80,IPT_AD_STICK_X) PORT_SENSITIVITY(100) PORT_KEYDELTA(1) PORT_MINMAX(1,0xff) PORT_CODE_DEC(JOYCODE_X_LEFT_SWITCH) PORT_CODE_INC(JOYCODE_X_RIGHT_SWITCH) PORT_PLAYER(2) + + PORT_START("y2") + PORT_BIT(0xff,0x80,IPT_AD_STICK_Y) PORT_SENSITIVITY(100) PORT_KEYDELTA(1) PORT_MINMAX(1,0xff) PORT_CODE_DEC(JOYCODE_Y_UP_SWITCH) PORT_CODE_INC(JOYCODE_Y_DOWN_SWITCH) PORT_PLAYER(2) +INPUT_PORTS_END + +ioport_constructor pc_basic_joy_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( pc_joystick ); +} + +const device_type PC_BASIC_JOY = &device_creator; + +pc_basic_joy_device::pc_basic_joy_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, PC_BASIC_JOY, "PC basic joystick", tag, owner, clock, "basic_joy", __FILE__), + device_pc_joy_interface(mconfig, *this), + m_btn(*this, "btn"), + m_x1(*this, "x1"), + m_y1(*this, "y1"), + m_x2(*this, "x2"), + m_y2(*this, "y2") +{ +} + +SLOT_INTERFACE_START(pc_joysticks) + SLOT_INTERFACE("basic_joy", PC_BASIC_JOY) + SLOT_INTERFACE("mssw_pad", PC_MSSW_PAD) +SLOT_INTERFACE_END diff --git a/src/devices/bus/pc_joy/pc_joy.h b/src/devices/bus/pc_joy/pc_joy.h new file mode 100644 index 00000000000..f67e74ff003 --- /dev/null +++ b/src/devices/bus/pc_joy/pc_joy.h @@ -0,0 +1,78 @@ +// license:BSD-3-Clause +// copyright-holders:Carl +/************************************************************************* + * + * pc_joy.h + * + * joystick port + * + *************************************************************************/ + +#ifndef PC_JOY_H +#define PC_JOY_H + +#include "emu.h" + +#define MCFG_PC_JOY_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, PC_JOY, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(pc_joysticks, "basic_joy", false) + +SLOT_INTERFACE_EXTERN(pc_joysticks); + +class device_pc_joy_interface: public device_slot_card_interface +{ +public: + device_pc_joy_interface(const machine_config &mconfig, device_t &device); + virtual ~device_pc_joy_interface(); + + virtual UINT8 x1(int delta) { return 0; } + virtual UINT8 x2(int delta) { return 0; } + virtual UINT8 y1(int delta) { return 0; } + virtual UINT8 y2(int delta) { return 0; } + virtual UINT8 btn() { return 0xf; } + virtual void port_write() { } +}; + +class pc_joy_device : public device_t, + public device_slot_interface +{ +public: + pc_joy_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + DECLARE_READ8_MEMBER(joy_port_r); + DECLARE_WRITE8_MEMBER(joy_port_w); +protected: + virtual void device_start() { m_stime = machine().time(); } + virtual void device_config_complete(); +private: + attotime m_stime; + device_pc_joy_interface *m_dev; +}; + +extern const device_type PC_JOY; + +class pc_basic_joy_device : public device_t, + public device_pc_joy_interface +{ +public: + pc_basic_joy_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual ioport_constructor device_input_ports() const; + + virtual UINT8 x1(int delta) { return (m_x1->read() > delta); } + virtual UINT8 x2(int delta) { return (m_x2->read() > delta); } + virtual UINT8 y1(int delta) { return (m_y1->read() > delta); } + virtual UINT8 y2(int delta) { return (m_y2->read() > delta); } + virtual UINT8 btn() { return m_btn->read(); } + +protected: + virtual void device_start() {} + +private: + required_ioport m_btn; + required_ioport m_x1; + required_ioport m_y1; + required_ioport m_x2; + required_ioport m_y2; +}; + +#endif /* PC_JOY_H */ diff --git a/src/devices/bus/pc_joy/pc_joy_sw.c b/src/devices/bus/pc_joy/pc_joy_sw.c new file mode 100644 index 00000000000..ebfb1af785b --- /dev/null +++ b/src/devices/bus/pc_joy/pc_joy_sw.c @@ -0,0 +1,177 @@ +// license:BSD-3-Clause +// copyright-holders:Carl +//TODO: determine when to switch modes and add single bit mode + +#include "pc_joy_sw.h" + +const device_type PC_MSSW_PAD = &device_creator; + +pc_mssw_pad_device::pc_mssw_pad_device(const machine_config& mconfig, const char* tag, device_t* owner, UINT32 clock) : + device_t(mconfig, PC_MSSW_PAD, "Microsoft Sidewinder Pad", tag, owner, clock, "mssw_pad", __FILE__), + device_pc_joy_interface(mconfig, *this), + m_btn1(*this, "btn1"), + m_btn2(*this, "btn2"), + m_btn3(*this, "btn3"), + m_btn4(*this, "btn4"), + m_conf(*this, "CONFIG") +{ +} + +void pc_mssw_pad_device::device_start() +{ + m_timer = timer_alloc(); +} + +void pc_mssw_pad_device::device_reset() +{ + m_count = 0; + m_state = 0xf; + m_active = false; + m_timer->adjust(attotime::never, 0); +} + +void pc_mssw_pad_device::device_timer(emu_timer &timer, device_timer_id tid, int param, void *ptr) +{ + UINT16 pad_state = 0; + // only multibit mode for now + if(m_count == -1) + { + reset(); + return; + } + + if((m_count / 5) > m_conf->read()) + { + m_timer->adjust(attotime::from_usec(50), 0); + m_state &= ~1; + m_count = -1; + return; + } + + if(m_state & 1) + { + m_state &= ~1; + return; + } + + switch(m_count / 5) + { + case 0: + pad_state = m_btn1->read(); + break; + case 1: + pad_state = m_btn2->read(); + break; + case 2: + pad_state = m_btn3->read(); + break; + case 3: + pad_state = m_btn4->read(); + break; + } + + switch(m_count % 5) + { + case 0: + m_state = ((pad_state & 7) << 1) | 1; + break; + case 1: + m_state = ((pad_state & 0x38) >> 2) | 1; + break; + case 2: + m_state = ((pad_state & 0x1c0) >> 5) | 1; + break; + case 3: + m_state = ((pad_state & 0xe00) >> 8) | 1; + break; + case 4: + { + UINT8 parity = (pad_state >> 8) ^ pad_state; + parity = (parity >> 4) ^ parity; + parity = (parity >> 2) ^ parity; + parity = (((parity >> 1) ^ parity) & 1); + + m_state = ((pad_state & 0x3000) >> 11) | (parity << 3) | 1; + break; + } + } + m_count++; +} + +static INPUT_PORTS_START( sidewinder_pad ) + PORT_START("btn1") + PORT_BIT( 0x0001, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) + PORT_BIT( 0x0002, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) + PORT_BIT( 0x0004, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) + PORT_BIT( 0x0008, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) + PORT_BIT( 0x0010, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_NAME("A") + PORT_BIT( 0x0020, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_NAME("B") + PORT_BIT( 0x0040, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_NAME("C") + PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_NAME("X") + PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_BUTTON5 ) PORT_NAME("Y") + PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_BUTTON6 ) PORT_NAME("Z") + PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_BUTTON7 ) PORT_NAME("L") + PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_BUTTON8 ) PORT_NAME("R") + PORT_BIT( 0x1000, IP_ACTIVE_LOW, IPT_BUTTON9 ) PORT_NAME("Start") + PORT_BIT( 0x2000, IP_ACTIVE_LOW, IPT_BUTTON10 ) PORT_NAME("M") + PORT_BIT( 0xc000, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_START("btn2") + PORT_BIT( 0x0001, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_PLAYER(2) + PORT_BIT( 0x0002, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_PLAYER(2) + PORT_BIT( 0x0004, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(2) + PORT_BIT( 0x0008, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_PLAYER(2) + PORT_BIT( 0x0010, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_NAME("A") PORT_PLAYER(2) + PORT_BIT( 0x0020, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_NAME("B") PORT_PLAYER(2) + PORT_BIT( 0x0040, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_NAME("C") PORT_PLAYER(2) + PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_NAME("X") PORT_PLAYER(2) + PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_BUTTON5 ) PORT_NAME("Y") PORT_PLAYER(2) + PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_BUTTON6 ) PORT_NAME("Z") PORT_PLAYER(2) + PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_BUTTON7 ) PORT_NAME("L") PORT_PLAYER(2) + PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_BUTTON8 ) PORT_NAME("R") PORT_PLAYER(2) + PORT_BIT( 0x1000, IP_ACTIVE_LOW, IPT_BUTTON9 ) PORT_NAME("Start") PORT_PLAYER(2) + PORT_BIT( 0x2000, IP_ACTIVE_LOW, IPT_BUTTON10 ) PORT_NAME("M") PORT_PLAYER(2) + PORT_BIT( 0xc000, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_START("btn3") + PORT_BIT( 0x0001, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_PLAYER(3) + PORT_BIT( 0x0002, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_PLAYER(3) + PORT_BIT( 0x0004, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(3) + PORT_BIT( 0x0008, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_PLAYER(3) + PORT_BIT( 0x0010, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_NAME("A") PORT_PLAYER(3) + PORT_BIT( 0x0020, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_NAME("B") PORT_PLAYER(3) + PORT_BIT( 0x0040, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_NAME("C") PORT_PLAYER(3) + PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_NAME("X") PORT_PLAYER(3) + PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_BUTTON5 ) PORT_NAME("Y") PORT_PLAYER(3) + PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_BUTTON6 ) PORT_NAME("Z") PORT_PLAYER(3) + PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_BUTTON7 ) PORT_NAME("L") PORT_PLAYER(3) + PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_BUTTON8 ) PORT_NAME("R") PORT_PLAYER(3) + PORT_BIT( 0x1000, IP_ACTIVE_LOW, IPT_BUTTON9 ) PORT_NAME("Start") PORT_PLAYER(3) + PORT_BIT( 0x2000, IP_ACTIVE_LOW, IPT_BUTTON10 ) PORT_NAME("M") PORT_PLAYER(3) + PORT_BIT( 0xc000, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_START("btn4") + PORT_BIT( 0x0001, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_PLAYER(4) + PORT_BIT( 0x0002, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_PLAYER(4) + PORT_BIT( 0x0004, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(4) + PORT_BIT( 0x0008, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_PLAYER(4) + PORT_BIT( 0x0010, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_NAME("A") PORT_PLAYER(4) + PORT_BIT( 0x0020, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_NAME("B") PORT_PLAYER(4) + PORT_BIT( 0x0040, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_NAME("C") PORT_PLAYER(4) + PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_NAME("X") PORT_PLAYER(4) + PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_BUTTON5 ) PORT_NAME("Y") PORT_PLAYER(4) + PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_BUTTON6 ) PORT_NAME("Z") PORT_PLAYER(4) + PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_BUTTON7 ) PORT_NAME("L") PORT_PLAYER(4) + PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_BUTTON8 ) PORT_NAME("R") PORT_PLAYER(4) + PORT_BIT( 0x1000, IP_ACTIVE_LOW, IPT_BUTTON9 ) PORT_NAME("Start") PORT_PLAYER(4) + PORT_BIT( 0x2000, IP_ACTIVE_LOW, IPT_BUTTON10 ) PORT_NAME("M") PORT_PLAYER(4) + PORT_BIT( 0xc000, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_START("CONFIG") + PORT_CONFNAME(0x03, 0x00, "Number of Sidewinder Pads") + PORT_CONFSETTING( 0x00, "1") + PORT_CONFSETTING( 0x01, "2") + PORT_CONFSETTING( 0x02, "3") + PORT_CONFSETTING( 0x03, "4") +INPUT_PORTS_END + +ioport_constructor pc_mssw_pad_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( sidewinder_pad ); +} diff --git a/src/devices/bus/pc_joy/pc_joy_sw.h b/src/devices/bus/pc_joy/pc_joy_sw.h new file mode 100644 index 00000000000..12506ef1f1b --- /dev/null +++ b/src/devices/bus/pc_joy/pc_joy_sw.h @@ -0,0 +1,38 @@ +// license:BSD-3-Clause +// copyright-holders:Carl +#ifndef PC_JOY_SW_H_ +#define PC_JOY_SW_H_ + +#include "pc_joy.h" + +class pc_mssw_pad_device : public device_t, + public device_pc_joy_interface +{ +public: + pc_mssw_pad_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual ioport_constructor device_input_ports() const; + + virtual UINT8 btn() { return m_state; } + // timing is guessed, calibrated for at486 + virtual void port_write() { if(!m_active) { m_timer->adjust(attotime::from_usec(50), 0, attotime::from_usec(5)); m_active = true; } } + +protected: + virtual void device_start(); + virtual void device_timer(emu_timer &timer, device_timer_id tid, int param, void *ptr); + virtual void device_reset(); + +private: + required_ioport m_btn1; + required_ioport m_btn2; + required_ioport m_btn3; + required_ioport m_btn4; + required_ioport m_conf; + emu_timer *m_timer; + int m_count; + UINT8 m_state; + bool m_active; +}; + +extern const device_type PC_MSSW_PAD; + +#endif /* PC_JOY_SW_H_ */ diff --git a/src/devices/bus/pc_kbd/ec1841.c b/src/devices/bus/pc_kbd/ec1841.c new file mode 100644 index 00000000000..54c4d6b3a97 --- /dev/null +++ b/src/devices/bus/pc_kbd/ec1841.c @@ -0,0 +1,486 @@ +// license:BSD-3-Clause +// copyright-holders:Sergey Svishchev +/********************************************************************** + + EC-1841 92-key keyboard emulation + + Sends 9 non-standard scan codes (54..5C) and reassigns 3 standard + ones (2A, 36, 3A). EC-1841 BIOS converts scan codes into Cyrillic + by default; 'Lat' key (mapped to F11) switches it to Latin mode. + 'Rus' (F12) switches back. + +*********************************************************************/ + +#include "ec1841.h" + +#define VERBOSE_DBG 0 /* general debug messages */ + +#define DBG_LOG(N,M,A) \ + do { \ + if(VERBOSE_DBG>=N) \ + { \ + logerror("%11.6f at %s: ",machine().time().as_double(),machine().describe_context()); \ + logerror A; \ + } \ + } while (0) + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define I8048_TAG "i8048" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type PC_KBD_EC_1841 = &device_creator; + + +//------------------------------------------------- +// ROM( ec_1841_keyboard ) +//------------------------------------------------- + +ROM_START( ec_1841_keyboard ) + ROM_REGION( 0x400, I8048_TAG, 0 ) + ROM_LOAD( "1816be48.bin", 0x000, 0x400, CRC(e9abfe44) SHA1(1db430c72c2d007ea0b8ae2514ff15c96baba308) ) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *ec_1841_keyboard_device::device_rom_region() const +{ + return ROM_NAME( ec_1841_keyboard ); +} + + +//------------------------------------------------- +// ADDRESS_MAP( kb_io ) +//------------------------------------------------- + +static ADDRESS_MAP_START( ec_1841_keyboard_io, AS_IO, 8, ec_1841_keyboard_device ) + AM_RANGE(MCS48_PORT_BUS, MCS48_PORT_BUS) AM_WRITE(bus_w) + AM_RANGE(MCS48_PORT_P1, MCS48_PORT_P1) AM_READWRITE(p1_r, p1_w) + AM_RANGE(MCS48_PORT_P2, MCS48_PORT_P2) AM_WRITE(p2_w) + AM_RANGE(MCS48_PORT_T1, MCS48_PORT_T1) AM_READ(t1_r) +ADDRESS_MAP_END + + +//------------------------------------------------- +// MACHINE_DRIVER( ec_1841_keyboard ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( ec_1841_keyboard ) + MCFG_CPU_ADD(I8048_TAG, I8048, XTAL_5_46MHz) + MCFG_CPU_IO_MAP(ec_1841_keyboard_io) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor ec_1841_keyboard_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( ec_1841_keyboard ); +} + + +//------------------------------------------------- +// INPUT_PORTS( ec_1841_keyboard ) +//------------------------------------------------- + +INPUT_PORTS_START( ec_1841_keyboard ) + PORT_START("MD00") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_TAB) PORT_CHAR(UCHAR_MAMEKEY(TAB)) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_A) PORT_CHAR('a') PORT_CHAR('A') + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Z) PORT_CHAR('z') PORT_CHAR('Z') + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Inf") PORT_CODE(KEYCODE_SLASH_PAD) PORT_CHAR(UCHAR_MAMEKEY(SLASH_PAD)) // 0x59 + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_MINUS_PAD) PORT_CHAR(UCHAR_MAMEKEY(MINUS_PAD)) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNUSED ) + + PORT_START("MD01") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_ESC) PORT_CHAR(UCHAR_MAMEKEY(ESC)) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Q) PORT_CHAR('q') PORT_CHAR('Q') + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_S) PORT_CHAR('s') PORT_CHAR('S') + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_X) PORT_CHAR('x') PORT_CHAR('X') + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_SPACE) PORT_CHAR(' ') + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad 7 Home") PORT_CODE(KEYCODE_7_PAD) PORT_CHAR(UCHAR_MAMEKEY(7_PAD)) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNUSED ) + + PORT_START("MD02") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_1) PORT_CHAR('1') PORT_CHAR('!') + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_W) PORT_CHAR('w') PORT_CHAR('W') + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_D) PORT_CHAR('d') PORT_CHAR('D') + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_C) PORT_CHAR('c') PORT_CHAR('C') + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_RCONTROL) // 0x5a = R/L (R) + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad 8 " UTF8_UP) PORT_CODE(KEYCODE_8_PAD) PORT_CHAR(UCHAR_MAMEKEY(8_PAD)) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNUSED ) + + PORT_START("MD03") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_2) PORT_CHAR('2') PORT_CHAR('@') + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_E) PORT_CHAR('e') PORT_CHAR('E') + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F) PORT_CHAR('f') PORT_CHAR('F') + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_V) PORT_CHAR('v') PORT_CHAR('V') + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F12) PORT_CHAR(UCHAR_MAMEKEY(F12)) // 0x5b = Rus + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad 9 PgUp") PORT_CODE(KEYCODE_9_PAD) PORT_CHAR(UCHAR_MAMEKEY(9_PAD)) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNUSED ) + + PORT_START("MD04") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_3) PORT_CHAR('3') PORT_CHAR('#') + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_R) PORT_CHAR('r') PORT_CHAR('R') + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_G) PORT_CHAR('g') PORT_CHAR('G') + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_B) PORT_CHAR('b') PORT_CHAR('B') + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F1) PORT_CHAR(UCHAR_MAMEKEY(F1)) + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad 4 " UTF8_LEFT) PORT_CODE(KEYCODE_4_PAD) PORT_CHAR(UCHAR_MAMEKEY(4_PAD)) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNUSED ) + + PORT_START("MD05") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_4) PORT_CHAR('4') PORT_CHAR('$') + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_T) PORT_CHAR('t') PORT_CHAR('T') + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_H) PORT_CHAR('h') PORT_CHAR('H') + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_N) PORT_CHAR('n') PORT_CHAR('N') + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F2) PORT_CHAR(UCHAR_MAMEKEY(F2)) + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_5_PAD) PORT_CHAR(UCHAR_MAMEKEY(5_PAD)) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNUSED ) + + PORT_START("MD06") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_5) PORT_CHAR('5') PORT_CHAR('%') + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Y) PORT_CHAR('y') PORT_CHAR('Y') + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_J) PORT_CHAR('j') PORT_CHAR('J') + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_M) PORT_CHAR('m') PORT_CHAR('M') + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F3) PORT_CHAR(UCHAR_MAMEKEY(F3)) + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad 6 " UTF8_RIGHT) PORT_CODE(KEYCODE_6_PAD) PORT_CHAR(UCHAR_MAMEKEY(6_PAD)) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNUSED ) + + PORT_START("MD07") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_6) PORT_CHAR('6') PORT_CHAR('^') + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_U) PORT_CHAR('u') PORT_CHAR('U') + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_K) PORT_CHAR('k') PORT_CHAR('K') + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_TILDE) PORT_CHAR('`') PORT_CHAR('~') + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F4) PORT_CHAR(UCHAR_MAMEKEY(F4)) + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad 1 End") PORT_CODE(KEYCODE_1_PAD) PORT_CHAR(UCHAR_MAMEKEY(1_PAD)) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNUSED ) + + PORT_START("MD08") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_7) PORT_CHAR('7') PORT_CHAR('&') + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_I) PORT_CHAR('i') PORT_CHAR('I') + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_L) PORT_CHAR('l') PORT_CHAR('L') + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("?2a?") + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F5) PORT_CHAR(UCHAR_MAMEKEY(F5)) + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad 2 " UTF8_DOWN) PORT_CODE(KEYCODE_2_PAD) PORT_CHAR(UCHAR_MAMEKEY(2_PAD)) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNUSED ) + + PORT_START("MD09") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_8) PORT_CHAR('8') PORT_CHAR('*') + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_O) PORT_CHAR('o') PORT_CHAR('O') + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_OPENBRACE) PORT_CHAR('[') PORT_CHAR('{') + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("?5c?") // 0x5c = YO + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F6) PORT_CHAR(UCHAR_MAMEKEY(F6)) + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad 3 PgDn") PORT_CODE(KEYCODE_3_PAD) PORT_CHAR(UCHAR_MAMEKEY(3_PAD)) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNUSED ) + + PORT_START("MD10") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_9) PORT_CHAR('9') PORT_CHAR('(') + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_P) PORT_CHAR('p') PORT_CHAR('P') + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_CLOSEBRACE) PORT_CHAR(']') PORT_CHAR('}') + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_COMMA) PORT_CHAR(',') PORT_CHAR('<') + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F7) PORT_CHAR(UCHAR_MAMEKEY(F7)) + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad 0 Ins") PORT_CODE(KEYCODE_0_PAD) PORT_CHAR(UCHAR_MAMEKEY(0_PAD)) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNUSED ) + + PORT_START("MD11") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_0) PORT_CHAR('0') PORT_CHAR(')') + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("?36?") + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_COLON) PORT_CHAR(';') PORT_CHAR(':') + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_STOP) PORT_CHAR('.') PORT_CHAR('>') + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F8) PORT_CHAR(UCHAR_MAMEKEY(F8)) + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad . Del") PORT_CODE(KEYCODE_DEL_PAD) PORT_CHAR(UCHAR_MAMEKEY(DEL_PAD)) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNUSED ) + + PORT_START("MD12") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_MINUS) PORT_CHAR('-') PORT_CHAR('_') + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("?3a?") + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_QUOTE) PORT_CHAR('\'') PORT_CHAR('"') + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_RSHIFT) PORT_CHAR(UCHAR_SHIFT_1) // 0x55 + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F9) PORT_CHAR(UCHAR_MAMEKEY(F9)) + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_PLUS_PAD) PORT_CHAR(UCHAR_MAMEKEY(PLUS_PAD)) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNUSED ) + + PORT_START("MD13") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_EQUALS) PORT_CHAR('=') PORT_CHAR('+') + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_SLASH) PORT_CHAR('/') PORT_CHAR('?') + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_ENTER) PORT_CHAR(13) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_CAPSLOCK) PORT_CHAR(UCHAR_MAMEKEY(CAPSLOCK)) // 0x56 + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F10) PORT_CHAR(UCHAR_MAMEKEY(F10)) + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNUSED ) + + PORT_START("MD14") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_BACKSLASH) PORT_CHAR('\\') PORT_CHAR('|') + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_PRTSCR) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_LALT) PORT_CHAR(UCHAR_MAMEKEY(LALT)) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F11) PORT_CHAR(UCHAR_MAMEKEY(F11)) // 0x57 = Lat + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_NUMLOCK) PORT_CHAR(UCHAR_MAMEKEY(NUMLOCK)) + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNUSED ) + + PORT_START("MD15") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_BACKSPACE) PORT_CHAR(8) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_LCONTROL) PORT_CHAR(UCHAR_SHIFT_2) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_LSHIFT) PORT_CHAR(UCHAR_SHIFT_1) // 0x54 + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_RALT) // 0x58 = R/L (L) + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Scroll Lock Break") PORT_CODE(KEYCODE_SCRLOCK) PORT_CHAR(UCHAR_MAMEKEY(SCRLOCK)) + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNUSED ) +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor ec_1841_keyboard_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( ec_1841_keyboard ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// ec_1841_keyboard_device - constructor +//------------------------------------------------- + +ec_1841_keyboard_device::ec_1841_keyboard_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, PC_KBD_EC_1841, "EC-1841 Keyboard", tag, owner, clock, "kb_ec1841", __FILE__), + device_pc_kbd_interface(mconfig, *this), + m_maincpu(*this, I8048_TAG), + m_md00(*this, "MD00"), + m_md01(*this, "MD01"), + m_md02(*this, "MD02"), + m_md03(*this, "MD03"), + m_md04(*this, "MD04"), + m_md05(*this, "MD05"), + m_md06(*this, "MD06"), + m_md07(*this, "MD07"), + m_md08(*this, "MD08"), + m_md09(*this, "MD09"), + m_md10(*this, "MD10"), + m_md11(*this, "MD11"), + m_md12(*this, "MD12"), + m_md13(*this, "MD13"), + m_md14(*this, "MD14"), + m_md15(*this, "MD15"), + m_bus(0xff), + m_p1(0xff), + m_p2(0xff), + m_q(1) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void ec_1841_keyboard_device::device_start() +{ + set_pc_kbdc_device(); + + // state saving + save_item(NAME(m_bus)); + save_item(NAME(m_p1)); + save_item(NAME(m_p2)); + save_item(NAME(m_q)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void ec_1841_keyboard_device::device_reset() +{ +} + + +//------------------------------------------------- +// clock_write - +//------------------------------------------------- + +WRITE_LINE_MEMBER( ec_1841_keyboard_device::clock_write ) +{ + DBG_LOG(1,0,( "%s: clock write %d\n", tag(), state)); +} + + +//------------------------------------------------- +// data_write - +//------------------------------------------------- + +WRITE_LINE_MEMBER( ec_1841_keyboard_device::data_write ) +{ + DBG_LOG(1,0,( "%s: data write %d\n", tag(), state)); +} + + +//------------------------------------------------- +// bus_w - +//------------------------------------------------- + +WRITE8_MEMBER( ec_1841_keyboard_device::bus_w ) +{ + DBG_LOG(2,0,( "%s: bus_w %02x\n", tag(), data)); + + m_bus = data; +} + + +//------------------------------------------------- +// p1_r - +//------------------------------------------------- + +READ8_MEMBER( ec_1841_keyboard_device::p1_r ) +{ + /* + + bit description + + 0 -REQ IN + 1 DATA IN + 2 + 3 + 4 + 5 + 6 + 7 + + */ + + UINT8 data = 0; + + data |= clock_signal(); + data |= data_signal() << 1; + + DBG_LOG(1,0,( "%s: p1_r %02x\n", tag(), data)); + + return data; +} + + +//------------------------------------------------- +// p1_w - +//------------------------------------------------- + +WRITE8_MEMBER( ec_1841_keyboard_device::p1_w ) +{ + /* + bit description + + 0 + 1 + 2 + 3 + 4 + 5 LED XXX + 6 LED XXX + 7 LED XXX + */ + DBG_LOG(1,0,( "%s: p1_w %02x\n", tag(), data)); + + m_p1 = data; +} + + +//------------------------------------------------- +// p2_w - +//------------------------------------------------- + +WRITE8_MEMBER( ec_1841_keyboard_device::p2_w ) +{ + /* + bit description + + 0 -STROBE (to matrix mux) + 1 XXX CLOCK out 1 + 2 XXX DATA out 1 + 3 + 4 + 5 XXX DATA out 2? + 6 XXX CLOCK out 2? + 7 XXX + */ + DBG_LOG(1,0,( "%s: p2_w %02x\n", tag(), data)); + + m_pc_kbdc->data_write_from_kb(BIT(data, 2)); + m_pc_kbdc->clock_write_from_kb(BIT(data, 1)); + + m_p2 = data; +} + + +//------------------------------------------------- +// t1_r - +//------------------------------------------------- + +READ8_MEMBER( ec_1841_keyboard_device::t1_r ) +{ + if (BIT(m_p2,0)) { + m_q = 1; + } else { + UINT8 sense = 0xff; + + switch(m_bus & 15) { + case 0: sense &= m_md00->read(); break; + case 1: sense &= m_md01->read(); break; + case 2: sense &= m_md02->read(); break; + case 3: sense &= m_md03->read(); break; + case 4: sense &= m_md04->read(); break; + case 5: sense &= m_md05->read(); break; + case 6: sense &= m_md06->read(); break; + case 7: sense &= m_md07->read(); break; + case 8: sense &= m_md08->read(); break; + case 9: sense &= m_md09->read(); break; + case 10: sense &= m_md10->read(); break; + case 11: sense &= m_md11->read(); break; + case 12: sense &= m_md12->read(); break; + case 13: sense &= m_md13->read(); break; + case 14: sense &= m_md14->read(); break; + case 15: sense &= m_md15->read(); break; + } + m_q = BIT(sense, (m_bus >> 4) & 7); + } + + DBG_LOG(1,0,( "%s: bus %02X t1_r %d\n", tag(), m_bus, m_q)); + + return m_q; +} diff --git a/src/devices/bus/pc_kbd/ec1841.h b/src/devices/bus/pc_kbd/ec1841.h new file mode 100644 index 00000000000..20c8e74a5d6 --- /dev/null +++ b/src/devices/bus/pc_kbd/ec1841.h @@ -0,0 +1,82 @@ +// license:BSD-3-Clause +// copyright-holders:Sergey Svishchev +/********************************************************************** + + EC-1841 92-key keyboard emulation + +*********************************************************************/ + +#pragma once + +#ifndef __PC_KBD_EC_1841__ +#define __PC_KBD_EC_1841__ + +#include "emu.h" +#include "cpu/mcs48/mcs48.h" +#include "pc_kbdc.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> ec_1841_keyboard_device + +class ec_1841_keyboard_device : public device_t, + public device_pc_kbd_interface +{ +public: + // construction/destruction + ec_1841_keyboard_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + virtual ioport_constructor device_input_ports() const; + + DECLARE_WRITE8_MEMBER( bus_w ); + DECLARE_READ8_MEMBER( p1_r ); + DECLARE_WRITE8_MEMBER( p1_w ); + DECLARE_WRITE8_MEMBER( p2_w ); + DECLARE_READ8_MEMBER( t1_r ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_pc_kbd_interface overrides + virtual DECLARE_WRITE_LINE_MEMBER( clock_write ); + virtual DECLARE_WRITE_LINE_MEMBER( data_write ); + +private: + required_device m_maincpu; + required_ioport m_md00; + required_ioport m_md01; + required_ioport m_md02; + required_ioport m_md03; + required_ioport m_md04; + required_ioport m_md05; + required_ioport m_md06; + required_ioport m_md07; + required_ioport m_md08; + required_ioport m_md09; + required_ioport m_md10; + required_ioport m_md11; + required_ioport m_md12; + required_ioport m_md13; + required_ioport m_md14; + required_ioport m_md15; + + UINT8 m_bus; + UINT8 m_p1; + UINT8 m_p2; + int m_q; +}; + + +// device type definition +extern const device_type PC_KBD_EC_1841; + +#endif diff --git a/src/devices/bus/pc_kbd/iskr1030.c b/src/devices/bus/pc_kbd/iskr1030.c new file mode 100644 index 00000000000..ecee5639129 --- /dev/null +++ b/src/devices/bus/pc_kbd/iskr1030.c @@ -0,0 +1,500 @@ +// license:BSD-3-Clause +// copyright-holders:Sergey Svishchev +/********************************************************************** + + Iskra-1030 and -1031 XX-key keyboard emulation + +*********************************************************************/ + +#include "iskr1030.h" + +#define VERBOSE_DBG 1 /* general debug messages */ + +#define DBG_LOG(N,M,A) \ + do { \ + if(VERBOSE_DBG>=N) \ + { \ + logerror("%11.6f at %s: ",machine().time().as_double(),machine().describe_context()); \ + logerror A; \ + } \ + } while (0) + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define I8048_TAG "i8048" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type PC_KBD_ISKR_1030 = &device_creator; + + +//------------------------------------------------- +// ROM( iskr_1030_keyboard ) +//------------------------------------------------- + +ROM_START( iskr_1030_keyboard ) + ROM_REGION( 0x800, I8048_TAG, 0 ) + ROM_LOAD( "i1030.bin", 0x000, 0x800, CRC(7cac9c4b) SHA1(03959d3350e012ebfe61cee9c062b6c1fdd8766e) ) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *iskr_1030_keyboard_device::device_rom_region() const +{ + return ROM_NAME( iskr_1030_keyboard ); +} + + +//------------------------------------------------- +// ADDRESS_MAP( kb_io ) +//------------------------------------------------- + +static ADDRESS_MAP_START( iskr_1030_keyboard_io, AS_IO, 8, iskr_1030_keyboard_device ) + AM_RANGE(0x00, 0xFF) AM_READWRITE(ram_r, ram_w) + AM_RANGE(MCS48_PORT_P1, MCS48_PORT_P1) AM_READWRITE(p1_r, p1_w) + AM_RANGE(MCS48_PORT_P2, MCS48_PORT_P2) AM_WRITE(p2_w) + AM_RANGE(MCS48_PORT_T1, MCS48_PORT_T1) AM_READ(t1_r) +ADDRESS_MAP_END + + +//------------------------------------------------- +// MACHINE_DRIVER( iskr_1030_keyboard ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( iskr_1030_keyboard ) + MCFG_CPU_ADD(I8048_TAG, I8048, XTAL_5MHz) + MCFG_CPU_IO_MAP(iskr_1030_keyboard_io) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor iskr_1030_keyboard_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( iskr_1030_keyboard ); +} + + +//------------------------------------------------- +// INPUT_PORTS( iskr_1030_keyboard ) +//------------------------------------------------- + +INPUT_PORTS_START( iskr_1030_keyboard ) + PORT_START("MD00") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) + + PORT_START("MD01") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) + + PORT_START("MD02") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) + + PORT_START("MD03") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) + + PORT_START("MD04") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) + + PORT_START("MD05") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) + + PORT_START("MD06") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) + + PORT_START("MD07") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) + + PORT_START("MD08") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) + + PORT_START("MD09") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) + + PORT_START("MD10") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) + + PORT_START("MD11") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) + + PORT_START("MD12") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) + + PORT_START("MD13") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) + + PORT_START("MD14") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) + + PORT_START("MD15") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) + + PORT_START("MD16") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) + + PORT_START("MD17") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) + + PORT_START("MD18") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) + + PORT_START("MD19") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) + + PORT_START("MD20") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) + + PORT_START("MD21") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) + + PORT_START("MD22") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) + + PORT_START("MD23") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor iskr_1030_keyboard_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( iskr_1030_keyboard ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// iskr_1030_keyboard_device - constructor +//------------------------------------------------- + +iskr_1030_keyboard_device::iskr_1030_keyboard_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, PC_KBD_ISKR_1030, "Iskra-1030 Keyboard", tag, owner, clock, "kb_iskr1030", __FILE__), + device_pc_kbd_interface(mconfig, *this), + m_maincpu(*this, I8048_TAG), + m_md00(*this, "MD00"), + m_md01(*this, "MD01"), + m_md02(*this, "MD02"), + m_md03(*this, "MD03"), + m_md04(*this, "MD04"), + m_md05(*this, "MD05"), + m_md06(*this, "MD06"), + m_md07(*this, "MD07"), + m_md08(*this, "MD08"), + m_md09(*this, "MD09"), + m_md10(*this, "MD10"), + m_md11(*this, "MD11"), + m_md12(*this, "MD12"), + m_md13(*this, "MD13"), + m_md14(*this, "MD14"), + m_md15(*this, "MD15"), + m_md16(*this, "MD16"), + m_md17(*this, "MD17"), + m_md18(*this, "MD18"), + m_md19(*this, "MD19"), + m_md20(*this, "MD20"), + m_md21(*this, "MD21"), + m_md22(*this, "MD22"), + m_md23(*this, "MD23"), + m_p1(0), + m_p2(0), + m_q(0) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void iskr_1030_keyboard_device::device_start() +{ + set_pc_kbdc_device(); + + m_ram.resize(0x100); + save_item(NAME(m_ram)); + + save_item(NAME(m_bus)); + save_item(NAME(m_p1)); + save_item(NAME(m_p2)); + save_item(NAME(m_q)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void iskr_1030_keyboard_device::device_reset() +{ +} + + +//------------------------------------------------- +// clock_write - +//------------------------------------------------- + +WRITE_LINE_MEMBER( iskr_1030_keyboard_device::clock_write ) +{ + DBG_LOG(1,0,( "%s: clock write %d\n", tag(), state)); + m_maincpu->set_input_line(MCS48_INPUT_IRQ, state ? CLEAR_LINE : ASSERT_LINE); +} + + +//------------------------------------------------- +// data_write - +//------------------------------------------------- + +WRITE_LINE_MEMBER( iskr_1030_keyboard_device::data_write ) +{ + DBG_LOG(1,0,( "%s: data write %d\n", tag(), state)); +} + + +//------------------------------------------------- +// t1_r - +//------------------------------------------------- + +READ8_MEMBER( iskr_1030_keyboard_device::t1_r ) +{ + UINT8 data = data_signal(); + UINT8 bias = m_p1 & 15; + + if (!BIT(m_p1, 7)) { + DBG_LOG(2,0,( "%s: t1_r (l) %d\n", tag(), data)); + return data; + } + + if (bias) { + DBG_LOG(2,0,( "%s: t1_r (b) %d\n", tag(), bias)); + return 1; + } + + data = 0; + switch (m_bus >> 2) + { + case 0<<1: data = m_md00->read(); break; + case 1<<1: data = m_md01->read(); break; + case 2<<1: data = m_md02->read(); break; + case 3<<1: data = m_md03->read(); break; + case 4<<1: data = m_md04->read(); break; + case 5<<1: data = m_md05->read(); break; + case 6<<1: data = m_md06->read(); break; + case 7<<1: data = m_md07->read(); break; + case 8<<1: data = m_md08->read(); break; + case 9<<1: data = m_md09->read(); break; + case 10<<1: data = m_md10->read(); break; + case 11<<1: data = m_md11->read(); break; + case (0<<1)+1: data = m_md12->read(); break; + case (1<<1)+1: data = m_md13->read(); break; + case (2<<1)+1: data = m_md14->read(); break; + case (3<<1)+1: data = m_md15->read(); break; + case (4<<1)+1: data = m_md16->read(); break; + case (5<<1)+1: data = m_md17->read(); break; + case (6<<1)+1: data = m_md18->read(); break; + case (7<<1)+1: data = m_md19->read(); break; + case (8<<1)+1: data = m_md20->read(); break; + case (9<<1)+1: data = m_md21->read(); break; + case (10<<1)+1: data = m_md22->read(); break; + case (11<<1)+1: data = m_md23->read(); break; + } + data = BIT(data, m_bus&3); + + DBG_LOG(2,0,( "%s: t1_r (k r%d c%d) %d\n", tag(), m_bus&3, m_bus>>2, data)); + return data; +} + + +//------------------------------------------------- +// ram_w - +//------------------------------------------------- + +WRITE8_MEMBER( iskr_1030_keyboard_device::ram_w ) +{ + DBG_LOG(2,0,( "%s: ram_w[%02x] <- %02x\n", tag(), offset, data)); + + m_bus = offset; + m_ram[offset] = data; +} + + +//------------------------------------------------- +// ram_r - +//------------------------------------------------- + +READ8_MEMBER( iskr_1030_keyboard_device::ram_r ) +{ + DBG_LOG(2,0,( "%s: ram_r[%02x] = %02x\n", tag(), offset, m_ram[offset])); + + return m_ram[offset]; +} + + +//------------------------------------------------- +// p1_r - +//------------------------------------------------- + +READ8_MEMBER( iskr_1030_keyboard_device::p1_r ) +{ + /* + bit description + + 0 -REQ IN + 1 DATA IN + 2 + 3 + 4 + 5 + 6 + 7 + */ + + UINT8 data = 0; + + DBG_LOG(1,0,( "%s: p1_r %02x\n", tag(), data)); + + return data; +} + + +//------------------------------------------------- +// p2_w - +//------------------------------------------------- + +WRITE8_MEMBER( iskr_1030_keyboard_device::p2_w ) +{ + /* + bit description + + 0 ... + 1 ... + 2 ... + 3 (not connected) + 4 SPEAKER + 5 LED RUS/LAT + 6 LED NLK + 7 LED CLK + */ + DBG_LOG(1,0,( "%s: p2_w %02x\n", tag(), data)); + + m_p2 = data; +} + + +//------------------------------------------------- +// p1_w - OK +//------------------------------------------------- + +WRITE8_MEMBER( iskr_1030_keyboard_device::p1_w ) +{ + /* + bit description + + 0 XXX + 1 XXX + 2 XXX + 3 XXX + 4 CLOCK out + 5 DATA out + 6 XXX + 7 POLL GATE + */ + + m_p1 = data; + + DBG_LOG(1,0,( "%s: p1_w %02x (c %d d %d bias %d)\n", tag(), data, BIT(data, 4), BIT(data, 5), data&15)); + + m_pc_kbdc->data_write_from_kb(BIT(data, 5)); + m_pc_kbdc->clock_write_from_kb(BIT(data, 4)); +} diff --git a/src/devices/bus/pc_kbd/iskr1030.h b/src/devices/bus/pc_kbd/iskr1030.h new file mode 100644 index 00000000000..40957295b52 --- /dev/null +++ b/src/devices/bus/pc_kbd/iskr1030.h @@ -0,0 +1,93 @@ +// license:BSD-3-Clause +// copyright-holders:Sergey Svishchev +/********************************************************************** + + Iskra-1030 XX-key keyboard emulation + +*********************************************************************/ + +#pragma once + +#ifndef __PC_KBD_ISKR_1030__ +#define __PC_KBD_ISKR_1030__ + +#include "emu.h" +#include "cpu/mcs48/mcs48.h" +#include "pc_kbdc.h" +#include "machine/rescap.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> iskr_1030_keyboard_device + +class iskr_1030_keyboard_device : public device_t, + public device_pc_kbd_interface +{ +public: + // construction/destruction + iskr_1030_keyboard_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + virtual ioport_constructor device_input_ports() const; + + DECLARE_READ8_MEMBER( ram_r ); + DECLARE_WRITE8_MEMBER( ram_w ); + DECLARE_READ8_MEMBER( p1_r ); + DECLARE_WRITE8_MEMBER( p1_w ); + DECLARE_WRITE8_MEMBER( p2_w ); + DECLARE_READ8_MEMBER( t1_r ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_pc_kbd_interface overrides + virtual DECLARE_WRITE_LINE_MEMBER( clock_write ); + virtual DECLARE_WRITE_LINE_MEMBER( data_write ); + +private: + required_device m_maincpu; + required_ioport m_md00; + required_ioport m_md01; + required_ioport m_md02; + required_ioport m_md03; + required_ioport m_md04; + required_ioport m_md05; + required_ioport m_md06; + required_ioport m_md07; + required_ioport m_md08; + required_ioport m_md09; + required_ioport m_md10; + required_ioport m_md11; + required_ioport m_md12; + required_ioport m_md13; + required_ioport m_md14; + required_ioport m_md15; + required_ioport m_md16; + required_ioport m_md17; + required_ioport m_md18; + required_ioport m_md19; + required_ioport m_md20; + required_ioport m_md21; + required_ioport m_md22; + required_ioport m_md23; + + dynamic_buffer m_ram; + UINT8 m_bus; + UINT8 m_p1; + UINT8 m_p2; + int m_q; +}; + + +// device type definition +extern const device_type PC_KBD_ISKR_1030; + +#endif diff --git a/src/devices/bus/pc_kbd/keyboards.c b/src/devices/bus/pc_kbd/keyboards.c new file mode 100644 index 00000000000..c9bc4c33acd --- /dev/null +++ b/src/devices/bus/pc_kbd/keyboards.c @@ -0,0 +1,28 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol + +#include "emu.h" +#include "keyboards.h" +#include "ec1841.h" +#include "iskr1030.h" +#include "keytro.h" +#include "msnat.h" +#include "pc83.h" +#include "pcxt83.h" +#include "pcat84.h" + +SLOT_INTERFACE_START(pc_xt_keyboards) + SLOT_INTERFACE(STR_KBD_KEYTRONIC_PC3270, PC_KBD_KEYTRONIC_PC3270) + SLOT_INTERFACE(STR_KBD_IBM_PC_83, PC_KBD_IBM_PC_83) + SLOT_INTERFACE(STR_KBD_IBM_PC_XT_83, PC_KBD_IBM_PC_XT_83) + SLOT_INTERFACE(STR_KBD_EC_1841, PC_KBD_EC_1841) + SLOT_INTERFACE(STR_KBD_ISKR_1030, PC_KBD_ISKR_1030) +SLOT_INTERFACE_END + + +SLOT_INTERFACE_START(pc_at_keyboards) + SLOT_INTERFACE(STR_KBD_KEYTRONIC_PC3270, PC_KBD_KEYTRONIC_PC3270_AT) + SLOT_INTERFACE(STR_KBD_MICROSOFT_NATURAL, PC_KBD_MICROSOFT_NATURAL) + SLOT_INTERFACE(STR_KBD_IBM_PC_AT_84, PC_KBD_IBM_PC_AT_84) + SLOT_INTERFACE(STR_KBD_IBM_3270PC_122, PC_KBD_IBM_3270PC_122) +SLOT_INTERFACE_END diff --git a/src/devices/bus/pc_kbd/keyboards.h b/src/devices/bus/pc_kbd/keyboards.h new file mode 100644 index 00000000000..cd88f8b1096 --- /dev/null +++ b/src/devices/bus/pc_kbd/keyboards.h @@ -0,0 +1,31 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +/*************************************************************************** + + PC Keyboards + +***************************************************************************/ + +#ifndef __PC_KEYBOARDS_H__ +#define __PC_KEYBOARDS_H__ + + +// PC XT protocol keyboards +#define STR_KBD_KEYTRONIC_PC3270 "keytronc_pc3270" +#define STR_KBD_IBM_PC_83 "pc" +#define STR_KBD_IBM_PC_XT_83 "pcxt" +#define STR_KBD_EC_1841 "ec1841" +#define STR_KBD_ISKR_1030 "iskr1030" + +SLOT_INTERFACE_EXTERN(pc_xt_keyboards); + +// PC AT protocol keyboards +// Reuses STR_KBD_KEYTRONIC_PC3270 (same keyboard in AT protocol mode by default) + +#define STR_KBD_MICROSOFT_NATURAL "ms_naturl" +#define STR_KBD_IBM_PC_AT_84 "pcat" +#define STR_KBD_IBM_3270PC_122 "3270pc" + +SLOT_INTERFACE_EXTERN(pc_at_keyboards); + +#endif /* __KB_KEYBOARDS_H__ */ diff --git a/src/devices/bus/pc_kbd/keytro.c b/src/devices/bus/pc_kbd/keytro.c new file mode 100644 index 00000000000..01fbaf6852b --- /dev/null +++ b/src/devices/bus/pc_kbd/keytro.c @@ -0,0 +1,629 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +/*************************************************************************** + +TODO: +- Add support for PF01 - PF24 + +Emulation file for Keytronic KB3270/PC keyboard by Wilbert Pol. + +This keyboard supports both the PC/XT and the PC/AT keyboard protocols. The +desired protocol can be selected by a switch on the keyboard. + +Keyboard matrix. + +Z5 = XR 22-00950-001 +Z6 = SN74LS132N +Z7 = XR 22-00950-001 +Z8 = SN74LS374N +Z11 = XR 22-908-03B + + + | Z11 pin 8 + | | Z11 pin 7 + | | | Z11 pin 6 + | | | | Z11 pin 5 + | | | | | Z11 pin 4 + | | | | | | + F1 -------- F2 ------------- F3 ----- F4 ----- F5 ----- F6 -------- J2 pin 2 - Z5 pin 19 + | | | | | | + F7 -------- F8 ------------- LShift - < ------ Z ------ X --------- J2 pin 1 - Z5 pin 18 + | | | | | | + F9 -------- F10 ------------ LCtrl -- LAlt --- Space -- RAlt ------ J1 pin 9 - Z5 pin 17 + | | | | | | + 1 --------- ` -------------- Q ------ TAB ---- A ------ Caps Lock - J1 pin 8 - Z5 pin 16 + | | | | | | + 2 --------- 3 -------------- W ------ E ------ S ------ D --------- J1 pin 7 - Z5 pin 15 + | | | | | | + 5 --------- 4 -------------- T ------ R ------ G ------ F --------- J2 pin 3 - Z7 pin 20 + | | | | | | + N --------- M -------------- B ------ V ------ C ------ , -------------------- Z7 pin 19 + | | | | | | + 6 --------- 7 -------------- Y ------ U ------ H ------ J -------------------- Z7 pin 18 + | | | | | | + 9 --------- 8 -------------- O ------ I ------ L ------ K -------------------- Z7 pin 17 + | | | | | | + Pad 2 ----- Pad 1 ---------- Unused - Unused - Down --- Enter ---------------- Z7 pin 16 + | | | | | | + | / -------------- Rshift - Rshift - Left --- . --------- J9 pin 8 - Z7 pin 15 + | | | | | | + 0 --------- - -------------- P ------ [ ------ ; ------ ' --------- J9 pin 7 - Z7 pin 14 + | | | | | | + Backspace - = -------------- Return - \ ------ Return - ] --------- J9 pin 6 - Z7 pin 13 + | | | | | | + Backspace - PA1/Dup -------- |<-- --- /a\ ---- Pad + -- Pad + ----- J9 pin 5 - Z7 pin 12 + | | | | | | + Esc ------- NumLock -------- Pad 7 -- Pad 8 -- Pad 4 -- Pad 5 ------J9 pin 3 - Z7 pin 2 + | | | | | | + SysReq ---- ScrLk ---------- -->| --- Pad 9 -- Pad - -- Pad 6 ---------------- goes under Z8 between pins 5 and 6 to Z8 pin 15? + | | | | | | + Pad 3 ----- Pad 0 ---------- Pad 0 -- Pad . -- Unused - Up ------------------- Z7 pin 7 + | | | | | | + PrtSc * --- PA2/Field Mark - Right -- /a ----- Center - Unused ---- J9 pin 2 - Z7 pin 3 + | | | | | | + +The 'Return', 'Backspace, 'Pad 0', 'Right Shift', 'Pad +' keys on the keyboard +are attached to two switches. The keys appear twice in the keyboard matrix. + +***************************************************************************/ + +#include "emu.h" +#include "keytro.h" +#include "cpu/mcs51/mcs51.h" + + +/*************************************************************************** + CONSTANTS +***************************************************************************/ + +#define LOG 0 + + +/***************************************************************************** + INPUT PORTS +*****************************************************************************/ + +static INPUT_PORTS_START( kb_keytronic_common ) + + PORT_START( "kb_keytronic_0f" ) + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_5) PORT_CHAR('5') /* 06 */ + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_4) PORT_CHAR('4') /* 05 */ + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_T) PORT_CHAR('T') /* 14 */ + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_R) PORT_CHAR('R') /* 13 */ + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_G) PORT_CHAR('G') /* 22 */ + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F) PORT_CHAR('F') /* 21 */ + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("F7 (IRMA)") /* 41 */ + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("?6a?") /* 6a */ + + PORT_START( "kb_keytronic_30_0" ) + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_N) PORT_CHAR('N') /* 31 */ + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_M) PORT_CHAR('M') /* 32 */ + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_B) PORT_CHAR('B') /* 30 */ + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_V) PORT_CHAR('V') /* 2f */ + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_C) PORT_CHAR('C') /* 2e */ + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_COMMA) PORT_CHAR(',') /* 33 */ + PORT_BIT( 0xc0, IP_ACTIVE_LOW, IPT_UNUSED ) + + PORT_START( "kb_keytronic_30_1" ) + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F1) PORT_CHAR(UCHAR_MAMEKEY(F1)) /* 58 */ + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F2) PORT_CHAR(UCHAR_MAMEKEY(F2)) /* 59 */ + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F3) PORT_CHAR(UCHAR_MAMEKEY(F3)) /* 5a */ + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F4) PORT_CHAR(UCHAR_MAMEKEY(F4)) /* 5b */ + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F5) PORT_CHAR(UCHAR_MAMEKEY(F5)) /* 5c */ + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F6) PORT_CHAR(UCHAR_MAMEKEY(F6)) /* 5d */ + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("?6b?") /* 6b */ + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("F8 (IRMA)") /* 42 */ + + PORT_START( "kb_keytronic_31_0" ) + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_6) PORT_CHAR('6') /* 07 */ + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_7) PORT_CHAR('7') /* 08 */ + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Y) PORT_CHAR('Y') /* 15 */ + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_U) PORT_CHAR('U') /* 16 */ + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_H) PORT_CHAR('H') /* 23 */ + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_J) PORT_CHAR('J') /* 24 */ + PORT_BIT( 0xc0, IP_ACTIVE_LOW, IPT_UNUSED ) + + PORT_START( "kb_keytronic_31_1" ) + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F7) PORT_CHAR(UCHAR_MAMEKEY(F7)) /* 37 */ + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F8) PORT_CHAR(UCHAR_MAMEKEY(F8)) /* 5f */ + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_LSHIFT) PORT_NAME("LShift") /* 2a */ + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("<") /* 70 */ + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Z) PORT_CHAR('Z') /* 2c */ + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_X) PORT_CHAR('X') /* 2d */ + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("?6c?") /* 6c */ + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("F9 (IRMA)") /* 43 */ + + PORT_START( "kb_keytronic_32_0" ) + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_9) PORT_CHAR('9') /* 0a */ + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_8) PORT_CHAR('8') /* 09 */ + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_O) PORT_CHAR('O') /* 18 */ + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_I) PORT_CHAR('I') /* 17 */ + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_L) PORT_CHAR('L') /* 26 */ + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_K) PORT_CHAR('K') /* 25 */ + PORT_BIT( 0xc0, IP_ACTIVE_LOW, IPT_UNUSED ) + + PORT_START( "kb_keytronic_32_1" ) + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F9) PORT_CHAR(UCHAR_MAMEKEY(F9)) /* 57 */ + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F10) PORT_CHAR(UCHAR_MAMEKEY(F10)) /* 1d */ + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_LCONTROL) PORT_CHAR(UCHAR_MAMEKEY(LCONTROL)) /* 71 */ + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_LALT) PORT_NAME("LAlt") /* 38 */ + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_SPACE) PORT_CHAR(' ') /* 39 */ + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_RALT) PORT_NAME("RAlt") /* 38 */ + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("?69?") /* 69 */ + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("F6 (IRMA)") /* 40 */ + + PORT_START( "kb_keytronic_33_0" ) + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_2_PAD) PORT_CODE(KEYCODE_DOWN) PORT_NAME("KP 2") /* 50 */ + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_1_PAD) PORT_CODE(KEYCODE_END) PORT_NAME("KP 1") /* 4f */ + PORT_BIT( 0x0c, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Down") /* 55 */ + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Enter") /* 75 */ + PORT_BIT( 0xc0, IP_ACTIVE_LOW, IPT_UNUSED ) + + PORT_START( "kb_keytronic_33_1" ) + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_1) PORT_CHAR('1') /* 02 */ + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_TILDE) PORT_CHAR('`') /* 29 */ + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Q) PORT_CHAR('Q') /* 10 */ + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_TAB) PORT_CHAR(9) /* 0f */ + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_A) PORT_CHAR('A') /* 1e */ + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_CAPSLOCK) PORT_NAME("Caps") /* 3a */ + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("?68?") /* 68 */ + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("F5 (IRMA)") /* 3f */ + + PORT_START( "kb_keytronic_34_0" ) + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_SLASH) PORT_CHAR('/') /* 35 */ + PORT_BIT( 0x0c, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_RSHIFT) PORT_CHAR(UCHAR_MAMEKEY(RSHIFT)) /* 36 */ + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Left") /* 56 */ + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_STOP) PORT_CHAR('.') /* 34 */ + PORT_BIT( 0xc0, IP_ACTIVE_LOW, IPT_UNUSED ) + + PORT_START( "kb_keytronic_34_1" ) + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_2) PORT_CHAR('2') /* 02 */ + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_3) PORT_CHAR('3') /* 03 */ + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_W) PORT_CHAR('W') /* 11 */ + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_E) PORT_CHAR('E') /* 12 */ + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_S) PORT_CHAR('S') /* 1f */ + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_D) PORT_CHAR('D') /* 20 */ + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("?67?") /* 67 */ + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("F4 (IRMA)") /* 3e */ + + PORT_START( "kb_keytronic_35_0" ) + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_0) PORT_CHAR('0') /* 0b */ + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_MINUS) PORT_CHAR('-') /* 0c */ + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_P) PORT_CHAR('P') /* 19 */ + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_OPENBRACE) PORT_CHAR('[') /* 1a */ + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_COLON) PORT_CHAR(';') /* 27 */ + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_QUOTE) PORT_CHAR('\'') /* 28 */ + PORT_BIT( 0xc0, IP_ACTIVE_LOW, IPT_UNUSED ) + + PORT_START( "kb_keytronic_35_1" ) + PORT_BIT( 0x3f, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("?66?") /* 66 */ + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("F3 (IRMA)") /* 3d */ + + PORT_START( "kb_keytronic_36_0" ) + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_BACKSPACE) PORT_CHAR(8) /* 0e */ + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_EQUALS) PORT_CHAR('=') /* 0d */ + PORT_BIT( 0x14, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_ENTER) PORT_CHAR(13) /* 1c */ + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_BACKSLASH) PORT_CHAR('\\') /* 2b */ + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_CLOSEBRACE) PORT_CHAR(']') /* 1b */ + PORT_BIT( 0xc0, IP_ACTIVE_LOW, IPT_UNUSED ) + + PORT_START( "kb_keytronic_36_1" ) + PORT_BIT( 0x7f, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("F2 (IRMA)") /* 3c */ + + PORT_START( "kb_keytronic_37_0" ) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("PA1") /* 7b */ + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("|<--") /* 7e */ + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("/a\\") /* 7a */ + PORT_BIT( 0x30, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_PLUS_PAD) PORT_NAME("KP +") /* 4e */ + PORT_BIT( 0xc0, IP_ACTIVE_LOW, IPT_UNUSED ) + + PORT_START( "kb_keytronic_37_1" ) + PORT_BIT( 0x3f, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("?64?") /* 64 */ + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("F1 (IRMA)") /* 3b */ + + PORT_START( "kb_keytronic_38_0" ) + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("SysReq") /* 54 */ + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) /*PORT_CODE(KEYCODE_SCRLOCK)*/ PORT_NAME("ScrLock") /* 46 */ + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("-->|") /* 7c */ + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_9_PAD) PORT_CODE(KEYCODE_PGUP) PORT_NAME("KP 9") /* 49 */ + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_MINUS_PAD) PORT_NAME("KP -") /* 4a */ + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_6_PAD) PORT_CODE(KEYCODE_RIGHT) PORT_NAME("KP 6") /* 4d */ + PORT_BIT( 0xc0, IP_ACTIVE_LOW, IPT_UNUSED ) + + PORT_START( "kb_keytronic_39_0" ) + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_ESC) PORT_NAME("Esc") /* 01 */ + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_NUMLOCK) PORT_NAME("NumLock") /* 45 */ + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_7_PAD) PORT_CODE(KEYCODE_HOME) PORT_NAME("KP 7") /* 47 */ + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_8_PAD) PORT_CODE(KEYCODE_UP) PORT_NAME("KP 8") /* 48 */ + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_4_PAD) PORT_CODE(KEYCODE_LEFT) PORT_NAME("KP 4") /* 4b */ + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_5_PAD) PORT_NAME("KP 5") /* 4c */ + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("?76?") /* 76 */ + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("?63?") /* 63 */ + + PORT_START( "kb_keytronic_3a_0" ) + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("PrtSc *") /* 6f */ + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("PA2") /* 7f */ + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Right") /* 7d */ + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("/a") /* 79 */ + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Center") /* 77 */ + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("?6e?") /* 6e */ + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("?62?") /* 62 */ + + PORT_START( "kb_keytronic_3b_0" ) + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_3_PAD) PORT_CODE(KEYCODE_PGDN) PORT_NAME("KP 3") /* 51 */ + PORT_BIT( 0x06, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_0_PAD) PORT_CODE(KEYCODE_INSERT) PORT_NAME("KP 0") /* 52 */ + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_DEL_PAD) PORT_CODE(KEYCODE_DEL) PORT_NAME("KP .") /* 53 */ + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Up") /* 78 */ + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("?6d?") /* 6d */ + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("F10 (IRMA)") /* 44 */ + +INPUT_PORTS_END + + +static INPUT_PORTS_START( kb_keytronic_pc ) + PORT_INCLUDE( kb_keytronic_common ) + + PORT_START( "kb_keytronic_0b" ) + PORT_DIPNAME( 0x01, 0x01, "Protocol selection" ) + PORT_DIPSETTING( 0x00, "Enhanced XT, AT and PS/2 models" ) + PORT_DIPSETTING( 0x01, "Standard PC and XT" ) + PORT_DIPNAME( 0x02, 0x00, "IRMA/Native scan code set" ) + PORT_DIPSETTING( 0x00, "Native scan code set" ) + PORT_DIPSETTING( 0x02, "IRMA Emulation" ) + PORT_DIPNAME( 0x04, 0x04, "Enhanced 101/Native scan code set" ) + PORT_DIPSETTING( 0x00, "Native scan code set" ) + PORT_DIPSETTING( 0x04, "Enhanced 101 scan code set" ) + PORT_DIPNAME( 0x08, 0x08, "Enable E0" ) + PORT_DIPSETTING( 0x00, "Enable E0" ) + PORT_DIPSETTING( 0x08, "Disable E0" ) + PORT_DIPNAME( 0x10, 0x10, "Code tables" ) + PORT_DIPSETTING( 0x00, "U.S. code tables" ) + PORT_DIPSETTING( 0x10, "International code tables" ) + PORT_BIT( 0x60, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_DIPNAME( 0x80, 0x80, "Key click" ) + PORT_DIPSETTING( 0x00, "No key click" ) + PORT_DIPSETTING( 0x80, "Key click" ) +INPUT_PORTS_END + + +static INPUT_PORTS_START( kb_keytronic_at ) + + PORT_INCLUDE( kb_keytronic_common ) + + PORT_START( "kb_keytronic_0b" ) + PORT_DIPNAME( 0x01, 0x00, "Protocol selection" ) + PORT_DIPSETTING( 0x00, "Enhanced XT, AT and PS/2 models" ) + PORT_DIPSETTING( 0x01, "Standard PC and XT" ) + PORT_DIPNAME( 0x02, 0x00, "IRMA/Native scan code set" ) + PORT_DIPSETTING( 0x00, "Native scan code set" ) + PORT_DIPSETTING( 0x02, "IRMA Emulation" ) + PORT_DIPNAME( 0x04, 0x04, "Enhanced 101/Native scan code set" ) + PORT_DIPSETTING( 0x00, "Native scan code set" ) + PORT_DIPSETTING( 0x04, "Enhanced 101 scan code set" ) + PORT_DIPNAME( 0x08, 0x00, "Enable E0" ) + PORT_DIPSETTING( 0x00, "Enable E0" ) + PORT_DIPSETTING( 0x08, "Disable E0" ) + PORT_DIPNAME( 0x10, 0x10, "Code tables" ) + PORT_DIPSETTING( 0x00, "U.S. code tables" ) + PORT_DIPSETTING( 0x10, "International code tables" ) + PORT_BIT( 0x60, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_DIPNAME( 0x80, 0x80, "Key click" ) + PORT_DIPSETTING( 0x00, "No key click" ) + PORT_DIPSETTING( 0x80, "Key click" ) +INPUT_PORTS_END + + +#if 0 +/*************************************************************************** + ROM DEFINITIONS +***************************************************************************/ + +ROM_START( kb_keytr ) + ROM_REGION(0x2000, "kb_keytr", 0) + ROM_LOAD("14166.bin", 0x0000, 0x2000, CRC(1aea1b53) SHA1(b75b6d4509036406052157bc34159f7039cdc72e)) +ROM_END +#endif + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type PC_KBD_KEYTRONIC_PC3270 = &device_creator; +const device_type PC_KBD_KEYTRONIC_PC3270_AT = &device_creator; + + +/***************************************************************************** + ADDRESS MAPS +*****************************************************************************/ + +static ADDRESS_MAP_START( keytronic_pc3270_program, AS_PROGRAM, 8, pc_kbd_keytronic_pc3270_device ) + AM_RANGE(0x0000, 0x0fff) AM_ROM AM_REGION("kb_keytr", 0) +ADDRESS_MAP_END + +static ADDRESS_MAP_START( keytronic_pc3270_io, AS_IO, 8, pc_kbd_keytronic_pc3270_device ) + AM_RANGE(0x0000, 0xffff) AM_READWRITE(internal_data_read, internal_data_write) + AM_RANGE(MCS51_PORT_P1, MCS51_PORT_P1) AM_READWRITE(p1_read, p1_write) + AM_RANGE(MCS51_PORT_P2, MCS51_PORT_P2) AM_READWRITE(p2_read, p2_write) + AM_RANGE(MCS51_PORT_P3, MCS51_PORT_P3) AM_READWRITE(p3_read, p3_write) +ADDRESS_MAP_END + + +/***************************************************************************** + MACHINE CONFIG +*****************************************************************************/ + +MACHINE_CONFIG_FRAGMENT( keytronic_pc3270 ) + MCFG_CPU_ADD("kb_keytr", I8051, 11060250) + MCFG_CPU_PROGRAM_MAP(keytronic_pc3270_program) + MCFG_CPU_IO_MAP(keytronic_pc3270_io) +MACHINE_CONFIG_END + + +/*************************************************************************** + ROM DEFINITIONS +***************************************************************************/ + +ROM_START( keytronic_pc3270 ) + ROM_REGION(0x2000, "kb_keytr", 0) + ROM_LOAD("14166.bin", 0x0000, 0x2000, CRC(1aea1b53) SHA1(b75b6d4509036406052157bc34159f7039cdc72e)) +ROM_END + + +pc_kbd_keytronic_pc3270_device::pc_kbd_keytronic_pc3270_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, PC_KBD_KEYTRONIC_PC3270, "Keytronic PC3270", tag, owner, clock, "keytronic_pc3270", __FILE__), + device_pc_kbd_interface(mconfig, *this), + m_cpu(*this, "kb_keytr") +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- +void pc_kbd_keytronic_pc3270_device::device_start() +{ + set_pc_kbdc_device(); + + /* setup savestates */ + save_item(NAME(m_p1)); + save_item(NAME(m_p1_data)); + save_item(NAME(m_p2)); + save_item(NAME(m_p3)); + save_item(NAME(m_last_write_addr)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- +void pc_kbd_keytronic_pc3270_device::device_reset() +{ + /* set default values */ + m_p3 = 0xff; + m_last_write_addr = 0; +} + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor pc_kbd_keytronic_pc3270_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( keytronic_pc3270 ); +} + + +ioport_constructor pc_kbd_keytronic_pc3270_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( kb_keytronic_pc ); +} + + +ioport_constructor pc_kbd_keytronic_pc3270_at_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( kb_keytronic_at ); +} + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *pc_kbd_keytronic_pc3270_device::device_rom_region() const +{ + return ROM_NAME( keytronic_pc3270 ); +} + + +WRITE_LINE_MEMBER( pc_kbd_keytronic_pc3270_device::clock_write ) +{ + m_cpu->set_input_line(MCS51_INT0_LINE, state ); +} + + +WRITE_LINE_MEMBER( pc_kbd_keytronic_pc3270_device::data_write ) +{ + m_cpu->set_input_line(MCS51_T0_LINE, state); +} + + +READ8_MEMBER( pc_kbd_keytronic_pc3270_device::internal_data_read ) +{ + if (LOG) + logerror("keytronic_pc3270::internal_data_read(): read from %04x\n", offset); + + if ( m_pc_kbdc ) + { + m_pc_kbdc->data_write_from_kb( BIT(offset, 8) ); + m_pc_kbdc->clock_write_from_kb( BIT(offset, 9) ); + } + + return 0xff; +} + + +WRITE8_MEMBER( pc_kbd_keytronic_pc3270_device::internal_data_write ) +{ + if (LOG) + logerror("keytronic_pc3270::internal_data_write(): write to offset %04x\n", offset); + + /* Check for low->high transition on AD8 */ + if ( ! ( m_last_write_addr & 0x0100 ) && ( offset & 0x0100 ) ) + { + switch (m_p1) + { + case 0x0e: + break; + case 0x0f: + m_p1_data = ioport("kb_keytronic_0f")->read(); + break; + case 0x30: + m_p1_data = ioport("kb_keytronic_30_0")->read(); + break; + case 0x31: + m_p1_data = ioport("kb_keytronic_31_0")->read(); + break; + case 0x32: + m_p1_data = ioport("kb_keytronic_32_0")->read(); + break; + case 0x33: + m_p1_data = ioport("kb_keytronic_33_0")->read(); + break; + case 0x34: + m_p1_data = ioport("kb_keytronic_34_0")->read(); + break; + case 0x35: + m_p1_data = ioport("kb_keytronic_35_0")->read(); + break; + case 0x36: + m_p1_data = ioport("kb_keytronic_36_0")->read(); + break; + case 0x37: + m_p1_data = ioport("kb_keytronic_37_0")->read() | (ioport("kb_keytronic_36_0")->read() & 0x01); + break; + case 0x38: + m_p1_data = ioport("kb_keytronic_38_0")->read(); + break; + case 0x39: + m_p1_data = ioport("kb_keytronic_39_0")->read(); + break; + case 0x3a: + m_p1_data = ioport("kb_keytronic_3a_0")->read(); + break; + case 0x3b: + m_p1_data = ioport("kb_keytronic_3b_0")->read(); + break; + } + } + + /* Check for low->high transition on AD9 */ + if ( ! ( m_last_write_addr & 0x0200 ) && ( offset & 0x0200 ) ) + { + switch (m_p1) + { + case 0x0b: + m_p1_data = ioport("kb_keytronic_0b")->read(); + break; + case 0x30: + m_p1_data = ioport("kb_keytronic_30_1")->read(); + break; + case 0x31: + m_p1_data = ioport("kb_keytronic_31_1")->read(); + break; + case 0x32: + m_p1_data = ioport("kb_keytronic_32_1")->read(); + break; + case 0x33: + m_p1_data = ioport("kb_keytronic_33_1")->read(); + break; + case 0x34: + m_p1_data = ioport("kb_keytronic_34_1")->read(); + break; + case 0x35: + m_p1_data = ioport("kb_keytronic_35_1")->read(); + break; + case 0x36: + m_p1_data = ioport("kb_keytronic_36_1")->read(); + break; + case 0x37: + m_p1_data = ioport("kb_keytronic_37_1")->read(); + break; + case 0x38: + m_p1_data = 0xff; + break; + case 0x39: + m_p1_data = 0xff; + break; + case 0x3a: + m_p1_data = 0xff; + break; + } + } + + m_last_write_addr = offset; +} + + +READ8_MEMBER( pc_kbd_keytronic_pc3270_device::p1_read ) +{ + return m_p1 & m_p1_data; +} + + +WRITE8_MEMBER( pc_kbd_keytronic_pc3270_device::p1_write ) +{ + if (LOG) + logerror("keytronic_pc3270::p1_write(): write %02x\n", data); + + m_p1 = data; +} + + +READ8_MEMBER( pc_kbd_keytronic_pc3270_device::p2_read ) +{ + return m_p2; +} + + +WRITE8_MEMBER( pc_kbd_keytronic_pc3270_device::p2_write ) +{ + if (LOG) + logerror("keytronic_pc3270::p2_write(): write %02x\n", data); + + m_p2 = data; +} + + +READ8_MEMBER( pc_kbd_keytronic_pc3270_device::p3_read ) +{ + UINT8 data = m_p3; + + data &= ~0x14; + + /* -INT0 signal */ + data |= (clock_signal() ? 0x04 : 0x00); + + /* T0 signal */ + data |= (data_signal() ? 0x00 : 0x10); + + return data; +} + + +WRITE8_MEMBER( pc_kbd_keytronic_pc3270_device::p3_write ) +{ + if (LOG) + logerror("keytronic_pc3270::p3_write(): write %02x\n", data); + + m_p3 = data; +} diff --git a/src/devices/bus/pc_kbd/keytro.h b/src/devices/bus/pc_kbd/keytro.h new file mode 100644 index 00000000000..4a41b9bb4f5 --- /dev/null +++ b/src/devices/bus/pc_kbd/keytro.h @@ -0,0 +1,76 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +/*************************************************************************** + + Keytronic Keyboard + +***************************************************************************/ + +#ifndef __KB_KEYTRO_H__ +#define __KB_KEYTRO_H__ + +#include "pc_kbdc.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> pc_kbd_keytronic_pc3270_device + +class pc_kbd_keytronic_pc3270_device : public device_t, + public device_pc_kbd_interface +{ +public: + // construction/destruction + pc_kbd_keytronic_pc3270_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + required_device m_cpu; + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual ioport_constructor device_input_ports() const; + virtual const rom_entry *device_rom_region() const; + + virtual DECLARE_WRITE_LINE_MEMBER(clock_write); + virtual DECLARE_WRITE_LINE_MEMBER(data_write); + + DECLARE_READ8_MEMBER( internal_data_read ); + DECLARE_WRITE8_MEMBER( internal_data_write ); + DECLARE_READ8_MEMBER( p1_read ); + DECLARE_WRITE8_MEMBER( p1_write ); + DECLARE_READ8_MEMBER( p2_read ); + DECLARE_WRITE8_MEMBER( p2_write ); + DECLARE_READ8_MEMBER( p3_read ); + DECLARE_WRITE8_MEMBER( p3_write ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + UINT8 m_p1; + UINT8 m_p1_data; + UINT8 m_p2; + UINT8 m_p3; + UINT16 m_last_write_addr; +}; + + +class pc_kbd_keytronic_pc3270_at_device : public pc_kbd_keytronic_pc3270_device +{ +public: + // construction/destruction + pc_kbd_keytronic_pc3270_at_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : pc_kbd_keytronic_pc3270_device(mconfig, tag, owner, clock) + { + } + + virtual ioport_constructor device_input_ports() const; +}; + + +// device type definition +extern const device_type PC_KBD_KEYTRONIC_PC3270; +extern const device_type PC_KBD_KEYTRONIC_PC3270_AT; + +#endif /* __KB_KEYTRO_H__ */ diff --git a/src/devices/bus/pc_kbd/msnat.c b/src/devices/bus/pc_kbd/msnat.c new file mode 100644 index 00000000000..201ff864fb2 --- /dev/null +++ b/src/devices/bus/pc_kbd/msnat.c @@ -0,0 +1,451 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +/*************************************************************************** + + Microsoft Natural Keybaord emulation + + +TODO: +- Keyboard LEDs + +***************************************************************************/ + +#include "emu.h" +#include "msnat.h" +#include "cpu/mcs51/mcs51.h" + + +/*************************************************************************** + ONSTANTS +***************************************************************************/ + +#define LOG 0 + + +/***************************************************************************** + INPUT PORTS +*****************************************************************************/ + +static INPUT_PORTS_START( microsoft_natural ) + PORT_START( "P2.0" ) + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Y) PORT_CHAR('Y') // 15 + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_H) PORT_CHAR('H') // 23 + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_J) PORT_CHAR('J') // 24 + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_N) PORT_CHAR('N') // 31 + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_M) PORT_CHAR('M') // 32 + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_U) PORT_CHAR('U') // 16 + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_6) PORT_CHAR('6') // 07 + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_7) PORT_CHAR('7') // 08 + + PORT_START( "P2.1" ) + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_EQUALS) PORT_CHAR('=') // 0D + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_CLOSEBRACE) PORT_CHAR(']') // 1B + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_BACKSLASH) PORT_CHAR('\\') // 2B 2 spots for backslash? + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_LEFT) PORT_CHAR(UCHAR_MAMEKEY(LEFT)) // E0 4B + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_ENTER) PORT_CHAR(13) // 1C + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_BACKSPACE) PORT_CHAR(8) // 0E + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F5) PORT_CHAR(UCHAR_MAMEKEY(F5)) // 3F + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F6) PORT_CHAR(UCHAR_MAMEKEY(F6)) // 40 + + PORT_START( "P2.2" ) + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_9) PORT_CHAR('9') // 0A + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_O) PORT_CHAR('O') // 18 + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_OPENBRACE) PORT_CHAR('[') // 1A + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_L) PORT_CHAR('L') // 26 + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_STOP) PORT_CHAR('.') // 34 + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_MINUS) PORT_CHAR('-') // 0C + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F7) PORT_CHAR(UCHAR_MAMEKEY(F7)) // 41 + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F8) PORT_CHAR(UCHAR_MAMEKEY(F8)) // 42 + + PORT_START( "P2.3" ) + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_0) PORT_CHAR('0') // 0B + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_COLON) PORT_CHAR(';') // 27 + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_QUOTE) PORT_CHAR('\'') // 28 + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_SLASH) PORT_CHAR('/') // 35 + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_DOWN) PORT_CHAR(UCHAR_MAMEKEY(DOWN)) // E0 50 + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_P) PORT_CHAR('P') // 19 + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F9) PORT_CHAR(UCHAR_MAMEKEY(F9)) // 43 + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F10) PORT_CHAR(UCHAR_MAMEKEY(F10)) // 44 + + PORT_START( "P2.4" ) + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_UP) PORT_CHAR(UCHAR_MAMEKEY(UP)) // E0 48 + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_UNUSED ) // FF + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Unknown 73") // 73 TODO + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("\\ 2nd?") // 2B 2 spots for backslash?? + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_UNUSED ) // FF + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_RWIN) PORT_CHAR(UCHAR_MAMEKEY(RWIN)) // E0 5C + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_RIGHT) PORT_CHAR(UCHAR_MAMEKEY(RIGHT)) // E0 4D + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_SPACE) PORT_CHAR(' ') // 39 + + PORT_START( "P2.5" ) + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_HOME) PORT_CHAR(UCHAR_MAMEKEY(HOME)) // E0 47 + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_8_PAD) PORT_CHAR(UCHAR_MAMEKEY(8_PAD)) // 48 + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_5_PAD) PORT_CHAR(UCHAR_MAMEKEY(5_PAD)) // 4C + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_2_PAD) PORT_CHAR(UCHAR_MAMEKEY(2_PAD)) // 50 + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_0_PAD) PORT_CHAR(UCHAR_MAMEKEY(0_PAD)) // 52 + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_END) PORT_CHAR(UCHAR_MAMEKEY(END)) // E0 4F + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F11) PORT_CHAR(UCHAR_MAMEKEY(F11)) // 57 + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F12) PORT_CHAR(UCHAR_MAMEKEY(F12)) // 58 + + PORT_START( "P2.6" ) + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_INSERT) PORT_CHAR(UCHAR_MAMEKEY(INSERT)) // E0 52 + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_DEL) PORT_CHAR(UCHAR_MAMEKEY(DEL)) // E0 53 + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_6_PAD) PORT_CHAR(UCHAR_MAMEKEY(6_PAD)) // 4D + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_3_PAD) PORT_CHAR(UCHAR_MAMEKEY(3_PAD)) // 51 + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_DEL_PAD) PORT_CHAR(UCHAR_MAMEKEY(DEL_PAD)) // 53 + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_9_PAD) PORT_CHAR(UCHAR_MAMEKEY(9_PAD)) // 49 + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F3) PORT_CHAR(UCHAR_MAMEKEY(F3)) // 3D + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F4) PORT_CHAR(UCHAR_MAMEKEY(F4)) // 3E + + PORT_START( "P2.7" ) + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_SLASH_PAD) PORT_CHAR(UCHAR_MAMEKEY(SLASH_PAD)) // E0 + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_7_PAD) PORT_CHAR(UCHAR_MAMEKEY(7_PAD)) // 47 + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_4_PAD) PORT_CHAR(UCHAR_MAMEKEY(4_PAD)) // 4B + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_PLUS_PAD) PORT_CHAR(UCHAR_MAMEKEY(PLUS_PAD)) // 4E + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_1_PAD) PORT_CHAR(UCHAR_MAMEKEY(1_PAD)) // 4F + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_ASTERISK) PORT_CHAR(UCHAR_MAMEKEY(ASTERISK)) // 37 TODO + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_PRTSCR) PORT_CHAR(UCHAR_MAMEKEY(PRTSCR)) // E0 2A E0 37 + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_MENU) PORT_CHAR(UCHAR_MAMEKEY(MENU)) // E0 5D + + PORT_START( "P1.0" ) + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_LWIN) PORT_CHAR(UCHAR_MAMEKEY(LWIN)) // E0 5B + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_UNUSED ) // FF + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("INT5 7E") // 7E INT5 + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_UNUSED ) // FF + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_UNUSED ) // FF + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_UNUSED ) // FF + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_SCRLOCK) PORT_CHAR(UCHAR_MAMEKEY(SCRLOCK)) // 46 + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_ENTER_PAD) PORT_CHAR(UCHAR_MAMEKEY(ENTER_PAD)) // E0 1C + + PORT_START( "P1.1" ) + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_UNUSED ) // FF + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_LCONTROL) PORT_CHAR(UCHAR_MAMEKEY(LCONTROL)) // 1D + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_UNUSED ) // FF + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_UNUSED ) // FF + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_RCONTROL) PORT_CHAR(UCHAR_MAMEKEY(RCONTROL)) // E0 1D + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_CAPSLOCK) PORT_CHAR(UCHAR_MAMEKEY(CAPSLOCK)) // 3A + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNUSED ) // FF + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNUSED ) // FF + + PORT_START( "P1.2" ) + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_PGUP) PORT_CHAR(UCHAR_MAMEKEY(PGUP)) // E0 49 + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_2) PORT_CHAR('2') // 03 + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_W) PORT_CHAR('W') // 11 + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_S) PORT_CHAR('S') // 1F + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_X) PORT_CHAR('X') // 2D + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_PGDN) PORT_CHAR(UCHAR_MAMEKEY(PGDN)) // E0 51 + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F1) PORT_CHAR(UCHAR_MAMEKEY(F1)) // 3B + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F2) PORT_CHAR(UCHAR_MAMEKEY(F2)) // 3C + + PORT_START( "P1.3" ) + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_UNUSED ) // FF + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_UNUSED ) // FF + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_LALT) PORT_CHAR(UCHAR_MAMEKEY(LALT)) // 38 + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_RALT) PORT_CHAR(UCHAR_MAMEKEY(RALT)) // E0 38 + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_UNUSED ) // FF + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_UNUSED ) // FF + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_MINUS_PAD) PORT_CHAR(UCHAR_MAMEKEY(MINUS_PAD)) // 4A + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_NUMLOCK) PORT_CHAR(UCHAR_MAMEKEY(NUMLOCK)) // 45 + + PORT_START( "P1.4" ) + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_I) PORT_CHAR('I') // 17 + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_K) PORT_CHAR('K') // 25 + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_D) PORT_CHAR('D') // 20 + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_C) PORT_CHAR('C') // 2E + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_COMMA) PORT_CHAR(',') // 33 + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_E) PORT_CHAR('E') // 12 + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_3) PORT_CHAR('3') // 04 + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_8) PORT_CHAR('8') // 09 + + PORT_START( "P1.5" ) + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_R) PORT_CHAR('R') // 13 + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F) PORT_CHAR('F') // 21 + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_G) PORT_CHAR('G') // 22 + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_V) PORT_CHAR('V') // 2F + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_B) PORT_CHAR('B') // 30 + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_T) PORT_CHAR('T') // 14 + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_4) PORT_CHAR('4') // 05 + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_5) PORT_CHAR('5') // 06 + + PORT_START( "P1.6" ) + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_1) PORT_CHAR('1') // 02 + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Q) PORT_CHAR('Q') // 10 + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_A) PORT_CHAR('A') // 1E + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("INT1 56") // 56 INT1? + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Z) PORT_CHAR('Z') // 2C + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_TAB) PORT_CHAR(9) // 0F + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_ESC) PORT_CHAR(UCHAR_MAMEKEY(ESC)) // 01 + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_TILDE) PORT_CHAR('`') // 29 + + PORT_START( "P1.7" ) + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_UNUSED ) // FF + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_LSHIFT) PORT_CHAR(UCHAR_MAMEKEY(LSHIFT)) // 2A + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_UNUSED ) // FF + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_UNUSED ) // FF + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_RSHIFT) PORT_CHAR(UCHAR_MAMEKEY(RSHIFT)) // 36 + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_UNUSED ) // FF + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_CANCEL) PORT_CHAR(UCHAR_MAMEKEY(CANCEL)) // E1 1D 45 E1 9D C5 + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNUSED ) // FF + +INPUT_PORTS_END + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type PC_KBD_MICROSOFT_NATURAL = &device_creator; + +/***************************************************************************** + ADDRESS MAPS +*****************************************************************************/ + +static ADDRESS_MAP_START( microsoft_natural_io, AS_IO, 8, pc_kbd_microsoft_natural_device ) + AM_RANGE(MCS51_PORT_P0, MCS51_PORT_P0) AM_READWRITE(p0_read, p0_write) + AM_RANGE(MCS51_PORT_P1, MCS51_PORT_P1) AM_WRITE(p1_write) + AM_RANGE(MCS51_PORT_P2, MCS51_PORT_P2) AM_WRITE(p2_write) + AM_RANGE(MCS51_PORT_P3, MCS51_PORT_P3) AM_READWRITE(p3_read, p3_write) +ADDRESS_MAP_END + + +/***************************************************************************** + MACHINE CONFIG +*****************************************************************************/ + +MACHINE_CONFIG_FRAGMENT( microsoft_natural ) + MCFG_CPU_ADD("ms_natrl_cpu", I8051, XTAL_6MHz) + MCFG_CPU_IO_MAP(microsoft_natural_io) +MACHINE_CONFIG_END + + +/*************************************************************************** + ROM DEFINITIONS +***************************************************************************/ + +ROM_START( microsoft_natural ) + ROM_REGION(0x1000, "ms_natrl_cpu", 0) + ROM_LOAD("natural.bin", 0x0000, 0x1000, CRC(aa8243ab) SHA1(72134882a5c03e785db07cc54dfb7572c0a730d9)) +ROM_END + + +pc_kbd_microsoft_natural_device::pc_kbd_microsoft_natural_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, PC_KBD_MICROSOFT_NATURAL, "Microsoft Natural Keyboard", tag, owner, clock, "ms_natural", __FILE__) + , device_pc_kbd_interface(mconfig, *this) + , m_cpu(*this, "ms_natrl_cpu") + , m_p2_0(*this, "P2.0") + , m_p2_1(*this, "P2.1") + , m_p2_2(*this, "P2.2") + , m_p2_3(*this, "P2.3") + , m_p2_4(*this, "P2.4") + , m_p2_5(*this, "P2.5") + , m_p2_6(*this, "P2.6") + , m_p2_7(*this, "P2.7") + , m_p1_0(*this, "P1.0") + , m_p1_1(*this, "P1.1") + , m_p1_2(*this, "P1.2") + , m_p1_3(*this, "P1.3") + , m_p1_4(*this, "P1.4") + , m_p1_5(*this, "P1.5") + , m_p1_6(*this, "P1.6") + , m_p1_7(*this, "P1.7") +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- +void pc_kbd_microsoft_natural_device::device_start() +{ + set_pc_kbdc_device(); + + /* setup savestates */ + save_item(NAME(m_p0)); + save_item(NAME(m_p1)); + save_item(NAME(m_p2)); + save_item(NAME(m_p3)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- +void pc_kbd_microsoft_natural_device::device_reset() +{ + /* set default values */ +} + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor pc_kbd_microsoft_natural_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( microsoft_natural ); +} + + +ioport_constructor pc_kbd_microsoft_natural_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( microsoft_natural ); +} + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *pc_kbd_microsoft_natural_device::device_rom_region() const +{ + return ROM_NAME( microsoft_natural ); +} + + +WRITE_LINE_MEMBER( pc_kbd_microsoft_natural_device::clock_write ) +{ +} + + +WRITE_LINE_MEMBER( pc_kbd_microsoft_natural_device::data_write ) +{ +} + + +READ8_MEMBER( pc_kbd_microsoft_natural_device::p0_read ) +{ + UINT8 data = 0xFF; + + if (LOG) + logerror("%s: P0 read. P1 = %02x, P2 = %02x\n", tag(), m_p1, m_p2 ); + + if ( ! ( m_p2 & 0x01 ) ) + { + data &= m_p2_0->read(); + } + + if ( ! ( m_p2 & 0x02 ) ) + { + data &= m_p2_1->read(); + } + + if ( ! ( m_p2 & 0x04 ) ) + { + data &= m_p2_2->read(); + } + + if ( ! ( m_p2 & 0x08 ) ) + { + data &= m_p2_3->read(); + } + + if ( ! ( m_p2 & 0x10 ) ) + { + data &= m_p2_4->read(); + } + + if ( ! ( m_p2 & 0x20 ) ) + { + data &= m_p2_5->read(); + } + + if ( ! ( m_p2 & 0x40 ) ) + { + data &= m_p2_6->read(); + } + + if ( ! ( m_p2 & 0x80 ) ) + { + data &= m_p2_7->read(); + } + + if ( ! ( m_p1 & 0x01 ) ) + { + data &= m_p1_0->read(); + } + + if ( ! ( m_p1 & 0x02 ) ) + { + data &= m_p1_1->read(); + } + + if ( ! ( m_p1 & 0x04 ) ) + { + data &= m_p1_2->read(); + } + + if ( ! ( m_p1 & 0x08 ) ) + { + data &= m_p1_3->read(); + } + + if ( ! ( m_p1 & 0x10 ) ) + { + data &= m_p1_4->read(); + } + + if ( ! ( m_p1 & 0x20 ) ) + { + data &= m_p1_5->read(); + } + + if ( ! ( m_p1 & 0x40 ) ) + { + data &= m_p1_6->read(); + } + + if ( ! ( m_p1 & 0x80 ) ) + { + data &= m_p1_7->read(); + } + + return data; +} + + +WRITE8_MEMBER( pc_kbd_microsoft_natural_device::p0_write ) +{ + m_p0 = data; +} + + +WRITE8_MEMBER( pc_kbd_microsoft_natural_device::p1_write ) +{ + m_p1 = data; +} + + +WRITE8_MEMBER( pc_kbd_microsoft_natural_device::p2_write ) +{ + m_p2 = data; +} + + +READ8_MEMBER( pc_kbd_microsoft_natural_device::p3_read ) +{ + UINT8 data = m_p3 & ~0x21; + + // (Incoming) Clock signal is tied to the T1/P3.5 pin + data |= (clock_signal() ? 0x20 : 0x00); + + // (Incoming) Data signal is tied to the RXD/P3.0 pin + data |= ( data_signal() ? 0x01 : 0x00 ); + + return data; +} + + +WRITE8_MEMBER( pc_kbd_microsoft_natural_device::p3_write ) +{ + if ( m_pc_kbdc ) + { + // (Outgoing) data signal is tied to the WR/P3.6 pin + m_pc_kbdc->data_write_from_kb( BIT(data, 6) ); + + // (Outgoing) clock signal is tied to the T0/P3.4 pin + m_pc_kbdc->clock_write_from_kb( BIT(data, 4) ); + } + + m_p3 = data; +} diff --git a/src/devices/bus/pc_kbd/msnat.h b/src/devices/bus/pc_kbd/msnat.h new file mode 100644 index 00000000000..6ed13a35b8e --- /dev/null +++ b/src/devices/bus/pc_kbd/msnat.h @@ -0,0 +1,74 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +/*************************************************************************** + + Microsoft Natural Keyboard + +***************************************************************************/ + +#ifndef __KB_MSNAT_H__ +#define __KB_MSNAT_H__ + +#include "pc_kbdc.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class pc_kbd_microsoft_natural_device : public device_t, + public device_pc_kbd_interface +{ +public: + // construction/destruction + pc_kbd_microsoft_natural_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + required_device m_cpu; + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual ioport_constructor device_input_ports() const; + virtual const rom_entry *device_rom_region() const; + + virtual DECLARE_WRITE_LINE_MEMBER(clock_write); + virtual DECLARE_WRITE_LINE_MEMBER(data_write); + + DECLARE_READ8_MEMBER(p0_read); + DECLARE_WRITE8_MEMBER(p0_write); + DECLARE_WRITE8_MEMBER(p1_write); + DECLARE_WRITE8_MEMBER(p2_write); + DECLARE_READ8_MEMBER(p3_read); + DECLARE_WRITE8_MEMBER(p3_write); + +protected: + required_ioport m_p2_0; + required_ioport m_p2_1; + required_ioport m_p2_2; + required_ioport m_p2_3; + required_ioport m_p2_4; + required_ioport m_p2_5; + required_ioport m_p2_6; + required_ioport m_p2_7; + required_ioport m_p1_0; + required_ioport m_p1_1; + required_ioport m_p1_2; + required_ioport m_p1_3; + required_ioport m_p1_4; + required_ioport m_p1_5; + required_ioport m_p1_6; + required_ioport m_p1_7; + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + UINT8 m_p0; + UINT8 m_p1; + UINT8 m_p2; + UINT8 m_p3; +}; + + +// device type definition +extern const device_type PC_KBD_MICROSOFT_NATURAL; + +#endif /* __KB_MSNAT_H__ */ diff --git a/src/devices/bus/pc_kbd/pc83.c b/src/devices/bus/pc_kbd/pc83.c new file mode 100644 index 00000000000..ef979eef530 --- /dev/null +++ b/src/devices/bus/pc_kbd/pc83.c @@ -0,0 +1,424 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + IBM 5150 83-key keyboard emulation + +*********************************************************************/ + +#include "pc83.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define I8048_TAG "u1" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type PC_KBD_IBM_PC_83 = &device_creator; + + +//------------------------------------------------- +// ROM( ibm_pc_83_keyboard ) +//------------------------------------------------- + +ROM_START( ibm_pc_83_keyboard ) + ROM_REGION( 0x400, I8048_TAG, 0 ) + ROM_LOAD( "8048.u1", 0x000, 0x400, NO_DUMP ) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *ibm_pc_83_keyboard_device::device_rom_region() const +{ + return ROM_NAME( ibm_pc_83_keyboard ); +} + + +//------------------------------------------------- +// ADDRESS_MAP( kb_io ) +//------------------------------------------------- + +static ADDRESS_MAP_START( ibm_pc_83_keyboard_io, AS_IO, 8, ibm_pc_83_keyboard_device ) + AM_RANGE(MCS48_PORT_BUS, MCS48_PORT_BUS) AM_WRITE(bus_w) + AM_RANGE(MCS48_PORT_P1, MCS48_PORT_P1) AM_READ(p1_r) AM_WRITENOP + AM_RANGE(MCS48_PORT_P2, MCS48_PORT_P2) AM_WRITE(p2_w) + AM_RANGE(MCS48_PORT_T0, MCS48_PORT_T0) AM_READ(t1_r) +ADDRESS_MAP_END + + +//------------------------------------------------- +// MACHINE_DRIVER( ibm_pc_83_keyboard ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( ibm_pc_83_keyboard ) + MCFG_CPU_ADD(I8048_TAG, I8048, MCS48_LC_CLOCK(IND_U(47), CAP_P(20))) + MCFG_CPU_IO_MAP(ibm_pc_83_keyboard_io) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor ibm_pc_83_keyboard_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( ibm_pc_83_keyboard ); +} + + +//------------------------------------------------- +// INPUT_PORTS( ibm_pc_83_keyboard ) +//------------------------------------------------- + +INPUT_PORTS_START( ibm_pc_83_keyboard ) + PORT_START("DR00") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) + + PORT_START("DR01") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) + + PORT_START("DR02") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) + + PORT_START("DR03") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) + + PORT_START("DR04") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) + + PORT_START("DR05") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) + + PORT_START("DR06") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) + + PORT_START("DR07") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) + + PORT_START("DR08") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) + + PORT_START("DR09") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) + + PORT_START("DR10") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) + + PORT_START("DR11") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) + + PORT_START("DR12") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) + + PORT_START("DR13") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) + + PORT_START("DR14") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) + + PORT_START("DR15") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) + + PORT_START("DR16") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) + + PORT_START("DR17") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) + + PORT_START("DR18") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) + + PORT_START("DR19") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) + + PORT_START("DR20") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) + + PORT_START("DR21") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) + + PORT_START("DR22") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) + + PORT_START("DR23") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor ibm_pc_83_keyboard_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( ibm_pc_83_keyboard ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// ibm_pc_83_keyboard_device - constructor +//------------------------------------------------- + +ibm_pc_83_keyboard_device::ibm_pc_83_keyboard_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, PC_KBD_IBM_PC_83, "IBM PC Keyboard", tag, owner, clock, "kb_pc83", __FILE__), + device_pc_kbd_interface(mconfig, *this), + m_maincpu(*this, I8048_TAG), + m_dr00(*this, "DR00"), + m_dr01(*this, "DR01"), + m_dr02(*this, "DR02"), + m_dr03(*this, "DR03"), + m_dr04(*this, "DR04"), + m_dr05(*this, "DR05"), + m_dr06(*this, "DR06"), + m_dr07(*this, "DR07"), + m_dr08(*this, "DR08"), + m_dr09(*this, "DR09"), + m_dr10(*this, "DR10"), + m_dr11(*this, "DR11"), + m_dr12(*this, "DR12"), + m_dr13(*this, "DR13"), + m_dr14(*this, "DR14"), + m_dr15(*this, "DR15"), + m_dr16(*this, "DR16"), + m_dr17(*this, "DR17"), + m_dr18(*this, "DR18"), + m_dr19(*this, "DR19"), + m_dr20(*this, "DR20"), + m_dr21(*this, "DR21"), + m_dr22(*this, "DR22"), + m_dr23(*this, "DR23") +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void ibm_pc_83_keyboard_device::device_start() +{ + // state saving + save_item(NAME(m_cnt)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void ibm_pc_83_keyboard_device::device_reset() +{ + m_maincpu->reset(); +} + + +//------------------------------------------------- +// bus_w - +//------------------------------------------------- + +WRITE8_MEMBER( ibm_pc_83_keyboard_device::bus_w ) +{ + /* + + bit description + + 0 CNT 1 + 1 CNT 2 + 2 CNT 4 + 3 CNT 8 + 4 CNT 16 + 5 CNT 32 + 6 CNT 64 + 7 + + */ + + m_cnt = data & 0x7f; +} + + +//------------------------------------------------- +// p1_r - +//------------------------------------------------- + +READ8_MEMBER( ibm_pc_83_keyboard_device::p1_r ) +{ + /* + + bit description + + 0 -REQ IN + 1 DATA IN + 2 + 3 + 4 + 5 + 6 + 7 + + */ + + UINT8 data = 0; + + data |= clock_signal(); + data |= data_signal() << 1; + + return data; +} + + +//------------------------------------------------- +// p2_w - +//------------------------------------------------- + +WRITE8_MEMBER( ibm_pc_83_keyboard_device::p2_w ) +{ + /* + + bit description + + 0 -MATRIX STROBE + 1 CLOCK OUT + 2 DATA OUT + 3 + 4 + 5 + 6 + 7 + + */ + + m_pc_kbdc->clock_write_from_kb(BIT(data, 1)); + m_pc_kbdc->data_write_from_kb(BIT(data, 2)); +} + + +//------------------------------------------------- +// t1_r - +//------------------------------------------------- + +READ8_MEMBER( ibm_pc_83_keyboard_device::t1_r ) +{ + UINT8 data = 0xff; + + switch (m_cnt >> 2) + { + case 0: data = m_dr00->read(); break; + case 1: data = m_dr01->read(); break; + case 2: data = m_dr02->read(); break; + case 3: data = m_dr03->read(); break; + case 4: data = m_dr04->read(); break; + case 5: data = m_dr05->read(); break; + case 6: data = m_dr06->read(); break; + case 7: data = m_dr07->read(); break; + case 8: data = m_dr08->read(); break; + case 9: data = m_dr09->read(); break; + case 10: data = m_dr10->read(); break; + case 11: data = m_dr11->read(); break; + case 12: data = m_dr12->read(); break; + case 13: data = m_dr13->read(); break; + case 14: data = m_dr14->read(); break; + case 15: data = m_dr15->read(); break; + case 16: data = m_dr16->read(); break; + case 17: data = m_dr17->read(); break; + case 18: data = m_dr18->read(); break; + case 19: data = m_dr19->read(); break; + case 20: data = m_dr20->read(); break; + case 21: data = m_dr21->read(); break; + case 22: data = m_dr22->read(); break; + case 23: data = m_dr23->read(); break; + } + + int sense = m_cnt & 0x03; + + return BIT(data, sense); +} diff --git a/src/devices/bus/pc_kbd/pc83.h b/src/devices/bus/pc_kbd/pc83.h new file mode 100644 index 00000000000..5ee259253ff --- /dev/null +++ b/src/devices/bus/pc_kbd/pc83.h @@ -0,0 +1,89 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + IBM 5150 83-key keyboard emulation + +*********************************************************************/ + +#pragma once + +#ifndef __PC_KBD_IBM_PC_83__ +#define __PC_KBD_IBM_PC_83__ + +#include "emu.h" +#include "cpu/mcs48/mcs48.h" +#include "pc_kbdc.h" +#include "machine/rescap.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> ibm_pc_83_keyboard_device + +class ibm_pc_83_keyboard_device : public device_t, + public device_pc_kbd_interface +{ +public: + // construction/destruction + ibm_pc_83_keyboard_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + virtual ioport_constructor device_input_ports() const; + + DECLARE_WRITE8_MEMBER( bus_w ); + DECLARE_READ8_MEMBER( p1_r ); + DECLARE_WRITE8_MEMBER( p2_w ); + DECLARE_READ8_MEMBER( t1_r ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_pc_kbd_interface overrides + virtual DECLARE_WRITE_LINE_MEMBER( clock_write ) { }; + virtual DECLARE_WRITE_LINE_MEMBER( data_write ) { }; + +private: + required_device m_maincpu; + required_ioport m_dr00; + required_ioport m_dr01; + required_ioport m_dr02; + required_ioport m_dr03; + required_ioport m_dr04; + required_ioport m_dr05; + required_ioport m_dr06; + required_ioport m_dr07; + required_ioport m_dr08; + required_ioport m_dr09; + required_ioport m_dr10; + required_ioport m_dr11; + required_ioport m_dr12; + required_ioport m_dr13; + required_ioport m_dr14; + required_ioport m_dr15; + required_ioport m_dr16; + required_ioport m_dr17; + required_ioport m_dr18; + required_ioport m_dr19; + required_ioport m_dr20; + required_ioport m_dr21; + required_ioport m_dr22; + required_ioport m_dr23; + + UINT8 m_cnt; +}; + + +// device type definition +extern const device_type PC_KBD_IBM_PC_83; + + + +#endif diff --git a/src/devices/bus/pc_kbd/pc_kbdc.c b/src/devices/bus/pc_kbd/pc_kbdc.c new file mode 100644 index 00000000000..296dbbef547 --- /dev/null +++ b/src/devices/bus/pc_kbd/pc_kbdc.c @@ -0,0 +1,235 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +/*************************************************************************** + + PC Keyboard connector interface + +The following basic program can be useful for identifying scancodes: +10 sc%=0:sp%=0 +20 sc%=inp(96) +30 if sc%<>sp% then print hex$(sc%):sp%=sc% +40 goto 20 + +***************************************************************************/ + + +#include "emu.h" +#include "emuopts.h" +#include "pc_kbdc.h" + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type PC_KBDC_SLOT = &device_creator; + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// pc_kbdc_slot_device - constructor +//------------------------------------------------- +pc_kbdc_slot_device::pc_kbdc_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, PC_KBDC_SLOT, "PC_KBDC_SLOT", tag, owner, clock, "pc_kbdc_slot", __FILE__), + device_slot_interface(mconfig, *this) +{ +} + + +void pc_kbdc_slot_device::static_set_pc_kbdc_slot(device_t &device, device_t *kbdc_device) +{ + pc_kbdc_slot_device &pc_kbdc = dynamic_cast(device); + pc_kbdc.m_kbdc_device = kbdc_device; +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void pc_kbdc_slot_device::device_start() +{ + device_pc_kbd_interface *pc_kbd = dynamic_cast(get_card_device()); + + if (pc_kbd) + { + device_pc_kbd_interface::static_set_pc_kbdc( *pc_kbd, m_kbdc_device ); + } +} + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type PC_KBDC = &device_creator; + + +//------------------------------------------------- +// pc_kbdc_device - constructor +//------------------------------------------------- +pc_kbdc_device::pc_kbdc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, PC_KBDC, "PC_KBDC", tag, owner, clock, "pc_kbdc", __FILE__), + m_out_clock_cb(*this), + m_out_data_cb(*this), + m_clock_state(-1), + m_data_state(-1), + m_kb_clock_state(1), + m_kb_data_state(1), + m_keyboard( NULL ) +{ +} + +void pc_kbdc_device::set_keyboard( device_pc_kbd_interface *keyboard ) +{ + m_keyboard = keyboard; +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- +void pc_kbdc_device::device_start() +{ + // resolve callbacks + m_out_clock_cb.resolve_safe(); + m_out_data_cb.resolve_safe(); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- +void pc_kbdc_device::device_reset() +{ + m_clock_state = -1; /* initial state of calculated clock line */ + m_data_state = -1; /* initial state of calculated data line */ + + // Initially assume both keyboard and mainboard have released their data and clock lines + m_mb_clock_state = 1; + m_mb_data_state = 1; + m_kb_clock_state = 1; + m_kb_data_state = 1; +} + + +void pc_kbdc_device::update_clock_state() +{ + int new_clock_state = m_mb_clock_state & m_kb_clock_state; + + if ( new_clock_state != m_clock_state ) + { + // We first set our state to prevent possible endless loops + m_clock_state = new_clock_state; + + // Send state to keyboard interface logic on mainboard + m_out_clock_cb( m_clock_state ); + + // Send state to keyboard + if ( m_keyboard ) + { + m_keyboard->clock_write( m_clock_state ); + } + } +} + + +void pc_kbdc_device::update_data_state() +{ + int new_data_state = m_mb_data_state & m_kb_data_state; + + if ( new_data_state != m_data_state ) + { + // We first set our state to prevent possible endless loops + m_data_state = new_data_state; + + // Send state to keyboard interface logic on mainboard + m_out_data_cb( m_data_state ); + + // Send state to keyboard + if ( m_keyboard ) + { + m_keyboard->data_write( m_data_state ); + } + } +} + + +WRITE_LINE_MEMBER( pc_kbdc_device::clock_write_from_mb ) +{ + m_mb_clock_state = state; + update_clock_state(); +} + + +WRITE_LINE_MEMBER( pc_kbdc_device::data_write_from_mb ) +{ + m_mb_data_state = state; + update_data_state(); +} + + +WRITE_LINE_MEMBER( pc_kbdc_device::clock_write_from_kb ) +{ + m_kb_clock_state = state; + update_clock_state(); +} + + +WRITE_LINE_MEMBER( pc_kbdc_device::data_write_from_kb ) +{ + m_kb_data_state = state; + update_data_state(); +} + + +//************************************************************************** +// DEVICE PC KBD INTERFACE +//************************************************************************** + +//------------------------------------------------- +// device_pc_kbd_interface - constructor +//------------------------------------------------- + +device_pc_kbd_interface::device_pc_kbd_interface(const machine_config &mconfig, device_t &device) + : device_slot_card_interface(mconfig, device), + m_pc_kbdc(NULL), + m_pc_kbdc_tag(NULL) +{ +} + + +//------------------------------------------------- +// ~device_pc_kbd_interface - destructor +//------------------------------------------------- + +device_pc_kbd_interface::~device_pc_kbd_interface() +{ +} + + +WRITE_LINE_MEMBER( device_pc_kbd_interface::clock_write ) +{ +} + + +WRITE_LINE_MEMBER( device_pc_kbd_interface::data_write ) +{ +} + + +void device_pc_kbd_interface::static_set_pc_kbdc(device_t &device, device_t *kbdc_device) +{ + device_pc_kbd_interface &pc_kbd = dynamic_cast(device); + pc_kbd.m_pc_kbdc = dynamic_cast(kbdc_device); +} + + +void device_pc_kbd_interface::set_pc_kbdc_device() +{ + if ( m_pc_kbdc ) + { + m_pc_kbdc->set_keyboard( this ); + } +} diff --git a/src/devices/bus/pc_kbd/pc_kbdc.h b/src/devices/bus/pc_kbd/pc_kbdc.h new file mode 100644 index 00000000000..76b82de023f --- /dev/null +++ b/src/devices/bus/pc_kbd/pc_kbdc.h @@ -0,0 +1,143 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +/*************************************************************************** + + PC Keyboard connector interface + +The data line is usually sampled on changes of the clock line. If you have +a device that changes both the data and clock lines at the same time, first +set the data line and then set the clock line. + +***************************************************************************/ + +#pragma once + +#ifndef __PC_KBDC_H__ +#define __PC_KBDC_H__ + +#include "emu.h" + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_PC_KBDC_OUT_CLOCK_CB(_devcb) \ + devcb = &pc_kbdc_device::set_out_clock_callback(*device, DEVCB_##_devcb); + +#define MCFG_PC_KBDC_OUT_DATA_CB(_devcb) \ + devcb = &pc_kbdc_device::set_out_data_callback(*device, DEVCB_##_devcb); + +#define MCFG_PC_KBDC_SLOT_ADD(_kbdc_tag, _tag, _slot_intf, _def_slot) \ + MCFG_DEVICE_ADD(_tag, PC_KBDC_SLOT, 0 ) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) \ + pc_kbdc_slot_device::static_set_pc_kbdc_slot(*device, owner->subdevice(_kbdc_tag) ); + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + + +class pc_kbdc_slot_device : public device_t, + public device_slot_interface +{ +public: + // construction/destruction + pc_kbdc_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + + // inline configuration + static void static_set_pc_kbdc_slot(device_t &device, device_t *kbdc_device); +protected: + // configuration + device_t *m_kbdc_device; +}; + + +// device type definition +extern const device_type PC_KBDC_SLOT; + + +class device_pc_kbd_interface; + +class pc_kbdc_device : public device_t +{ +public: + // construction/destruction + pc_kbdc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + template static devcb_base &set_out_clock_callback(device_t &device, _Object object) { return downcast(device).m_out_clock_cb.set_callback(object); } + template static devcb_base &set_out_data_callback(device_t &device, _Object object) { return downcast(device).m_out_data_cb.set_callback(object); } + + void set_keyboard(device_pc_kbd_interface *keyboard); + + int clock_signal() { return m_clock_state; } + int data_signal() { return m_data_state; } + + DECLARE_WRITE_LINE_MEMBER( clock_write_from_mb ); + DECLARE_WRITE_LINE_MEMBER( data_write_from_mb ); + DECLARE_WRITE_LINE_MEMBER( clock_write_from_kb ); + DECLARE_WRITE_LINE_MEMBER( data_write_from_kb ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + void update_clock_state(); + void update_data_state(); + + devcb_write_line m_out_clock_cb; + devcb_write_line m_out_data_cb; + + int m_clock_state; + int m_data_state; + + int m_mb_clock_state; + int m_mb_data_state; + int m_kb_clock_state; + int m_kb_data_state; + + device_pc_kbd_interface *m_keyboard; +}; + + +// device type definition +extern const device_type PC_KBDC; + + +// ======================> device_pc_pbd_interface + +class device_pc_kbd_interface : public device_slot_card_interface +{ + friend class pc_kbdc_device; +public: + // construction/destruction + device_pc_kbd_interface(const machine_config &mconfig, device_t &device); + virtual ~device_pc_kbd_interface(); + + device_pc_kbd_interface *next() const { return m_next; } + + void set_pc_kbdc_device(); + + int clock_signal() { return m_pc_kbdc ? m_pc_kbdc->clock_signal() : 1; } + int data_signal() { return m_pc_kbdc ? m_pc_kbdc->data_signal() : 1; } + + // + // Override the clock_write and data_write methods in a keyboard implementation + // + virtual DECLARE_WRITE_LINE_MEMBER( clock_write ); + virtual DECLARE_WRITE_LINE_MEMBER( data_write ); + + // inline configuration + static void static_set_pc_kbdc(device_t &device, device_t *kbdc_device); + + pc_kbdc_device *m_pc_kbdc; + const char *m_pc_kbdc_tag; + device_pc_kbd_interface *m_next; +}; + + + +#endif /* __PC_KBDC_H__ */ diff --git a/src/devices/bus/pc_kbd/pcat84.c b/src/devices/bus/pc_kbd/pcat84.c new file mode 100644 index 00000000000..471333e9d18 --- /dev/null +++ b/src/devices/bus/pc_kbd/pcat84.c @@ -0,0 +1,641 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + IBM Model F PC/AT 84-key / 3270PC 122-key keyboard emulation + +*********************************************************************/ + +/* + + TODO: + + - cpu LC timing + - 3270PC keys + +*/ + +/* + + Part No Layout + ------------------- + 6450225 UK 84-key + 6110344 UK 122-key + +*/ + +#include "pcat84.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define I8048_TAG "m5" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type PC_KBD_IBM_PC_AT_84 = &device_creator; +const device_type PC_KBD_IBM_3270PC_122 = &device_creator; + + +//------------------------------------------------- +// ROM( ibm_pc_at_84_keyboard ) +//------------------------------------------------- + +ROM_START( ibm_pc_at_84_keyboard ) + ROM_REGION( 0x400, I8048_TAG, 0 ) + /* + Keyboard Part No 6450225 + + PH 1503099 + D 878154 + 8441 D H + */ + ROM_LOAD( "1503099.m5", 0x000, 0x400, CRC(1e921f37) SHA1(5f722bdb3b57f5a532c02a5c3f78f30d785796f2) ) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *ibm_pc_at_84_keyboard_device::device_rom_region() const +{ + return ROM_NAME( ibm_pc_at_84_keyboard ); +} + + +//------------------------------------------------- +// ROM( ibm_3270pc_122_keyboard ) +//------------------------------------------------- + +ROM_START( ibm_3270pc_122_keyboard ) + ROM_REGION( 0x400, I8048_TAG, 0 ) + /* + Keyboard Part No 6110344 + + PH 1385001 + D + 8512 D H + */ + ROM_LOAD( "1385001.m5", 0x000, 0x400, CRC(c19767e9) SHA1(a3701e4617383a4de0fd5e2e86c4b74beaf94a7b) ) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *ibm_3270pc_122_keyboard_device::device_rom_region() const +{ + return ROM_NAME( ibm_3270pc_122_keyboard ); +} + + +//------------------------------------------------- +// ADDRESS_MAP( kb_io ) +//------------------------------------------------- + +static ADDRESS_MAP_START( ibm_pc_at_84_keyboard_io, AS_IO, 8, ibm_pc_at_84_keyboard_device ) + AM_RANGE(MCS48_PORT_BUS, MCS48_PORT_BUS) AM_READNOP AM_WRITE(bus_w) + AM_RANGE(MCS48_PORT_P1, MCS48_PORT_P1) AM_READWRITE(p1_r, p1_w) + AM_RANGE(MCS48_PORT_P2, MCS48_PORT_P2) AM_READWRITE(p2_r, p2_w) + AM_RANGE(MCS48_PORT_T0, MCS48_PORT_T0) AM_READ(t0_r) + AM_RANGE(MCS48_PORT_T1, MCS48_PORT_T1) AM_READ(t1_r) +ADDRESS_MAP_END + + +//------------------------------------------------- +// MACHINE_DRIVER( ibm_pc_at_84_keyboard ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( ibm_pc_at_84_keyboard ) + MCFG_CPU_ADD(I8048_TAG, I8048, 5364000) + MCFG_CPU_IO_MAP(ibm_pc_at_84_keyboard_io) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor ibm_pc_at_84_keyboard_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( ibm_pc_at_84_keyboard ); +} + + +//------------------------------------------------- +// INPUT_PORTS( ibm_pc_at_84_keyboard ) +//------------------------------------------------- + +INPUT_PORTS_START( ibm_pc_at_84_keyboard ) + PORT_START("DR00") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F9) PORT_CHAR(UCHAR_MAMEKEY(F9)) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F7) PORT_CHAR(UCHAR_MAMEKEY(F7)) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F5) PORT_CHAR(UCHAR_MAMEKEY(F5)) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F3) PORT_CHAR(UCHAR_MAMEKEY(F3)) + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F1) PORT_CHAR(UCHAR_MAMEKEY(F1)) + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F2) PORT_CHAR(UCHAR_MAMEKEY(F2)) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNUSED ) + + PORT_START("DR01") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F10) PORT_CHAR(UCHAR_MAMEKEY(F10)) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F8) PORT_CHAR(UCHAR_MAMEKEY(F8)) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F6) PORT_CHAR(UCHAR_MAMEKEY(F6)) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F4) PORT_CHAR(UCHAR_MAMEKEY(F4)) + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_TAB) PORT_CHAR(UCHAR_MAMEKEY(TAB)) + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNUSED ) + + PORT_START("DR02") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_LALT) PORT_CHAR(UCHAR_MAMEKEY(LALT)) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_LSHIFT) PORT_CHAR(UCHAR_SHIFT_1) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_LCONTROL) PORT_CHAR(UCHAR_SHIFT_2) + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Q) PORT_CHAR('q') PORT_CHAR('Q') + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_1) PORT_CHAR('1') PORT_CHAR('!') + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNUSED ) + + PORT_START("DR03") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Z) PORT_CHAR('z') PORT_CHAR('Z') + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_S) PORT_CHAR('s') PORT_CHAR('S') + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_A) PORT_CHAR('a') PORT_CHAR('A') + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_W) PORT_CHAR('w') PORT_CHAR('W') + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_2) PORT_CHAR('2') PORT_CHAR('@') + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNUSED ) + + PORT_START("DR04") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_C) PORT_CHAR('c') PORT_CHAR('C') + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_X) PORT_CHAR('x') PORT_CHAR('X') + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_D) PORT_CHAR('d') PORT_CHAR('D') + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_E) PORT_CHAR('e') PORT_CHAR('E') + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_4) PORT_CHAR('4') PORT_CHAR('$') + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_3) PORT_CHAR('3') PORT_CHAR('#') + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNUSED ) + + PORT_START("DR05") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_SPACE) PORT_CHAR(' ') + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_V) PORT_CHAR('v') PORT_CHAR('V') + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F) PORT_CHAR('f') PORT_CHAR('F') + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_T) PORT_CHAR('t') PORT_CHAR('T') + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_R) PORT_CHAR('r') PORT_CHAR('R') + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_5) PORT_CHAR('5') PORT_CHAR('%') + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNUSED ) + + PORT_START("DR06") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_N) PORT_CHAR('n') PORT_CHAR('N') + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_B) PORT_CHAR('b') PORT_CHAR('B') + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_H) PORT_CHAR('h') PORT_CHAR('H') + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_G) PORT_CHAR('g') PORT_CHAR('G') + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Y) PORT_CHAR('y') PORT_CHAR('Y') + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_6) PORT_CHAR('6') PORT_CHAR('^') + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNUSED ) + + PORT_START("DR07") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_M) PORT_CHAR('m') PORT_CHAR('M') + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_J) PORT_CHAR('j') PORT_CHAR('J') + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_U) PORT_CHAR('u') PORT_CHAR('U') + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_7) PORT_CHAR('7') PORT_CHAR('&') + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_8) PORT_CHAR('8') PORT_CHAR('*') + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNUSED ) + + PORT_START("DR08") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_COMMA) PORT_CHAR(',') PORT_CHAR('<') + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_K) PORT_CHAR('k') PORT_CHAR('K') + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_I) PORT_CHAR('i') PORT_CHAR('I') + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_O) PORT_CHAR('o') PORT_CHAR('O') + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_0) PORT_CHAR('0') PORT_CHAR(')') + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_9) PORT_CHAR('9') PORT_CHAR('(') + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNUSED ) + + PORT_START("DR09") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_STOP) PORT_CHAR('.') PORT_CHAR('>') + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_SLASH) PORT_CHAR('/') PORT_CHAR('?') + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_L) PORT_CHAR('l') PORT_CHAR('L') + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_COLON) PORT_CHAR(';') PORT_CHAR(':') + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_P) PORT_CHAR('p') PORT_CHAR('P') + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_MINUS) PORT_CHAR('-') PORT_CHAR('_') + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNUSED ) + + PORT_START("DR10") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_SPECIAL ) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_QUOTE) PORT_CHAR('\'') PORT_CHAR('"') + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_OPENBRACE) PORT_CHAR('[') PORT_CHAR('{') + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_EQUALS) PORT_CHAR('=') PORT_CHAR('+') + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_CAPSLOCK) PORT_CHAR(UCHAR_MAMEKEY(CAPSLOCK)) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_RSHIFT) PORT_CHAR(UCHAR_SHIFT_1) + + PORT_START("DR11") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_CLOSEBRACE) PORT_CHAR(']') PORT_CHAR('}') + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_ENTER) PORT_CHAR(13) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_TILDE) PORT_CHAR('`') PORT_CHAR('~') + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNUSED ) + + PORT_START("DR12") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_BACKSPACE) PORT_CHAR(8) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNUSED ) + + PORT_START("DR13") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad 1 End") PORT_CODE(KEYCODE_1_PAD) PORT_CHAR(UCHAR_MAMEKEY(1_PAD)) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad 4 " UTF8_LEFT) PORT_CODE(KEYCODE_4_PAD) PORT_CHAR(UCHAR_MAMEKEY(4_PAD)) + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad 7 Home") PORT_CODE(KEYCODE_7_PAD) PORT_CHAR(UCHAR_MAMEKEY(7_PAD)) + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNUSED ) + + PORT_START("DR14") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad 0 Ins") PORT_CODE(KEYCODE_0_PAD) PORT_CHAR(UCHAR_MAMEKEY(0_PAD)) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad . Del") PORT_CODE(KEYCODE_DEL_PAD) PORT_CHAR(UCHAR_MAMEKEY(DEL_PAD)) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad 2 " UTF8_DOWN) PORT_CODE(KEYCODE_2_PAD) PORT_CHAR(UCHAR_MAMEKEY(2_PAD)) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_5_PAD) PORT_CHAR(UCHAR_MAMEKEY(5_PAD)) + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad 6 " UTF8_RIGHT) PORT_CODE(KEYCODE_6_PAD) PORT_CHAR(UCHAR_MAMEKEY(6_PAD)) + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad 8 " UTF8_UP) PORT_CODE(KEYCODE_8_PAD) PORT_CHAR(UCHAR_MAMEKEY(8_PAD)) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_ESC) PORT_CHAR(UCHAR_MAMEKEY(ESC)) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_NUMLOCK) PORT_CHAR(UCHAR_MAMEKEY(NUMLOCK)) + + PORT_START("DR15") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_PLUS_PAD) PORT_CHAR(UCHAR_MAMEKEY(PLUS_PAD)) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad 3 PgDn") PORT_CODE(KEYCODE_3_PAD) PORT_CHAR(UCHAR_MAMEKEY(3_PAD)) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_MINUS_PAD) PORT_CHAR(UCHAR_MAMEKEY(MINUS_PAD)) + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad * PrtSc") PORT_CODE(KEYCODE_ASTERISK) PORT_CHAR(UCHAR_MAMEKEY(ASTERISK)) + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad 9 PgUp") PORT_CODE(KEYCODE_9_PAD) PORT_CHAR(UCHAR_MAMEKEY(9_PAD)) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Scroll Lock Break") PORT_CODE(KEYCODE_SCRLOCK) PORT_CHAR(UCHAR_MAMEKEY(SCRLOCK)) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Sys Req") +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor ibm_pc_at_84_keyboard_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( ibm_pc_at_84_keyboard ); +} + + +//------------------------------------------------- +// INPUT_PORTS( ibm_3270pc_122_keyboard ) +//------------------------------------------------- + +INPUT_PORTS_START( ibm_3270pc_122_keyboard ) + PORT_INCLUDE(ibm_pc_at_84_keyboard) + + PORT_START("KBDIDA") + PORT_DIPUNUSED( 0x01, IP_ACTIVE_LOW ) + PORT_DIPUNUSED( 0x02, IP_ACTIVE_LOW ) + PORT_DIPUNUSED( 0x04, IP_ACTIVE_LOW ) + PORT_DIPUNUSED( 0x08, IP_ACTIVE_LOW ) + PORT_DIPUNUSED( 0x10, IP_ACTIVE_LOW ) + PORT_DIPUNUSED( 0x20, IP_ACTIVE_LOW ) + + PORT_START("KBDIDB") + PORT_DIPUNUSED( 0x01, IP_ACTIVE_LOW ) + PORT_DIPUNUSED( 0x02, IP_ACTIVE_LOW ) + PORT_DIPUNUSED( 0x04, IP_ACTIVE_LOW ) + PORT_DIPUNUSED( 0x08, IP_ACTIVE_LOW ) + PORT_DIPUNUSED( 0x10, IP_ACTIVE_LOW ) + PORT_DIPUNUSED( 0x20, IP_ACTIVE_LOW ) +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor ibm_3270pc_122_keyboard_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( ibm_3270pc_122_keyboard ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// ibm_pc_at_84_keyboard_device - constructor +//------------------------------------------------- + +ibm_pc_at_84_keyboard_device::ibm_pc_at_84_keyboard_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_pc_kbd_interface(mconfig, *this), + m_maincpu(*this, I8048_TAG), + m_dr00(*this, "DR00"), + m_dr01(*this, "DR01"), + m_dr02(*this, "DR02"), + m_dr03(*this, "DR03"), + m_dr04(*this, "DR04"), + m_dr05(*this, "DR05"), + m_dr06(*this, "DR06"), + m_dr07(*this, "DR07"), + m_dr08(*this, "DR08"), + m_dr09(*this, "DR09"), + m_dr10(*this, "DR10"), + m_dr11(*this, "DR11"), + m_dr12(*this, "DR12"), + m_dr13(*this, "DR13"), + m_dr14(*this, "DR14"), + m_dr15(*this, "DR15"), + m_kbdida(*this, "KBDIDA"), + m_kbdidb(*this, "KBDIDB"), + m_db(0), + m_cnt(0), + m_sense(0), + m_t1(1) +{ +} + +ibm_pc_at_84_keyboard_device::ibm_pc_at_84_keyboard_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, PC_KBD_IBM_PC_AT_84, "IBM PC/AT Keyboard", tag, owner, clock, "kb_pcat84", __FILE__), + device_pc_kbd_interface(mconfig, *this), + m_maincpu(*this, I8048_TAG), + m_dr00(*this, "DR00"), + m_dr01(*this, "DR01"), + m_dr02(*this, "DR02"), + m_dr03(*this, "DR03"), + m_dr04(*this, "DR04"), + m_dr05(*this, "DR05"), + m_dr06(*this, "DR06"), + m_dr07(*this, "DR07"), + m_dr08(*this, "DR08"), + m_dr09(*this, "DR09"), + m_dr10(*this, "DR10"), + m_dr11(*this, "DR11"), + m_dr12(*this, "DR12"), + m_dr13(*this, "DR13"), + m_dr14(*this, "DR14"), + m_dr15(*this, "DR15"), + m_kbdida(*this, "KBDIDA"), + m_kbdidb(*this, "KBDIDB"), + m_db(0), + m_cnt(0), + m_sense(0), + m_t1(1) +{ +} + +ibm_3270pc_122_keyboard_device::ibm_3270pc_122_keyboard_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : ibm_pc_at_84_keyboard_device(mconfig, PC_KBD_IBM_3270PC_122, "IBM 3270PC Keyboard", tag, owner, clock, "kb_3270pc", __FILE__) { } + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void ibm_pc_at_84_keyboard_device::device_start() +{ + set_pc_kbdc_device(); + + // state saving + save_item(NAME(m_db)); + save_item(NAME(m_cnt)); + save_item(NAME(m_sense)); + save_item(NAME(m_t1)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void ibm_pc_at_84_keyboard_device::device_reset() +{ + m_maincpu->reset(); +} + + +//------------------------------------------------- +// bus_w - +//------------------------------------------------- + +WRITE8_MEMBER( ibm_pc_at_84_keyboard_device::bus_w ) +{ + /* + + bit description + + 0 SENSE 0 + 1 SENSE 1 + 2 SENSE 2 + 3 CNT 0 + 4 CNT 1 + 5 CNT 2 + 6 CNT 3 + 7 CNT G + + */ + + m_db = data; + + if (!BIT(data, 7)) + { + m_cnt = (data >> 3) & 0x0f; + } +} + + +//------------------------------------------------- +// p1_r - +//------------------------------------------------- + +READ8_MEMBER( ibm_pc_at_84_keyboard_device::p1_r ) +{ + /* + + bit description + + 0 + 1 + 2 KBDID A1 + 3 KBDID A2 + 4 KBDID A3 + 5 KBDID A4 + 6 KBDID A5 + 7 KBDID A6 + + */ + + UINT8 data = 0; + + data |= m_kbdida->read() << 2; + + return data; +} + + +//------------------------------------------------- +// p1_w - +//------------------------------------------------- + +WRITE8_MEMBER( ibm_pc_at_84_keyboard_device::p1_w ) +{ + /* + + bit description + + 0 SENSE G + 1 T1 + 2 + 3 + 4 + 5 + 6 + 7 + + */ + + if (!BIT(data, 0)) + { + m_sense = m_db & 0x07; + } + + m_t1 = BIT(data, 1); +} + + +//------------------------------------------------- +// p2_r - +//------------------------------------------------- + +READ8_MEMBER( ibm_pc_at_84_keyboard_device::p2_r ) +{ + /* + + bit description + + 0 KBDID B1 + 1 KBDID B2 + 2 KBDID B3 + 3 KBDID B4 + 4 KBDID B5 + 5 KBDID B6 + 6 + 7 + + */ + + UINT8 data = 0xc0; + + data |= m_kbdidb->read(); + + return data; +} + + +//------------------------------------------------- +// p2_w - +//------------------------------------------------- + +WRITE8_MEMBER( ibm_pc_at_84_keyboard_device::p2_w ) +{ + /* + + bit description + + 0 SCROLL LED + 1 NUM LED + 2 CAPS LED + 3 + 4 + 5 + 6 CLOCK + 7 DATA + + */ + + output_set_led_value(LED_SCROLL, BIT(data, 0)); + output_set_led_value(LED_NUM, BIT(data, 1)); + output_set_led_value(LED_CAPS, BIT(data, 2)); + + m_pc_kbdc->data_write_from_kb(!BIT(data, 7)); + m_pc_kbdc->clock_write_from_kb(!BIT(data, 6)); +} + + +//------------------------------------------------- +// t0_r - +//------------------------------------------------- + +READ8_MEMBER( ibm_pc_at_84_keyboard_device::t0_r ) +{ + return !data_signal(); +} + + +//------------------------------------------------- +// t1_r - +//------------------------------------------------- + +READ8_MEMBER( ibm_pc_at_84_keyboard_device::t1_r ) +{ + return key_depressed(); +} + + +//------------------------------------------------- +// key_depressed - +//------------------------------------------------- + +int ibm_pc_at_84_keyboard_device::key_depressed() +{ + UINT8 data = 0xff; + + switch (m_cnt) + { + case 0: data = m_dr00->read(); break; + case 1: data = m_dr01->read(); break; + case 2: data = m_dr02->read(); break; + case 3: data = m_dr03->read(); break; + case 4: data = m_dr04->read(); break; + case 5: data = m_dr05->read(); break; + case 6: data = m_dr06->read(); break; + case 7: data = m_dr07->read(); break; + case 8: data = m_dr08->read(); break; + case 9: data = m_dr09->read(); break; + case 10: data = m_dr10->read(); break; + case 11: data = m_dr11->read(); break; + case 12: data = m_dr12->read(); break; + case 13: data = m_dr13->read(); break; + case 14: data = m_dr14->read(); break; + case 15: data = m_dr15->read(); break; + } + + return m_t1 && BIT(data, m_sense); +} diff --git a/src/devices/bus/pc_kbd/pcat84.h b/src/devices/bus/pc_kbd/pcat84.h new file mode 100644 index 00000000000..06f58c84738 --- /dev/null +++ b/src/devices/bus/pc_kbd/pcat84.h @@ -0,0 +1,114 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + IBM Model F PC/AT 84-key / 3270PC 122-key keyboard emulation + +*********************************************************************/ + +#pragma once + +#ifndef __PC_KBD_IBM_PC_AT_84__ +#define __PC_KBD_IBM_PC_AT_84__ + +#include "emu.h" +#include "cpu/mcs48/mcs48.h" +#include "pc_kbdc.h" +#include "machine/rescap.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> ibm_pc_at_84_keyboard_device + +class ibm_pc_at_84_keyboard_device : public device_t, + public device_pc_kbd_interface +{ +public: + // construction/destruction + ibm_pc_at_84_keyboard_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + ibm_pc_at_84_keyboard_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + virtual ioport_constructor device_input_ports() const; + + DECLARE_WRITE8_MEMBER( bus_w ); + DECLARE_READ8_MEMBER( p1_r ); + DECLARE_WRITE8_MEMBER( p1_w ); + DECLARE_READ8_MEMBER( p2_r ); + DECLARE_WRITE8_MEMBER( p2_w ); + DECLARE_READ8_MEMBER( t0_r ); + DECLARE_READ8_MEMBER( t1_r ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_pc_kbd_interface overrides + virtual DECLARE_WRITE_LINE_MEMBER( clock_write ) { m_maincpu->set_input_line(MCS48_INPUT_IRQ, state); }; + virtual DECLARE_WRITE_LINE_MEMBER( data_write ) { }; + +private: + enum + { + LED_SCROLL, + LED_NUM, + LED_CAPS + }; + + int key_depressed(); + + required_device m_maincpu; + required_ioport m_dr00; + required_ioport m_dr01; + required_ioport m_dr02; + required_ioport m_dr03; + required_ioport m_dr04; + required_ioport m_dr05; + required_ioport m_dr06; + required_ioport m_dr07; + required_ioport m_dr08; + required_ioport m_dr09; + required_ioport m_dr10; + required_ioport m_dr11; + required_ioport m_dr12; + required_ioport m_dr13; + required_ioport m_dr14; + required_ioport m_dr15; + optional_ioport m_kbdida; + optional_ioport m_kbdidb; + + UINT8 m_db; + int m_cnt; + int m_sense; + int m_t1; +}; + + +// ======================> ibm_3270pc_122_keyboard_device + +class ibm_3270pc_122_keyboard_device : public ibm_pc_at_84_keyboard_device +{ +public: + // construction/destruction + ibm_3270pc_122_keyboard_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual ioport_constructor device_input_ports() const; +}; + + +// device type definition +extern const device_type PC_KBD_IBM_PC_AT_84; +extern const device_type PC_KBD_IBM_3270PC_122; + + + +#endif diff --git a/src/devices/bus/pc_kbd/pcxt83.c b/src/devices/bus/pc_kbd/pcxt83.c new file mode 100644 index 00000000000..dfbc5616b73 --- /dev/null +++ b/src/devices/bus/pc_kbd/pcxt83.c @@ -0,0 +1,451 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + IBM Model F PC/XT 83-key keyboard emulation + +*********************************************************************/ + +/* + + Part No Layout + ------------------- + 1501100 US + 1501102 Germany + 1501105 UK + +*/ + +#include "pcxt83.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define I8048_TAG "i8048" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type PC_KBD_IBM_PC_XT_83 = &device_creator; + + +//------------------------------------------------- +// ROM( ibm_pc_xt_83_keyboard ) +//------------------------------------------------- + +ROM_START( ibm_pc_xt_83_keyboard ) + ROM_REGION( 0x400, I8048_TAG, 0 ) + /* + Keyboard Part No. 1501105 + + MOI 74 01 + PN 4584751 + GX 344231 + + i 4429745 + ZO P 379297 + 8143 P + (C) INTEL 76 + */ + ROM_LOAD( "4584751.m1", 0x000, 0x400, CRC(c59aa9d1) SHA1(4f5b2a075c68f6493310ec1e2a24271ceea330df) ) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *ibm_pc_xt_83_keyboard_device::device_rom_region() const +{ + return ROM_NAME( ibm_pc_xt_83_keyboard ); +} + + +//------------------------------------------------- +// ADDRESS_MAP( kb_io ) +//------------------------------------------------- + +static ADDRESS_MAP_START( ibm_pc_xt_83_keyboard_io, AS_IO, 8, ibm_pc_xt_83_keyboard_device ) + AM_RANGE(MCS48_PORT_BUS, MCS48_PORT_BUS) AM_READWRITE(bus_r, bus_w) + AM_RANGE(MCS48_PORT_P1, MCS48_PORT_P1) AM_WRITE(p1_w) + AM_RANGE(MCS48_PORT_P2, MCS48_PORT_P2) AM_WRITE(p2_w) + AM_RANGE(MCS48_PORT_T0, MCS48_PORT_T0) AM_READ(t0_r) + AM_RANGE(MCS48_PORT_T1, MCS48_PORT_T1) AM_READ(t1_r) +ADDRESS_MAP_END + + +//------------------------------------------------- +// MACHINE_DRIVER( ibm_pc_xt_83_keyboard ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( ibm_pc_xt_83_keyboard ) + MCFG_CPU_ADD(I8048_TAG, I8048, MCS48_LC_CLOCK(IND_U(47), CAP_P(20.7))) + MCFG_CPU_IO_MAP(ibm_pc_xt_83_keyboard_io) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor ibm_pc_xt_83_keyboard_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( ibm_pc_xt_83_keyboard ); +} + + +//------------------------------------------------- +// INPUT_PORTS( ibm_pc_xt_83_keyboard ) +//------------------------------------------------- + +INPUT_PORTS_START( ibm_pc_xt_83_keyboard ) + PORT_START("MD00") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_PLUS_PAD) PORT_CHAR(UCHAR_MAMEKEY(PLUS_PAD)) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad 3 PgDn") PORT_CODE(KEYCODE_3_PAD) PORT_CHAR(UCHAR_MAMEKEY(3_PAD)) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad 6 " UTF8_RIGHT) PORT_CODE(KEYCODE_6_PAD) PORT_CHAR(UCHAR_MAMEKEY(6_PAD)) + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_MINUS_PAD) PORT_CHAR(UCHAR_MAMEKEY(MINUS_PAD)) + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad 9 PgUp") PORT_CODE(KEYCODE_9_PAD) PORT_CHAR(UCHAR_MAMEKEY(9_PAD)) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Scroll Lock Break") PORT_CODE(KEYCODE_SCRLOCK) PORT_CHAR(UCHAR_MAMEKEY(SCRLOCK)) + + PORT_START("MD01") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad . Del") PORT_CODE(KEYCODE_DEL_PAD) PORT_CHAR(UCHAR_MAMEKEY(DEL_PAD)) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad 2 " UTF8_DOWN) PORT_CODE(KEYCODE_2_PAD) PORT_CHAR(UCHAR_MAMEKEY(2_PAD)) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad 1 End") PORT_CODE(KEYCODE_1_PAD) PORT_CHAR(UCHAR_MAMEKEY(1_PAD)) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_5_PAD) PORT_CHAR(UCHAR_MAMEKEY(5_PAD)) + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad 4 " UTF8_LEFT) PORT_CODE(KEYCODE_4_PAD) PORT_CHAR(UCHAR_MAMEKEY(4_PAD)) + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad 7 Home") PORT_CODE(KEYCODE_7_PAD) PORT_CHAR(UCHAR_MAMEKEY(7_PAD)) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad 8 " UTF8_UP) PORT_CODE(KEYCODE_8_PAD) PORT_CHAR(UCHAR_MAMEKEY(8_PAD)) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_NUMLOCK) PORT_CHAR(UCHAR_MAMEKEY(NUMLOCK)) + + PORT_START("MD02") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad 0 Ins") PORT_CODE(KEYCODE_0_PAD) PORT_CHAR(UCHAR_MAMEKEY(0_PAD)) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad * PrtSc") PORT_CODE(KEYCODE_ASTERISK) PORT_CHAR(UCHAR_MAMEKEY(ASTERISK)) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_RSHIFT) PORT_CHAR(UCHAR_SHIFT_1) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_TILDE) PORT_CHAR('`') PORT_CHAR('~') + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_ENTER) PORT_CHAR(13) + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_BACKSPACE) PORT_CHAR(8) + + PORT_START("MD03") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_CAPSLOCK) PORT_CHAR(UCHAR_MAMEKEY(CAPSLOCK)) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_SLASH) PORT_CHAR('/') PORT_CHAR('?') + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_QUOTE) PORT_CHAR('\'') PORT_CHAR('"') + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_CLOSEBRACE) PORT_CHAR(']') PORT_CHAR('}') + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_OPENBRACE) PORT_CHAR('[') PORT_CHAR('{') + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_EQUALS) PORT_CHAR('=') PORT_CHAR('+') + + PORT_START("MD04") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_STOP) PORT_CHAR('.') PORT_CHAR('>') + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_COLON) PORT_CHAR(';') PORT_CHAR(':') + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_L) PORT_CHAR('l') PORT_CHAR('L') + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_P) PORT_CHAR('p') PORT_CHAR('P') + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_MINUS) PORT_CHAR('-') PORT_CHAR('_') + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_0) PORT_CHAR('0') PORT_CHAR(')') + + PORT_START("MD05") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_M) PORT_CHAR('m') PORT_CHAR('M') + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_COMMA) PORT_CHAR(',') PORT_CHAR('<') + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_K) PORT_CHAR('k') PORT_CHAR('K') + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_J) PORT_CHAR('j') PORT_CHAR('J') + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_O) PORT_CHAR('o') PORT_CHAR('O') + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_I) PORT_CHAR('i') PORT_CHAR('I') + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_9) PORT_CHAR('9') PORT_CHAR('(') + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_8) PORT_CHAR('8') PORT_CHAR('*') + + PORT_START("MD06") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_SPACE) PORT_CHAR(' ') + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_N) PORT_CHAR('n') PORT_CHAR('N') + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_B) PORT_CHAR('b') PORT_CHAR('B') + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_H) PORT_CHAR('h') PORT_CHAR('H') + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_U) PORT_CHAR('u') PORT_CHAR('U') + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Y) PORT_CHAR('y') PORT_CHAR('Y') + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_7) PORT_CHAR('7') PORT_CHAR('&') + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_6) PORT_CHAR('6') PORT_CHAR('^') + + PORT_START("MD07") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_C) PORT_CHAR('c') PORT_CHAR('C') + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_V) PORT_CHAR('v') PORT_CHAR('V') + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_G) PORT_CHAR('g') PORT_CHAR('G') + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F) PORT_CHAR('f') PORT_CHAR('F') + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_T) PORT_CHAR('t') PORT_CHAR('T') + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_R) PORT_CHAR('r') PORT_CHAR('R') + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_5) PORT_CHAR('5') PORT_CHAR('%') + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_4) PORT_CHAR('4') PORT_CHAR('$') + + PORT_START("MD08") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_X) PORT_CHAR('x') PORT_CHAR('X') + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Z) PORT_CHAR('z') PORT_CHAR('Z') + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_D) PORT_CHAR('d') PORT_CHAR('D') + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_S) PORT_CHAR('s') PORT_CHAR('S') + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_E) PORT_CHAR('e') PORT_CHAR('E') + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_W) PORT_CHAR('w') PORT_CHAR('W') + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_3) PORT_CHAR('3') PORT_CHAR('#') + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_2) PORT_CHAR('2') PORT_CHAR('@') + + PORT_START("MD09") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_BACKSLASH) PORT_CHAR('\\') PORT_CHAR('|') + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_LSHIFT) PORT_CHAR(UCHAR_SHIFT_1) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_LCONTROL) PORT_CHAR(UCHAR_SHIFT_2) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_A) PORT_CHAR('a') PORT_CHAR('A') + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Q) PORT_CHAR('q') PORT_CHAR('Q') + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_TAB) PORT_CHAR(UCHAR_MAMEKEY(TAB)) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_1) PORT_CHAR('1') PORT_CHAR('!') + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_ESC) PORT_CHAR(UCHAR_MAMEKEY(ESC)) + + PORT_START("MD10") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_LALT) PORT_CHAR(UCHAR_MAMEKEY(LALT)) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F10) PORT_CHAR(UCHAR_MAMEKEY(F10)) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F8) PORT_CHAR(UCHAR_MAMEKEY(F8)) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F6) PORT_CHAR(UCHAR_MAMEKEY(F6)) + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F4) PORT_CHAR(UCHAR_MAMEKEY(F4)) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F2) PORT_CHAR(UCHAR_MAMEKEY(F2)) + + PORT_START("MD11") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F9) PORT_CHAR(UCHAR_MAMEKEY(F9)) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F7) PORT_CHAR(UCHAR_MAMEKEY(F7)) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F5) PORT_CHAR(UCHAR_MAMEKEY(F5)) + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F3) PORT_CHAR(UCHAR_MAMEKEY(F3)) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_SPECIAL ) // 76 "Clear" + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F1) PORT_CHAR(UCHAR_MAMEKEY(F1)) +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor ibm_pc_xt_83_keyboard_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( ibm_pc_xt_83_keyboard ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// ibm_pc_xt_83_keyboard_device - constructor +//------------------------------------------------- + +ibm_pc_xt_83_keyboard_device::ibm_pc_xt_83_keyboard_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, PC_KBD_IBM_PC_XT_83, "IBM PC/XT Keyboard", tag, owner, clock, "kb_pcxt83", __FILE__), + device_pc_kbd_interface(mconfig, *this), + m_maincpu(*this, I8048_TAG), + m_md00(*this, "MD00"), + m_md01(*this, "MD01"), + m_md02(*this, "MD02"), + m_md03(*this, "MD03"), + m_md04(*this, "MD04"), + m_md05(*this, "MD05"), + m_md06(*this, "MD06"), + m_md07(*this, "MD07"), + m_md08(*this, "MD08"), + m_md09(*this, "MD09"), + m_md10(*this, "MD10"), + m_md11(*this, "MD11"), + m_bus(0xff), + m_p1(0xff), + m_p2(0xff), + m_sense(0), + m_q(1) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void ibm_pc_xt_83_keyboard_device::device_start() +{ + set_pc_kbdc_device(); + + // state saving + save_item(NAME(m_bus)); + save_item(NAME(m_p1)); + save_item(NAME(m_p2)); + save_item(NAME(m_sense)); + save_item(NAME(m_q)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void ibm_pc_xt_83_keyboard_device::device_reset() +{ +} + + +//------------------------------------------------- +// clock_write - +//------------------------------------------------- + +WRITE_LINE_MEMBER( ibm_pc_xt_83_keyboard_device::clock_write ) +{ +} + + +//------------------------------------------------- +// data_write - +//------------------------------------------------- + +WRITE_LINE_MEMBER( ibm_pc_xt_83_keyboard_device::data_write ) +{ + m_maincpu->set_input_line(MCS48_INPUT_IRQ, state ? CLEAR_LINE : ASSERT_LINE); +} + + +//------------------------------------------------- +// bus_r - +//------------------------------------------------- + +READ8_MEMBER( ibm_pc_xt_83_keyboard_device::bus_r ) +{ + // HACK this should be handled in mcs48.c + return m_bus; +} + + +//------------------------------------------------- +// bus_w - +//------------------------------------------------- + +WRITE8_MEMBER( ibm_pc_xt_83_keyboard_device::bus_w ) +{ + /* + + bit description + + 0 + 1 + 2 + 3 + 4 + 5 DATAOUT + 6 -REQOUT + 7 Z1 RESET + + */ + + m_pc_kbdc->data_write_from_kb(BIT(data, 5)); + m_pc_kbdc->clock_write_from_kb(BIT(data, 6)); + + if (!BIT(m_bus, 7) && BIT(data, 7)) + { + UINT8 data = 0xff; + + if (BIT(m_p1, 0)) data &= m_md00->read(); + if (BIT(m_p1, 1)) data &= m_md01->read(); + if (BIT(m_p1, 2)) data &= m_md02->read(); + if (BIT(m_p1, 3)) data &= m_md03->read(); + if (BIT(m_p1, 4)) data &= m_md04->read(); + if (BIT(m_p1, 5)) data &= m_md05->read(); + if (BIT(m_p1, 6)) data &= m_md06->read(); + if (BIT(m_p1, 7)) data &= m_md07->read(); + if (BIT(m_p2, 4)) data &= m_md08->read(); + if (BIT(m_p2, 5)) data &= m_md09->read(); + if (BIT(m_p2, 6)) data &= m_md10->read(); + if (BIT(m_p2, 7)) data &= m_md11->read(); + + m_q = BIT(data, m_sense); + } + + m_bus = data; +} + + +//------------------------------------------------- +// p1_w - +//------------------------------------------------- + +WRITE8_MEMBER( ibm_pc_xt_83_keyboard_device::p1_w ) +{ + /* + + bit description + + 0 MD00 + 1 MD01 + 2 MD02 + 3 MD03 + 4 MD04 + 5 MD05 + 6 MD06 + 7 MD07 + + */ + + m_p1 = data; +} + + +//------------------------------------------------- +// p2_w - +//------------------------------------------------- + +WRITE8_MEMBER( ibm_pc_xt_83_keyboard_device::p2_w ) +{ + /* + + bit description + + 0 SELECT 2 + 1 SELECT 1 + 2 SELECT 0 + 3 SA CLOSED + 4 MD08 + 5 MD09 + 6 MD10 + 7 MD11 + + */ + + if (!BIT(m_p2, 3) && BIT(data, 3)) + { + m_sense = data & 0x07; + } + + m_p2 = data; +} + + +//------------------------------------------------- +// t0_r - +//------------------------------------------------- + +READ8_MEMBER( ibm_pc_xt_83_keyboard_device::t0_r ) +{ + return clock_signal(); +} + + +//------------------------------------------------- +// t1_r - +//------------------------------------------------- + +READ8_MEMBER( ibm_pc_xt_83_keyboard_device::t1_r ) +{ + return BIT(m_p2, 3) && m_q; +} diff --git a/src/devices/bus/pc_kbd/pcxt83.h b/src/devices/bus/pc_kbd/pcxt83.h new file mode 100644 index 00000000000..cec03f8bc92 --- /dev/null +++ b/src/devices/bus/pc_kbd/pcxt83.h @@ -0,0 +1,83 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + IBM Model F PC/XT 83-key keyboard emulation + +*********************************************************************/ + +#pragma once + +#ifndef __PC_KBD_IBM_PC_XT_83__ +#define __PC_KBD_IBM_PC_XT_83__ + +#include "emu.h" +#include "cpu/mcs48/mcs48.h" +#include "pc_kbdc.h" +#include "machine/rescap.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> ibm_pc_xt_83_keyboard_device + +class ibm_pc_xt_83_keyboard_device : public device_t, + public device_pc_kbd_interface +{ +public: + // construction/destruction + ibm_pc_xt_83_keyboard_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + virtual ioport_constructor device_input_ports() const; + + DECLARE_READ8_MEMBER( bus_r ); + DECLARE_WRITE8_MEMBER( bus_w ); + DECLARE_WRITE8_MEMBER( p1_w ); + DECLARE_WRITE8_MEMBER( p2_w ); + DECLARE_READ8_MEMBER( t0_r ); + DECLARE_READ8_MEMBER( t1_r ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_pc_kbd_interface overrides + virtual DECLARE_WRITE_LINE_MEMBER( clock_write ); + virtual DECLARE_WRITE_LINE_MEMBER( data_write ); + +private: + required_device m_maincpu; + required_ioport m_md00; + required_ioport m_md01; + required_ioport m_md02; + required_ioport m_md03; + required_ioport m_md04; + required_ioport m_md05; + required_ioport m_md06; + required_ioport m_md07; + required_ioport m_md08; + required_ioport m_md09; + required_ioport m_md10; + required_ioport m_md11; + + UINT8 m_bus; + UINT8 m_p1; + UINT8 m_p2; + int m_sense; + int m_q; +}; + + +// device type definition +extern const device_type PC_KBD_IBM_PC_XT_83; + + + +#endif diff --git a/src/devices/bus/pce/pce_rom.c b/src/devices/bus/pce/pce_rom.c new file mode 100644 index 00000000000..8829e7823d0 --- /dev/null +++ b/src/devices/bus/pce/pce_rom.c @@ -0,0 +1,126 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + PC-Engine & Turbografx-16 cart emulation + + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "pce_rom.h" + + +//------------------------------------------------- +// pce_rom_device - constructor +//------------------------------------------------- + +const device_type PCE_ROM_STD = &device_creator; +const device_type PCE_ROM_CDSYS3 = &device_creator; +const device_type PCE_ROM_POPULOUS = &device_creator; +const device_type PCE_ROM_SF2 = &device_creator; + + +pce_rom_device::pce_rom_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_pce_cart_interface( mconfig, *this ) +{ +} + +pce_rom_device::pce_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, PCE_ROM_STD, "PCE & TG16 Carts", tag, owner, clock, "pce_rom", __FILE__), + device_pce_cart_interface( mconfig, *this ) +{ +} + +pce_cdsys3_device::pce_cdsys3_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : pce_rom_device(mconfig, PCE_ROM_CDSYS3, "PCE & TG16 CD-System Cart v3.00", tag, owner, clock, "pce_cdsys3", __FILE__) +{ +} + +pce_populous_device::pce_populous_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : pce_rom_device(mconfig, PCE_ROM_POPULOUS, "PCE Populous Cart", tag, owner, clock, "pce_populous", __FILE__) +{ +} + +pce_sf2_device::pce_sf2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : pce_rom_device(mconfig, PCE_ROM_SF2, "PCE Street Fighters 2 Cart", tag, owner, clock, "pce_sf2", __FILE__) +{ +} + + +//------------------------------------------------- +// mapper specific start/reset +//------------------------------------------------- + + +void pce_sf2_device::device_start() +{ + save_item(NAME(m_bank_base)); +} + +void pce_sf2_device::device_reset() +{ + m_bank_base = 0; +} + + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +READ8_MEMBER(pce_rom_device::read_cart) +{ + int bank = offset / 0x20000; + return m_rom[rom_bank_map[bank] * 0x20000 + (offset & 0x1ffff)]; +} + + +READ8_MEMBER(pce_cdsys3_device::read_cart) +{ + int bank = offset / 0x20000; + if (!m_ram.empty() && offset >= 0xd0000) + return m_ram[offset - 0xd0000]; + + return m_rom[rom_bank_map[bank] * 0x20000 + (offset & 0x1ffff)]; +} + +WRITE8_MEMBER(pce_cdsys3_device::write_cart) +{ + if (!m_ram.empty() && offset >= 0xd0000) + m_ram[offset - 0xd0000] = data; +} + + +READ8_MEMBER(pce_populous_device::read_cart) +{ + int bank = offset / 0x20000; + if (!m_ram.empty() && offset >= 0x80000 && offset < 0x88000) + return m_ram[offset & 0x7fff]; + + return m_rom[rom_bank_map[bank] * 0x20000 + (offset & 0x1ffff)]; +} + +WRITE8_MEMBER(pce_populous_device::write_cart) +{ + if (!m_ram.empty() && offset >= 0x80000 && offset < 0x88000) + m_ram[offset & 0x7fff] = data; +} + + +READ8_MEMBER(pce_sf2_device::read_cart) +{ + if (offset < 0x80000) + return m_rom[offset]; + else + return m_rom[0x80000 + m_bank_base * 0x80000 + (offset & 0x7ffff)]; +} + +WRITE8_MEMBER(pce_sf2_device::write_cart) +{ + if (offset >= 0x1ff0 && offset < 0x1ff4) + m_bank_base = offset & 3; +} diff --git a/src/devices/bus/pce/pce_rom.h b/src/devices/bus/pce/pce_rom.h new file mode 100644 index 00000000000..3f6b9efcd47 --- /dev/null +++ b/src/devices/bus/pce/pce_rom.h @@ -0,0 +1,85 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __PCE_ROM_H +#define __PCE_ROM_H + +#include "pce_slot.h" + + +// ======================> pce_rom_device + +class pce_rom_device : public device_t, + public device_pce_cart_interface +{ +public: + // construction/destruction + pce_rom_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + pce_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start() {} + virtual void device_reset() {} + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_cart); +}; + +// ======================> pce_cdsys3_device + +class pce_cdsys3_device : public pce_rom_device +{ +public: + // construction/destruction + pce_cdsys3_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_cart); + virtual DECLARE_WRITE8_MEMBER(write_cart); +}; + + +// ======================> pce_populous_device + +class pce_populous_device : public pce_rom_device +{ +public: + // construction/destruction + pce_populous_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_cart); + virtual DECLARE_WRITE8_MEMBER(write_cart); +}; + + +// ======================> pce_sf2_device + +class pce_sf2_device : public pce_rom_device +{ +public: + // construction/destruction + pce_sf2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_cart); + virtual DECLARE_WRITE8_MEMBER(write_cart); + +private: + UINT8 m_bank_base; +}; + + + +// device type definition +extern const device_type PCE_ROM_STD; +extern const device_type PCE_ROM_CDSYS3; +extern const device_type PCE_ROM_POPULOUS; +extern const device_type PCE_ROM_SF2; + + + +#endif diff --git a/src/devices/bus/pce/pce_slot.c b/src/devices/bus/pce/pce_slot.c new file mode 100644 index 00000000000..bc124852c0c --- /dev/null +++ b/src/devices/bus/pce/pce_slot.c @@ -0,0 +1,395 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + PC-Engine / Turbografx-16 cart emulation + (through slot devices) + + TODO: + - reimplement cart mirroring in a better way + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "pce_slot.h" + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type PCE_CART_SLOT = &device_creator; + +//************************************************************************** +// PCE cartridges Interface +//************************************************************************** + +//------------------------------------------------- +// device_pce_cart_interface - constructor +//------------------------------------------------- + +device_pce_cart_interface::device_pce_cart_interface(const machine_config &mconfig, device_t &device) + : device_slot_card_interface(mconfig, device), + m_rom(NULL), + m_rom_size(0) +{ +} + + +//------------------------------------------------- +// ~device_pce_cart_interface - destructor +//------------------------------------------------- + +device_pce_cart_interface::~device_pce_cart_interface() +{ +} + +//------------------------------------------------- +// rom_alloc - alloc the space for the cart +//------------------------------------------------- + +void device_pce_cart_interface::rom_alloc(UINT32 size, const char *tag) +{ + if (m_rom == NULL) + { + m_rom = device().machine().memory().region_alloc(std::string(tag).append(PCESLOT_ROM_REGION_TAG).c_str(), size, 1, ENDIANNESS_LITTLE)->base(); + m_rom_size = size; + } +} + + +//------------------------------------------------- +// ram_alloc - alloc the space for the ram +//------------------------------------------------- + +void device_pce_cart_interface::ram_alloc(UINT32 size) +{ + m_ram.resize(size); + device().save_item(NAME(m_ram)); +} + +//------------------------------------------------- +// rom_map_setup - setup map of rom banks in 128K +// blocks, so to simplify ROM access to mirror +//------------------------------------------------- + +void device_pce_cart_interface::rom_map_setup(UINT32 size) +{ + if (size == 0x60000) + { + // HuCard 384K are mapped with mirrored pieces + rom_bank_map[0] = 0; + rom_bank_map[1] = 1; + rom_bank_map[2] = 0; + rom_bank_map[3] = 1; + rom_bank_map[4] = 2; + rom_bank_map[5] = 2; + rom_bank_map[6] = 2; + rom_bank_map[7] = 2; + } + else if (size == 0x30000) + { + // 192K images (some demos) + rom_bank_map[0] = 0; + rom_bank_map[1] = 1; + rom_bank_map[2] = 2; + rom_bank_map[3] = 2; + rom_bank_map[4] = 0; + rom_bank_map[5] = 1; + rom_bank_map[6] = 2; + rom_bank_map[7] = 2; + } + else + { + int i; + + // setup the rom_bank_map array to faster ROM read + for (i = 0; i < size / 0x20000 && i < 8; i++) + rom_bank_map[i] = i; + + // fill up remaining blocks with mirrors + while (i % 8) + { + int j = 0, repeat_banks; + while ((i % (8 >> j)) && j < 3) + j++; + repeat_banks = i % (8 >> (j - 1)); + for (int k = 0; k < repeat_banks; k++) + rom_bank_map[i + k] = rom_bank_map[i + k - repeat_banks]; + i += repeat_banks; + } + } + // check bank map! +// for (i = 0; i < 8; i++) +// { +// printf("bank %3d = %3d\t", i, rom_bank_map[i]); +// } +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// pce_cart_slot_device - constructor +//------------------------------------------------- +pce_cart_slot_device::pce_cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, PCE_CART_SLOT, "PCE & TG16 Cartridge Slot", tag, owner, clock, "pce_cart_slot", __FILE__), + device_image_interface(mconfig, *this), + device_slot_interface(mconfig, *this), + m_interface("pce_cart"), + m_type(PCE_STD) +{ +} + + +//------------------------------------------------- +// pce_cart_slot_device - destructor +//------------------------------------------------- + +pce_cart_slot_device::~pce_cart_slot_device() +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void pce_cart_slot_device::device_start() +{ + m_cart = dynamic_cast(get_card_device()); +} + +//------------------------------------------------- +// device_config_complete - perform any +// operations now that the configuration is +// complete +//------------------------------------------------- + +void pce_cart_slot_device::device_config_complete() +{ + // set brief and instance name + update_names(); +} + + +//------------------------------------------------- +// PCE PCB +//------------------------------------------------- + +struct pce_slot +{ + int pcb_id; + const char *slot_option; +}; + +// Here, we take the feature attribute from .xml (i.e. the PCB name) and we assign a unique ID to it +static const pce_slot slot_list[] = +{ + { PCE_STD, "rom" }, + { PCE_CDSYS3U, "cdsys3u" }, + { PCE_CDSYS3J, "cdsys3j" }, + { PCE_POPULOUS, "populous" }, + { PCE_SF2, "sf2" }, +}; + +static int pce_get_pcb_id(const char *slot) +{ + for (int i = 0; i < ARRAY_LENGTH(slot_list); i++) + { + if (!core_stricmp(slot_list[i].slot_option, slot)) + return slot_list[i].pcb_id; + } + + return 0; +} + +static const char *pce_get_slot(int type) +{ + for (int i = 0; i < ARRAY_LENGTH(slot_list); i++) + { + if (slot_list[i].pcb_id == type) + return slot_list[i].slot_option; + } + + return "rom"; +} + + +/*------------------------------------------------- + call load + -------------------------------------------------*/ + +bool pce_cart_slot_device::call_load() +{ + if (m_cart) + { + UINT32 offset = 0; + UINT32 len = (software_entry() == NULL) ? length() : get_software_region_length("rom"); + UINT8 *ROM; + + // From fullpath, check for presence of a header and skip it + if (software_entry() == NULL && (len % 0x4000) == 512) + { + logerror("Rom-header found, skipping\n"); + offset = 512; + len -= offset; + fseek(offset, SEEK_SET); + } + + m_cart->rom_alloc(len, tag()); + ROM = m_cart->get_rom_base(); + + if (software_entry() == NULL) + fread(ROM, len); + else + memcpy(ROM, get_software_region("rom"), len); + + // check for encryption (US carts) + if (ROM[0x1fff] < 0xe0) + { + UINT8 decrypted[256]; + + /* Initialize decryption table */ + for (int i = 0; i < 256; i++) + decrypted[i] = ((i & 0x01) << 7) | ((i & 0x02) << 5) | ((i & 0x04) << 3) | ((i & 0x08) << 1) | ((i & 0x10) >> 1) | ((i & 0x20 ) >> 3) | ((i & 0x40) >> 5) | ((i & 0x80) >> 7); + + /* Decrypt ROM image */ + for (int i = 0; i < len; i++) + ROM[i] = decrypted[ROM[i]]; + } + + m_cart->rom_map_setup(len); + + if (software_entry() == NULL) + m_type = get_cart_type(ROM, len); + else + { + const char *pcb_name = get_feature("slot"); + if (pcb_name) + m_type = pce_get_pcb_id(pcb_name); + } + //printf("Type: %s\n", pce_get_slot(m_type)); + + if (m_type == PCE_POPULOUS) + m_cart->ram_alloc(0x8000); + if (m_type == PCE_CDSYS3J || m_type == PCE_CDSYS3U) + m_cart->ram_alloc(0x30000); + + return IMAGE_INIT_PASS; + } + + return IMAGE_INIT_PASS; +} + + +/*------------------------------------------------- + call_unload + -------------------------------------------------*/ + +void pce_cart_slot_device::call_unload() +{ +} + + +/*------------------------------------------------- + call softlist load + -------------------------------------------------*/ + +bool pce_cart_slot_device::call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry) +{ + load_software_part_region(*this, swlist, swname, start_entry); + return TRUE; +} + + + +/*------------------------------------------------- + get_cart_type - code to detect NVRAM type from + fullpath + -------------------------------------------------*/ + +int pce_cart_slot_device::get_cart_type(UINT8 *ROM, UINT32 len) +{ + int type = PCE_STD; + + /* Check for Street fighter 2 */ + if (len == 0x280000) + type = PCE_SF2; + + /* Check for Populous */ + if (len >= (0x1f26 + 8) && !memcmp(ROM + 0x1f26, "POPULOUS", 8)) + type = PCE_POPULOUS; + + // Check for CD system card v3 which adds on-cart RAM to the system + if (len >= (0x3ffb6 + 23) && !memcmp(ROM + 0x3ffb6, "PC Engine CD-ROM SYSTEM", 23)) + { + /* Check if 192KB additional system card ram should be used */ + if (!memcmp(ROM + 0x29d1, "VER. 3.", 7)) { type = PCE_CDSYS3J; } // JP version + else if (!memcmp(ROM + 0x29c4, "VER. 3.", 7 )) { type = PCE_CDSYS3U; } // US version + } + + return type; +} + + +/*------------------------------------------------- + get default card software + -------------------------------------------------*/ + +void pce_cart_slot_device::get_default_card_software(std::string &result) +{ + if (open_image_file(mconfig().options())) + { + const char *slot_string = "rom"; + UINT32 len = core_fsize(m_file); + dynamic_buffer rom(len); + int type; + + core_fread(m_file, &rom[0], len); + + type = get_cart_type(&rom[0], len); + slot_string = pce_get_slot(type); + + //printf("type: %s\n", slot_string); + clear(); + + result.assign(slot_string); + return; + } + + software_get_default_slot(result, "rom"); +} + +/*------------------------------------------------- + read + -------------------------------------------------*/ + +READ8_MEMBER(pce_cart_slot_device::read_cart) +{ + if (m_cart) + return m_cart->read_cart(space, offset); + else + return 0xff; +} + +/*------------------------------------------------- + write + -------------------------------------------------*/ + +WRITE8_MEMBER(pce_cart_slot_device::write_cart) +{ + if (m_cart) + m_cart->write_cart(space, offset, data); +} + + +/*------------------------------------------------- + Internal header logging + -------------------------------------------------*/ + +void pce_cart_slot_device::internal_header_logging(UINT8 *ROM, UINT32 len) +{ +} diff --git a/src/devices/bus/pce/pce_slot.h b/src/devices/bus/pce/pce_slot.h new file mode 100644 index 00000000000..e6968518b49 --- /dev/null +++ b/src/devices/bus/pce/pce_slot.h @@ -0,0 +1,129 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __PCE_SLOT_H +#define __PCE_SLOT_H + +/*************************************************************************** + TYPE DEFINITIONS + ***************************************************************************/ + + +/* PCB */ +enum +{ + PCE_STD = 0, + PCE_CDSYS3J, + PCE_CDSYS3U, + PCE_POPULOUS, + PCE_SF2 +}; + + +// ======================> device_pce_cart_interface + +class device_pce_cart_interface : public device_slot_card_interface +{ +public: + // construction/destruction + device_pce_cart_interface(const machine_config &mconfig, device_t &device); + virtual ~device_pce_cart_interface(); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_cart) { return 0xff; } + virtual DECLARE_WRITE8_MEMBER(write_cart) {}; + + void rom_alloc(UINT32 size, const char *tag); + void ram_alloc(UINT32 size); + UINT8* get_rom_base() { return m_rom; } + UINT8* get_ram_base() { return &m_ram[0]; } + UINT32 get_rom_size() { return m_rom_size; } + UINT32 get_ram_size() { return m_ram.size(); } + + // internal state + UINT8 *m_rom; + UINT32 m_rom_size; + dynamic_buffer m_ram; + + void rom_map_setup(UINT32 size); + + UINT8 rom_bank_map[8]; // 128K chunks of rom +}; + + +// ======================> pce_cart_slot_device + +class pce_cart_slot_device : public device_t, + public device_image_interface, + public device_slot_interface +{ +public: + // construction/destruction + pce_cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual ~pce_cart_slot_device(); + + // device-level overrides + virtual void device_start(); + virtual void device_config_complete(); + + // image-level overrides + virtual bool call_load(); + virtual void call_unload(); + virtual bool call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry); + + int get_type() { return m_type; } + int get_cart_type(UINT8 *ROM, UINT32 len); + + void setup_ram(UINT8 banks); + void internal_header_logging(UINT8 *ROM, UINT32 len); + + void set_intf(const char * interface) { m_interface = interface; } + + virtual iodevice_t image_type() const { return IO_CARTSLOT; } + virtual bool is_readable() const { return 1; } + virtual bool is_writeable() const { return 0; } + virtual bool is_creatable() const { return 0; } + virtual bool must_be_loaded() const { return 1; } + virtual bool is_reset_on_load() const { return 1; } + virtual const option_guide *create_option_guide() const { return NULL; } + virtual const char *image_interface() const { return m_interface; } + virtual const char *file_extensions() const { return "pce,bin"; } + + // slot interface overrides + virtual void get_default_card_software(std::string &result); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_cart); + virtual DECLARE_WRITE8_MEMBER(write_cart); + + +protected: + + const char *m_interface; + int m_type; + device_pce_cart_interface* m_cart; +}; + + + +// device type definition +extern const device_type PCE_CART_SLOT; + + +/*************************************************************************** + DEVICE CONFIGURATION MACROS + ***************************************************************************/ + +#define PCESLOT_ROM_REGION_TAG ":cart:rom" + +#define MCFG_PCE_CARTRIDGE_ADD(_tag,_slot_intf,_def_slot) \ + MCFG_DEVICE_ADD(_tag, PCE_CART_SLOT, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) \ + static_cast(device)->set_intf("pce_cart"); + +#define MCFG_TG16_CARTRIDGE_ADD(_tag,_slot_intf,_def_slot) \ + MCFG_DEVICE_ADD(_tag, PCE_CART_SLOT, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) \ + static_cast(device)->set_intf("tg16_cart"); + + +#endif diff --git a/src/devices/bus/pet/64k.c b/src/devices/bus/pet/64k.c new file mode 100644 index 00000000000..4bc9c01d596 --- /dev/null +++ b/src/devices/bus/pet/64k.c @@ -0,0 +1,203 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Commodore PET 64KB RAM Expansion emulation + +**********************************************************************/ + +#include "64k.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type PET_64K = &device_creator; + + + +//************************************************************************** +// INLINE HELPERS +//************************************************************************** + +//------------------------------------------------- +// read_ram - +//------------------------------------------------- + +inline UINT8 pet_64k_expansion_device::read_ram(offs_t offset) +{ + UINT8 data = 0; + + if (offset < 0xc000) + { + data = m_ram[(BIT(m_ctrl, 2) << 14) | (offset & 0x3fff)]; + } + else + { + data = m_ram[0x8000 | (BIT(m_ctrl, 3) << 14) | (offset & 0x3fff)]; + } + + return data; +} + + +//------------------------------------------------- +// write_ram - +//------------------------------------------------- + +inline void pet_64k_expansion_device::write_ram(offs_t offset, UINT8 data) +{ + if (offset < 0xc000) + { + if (!BIT(m_ctrl, 0)) + { + m_ram[(BIT(m_ctrl, 2) << 14) | (offset & 0x3fff)] = data; + } + } + else + { + if (!BIT(m_ctrl, 1)) + { + m_ram[0x8000 | (BIT(m_ctrl, 3) << 14) | (offset & 0x3fff)] = data; + } + } +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// pet_64k_expansion_device - constructor +//------------------------------------------------- + +pet_64k_expansion_device::pet_64k_expansion_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, PET_64K, "PET 64KB RAM", tag, owner, clock, "pet_64k", __FILE__), + device_pet_expansion_card_interface(mconfig, *this), + m_ram(*this, "ram"), + m_ctrl(0) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void pet_64k_expansion_device::device_start() +{ + // allocate memory + m_ram.allocate(0x10000); + + // state saving + save_item(NAME(m_ctrl)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void pet_64k_expansion_device::device_reset() +{ + m_ctrl = 0; +} + + +//------------------------------------------------- +// pet_norom_r - NO ROM read +//------------------------------------------------- + +int pet_64k_expansion_device::pet_norom_r(address_space &space, offs_t offset, int sel) +{ + return !BIT(m_ctrl, 7); +} + + +//------------------------------------------------- +// pet_bd_r - buffered data read +//------------------------------------------------- + +UINT8 pet_64k_expansion_device::pet_bd_r(address_space &space, offs_t offset, UINT8 data, int &sel) +{ + if (BIT(m_ctrl, 7)) + { + switch (sel) + { + case pet_expansion_slot_device::SEL8: + if (!BIT(m_ctrl, 5)) + { + data = read_ram(offset); + sel = pet_expansion_slot_device::SEL_NONE; + } + break; + + case pet_expansion_slot_device::SELE: + if (!BIT(m_ctrl, 6) || !BIT(offset, 11)) + { + data = read_ram(offset); + sel = pet_expansion_slot_device::SEL_NONE; + } + break; + + case pet_expansion_slot_device::SEL9: + case pet_expansion_slot_device::SELA: + case pet_expansion_slot_device::SELB: + case pet_expansion_slot_device::SELC: + case pet_expansion_slot_device::SELD: + case pet_expansion_slot_device::SELF: + data = read_ram(offset); + break; + } + } + + return data; +} + + +//------------------------------------------------- +// pet_bd_w - buffered data write +//------------------------------------------------- + +void pet_64k_expansion_device::pet_bd_w(address_space &space, offs_t offset, UINT8 data, int &sel) +{ + if (BIT(m_ctrl, 7)) + { + switch (sel) + { + case pet_expansion_slot_device::SEL8: + if (!BIT(m_ctrl, 5)) + { + write_ram(offset, data); + sel = pet_expansion_slot_device::SEL_NONE; + } + break; + + case pet_expansion_slot_device::SELE: + if (!BIT(m_ctrl, 6) || !BIT(offset, 11)) + { + write_ram(offset, data); + sel = pet_expansion_slot_device::SEL_NONE; + } + break; + + case pet_expansion_slot_device::SEL9: + case pet_expansion_slot_device::SELA: + case pet_expansion_slot_device::SELB: + case pet_expansion_slot_device::SELC: + case pet_expansion_slot_device::SELD: + case pet_expansion_slot_device::SELF: + write_ram(offset, data); + break; + } + } + + if (offset == 0xfff0) + { + m_ctrl = data; + } +} diff --git a/src/devices/bus/pet/64k.h b/src/devices/bus/pet/64k.h new file mode 100644 index 00000000000..6a7511357ad --- /dev/null +++ b/src/devices/bus/pet/64k.h @@ -0,0 +1,56 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Commodore PET 64KB RAM Expansion emulation + +**********************************************************************/ + +#pragma once + +#ifndef __PET_64K__ +#define __PET_64K__ + +#include "emu.h" +#include "exp.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> pet_64k_expansion_device + +class pet_64k_expansion_device : public device_t, + public device_pet_expansion_card_interface +{ +public: + // construction/destruction + pet_64k_expansion_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_pet_expansion_card_interface overrides + virtual int pet_norom_r(address_space &space, offs_t offset, int sel); + virtual UINT8 pet_bd_r(address_space &space, offs_t offset, UINT8 data, int &sel); + virtual void pet_bd_w(address_space &space, offs_t offset, UINT8 data, int &sel); + +private: + inline UINT8 read_ram(offs_t offset); + inline void write_ram(offs_t offset, UINT8 data); + + optional_shared_ptr m_ram; + + UINT8 m_ctrl; +}; + + +// device type definition +extern const device_type PET_64K; + + +#endif diff --git a/src/devices/bus/pet/c2n.c b/src/devices/bus/pet/c2n.c new file mode 100644 index 00000000000..aab392e9ffb --- /dev/null +++ b/src/devices/bus/pet/c2n.c @@ -0,0 +1,160 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Commodore C2N/1530/1531 Datassette emulation + +**********************************************************************/ + +#include "c2n.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type C2N = &device_creator; +const device_type C1530 = &device_creator; +const device_type C1531 = &device_creator; + + +//------------------------------------------------- +// MACHINE_CONFIG( c2n ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( c2n ) + MCFG_CASSETTE_ADD("cassette" ) + MCFG_CASSETTE_FORMATS(cbm_cassette_formats) + MCFG_CASSETTE_DEFAULT_STATE(CASSETTE_STOPPED | CASSETTE_MOTOR_DISABLED | CASSETTE_SPEAKER_MUTED) + MCFG_CASSETTE_INTERFACE("cbm_cass") +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor c2n_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( c2n ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// c2n_device - constructor +//------------------------------------------------- + +c2n_device::c2n_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_pet_datassette_port_interface(mconfig, *this), + m_cassette(*this, "cassette"), + m_motor(false) +{ +} + +c2n_device::c2n_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, C2N, "C2N Datassette", tag, owner, clock, "c2n", __FILE__), + device_pet_datassette_port_interface(mconfig, *this), + m_cassette(*this, "cassette"), + m_motor(false) +{ +} + + +//------------------------------------------------- +// c1530_device - constructor +//------------------------------------------------- + +c1530_device::c1530_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : c2n_device(mconfig, C1530, "C1530 Datassette", tag, owner, clock, "c1530", __FILE__) { } + + +//------------------------------------------------- +// c1531_device - constructor +//------------------------------------------------- + +c1531_device::c1531_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : c2n_device(mconfig, C1531, "C1531 Datassette", tag, owner, clock, "c1531", __FILE__) { } + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void c2n_device::device_start() +{ + // allocate timers + m_read_timer = timer_alloc(); + m_read_timer->adjust(attotime::from_hz(44100), 0, attotime::from_hz(44100)); +} + + +//------------------------------------------------- +// device_timer - handler timer events +//------------------------------------------------- + +void c2n_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + if (m_motor) + { + m_slot->read_w(datassette_read()); + } +} + + +//------------------------------------------------- +// datassette_read - read data +//------------------------------------------------- + +int c2n_device::datassette_read() +{ + return (m_cassette->input() > +0.0) ? 1 : 0; +} + + +//------------------------------------------------- +// datassette_write - write data +//------------------------------------------------- + +void c2n_device::datassette_write(int state) +{ + m_cassette->output(state ? -(0x5a9e >> 1) : +(0x5a9e >> 1)); +} + + +//------------------------------------------------- +// datassette_sense - switch sense +//------------------------------------------------- + +int c2n_device::datassette_sense() +{ + return (m_cassette->get_state() & CASSETTE_MASK_UISTATE) == CASSETTE_STOPPED; +} + + +//------------------------------------------------- +// datassette_motor - motor +//------------------------------------------------- + +void c2n_device::datassette_motor(int state) +{ + if (!state) + { + m_cassette->change_state(CASSETTE_MOTOR_ENABLED, CASSETTE_MASK_MOTOR); + m_motor = true; + } + else + { + m_cassette->change_state(CASSETTE_MOTOR_DISABLED, CASSETTE_MASK_MOTOR); + m_motor = false; + } + + m_slot->read_w(datassette_read()); +} diff --git a/src/devices/bus/pet/c2n.h b/src/devices/bus/pet/c2n.h new file mode 100644 index 00000000000..a8e09d57c00 --- /dev/null +++ b/src/devices/bus/pet/c2n.h @@ -0,0 +1,86 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Commodore C2N/1530/1531 Datassette emulation + +**********************************************************************/ + +#pragma once + +#ifndef __C2N__ +#define __C2N__ + +#include "emu.h" +#include "cass.h" +#include "formats/cbm_tap.h" +#include "imagedev/cassette.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> c2n_device + +class c2n_device : public device_t, + public device_pet_datassette_port_interface +{ +public: + // construction/destruction + c2n_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + c2n_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + // device_pet_datassette_port_interface overrides + virtual int datassette_read(); + virtual void datassette_write(int state); + virtual int datassette_sense(); + virtual void datassette_motor(int state); + +private: + required_device m_cassette; + + bool m_motor; + + // timers + emu_timer *m_read_timer; +}; + + +// ======================> c1530_device + +class c1530_device : public c2n_device +{ +public: + // construction/destruction + c1530_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +// ======================> c1531_device + +class c1531_device : public c2n_device +{ +public: + // construction/destruction + c1531_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +// device type definition +extern const device_type C2N; +extern const device_type C1530; +extern const device_type C1531; + + + +#endif diff --git a/src/devices/bus/pet/cass.c b/src/devices/bus/pet/cass.c new file mode 100644 index 00000000000..f425478e5a2 --- /dev/null +++ b/src/devices/bus/pet/cass.c @@ -0,0 +1,99 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Commodore PET/VIC-20/C64/Plus-4 Datassette Port emulation + +**********************************************************************/ + +#include "cass.h" + + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type PET_DATASSETTE_PORT = &device_creator; + + + +//************************************************************************** +// CARD INTERFACE +//************************************************************************** + +//------------------------------------------------- +// device_pet_datassette_port_interface - constructor +//------------------------------------------------- + +device_pet_datassette_port_interface::device_pet_datassette_port_interface(const machine_config &mconfig, device_t &device) + : device_slot_card_interface(mconfig,device) +{ + m_slot = dynamic_cast(device.owner()); +} + + +//------------------------------------------------- +// ~device_pet_datassette_port_interface - destructor +//------------------------------------------------- + +device_pet_datassette_port_interface::~device_pet_datassette_port_interface() +{ +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// pet_datassette_port_device - constructor +//------------------------------------------------- + +pet_datassette_port_device::pet_datassette_port_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, PET_DATASSETTE_PORT, "Datassette Port", tag, owner, clock, "pet_datassette_port", __FILE__), + device_slot_interface(mconfig, *this), + m_read_handler(*this) +{ +} + + +//------------------------------------------------- +// pet_datassette_port_device - destructor +//------------------------------------------------- + +pet_datassette_port_device::~pet_datassette_port_device() +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void pet_datassette_port_device::device_start() +{ + m_cart = dynamic_cast(get_card_device()); + + // resolve callbacks + m_read_handler.resolve_safe(); +} + + +READ_LINE_MEMBER( pet_datassette_port_device::read ) { int state = 1; if (m_cart != NULL) state = m_cart->datassette_read(); return state; } +WRITE_LINE_MEMBER( pet_datassette_port_device::write ) { if (m_cart != NULL) m_cart->datassette_write(state); } +READ_LINE_MEMBER( pet_datassette_port_device::sense_r ) { int state = 1; if (m_cart != NULL) state = m_cart->datassette_sense(); return state; } +WRITE_LINE_MEMBER( pet_datassette_port_device::motor_w ) { if (m_cart != NULL) m_cart->datassette_motor(state); } + +WRITE_LINE_MEMBER( pet_datassette_port_device::read_w ) { m_read_handler(state); } + + +//------------------------------------------------- +// SLOT_INTERFACE( cbm_datassette_devices ) +//------------------------------------------------- + +SLOT_INTERFACE_START( cbm_datassette_devices ) + SLOT_INTERFACE("c2n", C2N) + SLOT_INTERFACE("c1530", C1530) +SLOT_INTERFACE_END diff --git a/src/devices/bus/pet/cass.h b/src/devices/bus/pet/cass.h new file mode 100644 index 00000000000..b4c2da0738b --- /dev/null +++ b/src/devices/bus/pet/cass.h @@ -0,0 +1,117 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Commodore PET/VIC-20/C64/Plus-4 Datassette Port emulation + +********************************************************************** + + GND 1 A GND + +5V 2 B +5V + MOTOR 3 C MOTOR + READ 4 D READ + WRITE 5 E WRITE + SENSE 6 F SENSE + +**********************************************************************/ + +#pragma once + +#ifndef __PET_DATASSETTE_PORT__ +#define __PET_DATASSETTE_PORT__ + +#include "emu.h" + + + +//************************************************************************** +// CONSTANTS +//************************************************************************** + +#define PET_DATASSETTE_PORT_TAG "tape" +#define PET_DATASSETTE_PORT2_TAG "tape2" + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_PET_DATASSETTE_PORT_ADD(_tag, _slot_intf, _def_slot, _devcb) \ + MCFG_DEVICE_ADD(_tag, PET_DATASSETTE_PORT, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) \ + devcb = &pet_datassette_port_device::set_read_handler(*device, DEVCB_##_devcb); + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> pet_datassette_port_device + +class device_pet_datassette_port_interface; + +class pet_datassette_port_device : public device_t, + public device_slot_interface +{ +public: + // construction/destruction + pet_datassette_port_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual ~pet_datassette_port_device(); + + // static configuration helpers + template static devcb_base &set_read_handler(device_t &device, _Object object) { return downcast(device).m_read_handler.set_callback(object); } + + // computer interface + DECLARE_READ_LINE_MEMBER( read ); + DECLARE_WRITE_LINE_MEMBER( write ); + DECLARE_READ_LINE_MEMBER( sense_r ); + DECLARE_WRITE_LINE_MEMBER( motor_w ); + + // device interface + DECLARE_WRITE_LINE_MEMBER( read_w ); + +protected: + // device-level overrides + virtual void device_start(); + + devcb_write_line m_read_handler; + + device_pet_datassette_port_interface *m_cart; +}; + + +// ======================> device_pet_datassette_port_interface + +// class representing interface-specific live c64_expansion card +class device_pet_datassette_port_interface : public device_slot_card_interface +{ +public: + // construction/destruction + device_pet_datassette_port_interface(const machine_config &mconfig, device_t &device); + virtual ~device_pet_datassette_port_interface(); + + virtual int datassette_read() { return 1; }; + virtual void datassette_write(int state) { }; + virtual int datassette_sense() { return 1; }; + virtual void datassette_motor(int state) { }; + +protected: + pet_datassette_port_device *m_slot; +}; + + +// device type definition +extern const device_type PET_DATASSETTE_PORT; + + +// slot devices +#include "c2n.h" +#include "diag264_lb_tape.h" + +SLOT_INTERFACE_EXTERN( cbm_datassette_devices ); + + + +#endif diff --git a/src/devices/bus/pet/cb2snd.c b/src/devices/bus/pet/cb2snd.c new file mode 100644 index 00000000000..d89ef26268c --- /dev/null +++ b/src/devices/bus/pet/cb2snd.c @@ -0,0 +1,64 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/********************************************************************** + + Commodore PET userport "CB2 sound" audio device emulation + + http://zimmers.net/cbmpics/cbm/PETx/petfaq.html + +**********************************************************************/ + +#include "cb2snd.h" + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type PET_USERPORT_CB2_SOUND_DEVICE = &device_creator; + +#define DAC_TAG "dac" + +MACHINE_CONFIG_FRAGMENT( cb2snd ) + MCFG_SPEAKER_STANDARD_MONO("cb2spkr") + MCFG_SOUND_ADD(DAC_TAG, DAC, 0) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "cb2spkr", 1.00) +MACHINE_CONFIG_END + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor pet_userport_cb2_sound_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( cb2snd ); +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// pet_userport_cb2_sound_device - constructor +//------------------------------------------------- + +pet_userport_cb2_sound_device::pet_userport_cb2_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, PET_USERPORT_CB2_SOUND_DEVICE, "PET Userport 'CB2 Sound' Device", tag, owner, clock, "petucb2", __FILE__), + device_pet_user_port_interface(mconfig, *this), + m_dac(*this, DAC_TAG) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void pet_userport_cb2_sound_device::device_start() +{ +} + +DECLARE_WRITE_LINE_MEMBER( pet_userport_cb2_sound_device::input_m ) +{ + m_dac->write_unsigned8(state ? 0xff : 0x00); +} diff --git a/src/devices/bus/pet/cb2snd.h b/src/devices/bus/pet/cb2snd.h new file mode 100644 index 00000000000..77d5f93979a --- /dev/null +++ b/src/devices/bus/pet/cb2snd.h @@ -0,0 +1,44 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/********************************************************************** + + Commodore PET userport "CB2 sound" audio device emulation + +**********************************************************************/ + +#pragma once + +#ifndef __PETUSER_CB2__ +#define __PETUSER_CB2__ + +#include "emu.h" +#include "user.h" +#include "sound/dac.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class pet_userport_cb2_sound_device : public device_t, + public device_pet_user_port_interface +{ +public: + // construction/destruction + pet_userport_cb2_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual machine_config_constructor device_mconfig_additions() const; + + virtual DECLARE_WRITE_LINE_MEMBER( input_m ); + + required_device m_dac; + +protected: + // device-level overrides + virtual void device_start(); +}; + + +// device type definition +extern const device_type PET_USERPORT_CB2_SOUND_DEVICE; + +#endif diff --git a/src/devices/bus/pet/diag.c b/src/devices/bus/pet/diag.c new file mode 100644 index 00000000000..7cd73c6fff0 --- /dev/null +++ b/src/devices/bus/pet/diag.c @@ -0,0 +1,44 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/********************************************************************** + + Commodore PET User Port Diagnostic Connector emulation + +**********************************************************************/ + +#include "diag.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type PET_USERPORT_DIAGNOSTIC_CONNECTOR = &device_creator; + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// pet_userport_diagnostic_connector_t - constructor +//------------------------------------------------- + +pet_userport_diagnostic_connector_t::pet_userport_diagnostic_connector_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, PET_USERPORT_DIAGNOSTIC_CONNECTOR, "PET Userport Diagnostic Connector", tag, owner, clock, "pet_user_diag", __FILE__), + device_pet_user_port_interface(mconfig, *this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void pet_userport_diagnostic_connector_t::device_start() +{ + output_5(0); + output_e(0); +} diff --git a/src/devices/bus/pet/diag.h b/src/devices/bus/pet/diag.h new file mode 100644 index 00000000000..2f8d094ef01 --- /dev/null +++ b/src/devices/bus/pet/diag.h @@ -0,0 +1,57 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/********************************************************************** + + Commodore PET User Port Diagnostic Connector emulation + +**********************************************************************/ + +#pragma once + +#ifndef __PET_USER_DIAG__ +#define __PET_USER_DIAG__ + +#include "emu.h" +#include "user.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> pet_userport_diagnostic_connector_t + +class pet_userport_diagnostic_connector_t : public device_t, + public device_pet_user_port_interface +{ +public: + // construction/destruction + pet_userport_diagnostic_connector_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device_pet_user_port_interface overrides + virtual DECLARE_WRITE_LINE_MEMBER( input_2 ) { output_b(state); } + virtual DECLARE_WRITE_LINE_MEMBER( input_3 ) { output_c(state); } + virtual DECLARE_WRITE_LINE_MEMBER( input_4 ) { output_d(state); } + virtual DECLARE_WRITE_LINE_MEMBER( input_6 ) { output_7(state); output_8(state); } + virtual DECLARE_WRITE_LINE_MEMBER( input_7 ) { output_6(state); output_8(state); } + virtual DECLARE_WRITE_LINE_MEMBER( input_8 ) { output_6(state); output_7(state); } + virtual DECLARE_WRITE_LINE_MEMBER( input_9 ) { output_k(state); } + virtual DECLARE_WRITE_LINE_MEMBER( input_10 ) { output_l(state); } + virtual DECLARE_WRITE_LINE_MEMBER( input_b ) { output_2(state); } + virtual DECLARE_WRITE_LINE_MEMBER( input_c ) { output_3(state); } + virtual DECLARE_WRITE_LINE_MEMBER( input_d ) { output_4(state); } + virtual DECLARE_WRITE_LINE_MEMBER( input_k ) { output_9(state); } + virtual DECLARE_WRITE_LINE_MEMBER( input_l ) { output_10(state); } + +protected: + // device-level overrides + virtual void device_start(); +}; + + +// device type definition +extern const device_type PET_USERPORT_DIAGNOSTIC_CONNECTOR; + + +#endif diff --git a/src/devices/bus/pet/diag264_lb_tape.c b/src/devices/bus/pet/diag264_lb_tape.c new file mode 100644 index 00000000000..0c3bfb87d74 --- /dev/null +++ b/src/devices/bus/pet/diag264_lb_tape.c @@ -0,0 +1,83 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Diag264 Cassette Loop Back Connector emulation + +**********************************************************************/ + +#include "diag264_lb_tape.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type DIAG264_CASSETTE_LOOPBACK = &device_creator; + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// diag264_cassette_loopback_device - constructor +//------------------------------------------------- + +diag264_cassette_loopback_device::diag264_cassette_loopback_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, DIAG264_CASSETTE_LOOPBACK, "Diag264 Cassette Loopback", tag, owner, clock, "diag264_loopback_cassette", __FILE__), + device_pet_datassette_port_interface(mconfig, *this), + m_read(1), + m_sense(0) +{ } + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void diag264_cassette_loopback_device::device_start() +{ +} + + +//------------------------------------------------- +// datassette_read - read data +//------------------------------------------------- + +int diag264_cassette_loopback_device::datassette_read() +{ + return m_read; +} + + +//------------------------------------------------- +// datassette_write - write data +//------------------------------------------------- + +void diag264_cassette_loopback_device::datassette_write(int state) +{ + m_read = state; +} + + +//------------------------------------------------- +// datassette_sense - switch sense +//------------------------------------------------- + +int diag264_cassette_loopback_device::datassette_sense() +{ + return m_sense; +} + + +//------------------------------------------------- +// datassette_motor - motor +//------------------------------------------------- + +void diag264_cassette_loopback_device::datassette_motor(int state) +{ + m_sense = !state; +} diff --git a/src/devices/bus/pet/diag264_lb_tape.h b/src/devices/bus/pet/diag264_lb_tape.h new file mode 100644 index 00000000000..4d37e32ec94 --- /dev/null +++ b/src/devices/bus/pet/diag264_lb_tape.h @@ -0,0 +1,53 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Diag264 Cassette Loop Back Connector emulation + +**********************************************************************/ + +#pragma once + +#ifndef __DIAG264_CASSETTE_LOOPBACK__ +#define __DIAG264_CASSETTE_LOOPBACK__ + +#include "emu.h" +#include "cass.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> diag264_cassette_loopback_device + +class diag264_cassette_loopback_device : public device_t, + public device_pet_datassette_port_interface +{ +public: + // construction/destruction + diag264_cassette_loopback_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // device-level overrides + virtual void device_start(); + + // device_pet_datassette_port_interface overrides + virtual int datassette_read(); + virtual void datassette_write(int state); + virtual int datassette_sense(); + virtual void datassette_motor(int state); + +private: + int m_read; + int m_sense; +}; + + +// device type definition +extern const device_type DIAG264_CASSETTE_LOOPBACK; + + + +#endif diff --git a/src/devices/bus/pet/exp.c b/src/devices/bus/pet/exp.c new file mode 100644 index 00000000000..e550c2cf80f --- /dev/null +++ b/src/devices/bus/pet/exp.c @@ -0,0 +1,204 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Commodore PET Memory Expansion Port emulation + +**********************************************************************/ + +#include "exp.h" + + + +//************************************************************************** +// MACROS/CONSTANTS +//************************************************************************** + +#define LOG 0 + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type PET_EXPANSION_SLOT = &device_creator; + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// pet_expansion_slot_device - constructor +//------------------------------------------------- + +pet_expansion_slot_device::pet_expansion_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, PET_EXPANSION_SLOT, "PET memory expansion port", tag, owner, clock, "pet_expansion_slot", __FILE__), + device_slot_interface(mconfig, *this), + m_read_dma(*this), + m_write_dma(*this) +{ +} + + +//------------------------------------------------- +// pet_expansion_slot_device - destructor +//------------------------------------------------- + +pet_expansion_slot_device::~pet_expansion_slot_device() +{ +} + + +//------------------------------------------------- +// device_pet_expansion_card_interface - constructor +//------------------------------------------------- + +device_pet_expansion_card_interface::device_pet_expansion_card_interface(const machine_config &mconfig, device_t &device) + : device_slot_card_interface(mconfig, device) +{ + m_slot = dynamic_cast(device.owner()); +} + + +//------------------------------------------------- +// ~device_pet_expansion_card_interface - destructor +//------------------------------------------------- + +device_pet_expansion_card_interface::~device_pet_expansion_card_interface() +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void pet_expansion_slot_device::device_start() +{ + m_card = dynamic_cast(get_card_device()); + + // resolve callbacks + m_read_dma.resolve_safe(0); + m_write_dma.resolve_safe(); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void pet_expansion_slot_device::device_reset() +{ + if (m_card != NULL) + { + get_card_device()->reset(); + } +} + + +//------------------------------------------------- +// norom_r - NO ROM read +//------------------------------------------------- + +int pet_expansion_slot_device::norom_r(address_space &space, offs_t offset, int sel) +{ + return m_card ? m_card->pet_norom_r(space, offset, sel) : 1; +} + + +//------------------------------------------------- +// read - buffered data read +//------------------------------------------------- + +UINT8 pet_expansion_slot_device::read(address_space &space, offs_t offset, UINT8 data, int &sel) +{ + if (m_card != NULL) + { + data = m_card->pet_bd_r(space, offset, data, sel); + } + + return data; +} + + +//------------------------------------------------- +// write - buffered data write +//------------------------------------------------- + +void pet_expansion_slot_device::write(address_space &space, offs_t offset, UINT8 data, int &sel) +{ + if (m_card != NULL) + { + m_card->pet_bd_w(space, offset, data, sel); + } +} + + +//------------------------------------------------- +// diag_r - DIAG read +//------------------------------------------------- + +READ_LINE_MEMBER( pet_expansion_slot_device::diag_r ) +{ + return m_card ? m_card->pet_diag_r() : 1; +} + + +//------------------------------------------------- +// irq_w - IRQ write +//------------------------------------------------- + +WRITE_LINE_MEMBER( pet_expansion_slot_device::irq_w ) +{ + if (m_card) m_card->pet_irq_w(state); +} + + +//------------------------------------------------- +// dma_bd_r - DMA read +//------------------------------------------------- + +UINT8 pet_expansion_slot_device::dma_bd_r(offs_t offset) +{ + return m_read_dma(offset); +} + + +//------------------------------------------------- +// dma_bd_w - DMA write +//------------------------------------------------- + +void pet_expansion_slot_device::dma_bd_w(offs_t offset, UINT8 data) +{ + m_write_dma(offset, data); +} + + +//------------------------------------------------- +// phi2 - system clock frequency +//------------------------------------------------- + +int pet_expansion_slot_device::phi2() +{ + return clock(); +} + + +//------------------------------------------------- +// SLOT_INTERFACE( pet_expansion_cards ) +//------------------------------------------------- + +// slot devices +#include "64k.h" +#include "hsg.h" +#include "superpet.h" + +SLOT_INTERFACE_START( pet_expansion_cards ) + SLOT_INTERFACE("64k", PET_64K) + SLOT_INTERFACE("hsga", CBM8000_HSG_A) + SLOT_INTERFACE("hsgb", CBM8000_HSG_B) + SLOT_INTERFACE("superpet", SUPERPET) +SLOT_INTERFACE_END diff --git a/src/devices/bus/pet/exp.h b/src/devices/bus/pet/exp.h new file mode 100644 index 00000000000..ed583333c60 --- /dev/null +++ b/src/devices/bus/pet/exp.h @@ -0,0 +1,139 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Commodore PET Memory Expansion Port emulation + +********************************************************************** + +**********************************************************************/ + +#pragma once + +#ifndef __PET_EXPANSION_SLOT__ +#define __PET_EXPANSION_SLOT__ + +#include "emu.h" + + + +//************************************************************************** +// CONSTANTS +//************************************************************************** + +#define PET_EXPANSION_SLOT_TAG "exp" + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_PET_EXPANSION_SLOT_ADD(_tag, _clock, _slot_intf, _def_slot) \ + MCFG_DEVICE_ADD(_tag, PET_EXPANSION_SLOT, _clock) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) + + +#define MCFG_PET_EXPANSION_SLOT_DMA_CALLBACKS(_read, _write) \ + downcast(device)->set_callbacks(DEVCB_##_read, DEVCB_##_write); + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> pet_expansion_slot_device + +class device_pet_expansion_card_interface; + +class pet_expansion_slot_device : public device_t, + public device_slot_interface +{ +public: + // construction/destruction + pet_expansion_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual ~pet_expansion_slot_device(); + + template void set_callbacks(_read rd, _write wr) { + m_read_dma.set_callback(rd); + m_write_dma.set_callback(wr); + } + + // computer interface + int norom_r(address_space &space, offs_t offset, int sel); + UINT8 read(address_space &space, offs_t offset, UINT8 data, int &sel); + void write(address_space &space, offs_t offset, UINT8 data, int &sel); + DECLARE_READ_LINE_MEMBER( diag_r ); + DECLARE_WRITE_LINE_MEMBER( irq_w ); + + // cartridge interface + UINT8 dma_bd_r(offs_t offset); + void dma_bd_w(offs_t offset, UINT8 data); + int phi2(); + + enum + { + SEL_NONE = -1, + SEL0 = 0, + SEL1, + SEL2, + SEL3, + SEL4, + SEL5, + SEL6, + SEL7, + SEL8, + SEL9, + SELA, + SELB, + SELC, + SELD, + SELE, + SELF + }; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + device_pet_expansion_card_interface *m_card; + + devcb_read8 m_read_dma; + devcb_write8 m_write_dma; +}; + + +// ======================> device_pet_expansion_card_interface + +class device_pet_expansion_card_interface : public device_slot_card_interface +{ + friend class pet_expansion_slot_device; + +public: + // construction/destruction + device_pet_expansion_card_interface(const machine_config &mconfig, device_t &device); + virtual ~device_pet_expansion_card_interface(); + +protected: + // runtime + virtual int pet_norom_r(address_space &space, offs_t offset, int sel) { return 1; } + virtual UINT8 pet_bd_r(address_space &space, offs_t offset, UINT8 data, int &sel) { return data; }; + virtual void pet_bd_w(address_space &space, offs_t offset, UINT8 data, int &sel) { }; + virtual int pet_diag_r() { return 1; } + virtual void pet_irq_w(int state) { } + + pet_expansion_slot_device *m_slot; +}; + + +// device type definition +extern const device_type PET_EXPANSION_SLOT; + + +SLOT_INTERFACE_EXTERN( pet_expansion_cards ); + + + +#endif diff --git a/src/devices/bus/pet/hsg.c b/src/devices/bus/pet/hsg.c new file mode 100644 index 00000000000..5f2d7d1df9d --- /dev/null +++ b/src/devices/bus/pet/hsg.c @@ -0,0 +1,258 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + CBM 8000 High Speed Graphics (324402-01) card emulation + +**********************************************************************/ + +/* + + TODO: + + http://www.6502.org/users/sjgray/computer/hsg/index.html + + - version A (EF9365, 512x512 interlaced, 1 page) + - version B (EF9366, 512x256 non-interlaced, 2 pages) + +*/ + +#include "hsg.h" + + + +//************************************************************************** +// MACROS/CONSTANTS +//************************************************************************** + +#define EF9365_TAG "ef9365" +#define EF9366_TAG "ef9366" +#define SCREEN_TAG "screen" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type CBM8000_HSG_A = &device_creator; +const device_type CBM8000_HSG_B = &device_creator; + + +//------------------------------------------------- +// ROM( cbm8000_hsg ) +//------------------------------------------------- + +ROM_START( cbm8000_hsg ) + ROM_REGION( 0x1000, "9000", 0 ) + ROM_LOAD( "pet_hsg-ud12 on 8032 9000 (2532).bin", 0x0000, 0x1000, CRC(d651bf72) SHA1(d3d68228a5a8ec73fb39be860c00edb0d21bd1a9) ) + + ROM_REGION( 0x1000, "a000", 0 ) + ROM_LOAD( "324381-01 rev b sw graphi", 0x0000, 0x1000, CRC(c8e3bff9) SHA1(12ed3176ddd632f52e91082ab574adcba2149684) ) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *cbm8000_hsg_t::device_rom_region() const +{ + return ROM_NAME( cbm8000_hsg ); +} + + +//------------------------------------------------- +// screen_update - +//------------------------------------------------- + +UINT32 cbm8000_hsg_t::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + return 0; +} + + +//------------------------------------------------- +// MACHINE_CONFIG_FRAGMENT( cbm8000_hsg_a ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( cbm8000_hsg_a ) + MCFG_SCREEN_ADD(SCREEN_TAG, RASTER) + MCFG_SCREEN_UPDATE_DEVICE(DEVICE_SELF, cbm8000_hsg_t, screen_update) + MCFG_SCREEN_SIZE(512, 512) + MCFG_SCREEN_VISIBLE_AREA(0, 512-1, 0, 512-1) + MCFG_SCREEN_REFRESH_RATE(25) + MCFG_PALETTE_ADD_MONOCHROME_GREEN("palette") + + //MCFG_DEVICE_ADD(EF9365_TAG, EF9365, 0) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// MACHINE_CONFIG_FRAGMENT( cbm8000_hsg_b ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( cbm8000_hsg_b ) + MCFG_SCREEN_ADD(SCREEN_TAG, RASTER) + MCFG_SCREEN_UPDATE_DEVICE(DEVICE_SELF, cbm8000_hsg_t, screen_update) + MCFG_SCREEN_SIZE(512, 256) + MCFG_SCREEN_VISIBLE_AREA(0, 512-1, 0, 256-1) + MCFG_SCREEN_REFRESH_RATE(50) + MCFG_PALETTE_ADD_MONOCHROME_GREEN("palette") + + //MCFG_DEVICE_ADD(EF9366_TAG, EF9366, 0) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor cbm8000_hsg_a_t::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( cbm8000_hsg_a ); +} + +machine_config_constructor cbm8000_hsg_b_t::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( cbm8000_hsg_b ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// cbm8000_hsg_t - constructor +//------------------------------------------------- + +cbm8000_hsg_t::cbm8000_hsg_t(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_pet_expansion_card_interface(mconfig, *this), + m_9000(*this, "9000"), + m_a000(*this, "a000") +{ +} + +cbm8000_hsg_a_t::cbm8000_hsg_a_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + cbm8000_hsg_t(mconfig, CBM8000_HSG_A, "CBM 8000 High Speed Graphics (A)", tag, owner, clock, "cbm8000_hsg_a", __FILE__) + //m_gdc(*this, EF9365_TAG) +{ +} + +cbm8000_hsg_b_t::cbm8000_hsg_b_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + cbm8000_hsg_t(mconfig, CBM8000_HSG_B, "CBM 8000 High Speed Graphics (B)", tag, owner, clock, "cbm8000_hsg_b", __FILE__) + //m_gdc(*this, EF9366_TAG) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void cbm8000_hsg_t::device_start() +{ +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void cbm8000_hsg_t::device_reset() +{ + //m_gdc->reset(); +} + + +//------------------------------------------------- +// pet_norom_r - NO ROM read +//------------------------------------------------- + +int cbm8000_hsg_t::pet_norom_r(address_space &space, offs_t offset, int sel) +{ + return !(offset >= 0x9000 && offset < 0xaf00); +} + + +//------------------------------------------------- +// pet_bd_r - buffered data read +//------------------------------------------------- + +UINT8 cbm8000_hsg_t::pet_bd_r(address_space &space, offs_t offset, UINT8 data, int &sel) +{ + switch (sel) + { + case pet_expansion_slot_device::SEL9: + data = m_9000->base()[offset & 0xfff]; + break; + + case pet_expansion_slot_device::SELA: + if (offset < 0xaf00) + { + data = m_a000->base()[offset & 0xfff]; + } + else if (offset == 0xaf10) + { + /* + + bit description + + 0 light pen + 1 + 2 + 3 + 4 + 5 + 6 + 7 + + */ + } + else if (offset == 0xad30) + { + // hard copy + } + else if (offset >= 0xaf70 && offset < 0xaf80) + { + //data = m_gdc->data_r(space, offset & 0x0f); + } + break; + } + + return data; +} + + +//------------------------------------------------- +// pet_bd_w - buffered data write +//------------------------------------------------- + +void cbm8000_hsg_t::pet_bd_w(address_space &space, offs_t offset, UINT8 data, int &sel) +{ + if (offset == 0xaf00) + { + /* + + bit description + + 0 hard copy (0=active) + 1 operating page select (version B) + 2 + 3 read-modify-write (1=active) + 4 display switch (1=graphic) + 5 display page select (version B) + 6 + 7 + + */ + } + else if (offset >= 0xaf70 && offset < 0xaf80) + { + //m_gdc->data_w(space, offset & 0x0f, data); + } +} diff --git a/src/devices/bus/pet/hsg.h b/src/devices/bus/pet/hsg.h new file mode 100644 index 00000000000..40345894063 --- /dev/null +++ b/src/devices/bus/pet/hsg.h @@ -0,0 +1,87 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + CBM 8000 High Speed Graphics (324402-01) card emulation + +**********************************************************************/ + +#pragma once + +#ifndef __CBM8000_HSG__ +#define __CBM8000_HSG__ + +#include "emu.h" +#include "exp.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> cbm8000_hsg_t + +class cbm8000_hsg_t : public device_t, + public device_pet_expansion_card_interface +{ +public: + // construction/destruction + cbm8000_hsg_t(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + cbm8000_hsg_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + + // device_pet_expansion_card_interface overrides + virtual int pet_norom_r(address_space &space, offs_t offset, int sel); + virtual UINT8 pet_bd_r(address_space &space, offs_t offset, UINT8 data, int &sel); + virtual void pet_bd_w(address_space &space, offs_t offset, UINT8 data, int &sel); + + UINT32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + +private: + //required_device m_gdc; + required_memory_region m_9000; + required_memory_region m_a000; +}; + + +// ======================> cbm8000_hsg_a_t + +class cbm8000_hsg_a_t : public cbm8000_hsg_t +{ +public: + // construction/destruction + cbm8000_hsg_a_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; +}; + + +// ======================> cbm8000_hsg_b_t + +class cbm8000_hsg_b_t : public cbm8000_hsg_t +{ +public: + // construction/destruction + cbm8000_hsg_b_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; +}; + + +// device type definition +extern const device_type CBM8000_HSG_A; +extern const device_type CBM8000_HSG_B; + + + +#endif diff --git a/src/devices/bus/pet/petuja.c b/src/devices/bus/pet/petuja.c new file mode 100644 index 00000000000..4bc335e7dab --- /dev/null +++ b/src/devices/bus/pet/petuja.c @@ -0,0 +1,105 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/********************************************************************** + + Commodore PET userport joystick adapter emulation + + http://zimmers.net/cbmpics/cbm/PETx/petfaq.html + +**********************************************************************/ + +#include "petuja.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type PET_USERPORT_JOYSTICK_ADAPTER = &device_creator; + + +//------------------------------------------------- +// INPUT_PORTS( petuja ) +//------------------------------------------------- + +static INPUT_PORTS_START( petuja ) + PORT_START("JOY") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_8WAY PORT_PLAYER(1) PORT_WRITE_LINE_DEVICE_MEMBER(DEVICE_SELF, pet_userport_joystick_adapter_device, write_up1) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_8WAY PORT_PLAYER(1) PORT_WRITE_LINE_DEVICE_MEMBER(DEVICE_SELF, pet_userport_joystick_adapter_device, write_down1) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_8WAY PORT_PLAYER(1) PORT_WRITE_LINE_DEVICE_MEMBER(DEVICE_SELF, device_pet_user_port_interface, output_e) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_8WAY PORT_PLAYER(1) PORT_WRITE_LINE_DEVICE_MEMBER(DEVICE_SELF, device_pet_user_port_interface, output_f) + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_8WAY PORT_PLAYER(2) PORT_WRITE_LINE_DEVICE_MEMBER(DEVICE_SELF, pet_userport_joystick_adapter_device, write_up2) + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_8WAY PORT_PLAYER(2) PORT_WRITE_LINE_DEVICE_MEMBER(DEVICE_SELF, pet_userport_joystick_adapter_device, write_down2) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_8WAY PORT_PLAYER(2) PORT_WRITE_LINE_DEVICE_MEMBER(DEVICE_SELF, device_pet_user_port_interface, output_k) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_8WAY PORT_PLAYER(2) PORT_WRITE_LINE_DEVICE_MEMBER(DEVICE_SELF, device_pet_user_port_interface, output_l) + + PORT_START("FIRE") + PORT_BIT( 0x03, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(1) PORT_WRITE_LINE_DEVICE_MEMBER(DEVICE_SELF, pet_userport_joystick_adapter_device, write_fire1) + PORT_BIT( 0x30, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(2) PORT_WRITE_LINE_DEVICE_MEMBER(DEVICE_SELF, pet_userport_joystick_adapter_device, write_fire2) +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor pet_userport_joystick_adapter_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( petuja ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// pet_userport_joystick_adapter_device - constructor +//------------------------------------------------- + +pet_userport_joystick_adapter_device::pet_userport_joystick_adapter_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, PET_USERPORT_JOYSTICK_ADAPTER, "PET Userport Joystick Adapter", tag, owner, clock, "petuja", __FILE__), + device_pet_user_port_interface(mconfig, *this), + m_up1(1), + m_down1(1), + m_fire1(1), + m_up2(1), + m_down2(1), + m_fire2(1) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void pet_userport_joystick_adapter_device::device_start() +{ +} + + +//------------------------------------------------- +// update_port1 +//------------------------------------------------- + +void pet_userport_joystick_adapter_device::update_port1() +{ + printf( "update port1\n" ); + output_c(m_up1 && m_fire1); + output_d(m_down1 && m_fire1); +} + + +//------------------------------------------------- +// update_port2 +//------------------------------------------------- + +void pet_userport_joystick_adapter_device::update_port2() +{ + printf( "update port2\n" ); + output_h(m_up2 && m_fire2); + output_j(m_down2 && m_fire2); +} diff --git a/src/devices/bus/pet/petuja.h b/src/devices/bus/pet/petuja.h new file mode 100644 index 00000000000..f923b3dccda --- /dev/null +++ b/src/devices/bus/pet/petuja.h @@ -0,0 +1,63 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/********************************************************************** + + Commodore PET userport joystick adapter emulation + +**********************************************************************/ + +#pragma once + +#ifndef __PETUJA__ +#define __PETUJA__ + + +#include "emu.h" +#include "user.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> pet_userport_joystick_adapter_device + +class pet_userport_joystick_adapter_device : public device_t, + public device_pet_user_port_interface +{ +public: + // construction/destruction + pet_userport_joystick_adapter_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual ioport_constructor device_input_ports() const; + + // device_pet_user_port_interface overrides + WRITE_LINE_MEMBER( write_up1 ) { m_up1 = state; update_port1(); } + WRITE_LINE_MEMBER( write_down1 ) { m_down1 = state; update_port1(); } + WRITE_LINE_MEMBER( write_fire1 ) { m_fire1 = state; update_port1(); } + WRITE_LINE_MEMBER( write_up2 ) { m_up2 = state; update_port2(); } + WRITE_LINE_MEMBER( write_down2 ) { m_down2 = state; update_port2(); } + WRITE_LINE_MEMBER( write_fire2 ) { m_fire2 = state; update_port2(); } + +protected: + // device-level overrides + virtual void device_start(); + + void update_port1(); + void update_port2(); + int m_up1; + int m_down1; + int m_fire1; + int m_up2; + int m_down2; + int m_fire2; +}; + + +// device type definition +extern const device_type PET_USERPORT_JOYSTICK_ADAPTER; + + +#endif diff --git a/src/devices/bus/pet/superpet.c b/src/devices/bus/pet/superpet.c new file mode 100644 index 00000000000..35a80c2e298 --- /dev/null +++ b/src/devices/bus/pet/superpet.c @@ -0,0 +1,436 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Commodore SuperPET emulation + +**********************************************************************/ + +#include "superpet.h" +#include "bus/rs232/rs232.h" +#include "cpu/m6809/m6809.h" + + + +//************************************************************************** +// MACROS/CONSTANTS +//************************************************************************** + +#define M6809_TAG "u4" +#define MOS6551_TAG "u23" +#define MOS6702_TAG "u2" +#define RS232_TAG "rs232" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type SUPERPET = &device_creator; + + +//------------------------------------------------- +// ROM( superpet ) +//------------------------------------------------- + +ROM_START( superpet ) + ROM_REGION( 0x7000, M6809_TAG, 0 ) + ROM_LOAD( "901898-01.u17", 0x1000, 0x1000, CRC(728a998b) SHA1(0414b3ab847c8977eb05c2fcc72efcf2f9d92871) ) + ROM_LOAD( "901898-02.u18", 0x2000, 0x1000, CRC(6beb7c62) SHA1(df154939b934d0aeeb376813ec1ba0d43c2a3378) ) + ROM_LOAD( "901898-03.u19", 0x3000, 0x1000, CRC(5db4983d) SHA1(6c5b0cce97068f8841112ba6d5cd8e568b562fa3) ) + ROM_LOAD( "901898-04.u20", 0x4000, 0x1000, CRC(f55fc559) SHA1(b42a2050a319a1ffca7868a8d8d635fadd37ec37) ) + ROM_LOAD( "901897-01.u21", 0x5000, 0x0800, CRC(b2cee903) SHA1(e8ce8347451a001214a5e71a13081b38b4be23bc) ) + ROM_LOAD( "901898-05.u22", 0x6000, 0x1000, CRC(f42df0cb) SHA1(9b4a5134d20345171e7303445f87c4e0b9addc96) ) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *superpet_device::device_rom_region() const +{ + return ROM_NAME( superpet ); +} + + +//------------------------------------------------- +// ADDRESS_MAP( superpet_mem ) +//------------------------------------------------- + +static ADDRESS_MAP_START( superpet_mem, AS_PROGRAM, 8, superpet_device ) + AM_RANGE(0x0000, 0xffff) AM_READWRITE(read, write) +ADDRESS_MAP_END + + +//------------------------------------------------- +// MACHINE_CONFIG_FRAGMENT( superpet ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( superpet ) + MCFG_CPU_ADD(M6809_TAG, M6809, XTAL_16MHz/16) + MCFG_CPU_PROGRAM_MAP(superpet_mem) + + MCFG_MOS6702_ADD(MOS6702_TAG, XTAL_16MHz/16) + + MCFG_DEVICE_ADD(MOS6551_TAG, MOS6551, 0) + MCFG_MOS6551_XTAL(XTAL_1_8432MHz) + MCFG_MOS6551_IRQ_HANDLER(WRITELINE(superpet_device, acia_irq_w)) + MCFG_MOS6551_TXD_HANDLER(DEVWRITELINE(RS232_TAG, rs232_port_device, write_txd)) + + MCFG_RS232_PORT_ADD(RS232_TAG, default_rs232_devices, NULL) + MCFG_RS232_RXD_HANDLER(DEVWRITELINE(MOS6551_TAG, mos6551_device, write_rxd)) + MCFG_RS232_DCD_HANDLER(DEVWRITELINE(MOS6551_TAG, mos6551_device, write_dcd)) + MCFG_RS232_DSR_HANDLER(DEVWRITELINE(MOS6551_TAG, mos6551_device, write_dsr)) + MCFG_RS232_CTS_HANDLER(DEVWRITELINE(MOS6551_TAG, mos6551_device, write_cts)) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor superpet_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( superpet ); +} + + +//------------------------------------------------- +// INPUT_PORTS( superpet ) +//------------------------------------------------- + +static INPUT_PORTS_START( superpet ) + PORT_START("SW1") + PORT_DIPNAME( 0x03, 0x02, "RAM" ) + PORT_DIPSETTING( 0x00, "Read Only" ) + PORT_DIPSETTING( 0x01, "Read/Write" ) + PORT_DIPSETTING( 0x02, "System Port" ) + + PORT_START("SW2") + PORT_DIPNAME( 0x03, 0x02, "CPU" ) + PORT_DIPSETTING( 0x00, "6809" ) + PORT_DIPSETTING( 0x01, "6502" ) + PORT_DIPSETTING( 0x02, "System Port" ) +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor superpet_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( superpet ); +} + + + +//************************************************************************** +// INLINE HELPERS +//************************************************************************** + +//------------------------------------------------- +// update_cpu - +//------------------------------------------------- + +inline void superpet_device::update_cpu() +{ + int cpu = (m_sw2 == 2) ? BIT(m_system, 0) : m_sw2; + + if (cpu) + { + // 6502 active + m_maincpu->set_input_line(INPUT_LINE_HALT, ASSERT_LINE); + m_maincpu->set_input_line(INPUT_LINE_HALT, CLEAR_LINE); + } + else + { + // 6809 active + m_maincpu->set_input_line(INPUT_LINE_HALT, CLEAR_LINE); + m_maincpu->set_input_line(INPUT_LINE_HALT, ASSERT_LINE); + } +} + + +//------------------------------------------------- +// is_ram_writable - +//------------------------------------------------- + +inline bool superpet_device::is_ram_writable() +{ + return (m_sw1 == 2) ? BIT(m_system, 1) : m_sw1; +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// superpet_device - constructor +//------------------------------------------------- + +superpet_device::superpet_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, SUPERPET, "SuperPET", tag, owner, clock, "pet_superpet", __FILE__), + device_pet_expansion_card_interface(mconfig, *this), + m_maincpu(*this, M6809_TAG), + m_acia(*this, MOS6551_TAG), + m_dongle(*this, MOS6702_TAG), + m_rom(*this, M6809_TAG), + m_ram(*this, "ram"), + m_io_sw1(*this, "SW1"), + m_io_sw2(*this, "SW2"), + m_system(0), + m_bank(0), + m_sel9_rom(0), + m_pet_irq(CLEAR_LINE), + m_acia_irq(CLEAR_LINE) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void superpet_device::device_start() +{ + // allocate memory + m_ram.allocate(0x10000); + + // state saving + save_item(NAME(m_system)); + save_item(NAME(m_bank)); + save_item(NAME(m_sel9_rom)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void superpet_device::device_reset() +{ + m_maincpu->reset(); + m_acia->reset(); + m_dongle->reset(); + + m_system = 0; + m_bank = 0; + m_sel9_rom = 0; + m_sw1 = m_io_sw1->read(); + m_sw2 = m_io_sw2->read(); + + update_cpu(); +} + + +//------------------------------------------------- +// pet_norom_r - NO ROM read +//------------------------------------------------- + +int superpet_device::pet_norom_r(address_space &space, offs_t offset, int sel) +{ + return BIT(m_system, 0); +} + + +//------------------------------------------------- +// pet_bd_r - buffered data read +//------------------------------------------------- + +UINT8 superpet_device::pet_bd_r(address_space &space, offs_t offset, UINT8 data, int &sel) +{ + int norom = pet_norom_r(space, offset, sel); + + switch (sel) + { + case pet_expansion_slot_device::SEL9: + if (m_sel9_rom) + { + data = m_rom->base()[offset - 0x9000]; + } + else + { + data = m_ram[((m_bank & 0x0f) << 12) | (offset & 0xfff)]; + } + break; + + case pet_expansion_slot_device::SELA: + case pet_expansion_slot_device::SELB: + case pet_expansion_slot_device::SELC: + case pet_expansion_slot_device::SELD: + case pet_expansion_slot_device::SELF: + if (!norom) + { + data = m_rom->base()[offset - 0x9000]; + } + break; + + case pet_expansion_slot_device::SELE: + if (!norom && !BIT(offset, 11)) + { + data = m_rom->base()[offset - 0x9000]; + } + break; + } + + switch (offset) + { + case 0xefe0: + case 0xefe1: + case 0xefe2: + case 0xefe3: + data = m_dongle->read(space, offset & 0x03); + break; + + case 0xeff0: + case 0xeff1: + case 0xeff2: + case 0xeff3: + data = m_acia->read(space, offset & 0x03); + break; + } + + return data; +} + + +//------------------------------------------------- +// pet_bd_w - buffered data write +//------------------------------------------------- + +void superpet_device::pet_bd_w(address_space &space, offs_t offset, UINT8 data, int &sel) +{ + switch (sel) + { + case pet_expansion_slot_device::SEL9: + if (!m_sel9_rom && is_ram_writable()) + { + m_ram[((m_bank & 0x0f) << 12) | (offset & 0xfff)] = data; + } + break; + } + + switch (offset) + { + case 0xefe0: + case 0xefe1: + case 0xefe2: + case 0xefe3: + m_dongle->write(space, offset & 0x03, data); + printf("6702 %u %02x\n", offset & 0x03, data); + break; + + case 0xeff0: + case 0xeff1: + case 0xeff2: + case 0xeff3: + m_acia->write(space, offset & 0x03, data); + break; + + case 0xeff8: + case 0xeff9: + if (BIT(m_bank, 7)) + { + /* + + bit description + + 0 SW2 CPU (0=6809, 1=6502) + 1 SW1 RAM (0=read only, 1=read/write) + 2 + 3 DIAG + 4 + 5 + 6 + 7 + + */ + + m_system = data; + update_cpu(); + printf("SYSTEM %02x\n", data); + } + break; + + case 0xeffc: + case 0xeffd: + /* + + bit description + + 0 A0 + 1 A1 + 2 A2 + 3 SEL A + 4 J1 pin 40 + 5 SEL B + 6 J1 pin 39 + 7 BIT 7 + + */ + + m_bank = data; + printf("BANK %02x\n", data); + break; + } +} + + +//------------------------------------------------- +// pet_diag_r - DIAG read +//------------------------------------------------- + +int superpet_device::pet_diag_r() +{ + return BIT(m_system, 3); +} + + +//------------------------------------------------- +// pet_irq_w - IRQ write +//------------------------------------------------- + +void superpet_device::pet_irq_w(int state) +{ + m_pet_irq = state; + + //m_maincpu->set_input_line(M6809_IRQ_LINE, m_pet_irq || m_acia_irq); +} + + +//------------------------------------------------- +// read - +//------------------------------------------------- + +READ8_MEMBER( superpet_device::read ) +{ + return m_slot->dma_bd_r(offset); +} + + +//------------------------------------------------- +// write - +//------------------------------------------------- + +WRITE8_MEMBER( superpet_device::write ) +{ + m_slot->dma_bd_w(offset, data); +} + + +//------------------------------------------------- +// acia_irq_w - +//------------------------------------------------- + +WRITE_LINE_MEMBER( superpet_device::acia_irq_w ) +{ + m_acia_irq = state; + + //m_maincpu->set_input_line(M6809_IRQ_LINE, m_pet_irq || m_acia_irq); +} diff --git a/src/devices/bus/pet/superpet.h b/src/devices/bus/pet/superpet.h new file mode 100644 index 00000000000..2cf1c011c6e --- /dev/null +++ b/src/devices/bus/pet/superpet.h @@ -0,0 +1,80 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Commodore SuperPET emulation + +**********************************************************************/ + +#pragma once + +#ifndef __SUPERPET__ +#define __SUPERPET__ + +#include "exp.h" +#include "machine/mos6551.h" +#include "machine/mos6702.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> superpet_device + +class superpet_device : public device_t, + public device_pet_expansion_card_interface +{ +public: + // construction/destruction + superpet_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + virtual ioport_constructor device_input_ports() const; + + DECLARE_READ8_MEMBER( read ); + DECLARE_WRITE8_MEMBER( write ); + DECLARE_WRITE_LINE_MEMBER( acia_irq_w ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_pet_expansion_card_interface overrides + virtual int pet_norom_r(address_space &space, offs_t offset, int sel); + virtual UINT8 pet_bd_r(address_space &space, offs_t offset, UINT8 data, int &sel); + virtual void pet_bd_w(address_space &space, offs_t offset, UINT8 data, int &sel); + virtual int pet_diag_r(); + virtual void pet_irq_w(int state); + +private: + required_device m_maincpu; + required_device m_acia; + required_device m_dongle; + required_memory_region m_rom; + optional_shared_ptr m_ram; + required_ioport m_io_sw1; + required_ioport m_io_sw2; + + inline void update_cpu(); + inline bool is_ram_writable(); + + UINT8 m_system; + UINT8 m_bank; + UINT8 m_sw1; + UINT8 m_sw2; + int m_sel9_rom; + int m_pet_irq; + int m_acia_irq; +}; + + +// device type definition +extern const device_type SUPERPET; + + +#endif diff --git a/src/devices/bus/pet/user.c b/src/devices/bus/pet/user.c new file mode 100644 index 00000000000..b543777df63 --- /dev/null +++ b/src/devices/bus/pet/user.c @@ -0,0 +1,130 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/********************************************************************** + + Commodore PET User Port emulation + +**********************************************************************/ + +#include "user.h" + +// class pet_user_port_device + +const device_type PET_USER_PORT = &device_creator; + +pet_user_port_device::pet_user_port_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, PET_USER_PORT, "PET user port", tag, owner, clock, "pet_user_port", __FILE__), + device_slot_interface(mconfig, *this), + m_2_handler(*this), + m_3_handler(*this), + m_4_handler(*this), + m_5_handler(*this), + m_6_handler(*this), + m_7_handler(*this), + m_8_handler(*this), + m_9_handler(*this), + m_10_handler(*this), + m_b_handler(*this), + m_c_handler(*this), + m_d_handler(*this), + m_e_handler(*this), + m_f_handler(*this), + m_h_handler(*this), + m_j_handler(*this), + m_k_handler(*this), + m_l_handler(*this), + m_m_handler(*this), + m_card(NULL) +{ +} + +void pet_user_port_device::device_config_complete() +{ + m_card = dynamic_cast(get_card_device()); +} + +void pet_user_port_device::device_start() +{ + m_2_handler.resolve_safe(); + m_3_handler.resolve_safe(); + m_4_handler.resolve_safe(); + m_5_handler.resolve_safe(); + m_6_handler.resolve_safe(); + m_7_handler.resolve_safe(); + m_8_handler.resolve_safe(); + m_9_handler.resolve_safe(); + m_10_handler.resolve_safe(); + m_b_handler.resolve_safe(); + m_c_handler.resolve_safe(); + m_d_handler.resolve_safe(); + m_e_handler.resolve_safe(); + m_f_handler.resolve_safe(); + m_h_handler.resolve_safe(); + m_j_handler.resolve_safe(); + m_k_handler.resolve_safe(); + m_l_handler.resolve_safe(); + m_m_handler.resolve_safe(); + + // pull up + m_3_handler(1); + m_4_handler(1); + m_5_handler(1); + m_6_handler(1); + m_7_handler(1); + m_8_handler(1); + m_9_handler(1); + m_b_handler(1); + m_c_handler(1); + m_d_handler(1); + m_e_handler(1); + m_f_handler(1); + m_h_handler(1); + m_j_handler(1); + m_k_handler(1); + m_l_handler(1); + m_m_handler(1); +} + +WRITE_LINE_MEMBER( pet_user_port_device::write_2 ) { if (m_card != NULL) m_card->input_2(state); } +WRITE_LINE_MEMBER( pet_user_port_device::write_3 ) { if (m_card != NULL) m_card->input_3(state); } +WRITE_LINE_MEMBER( pet_user_port_device::write_4 ) { if (m_card != NULL) m_card->input_4(state); } +WRITE_LINE_MEMBER( pet_user_port_device::write_5 ) { if (m_card != NULL) m_card->input_5(state); } +WRITE_LINE_MEMBER( pet_user_port_device::write_6 ) { if (m_card != NULL) m_card->input_6(state); } +WRITE_LINE_MEMBER( pet_user_port_device::write_7 ) { if (m_card != NULL) m_card->input_7(state); } +WRITE_LINE_MEMBER( pet_user_port_device::write_8 ) { if (m_card != NULL) m_card->input_8(state); } +WRITE_LINE_MEMBER( pet_user_port_device::write_9 ) { if (m_card != NULL) m_card->input_9(state); } +WRITE_LINE_MEMBER( pet_user_port_device::write_10 ) { if (m_card != NULL) m_card->input_10(state); } +WRITE_LINE_MEMBER( pet_user_port_device::write_b ) { if (m_card != NULL) m_card->input_b(state); } +WRITE_LINE_MEMBER( pet_user_port_device::write_c ) { if (m_card != NULL) m_card->input_c(state); } +WRITE_LINE_MEMBER( pet_user_port_device::write_d ) { if (m_card != NULL) m_card->input_d(state); } +WRITE_LINE_MEMBER( pet_user_port_device::write_e ) { if (m_card != NULL) m_card->input_e(state); } +WRITE_LINE_MEMBER( pet_user_port_device::write_f ) { if (m_card != NULL) m_card->input_f(state); } +WRITE_LINE_MEMBER( pet_user_port_device::write_h ) { if (m_card != NULL) m_card->input_h(state); } +WRITE_LINE_MEMBER( pet_user_port_device::write_j ) { if (m_card != NULL) m_card->input_j(state); } +WRITE_LINE_MEMBER( pet_user_port_device::write_k ) { if (m_card != NULL) m_card->input_k(state); } +WRITE_LINE_MEMBER( pet_user_port_device::write_l ) { if (m_card != NULL) m_card->input_l(state); } +WRITE_LINE_MEMBER( pet_user_port_device::write_m ) { if (m_card != NULL) m_card->input_m(state); } + + +// class device_pet_user_port_interface + +device_pet_user_port_interface::device_pet_user_port_interface(const machine_config &mconfig, device_t &device) + : device_slot_card_interface(mconfig,device) +{ + m_slot = dynamic_cast(device.owner()); +} + +device_pet_user_port_interface::~device_pet_user_port_interface() +{ +} + + +#include "diag.h" +#include "petuja.h" +#include "cb2snd.h" + +SLOT_INTERFACE_START( pet_user_port_cards ) + SLOT_INTERFACE("diag", PET_USERPORT_DIAGNOSTIC_CONNECTOR) + SLOT_INTERFACE("petuja", PET_USERPORT_JOYSTICK_ADAPTER) + SLOT_INTERFACE("cb2snd", PET_USERPORT_CB2_SOUND_DEVICE) +SLOT_INTERFACE_END diff --git a/src/devices/bus/pet/user.h b/src/devices/bus/pet/user.h new file mode 100644 index 00000000000..9c6e6d8bd3e --- /dev/null +++ b/src/devices/bus/pet/user.h @@ -0,0 +1,231 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/********************************************************************** + + Commodore PET User Port emulation + +********************************************************************** + + GND 1 A GND + VIDEO 2 B CA1 + _SRQ IN 3 C PA0 + EOI 4 D PA1 + DIAG 5 E PA2 + #2 CASS READ 6 F PA3 + CASS WRITE 7 H PA4 + #1 CASS READ 8 J PA5 + VERT DRIVE 9 K PA6 + HORZ DRIVE 10 L PA7 + GND 11 M CB2 + GND 12 N GND + +**********************************************************************/ + +#pragma once + +#ifndef __PET_USER_PORT__ +#define __PET_USER_PORT__ + +#include "emu.h" + + +#define MCFG_PET_USER_PORT_ADD(_tag, _slot_intf, _def_slot) \ + MCFG_DEVICE_ADD(_tag, PET_USER_PORT, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) + +#define MCFG_PET_USER_PORT_2_HANDLER(_devcb) \ + devcb = &pet_user_port_device::set_2_handler(*device, DEVCB_##_devcb); + +#define MCFG_PET_USER_PORT_3_HANDLER(_devcb) \ + devcb = &pet_user_port_device::set_3_handler(*device, DEVCB_##_devcb); + +#define MCFG_PET_USER_PORT_4_HANDLER(_devcb) \ + devcb = &pet_user_port_device::set_4_handler(*device, DEVCB_##_devcb); + +#define MCFG_PET_USER_PORT_5_HANDLER(_devcb) \ + devcb = &pet_user_port_device::set_5_handler(*device, DEVCB_##_devcb); + +#define MCFG_PET_USER_PORT_6_HANDLER(_devcb) \ + devcb = &pet_user_port_device::set_6_handler(*device, DEVCB_##_devcb); + +#define MCFG_PET_USER_PORT_7_HANDLER(_devcb) \ + devcb = &pet_user_port_device::set_7_handler(*device, DEVCB_##_devcb); + +#define MCFG_PET_USER_PORT_8_HANDLER(_devcb) \ + devcb = &pet_user_port_device::set_8_handler(*device, DEVCB_##_devcb); + +#define MCFG_PET_USER_PORT_9_HANDLER(_devcb) \ + devcb = &pet_user_port_device::set_9_handler(*device, DEVCB_##_devcb); + +#define MCFG_PET_USER_PORT_10_HANDLER(_devcb) \ + devcb = &pet_user_port_device::set_10_handler(*device, DEVCB_##_devcb); + +#define MCFG_PET_USER_PORT_B_HANDLER(_devcb) \ + devcb = &pet_user_port_device::set_b_handler(*device, DEVCB_##_devcb); + +#define MCFG_PET_USER_PORT_C_HANDLER(_devcb) \ + devcb = &pet_user_port_device::set_c_handler(*device, DEVCB_##_devcb); + +#define MCFG_PET_USER_PORT_D_HANDLER(_devcb) \ + devcb = &pet_user_port_device::set_d_handler(*device, DEVCB_##_devcb); + +#define MCFG_PET_USER_PORT_E_HANDLER(_devcb) \ + devcb = &pet_user_port_device::set_e_handler(*device, DEVCB_##_devcb); + +#define MCFG_PET_USER_PORT_F_HANDLER(_devcb) \ + devcb = &pet_user_port_device::set_f_handler(*device, DEVCB_##_devcb); + +#define MCFG_PET_USER_PORT_H_HANDLER(_devcb) \ + devcb = &pet_user_port_device::set_h_handler(*device, DEVCB_##_devcb); + +#define MCFG_PET_USER_PORT_J_HANDLER(_devcb) \ + devcb = &pet_user_port_device::set_j_handler(*device, DEVCB_##_devcb); + +#define MCFG_PET_USER_PORT_K_HANDLER(_devcb) \ + devcb = &pet_user_port_device::set_k_handler(*device, DEVCB_##_devcb); + +#define MCFG_PET_USER_PORT_L_HANDLER(_devcb) \ + devcb = &pet_user_port_device::set_l_handler(*device, DEVCB_##_devcb); + +#define MCFG_PET_USER_PORT_M_HANDLER(_devcb) \ + devcb = &pet_user_port_device::set_m_handler(*device, DEVCB_##_devcb); + + +extern const device_type PET_USER_PORT; + +class device_pet_user_port_interface; + +class pet_user_port_device : public device_t, + public device_slot_interface +{ + friend class device_pet_user_port_interface; + +public: + pet_user_port_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + template static devcb_base &set_2_handler(device_t &device, _Object object) { return downcast(device).m_2_handler.set_callback(object); } + template static devcb_base &set_3_handler(device_t &device, _Object object) { return downcast(device).m_3_handler.set_callback(object); } + template static devcb_base &set_4_handler(device_t &device, _Object object) { return downcast(device).m_4_handler.set_callback(object); } + template static devcb_base &set_5_handler(device_t &device, _Object object) { return downcast(device).m_5_handler.set_callback(object); } + template static devcb_base &set_6_handler(device_t &device, _Object object) { return downcast(device).m_6_handler.set_callback(object); } + template static devcb_base &set_7_handler(device_t &device, _Object object) { return downcast(device).m_7_handler.set_callback(object); } + template static devcb_base &set_8_handler(device_t &device, _Object object) { return downcast(device).m_8_handler.set_callback(object); } + template static devcb_base &set_9_handler(device_t &device, _Object object) { return downcast(device).m_9_handler.set_callback(object); } + template static devcb_base &set_10_handler(device_t &device, _Object object) { return downcast(device).m_10_handler.set_callback(object); } + template static devcb_base &set_b_handler(device_t &device, _Object object) { return downcast(device).m_b_handler.set_callback(object); } + template static devcb_base &set_c_handler(device_t &device, _Object object) { return downcast(device).m_c_handler.set_callback(object); } + template static devcb_base &set_d_handler(device_t &device, _Object object) { return downcast(device).m_d_handler.set_callback(object); } + template static devcb_base &set_e_handler(device_t &device, _Object object) { return downcast(device).m_e_handler.set_callback(object); } + template static devcb_base &set_f_handler(device_t &device, _Object object) { return downcast(device).m_f_handler.set_callback(object); } + template static devcb_base &set_h_handler(device_t &device, _Object object) { return downcast(device).m_h_handler.set_callback(object); } + template static devcb_base &set_j_handler(device_t &device, _Object object) { return downcast(device).m_j_handler.set_callback(object); } + template static devcb_base &set_k_handler(device_t &device, _Object object) { return downcast(device).m_k_handler.set_callback(object); } + template static devcb_base &set_l_handler(device_t &device, _Object object) { return downcast(device).m_l_handler.set_callback(object); } + template static devcb_base &set_m_handler(device_t &device, _Object object) { return downcast(device).m_m_handler.set_callback(object); } + + DECLARE_WRITE_LINE_MEMBER( write_2 ); + DECLARE_WRITE_LINE_MEMBER( write_3 ); + DECLARE_WRITE_LINE_MEMBER( write_4 ); + DECLARE_WRITE_LINE_MEMBER( write_5 ); + DECLARE_WRITE_LINE_MEMBER( write_6 ); + DECLARE_WRITE_LINE_MEMBER( write_7 ); + DECLARE_WRITE_LINE_MEMBER( write_8 ); + DECLARE_WRITE_LINE_MEMBER( write_9 ); + DECLARE_WRITE_LINE_MEMBER( write_10 ); + DECLARE_WRITE_LINE_MEMBER( write_b ); + DECLARE_WRITE_LINE_MEMBER( write_c ); + DECLARE_WRITE_LINE_MEMBER( write_d ); + DECLARE_WRITE_LINE_MEMBER( write_e ); + DECLARE_WRITE_LINE_MEMBER( write_f ); + DECLARE_WRITE_LINE_MEMBER( write_h ); + DECLARE_WRITE_LINE_MEMBER( write_j ); + DECLARE_WRITE_LINE_MEMBER( write_k ); + DECLARE_WRITE_LINE_MEMBER( write_l ); + DECLARE_WRITE_LINE_MEMBER( write_m ); + +protected: + // device-level overrides + virtual void device_config_complete(); + virtual void device_start(); + + devcb_write_line m_2_handler; + devcb_write_line m_3_handler; + devcb_write_line m_4_handler; + devcb_write_line m_5_handler; + devcb_write_line m_6_handler; + devcb_write_line m_7_handler; + devcb_write_line m_8_handler; + devcb_write_line m_9_handler; + devcb_write_line m_10_handler; + devcb_write_line m_b_handler; + devcb_write_line m_c_handler; + devcb_write_line m_d_handler; + devcb_write_line m_e_handler; + devcb_write_line m_f_handler; + devcb_write_line m_h_handler; + devcb_write_line m_j_handler; + devcb_write_line m_k_handler; + devcb_write_line m_l_handler; + devcb_write_line m_m_handler; + +private: + device_pet_user_port_interface *m_card; +}; + + +class device_pet_user_port_interface : public device_slot_card_interface +{ + friend class pet_user_port_device; + +public: + device_pet_user_port_interface(const machine_config &mconfig, device_t &device); + virtual ~device_pet_user_port_interface(); + + DECLARE_WRITE_LINE_MEMBER( output_2 ) { m_slot->m_2_handler(state); } + DECLARE_WRITE_LINE_MEMBER( output_3 ) { m_slot->m_3_handler(state); } + DECLARE_WRITE_LINE_MEMBER( output_4 ) { m_slot->m_4_handler(state); } + DECLARE_WRITE_LINE_MEMBER( output_5 ) { m_slot->m_5_handler(state); } + DECLARE_WRITE_LINE_MEMBER( output_6 ) { m_slot->m_6_handler(state); } + DECLARE_WRITE_LINE_MEMBER( output_7 ) { m_slot->m_7_handler(state); } + DECLARE_WRITE_LINE_MEMBER( output_8 ) { m_slot->m_8_handler(state); } + DECLARE_WRITE_LINE_MEMBER( output_9 ) { m_slot->m_9_handler(state); } + DECLARE_WRITE_LINE_MEMBER( output_10 ) { m_slot->m_10_handler(state); } + DECLARE_WRITE_LINE_MEMBER( output_b ) { m_slot->m_b_handler(state); } + DECLARE_WRITE_LINE_MEMBER( output_c ) { m_slot->m_c_handler(state); } + DECLARE_WRITE_LINE_MEMBER( output_d ) { m_slot->m_d_handler(state); } + DECLARE_WRITE_LINE_MEMBER( output_e ) { m_slot->m_e_handler(state); } + DECLARE_WRITE_LINE_MEMBER( output_f ) { m_slot->m_f_handler(state); } + DECLARE_WRITE_LINE_MEMBER( output_h ) { m_slot->m_h_handler(state); } + DECLARE_WRITE_LINE_MEMBER( output_j ) { m_slot->m_j_handler(state); } + DECLARE_WRITE_LINE_MEMBER( output_k ) { m_slot->m_k_handler(state); } + DECLARE_WRITE_LINE_MEMBER( output_l ) { m_slot->m_l_handler(state); } + DECLARE_WRITE_LINE_MEMBER( output_m ) { m_slot->m_m_handler(state); } + +protected: + virtual DECLARE_WRITE_LINE_MEMBER( input_2 ) {} + virtual DECLARE_WRITE_LINE_MEMBER( input_3 ) {} + virtual DECLARE_WRITE_LINE_MEMBER( input_4 ) {} + virtual DECLARE_WRITE_LINE_MEMBER( input_5 ) {} + virtual DECLARE_WRITE_LINE_MEMBER( input_6 ) {} + virtual DECLARE_WRITE_LINE_MEMBER( input_7 ) {} + virtual DECLARE_WRITE_LINE_MEMBER( input_8 ) {} + virtual DECLARE_WRITE_LINE_MEMBER( input_9 ) {} + virtual DECLARE_WRITE_LINE_MEMBER( input_10 ) {} + virtual DECLARE_WRITE_LINE_MEMBER( input_b ) {} + virtual DECLARE_WRITE_LINE_MEMBER( input_c ) {} + virtual DECLARE_WRITE_LINE_MEMBER( input_d ) {} + virtual DECLARE_WRITE_LINE_MEMBER( input_e ) {} + virtual DECLARE_WRITE_LINE_MEMBER( input_f ) {} + virtual DECLARE_WRITE_LINE_MEMBER( input_h ) {} + virtual DECLARE_WRITE_LINE_MEMBER( input_j ) {} + virtual DECLARE_WRITE_LINE_MEMBER( input_k ) {} + virtual DECLARE_WRITE_LINE_MEMBER( input_l ) {} + virtual DECLARE_WRITE_LINE_MEMBER( input_m ) {} + + pet_user_port_device *m_slot; +}; + + +SLOT_INTERFACE_EXTERN( pet_user_port_cards ); + +#endif diff --git a/src/devices/bus/plus4/c1551.c b/src/devices/bus/plus4/c1551.c new file mode 100644 index 00000000000..5439eaf1fd5 --- /dev/null +++ b/src/devices/bus/plus4/c1551.c @@ -0,0 +1,552 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Commodore 1551 Single Disk Drive emulation + +**********************************************************************/ + +#include "c1551.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define M6510T_TAG "u2" +#define M6523_0_TAG "u3" +#define M6523_1_TAG "ci_u2" +#define C64H156_TAG "u6" +#define PLA_TAG "u1" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type C1551 = &device_creator; + + +//------------------------------------------------- +// ROM( c1551 ) +//------------------------------------------------- + +ROM_START( c1551 ) // schematic 251860 + ROM_REGION( 0x4000, M6510T_TAG, 0 ) + ROM_LOAD( "318001-01.u4", 0x0000, 0x4000, CRC(6d16d024) SHA1(fae3c788ad9a6cc2dbdfbcf6c0264b2ca921d55e) ) + + ROM_REGION( 0xf5, PLA_TAG, 0 ) // schematic 251925 + ROM_LOAD( "251641-03.u1", 0x00, 0xf5, NO_DUMP ) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *c1551_t::device_rom_region() const +{ + return ROM_NAME( c1551 ); +} + + +//------------------------------------------------- +// M6510_INTERFACE( cpu_intf ) +//------------------------------------------------- + +READ8_MEMBER( c1551_t::port_r ) +{ + /* + + bit description + + P0 + P1 + P2 + P3 + P4 WPS + P5 + P6 + P7 BYTE LTCHED + + */ + + UINT8 data = 0; + + // write protect sense + data |= !m_floppy->wpt_r() << 4; + + // byte latched + data |= m_ga->atn_r() << 7; + + return data; +} + +WRITE8_MEMBER( c1551_t::port_w ) +{ + /* + + bit description + + P0 STP0A + P1 STP0B + P2 MTR0 + P3 ACT0 + P4 + P5 DS0 + P6 DS1 + P7 + + */ + + // stepper motor + m_ga->stp_w(data & 0x03); + + // spindle motor + m_ga->mtr_w(BIT(data, 2)); + + // activity LED + output_set_led_value(LED_ACT, BIT(data, 3)); + + // density select + m_ga->ds_w((data >> 5) & 0x03); +} + + +//------------------------------------------------- +// tpi6525_interface tpi0_intf +//------------------------------------------------- + +READ8_MEMBER( c1551_t::tcbm_data_r ) +{ + /* + + bit description + + PA0 TCBM PA0 + PA1 TCBM PA1 + PA2 TCBM PA2 + PA3 TCBM PA3 + PA4 TCBM PA4 + PA5 TCBM PA5 + PA6 TCBM PA6 + PA7 TCBM PA7 + + */ + + return m_tcbm_data; +} + +WRITE8_MEMBER( c1551_t::tcbm_data_w ) +{ + /* + + bit description + + PA0 TCBM PA0 + PA1 TCBM PA1 + PA2 TCBM PA2 + PA3 TCBM PA3 + PA4 TCBM PA4 + PA5 TCBM PA5 + PA6 TCBM PA6 + PA7 TCBM PA7 + + */ + + m_tcbm_data = data; +} + +READ8_MEMBER( c1551_t::tpi0_r ) +{ + UINT8 data = m_tpi0->read(space, offset); + + m_ga->ted_w(0); + m_ga->ted_w(1); + + return data; +} + +WRITE8_MEMBER( c1551_t::tpi0_w ) +{ + m_tpi0->write(space, offset, data); + + m_ga->ted_w(0); + m_ga->ted_w(1); +} + +READ8_MEMBER( c1551_t::tpi0_pc_r ) +{ + /* + + bit description + + PC0 + PC1 + PC2 + PC3 + PC4 + PC5 JP1 + PC6 _SYNC + PC7 TCBM DAV + + */ + + UINT8 data = 0; + + // JP1 + data |= m_jp1->read() << 5; + + // SYNC detect line + data |= m_ga->sync_r() << 6; + + // TCBM data valid + data |= m_dav << 7; + + return data; +} + +WRITE8_MEMBER( c1551_t::tpi0_pc_w ) +{ + /* + + bit description + + PC0 TCBM STATUS0 + PC1 TCBM STATUS1 + PC2 TCBM DEV + PC3 TCBM ACK + PC4 MODE + PC5 + PC6 + PC7 + + */ + + // TCBM status + m_status = data & 0x03; + + // TCBM device number + m_dev = BIT(data, 2); + + // TCBM acknowledge + m_ack = BIT(data, 3); + + // read/write mode + m_ga->oe_w(BIT(data, 4)); +} + +//------------------------------------------------- +// tpi6525_interface tpi1_intf +//------------------------------------------------- + +READ8_MEMBER( c1551_t::tpi1_pb_r ) +{ + /* + + bit description + + PB0 STATUS0 + PB1 STATUS1 + PB2 + PB3 + PB4 + PB5 + PB6 + PB7 + + */ + + return m_status & 0x03; +} + +READ8_MEMBER( c1551_t::tpi1_pc_r ) +{ + /* + + bit description + + PC0 + PC1 + PC2 + PC3 + PC4 + PC5 + PC6 + PC7 TCBM ACK + + */ + + UINT8 data = 0; + + // TCBM acknowledge + data |= m_ack << 7; + + return data; +} + +WRITE8_MEMBER( c1551_t::tpi1_pc_w ) +{ + /* + + bit description + + PC0 + PC1 + PC2 + PC3 + PC4 + PC5 + PC6 TCBM DAV + PC7 + + */ + + // TCBM data valid + m_dav = BIT(data, 6); +} + +//------------------------------------------------- +// ADDRESS_MAP( c1551_mem ) +//------------------------------------------------- + +static ADDRESS_MAP_START( c1551_mem, AS_PROGRAM, 8, c1551_t ) + AM_RANGE(0x0000, 0x07ff) AM_MIRROR(0x0800) AM_RAM + AM_RANGE(0x4000, 0x4007) AM_MIRROR(0x3ff8) AM_READWRITE(tpi0_r, tpi0_w) + AM_RANGE(0xc000, 0xffff) AM_ROM AM_REGION(M6510T_TAG, 0) +ADDRESS_MAP_END + + +//------------------------------------------------- +// SLOT_INTERFACE( c1551_floppies ) +//------------------------------------------------- + +static SLOT_INTERFACE_START( c1551_floppies ) + SLOT_INTERFACE( "525ssqd", FLOPPY_525_SSQD ) +SLOT_INTERFACE_END + + +//------------------------------------------------- +// FLOPPY_FORMATS( floppy_formats ) +//------------------------------------------------- + +FLOPPY_FORMATS_MEMBER( c1551_t::floppy_formats ) + FLOPPY_D64_FORMAT, + FLOPPY_G64_FORMAT +FLOPPY_FORMATS_END + + +//------------------------------------------------- +// MACHINE_DRIVER( c1551 ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( c1551 ) + MCFG_CPU_ADD(M6510T_TAG, M6510T, XTAL_16MHz/8) + MCFG_CPU_PROGRAM_MAP(c1551_mem) + MCFG_M6510T_PORT_CALLBACKS(READ8(c1551_t, port_r), WRITE8(c1551_t, port_w)) + MCFG_QUANTUM_PERFECT_CPU(M6510T_TAG) + + MCFG_PLS100_ADD(PLA_TAG) + MCFG_DEVICE_ADD(M6523_0_TAG, TPI6525, 0) + MCFG_TPI6525_IN_PA_CB(READ8(c1551_t, tcbm_data_r)) + MCFG_TPI6525_OUT_PA_CB(WRITE8(c1551_t, tcbm_data_w)) + MCFG_TPI6525_IN_PB_CB(DEVREAD8(C64H156_TAG, c64h156_device, yb_r)) + MCFG_TPI6525_OUT_PB_CB(DEVWRITE8(C64H156_TAG, c64h156_device, yb_w)) + MCFG_TPI6525_IN_PC_CB(READ8(c1551_t, tpi0_pc_r)) + MCFG_TPI6525_OUT_PC_CB(WRITE8(c1551_t, tpi0_pc_w)) + MCFG_DEVICE_ADD(M6523_1_TAG, TPI6525, 0) + MCFG_TPI6525_IN_PA_CB(READ8(c1551_t, tcbm_data_r)) + MCFG_TPI6525_OUT_PA_CB(WRITE8(c1551_t, tcbm_data_w)) + MCFG_TPI6525_IN_PB_CB(READ8(c1551_t, tpi1_pb_r)) + MCFG_TPI6525_IN_PC_CB(READ8(c1551_t, tpi1_pc_r)) + MCFG_TPI6525_OUT_PC_CB(WRITE8(c1551_t, tpi1_pc_w)) + + MCFG_DEVICE_ADD(C64H156_TAG, C64H156, XTAL_16MHz) + MCFG_64H156_BYTE_CALLBACK(DEVWRITELINE(C64H156_TAG, c64h156_device, atni_w)) + MCFG_FLOPPY_DRIVE_ADD(C64H156_TAG":0", c1551_floppies, "525ssqd", c1551_t::floppy_formats) + + MCFG_PLUS4_PASSTHRU_EXPANSION_SLOT_ADD() +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor c1551_t::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( c1551 ); +} + + +//------------------------------------------------- +// INPUT_PORTS( c1551 ) +//------------------------------------------------- + +static INPUT_PORTS_START( c1551 ) + PORT_START("JP1") + PORT_DIPNAME( 0x01, 0x00, "Device Number" ) + PORT_DIPSETTING( 0x00, "8" ) + PORT_DIPSETTING( 0x01, "9" ) +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor c1551_t::device_input_ports() const +{ + return INPUT_PORTS_NAME( c1551 ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// c1551_t - constructor +//------------------------------------------------- + +c1551_t::c1551_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, C1551, "C1551", tag, owner, clock, "c1551", __FILE__), + device_plus4_expansion_card_interface(mconfig, *this), + m_maincpu(*this, M6510T_TAG), + m_tpi0(*this, M6523_0_TAG), + m_tpi1(*this, M6523_1_TAG), + m_ga(*this, C64H156_TAG), + m_pla(*this, PLA_TAG), + m_floppy(*this, C64H156_TAG":0:525ssqd"), + m_exp(*this, PLUS4_EXPANSION_SLOT_TAG), + m_jp1(*this, "JP1"), + m_tcbm_data(0xff), + m_status(1), + m_dav(1), + m_ack(1), + m_dev(0) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void c1551_t::device_start() +{ + // allocate timers + m_irq_timer = timer_alloc(); + m_irq_timer->adjust(attotime::zero, CLEAR_LINE); + + // install image callbacks + m_ga->set_floppy(m_floppy); + + // register for state saving + save_item(NAME(m_tcbm_data)); + save_item(NAME(m_status)); + save_item(NAME(m_dav)); + save_item(NAME(m_ack)); + save_item(NAME(m_dev)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void c1551_t::device_reset() +{ + m_maincpu->reset(); + + m_tpi0->reset(); + + m_exp->reset(); + + // initialize gate array + m_ga->test_w(1); + m_ga->soe_w(1); + m_ga->accl_w(1); + m_ga->atna_w(1); +} + + +//------------------------------------------------- +// device_timer - handler timer events +//------------------------------------------------- + +void c1551_t::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + m_maincpu->set_input_line(M6502_IRQ_LINE, param); + + if (param == ASSERT_LINE) + { + // Ts = 0.7*R2*C1 = 0.7*100R*0.1uF = 7us + m_irq_timer->adjust(attotime::from_usec(7), CLEAR_LINE); + } + else + { + // Tm = 0.7*(R1+R2)*C1 = 0.7*(120K+100R)*0.1uF = 0.008407s + m_irq_timer->adjust(attotime::from_usec(8407), ASSERT_LINE); + } +} + + +//------------------------------------------------- +// tpi1_selected - +//------------------------------------------------- + +bool c1551_t::tpi1_selected(offs_t offset) +{ +#ifdef PLA_DUMPED + int mux = 0, ras = 0, phi0 = 0, f7 = 0; + UINT16 input = A5 << 15 | A6 << 14 | A7 << 13 | A8 << 12 | A9 << 11 | mux << 10 | A10 << 9 | m_dev << 8 | ras << 7 | phi0 << 6 | A15 << 5 | A14 << 4 | A13 << 3 | A12 << 2 | A11 << 1 | f7; + UINT8 data = m_pla->read(input); + return BIT(data, 0) ? true : false; +#endif + + offs_t start_address = m_dev ? 0xfee0 : 0xfec0; + + if (offset >= start_address && offset < (start_address + 0x20)) + { + return true; + } + + return false; +} + + +//------------------------------------------------- +// plus4_cd_r - cartridge data read +//------------------------------------------------- + +UINT8 c1551_t::plus4_cd_r(address_space &space, offs_t offset, UINT8 data, int ba, int cs0, int c1l, int c2l, int cs1, int c1h, int c2h) +{ + data = m_exp->cd_r(space, offset, data, ba, cs0, c1l, c2l, cs1, c1h, c2h); + + if (tpi1_selected(offset)) + { + data = m_tpi1->read(space, offset & 0x07); + } + + return data; +} + + +//------------------------------------------------- +// plus4_cd_w - cartridge data write +//------------------------------------------------- + +void c1551_t::plus4_cd_w(address_space &space, offs_t offset, UINT8 data, int ba, int cs0, int c1l, int c2l, int cs1, int c1h, int c2h) +{ + if (tpi1_selected(offset)) + { + m_tpi1->write(space, offset & 0x07, data); + } + + m_exp->cd_w(space, offset, data, ba, cs0, c1l, c2l, cs1, c1h, c2h); +} diff --git a/src/devices/bus/plus4/c1551.h b/src/devices/bus/plus4/c1551.h new file mode 100644 index 00000000000..e31ec0afdd5 --- /dev/null +++ b/src/devices/bus/plus4/c1551.h @@ -0,0 +1,107 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Commodore 1551 Single Disk Drive emulation + +**********************************************************************/ + +#pragma once + +#ifndef __C1551__ +#define __C1551__ + +#include "emu.h" +#include "exp.h" +#include "cpu/m6502/m6510t.h" +#include "machine/64h156.h" +#include "machine/6525tpi.h" +#include "machine/pla.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> c1551_t + +class c1551_t : public device_t, + public device_plus4_expansion_card_interface +{ +public: + // construction/destruction + c1551_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + virtual ioport_constructor device_input_ports() const; + + DECLARE_READ8_MEMBER( port_r ); + DECLARE_WRITE8_MEMBER( port_w ); + + DECLARE_READ8_MEMBER( tcbm_data_r ); + DECLARE_WRITE8_MEMBER( tcbm_data_w ); + DECLARE_READ8_MEMBER( tpi0_r ); + DECLARE_WRITE8_MEMBER( tpi0_w ); + DECLARE_READ8_MEMBER( yb_r ); + DECLARE_WRITE8_MEMBER( yb_w ); + DECLARE_READ8_MEMBER( tpi0_pc_r ); + DECLARE_WRITE8_MEMBER( tpi0_pc_w ); + + DECLARE_READ8_MEMBER( tpi1_pa_r ); + DECLARE_WRITE8_MEMBER( tpi1_pa_w ); + DECLARE_READ8_MEMBER( tpi1_pb_r ); + DECLARE_READ8_MEMBER( tpi1_pc_r ); + DECLARE_WRITE8_MEMBER( tpi1_pc_w ); + + DECLARE_FLOPPY_FORMATS( floppy_formats ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + // device_plus4_expansion_card_interface overrides + virtual UINT8 plus4_cd_r(address_space &space, offs_t offset, UINT8 data, int ba, int cs0, int c1l, int c2l, int cs1, int c1h, int c2h); + virtual void plus4_cd_w(address_space &space, offs_t offset, UINT8 data, int ba, int cs0, int c1l, int c2l, int cs1, int c1h, int c2h); + +private: + enum + { + LED_POWER = 0, + LED_ACT + }; + + bool tpi1_selected(offs_t offset); + + required_device m_maincpu; + required_device m_tpi0; + required_device m_tpi1; + required_device m_ga; + required_device m_pla; + required_device m_floppy; + required_device m_exp; + required_ioport m_jp1; + + // TCBM bus + UINT8 m_tcbm_data; // data + int m_status; // status + int m_dav; // data valid + int m_ack; // acknowledge + int m_dev; // device number + + // timers + emu_timer *m_irq_timer; +}; + + + +// device type definition +extern const device_type C1551; + + + +#endif diff --git a/src/devices/bus/plus4/diag264_lb_user.c b/src/devices/bus/plus4/diag264_lb_user.c new file mode 100644 index 00000000000..10d93e462e6 --- /dev/null +++ b/src/devices/bus/plus4/diag264_lb_user.c @@ -0,0 +1,42 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/********************************************************************** + + Diag264 User Port Loop Back Connector emulation + +**********************************************************************/ + +#include "diag264_lb_user.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type DIAG264_USER_PORT_LOOPBACK = &device_creator; + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// diag264_user_port_loopback_device - constructor +//------------------------------------------------- + +diag264_user_port_loopback_device::diag264_user_port_loopback_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, DIAG264_USER_PORT_LOOPBACK, "Diag264 User Port Loopback", tag, owner, clock, "diag264_user_port_loopback", __FILE__), + device_pet_user_port_interface(mconfig, *this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void diag264_user_port_loopback_device::device_start() +{ +} diff --git a/src/devices/bus/plus4/diag264_lb_user.h b/src/devices/bus/plus4/diag264_lb_user.h new file mode 100644 index 00000000000..25e0766d064 --- /dev/null +++ b/src/devices/bus/plus4/diag264_lb_user.h @@ -0,0 +1,59 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/********************************************************************** + + Diag264 User Port Loop Back Connector emulation + +**********************************************************************/ + +#pragma once + +#ifndef __DIAG264_USER_PORT_LOOPBACK__ +#define __DIAG264_USER_PORT_LOOPBACK__ + +#include "emu.h" +#include "user.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> diag264_user_port_loopback_device + +class diag264_user_port_loopback_device : public device_t, + public device_pet_user_port_interface +{ +public: + // construction/destruction + diag264_user_port_loopback_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // device-level overrides + virtual void device_start(); + + // device_pet_user_port_interface overrides + virtual DECLARE_WRITE_LINE_MEMBER(input_b) { output_6(state); } + virtual DECLARE_WRITE_LINE_MEMBER(input_k) { output_7(state); } + virtual DECLARE_WRITE_LINE_MEMBER(input_4) { output_j(state); } + virtual DECLARE_WRITE_LINE_MEMBER(input_5) { output_f(state); } + + virtual DECLARE_WRITE_LINE_MEMBER(input_6) { output_b(state); } + virtual DECLARE_WRITE_LINE_MEMBER(input_7) { output_k(state); } + virtual DECLARE_WRITE_LINE_MEMBER(input_j) { output_4(state); } + virtual DECLARE_WRITE_LINE_MEMBER(input_f) { output_5(state); } + + virtual DECLARE_WRITE_LINE_MEMBER(input_c) { output_m(state); } + virtual DECLARE_WRITE_LINE_MEMBER(input_d) { output_l(state); } + virtual DECLARE_WRITE_LINE_MEMBER(input_e) { output_h(state); } + + virtual DECLARE_WRITE_LINE_MEMBER(input_m) { output_c(state); } + virtual DECLARE_WRITE_LINE_MEMBER(input_l) { output_d(state); } + virtual DECLARE_WRITE_LINE_MEMBER(input_h) { output_e(state); } +}; + +// device type definition +extern const device_type DIAG264_USER_PORT_LOOPBACK; + +#endif diff --git a/src/devices/bus/plus4/exp.c b/src/devices/bus/plus4/exp.c new file mode 100644 index 00000000000..801470cbf30 --- /dev/null +++ b/src/devices/bus/plus4/exp.c @@ -0,0 +1,209 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Commodore Plus/4 Expansion Port emulation + +**********************************************************************/ + +#include "exp.h" + + + +//************************************************************************** +// MACROS/CONSTANTS +//************************************************************************** + +#define LOG 0 + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type PLUS4_EXPANSION_SLOT = &device_creator; + + + +//************************************************************************** +// DEVICE PLUS4_EXPANSION CARD INTERFACE +//************************************************************************** + +//------------------------------------------------- +// device_plus4_expansion_card_interface - constructor +//------------------------------------------------- + +device_plus4_expansion_card_interface::device_plus4_expansion_card_interface(const machine_config &mconfig, device_t &device) + : device_slot_card_interface(mconfig, device), + m_c1l(*this, "c1l"), + m_c1h(*this, "c1h"), + m_c2l(*this, "c2l"), + m_c2h(*this, "c2h"), + m_c1l_mask(0), + m_c1h_mask(0), + m_c2l_mask(0), + m_c2h_mask(0) +{ + m_slot = dynamic_cast(device.owner()); +} + + +//------------------------------------------------- +// ~device_plus4_expansion_card_interface - destructor +//------------------------------------------------- + +device_plus4_expansion_card_interface::~device_plus4_expansion_card_interface() +{ +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// plus4_expansion_slot_device - constructor +//------------------------------------------------- + +plus4_expansion_slot_device::plus4_expansion_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, PLUS4_EXPANSION_SLOT, "Expansion Port", tag, owner, clock, "plus4_expansion_slot", __FILE__), + device_slot_interface(mconfig, *this), + device_image_interface(mconfig, *this), + m_write_irq(*this), + m_read_dma_cd(*this), + m_write_dma_cd(*this), + m_write_aec(*this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void plus4_expansion_slot_device::device_start() +{ + m_card = dynamic_cast(get_card_device()); + + // resolve callbacks + m_write_irq.resolve_safe(); + m_read_dma_cd.resolve_safe(0xff); + m_write_dma_cd.resolve_safe(); + m_write_aec.resolve_safe(); + + // inherit bus clock + if (clock() == 0) + { + plus4_expansion_slot_device *root = machine().device(PLUS4_EXPANSION_SLOT_TAG); + assert(root); + set_unscaled_clock(root->clock()); + } +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void plus4_expansion_slot_device::device_reset() +{ + if (get_card_device()) + { + get_card_device()->reset(); + } +} + + +//------------------------------------------------- +// call_load - +//------------------------------------------------- + +bool plus4_expansion_slot_device::call_load() +{ + if (m_card) + { + if (software_entry() == NULL) + { + // TODO + } + else + { + load_software_region("c1l", m_card->m_c1l); + load_software_region("c1h", m_card->m_c1h); + load_software_region("c2l", m_card->m_c2l); + load_software_region("c2h", m_card->m_c2h); + } + } + + return IMAGE_INIT_PASS; +} + + +//------------------------------------------------- +// call_softlist_load - +//------------------------------------------------- + +bool plus4_expansion_slot_device::call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry) +{ + load_software_part_region(*this, swlist, swname, start_entry); + + return true; +} + + +//------------------------------------------------- +// get_default_card_software - +//------------------------------------------------- + +void plus4_expansion_slot_device::get_default_card_software(std::string &result) +{ + software_get_default_slot(result, "standard"); +} + + +//------------------------------------------------- +// cd_r - cartridge data read +//------------------------------------------------- + +UINT8 plus4_expansion_slot_device::cd_r(address_space &space, offs_t offset, UINT8 data, int ba, int cs0, int c1l, int c2l, int cs1, int c1h, int c2h) +{ + if (m_card != NULL) + { + data = m_card->plus4_cd_r(space, offset, data, ba, cs0, c1l, c1h, cs1, c2l, c2h); + } + + return data; +} + + +//------------------------------------------------- +// cd_w - cartridge data write +//------------------------------------------------- + +void plus4_expansion_slot_device::cd_w(address_space &space, offs_t offset, UINT8 data, int ba, int cs0, int c1l, int c2l, int cs1, int c1h, int c2h) +{ + if (m_card != NULL) + { + m_card->plus4_cd_w(space, offset, data, ba, cs0, c1l, c1h, cs1, c2l, c2h); + } +} + + +//------------------------------------------------- +// SLOT_INTERFACE( plus4_expansion_cards ) +//------------------------------------------------- + +// slot devices +#include "c1551.h" +#include "sid.h" +#include "std.h" + +SLOT_INTERFACE_START( plus4_expansion_cards ) + SLOT_INTERFACE("c1551", C1551) + SLOT_INTERFACE("sid", PLUS4_SID) + + // the following need ROMs from the software list + SLOT_INTERFACE_INTERNAL("standard", PLUS4_STD) +SLOT_INTERFACE_END diff --git a/src/devices/bus/plus4/exp.h b/src/devices/bus/plus4/exp.h new file mode 100644 index 00000000000..0bd8e963cc6 --- /dev/null +++ b/src/devices/bus/plus4/exp.h @@ -0,0 +1,187 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Commodore Plus/4 Expansion Port emulation + +********************************************************************** + + GND 1 A GND + +5V 2 B C1 LOW + +5V 3 C _BRESET + _IRQ 4 D _RAS + R/_W 5 E phi0 + C1 HIGH 6 F A15 + C2 LOW 7 H A14 + C2 HIGH 8 J A13 + _CS1 9 K A12 + _CS0 10 L A11 + _CAS 11 M A10 + MUX 12 N A9 + BA 13 P A8 + D7 14 R A7 + D6 15 S A6 + D5 16 T A5 + D4 17 U A4 + D3 18 V A3 + D2 19 W A2 + D1 20 X A1 + D0 21 Y A0 + AEC 22 Z N.C. (RAMEN) + EXT AUDIO 23 AA N.C. + phi2 24 BB N.C. + GND 25 CC GND + +**********************************************************************/ + +#pragma once + +#ifndef __PLUS4_EXPANSION_SLOT__ +#define __PLUS4_EXPANSION_SLOT__ + +#include "emu.h" + + + +//************************************************************************** +// CONSTANTS +//************************************************************************** + +#define PLUS4_EXPANSION_SLOT_TAG "exp" + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_PLUS4_EXPANSION_SLOT_ADD(_tag, _clock, _slot_intf, _def_slot) \ + MCFG_DEVICE_ADD(_tag, PLUS4_EXPANSION_SLOT, _clock) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) + +#define MCFG_PLUS4_PASSTHRU_EXPANSION_SLOT_ADD() \ + MCFG_PLUS4_EXPANSION_SLOT_ADD(PLUS4_EXPANSION_SLOT_TAG, 0, plus4_expansion_cards, NULL) \ + MCFG_PLUS4_EXPANSION_SLOT_IRQ_CALLBACK(DEVWRITELINE(DEVICE_SELF_OWNER, plus4_expansion_slot_device, irq_w)) \ + MCFG_PLUS4_EXPANSION_SLOT_CD_INPUT_CALLBACK(DEVREAD8(DEVICE_SELF_OWNER, plus4_expansion_slot_device, dma_cd_r)) \ + MCFG_PLUS4_EXPANSION_SLOT_CD_OUTPUT_CALLBACK(DEVWRITE8(DEVICE_SELF_OWNER, plus4_expansion_slot_device, dma_cd_w)) \ + MCFG_PLUS4_EXPANSION_SLOT_AEC_CALLBACK(DEVWRITELINE(DEVICE_SELF_OWNER, plus4_expansion_slot_device, aec_w)) + + +#define MCFG_PLUS4_EXPANSION_SLOT_IRQ_CALLBACK(_write) \ + devcb = &plus4_expansion_slot_device::set_irq_wr_callback(*device, DEVCB_##_write); + +#define MCFG_PLUS4_EXPANSION_SLOT_CD_INPUT_CALLBACK(_read) \ + devcb = &plus4_expansion_slot_device::set_cd_rd_callback(*device, DEVCB_##_read); + +#define MCFG_PLUS4_EXPANSION_SLOT_CD_OUTPUT_CALLBACK(_write) \ + devcb = &plus4_expansion_slot_device::set_cd_wr_callback(*device, DEVCB_##_write); + +#define MCFG_PLUS4_EXPANSION_SLOT_AEC_CALLBACK(_write) \ + devcb = &plus4_expansion_slot_device::set_aec_wr_callback(*device, DEVCB_##_write); + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> plus4_expansion_slot_device + +class device_plus4_expansion_card_interface; + +class plus4_expansion_slot_device : public device_t, + public device_slot_interface, + public device_image_interface +{ +public: + // construction/destruction + plus4_expansion_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + template static devcb_base &set_irq_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_irq.set_callback(object); } + template static devcb_base &set_cd_rd_callback(device_t &device, _Object object) { return downcast(device).m_read_dma_cd.set_callback(object); } + template static devcb_base &set_cd_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_dma_cd.set_callback(object); } + template static devcb_base &set_aec_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_aec.set_callback(object); } + + // computer interface + UINT8 cd_r(address_space &space, offs_t offset, UINT8 data, int ba, int cs0, int c1l, int c2l, int cs1, int c1h, int c2h); + void cd_w(address_space &space, offs_t offset, UINT8 data, int ba, int cs0, int c1l, int c2l, int cs1, int c1h, int c2h); + + // cartridge interface + DECLARE_READ8_MEMBER( dma_cd_r ) { return m_read_dma_cd(offset); } + DECLARE_WRITE8_MEMBER( dma_cd_w ) { m_write_dma_cd(offset, data); } + DECLARE_WRITE_LINE_MEMBER( irq_w ) { m_write_irq(state); } + DECLARE_WRITE_LINE_MEMBER( aec_w ) { m_write_aec(state); } + int phi2() { return clock(); } + +protected: + // device-level overrides + virtual void device_config_complete() { update_names(); } + virtual void device_start(); + virtual void device_reset(); + + // image-level overrides + virtual bool call_load(); + virtual bool call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry); + + virtual iodevice_t image_type() const { return IO_CARTSLOT; } + + virtual bool is_readable() const { return 1; } + virtual bool is_writeable() const { return 0; } + virtual bool is_creatable() const { return 0; } + virtual bool must_be_loaded() const { return 0; } + virtual bool is_reset_on_load() const { return 1; } + virtual const char *image_interface() const { return "plus4_cart"; } + virtual const char *file_extensions() const { return "rom,bin"; } + virtual const option_guide *create_option_guide() const { return NULL; } + + // slot interface overrides + virtual void get_default_card_software(std::string &result); + + devcb_write_line m_write_irq; + devcb_read8 m_read_dma_cd; + devcb_write8 m_write_dma_cd; + devcb_write_line m_write_aec; + + device_plus4_expansion_card_interface *m_card; +}; + + +// ======================> device_plus4_expansion_card_interface + +class device_plus4_expansion_card_interface : public device_slot_card_interface +{ + friend class plus4_expansion_slot_device; + +public: + // construction/destruction + device_plus4_expansion_card_interface(const machine_config &mconfig, device_t &device); + virtual ~device_plus4_expansion_card_interface(); + + // runtime + virtual UINT8 plus4_cd_r(address_space &space, offs_t offset, UINT8 data, int ba, int cs0, int c1l, int c2l, int cs1, int c1h, int c2h) { return data; }; + virtual void plus4_cd_w(address_space &space, offs_t offset, UINT8 data, int ba, int cs0, int c1l, int c2l, int cs1, int c1h, int c2h) { }; + +protected: + optional_shared_ptr m_c1l; + optional_shared_ptr m_c1h; + optional_shared_ptr m_c2l; + optional_shared_ptr m_c2h; + + size_t m_c1l_mask; + size_t m_c1h_mask; + size_t m_c2l_mask; + size_t m_c2h_mask; + + plus4_expansion_slot_device *m_slot; +}; + + +// device type definition +extern const device_type PLUS4_EXPANSION_SLOT; + + +SLOT_INTERFACE_EXTERN( plus4_expansion_cards ); + + + +#endif diff --git a/src/devices/bus/plus4/sid.c b/src/devices/bus/plus4/sid.c new file mode 100644 index 00000000000..57515474824 --- /dev/null +++ b/src/devices/bus/plus4/sid.c @@ -0,0 +1,165 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Commodore Plus/4 SID cartridge emulation + + http://solder.dyndns.info/cgi-bin/showdir.pl?dir=files/commodore/plus4/hardware/SID-Card + +**********************************************************************/ + +/* + + TODO: + + - GAL16V8 dump + - get SID clock from expansion port + +*/ + +#include "sid.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define MOS8580_TAG "mos8580" +#define CONTROL1_TAG "joy1" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type PLUS4_SID = &device_creator; + + +//------------------------------------------------- +// ROM( plus4_sid ) +//------------------------------------------------- + +ROM_START( plus4_sid ) + ROM_REGION( 0x100, "pld", 0 ) + ROM_LOAD( "gal16v8", 0x000, 0x100, NO_DUMP ) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *plus4_sid_cartridge_device::device_rom_region() const +{ + return ROM_NAME( plus4_sid ); +} + + +//------------------------------------------------- +// MACHINE_CONFIG_FRAGMENT( plus4_sid ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( plus4_sid ) + MCFG_SPEAKER_STANDARD_MONO("mono") + MCFG_SOUND_ADD(MOS8580_TAG, MOS8580, XTAL_17_73447MHz/20) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 1.00) + MCFG_SOUND_ADD("dac", DAC, 0) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.25) + + MCFG_VCS_CONTROL_PORT_ADD(CONTROL1_TAG, vcs_control_port_devices, NULL) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor plus4_sid_cartridge_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( plus4_sid ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// plus4_sid_cartridge_device - constructor +//------------------------------------------------- + +plus4_sid_cartridge_device::plus4_sid_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, PLUS4_SID, "Plus/4 SID cartridge", tag, owner, clock, "plus4_sid", __FILE__), + device_plus4_expansion_card_interface(mconfig, *this), + m_sid(*this, MOS8580_TAG), + m_joy(*this, CONTROL1_TAG) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void plus4_sid_cartridge_device::device_start() +{ +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void plus4_sid_cartridge_device::device_reset() +{ + m_sid->reset(); +} + + +//------------------------------------------------- +// plus4_cd_r - cartridge data read +//------------------------------------------------- + +UINT8 plus4_sid_cartridge_device::plus4_cd_r(address_space &space, offs_t offset, UINT8 data, int ba, int cs0, int c1l, int c2l, int cs1, int c1h, int c2h) +{ + if ((offset >= 0xfe80 && offset < 0xfea0) || (offset >= 0xfd40 && offset < 0xfd60)) + { + data = m_sid->read(space, offset & 0x1f); + } + else if (offset >= 0xfd80 && offset < 0xfd90) + { + data = m_joy->joy_r(space, 0); + } + + return data; +} + + +//------------------------------------------------- +// plus4_cd_w - cartridge data write +//------------------------------------------------- + +void plus4_sid_cartridge_device::plus4_cd_w(address_space &space, offs_t offset, UINT8 data, int ba, int cs0, int c1l, int c2l, int cs1, int c1h, int c2h) +{ + if ((offset >= 0xfe80 && offset < 0xfea0) || (offset >= 0xfd40 && offset < 0xfd60)) + { + m_sid->write(space, offset & 0x1f, data); + } +} + + +//------------------------------------------------- +// plus4_breset_w - buffered reset write +//------------------------------------------------- + +void plus4_sid_cartridge_device::plus4_breset_w(int state) +{ + if (state == ASSERT_LINE) + { + device_reset(); + } +} diff --git a/src/devices/bus/plus4/sid.h b/src/devices/bus/plus4/sid.h new file mode 100644 index 00000000000..63a7040416f --- /dev/null +++ b/src/devices/bus/plus4/sid.h @@ -0,0 +1,59 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Commodore Plus/4 SID cartridge emulation + +**********************************************************************/ + +#pragma once + +#ifndef __PLUS4_SID_CARTRIDGE__ +#define __PLUS4_SID_CARTRIDGE__ + +#include "emu.h" +#include "exp.h" +#include "bus/vcs_ctrl/ctrl.h" +#include "sound/dac.h" +#include "sound/mos6581.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> plus4_sid_cartridge_device + +class plus4_sid_cartridge_device : public device_t, + public device_plus4_expansion_card_interface +{ +public: + // construction/destruction + plus4_sid_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_plus4_expansion_card_interface overrides + virtual UINT8 plus4_cd_r(address_space &space, offs_t offset, UINT8 data, int ba, int cs0, int c1l, int c2l, int cs1, int c1h, int c2h); + virtual void plus4_cd_w(address_space &space, offs_t offset, UINT8 data, int ba, int cs0, int c1l, int c2l, int cs1, int c1h, int c2h); + virtual void plus4_breset_w(int state); + +private: + required_device m_sid; + required_device m_joy; +}; + + +// device type definition +extern const device_type PLUS4_SID; + + +#endif diff --git a/src/devices/bus/plus4/std.c b/src/devices/bus/plus4/std.c new file mode 100644 index 00000000000..8627f99cc30 --- /dev/null +++ b/src/devices/bus/plus4/std.c @@ -0,0 +1,69 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Commodore Plus/4 standard cartridge emulation + +**********************************************************************/ + +#include "std.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type PLUS4_STD = &device_creator; + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// plus4_standard_cartridge_device - constructor +//------------------------------------------------- + +plus4_standard_cartridge_device::plus4_standard_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, PLUS4_STD, "Plus/4 standard cartridge", tag, owner, clock, "plus4_standard", __FILE__), + device_plus4_expansion_card_interface(mconfig, *this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void plus4_standard_cartridge_device::device_start() +{ +} + + +//------------------------------------------------- +// plus4_cd_r - cartridge data read +//------------------------------------------------- + +UINT8 plus4_standard_cartridge_device::plus4_cd_r(address_space &space, offs_t offset, UINT8 data, int ba, int cs0, int c1l, int c2l, int cs1, int c1h, int c2h) +{ + if (!c1l && m_c1l.bytes()) + { + data = m_c1l[offset & m_c1l.mask()]; + } + else if (!c1h && m_c1h.bytes()) + { + data = m_c1h[offset & m_c1h.mask()]; + } + else if (!c2l && m_c2l.bytes()) + { + data = m_c2l[offset & m_c2l.mask()]; + } + else if (!c2h && m_c2h.bytes()) + { + data = m_c2h[offset & m_c2h.mask()]; + } + + return data; +} diff --git a/src/devices/bus/plus4/std.h b/src/devices/bus/plus4/std.h new file mode 100644 index 00000000000..3949240b037 --- /dev/null +++ b/src/devices/bus/plus4/std.h @@ -0,0 +1,47 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Commodore Plus/4 standard cartridge emulation + +**********************************************************************/ + +#pragma once + +#ifndef __PLUS4_STANDARD_CARTRIDGE__ +#define __PLUS4_STANDARD_CARTRIDGE__ + +#include "emu.h" +#include "exp.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> plus4_standard_cartridge_device + +class plus4_standard_cartridge_device : public device_t, + public device_plus4_expansion_card_interface +{ +public: + // construction/destruction + plus4_standard_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // device-level overrides + virtual void device_start(); + + // device_plus4_expansion_card_interface overrides + virtual UINT8 plus4_cd_r(address_space &space, offs_t offset, UINT8 data, int ba, int cs0, int c1l, int c2l, int cs1, int c1h, int c2h); + + +}; + + +// device type definition +extern const device_type PLUS4_STD; + + +#endif diff --git a/src/devices/bus/plus4/user.c b/src/devices/bus/plus4/user.c new file mode 100644 index 00000000000..7c9c6ed24b5 --- /dev/null +++ b/src/devices/bus/plus4/user.c @@ -0,0 +1,22 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/********************************************************************** + + Commodore Plus/4 User Port emulation + +**********************************************************************/ + +#include "user.h" + +//------------------------------------------------- +// SLOT_INTERFACE( plus4_user_port_cards ) +//------------------------------------------------- + +// slot devices +#include "diag264_lb_user.h" +#include "bus/vic20/vic1011.h" + +SLOT_INTERFACE_START( plus4_user_port_cards ) + SLOT_INTERFACE("diag264", DIAG264_USER_PORT_LOOPBACK) + SLOT_INTERFACE("rs232", VIC1011) +SLOT_INTERFACE_END diff --git a/src/devices/bus/plus4/user.h b/src/devices/bus/plus4/user.h new file mode 100644 index 00000000000..abf4a909ccb --- /dev/null +++ b/src/devices/bus/plus4/user.h @@ -0,0 +1,33 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/********************************************************************** + + Commodore Plus/4 User Port emulation + +********************************************************************** + + GND 1 A GND + +5V 2 B P0 + _BRESET 3 C RxD + P2 4 D RTS + P3 5 E DTR + P4 6 F P7 + P5 7 H DCD + RxC 8 J P6 + ATN 9 K P1 + +9VAC 10 L DSR + +9VAC 11 M TxD + GND 12 N GND + +**********************************************************************/ + +#pragma once + +#ifndef __PLUS4_USER_PORT__ +#define __PLUS4_USER_PORT__ + +#include "bus/vic20/user.h" + +SLOT_INTERFACE_EXTERN( plus4_user_port_cards ); + +#endif diff --git a/src/devices/bus/psx/analogue.c b/src/devices/bus/psx/analogue.c new file mode 100644 index 00000000000..f9896dcd2e5 --- /dev/null +++ b/src/devices/bus/psx/analogue.c @@ -0,0 +1,264 @@ +// license:BSD-3-Clause +// copyright-holders:Carl +#include "analogue.h" + +const device_type PSX_ANALOG_JOYSTICK = &device_creator; +const device_type PSX_DUALSHOCK = &device_creator; + +psx_analog_controller_device::psx_analog_controller_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_psx_controller_interface(mconfig, *this), + m_pad0(*this, "PSXPAD0"), + m_pad1(*this, "PSXPAD1"), + m_rstickx(*this, "PSXRSTICKX"), + m_rsticky(*this, "PSXRSTICKY"), + m_lstickx(*this, "PSXLSTICKX"), + m_lsticky(*this, "PSXLSTICKY") +{ +} + +psx_dualshock_device::psx_dualshock_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + psx_analog_controller_device(mconfig, PSX_DUALSHOCK, "Playstation Dualshock Pad", tag, owner, clock, "psx_dualshock_pad", __FILE__) +{ + m_type = DUALSHOCK; +} + +psx_analog_joystick_device::psx_analog_joystick_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + psx_analog_controller_device(mconfig, PSX_ANALOG_JOYSTICK, "Playstation Analog Joystick", tag, owner, clock, "psx_analog_joystick", __FILE__) +{ + m_type = JOYSTICK; +} + +void psx_analog_controller_device::device_reset() +{ + m_confmode = false; + m_analogmode = false; + m_analoglock = false; + + m_cmd = 0; +} + +UINT8 psx_analog_controller_device::pad_data(int count, bool analog) +{ + UINT8 data = 0; + switch(count) + { + case 2: + data = m_pad0->read(); + if(!analog || (m_type == JOYSTICK)) + data |= 6; // l3/r3 + break; + case 3: + data = m_pad1->read(); + break; + case 4: + data = m_rstickx->read(); + break; + case 5: + data = m_rsticky->read(); + break; + case 6: + data = m_lstickx->read(); + break; + case 7: + data = m_lsticky->read(); + break; + } + return data; +} + +bool psx_analog_controller_device::get_pad(int count, UINT8 *odata, UINT8 idata) +{ + if(m_confmode) + { + switch(count) + { + case 0: + m_temp = 0; + *odata = 0xf3; + break; + case 1: + m_cmd = idata; + if((m_cmd & 0xf0) != 0x40) + return false; + *odata = 0x5a; + break; + default: + switch(m_cmd) + { + default: // 40,41,48,49,4a,4b,4f -- all unknown + *odata = 0x00; + break; + case CONFIG_MODE: // 43 + if(count == 3) + m_temp = idata; + /* no break */ + case QUERY_PAD_STATE: // 42 + *odata = pad_data(count, true); + break; + case 0x44: // set mode and lock ? + switch(count) + { + case 3: + m_analogmode = idata ? true : false; // only 0x01 ? + break; + case 4: + m_analoglock = idata ? true : false; // only 0x03 ? + break; + } + *odata = 0x00; + break; + case 0x45: // get mode ? + { + const UINT8 val[] = { 1, 2, 0, 2, 1, 0 }; + if(count == 4) + *odata = m_analogmode; + else + *odata = val[count-2]; + break; + } + case 0x46: // query act (vibrate) ? + { + const UINT8 val[2][6] = {{ 0, 0, 1, 2, 0, 10 }, + { 0, 0, 1, 1, 1, 14 }}; + *odata = val[m_temp][count-2]; + if(count == 3) + m_temp = idata ? 1 : 0; + break; + } + case 0x47: // query comb (combination?) ? + { + const UINT8 val[] = { 0, 0, 2, 0, 1, 0 }; + *odata = val[count-2]; + break; + } + case 0x4c: // query mode ? + switch(count) + { + case 3: + m_temp = idata; + /* no break */ + default: + *odata = 0x00; + break; + case 5: + *odata = m_analogmode ? 0x07 : 0x04; // ? + break; + } + break; + case 0x4d: // set act (vibrate) ? + *odata = 0xff; + break; + } + break; + case 8: + if(m_cmd == CONFIG_MODE) + m_confmode = m_temp; + return false; + } + } + else if(m_analogmode) + { + switch(count) + { + case 0: + if(m_type == JOYSTICK) + *odata = 0x53; + else + *odata = 0x73; + break; + case 1: + m_cmd = idata; + if((m_cmd & 0xfe) != QUERY_PAD_STATE) + return false; + *odata = 0x5a; + break; + case 3: + if(m_cmd == CONFIG_MODE) + m_temp = idata; + /* no break */ + default: + *odata = pad_data(count, true); + break; + case 8: + if(m_cmd == CONFIG_MODE) + m_confmode = m_temp; + return false; + } + } + else + { + switch(count) + { + case 0: + *odata = 0x41; + break; + case 1: + m_cmd = idata; + if((m_cmd & 0xfe) != QUERY_PAD_STATE) + return false; + *odata = 0x5a; + break; + case 3: + if(m_cmd == CONFIG_MODE) + m_temp = idata; + /* no break */ + default: + *odata = pad_data(count, false); + break; + case 4: + if(m_cmd == CONFIG_MODE) + m_confmode = m_temp; + return false; + } + } + return true; +} + +static INPUT_PORTS_START( psx_analog_controller ) + PORT_START("PSXPAD0") + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_START ) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_BUTTON9 ) PORT_NAME("R3") + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_BUTTON10 ) PORT_NAME("L3") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_SELECT ) + + PORT_START("PSXPAD1") + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_NAME("Square") + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_NAME("Cross") + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_NAME("Circle") + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_NAME("Triangle") + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_BUTTON5 ) PORT_NAME("R1") + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_BUTTON6 ) PORT_NAME("L1") + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_BUTTON7 ) PORT_NAME("R2") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_BUTTON8 ) PORT_NAME("L2") + + PORT_START("PSXRSTICKX") + PORT_BIT( 0xff, 0x80, IPT_AD_STICK_X ) PORT_NAME("Right Analog X") PORT_SENSITIVITY(100) + + PORT_START("PSXRSTICKY") + PORT_BIT( 0xff, 0x80, IPT_AD_STICK_Y ) PORT_NAME("Right Analog Y") PORT_SENSITIVITY(100) + + PORT_START("PSXLSTICKX") + PORT_BIT( 0xff, 0x80, IPT_AD_STICK_Z ) PORT_NAME("Left Analog X") PORT_SENSITIVITY(100) + + PORT_START("PSXLSTICKY") + PORT_BIT( 0xff, 0x80, IPT_PADDLE ) PORT_NAME("Left Analog Y") PORT_SENSITIVITY(100) + + PORT_START("PSXMISC") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_BUTTON11 ) PORT_NAME("Analog") PORT_TOGGLE PORT_CHANGED_MEMBER(DEVICE_SELF, psx_analog_controller_device, change_mode, 0) +INPUT_PORTS_END + +ioport_constructor psx_analog_controller_device::device_input_ports() const +{ + return INPUT_PORTS_NAME(psx_analog_controller); +} + +INPUT_CHANGED_MEMBER(psx_analog_controller_device::change_mode) +{ + if(!m_analoglock) + m_analogmode = newval; +} diff --git a/src/devices/bus/psx/analogue.h b/src/devices/bus/psx/analogue.h new file mode 100644 index 00000000000..dad5490f944 --- /dev/null +++ b/src/devices/bus/psx/analogue.h @@ -0,0 +1,57 @@ +// license:BSD-3-Clause +// copyright-holders:Carl +#ifndef PSXANALOG_H_ +#define PSXANALOG_H_ + +#include "ctlrport.h" + +extern const device_type PSX_DUALSHOCK; +extern const device_type PSX_ANALOG_JOYSTICK; + +class psx_analog_controller_device : public device_t, + public device_psx_controller_interface +{ +public: + psx_analog_controller_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + virtual ioport_constructor device_input_ports() const; + DECLARE_INPUT_CHANGED_MEMBER(change_mode); +protected: + virtual void device_reset(); + virtual void device_start() {} + enum { + JOYSTICK, + DUALSHOCK + } m_type; +private: + virtual bool get_pad(int count, UINT8 *odata, UINT8 idata); + UINT8 pad_data(int count, bool analog); + + bool m_confmode; + bool m_analogmode; + bool m_analoglock; + + UINT8 m_temp; + UINT8 m_cmd; + + required_ioport m_pad0; + required_ioport m_pad1; + required_ioport m_rstickx; + required_ioport m_rsticky; + required_ioport m_lstickx; + required_ioport m_lsticky; +}; + +class psx_dualshock_device : public psx_analog_controller_device +{ +public: + psx_dualshock_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class psx_analog_joystick_device : public psx_analog_controller_device +{ +public: + psx_analog_joystick_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +#endif /* PSXANALOG_H_ */ diff --git a/src/devices/bus/psx/ctlrport.c b/src/devices/bus/psx/ctlrport.c new file mode 100644 index 00000000000..09099cb5481 --- /dev/null +++ b/src/devices/bus/psx/ctlrport.c @@ -0,0 +1,231 @@ +// license:BSD-3-Clause +// copyright-holders:Carl +/* PAD emulation */ + +#include "ctlrport.h" +#include "analogue.h" +#include "multitap.h" + +const device_type PSX_CONTROLLER_PORT = &device_creator; + +psx_controller_port_device::psx_controller_port_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, PSX_CONTROLLER_PORT, "Playstation Controller Port", tag, owner, clock, "psx_controller_port", __FILE__), + device_slot_interface(mconfig, *this), + m_card(*this, "card") +{ +} + +void psx_controller_port_device::device_config_complete() +{ + m_dev = dynamic_cast(get_card_device()); +} + +static MACHINE_CONFIG_FRAGMENT( psx_memory_card ) + MCFG_PSXCARD_ADD("card") +MACHINE_CONFIG_END + +machine_config_constructor psx_controller_port_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( psx_memory_card ); +} + +void psx_controller_port_device::disable_card(bool state) +{ + if(state) + popmessage("Memory card port %s is disabled\n", m_card->brief_instance_name()); + + m_card->disable(state); +} + +const device_type PSXCONTROLLERPORTS = &device_creator; + +psxcontrollerports_device::psxcontrollerports_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, PSXCONTROLLERPORTS, "PSXCONTROLLERPORTS", tag, owner, clock, "psxcontrollerports", __FILE__), + m_dsr_handler(*this), + m_rxd_handler(*this) +{ +} + +void psxcontrollerports_device::device_start() +{ + m_dsr_handler.resolve_safe(); + m_rxd_handler.resolve_safe(); + + m_port0 = machine().device("port1"); + m_port1 = machine().device("port2"); + m_port0->setup_ack_cb(psx_controller_port_device::void_cb(FUNC(psxcontrollerports_device::ack), this)); + m_port1->setup_ack_cb(psx_controller_port_device::void_cb(FUNC(psxcontrollerports_device::ack), this)); +} + +// add controllers to define so they can be connected to the multitap +#define PSX_CONTROLLERS \ + SLOT_INTERFACE("digital_pad", PSX_STANDARD_CONTROLLER) \ + SLOT_INTERFACE("dualshock_pad", PSX_DUALSHOCK) \ + SLOT_INTERFACE("analog_joystick", PSX_ANALOG_JOYSTICK) + +SLOT_INTERFACE_START(psx_controllers) + PSX_CONTROLLERS + SLOT_INTERFACE("multitap", PSX_MULTITAP) +SLOT_INTERFACE_END + +SLOT_INTERFACE_START(psx_controllers_nomulti) + PSX_CONTROLLERS +SLOT_INTERFACE_END + +WRITE_LINE_MEMBER(psxcontrollerports_device::write_dtr) +{ + m_port0->sel_w(!state); + m_port1->sel_w(state); +} + +WRITE_LINE_MEMBER(psxcontrollerports_device::write_sck) +{ + m_port0->clock_w(state); + m_port1->clock_w(state); + m_rxd_handler(m_port0->rx_r() && m_port1->rx_r()); +} + +WRITE_LINE_MEMBER(psxcontrollerports_device::write_txd) +{ + m_port0->tx_w(state); + m_port1->tx_w(state); +} + +void psxcontrollerports_device::ack() +{ + m_dsr_handler(m_port0->ack_r() && m_port1->ack_r()); +} + +device_psx_controller_interface::device_psx_controller_interface(const machine_config &mconfig, device_t &device) : + device_slot_card_interface(mconfig, device), + m_ack(true) +{ +} + +device_psx_controller_interface::~device_psx_controller_interface() +{ +} + +void device_psx_controller_interface::interface_pre_reset() +{ + m_bit = 0; + m_count = 0; + m_idata = 0; + m_memcard = false; + + m_clock = true; + m_sel = true; + m_rx = true; + m_ack = true; + m_owner->ack(); +} + +void device_psx_controller_interface::interface_pre_start() +{ + m_owner = dynamic_cast(device().owner()); + m_ack_timer = device().machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(device_psx_controller_interface::ack_timer), this)); +} + +void device_psx_controller_interface::ack_timer(void *ptr, int param) +{ + m_ack = param; + m_owner->ack(); + + if(!param) + m_ack_timer->adjust(attotime::from_usec(2), 1); +} + +void device_psx_controller_interface::do_pad() +{ + if(!m_bit) + { + if(!m_count) + m_odata = 0xff; + m_idata = 0; + } + + m_rx = (m_odata & (1 << m_bit)) ? true : false; + m_idata |= (m_owner->tx_r()?1:0) << m_bit; + m_bit = (m_bit + 1) % 8; + + if(!m_bit) + { + if((!m_count) && (m_idata & 0xf0)) + { + m_memcard = true; + return; + } + + if(get_pad(m_count++, &m_odata, m_idata)) + m_ack_timer->adjust(attotime::from_usec(10), 0); + else + m_count = 0; + } +} + +void device_psx_controller_interface::sel_w(bool state) { + if(state && !m_sel) + interface_pre_reset(); // don't reset the controller, just the interface + m_sel = state; +} + +const device_type PSX_STANDARD_CONTROLLER = &device_creator; + +psx_standard_controller_device::psx_standard_controller_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, PSX_STANDARD_CONTROLLER, "Playstation Standard Controller", tag, owner, clock, "psx_standard_controller", __FILE__), + device_psx_controller_interface(mconfig, *this), + m_pad0(*this,"PSXPAD0"), + m_pad1(*this,"PSXPAD1") +{ +} + +bool psx_standard_controller_device::get_pad(int count, UINT8 *odata, UINT8 idata) +{ + switch(count) + { + case 0: + *odata = 0x41; + break; + case 1: + if(idata != QUERY_PAD_STATE) + return false; + *odata = 0x5a; + break; + case 2: + *odata = m_pad0->read(); + break; + case 3: + *odata = m_pad1->read(); + break; + case 4: + return false; + } + return true; +} + +static INPUT_PORTS_START( psx_standard_controller ) + PORT_START("PSXPAD0") + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_START ) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_UNUSED ) + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_SELECT ) + + PORT_START("PSXPAD1") + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_NAME("Square") + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_NAME("Cross") + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_NAME("Circle") + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_NAME("Triangle") + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_BUTTON5 ) PORT_NAME("R1") + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_BUTTON6 ) PORT_NAME("L1") + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_BUTTON7 ) PORT_NAME("R2") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_BUTTON8 ) PORT_NAME("L2") +INPUT_PORTS_END + +ioport_constructor psx_standard_controller_device::device_input_ports() const +{ + return INPUT_PORTS_NAME(psx_standard_controller); +} diff --git a/src/devices/bus/psx/ctlrport.h b/src/devices/bus/psx/ctlrport.h new file mode 100644 index 00000000000..2e7a35d2d9d --- /dev/null +++ b/src/devices/bus/psx/ctlrport.h @@ -0,0 +1,145 @@ +// license:BSD-3-Clause +// copyright-holders:Carl +#pragma once + +#ifndef __PSXCPORT_H__ +#define __PSXCPORT_H__ + +#include "memcard.h" + +#define MCFG_PSX_CTRL_PORT_ADD(_tag, _slot_intf, _def_slot) \ + MCFG_DEVICE_ADD(_tag, PSX_CONTROLLER_PORT, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) + +SLOT_INTERFACE_EXTERN(psx_controllers); + +extern const device_type PSXCONTROLLERPORTS; +extern const device_type PSX_CONTROLLER_PORT; +extern const device_type PSX_STANDARD_CONTROLLER; + +class psx_controller_port_device; + +class device_psx_controller_interface : public device_slot_card_interface +{ + friend class psx_multitap_device; +public: + device_psx_controller_interface(const machine_config &mconfig, device_t &device); + virtual ~device_psx_controller_interface(); + + void clock_w(bool state) { if(!m_clock && !m_sel && state && !m_memcard) do_pad(); m_clock = state; } + void sel_w(bool state); + + bool rx_r() { return m_rx; } + bool ack_r() { return m_ack; } + +protected: + virtual void interface_pre_reset(); + virtual void interface_pre_start(); + + enum + { + QUERY_PAD_STATE = 0x42, + CONFIG_MODE = 0x43 + }; + +private: + virtual bool get_pad(int count, UINT8 *odata, UINT8 idata) = 0; + virtual void do_pad(); + void ack_timer(void *ptr, int param); + + UINT8 m_odata; + UINT8 m_idata; + int m_bit; + int m_count; + bool m_memcard; + + bool m_clock; + bool m_sel; + bool m_ack; + bool m_rx; + + emu_timer *m_ack_timer; + psx_controller_port_device *m_owner; +}; + +class psx_standard_controller_device : public device_t, + public device_psx_controller_interface +{ +public: + psx_standard_controller_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual ioport_constructor device_input_ports() const; + +protected: + virtual void device_start() { } +private: + virtual bool get_pad(int count, UINT8 *odata, UINT8 idata); + + required_ioport m_pad0; + required_ioport m_pad1; +}; + +#define MCFG_PSX_CONTROLLER_PORTS_DSR_HANDLER(_devcb) \ + devcb = &psxcontrollerports_device::set_dsr_handler(*device, DEVCB_##_devcb); + +#define MCFG_PSX_CONTROLLER_PORTS_RXD_HANDLER(_devcb) \ + devcb = &psxcontrollerports_device::set_rxd_handler(*device, DEVCB_##_devcb); + +class psxcontrollerports_device : public device_t +{ +public: + psxcontrollerports_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + void ack(); + + template static devcb_base &set_dsr_handler(device_t &device, _Object object) { return downcast(device).m_dsr_handler.set_callback(object); } + template static devcb_base &set_rxd_handler(device_t &device, _Object object) { return downcast(device).m_rxd_handler.set_callback(object); } + + DECLARE_WRITE_LINE_MEMBER(write_sck); + DECLARE_WRITE_LINE_MEMBER(write_dtr); + DECLARE_WRITE_LINE_MEMBER(write_txd); + +protected: + virtual void device_start(); + +private: + psx_controller_port_device *m_port0; + psx_controller_port_device *m_port1; + + devcb_write_line m_dsr_handler; + devcb_write_line m_rxd_handler; +}; + +class psx_controller_port_device : public device_t, + public device_slot_interface +{ +public: + psx_controller_port_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual machine_config_constructor device_mconfig_additions() const; + + typedef delegate void_cb; + void ack() { if(!ack_cb.isnull()) ack_cb(); } + void setup_ack_cb(void_cb cb) { ack_cb = cb; } + + DECLARE_WRITE_LINE_MEMBER(tx_w) { m_tx = state; } + DECLARE_WRITE_LINE_MEMBER(sel_w) { if(m_dev) m_dev->sel_w(state); m_card->sel_w(state); } + DECLARE_WRITE_LINE_MEMBER(clock_w) { if(m_dev) m_dev->clock_w(state); m_card->clock_w(state); } + + DECLARE_READ_LINE_MEMBER(rx_r) { return (m_dev?m_dev->rx_r():true) && m_card->rx_r(); } + DECLARE_READ_LINE_MEMBER(ack_r) { return (m_dev?m_dev->ack_r():true) && m_card->ack_r(); } + DECLARE_READ_LINE_MEMBER(tx_r) { return m_tx; } + + void disable_card(bool status); + +protected: + virtual void device_start() {} + virtual void device_reset() { m_tx = true; } + virtual void device_config_complete(); + +private: + void_cb ack_cb; + bool m_tx; + + device_psx_controller_interface *m_dev; + required_device m_card; +}; +#endif diff --git a/src/devices/bus/psx/memcard.c b/src/devices/bus/psx/memcard.c new file mode 100644 index 00000000000..c0461a3efac --- /dev/null +++ b/src/devices/bus/psx/memcard.c @@ -0,0 +1,365 @@ +// license:BSD-3-Clause +// copyright-holders:Carl,psxAuthor,R. Belmont +/* + psxcard.c - Sony PlayStation memory card device + + by pSXAuthor + MESS conversion by R. Belmont +*/ + +#include "emu.h" +#include "memcard.h" +#include "ctlrport.h" + +// +// +// + +//#define debug_card + +// +// +// + +static const int block_size = 128; +static const int card_size = block_size * 1024; + +const device_type PSXCARD = &device_creator; + +enum transfer_states +{ + state_illegal=0, + state_command, + state_cmdack, + state_wait, + state_addr_hi, + state_addr_lo, + state_read, + state_write, + state_writeack_2, + state_writechk, + state_end +}; + +psxcard_device::psxcard_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, PSXCARD, "Sony PSX Memory Card", tag, owner, clock, "psxcard", __FILE__), + device_image_interface(mconfig, *this) +{ +} + +void psxcard_device::device_start() +{ + m_owner = dynamic_cast(owner()); + m_ack_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(psxcard_device::ack_timer), this)); + + m_ack = true; + m_disabled = false; + + // save state registrations + save_item(NAME(pkt)); + save_item(NAME(pkt_ptr)); + save_item(NAME(pkt_sz)); + save_item(NAME(cmd)); + save_item(NAME(addr)); + save_item(NAME(state)); + save_item(NAME(m_disabled)); + save_item(NAME(m_odata)); + save_item(NAME(m_idata)); + save_item(NAME(m_bit)); + save_item(NAME(m_count)); + save_item(NAME(m_pad)); +} + +void psxcard_device::device_reset() +{ + state = state_illegal; + addr = 0; + + m_bit = 0; + m_count = 0; + m_pad = false; + m_idata = 0; + + m_clock = true; + m_sel = true; + m_rx = true; + m_ack = true; + m_owner->ack(); +} + +void psxcard_device::device_config_complete() +{ + update_names(PSXCARD, "memcard", "mc"); +} + +// +// +// + +bool psxcard_device::transfer(UINT8 to, UINT8 *from) +{ + bool ret=true; + + switch (state) + { + case state_illegal: + if (is_loaded()) + { +// printf("CARD: begin\n"); + state = state_command; + *from = 0x00; + } + else + { + ret = false; + } + break; + + case state_command: + cmd=to; + *from=0x5a; + state=state_cmdack; + break; + + case state_cmdack: + *from=0x5d; + state=state_wait; + break; + + case state_wait: + *from=0x00; + state=state_addr_hi; + break; + + case state_addr_hi: + addr=(to<<8); +// printf("addr_hi: %02x, addr = %x\n", to, addr); + *from=to; + state=state_addr_lo; + break; + + case state_addr_lo: + addr|=(to&0xff); +// printf("addr_lo: %02x, addr = %x, cmd = %x\n", to, addr, cmd); + + switch (cmd) + { + case 'R': // 0x52 + { + pkt[0]=*from=0x5c; + pkt[1]=0x5d; + pkt[2]=(addr>>8); + pkt[3]=(addr&0xff); + read_card(addr,&pkt[4]); + pkt[4+128]=checksum_data(&pkt[2],128+2); + pkt[5+128]=0x47; + pkt_sz=6+128; + pkt_ptr=1; + state=state_read; + break; + } + case 'W': // 0x57 + { + pkt[0]=addr>>8; + pkt[1]=addr&0xff; + pkt_sz=129+2; + pkt_ptr=2; + state=state_write; + *from=to; + break; + } + default: + state=state_illegal; + break; + } + break; + + case state_read: + //assert(to==0); +// printf("state_read: pkt_ptr = %d, pkt_sz = %d\n", pkt_ptr, pkt_sz); + *from=pkt[pkt_ptr++]; + if (pkt_ptr==pkt_sz) + { + #ifdef debug_card + printf("card: read finished\n"); + #endif + + state=state_end; + } + break; + + case state_write: + *from=to; + pkt[pkt_ptr++]=to; + if (pkt_ptr==pkt_sz) + { + *from=0x5c; + state=state_writeack_2; + } + break; + + case state_writeack_2: + *from=0x5d; + state=state_writechk; + break; + + case state_writechk: + { + unsigned char chk=checksum_data(pkt,128+2); + if (chk==pkt[128+2]) + { + #ifdef debug_card + printf("card: write ok\n"); + #endif + + write_card(addr,pkt+2); + + *from='G'; + } else + { + #ifdef debug_card + printf("card: write fail\n"); + #endif + + *from='N'; + } + state=state_end; + break; + } + + case state_end: + ret = false; + state = state_illegal; + break; + + default: /*assert(0);*/ ret=false; break; + } + + #ifdef debug_card +// printf("card: transfer to=%02x from=%02x ret=%c\n",to,*from,ret ? 'T' : 'F'); + #endif + + return ret; +} + +void psxcard_device::read_card(const unsigned short addr, unsigned char *buf) +{ + #ifdef debug_card + printf("card: read block %d\n",addr); + #endif + + if (addr<(card_size/block_size)) + { + fseek(addr*block_size, SEEK_SET); + fread(buf, block_size); + } else + { + memset(buf,0,block_size); + } +} + +// +// +// + +void psxcard_device::write_card(const unsigned short addr, unsigned char *buf) +{ + #ifdef debug_card + printf("card: write block %d\n",addr); + #endif + + if (addr<(card_size/block_size)) + { + fseek(addr*block_size, SEEK_SET); + fwrite(buf, block_size); + } +} + +unsigned char psxcard_device::checksum_data(const unsigned char *buf, const unsigned int sz) +{ + unsigned char chk=*buf++; + int left=sz; + while (--left) chk^=*buf++; + return chk; +} + +bool psxcard_device::call_load() +{ + if(m_disabled) + { + logerror("psxcard: port disabled\n"); + return IMAGE_INIT_FAIL; + } + + if(length() != card_size) + return IMAGE_INIT_FAIL; + return IMAGE_INIT_PASS; +} + +bool psxcard_device::call_create(int format_type, option_resolution *format_options) +{ + UINT8 block[block_size]; + int i, ret; + + if(m_disabled) + { + logerror("psxcard: port disabled\n"); + return IMAGE_INIT_FAIL; + } + + memset(block, '\0', block_size); + for(i = 0; i < (card_size/block_size); i++) + { + ret = fwrite(block, block_size); + if(ret != block_size) + return IMAGE_INIT_FAIL; + } + return IMAGE_INIT_PASS; +} + +void psxcard_device::do_card() +{ + if(!m_bit) + { + m_idata = 0; + if(!m_count) + m_odata = 0xff; + } + + m_rx = (m_odata & (1 << m_bit)) ? true : false; + m_idata |= (m_owner->tx_r()?1:0) << m_bit; + m_bit = (m_bit + 1) % 8; + + if(!m_bit) + { + if((!m_count) && !(m_idata & 0x80)) + { + m_pad = true; + return; + } + + if(transfer(m_idata, &m_odata)) + { + m_count++; + m_ack_timer->adjust(attotime::from_usec(10), 0); + } + else + m_count = 0; + } +} + +void psxcard_device::ack_timer(void *ptr, int param) +{ + m_ack = param; + m_owner->ack(); + + if(!param) + m_ack_timer->adjust(attotime::from_usec(2), 1); +} + +void psxcard_device::sel_w(bool state) +{ + if(state && !m_sel) + reset(); + m_sel = state; +} diff --git a/src/devices/bus/psx/memcard.h b/src/devices/bus/psx/memcard.h new file mode 100644 index 00000000000..85b8d2fa4fd --- /dev/null +++ b/src/devices/bus/psx/memcard.h @@ -0,0 +1,77 @@ +// license:BSD-3-Clause +// copyright-holders:Carl,psxAuthor,R. Belmont +#pragma once + +#ifndef _PSXCARD_ +#define _PSXCARD_ + +#include "emu.h" + +class psx_controller_port_device; + +#define MCFG_PSXCARD_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, PSXCARD, 0) + +class psxcard_device : public device_t, + public device_image_interface +{ +public: + psxcard_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual iodevice_t image_type() const { return IO_MEMCARD; } + + virtual bool is_readable() const { return 1; } + virtual bool is_writeable() const { return 1; } + virtual bool is_creatable() const { return 1; } + virtual bool must_be_loaded() const { return 0; } + virtual bool is_reset_on_load() const { return 0; } + virtual const char *file_extensions() const { return "mc"; } + virtual const option_guide *create_option_guide() const { return NULL; } + + virtual bool call_load(); + virtual bool call_create(int format_type, option_resolution *format_options); + + void disable(bool state) { m_disabled = state; if(state) unload(); } + +private: + unsigned char pkt[0x8b], pkt_ptr, pkt_sz, cmd; + unsigned short addr; + int state; + bool m_disabled; + + UINT8 m_odata; + UINT8 m_idata; + int m_bit; + int m_count; + bool m_pad; + + bool m_clock; + bool m_sel; + bool m_ack; + bool m_rx; + + emu_timer *m_ack_timer; + psx_controller_port_device *m_owner; + + void read_card(const unsigned short addr, unsigned char *buf); + void write_card(const unsigned short addr, unsigned char *buf); + unsigned char checksum_data(const unsigned char *buf, const unsigned int sz); + void do_card(); + bool transfer(UINT8 to, UINT8 *from); + void ack_timer(void *ptr, int param); + +public: + virtual void device_start(); + virtual void device_reset(); + virtual void device_config_complete(); + + void clock_w(bool state) { if(!m_clock && !m_sel && state && !m_pad) do_card(); m_clock = state; } + void sel_w(bool state); + bool rx_r() { return m_rx; } + bool ack_r() { return m_ack; } +}; + +// device type definition +extern const device_type PSXCARD; + +#endif diff --git a/src/devices/bus/psx/multitap.c b/src/devices/bus/psx/multitap.c new file mode 100644 index 00000000000..67a794b1f58 --- /dev/null +++ b/src/devices/bus/psx/multitap.c @@ -0,0 +1,275 @@ +// license:BSD-3-Clause +// copyright-holders:Carl +// psx multitap emulation + +#include "multitap.h" + +const device_type PSX_MULTITAP = &device_creator; + +psx_multitap_device::psx_multitap_device(const machine_config& mconfig, const char* tag, device_t* owner, UINT32 clock) : + device_t(mconfig, PSX_MULTITAP, "Playstation Multitap", tag, owner, clock, "psx_multitap", __FILE__), + device_psx_controller_interface(mconfig, *this), + m_porta(*this, "a"), + m_portb(*this, "b"), + m_portc(*this, "c"), + m_portd(*this, "d") +{ +} + +static MACHINE_CONFIG_FRAGMENT( psx_multitap ) + MCFG_PSX_CTRL_PORT_ADD("a", psx_controllers_nomulti, "digital_pad") + MCFG_PSX_CTRL_PORT_ADD("b", psx_controllers_nomulti, NULL) + MCFG_PSX_CTRL_PORT_ADD("c", psx_controllers_nomulti, NULL) + MCFG_PSX_CTRL_PORT_ADD("d", psx_controllers_nomulti, NULL) +MACHINE_CONFIG_END + +machine_config_constructor psx_multitap_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( psx_multitap ); +} + +void psx_multitap_device::device_start() +{ + m_porta->setup_ack_cb(psx_controller_port_device::void_cb(FUNC(psx_multitap_device::ack), this)); + m_portb->setup_ack_cb(psx_controller_port_device::void_cb(FUNC(psx_multitap_device::ack), this)); + m_portc->setup_ack_cb(psx_controller_port_device::void_cb(FUNC(psx_multitap_device::ack), this)); + m_portd->setup_ack_cb(psx_controller_port_device::void_cb(FUNC(psx_multitap_device::ack), this)); + m_nextmode = false; + + save_item(NAME(m_activeport)); + save_item(NAME(m_cack)); + save_item(NAME(m_singlemode)); + save_item(NAME(m_nextmode)); + save_item(NAME(m_tapmc)); + save_item(NAME(m_data)); +} + +void psx_multitap_device::interface_pre_reset() +{ + m_activeport = -1; + m_singlemode = m_nextmode; + m_tapmc = false; + m_cack[0] = m_cack[1] = m_cack[2] = m_cack[3] = true; + memset(m_data, 0xff, sizeof(m_data)); + m_porta->sel_w(false); + m_portb->sel_w(false); + m_portc->sel_w(false); + m_portd->sel_w(false); + m_porta->sel_w(true); + m_portb->sel_w(true); + m_portc->sel_w(true); + m_portd->sel_w(true); + device_psx_controller_interface::interface_pre_reset(); +} + +void psx_multitap_device::set_tx_line(bool tx, int port) +{ + psx_controller_port_device *dev; + switch(port) + { + default: + case 0: + dev = m_porta; + break; + case 1: + dev = m_portb; + break; + case 2: + dev = m_portc; + break; + case 3: + dev = m_portd; + break; + } + dev->clock_w(0); + dev->tx_w(tx); + dev->clock_w(1); +} + +bool psx_multitap_device::get_rx_line(int port) +{ + psx_controller_port_device *dev; + switch(port) + { + default: + case 0: + dev = m_porta; + break; + case 1: + dev = m_portb; + break; + case 2: + dev = m_portc; + break; + case 3: + dev = m_portd; + break; + } + return dev->rx_r(); +} + +void psx_multitap_device::do_pad() +{ + bool tx = device_psx_controller_interface::m_owner->tx_r(); + + // we don't know which controller until after the first byte + if((m_singlemode || m_tapmc) && (m_count >= 1)) + { + if((m_count == 2) && !m_bit && !m_tapmc) + m_nextmode = !tx; + + set_tx_line(tx, m_activeport); + m_rx = get_rx_line(m_activeport); + m_bit = (m_bit + 1) % 8; + if(!m_bit) + m_count++; + return; + } + + if(!m_count) + { + // first send the select byte to all devices until we know whether it's accessing + // a controller or memcard + if(!m_bit) + { + m_porta->sel_w(false); + m_portb->sel_w(false); + m_portc->sel_w(false); + m_portd->sel_w(false); + } + device_psx_controller_interface::do_pad(); + set_tx_line(tx, 0); + set_tx_line(tx, 1); + set_tx_line(tx, 2); + set_tx_line(tx, 3); + if(!m_bit) + { + m_count = 1; + m_tapmc = m_memcard; + m_memcard = false; // make sure we still receive clocks + if(m_singlemode || m_tapmc) + { + m_activeport = (m_idata & 0xf) - 1; + m_porta->sel_w((m_activeport == 0) ? false : true); + m_portb->sel_w((m_activeport == 1) ? false : true); + m_portc->sel_w((m_activeport == 2) ? false : true); + m_portd->sel_w((m_activeport == 3) ? false : true); + } + } + return; + } + else if(m_count <= 2) + return device_psx_controller_interface::do_pad(); + else if(m_count < 11) + { + if((m_count == 3) && !m_bit) + m_nextmode = !m_idata; + + if((m_count < 5) && m_cack[0] && m_cack[1] && m_cack[2] && m_cack[3]) + return; // no acks? hang up. + + // all of the ports are polled here, port a is passed though. the data + // from the other ports is stored and can be retrieved at a much higher clock rate + // don't poll a port that is inactive or done + if(!m_cack[0]) + { + set_tx_line(tx, 0); + m_rx = m_porta->rx_r(); + } + else + { + m_rx = true; + m_porta->sel_w(true); + } + + if(!m_cack[1]) + { + set_tx_line(tx, 1); + m_data[0][m_count - 3] &= ~(!m_portb->rx_r() << m_bit); + } + else + m_portb->sel_w(true); + + if(!m_cack[2]) + { + set_tx_line(tx, 2); + m_data[1][m_count - 3] &= ~(!m_portc->rx_r() << m_bit); + } + else + m_portc->sel_w(true); + + if(!m_cack[3]) + { + set_tx_line(tx, 3); + m_data[2][m_count - 3] &= ~(!m_portd->rx_r() << m_bit); + } + else + m_portd->sel_w(true); + } + else if(m_count < 19) + // send stored port b data + m_rx = ((m_data[0][m_count - 11] & (1 << m_bit)) ? 1 : 0); + else if(m_count < 27) + // send stored port c data + m_rx = ((m_data[1][m_count - 19] & (1 << m_bit)) ? 1 : 0); + else + // send stored port d data + m_rx = ((m_data[2][m_count - 27] & (1 << m_bit)) ? 1 : 0); + + if(m_bit == 7) + { + // ports won't ack if they are done + m_cack[0] = m_cack[1] = m_cack[2] = m_cack[3] = true; + if(m_count < 11) + m_ack_timer->adjust(attotime::from_usec(12), 0); // give a bit of time for the ports to ack + else if(m_count < 35) + m_ack_timer->adjust(attotime::from_usec(10), 0); + } + + m_bit = (m_bit + 1) % 8; + if(!m_bit) + m_count++; +} + +bool psx_multitap_device::get_pad(int count, UINT8 *odata, UINT8 idata) +{ + if(!count) + *odata = 0x80; + else + *odata = 0x5a; + return true; +} + +void psx_multitap_device::ack() +{ + if(m_activeport != -1) + { + switch(m_activeport) + { + case 0: + m_ack = m_porta->ack_r(); + break; + case 1: + m_ack = m_portb->ack_r(); + break; + case 2: + m_ack = m_portc->ack_r(); + break; + case 3: + m_ack = m_portd->ack_r(); + break; + default: + return; + } + device_psx_controller_interface::m_owner->ack(); + return; + } + if(!m_porta->ack_r()) + m_cack[0] = false; + if(!m_portb->ack_r()) + m_cack[1] = false; + if(!m_portc->ack_r()) + m_cack[2] = false; + if(!m_portd->ack_r()) + m_cack[3] = false; +} diff --git a/src/devices/bus/psx/multitap.h b/src/devices/bus/psx/multitap.h new file mode 100644 index 00000000000..f968d4e4dc6 --- /dev/null +++ b/src/devices/bus/psx/multitap.h @@ -0,0 +1,43 @@ +// license:BSD-3-Clause +// copyright-holders:Carl +#ifndef PSXMULTITAP_H_ +#define PSXMULTITAP_H_ + +#include "ctlrport.h" + +SLOT_INTERFACE_EXTERN(psx_controllers_nomulti); + +class psx_multitap_device : public device_t, + public device_psx_controller_interface +{ +public: + psx_multitap_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual machine_config_constructor device_mconfig_additions() const; + +protected: + virtual void device_start(); + virtual void device_stop() { device_psx_controller_interface::m_owner->disable_card(false); } + virtual void device_reset() { device_psx_controller_interface::m_owner->disable_card(true); } + virtual void device_config_complete() { m_shortname = "psx_multitap"; } + virtual void interface_pre_reset(); + +private: + virtual bool get_pad(int count, UINT8 *odata, UINT8 idata); + virtual void do_pad(); + void ack(); + void set_tx_line(bool tx, int port); + bool get_rx_line(int port); + + int m_activeport; + bool m_cack[4]; + bool m_singlemode, m_nextmode, m_tapmc; + UINT8 m_data[3][8]; // port a is passed though + required_device m_porta; + required_device m_portb; + required_device m_portc; + required_device m_portd; +}; + +extern const device_type PSX_MULTITAP; + +#endif /* PSXMULTITAP_H_ */ diff --git a/src/devices/bus/ql/cst_q_plus4.c b/src/devices/bus/ql/cst_q_plus4.c new file mode 100644 index 00000000000..76f5a046566 --- /dev/null +++ b/src/devices/bus/ql/cst_q_plus4.c @@ -0,0 +1,144 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + CST Q+4 emulation + +**********************************************************************/ + +#include "cst_q_plus4.h" + + + +//************************************************************************** +// MACROS/CONSTANTS +//************************************************************************** + +#define MC6821_TAG "mc6821" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type CST_Q_PLUS4 = &device_creator; + + +//------------------------------------------------- +// ROM( cst_q_plus4 ) +//------------------------------------------------- + +ROM_START( cst_q_plus4 ) + ROM_REGION( 0x2000, "rom", 0 ) + ROM_LOAD( "qplus4.rom", 0x0000, 0x2000, CRC(53a078fb) SHA1(53d6828c1b6ba052b862fd80ac8a364b0078330d) ) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *cst_q_plus4_t::device_rom_region() const +{ + return ROM_NAME( cst_q_plus4 ); +} + + +//------------------------------------------------- +// MACHINE_CONFIG_FRAGMENT( cst_q_plus4 ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( cst_q_plus4 ) + MCFG_DEVICE_ADD(MC6821_TAG, PIA6821, 0) + + MCFG_QL_EXPANSION_SLOT_ADD("exp1", ql_expansion_cards, NULL) + MCFG_QL_EXPANSION_SLOT_EXTINTL_CALLBACK(WRITELINE(cst_q_plus4_t, exp1_extintl_w)) + + MCFG_QL_EXPANSION_SLOT_ADD("exp2", ql_expansion_cards, NULL) + MCFG_QL_EXPANSION_SLOT_EXTINTL_CALLBACK(WRITELINE(cst_q_plus4_t, exp2_extintl_w)) + + MCFG_QL_EXPANSION_SLOT_ADD("exp3", ql_expansion_cards, NULL) + MCFG_QL_EXPANSION_SLOT_EXTINTL_CALLBACK(WRITELINE(cst_q_plus4_t, exp3_extintl_w)) + + MCFG_QL_EXPANSION_SLOT_ADD("exp4", ql_expansion_cards, NULL) + MCFG_QL_EXPANSION_SLOT_EXTINTL_CALLBACK(WRITELINE(cst_q_plus4_t, exp4_extintl_w)) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor cst_q_plus4_t::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( cst_q_plus4 ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// cst_q_plus4_t - constructor +//------------------------------------------------- + +cst_q_plus4_t::cst_q_plus4_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, CST_Q_PLUS4, "CST Q+4", tag, owner, clock, "ql_qplus4", __FILE__), + device_ql_expansion_card_interface(mconfig, *this), + m_exp1(*this, "exp1"), + m_exp2(*this, "exp2"), + m_exp3(*this, "exp3"), + m_exp4(*this, "exp4"), + m_rom(*this, "rom"), + m_exp1_extinl(CLEAR_LINE), + m_exp2_extinl(CLEAR_LINE), + m_exp3_extinl(CLEAR_LINE), + m_exp4_extinl(CLEAR_LINE) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void cst_q_plus4_t::device_start() +{ +} + + +//------------------------------------------------- +// read - +//------------------------------------------------- + +UINT8 cst_q_plus4_t::read(address_space &space, offs_t offset, UINT8 data) +{ + if (offset >= 0xc000 && offset < 0xc200) + { + data = m_rom->base()[offset & 0x1fff]; + } + + data = m_exp1->read(space, offset, data); + data = m_exp2->read(space, offset, data); + data = m_exp3->read(space, offset, data); + data = m_exp4->read(space, offset, data); + + return data; +} + + +//------------------------------------------------- +// write - +//------------------------------------------------- + +void cst_q_plus4_t::write(address_space &space, offs_t offset, UINT8 data) +{ + m_exp1->write(space, offset, data); + m_exp2->write(space, offset, data); + m_exp3->write(space, offset, data); + m_exp4->write(space, offset, data); +} diff --git a/src/devices/bus/ql/cst_q_plus4.h b/src/devices/bus/ql/cst_q_plus4.h new file mode 100644 index 00000000000..3fa37a71bcc --- /dev/null +++ b/src/devices/bus/ql/cst_q_plus4.h @@ -0,0 +1,72 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + CST Q+4 emulation + +**********************************************************************/ + +#pragma once + +#ifndef __CST_Q_PLUS4__ +#define __CST_Q_PLUS4__ + +#include "exp.h" +#include "machine/6821pia.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> cst_q_plus4_t + +class cst_q_plus4_t : public device_t, + public device_ql_expansion_card_interface +{ +public: + // construction/destruction + cst_q_plus4_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + cst_q_plus4_t(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source, int ram_size); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + + DECLARE_WRITE_LINE_MEMBER( exp1_extintl_w ) { m_exp1_extinl = state; update_extintl(); } + DECLARE_WRITE_LINE_MEMBER( exp2_extintl_w ) { m_exp2_extinl = state; update_extintl(); } + DECLARE_WRITE_LINE_MEMBER( exp3_extintl_w ) { m_exp3_extinl = state; update_extintl(); } + DECLARE_WRITE_LINE_MEMBER( exp4_extintl_w ) { m_exp4_extinl = state; update_extintl(); } + +protected: + // device-level overrides + virtual void device_start(); + + // device_ql_expansion_card_interface overrides + virtual UINT8 read(address_space &space, offs_t offset, UINT8 data); + virtual void write(address_space &space, offs_t offset, UINT8 data); + +private: + void update_extintl() { m_slot->extintl_w(m_exp1_extinl || m_exp2_extinl || m_exp3_extinl || m_exp4_extinl); } + + required_device m_exp1; + required_device m_exp2; + required_device m_exp3; + required_device m_exp4; + required_memory_region m_rom; + + int m_exp1_extinl; + int m_exp2_extinl; + int m_exp3_extinl; + int m_exp4_extinl; +}; + + + +// device type definition +extern const device_type CST_Q_PLUS4; + + + +#endif diff --git a/src/devices/bus/ql/cst_qdisc.c b/src/devices/bus/ql/cst_qdisc.c new file mode 100644 index 00000000000..f9fdcf26e04 --- /dev/null +++ b/src/devices/bus/ql/cst_qdisc.c @@ -0,0 +1,85 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + CST QL Disc Interface emulation + +**********************************************************************/ + +#include "cst_qdisc.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type CST_QL_DISC_INTERFACE = &device_creator; + + +//------------------------------------------------- +// ROM( cst_ql_disc_interface ) +//------------------------------------------------- + +ROM_START( cst_ql_disc_interface ) + ROM_REGION( 0x2000, "rom", 0 ) + ROM_DEFAULT_BIOS("v116") + ROM_SYSTEM_BIOS( 0, "v113", "v1.13" ) + ROMX_LOAD( "cst_qdisc_controller_v1.13_1984.rom", 0x0000, 0x2000, CRC(e08d9b5b) SHA1(ec981e60db0269412c518930ca6b5187b20a44f5), ROM_BIOS(1) ) + ROM_SYSTEM_BIOS( 1, "v116", "v1.16" ) + ROMX_LOAD( "cst_qdisc_controller_v1.16_1984.rom", 0x0000, 0x2000, CRC(05a73b00) SHA1(de8c5a4257107a4a41bc94c532cbfb7c65bfb472), ROM_BIOS(2) ) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *cst_ql_disc_interface_t::device_rom_region() const +{ + return ROM_NAME( cst_ql_disc_interface ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// cst_ql_disc_interface_t - constructor +//------------------------------------------------- + +cst_ql_disc_interface_t::cst_ql_disc_interface_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, CST_QL_DISC_INTERFACE, "CST QL Disc Interface", tag, owner, clock, "ql_qdisc", __FILE__), + device_ql_expansion_card_interface(mconfig, *this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void cst_ql_disc_interface_t::device_start() +{ +} + + +//------------------------------------------------- +// read - +//------------------------------------------------- + +UINT8 cst_ql_disc_interface_t::read(address_space &space, offs_t offset, UINT8 data) +{ + return data; +} + + +//------------------------------------------------- +// write - +//------------------------------------------------- + +void cst_ql_disc_interface_t::write(address_space &space, offs_t offset, UINT8 data) +{ +} diff --git a/src/devices/bus/ql/cst_qdisc.h b/src/devices/bus/ql/cst_qdisc.h new file mode 100644 index 00000000000..a4f50cb7ccb --- /dev/null +++ b/src/devices/bus/ql/cst_qdisc.h @@ -0,0 +1,53 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + CST QL Disc Interface emulation + +**********************************************************************/ + +#pragma once + +#ifndef __CST_QL_DISC_INTERFACE__ +#define __CST_QL_DISC_INTERFACE__ + +#include "exp.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> cst_ql_disc_interface_t + +class cst_ql_disc_interface_t : public device_t, + public device_ql_expansion_card_interface +{ +public: + // construction/destruction + cst_ql_disc_interface_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + cst_ql_disc_interface_t(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source, int ram_size); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + +protected: + // device-level overrides + virtual void device_start(); + + // device_ql_expansion_card_interface overrides + virtual UINT8 read(address_space &space, offs_t offset, UINT8 data); + virtual void write(address_space &space, offs_t offset, UINT8 data); + +private: +}; + + + +// device type definition +extern const device_type CST_QL_DISC_INTERFACE; + + + +#endif diff --git a/src/devices/bus/ql/cumana_fdi.c b/src/devices/bus/ql/cumana_fdi.c new file mode 100644 index 00000000000..91259f0db43 --- /dev/null +++ b/src/devices/bus/ql/cumana_fdi.c @@ -0,0 +1,85 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Cumana Floppy Disk Interface emulation + +**********************************************************************/ + +#include "cumana_fdi.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type CUMANA_FLOPPY_DISK_INTERFACE = &device_creator; + + +//------------------------------------------------- +// ROM( cumana_floppy_disk_interface ) +//------------------------------------------------- + +ROM_START( cumana_floppy_disk_interface ) + ROM_REGION( 0x4000, "rom", 0 ) + ROM_DEFAULT_BIOS("v116") + ROM_SYSTEM_BIOS( 0, "v114", "v1.14" ) + ROMX_LOAD( "cumana114.rom", 0x0000, 0x4000, CRC(03baf164) SHA1(e487742c481be8c2771ab2c0fc5e3acd612dec54), ROM_BIOS(1) ) + ROM_SYSTEM_BIOS( 1, "v116", "v1.16" ) + ROMX_LOAD( "cumana116.rom", 0x0000, 0x4000, CRC(def02822) SHA1(323120cd3e1eaa38f6d0ae74367a4835a5a2a011), ROM_BIOS(2) ) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *cumana_floppy_disk_interface_t::device_rom_region() const +{ + return ROM_NAME( cumana_floppy_disk_interface ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// cumana_floppy_disk_interface_t - constructor +//------------------------------------------------- + +cumana_floppy_disk_interface_t::cumana_floppy_disk_interface_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, CUMANA_FLOPPY_DISK_INTERFACE, "Cumana Floppy Disk Interface", tag, owner, clock, "ql_cumanafdi", __FILE__), + device_ql_expansion_card_interface(mconfig, *this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void cumana_floppy_disk_interface_t::device_start() +{ +} + + +//------------------------------------------------- +// read - +//------------------------------------------------- + +UINT8 cumana_floppy_disk_interface_t::read(address_space &space, offs_t offset, UINT8 data) +{ + return data; +} + + +//------------------------------------------------- +// write - +//------------------------------------------------- + +void cumana_floppy_disk_interface_t::write(address_space &space, offs_t offset, UINT8 data) +{ +} diff --git a/src/devices/bus/ql/cumana_fdi.h b/src/devices/bus/ql/cumana_fdi.h new file mode 100644 index 00000000000..b3249e76cdf --- /dev/null +++ b/src/devices/bus/ql/cumana_fdi.h @@ -0,0 +1,53 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Cumana Floppy Disk Interface emulation + +**********************************************************************/ + +#pragma once + +#ifndef __CUMANA_FLOPPY_DISK_INTERFACE__ +#define __CUMANA_FLOPPY_DISK_INTERFACE__ + +#include "exp.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> cumana_floppy_disk_interface_t + +class cumana_floppy_disk_interface_t : public device_t, + public device_ql_expansion_card_interface +{ +public: + // construction/destruction + cumana_floppy_disk_interface_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + cumana_floppy_disk_interface_t(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source, int ram_size); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + +protected: + // device-level overrides + virtual void device_start(); + + // device_ql_expansion_card_interface overrides + virtual UINT8 read(address_space &space, offs_t offset, UINT8 data); + virtual void write(address_space &space, offs_t offset, UINT8 data); + +private: +}; + + + +// device type definition +extern const device_type CUMANA_FLOPPY_DISK_INTERFACE; + + + +#endif diff --git a/src/devices/bus/ql/exp.c b/src/devices/bus/ql/exp.c new file mode 100644 index 00000000000..4276f941811 --- /dev/null +++ b/src/devices/bus/ql/exp.c @@ -0,0 +1,110 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Sinclair QL expansion port emulation + +**********************************************************************/ + +#include "exp.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type QL_EXPANSION_SLOT = &device_creator; + + + +//************************************************************************** +// DEVICE QL_EXPANSION CARD INTERFACE +//************************************************************************** + +//------------------------------------------------- +// device_ql_expansion_card_interface - constructor +//------------------------------------------------- + +device_ql_expansion_card_interface::device_ql_expansion_card_interface(const machine_config &mconfig, device_t &device) : + device_slot_card_interface(mconfig, device), + m_romoeh(0) +{ + m_slot = dynamic_cast(device.owner()); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// ql_expansion_slot_t - constructor +//------------------------------------------------- + +ql_expansion_slot_t::ql_expansion_slot_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, QL_EXPANSION_SLOT, "QL expansion port", tag, owner, clock, "ql_expansion_slot", __FILE__), + device_slot_interface(mconfig, *this), + m_write_ipl0l(*this), + m_write_ipl1l(*this), + m_write_berrl(*this), + m_write_extintl(*this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void ql_expansion_slot_t::device_start() +{ + m_card = dynamic_cast(get_card_device()); + + // resolve callbacks + m_write_ipl0l.resolve_safe(); + m_write_ipl1l.resolve_safe(); + m_write_berrl.resolve_safe(); + m_write_extintl.resolve_safe(); +} + + +//------------------------------------------------- +// SLOT_INTERFACE( ql_expansion_cards ) +//------------------------------------------------- + +// slot devices +#include "cst_qdisc.h" +#include "cst_q_plus4.h" +#include "cumana_fdi.h" +#include "kempston_di.h" +#include "miracle_gold_card.h" +#include "mp_fdi.h" +#include "opd_basic_master.h" +#include "pcml_qdisk.h" +#include "qubide.h" +#include "sandy_superdisk.h" +#include "sandy_superqboard.h" +#include "trumpcard.h" + +SLOT_INTERFACE_START( ql_expansion_cards ) + SLOT_INTERFACE("qdisc", CST_QL_DISC_INTERFACE) + SLOT_INTERFACE("qplus4", CST_Q_PLUS4) + SLOT_INTERFACE("cumanafdi", CUMANA_FLOPPY_DISK_INTERFACE) + SLOT_INTERFACE("kdi", KEMPSTON_DISK_INTERFACE) + SLOT_INTERFACE("mpfdi", MICRO_PERIPHERALS_FLOPPY_DISK_INTERFACE) + SLOT_INTERFACE("gold", MIRACLE_GOLD_CARD) + SLOT_INTERFACE("pcmlqdi", PCML_Q_DISK_INTERFACE) + SLOT_INTERFACE("qubide", QUBIDE) + SLOT_INTERFACE("sdisk", SANDY_SUPER_DISK) + SLOT_INTERFACE("sqboard", SANDY_SUPERQBOARD) + SLOT_INTERFACE("sqboard512k", SANDY_SUPERQBOARD_512K) + SLOT_INTERFACE("sqmouse", SANDY_SUPERQMOUSE) + SLOT_INTERFACE("sqmouse512k", SANDY_SUPERQMOUSE_512K) + SLOT_INTERFACE("opdbasic", OPD_BASIC_MASTER) + SLOT_INTERFACE("trump", QL_TRUMP_CARD) + SLOT_INTERFACE("trump256k", QL_TRUMP_CARD_256K) + SLOT_INTERFACE("trump512k", QL_TRUMP_CARD_512K) + SLOT_INTERFACE("trump768k", QL_TRUMP_CARD_768K) +SLOT_INTERFACE_END diff --git a/src/devices/bus/ql/exp.h b/src/devices/bus/ql/exp.h new file mode 100644 index 00000000000..c9f84c793e9 --- /dev/null +++ b/src/devices/bus/ql/exp.h @@ -0,0 +1,151 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Sinclair QL expansion port emulation + +********************************************************************** + + A B + GND * 1 * GND + D3 * 2 * D2 + D4 * 3 * D1 + D5 * 4 * D0 + D6 * 5 * ASL + D7 * 6 * DSL + A19 * 7 * RDWL + A18 * 8 * DTACKL + A17 * 9 * BGL + A16 * 10 * BRL + CLKCPU * 11 * A15 + RED * 12 * RESETCPUL + A14 * 13 * CSYNCL + A13 * 14 * E + A12 * 15 * VSYNCH + A11 * 16 * VPAL + A10 * 17 * GREEN + A9 * 18 * BLUE + A8 * 19 * FC2 + A7 * 20 * FC1 + A6 * 21 * FC0 + A5 * 22 * A0 + A4 * 23 * ROMOEH + A3 * 24 * A1 + DBGL * 25 * A2 + SP2 * 26 * SP3 + DSCML * 27 * IPL0L + SP1 * 28 * BERRL + SP0 * 29 * IPL1L + VP12 * 30 * EXTINTL + VM12 * 31 * VIN + VIN * 32 * VIN + +**********************************************************************/ + +#pragma once + +#ifndef __QL_EXPANSION_SLOT__ +#define __QL_EXPANSION_SLOT__ + +#include "emu.h" + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_QL_EXPANSION_SLOT_ADD(_tag, _slot_intf, _def_slot) \ + MCFG_DEVICE_ADD(_tag, QL_EXPANSION_SLOT, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) + + +#define MCFG_QL_EXPANSION_SLOT_IPL0L_CALLBACK(_write) \ + devcb = &ql_expansion_slot_t::set_ipl0l_wr_callback(*device, DEVCB_##_write); + +#define MCFG_QL_EXPANSION_SLOT_IPL1L_CALLBACK(_write) \ + devcb = &ql_expansion_slot_t::set_ipl1l_wr_callback(*device, DEVCB_##_write); + +#define MCFG_QL_EXPANSION_SLOT_BERRL_CALLBACK(_write) \ + devcb = &ql_expansion_slot_t::set_berrl_wr_callback(*device, DEVCB_##_write); + +#define MCFG_QL_EXPANSION_SLOT_EXTINTL_CALLBACK(_write) \ + devcb = &ql_expansion_slot_t::set_extintl_wr_callback(*device, DEVCB_##_write); + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> device_ql_expansion_card_interface + +class ql_expansion_slot_t; + +class device_ql_expansion_card_interface : public device_slot_card_interface +{ + friend class ql_expansion_slot_t; + +public: + // construction/destruction + device_ql_expansion_card_interface(const machine_config &mconfig, device_t &device); + + virtual void romoeh_w(int state) { m_romoeh = state; } + virtual UINT8 read(address_space &space, offs_t offset, UINT8 data) { return data; } + virtual void write(address_space &space, offs_t offset, UINT8 data) { } + +protected: + ql_expansion_slot_t *m_slot; + + int m_romoeh; +}; + + +// ======================> ql_expansion_slot_t + +class ql_expansion_slot_t : public device_t, + public device_slot_interface +{ +public: + // construction/destruction + ql_expansion_slot_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + template static devcb_base &set_ipl0l_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_ipl0l.set_callback(object); } + template static devcb_base &set_ipl1l_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_ipl1l.set_callback(object); } + template static devcb_base &set_berrl_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_berrl.set_callback(object); } + template static devcb_base &set_extintl_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_extintl.set_callback(object); } + + // computer interface + UINT8 read(address_space &space, offs_t offset, UINT8 data) { if (m_card) data = m_card->read(space, offset, data); return data; } + void write(address_space &space, offs_t offset, UINT8 data) { if (m_card) m_card->write(space, offset, data); } + DECLARE_WRITE_LINE_MEMBER( romoeh_w ) { if (m_card) m_card->romoeh_w(state); } + + // card interface + DECLARE_WRITE_LINE_MEMBER( ipl0l_w ) { m_write_ipl0l(state); } + DECLARE_WRITE_LINE_MEMBER( ipl1l_w ) { m_write_ipl1l(state); } + DECLARE_WRITE_LINE_MEMBER( berrl_w ) { m_write_berrl(state); } + DECLARE_WRITE_LINE_MEMBER( extintl_w ) { m_write_extintl(state); } + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset() { if (get_card_device()) get_card_device()->reset(); } + + devcb_write_line m_write_ipl0l; + devcb_write_line m_write_ipl1l; + devcb_write_line m_write_berrl; + devcb_write_line m_write_extintl; + + device_ql_expansion_card_interface *m_card; +}; + + +// device type definition +extern const device_type QL_EXPANSION_SLOT; + + +SLOT_INTERFACE_EXTERN( ql_expansion_cards ); + + + +#endif diff --git a/src/devices/bus/ql/kempston_di.c b/src/devices/bus/ql/kempston_di.c new file mode 100644 index 00000000000..c69c129e2e9 --- /dev/null +++ b/src/devices/bus/ql/kempston_di.c @@ -0,0 +1,83 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Kempston Disk Interface emulation + +**********************************************************************/ + +#include "kempston_di.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type KEMPSTON_DISK_INTERFACE = &device_creator; + + +//------------------------------------------------- +// ROM( kempston_disk_system ) +//------------------------------------------------- + +ROM_START( kempston_disk_system ) + ROM_REGION( 0x2000, "rom", 0 ) + ROM_DEFAULT_BIOS("v114") + ROM_SYSTEM_BIOS( 0, "v114", "v1.14" ) + ROMX_LOAD( "kempston_disk_system_v1.14_1984.rom", 0x0000, 0x2000, CRC(0b70ad2e) SHA1(ff8158d25864d920f3f6df259167e91c2784692c), ROM_BIOS(1) ) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *kempston_disk_interface_t::device_rom_region() const +{ + return ROM_NAME( kempston_disk_system ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// kempston_disk_interface_t - constructor +//------------------------------------------------- + +kempston_disk_interface_t::kempston_disk_interface_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, KEMPSTON_DISK_INTERFACE, "Kempston Disk Interface", tag, owner, clock, "ql_kdi", __FILE__), + device_ql_expansion_card_interface(mconfig, *this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void kempston_disk_interface_t::device_start() +{ +} + + +//------------------------------------------------- +// read - +//------------------------------------------------- + +UINT8 kempston_disk_interface_t::read(address_space &space, offs_t offset, UINT8 data) +{ + return data; +} + + +//------------------------------------------------- +// write - +//------------------------------------------------- + +void kempston_disk_interface_t::write(address_space &space, offs_t offset, UINT8 data) +{ +} diff --git a/src/devices/bus/ql/kempston_di.h b/src/devices/bus/ql/kempston_di.h new file mode 100644 index 00000000000..0920fe2430d --- /dev/null +++ b/src/devices/bus/ql/kempston_di.h @@ -0,0 +1,53 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Kempston Disk Interface emulation + +**********************************************************************/ + +#pragma once + +#ifndef __KEMPSTON_DISK_INTERFACE__ +#define __KEMPSTON_DISK_INTERFACE__ + +#include "exp.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> kempston_disk_interface_t + +class kempston_disk_interface_t : public device_t, + public device_ql_expansion_card_interface +{ +public: + // construction/destruction + kempston_disk_interface_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + kempston_disk_interface_t(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source, int ram_size); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + +protected: + // device-level overrides + virtual void device_start(); + + // device_ql_expansion_card_interface overrides + virtual UINT8 read(address_space &space, offs_t offset, UINT8 data); + virtual void write(address_space &space, offs_t offset, UINT8 data); + +private: +}; + + + +// device type definition +extern const device_type KEMPSTON_DISK_INTERFACE; + + + +#endif diff --git a/src/devices/bus/ql/miracle_gold_card.c b/src/devices/bus/ql/miracle_gold_card.c new file mode 100644 index 00000000000..3e25f43e0a6 --- /dev/null +++ b/src/devices/bus/ql/miracle_gold_card.c @@ -0,0 +1,85 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Miracle Systems Gold Card emulation + +**********************************************************************/ + +#include "miracle_gold_card.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type MIRACLE_GOLD_CARD = &device_creator; + + +//------------------------------------------------- +// ROM( miracle_gold_card ) +//------------------------------------------------- + +ROM_START( miracle_gold_card ) + ROM_REGION( 0x10000, "rom", 0 ) + ROM_DEFAULT_BIOS("v249") + ROM_SYSTEM_BIOS( 0, "v228", "v2.28" ) + ROMX_LOAD( "goldcard228.bin", 0x00000, 0x10000, CRC(fee008de) SHA1(849f0a515ac32502f3b1a4f65ce957c0bef6e6d6), ROM_BIOS(1) ) + ROM_SYSTEM_BIOS( 1, "v249", "v2.49" ) + ROMX_LOAD( "sgcandgc249.bin", 0x00000, 0x10000, CRC(963c7bfc) SHA1(e80851fc536eef2b83c611e717e563b05bba8b3d), ROM_BIOS(2) ) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *miracle_gold_card_t::device_rom_region() const +{ + return ROM_NAME( miracle_gold_card ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// miracle_gold_card_t - constructor +//------------------------------------------------- + +miracle_gold_card_t::miracle_gold_card_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, MIRACLE_GOLD_CARD, "Miracle Gold Card", tag, owner, clock, "ql_gold", __FILE__), + device_ql_expansion_card_interface(mconfig, *this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void miracle_gold_card_t::device_start() +{ +} + + +//------------------------------------------------- +// read - +//------------------------------------------------- + +UINT8 miracle_gold_card_t::read(address_space &space, offs_t offset, UINT8 data) +{ + return data; +} + + +//------------------------------------------------- +// write - +//------------------------------------------------- + +void miracle_gold_card_t::write(address_space &space, offs_t offset, UINT8 data) +{ +} diff --git a/src/devices/bus/ql/miracle_gold_card.h b/src/devices/bus/ql/miracle_gold_card.h new file mode 100644 index 00000000000..36c358984a3 --- /dev/null +++ b/src/devices/bus/ql/miracle_gold_card.h @@ -0,0 +1,53 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Miracle Systems Gold Card emulation + +**********************************************************************/ + +#pragma once + +#ifndef __MIRACLE_GOLD_CARD__ +#define __MIRACLE_GOLD_CARD__ + +#include "exp.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> miracle_gold_card_t + +class miracle_gold_card_t : public device_t, + public device_ql_expansion_card_interface +{ +public: + // construction/destruction + miracle_gold_card_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + miracle_gold_card_t(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source, int ram_size); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + +protected: + // device-level overrides + virtual void device_start(); + + // device_ql_expansion_card_interface overrides + virtual UINT8 read(address_space &space, offs_t offset, UINT8 data); + virtual void write(address_space &space, offs_t offset, UINT8 data); + +private: +}; + + + +// device type definition +extern const device_type MIRACLE_GOLD_CARD; + + + +#endif diff --git a/src/devices/bus/ql/miracle_hd.c b/src/devices/bus/ql/miracle_hd.c new file mode 100644 index 00000000000..b181fc48918 --- /dev/null +++ b/src/devices/bus/ql/miracle_hd.c @@ -0,0 +1,83 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Miracle Hard Disk emulation + +**********************************************************************/ + +#include "miracle_hd.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type MIRACLE_HARD_DISK = &device_creator; + + +//------------------------------------------------- +// ROM( miracle_hard_disk ) +//------------------------------------------------- + +ROM_START( miracle_hard_disk ) + ROM_REGION( 0x2000, "rom", 0 ) + ROM_DEFAULT_BIOS("v202") + ROM_SYSTEM_BIOS( 0, "v202", "v2.02" ) + ROMX_LOAD( "miraculous_winny_v2.02_1989_qjump.rom", 0x0000, 0x2000, CRC(10982b35) SHA1(1beb87a207ecd0f47a43ed4b1bcc81d89ac75ffc), ROM_BIOS(1) ) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *miracle_hard_disk_t::device_rom_region() const +{ + return ROM_NAME( miracle_hard_disk ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// miracle_hard_disk_t - constructor +//------------------------------------------------- + +miracle_hard_disk_t::miracle_hard_disk_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, MIRACLE_HARD_DISK, "Miracle Hard Disk", tag, owner, clock, "ql_mhd", __FILE__), + device_ql_rom_cartridge_card_interface(mconfig, *this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void miracle_hard_disk_t::device_start() +{ +} + + +//------------------------------------------------- +// read - +//------------------------------------------------- + +UINT8 miracle_hard_disk_t::read(address_space &space, offs_t offset, UINT8 data) +{ + return data; +} + + +//------------------------------------------------- +// write - +//------------------------------------------------- + +void miracle_hard_disk_t::write(address_space &space, offs_t offset, UINT8 data) +{ +} diff --git a/src/devices/bus/ql/miracle_hd.h b/src/devices/bus/ql/miracle_hd.h new file mode 100644 index 00000000000..43ef817475a --- /dev/null +++ b/src/devices/bus/ql/miracle_hd.h @@ -0,0 +1,53 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Miracle Hard Disk emulation + +**********************************************************************/ + +#pragma once + +#ifndef __MIRACLE_HARD_DISK__ +#define __MIRACLE_HARD_DISK__ + +#include "rom.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> miracle_hard_disk_t + +class miracle_hard_disk_t : public device_t, + public device_ql_rom_cartridge_card_interface +{ +public: + // construction/destruction + miracle_hard_disk_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + miracle_hard_disk_t(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source, int ram_size); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + +protected: + // device-level overrides + virtual void device_start(); + + // device_ql_rom_cartridge_card_interface overrides + virtual UINT8 read(address_space &space, offs_t offset, UINT8 data); + virtual void write(address_space &space, offs_t offset, UINT8 data); + +private: +}; + + + +// device type definition +extern const device_type MIRACLE_HARD_DISK; + + + +#endif diff --git a/src/devices/bus/ql/mp_fdi.c b/src/devices/bus/ql/mp_fdi.c new file mode 100644 index 00000000000..d23542ab8f4 --- /dev/null +++ b/src/devices/bus/ql/mp_fdi.c @@ -0,0 +1,83 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Micro Peripherals Floppy Disk Interface emulation + +**********************************************************************/ + +#include "mp_fdi.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type MICRO_PERIPHERALS_FLOPPY_DISK_INTERFACE = &device_creator; + + +//------------------------------------------------- +// ROM( micro_peripherals_floppy_disk_interface ) +//------------------------------------------------- + +ROM_START( micro_peripherals_floppy_disk_interface ) + ROM_REGION( 0x2000, "rom", 0 ) + ROM_DEFAULT_BIOS("v53e") + ROM_SYSTEM_BIOS( 0, "v53e", "v5.3E" ) + ROMX_LOAD( "microp_disk system_v5.3e_1985.rom", 0x0000, 0x2000, CRC(9a8d8fa7) SHA1(f9f5e5d55f3046f63b4eae59222b81290d626e72), ROM_BIOS(1) ) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *micro_peripherals_floppy_disk_interface_t::device_rom_region() const +{ + return ROM_NAME( micro_peripherals_floppy_disk_interface ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// micro_peripherals_floppy_disk_interface_t - constructor +//------------------------------------------------- + +micro_peripherals_floppy_disk_interface_t::micro_peripherals_floppy_disk_interface_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, MICRO_PERIPHERALS_FLOPPY_DISK_INTERFACE, "Micro Peripherals Floppy Disk Interface", tag, owner, clock, "ql_mpfdi", __FILE__), + device_ql_expansion_card_interface(mconfig, *this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void micro_peripherals_floppy_disk_interface_t::device_start() +{ +} + + +//------------------------------------------------- +// read - +//------------------------------------------------- + +UINT8 micro_peripherals_floppy_disk_interface_t::read(address_space &space, offs_t offset, UINT8 data) +{ + return data; +} + + +//------------------------------------------------- +// write - +//------------------------------------------------- + +void micro_peripherals_floppy_disk_interface_t::write(address_space &space, offs_t offset, UINT8 data) +{ +} diff --git a/src/devices/bus/ql/mp_fdi.h b/src/devices/bus/ql/mp_fdi.h new file mode 100644 index 00000000000..5f0d3e9fd0f --- /dev/null +++ b/src/devices/bus/ql/mp_fdi.h @@ -0,0 +1,53 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Micro Peripherals Floppy Disk Interface emulation + +**********************************************************************/ + +#pragma once + +#ifndef __MICRO_PERIPHERALS_FLOPPY_DISK_INTERFACE__ +#define __MICRO_PERIPHERALS_FLOPPY_DISK_INTERFACE__ + +#include "exp.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> micro_peripherals_floppy_disk_interface_t + +class micro_peripherals_floppy_disk_interface_t : public device_t, + public device_ql_expansion_card_interface +{ +public: + // construction/destruction + micro_peripherals_floppy_disk_interface_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + micro_peripherals_floppy_disk_interface_t(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source, int ram_size); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + +protected: + // device-level overrides + virtual void device_start(); + + // device_ql_expansion_card_interface overrides + virtual UINT8 read(address_space &space, offs_t offset, UINT8 data); + virtual void write(address_space &space, offs_t offset, UINT8 data); + +private: +}; + + + +// device type definition +extern const device_type MICRO_PERIPHERALS_FLOPPY_DISK_INTERFACE; + + + +#endif diff --git a/src/devices/bus/ql/opd_basic_master.c b/src/devices/bus/ql/opd_basic_master.c new file mode 100644 index 00000000000..fa20bf4f5eb --- /dev/null +++ b/src/devices/bus/ql/opd_basic_master.c @@ -0,0 +1,81 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + OPD Basic Master emulation + +**********************************************************************/ + +#include "opd_basic_master.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type OPD_BASIC_MASTER = &device_creator; + + +//------------------------------------------------- +// ROM( opd_basic_master ) +//------------------------------------------------- + +ROM_START( opd_basic_master ) + ROM_REGION( 0x10000, "rom", 0 ) + ROM_LOAD( "opd_basic_master_1984.rom", 0x00000, 0x10000, CRC(7e534c0d) SHA1(de485e89272e3b51086967333cda9de806ba3876) ) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *opd_basic_master_t::device_rom_region() const +{ + return ROM_NAME( opd_basic_master ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// opd_basic_master_t - constructor +//------------------------------------------------- + +opd_basic_master_t::opd_basic_master_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, OPD_BASIC_MASTER, "OPD Basic Master", tag, owner, clock, "ql_opdbm", __FILE__), + device_ql_expansion_card_interface(mconfig, *this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void opd_basic_master_t::device_start() +{ +} + + +//------------------------------------------------- +// read - +//------------------------------------------------- + +UINT8 opd_basic_master_t::read(address_space &space, offs_t offset, UINT8 data) +{ + return data; +} + + +//------------------------------------------------- +// write - +//------------------------------------------------- + +void opd_basic_master_t::write(address_space &space, offs_t offset, UINT8 data) +{ +} diff --git a/src/devices/bus/ql/opd_basic_master.h b/src/devices/bus/ql/opd_basic_master.h new file mode 100644 index 00000000000..4a9b2b7e043 --- /dev/null +++ b/src/devices/bus/ql/opd_basic_master.h @@ -0,0 +1,53 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + OPD Basic Master emulation + +**********************************************************************/ + +#pragma once + +#ifndef __OPD_BASIC_MASTER__ +#define __OPD_BASIC_MASTER__ + +#include "exp.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> opd_basic_master_t + +class opd_basic_master_t : public device_t, + public device_ql_expansion_card_interface +{ +public: + // construction/destruction + opd_basic_master_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + opd_basic_master_t(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source, int ram_size); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + +protected: + // device-level overrides + virtual void device_start(); + + // device_ql_expansion_card_interface overrides + virtual UINT8 read(address_space &space, offs_t offset, UINT8 data); + virtual void write(address_space &space, offs_t offset, UINT8 data); + +private: +}; + + + +// device type definition +extern const device_type OPD_BASIC_MASTER; + + + +#endif diff --git a/src/devices/bus/ql/pcml_qdisk.c b/src/devices/bus/ql/pcml_qdisk.c new file mode 100644 index 00000000000..b5d534f68d7 --- /dev/null +++ b/src/devices/bus/ql/pcml_qdisk.c @@ -0,0 +1,83 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + PCML Q+ Disk Interface emulation + +**********************************************************************/ + +#include "pcml_qdisk.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type PCML_Q_DISK_INTERFACE = &device_creator; + + +//------------------------------------------------- +// ROM( pcml_q_disk_interface ) +//------------------------------------------------- + +ROM_START( pcml_q_disk_interface ) + ROM_REGION( 0x4000, "rom", 0 ) + ROM_DEFAULT_BIOS("v114") + ROM_SYSTEM_BIOS( 0, "v114", "v1.14" ) + ROMX_LOAD( "pcml_diskram system_v1.14_1984.rom", 0x0000, 0x4000, CRC(e38b41dd) SHA1(d2038f0b1a62e8e65ec86660d03c25489ce40274), ROM_BIOS(1) ) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *pcml_q_disk_interface_t::device_rom_region() const +{ + return ROM_NAME( pcml_q_disk_interface ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// pcml_q_disk_interface_t - constructor +//------------------------------------------------- + +pcml_q_disk_interface_t::pcml_q_disk_interface_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, PCML_Q_DISK_INTERFACE, "PCML Q+ Disk Interface", tag, owner, clock, "ql_pcmlqdi", __FILE__), + device_ql_expansion_card_interface(mconfig, *this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void pcml_q_disk_interface_t::device_start() +{ +} + + +//------------------------------------------------- +// read - +//------------------------------------------------- + +UINT8 pcml_q_disk_interface_t::read(address_space &space, offs_t offset, UINT8 data) +{ + return data; +} + + +//------------------------------------------------- +// write - +//------------------------------------------------- + +void pcml_q_disk_interface_t::write(address_space &space, offs_t offset, UINT8 data) +{ +} diff --git a/src/devices/bus/ql/pcml_qdisk.h b/src/devices/bus/ql/pcml_qdisk.h new file mode 100644 index 00000000000..e59d101d9c4 --- /dev/null +++ b/src/devices/bus/ql/pcml_qdisk.h @@ -0,0 +1,53 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + PCML Q+ Disk Interface emulation + +**********************************************************************/ + +#pragma once + +#ifndef __PCML_Q_DISK_INTERFACE__ +#define __PCML_Q_DISK_INTERFACE__ + +#include "exp.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> pcml_q_disk_interface_t + +class pcml_q_disk_interface_t : public device_t, + public device_ql_expansion_card_interface +{ +public: + // construction/destruction + pcml_q_disk_interface_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + pcml_q_disk_interface_t(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source, int ram_size); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + +protected: + // device-level overrides + virtual void device_start(); + + // device_ql_expansion_card_interface overrides + virtual UINT8 read(address_space &space, offs_t offset, UINT8 data); + virtual void write(address_space &space, offs_t offset, UINT8 data); + +private: +}; + + + +// device type definition +extern const device_type PCML_Q_DISK_INTERFACE; + + + +#endif diff --git a/src/devices/bus/ql/qubide.c b/src/devices/bus/ql/qubide.c new file mode 100644 index 00000000000..7af6c6d6694 --- /dev/null +++ b/src/devices/bus/ql/qubide.c @@ -0,0 +1,286 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Qubbesoft QubIDE emulation + +**********************************************************************/ + +/* + ------------------------------------------------------------------- + | This side goes into the QL | + | | ++---------------------------------------------------------------------+ +| o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o | +| +-------+ +---------+ | +| |o o|o o| |o|o|o|o|o| +--------------------------+ | +| +-------+ |o|o|o|o|o| | | | +| J6 J7 +---------+ | | | +|+----------+-- J1J2J3J4J5 |) EPROM | | +|| | | | | | +|| |7805 |-- +---------------+ | | | +|| | | | | +--------------------------+ | +|+----------+-- |) 74HCT688 | | +| | | | +| +---------------+ | +|+-------------------+ +-------------------+ +--------------------+ | +|| | | | | | | +||) GAL 1 | |) GAL 2 | |) 74HCT646 | | +|| | | | | | | +|+-------------------+ +-------------------+ +--------------------+ | +| | +| +-----------------------------------------+ +--------------------+ | +| | o o o o o o o o o o o o o o o o o o o o | | | | +| | o o o o o o o o o o o o o o o o o o o o | |) 74HCT646 | | +| +-----------------------------------------+ | | | +| +--------------------+ | +| +---+ +-----------+ | +| |o o| + |o o o o o o| Exp. Conn. | +| +---+ +-----------+ | +| LED | +| | +| o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o | ++---------------------------------------------------------------------+ + | | + | Through Connector | + ------------------------------------------------------------------- +*/ + +#include "qubide.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type QUBIDE = &device_creator; + + +//------------------------------------------------- +// ROM( qubide ) +//------------------------------------------------- + +ROM_START( qubide ) + ROM_REGION( 0x4000, "rom", 0 ) + ROM_DEFAULT_BIOS("v156") + ROM_SYSTEM_BIOS( 0, "v141", "v1.41" ) + ROMX_LOAD( "qide141.bin", 0x0000, 0x4000, CRC(28955132) SHA1(37e47043260977c1fa5bae4a50b65d5575cd8e5f), ROM_BIOS(1) ) + ROM_SYSTEM_BIOS( 1, "v156", "v1.56" ) + ROMX_LOAD( "qub156a.rom", 0x0000, 0x4000, CRC(95e8dd34) SHA1(74ea670ece5f579e61ddf4dbbc32645c21a80c03), ROM_BIOS(2) ) + ROM_SYSTEM_BIOS( 2, "v201", "v2.01" ) + ROMX_LOAD( "qb201_16k.rom", 0x0000, 0x4000, CRC(6f1d62a6) SHA1(1708d85397422e2024daa1a3406cac685f46730d), ROM_BIOS(3) ) + + ROM_REGION( 0x22e, "plds", 0 ) + ROM_LOAD( "gal 1a", 0x000, 0x117, CRC(cfb889ba) SHA1(657a2c61e4d372b84eaff78055ddeac6d2ee4d68) ) // old GAL (< v2.0) + ROM_LOAD( "gal 2a", 0x117, 0x117, CRC(53d01e17) SHA1(4cf0da7ff5c7a950e8e13f8ed7125fff10ddda0d) ) // old GAL (< v2.0) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *qubide_t::device_rom_region() const +{ + return ROM_NAME( qubide ); +} + + +//------------------------------------------------- +// MACHINE_CONFIG_FRAGMENT( qubide ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( qubide ) + MCFG_ATA_INTERFACE_ADD("ata", ata_devices, "hdd", NULL, false) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor qubide_t::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( qubide ); +} + + +//------------------------------------------------- +// INPUT_PORTS( qubide ) +//------------------------------------------------- + +INPUT_PORTS_START( qubide ) + PORT_START("J1-J5") + PORT_DIPNAME( 0x1f, 0x03, "Base Address" ) + PORT_DIPSETTING( 0x00, "00000h" ) + PORT_DIPSETTING( 0x01, "04000h" ) + PORT_DIPSETTING( 0x02, "08000h" ) + PORT_DIPSETTING( 0x03, "0c000h" ) + PORT_DIPSETTING( 0x04, "10000h" ) + PORT_DIPSETTING( 0x05, "14000h" ) + PORT_DIPSETTING( 0x06, "18000h" ) + PORT_DIPSETTING( 0x07, "1c000h" ) + PORT_DIPSETTING( 0x08, "20000h" ) + PORT_DIPSETTING( 0x09, "24000h" ) + PORT_DIPSETTING( 0x0a, "28000h" ) + PORT_DIPSETTING( 0x0b, "2c000h" ) + PORT_DIPSETTING( 0x0c, "30000h" ) + PORT_DIPSETTING( 0x0d, "34000h" ) + PORT_DIPSETTING( 0x0e, "38000h" ) + PORT_DIPSETTING( 0x0f, "3c000h" ) + PORT_DIPSETTING( 0x10, "c0000h" ) + PORT_DIPSETTING( 0x11, "c4000h" ) + PORT_DIPSETTING( 0x12, "c8000h" ) + PORT_DIPSETTING( 0x13, "cc000h" ) + PORT_DIPSETTING( 0x14, "d0000h" ) + PORT_DIPSETTING( 0x15, "d4000h" ) + PORT_DIPSETTING( 0x16, "d8000h" ) + PORT_DIPSETTING( 0x17, "dc000h" ) + PORT_DIPSETTING( 0x18, "e0000h" ) + PORT_DIPSETTING( 0x19, "e4000h" ) + PORT_DIPSETTING( 0x1a, "e8000h" ) + PORT_DIPSETTING( 0x1b, "ec000h" ) + PORT_DIPSETTING( 0x1c, "f0000h" ) + PORT_DIPSETTING( 0x1d, "f4000h" ) + PORT_DIPSETTING( 0x1e, "f8000h" ) + PORT_DIPSETTING( 0x1f, "fc000h" ) +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor qubide_t::device_input_ports() const +{ + return INPUT_PORTS_NAME( qubide ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// qubide_t - constructor +//------------------------------------------------- + +qubide_t::qubide_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, QUBIDE, "QubIDE", tag, owner, clock, "ql_qubide", __FILE__), + device_ql_expansion_card_interface(mconfig, *this), + m_ata(*this, "ata"), + m_rom(*this, "rom"), + m_j1_j5(*this, "J1-J5"), + m_base(0xc000), + m_ata_data(0) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void qubide_t::device_start() +{ +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void qubide_t::device_reset() +{ + int j1_j5 = m_j1_j5->read(); + + m_base = (j1_j5 & 0x0f) << 14; + + if (BIT(j1_j5, 4)) + { + m_base |= 0xc0000; + } +} + + +//------------------------------------------------- +// read - +//------------------------------------------------- + +UINT8 qubide_t::read(address_space &space, offs_t offset, UINT8 data) +{ + if ((offset & 0xfc000) == m_base) + { + if ((offset & 0x3f00) == 0x3f00) + { + switch (offset & 0x0f) + { + case 0: + data = m_ata->read_cs1(space, 0x07, 0xff); + break; + + default: + data = m_ata->read_cs0(space, offset & 0x07, 0xff); + break; + + case 0x08: case 0x0a: case 0x0c: + m_ata_data = m_ata->read_cs0(space, 0x00, 0xffff); + + data = m_ata_data >> 8; + break; + + case 0x09: case 0x0b: case 0x0d: + data = m_ata_data & 0xff; + break; + + case 0x0e: case 0x0f: + data = m_ata->read_cs1(space, 0x05, 0xff); + break; + } + } + else + { + data = m_rom->base()[offset & 0x3fff]; + } + } + + return data; +} + + +//------------------------------------------------- +// write - +//------------------------------------------------- + +void qubide_t::write(address_space &space, offs_t offset, UINT8 data) +{ + if ((offset & 0xfc000) == m_base) + { + if ((offset & 0x3f00) == 0x3f00) + { + switch (offset & 0x0f) + { + case 0: case 0x0e: case 0x0f: + m_ata->write_cs1(space, 0x05, data, 0xff); + break; + + case 0x08: case 0x0a: case 0x0c: + m_ata_data = (data << 8) | (m_ata_data & 0xff); + break; + + case 0x09: case 0x0b: case 0x0d: + m_ata_data = (m_ata_data & 0xff00) | data; + + m_ata->write_cs0(space, 0x00, m_ata_data, 0xffff); + break; + + default: + m_ata->write_cs0(space, offset & 0x07, data, 0xff); + break; + } + } + } +} diff --git a/src/devices/bus/ql/qubide.h b/src/devices/bus/ql/qubide.h new file mode 100644 index 00000000000..8c93c68cae6 --- /dev/null +++ b/src/devices/bus/ql/qubide.h @@ -0,0 +1,63 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Qubbesoft QubIDE emulation + +**********************************************************************/ + +#pragma once + +#ifndef __QUBIDE__ +#define __QUBIDE__ + +#include "exp.h" +#include "machine/ataintf.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> qubide_t + +class qubide_t : public device_t, + public device_ql_expansion_card_interface +{ +public: + // construction/destruction + qubide_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + qubide_t(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source, int ram_size); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + virtual ioport_constructor device_input_ports() const; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_ql_expansion_card_interface overrides + virtual UINT8 read(address_space &space, offs_t offset, UINT8 data); + virtual void write(address_space &space, offs_t offset, UINT8 data); + +private: + required_device m_ata; + required_memory_region m_rom; + required_ioport m_j1_j5; + + offs_t m_base; + UINT16 m_ata_data; +}; + + + +// device type definition +extern const device_type QUBIDE; + + + +#endif diff --git a/src/devices/bus/ql/rom.c b/src/devices/bus/ql/rom.c new file mode 100644 index 00000000000..13d72619e8b --- /dev/null +++ b/src/devices/bus/ql/rom.c @@ -0,0 +1,136 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Sinclair QL ROM cartridge port emulation + +**********************************************************************/ + +#include "rom.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type QL_ROM_CARTRIDGE_SLOT = &device_creator; + + + +//************************************************************************** +// CARD INTERFACE +//************************************************************************** + +//------------------------------------------------- +// device_ql_rom_cartridge_card_interface - constructor +//------------------------------------------------- + +device_ql_rom_cartridge_card_interface::device_ql_rom_cartridge_card_interface(const machine_config &mconfig, device_t &device) : + device_slot_card_interface(mconfig, device), + m_rom(*this, "rom"), + m_romoeh(0) +{ + m_slot = dynamic_cast(device.owner()); +} + + +//------------------------------------------------- +// ~device_ql_rom_cartridge_card_interface - destructor +//------------------------------------------------- + +device_ql_rom_cartridge_card_interface::~device_ql_rom_cartridge_card_interface() +{ +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// ql_rom_cartridge_slot_t - constructor +//------------------------------------------------- + +ql_rom_cartridge_slot_t::ql_rom_cartridge_slot_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, QL_ROM_CARTRIDGE_SLOT, "QL ROM cartridge slot", tag, owner, clock, "ql_rom_cartridge_slot", __FILE__), + device_slot_interface(mconfig, *this), + device_image_interface(mconfig, *this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void ql_rom_cartridge_slot_t::device_start() +{ + m_card = dynamic_cast(get_card_device()); +} + + +//------------------------------------------------- +// call_load - +//------------------------------------------------- + +bool ql_rom_cartridge_slot_t::call_load() +{ + if (m_card) + { + size_t size = 0; + + if (software_entry() == NULL) + { + size = length(); + + m_card->m_rom.allocate(size); + fread(m_card->m_rom, size); + } + else + { + load_software_region("rom", m_card->m_rom); + } + } + + return IMAGE_INIT_PASS; +} + + +//------------------------------------------------- +// call_softlist_load - +//------------------------------------------------- + +bool ql_rom_cartridge_slot_t::call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry) +{ + load_software_part_region(*this, swlist, swname, start_entry); + + return true; +} + + +//------------------------------------------------- +// get_default_card_software - +//------------------------------------------------- + +void ql_rom_cartridge_slot_t::get_default_card_software(std::string &result) +{ + software_get_default_slot(result, "standard"); +} + + +//------------------------------------------------- +// SLOT_INTERFACE( ql_rom_cartridge_cards ) +//------------------------------------------------- + +// slot devices +#include "miracle_hd.h" +#include "std.h" + +SLOT_INTERFACE_START( ql_rom_cartridge_cards ) + SLOT_INTERFACE("mhd", MIRACLE_HARD_DISK) + + // the following need ROMs from the software list + SLOT_INTERFACE_INTERNAL("standard", QL_STANDARD_ROM_CARTRIDGE) +SLOT_INTERFACE_END diff --git a/src/devices/bus/ql/rom.h b/src/devices/bus/ql/rom.h new file mode 100644 index 00000000000..a8b82d0dc57 --- /dev/null +++ b/src/devices/bus/ql/rom.h @@ -0,0 +1,126 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Sinclair QL ROM cartridge port emulation + +********************************************************************** + + A B + * 1 * VDD + A12 * 2 * A14 + A7 * 3 * A13 + A6 * 4 * A8 + A5 * 5 * A9 + SLOT 6 SLOT + A4 * 7 * A11 + A3 * 8 * ROMOEH + A2 * 9 * A10 + A1 * 10 * A15 + A0 * 11 * D7 + D0 * 12 * D6 + D1 * 13 * D5 + D2 * 14 * D4 + GND * 15 * D3 + +**********************************************************************/ + +#pragma once + +#ifndef __QL_ROM_CARTRIDGE_SLOT__ +#define __QL_ROM_CARTRIDGE_SLOT__ + +#include "emu.h" + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_QL_ROM_CARTRIDGE_SLOT_ADD(_tag, _slot_intf, _def_slot) \ + MCFG_DEVICE_ADD(_tag, QL_ROM_CARTRIDGE_SLOT, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> device_ql_rom_cartridge_card_interface + +class ql_rom_cartridge_slot_t; + +class device_ql_rom_cartridge_card_interface : public device_slot_card_interface +{ + friend class ql_rom_cartridge_slot_t; + +public: + // construction/destruction + device_ql_rom_cartridge_card_interface(const machine_config &mconfig, device_t &device); + virtual ~device_ql_rom_cartridge_card_interface(); + + virtual void romoeh_w(int state) { m_romoeh = state; } + virtual UINT8 read(address_space &space, offs_t offset, UINT8 data) { return data; } + virtual void write(address_space &space, offs_t offset, UINT8 data) { } + +protected: + ql_rom_cartridge_slot_t *m_slot; + + optional_shared_ptr m_rom; + + int m_romoeh; +}; + + +// ======================> ql_rom_cartridge_slot_t + +class ql_rom_cartridge_slot_t : public device_t, + public device_slot_interface, + public device_image_interface +{ +public: + // construction/destruction + ql_rom_cartridge_slot_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // computer interface + UINT8 read(address_space &space, offs_t offset, UINT8 data) { if (m_card) data = m_card->read(space, offset, data); return data; } + void write(address_space &space, offs_t offset, UINT8 data) { if (m_card) m_card->write(space, offset, data); } + DECLARE_WRITE_LINE_MEMBER( romoeh_w ) { if (m_card) m_card->romoeh_w(state); } + +protected: + // device-level overrides + virtual void device_config_complete() { update_names(); } + virtual void device_start(); + + // image-level overrides + virtual bool call_load(); + virtual bool call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry); + + virtual iodevice_t image_type() const { return IO_CARTSLOT; } + + virtual bool is_readable() const { return 1; } + virtual bool is_writeable() const { return 0; } + virtual bool is_creatable() const { return 0; } + virtual bool must_be_loaded() const { return 0; } + virtual bool is_reset_on_load() const { return 1; } + virtual const char *image_interface() const { return "ql_cart"; } + virtual const char *file_extensions() const { return "rom,bin"; } + virtual const option_guide *create_option_guide() const { return NULL; } + + // slot interface overrides + virtual void get_default_card_software(std::string &result); + + device_ql_rom_cartridge_card_interface *m_card; +}; + + +// device type definition +extern const device_type QL_ROM_CARTRIDGE_SLOT; + +SLOT_INTERFACE_EXTERN( ql_rom_cartridge_cards ); + + + +#endif diff --git a/src/devices/bus/ql/sandy_superdisk.c b/src/devices/bus/ql/sandy_superdisk.c new file mode 100644 index 00000000000..cf334d6db67 --- /dev/null +++ b/src/devices/bus/ql/sandy_superdisk.c @@ -0,0 +1,275 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder, Phill Harvey-Smith +/********************************************************************** + + Sandy Super Disk emulation + +**********************************************************************/ + +#include "sandy_superdisk.h" + + + +//************************************************************************** +// MACROS/CONSTANTS +//************************************************************************** + +#define WD1772_TAG "wd1772" +#define TTL74273_TAG "ttl74273" +#define CENTRONICS_TAG "centronics" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type SANDY_SUPER_DISK = &device_creator; + + +//------------------------------------------------- +// ROM( sandy_super_disk ) +//------------------------------------------------- + +ROM_START( sandy_super_disk ) + ROM_REGION( 0x4000, "rom", 0 ) + ROM_LOAD( "sandysuperdisk.rom", 0x0000, 0x4000, CRC(b52077da) SHA1(bf531758145ffd083e01c1cf9c45d0e9264a3b53) ) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *sandy_super_disk_t::device_rom_region() const +{ + return ROM_NAME( sandy_super_disk ); +} + + +//------------------------------------------------- +// SLOT_INTERFACE( sandy_super_disk_floppies ) +//------------------------------------------------- + +static SLOT_INTERFACE_START( sandy_super_disk_floppies ) + SLOT_INTERFACE( "35dd", FLOPPY_35_DD ) +SLOT_INTERFACE_END + + +//------------------------------------------------- +// FLOPPY_FORMATS( floppy_formats ) +//------------------------------------------------- + +FLOPPY_FORMATS_MEMBER( sandy_super_disk_t::floppy_formats ) + FLOPPY_QL_FORMAT +FLOPPY_FORMATS_END + + +//------------------------------------------------- +// centronics +//------------------------------------------------- + +WRITE_LINE_MEMBER( sandy_super_disk_t::busy_w ) +{ + m_busy = state; + check_interrupt(); +} + + +//------------------------------------------------- +// MACHINE_CONFIG_FRAGMENT( sandy_super_disk ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( sandy_super_disk ) + MCFG_DEVICE_ADD(WD1772_TAG, WD1772, 8000000) + MCFG_FLOPPY_DRIVE_ADD(WD1772_TAG":0", sandy_super_disk_floppies, "35dd", sandy_super_disk_t::floppy_formats) + MCFG_FLOPPY_DRIVE_ADD(WD1772_TAG":1", sandy_super_disk_floppies, NULL, sandy_super_disk_t::floppy_formats) + + MCFG_CENTRONICS_ADD(CENTRONICS_TAG, centronics_devices, "printer") + MCFG_CENTRONICS_BUSY_HANDLER(WRITELINE(sandy_super_disk_t, busy_w)) + MCFG_CENTRONICS_OUTPUT_LATCH_ADD(TTL74273_TAG, CENTRONICS_TAG) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor sandy_super_disk_t::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( sandy_super_disk ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// sandy_super_disk_t - constructor +//------------------------------------------------- + +sandy_super_disk_t::sandy_super_disk_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, SANDY_SUPER_DISK, "Sandy Super Disk", tag, owner, clock, "ql_sdisk", __FILE__), + device_ql_expansion_card_interface(mconfig, *this), + m_fdc(*this, WD1772_TAG), + m_floppy0(*this, WD1772_TAG":0"), + m_floppy1(*this, WD1772_TAG":1"), + m_centronics(*this, CENTRONICS_TAG), + m_latch(*this, TTL74273_TAG), + m_rom(*this, "rom"), + m_busy(1) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void sandy_super_disk_t::device_start() +{ + // state saving + save_item(NAME(m_busy)); + save_item(NAME(m_fd6)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void sandy_super_disk_t::device_reset() +{ + m_fdc->reset(); + m_fdc->set_floppy(NULL); + m_fdc->dden_w(0); + + m_latch->write(0); + m_centronics->write_strobe(1); +} + + +//------------------------------------------------- +// read - +//------------------------------------------------- + +UINT8 sandy_super_disk_t::read(address_space &space, offs_t offset, UINT8 data) +{ + if ((offset & 0xf0000) == 0xc0000) + { + if ((offset & 0xffc0) == 0x3fc0) + { + switch ((offset >> 2) & 0x03) + { + case 0: + data = m_fdc->read(space, offset & 0x03); + break; + + case 3: + /* + + bit description + + 0 BUSY + 1 + 2 + 3 + 4 + 5 + 6 + 7 + + */ + + data = m_busy; + break; + } + } + else if (offset < 0xc4000) + { + data = m_rom->base()[offset & 0x3fff]; + } + } + + return data; +} + + +//------------------------------------------------- +// write - +//------------------------------------------------- + +void sandy_super_disk_t::write(address_space &space, offs_t offset, UINT8 data) +{ + if ((offset & 0xf0000) == 0xc0000) + { + if ((offset & 0xffc0) == 0x3fc0) + { + switch ((offset >> 2) & 0x03) + { + case 0: + m_fdc->write(space, offset & 0x03, data); + break; + + case 1: + { + /* + + bit description + + 0 SIDE ONE + 1 DSEL0 + 2 DSEL1 + 3 M ON0 + 4 /DDEN + 5 STROBE inverted + 6 enable printer interrupt + 7 + + */ + + floppy_image_device *floppy = NULL; + + if (BIT(data, 1)) + { + floppy = m_floppy0->get_device(); + } + else if (BIT(data, 2)) + { + floppy = m_floppy1->get_device(); + } + + m_fdc->set_floppy(floppy); + + if (floppy) + { + floppy->ss_w(BIT(data, 0)); + floppy->mon_w(!BIT(data, 3)); + } + + m_fdc->dden_w(BIT(data, 4)); + + m_centronics->write_strobe(!BIT(data, 5)); + + m_fd6 = BIT(data, 6); + check_interrupt(); + } + break; + + case 2: + m_latch->write(data); + break; + } + } + } +} + +void sandy_super_disk_t::check_interrupt() +{ + int extint = m_fd6 && m_busy; + + m_slot->extintl_w(extint ? ASSERT_LINE : CLEAR_LINE); +} diff --git a/src/devices/bus/ql/sandy_superdisk.h b/src/devices/bus/ql/sandy_superdisk.h new file mode 100644 index 00000000000..350ba709c72 --- /dev/null +++ b/src/devices/bus/ql/sandy_superdisk.h @@ -0,0 +1,70 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder, Phill Harvey-Smith +/********************************************************************** + + Sandy Super Disk emulation + +**********************************************************************/ + +#pragma once + +#ifndef __SANDY_SUPER_DISK__ +#define __SANDY_SUPER_DISK__ + +#include "exp.h" +#include "bus/centronics/ctronics.h" +#include "formats/ql_dsk.h" +#include "machine/wd_fdc.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> sandy_super_disk_device + +class sandy_super_disk_t : public device_t, + public device_ql_expansion_card_interface +{ +public: + // construction/destruction + sandy_super_disk_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + + WRITE_LINE_MEMBER( busy_w ); + + DECLARE_FLOPPY_FORMATS( floppy_formats ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_ql_expansion_card_interface overrides + virtual UINT8 read(address_space &space, offs_t offset, UINT8 data); + virtual void write(address_space &space, offs_t offset, UINT8 data); + +private: + void check_interrupt(); + + required_device m_fdc; + required_device m_floppy0; + required_device m_floppy1; + required_device m_centronics; + required_device m_latch; + required_memory_region m_rom; + + int m_busy; + int m_fd6; +}; + + +// device type definition +extern const device_type SANDY_SUPER_DISK; + + +#endif diff --git a/src/devices/bus/ql/sandy_superqboard.c b/src/devices/bus/ql/sandy_superqboard.c new file mode 100644 index 00000000000..3e5558302db --- /dev/null +++ b/src/devices/bus/ql/sandy_superqboard.c @@ -0,0 +1,453 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder, Phill Harvey-Smith +/********************************************************************** + + Sandy SuperQBoard/SuperQMouse (with HD upgrade) emulation + +**********************************************************************/ + +#include "sandy_superqboard.h" + + + +//************************************************************************** +// MACROS/CONSTANTS +//************************************************************************** + +#define WD1772_TAG "ic3" +#define TTL74273_TAG "ic10" +#define CENTRONICS_TAG "j2" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type SANDY_SUPERQBOARD = &device_creator; +const device_type SANDY_SUPERQBOARD_512K = &device_creator; +const device_type SANDY_SUPERQMOUSE = &device_creator; +const device_type SANDY_SUPERQMOUSE_512K = &device_creator; + + +//------------------------------------------------- +// ROM( sandy_superqboard ) +//------------------------------------------------- + +ROM_START( sandy_superqboard ) + ROM_REGION( 0x8000, "rom", 0 ) + ROM_DEFAULT_BIOS("v118y") + ROM_SYSTEM_BIOS( 0, "v118y", "v1.18" ) + ROMX_LOAD( "sandy_disk_controller_v1.18y_1984.ic2", 0x0000, 0x8000, CRC(d02425be) SHA1(e730576e3e0c6a1acad042c09e15fc62a32d8fbd), ROM_BIOS(1) ) + ROM_SYSTEM_BIOS( 1, "v119", "v1.19N" ) + ROMX_LOAD( "sandysuperqboard_119n.ic2", 0x0000, 0x8000, CRC(5df04059) SHA1(51403f82a2eed3ef689e880936d1613e2b29c218), ROM_BIOS(2) ) + ROM_SYSTEM_BIOS( 2, "v121n", "v1.21N" ) + ROMX_LOAD( "sandy_disk_controller_v1.21n_1984_tk2.ic2", 0x0000, 0x8000, CRC(6a7a6a12) SHA1(a3a233e4f6c8450055fa537601a2a2eef143edca), ROM_BIOS(3) ) + + ROM_REGION( 0x100, "plds", 0 ) + ROM_LOAD( "gal16v8.ic5", 0x000, 0x100, NO_DUMP ) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *sandy_superqboard_t::device_rom_region() const +{ + return ROM_NAME( sandy_superqboard ); +} + + +//------------------------------------------------- +// SLOT_INTERFACE( sandy_superqboard_floppies ) +//------------------------------------------------- + +static SLOT_INTERFACE_START( sandy_superqboard_floppies ) + SLOT_INTERFACE( "35dd", FLOPPY_35_DD ) + SLOT_INTERFACE( "35hd", FLOPPY_35_HD ) +SLOT_INTERFACE_END + + +//------------------------------------------------- +// FLOPPY_FORMATS( floppy_formats ) +//------------------------------------------------- + +FLOPPY_FORMATS_MEMBER( sandy_superqboard_t::floppy_formats ) + FLOPPY_QL_FORMAT +FLOPPY_FORMATS_END + + +//------------------------------------------------- +// centronics +//------------------------------------------------- + +WRITE_LINE_MEMBER( sandy_superqboard_t::busy_w ) +{ + if (state) + { + m_status |= ST_BUSY; + } + else + { + m_status &= ~ST_BUSY; + } + + check_interrupt(); +} + + +//------------------------------------------------- +// MACHINE_CONFIG_FRAGMENT( sandy_superqboard ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( sandy_superqboard ) + MCFG_DEVICE_ADD(WD1772_TAG, WD1772, XTAL_16MHz/2) + MCFG_FLOPPY_DRIVE_ADD(WD1772_TAG":0", sandy_superqboard_floppies, "35hd", sandy_superqboard_t::floppy_formats) + MCFG_FLOPPY_DRIVE_ADD(WD1772_TAG":1", sandy_superqboard_floppies, NULL, sandy_superqboard_t::floppy_formats) + + MCFG_CENTRONICS_ADD(CENTRONICS_TAG, centronics_devices, "printer") + MCFG_CENTRONICS_BUSY_HANDLER(WRITELINE(sandy_superqboard_t, busy_w)) + MCFG_CENTRONICS_OUTPUT_LATCH_ADD(TTL74273_TAG, CENTRONICS_TAG) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor sandy_superqboard_t::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( sandy_superqboard ); +} + + +//------------------------------------------------- +// INPUT_CHANGED_MEMBER( mouse_x_changed ) +//------------------------------------------------- + +INPUT_CHANGED_MEMBER( sandy_superqboard_t::mouse_x_changed ) +{ + if (newval < oldval) + { + m_status |= ST_X_DIR; + } + else + { + m_status &= ~ST_X_DIR; + } + + m_status |= ST_X_INT; + + check_interrupt(); +} + + +//------------------------------------------------- +// INPUT_CHANGED_MEMBER( mouse_y_changed ) +//------------------------------------------------- + +INPUT_CHANGED_MEMBER( sandy_superqboard_t::mouse_y_changed ) +{ + if (newval < oldval) + { + m_status |= ST_Y_DIR; + } + else + { + m_status &= ~ST_Y_DIR; + } + + m_status |= ST_Y_INT; + + check_interrupt(); +} + + +//------------------------------------------------- +// INPUT_PORTS( sandy_superqmouse ) +//------------------------------------------------- + +INPUT_PORTS_START( sandy_superqmouse ) + PORT_START("mouse_x") + PORT_BIT( 0xff, 0x00, IPT_MOUSE_X ) PORT_SENSITIVITY(50) PORT_KEYDELTA(5) PORT_MINMAX(0, 255) PORT_CHANGED_MEMBER(DEVICE_SELF, sandy_superqboard_t, mouse_x_changed, 0) + + PORT_START("mouse_y") + PORT_BIT( 0xff, 0x00, IPT_MOUSE_Y ) PORT_SENSITIVITY(50) PORT_KEYDELTA(5) PORT_MINMAX(0, 255) PORT_CHANGED_MEMBER(DEVICE_SELF, sandy_superqboard_t, mouse_y_changed, 0) + + PORT_START("mouse_buttons") + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_NAME("Middle Mouse Button") PORT_CODE(MOUSECODE_BUTTON3) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_NAME("Right Mouse Button") PORT_CODE(MOUSECODE_BUTTON2) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_NAME("Left Mouse Button") PORT_CODE(MOUSECODE_BUTTON1) +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor sandy_superqmouse_t::device_input_ports() const +{ + return INPUT_PORTS_NAME( sandy_superqmouse ); +} + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor sandy_superqmouse_512k_t::device_input_ports() const +{ + return INPUT_PORTS_NAME( sandy_superqmouse ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// sandy_superqboard_t - constructor +//------------------------------------------------- + +sandy_superqboard_t::sandy_superqboard_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, SANDY_SUPERQBOARD, "Sandy SuperQBoard 256K", tag, owner, clock, "ql_sqboard256", __FILE__), + device_ql_expansion_card_interface(mconfig, *this), + m_fdc(*this, WD1772_TAG), + m_floppy0(*this, WD1772_TAG":0"), + m_floppy1(*this, WD1772_TAG":1"), + m_centronics(*this, CENTRONICS_TAG), + m_latch(*this, TTL74273_TAG), + m_rom(*this, "rom"), + m_ram(*this, "ram"), + m_buttons(*this, "mouse_buttons"), + m_ram_size(256*1024), + m_fd6(0), + m_fd7(0), + m_status(0) +{ +} + +sandy_superqboard_t::sandy_superqboard_t(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source, int ram_size) : + device_t(mconfig, type, name, tag, owner, clock, shortname, __FILE__), + device_ql_expansion_card_interface(mconfig, *this), + m_fdc(*this, WD1772_TAG), + m_floppy0(*this, WD1772_TAG":0"), + m_floppy1(*this, WD1772_TAG":1"), + m_centronics(*this, CENTRONICS_TAG), + m_latch(*this, TTL74273_TAG), + m_rom(*this, "rom"), + m_ram(*this, "ram"), + m_buttons(*this, "mouse_buttons"), + m_ram_size(ram_size), + m_fd6(0), + m_fd7(0), + m_status(0) +{ +} + +sandy_superqboard_512k_t::sandy_superqboard_512k_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : sandy_superqboard_t(mconfig, SANDY_SUPERQBOARD_512K, "Sandy SuperQBoard 512K", tag, owner, clock, "ql_sqboard512", __FILE__, 512*1024) { } + +sandy_superqmouse_t::sandy_superqmouse_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : sandy_superqboard_t(mconfig, SANDY_SUPERQMOUSE, "Sandy SuperQMouse", tag, owner, clock, "ql_sqmouse", __FILE__, 256*1024) { } + +sandy_superqmouse_512k_t::sandy_superqmouse_512k_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : sandy_superqboard_t(mconfig, SANDY_SUPERQMOUSE_512K, "Sandy SuperQMouse 512K", tag, owner, clock, "ql_sqmouse512", __FILE__, 512*1024) { } + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void sandy_superqboard_t::device_start() +{ + // allocate memory + m_ram.allocate(m_ram_size); + + // state saving + save_item(NAME(m_fd6)); + save_item(NAME(m_fd7)); + save_item(NAME(m_status)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void sandy_superqboard_t::device_reset() +{ + m_fdc->reset(); + m_fdc->set_floppy(NULL); + m_fdc->dden_w(0); + + m_latch->write(0); + m_centronics->write_strobe(1); + + m_fd6 = 0; + m_fd7 = 0; + m_status = 0; + + check_interrupt(); +} + + +//------------------------------------------------- +// read - +//------------------------------------------------- + +UINT8 sandy_superqboard_t::read(address_space &space, offs_t offset, UINT8 data) +{ + if ((offset & 0xf0000) == 0xc0000) + { + if ((offset & 0xffc0) == 0x3fc0) + { + switch ((offset >> 2) & 0x07) + { + case 0: + data = m_fdc->read(space, offset & 0x03); + break; + + case 3: + /* + + bit description + + 0 BUSY + 1 mouse pin 8 (middle button) + 2 mouse pin 1 (right button) + 3 mouse pin 2 (left button) + 4 mouse pin 4 flip-flop Q (Y direction) + 5 mouse pin 3 flip-flop Q (X direction) + 6 INT3 (Y interrupt) + 7 INT2 (X interrupt) + + */ + + data = m_buttons->read() & 0x0e; + data |= m_status & 0xf1; + break; + + case 4: + m_status &= ~(ST_Y_INT | ST_X_INT); + check_interrupt(); + break; + } + } + else if (offset < 0xc8000) + { + data = m_rom->base()[offset & 0x7fff]; + } + } + + if (offset >= 0x40000 && offset < 0xc0000) + { + if ((offset - 0x40000) < m_ram_size) + { + data = m_ram[offset - 0x40000]; + } + } + + return data; +} + + +//------------------------------------------------- +// write - +//------------------------------------------------- + +void sandy_superqboard_t::write(address_space &space, offs_t offset, UINT8 data) +{ + if ((offset & 0xf0000) == 0xc0000) + { + if ((offset & 0xffc0) == 0x3fc0) + { + switch ((offset >> 2) & 0x07) + { + case 0: + m_fdc->write(space, offset & 0x03, data); + break; + + case 1: + { + /* + + bit description + + 0 SIDE ONE + 1 DSEL0 + 2 DSEL1 + 3 M ON0 + 4 /DDEN + 5 STROBE inverted + 6 enable printer interrupt (GAL pin 11) + 7 enable mouse interrupt (GAL pin 9) + + */ + + floppy_image_device *floppy = NULL; + + if (BIT(data, 1)) + { + floppy = m_floppy0->get_device(); + } + else if (BIT(data, 2)) + { + floppy = m_floppy1->get_device(); + } + + m_fdc->set_floppy(floppy); + + if (floppy) + { + floppy->ss_w(BIT(data, 0)); + floppy->mon_w(!BIT(data, 3)); + } + + m_fdc->dden_w(BIT(data, 4)); + + m_centronics->write_strobe(!BIT(data, 5)); + + m_fd6 = BIT(data, 6); + m_fd7 = BIT(data, 7); + + check_interrupt(); + } + break; + + case 2: + m_latch->write(data); + break; + + case 4: + m_status &= ~(ST_Y_INT | ST_X_INT); + check_interrupt(); + break; + + case 5: + m_fdc->set_unscaled_clock(XTAL_16MHz / (BIT(data, 0) ? 1 : 2)); + break; + } + } + } + + if (offset >= 0x40000 && offset < 0xc0000) + { + if ((offset - 0x40000) < m_ram_size) + { + m_ram[offset - 0x40000] = data; + } + } +} + +void sandy_superqboard_t::check_interrupt() +{ + bool busy_int = m_fd6 && (m_status & ST_BUSY); + bool mouse_int = m_fd7 && (m_status & (ST_Y_INT | ST_X_INT)); + bool extint = busy_int || mouse_int; + + m_slot->extintl_w(extint ? ASSERT_LINE : CLEAR_LINE); +} diff --git a/src/devices/bus/ql/sandy_superqboard.h b/src/devices/bus/ql/sandy_superqboard.h new file mode 100644 index 00000000000..07bcd60a137 --- /dev/null +++ b/src/devices/bus/ql/sandy_superqboard.h @@ -0,0 +1,131 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder, Phill Harvey-Smith +/********************************************************************** + + Sandy SuperQBoard/SuperQMouse (with HD upgrade) emulation + +**********************************************************************/ + +#pragma once + +#ifndef __SANDY_SUPERQBOARD__ +#define __SANDY_SUPERQBOARD__ + +#include "exp.h" +#include "bus/centronics/ctronics.h" +#include "formats/ql_dsk.h" +#include "machine/wd_fdc.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> sandy_superqboard_t + +class sandy_superqboard_t : public device_t, + public device_ql_expansion_card_interface +{ +public: + // construction/destruction + sandy_superqboard_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + sandy_superqboard_t(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source, int ram_size); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + + WRITE_LINE_MEMBER( busy_w ); + + DECLARE_FLOPPY_FORMATS( floppy_formats ); + + DECLARE_INPUT_CHANGED_MEMBER( mouse_x_changed ); + DECLARE_INPUT_CHANGED_MEMBER( mouse_y_changed ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_ql_expansion_card_interface overrides + virtual UINT8 read(address_space &space, offs_t offset, UINT8 data); + virtual void write(address_space &space, offs_t offset, UINT8 data); + +private: + enum + { + ST_BUSY = 0x01, + ST_MIDDLE = 0x02, + ST_RIGHT = 0x04, + ST_LEFT = 0x08, + ST_Y_DIR = 0x10, + ST_X_DIR = 0x20, + ST_Y_INT = 0x40, + ST_X_INT = 0x80 + }; + + void check_interrupt(); + + required_device m_fdc; + required_device m_floppy0; + required_device m_floppy1; + required_device m_centronics; + required_device m_latch; + required_memory_region m_rom; + optional_shared_ptr m_ram; + optional_ioport m_buttons; + + int m_ram_size; + int m_fd6; + int m_fd7; + + UINT8 m_status; +}; + + +// ======================> sandy_superqboard_512k_t + +class sandy_superqboard_512k_t : public sandy_superqboard_t +{ +public: + // construction/destruction + sandy_superqboard_512k_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +// ======================> sandy_superqmouse_t + +class sandy_superqmouse_t : public sandy_superqboard_t +{ +public: + // construction/destruction + sandy_superqmouse_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual ioport_constructor device_input_ports() const; +}; + + +// ======================> sandy_superqmouse_512k_t + +class sandy_superqmouse_512k_t : public sandy_superqboard_t +{ +public: + // construction/destruction + sandy_superqmouse_512k_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual ioport_constructor device_input_ports() const; +}; + + +// device type definition +extern const device_type SANDY_SUPERQBOARD; +extern const device_type SANDY_SUPERQBOARD_512K; +extern const device_type SANDY_SUPERQMOUSE; +extern const device_type SANDY_SUPERQMOUSE_512K; + + + +#endif diff --git a/src/devices/bus/ql/std.c b/src/devices/bus/ql/std.c new file mode 100644 index 00000000000..11132954104 --- /dev/null +++ b/src/devices/bus/ql/std.c @@ -0,0 +1,57 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Sinclair QL standard ROM cartridge emulation + +**********************************************************************/ + +#include "std.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type QL_STANDARD_ROM_CARTRIDGE = &device_creator; + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// ql_standard_rom_cartridge_t - constructor +//------------------------------------------------- + +ql_standard_rom_cartridge_t::ql_standard_rom_cartridge_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, QL_STANDARD_ROM_CARTRIDGE, "QL standard ROM cartridge", tag, owner, clock, "ql_standard", __FILE__), + device_ql_rom_cartridge_card_interface(mconfig, *this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void ql_standard_rom_cartridge_t::device_start() +{ +} + + +//------------------------------------------------- +// read - cartridge data read +//------------------------------------------------- + +UINT8 ql_standard_rom_cartridge_t::read(address_space &space, offs_t offset, UINT8 data) +{ + if (m_romoeh && m_rom.bytes()) + { + data = m_rom[offset & m_rom.mask()]; + } + + return data; +} diff --git a/src/devices/bus/ql/std.h b/src/devices/bus/ql/std.h new file mode 100644 index 00000000000..70b1328d79c --- /dev/null +++ b/src/devices/bus/ql/std.h @@ -0,0 +1,44 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Sinclair QL standard ROM cartridge emulation + +**********************************************************************/ + +#pragma once + +#ifndef __QL_STANDARD_ROM_CARTRIDGE__ +#define __QL_STANDARD_ROM_CARTRIDGE__ + +#include "rom.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> ql_standard_rom_cartridge_t + +class ql_standard_rom_cartridge_t : public device_t, + public device_ql_rom_cartridge_card_interface +{ +public: + // construction/destruction + ql_standard_rom_cartridge_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // device-level overrides + virtual void device_start(); + + // device_ql_rom_cartridge_card_interface overrides + virtual UINT8 read(address_space &space, offs_t offset, UINT8 data); +}; + + +// device type definition +extern const device_type QL_STANDARD_ROM_CARTRIDGE; + + +#endif diff --git a/src/devices/bus/ql/trumpcard.c b/src/devices/bus/ql/trumpcard.c new file mode 100644 index 00000000000..fa77ed23d53 --- /dev/null +++ b/src/devices/bus/ql/trumpcard.c @@ -0,0 +1,291 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder, Phill Harvey-Smith +/********************************************************************** + + Miracle Systems QL Trump Card emulation + +**********************************************************************/ + +#include "trumpcard.h" + + + +//************************************************************************** +// MACROS/CONSTANTS +//************************************************************************** + +#define WD1772_TAG "wd1772" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type QL_TRUMP_CARD = &device_creator; +const device_type QL_TRUMP_CARD_256K = &device_creator; +const device_type QL_TRUMP_CARD_512K = &device_creator; +const device_type QL_TRUMP_CARD_768K = &device_creator; + + +//------------------------------------------------- +// ROM( ql_trump_card ) +//------------------------------------------------- + +ROM_START( ql_trump_card ) + ROM_REGION( 0x8000, "rom", 0 ) + ROM_DEFAULT_BIOS("v131") + ROM_SYSTEM_BIOS( 0, "v121a", "v1.21A" ) + ROMX_LOAD( "trump_card1v21a_256_bin", 0x0000, 0x8000, CRC(2eb0aa3a) SHA1(22da747afad5bc91184daf0d8b055a5e5264c67b), ROM_BIOS(1) ) + ROM_SYSTEM_BIOS( 1, "v125", "v1.25" ) + ROMX_LOAD( "trumpcard-125.rom", 0x0000, 0x8000, CRC(938eaa46) SHA1(9b3458cf3a279ed86ba395dc45c8f26939d6c44d), ROM_BIOS(2) ) + ROM_SYSTEM_BIOS( 2, "v127", "v1.27" ) + ROMX_LOAD( "trumpcard127.bin", 0x0000, 0x8000, CRC(3e053381) SHA1(69fa132cb73b9391a70e8fd3e5656890dbc0203f), ROM_BIOS(3) ) + ROM_SYSTEM_BIOS( 3, "v128", "v1.28" ) + ROMX_LOAD( "trump_card_v1_28.bin", 0x0000, 0x8000, CRC(4591a924) SHA1(3ad584ee74b6a7e46685e6b7bece1abe4d6f6937), ROM_BIOS(4) ) + ROM_SYSTEM_BIOS( 4, "v131", "v1.31" ) + ROMX_LOAD( "trumpcard131.bin", 0x0000, 0x8000, CRC(584c7835) SHA1(de0f67408021a3b33b3916514a5f81d9c8edad93), ROM_BIOS(5) ) + + ROM_REGION( 0x100, "plds", 0 ) + ROM_LOAD( "1u4", 0x000, 0x100, NO_DUMP ) + ROM_LOAD( "2u4", 0x000, 0x100, NO_DUMP ) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *ql_trump_card_t::device_rom_region() const +{ + return ROM_NAME( ql_trump_card ); +} + + +//------------------------------------------------- +// SLOT_INTERFACE( ql_trump_card_floppies ) +//------------------------------------------------- + +static SLOT_INTERFACE_START( ql_trump_card_floppies ) + SLOT_INTERFACE( "35dd", FLOPPY_35_DD ) +SLOT_INTERFACE_END + + +//------------------------------------------------- +// FLOPPY_FORMATS( floppy_formats ) +//------------------------------------------------- + +FLOPPY_FORMATS_MEMBER( ql_trump_card_t::floppy_formats ) + FLOPPY_QL_FORMAT +FLOPPY_FORMATS_END + + +//------------------------------------------------- +// MACHINE_CONFIG_FRAGMENT( ql_trump_card ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( ql_trump_card ) + MCFG_DEVICE_ADD(WD1772_TAG, WD1772, 8000000) + MCFG_FLOPPY_DRIVE_ADD(WD1772_TAG":0", ql_trump_card_floppies, "35dd", ql_trump_card_t::floppy_formats) + MCFG_FLOPPY_DRIVE_ADD(WD1772_TAG":1", ql_trump_card_floppies, NULL, ql_trump_card_t::floppy_formats) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor ql_trump_card_t::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( ql_trump_card ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// ql_trump_card_t - constructor +//------------------------------------------------- + +ql_trump_card_t::ql_trump_card_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, QL_TRUMP_CARD, "QL Trump Card", tag, owner, clock, "ql_trump", __FILE__), + device_ql_expansion_card_interface(mconfig, *this), + m_fdc(*this, WD1772_TAG), + m_floppy0(*this, WD1772_TAG":0"), + m_floppy1(*this, WD1772_TAG":1"), + m_rom(*this, "rom"), + m_ram(*this, "ram"), + m_ram_size(0) +{ +} + +ql_trump_card_t::ql_trump_card_t(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source, int ram_size) : + device_t(mconfig, type, name, tag, owner, clock, shortname, __FILE__), + device_ql_expansion_card_interface(mconfig, *this), + m_fdc(*this, WD1772_TAG), + m_floppy0(*this, WD1772_TAG":0"), + m_floppy1(*this, WD1772_TAG":1"), + m_rom(*this, "rom"), + m_ram(*this, "ram"), + m_ram_size(ram_size) +{ +} + +ql_trump_card_256k_t::ql_trump_card_256k_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : ql_trump_card_t(mconfig, QL_TRUMP_CARD_256K, "QL Trump Card 256K", tag, owner, clock, "ql_trump256", __FILE__, 256*1024) { } + +ql_trump_card_512k_t::ql_trump_card_512k_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : ql_trump_card_t(mconfig, QL_TRUMP_CARD_512K, "QL Trump Card 512K", tag, owner, clock, "ql_trump512", __FILE__, 512*1024) { } + +ql_trump_card_768k_t::ql_trump_card_768k_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : ql_trump_card_t(mconfig, QL_TRUMP_CARD_768K, "QL Trump Card 768K", tag, owner, clock, "ql_trump768", __FILE__, 768*1024) { } + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void ql_trump_card_t::device_start() +{ + // allocate memory + m_ram.allocate(m_ram_size); + + // state saving + save_item(NAME(m_rom_en)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void ql_trump_card_t::device_reset() +{ + m_fdc->set_floppy(NULL); + m_fdc->dden_w(0); + + m_rom_en = false; +} + + +//------------------------------------------------- +// read - +//------------------------------------------------- + +UINT8 ql_trump_card_t::read(address_space &space, offs_t offset, UINT8 data) +{ + if (offset >= 0xc000 && offset < 0x10000) + { + m_rom_en = true; + } + + if (offset >= 0x10000 && offset < 0x18000) + { + m_rom_en = false; + + data = m_rom->base()[offset & 0x7fff]; + } + + if (offset >= 0x1c000 && offset <= 0x1c003) + { + data = m_fdc->read(space, offset & 0x03); + } + + if (offset >= 0x40000 && offset < 0xc0000) + { + if ((offset - 0x40000) < m_ram_size) + { + data = m_ram[offset - 0x40000]; + } + } + + if (offset >= 0xc0000) + { + if (m_rom_en) + { + if (offset < 0xc8000) + { + data = m_rom->base()[offset & 0x7fff]; + } + } + else + { + if ((offset - 0x40000) < m_ram_size) + { + data = m_ram[offset - 0x40000]; + } + } + } + + return data; +} + + +//------------------------------------------------- +// write - +//------------------------------------------------- + +void ql_trump_card_t::write(address_space &space, offs_t offset, UINT8 data) +{ + if (offset >= 0x1c000 && offset <= 0x1c003) + { + m_fdc->write(space, offset & 0x03, data); + } + + if (offset == 0x1e000) + { + /* + + bit description + + 0 DRIVE1 + 1 DRIVE0 + 2 MOTOR + 3 SIDE + 4 + 5 + 6 + 7 + + */ + + floppy_image_device *floppy = NULL; + + if (BIT(data, 1)) + { + floppy = m_floppy0->get_device(); + } + else if (BIT(data, 0)) + { + floppy = m_floppy1->get_device(); + } + + m_fdc->set_floppy(floppy); + + if (floppy) + { + floppy->ss_w(BIT(data, 3)); + floppy->mon_w(!BIT(data, 2)); + } + } + + if (offset >= 0x40000 && offset < 0xc0000) + { + if ((offset - 0x40000) < m_ram_size) + { + m_ram[offset - 0x40000] = data; + } + } + + if (offset >= 0xc0000) + { + if (!m_rom_en) + { + m_ram[offset - 0x40000] = data; + } + } +} diff --git a/src/devices/bus/ql/trumpcard.h b/src/devices/bus/ql/trumpcard.h new file mode 100644 index 00000000000..4c303aafd3e --- /dev/null +++ b/src/devices/bus/ql/trumpcard.h @@ -0,0 +1,100 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder, Phill Harvey-Smith +/********************************************************************** + + Miracle Systems QL Trump Card emulation + +**********************************************************************/ + +#pragma once + +#ifndef __QL_TRUMP_CARD__ +#define __QL_TRUMP_CARD__ + +#include "exp.h" +#include "machine/wd_fdc.h" +#include "formats/ql_dsk.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> ql_trump_card_t + +class ql_trump_card_t : public device_t, + public device_ql_expansion_card_interface +{ +public: + // construction/destruction + ql_trump_card_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + ql_trump_card_t(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source, int ram_size); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + + DECLARE_FLOPPY_FORMATS( floppy_formats ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_ql_expansion_card_interface overrides + virtual UINT8 read(address_space &space, offs_t offset, UINT8 data); + virtual void write(address_space &space, offs_t offset, UINT8 data); + +private: + required_device m_fdc; + required_device m_floppy0; + required_device m_floppy1; + required_memory_region m_rom; + optional_shared_ptr m_ram; + + int m_ram_size; + bool m_rom_en; +}; + + +// ======================> ql_trump_card_256k_t + +class ql_trump_card_256k_t : public ql_trump_card_t +{ +public: + // construction/destruction + ql_trump_card_256k_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +// ======================> ql_trump_card_512k_t + +class ql_trump_card_512k_t : public ql_trump_card_t +{ +public: + // construction/destruction + ql_trump_card_512k_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +// ======================> ql_trump_card_768k_t + +class ql_trump_card_768k_t : public ql_trump_card_t +{ +public: + // construction/destruction + ql_trump_card_768k_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + + +// device type definition +extern const device_type QL_TRUMP_CARD; +extern const device_type QL_TRUMP_CARD_256K; +extern const device_type QL_TRUMP_CARD_512K; +extern const device_type QL_TRUMP_CARD_768K; + + + +#endif diff --git a/src/devices/bus/rs232/keyboard.c b/src/devices/bus/rs232/keyboard.c new file mode 100644 index 00000000000..f30d8476d56 --- /dev/null +++ b/src/devices/bus/rs232/keyboard.c @@ -0,0 +1,115 @@ +// license:BSD-3-Clause +// copyright-holders:smf +#include "keyboard.h" + +serial_keyboard_device::serial_keyboard_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : generic_keyboard_device(mconfig, SERIAL_KEYBOARD, "Serial Keyboard", tag, owner, clock, "serial_keyboard", __FILE__), + device_serial_interface(mconfig, *this), + device_rs232_port_interface(mconfig, *this), + m_key_valid(false), + m_rs232_txbaud(*this, "RS232_TXBAUD"), + m_rs232_startbits(*this, "RS232_STARTBITS"), + m_rs232_databits(*this, "RS232_DATABITS"), + m_rs232_parity(*this, "RS232_PARITY"), + m_rs232_stopbits(*this, "RS232_STOPBITS") +{ +} + +serial_keyboard_device::serial_keyboard_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : generic_keyboard_device(mconfig, type, name, tag, owner, clock, shortname, source), + device_serial_interface(mconfig, *this), + device_rs232_port_interface(mconfig, *this), + m_key_valid(false), + m_rs232_txbaud(*this, "RS232_TXBAUD"), + m_rs232_startbits(*this, "RS232_STARTBITS"), + m_rs232_databits(*this, "RS232_DATABITS"), + m_rs232_parity(*this, "RS232_PARITY"), + m_rs232_stopbits(*this, "RS232_STOPBITS") +{ +} + +static INPUT_PORTS_START(serial_keyboard) + PORT_INCLUDE(generic_keyboard) + + MCFG_RS232_BAUD("RS232_TXBAUD", RS232_BAUD_9600, "TX Baud", serial_keyboard_device, update_serial) + MCFG_RS232_STARTBITS("RS232_STARTBITS", RS232_STARTBITS_1, "Start Bits", serial_keyboard_device, update_serial) + MCFG_RS232_DATABITS("RS232_DATABITS", RS232_DATABITS_8, "Data Bits", serial_keyboard_device, update_serial) + MCFG_RS232_PARITY("RS232_PARITY", RS232_PARITY_NONE, "Parity", serial_keyboard_device, update_serial) + MCFG_RS232_STOPBITS("RS232_STOPBITS", RS232_STOPBITS_1, "Stop Bits", serial_keyboard_device, update_serial) +INPUT_PORTS_END + +ioport_constructor serial_keyboard_device::device_input_ports() const +{ + return INPUT_PORTS_NAME(serial_keyboard); +} + +void serial_keyboard_device::device_start() +{ + generic_keyboard_device::device_start(); + device_serial_interface::register_save_state(machine().save(), this); + save_item(NAME(m_curr_key)); + save_item(NAME(m_key_valid)); +} + +WRITE_LINE_MEMBER(serial_keyboard_device::update_serial) +{ + reset(); +} + +void serial_keyboard_device::device_reset() +{ + generic_keyboard_device::device_reset(); + + int startbits = convert_startbits(m_rs232_startbits->read()); + int databits = convert_databits(m_rs232_databits->read()); + parity_t parity = convert_parity(m_rs232_parity->read()); + stop_bits_t stopbits = convert_stopbits(m_rs232_stopbits->read()); + + set_data_frame(startbits, databits, parity, stopbits); + + int txbaud = convert_baud(m_rs232_txbaud->read()); + set_tra_rate(txbaud); + + output_rxd(1); + + // TODO: make this configurable + output_dcd(0); + output_dsr(0); + output_cts(0); + receive_register_reset(); +} + +void serial_keyboard_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + if (id) + device_serial_interface::device_timer(timer, id, param, ptr); + else + generic_keyboard_device::device_timer(timer, id, param, ptr); +} + +void serial_keyboard_device::send_key(UINT8 code) +{ + if(is_transmit_register_empty()) + { + transmit_register_setup(code); + return; + } + m_key_valid = true; + m_curr_key = code; +} + +void serial_keyboard_device::tra_callback() +{ + output_rxd(transmit_register_get_data_bit()); +} + +void serial_keyboard_device::tra_complete() +{ + if(m_key_valid) + { + transmit_register_setup(m_curr_key); + m_key_valid = false; + } +} + +const device_type SERIAL_KEYBOARD = &device_creator; diff --git a/src/devices/bus/rs232/keyboard.h b/src/devices/bus/rs232/keyboard.h new file mode 100644 index 00000000000..d2f12663d90 --- /dev/null +++ b/src/devices/bus/rs232/keyboard.h @@ -0,0 +1,48 @@ +// license:BSD-3-Clause +// copyright-holders:smf +#ifndef __RS232_KEYBOARD_H__ +#define __RS232_KEYBOARD_H__ + +#pragma once + +#include "rs232.h" +#include "machine/keyboard.h" + +class serial_keyboard_device : + public generic_keyboard_device, + public device_serial_interface, + public device_rs232_port_interface +{ +public: + serial_keyboard_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + serial_keyboard_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + virtual DECLARE_WRITE_LINE_MEMBER( input_txd ) { device_serial_interface::rx_w(state); } + DECLARE_READ_LINE_MEMBER(tx_r); + + virtual ioport_constructor device_input_ports() const; + + DECLARE_WRITE_LINE_MEMBER(update_serial); + +protected: + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + virtual void tra_callback(); + virtual void tra_complete(); + virtual void send_key(UINT8 code); + +private: + UINT8 m_curr_key; + bool m_key_valid; + + required_ioport m_rs232_txbaud; + required_ioport m_rs232_startbits; + required_ioport m_rs232_databits; + required_ioport m_rs232_parity; + required_ioport m_rs232_stopbits; +}; + +extern const device_type SERIAL_KEYBOARD; + +#endif /* __RS232_KEYBOARD_H__ */ diff --git a/src/devices/bus/rs232/loopback.c b/src/devices/bus/rs232/loopback.c new file mode 100644 index 00000000000..20c75e4099d --- /dev/null +++ b/src/devices/bus/rs232/loopback.c @@ -0,0 +1,42 @@ +// license:BSD-3-Clause +// copyright-holders:smf + +#include "loopback.h" + +const device_type RS232_LOOPBACK = &device_creator; + +rs232_loopback_device::rs232_loopback_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, RS232_LOOPBACK, "RS232 Loopback", tag, owner, clock, "rs232_loopback", __FILE__), + device_rs232_port_interface(mconfig, *this) +{ +} + +void rs232_loopback_device::device_start() +{ +} + +WRITE_LINE_MEMBER( rs232_loopback_device::input_txd ) +{ + if (started()) + { + output_rxd(state); + } +} + +WRITE_LINE_MEMBER( rs232_loopback_device::input_rts ) +{ + if (started()) + { + output_ri(state); + output_cts(state); + } +} + +WRITE_LINE_MEMBER( rs232_loopback_device::input_dtr ) +{ + if (started()) + { + output_dsr(state); + output_dcd(state); + } +} diff --git a/src/devices/bus/rs232/loopback.h b/src/devices/bus/rs232/loopback.h new file mode 100644 index 00000000000..3027fe167f3 --- /dev/null +++ b/src/devices/bus/rs232/loopback.h @@ -0,0 +1,25 @@ +// license:BSD-3-Clause +// copyright-holders:smf + +#ifndef RS232_LOOPBACK_H_ +#define RS232_LOOPBACK_H_ + +#include "rs232.h" + +class rs232_loopback_device : public device_t, + public device_rs232_port_interface +{ +public: + rs232_loopback_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual WRITE_LINE_MEMBER( input_txd ); + virtual WRITE_LINE_MEMBER( input_rts ); + virtual WRITE_LINE_MEMBER( input_dtr ); + +protected: + virtual void device_start(); +}; + +extern const device_type RS232_LOOPBACK; + +#endif diff --git a/src/devices/bus/rs232/null_modem.c b/src/devices/bus/rs232/null_modem.c new file mode 100644 index 00000000000..16fc4215c9a --- /dev/null +++ b/src/devices/bus/rs232/null_modem.c @@ -0,0 +1,131 @@ +// license:BSD-3-Clause +// copyright-holders:smf,Carl +#include "null_modem.h" + +null_modem_device::null_modem_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, NULL_MODEM, "Null Modem", tag, owner, clock, "null_modem", __FILE__), + device_serial_interface(mconfig, *this), + device_rs232_port_interface(mconfig, *this), + m_stream(*this, "stream"), + m_rs232_txbaud(*this, "RS232_TXBAUD"), + m_rs232_rxbaud(*this, "RS232_RXBAUD"), + m_rs232_startbits(*this, "RS232_STARTBITS"), + m_rs232_databits(*this, "RS232_DATABITS"), + m_rs232_parity(*this, "RS232_PARITY"), + m_rs232_stopbits(*this, "RS232_STOPBITS"), + m_input_count(0), + m_input_index(0) +{ +} + +static MACHINE_CONFIG_FRAGMENT(null_modem) + MCFG_DEVICE_ADD("stream", BITBANGER, 0) +MACHINE_CONFIG_END + +machine_config_constructor null_modem_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME(null_modem); +} + +static INPUT_PORTS_START(null_modem) + MCFG_RS232_BAUD("RS232_TXBAUD", RS232_BAUD_9600, "TX Baud", null_modem_device, update_serial) + MCFG_RS232_BAUD("RS232_RXBAUD", RS232_BAUD_9600, "RX Baud", null_modem_device, update_serial) + MCFG_RS232_STARTBITS("RS232_STARTBITS", RS232_STARTBITS_1, "Start Bits", null_modem_device, update_serial) + MCFG_RS232_DATABITS("RS232_DATABITS", RS232_DATABITS_8, "Data Bits", null_modem_device, update_serial) + MCFG_RS232_PARITY("RS232_PARITY", RS232_PARITY_NONE, "Parity", null_modem_device, update_serial) + MCFG_RS232_STOPBITS("RS232_STOPBITS", RS232_STOPBITS_1, "Stop Bits", null_modem_device, update_serial) +INPUT_PORTS_END + +ioport_constructor null_modem_device::device_input_ports() const +{ + return INPUT_PORTS_NAME(null_modem); +} + +void null_modem_device::device_start() +{ + m_timer_poll = timer_alloc(TIMER_POLL); +} + +WRITE_LINE_MEMBER(null_modem_device::update_serial) +{ + int startbits = convert_startbits(m_rs232_startbits->read()); + int databits = convert_databits(m_rs232_databits->read()); + parity_t parity = convert_parity(m_rs232_parity->read()); + stop_bits_t stopbits = convert_stopbits(m_rs232_stopbits->read()); + + set_data_frame(startbits, databits, parity, stopbits); + + int txbaud = convert_baud(m_rs232_txbaud->read()); + set_tra_rate(txbaud); + + int rxbaud = convert_baud(m_rs232_rxbaud->read()); + set_rcv_rate(rxbaud); + + output_rxd(1); + + // TODO: make this configurable + output_dcd(0); + output_dsr(0); + output_cts(0); +} + +void null_modem_device::device_reset() +{ + update_serial(0); + queue(); +} + +void null_modem_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch (id) + { + case TIMER_POLL: + queue(); + break; + + default: + device_serial_interface::device_timer(timer, id, param, ptr); + } +} + +void null_modem_device::queue() +{ + if (is_transmit_register_empty()) + { + if (m_input_index == m_input_count) + { + m_input_index = 0; + m_input_count = m_stream->input(m_input_buffer, sizeof(m_input_buffer)); + } + + if (m_input_count != 0) + { + transmit_register_setup(m_input_buffer[m_input_index++]); + + m_timer_poll->adjust(attotime::never); + } + else + { + int txbaud = convert_baud(m_rs232_txbaud->read()); + m_timer_poll->adjust(attotime::from_hz(txbaud)); + } + } +} + +void null_modem_device::tra_callback() +{ + output_rxd(transmit_register_get_data_bit()); +} + +void null_modem_device::tra_complete() +{ + queue(); +} + +void null_modem_device::rcv_complete() +{ + receive_register_extract(); + m_stream->output(get_received_char()); +} + +const device_type NULL_MODEM = &device_creator; diff --git a/src/devices/bus/rs232/null_modem.h b/src/devices/bus/rs232/null_modem.h new file mode 100644 index 00000000000..e985cafdda3 --- /dev/null +++ b/src/devices/bus/rs232/null_modem.h @@ -0,0 +1,53 @@ +// license:BSD-3-Clause +// copyright-holders:smf,Carl +#ifndef NULL_MODEM_H_ +#define NULL_MODEM_H_ + +#include "rs232.h" +#include "imagedev/bitbngr.h" + +class null_modem_device : public device_t, + public device_serial_interface, + public device_rs232_port_interface +{ +public: + null_modem_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual machine_config_constructor device_mconfig_additions() const; + + virtual WRITE_LINE_MEMBER( input_txd ) { device_serial_interface::rx_w(state); } + + DECLARE_WRITE_LINE_MEMBER(update_serial); + +protected: + virtual ioport_constructor device_input_ports() const; + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + virtual void tra_callback(); + virtual void tra_complete(); + virtual void rcv_complete(); + +private: + void queue(); + + static const int TIMER_POLL = 1; + + required_device m_stream; + + required_ioport m_rs232_txbaud; + required_ioport m_rs232_rxbaud; + required_ioport m_rs232_startbits; + required_ioport m_rs232_databits; + required_ioport m_rs232_parity; + required_ioport m_rs232_stopbits; + + UINT8 m_input_buffer[1000]; + UINT32 m_input_count; + UINT32 m_input_index; + emu_timer *m_timer_poll; +}; + +extern const device_type NULL_MODEM; + +#endif diff --git a/src/devices/bus/rs232/printer.c b/src/devices/bus/rs232/printer.c new file mode 100644 index 00000000000..e8734ad6de6 --- /dev/null +++ b/src/devices/bus/rs232/printer.c @@ -0,0 +1,85 @@ +// license:BSD-3-Clause +// copyright-holders:smf +#include "printer.h" + +serial_printer_device::serial_printer_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, SERIAL_PRINTER, "Serial Printer", tag, owner, clock, "serial_printer", __FILE__), + device_serial_interface(mconfig, *this), + device_rs232_port_interface(mconfig, *this), + m_printer(*this, "printer"), + m_rs232_rxbaud(*this, "RS232_RXBAUD"), + m_rs232_startbits(*this, "RS232_STARTBITS"), + m_rs232_databits(*this, "RS232_DATABITS"), + m_rs232_parity(*this, "RS232_PARITY"), + m_rs232_stopbits(*this, "RS232_STOPBITS") +{ +} + +static MACHINE_CONFIG_FRAGMENT(serial_printer) + MCFG_DEVICE_ADD("printer", PRINTER, 0) + MCFG_PRINTER_ONLINE_CB(WRITELINE(serial_printer_device, printer_online)) +MACHINE_CONFIG_END + +machine_config_constructor serial_printer_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME(serial_printer); +} + +static INPUT_PORTS_START(serial_printer) + MCFG_RS232_BAUD("RS232_RXBAUD", RS232_BAUD_9600, "RX Baud", serial_printer_device, update_serial) + MCFG_RS232_STARTBITS("RS232_STARTBITS", RS232_STARTBITS_1, "Start Bits", serial_printer_device, update_serial) + MCFG_RS232_DATABITS("RS232_DATABITS", RS232_DATABITS_8, "Data Bits", serial_printer_device, update_serial) + MCFG_RS232_PARITY("RS232_PARITY", RS232_PARITY_NONE, "Parity", serial_printer_device, update_serial) + MCFG_RS232_STOPBITS("RS232_STOPBITS", RS232_STOPBITS_1, "Stop Bits", serial_printer_device, update_serial) +INPUT_PORTS_END + +ioport_constructor serial_printer_device::device_input_ports() const +{ + return INPUT_PORTS_NAME(serial_printer); +} + +void serial_printer_device::device_start() +{ +} + +WRITE_LINE_MEMBER(serial_printer_device::update_serial) +{ + int startbits = convert_startbits(m_rs232_startbits->read()); + int databits = convert_databits(m_rs232_databits->read()); + parity_t parity = convert_parity(m_rs232_parity->read()); + stop_bits_t stopbits = convert_stopbits(m_rs232_stopbits->read()); + + set_data_frame(startbits, databits, parity, stopbits); + + int rxbaud = convert_baud(m_rs232_rxbaud->read()); + set_rcv_rate(rxbaud); + + // TODO: make this configurable + output_rxd(0); + output_dcd(0); + output_dsr(0); + output_cts(0); +} + +void serial_printer_device::device_reset() +{ + update_serial(0); +} + +WRITE_LINE_MEMBER(serial_printer_device::printer_online) +{ + /// TODO: ? +} + +void serial_printer_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + device_serial_interface::device_timer(timer, id, param, ptr); +} + +void serial_printer_device::rcv_complete() +{ + receive_register_extract(); + m_printer->output(get_received_char()); +} + +const device_type SERIAL_PRINTER = &device_creator; diff --git a/src/devices/bus/rs232/printer.h b/src/devices/bus/rs232/printer.h new file mode 100644 index 00000000000..ba36eef04eb --- /dev/null +++ b/src/devices/bus/rs232/printer.h @@ -0,0 +1,44 @@ +// license:BSD-3-Clause +// copyright-holders:smf +#ifndef __RS232_PRINTER_H__ +#define __RS232_PRINTER_H__ + +#pragma once + +#include "rs232.h" +#include "imagedev/printer.h" + +class serial_printer_device : public device_t, + public device_serial_interface, + public device_rs232_port_interface +{ +public: + serial_printer_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual DECLARE_WRITE_LINE_MEMBER( input_txd ) { device_serial_interface::rx_w(state); } + + DECLARE_WRITE_LINE_MEMBER(update_serial); + DECLARE_WRITE_LINE_MEMBER(printer_online); + +protected: + virtual machine_config_constructor device_mconfig_additions() const; + virtual ioport_constructor device_input_ports() const; + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + virtual void rcv_complete(); + +private: + required_device m_printer; + + required_ioport m_rs232_rxbaud; + required_ioport m_rs232_startbits; + required_ioport m_rs232_databits; + required_ioport m_rs232_parity; + required_ioport m_rs232_stopbits; +}; + +extern const device_type SERIAL_PRINTER; + +#endif diff --git a/src/devices/bus/rs232/rs232.c b/src/devices/bus/rs232/rs232.c new file mode 100644 index 00000000000..acc1af5dea3 --- /dev/null +++ b/src/devices/bus/rs232/rs232.c @@ -0,0 +1,113 @@ +// license:BSD-3-Clause +// copyright-holders:smf +#include "rs232.h" + +const device_type RS232_PORT = &device_creator; + +rs232_port_device::rs232_port_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, RS232_PORT, "RS232 Port", tag, owner, clock, "rs232", __FILE__), + device_slot_interface(mconfig, *this), + m_rxd_handler(*this), + m_dcd_handler(*this), + m_dsr_handler(*this), + m_ri_handler(*this), + m_cts_handler(*this), + m_dev(NULL) +{ +} + +rs232_port_device::rs232_port_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_slot_interface(mconfig, *this), + m_rxd_handler(*this), + m_dcd_handler(*this), + m_dsr_handler(*this), + m_ri_handler(*this), + m_cts_handler(*this), + m_dev(NULL) +{ +} + +rs232_port_device::~rs232_port_device() +{ +} + +void rs232_port_device::device_config_complete() +{ + m_dev = dynamic_cast(get_card_device()); +} + +void rs232_port_device::device_start() +{ + m_rxd_handler.resolve_safe(); + m_dcd_handler.resolve_safe(); + m_dsr_handler.resolve_safe(); + m_ri_handler.resolve_safe(); + m_cts_handler.resolve_safe(); + + save_item(NAME(m_rxd)); + save_item(NAME(m_dcd)); + save_item(NAME(m_dsr)); + save_item(NAME(m_ri)); + save_item(NAME(m_cts)); + + m_rxd = 1; + m_dcd = 1; + m_dsr = 1; + m_ri = 1; + m_cts = 1; + + m_rxd_handler(1); + m_dcd_handler(1); + m_dsr_handler(1); + m_ri_handler(1); + m_cts_handler(1); +} + +WRITE_LINE_MEMBER( rs232_port_device::write_txd ) +{ + if(m_dev) + m_dev->input_txd(state); +} + +WRITE_LINE_MEMBER( rs232_port_device::write_dtr ) +{ + if(m_dev) + m_dev->input_dtr(state); +} + +WRITE_LINE_MEMBER( rs232_port_device::write_rts ) +{ + if(m_dev) + m_dev->input_rts(state); +} + +WRITE_LINE_MEMBER( rs232_port_device::write_etc ) +{ + if(m_dev) + m_dev->input_etc(state); +} + +device_rs232_port_interface::device_rs232_port_interface(const machine_config &mconfig, device_t &device) + : device_slot_card_interface(mconfig, device) +{ + m_port = dynamic_cast(device.owner()); +} + +device_rs232_port_interface::~device_rs232_port_interface() +{ +} + +#include "keyboard.h" +#include "loopback.h" +#include "null_modem.h" +#include "printer.h" +#include "terminal.h" + +SLOT_INTERFACE_START( default_rs232_devices ) + SLOT_INTERFACE("keyboard", SERIAL_KEYBOARD) + SLOT_INTERFACE("loopback", RS232_LOOPBACK) + SLOT_INTERFACE("null_modem", NULL_MODEM) + SLOT_INTERFACE("printer", SERIAL_PRINTER) + SLOT_INTERFACE("terminal", SERIAL_TERMINAL) +SLOT_INTERFACE_END diff --git a/src/devices/bus/rs232/rs232.h b/src/devices/bus/rs232/rs232.h new file mode 100644 index 00000000000..6be21fcb639 --- /dev/null +++ b/src/devices/bus/rs232/rs232.h @@ -0,0 +1,263 @@ +// license:BSD-3-Clause +// copyright-holders:smf +#ifndef __BUS_RS232_H__ +#define __BUS_RS232_H__ + +#pragma once + +#include "emu.h" + +#define MCFG_RS232_PORT_ADD(_tag, _slot_intf, _def_slot) \ + MCFG_DEVICE_ADD(_tag, RS232_PORT, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) + +#define MCFG_RS232_RXD_HANDLER(_devcb) \ + devcb = &rs232_port_device::set_rxd_handler(*device, DEVCB_##_devcb); + +#define MCFG_RS232_DCD_HANDLER(_devcb) \ + devcb = &rs232_port_device::set_dcd_handler(*device, DEVCB_##_devcb); + +#define MCFG_RS232_DSR_HANDLER(_devcb) \ + devcb = &rs232_port_device::set_dsr_handler(*device, DEVCB_##_devcb); + +#define MCFG_RS232_RI_HANDLER(_devcb) \ + devcb = &rs232_port_device::set_ri_handler(*device, DEVCB_##_devcb); + +#define MCFG_RS232_CTS_HANDLER(_devcb) \ + devcb = &rs232_port_device::set_cts_handler(*device, DEVCB_##_devcb); + +#define RS232_BAUD_110 (0x00) +#define RS232_BAUD_150 (0x01) +#define RS232_BAUD_300 (0x02) +#define RS232_BAUD_600 (0x03) +#define RS232_BAUD_1200 (0x04) +#define RS232_BAUD_2400 (0x05) +#define RS232_BAUD_4800 (0x06) +#define RS232_BAUD_9600 (0x07) +#define RS232_BAUD_14400 (0x08) +#define RS232_BAUD_19200 (0x09) +#define RS232_BAUD_28800 (0x0a) +#define RS232_BAUD_38400 (0x0b) +#define RS232_BAUD_57600 (0x0c) +#define RS232_BAUD_115200 (0x0d) + +#define MCFG_RS232_BAUD(_tag, _default_baud, _description, _class, _write_line) \ + PORT_START(_tag) \ + PORT_CONFNAME(0xff, _default_baud, _description) PORT_WRITE_LINE_DEVICE_MEMBER(DEVICE_SELF, _class, _write_line) \ + PORT_CONFSETTING( RS232_BAUD_110, "110") \ + PORT_CONFSETTING( RS232_BAUD_150, "150") \ + PORT_CONFSETTING( RS232_BAUD_300, "300") \ + PORT_CONFSETTING( RS232_BAUD_600, "600") \ + PORT_CONFSETTING( RS232_BAUD_1200, "1200") \ + PORT_CONFSETTING( RS232_BAUD_2400, "2400") \ + PORT_CONFSETTING( RS232_BAUD_4800, "4800") \ + PORT_CONFSETTING( RS232_BAUD_9600, "9600") \ + PORT_CONFSETTING( RS232_BAUD_14400, "14400") \ + PORT_CONFSETTING( RS232_BAUD_19200, "19200") \ + PORT_CONFSETTING( RS232_BAUD_28800, "28800") \ + PORT_CONFSETTING( RS232_BAUD_38400, "38400") \ + PORT_CONFSETTING( RS232_BAUD_57600, "57600") \ + PORT_CONFSETTING( RS232_BAUD_115200, "115200") + +#define RS232_STARTBITS_0 (0x00) +#define RS232_STARTBITS_1 (0x01) + +#define MCFG_RS232_STARTBITS(_tag, _default_startbits, _description, _class, _write_line) \ + PORT_START(_tag) \ + PORT_CONFNAME(0xff, _default_startbits, _description) PORT_WRITE_LINE_DEVICE_MEMBER(DEVICE_SELF, _class, _write_line) \ + PORT_CONFSETTING( RS232_STARTBITS_0, "0") \ + PORT_CONFSETTING( RS232_STARTBITS_1, "1") + +#define RS232_DATABITS_5 (0x00) +#define RS232_DATABITS_6 (0x01) +#define RS232_DATABITS_7 (0x02) +#define RS232_DATABITS_8 (0x03) + +#define MCFG_RS232_DATABITS(_tag, _default_databits, _description, _class, _write_line) \ + PORT_START(_tag) \ + PORT_CONFNAME(0xff, _default_databits, _description) PORT_WRITE_LINE_DEVICE_MEMBER(DEVICE_SELF, _class, _write_line) \ + PORT_CONFSETTING( RS232_DATABITS_5, "5") \ + PORT_CONFSETTING( RS232_DATABITS_6, "6") \ + PORT_CONFSETTING( RS232_DATABITS_7, "7") \ + PORT_CONFSETTING( RS232_DATABITS_8, "8") + +#define RS232_PARITY_NONE (0x00) +#define RS232_PARITY_ODD (0x01) +#define RS232_PARITY_EVEN (0x02) +#define RS232_PARITY_MARK (0x03) +#define RS232_PARITY_SPACE (0x04) + +#define MCFG_RS232_PARITY(_tag, _default_parity, _description, _class, _write_line) \ + PORT_START(_tag) \ + PORT_CONFNAME(0xff, _default_parity, "Parity") PORT_WRITE_LINE_DEVICE_MEMBER(DEVICE_SELF, _class, _write_line) \ + PORT_CONFSETTING( RS232_PARITY_NONE, "None") \ + PORT_CONFSETTING( RS232_PARITY_ODD, "Odd") \ + PORT_CONFSETTING( RS232_PARITY_EVEN, "Even") \ + PORT_CONFSETTING( RS232_PARITY_MARK, "Mark") \ + PORT_CONFSETTING( RS232_PARITY_SPACE, "Space") + +#define RS232_STOPBITS_0 (0x00) +#define RS232_STOPBITS_1 (0x01) +#define RS232_STOPBITS_1_5 (0x02) +#define RS232_STOPBITS_2 (0x03) + +#define MCFG_RS232_STOPBITS(_tag, _default_stopbits, _description, _class, _write_line) \ + PORT_START(_tag) \ + PORT_CONFNAME(0xff, 0x01, _description) PORT_WRITE_LINE_DEVICE_MEMBER(DEVICE_SELF, _class, _write_line) \ + PORT_CONFSETTING( RS232_STOPBITS_0, "0") \ + PORT_CONFSETTING( RS232_STOPBITS_1, "1") \ + PORT_CONFSETTING( RS232_STOPBITS_1_5, "1.5") \ + PORT_CONFSETTING( RS232_STOPBITS_2, "2") + +class device_rs232_port_interface; + +class rs232_port_device : public device_t, + public device_slot_interface +{ + friend class device_rs232_port_interface; + +public: + rs232_port_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + rs232_port_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + virtual ~rs232_port_device(); + + // static configuration helpers + template static devcb_base &set_rxd_handler(device_t &device, _Object object) { return downcast(device).m_rxd_handler.set_callback(object); } + template static devcb_base &set_dcd_handler(device_t &device, _Object object) { return downcast(device).m_dcd_handler.set_callback(object); } + template static devcb_base &set_dsr_handler(device_t &device, _Object object) { return downcast(device).m_dsr_handler.set_callback(object); } + template static devcb_base &set_ri_handler(device_t &device, _Object object) { return downcast(device).m_ri_handler.set_callback(object); } + template static devcb_base &set_cts_handler(device_t &device, _Object object) { return downcast(device).m_cts_handler.set_callback(object); } + + DECLARE_WRITE_LINE_MEMBER( write_txd ); + DECLARE_WRITE_LINE_MEMBER( write_dtr ); + DECLARE_WRITE_LINE_MEMBER( write_rts ); + DECLARE_WRITE_LINE_MEMBER( write_etc ); + + DECLARE_READ_LINE_MEMBER( rxd_r ) { return m_rxd; } + DECLARE_READ_LINE_MEMBER( dcd_r ) { return m_dcd; } + DECLARE_READ_LINE_MEMBER( dsr_r ) { return m_dsr; } + DECLARE_READ_LINE_MEMBER( ri_r ) { return m_ri; } + DECLARE_READ_LINE_MEMBER( cts_r ) { return m_cts; } + +protected: + virtual void device_start(); + virtual void device_config_complete(); + + int m_rxd; + int m_dcd; + int m_dsr; + int m_ri; + int m_cts; + + devcb_write_line m_rxd_handler; + devcb_write_line m_dcd_handler; + devcb_write_line m_dsr_handler; + devcb_write_line m_ri_handler; + devcb_write_line m_cts_handler; + +private: + device_rs232_port_interface *m_dev; +}; + +class device_rs232_port_interface : public device_slot_card_interface +{ + friend class rs232_port_device; + +public: + device_rs232_port_interface(const machine_config &mconfig, device_t &device); + virtual ~device_rs232_port_interface(); + + virtual DECLARE_WRITE_LINE_MEMBER( input_txd ) {} + virtual DECLARE_WRITE_LINE_MEMBER( input_dtr ) {} + virtual DECLARE_WRITE_LINE_MEMBER( input_rts ) {} + virtual DECLARE_WRITE_LINE_MEMBER( input_etc ) {} + + DECLARE_WRITE_LINE_MEMBER( output_rxd ) { m_port->m_rxd = state; m_port->m_rxd_handler(state); } + DECLARE_WRITE_LINE_MEMBER( output_dcd ) { m_port->m_dcd = state; m_port->m_dcd_handler(state); } + DECLARE_WRITE_LINE_MEMBER( output_dsr ) { m_port->m_dsr = state; m_port->m_dsr_handler(state); } + DECLARE_WRITE_LINE_MEMBER( output_ri ) { m_port->m_ri = state; m_port->m_ri_handler(state); } + DECLARE_WRITE_LINE_MEMBER( output_cts ) { m_port->m_cts = state; m_port->m_cts_handler(state); } + +protected: + rs232_port_device *m_port; + + static int convert_baud(UINT8 baud) + { + static const int values[] = + { + 110, + 150, + 300, + 600, + 1200, + 2400, + 4800, + 9600, + 14400, + 19200, + 28800, + 38400, + 57600, + 115200 + }; + + return values[baud]; + } + + static int convert_startbits(UINT8 startbits) + { + static const int values[] = + { + 0, + 1 + }; + + return values[startbits]; + } + + static int convert_databits(UINT8 databits) + { + static const int values[] = + { + 5, + 6, + 7, + 8 + }; + + return values[databits]; + } + + static device_serial_interface::parity_t convert_parity(UINT8 parity) + { + static const device_serial_interface::parity_t values[] = + { + device_serial_interface::PARITY_NONE, + device_serial_interface::PARITY_ODD, + device_serial_interface::PARITY_EVEN, + device_serial_interface::PARITY_MARK, + device_serial_interface::PARITY_SPACE + }; + + return values[parity]; + } + + static device_serial_interface::stop_bits_t convert_stopbits(UINT8 stopbits) + { + static const device_serial_interface::stop_bits_t values[] = + { + device_serial_interface::STOP_BITS_0, + device_serial_interface::STOP_BITS_1, + device_serial_interface::STOP_BITS_1_5, + device_serial_interface::STOP_BITS_2 + }; + + return values[stopbits]; + } +}; + +extern const device_type RS232_PORT; + +SLOT_INTERFACE_EXTERN( default_rs232_devices ); + +#endif diff --git a/src/devices/bus/rs232/ser_mouse.c b/src/devices/bus/rs232/ser_mouse.c new file mode 100644 index 00000000000..cb2d4d12b50 --- /dev/null +++ b/src/devices/bus/rs232/ser_mouse.c @@ -0,0 +1,265 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/*************************************************************************** + + machine/ser_mouse.c + + Code for emulating PC-style serial mouses + +***************************************************************************/ + +#include "ser_mouse.h" + + +serial_mouse_device::serial_mouse_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_rs232_port_interface(mconfig, *this), + device_serial_interface(mconfig, *this), + m_dtr(1), + m_rts(1), + m_x(*this, "ser_mouse_x"), + m_y(*this, "ser_mouse_y"), + m_btn(*this, "ser_mouse_btn") +{ +} + +const device_type MSFT_SERIAL_MOUSE = &device_creator; + +microsoft_mouse_device::microsoft_mouse_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : serial_mouse_device(mconfig, MSFT_SERIAL_MOUSE, "Microsoft Serial Mouse", tag, owner, clock, "microsoft_mouse", __FILE__) +{ +} + +const device_type MSYSTEM_SERIAL_MOUSE = &device_creator; + +mouse_systems_mouse_device::mouse_systems_mouse_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : serial_mouse_device(mconfig, MSYSTEM_SERIAL_MOUSE, "Mouse Systems Serial Mouse", tag, owner, clock, "mouse_systems_mouse", __FILE__) +{ +} + +void serial_mouse_device::device_start() +{ + m_timer = timer_alloc(); + m_enabled = false; + set_frame(); + set_tra_rate(1200); + reset_mouse(); + + save_item(NAME(m_dtr)); + save_item(NAME(m_rts)); + save_item(NAME(m_queue)); + save_item(NAME(m_head)); + save_item(NAME(m_tail)); + save_item(NAME(m_mb)); + save_item(NAME(m_enabled)); +} + +void serial_mouse_device::reset_mouse() +{ + m_head = m_tail = 0; + output_rxd(1); + output_dcd(0); + output_dsr(0); + output_ri(0); + output_cts(0); +} + +void serial_mouse_device::tra_complete() +{ + if(m_tail != m_head) + transmit_register_setup(unqueue_data()); +} + +void serial_mouse_device::tra_callback() +{ + output_rxd(transmit_register_get_data_bit()); +} + +/************************************************************************** + * Check for mouse moves and buttons. Build delta x/y packets + **************************************************************************/ +void serial_mouse_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + if (id) + { + device_serial_interface::device_timer(timer, id, param, ptr); + return; + } + + static int ox = 0, oy = 0; + int nx,ny; + int dx, dy, nb; + int mbc; + + /* Do not get deltas or send packets if queue is not empty (Prevents drifting) */ + if (m_head==m_tail) + { + nx = m_x->read(); + + dx = nx - ox; + if (dx<=-0x800) dx = nx + 0x1000 - ox; /* Prevent jumping */ + if (dx>=0x800) dx = nx - 0x1000 - ox; + ox = nx; + + ny = m_y->read(); + + dy = ny - oy; + if (dy<=-0x800) dy = ny + 0x1000 - oy; + if (dy>=0x800) dy = ny - 0x1000 - oy; + oy = ny; + + nb = m_btn->read(); + mbc = nb^m_mb; + m_mb = nb; + + /* check if there is any delta or mouse buttons changed */ + if ( (dx!=0) || (dy!=0) || (mbc!=0) ) + mouse_trans(dx, dy, nb, mbc); + } + + + if(m_tail != m_head && is_transmit_register_empty()) + transmit_register_setup(unqueue_data()); +} + +void microsoft_mouse_device::mouse_trans(int dx, int dy, int nb, int mbc) +{ + /* split deltas into packets of -128..+127 max */ + do + { + UINT8 m0, m1, m2; + int ddx = (dx < -128) ? -128 : (dx > 127) ? 127 : dx; + int ddy = (dy < -128) ? -128 : (dy > 127) ? 127 : dy; + m0 = 0x40 | ((nb << 4) & 0x30) | ((ddx >> 6) & 0x03) | ((ddy >> 4) & 0x0c); + m1 = ddx & 0x3f; + m2 = ddy & 0x3f; + + /* KT - changed to use a function */ + queue_data(m0 | 0x40); + queue_data(m1 & 0x03f); + queue_data(m2 & 0x03f); + if ((mbc & 0x04) != 0) /* If button 3 changed send extra byte */ + queue_data( (nb & 0x04) << 3); + + dx -= ddx; + dy -= ddy; + } while( dx || dy ); +} + +/* mouse systems mouse + from "PC Mouse information" by Tomi Engdahl */ + +/* + The data is sent in 5 byte packets in following format: + D7 D6 D5 D4 D3 D2 D1 D0 + + 1. 1 0 0 0 0 LB CB RB + 2. X7 X6 X5 X4 X3 X2 X1 X0 + 3. Y7 Y6 Y5 Y4 Y3 Y4 Y1 Y0 + 4. X7' X6' X5' X4' X3' X2' X1' X0' + 5. Y7' Y6' Y5' Y4' Y3' Y4' Y1' Y0' + + LB is left button state (0=pressed, 1=released) + CB is center button state (0=pressed, 1=released) + RB is right button state (0=pressed, 1=released) + X7-X0 movement in X direction since last packet in signed byte + format (-128..+127), positive direction right + Y7-Y0 movement in Y direction since last packet in signed byte + format (-128..+127), positive direction up + X7'-X0' movement in X direction since sending of X7-X0 packet in signed byte + format (-128..+127), positive direction right + Y7'-Y0' movement in Y direction since sending of Y7-Y0 in signed byte + format (-128..+127), positive direction up + + The last two bytes in the packet (bytes 4 and 5) contains information + about movement data changes which have occurred after data bytes 2 and 3 have been sent. */ + +void mouse_systems_mouse_device::mouse_trans(int dx, int dy, int nb, int mbc) +{ + dy =-dy; + + do + { + int ddx = (dx < -128) ? -128 : (dx > 127) ? 127 : dx; + int ddy = (dy < -128) ? -128 : (dy > 127) ? 127 : dy; + + /* KT - changed to use a function */ + queue_data(0x080 | ((((nb & 0x04) >> 1) + ((nb & 0x02) << 1) + (nb & 0x01)) ^ 0x07)); + queue_data(ddx); + queue_data(ddy); + /* for now... */ + queue_data(0); + queue_data(0); + dx -= ddx; + dy -= ddy; + } while( dx || dy ); +} + +/************************************************************************** + * Check for mouse control line changes and (de-)install timer + **************************************************************************/ + +void serial_mouse_device::set_mouse_enable(bool state) +{ + if(state && !m_enabled) + { + m_timer->adjust(attotime::zero, 0, attotime::from_hz(240)); + } + else if(!state && m_enabled) + { + m_timer->adjust(attotime::never); + m_head = m_tail = 0; + } + m_enabled = state; + +} + + +WRITE_LINE_MEMBER(serial_mouse_device::input_dtr) +{ + m_dtr = state; + check_state(); +} + +WRITE_LINE_MEMBER(serial_mouse_device::input_rts) +{ + m_rts = state; + check_state(); +} + +WRITE_LINE_MEMBER(microsoft_mouse_device::input_rts) +{ + if (!m_dtr && m_rts && !state) + { + reset_mouse(); + /* Identify as Microsoft 3 Button Mouse */ + queue_data('M'); + queue_data('3'); + } + + serial_mouse_device::input_rts(state); +} + + + +/************************************************************************** + * Mouse INPUT_PORT declarations + **************************************************************************/ + +static INPUT_PORTS_START( ser_mouse ) + PORT_START( "ser_mouse_btn" ) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_BUTTON1) PORT_NAME("Mouse Left Button") PORT_CODE(MOUSECODE_BUTTON1) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_BUTTON2) PORT_NAME("Mouse Middle Button") PORT_CODE(MOUSECODE_BUTTON3) + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_BUTTON3) PORT_NAME("Mouse Right Button") PORT_CODE(MOUSECODE_BUTTON2) + + PORT_START( "ser_mouse_x" ) /* Mouse - X AXIS */ + PORT_BIT( 0xfff, 0x00, IPT_MOUSE_X) PORT_SENSITIVITY(100) PORT_KEYDELTA(0) PORT_PLAYER(1) + + PORT_START( "ser_mouse_y" ) /* Mouse - Y AXIS */ + PORT_BIT( 0xfff, 0x00, IPT_MOUSE_Y) PORT_SENSITIVITY(100) PORT_KEYDELTA(0) PORT_PLAYER(1) +INPUT_PORTS_END + +ioport_constructor serial_mouse_device::device_input_ports() const +{ + return INPUT_PORTS_NAME(ser_mouse); +} diff --git a/src/devices/bus/rs232/ser_mouse.h b/src/devices/bus/rs232/ser_mouse.h new file mode 100644 index 00000000000..ccc4cdbbdae --- /dev/null +++ b/src/devices/bus/rs232/ser_mouse.h @@ -0,0 +1,81 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/***************************************************************************** + * + * machine/ser_mouse.h + * + ****************************************************************************/ + +#ifndef SER_MOUSE_H_ +#define SER_MOUSE_H_ + +#include "rs232.h" + +class serial_mouse_device : + public device_t, + public device_rs232_port_interface, + public device_serial_interface +{ +public: + serial_mouse_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + virtual ioport_constructor device_input_ports() const; + +protected: + virtual void device_start(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + virtual void mouse_trans(int dx, int dy, int nb, int mbc) = 0; + virtual void set_frame() = 0; + void set_mouse_enable(bool state); + void queue_data(UINT8 data) {m_queue[m_head] = data; ++m_head %= 256;} + UINT8 unqueue_data() {UINT8 ret = m_queue[m_tail]; ++m_tail %= 256; return ret;} + virtual void tra_complete(); + virtual void tra_callback(); + void reset_mouse(); + + virtual WRITE_LINE_MEMBER(input_dtr); + virtual WRITE_LINE_MEMBER(input_rts); + int m_dtr; + int m_rts; + +private: + UINT8 m_queue[256]; + UINT8 m_head, m_tail, m_mb; + + emu_timer *m_timer; + bool m_enabled; + + required_ioport m_x; + required_ioport m_y; + required_ioport m_btn; + + void check_state() { set_mouse_enable(!m_dtr && !m_rts); } +}; + +class microsoft_mouse_device : public serial_mouse_device +{ +public: + microsoft_mouse_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual WRITE_LINE_MEMBER(input_rts); + + virtual void set_frame() { set_data_frame(1, 7, PARITY_NONE, STOP_BITS_2); } + virtual void mouse_trans(int dx, int dy, int nb, int mbc); +}; + +extern const device_type MSFT_SERIAL_MOUSE; + +class mouse_systems_mouse_device : public serial_mouse_device +{ +public: + mouse_systems_mouse_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual void set_frame() { set_data_frame(1, 8, PARITY_NONE, STOP_BITS_2); } + virtual void mouse_trans(int dx, int dy, int nb, int mbc); +}; + +extern const device_type MSYSTEM_SERIAL_MOUSE; + +#endif /* SER_MOUSE_H_ */ diff --git a/src/devices/bus/rs232/terminal.c b/src/devices/bus/rs232/terminal.c new file mode 100644 index 00000000000..a8b8db63e36 --- /dev/null +++ b/src/devices/bus/rs232/terminal.c @@ -0,0 +1,106 @@ +// license:BSD-3-Clause +// copyright-holders:smf +#include "terminal.h" + +serial_terminal_device::serial_terminal_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : generic_terminal_device(mconfig, SERIAL_TERMINAL, "Serial Terminal", tag, owner, clock, "serial_terminal", __FILE__), + device_serial_interface(mconfig, *this), + device_rs232_port_interface(mconfig, *this), + m_rs232_txbaud(*this, "RS232_TXBAUD"), + m_rs232_rxbaud(*this, "RS232_RXBAUD"), + m_rs232_startbits(*this, "RS232_STARTBITS"), + m_rs232_databits(*this, "RS232_DATABITS"), + m_rs232_parity(*this, "RS232_PARITY"), + m_rs232_stopbits(*this, "RS232_STOPBITS") +{ +} + +static INPUT_PORTS_START(serial_terminal) + PORT_INCLUDE(generic_terminal) + + MCFG_RS232_BAUD("RS232_TXBAUD", RS232_BAUD_9600, "TX Baud", serial_terminal_device, update_serial) + MCFG_RS232_BAUD("RS232_RXBAUD", RS232_BAUD_9600, "RX Baud", serial_terminal_device, update_serial) + MCFG_RS232_STARTBITS("RS232_STARTBITS", RS232_STARTBITS_1, "Start Bits", serial_terminal_device, update_serial) + MCFG_RS232_DATABITS("RS232_DATABITS", RS232_DATABITS_8, "Data Bits", serial_terminal_device, update_serial) + MCFG_RS232_PARITY("RS232_PARITY", RS232_PARITY_NONE, "Parity", serial_terminal_device, update_serial) + MCFG_RS232_STOPBITS("RS232_STOPBITS", RS232_STOPBITS_1, "Stop Bits", serial_terminal_device, update_serial) +INPUT_PORTS_END + +ioport_constructor serial_terminal_device::device_input_ports() const +{ + return INPUT_PORTS_NAME(serial_terminal); +} + +void serial_terminal_device::device_start() +{ + generic_terminal_device::device_start(); +} + +WRITE_LINE_MEMBER(serial_terminal_device::update_serial) +{ + int startbits = convert_startbits(m_rs232_startbits->read()); + int databits = convert_databits(m_rs232_databits->read()); + parity_t parity = convert_parity(m_rs232_parity->read()); + stop_bits_t stopbits = convert_stopbits(m_rs232_stopbits->read()); + + set_data_frame(startbits, databits, parity, stopbits); + + int txbaud = convert_baud(m_rs232_txbaud->read()); + set_tra_rate(txbaud); + + int rxbaud = convert_baud(m_rs232_rxbaud->read()); + set_rcv_rate(rxbaud); + + output_rxd(1); + + // TODO: make this configurable + output_dcd(0); + output_dsr(0); + output_cts(0); +} + +void serial_terminal_device::device_reset() +{ + generic_terminal_device::device_reset(); + + update_serial(0); +} + +void serial_terminal_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + device_serial_interface::device_timer(timer, id, param, ptr); +} + +void serial_terminal_device::send_key(UINT8 code) +{ + if (is_transmit_register_empty()) + { + transmit_register_setup(code); + return; + } + + m_key_valid = true; + m_curr_key = code; +} + +void serial_terminal_device::tra_callback() +{ + output_rxd(transmit_register_get_data_bit()); +} + +void serial_terminal_device::tra_complete() +{ + if (m_key_valid) + { + transmit_register_setup(m_curr_key); + m_key_valid = false; + } +} + +void serial_terminal_device::rcv_complete() +{ + receive_register_extract(); + term_write(get_received_char()); +} + +const device_type SERIAL_TERMINAL = &device_creator; diff --git a/src/devices/bus/rs232/terminal.h b/src/devices/bus/rs232/terminal.h new file mode 100644 index 00000000000..d2c92be9920 --- /dev/null +++ b/src/devices/bus/rs232/terminal.h @@ -0,0 +1,46 @@ +// license:BSD-3-Clause +// copyright-holders:smf +#ifndef __RS232_TERMINAL_H__ +#define __RS232_TERMINAL_H__ + +#include "rs232.h" +#include "machine/terminal.h" + + +class serial_terminal_device : public generic_terminal_device, + public device_serial_interface, + public device_rs232_port_interface +{ +public: + serial_terminal_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual DECLARE_WRITE_LINE_MEMBER( input_txd ) { device_serial_interface::rx_w(state); } + + DECLARE_WRITE_LINE_MEMBER(update_serial); + +protected: + virtual ioport_constructor device_input_ports() const; + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + virtual void tra_callback(); + virtual void tra_complete(); + virtual void rcv_complete(); + virtual void send_key(UINT8 code); + +private: + required_ioport m_rs232_txbaud; + required_ioport m_rs232_rxbaud; + required_ioport m_rs232_startbits; + required_ioport m_rs232_databits; + required_ioport m_rs232_parity; + required_ioport m_rs232_stopbits; + + UINT8 m_curr_key; + bool m_key_valid; +}; + +extern const device_type SERIAL_TERMINAL; + +#endif /* __RS232_TERMINAL_H__ */ diff --git a/src/devices/bus/rs232/xvd701.c b/src/devices/bus/rs232/xvd701.c new file mode 100644 index 00000000000..47c960e55af --- /dev/null +++ b/src/devices/bus/rs232/xvd701.c @@ -0,0 +1,150 @@ +// license:BSD-3-Clause +// copyright-holders:smf +#include "xvd701.h" + +jvc_xvd701_device::jvc_xvd701_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, JVC_XVD701, "JVC XV-D701", tag, owner, clock, "xvd701", __FILE__), + device_serial_interface(mconfig, *this), + device_rs232_port_interface(mconfig, *this) +{ +} + +static MACHINE_CONFIG_FRAGMENT(xvd701) +MACHINE_CONFIG_END + +machine_config_constructor jvc_xvd701_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME(xvd701); +} + +static INPUT_PORTS_START(xvd701) +INPUT_PORTS_END + +ioport_constructor jvc_xvd701_device::device_input_ports() const +{ + return INPUT_PORTS_NAME(xvd701); +} + +void jvc_xvd701_device::device_start() +{ + int startbits = 1; + int databits = 8; + parity_t parity = PARITY_ODD; + stop_bits_t stopbits = STOP_BITS_1; + + set_data_frame(startbits, databits, parity, stopbits); + + int txbaud = 9600; + set_tra_rate(txbaud); + + int rxbaud = 9600; + set_rcv_rate(rxbaud); + + output_rxd(1); + + // TODO: make this configurable + output_dcd(0); + output_dsr(0); + output_ri(0); + output_cts(0); + + m_timer_response = timer_alloc(TIMER_RESPONSE); +} + +void jvc_xvd701_device::device_reset() +{ + memset(m_command, 0, sizeof(m_command)); + + m_response_index = sizeof(m_response); +} + +void jvc_xvd701_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch (id) + { + case TIMER_RESPONSE: + send_response(); + break; + + default: + device_serial_interface::device_timer(timer, id, param, ptr); + } +} + +void jvc_xvd701_device::tra_callback() +{ + output_rxd(transmit_register_get_data_bit()); +} + +void jvc_xvd701_device::tra_complete() +{ + m_timer_response->adjust(attotime::from_msec(100)); +} + +unsigned char jvc_xvd701_device::sum(unsigned char *buffer, int length) +{ + int sum = 0; + + for (int i = 0; i < length; i++) + sum += buffer[i]; + + return sum & 0x7f; +} + +void jvc_xvd701_device::send_response() +{ + if (m_response_index < sizeof(m_response) && is_transmit_register_empty()) + { +// printf("sending %02x\n", m_response[m_response_index]); + transmit_register_setup(m_response[m_response_index++]); + } +} + +void jvc_xvd701_device::rcv_complete() +{ + receive_register_extract(); + + for (int i = 0; i < sizeof(m_command) - 1; i++) + m_command[i] = m_command[i + 1]; + + m_command[sizeof(m_command) - 1] = get_received_char(); + + if (m_command[0] == 0xff && + m_command[1] == 0xff && + m_command[2] == 0x21 && + sum(m_command, sizeof(m_command)) == 0) + { + // printf("xvd701"); + + //for (int i = 0; i < sizeof(m_command); i++) + // printf(" %02x", m_command[i]); + + //printf("\n"); + + // FF FF 21 3E 40 70 00 00 00 00 73 DEVICE ON + // FF FF 21 3E 40 60 00 00 00 00 03 DEVICE OFF + // FF FF 21 0C 44 60 00 00 00 00 31 STOP + // FF FF 21 0C 43 75 00 00 00 00 1D PLAY + // FF FF 21 0C 43 6D 00 00 00 00 25 PAUSE + // FF FF 21 0C 50 20 00 00 00 00 63 SEEK TO SPECIFIC CHAPTER + // FF FF 21 0C 50 73 00 00 00 00 12 FF (SEEK TO NEXT CHAPTER) + // FF FF 21 0C 50 61 00 00 00 00 24 PREV (SEEK TO PREVIOUS CHAPTER) + + m_response[0] = 0xff; + m_response[1] = 0xfe; + m_response[2] = 0x7f; + m_response[3] = 0x7e; + m_response[4] = 0x7d; + m_response[5] = 0x7c; + m_response[6] = 0x7b; + m_response[7] = 0x7a; + m_response[8] = 0x79; + m_response[9] = 0x78; + m_response[10] = 0x77; + m_response_index = 0; + + m_timer_response->adjust(attotime::from_msec(100)); + } +} + +const device_type JVC_XVD701 = &device_creator; diff --git a/src/devices/bus/rs232/xvd701.h b/src/devices/bus/rs232/xvd701.h new file mode 100644 index 00000000000..e25f91fd662 --- /dev/null +++ b/src/devices/bus/rs232/xvd701.h @@ -0,0 +1,44 @@ +// license:BSD-3-Clause +// copyright-holders:smf +#ifndef JVC_XV701_H_ +#define JVC_XV701_H_ + +#include "rs232.h" + +class jvc_xvd701_device : public device_t, + public device_serial_interface, + public device_rs232_port_interface +{ +public: + jvc_xvd701_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual machine_config_constructor device_mconfig_additions() const; + + virtual WRITE_LINE_MEMBER( input_txd ) { device_serial_interface::rx_w(state); } + + DECLARE_WRITE_LINE_MEMBER(update_serial); + +protected: + virtual ioport_constructor device_input_ports() const; + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + virtual void tra_callback(); + virtual void tra_complete(); + virtual void rcv_complete(); + +private: + static const int TIMER_RESPONSE = 1; + + void send_response(); + unsigned char sum(unsigned char *buffer, int length); + + unsigned char m_command[11]; + unsigned char m_response[11]; + int m_response_index; + emu_timer *m_timer_response; +}; + +extern const device_type JVC_XVD701; + +#endif diff --git a/src/devices/bus/s100/dj2db.c b/src/devices/bus/s100/dj2db.c new file mode 100644 index 00000000000..f32d32e3eb2 --- /dev/null +++ b/src/devices/bus/s100/dj2db.c @@ -0,0 +1,517 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Morrow Designs Disk Jockey 2D/B floppy controller board emulation + +**********************************************************************/ + +/* + + TODO: + + - stall logic (read from fdc data register halts CPU until intrq/drq from FDC) + +*/ + +#include "dj2db.h" + + + +//************************************************************************** +// MACROS/CONSTANTS +//************************************************************************** + +#define MB8866_TAG "14b" +#define S1602_TAG "14d" +#define BR1941_TAG "13d" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type S100_DJ2DB = &device_creator; + + +//------------------------------------------------- +// ROM( dj2db ) +//------------------------------------------------- + +ROM_START( dj2db ) + ROM_REGION( 0x400, "dj2db", ROMREGION_INVERT ) // 2708, inverted data outputs + ROM_LOAD( "bv-2 f8.11d", 0x000, 0x400, CRC(b6218d0b) SHA1(e4b2ae886c0dd7717e2e02ae2e202115d8ec2def) ) + + ROM_REGION( 0x220, "proms", 0 ) + ROM_LOAD( "8c-b f8.8c", 0x000, 0x200, NO_DUMP ) // 6301 + ROM_LOAD( "3d.3d", 0x200, 0x20, NO_DUMP ) // 6331 +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *s100_dj2db_device::device_rom_region() const +{ + return ROM_NAME( dj2db ); +} + + +//------------------------------------------------- +// COM8116_INTERFACE( brg_intf ) +//------------------------------------------------- + +WRITE_LINE_MEMBER( s100_dj2db_device::fr_w ) +{ + // S1602 RRC/TRC +} + +static SLOT_INTERFACE_START( s100_dj2db_floppies ) + SLOT_INTERFACE( "8dsdd", FLOPPY_8_DSDD ) +SLOT_INTERFACE_END + +WRITE_LINE_MEMBER( s100_dj2db_device::fdc_intrq_w ) +{ + if (state) m_bus->rdy_w(CLEAR_LINE); + + switch (m_j1a->read()) + { + case 0: m_bus->vi0_w(state); break; + case 1: m_bus->vi1_w(state); break; + case 2: m_bus->vi2_w(state); break; + case 3: m_bus->vi3_w(state); break; + case 4: m_bus->vi4_w(state); break; + case 5: m_bus->vi5_w(state); break; + case 6: m_bus->vi6_w(state); break; + case 7: m_bus->vi7_w(state); break; + case 8: m_bus->irq_w(state); break; + } +} + +WRITE_LINE_MEMBER( s100_dj2db_device::fdc_drq_w ) +{ + if (state) m_bus->rdy_w(CLEAR_LINE); +} + + +//------------------------------------------------- +// MACHINE_CONFIG_FRAGMENT( s100_dj2db ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( s100_dj2db ) + MCFG_DEVICE_ADD(BR1941_TAG, COM8116, XTAL_5_0688MHz) + MCFG_COM8116_FR_HANDLER(WRITELINE(s100_dj2db_device, fr_w)) + + MCFG_MB8866_ADD(MB8866_TAG, XTAL_10MHz/5) + MCFG_WD_FDC_INTRQ_CALLBACK(WRITELINE(s100_dj2db_device, fdc_intrq_w)) + MCFG_WD_FDC_DRQ_CALLBACK(WRITELINE(s100_dj2db_device, fdc_drq_w)) + + MCFG_FLOPPY_DRIVE_ADD(MB8866_TAG":0", s100_dj2db_floppies, "8dsdd", floppy_image_device::default_floppy_formats) + MCFG_FLOPPY_DRIVE_ADD(MB8866_TAG":1", s100_dj2db_floppies, NULL, floppy_image_device::default_floppy_formats) + MCFG_FLOPPY_DRIVE_ADD(MB8866_TAG":2", s100_dj2db_floppies, NULL, floppy_image_device::default_floppy_formats) + MCFG_FLOPPY_DRIVE_ADD(MB8866_TAG":3", s100_dj2db_floppies, NULL, floppy_image_device::default_floppy_formats) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor s100_dj2db_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( s100_dj2db ); +} + + +//------------------------------------------------- +// INPUT_PORTS( mm65k16s ) +//------------------------------------------------- + +static INPUT_PORTS_START( dj2db ) + PORT_START("SW1") + PORT_DIPNAME( 0xf8, 0xf8, "Power-On Jump Address" ) PORT_DIPLOCATION("SW1:1,2,3,4,5") PORT_CONDITION("SW1", 0x01, EQUALS, 0x00) + PORT_DIPSETTING( 0xf8, "F800H" ) + PORT_DIPSETTING( 0xf0, "F000H" ) + PORT_DIPSETTING( 0xe8, "E800H" ) + PORT_DIPSETTING( 0xe0, "E000H" ) + PORT_DIPSETTING( 0xd8, "D800H" ) + PORT_DIPSETTING( 0xd0, "D000H" ) + PORT_DIPSETTING( 0xc8, "C800H" ) + PORT_DIPSETTING( 0xc0, "C000H" ) + PORT_DIPSETTING( 0xb8, "B800H" ) + PORT_DIPSETTING( 0xb0, "B000H" ) + PORT_DIPSETTING( 0xa8, "A800H" ) + PORT_DIPSETTING( 0xa0, "A000H" ) + PORT_DIPSETTING( 0x98, "9800H" ) + PORT_DIPSETTING( 0x90, "9000H" ) + PORT_DIPSETTING( 0x88, "8800H" ) + PORT_DIPSETTING( 0x80, "8000H" ) + PORT_DIPSETTING( 0x78, "7800H" ) + PORT_DIPSETTING( 0x70, "7000H" ) + PORT_DIPSETTING( 0x68, "6800H" ) + PORT_DIPSETTING( 0x60, "6000H" ) + PORT_DIPSETTING( 0x58, "5800H" ) + PORT_DIPSETTING( 0x50, "5000H" ) + PORT_DIPSETTING( 0x48, "4800H" ) + PORT_DIPSETTING( 0x40, "4000H" ) + PORT_DIPSETTING( 0x38, "3800H" ) + PORT_DIPSETTING( 0x30, "3000H" ) + PORT_DIPSETTING( 0x28, "2800H" ) + PORT_DIPSETTING( 0x20, "2000H" ) + PORT_DIPSETTING( 0x18, "1800H" ) + PORT_DIPSETTING( 0x10, "1000H" ) + PORT_DIPSETTING( 0x08, "0800H" ) + PORT_DIPSETTING( 0x00, "0000H" ) + PORT_DIPNAME( 0x04, 0x04, "Phantom Line" ) PORT_DIPLOCATION("SW1:6") + PORT_DIPSETTING( 0x04, "Disabled" ) + PORT_DIPSETTING( 0x00, "Enabled" ) + PORT_DIPNAME( 0x02, 0x02, "Bus Speed" ) PORT_DIPLOCATION("SW1:7") + PORT_DIPSETTING( 0x02, "2 MHz" ) + PORT_DIPSETTING( 0x00, "4/6 MHz" ) + PORT_DIPNAME( 0x01, 0x01, "Power-On Jump" ) PORT_DIPLOCATION("SW1:8") + PORT_DIPSETTING( 0x01, "Disabled" ) + PORT_DIPSETTING( 0x00, "Enabled" ) + + PORT_START("SW2") + PORT_DIPNAME( 0x0f, 0x0f, "Baud Rate" ) PORT_DIPLOCATION("SW2:1,2,3,4") + PORT_DIPSETTING( 0x08, "110" ) + PORT_DIPSETTING( 0x0e, "1200" ) + PORT_DIPSETTING( 0x07, "9600" ) + PORT_DIPSETTING( 0x0f, "19200" ) + PORT_DIPNAME( 0x10, 0x00, "Word Length" ) PORT_DIPLOCATION("SW2:5") + PORT_DIPSETTING( 0x10, "8 Bits" ) + PORT_DIPSETTING( 0x00, "7 Bits" ) + PORT_DIPNAME( 0x20, 0x20, "Stop Bit Count" ) PORT_DIPLOCATION("SW2:6") + PORT_DIPSETTING( 0x20, "2 Stop Bits" ) + PORT_DIPSETTING( 0x00, "1 Stop Bit" ) + PORT_DIPNAME( 0x40, 0x40, "Parity" ) PORT_DIPLOCATION("SW2:7") PORT_CONDITION("SW2", 0x80, EQUALS, 0x00) + PORT_DIPSETTING( 0x40, "Even Parity" ) + PORT_DIPSETTING( 0x00, "Odd Parity" ) + PORT_DIPNAME( 0x80, 0x80, "Parity" ) PORT_DIPLOCATION("SW2:8") + PORT_DIPSETTING( 0x80, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x00, DEF_STR( On ) ) + + PORT_START("J4") + PORT_DIPNAME( 0x01, 0x00, "Power Up" ) + PORT_DIPSETTING( 0x00, "Inactive" ) + PORT_DIPSETTING( 0x01, "Active" ) + + PORT_START("J2") + PORT_DIPNAME( 0x01, 0x01, "Generate PHANTOM Signal" ) + PORT_DIPSETTING( 0x01, "Disabled" ) + PORT_DIPSETTING( 0x00, "Enabled" ) + + PORT_START("J3A") + PORT_DIPNAME( 0xff, 0x00, "Bank Select" ) + PORT_DIPSETTING( 0x00, "Disabled" ) + PORT_DIPSETTING( 0x01, "DATA 0" ) + PORT_DIPSETTING( 0x02, "DATA 1" ) + PORT_DIPSETTING( 0x04, "DATA 2" ) + PORT_DIPSETTING( 0x08, "DATA 2" ) + PORT_DIPSETTING( 0x10, "DATA 3" ) + PORT_DIPSETTING( 0x20, "DATA 4" ) + PORT_DIPSETTING( 0x40, "DATA 6" ) + PORT_DIPSETTING( 0x80, "DATA 7" ) + + PORT_START("J1A") + PORT_DIPNAME( 0x0f, 0x09, "Interrupt" ) + PORT_DIPSETTING( 0x09, "Disabled") + PORT_DIPSETTING( 0x00, "VI0") + PORT_DIPSETTING( 0x01, "VI1") + PORT_DIPSETTING( 0x02, "VI2") + PORT_DIPSETTING( 0x03, "VI3") + PORT_DIPSETTING( 0x04, "VI4") + PORT_DIPSETTING( 0x05, "VI5") + PORT_DIPSETTING( 0x06, "VI6") + PORT_DIPSETTING( 0x07, "VI7") + PORT_DIPSETTING( 0x08, "PINT") +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor s100_dj2db_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( dj2db ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// s100_dj2db_device - constructor +//------------------------------------------------- + +s100_dj2db_device::s100_dj2db_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, S100_DJ2DB, "DJ2DB", tag, owner, clock, "dj2db", __FILE__), + device_s100_card_interface(mconfig, *this), + m_fdc(*this, MB8866_TAG), + m_dbrg(*this, BR1941_TAG), + m_floppy0(*this, MB8866_TAG":0"), + m_floppy1(*this, MB8866_TAG":1"), + m_floppy2(*this, MB8866_TAG":2"), + m_floppy3(*this, MB8866_TAG":3"), + m_floppy(NULL), + m_rom(*this, "dj2db"), + m_ram(*this, "ram"), + m_j1a(*this, "J1A"), + m_j3a(*this, "J3A"), + m_j4(*this, "J4"), + m_sw1(*this, "SW1"), + m_drive(0), + m_head(1), + m_int_enbl(0), + m_access_enbl(0), + m_board_enbl(1), + m_phantom(1) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void s100_dj2db_device::device_start() +{ + // allocate memory + m_ram.allocate(0x400); + + // state saving + save_item(NAME(m_drive)); + save_item(NAME(m_head)); + save_item(NAME(m_int_enbl)); + save_item(NAME(m_access_enbl)); + save_item(NAME(m_board_enbl)); + save_item(NAME(m_phantom)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void s100_dj2db_device::device_reset() +{ + m_board_enbl = m_j4->read(); +} + + +//------------------------------------------------- +// s100_smemr_r - memory read +//------------------------------------------------- + +UINT8 s100_dj2db_device::s100_smemr_r(address_space &space, offs_t offset) +{ + UINT8 data = 0; + +// if (!(m_board_enbl & m_phantom)) return 0; + + if ((offset >= 0xf800) && (offset < 0xfbf8)) + { + data = m_rom->base()[offset & 0x3ff] ^ 0xff; + } + else if (offset == 0xfbf8) // SERIAL IN + { + // UART inverted data + } + else if (offset == 0xfbf9) // SERIAL STAT + { + /* + + bit description + + 0 PE + 1 OE + 2 DR + 3 TBRE + 4 FE + 5 + 6 + 7 + + */ + } + else if (offset == 0xfbfa) // DISK STAT + { + /* + + bit description + + 0 HEAD + 1 DATA RQ + 2 INT RQ + 3 _TWO SIDED + 4 _INDEX + 5 + 6 + 7 _READY + + */ + + data |= !m_head; + data |= !m_fdc->drq_r() << 1; + data |= !m_fdc->intrq_r() << 2; + data |= (m_floppy ? m_floppy->twosid_r() : 1) << 3; + data |= (m_floppy ? m_floppy->idx_r() : 1) << 4; + data |= (m_floppy ? m_floppy->ready_r() : 1) << 7; + } + else if ((offset >= 0xfbfc) && (offset < 0xfc00)) + { + m_bus->rdy_w(ASSERT_LINE); + + data = m_fdc->gen_r(offset & 0x03); + } + else if ((offset >= 0xfc00) && (offset < 0x10000)) + { + data = m_ram[offset & 0x3ff]; + } + else + { + return 0; + } + + // LS241 inverts data + return data ^ 0xff; +} + + +//------------------------------------------------- +// s100_mwrt_w - memory write +//------------------------------------------------- + +void s100_dj2db_device::s100_mwrt_w(address_space &space, offs_t offset, UINT8 data) +{ +// if (!(m_board_enbl & m_phantom)) return; + + // LS96 inverts data + data ^= 0xff; + + if (offset == 0xfbf8) // SERIAL OUT + { + // UART inverted data + } + else if (offset == 0xfbf9) // DRIVE SEL + { + /* + + bit description + + 0 DRIVE 1 + 1 DRIVE 2 + 2 DRIVE 3 + 3 DRIVE 4 + 4 IN USE / SIDE SELECT + 5 INT ENBL + 6 _ACCESS ENBL + 7 START + + */ + + // drive select + m_floppy = NULL; + + if (BIT(data, 0)) m_floppy = m_floppy0->get_device(); + if (BIT(data, 1)) m_floppy = m_floppy1->get_device(); + if (BIT(data, 2)) m_floppy = m_floppy2->get_device(); + if (BIT(data, 3)) m_floppy = m_floppy3->get_device(); + + m_fdc->set_floppy(m_floppy); + + // side select + if (m_floppy) + { + m_floppy->ss_w(BIT(data, 4)); + m_floppy->mon_w(0); + } + + // interrupt enable + m_int_enbl = BIT(data, 5); + + // access enable + m_access_enbl = BIT(data, 6); + + // master reset + if (!BIT(data, 7)) m_fdc->soft_reset(); + } + else if (offset == 0xfbfa) // FUNCTION SEL + { + /* + + bit description + + 0 DOUBLE + 1 8A SET + 2 8A CLEAR + 3 LEDOFF + 4 + 5 + 6 + 7 + + */ + + // density select + m_fdc->dden_w(BIT(data, 0)); + } + else if (offset == 0xfbfb) // WAIT ENBL + { + fatalerror("Z80 WAIT not supported by MAME core\n"); + } + else if ((offset >= 0xfbfc) && (offset < 0xfc00)) + { + m_fdc->gen_w(offset & 0x03, data); + } + else if ((offset >= 0xfc00) && (offset < 0x10000)) + { + m_ram[offset & 0x3ff] = data; + } +} + + +//------------------------------------------------- +// s100_sinp_r - I/O read +//------------------------------------------------- + +UINT8 s100_dj2db_device::s100_sinp_r(address_space &space, offs_t offset) +{ + return 0; +} + + +//------------------------------------------------- +// s100_sout_w - I/O write +//------------------------------------------------- + +void s100_dj2db_device::s100_sout_w(address_space &space, offs_t offset, UINT8 data) +{ + if (offset == 0x41) + { + m_board_enbl = (data & m_j3a->read()) ? 1 : 0; + } +} + + +//------------------------------------------------- +// s100_phantom_w - phantom +//------------------------------------------------- + +void s100_dj2db_device::s100_phantom_w(int state) +{ + if (!BIT(m_sw1->read(), 2)) + { + m_phantom = state; + } + else + { + m_phantom = 1; + } +} diff --git a/src/devices/bus/s100/dj2db.h b/src/devices/bus/s100/dj2db.h new file mode 100644 index 00000000000..460a45ff3dc --- /dev/null +++ b/src/devices/bus/s100/dj2db.h @@ -0,0 +1,88 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Morrow Designs Disk Jockey 2D/B floppy controller board emulation + +**********************************************************************/ + +#pragma once + +#ifndef __S100_DJ2DB__ +#define __S100_DJ2DB__ + +#include "emu.h" +#include "s100.h" +#include "machine/com8116.h" +#include "machine/wd_fdc.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> s100_dj2db_device + +class s100_dj2db_device : public device_t, + public device_s100_card_interface +{ +public: + // construction/destruction + s100_dj2db_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + virtual ioport_constructor device_input_ports() const; + + // not really public + DECLARE_WRITE_LINE_MEMBER( fr_w ); + DECLARE_WRITE_LINE_MEMBER( fdc_intrq_w ); + DECLARE_WRITE_LINE_MEMBER( fdc_drq_w ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_s100_card_interface overrides + virtual UINT8 s100_smemr_r(address_space &space, offs_t offset); + virtual void s100_mwrt_w(address_space &space, offs_t offset, UINT8 data); + virtual UINT8 s100_sinp_r(address_space &space, offs_t offset); + virtual void s100_sout_w(address_space &space, offs_t offset, UINT8 data); + virtual void s100_phantom_w(int state); + +private: + // internal state + required_device m_fdc; + required_device m_dbrg; + required_device m_floppy0; + required_device m_floppy1; + required_device m_floppy2; + required_device m_floppy3; + floppy_image_device *m_floppy; + required_memory_region m_rom; + optional_shared_ptr m_ram; + required_ioport m_j1a; + required_ioport m_j3a; + required_ioport m_j4; + required_ioport m_sw1; + + // floppy state + int m_drive; // selected drive + int m_head; // head loaded + int m_int_enbl; // interrupt enable + + // S-100 bus state + int m_access_enbl; // access enable + int m_board_enbl; // board enable + int m_phantom; // phantom +}; + + +// device type definition +extern const device_type S100_DJ2DB; + + +#endif diff --git a/src/devices/bus/s100/djdma.c b/src/devices/bus/s100/djdma.c new file mode 100644 index 00000000000..c0d93aed2f5 --- /dev/null +++ b/src/devices/bus/s100/djdma.c @@ -0,0 +1,127 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Morrow Designs Disk Jockey/DMA floppy controller board emulation + +**********************************************************************/ + +#include "djdma.h" + + + +//************************************************************************** +// MACROS/CONSTANTS +//************************************************************************** + +#define Z80_TAG "14a" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type S100_DJDMA = &device_creator; + + +//------------------------------------------------- +// ROM( djdma ) +//------------------------------------------------- + +ROM_START( djdma ) + ROM_REGION( 0x1000, Z80_TAG, 0 ) + ROM_LOAD( "djdma 2.5 26c2.16d", 0x0000, 0x1000, CRC(71ff1924) SHA1(6907575954836364826b8fdef3c108bb93bf3d25) ) + + ROM_REGION( 0x500, "proms", 0 ) + ROM_LOAD( "djdma2x.3d", 0x000, 0x200, CRC(f9b1648b) SHA1(1ebe6dc8ccfbfa6c7dc98cb65fbc9fa21e3b687f) ) + ROM_LOAD( "dj-11c-a.11c", 0x200, 0x200, CRC(0c6c4af0) SHA1(8fdcd34e3d07add793ff9ba27c77af864e1731bb) ) + ROM_LOAD( "dja-12b.12b", 0x400, 0x100, CRC(040044af) SHA1(d069dc0e6b680cb8848d165aff6681ed2d750961) ) + + ROM_REGION( 0x104, "plds", 0 ) + ROM_LOAD( "djdma-2b.2b", 0x000, 0x104, CRC(d6925f2c) SHA1(1e58dfb7b8a2a5bbaa6589d4018042626fd5ceaf) ) // PAL16R4 + ROM_LOAD( "djdma 2c 81d5.2c", 0x0000, 0x10, NO_DUMP ) // ? +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *s100_djdma_device::device_rom_region() const +{ + return ROM_NAME( djdma ); +} + + +//------------------------------------------------- +// ADDRESS_MAP( djdma_mem ) +//------------------------------------------------- + +static ADDRESS_MAP_START( djdma_mem, AS_PROGRAM, 8, s100_djdma_device ) + AM_RANGE(0x0000, 0x0fff) AM_ROM AM_REGION("14a", 0) +ADDRESS_MAP_END + + +//------------------------------------------------- +// ADDRESS_MAP( djdma_io ) +//------------------------------------------------- + +static ADDRESS_MAP_START( djdma_io, AS_IO, 8, s100_djdma_device ) +ADDRESS_MAP_END + + +//------------------------------------------------- +// MACHINE_CONFIG_FRAGMENT( s100_djdma ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( s100_djdma ) + MCFG_CPU_ADD(Z80_TAG, Z80, XTAL_4MHz) + MCFG_CPU_PROGRAM_MAP(djdma_mem) + MCFG_CPU_IO_MAP(djdma_io) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor s100_djdma_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( s100_djdma ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// s100_djdma_device - constructor +//------------------------------------------------- + +s100_djdma_device::s100_djdma_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, S100_DJDMA, "DJDMA", tag, owner, clock, "djdma", __FILE__), + device_s100_card_interface(mconfig, *this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void s100_djdma_device::device_start() +{ +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void s100_djdma_device::device_reset() +{ +} diff --git a/src/devices/bus/s100/djdma.h b/src/devices/bus/s100/djdma.h new file mode 100644 index 00000000000..b5b54c972c4 --- /dev/null +++ b/src/devices/bus/s100/djdma.h @@ -0,0 +1,51 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Morrow Designs Disk Jockey/DMA floppy controller board emulation + +**********************************************************************/ + +#pragma once + +#ifndef __S100_DJDMA__ +#define __S100_DJDMA__ + +#include "emu.h" +#include "s100.h" +#include "cpu/z80/z80.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> s100_djdma_device + +class s100_djdma_device : public device_t, + public device_s100_card_interface +{ +public: + // construction/destruction + s100_djdma_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual const rom_entry *device_rom_region() const; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + +private: + // internal state +}; + + +// device type definition +extern const device_type S100_DJDMA; + + +#endif diff --git a/src/devices/bus/s100/mm65k16s.c b/src/devices/bus/s100/mm65k16s.c new file mode 100644 index 00000000000..22240dd789a --- /dev/null +++ b/src/devices/bus/s100/mm65k16s.c @@ -0,0 +1,267 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Morrow Designs MM65K16S memory board emulation + +**********************************************************************/ + +#include "mm65k16s.h" + + + +//************************************************************************** +// MACROS/CONSTANTS +//************************************************************************** + + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type S100_MM65K16S = &device_creator; + + +//------------------------------------------------- +// ROM( mm65k16s ) +//------------------------------------------------- + +ROM_START( mm65k16s ) + ROM_REGION( 0x10000, "proms", 0 ) + ROM_LOAD( "82s100.6c", 0x0000, 0x10000, NO_DUMP ) + + ROM_REGION( 0x10, "plds", 0 ) + ROM_LOAD( "pal14l4.6d", 0x0000, 0x10, NO_DUMP ) + ROM_LOAD( "pal16l2.16d", 0x0000, 0x10, NO_DUMP ) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *s100_mm65k16s_device::device_rom_region() const +{ + return ROM_NAME( mm65k16s ); +} + + +//------------------------------------------------- +// INPUT_PORTS( mm65k16s ) +//------------------------------------------------- + +static INPUT_PORTS_START( mm65k16s ) + PORT_START("J6754") + PORT_DIPNAME( 0x01, 0x00, "Bank A Lower 32K" ) + PORT_DIPSETTING( 0x01, "Disabled" ) + PORT_DIPSETTING( 0x00, "Enabled" ) + PORT_DIPNAME( 0x02, 0x00, "Bank A Upper 32K" ) + PORT_DIPSETTING( 0x02, "Disabled" ) + PORT_DIPSETTING( 0x00, "Enabled" ) + PORT_DIPNAME( 0x04, 0x00, "Bank B Lower 32K" ) + PORT_DIPSETTING( 0x04, "Disabled" ) + PORT_DIPSETTING( 0x00, "Enabled" ) + PORT_DIPNAME( 0x08, 0x00, "Bank B Upper 32K" ) + PORT_DIPSETTING( 0x08, "Disabled" ) + PORT_DIPSETTING( 0x00, "Enabled" ) + + PORT_START("J2") + PORT_DIPNAME( 0x01, 0x00, "Bank A Recognizes Phantom" ) + PORT_DIPSETTING( 0x01, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x00, DEF_STR( On ) ) + + PORT_START("J1") + PORT_DIPNAME( 0x01, 0x00, "Bank B Recognizes Phantom" ) + PORT_DIPSETTING( 0x01, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x00, DEF_STR( On ) ) + + PORT_START("5D") + PORT_DIPNAME( 0x03, 0x00, "First 16K Memory Addressing" ) PORT_DIPLOCATION("5D:1,2") + PORT_DIPSETTING( 0x00, "Block 0 (0000H-3FFFH)" ) + PORT_DIPSETTING( 0x02, "Block 1 (4000H-7FFFH)" ) + PORT_DIPSETTING( 0x01, "Block 2 (8000H-BFFFH)" ) + PORT_DIPSETTING( 0x03, "Block 3 (C000H-FFFFH" ) + PORT_DIPNAME( 0x0c, 0x08, "Second 16K Memory Addressing" ) PORT_DIPLOCATION("5D:3,4") + PORT_DIPSETTING( 0x00, "Block 0 (0000H-3FFFH)" ) + PORT_DIPSETTING( 0x08, "Block 1 (4000H-7FFFH)" ) + PORT_DIPSETTING( 0x04, "Block 2 (8000H-BFFFH)" ) + PORT_DIPSETTING( 0x0c, "Block 3 (C000H-FFFFH" ) + PORT_DIPNAME( 0x30, 0x10, "Third 16K Memory Addressing" ) PORT_DIPLOCATION("5D:5,6") + PORT_DIPSETTING( 0x00, "Block 0 (0000H-3FFFH)" ) + PORT_DIPSETTING( 0x20, "Block 1 (4000H-7FFFH)" ) + PORT_DIPSETTING( 0x10, "Block 2 (8000H-BFFFH)" ) + PORT_DIPSETTING( 0x30, "Block 3 (C000H-FFFFH" ) + PORT_DIPNAME( 0xc0, 0xc0, "Fourth 16K Memory Addressing" ) PORT_DIPLOCATION("5D:7,8") + PORT_DIPSETTING( 0x00, "Block 0 (0000H-3FFFH)" ) + PORT_DIPSETTING( 0x80, "Block 1 (4000H-7FFFH)" ) + PORT_DIPSETTING( 0x40, "Block 2 (8000H-BFFFH)" ) + PORT_DIPSETTING( 0xc0, "Block 3 (C000H-FFFFH" ) + + PORT_START("PAGE07") + PORT_DIPNAME( 0x0f, 0x00, "2K Segment Disable" ) + PORT_DIPSETTING( 0x08, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x00, "Page 0" ) + PORT_DIPSETTING( 0x01, "Page 1" ) + PORT_DIPSETTING( 0x02, "Page 2" ) + PORT_DIPSETTING( 0x03, "Page 3" ) + PORT_DIPSETTING( 0x04, "Page 4" ) + PORT_DIPSETTING( 0x05, "Page 5" ) + PORT_DIPSETTING( 0x06, "Page 6" ) + PORT_DIPSETTING( 0x07, "Page 7" ) + + PORT_START("J3") + PORT_DIPNAME( 0x01, 0x01, "Addressing Mode" ) + PORT_DIPSETTING( 0x01, "Extended Addressing" ) + PORT_DIPSETTING( 0x00, "Bank Select" ) + + PORT_START("1C") + PORT_DIPNAME( 0xff, 0x00, "Extended Addressing" ) PORT_CONDITION("J3", 0x01, EQUALS, 0x01) + PORT_DIPSETTING( 0x00, "000000H" ) + // ... + PORT_DIPSETTING( 0xff, "FF0000H" ) + PORT_DIPNAME( 0xff, 0x40, "Bank Select Port" ) PORT_CONDITION("J3", 0x01, EQUALS, 0x00) + PORT_DIPSETTING( 0x00, "00H" ) + // ... + PORT_DIPSETTING( 0x40, "40H" ) + // ... + PORT_DIPSETTING( 0xff, "FFH" ) + + PORT_START("A0A7") + PORT_DIPNAME( 0x01, 0x01, "Bank Select Data Bit A0" ) PORT_CONDITION("J3", 0x01, EQUALS, 0x00) + PORT_DIPSETTING( 0x00, "0" ) + PORT_DIPSETTING( 0x01, "1" ) + PORT_DIPNAME( 0x02, 0x00, "Bank Select Data Bit A1" ) PORT_CONDITION("J3", 0x01, EQUALS, 0x00) + PORT_DIPSETTING( 0x00, "0" ) + PORT_DIPSETTING( 0x02, "1" ) + PORT_DIPNAME( 0x04, 0x00, "Bank Select Data Bit A2" ) PORT_CONDITION("J3", 0x01, EQUALS, 0x00) + PORT_DIPSETTING( 0x00, "0" ) + PORT_DIPSETTING( 0x04, "1" ) + PORT_DIPNAME( 0x08, 0x00, "Bank Select Data Bit A3" ) PORT_CONDITION("J3", 0x01, EQUALS, 0x00) + PORT_DIPSETTING( 0x00, "0" ) + PORT_DIPSETTING( 0x08, "1" ) + PORT_DIPNAME( 0x10, 0x00, "Bank Select Data Bit A4" ) PORT_CONDITION("J3", 0x01, EQUALS, 0x00) + PORT_DIPSETTING( 0x00, "0" ) + PORT_DIPSETTING( 0x10, "1" ) + PORT_DIPNAME( 0x20, 0x00, "Bank Select Data Bit A5" ) PORT_CONDITION("J3", 0x01, EQUALS, 0x00) + PORT_DIPSETTING( 0x00, "0" ) + PORT_DIPSETTING( 0x20, "1" ) + PORT_DIPNAME( 0x40, 0x00, "Bank Select Data Bit A6" ) PORT_CONDITION("J3", 0x01, EQUALS, 0x00) + PORT_DIPSETTING( 0x00, "0" ) + PORT_DIPSETTING( 0x40, "1" ) + PORT_DIPNAME( 0x80, 0x00, "Bank Select Data Bit A7" ) PORT_CONDITION("J3", 0x01, EQUALS, 0x00) + PORT_DIPSETTING( 0x00, "0" ) + PORT_DIPSETTING( 0x80, "1" ) + + PORT_START("0B7B") + PORT_DIPNAME( 0x01, 0x00, "Bank Select Data Bit 0B" ) PORT_CONDITION("J3", 0x01, EQUALS, 0x00) + PORT_DIPSETTING( 0x00, "0" ) + PORT_DIPSETTING( 0x01, "1" ) + PORT_DIPNAME( 0x02, 0x00, "Bank Select Data Bit 1B" ) PORT_CONDITION("J3", 0x01, EQUALS, 0x00) + PORT_DIPSETTING( 0x00, "0" ) + PORT_DIPSETTING( 0x02, "1" ) + PORT_DIPNAME( 0x04, 0x00, "Bank Select Data Bit 2B" ) PORT_CONDITION("J3", 0x01, EQUALS, 0x00) + PORT_DIPSETTING( 0x00, "0" ) + PORT_DIPSETTING( 0x04, "1" ) + PORT_DIPNAME( 0x08, 0x00, "Bank Select Data Bit 3B" ) PORT_CONDITION("J3", 0x01, EQUALS, 0x00) + PORT_DIPSETTING( 0x00, "0" ) + PORT_DIPSETTING( 0x08, "1" ) + PORT_DIPNAME( 0x10, 0x00, "Bank Select Data Bit 4B" ) PORT_CONDITION("J3", 0x01, EQUALS, 0x00) + PORT_DIPSETTING( 0x00, "0" ) + PORT_DIPSETTING( 0x10, "1" ) + PORT_DIPNAME( 0x20, 0x00, "Bank Select Data Bit 5B" ) PORT_CONDITION("J3", 0x01, EQUALS, 0x00) + PORT_DIPSETTING( 0x00, "0" ) + PORT_DIPSETTING( 0x20, "1" ) + PORT_DIPNAME( 0x40, 0x00, "Bank Select Data Bit 6B" ) PORT_CONDITION("J3", 0x01, EQUALS, 0x00) + PORT_DIPSETTING( 0x00, "0" ) + PORT_DIPSETTING( 0x40, "1" ) + PORT_DIPNAME( 0x80, 0x00, "Bank Select Data Bit 7B" ) PORT_CONDITION("J3", 0x01, EQUALS, 0x00) + PORT_DIPSETTING( 0x00, "0" ) + PORT_DIPSETTING( 0x80, "1" ) +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor s100_mm65k16s_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( mm65k16s ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// s100_mm65k16s_device - constructor +//------------------------------------------------- + +s100_mm65k16s_device::s100_mm65k16s_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, S100_MM65K16S, "MM65K16S", tag, owner, clock, "mm65k16s", __FILE__), + device_s100_card_interface(mconfig, *this), + m_ram(*this, "ram") +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void s100_mm65k16s_device::device_start() +{ + m_ram.allocate(0x10000); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void s100_mm65k16s_device::device_reset() +{ +} + + +//------------------------------------------------- +// s100_smemr_r - memory read +//------------------------------------------------- + +UINT8 s100_mm65k16s_device::s100_smemr_r(address_space &space, offs_t offset) +{ + UINT8 data = 0; + + if (offset < 0xf800) + { + data = m_ram[offset]; + } + + return data; +} + + +//------------------------------------------------- +// s100_mwrt_w - memory write +//------------------------------------------------- + +void s100_mm65k16s_device::s100_mwrt_w(address_space &space, offs_t offset, UINT8 data) +{ + if (offset < 0xf800) + { + m_ram[offset] = data; + } +} + + +//------------------------------------------------- +// s100_phantom_w - phantom +//------------------------------------------------- + +void s100_mm65k16s_device::s100_phantom_w(int state) +{ +} diff --git a/src/devices/bus/s100/mm65k16s.h b/src/devices/bus/s100/mm65k16s.h new file mode 100644 index 00000000000..35d9cbc21c5 --- /dev/null +++ b/src/devices/bus/s100/mm65k16s.h @@ -0,0 +1,55 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Morrow Designs MM65K16S memory board emulation + +**********************************************************************/ + +#pragma once + +#ifndef __S100_MM65K16S__ +#define __S100_MM65K16S__ + +#include "emu.h" +#include "s100.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> s100_mm65k16s_device + +class s100_mm65k16s_device : public device_t, + public device_s100_card_interface +{ +public: + // construction/destruction + s100_mm65k16s_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual ioport_constructor device_input_ports() const; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_s100_card_interface overrides + virtual UINT8 s100_smemr_r(address_space &space, offs_t offset); + virtual void s100_mwrt_w(address_space &space, offs_t offset, UINT8 data); + virtual void s100_phantom_w(int state); + +private: + optional_shared_ptr m_ram; +}; + + +// device type definition +extern const device_type S100_MM65K16S; + + +#endif diff --git a/src/devices/bus/s100/nsmdsa.c b/src/devices/bus/s100/nsmdsa.c new file mode 100644 index 00000000000..91fb4f46135 --- /dev/null +++ b/src/devices/bus/s100/nsmdsa.c @@ -0,0 +1,120 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + North Star MICRO-DISK System MDS-A (Single Density) emulation + +**********************************************************************/ + +#include "nsmdsa.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type S100_MDS_A = &device_creator; + + +//------------------------------------------------- +// ROM( mds_a ) +//------------------------------------------------- + +ROM_START( mds_a ) + ROM_REGION( 0x100, "psel", 0 ) + ROM_LOAD( "psel.7g", 0x000, 0x100, NO_DUMP ) // 74S287 + + ROM_REGION( 0x100, "pgm", 0 ) + ROM_LOAD( "pgml.3f", 0x000, 0x100, NO_DUMP ) // 74S287 + ROM_LOAD( "pgmr.3e", 0x000, 0x100, NO_DUMP ) // 74S287 + ROM_LOAD( "horizon.bin", 0x000, 0x100, CRC(754e53e5) SHA1(875e42942d639b972252b87d86c3dc2133304967) BAD_DUMP ) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *s100_mds_a_device::device_rom_region() const +{ + return ROM_NAME( mds_a ); +} + + +//------------------------------------------------- +// SLOT_INTERFACE( mds_a_floppies ) +//------------------------------------------------- + +static SLOT_INTERFACE_START( mds_a_floppies ) + SLOT_INTERFACE( "525sd", FLOPPY_525_SD ) // Shugart SA-400 +SLOT_INTERFACE_END + + +//------------------------------------------------- +// MACHINE_CONFIG_FRAGMENT( mds_a ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( mds_a ) + MCFG_FLOPPY_DRIVE_ADD("floppy0", mds_a_floppies, "525sd", floppy_image_device::default_floppy_formats) + MCFG_FLOPPY_DRIVE_ADD("floppy1", mds_a_floppies, "525sd", floppy_image_device::default_floppy_formats) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor s100_mds_a_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( mds_a ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// s100_mds_a_device - constructor +//------------------------------------------------- + +s100_mds_a_device::s100_mds_a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, S100_MDS_A, "MDS-A", tag, owner, clock, "nsmdsa", __FILE__), + device_s100_card_interface(mconfig, *this), + m_floppy0(*this, "floppy0"), + m_floppy1(*this, "floppy1"), + m_psel_rom(*this, "psel"), + m_pgm_rom(*this, "pgm") +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void s100_mds_a_device::device_start() +{ +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void s100_mds_a_device::device_reset() +{ +} + + +//------------------------------------------------- +// s100_smemr_r - memory read +//------------------------------------------------- + +UINT8 s100_mds_a_device::s100_smemr_r(address_space &space, offs_t offset) +{ + return 0; +} diff --git a/src/devices/bus/s100/nsmdsa.h b/src/devices/bus/s100/nsmdsa.h new file mode 100644 index 00000000000..88a2f330391 --- /dev/null +++ b/src/devices/bus/s100/nsmdsa.h @@ -0,0 +1,58 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + North Star MICRO-DISK System MDS-A (Single Density) emulation + +**********************************************************************/ + +#pragma once + +#ifndef __S100_MDS_A__ +#define __S100_MDS_A__ + +#include "emu.h" +#include "s100.h" +#include "imagedev/floppy.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> s100_mds_a_device + +class s100_mds_a_device : public device_t, + public device_s100_card_interface +{ +public: + // construction/destruction + s100_mds_a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_s100_card_interface overrides + virtual UINT8 s100_smemr_r(address_space &space, offs_t offset); + +private: + required_device m_floppy0; + required_device m_floppy1; + required_memory_region m_psel_rom; + required_memory_region m_pgm_rom; +}; + + +// device type definition +extern const device_type S100_MDS_A; + + + +#endif diff --git a/src/devices/bus/s100/nsmdsad.c b/src/devices/bus/s100/nsmdsad.c new file mode 100644 index 00000000000..d1a06407c6d --- /dev/null +++ b/src/devices/bus/s100/nsmdsad.c @@ -0,0 +1,122 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + North Star MICRO-DISK System MDS-A-D (Double Density) emulation + +**********************************************************************/ + +#include "nsmdsad.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type S100_MDS_AD = &device_creator; + + +//------------------------------------------------- +// ROM( mds_ad ) +//------------------------------------------------- + +ROM_START( mds_ad ) + ROM_REGION( 0x100, "dsel", 0 ) + ROM_LOAD( "dsel.11c", 0x000, 0x100, NO_DUMP ) // 82S129 + + ROM_REGION( 0x100, "dpgm", 0 ) + ROM_LOAD( "dpgm.9d", 0x000, 0x100, CRC(7aafa134) SHA1(bf1552c4818f30473798af4f54e65e1957e0db48) ) + + ROM_REGION( 0x100, "dwe", 0 ) + ROM_LOAD( "dwe.4c", 0x000, 0x100, NO_DUMP ) // 82S129 +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *s100_mds_ad_device::device_rom_region() const +{ + return ROM_NAME( mds_ad ); +} + + +//------------------------------------------------- +// SLOT_INTERFACE( mds_ad_floppies ) +//------------------------------------------------- + +static SLOT_INTERFACE_START( mds_ad_floppies ) + SLOT_INTERFACE( "525dd", FLOPPY_525_DD ) // Shugart SA-400 +SLOT_INTERFACE_END + + +//------------------------------------------------- +// MACHINE_CONFIG_FRAGMENT( mds_ad ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( mds_ad ) + MCFG_FLOPPY_DRIVE_ADD("floppy0", mds_ad_floppies, "525dd", floppy_image_device::default_floppy_formats) + MCFG_FLOPPY_DRIVE_ADD("floppy1", mds_ad_floppies, "525dd", floppy_image_device::default_floppy_formats) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor s100_mds_ad_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( mds_ad ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// s100_mds_ad_device - constructor +//------------------------------------------------- + +s100_mds_ad_device::s100_mds_ad_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, S100_MDS_AD, "MDS-A-D", tag, owner, clock, "nsmdsad", __FILE__), + device_s100_card_interface(mconfig, *this), + m_floppy0(*this, "floppy0"), + m_floppy1(*this, "floppy1"), + m_dsel_rom(*this, "dsel"), + m_dpgm_rom(*this, "dpgm"), + m_dwe_rom(*this, "dwe") +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void s100_mds_ad_device::device_start() +{ +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void s100_mds_ad_device::device_reset() +{ +} + + +//------------------------------------------------- +// s100_smemr_r - memory read +//------------------------------------------------- + +UINT8 s100_mds_ad_device::s100_smemr_r(address_space &space, offs_t offset) +{ + return 0; +} diff --git a/src/devices/bus/s100/nsmdsad.h b/src/devices/bus/s100/nsmdsad.h new file mode 100644 index 00000000000..1c156590ba1 --- /dev/null +++ b/src/devices/bus/s100/nsmdsad.h @@ -0,0 +1,59 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + North Star MICRO-DISK System MDS-A-D (Double Density) emulation + +**********************************************************************/ + +#pragma once + +#ifndef __S100_MDS_AD__ +#define __S100_MDS_AD__ + +#include "emu.h" +#include "s100.h" +#include "imagedev/floppy.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> s100_mds_ad_device + +class s100_mds_ad_device : public device_t, + public device_s100_card_interface +{ +public: + // construction/destruction + s100_mds_ad_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_s100_card_interface overrides + virtual UINT8 s100_smemr_r(address_space &space, offs_t offset); + +private: + required_device m_floppy0; + required_device m_floppy1; + required_memory_region m_dsel_rom; + required_memory_region m_dpgm_rom; + required_memory_region m_dwe_rom; +}; + + +// device type definition +extern const device_type S100_MDS_AD; + + + +#endif diff --git a/src/devices/bus/s100/s100.c b/src/devices/bus/s100/s100.c new file mode 100644 index 00000000000..aee9ecbccf6 --- /dev/null +++ b/src/devices/bus/s100/s100.c @@ -0,0 +1,200 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + S-100 (IEEE-696/1983) bus emulation + +**********************************************************************/ + +#include "s100.h" + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type S100_BUS = &device_creator; +const device_type S100_SLOT = &device_creator; + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// device_s100_card_interface - constructor +//------------------------------------------------- + +device_s100_card_interface::device_s100_card_interface(const machine_config &mconfig, device_t &device) + : device_slot_card_interface(mconfig, device) +{ +} + + +//------------------------------------------------- +// s100_slot_t - constructor +//------------------------------------------------- +s100_slot_t::s100_slot_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, S100_SLOT, "S100 slot", tag, owner, clock, "s100_slot", __FILE__), + device_slot_interface(mconfig, *this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void s100_slot_t::device_start() +{ + m_bus = machine().device(S100_TAG); + device_s100_card_interface *dev = dynamic_cast(get_card_device()); + if (dev) m_bus->add_card(dev); +} + + +//------------------------------------------------- +// s100_bus_t - constructor +//------------------------------------------------- + +s100_bus_t::s100_bus_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, S100_BUS, "S100", tag, owner, clock, "s100", __FILE__), + m_write_irq(*this), + m_write_nmi(*this), + m_write_vi0(*this), + m_write_vi1(*this), + m_write_vi2(*this), + m_write_vi3(*this), + m_write_vi4(*this), + m_write_vi5(*this), + m_write_vi6(*this), + m_write_vi7(*this), + m_write_dma0(*this), + m_write_dma1(*this), + m_write_dma2(*this), + m_write_dma3(*this), + m_write_rdy(*this), + m_write_hold(*this), + m_write_error(*this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void s100_bus_t::device_start() +{ + // resolve callbacks + m_write_irq.resolve_safe(); + m_write_nmi.resolve_safe(); + m_write_vi0.resolve_safe(); + m_write_vi1.resolve_safe(); + m_write_vi2.resolve_safe(); + m_write_vi3.resolve_safe(); + m_write_vi4.resolve_safe(); + m_write_vi5.resolve_safe(); + m_write_vi6.resolve_safe(); + m_write_vi7.resolve_safe(); + m_write_dma0.resolve_safe(); + m_write_dma1.resolve_safe(); + m_write_dma2.resolve_safe(); + m_write_dma3.resolve_safe(); + m_write_rdy.resolve_safe(); + m_write_hold.resolve_safe(); + m_write_error.resolve_safe(); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void s100_bus_t::device_reset() +{ +} + + +//------------------------------------------------- +// add_card - add card +//------------------------------------------------- + +void s100_bus_t::add_card(device_s100_card_interface *card) +{ + card->m_bus = this; + m_device_list.append(*card); +} + + +//------------------------------------------------- +// smemr_r - memory read +//------------------------------------------------- + +READ8_MEMBER( s100_bus_t::smemr_r ) +{ + UINT8 data = 0; + + device_s100_card_interface *entry = m_device_list.first(); + + while (entry) + { + data |= entry->s100_smemr_r(space, offset); + entry = entry->next(); + } + + return data; +} + + +//------------------------------------------------- +// mwrt_w - memory write +//------------------------------------------------- + +WRITE8_MEMBER( s100_bus_t::mwrt_w ) +{ + device_s100_card_interface *entry = m_device_list.first(); + + while (entry) + { + entry->s100_mwrt_w(space, offset, data); + entry = entry->next(); + } +} + + +//------------------------------------------------- +// sinp_r - I/O read +//------------------------------------------------- + +READ8_MEMBER( s100_bus_t::sinp_r ) +{ + UINT8 data = 0; + + device_s100_card_interface *entry = m_device_list.first(); + + while (entry) + { + data |= entry->s100_sinp_r(space, offset); + entry = entry->next(); + } + + return data; +} + + +//------------------------------------------------- +// sout_w - I/O write +//------------------------------------------------- + +WRITE8_MEMBER( s100_bus_t::sout_w ) +{ + device_s100_card_interface *entry = m_device_list.first(); + + while (entry) + { + entry->s100_sout_w(space, offset, data); + entry = entry->next(); + } +} diff --git a/src/devices/bus/s100/s100.h b/src/devices/bus/s100/s100.h new file mode 100644 index 00000000000..9d622b573b6 --- /dev/null +++ b/src/devices/bus/s100/s100.h @@ -0,0 +1,311 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + S-100 (IEEE Std 696-1983) bus emulation + +********************************************************************** + + +8 V (B) 1 51 +8 V (B) + +16 V (B) 2 52 -16 V (B) + XRDY (S) 3 53 0 V + VI0* (S) 4 54 SLAVE CLR* (B) + VI1* (S) 5 55 TMA0* (M) + VI2* (S) 6 56 TMA1* (M) + VI3* (S) 7 57 TMA2* (M) + VI4* (S) 8 58 sXTRQ* (M) + VI5* (S) 9 59 A19 (M) + VI6* (S) 10 60 SIXTN* (S) + VI7* (S) 11 61 A20 (M) + NMI* (S) 12 62 A21 (M) + PWRFAIL* (B) 13 63 A22 (M) + TMA3* (M) 14 64 A23 (M) + A18 (M) 15 65 NDEF + A16 (M) 16 66 NDEF + A17 (M) 17 67 PHANTOM* (M/S) + SDSB* (M) 18 68 MWRT (B) + CDSB* (M) 19 69 RFU + 0 V 20 70 0 V + NDEF 21 71 RFU + ADSB* (M) 22 72 RDY (S) + DODSB* (M) 23 73 INT* (S) + phi (B) 24 74 HOLD* (M) + pSTVAL* (M) 25 75 RESET* (B) + pHLDA (M) 26 76 pSYNC (M) + RFU 27 77 pWR* (M) + RFU 28 78 pDBIN (M) + A5 (M) 29 79 A0 (M) + A4 (M) 30 80 A1 (M) + A3 (M) 31 81 A2 (M) + A15 (M) 32 82 A6 (M) + A12 (M) 33 83 A7 (M) + A9 (M) 34 84 A8 (M) + DO1 (M)/ED1 (M/S) 35 85 A13 (M) + DO0 (M)/ED0 (M/S) 36 86 A14 (M) + A10 (M) 37 87 A11 (M) + DO4 (M)/ED4 (M/S) 38 88 DO2 (M)/ED2 (M/S) + DO5 (M)/ED5 (M/S) 39 89 DO3 (M)/ED3 (M/S) + DO6 (M)/ED6 (M/S) 40 90 DO7 (M)/ED7 (M/S) + DI2 (M)/OD2 (M/S) 41 91 DI4 (M)/OD4 (M/S) + DI3 (M)/OD3 (M/S) 42 92 DI5 (M)/OD5 (M/S) + DI7 (M)/OD7 (M/S) 43 93 DI6 (M)/OD6 (M/S) + sM1 (M) 44 94 DI1 (M)/OD1 (M/S) + sOUT (M) 45 95 DI0 (M)/OD0 (M/S) + sINP (M) 46 96 sINTA (M) + sMEMR (M) 47 97 sWO* (M) + sHLTA (M) 48 98 ERROR* (S) + CLOCK (B) 49 99 POC* (B) + 0 V 50 100 0 V + +**********************************************************************/ + +#pragma once + +#ifndef __S100__ +#define __S100__ + +#include "emu.h" + + + +//************************************************************************** +// CONSTANTS +//************************************************************************** + +#define S100_TAG "s100" + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_S100_BUS_ADD() \ + MCFG_DEVICE_ADD(S100_TAG, S100_BUS, 0) + +#define MCFG_S100_SLOT_ADD(_tag, _slot_intf, _def_slot) \ + MCFG_DEVICE_ADD(_tag, S100_SLOT, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) + + +#define MCFG_S100_IRQ_CALLBACK(_write) \ + devcb = &s100_bus_t::set_irq_wr_callback(*device, DEVCB_##_write); + +#define MCFG_S100_NMI_CALLBACK(_write) \ + devcb = &s100_bus_t::set_nmi_wr_callback(*device, DEVCB_##_write); + +#define MCFG_S100_VI0_CALLBACK(_write) \ + devcb = &s100_bus_t::set_vi0_wr_callback(*device, DEVCB_##_write); + +#define MCFG_S100_VI1_CALLBACK(_write) \ + devcb = &s100_bus_t::set_vi1_wr_callback(*device, DEVCB_##_write); + +#define MCFG_S100_VI2_CALLBACK(_write) \ + devcb = &s100_bus_t::set_vi2_wr_callback(*device, DEVCB_##_write); + +#define MCFG_S100_VI3_CALLBACK(_write) \ + devcb = &s100_bus_t::set_vi3_wr_callback(*device, DEVCB_##_write); + +#define MCFG_S100_VI4_CALLBACK(_write) \ + devcb = &s100_bus_t::set_vi4_wr_callback(*device, DEVCB_##_write); + +#define MCFG_S100_VI5_CALLBACK(_write) \ + devcb = &s100_bus_t::set_vi5_wr_callback(*device, DEVCB_##_write); + +#define MCFG_S100_VI6_CALLBACK(_write) \ + devcb = &s100_bus_t::set_vi6_wr_callback(*device, DEVCB_##_write); + +#define MCFG_S100_VI7_CALLBACK(_write) \ + devcb = &s100_bus_t::set_vi7_wr_callback(*device, DEVCB_##_write); + +#define MCFG_S100_DMA0_CALLBACK(_write) \ + devcb = &s100_bus_t::set_dma0_wr_callback(*device, DEVCB_##_write); + +#define MCFG_S100_DMA1_CALLBACK(_write) \ + devcb = &s100_bus_t::set_dma1_wr_callback(*device, DEVCB_##_write); + +#define MCFG_S100_DMA2_CALLBACK(_write) \ + devcb = &s100_bus_t::set_dma2_wr_callback(*device, DEVCB_##_write); + +#define MCFG_S100_DMA3_CALLBACK(_write) \ + devcb = &s100_bus_t::set_dma3_wr_callback(*device, DEVCB_##_write); + +#define MCFG_S100_RDY_CALLBACK(_write) \ + devcb = &s100_bus_t::set_rdy_wr_callback(*device, DEVCB_##_write); + +#define MCFG_S100_HOLD_CALLBACK(_write) \ + devcb = &s100_bus_t::set_hold_wr_callback(*device, DEVCB_##_write); + +#define MCFG_S100_ERROR_CALLBACK(_write) \ + devcb = &s100_bus_t::set_error_wr_callback(*device, DEVCB_##_write); + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class s100_bus_t; + +// ======================> device_s100_card_interface + +class device_s100_card_interface : public device_slot_card_interface +{ + friend class s100_bus_t; + +public: + // construction/destruction + device_s100_card_interface(const machine_config &mconfig, device_t &device); + virtual ~device_s100_card_interface() { } + + device_s100_card_interface *next() const { return m_next; } + + // interrupts + virtual void s100_int_w(int state) { }; + virtual void s100_nmi_w(int state) { }; + virtual UINT8 s100_sinta_r(offs_t offset) { return 0; }; + + // vectored interrupts + virtual void s100_vi0_w(int state) { }; + virtual void s100_vi1_w(int state) { }; + virtual void s100_vi2_w(int state) { }; + virtual void s100_vi3_w(int state) { }; + virtual void s100_vi4_w(int state) { }; + virtual void s100_vi5_w(int state) { }; + virtual void s100_vi6_w(int state) { }; + virtual void s100_vi7_w(int state) { }; + + // memory access + virtual UINT8 s100_smemr_r(address_space &space, offs_t offset) { return 0; }; + virtual void s100_mwrt_w(address_space &space, offs_t offset, UINT8 data) { }; + + // I/O access + virtual UINT8 s100_sinp_r(address_space &space, offs_t offset) { return 0; }; + virtual void s100_sout_w(address_space &space, offs_t offset, UINT8 data) { }; + + // configuration access + virtual void s100_phlda_w(int state) { } + virtual void s100_shalta_w(int state) { } + virtual void s100_phantom_w(int state) { } + virtual void s100_sxtrq_w(int state) { } + virtual int s100_sixtn_r() { return 1; } + + // reset + virtual void s100_poc_w(int state) { } + virtual void s100_reset_w(int state) { } + virtual void s100_slave_clr_w(int state) { } + +public: + s100_bus_t *m_bus; + device_s100_card_interface *m_next; +}; + + + +// ======================> s100_bus_t + +class s100_bus_t : public device_t +{ +public: + // construction/destruction + s100_bus_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + ~s100_bus_t() { m_device_list.detach_all(); } + + template static devcb_base &set_irq_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_irq.set_callback(object); } + template static devcb_base &set_nmi_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_nmi.set_callback(object); } + template static devcb_base &set_vi0_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_vi0.set_callback(object); } + template static devcb_base &set_vi1_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_vi1.set_callback(object); } + template static devcb_base &set_vi2_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_vi2.set_callback(object); } + template static devcb_base &set_vi3_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_vi3.set_callback(object); } + template static devcb_base &set_vi4_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_vi4.set_callback(object); } + template static devcb_base &set_vi5_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_vi5.set_callback(object); } + template static devcb_base &set_vi6_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_vi6.set_callback(object); } + template static devcb_base &set_vi7_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_vi7.set_callback(object); } + template static devcb_base &set_dma0_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_dma0.set_callback(object); } + template static devcb_base &set_dma1_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_dma1.set_callback(object); } + template static devcb_base &set_dma2_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_dma2.set_callback(object); } + template static devcb_base &set_dma3_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_dma3.set_callback(object); } + template static devcb_base &set_rdy_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_rdy.set_callback(object); } + template static devcb_base &set_hold_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_hold.set_callback(object); } + template static devcb_base &set_error_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_error.set_callback(object); } + + void add_card(device_s100_card_interface *card); + + DECLARE_READ8_MEMBER( smemr_r ); + DECLARE_WRITE8_MEMBER( mwrt_w ); + + DECLARE_READ8_MEMBER( sinp_r ); + DECLARE_WRITE8_MEMBER( sout_w ); + + DECLARE_WRITE_LINE_MEMBER( irq_w ) { m_write_irq(state); } + DECLARE_WRITE_LINE_MEMBER( nmi_w ) { m_write_nmi(state); } + DECLARE_WRITE_LINE_MEMBER( vi0_w ) { m_write_vi0(state); } + DECLARE_WRITE_LINE_MEMBER( vi1_w ) { m_write_vi1(state); } + DECLARE_WRITE_LINE_MEMBER( vi2_w ) { m_write_vi2(state); } + DECLARE_WRITE_LINE_MEMBER( vi3_w ) { m_write_vi3(state); } + DECLARE_WRITE_LINE_MEMBER( vi4_w ) { m_write_vi4(state); } + DECLARE_WRITE_LINE_MEMBER( vi5_w ) { m_write_vi5(state); } + DECLARE_WRITE_LINE_MEMBER( vi6_w ) { m_write_vi6(state); } + DECLARE_WRITE_LINE_MEMBER( vi7_w ) { m_write_vi7(state); } + DECLARE_WRITE_LINE_MEMBER( dma0_w ) { m_write_dma0(state); } + DECLARE_WRITE_LINE_MEMBER( dma1_w ) { m_write_dma1(state); } + DECLARE_WRITE_LINE_MEMBER( dma2_w ) { m_write_dma2(state); } + DECLARE_WRITE_LINE_MEMBER( dma3_w ) { m_write_dma3(state); } + DECLARE_WRITE_LINE_MEMBER( rdy_w ) { m_write_rdy(state); } + DECLARE_WRITE_LINE_MEMBER( hold_w ) { m_write_hold(state); } + DECLARE_WRITE_LINE_MEMBER( error_w ) { m_write_error(state); } + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + +private: + devcb_write_line m_write_irq; + devcb_write_line m_write_nmi; + devcb_write_line m_write_vi0; + devcb_write_line m_write_vi1; + devcb_write_line m_write_vi2; + devcb_write_line m_write_vi3; + devcb_write_line m_write_vi4; + devcb_write_line m_write_vi5; + devcb_write_line m_write_vi6; + devcb_write_line m_write_vi7; + devcb_write_line m_write_dma0; + devcb_write_line m_write_dma1; + devcb_write_line m_write_dma2; + devcb_write_line m_write_dma3; + devcb_write_line m_write_rdy; + devcb_write_line m_write_hold; + devcb_write_line m_write_error; + + simple_list m_device_list; +}; + + +// ======================> s100_slot_t + +class s100_slot_t : public device_t, + public device_slot_interface +{ +public: + // construction/destruction + s100_slot_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + +private: + s100_bus_t *m_bus; +}; + + + +// device type definition +extern const device_type S100_BUS; +extern const device_type S100_SLOT; + + + + +#endif diff --git a/src/devices/bus/s100/wunderbus.c b/src/devices/bus/s100/wunderbus.c new file mode 100644 index 00000000000..4b269a80e93 --- /dev/null +++ b/src/devices/bus/s100/wunderbus.c @@ -0,0 +1,528 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Morrow Designs Wunderbus I/O card emulation + +**********************************************************************/ + +#include "wunderbus.h" +#include "bus/rs232/rs232.h" + + + +//************************************************************************** +// MACROS/CONSTANTS +//************************************************************************** + +#define I8259A_TAG "13b" +#define INS8250_1_TAG "6d" +#define INS8250_2_TAG "5d" +#define INS8250_3_TAG "4d" +#define RS232_A_TAG "rs232a" +#define RS232_B_TAG "rs232b" +#define RS232_C_TAG "rs232c" +#define UPD1990C_TAG "12a" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type S100_WUNDERBUS = &device_creator; + + +//------------------------------------------------- +// pic8259_interface pic_intf +//------------------------------------------------- + +/* + + bit description + + IR0 S-100 VI0 + IR1 S-100 VI1 + IR2 S-100 VI2 + IR3 Serial Device 1 + IR4 Serial Device 2 + IR5 Serial Device 3 + IR6 Daisy PWR line + IR7 RT Clock TP line + +*/ + +WRITE_LINE_MEMBER( s100_wunderbus_device::pic_int_w ) +{ + m_bus->irq_w(state); +} + +static DEVICE_INPUT_DEFAULTS_START( terminal ) + DEVICE_INPUT_DEFAULTS( "RS232_TXBAUD", 0xff, RS232_BAUD_110 ) + DEVICE_INPUT_DEFAULTS( "RS232_RXBAUD", 0xff, RS232_BAUD_110 ) + DEVICE_INPUT_DEFAULTS( "RS232_STARTBITS", 0xff, RS232_STARTBITS_1 ) + DEVICE_INPUT_DEFAULTS( "RS232_DATABITS", 0xff, RS232_DATABITS_8 ) + DEVICE_INPUT_DEFAULTS( "RS232_PARITY", 0xff, RS232_PARITY_NONE ) + DEVICE_INPUT_DEFAULTS( "RS232_STOPBITS", 0xff, RS232_STOPBITS_2 ) +DEVICE_INPUT_DEFAULTS_END + + +//------------------------------------------------- +// UPD1990A_INTERFACE( rtc_intf ) +//------------------------------------------------- + +WRITE_LINE_MEMBER( s100_wunderbus_device::rtc_tp_w ) +{ + if (state) + { + m_rtc_tp = state; + m_pic->ir7_w(m_rtc_tp); + } +} + + +//------------------------------------------------- +// MACHINE_CONFIG_FRAGMENT( s100_wunderbus ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( s100_wunderbus ) + MCFG_PIC8259_ADD(I8259A_TAG, DEVWRITELINE(DEVICE_SELF, s100_wunderbus_device, pic_int_w), VCC, NULL) + MCFG_DEVICE_ADD(INS8250_1_TAG, INS8250, XTAL_18_432MHz/10) + MCFG_INS8250_OUT_TX_CB(DEVWRITELINE(RS232_A_TAG, rs232_port_device, write_txd)) + MCFG_INS8250_OUT_DTR_CB(DEVWRITELINE(RS232_A_TAG, rs232_port_device, write_dtr)) + MCFG_INS8250_OUT_RTS_CB(DEVWRITELINE(RS232_A_TAG, rs232_port_device, write_rts)) + MCFG_INS8250_OUT_INT_CB(DEVWRITELINE(I8259A_TAG, pic8259_device, ir3_w)) + MCFG_DEVICE_ADD(INS8250_2_TAG, INS8250, XTAL_18_432MHz/10) + MCFG_INS8250_OUT_TX_CB(DEVWRITELINE(RS232_B_TAG, rs232_port_device, write_txd)) + MCFG_INS8250_OUT_DTR_CB(DEVWRITELINE(RS232_B_TAG, rs232_port_device, write_dtr)) + MCFG_INS8250_OUT_RTS_CB(DEVWRITELINE(RS232_B_TAG, rs232_port_device, write_rts)) + MCFG_INS8250_OUT_INT_CB(DEVWRITELINE(I8259A_TAG, pic8259_device, ir4_w)) + MCFG_DEVICE_ADD(INS8250_3_TAG, INS8250, XTAL_18_432MHz/10) + MCFG_INS8250_OUT_TX_CB(DEVWRITELINE(RS232_C_TAG, rs232_port_device, write_txd)) + MCFG_INS8250_OUT_DTR_CB(DEVWRITELINE(RS232_C_TAG, rs232_port_device, write_dtr)) + MCFG_INS8250_OUT_RTS_CB(DEVWRITELINE(RS232_C_TAG, rs232_port_device, write_rts)) + MCFG_INS8250_OUT_INT_CB(DEVWRITELINE(I8259A_TAG, pic8259_device, ir5_w)) + + MCFG_RS232_PORT_ADD(RS232_A_TAG, default_rs232_devices, "terminal") + MCFG_RS232_RXD_HANDLER(DEVWRITELINE(INS8250_1_TAG, ins8250_uart_device, rx_w)) + MCFG_RS232_DCD_HANDLER(DEVWRITELINE(INS8250_1_TAG, ins8250_uart_device, dcd_w)) + MCFG_RS232_DSR_HANDLER(DEVWRITELINE(INS8250_1_TAG, ins8250_uart_device, dsr_w)) + MCFG_RS232_RI_HANDLER(DEVWRITELINE(INS8250_1_TAG, ins8250_uart_device, ri_w)) + MCFG_RS232_CTS_HANDLER(DEVWRITELINE(INS8250_1_TAG, ins8250_uart_device, cts_w)) + MCFG_DEVICE_CARD_DEVICE_INPUT_DEFAULTS("terminal", terminal) + + MCFG_RS232_PORT_ADD(RS232_B_TAG, default_rs232_devices, NULL) + MCFG_RS232_RXD_HANDLER(DEVWRITELINE(INS8250_2_TAG, ins8250_uart_device, rx_w)) + MCFG_RS232_DCD_HANDLER(DEVWRITELINE(INS8250_2_TAG, ins8250_uart_device, dcd_w)) + MCFG_RS232_DSR_HANDLER(DEVWRITELINE(INS8250_2_TAG, ins8250_uart_device, dsr_w)) + MCFG_RS232_RI_HANDLER(DEVWRITELINE(INS8250_2_TAG, ins8250_uart_device, ri_w)) + MCFG_RS232_CTS_HANDLER(DEVWRITELINE(INS8250_2_TAG, ins8250_uart_device, cts_w)) + + MCFG_RS232_PORT_ADD(RS232_C_TAG, default_rs232_devices, NULL) + MCFG_RS232_RXD_HANDLER(DEVWRITELINE(INS8250_3_TAG, ins8250_uart_device, rx_w)) + MCFG_RS232_DCD_HANDLER(DEVWRITELINE(INS8250_3_TAG, ins8250_uart_device, dcd_w)) + MCFG_RS232_DSR_HANDLER(DEVWRITELINE(INS8250_3_TAG, ins8250_uart_device, dsr_w)) + MCFG_RS232_RI_HANDLER(DEVWRITELINE(INS8250_3_TAG, ins8250_uart_device, ri_w)) + MCFG_RS232_CTS_HANDLER(DEVWRITELINE(INS8250_3_TAG, ins8250_uart_device, cts_w)) + + MCFG_UPD1990A_ADD(UPD1990C_TAG, XTAL_32_768kHz, NULL, DEVWRITELINE(DEVICE_SELF, s100_wunderbus_device, rtc_tp_w)) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor s100_wunderbus_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( s100_wunderbus ); +} + + +//------------------------------------------------- +// INPUT_PORTS( wunderbus ) +//------------------------------------------------- + +static INPUT_PORTS_START( wunderbus ) + PORT_START("7C") + PORT_DIPNAME( 0x01, 0x00, DEF_STR( Unused ) ) PORT_DIPLOCATION("7C:1") + PORT_DIPSETTING( 0x01, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x00, DEF_STR( On ) ) + PORT_DIPNAME( 0x3e, 0x12, "BASE Port Address" ) PORT_DIPLOCATION("7C:2,3,4,5,6") + PORT_DIPSETTING( 0x00, "00H" ) + PORT_DIPSETTING( 0x02, "08H" ) + PORT_DIPSETTING( 0x04, "10H" ) + PORT_DIPSETTING( 0x06, "18H" ) + PORT_DIPSETTING( 0x08, "20H" ) + PORT_DIPSETTING( 0x0a, "28H" ) + PORT_DIPSETTING( 0x0c, "30H" ) + PORT_DIPSETTING( 0x0e, "38H" ) + PORT_DIPSETTING( 0x10, "40H" ) + PORT_DIPSETTING( 0x12, "48H" ) + PORT_DIPSETTING( 0x14, "50H" ) + PORT_DIPSETTING( 0x16, "58H" ) + PORT_DIPSETTING( 0x18, "60H" ) + PORT_DIPSETTING( 0x1a, "68H" ) + PORT_DIPSETTING( 0x1c, "70H" ) + PORT_DIPSETTING( 0x1e, "78H" ) + PORT_DIPSETTING( 0x20, "80H" ) + PORT_DIPSETTING( 0x22, "88H" ) + PORT_DIPSETTING( 0x24, "90H" ) + PORT_DIPSETTING( 0x26, "98H" ) + PORT_DIPSETTING( 0x28, "A0H" ) + PORT_DIPSETTING( 0x2a, "A8H" ) + PORT_DIPSETTING( 0x2c, "B0H" ) + PORT_DIPSETTING( 0x2e, "B8H" ) + PORT_DIPSETTING( 0x30, "C0H" ) + PORT_DIPSETTING( 0x32, "C8H" ) + PORT_DIPSETTING( 0x34, "D0H" ) + PORT_DIPSETTING( 0x36, "D8H" ) + PORT_DIPSETTING( 0x38, "E0H" ) + PORT_DIPSETTING( 0x3a, "E8H" ) + PORT_DIPSETTING( 0x3c, "F0H" ) + PORT_DIPSETTING( 0x3e, "F8H" ) + PORT_DIPNAME( 0x40, 0x40, "FLAG2 Polarity" ) PORT_DIPLOCATION("7C:7") + PORT_DIPSETTING( 0x40, "Negative" ) + PORT_DIPSETTING( 0x00, "Positive" ) + PORT_DIPNAME( 0x80, 0x80, "FLAG1 Polarity" ) PORT_DIPLOCATION("7C:8") + PORT_DIPSETTING( 0x80, "Negative" ) + PORT_DIPSETTING( 0x00, "Positive" ) + + PORT_START("10A") + PORT_DIPNAME( 0x07, 0x00, "Baud Rate" ) PORT_DIPLOCATION("10A:1,2,3") + PORT_DIPSETTING( 0x00, "Automatic" ) + PORT_DIPSETTING( 0x01, "19200" ) + PORT_DIPSETTING( 0x02, "9600" ) + PORT_DIPSETTING( 0x03, "4800" ) + PORT_DIPSETTING( 0x04, "2400" ) + PORT_DIPSETTING( 0x05, "1200" ) + PORT_DIPSETTING( 0x06, "300" ) + PORT_DIPSETTING( 0x07, "110" ) + PORT_DIPNAME( 0x08, 0x00, DEF_STR( Unused ) ) PORT_DIPLOCATION("10A:4") + PORT_DIPSETTING( 0x08, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x00, DEF_STR( On ) ) + PORT_DIPNAME( 0x10, 0x10, DEF_STR( Unused ) ) PORT_DIPLOCATION("10A:5") + PORT_DIPSETTING( 0x10, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x00, DEF_STR( On ) ) + PORT_DIPNAME( 0x20, 0x00, DEF_STR( Unused ) ) PORT_DIPLOCATION("10A:6") + PORT_DIPSETTING( 0x20, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x00, DEF_STR( On ) ) + PORT_DIPNAME( 0x40, 0x40, DEF_STR( Unused ) ) PORT_DIPLOCATION("10A:7") + PORT_DIPSETTING( 0x40, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x00, DEF_STR( On ) ) + PORT_DIPNAME( 0x80, 0x80, DEF_STR( Unused ) ) PORT_DIPLOCATION("10A:8") + PORT_DIPSETTING( 0x80, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x00, DEF_STR( On ) ) +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor s100_wunderbus_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( wunderbus ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// s100_wunderbus_device - constructor +//------------------------------------------------- + +s100_wunderbus_device::s100_wunderbus_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, S100_WUNDERBUS, "Wunderbus I/O", tag, owner, clock, "s100_wunderbus", __FILE__), + device_s100_card_interface(mconfig, *this), + m_pic(*this, I8259A_TAG), + m_ace1(*this, INS8250_1_TAG), + m_ace2(*this, INS8250_2_TAG), + m_ace3(*this, INS8250_3_TAG), + m_rtc(*this, UPD1990C_TAG), + m_7c(*this, "7C"), + m_10a(*this, "10A") +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void s100_wunderbus_device::device_start() +{ +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void s100_wunderbus_device::device_reset() +{ +} + + +//------------------------------------------------- +// s100_vi0_w - vectored interrupt 0 +//------------------------------------------------- + +void s100_wunderbus_device::s100_vi0_w(int state) +{ + m_pic->ir0_w(state); +} + + +//------------------------------------------------- +// s100_vi1_w - vectored interrupt 1 +//------------------------------------------------- + +void s100_wunderbus_device::s100_vi1_w(int state) +{ + m_pic->ir1_w(state); +} + + +//------------------------------------------------- +// s100_vi2_w - vectored interrupt 2 +//------------------------------------------------- + +void s100_wunderbus_device::s100_vi2_w(int state) +{ + m_pic->ir2_w(state); +} + + +//------------------------------------------------- +// s100_sinp_r - I/O read +//------------------------------------------------- + +UINT8 s100_wunderbus_device::s100_sinp_r(address_space &space, offs_t offset) +{ + UINT8 address = (m_7c->read() & 0x3e) << 2; + if ((offset & 0xf8) != address) return 0; + + UINT8 data = 0; + + if ((offset & 0x07) < 7) + { + switch (m_group) + { + case 0: + switch (offset & 0x07) + { + case 0: // DAISY 0 IN (STATUS) + /* + + bit description + + 0 End of Ribbon + 1 Paper Out + 2 Cover Open + 3 Paper Feed Ready + 4 Carriage Ready + 5 Print Wheel Ready + 6 Check + 7 Printer Ready + + */ + break; + + case 1: // Switch/Parallel port flags + /* + + bit description + + 0 FLAG1 + 1 FLAG2 + 2 10A S6 + 3 10A S5 + 4 10A S4 + 5 10A S3 + 6 10A S2 + 7 10A S1 + + */ + + data = BITSWAP8(m_10a->read(),0,1,2,3,4,5,6,7) & 0xfc; + break; + + case 2: // R.T. Clock IN/RESET CLK. Int. + /* + + bit description + + 0 1990 Data Out + 1 1990 TP + 2 + 3 + 4 + 5 + 6 + 7 + + */ + + data |= m_rtc->data_out_r(); + data |= m_rtc->tp_r() << 1; + + // reset clock interrupt + m_rtc_tp = 0; + m_pic->ir7_w(m_rtc_tp); + break; + + case 3: // Parallel data IN + break; + + case 4: // 8259 0 register + case 5: // 8259 1 register + data = m_pic->read(space, offset & 0x01); + break; + + case 6: // not used + break; + } + break; + + case 1: + data = m_ace1->ins8250_r(space, offset & 0x07); + break; + + case 2: + data = m_ace2->ins8250_r(space, offset & 0x07); + break; + + case 3: + data = m_ace3->ins8250_r(space, offset & 0x07); + break; + } + } + + return data; +} + + +//------------------------------------------------- +// s100_sout_w - I/O write +//------------------------------------------------- + +void s100_wunderbus_device::s100_sout_w(address_space &space, offs_t offset, UINT8 data) +{ + UINT8 address = (m_7c->read() & 0x3e) << 2; + if ((offset & 0xf8) != address) return; + + if ((offset & 0x07) == 7) + { + m_group = data & 0x03; + } + else + { + switch (m_group) + { + case 0: + switch (offset & 0x07) + { + case 0: // DAISY 0 OUT + /* + + bit description + + 0 Data Bit 9 + 1 Data Bit 10 + 2 Data Bit 11 + 3 Data Bit 12 + 4 Paper Feed Strobe + 5 Carriage Strobe + 6 Print Wheel Strobe + 7 Restore + + */ + break; + + case 1: // DAISY 1 OUT + /* + + bit description + + 0 Data Bit 1 + 1 Data Bit 2 + 2 Data Bit 3 + 3 Data Bit 4 + 4 Data Bit 5 + 5 Data Bit 6 + 6 Data Bit 7 + 7 Data Bit 8 + + */ + break; + + case 2: // R.T. Clock OUT + /* + + bit description + + 0 1990 Data In + 1 1990 Clk + 2 1990 C0 + 3 1990 C1 + 4 1990 C2 + 5 1990 STB + 6 Ribbon Lift + 7 Select + + */ + + m_rtc->data_in_w(BIT(data, 0)); + m_rtc->clk_w(BIT(data, 1)); + m_rtc->c0_w(BIT(data, 2)); + m_rtc->c1_w(BIT(data, 3)); + m_rtc->c2_w(BIT(data, 4)); + m_rtc->stb_w(BIT(data, 5)); + break; + + case 3: // Par. data OUT + break; + + case 4: // 8259 0 register + case 5: // 8259 1 register + m_pic->write(space, offset & 0x01, data); + break; + + case 6: // Par. port cntrl. + /* + + bit description + + 0 POE + 1 _RST1 + 2 _RST2 + 3 _ATTN1 + 4 _ATTN2 + 5 + 6 + 7 + + */ + break; + } + break; + + case 1: + m_ace1->ins8250_w(space, offset & 0x07, data); + break; + + case 2: + m_ace2->ins8250_w(space, offset & 0x07, data); + break; + + case 3: + m_ace3->ins8250_w(space, offset & 0x07, data); + break; + } + } +} diff --git a/src/devices/bus/s100/wunderbus.h b/src/devices/bus/s100/wunderbus.h new file mode 100644 index 00000000000..9b51f9afaee --- /dev/null +++ b/src/devices/bus/s100/wunderbus.h @@ -0,0 +1,72 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Morrow Designs Wunderbus I/O card emulation + +**********************************************************************/ + +#pragma once + +#ifndef __S100_WUNDERBUS__ +#define __S100_WUNDERBUS__ + +#include "s100.h" +#include "machine/ins8250.h" +#include "machine/pic8259.h" +#include "machine/upd1990a.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> s100_wunderbus_device + +class s100_wunderbus_device : public device_t, + public device_s100_card_interface +{ +public: + // construction/destruction + s100_wunderbus_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual ioport_constructor device_input_ports() const; + + // not really public + DECLARE_WRITE_LINE_MEMBER( pic_int_w ); + DECLARE_WRITE_LINE_MEMBER( rtc_tp_w ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_s100_card_interface overrides + virtual void s100_vi0_w(int state); + virtual void s100_vi1_w(int state); + virtual void s100_vi2_w(int state); + virtual UINT8 s100_sinp_r(address_space &space, offs_t offset); + virtual void s100_sout_w(address_space &space, offs_t offset, UINT8 data); + +private: + required_device m_pic; + required_device m_ace1; + required_device m_ace2; + required_device m_ace3; + required_device m_rtc; + required_ioport m_7c; + required_ioport m_10a; + + UINT8 m_group; + int m_rtc_tp; +}; + + +// device type definition +extern const device_type S100_WUNDERBUS; + + +#endif diff --git a/src/devices/bus/saturn/bram.c b/src/devices/bus/saturn/bram.c new file mode 100644 index 00000000000..28d0aba2945 --- /dev/null +++ b/src/devices/bus/saturn/bram.c @@ -0,0 +1,110 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + Saturn Battery RAM cart emulation + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "bram.h" + + +//------------------------------------------------- +// constructor +//------------------------------------------------- + +const device_type SATURN_BRAM_4MB = &device_creator; +const device_type SATURN_BRAM_8MB = &device_creator; +const device_type SATURN_BRAM_16MB = &device_creator; +const device_type SATURN_BRAM_32MB = &device_creator; + + +saturn_bram_device::saturn_bram_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_sat_cart_interface( mconfig, *this ), + device_nvram_interface(mconfig, *this) +{ +} + +saturn_bram4mb_device::saturn_bram4mb_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : saturn_bram_device(mconfig, SATURN_BRAM_4MB, "Saturn Battery RAM 4Mbit Cart", tag, owner, clock, "sat_bram_4mb", __FILE__) +{ + m_cart_type = 0x21; +} + +saturn_bram8mb_device::saturn_bram8mb_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : saturn_bram_device(mconfig, SATURN_BRAM_8MB, "Saturn Battery RAM 8Mbit Cart", tag, owner, clock, "sat_bram_8mb", __FILE__) +{ + m_cart_type = 0x22; +} + +saturn_bram16mb_device::saturn_bram16mb_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : saturn_bram_device(mconfig, SATURN_BRAM_16MB, "Saturn Battery RAM 16Mbit Cart", tag, owner, clock, "sat_bram_16mb", __FILE__) +{ + m_cart_type = 0x23; +} + +saturn_bram32mb_device::saturn_bram32mb_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : saturn_bram_device(mconfig, SATURN_BRAM_32MB, "Saturn Battery RAM 32Mbit Cart", tag, owner, clock, "sat_bram_32mb", __FILE__) +{ + m_cart_type = 0x24; +} + + +//------------------------------------------------- +// start/reset +//------------------------------------------------- + +void saturn_bram_device::device_start() +{ +} + +void saturn_bram_device::device_reset() +{ +} + +void saturn_bram_device::nvram_default() +{ + static const UINT8 init[16] = + { 'B', 'a', 'c', 'k', 'U', 'p', 'R', 'a', 'm', ' ', 'F', 'o', 'r', 'm', 'a', 't' }; + memset(&m_ext_bram[0], 0, m_ext_bram.size()); + + for (int i = 0; i < 32; i++) + { + for (int j = 0; j < 16; j++) + m_ext_bram[i * 16 + j] = init[j]; + } +} + + +/*------------------------------------------------- + IO handlers + -------------------------------------------------*/ + +// Battery RAM: single chip + +READ32_MEMBER(saturn_bram_device::read_ext_bram) +{ + if (offset < m_ext_bram.size()/2) + return (m_ext_bram[offset * 2] << 16) | m_ext_bram[offset * 2 + 1]; + else + { + popmessage("Battery RAM read beyond its boundary! offs: %X\n", offset); + return 0xffffffff; + } +} + +WRITE32_MEMBER(saturn_bram_device::write_ext_bram) +{ + if (offset < m_ext_bram.size()/2) + { + if (ACCESSING_BITS_16_23) + m_ext_bram[offset * 2 + 0] = (data & 0x00ff0000) >> 16; + if (ACCESSING_BITS_0_7) + m_ext_bram[offset * 2 + 1] = (data & 0x000000ff) >> 0; + } + else + popmessage("Battery RAM write beyond its boundary! offs: %X data: %X\n", offset, data); +} diff --git a/src/devices/bus/saturn/bram.h b/src/devices/bus/saturn/bram.h new file mode 100644 index 00000000000..c4402431caf --- /dev/null +++ b/src/devices/bus/saturn/bram.h @@ -0,0 +1,69 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __SAT_BRAM_H +#define __SAT_BRAM_H + +#include "sat_slot.h" + + +// ======================> saturn_bram_device + +class saturn_bram_device : public device_t, + public device_sat_cart_interface, + public device_nvram_interface +{ +public: + // construction/destruction + saturn_bram_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_nvram_interface overrides + virtual void nvram_default(); + virtual void nvram_read(emu_file &file) { if (!m_ext_bram.empty()) file.read(&m_ext_bram[0], m_ext_bram.size()); } + virtual void nvram_write(emu_file &file) { if (!m_ext_bram.empty()) file.write(&m_ext_bram[0], m_ext_bram.size()); } + + // reading and writing + virtual DECLARE_READ32_MEMBER(read_ext_bram); + virtual DECLARE_WRITE32_MEMBER(write_ext_bram); +}; + +class saturn_bram4mb_device : public saturn_bram_device +{ +public: + // construction/destruction + saturn_bram4mb_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class saturn_bram8mb_device : public saturn_bram_device +{ +public: + // construction/destruction + saturn_bram8mb_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class saturn_bram16mb_device : public saturn_bram_device +{ +public: + // construction/destruction + saturn_bram16mb_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class saturn_bram32mb_device : public saturn_bram_device +{ +public: + // construction/destruction + saturn_bram32mb_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + + +// device type definition +extern const device_type SATURN_BRAM_4MB; +extern const device_type SATURN_BRAM_8MB; +extern const device_type SATURN_BRAM_16MB; +extern const device_type SATURN_BRAM_32MB; + +#endif diff --git a/src/devices/bus/saturn/dram.c b/src/devices/bus/saturn/dram.c new file mode 100644 index 00000000000..d1078fcc722 --- /dev/null +++ b/src/devices/bus/saturn/dram.c @@ -0,0 +1,96 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + Saturn cart emulation + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "dram.h" + + +//------------------------------------------------- +// constructor +//------------------------------------------------- + +const device_type SATURN_DRAM_8MB = &device_creator; +const device_type SATURN_DRAM_32MB = &device_creator; + + +saturn_dram_device::saturn_dram_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_sat_cart_interface( mconfig, *this ) +{ +} + +saturn_dram8mb_device::saturn_dram8mb_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : saturn_dram_device(mconfig, SATURN_DRAM_8MB, "Saturn Data RAM 8Mbit Cart", tag, owner, clock, "sat_dram_8mb", __FILE__) +{ + m_cart_type = 0x5a; +} + +saturn_dram32mb_device::saturn_dram32mb_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : saturn_dram_device(mconfig, SATURN_DRAM_32MB, "Saturn Data RAM 32Mbit Cart", tag, owner, clock, "sat_dram_32mb", __FILE__) +{ + m_cart_type = 0x5c; +} + + +//------------------------------------------------- +// mapper specific start/reset +//------------------------------------------------- + +void saturn_dram_device::device_start() +{ +} + +void saturn_dram_device::device_reset() +{ +} + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +// RAM: two DRAM chips are present in the cart, thus accesses only go up to m_size/2! + +READ32_MEMBER(saturn_dram_device::read_ext_dram0) +{ + if (offset < (0x400000/2)/4) + return m_ext_dram0[offset % m_ext_dram0.size()]; + else + { + popmessage("DRAM0 read beyond its boundary! offs: %X\n", offset); + return 0xffffffff; + } +} + +READ32_MEMBER(saturn_dram_device::read_ext_dram1) +{ + if (offset < (0x400000/2)/4) + return m_ext_dram1[offset % m_ext_dram1.size()]; + else + { + popmessage("DRAM1 read beyond its boundary! offs: %X\n", offset); + return 0xffffffff; + } +} + +WRITE32_MEMBER(saturn_dram_device::write_ext_dram0) +{ + if (offset < (0x400000/2)/4) + COMBINE_DATA(&m_ext_dram0[offset % m_ext_dram0.size()]); + else + popmessage("DRAM0 write beyond its boundary! offs: %X data: %X\n", offset, data); +} + +WRITE32_MEMBER(saturn_dram_device::write_ext_dram1) +{ + if (offset < (0x400000/2)/4) + COMBINE_DATA(&m_ext_dram1[offset % m_ext_dram1.size()]); + else + popmessage("DRAM1 write beyond its boundary! offs: %X data: %X\n", offset, data); +} diff --git a/src/devices/bus/saturn/dram.h b/src/devices/bus/saturn/dram.h new file mode 100644 index 00000000000..53bf97d8468 --- /dev/null +++ b/src/devices/bus/saturn/dram.h @@ -0,0 +1,49 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __SAT_DRAM_H +#define __SAT_DRAM_H + +#include "sat_slot.h" + + +// ======================> saturn_dram_device + +class saturn_dram_device : public device_t, + public device_sat_cart_interface +{ +public: + // construction/destruction + saturn_dram_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // reading and writing + virtual DECLARE_READ32_MEMBER(read_ext_dram0); + virtual DECLARE_READ32_MEMBER(read_ext_dram1); + virtual DECLARE_WRITE32_MEMBER(write_ext_dram0); + virtual DECLARE_WRITE32_MEMBER(write_ext_dram1); +}; + +class saturn_dram8mb_device : public saturn_dram_device +{ +public: + // construction/destruction + saturn_dram8mb_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class saturn_dram32mb_device : public saturn_dram_device +{ +public: + // construction/destruction + saturn_dram32mb_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + + +// device type definition +extern const device_type SATURN_DRAM_8MB; +extern const device_type SATURN_DRAM_32MB; + +#endif diff --git a/src/devices/bus/saturn/rom.c b/src/devices/bus/saturn/rom.c new file mode 100644 index 00000000000..7b8068735a1 --- /dev/null +++ b/src/devices/bus/saturn/rom.c @@ -0,0 +1,55 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + Saturn ROM cart emulation + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "rom.h" + + +//------------------------------------------------- +// saturn_rom_device - constructor +//------------------------------------------------- + +const device_type SATURN_ROM = &device_creator; + + +saturn_rom_device::saturn_rom_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_sat_cart_interface( mconfig, *this ) +{ +} + +saturn_rom_device::saturn_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, SATURN_ROM, "Saturn ROM Carts", tag, owner, clock, "sat_rom", __FILE__), + device_sat_cart_interface( mconfig, *this ) +{ + m_cart_type = 0xff; // actually not clear if ROM carts have a type ID like DRAM/BRAM carts +} + + +//------------------------------------------------- +// mapper specific start/reset +//------------------------------------------------- + +void saturn_rom_device::device_start() +{ +} + +void saturn_rom_device::device_reset() +{ +} + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +READ32_MEMBER(saturn_rom_device::read_rom) +{ + return m_rom[offset & (m_rom_size/4 - 1)]; +} diff --git a/src/devices/bus/saturn/rom.h b/src/devices/bus/saturn/rom.h new file mode 100644 index 00000000000..021526bcce4 --- /dev/null +++ b/src/devices/bus/saturn/rom.h @@ -0,0 +1,33 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __SAT_ROM_H +#define __SAT_ROM_H + +#include "sat_slot.h" + + +// ======================> saturn_rom_device + +class saturn_rom_device : public device_t, + public device_sat_cart_interface +{ +public: + // construction/destruction + saturn_rom_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + saturn_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // reading and writing + virtual DECLARE_READ32_MEMBER(read_rom); +}; + + + +// device type definition +extern const device_type SATURN_ROM; + + +#endif diff --git a/src/devices/bus/saturn/sat_slot.c b/src/devices/bus/saturn/sat_slot.c new file mode 100644 index 00000000000..aa3a563f68d --- /dev/null +++ b/src/devices/bus/saturn/sat_slot.c @@ -0,0 +1,295 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + Saturn cart emulation + (through slot devices) + + Despite the system having a single cart slot, 3 different kinds of cart can be inserted and + different memory areas are exposed to each of them + * ROM carts are accessed in range 0x02000000-0x023fffff and 0x22000000-0x24ffffff of both CPUs + * Data RAM carts are accessed in range 0x02400000-0x027fffff of both CPUs (each DRAM chip is + mapped independently, the 1st at 0x2400000, the second at 0x2600000) + * Battery RAM carts are accessed in range 0x04000000-0x047fffff of both CPUs + + It is not clear what happens to accesses beyond the cart size (open bus? mirror of cart data?), + e.g. if you have a 16Mbit battery cart inserted and the system tries to read/write above 0x04400000, + so for the moment the whole range is mapped and an error message is printed for out-of-bounds + accesses + + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "sat_slot.h" + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type SATURN_CART_SLOT = &device_creator; + + +//------------------------------------------------- +// device_sat_cart_interface - constructor +//------------------------------------------------- + +device_sat_cart_interface::device_sat_cart_interface(const machine_config &mconfig, device_t &device) + : device_slot_card_interface(mconfig, device), + m_rom(NULL), + m_rom_size(0) +{ +} + + +//------------------------------------------------- +// ~device_sat_cart_interface - destructor +//------------------------------------------------- + +device_sat_cart_interface::~device_sat_cart_interface() +{ +} + +//------------------------------------------------- +// rom_alloc - alloc the space for the cart +//------------------------------------------------- + +void device_sat_cart_interface::rom_alloc(UINT32 size, const char *tag) +{ + if (m_rom == NULL) + { + m_rom = (UINT32 *)device().machine().memory().region_alloc(std::string(tag).append(SATSLOT_ROM_REGION_TAG).c_str(), size, 4, ENDIANNESS_LITTLE)->base(); + m_rom_size = size; + } +} + + +//------------------------------------------------- +// bram_alloc - alloc the space for the Backup RAM +//------------------------------------------------- + +void device_sat_cart_interface::bram_alloc(UINT32 size) +{ + m_ext_bram.resize(size); + device().save_item(NAME(m_ext_bram)); +} + + +//------------------------------------------------- +// dram*_alloc - alloc the space for the DRAM +//------------------------------------------------- + +void device_sat_cart_interface::dram0_alloc(UINT32 size) +{ + m_ext_dram0.resize(size/sizeof(UINT32)); + device().save_item(NAME(m_ext_dram0)); +} + +void device_sat_cart_interface::dram1_alloc(UINT32 size) +{ + m_ext_dram1.resize(size/sizeof(UINT32)); + device().save_item(NAME(m_ext_dram1)); +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// sat_cart_slot_device - constructor +//------------------------------------------------- +sat_cart_slot_device::sat_cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, SATURN_CART_SLOT, "Saturn Cartridge Slot", tag, owner, clock, "sat_cart_slot", __FILE__), + device_image_interface(mconfig, *this), + device_slot_interface(mconfig, *this) +{ +} + + +//------------------------------------------------- +// sat_cart_slot_device - destructor +//------------------------------------------------- + +sat_cart_slot_device::~sat_cart_slot_device() +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void sat_cart_slot_device::device_start() +{ + m_cart = dynamic_cast(get_card_device()); +} + +//------------------------------------------------- +// device_config_complete - perform any +// operations now that the configuration is +// complete +//------------------------------------------------- + +void sat_cart_slot_device::device_config_complete() +{ + // set brief and instance name + update_names(); +} + + + +/*------------------------------------------------- + call load + -------------------------------------------------*/ + + +bool sat_cart_slot_device::call_load() +{ + if (m_cart) + { + bool is_rom = ((software_entry() == NULL) || ((software_entry() != NULL) && get_software_region("rom"))); + + if (is_rom) + { + // from fullpath, only ROM carts + UINT32 len = (software_entry() != NULL) ? get_software_region_length("rom") : length(); + UINT32 *ROM; + + m_cart->rom_alloc(len, tag()); + ROM = m_cart->get_rom_base(); + + if (software_entry() != NULL) + memcpy(ROM, get_software_region("rom"), len); + else + fread(ROM, len); + + // fix endianness.... + for (int i = 0; i < len/4; i ++) + ROM[i] = BITSWAP32(ROM[i],7,6,5,4,3,2,1,0,15,14,13,12,11,10,9,8,23,22,21,20,19,18,17,16,31,30,29,28,27,26,25,24); +// { +// UINT8 tempa = ROM[i+0]; +// UINT8 tempb = ROM[i+1]; +// ROM[i+1] = ROM[i+2]; +// ROM[i+0] = ROM[i+3]; +// ROM[i+3] = tempa; +// ROM[i+2] = tempb; +// } + } + else + { + // DRAM or BRAM carts from softlist + if (get_software_region("bram")) + m_cart->bram_alloc(get_software_region_length("bram")); + if (get_software_region("dram0")) + m_cart->dram0_alloc(get_software_region_length("dram0")); + if (get_software_region("dram1")) + m_cart->dram1_alloc(get_software_region_length("dram1")); + } + return IMAGE_INIT_PASS; + } + + return IMAGE_INIT_PASS; +} + + +/*------------------------------------------------- + call_unload + -------------------------------------------------*/ + +void sat_cart_slot_device::call_unload() +{ +} + + + +/*------------------------------------------------- + call softlist load + -------------------------------------------------*/ + +bool sat_cart_slot_device::call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry) +{ + load_software_part_region(*this, swlist, swname, start_entry); + return TRUE; +} + + +/*------------------------------------------------- + get default card software + -------------------------------------------------*/ + +void sat_cart_slot_device::get_default_card_software(std::string &result) +{ + software_get_default_slot(result, "rom"); +} + + + +int sat_cart_slot_device::get_cart_type() +{ + if (m_cart) + return m_cart->get_cart_type(); + + return 0xff; +} + + + +/*------------------------------------------------- + read + -------------------------------------------------*/ + +READ32_MEMBER(sat_cart_slot_device::read_rom) +{ + if (m_cart) + return m_cart->read_rom(space, offset, mem_mask); + else + return 0xffffffff; +} + +READ32_MEMBER(sat_cart_slot_device::read_ext_dram0) +{ + if (m_cart) + return m_cart->read_ext_dram0(space, offset, mem_mask); + else + return 0xffffffff; +} + +READ32_MEMBER(sat_cart_slot_device::read_ext_dram1) +{ + if (m_cart) + return m_cart->read_ext_dram1(space, offset, mem_mask); + else + return 0xffffffff; +} + +READ32_MEMBER(sat_cart_slot_device::read_ext_bram) +{ + if (m_cart) + return m_cart->read_ext_bram(space, offset, mem_mask); + else + return 0xffffffff; +} + +/*------------------------------------------------- + write + -------------------------------------------------*/ + +WRITE32_MEMBER(sat_cart_slot_device::write_ext_dram0) +{ + if (m_cart) + m_cart->write_ext_dram0(space, offset, data, mem_mask); +} + +WRITE32_MEMBER(sat_cart_slot_device::write_ext_dram1) +{ + if (m_cart) + m_cart->write_ext_dram1(space, offset, data, mem_mask); +} + +WRITE32_MEMBER(sat_cart_slot_device::write_ext_bram) +{ + if (m_cart) + m_cart->write_ext_bram(space, offset, data, mem_mask); +} diff --git a/src/devices/bus/saturn/sat_slot.h b/src/devices/bus/saturn/sat_slot.h new file mode 100644 index 00000000000..13b46c23374 --- /dev/null +++ b/src/devices/bus/saturn/sat_slot.h @@ -0,0 +1,123 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __SAT_SLOT_H +#define __SAT_SLOT_H + +/*************************************************************************** + TYPE DEFINITIONS + ***************************************************************************/ + + +// ======================> device_sat_cart_interface + +class device_sat_cart_interface : public device_slot_card_interface +{ +public: + // construction/destruction + device_sat_cart_interface(const machine_config &mconfig, device_t &device); + virtual ~device_sat_cart_interface(); + + // reading from ROM + virtual DECLARE_READ32_MEMBER(read_rom) { return 0xffffffff; } + // reading and writing to Extended DRAM chips + virtual DECLARE_READ32_MEMBER(read_ext_dram0) { return 0xffffffff; } + virtual DECLARE_WRITE32_MEMBER(write_ext_dram0) {} + virtual DECLARE_READ32_MEMBER(read_ext_dram1) { return 0xffffffff; } + virtual DECLARE_WRITE32_MEMBER(write_ext_dram1) {} + // reading and writing to Extended BRAM chip + virtual DECLARE_READ32_MEMBER(read_ext_bram) { return 0xffffffff; } + virtual DECLARE_WRITE32_MEMBER(write_ext_bram) {} + + virtual int get_cart_type() { return m_cart_type; }; + + + void rom_alloc(UINT32 size, const char *tag); + void bram_alloc(UINT32 size); + void dram0_alloc(UINT32 size); + void dram1_alloc(UINT32 size); + UINT32* get_rom_base() { return m_rom; } + UINT32* get_ext_dram0_base() { return &m_ext_dram0[0]; } + UINT32* get_ext_dram1_base() { return &m_ext_dram1[0]; } + UINT8* get_ext_bram_base() { return &m_ext_bram[0]; } + UINT32 get_rom_size() { return m_rom_size; } + UINT32 get_ext_dram0_size() { return m_ext_dram0.size()*sizeof(UINT32); } + UINT32 get_ext_dram1_size() { return m_ext_dram1.size()*sizeof(UINT32); } + UINT32 get_ext_bram_size() { return m_ext_bram.size(); } + +protected: + int m_cart_type; + + // internal state + UINT32 *m_rom; + UINT32 m_rom_size; + std::vector m_ext_dram0; + std::vector m_ext_dram1; + dynamic_buffer m_ext_bram; +}; + + +// ======================> sat_cart_slot_device + +class sat_cart_slot_device : public device_t, + public device_image_interface, + public device_slot_interface +{ +public: + // construction/destruction + sat_cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual ~sat_cart_slot_device(); + + // device-level overrides + virtual void device_start(); + virtual void device_config_complete(); + + // image-level overrides + virtual bool call_load(); + virtual void call_unload(); + virtual bool call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry); + + int get_cart_type(); + + virtual iodevice_t image_type() const { return IO_CARTSLOT; } + virtual bool is_readable() const { return 1; } + virtual bool is_writeable() const { return 0; } + virtual bool is_creatable() const { return 0; } + virtual bool must_be_loaded() const { return 0; } + virtual bool is_reset_on_load() const { return 1; } + virtual const option_guide *create_option_guide() const { return NULL; } + virtual const char *image_interface() const { return "sat_cart"; } + virtual const char *file_extensions() const { return "bin"; } + + // slot interface overrides + virtual void get_default_card_software(std::string &result); + + // reading and writing + virtual DECLARE_READ32_MEMBER(read_rom); + virtual DECLARE_READ32_MEMBER(read_ext_dram0); + virtual DECLARE_WRITE32_MEMBER(write_ext_dram0); + virtual DECLARE_READ32_MEMBER(read_ext_dram1); + virtual DECLARE_WRITE32_MEMBER(write_ext_dram1); + virtual DECLARE_READ32_MEMBER(read_ext_bram); + virtual DECLARE_WRITE32_MEMBER(write_ext_bram); + +private: + device_sat_cart_interface* m_cart; +}; + + +// device type definition +extern const device_type SATURN_CART_SLOT; + + +/*************************************************************************** + DEVICE CONFIGURATION MACROS + ***************************************************************************/ + +#define SATSLOT_ROM_REGION_TAG ":cart:rom" + +#define MCFG_SATURN_CARTRIDGE_ADD(_tag,_slot_intf,_def_slot) \ + MCFG_DEVICE_ADD(_tag, SATURN_CART_SLOT, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) + + +#endif diff --git a/src/devices/bus/scsi/acb4070.c b/src/devices/bus/scsi/acb4070.c new file mode 100644 index 00000000000..1503272b55c --- /dev/null +++ b/src/devices/bus/scsi/acb4070.c @@ -0,0 +1,63 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/* + * ACB4070 + RLL drive + * + */ + +#include "acb4070.h" + +// device type definition +const device_type ACB4070 = &device_creator; + +acb4070_device::acb4070_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : scsihd_device(mconfig, ACB4070, "ACB4070", tag, owner, clock, "acb4070", __FILE__) +{ +} + +#define ACB4070_CMD_WRITE_DATA_BUFFER ( 0x13 ) +#define ACB4070_CMD_READ_DATA_BUFFER ( 0x14 ) + +#define TRANSFERLENGTH_DATA_BUFFER 0x0400 + +void acb4070_device::ExecCommand() +{ + switch( command[ 0 ] ) + { + case ACB4070_CMD_WRITE_DATA_BUFFER: + m_phase = SCSI_PHASE_DATAOUT; + m_status_code = SCSI_STATUS_CODE_GOOD; + m_transfer_length = TRANSFERLENGTH_DATA_BUFFER; + break; + + case ACB4070_CMD_READ_DATA_BUFFER: + m_phase = SCSI_PHASE_DATAIN; + m_status_code = SCSI_STATUS_CODE_GOOD; + m_transfer_length = TRANSFERLENGTH_DATA_BUFFER; + break; + + case T10SPC_CMD_MODE_SELECT_6: + m_phase = SCSI_PHASE_DATAOUT; + m_status_code = SCSI_STATUS_CODE_GOOD; + m_transfer_length = SCSILengthFromUINT8( &command[ 4 ] ); + break; + + default: + scsihd_device::ExecCommand(); + break; + } +} + +void acb4070_device::WriteData( UINT8 *data, int dataLength ) +{ + switch( command[ 0 ] ) + { + case T10SPC_CMD_MODE_SELECT_6: + adaptec_sense_t *sense=(adaptec_sense_t *) data; + int tracks=(sense->cylinder_count[0]<<8)+sense->cylinder_count[1]; + int capacity=(tracks * sense->head_count * 17); + logerror("Tracks=%d, Heads=%d sec/track=%d\n",tracks,sense->head_count,sense->sectors_per_track); + logerror("Setting disk capacity to %d blocks\n",capacity); + break; + } +} diff --git a/src/devices/bus/scsi/acb4070.h b/src/devices/bus/scsi/acb4070.h new file mode 100644 index 00000000000..e396c6eb58f --- /dev/null +++ b/src/devices/bus/scsi/acb4070.h @@ -0,0 +1,47 @@ +// license:BSD-3-Clause +// copyright-holders:smf +#pragma once + +#ifndef __ACB4070__ +#define __ACB4070__ + +#include "scsihd.h" + +class acb4070_device : public scsihd_device +{ +public: + // construction/destruction + acb4070_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual void ExecCommand(); + virtual void WriteData( UINT8 *data, int dataLength ); + +private: + struct adaptec_sense_t + { + // parameter list + UINT8 reserved1[3]; + UINT8 length; + + // descriptor list + UINT8 density; + UINT8 reserved2[4]; + UINT8 block_size[3]; + + // drive parameter list + UINT8 format_code; + UINT8 cylinder_count[2]; + UINT8 head_count; + UINT8 reduced_write[2]; + UINT8 write_precomp[2]; + UINT8 landing_zone; + UINT8 step_pulse_code; + UINT8 bit_flags; + UINT8 sectors_per_track; + }; +}; + +// device type definition +extern const device_type ACB4070; + +#endif diff --git a/src/devices/bus/scsi/cdu76s.c b/src/devices/bus/scsi/cdu76s.c new file mode 100644 index 00000000000..bb6a70390ed --- /dev/null +++ b/src/devices/bus/scsi/cdu76s.c @@ -0,0 +1,47 @@ +// license:BSD-3-Clause +// copyright-holders:smf +#include "cdu76s.h" + +void sony_cdu76s_device::ExecCommand() +{ + switch ( command[0] ) + { + case 0x12: // INQUIRY + logerror("CDU76S: INQUIRY\n"); + m_phase = SCSI_PHASE_DATAIN; + m_status_code = SCSI_STATUS_CODE_GOOD; + m_transfer_length = SCSILengthFromUINT8( &command[ 4 ] ); + break; + } +} + +void sony_cdu76s_device::ReadData( UINT8 *data, int dataLength ) +{ + switch ( command[0] ) + { + case 0x12: // INQUIRY + memset( data, 0, dataLength ); + data[0] = 0x05; // device is present, device is CD/DVD (MMC-3) + data[1] = 0x80; // media is removable + data[2] = 0x05; // device complies with SPC-3 standard + data[3] = 0x02; // response data format = SPC-3 standard + // some Konami games freak out if this isn't "Sony", so we'll lie + // this is the actual drive on my Nagano '98 board + strcpy((char *)&data[8], "Sony"); + strcpy((char *)&data[16], "CDU-76S"); + strcpy((char *)&data[32], "1.0"); + break; + + default: + scsicd_device::ReadData( data, dataLength ); + break; + } +} + +// device type definition +const device_type CDU76S = &device_creator; + +sony_cdu76s_device::sony_cdu76s_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + scsicd_device(mconfig, CDU76S, "Sony CDU-76S", tag, owner, clock, "cdu76s", __FILE__) +{ +} diff --git a/src/devices/bus/scsi/cdu76s.h b/src/devices/bus/scsi/cdu76s.h new file mode 100644 index 00000000000..a0997ea6c05 --- /dev/null +++ b/src/devices/bus/scsi/cdu76s.h @@ -0,0 +1,31 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/*************************************************************************** + + cdu76s.h + + Sony CDU-76S + +***************************************************************************/ + +#pragma once + +#ifndef __CDU76S_H__ +#define __CDU76S_H__ + +#include "scsicd.h" +#include "machine/t10mmc.h" + +class sony_cdu76s_device : public scsicd_device +{ +public: + sony_cdu76s_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual void ExecCommand(); + virtual void ReadData( UINT8 *data, int dataLength ); +}; + +// device type definition +extern const device_type CDU76S; + +#endif diff --git a/src/devices/bus/scsi/d9060hd.c b/src/devices/bus/scsi/d9060hd.c new file mode 100644 index 00000000000..3d212582a39 --- /dev/null +++ b/src/devices/bus/scsi/d9060hd.c @@ -0,0 +1,36 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/* + * D9060 - SASI + TANDON TM602S + * + */ + +#include "d9060hd.h" + +// device type definition +const device_type D9060HD = &device_creator; + +d9060hd_device::d9060hd_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : scsihd_device(mconfig, D9060HD, "D9060HD", tag, owner, clock, "d9060hd", __FILE__) +{ +} + +#define D9060HD_CMD_PHYSICAL_DEVICE_ID ( 0xc0 ) +#define D9060HD_CMD_DRIVE_DIAGS ( 0xe3 ) + +void d9060hd_device::ExecCommand() +{ + switch( command[ 0 ] ) + { + case D9060HD_CMD_PHYSICAL_DEVICE_ID: + case D9060HD_CMD_DRIVE_DIAGS: + m_phase = SCSI_PHASE_STATUS; + m_status_code = SCSI_STATUS_CODE_GOOD; + m_transfer_length = 0; + break; + + default: + scsihd_device::ExecCommand(); + break; + } +} diff --git a/src/devices/bus/scsi/d9060hd.h b/src/devices/bus/scsi/d9060hd.h new file mode 100644 index 00000000000..f3fa504cf81 --- /dev/null +++ b/src/devices/bus/scsi/d9060hd.h @@ -0,0 +1,22 @@ +// license:BSD-3-Clause +// copyright-holders:smf +#pragma once + +#ifndef __D9060HD__ +#define __D9060HD__ + +#include "scsihd.h" + +class d9060hd_device : public scsihd_device +{ +public: + // construction/destruction + d9060hd_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual void ExecCommand(); +}; + +// device type definition +extern const device_type D9060HD; + +#endif diff --git a/src/devices/bus/scsi/omti5100.c b/src/devices/bus/scsi/omti5100.c new file mode 100644 index 00000000000..9e10538102d --- /dev/null +++ b/src/devices/bus/scsi/omti5100.c @@ -0,0 +1,94 @@ +// license:BSD-3-Clause +// copyright-holders:smf +#include "omti5100.h" + +#define OMTI_STATUS_NOT_READY 0x04 +#define OMTI_READ_DATA_BUFFER 0xec +#define OMTI_ASSIGN_DISK_PARAM 0xc2 + +const device_type OMTI5100 = &device_creator; + +#if 0 +ROM_START( omti5100 ) + ROM_REGION(0x1000, "mcu", 0) // Hitachi Z8 + ROM_LOAD("100240-N.7a", 0x0000, 0x1000, CRC(d227d6cb) SHA1(3d6140764d3d043428c941826370ebf1597c63bd)) +ROM_END + +const rom_entry *omti5100_device::device_rom_region() const +{ + return ROM_NAME( omti5100 ); +} +#endif + +omti5100_device::omti5100_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : scsihd_device(mconfig, OMTI5100, "OMTI 5100", tag, owner, clock, "omti5100", __FILE__), + m_image0(*this, "image0"), + m_image1(*this, "image1") +{ +} + +void omti5100_device::device_start() +{ + m_image = m_image0; + scsihle_device::device_start(); +} + +void omti5100_device::ExecCommand() +{ + harddisk_image_device *image = ((command[1] >> 5) & 1) ? m_image1 : m_image0; + switch(command[0]) + { + case OMTI_READ_DATA_BUFFER: + m_phase = SCSI_PHASE_DATAIN; + m_status_code = SCSI_STATUS_CODE_GOOD; + m_transfer_length = 512; + break; + case OMTI_ASSIGN_DISK_PARAM: + m_phase = SCSI_PHASE_DATAOUT; + m_status_code = SCSI_STATUS_CODE_GOOD; + m_transfer_length = 10; + break; + default: + if(!image) + { + m_phase = SCSI_PHASE_STATUS; + m_status_code = SCSI_STATUS_CODE_CHECK_CONDITION; + m_sense_asc = OMTI_STATUS_NOT_READY; + m_transfer_length = 0; + } + else + { + SetDevice(image); + scsihd_device::ExecCommand(); + } + break; + } +} + +void omti5100_device::ReadData( UINT8 *data, int dataLength ) +{ + switch( command[ 0 ] ) + { + case OMTI_READ_DATA_BUFFER: + data[0] = '5'; + data[1] = '1'; + data[2] = '0'; + data[3] = '0'; + break; + + default: + scsihd_device::ReadData( data, dataLength ); + break; + } +} + +static MACHINE_CONFIG_FRAGMENT( omti5100 ) + MCFG_HARDDISK_ADD("image0") + MCFG_HARDDISK_ADD("image1") +MACHINE_CONFIG_END + + +machine_config_constructor omti5100_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( omti5100 ); +} diff --git a/src/devices/bus/scsi/omti5100.h b/src/devices/bus/scsi/omti5100.h new file mode 100644 index 00000000000..9c9e1e5444c --- /dev/null +++ b/src/devices/bus/scsi/omti5100.h @@ -0,0 +1,30 @@ +// license:BSD-3-Clause +// copyright-holders:smf +#ifndef OMTI5100_H_ +#define OMTI5100_H_ + +#include "emu.h" +#include "scsi.h" +#include "scsihd.h" +#include "imagedev/harddriv.h" + +class omti5100_device : public scsihd_device +{ +public: + omti5100_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual machine_config_constructor device_mconfig_additions() const; + //virtual const rom_entry *device_rom_region() const; + + virtual void ExecCommand(); + virtual void ReadData( UINT8 *data, int dataLength ); + void device_start(); + +private: + required_device m_image0; + required_device m_image1; +}; + +extern const device_type OMTI5100; + +#endif /* OMTI5100_H_ */ diff --git a/src/devices/bus/scsi/pc9801_sasi.c b/src/devices/bus/scsi/pc9801_sasi.c new file mode 100644 index 00000000000..619f9f074da --- /dev/null +++ b/src/devices/bus/scsi/pc9801_sasi.c @@ -0,0 +1,28 @@ +// license:BSD-3-Clause +// copyright-holders:smf +#include "pc9801_sasi.h" + +#define SASI_CMD_SPECIFY 0xc2 // according to x68k_hdc.c + +const device_type PC9801_SASI = &device_creator; + +pc9801_sasi_device::pc9801_sasi_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : scsihd_device(mconfig, PC9801_SASI, "PC-9801 SASI Controller", tag, owner, clock, "pc9801_sasi", __FILE__) +{ +} + +void pc9801_sasi_device::ExecCommand() +{ + switch(command[0]) + { + case SASI_CMD_SPECIFY: + m_phase = SCSI_PHASE_DATAOUT; + m_status_code = SCSI_STATUS_CODE_GOOD; + m_transfer_length = 10; + break; + + default: + scsihd_device::ExecCommand(); + break; + } +} diff --git a/src/devices/bus/scsi/pc9801_sasi.h b/src/devices/bus/scsi/pc9801_sasi.h new file mode 100644 index 00000000000..44ef5f5e0cc --- /dev/null +++ b/src/devices/bus/scsi/pc9801_sasi.h @@ -0,0 +1,20 @@ +// license:BSD-3-Clause +// copyright-holders:smf +#ifndef PC9801_SASI_H_ +#define PC9801_SASI_H_ + +#include "scsihd.h" + +class pc9801_sasi_device : public scsihd_device +{ +public: + // construction/destruction + pc9801_sasi_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual void ExecCommand(); +}; + +// device type definition +extern const device_type PC9801_SASI; + +#endif /* PC9801_SASI_H_ */ diff --git a/src/devices/bus/scsi/s1410.c b/src/devices/bus/scsi/s1410.c new file mode 100644 index 00000000000..59b964ce4f2 --- /dev/null +++ b/src/devices/bus/scsi/s1410.c @@ -0,0 +1,365 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Xebec S1410 5.25" Winchester Disk Controller emulation + +**********************************************************************/ + +/* + +Xebec S1410 + +PCB Layout +---------- + +ASSY 104527 REV E04 SN 127623 + +|-------------------------------------------| +| | +|CN1 | +| | +| | +|CN2 | +| XEBEC2 CN5| +| PROM 2114 | +|CN3 XEBEC1 2114 | +| | +|CN4 Z80 ROM | +| 20MHz 16MHz | +|-------------------------------------------| + +Notes: + Relevant IC's shown. + + Z80 - Zilog Z8400APS Z80A CPU + ROM - 2732 pinout ROM "XEBEC 104521G 2155008 M460949" + PROM - National Semiconductor DM74S288N "103911" 32x8 TTL PROM + 2114 - National Semiconductor NMC2148HN-3 1Kx4 RAM + XEBEC1 - Xebec 3198-0009 + XEBEC2 - Xebec 3198-0045 "T20" + CN1 - 4-pin Molex, drive power + CN2 - 34-pin PCB edge, ST-506 drive 0/1 control + CN3 - 2x10 PCB header, ST-506 drive 0 data + CN4 - 2x10 PCB header, ST-506 drive 1 data + CN5 - 2x25 PCB header, SASI host interface + + +ASSY 104766 REV C02 SN 231985P + +|-------------------------------------------| +| | +| CN1 SY2158 | +| CN7 CN6 | +| ROM | +| CN2 | +| XEBEC1 Z80 | +| CN5 | +| CN3 XEBEC2 20MHz XEBEC3 | +| | +| CN4 XEBEC4 XEBEC5 | +| | +|-------------------------------------------| + +Notes: + Relevant IC's shown. + + Z80 - Zilog Z8400APS Z80A CPU + ROM - 2732 pinout ROM "104788D" + SY2158 - Synertek SY2158A-3 1Kx8 RAM + XEBEC1 - Xebec 3198-0046N8445 + XEBEC2 - Xebec 3198-0009 + XEBEC3 - Xebec 3198-0057 + XEBEC4 - Xebec 3198-0058 + XEBEC5 - Xebec 3198-0056 + CN1 - 4-pin Molex, drive power + CN2 - 34-pin PCB edge, ST-506 drive 0/1 control + CN3 - 2x10 PCB header, ST-506 drive 0 data + CN4 - 2x10 PCB header, ST-506 drive 1 data + CN5 - 2x25 PCB header, SASI host interface + CN6 - 2x8 PCB header + CN7 - 2x10 PCB header (test only) + +*/ + + +#include "s1410.h" +#include "cpu/z80/z80.h" +#include "imagedev/harddriv.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define Z8400A_TAG "z80" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type S1410 = &device_creator; + +//------------------------------------------------- +// ROM( s1410 ) +//------------------------------------------------- + +ROM_START( s1410 ) + ROM_REGION( 0x1000, Z8400A_TAG, 0 ) + ROM_LOAD( "104521f", 0x0000, 0x1000, CRC(305b8e76) SHA1(9efaa53ae86bc111bd263ad433e083f78a000cab) ) + ROM_LOAD( "104521g", 0x0000, 0x1000, CRC(24385115) SHA1(c389f6108cd5ed798a090acacce940ee43d77042) ) + ROM_LOAD( "104788d", 0x0000, 0x1000, CRC(2e385e2d) SHA1(7e2c349b2b6e95f2134f82cffc38d86b8a68390d) ) + + ROM_REGION( 0x20, "103911", 0 ) + ROM_LOAD( "103911", 0x00, 0x20, NO_DUMP ) // DM74S288N +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *s1410_device::device_rom_region() const +{ + return ROM_NAME( s1410 ); +} + + +//------------------------------------------------- +// ADDRESS_MAP( s1410_mem ) +//------------------------------------------------- + +static ADDRESS_MAP_START( s1410_mem, AS_PROGRAM, 8, s1410_device ) + AM_RANGE(0x0000, 0x0fff) AM_ROM AM_REGION(Z8400A_TAG, 0) + AM_RANGE(0x1000, 0x13ff) AM_RAM +ADDRESS_MAP_END + + +//------------------------------------------------- +// ADDRESS_MAP( s1410_io ) +//------------------------------------------------- + +static ADDRESS_MAP_START( s1410_io, AS_IO, 8, s1410_device ) + ADDRESS_MAP_GLOBAL_MASK(0xff) + AM_RANGE(0x66, 0x66) AM_WRITENOP + AM_RANGE(0x67, 0x67) AM_WRITENOP + AM_RANGE(0x68, 0x68) AM_READNOP + AM_RANGE(0x69, 0x69) AM_WRITENOP + AM_RANGE(0x6a, 0x6a) AM_WRITENOP + AM_RANGE(0x6b, 0x6b) AM_WRITENOP + AM_RANGE(0x6c, 0x6c) AM_WRITENOP + AM_RANGE(0xa0, 0xa0) AM_NOP + AM_RANGE(0xc1, 0xc1) AM_WRITENOP + AM_RANGE(0xc2, 0xc2) AM_WRITENOP + AM_RANGE(0xc3, 0xc3) AM_WRITENOP +ADDRESS_MAP_END + + +//------------------------------------------------- +// MACHINE_DRIVER( s1410 ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( s1410 ) + MCFG_CPU_ADD(Z8400A_TAG, Z80, XTAL_16MHz/4) + MCFG_CPU_PROGRAM_MAP(s1410_mem) + MCFG_CPU_IO_MAP(s1410_io) + MCFG_DEVICE_DISABLE() + + MCFG_HARDDISK_ADD("image") +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor s1410_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( s1410 ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// s1410_device - constructor +//------------------------------------------------- + +s1410_device::s1410_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : scsihd_device(mconfig, S1410, "Xebec S1410", tag, owner, clock, "s1410", __FILE__) +{ +} + +#define S1410_CMD_CHECK_TRACK_FORMAT ( 0x05 ) +#define S1410_CMD_FORMAT_TRACK ( 0x06 ) +#define S1410_CMD_INIT_DRIVE_PARAMS ( 0x0c ) +#define S1410_CMD_FORMAT_ALT_TRACK ( 0x0E ) +#define S1410_CMD_WRITE_SEC_BUFFER ( 0x0F ) +#define S1410_CMD_READ_SEC_BUFFER ( 0x10 ) +#define S1410_CMD_RAM_DIAGS ( 0xe0 ) +#define S1410_CMD_DRIVE_DIAGS ( 0xe3 ) +#define S1410_CMD_CONTROLER_DIAGS ( 0xe4 ) + +#define S1410_STATUS_NOT_READY ( 0x04 ) + +#define TRANSFERLENGTH_INIT_DRIVE_PARAMS ( 0x08 ) +#define TRANSFERLENGTH_FORMAT_ALT_TRACK ( 0x03 ) +#define TRANSFERLENGTH_SECTOR_BUFFER ( 0x0200 ) + +void s1410_device::ExecCommand() +{ + switch( command[ 0 ] ) + { + case T10SPC_CMD_RECALIBRATE: + if (command[1] >> 5) + { + m_phase = SCSI_PHASE_STATUS; + m_status_code = SCSI_STATUS_CODE_CHECK_CONDITION; + m_sense_asc = S1410_STATUS_NOT_READY; + m_transfer_length = 0; + } + else + { + scsihd_device::ExecCommand(); + } + break; + + case T10SPC_CMD_REQUEST_SENSE: + m_phase = SCSI_PHASE_DATAIN; + m_status_code = SCSI_STATUS_CODE_GOOD; + m_transfer_length = 4; + break; + + case S1410_CMD_FORMAT_TRACK: + { + m_lba = (command[1]&0x1f)<<16 | command[2]<<8 | command[3]; + + switch( m_sector_bytes ) + { + case 256: + m_blocks = 32; + break; + + case 512: + m_blocks = 17; + break; + } + + logerror("S1410: FORMAT TRACK at LBA %x for %x blocks\n", m_lba, m_blocks); + + if ((m_disk) && (m_blocks)) + { + dynamic_buffer data(m_sector_bytes); + memset(&data[0], 0xc6, m_sector_bytes); + + while (m_blocks > 0) + { + if (!hard_disk_write(m_disk, m_lba, &data[0])) + { + logerror("S1410: HD write error!\n"); + } + m_lba++; + m_blocks--; + } + } + + m_phase = SCSI_PHASE_STATUS; + m_transfer_length = 0; + } + break; + + case S1410_CMD_INIT_DRIVE_PARAMS: + m_phase = SCSI_PHASE_DATAOUT; + m_status_code = SCSI_STATUS_CODE_GOOD; + m_transfer_length = TRANSFERLENGTH_INIT_DRIVE_PARAMS; + break; + + case S1410_CMD_FORMAT_ALT_TRACK: + m_phase = SCSI_PHASE_DATAOUT; + m_status_code = SCSI_STATUS_CODE_GOOD; + m_transfer_length = TRANSFERLENGTH_FORMAT_ALT_TRACK; + break; + + case S1410_CMD_WRITE_SEC_BUFFER: + m_phase = SCSI_PHASE_DATAOUT; + m_status_code = SCSI_STATUS_CODE_GOOD; + m_transfer_length = TRANSFERLENGTH_SECTOR_BUFFER; + break; + + case S1410_CMD_READ_SEC_BUFFER: + m_phase = SCSI_PHASE_DATAIN; + m_status_code = SCSI_STATUS_CODE_GOOD; + m_transfer_length = TRANSFERLENGTH_SECTOR_BUFFER; + break; + + case S1410_CMD_CHECK_TRACK_FORMAT: + case S1410_CMD_RAM_DIAGS: + case S1410_CMD_DRIVE_DIAGS: + case S1410_CMD_CONTROLER_DIAGS: + m_phase = SCSI_PHASE_STATUS; + m_status_code = SCSI_STATUS_CODE_GOOD; + m_transfer_length = 0; + break; + + default: + scsihd_device::ExecCommand(); + break; + } +} + +void s1410_device::WriteData( UINT8 *data, int dataLength ) +{ + switch( command[ 0 ] ) + { + case S1410_CMD_INIT_DRIVE_PARAMS: + { + int sectorsPerTrack = 0; + + switch( m_sector_bytes ) + { + case 256: + sectorsPerTrack = 32; + break; + + case 512: + sectorsPerTrack = 17; + break; + } + + UINT16 tracks = ((data[0]<<8)+data[1]); + UINT8 heads = data[2]; + UINT32 capacity = tracks * heads * sectorsPerTrack * m_sector_bytes; + + logerror("S1410_CMD_INIT_DRIVE_PARAMS Tracks=%d, Heads=%d, Capacity=%d\n",tracks,heads,capacity); + } + break; + + default: + scsihd_device::WriteData( data, dataLength ); + break; + } +} + +void s1410_device::ReadData( UINT8 *data, int dataLength ) +{ + switch( command[ 0 ] ) + { + case T10SPC_CMD_REQUEST_SENSE: + data[0] = m_sense_asc & 0x7f; + data[1] = (m_sense_information >> 16) & 0x1f; + data[2] = (m_sense_information >> 8) & 0xff; + data[3] = (m_sense_information >> 0) & 0xff; + break; + + default: + scsihd_device::ReadData( data, dataLength ); + break; + } +} diff --git a/src/devices/bus/scsi/s1410.h b/src/devices/bus/scsi/s1410.h new file mode 100644 index 00000000000..b7834f56c88 --- /dev/null +++ b/src/devices/bus/scsi/s1410.h @@ -0,0 +1,35 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Xebec S1410 5.25" Winchester Disk Controller emulation + +**********************************************************************/ + +#pragma once + +#ifndef __S1410__ +#define __S1410__ + +#include "scsihd.h" + +class s1410_device : public scsihd_device +{ +public: + // construction/destruction + s1410_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + + virtual void ExecCommand(); + virtual void WriteData( UINT8 *data, int dataLength ); + virtual void ReadData( UINT8 *data, int dataLength ); +}; + + +// device type definition +extern const device_type S1410; + +#endif diff --git a/src/devices/bus/scsi/sa1403d.c b/src/devices/bus/scsi/sa1403d.c new file mode 100644 index 00000000000..1abe47e0805 --- /dev/null +++ b/src/devices/bus/scsi/sa1403d.c @@ -0,0 +1,148 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Shugart SA1403D Winchester Disk Controller emulation + +**********************************************************************/ + +#include "sa1403d.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type SA1403D = &device_creator; + + +//------------------------------------------------- +// ROM( sa1403d ) +//------------------------------------------------- + +ROM_START( sa1403d ) + ROM_REGION( 0x4000, "sa1403d", 0 ) + ROM_DEFAULT_BIOS( "as31" ) + ROM_SYSTEM_BIOS( 0, "as30", "AS30" ) + ROMX_LOAD( "i", 0x0000, 0x1000, NO_DUMP, ROM_BIOS(1) ) + ROMX_LOAD( "ii", 0x1000, 0x1000, NO_DUMP, ROM_BIOS(1) ) + ROMX_LOAD( "iii", 0x2000, 0x1000, NO_DUMP, ROM_BIOS(1) ) + ROMX_LOAD( "iv", 0x3000, 0x1000, NO_DUMP, ROM_BIOS(1) ) + ROM_SYSTEM_BIOS( 1, "as31", "AS31" ) + ROMX_LOAD( "i", 0x0000, 0x1000, NO_DUMP, ROM_BIOS(2) ) + ROMX_LOAD( "ii", 0x1000, 0x1000, NO_DUMP, ROM_BIOS(2) ) + ROMX_LOAD( "iii", 0x2000, 0x1000, NO_DUMP, ROM_BIOS(2) ) + ROMX_LOAD( "iv", 0x3000, 0x1000, NO_DUMP, ROM_BIOS(2) ) + ROM_SYSTEM_BIOS( 2, "u50", "Diagnostic PROM set 12668" ) + ROMX_LOAD( "i", 0x0000, 0x1000, NO_DUMP, ROM_BIOS(3) ) + ROMX_LOAD( "ii", 0x1000, 0x1000, NO_DUMP, ROM_BIOS(3) ) + ROMX_LOAD( "iii", 0x2000, 0x1000, NO_DUMP, ROM_BIOS(3) ) + ROMX_LOAD( "iv", 0x3000, 0x1000, NO_DUMP, ROM_BIOS(3) ) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *sa1403d_device::device_rom_region() const +{ + return ROM_NAME( sa1403d ); +} + + +//------------------------------------------------- +// MACHINE_DRIVER( sa1403d ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( sa1403d ) + MCFG_HARDDISK_ADD("image") +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor sa1403d_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( sa1403d ); +} + + +//------------------------------------------------- +// INPUT_PORTS( sa1403d ) +//------------------------------------------------- + +INPUT_PORTS_START( sa1403d ) + PORT_INCLUDE(scsihle) + + PORT_START("2H") + PORT_DIPNAME( 0xc0, 0x40, "LUN 0 Drive Type" ) PORT_DIPLOCATION("2H:7,8") + PORT_DIPSETTING( 0x00, "SA1002" ) // 2 heads, 256 cylinders + PORT_DIPSETTING( 0x40, "SA1004" ) // 4 heads, 256 cylinders + PORT_DIPSETTING( 0x80, "SA800" ) // 1 head, 77 cylinders + PORT_DIPSETTING( 0xc0, "SA850" ) // 2 heads, 77 cylinders + PORT_DIPNAME( 0x30, 0x30, "LUN 1 Drive Type" ) PORT_DIPLOCATION("2H:5,6") + PORT_DIPSETTING( 0x00, "SA1002" ) + PORT_DIPSETTING( 0x10, "SA1004" ) + PORT_DIPSETTING( 0x20, "SA800" ) + PORT_DIPSETTING( 0x30, "SA850" ) + PORT_DIPNAME( 0x0c, 0x0c, "LUN 2 Drive Type" ) PORT_DIPLOCATION("2H:3,4") + PORT_DIPSETTING( 0x00, "SA1002" ) + PORT_DIPSETTING( 0x04, "SA1004" ) + PORT_DIPSETTING( 0x08, "SA800" ) + PORT_DIPSETTING( 0x0c, "SA850" ) + PORT_DIPNAME( 0x03, 0x03, "LUN 3 Drive Type" ) PORT_DIPLOCATION("2H:1,2") + PORT_DIPSETTING( 0x00, "SA1002" ) + PORT_DIPSETTING( 0x01, "SA1004" ) + PORT_DIPSETTING( 0x02, "SA800" ) + PORT_DIPSETTING( 0x03, "SA850" ) +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor sa1403d_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( sa1403d ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// sa1403d_device - constructor +//------------------------------------------------- + +sa1403d_device::sa1403d_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : scsihd_device(mconfig, SA1403D, "Shugart SA1403D", tag, owner, clock, "sa1403d", __FILE__) +{ +} + +void sa1403d_device::ExecCommand() +{ + switch( command[ 0 ] ) + { + default: + scsihd_device::ExecCommand(); + break; + } +} + +void sa1403d_device::WriteData( UINT8 *data, int dataLength ) +{ + switch( command[ 0 ] ) + { + default: + scsihd_device::WriteData( data, dataLength ); + break; + } +} diff --git a/src/devices/bus/scsi/sa1403d.h b/src/devices/bus/scsi/sa1403d.h new file mode 100644 index 00000000000..5f92ff11240 --- /dev/null +++ b/src/devices/bus/scsi/sa1403d.h @@ -0,0 +1,36 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Shugart SA1403D Winchester Disk Controller emulation + +**********************************************************************/ + +#pragma once + +#ifndef __SA1403D__ +#define __SA1403D__ + +#include "scsihd.h" +#include "imagedev/harddriv.h" + +class sa1403d_device : public scsihd_device +{ +public: + // construction/destruction + sa1403d_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + virtual ioport_constructor device_input_ports() const; + + virtual void ExecCommand(); + virtual void WriteData( UINT8 *data, int dataLength ); +}; + + +// device type definition +extern const device_type SA1403D; + +#endif diff --git a/src/devices/bus/scsi/scsi.c b/src/devices/bus/scsi/scsi.c new file mode 100644 index 00000000000..7eac8fc7631 --- /dev/null +++ b/src/devices/bus/scsi/scsi.c @@ -0,0 +1,709 @@ +// license:BSD-3-Clause +// copyright-holders:smf + +#include "scsi.h" + +SCSI_PORT_DEVICE::SCSI_PORT_DEVICE(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, SCSI_PORT, "SCSI Port", tag, owner, clock, "scsi", __FILE__), + m_bsy_handler(*this), + m_sel_handler(*this), + m_cd_handler(*this), + m_io_handler(*this), + m_msg_handler(*this), + m_req_handler(*this), + m_ack_handler(*this), + m_atn_handler(*this), + m_rst_handler(*this), + m_data0_handler(*this), + m_data1_handler(*this), + m_data2_handler(*this), + m_data3_handler(*this), + m_data4_handler(*this), + m_data5_handler(*this), + m_data6_handler(*this), + m_data7_handler(*this), + m_bsy_in(0), + m_sel_in(0), + m_cd_in(0), + m_io_in(0), + m_msg_in(0), + m_req_in(0), + m_ack_in(0), + m_rst_in(0), + m_data0_in(0), + m_data1_in(0), + m_data2_in(0), + m_data3_in(0), + m_data4_in(0), + m_data5_in(0), + m_data6_in(0), + m_data7_in(0), + m_bsy_out(0), + m_sel_out(0), + m_cd_out(0), + m_io_out(0), + m_msg_out(0), + m_req_out(0), + m_ack_out(0), + m_rst_out(0), + m_data0_out(0), + m_data1_out(0), + m_data2_out(0), + m_data3_out(0), + m_data4_out(0), + m_data5_out(0), + m_data6_out(0), + m_data7_out(0) +{ +} + +static MACHINE_CONFIG_FRAGMENT( scsi_port ) + MCFG_DEVICE_ADD( SCSI_PORT_DEVICE1, SCSI_PORT_SLOT, 0 ) + MCFG_DEVICE_ADD( SCSI_PORT_DEVICE2, SCSI_PORT_SLOT, 0 ) + MCFG_DEVICE_ADD( SCSI_PORT_DEVICE3, SCSI_PORT_SLOT, 0 ) + MCFG_DEVICE_ADD( SCSI_PORT_DEVICE4, SCSI_PORT_SLOT, 0 ) + MCFG_DEVICE_ADD( SCSI_PORT_DEVICE5, SCSI_PORT_SLOT, 0 ) + MCFG_DEVICE_ADD( SCSI_PORT_DEVICE6, SCSI_PORT_SLOT, 0 ) + MCFG_DEVICE_ADD( SCSI_PORT_DEVICE7, SCSI_PORT_SLOT, 0 ) +MACHINE_CONFIG_END + +machine_config_constructor SCSI_PORT_DEVICE::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( scsi_port ); +} + +void SCSI_PORT_DEVICE::device_start() +{ + const char *deviceName[] = + { + SCSI_PORT_DEVICE1, + SCSI_PORT_DEVICE2, + SCSI_PORT_DEVICE3, + SCSI_PORT_DEVICE4, + SCSI_PORT_DEVICE5, + SCSI_PORT_DEVICE6, + SCSI_PORT_DEVICE7 + }; + + m_device_count = 0; + + for (int i = 0; i < 7; i++) + { + SCSI_PORT_SLOT_device *slot = subdevice(deviceName[i]); + m_slot[i] = slot; + + if (slot != NULL) + m_device_count = i + 1; + } + + m_bsy_handler.resolve_safe(); + m_sel_handler.resolve_safe(); + m_cd_handler.resolve_safe(); + m_io_handler.resolve_safe(); + m_msg_handler.resolve_safe(); + m_req_handler.resolve_safe(); + m_ack_handler.resolve_safe(); + m_atn_handler.resolve_safe(); + m_rst_handler.resolve_safe(); + m_data0_handler.resolve_safe(); + m_data1_handler.resolve_safe(); + m_data2_handler.resolve_safe(); + m_data3_handler.resolve_safe(); + m_data4_handler.resolve_safe(); + m_data5_handler.resolve_safe(); + m_data6_handler.resolve_safe(); + m_data7_handler.resolve_safe(); + + m_data0_handler(0); + m_data1_handler(0); + m_data2_handler(0); + m_data3_handler(0); + m_data4_handler(0); + m_data5_handler(0); + m_data6_handler(0); + m_data7_handler(0); + + m_bsy_handler(0); + m_sel_handler(0); + m_cd_handler(0); + m_io_handler(0); + m_msg_handler(0); + m_req_handler(0); + m_ack_handler(0); + m_atn_handler(0); + m_rst_handler(0); +} + +void SCSI_PORT_DEVICE::update_bsy() +{ + int bsy = m_bsy_in; + for (int i = 0; i < m_device_count; i++) + { + bsy |= m_slot[i]->m_bsy; + } + + if (m_bsy_out != bsy) + { + m_bsy_out = bsy; + m_bsy_handler(bsy); + + for (int i = 0; i < m_device_count; i++) + { + scsi_port_interface *dev = m_slot[i]->dev(); + if (dev != NULL) + dev->input_bsy(bsy); + } + } +} + +void SCSI_PORT_DEVICE::update_sel() +{ + int sel = m_sel_in; + for (int i = 0; i < m_device_count; i++) + { + sel |= m_slot[i]->m_sel; + } + + if (m_sel_out != sel) + { + m_sel_out = sel; + m_sel_handler(sel); + + for (int i = 0; i < m_device_count; i++) + { + scsi_port_interface *dev = m_slot[i]->dev(); + if (dev != NULL) + dev->input_sel(sel); + } + } +} + +void SCSI_PORT_DEVICE::update_cd() +{ + int cd = m_cd_in; + for (int i = 0; i < m_device_count; i++) + { + cd |= m_slot[i]->m_cd; + } + + if (m_cd_out != cd) + { + m_cd_out = cd; + m_cd_handler(cd); + + for (int i = 0; i < m_device_count; i++) + { + scsi_port_interface *dev = m_slot[i]->dev(); + if (dev != NULL) + dev->input_cd(cd); + } + } +} + +void SCSI_PORT_DEVICE::update_io() +{ + int io = m_io_in; + for (int i = 0; i < m_device_count; i++) + { + io |= m_slot[i]->m_io; + } + + if (m_io_out != io) + { + m_io_out = io; + m_io_handler(io); + + for (int i = 0; i < m_device_count; i++) + { + scsi_port_interface *dev = m_slot[i]->dev(); + if (dev != NULL) + dev->input_io(io); + } + } +} + +void SCSI_PORT_DEVICE::update_msg() +{ + int msg = m_msg_in; + for (int i = 0; i < m_device_count; i++) + { + msg |= m_slot[i]->m_msg; + } + + if (m_msg_out != msg) + { + m_msg_out = msg; + m_msg_handler(msg); + + for (int i = 0; i < m_device_count; i++) + { + scsi_port_interface *dev = m_slot[i]->dev(); + if (dev != NULL) + dev->input_msg(msg); + } + } +} + +void SCSI_PORT_DEVICE::update_req() +{ + int req = m_req_in; + for (int i = 0; i < m_device_count; i++) + { + req |= m_slot[i]->m_req; + } + + if (m_req_out != req) + { + m_req_out = req; + m_req_handler(req); + + for (int i = 0; i < m_device_count; i++) + { + scsi_port_interface *dev = m_slot[i]->dev(); + if (dev != NULL) + dev->input_req(req); + } + } +} + +void SCSI_PORT_DEVICE::update_ack() +{ + int ack = m_ack_in; + for (int i = 0; i < m_device_count; i++) + { + ack |= m_slot[i]->m_ack; + } + + if (m_ack_out != ack) + { + m_ack_out = ack; + m_ack_handler(ack); + + for (int i = 0; i < m_device_count; i++) + { + scsi_port_interface *dev = m_slot[i]->dev(); + if (dev != NULL) + dev->input_ack(ack); + } + } +} + +void SCSI_PORT_DEVICE::update_atn() +{ + int atn = m_atn_in; + for (int i = 0; i < m_device_count; i++) + { + atn |= m_slot[i]->m_atn; + } + + if (m_atn_out != atn) + { + m_atn_out = atn; + m_atn_handler(atn); + + for (int i = 0; i < m_device_count; i++) + { + scsi_port_interface *dev = m_slot[i]->dev(); + if (dev != NULL) + dev->input_atn(atn); + } + } +} + +void SCSI_PORT_DEVICE::update_rst() +{ + int rst = m_rst_in; + for (int i = 0; i < m_device_count; i++) + { + rst |= m_slot[i]->m_rst; + } + + if (m_rst_out != rst) + { + m_rst_out = rst; + m_rst_handler(rst); + + for (int i = 0; i < m_device_count; i++) + { + scsi_port_interface *dev = m_slot[i]->dev(); + if (dev != NULL) + dev->input_rst(rst); + } + } +} + +void SCSI_PORT_DEVICE::update_data0() +{ + int data0 = m_data0_in; + for (int i = 0; i < m_device_count; i++) + { + data0 |= m_slot[i]->m_data0; + } + + if (m_data0_out != data0) + { + m_data0_out = data0; + m_data0_handler(data0); + + for (int i = 0; i < m_device_count; i++) + { + scsi_port_interface *dev = m_slot[i]->dev(); + if (dev != NULL) + dev->input_data0(data0); + } + } +} + +void SCSI_PORT_DEVICE::update_data1() +{ + int data1 = m_data1_in; + for (int i = 0; i < m_device_count; i++) + { + data1 |= m_slot[i]->m_data1; + } + + if (m_data1_out != data1) + { + m_data1_out = data1; + m_data1_handler(data1); + + for (int i = 0; i < m_device_count; i++) + { + scsi_port_interface *dev = m_slot[i]->dev(); + if (dev != NULL) + dev->input_data1(data1); + } + } +} + +void SCSI_PORT_DEVICE::update_data2() +{ + int data2 = m_data2_in; + for (int i = 0; i < m_device_count; i++) + { + data2 |= m_slot[i]->m_data2; + } + + if (m_data2_out != data2) + { + m_data2_out = data2; + m_data2_handler(data2); + + for (int i = 0; i < m_device_count; i++) + { + scsi_port_interface *dev = m_slot[i]->dev(); + if (dev != NULL) + dev->input_data2(data2); + } + } +} + +void SCSI_PORT_DEVICE::update_data3() +{ + int data3 = m_data3_in; + for (int i = 0; i < m_device_count; i++) + { + data3 |= m_slot[i]->m_data3; + } + + if (m_data3_out != data3) + { + m_data3_out = data3; + m_data3_handler(data3); + + for (int i = 0; i < m_device_count; i++) + { + scsi_port_interface *dev = m_slot[i]->dev(); + if (dev != NULL) + dev->input_data3(data3); + } + } +} + +void SCSI_PORT_DEVICE::update_data4() +{ + int data4 = m_data4_in; + for (int i = 0; i < m_device_count; i++) + { + data4 |= m_slot[i]->m_data4; + } + + if (m_data4_out != data4) + { + m_data4_out = data4; + m_data4_handler(data4); + + for (int i = 0; i < m_device_count; i++) + { + scsi_port_interface *dev = m_slot[i]->dev(); + if (dev != NULL) + dev->input_data4(data4); + } + } +} + +void SCSI_PORT_DEVICE::update_data5() +{ + int data5 = m_data5_in; + for (int i = 0; i < m_device_count; i++) + { + data5 |= m_slot[i]->m_data5; + } + + if (m_data5_out != data5) + { + m_data5_out = data5; + m_data5_handler(data5); + + for (int i = 0; i < m_device_count; i++) + { + scsi_port_interface *dev = m_slot[i]->dev(); + if (dev != NULL) + dev->input_data5(data5); + } + } +} + +void SCSI_PORT_DEVICE::update_data6() +{ + int data6 = m_data6_in; + for (int i = 0; i < m_device_count; i++) + { + data6 |= m_slot[i]->m_data6; + } + + if (m_data6_out != data6) + { + m_data6_out = data6; + m_data6_handler(data6); + + for (int i = 0; i < m_device_count; i++) + { + scsi_port_interface *dev = m_slot[i]->dev(); + if (dev != NULL) + dev->input_data6(data6); + } + } +} + +void SCSI_PORT_DEVICE::update_data7() +{ + int data7 = m_data7_in; + for (int i = 0; i < m_device_count; i++) + { + data7 |= m_slot[i]->m_data7; + } + + if (m_data7_out != data7) + { + m_data7_out = data7; + m_data7_handler(data7); + + for (int i = 0; i < m_device_count; i++) + { + scsi_port_interface *dev = m_slot[i]->dev(); + if (dev != NULL) + dev->input_data7(data7); + } + } +} + +WRITE_LINE_MEMBER( SCSI_PORT_DEVICE::write_bsy ) +{ + if (m_bsy_in != state) + { + m_bsy_in = state; + update_bsy(); + } +} + +WRITE_LINE_MEMBER( SCSI_PORT_DEVICE::write_sel ) +{ + if (m_sel_in != state) + { + m_sel_in = state; + update_sel(); + } +} + +WRITE_LINE_MEMBER( SCSI_PORT_DEVICE::write_cd ) +{ + if (m_cd_in != state) + { + m_cd_in = state; + update_cd(); + } +} + +WRITE_LINE_MEMBER( SCSI_PORT_DEVICE::write_io ) +{ + if (m_io_in != state) + { + m_io_in = state; + update_io(); + } +} + +WRITE_LINE_MEMBER( SCSI_PORT_DEVICE::write_msg ) +{ + if (m_msg_in != state) + { + m_msg_in = state; + update_msg(); + } +} + +WRITE_LINE_MEMBER( SCSI_PORT_DEVICE::write_req ) +{ + if (m_req_in != state) + { + m_req_in = state; + update_req(); + } +} + +WRITE_LINE_MEMBER( SCSI_PORT_DEVICE::write_ack ) +{ + if (m_ack_in != state) + { + m_ack_in = state; + update_ack(); + } +} + +WRITE_LINE_MEMBER( SCSI_PORT_DEVICE::write_atn ) +{ + if (m_atn_in != state) + { + m_atn_in = state; + update_atn(); + } +} + +WRITE_LINE_MEMBER( SCSI_PORT_DEVICE::write_rst ) +{ + if (m_rst_in != state) + { + m_rst_in = state; + update_rst(); + } +} + +WRITE_LINE_MEMBER( SCSI_PORT_DEVICE::write_data0 ) +{ + if (m_data0_in != state) + { + m_data0_in = state; + update_data0(); + } +} + +WRITE_LINE_MEMBER( SCSI_PORT_DEVICE::write_data1 ) +{ + if (m_data1_in != state) + { + m_data1_in = state; + update_data1(); + } +} + +WRITE_LINE_MEMBER( SCSI_PORT_DEVICE::write_data2 ) +{ + if (m_data2_in != state) + { + m_data2_in = state; + update_data2(); + } +} + +WRITE_LINE_MEMBER( SCSI_PORT_DEVICE::write_data3 ) +{ + if (m_data3_in != state) + { + m_data3_in = state; + update_data3(); + } +} + +WRITE_LINE_MEMBER( SCSI_PORT_DEVICE::write_data4 ) +{ + if (m_data4_in != state) + { + m_data4_in = state; + update_data4(); + } +} + +WRITE_LINE_MEMBER( SCSI_PORT_DEVICE::write_data5 ) +{ + if (m_data5_in != state) + { + m_data5_in = state; + update_data5(); + } +} + +WRITE_LINE_MEMBER( SCSI_PORT_DEVICE::write_data6 ) +{ + if (m_data6_in != state) + { + m_data6_in = state; + update_data6(); + } +} + +WRITE_LINE_MEMBER( SCSI_PORT_DEVICE::write_data7 ) +{ + if (m_data7_in != state) + { + m_data7_in = state; + update_data7(); + } +} + +const device_type SCSI_PORT = &device_creator; + +SCSI_PORT_SLOT_device::SCSI_PORT_SLOT_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, SCSI_PORT_SLOT, "SCSI Connector", tag, owner, clock, "scsi_slot", __FILE__), + device_slot_interface(mconfig, *this), + m_dev(NULL), + m_bsy(0), + m_sel(0), + m_cd(0), + m_io(0), + m_msg(0), + m_req(0), + m_ack(0), + m_rst(0), + m_data0(0), + m_data1(0), + m_data2(0), + m_data3(0), + m_data4(0), + m_data5(0), + m_data6(0), + m_data7(0) +{ + m_port = dynamic_cast(device().owner()); +} + +void SCSI_PORT_SLOT_device::device_config_complete() +{ + m_dev = dynamic_cast(get_card_device()); +} + +void SCSI_PORT_SLOT_device::device_start() +{ +} + +const device_type SCSI_PORT_SLOT = &device_creator; + +scsi_port_interface::scsi_port_interface(const machine_config &mconfig, device_t &device) + : device_slot_card_interface(mconfig, device) +{ + m_slot = dynamic_cast(device.owner()); +} + +scsi_port_interface::~scsi_port_interface() +{ +} diff --git a/src/devices/bus/scsi/scsi.h b/src/devices/bus/scsi/scsi.h new file mode 100644 index 00000000000..dd8c88635ed --- /dev/null +++ b/src/devices/bus/scsi/scsi.h @@ -0,0 +1,313 @@ +// license:BSD-3-Clause +// copyright-holders:smf + +#pragma once + +#ifndef _SCSI_H_ +#define _SCSI_H_ + +#include "emu.h" +#include "machine/buffer.h" +#include "machine/latch.h" + +#define SCSI_PORT_DEVICE1 "1" +#define SCSI_PORT_DEVICE2 "2" +#define SCSI_PORT_DEVICE3 "3" +#define SCSI_PORT_DEVICE4 "4" +#define SCSI_PORT_DEVICE5 "5" +#define SCSI_PORT_DEVICE6 "6" +#define SCSI_PORT_DEVICE7 "7" + +#define MCFG_SCSI_BSY_HANDLER(_devcb) \ + devcb = &SCSI_PORT_DEVICE::set_bsy_handler(*device, DEVCB_##_devcb); + +#define MCFG_SCSI_SEL_HANDLER(_devcb) \ + devcb = &SCSI_PORT_DEVICE::set_sel_handler(*device, DEVCB_##_devcb); + +#define MCFG_SCSI_CD_HANDLER(_devcb) \ + devcb = &SCSI_PORT_DEVICE::set_cd_handler(*device, DEVCB_##_devcb); + +#define MCFG_SCSI_IO_HANDLER(_devcb) \ + devcb = &SCSI_PORT_DEVICE::set_io_handler(*device, DEVCB_##_devcb); + +#define MCFG_SCSI_MSG_HANDLER(_devcb) \ + devcb = &SCSI_PORT_DEVICE::set_msg_handler(*device, DEVCB_##_devcb); + +#define MCFG_SCSI_REQ_HANDLER(_devcb) \ + devcb = &SCSI_PORT_DEVICE::set_req_handler(*device, DEVCB_##_devcb); + +#define MCFG_SCSI_ACK_HANDLER(_devcb) \ + devcb = &SCSI_PORT_DEVICE::set_ack_handler(*device, DEVCB_##_devcb); + +#define MCFG_SCSI_ATN_HANDLER(_devcb) \ + devcb = &SCSI_PORT_DEVICE::set_atn_handler(*device, DEVCB_##_devcb); + +#define MCFG_SCSI_RST_HANDLER(_devcb) \ + devcb = &SCSI_PORT_DEVICE::set_rst_handler(*device, DEVCB_##_devcb); + +#define MCFG_SCSI_DATA0_HANDLER(_devcb) \ + devcb = &SCSI_PORT_DEVICE::set_data0_handler(*device, DEVCB_##_devcb); + +#define MCFG_SCSI_DATA1_HANDLER(_devcb) \ + devcb = &SCSI_PORT_DEVICE::set_data1_handler(*device, DEVCB_##_devcb); + +#define MCFG_SCSI_DATA2_HANDLER(_devcb) \ + devcb = &SCSI_PORT_DEVICE::set_data2_handler(*device, DEVCB_##_devcb); + +#define MCFG_SCSI_DATA3_HANDLER(_devcb) \ + devcb = &SCSI_PORT_DEVICE::set_data3_handler(*device, DEVCB_##_devcb); + +#define MCFG_SCSI_DATA4_HANDLER(_devcb) \ + devcb = &SCSI_PORT_DEVICE::set_data4_handler(*device, DEVCB_##_devcb); + +#define MCFG_SCSI_DATA5_HANDLER(_devcb) \ + devcb = &SCSI_PORT_DEVICE::set_data5_handler(*device, DEVCB_##_devcb); + +#define MCFG_SCSI_DATA6_HANDLER(_devcb) \ + devcb = &SCSI_PORT_DEVICE::set_data6_handler(*device, DEVCB_##_devcb); + +#define MCFG_SCSI_DATA7_HANDLER(_devcb) \ + devcb = &SCSI_PORT_DEVICE::set_data7_handler(*device, DEVCB_##_devcb); + +#define MCFG_SCSI_OUTPUT_LATCH_ADD(_tag, scsi_port_tag) \ + MCFG_DEVICE_ADD(_tag, OUTPUT_LATCH, 0) \ + MCFG_OUTPUT_LATCH_BIT0_HANDLER(DEVWRITELINE(scsi_port_tag, SCSI_PORT_DEVICE, write_data0)) \ + MCFG_OUTPUT_LATCH_BIT1_HANDLER(DEVWRITELINE(scsi_port_tag, SCSI_PORT_DEVICE, write_data1)) \ + MCFG_OUTPUT_LATCH_BIT2_HANDLER(DEVWRITELINE(scsi_port_tag, SCSI_PORT_DEVICE, write_data2)) \ + MCFG_OUTPUT_LATCH_BIT3_HANDLER(DEVWRITELINE(scsi_port_tag, SCSI_PORT_DEVICE, write_data3)) \ + MCFG_OUTPUT_LATCH_BIT4_HANDLER(DEVWRITELINE(scsi_port_tag, SCSI_PORT_DEVICE, write_data4)) \ + MCFG_OUTPUT_LATCH_BIT5_HANDLER(DEVWRITELINE(scsi_port_tag, SCSI_PORT_DEVICE, write_data5)) \ + MCFG_OUTPUT_LATCH_BIT6_HANDLER(DEVWRITELINE(scsi_port_tag, SCSI_PORT_DEVICE, write_data6)) \ + MCFG_OUTPUT_LATCH_BIT7_HANDLER(DEVWRITELINE(scsi_port_tag, SCSI_PORT_DEVICE, write_data7)) + +#define MCFG_SCSI_DATA_INPUT_BUFFER(_tag) \ + MCFG_SCSI_DATA0_HANDLER(DEVWRITELINE(_tag, input_buffer_device, write_bit0)) \ + MCFG_SCSI_DATA1_HANDLER(DEVWRITELINE(_tag, input_buffer_device, write_bit1)) \ + MCFG_SCSI_DATA2_HANDLER(DEVWRITELINE(_tag, input_buffer_device, write_bit2)) \ + MCFG_SCSI_DATA3_HANDLER(DEVWRITELINE(_tag, input_buffer_device, write_bit3)) \ + MCFG_SCSI_DATA4_HANDLER(DEVWRITELINE(_tag, input_buffer_device, write_bit4)) \ + MCFG_SCSI_DATA5_HANDLER(DEVWRITELINE(_tag, input_buffer_device, write_bit5)) \ + MCFG_SCSI_DATA6_HANDLER(DEVWRITELINE(_tag, input_buffer_device, write_bit6)) \ + MCFG_SCSI_DATA7_HANDLER(DEVWRITELINE(_tag, input_buffer_device, write_bit7)) + +class SCSI_PORT_SLOT_device; +class scsi_port_interface; + +class SCSI_PORT_DEVICE : public device_t +{ + friend class scsi_port_interface; + +public: + // construction/destruction + SCSI_PORT_DEVICE(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + template static devcb_base &set_bsy_handler(device_t &device, _Object object) { return downcast(device).m_bsy_handler.set_callback(object); } + template static devcb_base &set_sel_handler(device_t &device, _Object object) { return downcast(device).m_sel_handler.set_callback(object); } + template static devcb_base &set_cd_handler(device_t &device, _Object object) { return downcast(device).m_cd_handler.set_callback(object); } + template static devcb_base &set_io_handler(device_t &device, _Object object) { return downcast(device).m_io_handler.set_callback(object); } + template static devcb_base &set_msg_handler(device_t &device, _Object object) { return downcast(device).m_msg_handler.set_callback(object); } + template static devcb_base &set_req_handler(device_t &device, _Object object) { return downcast(device).m_req_handler.set_callback(object); } + template static devcb_base &set_ack_handler(device_t &device, _Object object) { return downcast(device).m_ack_handler.set_callback(object); } + template static devcb_base &set_atn_handler(device_t &device, _Object object) { return downcast(device).m_atn_handler.set_callback(object); } + template static devcb_base &set_rst_handler(device_t &device, _Object object) { return downcast(device).m_rst_handler.set_callback(object); } + template static devcb_base &set_data0_handler(device_t &device, _Object object) { return downcast(device).m_data0_handler.set_callback(object); } + template static devcb_base &set_data1_handler(device_t &device, _Object object) { return downcast(device).m_data1_handler.set_callback(object); } + template static devcb_base &set_data2_handler(device_t &device, _Object object) { return downcast(device).m_data2_handler.set_callback(object); } + template static devcb_base &set_data3_handler(device_t &device, _Object object) { return downcast(device).m_data3_handler.set_callback(object); } + template static devcb_base &set_data4_handler(device_t &device, _Object object) { return downcast(device).m_data4_handler.set_callback(object); } + template static devcb_base &set_data5_handler(device_t &device, _Object object) { return downcast(device).m_data5_handler.set_callback(object); } + template static devcb_base &set_data6_handler(device_t &device, _Object object) { return downcast(device).m_data6_handler.set_callback(object); } + template static devcb_base &set_data7_handler(device_t &device, _Object object) { return downcast(device).m_data7_handler.set_callback(object); } + + DECLARE_WRITE_LINE_MEMBER( write_bsy ); + DECLARE_WRITE_LINE_MEMBER( write_sel ); + DECLARE_WRITE_LINE_MEMBER( write_cd ); + DECLARE_WRITE_LINE_MEMBER( write_io ); + DECLARE_WRITE_LINE_MEMBER( write_msg ); + DECLARE_WRITE_LINE_MEMBER( write_req ); + DECLARE_WRITE_LINE_MEMBER( write_ack ); + DECLARE_WRITE_LINE_MEMBER( write_atn ); + DECLARE_WRITE_LINE_MEMBER( write_rst ); + DECLARE_WRITE_LINE_MEMBER( write_data0 ); + DECLARE_WRITE_LINE_MEMBER( write_data1 ); + DECLARE_WRITE_LINE_MEMBER( write_data2 ); + DECLARE_WRITE_LINE_MEMBER( write_data3 ); + DECLARE_WRITE_LINE_MEMBER( write_data4 ); + DECLARE_WRITE_LINE_MEMBER( write_data5 ); + DECLARE_WRITE_LINE_MEMBER( write_data6 ); + DECLARE_WRITE_LINE_MEMBER( write_data7 ); + +protected: + // device-level overrides + virtual void device_start(); + virtual machine_config_constructor device_mconfig_additions() const; + + void update_bsy(); + void update_sel(); + void update_cd(); + void update_io(); + void update_msg(); + void update_req(); + void update_ack(); + void update_atn(); + void update_rst(); + void update_data0(); + void update_data1(); + void update_data2(); + void update_data3(); + void update_data4(); + void update_data5(); + void update_data6(); + void update_data7(); + +private: + devcb_write_line m_bsy_handler; + devcb_write_line m_sel_handler; + devcb_write_line m_cd_handler; + devcb_write_line m_io_handler; + devcb_write_line m_msg_handler; + devcb_write_line m_req_handler; + devcb_write_line m_ack_handler; + devcb_write_line m_atn_handler; + devcb_write_line m_rst_handler; + devcb_write_line m_data0_handler; + devcb_write_line m_data1_handler; + devcb_write_line m_data2_handler; + devcb_write_line m_data3_handler; + devcb_write_line m_data4_handler; + devcb_write_line m_data5_handler; + devcb_write_line m_data6_handler; + devcb_write_line m_data7_handler; + + SCSI_PORT_SLOT_device *m_slot[7]; + int m_device_count; + + int m_bsy_in; + int m_sel_in; + int m_cd_in; + int m_io_in; + int m_msg_in; + int m_req_in; + int m_ack_in; + int m_atn_in; + int m_rst_in; + int m_data0_in; + int m_data1_in; + int m_data2_in; + int m_data3_in; + int m_data4_in; + int m_data5_in; + int m_data6_in; + int m_data7_in; + int m_bsy_out; + int m_sel_out; + int m_cd_out; + int m_io_out; + int m_msg_out; + int m_req_out; + int m_ack_out; + int m_atn_out; + int m_rst_out; + int m_data0_out; + int m_data1_out; + int m_data2_out; + int m_data3_out; + int m_data4_out; + int m_data5_out; + int m_data6_out; + int m_data7_out; +}; + +extern const device_type SCSI_PORT; + +class scsi_port_interface; + +class SCSI_PORT_SLOT_device : public device_t, + public device_slot_interface +{ + friend class SCSI_PORT_DEVICE; + friend class scsi_port_interface; + +public: + SCSI_PORT_SLOT_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + scsi_port_interface *dev() { return m_dev; } + SCSI_PORT_DEVICE *port() { return m_port; } + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_config_complete(); + +protected: + scsi_port_interface *m_dev; + SCSI_PORT_DEVICE *m_port; + + int m_bsy; + int m_sel; + int m_cd; + int m_io; + int m_msg; + int m_req; + int m_ack; + int m_atn; + int m_rst; + int m_data0; + int m_data1; + int m_data2; + int m_data3; + int m_data4; + int m_data5; + int m_data6; + int m_data7; +}; + +extern const device_type SCSI_PORT_SLOT; + +class scsi_port_interface : public device_slot_card_interface +{ +public: + scsi_port_interface(const machine_config &mconfig, device_t &device); + virtual ~scsi_port_interface(); + + virtual DECLARE_WRITE_LINE_MEMBER( input_bsy ) {} + virtual DECLARE_WRITE_LINE_MEMBER( input_sel ) {} + virtual DECLARE_WRITE_LINE_MEMBER( input_cd ) {} + virtual DECLARE_WRITE_LINE_MEMBER( input_io ) {} + virtual DECLARE_WRITE_LINE_MEMBER( input_msg ) {} + virtual DECLARE_WRITE_LINE_MEMBER( input_req ) {} + virtual DECLARE_WRITE_LINE_MEMBER( input_ack ) {} + virtual DECLARE_WRITE_LINE_MEMBER( input_atn ) {} + virtual DECLARE_WRITE_LINE_MEMBER( input_rst ) {} + virtual DECLARE_WRITE_LINE_MEMBER( input_data0 ) {} + virtual DECLARE_WRITE_LINE_MEMBER( input_data1 ) {} + virtual DECLARE_WRITE_LINE_MEMBER( input_data2 ) {} + virtual DECLARE_WRITE_LINE_MEMBER( input_data3 ) {} + virtual DECLARE_WRITE_LINE_MEMBER( input_data4 ) {} + virtual DECLARE_WRITE_LINE_MEMBER( input_data5 ) {} + virtual DECLARE_WRITE_LINE_MEMBER( input_data6 ) {} + virtual DECLARE_WRITE_LINE_MEMBER( input_data7 ) {} + + DECLARE_WRITE_LINE_MEMBER( output_bsy ) { if (m_slot->m_bsy != state) { m_slot->m_bsy = state; m_slot->port()->update_bsy(); } } + DECLARE_WRITE_LINE_MEMBER( output_sel ) { if (m_slot->m_sel != state) { m_slot->m_sel = state; m_slot->port()->update_sel(); } } + DECLARE_WRITE_LINE_MEMBER( output_cd ) { if (m_slot->m_cd != state) { m_slot->m_cd = state; m_slot->port()->update_cd(); } } + DECLARE_WRITE_LINE_MEMBER( output_io ) { if (m_slot->m_io != state) { m_slot->m_io = state; m_slot->port()->update_io(); } } + DECLARE_WRITE_LINE_MEMBER( output_msg ) { if (m_slot->m_msg != state) { m_slot->m_msg = state; m_slot->port()->update_msg(); } } + DECLARE_WRITE_LINE_MEMBER( output_req ) { if (m_slot->m_req != state) { m_slot->m_req = state; m_slot->port()->update_req(); } } + DECLARE_WRITE_LINE_MEMBER( output_ack ) { if (m_slot->m_ack != state) { m_slot->m_ack = state; m_slot->port()->update_ack(); } } + DECLARE_WRITE_LINE_MEMBER( output_atn ) { if (m_slot->m_atn != state) { m_slot->m_atn = state; m_slot->port()->update_atn(); } } + DECLARE_WRITE_LINE_MEMBER( output_rst ) { if (m_slot->m_rst != state) { m_slot->m_rst = state; m_slot->port()->update_rst(); } } + DECLARE_WRITE_LINE_MEMBER( output_data0 ) { if (m_slot->m_data0 != state) { m_slot->m_data0 = state; m_slot->port()->update_data0(); } } + DECLARE_WRITE_LINE_MEMBER( output_data1 ) { if (m_slot->m_data1 != state) { m_slot->m_data1 = state; m_slot->port()->update_data1(); } } + DECLARE_WRITE_LINE_MEMBER( output_data2 ) { if (m_slot->m_data2 != state) { m_slot->m_data2 = state; m_slot->port()->update_data2(); } } + DECLARE_WRITE_LINE_MEMBER( output_data3 ) { if (m_slot->m_data3 != state) { m_slot->m_data3 = state; m_slot->port()->update_data3(); } } + DECLARE_WRITE_LINE_MEMBER( output_data4 ) { if (m_slot->m_data4 != state) { m_slot->m_data4 = state; m_slot->port()->update_data4(); } } + DECLARE_WRITE_LINE_MEMBER( output_data5 ) { if (m_slot->m_data5 != state) { m_slot->m_data5 = state; m_slot->port()->update_data5(); } } + DECLARE_WRITE_LINE_MEMBER( output_data6 ) { if (m_slot->m_data6 != state) { m_slot->m_data6 = state; m_slot->port()->update_data6(); } } + DECLARE_WRITE_LINE_MEMBER( output_data7 ) { if (m_slot->m_data7 != state) { m_slot->m_data7 = state; m_slot->port()->update_data7(); } } + +private: + SCSI_PORT_SLOT_device *m_slot; +}; + +#endif diff --git a/src/devices/bus/scsi/scsicd.c b/src/devices/bus/scsi/scsicd.c new file mode 100644 index 00000000000..9ee7d92668f --- /dev/null +++ b/src/devices/bus/scsi/scsicd.c @@ -0,0 +1,41 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/*************************************************************************** + + scsicd.c - Implementation of a SCSI CD-ROM device + +***************************************************************************/ + +#include "scsicd.h" + +// device type definition +const device_type SCSICD = &device_creator; + +scsicd_device::scsicd_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + scsihle_device(mconfig, SCSICD, "SCSI CD", tag, owner, clock, "scsicd", __FILE__) +{ +} + +scsicd_device::scsicd_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + scsihle_device(mconfig, type, name, tag, owner, clock, shortname, source) +{ +} + +void scsicd_device::device_start() +{ + m_image = subdevice("image"); + m_cdda = subdevice("cdda"); + + scsihle_device::device_start(); +} + +static MACHINE_CONFIG_FRAGMENT(scsi_cdrom) + MCFG_CDROM_ADD("image") + MCFG_CDROM_INTERFACE("cdrom") + MCFG_SOUND_ADD("cdda", CDDA, 0) +MACHINE_CONFIG_END + +machine_config_constructor scsicd_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME(scsi_cdrom); +} diff --git a/src/devices/bus/scsi/scsicd.h b/src/devices/bus/scsi/scsicd.h new file mode 100644 index 00000000000..c7667ee3321 --- /dev/null +++ b/src/devices/bus/scsi/scsicd.h @@ -0,0 +1,31 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/*************************************************************************** + + scsicd.h + +***************************************************************************/ + +#ifndef _SCSICD_H_ +#define _SCSICD_H_ + +#include "scsihle.h" +#include "machine/t10mmc.h" + +class scsicd_device : public scsihle_device, + public t10mmc +{ +public: + // construction/destruction + scsicd_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + scsicd_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + virtual machine_config_constructor device_mconfig_additions() const; + +protected: + virtual void device_start(); +}; + +// device type definition +extern const device_type SCSICD; + +#endif diff --git a/src/devices/bus/scsi/scsihd.c b/src/devices/bus/scsi/scsihd.c new file mode 100644 index 00000000000..8774310d0b3 --- /dev/null +++ b/src/devices/bus/scsi/scsihd.c @@ -0,0 +1,39 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/*************************************************************************** + + scsihd.c - Implementation of a SCSI hard disk drive + +***************************************************************************/ + +#include "scsihd.h" + +// device type definition +const device_type SCSIHD = &device_creator; + +scsihd_device::scsihd_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : scsihle_device(mconfig, SCSIHD, "SCSI HD", tag, owner, clock, "scsihd", __FILE__) +{ +} + +scsihd_device::scsihd_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + scsihle_device(mconfig, type, name, tag, owner, clock, shortname, source) +{ +} + +void scsihd_device::device_start() +{ + m_image = subdevice("image"); + + scsihle_device::device_start(); +} + +static MACHINE_CONFIG_FRAGMENT(scsi_harddisk) + MCFG_HARDDISK_ADD("image") + MCFG_HARDDISK_INTERFACE("scsi_hdd") +MACHINE_CONFIG_END + +machine_config_constructor scsihd_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME(scsi_harddisk); +} diff --git a/src/devices/bus/scsi/scsihd.h b/src/devices/bus/scsi/scsihd.h new file mode 100644 index 00000000000..db151095847 --- /dev/null +++ b/src/devices/bus/scsi/scsihd.h @@ -0,0 +1,31 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/*************************************************************************** + + scsihd.h + +***************************************************************************/ + +#ifndef _SCSIHD_H_ +#define _SCSIHD_H_ + +#include "scsihle.h" +#include "machine/t10sbc.h" + +class scsihd_device : public scsihle_device, + public t10sbc +{ +public: + // construction/destruction + scsihd_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + scsihd_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + virtual machine_config_constructor device_mconfig_additions() const; + +protected: + virtual void device_start(); +}; + +// device type definition +extern const device_type SCSIHD; + +#endif diff --git a/src/devices/bus/scsi/scsihle.c b/src/devices/bus/scsi/scsihle.c new file mode 100644 index 00000000000..033e1f66bae --- /dev/null +++ b/src/devices/bus/scsi/scsihle.c @@ -0,0 +1,591 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/* + +scsihle.c + +Base class for HLE'd SCSI devices. + +*/ + +#include "scsihle.h" + +scsihle_device::scsihle_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + scsi_port_interface(mconfig, *this), + m_scsi_id(*this, "SCSI_ID"), + m_input_data(0) +{ +} + +INPUT_PORTS_START(scsihle) + PORT_START("SCSI_ID") + PORT_CONFNAME(0x07, 0x07, "SCSI ID") + PORT_CONFSETTING( 0x00, "0") + PORT_CONFSETTING( 0x01, "1") + PORT_CONFSETTING( 0x02, "2") + PORT_CONFSETTING( 0x03, "3") + PORT_CONFSETTING( 0x04, "4") + PORT_CONFSETTING( 0x05, "5") + PORT_CONFSETTING( 0x06, "6") + PORT_CONFSETTING( 0x07, "7") +INPUT_PORTS_END + +DEVICE_INPUT_DEFAULTS_START( SCSI_ID_0 ) + DEVICE_INPUT_DEFAULTS( "SCSI_ID", 7, 0 ) +DEVICE_INPUT_DEFAULTS_END + +DEVICE_INPUT_DEFAULTS_START( SCSI_ID_1 ) + DEVICE_INPUT_DEFAULTS( "SCSI_ID", 7, 1 ) +DEVICE_INPUT_DEFAULTS_END + +DEVICE_INPUT_DEFAULTS_START( SCSI_ID_2 ) + DEVICE_INPUT_DEFAULTS( "SCSI_ID", 7, 2 ) +DEVICE_INPUT_DEFAULTS_END + +DEVICE_INPUT_DEFAULTS_START( SCSI_ID_3 ) + DEVICE_INPUT_DEFAULTS( "SCSI_ID", 7, 3 ) +DEVICE_INPUT_DEFAULTS_END + +DEVICE_INPUT_DEFAULTS_START( SCSI_ID_4 ) + DEVICE_INPUT_DEFAULTS( "SCSI_ID", 7, 4 ) +DEVICE_INPUT_DEFAULTS_END + +DEVICE_INPUT_DEFAULTS_START( SCSI_ID_5 ) + DEVICE_INPUT_DEFAULTS( "SCSI_ID", 7, 5 ) +DEVICE_INPUT_DEFAULTS_END + +DEVICE_INPUT_DEFAULTS_START( SCSI_ID_6 ) + DEVICE_INPUT_DEFAULTS( "SCSI_ID", 7, 6 ) +DEVICE_INPUT_DEFAULTS_END + +DEVICE_INPUT_DEFAULTS_START( SCSI_ID_7 ) + DEVICE_INPUT_DEFAULTS( "SCSI_ID", 7, 7 ) +DEVICE_INPUT_DEFAULTS_END + +ioport_constructor scsihle_device::device_input_ports() const +{ + return INPUT_PORTS_NAME(scsihle); +} + +void scsihle_device::device_start() +{ + t10_start(*this); + + req_timer = timer_alloc(0); + sel_timer = timer_alloc(1); + dataout_timer = timer_alloc(2); +} + +void scsihle_device::device_reset() +{ + scsiID = m_scsi_id->read(); + t10_reset(); +} + +int scsihle_device::GetDeviceID() +{ + return scsiID; +} + +#define BSY_DELAY_NS 50 +#define REQ_DELAY_NS 90 + +static const char *const phasenames[] = +{ + "data out", "data in", "command", "status", "none", "none", "message out", "message in", "bus free","select" +}; + +// scsihle +#define SCSI_CMD_BUFFER_WRITE ( 0x3b ) +#define SCSI_CMD_BUFFER_READ ( 0x3c ) + +// scsihd +#define SCSI_CMD_FORMAT_UNIT 0x04 +#define SCSI_CMD_SEARCH_DATA_EQUAL 0x31 +#define SCSI_CMD_READ_DEFECT 0x37 + + +#define IS_COMMAND(cmd) (command[0]==cmd) + +#define FORMAT_UNIT_TIMEOUT 5 + +/* + LOGLEVEL + 0 no logging, + 1 just commands + 2 1 + data + 3 2 + line changes +*/ + +#define LOGLEVEL 0 + +#define LOG(level, ...) if(LOGLEVEL>=level) logerror(__VA_ARGS__) + +void scsihle_device::data_out(UINT8 data) +{ +// printf( "%s data out %02x\n", tag(), data ); + output_data0(BIT(data, 0)); + output_data1(BIT(data, 1)); + output_data2(BIT(data, 2)); + output_data3(BIT(data, 3)); + output_data4(BIT(data, 4)); + output_data5(BIT(data, 5)); + output_data6(BIT(data, 6)); + output_data7(BIT(data, 7)); +} + +void scsihle_device::scsi_out_req_delay(UINT8 state) +{ + req_timer->adjust(attotime::from_nsec(REQ_DELAY_NS),state); +} + +void scsihle_device::dump_bytes(UINT8 *buff, int count) +{ + int byteno; + + for(byteno=0; byteno= m_sector_bytes) ? m_sector_bytes : bytes_left; + + LOG(2,"SCSIBUS:scsibus_read_data bytes_left=%04X, data_last=%04X\n",bytes_left,data_last); + + data_idx=0; + + if (data_last > 0) + { + ReadData(buffer, data_last); + bytes_left-=data_last; + + data_out(buffer[ data_idx++ ]); + } +} + +void scsihle_device::scsibus_write_data() +{ + if (data_last > 0) + { + WriteData(buffer, data_last); + bytes_left -= data_last; + } + + data_idx=0; +} + +void scsihle_device::device_timer(emu_timer &timer, device_timer_id tid, int param, void *ptr) +{ + switch (tid) + { + case 0: + output_req(param); + break; + + case 1: + output_bsy(param); + break; + + case 2: + // Some drives, notably the ST225N and ST125N, accept fromat unit commands + // with flags set indicating that bad block data should be transfered but + // don't then implemnt a data in phase, this timeout it to catch these ! + if (IS_COMMAND(SCSI_CMD_FORMAT_UNIT) && (data_idx==0)) + { + scsi_change_phase(SCSI_PHASE_STATUS); + } + break; + } +} + +void scsihle_device::scsibus_exec_command() +{ + int command_local = 0; + + if (LOGLEVEL) + dump_command_bytes(); + + //is_linked=command[cmd_idx-1] & 0x01; + is_linked=0; + + // Check for locally executed commands, and if found execute them + switch (command[0]) + { + // Format unit + case SCSI_CMD_FORMAT_UNIT: + LOG(1,"SCSIBUS: format unit command[1]=%02X & 0x10\n",(command[1] & 0x10)); + command_local=1; + if ((command[1] & 0x10)==0x10) + m_phase = SCSI_PHASE_DATAOUT; + else + m_phase = SCSI_PHASE_STATUS; + + m_status_code = SCSI_STATUS_CODE_GOOD; + bytes_left=4; + dataout_timer->adjust(attotime::from_seconds(FORMAT_UNIT_TIMEOUT)); + break; + + case SCSI_CMD_SEARCH_DATA_EQUAL: + LOG(1,"SCSIBUS: Search_data_equaln"); + command_local=1; + bytes_left=0; + m_phase = SCSI_PHASE_STATUS; + m_status_code = SCSI_STATUS_CODE_GOOD; + break; + + case SCSI_CMD_READ_DEFECT: + LOG(1,"SCSIBUS: read defect list\n"); + command_local=1; + + buffer[0] = 0x00; + buffer[1] = command[2]; + buffer[3] = 0x00; // defect list len msb + buffer[4] = 0x00; // defect list len lsb + + bytes_left=4; + m_phase = SCSI_PHASE_DATAIN; + m_status_code = SCSI_STATUS_CODE_GOOD; + break; + + // write buffer + case SCSI_CMD_BUFFER_WRITE: + LOG(1,"SCSIBUS: write_buffer\n"); + command_local=1; + bytes_left=(command[7]<<8)+command[8]; + m_phase = SCSI_PHASE_DATAOUT; + m_status_code = SCSI_STATUS_CODE_GOOD; + break; + + // read buffer + case SCSI_CMD_BUFFER_READ: + LOG(1,"SCSIBUS: read_buffer\n"); + command_local=1; + bytes_left = (command[7]<<8) + command[8]; + m_phase = SCSI_PHASE_DATAIN; + m_status_code = SCSI_STATUS_CODE_GOOD; + break; + } + + + // Check for locally executed command, if not then pass it on + // to the disk driver + if (!command_local) + { + SetCommand(command, cmd_idx); + ExecCommand(); + GetLength(&bytes_left); + data_idx=0; + } + + scsi_change_phase(m_phase); + + LOG(1,"SCSIBUS:bytes_left=%02X data_idx=%02X\n",bytes_left,data_idx); + + // This is correct as we need to read from disk for commands other than just read data + if ((m_phase == SCSI_PHASE_DATAIN) && (!command_local)) + scsibus_read_data(); +} + +UINT8 scsihle_device::scsibus_driveno(UINT8 drivesel) +{ + switch (drivesel) + { + case 0x01: return 0; + case 0x02: return 1; + case 0x04: return 2; + case 0x08: return 3; + case 0x10: return 4; + case 0x20: return 5; + case 0x40: return 6; + case 0x80: return 7; + default: return 0; + } +} + +void scsihle_device::scsi_change_phase(UINT8 newphase) +{ + LOG(1,"scsi_change_phase() from=%s, to=%s\n",phasenames[m_phase],phasenames[newphase]); + + m_phase=newphase; + cmd_idx=0; + data_idx=0; + + switch(m_phase) + { + case SCSI_PHASE_BUS_FREE: + output_bsy(0); + // sel + output_cd(0); + output_io(0); + output_msg(0); + output_req(0); + // ack + // atn + // rst + data_out(0); + LOG(1,"SCSIBUS: done\n\n"); + break; + + case SCSI_PHASE_COMMAND: + output_cd(1); + output_io(0); + output_msg(0); + scsi_out_req_delay(1); + data_out(0); + LOG(1,"\nSCSIBUS: Command begin\n"); + break; + + case SCSI_PHASE_DATAOUT: + output_cd(0); + output_io(0); + output_msg(0); + scsi_out_req_delay(1); + data_out(0); + break; + + case SCSI_PHASE_DATAIN: + output_cd(0); + output_io(1); + output_msg(0); + scsi_out_req_delay(1); + break; + + case SCSI_PHASE_STATUS: + output_cd(1); + output_io(1); + output_msg(0); + scsi_out_req_delay(1); + data_out(m_status_code); + break; + + case SCSI_PHASE_MESSAGE_OUT: + output_cd(1); + output_io(0); + output_msg(1); + scsi_out_req_delay(1); + data_out(0); + break; + + case SCSI_PHASE_MESSAGE_IN: + output_cd(1); + output_io(1); + output_msg(1); + scsi_out_req_delay(1); + data_out(0); // no errors for the time being ! + break; + } +} + +WRITE_LINE_MEMBER( scsihle_device::input_sel ) +{ +// printf( "sel %d %d %02x\n", state, m_phase, m_input_data ); + switch (m_phase) + { + case SCSI_PHASE_BUS_FREE: + // Note this assumes we only have one initiator and therefore + // only one line active. + if (scsibus_driveno(m_input_data) == scsiID) + { + void *hdfile = NULL; + // Check to see if device had image file mounted, if not, do not set busy, + // and stay busfree. + GetDevice(&hdfile); + if (hdfile != NULL) + { + if (!state) + { + scsi_change_phase(SCSI_PHASE_COMMAND); + } + else + { + sel_timer->adjust(attotime::from_nsec(BSY_DELAY_NS),1); + } + } + } + break; + } +} + +WRITE_LINE_MEMBER( scsihle_device::input_ack ) +{ + switch (m_phase) + { + case SCSI_PHASE_COMMAND: + if (!state) + { + command[ cmd_idx++ ] = m_input_data; + + // If the command is ready go and execute it + if (cmd_idx == get_scsi_cmd_len(command[0])) + { + scsibus_exec_command(); + } + else + { + scsi_out_req_delay(1); + } + } + else + { + scsi_out_req_delay(0); + } + break; + + case SCSI_PHASE_DATAIN: + if (!state) + { + // check to see if we have reached the end of the block buffer + // and that there is more data to read from the scsi disk + if (data_idx == m_sector_bytes && bytes_left > 0) + { + scsibus_read_data(); + scsi_out_req_delay(1); + } + else if (data_idx == data_last && bytes_left == 0) + { + scsi_change_phase(SCSI_PHASE_STATUS); + } + else + { + data_out(buffer[data_idx++]); + scsi_out_req_delay(1); + } + } + else + { + scsi_out_req_delay(0); + } + break; + + case SCSI_PHASE_DATAOUT: + if (!state) + { + //LOG(1,"SCSIBUS:bytes_left=%02X data_idx=%02X\n",bytes_left,data_idx); + buffer[data_idx++] = m_input_data; + + if (IS_COMMAND(SCSI_CMD_FORMAT_UNIT)) + { + // If we have the first byte, then cancel the dataout timout + if (data_idx == 1) + dataout_timer->adjust(attotime::never); + + // When we have the first 3 bytes, calculate how many more are in the + // bad block list. + if (data_idx == 3) + { + bytes_left += ((buffer[2]<<8) + buffer[3]); + LOG(1, "format_unit reading an extra %d bytes\n", bytes_left - 4); + dump_data_bytes(4); + } + } + + // If the data buffer is full flush it to the SCSI disk + + data_last = (bytes_left >= m_sector_bytes) ? m_sector_bytes : bytes_left; + + if (data_idx == data_last) + scsibus_write_data(); + + if (data_idx == 0 && bytes_left == 0) + { + scsi_change_phase(SCSI_PHASE_STATUS); + } + else + { + scsi_out_req_delay(1); + } + } + else + { + scsi_out_req_delay(0); + } + break; + + case SCSI_PHASE_STATUS: + if (!state) + { + if (cmd_idx > 0) + { + scsi_change_phase(SCSI_PHASE_MESSAGE_IN); + } + else + { + scsi_out_req_delay(1); + } + } + else + { + cmd_idx++; + scsi_out_req_delay(0); + } + break; + + case SCSI_PHASE_MESSAGE_IN: + if (!state) + { + if (cmd_idx > 0) + { + if (is_linked) + scsi_change_phase(SCSI_PHASE_COMMAND); + else + scsi_change_phase(SCSI_PHASE_BUS_FREE); + } + else + { + scsi_out_req_delay(1); + } + } + else + { + cmd_idx++; + scsi_out_req_delay(0); + } + break; + } +} + +WRITE_LINE_MEMBER( scsihle_device::input_rst ) +{ + if (state) + { + scsi_change_phase(SCSI_PHASE_BUS_FREE); + cmd_idx = 0; + data_idx = 0; + is_linked = 0; + } +} + +// get the length of a SCSI command based on it's command byte type +int scsihle_device::get_scsi_cmd_len(int cbyte) +{ + int group; + + group = (cbyte>>5) & 7; + + if (group == 0 || group == 3 || group == 6 || group == 7) return 6; + if (group == 1 || group == 2) return 10; + if (group == 5) return 12; + + fatalerror("scsihle: Unknown SCSI command group %d, command byte=%02X\n", group,cbyte); + + // never executed + //return 6; +} diff --git a/src/devices/bus/scsi/scsihle.h b/src/devices/bus/scsi/scsihle.h new file mode 100644 index 00000000000..5f638149ffd --- /dev/null +++ b/src/devices/bus/scsi/scsihle.h @@ -0,0 +1,92 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/* + +scsihle.h + +Base class for HLE'd SCSI devices. + +*/ + +#ifndef _SCSIHLE_H_ +#define _SCSIHLE_H_ + +#include "scsi.h" +#include "machine/t10spc.h" + +INPUT_PORTS_EXTERN( scsihle ); + +class scsihle_device : public device_t, + public scsi_port_interface, + public virtual t10spc +{ +public: + // construction/destruction + scsihle_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + virtual int GetDeviceID(); // hack for legacy_scsi_host_adapter::get_device + + virtual DECLARE_WRITE_LINE_MEMBER( input_sel ); + virtual DECLARE_WRITE_LINE_MEMBER( input_ack ); + virtual DECLARE_WRITE_LINE_MEMBER( input_rst ); + virtual DECLARE_WRITE_LINE_MEMBER( input_data0 ) { if (state) m_input_data |= 0x01; else m_input_data &= ~0x01; } + virtual DECLARE_WRITE_LINE_MEMBER( input_data1 ) { if (state) m_input_data |= 0x02; else m_input_data &= ~0x02; } + virtual DECLARE_WRITE_LINE_MEMBER( input_data2 ) { if (state) m_input_data |= 0x04; else m_input_data &= ~0x04; } + virtual DECLARE_WRITE_LINE_MEMBER( input_data3 ) { if (state) m_input_data |= 0x08; else m_input_data &= ~0x08; } + virtual DECLARE_WRITE_LINE_MEMBER( input_data4 ) { if (state) m_input_data |= 0x10; else m_input_data &= ~0x10; } + virtual DECLARE_WRITE_LINE_MEMBER( input_data5 ) { if (state) m_input_data |= 0x20; else m_input_data &= ~0x20; } + virtual DECLARE_WRITE_LINE_MEMBER( input_data6 ) { if (state) m_input_data |= 0x40; else m_input_data &= ~0x40; } + virtual DECLARE_WRITE_LINE_MEMBER( input_data7 ) { if (state) m_input_data |= 0x80; else m_input_data &= ~0x80; } + +protected: + // device-level overrides + virtual ioport_constructor device_input_ports() const; + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + +private: + required_ioport m_scsi_id; + void data_out(UINT8 data); + void scsi_out_req_delay(UINT8 state); + void scsi_change_phase(UINT8 newphase); + int get_scsi_cmd_len(int cbyte); + UINT8 scsibus_driveno(UINT8 drivesel); + void scsibus_read_data(); + void scsibus_write_data(); + void scsibus_exec_command(); + void dump_command_bytes(); + void dump_data_bytes(int count); + void dump_bytes(UINT8 *buff, int count); + + emu_timer *req_timer; + emu_timer *sel_timer; + emu_timer *dataout_timer; + + UINT8 cmd_idx; + UINT8 is_linked; + + UINT8 buffer[ 1024 ]; + UINT16 data_idx; + int bytes_left; + int data_last; + + int scsiID; + UINT8 m_input_data; +}; + +extern const input_device_default DEVICE_INPUT_DEFAULTS_NAME(SCSI_ID_0)[]; +extern const input_device_default DEVICE_INPUT_DEFAULTS_NAME(SCSI_ID_1)[]; +extern const input_device_default DEVICE_INPUT_DEFAULTS_NAME(SCSI_ID_2)[]; +extern const input_device_default DEVICE_INPUT_DEFAULTS_NAME(SCSI_ID_3)[]; +extern const input_device_default DEVICE_INPUT_DEFAULTS_NAME(SCSI_ID_4)[]; +extern const input_device_default DEVICE_INPUT_DEFAULTS_NAME(SCSI_ID_5)[]; +extern const input_device_default DEVICE_INPUT_DEFAULTS_NAME(SCSI_ID_6)[]; +extern const input_device_default DEVICE_INPUT_DEFAULTS_NAME(SCSI_ID_7)[]; + +#define MCFG_SCSIDEV_ADD(_tag, _option, _type, _id) \ + MCFG_DEVICE_MODIFY(_tag ) \ + MCFG_SLOT_OPTION_ADD( _option, _type ) \ + MCFG_SLOT_OPTION_DEVICE_INPUT_DEFAULTS( _option, _id ) \ + MCFG_SLOT_DEFAULT_OPTION( _option ) +#endif diff --git a/src/devices/bus/scv/rom.c b/src/devices/bus/scv/rom.c new file mode 100644 index 00000000000..ce71249d453 --- /dev/null +++ b/src/devices/bus/scv/rom.c @@ -0,0 +1,205 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + Epoch Super Cassette Vision cart emulation + + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "rom.h" + + +//------------------------------------------------- +// scv_rom_device - constructor +//------------------------------------------------- + +const device_type SCV_ROM8K = &device_creator; +const device_type SCV_ROM16K = &device_creator; +const device_type SCV_ROM32K = &device_creator; +const device_type SCV_ROM32K_RAM8K = &device_creator; +const device_type SCV_ROM64K = &device_creator; +const device_type SCV_ROM128K = &device_creator; +const device_type SCV_ROM128K_RAM4K = &device_creator; + + +scv_rom8_device::scv_rom8_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_scv_cart_interface( mconfig, *this ) +{ +} + +scv_rom8_device::scv_rom8_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, SCV_ROM8K, "SCV 8K Carts", tag, owner, clock, "scv_rom8", __FILE__), + device_scv_cart_interface( mconfig, *this ) +{ +} + +scv_rom16_device::scv_rom16_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : scv_rom8_device(mconfig, SCV_ROM16K, "SCV 16K Carts", tag, owner, clock, "scv_rom16", __FILE__) +{ +} + +scv_rom32_device::scv_rom32_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : scv_rom8_device(mconfig, SCV_ROM32K, "SCV 32K Carts", tag, owner, clock, "scv_rom32", __FILE__) +{ +} + +scv_rom32ram8_device::scv_rom32ram8_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : scv_rom8_device(mconfig, SCV_ROM32K_RAM8K, "SCV 32K + RAM 8K Carts", tag, owner, clock, "scv_rom32_ram8", __FILE__) +{ +} + +scv_rom64_device::scv_rom64_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : scv_rom8_device(mconfig, SCV_ROM16K, "SCV 64K Carts", tag, owner, clock, "scv_rom64", __FILE__) +{ +} + +scv_rom128_device::scv_rom128_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : scv_rom8_device(mconfig, SCV_ROM32K, "SCV 128K Carts", tag, owner, clock, "scv_rom128", __FILE__) +{ +} + +scv_rom128ram4_device::scv_rom128ram4_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : scv_rom8_device(mconfig, SCV_ROM128K_RAM4K, "SCV 128K + RAM 4K Carts", tag, owner, clock, "scv_rom128_ram4", __FILE__) +{ +} + + +//------------------------------------------------- +// mapper specific start/reset +//------------------------------------------------- + +void scv_rom32ram8_device::device_start() +{ + save_item(NAME(m_ram_enabled)); +} + +void scv_rom32ram8_device::device_reset() +{ + m_ram_enabled = 1; +} + + +void scv_rom64_device::device_start() +{ + save_item(NAME(m_bank_base)); +} + +void scv_rom64_device::device_reset() +{ + m_bank_base = 0; +} + + +void scv_rom128_device::device_start() +{ + save_item(NAME(m_bank_base)); +} + +void scv_rom128_device::device_reset() +{ + m_bank_base = 0; +} + + +void scv_rom128ram4_device::device_start() +{ + save_item(NAME(m_bank_base)); + save_item(NAME(m_ram_enabled)); +} + +void scv_rom128ram4_device::device_reset() +{ + m_bank_base = 0; + m_ram_enabled = 1; +} + + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +READ8_MEMBER(scv_rom8_device::read_cart) +{ + return m_rom[offset & 0x1fff]; +} + + +READ8_MEMBER(scv_rom16_device::read_cart) +{ + return m_rom[offset & 0x3fff]; +} + + +READ8_MEMBER(scv_rom32_device::read_cart) +{ + return m_rom[offset]; +} + + +READ8_MEMBER(scv_rom32ram8_device::read_cart) +{ + if (m_ram_enabled && offset >= 0x6000) + return m_ram[offset & 0x1fff]; + + return m_rom[offset]; +} + +WRITE8_MEMBER(scv_rom32ram8_device::write_cart) +{ + if (m_ram_enabled && offset >= 0x6000) + m_ram[offset & 0x1fff] = data; +} + +WRITE8_MEMBER(scv_rom32ram8_device::write_bank) +{ + m_ram_enabled = BIT(data, 5); +} + + +READ8_MEMBER(scv_rom64_device::read_cart) +{ + return m_rom[offset + (m_bank_base * 0x8000)]; +} + +WRITE8_MEMBER(scv_rom64_device::write_bank) +{ + m_bank_base = BIT(data, 5); +} + + +READ8_MEMBER(scv_rom128_device::read_cart) +{ + return m_rom[offset + (m_bank_base * 0x8000)]; +} + +WRITE8_MEMBER(scv_rom128_device::write_bank) +{ + m_bank_base = (data >> 5) & 0x03; +} + + +READ8_MEMBER(scv_rom128ram4_device::read_cart) +{ + if (m_ram_enabled && offset >= 0x7000) + return m_ram[offset & 0xfff]; + + return m_rom[offset + (m_bank_base * 0x8000)]; +} + +WRITE8_MEMBER(scv_rom128ram4_device::write_cart) +{ + if (m_ram_enabled && offset >= 0x7000) + m_ram[offset & 0xfff] = data; +} + +WRITE8_MEMBER(scv_rom128ram4_device::write_bank) +{ + m_bank_base = (data >> 5) & 0x03; + m_ram_enabled = BIT(data, 6); +} diff --git a/src/devices/bus/scv/rom.h b/src/devices/bus/scv/rom.h new file mode 100644 index 00000000000..412f72acfef --- /dev/null +++ b/src/devices/bus/scv/rom.h @@ -0,0 +1,151 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __SCV_ROM_H +#define __SCV_ROM_H + +#include "slot.h" + + +// ======================> scv_rom8_device + +class scv_rom8_device : public device_t, + public device_scv_cart_interface +{ +public: + // construction/destruction + scv_rom8_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + scv_rom8_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start() {} + virtual void device_reset() {} + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_cart); +}; + +// ======================> scv_rom16_device + +class scv_rom16_device : public scv_rom8_device +{ +public: + // construction/destruction + scv_rom16_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_cart); +}; + + +// ======================> scv_rom32_device + +class scv_rom32_device : public scv_rom8_device +{ +public: + // construction/destruction + scv_rom32_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_cart); +}; + + +// ======================> scv_rom32ram8_device + +class scv_rom32ram8_device : public scv_rom8_device +{ +public: + // construction/destruction + scv_rom32ram8_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_cart); + virtual DECLARE_WRITE8_MEMBER(write_cart); + virtual DECLARE_WRITE8_MEMBER(write_bank); + +private: + UINT8 m_ram_enabled; +}; + + +// ======================> scv_rom64_device + +class scv_rom64_device : public scv_rom8_device +{ +public: + // construction/destruction + scv_rom64_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_cart); + virtual DECLARE_WRITE8_MEMBER(write_bank); + +private: + UINT8 m_bank_base; +}; + + +// ======================> scv_rom128_device + +class scv_rom128_device : public scv_rom8_device +{ +public: + // construction/destruction + scv_rom128_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_cart); + virtual DECLARE_WRITE8_MEMBER(write_bank); + +private: + UINT8 m_bank_base; +}; + + +// ======================> scv_rom128ram4_device + +class scv_rom128ram4_device : public scv_rom8_device +{ +public: + // construction/destruction + scv_rom128ram4_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_cart); + virtual DECLARE_WRITE8_MEMBER(write_cart); + virtual DECLARE_WRITE8_MEMBER(write_bank); + +private: + UINT8 m_bank_base, m_ram_enabled; +}; + + + +// device type definition +extern const device_type SCV_ROM8K; +extern const device_type SCV_ROM16K; +extern const device_type SCV_ROM32K; +extern const device_type SCV_ROM32K_RAM8K; +extern const device_type SCV_ROM64K; +extern const device_type SCV_ROM128K; +extern const device_type SCV_ROM128K_RAM4K; + + + +#endif diff --git a/src/devices/bus/scv/slot.c b/src/devices/bus/scv/slot.c new file mode 100644 index 00000000000..12ecf7c4db9 --- /dev/null +++ b/src/devices/bus/scv/slot.c @@ -0,0 +1,317 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + Epoch Super Cassette Vision cart emulation + (through slot devices) + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "slot.h" + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type SCV_CART_SLOT = &device_creator; + +//************************************************************************** +// SCV cartridges Interface +//************************************************************************** + +//------------------------------------------------- +// device_scv_cart_interface - constructor +//------------------------------------------------- + +device_scv_cart_interface::device_scv_cart_interface(const machine_config &mconfig, device_t &device) + : device_slot_card_interface(mconfig, device), + m_rom(NULL), + m_rom_size(0) +{ +} + + +//------------------------------------------------- +// ~device_scv_cart_interface - destructor +//------------------------------------------------- + +device_scv_cart_interface::~device_scv_cart_interface() +{ +} + +//------------------------------------------------- +// rom_alloc - alloc the space for the cart +//------------------------------------------------- + +void device_scv_cart_interface::rom_alloc(UINT32 size, const char *tag) +{ + if (m_rom == NULL) + { + m_rom = device().machine().memory().region_alloc(std::string(tag).append(SCVSLOT_ROM_REGION_TAG).c_str(), size, 1, ENDIANNESS_LITTLE)->base(); + m_rom_size = size; + } +} + + +//------------------------------------------------- +// ram_alloc - alloc the space for the ram +//------------------------------------------------- + +void device_scv_cart_interface::ram_alloc(UINT32 size) +{ + m_ram.resize(size); +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// scv_cart_slot_device - constructor +//------------------------------------------------- +scv_cart_slot_device::scv_cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, SCV_CART_SLOT, "SCV Cartridge Slot", tag, owner, clock, "scv_cart_slot", __FILE__), + device_image_interface(mconfig, *this), + device_slot_interface(mconfig, *this), + m_type(SCV_8K) +{ +} + + +//------------------------------------------------- +// scv_cart_slot_device - destructor +//------------------------------------------------- + +scv_cart_slot_device::~scv_cart_slot_device() +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void scv_cart_slot_device::device_start() +{ + m_cart = dynamic_cast(get_card_device()); +} + +//------------------------------------------------- +// device_config_complete - perform any +// operations now that the configuration is +// complete +//------------------------------------------------- + +void scv_cart_slot_device::device_config_complete() +{ + // set brief and instance name + update_names(); +} + + +//------------------------------------------------- +// SCV PCB +//------------------------------------------------- + +struct scv_slot +{ + int pcb_id; + const char *slot_option; +}; + +// Here, we take the feature attribute from .xml (i.e. the PCB name) and we assign a unique ID to it +static const scv_slot slot_list[] = +{ + { SCV_8K, "rom8k" }, + { SCV_16K, "rom16k" }, + { SCV_32K, "rom32k" }, + { SCV_32K_RAM, "rom32k_ram" }, + { SCV_64K, "rom64k" }, + { SCV_128K, "rom128k" }, + { SCV_128K_RAM, "rom128k_ram" } +}; + +static int scv_get_pcb_id(const char *slot) +{ + for (int i = 0; i < ARRAY_LENGTH(slot_list); i++) + { + if (!core_stricmp(slot_list[i].slot_option, slot)) + return slot_list[i].pcb_id; + } + + return 0; +} + +static const char *scv_get_slot(int type) +{ + for (int i = 0; i < ARRAY_LENGTH(slot_list); i++) + { + if (slot_list[i].pcb_id == type) + return slot_list[i].slot_option; + } + + return "rom8k"; +} + + +/*------------------------------------------------- + call load + -------------------------------------------------*/ + +bool scv_cart_slot_device::call_load() +{ + if (m_cart) + { + UINT8 *ROM; + UINT32 len = (software_entry() == NULL) ? length() : get_software_region_length("rom"); + bool has_ram = (software_entry() != NULL) && get_software_region("ram"); + + if (len > 0x20000) + { + seterror(IMAGE_ERROR_UNSPECIFIED, "Unsupported cartridge size"); + return IMAGE_INIT_FAIL; + } + + m_cart->rom_alloc(len, tag()); + if (has_ram) + m_cart->ram_alloc(get_software_region_length("ram")); + + ROM = m_cart->get_rom_base(); + + if (software_entry() == NULL) + fread(ROM, len); + else + memcpy(ROM, get_software_region("rom"), len); + + if (software_entry() == NULL) + m_type = get_cart_type(ROM, len); + else + { + const char *pcb_name = get_feature("slot"); + if (pcb_name) + m_type = scv_get_pcb_id(pcb_name); + } + + // for the moment we only support RAM from softlist and in the following configurations + // 1) 32K ROM + 8K RAM; 2) 128K ROM + 4K RAM + if (m_type == SCV_32K && has_ram) + m_type = SCV_32K_RAM; + if (m_type == SCV_128K && has_ram) + m_type = SCV_128K_RAM; + + //printf("Type: %s\n", scv_get_slot(m_type)); + + return IMAGE_INIT_PASS; + } + + return IMAGE_INIT_PASS; +} + + +/*------------------------------------------------- + call softlist load + -------------------------------------------------*/ + +bool scv_cart_slot_device::call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry) +{ + load_software_part_region(*this, swlist, swname, start_entry); + return TRUE; +} + + + +/*------------------------------------------------- + get_cart_type - code to detect NVRAM type from + fullpath + -------------------------------------------------*/ + +int scv_cart_slot_device::get_cart_type(UINT8 *ROM, UINT32 len) +{ + int type = SCV_8K; + + // TO DO: is there any way to identify carts with RAM?!? + switch (len) + { + case 0x2000: + type = SCV_8K; + break; + case 0x4000: + type = SCV_16K; + break; + case 0x8000: + type = SCV_32K; + break; + case 0x10000: + type = SCV_64K; + break; + case 0x20000: + type = SCV_128K; + break; + } + + return type; +} + + +/*------------------------------------------------- + get default card software + -------------------------------------------------*/ + +void scv_cart_slot_device::get_default_card_software(std::string &result) +{ + if (open_image_file(mconfig().options())) + { + const char *slot_string = "rom8k"; + UINT32 len = core_fsize(m_file); + dynamic_buffer rom(len); + int type; + + core_fread(m_file, &rom[0], len); + + type = get_cart_type(&rom[0], len); + slot_string = scv_get_slot(type); + + //printf("type: %s\n", slot_string); + clear(); + + result.assign(slot_string); + return; + } + + software_get_default_slot(result, "rom8k"); +} + +/*------------------------------------------------- + read + -------------------------------------------------*/ + +READ8_MEMBER(scv_cart_slot_device::read_cart) +{ + if (m_cart) + return m_cart->read_cart(space, offset); + else + return 0xff; +} + +/*------------------------------------------------- + write + -------------------------------------------------*/ + +WRITE8_MEMBER(scv_cart_slot_device::write_cart) +{ + if (m_cart) + m_cart->write_cart(space, offset, data); +} + + +/*------------------------------------------------- + write_bank + -------------------------------------------------*/ + +WRITE8_MEMBER(scv_cart_slot_device::write_bank) +{ + if (m_cart) + m_cart->write_bank(space, offset, data); +} diff --git a/src/devices/bus/scv/slot.h b/src/devices/bus/scv/slot.h new file mode 100644 index 00000000000..dea4af488fb --- /dev/null +++ b/src/devices/bus/scv/slot.h @@ -0,0 +1,119 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __SCV_SLOT_H +#define __SCV_SLOT_H + +/*************************************************************************** + TYPE DEFINITIONS + ***************************************************************************/ + + +/* PCB */ +enum +{ + SCV_8K = 0, + SCV_16K, + SCV_32K, + SCV_32K_RAM, + SCV_64K, + SCV_128K, + SCV_128K_RAM +}; + + +// ======================> device_scv_cart_interface + +class device_scv_cart_interface : public device_slot_card_interface +{ +public: + // construction/destruction + device_scv_cart_interface(const machine_config &mconfig, device_t &device); + virtual ~device_scv_cart_interface(); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_cart) { return 0xff; } + virtual DECLARE_WRITE8_MEMBER(write_cart) {} + virtual DECLARE_WRITE8_MEMBER(write_bank) {} + + void rom_alloc(UINT32 size, const char *tag); + void ram_alloc(UINT32 size); + UINT8* get_rom_base() { return m_rom; } + UINT8* get_ram_base() { return &m_ram[0]; } + UINT32 get_rom_size() { return m_rom_size; } + UINT32 get_ram_size() { return m_ram.size(); } + + void save_ram() { device().save_item(NAME(m_ram)); } + +protected: + // internal state + UINT8 *m_rom; + UINT32 m_rom_size; + dynamic_buffer m_ram; +}; + + +// ======================> scv_cart_slot_device + +class scv_cart_slot_device : public device_t, + public device_image_interface, + public device_slot_interface +{ +public: + // construction/destruction + scv_cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual ~scv_cart_slot_device(); + + // device-level overrides + virtual void device_start(); + virtual void device_config_complete(); + + // image-level overrides + virtual bool call_load(); + virtual void call_unload() {} + virtual bool call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry); + + int get_type() { return m_type; } + int get_cart_type(UINT8 *ROM, UINT32 len); + + void save_ram() { if (m_cart && m_cart->get_ram_size()) m_cart->save_ram(); } + + virtual iodevice_t image_type() const { return IO_CARTSLOT; } + virtual bool is_readable() const { return 1; } + virtual bool is_writeable() const { return 0; } + virtual bool is_creatable() const { return 0; } + virtual bool must_be_loaded() const { return 0; } + virtual bool is_reset_on_load() const { return 1; } + virtual const option_guide *create_option_guide() const { return NULL; } + virtual const char *image_interface() const { return "scv_cart"; } + virtual const char *file_extensions() const { return "bin"; } + + // slot interface overrides + virtual void get_default_card_software(std::string &result); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_cart); + virtual DECLARE_WRITE8_MEMBER(write_cart); + virtual DECLARE_WRITE8_MEMBER(write_bank); + +protected: + + int m_type; + device_scv_cart_interface* m_cart; +}; + + + +// device type definition +extern const device_type SCV_CART_SLOT; + + +/*************************************************************************** + DEVICE CONFIGURATION MACROS + ***************************************************************************/ + +#define SCVSLOT_ROM_REGION_TAG ":cart:rom" + +#define MCFG_SCV_CARTRIDGE_ADD(_tag,_slot_intf,_def_slot) \ + MCFG_DEVICE_ADD(_tag, SCV_CART_SLOT, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) +#endif diff --git a/src/devices/bus/sega8/ccatch.c b/src/devices/bus/sega8/ccatch.c new file mode 100644 index 00000000000..ec42d1304b4 --- /dev/null +++ b/src/devices/bus/sega8/ccatch.c @@ -0,0 +1,63 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + SG-1000 Card Catcher emulation + + Sega Card Catcher is a passthrough adapter for + SG-1000 to load games in MyCard format into the + main cartslot + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "ccatch.h" + + +//------------------------------------------------- +// constructors +//------------------------------------------------- + +const device_type SEGA8_ROM_CARDCATCH = &device_creator; + + + +sega8_cardcatch_device::sega8_cardcatch_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : sega8_rom_device(mconfig, SEGA8_ROM_CARDCATCH, "SG-1000 Card Catcher Cart", tag, owner, clock, "sega8_ccatch", __FILE__), + m_card(*this, "cardslot") +{ +} + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +READ8_MEMBER(sega8_cardcatch_device::read_cart) +{ + if (offset < 0x8000) + return m_card->read_cart(space, offset); + + return 0xff; +} + +WRITE8_MEMBER(sega8_cardcatch_device::write_cart) +{ + // this should never happen, because there is no RAM on cards + if (offset < 0x8000) + logerror("Attempt to write to MyCard\n"); +} + +static SLOT_INTERFACE_START(sg1000_card) + SLOT_INTERFACE_INTERNAL("rom", SEGA8_ROM_STD) +SLOT_INTERFACE_END + +static MACHINE_CONFIG_FRAGMENT( sub_slot ) + MCFG_SG1000_CARD_ADD("cardslot", sg1000_card, NULL) +MACHINE_CONFIG_END + +machine_config_constructor sega8_cardcatch_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( sub_slot ); +} diff --git a/src/devices/bus/sega8/ccatch.h b/src/devices/bus/sega8/ccatch.h new file mode 100644 index 00000000000..ece120c0a57 --- /dev/null +++ b/src/devices/bus/sega8/ccatch.h @@ -0,0 +1,35 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __SEGA8_CCATCH_H +#define __SEGA8_CCATCH_H + +#include "sega8_slot.h" +#include "rom.h" + +// ======================> sega8_cardcatch_device + +class sega8_cardcatch_device : public sega8_rom_device +{ +public: + // construction/destruction + sega8_cardcatch_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_cart); + virtual DECLARE_WRITE8_MEMBER(write_cart); + virtual DECLARE_WRITE8_MEMBER(write_mapper) {} + + virtual machine_config_constructor device_mconfig_additions() const; + +protected: + required_device m_card; +}; + + + + + +// device type definition +extern const device_type SEGA8_ROM_CARDCATCH; + +#endif diff --git a/src/devices/bus/sega8/mgear.c b/src/devices/bus/sega8/mgear.c new file mode 100644 index 00000000000..250eb58e13a --- /dev/null +++ b/src/devices/bus/sega8/mgear.c @@ -0,0 +1,46 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + Master Gear Adapter emulation + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "mgear.h" + + +//------------------------------------------------- +// constructors +//------------------------------------------------- + +const device_type SEGA8_ROM_MGEAR = &device_creator; + +sega8_mgear_device::sega8_mgear_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : sega8_rom_device(mconfig, SEGA8_ROM_MGEAR, "Master Gear Adapter", tag, owner, clock, "sega8_mgear", __FILE__), + m_subslot(*this, "subslot") +{ +} + + +void sega8_mgear_device::device_start() +{ +} + +void sega8_mgear_device::device_reset() +{ +} + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +static MACHINE_CONFIG_FRAGMENT( sub_slot ) + MCFG_SMS_CARTRIDGE_ADD("subslot", sms_cart, NULL) +MACHINE_CONFIG_END + +machine_config_constructor sega8_mgear_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( sub_slot ); +} diff --git a/src/devices/bus/sega8/mgear.h b/src/devices/bus/sega8/mgear.h new file mode 100644 index 00000000000..2e4afa40466 --- /dev/null +++ b/src/devices/bus/sega8/mgear.h @@ -0,0 +1,39 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __SEGA8_MGEAR_H +#define __SEGA8_MGEAR_H + +#include "sega8_slot.h" +#include "rom.h" + + +// ======================> sega8_mgear_device + +class sega8_mgear_device : public sega8_rom_device +{ +public: + // construction/destruction + sega8_mgear_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_cart) { return m_subslot->read_cart(space, offset); } + virtual DECLARE_WRITE8_MEMBER(write_cart) { m_subslot->write_cart(space, offset, data); } + virtual DECLARE_WRITE8_MEMBER(write_mapper) { m_subslot->write_mapper(space, offset, data); } + virtual int get_lphaser_xoffs() { return m_subslot->m_cart ? m_subslot->m_cart->get_lphaser_xoffs() : -1; } + + virtual machine_config_constructor device_mconfig_additions() const; + +protected: + required_device m_subslot; +}; + + +// device type definition +extern const device_type SEGA8_ROM_MGEAR; + + +#endif diff --git a/src/devices/bus/sega8/rom.c b/src/devices/bus/sega8/rom.c new file mode 100644 index 00000000000..3770560806d --- /dev/null +++ b/src/devices/bus/sega8/rom.c @@ -0,0 +1,940 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + Sega 8-bit cart emulation (for Master System, GameGear and SG-1000) + + TODO: implement proper ROM & RAM mirroring when the cart size is not a power of 2K (e.g. 24K or 48K) + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "rom.h" + + +//------------------------------------------------- +// constructors +//------------------------------------------------- + +// Base cart type shared across SG-1000, SG-1000 Mark II, SG-1000 Mark III, SMS, GG +// even if in sg1000 rom banks are never changed and ram is never enabled +const device_type SEGA8_ROM_STD = &device_creator; + +// Specific SG-1000 MkI - MkII cart types +const device_type SEGA8_ROM_OTHELLO = &device_creator; +const device_type SEGA8_ROM_CASTLE = &device_creator; +const device_type SEGA8_ROM_BASIC_L3 = &device_creator; +const device_type SEGA8_ROM_MUSIC_EDITOR = &device_creator; +const device_type SEGA8_ROM_TEREBI = &device_creator; +const device_type SEGA8_ROM_DAHJEE_TYPEA = &device_creator; +const device_type SEGA8_ROM_DAHJEE_TYPEB = &device_creator; + +// Specific SG-1000 MkIII - SMS - GG cart types +const device_type SEGA8_ROM_EEPROM = &device_creator; +const device_type SEGA8_ROM_CODEMASTERS = &device_creator; +const device_type SEGA8_ROM_4PAK = &device_creator; +const device_type SEGA8_ROM_ZEMINA = &device_creator; +const device_type SEGA8_ROM_NEMESIS = &device_creator; +const device_type SEGA8_ROM_JANGGUN = &device_creator; +const device_type SEGA8_ROM_HICOM = &device_creator; +const device_type SEGA8_ROM_KOREAN = &device_creator; +const device_type SEGA8_ROM_KOREAN_NB = &device_creator; + + + +sega8_rom_device::sega8_rom_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_sega8_cart_interface( mconfig, *this ) +{ +} + +sega8_rom_device::sega8_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, SEGA8_ROM_STD, "Mark III, SMS & GG Carts", tag, owner, clock, "sega8_rom", __FILE__), + device_sega8_cart_interface( mconfig, *this ) +{ +} + + + + +sega8_othello_device::sega8_othello_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : sega8_rom_device(mconfig, SEGA8_ROM_OTHELLO, "SG-1000 Othello Cart", tag, owner, clock, "sega8_othello", __FILE__) +{ +} + + +sega8_castle_device::sega8_castle_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : sega8_rom_device(mconfig, SEGA8_ROM_CASTLE, "SG-1000 The Castle Cart", tag, owner, clock, "sega8_castle", __FILE__) +{ +} + + +sega8_basic_l3_device::sega8_basic_l3_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : sega8_rom_device(mconfig, SEGA8_ROM_BASIC_L3, "SC-3000 BASIC Level III Cart", tag, owner, clock, "sega8_basicl3", __FILE__) +{ +} + + +sega8_music_editor_device::sega8_music_editor_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : sega8_rom_device(mconfig, SEGA8_ROM_MUSIC_EDITOR, "SC-3000 Music Editor Cart", tag, owner, clock, "sega8_music", __FILE__) +{ +} + + +sega8_terebi_device::sega8_terebi_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : sega8_rom_device(mconfig, SEGA8_ROM_TEREBI, "SG-1000 Terebi Oekaki Cart", tag, owner, clock, "sega8_terebi", __FILE__), + m_tvdraw_x(*this, "TVDRAW_X"), + m_tvdraw_y(*this, "TVDRAW_Y"), + m_tvdraw_pen(*this, "TVDRAW_PEN") +{ +} + + +sega8_dahjee_typea_device::sega8_dahjee_typea_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : sega8_rom_device(mconfig, SEGA8_ROM_DAHJEE_TYPEA, "SG-1000 Dahjee RAM expansion + Cart (Type A)", tag, owner, clock, "sega8_dahjeea", __FILE__) +{ +} + + +sega8_dahjee_typeb_device::sega8_dahjee_typeb_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : sega8_rom_device(mconfig, SEGA8_ROM_DAHJEE_TYPEB, "SG-1000 Dahjee RAM expansion + Cart (Type B)", tag, owner, clock, "sega8_dahjeeb", __FILE__) +{ +} + + + + +sega8_eeprom_device::sega8_eeprom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, SEGA8_ROM_EEPROM, "GG Carts + EEPROM", tag, owner, clock, "sega8_eeprom", __FILE__), + device_sega8_cart_interface( mconfig, *this ), + m_eeprom(*this, "eeprom") +{ +} + + +sega8_codemasters_device::sega8_codemasters_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, SEGA8_ROM_CODEMASTERS, "Mark III, SMS & GG Codemasters Carts", tag, owner, clock, "sega8_codemasters", __FILE__), + device_sega8_cart_interface( mconfig, *this ) +{ +} + + +sega8_4pak_device::sega8_4pak_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : sega8_rom_device(mconfig, SEGA8_ROM_4PAK, "SMS 4-Pak Cart", tag, owner, clock, "sega8_4pak", __FILE__) +{ +} + + +sega8_zemina_device::sega8_zemina_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_sega8_cart_interface( mconfig, *this ) +{ +} + +sega8_zemina_device::sega8_zemina_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, SEGA8_ROM_ZEMINA, "SMS Zemina Carts", tag, owner, clock, "sega8_zemina", __FILE__), + device_sega8_cart_interface( mconfig, *this ) +{ +} + + +sega8_nemesis_device::sega8_nemesis_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : sega8_zemina_device(mconfig, SEGA8_ROM_NEMESIS, "SMS Nemesis Cart", tag, owner, clock, "sega8_nemesis", __FILE__) +{ +} + + +sega8_janggun_device::sega8_janggun_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, SEGA8_ROM_JANGGUN, "SMS Janggun Cart", tag, owner, clock, "sega8_janggun", __FILE__), + device_sega8_cart_interface( mconfig, *this ) +{ +} + + +sega8_hicom_device::sega8_hicom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : sega8_rom_device(mconfig, SEGA8_ROM_HICOM, "SMS Hi-Com Carts", tag, owner, clock, "sega8_hicom", __FILE__) +{ +} + + +sega8_korean_device::sega8_korean_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : sega8_rom_device(mconfig, SEGA8_ROM_KOREAN, "SMS Korean Carts", tag, owner, clock, "sega8_korean", __FILE__) +{ +} + + +sega8_korean_nb_device::sega8_korean_nb_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : sega8_rom_device(mconfig, SEGA8_ROM_KOREAN_NB, "SMS Korean No-Bank Mapper Carts", tag, owner, clock, "sega8_korean_nb", __FILE__) +{ +} + + +void sega8_rom_device::device_start() +{ + save_item(NAME(m_rom_bank_base)); + save_item(NAME(m_ram_base)); + save_item(NAME(m_ram_enabled)); +} + +void sega8_rom_device::device_reset() +{ + m_ram_base = 0; + m_ram_enabled = 0; +} + + + +void sega8_terebi_device::device_start() +{ + save_item(NAME(m_rom_bank_base)); + save_item(NAME(m_tvdraw_data)); +} + +void sega8_terebi_device::device_reset() +{ + m_tvdraw_data = 0; +} + + + + +void sega8_eeprom_device::device_start() +{ + save_item(NAME(m_rom_bank_base)); + save_item(NAME(m_93c46_enabled)); + save_item(NAME(m_93c46_lines)); +} + +void sega8_eeprom_device::device_reset() +{ + m_93c46_lines = 0; + m_93c46_enabled = 0; +} + + +void sega8_codemasters_device::device_start() +{ + save_item(NAME(m_rom_bank_base)); + save_item(NAME(m_ram_base)); + save_item(NAME(m_ram_enabled)); +} + +void sega8_codemasters_device::device_reset() +{ + m_ram_base = 0; + m_ram_enabled = 0; +} + +void sega8_4pak_device::device_start() +{ + save_item(NAME(m_rom_bank_base)); + save_item(NAME(m_reg)); +} + +void sega8_4pak_device::device_reset() +{ + memset(m_reg, 0, sizeof(m_reg)); +} + + +void sega8_zemina_device::device_start() +{ + save_item(NAME(m_rom_bank_base)); + save_item(NAME(m_ram_base)); + save_item(NAME(m_ram_enabled)); +} + +void sega8_zemina_device::device_reset() +{ + m_ram_base = 0; + m_ram_enabled = 0; +} + + +// initial bank setup needs to know how many 16K banks are available, so it needs to be called during cart loading... + +void sega8_rom_device::late_bank_setup() +{ + m_rom_bank_base[0] = 0; + m_rom_bank_base[1] = 1 % m_rom_page_count; + m_rom_bank_base[2] = 2 % m_rom_page_count; +} + +void sega8_eeprom_device::late_bank_setup() +{ + m_rom_bank_base[0] = 0; + m_rom_bank_base[1] = 1 % m_rom_page_count; + m_rom_bank_base[2] = 2 % m_rom_page_count; +} + +void sega8_codemasters_device::late_bank_setup() +{ + m_rom_bank_base[0] = 0; + m_rom_bank_base[1] = 1 % m_rom_page_count; + m_rom_bank_base[2] = 0; +} + +void sega8_zemina_device::late_bank_setup() +{ + m_rom_bank_base[0] = 0; + m_rom_bank_base[1] = 1 % (m_rom_page_count * 2); + m_rom_bank_base[2] = 2 % (m_rom_page_count * 2); + m_rom_bank_base[3] = 3 % (m_rom_page_count * 2); + m_rom_bank_base[4] = 4 % (m_rom_page_count * 2); + m_rom_bank_base[5] = 5 % (m_rom_page_count * 2); +} + +void sega8_nemesis_device::late_bank_setup() +{ + // Nemesis starts with last 8kb bank in page 0 (m_rom_page_count is for 16kb pages) + m_rom_bank_base[0] = m_rom_page_count * 2 - 1; + m_rom_bank_base[1] = 1 % (m_rom_page_count * 2); + m_rom_bank_base[2] = 2 % (m_rom_page_count * 2); + m_rom_bank_base[3] = 3 % (m_rom_page_count * 2); + m_rom_bank_base[4] = 4 % (m_rom_page_count * 2); + m_rom_bank_base[5] = 5 % (m_rom_page_count * 2); +} + +void sega8_janggun_device::late_bank_setup() +{ + m_rom_bank_base[0] = 0; + m_rom_bank_base[1] = 1; + m_rom_bank_base[2] = 2; + m_rom_bank_base[3] = 3; + m_rom_bank_base[4] = 4; + m_rom_bank_base[5] = 5; +} + +void sega8_hicom_device::late_bank_setup() +{ + m_rom_bank_base = 0; +} + +void sega8_korean_device::late_bank_setup() +{ + m_rom_bank_base[0] = 0; + m_rom_bank_base[1] = 1; + m_rom_bank_base[2] = 2; +} + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +/*------------------------------------------------- + + Base Sega 8bit carts, possibly with bankswitch + (only used by Mark III, SMS and GG games) + + -------------------------------------------------*/ + +READ8_MEMBER(sega8_rom_device::read_cart) +{ + int bank = offset / 0x4000; + + if (bank == 2 && !m_ram.empty() && m_ram_enabled) + return m_ram[(m_ram_base * 0x4000 + (offset & 0x3fff)) % m_ram.size()]; + + if (offset < 0x400) // first 1k is hardcoded + return m_rom[offset]; + + return m_rom[m_rom_bank_base[bank] * 0x4000 + (offset & 0x3fff)]; +} + +WRITE8_MEMBER(sega8_rom_device::write_cart) +{ + int bank = offset / 0x4000; + + if (bank == 2 && !m_ram.empty() && m_ram_enabled) + m_ram[(m_ram_base * 0x4000 + (offset & 0x3fff)) % m_ram.size()] = data; +} + +WRITE8_MEMBER(sega8_rom_device::write_mapper) +{ + switch (offset) + { + case 0: + if (data & 0x08) + { + // hack: if we were loading from fullpath (hence allowing m_late_battery_enable to be true) + // and the RAM is ever enabled by the game, then we save it at exit... + if (m_late_battery_enable) + has_battery = 1; + m_ram_enabled = 1; + m_ram_base = (data & 0x04) >> 2; + } + else + m_ram_enabled = 0; + break; + + case 1: // Select 16k ROM bank for 0000-3fff + case 2: // Select 16k ROM bank for 4000-7fff + case 3: // Select 16k ROM bank for 8000-bfff + m_rom_bank_base[offset - 1] = data % m_rom_page_count; + break; + } +} + + +/*------------------------------------------------- + + Othello is a SG-1000 game featuring 2K of + oncart RAM, mapped at 0x8000-0x9fff. + Is RAM mirrored? For now we assume so... + + -------------------------------------------------*/ + +READ8_MEMBER(sega8_othello_device::read_cart) +{ + // 8K of RAM sits in 0x8000-0x9fff + if (offset >= 0x8000 && offset < 0xa000) + return m_ram[offset & 0x7ff]; + + return m_rom[offset % m_rom_size]; +} + +WRITE8_MEMBER(sega8_othello_device::write_cart) +{ + // 2K of RAM sits in 0x8000-0x9fff + if (offset >= 0x8000 && offset < 0xa000) + m_ram[offset & 0x7ff] = data; +} + + +/*------------------------------------------------- + + The Castle is a SG-1000 game featuring 8K of + oncart RAM, mapped at 0x8000-0x9fff + + -------------------------------------------------*/ + +READ8_MEMBER(sega8_castle_device::read_cart) +{ + // 8K of RAM sits in 0x8000-0x9fff + if (offset >= 0x8000 && offset < 0xa000) + return m_ram[offset & 0x1fff]; + + return m_rom[offset % m_rom_size]; +} + +WRITE8_MEMBER(sega8_castle_device::write_cart) +{ + // 8K of RAM sits in 0x8000-0x9fff + if (offset >= 0x8000 && offset < 0xa000) + m_ram[offset & 0x1fff] = data; +} + + +/*------------------------------------------------- + + BASIC Level III cart featured 32K of + oncart RAM, mapped at 0x8000-0xffff? + + -------------------------------------------------*/ + +READ8_MEMBER(sega8_basic_l3_device::read_cart) +{ + // 8K of RAM sits in 0x8000-0x9fff + if (offset >= 0x8000) + return m_ram[offset & 0x3fff]; + + return m_rom[offset % m_rom_size]; +} + +WRITE8_MEMBER(sega8_basic_l3_device::write_cart) +{ + // 8K of RAM sits in 0x8000-0x9fff + if (offset >= 0x8000) + m_ram[offset & 0x3fff] = data; +} + +READ8_MEMBER(sega8_basic_l3_device::read_ram) +{ + return m_ram[0x4000 + (offset & 0x3fff)]; +} + +WRITE8_MEMBER(sega8_basic_l3_device::write_ram) +{ + m_ram[0x4000 + (offset & 0x3fff)] = data; +} + + +/*------------------------------------------------- + + Music Editor cart featured 10K of oncart RAM, mapped + in 0x8000-0x9fff and 0xc000-0xffff + + -------------------------------------------------*/ + +READ8_MEMBER(sega8_music_editor_device::read_cart) +{ + // 8K of RAM sits in 0x8000-0x9fff + if (offset >= 0x8000 && offset < 0xa000) + return m_ram[offset & 0x1fff]; + + return m_rom[offset % m_rom_size]; +} + +WRITE8_MEMBER(sega8_music_editor_device::write_cart) +{ + // 8K of RAM sits in 0x8000-0x9fff + if (offset >= 0x8000 && offset < 0xa000) + m_ram[offset & 0x1fff] = data; +} + +READ8_MEMBER(sega8_music_editor_device::read_ram) +{ + // 2K more of RAM sits in 0xc000-0xc3ff (and mirrored up to 0xffff) + // or should it simply go to the 2K of SC3000 RAM??? + return m_ram[0x2000 + (offset & 0x7ff)]; +} + +WRITE8_MEMBER(sega8_music_editor_device::write_ram) +{ + // 2K more of RAM sits in 0xc000-0xc3ff (and mirrored up to 0xffff) + // or should it simply go to the 2K of SC3000 RAM??? + m_ram[0x2000 + (offset & 0x7ff)] = data; +} + + +/*------------------------------------------------- + + SG-1000 Terebi Oekaki using a Tablet input device + + -------------------------------------------------*/ + +/* + + Terebi Oekaki (TV Draw) + + Address Access Bits + 7 6 5 4 3 2 1 0 + $6000 W - - - - - - - AXIS + $8000 R BUSY - - - - - - PRESS + $A000 R/W DATA + + AXIS: write 0 to select X axis, 1 to select Y axis. + BUSY: reads 1 when graphic board is busy sampling position, else 0. + PRESS: reads 0 when pen is touching graphic board, else 1. + DATA: when pen is touching graphic board, return 8-bit sample position for currently selected axis (X is in the 0-255 range, Y in the 0-191 range). Else, return 0. + + */ + + +READ8_MEMBER(sega8_terebi_device::read_cart) +{ + int bank = offset / 0x4000; + + if (offset == 0x8000) + return m_tvdraw_pen->read(); + if (offset == 0xa000) + return m_tvdraw_data; + + return m_rom[m_rom_bank_base[bank] * 0x4000 + (offset & 0x3fff)]; +} + +WRITE8_MEMBER(sega8_terebi_device::write_cart) +{ + switch (offset) + { + case 0x6000: + if (data & 0x01) + { + m_tvdraw_data = m_tvdraw_x->read(); + + if (m_tvdraw_data < 4) m_tvdraw_data = 4; + if (m_tvdraw_data > 251) m_tvdraw_data = 251; + } + else + m_tvdraw_data = m_tvdraw_y->read() + 0x20; + break; + case 0xa000: + // effect unknown + break; + } +} + +static INPUT_PORTS_START( tvdraw ) + PORT_START("TVDRAW_X") + PORT_BIT( 0xff, 0x80, IPT_LIGHTGUN_X ) PORT_NAME("Tablet - X Axis") PORT_CROSSHAIR(X, 1.0, 0.0, 0) PORT_SENSITIVITY(50) PORT_KEYDELTA(10) PORT_PLAYER(1) + + PORT_START("TVDRAW_Y") + PORT_BIT( 0xff, 0x60, IPT_LIGHTGUN_Y ) PORT_NAME("Tablet - Y Axis") PORT_CROSSHAIR(Y, 1.0, 0.0, 0) PORT_MINMAX(0, 191) PORT_SENSITIVITY(50) PORT_KEYDELTA(10) PORT_PLAYER(1) + + PORT_START("TVDRAW_PEN") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_NAME("Tablet - Pen") +INPUT_PORTS_END + +ioport_constructor sega8_terebi_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( tvdraw ); +} + + +/*------------------------------------------------- + + Dahjee carts were sold with a RAM expansion pass-through + cart (which we don't emulate separately for the + moment) which allowed to play on old SG1000 machines + some MSX conversions requiring more RAM than available + + Two kind of expansion existed (for different games), + one with 9K of RAM (Type A) and one with 8K of + RAM (Type B). + + -------------------------------------------------*/ + +// TYPE A +READ8_MEMBER(sega8_dahjee_typea_device::read_cart) +{ + // 8K of RAM sits in 0x2000-0x3fff + if (offset >= 0x2000 && offset < 0x4000) + return m_ram[offset & 0x1fff]; + + return m_rom[offset % m_rom_size]; +} + +WRITE8_MEMBER(sega8_dahjee_typea_device::write_cart) +{ + // 8K of RAM sits in 0x2000-0x3fff + if (offset >= 0x2000 && offset < 0x4000) + m_ram[offset & 0x1fff] = data; +} + +READ8_MEMBER(sega8_dahjee_typea_device::read_ram) +{ + // 1K more of RAM sits in 0xc000-0xc3ff (and mirrored up to 0xffff + // or should it simply go to the 1K of SG1000 RAM??? + return m_ram[0x2000 + (offset & 0x3ff)]; +} + +WRITE8_MEMBER(sega8_dahjee_typea_device::write_ram) +{ + // 1K more of RAM sits in 0xc000-0xc3ff (and mirrored up to 0xffff + // or should it simply go to the 1K of SG1000 RAM??? + m_ram[0x2000 + (offset & 0x3ff)] = data; +} + + +// TYPE B +READ8_MEMBER(sega8_dahjee_typeb_device::read_cart) +{ + return m_rom[offset % m_rom_size]; +} + +READ8_MEMBER(sega8_dahjee_typeb_device::read_ram) +{ + // 8K more of RAM sits in 0xc000-0xffff + return m_ram[offset & 0x1fff]; +} + +WRITE8_MEMBER(sega8_dahjee_typeb_device::write_ram) +{ + // 8K more of RAM sits in 0xc000-0xffff + m_ram[offset & 0x1fff] = data; +} + + + + +/*------------------------------------------------- + + Sega carts + EEPROM, used for some GameGear baseball + games + + -------------------------------------------------*/ + + +READ8_MEMBER(sega8_eeprom_device::read_cart) +{ + int bank = offset / 0x4000; + + if (offset == 0x8000 && m_93c46_enabled) + { + UINT8 value = (m_93c46_lines & 0xfc) | 0x02; + value |= m_eeprom->do_read() ? 1 : 0; + return value; + } + + if (offset < 0x400) // first 1k is hardcoded + return m_rom[offset]; + + return m_rom[m_rom_bank_base[bank] * 0x4000 + (offset & 0x3fff)]; +} + +WRITE8_MEMBER(sega8_eeprom_device::write_cart) +{ + if (offset == 0x8000 && m_93c46_enabled) + { + m_93c46_lines = data; + m_eeprom->di_write((data & 0x01) ? ASSERT_LINE : CLEAR_LINE); + m_eeprom->cs_write((data & 0x04) ? ASSERT_LINE : CLEAR_LINE); + m_eeprom->clk_write((data & 0x02) ? ASSERT_LINE : CLEAR_LINE); + } +} + +WRITE8_MEMBER(sega8_eeprom_device::write_mapper) +{ + switch (offset) + { + case 0: + if (data & 0x80) + { + m_eeprom->reset(); + logerror("eeprom CS = 1\n"); + m_eeprom->cs_write(CLEAR_LINE); + } + m_93c46_enabled = BIT(data, 3); + logerror("eeprom %s\n", m_93c46_enabled ? "enabled" : "disabled"); + break; + + case 1: // Select 16k ROM bank for 0000-3fff + case 2: // Select 16k ROM bank for 4000-7fff + case 3: // Select 16k ROM bank for 8000-bfff + m_rom_bank_base[offset - 1] = data % m_rom_page_count; + break; + } +} + +MACHINE_CONFIG_FRAGMENT( gg_eeprom ) + MCFG_EEPROM_SERIAL_93C46_ADD("eeprom") +MACHINE_CONFIG_END + +machine_config_constructor sega8_eeprom_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( gg_eeprom ); +} + + +/*------------------------------------------------- + + Codemasters carts, possibly having on cart RAM + (Ernie Els Golf) + + -------------------------------------------------*/ + +READ8_MEMBER(sega8_codemasters_device::read_cart) +{ + int bank = offset / 0x2000; + + if (bank == 5 && !m_ram.empty() && m_ram_enabled) + return m_ram[(m_ram_base * 0x2000 + (offset & 0x1fff)) % m_ram.size()]; + + return m_rom[m_rom_bank_base[bank/2] * 0x4000 + (offset & 0x3fff)]; +} + +WRITE8_MEMBER(sega8_codemasters_device::write_cart) +{ + int bank = offset / 0x2000; + + switch (offset) + { + case 0x0000: + m_rom_bank_base[0] = data % m_rom_page_count; + break; + case 0x4000: + if (data & 0x80) + { + m_ram_enabled = 1; + m_ram_base = data & 0x07; + } + else + { + m_ram_enabled = 0; + m_rom_bank_base[1] = data % m_rom_page_count; + } + break; + case 0x8000: + m_rom_bank_base[2] = data % m_rom_page_count; + break; + } + + if (bank == 5 && !m_ram.empty() && m_ram_enabled) + m_ram[(m_ram_base * 0x2000 + (offset & 0x1fff)) % m_ram.size()] = data; +} + +/*------------------------------------------------- + + HES 4 PAK All Action cart + + -------------------------------------------------*/ + + +READ8_MEMBER(sega8_4pak_device::read_cart) +{ + int bank = offset / 0x4000; + + return m_rom[m_rom_bank_base[bank] * 0x4000 + (offset & 0x3fff)]; +} + + +WRITE8_MEMBER(sega8_4pak_device::write_cart) +{ + switch (offset) + { + case 0x3ffe: + m_reg[0] = data; + m_rom_bank_base[0] = data % m_rom_page_count; + m_rom_bank_base[2] = ((m_reg[0] & 0x30) + m_reg[2]) % m_rom_page_count; + break; + case 0x7fff: + m_reg[1] = data; + m_rom_bank_base[1] = data % m_rom_page_count; + break; + case 0xbfff: + m_reg[2] = data; + m_rom_bank_base[2] = ((m_reg[0] & 0x30) + m_reg[2]) % m_rom_page_count; + break; + } +} + + +/*------------------------------------------------- + + base Zemina carts, allowing for 8K bankswitch + + -------------------------------------------------*/ + +READ8_MEMBER(sega8_zemina_device::read_cart) +{ + int bank = offset / 0x2000; + + if (bank >= 4 && !m_ram.empty() && m_ram_enabled) + return m_ram[(m_ram_base * 0x2000 + (offset & 0x1fff)) % m_ram.size()]; + + return m_rom[m_rom_bank_base[bank] * 0x2000 + (offset & 0x1fff)]; +} + +WRITE8_MEMBER(sega8_zemina_device::write_cart) +{ + int bank = offset / 0x2000; + + if (bank >= 4 && !m_ram.empty() && m_ram_enabled) + m_ram[(m_ram_base * 0x2000 + (offset & 0x1fff)) % m_ram.size()] = data; + + if (offset < 4) + { + switch (offset & 3) + { + case 0: + m_rom_bank_base[4] = data % (m_rom_page_count * 2); + break; + case 1: + m_rom_bank_base[5] = data % (m_rom_page_count * 2); + break; + case 2: + m_rom_bank_base[2] = data % (m_rom_page_count * 2); + break; + case 3: + m_rom_bank_base[3] = data % (m_rom_page_count * 2); + break; + } + } +} + +/*------------------------------------------------- + + Zemina cart used for Nemesis: same as above, but + different bank layout at start (see late_bank_setup) + + -------------------------------------------------*/ + +/*------------------------------------------------- + + Daiou cart used for SMS Janggun-ui Adeul + + the game expects to access 256 x 8K banks: + first 64 are just the game, second 64 are a mirror of the first ones + upper 128 are the same as the previous but with bytes in reverse order + probably as a shortcut to get sprite flipping for free from hw + so if bit7 of current bank page is set, we swap the result + + -------------------------------------------------*/ + +READ8_MEMBER(sega8_janggun_device::read_cart) +{ + int bank = offset / 0x2000; + + if (m_rom_bank_base[bank] < 0x80) + return m_rom[(m_rom_bank_base[bank] & 0x3f) * 0x2000 + (offset & 0x1fff)]; + else + return BITSWAP8(m_rom[(m_rom_bank_base[bank] & 0x3f) * 0x2000 + (offset & 0x1fff)], 0, 1, 2, 3, 4, 5, 6, 7); +} + + +WRITE8_MEMBER(sega8_janggun_device::write_cart) +{ + switch (offset) + { + case 0x4000: + m_rom_bank_base[2] = data; + break; + case 0x6000: + m_rom_bank_base[3] = data; + break; + case 0x8000: + m_rom_bank_base[4] = data; + break; + case 0xa000: + m_rom_bank_base[5] = data; + break; + } +} + +WRITE8_MEMBER(sega8_janggun_device::write_mapper) +{ + switch (offset) + { + case 0: + break; + + case 1: // Select 16k ROM bank for 0000-3fff + case 2: // Select 16k ROM bank for 4000-7fff + case 3: // Select 16k ROM bank for 8000-bfff + m_rom_bank_base[(offset - 1) * 2] = (data % m_rom_page_count) * 2; + m_rom_bank_base[(offset - 1) * 2 + 1] = (data % m_rom_page_count) * 2 + 1; + break; + } +} + + +/*------------------------------------------------- + + Hi-Com X-in-1 cart, uses writes to 0xffff to + change program bank in 0x0000-0x7fff + + -------------------------------------------------*/ + +READ8_MEMBER(sega8_hicom_device::read_cart) +{ + if (offset >= 0x8000) + return m_rom[offset & 0x3fff]; + + return m_rom[(m_rom_bank_base * 0x8000) + offset]; +} + +WRITE8_MEMBER(sega8_hicom_device::write_mapper) +{ + if (offset == 0x03) + m_rom_bank_base = data % (m_rom_page_count << 1); +} + +/*------------------------------------------------- + + Korean cart, used e.g. in Dodgeball King, + uses writes to 0xa000 for bankswitch + + -------------------------------------------------*/ + +WRITE8_MEMBER(sega8_korean_device::write_cart) +{ + int bank = offset / 0x4000; + + if (bank == 2 && !m_ram.empty() && m_ram_enabled) + m_ram[m_ram_base * 0x4000 + (offset & 0x3fff)] = data; + + if (offset == 0xa000) + m_rom_bank_base[2] = data % m_rom_page_count; +} diff --git a/src/devices/bus/sega8/rom.h b/src/devices/bus/sega8/rom.h new file mode 100644 index 00000000000..c04a149fdc9 --- /dev/null +++ b/src/devices/bus/sega8/rom.h @@ -0,0 +1,388 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __SEGA8_ROM_H +#define __SEGA8_ROM_H + +#include "sega8_slot.h" +#include "machine/eepromser.h" + +// ======================> sega8_rom_device + +class sega8_rom_device : public device_t, + public device_sega8_cart_interface +{ +public: + // construction/destruction + sega8_rom_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + sega8_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + virtual void late_bank_setup(); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_cart); + virtual DECLARE_WRITE8_MEMBER(write_cart); + virtual DECLARE_WRITE8_MEMBER(write_mapper); + +protected: + UINT8 m_rom_bank_base[3]; + UINT8 m_ram_base; + int m_ram_enabled; +}; + + + + +// ======================> sega8_othello_device + +class sega8_othello_device : public sega8_rom_device +{ +public: + // construction/destruction + sega8_othello_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_cart); + virtual DECLARE_WRITE8_MEMBER(write_cart); + virtual DECLARE_WRITE8_MEMBER(write_mapper) {} +}; + + +// ======================> sega8_castle_device + +class sega8_castle_device : public sega8_rom_device +{ +public: + // construction/destruction + sega8_castle_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_cart); + virtual DECLARE_WRITE8_MEMBER(write_cart); + virtual DECLARE_WRITE8_MEMBER(write_mapper) {} +}; + + +// ======================> sega8_basic_l3_device + +class sega8_basic_l3_device : public sega8_rom_device +{ +public: + // construction/destruction + sega8_basic_l3_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_cart); + virtual DECLARE_WRITE8_MEMBER(write_cart); + virtual DECLARE_WRITE8_MEMBER(write_mapper) {} + + // has internal RAM which overwrites the system one! + virtual DECLARE_READ8_MEMBER(read_ram); + virtual DECLARE_WRITE8_MEMBER(write_ram); +}; + + +// ======================> sega8_music_editor_device + +class sega8_music_editor_device : public sega8_rom_device +{ +public: + // construction/destruction + sega8_music_editor_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_cart); + virtual DECLARE_WRITE8_MEMBER(write_cart); + virtual DECLARE_WRITE8_MEMBER(write_mapper) {} + + // has internal RAM which overwrites the system one! + virtual DECLARE_READ8_MEMBER(read_ram); + virtual DECLARE_WRITE8_MEMBER(write_ram); +}; + + +// ======================> sega8_terebi_device + +class sega8_terebi_device : public sega8_rom_device +{ +public: + // construction/destruction + sega8_terebi_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual ioport_constructor device_input_ports() const; + virtual void device_reset(); + + required_ioport m_tvdraw_x; + required_ioport m_tvdraw_y; + required_ioport m_tvdraw_pen; + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_cart); + virtual DECLARE_WRITE8_MEMBER(write_cart); + virtual DECLARE_WRITE8_MEMBER(write_mapper) {} + +protected: + UINT8 m_tvdraw_data; +}; + + +// ======================> sega8_dahjee_typea_device + +class sega8_dahjee_typea_device : public sega8_rom_device +{ +public: + // construction/destruction + sega8_dahjee_typea_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_cart); + virtual DECLARE_WRITE8_MEMBER(write_cart); + virtual DECLARE_WRITE8_MEMBER(write_mapper) {} + + // has internal RAM which overwrites the system one! + virtual DECLARE_READ8_MEMBER(read_ram); + virtual DECLARE_WRITE8_MEMBER(write_ram); +}; + + +// ======================> sega8_dahjee_typeb_device + +class sega8_dahjee_typeb_device : public sega8_rom_device +{ +public: + // construction/destruction + sega8_dahjee_typeb_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_cart); + virtual DECLARE_WRITE8_MEMBER(write_cart) {} + virtual DECLARE_WRITE8_MEMBER(write_mapper) {} + + // has internal RAM which overwrites the system one! + virtual DECLARE_READ8_MEMBER(read_ram); + virtual DECLARE_WRITE8_MEMBER(write_ram); +}; + + + + +// ======================> sega8_eeprom_device + +class sega8_eeprom_device : public device_t, + public device_sega8_cart_interface +{ +public: + // construction/destruction + sega8_eeprom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual machine_config_constructor device_mconfig_additions() const; + virtual void device_reset(); + + virtual void late_bank_setup(); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_cart); + virtual DECLARE_WRITE8_MEMBER(write_cart); + virtual DECLARE_WRITE8_MEMBER(write_mapper); + +protected: + UINT8 m_rom_bank_base[3]; + + required_device m_eeprom; + int m_93c46_enabled; + UINT8 m_93c46_lines; +}; + + +// ======================> sega8_codemasters_device + +class sega8_codemasters_device : public device_t, + public device_sega8_cart_interface +{ +public: + // construction/destruction + sega8_codemasters_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + virtual void late_bank_setup(); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_cart); + virtual DECLARE_WRITE8_MEMBER(write_cart); + // no mapper write for this! + +protected: + UINT8 m_rom_bank_base[3]; + UINT8 m_ram_base; + int m_ram_enabled; +}; + + +// ======================> sega8_4pak_device + +class sega8_4pak_device : public sega8_rom_device +{ +public: + // construction/destruction + sega8_4pak_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_cart); + virtual DECLARE_WRITE8_MEMBER(write_cart); + +private: + UINT8 m_reg[3]; +}; + + +// ======================> sega8_zemina_device + +class sega8_zemina_device : public device_t, + public device_sega8_cart_interface +{ +public: + // construction/destruction + sega8_zemina_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + sega8_zemina_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + virtual void late_bank_setup(); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_cart); + virtual DECLARE_WRITE8_MEMBER(write_cart); + // no mapper write for this! + +protected: + UINT8 m_rom_bank_base[6]; + UINT8 m_ram_base; + int m_ram_enabled; +}; + + +// ======================> sega8_nemesis_device + +class sega8_nemesis_device : public sega8_zemina_device +{ +public: + // construction/destruction + sega8_nemesis_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual void late_bank_setup(); +}; + + +// ======================> sega8_janggun_device + +class sega8_janggun_device : public device_t, + public device_sega8_cart_interface +{ +public: + // construction/destruction + sega8_janggun_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start() { save_item(NAME(m_rom_bank_base)); } + + virtual void late_bank_setup(); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_cart); + virtual DECLARE_WRITE8_MEMBER(write_cart); + virtual DECLARE_WRITE8_MEMBER(write_mapper); + +protected: + UINT8 m_rom_bank_base[6]; +}; + + +// ======================> sega8_hicom_device + +class sega8_hicom_device : public sega8_rom_device +{ +public: + // construction/destruction + sega8_hicom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start() { save_item(NAME(m_rom_bank_base)); } + + virtual void late_bank_setup(); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_cart); + virtual DECLARE_WRITE8_MEMBER(write_cart) {} + virtual DECLARE_WRITE8_MEMBER(write_mapper); + +protected: + UINT8 m_rom_bank_base; +}; + + +// ======================> sega8_korean_device + +class sega8_korean_device : public sega8_rom_device +{ +public: + // construction/destruction + sega8_korean_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual void late_bank_setup(); + + // reading and writing + virtual DECLARE_WRITE8_MEMBER(write_cart); + virtual DECLARE_WRITE8_MEMBER(write_mapper) {} +}; + + +// ======================> sega8_korean_nb_device + +class sega8_korean_nb_device : public sega8_rom_device +{ +public: + // construction/destruction + sega8_korean_nb_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // reading and writing + virtual DECLARE_WRITE8_MEMBER(write_mapper) {} +}; + + + +// device type definition +extern const device_type SEGA8_ROM_STD; +extern const device_type SEGA8_ROM_OTHELLO; +extern const device_type SEGA8_ROM_CASTLE; +extern const device_type SEGA8_ROM_BASIC_L3; +extern const device_type SEGA8_ROM_MUSIC_EDITOR; +extern const device_type SEGA8_ROM_DAHJEE_TYPEA; +extern const device_type SEGA8_ROM_DAHJEE_TYPEB; +extern const device_type SEGA8_ROM_EEPROM; +extern const device_type SEGA8_ROM_TEREBI; +extern const device_type SEGA8_ROM_CODEMASTERS; +extern const device_type SEGA8_ROM_4PAK; +extern const device_type SEGA8_ROM_ZEMINA; +extern const device_type SEGA8_ROM_NEMESIS; +extern const device_type SEGA8_ROM_JANGGUN; +extern const device_type SEGA8_ROM_HICOM; +extern const device_type SEGA8_ROM_KOREAN; +extern const device_type SEGA8_ROM_KOREAN_NB; + +#endif diff --git a/src/devices/bus/sega8/sega8_slot.c b/src/devices/bus/sega8/sega8_slot.c new file mode 100644 index 00000000000..ac696a0ac95 --- /dev/null +++ b/src/devices/bus/sega8/sega8_slot.c @@ -0,0 +1,872 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + Sega 8-bit cart emulation + (through slot devices) + + Master System (Mark III) and Game Gear memory map can access 3 x 16K banks of ROM in + 0x0000-0xbfff memory range. These banks can however point to different ROM or RAM area + of the cart (or to BIOS banks, but these are handled directly in SMS emulation). + + Hence, carts can interface with the main system through the following handlers + * read_cart : to read from ROM/RAM in memory range [0000-bfff] + * write_cart : to write to ROM/RAM in memory range [0000-bfff] + * write_mapper : to write to range [fffc-ffff] (called by the handler accessing those + same addresses in sms.c) + + Note about Sega Card / MyCard: the data contained in these matches the data in carts, it's only + the connector to be different. We emulate this with a variant of the slot having different media + switch and different interface (the latter not implemented yet) + + TODO: + - investigate SG-1000 carts so to reduce duplicated code and to add full .sg support to sg1000m3 + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "sega8_slot.h" + +#define VERBOSE 0 +#define LOG(x) do { if (VERBOSE) logerror x; } while (0) + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type SEGA8_CART_SLOT = &device_creator; +const device_type SEGA8_CARD_SLOT = &device_creator; + + +//************************************************************************** +// SMS cartridges Interface +//************************************************************************** + +//------------------------------------------------- +// device_sega8_cart_interface - constructor +//------------------------------------------------- + +device_sega8_cart_interface::device_sega8_cart_interface(const machine_config &mconfig, device_t &device) + : device_slot_card_interface(mconfig, device), + m_rom(NULL), + m_rom_size(0), + m_rom_page_count(0), + has_battery(FALSE), + m_late_battery_enable(FALSE), + m_lphaser_xoffs(-1), + m_sms_mode(0) +{ +} + + +//------------------------------------------------- +// ~device_sega8_cart_interface - destructor +//------------------------------------------------- + +device_sega8_cart_interface::~device_sega8_cart_interface() +{ +} + +//------------------------------------------------- +// rom_alloc - alloc the space for the cart +//------------------------------------------------- + +void device_sega8_cart_interface::rom_alloc(UINT32 size, const char *tag) +{ + if (m_rom == NULL) + { + m_rom = device().machine().memory().region_alloc(std::string(tag).append(S8SLOT_ROM_REGION_TAG).c_str(), size, 1, ENDIANNESS_LITTLE)->base(); + m_rom_size = size; + m_rom_page_count = size / 0x4000; + if (!m_rom_page_count) + m_rom_page_count = 1; // we compute rom pages through (XXX % m_rom_page_count)! + late_bank_setup(); + } +} + + +//------------------------------------------------- +// ram_alloc - alloc the space for the ram +//------------------------------------------------- + +void device_sega8_cart_interface::ram_alloc(UINT32 size) +{ + m_ram.resize(size); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// sega8_cart_slot_device - constructor +//------------------------------------------------- + +sega8_cart_slot_device::sega8_cart_slot_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, bool is_card, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_image_interface(mconfig, *this), + device_slot_interface(mconfig, *this), + m_type(SEGA8_BASE_ROM), + m_must_be_loaded(FALSE), + m_interface("sms_cart"), + m_extensions("bin") +{ + m_is_card = is_card; +} + +sega8_cart_slot_device::sega8_cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, SEGA8_CART_SLOT, "Sega Master System / Game Gear / SG1000 Cartridge Slot", tag, owner, clock, "sega8_cart_slot", __FILE__), + device_image_interface(mconfig, *this), + device_slot_interface(mconfig, *this), + m_type(SEGA8_BASE_ROM), + m_must_be_loaded(FALSE), + m_is_card(FALSE), + m_interface("sms_cart"), + m_extensions("bin") +{ +} + +sega8_card_slot_device::sega8_card_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + sega8_cart_slot_device(mconfig, SEGA8_CARD_SLOT, "Sega Master System / Game Gear / SG1000 Card Slot", tag, owner, clock, TRUE, "sega8_card_slot", __FILE__) +{ +} + + +//------------------------------------------------- +// sega8_cart_slot_device - destructor +//------------------------------------------------- + +sega8_cart_slot_device::~sega8_cart_slot_device() +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void sega8_cart_slot_device::device_start() +{ + m_cart = dynamic_cast(get_card_device()); +} + +//------------------------------------------------- +// SMS PCB +//------------------------------------------------- + + +struct sega8_slot +{ + int pcb_id; + const char *slot_option; +}; + +// Here, we take the feature attribute from .xml (i.e. the PCB name) and we assign a unique ID to it +static const sega8_slot slot_list[] = +{ + { SEGA8_BASE_ROM, "rom" }, + { SEGA8_EEPROM, "eeprom" }, + { SEGA8_TEREBIOEKAKI, "terebi" }, + { SEGA8_4PAK, "4pak" }, + { SEGA8_CODEMASTERS, "codemasters" }, + { SEGA8_ZEMINA, "zemina" }, + { SEGA8_NEMESIS, "nemesis" }, + { SEGA8_JANGGUN, "janggun" }, + { SEGA8_KOREAN, "korean" }, + { SEGA8_KOREAN_NOBANK, "korean_nb" }, + { SEGA8_OTHELLO, "othello" }, + { SEGA8_CASTLE, "castle" }, + { SEGA8_BASIC_L3, "level3" }, + { SEGA8_MUSIC_EDITOR, "music_editor" }, + { SEGA8_DAHJEE_TYPEA, "dahjee_typea" }, + { SEGA8_DAHJEE_TYPEB, "dahjee_typeb" } +}; + +static int sega8_get_pcb_id(const char *slot) +{ + for (int i = 0; i < ARRAY_LENGTH(slot_list); i++) + { + if (!core_stricmp(slot_list[i].slot_option, slot)) + return slot_list[i].pcb_id; + } + + return 0; +} + +static const char *sega8_get_slot(int type) +{ + for (int i = 0; i < ARRAY_LENGTH(slot_list); i++) + { + if (slot_list[i].pcb_id == type) + return slot_list[i].slot_option; + } + + return "rom"; +} + + +/*------------------------------------------------- + call load + -------------------------------------------------*/ + +int sega8_cart_slot_device::verify_cart( UINT8 *magic, int size ) +{ + int retval = IMAGE_VERIFY_FAIL; + + // Verify the file is a valid image - check $7ff0 for "TMR SEGA" + if (size >= 0x8000) + { + if (!strncmp((char*)&magic[0x7ff0], "TMR SEGA", 8)) + retval = IMAGE_VERIFY_PASS; + } + + return retval; +} + +void sega8_cart_slot_device::set_lphaser_xoffset( UINT8 *rom, int size ) +{ + static const UINT8 signatures[7][16] = + { + /* Spacegun */ + { 0x54, 0x4d, 0x52, 0x20, 0x53, 0x45, 0x47, 0x41, 0xff, 0xff, 0x9d, 0x99, 0x10, 0x90, 0x00, 0x40 }, + /* Gangster Town */ + { 0x54, 0x4d, 0x52, 0x20, 0x53, 0x45, 0x47, 0x41, 0x19, 0x87, 0x1b, 0xc9, 0x74, 0x50, 0x00, 0x4f }, + /* Shooting Gallery */ + { 0x54, 0x4d, 0x52, 0x20, 0x53, 0x45, 0x47, 0x41, 0x20, 0x20, 0x8a, 0x3a, 0x72, 0x50, 0x00, 0x4f }, + /* Rescue Mission */ + { 0x54, 0x4d, 0x52, 0x20, 0x53, 0x45, 0x47, 0x41, 0x20, 0x20, 0xfb, 0xd3, 0x06, 0x51, 0x00, 0x4f }, + /* Laser Ghost */ + { 0x54, 0x4d, 0x52, 0x20, 0x53, 0x45, 0x47, 0x41, 0x00, 0x00, 0xb7, 0x55, 0x74, 0x70, 0x00, 0x40 }, + /* Assault City */ + { 0x54, 0x4d, 0x52, 0x20, 0x53, 0x45, 0x47, 0x41, 0xff, 0xff, 0x9f, 0x74, 0x34, 0x70, 0x00, 0x40 }, + /* Missile Defense 3-D */ + { 0x54, 0x4d, 0x52, 0x20, 0x53, 0x45, 0x47, 0x41, 0x41, 0x4c, 0x15, 0x4a, 0x01, 0x80, 0x00, 0x4f } + }; + + int xoff = -1; + + if (size >= 0x8000) + { + if (!memcmp(&rom[0x7ff0], signatures[0], 16) || !memcmp(&rom[0x7ff0], signatures[1], 16)) + xoff = 26; + else if (!memcmp(&rom[0x7ff0], signatures[2], 16)) + xoff = 36; + else if (!memcmp(&rom[0x7ff0], signatures[3], 16)) + xoff = 32; + else if (!memcmp(&rom[0x7ff0], signatures[4], 16)) + xoff = 30; + else if (!memcmp(&rom[0x7ff0], signatures[5], 16)) + xoff = 39; + else if (!memcmp(&rom[0x7ff0], signatures[6], 16)) + xoff = 38; + } + + m_cart->set_lphaser_xoffs(xoff); +} + +void sega8_cart_slot_device::setup_ram() +{ + if (software_entry() == NULL) + { + if (m_type == SEGA8_CASTLE) + { + m_cart->ram_alloc(0x2000); + m_cart->set_has_battery(FALSE); + } + else if (m_type == SEGA8_OTHELLO) + { + m_cart->ram_alloc(0x800); + m_cart->set_has_battery(FALSE); + } + else if (m_type == SEGA8_BASIC_L3) + { + m_cart->ram_alloc(0x8000); + m_cart->set_has_battery(FALSE); + } + else if (m_type == SEGA8_MUSIC_EDITOR) + { + m_cart->ram_alloc(0x2800); + m_cart->set_has_battery(FALSE); + } + else if (m_type == SEGA8_DAHJEE_TYPEA) + { + m_cart->ram_alloc(0x2400); + m_cart->set_has_battery(FALSE); + } + else if (m_type == SEGA8_DAHJEE_TYPEB) + { + m_cart->ram_alloc(0x2000); + m_cart->set_has_battery(FALSE); + } + else if (m_type == SEGA8_CODEMASTERS) + { + // Codemasters cart can have 64KB of RAM (Ernie Els Golf? or 8KB?) and no battery + m_cart->ram_alloc(0x10000); + m_cart->set_has_battery(FALSE); + } + else + { + // for generic carts loaded from fullpath we have no way to know exactly if there was RAM, + // how much RAM was in the cart and if there was a battery so we always alloc 32KB and + // we save its content only if the game enable the RAM + m_cart->set_late_battery(TRUE); + m_cart->ram_alloc(0x08000); + } + } + else + { + // from softlist we rely on the xml to only allocate the correct amount of RAM and to save it only if a battery was present + const char *battery = get_feature("battery"); + m_cart->set_late_battery(FALSE); + + if (get_software_region_length("ram")) + m_cart->ram_alloc(get_software_region_length("ram")); + + if (battery && !strcmp(battery, "yes")) + m_cart->set_has_battery(TRUE); + } +} + +bool sega8_cart_slot_device::call_load() +{ + if (m_cart) + { + UINT32 len = (software_entry() == NULL) ? length() : get_software_region_length("rom"); + UINT32 offset = 0; + UINT8 *ROM; + + if (m_is_card && len > 0x8000) + { + seterror(IMAGE_ERROR_UNSPECIFIED, "Attempted loading a card larger than 32KB"); + return IMAGE_INIT_FAIL; + } + + // check for header + if ((len % 0x4000) == 512) + { + offset = 512; + len -= 512; + } + + // make sure that we only get complete (0x4000) rom banks + if (len & 0x3fff) + len = ((len >> 14) + 1) << 14; + + m_cart->rom_alloc(len, tag()); + ROM = m_cart->get_rom_base(); + + if (software_entry() == NULL) + { + fseek(offset, SEEK_SET); + fread(ROM, len); + } + else + memcpy(ROM, get_software_region("rom"), get_software_region_length("rom")); + + /* check the image */ + if (verify_cart(ROM, len) == IMAGE_VERIFY_FAIL) + logerror("Warning loading image: verify_cart failed\n"); + + if (software_entry() != NULL) + m_type = sega8_get_pcb_id(get_feature("slot") ? get_feature("slot") : "rom"); + else + m_type = get_cart_type(ROM, len); + + set_lphaser_xoffset(ROM, len); + + setup_ram(); + + // Check for gamegear cartridges with PIN 42 set to SMS mode + if (software_entry() != NULL) + { + const char *pin_42 = get_feature("pin_42"); + if (pin_42 && !strcmp(pin_42, "sms_mode")) + m_cart->set_sms_mode(1); + } + + // when loading from fullpath m_late_battery_enable can be TRUE and in that case + // we attempt to load a battery because the game might have it! + if (m_cart->get_ram_size() && (m_cart->get_has_battery() || m_cart->get_late_battery())) + battery_load(m_cart->get_ram_base(), m_cart->get_ram_size(), 0x00); + + //printf("Type: %s\n", sega8_get_slot(type)); + + internal_header_logging(ROM + offset, len, m_cart->get_ram_size()); + + return IMAGE_INIT_PASS; + } + + return IMAGE_INIT_PASS; +} + + +/*------------------------------------------------- + call_unload + -------------------------------------------------*/ + +void sega8_cart_slot_device::call_unload() +{ + if (m_cart && m_cart->get_ram_base() && m_cart->get_ram_size() && m_cart->get_has_battery()) + battery_save(m_cart->get_ram_base(), m_cart->get_ram_size()); +} + + +/*------------------------------------------------- + call softlist load + -------------------------------------------------*/ + +bool sega8_cart_slot_device::call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry) +{ + load_software_part_region(*this, swlist, swname, start_entry); + return TRUE; +} + + +#ifdef UNUSED_FUNCTION +// For the moment we switch to a different detection routine which allows to detect +// in a single run Codemasters mapper, Korean mapper (including Jang Pung 3 which +// uses a diff signature then the one below here) and Zemina mapper (used by Wonsiin, etc.). +// I leave these here to document alt. detection routines and in the case these functions +// can be updated + +/* Check for Codemasters mapper + 0x7FE3 - 93 - sms Cosmis Spacehead + - sms Dinobasher + - sms The Excellent Dizzy Collection + - sms Fantastic Dizzy + - sms Micro Machines + - gamegear Cosmic Spacehead + - gamegear Micro Machines + - 94 - gamegear Dropzone + - gamegear Ernie Els Golf (also has 64KB additional RAM on the cartridge) + - gamegear Pete Sampras Tennis + - gamegear S.S. Lucifer + - 95 - gamegear Micro Machines 2 - Turbo Tournament + + The Korean game Jang Pung II also seems to use a codemasters style mapper. + */ +int sms_state::detect_codemasters_mapper( UINT8 *rom ) +{ + static const UINT8 jang_pung2[16] = { 0x00, 0xba, 0x38, 0x0d, 0x00, 0xb8, 0x38, 0x0c, 0x00, 0xb6, 0x38, 0x0b, 0x00, 0xb4, 0x38, 0x0a }; + + if (((rom[0x7fe0] & 0x0f ) <= 9) && (rom[0x7fe3] == 0x93 || rom[0x7fe3] == 0x94 || rom[0x7fe3] == 0x95) && rom[0x7fef] == 0x00) + return 1; + + if (!memcmp(&rom[0x7ff0], jang_pung2, 16)) + return 1; + + return 0; +} + + +int sms_state::detect_korean_mapper( UINT8 *rom ) +{ + static const UINT8 signatures[2][16] = + { + { 0x3e, 0x11, 0x32, 0x00, 0xa0, 0x78, 0xcd, 0x84, 0x85, 0x3e, 0x02, 0x32, 0x00, 0xa0, 0xc9, 0xff }, /* Dodgeball King */ + { 0x41, 0x48, 0x37, 0x37, 0x44, 0x37, 0x4e, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x20 }, /* Sangokushi 3 */ + }; + int i; + + for (i = 0; i < 2; i++) + { + if (!memcmp(&rom[0x7ff0], signatures[i], 16)) + { + return 1; + } + } + return 0; +} +#endif + +int sega8_cart_slot_device::get_cart_type(UINT8 *ROM, UINT32 len) +{ + int type = SEGA8_BASE_ROM; + + // Check for special cartridge features (new routine, courtesy of Omar Cornut, from MEKA) + if (len >= 0x8000) + { + int _0002 = 0, _8000 = 0, _a000 = 0, _ffff = 0, _3ffe = 0, _4000 = 0, _6000 = 0; + for (int i = 0; i < 0x8000; i++) + { + if (ROM[i] == 0x32) // Z80 opcode for: LD (xxxx), A + { + UINT16 addr = (ROM[i + 2] << 8) | ROM[i + 1]; + if (addr == 0xffff) + { i += 2; _ffff++; continue; } + if (addr == 0x0002 || addr == 0x0003 || addr == 0x0004) + { i += 2; _0002++; continue; } + if (addr == 0x8000) + { i += 2; _8000++; continue; } + if (addr == 0xa000) + { i += 2; _a000++; continue; } + if ( addr == 0x3ffe) + { i += 2; _3ffe++; continue; } + if ( addr == 0x4000 ) + { i += 2; _4000++; continue; } + if ( addr == 0x6000 ) + { i += 2; _6000++; continue; } + } + } + + LOG(("Mapper test: _0002 = %d, _8000 = %d, _a000 = %d, _ffff = %d\n", _0002, _8000, _a000, _ffff)); + + // 2 is a security measure, although tests on existing ROM showed it was not needed + if (len > 0x10000 && (_0002 > _ffff + 2 || (_0002 > 0 && _ffff == 0))) + { + type = SEGA8_ZEMINA; + + // Check for special bank 0 signature + if (len == 0x20000 && ROM[0] == 0x00 && ROM[1] == 0x00 && ROM[2] == 0x00 && + ROM[0x1e000] == 0xF3 && ROM[0x1e001] == 0xed && ROM[0x1e002] == 0x56) + type = SEGA8_NEMESIS; + } + else if (_8000 > _ffff + 2 || (_8000 > 0 && _ffff == 0)) + type = SEGA8_CODEMASTERS; + else if (_a000 > _ffff + 2 || (_a000 > 0 && _ffff == 0)) + type = SEGA8_KOREAN; + else if (_3ffe > _ffff + 2 || _3ffe > 0) + type = SEGA8_4PAK; + else if (_4000 > 0 && _6000 > 0 && _8000 > 0 && _a000 > 0) + type = SEGA8_JANGGUN; + } + + // Try to detect Dahjee RAM Expansions + if (len >= 0x8000) + { + int x2000_3000 = 0, xd000_e000_f000 = 0, x2000_ff = 0; + + for (int i = 0; i < 0x8000; i++) + { + if (ROM[i] == 0x32) + { + UINT16 addr = ROM[i + 1] | (ROM[i + 2] << 8); + + switch (addr & 0xf000) + { + case 0x2000: + case 0x3000: + i += 2; + x2000_3000++; + break; + + case 0xd000: + case 0xe000: + case 0xf000: + i += 2; + xd000_e000_f000++; + break; + } + } + } + for (int i = 0x2000; i < 0x4000; i++) + { + if (ROM[i] == 0xff) + x2000_ff++; + } + if (x2000_ff == 0x2000 && (xd000_e000_f000 > 10 || x2000_3000 > 10)) + { + if (xd000_e000_f000 > x2000_3000) + type = SEGA8_DAHJEE_TYPEB; + else + type = SEGA8_DAHJEE_TYPEA; + } + } + + // Terebi Oekaki (TV Draw) + if (len >= 0x13b3 + 7 && !strncmp((const char *)&ROM[0x13b3], "annakmn", 7)) + type = SEGA8_TEREBIOEKAKI; + + // The Castle (ROM+RAM) + if (len >= 0x1cc3 + 10 && !strncmp((const char *)&ROM[0x1cc3], "ASCII 1986", 10)) + type = SEGA8_CASTLE; + + // BASIC Level 3 + if (len >= 0x6a20 + 29 && !strncmp((const char *)&ROM[0x6a20], "SC-3000 BASIC Level 3 ver 1.0", 29)) + type = SEGA8_BASIC_L3; + + // Music Editor + if (len >= 0x0841 + 5) + { + if (!strncmp((const char *)&ROM[0x0841], "PIANO", 5) || !strncmp((const char *)&ROM[0x0841], "music", 5)) + type = SEGA8_MUSIC_EDITOR; + } + + + return type; +} +/*------------------------------------------------- + get default card software + -------------------------------------------------*/ + +void sega8_cart_slot_device::get_default_card_software(std::string &result) +{ + if (open_image_file(mconfig().options())) + { + const char *slot_string = "rom"; + UINT32 len = core_fsize(m_file), offset = 0; + dynamic_buffer rom(len); + int type; + + core_fread(m_file, &rom[0], len); + + if ((len % 0x4000) == 512) + offset = 512; + + type = get_cart_type(&rom[offset], len - offset); + slot_string = sega8_get_slot(type); + + //printf("type: %s\n", slot_string); + clear(); + + result.assign(slot_string); + return; + } + + software_get_default_slot(result, "rom"); +} + + + +/*------------------------------------------------- + read + -------------------------------------------------*/ + +READ8_MEMBER(sega8_cart_slot_device::read_cart) +{ + if (m_cart) + return m_cart->read_cart(space, offset); + else + return 0xff; +} + +READ8_MEMBER(sega8_cart_slot_device::read_ram) +{ + if (m_cart) + return m_cart->read_ram(space, offset); + else + return 0xff; +} + + +/*------------------------------------------------- + write + -------------------------------------------------*/ + +WRITE8_MEMBER(sega8_cart_slot_device::write_mapper) +{ + if (m_cart) + m_cart->write_mapper(space, offset, data); +} + +WRITE8_MEMBER(sega8_cart_slot_device::write_cart) +{ + if (m_cart) + m_cart->write_cart(space, offset, data); +} + +WRITE8_MEMBER(sega8_cart_slot_device::write_ram) +{ + if (m_cart) + m_cart->write_ram(space, offset, data); +} + + +/*------------------------------------------------- + Internal header logging + -------------------------------------------------*/ + +void sega8_cart_slot_device::internal_header_logging(UINT8 *ROM, UINT32 len, UINT32 nvram_len) +{ + static const char *const system_region[] = + { + "", + "", + "", + "Master System Japan", + "Master System Export", + "Game Gear Japan", + "Game Gear Export", + "Game Gear International", + "", + "", + "", + "", + "", + "", + "", + "" + }; + + static int csum_length[] = + { + 0x40000, + 0x80000, + 0x100000, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0x1ff0, + 0x3ff0, + 0x7ff0, + 0xcff0, + 0x10000, + 0x20000, + }; + + char reserved[10]; + UINT8 version, csum_size, region, serial[3]; + UINT16 checksum, csum = 0; + UINT32 csum_end = 0; + + // LOG FILE DETAILS + logerror("FILE DETAILS\n" ); + logerror("============\n" ); + logerror("Name: %s\n", basename()); + logerror("File Size: 0x%08x\n", (software_entry() == NULL) ? (int)length() : (int)get_software_region_length("rom")); + logerror("Detected type: %s\n", sega8_get_slot(m_type)); + logerror("ROM (Allocated) Size: 0x%X\n", len); + logerror("RAM: %s\n", nvram_len ? "Yes" : "No"); + if (nvram_len) + logerror("RAM (Allocated) Size: 0x%X - Battery: %s\n", nvram_len, m_cart->get_has_battery() ? "Yes" : "No"); + logerror("\n" ); + + + // LOG HEADER DETAILS + if (len < 0x8000) + return; + + for (int i = 0; i < 10; i++) + reserved[i] = ROM[0x7ff0 + i]; + + checksum = ROM[0x7ffa] | (ROM[0x7ffb] << 8); + + for (int i = 0; i < 3; i++) + serial[i] = ROM[0x7ffc + i]; + serial[2] &= 0x0f; + + version = (ROM[0x7ffe] & 0xf0) >> 4; + + csum_size = ROM[0x7fff] & 0x0f; + csum_end = csum_length[csum_size]; + if (!csum_end || csum_end > len) + csum_end = len; + + region = (ROM[0x7fff] & 0xf0) >> 4; + + // compute cart checksum to compare with expected one + for (int i = 0; i < csum_end; i++) + { + if (i < 0x7ff0 || i >= 0x8000) + { + csum += ROM[i]; + csum &= 0xffff; + } + } + + logerror("INTERNAL HEADER\n" ); + logerror("===============\n" ); + logerror("Reserved String: %.10s\n", reserved); + logerror("Region: %s\n", system_region[region]); + logerror("Checksum: (Expected) 0x%x - (Computed) 0x%x\n", checksum, csum); + logerror(" [checksum over 0x%X bytes]\n", csum_length[csum_size]); + logerror("Serial String: %X\n", serial[0] | (serial[1] << 8) | (serial[2] << 16)); + logerror("Software Revision: %x\n", version); + logerror("\n" ); + + + if (m_type == SEGA8_CODEMASTERS) + { + UINT8 day, month, year, hour, minute; + csum = 0; + + day = ROM[0x7fe1]; + month = ROM[0x7fe2]; + year = ROM[0x7fe3]; + hour = ROM[0x7fe4]; + minute = ROM[0x7fe5]; + checksum = ROM[0x7fe6] | (ROM[0x7fe7] << 8); + csum_size = ROM[0x7fe0]; + + // compute cart checksum to compare with expected one + for (int i = 0; i < len; i += 2) + { + if (i < 0x7ff0 || i >= 0x8000) + { + csum += (ROM[i] | (ROM[i + 1] << 8)); + csum &= 0xffff; + } + } + + logerror("CODEMASTERS HEADER\n" ); + logerror("==================\n" ); + logerror("Build date & time: %x/%x/%x %.2x:%.2x\n", day, month, year, hour, minute); + logerror("Checksum: (Expected) 0x%x - (Computed) 0x%x\n", checksum, csum); + logerror(" [checksum over 0x%X bytes]\n", csum_size * 0x4000); + logerror("\n" ); + } +} + +// slot interfaces +#include "rom.h" +#include "ccatch.h" +#include "mgear.h" + +SLOT_INTERFACE_START(sg1000_cart) + SLOT_INTERFACE_INTERNAL("rom", SEGA8_ROM_STD) + SLOT_INTERFACE_INTERNAL("othello", SEGA8_ROM_OTHELLO) + SLOT_INTERFACE_INTERNAL("castle", SEGA8_ROM_CASTLE) + SLOT_INTERFACE_INTERNAL("terebi", SEGA8_ROM_TEREBI) + SLOT_INTERFACE_INTERNAL("level3", SEGA8_ROM_BASIC_L3) + SLOT_INTERFACE_INTERNAL("music_editor", SEGA8_ROM_MUSIC_EDITOR) + SLOT_INTERFACE_INTERNAL("dahjee_typea", SEGA8_ROM_DAHJEE_TYPEA) + SLOT_INTERFACE_INTERNAL("dahjee_typeb", SEGA8_ROM_DAHJEE_TYPEB) + SLOT_INTERFACE_INTERNAL("cardcatcher", SEGA8_ROM_CARDCATCH) +SLOT_INTERFACE_END + +SLOT_INTERFACE_START(sg1000mk3_cart) + SLOT_INTERFACE_INTERNAL("rom", SEGA8_ROM_STD) + SLOT_INTERFACE_INTERNAL("terebi", SEGA8_ROM_TEREBI) + SLOT_INTERFACE_INTERNAL("codemasters", SEGA8_ROM_CODEMASTERS) + SLOT_INTERFACE_INTERNAL("4pak", SEGA8_ROM_4PAK) + SLOT_INTERFACE_INTERNAL("zemina", SEGA8_ROM_ZEMINA) + SLOT_INTERFACE_INTERNAL("nemesis", SEGA8_ROM_NEMESIS) + SLOT_INTERFACE_INTERNAL("janggun", SEGA8_ROM_JANGGUN) + SLOT_INTERFACE_INTERNAL("hicom", SEGA8_ROM_HICOM) + SLOT_INTERFACE_INTERNAL("korean", SEGA8_ROM_KOREAN) + SLOT_INTERFACE_INTERNAL("korean_nb", SEGA8_ROM_KOREAN_NB) + SLOT_INTERFACE_INTERNAL("othello", SEGA8_ROM_OTHELLO) + SLOT_INTERFACE_INTERNAL("castle", SEGA8_ROM_CASTLE) + SLOT_INTERFACE_INTERNAL("dahjee_typea", SEGA8_ROM_DAHJEE_TYPEA) + SLOT_INTERFACE_INTERNAL("dahjee_typeb", SEGA8_ROM_DAHJEE_TYPEB) + // are these SC-3000 carts below actually compatible or not? remove if not! + SLOT_INTERFACE_INTERNAL("level3", SEGA8_ROM_BASIC_L3) + SLOT_INTERFACE_INTERNAL("music_editor", SEGA8_ROM_MUSIC_EDITOR) +SLOT_INTERFACE_END + +SLOT_INTERFACE_START(sms_cart) + SLOT_INTERFACE_INTERNAL("rom", SEGA8_ROM_STD) + SLOT_INTERFACE_INTERNAL("codemasters", SEGA8_ROM_CODEMASTERS) + SLOT_INTERFACE_INTERNAL("4pak", SEGA8_ROM_4PAK) + SLOT_INTERFACE_INTERNAL("zemina", SEGA8_ROM_ZEMINA) + SLOT_INTERFACE_INTERNAL("nemesis", SEGA8_ROM_NEMESIS) + SLOT_INTERFACE_INTERNAL("janggun", SEGA8_ROM_JANGGUN) + SLOT_INTERFACE_INTERNAL("hicom", SEGA8_ROM_HICOM) + SLOT_INTERFACE_INTERNAL("korean", SEGA8_ROM_KOREAN) + SLOT_INTERFACE_INTERNAL("korean_nb", SEGA8_ROM_KOREAN_NB) +SLOT_INTERFACE_END + +SLOT_INTERFACE_START(gg_cart) + SLOT_INTERFACE_INTERNAL("rom", SEGA8_ROM_STD) + SLOT_INTERFACE_INTERNAL("eeprom", SEGA8_ROM_EEPROM) + SLOT_INTERFACE_INTERNAL("codemasters", SEGA8_ROM_CODEMASTERS) + SLOT_INTERFACE_INTERNAL("mgear", SEGA8_ROM_MGEAR) +SLOT_INTERFACE_END diff --git a/src/devices/bus/sega8/sega8_slot.h b/src/devices/bus/sega8/sega8_slot.h new file mode 100644 index 00000000000..ac0fdd406cd --- /dev/null +++ b/src/devices/bus/sega8/sega8_slot.h @@ -0,0 +1,243 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __SEGA8_SLOT_H +#define __SEGA8_SLOT_H + +/*************************************************************************** + TYPE DEFINITIONS + ***************************************************************************/ + + +/* PCB */ +enum +{ + SEGA8_BASE_ROM = 0, + SEGA8_EEPROM, + SEGA8_TEREBIOEKAKI, + SEGA8_4PAK, + SEGA8_CODEMASTERS, + SEGA8_ZEMINA, + SEGA8_NEMESIS, + SEGA8_JANGGUN, + SEGA8_KOREAN, + SEGA8_KOREAN_NOBANK, + SEGA8_OTHELLO, + SEGA8_CASTLE, + SEGA8_BASIC_L3, + SEGA8_MUSIC_EDITOR, + SEGA8_DAHJEE_TYPEA, + SEGA8_DAHJEE_TYPEB +}; + + +extern const device_type SEGA8_CART_SLOT; +extern const device_type SEGA8_CARD_SLOT; + + +// ======================> device_sega8_cart_interface + +class device_sega8_cart_interface : public device_slot_card_interface +{ +public: + // construction/destruction + device_sega8_cart_interface(const machine_config &mconfig, device_t &device); + virtual ~device_sega8_cart_interface(); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_cart) { return 0xff; } + virtual DECLARE_WRITE8_MEMBER(write_cart) {} + virtual DECLARE_WRITE8_MEMBER(write_mapper) {} + virtual int get_lphaser_xoffs() { return m_lphaser_xoffs; } + // a few carts (for SG1000) acts as a RAM expansion, taking control of the system RAM in 0xc000-0xffff + virtual DECLARE_READ8_MEMBER(read_ram) { return 0xff; } + virtual DECLARE_WRITE8_MEMBER(write_ram) {} + + void rom_alloc(UINT32 size, const char *tag); + void ram_alloc(UINT32 size); + + virtual void late_bank_setup() {} + + void set_has_battery(bool val) { has_battery = val; } + bool get_has_battery() { return has_battery; } + void set_late_battery(bool val) { m_late_battery_enable = val; } + bool get_late_battery() { return m_late_battery_enable; } + void set_lphaser_xoffs(int val) { m_lphaser_xoffs = val; } + void set_sms_mode(int val) { m_sms_mode = val; } + int get_sms_mode() { return m_sms_mode; } + +//protected: + UINT8* get_rom_base() { return m_rom; } + UINT8* get_ram_base() { return &m_ram[0]; } + UINT32 get_rom_size() { return m_rom_size; } + UINT32 get_ram_size() { return m_ram.size(); } + + void rom_map_setup(UINT32 size); + void ram_map_setup(UINT8 banks); + + void save_ram() { device().save_item(NAME(m_ram)); } + +//private: + // internal state + UINT8 *m_rom; + UINT32 m_rom_size; + dynamic_buffer m_ram; + int m_rom_page_count; + + bool has_battery; + + // we use this variable for fullpath loading only: in this case, RAM is always allocated, + // but we set has_battery only if RAM is actually enabled during game... + bool m_late_battery_enable; + + int m_lphaser_xoffs; + int m_sms_mode; +}; + + +// ======================> sega8_cart_slot_device + +class sega8_cart_slot_device : public device_t, + public device_image_interface, + public device_slot_interface +{ +public: + // construction/destruction + sega8_cart_slot_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, bool is_card, const char *shortname, const char *source); + sega8_cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual ~sega8_cart_slot_device(); + + // device-level overrides + virtual void device_start(); + virtual void device_config_complete() { update_names(SEGA8_CART_SLOT, "cartridge", "cart"); } + + // image-level overrides + virtual bool call_load(); + virtual void call_unload(); + virtual bool call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry); + + int get_type() { return m_type; } + int get_cart_type(UINT8 *ROM, UINT32 len); + + void setup_ram(); + void internal_header_logging(UINT8 *ROM, UINT32 len, UINT32 nvram_len); + int verify_cart(UINT8 *magic, int size); + void set_lphaser_xoffset(UINT8 *rom, int size); + + void save_ram() { if (m_cart && m_cart->get_ram_size()) m_cart->save_ram(); } + + void set_mandatory(bool val) { m_must_be_loaded = val; } + void set_intf(const char * interface) { m_interface = interface; } + void set_ext(const char * extensions) { m_extensions = extensions; } + + virtual iodevice_t image_type() const { return IO_CARTSLOT; } + virtual bool is_readable() const { return 1; } + virtual bool is_writeable() const { return 0; } + virtual bool is_creatable() const { return 0; } + virtual bool must_be_loaded() const { return m_must_be_loaded; } + virtual bool is_reset_on_load() const { return 1; } + virtual const option_guide *create_option_guide() const { return NULL; } + virtual const char *image_interface() const { return m_interface; } + virtual const char *file_extensions() const { return m_extensions; } + + // slot interface overrides + virtual void get_default_card_software(std::string &result); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_cart); + virtual DECLARE_WRITE8_MEMBER(write_cart); + virtual DECLARE_WRITE8_MEMBER(write_mapper); + virtual DECLARE_READ8_MEMBER(read_ram); + virtual DECLARE_WRITE8_MEMBER(write_ram); + + +//protected: + int m_type; + bool m_must_be_loaded, m_is_card; + const char *m_interface; + const char *m_extensions; + device_sega8_cart_interface* m_cart; +}; + +// ======================> sega8_card_slot_device + +class sega8_card_slot_device : public sega8_cart_slot_device +{ +public: + // construction/destruction + sega8_card_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual void device_config_complete() { update_names(SEGA8_CARD_SLOT, "card", "card"); } +}; + + +/*************************************************************************** + DEVICE CONFIGURATION MACROS + ***************************************************************************/ + +#define S8SLOT_ROM_REGION_TAG ":cart:rom" + + +#define MCFG_SG1000_CARTRIDGE_ADD(_tag,_slot_intf,_def_slot) \ + MCFG_DEVICE_ADD(_tag, SEGA8_CART_SLOT, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) \ + static_cast(device)->set_mandatory(TRUE); \ + static_cast(device)->set_intf("sg1000_cart"); \ + static_cast(device)->set_ext("bin,sg"); + +#define MCFG_OMV_CARTRIDGE_ADD(_tag,_slot_intf,_def_slot) \ + MCFG_DEVICE_ADD(_tag, SEGA8_CART_SLOT, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) \ + static_cast(device)->set_mandatory(FALSE); \ + static_cast(device)->set_intf("sg1000_cart"); \ + static_cast(device)->set_ext("bin,sg"); + +#define MCFG_SC3000_CARTRIDGE_ADD(_tag,_slot_intf,_def_slot) \ + MCFG_DEVICE_ADD(_tag, SEGA8_CART_SLOT, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) \ + static_cast(device)->set_mandatory(TRUE); \ + static_cast(device)->set_intf("sg1000_cart"); \ + static_cast(device)->set_ext("bin,sg,sc"); + +#define MCFG_SG1000MK3_CARTRIDGE_ADD(_tag,_slot_intf,_def_slot) \ + MCFG_DEVICE_ADD(_tag, SEGA8_CART_SLOT, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) \ + static_cast(device)->set_mandatory(FALSE); \ + static_cast(device)->set_intf("sms_cart"); \ + static_cast(device)->set_ext("bin,sms,sg"); + +#define MCFG_SMS_CARTRIDGE_ADD(_tag,_slot_intf,_def_slot) \ + MCFG_DEVICE_ADD(_tag, SEGA8_CART_SLOT, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) \ + static_cast(device)->set_mandatory(FALSE); \ + static_cast(device)->set_intf("sms_cart"); \ + static_cast(device)->set_ext("bin,sms"); + +#define MCFG_GG_CARTRIDGE_ADD(_tag,_slot_intf,_def_slot) \ + MCFG_DEVICE_ADD(_tag, SEGA8_CART_SLOT, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) \ + static_cast(device)->set_mandatory(TRUE); \ + static_cast(device)->set_intf("gamegear_cart"); \ + static_cast(device)->set_ext("bin,gg"); + + + +#define MCFG_SMS_CARD_ADD(_tag,_slot_intf,_def_slot) \ + MCFG_DEVICE_ADD(_tag, SEGA8_CARD_SLOT, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) \ + static_cast(device)->set_mandatory(FALSE); \ + static_cast(device)->set_intf("sms_card"); \ + static_cast(device)->set_ext("bin"); +#define MCFG_SG1000_CARD_ADD(_tag,_slot_intf,_def_slot) \ + MCFG_DEVICE_ADD(_tag, SEGA8_CARD_SLOT, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) \ + static_cast(device)->set_intf("sg1000_cart"); \ + static_cast(device)->set_ext("bin,sg"); + + +// slot interfaces +SLOT_INTERFACE_EXTERN( sg1000_cart ); +SLOT_INTERFACE_EXTERN( sg1000mk3_cart ); +SLOT_INTERFACE_EXTERN( sms_cart ); +SLOT_INTERFACE_EXTERN( gg_cart ); + +#endif diff --git a/src/devices/bus/sms_ctrl/graphic.c b/src/devices/bus/sms_ctrl/graphic.c new file mode 100644 index 00000000000..31d211e30a8 --- /dev/null +++ b/src/devices/bus/sms_ctrl/graphic.c @@ -0,0 +1,156 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/********************************************************************** + + Sega Master System "Graphic Board" emulation + +I/O 3f write | this method + 0x20 | 0x7f + 0x00 | 0x3f + 0x30 | 0xff + +Typical sequence: +- 3f write 0x20 +- read dc +- 3f write 0x00 +- read dc +- 3f write 0x20 +- read dc +- 3f write 0x30 +Suspect from kind of counter that is reset by a 0x30 write to I/O port 0x3f. +Once reset reads from i/O port dc expect to see 0xE0. +And then any write with differing bits goes through several internal I/O ports +with the first port being the one with the buttons + +In the reset/start state the lower four/five bits are 0. +Then a nibble is read containing the buttons (active low) +Then 2 nibbles are read to form a byte (first high nibble, then low nibble) indicating +whether the pen is on the graphic board, a value of FD, FE, or FF used for this. For +any other value the following 2 bytes are not read. +Then 2 nibbles are read to form a byte containing the absolute X coordinate. +THen 2 nibbles are read to form a byte containing the absolute Y coordiante. + +**********************************************************************/ + +#include "graphic.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type SMS_GRAPHIC = &device_creator; + + +static INPUT_PORTS_START( sms_graphic ) + PORT_START("BUTTONS") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_BUTTON1 ) // MENU + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_BUTTON2 ) // DO + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_BUTTON3 ) // PEN + PORT_BIT( 0xf8, IP_ACTIVE_LOW, IPT_UNUSED ) + + PORT_START("X") + PORT_BIT( 0xff, 0x00, IPT_LIGHTGUN_X) PORT_CROSSHAIR(X, 1.0, 0.0, 0) PORT_SENSITIVITY(50) PORT_KEYDELTA(15) + + PORT_START("Y") + PORT_BIT( 0xff, 0x00, IPT_LIGHTGUN_Y) PORT_CROSSHAIR(Y, 1.0, 0.0, 0) PORT_SENSITIVITY(50) PORT_KEYDELTA(15) +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor sms_graphic_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( sms_graphic ); +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// sms_graphic_device - constructor +//------------------------------------------------- + +sms_graphic_device::sms_graphic_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, SMS_GRAPHIC, "Sega SMS Graphic Board", tag, owner, clock, "sms_graphic", __FILE__) + , device_sms_control_port_interface(mconfig, *this) + , m_buttons(*this, "BUTTONS") + , m_x(*this, "X") + , m_y(*this, "Y") + , m_index(0) + , m_previous_write(0xff) + , m_pressure(0xfd) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void sms_graphic_device::device_start() +{ + save_item(NAME(m_index)); + save_item(NAME(m_previous_write)); +} + + +//------------------------------------------------- +// sms_peripheral_r - joypad read +//------------------------------------------------- + +UINT8 sms_graphic_device::peripheral_r() +{ + switch (m_index) + { + case 0: // Initial state / "I am a board" + // If any regular button is pressed raise/lower TL ? +// if ((m_buttons->read() & 0x07) != 0x07) +// return 0xf0; + return 0xd0; + + case 1: // Read buttons (active low) + return m_buttons->read(); + + case 2: // Some thing only FD, FE, and FF cause the other values to be read + return m_pressure >> 4; + + case 3: + return m_pressure & 0x0f; + + case 4: // High nibble X? + return m_x->read() >> 4; + + case 5: // Low nibble X? + return m_x->read() & 0x0f; + + case 6: // High nibble Y? + return m_y->read() >> 4; + + case 7: // Low Nibble Y? + return m_y->read() & 0x0f; + } + + return 0xff; +} + +void sms_graphic_device::peripheral_w(UINT8 data) +{ + // Check for toggle on TH/TL + if ((data ^ m_previous_write) & 0xc0) + { + m_index++; + } + + // If TR is high, restart + if (data & 0x80) + { + m_index = 0; + } + + m_previous_write = data; +} diff --git a/src/devices/bus/sms_ctrl/graphic.h b/src/devices/bus/sms_ctrl/graphic.h new file mode 100644 index 00000000000..852a6f7a71b --- /dev/null +++ b/src/devices/bus/sms_ctrl/graphic.h @@ -0,0 +1,59 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/********************************************************************** + + Sega Master System "Graphic Board" emulation + +**********************************************************************/ + +#pragma once + +#ifndef __SMS_GRAPHIC__ +#define __SMS_GRAPHIC__ + + +#include "emu.h" +#include "smsctrl.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> sms_graphic_device + +class sms_graphic_device : public device_t, + public device_sms_control_port_interface +{ +public: + // construction/destruction + sms_graphic_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual ioport_constructor device_input_ports() const; + +protected: + // device-level overrides + virtual void device_start(); + + // device_sms_control_port_interface overrides + virtual UINT8 peripheral_r(); + virtual void peripheral_w(UINT8 data); + +private: + required_ioport m_buttons; + required_ioport m_x; + required_ioport m_y; + + int m_index; + UINT8 m_previous_write; + UINT8 m_pressure; +}; + + +// device type definition +extern const device_type SMS_GRAPHIC; + + +#endif diff --git a/src/devices/bus/sms_ctrl/joypad.c b/src/devices/bus/sms_ctrl/joypad.c new file mode 100644 index 00000000000..b2537453c6a --- /dev/null +++ b/src/devices/bus/sms_ctrl/joypad.c @@ -0,0 +1,76 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/********************************************************************** + + Sega Master System "Control Pad"/generic joystick emulation + +**********************************************************************/ + +#include "joypad.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type SMS_JOYPAD = &device_creator; + + +static INPUT_PORTS_START( sms_joypad ) + PORT_START("JOYPAD") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_8WAY + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_8WAY + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_8WAY + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_8WAY + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_UNUSED ) // Vcc + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_BUTTON1 ) // TL + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNUSED ) // TH + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_BUTTON2 ) // TR +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor sms_joypad_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( sms_joypad ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// sms_joypad_device - constructor +//------------------------------------------------- + +sms_joypad_device::sms_joypad_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, SMS_JOYPAD, "Sega SMS Control Pad", tag, owner, clock, "sms_joypad", __FILE__), + device_sms_control_port_interface(mconfig, *this), + m_joypad(*this, "JOYPAD") +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void sms_joypad_device::device_start() +{ +} + + +//------------------------------------------------- +// sms_peripheral_r - joypad read +//------------------------------------------------- + +UINT8 sms_joypad_device::peripheral_r() +{ + return m_joypad->read(); +} diff --git a/src/devices/bus/sms_ctrl/joypad.h b/src/devices/bus/sms_ctrl/joypad.h new file mode 100644 index 00000000000..ed7b1141b03 --- /dev/null +++ b/src/devices/bus/sms_ctrl/joypad.h @@ -0,0 +1,52 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/********************************************************************** + + Sega Master System "Control Pad"/generic joystick emulation + +**********************************************************************/ + +#pragma once + +#ifndef __SMS_JOYPAD__ +#define __SMS_JOYPAD__ + + +#include "emu.h" +#include "smsctrl.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> sms_joypad_device + +class sms_joypad_device : public device_t, + public device_sms_control_port_interface +{ +public: + // construction/destruction + sms_joypad_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual ioport_constructor device_input_ports() const; + +protected: + // device-level overrides + virtual void device_start(); + + // device_sms_control_port_interface overrides + virtual UINT8 peripheral_r(); + +private: + required_ioport m_joypad; +}; + + +// device type definition +extern const device_type SMS_JOYPAD; + + +#endif diff --git a/src/devices/bus/sms_ctrl/lphaser.c b/src/devices/bus/sms_ctrl/lphaser.c new file mode 100644 index 00000000000..32998115887 --- /dev/null +++ b/src/devices/bus/sms_ctrl/lphaser.c @@ -0,0 +1,291 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/********************************************************************** + + Sega Master System "Light Phaser" (light gun) emulation + +**********************************************************************/ + +#include "lphaser.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type SMS_LIGHT_PHASER = &device_creator; + + +#define LGUN_RADIUS 6 +#define LGUN_X_INTERVAL 4 + + +CUSTOM_INPUT_MEMBER( sms_light_phaser_device::th_pin_r ) +{ + // The returned value is inverted due to IP_ACTIVE_LOW mapping. + return ~m_sensor_last_state; +} + + +INPUT_CHANGED_MEMBER( sms_light_phaser_device::position_changed ) +{ + if (newval != oldval) + sensor_check(); +} + + +static INPUT_PORTS_START( sms_light_phaser ) + PORT_START("CTRL_PORT") + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_BUTTON1 ) // TL (trigger) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_SPECIAL ) PORT_CUSTOM_MEMBER(DEVICE_SELF, sms_light_phaser_device, th_pin_r, NULL) + PORT_BIT( 0x9f, IP_ACTIVE_LOW, IPT_UNUSED ) + + PORT_START("LPHASER_X") + PORT_BIT( 0xff, 0x00, IPT_LIGHTGUN_X) PORT_CROSSHAIR(X, 1.0, 0.0, 0) PORT_SENSITIVITY(50) PORT_KEYDELTA(15) PORT_CHANGED_MEMBER(DEVICE_SELF, sms_light_phaser_device, position_changed, 0) + + PORT_START("LPHASER_Y") + PORT_BIT( 0xff, 0x00, IPT_LIGHTGUN_Y) PORT_CROSSHAIR(Y, 1.0, 0.0, 0) PORT_SENSITIVITY(50) PORT_KEYDELTA(15) PORT_CHANGED_MEMBER(DEVICE_SELF, sms_light_phaser_device, position_changed, 0) +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor sms_light_phaser_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( sms_light_phaser ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// sms_light_phaser_device - constructor +//------------------------------------------------- + +sms_light_phaser_device::sms_light_phaser_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, SMS_LIGHT_PHASER, "Sega SMS Light Phaser", tag, owner, clock, "sms_light_phaser", __FILE__), + device_video_interface(mconfig, *this), + device_sms_control_port_interface(mconfig, *this), + m_lphaser_pins(*this, "CTRL_PORT"), + m_lphaser_x(*this, "LPHASER_X"), + m_lphaser_y(*this, "LPHASER_Y") +{ + // Workaround for failed validation that occurs when running on a driver + // with Sega Scope emulation, which adds 2 screens (left/right lenses). + m_screen_tag = ":screen"; +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void sms_light_phaser_device::device_start() +{ + save_item(NAME(m_sensor_last_state)); + m_lphaser_timer = timer_alloc(TIMER_LPHASER); +} + + +void sms_light_phaser_device::device_reset() +{ + m_sensor_last_state = 1; // off (1) +} + + +//------------------------------------------------- +// sms_peripheral_r - light phaser read +//------------------------------------------------- + +UINT8 sms_light_phaser_device::peripheral_r() +{ + return m_lphaser_pins->read(); +} + + +/* + Light Phaser (light gun) emulation notes: + - The sensor is activated based on color brightness of some individual + pixels being drawn by the beam, at circular area where the gun is aiming. + - Currently, brightness is calculated based only on single pixels. + - In general, after the trigger is pressed, games draw the next frame using + a light color pattern, to make sure sensor will be activated. If emulation + skips that frame, sensor may stay deactivated. Frameskip set to 0 (no skip) + is recommended to avoid problems. + - When sensor switches from on (0) to off (1), a value is latched for the + HCount register. + - When sensor switches from off to on, a flag is set. The emulation uses the + flag to signal that TH line is activated when the status of the input port + is read. After read, the flag is cleared, or else it is cleared later when + the Pause status is read (end of a frame). This is necessary because the + "Color & Switch Test" ROM only reads the TH state after VINT occurs. + - The gun test of "Color & Switch Test" is an example that requires checks + of sensor status independent of other events, like trigger press or TH bit + reads. Another example is the title screen of "Hang-On & Safari Hunt", where + the game only reads HCount register in a loop, expecting a latch by the gun. + - The whole procedure is managed by a timer callback, that always reschedule + itself to run in some intervals when the beam is at the circular area. +*/ +int sms_light_phaser_device::bright_aim_area( emu_timer *timer, int lgun_x, int lgun_y ) +{ + const int r_x_r = LGUN_RADIUS * LGUN_RADIUS; + const rectangle &visarea = m_screen->visible_area(); + rectangle aim_area; + int beam_x = m_screen->hpos(); + int beam_y = m_screen->vpos(); + int beam_x_orig = beam_x; + int beam_y_orig = beam_y; + int dy, result = 1; + double dx_radius; + bool new_check_point = false; + + aim_area.min_y = MAX(lgun_y - LGUN_RADIUS, visarea.min_y); + aim_area.max_y = MIN(lgun_y + LGUN_RADIUS, visarea.max_y); + + while (!new_check_point) + { + /* If beam's y doesn't point to a line where the aim area is, + change it to the first line where the beam enters that area. */ + if (beam_y < aim_area.min_y || beam_y > aim_area.max_y) + { + beam_y = aim_area.min_y; + } + dy = abs(beam_y - lgun_y); + + /* Caculate distance in x of the radius, relative to beam's y distance. + First try some shortcuts. */ + switch (dy) + { + case LGUN_RADIUS: + dx_radius = 0; + break; + case 0: + dx_radius = LGUN_RADIUS; + break; + default: + /* step 1: r^2 = dx^2 + dy^2 */ + /* step 2: dx^2 = r^2 - dy^2 */ + /* step 3: dx = sqrt(r^2 - dy^2) */ + dx_radius = ceil((float) sqrt((float) (r_x_r - (dy * dy)))); + } + + aim_area.min_x = MAX(lgun_x - dx_radius, visarea.min_x); + aim_area.max_x = MIN(lgun_x + dx_radius, visarea.max_x); + + while (!new_check_point) + { + /* If beam's x has passed the aim area, change it to the + next line and go back to recheck y/x coordinates. */ + if (beam_x > aim_area.max_x) + { + beam_x = visarea.min_x; + beam_y++; + break; + } + + /* If beam's x isn't in the aim area, change it to the + next point where the beam enters that area. */ + if (beam_x < aim_area.min_x) + { + beam_x = aim_area.min_x; + } + + if (beam_x_orig != beam_x || beam_y_orig != beam_y) + { + /* adopt the new coordinates to adjust the timer */ + new_check_point = true; + break; + } + + if (m_sensor_last_state == 0) + { + /* sensor is already on */ + /* keep sensor on until out of the aim area */ + result = 0; + } + else + { + rgb_t color; + UINT8 brightness; + /* brightness of the lightgray color in the frame drawn by Light Phaser games */ + const UINT8 sensor_min_brightness = 0x7f; + + color = m_port->pixel_r(); + + /* reference: http://www.w3.org/TR/AERT#color-contrast */ + brightness = (color.r() * 0.299) + (color.g() * 0.587) + (color.b() * 0.114); + //printf ("color brightness: %2X for x %d y %d\n", brightness, beam_x, beam_y); + + result = (brightness >= sensor_min_brightness) ? 0 : 1; + } + + if (result == 0) /* sensor on */ + { + /* Set next check for when sensor will be off */ + beam_x = aim_area.max_x + 1; + + /* adopt the new coordinates to adjust the timer */ + new_check_point = true; + } + else + { + /* Next check will happen after the minimum interval */ + beam_x += LGUN_X_INTERVAL; + } + } + } + + timer->adjust(m_screen->time_until_pos(beam_y, beam_x)); + return result; +} + + +UINT16 sms_light_phaser_device::screen_hpos_nonscaled(int scaled_hpos) +{ + const rectangle &visarea = m_screen->visible_area(); + int offset_x = (scaled_hpos * (visarea.max_x - visarea.min_x)) / 255; + return visarea.min_x + offset_x; +} + + +UINT16 sms_light_phaser_device::screen_vpos_nonscaled(int scaled_vpos) +{ + const rectangle &visarea = m_screen->visible_area(); + int offset_y = (scaled_vpos * (visarea.max_y - visarea.min_y)) / 255; + return visarea.min_y + offset_y; +} + + +void sms_light_phaser_device::sensor_check() +{ + int sensor_new_state; + + const int x = screen_hpos_nonscaled(m_lphaser_x->read()); + const int y = screen_vpos_nonscaled(m_lphaser_y->read()); + + sensor_new_state = bright_aim_area(m_lphaser_timer, x, y); + if (sensor_new_state != m_sensor_last_state) + { + m_port->th_pin_w(sensor_new_state); + m_sensor_last_state = sensor_new_state; + } +} + + +void sms_light_phaser_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch (id) + { + case TIMER_LPHASER: + sensor_check(); + break; + default: + assert_always(FALSE, "Unknown id in sms_light_phaser_device::device_timer"); + } +} diff --git a/src/devices/bus/sms_ctrl/lphaser.h b/src/devices/bus/sms_ctrl/lphaser.h new file mode 100644 index 00000000000..ed0687a9f6e --- /dev/null +++ b/src/devices/bus/sms_ctrl/lphaser.h @@ -0,0 +1,69 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/********************************************************************** + + Sega Master System "Light Phaser" (light gun) emulation + +**********************************************************************/ + +#pragma once + +#ifndef __SMS_LIGHT_PHASER__ +#define __SMS_LIGHT_PHASER__ + + +#include "emu.h" +#include "smsctrl.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> sms_light_phaser_device + +class sms_light_phaser_device : public device_t, + public device_video_interface, + public device_sms_control_port_interface +{ +public: + // construction/destruction + sms_light_phaser_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual ioport_constructor device_input_ports() const; + + DECLARE_CUSTOM_INPUT_MEMBER( th_pin_r ); + DECLARE_INPUT_CHANGED_MEMBER( position_changed ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_sms_control_port_interface overrides + virtual UINT8 peripheral_r(); + +private: + required_ioport m_lphaser_pins; + required_ioport m_lphaser_x; + required_ioport m_lphaser_y; + + int m_sensor_last_state; + emu_timer *m_lphaser_timer; + static const device_timer_id TIMER_LPHASER = 0; + + void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + void sensor_check(); + int bright_aim_area( emu_timer *timer, int lgun_x, int lgun_y ); + UINT16 screen_hpos_nonscaled(int scaled_hpos); + UINT16 screen_vpos_nonscaled(int scaled_vpos); +}; + + +// device type definition +extern const device_type SMS_LIGHT_PHASER; + + +#endif diff --git a/src/devices/bus/sms_ctrl/multitap.c b/src/devices/bus/sms_ctrl/multitap.c new file mode 100644 index 00000000000..fd098b82c18 --- /dev/null +++ b/src/devices/bus/sms_ctrl/multitap.c @@ -0,0 +1,154 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/********************************************************************** + + Furrtek's homemade multitap emulation + +**********************************************************************/ + +#include "multitap.h" + + +// Scheme: http://www.smspower.org/uploads/Homebrew/BOoM-SMS-sms4p_2.png + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type SMS_MULTITAP = &device_creator; + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// sms_multitap_device - constructor +//------------------------------------------------- + +sms_multitap_device::sms_multitap_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, SMS_MULTITAP, "Sega SMS Multitap", tag, owner, clock, "sms_multitap", __FILE__), + device_sms_control_port_interface(mconfig, *this), + m_subctrl1_port(*this, "ctrl1"), + m_subctrl2_port(*this, "ctrl2"), + m_subctrl3_port(*this, "ctrl3"), + m_subctrl4_port(*this, "ctrl4"), + m_read_state(0), + m_last_data(0) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void sms_multitap_device::device_start() +{ + save_item(NAME(m_read_state)); + save_item(NAME(m_last_data)); + + m_subctrl1_port->device_start(); + m_subctrl2_port->device_start(); + m_subctrl3_port->device_start(); + m_subctrl4_port->device_start(); +} + + +//------------------------------------------------- +// sms_peripheral_r - multitap read +//------------------------------------------------- + +UINT8 sms_multitap_device::peripheral_r() +{ + UINT8 data = 0xff; + + switch(m_read_state) + { + case 0: + data = m_subctrl1_port->port_r(); + break; + case 1: + data = m_subctrl2_port->port_r(); + break; + case 2: + data = m_subctrl3_port->port_r(); + break; + case 3: + data = m_subctrl4_port->port_r(); + break; + } + + // force TH level high (1), as the line is not connected to subports. + data |= 0x40; + + return data; +} + + +//------------------------------------------------- +// sms_peripheral_w - multitap write +//------------------------------------------------- + +void sms_multitap_device::peripheral_w(UINT8 data) +{ + UINT8 output_data; + + // check if TH level is low (0) and was high (1) + if (!(data & 0x40) && (m_last_data & 0x40)) + { + m_read_state = (m_read_state + 1) & 3; + } + m_last_data = data; + + // output default TH level (1), as the line is not connected to subports. + output_data = data | 0x40; + + switch(m_read_state) + { + case 0: + m_subctrl1_port->port_w(output_data); + break; + case 1: + m_subctrl2_port->port_w(output_data); + break; + case 2: + m_subctrl3_port->port_w(output_data); + break; + case 3: + m_subctrl4_port->port_w(output_data); + break; + } +} + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +READ32_MEMBER( sms_multitap_device::pixel_r ) +{ + return m_port->pixel_r(); +} + + +static MACHINE_CONFIG_FRAGMENT( multitap_slot ) + // Controller subports setup, without the TH callback declaration, + // because the circuit scheme shows TH of subports without connection. + MCFG_SMS_CONTROL_PORT_ADD("ctrl1", sms_control_port_devices, "joypad") + MCFG_SMS_CONTROL_PORT_PIXEL_HANDLER(READ32(sms_multitap_device, pixel_r)) + MCFG_SMS_CONTROL_PORT_ADD("ctrl2", sms_control_port_devices, "joypad") + MCFG_SMS_CONTROL_PORT_PIXEL_HANDLER(READ32(sms_multitap_device, pixel_r)) + MCFG_SMS_CONTROL_PORT_ADD("ctrl3", sms_control_port_devices, "joypad") + MCFG_SMS_CONTROL_PORT_PIXEL_HANDLER(READ32(sms_multitap_device, pixel_r)) + MCFG_SMS_CONTROL_PORT_ADD("ctrl4", sms_control_port_devices, "joypad") + MCFG_SMS_CONTROL_PORT_PIXEL_HANDLER(READ32(sms_multitap_device, pixel_r)) +MACHINE_CONFIG_END + + +machine_config_constructor sms_multitap_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( multitap_slot ); +} diff --git a/src/devices/bus/sms_ctrl/multitap.h b/src/devices/bus/sms_ctrl/multitap.h new file mode 100644 index 00000000000..9fc8de8b745 --- /dev/null +++ b/src/devices/bus/sms_ctrl/multitap.h @@ -0,0 +1,59 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/********************************************************************** + + Furrtek's homemade multitap emulation + +**********************************************************************/ + +#pragma once + +#ifndef __SMS_MULTITAP__ +#define __SMS_MULTITAP__ + + +#include "emu.h" +#include "smsctrl.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> sms_multitap_device + +class sms_multitap_device : public device_t, + public device_sms_control_port_interface +{ +public: + // construction/destruction + sms_multitap_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + DECLARE_READ32_MEMBER(pixel_r); + +protected: + // device-level overrides + virtual void device_start(); + virtual machine_config_constructor device_mconfig_additions() const; + + // device_sms_control_port_interface overrides + virtual UINT8 peripheral_r(); + virtual void peripheral_w(UINT8 data); + +private: + required_device m_subctrl1_port; + required_device m_subctrl2_port; + required_device m_subctrl3_port; + required_device m_subctrl4_port; + + UINT8 m_read_state; + UINT8 m_last_data; +}; + + +// device type definition +extern const device_type SMS_MULTITAP; + + +#endif diff --git a/src/devices/bus/sms_ctrl/paddle.c b/src/devices/bus/sms_ctrl/paddle.c new file mode 100644 index 00000000000..e2418f38345 --- /dev/null +++ b/src/devices/bus/sms_ctrl/paddle.c @@ -0,0 +1,108 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/********************************************************************** + + Sega Master System "Paddle Control" emulation + +**********************************************************************/ + +#include "paddle.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type SMS_PADDLE = &device_creator; + + +#define PADDLE_INTERVAL attotime::from_hz(XTAL_53_693175MHz/15/256) + + +CUSTOM_INPUT_MEMBER( sms_paddle_device::dir_pins_r ) +{ + UINT8 data = m_paddle_x->read(); + + if (m_read_state) + data >>= 4; + + // The returned value is inverted due to IP_ACTIVE_LOW mapping. + return ~data; +} + + +CUSTOM_INPUT_MEMBER( sms_paddle_device::tr_pin_r ) +{ + // The returned value is inverted due to IP_ACTIVE_LOW mapping. + return ~m_read_state; +} + + +static INPUT_PORTS_START( sms_paddle ) + PORT_START("CTRL_PORT") + PORT_BIT( 0x0f, IP_ACTIVE_LOW, IPT_SPECIAL ) PORT_CUSTOM_MEMBER(DEVICE_SELF, sms_paddle_device, dir_pins_r, NULL) // Directional pins + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_UNUSED ) // Vcc + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_BUTTON1 ) // TL + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNUSED ) // TH + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_SPECIAL ) PORT_CUSTOM_MEMBER(DEVICE_SELF, sms_paddle_device, tr_pin_r, NULL) + + PORT_START("PADDLE_X") // Paddle knob + PORT_BIT( 0xff, 0x80, IPT_PADDLE) PORT_SENSITIVITY(40) PORT_KEYDELTA(20) PORT_CENTERDELTA(0) PORT_MINMAX(0,255) +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor sms_paddle_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( sms_paddle ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// sms_paddle_device - constructor +//------------------------------------------------- + +sms_paddle_device::sms_paddle_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, SMS_PADDLE, "Sega SMS Paddle", tag, owner, clock, "sms_paddle", __FILE__), + device_sms_control_port_interface(mconfig, *this), + m_paddle_pins(*this, "CTRL_PORT"), + m_paddle_x(*this, "PADDLE_X"), + m_read_state(0), + m_interval(PADDLE_INTERVAL) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void sms_paddle_device::device_start() +{ + m_start_time = machine().time(); + + save_item(NAME(m_start_time)); + save_item(NAME(m_read_state)); +} + + +//------------------------------------------------- +// sms_peripheral_r - paddle read +//------------------------------------------------- + +UINT8 sms_paddle_device::peripheral_r() +{ + int num_intervals = (machine().time() - m_start_time).as_double() / m_interval.as_double(); + m_read_state = num_intervals & 1; + + return m_paddle_pins->read(); +} diff --git a/src/devices/bus/sms_ctrl/paddle.h b/src/devices/bus/sms_ctrl/paddle.h new file mode 100644 index 00000000000..984b5a87082 --- /dev/null +++ b/src/devices/bus/sms_ctrl/paddle.h @@ -0,0 +1,60 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/********************************************************************** + + Sega Master System "Paddle Control" emulation + +**********************************************************************/ + +#pragma once + +#ifndef __SMS_PADDLE__ +#define __SMS_PADDLE__ + + +#include "emu.h" +#include "smsctrl.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> sms_paddle_device + +class sms_paddle_device : public device_t, + public device_sms_control_port_interface +{ +public: + // construction/destruction + sms_paddle_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual ioport_constructor device_input_ports() const; + + DECLARE_CUSTOM_INPUT_MEMBER( dir_pins_r ); + DECLARE_CUSTOM_INPUT_MEMBER( tr_pin_r ); + +protected: + // device-level overrides + virtual void device_start(); + + // device_sms_control_port_interface overrides + virtual UINT8 peripheral_r(); + +private: + required_ioport m_paddle_pins; + required_ioport m_paddle_x; + + UINT8 m_read_state; + attotime m_start_time; + const attotime m_interval; +}; + + +// device type definition +extern const device_type SMS_PADDLE; + + +#endif diff --git a/src/devices/bus/sms_ctrl/rfu.c b/src/devices/bus/sms_ctrl/rfu.c new file mode 100644 index 00000000000..3da326aa378 --- /dev/null +++ b/src/devices/bus/sms_ctrl/rfu.c @@ -0,0 +1,140 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/********************************************************************** + + Sega Master System "Rapid Fire Unit" emulation + +**********************************************************************/ + +#include "rfu.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type SMS_RAPID_FIRE = &device_creator; + + +#define RAPID_FIRE_INTERVAL attotime::from_hz(10) + + +static INPUT_PORTS_START( sms_rapid_fire ) + PORT_START("rfu_sw") // Rapid Fire Unit switches + PORT_CONFNAME( 0x03, 0x00, "Rapid Fire Unit" ) + PORT_CONFSETTING( 0x00, DEF_STR( Off ) ) + PORT_CONFSETTING( 0x01, "Button 1" ) + PORT_CONFSETTING( 0x02, "Button 2" ) + PORT_CONFSETTING( 0x03, "Button 1 + 2" ) +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor sms_rapid_fire_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( sms_rapid_fire ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// sms_rapid_fire_device - constructor +//------------------------------------------------- + +sms_rapid_fire_device::sms_rapid_fire_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, SMS_RAPID_FIRE, "Sega SMS Rapid Fire", tag, owner, clock, "sms_rapid_fire", __FILE__), + device_sms_control_port_interface(mconfig, *this), + m_rfire_sw(*this, "rfu_sw"), + m_subctrl_port(*this, "ctrl"), + m_read_state(0), + m_interval(RAPID_FIRE_INTERVAL) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void sms_rapid_fire_device::device_start() +{ + m_start_time = machine().time(); + + save_item(NAME(m_start_time)); + save_item(NAME(m_read_state)); + + m_subctrl_port->device_start(); +} + + +//------------------------------------------------- +// sms_peripheral_r - rapid fire read +//------------------------------------------------- + +UINT8 sms_rapid_fire_device::peripheral_r() +{ + UINT8 data = 0xff; + + int num_intervals = (machine().time() - m_start_time).as_double() / m_interval.as_double(); + m_read_state = num_intervals & 1; + + data = m_subctrl_port->port_r(); + + /* Check Rapid Fire switch for Button 1 (TL) */ + if (!(data & 0x20) && (m_rfire_sw->read() & 0x01)) + data |= m_read_state << 5; + + /* Check Rapid Fire switch for Button 2 (TR) */ + if (!(data & 0x80) && (m_rfire_sw->read() & 0x02)) + data |= m_read_state << 7; + + return data; +} + + +//------------------------------------------------- +// sms_peripheral_w - rapid fire write +//------------------------------------------------- + +void sms_rapid_fire_device::peripheral_w(UINT8 data) +{ + m_subctrl_port->port_w(data); +} + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +WRITE_LINE_MEMBER( sms_rapid_fire_device::th_pin_w ) +{ + m_port->th_pin_w(state); +} + + +READ32_MEMBER( sms_rapid_fire_device::pixel_r ) +{ + return m_port->pixel_r(); +} + + +static MACHINE_CONFIG_FRAGMENT( rfire_slot ) + MCFG_SMS_CONTROL_PORT_ADD("ctrl", sms_control_port_devices, "joypad") + MCFG_SMS_CONTROL_PORT_TH_INPUT_HANDLER(WRITELINE(sms_rapid_fire_device, th_pin_w)) + MCFG_SMS_CONTROL_PORT_PIXEL_HANDLER(READ32(sms_rapid_fire_device, pixel_r)) +MACHINE_CONFIG_END + + +machine_config_constructor sms_rapid_fire_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( rfire_slot ); +} diff --git a/src/devices/bus/sms_ctrl/rfu.h b/src/devices/bus/sms_ctrl/rfu.h new file mode 100644 index 00000000000..a27ef0aca02 --- /dev/null +++ b/src/devices/bus/sms_ctrl/rfu.h @@ -0,0 +1,62 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/********************************************************************** + + Sega Master System "Rapid Fire Unit" emulation + +**********************************************************************/ + +#pragma once + +#ifndef __SMS_RAPID_FIRE__ +#define __SMS_RAPID_FIRE__ + + +#include "emu.h" +#include "smsctrl.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> sms_rapid_fire_device + +class sms_rapid_fire_device : public device_t, + public device_sms_control_port_interface +{ +public: + // construction/destruction + sms_rapid_fire_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual ioport_constructor device_input_ports() const; + + DECLARE_WRITE_LINE_MEMBER(th_pin_w); + DECLARE_READ32_MEMBER(pixel_r); + +protected: + // device-level overrides + virtual void device_start(); + virtual machine_config_constructor device_mconfig_additions() const; + + // device_sms_control_port_interface overrides + virtual UINT8 peripheral_r(); + virtual void peripheral_w(UINT8 data); + +private: + required_ioport m_rfire_sw; + required_device m_subctrl_port; + + UINT8 m_read_state; + attotime m_start_time; + const attotime m_interval; +}; + + +// device type definition +extern const device_type SMS_RAPID_FIRE; + + +#endif diff --git a/src/devices/bus/sms_ctrl/smsctrl.c b/src/devices/bus/sms_ctrl/smsctrl.c new file mode 100644 index 00000000000..59536ef0f38 --- /dev/null +++ b/src/devices/bus/sms_ctrl/smsctrl.c @@ -0,0 +1,133 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/********************************************************************** + + Sega Master System controller port emulation + +**********************************************************************/ + +#include "smsctrl.h" +// slot devices +#include "joypad.h" +#include "lphaser.h" +#include "paddle.h" +#include "sports.h" +#include "sportsjp.h" +#include "rfu.h" +#include "multitap.h" +#include "graphic.h" + + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type SMS_CONTROL_PORT = &device_creator; + + + +//************************************************************************** +// CARD INTERFACE +//************************************************************************** + +//------------------------------------------------- +// device_sms_control_port_interface - constructor +//------------------------------------------------- + +device_sms_control_port_interface::device_sms_control_port_interface(const machine_config &mconfig, device_t &device) + : device_slot_card_interface(mconfig,device) +{ + m_port = dynamic_cast(device.owner()); +} + + +//------------------------------------------------- +// ~device_sms_control_port_interface - destructor +//------------------------------------------------- + +device_sms_control_port_interface::~device_sms_control_port_interface() +{ +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// sms_control_port_device - constructor +//------------------------------------------------- + +sms_control_port_device::sms_control_port_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, SMS_CONTROL_PORT, "Sega SMS control port", tag, owner, clock, "sms_control_port", __FILE__), + device_slot_interface(mconfig, *this), + m_th_pin_handler(*this), + m_pixel_handler(*this) +{ +} + + +//------------------------------------------------- +// sms_control_port_device - destructor +//------------------------------------------------- + +sms_control_port_device::~sms_control_port_device() +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void sms_control_port_device::device_start() +{ + m_device = dynamic_cast(get_card_device()); + + m_th_pin_handler.resolve_safe(); + m_pixel_handler.resolve_safe(0); +} + + +UINT8 sms_control_port_device::port_r() +{ + UINT8 data = 0xff; + if (m_device) + data = m_device->peripheral_r(); + return data; +} + +void sms_control_port_device::port_w( UINT8 data ) +{ + if (m_device) + m_device->peripheral_w(data); +} + + +void sms_control_port_device::th_pin_w(int state) +{ + m_th_pin_handler(state); +} + +UINT32 sms_control_port_device::pixel_r() +{ + return m_pixel_handler(); +} + + +//------------------------------------------------- +// SLOT_INTERFACE( sms_control_port_devices ) +//------------------------------------------------- + +SLOT_INTERFACE_START( sms_control_port_devices ) + SLOT_INTERFACE("joypad", SMS_JOYPAD) + SLOT_INTERFACE("lphaser", SMS_LIGHT_PHASER) + SLOT_INTERFACE("paddle", SMS_PADDLE) + SLOT_INTERFACE("sportspad", SMS_SPORTS_PAD) + SLOT_INTERFACE("sportspadjp", SMS_SPORTS_PAD_JP) + SLOT_INTERFACE("rapidfire", SMS_RAPID_FIRE) + SLOT_INTERFACE("multitap", SMS_MULTITAP) + SLOT_INTERFACE("graphic", SMS_GRAPHIC) +SLOT_INTERFACE_END diff --git a/src/devices/bus/sms_ctrl/smsctrl.h b/src/devices/bus/sms_ctrl/smsctrl.h new file mode 100644 index 00000000000..950e620c99b --- /dev/null +++ b/src/devices/bus/sms_ctrl/smsctrl.h @@ -0,0 +1,118 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/********************************************************************** + + Sega Master System controller port emulation + +********************************************************************** + + +**********************************************************************/ + +#pragma once + +#ifndef __SMS_CONTROL_PORT__ +#define __SMS_CONTROL_PORT__ + +#include "emu.h" + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_SMS_CONTROL_PORT_ADD(_tag, _slot_intf, _def_slot) \ + MCFG_DEVICE_ADD(_tag, SMS_CONTROL_PORT, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) +#define MCFG_SMS_CONTROL_PORT_MODIFY(_tag) \ + MCFG_DEVICE_MODIFY(_tag) + + +#define MCFG_SMS_CONTROL_PORT_TH_INPUT_HANDLER(_devcb) \ + devcb = &sms_control_port_device::set_th_input_handler(*device, DEVCB_##_devcb); + + +#define MCFG_SMS_CONTROL_PORT_PIXEL_HANDLER(_devcb) \ + devcb = &sms_control_port_device::set_pixel_handler(*device, DEVCB_##_devcb); + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> sms_control_port_device + +class device_sms_control_port_interface; + +class sms_control_port_device : public device_t, + public device_slot_interface +{ +public: + // construction/destruction + sms_control_port_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual ~sms_control_port_device(); + + // static configuration helpers + template static devcb_base &set_th_input_handler(device_t &device, _Object object) { return downcast(device).m_th_pin_handler.set_callback(object); } + + template static devcb_base &set_pixel_handler(device_t &device, _Object object) { return downcast(device).m_pixel_handler.set_callback(object); } + + // Physical DE-9 connector interface + + // Data returned by the port_r methods: + // bit 0 - pin 1 - Up + // bit 1 - pin 2 - Down + // bit 2 - pin 3 - Left + // bit 3 - pin 4 - Right + // bit 4 - pin 5 - Vcc (no data) + // bit 5 - pin 6 - TL (Button 1/Light Phaser Trigger) + // bit 6 - pin 7 - TH (Light Phaser sensor) + // pin 8 - GND + // bit 7 - pin 9 - TR (Button 2) + // + UINT8 port_r(); + void port_w( UINT8 data ); + + void th_pin_w(int state); + UINT32 pixel_r(); + +//protected: + // device-level overrides + virtual void device_start(); + + device_sms_control_port_interface *m_device; + +private: + devcb_write_line m_th_pin_handler; + devcb_read32 m_pixel_handler; +}; + + +// ======================> device_sms_control_port_interface + +// class representing interface-specific live sms_expansion card +class device_sms_control_port_interface : public device_slot_card_interface +{ +public: + // construction/destruction + device_sms_control_port_interface(const machine_config &mconfig, device_t &device); + virtual ~device_sms_control_port_interface(); + + virtual UINT8 peripheral_r() { return 0xff; }; + virtual void peripheral_w(UINT8 data) { }; + +protected: + sms_control_port_device *m_port; +}; + + +// device type definition +extern const device_type SMS_CONTROL_PORT; + + +SLOT_INTERFACE_EXTERN( sms_control_port_devices ); + + +#endif diff --git a/src/devices/bus/sms_ctrl/sports.c b/src/devices/bus/sms_ctrl/sports.c new file mode 100644 index 00000000000..f5bc15e170b --- /dev/null +++ b/src/devices/bus/sms_ctrl/sports.c @@ -0,0 +1,158 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/********************************************************************** + + Sega Master System "Sports Pad" (US model) emulation + +**********************************************************************/ + +#include "sports.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type SMS_SPORTS_PAD = &device_creator; + + +#define SPORTS_PAD_INTERVAL attotime::from_hz(XTAL_53_693175MHz/15/512) + + +CUSTOM_INPUT_MEMBER( sms_sports_pad_device::dir_pins_r ) +{ + UINT8 data = 0; + + switch (m_read_state) + { + case 0: + data = m_sports_x->read() >> 4; + break; + case 1: + data = m_sports_x->read(); + break; + case 2: + data = m_sports_y->read() >> 4; + break; + case 3: + data = m_sports_y->read(); + break; + } + + // The returned value is inverted due to IP_ACTIVE_LOW mapping. + return ~(data & 0x0f); +} + + +CUSTOM_INPUT_MEMBER( sms_sports_pad_device::th_pin_r ) +{ + return m_last_data; +} + + +INPUT_CHANGED_MEMBER( sms_sports_pad_device::th_pin_w ) +{ + attotime cur_time = machine().time(); + + if (cur_time - m_last_time > m_interval) + { + m_read_state = 0; + } + else + { + m_read_state = (m_read_state + 1) & 3; + } + m_last_time = cur_time; + m_last_data = newval; +} + + +static INPUT_PORTS_START( sms_sports_pad ) + PORT_START("SPORTS_IN") + PORT_BIT( 0x0f, IP_ACTIVE_LOW, IPT_SPECIAL ) PORT_CUSTOM_MEMBER(DEVICE_SELF, sms_sports_pad_device, dir_pins_r, NULL) // Directional pins + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_UNUSED ) // Vcc + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_BUTTON1 ) // TL (Button 1) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_SPECIAL ) PORT_CUSTOM_MEMBER(DEVICE_SELF, sms_sports_pad_device, th_pin_r, NULL) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_BUTTON2 ) // TR (Button 2) + + PORT_START("SPORTS_OUT") + PORT_BIT( 0x0f, IP_ACTIVE_LOW, IPT_UNUSED ) // Directional pins + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_UNUSED ) // Vcc + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_UNUSED ) // TL (Button 1) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_OUTPUT ) PORT_CHANGED_MEMBER(DEVICE_SELF, sms_sports_pad_device, th_pin_w, NULL) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNUSED ) // TR (Button 2) + + PORT_START("SPORTS_X") /* Sports Pad X axis */ + PORT_BIT( 0xff, 0x00, IPT_TRACKBALL_X ) PORT_SENSITIVITY(50) PORT_KEYDELTA(40) PORT_RESET PORT_REVERSE + + PORT_START("SPORTS_Y") /* Sports Pad Y axis */ + PORT_BIT( 0xff, 0x00, IPT_TRACKBALL_Y ) PORT_SENSITIVITY(50) PORT_KEYDELTA(40) PORT_RESET PORT_REVERSE +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor sms_sports_pad_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( sms_sports_pad ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// sms_sports_pad_device - constructor +//------------------------------------------------- + +sms_sports_pad_device::sms_sports_pad_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, SMS_SPORTS_PAD, "Sega SMS Sports Pad US", tag, owner, clock, "sms_sports_pad", __FILE__), + device_sms_control_port_interface(mconfig, *this), + m_sports_in(*this, "SPORTS_IN"), + m_sports_out(*this, "SPORTS_OUT"), + m_sports_x(*this, "SPORTS_X"), + m_sports_y(*this, "SPORTS_Y"), + m_read_state(0), + m_last_data(0), + m_interval(SPORTS_PAD_INTERVAL) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void sms_sports_pad_device::device_start() +{ + m_last_time = machine().time(); + + save_item(NAME(m_read_state)); + save_item(NAME(m_last_data)); + save_item(NAME(m_last_time)); +} + + +//------------------------------------------------- +// sms_peripheral_r - sports pad read +//------------------------------------------------- + +UINT8 sms_sports_pad_device::peripheral_r() +{ + return m_sports_in->read(); +} + + +//------------------------------------------------- +// sms_peripheral_w - sports pad write +//------------------------------------------------- + +void sms_sports_pad_device::peripheral_w(UINT8 data) +{ + m_sports_out->write(data); +} diff --git a/src/devices/bus/sms_ctrl/sports.h b/src/devices/bus/sms_ctrl/sports.h new file mode 100644 index 00000000000..b0efde2abe8 --- /dev/null +++ b/src/devices/bus/sms_ctrl/sports.h @@ -0,0 +1,65 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/********************************************************************** + + Sega Master System "Sports Pad" (US model) emulation + +**********************************************************************/ + +#pragma once + +#ifndef __SMS_SPORTS_PAD__ +#define __SMS_SPORTS_PAD__ + + +#include "emu.h" +#include "smsctrl.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> sms_sports_pad_device + +class sms_sports_pad_device : public device_t, + public device_sms_control_port_interface +{ +public: + // construction/destruction + sms_sports_pad_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual ioport_constructor device_input_ports() const; + + DECLARE_CUSTOM_INPUT_MEMBER( dir_pins_r ); + DECLARE_CUSTOM_INPUT_MEMBER( th_pin_r ); + DECLARE_INPUT_CHANGED_MEMBER( th_pin_w ); + +protected: + // device-level overrides + virtual void device_start(); + + // device_sms_control_port_interface overrides + virtual UINT8 peripheral_r(); + virtual void peripheral_w(UINT8 data); + +private: + required_ioport m_sports_in; + required_ioport m_sports_out; + required_ioport m_sports_x; + required_ioport m_sports_y; + + UINT8 m_read_state; + UINT8 m_last_data; + const attotime m_interval; + attotime m_last_time; +}; + + +// device type definition +extern const device_type SMS_SPORTS_PAD; + + +#endif diff --git a/src/devices/bus/sms_ctrl/sportsjp.c b/src/devices/bus/sms_ctrl/sportsjp.c new file mode 100644 index 00000000000..d431f0a6816 --- /dev/null +++ b/src/devices/bus/sms_ctrl/sportsjp.c @@ -0,0 +1,156 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/********************************************************************** + + Sega Master System "Sports Pad" (Japanese model) emulation + +**********************************************************************/ + +// The Japanese Sports Pad controller is only required to play the cartridge +// Sports Pad Soccer, released in Japan. It uses a different mode than the +// used by the US model, due to missing output lines on Sega Mark III +// controller ports. + +#include "sportsjp.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type SMS_SPORTS_PAD_JP = &device_creator; + + +#define SPORTS_PAD_JP_INTERVAL attotime::from_hz(30000) // 30Hz (not measured) + + +DECLARE_CUSTOM_INPUT_MEMBER( sms_sports_pad_jp_device::dir_pins_r ) +{ + UINT8 data = 0; + + switch (m_read_state) + { + case 0: + data = m_sports_jp_x->read() >> 4; + break; + case 1: + data = m_sports_jp_x->read(); + break; + case 2: + data = m_sports_jp_y->read() >> 4; + break; + case 3: + data = m_sports_jp_y->read(); + break; + } + + // The returned value is inverted due to IP_ACTIVE_LOW mapping. + return ~(data & 0x0f); +} + + +static INPUT_PORTS_START( sms_sports_pad_jp ) + PORT_START("SPORTS_JP_IN") + PORT_BIT( 0x0f, IP_ACTIVE_LOW, IPT_SPECIAL ) PORT_CUSTOM_MEMBER(DEVICE_SELF, sms_sports_pad_jp_device, dir_pins_r, NULL) // Directional pins + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_UNUSED ) // Vcc + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_BUTTON1 ) // TL (Button 1) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNUSED ) // TH + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_BUTTON2 ) // TR (Button 2) + + PORT_START("SPORTS_JP_X") /* Sports Pad X axis */ + PORT_BIT( 0xff, 0x00, IPT_TRACKBALL_X ) PORT_SENSITIVITY(50) PORT_KEYDELTA(40) + + PORT_START("SPORTS_JP_Y") /* Sports Pad Y axis */ + PORT_BIT( 0xff, 0x00, IPT_TRACKBALL_Y ) PORT_SENSITIVITY(50) PORT_KEYDELTA(40) +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor sms_sports_pad_jp_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( sms_sports_pad_jp ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// sms_sports_pad_jp_device - constructor +//------------------------------------------------- + +sms_sports_pad_jp_device::sms_sports_pad_jp_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, SMS_SPORTS_PAD_JP, "Sega SMS Sports Pad JP", tag, owner, clock, "sms_sports_pad_jp", __FILE__), + device_sms_control_port_interface(mconfig, *this), + m_sports_jp_in(*this, "SPORTS_JP_IN"), + m_sports_jp_x(*this, "SPORTS_JP_X"), + m_sports_jp_y(*this, "SPORTS_JP_Y"), + m_read_state(0), + m_interval(SPORTS_PAD_JP_INTERVAL) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void sms_sports_pad_jp_device::device_start() +{ + m_start_time = machine().time(); + + save_item(NAME(m_start_time)); + save_item(NAME(m_read_state)); +} + + +//------------------------------------------------- +// sms_peripheral_r - sports pad read +//------------------------------------------------- + +UINT8 sms_sports_pad_jp_device::peripheral_r() +{ + UINT8 data; + int num_intervals = (machine().time() - m_start_time).as_double() / m_interval.as_double(); + m_read_state = num_intervals % 5; + + data = m_sports_jp_in->read(); + + switch (m_read_state) + { + case 0: + // X high nibble + data &= ~0x20; // TL 0 + data &= ~0x80; // TR 0 + break; + case 1: + // X low nibble + data |= 0x20; // TL 1 + data &= ~0x80; // TR 0 + break; + case 2: + // Y high nibble + data &= ~0x20; // TL 0 + data &= ~0x80; // TR 0 + break; + case 3: + // Y low nibble + data |= 0x20; // TL 1 + data &= ~0x80; // TR 0 + break; + case 4: + // buttons 1 and 2 + data = (data & 0x20) >> 5 | (data & 0x80) >> 6 | 0xfc; + data |= 0x20; // TL 1 + data |= 0x80; // TR 1 + break; + } + + return data; +} diff --git a/src/devices/bus/sms_ctrl/sportsjp.h b/src/devices/bus/sms_ctrl/sportsjp.h new file mode 100644 index 00000000000..082546221e6 --- /dev/null +++ b/src/devices/bus/sms_ctrl/sportsjp.h @@ -0,0 +1,65 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/********************************************************************** + + Sega Master System "Sports Pad" (Japanese model) emulation + +**********************************************************************/ + +// The Japanese Sports Pad controller is only required to play the cartridge +// Sports Pad Soccer, released in Japan. It uses a different mode than the +// used by the US model, due to missing output lines on Sega Mark III +// controller ports. + +#pragma once + +#ifndef __SMS_SPORTS_PAD_JP__ +#define __SMS_SPORTS_PAD_JP__ + + +#include "emu.h" +#include "smsctrl.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> sms_sports_pad_jp_device + +class sms_sports_pad_jp_device : public device_t, + public device_sms_control_port_interface +{ +public: + // construction/destruction + sms_sports_pad_jp_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual ioport_constructor device_input_ports() const; + + CUSTOM_INPUT_MEMBER( dir_pins_r ); + +protected: + // device-level overrides + virtual void device_start(); + + // device_sms_control_port_interface overrides + virtual UINT8 peripheral_r(); + +private: + required_ioport m_sports_jp_in; + required_ioport m_sports_jp_x; + required_ioport m_sports_jp_y; + + UINT8 m_read_state; + attotime m_start_time; + const attotime m_interval; +}; + + +// device type definition +extern const device_type SMS_SPORTS_PAD_JP; + + +#endif diff --git a/src/devices/bus/sms_exp/gender.c b/src/devices/bus/sms_exp/gender.c new file mode 100644 index 00000000000..4ef55b1ffe5 --- /dev/null +++ b/src/devices/bus/sms_exp/gender.c @@ -0,0 +1,103 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/********************************************************************** + + Sega Master System "Gender Adapter" emulation + +**********************************************************************/ + +#include "gender.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type SMS_GENDER_ADAPTER = &device_creator; + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// sms_gender_adapter_device - constructor +//------------------------------------------------- + +sms_gender_adapter_device::sms_gender_adapter_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, SMS_GENDER_ADAPTER, "Gender Adapter", tag, owner, clock, "sms_gender_adapter", __FILE__), + device_sms_expansion_slot_interface(mconfig, *this), + m_subslot(*this, "subslot") +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void sms_gender_adapter_device::device_start() +{ + if (m_subslot->m_cart) + m_subslot->m_cart->save_ram(); +} + + +//------------------------------------------------- +// read +//------------------------------------------------- + +READ8_MEMBER(sms_gender_adapter_device::read) +{ + return m_subslot->read_cart(space, offset); +} + +READ8_MEMBER(sms_gender_adapter_device::read_ram) +{ + return m_subslot->read_ram(space, offset); +} + +int sms_gender_adapter_device::get_lphaser_xoffs() +{ + if (m_subslot->m_cart) + return m_subslot->m_cart->get_lphaser_xoffs(); + else + return 0; +} + + +//------------------------------------------------- +// write +//------------------------------------------------- + +WRITE8_MEMBER(sms_gender_adapter_device::write_mapper) +{ + m_subslot->write_mapper(space, offset, data); +} + +WRITE8_MEMBER(sms_gender_adapter_device::write) +{ + m_subslot->write_cart(space, offset, data); +} + +WRITE8_MEMBER(sms_gender_adapter_device::write_ram) +{ + m_subslot->write_ram(space, offset, data); +} + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( genderadp_slot ) + MCFG_SMS_CARTRIDGE_ADD("subslot", sms_cart, NULL) +MACHINE_CONFIG_END + + +machine_config_constructor sms_gender_adapter_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( genderadp_slot ); +} diff --git a/src/devices/bus/sms_exp/gender.h b/src/devices/bus/sms_exp/gender.h new file mode 100644 index 00000000000..2b8503da968 --- /dev/null +++ b/src/devices/bus/sms_exp/gender.h @@ -0,0 +1,57 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/********************************************************************** + + Sega Master System "Gender Adapter" emulation + +**********************************************************************/ + +#pragma once + +#ifndef __SMS_GENDER_ADAPTER__ +#define __SMS_GENDER_ADAPTER__ + + +#include "emu.h" +#include "smsexp.h" +#include "bus/sega8/sega8_slot.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> sms_gender_adapter_device + +class sms_gender_adapter_device : public device_t, + public device_sms_expansion_slot_interface +{ +public: + // construction/destruction + sms_gender_adapter_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device_sms_expansion_slot_interface overrides + virtual DECLARE_READ8_MEMBER(read); + virtual DECLARE_WRITE8_MEMBER(write); + virtual DECLARE_WRITE8_MEMBER(write_mapper); + virtual DECLARE_READ8_MEMBER(read_ram); + virtual DECLARE_WRITE8_MEMBER(write_ram); + + virtual int get_lphaser_xoffs(); + +protected: + // device-level overrides + virtual void device_start(); + virtual machine_config_constructor device_mconfig_additions() const; + +private: + required_device m_subslot; +}; + + +// device type definition +extern const device_type SMS_GENDER_ADAPTER; + + +#endif diff --git a/src/devices/bus/sms_exp/smsexp.c b/src/devices/bus/sms_exp/smsexp.c new file mode 100644 index 00000000000..9b26999a94b --- /dev/null +++ b/src/devices/bus/sms_exp/smsexp.c @@ -0,0 +1,137 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/********************************************************************** + + Sega Master System expansion slot emulation + +**********************************************************************/ + +#include "smsexp.h" + + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type SMS_EXPANSION_SLOT = &device_creator; + + + +//************************************************************************** +// CARD INTERFACE +//************************************************************************** + +//------------------------------------------------- +// device_sms_expansion_slot_interface - constructor +//------------------------------------------------- + +device_sms_expansion_slot_interface::device_sms_expansion_slot_interface(const machine_config &mconfig, device_t &device) + : device_slot_card_interface(mconfig,device) +{ +} + + +//------------------------------------------------- +// ~device_sms_expansion_slot_interface - destructor +//------------------------------------------------- + +device_sms_expansion_slot_interface::~device_sms_expansion_slot_interface() +{ +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// sms_expansion_slot_device - constructor +//------------------------------------------------- + +sms_expansion_slot_device::sms_expansion_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, SMS_EXPANSION_SLOT, "Sega SMS expansion slot", tag, owner, clock, "sms_expansion_slot", __FILE__), + device_slot_interface(mconfig, *this) +{ +} + + +//------------------------------------------------- +// sms_expansion_slot_device - destructor +//------------------------------------------------- + +sms_expansion_slot_device::~sms_expansion_slot_device() +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void sms_expansion_slot_device::device_start() +{ + m_device = dynamic_cast(get_card_device()); +} + + +//------------------------------------------------- +// read +//------------------------------------------------- + +READ8_MEMBER(sms_expansion_slot_device::read) +{ + if (m_device) + return m_device->read(space, offset); + else + return 0xff; +} + +READ8_MEMBER(sms_expansion_slot_device::read_ram) +{ + if (m_device) + return m_device->read_ram(space, offset); + else + return 0xff; +} + +int sms_expansion_slot_device::get_lphaser_xoffs() +{ + if (m_device) + return m_device->get_lphaser_xoffs(); + else + return 0; +} + + +//------------------------------------------------- +// write +//------------------------------------------------- + +WRITE8_MEMBER(sms_expansion_slot_device::write_mapper) +{ + if (m_device) + m_device->write_mapper(space, offset, data); +} + +WRITE8_MEMBER(sms_expansion_slot_device::write) +{ + if (m_device) + m_device->write(space, offset, data); +} + +WRITE8_MEMBER(sms_expansion_slot_device::write_ram) +{ + if (m_device) + m_device->write_ram(space, offset, data); +} + + +//------------------------------------------------- +// SLOT_INTERFACE( sms_expansion_devices ) +//------------------------------------------------- + +SLOT_INTERFACE_START( sms_expansion_devices ) + SLOT_INTERFACE("genderadp", SMS_GENDER_ADAPTER) +SLOT_INTERFACE_END diff --git a/src/devices/bus/sms_exp/smsexp.h b/src/devices/bus/sms_exp/smsexp.h new file mode 100644 index 00000000000..58d1a33228d --- /dev/null +++ b/src/devices/bus/sms_exp/smsexp.h @@ -0,0 +1,95 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/********************************************************************** + + Sega Master System expansion slot emulation + +********************************************************************** + + +**********************************************************************/ + +#pragma once + +#ifndef __SMS_EXPANSION_SLOT__ +#define __SMS_EXPANSION_SLOT__ + +#include "emu.h" + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_SMS_EXPANSION_ADD(_tag, _slot_intf, _def_slot) \ + MCFG_DEVICE_ADD(_tag, SMS_EXPANSION_SLOT, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> sms_expansion_slot_device + +class device_sms_expansion_slot_interface; + +class sms_expansion_slot_device : public device_t, + public device_slot_interface +{ +public: + // construction/destruction + sms_expansion_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual ~sms_expansion_slot_device(); + + // reading and writing + DECLARE_READ8_MEMBER(read); + DECLARE_WRITE8_MEMBER(write); + DECLARE_WRITE8_MEMBER(write_mapper); + DECLARE_READ8_MEMBER(read_ram); + DECLARE_WRITE8_MEMBER(write_ram); + + int get_lphaser_xoffs(); + + device_sms_expansion_slot_interface *m_device; + +protected: + // device-level overrides + virtual void device_start(); +}; + + +// ======================> device_sms_expansion_slot_interface + +// class representing interface-specific live sms_expansion card +class device_sms_expansion_slot_interface : public device_slot_card_interface +{ +public: + // construction/destruction + device_sms_expansion_slot_interface(const machine_config &mconfig, device_t &device); + virtual ~device_sms_expansion_slot_interface(); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read) { return 0xff; }; + virtual DECLARE_WRITE8_MEMBER(write) { }; + virtual DECLARE_WRITE8_MEMBER(write_mapper) {}; + virtual DECLARE_READ8_MEMBER(read_ram) { return 0xff; }; + virtual DECLARE_WRITE8_MEMBER(write_ram) { }; + + virtual int get_lphaser_xoffs() { return 0; }; +}; + + +// device type definition +extern const device_type SMS_EXPANSION_SLOT; + + +// slot devices +#include "gender.h" + +SLOT_INTERFACE_EXTERN( sms_expansion_devices ); + + +#endif diff --git a/src/devices/bus/snes/bsx.c b/src/devices/bus/snes/bsx.c new file mode 100644 index 00000000000..08fa68dc082 --- /dev/null +++ b/src/devices/bus/snes/bsx.c @@ -0,0 +1,546 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + BS-X Satellaview cartridge emulation (for SNES/SFC) + + ***********************************************************************************************************/ + + +// TODO: Emulate FLASH memory... (possibly using flash device?) + + +#include "emu.h" +#include "bsx.h" + + +//------------------------------------------------- +// sns_rom_bsx_device - constructor +//------------------------------------------------- + +const device_type SNS_ROM_BSX = &device_creator; +const device_type SNS_LOROM_BSX = &device_creator; +const device_type SNS_HIROM_BSX = &device_creator; +const device_type SNS_BSMEMPAK = &device_creator; + + +sns_rom_bsx_device::sns_rom_bsx_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : sns_rom_device(mconfig, type, name, tag, owner, clock, shortname, source), + m_slot(*this, "bs_slot") +{ +} + +sns_rom_bsx_device::sns_rom_bsx_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : sns_rom_device(mconfig, SNS_ROM_BSX, "SNES BS-X Cart", tag, owner, clock, "sns_rom_bsx", __FILE__), + m_slot(*this, "bs_slot") +{ +} + +sns_rom_bsxlo_device::sns_rom_bsxlo_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : sns_rom_device(mconfig, SNS_LOROM_BSX, "SNES Cart (LoROM) + BS-X slot", tag, owner, clock, "sns_rom_bsxlo", __FILE__), + m_slot(*this, "bs_slot") +{ +} + +sns_rom_bsxhi_device::sns_rom_bsxhi_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : sns_rom21_device(mconfig, SNS_HIROM_BSX, "SNES Cart (HiROM) + BS-X slot", tag, owner, clock, "sns_rom_bsxhi", __FILE__), + m_slot(*this, "bs_slot") +{ +} + +sns_rom_bsmempak_device::sns_rom_bsmempak_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : sns_rom_device(mconfig, SNS_BSMEMPAK, "SNES BS-X Memory packs", tag, owner, clock, "sns_bsmempak", __FILE__) +{ +} + + +void sns_rom_bsx_device::device_start() +{ + m_base_unit = auto_alloc(machine(), BSX_base(machine())); + m_base_unit->init(); + + memset(m_cart_regs, 0x00, sizeof(m_cart_regs)); + m_cart_regs[7] = 0x80; + m_cart_regs[8] = 0x80; + access_update(); + + save_item(NAME(m_cart_regs)); + save_item(NAME(access_00_1f)); + save_item(NAME(access_80_9f)); + save_item(NAME(access_40_4f)); + save_item(NAME(access_50_5f)); + save_item(NAME(access_60_6f)); + save_item(NAME(rom_access)); + save_item(NAME(m_pram)); +} + +void sns_rom_bsx_device::device_reset() +{ + memset(m_pram, 0xff, sizeof(m_pram)); +} + +void sns_rom_bsxlo_device::device_start() +{ +} + +void sns_rom_bsxhi_device::device_start() +{ +} + +void sns_rom_bsmempak_device::device_start() +{ + save_item(NAME(m_command)); + save_item(NAME(m_write_old)); + save_item(NAME(m_write_new)); + save_item(NAME(m_flash_enable)); + save_item(NAME(m_read_enable)); + save_item(NAME(m_write_enable)); +} + +void sns_rom_bsmempak_device::device_reset() +{ + m_command = 0; + m_write_old = 0; + m_write_new = 0; + + m_flash_enable = 0; + m_read_enable = 0; + m_write_enable = 0; +} + + + +// BS-X Base Unit emulation, to be device-fied ? + +BSX_base::BSX_base(running_machine &machine) + : m_machine(machine) +{ + m_machine.save().save_item(regs, "SNES_BSX/regs"); + m_machine.save().save_item(r2192_counter, "SNES_BSX/r2192_counter"); + m_machine.save().save_item(r2192_hour, "SNES_BSX/r2192_hour"); + m_machine.save().save_item(r2192_second, "SNES_BSX/r2192_second"); +} + +void BSX_base::init() +{ + memset(regs, 0x00, sizeof(regs)); + r2192_counter = 0; + r2192_hour = 0; + r2192_minute = 0; + r2192_second = 0; +} + + +UINT8 BSX_base::read(UINT32 offset) +{ + offset &= 0xffff; + if (offset < 0x2188 || offset >= 0x21a0) + { + osd_printf_debug("BS-X Base Unit reg read outside correct range!\n"); + return 0x00; + } + + switch (offset) + { + // no 218b? no 218d? no 2191? no 2195? no 219a-219f? + case 0x2192: + { + UINT8 counter = r2192_counter++; + if (r2192_counter >= 18) + r2192_counter = 0; + + if (counter == 0) + { + system_time curtime, *systime = &curtime; + m_machine.current_datetime(curtime); + r2192_hour = systime->local_time.hour; + r2192_minute = systime->local_time.minute; + r2192_second = systime->local_time.second; + } + + switch (counter) + { + case 0: return 0x00; //??? + case 1: return 0x00; //??? + case 2: return 0x00; //??? + case 3: return 0x00; //??? + case 4: return 0x00; //??? + case 5: return 0x01; + case 6: return 0x01; + case 7: return 0x00; + case 8: return 0x00; + case 9: return 0x00; + case 10: return r2192_second; + case 11: return r2192_minute; + case 12: return r2192_hour; + case 13: return 0x00; //??? + case 14: return 0x00; //??? + case 15: return 0x00; //??? + case 16: return 0x00; //??? + case 17: return 0x00; //??? + } + } + break; + + case 0x2193: + return regs[offset - 0x2188] & ~0x0c; + + default: + return regs[offset - 0x2188]; + } + + return 0x00; +} + + +void BSX_base::write(UINT32 offset, UINT8 data) +{ + offset &= 0xffff; + if (offset < 0x2188 || offset >= 0x21a0) + { + osd_printf_debug("BS-X Base Unit reg write outside correct range!\n"); + return; + } + + switch(offset) + { + // no 218d? no 2190? no 2195? no 2196? no 2198? no 219a-219f? + case 0x218f: + regs[6] >>= 1; // 0x218e + regs[6] = regs[7] - regs[6]; // 0x218f - 0x218e + regs[7] >>= 1; // 0x218f + break; + + case 0x2191: + regs[offset - 0x2188] = data; + r2192_counter = 0; + break; + + case 0x2192: + regs[8] = data; // sets 0x2190 + break; + + default: + regs[offset - 0x2188] = data; + break; + } +} + +//------------------------------------------------- +// MACHINE_CONFIG_FRAGMENT( bs_slot ) +//------------------------------------------------- + +static SLOT_INTERFACE_START(bsx_cart) + SLOT_INTERFACE_INTERNAL("bsmempak", SNS_BSMEMPAK) +SLOT_INTERFACE_END + +static MACHINE_CONFIG_FRAGMENT( bs_slot ) + MCFG_SNS_BSX_CARTRIDGE_ADD("bs_slot", bsx_cart, NULL) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor sns_rom_bsx_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( bs_slot ); +} + +machine_config_constructor sns_rom_bsxlo_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( bs_slot ); +} + +machine_config_constructor sns_rom_bsxhi_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( bs_slot ); +} + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +// BS-X base + cart + +void sns_rom_bsx_device::access_update() +{ + access_00_1f = BIT(m_cart_regs[0x07], 7); + access_40_4f = !BIT(m_cart_regs[0x05], 7); + access_50_5f = !BIT(m_cart_regs[0x06], 7); + access_60_6f = BIT(m_cart_regs[0x03], 7); + access_80_9f = BIT(m_cart_regs[0x08], 7); + if (BIT(m_cart_regs[0x01], 7)) + rom_access = 0; + else + { +// rom_access = BIT(m_cart_regs[0x02], 7) + 1; + rom_access = 1; // for whatever reason bsxsore changes access mode here and then fails to read the ROM properly! + printf("rom_access %s\n", !BIT(m_cart_regs[0x02], 7) ? "Lo" : "Hi"); + } +} + +READ8_MEMBER(sns_rom_bsx_device::read_l) +{ + if (offset < 0x200000 && access_00_1f) + { + // 0x00-0x1f:0x8000-0xffff -> CART + if (m_slot->m_cart && m_slot->m_cart->get_rom_size()) + return m_slot->m_cart->read_l(space, offset); + } + if (offset >= 0x200000 && offset < 0x400000) + { + // 0x20-0x3f:0x6000-0x7fff -> PRAM + if ((offset & 0xffff) >= 0x6000 && (offset & 0xffff) < 0x8000) + return m_pram[offset & 0xffff]; + } + if (offset >= 0x400000 && offset < 0x500000 && access_40_4f) + { + // 0x40-0x4f:0x0000-0xffff -> PRAM + return m_pram[offset & 0x7ffff]; + } + if (offset >= 0x500000 && offset < 0x600000 && access_50_5f) + { + // 0x50-0x5f:0x0000-0xffff -> PRAM + return m_pram[offset & 0x7ffff]; + } + if (offset >= 0x600000 && offset < 0x700000 && access_60_6f) + { + // 0x60-0x6f:0x0000-0xffff -> PRAM + return m_pram[offset & 0x7ffff]; + } + if (offset >= 0x700000 && offset < 0x780000) + { + // 0x70-0x77:0x0000-0xffff -> PRAM + return m_pram[offset & 0x7ffff]; + } + + // if not in any of the cases above... + //$00-3f|80-bf:8000-ffff + //$40-7f|c0-ff:0000-ffff + if (!rom_access) + return m_pram[offset & 0x7ffff]; + else + { + int bank = (rom_access == 1) ? (offset / 0x10000) : (offset / 0x8000); + return m_rom[rom_bank_map[bank] * 0x8000 + (offset & 0x7fff)]; + } + + // never executed + //return 0x00; +} + + +READ8_MEMBER(sns_rom_bsx_device::read_h) +{ + if (offset < 0x200000 && access_80_9f) + { + // 0x80-0x9f:0x8000-0xffff -> CART + if (m_slot->m_cart && m_slot->m_cart->get_rom_size()) + return m_slot->m_cart->read_l(space, offset); + } + + // if not in any of the cases above... + //$00-3f|80-bf:8000-ffff + //$40-7f|c0-ff:0000-ffff + if (!rom_access) + return m_pram[offset & 0x7ffff]; + else + { + int bank = (rom_access == 1) ? (offset / 0x10000) : (offset / 0x8000); + return m_rom[rom_bank_map[bank] * 0x8000 + (offset & 0x7fff)]; + } + + // never executed + //return 0x00; +} + +WRITE8_MEMBER(sns_rom_bsx_device::write_l) +{ + if (offset < 0x200000 && access_00_1f) + { + // write to cart... + return; + } + if (offset >= 0x200000 && offset < 0x400000) + { + // 0x20-0x3f:0x6000-0x7fff -> PRAM + if ((offset & 0xffff) >= 0x6000 && (offset & 0xffff) < 0x8000) + m_pram[offset & 0xffff] = data; + } + if (offset >= 0x400000 && offset < 0x500000 && access_40_4f) + { + // 0x40-0x4f:0x0000-0xffff -> PRAM + m_pram[offset & 0x7ffff] = data; + } + if (offset >= 0x500000 && offset < 0x600000 && access_50_5f) + { + // 0x50-0x5f:0x0000-0xffff -> PRAM + m_pram[offset & 0x7ffff] = data; + } + if (offset >= 0x600000 && offset < 0x700000 && access_60_6f) + { + // 0x60-0x6f:0x0000-0xffff -> PRAM + m_pram[offset & 0x7ffff] = data; + } + if (offset >= 0x700000 && offset < 0x780000) + { + // 0x70-0x77:0x0000-0xffff -> PRAM + m_pram[offset & 0x7ffff] = data; + } + + // if not in any of the cases above... + //$00-3f|80-bf:8000-ffff + //$40-7f|c0-ff:0000-ffff + if (!rom_access) + m_pram[offset & 0x7ffff] = data; +} + + +WRITE8_MEMBER(sns_rom_bsx_device::write_h) +{ + if (offset < 0x200000 && access_80_9f) + { + // write to cart... + return; + } + + // if not in any of the cases above... + //$00-3f|80-bf:8000-ffff + //$40-7f|c0-ff:0000-ffff + if (!rom_access) + m_pram[offset & 0x7ffff] = data; +} + + +READ8_MEMBER(sns_rom_bsx_device::chip_read) +{ + if ((offset & 0xffff) >= 0x2188 && (offset & 0xffff) < 0x21a0) + return m_base_unit->read(offset & 0xffff); + + if ((offset & 0xf0ffff) == 0x005000) //$[00-0f]:5000 reg access + { + UINT8 n = (offset >> 16) & 0x0f; + return m_cart_regs[n]; + } + + if ((offset & 0xf8f000) == 0x105000) //$[10-17]:[5000-5fff] SRAM access + { + return m_nvram[((offset >> 16) & 7) * 0x1000 + (offset & 0xfff)]; + } + + return 0x00; +} + +WRITE8_MEMBER(sns_rom_bsx_device::chip_write) +{ + if ((offset & 0xffff) >= 0x2188 && (offset & 0xffff) < 0x21a0) + m_base_unit->write(offset & 0xffff, data); + + if ((offset & 0xf0ffff) == 0x005000) //$[00-0f]:5000 reg access + { + UINT8 n = (offset >> 16) & 0x0f; + m_cart_regs[n] = data; + if (n == 0x0e && data & 0x80) + access_update(); + } + + if ((offset & 0xf8f000) == 0x105000) //$[10-17]:[5000-5fff] SRAM access + { + m_nvram[((offset >> 16) & 7) * 0x1000 + (offset & 0xfff)] = data; + } +} + + +// LoROM cart w/BS-X slot + +READ8_MEMBER(sns_rom_bsxlo_device::read_l) +{ + if (offset < 0x400000) + { + int bank = offset / 0x10000; + return m_rom[rom_bank_map[bank] * 0x8000 + (offset & 0x7fff)]; + } + // nothing [40-6f] + // RAM [70-7f] + return 0x00; +} + +READ8_MEMBER(sns_rom_bsxlo_device::read_h) +{ + if (offset < 0x400000) + { + int bank = offset / 0x10000; + if (offset < 0x200000) + bank += 64; + return m_rom[rom_bank_map[bank] * 0x8000 + (offset & 0x7fff)]; + } + else if (offset < 0x700000) + { + if (m_slot->m_cart && m_slot->m_cart->get_rom_size()) + return m_slot->m_cart->read_h(space, offset); + } + // RAM [70-7f] + return 0x00; +} + + +// HiROM cart w/BS-X slot + +READ8_MEMBER(sns_rom_bsxhi_device::read_l) +{ + return read_h(space, offset); +} + +READ8_MEMBER(sns_rom_bsxhi_device::read_h) +{ + if (offset < 0x200000 && (offset & 0xffff) >= 0x8000) + { + int bank = offset / 0x8000; + return m_rom[rom_bank_map[bank] * 0x8000 + (offset & 0x7fff)]; + } + if (offset >= 0x200000 && offset < 0x400000) + { + if (m_slot->m_cart && m_slot->m_cart->get_rom_size() && (offset & 0xffff) >= 0x8000) + return m_slot->m_cart->read_h(space, offset); + } + if (offset >= 0x400000 && offset < 0x600000) + { + // TODO: Ongaku Tsukuru Kanadeeru does not like accesses in 0x0000-0x8000 here... investigate... + int bank = offset / 0x8000; + return m_rom[rom_bank_map[bank] * 0x8000 + (offset & 0x7fff)]; + } + if (offset >= 0x600000) + { + if (m_slot->m_cart && m_slot->m_cart->get_rom_size()) + return m_slot->m_cart->read_h(space, offset); + } + return 0xff; +} + +/*------------------------------------------------- + BS-X Memory Packs + -------------------------------------------------*/ + +// Here we're cheating a bit, for the moment, to avoid the need of BSX mempacks as a completely different device +// which would require separate loading routines +// Hence, we use low read handler for ROM access in the 0x8000-0xffff range (i.e. mempack mapped as LoROM) and +// hi read handler for ROM access in the 0x0000-0xffff range (i.e. mempack mapped as HiROM)... + +READ8_MEMBER(sns_rom_bsmempak_device::read_l) +{ + int bank = offset / 0x10000; + return m_rom[rom_bank_map[bank] * 0x8000 + (offset & 0x7fff)]; +} + +READ8_MEMBER(sns_rom_bsmempak_device::read_h) +{ + int bank = offset / 0x8000; + return m_rom[rom_bank_map[bank] * 0x8000 + (offset & 0x7fff)]; +} + +WRITE8_MEMBER(sns_rom_bsmempak_device::write_l) +{ +} diff --git a/src/devices/bus/snes/bsx.h b/src/devices/bus/snes/bsx.h new file mode 100644 index 00000000000..a91e713560d --- /dev/null +++ b/src/devices/bus/snes/bsx.h @@ -0,0 +1,151 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __SNS_BSX_H +#define __SNS_BSX_H + +#include "snes_slot.h" +#include "rom.h" +#include "rom21.h" + +class BSX_base +{ +public: + BSX_base(running_machine &machine); + running_machine &machine() const { return m_machine; } + + void init(); + UINT8 read(UINT32 offset); + void write(UINT32 offset, UINT8 data); + +private: + // regs + UINT8 regs[0x18]; // 0x2188-0x219f + + // counter + clock + UINT8 r2192_counter; + UINT8 r2192_hour, r2192_minute, r2192_second; + + running_machine& m_machine; +}; + +// ======================> sns_rom_bsx_device + +class sns_rom_bsx_device : public sns_rom_device +{ +public: + // construction/destruction + sns_rom_bsx_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + sns_rom_bsx_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual machine_config_constructor device_mconfig_additions() const; + + // additional reading and writing + virtual DECLARE_READ8_MEMBER(read_l); + virtual DECLARE_READ8_MEMBER(read_h); + virtual DECLARE_WRITE8_MEMBER(write_l); + virtual DECLARE_WRITE8_MEMBER(write_h); + virtual DECLARE_READ8_MEMBER(chip_read); + virtual DECLARE_WRITE8_MEMBER(chip_write); + + // base regs + BSX_base *m_base_unit; + + // cart regs + UINT8 m_cart_regs[16]; + UINT8 access_00_1f; // 1 = CART, 0 = NOTHING + UINT8 access_80_9f; // 1 = CART, 0 = NOTHING + UINT8 access_40_4f; // 1 = NOTHING, 0 = PRAM + UINT8 access_50_5f; // 1 = NOTHING, 0 = PRAM + UINT8 access_60_6f; // 1 = PRAM, 0 = NOTHING + UINT8 rom_access; // 2 = HiROM, 1 = LoROM, 0 = PRAM + void access_update(); + + + UINT8 m_pram[0x80000]; + +private: + required_device m_slot; +}; + +// ======================> sns_rom_bsxlo_device + +class sns_rom_bsxlo_device : public sns_rom_device +{ +public: + // construction/destruction + sns_rom_bsxlo_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual machine_config_constructor device_mconfig_additions() const; + + // additional reading and writing + virtual DECLARE_READ8_MEMBER(read_l); + virtual DECLARE_READ8_MEMBER(read_h); + +private: + required_device m_slot; +}; + +// ======================> sns_rom_bsxhi_device + +class sns_rom_bsxhi_device : public sns_rom21_device +{ +public: + // construction/destruction + sns_rom_bsxhi_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual machine_config_constructor device_mconfig_additions() const; + + // additional reading and writing + virtual DECLARE_READ8_MEMBER(read_l); + virtual DECLARE_READ8_MEMBER(read_h); + +private: + required_device m_slot; +}; + + +// ======================> sns_rom_bsmempak_device + +class sns_rom_bsmempak_device : public sns_rom_device +{ +public: + // construction/destruction + sns_rom_bsmempak_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // additional reading and writing + virtual DECLARE_READ8_MEMBER(read_l); + virtual DECLARE_READ8_MEMBER(read_h); + virtual DECLARE_WRITE8_MEMBER(write_l); +// virtual DECLARE_WRITE8_MEMBER(write_h); +// virtual DECLARE_READ8_MEMBER(chip_read); +// virtual DECLARE_WRITE8_MEMBER(chip_write); + + // flash regs + UINT32 m_command; + UINT8 m_write_old; + UINT8 m_write_new; + + int m_flash_enable; + int m_read_enable; + int m_write_enable; +}; + + +// device type definition +extern const device_type SNS_ROM_BSX; +extern const device_type SNS_LOROM_BSX; +extern const device_type SNS_HIROM_BSX; +extern const device_type SNS_BSMEMPAK; + +#endif diff --git a/src/devices/bus/snes/event.c b/src/devices/bus/snes/event.c new file mode 100644 index 00000000000..ebd203adaad --- /dev/null +++ b/src/devices/bus/snes/event.c @@ -0,0 +1,285 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + Super NES/Famicom Event cartridges emulation (for SNES/SFC) + + TODO: figure out how the Test Mode switch works... + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "event.h" + + +//------------------------------------------------- +// sns_rom_device - constructor +//------------------------------------------------- + +const device_type SNS_PFEST94 = &device_creator; + + +sns_pfest94_device::sns_pfest94_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, SNS_PFEST94, "SNES Powerfest '94", tag, owner, clock, "sns_pfest94", __FILE__), + device_sns_cart_interface( mconfig, *this ), + m_upd7725(*this, "dsp"), + m_dsw(*this, "DIPSW") +{ +} + + +void sns_pfest94_device::device_start() +{ + m_dsp_prg.resize(0x2000/sizeof(UINT32)); + m_dsp_data.resize(0x800/sizeof(UINT16)); + pfest94_timer = timer_alloc(TIMER_EVENT); + pfest94_timer->reset(); + + save_item(NAME(m_base_bank)); + save_item(NAME(m_mask)); + save_item(NAME(m_status)); + save_item(NAME(m_count)); +} + +void sns_pfest94_device::device_reset() +{ + m_base_bank = 0; + m_mask = 0x07; + m_status = 0; + m_count = 0; +} + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +READ8_MEMBER(sns_pfest94_device::read_l) +{ + // menu + if ((offset & 0x208000) == 0x208000) + { + int bank = ((offset - 0x200000) / 0x10000) & 7; + return m_rom[rom_bank_map[bank] * 0x8000 + (offset & 0x7fff)]; + } + else + { + // never called beyond 0x400000! + offset &= 0x1fffff; + int bank = (m_base_bank == 0x18) ? offset / 0x8000 : offset / 0x10000; + return m_rom[rom_bank_map[m_base_bank + (bank & m_mask)] * 0x8000 + (offset & 0x7fff)]; + } +} + +READ8_MEMBER(sns_pfest94_device::read_h) +{ + // menu + if ((offset & 0x208000) == 0x208000) + { + int bank = ((offset - 0x200000) / 0x8000) & 7; + return m_rom[rom_bank_map[bank] * 0x8000 + (offset & 0x7fff)]; + } + + // called beyond 0x400000! + if (offset < 0x400000) + { + offset &= 0x1fffff; + int bank = (m_base_bank == 0x18) ? offset / 0x8000 : offset / 0x10000; + return m_rom[rom_bank_map[m_base_bank + (bank & m_mask)] * 0x8000 + (offset & 0x7fff)]; + } + else + { + offset &= 0x3fffff; + int bank = offset / 0x8000; + return m_rom[rom_bank_map[m_base_bank + (bank & m_mask)] * 0x8000 + (offset & 0x7fff)]; + } +} + + +// these are used for two diff effects: both to select game from menu and to access the DSP when running SMK! +READ8_MEMBER( sns_pfest94_device::chip_read ) +{ + if (offset & 0x8000) + { + // menu access + return m_status; + } + else + { + // DSP access + offset &= 0x1fff; + return m_upd7725->snesdsp_read(offset < 0x1000); + } +} + + +WRITE8_MEMBER( sns_pfest94_device::chip_write ) +{ + if (offset & 0x8000) + { + // menu access + if (data == 0x00) + { + m_base_bank = 0; + m_mask = 0x07; + } + if (data == 0x09) + { + m_base_bank = 0x08; + m_mask = 0x0f; + // start timer + m_count = (3 + ((m_dsw->read() & 0xf0) >> 4)) * 60; + pfest94_timer->adjust(attotime::zero, 0, attotime::from_seconds(1)); + } + if (data == 0x0c) + { + m_base_bank = 0x18; + m_mask = 0x0f; + } + if (data == 0x0a) + { + m_base_bank = 0x28; + m_mask = 0x1f; + } + } + else + { + // DSP access + offset &= 0x1fff; + m_upd7725->snesdsp_write(offset < 0x1000, data); + } +} + + +//------------------------------------------------- +// NEC DSP +//------------------------------------------------- + +// helpers +inline UINT32 get_prg(UINT8 *CPU, UINT32 addr) +{ + return ((CPU[addr * 4] << 24) | (CPU[addr * 4 + 1] << 16) | (CPU[addr * 4 + 2] << 8) | 0x00); +} +inline UINT16 get_data(UINT8 *CPU, UINT32 addr) +{ + return ((CPU[addr * 2] << 8) | CPU[addr * 2 + 1]); +} + +void sns_pfest94_device::speedup_addon_bios_access() +{ + m_upd7725->space(AS_PROGRAM).install_read_bank(0x0000, 0x07ff, "dsp_prg"); + m_upd7725->space(AS_DATA).install_read_bank(0x0000, 0x03ff, "dsp_data"); + membank("dsp_prg")->set_base(&m_dsp_prg[0]); + membank("dsp_data")->set_base(&m_dsp_data[0]); + // copy data in the correct format + for (int x = 0; x < 0x800; x++) + m_dsp_prg[x] = (m_bios[x * 4] << 24) | (m_bios[x * 4 + 1] << 16) | (m_bios[x * 4 + 2] << 8) | 0x00; + for (int x = 0; x < 0x400; x++) + m_dsp_data[x] = (m_bios[0x2000 + x * 2] << 8) | m_bios[0x2000 + x * 2 + 1]; +} + + +// DSP dump contains prg at offset 0 and data at offset 0x2000 +READ32_MEMBER( sns_pfest94_device::necdsp_prg_r ) +{ + return get_prg(&m_bios[0], offset); +} + +READ16_MEMBER( sns_pfest94_device::necdsp_data_r ) +{ + return get_data(&m_bios[0], offset + 0x2000/2); +} + + +//------------------------------------------------- +// ADDRESS_MAP( dsp_prg_map ) +//------------------------------------------------- + +static ADDRESS_MAP_START( dsp_prg_map_lorom, AS_PROGRAM, 32, sns_pfest94_device ) + AM_RANGE(0x0000, 0x07ff) AM_READ(necdsp_prg_r) +ADDRESS_MAP_END + + +//------------------------------------------------- +// ADDRESS_MAP( dsp_data_map ) +//------------------------------------------------- + +static ADDRESS_MAP_START( dsp_data_map_lorom, AS_DATA, 16, sns_pfest94_device ) + AM_RANGE(0x0000, 0x03ff) AM_READ(necdsp_data_r) +ADDRESS_MAP_END + + +//------------------------------------------------- +// MACHINE_DRIVER( snes_dsp ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( snes_dsp_pfest94 ) + MCFG_CPU_ADD("dsp", UPD7725, 8000000) + MCFG_CPU_PROGRAM_MAP(dsp_prg_map_lorom) + MCFG_CPU_DATA_MAP(dsp_data_map_lorom) +MACHINE_CONFIG_END + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor sns_pfest94_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( snes_dsp_pfest94 ); +} + +//------------------------------------------------- +// Dipswicth +//------------------------------------------------- + +static INPUT_PORTS_START( pfest94_dsw ) + PORT_START("DIPSW") + PORT_DIPUNUSED(0x03, 0x00) + PORT_DIPNAME( 0x04, 0x00, "Test Mode" ) + PORT_DIPSETTING( 0x00, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x04, DEF_STR( On ) ) + PORT_DIPUNUSED(0x08, 0x08) + PORT_DIPNAME( 0xf0, 0x30, "Timer" ) + PORT_DIPSETTING( 0x00, "3 Minutes" ) + PORT_DIPSETTING( 0x10, "4 Minutes" ) + PORT_DIPSETTING( 0x20, "5 Minutes" ) + PORT_DIPSETTING( 0x30, "6 Minutes" ) + PORT_DIPSETTING( 0x40, "7 Minutes" ) + PORT_DIPSETTING( 0x50, "8 Minutes" ) + PORT_DIPSETTING( 0x60, "9 Minutes" ) + PORT_DIPSETTING( 0x70, "10 Minutes" ) + PORT_DIPSETTING( 0x80, "11 Minutes" ) + PORT_DIPSETTING( 0x90, "12 Minutes" ) + PORT_DIPSETTING( 0xa0, "13 Minutes" ) + PORT_DIPSETTING( 0xb0, "14 Minutes" ) + PORT_DIPSETTING( 0xc0, "15 Minutes" ) + PORT_DIPSETTING( 0xd0, "16 Minutes" ) + PORT_DIPSETTING( 0xe0, "17 Minutes" ) + PORT_DIPSETTING( 0xf0, "18 Minutes" ) +INPUT_PORTS_END + + +ioport_constructor sns_pfest94_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( pfest94_dsw ); +} + + +//------------------------------------------------- +// device_timer - handler timer events +//------------------------------------------------- + +void sns_pfest94_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + if (id == TIMER_EVENT) + { + if (!m_count) + { + m_status |= 2; + pfest94_timer->reset(); + } + m_count--; + } +} diff --git a/src/devices/bus/snes/event.h b/src/devices/bus/snes/event.h new file mode 100644 index 00000000000..1bd3e0c97e0 --- /dev/null +++ b/src/devices/bus/snes/event.h @@ -0,0 +1,57 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __SNS_EVENT_H +#define __SNS_EVENT_H + +#include "snes_slot.h" +#include "cpu/upd7725/upd7725.h" + + +// ======================> sns_pfest94_device + +class sns_pfest94_device : public device_t, + public device_sns_cart_interface +{ +public: + // construction/destruction + sns_pfest94_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + virtual machine_config_constructor device_mconfig_additions() const; + virtual ioport_constructor device_input_ports() const; + + required_device m_upd7725; + required_ioport m_dsw; + + virtual void speedup_addon_bios_access(); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_l); + virtual DECLARE_READ8_MEMBER(read_h); + virtual DECLARE_READ8_MEMBER(chip_read); + virtual DECLARE_WRITE8_MEMBER(chip_write); + + virtual DECLARE_READ32_MEMBER(necdsp_prg_r); + virtual DECLARE_READ16_MEMBER(necdsp_data_r); + +private: + UINT8 m_base_bank; + UINT8 m_mask; + UINT8 m_status; + UINT32 m_count; + + std::vector m_dsp_prg; + std::vector m_dsp_data; + + static const device_timer_id TIMER_EVENT = 0; + emu_timer *pfest94_timer; +}; + + +// device type definition +extern const device_type SNS_PFEST94; + +#endif diff --git a/src/devices/bus/snes/rom.c b/src/devices/bus/snes/rom.c new file mode 100644 index 00000000000..9e77da8dda5 --- /dev/null +++ b/src/devices/bus/snes/rom.c @@ -0,0 +1,510 @@ +// license:GPL-2.0+ +// copyright-holders:Fabio Priuli, byuu +/*********************************************************************************************************** + + Super NES/Famicom (LoROM) cartridge emulation (for SNES/SFC) + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "rom.h" + + +//------------------------------------------------- +// sns_rom_device - constructor +//------------------------------------------------- + +const device_type SNS_LOROM = &device_creator; +const device_type SNS_LOROM_OBC1 = &device_creator; +// LoROM pirate carts with protection +const device_type SNS_LOROM_POKEMON = &device_creator; +const device_type SNS_LOROM_TEKKEN2 = &device_creator; +const device_type SNS_LOROM_SOULBLAD = &device_creator; +const device_type SNS_LOROM_BANANA = &device_creator; +const device_type SNS_LOROM_BUGSLIFE = &device_creator; +// LoROM pirate multicarts +const device_type SNS_LOROM_MCPIR1 = &device_creator; +const device_type SNS_LOROM_MCPIR2 = &device_creator; +const device_type SNS_LOROM_20COL = &device_creator; + + +sns_rom_device::sns_rom_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_sns_cart_interface( mconfig, *this ) +{ +} + +sns_rom_device::sns_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, SNS_LOROM, "SNES Cart (LoROM)", tag, owner, clock, "sns_rom", __FILE__), + device_sns_cart_interface( mconfig, *this ) +{ +} + +sns_rom_obc1_device::sns_rom_obc1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : sns_rom_device(mconfig, SNS_LOROM_OBC1, "SNES Cart (LoROM) + OBC-1", tag, owner, clock, "sns_rom_obc1", __FILE__) +{ +} + + + +// Pirate LoROM 'mappers' +sns_rom_pokemon_device::sns_rom_pokemon_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : sns_rom_device(mconfig, SNS_LOROM_POKEMON, "SNES Pirate Carts with Protection", tag, owner, clock, "sns_rom_pokemon", __FILE__) +{ +} + +sns_rom_tekken2_device::sns_rom_tekken2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : sns_rom_device(mconfig, SNS_LOROM_TEKKEN2, "SNES Tekken 2", tag, owner, clock, "sns_rom_tekken2", __FILE__) +{ +} + +sns_rom_soulblad_device::sns_rom_soulblad_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : sns_rom_device(mconfig, SNS_LOROM_SOULBLAD, "SNES Soul Blade", tag, owner, clock, "sns_rom_soulblad", __FILE__) +{ +} + +sns_rom_banana_device::sns_rom_banana_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : sns_rom_device(mconfig, SNS_LOROM_BANANA, "SNES Banana de Pijamas", tag, owner, clock, "sns_rom_banana", __FILE__) +{ +} + +sns_rom_bugs_device::sns_rom_bugs_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : sns_rom_device(mconfig, SNS_LOROM_BUGSLIFE, "SNES A Bug's Life", tag, owner, clock, "sns_rom_bugslife", __FILE__) +{ +} + +// Multigame LoROM 'mappers' +sns_rom_mcpirate1_device::sns_rom_mcpirate1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : sns_rom_device(mconfig, SNS_LOROM_MCPIR1, "SNES Pirate Multigame Carts Type 1", tag, owner, clock, "sns_rom_mcpirate1", __FILE__) +{ +} + +sns_rom_mcpirate2_device::sns_rom_mcpirate2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : sns_rom_device(mconfig, SNS_LOROM_MCPIR2, "SNES Pirate Multigame Carts Type 2", tag, owner, clock, "sns_rom_mcpirate2", __FILE__) +{ +} + +sns_rom_20col_device::sns_rom_20col_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : sns_rom_device(mconfig, SNS_LOROM_20COL, "SNES Super 20 Collection", tag, owner, clock, "sns_rom_20col", __FILE__) +{ +} + + +void sns_rom_device::device_start() +{ +} + +void sns_rom_obc1_device::device_start() +{ + save_item(NAME(m_ram)); + save_item(NAME(m_address)); + save_item(NAME(m_offset)); + save_item(NAME(m_shift)); +} + +void sns_rom_obc1_device::device_reset() +{ + memset(m_ram, 0xff, sizeof(m_ram)); + // or from rom? + m_offset = (m_ram[0x1ff5] & 0x01) ? 0x1800 : 0x1c00; + m_address = (m_ram[0x1ff6] & 0x7f); + m_shift = (m_ram[0x1ff6] & 0x03) << 1; +} + + +void sns_rom_pokemon_device::device_start() +{ + save_item(NAME(m_latch)); +} + +void sns_rom_pokemon_device::device_reset() +{ + m_latch = 0; +} + +void sns_rom_tekken2_device::device_start() +{ + save_item(NAME(m_prot)); +} + +void sns_rom_tekken2_device::device_reset() +{ + m_prot = 0; +} + +void sns_rom_bugs_device::device_start() +{ + save_item(NAME(m_latch)); +} + +void sns_rom_bugs_device::device_reset() +{ + memset(m_latch, 0, sizeof(m_latch)); +} + + + +void sns_rom_mcpirate1_device::device_start() +{ + m_base_bank = 0; + save_item(NAME(m_base_bank)); +} + +void sns_rom_mcpirate1_device::device_reset() +{ +} + +void sns_rom_mcpirate2_device::device_start() +{ + m_base_bank = 0; + save_item(NAME(m_base_bank)); +} + +void sns_rom_mcpirate2_device::device_reset() +{ +} + +void sns_rom_20col_device::device_start() +{ + m_base_bank = 4; + save_item(NAME(m_base_bank)); +} + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +READ8_MEMBER(sns_rom_device::read_l) +{ + return read_h(space, offset); +} + +READ8_MEMBER(sns_rom_device::read_h) +{ + int bank = offset / 0x10000; + return m_rom[rom_bank_map[bank] * 0x8000 + (offset & 0x7fff)]; +} + + + +// Lo-ROM + OBC-1 (used by Metal Combat - Falcon's Revenge) +// same as above but additional read/write handling for the add-on chip + +/*************************************************************************** + + Based on C++ implementation by Byuu in BSNES. + + Byuu's code is released under GNU General Public License + version 2 as published by the Free Software Foundation. + + ***********************************************************************************************************/ + + +READ8_MEMBER( sns_rom_obc1_device::chip_read ) +{ + UINT16 address = offset & 0x1fff; + UINT8 value; + + switch (address) + { + case 0x1ff0: + value = m_ram[m_offset + (m_address << 2) + 0]; + break; + + case 0x1ff1: + value = m_ram[m_offset + (m_address << 2) + 1]; + break; + + case 0x1ff2: + value = m_ram[m_offset + (m_address << 2) + 2]; + break; + + case 0x1ff3: + value = m_ram[m_offset + (m_address << 2) + 3]; + break; + + case 0x1ff4: + value = m_ram[m_offset + (m_address >> 2) + 0x200]; + break; + + default: + value = m_ram[address]; + break; + } + + return value; +} + + +WRITE8_MEMBER( sns_rom_obc1_device::chip_write ) +{ + UINT16 address = offset & 0x1fff; + UINT8 temp; + + switch(address) + { + case 0x1ff0: + m_ram[m_offset + (m_address << 2) + 0] = data; + break; + + case 0x1ff1: + m_ram[m_offset + (m_address << 2) + 1] = data; + break; + + case 0x1ff2: + m_ram[m_offset + (m_address << 2) + 2] = data; + break; + + case 0x1ff3: + m_ram[m_offset + (m_address << 2) + 3] = data; + break; + + case 0x1ff4: + temp = m_ram[m_offset + (m_address >> 2) + 0x200]; + temp = (temp & ~(3 << m_shift)) | ((data & 0x03) << m_shift); + m_ram[m_offset + (m_address >> 2) + 0x200] = temp; + break; + + case 0x1ff5: + m_offset = (data & 0x01) ? 0x1800 : 0x1c00; + m_ram[address & 0x1fff] = data; + break; + + case 0x1ff6: + m_address = data & 0x7f; + m_shift = (data & 0x03) << 1; + m_ram[address & 0x1fff] = data; + break; + + default: + m_ram[address & 0x1fff] = data; + break; + } +} + + + +// Lo-ROM + Protection devices used in pirate carts + + +// Pokemon (and many others): a byte is written and a permutation of its bits must be returned. +// Address range for read/write depends on the game (check snes.xml) +READ8_MEMBER( sns_rom_pokemon_device::chip_read ) +{ + return BITSWAP8(m_latch,0,6,7,1,2,3,4,5); +} + +WRITE8_MEMBER( sns_rom_pokemon_device::chip_write ) +{ + m_latch = data; +} + + +// Tekken 2: It accesses the protection in a very strange way, always reading/writing the same data $f0 times, +// because each access must be repeated a couple of times to be registered (typically around 7-30 times) +// They probably used a microcontroller here. +// The protection itself is accessed in banks $80-$bf. Accessing (read/write, doesn't matter) address lines +// A8,A9,A10 in these banks in a certain sequence makes the mc return a 4bit value. [d4s] +// Details on a possible algorythm behind the sequence of accesses were provided by nocash. Thanks! +void sns_rom_tekken2_device::update_prot(UINT32 offset) +{ + // accesses to [80-bf][8000-87ff] ranges update the protection value + offset &= 0x7ff; + + switch (offset & 0x700) + { + case 0x000: + m_prot = 0; + break; + case 0x100: + // used for read access + break; + case 0x200: // BIT 0 + m_prot |= 1; + break; + case 0x300: // BIT 1 + m_prot |= 2; + break; + case 0x400: // BIT 2 + m_prot |= 4; + break; + case 0x500: // BIT 3 + m_prot |= 8; + break; + case 0x600: // DIRECTION + m_prot |= 0x10; + break; + case 0x700: // FUNCTION + m_prot |= 0x20; + break; + } +} + +READ8_MEMBER( sns_rom_tekken2_device::chip_read ) +{ + update_prot(offset); + + if ((offset & 0x700) == 0x100) + { + if (BIT(m_prot, 5)) // FUNCTION = 1 means Shift + { + if (BIT(m_prot, 4)) // DIRECTION = 1 means Right + return (m_prot & 0x0f) >> 1; + else // DIRECTION = 0 means Left + return (m_prot & 0x0f) << 1; + } + else // FUNCTION = 0 means Add/Sub + { + if (BIT(m_prot, 4)) // DIRECTION = 1 means Minus + return (m_prot & 0x0f) - 1; + else // DIRECTION = 0 means Plus + return (m_prot & 0x0f) + 1; + } + } + + return 0xff; // should be open_bus +} + +WRITE8_MEMBER( sns_rom_tekken2_device::chip_write ) +{ + update_prot(offset); +} + + +// Soul Blade: Adresses $xxx0-$xxx3 in banks $80-$bf always read $55, $0f, $aa, $f0. +// Banks $c0-$ff return open bus. +READ8_MEMBER( sns_rom_soulblad_device::chip_read ) +{ + UINT8 value = 0; + offset &= 3; + switch (offset) + { + case 0: + default: + value = 0x55; + break; + case 1: + value = 0x0f; + break; + case 2: + value = 0xaa; + break; + case 3: + value = 0xf0; + break; + } + return value; +} + +// Multicart pirate banking emulation +// LoROM games, writes to [ff][ff00-ffff] control bankswitch +// The actual banks depends on the last 8bits of the address accessed. + +// Type 1: bits0-4 of the address are used as base bank (256KB chunks) +READ8_MEMBER(sns_rom_mcpirate1_device::read_l) +{ + return read_h(space, offset); +} + +READ8_MEMBER(sns_rom_mcpirate1_device::read_h) +{ + int bank = (offset / 0x10000) + (m_base_bank * 8); + return m_rom[rom_bank_map[bank] * 0x8000 + (offset & 0x7fff)]; +} + +WRITE8_MEMBER( sns_rom_mcpirate1_device::chip_write ) +{ + m_base_bank = offset & 0x1f; +// printf("offset %X data %X bank %X\n", offset, data, m_base_bank); +} + +// Type 2: bits0-3 & bit5 of the address are used as base bank (256KB chunks) +READ8_MEMBER(sns_rom_mcpirate2_device::read_l) +{ + return read_h(space, offset); +} + +READ8_MEMBER(sns_rom_mcpirate2_device::read_h) +{ + int bank = (offset / 0x10000) + (m_base_bank * 8); + return m_rom[rom_bank_map[bank] * 0x8000 + (offset & 0x7fff)]; +} + +WRITE8_MEMBER( sns_rom_mcpirate2_device::chip_write ) +{ + m_base_bank = (offset & 0x0f) | ((offset & 0x20) >> 1); +// printf("offset %X data %X bank %X\n", offset, data, m_base_bank); +} + +// Korean 20 in 1 collection with NES games +// - base bank is selected (in 32KB chunks) by bits 0-4 of data written at 0x808000 +// - bits 6-7 seem related to prg size: 0x00 means 4*32KB, 0xc0 means 2*32KB, 0x80 means 1*32KB +// (they are used to setup how large is the ROM to be accessed, games 15-20 don't work well if +// accesses in [01-3f] don't go to the only 32KB bank) +// - bit 5 is always 0 +// it's worth to notice that for FC games size of bank is twice the size of original FC PRG +READ8_MEMBER(sns_rom_20col_device::read_l) +{ + return read_h(space, offset); +} + +READ8_MEMBER(sns_rom_20col_device::read_h) +{ + int prg32k = (!BIT(m_base_bank, 6) && BIT(m_base_bank, 7)); + int bank = prg32k ? 0 : (offset / 0x10000); + return m_rom[((m_base_bank & 0x1f) + bank) * 0x8000 + (offset & 0x7fff)]; +} + +WRITE8_MEMBER( sns_rom_20col_device::chip_write ) +{ + // [#] game - written bank value + // [01] spartan x - c6 + // [02] smb - c8 + // [03] antarcitc adv - 8e + // [04] twinbee - ca + // [05] battle city - 8f + // [06] circus charlie - 90 + // [07] galaga - 91 + // [08] yie ar kungfu - 92 + // [09] star force - 93 + // [10] road fighter - 94 + // [11] pinball - 95 + // [12] bomberman - 96 + // [13] new tetris?? - 0 + // [14] arkanoid - cc + // [15] balloon fight - 97 + // [16] donkey kong - 98 + // [17] donkey kong 3 - 99 + // [18] donkey kong jr - 9a + // [19] mario bros - 9b + // [20] popeye - 9c + m_base_bank = data & 0xdf; +// printf("offset %X data %X bank %X\n", offset, data, m_base_bank); +} + + + +// Work in progress (probably very wrong) + +READ8_MEMBER( sns_rom_banana_device::chip_read ) +{ + return BITSWAP8(m_latch[0xf],0,6,7,1,2,3,4,5); +} + +WRITE8_MEMBER( sns_rom_banana_device::chip_write ) +{ +// printf("write addr %X data %X\n", offset, data); + m_latch[0xf] = data; +} + +READ8_MEMBER( sns_rom_bugs_device::chip_read ) +{ + return BITSWAP8(m_latch[offset & 0xff],0,6,7,1,2,3,4,5); +} + +WRITE8_MEMBER( sns_rom_bugs_device::chip_write ) +{ + m_latch[offset & 0xff] = data; +} diff --git a/src/devices/bus/snes/rom.h b/src/devices/bus/snes/rom.h new file mode 100644 index 00000000000..bdcbd8ed92c --- /dev/null +++ b/src/devices/bus/snes/rom.h @@ -0,0 +1,209 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __SNS_ROM_H +#define __SNS_ROM_H + +#include "snes_slot.h" + + +// ======================> sns_rom_device + +class sns_rom_device : public device_t, + public device_sns_cart_interface +{ +public: + // construction/destruction + sns_rom_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + sns_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_l); + virtual DECLARE_READ8_MEMBER(read_h); +}; + +// ======================> sns_rom_obc1_device + +class sns_rom_obc1_device : public sns_rom_device +{ +public: + // construction/destruction + sns_rom_obc1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // additional reading and writing + virtual DECLARE_READ8_MEMBER(chip_read); + virtual DECLARE_WRITE8_MEMBER(chip_write); + + int m_address; + int m_offset; + int m_shift; + UINT8 m_ram[0x2000]; +}; + + + +// ======================> sns_rom_pokemon_device + +class sns_rom_pokemon_device : public sns_rom_device +{ +public: + // construction/destruction + sns_rom_pokemon_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // reading and writing + virtual DECLARE_READ8_MEMBER(chip_read); // protection device + virtual DECLARE_WRITE8_MEMBER(chip_write); // protection device + UINT8 m_latch; +}; + +// ======================> sns_rom_tekken2_device + +class sns_rom_tekken2_device : public sns_rom_device +{ +public: + // construction/destruction + sns_rom_tekken2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // reading and writing + virtual DECLARE_READ8_MEMBER(chip_read); // protection device + virtual DECLARE_WRITE8_MEMBER(chip_write); // protection device + + void update_prot(UINT32 offset); + + // bit0-3 prot value, bit4 direction, bit5 function + // reads must return (prot value) +1/-1/<<1/>>1 depending on bit4 & bit5 + UINT8 m_prot; +}; + +// ======================> sns_rom_soulblad_device + +class sns_rom_soulblad_device : public sns_rom_device +{ +public: + // construction/destruction + sns_rom_soulblad_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // reading and writing + virtual DECLARE_READ8_MEMBER(chip_read); // protection device +}; + +// ======================> sns_rom_mcpirate1_device + +class sns_rom_mcpirate1_device : public sns_rom_device +{ +public: + // construction/destruction + sns_rom_mcpirate1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_l); + virtual DECLARE_READ8_MEMBER(read_h); + virtual DECLARE_WRITE8_MEMBER(chip_write); // bankswitch device + UINT8 m_base_bank; +}; + +// ======================> sns_rom_mcpirate2_device + +class sns_rom_mcpirate2_device : public sns_rom_device +{ +public: + // construction/destruction + sns_rom_mcpirate2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_l); + virtual DECLARE_READ8_MEMBER(read_h); + virtual DECLARE_WRITE8_MEMBER(chip_write); // bankswitch device + UINT8 m_base_bank; +}; + +// ======================> sns_rom_20col_device + +class sns_rom_20col_device : public sns_rom_device +{ +public: + // construction/destruction + sns_rom_20col_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_l); + virtual DECLARE_READ8_MEMBER(read_h); + virtual DECLARE_WRITE8_MEMBER(chip_write); // bankswitch device + UINT8 m_base_bank; +}; + +// ======================> sns_rom_banana_device + +class sns_rom_banana_device : public sns_rom_device +{ +public: + // construction/destruction + sns_rom_banana_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides +// virtual void device_start(); +// virtual void device_reset(); + + // reading and writing + virtual DECLARE_READ8_MEMBER(chip_read); // protection device + virtual DECLARE_WRITE8_MEMBER(chip_write); // protection device + UINT8 m_latch[16]; +}; + +// ======================> sns_rom_bugs_device + +class sns_rom_bugs_device : public sns_rom_device +{ +public: + // construction/destruction + sns_rom_bugs_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // reading and writing + virtual DECLARE_READ8_MEMBER(chip_read); // protection device + virtual DECLARE_WRITE8_MEMBER(chip_write); // protection device + UINT8 m_latch[0x800]; +}; + + +// device type definition +extern const device_type SNS_LOROM; +extern const device_type SNS_LOROM_OBC1; +extern const device_type SNS_LOROM_POKEMON; +extern const device_type SNS_LOROM_TEKKEN2; +extern const device_type SNS_LOROM_SOULBLAD; +extern const device_type SNS_LOROM_MCPIR1; +extern const device_type SNS_LOROM_MCPIR2; +extern const device_type SNS_LOROM_20COL; +extern const device_type SNS_LOROM_BANANA; +extern const device_type SNS_LOROM_BUGSLIFE; + +#endif diff --git a/src/devices/bus/snes/rom21.c b/src/devices/bus/snes/rom21.c new file mode 100644 index 00000000000..09630b7e393 --- /dev/null +++ b/src/devices/bus/snes/rom21.c @@ -0,0 +1,258 @@ +// license:GPL-2.0+ +// copyright-holders:Fabio Priuli, byuu +/*********************************************************************************************************** + + Super NES/Famicom (HiROM) cartridge emulation (for SNES/SFC) + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "rom21.h" + + +//------------------------------------------------- +// sns_rom_device - constructor +//------------------------------------------------- + +const device_type SNS_HIROM = &device_creator; +const device_type SNS_HIROM_SRTC = &device_creator; + + +sns_rom21_device::sns_rom21_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_sns_cart_interface( mconfig, *this ) +{ +} + +sns_rom21_device::sns_rom21_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, SNS_HIROM, "SNES Cart (HiROM)", tag, owner, clock, "sns_rom21", __FILE__), + device_sns_cart_interface( mconfig, *this ) +{ +} + +sns_rom21_srtc_device::sns_rom21_srtc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : sns_rom21_device(mconfig, SNS_HIROM_SRTC, "SNES Cart (HiROM) + S-RTC", tag, owner, clock, "sns_rom21_srtc", __FILE__) +{ +} + + +void sns_rom21_device::device_start() +{ +} + +void sns_rom21_device::device_reset() +{ +} + +void sns_rom21_srtc_device::device_start() +{ + save_item(NAME(m_mode)); + save_item(NAME(m_index)); +// save_item(NAME(m_rtc_ram)); +} + +void sns_rom21_srtc_device::device_reset() +{ + m_mode = RTCM_Read; + m_index = -1; +// memset(m_rtc_ram, 0, sizeof(m_rtc_ram)); + +// at this stage, rtc_ram is not yet allocated. this will be fixed when converting RTC to be a separate device. +// update_time(); +} + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +// low and hi reads are not the same! (different ROM banks are accessed) + +READ8_MEMBER(sns_rom21_device::read_l) +{ + // here ROM banks from 128 to 255, mirrored twice + int bank = (offset & 0x3fffff) / 0x8000; + return m_rom[rom_bank_map[bank + 0x80] * 0x8000 + (offset & 0x7fff)]; +} + +READ8_MEMBER(sns_rom21_device::read_h) +{ + // here ROM banks from 0 to 127, mirrored twice + int bank = (offset & 0x3fffff) / 0x8000; + return m_rom[rom_bank_map[bank] * 0x8000 + (offset & 0x7fff)]; +} + + +// Hi-ROM + S-RTC (used by Daikaijuu Monogatari II) +// same as above but additional read/write handling for the RTC +/*************************************************************************** + + Based on C++ implementation by Byuu in BSNES. + + Byuu's code is released under GNU General Public License + version 2 as published by the Free Software Foundation. + + ***************************************************************************/ + +static const UINT8 srtc_months[12] = +{ + 31, 28, 31, + 30, 31, 30, + 31, 31, 30, + 31, 30, 31 +}; + +void sns_rom21_srtc_device::update_time() +{ + system_time curtime, *systime = &curtime; + machine().current_datetime(curtime); + m_rtc_ram[0] = systime->local_time.second % 10; + m_rtc_ram[1] = systime->local_time.second / 10; + m_rtc_ram[2] = systime->local_time.minute % 10; + m_rtc_ram[3] = systime->local_time.minute / 10; + m_rtc_ram[4] = systime->local_time.hour % 10; + m_rtc_ram[5] = systime->local_time.hour / 10; + m_rtc_ram[6] = systime->local_time.mday % 10; + m_rtc_ram[7] = systime->local_time.mday / 10; + m_rtc_ram[8] = systime->local_time.month; + m_rtc_ram[9] = (systime->local_time.year - 1000) % 10; + m_rtc_ram[10] = ((systime->local_time.year - 1000) / 10) % 10; + m_rtc_ram[11] = (systime->local_time.year - 1000) / 100; + m_rtc_ram[12] = systime->local_time.weekday % 7; +} + +// Returns day-of-week for specified date +// e.g. 0 = Sunday, 1 = Monday, ... 6 = Saturday +// Usage: weekday(2008, 1, 1) returns the weekday of January 1st, 2008 +UINT8 sns_rom21_srtc_device::srtc_weekday( UINT32 year, UINT32 month, UINT32 day ) +{ + UINT32 y = 1900, m = 1; // Epoch is 1900-01-01 + UINT32 sum = 0; // Number of days passed since epoch + + year = MAX(1900, year); + month = MAX(1, MIN(12, month)); + day = MAX(1, MIN(31, day)); + + while (y < year) + { + UINT8 leapyear = 0; + if ((y % 4) == 0) + { + leapyear = 1; + if ((y % 100) == 0 && (y % 400) != 0) + { + leapyear = 0; + } + } + sum += leapyear ? 366 : 365; + y++; + } + + while (m < month) + { + UINT32 days = srtc_months[m - 1]; + if (days == 28) + { + UINT8 leapyear = 0; + if ((y % 4) == 0) + { + leapyear = 1; + if ((y % 100) == 0 && (y % 400) != 0) + { + leapyear = 0; + } + } + days += leapyear ? 1 : 0; + } + sum += days; + m++; + } + + sum += day - 1; + return (sum + 1) % 7; // 1900-01-01 was a Monday +} + + +// this gets called only for accesses at 0x2800, +// because for 0x2801 open bus gets returned... +READ8_MEMBER(sns_rom21_srtc_device::chip_read) +{ + if (m_mode != RTCM_Read) + return 0x00; + + if (m_index < 0) + { + update_time(); + m_index++; + return 0x0f; + } + else if (m_index > 12) + { + m_index = -1; + return 0x0f; + } + else + return m_rtc_ram[m_index++]; +} + +// this gets called only for accesses at 0x2801 +WRITE8_MEMBER(sns_rom21_srtc_device::chip_write) +{ + data &= 0x0f; // Only the low four bits are used + + if (data == 0x0d) + { + m_mode = RTCM_Read; + m_index = -1; + return; + } + + if (data == 0x0e) + { + m_mode = RTCM_Command; + return; + } + + if (data == 0x0f) + return; // Unknown behaviour + + if (m_mode == RTCM_Write) + { + if (m_index >= 0 && m_index < 12) + { + m_rtc_ram[m_index++] = data; + + if (m_index == 12) + { + // Day of week is automatically calculated and written + UINT32 day = m_rtc_ram[6] + m_rtc_ram[7] * 10; + UINT32 month = m_rtc_ram[8]; + UINT32 year = m_rtc_ram[9] + m_rtc_ram[10] * 10 + m_rtc_ram[11] * 100; + year += 1000; + + m_rtc_ram[m_index++] = srtc_weekday(year, month, day); + } + } + } + else if (m_mode == RTCM_Command) + { + if (data == 0) + { + m_mode = RTCM_Write; + m_index = 0; + } + else if (data == 4) + { + UINT8 i; + m_mode = RTCM_Ready; + m_index = -1; + for(i = 0; i < 13; i++) + m_rtc_ram[i] = 0; + } + else + { + // Unknown behaviour + m_mode = RTCM_Ready; + } + } +} diff --git a/src/devices/bus/snes/rom21.h b/src/devices/bus/snes/rom21.h new file mode 100644 index 00000000000..a70d9fdc6c8 --- /dev/null +++ b/src/devices/bus/snes/rom21.h @@ -0,0 +1,67 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __SNS_ROM21_H +#define __SNS_ROM21_H + +#include "snes_slot.h" + + +// ======================> sns_rom21_device + +class sns_rom21_device : public device_t, + public device_sns_cart_interface +{ +public: + // construction/destruction + sns_rom21_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + sns_rom21_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_l); + virtual DECLARE_READ8_MEMBER(read_h); +}; + +// ======================> sns_rom21_srtc_device + +class sns_rom21_srtc_device : public sns_rom21_device +{ +public: + // construction/destruction + sns_rom21_srtc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // reading and writing + virtual DECLARE_READ8_MEMBER(chip_read); + virtual DECLARE_WRITE8_MEMBER(chip_write); + + // S-RTC specific variables + enum + { + RTCM_Ready = 0, + RTCM_Command, + RTCM_Read, + RTCM_Write + }; + + void update_time(); + UINT8 srtc_weekday(UINT32 year, UINT32 month, UINT32 day); + + //this is now allocated in the main snes cart class, to allow saving to nvram + //UINT8 m_rtc_ram[13]; + INT32 m_mode; + INT8 m_index; +}; + + +// device type definition +extern const device_type SNS_HIROM; +extern const device_type SNS_HIROM_SRTC; + +#endif diff --git a/src/devices/bus/snes/sa1.c b/src/devices/bus/snes/sa1.c new file mode 100644 index 00000000000..6da031f21b2 --- /dev/null +++ b/src/devices/bus/snes/sa1.c @@ -0,0 +1,1144 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli, R. Belmont +/*********************************************************************************************************** + + SA-1 add-on chip emulation (for SNES/SFC) + + Note: + - SA-1 register description below is based on no$cash docs. + - about bankswitch handling: no matter what is ROM size, at loading the ROM is mirrored up to 8MB and a + rom_bank_map[0x100] array is built as a lookup table for 256x32KB banks filling the 8MB accessible ROM + area; this allows to handle any 0-7 value written to CXB/DXB/EXB/FXB SA-1 registers without any masking! + - about BWRAM "bitmap mode": in 2bits mode + 600000h.Bit0-1 mirrors to 400000h.Bit0-1 + 600001h.Bit0-1 mirrors to 400000h.Bit2-3 + 600002h.Bit0-1 mirrors to 400000h.Bit4-5 + 600003h.Bit0-1 mirrors to 400000h.Bit6-7 + ... + in 4bits mode + 600000h.Bit0-3 mirrors to 400000h.Bit0-3 + 600001h.Bit0-3 mirrors to 400000h.Bit4-7 + 600002h.Bit0-3 mirrors to 400001h.Bit0-3 + 600003h.Bit0-3 mirrors to 400001h.Bit4-7 + ... + to handle the separate modes, bitmap accesses go to offset + 0x100000 + + TODO: + - test case for BWRAM & IRAM write protect (bsnes does not seem to ever protect either, so it's not implemented + for the moment) + - almost everything CPU related! + + Compatibility: + asahishi: plays OK + daisenx2: plays OK + derbyjo2: hangs going into game + dbzhypd, dbzhypdj: plays OK + habumeij: boots, goes into game, on-screen timer counts down after SA-1 is enabled but controls aren't responsive + haruaug3a, pebble, haruaug3: uses SA-1 DMA + itoibass: boots, some missing gfx + jikkparo: plays OK + jl96drem: plays OK + jumpind: boots and runs, uses SA-1 normal DMA only but has corrupt gfx + kakinoki: S-CPU crashes after pressing start + kirby3j, kirby3: uses SA-1 DMA + kirbysdb, kirbyss, kirbyfun, kirbysd, kirbysda: plays OK + marvelou: plays OK, uses SA-1 normal DMA only but has corrupt gfx + miniyonk: plays OK + panicbw: plays OK + pgaeuro, pgaeurou, pga96, pga96u, pga, pgaj: plays OK + przeo, przeou: plays OK + prokishi: plays OK + rinkaiho: plays OK + saikouso: plays OK + sdf1gpp, sdf1gp: corrupt menu gfx, hangs going into game (I think) + sdgungnx: plays OK + shinshog: plays OK + shogisai: plays OK + shogisa2: plays OK + smrpgj, smrpg: needs SA-1 character conversion for level up Bonus Chance (possible to get past now) + srobotg: some corrupt in-game GFX, may be SNES rendering errors + sshogi3: plays OK + taikyoid: plays OK + takemiya: plays OK + [Note: for Igo & Shougi games, "plays OK" means you can get ingame and the CPU replies to your moves... subtle bugs + might indeed exist...] + + ***********************************************************************************************************/ + +#include "emu.h" +#include "sa1.h" + +#define SA1_IRQ_SCPU (0x80) +#define SA1_IRQ_TIMER (0x40) +#define SA1_IRQ_DMA (0x20) +#define SA1_NMI_SCPU (0x10) + +#define SCPU_IRQ_SA1 (0x80) +#define SCPU_IRQV_ALT (0x40) +#define SCPU_IRQ_CHARCONV (0x20) +#define SCPU_NMIV_ALT (0x10) + +//------------------------------------------------- +// constructor +//------------------------------------------------- + +const device_type SNS_LOROM_SA1 = &device_creator; + + +sns_sa1_device::sns_sa1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, SNS_LOROM_SA1, "SNES Cart + SA-1", tag, owner, clock, "sns_rom_sa1", __FILE__), + device_sns_cart_interface( mconfig, *this ), + m_sa1(*this, "sa1cpu") +{ +} + + +void sns_sa1_device::device_start() +{ + m_scpu_ctrl = 0; + m_nmi_vector = 0; + m_bank_c_hi = 0; + m_bank_c_rom = 0; +} + +void sns_sa1_device::device_reset() +{ + memset(m_internal_ram, 0, sizeof(m_internal_ram)); + + m_sa1_ctrl = 0x20; + m_scpu_ctrl = 0; + m_irq_vector = 0; + m_nmi_vector = 0; + m_hcount = 0; + m_vcount = 0; + m_bank_c_hi = 0; + m_bank_c_rom = 0; + m_bank_d_hi = 0; + m_bank_d_rom = 1; + m_bank_e_hi = 0; + m_bank_e_rom = 2; + m_bank_f_hi = 0; + m_bank_f_rom = 3; + m_bwram_snes = 0; + m_bwram_sa1 = 0; + m_bwram_sa1_source = 0; + m_bwram_sa1_format = 0; + m_bwram_write_snes = 1; + m_bwram_write_sa1 = 1; + m_bwpa_sa1 = 0x0f; + m_iram_write_snes = 1; + m_iram_write_sa1 = 1; + m_src_addr = 0; + m_dst_addr = 0; + memset(m_brf_reg, 0, sizeof(m_brf_reg)); + m_math_ctlr = 0; + m_math_overflow = 0; + m_math_a = 0; + m_math_b = 0; + m_math_res = 0; + m_vda = 0; + m_vbit = 0; + m_vlen = 0; + m_drm = 0; + m_hcr = 0; + m_vcr = 0; + m_scpu_sie = m_sa1_sie = 0; + m_scpu_flags = m_sa1_flags = 0; + m_dma_ctrl = 0; + m_dma_ccparam = 0; + m_dma_cnt = 0; + + // sa-1 CPU starts out not running? + m_sa1->set_input_line(INPUT_LINE_HALT, ASSERT_LINE); +} + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +void sns_sa1_device::recalc_irqs() +{ + if (m_scpu_flags & m_scpu_sie & (SCPU_IRQ_SA1|SCPU_IRQ_CHARCONV)) + { + machine().device("maincpu")->execute().set_input_line(G65816_LINE_IRQ, ASSERT_LINE); + } + else + { + machine().device("maincpu")->execute().set_input_line(G65816_LINE_IRQ, CLEAR_LINE); + } + + if (m_sa1_flags & m_sa1_sie & (SA1_IRQ_SCPU|SA1_IRQ_TIMER|SA1_IRQ_DMA)) + { + m_sa1->set_input_line(G65816_LINE_IRQ, ASSERT_LINE); + } + else + { + m_sa1->set_input_line(G65816_LINE_IRQ, CLEAR_LINE); + } + + if (m_sa1_flags & m_sa1_sie & SA1_NMI_SCPU) + { + m_sa1->set_input_line(G65816_LINE_NMI, ASSERT_LINE); + } + else + { + m_sa1->set_input_line(G65816_LINE_NMI, CLEAR_LINE); + } +} + + +/*------------------------------------------------- + RAM / SRAM / Registers + -------------------------------------------------*/ + + +// handle this separately to avoid accessing recursively the regs? + +UINT8 sns_sa1_device::var_length_read(address_space &space, UINT32 offset) +{ + // handle 0xffea/0xffeb/0xffee/0xffef + if ((offset & 0xffffe0) == 0x00ffe0) + { + if (offset == 0xffea && BIT(m_scpu_ctrl, 4)) return (m_nmi_vector >> 0) & 0xff; + if (offset == 0xffeb && BIT(m_scpu_ctrl, 4)) return (m_nmi_vector >> 8) & 0xff; + if (offset == 0xffee && BIT(m_scpu_ctrl, 6)) return (m_irq_vector >> 0) & 0xff; + if (offset == 0xffef && BIT(m_scpu_ctrl, 6)) return (m_irq_vector >> 8) & 0xff; + } + + if ((offset & 0xc08000) == 0x008000) //$00-3f:8000-ffff + return read_l(space, (offset & 0x7fffff)); + + if ((offset & 0xc08000) == 0x808000) //$80-bf:8000-ffff + return read_h(space, (offset & 0x7fffff)); + + if ((offset & 0xc00000) == 0xc00000) //$c0-ff:0000-ffff + return read_h(space, (offset & 0x7fffff)); + + if ((offset & 0x40e000) == 0x006000) //$00-3f|80-bf:6000-7fff + return read_bwram((m_bwram_snes * 0x2000) + (offset & 0x1fff)); + + if ((offset & 0xf00000) == 0x400000) //$40-4f:0000-ffff + return read_bwram(offset & 0xfffff); + + if ((offset & 0x40f800) == 0x000000) //$00-3f|80-bf:0000-07ff + return read_iram(offset); + + if ((offset & 0x40f800) == 0x003000) //$00-3f|80-bf:3000-37ff + return read_iram(offset); + + return 0; +} + +void sns_sa1_device::dma_transfer(address_space &space) +{ +// printf("DMA src %08x (%d), dst %08x (%d) cnt %d\n", m_src_addr, m_dma_ctrl & 3, m_dst_addr, m_dma_ctrl & 4, m_dma_cnt); + + while (m_dma_cnt--) + { + UINT8 data = 0; // open bus? + UINT32 dma_src = m_src_addr++; + UINT32 dma_dst = m_dst_addr++; + + // source and destination cannot be the same + // source = { 0=ROM, 1=BWRAM, 2=IRAM } + // destination = { 0=IRAM, 1=BWRAM } + if ((m_dma_ctrl & 0x03) == 1 && (m_dma_ctrl & 0x04) == 0x04) continue; + if ((m_dma_ctrl & 0x03) == 2 && (m_dma_ctrl & 0x04) == 0x00) continue; + + switch (m_dma_ctrl & 0x03) + { + case 0: // ROM + if ((dma_src & 0x408000) == 0x008000 && (dma_src & 0x800000) == 0x000000) + { + data = read_l(space, (dma_src & 0x7fffff)); + } + if ((dma_src & 0x408000) == 0x008000 && (dma_src & 0x800000) == 0x800000) + { + data = read_h(space, (dma_src & 0x7fffff)); + } + if ((dma_src & 0xc00000) == 0xc00000) + { + data = read_h(space, (dma_src & 0x7fffff)); + } + break; + + case 1: // BWRAM + if ((dma_src & 0x40e000) == 0x006000) + { + data = read_bwram((m_bwram_sa1 * 0x2000) + (dma_src & 0x1fff)); + } + if ((dma_src & 0xf00000) == 0x400000) + { + data = read_bwram(dma_src & 0xfffff); + } + break; + + case 2: // IRAM + data = read_iram(dma_src); + break; + } + + switch (m_dma_ctrl & 0x04) + { + case 0x00: // IRAM + write_iram(dma_dst, data); + break; + + case 0x04: // BWRAM + if ((dma_dst & 0x40e000) == 0x006000) + { + write_bwram((m_bwram_sa1 * 0x2000) + (dma_dst & 0x1fff), data); + } + if ((dma_dst & 0xf00000) == 0x400000) + { + write_bwram(dma_dst & 0xfffff, data); + } + break; + } + } + + m_sa1_flags |= SA1_IRQ_DMA; + recalc_irqs(); +} + +void sns_sa1_device::dma_cctype1_transfer(address_space &space) +{ + m_scpu_flags |= SCPU_IRQ_CHARCONV; + recalc_irqs(); +} + +void sns_sa1_device::dma_cctype2_transfer(address_space &space) +{ +} + +UINT8 sns_sa1_device::read_regs(address_space &space, UINT32 offset) +{ + UINT8 value = 0xff; + offset &= 0x1ff; // $2200 + offset gives the reg value to compare with docs + + switch (offset) + { + case 0x100: + // S-CPU Flag Read + value = (m_scpu_ctrl & 0x0f) | m_scpu_flags; + break; + case 0x101: + // SA-1 Flag Read + value = (m_sa1_ctrl & 0x0f) | m_sa1_flags; + break; + case 0x102: + // H-Count Read Low + //latch counters + m_hcr = m_hcount >> 2; + m_vcr = m_vcount; + //then return h-count + value = (m_hcr >> 0) & 0xff; + break; + case 0x103: + // H-Count Read High + value = (m_hcr >> 8) & 0xff; + break; + case 0x104: + // V-Count Read Low + value = (m_vcr >> 0) & 0xff; + break; + case 0x105: + // V-Count Read High + value = (m_vcr >> 8) & 0xff; + break; + case 0x106: + // Math Result bits0-7 + value = (UINT64)(m_math_res >> 0) & 0xff; + break; + case 0x107: + // Math Result bits8-15 + value = (UINT64)(m_math_res >> 8) & 0xff; + break; + case 0x108: + // Math Result bits16-23 + value = (UINT64)(m_math_res >> 16) & 0xff; + break; + case 0x109: + // Math Result bits24-31 + value = (UINT64)(m_math_res >> 24) & 0xff; + break; + case 0x10a: + // Math Result bits32-39 + value = (UINT64)(m_math_res >> 32) & 0xff; + break; + case 0x10b: + // Math Overflow (above 40bit result) + value = m_math_overflow; + break; + case 0x10c: + // Var-Length Read Port Low + { + UINT32 data = (var_length_read(space, m_vda + 0) << 0) | (var_length_read(space, m_vda + 1) << 8) + | (var_length_read(space, m_vda + 2) << 16); + data >>= m_vbit; + value = (data >> 0) & 0xff; + } + break; + case 0x10d: + // Var-Length Read Port High + { + UINT32 data = (var_length_read(space, m_vda + 0) << 0) | (var_length_read(space, m_vda + 1) << 8) + | (var_length_read(space, m_vda + 2) << 16); + data >>= m_vbit; + + if (m_drm == 1) + { + //auto-increment mode + m_vbit += m_vlen; + m_vda += (m_vbit >> 3); + m_vbit &= 7; + } + + value = (data >> 8) & 0xff; + } + break; + case 0x10e: + // SNES VC Version Code Register (R) + break; + default: + logerror("SA-1 Read access to an unmapped reg (%x)", offset); + break; + } + return value; +} + +void sns_sa1_device::write_regs(address_space &space, UINT32 offset, UINT8 data) +{ + offset &= 0x1ff; // $2200 + offset gives the reg value to compare with docs + + switch (offset) + { + case 0x000: + // SA-1 control flags +// printf("%02x to SA-1 control\n", data); + if ((BIT(data, 5)) && !(BIT(m_sa1_ctrl, 5))) + { +// printf("Engaging SA-1 reset\n"); + m_sa1->set_input_line(INPUT_LINE_HALT, ASSERT_LINE); + } + else if (!(BIT(data, 5)) && (BIT(m_sa1_ctrl, 5))) + { +// printf("Releasing SA-1 reset\n"); + m_sa1->set_input_line(INPUT_LINE_HALT, CLEAR_LINE); + m_sa1->set_input_line(INPUT_LINE_RESET, ASSERT_LINE); + m_sa1->set_input_line(INPUT_LINE_RESET, CLEAR_LINE); + } + + m_sa1_ctrl = data; + + // message to S-CPU + m_scpu_ctrl &= 0xf0; + m_scpu_ctrl |= (data & 0x0f); + + if (BIT(m_sa1_ctrl, 7)) + { + m_sa1_flags |= SA1_IRQ_SCPU; + } + if (BIT(m_sa1_ctrl, 4)) + { + m_sa1_flags |= SA1_NMI_SCPU; + } + recalc_irqs(); + break; + case 0x001: + // SNES SIE 00h SNES CPU Int Enable (W) + m_scpu_sie = data; +// printf("S-CPU IE = %02x\n", data); + recalc_irqs(); + break; + case 0x002: + // SNES SIC 00h SNES CPU Int Clear (W) + if (BIT(data, 7)) // ack IRQ from SA-1 + { + m_scpu_flags &= ~SCPU_IRQ_SA1; + } + if (BIT(data, 5)) // ack character conversion IRQ + { + m_scpu_flags &= ~SCPU_IRQ_CHARCONV; + } + recalc_irqs(); + break; + case 0x003: + // SNES CRV - SA-1 CPU Reset Vector Lsb (W) + m_sa1_reset &= 0xff00; + m_sa1_reset |= data; + break; + case 0x004: + // SNES CRV - SA-1 CPU Reset Vector Msb (W) + m_sa1_reset &= 0x00ff; + m_sa1_reset |= (data<<8); + break; + case 0x005: + // SNES CNV - SA-1 CPU NMI Vector Lsb (W) + m_sa1_nmi &= 0xff00; + m_sa1_nmi |= data; + break; + case 0x006: + // SNES CNV - SA-1 CPU NMI Vector Msb (W) + m_sa1_nmi &= 0x00ff; + m_sa1_nmi |= (data<<8); + break; + case 0x007: + // SNES CIV - SA-1 CPU IRQ Vector Lsb (W) + m_sa1_irq &= 0xff00; + m_sa1_irq |= data; + break; + case 0x008: + // SNES CIV - SA-1 CPU IRQ Vector Msb (W) + m_sa1_irq &= 0x00ff; + m_sa1_irq |= (data<<8); + break; + case 0x009: + // S-CPU control flags + m_scpu_ctrl = data; + if (m_scpu_ctrl & 0x80) + { + m_scpu_flags |= SCPU_IRQ_SA1; +// printf("SA-1 cause S-CPU IRQ\n"); + } + + // message to SA-1 + m_sa1_ctrl &= 0xf0; + m_sa1_ctrl |= (data & 0x0f); + + // clear IRQ/NMI override flags in flags word + m_scpu_flags &= ~(SCPU_IRQV_ALT|SCPU_NMIV_ALT); + + // and set them + m_scpu_flags |= (data & (SCPU_IRQV_ALT|SCPU_NMIV_ALT)); + + recalc_irqs(); + break; + case 0x00a: + // SA-1 CIE 00h SA-1 CPU Int Enable (W) + m_sa1_sie = data; +// printf("SA-1 IE = %02x\n", data); + recalc_irqs(); + break; + case 0x00b: + // SA-1 CIC 00h SA-1 CPU Int Clear (W) + if (BIT(data, 7)) + { + m_sa1_flags &= ~SA1_IRQ_SCPU; + } + if (BIT(data, 6)) + { + m_sa1_flags &= ~SA1_IRQ_TIMER; + } + if (BIT(data, 5)) + { + m_sa1_flags &= ~SA1_IRQ_DMA; + } + if (BIT(data, 4)) + { + m_sa1_flags &= ~SA1_NMI_SCPU; + } + recalc_irqs(); + break; + case 0x00c: + // NMI Vector Low + m_nmi_vector = (m_nmi_vector & 0xff00) | (data << 0); + break; + case 0x00d: + // NMI Vector High + m_nmi_vector = (m_nmi_vector & 0x00ff) | (data << 8); + break; + case 0x00e: + // IRQ Vector Low + m_irq_vector = (m_irq_vector & 0xff00) | (data << 0); + break; + case 0x00f: + // IRQ Vector High + m_irq_vector = (m_irq_vector & 0x00ff) | (data << 8); + break; + case 0x010: + // SA-1 TMC 00h H/V Timer Control (W) + break; + case 0x011: + // SA-1 CTR - SA-1 CPU Timer Restart (W) + break; + case 0x012: + // H-Count Low + m_hcount = (m_hcount & 0xff00) | (data << 0); + break; + case 0x013: + // H-Count High + m_hcount = (m_hcount & 0x00ff) | (data << 8); + break; + case 0x014: + // V-Count Low + m_vcount = (m_vcount & 0xff00) | (data << 0); + break; + case 0x015: + // V-Count High + m_vcount = (m_vcount & 0x00ff) | (data << 8); + break; + case 0x020: + // ROM 1MB bank for [c0-cf] + m_bank_c_hi = BIT(data, 7); + m_bank_c_rom = data & 0x07; + break; + case 0x021: + // ROM 1MB bank for [d0-df] + m_bank_d_hi = BIT(data, 7); + m_bank_d_rom = data & 0x07; + break; + case 0x022: + // ROM 1MB bank for [e0-ef] + m_bank_e_hi = BIT(data, 7); + m_bank_e_rom = data & 0x07; + break; + case 0x023: + // ROM 1MB bank for [f0-ff] + m_bank_f_hi = BIT(data, 7); + m_bank_f_rom = data & 0x07; + break; + case 0x024: + // BWRAM bank from SNES side + m_bwram_snes = data & 0x1f; // max 32x8K banks + break; + case 0x025: + // BWRAM bank & type from SA-1 side + m_bwram_sa1_source = BIT(data, 7); // 0 = normal, 1 = bitmap? + m_bwram_sa1 = data & 0x7f; // up to 128x8K banks here? + break; + case 0x026: + // enable writing to BWRAM from SNES + m_bwram_write_snes = BIT(data, 7); + break; + case 0x027: + // enable writing to BWRAM from SA-1 + m_bwram_write_sa1 = BIT(data, 7); + break; + case 0x028: + // write protected area at bottom of BWRAM + m_bwpa_sa1 = 0x100 * (data & 0x0f); + break; + case 0x029: + // enable writing to IRAM from SNES (1 bit for each 0x100 chunk) + m_iram_write_snes = data; + break; + case 0x02a: + // enable writing to IRAM from SA-1 (1 bit for each 0x100 chunk) + m_iram_write_sa1 = data; + break; + case 0x030: + // SA-1 DCNT 00h DMA Control (W) +// printf("%02x to SA-1 DMA control\n", data); + m_dma_ctrl = data; + break; + case 0x031: + // Both CDMA 00h Character Conversion DMA Parameters (W) + m_dma_ccparam = data; + break; + case 0x032: + // DMA Source Device Start Address Low + m_src_addr = (m_src_addr & 0xffff00) | (data << 0); + break; + case 0x033: + // DMA Source Device Start Address Mid + m_src_addr = (m_src_addr & 0xff00ff) | (data << 8); + break; + case 0x034: + // DMA Source Device Start Address High + m_src_addr = (m_src_addr & 0x00ffff) | (data << 16); + break; + case 0x035: + // DMA Dest Device Start Address Low + m_dst_addr = (m_dst_addr & 0xffff00) | (data << 0); + break; + case 0x036: + // DMA Dest Device Start Address Mid + m_dst_addr = (m_dst_addr & 0xff00ff) | (data << 8); + if (m_dma_ctrl & 0x80) + { + if (!(m_dma_ctrl & 0x20) && !(m_dma_ctrl & 0x04)) // Normal DMA to IRAM + { + dma_transfer(space); +// printf("SA-1: normal DMA to IRAM\n"); + } + + if (m_dma_ctrl & 0x20 && m_dma_ctrl & 0x10) // CC DMA Type 1 + { +// printf("SA-1: CC DMA type 1\n"); + dma_cctype1_transfer(space); + } + } + break; + case 0x037: + // DMA Dest Device Start Address High + m_dst_addr = (m_dst_addr & 0xffff00) | (data << 16); + if (m_dma_ctrl & 0x80) + { + if (!(m_dma_ctrl & 0x20) && m_dma_ctrl & 0x04) // Normal DMA to BWRAM + { +// printf("SA-1: normal DMA to BWRAM\n"); + dma_transfer(space); + } + } + break; + case 0x038: + // SA-1 DTC - DMA Terminal Counter Lsb (W) + m_dma_cnt &= 0xff00; + m_dma_cnt |= data; + break; + case 0x039: + // SA-1 DTC - DMA Terminal Counter Msb (W) + m_dma_cnt &= 0x00ff; + m_dma_cnt |= (data<<8); + break; + case 0x03f: + // Format for BWRAM when mapped to bitmap + m_bwram_sa1_format = BIT(data, 7); // 0 = 4bit, 1 = 2bit + break; + case 0x040: + case 0x041: + case 0x042: + case 0x043: + case 0x044: + case 0x045: + case 0x046: + case 0x047: + case 0x048: + case 0x049: + case 0x04a: + case 0x04b: + case 0x04c: + case 0x04d: + case 0x04e: + case 0x04f: + // Bit Map Register File (2240h..224Fh) + m_brf_reg[offset & 0x0f] = data; + if ((offset & 0x07) == 7 && m_dma_ctrl & 0x80) + { + if (m_dma_ctrl & 0x20 && !(m_dma_ctrl & 0x10)) // CC DMA Type 2 + { +// printf("SA-1: CC DMA type 2\n"); + dma_cctype2_transfer(space); + } + } + break; + case 0x050: + // Math control + m_math_ctlr = data & 0x03; + if (data & 0x02) + m_math_res = 0; + break; + case 0x051: + // Math A Low + m_math_a = (m_math_a & 0xff00) | data; + break; + case 0x052: + // Math A High + m_math_a = (data << 8) | (m_math_a & 0x00ff); + break; + case 0x053: + // Math B Low + m_math_b = (m_math_b & 0xff00) | data; + break; + case 0x054: + // Math B High + m_math_b = (data << 8) | (m_math_b & 0x00ff); + // After Math B has been written, we do math + switch (m_math_ctlr) + { + case 0: //signed multiplication + m_math_res = (INT16)m_math_a * (INT16)m_math_b; + m_math_b = 0; + break; + case 1: //unsigned division + if (m_math_b == 0) + m_math_res = 0; + else + { + INT16 quotient = (INT16)m_math_a / (UINT16)m_math_b; + UINT16 remainder = (INT16)m_math_a % (UINT16)m_math_b; + m_math_res = (UINT64)((remainder << 16) | quotient); + } + break; + case 2: //sigma (accumulative multiplication) + case 3: + UINT64 acum = (INT16)m_math_a * (INT16)m_math_b; + UINT64 mask = U64(0xffffffffff); + m_math_res += acum; + m_math_overflow = (m_math_res > mask) ? 0x80 : 0; + m_math_res &= mask; + m_math_b = 0; + break; + } + break; + case 0x058: + // Var-Length Bit Processing + m_drm = BIT(data, 7); // Data Read Mode + m_vlen = (data & 0x0f); + if (m_vlen == 0) + m_vlen = 16; + + if (m_drm == 0) + { + //fixed mode + m_vbit += m_vlen; + m_vda += (m_vbit >> 3); + m_vbit &= 7; + } + break; + case 0x059: + // Var-Length Read Start Address Low + m_vda = (m_vda & 0xffff00) | (data << 0); + break; + case 0x05a: + // Var-Length Read Start Address Mid + m_vda = (m_vda & 0xff00ff) | (data << 8); + break; + case 0x05b: + // Var-Length Read Start Address High + m_vda = (m_vda & 0x00ffff) | (data << 16); + m_vbit = 0; + break; + default: + logerror("SA-1 Write access to an unmapped reg (%x) with data %x", offset, data); + break; + } +} + +UINT8 sns_sa1_device::read_iram(UINT32 offset) +{ + return m_internal_ram[offset & 0x7ff]; +} + +void sns_sa1_device::write_iram(UINT32 offset, UINT8 data) +{ + m_internal_ram[offset & 0x7ff] = data; +} + +UINT8 sns_sa1_device::read_bwram(UINT32 offset) +{ + int shift = 0; + UINT8 mask = 0xff; + + if (m_nvram.empty()) + return 0xff; // this should probably never happen, or are there SA-1 games with no BWRAM? + + if (offset < 0x100000) + return m_nvram[offset & (m_nvram.size() - 1)]; + + // Bitmap BWRAM + offset -= 0x100000; + + if (m_bwram_sa1_format) + { + // 2bits mode + offset /= 4; + shift = ((offset % 4) * 2); + mask = 0x03; + } + else + { + // 4bits mode + offset /= 2; + shift = ((offset % 2) * 4); + mask = 0x0f; + } + + // only return the correct bits + return (m_nvram[offset & (m_nvram.size() - 1)] >> shift) & mask; +} + +void sns_sa1_device::write_bwram(UINT32 offset, UINT8 data) +{ + UINT8 mask = 0xff; + + if (m_nvram.empty()) + return; // this should probably never happen, or are there SA-1 games with no BWRAM? + + if (offset < 0x100000) + { + m_nvram[offset & (m_nvram.size() - 1)] = data; + return; + } + + // Bitmap BWRAM + offset -= 0x100000; + + if (m_bwram_sa1_format) + { + // 2bits mode + offset /= 4; + data = (data & 0x03) << ((offset % 4) * 2); + mask = 0x03 << ((offset % 4) * 2); + } + else + { + // 4bits mode + offset /= 2; + data = (data & 0x0f) << ((offset % 2) * 4); + mask = 0x0f << ((offset % 2) * 4); + } + + // only change the correct bits, keeping the rest untouched + m_nvram[offset & (m_nvram.size() - 1)] = (m_nvram[offset & (m_nvram.size() - 1)] & ~mask) | data; +} + + + +/*------------------------------------------------- + Accesses from SNES CPU + -------------------------------------------------*/ + + +READ8_MEMBER(sns_sa1_device::read_l) +{ + int bank = 0; + + if (offset == 0xffea && BIT(m_scpu_ctrl, 4)) return (m_nmi_vector >> 0) & 0xff; + if (offset == 0xffeb && BIT(m_scpu_ctrl, 4)) return (m_nmi_vector >> 8) & 0xff; + if (offset == 0xffee && BIT(m_scpu_ctrl, 6)) return (m_irq_vector >> 0) & 0xff; + if (offset == 0xffef && BIT(m_scpu_ctrl, 6)) return (m_irq_vector >> 8) & 0xff; + + // ROM is mapped to [00-3f][8000-ffff] only here + if (offset < 0x200000) + { + if (!m_bank_c_hi) // when HiROM mapping is disabled, we always access first 1MB here + bank = (offset / 0x10000) + 0x00; + else // when HiROM mapping is enabled, we mirror [c0-cf][0000-ffff] bank + bank = (offset / 0x10000) + (m_bank_c_rom * 0x20); + + bank &= 0xff; + return m_rom[rom_bank_map[bank] * 0x8000 + (offset & 0x7fff)]; + } + else if (offset < 0x400000) + { + offset -= 0x200000; + if (!m_bank_d_hi) // when HiROM mapping is disabled, we always access second 1MB here + bank = (offset / 0x10000) + 0x20; + else // when HiROM mapping is enabled, we mirror [d0-df][0000-ffff] bank + bank = (offset / 0x10000) + (m_bank_d_rom * 0x20); + + bank &= 0xff; + return m_rom[rom_bank_map[bank] * 0x8000 + (offset & 0x7fff)]; + } + else + return 0; // this should not happen (the driver should only call read_l in the above case) +} + +READ8_MEMBER(sns_sa1_device::read_h) +{ + int bank = 0; + + // ROM is mapped to [80-bf][8000-ffff] & [c0-ff][0000-ffff] + if (offset < 0x200000) + { + if (!m_bank_e_hi) // when HiROM mapping is disabled, we always access third 1MB here + bank = (offset / 0x10000) + 0x40; + else // when HiROM mapping is enabled, we mirror [e0-ef][0000-ffff] bank + bank = (offset / 0x10000) + (m_bank_e_rom * 0x20); + + bank &= 0xff; + return m_rom[rom_bank_map[bank] * 0x8000 + (offset & 0x7fff)]; + } + else if (offset < 0x400000) + { + offset -= 0x200000; + if (!m_bank_f_hi) // when HiROM mapping is disabled, we always access fourth 1MB here + bank = (offset / 0x10000) + 0x60; + else // when HiROM mapping is enabled, we mirror [f0-ff][0000-ffff] bank + bank = (offset / 0x10000) + (m_bank_f_rom * 0x20); + + bank &= 0xff; + return m_rom[rom_bank_map[bank] * 0x8000 + (offset & 0x7fff)]; + } + else if (offset < 0x500000) + return m_rom[rom_bank_map[(m_bank_c_rom * 0x20) + ((offset - 0x400000) / 0x8000)] * 0x8000 + (offset & 0x7fff)]; + else if (offset < 0x600000) + return m_rom[rom_bank_map[(m_bank_d_rom * 0x20) + ((offset - 0x500000) / 0x8000)] * 0x8000 + (offset & 0x7fff)]; + else if (offset < 0x700000) + return m_rom[rom_bank_map[(m_bank_e_rom * 0x20) + ((offset - 0x600000) / 0x8000)] * 0x8000 + (offset & 0x7fff)]; + else + return m_rom[rom_bank_map[(m_bank_f_rom * 0x20) + ((offset - 0x700000) / 0x8000)] * 0x8000 + (offset & 0x7fff)]; +} + +WRITE8_MEMBER(sns_sa1_device::write_l) +{ +} + +WRITE8_MEMBER(sns_sa1_device::write_h) +{ +} + +READ8_MEMBER( sns_sa1_device::chip_read ) +{ + UINT16 address = offset & 0xffff; + + if (offset < 0x400000 && address >= 0x2200 && address < 0x2400) + return read_regs(space, address & 0x1ff); // SA-1 Regs + + if (offset < 0x400000 && address >= 0x3000 && address < 0x3800) + return read_iram(address & 0x7ff); // Internal SA-1 RAM (2K) + + if (offset < 0x400000 && address >= 0x6000 && address < 0x8000) + return read_bwram((m_bwram_snes * 0x2000) + (offset & 0x1fff)); // SA-1 BWRAM + + if (offset >= 0x400000 && offset < 0x500000) + return read_bwram(offset & 0xfffff); // SA-1 BWRAM again (but not called for the [c0-cf] range, because it's not mirrored) + + return 0xff; +} + + +WRITE8_MEMBER( sns_sa1_device::chip_write ) +{ + UINT16 address = offset & 0xffff; + + if (offset < 0x400000 && address >= 0x2200 && address < 0x2400) + write_regs(space, address & 0x1ff, data); // SA-1 Regs + + if (offset < 0x400000 && address >= 0x3000 && address < 0x3800) + write_iram(address & 0x7ff, data); // Internal SA-1 RAM (2K) + + if (offset < 0x400000 && address >= 0x6000 && address < 0x8000) + write_bwram((m_bwram_snes * 0x2000) + (offset & 0x1fff), data); // SA-1 BWRAM + + if (offset >= 0x400000 && offset < 0x500000) + write_bwram(offset & 0xfffff, data); // SA-1 BWRAM again (but not called for the [c0-cf] range, because it's not mirrored) +} + + +/*------------------------------------------------- + Accesses from SA-1 CPU + -------------------------------------------------*/ + +// These handlers basically match the SNES CPU ones, but there is no access to internal +// I/O regs or WRAM, and there are a few additional accesses to IRAM (in [00-3f][0000-07ff]) +// and to BWRAM (in [60-6f][0000-ffff], so-called bitmap mode) + +READ8_MEMBER( sns_sa1_device::sa1_hi_r ) +{ + UINT16 address = offset & 0xffff; + + if (offset < 0x400000) + { + if (address < 0x6000) + { + if (address < 0x0800) + return read_iram(offset); // Internal SA-1 RAM (2K) + else if (address >= 0x2200 && address < 0x2400) + return read_regs(space, offset & 0x1ff); // SA-1 Regs + else if (address >= 0x3000 && address < 0x3800) + return read_iram(offset); // Internal SA-1 RAM (2K) + } + else if (address < 0x8000) + return read_bwram((m_bwram_sa1 * 0x2000) + (offset & 0x1fff) + (m_bwram_sa1_source * 0x100000)); // SA-1 BWRAM + else + return read_h(space, offset); // ROM + + return 0xff; // maybe open bus? same as the main system one or diff? (currently not accessible from carts anyway...) + } + else + return read_h(space, offset); // ROM +} + +READ8_MEMBER( sns_sa1_device::sa1_lo_r ) +{ + UINT16 address = offset & 0xffff; + + if (offset < 0x400000) + { + if (address < 0x6000) + { + if (address < 0x0800) + return read_iram(offset); // Internal SA-1 RAM (2K) + else if (address >= 0x2200 && address < 0x2400) + return read_regs(space, offset & 0x1ff); // SA-1 Regs + else if (address >= 0x3000 && address < 0x3800) + return read_iram(offset); // Internal SA-1 RAM (2K) + } + else if (address < 0x8000) + return read_bwram((m_bwram_sa1 * 0x2000) + (offset & 0x1fff) + (m_bwram_sa1_source * 0x100000)); // SA-1 BWRAM + else if (offset == 0xffee) + { + return m_sa1_irq & 0xff; + } + else if (offset == 0xffef) + { + return m_sa1_irq>>8; + } + else if (offset == 0xffea) + { + return m_sa1_nmi & 0xff; + } + else if (offset == 0xffeb) + { + return m_sa1_nmi>>8; + } + else if (offset == 0xfffc) + { + return m_sa1_reset & 0xff; + } + else if (offset == 0xfffd) + { + return m_sa1_reset>>8; + } + else + return read_l(space, offset); // ROM + + return 0xff; // maybe open bus? same as the main system one or diff? (currently not accessible from carts anyway...) + } + else if (offset < 0x500000) + return read_bwram(offset & 0xfffff); // SA-1 BWRAM (not mirrored above!) + else if (offset >= 0x600000 && offset < 0x700000) + return read_bwram((offset & 0xfffff) + 0x100000); // SA-1 BWRAM Bitmap mode + else + return 0xff; // nothing should be mapped here, so maybe open bus? +} + +WRITE8_MEMBER( sns_sa1_device::sa1_hi_w ) +{ + UINT16 address = offset & 0xffff; + if (offset < 0x400000) + { + if (address < 0x6000) + { + if (address < 0x0800) + write_iram(offset, data); // Internal SA-1 RAM (2K) + else if (address >= 0x2200 && address < 0x2400) + write_regs(space, offset & 0x1ff, data); // SA-1 Regs + else if (address >= 0x3000 && address < 0x3800) + write_iram(offset, data); // Internal SA-1 RAM (2K) + } + else if (address < 0x8000) + write_bwram((m_bwram_sa1 * 0x2000) + (offset & 0x1fff) + (m_bwram_sa1_source * 0x100000), data); // SA-1 BWRAM + } +} + +WRITE8_MEMBER( sns_sa1_device::sa1_lo_w ) +{ + if (offset >= 0x400000 && offset < 0x500000) + write_bwram(offset & 0xfffff, data); // SA-1 BWRAM (not mirrored above!) + else if (offset >= 0x600000 && offset < 0x700000) + write_bwram((offset & 0xfffff) + 0x100000, data); // SA-1 BWRAM Bitmap mode + else + sa1_hi_w(space, offset, data); +} + +static ADDRESS_MAP_START( sa1_map, AS_PROGRAM, 8, sns_sa1_device ) + AM_RANGE(0x000000, 0x7dffff) AM_READWRITE(sa1_lo_r, sa1_lo_w) + AM_RANGE(0x7e0000, 0x7fffff) AM_NOP + AM_RANGE(0x800000, 0xffffff) AM_READWRITE(sa1_hi_r, sa1_hi_w) +ADDRESS_MAP_END + + +static MACHINE_CONFIG_FRAGMENT( snes_sa1 ) + MCFG_CPU_ADD("sa1cpu", G65816, 10000000) + MCFG_CPU_PROGRAM_MAP(sa1_map) +MACHINE_CONFIG_END + +machine_config_constructor sns_sa1_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( snes_sa1 ); +} diff --git a/src/devices/bus/snes/sa1.h b/src/devices/bus/snes/sa1.h new file mode 100644 index 00000000000..d388303f9f9 --- /dev/null +++ b/src/devices/bus/snes/sa1.h @@ -0,0 +1,113 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli, R. Belmont +#ifndef __SNS_SA1_H +#define __SNS_SA1_H + +#include "snes_slot.h" +#include "cpu/g65816/g65816.h" + + +// ======================> sns_sa1_device + +class sns_sa1_device : public device_t, + public device_sns_cart_interface +{ +public: + // construction/destruction + sns_sa1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual machine_config_constructor device_mconfig_additions() const; + virtual void device_reset(); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_l); + virtual DECLARE_READ8_MEMBER(read_h); + virtual DECLARE_WRITE8_MEMBER(write_l); + virtual DECLARE_WRITE8_MEMBER(write_h); + + // additional reading and writing + virtual DECLARE_READ8_MEMBER(chip_read); + virtual DECLARE_WRITE8_MEMBER(chip_write); + + DECLARE_READ8_MEMBER(sa1_lo_r); + DECLARE_READ8_MEMBER(sa1_hi_r); + DECLARE_WRITE8_MEMBER(sa1_lo_w); + DECLARE_WRITE8_MEMBER(sa1_hi_w); + +private: + + UINT8 var_length_read(address_space &space, UINT32 offset); + void dma_transfer(address_space &space); + void dma_cctype1_transfer(address_space &space); + void dma_cctype2_transfer(address_space &space); + + UINT8 read_regs(address_space &space, UINT32 offset); + UINT8 read_iram(UINT32 offset); + UINT8 read_bwram(UINT32 offset); + void write_regs(address_space &space, UINT32 offset, UINT8 data); + void write_iram(UINT32 offset, UINT8 data); + void write_bwram(UINT32 offset, UINT8 data); + void recalc_irqs(); + + required_device m_sa1; + + UINT8 m_internal_ram[0x800]; + + // register related + // $2200 + UINT8 m_sa1_ctrl; + // $2201 + UINT8 m_scpu_sie; + // $2203-$2208 + UINT16 m_sa1_reset, m_sa1_nmi, m_sa1_irq; + // $2209 + UINT8 m_scpu_ctrl; + // $220a + UINT8 m_sa1_sie; + // $200c-$200d - S-CPU vectors + UINT16 m_irq_vector, m_nmi_vector; + // $2012-$2015 + UINT16 m_hcount, m_vcount; + // $2220-$2223 + int m_bank_c_hi, m_bank_c_rom; + int m_bank_d_hi, m_bank_d_rom; + int m_bank_e_hi, m_bank_e_rom; + int m_bank_f_hi, m_bank_f_rom; + // $2224-$2225 & $223f + UINT8 m_bwram_snes, m_bwram_sa1; + int m_bwram_sa1_source, m_bwram_sa1_format; + // $2226-$2227 + int m_bwram_write_snes, m_bwram_write_sa1; + // $2228 + UINT32 m_bwpa_sa1; + // $2229-$222a + UINT8 m_iram_write_snes, m_iram_write_sa1; + // $2230-$2231 + UINT8 m_dma_ctrl, m_dma_ccparam; + // $2232-$2237 + UINT32 m_src_addr, m_dst_addr; + // $2238-$2239 + UINT16 m_dma_cnt; + // $2240-$224f + UINT8 m_brf_reg[0x10]; + // $2250-$2254 + UINT8 m_math_ctlr, m_math_overflow; + UINT16 m_math_a, m_math_b; + UINT64 m_math_res; + // $2258-$225b + UINT32 m_vda; + UINT8 m_vbit, m_vlen; + int m_drm; + // $2300-$2301 + UINT8 m_scpu_flags, m_sa1_flags; + // $2302-$2305 + UINT16 m_hcr, m_vcr; +}; + + +// device type definition +extern const device_type SNS_LOROM_SA1; + +#endif diff --git a/src/devices/bus/snes/sdd1.c b/src/devices/bus/snes/sdd1.c new file mode 100644 index 00000000000..fe7b2c762ec --- /dev/null +++ b/src/devices/bus/snes/sdd1.c @@ -0,0 +1,617 @@ +// license:BSD-3-Clause +// copyright-holders:Ryan Holtz, Andreas Naive, Fabio Priuli +/*********************************************************************************************************** + + S-DD1 add-on chip emulation (for SNES/SFC) + + Based on Andreas Naive Public Domain code. + Code ported by MooglyGuy and updated to slots by Fabio Priuli. + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "sdd1.h" + + +#define SSD1_ADD(addr)\ + mmc[(addr >> 20) & 3] + (addr & 0x0fffff) + + +// Input Manager + +void SDD1_IM::IM_prepareDecomp(UINT32 in_buf) +{ + m_byte_ptr = in_buf; + m_bit_count = 4; +} + +UINT8 SDD1_IM::IM_getCodeword(UINT8 *ROM, UINT32 *mmc, const UINT8 code_len) +{ + UINT8 codeword = ROM[SSD1_ADD(m_byte_ptr)] << m_bit_count; + + ++m_bit_count; + + if (codeword & 0x80) + { + codeword |= ROM[SSD1_ADD((m_byte_ptr + 1))] >> (9 - m_bit_count); + m_bit_count += code_len; + } + + if (m_bit_count & 0x08) + { + m_byte_ptr++; + m_bit_count &= 0x07; + } + + return codeword; +} + +// GCD + +void SDD1_GCD::GCD_getRunCount(UINT8 *ROM, UINT32 *mmc, UINT8 code_num, UINT8* MPScount, UINT8* LPSind) +{ + const UINT8 run_count[] = + { + 0x00, 0x00, 0x01, 0x00, 0x03, 0x01, 0x02, 0x00, + 0x07, 0x03, 0x05, 0x01, 0x06, 0x02, 0x04, 0x00, + 0x0f, 0x07, 0x0b, 0x03, 0x0d, 0x05, 0x09, 0x01, + 0x0e, 0x06, 0x0a, 0x02, 0x0c, 0x04, 0x08, 0x00, + 0x1f, 0x0f, 0x17, 0x07, 0x1b, 0x0b, 0x13, 0x03, + 0x1d, 0x0d, 0x15, 0x05, 0x19, 0x09, 0x11, 0x01, + 0x1e, 0x0e, 0x16, 0x06, 0x1a, 0x0a, 0x12, 0x02, + 0x1c, 0x0c, 0x14, 0x04, 0x18, 0x08, 0x10, 0x00, + 0x3f, 0x1f, 0x2f, 0x0f, 0x37, 0x17, 0x27, 0x07, + 0x3b, 0x1b, 0x2b, 0x0b, 0x33, 0x13, 0x23, 0x03, + 0x3d, 0x1d, 0x2d, 0x0d, 0x35, 0x15, 0x25, 0x05, + 0x39, 0x19, 0x29, 0x09, 0x31, 0x11, 0x21, 0x01, + 0x3e, 0x1e, 0x2e, 0x0e, 0x36, 0x16, 0x26, 0x06, + 0x3a, 0x1a, 0x2a, 0x0a, 0x32, 0x12, 0x22, 0x02, + 0x3c, 0x1c, 0x2c, 0x0c, 0x34, 0x14, 0x24, 0x04, + 0x38, 0x18, 0x28, 0x08, 0x30, 0x10, 0x20, 0x00, + 0x7f, 0x3f, 0x5f, 0x1f, 0x6f, 0x2f, 0x4f, 0x0f, + 0x77, 0x37, 0x57, 0x17, 0x67, 0x27, 0x47, 0x07, + 0x7b, 0x3b, 0x5b, 0x1b, 0x6b, 0x2b, 0x4b, 0x0b, + 0x73, 0x33, 0x53, 0x13, 0x63, 0x23, 0x43, 0x03, + 0x7d, 0x3d, 0x5d, 0x1d, 0x6d, 0x2d, 0x4d, 0x0d, + 0x75, 0x35, 0x55, 0x15, 0x65, 0x25, 0x45, 0x05, + 0x79, 0x39, 0x59, 0x19, 0x69, 0x29, 0x49, 0x09, + 0x71, 0x31, 0x51, 0x11, 0x61, 0x21, 0x41, 0x01, + 0x7e, 0x3e, 0x5e, 0x1e, 0x6e, 0x2e, 0x4e, 0x0e, + 0x76, 0x36, 0x56, 0x16, 0x66, 0x26, 0x46, 0x06, + 0x7a, 0x3a, 0x5a, 0x1a, 0x6a, 0x2a, 0x4a, 0x0a, + 0x72, 0x32, 0x52, 0x12, 0x62, 0x22, 0x42, 0x02, + 0x7c, 0x3c, 0x5c, 0x1c, 0x6c, 0x2c, 0x4c, 0x0c, + 0x74, 0x34, 0x54, 0x14, 0x64, 0x24, 0x44, 0x04, + 0x78, 0x38, 0x58, 0x18, 0x68, 0x28, 0x48, 0x08, + 0x70, 0x30, 0x50, 0x10, 0x60, 0x20, 0x40, 0x00, + }; + + UINT8 codeword = m_IM->IM_getCodeword(ROM, mmc, code_num); + + if (codeword & 0x80) + { + *LPSind = 1; + *MPScount = run_count[codeword >> (code_num ^ 0x07)]; + } + else + { + *MPScount = (1 << code_num); + } +} + +// BG + +void SDD1_BG::BG_prepareDecomp() +{ + m_MPScount = 0; + m_LPSind = 0; +} + +UINT8 SDD1_BG::BG_getBit(UINT8 *ROM, UINT32 *mmc, UINT8* endOfRun) +{ + UINT8 bit; + + if (!(m_MPScount || m_LPSind)) + { + m_GCD->GCD_getRunCount(ROM, mmc, m_code_num, &(m_MPScount), &(m_LPSind)); + } + + if (m_MPScount) + { + bit = 0; + m_MPScount--; + } + else + { + bit = 1; + m_LPSind = 0; + } + + if (m_MPScount || m_LPSind) + { + (*endOfRun) = 0; + } + else + { + (*endOfRun) = 1; + } + + return bit; +} + +// PEM + +struct SDD1_PEM_state +{ + UINT8 code_num; + UINT8 nextIfMPS; + UINT8 nextIfLPS; +}; + +static const SDD1_PEM_state PEM_evolution_table[33] = +{ + { 0,25,25}, + { 0, 2, 1}, + { 0, 3, 1}, + { 0, 4, 2}, + { 0, 5, 3}, + { 1, 6, 4}, + { 1, 7, 5}, + { 1, 8, 6}, + { 1, 9, 7}, + { 2,10, 8}, + { 2,11, 9}, + { 2,12,10}, + { 2,13,11}, + { 3,14,12}, + { 3,15,13}, + { 3,16,14}, + { 3,17,15}, + { 4,18,16}, + { 4,19,17}, + { 5,20,18}, + { 5,21,19}, + { 6,22,20}, + { 6,23,21}, + { 7,24,22}, + { 7,24,23}, + { 0,26, 1}, + { 1,27, 2}, + { 2,28, 4}, + { 3,29, 8}, + { 4,30,12}, + { 5,31,16}, + { 6,32,18}, + { 7,24,22} +}; + +void SDD1_PEM::PEM_prepareDecomp() +{ + for (int i = 0; i < 32; i++) + { + m_contextInfo[i].status = 0; + m_contextInfo[i].MPS = 0; + } +} + +UINT8 SDD1_PEM::PEM_getBit(UINT8 *ROM, UINT32 *mmc, UINT8 context) +{ + UINT8 endOfRun; + UINT8 bit; + + SDD1_PEM_ContextInfo *pContInfo = &(m_contextInfo)[context]; + UINT8 currStatus = pContInfo->status; + const SDD1_PEM_state* pState = &(PEM_evolution_table[currStatus]); + UINT8 currentMPS = pContInfo->MPS; + + bit = m_BG[pState->code_num]->BG_getBit(ROM, mmc, &endOfRun); + + if (endOfRun) + { + if (bit) + { + if (!(currStatus & 0xfe)) + { + (pContInfo->MPS) ^= 0x01; + } + pContInfo->status = pState->nextIfLPS; + } + else + { + pContInfo->status = pState->nextIfMPS; + } + } + + return bit ^ currentMPS; +} + +// CM + +void SDD1_CM::CM_prepareDecomp(UINT8 *ROM, UINT32 *mmc, UINT32 first_byte) +{ + INT32 i = 0; + m_bitplanesInfo = ROM[SSD1_ADD(first_byte)] & 0xc0; + m_contextBitsInfo = ROM[SSD1_ADD(first_byte)] & 0x30; + m_bit_number = 0; + for (i = 0; i < 8; i++) + { + m_prevBitplaneBits[i] = 0; + } + switch (m_bitplanesInfo) + { + case 0x00: + m_currBitplane = 1; + break; + case 0x40: + m_currBitplane = 7; + break; + case 0x80: + m_currBitplane = 3; + break; + } +} + +UINT8 SDD1_CM::CM_getBit(UINT8 *ROM, UINT32 *mmc) +{ + UINT8 currContext; + UINT16 *context_bits; + UINT8 bit = 0; + + switch (m_bitplanesInfo) + { + case 0x00: + m_currBitplane ^= 0x01; + break; + case 0x40: + m_currBitplane ^= 0x01; + if (!(m_bit_number & 0x7f)) + m_currBitplane = ((m_currBitplane + 2) & 0x07); + break; + case 0x80: + m_currBitplane ^= 0x01; + if (!(m_bit_number & 0x7f)) + m_currBitplane ^= 0x02; + break; + case 0xc0: + m_currBitplane = m_bit_number & 0x07; + break; + } + + context_bits = &(m_prevBitplaneBits)[m_currBitplane]; + + currContext = (m_currBitplane & 0x01) << 4; + switch (m_contextBitsInfo) + { + case 0x00: + currContext |= ((*context_bits & 0x01c0) >> 5) | (*context_bits & 0x0001); + break; + case 0x10: + currContext |= ((*context_bits & 0x0180) >> 5) | (*context_bits & 0x0001); + break; + case 0x20: + currContext |= ((*context_bits & 0x00c0) >> 5) | (*context_bits & 0x0001); + break; + case 0x30: + currContext |= ((*context_bits & 0x0180) >> 5) | (*context_bits & 0x0003); + break; + } + + bit = m_PEM->PEM_getBit(ROM, mmc, currContext); + + *context_bits <<= 1; + *context_bits |= bit; + + m_bit_number++; + + return bit; +} + +// OL + +void SDD1_OL::OL_prepareDecomp(UINT8 *ROM, UINT32 *mmc, UINT32 first_byte, UINT16 out_len, UINT8 *out_buf) +{ + m_bitplanesInfo = ROM[SSD1_ADD(first_byte)] & 0xc0; + m_length = out_len; + m_buffer = out_buf; +} + +void SDD1_OL::OL_launch(UINT8 *ROM, UINT32 *mmc) +{ + UINT8 i; + UINT8 register1 = 0, register2 = 0; + + switch (m_bitplanesInfo) + { + case 0x00: + case 0x40: + case 0x80: + i = 1; + do + { // if length == 0, we output 2^16 bytes + if (!i) + { + *(m_buffer++) = register2; + i = ~i; + } + else + { + for (register1 = register2 = 0, i = 0x80; i; i >>= 1) + { + if (m_CM->CM_getBit(ROM, mmc)) + register1 |= i; + + if (m_CM->CM_getBit(ROM, mmc)) + register2 |= i; + } + *(m_buffer++) = register1; + } + } while (--(m_length)); + break; + case 0xc0: + do + { + for (register1 = 0, i = 0x01; i; i <<= 1) + { + if (m_CM->CM_getBit(ROM, mmc)) + { + register1 |= i; + } + } + *(m_buffer++) = register1; + } while (--(m_length)); + break; + } +} + +// S-DD1 + +SDD1_emu::SDD1_emu(running_machine &machine) + : m_machine(machine) +{ + m_IM = auto_alloc(machine, SDD1_IM()); + m_GCD = auto_alloc(machine, SDD1_GCD(m_IM)); + m_BG0 = auto_alloc(machine, SDD1_BG(m_GCD, 0)); + m_BG1 = auto_alloc(machine, SDD1_BG(m_GCD, 1)); + m_BG2 = auto_alloc(machine, SDD1_BG(m_GCD, 2)); + m_BG3 = auto_alloc(machine, SDD1_BG(m_GCD, 3)); + m_BG4 = auto_alloc(machine, SDD1_BG(m_GCD, 4)); + m_BG5 = auto_alloc(machine, SDD1_BG(m_GCD, 5)); + m_BG6 = auto_alloc(machine, SDD1_BG(m_GCD, 6)); + m_BG7 = auto_alloc(machine, SDD1_BG(m_GCD, 7)); + m_PEM = auto_alloc(machine, SDD1_PEM(m_BG0, m_BG1, m_BG2, m_BG3, + m_BG4, m_BG5, m_BG6, m_BG7)); + m_CM = auto_alloc(machine, SDD1_CM(m_PEM)); + m_OL = auto_alloc(machine, SDD1_OL(m_CM)); +} + +void SDD1_emu::SDD1emu_decompress(UINT8 *ROM, UINT32 *mmc, UINT32 in_buf, UINT16 out_len, UINT8 *out_buf) +{ + m_IM->IM_prepareDecomp(in_buf); + m_BG0->BG_prepareDecomp(); + m_BG1->BG_prepareDecomp(); + m_BG2->BG_prepareDecomp(); + m_BG3->BG_prepareDecomp(); + m_BG4->BG_prepareDecomp(); + m_BG5->BG_prepareDecomp(); + m_BG6->BG_prepareDecomp(); + m_BG7->BG_prepareDecomp(); + m_PEM->PEM_prepareDecomp(); + m_CM->CM_prepareDecomp(ROM, mmc, in_buf); + m_OL->OL_prepareDecomp(ROM, mmc, in_buf, out_len, out_buf); + + m_OL->OL_launch(ROM, mmc); +} + + +//------------------------------------------------- +// sns_rom_sdd1_device - constructor +//------------------------------------------------- + +const device_type SNS_LOROM_SDD1 = &device_creator; + + +sns_rom_sdd1_device::sns_rom_sdd1_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_sns_cart_interface( mconfig, *this ) +{ +} + +sns_rom_sdd1_device::sns_rom_sdd1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, SNS_LOROM_SDD1, "SNES Cart + S-DD1", tag, owner, clock, "sns_rom_sdd1", __FILE__), + device_sns_cart_interface( mconfig, *this ) +{ +} + + +void sns_rom_sdd1_device::device_start() +{ + m_sdd1emu = auto_alloc(machine(), SDD1_emu(machine())); + + m_buffer.data = (UINT8*)auto_alloc_array(machine(), UINT8, 0x10000); + m_buffer.ready = 0; + + save_item(NAME(m_sdd1_enable)); + save_item(NAME(m_xfer_enable)); + save_item(NAME(m_mmc)); + + for (int i = 0; i < 8; i++) + { + save_item(NAME(m_dma[i].addr), i); + save_item(NAME(m_dma[i].size), i); + } + + save_pointer(NAME(m_buffer.data), 0x10000); + save_item(NAME(m_buffer.offset)); + save_item(NAME(m_buffer.size)); + save_item(NAME(m_buffer.ready)); + + // TODO: save remaining decomp-related items so to fix support if we try to save mid-decompression... +} + +void sns_rom_sdd1_device::device_reset() +{ + m_sdd1_enable = 0x00; + m_xfer_enable = 0x00; + + m_mmc[0] = 0 << 20; + m_mmc[1] = 1 << 20; + m_mmc[2] = 2 << 20; + m_mmc[3] = 3 << 20; + + for(int i = 0; i < 8; i++) + { + m_dma[i].addr = 0; + m_dma[i].size = 0; + } +} + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +READ8_MEMBER( sns_rom_sdd1_device::chip_read ) +{ + UINT16 addr = offset & 0xffff; + + switch (addr) + { + case 0x4804: + return (m_mmc[0] >> 20) & 7; + case 0x4805: + return (m_mmc[1] >> 20) & 7; + case 0x4806: + return (m_mmc[2] >> 20) & 7; + case 0x4807: + return (m_mmc[3] >> 20) & 7; + } + +// we should never get here, but... + return 0; +} + + +WRITE8_MEMBER( sns_rom_sdd1_device::chip_write ) +{ + UINT16 addr = offset & 0xffff; + + if ((addr & 0x4380) == 0x4300) + { + UINT8 channel = (addr >> 4) & 7; + switch(addr & 0xf) + { + case 2: + m_dma[channel].addr = (m_dma[channel].addr & 0xffff00) + (data << 0); + break; + case 3: + m_dma[channel].addr = (m_dma[channel].addr & 0xff00ff) + (data << 8); + break; + case 4: + m_dma[channel].addr = (m_dma[channel].addr & 0x00ffff) + (data << 16); + break; + + case 5: + m_dma[channel].size = (m_dma[channel].size & 0xff00) + (data << 0); + break; + case 6: + m_dma[channel].size = (m_dma[channel].size & 0x00ff) + (data << 8); + break; + } + return; + } + + switch(addr) + { + case 0x4800: + m_sdd1_enable = data; + break; + case 0x4801: + m_xfer_enable = data; + break; + + case 0x4804: + m_mmc[0] = (data & 7) << 20; + break; + case 0x4805: + m_mmc[1] = (data & 7) << 20; + break; + case 0x4806: + m_mmc[2] = (data & 7) << 20; + break; + case 0x4807: + m_mmc[3] = (data & 7) << 20; + break; + } + +} + +UINT8 sns_rom_sdd1_device::read_helper(UINT32 addr) +{ + if (m_sdd1_enable & m_xfer_enable) + { + // at least one channel has S-DD1 decompression enabled... + for (int i = 0; i < 8; i++) + { + if (m_sdd1_enable & m_xfer_enable & (1 << i)) + { + // S-DD1 always uses fixed transfer mode, so address will not change during transfer + if ((addr + 0xc00000) == m_dma[i].addr) + { + UINT8 data; + if (!m_buffer.ready) + { + // first byte read for channel performs full decompression. + // this really should stream byte-by-byte, but it's not necessary since the size is known + m_buffer.offset = 0; + m_buffer.size = m_dma[i].size ? m_dma[i].size : 65536; + + // SDD1_emu calls this function; it needs to access uncompressed data; + // so temporarily disable decompression mode for decompress() call. + m_sdd1emu->SDD1emu_decompress(m_rom, m_mmc, addr, m_buffer.size, m_buffer.data); + + m_buffer.ready = 1; + } + + // fetch a decompressed byte; once buffer is depleted, disable channel and invalidate buffer + data = m_buffer.data[(UINT16)m_buffer.offset++]; + if (m_buffer.offset >= m_buffer.size) + { + m_buffer.ready = 0; + m_xfer_enable &= ~(1 << i); + } + + return data; + } + } + } + } + + return m_rom[m_mmc[(addr >> 20) & 3] + (addr & 0x0fffff)]; +} + +READ8_MEMBER(sns_rom_sdd1_device::read_l) +{ + if (offset < 0x400000) + return m_rom[rom_bank_map[offset / 0x10000] * 0x8000 + (offset & 0x7fff)]; + else + return m_rom[rom_bank_map[(offset - 0x400000) / 0x8000] * 0x8000 + (offset & 0x7fff)]; +} + +READ8_MEMBER(sns_rom_sdd1_device::read_h) +{ + if (offset >= 0x400000) + return read_helper(offset - 0x400000); + else + return read_l(space, offset); +} + + +READ8_MEMBER( sns_rom_sdd1_device::read_ram ) +{ + return m_nvram[offset & 0x1fff]; +} + +WRITE8_MEMBER( sns_rom_sdd1_device::write_ram ) +{ + m_nvram[offset & 0x1fff] = data; +} diff --git a/src/devices/bus/snes/sdd1.h b/src/devices/bus/snes/sdd1.h new file mode 100644 index 00000000000..cef80512694 --- /dev/null +++ b/src/devices/bus/snes/sdd1.h @@ -0,0 +1,187 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __SNS_SDD1_H +#define __SNS_SDD1_H + +#include "snes_slot.h" + +// misc classes for the S-DD1 + +class SDD1_IM //Input Manager +{ +public: + SDD1_IM() {} + + UINT32 m_byte_ptr; + UINT8 m_bit_count; + + void IM_prepareDecomp(UINT32 in_buf); + UINT8 IM_getCodeword(UINT8 *ROM, UINT32 *mmc, const UINT8 code_len); +}; + +class SDD1_GCD //Golomb-Code Decoder +{ +public: + SDD1_GCD(SDD1_IM* associatedIM) + : m_IM(associatedIM) { } + + SDD1_IM* m_IM; + + void GCD_getRunCount(UINT8 *ROM, UINT32 *mmc, UINT8 code_num, UINT8* MPScount, UINT8* LPSind); +}; + +class SDD1_BG // Bits Generator +{ +public: + SDD1_BG(SDD1_GCD* associatedGCD, UINT8 code) + : m_code_num(code), + m_GCD(associatedGCD) { } + + UINT8 m_code_num; + UINT8 m_MPScount; + UINT8 m_LPSind; + SDD1_GCD* m_GCD; + + void BG_prepareDecomp(); + UINT8 BG_getBit(UINT8 *ROM, UINT32 *mmc, UINT8* endOfRun); +} ; + +struct SDD1_PEM_ContextInfo +{ + UINT8 status; + UINT8 MPS; +}; + +class SDD1_PEM //Probability Estimation Module +{ +public: + SDD1_PEM( + SDD1_BG* associatedBG0, SDD1_BG* associatedBG1, + SDD1_BG* associatedBG2, SDD1_BG* associatedBG3, + SDD1_BG* associatedBG4, SDD1_BG* associatedBG5, + SDD1_BG* associatedBG6, SDD1_BG* associatedBG7) + { + m_BG[0] = associatedBG0; + m_BG[1] = associatedBG1; + m_BG[2] = associatedBG2; + m_BG[3] = associatedBG3; + m_BG[4] = associatedBG4; + m_BG[5] = associatedBG5; + m_BG[6] = associatedBG6; + m_BG[7] = associatedBG7; + } + + SDD1_PEM_ContextInfo m_contextInfo[32]; + SDD1_BG* m_BG[8]; + + void PEM_prepareDecomp(); + UINT8 PEM_getBit(UINT8 *ROM, UINT32 *mmc, UINT8 context); +} ; + + +class SDD1_CM +{ +public: + SDD1_CM(SDD1_PEM* associatedPEM) + : m_PEM(associatedPEM) { } + + UINT8 m_bitplanesInfo; + UINT8 m_contextBitsInfo; + UINT8 m_bit_number; + UINT8 m_currBitplane; + UINT16 m_prevBitplaneBits[8]; + SDD1_PEM* m_PEM; + + void CM_prepareDecomp(UINT8 *ROM, UINT32 *mmc, UINT32 first_byte); + UINT8 CM_getBit(UINT8 *ROM, UINT32 *mmc); +} ; + + +class SDD1_OL +{ +public: + SDD1_OL(SDD1_CM* associatedCM) + : m_CM(associatedCM) { } + + UINT8 m_bitplanesInfo; + UINT16 m_length; + UINT8* m_buffer; + SDD1_CM* m_CM; + + void OL_prepareDecomp(UINT8 *ROM, UINT32 *mmc, UINT32 first_byte, UINT16 out_len, UINT8 *out_buf); + void OL_launch(UINT8 *ROM, UINT32 *mmc); +} ; + +class SDD1_emu +{ +public: + SDD1_emu(running_machine &machine); + + running_machine &machine() const { return m_machine; } + + SDD1_IM* m_IM; + SDD1_GCD* m_GCD; + SDD1_BG* m_BG0; SDD1_BG* m_BG1; SDD1_BG* m_BG2; SDD1_BG* m_BG3; + SDD1_BG* m_BG4; SDD1_BG* m_BG5; SDD1_BG* m_BG6; SDD1_BG* m_BG7; + SDD1_PEM* m_PEM; + SDD1_CM* m_CM; + SDD1_OL* m_OL; + + void SDD1emu_decompress(UINT8 *ROM, UINT32 *mmc, UINT32 in_buf, UINT16 out_len, UINT8 *out_buf); + +private: + running_machine& m_machine; +}; + + + +// ======================> sns_rom_sdd1_device + +class sns_rom_sdd1_device : public device_t, + public device_sns_cart_interface +{ +public: + // construction/destruction + sns_rom_sdd1_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + sns_rom_sdd1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_l); + virtual DECLARE_READ8_MEMBER(read_h); + virtual DECLARE_READ8_MEMBER(read_ram); + virtual DECLARE_WRITE8_MEMBER(write_ram); + virtual DECLARE_READ8_MEMBER(chip_read); + virtual DECLARE_WRITE8_MEMBER(chip_write); + + UINT8 read_helper(UINT32 offset); + + UINT8 m_sdd1_enable; // channel bit-mask + UINT8 m_xfer_enable; // channel bit-mask + UINT32 m_mmc[4]; // memory map controller ROM indices + + struct + { + UINT32 addr; // $43x2-$43x4 -- DMA transfer address + UINT16 size; // $43x5-$43x6 -- DMA transfer size + } m_dma[8]; + + SDD1_emu* m_sdd1emu; + + struct + { + UINT8 *data; // pointer to decompressed S-DD1 data (65536 bytes) + UINT16 offset; // read index into S-DD1 decompression buffer + UINT32 size; // length of data buffer; reads decrement counter, set ready to false at 0 + UINT8 ready; // 1 when data[] is valid; 0 to invoke sdd1emu.decompress() + } m_buffer; +}; + + +// device type definition +extern const device_type SNS_LOROM_SDD1; + +#endif diff --git a/src/devices/bus/snes/sfx.c b/src/devices/bus/snes/sfx.c new file mode 100644 index 00000000000..9fce31d00db --- /dev/null +++ b/src/devices/bus/snes/sfx.c @@ -0,0 +1,148 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + SuperFX add-on chip emulation (for SNES/SFC) + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "sfx.h" +#include "cpu/g65816/g65816.h" + +//------------------------------------------------- +// sns_rom_superfx_device - constructor +//------------------------------------------------- + +const device_type SNS_LOROM_SUPERFX = &device_creator; + + +sns_rom_superfx_device::sns_rom_superfx_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : sns_rom_device(mconfig, SNS_LOROM_SUPERFX, "SNES Cart (LoROM) + SuperFX", tag, owner, clock, "sns_rom_superfx", __FILE__), + m_superfx(*this, "superfx") +{ +} + +void sns_rom_superfx_device::device_start() +{ + save_item(NAME(sfx_ram)); +} + +void sns_rom_superfx_device::device_reset() +{ + memset(sfx_ram, 0x00, sizeof(sfx_ram)); +} + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +// LoROM + SuperFX (GSU-1,2) +// TODO: mask sfx_ram based on the actual RAM... + +READ8_MEMBER( sns_rom_superfx_device::superfx_r_bank1 ) +{ + return m_rom[rom_bank_map[offset / 0x10000] * 0x8000 + (offset & 0x7fff)]; +} + +READ8_MEMBER( sns_rom_superfx_device::superfx_r_bank2 ) +{ + return m_rom[rom_bank_map[offset / 0x8000] * 0x8000 + (offset & 0x7fff)]; +} + +READ8_MEMBER( sns_rom_superfx_device::superfx_r_bank3 ) +{ + return sfx_ram[offset & 0xfffff]; +} + +WRITE8_MEMBER( sns_rom_superfx_device::superfx_w_bank1 ) +{ +} + +WRITE8_MEMBER( sns_rom_superfx_device::superfx_w_bank2 ) +{ +} + +WRITE8_MEMBER( sns_rom_superfx_device::superfx_w_bank3 ) +{ + sfx_ram[offset & 0xfffff] = data; +} + +static ADDRESS_MAP_START( sfx_map, AS_PROGRAM, 8, sns_rom_superfx_device ) + AM_RANGE(0x000000, 0x3fffff) AM_READWRITE(superfx_r_bank1, superfx_w_bank1) + AM_RANGE(0x400000, 0x5fffff) AM_READWRITE(superfx_r_bank2, superfx_w_bank2) + AM_RANGE(0x600000, 0x7dffff) AM_READWRITE(superfx_r_bank3, superfx_w_bank3) + AM_RANGE(0x800000, 0xbfffff) AM_READWRITE(superfx_r_bank1, superfx_w_bank1) + AM_RANGE(0xc00000, 0xdfffff) AM_READWRITE(superfx_r_bank2, superfx_w_bank2) + AM_RANGE(0xe00000, 0xffffff) AM_READWRITE(superfx_r_bank3, superfx_w_bank3) +ADDRESS_MAP_END + + +WRITE_LINE_MEMBER(sns_rom_superfx_device::snes_extern_irq_w) +{ + machine().device("maincpu")->execute().set_input_line(G65816_LINE_IRQ, state); +} + + +static MACHINE_CONFIG_FRAGMENT( snes_sfx ) + MCFG_CPU_ADD("superfx", SUPERFX, 21480000) /* 21.48MHz */ + MCFG_CPU_PROGRAM_MAP(sfx_map) + MCFG_SUPERFX_OUT_IRQ(WRITELINE(sns_rom_superfx_device, snes_extern_irq_w)) /* IRQ line from cart */ +MACHINE_CONFIG_END + +machine_config_constructor sns_rom_superfx_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( snes_sfx ); +} + +READ8_MEMBER( sns_rom_superfx_device::chip_read ) +{ + return m_superfx->mmio_read(offset); +} + +WRITE8_MEMBER( sns_rom_superfx_device::chip_write ) +{ + m_superfx->mmio_write(offset, data); +} + + +READ8_MEMBER( sns_rom_superfx_device::read_l ) +{ + return read_h(space, offset); +} + +READ8_MEMBER(sns_rom_superfx_device::read_h) +{ + if (offset < 0x400000) + return m_rom[rom_bank_map[offset / 0x10000] * 0x8000 + (offset & 0x7fff)]; + else if (offset < 0x600000) + { + if (m_superfx->access_rom()) + { + return m_rom[rom_bank_map[(offset - 0x400000) / 0x8000] * 0x8000 + (offset & 0x7fff)]; + } + else + { + static const UINT8 sfx_data[16] = { + 0x00, 0x01, 0x00, 0x01, 0x04, 0x01, 0x00, 0x01, + 0x00, 0x01, 0x08, 0x01, 0x00, 0x01, 0x0c, 0x01, + }; + return sfx_data[offset & 0x0f]; + } + } + return 0xff; // this handler should never be called for [60-7f]/[e0-ff] ranges +} + +READ8_MEMBER( sns_rom_superfx_device::read_ram ) +{ + if (m_superfx->access_ram()) + return sfx_ram[offset & 0xfffff]; + return 0xff; // should be open bus... +} + +WRITE8_MEMBER( sns_rom_superfx_device::write_ram ) +{ + if (m_superfx->access_ram()) + sfx_ram[offset & 0xfffff] = data; +} diff --git a/src/devices/bus/snes/sfx.h b/src/devices/bus/snes/sfx.h new file mode 100644 index 00000000000..04a2313fd92 --- /dev/null +++ b/src/devices/bus/snes/sfx.h @@ -0,0 +1,50 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __SNS_SFX_H +#define __SNS_SFX_H + +#include "snes_slot.h" +#include "rom.h" +#include "cpu/superfx/superfx.h" + + +// ======================> sns_rom_superfx_device + +class sns_rom_superfx_device : public sns_rom_device +{ +public: + // construction/destruction + sns_rom_superfx_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual machine_config_constructor device_mconfig_additions() const; + + required_device m_superfx; + + // additional reading and writing + virtual DECLARE_READ8_MEMBER(read_l); + virtual DECLARE_READ8_MEMBER(read_h); + virtual DECLARE_READ8_MEMBER(read_ram); + virtual DECLARE_WRITE8_MEMBER(write_ram); + virtual DECLARE_READ8_MEMBER(chip_read); + virtual DECLARE_WRITE8_MEMBER(chip_write); + + virtual DECLARE_READ8_MEMBER(superfx_r_bank1); + virtual DECLARE_READ8_MEMBER(superfx_r_bank2); + virtual DECLARE_READ8_MEMBER(superfx_r_bank3); + virtual DECLARE_WRITE8_MEMBER(superfx_w_bank1); + virtual DECLARE_WRITE8_MEMBER(superfx_w_bank2); + virtual DECLARE_WRITE8_MEMBER(superfx_w_bank3); + virtual DECLARE_WRITE_LINE_MEMBER(snes_extern_irq_w); + + + UINT8 sfx_ram[0x200000]; +}; + + +// device type definition +extern const device_type SNS_LOROM_SUPERFX; + +#endif diff --git a/src/devices/bus/snes/sgb.c b/src/devices/bus/snes/sgb.c new file mode 100644 index 00000000000..93edb4aeb50 --- /dev/null +++ b/src/devices/bus/snes/sgb.c @@ -0,0 +1,292 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + Super Game Boy emulation (for SNES/SFC) + + TODO: almost everything, e.g. + * implement gb_timer_callback + * gb_io_r/w + * add hook-up to copy LCD scanline to m_lcd_buffer + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "sgb.h" + +//------------------------------------------------- +// sns_rom_sgb_device - constructor +//------------------------------------------------- + +const device_type SNS_LOROM_SUPERGB = &device_creator; + + +sns_rom_sgb_device::sns_rom_sgb_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : sns_rom_device(mconfig, SNS_LOROM_SUPERGB, "SNES Super Game Boy Cart", tag, owner, clock, "sns_rom_sgb", __FILE__), + m_gb_cpu(*this, "sgb_cpu"), + m_gb_snd(*this, "sgb_snd"), + m_gb_lcd(*this, "sgb_lcd"), + m_cartslot(*this, "gb_slot") +{ +} + + +void sns_rom_sgb_device::device_start() +{ +} + +void sns_rom_sgb_device::device_reset() +{ +} + + + +// SuperGB emulation + +//------------------------------------------------- +// ADDRESS_MAP( supergb_map ) +//------------------------------------------------- + +READ8_MEMBER(sns_rom_sgb_device::gb_cart_r) +{ + return m_cartslot->read_rom(space, offset); +} + +WRITE8_MEMBER(sns_rom_sgb_device::gb_bank_w) +{ + m_cartslot->write_bank(space, offset, data); +} + +READ8_MEMBER(sns_rom_sgb_device::gb_ram_r) +{ + return m_cartslot->read_ram(space, offset); +} + +WRITE8_MEMBER(sns_rom_sgb_device::gb_ram_w) +{ + m_cartslot->write_ram(space, offset, data); +} + +READ8_MEMBER(sns_rom_sgb_device::gb_echo_r) +{ + return space.read_byte(0xc000 + offset); +} + +WRITE8_MEMBER(sns_rom_sgb_device::gb_echo_w) +{ + return space.write_byte(0xc000 + offset, data); +} + +READ8_MEMBER(sns_rom_sgb_device::gb_io_r) +{ + return 0; +} + +WRITE8_MEMBER(sns_rom_sgb_device::gb_io_w) +{ +} + +READ8_MEMBER(sns_rom_sgb_device::gb_ie_r) +{ + return m_gb_cpu->get_ie(); +} + +WRITE8_MEMBER(sns_rom_sgb_device::gb_ie_w) +{ + m_gb_cpu->set_ie(data & 0x1f); +} + + + +static ADDRESS_MAP_START(supergb_map, AS_PROGRAM, 8, sns_rom_sgb_device ) + ADDRESS_MAP_UNMAP_HIGH + AM_RANGE(0x0000, 0x7fff) AM_READWRITE(gb_cart_r, gb_bank_w) + AM_RANGE(0x8000, 0x9fff) AM_DEVREADWRITE("sgb_lcd", sgb_lcd_device, vram_r, vram_w) /* 8k VRAM */ + AM_RANGE(0xa000, 0xbfff) AM_READWRITE(gb_ram_r, gb_ram_w ) /* 8k switched RAM bank (cartridge) */ + AM_RANGE(0xc000, 0xdfff) AM_RAM /* 8k low RAM */ + AM_RANGE(0xe000, 0xfdff) AM_READWRITE(gb_echo_r, gb_echo_w) /* echo RAM */ + AM_RANGE(0xff00, 0xff0f) AM_READWRITE(gb_io_r, gb_io_w) /* I/O */ + AM_RANGE(0xff10, 0xff26) AM_DEVREADWRITE("sgb_snd", gameboy_sound_device, sound_r, sound_w) /* sound registers */ + AM_RANGE(0xfe00, 0xfeff) AM_DEVREADWRITE("sgb_lcd", sgb_lcd_device, oam_r, oam_w) /* OAM RAM */ + AM_RANGE(0xff27, 0xff2f) AM_NOP /* unused */ + AM_RANGE(0xff30, 0xff3f) AM_DEVREADWRITE("sgb_snd", gameboy_sound_device, wave_r, wave_w) /* Wave RAM */ + AM_RANGE(0xff40, 0xff7f) AM_DEVREADWRITE("sgb_lcd", sgb_lcd_device, video_r, video_w) /* also disable bios?? */ /* Video controller & BIOS flip-flop */ + AM_RANGE(0xff80, 0xfffe) AM_RAM /* High RAM */ + AM_RANGE(0xffff, 0xffff) AM_READWRITE(gb_ie_r, gb_ie_w) /* Interrupt enable register */ +ADDRESS_MAP_END + + + +WRITE8_MEMBER( sns_rom_sgb_device::gb_timer_callback ) +{ +} + + +static SLOT_INTERFACE_START(supergb_cart) + SLOT_INTERFACE_INTERNAL("rom", GB_STD_ROM) + SLOT_INTERFACE_INTERNAL("rom_mbc1", GB_ROM_MBC1) +SLOT_INTERFACE_END + +static MACHINE_CONFIG_FRAGMENT( supergb ) + MCFG_CPU_ADD("sgb_cpu", LR35902, 4295454) /* 4.295454 MHz */ + MCFG_CPU_PROGRAM_MAP(supergb_map) + MCFG_LR35902_TIMER_CB(WRITE8(sns_rom_sgb_device, gb_timer_callback)) + MCFG_LR35902_HALT_BUG + + MCFG_GB_LCD_SGB_ADD("sgb_lcd") + + MCFG_SOUND_ADD("sgb_snd", GAMEBOY, 0) + + MCFG_GB_CARTRIDGE_ADD("gb_slot", supergb_cart, NULL) +MACHINE_CONFIG_END + + +machine_config_constructor sns_rom_sgb_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( supergb ); +} + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + + +READ8_MEMBER(sns_rom_sgb_device::read_l) +{ + return read_h(space, offset); +} + +READ8_MEMBER(sns_rom_sgb_device::read_h) +{ + int bank = offset / 0x10000; + return m_rom[rom_bank_map[bank] * 0x8000 + (offset & 0x7fff)]; +} + +READ8_MEMBER( sns_rom_sgb_device::chip_read ) +{ + UINT16 address = offset & 0xffff; + + //LY counter + if (address == 0x6000) + { + m_sgb_ly = 0;// GameBoy PPU LY here + m_sgb_row = m_lcd_row; + return m_sgb_ly; + } + + //command ready port + if (address == 0x6002) + { + bool data = (m_packetsize > 0); + if (data) + { + for (int i = 0; i < 16; i++) + m_joy_pckt[i] = m_packet_data[0][i]; + m_packetsize--; + + //hack because we still don't emulate input packets! + if (!m_packetsize) m_packetsize = 64; + + // shift packet + for (int i = 0; i < m_packetsize; i++) + for (int j = 0; j < 16; j++) + m_packet_data[i][j] = m_packet_data[i + 1][j]; + } + return data; + } + + //ICD2 revision + if (address == 0x600f) + return 0x21; + + //command port + if ((address & 0xfff0) == 0x7000) + return m_joy_pckt[address & 0x0f]; + + //VRAM port + if (address == 0x7800) + { + UINT8 data = m_lcd_output[m_vram_offs]; + m_vram_offs = (m_vram_offs + 1) % 320; + return data; + } + + return 0x00; // this should never happen? +} + +void sns_rom_sgb_device::lcd_render(UINT32 *source) +{ + memset(m_lcd_output, 0x00, 320 * sizeof(UINT16)); + + for (int y = 0; y < 8; y++) + { + for (int x = 0; x < 160; x++) + { + UINT32 pixel = *source++; + UINT16 addr = y * 2 + (x / 8 * 16); + m_lcd_output[addr + 0] |= ((pixel & 1) >> 0) << (7 - (x & 7)); + m_lcd_output[addr + 1] |= ((pixel & 2) >> 1) << (7 - (x & 7)); + } + } +} + +WRITE8_MEMBER( sns_rom_sgb_device::chip_write ) +{ + UINT16 address = offset & 0xffff; + + //VRAM port + if (address == 0x6001) + { + m_vram = data; + m_vram_offs = 0; + + UINT8 offset = (m_sgb_row - (4 - (m_vram - (m_sgb_ly & 3)))) & 3; + lcd_render(m_lcd_buffer + offset * 160 * 8); + + return; + } + + //control port + if (address == 0x6003) + { + if ((m_port & 0x80) == 0x00 && (data & 0x80) == 0x80) + { + //reset + } + + switch (data & 3) + { + //change CPU frequency + } + m_port = data; + return; + } + + if (address == 0x6004) + { + //joypad 1 + m_joy1 = data; + return; + } + if (address == 0x6005) + { + //joypad 2 + m_joy2 = data; + return; + } + if (address == 0x6006) + { + //joypad 3 + m_joy3 = data; + return; + } + if (address == 0x6007) + { + //joypad 4 + m_joy4 = data; + return; + } + +} diff --git a/src/devices/bus/snes/sgb.h b/src/devices/bus/snes/sgb.h new file mode 100644 index 00000000000..01bfd6ea887 --- /dev/null +++ b/src/devices/bus/snes/sgb.h @@ -0,0 +1,78 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __SNS_SGB_H +#define __SNS_SGB_H + +#include "snes_slot.h" +#include "rom.h" + +#include "cpu/lr35902/lr35902.h" +#include "bus/gameboy/gb_slot.h" +#include "bus/gameboy/rom.h" +#include "bus/gameboy/mbc.h" +#include "video/gb_lcd.h" +#include "audio/gb.h" + + +// ======================> sns_rom_sgb_device + +class sns_rom_sgb_device : public sns_rom_device +{ +public: + // construction/destruction + sns_rom_sgb_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual machine_config_constructor device_mconfig_additions() const; + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_l); + virtual DECLARE_READ8_MEMBER(read_h); + virtual DECLARE_READ8_MEMBER(chip_read); + virtual DECLARE_WRITE8_MEMBER(chip_write); + + virtual DECLARE_READ8_MEMBER(gb_cart_r); + virtual DECLARE_WRITE8_MEMBER(gb_bank_w); + virtual DECLARE_READ8_MEMBER(gb_ram_r); + virtual DECLARE_WRITE8_MEMBER(gb_ram_w); + virtual DECLARE_READ8_MEMBER(gb_echo_r); + virtual DECLARE_WRITE8_MEMBER(gb_echo_w); + virtual DECLARE_READ8_MEMBER(gb_io_r); + virtual DECLARE_WRITE8_MEMBER(gb_io_w); + virtual DECLARE_READ8_MEMBER(gb_ie_r); + virtual DECLARE_WRITE8_MEMBER(gb_ie_w); + virtual DECLARE_WRITE8_MEMBER(gb_timer_callback); + + required_device m_gb_cpu; + required_device m_gb_snd; + required_device m_gb_lcd; + required_device m_cartslot; + + void lcd_render(UINT32 *source); + + // ICD2 regs + UINT8 m_sgb_ly; + UINT8 m_sgb_row; + UINT8 m_vram; + UINT8 m_port; + UINT8 m_joy1, m_joy2, m_joy3, m_joy4; + UINT8 m_joy_pckt[16]; + UINT16 m_vram_offs; + UINT8 m_mlt_req; + + UINT32 m_lcd_buffer[4 * 160 * 8]; + UINT16 m_lcd_output[320]; + UINT16 m_lcd_row; + + // input bits + int m_packetsize; + UINT8 m_packet_data[64][16]; +}; + + +// device type definition +extern const device_type SNS_LOROM_SUPERGB; + +#endif diff --git a/src/devices/bus/snes/snes_carts.c b/src/devices/bus/snes/snes_carts.c new file mode 100644 index 00000000000..478dd6af83c --- /dev/null +++ b/src/devices/bus/snes/snes_carts.c @@ -0,0 +1,52 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/********************************************************************** + + SNES carts + +**********************************************************************/ + +#include "snes_carts.h" + +SLOT_INTERFACE_START(snes_cart) + SLOT_INTERFACE_INTERNAL("lorom", SNS_LOROM) + SLOT_INTERFACE_INTERNAL("lorom_bsx", SNS_LOROM_BSX) // LoROM + BS-X slot - unsupported + SLOT_INTERFACE_INTERNAL("lorom_cx4", SNS_LOROM) // Cart + CX4 - unsupported + SLOT_INTERFACE_INTERNAL("lorom_dsp", SNS_LOROM_NECDSP) + SLOT_INTERFACE_INTERNAL("lorom_dsp4", SNS_LOROM_NECDSP) + SLOT_INTERFACE_INTERNAL("lorom_obc1", SNS_LOROM_OBC1) + SLOT_INTERFACE_INTERNAL("lorom_sa1", SNS_LOROM_SA1) // Cart + SA1 - unsupported + SLOT_INTERFACE_INTERNAL("lorom_sdd1", SNS_LOROM_SDD1) + SLOT_INTERFACE_INTERNAL("lorom_sfx", SNS_LOROM_SUPERFX) + SLOT_INTERFACE_INTERNAL("lorom_sgb", SNS_LOROM_SUPERGB) // SuperGB base cart - unsupported + SLOT_INTERFACE_INTERNAL("lorom_st010", SNS_LOROM_SETA10) + SLOT_INTERFACE_INTERNAL("lorom_st011", SNS_LOROM_SETA11) + SLOT_INTERFACE_INTERNAL("lorom_st018", SNS_LOROM) // Cart + ST018 - unsupported + SLOT_INTERFACE_INTERNAL("lorom_sufami", SNS_LOROM_SUFAMI) // Sufami Turbo base cart + SLOT_INTERFACE_INTERNAL("hirom", SNS_HIROM) + SLOT_INTERFACE_INTERNAL("hirom_bsx", SNS_HIROM_BSX) // HiROM + BS-X slot - unsupported + SLOT_INTERFACE_INTERNAL("hirom_dsp", SNS_HIROM_NECDSP) + SLOT_INTERFACE_INTERNAL("hirom_spc7110", SNS_HIROM_SPC7110) + SLOT_INTERFACE_INTERNAL("hirom_spcrtc", SNS_HIROM_SPC7110_RTC) + SLOT_INTERFACE_INTERNAL("hirom_srtc", SNS_HIROM_SRTC) + SLOT_INTERFACE_INTERNAL("bsxrom", SNS_ROM_BSX) // BS-X base cart - partial support only + SLOT_INTERFACE_INTERNAL("pfest94", SNS_PFEST94) + // pirate carts + SLOT_INTERFACE_INTERNAL("lorom_poke", SNS_LOROM_POKEMON) + SLOT_INTERFACE_INTERNAL("lorom_tekken2", SNS_LOROM_TEKKEN2) + SLOT_INTERFACE_INTERNAL("lorom_sbld", SNS_LOROM_SOULBLAD) + SLOT_INTERFACE_INTERNAL("lorom_mcpir1", SNS_LOROM_MCPIR1) + SLOT_INTERFACE_INTERNAL("lorom_mcpir2", SNS_LOROM_MCPIR2) + SLOT_INTERFACE_INTERNAL("lorom_20col", SNS_LOROM_20COL) + SLOT_INTERFACE_INTERNAL("lorom_pija", SNS_LOROM_BANANA) // not working yet + SLOT_INTERFACE_INTERNAL("lorom_bugs", SNS_LOROM_BUGSLIFE) // not working yet + // legacy slots to support DSPx games from fullpath + SLOT_INTERFACE_INTERNAL("lorom_dsp1leg", SNS_LOROM_NECDSP1_LEG) + SLOT_INTERFACE_INTERNAL("lorom_dsp1bleg",SNS_LOROM_NECDSP1B_LEG) + SLOT_INTERFACE_INTERNAL("lorom_dsp2leg", SNS_LOROM_NECDSP2_LEG) + SLOT_INTERFACE_INTERNAL("lorom_dsp3leg", SNS_LOROM_NECDSP3_LEG) + SLOT_INTERFACE_INTERNAL("lorom_dsp4leg", SNS_LOROM_NECDSP4_LEG) + SLOT_INTERFACE_INTERNAL("hirom_dsp1leg", SNS_HIROM_NECDSP1_LEG) + SLOT_INTERFACE_INTERNAL("lorom_st10leg", SNS_LOROM_SETA10_LEG) + SLOT_INTERFACE_INTERNAL("lorom_st11leg", SNS_LOROM_SETA11_LEG) +SLOT_INTERFACE_END diff --git a/src/devices/bus/snes/snes_carts.h b/src/devices/bus/snes/snes_carts.h new file mode 100644 index 00000000000..11eab07a315 --- /dev/null +++ b/src/devices/bus/snes/snes_carts.h @@ -0,0 +1,31 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/********************************************************************** + + SNES carts + +**********************************************************************/ + +#pragma once + +#ifndef __SNES_CARTS_H__ +#define __SNES_CARTS_H__ + +#include "emu.h" + +#include "rom.h" +#include "rom21.h" +#include "bsx.h" +#include "sa1.h" +#include "sdd1.h" +#include "sfx.h" +#include "sgb.h" +#include "spc7110.h" +#include "sufami.h" +#include "upd.h" +#include "event.h" + +// supported devices +SLOT_INTERFACE_EXTERN(snes_cart); + +#endif // __SNES_CARTS_H__ diff --git a/src/devices/bus/snes/snes_slot.c b/src/devices/bus/snes/snes_slot.c new file mode 100644 index 00000000000..d44325d728f --- /dev/null +++ b/src/devices/bus/snes/snes_slot.c @@ -0,0 +1,1374 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli,Cowering +/*********************************************************************************************************** + + + SNES cart emulation + (through slot devices) + + + Carts can be mapped in memory in several different ways and accesses to carts depend + on the presence of add-on chips (which map their I/O to diff memory areas) + + Hence, carts can interface with the main system through the following handlers + * read_l : typically used to read ROM from memory range [00-7f][0000-ffff] + * read_h : typically used to read ROM from memory range [80-ff][0000-ffff] + * read_ram : used to read (NV)RAM at the appropriate offset (masks has to be applied + *before* calling it, if dealing with >32K RAM) + * write_ram : used to write (NV)RAM at the appropriate offset + * read_chip : used to read add-on chip registers + * write_chip : used to write to add-on chip registers + + Also, we define two additional ROM access handlers, write_l & write_h for carts with + subslots (e.g. BS-X compatible ones), that need to write to subslot (NV)RAM independently + to accesses to their own (NV)RAM. + + Notes about add-on detection and handling (useful for future addition of st018, cx4, etc.) + =============================================================================================== + When loading from softlist, m_type would be enough to take care of add-on chips, because + the ones needing a CPU dump have it in the zipfile. However, to support these games also + from fullpath, both with files having DSP data appended to the .sfc and with older dumps + missing DSP data, a second variable is present in the SNES slot: m_addon. + From fullpath, support works as follows + - get_default_card_software needs to decide whether to use the main devices or the legacy + ones containing DSP dump as device roms, so it gets m_type as the main device should be + used and if m_addon is ADDON_DSP* or ADDON_ST*, then it checks if the DSP data is appended + or if m_type has to be switched to legacy type + - call_load needs to detect faulty dumps too, to alloc m_addon_bios and copy the data from + the correct place, so if m_addon is ADDON_DSP* or ADDON_ST* it checks whether DSP data is + appended or not: if it is, this data is copied to m_addon_bios; if not, then we are in + the legacy device case and data is copied from the device rom + After the cart has been loaded and emulation has started, only m_type is needed to later + handlers installation and cart accesses + + Also notice that, from softlist, DSP1, 1B, 2, 3 are treated as the same device, because they + all have the same I/O and the only difference (i.e. the DSP data) comes from the zipfile itself. + OTOH, to support faulty dumps missing DSP content, we need separate legacy devices... + + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "snes_slot.h" + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type SNS_CART_SLOT = &device_creator; +const device_type SNS_SUFAMI_CART_SLOT = &device_creator; +const device_type SNS_BSX_CART_SLOT = &device_creator; + +//************************************************************************** +// SNES Cartridge Interface +//************************************************************************** + +//------------------------------------------------- +// device_sns_cart_interface - constructor +//------------------------------------------------- + +device_sns_cart_interface::device_sns_cart_interface(const machine_config &mconfig, device_t &device) + : device_slot_card_interface(mconfig, device), + m_rom(NULL), + m_rom_size(0) +{ +} + + +//------------------------------------------------- +// ~device_sns_cart_interface - destructor +//------------------------------------------------- + +device_sns_cart_interface::~device_sns_cart_interface() +{ +} + +//------------------------------------------------- +// rom_alloc - alloc the space for the cart +//------------------------------------------------- + +void device_sns_cart_interface::rom_alloc(UINT32 size, const char *tag) +{ + if (m_rom == NULL) + { + m_rom = device().machine().memory().region_alloc(std::string(tag).append(SNSSLOT_ROM_REGION_TAG).c_str(), size, 1, ENDIANNESS_LITTLE)->base(); + m_rom_size = size; + } +} + + +//------------------------------------------------- +// nvram_alloc - alloc the space for the nvram +//------------------------------------------------- + +void device_sns_cart_interface::nvram_alloc(UINT32 size) +{ + m_nvram.resize(size); +} + + +//------------------------------------------------- +// rtc_ram_alloc - alloc the space for the rtc_ram +// (needed to save it to NVRAM, will be removed +// once the RTCs become devices and NVRAM gets +// saved by the device itself) +//------------------------------------------------- + +void device_sns_cart_interface::rtc_ram_alloc(UINT32 size) +{ + m_rtc_ram.resize(size); +} + + +//------------------------------------------------- +// addon_bios_alloc - alloc the space for the +// (optional) add-on CPU bios +//------------------------------------------------- + +void device_sns_cart_interface::addon_bios_alloc(UINT32 size) +{ + m_bios.resize(size); +} + + +//------------------------------------------------- +// rom_map_setup - setup map of rom banks in 32K +// blocks, so to simplify ROM access +//------------------------------------------------- + +void device_sns_cart_interface::rom_map_setup(UINT32 size) +{ + int i; + // setup the rom_bank_map array to faster ROM read + for (i = 0; i < size / 0x8000; i++) + rom_bank_map[i] = i; + + // fill up remaining blocks with mirrors + while (i % 256) + { + int j = 0, repeat_banks; + while ((i % (256 >> j)) && j < 8) + j++; + repeat_banks = i % (256 >> (j - 1)); + for (int k = 0; k < repeat_banks; k++) + rom_bank_map[i + k] = rom_bank_map[i + k - repeat_banks]; + i += repeat_banks; + } + +// check bank map! +// for (i = 0; i < 256; i++) +// { +// printf("bank %3d = %3d\t", i, rom_bank_map[i]); +// if ((i%8) == 7) +// printf("\n"); +// } +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// base_sns_cart_slot_device - constructor +//------------------------------------------------- +base_sns_cart_slot_device::base_sns_cart_slot_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_image_interface(mconfig, *this), + device_slot_interface(mconfig, *this), + m_addon(ADDON_NONE), + m_type(SNES_MODE20) +{ +} + +sns_cart_slot_device::sns_cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + base_sns_cart_slot_device(mconfig, SNS_CART_SLOT, "SNES Cartridge Slot", tag, owner, clock, "sns_cart_slot", __FILE__) +{ +} + +sns_sufami_cart_slot_device::sns_sufami_cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + base_sns_cart_slot_device(mconfig, SNS_SUFAMI_CART_SLOT, "SNES Sufami Turbo Cartridge Slot", tag, owner, clock, "sns_sufami_cart_slot", __FILE__) +{ +} + +sns_bsx_cart_slot_device::sns_bsx_cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + base_sns_cart_slot_device(mconfig, SNS_BSX_CART_SLOT, "SNES BS-X Cartridge Slot", tag, owner, clock, "sns_bsx_cart_slot", __FILE__) +{ +} + +//------------------------------------------------- +// base_sns_cart_slot_device - destructor +//------------------------------------------------- + +base_sns_cart_slot_device::~base_sns_cart_slot_device() +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void base_sns_cart_slot_device::device_start() +{ + m_cart = dynamic_cast(get_card_device()); +} + +//------------------------------------------------- +// device_config_complete - perform any +// operations now that the configuration is +// complete +//------------------------------------------------- + +void base_sns_cart_slot_device::device_config_complete() +{ + // set brief and instance name + update_names(); +} + + +//------------------------------------------------- +// SNES PCB +//------------------------------------------------- + + +struct sns_slot +{ + int pcb_id; + const char *slot_option; +}; + +// Here, we take the feature attribute from .xml (i.e. the PCB name) and we assign a unique ID to it +static const sns_slot slot_list[] = +{ + { SNES_MODE20, "lorom"}, + { SNES_BSXLO, "lorom_bsx"}, + { SNES_CX4, "lorom_cx4"}, + { SNES_DSP, "lorom_dsp"}, + { SNES_DSP4, "lorom_dsp4"}, + { SNES_OBC1, "lorom_obc1"}, + { SNES_SA1, "lorom_sa1"}, + { SNES_SDD1, "lorom_sdd1"}, + { SNES_SFX, "lorom_sfx"}, + { SNES_Z80GB, "lorom_sgb"}, + { SNES_ST010, "lorom_st010"}, + { SNES_ST011, "lorom_st011"}, + { SNES_ST018, "lorom_st018"}, + { SNES_SUFAMITURBO, "lorom_sufami"}, + { SNES_MODE21, "hirom"}, + { SNES_DSP_MODE21, "hirom_dsp"}, + { SNES_BSXHI, "hirom_bsx"}, + { SNES_SPC7110, "hirom_spc7110"}, + { SNES_SPC7110_RTC, "hirom_spcrtc"}, + { SNES_SRTC, "hirom_srtc"}, + { SNES_BSX, "bsxrom"}, + // BS-X memory packs + { SNES_BSMEMPAK, "bsmempak"}, + // Sufami Turbo carts + { SNES_STROM, "strom"}, + // Event carts + { SNES_PFEST94, "pfest94" }, + // pirate carts + { SNES_POKEMON, "lorom_poke"}, + { SNES_TEKKEN2, "lorom_tekken2"}, + { SNES_SOULBLAD, "lorom_sbld"}, + { SNES_MCPIR1, "lorom_mcpir1"}, + { SNES_MCPIR2, "lorom_mcpir2"}, + { SNES_20COL, "lorom_20col"}, + { SNES_BANANA, "lorom_pija"}, // wip + { SNES_BUGS, "lorom_bugs"}, // wip + // legacy slots to support DSPx games from fullpath + { SNES_DSP1_LEG, "lorom_dsp1leg"}, + { SNES_DSP1B_LEG, "lorom_dsp1bleg"}, + { SNES_DSP2_LEG, "lorom_dsp2leg"}, + { SNES_DSP3_LEG, "lorom_dsp3leg"}, + { SNES_DSP4_LEG, "lorom_dsp4leg"}, + { SNES_DSP1_MODE21_LEG, "hirom_dsp1leg"}, + { SNES_ST010_LEG, "lorom_st10leg"}, + { SNES_ST011_LEG, "lorom_st11leg"} +}; + +static int sns_get_pcb_id(const char *slot) +{ + for (int i = 0; i < ARRAY_LENGTH(slot_list); i++) + { + if (!core_stricmp(slot_list[i].slot_option, slot)) + return slot_list[i].pcb_id; + } + + return 0; +} + +static const char *sns_get_slot(int type) +{ + for (int i = 0; i < ARRAY_LENGTH(slot_list); i++) + { + if (slot_list[i].pcb_id == type) + return slot_list[i].slot_option; + } + + return "lorom"; +} + + +/*------------------------------------------------- + SRAM handling + -------------------------------------------------*/ + +/************************************* + * Helper functions + *************************************/ + + +/* Here we add a couple of cart utilities, to avoid duplicating the code in each DEVICE_IMAGE_LOAD */ +UINT32 base_sns_cart_slot_device::snes_skip_header( UINT8 *ROM, UINT32 rom_size ) +{ + UINT8 header[512]; + UINT32 offset = 512; + + /* Check for a header (512 bytes) */ + memcpy(header, ROM, 512); + + if ((header[8] == 0xaa) && (header[9] == 0xbb) && (header[10] == 0x04)) + { + /* Found an SWC identifier */ + logerror("Found header (SWC) - Skipped\n"); + } + else if ((header[0] | (header[1] << 8)) == (((rom_size - 512) / 1024) / 8)) + { + /* Some headers have the rom size at the start, if this matches with the actual rom size, we probably have a header */ + logerror("Found header (size) - Skipped\n"); + } + else if ((rom_size % 0x8000) == 512) + { + /* As a last check we'll see if there's exactly 512 bytes extra to this image. */ + logerror("Found header (extra) - Skipped\n"); + } + else + { + /* No header found so go back to the start of the file */ + logerror("No header found.\n"); + offset = 0; + } + + return offset; +} + + +/* This function assign a 'score' to data immediately after 'offset' to measure how valid they are + as information block (to decide if the image is HiRom, LoRom, ExLoRom or ExHiRom) */ +/* Code from bsnes, courtesy of byuu - http://byuu.org/ , based on previous code by Cowering */ +static int snes_validate_infoblock( UINT8 *infoblock, UINT32 offset ) +{ + int score = 0; + UINT16 reset_vector = infoblock[offset + 0x3c] | (infoblock[offset + 0x3d] << 8); + UINT16 checksum = infoblock[offset + 0x1e] | (infoblock[offset + 0x1f] << 8); + UINT16 ichecksum = infoblock[offset + 0x1c] | (infoblock[offset + 0x1d] << 8); + UINT8 reset_opcode = infoblock[(offset & ~0x7fff) | (reset_vector & 0x7fff)]; //first opcode executed upon reset + UINT8 mapper = infoblock[offset + 0x15] & ~0x10; //mask off irrelevant FastROM-capable bit + + /* $00:[000-7fff] contains uninitialized RAM and MMIO. + reset vector must point to ROM at $00:[8000-ffff] to be considered valid. */ + if (reset_vector < 0x8000) + return 0; + + /* some images duplicate the header in multiple locations, and others have completely + invalid header information that cannot be relied upon. The code below will analyze + the first opcode executed at the specified reset vector to determine the probability + that this is the correct header. Score is assigned accordingly. */ + + /* most likely opcodes */ + if (reset_opcode == 0x78 //sei + || reset_opcode == 0x18 //clc (clc; xce) + || reset_opcode == 0x38 //sec (sec; xce) + || reset_opcode == 0x9c //stz $nnnn (stz $4200) + || reset_opcode == 0x4c //jmp $nnnn + || reset_opcode == 0x5c //jml $nnnnnn + ) + score += 8; + + /* plausible opcodes */ + if (reset_opcode == 0xc2 //rep #$nn + || reset_opcode == 0xe2 //sep #$nn + || reset_opcode == 0xad //lda $nnnn + || reset_opcode == 0xae //ldx $nnnn + || reset_opcode == 0xac //ldy $nnnn + || reset_opcode == 0xaf //lda $nnnnnn + || reset_opcode == 0xa9 //lda #$nn + || reset_opcode == 0xa2 //ldx #$nn + || reset_opcode == 0xa0 //ldy #$nn + || reset_opcode == 0x20 //jsr $nnnn + || reset_opcode == 0x22 //jsl $nnnnnn + ) + score += 4; + + /* implausible opcodes */ + if (reset_opcode == 0x40 //rti + || reset_opcode == 0x60 //rts + || reset_opcode == 0x6b //rtl + || reset_opcode == 0xcd //cmp $nnnn + || reset_opcode == 0xec //cpx $nnnn + || reset_opcode == 0xcc //cpy $nnnn + ) + score -= 4; + + /* least likely opcodes */ + if (reset_opcode == 0x00 //brk #$nn + || reset_opcode == 0x02 //cop #$nn + || reset_opcode == 0xdb //stp + || reset_opcode == 0x42 //wdm + || reset_opcode == 0xff //sbc $nnnnnn,x + ) + score -= 8; + + /* Sometimes, both the header and reset vector's first opcode will match ... + fallback and rely on info validity in these cases to determine more likely header. */ + + /* a valid checksum is the biggest indicator of a valid header. */ + if ((checksum + ichecksum) == 0xffff && (checksum != 0) && (ichecksum != 0)) + score += 4; + + /* then there are the expected mapper values */ + if (offset == 0x007fc0 && mapper == 0x20) // 0x20 is usually LoROM + score += 2; + + if (offset == 0x00ffc0 && mapper == 0x21) // 0x21 is usually HiROM + score += 2; + + if (offset == 0x007fc0 && mapper == 0x22) // 0x22 is usually ExLoROM + score += 2; + + if (offset == 0x40ffc0 && mapper == 0x25) // 0x25 is usually ExHiROM + score += 2; + + /* finally, there are valid values in the Company, Region etc. fields */ + if (infoblock[offset + 0x1a] == 0x33) // Company field: 0x33 indicates extended header + score += 2; + + if (infoblock[offset + 0x16] < 0x08) // ROM Type field + score++; + + if (infoblock[offset + 0x17] < 0x10) // ROM Size field + score++; + + if (infoblock[offset + 0x18] < 0x08) // SRAM Size field + score++; + + if (infoblock[offset + 0x19] < 14) // Region field + score++; + + /* do we still have a positive score? */ + if (score < 0) + score = 0; + + return score; +} + +/* This determines if a cart is in Mode 20, 21, 22 or 25; sets state->m_cart[0].mode and + state->m_cart[0].sram accordingly; and returns the offset of the internal header (needed to + detect BSX and ST carts) */ +static UINT32 snes_find_hilo_mode( UINT8 *buffer, UINT32 buf_len ) +{ + UINT8 valid_mode20 = 0; + UINT8 valid_mode21 = 0; + UINT8 valid_mode25 = 0; + UINT32 retvalue; + + /* Now to determine if this is a lo-ROM, a hi-ROM or an extended lo/hi-ROM */ + if (buf_len > 0x007fc0) + valid_mode20 = snes_validate_infoblock(buffer, 0x007fc0); + if (buf_len > 0x00ffc0) + valid_mode21 = snes_validate_infoblock(buffer, 0x00ffc0); + if (buf_len > 0x40ffc0) + valid_mode25 = snes_validate_infoblock(buffer, 0x40ffc0); + + /* Images larger than 32mbits are likely ExHiRom */ + if (valid_mode25) + valid_mode25 += 4; + + if ((valid_mode20 >= valid_mode21) && (valid_mode20 >= valid_mode25)) + retvalue = 0x007fc0; + else if (valid_mode21 >= valid_mode25) + retvalue = 0x00ffc0; + else + retvalue = 0x40ffc0; + + logerror( "\t HiROM/LoROM id: %s (LoROM: %d , HiROM: %d, ExHiROM: %d)\n", + (retvalue == 0x007fc0) ? "LoROM" : + (retvalue == 0x00ffc0) ? "HiROM" : + (retvalue == 0x40ffc0) ? "ExHiROM" : "Other", + valid_mode20, valid_mode21, valid_mode25); + + return retvalue; +} + + +static int snes_find_addon_chip( UINT8 *buffer, UINT32 start_offs ) +{ + /* Info mostly taken from http://snesemu.black-ship.net/misc/hardware/-from%20nsrt.edgeemu.com-chipinfo.htm */ + switch (buffer[start_offs + 0x16]) + { + case 0x00: + case 0x01: + case 0x02: + break; + + case 0x03: + if (buffer[start_offs + 0x15] == 0x30) + return ADDON_DSP4; + else + return ADDON_DSP1; + + case 0x04: + return ADDON_DSP1; + + case 0x05: + // DSP2 can be detected by (buffer[start_offs + 0x15] == 0x20) + // DSP3 is harder to detect, and one has to rely on the manufacturer (Bandai) + // by checking (buffer[start_offs + 0x15] == 0x30) && (buffer[start_offs + 0x1a] == 0xb2) + // in other cases is DSP1, but we do treat all these together... + if (buffer[start_offs + 0x15] == 0x20) + return ADDON_DSP2; + else if ((buffer[start_offs + 0x15] == 0x30) && (buffer[start_offs + 0x1a] == 0xb2)) + return ADDON_DSP3; + else + return ADDON_DSP1; + + case 0x13: // Mario Chip 1 + case 0x14: // GSU-x + case 0x15: // GSU-x + case 0x1a: // GSU-1 (21 MHz at start) + if (buffer[start_offs + 0x15] == 0x20) + return ADDON_SFX; + break; + + case 0x25: + return ADDON_OBC1; + + case 0x32: // needed by a Sample game (according to ZSNES) + case 0x34: + case 0x35: + if (buffer[start_offs + 0x15] == 0x23) + return ADDON_SA1; + break; + + case 0x43: + case 0x45: + if (buffer[start_offs + 0x15] == 0x32) + return ADDON_SDD1; + break; + + case 0x55: + if (buffer[start_offs + 0x15] == 0x35) + return ADDON_SRTC; + break; + + case 0xe3: + return ADDON_Z80GB; + + case 0xf3: + return ADDON_CX4; + + case 0xf5: + if (buffer[start_offs + 0x15] == 0x30) + return ADDON_ST018; + else if (buffer[start_offs + 0x15] == 0x3a) + return ADDON_SPC7110; + break; + + case 0xf6: + /* These Seta ST-01X chips have both 0x30 at 0xffd5, + they only differ for the 'size' at 0xffd7 */ + if (buffer[start_offs + 0x17] < 0x0a) + return ADDON_ST011; + else + return ADDON_ST010; + + case 0xf9: + if (buffer[start_offs + 0x15] == 0x3a) + return ADDON_SPC7110_RTC; + break; + + default: + break; + } + return -1; +} + + +/*------------------------------------------------- + call load + -------------------------------------------------*/ + + +bool base_sns_cart_slot_device::call_load() +{ + if (m_cart) + { + UINT8 *ROM; + UINT32 len, offset = 0; + const char *slot_name; + + /* Check for a header (512 bytes), and skip it if found */ + if (software_entry() == NULL) + { + UINT32 tmplen = length(); + dynamic_buffer tmpROM(tmplen); + fread(&tmpROM[0], tmplen); + offset = snes_skip_header(&tmpROM[0], tmplen); + fseek(offset, SEEK_SET); + } + + len = (software_entry() == NULL) ? (length() - offset) : get_software_region_length("rom"); + + m_cart->rom_alloc(len, tag()); + ROM = m_cart->get_rom_base(); + if (software_entry() == NULL) + fread(ROM, len); + else + memcpy(ROM, get_software_region("rom"), len); + + m_cart->rom_map_setup(len); + + // check for on-cart CPU bios + if (software_entry() != NULL) + { + if (get_software_region("addon")) + { + m_cart->addon_bios_alloc(get_software_region_length("addon")); + memcpy(m_cart->get_addon_bios_base(), get_software_region("addon"), get_software_region_length("addon")); + } + } + + // get pcb type + if (software_entry() == NULL) + get_cart_type_addon(ROM, len, m_type, m_addon); + else + { + if ((slot_name = get_feature("slot")) == NULL) + m_type = SNES_MODE20; + else + m_type = sns_get_pcb_id(slot_name); + + if (m_type == SNES_DSP && len > 0x100000) + m_type = SNES_DSP_2MB; + } + + if (software_entry() == NULL) + setup_addon_from_fullpath(); + + // in carts with an add-on CPU having internal dump, this speeds up access to the internal rom + // by installing read_bank in address space and mapping m_bios there + m_cart->speedup_addon_bios_access(); + + setup_nvram(); + + if (m_cart->get_nvram_size() || m_cart->get_rtc_ram_size()) + { + UINT32 tot_size = m_cart->get_nvram_size() + m_cart->get_rtc_ram_size(); + dynamic_buffer temp_nvram(tot_size); + battery_load(&temp_nvram[0], tot_size, 0xff); + if (m_cart->get_nvram_size()) + memcpy(m_cart->get_nvram_base(), &temp_nvram[0], m_cart->get_nvram_size()); + if (m_cart->get_rtc_ram_size()) + memcpy(m_cart->get_rtc_ram_base(), &temp_nvram[m_cart->get_nvram_size()], m_cart->get_rtc_ram_size()); + } + + //printf("Type %d\n", m_type); + + internal_header_logging(ROM, len); + + return IMAGE_INIT_PASS; + } + + return IMAGE_INIT_PASS; +} + + +/*------------------------------------------------- + call_unload + -------------------------------------------------*/ + +void base_sns_cart_slot_device::call_unload() +{ + if (m_cart) + { + if (m_cart->get_nvram_size() || m_cart->get_rtc_ram_size()) + { + UINT32 tot_size = m_cart->get_nvram_size() + m_cart->get_rtc_ram_size(); + dynamic_buffer temp_nvram(tot_size); + if (m_cart->get_nvram_size()) + memcpy(&temp_nvram[0], m_cart->get_nvram_base(), m_cart->get_nvram_size()); + if (m_cart->get_rtc_ram_size()) + memcpy(&temp_nvram[m_cart->get_nvram_size()], m_cart->get_rtc_ram_base(), m_cart->get_rtc_ram_size()); + + battery_save(&temp_nvram[0], tot_size); + } + } +} + + +void base_sns_cart_slot_device::setup_addon_from_fullpath() +{ + // if we already have an add-on bios or if no addon has been detected, we have nothing to do + if (m_cart->get_addon_bios_size() || m_addon == ADDON_NONE) + return; + + // check if the add-on dump is appended to the file + // if this is the case, copy it in m_bios and refresh + // the rom_bank_map with correct game rom size + switch (m_addon) + { + case ADDON_DSP1: + case ADDON_DSP1B: + case ADDON_DSP2: + case ADDON_DSP3: + case ADDON_DSP4: + // check for add-on dump + if ((m_cart->get_rom_size() & 0x7fff) == 0x2800) + { + logerror("Found NEC DSP dump at the bottom of the ROM.\n"); + m_cart->addon_bios_alloc(0x2800); + memcpy(m_cart->get_addon_bios_base(), m_cart->get_rom_base() + (m_cart->get_rom_size() - 0x2800), 0x2800); + m_cart->rom_map_setup(m_cart->get_rom_size() - 0x2800); + } + // check for byuu's compressed version (swapped order of bytes and stripped fixed 0x00 bytes) + if ((m_cart->get_rom_size() & 0x7fff) == 0x2000) + { + logerror("Found NEC DSP dump (byuu's version) at the bottom of the ROM.\n"); + m_cart->addon_bios_alloc(0x2800); + for (int i = 0; i < 0x800; i++) + { + memcpy(m_cart->get_addon_bios_base() + i * 4 + 2, m_cart->get_rom_base() + (m_cart->get_rom_size() - 0x2000) + i * 3 + 0, 1); + memcpy(m_cart->get_addon_bios_base() + i * 4 + 1, m_cart->get_rom_base() + (m_cart->get_rom_size() - 0x2000) + i * 3 + 1, 1); + memcpy(m_cart->get_addon_bios_base() + i * 4 + 0, m_cart->get_rom_base() + (m_cart->get_rom_size() - 0x2000) + i * 3 + 2, 1); + memset(m_cart->get_addon_bios_base() + i * 4 + 3, 0xff, 1); + } + memcpy(m_cart->get_addon_bios_base() + 0x2000, m_cart->get_rom_base() + (m_cart->get_rom_size() - 0x1800), 0x800); + m_cart->rom_map_setup(m_cart->get_rom_size() - 0x2000); + } + break; + case ADDON_ST010: + case ADDON_ST011: + // check for add-on dump + if ((m_cart->get_rom_size() & 0x3ffff) == 0x11000) + { + logerror("Found Seta DSP dump at the bottom of the ROM.\n"); + m_cart->addon_bios_alloc(0x11000); + memcpy(m_cart->get_addon_bios_base(), m_cart->get_rom_base() + (m_cart->get_rom_size() - 0x11000), 0x11000); + m_cart->rom_map_setup(m_cart->get_rom_size() - 0x11000); + } + // check for byuu's compressed version (swapped order of bytes and stripped fixed 0x00 bytes) + if ((m_cart->get_rom_size() & 0xffff) == 0xd000) + { + logerror("Found Seta DSP dump (byuu's version) at the bottom of the ROM.\n"); + m_cart->addon_bios_alloc(0x11000); + for (int i = 0; i < 0x4000; i++) + { + memcpy(m_cart->get_addon_bios_base() + i * 4 + 2, m_cart->get_rom_base() + (m_cart->get_rom_size() - 0xd000) + i * 3 + 0, 1); + memcpy(m_cart->get_addon_bios_base() + i * 4 + 1, m_cart->get_rom_base() + (m_cart->get_rom_size() - 0xd000) + i * 3 + 1, 1); + memcpy(m_cart->get_addon_bios_base() + i * 4 + 0, m_cart->get_rom_base() + (m_cart->get_rom_size() - 0xd000) + i * 3 + 2, 1); + memset(m_cart->get_addon_bios_base() + i * 4 + 3, 0xff, 1); + } + memcpy(m_cart->get_addon_bios_base() + 0x10000, m_cart->get_rom_base() + (m_cart->get_rom_size() - 0xc000), 0x1000); + m_cart->rom_map_setup(m_cart->get_rom_size() - 0xd000); + } + break; + case ADDON_CX4: + if ((m_cart->get_rom_size() & 0x7fff) == 0x0c00) + { + logerror("Found CX4 dump at the bottom of the ROM.\n"); + m_cart->addon_bios_alloc(0x0c00); + memcpy(m_cart->get_addon_bios_base(), m_cart->get_rom_base() + (m_cart->get_rom_size() - 0x0c00), 0x0c00); + m_cart->rom_map_setup(m_cart->get_rom_size() - 0x0c00); + } + break; + case ADDON_ST018: + if ((m_cart->get_rom_size() & 0x3ffff) == 0x28000) + { + logerror("Found ST018 dump at the bottom of the ROM.\n"); + m_cart->addon_bios_alloc(0x28000); + memcpy(m_cart->get_addon_bios_base(), m_cart->get_rom_base() + (m_cart->get_rom_size() - 0x28000), 0x28000); + m_cart->rom_map_setup(m_cart->get_rom_size() - 0x28000); + } + break; + } + + // otherwise, we need to use the legacy versions including DSP dump in device romset + if (!m_cart->get_addon_bios_size()) + { + std::string region = std::string(m_cart->device().tag()).append(":addon"); + UINT8 *ROM = NULL; + + switch (m_addon) + { + case ADDON_DSP1: + ROM = machine().root_device().memregion(region.c_str())->base(); + m_cart->addon_bios_alloc(0x2800); + memcpy(m_cart->get_addon_bios_base(), ROM, 0x2800); + break; + case ADDON_DSP1B: + ROM = machine().root_device().memregion(region.c_str())->base(); + m_cart->addon_bios_alloc(0x2800); + memcpy(m_cart->get_addon_bios_base(), ROM, 0x2800); + break; + case ADDON_DSP2: + ROM = machine().root_device().memregion(region.c_str())->base(); + m_cart->addon_bios_alloc(0x2800); + memcpy(m_cart->get_addon_bios_base(), ROM, 0x2800); + break; + case ADDON_DSP3: + ROM = machine().root_device().memregion(region.c_str())->base(); + m_cart->addon_bios_alloc(0x2800); + memcpy(m_cart->get_addon_bios_base(), ROM, 0x2800); + break; + case ADDON_DSP4: + ROM = machine().root_device().memregion(region.c_str())->base(); + m_cart->addon_bios_alloc(0x2800); + memcpy(m_cart->get_addon_bios_base(), ROM, 0x2800); + break; + case ADDON_ST010: + ROM = machine().root_device().memregion(region.c_str())->base(); + m_cart->addon_bios_alloc(0x11000); + memcpy(m_cart->get_addon_bios_base(), ROM, 0x11000); + break; + case ADDON_ST011: + ROM = machine().root_device().memregion(region.c_str())->base(); + m_cart->addon_bios_alloc(0x11000); + memcpy(m_cart->get_addon_bios_base(), ROM, 0x11000); + break; + } + } + +} + +void base_sns_cart_slot_device::setup_nvram() +{ + UINT8 *ROM = (UINT8 *)m_cart->get_rom_base(); + UINT32 size = 0; + if (software_entry() == NULL) + { + int hilo_mode = snes_find_hilo_mode(ROM, m_cart->get_rom_size()); + UINT8 sram_size = (m_type == SNES_SFX) ? (ROM[0x00ffbd] & 0x07) : (ROM[hilo_mode + 0x18] & 0x07); + if (sram_size) + { + UINT32 max = (hilo_mode == 0x007fc0) ? 0x80000 : 0x20000; // MODE20 vs MODE21 + size = 1024 << sram_size; + if (size > max) + size = max; + } + } + else + { + if (get_software_region("nvram")) + size = get_software_region_length("nvram"); + } + + if (size) + m_cart->nvram_alloc(size); + + if (m_type == SNES_STROM) + m_cart->nvram_alloc(0x20000); + if (m_type == SNES_BSX) + m_cart->nvram_alloc(0x8000); + + // setup also RTC SRAM, when needed (to be removed when RTCs are converted to devices) + if (m_type == SNES_SRTC) + m_cart->rtc_ram_alloc(13); + if (m_type == SNES_SPC7110_RTC) + m_cart->rtc_ram_alloc(16); +} + + + +/*------------------------------------------------- + call softlist load + -------------------------------------------------*/ + +bool base_sns_cart_slot_device::call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry) +{ + load_software_part_region(*this, swlist, swname, start_entry ); + return TRUE; +} + +void base_sns_cart_slot_device::get_cart_type_addon(UINT8 *ROM, UINT32 len, int &type, int &addon) +{ + // First, look if the cart is HiROM or LoROM (and set snes_cart accordingly) + int hilo_mode = snes_find_hilo_mode(ROM, len); + + switch (hilo_mode) + { + case 0x007fc0: // LoRom & ExLoRom + type = SNES_MODE20; + break; + case 0x00ffc0: // HiRom + case 0x40ffc0: // ExHiRom + type = SNES_MODE21; + break; + default: + break; + } + + // detect Sufami Turbo... + if (type == SNES_MODE20 && !memcmp(ROM, "BANDAI SFC-ADX", 14)) + { + if (!memcmp(ROM + 16, "SFC-ADX BACKUP", 14)) + type = SNES_SUFAMITURBO; + else + type = SNES_STROM; + } + + // detect BS-X Base Cart + if (!memcmp(ROM + hilo_mode, "Satellaview BS-X ", 21)) + type = SNES_BSX; + // Detect BS-X Flash Cart + if ((ROM[hilo_mode + 0x13] == 0x00 || ROM[hilo_mode + 0x13] == 0xff) && ROM[hilo_mode + 0x14] == 0x00) + { + UINT8 n15 = ROM[hilo_mode + 0x15]; + if (n15 == 0x00 || n15 == 0x80 || n15 == 0x84 || n15 == 0x9c || n15 == 0xbc || n15 == 0xfc) + { + if (ROM[hilo_mode + 0x1a] == 0x33 || ROM[hilo_mode + 0x1a] == 0xff) + type = SNES_BSMEMPAK; + } + } + + // check for add-on chips... + if (len >= hilo_mode + 0x1a) + { + addon = snes_find_addon_chip(ROM, hilo_mode); + if (addon != -1) + { + // m_type handles DSP1,2,3 in the same way, but snes_add requires them to be separate... + switch (addon) + { + case ADDON_CX4: + type = SNES_CX4; + break; + case ADDON_DSP1: + case ADDON_DSP1B: + case ADDON_DSP2: + case ADDON_DSP3: + if (type == SNES_MODE20 && len > 0x100000) + type = SNES_DSP_2MB; + else if (type == SNES_MODE21) + type = SNES_DSP_MODE21; + else + type = SNES_DSP; + break; + case ADDON_DSP4: + type = SNES_DSP4; + break; + case ADDON_OBC1: + type = SNES_OBC1; + break; + case ADDON_SA1: + type = SNES_SA1; + break; + case ADDON_SDD1: + type = SNES_SDD1; + break; + case ADDON_SFX: + type = SNES_SFX; + break; + case ADDON_SPC7110: + type = SNES_SPC7110; + break; + case ADDON_SPC7110_RTC: + type = SNES_SPC7110_RTC; + break; + case ADDON_ST010: + type = SNES_ST010; + break; + case ADDON_ST011: + type = SNES_ST011; + break; + case ADDON_ST018: + type = SNES_ST018; + break; + case ADDON_SRTC: + type = SNES_SRTC; + break; + case ADDON_Z80GB: + type = SNES_Z80GB; + break; + } + } + } +} + +/*------------------------------------------------- + get default card software + -------------------------------------------------*/ + +void base_sns_cart_slot_device::get_default_card_software(std::string &result) +{ + bool fullpath = open_image_file(mconfig().options()); + + if (fullpath) + { + const char *slot_string = "lorom"; + UINT32 offset = 0; + UINT32 len = core_fsize(m_file); + dynamic_buffer rom(len); + int type = 0, addon = 0; + + core_fread(m_file, &rom[0], len); + + offset = snes_skip_header(&rom[0], len); + + get_cart_type_addon(&rom[offset], len - offset, type, addon); + // here we're from fullpath, so check if it's a DSP game which needs legacy device (i.e. it has no appended DSP dump) + switch (addon) + { + case ADDON_DSP1: + if ((len & 0x7fff) != 0x2800 && (len & 0x7fff) != 0x2000) + { + if (type == SNES_DSP_MODE21) + type = SNES_DSP1_MODE21_LEG; + else + type = SNES_DSP1_LEG; + } + break; + case ADDON_DSP1B: + if ((len & 0x7fff) != 0x2800 && (len & 0x7fff) != 0x2000) + type = SNES_DSP1B_LEG; + break; + case ADDON_DSP2: + if ((len & 0x7fff) != 0x2800 && (len & 0x7fff) != 0x2000) + type = SNES_DSP2_LEG; + break; + case ADDON_DSP3: + if ((len & 0x7fff) != 0x2800 && (len & 0x7fff) != 0x2000) + type = SNES_DSP3_LEG; + break; + case ADDON_DSP4: + if ((len & 0x7fff) != 0x2800 && (len & 0x7fff) != 0x2000) + type = SNES_DSP4_LEG; + break; + case ADDON_ST010: + if ((len & 0x3ffff) != 0x11000 && (len & 0xffff) != 0xd000) + type = SNES_ST010_LEG; + break; + case ADDON_ST011: + if ((len & 0x3ffff) != 0x11000 && (len & 0xffff) != 0xd000) + type = SNES_ST011_LEG; + break; + } + + slot_string = sns_get_slot(type); + + clear(); + + result.assign(slot_string); + return; + } + + software_get_default_slot(result, "lorom"); +} + + +/*------------------------------------------------- + read + -------------------------------------------------*/ + +READ8_MEMBER(base_sns_cart_slot_device::read_l) +{ + if (m_cart) + return m_cart->read_l(space, offset); + else + return 0xff; +} + +READ8_MEMBER(base_sns_cart_slot_device::read_h) +{ + if (m_cart) + return m_cart->read_h(space, offset); + else + return 0xff; +} + +READ8_MEMBER(base_sns_cart_slot_device::read_ram) +{ + if (m_cart) + return m_cart->read_ram(space, offset); + else + return 0xff; +} + +READ8_MEMBER(base_sns_cart_slot_device::chip_read) +{ + if (m_cart) + return m_cart->chip_read(space, offset); + else + return 0xff; +} + +/*------------------------------------------------- + write + -------------------------------------------------*/ + +WRITE8_MEMBER(base_sns_cart_slot_device::write_l) +{ + if (m_cart) + m_cart->write_l(space, offset, data); +} + +WRITE8_MEMBER(base_sns_cart_slot_device::write_h) +{ + if (m_cart) + m_cart->write_h(space, offset, data); +} + +WRITE8_MEMBER(base_sns_cart_slot_device::write_ram) +{ + if (m_cart) + m_cart->write_ram(space, offset, data); +} + +WRITE8_MEMBER(base_sns_cart_slot_device::chip_write) +{ + if (m_cart) + m_cart->chip_write(space, offset, data); +} + + +/*------------------------------------------------- + Internal header logging + -------------------------------------------------*/ + +/* We use this to convert the company_id in the header to int value to be passed in companies[] */ +static int char_to_int_conv( char id ) +{ + int value; + + if (id == '1') value = 0x01; + else if (id == '2') value = 0x02; + else if (id == '3') value = 0x03; + else if (id == '4') value = 0x04; + else if (id == '5') value = 0x05; + else if (id == '6') value = 0x06; + else if (id == '7') value = 0x07; + else if (id == '8') value = 0x08; + else if (id == '9') value = 0x09; + else if (id == 'A') value = 0x0a; + else if (id == 'B') value = 0x0b; + else if (id == 'C') value = 0x0c; + else if (id == 'D') value = 0x0d; + else if (id == 'E') value = 0x0e; + else if (id == 'F') value = 0x0f; + else value = 0x00; + + return value; +} + +#define UNK "UNKNOWN" + +void base_sns_cart_slot_device::internal_header_logging(UINT8 *ROM, UINT32 len) +{ + static const char *const cart_types[] = + { + "ROM (LoROM)", + "ROM (HiROM)", + "ROM (ExLoROM)", + "ROM (ExHiROM)", + "ROM, CX4", + "ROM, DSP-1,2,3 (LoROM)", + "ROM, DSP-1 (LoROM 2MB)", + "ROM, DSP-1 (HiROM)", + "ROM, DSP-4", + "ROM, OBC-1", + "ROM, SA-1", + "ROM, S-DD1", + "ROM, Super FX / FX2", + "ROM, SPC7110", + "ROM, SPC7110, RTC", + "ROM, S-RTC", + "ROM, Seta ST-010", + "ROM, Seta ST-011", + "ROM, Seta ST-018", + "ROM, Z80GB (Super Game Boy)", + "ROM, BS-X Base cart", + "ROM, BS-X compatible (LoROM)", + "ROM, BS-X compatible (HiROM)", + "BS-X memory pack", + "ROM, Sufami Turbo", + "Sufami Turbo cart", + // pirate cart types which are not recognized from fullpath + UNK, + UNK, + UNK + }; + + /* Some known countries */ + static const char *const countries[] = + { + /* 0*/ "Japan (NTSC)", "USA & Canada (NTSC)", "Europe, Oceania & Asia (PAL)", "Sweden (PAL)", + /* 4*/ "Finland (PAL)", "Denmark (PAL)", "France (PAL)", "Holland (PAL)", + /* 8*/ "Spain (PAL)", "Germany, Austria & Switzerland (PAL)", "Italy (PAL)", "Hong Kong & China (PAL)", + /* c*/ "Indonesia (PAL)", "South Korea (NTSC)", UNK, UNK, + }; + + /* Some known companies (integrations to the list from Snes9x) */ + static const char *const companies[] = + { + /* 0*/ "Invalid", "Nintendo", "Ajinomoto", "Imagineer-Zoom", "Chris Gray Enterprises Inc.", "Zamuse", "Falcom", UNK, + /* 8*/ "Capcom", "HOT-B", "Jaleco", "Coconuts", "Rage Software", "Micronet", "Technos", "Mebio Software", + /*10*/ "SHOUEi System", "Starfish", "Gremlin Graphics", "Electronic Arts", "NCS / Masaya", "COBRA Team", "Human/Field", "KOEI", + /*18*/ "Hudson Soft", "Game Village", "Yanoman", UNK, "Tecmo", UNK, "Open System", "Virgin Games", + /*20*/ "KSS", "Sunsoft", "POW", "Micro World", UNK, UNK, "Enix", "Loriciel/Electro Brain", + /*28*/ "Kemco", "Seta Co.,Ltd.", "Culture Brain", "Irem Japan", "Pal Soft", "Visit Co.,Ltd.", "INTEC Inc.", "System Sacom Corp.", + /*30*/ "Viacom New Media", "Carrozzeria", "Dynamic", "Nintendo", "Magifact", "Hect", UNK, UNK, + /*38*/ "Capcom Europe", "Accolade Europe", UNK, "Arcade Zone", "Empire Software", "Loriciel", "Gremlin Graphics", UNK, + /*40*/ "Seika Corp.", "UBI Soft", UNK, UNK, "LifeFitness Exertainment", UNK, "System 3", "Spectrum Holobyte", + /*48*/ UNK, "Irem", UNK, "Raya Systems/Sculptured Software", "Renovation Products", "Malibu Games/Black Pearl", UNK, "U.S. Gold", + /*50*/ "Absolute Entertainment", "Acclaim", "Activision", "American Sammy", "GameTek", "Hi Tech Expressions", "LJN Toys", UNK, + /*58*/ UNK, UNK, "Mindscape", "Romstar, Inc.", UNK, "Tradewest", UNK, "American Softworks Corp.", + /*60*/ "Titus", "Virgin Interactive Entertainment", "Maxis", "Origin/FCI/Pony Canyon", UNK, UNK, UNK, "Ocean", + /*68*/ UNK, "Electronic Arts", UNK, "Laser Beam", UNK, UNK, "Elite", "Electro Brain", + /*70*/ "Infogrames", "Interplay", "LucasArts", "Parker Brothers", "Konami", "STORM", UNK, UNK, + /*78*/ "THQ Software", "Accolade Inc.", "Triffix Entertainment", UNK, "Microprose", UNK, UNK, "Kemco", + /*80*/ "Misawa", "Teichio", "Namco Ltd.", "Lozc", "Koei", UNK, "Tokuma Shoten Intermedia", "Tsukuda Original", + /*88*/ "DATAM-Polystar", UNK, UNK, "Bullet-Proof Software", "Vic Tokai", UNK, "Character Soft", "I\'\'Max", + /*90*/ "Takara", "CHUN Soft", "Video System Co., Ltd.", "BEC", UNK, "Varie", "Yonezawa / S'Pal Corp.", "Kaneco", + /*98*/ UNK, "Pack in Video", "Nichibutsu", "TECMO", "Imagineer Co.", UNK, UNK, UNK, + /*a0*/ "Telenet", "Hori", UNK, UNK, "Konami", "K.Amusement Leasing Co.", UNK, "Takara", + /*a8*/ UNK, "Technos Jap.", "JVC", UNK, "Toei Animation", "Toho", UNK, "Namco Ltd.", + /*b0*/ "Media Rings Corp.", "ASCII Co. Activison", "Bandai", UNK, "Enix America", UNK, "Halken", UNK, + /*b8*/ UNK, UNK, "Culture Brain", "Sunsoft", "Toshiba EMI", "Sony Imagesoft", UNK, "Sammy", + /*c0*/ "Taito", UNK, "Kemco", "Square", "Tokuma Soft", "Data East", "Tonkin House", UNK, + /*c8*/ "KOEI", UNK, "Konami USA", "NTVIC", UNK, "Meldac", "Pony Canyon", "Sotsu Agency/Sunrise", + /*d0*/ "Disco/Taito", "Sofel", "Quest Corp.", "Sigma", "Ask Kodansha Co., Ltd.", UNK, "Naxat", UNK, + /*d8*/ "Capcom Co., Ltd.", "Banpresto", "Tomy", "Acclaim", UNK, "NCS", "Human Entertainment", "Altron", + /*e0*/ "Jaleco", UNK, "Yutaka", UNK, "T&ESoft", "EPOCH Co.,Ltd.", UNK, "Athena", + /*e8*/ "Asmik", "Natsume", "King Records", "Atlus", "Sony Music Entertainment", UNK, "IGS", UNK, + /*f0*/ UNK, "Motown Software", "Left Field Entertainment", "Beam Software", "Tec Magik", UNK, UNK, UNK, + /*f8*/ UNK, "Cybersoft", UNK, "Psygnosis", UNK, UNK, "Davidson", UNK, + }; + + int hilo_mode = snes_find_hilo_mode(ROM, len); + char title[21], rom_id[4], company_id[2]; + int type = 0, company, addon, has_ram = 0, has_sram = 0; + switch (hilo_mode) + { + case 0x007fc0: + if ((ROM[0x007fd5] == 0x32) || (len > 0x401000)) + type = SNES_MODE22; // ExLoRom + else + type = SNES_MODE20; // LoRom + type = SNES_MODE20; // LoRom & ExLoRom + break; + case 0x00ffc0: + type = SNES_MODE21; // HiRom + break; + case 0x40ffc0: + type = SNES_MODE25; // ExHiRom + break; + default: + break; + } + + // detect Sufami Turbo... + if (type == SNES_MODE20 && !memcmp(ROM, "BANDAI SFC-ADX", 14)) + { + if (!memcmp(ROM + 16, "SFC-ADX BACKUP", 14)) + type = SNES_SUFAMITURBO; + else + type = SNES_STROM; + } + + // detect BS-X Base Cart + if (!memcmp(ROM + hilo_mode, "Satellaview BS-X ", 21)) + type = SNES_BSX; + // Detect BS-X Flash Cart + if ((ROM[hilo_mode + 0x13] == 0x00 || ROM[hilo_mode + 0x13] == 0xff) && ROM[hilo_mode + 0x14] == 0x00) + { + UINT8 n15 = ROM[hilo_mode + 0x15]; + if (n15 == 0x00 || n15 == 0x80 || n15 == 0x84 || n15 == 0x9c || n15 == 0xbc || n15 == 0xfc) + { + if (ROM[hilo_mode + 0x1a] == 0x33 || ROM[hilo_mode + 0x1a] == 0xff) + type = SNES_BSMEMPAK; + } + } + + addon = snes_find_addon_chip(ROM, hilo_mode); + if (addon != -1) + { + if (type == SNES_MODE20 && addon == SNES_DSP) + { + if (len > 0x100000) + type = SNES_DSP_2MB; + else + type = SNES_DSP; + } + else if (type == SNES_MODE21 && addon == SNES_DSP) + type = SNES_DSP_MODE21; + else + type = addon; + } + + /* Company */ + for (int i = 0; i < 2; i++) + company_id[i] = ROM[hilo_mode - 0x10 + i]; + company = (char_to_int_conv(company_id[0]) << 4) + char_to_int_conv(company_id[1]); + if (company == 0) + company = ROM[hilo_mode + 0x1a]; + + /* ROM ID */ + for(int i = 0; i < 4; i++ ) + rom_id[i] = ROM[hilo_mode - 0x0e + i]; + + /* Title */ + for(int i = 0; i < 21; i++ ) + title[i] = ROM[hilo_mode + i]; + + /* RAM */ + if (((ROM[hilo_mode + 0x16] & 0xf) == 1) || + ((ROM[hilo_mode + 0x16] & 0xf) == 2) || + ((ROM[hilo_mode + 0x16] & 0xf) == 4) || + ((ROM[hilo_mode + 0x16] & 0xf) == 5)) + has_ram = 1; + + /* SRAM */ + if (((ROM[hilo_mode + 0x16] & 0xf) == 2) || + ((ROM[hilo_mode + 0x16] & 0xf) == 5) || + ((ROM[hilo_mode + 0x16] & 0xf) == 6)) + has_sram = 1; + + logerror( "ROM DETAILS\n" ); + logerror( "===========\n\n" ); + logerror( "\tTotal blocks: 0x%x\n", len); + logerror( "\tROM bank size: %s \n", + (type == SNES_MODE20) ? "LoROM" : + (type == SNES_MODE21) ? "HiROM" : + (type == SNES_MODE22) ? "ExLoROM" : + (type == SNES_MODE25) ? "ExHiROM" : "Other (BSX or ST)" ); + logerror( "\tCompany: %s [%.2s]\n", companies[company], company_id ); + logerror( "\tROM ID: %.4s\n\n", rom_id ); + + logerror( "HEADER DETAILS\n" ); + logerror( "==============\n\n" ); + logerror( "\tName: %.21s\n", title ); + logerror( "\tSpeed: %s [%d]\n", (ROM[hilo_mode + 0x15] & 0xf0) ? "FastROM" : "SlowROM", (ROM[hilo_mode + 0x15] & 0xf0) >> 4); + logerror( "\tBank size: %s [%d]\n", (ROM[hilo_mode + 0x15] & 0xf) ? "HiROM" : "LoROM", ROM[hilo_mode + 0x15] & 0xf); + + logerror( "\tType: %s", cart_types[type]); + if (has_ram) + logerror( ", RAM"); + if (has_sram) + logerror( ", SRAM"); + logerror( " [%d]\n", ROM[hilo_mode + 0x16]); + + logerror( "\tSize: %d megabits [%d]\n", 1 << (ROM[hilo_mode + 0x17] - 7), ROM[hilo_mode + 0x17]); + logerror( "\tSRAM: %d kilobits [%d]\n", ROM[hilo_mode + 0x18] * 8, ROM[hilo_mode + 0x18] ); + if (ROM[hilo_mode + 0x19] < ARRAY_LENGTH(countries)) + logerror( "\tCountry: %s [%d]\n", countries[ROM[hilo_mode + 0x19]], ROM[hilo_mode + 0x19]); + else + logerror( "\tCountry: Unknown [%d]\n", ROM[hilo_mode + 0x19]); + logerror( "\tLicense: %s [%X]\n", companies[ROM[hilo_mode + 0x1a]], ROM[hilo_mode + 0x1a]); + logerror( "\tVersion: 1.%d\n", ROM[hilo_mode + 0x1b]); + logerror( "\tInv Checksum: %X %X\n", ROM[hilo_mode + 0x1d], ROM[hilo_mode + 0x1c]); + logerror( "\tChecksum: %X %X\n", ROM[hilo_mode + 0x1f], ROM[hilo_mode + 0x1e]); + logerror( "\tNMI Address: %2X%2Xh\n", ROM[hilo_mode + 0x3b], ROM[hilo_mode + 0x3a]); + logerror( "\tStart Address: %2X%2Xh\n\n", ROM[hilo_mode + 0x3d], ROM[hilo_mode + 0x3c]); + + logerror( "\tMode: %d\n", type); +} diff --git a/src/devices/bus/snes/snes_slot.h b/src/devices/bus/snes/snes_slot.h new file mode 100644 index 00000000000..a6fa076810f --- /dev/null +++ b/src/devices/bus/snes/snes_slot.h @@ -0,0 +1,274 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __SNS_SLOT_H +#define __SNS_SLOT_H + +/*************************************************************************** + TYPE DEFINITIONS + ***************************************************************************/ + +// offset of add-on dumps inside snes_add/snesp_add bios, to support old dumps missing add-on data +#define SNES_DSP1_OFFSET (0x00000) +#define SNES_DSP1B_OFFSET (0x03000) +#define SNES_DSP2_OFFSET (0x06000) +#define SNES_DSP3_OFFSET (0x09000) +#define SNES_DSP4_OFFSET (0x0c000) +#define SNES_ST10_OFFSET (0x0f000) +#define SNES_ST11_OFFSET (0x20000) +#define SNES_CX4_OFFSET (0x31000) +#define SNES_ST18_OFFSET1 (0x32000) +#define SNES_ST18_OFFSET2 (0x52000) + + +/* PCB */ +enum +{ + SNES_MODE20 = 0, + SNES_MODE21, + SNES_MODE22, // ExLoROM - not used anymore in emulation (only to log info), will be removed + SNES_MODE25, // ExHiROM - not used anymore in emulation (only to log info), will be removed + SNES_CX4, + SNES_DSP, + SNES_DSP_2MB, + SNES_DSP_MODE21, + SNES_DSP4, + SNES_OBC1, + SNES_SA1, + SNES_SDD1, + SNES_SFX, + SNES_SPC7110, + SNES_SPC7110_RTC, + SNES_SRTC, + SNES_ST010, + SNES_ST011, + SNES_ST018, + SNES_Z80GB, + SNES_PFEST94, + SNES_BSX, + SNES_BSXLO, + SNES_BSXHI, + SNES_BSMEMPAK, + SNES_SUFAMITURBO, + SNES_STROM, + // pirate carts + SNES_POKEMON, + SNES_TEKKEN2, + SNES_SOULBLAD, + SNES_MCPIR1, + SNES_MCPIR2, + SNES_20COL, + SNES_BANANA, // wip + SNES_BUGS, // wip + // legacy types to support DSPx games from fullpath + SNES_DSP1_LEG, + SNES_DSP1B_LEG, + SNES_DSP2_LEG, + SNES_DSP3_LEG, + SNES_DSP4_LEG, + SNES_DSP1_MODE21_LEG, + SNES_ST010_LEG, + SNES_ST011_LEG +}; + +/* add-ons to handle legacy dumps in snes_add */ +enum +{ + ADDON_NONE = 0, + ADDON_CX4, + ADDON_DSP1, + ADDON_DSP1B, + ADDON_DSP2, + ADDON_DSP3, + ADDON_DSP4, + ADDON_OBC1, + ADDON_SA1, + ADDON_SDD1, + ADDON_SFX, + ADDON_SPC7110, + ADDON_SPC7110_RTC, + ADDON_ST010, + ADDON_ST011, + ADDON_ST018, + ADDON_SRTC, + ADDON_Z80GB +}; + +// ======================> device_sns_cart_interface + +class device_sns_cart_interface : public device_slot_card_interface +{ +public: + // construction/destruction + device_sns_cart_interface(const machine_config &mconfig, device_t &device); + virtual ~device_sns_cart_interface(); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_l) { return 0xff; } // ROM access in range [00-7f] + virtual DECLARE_READ8_MEMBER(read_h) { return 0xff; } // ROM access in range [80-ff] + virtual DECLARE_READ8_MEMBER(read_ram) { if (!m_nvram.empty()) return m_nvram[offset & (m_nvram.size()-1)]; else return 0xff; } // NVRAM access + virtual DECLARE_WRITE8_MEMBER(write_l) {} // used by carts with subslots + virtual DECLARE_WRITE8_MEMBER(write_h) {} // used by carts with subslots + virtual DECLARE_WRITE8_MEMBER(write_ram) { if (!m_nvram.empty()) m_nvram[offset & (m_nvram.size()-1)] = data; } // NVRAM access + virtual DECLARE_READ8_MEMBER(chip_read) { return 0xff; } + virtual DECLARE_WRITE8_MEMBER(chip_write) {} + virtual void speedup_addon_bios_access() {}; + + void rom_alloc(UINT32 size, const char *tag); + void nvram_alloc(UINT32 size); + void rtc_ram_alloc(UINT32 size); + void addon_bios_alloc(UINT32 size); + UINT8* get_rom_base() { return m_rom; }; + UINT8* get_nvram_base() { return &m_nvram[0]; }; + UINT8* get_addon_bios_base() { return &m_bios[0]; }; + UINT8* get_rtc_ram_base() { return &m_rtc_ram[0]; }; + UINT32 get_rom_size() { return m_rom_size; }; + UINT32 get_nvram_size() { return m_nvram.size(); }; + UINT32 get_addon_bios_size() { return m_bios.size(); }; + UINT32 get_rtc_ram_size() { return m_rtc_ram.size(); }; + + void rom_map_setup(UINT32 size); + void save_nvram() { device().save_item(NAME(m_nvram)); } + void save_rtc_ram() { device().save_item(NAME(m_rtc_ram)); } + + // internal state + UINT8 *m_rom; + UINT32 m_rom_size; + dynamic_buffer m_nvram; + dynamic_buffer m_bios; + dynamic_buffer m_rtc_ram; // temp pointer to save RTC ram to nvram (will disappear when RTCs become devices) + + UINT8 rom_bank_map[256]; // 32K chunks of rom +}; + + +// ======================> base_sns_cart_slot_device + +class base_sns_cart_slot_device : public device_t, + public device_image_interface, + public device_slot_interface +{ +public: + // construction/destruction + base_sns_cart_slot_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + virtual ~base_sns_cart_slot_device(); + + // device-level overrides + virtual void device_start(); + virtual void device_config_complete(); + + // image-level overrides + virtual bool call_load(); + virtual void call_unload(); + virtual bool call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry); + + void get_cart_type_addon(UINT8 *ROM, UINT32 len, int &type, int &addon); + UINT32 snes_skip_header(UINT8 *ROM, UINT32 snes_rom_size); + int get_type() { return m_type; } + + void setup_nvram(); + void internal_header_logging(UINT8 *ROM, UINT32 len); + + void save_ram() { if (m_cart && m_cart->get_nvram_size()) m_cart->save_nvram(); + if (m_cart && m_cart->get_rtc_ram_size()) m_cart->save_rtc_ram(); } + + virtual iodevice_t image_type() const { return IO_CARTSLOT; } + virtual bool is_readable() const { return 1; } + virtual bool is_writeable() const { return 0; } + virtual bool is_creatable() const { return 0; } + virtual bool must_be_loaded() const { return 1; } + virtual bool is_reset_on_load() const { return 1; } + virtual const option_guide *create_option_guide() const { return NULL; } + + // slot interface overrides + virtual void get_default_card_software(std::string &result); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_l); + virtual DECLARE_READ8_MEMBER(read_h); + virtual DECLARE_READ8_MEMBER(read_ram); + virtual DECLARE_WRITE8_MEMBER(write_l); + virtual DECLARE_WRITE8_MEMBER(write_h); + virtual DECLARE_WRITE8_MEMBER(write_ram); + virtual DECLARE_READ8_MEMBER(chip_read); + virtual DECLARE_WRITE8_MEMBER(chip_write); + + // in order to support legacy dumps + add-on CPU dump appended at the end of the file, we + // check if the required data is present and update bank map accordingly + void setup_addon_from_fullpath(); + + +// m_cart cannot be made private yet, because we need to check nvram_size from the driver... +// more work needed +//private: + + // this is used to support legacy DSPx/ST0xx/CX4 dumps not including the CPU data... + // i.e. it's only used for snes_add/snesp_add + int m_addon; + + int m_type; + device_sns_cart_interface* m_cart; +}; + +// ======================> sns_cart_slot_device + +class sns_cart_slot_device : public base_sns_cart_slot_device +{ +public: + // construction/destruction + sns_cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual const char *image_interface() const { return "snes_cart"; } + virtual const char *file_extensions() const { return "sfc"; } +}; + +// ======================> sns_sufami_cart_slot_device + +class sns_sufami_cart_slot_device : public base_sns_cart_slot_device +{ +public: + // construction/destruction + sns_sufami_cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual const char *image_interface() const { return "st_cart"; } + virtual const char *file_extensions() const { return "st"; } + virtual bool must_be_loaded() const { return 0; } +}; + +// ======================> sns_sufami_cart_slot_device + +class sns_bsx_cart_slot_device : public base_sns_cart_slot_device +{ +public: + // construction/destruction + sns_bsx_cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual const char *image_interface() const { return "bspack"; } + virtual const char *file_extensions() const { return "bs"; } + virtual bool must_be_loaded() const { return 0; } +}; + + +// device type definition +extern const device_type SNS_CART_SLOT; +extern const device_type SNS_SUFAMI_CART_SLOT; +extern const device_type SNS_BSX_CART_SLOT; + + +/*************************************************************************** + DEVICE CONFIGURATION MACROS + ***************************************************************************/ + +#define SNSSLOT_ROM_REGION_TAG ":cart:rom" + + +#define MCFG_SNS_CARTRIDGE_ADD(_tag,_slot_intf,_def_slot) \ + MCFG_DEVICE_ADD(_tag, SNS_CART_SLOT, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) + +#define MCFG_SNS_SUFAMI_CARTRIDGE_ADD(_tag,_slot_intf,_def_slot) \ + MCFG_DEVICE_ADD(_tag, SNS_SUFAMI_CART_SLOT, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) + +#define MCFG_SNS_BSX_CARTRIDGE_ADD(_tag,_slot_intf,_def_slot) \ + MCFG_DEVICE_ADD(_tag, SNS_BSX_CART_SLOT, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) + + +#endif diff --git a/src/devices/bus/snes/spc7110.c b/src/devices/bus/snes/spc7110.c new file mode 100644 index 00000000000..6124ddec6d1 --- /dev/null +++ b/src/devices/bus/snes/spc7110.c @@ -0,0 +1,1677 @@ +// license:GPL-2.0+ +// copyright-holders:Fabio Priuli, byuu +/*********************************************************************************************************** + + SPC-7110 add-on chip emulation (for SNES/SFC) + + Based on C++ implementation by Byuu in BSNES. + + Byuu's code is released under GNU General Public License + version 2 as published by the Free Software Foundation. + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "spc7110.h" + + +//------------------------------------------------- +// constructor +//------------------------------------------------- + +const device_type SNS_HIROM_SPC7110 = &device_creator; +const device_type SNS_HIROM_SPC7110_RTC = &device_creator; + + +sns_rom_spc7110_device::sns_rom_spc7110_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : sns_rom21_device(mconfig, type, name, tag, owner, clock, shortname, source) +{ +} + +sns_rom_spc7110_device::sns_rom_spc7110_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : sns_rom21_device(mconfig, SNS_HIROM_SPC7110, "SNES Cart + SPC-7110", tag, owner, clock, "sns_rom_spc7110", __FILE__) +{ +} + +sns_rom_spc7110rtc_device::sns_rom_spc7110rtc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : sns_rom_spc7110_device(mconfig, SNS_HIROM_SPC7110_RTC, "SNES Cart + SPC-7110 + RTC", tag, owner, clock, "sns_rom_spc7110rtc", __FILE__) +{ +} + + +void sns_rom_spc7110_device::spc7110_start() +{ + m_decomp = auto_alloc(machine(), SPC7110_Decomp(machine())); + + // The SPC7110 works in conjunction with 0x2000 of RAM, which is battery backed up (and hence emulated by our m_nvram) + + m_r4801 = 0x00; + m_r4802 = 0x00; + m_r4803 = 0x00; + m_r4804 = 0x00; + m_r4805 = 0x00; + m_r4806 = 0x00; + m_r4807 = 0x00; + m_r4808 = 0x00; + m_r4809 = 0x00; + m_r480a = 0x00; + m_r480b = 0x00; + m_r480c = 0x00; + + m_r4811 = 0x00; + m_r4812 = 0x00; + m_r4813 = 0x00; + m_r4814 = 0x00; + m_r4815 = 0x00; + m_r4816 = 0x00; + m_r4817 = 0x00; + m_r4818 = 0x00; + + m_r481x = 0x00; + m_r4814_latch = 0; + m_r4815_latch = 0; + + m_r4820 = 0x00; + m_r4821 = 0x00; + m_r4822 = 0x00; + m_r4823 = 0x00; + m_r4824 = 0x00; + m_r4825 = 0x00; + m_r4826 = 0x00; + m_r4827 = 0x00; + m_r4828 = 0x00; + m_r4829 = 0x00; + m_r482a = 0x00; + m_r482b = 0x00; + m_r482c = 0x00; + m_r482d = 0x00; + m_r482e = 0x00; + m_r482f = 0x00; + + m_r4830 = 0x00; + m_r4831 = 0; + m_dx_offset = spc7110_datarom_addr(0 * 0x100000, 0x200000); // we would need the rom length here... + m_r4832 = 1; + m_ex_offset = spc7110_datarom_addr(1 * 0x100000, 0x200000); // we would need the rom length here... + m_r4833 = 2; + m_fx_offset = spc7110_datarom_addr(2 * 0x100000, 0x200000); // we would need the rom length here... + m_r4834 = 0x00; + + m_r4840 = 0x00; + m_r4841 = 0x00; + m_r4842 = 0x00; + + save_item(NAME(m_r4801)); + save_item(NAME(m_r4802)); + save_item(NAME(m_r4803)); + save_item(NAME(m_r4804)); + save_item(NAME(m_r4805)); + save_item(NAME(m_r4806)); + save_item(NAME(m_r4807)); + save_item(NAME(m_r4808)); + save_item(NAME(m_r4809)); + save_item(NAME(m_r480a)); + save_item(NAME(m_r480b)); + save_item(NAME(m_r480c)); + save_item(NAME(m_r4811)); + save_item(NAME(m_r4812)); + save_item(NAME(m_r4813)); + save_item(NAME(m_r4814)); + save_item(NAME(m_r4815)); + save_item(NAME(m_r4816)); + save_item(NAME(m_r4817)); + save_item(NAME(m_r4818)); + save_item(NAME(m_r481x)); + save_item(NAME(m_r4814_latch)); + save_item(NAME(m_r4815_latch)); + save_item(NAME(m_r4820)); + save_item(NAME(m_r4821)); + save_item(NAME(m_r4822)); + save_item(NAME(m_r4823)); + save_item(NAME(m_r4824)); + save_item(NAME(m_r4825)); + save_item(NAME(m_r4826)); + save_item(NAME(m_r4827)); + save_item(NAME(m_r4828)); + save_item(NAME(m_r4829)); + save_item(NAME(m_r482a)); + save_item(NAME(m_r482b)); + save_item(NAME(m_r482c)); + save_item(NAME(m_r482d)); + save_item(NAME(m_r482e)); + save_item(NAME(m_r482f)); + save_item(NAME(m_r4830)); + save_item(NAME(m_r4831)); + save_item(NAME(m_r4832)); + save_item(NAME(m_r4833)); + save_item(NAME(m_r4834)); + save_item(NAME(m_r4840)); + save_item(NAME(m_r4841)); + save_item(NAME(m_r4842)); + save_item(NAME(m_dx_offset)); + save_item(NAME(m_ex_offset)); + save_item(NAME(m_fx_offset)); +} + +void sns_rom_spc7110_device::device_start() +{ + spc7110_start(); +} + +void sns_rom_spc7110rtc_device::device_start() +{ + spc7110_start(); + + // RTC + m_rtc_state = RTCS_Inactive; + m_rtc_mode = RTCM_Linear; + m_rtc_index = 0; + m_rtc_offset = 0; + +// at this stage, rtc_ram is not yet allocated. this will be fixed when converting RTC to be a separate device. +// spc7110_update_time(0); + + // set basetime for RTC + machine().current_datetime(m_rtc_basetime); + + save_item(NAME(m_rtc_state)); + save_item(NAME(m_rtc_mode)); + save_item(NAME(m_rtc_index)); + save_item(NAME(m_rtc_offset)); +} + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +#define SPC7110_DECOMP_BUFFER_SIZE 64 + +static const UINT8 spc7110_evolution_table[53][4] = +{ + { 0x5a, 1, 1, 1 }, + { 0x25, 6, 2, 0 }, + { 0x11, 8, 3, 0 }, + { 0x08, 10, 4, 0 }, + { 0x03, 12, 5, 0 }, + { 0x01, 15, 5, 0 }, + + { 0x5a, 7, 7, 1 }, + { 0x3f, 19, 8, 0 }, + { 0x2c, 21, 9, 0 }, + { 0x20, 22, 10, 0 }, + { 0x17, 23, 11, 0 }, + { 0x11, 25, 12, 0 }, + { 0x0c, 26, 13, 0 }, + { 0x09, 28, 14, 0 }, + { 0x07, 29, 15, 0 }, + { 0x05, 31, 16, 0 }, + { 0x04, 32, 17, 0 }, + { 0x03, 34, 18, 0 }, + { 0x02, 35, 5, 0 }, + + { 0x5a, 20, 20, 1 }, + { 0x48, 39, 21, 0 }, + { 0x3a, 40, 22, 0 }, + { 0x2e, 42, 23, 0 }, + { 0x26, 44, 24, 0 }, + { 0x1f, 45, 25, 0 }, + { 0x19, 46, 26, 0 }, + { 0x15, 25, 27, 0 }, + { 0x11, 26, 28, 0 }, + { 0x0e, 26, 29, 0 }, + { 0x0b, 27, 30, 0 }, + { 0x09, 28, 31, 0 }, + { 0x08, 29, 32, 0 }, + { 0x07, 30, 33, 0 }, + { 0x05, 31, 34, 0 }, + { 0x04, 33, 35, 0 }, + { 0x04, 33, 36, 0 }, + { 0x03, 34, 37, 0 }, + { 0x02, 35, 38, 0 }, + { 0x02, 36, 5, 0 }, + + { 0x58, 39, 40, 1 }, + { 0x4d, 47, 41, 0 }, + { 0x43, 48, 42, 0 }, + { 0x3b, 49, 43, 0 }, + { 0x34, 50, 44, 0 }, + { 0x2e, 51, 45, 0 }, + { 0x29, 44, 46, 0 }, + { 0x25, 45, 24, 0 }, + + { 0x56, 47, 48, 1 }, + { 0x4f, 47, 49, 0 }, + { 0x47, 48, 50, 0 }, + { 0x41, 49, 51, 0 }, + { 0x3c, 50, 52, 0 }, + { 0x37, 51, 43, 0 }, +}; + +static const UINT8 spc7110_mode2_context_table[32][2] = +{ + { 1, 2 }, + + { 3, 8 }, + { 13, 14 }, + + { 15, 16 }, + { 17, 18 }, + { 19, 20 }, + { 21, 22 }, + { 23, 24 }, + { 25, 26 }, + { 25, 26 }, + { 25, 26 }, + { 25, 26 }, + { 25, 26 }, + { 27, 28 }, + { 29, 30 }, + + { 31, 31 }, + { 31, 31 }, + { 31, 31 }, + { 31, 31 }, + { 31, 31 }, + { 31, 31 }, + { 31, 31 }, + { 31, 31 }, + { 31, 31 }, + { 31, 31 }, + { 31, 31 }, + { 31, 31 }, + { 31, 31 }, + { 31, 31 }, + { 31, 31 }, + { 31, 31 }, + + { 31, 31 }, +}; + +SPC7110_Decomp::SPC7110_Decomp(running_machine &machine) + : m_machine(machine) +{ + m_decomp_buffer = (UINT8*)auto_alloc_array(machine, UINT8, SPC7110_DECOMP_BUFFER_SIZE); + reset(); + + for (int i = 0; i < 256; i++) + { +#define map(x, y) (((i >> x) & 1) << y) + //2x8-bit + m_morton16[1][i] = map(7, 15) + map(6, 7) + map(5, 14) + map(4, 6) + + map(3, 13) + map(2, 5) + map(1, 12) + map(0, 4); + m_morton16[0][i] = map(7, 11) + map(6, 3) + map(5, 10) + map(4, 2) + + map(3, 9) + map(2, 1) + map(1, 8) + map(0, 0); + //4x8-bit + m_morton32[3][i] = map(7, 31) + map(6, 23) + map(5, 15) + map(4, 7) + + map(3, 30) + map(2, 22) + map(1, 14) + map(0, 6); + m_morton32[2][i] = map(7, 29) + map(6, 21) + map(5, 13) + map(4, 5) + + map(3, 28) + map(2, 20) + map(1, 12) + map(0, 4); + m_morton32[1][i] = map(7, 27) + map(6, 19) + map(5, 11) + map(4, 3) + + map(3, 26) + map(2, 18) + map(1, 10) + map(0, 2); + m_morton32[0][i] = map(7, 25) + map(6, 17) + map(5, 9) + map(4, 1) + + map(3, 24) + map(2, 16) + map(1, 8) + map(0, 0); +#undef map + } + + m_machine.save().save_item(m_decomp_mode, "SNES_SPC7110/m_decomp_mode"); + m_machine.save().save_item(m_decomp_offset, "SNES_SPC7110/m_decomp_offset"); + m_machine.save().save_pointer(m_decomp_buffer, "SNES_SPC7110/m_decomp_buffer", SPC7110_DECOMP_BUFFER_SIZE); + m_machine.save().save_item(m_decomp_buffer_rdoffset, "SNES_SPC7110/m_decomp_buffer_rdoffset"); + m_machine.save().save_item(m_decomp_buffer_wroffset, "SNES_SPC7110/m_decomp_buffer_wroffset"); + m_machine.save().save_item(m_decomp_buffer_length, "SNES_SPC7110/m_decomp_buffer_length"); + + for (int i = 0; i < 32; i++) + { + m_machine.save().save_item(m_context[i].index, "SNES_SPC7110/m_context[i].index", i); + m_machine.save().save_item(m_context[i].invert, "SNES_SPC7110/m_context[i].invert", i); + } + + m_machine.save().save_item(m_m0_val, "SNES_SPC7110/m_m0_val"); + m_machine.save().save_item(m_m0_in, "SNES_SPC7110/m_m0_in"); + m_machine.save().save_item(m_m0_span, "SNES_SPC7110/m_m0_span"); + m_machine.save().save_item(m_m0_out, "SNES_SPC7110/m_m0_out"); + m_machine.save().save_item(m_m0_inverts, "SNES_SPC7110/m_m0_inverts"); + m_machine.save().save_item(m_m0_lps, "SNES_SPC7110/m_m0_lps"); + m_machine.save().save_item(m_m0_in_count, "SNES_SPC7110/m_m0_in_count"); + + m_machine.save().save_item(m_m1_pixelorder, "SNES_SPC7110/m_m1_pixelorder"); + m_machine.save().save_item(m_m1_realorder, "SNES_SPC7110/m_m1_realorder"); + m_machine.save().save_item(m_m1_val, "SNES_SPC7110/m_m1_val"); + m_machine.save().save_item(m_m1_in, "SNES_SPC7110/m_m1_in"); + m_machine.save().save_item(m_m1_span, "SNES_SPC7110/m_m1_span"); + m_machine.save().save_item(m_m1_out, "SNES_SPC7110/m_m1_out"); + m_machine.save().save_item(m_m1_inverts, "SNES_SPC7110/m_m1_inverts"); + m_machine.save().save_item(m_m1_lps, "SNES_SPC7110/m_m1_lps"); + m_machine.save().save_item(m_m1_in_count, "SNES_SPC7110/m_m1_in_count"); + + m_machine.save().save_item(m_m2_pixelorder, "SNES_SPC7110/m_m2_pixelorder"); + m_machine.save().save_item(m_m2_realorder, "SNES_SPC7110/m_m2_realorder"); + m_machine.save().save_item(m_m2_bitplanebuffer, "SNES_SPC7110/m_m2_bitplanebuffer"); + m_machine.save().save_item(m_m2_buffer_index, "SNES_SPC7110/m_m2_buffer_index"); + m_machine.save().save_item(m_m2_val, "SNES_SPC7110/m_m2_val"); + m_machine.save().save_item(m_m2_in, "SNES_SPC7110/m_m2_in"); + m_machine.save().save_item(m_m2_span, "SNES_SPC7110/m_m2_span"); + m_machine.save().save_item(m_m2_out0, "SNES_SPC7110/m_m2_out0"); + m_machine.save().save_item(m_m2_out1, "SNES_SPC7110/m_m2_out1"); + m_machine.save().save_item(m_m2_inverts, "SNES_SPC7110/m_m2_inverts"); + m_machine.save().save_item(m_m2_lps, "SNES_SPC7110/m_m2_lps"); + m_machine.save().save_item(m_m2_in_count, "SNES_SPC7110/m_m2_in_count"); +} + +void SPC7110_Decomp::reset() +{ + //mode 3 is invalid; this is treated as a special case to always return 0x00 + //set to mode 3 so that reading decomp port before starting first decomp will return 0x00 + m_decomp_mode = 3; + + m_decomp_buffer_rdoffset = 0; + m_decomp_buffer_wroffset = 0; + m_decomp_buffer_length = 0; +} + +void SPC7110_Decomp::init(running_machine &machine, UINT8 *ROM, UINT32 len, UINT32 mode, UINT32 offset, UINT32 index) +{ + m_decomp_mode = mode; + m_decomp_offset = offset; + + m_decomp_buffer_rdoffset = 0; + m_decomp_buffer_wroffset = 0; + m_decomp_buffer_length = 0; + + //reset context states + for (int i = 0; i < 32; i++) + { + m_context[i].index = 0; + m_context[i].invert = 0; + } + + switch (m_decomp_mode) + { + case 0: mode0(1, ROM, len); break; + case 1: mode1(1, ROM, len); break; + case 2: mode2(1, ROM, len); break; + } + + //decompress up to requested output data index + while (index--) + { + read(ROM, len); + } +} + +UINT8 SPC7110_Decomp::read(UINT8 *ROM, UINT32 len) +{ + UINT8 data; + + if (m_decomp_buffer_length == 0) + { + //decompress at least (SPC7110_DECOMP_BUFFER_SIZE / 2) bytes to the buffer + switch (m_decomp_mode) + { + case 0: + mode0(0, ROM, len); + break; + + case 1: + mode1(0, ROM, len); + break; + + case 2: + mode2(0, ROM, len); + break; + + default: + return 0x00; + } + } + + data = m_decomp_buffer[m_decomp_buffer_rdoffset++]; + m_decomp_buffer_rdoffset &= SPC7110_DECOMP_BUFFER_SIZE - 1; + m_decomp_buffer_length--; + return data; +} + +void SPC7110_Decomp::write(UINT8 data) +{ + m_decomp_buffer[m_decomp_buffer_wroffset++] = data; + m_decomp_buffer_wroffset &= SPC7110_DECOMP_BUFFER_SIZE - 1; + m_decomp_buffer_length++; +} + +UINT8 SPC7110_Decomp::dataread(UINT8 *ROM, UINT32 len) +{ + UINT32 size = len - 0x100000; + while (m_decomp_offset >= size) + { + m_decomp_offset -= size; + } + return ROM[0x100000 + m_decomp_offset++]; +} + +void SPC7110_Decomp::mode0(UINT8 init, UINT8 *ROM, UINT32 len) +{ + if (init == 1) + { + m_m0_out = m_m0_inverts = m_m0_lps = 0; + m_m0_span = 0xff; + m_m0_val = dataread(ROM, len); + m_m0_in = dataread(ROM, len); + m_m0_in_count = 8; + return; + } + + while (m_decomp_buffer_length < (SPC7110_DECOMP_BUFFER_SIZE >> 1)) + { + for (int bit = 0; bit < 8; bit++) + { + //get context + UINT8 mask = (1 << (bit & 3)) - 1; + UINT8 con = mask + ((m_m0_inverts & mask) ^ (m_m0_lps & mask)); + UINT32 prob, mps, flag_lps; + UINT32 shift = 0; + if (bit > 3) + { + con += 15; + } + + //get prob and mps + prob = probability(con); + mps = (((m_m0_out >> 15) & 1) ^ m_context[con].invert); + + //get bit + if (m_m0_val <= m_m0_span - prob) //mps + { + m_m0_span = m_m0_span - prob; + m_m0_out = (m_m0_out << 1) + mps; + flag_lps = 0; + } + else //lps + { + m_m0_val = m_m0_val - (m_m0_span - (prob - 1)); + m_m0_span = prob - 1; + m_m0_out = (m_m0_out << 1) + 1 - mps; + flag_lps = 1; + } + + //renormalize + while (m_m0_span < 0x7f) + { + shift++; + + m_m0_span = (m_m0_span << 1) + 1; + m_m0_val = (m_m0_val << 1) + (m_m0_in >> 7); + + m_m0_in <<= 1; + if (--m_m0_in_count == 0) + { + m_m0_in = dataread(ROM, len); + m_m0_in_count = 8; + } + } + + //update processing info + m_m0_lps = (m_m0_lps << 1) + flag_lps; + m_m0_inverts = (m_m0_inverts << 1) + m_context[con].invert; + + //update context state + if (flag_lps & toggle_invert(con)) + { + m_context[con].invert ^= 1; + } + if (flag_lps) + { + m_context[con].index = next_lps(con); + } + else if (shift) + { + m_context[con].index = next_mps(con); + } + } + + //save byte + write(m_m0_out); + } +} + +void SPC7110_Decomp::mode1(UINT8 init, UINT8 *ROM, UINT32 len) +{ + if (init == 1) + { + for (int i = 0; i < 4; i++) + { + m_m1_pixelorder[i] = i; + } + m_m1_out = m_m1_inverts = m_m1_lps = 0; + m_m1_span = 0xff; + m_m1_val = dataread(ROM, len); + m_m1_in = dataread(ROM, len); + m_m1_in_count = 8; + return; + } + + while (m_decomp_buffer_length < (SPC7110_DECOMP_BUFFER_SIZE >> 1)) + { + UINT16 data; + for (int pixel = 0; pixel < 8; pixel++) + { + //get first symbol context + UINT32 a = ((m_m1_out >> (1 * 2)) & 3); + UINT32 b = ((m_m1_out >> (7 * 2)) & 3); + UINT32 c = ((m_m1_out >> (8 * 2)) & 3); + UINT32 con = (a == b) ? (b != c) : (b == c) ? 2 : 4 - (a == c); + + //update pixel order + UINT32 m, n; + for (m = 0; m < 4; m++) + { + if (m_m1_pixelorder[m] == a) + { + break; + } + } + for (n = m; n > 0; n--) + { + m_m1_pixelorder[n] = m_m1_pixelorder[n - 1]; + } + m_m1_pixelorder[0] = a; + + //calculate the real pixel order + for (m = 0; m < 4; m++) + { + m_m1_realorder[m] = m_m1_pixelorder[m]; + } + + //rotate reference pixel c value to top + for (m = 0; m < 4; m++) + { + if (m_m1_realorder[m] == c) + { + break; + } + } + for (n = m; n > 0; n--) + { + m_m1_realorder[n] = m_m1_realorder[n - 1]; + } + m_m1_realorder[0] = c; + + //rotate reference pixel b value to top + for (m = 0; m < 4; m++) + { + if (m_m1_realorder[m] == b) + { + break; + } + } + for (n = m; n > 0; n--) + { + m_m1_realorder[n] = m_m1_realorder[n - 1]; + } + m_m1_realorder[0] = b; + + //rotate reference pixel a value to top + for (m = 0; m < 4; m++) + { + if (m_m1_realorder[m] == a) + { + break; + } + } + for (n = m; n > 0; n--) + { + m_m1_realorder[n] = m_m1_realorder[n - 1]; + } + m_m1_realorder[0] = a; + + //get 2 symbols + for (int bit = 0; bit < 2; bit++) + { + //get prob + UINT32 prob = probability(con); + UINT32 shift = 0; + + //get symbol + UINT32 flag_lps; + if (m_m1_val <= m_m1_span - prob) //mps + { + m_m1_span = m_m1_span - prob; + flag_lps = 0; + } + else //lps + { + m_m1_val = m_m1_val - (m_m1_span - (prob - 1)); + m_m1_span = prob - 1; + flag_lps = 1; + } + + //renormalize + while (m_m1_span < 0x7f) + { + shift++; + + m_m1_span = (m_m1_span << 1) + 1; + m_m1_val = (m_m1_val << 1) + (m_m1_in >> 7); + + m_m1_in <<= 1; + if (--m_m1_in_count == 0) + { + m_m1_in = dataread(ROM, len); + m_m1_in_count = 8; + } + } + + //update processing info + m_m1_lps = (m_m1_lps << 1) + flag_lps; + m_m1_inverts = (m_m1_inverts << 1) + m_context[con].invert; + + //update context state + if (flag_lps & toggle_invert(con)) + { + m_context[con].invert ^= 1; + } + if (flag_lps) + { + m_context[con].index = next_lps(con); + } + else if (shift) + { + m_context[con].index = next_mps(con); + } + + //get next context + con = 5 + (con << 1) + ((m_m1_lps ^ m_m1_inverts) & 1); + } + + //get pixel + b = m_m1_realorder[(m_m1_lps ^ m_m1_inverts) & 3]; + m_m1_out = (m_m1_out << 2) + b; + } + + //turn pixel data into bitplanes + data = morton_2x8(m_m1_out); + write(data >> 8); + write(data >> 0); + } +} + +void SPC7110_Decomp::mode2(UINT8 init, UINT8 *ROM, UINT32 len) +{ + if (init == 1) + { + for (int i = 0; i < 16; i++) + { + m_m2_pixelorder[i] = i; + } + m_m2_buffer_index = 0; + m_m2_out0 = m_m2_out1 = m_m2_inverts = m_m2_lps = 0; + m_m2_span = 0xff; + m_m2_val = dataread(ROM, len); + m_m2_in = dataread(ROM, len); + m_m2_in_count = 8; + return; + } + + while (m_decomp_buffer_length < (SPC7110_DECOMP_BUFFER_SIZE >> 1)) + { + UINT32 data; + for (int pixel = 0; pixel < 8; pixel++) + { + //get first symbol context + UINT32 a = ((m_m2_out0 >> (0 * 4)) & 15); + UINT32 b = ((m_m2_out0 >> (7 * 4)) & 15); + UINT32 c = ((m_m2_out1 >> (0 * 4)) & 15); + UINT32 con = 0; + UINT32 refcon = (a == b) ? (b != c) : (b == c) ? 2 : 4 - (a == c); + + //update pixel order + UINT32 m, n; + for (m = 0; m < 16; m++) + { + if (m_m2_pixelorder[m] == a) + { + break; + } + } + for (n = m; n > 0; n--) + { + m_m2_pixelorder[n] = m_m2_pixelorder[n - 1]; + } + m_m2_pixelorder[0] = a; + + //calculate the real pixel order + for (m = 0; m < 16; m++) + { + m_m2_realorder[m] = m_m2_pixelorder[m]; + } + + //rotate reference pixel c value to top + for (m = 0; m < 16; m++) + { + if (m_m2_realorder[m] == c) + { + break; + } + } + for (n = m; n > 0; n--) + { + m_m2_realorder[n] = m_m2_realorder[n - 1]; + } + m_m2_realorder[0] = c; + + //rotate reference pixel b value to top + for (m = 0; m < 16; m++) + { + if (m_m2_realorder[m] == b) + { + break; + } + } + for (n = m; n > 0; n--) + { + m_m2_realorder[n] = m_m2_realorder[n - 1]; + } + m_m2_realorder[0] = b; + + //rotate reference pixel a value to top + for (m = 0; m < 16; m++) + { + if (m_m2_realorder[m] == a) + { + break; + } + } + for (n = m; n > 0; n--) + { + m_m2_realorder[n] = m_m2_realorder[n - 1]; + } + m_m2_realorder[0] = a; + + //get 4 symbols + for (int bit = 0; bit < 4; bit++) + { + UINT32 invertbit, shift; + + //get prob + UINT32 prob = probability(con); + + //get symbol + UINT32 flag_lps; + if (m_m2_val <= m_m2_span - prob) //mps + { + m_m2_span = m_m2_span - prob; + flag_lps = 0; + } + else //lps + { + m_m2_val = m_m2_val - (m_m2_span - (prob - 1)); + m_m2_span = prob - 1; + flag_lps = 1; + } + + //renormalize + shift = 0; + while (m_m2_span < 0x7f) + { + shift++; + + m_m2_span = (m_m2_span << 1) + 1; + m_m2_val = (m_m2_val << 1) + (m_m2_in >> 7); + + m_m2_in <<= 1; + if (--m_m2_in_count == 0) + { + m_m2_in = dataread(ROM, len); + m_m2_in_count = 8; + } + } + + //update processing info + m_m2_lps = (m_m2_lps << 1) + flag_lps; + invertbit = m_context[con].invert; + m_m2_inverts = (m_m2_inverts << 1) + invertbit; + + //update context state + if (flag_lps & toggle_invert(con)) + { + m_context[con].invert ^= 1; + } + if (flag_lps) + { + m_context[con].index = next_lps(con); + } + else if (shift) + { + m_context[con].index = next_mps(con); + } + + //get next context + con = spc7110_mode2_context_table[con][flag_lps ^ invertbit] + (con == 1 ? refcon : 0); + } + + //get pixel + b = m_m2_realorder[(m_m2_lps ^ m_m2_inverts) & 0x0f]; + m_m2_out1 = (m_m2_out1 << 4) + ((m_m2_out0 >> 28) & 0x0f); + m_m2_out0 = (m_m2_out0 << 4) + b; + } + + //convert pixel data into bitplanes + data = morton_4x8(m_m2_out0); + write(data >> 24); + write(data >> 16); + m_m2_bitplanebuffer[m_m2_buffer_index++] = data >> 8; + m_m2_bitplanebuffer[m_m2_buffer_index++] = data >> 0; + + if (m_m2_buffer_index == 16) + { + for (int i = 0; i < 16; i++) + { + write(m_m2_bitplanebuffer[i]); + } + m_m2_buffer_index = 0; + } + } +} + +UINT8 SPC7110_Decomp::probability(UINT32 n) +{ + return spc7110_evolution_table[m_context[n].index][0]; +} + +UINT8 SPC7110_Decomp::next_lps(UINT32 n) +{ + return spc7110_evolution_table[m_context[n].index][1]; +} + +UINT8 SPC7110_Decomp::next_mps(UINT32 n) +{ + return spc7110_evolution_table[m_context[n].index][2]; +} + +UINT8 SPC7110_Decomp::toggle_invert(UINT32 n) +{ + return spc7110_evolution_table[m_context[n].index][3]; +} + +UINT32 SPC7110_Decomp::morton_2x8(UINT32 data) +{ + //reverse morton lookup: de-interleave two 8-bit values + //15, 13, 11, 9, 7, 5, 3, 1 -> 15- 8 + //14, 12, 10, 8, 6, 4, 2, 0 -> 7- 0 + return m_morton16[0][(data >> 0) & 255] + m_morton16[1][(data >> 8) & 255]; +} + +UINT32 SPC7110_Decomp::morton_4x8(UINT32 data) +{ + //reverse morton lookup: de-interleave four 8-bit values + //31, 27, 23, 19, 15, 11, 7, 3 -> 31-24 + //30, 26, 22, 18, 14, 10, 6, 2 -> 23-16 + //29, 25, 21, 17, 13, 9, 5, 1 -> 15- 8 + //28, 24, 20, 16, 12, 8, 4, 0 -> 7- 0 + return m_morton32[0][(data >> 0) & 255] + m_morton32[1][(data >> 8) & 255] + + m_morton32[2][(data >> 16) & 255] + m_morton32[3][(data >> 24) & 255]; +} + + +static const UINT32 spc7110_months[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; + +UINT32 sns_rom_spc7110_device::spc7110_datarom_addr(UINT32 addr, UINT32 rom_len) +{ + UINT32 size = rom_len - 0x100000; + while (addr >= size) + { + addr -= size; + } + return addr + 0x100000; +} + +UINT32 sns_rom_spc7110_device::spc7110_data_pointer(void) +{ + return m_r4811 + (m_r4812 << 8) + (m_r4813 << 16); +} + +UINT32 sns_rom_spc7110_device::spc7110_data_adjust(void) +{ + return m_r4814 + (m_r4815 << 8); +} + +UINT32 sns_rom_spc7110_device::spc7110_data_increment(void) +{ + return m_r4816 + (m_r4817 << 8); +} + +void sns_rom_spc7110_device::spc7110_set_data_pointer(UINT32 addr) +{ + m_r4811 = addr; + m_r4812 = addr >> 8; + m_r4813 = addr >> 16; +} + +void sns_rom_spc7110_device::spc7110_set_data_adjust(UINT32 addr) +{ + m_r4814 = addr; + m_r4815 = addr >> 8; +} + +// FIXME: SPC7110 RTC is capable of rounding/adding/zero-ing seconds, so +// we should probably keep track internally of the time rather than updating +// to the system time at each call with a "offset" tracking as we do now... +// (and indeed current code fails to pass Tengai Makyou Zero tests) +void sns_rom_spc7110_device::spc7110_update_time(UINT8 offset) +{ + system_time curtime; + machine().current_datetime(curtime); + INT64 diff = curtime.time - m_rtc_basetime.time - offset; +// printf("diff %llx\n", diff); + bool update = TRUE; + + // TEST: can we go beyond 24hrs of rounding?!? I doubt it will ever go beyond 3600, but I could be wrong... + assert(diff < 86400); + + /* do not update if CR0 or CR2 timer disable flags are set */ + if ((m_rtc_ram[13] & 0x01) || (m_rtc_ram[15] & 0x03)) + update = FALSE; + + if (update && diff > 0) + { + /* update time with offset, assuming offset < 3600s */ + UINT32 second = m_rtc_ram[0] + m_rtc_ram[1] * 10; + UINT8 minute = m_rtc_ram[2] + m_rtc_ram[3] * 10; + UINT8 hour = m_rtc_ram[4] + m_rtc_ram[5] * 10; + UINT8 day = m_rtc_ram[6] + m_rtc_ram[7] * 10; + UINT8 month = m_rtc_ram[8] + m_rtc_ram[9] * 10; + UINT8 year = m_rtc_ram[10] + m_rtc_ram[11] * 10; + UINT8 weekday = m_rtc_ram[12]; + day--; + month--; + year += (year >= 90) ? 1900 : 2000; + + second += (UINT32)diff; + while (second >= 60) + { + second -= 60; + minute++; + + // are we below 60 minutes? + if (minute < 60) + continue; + // otherwise we have to increase hour! + minute = 0; + hour++; + + // are we below 24 hours? + if (hour < 24) + continue; + // otherwise we have to increase day! + hour = 0; + day++; + + weekday = (weekday + 1) % 7; + + UINT8 days = spc7110_months[month % 12]; + // check for feb 29th + if (days == 28) + { + bool leap = FALSE; + if ((year % 4) == 0) + { + if(year % 100 || !(year % 400)) + leap = TRUE; + } + if (leap) + days++; + } + + // are we below end of month? + if (day < days) + continue; + // otherwise we have to increase month! + day = 0; + month++; + + // are we below end of year? + if (month < 12) + continue; + // otherwise we have to increase year! + month = 0; + year++; + } + + day++; + month++; + year %= 100; + + m_rtc_ram[0] = second % 10; + m_rtc_ram[1] = second / 10; + m_rtc_ram[2] = minute % 10; + m_rtc_ram[3] = minute / 10; + m_rtc_ram[4] = hour % 10; + m_rtc_ram[5] = hour / 10; + m_rtc_ram[6] = day % 10; + m_rtc_ram[7] = day / 10; + m_rtc_ram[8] = month % 10; + m_rtc_ram[9] = month / 10; + m_rtc_ram[10] = year % 10; + m_rtc_ram[11] = (year / 10) % 10; + m_rtc_ram[12] = weekday % 7; + m_rtc_basetime = curtime; + } +} + +READ8_MEMBER(sns_rom_spc7110_device::chip_read) +{ + UINT8 *ROM = get_rom_base(); + UINT32 len = get_rom_size(); + UINT16 addr = offset & 0xffff; + + switch (addr) + { + //================== + //decompression unit + //================== + + case 0x4800: + { + UINT16 counter = (m_r4809 + (m_r480a << 8)); + counter--; + m_r4809 = counter; + m_r480a = counter >> 8; + return m_decomp->read(ROM, len); + } + case 0x4801: return m_r4801; + case 0x4802: return m_r4802; + case 0x4803: return m_r4803; + case 0x4804: return m_r4804; + case 0x4805: return m_r4805; + case 0x4806: return m_r4806; + case 0x4807: return m_r4807; + case 0x4808: return m_r4808; + case 0x4809: return m_r4809; + case 0x480a: return m_r480a; + case 0x480b: return m_r480b; + case 0x480c: + { + UINT8 status = m_r480c; + m_r480c &= 0x7f; + return status; + } + + //============== + //data port unit + //============== + + case 0x4810: + { + UINT8 data; + UINT32 address, adjust, adjustaddr; + + if (m_r481x != 0x07) return 0x00; + + address = spc7110_data_pointer(); + adjust = spc7110_data_adjust(); + if (m_r4818 & 8) + { + adjust = (INT16)adjust; //16-bit sign extend + } + + adjustaddr = address; + if (m_r4818 & 2) + { + adjustaddr += adjust; + spc7110_set_data_adjust(adjust + 1); + } + + data = ROM[spc7110_datarom_addr(adjustaddr, len)]; + if (!(m_r4818 & 2)) + { + UINT32 increment = (m_r4818 & 1) ? spc7110_data_increment() : 1; + if (m_r4818 & 4) + { + increment = (INT16)increment; //16-bit sign extend + } + + if ((m_r4818 & 16) == 0) + { + spc7110_set_data_pointer(address + increment); + } + else + { + spc7110_set_data_adjust(adjust + increment); + } + } + + return data; + } + case 0x4811: return m_r4811; + case 0x4812: return m_r4812; + case 0x4813: return m_r4813; + case 0x4814: return m_r4814; + case 0x4815: return m_r4815; + case 0x4816: return m_r4816; + case 0x4817: return m_r4817; + case 0x4818: return m_r4818; + case 0x481a: + { + UINT8 data; + UINT32 address, adjust; + if (m_r481x != 0x07) + { + return 0x00; + } + + address = spc7110_data_pointer(); + adjust = spc7110_data_adjust(); + if (m_r4818 & 8) + { + adjust = (INT16)adjust; //16-bit sign extend + } + + data = ROM[spc7110_datarom_addr(address + adjust, len)]; + if ((m_r4818 & 0x60) == 0x60) + { + if ((m_r4818 & 16) == 0) + { + spc7110_set_data_pointer(address + adjust); + } + else + { + spc7110_set_data_adjust(adjust + adjust); + } + } + + return data; + } + + //========= + //math unit + //========= + + case 0x4820: return m_r4820; + case 0x4821: return m_r4821; + case 0x4822: return m_r4822; + case 0x4823: return m_r4823; + case 0x4824: return m_r4824; + case 0x4825: return m_r4825; + case 0x4826: return m_r4826; + case 0x4827: return m_r4827; + case 0x4828: return m_r4828; + case 0x4829: return m_r4829; + case 0x482a: return m_r482a; + case 0x482b: return m_r482b; + case 0x482c: return m_r482c; + case 0x482d: return m_r482d; + case 0x482e: return m_r482e; + case 0x482f: + { + UINT8 status = m_r482f; + m_r482f &= 0x7f; + return status; + } + + //=================== + //memory mapping unit + //=================== + + case 0x4830: return m_r4830; + case 0x4831: return m_r4831; + case 0x4832: return m_r4832; + case 0x4833: return m_r4833; + case 0x4834: return m_r4834; + + //==================== + //real-time clock unit + //==================== + case 0x4840: return m_r4840; + case 0x4841: + { + UINT8 data = 0; + if (m_rtc_state == RTCS_Inactive || m_rtc_state == RTCS_ModeSelect) + return 0x00; + + m_r4842 = 0x80; + data = m_rtc_ram[m_rtc_index]; + m_rtc_index = (m_rtc_index + 1) & 15; + return data; + } + case 0x4842: + { + UINT8 status = m_r4842; + m_r4842 &= 0x7f; + return status; + } + } + + return 0xff; +} + +WRITE8_MEMBER(sns_rom_spc7110_device::chip_write) +{ + UINT8 *ROM = get_rom_base(); + UINT32 len = get_rom_size(); + UINT16 addr = offset & 0xffff; + + switch (addr) + { + //================== + //decompression unit + //================== + + case 0x4801: m_r4801 = data; break; + case 0x4802: m_r4802 = data; break; + case 0x4803: m_r4803 = data; break; + case 0x4804: m_r4804 = data; break; + case 0x4805: m_r4805 = data; break; + case 0x4806: + { + UINT32 table, index, address, mode, offset; + m_r4806 = data; + + table = (m_r4801 + (m_r4802 << 8) + (m_r4803 << 16)); + index = (m_r4804 << 2); + //length = (m_r4809 + (m_r480a << 8)); + address = spc7110_datarom_addr(table + index, len); + mode = (ROM[address + 0]); + offset = (ROM[address + 1] << 16) + + (ROM[address + 2] << 8) + + (ROM[address + 3] << 0); + + m_decomp->init(machine(), ROM, len, mode, offset, (m_r4805 + (m_r4806 << 8)) << mode); + m_r480c = 0x80; + } + break; + + case 0x4807: m_r4807 = data; break; + case 0x4808: m_r4808 = data; break; + case 0x4809: m_r4809 = data; break; + case 0x480a: m_r480a = data; break; + case 0x480b: m_r480b = data; break; + + //============== + //data port unit + //============== + + case 0x4811: m_r4811 = data; m_r481x |= 0x01; break; + case 0x4812: m_r4812 = data; m_r481x |= 0x02; break; + case 0x4813: m_r4813 = data; m_r481x |= 0x04; break; + case 0x4814: + { + m_r4814 = data; + m_r4814_latch = 1; + if (!m_r4815_latch) + { + break; + } + if (!(m_r4818 & 2)) + { + break; + } + if (m_r4818 & 0x10) + { + break; + } + + if ((m_r4818 & 0x60) == 0x20) + { + UINT32 increment = spc7110_data_adjust() & 0xff; + if (m_r4818 & 8) + { + increment = (INT8)increment; //8-bit sign extend + } + spc7110_set_data_pointer(spc7110_data_pointer() + increment); + } + else if ((m_r4818 & 0x60) == 0x40) + { + UINT32 increment = spc7110_data_adjust(); + if (m_r4818 & 8) + { + increment = (INT16)increment; //16-bit sign extend + } + spc7110_set_data_pointer(spc7110_data_pointer() + increment); + } + break; + } + + case 0x4815: + { + m_r4815 = data; + m_r4815_latch = 1; + if (!m_r4814_latch) + { + break; + } + if (!(m_r4818 & 2)) + { + break; + } + if (m_r4818 & 0x10) + { + break; + } + + if ((m_r4818 & 0x60) == 0x20) + { + UINT32 increment = spc7110_data_adjust() & 0xff; + if (m_r4818 & 8) + { + increment = (INT8)increment; //8-bit sign extend + } + spc7110_set_data_pointer(spc7110_data_pointer() + increment); + } + else if ((m_r4818 & 0x60) == 0x40) + { + UINT32 increment = spc7110_data_adjust(); + if (m_r4818 & 8) + { + increment = (INT16)increment; //16-bit sign extend + } + spc7110_set_data_pointer(spc7110_data_pointer() + increment); + } + break; + } + + case 0x4816: m_r4816 = data; break; + case 0x4817: m_r4817 = data; break; + case 0x4818: + { + if (m_r481x != 0x07) + break; + + m_r4818 = data; + m_r4814_latch = m_r4815_latch = 0; + break; + } + + //========= + //math unit + //========= + + case 0x4820: m_r4820 = data; break; + case 0x4821: m_r4821 = data; break; + case 0x4822: m_r4822 = data; break; + case 0x4823: m_r4823 = data; break; + case 0x4824: m_r4824 = data; break; + case 0x4825: + { + m_r4825 = data; + + if (m_r482e & 1) + { + //signed 16-bit x 16-bit multiplication + INT16 r0 = (INT16)(m_r4824 + (m_r4825 << 8)); + INT16 r1 = (INT16)(m_r4820 + (m_r4821 << 8)); + + INT32 result = r0 * r1; + m_r4828 = result; + m_r4829 = result >> 8; + m_r482a = result >> 16; + m_r482b = result >> 24; + } + else + { + //unsigned 16-bit x 16-bit multiplication + UINT16 r0 = (UINT16)(m_r4824 + (m_r4825 << 8)); + UINT16 r1 = (UINT16)(m_r4820 + (m_r4821 << 8)); + + UINT32 result = r0 * r1; + m_r4828 = result; + m_r4829 = result >> 8; + m_r482a = result >> 16; + m_r482b = result >> 24; + } + + m_r482f = 0x80; + break; + } + + case 0x4826: m_r4826 = data; break; + case 0x4827: + { + m_r4827 = data; + + if (m_r482e & 1) + { + //signed 32-bit x 16-bit division + INT32 dividend = (INT32)(m_r4820 + (m_r4821 << 8) + (m_r4822 << 16) + (m_r4823 << 24)); + INT16 divisor = (INT16)(m_r4826 + (m_r4827 << 8)); + + INT32 quotient; + INT16 remainder; + + if (divisor) + { + quotient = (INT32)(dividend / divisor); + remainder = (INT32)(dividend % divisor); + } + else + { + //illegal division by zero + quotient = 0; + remainder = dividend & 0xffff; + } + + m_r4828 = quotient; + m_r4829 = quotient >> 8; + m_r482a = quotient >> 16; + m_r482b = quotient >> 24; + + m_r482c = remainder; + m_r482d = remainder >> 8; + } + else + { + //unsigned 32-bit x 16-bit division + UINT32 dividend = (UINT32)(m_r4820 + (m_r4821 << 8) + (m_r4822 << 16) + (m_r4823 << 24)); + UINT16 divisor = (UINT16)(m_r4826 + (m_r4827 << 8)); + + UINT32 quotient; + UINT16 remainder; + + if (divisor) + { + quotient = (UINT32)(dividend / divisor); + remainder = (UINT16)(dividend % divisor); + } + else + { + //illegal division by zero + quotient = 0; + remainder = dividend & 0xffff; + } + + m_r4828 = quotient; + m_r4829 = quotient >> 8; + m_r482a = quotient >> 16; + m_r482b = quotient >> 24; + + m_r482c = remainder; + m_r482d = remainder >> 8; + } + + m_r482f = 0x80; + break; + } + + case 0x482e: + { + //reset math unit + m_r4820 = m_r4821 = m_r4822 = m_r4823 = 0; + m_r4824 = m_r4825 = m_r4826 = m_r4827 = 0; + m_r4828 = m_r4829 = m_r482a = m_r482b = 0; + m_r482c = m_r482d = 0; + + m_r482e = data; + break; + } + + //=================== + //memory mapping unit + //=================== + + case 0x4830: m_r4830 = data; break; + + case 0x4831: + { + m_r4831 = data; + m_dx_offset = spc7110_datarom_addr(data * 0x100000, len); + break; + } + + case 0x4832: + { + m_r4832 = data; + m_ex_offset = spc7110_datarom_addr(data * 0x100000, len); + break; + } + + case 0x4833: + { + m_r4833 = data; + m_fx_offset = spc7110_datarom_addr(data * 0x100000, len); + break; + } + + case 0x4834: m_r4834 = data; break; + + //==================== + //real-time clock unit + //==================== + + case 0x4840: + { + m_r4840 = data; + + if (!(m_r4840 & 1)) + { + //disable RTC + m_rtc_state = RTCS_Inactive; + spc7110_update_time(0); + } + else + { + //enable RTC + m_r4842 = 0x80; + m_rtc_state = RTCS_ModeSelect; + } + } + break; + + case 0x4841: + { + m_r4841 = data; + + switch (m_rtc_state) + { + case RTCS_ModeSelect: + if (data == RTCM_Linear || data == RTCM_Indexed) + { + m_r4842 = 0x80; + m_rtc_state = RTCS_IndexSelect; + m_rtc_mode = (RTC_Mode)data; + m_rtc_index = 0; + } + break; + + case RTCS_IndexSelect: + m_r4842 = 0x80; + m_rtc_index = data & 15; + if (m_rtc_mode == RTCM_Linear) + m_rtc_state = RTCS_Write; + break; + + case RTCS_Write: + m_r4842 = 0x80; + + //control register 0 + if (m_rtc_index == 13) + { + //increment second counter + if (data & 2) + spc7110_update_time(1); + + //round minute counter + if (data & 8) + { + spc7110_update_time(0); + + UINT8 second = m_rtc_ram[0] + m_rtc_ram[1] * 10; + //clear seconds + m_rtc_ram[0] = 0; + m_rtc_ram[1] = 0; + + if (second >= 30) + spc7110_update_time(60); + } + } + + //control register 2 + if (m_rtc_index == 15) + { + //disable timer and clear second counter + if ((data & 1) && !(m_rtc_ram[15] & 1)) + { + spc7110_update_time(0); + + //clear seconds + m_rtc_ram[0] = 0; + m_rtc_ram[1] = 0; + } + + //disable timer + if ((data & 2) && !(m_rtc_ram[15] & 2)) + spc7110_update_time(0); + } + + m_rtc_ram[m_rtc_index] = data & 15; + m_rtc_index = (m_rtc_index + 1) & 15; + break; + } + } + break; + } +} + +READ8_MEMBER(sns_rom_spc7110_device::read_l) +{ + if (offset < 0x400000) + return m_rom[rom_bank_map[offset / 0x8000] * 0x8000 + (offset & 0x7fff)]; + + return 0xff; +} + +READ8_MEMBER(sns_rom_spc7110_device::read_h) +{ + UINT16 address = offset & 0xfffff; + + if (offset < 0x400000) + return m_rom[rom_bank_map[offset / 0x8000] * 0x8000 + (offset & 0x7fff)]; + else + { + switch (offset & 0x300000) + { + case 0x000000: + return m_rom[rom_bank_map[(offset - 0x400000) / 0x8000] * 0x8000 + (offset & 0x7fff)]; + case 0x100000: + return m_rom[m_dx_offset + address]; + case 0x200000: + return m_rom[m_ex_offset + address]; + case 0x300000: + return m_rom[m_fx_offset + address]; + default: + break; + } + } + + return 0xff; +} + + +READ8_MEMBER( sns_rom_spc7110_device::read_ram ) +{ + return m_nvram[offset & 0x1fff]; +} + +WRITE8_MEMBER( sns_rom_spc7110_device::write_ram ) +{ + m_nvram[offset & 0x1fff] = data; +} diff --git a/src/devices/bus/snes/spc7110.h b/src/devices/bus/snes/spc7110.h new file mode 100644 index 00000000000..128c3ecc5a8 --- /dev/null +++ b/src/devices/bus/snes/spc7110.h @@ -0,0 +1,226 @@ +// license:GPL-2.0+ +// copyright-holders:Fabio Priuli, byuu +#ifndef __SNS_SPC7110_H +#define __SNS_SPC7110_H + +#include "snes_slot.h" +#include "rom21.h" + + +enum RTC_State +{ + RTCS_Inactive, + RTCS_ModeSelect, + RTCS_IndexSelect, + RTCS_Write +}; + +enum RTC_Mode +{ + RTCM_Linear = 0x03, + RTCM_Indexed = 0x0c +}; + +class SPC7110_Decomp +{ +public: + SPC7110_Decomp(running_machine &machine); + + running_machine &machine() const { return m_machine; } + + void init(running_machine &machine, UINT8 *ROM, UINT32 len, UINT32 mode, UINT32 offset, UINT32 index); + void reset(); + + UINT8 read(UINT8 *ROM, UINT32 len); + void write(UINT8 data); + void mode0(UINT8 init, UINT8 *ROM, UINT32 len); + void mode1(UINT8 init, UINT8 *ROM, UINT32 len); + void mode2(UINT8 init, UINT8 *ROM, UINT32 len); + +private: + + UINT8 dataread(UINT8 *ROM, UINT32 len); + UINT8 probability(UINT32 n); + UINT8 next_lps(UINT32 n); + UINT8 next_mps(UINT32 n); + UINT8 toggle_invert(UINT32 n); + UINT32 morton_2x8(UINT32 data); + UINT32 morton_4x8(UINT32 data); + + UINT32 m_decomp_mode; + UINT32 m_decomp_offset; + + UINT8 *m_decomp_buffer; + UINT32 m_decomp_buffer_rdoffset; + UINT32 m_decomp_buffer_wroffset; + UINT32 m_decomp_buffer_length; + + struct ContextState + { + UINT8 index; + UINT8 invert; + } m_context[32]; + + UINT32 m_morton16[2][256]; + UINT32 m_morton32[4][256]; + + // mode 0 vars + UINT8 m_m0_val, m_m0_in, m_m0_span; + INT32 m_m0_out, m_m0_inverts, m_m0_lps, m_m0_in_count; + + // mode 1 vars + INT32 m_m1_pixelorder[4], m_m1_realorder[4]; + UINT8 m_m1_in, m_m1_val, m_m1_span; + INT32 m_m1_out, m_m1_inverts, m_m1_lps, m_m1_in_count; + + // mode 2 vars + INT32 m_m2_pixelorder[16], m_m2_realorder[16]; + UINT8 m_m2_bitplanebuffer[16], m_m2_buffer_index; + UINT8 m_m2_in, m_m2_val, m_m2_span; + INT32 m_m2_out0, m_m2_out1, m_m2_inverts, m_m2_lps, m_m2_in_count; + + running_machine& m_machine; + //UINT32 m_rom_size; +}; + +// ======================> sns_rom_spc7110_device + +class sns_rom_spc7110_device : public sns_rom21_device +{ +public: + // construction/destruction + sns_rom_spc7110_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + sns_rom_spc7110_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_l); + virtual DECLARE_READ8_MEMBER(read_h); + virtual DECLARE_READ8_MEMBER(read_ram); + virtual DECLARE_WRITE8_MEMBER(write_ram); + + virtual DECLARE_READ8_MEMBER(chip_read); + virtual DECLARE_WRITE8_MEMBER(chip_write); + + void spc7110_start(); + UINT32 spc7110_datarom_addr(UINT32 addr, UINT32 len); + UINT32 spc7110_data_pointer(); + UINT32 spc7110_data_adjust(); + UINT32 spc7110_data_increment(); + void spc7110_set_data_pointer(UINT32 addr); + void spc7110_set_data_adjust(UINT32 addr); + void spc7110_update_time(UINT8 offset); + + + //================== + //decompression unit + //================== + UINT8 m_r4801; // compression table low + UINT8 m_r4802; // compression table high + UINT8 m_r4803; // compression table bank + UINT8 m_r4804; // compression table index + UINT8 m_r4805; // decompression buffer index low + UINT8 m_r4806; // decompression buffer index high + UINT8 m_r4807; // ??? + UINT8 m_r4808; // ??? + UINT8 m_r4809; // compression length low + UINT8 m_r480a; // compression length high + UINT8 m_r480b; // decompression control register + UINT8 m_r480c; // decompression status + + SPC7110_Decomp* m_decomp; + + UINT8 m_r4811; // data pointer low + UINT8 m_r4812; // data pointer high + UINT8 m_r4813; // data pointer bank + UINT8 m_r4814; // data adjust low + UINT8 m_r4815; // data adjust high + UINT8 m_r4816; // data increment low + UINT8 m_r4817; // data increment high + UINT8 m_r4818; // data port control register + + UINT8 m_r481x; + + UINT8 m_r4814_latch; + UINT8 m_r4815_latch; + + //========= + //math unit + //========= + UINT8 m_r4820; // 16-bit multiplicand B0, 32-bit dividend B0 + UINT8 m_r4821; // 16-bit multiplicand B1, 32-bit dividend B1 + UINT8 m_r4822; // 32-bit dividend B2 + UINT8 m_r4823; // 32-bit dividend B3 + UINT8 m_r4824; // 16-bit multiplier B0 + UINT8 m_r4825; // 16-bit multiplier B1 + UINT8 m_r4826; // 16-bit divisor B0 + UINT8 m_r4827; // 16-bit divisor B1 + UINT8 m_r4828; // 32-bit product B0, 32-bit quotient B0 + UINT8 m_r4829; // 32-bit product B1, 32-bit quotient B1 + UINT8 m_r482a; // 32-bit product B2, 32-bit quotient B2 + UINT8 m_r482b; // 32-bit product B3, 32-bit quotient B3 + UINT8 m_r482c; // 16-bit remainder B0 + UINT8 m_r482d; // 16-bit remainder B1 + UINT8 m_r482e; // math control register + UINT8 m_r482f; // math status + + //=================== + //memory mapping unit + //=================== + UINT8 m_r4830; // SRAM write enable + UINT8 m_r4831; // $[d0-df]:[0000-ffff] mapping + UINT8 m_r4832; // $[e0-ef]:[0000-ffff] mapping + UINT8 m_r4833; // $[f0-ff]:[0000-ffff] mapping + UINT8 m_r4834; // ??? + + UINT32 m_dx_offset; + UINT32 m_ex_offset; + UINT32 m_fx_offset; + + //==================== + //real-time clock unit + //==================== + UINT8 m_r4840; // RTC latch + UINT8 m_r4841; // RTC index/data port + UINT8 m_r4842; // RTC status + + UINT32 m_rtc_state; + UINT32 m_rtc_mode; + UINT32 m_rtc_index; + + UINT64 m_rtc_offset; + + system_time m_rtc_basetime; + + //this is now allocated in the main snes cart class, to allow saving to nvram + //UINT8 m_rtc_ram[16]; // 0-12 secs, min, hrs, etc.; 13-14-15 control registers +}; + +// ======================> sns_rom_spc7110_device + +class sns_rom_spc7110rtc_device : public sns_rom_spc7110_device +{ +public: + // construction/destruction + sns_rom_spc7110rtc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + + // reading and writing + +// we just use the spc7110 ones for the moment, pending the split of regs 0x4840-0x4842 (RTC) from the base add-on +// virtual DECLARE_READ8_MEMBER(read_l); +// virtual DECLARE_READ8_MEMBER(read_h); + +// virtual DECLARE_READ8_MEMBER(chip_read); +// virtual DECLARE_WRITE8_MEMBER(chip_write); +}; + +// device type definition +extern const device_type SNS_HIROM_SPC7110; +extern const device_type SNS_HIROM_SPC7110_RTC; + +#endif diff --git a/src/devices/bus/snes/sufami.c b/src/devices/bus/snes/sufami.c new file mode 100644 index 00000000000..2cf4de90d6c --- /dev/null +++ b/src/devices/bus/snes/sufami.c @@ -0,0 +1,162 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + Bandai Sufami Turbo cartridge emulation (for SNES/SFC) + + This is basically a standard LoROM cart with two slots for ST minicarts + The content of each slot (with ROM and RAM) is mapped to a separate memory range + Slot 1: ROM [20-3f][8000-ffff], RAM [60-63][8000-ffff] + Slot 2: ROM [40-5f][8000-ffff], RAM [70-73][8000-ffff] + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "sufami.h" + + +//------------------------------------------------- +// sns_rom_sufami_device - constructor +//------------------------------------------------- + +const device_type SNS_LOROM_SUFAMI = &device_creator; +const device_type SNS_STROM = &device_creator; + + +sns_rom_sufami_device::sns_rom_sufami_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : sns_rom_device(mconfig, SNS_LOROM_SUFAMI, "SNES Sufami Turbo Cart", tag, owner, clock, "sns_rom_sufami", __FILE__), + m_slot1(*this, "st_slot1"), + m_slot2(*this, "st_slot2") +{ +} + +sns_rom_strom_device::sns_rom_strom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : sns_rom_device(mconfig, SNS_STROM, "SNES Sufami Turbo Minicart", tag, owner, clock, "sns_strom", __FILE__) +{ +} + + +void sns_rom_sufami_device::device_start() +{ +} + +void sns_rom_strom_device::device_start() +{ +} + +//------------------------------------------------- +// MACHINE_CONFIG_FRAGMENT( st_slot ) +//------------------------------------------------- + +static SLOT_INTERFACE_START(sufamiturbo_cart) + SLOT_INTERFACE_INTERNAL("strom", SNS_STROM) +SLOT_INTERFACE_END + +static MACHINE_CONFIG_FRAGMENT( st_slot ) + MCFG_SNS_SUFAMI_CARTRIDGE_ADD("st_slot1", sufamiturbo_cart, NULL) + MCFG_SNS_SUFAMI_CARTRIDGE_ADD("st_slot2", sufamiturbo_cart, NULL) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor sns_rom_sufami_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( st_slot ); +} + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +READ8_MEMBER(sns_rom_sufami_device::read_l) +{ + return read_h(space, offset); +} + +READ8_MEMBER(sns_rom_sufami_device::read_h) +{ + int bank; + + if (offset < 0x200000) // SUFAMI TURBO ROM + { + bank = offset / 0x10000; + return m_rom[rom_bank_map[bank] * 0x8000 + (offset & 0x7fff)]; + } + if (offset >= 0x200000 && offset < 0x400000) // SLOT1 STROM + { + return m_slot1->read_l(space, offset - 0x200000); + } + if (offset >= 0x400000 && offset < 0x600000) // SLOT2 STROM + { + return m_slot2->read_l(space, offset - 0x400000); + } + if (offset >= 0x600000 && offset < 0x640000) // SLOT1 RAM + { + if ((offset & 0xffff) >= 0x8000) + { + offset -= 0x600000; + bank = offset / 0x10000; + return m_slot1->read_ram(space, bank * 0x8000 + (offset & 0x7fff)); + } + } + if (offset >= 0x700000 && offset < 0x740000) // SLOT2 RAM + { + if ((offset & 0xffff) >= 0x8000) + { + offset -= 0x700000; + bank = offset / 0x10000; + return m_slot2->read_ram(space, bank * 0x8000 + (offset & 0x7fff)); + } + } + + return 0xff; +} + +WRITE8_MEMBER(sns_rom_sufami_device::write_l) +{ + write_h(space, offset, data); +} + +WRITE8_MEMBER(sns_rom_sufami_device::write_h) +{ + int bank; + if (offset >= 0x600000 && offset < 0x640000) // SLOT1 RAM + { + if ((offset & 0xffff) >= 0x8000) + { + offset -= 0x600000; + bank = offset / 0x10000; + m_slot1->write_ram(space, bank * 0x8000 + (offset & 0x7fff), data); + } + } + + if (offset >= 0x700000 && offset < 0x740000) // SLOT2 RAM + { + if ((offset & 0xffff) >= 0x8000) + { + offset -= 0x700000; + bank = offset / 0x10000; + m_slot2->write_ram(space, bank * 0x8000 + (offset & 0x7fff), data); + } + } + +} + +/*------------------------------------------------- + Sufami Turbo 'minicart' emulation + -------------------------------------------------*/ + +READ8_MEMBER(sns_rom_strom_device::read_l) +{ + if (offset < 0x200000) + { + int bank = offset / 0x10000; + return m_rom[rom_bank_map[bank] * 0x8000 + (offset & 0x7fff)]; + } + return 0xff; +} diff --git a/src/devices/bus/snes/sufami.h b/src/devices/bus/snes/sufami.h new file mode 100644 index 00000000000..c56f566777f --- /dev/null +++ b/src/devices/bus/snes/sufami.h @@ -0,0 +1,53 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __SNS_SUFAMI_H +#define __SNS_SUFAMI_H + +#include "snes_slot.h" +#include "rom.h" + + +// ======================> sns_rom_sufami_device + +class sns_rom_sufami_device : public sns_rom_device +{ +public: + // construction/destruction + sns_rom_sufami_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual machine_config_constructor device_mconfig_additions() const; + + // additional reading and writing + virtual DECLARE_READ8_MEMBER(read_l); + virtual DECLARE_READ8_MEMBER(read_h); + virtual DECLARE_WRITE8_MEMBER(write_l); + virtual DECLARE_WRITE8_MEMBER(write_h); + +private: + required_device m_slot1; + required_device m_slot2; +}; + +// ======================> sns_rom_strom_device + +class sns_rom_strom_device : public sns_rom_device +{ +public: + // construction/destruction + sns_rom_strom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + + // additional reading and writing + virtual DECLARE_READ8_MEMBER(read_l); +}; + + +// device type definition +extern const device_type SNS_LOROM_SUFAMI; +extern const device_type SNS_STROM; + +#endif diff --git a/src/devices/bus/snes/upd.c b/src/devices/bus/snes/upd.c new file mode 100644 index 00000000000..056f462e2fa --- /dev/null +++ b/src/devices/bus/snes/upd.c @@ -0,0 +1,566 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + UPD7725 / UPD96050 add-on chip emulation (for SNES/SFC) + used in carts with DSP-1, DSP-1A, DSP-1B, DSP-2, DSP-3, DSP-4, ST-010 & ST-011 add-on chips + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "upd.h" + + +// helpers +inline UINT32 get_prg(UINT8 *CPU, UINT32 addr) +{ + return ((CPU[addr * 4] << 24) | (CPU[addr * 4 + 1] << 16) | (CPU[addr * 4 + 2] << 8) | 0x00); +} +inline UINT16 get_data(UINT8 *CPU, UINT32 addr) +{ + return ((CPU[addr * 2] << 8) | CPU[addr * 2 + 1]); +} + +//------------------------------------------------- +// constructor +//------------------------------------------------- + +const device_type SNS_LOROM_NECDSP = &device_creator; +const device_type SNS_HIROM_NECDSP = &device_creator; +const device_type SNS_LOROM_SETA10 = &device_creator; +const device_type SNS_LOROM_SETA11 = &device_creator; + + +sns_rom20_necdsp_device::sns_rom20_necdsp_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : sns_rom_device(mconfig, type, name, tag, owner, clock, shortname, source), + m_upd7725(*this, "dsp") +{ +} + +sns_rom20_necdsp_device::sns_rom20_necdsp_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : sns_rom_device(mconfig, SNS_LOROM_NECDSP, "SNES Cart (LoROM) + NEC DSP", tag, owner, clock, "sns_rom_necdsp", __FILE__), + m_upd7725(*this, "dsp") +{ +} + +sns_rom21_necdsp_device::sns_rom21_necdsp_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : sns_rom21_device(mconfig, type, name, tag, owner, clock, shortname, source), + m_upd7725(*this, "dsp") +{ +} + +sns_rom21_necdsp_device::sns_rom21_necdsp_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : sns_rom21_device(mconfig, SNS_HIROM_NECDSP, "SNES Cart (HiROM) + NEC DSP", tag, owner, clock, "sns_rom21_necdsp", __FILE__), + m_upd7725(*this, "dsp") +{ +} + +sns_rom_setadsp_device::sns_rom_setadsp_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : sns_rom_device(mconfig, type, name, tag, owner, clock, shortname, source), + m_upd96050(*this, "dsp") +{ +} + +sns_rom_seta10dsp_device::sns_rom_seta10dsp_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : sns_rom_setadsp_device(mconfig, SNS_LOROM_SETA10, "SNES Cart (LoROM) + Seta ST010 DSP", tag, owner, clock, "sns_rom_seta10", __FILE__) +{ +} + +sns_rom_seta11dsp_device::sns_rom_seta11dsp_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : sns_rom_setadsp_device(mconfig, SNS_LOROM_SETA11, "SNES Cart (LoROM) + Seta ST011 DSP", tag, owner, clock, "sns_rom_seta11", __FILE__) +{ +} + + +void sns_rom20_necdsp_device::device_start() +{ + m_dsp_prg.resize(0x2000/sizeof(UINT32)); + m_dsp_data.resize(0x800/sizeof(UINT16)); +} + +void sns_rom21_necdsp_device::device_start() +{ + m_dsp_prg.resize(0x2000/sizeof(UINT32)); + m_dsp_data.resize(0x800/sizeof(UINT16)); +} + +void sns_rom_setadsp_device::device_start() +{ + m_dsp_prg.resize(0x10000/sizeof(UINT32)); + m_dsp_data.resize(0x1000/sizeof(UINT16)); +} + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +//------------------------------------------------- +// NEC DSP +//------------------------------------------------- + +// Lo-ROM + +// DSP dump contains prg at offset 0 and data at offset 0x2000 +READ32_MEMBER( sns_rom20_necdsp_device::necdsp_prg_r ) +{ + return get_prg(&m_bios[0], offset); +} + +READ16_MEMBER( sns_rom20_necdsp_device::necdsp_data_r ) +{ + return get_data(&m_bios[0], offset + 0x2000/2); +} + + +//------------------------------------------------- +// ADDRESS_MAP( dsp_prg_map ) +//------------------------------------------------- + +static ADDRESS_MAP_START( dsp_prg_map_lorom, AS_PROGRAM, 32, sns_rom20_necdsp_device ) + AM_RANGE(0x0000, 0x07ff) AM_READ(necdsp_prg_r) +ADDRESS_MAP_END + + +//------------------------------------------------- +// ADDRESS_MAP( dsp_data_map ) +//------------------------------------------------- + +static ADDRESS_MAP_START( dsp_data_map_lorom, AS_DATA, 16, sns_rom20_necdsp_device ) + AM_RANGE(0x0000, 0x03ff) AM_READ(necdsp_data_r) +ADDRESS_MAP_END + + +//------------------------------------------------- +// MACHINE_DRIVER( snes_dsp ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( snes_dsp_lorom ) + MCFG_CPU_ADD("dsp", UPD7725, 8000000) + MCFG_CPU_PROGRAM_MAP(dsp_prg_map_lorom) + MCFG_CPU_DATA_MAP(dsp_data_map_lorom) +MACHINE_CONFIG_END + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor sns_rom20_necdsp_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( snes_dsp_lorom ); +} + +READ8_MEMBER( sns_rom20_necdsp_device::chip_read ) +{ + offset &= 0x7fff; + return m_upd7725->snesdsp_read(offset < 0x4000); +} + + +WRITE8_MEMBER( sns_rom20_necdsp_device::chip_write ) +{ + offset &= 0x7fff; + m_upd7725->snesdsp_write(offset < 0x4000, data); +} + + +// Hi-ROM + +// DSP dump contains prg at offset 0 and data at offset 0x2000 +READ32_MEMBER( sns_rom21_necdsp_device::necdsp_prg_r ) +{ + return get_prg(&m_bios[0], offset); +} + +READ16_MEMBER( sns_rom21_necdsp_device::necdsp_data_r ) +{ + return get_data(&m_bios[0], offset + 0x2000/2); +} + + +//------------------------------------------------- +// ADDRESS_MAP( dsp_prg_map ) +//------------------------------------------------- + +static ADDRESS_MAP_START( dsp_prg_map_hirom, AS_PROGRAM, 32, sns_rom21_necdsp_device ) + AM_RANGE(0x0000, 0x07ff) AM_READ(necdsp_prg_r) +ADDRESS_MAP_END + + +//------------------------------------------------- +// ADDRESS_MAP( dsp_data_map ) +//------------------------------------------------- + +static ADDRESS_MAP_START( dsp_data_map_hirom, AS_DATA, 16, sns_rom21_necdsp_device ) + AM_RANGE(0x0000, 0x03ff) AM_READ(necdsp_data_r) +ADDRESS_MAP_END + + +//------------------------------------------------- +// MACHINE_DRIVER( snes_dsp ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( snes_dsp_hirom ) + MCFG_CPU_ADD("dsp", UPD7725, 8000000) + MCFG_CPU_PROGRAM_MAP(dsp_prg_map_hirom) + MCFG_CPU_DATA_MAP(dsp_data_map_hirom) +MACHINE_CONFIG_END + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor sns_rom21_necdsp_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( snes_dsp_hirom ); +} + +READ8_MEMBER( sns_rom21_necdsp_device::chip_read ) +{ + offset &= 0x1fff; + return m_upd7725->snesdsp_read(offset < 0x1000); +} + + +WRITE8_MEMBER( sns_rom21_necdsp_device::chip_write ) +{ + offset &= 0x1fff; + m_upd7725->snesdsp_write(offset < 0x1000, data); +} + + +//------------------------------------------------- +// Seta DSP +//------------------------------------------------- + +// same as above but additional read/write handling for the add-on chip + +READ8_MEMBER( sns_rom_setadsp_device::chip_read ) +{ + if (offset >= 0x600000 && offset < 0x680000 && (offset & 0xffff) < 0x4000) + m_upd96050->snesdsp_read((offset & 0x01) ? FALSE : TRUE); + + if (offset >= 0x680000 && offset < 0x700000 && (offset & 0xffff) < 0x8000) + { + UINT16 address = offset & 0xffff; + UINT16 temp = m_upd96050->dataram_r(address/2); + if (offset & 1) + return temp >> 8; + else + return temp & 0xff; + } + + return 0xff; +} + + +WRITE8_MEMBER( sns_rom_setadsp_device::chip_write ) +{ + if (offset >= 0x600000 && offset < 0x680000 && (offset & 0xffff) < 0x4000) + { + m_upd96050->snesdsp_write((offset & 0x01) ? FALSE : TRUE, data); + return; + } + + if (offset >= 0x680000 && offset < 0x700000 && (offset & 0xffff) < 0x8000) + { + UINT16 address = offset & 0xffff; + UINT16 temp = m_upd96050->dataram_r(address/2); + + if (offset & 1) + { + temp &= 0xff; + temp |= data << 8; + } + else + { + temp &= 0xff00; + temp |= data; + } + + m_upd96050->dataram_w(address/2, temp); + return; + } +} + + +// DSP dump contains prg at offset 0 and data at offset 0x10000 +READ32_MEMBER( sns_rom_setadsp_device::setadsp_prg_r ) +{ + return get_prg(&m_bios[0], offset); +} + +READ16_MEMBER( sns_rom_setadsp_device::setadsp_data_r ) +{ + return get_data(&m_bios[0], offset + 0x10000/2); +} + + +//------------------------------------------------- +// ADDRESS_MAP( st01x_prg_map ) +//------------------------------------------------- + +static ADDRESS_MAP_START( st01x_prg_map, AS_PROGRAM, 32, sns_rom_setadsp_device ) + AM_RANGE(0x0000, 0x3fff) AM_READ(setadsp_prg_r) +ADDRESS_MAP_END + + +//------------------------------------------------- +// ADDRESS_MAP( st01x_data_map ) +//------------------------------------------------- + +static ADDRESS_MAP_START( st01x_data_map, AS_DATA, 16, sns_rom_setadsp_device ) + AM_RANGE(0x0000, 0x07ff) AM_READ(setadsp_data_r) +ADDRESS_MAP_END + + +//------------------------------------------------- +// MACHINE_DRIVER( snes_st010 ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( snes_st010 ) + MCFG_CPU_ADD("dsp", UPD96050, 10000000) + MCFG_CPU_PROGRAM_MAP(st01x_prg_map) + MCFG_CPU_DATA_MAP(st01x_data_map) +MACHINE_CONFIG_END + +//------------------------------------------------- +// MACHINE_DRIVER( snes_st011 ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( snes_st011 ) + MCFG_CPU_ADD("dsp", UPD96050, 15000000) + MCFG_CPU_PROGRAM_MAP(st01x_prg_map) + MCFG_CPU_DATA_MAP(st01x_data_map) +MACHINE_CONFIG_END + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor sns_rom_seta10dsp_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( snes_st010 ); +} + +machine_config_constructor sns_rom_seta11dsp_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( snes_st011 ); +} + + +// To make faster DSP access to its internal rom, let's install read banks and map m_bios there with correct byte order + +void sns_rom20_necdsp_device::speedup_addon_bios_access() +{ + m_upd7725->space(AS_PROGRAM).install_read_bank(0x0000, 0x07ff, "dsp_prg"); + m_upd7725->space(AS_DATA).install_read_bank(0x0000, 0x03ff, "dsp_data"); + membank("dsp_prg")->set_base(&m_dsp_prg[0]); + membank("dsp_data")->set_base(&m_dsp_data[0]); + // copy data in the correct format + for (int x = 0; x < 0x800; x++) + m_dsp_prg[x] = (m_bios[x * 4] << 24) | (m_bios[x * 4 + 1] << 16) | (m_bios[x * 4 + 2] << 8) | 0x00; + for (int x = 0; x < 0x400; x++) + m_dsp_data[x] = (m_bios[0x2000 + x * 2] << 8) | m_bios[0x2000 + x * 2 + 1]; +} + +void sns_rom21_necdsp_device::speedup_addon_bios_access() +{ + m_upd7725->space(AS_PROGRAM).install_read_bank(0x0000, 0x07ff, "dsp_prg"); + m_upd7725->space(AS_DATA).install_read_bank(0x0000, 0x03ff, "dsp_data"); + membank("dsp_prg")->set_base(&m_dsp_prg[0]); + membank("dsp_data")->set_base(&m_dsp_data[0]); + // copy data in the correct format + for (int x = 0; x < 0x800; x++) + m_dsp_prg[x] = (m_bios[x * 4] << 24) | (m_bios[x * 4 + 1] << 16) | (m_bios[x * 4 + 2] << 8) | 0x00; + for (int x = 0; x < 0x400; x++) + m_dsp_data[x] = (m_bios[0x2000 + x * 2] << 8) | m_bios[0x2000 + x * 2 + 1]; +} + +void sns_rom_setadsp_device::speedup_addon_bios_access() +{ + m_upd96050->space(AS_PROGRAM).install_read_bank(0x0000, 0x3fff, "dsp_prg"); + m_upd96050->space(AS_DATA).install_read_bank(0x0000, 0x07ff, "dsp_data"); + membank("dsp_prg")->set_base(&m_dsp_prg[0]); + membank("dsp_data")->set_base(&m_dsp_data[0]); + // copy data in the correct format + for (int x = 0; x < 0x3fff; x++) + m_dsp_prg[x] = (m_bios[x * 4] << 24) | (m_bios[x * 4 + 1] << 16) | (m_bios[x * 4 + 2] << 8) | 0x00; + for (int x = 0; x < 0x07ff; x++) + m_dsp_data[x] = (m_bios[0x10000 + x * 2] << 8) | m_bios[0x10000 + x * 2 + 1]; +} + + + + +// Legacy versions including DSP dump roms, in order to support faulty dumps missing DSP data... + +const device_type SNS_LOROM_NECDSP1_LEG = &device_creator; +const device_type SNS_LOROM_NECDSP1B_LEG = &device_creator; +const device_type SNS_LOROM_NECDSP2_LEG = &device_creator; +const device_type SNS_LOROM_NECDSP3_LEG = &device_creator; +const device_type SNS_LOROM_NECDSP4_LEG = &device_creator; +const device_type SNS_HIROM_NECDSP1_LEG = &device_creator; +const device_type SNS_LOROM_SETA10_LEG = &device_creator; +const device_type SNS_LOROM_SETA11_LEG = &device_creator; + + +sns_rom20_necdsp1_legacy_device::sns_rom20_necdsp1_legacy_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : sns_rom20_necdsp_device(mconfig, SNS_LOROM_NECDSP1_LEG, "SNES Cart (LoROM) + NEC DSP1 Legacy", tag, owner, clock, "dsp1leg", __FILE__) +{ +} + +sns_rom20_necdsp1b_legacy_device::sns_rom20_necdsp1b_legacy_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : sns_rom20_necdsp_device(mconfig, SNS_LOROM_NECDSP1B_LEG, "SNES Cart (LoROM) + NEC DSP1B Legacy", tag, owner, clock, "dsp1bleg", __FILE__) +{ +} + +sns_rom20_necdsp2_legacy_device::sns_rom20_necdsp2_legacy_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : sns_rom20_necdsp_device(mconfig, SNS_LOROM_NECDSP2_LEG, "SNES Cart (LoROM) + NEC DSP2 Legacy", tag, owner, clock, "dsp2leg", __FILE__) +{ +} + +sns_rom20_necdsp3_legacy_device::sns_rom20_necdsp3_legacy_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : sns_rom20_necdsp_device(mconfig, SNS_LOROM_NECDSP3_LEG, "SNES Cart (LoROM) + NEC DSP3 Legacy", tag, owner, clock, "dsp3leg", __FILE__) +{ +} + +sns_rom20_necdsp4_legacy_device::sns_rom20_necdsp4_legacy_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : sns_rom20_necdsp_device(mconfig, SNS_LOROM_NECDSP4_LEG, "SNES Cart (LoROM) + NEC DSP4 Legacy", tag, owner, clock, "dsp4leg", __FILE__) +{ +} + +sns_rom21_necdsp1_legacy_device::sns_rom21_necdsp1_legacy_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : sns_rom21_necdsp_device(mconfig, SNS_HIROM_NECDSP1_LEG, "SNES Cart (HiROM) + NEC DSP1 Legacy", tag, owner, clock, "dsp1leg_hi", __FILE__) +{ +} + +sns_rom_seta10dsp_legacy_device::sns_rom_seta10dsp_legacy_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : sns_rom_setadsp_device(mconfig, SNS_LOROM_SETA10_LEG, "SNES Cart (LoROM) + Seta ST010 DSP Legacy", tag, owner, clock, "seta10leg", __FILE__) +{ +} + +sns_rom_seta11dsp_legacy_device::sns_rom_seta11dsp_legacy_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : sns_rom_setadsp_device(mconfig, SNS_LOROM_SETA11_LEG, "SNES Cart (LoROM) + Seta ST011 DSP Legacy", tag, owner, clock, "seta11leg", __FILE__) +{ +} + + +machine_config_constructor sns_rom20_necdsp1_legacy_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( snes_dsp_lorom ); +} + +machine_config_constructor sns_rom20_necdsp1b_legacy_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( snes_dsp_lorom ); +} + +machine_config_constructor sns_rom20_necdsp2_legacy_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( snes_dsp_lorom ); +} + +machine_config_constructor sns_rom20_necdsp3_legacy_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( snes_dsp_lorom ); +} + +machine_config_constructor sns_rom20_necdsp4_legacy_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( snes_dsp_lorom ); +} + +machine_config_constructor sns_rom21_necdsp1_legacy_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( snes_dsp_hirom ); +} + +machine_config_constructor sns_rom_seta10dsp_legacy_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( snes_st010 ); +} + +machine_config_constructor sns_rom_seta11dsp_legacy_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( snes_st011 ); +} + + +ROM_START( snes_dsp1 ) + ROM_REGION(0x2800, "addon", 0) + ROM_LOAD( "dsp1.bin", 0, 0x02800, CRC(2838f9f5) SHA1(0a03ccb1fd2bea91151c745a4d1f217ae784f889) ) +ROM_END + +ROM_START( snes_dsp1b ) + ROM_REGION(0x2800, "addon", 0) + ROM_LOAD( "dsp1b.bin", 0, 0x02800, CRC(453557e0) SHA1(3a218b0e4572a8eba6d0121b17fdac9529609220) ) +ROM_END + +ROM_START( snes_dsp2 ) + ROM_REGION(0x2800, "addon", 0) + ROM_LOAD( "dsp2.bin", 0, 0x02800, CRC(8e9fbd9b) SHA1(06dd9fcb118d18f6bbe234e013cb8780e06d6e63) ) +ROM_END + +ROM_START( snes_dsp3 ) + ROM_REGION(0x2800, "addon", 0) + ROM_LOAD( "dsp3.bin", 0, 0x02800, CRC(6b86728a) SHA1(1b133741fad810eb7320c21ecfdd427d25a46da1) ) +ROM_END + +ROM_START( snes_dsp4 ) + ROM_REGION(0x2800, "addon", 0) + ROM_LOAD( "dsp4.bin", 0, 0x02800, CRC(ce0c7783) SHA1(76fd25f7dc26c3b3f7868a3aa78c7684068713e5) ) +ROM_END + +ROM_START( snes_st010 ) + ROM_REGION(0x11000, "addon", 0) + ROM_LOAD( "st010.bin", 0, 0x11000, CRC(aa11ee2d) SHA1(cc1984e989cb94e3dcbb5f99e085b5414e18a017) ) +ROM_END + +ROM_START( snes_st011 ) + ROM_REGION(0x11000, "addon", 0) + ROM_LOAD( "st011.bin", 0, 0x11000, CRC(34d2952c) SHA1(1375b8c1efc8cae4962b57dfe22f6b78e1ddacc8) ) +ROM_END + +const rom_entry *sns_rom20_necdsp1_legacy_device::device_rom_region() const +{ + return ROM_NAME( snes_dsp1 ); +} + +const rom_entry *sns_rom20_necdsp1b_legacy_device::device_rom_region() const +{ + return ROM_NAME( snes_dsp1b ); +} + +const rom_entry *sns_rom20_necdsp2_legacy_device::device_rom_region() const +{ + return ROM_NAME( snes_dsp2 ); +} + +const rom_entry *sns_rom20_necdsp3_legacy_device::device_rom_region() const +{ + return ROM_NAME( snes_dsp3 ); +} + +const rom_entry *sns_rom20_necdsp4_legacy_device::device_rom_region() const +{ + return ROM_NAME( snes_dsp4 ); +} + +const rom_entry *sns_rom21_necdsp1_legacy_device::device_rom_region() const +{ + return ROM_NAME( snes_dsp1 ); +} + +const rom_entry *sns_rom_seta10dsp_legacy_device::device_rom_region() const +{ + return ROM_NAME( snes_st010 ); +} + +const rom_entry *sns_rom_seta11dsp_legacy_device::device_rom_region() const +{ + return ROM_NAME( snes_st011 ); +} diff --git a/src/devices/bus/snes/upd.h b/src/devices/bus/snes/upd.h new file mode 100644 index 00000000000..28fdf077f11 --- /dev/null +++ b/src/devices/bus/snes/upd.h @@ -0,0 +1,223 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __SNS_UPD_H +#define __SNS_UPD_H + +#include "snes_slot.h" +#include "rom.h" +#include "rom21.h" +#include "cpu/upd7725/upd7725.h" + +// ======================> sns_rom_necdsp_device + +class sns_rom20_necdsp_device : public sns_rom_device +{ +public: + // construction/destruction + sns_rom20_necdsp_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + sns_rom20_necdsp_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual machine_config_constructor device_mconfig_additions() const; + virtual void speedup_addon_bios_access(); + + required_device m_upd7725; + + // additional reading and writing + virtual DECLARE_READ8_MEMBER(chip_read); + virtual DECLARE_WRITE8_MEMBER(chip_write); + + virtual DECLARE_READ32_MEMBER(necdsp_prg_r); + virtual DECLARE_READ16_MEMBER(necdsp_data_r); + + std::vector m_dsp_prg; + std::vector m_dsp_data; +}; + +// ======================> sns_rom21_necdsp_device + +class sns_rom21_necdsp_device : public sns_rom21_device +{ +public: + // construction/destruction + sns_rom21_necdsp_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + sns_rom21_necdsp_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual machine_config_constructor device_mconfig_additions() const; + virtual void speedup_addon_bios_access(); + + required_device m_upd7725; + + // additional reading and writing + virtual DECLARE_READ8_MEMBER(chip_read); + virtual DECLARE_WRITE8_MEMBER(chip_write); + + virtual DECLARE_READ32_MEMBER(necdsp_prg_r); + virtual DECLARE_READ16_MEMBER(necdsp_data_r); + + std::vector m_dsp_prg; + std::vector m_dsp_data; +}; + +// ======================> sns_rom_setadsp_device + +class sns_rom_setadsp_device : public sns_rom_device +{ +public: + // construction/destruction + sns_rom_setadsp_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + // device-level overrides + virtual void device_start(); + virtual void speedup_addon_bios_access(); + + required_device m_upd96050; + + // additional reading and writing + virtual DECLARE_READ8_MEMBER(chip_read); + virtual DECLARE_WRITE8_MEMBER(chip_write); + + virtual DECLARE_READ32_MEMBER(setadsp_prg_r); + virtual DECLARE_READ16_MEMBER(setadsp_data_r); + + std::vector m_dsp_prg; + std::vector m_dsp_data; +}; + +// ======================> sns_rom_seta10dsp_device + +class sns_rom_seta10dsp_device : public sns_rom_setadsp_device +{ +public: + // construction/destruction + sns_rom_seta10dsp_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual machine_config_constructor device_mconfig_additions() const; +}; + +// ======================> sns_rom_seta11dsp_device [Faster CPU than ST010] + +class sns_rom_seta11dsp_device : public sns_rom_setadsp_device +{ +public: + // construction/destruction + sns_rom_seta11dsp_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual machine_config_constructor device_mconfig_additions() const; +}; + + +// device type definition +extern const device_type SNS_LOROM_NECDSP; +extern const device_type SNS_HIROM_NECDSP; +extern const device_type SNS_LOROM_SETA10; +extern const device_type SNS_LOROM_SETA11; + + + + +// Devices including DSP dumps to support faulty .sfc dumps missing DSP data + +class sns_rom20_necdsp1_legacy_device : public sns_rom20_necdsp_device +{ +public: + // construction/destruction + sns_rom20_necdsp1_legacy_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual const rom_entry *device_rom_region() const; +}; + +class sns_rom20_necdsp1b_legacy_device : public sns_rom20_necdsp_device +{ +public: + // construction/destruction + sns_rom20_necdsp1b_legacy_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual const rom_entry *device_rom_region() const; +}; + +class sns_rom20_necdsp2_legacy_device : public sns_rom20_necdsp_device +{ +public: + // construction/destruction + sns_rom20_necdsp2_legacy_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual const rom_entry *device_rom_region() const; +}; + +class sns_rom20_necdsp3_legacy_device : public sns_rom20_necdsp_device +{ +public: + // construction/destruction + sns_rom20_necdsp3_legacy_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual const rom_entry *device_rom_region() const; +}; + +class sns_rom20_necdsp4_legacy_device : public sns_rom20_necdsp_device +{ +public: + // construction/destruction + sns_rom20_necdsp4_legacy_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual const rom_entry *device_rom_region() const; +}; + +class sns_rom21_necdsp1_legacy_device : public sns_rom21_necdsp_device +{ +public: + // construction/destruction + sns_rom21_necdsp1_legacy_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual const rom_entry *device_rom_region() const; +}; + +class sns_rom_seta10dsp_legacy_device : public sns_rom_setadsp_device +{ +public: + // construction/destruction + sns_rom_seta10dsp_legacy_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual const rom_entry *device_rom_region() const; +}; + +class sns_rom_seta11dsp_legacy_device : public sns_rom_setadsp_device +{ +public: + // construction/destruction + sns_rom_seta11dsp_legacy_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual const rom_entry *device_rom_region() const; +}; + +extern const device_type SNS_LOROM_NECDSP1_LEG; +extern const device_type SNS_LOROM_NECDSP1B_LEG; +extern const device_type SNS_LOROM_NECDSP2_LEG; +extern const device_type SNS_LOROM_NECDSP3_LEG; +extern const device_type SNS_LOROM_NECDSP4_LEG; +extern const device_type SNS_HIROM_NECDSP1_LEG; +extern const device_type SNS_LOROM_SETA10_LEG; +extern const device_type SNS_LOROM_SETA11_LEG; + +#endif diff --git a/src/devices/bus/snes_ctrl/bcbattle.c b/src/devices/bus/snes_ctrl/bcbattle.c new file mode 100644 index 00000000000..5d332c4885e --- /dev/null +++ b/src/devices/bus/snes_ctrl/bcbattle.c @@ -0,0 +1,212 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/********************************************************************** + + Nintendo Super Famicom - Epoch Barcode Battler + + TODO: this should be actually emulated as a standalone system with + a few 7segments LEDs, once we get a dump of its BIOS + At the moment we only emulated the connection with a Super Famicom + +**********************************************************************/ + +#include "bcbattle.h" + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type SNES_BARCODE_BATTLER = &device_creator; + + +MACHINE_CONFIG_FRAGMENT( snes_battler ) + MCFG_BARCODE_READER_ADD("battler") +MACHINE_CONFIG_END + +machine_config_constructor snes_bcbattle_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( snes_battler ); +} + + +//------------------------------------------------- +// device_timer - handler timer events +//------------------------------------------------- + +// This part is the hacky replacement for the real Barcode unit [shared with NES implementation]: +// code periodically checks whether a new code has been scanned and it moves it to the +// m_current_barcode array +void snes_bcbattle_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + if (id == TIMER_BATTLER) + { + int old = m_new_code; + m_new_code = m_reader->get_pending_code(); + // has something new been scanned? + if (old < m_new_code) + { + if (m_reader->get_byte_length() == 13) + { + for (int i = 0; i < 13; i++) + m_current_barcode[i] = m_reader->read_code() + '0'; + } + else if (m_reader->get_byte_length() == 8) + { + for (int i = 0; i < 5; i++) + m_current_barcode[i] = 0x20; + for (int i = 5; i < 13; i++) + m_current_barcode[i] = m_reader->read_code() + '0'; + } + // read one more, to reset the internal byte counter + m_reader->read_code(); + + // the string "SUNSOFT" is accepted as well by Barcode World + m_current_barcode[13] = 'E'; + m_current_barcode[14] = 'P'; + m_current_barcode[15] = 'O'; + m_current_barcode[16] = 'C'; + m_current_barcode[17] = 'H'; + m_current_barcode[18] = 0x0d; + m_current_barcode[19] = 0x0a; + m_pending_code = 1; + } + } +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// snes_bcbattle_device - constructor +//------------------------------------------------- + +snes_bcbattle_device::snes_bcbattle_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, SNES_BARCODE_BATTLER, "Epoch Barcode Battler (SFC)", tag, owner, clock, "snes_bcbattle", __FILE__), + device_snes_control_port_interface(mconfig, *this), + m_reader(*this, "battler") +{ +} + + +//------------------------------------------------- +// device_start +//------------------------------------------------- + +void snes_bcbattle_device::device_start() +{ + // lacking emulation of the standalone Barcode Battler, we refresh periodically the input from the reader + // proper emulation would have the standalone unit acknowledging that a new barcode has been scanned + // and sending the proper serial bits, instead of our read_current_bit() function! + battler_timer = timer_alloc(TIMER_BATTLER); + battler_timer->adjust(attotime::zero, 0, machine().device("maincpu")->cycles_to_attotime(1000)); + + save_item(NAME(m_current_barcode)); + save_item(NAME(m_new_code)); + save_item(NAME(m_pending_code)); + save_item(NAME(m_transmitting)); + save_item(NAME(m_cur_bit)); + save_item(NAME(m_cur_byte)); +} + + +//------------------------------------------------- +// device_reset +//------------------------------------------------- + +void snes_bcbattle_device::device_reset() +{ + m_pending_code = 0; + m_new_code = 0; + m_transmitting = 0; + m_cur_bit = 0; + m_cur_byte = 0; + memset(m_current_barcode, 0, ARRAY_LENGTH(m_current_barcode)); +} + + +//------------------------------------------------- +// read +//------------------------------------------------- + +int snes_bcbattle_device::read_current_bit() +{ + if (m_pending_code) + { + if (m_cur_bit < 4) + { + int bit = BIT(m_current_barcode[m_cur_byte], m_cur_bit - 1); + m_cur_bit++; + return bit; + } + if (m_cur_bit == 4) // only the low nibble is transmitted (this is the main action of the BBII interface for SNES) + { + m_cur_bit = 0; + //printf("%X ", m_current_barcode[m_cur_byte]); + m_cur_byte++; + if (m_cur_byte == 13) + { + m_cur_byte = 0; + m_pending_code = 0; + } + return 0; + } + } + + return 0; +} + + +//------------------------------------------------- +// poll +//------------------------------------------------- + +void snes_bcbattle_device::port_poll() +{ + m_idx = 0; +} + + +//------------------------------------------------- +// read +//------------------------------------------------- + +UINT8 snes_bcbattle_device::read_pin4() +{ + UINT8 ret = 0; + + if (m_idx >= 80) + ret |= 0x00; + else if (m_idx >= 28) // scan actual barcode + { + ret |= read_current_bit(); // if no code is pending transmission, the function returns 0 + m_idx++; + } + else if (m_idx >= 25) // unknown flags? + m_idx++; + else if (m_idx == 24) // barcode present + { + ret |= m_pending_code; + m_idx++; + } + else if (m_idx >= 12) // controller ID + ret |= BIT(0x7000, m_idx++); + else // first 12 bytes are unknown and probably always 0 + m_idx++; + + return ret; +} + + +//------------------------------------------------- +// write +//------------------------------------------------- + +void snes_bcbattle_device::write_strobe(UINT8 data) +{ + int old = m_strobe; + m_strobe = data & 0x01; + + if (m_strobe < old) // 1 -> 0 transition + port_poll(); +} diff --git a/src/devices/bus/snes_ctrl/bcbattle.h b/src/devices/bus/snes_ctrl/bcbattle.h new file mode 100644 index 00000000000..120c289c894 --- /dev/null +++ b/src/devices/bus/snes_ctrl/bcbattle.h @@ -0,0 +1,60 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/********************************************************************** + + Nintendo Super Famicom - Epoch Barcode Battler + +**********************************************************************/ + +#pragma once + +#ifndef __SNES_BCBATTLE__ +#define __SNES_BCBATTLE__ + + +#include "emu.h" +#include "ctrl.h" +#include "machine/bcreader.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> snes_bcbattle_device + +class snes_bcbattle_device : public device_t, + public device_snes_control_port_interface +{ +public: + // construction/destruction + snes_bcbattle_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + virtual machine_config_constructor device_mconfig_additions() const; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + virtual UINT8 read_pin4(); + virtual void write_strobe(UINT8 data); + virtual void port_poll(); + + int read_current_bit(); + +private: + + static const device_timer_id TIMER_BATTLER = 1; + required_device m_reader; + UINT8 m_current_barcode[20]; + int m_pending_code, m_new_code, m_transmitting, m_cur_bit, m_cur_byte; + emu_timer *battler_timer; + + int m_strobe, m_idx; +}; + +// device type definition +extern const device_type SNES_BARCODE_BATTLER; + +#endif diff --git a/src/devices/bus/snes_ctrl/ctrl.c b/src/devices/bus/snes_ctrl/ctrl.c new file mode 100644 index 00000000000..ccd05ec8cf9 --- /dev/null +++ b/src/devices/bus/snes_ctrl/ctrl.c @@ -0,0 +1,136 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/********************************************************************** + + Nintendo Super Famicom & SNES controller port emulation + +**********************************************************************/ + +#include "ctrl.h" +// slot devices +#include "bcbattle.h" +#include "joypad.h" +#include "miracle.h" +#include "mouse.h" +#include "multitap.h" +#include "pachinko.h" +#include "sscope.h" +#include "twintap.h" + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type SNES_CONTROL_PORT = &device_creator; + + +//************************************************************************** +// CARD INTERFACE +//************************************************************************** + +//------------------------------------------------- +// device_snes_control_port_interface - constructor +//------------------------------------------------- + +device_snes_control_port_interface::device_snes_control_port_interface(const machine_config &mconfig, device_t &device) + : device_slot_card_interface(mconfig,device) +{ + m_port = dynamic_cast(device.owner()); +} + + +//------------------------------------------------- +// ~device_snes_control_port_interface - destructor +//------------------------------------------------- + +device_snes_control_port_interface::~device_snes_control_port_interface() +{ +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// snes_control_port_device - constructor +//------------------------------------------------- + +snes_control_port_device::snes_control_port_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, SNES_CONTROL_PORT, "Nintendo SNES / SFC control port", tag, owner, clock, "snes_control_port", __FILE__), + device_slot_interface(mconfig, *this) +{ +} + + +//------------------------------------------------- +// snes_control_port_device - destructor +//------------------------------------------------- + +snes_control_port_device::~snes_control_port_device() +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void snes_control_port_device::device_start() +{ + m_device = dynamic_cast(get_card_device()); + m_onscreen_cb.bind_relative_to(*owner()); + m_gunlatch_cb.bind_relative_to(*owner()); +} + + +UINT8 snes_control_port_device::read_pin4() +{ + UINT8 data = 0; + if (m_device) + data |= m_device->read_pin4(); + return data; +} + +UINT8 snes_control_port_device::read_pin5() +{ + UINT8 data = 0; + if (m_device) + data |= m_device->read_pin5(); + return data; +} + +void snes_control_port_device::write_strobe(UINT8 data) +{ + if (m_device) + m_device->write_strobe(data); +} + +void snes_control_port_device::write_pin6(UINT8 data) +{ + if (m_device) + m_device->write_pin6(data); +} + +void snes_control_port_device::port_poll() +{ + if (m_device) + m_device->port_poll(); +} + + +//------------------------------------------------- +// SLOT_INTERFACE( snes_control_port_devices ) +//------------------------------------------------- + +SLOT_INTERFACE_START( snes_control_port_devices ) + SLOT_INTERFACE("joypad", SNES_JOYPAD) + SLOT_INTERFACE("mouse", SNES_MOUSE) + SLOT_INTERFACE("multitap", SNES_MULTITAP) + SLOT_INTERFACE("pachinko", SNES_PACHINKO) + SLOT_INTERFACE("sscope", SNES_SUPERSCOPE) + SLOT_INTERFACE("twintap", SNES_TWINTAP) + SLOT_INTERFACE("barcode_battler", SNES_BARCODE_BATTLER) + SLOT_INTERFACE("miracle_piano", SNES_MIRACLE) +SLOT_INTERFACE_END diff --git a/src/devices/bus/snes_ctrl/ctrl.h b/src/devices/bus/snes_ctrl/ctrl.h new file mode 100644 index 00000000000..d2ef092e4e7 --- /dev/null +++ b/src/devices/bus/snes_ctrl/ctrl.h @@ -0,0 +1,100 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/********************************************************************** + + Nintendo Super Famicom & SNES controller port emulation + +**********************************************************************/ + + +#pragma once + +#ifndef __SNES_CONTROL_PORT__ +#define __SNES_CONTROL_PORT__ + +#include "emu.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class snes_control_port_device; + +// ======================> device_snes_control_port_interface + +class device_snes_control_port_interface : public device_slot_card_interface +{ +public: + // construction/destruction + device_snes_control_port_interface(const machine_config &mconfig, device_t &device); + virtual ~device_snes_control_port_interface(); + + virtual UINT8 read_pin4() { return 0; }; + virtual UINT8 read_pin5() { return 0; }; + virtual void write_pin6(UINT8 data) { }; + virtual void write_strobe(UINT8 data) { }; + virtual void port_poll() { }; + +protected: + snes_control_port_device *m_port; +}; + +typedef device_delegate snesctrl_onscreen_delegate; +#define SNESCTRL_ONSCREEN_CB(name) bool name(INT16 x, INT16 y) + +typedef device_delegate snesctrl_gunlatch_delegate; +#define SNESCTRL_GUNLATCH_CB(name) void name(INT16 x, INT16 y) + +// ======================> snes_control_port_device + +class snes_control_port_device : public device_t, + public device_slot_interface +{ +public: + // construction/destruction + snes_control_port_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual ~snes_control_port_device(); + + static void set_onscreen_callback(device_t &device, snesctrl_onscreen_delegate callback) { downcast(device).m_onscreen_cb = callback; } + static void set_gunlatch_callback(device_t &device, snesctrl_gunlatch_delegate callback) { downcast(device).m_gunlatch_cb = callback; } + + UINT8 read_pin4(); + UINT8 read_pin5(); + void write_pin6(UINT8 data); + void write_strobe(UINT8 data); + void port_poll(); + + snesctrl_onscreen_delegate m_onscreen_cb; + snesctrl_gunlatch_delegate m_gunlatch_cb; + +protected: + // device-level overrides + virtual void device_start(); + + device_snes_control_port_interface *m_device; +}; + + +// device type definition +extern const device_type SNES_CONTROL_PORT; + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_SNES_CONTROL_PORT_ADD(_tag, _slot_intf, _def_slot) \ + MCFG_DEVICE_ADD(_tag, SNES_CONTROL_PORT, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) + +#define MCFG_SNESCTRL_ONSCREEN_CB(_class, _method) \ + snes_control_port_device::set_onscreen_callback(*device, snesctrl_onscreen_delegate(&_class::_method, #_class "::" #_method, downcast<_class *>(owner))); + +#define MCFG_SNESCTRL_GUNLATCH_CB(_class, _method) \ + snes_control_port_device::set_gunlatch_callback(*device, snesctrl_gunlatch_delegate(&_class::_method, #_class "::" #_method, downcast<_class *>(owner))); + + +SLOT_INTERFACE_EXTERN( snes_control_port_devices ); + + +#endif diff --git a/src/devices/bus/snes_ctrl/joypad.c b/src/devices/bus/snes_ctrl/joypad.c new file mode 100644 index 00000000000..6c638a321b8 --- /dev/null +++ b/src/devices/bus/snes_ctrl/joypad.c @@ -0,0 +1,125 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/********************************************************************** + + Nintendo Super Famicom & SNES Joypad + +**********************************************************************/ + +#include "joypad.h" + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type SNES_JOYPAD = &device_creator; + + +static INPUT_PORTS_START( snes_joypad ) + PORT_START("JOYPAD") + PORT_BIT( 0x0001, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("B") + PORT_BIT( 0x0002, IP_ACTIVE_HIGH, IPT_BUTTON4 ) PORT_NAME("Y") + PORT_BIT( 0x0004, IP_ACTIVE_HIGH, IPT_SELECT ) PORT_NAME("Select") + PORT_BIT( 0x0008, IP_ACTIVE_HIGH, IPT_START1 ) PORT_NAME("Start") + PORT_BIT( 0x0010, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP ) + PORT_BIT( 0x0020, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN ) + PORT_BIT( 0x0040, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT ) + PORT_BIT( 0x0080, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT ) + PORT_BIT( 0x0100, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_NAME("A") + PORT_BIT( 0x0200, IP_ACTIVE_HIGH, IPT_BUTTON5 ) PORT_NAME("X") + PORT_BIT( 0x0400, IP_ACTIVE_HIGH, IPT_BUTTON6 ) PORT_NAME("L") + PORT_BIT( 0x0800, IP_ACTIVE_HIGH, IPT_BUTTON3 ) PORT_NAME("R") + PORT_BIT( 0xf000, IP_ACTIVE_HIGH, IPT_UNUSED ) +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor snes_joypad_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( snes_joypad ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// snes_joypad_device - constructor +//------------------------------------------------- + +snes_joypad_device::snes_joypad_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, SNES_JOYPAD, "Nintendo SNES / SFC Control Pad", tag, owner, clock, "snes_joypad", __FILE__), + device_snes_control_port_interface(mconfig, *this), + m_joypad(*this, "JOYPAD") +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void snes_joypad_device::device_start() +{ + save_item(NAME(m_latch)); + save_item(NAME(m_strobe)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void snes_joypad_device::device_reset() +{ + m_latch = 0; + m_strobe = 0; +} + + +//------------------------------------------------- +// poll +//------------------------------------------------- + +void snes_joypad_device::port_poll() +{ + UINT16 temp = m_joypad->read(); + // avoid sending signals that could crash games + // if left, no right + if (temp & 0x40) + temp &= ~0x80; + // if up, no down + if (temp & 0x10) + temp &= ~0x20; + + m_latch = temp | 0xffff0000; +} + +//------------------------------------------------- +// read +//------------------------------------------------- + +UINT8 snes_joypad_device::read_pin4() +{ + UINT8 ret = m_latch & 1; + m_latch >>= 1; + return ret; +} + +//------------------------------------------------- +// write +//------------------------------------------------- + +void snes_joypad_device::write_strobe(UINT8 data) +{ + int old = m_strobe; + m_strobe = data & 0x01; + + if (m_strobe < old) // 1 -> 0 transition + port_poll(); +} diff --git a/src/devices/bus/snes_ctrl/joypad.h b/src/devices/bus/snes_ctrl/joypad.h new file mode 100644 index 00000000000..2133f396d0f --- /dev/null +++ b/src/devices/bus/snes_ctrl/joypad.h @@ -0,0 +1,55 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/********************************************************************** + + Nintendo Super Famicom & SNES Joypad + +**********************************************************************/ + +#pragma once + +#ifndef __SNES_JOYPAD__ +#define __SNES_JOYPAD__ + + +#include "emu.h" +#include "ctrl.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> snes_joypad_device + +class snes_joypad_device : public device_t, + public device_snes_control_port_interface +{ +public: + // construction/destruction + snes_joypad_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual ioport_constructor device_input_ports() const; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_sms_control_port_interface overrides + virtual UINT8 read_pin4(); + virtual void write_strobe(UINT8 data); + virtual void port_poll(); + +private: + required_ioport m_joypad; + int m_strobe; + UINT32 m_latch; +}; + + +// device type definition +extern const device_type SNES_JOYPAD; + + +#endif diff --git a/src/devices/bus/snes_ctrl/miracle.c b/src/devices/bus/snes_ctrl/miracle.c new file mode 100644 index 00000000000..d0dfddb71ff --- /dev/null +++ b/src/devices/bus/snes_ctrl/miracle.c @@ -0,0 +1,278 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/********************************************************************** + + Super Nintendo Entertainment System - Miracle Piano Keyboard + + recv at PC = 008a4a + xmit at PC = 008adb + +**********************************************************************/ + +#include "miracle.h" + +#define MIRACLE_MIDI_WAITING 0 +#define MIRACLE_MIDI_RECEIVE 1 // receive byte from piano +#define MIRACLE_MIDI_SEND 2 // send byte to piano + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type SNES_MIRACLE = &device_creator; + + +MACHINE_CONFIG_FRAGMENT( snes_miracle ) + MCFG_MIDI_PORT_ADD("mdin", midiin_slot, "midiin") + MCFG_MIDI_RX_HANDLER(WRITELINE(snes_miracle_device, rx_w)) + + MCFG_MIDI_PORT_ADD("mdout", midiout_slot, "midiout") +MACHINE_CONFIG_END + +machine_config_constructor snes_miracle_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( snes_miracle ); +} + + +//------------------------------------------------- +// device_timer - handler timer events +//------------------------------------------------- + +void snes_miracle_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + if (id == TIMER_STROBE_ON) + { + m_strobe_clock++; + } + else + { + device_serial_interface::device_timer(timer, id, param, ptr); + } +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// snes_miracle_device - constructor +//------------------------------------------------- + +snes_miracle_device::snes_miracle_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, SNES_MIRACLE, "Miracle Piano SNES Cable", tag, owner, clock, "snes_miracle", __FILE__), + device_serial_interface(mconfig, *this), + device_snes_control_port_interface(mconfig, *this), + m_midiin(*this, "mdin"), + m_midiout(*this, "mdout") +{ +} + + +//------------------------------------------------- +// device_start +//------------------------------------------------- + +void snes_miracle_device::device_start() +{ + strobe_timer = timer_alloc(TIMER_STROBE_ON); + strobe_timer->adjust(attotime::never); + save_item(NAME(m_strobe_on)); + save_item(NAME(m_sent_bits)); + save_item(NAME(m_strobe_clock)); + save_item(NAME(m_midi_mode)); +} + + +//------------------------------------------------- +// device_reset +//------------------------------------------------- + +void snes_miracle_device::device_reset() +{ + m_strobe_on = 0; + m_sent_bits = 0; + m_strobe_clock = 0; + m_midi_mode = MIRACLE_MIDI_WAITING; + + // set standard MIDI parameters + set_data_frame(1, 8, PARITY_NONE, STOP_BITS_1); + set_rcv_rate(31250); + set_tra_rate(31250); + + m_xmit_read = m_xmit_write = 0; + m_recv_read = m_recv_write = 0; + m_read_status = m_status_bit = false; + m_tx_busy = false; +} + +UINT8 snes_miracle_device::read_pin4() +{ + UINT8 ret = 0; + + if (m_midi_mode == MIRACLE_MIDI_RECEIVE) + { + if (m_status_bit) + { + m_status_bit = false; + ret = (m_read_status) ? 1 : 0; + } + else + { + ret = (m_data_sent & 0x80) ? 0 : 1; + m_data_sent <<= 1; + } + } + + return ret; +} + +void snes_miracle_device::write_pin6(UINT8 data) +{ +// printf("%02x to pin6\n", data); +} + +void snes_miracle_device::write_strobe(UINT8 data) +{ +// printf("%02x to strobe\n", data); + + if (m_midi_mode == MIRACLE_MIDI_SEND) + { + // console writes (data & 1) to Miracle Piano. + // 1st write is data present flag (1=data present) + // next 8 writes are actual data bits (with ^1) + m_sent_bits++; + m_data_sent <<= 1; + m_data_sent |= (data & 1); + // then we go back to waiting + if (m_sent_bits == 8) + { +// printf("xmit MIDI byte %02x\n", m_data_sent); + xmit_char(m_data_sent); + m_midi_mode = MIRACLE_MIDI_WAITING; + m_sent_bits = 0; + } + + return; + } + + if (data == 1 && !m_strobe_on) + { + strobe_timer->adjust(attotime::zero, 0, machine().device("maincpu")->cycles_to_attotime(1)); + m_strobe_on = 1; + return; + } + + if (m_strobe_on) + { + // was timer running? + if (m_strobe_clock > 0) + { +// printf("got strobe at %d clocks\n", m_strobe_clock); + + if (m_strobe_clock < 500 && data == 0) + { + // short delay is receive mode + m_midi_mode = MIRACLE_MIDI_RECEIVE; + strobe_timer->reset(); + m_strobe_on = 0; + m_strobe_clock = 0; + + m_status_bit = true; + if (m_recv_read != m_recv_write) + { +// printf("Getting %02x from Miracle[%d]\n", m_recvring[m_recv_read], m_recv_read); + m_data_sent = m_recvring[m_recv_read++]; + if (m_recv_read >= RECV_RING_SIZE) + { + m_recv_read = 0; + } + m_read_status = true; + } + else + { + m_read_status = false; +// printf("Miracle has no data\n"); + } + return; + } + else if (m_strobe_clock >= 500) + { + // more than ~520 clocks since strobe on write means send mode + // (ranges from 522-528 have been seen) + m_midi_mode = MIRACLE_MIDI_SEND; + strobe_timer->reset(); + m_strobe_on = 0; + m_strobe_clock = 0; + m_sent_bits = 1; + m_data_sent <<= 1; + m_data_sent |= (data & 1); + return; + } + } + + if (m_midi_mode == MIRACLE_MIDI_SEND && data == 0) + { + // strobe off after the end of a byte + m_midi_mode = MIRACLE_MIDI_WAITING; + } + } +} + +void snes_miracle_device::rcv_complete() // Rx completed receiving byte +{ + receive_register_extract(); + UINT8 rcv = get_received_char(); + +// printf("Got %02x -> [%d]\n", rcv, m_recv_write); + m_recvring[m_recv_write++] = rcv; + if (m_recv_write >= RECV_RING_SIZE) + { + m_recv_write = 0; + } +} + +void snes_miracle_device::tra_complete() // Tx completed sending byte +{ + // is there more waiting to send? + if (m_xmit_read != m_xmit_write) + { + transmit_register_setup(m_xmitring[m_xmit_read++]); + if (m_xmit_read >= XMIT_RING_SIZE) + { + m_xmit_read = 0; + } + } + else + { + m_tx_busy = false; + } +} + +void snes_miracle_device::tra_callback() // Tx send bit +{ + UINT8 bit = transmit_register_get_data_bit(); + + // send this to midi out + m_midiout->write_txd(bit); +} + +void snes_miracle_device::xmit_char(UINT8 data) +{ + // if tx is busy it'll pick this up automatically when it completes + // if not, send now! + if (!m_tx_busy) + { + m_tx_busy = true; + transmit_register_setup(data); + } + else + { + // tx is busy, it'll pick this up next time + m_xmitring[m_xmit_write++] = data; + if (m_xmit_write >= XMIT_RING_SIZE) + { + m_xmit_write = 0; + } + } +} diff --git a/src/devices/bus/snes_ctrl/miracle.h b/src/devices/bus/snes_ctrl/miracle.h new file mode 100644 index 00000000000..2a814050593 --- /dev/null +++ b/src/devices/bus/snes_ctrl/miracle.h @@ -0,0 +1,72 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/********************************************************************** + + Super Nintendo Entertainment System - Miracle Piano Keyboard + +**********************************************************************/ + +#pragma once + +#ifndef __SNES_MIRACLE__ +#define __SNES_MIRACLE__ + + +#include "emu.h" +#include "ctrl.h" +#include "bus/midi/midi.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> snes_miracle_device + +class snes_miracle_device : public device_t, + public device_serial_interface, + public device_snes_control_port_interface +{ +public: + static const int XMIT_RING_SIZE = 64; + static const int RECV_RING_SIZE = 64; + + // construction/destruction + snes_miracle_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + virtual machine_config_constructor device_mconfig_additions() const; + + // serial overrides + virtual void rcv_complete(); // Rx completed receiving byte + virtual void tra_complete(); // Tx completed sending byte + virtual void tra_callback(); // Tx send bit + + void xmit_char(UINT8 data); + + required_device m_midiin, m_midiout; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + UINT8 read_pin4(); + void write_pin6(UINT8 data); + void write_strobe(UINT8 data); + + static const device_timer_id TIMER_STROBE_ON = 0; + emu_timer *strobe_timer; + + int m_strobe_on, m_midi_mode, m_sent_bits; + UINT32 m_strobe_clock; + UINT8 m_data_sent; + UINT8 m_xmitring[XMIT_RING_SIZE], m_recvring[RECV_RING_SIZE]; + int m_xmit_read, m_xmit_write; + int m_recv_read, m_recv_write; + bool m_tx_busy, m_read_status, m_status_bit; +}; + +// device type definition +extern const device_type SNES_MIRACLE; + +#endif diff --git a/src/devices/bus/snes_ctrl/mouse.c b/src/devices/bus/snes_ctrl/mouse.c new file mode 100644 index 00000000000..535b68d02bb --- /dev/null +++ b/src/devices/bus/snes_ctrl/mouse.c @@ -0,0 +1,239 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/********************************************************************** + + Nintendo Super Famicom & SNES Mouse + +**********************************************************************/ + +#include "mouse.h" + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type SNES_MOUSE = &device_creator; + + +static INPUT_PORTS_START( snes_mouse ) + PORT_START("BUTTONS") + PORT_BIT( 0x00ff, IP_ACTIVE_HIGH, IPT_SPECIAL ) // these must be 0! + PORT_BIT( 0x0100, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_NAME("Button Right") + PORT_BIT( 0x0200, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("Button Left") + PORT_BIT( 0x0c00, IP_ACTIVE_HIGH, IPT_UNUSED ) // mouse speed: 0 = slow, 1 = normal, 2 = fast, 3 = unused + PORT_BIT( 0x1000, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x2000, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x4000, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x8000, IP_ACTIVE_LOW, IPT_UNUSED ) + + // we use IPT_LIGHTGUN instead of IPT_MOUSE to avoid input to wrap when you reach the screen border + // due to the relative nature of movement detection in SNES mouse, when we wrap the system would + // detect a sudden jump in the wrong direction, making the usage unfriendly... + PORT_START("MOUSE_X") + PORT_BIT( 0x1ff, 0x100, IPT_LIGHTGUN_X ) PORT_NAME("Superscope X Axis") PORT_SENSITIVITY(30) PORT_KEYDELTA(5) +// PORT_BIT( 0xff, 0x00, IPT_MOUSE_X) PORT_SENSITIVITY(30) PORT_KEYDELTA(5) + + PORT_START("MOUSE_Y") + PORT_BIT( 0x1ff, 0x100, IPT_LIGHTGUN_Y) PORT_NAME("Superscope Y Axis") PORT_SENSITIVITY(30) PORT_KEYDELTA(5) +// PORT_BIT( 0xff, 0x00, IPT_MOUSE_Y) PORT_SENSITIVITY(30) PORT_KEYDELTA(5) +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor snes_mouse_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( snes_mouse ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// snes_mouse_device - constructor +//------------------------------------------------- + +snes_mouse_device::snes_mouse_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, SNES_MOUSE, "Nintendo SNES / SFC Mouse Controller", tag, owner, clock, "snes_mouse", __FILE__), + device_snes_control_port_interface(mconfig, *this), + m_buttons(*this, "BUTTONS"), + m_xaxis(*this, "MOUSE_X"), + m_yaxis(*this, "MOUSE_Y") +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void snes_mouse_device::device_start() +{ + save_item(NAME(m_strobe)); + save_item(NAME(m_idx)); + save_item(NAME(m_latch)); + save_item(NAME(m_x)); + save_item(NAME(m_y)); + save_item(NAME(m_oldx)); + save_item(NAME(m_oldy)); + save_item(NAME(m_deltax)); + save_item(NAME(m_deltay)); + save_item(NAME(m_speed)); + save_item(NAME(m_dirx)); + save_item(NAME(m_diry)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void snes_mouse_device::device_reset() +{ + m_strobe = 0; + m_idx = 0; + m_latch = 0; + m_x = 0; + m_y = 0; + m_oldx = 0; + m_oldy = 0; + m_deltax = 0; + m_deltay = 0; + m_speed = 0; + m_dirx = -1; + m_diry = -1; +} + + +//------------------------------------------------- +// poll +//------------------------------------------------- + +void snes_mouse_device::port_poll() +{ + INT16 var; + int new_dir; + m_idx = 0; + m_latch = m_buttons->read(); + + m_oldx = m_x; + m_oldy = m_y; + m_x = m_xaxis->read(); + m_y = m_yaxis->read(); + + var = m_x - m_oldx; + if (var) + { + new_dir = (var < 0) ? 1 : 0; + if (m_dirx != new_dir) + m_dirx = new_dir; + } + + if (var < -127) + { + m_deltax = 0x7f; + m_oldx -= 127; + } + else if (var < 0) + { + m_deltax = -var; + m_oldx = m_x; + } + else if (var > 127) + { + m_deltax = 0x7f; + m_oldx += 127; + } + else + { + m_deltax = var; + m_oldx = m_x; + } + + var = m_y - m_oldy; + if (var) + { + new_dir = (var < 0) ? 1 : 0; + if (m_diry != new_dir) + m_diry = new_dir; + } + + if (var < -127) + { + m_deltay = 0x7f; + m_oldy -= 127; + } + else if (var < 0) + { + m_deltay = -var; + m_oldy = m_y; + } + else if (var > 127) + { + m_deltay = 0x7f; + m_oldy += 127; + } + else + { + m_deltay = var; + m_oldy = m_y; + } + + m_deltax |= (m_dirx << 7); + m_deltay |= (m_diry << 7); +} + +//------------------------------------------------- +// read +//------------------------------------------------- + +UINT8 snes_mouse_device::read_pin4() +{ + UINT8 res = 0; + + if (m_strobe == 1) + { + // reading with strobe 1, changes mouse speed + m_speed = (m_speed + 1) % 3; + return res; + } + + if (m_idx >= 32) + res |= 0x01; + else if (m_idx >= 24) + res |= BIT(m_deltax, (31 - m_idx++)); + else if (m_idx >= 16) + res |= BIT(m_deltay, (23 - m_idx++)); + else if (m_idx == 11) + { + res |= BIT(m_speed, 0); + m_idx++; + } + else if (m_idx == 10) + { + res |= BIT(m_speed, 1); + m_idx++; + } + else + res |= BIT(m_latch, m_idx++); + + return res; +} + +//------------------------------------------------- +// write +//------------------------------------------------- + +void snes_mouse_device::write_strobe(UINT8 data) +{ + int old = m_strobe; + m_strobe = data & 0x01; + + if (m_strobe < old) // 1 -> 0 transition + port_poll(); +} diff --git a/src/devices/bus/snes_ctrl/mouse.h b/src/devices/bus/snes_ctrl/mouse.h new file mode 100644 index 00000000000..56608e40992 --- /dev/null +++ b/src/devices/bus/snes_ctrl/mouse.h @@ -0,0 +1,63 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/********************************************************************** + + Nintendo Super Famicom & SNES Mouse + +**********************************************************************/ + +#pragma once + +#ifndef __SNES_MOUSE__ +#define __SNES_MOUSE__ + + +#include "emu.h" +#include "ctrl.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> snes_mouse_device + +class snes_mouse_device : public device_t, + public device_snes_control_port_interface +{ +public: + // construction/destruction + snes_mouse_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual ioport_constructor device_input_ports() const; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_sms_control_port_interface overrides + virtual UINT8 read_pin4(); + virtual void write_strobe(UINT8 data); + virtual void port_poll(); + +private: + required_ioport m_buttons; + required_ioport m_xaxis; + required_ioport m_yaxis; + int m_strobe; + int m_idx; + UINT32 m_latch; + + INT16 m_x, m_y, m_oldx, m_oldy; + UINT8 m_deltax, m_deltay; + int m_speed; + int m_dirx, m_diry; +}; + + +// device type definition +extern const device_type SNES_MOUSE; + + +#endif diff --git a/src/devices/bus/snes_ctrl/multitap.c b/src/devices/bus/snes_ctrl/multitap.c new file mode 100644 index 00000000000..7b5ad87bfbc --- /dev/null +++ b/src/devices/bus/snes_ctrl/multitap.c @@ -0,0 +1,154 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/********************************************************************** + + Nintendo Super Famicom & SNES Multitap Adapter + +**********************************************************************/ + +#include "multitap.h" +#include "joypad.h" +#include "twintap.h" + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type SNES_MULTITAP = &device_creator; + + +static INPUT_PORTS_START( snes_multitap ) + PORT_START("CONFIG") + PORT_CONFNAME( 0x01, 0x00, "Number of players") + PORT_CONFSETTING( 0x00, "3-5P" ) + PORT_CONFSETTING( 0x01, "2P" ) +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor snes_multitap_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( snes_multitap ); +} + + +static SLOT_INTERFACE_START( snes_multitap ) + SLOT_INTERFACE("joypad", SNES_JOYPAD) + SLOT_INTERFACE("twintap", SNES_TWINTAP) +SLOT_INTERFACE_END + +static MACHINE_CONFIG_FRAGMENT( multi5p ) + MCFG_SNES_CONTROL_PORT_ADD("port1", snes_multitap, "joypad") + MCFG_SNES_CONTROL_PORT_ADD("port2", snes_multitap, "joypad") + MCFG_SNES_CONTROL_PORT_ADD("port3", snes_multitap, "joypad") + MCFG_SNES_CONTROL_PORT_ADD("port4", snes_multitap, "joypad") +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor snes_multitap_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( multi5p ); +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// snes_multitap_device - constructor +//------------------------------------------------- + +snes_multitap_device::snes_multitap_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, SNES_MULTITAP, "Nintendo SNES / SFC Multitap Adapter", tag, owner, clock, "snes_multitap", __FILE__), + device_snes_control_port_interface(mconfig, *this), + m_port1(*this, "port1"), + m_port2(*this, "port2"), + m_port3(*this, "port3"), + m_port4(*this, "port4"), + m_cfg(*this, "CONFIG") +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void snes_multitap_device::device_start() +{ + save_item(NAME(m_select)); +} + +void snes_multitap_device::device_reset() +{ + m_select = 1; +} + +//------------------------------------------------- +// poll +//------------------------------------------------- + +void snes_multitap_device::port_poll() +{ + m_port1->port_poll(); + if (m_cfg->read() == 0) // 4P + { + m_port2->port_poll(); + m_port3->port_poll(); + m_port4->port_poll(); + } +} + +//------------------------------------------------- +// read +//------------------------------------------------- + +UINT8 snes_multitap_device::read_pin4() +{ + UINT8 ret = 0; + + if (m_cfg->read() == 0) // 4P + ret |= m_select ? m_port1->read_pin4() : m_port3->read_pin4(); + else // 1P + ret |= m_select ? m_port1->read_pin4() : 0; + + return ret; +} + +UINT8 snes_multitap_device::read_pin5() +{ + UINT8 ret = 0; + + if (m_cfg->read() == 0) // 4P + ret |= m_select ? m_port2->read_pin4() : m_port4->read_pin4(); + return ret; +} + +//------------------------------------------------- +// write +//------------------------------------------------- + +void snes_multitap_device::write_strobe(UINT8 data) +{ + m_port1->write_strobe(data); + if (m_cfg->read() == 0) // 4P + { + m_port2->write_strobe(data); + m_port3->write_strobe(data); + m_port4->write_strobe(data); + } +} + +void snes_multitap_device::write_pin6(UINT8 data) +{ + m_select = data & 1; +} diff --git a/src/devices/bus/snes_ctrl/multitap.h b/src/devices/bus/snes_ctrl/multitap.h new file mode 100644 index 00000000000..1720fe6280e --- /dev/null +++ b/src/devices/bus/snes_ctrl/multitap.h @@ -0,0 +1,61 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/********************************************************************** + + Nintendo Super Famicom & SNES Multitap Adapter + +**********************************************************************/ + +#pragma once + +#ifndef __SNES_MULTITAP__ +#define __SNES_MULTITAP__ + + +#include "emu.h" +#include "ctrl.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> snes_multitap_device + +class snes_multitap_device : public device_t, + public device_snes_control_port_interface +{ +public: + // construction/destruction + snes_multitap_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual ioport_constructor device_input_ports() const; + virtual machine_config_constructor device_mconfig_additions() const; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_sms_control_port_interface overrides + virtual UINT8 read_pin4(); + virtual UINT8 read_pin5(); + virtual void write_strobe(UINT8 data); + virtual void write_pin6(UINT8 data); + virtual void port_poll(); + +private: + required_device m_port1; + required_device m_port2; + required_device m_port3; + required_device m_port4; + required_ioport m_cfg; + int m_select; +}; + + +// device type definition +extern const device_type SNES_MULTITAP; + + +#endif diff --git a/src/devices/bus/snes_ctrl/pachinko.c b/src/devices/bus/snes_ctrl/pachinko.c new file mode 100644 index 00000000000..724c4bccbd9 --- /dev/null +++ b/src/devices/bus/snes_ctrl/pachinko.c @@ -0,0 +1,110 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/********************************************************************** + + Nintendo Super Famicom - Sunsoft Pachinko Controller + +**********************************************************************/ + +#include "pachinko.h" + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type SNES_PACHINKO = &device_creator; + + +static INPUT_PORTS_START( snes_pachinko ) + PORT_START("DIAL") + PORT_BIT( 0x7f, 0x3f, IPT_PADDLE) PORT_SENSITIVITY(25) PORT_KEYDELTA(25) PORT_CENTERDELTA(0) PORT_MINMAX(0x18,0x7f) + + PORT_START("BUTTON") + PORT_BIT( 0x00ff, IP_ACTIVE_HIGH, IPT_UNUSED) + PORT_BIT( 0x0100, IP_ACTIVE_HIGH, IPT_BUTTON1) PORT_NAME("Button") + PORT_BIT( 0xfe00, IP_ACTIVE_HIGH, IPT_UNUSED) +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor snes_pachinko_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( snes_pachinko ); +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// snes_pachinko_device - constructor +//------------------------------------------------- + +snes_pachinko_device::snes_pachinko_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, SNES_PACHINKO, "Sunsoft Pachinko Controller", tag, owner, clock, "snes_pachinko", __FILE__), + device_snes_control_port_interface(mconfig, *this), + m_dial(*this, "DIAL"), + m_button(*this, "BUTTON") +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void snes_pachinko_device::device_start() +{ + save_item(NAME(m_latch)); + save_item(NAME(m_strobe)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void snes_pachinko_device::device_reset() +{ + m_latch = 0; + m_strobe = 0; +} + + +//------------------------------------------------- +// poll +//------------------------------------------------- + +void snes_pachinko_device::port_poll() +{ + UINT8 dial = BITSWAP8(m_dial->read() ^ 0xff,7,6,5,4,3,2,1,0); + m_latch = m_button->read() | (dial << 25) | 0xee7000; // add ID +} + +//------------------------------------------------- +// read +//------------------------------------------------- + +UINT8 snes_pachinko_device::read_pin4() +{ + UINT8 ret = m_latch & 1; + m_latch >>= 1; + return ret; +} + +//------------------------------------------------- +// write +//------------------------------------------------- + +void snes_pachinko_device::write_strobe(UINT8 data) +{ + int old = m_strobe; + m_strobe = data & 0x01; + + if (m_strobe < old) // 1 -> 0 transition + port_poll(); +} diff --git a/src/devices/bus/snes_ctrl/pachinko.h b/src/devices/bus/snes_ctrl/pachinko.h new file mode 100644 index 00000000000..ae47adc40b4 --- /dev/null +++ b/src/devices/bus/snes_ctrl/pachinko.h @@ -0,0 +1,56 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/********************************************************************** + + Nintendo Super Famicom - Sunsoft Pachinko Controller + +**********************************************************************/ + +#pragma once + +#ifndef __SNES_PACHINKO__ +#define __SNES_PACHINKO__ + + +#include "emu.h" +#include "ctrl.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> snes_pachinko_device + +class snes_pachinko_device : public device_t, + public device_snes_control_port_interface +{ +public: + // construction/destruction + snes_pachinko_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual ioport_constructor device_input_ports() const; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_sms_control_port_interface overrides + virtual UINT8 read_pin4(); + virtual void write_strobe(UINT8 data); + virtual void port_poll(); + +private: + required_ioport m_dial; + required_ioport m_button; + int m_strobe; + UINT32 m_latch; +}; + + +// device type definition +extern const device_type SNES_PACHINKO; + + +#endif diff --git a/src/devices/bus/snes_ctrl/sscope.c b/src/devices/bus/snes_ctrl/sscope.c new file mode 100644 index 00000000000..72c81e84328 --- /dev/null +++ b/src/devices/bus/snes_ctrl/sscope.c @@ -0,0 +1,185 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/********************************************************************** + + Nintendo Super Famicom & SNES SuperScope + + TODO: x,y positions are not correctly latched + +**********************************************************************/ + +#include "sscope.h" + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type SNES_SUPERSCOPE = &device_creator; + + +static INPUT_PORTS_START( snes_sscope ) + PORT_START("BUTTONS") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("Superscope Fire") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_NAME("Superscope Cursor") + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_BUTTON3 ) PORT_NAME("Superscope Turbo") + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_BUTTON4 ) PORT_NAME("Superscope Pause") + PORT_BIT( 0x30, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_UNUSED ) // On-screen (handled below in port_poll) + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_UNUSED ) // Noise + + PORT_START("SSX") + PORT_BIT( 0xff, 0x80, IPT_LIGHTGUN_X ) PORT_NAME("Superscope X Axis") PORT_CROSSHAIR(X, 1.0, 0.0, 0) PORT_SENSITIVITY(25) PORT_KEYDELTA(15) + + PORT_START("SSY") + PORT_BIT( 0xff, 0x80, IPT_LIGHTGUN_Y) PORT_NAME("Superscope Y Axis") PORT_CROSSHAIR(Y, 1.0, 0.0, 0) PORT_SENSITIVITY(25) PORT_KEYDELTA(15) +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor snes_sscope_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( snes_sscope ); +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// snes_sscope_device - constructor +//------------------------------------------------- + +snes_sscope_device::snes_sscope_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, SNES_SUPERSCOPE, "Nintendo SNES / SFC SuperScope", tag, owner, clock, "snes_sscope", __FILE__), + device_snes_control_port_interface(mconfig, *this), + m_buttons(*this, "BUTTONS"), + m_xaxis(*this, "SSX"), + m_yaxis(*this, "SSY") +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void snes_sscope_device::device_start() +{ + save_item(NAME(m_strobe)); + save_item(NAME(m_idx)); + save_item(NAME(m_latch)); + save_item(NAME(m_x)); + save_item(NAME(m_y)); + save_item(NAME(m_turbo_lock)); + save_item(NAME(m_pause_lock)); + save_item(NAME(m_fire_lock)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void snes_sscope_device::device_reset() +{ + m_strobe = 0; + m_idx = 0; + m_latch = 0; + m_x = 0; + m_y = 0; + m_turbo_lock = 0; + m_pause_lock = 0; + m_fire_lock = 0; +} + + +//------------------------------------------------- +// poll +//------------------------------------------------- + +void snes_sscope_device::port_poll() +{ + // first read input bits + UINT8 input = m_buttons->read(); + m_x = m_xaxis->read(); + m_y = m_yaxis->read(); + m_idx = 0; + + // then start elaborating input bits + // 1. only keep old turbo value + m_latch &= 0x04; + + // 2. set onscreen/offscreen + if (!m_port->m_onscreen_cb.isnull()) + m_latch |= (m_port->m_onscreen_cb(m_x, m_y) ? 0x00 : 0x40); + + // 3. pause is a button that is always edge sensitive + if (BIT(input, 3) && !m_pause_lock) + { + m_latch |= 0x08; + m_pause_lock = 1; + } + else if (!BIT(input, 3)) + m_pause_lock = 0; + + // 4. turbo is a switch; toggle is edge sensitive + if (BIT(input, 2) && !m_turbo_lock) + { + m_latch ^= 0x04; + m_turbo_lock = 1; + } + else if (!BIT(input, 2)) + m_turbo_lock = 0; + + // 5. cursor is a button that is always level sensitive + m_latch |= BIT(input, 1); + + // 6. fire is a button with two behaviors: if turbo is active, trigger is level sensitive; + // otherwise it is edge sensitive + if (BIT(input, 0) && (BIT(m_latch, 2) || !m_fire_lock)) + { + m_latch |= 0x01; + m_fire_lock = 1; + } + else if (!BIT(input, 0)) + m_fire_lock = 0; + + // If we have pressed fire or cursor and we are on-screen and SuperScope is in Port2, then latch video signal. + // Notice that this only works in Port2 because its IOBit pin is connected to bit7 of the IO Port, while Port1 + // has IOBit pin connected to bit6 of the IO Port, and the latter is not detected by the H/V Counters. In other + // words, you can connect SuperScope to Port1, but there is no way SNES could detect its on-screen position + if ((m_latch & 0x03) && !(m_latch & 0x40) && !m_port->m_gunlatch_cb.isnull()) + m_port->m_gunlatch_cb(m_x, m_y); +} + +//------------------------------------------------- +// read +//------------------------------------------------- + +UINT8 snes_sscope_device::read_pin4() +{ + UINT8 res = 0; + + if (m_idx >= 8) // bits 8-15 = ID = all 1s; bits >= 16 all 1s + res |= 0x01; + else + res |= BIT(m_latch, m_idx++); + + return res; +} + +//------------------------------------------------- +// write +//------------------------------------------------- + +void snes_sscope_device::write_strobe(UINT8 data) +{ + int old = m_strobe; + m_strobe = data & 0x01; + + if (m_strobe < old) // 1 -> 0 transition + port_poll(); +} diff --git a/src/devices/bus/snes_ctrl/sscope.h b/src/devices/bus/snes_ctrl/sscope.h new file mode 100644 index 00000000000..a207a29d9a6 --- /dev/null +++ b/src/devices/bus/snes_ctrl/sscope.h @@ -0,0 +1,60 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/********************************************************************** + + Nintendo Super Famicom & SNES SuperScope + +**********************************************************************/ + +#pragma once + +#ifndef __SNES_SUPERSCOPE__ +#define __SNES_SUPERSCOPE__ + + +#include "emu.h" +#include "ctrl.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> snes_sscope_device + +class snes_sscope_device : public device_t, + public device_snes_control_port_interface +{ +public: + // construction/destruction + snes_sscope_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual ioport_constructor device_input_ports() const; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_sms_control_port_interface overrides + virtual UINT8 read_pin4(); + virtual void write_strobe(UINT8 data); + virtual void port_poll(); + +private: + required_ioport m_buttons; + required_ioport m_xaxis; + required_ioport m_yaxis; + int m_strobe, m_idx; + UINT32 m_latch; + + INT16 m_x, m_y; + int m_turbo_lock, m_pause_lock, m_fire_lock; +}; + + +// device type definition +extern const device_type SNES_SUPERSCOPE; + + +#endif diff --git a/src/devices/bus/snes_ctrl/twintap.c b/src/devices/bus/snes_ctrl/twintap.c new file mode 100644 index 00000000000..0755e14ef74 --- /dev/null +++ b/src/devices/bus/snes_ctrl/twintap.c @@ -0,0 +1,113 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/********************************************************************** + + Nintendo Super Famicom - Yonezawa / PartyRoom 21 Twin Tap Controller + + This controller consists of two 1-button small units attached to a + single 7pin connector. You plug the connector to Port2 and two + players can compete on the quiz game (Port1 should have a joypad + plugged in, to start the game and browse the menus). By plugging + a multitap adapter to Port2, up to 4 Twin Tap controllers can be + attached at the same time, allowing for 8 players quiz sessions. + +**********************************************************************/ + +#include "twintap.h" + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type SNES_TWINTAP = &device_creator; + + +static INPUT_PORTS_START( snes_twintap ) + PORT_START("INPUTS") + PORT_BIT( 0x0001, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Button 2") + PORT_BIT( 0x0002, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Button 1") + PORT_BIT( 0x8ffc, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x7000, IP_ACTIVE_LOW, IPT_UNUSED ) // controller ID unknown +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor snes_twintap_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( snes_twintap ); +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// snes_twintap_device - constructor +//------------------------------------------------- + +snes_twintap_device::snes_twintap_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, SNES_TWINTAP, "Yonezawa Twin Tap Controller", tag, owner, clock, "snes_twintap", __FILE__), + device_snes_control_port_interface(mconfig, *this), + m_inputs(*this, "INPUTS") +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void snes_twintap_device::device_start() +{ + save_item(NAME(m_latch)); + save_item(NAME(m_strobe)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void snes_twintap_device::device_reset() +{ + m_latch = 0; + m_strobe = 0; +} + + +//------------------------------------------------- +// poll +//------------------------------------------------- + +void snes_twintap_device::port_poll() +{ + m_latch = m_inputs->read(); +} + +//------------------------------------------------- +// read +//------------------------------------------------- + +UINT8 snes_twintap_device::read_pin4() +{ + UINT8 ret = m_latch & 1; + m_latch >>= 1; + return ret; +} + +//------------------------------------------------- +// write +//------------------------------------------------- + +void snes_twintap_device::write_strobe(UINT8 data) +{ + int old = m_strobe; + m_strobe = data & 0x01; + + if (m_strobe < old) // 1 -> 0 transition + port_poll(); +} diff --git a/src/devices/bus/snes_ctrl/twintap.h b/src/devices/bus/snes_ctrl/twintap.h new file mode 100644 index 00000000000..4474ec1e6da --- /dev/null +++ b/src/devices/bus/snes_ctrl/twintap.h @@ -0,0 +1,55 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/********************************************************************** + + Nintendo Super Famicom - Yonezawa / PartyRoom 21 Twin Tap Controller + +**********************************************************************/ + +#pragma once + +#ifndef __SNES_TWINTAP__ +#define __SNES_TWINTAP__ + + +#include "emu.h" +#include "ctrl.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> snes_twintap_device + +class snes_twintap_device : public device_t, + public device_snes_control_port_interface +{ +public: + // construction/destruction + snes_twintap_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual ioport_constructor device_input_ports() const; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_sms_control_port_interface overrides + virtual UINT8 read_pin4(); + virtual void write_strobe(UINT8 data); + virtual void port_poll(); + +private: + required_ioport m_inputs; + int m_strobe; + UINT32 m_latch; +}; + + +// device type definition +extern const device_type SNES_TWINTAP; + + +#endif diff --git a/src/devices/bus/spc1000/exp.c b/src/devices/bus/spc1000/exp.c new file mode 100644 index 00000000000..7a63161096e --- /dev/null +++ b/src/devices/bus/spc1000/exp.c @@ -0,0 +1,82 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + Samsung SPC-1000 Expansion port + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "exp.h" + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type SPC1000_EXP_SLOT = &device_creator; + + +device_spc1000_card_interface::device_spc1000_card_interface(const machine_config &mconfig, device_t &device) + : device_slot_card_interface(mconfig, device) +{ +} + + +device_spc1000_card_interface::~device_spc1000_card_interface() +{ +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// spc1000_exp_device - constructor +//------------------------------------------------- +spc1000_exp_device::spc1000_exp_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, SPC1000_EXP_SLOT, "Samsung SPC-1000 expansion", tag, owner, clock, "spc1000_exp", __FILE__), + device_slot_interface(mconfig, *this) +{ +} + + +//------------------------------------------------- +// spc1000_exp_device - destructor +//------------------------------------------------- + +spc1000_exp_device::~spc1000_exp_device() +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void spc1000_exp_device::device_start() +{ + m_card = dynamic_cast(get_card_device()); +} + +/*------------------------------------------------- + read + -------------------------------------------------*/ + +READ8_MEMBER(spc1000_exp_device::read) +{ + if (m_card) + return m_card->read(space, offset); + else + return 0xff; +} + +/*------------------------------------------------- + write + -------------------------------------------------*/ + +WRITE8_MEMBER(spc1000_exp_device::write) +{ + if (m_card) + m_card->write(space, offset, data); +} diff --git a/src/devices/bus/spc1000/exp.h b/src/devices/bus/spc1000/exp.h new file mode 100644 index 00000000000..3607f021a0e --- /dev/null +++ b/src/devices/bus/spc1000/exp.h @@ -0,0 +1,50 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __SCP1000_SLOT_H +#define __SCP1000_SLOT_H + +// ======================> device_spc1000_card_interface + +class device_spc1000_card_interface : public device_slot_card_interface +{ +public: + // construction/destruction + device_spc1000_card_interface(const machine_config &mconfig, device_t &device); + virtual ~device_spc1000_card_interface(); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read) { return 0xff; } + virtual DECLARE_WRITE8_MEMBER(write) {} + +protected: +}; + + +// ======================> spc1000_exp_device + +class spc1000_exp_device : public device_t, + public device_slot_interface +{ +public: + // construction/destruction + spc1000_exp_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual ~spc1000_exp_device(); + + // device-level overrides + virtual void device_start(); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read); + virtual DECLARE_WRITE8_MEMBER(write); + +protected: + + device_spc1000_card_interface* m_card; +}; + + + +// device type definition +extern const device_type SPC1000_EXP_SLOT; + +#endif diff --git a/src/devices/bus/spc1000/fdd.c b/src/devices/bus/spc1000/fdd.c new file mode 100644 index 00000000000..9089dae5829 --- /dev/null +++ b/src/devices/bus/spc1000/fdd.c @@ -0,0 +1,226 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*************************************************************************** + + SPC-1000 FDD unit + +***************************************************************************/ + +#include "emu.h" +#include "fdd.h" + + +/*************************************************************************** + IMPLEMENTATION +***************************************************************************/ + +READ8_MEMBER(spc1000_fdd_exp_device::i8255_c_r) +{ + return m_i8255_0_pc >> 4; +} + +WRITE8_MEMBER(spc1000_fdd_exp_device::i8255_b_w) +{ + m_i8255_portb = data; +} + +WRITE8_MEMBER(spc1000_fdd_exp_device::i8255_c_w) +{ + m_i8255_1_pc = data; +} + +//------------------------------------------------- +// fdc interrupt +//------------------------------------------------- + +READ8_MEMBER( spc1000_fdd_exp_device::tc_r ) +{ + logerror("%s: tc_r\n", space.machine().describe_context()); + + // toggle tc on read + m_fdc->tc_w(true); + m_timer_tc->adjust(attotime::zero); + + return 0xff; +} + +WRITE8_MEMBER( spc1000_fdd_exp_device::control_w ) +{ + logerror("%s: control_w(%02x)\n", space.machine().describe_context(), data); + + // bit 0, motor on signal + if (m_fd0) + m_fd0->mon_w(!BIT(data, 0)); + if (m_fd1) + m_fd1->mon_w(!BIT(data, 0)); +} + +static ADDRESS_MAP_START( sd725_mem, AS_PROGRAM, 8, spc1000_fdd_exp_device ) + ADDRESS_MAP_UNMAP_HIGH + AM_RANGE(0x0000, 0x1fff) AM_ROM + AM_RANGE(0x2000, 0xffff) AM_RAM +ADDRESS_MAP_END + +static ADDRESS_MAP_START( sd725_io, AS_IO, 8, spc1000_fdd_exp_device ) + ADDRESS_MAP_UNMAP_HIGH + ADDRESS_MAP_GLOBAL_MASK(0xff) + AM_RANGE(0xf8, 0xf8) AM_READWRITE(tc_r, control_w) // (R) Terminal Count Port (W) Motor Control Port + AM_RANGE(0xfa, 0xfb) AM_DEVICE("upd765", upd765a_device, map) + AM_RANGE(0xfc, 0xff) AM_DEVREADWRITE("d8255_master", i8255_device, read, write) +ADDRESS_MAP_END + +static SLOT_INTERFACE_START( sd725_floppies ) + SLOT_INTERFACE("sd320", EPSON_SD_320) +SLOT_INTERFACE_END + +static MACHINE_CONFIG_FRAGMENT(spc1000_fdd) + + /* sub CPU(5 inch floppy drive) */ + MCFG_CPU_ADD("fdccpu", Z80, XTAL_4MHz) /* 4 MHz */ + MCFG_CPU_PROGRAM_MAP(sd725_mem) + MCFG_CPU_IO_MAP(sd725_io) + + MCFG_DEVICE_ADD("d8255_master", I8255, 0) + MCFG_I8255_IN_PORTA_CB(DEVREAD8("d8255_master", i8255_device, pb_r)) + MCFG_I8255_IN_PORTB_CB(DEVREAD8("d8255_master", i8255_device, pa_r)) + MCFG_I8255_OUT_PORTB_CB(WRITE8(spc1000_fdd_exp_device, i8255_b_w)) + MCFG_I8255_IN_PORTC_CB(READ8(spc1000_fdd_exp_device, i8255_c_r)) + MCFG_I8255_OUT_PORTC_CB(WRITE8(spc1000_fdd_exp_device, i8255_c_w)) + + // floppy disk controller + MCFG_UPD765A_ADD("upd765", true, true) + MCFG_UPD765_INTRQ_CALLBACK(INPUTLINE("fdccpu", INPUT_LINE_IRQ0)) + + // floppy drives + MCFG_FLOPPY_DRIVE_ADD("upd765:0", sd725_floppies, "sd320", floppy_image_device::default_floppy_formats) + MCFG_FLOPPY_DRIVE_ADD("upd765:1", sd725_floppies, "sd320", floppy_image_device::default_floppy_formats) +MACHINE_CONFIG_END + +//------------------------------------------------- +// device_mconfig_additions +//------------------------------------------------- + +machine_config_constructor spc1000_fdd_exp_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( spc1000_fdd ); +} + +ROM_START( spc1000_fdd ) + ROM_REGION(0x10000, "fdccpu", 0) + ROM_LOAD("sd725a.bin", 0x0000, 0x1000, CRC(96ac2eb8) SHA1(8e9d8f63a7fb87af417e95603e71cf537a6e83f1)) +ROM_END + +//------------------------------------------------- +// device_rom_region +//------------------------------------------------- + +const rom_entry *spc1000_fdd_exp_device::device_rom_region() const +{ + return ROM_NAME( spc1000_fdd ); +} + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type SPC1000_FDD_EXP = &device_creator; + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// spc1000_fdd_exp_device - constructor +//------------------------------------------------- + +spc1000_fdd_exp_device::spc1000_fdd_exp_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, SPC1000_FDD_EXP, "SPC1000 FDD expansion", tag, owner, clock, "spc1000_fdd_exp", __FILE__), + device_spc1000_card_interface(mconfig, *this), + m_cpu(*this, "fdccpu"), + m_fdc(*this, "upd765"), + m_pio(*this, "d8255_master") +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void spc1000_fdd_exp_device::device_start() +{ + m_timer_tc = timer_alloc(TIMER_TC); + m_timer_tc->adjust(attotime::never); + + m_fd0 = subdevice("upd765:0")->get_device(); + m_fd1 = subdevice("upd765:1")->get_device(); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void spc1000_fdd_exp_device::device_reset() +{ + m_cpu->set_input_line_vector(0, 0); + + // enable rom (is this really needed? it does not seem necessary for FDD to work) + m_cpu->space(AS_PROGRAM).install_rom(0x0000, 0x0fff, 0, 0x2000, device().machine().root_device().memregion("fdccpu")->base()); +} + +void spc1000_fdd_exp_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch (id) + { + case TIMER_TC: + m_fdc->tc_w(false); + break; + } +} + +/*------------------------------------------------- + read +-------------------------------------------------*/ + +READ8_MEMBER(spc1000_fdd_exp_device::read) +{ + // this should be m_pio->read on the whole 0x00-0x03 range? + if (offset >= 3) + return 0xff; + else + { + UINT8 data = 0; + switch (offset) + { + case 1: + data = m_i8255_portb; + break; + case 2: + data = m_i8255_1_pc >> 4; + break; + } + return data; + } +} + +//------------------------------------------------- +// write +//------------------------------------------------- + +WRITE8_MEMBER(spc1000_fdd_exp_device::write) +{ + // this should be m_pio->write on the whole 0x00-0x03 range? + if (offset < 3) + { + switch (offset) + { + case 0: + m_pio->write(space, 1, data); + break; + case 2: + m_i8255_0_pc = data; + break; + } + } +} diff --git a/src/devices/bus/spc1000/fdd.h b/src/devices/bus/spc1000/fdd.h new file mode 100644 index 00000000000..4d384e2ee44 --- /dev/null +++ b/src/devices/bus/spc1000/fdd.h @@ -0,0 +1,65 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __SPC1000_FDD_H__ +#define __SPC1000_FDD_H__ + +#include "exp.h" +#include "cpu/z80/z80.h" +#include "machine/i8255.h" +#include "machine/upd765.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> spc1000_fdd_exp_device + +class spc1000_fdd_exp_device : public device_t, + public device_spc1000_card_interface +{ +public: + // construction/destruction + spc1000_fdd_exp_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual const rom_entry *device_rom_region() const; + +public: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + virtual DECLARE_READ8_MEMBER(read); + virtual DECLARE_WRITE8_MEMBER(write); + + DECLARE_READ8_MEMBER(tc_r); + DECLARE_WRITE8_MEMBER(control_w); + DECLARE_WRITE8_MEMBER(i8255_b_w); + DECLARE_READ8_MEMBER(i8255_c_r); + DECLARE_WRITE8_MEMBER(i8255_c_w); + +private: + // internal state + required_device m_cpu; + required_device m_fdc; + required_device m_pio; + + floppy_image_device *m_fd0; + floppy_image_device *m_fd1; + + emu_timer *m_timer_tc; + + UINT8 m_i8255_0_pc; + UINT8 m_i8255_1_pc; + UINT8 m_i8255_portb; + + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + static const device_timer_id TIMER_TC = 0; +}; + + +// device type definition +extern const device_type SPC1000_FDD_EXP; + +#endif /* __SPC1000_FDD_H__ */ diff --git a/src/devices/bus/spc1000/vdp.c b/src/devices/bus/spc1000/vdp.c new file mode 100644 index 00000000000..7824e9fccb4 --- /dev/null +++ b/src/devices/bus/spc1000/vdp.c @@ -0,0 +1,106 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*************************************************************************** + + SPC-1000 VDP expansion unit + +***************************************************************************/ + +#include "emu.h" +#include "vdp.h" + + +/*************************************************************************** + IMPLEMENTATION +***************************************************************************/ + +WRITE_LINE_MEMBER(spc1000_vdp_exp_device::vdp_interrupt) +{ + // nothing here? +} + +static MACHINE_CONFIG_FRAGMENT(scp1000_vdp) + + MCFG_DEVICE_ADD("tms", TMS9928A, XTAL_10_738635MHz / 2) // TODO: which clock? + MCFG_TMS9928A_VRAM_SIZE(0x4000) + MCFG_TMS9928A_OUT_INT_LINE_CB(WRITELINE(spc1000_vdp_exp_device, vdp_interrupt)) + MCFG_TMS9928A_SCREEN_ADD_NTSC("tms_screen") + MCFG_SCREEN_UPDATE_DEVICE("tms", tms9928a_device, screen_update) +MACHINE_CONFIG_END + +//------------------------------------------------- +// device_mconfig_additions +//------------------------------------------------- + +machine_config_constructor spc1000_vdp_exp_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( scp1000_vdp ); +} + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type SPC1000_VDP_EXP = &device_creator; + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// spc1000_vdp_exp_device - constructor +//------------------------------------------------- + +spc1000_vdp_exp_device::spc1000_vdp_exp_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, SPC1000_VDP_EXP, "SPC1000 VDP expansion", tag, owner, clock, "spc1000_vdp_exp", __FILE__), + device_spc1000_card_interface(mconfig, *this), + m_vdp(*this, "tms") +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void spc1000_vdp_exp_device::device_start() +{ +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void spc1000_vdp_exp_device::device_reset() +{ +} + +/*------------------------------------------------- + read +-------------------------------------------------*/ +READ8_MEMBER(spc1000_vdp_exp_device::read) +{ + if (!(offset & 0x800)) + return 0xff; + + if (offset & 1) + return m_vdp->register_read(space, offset); + else + return m_vdp->vram_read(space, offset); +} + +//------------------------------------------------- +// write +//------------------------------------------------- + +WRITE8_MEMBER(spc1000_vdp_exp_device::write) +{ + if (offset & 0x800) + { + if (offset & 1) + m_vdp->register_write(space, offset, data); + else + m_vdp->vram_write(space, offset, data); + } +} diff --git a/src/devices/bus/spc1000/vdp.h b/src/devices/bus/spc1000/vdp.h new file mode 100644 index 00000000000..d7311f8c104 --- /dev/null +++ b/src/devices/bus/spc1000/vdp.h @@ -0,0 +1,45 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __SPC1000_VDP_H__ +#define __SPC1000_VDP_H__ + +#include "exp.h" +#include "video/tms9928a.h" + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> spc1000_vdp_exp_device + +class spc1000_vdp_exp_device : public device_t, + public device_spc1000_card_interface +{ +public: + // construction/destruction + spc1000_vdp_exp_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + +public: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + virtual DECLARE_READ8_MEMBER(read); + virtual DECLARE_WRITE8_MEMBER(write); + + DECLARE_WRITE_LINE_MEMBER(vdp_interrupt); + +private: + // internal state + required_device m_vdp; +}; + + +// device type definition +extern const device_type SPC1000_VDP_EXP; + +#endif /* __SPC1000_VDP_H__ */ diff --git a/src/devices/bus/ti99_peb/bwg.c b/src/devices/bus/ti99_peb/bwg.c new file mode 100644 index 00000000000..55a1150f972 --- /dev/null +++ b/src/devices/bus/ti99_peb/bwg.c @@ -0,0 +1,704 @@ +// license:LGPL-2.1+ +// copyright-holders:Michael Zapf +/******************************************************************************* + SNUG BwG Disk Controller + Based on WD1773 + Double Density, Double-sided + + * Supports Double Density. + * As this card includes its own RAM, it does not need to allocate a portion + of VDP RAM to store I/O buffers. + * Includes a MM58274C RTC. + * Support an additional floppy drive, for a total of 4 floppies. + + Reference: + * BwG Disketten-Controller: Beschreibung der DSR (Description of the DSR) + + + +------------------------+ + | 32 KiB EPROM | --- 1 of 4 pages--> 4000 +------------------+ + | | | DSR space | + +------------------------+ | (Driver) | + | 2 KiB RAM | --- 1 of 2 pages--> 5c00 +------------------+ + +------------------------+ | RAM buffer | + 5fe0 +------------------+ + | RTC or WD1773 | + 5fff +------------------+ + + Michael Zapf, September 2010 + January 2012: rewritten as class (MZ) + February 2014: rewritten for new floppy subsystem (MZ) + + Known issues (Feb 2014): + + - The BwG controller cannot run with the Geneve or other non-9900 computers. + The reason for that is the wait state logic. It assumes that when + executing MOVB @>5FF6,*R2, first a value from 5FF7 is attempted to be read, + just as the TI console does. In that case, wait states are inserted if + necessary. The Geneve, however, will try to read a single byte from 5FF6 + only and therefore circumvent the wait state generation. This is in fact + not an emulation glitch but the behavior of the real expansion card. + + +*******************************************************************************/ + +#include "emu.h" +#include "peribox.h" +#include "bwg.h" +#include "formats/ti99_dsk.h" +#include "imagedev/flopdrv.h" + +// ---------------------------------- +// Flags for debugging + +// Show read and write accesses +#define TRACE_RW 0 + +// Show CRU bit accesses +#define TRACE_CRU 0 + +// Show ready line activity +#define TRACE_READY 0 + +// Show detailed signal activity +#define TRACE_SIGNALS 0 + +// Show sector data +#define TRACE_DATA 0 + +// Show address bus operations +#define TRACE_ADDRESS 0 + +// Show address bus operations +#define TRACE_MOTOR 0 + +// ---------------------------------- + +#define MOTOR_TIMER 1 +#define CLOCK_TAG "mm58274c" +#define FDC_TAG "wd1773" + +#define BUFFER "ram" + +/* + Modern implementation +*/ + +snug_bwg_device::snug_bwg_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : ti_expansion_card_device(mconfig, TI99_BWG, "SNUG BwG Floppy Controller", tag, owner, clock, "ti99_bwg", __FILE__), + m_wd1773(*this, FDC_TAG), + m_clock(*this, CLOCK_TAG) { } + +/* + Operate the wait state logic. +*/ +void snug_bwg_device::operate_ready_line() +{ + // This is the wait state logic + if (TRACE_SIGNALS) logerror("bwg: address=%04x, DRQ=%d, INTRQ=%d, MOTOR=%d\n", m_address & 0xffff, m_DRQ, m_IRQ, m_MOTOR_ON); + line_state nready = (m_dataregLB && // Are we accessing 5ff7 + m_WAITena && // and the wait state generation is active (SBO 2) + (m_DRQ==CLEAR_LINE) && // and we are waiting for a byte + (m_IRQ==CLEAR_LINE) && // and there is no interrupt yet + (m_MOTOR_ON==ASSERT_LINE) // and the motor is turning? + )? ASSERT_LINE : CLEAR_LINE; // In that case, clear READY and thus trigger wait states + + if (TRACE_READY) if (nready==ASSERT_LINE) logerror("bwg: READY line = %d\n", (nready==CLEAR_LINE)? 1:0); + m_slot->set_ready((nready==CLEAR_LINE)? ASSERT_LINE : CLEAR_LINE); +} + +/* + Callbacks from the WD1773 chip +*/ +WRITE_LINE_MEMBER( snug_bwg_device::fdc_irq_w ) +{ + if (TRACE_SIGNALS) logerror("bwg: set intrq = %d\n", state); + m_IRQ = (line_state)state; + // Unlike the TI FDC, the BwG does not set the INTB line. Anyway, no one cares. + // We need to explicitly set the READY line to release the datamux + operate_ready_line(); +} + +WRITE_LINE_MEMBER( snug_bwg_device::fdc_drq_w ) +{ + if (TRACE_SIGNALS) logerror("bwg: set drq = %d\n", state); + m_DRQ = (line_state)state; + + // We need to explicitly set the READY line to release the datamux + operate_ready_line(); +} + +SETADDRESS_DBIN_MEMBER( snug_bwg_device::setaddress_dbin ) +{ + // Do not allow setaddress for debugger + if (space.debugger_access()) return; + + // Selection login in the PAL and some circuits on the board + + // Is the card being selected? + m_address = offset; + m_inDsrArea = ((m_address & m_select_mask)==m_select_value); + + if (!m_inDsrArea) return; + + if (TRACE_ADDRESS) logerror("bwg: set address = %04x\n", offset & 0xffff); + + // Is the WD chip on the card being selected? + // We need the even and odd addresses for the wait state generation, + // but only the even addresses when we access it + m_WDsel0 = m_inDsrArea && !m_rtc_enabled + && ((state==ASSERT_LINE && ((m_address & 0x1ff8)==0x1ff0)) // read + || (state==CLEAR_LINE && ((m_address & 0x1ff8)==0x1ff8))); // write + + m_WDsel = m_WDsel0 && ((m_address & 1)==0); + + // Is the RTC selected on the card? (even addr) + m_RTCsel = m_inDsrArea && m_rtc_enabled && ((m_address & 0x1fe1)==0x1fe0); + + // RTC disabled: + // 5c00 - 5fef: RAM + // 5ff0 - 5fff: Controller (f0 = status, f2 = track, f4 = sector, f6 = data) + + // RTC enabled: + // 5c00 - 5fdf: RAM + // 5fe0 - 5fff: Clock (even addr) + + // Is RAM selected? We just check for the last 1K and let the RTC or WD + // just take control before + m_lastK = m_inDsrArea && ((m_address & 0x1c00)==0x1c00); + + // Is the data register port of the WD being selected? + // In fact, the address to read the data from is 5FF6, but the TI-99 datamux + // fetches both bytes from 5FF7 and 5FF6, the odd one first. The BwG uses + // the odd address to operate the READY line + m_dataregLB = m_WDsel0 && ((m_address & 0x07)==0x07); + + // Clear or assert the outgoing READY line + operate_ready_line(); +} + +/* + Access for debugger. This is a stripped-down version of the + main methods below. We only allow ROM and RAM access. +*/ +void snug_bwg_device::debug_read(offs_t offset, UINT8* value) +{ + if (((offset & m_select_mask)==m_select_value) && m_selected) + { + if ((offset & 0x1c00)==0x1c00) + { + if ((offset & 0x1fe0)!=0x1fe0) + *value = m_buffer_ram[(m_ram_page<<10) | (offset & 0x03ff)]; + } + else + *value = m_dsrrom[(m_rom_page<<13) | (offset & 0x1fff)]; + } +} + +void snug_bwg_device::debug_write(offs_t offset, UINT8 data) +{ + if (((offset & m_select_mask)==m_select_value) && m_selected) + { + if (((offset & 0x1c00)==0x1c00) && ((offset & 0x1fe0)!=0x1fe0)) + m_buffer_ram[(m_ram_page<<10) | (m_address & 0x03ff)] = data; + } +} + +/* + Read a byte from ROM, RAM, FDC, or RTC. See setaddress_dbin for selection + logic. +*/ +READ8Z_MEMBER(snug_bwg_device::readz) +{ + if (space.debugger_access()) + { + debug_read(offset, value); + return; + } + + if (m_inDsrArea && m_selected) + { + // 010x xxxx xxxx xxxx + if (m_lastK) + { + // ...1 11xx xxxx xxxx + if (m_rtc_enabled) + { + if (m_RTCsel) + { + // .... ..11 111x xxx0 + *value = m_clock->read(space, (m_address & 0x001e) >> 1); + if (TRACE_RW) logerror("bwg: read RTC: %04x -> %02x\n", m_address & 0xffff, *value); + } + else + { + *value = m_buffer_ram[(m_ram_page<<10) | (m_address & 0x03ff)]; + if (TRACE_RW) logerror("bwg: read ram: %04x (page %d)-> %02x\n", m_address & 0xffff, m_ram_page, *value); + } + } + else + { + if (m_WDsel) + { + // .... ..11 1111 0xx0 + // Note that the value is inverted again on the board, + // so we can drop the inversion + *value = m_wd1773->gen_r((m_address >> 1)&0x03); + if (TRACE_RW) logerror("bwg: read FDC: %04x -> %02x\n", m_address & 0xffff, *value); + if (TRACE_DATA) + { + if ((m_address & 0xffff)==0x5ff6) logerror("%02x ", *value); + else logerror("\n%04x: %02x", m_address&0xffff, *value); + } + } + else + { + *value = m_buffer_ram[(m_ram_page<<10) | (m_address & 0x03ff)]; + if (TRACE_RW) logerror("bwg: read ram: %04x (page %d)-> %02x\n", m_address & 0xffff, m_ram_page, *value); + } + } + } + else + { + *value = m_dsrrom[(m_rom_page<<13) | (m_address & 0x1fff)]; + if (TRACE_RW) logerror("bwg: read dsr: %04x (page %d)-> %02x\n", m_address & 0xffff, m_rom_page, *value); + } + } +} + +/* + Write a byte + 4000 - 5bff: ROM, ignore write (4 banks) + + rtc disabled: + 5c00 - 5fef: RAM + 5ff0 - 5fff: Controller (f8 = command, fa = track, fc = sector, fe = data) + + rtc enabled: + 5c00 - 5fdf: RAM + 5fe0 - 5fff: Clock (even addr) +*/ +WRITE8_MEMBER(snug_bwg_device::write) +{ + if (space.debugger_access()) + { + debug_write(offset, data); + return; + } + + if (m_inDsrArea && m_selected) + { + if (m_lastK) + { + if (m_rtc_enabled) + { + if (m_RTCsel) + { + // .... ..11 111x xxx0 + if (TRACE_RW) logerror("bwg: write RTC: %04x <- %02x\n", m_address & 0xffff, data); + m_clock->write(space, (m_address & 0x001e) >> 1, data); + } + else + { + if (TRACE_RW) logerror("bwg: write ram: %04x (page %d) <- %02x\n", m_address & 0xffff, m_ram_page, data); + m_buffer_ram[(m_ram_page<<10) | (m_address & 0x03ff)] = data; + } + } + else + { + if (m_WDsel) + { + // .... ..11 1111 1xx0 + // Note that the value is inverted again on the board, + // so we can drop the inversion + if (TRACE_RW) logerror("bwg: write FDC: %04x <- %02x\n", m_address & 0xffff, data); + m_wd1773->gen_w((m_address >> 1)&0x03, data); + } + else + { + if (TRACE_RW) logerror("bwg: write ram: %04x (page %d) <- %02x\n", m_address & 0xffff, m_ram_page, data); + m_buffer_ram[(m_ram_page<<10) | (m_address & 0x03ff)] = data; + } + } + } + } +} + +/* + CRU read handler. *=inverted. + bit 0: DSK4 connected* + bit 1: DSK1 connected* + bit 2: DSK2 connected* + bit 3: DSK3 connected* + bit 4: Dip 1 + bit 5: Dip 2 + bit 6: Dip 3 + bit 7: Dip 4 +*/ +READ8Z_MEMBER(snug_bwg_device::crureadz) +{ + UINT8 reply = 0; + + if ((offset & 0xff00)==m_cru_base) + { + if ((offset & 0x00ff)==0) + { + // Check what drives are not connected + reply = ((m_floppy[0] != NULL)? 0 : 0x02) // DSK1 + | ((m_floppy[1] != NULL)? 0 : 0x04) // DSK2 + | ((m_floppy[2] != NULL)? 0 : 0x08) // DSK3 + | ((m_floppy[3] != NULL)? 0 : 0x01); // DSK4 + + // DIP switches for step and date/time display + if (m_dip1 != 0) reply |= 0x10; + if (m_dip2 != 0) reply |= 0x20; + + // DIP switches for drive range selection + // 00 = only DSK1; 01 = DSK1+DSK2, 10=DSK1+DSK2+DSK3, 11=all + reply |= (m_dip34 << 6); + + // Invert all + *value = ~reply; + } + else + *value = 0; + if (TRACE_CRU) logerror("bwg: Read CRU = %02x\n", *value); + } +} + +WRITE8_MEMBER(snug_bwg_device::cruwrite) +{ +// int drive, drivebit; + + if ((offset & 0xff00)==m_cru_base) + { + int bit = (offset >> 1) & 0x0f; + switch (bit) + { + case 0: + /* (De)select the card. Indicated by a LED on the board. */ + m_selected = (data != 0); + if (TRACE_CRU) logerror("bwg: Map DSR (bit 0) = %d\n", m_selected); + break; + + case 1: + // Activate motor + if (data==1 && m_lastval==0) + { // on rising edge, set motor_running for 4.23s + if (TRACE_CRU) logerror("bwg: trigger motor (bit 1)\n"); + set_floppy_motors_running(true); + } + m_lastval = data; + break; + + case 2: + /* Set disk ready/hold (bit 2) */ + // 0: ignore IRQ and DRQ + // 1: TMS9900 is stopped until IRQ or DRQ are set + // OR the motor stops rotating - rotates for 4.23s after write + // to CRU bit 1 + if (TRACE_CRU) logerror("bwg: arm wait state logic (bit 2) = %d\n", data); + m_WAITena = (data != 0); + break; + + case 3: + // Load disk heads (HLT pin) (bit 3). Not implemented. + if (TRACE_CRU) logerror("bwg: set head load (bit 3) = %d\n", data); + break; + + case 4: + // Select drive 0-2 (DSK1-DSK3) (bits 4-6) + m_DSEL = (data != 0)? (m_DSEL | 0x01) : (m_DSEL & 0xfe); + set_drive(); + break; + case 5: + m_DSEL = (data != 0)? (m_DSEL | 0x02) : (m_DSEL & 0xfd); + set_drive(); + break; + case 6: + m_DSEL = (data != 0)? (m_DSEL | 0x04) : (m_DSEL & 0xfb); + set_drive(); + break; + + case 7: + // Select side of disk (bit 7) + m_SIDSEL = (data==1)? ASSERT_LINE : CLEAR_LINE; + if (TRACE_CRU) logerror("bwg: set side (bit 7) = %d\n", data); + if (m_current_floppy != NULL) m_current_floppy->ss_w(data); + break; + + case 8: + // Select drive 3 (DSK4) (bit 8) */ + m_DSEL = (data != 0)? (m_DSEL | 0x08) : (m_DSEL & 0xf7); + set_drive(); + break; + + case 10: + /* double density enable (active low) */ + if (TRACE_CRU) logerror("bwg: set double density (bit 10) = %d\n", data); + m_wd1773->dden_w(data != 0); + break; + + case 11: + /* EPROM A13 */ + if (data != 0) + m_rom_page |= 1; + else + m_rom_page &= 0xfe; // 11111110 + if (TRACE_CRU) logerror("bwg: set ROM page (bit 11) = %d, page = %d\n", bit, m_rom_page); + break; + + case 13: + /* RAM A10 */ + m_ram_page = data; + if (TRACE_CRU) logerror("bwg: set RAM page (bit 13) = %d, page = %d\n", bit, m_ram_page); + break; + + case 14: + /* Override FDC with RTC (active high) */ + if (TRACE_CRU) logerror("bwg: turn on RTC (bit 14) = %d\n", data); + m_rtc_enabled = (data != 0); + break; + + case 15: + /* EPROM A14 */ + if (data != 0) + m_rom_page |= 2; + else + m_rom_page &= 0xfd; // 11111101 + if (TRACE_CRU) logerror("bwg: set ROM page (bit 15) = %d, page = %d\n", bit, m_rom_page); + break; + + case 9: + case 12: + /* Unused (bit 3, 9 & 12) */ + if (TRACE_CRU) logerror("bwg: set unknown bit %d = %d\n", bit, data); + break; + } + } +} + +/* + Set the current drive. See also ti_fdc.c +*/ +void snug_bwg_device::set_drive() +{ + if (TRACE_CRU) logerror("bwg: new DSEL = %d\n", m_DSEL); + + if ((m_DSEL != 0) && (m_DSEL != 1) && (m_DSEL != 2) && (m_DSEL != 4) && (m_DSEL != 8)) + { + logerror("bwg: Warning - multiple drives selected\n"); + } + + // The schematics do not reveal any countermeasures against multiple selection + // so we assume that the highest value wins. + + int bits = m_DSEL & 0x0f; + int i = -1; + + while (bits != 0) + { + bits >>= 1; + i++; + } + if (i != -1) + { + m_current_floppy = m_floppy[i]; + if (TRACE_CRU) logerror("bwg: Selected floppy %d\n", i); + } + else + { + m_current_floppy = NULL; + if (TRACE_CRU) logerror("bwg: All drives deselected\n"); + } + m_wd1773->set_floppy(m_current_floppy); +} + +/* + Monoflop has gone back to the OFF state. +*/ +void snug_bwg_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + set_floppy_motors_running(false); +} + +/* + All floppy motors are operated by the same line. +*/ +void snug_bwg_device::set_floppy_motors_running(bool run) +{ + if (run) + { + if (TRACE_MOTOR) + if (m_MOTOR_ON==CLEAR_LINE) logerror("bwg: Motor START\n"); + m_MOTOR_ON = ASSERT_LINE; + m_motor_on_timer->adjust(attotime::from_msec(4230)); + } + else + { + if (TRACE_MOTOR) + if (m_MOTOR_ON==ASSERT_LINE) logerror("bwg: Motor STOP\n"); + m_MOTOR_ON = CLEAR_LINE; + } + + // The motor-on line is connected to pin 20 which is falsely called "MO" + // in the schematics; should be called "READY" as we are using the WD1773. + m_wd1773->set_force_ready(run); + + // Set all motors + for (int i=0; i < 4; i++) + if (m_floppy[i] != NULL) m_floppy[i]->mon_w((run)? 0 : 1); + + // The motor-on line also connects to the wait state logic + operate_ready_line(); +} + +void snug_bwg_device::device_start(void) +{ + logerror("bwg: BWG start\n"); + m_dsrrom = memregion(DSRROM)->base(); + m_buffer_ram = memregion(BUFFER)->base(); + m_motor_on_timer = timer_alloc(MOTOR_TIMER); + m_cru_base = 0x1100; +} + +void snug_bwg_device::device_reset() +{ + logerror("bwg: BWG reset\n"); + + if (m_genmod) + { + m_select_mask = 0x1fe000; + m_select_value = 0x174000; + } + else + { + m_select_mask = 0x7e000; + m_select_value = 0x74000; + } + + m_lastval = 0; + + m_DRQ = CLEAR_LINE; + m_IRQ = CLEAR_LINE; + m_MOTOR_ON = CLEAR_LINE; + + m_SIDSEL = CLEAR_LINE; + + m_wd1773->set_force_ready(false); + + m_DSEL = 0; + m_WAITena = false; + m_selected = false; + m_debug_dataout = false; + m_rtc_enabled = false; + m_dataregLB = false; + m_lastK = false; + m_RTCsel = false; + m_inDsrArea = false; + m_address = 0; + m_WDsel = false; + m_WDsel0 = false; + + for (int i=0; i < 4; i++) + { + if (m_floppy[i] != NULL) + logerror("bwg: Connector %d with %s\n", i, m_floppy[i]->name()); + else + logerror("bwg: Connector %d has no floppy attached\n", i); + } + + m_wd1773->set_floppy(m_current_floppy = m_floppy[0]); + + m_dip1 = ioport("BWGDIP1")->read(); + m_dip2 = ioport("BWGDIP2")->read(); + m_dip34 = ioport("BWGDIP34")->read(); + + m_rom_page = 0; + m_ram_page = 0; +} + +void snug_bwg_device::device_config_complete() +{ + for (int i=0; i < 4; i++) + m_floppy[i] = NULL; + + // Seems to be null when doing a "-listslots" + if (subdevice("0")!=NULL) m_floppy[0] = static_cast(subdevice("0")->first_subdevice()); + if (subdevice("1")!=NULL) m_floppy[1] = static_cast(subdevice("1")->first_subdevice()); + if (subdevice("2")!=NULL) m_floppy[2] = static_cast(subdevice("2")->first_subdevice()); + if (subdevice("3")!=NULL) m_floppy[3] = static_cast(subdevice("3")->first_subdevice()); +} + +INPUT_PORTS_START( bwg_fdc ) + PORT_START( "BWGDIP1" ) + PORT_DIPNAME( 0x01, 0x00, "BwG step rate" ) + PORT_DIPSETTING( 0x00, "6 ms") + PORT_DIPSETTING( 0x01, "20 ms") + + PORT_START( "BWGDIP2" ) + PORT_DIPNAME( 0x01, 0x00, "BwG date/time display" ) + PORT_DIPSETTING( 0x00, "Hide") + PORT_DIPSETTING( 0x01, "Show") + + PORT_START( "BWGDIP34" ) + PORT_DIPNAME( 0x03, 0x03, "BwG drives" ) + PORT_DIPSETTING( 0x00, "DSK1 only") + PORT_DIPSETTING( 0x01, "DSK1-DSK2") + PORT_DIPSETTING( 0x02, "DSK1-DSK3") + PORT_DIPSETTING( 0x03, "DSK1-DSK4") +INPUT_PORTS_END + +FLOPPY_FORMATS_MEMBER(snug_bwg_device::floppy_formats) + FLOPPY_TI99_SDF_FORMAT, + FLOPPY_TI99_TDF_FORMAT +FLOPPY_FORMATS_END + +static SLOT_INTERFACE_START( bwg_floppies ) + SLOT_INTERFACE( "525dd", FLOPPY_525_DD ) // 40 tracks + SLOT_INTERFACE( "525qd", FLOPPY_525_QD ) // 80 tracks + SLOT_INTERFACE( "35dd", FLOPPY_35_DD ) // 80 tracks +SLOT_INTERFACE_END + +MACHINE_CONFIG_FRAGMENT( bwg_fdc ) + MCFG_WD1773_ADD(FDC_TAG, XTAL_8MHz) + MCFG_WD_FDC_INTRQ_CALLBACK(WRITELINE(snug_bwg_device, fdc_irq_w)) + MCFG_WD_FDC_DRQ_CALLBACK(WRITELINE(snug_bwg_device, fdc_drq_w)) + + MCFG_DEVICE_ADD(CLOCK_TAG, MM58274C, 0) + MCFG_MM58274C_MODE24(1) // 24 hour + MCFG_MM58274C_DAY1(0) // sunday + + MCFG_FLOPPY_DRIVE_ADD("0", bwg_floppies, "525dd", snug_bwg_device::floppy_formats) + MCFG_FLOPPY_DRIVE_SOUND(true) + MCFG_FLOPPY_DRIVE_ADD("1", bwg_floppies, "525dd", snug_bwg_device::floppy_formats) + MCFG_FLOPPY_DRIVE_SOUND(true) + MCFG_FLOPPY_DRIVE_ADD("2", bwg_floppies, NULL, snug_bwg_device::floppy_formats) + MCFG_FLOPPY_DRIVE_SOUND(true) + MCFG_FLOPPY_DRIVE_ADD("3", bwg_floppies, NULL, snug_bwg_device::floppy_formats) + MCFG_FLOPPY_DRIVE_SOUND(true) +MACHINE_CONFIG_END + +ROM_START( bwg_fdc ) + ROM_REGION(0x8000, DSRROM, 0) + ROM_LOAD("bwg.bin", 0x0000, 0x8000, CRC(06f1ec89) SHA1(6ad77033ed268f986d9a5439e65f7d391c4b7651)) /* BwG disk DSR ROM */ + ROM_REGION(0x0800, BUFFER, 0) /* BwG RAM buffer */ + ROM_FILL(0x0000, 0x0400, 0x00) +ROM_END + +machine_config_constructor snug_bwg_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( bwg_fdc ); +} + +ioport_constructor snug_bwg_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( bwg_fdc ); +} + +const rom_entry *snug_bwg_device::device_rom_region() const +{ + return ROM_NAME( bwg_fdc ); +} + +const device_type TI99_BWG = &device_creator; diff --git a/src/devices/bus/ti99_peb/bwg.h b/src/devices/bus/ti99_peb/bwg.h new file mode 100644 index 00000000000..a1012e06257 --- /dev/null +++ b/src/devices/bus/ti99_peb/bwg.h @@ -0,0 +1,142 @@ +// license:LGPL-2.1+ +// copyright-holders:Michael Zapf +/**************************************************************************** + + SNUG BwG Disk Controller + Based on WD1770 + Double Density, Double-sided + + Michael Zapf, September 2010 + February 2012: Rewritten as class + +*****************************************************************************/ + +#ifndef __BWG__ +#define __BWG__ + +#include "imagedev/flopdrv.h" +#include "machine/mm58274c.h" +#include "machine/wd_fdc.h" + +extern const device_type TI99_BWG; + +class snug_bwg_device : public ti_expansion_card_device +{ +public: + snug_bwg_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + DECLARE_READ8Z_MEMBER(readz); + DECLARE_WRITE8_MEMBER(write); + DECLARE_SETADDRESS_DBIN_MEMBER(setaddress_dbin); + + DECLARE_WRITE_LINE_MEMBER( intrq_w ); + DECLARE_WRITE_LINE_MEMBER( drq_w ); + + DECLARE_READ8Z_MEMBER(crureadz); + DECLARE_WRITE8_MEMBER(cruwrite); + + DECLARE_FLOPPY_FORMATS( floppy_formats ); + + DECLARE_WRITE_LINE_MEMBER( fdc_irq_w ); + DECLARE_WRITE_LINE_MEMBER( fdc_drq_w ); + +protected: + void device_start(); + void device_reset(); + void device_config_complete(); + + const rom_entry *device_rom_region() const; + machine_config_constructor device_mconfig_additions() const; + ioport_constructor device_input_ports() const; + +private: + void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + // Debugger accessors + void debug_read(offs_t offset, UINT8* value); + void debug_write(offs_t offset, UINT8 data); + + // Wait state logic + void operate_ready_line(); + + // Set the current floppy + void set_drive(); + + // Holds the status of the DRQ and IRQ lines. + line_state m_DRQ, m_IRQ; + + // DIP switch state + int m_dip1, m_dip2, m_dip34; + + // Page selection for ROM and RAM + int m_ram_page; // 0-1 + int m_rom_page; // 0-3 + + // Operate the floppy motors + void set_floppy_motors_running(bool run); + + // When true, the READY line will be cleared (create wait states) when + // waiting for data from the controller. + bool m_WAITena; + + // Address in card area + bool m_inDsrArea; + + // WD selected + bool m_WDsel, m_WDsel0; + + // RTC selected + bool m_RTCsel; + + // last 1K area selected + bool m_lastK; + + // Data register +1 selected + bool m_dataregLB; + + // Indicates whether the clock is mapped into the address space. + bool m_rtc_enabled; + + // Signal motor_on. When TRUE, makes all drives turning. + line_state m_MOTOR_ON; + + // Needed for triggering the motor monoflop + UINT8 m_lastval; + + // Recent address + int m_address; + + /* Indicates which drive has been selected. Values are 0, 1, 2, and 4. */ + // 000 = no drive + // 001 = drive 1 + // 010 = drive 2 + // 100 = drive 3 + int m_DSEL; + + // Signal SIDSEL. 0 or 1, indicates the selected head. + line_state m_SIDSEL; + + // count 4.23s from rising edge of motor_on + emu_timer* m_motor_on_timer; + + // DSR ROM + UINT8* m_dsrrom; + + // Buffer RAM + UINT8* m_buffer_ram; + + // Link to the attached floppy drives + floppy_image_device* m_floppy[4]; + + // Currently selected floppy drive + floppy_image_device* m_current_floppy; + + // Link to the WD1773 controller on the board. + required_device m_wd1773; + + // Link to the real-time clock on the board. + required_device m_clock; + + // Debugging + bool m_debug_dataout; +}; +#endif diff --git a/src/devices/bus/ti99_peb/evpc.c b/src/devices/bus/ti99_peb/evpc.c new file mode 100644 index 00000000000..57b16fb9466 --- /dev/null +++ b/src/devices/bus/ti99_peb/evpc.c @@ -0,0 +1,369 @@ +// license:LGPL-2.1+ +// copyright-holders:Michael Zapf +/**************************************************************************** + SNUG Enhanced Video Processor Card (evpc) + based on v9938 (may also be equipped with v9958) + Can be used with TI-99/4A as an add-on card; internal VDP must be removed + + The SGCPU ("TI-99/4P") only runs with EVPC. + Michael Zapf + + October 2010: Rewritten as device + February 2012: Rewritten as class + + FIXME: Locks up on startup when HFDC is present. This can be avoided + by using another controller (like bwg) or doing a soft reset. + +*****************************************************************************/ + +#include "evpc.h" + +#define EVPC_CRU_BASE 0x1400 +#define VERBOSE 1 +#define LOG logerror + +#define NOVRAM_SIZE 256 + +snug_enhanced_video_device::snug_enhanced_video_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) +: ti_expansion_card_device(mconfig, TI99_EVPC, "SNUG Enhanced Video Processor Card", tag, owner, clock, "ti99_evpc", __FILE__), + device_nvram_interface(mconfig, *this) +{ +} + +//------------------------------------------------- +// nvram_default - called to initialize NVRAM to +// its default state +//------------------------------------------------- + +void snug_enhanced_video_device::nvram_default() +{ + memset(m_novram, 0, NOVRAM_SIZE); +} + +//------------------------------------------------- +// nvram_read - called to read NVRAM from the +// .nv file +//------------------------------------------------- + +void snug_enhanced_video_device::nvram_read(emu_file &file) +{ + file.read(m_novram, NOVRAM_SIZE); +} + +//------------------------------------------------- +// nvram_write - called to write NVRAM to the +// .nv file +//------------------------------------------------- + +void snug_enhanced_video_device::nvram_write(emu_file &file) +{ + file.write(m_novram, NOVRAM_SIZE); +} + + +/* + Read a byte in evpc DSR space + 0x4000 - 0x5eff DSR (paged) + 0x5f00 - 0x5fef NOVRAM + 0x5ff0 - 0x5fff Palette +*/ +READ8Z_MEMBER(snug_enhanced_video_device::readz) +{ + if (m_selected) + { + if ((offset & m_select_mask)==m_select_value) + { + if ((offset & 0x1ff0)==0x1ff0) // Palette control + { + switch (offset & 0x000f) + { + case 0: + /* Palette Read Address Register */ + *value = m_palette.write_index; + break; + + case 2: + /* Palette Read Color Value */ + if (m_palette.read) + { + switch (m_palette.state) + { + case 0: + *value = m_palette.color[m_palette.read_index].red; + break; + case 1: + *value = m_palette.color[m_palette.read_index].green; + break; + case 2: + *value = m_palette.color[m_palette.read_index].blue; + break; + } + m_palette.state++; + if (m_palette.state == 3) + { + m_palette.state = 0; + m_palette.read_index++; + } + } + break; + + case 4: + /* Palette Read Pixel Mask */ + *value = m_palette.mask; + break; + case 6: + /* Palette Read Address Register for Color Value */ + if (m_palette.read) + *value = 0; + else + *value = 3; + break; + } + } + else + { + if ((offset & 0x1f00)==0x1f00) + { + if (m_RAMEN) // NOVRAM hides DSR + { + *value = m_novram[offset & 0x00ff]; + } + else // DSR + { + *value = m_dsrrom[(offset&0x1fff) | (m_dsr_page<<13)]; + } + } + else + { + *value = m_dsrrom[(offset&0x1fff) | (m_dsr_page<<13)]; + } + } + } + } +} + +/* + Write a byte in evpc DSR space + 0x4000 - 0x5eff DSR (paged) + 0x5f00 - 0x5fef NOVRAM + 0x5ff0 - 0x5fff Palette +*/ +WRITE8_MEMBER(snug_enhanced_video_device::write) +{ + if (m_selected) + { + if ((offset & m_select_mask)==m_select_value) + { + if ((offset & 0x1ff0)==0x1ff0) + { + /* PALETTE */ + if (VERBOSE>5) LOG("palette write %04x <- %02x\n", offset&0xffff, data); + switch (offset & 0x000f) + { + case 0x08: + /* Palette Write Address Register */ + if (VERBOSE>5) LOG("EVPC palette address write (for write access)\n"); + m_palette.write_index = data; + m_palette.state = 0; + m_palette.read = 0; + break; + + case 0x0a: + /* Palette Write Color Value */ + if (VERBOSE>5) LOG("EVPC palette color write\n"); + if (!m_palette.read) + { + switch (m_palette.state) + { + case 0: + m_palette.color[m_palette.write_index].red = data; + break; + case 1: + m_palette.color[m_palette.write_index].green = data; + break; + case 2: + m_palette.color[m_palette.write_index].blue = data; + break; + } + m_palette.state++; + if (m_palette.state == 3) + { + m_palette.state = 0; + m_palette.write_index++; + } + //evpc_palette.dirty = 1; + } + break; + + case 0x0c: + /* Palette Write Pixel Mask */ + if (VERBOSE>5) LOG("EVPC palette mask write\n"); + m_palette.mask = data; + break; + + case 0x0e: + /* Palette Write Address Register for Color Value */ + if (VERBOSE>5) LOG("EVPC palette address write (for read access)\n"); + m_palette.read_index = data; + m_palette.state = 0; + m_palette.read = 1; + break; + } + } + else + { + if ((offset & 0x1f00)==0x1f00) + { + if (m_RAMEN) + { + // NOVRAM + m_novram[offset & 0x00ff] = data; + } + } + } + } + } +} + +/* + The CRU read handler. Read EVPC DIP switches + 0: Video timing (PAL/NTSC) + 1: - + 2: charset + 3: RAM shift + 4: - + 5: - + 6: - + 7: DIP or NOVRAM + Logic is inverted +*/ +READ8Z_MEMBER(snug_enhanced_video_device::crureadz) +{ + if ((offset & 0xff00)==EVPC_CRU_BASE) + { + if ((offset & 0x00f0)==0) // offset 0 delivers bits 0-7 (address 00-0f) + { + *value = ~(ioport("EVPC-SW1")->read() | (ioport("EVPC-SW3")->read()<<2) + | (ioport("EVPC-SW4")->read()<<3) | (ioport("EVPC-SW8")->read()<<7)); + } + } +} + +/* + The CRU write handler. + Bit 0: Turn on DSR ROM + Bit 1: DSR page select (bit 0) + Bit 2: - + Bit 3: RAM enable + Bit 4: DSR page select (bit 2) + Bit 5: DSR page select (bit 1) + Bit 6: - + Bit 7: - +*/ +WRITE8_MEMBER(snug_enhanced_video_device::cruwrite) +{ + if ((offset & 0xff00)==EVPC_CRU_BASE) + { + int bit = (offset >> 1) & 0x0f; + switch (bit) + { + case 0: + m_selected = (data!=0); + if (VERBOSE>4) LOG("evpc: Map DSR = %d\n", m_selected); + break; + + case 1: + if (data!=0) + m_dsr_page |= 1; + else + m_dsr_page &= ~1; + break; + + case 3: + m_RAMEN = (data!=0); + break; + + case 4: + if (data!=0) + m_dsr_page |= 4; + else + m_dsr_page &= ~4; + break; + + case 5: + if (data!=0) + m_dsr_page |= 2; + else + m_dsr_page &= ~2; + break; + + case 2: + case 6: + case 7: + break; + } + } +} + +void snug_enhanced_video_device::device_start() +{ + m_dsrrom = memregion(DSRROM)->base(); + m_novram = global_alloc_array(UINT8, NOVRAM_SIZE); +} + +void snug_enhanced_video_device::device_reset() +{ + if (VERBOSE>5) LOG("evpc: reset\n"); + m_select_mask = 0x7e000; + m_select_value = 0x74000; + m_dsr_page = 0; + m_RAMEN = false; + m_selected = false; +} + +void snug_enhanced_video_device::device_stop() +{ + global_free_array(m_novram); +} + +ROM_START( ti99_evpc ) + ROM_REGION(0x10000, DSRROM, 0) + ROM_LOAD("evpcdsr.bin", 0, 0x10000, CRC(a062b75d) SHA1(6e8060f86e3bb9c36f244d88825e3fe237bfe9a9)) /* evpc DSR ROM */ +ROM_END + +/* + Input ports for the EPVC +*/ +INPUT_PORTS_START( ti99_evpc ) + PORT_START( "EVPC-SW1" ) + PORT_DIPNAME( 0x01, 0x00, "EVPC video mode" ) PORT_CONDITION( "EVPC-SW8", 0x01, EQUALS, 0x00 ) + PORT_DIPSETTING( 0x00, "PAL" ) + PORT_DIPSETTING( 0x01, "NTSC" ) + + PORT_START( "EVPC-SW3" ) + PORT_DIPNAME( 0x01, 0x00, "EVPC charset" ) PORT_CONDITION( "EVPC-SW8", 0x01, EQUALS, 0x00 ) + PORT_DIPSETTING( 0x00, DEF_STR( International )) + PORT_DIPSETTING( 0x01, DEF_STR( German )) + + PORT_START( "EVPC-SW4" ) + PORT_DIPNAME( 0x01, 0x00, "EVPC VDP RAM" ) PORT_CONDITION( "EVPC-SW8", 0x01, EQUALS, 0x00 ) + PORT_DIPSETTING( 0x00, "shifted" ) + PORT_DIPSETTING( 0x01, "not shifted" ) + + PORT_START( "EVPC-SW8" ) + PORT_DIPNAME( 0x01, 0x00, "EVPC Configuration" ) + PORT_DIPSETTING( 0x00, "DIP" ) + PORT_DIPSETTING( 0x01, "NOVRAM" ) +INPUT_PORTS_END + +const rom_entry *snug_enhanced_video_device::device_rom_region() const +{ + return ROM_NAME( ti99_evpc ); +} + +ioport_constructor snug_enhanced_video_device::device_input_ports() const +{ + return INPUT_PORTS_NAME(ti99_evpc); +} + +const device_type TI99_EVPC = &device_creator; diff --git a/src/devices/bus/ti99_peb/evpc.h b/src/devices/bus/ti99_peb/evpc.h new file mode 100644 index 00000000000..86ec224246e --- /dev/null +++ b/src/devices/bus/ti99_peb/evpc.h @@ -0,0 +1,62 @@ +// license:LGPL-2.1+ +// copyright-holders:Michael Zapf +/**************************************************************************** + + SNUG Enhanced Video Processor Card (evpc) + See evpc.c for documentation. + + Michael Zapf + + October 2010: Rewritten as device + February 2012: Rewritten as class + +*****************************************************************************/ + +#ifndef __EVPC__ +#define __EVPC__ + +#include "emu.h" +#include "peribox.h" + +extern const device_type TI99_EVPC; + +struct evpc_palette +{ + UINT8 read_index, write_index, mask; + int read; + int state; + struct { UINT8 red, green, blue; } color[0x100]; + //int dirty; +}; + +class snug_enhanced_video_device : public ti_expansion_card_device, public device_nvram_interface +{ +public: + snug_enhanced_video_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + DECLARE_READ8Z_MEMBER(readz); + DECLARE_WRITE8_MEMBER(write); + + DECLARE_READ8Z_MEMBER(crureadz); + DECLARE_WRITE8_MEMBER(cruwrite); + +protected: + virtual void device_start(void); + virtual void device_reset(void); + virtual void device_stop(void); + + virtual const rom_entry *device_rom_region() const; + virtual ioport_constructor device_input_ports() const; + + void nvram_default(); + void nvram_read(emu_file &file); + void nvram_write(emu_file &file); + +private: + UINT8* m_dsrrom; + bool m_RAMEN; + int m_dsr_page; + UINT8* m_novram; /* NOVRAM area */ + evpc_palette m_palette; +}; + +#endif diff --git a/src/devices/bus/ti99_peb/hfdc.c b/src/devices/bus/ti99_peb/hfdc.c new file mode 100644 index 00000000000..62f31b7d141 --- /dev/null +++ b/src/devices/bus/ti99_peb/hfdc.c @@ -0,0 +1,1079 @@ +// license:LGPL-2.1+ +// copyright-holders:Michael Zapf +/**************************************************************************** + + Myarc Hard and Floppy Disk Controller ("HFDC") + + The HFDC is based on the HDC9234 controller chip from Standard + Microsystems Corporation (SMC). It can work with up to three MFM hard disk + drives and up to four floppy disk drives. + + Data flow is detached from the main CPU. The HDC transfers data to/from + the drives using direct memory access to attached memory circuits. That + is, to write a sector on a drive the CPU must set up the contents in the + memory, then initiate a sector write operation. + + The advantage is a much higher data rate (in particular important when + working with hard disks) with less load for the main CPU. Also, we do not + need a READY line control (as seen with the WD17xx-based controllers). + Any kinds of asynchronous events are propagated via INTA* (configurable + to INTB*). + + Most of the control logic is hidden in the custom Gate Array chip. We do + not have details on its contents, but the specifications in the HFDC manual + and in the schematics are sufficient to create a (functionally) proper + emulation. + + The HDC9234 can also control tape drives. In early HFDC controller card + layouts, a socket for connecting a drive is available. However, there + never was a support from the DSR (firmware), so this feature was eliminated + in later releases. + + DIP switches + - Settings for step rate and track count for each floppy drive (DSK1-DSK4) + - CRU base address. Note that only on all other addresses than 1100, the + floppy drives are labeled DSK5-DSK8 by the card software. + + + Components + + HDC 9234 - Universal Disk Controller + FDC 9216 - Floppy disk data separator (8 MHz, divider is set by CD0 and CD1) + HDC 92C26 - MFM hard disk data separator (10 MHz, also used for 9234) + HDC 9223 - Analog data separator support + DS 1000-50 - Delay circuit + MM 58274BN - Real time clock + HM 6264-LP15 - SRAM 8K x 8 (may also be 32K x 8) + 27C128 - EPROM 16K x 8 + + References: + [1] Myarc Inc.: Hard and Floppy Disk Controller / Users Manual + + Michael Zapf + July 2015 + +*****************************************************************************/ + +#include "emu.h" +#include "peribox.h" +#include "hfdc.h" +#include "formats/mfm_hd.h" +#include "formats/ti99_dsk.h" // Format + +#define BUFFER "ram" +#define FDC_TAG "hdc9234" +#define CLOCK_TAG "mm58274c" + +#define MOTOR_TIMER 1 + +#define TAPE_ADDR 0x0fc0 +#define HDC_R_ADDR 0x0fd0 +#define HDC_W_ADDR 0x0fd2 +#define CLK_ADDR 0x0fe0 +#define RAM_ADDR 0x1000 + +#define TRACE_EMU 0 +#define TRACE_CRU 0 +#define TRACE_COMP 0 +#define TRACE_RAM 0 +#define TRACE_ROM 0 +#define TRACE_LINES 0 +#define TRACE_MOTOR 0 +#define TRACE_DMA 0 +#define TRACE_INT 0 + +// ========================================================================= + +/* + Constructor for the HFDC card. +*/ +myarc_hfdc_device::myarc_hfdc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : ti_expansion_card_device(mconfig, TI99_HFDC, "Myarc Hard and Floppy Disk Controller", tag, owner, clock, "ti99_hfdc", __FILE__), + m_hdc9234(*this, FDC_TAG), + m_clock(*this, CLOCK_TAG) +{ +} + +SETADDRESS_DBIN_MEMBER( myarc_hfdc_device::setaddress_dbin ) +{ + // Do not allow setaddress for the debugger. It will mess up the + // setaddress/memory access pairs when the CPU enters wait states. + if (space.debugger_access()) return; + + // Selection login in the PAL and some circuits on the board + + // Is the card being selected? + // Area = 4000-5fff + // 010x xxxx xxxx xxxx + m_address = offset; + + m_inDsrArea = ((m_address & m_select_mask)==m_select_value); + + if (!m_inDsrArea) return; + + // Is the HDC chip on the card being selected? + // HDC9234: read: 4fd0,4 (mirror 8,c) + // HDC9234: write: 4fd2,6 (mirror a,e) + // read: ...0 1111 1101 xx00 + // write: ...0 1111 1101 xx10 + + m_HDCsel = m_inDsrArea && + ((state==ASSERT_LINE && ((m_address & 0x1ff3)==HDC_R_ADDR)) // read + || (state==CLEAR_LINE && ((m_address & 0x1ff3)==HDC_W_ADDR))); // write + + // Is the tape selected? + // ...0 1111 1100 xxxx + m_tapesel = m_inDsrArea && ((m_address & 0x1ff0)==TAPE_ADDR); + + // Is the RTC selected on the card? (even addr) + // ...0 1111 111x xxx0 + m_RTCsel = m_inDsrArea && ((m_address & 0x1fe1)==CLK_ADDR); + + // Is RAM selected? + // ...1 xxxx xxxx xxxx + m_RAMsel = m_inDsrArea && ((m_address & 0x1000)==RAM_ADDR); + + // Is ROM selected? + // not 0100 1111 11xx xxxx + m_ROMsel = m_inDsrArea && !m_RAMsel && !((m_address & 0x0fc0)==0x0fc0); +} + +/* + Access for debugger. This is a stripped-down version of the + main methods below. We only allow ROM and RAM access. +*/ +void myarc_hfdc_device::debug_read(offs_t offset, UINT8* value) +{ + if (((offset & m_select_mask)==m_select_value) && m_selected) + { + if ((offset & 0x1000)==RAM_ADDR) + { + int bank = (offset & 0x0c00) >> 10; + *value = m_buffer_ram[(m_ram_page[bank]<<10) | (offset & 0x03ff)]; + } + else + { + if ((offset & 0x0fc0)!=0x0fc0) + { + *value = m_dsrrom[(m_rom_page << 12) | (offset & 0x0fff)]; + } + } + } +} + +void myarc_hfdc_device::debug_write(offs_t offset, UINT8 data) +{ + if (((offset & m_select_mask)==m_select_value) && m_selected) + { + if ((offset & 0x1000)==RAM_ADDR) + { + int bank = (offset & 0x0c00) >> 10; + m_buffer_ram[(m_ram_page[bank]<<10) | (m_address & 0x03ff)] = data; + } + } +} + +/* + Read a byte from the memory address space of the HFDC + + 0x4000 - 0x4fbf one of four possible ROM pages + 0x4fc0 - 0x4fcf Tape control (only available in prototype HFDC models) + 0x4fd0 - 0x4fdf HDC 9234 ports + 0x4fe0 - 0x4fff RTC chip ports + + 0x5000 - 0x53ff static RAM page 0x08 + 0x5400 - 0x57ff static RAM page any of 32 pages + 0x5800 - 0x5bff static RAM page any of 32 pages + 0x5c00 - 0x5fff static RAM page any of 32 pages + + HFDC manual, p. 44 +*/ +READ8Z_MEMBER(myarc_hfdc_device::readz) +{ + if (space.debugger_access()) + { + debug_read(offset, value); + return; + } + + if (m_inDsrArea && m_selected) + { + if (m_tapesel) + { + logerror("%s: Tape support not available on this HFDC version (access to address %04x)\n", tag(), m_address & 0xffff); + return; + } + + if (m_HDCsel) + { + *value = m_hdc9234->read(space, (m_address>>2)&1, 0xff); + if (TRACE_COMP) logerror("%s: %04x[HDC] -> %02x\n", tag(), m_address & 0xffff, *value); + return; + } + + if (m_RTCsel) + { + *value = m_clock->read(space, (m_address & 0x001e) >> 1); + if (TRACE_COMP) logerror("%s: %04x[CLK] -> %02x\n", tag(), m_address & 0xffff, *value); + return; + } + + if (m_RAMsel) + { + // 0101 00xx xxxx xxxx static 0x08 + // 0101 01xx xxxx xxxx bank 1 + // 0101 10xx xxxx xxxx bank 2 + // 0101 11xx xxxx xxxx bank 3 + int bank = (m_address & 0x0c00) >> 10; + + // If a DMA is in progress, do not respond + if (m_dip == CLEAR_LINE) *value = m_buffer_ram[(m_ram_page[bank]<<10) | (m_address & 0x03ff)]; + if (TRACE_RAM) + { + if ((m_address & 1)==0) // only show even addresses with words + { + int valword = (((*value) << 8) | m_buffer_ram[(m_ram_page[bank]<<10) | ((m_address+1) & 0x03ff)])&0xffff; + logerror("%s: %04x[%02x] -> %04x\n", tag(), m_address & 0xffff, m_ram_page[bank], valword); + } + } + return; + } + + if (m_ROMsel) + { + *value = m_dsrrom[(m_rom_page << 12) | (m_address & 0x0fff)]; + if (TRACE_ROM) + { + if ((m_address & 1)==0) // only show even addresses with words + { + int valword = (((*value) << 8) | m_dsrrom[(m_rom_page << 12) | ((m_address + 1) & 0x0fff)])&0xffff; + logerror("%s: %04x[%02x] -> %04x\n", tag(), m_address & 0xffff, m_rom_page, valword); + } + } + return; + } + } +} + +/* + Write a byte to the memory address space of the HFDC + + 0x4fc0 - 0x4fcf Tape control (only available in prototype HFDC models) + 0x4fd0 - 0x4fdf HDC 9234 ports + 0x4fe0 - 0x4fff RTC chip ports + + 0x5000 - 0x53ff static RAM page 0x08 + 0x5400 - 0x57ff static RAM page any of 32 pages + 0x5800 - 0x5bff static RAM page any of 32 pages + 0x5c00 - 0x5fff static RAM page any of 32 pages +*/ +WRITE8_MEMBER( myarc_hfdc_device::write ) +{ + if (space.debugger_access()) + { + debug_write(offset, data); + return; + } + + if (m_inDsrArea && m_selected) + { + if (m_tapesel) + { + logerror("%s: Tape support not available on this HFDC version (write access to address %04x: %02x)\n", tag(), m_address & 0xffff, data); + return; + } + + if (m_HDCsel) + { + if (TRACE_COMP) logerror("%s: %04x[HDC] <- %02x\n", tag(), m_address & 0xffff, data); + m_hdc9234->write(space, (m_address>>2)&1, data, 0xff); + return; + } + + if (m_RTCsel) + { + if (TRACE_COMP) logerror("%s: %04x[CLK] <- %02x\n", tag(), m_address & 0xffff, data); + m_clock->write(space, (m_address & 0x001e) >> 1, data); + return; + } + + if (m_RAMsel) + { + // 0101 00xx xxxx xxxx static 0x08 + // 0101 01xx xxxx xxxx bank 1 + // 0101 10xx xxxx xxxx bank 2 + // 0101 11xx xxxx xxxx bank 3 + int bank = (m_address & 0x0c00) >> 10; + if (TRACE_RAM) logerror("%s: %04x[%02x] <- %02x\n", tag(), m_address & 0xffff, m_ram_page[bank], data); + + // When a DMA is in progress, do not change anything + if (m_dip == CLEAR_LINE) m_buffer_ram[(m_ram_page[bank]<<10) | (m_address & 0x03ff)] = data; + return; + } + // The rest is ROM + if (m_ROMsel) + { + if (TRACE_ROM) logerror("%s: Ignoring write ROM %04x[%02x]: %02x\n", tag(), m_address & 0xffff, m_rom_page, data); + } + } +} + +/* + Read a set of 8 bits in the CRU space of the HFDC + There are two banks, according to the state of m_see_switches + + m_see_switches == true: + + 7 6 5 4 3 2 1 0 CRU bit + +-----+-----+-----+-----+-----+-----+-----+-----+ + |DIP5*|DIP6*|DIP7*|DIP8*|DIP1*|DIP2*|DIP3*|DIP4*| + +-----+-----+-----+-----+-----+-----+-----+-----+ + | DSK3 | DSK4 | DSK1 | DSK2 | + +-----+-----+-----+-----+-----+-----+-----+-----+ + + Settings for DSKn: (n=1..4) + + DIP(2n-1) DIP(2n) Tracks Step(ms) Sectors (256 byte) + off off 40 16 18/16/9 + on off 40 8 18/16/9 + off on 80/40 2 18/16/9 + on on 80 2 36 + + Inverted logic: switch=on means a 0 bit, off is a 1 bit when read by the CRU + + Caution: The last setting is declared as "future expansion" and is + locked to a 1.44 MiB capacity. No lower formats can be used. + + --- + + m_see_switches == false: + + 7 6 5 4 3 2 1 0 + +-----+-----+-----+-----+-----+-----+-----+-----+ + | 0 | 0 | 0 | 0 | WAIT| MON*| DIP | IRQ | + +-----+-----+-----+-----+-----+-----+-----+-----+ + + WAIT = Wait for WDS1 to become ready + MON* = Motor on + DIP = DMA in progress + IRQ = Interrupt request + --- + 0 on all other locations +*/ +READ8Z_MEMBER(myarc_hfdc_device::crureadz) +{ + UINT8 reply; + if ((offset & 0xff00)==m_cru_base) + { + if ((offset & 0x00ff)==0) // CRU bits 0-7 + { + if (m_see_switches) + { + reply = ~(ioport("HFDCDIP")->read()); + } + else + { + reply = 0; + if (m_irq == ASSERT_LINE) reply |= 0x01; + if (m_dip == ASSERT_LINE) reply |= 0x02; + if (!m_motor_running) reply |= 0x04; + if (m_wait_for_hd1) reply |= 0x08; + } + *value = reply; + } + else // CRU bits 8+ + { + *value = 0; + } + + if (TRACE_CRU) logerror("%s: CRU %04x -> %02x\n", tag(), offset & 0xffff, *value); + } +} + +/* + Set a bit in the CRU space of the HFDC + + 7 6 5 4 3 2 1 0 + +-----+-----+-----+-----+-----+-----+-----+-----+ + | - | - | - | ROM1| ROM0| MON | RES*| SEL | + | | | | CSEL| CD1 | CD0 | | | + +-----+-----+-----+-----+-----+-----+-----+-----+ + + 17 16 15 14 13 12 11 10 F E D C B A 9 8 + +-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+ + | RAM page select @5C00 | RAM page select @5800 | RAM page select @5400 | - | + +-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+ + + SEL = Select card (and map ROM into address space) + RES* = Reset controller + MON = Motor on / same line goes to CD0 input of floppy separator + ROM bank select: bank 0..3; bit 3 = MSB, 4 = LSB + RAM bank select: bank 0..31; bit 9 = LSB (accordingly for other two areas) + CD0 and CD1 are Clock Divider selections for the Floppy Data Separator (FDC9216) + CSEL = CRU input select (m_see_switches) + + HFDC manual p. 43 +*/ +WRITE8_MEMBER(myarc_hfdc_device::cruwrite) +{ + if ((offset & 0xff00)==m_cru_base) + { + if (TRACE_CRU) logerror("%s: CRU %04x <- %d\n", tag(), offset & 0xffff, data); + + int bit = (offset >> 1) & 0x1f; + + // Handle the page selects right here + if (bit >= 0x09 && bit < 0x18) + { + if (data) + // we leave index 0 unchanged; modify indices 1-3 + m_ram_page[(bit-4)/5] |= 1 << ((bit-9)%5); + else + m_ram_page[(bit-4)/5] &= ~(1 << ((bit-9)%5)); + + if (TRACE_CRU) + { + if (bit==0x0d) logerror("%s: RAM page @5400 = %d\n", tag(), m_ram_page[1]); + if (bit==0x12) logerror("%s: RAM page @5800 = %d\n", tag(), m_ram_page[2]); + if (bit==0x17) logerror("%s: RAM page @5C00 = %d\n", tag(), m_ram_page[3]); + } + return; + } + + switch (bit) + { + case 0: + { + bool turnOn = (data!=0); + // Avoid too many meaningless log outputs + if (TRACE_CRU) if (m_selected != turnOn) logerror("%s: card %s\n", tag(), turnOn? "selected" : "unselected"); + m_selected = turnOn; + break; + } + case 1: + if (TRACE_CRU) if (data==0) logerror("%s: trigger HDC reset\n", tag()); + m_hdc9234->reset((data == 0)? ASSERT_LINE : CLEAR_LINE); + break; + + case 2: + m_hdc9234->set_clock_divider(0, data); + + // Activate motor + // When 1, let motor run continuously. When 0, a simple monoflop circuit keeps the line active for another 4 sec + if (data==1) + { + m_motor_on_timer->reset(); + set_floppy_motors_running(true); + } + else + { + m_motor_on_timer->adjust(attotime::from_msec(4230)); + } + m_lastval = data; + break; + + case 3: + m_hdc9234->set_clock_divider(1, data); + m_rom_page = (data != 0)? (m_rom_page | 2) : (m_rom_page & 0xfd); + if (TRACE_CRU) logerror("%s: ROM page = %d\n", tag(), m_rom_page); + break; + + case 4: + m_see_switches = (data != 0); + m_rom_page = (data != 0)? (m_rom_page | 1) : (m_rom_page & 0xfe); + if (TRACE_CRU) logerror("%s: ROM page = %d, see_switches = %d\n", tag(), m_rom_page, m_see_switches); + break; + + default: + logerror("%s: Attempt to set undefined CRU bit %d\n", tag(), bit); + } + } +} + +/* + Monoflop has gone back to the OFF state. +*/ +void myarc_hfdc_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + set_floppy_motors_running(false); +} + +/* + This is called back from the floppy when an index hole is passing by. +*/ +void myarc_hfdc_device::floppy_index_callback(floppy_image_device *floppy, int state) +{ + if (TRACE_LINES) if (state==1) logerror("%s: Floppy index pulse\n", tag()); + // m_status_latch = (state==ASSERT_LINE)? (m_status_latch | HDC_DS_INDEX) : (m_status_latch & ~HDC_DS_INDEX); + set_bits(m_status_latch, HDC_DS_INDEX, (state==ASSERT_LINE)); + signal_drive_status(); +} + +/* + This is called back from the hard disk when an index hole is passing by. +*/ +void myarc_hfdc_device::harddisk_index_callback(mfm_harddisk_device *harddisk, int state) +{ + if (TRACE_LINES) if (state==1) logerror("%s: HD index pulse\n", tag()); + set_bits(m_status_latch, HDC_DS_INDEX, (state==ASSERT_LINE)); + signal_drive_status(); +} + +/* + This is called back from the hard disk when READY becomes asserted. +*/ +void myarc_hfdc_device::harddisk_ready_callback(mfm_harddisk_device *harddisk, int state) +{ + if (TRACE_LINES) logerror("%s: HD READY = %d\n", tag(), state); + set_bits(m_status_latch, HDC_DS_READY, (state==ASSERT_LINE)); + signal_drive_status(); +} + +/* + This is called back from the hard disk when seek_complete becomes asserted. +*/ +void myarc_hfdc_device::harddisk_skcom_callback(mfm_harddisk_device *harddisk, int state) +{ + if (TRACE_LINES) logerror("%s: HD seek complete = %d\n", tag(), state); + set_bits(m_status_latch, HDC_DS_SKCOM, (state==ASSERT_LINE)); + signal_drive_status(); +} + +void myarc_hfdc_device::set_bits(UINT8& byte, int mask, bool set) +{ + if (set) byte |= mask; + else byte &= ~mask; +} + +/* + Maps the set bit to an index. The rightmost 1 bit is significant. When no + bit is set, returns -1. +*/ +int myarc_hfdc_device::bit_to_index(int value) +{ + if (value & 0x01) return 0; + if (value & 0x02) return 1; + if (value & 0x04) return 2; + if (value & 0x08) return 3; + return -1; +} + +/* + Notify the controller about the status change +*/ +void myarc_hfdc_device::signal_drive_status() +{ + UINT8 reply = 0; + // Status byte as defined by HDC9234 + // +------+------+------+------+------+------+------+------+ + // | ECC |Index | SeekC| Tr00 | User | WrPrt| Ready|Fault | + // +------+------+------+------+------+------+------+------+ + // + // Set by HFDC + // 74LS240 is used for driving the lines; it also inverts the inputs + // If no hard drive or floppy is connected, all lines are 0 + // +------+------+------+------+------+------+------+------+ + // | 0 | Index| SeekC| Tr00 | 0 | WrPrt| Ready|Fault | + // +------+------+------+------+------+------+------+------+ + // + // Ready = /WDS.ready* | DSK + // SeekComplete = /WDS.seekComplete* | DSK + + // If DSK is selected, set Ready and SeekComplete to 1 + if ((m_output1_latch & 0x10)!=0) + { + reply |= 0x22; + + // Check for TRK00* + if ((m_current_floppy != NULL) && (!m_current_floppy->trk00_r())) + reply |= HDC_DS_TRK00; + } + else + { + if ((m_output1_latch & 0xe0)!=0) + { + if (m_current_harddisk != NULL) + { + if (m_current_harddisk->ready_r()==ASSERT_LINE) + { + m_status_latch |= HDC_DS_READY; + set_bits(m_status_latch, HDC_DS_SKCOM, m_current_harddisk->seek_complete_r()==ASSERT_LINE); + set_bits(m_status_latch, HDC_DS_TRK00, m_current_harddisk->trk00_r()==ASSERT_LINE); + } + } + // If WDS is selected but not connected, WDS.ready* and WDS.seekComplete* are 1, so Ready=SeekComplete=0 + else set_bits(m_status_latch, HDC_DS_READY | HDC_DS_SKCOM, false); + } + } + + reply |= m_status_latch; + + m_hdc9234->auxbus_in(reply); +} + +/* + When the HDC outputs a byte via its AB (auxiliary bus), we need to latch it. + The target of the transfer is determined by two control lines (S1,S0). + (0,0) = input drive status + (0,1) = DMA address + (1,0) = OUTPUT1 + (1,1) = OUTPUT2 +*/ +WRITE8_MEMBER( myarc_hfdc_device::auxbus_out ) +{ + int index; + switch (offset) + { + case HDC_INPUT_STATUS: + logerror("%s: Invalid operation: S0=S1=0, but tried to write (expected: read drive status)\n", tag()); + break; + + case HDC_OUTPUT_DMA_ADDR: + // Value is dma address byte. Shift previous contents to the left. + // The value is latched inside the Gate Array. + m_dma_address = ((m_dma_address << 8) + (data&0xff))&0xffffff; + if (TRACE_DMA) logerror("%s: Setting DMA address; current value = %06x\n", tag(), m_dma_address); + break; + + case HDC_OUTPUT_1: + // value is output1 + // The HFDC interprets the value as follows: + // WDS = Winchester Drive System, old name for hard disk + // +------+------+------+------+------+------+------+------+ + // | WDS3 | WDS2 | WDS1 | DSKx | x=4 | x=3 | x=2 | x=1 | + // +------+------+------+------+------+------+------+------+ + // Accordingly, drive 0 is always the floppy; selected by the low nibble + + m_output1_latch = data; + + if ((data & 0x10) != 0) connect_floppy_unit(bit_to_index(data & 0x0f)); // Floppy selected + else + { + index = bit_to_index((data>>4) & 0x0f); + + if (index > 0) connect_harddisk_unit(index-1); // HD selected; index >= 1 + else + { + disconnect_floppy_drives(); + disconnect_hard_drives(); + + // Turn off READY and SEEK COMPLETE + set_bits(m_status_latch, HDC_DS_READY | HDC_DS_SKCOM, false); + } + } + break; + + case HDC_OUTPUT_2: + // value is output2 + // DS3* = /WDS3 + // WCur = Reduced Write Current + // Dir = Step direction + // Step = Step pulse + // Head = Selected head number (floppy: 0000 or 0001) + // +------+------+------+------+------+------+------+------+ + // | DS3* | WCur | Dir | Step | Head | + // +------+------+------+------+------+------+------+------+ + m_output2_latch = data; + + // Output the step pulse to the selected floppy drive + if (m_current_floppy != NULL) + { + m_current_floppy->ss_w(data & 0x01); + m_current_floppy->dir_w((data & 0x20)==0); + m_current_floppy->stp_w((data & 0x10)==0); + } + + if (m_current_harddisk != NULL) + { + // Dir = 0 -> outward + m_current_harddisk->direction_in_w((data & 0x20)? ASSERT_LINE : CLEAR_LINE); + m_current_harddisk->step_w((data & 0x10)? ASSERT_LINE : CLEAR_LINE); + m_current_harddisk->headsel_w(data & 0x0f); + } + + // We are pushing the drive status after OUTPUT2 + signal_drive_status(); + break; + } +} + +enum +{ + HFDC_FLOPPY = 1, + HFDC_HARDDISK = 2 +}; + +void myarc_hfdc_device::connect_floppy_unit(int index) +{ + // Check if we have a new floppy + if (m_floppy_unit[index] != m_current_floppy) + { + // Clear all latched flags from other drives + m_status_latch = 0; + disconnect_floppy_drives(); + if (TRACE_LINES) logerror("%s: Select floppy drive DSK%d\n", tag(), index+1); + + // Connect new drive + m_current_floppy = m_floppy_unit[index]; + + // We don't use the READY line of floppy drives. + // READY is asserted when DSKx = 1 + // The controller fetches the state with the auxbus access + if (TRACE_LINES) logerror("%s: Connect index callback DSK%d\n", tag(), index+1); + if (m_current_floppy != NULL) + m_current_floppy->setup_index_pulse_cb(floppy_image_device::index_pulse_cb(FUNC(myarc_hfdc_device::floppy_index_callback), this)); + else + logerror("%s: Connection to DSK%d failed because no drive is connected\n", tag(), index+1); + m_hdc9234->connect_floppy_drive(m_floppy_unit[index]); + } + + // We can only run a floppy or a harddisk at a time, not both + disconnect_hard_drives(); +} + +void myarc_hfdc_device::connect_harddisk_unit(int index) +{ + if (m_harddisk_unit[index] != m_current_harddisk) + { + // Clear all latched flags form other drives + m_status_latch = 0; + disconnect_hard_drives(); + if (TRACE_LINES) logerror("%s: Select hard disk WDS%d\n", tag(), index+1); + + // Connect new drive + m_current_harddisk = m_harddisk_unit[index]; + + if (TRACE_LINES) logerror("%s: Connect index callback WDS%d\n", tag(), index+1); + if (m_current_harddisk != NULL) + { + m_current_harddisk->setup_index_pulse_cb(mfm_harddisk_device::index_pulse_cb(FUNC(myarc_hfdc_device::harddisk_index_callback), this)); + m_current_harddisk->setup_ready_cb(mfm_harddisk_device::ready_cb(FUNC(myarc_hfdc_device::harddisk_ready_callback), this)); + m_current_harddisk->setup_seek_complete_cb(mfm_harddisk_device::seek_complete_cb(FUNC(myarc_hfdc_device::harddisk_skcom_callback), this)); + } + else + logerror("%s: Connection to WDS%d failed because no drive is connected\n", tag(), index+1); + m_hdc9234->connect_hard_drive(m_current_harddisk); + } + + // We can only run a floppy or a harddisk at a time, not both + disconnect_floppy_drives(); +} + +void myarc_hfdc_device::disconnect_floppy_drives() +{ + if (TRACE_LINES) logerror("%s: Unselect floppy drives\n", tag()); + // Disconnect current floppy + if (m_current_floppy != NULL) + { + m_current_floppy->setup_index_pulse_cb(floppy_image_device::index_pulse_cb()); + m_current_floppy = NULL; + } +} + +void myarc_hfdc_device::disconnect_hard_drives() +{ + if (TRACE_LINES) logerror("%s: Unselect hard drives\n", tag()); + if (m_current_harddisk != NULL) + { + m_current_harddisk->setup_index_pulse_cb(mfm_harddisk_device::index_pulse_cb()); + m_current_harddisk->setup_seek_complete_cb(mfm_harddisk_device::seek_complete_cb()); + m_current_harddisk = NULL; + } +} + +/* + All floppy motors are operated by the same line. +*/ +void myarc_hfdc_device::set_floppy_motors_running(bool run) +{ + if (run) + { + if (TRACE_MOTOR) + if (m_MOTOR_ON==CLEAR_LINE) logerror("%s: Motor START\n", tag()); + m_MOTOR_ON = ASSERT_LINE; + } + else + { + if (TRACE_MOTOR) + if (m_MOTOR_ON==ASSERT_LINE) logerror("%s: Motor STOP\n", tag()); + m_MOTOR_ON = CLEAR_LINE; + } + + // Set all motors + for (int i=0; i < 4; i++) + if (m_floppy_unit[i] != NULL) m_floppy_unit[i]->mon_w((run)? 0 : 1); +} + +/* + Called whenever the state of the HDC9234 interrupt pin changes. +*/ +WRITE_LINE_MEMBER( myarc_hfdc_device::intrq_w ) +{ + m_irq = (line_state)state; + if (TRACE_INT) logerror("%s: INT pin from controller = %d, propagating to INTA*\n", tag(), state); + + // Set INTA* + // Signal from SMC is active high, INTA* is active low; board inverts signal + // Anyway, we stay with ASSERT_LINE and CLEAR_LINE + m_slot->set_inta(state); +} + +/* + Called whenever the HDC9234 desires bus access to the buffer RAM. The + controller expects a call to dmarq in 1 byte time. +*/ +WRITE_LINE_MEMBER( myarc_hfdc_device::dmarq_w ) +{ + if (TRACE_DMA) logerror("%s: DMARQ pin from controller = %d\n", tag(), state); + if (state == ASSERT_LINE) + { + m_hdc9234->dmaack(ASSERT_LINE); + } +} + +/* + Called whenever the state of the HDC9234 DMA in progress changes. +*/ +WRITE_LINE_MEMBER( myarc_hfdc_device::dip_w ) +{ + m_dip = (line_state)state; +} + +/* + Read a byte from the onboard SRAM. This is called from the HDC9234. +*/ +READ8_MEMBER( myarc_hfdc_device::read_buffer ) +{ + if (TRACE_DMA) logerror("%s: Read access to onboard SRAM at %04x\n", tag(), m_dma_address); + if (m_dma_address > 0x8000) logerror("%s: Read access beyond RAM size: %06x\n", tag(), m_dma_address); + UINT8 value = m_buffer_ram[m_dma_address & 0x7fff]; + m_dma_address = (m_dma_address+1) & 0x7fff; + return value; +} + +/* + Write a byte to the onboard SRAM. This is called from the HDC9234. +*/ +WRITE8_MEMBER( myarc_hfdc_device::write_buffer ) +{ + if (TRACE_DMA) logerror("%s: Write access to onboard SRAM at %04x: %02x\n", tag(), m_dma_address, data); + if (m_dma_address > 0x8000) logerror("%s: Write access beyond RAM size: %06x\n", tag(), m_dma_address); + m_buffer_ram[m_dma_address & 0x7fff] = data; + m_dma_address = (m_dma_address+1) & 0x7fff; +} + +void myarc_hfdc_device::device_start() +{ + if (TRACE_EMU) logerror("%s: start\n", tag()); + m_dsrrom = memregion(DSRROM)->base(); + m_buffer_ram = memregion(BUFFER)->base(); + m_motor_on_timer = timer_alloc(MOTOR_TIMER); + // The HFDC does not use READY; it has on-board RAM for DMA + m_current_floppy = NULL; + m_current_harddisk = NULL; +} + +void myarc_hfdc_device::device_reset() +{ + if (TRACE_EMU) logerror("%s: reset\n", tag()); + + // The GenMOD mod; our implementation automagically adapts all cards + if (m_genmod) + { + m_select_mask = 0x1fe000; + m_select_value = 0x174000; + } + else + { + m_select_mask = 0x7e000; + m_select_value = 0x74000; + } + + m_cru_base = ioport("CRUHFDC")->read(); + m_wait_for_hd1 = ioport("WAITHD1")->read(); + + // Resetting values + m_rom_page = 0; + + m_ram_page[0] = 0x08; // static page 0x08 + for (int i=1; i < 4; i++) m_ram_page[i] = 0; + + m_output1_latch = m_output2_latch = 0; + + m_status_latch = 0x00; + + m_dip = m_irq = CLEAR_LINE; + m_see_switches = false; + m_motor_running = false; + m_selected = false; + m_lastval = 0; + m_readyflags = 0; + + for (int i=0; i < 4; i++) + { + if (m_floppy_unit[i] != NULL) + logerror("%s: FD connector %d with %s\n", tag(), i+1, m_floppy_unit[i]->name()); + else + logerror("%s: FD connector %d has no floppy attached\n", tag(), i+1); + } + + for (int i=0; i < 3; i++) + { + if (m_harddisk_unit[i] != NULL) + logerror("%s: HD connector %d with %s\n", tag(), i+1, m_harddisk_unit[i]->name()); + else + logerror("%s: HD connector %d has no drive attached\n", tag(), i+1); + } + + // Disconnect all units + disconnect_floppy_drives(); + disconnect_hard_drives(); +} + +void myarc_hfdc_device::device_config_complete() +{ + for (int i=0; i < 3; i++) + { + m_floppy_unit[i] = NULL; + m_harddisk_unit[i] = NULL; + } + m_floppy_unit[3] = NULL; + + // Seems to be null when doing a "-listslots" + if (subdevice("f1")!=NULL) + { + m_floppy_unit[0] = static_cast(subdevice("f1"))->get_device(); + m_floppy_unit[1] = static_cast(subdevice("f2"))->get_device(); + m_floppy_unit[2] = static_cast(subdevice("f3"))->get_device(); + m_floppy_unit[3] = static_cast(subdevice("f4"))->get_device(); + + m_harddisk_unit[0] = static_cast(subdevice("h1"))->get_device(); + m_harddisk_unit[1] = static_cast(subdevice("h2"))->get_device(); + m_harddisk_unit[2] = static_cast(subdevice("h3"))->get_device(); + } +} + +/* + The HFDC controller can be configured for different CRU base addresses, + but DSK1-DSK4 are only available for CRU 1100. For all other addresses, + the drives 1 to 4 are renamed to DSK5-DSK8 (see [1] p. 7). +*/ +INPUT_PORTS_START( ti99_hfdc ) + PORT_START( "WAITHD1" ) + PORT_DIPNAME( 0x01, 0x00, "HFDC Wait for HD1" ) + PORT_DIPSETTING( 0x00, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x01, DEF_STR( On ) ) + + PORT_START( "CRUHFDC" ) + PORT_DIPNAME( 0x1f00, 0x1100, "HFDC CRU base" ) + PORT_DIPSETTING( 0x1000, "1000" ) + PORT_DIPSETTING( 0x1100, "1100" ) + PORT_DIPSETTING( 0x1200, "1200" ) + PORT_DIPSETTING( 0x1300, "1300" ) + PORT_DIPSETTING( 0x1400, "1400" ) + PORT_DIPSETTING( 0x1500, "1500" ) + PORT_DIPSETTING( 0x1600, "1600" ) + PORT_DIPSETTING( 0x1700, "1700" ) + PORT_DIPSETTING( 0x1800, "1800" ) + PORT_DIPSETTING( 0x1900, "1900" ) + PORT_DIPSETTING( 0x1a00, "1A00" ) + PORT_DIPSETTING( 0x1b00, "1B00" ) + PORT_DIPSETTING( 0x1c00, "1C00" ) + PORT_DIPSETTING( 0x1d00, "1D00" ) + PORT_DIPSETTING( 0x1e00, "1E00" ) + PORT_DIPSETTING( 0x1f00, "1F00" ) + + PORT_START( "HFDCDIP" ) + PORT_DIPNAME( 0x0c, 0x00, "HFDC drive 1 config" ) + PORT_DIPSETTING( 0x00, "40 track, 16 ms") + PORT_DIPSETTING( 0x08, "40 track, 8 ms") + PORT_DIPSETTING( 0x04, "80 track, 2 ms") + PORT_DIPSETTING( 0x0c, "80 track HD, 2 ms") + PORT_DIPNAME( 0x03, 0x00, "HFDC drive 2 config" ) + PORT_DIPSETTING( 0x00, "40 track, 16 ms") + PORT_DIPSETTING( 0x02, "40 track, 8 ms") + PORT_DIPSETTING( 0x01, "80 track, 2 ms") + PORT_DIPSETTING( 0x03, "80 track HD, 2 ms") + PORT_DIPNAME( 0xc0, 0x00, "HFDC drive 3 config" ) + PORT_DIPSETTING( 0x00, "40 track, 16 ms") + PORT_DIPSETTING( 0x80, "40 track, 8 ms") + PORT_DIPSETTING( 0x40, "80 track, 2 ms") + PORT_DIPSETTING( 0xc0, "80 track HD, 2 ms") + PORT_DIPNAME( 0x30, 0x00, "HFDC drive 4 config" ) + PORT_DIPSETTING( 0x00, "40 track, 16 ms") + PORT_DIPSETTING( 0x20, "40 track, 8 ms") + PORT_DIPSETTING( 0x10, "80 track, 2 ms") + PORT_DIPSETTING( 0x30, "80 track HD, 2 ms") +INPUT_PORTS_END + +FLOPPY_FORMATS_MEMBER(myarc_hfdc_device::floppy_formats) + FLOPPY_TI99_SDF_FORMAT, + FLOPPY_TI99_TDF_FORMAT +FLOPPY_FORMATS_END + +static SLOT_INTERFACE_START( hfdc_floppies ) + SLOT_INTERFACE( "525dd", FLOPPY_525_DD ) // 40 tracks + SLOT_INTERFACE( "525qd", FLOPPY_525_QD ) // 80 tracks + SLOT_INTERFACE( "35dd", FLOPPY_35_DD ) // 80 tracks + SLOT_INTERFACE( "35hd", FLOPPY_35_HD ) // 80 tracks 1.4 MiB +SLOT_INTERFACE_END + +static SLOT_INTERFACE_START( hfdc_harddisks ) + SLOT_INTERFACE( "generic", MFMHD_GENERIC ) // Generic hard disk (self-adapting to image) + SLOT_INTERFACE( "st213", MFMHD_ST213 ) // Seagate ST-213 (10 MB) + SLOT_INTERFACE( "st225", MFMHD_ST225 ) // Seagate ST-225 (20 MB) + SLOT_INTERFACE( "st251", MFMHD_ST251 ) // Seagate ST-251 (40 MB) +SLOT_INTERFACE_END + +MACHINE_CONFIG_FRAGMENT( ti99_hfdc ) + MCFG_DEVICE_ADD(FDC_TAG, HDC9234, 0) + MCFG_HDC92X4_INTRQ_CALLBACK(WRITELINE(myarc_hfdc_device, intrq_w)) + MCFG_HDC92X4_DIP_CALLBACK(WRITELINE(myarc_hfdc_device, dip_w)) + MCFG_HDC92X4_AUXBUS_OUT_CALLBACK(WRITE8(myarc_hfdc_device, auxbus_out)) + MCFG_HDC92X4_DMARQ_CALLBACK(WRITELINE(myarc_hfdc_device, dmarq_w)) + MCFG_HDC92X4_DMA_IN_CALLBACK(READ8(myarc_hfdc_device, read_buffer)) + MCFG_HDC92X4_DMA_OUT_CALLBACK(WRITE8(myarc_hfdc_device, write_buffer)) + + MCFG_FLOPPY_DRIVE_ADD("f1", hfdc_floppies, "525dd", myarc_hfdc_device::floppy_formats) + MCFG_FLOPPY_DRIVE_SOUND(true) + MCFG_FLOPPY_DRIVE_ADD("f2", hfdc_floppies, "525dd", myarc_hfdc_device::floppy_formats) + MCFG_FLOPPY_DRIVE_SOUND(true) + MCFG_FLOPPY_DRIVE_ADD("f3", hfdc_floppies, NULL, myarc_hfdc_device::floppy_formats) + MCFG_FLOPPY_DRIVE_SOUND(true) + MCFG_FLOPPY_DRIVE_ADD("f4", hfdc_floppies, NULL, myarc_hfdc_device::floppy_formats) + MCFG_FLOPPY_DRIVE_SOUND(true) + + // NB: Hard disks don't go without image (other than floppy drives) + MCFG_MFM_HARDDISK_CONN_ADD("h1", hfdc_harddisks, NULL, MFM_BYTE, 3000, 20, MFMHD_GEN_FORMAT) + MCFG_MFM_HARDDISK_CONN_ADD("h2", hfdc_harddisks, NULL, MFM_BYTE, 2000, 20, MFMHD_GEN_FORMAT) + MCFG_MFM_HARDDISK_CONN_ADD("h3", hfdc_harddisks, NULL, MFM_BYTE, 2000, 20, MFMHD_GEN_FORMAT) + + MCFG_DEVICE_ADD(CLOCK_TAG, MM58274C, 0) + MCFG_MM58274C_MODE24(1) // 24 hour + MCFG_MM58274C_DAY1(0) // sunday +MACHINE_CONFIG_END + +ROM_START( ti99_hfdc ) + ROM_REGION(0x4000, DSRROM, 0) + ROM_LOAD("hfdc.bin", 0x0000, 0x4000, CRC(66fbe0ed) SHA1(11df2ecef51de6f543e4eaf8b2529d3e65d0bd59)) /* HFDC disk DSR ROM */ + ROM_REGION(0x8000, BUFFER, 0) /* HFDC RAM buffer 32 KiB */ + ROM_FILL(0x0000, 0x8000, 0x00) +ROM_END + + +machine_config_constructor myarc_hfdc_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( ti99_hfdc ); +} + +const rom_entry *myarc_hfdc_device::device_rom_region() const +{ + return ROM_NAME( ti99_hfdc ); +} + +ioport_constructor myarc_hfdc_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( ti99_hfdc ); +} + +const device_type TI99_HFDC = &device_creator; diff --git a/src/devices/bus/ti99_peb/hfdc.h b/src/devices/bus/ti99_peb/hfdc.h new file mode 100644 index 00000000000..a49e6062c44 --- /dev/null +++ b/src/devices/bus/ti99_peb/hfdc.h @@ -0,0 +1,188 @@ +// license:LGPL-2.1+ +// copyright-holders:Michael Zapf +/**************************************************************************** + + Myarc Hard and Floppy Disk Controller + See hfdc.c for documentation + + January 2012: rewritten as class + June 2014: rewritten for modern floppy implementation + + Michael Zapf + July 2015 + +****************************************************************************/ + +#ifndef __HFDC__ +#define __HFDC__ + +#include "imagedev/floppy.h" +#include "imagedev/mfmhd.h" + +#include "machine/mm58274c.h" +#include "machine/hdc92x4.h" + +extern const device_type TI99_HFDC; + +/* + Implementation for modern floppy system. +*/ +class myarc_hfdc_device : public ti_expansion_card_device +{ +public: + myarc_hfdc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + DECLARE_READ8Z_MEMBER(readz); + DECLARE_WRITE8_MEMBER(write); + DECLARE_SETADDRESS_DBIN_MEMBER(setaddress_dbin); + DECLARE_READ8Z_MEMBER(crureadz); + DECLARE_WRITE8_MEMBER(cruwrite); + + DECLARE_WRITE_LINE_MEMBER( dmarq_w ); + DECLARE_WRITE_LINE_MEMBER( intrq_w ); + DECLARE_WRITE_LINE_MEMBER( dip_w ); + DECLARE_WRITE8_MEMBER( auxbus_out ); + DECLARE_READ8_MEMBER( read_buffer ); + DECLARE_WRITE8_MEMBER( write_buffer ); + + DECLARE_FLOPPY_FORMATS( floppy_formats ); + +protected: + void device_config_complete(); + +private: + void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + void device_start(); + void device_reset(); + + const rom_entry *device_rom_region() const; + machine_config_constructor device_mconfig_additions() const; + ioport_constructor device_input_ports() const; + + // Debug accessors + void debug_read(offs_t offset, UINT8* value); + void debug_write(offs_t offset, UINT8 data); + + // Callbacks for the index hole and seek complete + void floppy_index_callback(floppy_image_device *floppy, int state); + void harddisk_index_callback(mfm_harddisk_device *harddisk, int state); + void harddisk_ready_callback(mfm_harddisk_device *harddisk, int state); + void harddisk_skcom_callback(mfm_harddisk_device *harddisk, int state); + + // Operate the floppy motors + void set_floppy_motors_running(bool run); + + // Connect floppy drives + void connect_floppy_unit(int index); + + // Connect harddisk drives + void connect_harddisk_unit(int index); + + // Disconnect drives + void disconnect_floppy_drives(); + void disconnect_hard_drives(); + + // Pushes the drive status to the HDC + void signal_drive_status(); + + // Motor monoflop (4.23 sec) + emu_timer* m_motor_on_timer; + + // HDC9234 controller on the board + required_device m_hdc9234; + + // Clock chip on the board + required_device m_clock; + + // Link to the attached floppy drives + floppy_image_device* m_floppy_unit[4]; + + // Link to the attached hard disks + mfm_harddisk_device* m_harddisk_unit[3]; + + // Currently selected floppy drive + floppy_image_device* m_current_floppy; + + // Currently selected hard drive + mfm_harddisk_device* m_current_harddisk; + + // True: Access to DIP switch settings, false: access to line states + bool m_see_switches; + + // IRQ state + line_state m_irq; + + // DMA in Progress state + line_state m_dip; + + // When true, motor monoflop is high + bool m_motor_running; + + // Address in card area + bool m_inDsrArea; + + // HDC selected + bool m_HDCsel; + + // RTC selected + bool m_RTCsel; + + // Tape selected + bool m_tapesel; + + // RAM selected + bool m_RAMsel; + + // RAM selected + bool m_ROMsel; + + // Recent address + int m_address; + + // DMA in progress + bool m_dma_in_progress; + + // Wait for HD. This was an addition in later cards. + bool m_wait_for_hd1; + + // Device Service Routine ROM (firmware) + UINT8* m_dsrrom; + + // ROM banks. + int m_rom_page; + + // HFDC on-board SRAM (8K or 32K) + UINT8* m_buffer_ram; + + // RAM page registers + int m_ram_page[4]; + + // Drive status latch (STB0) + UINT8 m_status_latch; + + // DMA address latch (in Gate Array) (STB1) + UINT32 m_dma_address; + + // Output 1 latch (STB2) + UINT8 m_output1_latch; + + // Output 2 latch (STB3) + UINT8 m_output2_latch; + + // Needed for triggering the motor monoflop + UINT8 m_lastval; + + // Signal motor_on. When TRUE, makes all drives turning. + line_state m_MOTOR_ON; + + // Calculates the index from the bit + int bit_to_index(int value); + + // Utility function to set or unset bits in a byte + void set_bits(UINT8& byte, int mask, bool set); + + // Joined ready line towards the controller + void set_ready(int dev, bool ready); + int m_readyflags; +}; +#endif diff --git a/src/devices/bus/ti99_peb/horizon.c b/src/devices/bus/ti99_peb/horizon.c new file mode 100644 index 00000000000..36bf35cbd18 --- /dev/null +++ b/src/devices/bus/ti99_peb/horizon.c @@ -0,0 +1,450 @@ +// license:LGPL-2.1+ +// copyright-holders:Michael Zapf +/**************************************************************************** + + Horizon Ramdisk + + This emulation realizes the latest development, the HRD 4000, which could + host up to 16 MiB of SRAM. Real cards rarely had more than 1.5 MiB since + the SRAM used on the card is rather expensive. + + The SRAM is buffered with a battery pack. Also, there is an option for + an additional 32 KiB of unbuffered memory. + + The driver (ROS) of the ramdisk is stored in another buffered 8 KiB SRAM. + + The Horizon RAMdisk comes with a disk containing the ROS and a configuration + program (CFG). The latest version is ROS 8.14. + + Technical details: + + In the tradition (Horizon) mode, memory is organized as 2 KiB pages. The + pages are selected via CRU bits and visible in the address area 5800 - 5fff. + The area 4000-57ff is occupied by the ROS. As with all peripheral cards, + the 4000-5fff area requires a CRU bit to be set (usually bit 0 of this + card's CRU base). + + Next releases of the HRD included new modes. The RAMBO (RAM Block operator) + mode gathers four pages to a single 8 KiB page that is visible in the + area 6000-7fff (cartridge space). Note that due to a possible design glitch, + each RAMBO page n covers Horizon pages 4n, 4n+2, 4n+1, 4n+3 in this sequence. + We emulate this by swapping two CRU lines. + + The RAMDisk may be split in two separate drives, which is called the + Phoenix extension. This is particularly important for use in the Geneve. + As a bootable drive, the RAMdisk must not + exceed 256 KiB; consequently, the RAM area is split, and one part realizes + the boot drive while the other is still available for data. Also, there + is a mechanism for selecting the parts of the card: The TI setting allows + to select two CRU addresses, one for each part. In the Geneve mode, only + one CRU address is used (1400 or 1600), and the part is selected by the + fact that one disk uses CRU bits higher than 8, while the other uses the + bits lower than 8. + + The card is able to handle 128K*8 and 512K*8 SRAM chips, allowing a total + of 16 MiB memory space. Unfortunately, a bug causes the configuration + program to crash when used with more than 2 MiB. Although the card was + quite popular, this bug was not found because most cards were sold with + less than 2 MiB onboard. As the community is still alive we can hope for + a fix for this problem; so we make the size configurable. + + Michael Zapf + February 2012 + +*****************************************************************************/ + +#include "horizon.h" + +#define RAMREGION "ram" +#define NVRAMREGION "nvram" +#define ROSREGION "ros" + +// Paged RAM is max 16 MiB; behind we add the 8 KiB for the buffered RAM for the ROS +#define MAXRAM_SIZE 16777216+8192 + +#define VERBOSE 1 +#define LOG logerror + +horizon_ramdisk_device::horizon_ramdisk_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) +: ti_expansion_card_device(mconfig, TI99_HORIZON, "Horizon 4000 Ramdisk", tag, owner, clock,"ti99_horizon",__FILE__), + device_nvram_interface(mconfig, *this) +{ +} + +//------------------------------------------------- +// nvram_default - called to initialize NVRAM to +// its default state +//------------------------------------------------- + +int horizon_ramdisk_device::get_size() +{ + int size = 8192 + 2097152*(1 << ioport("HORIZONSIZE")->read()); + if (VERBOSE>2) LOG("horizon: size = %d\n", size); + return size; +} + +void horizon_ramdisk_device::nvram_default() +{ + memset(m_nvram, 0, get_size()); +} + +//------------------------------------------------- +// nvram_read - called to read NVRAM from the +// .nv file +//------------------------------------------------- + +void horizon_ramdisk_device::nvram_read(emu_file &file) +{ + int size = get_size(); + int readsize = file.read(m_nvram, size); + // If we increased the size, fill the remaining parts with 0 + if (readsize < size) + { + memset(m_nvram + readsize, 0, size-readsize); + } +} + +//------------------------------------------------- +// nvram_write - called to write NVRAM to the +// .nv file +//------------------------------------------------- + +void horizon_ramdisk_device::nvram_write(emu_file &file) +{ + int size = get_size(); + file.write(m_nvram, size); +} + +READ8Z_MEMBER(horizon_ramdisk_device::readz) +{ + // 32K expansion + if (m_32k_installed) + { + switch((offset & 0xe000)>>13) + { + case 1: // 2000-3fff + *value = m_ram[offset & 0x1fff]; + return; + case 5: // a000-bfff + *value = m_ram[(offset & 0x1fff) | 0x2000]; + return; + case 6: // c000-dfff + *value = m_ram[(offset & 0x1fff) | 0x4000]; + return; + case 7: // e000-ffff + *value = m_ram[(offset & 0x1fff) | 0x6000]; + return; + default: + break; + } + } + + if (m_killswitch) return; + + // I think RAMBO mode does not need the card to be selected + if (!m_selected && !m_rambo_mode) return; + + if (!m_rambo_mode) + { + if ((offset & m_select_mask) == m_select_value) + { + if ((offset & 0x1800) == 0x1800) + { + // NVRAM page of size 2 KiB + *value = m_nvram[(m_page << 11)|(offset & 0x07ff)]; + if (VERBOSE>5) LOG("horizon: offset=%04x, page=%04x -> %02x\n", offset&0xffff, m_page, *value); + } + else + { + // ROS + *value = m_ros[offset & 0x1fff]; + if (VERBOSE>5) LOG("horizon: offset=%04x -> %02x\n", offset&0xffff, *value); + } + } + } + else + { + if ((offset & m_select_mask)==m_select_value) + { + *value = m_ros[offset & 0x1fff]; + if (VERBOSE>5) LOG("horizon: offset=%04x (Rambo) -> %02x\n", offset&0xffff, *value); + } + if ((offset & m_select_mask)==m_select6_value) + { + // In RAMBO mode the page numbers are multiples of 4 + // (encompassing 4 Horizon pages) + // We clear away the rightmost two bits + *value = m_nvram[((m_page&0xfffc)<<11) | (offset & 0x1fff)]; + if (VERBOSE>5) LOG("horizon: offset=%04x, page=%04x (Rambo) -> %02x\n", offset&0xffff, m_page, *value); + } + } +} + +WRITE8_MEMBER(horizon_ramdisk_device::write) +{ + // 32K expansion + if (m_32k_installed) + { + switch((offset & 0xe000)>>13) + { + case 1: // 2000-3fff + m_ram[offset & 0x1fff] = data; + return; + case 5: // a000-bfff + m_ram[(offset & 0x1fff) | 0x2000] = data; + return; + case 6: // c000-dfff + m_ram[(offset & 0x1fff) | 0x4000] = data; + return; + case 7: // e000-ffff + m_ram[(offset & 0x1fff) | 0x6000] = data; + return; + default: + break; + } + } + + if (m_killswitch) return; + + // I think RAMBO mode does not need the card to be selected + if (!m_selected && !m_rambo_mode) return; + + if (!m_rambo_mode) + { + if ((offset & m_select_mask) == m_select_value) + { + if ((offset & 0x1800) == 0x1800) + { + // NVRAM page of size 2 KiB + m_nvram[(m_page << 11)|(offset & 0x07ff)] = data; + if (VERBOSE>5) LOG("horizon: offset=%04x, page=%04x <- %02x\n", offset&0xffff, m_page, data); + } + else + { + // ROS + m_ros[offset & 0x1fff] = data; + if (VERBOSE>5) LOG("horizon: offset=%04x <- %02x\n", offset&0xffff, data); + } + } + } + else + { + if ((offset & m_select_mask)==m_select_value) + { + m_ros[offset & 0x1fff] = data; + if (VERBOSE>5) LOG("horizon: offset=%04x (Rambo) <- %02x\n", offset&0xffff, data); + } + if ((offset & m_select_mask)==m_select6_value) + { + // In RAMBO mode the page numbers are multiples of 4 + // (encompassing 4 Horizon pages) + // We clear away the rightmost two bits + m_nvram[((m_page&0xfffc)<<11) | (offset & 0x1fff)] = data; + if (VERBOSE>5) LOG("horizon: offset=%04x, page=%04x (Rambo) <- %02x\n", offset&0xffff, m_page, data); + } + } +} + +READ8Z_MEMBER(horizon_ramdisk_device::crureadz) +{ + // There is no CRU read operation for the Horizon. + return; +} + +void horizon_ramdisk_device::setbit(int& page, int pattern, bool set) +{ + if (set) + { + page |= pattern; + } + else + { + page &= ~pattern; + } +} + +WRITE8_MEMBER(horizon_ramdisk_device::cruwrite) +{ + int size = ioport("HORIZONSIZE")->read(); + int split_bit = size + 10; + int splitpagebit = 0x0200 << size; + + if (((offset & 0xff00)==m_cru_horizon)||((offset & 0xff00)==m_cru_phoenix)) + { + int bit = (offset >> 1) & 0x0f; + if (VERBOSE>5) LOG("horizon: CRU write bit %d <- %d\n", bit, data); + switch (bit) + { + case 0: + m_selected = (data!=0); + if (VERBOSE>4) LOG("horizon: Activate ROS = %d\n", m_selected); + break; + case 1: + // Swap the lines so that the access with RAMBO is consistent + if (!m_rambo_mode) setbit(m_page, 0x0002, data!=0); + break; + case 2: + // Swap the lines so that the access with RAMBO is consistent + if (!m_rambo_mode) setbit(m_page, 0x0001, data!=0); + break; + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + setbit(m_page, 0x0001 << (bit-1), data!=0); + break; + case 14: + break; + case 15: + if (m_use_rambo) + { + m_rambo_mode = (data != 0); + if (VERBOSE>4) LOG("horizon: RAMBO = %d\n", m_rambo_mode); + } + break; + + default: // bits 10-13 + if (bit != split_bit || !m_split_mode) + { + if (bit <= split_bit) setbit(m_page, 0x0200<<(bit-10), data!=0); + } + break; + } + + if (m_split_mode) + { + if (m_timode) + { + // In TI mode, switch between both RAMDisks using the CRU address + setbit(m_page, splitpagebit, ((offset & 0xff00)==m_cru_phoenix)); + } + else + { + // In Geneve mode, switch between both RAMdisks by + // using the bit number of the last CRU access + setbit(m_page, splitpagebit, (bit>7)); + } + } + } +} + +void horizon_ramdisk_device::device_start(void) +{ + m_nvram = memregion(NVRAMREGION)->base(); + m_ram = memregion(RAMREGION)->base(); + m_ros = m_nvram + MAXRAM_SIZE - 8192; + m_cru_horizon = 0; + m_cru_phoenix = 0; +} + +void horizon_ramdisk_device::device_reset(void) +{ + if (m_genmod) + { + m_select_mask = 0x1fe000; + m_select_value = 0x174000; + m_select6_value = 0x176000; + m_select_all = 0x170000; + } + else + { + m_select_mask = 0x7e000; + m_select_value = 0x74000; + m_select6_value = 0x76000; + m_select_all = 0x70000; + } + + m_ros = m_nvram + get_size()-8192; + m_cru_horizon = ioport("CRUHOR")->read(); + m_cru_phoenix = ioport("CRUPHOE")->read(); + + m_32k_installed = (ioport("HORIZON32")->read()!=0); + + m_split_mode = (ioport("HORIZONDUAL")->read()!=0); + m_timode = (ioport("HORIZONDUAL")->read()==1); + + m_rambo_mode = false; + m_killswitch = (ioport("HORIZONACT")->read()!=0); + + m_use_rambo = (ioport("RAMBO")->read()!=0); + + m_page = 0; + m_selected = false; +} + +INPUT_CHANGED_MEMBER( horizon_ramdisk_device::ks_changed ) +{ + if (VERBOSE>5) LOG("horizon: killswitch changed %d\n", newval); + m_killswitch = (newval!=0); +} + +/* + Input ports for the Horizon +*/ +INPUT_PORTS_START( horizon ) + PORT_START( "CRUHOR" ) + PORT_DIPNAME( 0x1f00, 0x1200, "Horizon CRU base" ) + PORT_DIPSETTING( 0x0000, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x1000, "1000" ) + PORT_DIPSETTING( 0x1200, "1200" ) + PORT_DIPSETTING( 0x1400, "1400" ) + PORT_DIPSETTING( 0x1500, "1500" ) + PORT_DIPSETTING( 0x1600, "1600" ) + PORT_DIPSETTING( 0x1700, "1700" ) + + PORT_START( "CRUPHOE" ) + PORT_DIPNAME( 0x1f00, 0x0000, "Phoenix CRU base" ) + PORT_DIPSETTING( 0x0000, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x1400, "1400" ) + PORT_DIPSETTING( 0x1600, "1600" ) + + PORT_START( "HORIZONDUAL" ) + PORT_DIPNAME( 0x03, 0x00, "Horizon ramdisk split" ) + PORT_DIPSETTING( 0x00, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x01, "TI mode" ) + PORT_DIPSETTING( 0x02, "Geneve mode" ) + + PORT_START( "HORIZONACT" ) + PORT_DIPNAME( 0x01, 0x00, "Horizon killswitch" ) PORT_CHANGED_MEMBER(DEVICE_SELF, horizon_ramdisk_device, ks_changed, 1) + PORT_DIPSETTING( 0x00, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x01, DEF_STR( On ) ) + + PORT_START( "HORIZON32" ) + PORT_CONFNAME( 0x01, 0x00, "Horizon 32 KiB upgrade" ) + PORT_CONFSETTING( 0x00, DEF_STR( Off )) + PORT_CONFSETTING( 0x01, DEF_STR( On )) + + PORT_START( "RAMBO" ) + PORT_CONFNAME( 0x01, 0x01, "Horizon RAMBO" ) + PORT_CONFSETTING( 0x00, DEF_STR( Off )) + PORT_CONFSETTING( 0x01, DEF_STR( On )) + + PORT_START( "HORIZONSIZE" ) + PORT_CONFNAME( 0x03, 0x00, "Horizon size" ) + PORT_CONFSETTING( 0x00, "2 MiB") + PORT_CONFSETTING( 0x01, "4 MiB") + PORT_CONFSETTING( 0x03, "16 MiB") + +INPUT_PORTS_END + +ROM_START( horizon ) + ROM_REGION(MAXRAM_SIZE, NVRAMREGION, 0) + ROM_FILL(0x0000, MAXRAM_SIZE, 0x00) + ROM_REGION(0x8000, RAMREGION, 0) + ROM_FILL(0x0000, 0x8000, 0x00) +ROM_END + +const rom_entry *horizon_ramdisk_device::device_rom_region() const +{ + return ROM_NAME( horizon ); +} + +ioport_constructor horizon_ramdisk_device::device_input_ports() const +{ + return INPUT_PORTS_NAME(horizon); +} + +const device_type TI99_HORIZON = &device_creator; diff --git a/src/devices/bus/ti99_peb/horizon.h b/src/devices/bus/ti99_peb/horizon.h new file mode 100644 index 00000000000..f1241c001ad --- /dev/null +++ b/src/devices/bus/ti99_peb/horizon.h @@ -0,0 +1,67 @@ +// license:LGPL-2.1+ +// copyright-holders:Michael Zapf +/**************************************************************************** + + Horizon Ramdisk + See horizon.c for documentation + + Michael Zapf + + February 2012 + +*****************************************************************************/ + +#ifndef __HORIZON__ +#define __HORIZON__ + +#include "emu.h" +#include "peribox.h" + +extern const device_type TI99_HORIZON; + +class horizon_ramdisk_device : public ti_expansion_card_device, public device_nvram_interface +{ +public: + horizon_ramdisk_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + DECLARE_READ8Z_MEMBER(readz); + DECLARE_WRITE8_MEMBER(write); + + DECLARE_READ8Z_MEMBER(crureadz); + DECLARE_WRITE8_MEMBER(cruwrite); + + DECLARE_INPUT_CHANGED_MEMBER( ks_changed ); + +protected: + virtual void device_start(); + virtual void device_reset(); + + virtual const rom_entry *device_rom_region() const; + virtual ioport_constructor device_input_ports() const; + + void nvram_default(); + void nvram_read(emu_file &file); + void nvram_write(emu_file &file); + +private: + void setbit(int& page, int pattern, bool set); + int get_size(); + UINT8* m_ram; + UINT8* m_nvram; + UINT8* m_ros; + + int m_select6_value; + int m_select_all; + + int m_page; + + int m_cru_horizon; + int m_cru_phoenix; + bool m_timode; + bool m_32k_installed; + bool m_split_mode; + bool m_rambo_mode; + bool m_killswitch; + bool m_use_rambo; +}; + +#endif diff --git a/src/devices/bus/ti99_peb/hsgpl.c b/src/devices/bus/ti99_peb/hsgpl.c new file mode 100644 index 00000000000..8cfe1c9ede7 --- /dev/null +++ b/src/devices/bus/ti99_peb/hsgpl.c @@ -0,0 +1,680 @@ +// license:LGPL-2.1+ +// copyright-holders:Michael Zapf +/**************************************************************************** + + SNUG HSGPL card emulation. + + The HSGPL card is a card for the peripheral expansion box which simulates + 16 banks of 64 KiB GROM space, using flash memory to keep data persistent. + + Main usage: + - store cartridges in the card for quick selection + - replace the console GROMs, thus making it possible to patch or enhance the + console operating system + - provide necessary ROMs for the SGCPU (aka TI-99/4P) + + (So for using the ti99_4p emulation, you MUST have a properly set up HSGPL + card. The best way to get this done is to prepare this card within the + ti99_4ev emulation, then copy the contents to the ti99_4p nvram directory.) + + The card does not contain real GROM circuits, and accordingly, we do not + use the grom emulation. The logic on the board, mainly contained in the + MACH chip, simulates GROM behavior. With the possibility to upload data + into the simulated GROMs, we can also enjoy GRAM behavior, although real + GRAMs are not known to have become available ever. + + Contents: + + Supports 16 banks of 8 GROMs (8kbytes each) with 16 associated banks of + 32kbytes (8kbytes*4) of module ROM, 2 banks of 8 GRAMs with 2 associated + banks of 32 kbytes of RAM, and 512kbytes of DSR. Roms are implemented with + 512kbyte EEPROMs (1 for DSR, 2 for GROMs, 1 for cartridge ROM). RAM is + implemented with 128kbyte SRAMs (1 for GRAM, 1 for cartridge RAM - only the + first 64kbytes of the cartridge RAM chip is used). + + CRU bits: + Name Equates Meaning + >0 DEN DSRENA DSR Enable + >1 GRMENA GRMENA Enable GRAM instead of GROM in banks 0 and 1 + >2 BNKINH* BNKENA Disable banking + >3 PG0 PG0 + >4 PG1 PG1 + >5 PG2 PG2 Paging-Bits for DSR-area + >6 PG3 PG3 + >7 PG4 PG4 + >8 PG5 PG5 + >9 CRDENA CRDENA Activate memory areas of HSGPL (i.e. enable HSGPL GROM and ROM6 ports) + >A WRIENA WRIENA write enable for RAM and GRAM (and flash GROM!) + >B SCENA SCARTE Activate SuperCart-banking + >C LEDENA LEDENA turn LED on + >D - - free + >E MBXENA MBXENA Activate MBX-Banking + >F RAMENA RAMENA Enable RAM6000 instead of ROM6000 in banks 0 and 1 + + + Direct access ports for all memory areas (the original manual says + >9880->989C and >9C80->9C9C for ROM6000, but this is clearly incorrect): + + Module bank Read Write Read ROM6000 Write ROM6000 + GROM GROM + 0 >9800 >9C00 >9860 Offset >0000 >9C60 Offset >0000 + 1 >9804 >9C04 >9860 Offset >8000 >9C60 Offset >8000 + 2 >9808 >9C08 >9864 Offset >0000 >9C64 Offset >0000 + 3 >980C >9C0C >9864 Offset >8000 >9C64 Offset >8000 + 4 >9810 >9C10 >9868 Offset >0000 >9C68 Offset >0000 + 5 >9814 >9C14 >9868 Offset >8000 >9C68 Offset >8000 + 6 >9818 >9C18 >986C Offset >0000 >9C6C Offset >0000 + 7 >981C >9C1C >986C Offset >8000 >9C6C Offset >8000 + 8 >9820 >9C20 >9870 Offset >0000 >9C70 Offset >0000 + 9 >9824 >9C24 >9870 Offset >8000 >9C70 Offset >8000 + 10 >9828 >9C28 >9874 Offset >0000 >9C74 Offset >0000 + 11 >982C >9C2C >9874 Offset >8000 >9C74 Offset >8000 + 12 >9830 >9C30 >9878 Offset >0000 >9C78 Offset >0000 + 13 >9834 >9C34 >9878 Offset >8000 >9C78 Offset >8000 + 14 >9838 >9C38 >987C Offset >0000 >9C7C Offset >0000 + 15 >983C >9C3C >987C Offset >8000 >9C7C Offset >8000 + + Module bank Read Write Read RAM6000 Write RAM6000 + GRAM GRAM + 16 (Ram) >9880 >9C80 >98C0 Offset >0000 >9CC0 Offset >0000 + 17 (Ram) >9884 >9C84 >98C0 Offset >8000 >9CC0 Offset >8000 + + DSR bank Read Write + 0 - 7 >9840 >9C40 + 8 - 15 >9844 >9C44 + 16 - 23 >9848 >9C48 + 24 - 31 >984C >9C4C + 32 - 39 >9850 >9C50 + 40 - 47 >9854 >9C54 + 48 - 55 >9858 >9C58 + 56 - 63 >985C >9C5C + + Notes: + 1. The bank numbering of the modules is not exactly the GROM bank numbering. + The first 16 banks are numbered as expected, but bank 16 is DSR bank 0-7, + bank 23 is DSR bank 56-63, bank 24 is ROM6000 of module bank 0, bank 31 is + ROM6000 of module bank 25, and finally bank 32 and 33 and the GRAM banks, + and bank 48 and 49 are the RAM banks. + Only accesses to the GROM/GRAM addresses will change the module bank. + + 2. Writing only works for areas set up as RAM. To write to the + FEEPROMs, you must used the algorithm specified by their respective + manufacturer. + + CRDENA: This flag is used to turn on and off the HSGPL. It is used in + particular at start-up when the DSR detects a cartridge in the + cartridge slot. In that case the memory locations 6000-7fff must be + deactivated on the HSGPL, or it would cause a collision with the + cartridge. However, CRDENA must not completely turn off the HSGPL, or the + console will not start up at all. At least GROMs 0, 1, and 2 must remain + active. + The technical specifications are not clear enough at this point. + + Raphael Nabet, 2003. + + Michael Zapf + October 2010: Rewritten as device + February 2012: Rewritten as class + +*****************************************************************************/ + +#include "hsgpl.h" + +#define CRU_BASE 0x1B00 +#define SUPERCART_BASE 0x0800 + +#define TRACE_PORT 0 +#define TRACE_DSR 0 +#define TRACE_BANKING 0 +#define TRACE_CRU 0 +#define TRACE_READ 0 +#define TRACE_WRITE 0 +#define TRACE_IGNORE 0 + +#define RAMSIZE 0x020000 +#define GRAMSIZE 0x020000 + +#define DSR_EEPROM "u9_dsr" +#define GROM_B_EEPROM "u4_grom" +#define GROM_A_EEPROM "u1_grom" +#define ROM6_EEPROM "u6_rom6" + +snug_high_speed_gpl_device::snug_high_speed_gpl_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) +: ti_expansion_card_device(mconfig, TI99_HSGPL, "SNUG High-speed GPL card", tag, owner, clock, "ti99_hsgpl", __FILE__) +{ +} + +/* + Read hsgpl CRU interface. None here. +*/ +READ8Z_MEMBER(snug_high_speed_gpl_device::crureadz) +{ + return; +} + +/* + Write hsgpl CRU interface +*/ +WRITE8_MEMBER(snug_high_speed_gpl_device::cruwrite) +{ + // SuperCart handling - see gromport.c + if (m_supercart_enabled && ((offset & 0xfff0)==SUPERCART_BASE)) + { + if (data != 0) + { + if (TRACE_CRU) logerror("%s: Supercart cru setting %04x\n", tag(), offset); + m_current_bank = (offset-0x0802)>>2; + } + return; + } + + // Common CRU handling + if ((offset & 0xff00)==CRU_BASE) + { + int bit = (offset >> 1) & 0x0f; + switch (bit) + { + case 0: + m_dsr_enabled = (data != 0); + if (TRACE_CRU) logerror("%s: Set dsr_enabled=%x\n", tag(), data); + break; + case 1: + m_gram_enabled = (data != 0); + if (TRACE_CRU) logerror("%s: Set gram_enabled=%x\n", tag(), data); + break; + case 2: + m_bank_inhibit = (data != 0); + if (TRACE_CRU) logerror("%s: Set bank_inhibit=%x\n", tag(), data); + break; + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + if (data) + m_dsr_page |= (1 << (bit-3)); + else + m_dsr_page &= ~(1 << (bit-3)); + if (TRACE_CRU) logerror("%s: Set dsr_page=%d\n", tag(), m_dsr_page); + break; + case 9: + m_card_enabled = data; + if (TRACE_CRU) logerror("%s: Set card_enabled=%x\n", tag(), data); + break; + case 10: + m_write_enabled = data; + if (TRACE_CRU) logerror("%s: Set write_enabled=%x\n", tag(), data); + break; + case 11: + m_supercart_enabled = data; + // CHECK: Do we have to reset the bank? + if (TRACE_CRU) logerror("%s: Set supercart_enabled=%x\n", tag(), data); + break; + case 12: + m_led_on = data; + if (TRACE_CRU) logerror("%s: Set led_on=%x\n", tag(), data); + break; + case 13: + break; + case 14: + m_mbx_enabled = data; + if (TRACE_CRU) logerror("%s: Set mbx_enabled=%x\n", tag(), data); + break; + case 15: + m_ram_enabled = data; + if (TRACE_CRU) logerror("%s: Set ram_enabled=%x\n", tag(), data); + break; + } + } +} + +/* + Memory read +*/ +READ8Z_MEMBER(snug_high_speed_gpl_device::readz) +{ + if ((offset & 0x7e000)==0x74000) + { + dsrspace_readz(space, offset & 0xffff, value, mem_mask); + } + + if ((offset & 0x7e000)==0x76000) + { + cartspace_readz(space, offset & 0xffff, value, mem_mask); + } + + // 1001 1wbb bbbb bba0 + if ((offset & 0x7fc01)==0x79800) + { + grom_readz(space, offset & 0xffff, value, mem_mask); + } +} + +/* + Memory write +*/ +WRITE8_MEMBER(snug_high_speed_gpl_device::write) +{ + if ((offset & 0x7e000)==0x76000) + { + cartspace_write(space, offset & 0xffff, data, mem_mask); + } + + // 1001 1wbb bbbb bba0 + if ((offset & 0x7fc01)==0x79c00) + { + grom_write(space, offset & 0xffff, data, mem_mask); + } +} + +/* + Specific read access: dsrspace +*/ +void snug_high_speed_gpl_device::dsrspace_readz(address_space& space, offs_t offset, UINT8* value, UINT8 mem_mask) +{ + if (m_dsr_enabled) + { + *value = m_dsr_eeprom->read(space, (offset & 0x1fff) | (m_dsr_page<<13), mem_mask); + if (TRACE_READ) logerror("%s: read dsr %04x[%02x] -> %02x\n", tag(), offset, m_dsr_page, *value); + } +} + +/* + Specific read access: cartspace +*/ +void snug_high_speed_gpl_device::cartspace_readz(address_space& space, offs_t offset, UINT8* value, UINT8 mem_mask) +{ + if (!m_card_enabled || m_flash_mode) + { + if (TRACE_IGNORE) logerror("%s: cartridge space read ignored (enable=%d, flash_mode=%d)\n", tag(), m_card_enabled, m_flash_mode); + return; + } + + if (m_module_bank < 16) + { + *value = m_rom6_eeprom->read(space, (offset & 0x1fff) | (m_current_bank<<13) | (m_current_grom_port<<15), mem_mask); + if (TRACE_READ) logerror("%s: cartridge space read %04x -> %02x\n", tag(), offset, *value); + } + else + { + if (m_module_bank==16 || m_module_bank==17) + { + *value = m_ram6_memory[(offset & 0x1fff) | (m_current_bank<<13) | ((m_module_bank & 0x000f)<<15)]; + } + else + { + logerror("%s: unknown 0x6000 port\n", tag()); + } + } +} + +/* + Specific read access: grom + Although we have a complete emulation of a GROM circuit, we need to re-implement + it here - which is indeed closer to reality, since the real HSGPL also + emulates GROM instead of using proper ones. +*/ +void snug_high_speed_gpl_device::grom_readz(address_space& space, offs_t offset, UINT8* value, UINT8 mem_mask) +{ + if (space.debugger_access()) return; + + //activedevice_adjust_icount(-4); + + // 1001 10bb bbbb bba0 + int port = (offset & 0x3fc) >> 2; + + if (offset & 2) + { // Read GPL address. This must be available even when the rest + // of the card is offline (card_enabled=0). + m_waddr_LSB = false; + + if (m_raddr_LSB) + { + *value = ((m_grom_address + 1) & 0xff); + m_raddr_LSB = false; + } + else + { + *value = ((m_grom_address + 1) >> 8) & 0xff; + m_raddr_LSB = true; + } + } + else + { /* read GPL data */ + bool bNew = (port != m_current_grom_port); + m_current_grom_port = port; + + // It is not clear what effect a CRDENA=0 really has. + // At least GROMs 0-2 must remain visible, or the console will lock up. + if (m_card_enabled || m_grom_address < 0x6000) + { + if ((port < 2) && (m_gram_enabled)) + { + *value = m_gram_memory[m_grom_address | (port<<16)]; + m_module_bank = port + 16; + if (TRACE_PORT) if (bNew) logerror("%s: GRAM read access at %04x (GRMENA=1) - switch to bank %d\n", tag(), offset & 0xffff, m_module_bank); + } + else + { + if (port < 8) + { + if (!m_flash_mode) + { + *value = m_grom_a_eeprom->read(space, m_grom_address | (port<<16), mem_mask); + m_module_bank = port; + if (TRACE_PORT) if (bNew) logerror("%s: GROM read access at %04x - switch to bank %d\n", tag(), offset & 0xffff, m_module_bank); + } + } + else + { + if (port < 16) + { + *value = m_grom_b_eeprom->read(space, m_grom_address | ((port-8)<<16), mem_mask); + m_module_bank = port; + if (TRACE_PORT) if (bNew) logerror("%s: GROM read access at %04x - switch to bank %d\n", tag(), offset & 0xffff, m_module_bank); + } + else + { + if (port < 24) + { + // 9840-985c + // DSR banks 0-63 (8 KiB per bank, 8 banks per port) + *value = m_dsr_eeprom->read(space, m_grom_address | ((port-16)<<16), mem_mask); + // Don't change the module port + if (TRACE_DSR) if (bNew) logerror("%s: read access to DSR bank %d-%d (%04x)\n", tag(), (port-16)<<3, ((port-16)<<3)+7, offset); + } + else + { + if (port < 32) + { + // 9860-987c (ports 24-31) + // Each ROM6 is available as 4 (sub)banks (switchable via 6000, 6002, 6004, 6006) + // Accordingly, each port has two complete sets + *value = m_rom6_eeprom->read(space, m_grom_address | ((port-24)<<16), mem_mask); + if (TRACE_PORT) if (bNew) logerror("%s: ROM6 read access for module bank %d-%d (%04x)\n", tag(), (port-24)<<1, ((port-24)<<1)+1, offset & 0xffff); + } + else + { + // 9880, 9884 + if (port==32 || port==33) + { + *value = m_gram_memory[m_grom_address | ((port-32)<<16)]; + m_module_bank = port - 16; + if (TRACE_PORT) if (bNew) logerror("%s: GRAM read access at %04x - switch to bank %d\n", tag(), offset & 0xffff, m_module_bank); + } + else + { + if (port==48 || port==49) + { +// *value = m_ram6_memory[m_grom_address]; + *value = m_ram6_memory[m_grom_address | ((port-48)<<16)]; + if (TRACE_PORT) if (bNew) logerror("%s: RAM read access at %04x\n", tag(), offset & 0xffff); + } + else + { + logerror("%s: Attempt to read from undefined port 0x%0x; ignored.\n", tag(), port); + } + } + } + } + } + } + } + } + // The address auto-increment should be done even when the card is + // offline + m_grom_address++; + m_raddr_LSB = m_waddr_LSB = false; + } +} + +/* + Specific write access: cartspace +*/ +void snug_high_speed_gpl_device::cartspace_write(address_space& space, offs_t offset, UINT8 data, UINT8 mem_mask) +{ + if (!m_card_enabled || m_flash_mode) + { + if (TRACE_IGNORE) logerror("%s: write ignored: card_enabled=%d, flash_mode=%d\n", tag(), m_card_enabled, m_flash_mode); + return; + } + + if (TRACE_WRITE) logerror("%s: cartridge space write %04x <- %02x\n", tag(), offset, data); + + if (!m_bank_inhibit && (m_module_bank < 16)) + { + if ((offset & 1) == 0) + { + if ((offset & 0x9ff0)!=0) logerror("%s: unplausible ROM6 write: %04x <- %02x\n", tag(), offset, data); + m_current_bank = (offset>>1) & 3; + if (TRACE_BANKING) logerror("%s: select bank %d\n", tag(), m_current_bank); + } + return; /* right??? */ + } + + if ((m_mbx_enabled) && (offset==0x6ffe)) + { /* MBX: mapper at 0x6ffe */ + m_current_bank = data & 0x03; + if (TRACE_BANKING) logerror("%s: select bank MBX %d\n", tag(), m_current_bank); + return; + } + + // MBX: RAM in 0x6c00-0x6ffd (it is unclear whether the MBX RAM area is + // enabled/disabled by the wriena bit). I guess RAM is unpaged, but it is + // not implemented + if ((m_write_enabled) || ((m_mbx_enabled) && ((offset & 0xfc00)==0x6c00))) + { + if ((m_module_bank < 2) && (m_ram_enabled)) + { + m_ram6_memory[(offset & 0x1fff) | (m_current_bank<<13) | (m_module_bank<<15) ] = data; + } + else + { // keep in mind that these lines are also reached for port < 2 + // and !ram_enabled + if (m_module_bank < 16) + { + logerror("%s: invalid write %04x <- %02x\n", tag(), offset, data); + // feeprom is normally written to using GPL ports, and I don't know + // whether writing through >6000 page is enabled +/* + at29c040a_w(feeprom_rom6, 1 + 2*offset + 0x2000*hsgpl.cur_bank + 0x8000*port, data); + at29c040a_w(feeprom_rom6, 2*offset + 0x2000*hsgpl.cur_bank + 0x8000*port, data >> 8); +*/ + } + else + { + if (m_module_bank==16 || m_module_bank==17) + { + m_ram6_memory[(offset & 0x1fff) | (m_current_bank<<13) | ((m_module_bank-16)<<15)] = data; + } + else + { + logerror("%s: unknown 0x6000 port\n", tag()); + } + } + } + } +} + +/* + Specific write access: grom_write +*/ +void snug_high_speed_gpl_device::grom_write(address_space& space, offs_t offset, UINT8 data, UINT8 mem_mask) +{ + if (space.debugger_access()) return; + + //activedevice_adjust_icount(-4); + + // 1001 11bb bbbb bba0 + int port = (offset & 0x3fc) >> 2; + + if (offset & 2) + { // Write GPL address. This must be available even when the rest + // of the card is offline (card_enabled=0). + m_raddr_LSB = false; + + if (m_waddr_LSB) + { + m_grom_address = (m_grom_address & 0xFF00) | data; + m_waddr_LSB = false; + } + else + { + m_grom_address = (data << 8) | (m_grom_address & 0xFF); + m_waddr_LSB = true; + } + } + else + { + bool bNew = (port != m_current_grom_port); + m_current_grom_port = port; + // It is not clear what effect a CRDENA=0 really has. + // At least GROMs 0-2 must remain visible, or the console will lock up. + if (m_card_enabled || m_grom_address < 0x6000) + { + /* write GPL data */ + if (m_write_enabled) + { + if ((port < 2) && (m_gram_enabled)) + { + m_gram_memory[m_grom_address | (port<<16)] = data; + m_module_bank = port + 16; + if (TRACE_PORT) if (bNew) logerror("%s: GRAM write access at %04x (GRMENA=1) - switch to bank %d\n", tag(), offset & 0xffff, port); + } + else + { + if (port < 8) + { + m_grom_a_eeprom->write(space, m_grom_address | (port<<16), data, mem_mask); + m_module_bank = port; + if (TRACE_PORT) if (bNew) logerror("%s: GROM write access at %04x - switch to bank %d\n", tag(), offset & 0xffff, port); + } + else + { + if (port < 16) + { + m_grom_b_eeprom->write(space, m_grom_address | ((port-8)<<16), data, mem_mask); + m_module_bank = port; + if (TRACE_PORT) if (bNew) logerror("%s: GROM write access at %04x - switch to bank %d\n", tag(), offset & 0xffff, port); + } + else + { + if (port < 24) + { + m_dsr_eeprom->write(space, m_grom_address | ((port-16)<<16), data, mem_mask); + if (TRACE_DSR) if (bNew) logerror("%s: write access to DSR bank %d-%d (%04x)\n", tag(), (port-16)<<3, ((port-16)<<3)+7, offset); + } + else + { + if (port < 32) + { + m_rom6_eeprom->write(space, m_grom_address | ((port-24)<<16), data, mem_mask); + if (TRACE_PORT) if (bNew) logerror("%s: ROM6 write access for module bank %d-%d (%04x)\n", tag(), (port-24)<<1, ((port-24)<<1)+1,offset & 0xffff); + } + else + { + if (port==32 || port==33) + { + m_gram_memory[m_grom_address | ((port-32)<<16)] = data; + m_module_bank = port - 16; + if (TRACE_PORT) if (bNew) logerror("%s: GRAM write access at %04x - switch to bank %d\n", tag(), offset & 0xffff, m_module_bank); + } + else + { + if (port==48 || port==49) + { +// m_ram6_memory[m_grom_address] = data; + m_ram6_memory[m_grom_address | ((port-48)<<16)] = data; + if (TRACE_PORT) if (bNew) logerror("%s: RAM write access at %04x\n", tag(), offset & 0xffff); + } + else + { + logerror("%s: Attempt to write to undefined port; ignored.\n", tag()); + } + } + } + } + } + } + } + } + } + // The address auto-increment should be done even when the card is + // offline + m_grom_address++; + m_raddr_LSB = m_waddr_LSB = false; + } +} + + +void snug_high_speed_gpl_device::device_start() +{ + m_ram6_memory = global_alloc_array(UINT8, RAMSIZE); + m_gram_memory = global_alloc_array(UINT8, GRAMSIZE); +} + +void snug_high_speed_gpl_device::device_reset() +{ + logerror("%s: reset\n", tag()); + m_dsr_enabled = false; + m_gram_enabled = false; + m_bank_inhibit = false; + m_dsr_page = 0; + m_card_enabled = true; // important, assumed to be enabled by default + m_write_enabled = false; + m_supercart_enabled = false; + m_led_on = false; + m_mbx_enabled = false; + m_ram_enabled = false; + m_flash_mode = (ioport("HSGPLMODE")->read()==0); + + m_current_grom_port = 0; + m_current_bank = 0; + + m_waddr_LSB = false; + m_raddr_LSB = false; + m_grom_address = 0; + m_module_bank = 0; +} + +void snug_high_speed_gpl_device::device_config_complete(void) +{ + m_dsr_eeprom = subdevice(DSR_EEPROM); + m_rom6_eeprom = subdevice(ROM6_EEPROM); + m_grom_a_eeprom = subdevice(GROM_A_EEPROM); + m_grom_b_eeprom = subdevice(GROM_B_EEPROM); +} + +void snug_high_speed_gpl_device::device_stop() +{ + global_free_array(m_ram6_memory); + global_free_array(m_gram_memory); +} + +// Flash setting is used to flash an empty HSGPL DSR ROM +INPUT_PORTS_START( ti99_hsgpl) + PORT_START( "HSGPLMODE" ) + PORT_DIPNAME( 0x01, 0x01, "HSGPL mode" ) + PORT_DIPSETTING( 0x00, "Flash" ) + PORT_DIPSETTING( 0x01, "Normal" ) +INPUT_PORTS_END + +MACHINE_CONFIG_FRAGMENT( ti99_hsgpl ) + MCFG_AT29C040A_ADD( DSR_EEPROM ) + MCFG_AT29C040A_ADD( GROM_B_EEPROM ) + MCFG_AT29C040A_ADD( GROM_A_EEPROM ) + MCFG_AT29C040A_ADD( ROM6_EEPROM ) +MACHINE_CONFIG_END + +machine_config_constructor snug_high_speed_gpl_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( ti99_hsgpl ); +} + +ioport_constructor snug_high_speed_gpl_device::device_input_ports() const +{ + return INPUT_PORTS_NAME(ti99_hsgpl); +} + +const device_type TI99_HSGPL = &device_creator; diff --git a/src/devices/bus/ti99_peb/hsgpl.h b/src/devices/bus/ti99_peb/hsgpl.h new file mode 100644 index 00000000000..bb87cc77a38 --- /dev/null +++ b/src/devices/bus/ti99_peb/hsgpl.h @@ -0,0 +1,83 @@ +// license:LGPL-2.1+ +// copyright-holders:Michael Zapf +/**************************************************************************** + + SNUG HSGPL card emulation. + See hsgpl.c for documentation + + Raphael Nabet, 2003. + + Michael Zapf + October 2010: Rewritten as device + February 2012: Rewritten as class + +*****************************************************************************/ + +#ifndef __HSGPL__ +#define __HSGPL__ + +#include "emu.h" +#include "peribox.h" +#include "machine/at29x.h" + +extern const device_type TI99_HSGPL; + +class snug_high_speed_gpl_device : public ti_expansion_card_device +{ +public: + snug_high_speed_gpl_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + DECLARE_READ8Z_MEMBER(readz); + DECLARE_WRITE8_MEMBER(write); + + DECLARE_READ8Z_MEMBER(crureadz); + DECLARE_WRITE8_MEMBER(cruwrite); + +protected: + virtual void device_start(void); + virtual void device_reset(void); + virtual void device_stop(void); + virtual void device_config_complete(void); + virtual ioport_constructor device_input_ports() const; + + virtual machine_config_constructor device_mconfig_additions() const; + +private: + at29c040a_device* m_dsr_eeprom; + at29c040a_device* m_rom6_eeprom; + at29c040a_device* m_grom_a_eeprom; + at29c040a_device* m_grom_b_eeprom; + + UINT8* m_ram6_memory; + UINT8* m_gram_memory; + + void dsrspace_readz(address_space& space, offs_t offset, UINT8* value, UINT8 mem_mask); + void cartspace_readz(address_space& space, offs_t offset, UINT8* value, UINT8 mem_mask); + void grom_readz(address_space& space, offs_t offset, UINT8* value, UINT8 mem_mask); + + void cartspace_write(address_space& space, offs_t offset, UINT8 data, UINT8 mem_mask); + void grom_write(address_space& space, offs_t offset, UINT8 data, UINT8 mem_mask); + + bool m_dsr_enabled; + bool m_gram_enabled; + bool m_bank_inhibit; + int m_dsr_page; + bool m_card_enabled; + bool m_write_enabled; + bool m_supercart_enabled; + bool m_led_on; + bool m_mbx_enabled; + bool m_ram_enabled; + bool m_flash_mode; + + int m_current_grom_port; + int m_current_bank; + + int m_module_bank; + + // GROM emulation + bool m_waddr_LSB; + bool m_raddr_LSB; + int m_grom_address; +}; + +#endif diff --git a/src/devices/bus/ti99_peb/memex.c b/src/devices/bus/ti99_peb/memex.c new file mode 100644 index 00000000000..66c3a571838 --- /dev/null +++ b/src/devices/bus/ti99_peb/memex.c @@ -0,0 +1,176 @@ +// license:LGPL-2.1+ +// copyright-holders:Michael Zapf +/*************************************************************************** + + Geneve "Memex" memory expansion + may be used together with the GenMod feature to expand the memory to the + full 2 MiB range. + + Michael Zapf + February 2011 + February 2012: rewritten as class + +****************************************************************************/ + +#include "memex.h" + +#define MEMEX_SIZE 0x200000 +#define RAMREGION "ram" + +#define VERBOSE 1 +#define LOG logerror + +enum +{ + MDIP1 = 0x01, + MDIP2 = 0x02, + MDIP3 = 0x04, + MDIP4 = 0x08, + MDIP5 = 0x10, + MDIP6 = 0x20, + MDIP7 = 0x40, + MDIP8 = 0x80 +}; + +geneve_memex_device::geneve_memex_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) +: ti_expansion_card_device(mconfig, TI99_MEMEX, "Geneve memory expansion card", tag, owner, clock, "ti99_memex", __FILE__) +{ +} + +bool geneve_memex_device::access_enabled(offs_t offset) +{ + // 1 0111 .... .... .... .... p-box address block 0xxx ... fxxx + // first two bits are AME, AMD bits available on Genmod only + // if AMD, AME are not available we assume AMD=0, AME=1 + // must be set on the Geneve board + // Some traditional cards will not decode the AMx lines, so + // we may have to lock out those areas + int page = (offset >> 13)&0xff; + int index = 0; + + // SW2: "off" locks + // 10xxx010 + // 10111010 also locked when "on" + if (page == 0xba) return false; + if ((page & 0xc7)==0x82 && m_dip_switch[1]==false) + { + if (VERBOSE>8) LOG("geneve: memex blocks page %02x; dip1=%d\n", page, m_dip_switch[1]); + return false; + } + + // SW3: 111010xx 0=enabled 1=locked out + // SW4: 111011xx + // SW5: 111100xx + // SW6: 111101xx + // SW7: 111110xx + // SW8: 111111xx + + index = ((page >> 2)&0x3f); + if (index >= 0x3a && index <= 0x3f) + { + if (m_dip_switch[index - 0x38]==0) return true; + else + { + return false; + } + } + return true; +} + +/* + Memory read. The memory is at locations 0x000000-0x1fffff. Some of these + regions are hidden by onboard devices of the Geneve. We must block some + areas which would otherwise interfere with peripheral cards. + + Note that the incomplete decoding of the standard Geneve must be + considered. +*/ +READ8Z_MEMBER( geneve_memex_device::readz ) +{ + /* If not Genmod, add the upper two address bits 10 */ + if (!m_genmod) offset |= 0x100000; + + // The card is accessed for all addresses in the address space + if (access_enabled(offset)) + { + *value = m_ram[offset]; + } +} + +/* + Memory write +*/ +WRITE8_MEMBER( geneve_memex_device::write ) +{ + /* If not Genmod, add the upper two address bits 10 */ + if (!m_genmod) offset |= 0x100000; + + // The card is accessed for all addresses in the address space + if (access_enabled(offset)) + { + m_ram[offset] = data; + } +} + +/**************************************************************************/ + +void geneve_memex_device::device_start() +{ + m_ram = memregion(RAMREGION)->base(); +} + +void geneve_memex_device::device_reset() +{ + UINT8 dips = ioport("MEMEXDIPS")->read(); + if (VERBOSE>5) LOG("geneve: memex dips = %02x\n", dips); + for (int i=0; i < 8; i++) + { + m_dip_switch[i] = ((dips & 0x01)!=0x00); + dips = dips >> 1; + } +} + +INPUT_PORTS_START( memex ) + PORT_START( "MEMEXDIPS" ) + PORT_DIPNAME( MDIP1, MDIP1, "MEMEX SW1" ) + PORT_DIPSETTING( 0x00, "LED half-bright for 0 WS") + PORT_DIPSETTING( MDIP1, "LED full-bright") + PORT_DIPNAME( MDIP2, 0x00, "MEMEX SW2" ) + PORT_DIPSETTING( 0x00, "Lock out all BA mirrors") + PORT_DIPSETTING( MDIP2, "Lock out page BA only") + PORT_DIPNAME( MDIP3, 0x00, "MEMEX SW3" ) + PORT_DIPSETTING( 0x00, "Enable pages E8-EB") + PORT_DIPSETTING( MDIP3, "Lock out pages E8-EB") + PORT_DIPNAME( MDIP4, 0x00, "MEMEX SW4" ) + PORT_DIPSETTING( 0x00, "Enable pages EC-EF") + PORT_DIPSETTING( MDIP4, "Lock out pages EC-EF") + PORT_DIPNAME( MDIP5, 0x00, "MEMEX SW5" ) + PORT_DIPSETTING( 0x00, "Enable pages F0-F3") + PORT_DIPSETTING( MDIP5, "Lock out pages F0-F3") + PORT_DIPNAME( MDIP6, 0x00, "MEMEX SW6" ) + PORT_DIPSETTING( 0x00, "Enable pages F4-F7") + PORT_DIPSETTING( MDIP6, "Lock out pages F4-F7") + PORT_DIPNAME( MDIP7, 0x00, "MEMEX SW7" ) + PORT_DIPSETTING( 0x00, "Enable pages F8-FB") + PORT_DIPSETTING( MDIP7, "Lock out pages F8-FB") + PORT_DIPNAME( MDIP8, 0x00, "MEMEX SW8" ) + PORT_DIPSETTING( 0x00, "Enable pages FC-FF") + PORT_DIPSETTING( MDIP8, "Lock out pages FC-FF") +INPUT_PORTS_END + +ROM_START( memex ) + ROM_REGION(MEMEX_SIZE, RAMREGION, 0) + ROM_FILL(0x000000, MEMEX_SIZE, 0x00) +ROM_END + +ioport_constructor geneve_memex_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( memex ); +} + +const rom_entry *geneve_memex_device::device_rom_region() const +{ + return ROM_NAME( memex ); +} + +const device_type TI99_MEMEX = &device_creator; diff --git a/src/devices/bus/ti99_peb/memex.h b/src/devices/bus/ti99_peb/memex.h new file mode 100644 index 00000000000..bccc4da161c --- /dev/null +++ b/src/devices/bus/ti99_peb/memex.h @@ -0,0 +1,45 @@ +// license:LGPL-2.1+ +// copyright-holders:Michael Zapf +/**************************************************************************** + + Geneve "Memex" memory expansion + See memex.c for documentation + + Michael Zapf, February 2011 + February 2012: Rewritten as class + +*****************************************************************************/ + +#ifndef __MEMEXMEM__ +#define __MEMEXMEM__ + +#include "emu.h" +#include "peribox.h" + +extern const device_type TI99_MEMEX; + +class geneve_memex_device : public ti_expansion_card_device +{ +public: + geneve_memex_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + DECLARE_READ8Z_MEMBER(readz); + DECLARE_WRITE8_MEMBER(write); + + DECLARE_READ8Z_MEMBER(crureadz) { }; + DECLARE_WRITE8_MEMBER(cruwrite) { }; + +protected: + virtual void device_start(); + virtual void device_reset(); + virtual ioport_constructor device_input_ports() const; + virtual const rom_entry *device_rom_region() const; + +private: + bool access_enabled(offs_t offset); + + UINT8* m_ram; + UINT8 m_dip_switch[8]; + int m_genmod; +}; + +#endif diff --git a/src/devices/bus/ti99_peb/myarcmem.c b/src/devices/bus/ti99_peb/myarcmem.c new file mode 100644 index 00000000000..caeeb9504df --- /dev/null +++ b/src/devices/bus/ti99_peb/myarcmem.c @@ -0,0 +1,209 @@ +// license:LGPL-2.1+ +// copyright-holders:Michael Zapf +/**************************************************************************** + + TI-99 Myarc memory expansion + + The card features 128 KiB of RAM, not buffered. In the TI-99/4A address + space, RAM is located at 2000-3fff and a000-ffff (32 KiB). Using the CRU + interface, four banks of 32K each can be made visible in this area. + + We also emulate the 512 KiB version of this card; it works in the same way + but offers two more CRU bits for a total of 16 banks of 32 KiB RAM. + + Beside the RAM, the card also contains ROM with a DSR (Device service + routine, TI's term for the firmware). This 8 KiB ROM allows for + testing and partitioning the card, and it introduces new devices which + are make available to BASIC programs, like a RAMdisk device. + + There also was a 32 KiB version which did not contain a DSR; thus, it was + equivalent to a standard TI 32 KiB memory expansion and is not emulated + here. + + The firmware to be used with this card is a version that is tailored to + work with Myarc Extended Basic II. + + Michael Zapf + February 2012: rewritten as a class, adding DSR support + +****************************************************************************/ +#include "myarcmem.h" + +#define RAMREGION "ram" + +#define VERBOSE 0 +#define LOG logerror + +/* This card has two CRU bases where it answers. */ +#define MYARCMEM_CRU_BASE1 0x1000 +#define MYARCMEM_CRU_BASE2 0x1900 + +enum +{ + SIZE_128, + SIZE_512 +}; + +myarc_memory_expansion_device::myarc_memory_expansion_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) +: ti_expansion_card_device(mconfig, TI99_MYARCMEM, "Myarc Memory expansion card MEXP-1", tag, owner, clock, "ti99_myarcmem", __FILE__) +{ +} + +int myarc_memory_expansion_device::get_base(int offset) +{ + int base = 0; + if (m_size == SIZE_128) + { + base = ((m_bank & 0x03) << 15); + } + else + { + base = (m_bank << 15); + } + base |= (offset & 0x1fff); + return base; +} + +/* + Memory read access. + RAM is at 2000-3fff, a000-ffff; + ROM is at 4000-5fff (if CRU bit 0 is set) +*/ +READ8Z_MEMBER(myarc_memory_expansion_device::readz) +{ + int base = get_base(offset); + + switch((offset & 0xe000)>>13) + { + case 1: + *value = m_ram[base]; + break; + case 2: + if (m_selected) *value = m_dsrrom[offset & 0x1fff]; + break; + case 5: + *value = m_ram[base | 0x2000]; + break; + case 6: + *value = m_ram[base | 0x4000]; + break; + case 7: + *value = m_ram[base | 0x6000]; + break; + default: + break; + } +} + +/* + Memory write access. DSRROM does not allow writing. +*/ +WRITE8_MEMBER(myarc_memory_expansion_device::write) +{ + int base = get_base(offset); + + switch((offset & 0xe000)>>13) + { + case 1: + m_ram[base] = data; + break; + case 5: + m_ram[base | 0x2000] = data; + break; + case 6: + m_ram[base | 0x4000] = data; + break; + case 7: + m_ram[base | 0x6000] = data; + break; + default: + break; + } +} + +/* + CRU read. None here. +*/ +READ8Z_MEMBER(myarc_memory_expansion_device::crureadz) +{ +} + +/* + CRU write. Bit 0 turns on the DSR (firmware), bits 1-3 are used to select + one of several 32K RAM banks. + + Select bits + 1000 = DSRROM seen on 4000-5fff (128, 512K) + 1002 = bit 0 of RAM bank value (128, 512K) + 1004 = bit 1 of RAM bank value (128, 512K) + 1006 = bit 2 of RAM bank value (512K) + 1008 = bit 3 of RAM bank value (512K) +*/ +WRITE8_MEMBER(myarc_memory_expansion_device::cruwrite) +{ + if (((offset & 0xff00)==MYARCMEM_CRU_BASE1)||((offset & 0xff00)==MYARCMEM_CRU_BASE2)) + { + if ((offset & 0x000e)==0) + { + // Turn on/off DSR + m_selected = (data!=0); + } + else + { + // xxxx xxxx xxxx 0010 + // xxxx xxxx xxxx 0100 + // xxxx xxxx xxxx 0110 + // xxxx xxxx xxxx 1000 + int bankbit = 1 << (((offset & 0x000e)>>1)-1); + + if (data==0) + m_bank &= ~bankbit; + else + m_bank |= bankbit; + } + } +} + + +INPUT_PORTS_START( myarc_exp ) + PORT_START( "SIZE" ) + PORT_CONFNAME( 0x01, SIZE_512, "Myarc memory card size" ) + PORT_CONFSETTING( SIZE_128, "128 KiB") + PORT_CONFSETTING( SIZE_512, "512 KiB") +INPUT_PORTS_END + +ROM_START( myarc_exp ) + ROM_REGION(0x2000, DSRROM, 0) + ROM_LOAD("myarc512k_xb2.bin", 0x0000, 0x2000, CRC(41fbb96d) SHA1(4dc7fdfa46842957bcbb0cf2c37764e4bb6d877a)) /* DSR for Ramdisk etc. */ + ROM_REGION(0x80000, RAMREGION, 0) + ROM_FILL(0x0000, 0x80000, 0x00) +ROM_END + +void myarc_memory_expansion_device::device_start() +{ + if (VERBOSE>5) LOG("myarc memexp: start\n"); + m_dsrrom = memregion(DSRROM)->base(); + m_ram = memregion(RAMREGION)->base(); +} + +void myarc_memory_expansion_device::device_reset() +{ + if (VERBOSE>5) LOG("myarc memexp: reset\n"); + m_size = ioport("SIZE")->read(); + + // Resetting values + m_bank = 0; + m_selected = false; +} + +const rom_entry *myarc_memory_expansion_device::device_rom_region() const +{ + return ROM_NAME( myarc_exp ); +} + +ioport_constructor myarc_memory_expansion_device::device_input_ports() const +{ + return INPUT_PORTS_NAME(myarc_exp); +} + +const device_type TI99_MYARCMEM = &device_creator; diff --git a/src/devices/bus/ti99_peb/myarcmem.h b/src/devices/bus/ti99_peb/myarcmem.h new file mode 100644 index 00000000000..a28c4d989b2 --- /dev/null +++ b/src/devices/bus/ti99_peb/myarcmem.h @@ -0,0 +1,45 @@ +// license:LGPL-2.1+ +// copyright-holders:Michael Zapf +/**************************************************************************** + + TI-99 Myarc memory expansion + See myarcmem.c for documentation + + Michael Zapf, September 2010 + February 2012: Rewritten as class + +*****************************************************************************/ + +#ifndef __MYARCMEM__ +#define __MYARCMEM__ + +#include "emu.h" +#include "peribox.h" + +extern const device_type TI99_MYARCMEM; + +class myarc_memory_expansion_device : public ti_expansion_card_device +{ +public: + myarc_memory_expansion_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + DECLARE_READ8Z_MEMBER(readz); + DECLARE_WRITE8_MEMBER(write); + + DECLARE_READ8Z_MEMBER(crureadz); + DECLARE_WRITE8_MEMBER(cruwrite); + +protected: + virtual void device_start(void); + virtual void device_reset(void); + virtual const rom_entry *device_rom_region(void) const; + virtual ioport_constructor device_input_ports() const; + +private: + int get_base(int offset); + UINT8* m_ram; + UINT8* m_dsrrom; + int m_bank; + int m_size; +}; + +#endif diff --git a/src/devices/bus/ti99_peb/pcode.c b/src/devices/bus/ti99_peb/pcode.c new file mode 100644 index 00000000000..eb12a20a8e8 --- /dev/null +++ b/src/devices/bus/ti99_peb/pcode.c @@ -0,0 +1,331 @@ +// license:LGPL-2.1+ +// copyright-holders:Michael Zapf +/**************************************************************************** + + TI-99 P-Code Card emulation. + + The P-Code card is part of the UCSD p-System support for the TI-99 + computer family. This system is a comprehensive development system for + creating, running, and debugging programs written in UCSD Pascal. + + The complete system consists of + - P-Code card, plugged into the Peripheral Expansion Box (PEB) + - Software on disk: + + PHD5063: UCSD p-System Compiler + + PHD5064: UCSD p-System Assembler/Linker + + PHD5065: UCSD p-System Editor/Filer (2 disks) + + The card has a switch on the circuit board extending outside the PEB + which allows to turn off the card without removing it. Unlike other + expansion cards for the TI system, the P-Code card immediately takes + over control after the system is turned on. + + When the p-System is booted, the screen turns cyan and remains empty. + There are two beeps, a pause for about 15 seconds, another three beeps, + and then a welcome text is displayed with a one-line menu at the screen + top. (Delay times seem unrealistically short; the manual says + 30-60 seconds. To be checked.) + Many of the functions require one of the disks be inserted in one + of the disk drives. You can leave the p-System by waiting for the menu + to appear, and typing H (halt). This returns you to the Master Title + Screen, and the card is inactive until the system is reset. + + The P-Code card contains the P-Code interpreter which is somewhat + comparable to today's Java virtual machine. Programs written for the + p-System are interchangeable between different platforms. + + On the P-Code card we find 12 KiB of ROM, visible in the DSR memory area + (>4000 to >5FFF). The first 4 KiB (>4000->4FFF) are from the 4732 ROM, + the second and third 4 KiB (>5000->5FFF) are from a 4764 ROM, switched + by setting the CRU bit 4 to 1 on the CRU base >1F00. + + CRU base >1F00 + Bit 0: Activate card + Bit 4: Select bank 2 of the 4764 ROM (0 = bank 1) + Bit 7: May be connected to an indicator LED which is by default + wired to bit 0 (on the PCB) + + The lines are used in a slightly uncommon way: the three bits of the + CRU bit address are A8, A13, and A14 (A15=LSB). Hence, bit 4 is at + address >1F80, and bit 7 is at address >1F86. These bits are purely + write-only. + + Moreover, the card contains 48 KiB of GROM memory, occupying the address + space from G>0000 to G>FFFF in portions of 6KiB at every 8KiB boundary. + + Another specialty of the card is that the GROM contents are accessed via + another GROM base address than what is used in the console: + - >5BFC = read GROM data + - >5BFE = read GROM address + - >5FFC = write GROM data + - >5FFE = write GROM address + + This makes the GROM memory "private" to the card; together with the + rest of the ROM space the ports become invisible when the card is + deactivated. + + Michael Zapf + + July 2009: First version + September 2010: Rewritten as device + February 2012: Rewritten as class + +*****************************************************************************/ + +#include "pcode.h" + +#define PCODE_GROM_TAG "pcode_grom" +#define PCODE_ROM_TAG "pcode_rom" + +#define PGROM0_TAG "grom0" +#define PGROM1_TAG "grom1" +#define PGROM2_TAG "grom2" +#define PGROM3_TAG "grom3" +#define PGROM4_TAG "grom4" +#define PGROM5_TAG "grom5" +#define PGROM6_TAG "grom6" +#define PGROM7_TAG "grom7" + +#define GROMMASK 0x1ffd +#define GROMREAD 0x1bfc +#define GROMWRITE 0x1ffc + +#define ACTIVE_TAG "ACTIVE" + +#define LOG logerror +#define VERBOSE 1 + +ti_pcode_card_device::ti_pcode_card_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) +: ti_expansion_card_device(mconfig, TI99_P_CODE, "TI-99 P-Code Card", tag, owner, clock, "ti99_pcode", __FILE__) +{ +} + +READ8Z_MEMBER( ti_pcode_card_device::readz ) +{ + if (m_switch && m_selected && ((offset & m_select_mask)==m_select_value)) + { + // GROM access + if ((offset & GROMMASK)==GROMREAD) + { + for (int i=0; i < 8; i++) m_grom[i]->readz(space, offset, value, mem_mask); + if (VERBOSE>5) LOG("ti99_pcode: read from grom %04x: %02x\n", offset&0xffff, *value); + } + else + { + if ((offset & 0x1000) == 0x0000) + { + /* Accesses ROM 4732 (4K) */ + // 0000 xxxx xxxx xxxx + *value = m_rom[offset & 0x0fff]; + if (VERBOSE>5) LOG("ti99_pcode: read from rom %04x: %02x\n", offset&0xffff, *value); + } + else + { + // Accesses ROM 4764 (2*4K) + // We have two banks here which are activated according + // to the setting of CRU bit 4 + // Bank 0 is the ROM above + // 0001 xxxx xxxx xxxx Bank 1 + // 0010 xxxx xxxx xxxx Bank 2 + *value = m_rom[(m_bank_select<<12) | (offset & 0x0fff)]; + if (VERBOSE>5) LOG("ti99_pcode: read from rom %04x (%02x): %02x\n", offset&0xffff, m_bank_select, *value); + } + } + } +} + +/* + Write a byte in P-Code ROM space. This is only used for setting the + GROM address. +*/ +WRITE8_MEMBER( ti_pcode_card_device::write ) +{ + if (m_switch && m_selected) + { + if ((offset & m_select_mask)==m_select_value) + { + if (VERBOSE>5) LOG("ti99_pcode: write to address %04x: %02x\n", offset & 0xffff, data); + // 0101 1111 1111 11x0 + if ((offset & GROMMASK) == GROMWRITE) + { + for (int i=0; i < 8; i++) m_grom[i]->write(space, offset, data, mem_mask); + } + } + } +} + +/* + Common READY* line from the GROMs. + At this time we do not emulate GROM READY* since the CPU emulation does + not yet process READY*. If it did, however, we would have to do a similar + handling as in peribox (with INTA*): The common READY* line is a logical + AND of all single READY lines. If any GROM pulls it down, the line goes + down, and only if all GROMs release it, it pulls up again. We should think + about a general solution. +*/ +WRITE_LINE_MEMBER( ti_pcode_card_device::ready_line ) +{ + m_slot->set_ready(state); +} + +/* + CRU read handler. The P-Code card does not offer CRU read lines, so + we just ignore any request. (Note that CRU lines are not like memory; you + may be able to write to them, but not necessarily read them again.) +*/ +READ8Z_MEMBER(ti_pcode_card_device::crureadz) +{ +} + +/* + The CRU write handler. + Bit 0 = activate card + Bit 4 = select second bank of high ROM. + + Somewhat uncommon, the CRU address is created from address lines + A8, A13, and A14 so bit 0 is at 0x1f00, but bit 4 is at 0x1f80. Accordingly, + bit 7 would be 0x1f86 but it is not used. +*/ +WRITE8_MEMBER(ti_pcode_card_device::cruwrite) +{ + if ((offset & 0xff00)==m_cru_base) + { + int addr = offset & 0x00ff; + + if (addr==0) + m_selected = (data != 0); + + if (addr==0x80) // Bit 4 is on address line 8 + { + m_bank_select = (data+1); // we're calling this bank 1 and bank 2 + if (VERBOSE>5) LOG("ti99_pcode: select rom bank %d\n", m_bank_select); + } + } +} + +static GROM_CONFIG(pgrom0_config) +{ + false, 0, PCODE_GROM_TAG, 0x0000, 0x1800, GROMFREQ +}; +static GROM_CONFIG(pgrom1_config) +{ + false, 1, PCODE_GROM_TAG, 0x2000, 0x1800, GROMFREQ +}; +static GROM_CONFIG(pgrom2_config) +{ + false, 2, PCODE_GROM_TAG, 0x4000, 0x1800, GROMFREQ +}; +static GROM_CONFIG(pgrom3_config) +{ + false, 3, PCODE_GROM_TAG, 0x6000, 0x1800, GROMFREQ +}; +static GROM_CONFIG(pgrom4_config) +{ + false, 4, PCODE_GROM_TAG, 0x8000, 0x1800, GROMFREQ +}; +static GROM_CONFIG(pgrom5_config) +{ + false, 5, PCODE_GROM_TAG, 0xa000, 0x1800, GROMFREQ +}; +static GROM_CONFIG(pgrom6_config) +{ + false, 6, PCODE_GROM_TAG, 0xc000, 0x1800, GROMFREQ +}; +static GROM_CONFIG(pgrom7_config) +{ + false, 7, PCODE_GROM_TAG, 0xe000, 0x1800, GROMFREQ +}; + +void ti_pcode_card_device::device_start() +{ + m_cru_base = 0x1f00; + m_grom[0] = static_cast(subdevice(PGROM0_TAG)); + m_grom[1] = static_cast(subdevice(PGROM1_TAG)); + m_grom[2] = static_cast(subdevice(PGROM2_TAG)); + m_grom[3] = static_cast(subdevice(PGROM3_TAG)); + m_grom[4] = static_cast(subdevice(PGROM4_TAG)); + m_grom[5] = static_cast(subdevice(PGROM5_TAG)); + m_grom[6] = static_cast(subdevice(PGROM6_TAG)); + m_grom[7] = static_cast(subdevice(PGROM7_TAG)); + m_rom = memregion(PCODE_ROM_TAG)->base(); +} + +void ti_pcode_card_device::device_reset() +{ + if (m_genmod) + { + m_select_mask = 0x1fe000; + m_select_value = 0x174000; + } + else + { + m_select_mask = 0x7e000; + m_select_value = 0x74000; + } + m_bank_select = 1; + m_selected = false; + + m_switch = ioport(ACTIVE_TAG)->read(); +} + +void ti_pcode_card_device::device_config_complete() +{ +} + +INPUT_CHANGED_MEMBER( ti_pcode_card_device::switch_changed ) +{ + if (VERBOSE>7) LOG("ti_pcode_card_device: switch changed to %d\n", newval); + m_switch = (newval != 0); +} + + +MACHINE_CONFIG_FRAGMENT( ti99_pcode ) + MCFG_GROM_ADD( PGROM0_TAG, pgrom0_config ) + MCFG_GROM_READY_CALLBACK(WRITELINE(ti_pcode_card_device, ready_line)) + MCFG_GROM_ADD( PGROM1_TAG, pgrom1_config ) + MCFG_GROM_READY_CALLBACK(WRITELINE(ti_pcode_card_device, ready_line)) + MCFG_GROM_ADD( PGROM2_TAG, pgrom2_config ) + MCFG_GROM_READY_CALLBACK(WRITELINE(ti_pcode_card_device, ready_line)) + MCFG_GROM_ADD( PGROM3_TAG, pgrom3_config ) + MCFG_GROM_READY_CALLBACK(WRITELINE(ti_pcode_card_device, ready_line)) + MCFG_GROM_ADD( PGROM4_TAG, pgrom4_config ) + MCFG_GROM_READY_CALLBACK(WRITELINE(ti_pcode_card_device, ready_line)) + MCFG_GROM_ADD( PGROM5_TAG, pgrom5_config ) + MCFG_GROM_READY_CALLBACK(WRITELINE(ti_pcode_card_device, ready_line)) + MCFG_GROM_ADD( PGROM6_TAG, pgrom6_config ) + MCFG_GROM_READY_CALLBACK(WRITELINE(ti_pcode_card_device, ready_line)) + MCFG_GROM_ADD( PGROM7_TAG, pgrom7_config ) + MCFG_GROM_READY_CALLBACK(WRITELINE(ti_pcode_card_device, ready_line)) +MACHINE_CONFIG_END + +INPUT_PORTS_START( ti99_pcode ) + PORT_START( ACTIVE_TAG ) + PORT_DIPNAME( 0x01, 0x00, "P-Code activation switch" ) PORT_CHANGED_MEMBER(DEVICE_SELF, ti_pcode_card_device, switch_changed, 0) + PORT_DIPSETTING( 0x00, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x01, DEF_STR( On ) ) +INPUT_PORTS_END + +ROM_START( ti99_pcode ) + ROM_REGION(0x10000, PCODE_GROM_TAG, 0) + ROM_LOAD("pcode_g0.bin", 0x0000, 0x10000, CRC(541b3860) SHA1(7be77c216737334ae997753a6a85136f117affb7)) /* TI P-Code card groms */ + ROM_REGION(0x3000, PCODE_ROM_TAG, 0) + ROM_LOAD("pcode_r0.bin", 0x0000, 0x1000, CRC(3881d5b0) SHA1(a60e0468bb15ff72f97cf6e80979ca8c11ed0426)) /* TI P-Code card rom4732 */ + ROM_LOAD("pcode_r1.bin", 0x1000, 0x2000, CRC(46a06b8b) SHA1(24e2608179921aef312cdee6f455e3f46deb30d0)) /* TI P-Code card rom4764 */ +ROM_END + +machine_config_constructor ti_pcode_card_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( ti99_pcode ); +} + +const rom_entry *ti_pcode_card_device::device_rom_region() const +{ + return ROM_NAME( ti99_pcode ); +} + +ioport_constructor ti_pcode_card_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( ti99_pcode ); +} + +const device_type TI99_P_CODE = &device_creator; diff --git a/src/devices/bus/ti99_peb/pcode.h b/src/devices/bus/ti99_peb/pcode.h new file mode 100644 index 00000000000..4630d127f13 --- /dev/null +++ b/src/devices/bus/ti99_peb/pcode.h @@ -0,0 +1,51 @@ +// license:LGPL-2.1+ +// copyright-holders:Michael Zapf +/**************************************************************************** + + TI-99 P-Code Card emulation. + See p_code.c for documentation + + Michael Zapf + July 2009 + Revised July 2010 + February 2012: Rewritten as class + +*****************************************************************************/ + +#ifndef __PCODE__ +#define __PCODE__ + +#include "emu.h" +#include "peribox.h" +#include "bus/ti99x/grom.h" + +extern const device_type TI99_P_CODE; + +class ti_pcode_card_device : public ti_expansion_card_device +{ +public: + ti_pcode_card_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + DECLARE_READ8Z_MEMBER(readz); + DECLARE_WRITE8_MEMBER(write); + DECLARE_READ8Z_MEMBER(crureadz); + DECLARE_WRITE8_MEMBER(cruwrite); + + DECLARE_WRITE_LINE_MEMBER( ready_line ); + DECLARE_INPUT_CHANGED_MEMBER( switch_changed ); + +protected: + virtual void device_start(); + virtual void device_reset(); + virtual void device_config_complete(); + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + virtual ioport_constructor device_input_ports() const; + +private: + ti99_grom_device* m_grom[8]; + UINT8* m_rom; + int m_bank_select; + bool m_switch; +}; + +#endif diff --git a/src/devices/bus/ti99_peb/peribox.c b/src/devices/bus/ti99_peb/peribox.c new file mode 100644 index 00000000000..9d5024e7fa6 --- /dev/null +++ b/src/devices/bus/ti99_peb/peribox.c @@ -0,0 +1,722 @@ +// license:LGPL-2.1+ +// copyright-holders:Michael Zapf +/**************************************************************************** + + Peripheral expansion system + + The ti-99/4, ti-99/4a, ti computer 99/8, myarc geneve, and snug sgcpu + 99/4p systems all feature a bus connector that enables the connection of + extension cards. (Although the hexbus is the preferred bus to add + additional peripherals to a ti-99/8, ti-99/8 is believed to be compatible + with the older PEB system.) In the case of the TI consoles, this bus + connector is located on the right side of the console. + + While a few extension cards connect to the side bus connector of the + ti-99/4(a) console directly, most extension cards were designed to be + inserted in a PEB instead. The PEB (Peripheral Expansion Box) is a big box + with power supply, a few bus drivers, and several card slots, that + connects to the ti-99/4(a) side port. The reason for using a PEB is that + daisy-chaining many modules caused the system to be unreliable due to the + noise produced by the successive contacts. (As a matter of fact, TI + initially released most of its extension cards as side bus units, but when + the design proved to be unreliable, the PEB was introduced. The TI speech + synthesizer was the only TI extension that remained on the side bus after + the introduction of the PEB, probably because TI wanted the speech + synthesizer to be a cheap extension, and the PEB was not cheap.) + + + =================## connection cable to console + || + || + +--------------+----+----+----+----+----+----+----+----+------------+ + | | S | S | S | S | S | S | S | S x passthru | + | | L | L | L | L | L | L | L | L x for cable | + | Power | O | O | O | O | O | O | O | O x | + | unit | T | T | T | T | T | T | T | T | | + | and | | | | | | | | | Floppy | + | ventilation | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | drive | + | | | | | | | | | | compartment| + | | | | | | | | | | | + | | | | | | | | | | 1 full hgt | + | | | | | | | | |LED | or 2 "slim"| + | +----+----+----+----+----+----+----+-|--+ (half-hgt) | + | : | seen from above | | | | | | + +--------------+-O----O----O----O----O----O----O----O---------------+ + + All slots are connected in parallel with all signal lines. The cards + must be equipped with bus drivers (244/245) and are usually activated + by turning a CRU bit on (except for the memory expansions which are + always active). + + This is emulation in exactly the same way. The data coming from the + console is propagated to all slots, and each card decides whether to + react or not. Similarly, for read operations, all cards are checked, + and only the active cards actually put a value on the data bus + (we do this using the bus8z_device; see ti99defs.h). + + Slot 1 is usually reserved for the "Flex cable interface" when connecting + a TI-99/4(A)/8 console. Also, the Geneve is put into slot 1. We therefore + do not offer peb:slot1. Slot 8 is usually used for floppy controllers + as there is a passthrough for cables. + + + Slots: + + REAR + +8V 1||2 +8V + GND 3||4 READY + GND 5||6 RESET* + GND 7||8 SCLK + BOOTPG* 9||10 AUDIO + RDBENA* 11||12 PCBEN + HOLD* 13||14 IAQHDA + SENILA* 15||16 SENILB* + INTA* 17||18 INTB* + D7 19||20 GND + D5 21||22 D6 + D3 23||24 D4 + D1 25||26 D2 + GND 27||28 D0 + A14 29||30 A15/CRUOUT + A12 31||32 A13 + A10 33||34 A11 + A8 35||36 A9 + A6 37||38 A7 + A4 39||40 A5 + A2 41||42 A3 + A0 43||44 A1 + AMB 45||46 AMA + GND 47||48 AMC + GND 49||50 CLKOUT* +CRUCLK* 51||52 DBIN + GND 53||54 WE* + CRUIN 55||56 MEMEN* + -16V 57||58 -16V + +16V 59||60 +16V + FRONT + + < from box to console + > from console into box + + READYA < System ready (goes to READY, 10K pull-up to +5V) A low level puts the cpu on hold. + RESET* > System reset (active low) + SCLK nc System clock (not connected in interface card) + LCP* nc CPU indicator 1=TI99 0=2nd generation (not connected in interface card) + BOOTPG* nc ? + AUDIO < Input audio (to AUDIOIN in console) + RDBENA* < Active low: enable flex cable data bus drivers (1K pull-up) + PCBEN H PCB enable for burn-in (always High) + HOLD* H Active low CPU hold request (always High) + IAQHDA nc IAQ [or] HOLDA (logical or) + SENILA* H(>) Interrupt level A sense enable (always High) + SENILB* H(>) Interrupt level B sense enable (always High) + INTA* < Interrupt level A (active low, goes to EXTINT*) + INTB* nc Interrupt level B (not used) + LOAD* nc Unmaskable interrupt (not carried by interface cable/card) + D0-D7 <> Data bus (D0 most significant) + A0-A15 > Address bus (A0 most sig; A15 also used as CRUOUT) + AMA/B/C H Extra address bits (always high for TI-99/4x, but used with SGCPU and Geneve) + CLKOUT* > Inverted PHI3 clock, from TIM9904 clock generator + CRUCLK* > Inverted CRU clock, from TMS9900 CRUCLK pin + DBIN > Active high = read memory. Drives the data bus buffers. + WE* > Write Enable pulse (derived from TMS9900 WE* pin) + CRUIN < CRU input bit to TMS9900 + MEMEN* > Memory access enable (active low) + + The SENILx lines are somewhat obscure, since there have never been hardware + or software that made practical use of them. The intended use can be guessed + from some few traditional cards (like the TI RS232) which indeed have + connections. + + With SENILA* asserted (low), a value shall be put on the data bus, + representing the interrupt status bits. It can also be used to determine + the source of the interrupt: The RS232 card (in its standard configuration) + uses the data bus bits 0 and 1 for its two UARTs, while in the second + configuration, it uses bits 4 and 5. + + SENILB* / INTB* was planned to be used with disk controllers. The PHP1240 disk + controller puts the value of INTB* on D0 when SENILB* gets active (low) which + reflects the INTRQ output pin of the WD1771. This signal is not used, however. + Instead, the disk controller combines DRQ and IRQ and makes use of a READY/HOLD + control of the CPU. + + Obviously, SENILA* and SENILB* should never be active at the same time, and + neither should any memory access to a card be active at the same time, for in + both cases, data bus lines may be set to different levels simultaneously. One + possible application case is to turn off all cards in the box, assert SENILA*, + and then do a read access in the memory area of any card in the P-Box (e.g. + 0x4000-0x5fff). Another possiblity is that the currently active card simply + does not respond to a certain memory access, and in this case the status bits + can be read. + + Also note that the SENILx lines access all cards in parallel, meaning that there + must be an agreement which cards may use which bits on the data bus. The lines + do not depend on the card being active at that time. + + Emulation architecture + + console ---- peribox --+ [-- slot1 (always occupied by console connector) ] + | + +--- slot2 --- card + | + +--- slot3 --- card + : + +--- slot8 --- card (usually some floppy controller) + + We have an instance of peribox_device which contains 7 slots + (peribox_slot_device) which are subclasses of device_slot_interface. + Each slot may host one of several cards (ti_expansion_card_device), + which are subclassed from device_slot_card_interface. + + For bus8z_device consult ti99defs.h + --------------------- + + June 2010: Reimplemented using device structure (MZ) + January 2012: Reimplemented as class (MZ) + +*****************************************************************************/ + +#include "emu.h" +#include "peribox.h" + +// The cards +#include "ti_32kmem.h" +#include "ti_fdc.h" +#include "bwg.h" +#include "hfdc.h" +#include "pcode.h" +#include "myarcmem.h" +#include "samsmem.h" +#include "tn_ide.h" +#include "tn_usbsm.h" +#include "evpc.h" +#include "hsgpl.h" +#include "ti_rs232.h" +#include "spchsyn.h" +#include "memex.h" +#include "horizon.h" + +/* + Debugging flags. Set to 0 or 1. +*/ +// Show interrupt line activity +#define TRACE_INT 0 + +// Show ready line activity +#define TRACE_READY 0 + +// Show emulation details +#define TRACE_EMU 1 + +#define PEBSLOT2 "slot2" +#define PEBSLOT3 "slot3" +#define PEBSLOT4 "slot4" +#define PEBSLOT5 "slot5" +#define PEBSLOT6 "slot6" +#define PEBSLOT7 "slot7" +#define PEBSLOT8 "slot8" + +peribox_device::peribox_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) +: bus8z_device(mconfig, PERIBOX, "Peripheral expansion box", tag, owner, clock, "peribox", __FILE__), + m_console_inta(*this), + m_console_intb(*this), + m_datamux_ready(*this) +{ + for (int i=2; i <= 8; i++) m_slot[i] = NULL; + // The address prefix is actually created by the "Flex cable interface" + // which sits in slot 1. + m_address_prefix = 0x70000; +} + +/* + Constructor called from subclasses. +*/ +peribox_device::peribox_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) +: bus8z_device(mconfig, type, name, tag, owner, clock, shortname, source), + m_console_inta(*this), + m_console_intb(*this), + m_datamux_ready(*this) +{ + for (int i=2; i <= 8; i++) m_slot[i] = NULL; +} + +READ8Z_MEMBER(peribox_device::readz) +{ + for (int i=2; i <= 8; i++) + { + if (m_slot[i]!=NULL) m_slot[i]->readz(space, offset | m_address_prefix, value, mem_mask); + } +} + +WRITE8_MEMBER(peribox_device::write) +{ + for (int i=2; i <= 8; i++) + { + if (m_slot[i]!=NULL) m_slot[i]->write(space, offset | m_address_prefix, data, mem_mask); + } +} + +SETADDRESS_DBIN_MEMBER(peribox_device::setaddress_dbin) +{ + for (int i=2; i <= 8; i++) + { + if (m_slot[i]!=NULL) m_slot[i]->setaddress_dbin(space, offset | m_address_prefix, state); + } +} + +READ8Z_MEMBER(peribox_device::crureadz) +{ + for (int i=2; i <= 8; i++) + { + if (m_slot[i]!=NULL) m_slot[i]->crureadz(space, offset, value); + } +} + +WRITE8_MEMBER(peribox_device::cruwrite) +{ + for (int i=2; i <= 8; i++) + { + if (m_slot[i]!=NULL) m_slot[i]->cruwrite(space, offset, data); + } +} + +/* + And here are finally the two mythical lines SENILA* and SENILB*; mythical + since there is no report of any software that ever used them. +*/ +WRITE_LINE_MEMBER(peribox_device::senila) +{ + for (int i=2; i <= 8; i++) + { + if (m_slot[i]!=NULL) m_slot[i]->senila(state); + } +} + +WRITE_LINE_MEMBER(peribox_device::senilb) +{ + for (int i=2; i <= 8; i++) + { + if (m_slot[i]!=NULL) m_slot[i]->senilb(state); + } +} + +/* + The Genmod modification is only of interest for the Geneve. It requires + to modify the decoding of each single card. +*/ +INPUT_CHANGED_MEMBER( peribox_device::genmod_changed ) +{ + set_genmod(newval==1); +} + +void peribox_device::set_genmod(bool set) +{ + for (int i=2; i <= 8; i++) + { + if (m_slot[i]!=NULL) m_slot[i]->set_genmod(set); + } +} + +/* + The INTA*, INTB*, and READY* lines are connected to each PEB card and are + pulled up when inactive. If any card asserts the line (pulling down), the + line state goes down. So we must keep a record which cards pull down the + line. + + (We're doing a kind of wired-AND here.) +*/ +void peribox_device::inta_join(int slot, int state) +{ + if (TRACE_INT) logerror("%s: propagating INTA from slot %d to console: %d\n", tag(), slot, state); + if (state==ASSERT_LINE) + m_inta_flag |= (1 << slot); + else + m_inta_flag &= ~(1 << slot); + + m_console_inta((m_inta_flag != 0)? ASSERT_LINE : CLEAR_LINE); +} + +void peribox_device::intb_join(int slot, int state) +{ + if (TRACE_INT) logerror("%s: propagating INTB from slot %d to console: %d\n", tag(), slot, state); + if (state==ASSERT_LINE) + m_intb_flag |= (1 << slot); + else + m_intb_flag &= ~(1 << slot); + + m_console_intb((m_intb_flag != 0)? ASSERT_LINE : CLEAR_LINE); +} + +/* + When any device pulls down READY, READY goes down. +*/ +void peribox_device::ready_join(int slot, int state) +{ + if (TRACE_READY) logerror("%s: Incoming READY=%d from slot %d\n", tag(), state, slot); + // We store the inverse state + if (state==CLEAR_LINE) + m_ready_flag |= (1 << slot); + else + m_ready_flag &= ~(1 << slot); + + m_datamux_ready((m_ready_flag != 0)? CLEAR_LINE : ASSERT_LINE); +} + +void peribox_device::set_slot_loaded(int slot, peribox_slot_device* slotdev) +{ + m_slot[slot] = slotdev; +} + +void peribox_device::device_start(void) +{ + if (TRACE_EMU) logerror("%s: started\n", tag()); + + // Resolve the callback lines to the console + m_console_inta.resolve(); + m_console_intb.resolve(); + m_datamux_ready.resolve(); + + if (TRACE_EMU) + { + logerror("%s: AMA/B/C address prefix set to %05x\n", tag(), m_address_prefix); + for (int i=2; i < 9; i++) + { + logerror("%s: Slot %d = %s\n", tag(), i, (m_slot[i] != NULL)? m_slot[i]->m_card->tag() : "EMPTY"); + } + } +} + +void peribox_device::device_config_complete() +{ + m_inta_flag = 0; + m_intb_flag = 0; + m_ready_flag = 0; +} + +SLOT_INTERFACE_START( peribox_slot ) + SLOT_INTERFACE("32kmem", TI_32KMEM) + SLOT_INTERFACE("myarcmem", TI99_MYARCMEM) + SLOT_INTERFACE("samsmem", TI99_SAMSMEM) + SLOT_INTERFACE("pcode", TI99_P_CODE) + SLOT_INTERFACE("hsgpl", TI99_HSGPL) + SLOT_INTERFACE("tirs232", TI99_RS232) + SLOT_INTERFACE("speech", TI99_SPEECH) + SLOT_INTERFACE("horizon", TI99_HORIZON) +SLOT_INTERFACE_END + +SLOT_INTERFACE_START( peribox_slot6 ) + SLOT_INTERFACE("ide", TI99_IDE) + SLOT_INTERFACE("usbsm", TI99_USBSM) + SLOT_INTERFACE("tirs232", TI99_RS232) + SLOT_INTERFACE("speech", TI99_SPEECH) +SLOT_INTERFACE_END + +SLOT_INTERFACE_START( peribox_slot7 ) + SLOT_INTERFACE("ide", TI99_IDE) + SLOT_INTERFACE("usbsm", TI99_USBSM) + SLOT_INTERFACE("bwg", TI99_BWG) + SLOT_INTERFACE("hfdc", TI99_HFDC) +SLOT_INTERFACE_END + +SLOT_INTERFACE_START( peribox_slot8 ) + SLOT_INTERFACE("tifdc", TI99_FDC) + SLOT_INTERFACE("bwg", TI99_BWG) + SLOT_INTERFACE("hfdc", TI99_HFDC) +SLOT_INTERFACE_END + +MACHINE_CONFIG_FRAGMENT( peribox_device ) + MCFG_PERIBOX_SLOT_ADD( PEBSLOT2, peribox_slot ) + MCFG_PERIBOX_SLOT_ADD( PEBSLOT3, peribox_slot ) + MCFG_PERIBOX_SLOT_ADD( PEBSLOT4, peribox_slot ) + MCFG_PERIBOX_SLOT_ADD( PEBSLOT5, peribox_slot ) + MCFG_PERIBOX_SLOT_ADD( PEBSLOT6, peribox_slot6 ) + MCFG_PERIBOX_SLOT_ADD( PEBSLOT7, peribox_slot7 ) + MCFG_PERIBOX_SLOT_ADD( PEBSLOT8, peribox_slot8 ) +MACHINE_CONFIG_END + +machine_config_constructor peribox_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( peribox_device ); +} + +/**************************************************************************** + A variant of the box used for the Geneve. +*****************************************************************************/ + +peribox_gen_device::peribox_gen_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) +: peribox_device(mconfig, PERIBOX_GEN, "Peripheral expansion box Geneve", tag, owner, clock, "peribox_gen", __FILE__) +{ + // The Geneve sits in slot 1; there is no prefix here - it can control + // a maximum address space of 512 KiB in the box. With the Genmod + // modification, the full 2 MiB space is available. + m_address_prefix = 0x00000; +} + +// The BwG controller will not run with the Geneve due to its wait state +// logic; it assumes that before reading 5FF6 (data register), address 5FF7 +// is also read (by means of the datamux). Unlike the 9900, the 9995 can read +// single bytes, so it will never trigger a read operation on 5FF7. + +SLOT_INTERFACE_START( peribox_slot7nobwg ) + SLOT_INTERFACE("ide", TI99_IDE) + SLOT_INTERFACE("usbsm", TI99_USBSM) + SLOT_INTERFACE("hfdc", TI99_HFDC) +SLOT_INTERFACE_END + +SLOT_INTERFACE_START( peribox_slot8nobwg ) + SLOT_INTERFACE("tifdc", TI99_FDC) + SLOT_INTERFACE("hfdc", TI99_HFDC) +SLOT_INTERFACE_END + +SLOT_INTERFACE_START( peribox_slotg ) + SLOT_INTERFACE("memex", TI99_MEMEX) + SLOT_INTERFACE("myarcmem", TI99_MYARCMEM) + SLOT_INTERFACE("samsmem", TI99_SAMSMEM) + SLOT_INTERFACE("pcode", TI99_P_CODE) + SLOT_INTERFACE("tirs232", TI99_RS232) + SLOT_INTERFACE("speech", TI99_SPEECH) + SLOT_INTERFACE("horizon", TI99_HORIZON) +SLOT_INTERFACE_END + +MACHINE_CONFIG_FRAGMENT( peribox_gen_device ) + MCFG_PERIBOX_SLOT_ADD( PEBSLOT2, peribox_slotg ) + MCFG_PERIBOX_SLOT_ADD( PEBSLOT3, peribox_slotg ) + MCFG_PERIBOX_SLOT_ADD( PEBSLOT4, peribox_slotg ) + MCFG_PERIBOX_SLOT_ADD( PEBSLOT5, peribox_slotg ) + MCFG_PERIBOX_SLOT_ADD( PEBSLOT6, peribox_slot6 ) + MCFG_PERIBOX_SLOT_ADD( PEBSLOT7, peribox_slot7nobwg ) + MCFG_PERIBOX_SLOT_ADD( PEBSLOT8, peribox_slot8nobwg ) +MACHINE_CONFIG_END + +machine_config_constructor peribox_gen_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( peribox_gen_device ); +} + +/**************************************************************************** + A variant of the box used for the TI-99/8 +*****************************************************************************/ + +peribox_998_device::peribox_998_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) +: peribox_device(mconfig, PERIBOX_998, "Peripheral expansion box 99/8", tag, owner, clock, "peribox_998", __FILE__) +{ + m_address_prefix = 0x70000; +} + +// The BwG controller will not run with the TI-99/8 for the same reason why +// it won't work with the Geneve. +// We don't have many options here. The P-Box is not the prefered device for +// the 99/8; it was intended to use the Hexbus interface. None of the memory +// expansions are really supposed to work here. +SLOT_INTERFACE_START( peribox_slot998 ) + SLOT_INTERFACE("myarcmem", TI99_MYARCMEM) + SLOT_INTERFACE("samsmem", TI99_SAMSMEM) + SLOT_INTERFACE("horizon", TI99_HORIZON) + SLOT_INTERFACE("ide", TI99_IDE) + SLOT_INTERFACE("usbsm", TI99_USBSM) + SLOT_INTERFACE("tirs232", TI99_RS232) +SLOT_INTERFACE_END + +MACHINE_CONFIG_FRAGMENT( peribox_998_device ) + MCFG_PERIBOX_SLOT_ADD( PEBSLOT2, peribox_slot998 ) + MCFG_PERIBOX_SLOT_ADD( PEBSLOT3, peribox_slot998 ) + MCFG_PERIBOX_SLOT_ADD( PEBSLOT4, peribox_slot998 ) + MCFG_PERIBOX_SLOT_ADD( PEBSLOT5, peribox_slot998 ) + MCFG_PERIBOX_SLOT_ADD( PEBSLOT6, peribox_slot998 ) + MCFG_PERIBOX_SLOT_ADD( PEBSLOT7, peribox_slot998 ) + MCFG_PERIBOX_SLOT_ADD( PEBSLOT8, peribox_slot8nobwg ) +MACHINE_CONFIG_END + +machine_config_constructor peribox_998_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( peribox_998_device ); +} + +/**************************************************************************** + A variant of the box used for the SGCPU (aka TI-99/4P). +*****************************************************************************/ + +peribox_sg_device::peribox_sg_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) +: peribox_device(mconfig, PERIBOX_SG, "Peripheral expansion box SGCPU", tag, owner, clock, "peribox_sg", __FILE__) +{ + m_address_prefix = 0x70000; +} + +SLOT_INTERFACE_START( peribox_slotp ) + SLOT_INTERFACE("pcode", TI99_P_CODE) + SLOT_INTERFACE("tirs232", TI99_RS232) + SLOT_INTERFACE("speech", TI99_SPEECH) + SLOT_INTERFACE("horizon", TI99_HORIZON) +SLOT_INTERFACE_END + +SLOT_INTERFACE_START( peribox_ev_slot ) + SLOT_INTERFACE("evpc", TI99_EVPC) +SLOT_INTERFACE_END + +SLOT_INTERFACE_START( peribox_hs_slot ) + SLOT_INTERFACE("hsgpl", TI99_HSGPL) +SLOT_INTERFACE_END + +MACHINE_CONFIG_FRAGMENT( peribox_sg_device ) + MCFG_PERIBOX_SLOT_ADD_DEF( PEBSLOT2, peribox_ev_slot, "evpc" ) + MCFG_PERIBOX_SLOT_ADD_DEF( PEBSLOT3, peribox_hs_slot, "hsgpl" ) + MCFG_PERIBOX_SLOT_ADD( PEBSLOT4, peribox_slotp ) + MCFG_PERIBOX_SLOT_ADD( PEBSLOT5, peribox_slotp ) + MCFG_PERIBOX_SLOT_ADD( PEBSLOT6, peribox_slot6 ) + MCFG_PERIBOX_SLOT_ADD( PEBSLOT7, peribox_slot7 ) + MCFG_PERIBOX_SLOT_ADD( PEBSLOT8, peribox_slot8 ) +MACHINE_CONFIG_END + +machine_config_constructor peribox_sg_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( peribox_sg_device ); +} + +/**************************************************************************** + Another variant of the box; used for the TI with EVPC. The EVPC is + obviously required. +*****************************************************************************/ + +peribox_ev_device::peribox_ev_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) +: peribox_device(mconfig, PERIBOX_EV, "Peripheral expansion box EVPC", tag, owner, clock, "peribox_ev", __FILE__) +{ + m_address_prefix = 0x70000; +} + +MACHINE_CONFIG_FRAGMENT( peribox_ev_device ) + MCFG_PERIBOX_SLOT_ADD_DEF( PEBSLOT2, peribox_ev_slot, "evpc" ) + MCFG_PERIBOX_SLOT_ADD( PEBSLOT3, peribox_slot ) + MCFG_PERIBOX_SLOT_ADD( PEBSLOT4, peribox_slot ) + MCFG_PERIBOX_SLOT_ADD( PEBSLOT5, peribox_slot ) + MCFG_PERIBOX_SLOT_ADD( PEBSLOT6, peribox_slot6 ) + MCFG_PERIBOX_SLOT_ADD( PEBSLOT7, peribox_slot7 ) + MCFG_PERIBOX_SLOT_ADD( PEBSLOT8, peribox_slot8 ) +MACHINE_CONFIG_END + +machine_config_constructor peribox_ev_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( peribox_ev_device ); +} + +/*************************************************************************** + Implementation of a slot within the box. +****************************************************************************/ + +int peribox_slot_device::get_index_from_tagname() +{ + const char *mytag = tag(); + int maxlen = strlen(mytag); + int i; + for (i=maxlen-1; i >=0; i--) + if (mytag[i] < 48 || mytag[i] > 57) break; + + return atoi(mytag+i+1); +} + +peribox_slot_device::peribox_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) +: bus8z_device(mconfig, PERIBOX_SLOT, "TI P-Box slot", tag, owner, clock, "peribox_slot", __FILE__), device_slot_interface(mconfig, *this) +{ +} + +READ8Z_MEMBER(peribox_slot_device::readz) +{ + m_card->readz(space, offset, value, mem_mask); +} + +WRITE8_MEMBER(peribox_slot_device::write) +{ + m_card->write(space, offset, data, mem_mask); +} + +SETADDRESS_DBIN_MEMBER(peribox_slot_device::setaddress_dbin) +{ + m_card->setaddress_dbin(space, offset, state); +} + +READ8Z_MEMBER(peribox_slot_device::crureadz) +{ + m_card->crureadz(space, offset, value); +} + +WRITE8_MEMBER(peribox_slot_device::cruwrite) +{ + m_card->cruwrite(space, offset, data); +} + +WRITE_LINE_MEMBER( peribox_slot_device::senila ) +{ + m_card->set_senila(state); +} + +WRITE_LINE_MEMBER( peribox_slot_device::senilb ) +{ + m_card->set_senilb(state); +} + +/* + Genmod support +*/ +void peribox_slot_device::set_genmod(bool set) +{ + m_card->m_genmod = set; +} + +void peribox_slot_device::device_start(void) +{ +} + +void peribox_slot_device::device_config_complete() +{ + m_slotnumber = get_index_from_tagname(); + device_t *carddev = first_subdevice(); + peribox_device *peb = static_cast(owner()); + if (carddev != NULL) + { + peb->set_slot_loaded(m_slotnumber, this); + m_card = static_cast(carddev); + } + else + { + peb->set_slot_loaded(m_slotnumber, NULL); + m_card = NULL; + } +} + +/* + Delivers the drives that are installed in the box. Called from a card. +*/ +device_t* peribox_slot_device::get_drive(const char* name) +{ + return owner()->subdevice(name); +} + +/* + These methods are called from the expansion cards. They add the + slot number to identify the slot to the box. +*/ +WRITE_LINE_MEMBER( peribox_slot_device::set_inta ) +{ + peribox_device *peb = static_cast(owner()); + peb->inta_join(m_slotnumber, state); +} + +WRITE_LINE_MEMBER( peribox_slot_device::set_intb ) +{ + peribox_device *peb = static_cast(owner()); + peb->intb_join(m_slotnumber, state); +} + +WRITE_LINE_MEMBER( peribox_slot_device::set_ready ) +{ + peribox_device *peb = static_cast(owner()); + peb->ready_join(m_slotnumber, state); +} + +/***************************************************************************/ +const device_type PERIBOX = &device_creator; +const device_type PERIBOX_SLOT = &device_creator; + +const device_type PERIBOX_EV = &device_creator; +const device_type PERIBOX_SG = &device_creator; +const device_type PERIBOX_GEN = &device_creator; +const device_type PERIBOX_998 = &device_creator; diff --git a/src/devices/bus/ti99_peb/peribox.h b/src/devices/bus/ti99_peb/peribox.h new file mode 100644 index 00000000000..7e48726f75c --- /dev/null +++ b/src/devices/bus/ti99_peb/peribox.h @@ -0,0 +1,246 @@ +// license:LGPL-2.1+ +// copyright-holders:Michael Zapf +/**************************************************************************** + + Peripheral expansion box + See peribox.c for documentation + + Michael Zapf + + February 2012: Rewritten as class + +*****************************************************************************/ + +#ifndef __PBOX__ +#define __PBOX__ + +#include "bus/ti99x/ti99defs.h" + +extern const device_type PERIBOX; +extern const device_type PERIBOX_SLOT; + +extern const device_type PERIBOX_EV; +extern const device_type PERIBOX_SG; +extern const device_type PERIBOX_GEN; +extern const device_type PERIBOX_998; + +class ti_expansion_card_device; +class peribox_slot_device; + +/***************************************************************************** + The overall Peripheral Expansion Box. + See ti99defs.h for bus8z_device +******************************************************************************/ + +class peribox_device : public bus8z_device +{ + friend class peribox_slot_device; +public: + peribox_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + peribox_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + template static devcb_base &static_set_inta_callback(device_t &device, _Object object) { return downcast(device).m_console_inta.set_callback(object); } + template static devcb_base &static_set_intb_callback(device_t &device, _Object object) { return downcast(device).m_console_intb.set_callback(object); } + template static devcb_base &static_set_ready_callback(device_t &device, _Object object) { return downcast(device).m_datamux_ready.set_callback(object); } + + // Next seven methods are called from the console + DECLARE_READ8Z_MEMBER(readz); + DECLARE_WRITE8_MEMBER(write); + DECLARE_SETADDRESS_DBIN_MEMBER(setaddress_dbin); + + DECLARE_READ8Z_MEMBER(crureadz); + DECLARE_WRITE8_MEMBER(cruwrite); + DECLARE_WRITE_LINE_MEMBER(senila); + DECLARE_WRITE_LINE_MEMBER(senilb); + + // Part of configuration + void set_prefix(int prefix) { m_address_prefix = prefix; } + + // Genmod support + DECLARE_INPUT_CHANGED_MEMBER( genmod_changed ); + void set_genmod(bool set); + +protected: + virtual void device_start(void); + virtual void device_config_complete(void); + + virtual machine_config_constructor device_mconfig_additions() const; + + // Next three methods call back the console + devcb_write_line m_console_inta; // INTA line (Box to console) + devcb_write_line m_console_intb; // INTB line + devcb_write_line m_datamux_ready; // READY line (to the datamux) + + void set_slot_loaded(int slot, peribox_slot_device* slotdev); + peribox_slot_device *m_slot[9]; // for the sake of simplicity we donate the first two positions (0,1) + + // Propagators for the slot signals. All signals are active low, and + // if any one slot asserts the line, the joint line is asserted. + void inta_join(int slot, int state); + void intb_join(int slot, int state); + void ready_join(int slot, int state); + + int m_inta_flag; + int m_intb_flag; + int m_ready_flag; + + // The TI-99/4(A) Flex Cable Interface (slot 1) pulls up the AMA/AMB/AMC lines to 1/1/1. + int m_address_prefix; +}; + +/************************************************************************ + Specific Box compositions +************************************************************************/ +/* + Variation for EVPC. We'd like to offer the EVPC slot device only if + we started the ti99_4ev driver. +*/ +class peribox_ev_device : public peribox_device +{ +public: + peribox_ev_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual machine_config_constructor device_mconfig_additions() const; +}; + +/* + Variation for SGCPU (TI-99/4P). We put the EVPC and the HSGPL in slots 2 and 3. +*/ +class peribox_sg_device : public peribox_device +{ +public: + peribox_sg_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual machine_config_constructor device_mconfig_additions() const; +}; + +/* + Variation for Geneve. +*/ +class peribox_gen_device : public peribox_device +{ +public: + peribox_gen_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual machine_config_constructor device_mconfig_additions() const; +}; + +/* + Variation for TI-99/8 +*/ +class peribox_998_device : public peribox_device +{ +public: + peribox_998_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual machine_config_constructor device_mconfig_additions() const; +}; + +/***************************************************************************** + A single slot in the box. +******************************************************************************/ + +class peribox_slot_device : public bus8z_device, public device_slot_interface +{ + friend class peribox_device; +public: + peribox_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // Called from the box (direction to card) + DECLARE_READ8Z_MEMBER(readz); + DECLARE_WRITE8_MEMBER(write); + DECLARE_SETADDRESS_DBIN_MEMBER(setaddress_dbin); + + DECLARE_WRITE_LINE_MEMBER(senila); + DECLARE_WRITE_LINE_MEMBER(senilb); + + // Called from the card (direction to box) + DECLARE_WRITE_LINE_MEMBER( set_inta ); + DECLARE_WRITE_LINE_MEMBER( set_intb ); + DECLARE_WRITE_LINE_MEMBER( set_ready ); + + DECLARE_READ8Z_MEMBER(crureadz); + DECLARE_WRITE8_MEMBER(cruwrite); + + // called from the box itself + void set_genmod(bool set); + + device_t* get_drive(const char* name); + +protected: + void device_start(void); + void device_config_complete(void); + +private: + int get_index_from_tagname(); + ti_expansion_card_device *m_card; + int m_slotnumber; +}; + + +/***************************************************************************** + The parent class for all expansion cards. +******************************************************************************/ + +class ti_expansion_card_device : public bus8z_device, public device_slot_card_interface +{ + friend class peribox_slot_device; + +public: + ti_expansion_card_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : bus8z_device(mconfig, type, name, tag, owner, clock, shortname, source), + device_slot_card_interface(mconfig, *this) + { + m_slot = static_cast(owner); + m_senila = CLEAR_LINE; + m_senilb = CLEAR_LINE; + m_genmod = false; + } + + virtual DECLARE_READ8Z_MEMBER(crureadz) =0; + virtual DECLARE_WRITE8_MEMBER(cruwrite) =0; + + void set_senila(int state) { m_senila = state; } + void set_senilb(int state) { m_senilb = state; } + +protected: + peribox_slot_device *m_slot; // using a link to the slot for callbacks + int m_senila; + int m_senilb; + + // When TRUE, card is accessible. Indicated by a LED. + bool m_selected; + + // When TRUE, GenMod is selected. + bool m_genmod; + + // CRU base. Used to configure the address by which a card is selected. + int m_cru_base; + + // Used to decide whether this card has been selected. + int m_select_mask; + int m_select_value; +}; + +#define MCFG_PERIBOX_SLOT_ADD(_tag, _slot_intf) \ + MCFG_DEVICE_ADD(_tag, PERIBOX_SLOT, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, NULL, false) + +#define MCFG_PERIBOX_SLOT_ADD_DEF(_tag, _slot_intf, _default) \ + MCFG_DEVICE_ADD(_tag, PERIBOX_SLOT, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _default, false) + +#define MCFG_PERIBOX_INTA_HANDLER( _inta ) \ + devcb = &peribox_device::static_set_inta_callback( *device, DEVCB_##_inta ); + +#define MCFG_PERIBOX_INTB_HANDLER( _intb ) \ + devcb = &peribox_device::static_set_intb_callback( *device, DEVCB_##_intb ); + +#define MCFG_PERIBOX_READY_HANDLER( _ready ) \ + devcb = &peribox_device::static_set_ready_callback( *device, DEVCB_##_ready ); + +#endif /* __PBOX__ */ diff --git a/src/devices/bus/ti99_peb/samsmem.c b/src/devices/bus/ti99_peb/samsmem.c new file mode 100644 index 00000000000..7a8db384ffd --- /dev/null +++ b/src/devices/bus/ti99_peb/samsmem.c @@ -0,0 +1,133 @@ +// license:LGPL-2.1+ +// copyright-holders:Michael Zapf +/**************************************************************************** + + TI-99 SuperAMS Memory Expansion Card. Uses a 74LS612 memory mapper. + The card can be equipped with up to 1 MiB of static CMOS memory; it is + not buffered, however. + + SAMS organizes memory in 4 KiB blocks which are mapped into the address + space by a memory mapper. The mapper can be configured via a sequence of + addresses at 4000, 4002, ..., 401e, which correspond to memory locations + 0000-0fff, 1000-1fff, ..., f000-ffff. + + Michael Zapf + + February 2012: Rewritten as class + +*****************************************************************************/ + +#include "samsmem.h" +#define RAMREGION "ram" + +#define SAMS_CRU_BASE 0x1e00 + +#define VERBOSE 1 +#define LOG logerror + +sams_memory_expansion_device::sams_memory_expansion_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) +: ti_expansion_card_device(mconfig, TI99_SAMSMEM, "SuperAMS memory expansion card", tag, owner, clock, "ti99_sams", __FILE__) +{ +} + +/* + Memory read. The SAMS card has two address areas: The memory is at locations + 0x2000-0x3fff and 0xa000-0xffff, and the mapper area is at 0x4000-0x401e + (only even addresses). +*/ +READ8Z_MEMBER(sams_memory_expansion_device::readz) +{ + int base = 0; + + if (m_access_mapper && ((offset & 0xe000)==0x4000)) + { + *value = m_mapper[(offset>>1)&0x000f]; + } + + if (((offset & 0xe000)==0x2000) || ((offset & 0xe000)==0xa000) || ((offset & 0xe000)==0xc000) || ((offset & 0xe000)==0xe000)) + { + if (!m_map_mode) + { + // transparent mode + *value = m_ram[offset & 0xffff]; + } + else + { + base = (m_mapper[(offset & 0xf000)>>12] << 12); + *value = m_ram[base | (offset & 0x0fff)]; + } + } +} + +WRITE8_MEMBER(sams_memory_expansion_device::write) +{ + int base = 0; + + if (m_access_mapper && ((offset & 0xe000)==0x4000)) + { + m_mapper[(offset>>1)&0x000f] = data; + } + + if (((offset & 0xe000)==0x2000) || ((offset & 0xe000)==0xa000) || ((offset & 0xe000)==0xc000) || ((offset & 0xe000)==0xe000)) + { + if (!m_map_mode) + { + // transparent mode + m_ram[offset & 0xffff] = data; + } + else + { + base = (m_mapper[(offset & 0xf000)>>12] << 12); + m_ram[base | (offset & 0x0fff)] = data; + } + } +} + +/* + CRU read. None here. +*/ +READ8Z_MEMBER(sams_memory_expansion_device::crureadz) +{ +} + +/* + CRU write. Turns on the mapper and allows to change it. +*/ +WRITE8_MEMBER(sams_memory_expansion_device::cruwrite) +{ + if ((offset & 0xff00)==SAMS_CRU_BASE) + { + if (VERBOSE>7) LOG("cru address %04x = %02x\n", offset&0xffff, data); + + if ((offset & 0x000e)==0) m_access_mapper = (data!=0); + if ((offset & 0x000e)==2) m_map_mode = (data!=0); + } +} + + +ROM_START( sams_card ) + ROM_REGION(0x100000, RAMREGION, 0) + ROM_FILL(0x0000, 0x100000, 0x00) +ROM_END + +void sams_memory_expansion_device::device_start() +{ + if (VERBOSE>5) LOG("SuperAMS: start\n"); + m_ram = memregion(RAMREGION)->base(); +} + +void sams_memory_expansion_device::device_reset() +{ + if (VERBOSE>5) LOG("SuperAMS: reset\n"); + // Resetting values + m_map_mode = false; + m_access_mapper = false; + for (int i=0; i < 16; i++) m_mapper[i] = 0; +} + +const rom_entry *sams_memory_expansion_device::device_rom_region() const +{ + return ROM_NAME( sams_card ); +} + +const device_type TI99_SAMSMEM = &device_creator; diff --git a/src/devices/bus/ti99_peb/samsmem.h b/src/devices/bus/ti99_peb/samsmem.h new file mode 100644 index 00000000000..0dd5e959755 --- /dev/null +++ b/src/devices/bus/ti99_peb/samsmem.h @@ -0,0 +1,44 @@ +// license:LGPL-2.1+ +// copyright-holders:Michael Zapf +/**************************************************************************** + + TI-99 SuperAMS memory expansion + See samsmem.c for documentation + + Michael Zapf + September 2010 + + February 2012: Rewritten as class + +*****************************************************************************/ + +#ifndef __SAMSMEM__ +#define __SAMSMEM__ + +#include "emu.h" +#include "peribox.h" + +extern const device_type TI99_SAMSMEM; + +class sams_memory_expansion_device : public ti_expansion_card_device +{ +public: + sams_memory_expansion_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + DECLARE_READ8Z_MEMBER(readz); + DECLARE_WRITE8_MEMBER(write); + + DECLARE_READ8Z_MEMBER(crureadz); + DECLARE_WRITE8_MEMBER(cruwrite); + +protected: + virtual void device_start(void); + virtual void device_reset(void); + virtual const rom_entry *device_rom_region(void) const; + +private: + UINT8* m_ram; + int m_mapper[16]; + bool m_map_mode; + bool m_access_mapper; +}; +#endif diff --git a/src/devices/bus/ti99_peb/spchsyn.c b/src/devices/bus/ti99_peb/spchsyn.c new file mode 100644 index 00000000000..70be9ee3db6 --- /dev/null +++ b/src/devices/bus/ti99_peb/spchsyn.c @@ -0,0 +1,188 @@ +// license:LGPL-2.1+ +// copyright-holders:Michael Zapf +/**************************************************************************** + + TI-99 Speech synthesizer + + We emulate the Speech Synthesizer plugged onto a P-Box adapter. The original + Speech Synthesizer device was provided as a box to be plugged into the + right side of the console. In order to be used with Geneve and SGCPU, the + speech synthesizer must be moved into the Peripheral Box. + + The Speech Synthesizer used for the TI was the CD2501E, AKA TMS5200, + (internal name TMC0285), a predecessor of the TMS5220 which was used in + other commercial products. + + Note that this adapter also contains the speech roms. + + Michael Zapf + + February 2012: Rewritten as class + +*****************************************************************************/ + +#include "spchsyn.h" +#include "sound/wave.h" +#include "machine/spchrom.h" + +#define TMS5220_ADDRESS_MASK 0x3FFFFUL /* 18-bit mask for tms5220 address */ + +#define VERBOSE 1 +#define LOG logerror + +/****************************************************************************/ + +ti_speech_synthesizer_device::ti_speech_synthesizer_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) +: ti_expansion_card_device(mconfig, TI99_SPEECH, "TI-99 Speech synthesizer (on adapter card)", tag, owner, clock, "ti99_speech", __FILE__) +{ +} + +/* + Memory read +*/ + +READ8Z_MEMBER( ti_speech_synthesizer_device::readz ) +{ + if (space.debugger_access()) return; + + if ((offset & m_select_mask)==m_select_value) + { + *value = m_vsp->status_r(space, offset, 0xff) & 0xff; + if (VERBOSE>4) LOG("spchsyn: read value = %02x\n", *value); + // We should clear the lines at this point. The TI-99/4A clears the + // lines by setting the address bus to a different value, but the + // Geneve may behave differently. This may not 100% reflect the real + // situation, but it ensures a safe processing. + m_vsp->rsq_w(TRUE); + m_vsp->wsq_w(TRUE); + } +} + +/* + Memory write +*/ +WRITE8_MEMBER( ti_speech_synthesizer_device::write ) +{ + if (space.debugger_access()) return; + + if ((offset & m_select_mask)==(m_select_value | 0x0400)) + { + if (VERBOSE>4) LOG("spchsyn: write value = %02x\n", data); + m_vsp->data_w(space, offset, data); + // Note that we must NOT clear the lines here. Find the lines in the + // READY callback below. + } +} + +SETADDRESS_DBIN_MEMBER( ti_speech_synthesizer_device::setaddress_dbin ) +{ + if ((offset & m_select_mask & ~0x0400)==m_select_value) + { + if (VERBOSE>4) LOG("spchsyn: set address = %04x, dbin = %d\n", offset, state); + m_read_mode = (state==ASSERT_LINE); + bool readop = (offset & 0x0400)==0; + + if (m_read_mode != readop) + { + // reset all; this is not a valid access + m_vsp->rsq_w(TRUE); + m_vsp->wsq_w(TRUE); + } + else + { + if (readop) + { + // Caution: We MUST first clear (TRUE) one line to avoid + // both RS* and WS* be asserted (otherwise tms5220 will report "illegal") + m_vsp->wsq_w(TRUE); + m_vsp->rsq_w(FALSE); + } + else + { + m_vsp->rsq_w(TRUE); + m_vsp->wsq_w(FALSE); + } + } + } + else + { + // If other address, turn off RS* and WS* (negative logic!) + m_vsp->rsq_w(TRUE); + m_vsp->wsq_w(TRUE); + return; + } +} + +/****************************************************************************/ + +WRITE_LINE_MEMBER( ti_speech_synthesizer_device::speech_ready ) +{ + // The TMS5200 implementation uses TRUE/FALSE, not ASSERT/CLEAR semantics + // and we have to adapt a /READY to a READY line. + // The real synthesizer board uses a transistor for that purpose. + m_slot->set_ready((state==0)? ASSERT_LINE : CLEAR_LINE); + if (VERBOSE>5) LOG("spchsyn: READY = %d\n", (state==0)); + + if ((state==0) && !m_read_mode) + { + // Clear the lines only when we are done with writing. + m_vsp->rsq_w(TRUE); + m_vsp->wsq_w(TRUE); + } +} + +void ti_speech_synthesizer_device::device_start() +{ + m_read_mode = false; +} + +void ti_speech_synthesizer_device::device_config_complete() +{ + m_vsp = subdevice("speechsyn"); +} + +void ti_speech_synthesizer_device::device_reset() +{ + if (VERBOSE>5) LOG("spchsyn: reset\n"); + if (m_genmod) + { + m_select_mask = 0x1ffc01; + m_select_value = 0x179000; + } + else + { + m_select_mask = 0x7fc01; + m_select_value = 0x79000; + } + m_read_mode = false; +} + +MACHINE_CONFIG_FRAGMENT( ti99_speech ) + MCFG_DEVICE_ADD("vsm", SPEECHROM, 0) + + MCFG_SPEAKER_STANDARD_MONO("mono") + MCFG_SOUND_ADD("speechsyn", CD2501E, 640000L) + MCFG_TMS52XX_READYQ_HANDLER(WRITELINE(ti_speech_synthesizer_device, speech_ready)) + MCFG_TMS52XX_SPEECHROM("vsm") + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.50) +MACHINE_CONFIG_END + +ROM_START( ti99_speech ) + ROM_REGION(0x8000, "vsm", 0) + // Note: the following line is actually wrong; the speech roms in the ti 99/4a and 99/8 are two VSM roms labeled CD2325A and CD2326A, and contain the same data as the following line rom does, but with the byte bit order reversed. This bit ordering issue needs to be fixed elsewhere in the code here before the original/real roms can be used. + ROM_LOAD_OPTIONAL("spchrom.bin", 0x0000, 0x8000, CRC(58b155f7) SHA1(382292295c00dff348d7e17c5ce4da12a1d87763)) /* system speech ROM */ + // correct lines are: + // ROM_LOAD_OPTIONAL("cd2325a.u2a", 0x0000, 0x4000, CRC(1f58b571) SHA1(0ef4f178716b575a1c0c970c56af8a8d97561ffe)) // at location u2, bottom of stack + // ROM_LOAD_OPTIONAL("cd2326a.u2b", 0x4000, 0x4000, CRC(65d00401) SHA1(a367242c2c96cebf0e2bf21862f3f6734b2b3020)) // at location u2, top of stack +ROM_END + +machine_config_constructor ti_speech_synthesizer_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( ti99_speech ); +} + +const rom_entry *ti_speech_synthesizer_device::device_rom_region() const +{ + return ROM_NAME( ti99_speech ); +} +const device_type TI99_SPEECH = &device_creator; diff --git a/src/devices/bus/ti99_peb/spchsyn.h b/src/devices/bus/ti99_peb/spchsyn.h new file mode 100644 index 00000000000..0984cf4de2e --- /dev/null +++ b/src/devices/bus/ti99_peb/spchsyn.h @@ -0,0 +1,51 @@ +// license:LGPL-2.1+ +// copyright-holders:Michael Zapf +/**************************************************************************** + + TI-99 Speech Synthesizer + See spchsyn.c for documentation + + Michael Zapf, October 2010 + February 2012: Rewritten as class + +*****************************************************************************/ + +#ifndef __TISPEECH__ +#define __TISPEECH__ + +#include "emu.h" +#include "peribox.h" +#include "sound/tms5220.h" + +extern const device_type TI99_SPEECH; + +class ti_speech_synthesizer_device : public ti_expansion_card_device +{ +public: + ti_speech_synthesizer_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + DECLARE_READ8Z_MEMBER(readz); + DECLARE_WRITE8_MEMBER(write); + DECLARE_SETADDRESS_DBIN_MEMBER(setaddress_dbin); + + DECLARE_READ8Z_MEMBER(crureadz) { }; + DECLARE_WRITE8_MEMBER(cruwrite) { }; + + DECLARE_WRITE_LINE_MEMBER( speech_ready ); + + DECLARE_READ8_MEMBER( spchrom_read ); + DECLARE_WRITE8_MEMBER( spchrom_load_address ); + DECLARE_WRITE8_MEMBER( spchrom_read_and_branch ); + +protected: + virtual void device_start(); + virtual void device_reset(void); + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + virtual void device_config_complete(); + +private: + cd2501e_device *m_vsp; + bool m_read_mode; +}; + +#endif diff --git a/src/devices/bus/ti99_peb/ti_32kmem.c b/src/devices/bus/ti99_peb/ti_32kmem.c new file mode 100644 index 00000000000..49ce105b89c --- /dev/null +++ b/src/devices/bus/ti99_peb/ti_32kmem.c @@ -0,0 +1,118 @@ +// license:LGPL-2.1+ +// copyright-holders:Michael Zapf +/**************************************************************************** + + TI-99 32 KiB Memory Expansion Card + This is a fairly simple memory expansion for the TI-99/4A, adding + unbuffered 32 KiB. Yet it was a very popular card since it was + required for any kind of advanced programming beyond the console BASIC. + + As a peripheral box card, it is connected via the 8-bit mutiplexed data bus. + Later, modifications of the console became increasingly popular which + avoided the bus multiplex so that the full 16bit access was possible. + This helped to noticeably speed up the system. + + The memory is available on the addresses + + 0x2000 - 0x3fff ("low memory") + 0xa000 - 0xffff ("high memory") + + The console TI BASIC is not able to access the memory expansion, but + Extended Basic (available as a cartridge) makes use of it. + + Michael Zapf + February 2012: Rewritten as class + +*****************************************************************************/ + +#include "emu.h" +#include "peribox.h" +#include "ti_32kmem.h" + +#define RAMREGION "ram" + +ti_32k_expcard_device::ti_32k_expcard_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) +: ti_expansion_card_device(mconfig, TI_32KMEM, "TI-99 32KiB memory expansion card", tag, owner, clock, "ti99_32k", __FILE__) +{ +} + +READ8Z_MEMBER(ti_32k_expcard_device::readz) +{ + UINT8 val = 0; + bool access = true; + switch((offset & 0xe000)>>13) + { + case 1: + val = m_ram_ptr[offset & 0x1fff]; + break; + case 5: + val = m_ram_ptr[(offset & 0x1fff) | 0x2000]; + break; + case 6: + val = m_ram_ptr[(offset & 0x1fff) | 0x4000]; + break; + case 7: + val = m_ram_ptr[(offset & 0x1fff) | 0x6000]; + break; + default: + access = false; + break; + } + if (access) + { + // There is no evidence for an inverted write on the even addresses; + // we assume that the FF00 byte sequence in this memory is a power-on + // artifact. + + /* if ((offset&1)!=1) *value = ~val; + else */ + *value = val; + } +} + +WRITE8_MEMBER(ti_32k_expcard_device::write) +{ + UINT8 data1 = data; + // if ((offset&1)!=1) data1 = ~data; + switch((offset & 0xe000)>>13) + { + case 1: + m_ram_ptr[offset & 0x1fff] = data1; + break; + case 5: + m_ram_ptr[(offset & 0x1fff) | 0x2000] = data1; + break; + case 6: + m_ram_ptr[(offset & 0x1fff) | 0x4000] = data1; + break; + case 7: + m_ram_ptr[(offset & 0x1fff) | 0x6000] = data1; + break; + default: + break; + } +} + +void ti_32k_expcard_device::device_start(void) +{ + m_ram_ptr = memregion(RAMREGION)->base(); + m_cru_base = 0; + // See above. Preset the memory with FF00 + // ROM_FILL does not seem to allow filling with an alternating pattern + for (int i=0; i < 0x8000; i+=2) + { + m_ram_ptr[i] = (UINT8)0xff; + } +} + +ROM_START( ti_exp_32k ) + ROM_REGION(0x8000, RAMREGION, 0) + ROM_FILL(0x0000, 0x8000, 0x00) +ROM_END + +const rom_entry *ti_32k_expcard_device::device_rom_region() const +{ + return ROM_NAME( ti_exp_32k ); +} + +const device_type TI_32KMEM = &device_creator; diff --git a/src/devices/bus/ti99_peb/ti_32kmem.h b/src/devices/bus/ti99_peb/ti_32kmem.h new file mode 100644 index 00000000000..5e0e1f2c5cf --- /dev/null +++ b/src/devices/bus/ti99_peb/ti_32kmem.h @@ -0,0 +1,36 @@ +// license:LGPL-2.1+ +// copyright-holders:Michael Zapf +/**************************************************************************** + + TI-99 32K memory expansion + See ti32kmem.c for documentation + + Michael Zapf + + February 2012: Rewritten as class + +*****************************************************************************/ + +#ifndef __TI32K__ +#define __TI32K__ + +extern const device_type TI_32KMEM; + +class ti_32k_expcard_device : public ti_expansion_card_device +{ +public: + ti_32k_expcard_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + DECLARE_READ8Z_MEMBER(readz); + DECLARE_WRITE8_MEMBER(write); + + DECLARE_READ8Z_MEMBER(crureadz) { }; + DECLARE_WRITE8_MEMBER(cruwrite) { }; + +protected: + virtual void device_start(); + virtual const rom_entry *device_rom_region() const; +private: + UINT8* m_ram_ptr; +}; + +#endif diff --git a/src/devices/bus/ti99_peb/ti_fdc.c b/src/devices/bus/ti99_peb/ti_fdc.c new file mode 100644 index 00000000000..e43a1be2475 --- /dev/null +++ b/src/devices/bus/ti99_peb/ti_fdc.c @@ -0,0 +1,432 @@ +// license:LGPL-2.1+ +// copyright-holders:Michael Zapf +/**************************************************************************** + + TI-99 Standard Floppy Disk Controller Card + Based on WD1771 + Single Density, Double-sided + + Michael Zapf + September 2010 + January 2012: rewritten as class (MZ) + +****************************************************************************/ + +#include "emu.h" +#include "peribox.h" +#include "ti_fdc.h" +#include "formats/ti99_dsk.h" + +// ---------------------------------- +// Flags for debugging + +// Show read and write accesses +#define TRACE_RW 0 + +// Show CRU bit accesses +#define TRACE_CRU 0 + +// Show ready line activity +#define TRACE_READY 0 + +// Show detailed signal activity +#define TRACE_SIGNALS 0 + +// Show sector data +#define TRACE_DATA 0 + +// Show address bus operations +#define TRACE_ADDRESS 0 + +// Show address bus operations +#define TRACE_MOTOR 0 + +// ---------------------------------- +#define FDC_TAG "fd1771" +#define MOTOR_TIMER 1 + +#define TI_FDC_TAG "ti_dssd_controller" + +ti_fdc_device::ti_fdc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : ti_expansion_card_device(mconfig, TI99_FDC, "TI-99 Standard DSSD Floppy Controller", tag, owner, clock, "ti99_fdc", __FILE__), + m_fd1771(*this, FDC_TAG) { } + +/* + Operate the wait state logic. +*/ +void ti_fdc_device::operate_ready_line() +{ + // This is the wait state logic + if (TRACE_SIGNALS) logerror("tifdc: address=%04x, DRQ=%d, INTRQ=%d, MOTOR=%d\n", m_address & 0xffff, m_DRQ, m_IRQ, m_DVENA); + line_state nready = (m_WDsel && // Are we accessing 5ffx (even addr)? + m_WAITena && // and the wait state generation is active (SBO 2) + (m_DRQ==CLEAR_LINE) && // and we are waiting for a byte + (m_IRQ==CLEAR_LINE) && // and there is no interrupt yet + (m_DVENA==ASSERT_LINE) // and the motor is turning? + )? ASSERT_LINE : CLEAR_LINE; // In that case, clear READY and thus trigger wait states + + if (TRACE_READY) logerror("tifdc: READY line = %d\n", (nready==CLEAR_LINE)? 1:0); + m_slot->set_ready((nready==CLEAR_LINE)? ASSERT_LINE : CLEAR_LINE); +} + +/* + * Callbacks from the FD1771 chip + */ +WRITE_LINE_MEMBER( ti_fdc_device::fdc_irq_w ) +{ + m_IRQ = state? ASSERT_LINE : CLEAR_LINE; + if (TRACE_SIGNALS) logerror("tifdc: INTRQ callback = %d\n", m_IRQ); + operate_ready_line(); +} + +WRITE_LINE_MEMBER( ti_fdc_device::fdc_drq_w ) +{ + m_DRQ = state? ASSERT_LINE : CLEAR_LINE; + if (TRACE_SIGNALS) logerror("tifdc: DRQ callback = %d\n", m_DRQ); + operate_ready_line(); +} + +// bool ti_fdc_device::dvena_r() +// { +// if (TRACE_SIGNALS) logerror("tifdc: reading DVENA = %d\n", m_DVENA); +// return (m_DVENA==ASSERT_LINE); +// } + +SETADDRESS_DBIN_MEMBER( ti_fdc_device::setaddress_dbin ) +{ + // Selection login in the PAL and some circuits on the board + + // Is the card being selected? + m_address = offset; + m_inDsrArea = ((m_address & m_select_mask)==m_select_value); + + if (!m_inDsrArea || !m_selected) return; + + if (TRACE_ADDRESS) logerror("tifdc: set address = %04x\n", offset & 0xffff); + + // Is the WD chip on the card being selected? + m_WDsel = m_inDsrArea && ((m_address & 0x1ff1)==0x1ff0); + + // Clear or assert the outgoing READY line + operate_ready_line(); +} + +READ8Z_MEMBER(ti_fdc_device::readz) +{ + if (m_inDsrArea && m_selected) + { + // Read ports of 1771 are mapped to 5FF0,2,4,6: 0101 1111 1111 0xx0 + // Note that incoming/outgoing data are inverted for FD1771 + UINT8 reply = 0; + + if (m_WDsel && ((m_address & 9)==0)) + { + if (!space.debugger_access()) reply = m_fd1771->gen_r((offset >> 1)&0x03); + if (TRACE_DATA) + { + if ((m_address & 0xffff)==0x5ff6) + { + if (!m_debug_dataout) logerror("tifdc: Read data = "); + m_debug_dataout = true; + logerror("%02x ", ~reply & 0xff); + } + else + { + if (m_debug_dataout) logerror("\n"); + m_debug_dataout = false; + } + } + } + else + { + reply = m_dsrrom[m_address & 0x1fff]; + } + *value = reply; + if (TRACE_RW) logerror("tifdc: %04x -> %02x\n", offset & 0xffff, *value); + } +} + +WRITE8_MEMBER(ti_fdc_device::write) +{ + if (m_inDsrArea && m_selected) + { + // Write ports of 1771 are mapped to 5FF8,A,C,E: 0101 1111 1111 1xx0 + // This is important for the TI console: The TMS9900 CPU always performs a + // read operation before the write operation, and if we did not use + // different read and write ports, it would attempt to read from the + // controller before passing a command or data + // to it. In the best case, nothing happens; in the worst case, status + // flags may be reset by the read operation. + + // Note that incoming/outgoing data are inverted for FD1771 + if (TRACE_RW) logerror("tifdc: %04x <- %02x\n", offset & 0xffff, ~data & 0xff); + if (m_WDsel && ((m_address & 9)==8)) + { + // As this is a memory-mapped access we must prevent the debugger + // from messing with the operation + if (!space.debugger_access()) m_fd1771->gen_w((offset >> 1)&0x03, data); + } + } +} + +/* + CRU read access + + 7 6 5 4 3 2 1 0 + +-----+-----+-----+------+-----+-----+-----+-----+ + | Side| 1 | 0 |DVENA*| DSK3| DSK2| DSK1| HLD | + +-----+-----+-----+------+-----+-----+-----+-----+ + + We have only 8 bits for query; within this implementation this means + we only use the base address (offset 0). +*/ +READ8Z_MEMBER(ti_fdc_device::crureadz) +{ + if ((offset & 0xff00)==m_cru_base) + { + UINT8 reply = 0; + if ((offset & 0x07) == 0) + { + // Selected drive + reply |= ((m_DSEL)<<1); + // The DVENA state is returned as inverted + if (m_DVENA==CLEAR_LINE) reply |= 0x10; + // Always 1 + reply |= 0x40; + // Selected side + if (m_SIDSEL==ASSERT_LINE) reply |= 0x80; + } + *value = reply; + if (TRACE_CRU) logerror("tifdc: Read CRU = %02x\n", *value); + } +} + +WRITE8_MEMBER(ti_fdc_device::cruwrite) +{ + if ((offset & 0xff00)==m_cru_base) + { + int bit = (offset >> 1) & 0x07; + switch (bit) + { + case 0: + // (De)select the card. Indicated by a LED on the board. + m_selected = (data!=0); + if (TRACE_CRU) logerror("tifdc: Map DSR (bit 0) = %d\n", m_selected); + break; + + case 1: + // Activate motor + if (data==1 && m_lastval==0) + { // On rising edge, set motor_running for 4.23s + if (TRACE_CRU) logerror("tifdc: trigger motor (bit 1)\n"); + set_floppy_motors_running(true); + } + m_lastval = data; + break; + + case 2: + // Set disk ready/hold (bit 2) + // 0: ignore IRQ and DRQ + // 1: TMS9900 is stopped until IRQ or DRQ are set + // OR the motor stops rotating - rotates for 4.23s after write + // to CRU bit 1 + m_WAITena = (data != 0); + if (TRACE_CRU) logerror("tifdc: arm wait state logic (bit 2) = %d\n", data); + break; + + case 3: + // Load disk heads (HLT pin) (bit 3). Not implemented. + if (TRACE_CRU) logerror("tifdc: set head load (bit 3) = %d\n", data); + break; + + case 4: + m_DSEL = (data != 0)? (m_DSEL | 0x01) : (m_DSEL & 0xfe); + set_drive(); + break; + case 5: + m_DSEL = (data != 0)? (m_DSEL | 0x02) : (m_DSEL & 0xfd); + set_drive(); + break; + case 6: + m_DSEL = (data != 0)? (m_DSEL | 0x04) : (m_DSEL & 0xfb); + set_drive(); + break; + + case 7: + // Select side of disk (bit 7) + m_SIDSEL = (data==1)? ASSERT_LINE : CLEAR_LINE; + if (TRACE_CRU) logerror("tifdc: set side (bit 7) = %d\n", data); + if (m_current_floppy != NULL) m_current_floppy->ss_w(data); + break; + + default: + break; + } + } +} + +void ti_fdc_device::set_drive() +{ + int i = -1; + switch (m_DSEL) + { + case 0: + m_current_floppy = NULL; + if (TRACE_CRU) logerror("tifdc: all drives deselected\n"); + break; + case 1: + i = 0; + break; + case 2: + i = 1; + break; + case 3: + // The schematics do not reveal any countermeasures against multiple selection + // so we assume that the highest value wins. + i = 1; + logerror("tifdc: Warning - multiple drives selected\n"); + break; + case 4: + i = 2; + break; + default: + i = 2; + logerror("tifdc: Warning - multiple drives selected\n"); + break; + } + if (TRACE_CRU) logerror("tifdc: new DSEL = %d\n", m_DSEL); + if (i != -1) m_current_floppy = m_floppy[i]; + + m_fd1771->set_floppy(m_current_floppy); +} + +/* + Monoflop has gone back to the OFF state. +*/ +void ti_fdc_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + set_floppy_motors_running(false); +} + +/* + All floppy motors are operated by the same line. +*/ +void ti_fdc_device::set_floppy_motors_running(bool run) +{ + if (run) + { + if (TRACE_MOTOR) + if (m_DVENA==CLEAR_LINE) logerror("tifdc: Motor START\n"); + m_DVENA = ASSERT_LINE; + m_motor_on_timer->adjust(attotime::from_msec(4230)); + } + else + { + if (TRACE_MOTOR) + if (m_DVENA==ASSERT_LINE) logerror("tifdc: Motor STOP\n"); + m_DVENA = CLEAR_LINE; + } + + // The monoflop is connected to the READY line + m_fd1771->set_force_ready(run); + + // Set all motors + for (int i=0; i < 3; i++) + if (m_floppy[i] != NULL) m_floppy[i]->mon_w((run)? 0 : 1); + + // The motor-on line also connects to the wait state logic + operate_ready_line(); +} + +void ti_fdc_device::device_start() +{ + logerror("tifdc: TI FDC start\n"); + m_dsrrom = memregion(DSRROM)->base(); + m_motor_on_timer = timer_alloc(MOTOR_TIMER); + m_cru_base = 0x1100; + // In case we implement a callback after all: + // m_fd1771->setup_ready_cb(wd_fdc_t::rline_cb(FUNC(ti_fdc_device::dvena_r), this)); +} + +void ti_fdc_device::device_reset() +{ + logerror("tifdc: TI FDC reset\n"); + m_lastval = 0; + if (m_genmod) + { + m_select_mask = 0x1fe000; + m_select_value = 0x174000; + } + else + { + m_select_mask = 0x7e000; + m_select_value = 0x74000; + } + m_DRQ = CLEAR_LINE; + m_IRQ = CLEAR_LINE; + m_DVENA = CLEAR_LINE; + m_fd1771->set_force_ready(false); + + m_DSEL = 0; + m_WAITena = false; + m_selected = false; + m_debug_dataout = false; + m_inDsrArea = false; + m_WDsel = false; + + for (int i=0; i < 3; i++) + { + if (m_floppy[i] != NULL) + logerror("tifdc: Connector %d with %s\n", i, m_floppy[i]->name()); + else + logerror("tifdc: No floppy attached to connector %d\n", i); + } + + m_fd1771->set_floppy(m_current_floppy = m_floppy[0]); +} + +void ti_fdc_device::device_config_complete() +{ + // Seems to be null when doing a "-listslots" + if (subdevice("0")!=NULL) m_floppy[0] = static_cast(subdevice("0")->first_subdevice()); + if (subdevice("1")!=NULL) m_floppy[1] = static_cast(subdevice("1")->first_subdevice()); + if (subdevice("2")!=NULL) m_floppy[2] = static_cast(subdevice("2")->first_subdevice()); +} + +FLOPPY_FORMATS_MEMBER(ti_fdc_device::floppy_formats) + FLOPPY_TI99_SDF_FORMAT, + FLOPPY_TI99_TDF_FORMAT +FLOPPY_FORMATS_END + +static SLOT_INTERFACE_START( tifdc_floppies ) + SLOT_INTERFACE( "525dd", FLOPPY_525_DD ) +SLOT_INTERFACE_END + +MACHINE_CONFIG_FRAGMENT( ti_fdc ) + MCFG_FD1771_ADD(FDC_TAG, XTAL_1MHz) + MCFG_WD_FDC_INTRQ_CALLBACK(WRITELINE(ti_fdc_device, fdc_irq_w)) + MCFG_WD_FDC_DRQ_CALLBACK(WRITELINE(ti_fdc_device, fdc_drq_w)) + MCFG_FLOPPY_DRIVE_ADD("0", tifdc_floppies, "525dd", ti_fdc_device::floppy_formats) + MCFG_FLOPPY_DRIVE_SOUND(true) + MCFG_FLOPPY_DRIVE_ADD("1", tifdc_floppies, "525dd", ti_fdc_device::floppy_formats) + MCFG_FLOPPY_DRIVE_SOUND(true) + MCFG_FLOPPY_DRIVE_ADD("2", tifdc_floppies, NULL, ti_fdc_device::floppy_formats) + MCFG_FLOPPY_DRIVE_SOUND(true) +MACHINE_CONFIG_END + +ROM_START( ti_fdc ) + ROM_REGION(0x2000, DSRROM, 0) + ROM_LOAD("disk.bin", 0x0000, 0x2000, CRC(8f7df93f) SHA1(ed91d48c1eaa8ca37d5055bcf67127ea51c4cad5)) /* TI disk DSR ROM */ +ROM_END + +machine_config_constructor ti_fdc_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( ti_fdc ); +} + +const rom_entry *ti_fdc_device::device_rom_region() const +{ + return ROM_NAME( ti_fdc ); +} + +const device_type TI99_FDC = &device_creator; diff --git a/src/devices/bus/ti99_peb/ti_fdc.h b/src/devices/bus/ti99_peb/ti_fdc.h new file mode 100644 index 00000000000..9fedb1c2590 --- /dev/null +++ b/src/devices/bus/ti99_peb/ti_fdc.h @@ -0,0 +1,111 @@ +// license:LGPL-2.1+ +// copyright-holders:Michael Zapf +/**************************************************************************** + + TI-99 Standard Floppy Disk Controller Card + See ti_fdc.c for documentation + + Michael Zapf + + September 2010 + January 2012: rewritten as class (MZ) + +****************************************************************************/ +#ifndef __TIFDC__ +#define __TIFDC__ + +#include "machine/wd_fdc.h" +#include "imagedev/floppy.h" + +extern const device_type TI99_FDC; + +class ti_fdc_device : public ti_expansion_card_device +{ +public: + ti_fdc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + DECLARE_READ8Z_MEMBER(readz); + DECLARE_WRITE8_MEMBER(write); + DECLARE_SETADDRESS_DBIN_MEMBER(setaddress_dbin); + + DECLARE_WRITE_LINE_MEMBER( intrq_w ); + DECLARE_WRITE_LINE_MEMBER( drq_w ); + + DECLARE_READ8Z_MEMBER(crureadz); + DECLARE_WRITE8_MEMBER(cruwrite); + + DECLARE_FLOPPY_FORMATS( floppy_formats ); + + DECLARE_WRITE_LINE_MEMBER( fdc_irq_w ); + DECLARE_WRITE_LINE_MEMBER( fdc_drq_w ); + // bool dvena_r(); + +protected: + void device_start(); + void device_reset(); + void device_config_complete(); + + const rom_entry *device_rom_region() const; + machine_config_constructor device_mconfig_additions() const; + + void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + +private: + // Wait state logic + void operate_ready_line(); + + // Set the current floppy + void set_drive(); + + // Operate the floppy motors + void set_floppy_motors_running(bool run); + + // Recent address + int m_address; + + // Holds the status of the DRQ and IRQ lines. + line_state m_DRQ, m_IRQ; + + // Needed for triggering the motor monoflop + UINT8 m_lastval; + + // Signal DVENA. When TRUE, makes some drive turning. + line_state m_DVENA; + + // Set when address is in card area + bool m_inDsrArea; + + // When TRUE the CPU is halted while DRQ/IRQ are true. + bool m_WAITena; + + // WD chip selected + bool m_WDsel; + + // Indicates which drive has been selected. Values are 0, 1, 2, and 4. + // 000 = no drive + // 001 = drive 1 + // 010 = drive 2 + // 100 = drive 3 + int m_DSEL; + + // Signal SIDSEL. 0 or 1, indicates the selected head. + line_state m_SIDSEL; + + // count 4.23s from rising edge of motor_on + emu_timer* m_motor_on_timer; + + // Link to the FDC1771 controller on the board. + required_device m_fd1771; + + // DSR ROM + UINT8* m_dsrrom; + + // Link to the attached floppy drives + floppy_image_device* m_floppy[3]; + + // Currently selected floppy drive + floppy_image_device* m_current_floppy; + + // Debugging + bool m_debug_dataout; +}; +#endif diff --git a/src/devices/bus/ti99_peb/ti_rs232.c b/src/devices/bus/ti99_peb/ti_rs232.c new file mode 100644 index 00000000000..9f3706cece1 --- /dev/null +++ b/src/devices/bus/ti99_peb/ti_rs232.c @@ -0,0 +1,1135 @@ +// license:LGPL-2.1+ +// copyright-holders:Michael Zapf +/**************************************************************************** + + TI-99 RS232 and Parallel interface card + + TI99 RS232 card ('rs232') + TMS9902 ('rs232:tms9902_0') + TMS9902 ('rs232:tms9902_1') + TI99 RS232 attached serial device ('rs232:serdev0') + TI99 RS232 attached serial device ('rs232:serdev1') + TI99 PIO attached parallel device ('rs232:piodev') + + Currently this emulation does not directly interact with the serial + interface on the host computer. However, using a socket connection it is + possible to attach an external bridge which interacts with a real UART. + + TI RS232 card wiring + -------------------- + The card uses this wiring (inverters not included) + + +-----+ Pins of the connector + | 9902| (common naming) + | RIN |---<------- 2 (TD) + | XOUT|--->------- 3 (RD) + | RTS |--->------- 8 (DCD) + | CTS |-<-+------- 20 (DTR) + | DSR |-<-+ H--> 6 (DSR) + +-----+ +-----> 5 (CTS) + / + +-----+ / + | CRU |--+ + +-----+ + + This wiring is typical for a DCE, not a DTE. The TI RS232 was obviously + designed to look like a modem. The advantage is that you can use the same + cables for connecting a modem to the RS232 interface or for connecting + a second TI via its interface. To connect to a DTE you can use a 1-1 + wiring cable (1 on 1, 2 on 2 ...) + + The TI manual for the RS232 card suggests the following cables: + + TI RS232 - Modem or other TI RS232 + 2 -----<----- 3 + 3 ----->----- 2 + 6 ----->---- 20 (crossover cable) + 20 -----<----- 6 + + TI RS232 - Terminal (DTE) + 2 ----<------ 2 + 3 ---->------ 3 + 5 ---->------ 5 + 6 ---->------ 6 (1-1 cable) + 8 ---->------ 8 + 20 ----<------20 + + If we want to use a PC serial interface to play the role of the TI + interface we have to map the TI wiring to a suitable wiring for PC + interfaces which are designed as DTEs. This is achieved by the functions + map_lines_in, map_lines_out. + + Note that we now have to swap the cable types: Use a 1-1 cable to connect + another TI or a modem on the other end, and use a crossover cable for + another PC (the usual way of connecting). + + RS232 Over IP protocol + ---------------------- + This implementation can make use of such an external bridge. Normal data + are forwarded to the bridge and back, while line control is organized via + special byte sequences. These sequences are introduced by a 0x1B byte (ESC). + + The protocol has two modes: normal and escape + + normal mode: transmit byte (!= 0x1b) unchanged + escape mode: entered by ESC, bytes following: + ESC = plain ESC byte + length byte[length] = control sequence (length != 0x1b) + + byte[]: + All configuration settings are related to a specified UART; UARTs may + differ in their capabilities and may require specific settings + (e.g. the TMS9902 specifies the line speed by a clock ratio, while + others may have indexed, fixed rates or use integers) + + (x=unused) + + 1ccc xaaa = configuration of parameter ccc; UART type aaa + 1111 xaaa rrrr rrrr rrrr 0000 = config receive rate on aaa + 1110 xaaa rrrr rrrr rrrr 0000 = config transmit rate on aaa + 1101 xaaa xxxx xxbb = config databits bb (00=5 ... 11=8) + 1100 xaaa xxxx xxss = config stop bits ss (00=1.5, 01=2, 1x=1) + 1011 xaaa xxxx xxpp = config parity pp (1x=enable, x1=odd) + + 00ab cdef = line state of RTS=a, CTS=b, DSR=c, DCD=d, DTR=e, RI=f + 01gh i000 = exception g=BRK, h=FRMERR, i=PARERR + + The protocol changes back to normal mode after transmitting the control + sequence. + + Michael Zapf + February 2012: Rewritten as class + +*****************************************************************************/ + +#include "ti_rs232.h" + +#define SENILA_0_BIT 0x80 +#define SENILA_1_BIT 0x40 + +#define RECV_MODE_NORMAL 1 +#define RECV_MODE_ESC 2 +#define RECV_MODE_ESC_LINES 3 + +#define VERBOSE 1 +#define LOG logerror + +#define ESC 0x1b + +ti_rs232_pio_device::ti_rs232_pio_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) +: ti_expansion_card_device(mconfig, TI99_RS232, "TI-99 RS232/PIO interface", tag, owner, clock, "ti99_rs232", __FILE__) +{ +} + + +/**************************************************************************/ +/* Ports */ + +ti_rs232_attached_device::ti_rs232_attached_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) +: device_t(mconfig, TI99_RS232_DEV, "Serial attached device", tag, owner, clock, "ti_rs232_attached", __FILE__), + device_image_interface(mconfig, *this) +{ +} + +ti_pio_attached_device::ti_pio_attached_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) +: device_t(mconfig, TI99_PIO_DEV, "Parallel attached device", tag, owner, clock, "ti_pio_attached", __FILE__), + device_image_interface(mconfig, *this) +{ +} + +void ti_rs232_attached_device::device_start() +{ +} + +void ti_pio_attached_device::device_start() +{ +} + +void ti_rs232_attached_device::device_config_complete() +{ + update_names(); +} + +void ti_pio_attached_device::device_config_complete() +{ + update_names(); +} + +/* + Find the index of the image name. We assume the format + , i.e. the number is the longest string from the right + which can be interpreted as a number. +*/ +int ti_rs232_attached_device::get_index_from_tagname() +{ + const char *mytag = tag(); + int maxlen = strlen(mytag); + int i; + for (i=maxlen-1; i >=0; i--) + if (mytag[i] < 48 || mytag[i] > 57) break; + + return atoi(mytag+i+1); +} + +/* + Initialize rs232 unit and open image +*/ +bool ti_rs232_attached_device::call_load() +{ + tms9902_device* tms9902 = NULL; +// ti_rs232_pio_device* card = static_cast(owner()); + + int devnumber = get_index_from_tagname(); + if (devnumber==0) + { + tms9902 = siblingdevice("tms9902_0"); + // Turn on polling + tms9902->set_clock(true); + } + else if (devnumber==1) + { + tms9902 = siblingdevice("tms9902_1"); + // Turn on polling + tms9902->set_clock(true); + } + else + { + LOG("ti99/rs232: Could not find device tag number\n"); + return true; + } + + // The following line may cause trouble in the init phase + // card->incoming_dtr(devnumber, (m_file!=NULL)? ASSERT_LINE : CLEAR_LINE); + + return false; // OK +} + +void ti_rs232_attached_device::call_unload() +{ + tms9902_device* tms9902 = NULL; + + int devnumber = get_index_from_tagname(); + if (devnumber==0) + { + tms9902 = siblingdevice("tms9902_0"); + // Turn off polling + tms9902->set_clock(false); + } + else if (devnumber==1) + { + tms9902 = siblingdevice("tms9902_1"); + // Turn off polling + tms9902->set_clock(false); + } +} + +/* + Initialize pio unit and open image +*/ +bool ti_pio_attached_device::call_load() +{ + ti_rs232_pio_device* card = static_cast(owner()); + + // tell whether the image is readable + card->m_pio_readable = !has_been_created(); + // tell whether the image is writable + card->m_pio_writable = !is_readonly(); + + if (card->m_pio_write && card->m_pio_writable) + card->m_pio_handshakein = false; // receiver ready + else + card->m_pio_handshakein = true; + + return false; // OK +} + +/* + close a pio image +*/ +void ti_pio_attached_device::call_unload() +{ + ti_rs232_pio_device* card = static_cast(owner()); + + card->m_pio_writable = false; + card->m_pio_handshakein = true; /* receiver not ready */ + card->m_pio_sparein = false; +} + +/****************************************************************************/ + +/* + CRU read +*/ +READ8Z_MEMBER(ti_rs232_pio_device::crureadz) +{ + if ((offset & 0xff00)==m_cru_base) + { + if ((offset & 0x00c0)==0x0000) + { + UINT8 reply = 0x00; + if (m_pio_direction_in) reply |= 0x02; + if (m_pio_handshakein) reply |= 0x04; + if (m_pio_sparein) reply |= 0x08; + if (m_flag0) reply |= 0x10; + // The CTS line is realized as CRU bits + // Mind that this line is handled as an output going to the remote CTS + if ((m_signals[0] & CTS)!=0) reply |= 0x20; + if ((m_signals[1] & CTS)!=0) reply |= 0x40; + if (m_led) reply |= 0x80; + *value = reply; + return; + } + if ((offset & 0x00c0)==0x0040) + { + *value = m_uart[0]->cruread(space, offset>>4, 0xff); + return; + } + if ((offset & 0x00c0)==0x0080) + { + *value = m_uart[1]->cruread(space, offset>>4, 0xff); + return; + } + } +} + +/* + CRU write +*/ +WRITE8_MEMBER(ti_rs232_pio_device::cruwrite) +{ + if ((offset & 0xff00)==m_cru_base) + { + if ((offset & 0x00c0)==0x0040) + { + m_uart[0]->cruwrite(space, offset>>1, data, 0xff); + return; + } + if ((offset & 0x00c0)==0x0080) + { + m_uart[1]->cruwrite(space, offset>>1, data, 0xff); + return; + } + + device_image_interface *image = dynamic_cast(m_piodev); + + int bit = (offset & 0x00ff)>>1; + switch (bit) + { + case 0: + m_selected = (data!=0); + break; + + case 1: + m_pio_direction_in = (data!=0); + break; + + case 2: + if ((data!=0) != m_pio_handshakeout) + { + m_pio_handshakeout = (data!=0); + if (m_pio_write && m_pio_writable && (!m_pio_direction_in)) + { /* PIO in output mode */ + if (!m_pio_handshakeout) + { /* write data strobe */ + /* write data and acknowledge */ + UINT8 buf = m_pio_out_buffer; + int ret = image->fwrite(&buf, 1); + if (ret) + m_pio_handshakein = 1; + } + else + { + /* end strobe */ + /* we can write some data: set receiver ready */ + m_pio_handshakein = 0; + } + } + if ((!m_pio_write) && m_pio_readable /*&& pio_direction_in*/) + { /* PIO in input mode */ + if (!m_pio_handshakeout) + { /* receiver ready */ + /* send data and strobe */ + UINT8 buf; + if (image->fread(&buf, 1)) + m_pio_in_buffer = buf; + m_pio_handshakein = 0; + } + else + { + /* data acknowledge */ + /* we can send some data: set transmitter ready */ + m_pio_handshakein = 1; + } + } + } + break; + + case 3: + m_pio_spareout = (data!=0); + break; + + case 4: + m_flag0 = (data!=0); + break; + + case 5: + // Set the CTS line for RS232/1 + if (VERBOSE>5) LOG("TI-RS232/1/3: Setting CTS* via CRU to %d\n", data); + output_line_state(0, CTS, (data==0)? CTS : 0); + break; + + case 6: + // Set the CTS line for RS232/2 + if (VERBOSE>5) LOG("TI-RS232/2/4: Setting CTS* via CRU to %d\n", data); + output_line_state(1, CTS, (data==0)? CTS : 0); + break; + + case 7: + m_led = (data!=0); + break; + } + return; + } +} + +/* + Memory read +*/ +READ8Z_MEMBER( ti_rs232_pio_device::readz ) +{ + if (m_senila==ASSERT_LINE) + { + if (VERBOSE>3) LOG("ti99/rs232: Sensing ILA\n"); + *value = m_ila; + // The card ROM must be unselected, or we get two values + // on the data bus + + // Not sure whether this is correct; there is no software that makes + // use of it + m_ila = 0; + } + if (((offset & m_select_mask)==m_select_value) && m_selected) + { + if ((offset & 0x1000)==0x0000) + { + *value = m_dsrrom[offset&0x0fff]; + } + else + { + *value = m_pio_direction_in ? m_pio_in_buffer : m_pio_out_buffer; + } + } +} + +/* + Memory write +*/ +WRITE8_MEMBER( ti_rs232_pio_device::write ) +{ + if (((offset & m_select_mask)==m_select_value) && m_selected) + { + if ((offset & 0x1001)==0x1000) + { + m_pio_out_buffer = data; + } + } +} + +/**************************************************************************/ + + +// ========================================================== + +/* + The DTR line of the interface card is wired to the CTS and DSR + of the UART. +*/ +void ti_rs232_pio_device::incoming_dtr(int uartind, line_state value) +{ + if (VERBOSE>2) LOG("TI-RS232/%d: incoming DTR = %d\n", uartind+1, (value==ASSERT_LINE)? 1:0); + + m_uart[uartind]->rcv_cts(value); + m_uart[uartind]->rcv_dsr(value); +} + +/* + Data transmission +*/ +void ti_rs232_pio_device::transmit_data(int uartind, UINT8 value) +{ + UINT8 buf = value; + + device_image_interface *serial; + serial = dynamic_cast(m_serdev[uartind]); + if (!serial->exists()) + { + if (VERBOSE>1) LOG("TI-RS232/%d: No serial output attached\n", uartind+1); + return; + } + + // Send a double ESC if this is not a control operation + if (buf==0x1b) + { + if (VERBOSE>2) LOG("TI-RS232/%d: send ESC (requires another ESC)\n", uartind+1); + serial->fwrite(&buf, 1); + } + if (VERBOSE>3) LOG("TI-RS232/%d: send %c <%02x>\n", uartind+1, buf, buf); + serial->fwrite(&buf, 1); +} + +/* + Map the DCE-like wiring to a DTE-like wiring (and vice versa), V1 + + Emulated PC serial + TI RS232 interface + XOUT 2 -----------( 3) ---> TXD + RIN 3 -----------( 2) <--- RXD + nc 4 -----------( 5) <--- CTS (cable) + CRU 5 -| |-( 8) <--- DCD + DSR+CTS 20 -----------( 6) <--- DSR + +12V 6 -----------(20) ---> DTR + RTS 8 -----------( 4) ---> RTS + + + Alternative mapping for the PORT terminal emulator: (V2) + + Emulated PC serial + TI RS232 interface + XOUT 2 -----------( 3) ---> TXD + RIN 3 -----------( 2) <--- RXD + DSR+CTS 20 -----------( 5) <--- CTS (cable) + RTS 8 -----------(20) ---> DTR + CRU 5 -----------( 4) ---> RTS + +12V 6 -| |-( 6) <--- DSR + nc 4 -----------( 8) <--- DCD + + Yet another mapping for the PORT terminal emulator: (V3) + + Emulated PC serial + TI RS232 interface + XOUT 2 -----------( 3) ---> TXD + RIN 3 -----------( 2) <--- RXD + DSR+CTS 20 -----------( 5) <--- CTS (cable) + CRU 5 -----------(20) ---> DTR + RTS 8 -----------( 4) ---> RTS + +12V 6 -| |-( 6) <--- DSR + nc 4 -----------( 8) <--- DCD +*/ +UINT8 ti_rs232_pio_device::map_lines_out(int uartind, UINT8 value) +{ + UINT8 ret = 0; + int mapping = ioport("SERIALMAP")->read(); + + // 00ab cdef = setting line RTS=a, CTS=b, DSR=c, DCD=d, DTR=e, RI=f + + if (VERBOSE>3) LOG("TI-RS232/%d: out connector pins = 0x%02x; translate for DTE\n", uartind+1, value); + + if (value & BRK) + { + if (VERBOSE>5) LOG("TI-RS232/%d: ... sending BRK\n", uartind+1); + ret |= EXCEPT | BRK; + } + + if (mapping==0) + { + // V1 + if (value & CTS) + { + if (VERBOSE>5) LOG("TI-RS232/%d: ... cannot map CTS line, ignoring\n", uartind+1); + } + if (value & DSR) + { + ret |= DTR; + if (VERBOSE>5) LOG("TI-RS232/%d: ... setting DTR line\n", uartind+1); + } + if (value & DCD) + { + ret |= RTS; + if (VERBOSE>5) LOG("TI-RS232/%d: ... setting RTS line\n", uartind+1); + } + } + else + { + if (mapping==1) + { + // V2 + if (value & CTS) + { + ret |= RTS; + if (VERBOSE>5) LOG("TI-RS232/%d: ... setting RTS line\n", uartind+1); + } + if (value & DCD) + { + ret |= DTR; + if (VERBOSE>5) LOG("TI-RS232/%d: ... setting DTR line\n", uartind+1); + } + } + else + { + // v3 + if (value & CTS) + { + ret |= DTR; + if (VERBOSE>5) LOG("TI-RS232/%d: ... setting DTR line\n", uartind+1); + } + if (value & DSR) + { + if (VERBOSE>5) LOG("TI-RS232/%d: ... cannot map DSR line, ignoring\n", uartind+1); + } + if (value & DCD) + { + ret |= RTS; + if (VERBOSE>5) LOG("TI-RS232/%d: ... setting RTS line\n", uartind+1); + } + } + } + + return ret; +} + +UINT8 ti_rs232_pio_device::map_lines_in(int uartind, UINT8 value) +{ + UINT8 ret = 0; + int mapping = ioport("SERIALMAP")->read(); + + // 00ab cdef = setting line RTS=a, CTS=b, DSR=c, DCD=d, DTR=e, RI=f + + if (VERBOSE>3) LOG("TI-RS232/%d: in connector pins = 0x%02x; translate from DTE\n", uartind+1, value); + + if (value & BRK) + { + if (VERBOSE>5) LOG("TI-RS232/%d: ... getting BRK\n", uartind+1); + ret |= EXCEPT | BRK; + } + + if (mapping==0) + { + // V1 + if (value & CTS) + { + if (VERBOSE>5) LOG("TI-RS232/%d: ... cannot map CTS line, ignoring\n", uartind+1); + } + if (value & DSR) + { + ret |= DTR; + if (VERBOSE>5) LOG("TI-RS232/%d: ... setting DTR line\n", uartind+1); + } + if (value & DCD) + { + if (VERBOSE>5) LOG("TI-RS232/%d: ... cannot map DCD line, ignoring\n", uartind+1); + } + } + else + { + if (mapping==1) + { + // V2 (PORT application) + if (value & CTS) + { + ret |= DTR; + if (VERBOSE>5) LOG("TI-RS232/%d: ... setting DTR line\n", uartind+1); + } + if (value & DSR) + { + if (VERBOSE>5) LOG("TI-RS232/%d: ... cannot map DSR line, ignoring\n", uartind+1); + } + if (value & DCD) + { + if (VERBOSE>5) LOG("TI-RS232/%d: ... cannot map DCD line, ignoring\n", uartind+1); + } + } + else + { + if (value & CTS) + { + ret |= DTR; + if (VERBOSE>5) LOG("TI-RS232/%d: ... setting DTR line\n", uartind+1); + } + if (value & DSR) + { + if (VERBOSE>5) LOG("TI-RS232/%d: ... cannot map DSR line, ignoring\n", uartind+1); + } + if (value & DCD) + { + if (VERBOSE>5) LOG("TI-RS232/%d: ... cannot map DCD line, ignoring\n", uartind+1); + } + } + } + + return ret; +} +/* + Receive a character or a line state from the remote site. This method + is called by a timer with some sufficiently high polling frequency. Note + that the control lines are not subject to baud rates. + The higher polling frequency will cause overloads in the TMS9902 which has + a one-byte buffer only: Since the data source (e.g. the PC UART and the + socket connection) may be buffered, we may get a cluster of bytes in rapid + succession. In order to avoid this, this function uses the parameter + "baudpoll" which is the ratio of the characters/second and the polling + frequency. (char/sec is baud rate divided by 10.) + Whenever we receive a character that is passed to the UART, we have to + pause for 1/baudpoll iterations before getting the next byte from the + data source. + + FIXME: This may fail when the emulated system tries to stop the remote + system by deactivating RTS or DTR, but there are still incoming + bytes in the socket or PC UART buffer. The buffered bytes may then cause + an overflow in the emulated UART, since the application program expects + the remote system to stop sending instantly. + The only way to handle this is to mirror the activity within the serial + bridge: Whenever a RTS=0 or DTR=0 is transmitted to the remote site, the + serial bridge must stop delivering data bytes until the handshake opens the + channel again. +*/ +void ti_rs232_pio_device::receive_data_or_line_state(int uartind) +{ + device_image_interface *serial; + UINT8 buffer; + + serial = dynamic_cast(m_serdev[uartind]); + + if (!serial->exists()) + { + if (VERBOSE>1) LOG("TI-RS232/%d: No serial input attached\n", uartind+1); + return; + } + + double baudpoll = m_uart[uartind]->get_baudpoll(); + + // If more than the minimum waiting time since the last data byte has + // elapsed, we can get a new value. + if (m_time_hold[uartind] > 1.0) + { + // Buffer empty? + if (m_bufpos[uartind] == m_buflen[uartind]) + { + // Get all out of sdlsocket + m_buflen[uartind] = serial->fread(m_recvbuf[uartind], 512); + m_bufpos[uartind] = 0; + if (m_buflen[uartind]==0) return; + } + buffer = m_recvbuf[uartind][m_bufpos[uartind]++]; + } + else + { + // number of polls has not yet elapsed; we have to wait. + m_time_hold[uartind] += baudpoll; + return; + } + + // No config parameters here, only data or line setting + switch (m_recv_mode[uartind]) + { + case RECV_MODE_NORMAL: + if (buffer==0x1b) + { + if (VERBOSE>2) LOG("TI-RS232/%d: received: %c <%02x>, switch to ESC mode\n", uartind+1, buffer, buffer); + m_recv_mode[uartind] = RECV_MODE_ESC; + } + else + { + if (VERBOSE>3) LOG("TI-RS232/%d: received: %c <%02x>, pass to UART\n", uartind+1, buffer, buffer); + m_uart[uartind]->rcv_data(buffer); + m_time_hold[uartind] = 0.0; + } + break; + case RECV_MODE_ESC: + if (buffer==0x1b) + { + m_recv_mode[uartind] = RECV_MODE_NORMAL; + if (VERBOSE>2) LOG("TI-RS232/%d: leaving ESC mode, received: %c <%02x>, pass to UART\n", uartind+1, buffer, buffer); + m_uart[uartind]->rcv_data(buffer); + m_time_hold[uartind] = 0.0; + } + else + { + // the byte in buffer is the length byte + if (VERBOSE>3) LOG("TI-RS232/%d: received length byte <%02x> in ESC mode\n", uartind+1, buffer); + if (buffer != 1) + { + LOG("TI-RS232/%d: expected length 1 but got %02x, leaving ESC mode.\n", uartind+1, buffer); + m_recv_mode[uartind] = RECV_MODE_NORMAL; + } + else + m_recv_mode[uartind] = RECV_MODE_ESC_LINES; + } + break; + + case RECV_MODE_ESC_LINES: + // Map the real serial interface lines to our emulated connector + // The mapping is the same for both directions, so we use the same function + if (buffer & EXCEPT) + { + // Exception states: BRK, FRMERR, PARERR + m_uart[uartind]->rcv_break(((buffer & BRK)!=0)); + + if (buffer & FRMERR) m_uart[uartind]->rcv_framing_error(); + if (buffer & PARERR) m_uart[uartind]->rcv_parity_error(); + } + else + { + buffer = map_lines_in(uartind, buffer); + if (VERBOSE>2) LOG("TI-RS232/%d: received (remapped) <%02x> in ESC mode\n", uartind+1, buffer); + + // The DTR line on the RS232 connector of the board is wired to both the + // CTS and the DSR pin of the TMS9902 + // Apart from the data line, DTR is the only input line + incoming_dtr(uartind, (buffer & DTR)? ASSERT_LINE : CLEAR_LINE); + } + + m_recv_mode[uartind] = RECV_MODE_NORMAL; + break; + + default: + if (VERBOSE>1) LOG("TI-RS232/%d: unknown mode: %d\n", uartind+1, m_recv_mode[uartind]); + } +} + +/* + Control operations like configuration or line changes +*/ +void ti_rs232_pio_device::configure_interface(int uartind, int type, int value) +{ + UINT8 bufctrl[4]; + device_image_interface *serial; + UINT8 esc = ESC; + + serial = dynamic_cast(m_serdev[uartind]); + + if (!serial->exists()) + { + if (VERBOSE>1) LOG("TI-RS232/%d: No serial output attached\n", uartind+1); + return; + } + + serial->fwrite(&esc, 1); + bufctrl[0] = 0x02; + bufctrl[1] = CONFIG | TYPE_TMS9902; + + switch (type) { + case RATERECV: + if (VERBOSE>2) LOG("TI-RS232/%d: send receive rate %04x\n", uartind+1, value); + // value has 12 bits + // 1ccc xaaa = config adapter type a + // 1111 xaaa rrrr rrrr rrrr 0000 = config receive rate on a + // 1110 xaaa rrrr rrrr rrrr 0000 = config transmit rate on a + bufctrl[0] = 0x03; // length + bufctrl[1] |= RATERECV; + bufctrl[2] = (value & 0x0ff0)>>4; + bufctrl[3] = (value & 0x0f)<<4; + break; + case RATEXMIT: + if (VERBOSE>2) LOG("TI-RS232/%d: send transmit rate %04x\n", uartind+1, value); + bufctrl[0] = 0x03; // length + bufctrl[1] |= RATEXMIT; + bufctrl[2] = (value & 0x0ff0)>>4; + bufctrl[3] = (value & 0x0f)<<4; + break; + case STOPBITS: + if (VERBOSE>2) LOG("TI-RS232/%d: send stop bit config %02x\n", uartind+1, value&0x03); + bufctrl[1] |= STOPBITS; + bufctrl[2] = (value & 0x03); + break; + case DATABITS: + if (VERBOSE>2) LOG("TI-RS232/%d: send data bit config %02x\n", uartind+1, value&0x03); + bufctrl[1] |= DATABITS; + bufctrl[2] = (value & 0x03); + break; + case PARITY: + if (VERBOSE>2) LOG("TI-RS232/%d: send parity config %02x\n", uartind+1, value&0x03); + bufctrl[1] |= PARITY; + bufctrl[2] = (value & 0x03); + break; + default: + if (VERBOSE>1) LOG("TI-RS232/%d: error - unknown config type %02x\n", uartind+1, type); + } + + serial->fwrite(bufctrl, bufctrl[0]+1); +} + +void ti_rs232_pio_device::set_bit(int uartind, int line, int value) +{ + if (VERBOSE>5) + { + switch (line) + { + case CTS: LOG("TI-RS232/%d: set CTS(out)=%s\n", uartind+1, (value!=0)? "asserted" : "cleared"); break; + case DCD: LOG("TI-RS232/%d: set DCD(out)=%s\n", uartind+1, (value!=0)? "asserted" : "cleared"); break; + case BRK: LOG("TI-RS232/%d: set BRK(out)=%s\n", uartind+1, (value!=0)? "asserted" : "cleared"); break; + } + } + + if (value!=0) m_signals[uartind] |= line; + else m_signals[uartind] &= ~line; +} + +/* + Line changes +*/ +void ti_rs232_pio_device::output_exception(int uartind, int param, UINT8 value) +{ + device_image_interface *serial; + UINT8 bufctrl[2]; + UINT8 esc = ESC; + + serial = dynamic_cast(m_serdev[uartind]); + + if (!serial->exists()) + { + if (VERBOSE>1) LOG("TI-RS232/%d: No serial output attached\n", uartind+1); + return; + } + + serial->fwrite(&esc, 1); + + bufctrl[0] = 1; + // 0100 0xxv = exception xx: 02=BRK, 04=FRMERR, 06=PARERR; v=0,1 (only for BRK) + // BRK is the only output exception + bufctrl[1] = EXCEPT | param | (value&1); + serial->fwrite(bufctrl, 2); +} + +/* + Line changes +*/ +void ti_rs232_pio_device::output_line_state(int uartind, int mask, UINT8 value) +{ + device_image_interface *serial; + UINT8 bufctrl[2]; + UINT8 esc = ESC; + + serial = dynamic_cast(m_serdev[uartind]); + + if (!serial->exists()) + { + if (VERBOSE>1) LOG("TI-RS232/%d: No serial output attached\n", uartind+1); + return; + } + + serial->fwrite(&esc, 1); + + // 01ab cdef = setting line RTS=a, CTS=b, DSR=c, DCD=d, DTR=e, RI=f + bufctrl[0] = 1; + + // The CTS line (coming from a CRU bit) is connected to the CTS pin + if (mask & CTS) set_bit(uartind, CTS, value & CTS); + + // The RTS line (from 9902) is connected to the DCD pin + if (mask & RTS) set_bit(uartind, DCD, value & RTS); + + // The DSR pin is hardwired to +5V + set_bit(uartind, DSR, 1); + + // As of here, the lines are set according to the schematics of the + // serial interface. + + // Now translate the signals of the board to those of a DTE-like device + // so that we can pass the signal to the real PC serial interface + // (can be imagined as if we emulated the cable) + bufctrl[1] = map_lines_out(uartind, m_signals[uartind]); + serial->fwrite(bufctrl, 2); +} + +/*********************************************************************** + callbacks +************************************************************************/ +/* + Propagates the /INT signal of the UARTs to the /INT line of the pbox. +*/ +WRITE_LINE_MEMBER( ti_rs232_pio_device::int0_callback ) +{ + int senila_bit = SENILA_0_BIT; + + if (state==ASSERT_LINE) m_ila |= senila_bit; + else m_ila &= ~senila_bit; + + m_slot->set_inta(state); +} + +WRITE_LINE_MEMBER( ti_rs232_pio_device::int1_callback ) +{ + int senila_bit = SENILA_1_BIT; + + if (state==ASSERT_LINE) m_ila |= senila_bit; + else m_ila &= ~senila_bit; + + m_slot->set_inta(state); +} + +/* + Called from the UART when it wants to receive a character + However, characters are not passed to it at this point + Instead, we check for signal line change or data transmission + and call the respective function +*/ +WRITE_LINE_MEMBER( ti_rs232_pio_device::rcv0_callback ) +{ + receive_data_or_line_state(0); +} + +WRITE_LINE_MEMBER( ti_rs232_pio_device::rcv1_callback ) +{ + receive_data_or_line_state(1); +} + +WRITE8_MEMBER( ti_rs232_pio_device::xmit0_callback ) +{ + transmit_data(0, data); +} + +WRITE8_MEMBER( ti_rs232_pio_device::xmit1_callback ) +{ + transmit_data(1, data); +} + +void ti_rs232_pio_device::ctrl_callback(int uartind, int offset, UINT8 data) +{ + if ((offset & CONFIG)!=0) + { + // We cannot pass the configuration data as they need more than 8 bits. + // Could be done by a write16 function as well. + configure_interface(uartind, data, m_uart[uartind]->get_config_value()); + } + else + { + if ((offset & EXCEPT)!=0) + { + output_exception(uartind, offset & ~EXCEPT, data); + } + else + { + output_line_state(uartind, offset, data); + } + } +} + +WRITE8_MEMBER( ti_rs232_pio_device::ctrl0_callback ) +{ + ctrl_callback(0, offset, data); +} + +WRITE8_MEMBER( ti_rs232_pio_device::ctrl1_callback ) +{ + ctrl_callback(1, offset, data); +} + +void ti_rs232_pio_device::device_start() +{ + m_dsrrom = memregion(DSRROM)->base(); + m_uart[0] = subdevice("tms9902_0"); + m_uart[1] = subdevice("tms9902_1"); + m_serdev[0] = subdevice("serdev0"); + m_serdev[1] = subdevice("serdev1"); + m_piodev = subdevice("piodev"); + // Prepare the receive buffers + m_recvbuf[0] = global_alloc_array(UINT8, 512); + m_recvbuf[1] = global_alloc_array(UINT8, 512); + m_pio_write = true; // required for call_load of pio_attached_device + m_pio_writable = false; + m_pio_handshakein = false; +} + +void ti_rs232_pio_device::device_stop() +{ + if (m_recvbuf[0] != NULL) global_free_array(m_recvbuf[0]); + if (m_recvbuf[1] != NULL) global_free_array(m_recvbuf[1]); +} + +void ti_rs232_pio_device::device_reset() +{ + m_pio_direction_in = false; + m_pio_handshakeout = false; + m_pio_spareout = false; + m_flag0 = false; + + set_bit(0, CTS, 0); + set_bit(1, CTS, 0); + + m_led = false; + m_recv_mode[0] = RECV_MODE_NORMAL; + m_recv_mode[1] = RECV_MODE_NORMAL; + + m_bufpos[0] = m_bufpos[1] = m_buflen[0] = m_buflen[1] = 0; + + if (m_genmod) + { + m_select_mask = 0x1fe000; + m_select_value = 0x174000; + } + else + { + m_select_mask = 0x7e000; + m_select_value = 0x74000; + } + + m_selected = false; + + m_cru_base = (ioport("CRURS232")->read()==0)? 0x1300 : 0x1500; + + m_time_hold[0] = m_time_hold[1] = 0.0; + + // The GenMod modification changes the address bus width of the Geneve. + // All peripheral cards need to be manually modified to properly decode + // the wider address. The next lines perform this soldering job + // automagically. + /* if (device->machine().root_device().ioport("MODE")->read()==GENMOD) + { + // GenMod card modification + card->select_mask = 0x1fe000; + card->select_value = 0x174000; + }*/ +} + +static MACHINE_CONFIG_FRAGMENT( ti_rs232 ) + MCFG_DEVICE_ADD("tms9902_0", TMS9902, 3000000) + MCFG_TMS9902_INT_CB(WRITELINE(ti_rs232_pio_device, int0_callback)) /* called when interrupt pin state changes */ + MCFG_TMS9902_RCV_CB(WRITELINE(ti_rs232_pio_device, rcv0_callback)) /* called when a character is received */ + MCFG_TMS9902_XMIT_CB(WRITE8(ti_rs232_pio_device, xmit0_callback)) /* called when a character is transmitted */ + MCFG_TMS9902_CTRL_CB(WRITE8(ti_rs232_pio_device, ctrl0_callback)) + MCFG_DEVICE_ADD("tms9902_1", TMS9902, 3000000) + MCFG_TMS9902_INT_CB(WRITELINE(ti_rs232_pio_device, int1_callback)) /* called when interrupt pin state changes */ + MCFG_TMS9902_RCV_CB(WRITELINE(ti_rs232_pio_device, rcv1_callback)) /* called when a character is received */ + MCFG_TMS9902_XMIT_CB(WRITE8(ti_rs232_pio_device, xmit1_callback)) /* called when a character is transmitted */ + MCFG_TMS9902_CTRL_CB(WRITE8(ti_rs232_pio_device, ctrl1_callback)) + MCFG_DEVICE_ADD("serdev0", TI99_RS232_DEV, 0) + MCFG_DEVICE_ADD("serdev1", TI99_RS232_DEV, 0) + MCFG_DEVICE_ADD("piodev", TI99_PIO_DEV, 0) +MACHINE_CONFIG_END + +ROM_START( ti_rs232 ) + ROM_REGION(0x1000, DSRROM, 0) + ROM_LOAD("rs232.bin", 0x0000, 0x1000, CRC(eab382fb) SHA1(ee609a18a21f1a3ddab334e8798d5f2a0fcefa91)) /* TI rs232 DSR ROM */ +ROM_END + +INPUT_PORTS_START( ti_rs232 ) + PORT_START( "CRURS232" ) + PORT_DIPNAME( 0x01, 0x00, "TI-RS232 CRU base" ) + PORT_DIPSETTING( 0x00, "1300" ) + PORT_DIPSETTING( 0x00, "1500" ) + + PORT_START( "SERIALMAP" ) + PORT_CONFNAME( 0x03, 0x00, "Serial cable pin mapping" ) + PORT_CONFSETTING( 0x00, "6-20" ) + PORT_CONFSETTING( 0x01, "8-20" ) + PORT_CONFSETTING( 0x02, "5-20" ) +INPUT_PORTS_END + +machine_config_constructor ti_rs232_pio_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( ti_rs232 ); +} + +const rom_entry *ti_rs232_pio_device::device_rom_region() const +{ + return ROM_NAME( ti_rs232 ); +} + +ioport_constructor ti_rs232_pio_device::device_input_ports() const +{ + return INPUT_PORTS_NAME(ti_rs232); +} + +const device_type TI99_RS232 = &device_creator; +const device_type TI99_RS232_DEV = &device_creator; +const device_type TI99_PIO_DEV = &device_creator; diff --git a/src/devices/bus/ti99_peb/ti_rs232.h b/src/devices/bus/ti99_peb/ti_rs232.h new file mode 100644 index 00000000000..7c75e208d65 --- /dev/null +++ b/src/devices/bus/ti99_peb/ti_rs232.h @@ -0,0 +1,168 @@ +// license:LGPL-2.1+ +// copyright-holders:Michael Zapf +/**************************************************************************** + + TI-99 Serial and parallel interface card + See ti_rs232.c for documentation + + Michael Zapf + February 2012: Rewritten as class + +*****************************************************************************/ + +#ifndef __TIRS232__ +#define __TIRS232__ + +#include "emu.h" +#include "peribox.h" +#include "machine/tms9902.h" + +extern const device_type TI99_RS232; +extern const device_type TI99_RS232_DEV; +extern const device_type TI99_PIO_DEV; + +class ti_rs232_attached_device; +class ti_pio_attached_device; + +class ti_rs232_pio_device : public ti_expansion_card_device +{ + friend class ti_pio_attached_device; + friend class ti_rs232_attached_device; + +public: + ti_rs232_pio_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + DECLARE_READ8Z_MEMBER(readz); + DECLARE_WRITE8_MEMBER(write); + + DECLARE_READ8Z_MEMBER(crureadz); + DECLARE_WRITE8_MEMBER(cruwrite); + + DECLARE_WRITE_LINE_MEMBER( int0_callback ); + DECLARE_WRITE_LINE_MEMBER( int1_callback ); + DECLARE_WRITE_LINE_MEMBER( rcv0_callback ); + DECLARE_WRITE_LINE_MEMBER( rcv1_callback ); + DECLARE_WRITE8_MEMBER( xmit0_callback ); + DECLARE_WRITE8_MEMBER( xmit1_callback ); + DECLARE_WRITE8_MEMBER( ctrl0_callback ); + DECLARE_WRITE8_MEMBER( ctrl1_callback ); + DECLARE_WRITE_LINE_MEMBER( senila ); + +protected: + virtual void device_start(void); + virtual void device_reset(void); + virtual void device_stop(void); + virtual const rom_entry *device_rom_region(void) const; + virtual machine_config_constructor device_mconfig_additions() const; + virtual ioport_constructor device_input_ports() const; + +private: + void incoming_dtr(int uartind, line_state value); + void transmit_data(int uartind, UINT8 value); + UINT8 map_lines_out(int uartind, UINT8 value); + UINT8 map_lines_in(int uartind, UINT8 value); + void receive_data_or_line_state(int uartind); + void set_bit(int uartind, int line, int value); + + void configure_interface(int uartind, int type, int value); + void output_line_state(int uartind, int mask, UINT8 value); + void output_exception(int uartind, int param, UINT8 value); + void ctrl_callback(int uartind, int type, UINT8 data); + + // UART chips + tms9902_device* m_uart[2]; + // Connected images (file or socket connection) that represent the + // devices that are connected to the serial adapters + ti_rs232_attached_device* m_serdev[2]; + // Connected image (file) that represents the device connected to the + // parallel interface + ti_pio_attached_device* m_piodev; + UINT8* m_dsrrom; + + // Input buffer for each UART. We have to copy the contents of sdlsocket here + // because the buffer in corefile will be lost on the next write operation + UINT8* m_recvbuf[2]; + int m_bufpos[2], m_buflen[2]; + + // Latches the state of the output lines for UART0/UART1 + UINT8 m_signals[2]; + int m_recv_mode[2]; // May be NORMAL or ESC + + // Baud rate management + // not part of the real device, but required for the connection to the + // real UART + double m_time_hold[2]; + + // PIO flags + bool m_pio_direction_in; // a.k.a. PIOOC pio in output mode if 0 + bool m_pio_handshakeout; + bool m_pio_handshakein; + bool m_pio_spareout; + bool m_pio_sparein; + bool m_flag0; // spare + bool m_led; // a.k.a. flag3 + int m_pio_out_buffer; + int m_pio_in_buffer; + bool m_pio_readable; + bool m_pio_writable; + bool m_pio_write; // true if image is to be written to + + /* Keeps the value put on the bus when SENILA becomes active. */ + UINT8 m_ila; +}; + +/****************************************************************************/ + +/* + Defines the serial serdev. "TI99 RS232 attached serial device" +*/ +class ti_rs232_attached_device : public device_t, public device_image_interface +{ +public: + ti_rs232_attached_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + iodevice_t image_type() const { return IO_SERIAL; } + bool is_readable() const { return true; } + bool is_writeable() const { return true; } + bool is_creatable() const { return true; } + bool must_be_loaded() const { return false; } + bool is_reset_on_load() const { return false; } + const char *image_interface() const { return ""; } + const char *file_extensions() const { return ""; } + const option_guide *create_option_guide() const { return NULL; } + +protected: + virtual void device_start(void); + bool call_load(); + void call_unload(); + virtual void device_config_complete(); + +private: + int get_index_from_tagname(); +}; + +/* + Defines the PIO (parallel IO) "TI99 PIO attached device" +*/ +class ti_pio_attached_device : public device_t, public device_image_interface +{ +public: + ti_pio_attached_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + iodevice_t image_type() const { return IO_PARALLEL; } + bool is_readable() const { return true; } + bool is_writeable() const { return true; } + bool is_creatable() const { return true; } + bool must_be_loaded() const { return false; } + bool is_reset_on_load() const { return false; } + const char *image_interface() const { return ""; } + const char *file_extensions() const { return ""; } + const option_guide *create_option_guide() const { return NULL; } + +protected: + virtual void device_start(void); + bool call_load(); + void call_unload(); + virtual void device_config_complete(); +}; + +#endif diff --git a/src/devices/bus/ti99_peb/tn_ide.c b/src/devices/bus/ti99_peb/tn_ide.c new file mode 100644 index 00000000000..10e69ace518 --- /dev/null +++ b/src/devices/bus/ti99_peb/tn_ide.c @@ -0,0 +1,382 @@ +// license:LGPL-2.1+ +// copyright-holders:Michael Zapf +/**************************************************************************** + + Thierry Nouspikel's IDE card emulation + + This card is just a prototype. It has been designed by Thierry Nouspikel, + and its description was published in 2001. The card has been revised in + 2004. + + The specs have been published in . + + The IDE interface is quite simple, since it only implements PIO transfer. + The card includes a clock chip to timestamp files, and an SRAM for the DSR. + It should be possible to use a battery backed DSR SRAM, but since the clock + chip includes 4kb of battery-backed RAM, a bootstrap loader can be saved in + the clock SRAM in order to load the DSR from the HD when the computer + starts. + + Raphael Nabet, 2002-2004. + + Michael Zapf + September 2010: Rewritten as device + February 2012: Rewritten as class + + FIXME: Completely untested and likely to be broken + +*****************************************************************************/ + +#include "emu.h" +#include "peribox.h" +#include "machine/ataintf.h" +#include "tn_ide.h" + +#define CRU_BASE 0x1000 + +#define BUFFER_TAG "ram" + +/* previously 0xff */ +#define PAGE_MASK 0x3f + +enum +{ + cru_reg_page_switching = 0x04, + cru_reg_page_0 = 0x08, + /*cru_reg_rambo = 0x10,*/ /* not emulated */ + cru_reg_wp = 0x20, + cru_reg_int_en = 0x40, + cru_reg_reset = 0x80 +}; + +nouspikel_ide_interface_device::nouspikel_ide_interface_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : ti_expansion_card_device(mconfig, TI99_IDE, "Nouspikel IDE interface card", tag, owner, clock, "ti99_ide", __FILE__), + m_ata(*this, "ata") +{ +} + +/* + CRU read +*/ +READ8Z_MEMBER(nouspikel_ide_interface_device::crureadz) +{ + UINT8 reply = 0; + if ((offset & 0xff00)==m_cru_base) + { + int bit = (offset >> 4) & 7; + + if (bit==0) + { + reply = m_cru_register & 0x30; + reply |= 8; /* IDE bus IORDY always set */ + if (!m_clk_irq) + reply |= 4; + if (m_sram_enable_dip) + reply |= 2; + if (!m_ata_irq) + reply |= 1; + } + *value = reply; + } +} + +/* + CRU write +*/ +WRITE8_MEMBER(nouspikel_ide_interface_device::cruwrite) +{ + if ((offset & 0xff00)==m_cru_base) + { + int bit = (offset >>1) & 7; + switch (bit) + { + case 0: + m_selected = (data!=0); + + case 1: // enable SRAM or registers in 0x4000-0x40ff + m_sram_enable = (data!=0); + break; + + case 2: // enable SRAM page switching + case 3: // force SRAM page 0 + case 4: // enable SRAM in 0x6000-0x7000 ("RAMBO" mode) + case 5: // write-protect RAM + case 6: // irq and reset enable + case 7: // reset drive + if (data!=0) + m_cru_register |= 1 << bit; + else + m_cru_register &= ~(1 << bit); + + if (bit == 6) + m_slot->set_inta((m_cru_register & cru_reg_int_en) && m_ata_irq); + + if ((bit == 6) || (bit == 7)) + if ((m_cru_register & cru_reg_int_en) && !(m_cru_register & cru_reg_reset)) + m_ata->reset(); + break; + } + } +} + +/* + Memory read +*/ +READ8Z_MEMBER(nouspikel_ide_interface_device::readz) +{ + UINT8 reply = 0; + if (space.debugger_access()) return; + + if (((offset & m_select_mask)==m_select_value) && m_selected) + { + int addr = offset & 0x1fff; + + if ((addr <= 0xff) && (m_sram_enable == m_sram_enable_dip)) + { /* registers */ + switch ((addr >> 5) & 0x3) + { + case 0: /* RTC RAM */ + if (addr & 0x80) + /* RTC RAM page register */ + reply = m_rtc->xram_r(machine().driver_data()->generic_space(),(addr & 0x1f) | 0x20); + else + /* RTC RAM read */ + reply = m_rtc->xram_r(machine().driver_data()->generic_space(),addr); + break; + case 1: /* RTC registers */ + if (addr & 0x10) + /* register data */ + reply = m_rtc->rtc_r(machine().driver_data()->generic_space(),1); + else + /* register select */ + reply = m_rtc->rtc_r(machine().driver_data()->generic_space(),0); + break; + case 2: /* IDE registers set 1 (CS1Fx) */ + if (m_tms9995_mode ? (!(addr & 1)) : (addr & 1)) + { /* first read triggers 16-bit read cycle */ + m_input_latch = (! (addr & 0x10)) ? m_ata->read_cs0(space, (addr >> 1) & 0x7, 0xffff) : 0; + } + + /* return latched input */ + /*reply = (addr & 1) ? input_latch : (input_latch >> 8);*/ + /* return latched input - bytes are swapped in 2004 IDE card */ + reply = ((addr & 1) ? (m_input_latch >> 8) : m_input_latch) & 0xff; + break; + case 3: /* IDE registers set 2 (CS3Fx) */ + if (m_tms9995_mode ? (!(addr & 1)) : (addr & 1)) + { /* first read triggers 16-bit read cycle */ + m_input_latch = (! (addr & 0x10)) ? m_ata->read_cs1(space, (addr >> 1) & 0x7, 0xffff) : 0; + } + + /* return latched input */ + /*reply = (addr & 1) ? input_latch : (input_latch >> 8);*/ + /* return latched input - bytes are swapped in 2004 IDE card */ + reply = ((addr & 1) ? (m_input_latch >> 8) : m_input_latch) & 0xff; + break; + } + } + else + { /* sram */ + if ((m_cru_register & cru_reg_page_0) || (addr >= 0x1000)) + reply = m_ram[addr+0x2000 * m_cur_page]; + else + reply = m_ram[addr]; + } + *value = reply; + } +} + +/* + Memory write. The controller is 16 bit, so we need to demultiplex again. +*/ +WRITE8_MEMBER(nouspikel_ide_interface_device::write) +{ + if (space.debugger_access()) return; + + if (((offset & m_select_mask)==m_select_value) && m_selected) + { + if (m_cru_register & cru_reg_page_switching) + { + m_cur_page = (offset >> 1) & PAGE_MASK; + } + + int addr = offset & 0x1fff; + + if ((addr <= 0xff) && (m_sram_enable == m_sram_enable_dip)) + { /* registers */ + switch ((addr >> 5) & 0x3) + { + case 0: /* RTC RAM */ + if (addr & 0x80) + /* RTC RAM page register */ + m_rtc->xram_w(machine().driver_data()->generic_space(),(addr & 0x1f) | 0x20, data); + else + /* RTC RAM write */ + m_rtc->xram_w(machine().driver_data()->generic_space(),addr, data); + break; + case 1: /* RTC registers */ + if (addr & 0x10) + /* register data */ + m_rtc->rtc_w(machine().driver_data()->generic_space(),1, data); + else + /* register select */ + m_rtc->rtc_w(machine().driver_data()->generic_space(),0, data); + break; + case 2: /* IDE registers set 1 (CS1Fx) */ +/* + if (addr & 1) + m_output_latch = (m_output_latch & 0xff00) | data; + else + m_output_latch = (m_output_latch & 0x00ff) | (data << 8); +*/ + /* latch write - bytes are swapped in 2004 IDE card */ + if (addr & 1) + m_output_latch = (m_output_latch & 0x00ff) | (data << 8); + else + m_output_latch = (m_output_latch & 0xff00) | data; + + if (m_tms9995_mode ? (addr & 1) : (!(addr & 1))) + { /* second write triggers 16-bit write cycle */ + m_ata->write_cs0(space, (addr >> 1) & 0x7, m_output_latch, 0xffff); + } + break; + case 3: /* IDE registers set 2 (CS3Fx) */ +/* + if (addr & 1) + m_output_latch = (m_output_latch & 0xff00) | data; + else + m_output_latch = (m_output_latch & 0x00ff) | (data << 8); +*/ + /* latch write - bytes are swapped in 2004 IDE card */ + if (addr & 1) + m_output_latch = (m_output_latch & 0x00ff) | (data << 8); + else + m_output_latch = (m_output_latch & 0xff00) | data; + + if (m_tms9995_mode ? (addr & 1) : (!(addr & 1))) + { /* second write triggers 16-bit write cycle */ + m_ata->write_cs1(space, (addr >> 1) & 0x7, m_output_latch, 0xffff); + } + break; + } + } + else + { /* sram */ + if (! (m_cru_register & cru_reg_wp)) + { + if ((m_cru_register & cru_reg_page_0) || (addr >= 0x1000)) + m_ram[addr+0x2000 * m_cur_page] = data; + else + m_ram[addr] = data; + } + } + } +} + +void nouspikel_ide_interface_device::do_inta(int state) +{ + m_slot->set_inta(state); +} + +/* + ti99_ide_interrupt() + IDE interrupt callback +*/ +WRITE_LINE_MEMBER(nouspikel_ide_interface_device::ide_interrupt_callback) +{ + m_ata_irq = state; + if (m_cru_register & cru_reg_int_en) + do_inta(state); +} + +/* + clk_interrupt_callback() + clock interrupt callback +*/ +WRITE_LINE_MEMBER(nouspikel_ide_interface_device::clock_interrupt_callback) +{ + m_clk_irq = (state!=0); + m_slot->set_inta(state); +} + +void nouspikel_ide_interface_device::device_start() +{ + m_rtc = subdevice("ide_rtc"); + + m_ram = memregion(BUFFER_TAG)->base(); + m_sram_enable_dip = false; // TODO: what is this? +} + +void nouspikel_ide_interface_device::device_reset() +{ + m_cur_page = 0; + m_sram_enable = false; + m_cru_register = 0; + + if (m_genmod) + { + m_select_mask = 0x1fe000; + m_select_value = 0x174000; + } + else + { + m_select_mask = 0x7e000; + m_select_value = 0x74000; + } + m_selected = false; + + m_cru_base = ioport("CRUIDE")->read(); + m_clk_irq = false; + + m_tms9995_mode = false; // (device->type()==TMS9995); +} + +MACHINE_CONFIG_FRAGMENT( tn_ide ) + MCFG_DEVICE_ADD( "ide_rtc", RTC65271, 0 ) + MCFG_RTC65271_INTERRUPT_CB(WRITELINE(nouspikel_ide_interface_device, clock_interrupt_callback)) + MCFG_ATA_INTERFACE_ADD( "ata", ata_devices, "hdd", NULL, false) + MCFG_ATA_INTERFACE_IRQ_HANDLER(WRITELINE(nouspikel_ide_interface_device, ide_interrupt_callback)) +MACHINE_CONFIG_END + +ROM_START( tn_ide ) + ROM_REGION(0x80000, BUFFER_TAG, 0) /* RAM buffer 512 KiB */ + ROM_FILL(0x0000, 0x80000, 0x00) +ROM_END + +INPUT_PORTS_START( tn_ide ) + PORT_START( "CRUIDE" ) + PORT_DIPNAME( 0x1f00, 0x1000, "IDE CRU base" ) + PORT_DIPSETTING( 0x1000, "1000" ) + PORT_DIPSETTING( 0x1100, "1100" ) + PORT_DIPSETTING( 0x1200, "1200" ) + PORT_DIPSETTING( 0x1300, "1300" ) + PORT_DIPSETTING( 0x1400, "1400" ) + PORT_DIPSETTING( 0x1500, "1500" ) + PORT_DIPSETTING( 0x1600, "1600" ) + PORT_DIPSETTING( 0x1700, "1700" ) + PORT_DIPSETTING( 0x1800, "1800" ) + PORT_DIPSETTING( 0x1900, "1900" ) + PORT_DIPSETTING( 0x1a00, "1A00" ) + PORT_DIPSETTING( 0x1b00, "1B00" ) + PORT_DIPSETTING( 0x1c00, "1C00" ) + PORT_DIPSETTING( 0x1d00, "1D00" ) + PORT_DIPSETTING( 0x1e00, "1E00" ) + PORT_DIPSETTING( 0x1f00, "1F00" ) +INPUT_PORTS_END + +machine_config_constructor nouspikel_ide_interface_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( tn_ide ); +} + +const rom_entry *nouspikel_ide_interface_device::device_rom_region() const +{ + return ROM_NAME( tn_ide ); +} + +ioport_constructor nouspikel_ide_interface_device::device_input_ports() const +{ + return INPUT_PORTS_NAME(tn_ide); +} + +const device_type TI99_IDE = &device_creator; diff --git a/src/devices/bus/ti99_peb/tn_ide.h b/src/devices/bus/ti99_peb/tn_ide.h new file mode 100644 index 00000000000..bb9371e4cfb --- /dev/null +++ b/src/devices/bus/ti99_peb/tn_ide.h @@ -0,0 +1,64 @@ +// license:LGPL-2.1+ +// copyright-holders:Michael Zapf +/**************************************************************************** + + Nouspikel IDE controller card + See tn_ide.c for documentation + + Michael Zapf + + February 2012: Rewritten as class + +*****************************************************************************/ + +#ifndef __TNIDE__ +#define __TNIDE__ + +#include "emu.h" +#include "machine/ataintf.h" +#include "machine/rtc65271.h" + +extern const device_type TI99_IDE; + +class nouspikel_ide_interface_device : public ti_expansion_card_device +{ +public: + nouspikel_ide_interface_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + DECLARE_READ8Z_MEMBER(readz); + DECLARE_WRITE8_MEMBER(write); + + DECLARE_READ8Z_MEMBER(crureadz); + DECLARE_WRITE8_MEMBER(cruwrite); + + void do_inta(int state); + bool m_ata_irq; + int m_cru_register; + + DECLARE_WRITE_LINE_MEMBER(clock_interrupt_callback); + DECLARE_WRITE_LINE_MEMBER(ide_interrupt_callback); + +protected: + virtual void device_start(void); + virtual void device_reset(void); + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + virtual ioport_constructor device_input_ports() const; + +private: + rtc65271_device* m_rtc; + required_device m_ata; + + bool m_clk_irq; + bool m_sram_enable; + bool m_sram_enable_dip; + int m_cur_page; + + bool m_tms9995_mode; + + UINT16 m_input_latch; + UINT16 m_output_latch; + + UINT8 *m_ram; +}; + +#endif diff --git a/src/devices/bus/ti99_peb/tn_usbsm.c b/src/devices/bus/ti99_peb/tn_usbsm.c new file mode 100644 index 00000000000..f3a911af0f2 --- /dev/null +++ b/src/devices/bus/ti99_peb/tn_usbsm.c @@ -0,0 +1,345 @@ +// license:LGPL-2.1+ +// copyright-holders:Michael Zapf +/**************************************************************************** + + Thierry Nouspikel's USB-SmartMedia card emulation + + This card features three USB ports (two host and one device) and a + SmartMedia interface. The original prototype was designed by Thierry + Nouspikel, and its description was published in 2003; a small series of + approximately 100 printed-circuit boards was ordered shortly afterwards + by various TI users. + + The specs have been published in . + + The USB interface uses a Philips ISP1161A USB controller that supports + USB 2.0 full-speed (12 Mbit/s) and low-speed (1.5 Mbit/s) I/O (high speed + (480 Mbits/sec) is not supported, but it is hardly a problem since TI99 is + too slow to take advantage from high speed). The SmartMedia interface uses + a few TTL buffers. The card also includes an 8MByte StrataFlash FEEPROM + and 1MByte of SRAM for DSR use. + + The card has a 8-bit->16-bit demultiplexer that can be set-up to assume + either that the LSByte of a word is accessed first or that the MSByte of a word + is accessed first. The former is true with ti-99/4(a), the latter with the + tms9995 CPU used by Geneve and ti-99/8. + + TODO: + * Test SmartMedia support + * Implement USB controller and assorted USB devices + * Save DSR FEEPROM to disk + + Raphael Nabet, 2004. + + Michael Zapf + September 2010: Rewritten as device + February 2012: Rewritten as class + + FIXME: Completely untested and likely to be broken + +*****************************************************************************/ + +#include "tn_usbsm.h" + +#define STRATA_TAG "strata" + +enum +{ + IO_REGS_ENABLE = 0x02, + INT_ENABLE = 0x04, + SM_ENABLE = 0x08, + FEEPROM_WRITE_ENABLE = 0x10 +}; + +nouspikel_usb_smartmedia_device::nouspikel_usb_smartmedia_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) +: ti_expansion_card_device(mconfig, TI99_USBSM, "Nouspikel USB/Smartmedia card", tag, owner, clock, "ti99_usbsm", __FILE__), + m_smartmedia(*this, "smartmedia"), + m_flash(*this, STRATA_TAG) +{ +} + +/* + CRU read +*/ +READ8Z_MEMBER(nouspikel_usb_smartmedia_device::crureadz) +{ + if ((offset & 0xff00)==m_cru_base) + { + UINT8 reply = 0; + offset &= 3; + + if (offset == 0) + { + // bit + // 0 >1x00 0: USB Host controller requests interrupt. + // 1 >1x02 0: USB Device controller requests interrupt. + // 2 >1x04 1: USB Host controller suspended. + // 3 >1x06 1: USB Device controller suspended. + // 4 >1x08 0: Strata FEEPROM is busy. + // 1: Strata FEEPROM is ready. + // 5 >1x0A 0: SmartMedia card is busy. + // 1: SmartMedia card absent or ready. + // 6 >1x0C 0: No SmartMedia card present. + // 1: A card is in the connector. + // 7 >1x0E 0: SmartMedia card is protected. + // 1: Card absent or not protected. + + reply = 0x33; + if (!m_smartmedia->is_present()) + reply |= 0xc0; + else if (!m_smartmedia->is_protected()) + reply |= 0x80; + } + *value = reply; + } +} + +/* + CRU write +*/ +WRITE8_MEMBER(nouspikel_usb_smartmedia_device::cruwrite) +{ + if ((offset & 0xff00)==m_cru_base) + { + int bit = (offset >> 1) & 0x1f; + + switch (bit) + { + case 0: + m_selected = data; + break; + case 1: + // enable I/O registers + m_enable_io = data; + break; + case 2: + // enable interrupts + m_enable_int = data; + break; + case 3: + // enable SmartMedia card + m_enable_sm = data; + break; + case 4: + // enable FEEPROM writes (and disable reads) + m_write_flash = data; + break; + case 5: /* FEEPROM page */ + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + case 14: + case 15: + if (data) + m_feeprom_page |= 1 << (bit-5); + else + m_feeprom_page &= ~ (1 << (bit-5)); + break; + + case 16: /* SRAM page */ + case 17: + case 18: + case 19: + case 20: + case 21: + case 22: + case 23: + if (data) + m_sram_page |= 1 << (bit-16); + else + m_sram_page &= ~ (1 << (bit-16)); + break; + } + } +} + +/* + Memory read + TODO: Check whether AMA/B/C is actually checked +*/ +READ8Z_MEMBER(nouspikel_usb_smartmedia_device::readz) +{ + if (space.debugger_access()) return; + + if (((offset & m_select_mask)==m_select_value) && m_selected) + { + if (m_tms9995_mode ? (!(offset & 1)) : (offset & 1)) + { + // first read triggers 16-bit read cycle + + if (offset < 0x5000) + { + // 0x4000-0x4fff range + if (m_enable_io && (offset >= 0x4ff0)) + { + // SmartMedia interface (4ff0-4ff7) + if ((offset & 8) == 0) + m_input_latch = m_smartmedia->data_r() << 8; + } + else + { + // FEEPROM + if (!m_write_flash) + m_input_latch = m_flash->read16(space, (offset>>1)&0xffff); + } + } + else + { + // 0x5000-0x5fff range + if (m_enable_io && (offset >= 0x5ff0)) + { + // USB controller. Not implemented. + logerror("tn_usbsm: Reading from USB\n"); + } + else + { + // SRAM + m_input_latch = m_ram[m_sram_page*0x800+((offset>>1)&0x07ff)]; + } + } + } + + // return latched input + *value = ((offset & 1) ? (m_input_latch) : (m_input_latch >> 8)) & 0xff; + } +} + +/* + Memory write. The controller is 16 bit, so we need to demultiplex again. +*/ +WRITE8_MEMBER(nouspikel_usb_smartmedia_device::write) +{ + if (space.debugger_access()) return; + + if (((offset & m_select_mask)==m_select_value) && m_selected) + { + /* latch write */ + if (offset & 1) + m_output_latch = (m_output_latch & 0xff00) | data; + else + m_output_latch = (m_output_latch & 0x00ff) | (data << 8); + + if ((m_tms9995_mode)? (offset & 1) : (!(offset & 1))) + { + // second write triggers 16-bit write cycle + if (offset < 0x5000) + { + // 0x4000-0x4fff range + if (m_enable_io && (offset >= 0x4ff0)) + { + // SmartMedia interface + switch (offset & 3) + { + case 0: + m_smartmedia->data_w(m_output_latch >> 8); + break; + case 1: + m_smartmedia->address_w(m_output_latch >> 8); + break; + case 2: + m_smartmedia->command_w(m_output_latch >> 8); + break; + case 3: + /* bogus, don't use(?) */ + break; + } + } + else + { // FEEPROM + if (m_write_flash) + m_flash->write16(space, (offset>>1)&0xffff, m_output_latch); + } + } + else + { /* 0x5000-0x5fff range */ + if (m_enable_io && (offset >= 0x5ff0)) + { + // USB controller. Not implemented. + logerror("tn_usbsm: Writing to USB controller.\n"); + } + else + { // SRAM + m_ram[m_sram_page*0x800+((offset>>1) & 0x07ff)] = m_output_latch; + } + } + } + } +} + +void nouspikel_usb_smartmedia_device::device_start() +{ + m_ram.resize(0x80000/2); +} + +void nouspikel_usb_smartmedia_device::device_reset() +{ + m_feeprom_page = 0; + m_sram_page = 0; + m_cru_register = 0; + m_tms9995_mode = (ioport("BYTEORDER")->read() == 0x01); + m_enable_io = false; + m_enable_int = false; + m_enable_sm = false; + m_write_flash = false; + + if (m_genmod) + { + m_select_mask = 0x1fe000; + m_select_value = 0x174000; + } + else + { + m_select_mask = 0x7e000; + m_select_value = 0x74000; + } + m_selected = false; + + m_cru_base = ioport("CRUUSBSM")->read(); +} + +INPUT_PORTS_START( tn_usbsm ) + PORT_START( "CRUUSBSM" ) + PORT_DIPNAME( 0x1f00, 0x1600, "USB/Smartmedia CRU base" ) + PORT_DIPSETTING( 0x1000, "1000" ) + PORT_DIPSETTING( 0x1100, "1100" ) + PORT_DIPSETTING( 0x1200, "1200" ) + PORT_DIPSETTING( 0x1300, "1300" ) + PORT_DIPSETTING( 0x1400, "1400" ) + PORT_DIPSETTING( 0x1500, "1500" ) + PORT_DIPSETTING( 0x1600, "1600" ) + PORT_DIPSETTING( 0x1700, "1700" ) + PORT_DIPSETTING( 0x1800, "1800" ) + PORT_DIPSETTING( 0x1900, "1900" ) + PORT_DIPSETTING( 0x1a00, "1A00" ) + PORT_DIPSETTING( 0x1b00, "1B00" ) + PORT_DIPSETTING( 0x1c00, "1C00" ) + PORT_DIPSETTING( 0x1d00, "1D00" ) + PORT_DIPSETTING( 0x1e00, "1E00" ) + PORT_DIPSETTING( 0x1f00, "1F00" ) + PORT_START( "BYTEORDER" ) + PORT_DIPNAME( 0x01, 0x00, "Multiplex mode" ) + PORT_DIPSETTING( 0x00, "TI mode") + PORT_DIPSETTING( 0x01, "Geneve mode") +INPUT_PORTS_END + +MACHINE_CONFIG_FRAGMENT( tn_usbsm ) + MCFG_DEVICE_ADD("smartmedia", SMARTMEDIA, 0) + MCFG_STRATAFLASH_ADD(STRATA_TAG) +MACHINE_CONFIG_END + +machine_config_constructor nouspikel_usb_smartmedia_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( tn_usbsm ); +} + +ioport_constructor nouspikel_usb_smartmedia_device::device_input_ports() const +{ + return INPUT_PORTS_NAME(tn_usbsm); +} + +const device_type TI99_USBSM = &device_creator; diff --git a/src/devices/bus/ti99_peb/tn_usbsm.h b/src/devices/bus/ti99_peb/tn_usbsm.h new file mode 100644 index 00000000000..951565b0367 --- /dev/null +++ b/src/devices/bus/ti99_peb/tn_usbsm.h @@ -0,0 +1,60 @@ +// license:LGPL-2.1+ +// copyright-holders:Michael Zapf +/**************************************************************************** + + Nouspikel USB / SmartMedia interface card + See tn_usmsm.c for documentation + + Michael Zapf + + February 2012: Rewritten as class + +*****************************************************************************/ + +#ifndef __USBSMART__ +#define __USBSMART__ + +#include "emu.h" +#include "peribox.h" +#include "machine/smartmed.h" +#include "machine/strata.h" + +extern const device_type TI99_USBSM; + +class nouspikel_usb_smartmedia_device : public ti_expansion_card_device +{ +public: + nouspikel_usb_smartmedia_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + DECLARE_READ8Z_MEMBER(readz); + DECLARE_WRITE8_MEMBER(write); + + DECLARE_READ8Z_MEMBER(crureadz); + DECLARE_WRITE8_MEMBER(cruwrite); + +protected: + virtual void device_start(void); + virtual void device_reset(void); + virtual machine_config_constructor device_mconfig_additions() const; + virtual ioport_constructor device_input_ports() const; + +private: + + int m_feeprom_page; + int m_sram_page; + int m_cru_register; + bool m_tms9995_mode; + + bool m_enable_io; + bool m_enable_int; + bool m_enable_sm; + bool m_write_flash; + + UINT16 m_input_latch; + UINT16 m_output_latch; + std::vector m_ram; + + required_device m_smartmedia; + required_device m_flash; +}; + +#endif diff --git a/src/devices/bus/ti99x/990_dk.c b/src/devices/bus/ti99x/990_dk.c new file mode 100644 index 00000000000..5eb8ea58892 --- /dev/null +++ b/src/devices/bus/ti99x/990_dk.c @@ -0,0 +1,893 @@ +// license:GPL-2.0+ +// copyright-holders:Raphael Nabet +/* + 990_dk.c: emulation of a TI FD800 'Diablo' floppy disk controller + controller, for use with any TI990 system (and possibly any system which + implements the CRU bus). + + This floppy disk controller supports IBM-format 8" SSSD and DSSD floppies. + + Raphael Nabet 2003 + + Rewritten as class + Michael Zapf 2014 + + TODO: Make it work +*/ + +#include "emu.h" + +#include "990_dk.h" + +/* status bits */ +enum +{ + status_OP_complete = 1 << 0, + status_XFER_ready = 1 << 1, + status_drv_not_ready= 1 << 2, + status_dat_chk_err = 1 << 3, + status_seek_err = 1 << 4, + status_invalid_cmd = 1 << 5, + status_no_addr_mark = 1 << 6, + status_equ_chk_err = 1 << 7, + status_ID_chk_err = 1 << 8, + status_ID_not_found = 1 << 9, + status_ctlr_busy = 1 << 10, + status_write_prot = 1 << 11, + status_del_sector = 1 << 12, + status_interrupt = 1 << 15, + + status_unit_shift = 13 +}; + +const device_type FD800 = &device_creator; + +fd800_legacy_device::fd800_legacy_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, FD800, "TI FD800 Diablo floppy disk controller", tag, owner, clock, "fd800", __FILE__), + m_int_line(*this) +{ +} + +void fd800_legacy_device::set_interrupt_line() +{ + if ((m_stat_reg & status_interrupt) && ! m_interrupt_f_f) + m_int_line(ASSERT_LINE); + else + m_int_line(CLEAR_LINE); +} + + +/* void fd800_legacy_device::unload_proc(device_image_interface &image) +{ + int unit = floppy_get_drive(&image.device()); + + m_drv[unit].log_cylinder[0] = m_drv[unit].log_cylinder[1] = -1; +} + + +void fd800_machine_init(void (*interrupt_callback)(running_machine &machine, int state)) +{ + int i; + + m_machine = &machine; + m_interrupt_callback = interrupt_callback; + + m_stat_reg = 0; + m_interrupt_f_f = 1; + + m_buf_pos = 0; + m_buf_mode = bm_off; + + for (i=0; i(floppy_get_device(machine, i)); + m_drv[i].phys_cylinder = -1; + m_drv[i].log_cylinder[0] = m_drv[i].log_cylinder[1] = -1; + m_drv[i].seclen = 64; + floppy_install_unload_proc(&m_drv[i].img->device(), unload_proc); + } + + set_interrupt_line(); +} +*/ + +/* + Read the first id field that can be found on the floppy disk. + + unit: floppy drive index + head: selected head + cylinder_id: cylinder ID read + sector_id: sector ID read + + Return TRUE if an ID was found +*/ +int fd800_legacy_device::read_id(int unit, int head, int *cylinder_id, int *sector_id) +{ + //UINT8 revolution_count;*/ + // chrn_id id; + + //revolution_count = 0;*/ + + /*while (revolution_count < 2)*/ + /*{*/ + /* if (m_drv[unit].img->floppy_drive_get_next_id(head, &id)) + { + if (cylinder_id) + *cylinder_id = id.C; + if (sector_id) + *sector_id = id.R; + return TRUE; + } + }*/ + + return FALSE; +} + +/* + Find a sector by id. + + unit: floppy drive index + head: selected head + sector: sector ID to search + data_id: data ID to be used when calling sector read/write functions + + Return TRUE if the given sector ID was found +*/ +int fd800_legacy_device::find_sector(int unit, int head, int sector, int *data_id) +{ +/* UINT8 revolution_count; + chrn_id id; + + revolution_count = 0; + + while (revolution_count < 2) + { + if (m_drv[unit].img->floppy_drive_get_next_id(head, &id)) + { + // compare id + if ((id.R == sector) && (id.N == 0)) + { + *data_id = id.data_id; + // get ddam status + // w->ddam = id.flags & ID_FLAG_DELETED_DATA; + return TRUE; + } + } + } +*/ + return FALSE; +} + +/* + Perform seek command + + unit: floppy drive index + cylinder: track to seek for + head: head for which the seek is performed + + Return FALSE if the seek was successful +*/ +int fd800_legacy_device::do_seek(int unit, int cylinder, int head) +{ +/* int retries; + + if (cylinder > 76) + { + m_stat_reg |= status_invalid_cmd; + return TRUE; + } + + if (m_drv[unit].img == NULL || !m_drv[unit].img->exists()) + { + m_stat_reg |= status_drv_not_ready; + return TRUE; + } + + if (m_drv[unit].log_cylinder[head] == -1) + { + if (!read_id(unit, head, &m_drv[unit].log_cylinder[head], NULL)) + { + m_stat_reg |= status_ID_not_found; + return TRUE; + } + } + + if (m_drv[unit].log_cylinder[head] == cylinder) + { + + return FALSE; + } + for (retries=0; retries<10; retries++) + { + m_drv[unit].img->floppy_drive_seek(cylinder-m_drv[unit].log_cylinder[head]); + + if (m_drv[unit].phys_cylinder != -1) + m_drv[unit].phys_cylinder += cylinder-m_drv[unit].log_cylinder[head]; + + if (!read_id(unit, head, &m_drv[unit].log_cylinder[head], NULL)) + { + m_drv[unit].log_cylinder[head] = -1; + m_stat_reg |= status_ID_not_found; + return TRUE; + } + + if (m_drv[unit].log_cylinder[head] == cylinder) + { + + return FALSE; + } + } + + m_stat_reg |= status_seek_err; + */ + return TRUE; +} + +/* + Perform restore command + + unit: floppy drive index + + Return FALSE if the restore was successful +*/ +int fd800_legacy_device::do_restore(int unit) +{ + int seek_complete = 0; +/* int seek_count = 0; + + if (!m_drv[unit].img->exists()) + { + m_stat_reg |= status_drv_not_ready; + return TRUE; + } + + + while (!(seek_complete = !m_drv[unit].img->floppy_tk00_r()) && (seek_count < 76)) + { + m_drv[unit].img->floppy_drive_seek(-1); + seek_count++; + } + if (! seek_complete) + { + m_drv[unit].phys_cylinder = -1; + m_stat_reg |= status_seek_err; + } + else + { + m_drv[unit].phys_cylinder = 0; + + } +*/ + return ! seek_complete; +} + +/* + Perform a read operation for one sector +*/ +void fd800_legacy_device::do_read(void) +{ +/* int data_id; + + if ((m_sector == 0) || (m_sector > 26)) + { + m_stat_reg |= status_invalid_cmd; + return; + } + + if (!find_sector(m_unit, m_head, m_sector, &data_id)) + { + m_stat_reg |= status_ID_not_found; + return; + } + + m_drv[m_unit].img->floppy_drive_read_sector_data(m_head, data_id, m_buf, 128); + m_buf_pos = 0; + m_buf_mode = bm_read; + m_recv_buf = (m_buf[m_buf_pos<<1] << 8) | m_buf[(m_buf_pos<<1)+1]; + + m_stat_reg |= status_XFER_ready; + m_stat_reg |= status_OP_complete; +*/ +} + +/* + Perform a write operation for one sector +*/ +void fd800_legacy_device::do_write(void) +{ +/* int data_id; + + if (m_drv[m_unit].seclen < 64) + memset(m_buf+(m_drv[m_unit].seclen<<1), 0, (64-m_drv[m_unit].seclen)<<1); + + if (!find_sector(m_unit, m_head, m_sector, &data_id)) + { + m_stat_reg |= status_ID_not_found; + return; + } + + m_drv[m_unit].img->floppy_drive_write_sector_data(m_head, data_id, m_buf, 128, m_ddam); + m_buf_pos = 0; + m_buf_mode = bm_write; + + m_stat_reg |= status_XFER_ready; + m_stat_reg |= status_OP_complete; +*/ +} + +/* + Execute a fdc command +*/ +void fd800_legacy_device::do_cmd(void) +{ +/* + int unit; + int cylinder; + int head; + int seclen; + int sector; + + + if (m_buf_mode != bm_off) + { // All commands in the midst of read or write are interpreted as Stop + unit = (m_cmd_reg >> 10) & 3; + + // reset status + m_stat_reg = unit << status_unit_shift; + + m_buf_pos = 0; + m_buf_mode = bm_off; + + m_stat_reg |= status_OP_complete; + + m_stat_reg |= status_interrupt; + set_interrupt_line(); + + return; + } + + switch (m_cmd_reg >> 12) + { + case 0: // select + // bits 16-25: 0s + // bits 26-27: unit number (0-3) + unit = (m_cmd_reg >> 10) & 3; + + // reset status + m_stat_reg = unit << status_unit_shift; + + if (!m_drv[unit].img->exists()) + m_stat_reg |= status_drv_not_ready; // right??? + else if (m_drv[unit].img->is_readonly()) + m_stat_reg |= status_write_prot; + else + m_stat_reg |= status_OP_complete; + + m_stat_reg |= status_interrupt; + set_interrupt_line(); + break; + + case 1: // seek + bits 16-22: cylinder number (0-76) + bits 23-24: 0s + bits 25: head number (1=upper) + bits 26-27: unit number (0-3) + unit = (m_cmd_reg >> 10) & 3; + head = (m_cmd_reg >> 9) & 1; + cylinder = m_cmd_reg & 0x7f; + + // reset status + m_stat_reg = unit << status_unit_shift; + + if (!do_seek(unit, cylinder, head)) + m_stat_reg |= status_OP_complete; + + m_stat_reg |= status_interrupt; + set_interrupt_line(); + break; + + case 2: // restore + bits 16-25: 0s + bits 26-27: unit number (0-3) + unit = (m_cmd_reg >> 10) & 3; + + // reset status + m_stat_reg = unit << status_unit_shift; + + if (!do_restore(unit)) + m_stat_reg |= status_OP_complete; + + m_stat_reg |= status_interrupt; + set_interrupt_line(); + break; + + case 3: // sector length + bits 16-22: sector word count (0-64) + bits 23-25: 0s + bits 26-27: unit number (0-3) + unit = (m_cmd_reg >> 10) & 3; + seclen = m_cmd_reg & 0x7f; + + // reset status + m_stat_reg = unit << status_unit_shift; + + if ((seclen > 64) || (seclen == 0)) + { + m_stat_reg |= status_invalid_cmd; + } + else + { + m_drv[unit].seclen = seclen; + m_stat_reg |= status_OP_complete; + } + + m_stat_reg |= status_interrupt; + set_interrupt_line(); + break; + + case 4: // read + bits 16-20: sector number (1-26) + bits 21-23: 0s + bit 24: no sequential sectoring (1=active) + bit 25: head number (1=upper) + bits 26-27: unit number (0-3) + unit = (m_cmd_reg >> 10) & 3; + head = (m_cmd_reg >> 9) & 1; + //non_seq_mode = (m_cmd_reg >> 8) & 1; + sector = m_cmd_reg & 0x1f; + + m_unit = unit; + m_head = head; + m_sector = sector; + //m_non_seq_mode = non_seq_mode; + + // reset status + m_stat_reg = unit << status_unit_shift; + + do_read(); + + m_stat_reg |= status_interrupt; + set_interrupt_line(); + break; + + case 5: // read ID + bits 16-24: 0s + bit 25: head number (1=upper) + bits 26-27: unit number (0-3) + unit = (m_cmd_reg >> 10) & 3; + head = (m_cmd_reg >> 9) & 1; + + // reset status + m_stat_reg = unit << status_unit_shift; + + if (!read_id(unit, head, &cylinder, §or)) + { + m_stat_reg |= status_ID_not_found; + } + else + { + m_recv_buf = (cylinder << 8) | sector; + m_stat_reg |= status_OP_complete; + } + + m_stat_reg |= status_interrupt; + set_interrupt_line(); + break; + + case 6: // read unformatted + bits 16-20: sector number (1-26) + bits 21-24: 0s + bit 25: head number (1=upper) + bits 26-27: unit number (0-3) + // ... + break; + + case 7: // write + bits 16-20: sector number (1-26) + bits 21-24: 0s + bit 25: head number (1=upper) + bits 26-27: unit number (0-3) + unit = (m_cmd_reg >> 10) & 3; + head = (m_cmd_reg >> 9) & 1; + sector = m_cmd_reg & 0x1f; + + // reset status + m_stat_reg = unit << status_unit_shift; + + if ((m_sector == 0) || (m_sector > 26)) + { + m_stat_reg |= status_invalid_cmd; + } + else + { + m_unit = unit; + m_head = head; + m_sector = sector; + m_ddam = 0; + + m_buf_pos = 0; + m_buf_mode = bm_write; + m_stat_reg |= status_XFER_ready; + m_stat_reg |= status_OP_complete; // right??? + } + + m_stat_reg |= status_interrupt; + set_interrupt_line(); + break; + + case 8: // write delete + bits 16-20: sector number (1-26) + bits 21-24: 0s + bit 25: head number (1=upper) + bits 26-27: unit number (0-3) + unit = (m_cmd_reg >> 10) & 3; + head = (m_cmd_reg >> 9) & 1; + sector = m_cmd_reg & 0x1f; + + // reset status + m_stat_reg = unit << status_unit_shift; + + if ((m_sector == 0) || (m_sector > 26)) + { + m_stat_reg |= status_invalid_cmd; + } + else + { + m_unit = unit; + m_head = head; + m_sector = sector; + m_ddam = 1; + + m_buf_pos = 0; + m_buf_mode = bm_write; + m_stat_reg |= status_XFER_ready; + m_stat_reg |= status_OP_complete; // right??? + } + + m_stat_reg |= status_interrupt; + set_interrupt_line(); + break; + + case 9: // format track + bits 16-23: track ID (0-255, normally current cylinder index, or 255 for bad track) + bit 24: verify only (1 - verify, 0 - format & verify) + bit 25: head number (1=upper) + bits 26-27: unit number (0-3) + // ... + break; + + case 10: // load int mask + bit 16: bad mask for interrupt (0 = unmask or enable interrupt) + bits 17-27: 0s + m_interrupt_f_f = m_cmd_reg & 1; + set_interrupt_line(); + break; + + case 11: // stop + bits 16-25: 0s + bits 26-27: unit number (0-3) + unit = (m_cmd_reg >> 10) & 3; + + // reset status + m_stat_reg = unit << status_unit_shift; + + m_stat_reg |= status_OP_complete; + + m_stat_reg |= status_interrupt; + set_interrupt_line(); + break; + + case 12: // step head + bits 16-22: track number (0-76) + bits 23-25: 0s + bits 26-27: unit number (0-3) + unit = (m_cmd_reg >> 10) & 3; + cylinder = m_cmd_reg & 0x7f; + + if (cylinder > 76) + { + m_stat_reg |= status_invalid_cmd; + } + else if ((m_drv[unit].phys_cylinder != -1) || (!do_restore(unit))) + { + m_drv[unit].img->floppy_drive_seek(cylinder-m_drv[unit].phys_cylinder); + m_stat_reg |= status_OP_complete; + } + + m_stat_reg |= status_interrupt; + set_interrupt_line(); + break; + + case 13: // maintenance commands + bits 16-23: according to extended command code + bits 24-27: extended command code (0-7) + switch ((m_cmd_reg >> 8) & 15) + { + case 0: // reset + bits 16-23: 0s + // ... + break; + case 1: // retry inhibit + bits 16-23: 0s + // ... + break; + case 2: // LED test + bit 16: 1 + bits 17-19: 0s + bit 20: LED #2 enable + bit 21: LED #3 enable + bit 22: LED #4 enable + bit 23: enable LEDs + // ... + break; + case 3: // program error (a.k.a. invalid command) + bits 16-23: 0s + // ... + break; + case 4: // memory read + bits 16-20: controller memory address (shifted left by 8 to generate 9900 address) + bits 21-23: 0s + // ... + break; + case 5: // RAM load + bit 16: 0 + bits 17-23: RAM offset (shifted left by 1 and offset by >1800 to generate 9900 address) + // ... + break; + case 6: // RAM run + bit 16: 0 + bits 17-23: RAM offset (shifted left by 1 and offset by >1800 to generate 9900 address) + // ... + break; + case 7: // power up simulation + bits 16-23: 0s + // ... + break; + } + // ... + break; + + case 14: // IPL + bits 16-22: track number (0-76) + bit 23: 0 + bit 24: no sequential sectoring (1=active) + bit 25: head number (1=upper) + bits 26-27: unit number (0-3) + unit = (m_cmd_reg >> 10) & 3; + head = (m_cmd_reg >> 9) & 1; + //non_seq_mode = (m_cmd_reg >> 8) & 1; + cylinder = m_cmd_reg & 0x7f; + + if (!do_seek(unit, cylinder, head)) + { + m_unit = unit; + m_head = head; + m_sector = 1; + //m_non_seq_mode = non_seq_mode; + + do_read(); + } + + m_stat_reg |= status_interrupt; + set_interrupt_line(); + break; + + case 15: // Clear Status port + bits 16-27: 0s + m_stat_reg = 0; + set_interrupt_line(); + break; + } + */ +} + +/* + read one CRU bit + + 0-15: receive buffer + 16-31: status: + 16: OP complete (1 -> complete???) + 17: Xfer ready (XFER) (1 -> ready???) + 18: drive not ready + 19: data check error + 20: seek error/?????? + 21 invalid command/?????? + 22: no address mark found/?????? + 23: equipment check error/?????? + 24: ID check error + 25: ID not found + 26: Controller busy (CTLBSY) (0 -> controller is ready) + 27: write protect + 28: deleted sector detected + 29: unit LSB + 30: unit MSB + 31: Interrupt (CBUSY???) (1 -> controller is ready) +*/ +READ8_MEMBER( fd800_legacy_device::cru_r ) +{ + int reply = 0; + + switch (offset) + { + case 0: + case 1: + // receive buffer + reply = m_recv_buf >> (offset*8); + break; + + case 2: + case 3: + // status register + reply = m_stat_reg >> ((offset-2)*8); + break; + } + + return reply; +} + +/* + write one CRU bit + + 0-15: controller data word (transmit buffer) + 16-31: controller command word (command register) + 16-23: parameter value + 24: flag bit/extended command code + 25: head select/extended command code + 26: FD unit number LSB/extended command code + 27: FD unit number MSB/extended command code + 28-31: command code +*/ +WRITE8_MEMBER( fd800_legacy_device::cru_w ) +{ + switch (offset) + { + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + case 14: + case 15: + // transmit buffer + if (data) + m_xmit_buf |= 1 << offset; + else + m_xmit_buf &= ~(1 << offset); + if (offset == 15) + { + switch (m_buf_mode) + { + case bm_off: + break; + case bm_read: + m_buf_pos++; + if (m_buf_pos == m_drv[m_unit].seclen) + { // end of sector + if (m_sector == 26) + { // end of track -> end command (right???) + m_stat_reg &= ~status_XFER_ready; + m_stat_reg |= status_OP_complete; + m_stat_reg |= status_interrupt; + m_buf_mode = bm_off; + set_interrupt_line(); + } + else + { // read next sector + m_sector++; + m_stat_reg &= ~status_XFER_ready | status_OP_complete | status_interrupt; + do_read(); + m_stat_reg |= status_interrupt; + set_interrupt_line(); + } + } + else + m_recv_buf = (m_buf[m_buf_pos<<1] << 8) | m_buf[(m_buf_pos<<1)+1]; + break; + + case bm_write: + m_buf[m_buf_pos<<1] = m_xmit_buf >> 8; + m_buf[(m_buf_pos<<1)+1] = m_xmit_buf & 0xff; + m_buf_pos++; + if (m_buf_pos == m_drv[m_unit].seclen) + { // end of sector + do_write(); + if (m_sector == 26) + { + // end of track -> end command (right???) + m_stat_reg &= ~status_XFER_ready; + m_stat_reg |= status_OP_complete; + m_stat_reg |= status_interrupt; + m_buf_mode = bm_off; + set_interrupt_line(); + } + else + { // increment to next sector + m_sector++; + m_stat_reg |= status_interrupt; + set_interrupt_line(); + } + } + break; + } + } + break; + + case 16: + case 17: + case 18: + case 19: + case 20: + case 21: + case 22: + case 23: + case 24: + case 25: + case 26: + case 27: + case 28: + case 29: + case 30: + case 31: + // command register + if (data) + m_cmd_reg |= 1 << (offset-16); + else + m_cmd_reg &= ~(1 << (offset-16)); + if (offset == 31) + do_cmd(); + break; + } +} + +#if 0 +LEGACY_FLOPPY_OPTIONS_START(fd800) + // SSSD 8" + LEGACY_FLOPPY_OPTION(fd800, "dsk", "TI990 8\" SSSD disk image", basicdsk_identify_default, basicdsk_construct_default, NULL, + HEADS([1]) + TRACKS([77]) + SECTORS([26]) + SECTOR_LENGTH([128]) + FIRST_SECTOR_ID([1])) + + // DSSD 8" + LEGACY_FLOPPY_OPTION(fd800, "dsk", "TI990 8\" DSSD disk image", basicdsk_identify_default, basicdsk_construct_default, NULL, + HEADS([2]) + TRACKS([77]) + SECTORS([26]) + SECTOR_LENGTH([128]) + FIRST_SECTOR_ID([1])) +LEGACY_FLOPPY_OPTIONS_END +#endif + +void fd800_legacy_device::device_start(void) +{ + logerror("fd800: start\n"); + m_int_line.resolve(); + + for (int i=0; i static devcb_base &static_set_int_callback(device_t &device, _Object object) + { + return downcast(device).m_int_line.set_callback(object); + } + +private: + void device_start(void); + void device_reset(void); + void set_interrupt_line(); + + int read_id(int unit, int head, int *cylinder_id, int *sector_id); + int find_sector(int unit, int head, int sector, int *data_id); + int do_seek(int unit, int cylinder, int head); + int do_restore(int unit); + void do_read(void); + void do_write(void); + void do_cmd(void); + + UINT16 m_recv_buf; + UINT16 m_stat_reg; + UINT16 m_xmit_buf; + UINT16 m_cmd_reg; + + int m_interrupt_f_f; + devcb_write_line m_int_line; + + enum buf_mode_t { + bm_off, bm_read, bm_write + }; + + UINT8 m_buf[128]; + int m_buf_pos; + buf_mode_t m_buf_mode; + int m_unit; +// int m_head; + int m_sector; + /*int m_non_seq_mode;*/ +// int m_ddam; + + struct + { + // legacy_floppy_image_device *img; + int phys_cylinder; + int log_cylinder[2]; + int seclen; + } m_drv[MAX_FLOPPIES]; +}; + +// LEGACY_FLOPPY_OPTIONS_EXTERN(fd800); + +#define MCFG_FD800_INT_HANDLER( _intcallb ) \ + devcb = &fd800_legacy_device::static_set_int_callback( *device, DEVCB_##_intcallb ); + +#endif diff --git a/src/devices/bus/ti99x/990_hd.c b/src/devices/bus/ti99x/990_hd.c new file mode 100644 index 00000000000..fa0cd00646b --- /dev/null +++ b/src/devices/bus/ti99x/990_hd.c @@ -0,0 +1,1025 @@ +// license:GPL-2.0+ +// copyright-holders:Raphael Nabet +/* + 990_hd.c: emulation of a generic ti990 hard disk controller, for use with + TILINE-based TI990 systems (TI990/10, /12, /12LR, /10A, Business system 300 + and 300A). + + This core will emulate the common feature set found in every disk controller. + Most controllers support additional features, but are still compatible with + the basic feature set. I have a little documentation on two specific + disk controllers (WD900 and WD800/WD800A), but I have not tried to emulate + controller-specific features. + + + Long description: see 2234398-9701 and 2306140-9701. + + + Raphael Nabet 2002-2003 +*/ + +#include "emu.h" + +#include "990_hd.h" + +#include "harddisk.h" +#include "imagedev/harddriv.h" + +/* Max sector length is bytes. Generally 256, except for a few older disk +units which use 288-byte-long sectors, and SCSI units which generally use +standard 512-byte-long sectors. */ +/* I chose a limit of 512. No need to use more until someone writes CD-ROMs +for TI990. */ +#define MAX_SECTOR_SIZE 512 + +/* Description of custom format */ +/* We can use MAME's harddisk.c image format instead. */ + +/* machine-independent big-endian 32-bit integer */ +struct UINT32BE +{ + UINT8 bytes[4]; +}; + +INLINE UINT32 get_UINT32BE(UINT32BE word) +{ + return (word.bytes[0] << 24) | (word.bytes[1] << 16) | (word.bytes[2] << 8) | word.bytes[3]; +} + +#ifdef UNUSED_FUNCTION +INLINE void set_UINT32BE(UINT32BE *word, UINT32 data) +{ + word->bytes[0] = (data >> 24) & 0xff; + word->bytes[1] = (data >> 16) & 0xff; + word->bytes[2] = (data >> 8) & 0xff; + word->bytes[3] = data & 0xff; +} +#endif + +/* disk image header */ +struct disk_image_header +{ + UINT32BE cylinders; /* number of cylinders on hard disk (big-endian) */ + UINT32BE heads; /* number of heads on hard disk (big-endian) */ + UINT32BE sectors_per_track; /* number of sectors per track on hard disk (big-endian) */ + UINT32BE bytes_per_sector; /* number of bytes of data per sector on hard disk (big-endian) */ +}; + +enum +{ + header_len = sizeof(disk_image_header) +}; + + +/* masks for individual bits controller registers */ +enum +{ + w0_offline = 0x8000, + w0_not_ready = 0x4000, + w0_write_protect = 0x2000, + w0_unsafe = 0x1000, + w0_end_of_cylinder = 0x0800, + w0_seek_incomplete = 0x0400, + /*w0_offset_active = 0x0200,*/ + w0_pack_change = 0x0100, + + w0_attn_lines = 0x00f0, + w0_attn_mask = 0x000f, + + w1_extended_command = 0xc000, + /*w1_strobe_early = 0x2000, + w1_strobe_late = 0x1000,*/ + w1_transfer_inhibit = 0x0800, + w1_command = 0x0700, + w1_offset = 0x0080, + w1_offset_forward = 0x0040, + w1_head_address = 0x003f, + + w6_unit0_sel = 0x0800, + w6_unit1_sel = 0x0400, + w6_unit2_sel = 0x0200, + w6_unit3_sel = 0x0100, + + w7_idle = 0x8000, + w7_complete = 0x4000, + w7_error = 0x2000, + w7_int_enable = 0x1000, + /*w7_lock_out = 0x0800,*/ + w7_retry = 0x0400, + w7_ecc = 0x0200, + w7_abnormal_completion = 0x0100, + w7_memory_error = 0x0080, + w7_data_error = 0x0040, + w7_tiline_timeout_err = 0x0020, + w7_header_err = 0x0010, + w7_rate_err = 0x0008, + w7_command_time_out_err = 0x0004, + w7_search_err = 0x0002, + w7_unit_err = 0x0001 +}; + +/* masks for computer-controlled bit in each controller register */ +static const UINT16 w_mask[8] = +{ + 0x000f, /* Controllers should prevent overwriting of w0 status bits, and I know + that some controllers do so. */ + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xf7ff /* Don't overwrite reserved bits */ +}; + + +int ti990_hdc_device::get_id_from_device( device_t *device ) +{ + int id = -1; + + if ( ! strcmp( ":harddisk1", device->tag() ) ) + { + id = 0; + } + else if ( ! strcmp( ":harddisk2", device->tag() ) ) + { + id = 1; + } + else if ( ! strcmp( ":harddisk3", device->tag() ) ) + { + id = 2; + } + else if ( ! strcmp( ":harddisk4", device->tag() ) ) + { + id = 3; + } + assert( id >= 0 ); + + return id; +} + + +/* + Initialize hard disk unit and open a hard disk image +*/ +DEVICE_IMAGE_LOAD_MEMBER( ti990_hdc_device, ti990_hd ) +{ + int id = get_id_from_device( &image.device() ); + hd_unit_t *d; + hard_disk_file *hd_file; + + d = &m_d[id]; + d->img = ℑ + + hd_file = dynamic_cast(&image)->get_hard_disk_file(); + + if ( hd_file ) + { + const hard_disk_info *standard_header; + + d->format = format_mame; + d->hd_handle = hd_file; + + /* use standard hard disk image header. */ + standard_header = hard_disk_get_info(d->hd_handle); + + d->cylinders = standard_header->cylinders; + d->heads = standard_header->heads; + d->sectors_per_track = standard_header->sectors; + d->bytes_per_sector = standard_header->sectorbytes; + } + else + { + /* older, custom format */ + disk_image_header custom_header; + int bytes_read; + + /* set file descriptor */ + d->format = format_old; + d->hd_handle = NULL; + + /* use custom image header. */ + /* to convert old header-less images to this format, insert a 16-byte + header as follow: 00 00 03 8f 00 00 00 05 00 00 00 21 00 00 01 00 */ + d->img->fseek(0, SEEK_SET); + bytes_read = d->img->fread(&custom_header, sizeof(custom_header)); + if (bytes_read != sizeof(custom_header)) + { + d->format = format_mame; /* don't care */ + d->wp = 1; + d->unsafe = 1; + return IMAGE_INIT_FAIL; + } + + d->cylinders = get_UINT32BE(custom_header.cylinders); + d->heads = get_UINT32BE(custom_header.heads); + d->sectors_per_track = get_UINT32BE(custom_header.sectors_per_track); + d->bytes_per_sector = get_UINT32BE(custom_header.bytes_per_sector); + } + + if (d->bytes_per_sector > MAX_SECTOR_SIZE) + { + d->format = format_mame; + d->hd_handle = NULL; + d->wp = 1; + d->unsafe = 1; + return IMAGE_INIT_FAIL; + } + + /* tell whether the image is writable */ + d->wp = image.is_readonly(); + + d->unsafe = 1; + /* set attention line */ + m_w[0] |= (0x80 >> id); + + return IMAGE_INIT_PASS; +} + +/* + close a hard disk image +*/ +DEVICE_IMAGE_UNLOAD_MEMBER( ti990_hdc_device, ti990_hd ) +{ + int id = get_id_from_device( image ); + hd_unit_t *d; + + d = &m_d[id]; + + d->format = format_mame; /* don't care */ + d->hd_handle = NULL; + d->wp = 1; + d->unsafe = 1; + + /* clear attention line */ + m_w[0] &= ~ (0x80 >> id); +} + +/* + Return true if a HD image has been loaded +*/ +int ti990_hdc_device::is_unit_loaded(int unit) +{ + int reply = 0; + + switch (m_d[unit].format) + { + case format_mame: + reply = (m_d[unit].hd_handle != NULL); + break; + + case format_old: + reply = (m_d[unit].img->exists() ? 1 : 0); + break; + } + + return reply; +} + +/* + Parse the disk select lines, and return the corresponding tape unit. + (-1 if none) +*/ +int ti990_hdc_device::cur_disk_unit(void) +{ + int reply; + + + if (m_w[6] & w6_unit0_sel) + reply = 0; + else if (m_w[6] & w6_unit1_sel) + reply = 1; + else if (m_w[6] & w6_unit2_sel) + reply = 2; + else if (m_w[6] & w6_unit3_sel) + reply = 3; + else + reply = -1; + + if (reply >= MAX_DISK_UNIT) + reply = -1; + + return reply; +} + +/* + Update interrupt state +*/ +void ti990_hdc_device::update_interrupt() +{ + if (!m_interrupt_callback.isnull()) + m_interrupt_callback((m_w[7] & w7_idle) + && (((m_w[7] & w7_int_enable) && (m_w[7] & (w7_complete | w7_error))) + || ((m_w[0] & (m_w[0] >> 4)) & w0_attn_mask))); +} + +/* + Check that a sector address is valid. + + Terminate current command and return non-zero if the address is invalid. +*/ +int ti990_hdc_device::check_sector_address(int unit, unsigned int cylinder, unsigned int head, unsigned int sector) +{ + if ((cylinder > m_d[unit].cylinders) || (head > m_d[unit].heads) || (sector > m_d[unit].sectors_per_track)) + { /* invalid address */ + if (cylinder > m_d[unit].cylinders) + { + m_w[0] |= w0_seek_incomplete; + m_w[7] |= w7_idle | w7_error | w7_unit_err; + } + else if (head > m_d[unit].heads) + { + m_w[0] |= w0_end_of_cylinder; + m_w[7] |= w7_idle | w7_error | w7_unit_err; + } + else if (sector > m_d[unit].sectors_per_track) + m_w[7] |= w7_idle | w7_error | w7_command_time_out_err; + update_interrupt(); + return 1; + } + + return 0; +} + +/* + Seek to sector whose address is given +*/ +int ti990_hdc_device::sector_to_lba(int unit, unsigned int cylinder, unsigned int head, unsigned int sector, unsigned int *lba) +{ + if (check_sector_address(unit, cylinder, head, sector)) + return 1; + + * lba = (cylinder*m_d[unit].heads + head)*m_d[unit].sectors_per_track + sector; + + return 0; +} + +/* + Read one given sector +*/ +int ti990_hdc_device::read_sector(int unit, unsigned int lba, void *buffer, unsigned int bytes_to_read) +{ + unsigned long byte_position; + unsigned int bytes_read; + + switch (m_d[unit].format) + { + case format_mame: + bytes_read = m_d[unit].bytes_per_sector * hard_disk_read(m_d[unit].hd_handle, lba, buffer); + if (bytes_read > bytes_to_read) + bytes_read = bytes_to_read; + break; + + case format_old: + byte_position = lba*m_d[unit].bytes_per_sector + header_len; + m_d[unit].img->fseek(byte_position, SEEK_SET); + bytes_read = m_d[unit].img->fread(buffer, bytes_to_read); + break; + + default: + bytes_read = 0; + break; + } + + return bytes_read; +} + +/* + Write one given sector +*/ +int ti990_hdc_device::write_sector(int unit, unsigned int lba, const void *buffer, unsigned int bytes_to_write) +{ + unsigned long byte_position; + unsigned int bytes_written; + + switch (m_d[unit].format) + { + case format_mame: + bytes_written = m_d[unit].bytes_per_sector * hard_disk_write(m_d[unit].hd_handle, lba, buffer); + if (bytes_written > bytes_to_write) + bytes_written = bytes_to_write; + break; + + case format_old: + byte_position = lba*m_d[unit].bytes_per_sector + header_len; + m_d[unit].img->fseek(byte_position, SEEK_SET); + bytes_written = m_d[unit].img->fwrite(buffer, bytes_to_write); + break; + + default: + bytes_written = 0; + break; + } + + return bytes_written; +} + +/* + Handle the store registers command: read the drive geometry. +*/ +void ti990_hdc_device::store_registers() +{ + int dma_address; + int byte_count; + + UINT16 buffer[3]; + int i, real_word_count; + + int dsk_sel = cur_disk_unit(); + + + if (dsk_sel == -1) + { + /* No idea what to report... */ + m_w[7] |= w7_idle | w7_error | w7_abnormal_completion; + update_interrupt(); + return; + } + else if (! is_unit_loaded(dsk_sel)) + { /* offline */ + m_w[0] |= w0_offline | w0_not_ready; + m_w[7] |= w7_idle | w7_error | w7_unit_err; + update_interrupt(); + return; + } + + m_d[dsk_sel].unsafe = 0; /* I think */ + + dma_address = ((((int) m_w[6]) << 16) | m_w[5]) & 0x1ffffe; + byte_count = m_w[4] & 0xfffe; + + /* formatted words per track */ + buffer[0] = (m_d[dsk_sel].sectors_per_track*m_d[dsk_sel].bytes_per_sector) >> 1; + /* MSByte: sectors per track; LSByte: bytes of overhead per sector */ + buffer[1] = (m_d[dsk_sel].sectors_per_track << 8) | 0; + /* bits 0-4: heads; bits 5-15: cylinders */ + buffer[2] = (m_d[dsk_sel].heads << 11) | m_d[dsk_sel].cylinders; + + real_word_count = byte_count >> 1; + if (real_word_count > 3) + real_word_count = 3; + + /* DMA */ + if (! (m_w[1] & w1_transfer_inhibit)) + for (i=0; imemory().space(AS_PROGRAM).write_word(dma_address, buffer[i]); + dma_address = (dma_address + 2) & 0x1ffffe; + } + + m_w[7] |= w7_idle | w7_complete; + update_interrupt(); +} + +/* + Handle the write format command: format a complete track on disk. + + The emulation just clears the track data in the disk image. +*/ +void ti990_hdc_device::write_format() +{ + unsigned int cylinder, head, sector; + unsigned int lba; + + UINT8 buffer[MAX_SECTOR_SIZE]; + int bytes_written; + + int dsk_sel = cur_disk_unit(); + + + if (dsk_sel == -1) + { + /* No idea what to report... */ + m_w[7] |= w7_idle | w7_error | w7_abnormal_completion; + update_interrupt(); + return; + } + else if (! is_unit_loaded(dsk_sel)) + { /* offline */ + m_w[0] |= w0_offline | w0_not_ready; + m_w[7] |= w7_idle | w7_error | w7_unit_err; + update_interrupt(); + return; + } + else if (m_d[dsk_sel].unsafe) + { /* disk in unsafe condition */ + m_w[0] |= w0_unsafe | w0_pack_change; + m_w[7] |= w7_idle | w7_error | w7_unit_err; + update_interrupt(); + return; + } + else if (m_d[dsk_sel].wp) + { /* disk write-protected */ + m_w[0] |= w0_write_protect; + m_w[7] |= w7_idle | w7_error | w7_unit_err; + update_interrupt(); + return; + } + + cylinder = m_w[3]; + head = m_w[1] & w1_head_address; + + if (sector_to_lba(dsk_sel, cylinder, head, 0, &lba)) + return; + + memset(buffer, 0, m_d[dsk_sel].bytes_per_sector); + + for (sector=0; sector m_d[dsk_sel].cylinders) + { + m_w[0] |= w0_seek_incomplete; + m_w[7] |= w7_idle | w7_error | w7_unit_err; + update_interrupt(); + return; + } + + bytes_to_read = (byte_count < m_d[dsk_sel].bytes_per_sector) ? byte_count : m_d[dsk_sel].bytes_per_sector; + bytes_read = read_sector(dsk_sel, lba, buffer, bytes_to_read); + + if (bytes_read != bytes_to_read) + { /* behave as if the controller could not found the sector ID mark */ + m_w[7] |= w7_idle | w7_error | w7_command_time_out_err; + update_interrupt(); + return; + } + + /* DMA */ + if (! (m_w[1] & w1_transfer_inhibit)) + for (i=0; imemory().space(AS_PROGRAM).write_word(dma_address, (((int) buffer[i]) << 8) | buffer[i+1]); + dma_address = (dma_address + 2) & 0x1ffffe; + } + + byte_count -= bytes_read; + + /* update sector address to point to next sector */ + lba++; + sector++; + if (sector == m_d[dsk_sel].sectors_per_track) + { + sector = 0; + head++; + if (head == m_d[dsk_sel].heads) + { + head = 0; + cylinder++; + } + } + } + + m_w[7] |= w7_idle | w7_complete; + update_interrupt(); +} + +/* + Handle the write data command: write a variable number of sectors from disk. +*/ +void ti990_hdc_device::write_data() +{ + int dma_address; + int byte_count; + + unsigned int cylinder, head, sector; + unsigned int lba; + + UINT8 buffer[MAX_SECTOR_SIZE]; + UINT16 word; + int bytes_written; + int i; + + int dsk_sel = cur_disk_unit(); + + + if (dsk_sel == -1) + { + /* No idea what to report... */ + m_w[7] |= w7_idle | w7_error | w7_abnormal_completion; + update_interrupt(); + return; + } + else if (! is_unit_loaded(dsk_sel)) + { /* offline */ + m_w[0] |= w0_offline | w0_not_ready; + m_w[7] |= w7_idle | w7_error | w7_unit_err; + update_interrupt(); + return; + } + else if (m_d[dsk_sel].unsafe) + { /* disk in unsafe condition */ + m_w[0] |= w0_unsafe | w0_pack_change; + m_w[7] |= w7_idle | w7_error | w7_unit_err; + update_interrupt(); + return; + } + else if (m_d[dsk_sel].wp) + { /* disk write-protected */ + m_w[0] |= w0_write_protect; + m_w[7] |= w7_idle | w7_error | w7_unit_err; + update_interrupt(); + return; + } + + dma_address = ((((int) m_w[6]) << 16) | m_w[5]) & 0x1ffffe; + byte_count = m_w[4] & 0xfffe; + + cylinder = m_w[3]; + head = m_w[1] & w1_head_address; + sector = m_w[2] & 0xff; + + if (sector_to_lba(dsk_sel, cylinder, head, sector, &lba)) + return; + + while (byte_count > 0) + { /* write data sector per sector */ + if (cylinder > m_d[dsk_sel].cylinders) + { + m_w[0] |= w0_seek_incomplete; + m_w[7] |= w7_idle | w7_error | w7_unit_err; + update_interrupt(); + return; + } + + /* DMA */ + for (i=0; (imemory().space(AS_PROGRAM).read_word(dma_address); + buffer[i] = word >> 8; + buffer[i+1] = word & 0xff; + + dma_address = (dma_address + 2) & 0x1ffffe; + } + /* fill with 0s if we did not reach sector end */ + for (; i> 1; + + real_word_count = byte_count >> 1; + if (real_word_count > 3) + real_word_count = 3; + + /* DMA */ + if (! (m_w[1] & w1_transfer_inhibit)) + for (i=0; imemory().space(AS_PROGRAM).write_word(dma_address, buffer[i]); + dma_address = (dma_address + 2) & 0x1ffffe; + } + + m_w[7] |= w7_idle | w7_complete; + update_interrupt(); +} + +/* + Handle the restore command: return to track 0. +*/ +void ti990_hdc_device::restore() +{ + int dsk_sel = cur_disk_unit(); + + + if (dsk_sel == -1) + { + /* No idea what to report... */ + m_w[7] |= w7_idle | w7_error | w7_abnormal_completion; + update_interrupt(); + return; + } + else if (! is_unit_loaded(dsk_sel)) + { /* offline */ + m_w[0] |= w0_offline | w0_not_ready; + m_w[7] |= w7_idle | w7_error | w7_unit_err; + update_interrupt(); + return; + } + + m_d[dsk_sel].unsafe = 0; /* I think */ + + /*if (seek_to_sector(dsk_sel, 0, 0, 0)) + return;*/ + + m_w[7] |= w7_idle | w7_complete; + update_interrupt(); +} + +/* + Parse command code and execute the command. +*/ +void ti990_hdc_device::execute_command() +{ + /* hack */ + m_w[0] &= 0xff; + + if (m_w[1] & w1_extended_command) + logerror("extended commands not supported\n"); + + switch (/*((m_w[1] & w1_extended_command) >> 11) |*/ ((m_w[1] & w1_command) >> 8)) + { + case 0x00: //0b000: + /* store registers */ + logerror("store registers\n"); + store_registers(); + break; + case 0x01: //0b001: + /* write format */ + logerror("write format\n"); + write_format(); + break; + case 0x02: //0b010: + /* read data */ + logerror("read data\n"); + read_data(); + break; + case 0x03: //0b011: + /* write data */ + logerror("write data\n"); + write_data(); + break; + case 0x04: //0b100: + /* unformatted read */ + logerror("unformatted read\n"); + unformatted_read(); + break; + case 0x05: //0b101: + /* unformatted write */ + logerror("unformatted write\n"); + /* ... */ + m_w[7] |= w7_idle | w7_error | w7_abnormal_completion; + update_interrupt(); + break; + case 0x06: //0b110: + /* seek */ + logerror("seek\n"); + /* This command can (almost) safely be ignored */ + m_w[7] |= w7_idle | w7_complete; + update_interrupt(); + break; + case 0x07: //0b111: + /* restore */ + logerror("restore\n"); + restore(); + break; + } +} + +/* + Read one register in TPCS space +*/ +READ16_MEMBER(ti990_hdc_device::read) +{ + if (offset < 8) + return m_w[offset]; + else + return 0; +} + +/* + Write one register in TPCS space. Execute command if w7_idle is cleared. +*/ +WRITE16_MEMBER(ti990_hdc_device::write) +{ + if (offset < 8) + { + /* write protect if a command is in progress */ + if (m_w[7] & w7_idle) + { + UINT16 old_data = m_w[offset]; + + /* Only write writable bits AND honor byte accesses (ha!) */ + m_w[offset] = (m_w[offset] & ((~w_mask[offset]) | mem_mask)) | (data & w_mask[offset] & ~mem_mask); + + if ((offset == 0) || (offset == 7)) + update_interrupt(); + + if ((offset == 7) && (old_data & w7_idle) && ! (data & w7_idle)) + { /* idle has been cleared: start command execution */ + execute_command(); + } + } + } +} + + +static MACHINE_CONFIG_FRAGMENT( ti990_hdc ) + MCFG_HARDDISK_ADD( "harddisk1" ) + MCFG_HARDDISK_LOAD(ti990_hdc_device, ti990_hd) + MCFG_HARDDISK_UNLOAD(ti990_hdc_device, ti990_hd) + MCFG_HARDDISK_ADD( "harddisk2" ) + MCFG_HARDDISK_LOAD(ti990_hdc_device, ti990_hd) + MCFG_HARDDISK_UNLOAD(ti990_hdc_device, ti990_hd) + MCFG_HARDDISK_ADD( "harddisk3" ) + MCFG_HARDDISK_LOAD(ti990_hdc_device, ti990_hd) + MCFG_HARDDISK_UNLOAD(ti990_hdc_device, ti990_hd) + MCFG_HARDDISK_ADD( "harddisk4" ) + MCFG_HARDDISK_LOAD(ti990_hdc_device, ti990_hd) + MCFG_HARDDISK_UNLOAD(ti990_hdc_device, ti990_hd) +MACHINE_CONFIG_END + +const device_type TI990_HDC = &device_creator; + +ti990_hdc_device::ti990_hdc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, TI990_HDC, "Generic TI-990 Hard Disk Controller", tag, owner, clock, "hdc_990", __FILE__), + m_interrupt_callback(*this) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void ti990_hdc_device::device_start() +{ + int i; + + /* initialize harddisk information */ + /* attention lines will be set by DEVICE_IMAGE_LOD */ + for (i=0; i(subdevice("harddisk1")); + m_d[1].img = dynamic_cast(subdevice("harddisk2")); + m_d[2].img = dynamic_cast(subdevice("harddisk3")); + m_d[3].img = dynamic_cast(subdevice("harddisk4")); + + m_interrupt_callback.resolve_safe(); + + update_interrupt(); +} + + +//------------------------------------------------- +// device_mconfig_additions - return a pointer to +// the device's machine fragment +//------------------------------------------------- + +machine_config_constructor ti990_hdc_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( ti990_hdc ); +} diff --git a/src/devices/bus/ti99x/990_hd.h b/src/devices/bus/ti99x/990_hd.h new file mode 100644 index 00000000000..4c5e85f928d --- /dev/null +++ b/src/devices/bus/ti99x/990_hd.h @@ -0,0 +1,80 @@ +// license:GPL-2.0+ +// copyright-holders:Raphael Nabet +/* + 990_hd.h: include file for 990_hd.c +*/ +#ifndef __990_HD_H_ +#define __990_HD_H_ + +#include "imagedev/harddriv.h" + +/* max disk units per controller: 4 is the protocol limit, but it may be +overriden if more than one controller is used */ +#define MAX_DISK_UNIT 4 + +class ti990_hdc_device : public device_t +{ +public: + ti990_hdc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + template static devcb_base &static_set_int_callback(device_t &device, _Object object) { return downcast(device).m_interrupt_callback.set_callback(object); } + + DECLARE_READ16_MEMBER(read); + DECLARE_WRITE16_MEMBER(write); + + DECLARE_DEVICE_IMAGE_LOAD_MEMBER( ti990_hd ); + DECLARE_DEVICE_IMAGE_UNLOAD_MEMBER( ti990_hd ); +protected: + // device-level overrides + virtual void device_start(); + virtual machine_config_constructor device_mconfig_additions() const; + + int get_id_from_device( device_t *device ); + + inline int is_unit_loaded(int unit); + int cur_disk_unit(void); + void update_interrupt(); + int check_sector_address(int unit, unsigned int cylinder, unsigned int head, unsigned int sector); + int sector_to_lba(int unit, unsigned int cylinder, unsigned int head, unsigned int sector, unsigned int *lba); + int read_sector(int unit, unsigned int lba, void *buffer, unsigned int bytes_to_read); + int write_sector(int unit, unsigned int lba, const void *buffer, unsigned int bytes_to_write); + void store_registers(); + void write_format(); + void read_data(); + void write_data(); + void unformatted_read(); + void restore(); + void execute_command(); +private: + enum format_t + { + format_mame, + format_old + }; + + /* disk drive unit descriptor */ + struct hd_unit_t + { + device_image_interface *img; /* image descriptor */ + format_t format; + hard_disk_file *hd_handle; /* mame hard disk descriptor - only if format == format_mame */ + unsigned int wp : 1; /* TRUE if disk is write-protected */ + unsigned int unsafe : 1; /* TRUE when a disk has just been connected */ + + /* disk geometry */ + unsigned int cylinders, heads, sectors_per_track, bytes_per_sector; + }; + + UINT16 m_w[8]; + + devcb_write_line m_interrupt_callback; + + hd_unit_t m_d[MAX_DISK_UNIT]; +}; + +#define MCFG_TI990_HDC_INT_CALLBACK( _write ) \ + devcb = &ti990_hdc_device::static_set_int_callback( *device, DEVCB_##_write ); + +extern const device_type TI990_HDC; + +#endif diff --git a/src/devices/bus/ti99x/990_tap.c b/src/devices/bus/ti99x/990_tap.c new file mode 100644 index 00000000000..20ca2333f7b --- /dev/null +++ b/src/devices/bus/ti99x/990_tap.c @@ -0,0 +1,1021 @@ +// license:GPL-2.0+ +// copyright-holders:Raphael Nabet +/* + 990_tap.c: emulation of a generic ti990 tape controller, for use with + TILINE-based TI990 systems (TI990/10, /12, /12LR, /10A, Business system 300 + and 300A). + + This core will emulate the common feature set found in every tape controller. + Most controllers support additional features, but are still compatible with + the basic feature set. I have a little documentation on two specific + tape controllers (MT3200 and WD800/WD800A), but I have not tried to emulate + controller-specific features. + + + Long description: see 2234398-9701 and 2306140-9701. + + + Raphael Nabet 2002 +*/ +/* + Image encoding: + + + 2 bytes: record len - little-endian + 2 bytes: always 0s (length MSBs?) + len bytes: data + 2 bytes: record len - little-endian + 2 bytes: always 0s (length MSBs?) + + 4 0s: EOF mark +*/ + +#include "emu.h" +#include "990_tap.h" + +enum +{ + w0_offline = 0x8000, + w0_BOT = 0x4000, + w0_EOR = 0x2000, + w0_EOF = 0x1000, + w0_EOT = 0x0800, + w0_write_ring = 0x0400, + w0_tape_rewinding = 0x0200, + w0_command_timeout = 0x0100, + + w0_rewind_status = 0x00f0, + w0_rewind_mask = 0x000f, + + w6_unit0_sel = 0x8000, + w6_unit1_sel = 0x4000, + w6_unit2_sel = 0x2000, + w6_unit3_sel = 0x1000, + w6_command = 0x0f00, + + w7_idle = 0x8000, + w7_complete = 0x4000, + w7_error = 0x2000, + w7_int_enable = 0x1000, + w7_PE_format = 0x0200, + w7_abnormal_completion = 0x0100, + w7_interface_parity_err = 0x0080, + w7_err_correction_enabled = 0x0040, + w7_hard_error = 0x0020, + w7_tiline_parity_err = 0x0010, + w7_tiline_timing_err = 0x0008, + w7_tiline_timeout_err = 0x0004, + /*w7_format_error = 0x0002,*/ + w7_tape_error = 0x0001 +}; + +static const UINT16 w_mask[8] = +{ + 0x000f, /* Controllers should prevent overwriting of w0 status bits, and I know + that some controllers do so. */ + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xf3ff /* Don't overwrite reserved bits */ +}; + +/* + Parse the tape select lines, and return the corresponding tape unit. + (-1 if none) +*/ +int tap_990_device::cur_tape_unit() +{ + int reply; + + if (m_w[6] & w6_unit0_sel) + reply = 0; + else if (m_w[6] & w6_unit1_sel) + reply = 1; + else if (m_w[6] & w6_unit2_sel) + reply = 2; + else if (m_w[6] & w6_unit3_sel) + reply = 3; + else + reply = -1; + + if (reply >= MAX_TAPE_UNIT) + reply = -1; + + return reply; +} + +/* + Update interrupt state +*/ +void tap_990_device::update_interrupt() +{ + bool level = (m_w[7] & w7_idle) + && (((m_w[7] & w7_int_enable) && (m_w[7] & (w7_complete | w7_error))) + || ((m_w[0] & ~(m_w[0] >> 4)) & w0_rewind_mask)); + m_int_line(level); +} + +/* + Handle the read binary forward command: read the next record on tape. +*/ +void tap_990_device::cmd_read_binary_forward() +{ + UINT8 buffer[256]; + int reclen; + + int dma_address; + int char_count; + int read_offset; + + int rec_count = 0; + int chunk_len; + int bytes_to_read; + int bytes_read; + int i; + + int tap_sel = cur_tape_unit(); + + if (tap_sel == -1) + { + /* No idea what to report... */ + m_w[7] |= w7_idle | w7_error | w7_hard_error; + update_interrupt(); + return; + } + else if (!m_tape[tap_sel].img->exists()) + { /* offline */ + m_w[0] |= w0_offline; + m_w[7] |= w7_idle | w7_error | w7_tape_error; + update_interrupt(); + return; + } +#if 0 + else if (0) + { /* rewind in progress */ + m_w[0] |= 0x80 >> tap_sel; + m_w[7] |= w7_idle | w7_error | w7_tape_error; + update_interrupt(); + return; + } +#endif + + m_tape[tap_sel].bot = 0; + + dma_address = ((((int)m_w[6]) << 16) | m_w[5]) & 0x1ffffe; + char_count = m_w[4]; + read_offset = m_w[3]; + + bytes_read = m_tape[tap_sel].img->fread(buffer, 4); + if (bytes_read != 4) + { + if (bytes_read == 0) + { /* legitimate EOF */ + m_tape[tap_sel].eot = 1; + m_w[0] |= w0_EOT; /* or should it be w0_command_timeout? */ + m_w[7] |= w7_idle | w7_error | w7_tape_error; + update_interrupt(); + goto update_registers; + } + else + { /* illegitimate EOF */ + /* No idea what to report... */ + /* eject tape to avoid catastrophes */ + logerror("Tape error\n"); + m_tape[tap_sel].img->unload(); + m_w[0] |= w0_offline; + m_w[7] |= w7_idle | w7_error | w7_hard_error; + update_interrupt(); + goto update_registers; + } + } + reclen = (((int) buffer[1]) << 8) | buffer[0]; + if (buffer[2] || buffer[3]) + { /* no idea what these bytes mean */ + logerror("Tape error\n"); + logerror("Tape format looks gooofy\n"); + /* eject tape to avoid catastrophes */ + m_tape[tap_sel].img->unload(); + m_w[0] |= w0_offline; + m_w[7] |= w7_idle | w7_error | w7_hard_error; + update_interrupt(); + goto update_registers; + } + + /* test for EOF mark */ + if (reclen == 0) + { + logerror("read binary forward: found EOF, requested %d\n", char_count); + m_w[0] |= w0_EOF; + m_w[7] |= w7_idle | w7_error | w7_tape_error; + update_interrupt(); + goto update_registers; + } + + logerror("read binary forward: rec length %d, requested %d\n", reclen, char_count); + + rec_count = reclen; + + /* skip up to read_offset bytes */ + chunk_len = (read_offset > rec_count) ? rec_count : read_offset; + + if (m_tape[tap_sel].img->fseek(chunk_len, SEEK_CUR)) + { /* eject tape */ + logerror("Tape error\n"); + m_tape[tap_sel].img->unload(); + m_w[0] |= w0_offline; + m_w[7] |= w7_idle | w7_error | w7_hard_error; + update_interrupt(); + goto update_registers; + } + + rec_count -= chunk_len; + read_offset -= chunk_len; + if (read_offset) + { + m_w[0] |= w0_EOR; + m_w[7] |= w7_idle | w7_error | w7_tape_error; + update_interrupt(); + goto skip_trailer; + } + + /* read up to char_count bytes */ + chunk_len = (char_count > rec_count) ? rec_count : char_count; + + for (; chunk_len>0; ) + { + bytes_to_read = (chunk_len < sizeof(buffer)) ? chunk_len : sizeof(buffer); + bytes_read = m_tape[tap_sel].img->fread(buffer, bytes_to_read); + + if (bytes_read & 1) + { + buffer[bytes_read] = 0xff; + } + + /* DMA */ + for (i=0; imemory().space(AS_PROGRAM).write_word(dma_address, (((int) buffer[i]) << 8) | buffer[i+1]); + dma_address = (dma_address + 2) & 0x1ffffe; + } + + rec_count -= bytes_read; + char_count -= bytes_read; + chunk_len -= bytes_read; + + if (bytes_read != bytes_to_read) + { /* eject tape */ + logerror("Tape error\n"); + m_tape[tap_sel].img->unload(); + m_w[0] |= w0_offline; + m_w[7] |= w7_idle | w7_error | w7_hard_error; + update_interrupt(); + goto update_registers; + } + } + + if (char_count) + { + m_w[0] |= w0_EOR; + m_w[7] |= w7_idle | w7_error | w7_tape_error; + update_interrupt(); + goto skip_trailer; + } + + if (rec_count) + { /* skip end of record */ + if (m_tape[tap_sel].img->fseek(rec_count, SEEK_CUR)) + { /* eject tape */ + logerror("Tape error\n"); + m_tape[tap_sel].img->unload(); + m_w[0] |= w0_offline; + m_w[7] |= w7_idle | w7_error | w7_hard_error; + update_interrupt(); + goto update_registers; + } + } + +skip_trailer: + if (m_tape[tap_sel].img->fread(buffer, 4) != 4) + { /* eject tape */ + logerror("Tape error\n"); + m_tape[tap_sel].img->unload(); + m_w[0] |= w0_offline; + m_w[7] |= w7_idle | w7_error | w7_hard_error; + update_interrupt(); + goto update_registers; + } + + if (reclen != ((((int) buffer[1]) << 8) | buffer[0])) + { /* eject tape */ + logerror("Tape error\n"); + m_tape[tap_sel].img->unload(); + m_w[0] |= w0_offline; + m_w[7] |= w7_idle | w7_error | w7_hard_error; + update_interrupt(); + goto update_registers; + } + if (buffer[2] || buffer[3]) + { /* no idea what these bytes mean */ + logerror("Tape error\n"); + logerror("Tape format looks gooofy\n"); + /* eject tape to avoid catastrophes */ + m_tape[tap_sel].img->unload(); + m_w[0] |= w0_offline; + m_w[7] |= w7_idle | w7_error | w7_hard_error; + update_interrupt(); + goto update_registers; + } + + if (! (m_w[7] & w7_error)) + { + m_w[7] |= w7_idle | w7_complete; + update_interrupt(); + } + +update_registers: + m_w[1] = rec_count & 0xffff; + m_w[2] = (rec_count >> 8) & 0xff; + m_w[3] = read_offset; + m_w[4] = char_count; + m_w[5] = (dma_address >> 1) & 0xffff; + m_w[6] = (m_w[6] & 0xffe0) | ((dma_address >> 17) & 0xf); +} + +/* + Handle the record skip forward command: skip a specified number of records. +*/ +void tap_990_device::cmd_record_skip_forward() +{ + UINT8 buffer[4]; + int reclen; + + int record_count; + int bytes_read; + + int tap_sel = cur_tape_unit(); + + if (tap_sel == -1) + { + /* No idea what to report... */ + m_w[7] |= w7_idle | w7_error | w7_hard_error; + update_interrupt(); + return; + } + else if (! m_tape[tap_sel].img->exists()) + { /* offline */ + m_w[0] |= w0_offline; + m_w[7] |= w7_idle | w7_error | w7_tape_error; + update_interrupt(); + return; + } +#if 0 + else if (0) + { /* rewind in progress */ + m_w[0] |= 0x80 >> tap_sel; + m_w[7] |= w7_idle | w7_error | w7_tape_error; + update_interrupt(); + return; + } +#endif + + record_count = m_w[4]; + + if (record_count) + m_tape[tap_sel].bot = 0; + + while (record_count > 0) + { + bytes_read = m_tape[tap_sel].img->fread(buffer, 4); + if (bytes_read != 4) + { + if (bytes_read == 0) + { /* legitimate EOF */ + m_tape[tap_sel].eot = 1; + m_w[0] |= w0_EOT; /* or should it be w0_command_timeout? */ + m_w[7] |= w7_idle | w7_error | w7_tape_error; + update_interrupt(); + goto update_registers; + } + else + { /* illegitimate EOF */ + /* No idea what to report... */ + /* eject tape to avoid catastrophes */ + m_tape[tap_sel].img->unload(); + m_w[0] |= w0_offline; + m_w[7] |= w7_idle | w7_error | w7_hard_error; + update_interrupt(); + goto update_registers; + } + } + reclen = (((int) buffer[1]) << 8) | buffer[0]; + if (buffer[2] || buffer[3]) + { /* no idea what these bytes mean */ + logerror("Tape format looks gooofy\n"); + /* eject tape to avoid catastrophes */ + m_tape[tap_sel].img->unload(); + m_w[0] |= w0_offline; + m_w[7] |= w7_idle | w7_error | w7_hard_error; + update_interrupt(); + goto update_registers; + } + + /* test for EOF mark */ + if (reclen == 0) + { + logerror("record skip forward: found EOF\n"); + m_w[0] |= w0_EOF; + m_w[7] |= w7_idle | w7_error | w7_tape_error; + update_interrupt(); + goto update_registers; + } + + /* skip record data */ + if (m_tape[tap_sel].img->fseek(reclen, SEEK_CUR)) + { /* eject tape */ + m_tape[tap_sel].img->unload(); + m_w[0] |= w0_offline; + m_w[7] |= w7_idle | w7_error | w7_hard_error; + update_interrupt(); + goto update_registers; + } + + if (m_tape[tap_sel].img->fread(buffer, 4) != 4) + { /* eject tape */ + m_tape[tap_sel].img->unload(); + m_w[0] |= w0_offline; + m_w[7] |= w7_idle | w7_error | w7_hard_error; + update_interrupt(); + goto update_registers; + } + + if (reclen != ((((int) buffer[1]) << 8) | buffer[0])) + { /* eject tape */ + m_tape[tap_sel].img->unload(); + m_w[0] |= w0_offline; + m_w[7] |= w7_idle | w7_error | w7_hard_error; + update_interrupt(); + goto update_registers; + } + if (buffer[2] || buffer[3]) + { /* no idea what these bytes mean */ + logerror("Tape format looks gooofy\n"); + /* eject tape to avoid catastrophes */ + m_tape[tap_sel].img->unload(); + m_w[0] |= w0_offline; + m_w[7] |= w7_idle | w7_error | w7_hard_error; + update_interrupt(); + goto update_registers; + } + + record_count--; + } + + m_w[7] |= w7_idle | w7_complete; + update_interrupt(); + +update_registers: + m_w[4] = record_count; +} + +/* + Handle the record skip reverse command: skip a specified number of records backwards. +*/ +void tap_990_device::cmd_record_skip_reverse() +{ + UINT8 buffer[4]; + int reclen; + + int record_count; + + int bytes_read; + + int tap_sel = cur_tape_unit(); + + if (tap_sel == -1) + { + /* No idea what to report... */ + m_w[7] |= w7_idle | w7_error | w7_hard_error; + update_interrupt(); + return; + } + else if (! m_tape[tap_sel].img->exists()) + { /* offline */ + m_w[0] |= w0_offline; + m_w[7] |= w7_idle | w7_error | w7_tape_error; + update_interrupt(); + return; + } +#if 0 + else if (0) + { /* rewind in progress */ + m_w[0] |= 0x80 >> tap_sel; + m_w[7] |= w7_idle | w7_error | w7_tape_error; + update_interrupt(); + return; + } +#endif + + record_count = m_w[4]; + + if (record_count) + m_tape[tap_sel].eot = 0; + + while (record_count > 0) + { + if (m_tape[tap_sel].img->ftell() == 0) + { /* bot */ + m_tape[tap_sel].bot = 1; + m_w[0] |= w0_BOT; + m_w[7] |= w7_idle | w7_error | w7_tape_error; + update_interrupt(); + goto update_registers; + } + if (m_tape[tap_sel].img->fseek(-4, SEEK_CUR)) + { /* eject tape */ + m_tape[tap_sel].img->unload(); + m_w[0] |= w0_offline; + m_w[7] |= w7_idle | w7_error | w7_hard_error; + update_interrupt(); + goto update_registers; + } + bytes_read = m_tape[tap_sel].img->fread(buffer, 4); + if (bytes_read != 4) + { + /* illegitimate EOF */ + /* No idea what to report... */ + /* eject tape to avoid catastrophes */ + m_tape[tap_sel].img->unload(); + m_w[0] |= w0_offline; + m_w[7] |= w7_idle | w7_error | w7_hard_error; + update_interrupt(); + goto update_registers; + } + reclen = (((int) buffer[1]) << 8) | buffer[0]; + if (buffer[2] || buffer[3]) + { /* no idea what these bytes mean */ + logerror("Tape format looks gooofy\n"); + /* eject tape to avoid catastrophes */ + m_tape[tap_sel].img->unload(); + m_w[0] |= w0_offline; + m_w[7] |= w7_idle | w7_error | w7_hard_error; + update_interrupt(); + goto update_registers; + } + + /* look for EOF mark */ + if (reclen == 0) + { + logerror("record skip reverse: found EOF\n"); + if (m_tape[tap_sel].img->fseek(-4, SEEK_CUR)) + { /* eject tape */ + m_tape[tap_sel].img->unload(); + m_w[0] |= w0_offline; + m_w[7] |= w7_idle | w7_error | w7_hard_error; + update_interrupt(); + goto update_registers; + } + m_w[0] |= w0_EOF; + m_w[7] |= w7_idle | w7_error | w7_tape_error; + update_interrupt(); + goto update_registers; + } + + if (m_tape[tap_sel].img->fseek(-reclen-8, SEEK_CUR)) + { /* eject tape */ + m_tape[tap_sel].img->unload(); + m_w[0] |= w0_offline; + m_w[7] |= w7_idle | w7_error | w7_hard_error; + update_interrupt(); + goto update_registers; + } + + if (m_tape[tap_sel].img->fread(buffer, 4) != 4) + { /* eject tape */ + m_tape[tap_sel].img->unload(); + m_w[0] |= w0_offline; + m_w[7] |= w7_idle | w7_error | w7_hard_error; + update_interrupt(); + goto update_registers; + } + if (reclen != ((((int) buffer[1]) << 8) | buffer[0])) + { /* eject tape */ + m_tape[tap_sel].img->unload(); + m_w[0] |= w0_offline; + m_w[7] |= w7_idle | w7_error | w7_hard_error; + update_interrupt(); + goto update_registers; + } + if (buffer[2] || buffer[3]) + { /* no idea what these bytes mean */ + logerror("Tape format looks gooofy\n"); + /* eject tape to avoid catastrophes */ + m_tape[tap_sel].img->unload(); + m_w[0] |= w0_offline; + m_w[7] |= w7_idle | w7_error | w7_hard_error; + update_interrupt(); + goto update_registers; + } + + if (m_tape[tap_sel].img->fseek(-4, SEEK_CUR)) + { /* eject tape */ + m_tape[tap_sel].img->unload(); + m_w[0] |= w0_offline; + m_w[7] |= w7_idle | w7_error | w7_hard_error; + update_interrupt(); + goto update_registers; + } + + record_count--; + } + + m_w[7] |= w7_idle | w7_complete; + update_interrupt(); + +update_registers: + m_w[4] = record_count; +} + +/* + Handle the rewind command: rewind to BOT. +*/ +void tap_990_device::cmd_rewind() +{ + int tap_sel = cur_tape_unit(); + + if (tap_sel == -1) + { + /* No idea what to report... */ + m_w[7] |= w7_idle | w7_error | w7_hard_error; + update_interrupt(); + return; + } + else if (! m_tape[tap_sel].img->exists()) + { /* offline */ + m_w[0] |= w0_offline; + m_w[7] |= w7_idle | w7_error | w7_tape_error; + update_interrupt(); + return; + } +#if 0 + else if (0) + { /* rewind in progress */ + m_w[0] |= 0x80 >> tap_sel; + m_w[7] |= w7_idle | w7_error | w7_tape_error; + update_interrupt(); + return; + } +#endif + + m_tape[tap_sel].eot = 0; + + if (m_tape[tap_sel].img->fseek(0, SEEK_SET)) + { /* eject tape */ + m_tape[tap_sel].img->unload(); + m_w[0] |= w0_offline; + m_w[7] |= w7_idle | w7_error | w7_hard_error; + update_interrupt(); + return; + } + m_tape[tap_sel].bot = 1; + + m_w[7] |= w7_idle | w7_complete; + update_interrupt(); +} + +/* + Handle the rewind and offline command: disable the tape unit. +*/ +void tap_990_device::cmd_rewind_and_offline() +{ + int tap_sel = cur_tape_unit(); + + if (tap_sel == -1) + { + /* No idea what to report... */ + m_w[7] |= w7_idle | w7_error | w7_hard_error; + update_interrupt(); + return; + } + else if (! m_tape[tap_sel].img->exists()) + { /* offline */ + m_w[0] |= w0_offline; + m_w[7] |= w7_idle | w7_error | w7_tape_error; + update_interrupt(); + return; + } +#if 0 + else if (0) + { /* rewind in progress */ + m_w[0] |= 0x80 >> tap_sel; + m_w[7] |= w7_idle | w7_error | w7_tape_error; + update_interrupt(); + return; + } +#endif + + /* eject tape */ + m_tape[tap_sel].img->unload(); + + m_w[7] |= w7_idle | w7_complete; + update_interrupt(); +} + +/* + Handle the read transport status command: return the current tape status. +*/ +void tap_990_device::read_transport_status() +{ + int tap_sel = cur_tape_unit(); + + if (tap_sel == -1) + { + /* No idea what to report... */ + m_w[7] |= w7_idle | w7_error | w7_hard_error; + update_interrupt(); + } + else if (! m_tape[tap_sel].img->exists()) + { /* offline */ + m_w[0] |= w0_offline; + m_w[7] |= w7_idle | w7_error | w7_tape_error; + update_interrupt(); + } +#if 0 + else if (0) + { /* rewind in progress */ + m_w[0] |= /*...*/; + m_w[7] |= w7_idle | w7_error | w7_tape_error; + update_interrupt(); + } +#endif + else + { /* no particular error condition */ + if (m_tape[tap_sel].bot) + m_w[0] |= w0_BOT; + if (m_tape[tap_sel].eot) + m_w[0] |= w0_EOT; + if (m_tape[tap_sel].wp) + m_w[0] |= w0_write_ring; + m_w[7] |= w7_idle | w7_complete; + update_interrupt(); + } +} + +/* + Parse command code and execute the command. +*/ +void tap_990_device::execute_command() +{ + /* hack */ + m_w[0] &= 0xff; + + switch ((m_w[6] & w6_command) >> 8) + { + case 0x00: + case 0x0C: + case 0x0E: + /* NOP */ + logerror("NOP\n"); + m_w[7] |= w7_idle | w7_complete; + update_interrupt(); + break; + case 0x01: + /* buffer sync: means nothing under emulation */ + logerror("buffer sync\n"); + m_w[7] |= w7_idle | w7_complete; + update_interrupt(); + break; + case 0x02: + /* write EOF - not emulated */ + logerror("write EOF\n"); + /* ... */ + m_w[7] |= w7_idle | w7_error | w7_hard_error; + update_interrupt(); + break; + case 0x03: + /* record skip reverse - not fully tested */ + logerror("record skip reverse\n"); + cmd_record_skip_reverse(); + break; + case 0x04: + /* read binary forward */ + logerror("read binary forward\n"); + cmd_read_binary_forward(); + break; + case 0x05: + /* record skip forward - not tested */ + logerror("record skip forward\n"); + cmd_record_skip_forward(); + break; + case 0x06: + /* write binary forward - not emulated */ + logerror("write binary forward\n"); + /* ... */ + m_w[7] |= w7_idle | w7_error | w7_hard_error; + update_interrupt(); + break; + case 0x07: + /* erase - not emulated */ + logerror("erase\n"); + /* ... */ + m_w[7] |= w7_idle | w7_error | w7_hard_error; + update_interrupt(); + break; + case 0x08: + case 0x09: + /* read transport status */ + logerror("read transport status\n"); + read_transport_status(); + break; + case 0x0A: + /* rewind - not tested */ + logerror("rewind\n"); + cmd_rewind(); + break; + case 0x0B: + /* rewind and offline - not tested */ + logerror("rewind and offline\n"); + cmd_rewind_and_offline(); + break; + case 0x0F: + /* extended control and status - not emulated */ + logerror("extended control and status\n"); + /* ... */ + m_w[7] |= w7_idle | w7_error | w7_hard_error; + update_interrupt(); + break; + } +} + + +/* + Read one register in TPCS space +*/ +READ16_MEMBER( tap_990_device::read ) +{ + if (offset < 8) + return m_w[offset]; + else + return 0; +} + +/* + Write one register in TPCS space. Execute command if w7_idle is cleared. +*/ +WRITE16_MEMBER( tap_990_device::write ) +{ + if (offset < 8) + { + /* write protect if a command is in progress */ + if (m_w[7] & w7_idle) + { + UINT16 old_data = m_w[offset]; + + /* Only write writable bits AND honor byte accesses (ha!) */ + m_w[offset] = (m_w[offset] & ((~w_mask[offset]) | mem_mask)) | (data & w_mask[offset] & ~mem_mask); + + if ((offset == 0) || (offset == 7)) + update_interrupt(); + + if ((offset == 7) && (old_data & w7_idle) && ! (data & w7_idle)) + { /* idle has been cleared: start command execution */ + execute_command(); + } + } + } +} + +class ti990_tape_image_device : public device_t, + public device_image_interface +{ +public: + // construction/destruction + ti990_tape_image_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // image-level overrides + virtual iodevice_t image_type() const { return IO_MAGTAPE; } + + virtual bool is_readable() const { return 1; } + virtual bool is_writeable() const { return 1; } + virtual bool is_creatable() const { return 1; } + virtual bool must_be_loaded() const { return 0; } + virtual bool is_reset_on_load() const { return 0; } + virtual const char *image_interface() const { return NULL; } + virtual const char *file_extensions() const { return "tap"; } + virtual const option_guide *create_option_guide() const { return NULL; } + + virtual bool call_load(); + virtual void call_unload(); +protected: + // device-level overrides + virtual void device_config_complete(); + virtual void device_start(); +private: + int tape_get_id(); +}; + +const device_type TI990_TAPE = &device_creator; + +ti990_tape_image_device::ti990_tape_image_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, TI990_TAPE, "TI-990 Magnetic Tape", tag, owner, clock, "ti990_tape_image", __FILE__), + device_image_interface(mconfig, *this) +{ +} + +void ti990_tape_image_device::device_config_complete() +{ + update_names(); +} + +void ti990_tape_image_device::device_start() +{ + tap_990_device* tpc = downcast(owner()); + tpc->set_tape(tape_get_id(), this, true, false, false); +} + +int ti990_tape_image_device::tape_get_id() +{ + int drive =0; + if (strcmp(tag(), ":tape0") == 0) drive = 0; + if (strcmp(tag(), ":tape1") == 0) drive = 1; + if (strcmp(tag(), ":tape2") == 0) drive = 2; + if (strcmp(tag(), ":tape3") == 0) drive = 3; + return drive; +} + +/* + Open a tape image +*/ +bool ti990_tape_image_device::call_load() +{ + tap_990_device* tpc = downcast(owner()); + tpc->set_tape(tape_get_id(), this, true, false, is_readonly()); + + return IMAGE_INIT_PASS; +} + +/* + Close a tape image +*/ +void ti990_tape_image_device::call_unload() +{ + tap_990_device* tpc = downcast(owner()); + tpc->set_tape(tape_get_id(), this, false, false, true); +} + +#define MCFG_TI990_TAPE_ADD(_tag) \ + MCFG_DEVICE_ADD((_tag), TI990_TAPE, 0) + + +static MACHINE_CONFIG_FRAGMENT( tap_990 ) + MCFG_TI990_TAPE_ADD("tape0") + MCFG_TI990_TAPE_ADD("tape1") + MCFG_TI990_TAPE_ADD("tape2") + MCFG_TI990_TAPE_ADD("tape3") +MACHINE_CONFIG_END + +const device_type TI990_TAPE_CTRL = &device_creator; + +tap_990_device::tap_990_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, TI990_TAPE_CTRL, "Generic TI-990 Tape Controller", tag, owner, clock, "tap_990", __FILE__), + m_int_line(*this) +{ +} + +//------------------------------------------------- +// device_config_complete - perform any +// operations now that the configuration is +// complete +//------------------------------------------------- + +void tap_990_device::device_config_complete() +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void tap_990_device::device_start() +{ + m_int_line.resolve(); + memset(m_w, 0, sizeof(m_w)); + + // The PE bit is always set for the MT3200 (but not MT1600) + // According to MT3200 manual, w7 bit #4 (reserved) is always set + m_w[7] = w7_idle /*| w7_PE_format*/ | 0x0800; + + update_interrupt(); +} + +//------------------------------------------------- +// device_mconfig_additions - return a pointer to +// the device's machine fragment +//------------------------------------------------- + +machine_config_constructor tap_990_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( tap_990 ); +} diff --git a/src/devices/bus/ti99x/990_tap.h b/src/devices/bus/ti99x/990_tap.h new file mode 100644 index 00000000000..09e2e30da0a --- /dev/null +++ b/src/devices/bus/ti99x/990_tap.h @@ -0,0 +1,63 @@ +// license:GPL-2.0+ +// copyright-holders:Raphael Nabet +/* + 990_tap.h: include file for 990_tap.c +*/ + +extern const device_type TI990_TAPE_CTRL; +#define MAX_TAPE_UNIT 4 + +struct tape_unit_t +{ + device_image_interface *img; // image descriptor + bool bot; // TRUE if we are at the beginning of tape + bool eot; // TRUE if we are at the end of tape + bool wp; // TRUE if tape is write-protected +}; + +class tap_990_device : public device_t +{ +public: + tap_990_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + template static devcb_base &static_set_int_callback(device_t &device, _Object object) + { + return downcast(device).m_int_line.set_callback(object); + } + + DECLARE_READ16_MEMBER( read ); + DECLARE_WRITE16_MEMBER( write ); + + void set_tape(int id, device_image_interface *img, bool bot, bool eot, bool wp) + { + m_tape[id].img = img; + m_tape[id].bot = bot; + m_tape[id].eot = eot; + m_tape[id].wp = wp; + } + +protected: + // device-level overrides + virtual void device_config_complete(); + virtual void device_start(); + virtual machine_config_constructor device_mconfig_additions() const; + +private: + int cur_tape_unit(); + void update_interrupt(); + void cmd_read_binary_forward(); + void cmd_record_skip_forward(); + void cmd_record_skip_reverse(); + void cmd_rewind(); + void cmd_rewind_and_offline(); + void read_transport_status(); + void execute_command(); + + devcb_write_line m_int_line; + + UINT16 m_w[8]; + + tape_unit_t m_tape[MAX_TAPE_UNIT]; +}; + +#define MCFG_TI990_TAPE_INT_HANDLER( _intcallb ) \ + devcb = &tap_990_device::static_set_int_callback( *device, DEVCB_##_intcallb ); diff --git a/src/devices/bus/ti99x/998board.c b/src/devices/bus/ti99x/998board.c new file mode 100644 index 00000000000..987cac6de54 --- /dev/null +++ b/src/devices/bus/ti99x/998board.c @@ -0,0 +1,1076 @@ +// license:LGPL-2.1+ +// copyright-holders:Michael Zapf +/*************************************************************************** + + TI-99/8 main board logic + + This component implements the address decoder and mapper logic from the + TI-99/8 console. + + The TI-99/8 defines a "logical address map" with 64 KiB (according to the + 16 address bits) and a "physical address map" with 16 MiB (according to the + 24 address bits of the mapper). Note that the mapper only uses 16 outgoing + address lines and multiplexes the address bytes. + + Note: The TI-99/8's internal codename was "Armadillo" + +============================== + Mapper (codename "Amigo") +============================== + + Initial setting of mapper (as defined in the power-up routine, TI-99/4A mode) + + 0 00ff0000 -> Unmapped; logical address 0000...0fff = ROM0 + 1 00ff0000 -> Unmapped; logical address 1000...1fff = ROM0 + 2 00000800 -> DRAM; 2000 = 000800, 2fff = 0017ff + 3 00001800 -> DRAM; 3000 = 001800, 3fff = 0027ff + 4 00ff4000 -> DSR space (internal / ioport) + 5 00ff5000 -> DSR space (internal / ioport) + 6 00ff6000 -> Cartridge space (6000..6fff) + 7 00ff7000 -> Cartridge space (7000..7fff) + 8 00ff0000 -> Unmapped; device ports (VDP) and SRAM + 9 00ff0000 -> Unmapped; device ports (Speech, GROM) + A 00002800 -> DRAM; a000 = 002800, afff = 0037ff + B 00003800 -> DRAM; b000 = 003800, bfff = 0047ff + C 00004800 -> DRAM; c000 = 004800, cfff = 0057ff + D 00005800 -> DRAM; d000 = 005800, dfff = 0067ff + E 00006800 -> DRAM; e000 = 006800, efff = 0077ff + F 00007800 -> DRAM; f000 = 007800, ffff = 0087ff + + Format of map table entry (not emulated) + + +------+------+------+------+---+---+---+---------+----------+---------+ + | WProt| XProt| RProt| * | 0 | 0 | 0 | Upper | High | Low | + +------+------+------+------+---+---+---+---------+----------+---------+ + + WProt: Write protection if set to 1 + XProt: Execute protection if set to 1 + RProt: Read protection if set to 1 + + When a protection violation occurs, the tms9901 INT1* pin is pulled low + (active). The pin remains low until the mapper status register is read. + + Address handling + ---------------- + Physical address is (Upper * 2^16) + (High * 2^8) + Low + + The mapper calculates the actual physical address by looking up the + table entry from the first four bits of the logical address and then + *adding* the remaining 12 bits of the logical address on the map value. + + The value 0xff0000 is used to indicate a non-mapped area. + + Mapper control register + ----------------------- + The mapper control register is used to initiate a map load/save operation. + + +---+---+---+---+---+---+---+---+ + | 0 | 0 | 0 | 0 | Map File | RW| + +---+---+---+---+---+---+---+---+ + + The map file is a number from 0-7 indicating the set of map values for the + operation, which means the location in SRAM where the next 64 values are + loaded from or stored into. + + RW = 1: load from SRAM into mapper + RW = 0: store from mapper into SRAM + + When read, the mapper register returns the violation flags: + +------+------+------+---+---+---+---+---+ + | WProt| XProt| RProt| 0 | 0 | 0 | 0 | 0 | + +------+------+------+---+---+---+---+---+ + + Logical address space (LAS) + =========================== + The LAS is the address space as seen by the TMS 9995 CPU. It is 64 KiB large. + The LAS can be configured in two ways: + - the native (99/8) mode + - and the compatibility mode (99/4A) + + Both modes are selected by CRU bit 20 on base 0000 (named "CRUS"). + + The console starts up in compatibility mode. + + The compatibility mode organizes the LAS in a similar way as the TI-99/4A. + This means that machine language programs should run with no or only minor + changes. In particular, game cartridges work without problems. + + The native mode rearranges the address space and puts memory-mapped devices + to other positions. + + TI-99/4A compatibility mode (CRUS=1) + ------------------------------------ + 0000-1fff: 2 KiB ROM0 + 2000-7fff: Free area + 8000-87ff: 2 KiB SRAM + 8000-81ff: mapper files (8 files with 16*4 bytes each) + 8200-82ff: Free RAM + 8300-83ff: Scratch-pad RAM as in the 99/4A + 8400-840f: Sound chip + 8800-880f: VDP read port (data, status) + 8810-881f: Mapper access port + 8820-8bff: Free area + 8c00-8c0f: VDP write port (data, address) + 8c10-8fff: Free area + 9000-900f: Speech synthesizer read (on-board) + 9010-93ff: Free area + 9400-940f: Speech synthesizer write (on-board) + 9410-97ff: Free area + 9800-980f: System GROM read (data, address) + 9810-9bff: Free area + 9c00-9c0f: System GROM write (data, address) + 9c10-fffb: Free area + fffc-ffff: NMI vector + + TI-99/8 native mode (CRUS=0) + ---------------------------- + 0000-efff: Free area + f000-f7ff: 2 KiB SRAM + f000-f1ff: mapper files (8 files with 16*4 bytes each) + f200-f7ff: Free RAM + f800-f80f: Sound chip + f810-f81f: VDP read (data, status) and write (data, address) + f820-f82f: Speech synthesizer read/write + f830-f83f: System GROM read/write + f840-f86f: Free area + f870-f87f: Mapper access port + f880-fffb: Free area + fffc-ffff: NMI vector + + Note that ROM0 is not visible in the native mode. + + If CRU bit 21 (PTGEN*) is set to 0, Pascal GROMs appear in the LAS in either + mode. It is highly recommended to use native mode when turning on these + GROMs, because the area where they appear may be occupied by a program in + 99/4A mode. + + Pascal and Text-to-speech GROM enabled (PTGEN*=0) + ------------------------------------------------- + f840-f84f: Text-to-speech GROM read/write + f850-f85f: P-Code library #1 GROM read/write + f860-f86f: P-Code library #2 GROM read/write + + Physical address space (PAS) + ============================ + The PAS is 24 bits wide and accessed via the custom mapper chip nicknamed + "Amigo". The mapper exchanges map definitions with SRAM (see LAS). That + means, a map can be prepared in SRAM, and for activating it, the mapper + is accessed on its port, telling it to load or save a map. + + 000000-00ffff: 64 KiB console DRAM + 010000-efffff: undefined + f00000-f03fff: P-Code ROM (not mentioned in [1]) + f04000-feffff: undefined + ff0000 : unmapped (code for mapper) + ff0001-ff3fff: undefined + ff4000-ff5fff: DSR ROM in Peripheral Box, Hexbus DSR (CRU 1700) or additional ROM (CRU 2700) + ff6000-ff9fff: Cartridge ROM space + ffa000-ffdfff: 16 KiB ROM1 + ffe000-ffe00f: Interrupt level sense + ffe010-ffffff: undefined + + + CRU map (I/O address space) + =========================== + 0000-003e: TMS9901 system interface (see ti99_8.c) + 1700-17fe: Hexbus + 2000-26fe: Future external devices + 2700-27fe: Additional ROM ("internal DSR") + 2702: System reset (when set to 1) + 2800-3ffe: Future external devices + 4000-fffe: Future external devices + + The TMS9995 offers the full 15-bit CRU address space. Devices designed for + the TI-99/4A should only be accessed in the area 1000-1ffe. They will (by + design) incompletely decode the CRU address and be mirrored in the higher areas. + + Michael Zapf, October 2010 + February 2012: Rewritten as class + + Informations taken from + [1] ARMADILLO PRODUCT SPECIFICATIONS + [2] TI-99/8 Graphics Programming Language interpreter + +***************************************************************************/ + +#include "998board.h" + +#define TRACE_CRU 0 +#define TRACE_MEM 0 +#define TRACE_MAP 0 +#define TRACE_CONFIG 0 +#define TRACE_OSO 0 +#define TRACE_SPEECH 0 +#define TRACE_DETAIL 0 + +mainboard8_device::mainboard8_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : bus8z_device(mconfig, MAINBOARD8, "TI-99/8 Main board", tag, owner, clock, "ti998_mainboard", __FILE__), + m_ready(*this), + m_oso(*this, OSO_TAG) + { } + +/*************************************************************************** + CRU access +***************************************************************************/ + +#define HEXBUS_CRU_BASE 0x1700 +#define MAPPER_CRU_BASE 0x2700 + +READ8Z_MEMBER(mainboard8_device::crureadz) +{ + if (TRACE_CRU) logerror("%s: read CRU %04x ignored\n", tag(), offset); + // Nothing here. +} + +/* + CRU handling. We handle the internal device at CRU address 0x2700 via + this mapper component. +*/ +WRITE8_MEMBER(mainboard8_device::cruwrite) +{ + if ((offset & 0xff00)==MAPPER_CRU_BASE) + { + int bit = (offset & 0xff)>>1; + switch (bit) + { + case 0: + // Turn on/off the internal DSR + m_dsr_selected = (data!=0); + if (TRACE_CRU) logerror("%s: DSR select = %d\n", tag(), data); + break; + case 1: + if (TRACE_CRU) logerror("%s: System reset by CRU request\n", tag()); + machine().schedule_soft_reset(); + break; + } + return; + } + + if ((offset & 0xff00)==HEXBUS_CRU_BASE) + { + int bit = (offset & 0xff)>>1; + switch (bit) + { + case 0: + // Turn on/off the Hexbus DSR + m_hexbus_selected = (data!=0); + if (TRACE_CRU) logerror("%s: Hexbus select = %d\n", tag(), data); + break; + default: + if (TRACE_CRU) logerror("%s: Set CRU>%04x (Hexbus) to %d\n", tag(), offset,data); + break; + } + return; + } + + if ((offset & 0xff00)>=0x0100) + { + if (TRACE_CRU) logerror("%s: Set CRU>%04x (unknown) to %d\n", tag(), offset,data); + return; + } +} + +void mainboard8_device::CRUS_set(bool state) +{ + if (TRACE_CRU) logerror("%s: set CRUS=%d\n", tag(), state); + m_CRUS = state; +} + +/* + Note that PTGEN is negative logic. We invert these semantics here. +*/ +void mainboard8_device::PTGE_set(bool state) +{ + if (TRACE_CRU) logerror("%s: set PTGEN=%d\n", tag(), state? 1:0); + m_PTGE = state; +} + +/*************************************************************************** + Access by address map +***************************************************************************/ + +/* + This method is called via the address map. +*/ +READ8_MEMBER( mainboard8_device::readm ) +{ + UINT8 value = 0; + bool found = false; + if (TRACE_MEM) logerror("%s: read from %04x\n", tag(), offset); + found = access_logical_r(space, offset, &value, mem_mask); + m_waitcount = 2; + + if (!found) + { + // In that case, the address decoder could not find a suitable device. + // This means the logical address is transformed by the mapper. + // NOTE: Use "+", not OR. The offset is not a prefix. + UINT32 pas_address = m_pas_offset[(offset & 0xf000)>>12] + (offset & 0xfff); + + // So now let's do the same as above with physical addresses + access_physical_r(space, pas_address, &value, mem_mask); + + // The PAS area requires one more wait state, as the address bus + // is multiplexed + m_waitcount = 3; + } + + // Insert wait states and let CPU enter wait state + m_ready(CLEAR_LINE); + + return value; +} + +WRITE8_MEMBER( mainboard8_device::writem ) +{ + bool found = false; + + // Look for components responding to the logical address + found = access_logical_w(space, offset, data, mem_mask); + m_waitcount = 2; + + if (!found) + { + // In that case, the address decoder could not find a suitable device. + // This means the logical address is transformed by the mapper. + // NOTE: Use "+", not OR. The offset is not a prefix. + UINT32 pas_address = m_pas_offset[(offset & 0xf000)>>12] + (offset & 0xfff); + + // So now let's do the same as above with physical addresses + access_physical_w(space, pas_address, data, mem_mask); + + // The PAS area requires one more wait state, as the address bus + // is multiplexed + m_waitcount = 3; + } + + // Insert wait states and let CPU enter wait state + m_ready(CLEAR_LINE); +} + +/*************************************************************************** + Indirect calls (mapper calls itself) +***************************************************************************/ +/* + This method is called by the mapper itself for + f870 (NATIVE): mapper: ignore + 8810 (TI99EM): mapper: ignore + ff4000 (PHYSIC): DSR +*/ +READ8Z_MEMBER( mainboard8_device::readz ) +{ + if ((offset & 0xffe000)==0xff4000) + { + if (m_dsr_selected) + { + // Starts at 0x4000 in the image + *value = m_rom1[0x4000 | (offset & 0x1fff)]; + if (TRACE_MEM) logerror("%s: (intDSR) %04x -> %02x\n", tag(), offset, *value); + } + else + { + if (m_hexbus_selected) + { + if ((offset & 0x1ff0)==0x1ff0) + { + *value = m_oso->read(space, (offset>>1) & 0x0003); + } + else + { + // Starts at 0x6000 in the image + *value = m_rom1[0x6000 | (offset & 0x1fff)]; + if (TRACE_MEM) logerror("%s: (HexDSR) %04x -> %02x\n", tag(), offset, *value); + } + } + } + } + else + { + if (((offset & 0xfff0)==0xf870 && m_CRUS==false)||(((offset & 0xfff0)==0x8810 && m_CRUS==true))) + { + if (TRACE_MEM) logerror("%s: read access to mapper ignored: %04x\n", tag(), offset); + } + } +} + +/* + This method is called by the mapper itself for + ff4000 (PHYSIC): DSR. ignore + +*/ +WRITE8_MEMBER( mainboard8_device::write ) +{ + if ((offset & 0xffe000)==0xff4000) + { + if (m_hexbus_selected) + { + if ((offset & 0x1ff0)==0x1ff0) + { + m_oso->write(space, (offset>>1) & 0x0003, data); + } + else + { + logerror("%s: Write access to Hexbus DSR address %06x ignored\n", tag(), offset); + } + } + else + { + if (m_dsr_selected) + { + logerror("%s: Write access to internal DSR address %06x ignored\n", tag(), offset); + } + else + { + logerror("%s: Write access to unmapped DSR space at address %06x ignored\n", tag(), offset); + } + } + } + else + { + if (((offset & 0xfff0)==0xf870 && m_CRUS==false)||(((offset & 0xfff0)==0x8810 && m_CRUS==true))) + { + mapwrite(offset, data); + } + } +} + +/* + Reconfigure mapper. Writing to this address copies the values in the + SRAM into the mapper and vice versa. + Format: + 0000 bbbl; bbb=bank, l=load + + TODO: Emulate properly, making use of HOLD +*/ +void mainboard8_device::mapwrite(int offset, UINT8 data) +{ + if ((data & 0xf0)==0x00) + { + int bankindx = (data & 0x0e)>>1; + if (data & 1) + { + if (TRACE_MAP) logerror("%s: load mapper from SRAM, bank %d\n", tag(), bankindx); + // Load from SRAM + // In reality the CPU is put on HOLD during this transfer + for (int i=0; i < 16; i++) + { + int ptr = (bankindx << 6); + m_pas_offset[i] = (m_sram[(i<<2) + ptr] << 24) | (m_sram[(i<<2)+ ptr+1] << 16) + | (m_sram[(i<<2) + ptr+2] << 8) | (m_sram[(i<<2) + ptr+3]); + if (TRACE_MAP) logerror("%s: load %d=%08x\n", tag(), i, m_pas_offset[i]); + } + } + else + { + if (TRACE_MAP) logerror("%s: store mapper to SRAM, bank %d\n", tag(), bankindx); + // Store in SRAM + for (int i=0; i < 16; i++) + { + int ptr = (bankindx << 6); + m_sram[(i<<2) + ptr] = (m_pas_offset[i] >> 24)& 0xff; + m_sram[(i<<2) + ptr +1] = (m_pas_offset[i] >> 16)& 0xff; + m_sram[(i<<2) + ptr +2] = (m_pas_offset[i] >> 8)& 0xff; + m_sram[(i<<2) + ptr +3] = (m_pas_offset[i])& 0xff; + if (TRACE_MAP) logerror("%s: save %d=%08x\n", tag(), i, m_pas_offset[i]); + } + } + } +} + +/*************************************************************************** + Lookup methods. +***************************************************************************/ + +bool mainboard8_device::access_logical_r(address_space& space, offs_t offset, UINT8 *value, UINT8 mem_mask ) +{ + bool found = false; + logically_addressed_device *ldev = m_logcomp.first(); + bus8z_device *bdev = NULL; + + if (TRACE_MEM) logerror("%s: offset=%04x; CRUS=%d, PTGEN=%d\n", tag(), offset, m_CRUS? 1:0, m_PTGE? 0:1); + while (ldev != NULL) + { + if (TRACE_MEM) logerror("%s: checking node=%s\n", tag(), ldev->m_config->name); + // Check the mode + if (((ldev->m_config->mode == NATIVE) && (m_CRUS==false)) + || ((ldev->m_config->mode == TI99EM) && (m_CRUS==true)) + || ((ldev->m_config->mode == PATGEN) && (m_PTGE==true))) + { + if ((offset & ldev->m_config->address_mask)==ldev->m_config->select_pattern) + { + switch (ldev->m_kind) + { + case MAP8_SRAM: + *value = m_sram[offset & ~ldev->m_config->address_mask]; + if (TRACE_MEM) logerror("%s: (SRAM) %04x -> %02x\n", tag(), offset, *value); + break; + case MAP8_ROM0: + // Starts at 0000 + *value = m_rom0[offset & ~ldev->m_config->address_mask]; + if (TRACE_MEM) logerror("%s: (ROM0) %04x -> %02x\n", tag(), offset, *value); + break; + case MAP8_DEV: + // device + bdev = static_cast(ldev->m_device); + bdev->readz(space, offset, value, mem_mask); + if (TRACE_MEM) logerror("%s: (dev %s) %04x -> %02x\n", tag(), ldev->m_config->name, offset, *value); + break; + default: + if (TRACE_MEM) logerror("%s: Invalid kind for read access: %d\n", tag(), ldev->m_kind); + } + found = true; + if (ldev->m_config->stop==STOP) break; + } + } + ldev = ldev->m_next; + } + return found; +} + +bool mainboard8_device::access_logical_w(address_space& space, offs_t offset, UINT8 data, UINT8 mem_mask ) +{ + bool found = false; + logically_addressed_device *ldev = m_logcomp.first(); + bus8z_device *bdev = NULL; + + while (ldev != NULL) + { + // Check the mode + if (((ldev->m_config->mode == NATIVE) && (m_CRUS==false)) + || ((ldev->m_config->mode == TI99EM) && (m_CRUS==true)) + || ((ldev->m_config->mode == PATGEN) && (m_PTGE==true))) + { + if ((offset & ldev->m_config->address_mask)==(ldev->m_config->select_pattern | ldev->m_config->write_select)) + { + switch (ldev->m_kind) + { + case MAP8_SRAM: + m_sram[offset & ~ldev->m_config->address_mask] = data; + if (TRACE_MEM) logerror("%s: (SRAM) %04x <- %02x\n", tag(), offset, data); + break; + case MAP8_ROM0: + if (TRACE_MEM) logerror("%s: (ROM0) %04x <- %02x (ignored)\n", tag(), offset, data); + break; + case MAP8_DEV: + // device + bdev = static_cast(ldev->m_device); + bdev->write(space, offset, data, mem_mask); + if (TRACE_MEM) logerror("%s: (dev %s) %04x <- %02x\n", tag(), ldev->m_config->name, offset, data); + break; + default: + if (TRACE_MEM) logerror("%s: Invalid kind for write access: %d\n", tag(), ldev->m_kind); + } + found = true; + if (ldev->m_config->stop==STOP) break; + } + } + ldev = ldev->m_next; + } + return found; +} + + +void mainboard8_device::access_physical_r( address_space& space, offs_t pas_address, UINT8 *value, UINT8 mem_mask ) +{ + physically_addressed_device *pdev = m_physcomp.first(); + bus8z_device *bdev = NULL; + + while (pdev != NULL) + { + if ((pas_address & pdev->m_config->address_mask)==pdev->m_config->select_pattern) + { + switch (pdev->m_kind) + { + case MAP8_DRAM: + *value = m_dram[pas_address & ~pdev->m_config->address_mask]; + if (TRACE_MEM) logerror("%s: (DRAM) %06x -> %02x\n", tag(), pas_address, *value); + break; + case MAP8_ROM1A0: + // Starts at 0000 in the image, 8K + *value = m_rom1[pas_address & 0x1fff]; + if (TRACE_MEM) logerror("%s: (ROM) %06x -> %02x\n", tag(), pas_address, *value); + break; + case MAP8_ROM1C0: + // Starts at 2000 in the image, 8K + *value = m_rom1[0x2000 | (pas_address & 0x1fff)]; + if (TRACE_MEM) logerror("%s: (ROM) %06x -> %02x\n", tag(), pas_address, *value); + break; + case MAP8_PCODE: + *value = m_pcode[pas_address & 0x3fff]; + if (TRACE_MEM) logerror("%s: (PCODE) %06x -> %02x\n", tag(), pas_address, *value); + break; + case MAP8_INTS: + // Interrupt sense + logerror("%s: ILSENSE not implemented.\n", tag()); + break; + case MAP8_DEV: + // devices + bdev = static_cast(pdev->m_device); + bdev->readz(space, pas_address, value, mem_mask); + if (TRACE_MEM) logerror("%s: (dev %s) %06x -> %02x\n", tag(), pdev->m_config->name, pas_address, *value); + break; + default: + logerror("%s: Invalid kind for physical read access: %d\n", tag(), pdev->m_kind); + } + if (pdev->m_config->stop==STOP) break; + } + pdev = pdev->m_next; + } +} + +void mainboard8_device::access_physical_w( address_space& space, offs_t pas_address, UINT8 data, UINT8 mem_mask ) +{ + physically_addressed_device *pdev = m_physcomp.first(); + bus8z_device *bdev = NULL; + + while (pdev != NULL) + { + if ((pas_address & pdev->m_config->address_mask)==(pdev->m_config->select_pattern | pdev->m_config->write_select)) + { + switch (pdev->m_kind) + { + case MAP8_DRAM: + m_dram[pas_address & ~pdev->m_config->address_mask] = data; + if (TRACE_MEM) logerror("%s: (DRAM) %06x <- %02x\n", tag(), pas_address, data); + break; + case MAP8_ROM1A0: + case MAP8_ROM1C0: + if (TRACE_MEM) logerror("%s: (ROM1) %06x <- %02x (ignored)\n", tag(), pas_address, data); + break; + case MAP8_PCODE: + if (TRACE_MEM) logerror("%s: (PCODE) %06x <- %02x (ignored)\n", tag(), pas_address, data); + break; + case MAP8_INTS: + // Interrupt sense + logerror("%s: write to ilsense ignored\n", tag()); + break; + case MAP8_DEV: + // devices + bdev = static_cast(pdev->m_device); + if (TRACE_MEM) logerror("%s: (dev %s) %06x <- %02x\n", tag(), pdev->m_config->name, pas_address, data); + bdev->write(space, pas_address, data, mem_mask); + break; + default: + logerror("%s: Invalid kind for physical write access: %d\n", tag(), pdev->m_kind); + } + if (pdev->m_config->stop==STOP) break; + } + pdev = pdev->m_next; + } +} + +/* + The mapper is connected to the clock line in order to operate + the wait state counter. +*/ +void mainboard8_device::clock_in(int clock) +{ + if (clock==ASSERT_LINE && m_waitcount!=0) + { + m_waitcount--; + if (m_waitcount==0) m_ready(ASSERT_LINE); + } +} + + +/*************************************************************************** + DEVICE LIFECYCLE FUNCTIONS +***************************************************************************/ +/* + We need to do all of the configuration in device_start since we don't have all + required links earlier. + + Note that device_reset is too late; the initial context switch occurs earlier. +*/ +void mainboard8_device::device_start() +{ + logerror("%s: Starting mapper\n", tag()); + + // String values of the pseudo constants, used in the configuration. + const char *const pseudodev[7] = { SRAMNAME, ROM0NAME, ROM1A0NAME, ROM1C0NAME, DRAMNAME, PCODENAME, INTSNAME }; + + const mapper8_config *conf = reinterpret_cast(static_config()); + + const mapper8_list_entry *entry = conf->devlist; + m_ready.resolve_safe(); + + m_sram = machine().root_device().memregion(SRAM_TAG)->base(); + m_dram = machine().root_device().memregion(DRAM_TAG)->base(); + m_rom0 = machine().root_device().memregion(ROM0_TAG)->base(); + m_rom1 = machine().root_device().memregion(ROM1_TAG)->base(); + m_pcode = machine().root_device().memregion(PCODEROM_TAG)->base(); + + // Clear the lists + m_logcomp.reset(); + m_physcomp.reset(); + + // Now building the list of active devices at this mapper. + // Coyping partly from datamux.c. + if ( entry != NULL ) + { + bool done = false; + for (int i=0; !done; i++) + { + if (entry[i].name == NULL) + { + done = true; + } + else + { + device_t *dev = NULL; + mapper8_device_kind kind = MAP8_UNDEF; + + for (int j=1; (j < 8) && (kind == MAP8_UNDEF); j++) + { + // Pseudo devices are enumerated as 1 ... 6 (see MAP8_SRAM etc.) + if (strcmp(entry[i].name, pseudodev[j-1])==0) kind = (mapper8_device_kind)j; + } + if (kind==MAP8_UNDEF) + { + // This entry points to a "real" device, not to a special constant + kind = MAP8_DEV; + dev = machine().device(entry[i].name); + } + if (kind != MAP8_DEV || dev != NULL) + { + if (entry[i].mode != PHYSIC) + { + logically_addressed_device *ad = new logically_addressed_device(kind, (device_t*)dev, entry[i]); + m_logcomp.append(*ad); + if (TRACE_CONFIG) logerror("%s: Device %s mounted into logical address space.\n", tag(), entry[i].name); + } + else + { + physically_addressed_device *ad = new physically_addressed_device(kind, (device_t*)dev, entry[i]); + m_physcomp.append(*ad); + if (TRACE_CONFIG) logerror("%s: Device %s mounted into physical address space.\n", tag(), entry[i].name); + } + } + else + { + if (TRACE_CONFIG) logerror("%s: Device %s not found.\n", tag(), entry[i].name); + } + } + } + } + if (TRACE_CONFIG) logerror("%s: Mapper logical device count = %d\n", tag(), m_logcomp.count()); + if (TRACE_CONFIG) logerror("%s: Mapper physical device count = %d\n", tag(), m_physcomp.count()); + + m_dsr_selected = false; + m_CRUS = true; + m_PTGE = false; + + // Clean mapper + for (int i=0; i < 16; i++) m_pas_offset[i] = 0; +} + +void mainboard8_device::device_reset() +{ + m_dsr_selected = false; + m_CRUS = true; + m_PTGE = false; + m_waitcount = 0; + m_hexbus_selected = false; + + // Clean mapper + for (int i=0; i < 16; i++) m_pas_offset[i] = 0; + + m_ready(ASSERT_LINE); +} + +MACHINE_CONFIG_FRAGMENT( ti998_mainboard ) + MCFG_DEVICE_ADD(OSO_TAG, OSO, 0) +MACHINE_CONFIG_END + +machine_config_constructor mainboard8_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( ti998_mainboard ); +} + +const device_type MAINBOARD8 = &device_creator; + +/*************************************************************************** + + Custom chips of the TI-99/8 + + ===== OSO: Hexbus interface ===== + + The Hexbus is a 4-bit peripheral bus with master/slave coordination. Bytes + are written over the bus in two passes. Hexbus was the designated standard + peripheral bus for TI computers before TI left the home computer market. + + Existing devices are floppy drive, RS232 serial adapter, and + a "Wafertape" drive (kind of tape streamer) + + Registers: Read Write Bits of register + ---------------------------------------------------------------------------- + Data : 5FF8 - ADB3 ADB2 ADB1 ADB0 ADB3 ADB2 ADB1 ADB0 + Status : 5FFA - HSKWT HSKRD BAVIAS BAVAIS SBAV WBUSY RBUSY SHSK + Control : 5FFC 5FFA WIEN RIEN BAVIAEN BAVAIEN BAVC WEN REN CR7 + Xmit : 5FFE 5FF8 XDR0 XDR1 XDR2 XDR3 XDR4 XDR5 XDR6 XDR7 + + ADBx = Hexbus data bit X + HSKWT = Set when a byte has been sent over the bus and HSK has been asserted + HSKRD = Set when a byte has been received + BAVIAS = set when the BAV* signal (bus available) transits to active state + BAVAIS = set when the BAV* signal transits to inactive state (=1) + SBAV = set when BAV* = 0 (active) + WBUSY = set when a write action is in progress (two transfers @ 4 bits) + Reset when HSKWT is set + RBUSY = set when a read action is in progress (two transfers @ 4 bits) + Reset when HSKRD is set + SHSK = set when HSK* is active (0) + + WIEN = Enable interrupt for write completion + RIEN = Enable interrupt for read completion + BAVIAEN = BAVIA enable (slave mode) + BAVAIEN = BAVAI enable (slave mode) + BAVC = set BAV* line (0=active) + WEN = set write enable (byte is written from xmit reg) + REN = set read enable (latch HSK and read byte into data reg) + CR7 = future extension + XDRx = transmit register bit + + Hexbus connector (console) + +---+---+---+---+ + | 4 | 3 | 2 | 1 | 4 = L; 3 = BAV*; 2 = ADB1; 1 = ADB0 + +---+---+---+---+ + | 8 | 7 | 6 | 5 | 8 = ADB3; 7 = ADB2; 6 = nc; 5 = HSK* + +---+---+---+---+ + + TODO: This is just a preliminary implementation to satisfy the operating + system. When completed we can hopefully emulate a Hexbus floppy and + use it in Extended Basic II which refuses to work with the PEB cards. + The Hexbus should then be designed as a slot device. + +****************************************************************************/ + +/* Status register bits */ +enum +{ + HSKWT = 0x80, + HSKRD = 0x40, + BAVIAS = 0x20, + BAVAIS = 0x10, + SBAV = 0x08, + WBUSY = 0x04, + RBUSY = 0x02, + SHSK = 0x01 +}; + +ti998_oso_device::ti998_oso_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) +: device_t(mconfig, OSO, "OSO Hexbus interface", tag, owner, clock, "ti998_oso", __FILE__) +{ +} + +READ8_MEMBER( ti998_oso_device::read ) +{ + int value = 0; + offset &= 0x03; + switch (offset) + { + case 0: + // read 5FF8: read data register + if (TRACE_OSO) logerror("%s: Read data register = %02x\n", tag(), value); + value = m_data; + break; + case 1: + // read 5FFA: read status register + value = m_status; + if (TRACE_OSO) logerror("%s: Read status %02x\n", tag(), value); + break; + case 2: + // read 5FFC: read control register + value = m_control; + if (TRACE_OSO) logerror("%s: Read control register = %02x\n", tag(), value); + break; + case 3: + // read 5FFE: read transmit register + value = m_xmit; + if (TRACE_OSO) logerror("%s: Read transmit register = %02x\n", tag(), value); + break; + } + return value; +} + +WRITE8_MEMBER( ti998_oso_device::write ) +{ + offset &= 0x03; + switch (offset) + { + case 0: + // write 5FF8: write transmit register + if (TRACE_OSO) logerror("%s: Write transmit register %02x\n", tag(), data); + m_xmit = data; + // We set the status register directly in order to prevent lock-ups + // until we have a complete Hexbus implementation + m_status |= HSKWT; + break; + case 1: + // write 5FFA: write control register + if (TRACE_OSO) logerror("%s: Write control register %02x\n", tag(), data); + m_control = data; + break; + default: + // write 5FFC, 5FFE: undefined + if (TRACE_OSO) logerror("%s: Invalid write on %04x: %02x\n", tag(), (offset<<1) | 0x5ff0, data); + break; + } +} + +void ti998_oso_device::device_start() +{ + m_status = m_xmit = m_control = m_data = 0; +} + +const device_type OSO = &device_creator; + + +// ======================================================================== + +/**************************************************************************** + + TI-99/8 Speech synthesizer subsystem + + The TI-99/8 contains a speech synthesizer inside the console, so we cannot + reuse the spchsyn implementation of the P-Box speech synthesizer. + Accordingly, this is not a ti_expansion_card_device. + + For comments on real timing see ti99/spchsyn.c + + Note that before the REAL_TIMING can be used we must first establish + the set_address logic in 998board. + +*****************************************************************************/ + +#define TMS5220_ADDRESS_MASK 0x3FFFFUL /* 18-bit mask for tms5220 address */ +#define SPEECHSYN_TAG "speechsyn" +#define REAL_TIMING 0 + +ti998_spsyn_device::ti998_spsyn_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) +: bus8z_device(mconfig, SPEECH8, "TI-99/8 Onboard Speech synthesizer", tag, owner, clock, "ti998_speech", __FILE__), + m_ready(*this) +{ +} + +/* + Memory read +*/ +#if REAL_TIMING +// ====== This is the version with real timing ======= +READ8Z_MEMBER( ti998_spsyn_device::readz ) +{ + m_vsp->wsq_w(TRUE); + m_vsp->rsq_w(FALSE); + *value = m_vsp->read(offset) & 0xff; + if (TRACE_SPEECH) logerror("%s: read value = %02x\n", tag(), *value); +} + +/* + Memory write +*/ +WRITE8_MEMBER( ti998_spsyn_device::write ) +{ + m_vsp->rsq_w(m_vsp, TRUE); + m_vsp->wsq_w(m_vsp, FALSE); + if (TRACE_SPEECH) logerror("%s: write value = %02x\n", tag(), data); + m_vsp->write(offset, data); +} + +#else +// ====== This is the version without real timing ======= + +READ8Z_MEMBER( ti998_spsyn_device::readz ) +{ + machine().device("maincpu")->execute().adjust_icount(-(18+3)); /* this is just a minimum, it can be more */ + *value = m_vsp->status_r(space, offset, 0xff) & 0xff; + if (TRACE_SPEECH) logerror("%s: read value = %02x\n", tag(), *value); +} + +/* + Memory write +*/ +WRITE8_MEMBER( ti998_spsyn_device::write ) +{ + machine().device("maincpu")->execute().adjust_icount(-(54+3)); /* this is just an approx. minimum, it can be much more */ + + /* RN: the stupid design of the tms5220 core means that ready is cleared */ + /* when there are 15 bytes in FIFO. It should be 16. Of course, if */ + /* it were the case, we would need to store the value on the bus, */ + /* which would be more complex. */ + if (!m_vsp->readyq_r()) + { + attotime time_to_ready = attotime::from_double(m_vsp->time_to_ready()); + int cycles_to_ready = machine().device("maincpu")->attotime_to_cycles(time_to_ready); + if (TRACE_SPEECH && TRACE_DETAIL) logerror("%s: time to ready: %f -> %d\n", tag(), time_to_ready.as_double(), (int) cycles_to_ready); + + machine().device("maincpu")->execute().adjust_icount(-cycles_to_ready); + machine().scheduler().timer_set(attotime::zero, FUNC_NULL); + } + if (TRACE_SPEECH) logerror("%s: write value = %02x\n", tag(), data); + m_vsp->data_w(space, offset, data); +} +#endif + +/**************************************************************************/ + +WRITE_LINE_MEMBER( ti998_spsyn_device::speech8_ready ) +{ + // The TMS5200 implementation uses TRUE/FALSE, not ASSERT/CLEAR semantics + m_ready((state==0)? ASSERT_LINE : CLEAR_LINE); + if (TRACE_SPEECH) logerror("%s: READY = %d\n", tag(), (state==0)); + +#if REAL_TIMING + // Need to do that here (see explanations in spchsyn.c) + if (state==0) + { + m_vsp->rsq_w(TRUE); + m_vsp->wsq_w(TRUE); + } +#endif +} + +void ti998_spsyn_device::device_start() +{ + m_ready.resolve_safe(); + m_vsp = subdevice(SPEECHSYN_TAG); + speechrom_device* mem = subdevice("vsm"); + mem->set_reverse_bit_order(true); +} + +void ti998_spsyn_device::device_reset() +{ + if (TRACE_SPEECH) logerror("%s: reset\n", tag()); +} + +// Unlike the TI-99/4A, the 99/8 uses the CD2501ECD +// The CD2501ECD is a tms5200/cd2501e with the rate control from the tms5220c added in. +// (it's probably actually a tms5220c die with the cd2501e/tms5200 lpc rom masked onto it) +MACHINE_CONFIG_FRAGMENT( ti998_speech ) + MCFG_DEVICE_ADD("vsm", SPEECHROM, 0) + + MCFG_SPEAKER_STANDARD_MONO("mono") + MCFG_SOUND_ADD(SPEECHSYN_TAG, CD2501ECD, 640000L) + MCFG_TMS52XX_READYQ_HANDLER(WRITELINE(ti998_spsyn_device, speech8_ready)) + MCFG_TMS52XX_SPEECHROM("vsm") + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.50) +MACHINE_CONFIG_END + +/* Verified on a real machine: TI-99/8 uses the same speech rom contents + as the TI speech synthesizer. */ +ROM_START( ti998_speech ) + ROM_REGION(0x8000, "vsm", 0) + ROM_LOAD("cd2325a.vsm", 0x0000, 0x4000, CRC(1f58b571) SHA1(0ef4f178716b575a1c0c970c56af8a8d97561ffe)) + ROM_LOAD("cd2326a.vsm", 0x4000, 0x4000, CRC(65d00401) SHA1(a367242c2c96cebf0e2bf21862f3f6734b2b3020)) +ROM_END + +machine_config_constructor ti998_spsyn_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( ti998_speech ); +} + +const rom_entry *ti998_spsyn_device::device_rom_region() const +{ + return ROM_NAME( ti998_speech ); +} +const device_type SPEECH8 = &device_creator; diff --git a/src/devices/bus/ti99x/998board.h b/src/devices/bus/ti99x/998board.h new file mode 100644 index 00000000000..87332491b97 --- /dev/null +++ b/src/devices/bus/ti99x/998board.h @@ -0,0 +1,278 @@ +// license:LGPL-2.1+ +// copyright-holders:Michael Zapf +/**************************************************************************** + + TI-99/8 main board logic + + This component implements the address decoder and mapper logic from the + TI-99/8 console. + + See 998board.c for documentation + + Michael Zapf + +*****************************************************************************/ + +#ifndef __MAPPER8__ +#define __MAPPER8__ + +#include "emu.h" +#include "ti99defs.h" +#include "sound/tms5220.h" + +extern const device_type MAINBOARD8; +extern const device_type OSO; +extern const device_type SPEECH8; + +#define OSO_TAG "oso" +#define SPEECHSYN_TAG "speechsyn" + +#define NATIVE 0 +#define TI99EM 1 +#define PATGEN 2 +#define PHYSIC 3 +#define CONT 0 +#define STOP 1 + +#define SRAMNAME "SRAM" +#define ROM0NAME "ROM0" +#define ROM1A0NAME "ROM1A" +#define ROM1C0NAME "ROM1C" +#define INTSNAME "INTS" +#define DRAMNAME "DRAM" +#define PCODENAME "PCODE" + +#define SRAM_SIZE 2048 +#define DRAM_SIZE 65536 + +// We use these constants in the read/write functions. +enum mapper8_device_kind +{ + MAP8_UNDEF = 0, + MAP8_SRAM, + MAP8_ROM0, + MAP8_ROM1A0, + MAP8_ROM1C0, + MAP8_DRAM, + MAP8_PCODE, + MAP8_INTS, + MAP8_DEV // device by name +}; + +struct mapper8_list_entry +{ + const char* name; // Name of the device (used for looking up the device) + int mode; // Mode of the system which applies to this entry + int stop; // Mapper shall stop searching for a matching device when this entry applies + UINT32 select_pattern; // State of the address line bits when addressing this device + UINT32 address_mask; // Bits of the address bus used to address this device + UINT32 write_select; // Additional bits set when doing write accesses to this device +}; + +#define MAPPER8_CONFIG(name) \ + const mapper8_config(name) = + +#define MCFG_MAINBOARD8_READY_CALLBACK(_write) \ + devcb = &mainboard8_device::set_ready_wr_callback(*device, DEVCB_##_write); + +struct mapper8_config +{ + const mapper8_list_entry *devlist; +}; + +/* + Device list of the mapper. +*/ +class logically_addressed_device +{ + friend class simple_list; + friend class mainboard8_device; + +public: + logically_addressed_device(mapper8_device_kind kind, device_t *busdevice, const mapper8_list_entry &entry) + : m_kind(kind), m_device(busdevice), m_config(&entry) { }; + +private: + logically_addressed_device *m_next; // needed for simple_list + mapper8_device_kind m_kind; // named device or predefined + device_t *m_device; // the actual device + const mapper8_list_entry *m_config; +}; + +/* + Device list of the mapper. +*/ +class physically_addressed_device +{ + friend class simple_list; + friend class mainboard8_device; + +public: + physically_addressed_device(mapper8_device_kind kind, device_t *busdevice, const mapper8_list_entry &entry) + : m_kind(kind), m_device(busdevice), m_config(&entry) { }; + +private: + physically_addressed_device *m_next; // needed for simple_list + mapper8_device_kind m_kind; // named device or predefined + device_t *m_device; // the actual device + const mapper8_list_entry *m_config; +}; + +/* + Custom chip: OSO +*/ +class ti998_oso_device : public device_t +{ +public: + ti998_oso_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + DECLARE_READ8_MEMBER( read ); + DECLARE_WRITE8_MEMBER( write ); + void device_start(); + +private: + UINT8 m_data; + UINT8 m_status; + UINT8 m_control; + UINT8 m_xmit; +}; + +/* + Speech support +*/ +#define MCFG_SPEECH8_READY_CALLBACK(_write) \ + devcb = &ti998_spsyn_device::set_ready_wr_callback(*device, DEVCB_##_write); + +class ti998_spsyn_device : public bus8z_device +{ +public: + ti998_spsyn_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + template static devcb_base &set_ready_wr_callback(device_t &device, _Object object) { return downcast(device).m_ready.set_callback(object); } + + DECLARE_READ8Z_MEMBER(readz); + DECLARE_WRITE8_MEMBER(write); + + DECLARE_READ8Z_MEMBER(crureadz) { }; + DECLARE_WRITE8_MEMBER(cruwrite) { }; + + DECLARE_WRITE_LINE_MEMBER( speech8_ready ); + + DECLARE_READ8_MEMBER( spchrom_read ); + DECLARE_WRITE8_MEMBER( spchrom_load_address ); + DECLARE_WRITE8_MEMBER( spchrom_read_and_branch ); + +protected: + virtual void device_start(); + virtual void device_reset(void); + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + +private: + tms5220_device *m_vsp; +// UINT8 *m_speechrom; // pointer to speech ROM data +// int m_load_pointer; // which 4-bit nibble will be affected by load address +// int m_rombits_count; // current bit position in ROM +// UINT32 m_sprom_address; // 18 bit pointer in ROM +// UINT32 m_sprom_length; // length of data pointed by speechrom_data, from 0 to 2^18 + + // Ready line to the CPU + devcb_write_line m_ready; +}; + +#define MCFG_TISPEECH8_ADD(_tag, _conf) \ + MCFG_DEVICE_ADD(_tag, TI99_SPEECH8, 0) \ + MCFG_DEVICE_CONFIG(_conf) + + +/* + Main class +*/ +class mainboard8_device : public bus8z_device +{ +public: + mainboard8_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + template static devcb_base &set_ready_wr_callback(device_t &device, _Object object) { return downcast(device).m_ready.set_callback(object); } + + DECLARE_READ8_MEMBER( readm); // used from address map + DECLARE_WRITE8_MEMBER( writem ); // used from address map + + DECLARE_READ8Z_MEMBER( readz ); + DECLARE_WRITE8_MEMBER( write ); + + DECLARE_READ8Z_MEMBER(crureadz); + DECLARE_WRITE8_MEMBER(cruwrite); + + void CRUS_set(bool state); + void PTGE_set(bool state); + + void clock_in(int state); + +protected: + void device_start(void); + void device_reset(void); + machine_config_constructor device_mconfig_additions() const; + +private: + bool access_logical_r(address_space& space, offs_t offset, UINT8 *value, UINT8 mem_mask ); + bool access_logical_w(address_space& space, offs_t offset, UINT8 data, UINT8 mem_mask ); + void access_physical_r(address_space& space, offs_t offset, UINT8 *value, UINT8 mem_mask ); + void access_physical_w(address_space& space, offs_t offset, UINT8 data, UINT8 mem_mask ); + void mapwrite(int offset, UINT8 data); + + // Ready line to the CPU + devcb_write_line m_ready; + + // All devices that are attached to the 16-bit address bus. + simple_list m_logcomp; + + // All devices that are attached to the 24-bit mapped address bus. + simple_list m_physcomp; + + // Select bit for the internal DSR. + bool m_dsr_selected; + + // Select bit for the Hexbus DSR. + bool m_hexbus_selected; + + // 99/4A compatibility mode. Name is taken from the spec. If 1, 99/4A compatibility is active. + bool m_CRUS; + + // P-Code mode. Name is taken from the spec. If 0, P-Code libraries are available. + // May be read as "Pascal and Text-to-speech GROM libraries Enable (Negative)" + // Note: this is negative logic. GROMs are present only for PTGEN=0 + // We use PTGE as the inverse signal. + bool m_PTGE; + + // Counter for the wait states. + int m_waitcount; + + // Address mapper registers. Each offset is selected by the first 4 bits + // of the logical address. + UINT32 m_pas_offset[16]; + + // SRAM area of the system. Directly connected to the address decoder. + UINT8 *m_sram; + + // DRAM area of the system. Connected to the mapped address bus. + UINT8 *m_dram; + + // ROM area of the system. Directly connected to the logical address decoder. + UINT8 *m_rom0; + + // ROM area of the system. Directly connected to the physical address decoder. + UINT8 *m_rom1; + + // P-Code ROM area of the system. Directly connected to the physical address decoder. + UINT8 *m_pcode; + + // Custom chips + required_device m_oso; +}; + + +#define MCFG_MAINBOARD8_ADD(_tag, _devices) \ + MCFG_DEVICE_ADD(_tag, MAINBOARD8, 0) \ + MCFG_DEVICE_CONFIG( _devices ) + +#endif diff --git a/src/devices/bus/ti99x/datamux.c b/src/devices/bus/ti99x/datamux.c new file mode 100644 index 00000000000..c9db97f1788 --- /dev/null +++ b/src/devices/bus/ti99x/datamux.c @@ -0,0 +1,489 @@ +// license:LGPL-2.1+ +// copyright-holders:Michael Zapf +/*************************************************************************** + + TI-99/4(A) databus multiplexer circuit + + The DMUX is used to convert the 16-bit databus of the TMS9900 into + an 8-bit databus. The processor writes a 16 bit word which is split + by this circuit into two bytes that are sent subsequently over the 8-bit bus. + In the opposite direction, one 16-bit read request from the CPU is + translated into two 8-bit read requests (odd address / even address) from + this datamux. Its 8-bit latch (LS373) holds the first (odd address) byte, + while the datamux puts the CPU on hold, gets the second byte, + and routes that second byte to the D0-D7 lines, while the latch now puts + the first byte on D8-D15. Since we get two memory accesses each time, + there are twice as many wait states than for a direct 16-bit access + (order LSB, MSB). + + In addition, since the TMS 9900 also supports byte operations, all write + operations are automatically preceded by a read operation, so this adds even + more delays. + + Within the TI-99/4(A) console, only the internal ROM and the small internal + RAM ("scratch pad RAM") are directly connected to the 16-bit bus. All other + devices (video, audio, speech, GROM, and the complete P-Box system are + connected to the datamux. + + The TMS9995 which is used in the Geneve has an internal multiplex, and + the byte order is reversed: MSB, LSB + + ROM = 4K * 16 bit (8 KiB) system ROM (kind of BIOS, plus the GPL interpreter) + RAM = 128 * 16 bit (256 byte) system RAM ("scratch pad") + + Many users (me too) used to solder a 16K * 16 bit (32 KiB) SRAM circuit into + the console, before the datamux, decoded to 0x2000-0x3fff and 0xa000-0xffff. + (This expansion was also called 0-waitstate, since it could be accessed + with the full databus width, and the datamux did not create waitstates.) + + +---+ +-------+ + | |===##========##== D0-D7 ==========##===============|TMS9918| Video + | | || || || +-------+ + | T | +-----+ +-----+ LS245 +----+ + | M | | ROM | | RAM | +----+ + | S | +-----+ +-----+ || | : + | |---||-||-----||-||----------------||-|---------------------: + | 9 | || || A0 - A14 || | A0 : Sound + | 9 |---||--------||-------------------||-|----------+ -A15 : GROM + | 0 | || || LS373 +-+ || | +----A15-+----------: Cartridges + | 0 | || || ##========|<|===## | | : Speech + | | || || || +-+ +-+ || | | : Expansion + | |===## D8-D15 ##===##==|>|=====|===##=|=|=========== D0-D7 =: cards + +---+ +-+ | | | : + ^ LS244| | | | + | | +--+---+-++ + | +--------| DMUX |---------------<--: READY + +--- READY -------------------------+------+ + + Databus width + :------------- 16 bit ---------------|---------- 8 bit -----: + + A0=MSB; A15=LSB + D0=MSB; D15=LSB + + We integrate the 16 bit memory expansion in this datamux component + (pretending that the memory expansion was soldered on top of the datamux) + + January 2012: Rewritten as class + +***************************************************************************/ + +#include "emu.h" +#include "datamux.h" + +/* + Constructor +*/ +ti99_datamux_device::ti99_datamux_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) +: device_t(mconfig, DATAMUX, "Databus multiplexer", tag, owner, clock, "ti99_datamux", __FILE__), + m_ready(*this) { } + +#define TRACE_READY 0 +#define TRACE_ACCESS 0 +#define TRACE_ADDRESS 0 +#define TRACE_WAITCOUNT 0 +#define TRACE_SETUP 0 + +/*************************************************************************** + DEVICE ACCESSOR FUNCTIONS +***************************************************************************/ + +void ti99_datamux_device::read_all(address_space& space, UINT16 addr, UINT8 *target) +{ + attached_device *dev = m_devices.first(); + + // Reading the odd address first (addr+1) + while (dev != NULL) + { + if (dev->m_config->write_select != 0xffff) // write-only + { + if ((addr & dev->m_config->address_mask)==dev->m_config->select) + { + // Cast to the bus8z_device (see ti99defs.h) + bus8z_device *devz = static_cast(dev->m_device); + devz->readz(space, addr, target); + } + // hope we don't have two devices answering... + // consider something like a logical OR and maybe some artificial smoke + } + dev = dev->m_next; + } +} + +void ti99_datamux_device::write_all(address_space& space, UINT16 addr, UINT8 value) +{ + attached_device *dev = m_devices.first(); + while (dev != NULL) + { + if ((addr & dev->m_config->address_mask)==(dev->m_config->select | dev->m_config->write_select)) + { + bus8z_device *devz = static_cast(dev->m_device); + devz->write(space, addr, value); + } + dev = dev->m_next; + } +} + +void ti99_datamux_device::setaddress_all(address_space& space, UINT16 addr) +{ + attached_device *dev = m_devices.first(); + while (dev != NULL) + { + if ((addr & dev->m_config->address_mask)==(dev->m_config->select | dev->m_config->write_select)) + { + bus8z_device *devz = static_cast(dev->m_device); + devz->setaddress_dbin(space, addr, m_read_mode? ASSERT_LINE : CLEAR_LINE); + } + dev = dev->m_next; + } +} + +/* + Special debugger access; these routines have no influence on the wait + state generation. +*/ +UINT16 ti99_datamux_device::debugger_read(address_space& space, UINT16 addr) +{ + UINT16 base32k = 0; + UINT8 lval, hval; + + UINT16 addrb = addr << 1; + if (m_use32k) + { + if ((addrb & 0xe000)==0x2000) base32k = 0x1000; + if (((addrb & 0xe000)==0xa000) || ((addrb & 0xc000)==0xc000)) base32k = 0x4000; + } + if (base32k != 0) + { + return m_ram16b[addr - base32k]; + } + else + { + lval = hval = 0; + read_all(space, addrb+1, &lval); + read_all(space, addrb, &hval); + return ((hval << 8)&0xff00) | (lval & 0xff); + } +} + +void ti99_datamux_device::debugger_write(address_space& space, UINT16 addr, UINT16 data) +{ + UINT16 base32k = 0; + + UINT16 addrb = addr << 1; + if (m_use32k) + { + if ((addrb & 0xe000)==0x2000) base32k = 0x1000; + if (((addrb & 0xe000)==0xa000) || ((addrb & 0xc000)==0xc000)) base32k = 0x4000; + } + if (base32k != 0) + { + m_ram16b[addr - base32k] = data; + } + else + { + write_all(space, addrb+1, data & 0xff); + write_all(space, addrb, (data >> 8) & 0xff); + } +} + +/* + Read access. We are using two loops because the delay between both + accesses must not occur within the loop. So we have one access on the bus, + a delay, and then the second access (each one with possibly many attached + devices) +*/ +READ16_MEMBER( ti99_datamux_device::read ) +{ + // Care for debugger + if (space.debugger_access()) + { + return debugger_read(space, offset); + } + + // Looks ugly, but this is close to the real thing. If the 16bit + // memory expansion is installed in the console, and the access hits its + // space, just respond to the memory access and don't bother the + // datamux in any way. In particular, do not make the datamux insert wait + // states. + + if (m_base32k != 0) + { + UINT16 reply = m_ram16b[offset-m_base32k]; + return reply & mem_mask; + } + else + { + // The byte from the odd address has already been read into the latch + // Reading the even address now (addr) + UINT8 hbyte = 0; + read_all(space, m_addr_buf, &hbyte); + if (TRACE_ACCESS) logerror("datamux: read even byte from address %04x -> %02x\n", m_addr_buf, hbyte); + + return ((hbyte<<8) | m_latch) & mem_mask; + } +} + +/* + Write access. +*/ +WRITE16_MEMBER( ti99_datamux_device::write ) +{ + // Addresses below 0x2000 are ROM and should be handled in the address map + // by the ROM entry, but as the write handler for ROM is not mapped, we end up + // here when there are invalid accesses, and this will mess up everything. + if (offset < 0x1000) return; + + if (space.debugger_access()) + { + debugger_write(space, offset, data); + return; + } + + // Handle the internal 32K expansion + if (m_base32k != 0) + { + m_ram16b[offset-m_base32k] = data; + } + else + { + // Otherwise the datamux is in normal operation which means it puts + // the even value into the latch and outputs the odd value now. + m_latch = (data >> 8) & 0xff; + + // write odd byte + if (TRACE_ACCESS) logerror("datamux: write odd byte to address %04x <- %02x\n", m_addr_buf+1, data & 0xff); + write_all(space, m_addr_buf+1, data & 0xff); + } +} + +/* + Called when the memory access starts by setting the address bus. From that + point on, we suspend the CPU until all operations are done. +*/ +SETOFFSET_MEMBER( ti99_datamux_device::setoffset ) +{ + if (TRACE_ADDRESS) logerror("datamux: set address %04x\n", offset << 1); + // Initialize counter + // 1 cycle for loading into the datamux + // 2 subsequent wait states (LSB) + // 2 subsequent wait states (MSB) + // clock cycle 6 is the nominal follower of the last wait state + m_waitcount = 5; + m_addr_buf = offset << 1; + m_spacep = &space; + + m_base32k = 0; + if (m_use32k) + { + if ((m_addr_buf & 0xe000)==0x2000) m_base32k = 0x1000; + if (((m_addr_buf & 0xe000)==0xa000) || ((m_addr_buf & 0xc000)==0xc000)) m_base32k = 0x4000; + } + + // Suspend the CPU if not using the 32K + if (m_base32k == 0) + { + // propagate the setaddress operation + // First the odd address + setaddress_all(space, m_addr_buf+1); + m_muxready = CLEAR_LINE; + ready_join(); + } + else m_waitcount = 0; +} + +/* + The datamux is connected to the clock line in order to operate + the wait state counter and to read/write the bytes. +*/ +WRITE_LINE_MEMBER( ti99_datamux_device::clock_in ) +{ + // return immediately if the datamux is currently inactive + if (m_waitcount>0) + { + if (TRACE_WAITCOUNT) logerror("datamux: wait count %d\n", m_waitcount); + if (m_sysready==CLEAR_LINE) + { + if (TRACE_READY) logerror("datamux: stalled due to external READY=0\n"); + return; + } + if (m_read_mode) + { + // Reading + if (state==ASSERT_LINE) + { // raising edge + m_waitcount--; + if (m_waitcount==0) + { + m_muxready = ASSERT_LINE; + ready_join(); + } + if (m_waitcount==2) + { + // read odd byte + read_all(*m_spacep, m_addr_buf+1, &m_latch); + if (TRACE_ACCESS) logerror("datamux: read odd byte from address %04x -> %02x\n", m_addr_buf+1, m_latch); + // do the setaddress for the even address + setaddress_all(*m_spacep, m_addr_buf); + } + } + } + else + { + if (state==ASSERT_LINE) + { // raising edge + m_waitcount--; + if (m_waitcount==0) + { + m_muxready = ASSERT_LINE; + ready_join(); + } + } + else + { // falling edge + if (m_waitcount==2) + { + // do the setaddress for the even address + setaddress_all(*m_spacep, m_addr_buf); + // write even byte + if (TRACE_ACCESS) logerror("datamux: write even byte to address %04x <- %02x\n", m_addr_buf, m_latch); + write_all(*m_spacep, m_addr_buf, m_latch); + } + } + } + } +} + +/* + Combine the external (sysready) and the own (muxready) READY states. +*/ +void ti99_datamux_device::ready_join() +{ + m_ready((m_sysready==CLEAR_LINE || m_muxready==CLEAR_LINE)? CLEAR_LINE : ASSERT_LINE); +} + +WRITE_LINE_MEMBER( ti99_datamux_device::dbin_in ) +{ + m_read_mode = (state==ASSERT_LINE); + if (TRACE_ADDRESS) logerror("datamux: data bus in = %d\n", m_read_mode? 1:0 ); +} + +WRITE_LINE_MEMBER( ti99_datamux_device::ready_line ) +{ + if (TRACE_READY) + { + if (state != m_sysready) logerror("datamux: READY line from PBox = %d\n", state); + } + m_sysready = (line_state)state; + // Also propagate to CPU via driver + ready_join(); +} + +/*************************************************************************** + DEVICE LIFECYCLE FUNCTIONS +***************************************************************************/ + +void ti99_datamux_device::device_start(void) +{ + m_ram16b = NULL; + m_muxready = ASSERT_LINE; + m_ready.resolve(); +} + +void ti99_datamux_device::device_stop(void) +{ + if (m_ram16b) global_free_array(m_ram16b); +} + +void ti99_datamux_device::device_reset(void) +{ + const datamux_config *conf = reinterpret_cast(static_config()); + + const dmux_device_list_entry *list = conf->devlist; + + m_cpu = machine().device("maincpu"); + // m_space = &m_cpu->memory().space(AS_PROGRAM); + + m_devices.reset(); // clear the list + m_use32k = (ioport("RAM")->read()==1); + + // better use a region? + if (m_ram16b==NULL) + { + m_ram16b = global_alloc_array_clear(UINT16, 32768/2); + } + + // Now building the list of active devices at this databus multiplex. + // We allow for turning off devices according to configuration switch settings. + // In particular, the HSGPL card cannot function unless the console GROMs are + // removed. + if ( list != NULL ) + { + bool done = false; + for (int i=0; !done; i++) + { + if (list[i].name == NULL) + { + done = true; + } + else + { + UINT32 set = 0; + bool active_device = true; + if (list[i].setting!=NULL) + { + set = ioport(list[i].setting)->read(); + active_device = ((set & list[i].set)==list[i].set) && ((set & list[i].unset)==0); + } + if (active_device) + { + device_t *dev = machine().device(list[i].name); + if (dev != NULL) + { + attached_device *ad = new attached_device(dev, list[i]); + m_devices.append(*ad); + if (TRACE_SETUP) logerror("datamux: Device %s mounted at index %d.\n", list[i].name, i); + } + else + { + if (TRACE_SETUP) logerror("datamux: Device %s not found.\n", list[i].name); + } + } + else + { + if (TRACE_SETUP) logerror("datamux: Device %s not mounted due to configuration setting %s.\n", list[i].name, list[i].setting); + } + } + } + } + if (TRACE_SETUP) logerror("datamux: Device count = %d\n", m_devices.count()); + + m_sysready = ASSERT_LINE; + m_muxready = ASSERT_LINE; + ready_join(); + + m_waitcount = 0; + m_latch = 0; + + m_read_mode = true; +} + +INPUT_PORTS_START( datamux ) + PORT_START( "RAM" ) /* config */ + PORT_CONFNAME( 0x01, 0x00, "Console 32 KiB RAM upgrade (16 bit)" ) + PORT_CONFSETTING( 0x00, DEF_STR( Off ) ) + PORT_CONFSETTING( 0x01, DEF_STR( On ) ) + + PORT_START( "GROMENA" ) + PORT_CONFNAME( 0x01, 0x01, "Console GROMs" ) + PORT_CONFSETTING( 0x00, DEF_STR( Off ) ) + PORT_CONFSETTING( 0x01, DEF_STR( On ) ) + +INPUT_PORTS_END + +ioport_constructor ti99_datamux_device::device_input_ports() const +{ + return INPUT_PORTS_NAME(datamux); +} + +const device_type DATAMUX = &device_creator; diff --git a/src/devices/bus/ti99x/datamux.h b/src/devices/bus/ti99x/datamux.h new file mode 100644 index 00000000000..7bc52972602 --- /dev/null +++ b/src/devices/bus/ti99x/datamux.h @@ -0,0 +1,157 @@ +// license:LGPL-2.1+ +// copyright-holders:Michael Zapf +/**************************************************************************** + + TI-99/4(A) databus multiplexer circuit + See datamux.c for documentation + + Michael Zapf + + February 2012: Rewritten as class + +*****************************************************************************/ + +#ifndef __DMUX__ +#define __DMUX__ + +#include "ti99defs.h" + +extern const device_type DATAMUX; + +/* + Device that is attached to this datamux. + The configuration setting is used for certain configurations + where devices may only be used if others are turned off. In particular, + if the HGSPL expansion card is used, the GROMs in the console must be + removed. +*/ +struct dmux_device_list_entry +{ + const char *name; // Name of the device (used for looking up the device) + UINT16 select; // State of the address line bits when addressing this device + UINT16 address_mask; // Bits of the address bus used to address this device + UINT16 write_select; // Bits set when doing write accesses to this device (ffff = write-only) + const char *setting; // configuration switch that may have an effect for the presence of this device + UINT8 set; // bits that must be set for this switch so that this device is present + UINT8 unset; // bits that must be reset for this switch so that this device is present +}; + +#define DMUX_CONFIG(name) \ + const datamux_config(name) = + +struct datamux_config +{ + const dmux_device_list_entry *devlist; +}; + +/* + Device list of this datamux. +*/ +class attached_device +{ + friend class simple_list; + friend class ti99_datamux_device; + +public: + attached_device(device_t *busdevice, const dmux_device_list_entry &entry) + : m_device(busdevice), m_config(&entry) { }; + +private: + attached_device *m_next; + device_t *m_device; // the actual device + const dmux_device_list_entry *m_config; +}; + +/* + Main class +*/ +class ti99_datamux_device : public device_t +{ +public: + ti99_datamux_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + DECLARE_READ16_MEMBER( read ); + DECLARE_WRITE16_MEMBER( write ); + DECLARE_SETOFFSET_MEMBER( setoffset ); + + DECLARE_WRITE_LINE_MEMBER( clock_in ); + DECLARE_WRITE_LINE_MEMBER( dbin_in ); + DECLARE_WRITE_LINE_MEMBER( ready_line ); + + template static devcb_base &static_set_ready_callback(device_t &device, _Object object) + { + return downcast(device).m_ready.set_callback(object); + } + +protected: + /* Constructor */ + void device_start(); + void device_stop(); + void device_reset(); + ioport_constructor device_input_ports() const; + +private: + // Keeps the address space pointer + address_space* m_spacep; + + // Common read routine + void read_all(address_space& space, UINT16 addr, UINT8 *target); + + // Common write routine + void write_all(address_space& space, UINT16 addr, UINT8 value); + + // Common set address method + void setaddress_all(address_space& space, UINT16 addr); + + // Debugger access + UINT16 debugger_read(address_space& space, UINT16 addr); + void debugger_write(address_space& space, UINT16 addr, UINT16 data); + + // Join own READY and external READY + void ready_join(); + + // Ready line to the CPU + devcb_write_line m_ready; + + // Own ready state. + line_state m_muxready; + + // Ready state. Needed to control wait state generation via inbound READY + line_state m_sysready; + + /* Address latch (emu). In reality, the address bus remains constant. */ + UINT16 m_addr_buf; + + /* Stores the state of the DBIN line. */ + bool m_read_mode; + + /* All devices that are attached to the 8-bit bus. */ + simple_list m_devices; + + /* Latch which stores the first (odd) byte */ + UINT8 m_latch; + + /* Counter for the wait states. */ + int m_waitcount; + + /* Memory expansion (internal, 16 bit). */ + UINT16 *m_ram16b; + + /* Use the memory expansion? */ + bool m_use32k; + + /* Memory base for piggy-back 32K expansion. If 0, expansion is not used. */ + UINT16 m_base32k; + + /* Reference to the CPU; avoid lookups. */ + device_t *m_cpu; +}; + +/******************************************************************************/ + +#define MCFG_DMUX_ADD(_tag, _devices) \ + MCFG_DEVICE_ADD(_tag, DATAMUX, 0) \ + MCFG_DEVICE_CONFIG( _devices ) +#endif + +#define MCFG_DMUX_READY_HANDLER( _intcallb ) \ + devcb = &ti99_datamux_device::static_set_ready_callback( *device, DEVCB_##_intcallb ); diff --git a/src/devices/bus/ti99x/genboard.c b/src/devices/bus/ti99x/genboard.c new file mode 100644 index 00000000000..0c021bd0234 --- /dev/null +++ b/src/devices/bus/ti99x/genboard.c @@ -0,0 +1,1994 @@ +// license:LGPL-2.1+ +// copyright-holders:Michael Zapf +/*************************************************************************** + Geneve 9640 mapper and more components + + This file contains 3 classes: + - mapper: main function of the Gate Array on the Geneve board. Maps logical + memory accesses to a wider address space using map registers. + - keyboard: an implementation of a XT-style keyboard. This should be dropped + and replaced by a proper XT keyboard implementation. + - mouse: an implementation of an Atari-style mouse connected to the v9938. + + Onboard SRAM configuration: + There is an adjustable SRAM configuration on board, representing the + various enhancements by users. + + The standard memory configuration as reported by chkdsk (32 KiB): + 557056 bytes of total memory + + With 64 KiB SRAM: + 589824 bytes of total memory + + With 384 KiB SRAM: + 917504 bytes of total memory + + The original 32 KiB SRAM memory needs to be expanded to 64 KiB for + MDOS 2.50s and higher, or the system will lock up. Therefore the emulation + default is 64 KiB. + + The ultimate expansion is a 512 KiB SRAM circuit wired to the gate array + to provide 48 pages of fast static RAM. This also requires to build an + adapter for a larger socket. From the 512 KiB, only 384 KiB will be + accessed, since the higher pages are hidden behind the EPROM pages. + + === Address map === + p,q = page value bit (q = AMC, AMB, AMA) + c = address offset within 8 KiB page + + p pqqq pppc cccc cccc cccc + + 0 0... .... .... .... .... on-board dram 512 KiB + + 0 1... .... .... .... .... on-board future expansion 512 KiB or Memex with Genmod + + 1 00.. .... .... .... .... p-box AMA=0 (256 KiB) + 1 010. .... .... .... .... p-box AMA=1 AMB=0 (128 KiB) + 1 0110 .... .... .... .... p-box AMA=1 AMB=1 AMC=0 (64 KiB) + + 1 0111 00.. .... .... .... p-box address block 0xxx, 2xxx + 1 0111 010. .... .... .... p-box address block 4xxx (DSR) + 1 0111 011. .... .... .... p-box address block 6xxx + 1 0111 100. .... .... .... p-box address block 8xxx (Speech at 0x9000) + 1 0111 101. .... .... .... p-box address block axxx + 1 0111 11.. .... .... .... p-box address block cxxx, exxx + + 1 100. .... .... .... .... on-board sram (128K) -\ + 1 101. .... .... .... .... on-board sram (128K) --+- maximum SRAM expansion + 1 1100 .... .... .... .... on-board sram (64K) --/ + 1 1101 0... .... .... .... on-board sram (32K) - additional 32 KiB required for MDOS 2.50s and higher + 1 1101 1... .... .... .... on-board sram (32K) - standard setup + + 1 111. ..0. .... .... .... on-board boot1 + 1 111. ..1. .... .... .... on-board boot2 + + The TI console (or more precise, the Flex Cable Interface) sets the AMA/B/C + lines to 1. Most cards actually check for AMA/B/C=1. However, this decoding + was forgotten in third party cards which cause the card address space + to be mirrored. The usual DSR space at 4000-5fff which would be reachable + via page 0xba is then mirrored on a number of other pages: + + 10 xxx 010x = 82, 8a, 92, 9a, a2, aa, b2, ba + + Another block to take care of is 0xbc which covers 8000-9fff since this + area contains the speech synthesizer port at 9000/9400. + + For the standard Geneve, only prefix 10 is routed to the P-Box. The Genmod + modification wires these address lines to pins 8 and 9 in the P-Box as AMD and + AME. This requires all cards to be equipped with an additional selection logic + to detect AMD=0, AME=1. Otherwise these cards, although completely decoding the + 19-bit address, would reappear at 512 KiB distances. + + Genmod's double switch box is also emulated. There are two switches: + - Turbo mode: Activates or deactivates the wait state logic on the Geneve + board. This switch may be changed at any time. + - TI mode: Selects between the on-board memory, which is obviously required + for the GPL interpreter, and the external Memex memory. This switch + triggers a reset when changed. + + + =================== + Mapping + =================== + + Logical address space: 64 KiB + + Geneve mode: + + Video: F100, F102, F104, F106 (mirror: +8) + Mapper: F110 - F117 + Keyboard: F118 + Clock: F130 - F13F + Sound: F120 + + TI mode: + + Video: 8800, 8802, 8804, 8806 + Mapper: 8000 - 8007 + Keyboard: 8008 - 800F + Clock: 8010 - 801F + Speech: 9000 / 9400 + Grom: 9800 / 9802 + + Physical address space: 2 MiB + + Start End Banks + 000000 - 07FFFF 00-3F 512 KiB DRAM on-board + 080000 - 0FFFFF 40-7F 512 KiB on-board expansion (never used) + 100000 - 16FFFF 80-B7 448 KiB P-Box space (special cards, like MEMEX) + 170000 - 17FFFF B8-BF 64 KiB P-Box space (current cards) + 180000 - 1DFFFF C0-EF 384 KiB SRAM space on-board; stock Geneve comes with 32 KiB + 1E0000 - 1FFFFF F0-FF 128 KiB EPROM space; 16 KiB actually used, 8 mirrors + + + GenMod modification: + + TI mode + 000000 - 07FFFF 00-3F 512 KiB DRAM on-board + 080000 - 1DFFFF 40-EF 1408 KiB P-Box space + 1E0000 - 1FFFFF F0-FF 128 KiB EPROM space; 16 KiB actually used, 8 mirrors + + Non-TI mode + 000000 - 1DFFFF 00-EF 1920 KiB P-Box space + 1E0000 - 1FFFFF F0-FF 128 KiB EPROM space; 16 KiB actually used, 8 mirrors + + Waitstate handling + ------------------ + Waitstates are caused by a cleared READY line of the TMS9995 processor + during an external memory cycle. That means that waitstates have no effect + for operations within the on-chip memory, and only when an access to the + external memory or other devices occurs, a delay will be noticed. + + The waitstates are generated by the custom Gate Array chip on the board + and the PAL 16R4, both lacking proper documentation. All of the following + numbers have been determined by experiments with the real machine. + + Waitstates are generated for: + - memory-mapped devices (mapper, clock, keyboard): 1 WS + - accesses to the peripheral expansion box: 1 WS + - accesses to on-board DRAM: 1 WS + - accesses to video: 15 WS + - accesses to sound: ~25 WS + - accesses to SRAM: 0 WS + + Additional waitstates are created when one of the CRU bits is set. In that + case, all delays are extended to 2 WS (including SRAM). + + Sound waitstates are somewhat unpredictable. It seems as if they depend + on the clock of the sound chip; the theory is that the READY line is + pulled down until the next clock pulse, which may take some value between + 18 CPU cycles and 30 CPU cycles. + + The gate array is able to create wait states for video accesses. However, + these wait states are effective after the video access has been completed. + Wait states are not effective when the execution is running in on-chip + RAM. Additional wait states are requested by m_video_waitstates = true. + Without additional wait states, the video access takes the usual 1 or 2 WS. + + Waitstate behavior (Nov 2013) + Almost perfect. Only video read access from code in DRAM is too fast by one WS + + ========================== + PFM expansion + ========================== + + The "Programmable Flash Memory expansion" is a replacement for the boot + EPROM. + + PFM: Original version, 128 KiB + PFM+: Expansion of the original version, piggybacked, adds another 128KiB + PFM512: Using an AT29C040 (not A), 512 KiB + + The PFM is visible as four banks in memory pages 0xF0 - 0xFF. + + Bank switching is done by four 9901 pins: + + 0028: LSB of bank number + 003A: MSB of bank number + + Bank 0 is the boot code, while banks 1-3 can be used as flash drives + + Michael Zapf, October 2011 + February 2012: rewritten as class, restructured + Aug 2015: PFM added + +***************************************************************************/ + +#include "genboard.h" + +#define TRACE_READ 0 +#define TRACE_WRITE 0 +#define TRACE_DETAIL 0 +#define TRACE_KEYBOARD 0 +#define TRACE_CLOCK 0 +#define TRACE_LINES 0 +#define TRACE_SETTING 1 +#define TRACE_PFM 0 + +geneve_mapper_device::geneve_mapper_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) +: device_t(mconfig, GENEVE_MAPPER, "Geneve Gate Array", tag, owner, clock, "geneve_mapper", __FILE__), + m_ready(*this) +{ + m_eprom = NULL; +} + +INPUT_CHANGED_MEMBER( geneve_mapper_device::settings_changed ) +{ + int number = (int)((UINT64)param&0x03); + int value = newval; + + switch (number) + { + case 1: + // Turbo switch. May be changed at any time. + if (TRACE_SETTING) logerror("%s: Setting turbo flag to %d\n", tag(), value); + m_turbo = (value!=0); + break; + case 2: + // TIMode switch. Causes reset when changed. + if (TRACE_SETTING) logerror("%s: Setting timode flag to %d\n", tag(), value); + m_timode = (value!=0); + machine().schedule_hard_reset(); + break; + case 3: + // Used when switching the boot ROMs during runtime, especially the PFM + set_boot_rom(value); + break; + default: + logerror("%s: Unknown setting %d ignored\n", tag(), number); + } +} + +/**************************************************************************** + GROM simulation. The Geneve board simulated GROM circuits within its gate + array. +*****************************************************************************/ + +/* + Simulates GROM. The real Geneve does not use GROMs but simulates them + within the gate array. Unlike with real GROMs, no address wrapping occurs, + and the complete 64K space is available. +*/ +READ8_MEMBER( geneve_mapper_device::read_grom ) +{ + UINT8 reply; + if (offset & 0x0002) + { + // GROM address handling + m_gromwaddr_LSB = false; + + if (m_gromraddr_LSB) + { + reply = m_grom_address & 0xff; + m_gromraddr_LSB = false; + } + else + { + reply = (m_grom_address >> 8) & 0xff; + m_gromraddr_LSB = true; + } + } + else + { + // GROM data handling + // GROMs are stored in pages 38..3f + int page = 0x38; + reply = m_dram[(page<<13) + m_grom_address]; + m_grom_address = (m_grom_address + 1) & 0xffff; + m_gromraddr_LSB = m_gromwaddr_LSB = false; + } + return reply; +} + +/* + Simulates GROM. The real Geneve does not use GROMs but simulates them + within the gate array. +*/ +WRITE8_MEMBER( geneve_mapper_device::write_grom ) +{ + if (offset & 0x0002) + { + // set address + m_gromraddr_LSB = false; + if (m_gromwaddr_LSB) + { + m_grom_address = (m_grom_address & 0xff00) | data; + m_grom_address = (m_grom_address + 1) & 0xffff; + m_gromwaddr_LSB = false; + } + else + { + m_grom_address = (m_grom_address & 0x00ff) | ((UINT16)data<<8); + m_gromwaddr_LSB = true; + } + } + else + { // write GPL data + // The Geneve GROM simulator allows for GROM writing (verified with a real system) + int page = 0x38; + m_dram[(page<<13) + m_grom_address] = data; + + m_grom_address = (m_grom_address + 1) & 0xffff; + m_gromraddr_LSB = m_gromwaddr_LSB = false; + } +} + +void geneve_mapper_device::set_wait(int min) +{ + if (m_debug_no_ws) return; + if (m_extra_waitstates && min < 2) min = 2; + + // if we still have video wait states, do not set this counter + // (or it will assert READY when expiring) + if (m_ext_waitcount > min) return; + + // need one more pass so that READY will be asserted again + m_waitcount = min + 1; + if (m_waitcount > 1) + { + if (TRACE_LINES) logerror("%s: Pulling down READY line for %d cycles\n", tag(), min); + m_ready(CLEAR_LINE); + m_ready_asserted = false; + } +} + +void geneve_mapper_device::set_ext_wait(int min) +{ + if (m_debug_no_ws) return; + m_ext_waitcount = min; +} + +void geneve_mapper_device::set_boot_rom(int selection) +{ + switch (selection) + { + case GENEVE_098: + logerror("%s: Using 0.98 boot eprom\n", tag()); + m_eprom = machine().root_device().memregion("maincpu")->base() + 0x4000; + m_pfm_mode = 0; + break; + case GENEVE_100: + logerror("%s: Using 1.00 boot eprom\n", tag()); + m_eprom = machine().root_device().memregion("maincpu")->base(); + m_pfm_mode = 0; + break; + case GENEVE_PFM512: + logerror("%s: Using PFM512 (AT29C040)\n", tag()); + m_pfm_mode = 1; + break; + case GENEVE_PFM512A: + logerror("%s: Using PFM512A (AT29C040A)\n", tag()); + m_pfm_mode = 2; + break; + default: + logerror("%s: Unknown boot ROM selection\n", tag()); + } +} + +void geneve_mapper_device::set_geneve_mode(bool geneve) +{ + if (TRACE_SETTING) logerror("%s: Setting Geneve mode = %d\n", tag(), geneve); + m_geneve_mode = geneve; +} + +void geneve_mapper_device::set_direct_mode(bool direct) +{ + if (TRACE_SETTING) logerror("%s: Setting direct mode = %d\n", tag(), direct); + m_direct_mode = direct; +} + +void geneve_mapper_device::set_cartridge_size(int size) +{ + if (TRACE_SETTING) logerror("%s: Setting cartridge size to %d\n", tag(), size); + m_cartridge_size = size; +} + +void geneve_mapper_device::set_cartridge_writable(int base, bool write) +{ + if (TRACE_SETTING) logerror("%s: Cartridge %04x space writable = %d\n", tag(), base, write); + if (base==0x6000) m_cartridge6_writable = write; + else m_cartridge7_writable = write; +} + +void geneve_mapper_device::set_video_waitstates(bool wait) +{ + if (TRACE_SETTING) logerror("%s: Setting video waitstates = %d\n", tag(), wait); + m_video_waitstates = wait; +} + +void geneve_mapper_device::set_extra_waitstates(bool wait) +{ + if (TRACE_SETTING) logerror("%s: Setting extra waitstates = %d\n", tag(), wait); + m_extra_waitstates = wait; +} + + +/************************************************************************ + Called by the address map +************************************************************************/ +/* + Constants for mapper decoding. Naming scheme: + M=mapper + L=Logical space; P=Physical space + G=Geneve mode; T=TI mode; GM=GenMod +*/ +enum +{ + MLGVIDEO=1, + MLGMAPPER, + MLGKEY, + MLGCLOCK, + MLGSOUND, + MLTMAPPER, + MLTKEY, + MLTCLOCK, + MLTVIDEO, + MLTSPEECH, + MLTGROM, + MLTSOUND, + MPGDRAM, + MPGEXP, + MPGEPROM, + MPGSRAM, + MPGBOX, + MPGMDRAM, + MPGMEPROM, + MPGMBOX +}; + +/* + Read a byte via the data bus. The decoding has already been done in the + SETOFFSET method, and we re-use the values stored there to quickly + access the appropriate component. +*/ +READ8_MEMBER( geneve_mapper_device::readm ) +{ + UINT8 value = 0; + + decdata *dec; + decdata debug; + + // For the debugger, do the decoding here with no wait states + if (space.debugger_access()) + { + if (m_cpu->is_onchip(offset)) return m_cpu->debug_read_onchip_memory(offset&0xff); + dec = &debug; + m_debug_no_ws = true; + decode(space, offset, true, dec); + } + else + { + // Use the values found in the setaddress phase + dec = &m_decoded; + m_debug_no_ws = false; + } + + switch (dec->function) + { + case MLGVIDEO: + m_video->readz(space, dec->offset, &value, 0xff); + if (TRACE_READ) logerror("%s: Read video %04x -> %02x\n", tag(), dec->offset, value); + // Video wait states are created *after* the access + // Accordingly, they have no effect when execution is in onchip RAM + if (m_video_waitstates) set_ext_wait(15); + break; + + case MLGMAPPER: + // mapper + value = m_map[dec->offset]; + if (TRACE_READ) logerror("%s: read mapper %04x -> %02x\n", tag(), dec->offset, value); + break; + + case MLGKEY: + // key + if (!space.debugger_access()) value = m_keyboard->get_recent_key(); + if (TRACE_READ) logerror("%s: Read keyboard -> %02x\n", tag(), value); + break; + + case MLGCLOCK: + // clock + // tests on the real machine showed that + // upper nibble is 0xf (probably because of the location at 0xf130?) + value = m_clock->read(space, dec->offset) | 0xf0; + if (TRACE_READ) logerror("%s: Read clock %04x -> %02x\n", tag(), dec->offset, value); + break; + + case MLTMAPPER: + // mapper + value = m_map[dec->offset]; + if (TRACE_READ) logerror("%s: Read mapper %04x -> %02x\n", tag(), dec->offset, value); + break; + + case MLTKEY: + // key + if (!space.debugger_access()) value = m_keyboard->get_recent_key(); + if (TRACE_READ) logerror("%s: Read keyboard -> %02x\n", tag(), value); + break; + + case MLTCLOCK: + // clock + // upper nibble is 1, only last byte gets a 2 + // probably because of the location at 8010...8020? + // (TI mode used swapped byte order) + // unless we use a workspace at >F000, in which case we get 8x values + // Obscure, needs more investigation. We might as well ignore this, + // as the high nibble is obviously undefined and takes some past + // value floating around. + value = m_clock->read(space, dec->offset); + value |= (dec->offset==0x000f)? 0x20 : 0x10; + if (TRACE_READ) logerror("%s: Read clock %04x -> %02x\n", tag(), dec->offset, value); + break; + + case MLTVIDEO: + // video + // ++++ ++-- ---- ---+ + // 1000 1000 0000 00x0 + m_video->readz(space, dec->offset, &value, 0xff); + if (TRACE_READ) logerror("%s: Read video %04x -> %02x\n", tag(), dec->offset, value); + // See above + if (m_video_waitstates) set_ext_wait(15); + break; + + case MLTSPEECH: + // speech + // ++++ ++-- ---- ---+ + // 1001 0000 0000 0000 + // We need to add the address prefix bits + m_peribox->readz(space, dec->offset, &value, 0xff); + if (TRACE_READ) logerror("%s: Read speech -> %02x\n", tag(), value); + break; + + case MLTGROM: + // grom simulation + // ++++ ++-- ---- ---+ + // 1001 1000 0000 00x0 + if (!space.debugger_access()) value = read_grom(space, dec->offset, 0xff); + if (TRACE_READ) logerror("%s: Read GROM %04x -> %02x\n", tag(), dec->offset, value); + break; + + case MLGSOUND: + case MLTSOUND: + value = 0; + break; + + + case MPGDRAM: + // DRAM. + value = m_dram[dec->physaddr]; +// LOG("dram read physaddr = %06x logaddr = %04x value = %02x\n", dec->physaddr, dec->offset, value); + if (TRACE_READ) logerror("%s: Read DRAM %04x (%06x) -> %02x\n", tag(), dec->offset, dec->physaddr, value); + break; + + case MPGEXP: + // On-board memory expansion for standard Geneve (never used) + if (TRACE_READ) logerror("%s: Read unmapped area %06x\n", tag(), dec->physaddr); + value = 0; + break; + + case MPGEPROM: + // 1 111. ..xx xxxx xxxx xxxx on-board eprom (16K) + // mirrored for f0, f2, f4, ...; f1, f3, f5, ... + if (m_pfm_mode == 0) + { + value = m_eprom[dec->physaddr & 0x003fff]; + if (TRACE_READ) logerror("%s: Read EPROM %04x (%06x) -> %02x\n", tag(), dec->offset, dec->physaddr, value); + } + else value = read_from_pfm(space, dec->physaddr, 0xff); + + break; + + case MPGSRAM: + if ((dec->physaddr & m_sram_mask)==m_sram_val) + { + value = m_sram[dec->physaddr & ~m_sram_mask]; + } + else value = 0; + // Return in any case +// LOG("sram read physaddr = %06x logaddr = %04x value = %02x\n", dec->physaddr, dec->offset, value); + if (TRACE_READ) logerror("%s: Read SRAM %04x (%06x) -> %02x\n", tag(), dec->offset, dec->physaddr, value); + break; + + case MPGBOX: + // Route everything else to the P-Box + // 0x000000-0x07ffff for the stock Geneve (AMC,AMB,AMA,A0 ...,A15) + // 0x000000-0x1fffff for the GenMod.(AME,AMD,AMC,AMB,AMA,A0 ...,A15) + + m_peribox->readz(space, dec->physaddr, &value, 0xff); + if (TRACE_READ) logerror("%s: Read P-Box %04x (%06x) -> %02x\n", tag(), dec->offset, dec->physaddr, value); + break; + + case MPGMDRAM: + // DRAM. One wait state. + value = m_dram[dec->physaddr]; + break; + + case MPGMEPROM: + // 1 111. ..xx xxxx xxxx xxxx on-board eprom (16K) + // mirrored for f0, f2, f4, ...; f1, f3, f5, ... + if (m_pfm_mode == 0) + { + value = m_eprom[dec->physaddr & 0x003fff]; + if (TRACE_READ) logerror("%s: Read EPROM %04x (%06x) -> %02x\n", tag(), dec->offset, dec->physaddr, value); + } + else value = read_from_pfm(space, dec->physaddr, 0xff); + break; + + case MPGMBOX: + // Route everything else to the P-Box + m_peribox->readz(space, dec->physaddr, &value, 0xff); + break; + } + return value; +} + +WRITE8_MEMBER( geneve_mapper_device::writem ) +{ + decdata *dec; + decdata debug; + + // For the debugger, do the decoding here with no wait states + if (space.debugger_access()) + { + dec = &debug; + m_debug_no_ws = true; + decode(space, offset, false, dec); + } + else + { + // Use the values found in the setaddress phase + m_debug_no_ws = false; + dec = &m_decoded; + } + + switch (dec->function) + { + case MLGVIDEO: + // video + // ++++ ++++ ++++ ---+ + // 1111 0001 0000 .cc0 + m_video->write(space, dec->offset, data, 0xff); + if (TRACE_WRITE) logerror("%s: Write video %04x <- %02x\n", tag(), offset, data); + // See above + if (m_video_waitstates) set_ext_wait(15); + break; + + case MLGMAPPER: + // mapper + m_map[dec->offset] = data; + if (TRACE_WRITE) logerror("%s: Write mapper %04x <- %02x\n", tag(), offset, data); + break; + + case MLGCLOCK: + // clock + // ++++ ++++ ++++ ---- + m_clock->write(space, dec->offset, data); + if (TRACE_WRITE) logerror("%s: Write clock %04x <- %02x\n", tag(), offset, data); + break; + + case MLGSOUND: + // sound + // ++++ ++++ ++++ ---+ + m_sound->write(space, 0, data, 0xff); + if (TRACE_WRITE) logerror("%s: Write sound <- %02x\n", tag(), data); + break; + + case MLTMAPPER: + // mapper + m_map[dec->offset] = data; + if (TRACE_WRITE) logerror("%s: Write mapper %04x <- %02x\n", tag(), offset, data); + break; + + case MLTCLOCK: + // clock + m_clock->write(space, dec->offset, data); + if (TRACE_WRITE) logerror("%s: Write clock %04x <- %02x\n", tag(), offset, data); + break; + + case MLTVIDEO: + // video + // ++++ ++-- ---- ---+ + // 1000 1100 0000 00c0 + // Initialize waitstate timer + m_video->write(space, dec->offset, data, 0xff); + if (TRACE_WRITE) logerror("%s: Write video %04x <- %02x\n", tag(), offset, data); + // See above + if (m_video_waitstates) set_ext_wait(15); + break; + + case MLTSPEECH: + // speech + // ++++ ++-- ---- ---+ + // 1001 0100 0000 0000 + // We need to add the address prefix bits + m_peribox->write(space, dec->offset, data, 0xff); + if (TRACE_WRITE) logerror("%s: Write speech <- %02x\n", tag(), data); + break; + + case MLTGROM: + // grom simulation + // ++++ ++-- ---- ---+ + // 1001 1100 0000 00c0 + write_grom(space, dec->offset, data, 0xff); + if (TRACE_WRITE) logerror("%s: Write GROM %04x <- %02x\n", tag(), offset, data); + break; + + case MLTSOUND: + // sound + // ++++ ++-- ---- ---+ + // 1000 0100 0000 0000 + m_sound->write(space, 0, data, 0xff); + if (TRACE_WRITE) logerror("%s: Write sound <- %02x\n", tag(), data); + break; + + case MLTKEY: + case MLGKEY: + break; + + case MPGDRAM: + // DRAM write. One wait state. (only for normal Geneve) + m_dram[dec->physaddr] = data; + if (TRACE_WRITE) logerror("%s: Write DRAM %04x (%06x) <- %02x\n", tag(), offset, dec->physaddr, data); + break; + + case MPGEXP: + // On-board memory expansion for standard Geneve (never used) + if (TRACE_WRITE) logerror("%s: Write unmapped area %06x\n", tag(), dec->physaddr); + break; + + case MPGEPROM: + // 1 111. ..xx xxxx xxxx xxxx on-board eprom (16K) + // mirrored for f0, f2, f4, ...; f1, f3, f5, ... + // Ignore EPROM write (unless PFM) + if (m_pfm_mode != 0) write_to_pfm(space, dec->physaddr, data, 0xff); + else + logerror("%s: Write EPROM %04x (%06x) <- %02x, ignored\n", tag(), offset, dec->physaddr, data); + break; + + case MPGSRAM: + if ((dec->physaddr & m_sram_mask)==m_sram_val) + { + m_sram[dec->physaddr & ~m_sram_mask] = data; + } + if (TRACE_WRITE) logerror("%s: Write SRAM %04x (%06x) <- %02x\n", tag(), offset, dec->physaddr, data); + break; + + case MPGBOX: + dec->physaddr = (dec->physaddr & 0x0007ffff); // 19 bit address + if (TRACE_WRITE) logerror("%s: Write P-Box %04x (%06x) <- %02x\n", tag(), offset, dec->physaddr, data); + m_peribox->write(space, dec->physaddr, data, 0xff); + break; + + case MPGMDRAM: + // DRAM. One wait state. + m_dram[dec->physaddr] = data; + break; + + case MPGMEPROM: + // 1 111. ..xx xxxx xxxx xxxx on-board eprom (16K) + // mirrored for f0, f2, f4, ...; f1, f3, f5, ... + // Ignore EPROM write + if (m_pfm_mode != 0) write_to_pfm(space, dec->physaddr, data, 0xff); + else + logerror("%s: Write EPROM %04x (%06x) <- %02x, ignored\n", tag(), offset, dec->physaddr, data); + break; + + case MPGMBOX: + // Route everything else to the P-Box + m_peribox->write(space, dec->physaddr, data, 0xff); + break; + } +} + +void geneve_mapper_device::decode(address_space& space, offs_t offset, bool read_mode, geneve_mapper_device::decdata* dec) +{ + dec->function = 0; + dec->offset = offset; + dec->physaddr = 0; + + int page; + + if (read_mode) // got this from DBIN + { + // Logical addresses + if (m_geneve_mode) + { + // TODO: shortcut offset & 0xffc0 = 0xf100 + if ((offset & 0xfff5)==0xf100) + { + // video + // ++++ ++++ ++++ -+-+ + // 1111 0001 0000 0000 + // 1111 0001 0000 0010 + // 1111 0001 0000 1000 + // 1111 0001 0000 1010 + + dec->function = MLGVIDEO; + set_wait(1); + return; + } + if ((offset & 0xfff8)==0xf110) + { + // mapper + dec->function = MLGMAPPER; + dec->offset = dec->offset & 0x0007; + set_wait(1); + return; + } + if ((offset & 0xfff8) == 0xf118) + { + // key + dec->function = MLGKEY; + set_wait(1); + return; + } + if ((offset & 0xfff0)==0xf130) + { + // clock + // tests on the real machine showed that + // upper nibble is 0xf (probably because of the location at 0xf130?) + dec->function = MLGCLOCK; + dec->offset = dec->offset & 0x000f; + set_wait(1); + return; + } + } + else + { + if ((offset & 0xfff8)==0x8000) + { + // mapper + dec->function = MLTMAPPER; + dec->offset = dec->offset & 0x0007; + set_wait(1); + return; + } + if ((offset & 0xfff8)== 0x8008) + { + // key + dec->function = MLTKEY; + set_wait(1); + return; + } + if ((offset & 0xfff0)==0x8010) + { + // clock + dec->function = MLTCLOCK; + dec->offset = dec->offset & 0x000f; + set_wait(1); + return; + } + if ((offset & 0xfc01)==0x8800) + { + // video + // ++++ ++-- ---- ---+ + // 1000 1000 0000 00x0 + // 1 WS is always added; any pending video waitstates are canceled + dec->function = MLTVIDEO; + set_wait(1); + return; + } + if ((offset & 0xfc01)==0x9000) + { + // speech + // ++++ ++-- ---- ---+ + // 1001 0000 0000 0000 + // We need to add the address prefix bits + dec->function = MLTSPEECH; + dec->offset = offset | ((m_genmod)? 0x170000 : 0x070000); + m_peribox->setaddress_dbin(space, dec->offset, read_mode); + set_wait(1); + return; + } + if ((offset & 0xfc01)==0x9800) + { + // grom simulation + // ++++ ++-- ---- ---+ + // 1001 1000 0000 00x0 + dec->function = MLTGROM; + set_wait(1); + return; + } + } + // still here? Then go via mapping. + page = (offset & 0xe000) >> 13; + + // Determine physical address + if (m_direct_mode) + { + dec->physaddr = 0x1f0000; // points to boot eprom (page F8) + } + else + { + if (!m_geneve_mode && page==3) + { + if (m_cartridge_size==0x4000 && m_cartridge_secondpage) dec->physaddr = 0x06e000; + else dec->physaddr = 0x06c000; + } + else + { + dec->physaddr = (m_map[page] << 13); + } + } + dec->physaddr |= (offset & 0x1fff); + + if (!m_genmod) // Standard Geneve + { + if ((dec->physaddr & 0x180000)==0x000000) + { + // DRAM. + dec->physaddr = dec->physaddr & 0x07ffff; + dec->function = MPGDRAM; + set_wait(1); + return; + } + + if ((dec->physaddr & 0x180000)==0x080000) + { + // On-board memory expansion for standard Geneve (never used) + dec->function = MPGEXP; + set_wait(1); + return; + } + + if ((dec->physaddr & 0x1e0000)==0x1e0000) + { + // 1 111. ..xx xxxx xxxx xxxx on-board eprom (16K) + // mirrored for f0, f2, f4, ...; f1, f3, f5, ... unless using PFM + dec->function = MPGEPROM; + set_wait(0); + return; + } + + if ((dec->physaddr & 0x180000)==0x180000) + { + dec->function = MPGSRAM; + set_wait(0); + return; + } + + // Route everything else to the P-Box + // 0x000000-0x07ffff for the stock Geneve (AMC,AMB,AMA,A0 ...,A15) + // 0x000000-0x1fffff for the GenMod.(AME,AMD,AMC,AMB,AMA,A0 ...,A15) + // Add a wait state + set_wait(1); + dec->function = MPGBOX; + + dec->physaddr = (dec->physaddr & 0x0007ffff); // 19 bit address (with AMA..AMC) + m_peribox->setaddress_dbin(space, dec->physaddr, read_mode); + return; + } + else + { + // GenMod mode + if ((m_timode) && ((dec->physaddr & 0x180000)==0x000000)) + { + // DRAM. One wait state. + dec->function = MPGMDRAM; + dec->physaddr = dec->physaddr & 0x07ffff; + if (!m_turbo) set_wait(1); + return; + } + + if ((dec->physaddr & 0x1e0000)==0x1e0000) + { + // 1 111. ..xx xxxx xxxx xxxx on-board eprom (16K) + // mirrored for f0, f2, f4, ...; f1, f3, f5, ... unless using PFM + dec->function = MPGMEPROM; + set_wait(0); + return; + } + + // Route everything else to the P-Box + dec->physaddr = (dec->physaddr & 0x001fffff); // 21 bit address for Genmod + dec->function = MPGMBOX; + + if (!m_turbo) set_wait(1); + // Check: Are waitstates completely turned off for turbo mode, or + // merely the waitstates for DRAM memory access and box access? + + m_peribox->setaddress_dbin(space, dec->physaddr, read_mode); + return; + } + } + else + { // Write access + // Logical addresses + if (m_geneve_mode) + { + if ((offset & 0xfff1)==0xf100) + { + // 1 WS is always added; any pending video waitstates are canceled + dec->function = MLGVIDEO; + set_wait(1); + return; + } + if ((offset & 0xfff8)==0xf110) + { + dec->function = MLGMAPPER; + dec->offset = dec->offset & 0x0007; + set_wait(1); + return; + } + if ((offset & 0xfff1)==0xf120) + { + // Add 24 waitstates. This is an average value, as the + // waitstate generation seems to depend on an external timer of + // the sound chip + // TODO: do it properly with the use of READY + dec->function = MLGSOUND; + set_wait(24); + return; + } + if ((offset & 0xfff0)==0xf130) + { + dec->function = MLGCLOCK; + dec->offset = dec->offset & 0x00f; + set_wait(1); + return; + } + } + else + { + // TI mode + if ((offset & 0xfff8)==0x8000) + { + dec->function = MLTMAPPER; + dec->offset = dec->offset & 0x0007; + set_wait(1); + return; + } + if ((offset & 0xfff0)==0x8010) + { + dec->function = MLTCLOCK; + dec->offset = dec->offset & 0x00f; + set_wait(1); + return; + } + if ((offset & 0xfc01)==0x9c00) + { + dec->function = MLTGROM; + set_wait(1); + return; + } + if ((offset & 0xfc01)==0x8400) + { + // Add 24 waitstates. This is an approximation, as the + // waitstate generation seems to depend on an external timer of + // the sound chip + // TODO: do it properly with the use of READY- + dec->function = MLTSOUND; + set_wait(24); + return; + } + if ((offset & 0xfc01)==0x8c00) + { + // 1 WS is always added; any pending video waitstates are canceled + dec->function = MLTVIDEO; + set_wait(1); + return; + } + + if ((offset & 0xfc01)==0x9400) + { + dec->function = MLTSPEECH; + dec->offset = dec->offset | ((m_genmod)? 0x170000 : 0x070000); + m_peribox->setaddress_dbin(space, dec->offset, read_mode); + set_wait(1); + return; + } + } + + // Determine physical address + page = (dec->offset & 0xe000) >> 13; + + if (m_direct_mode) + { + dec->physaddr = 0x1e0000; // points to boot eprom + } + else + { + if (!m_geneve_mode && page==3) + { + if (m_cartridge_size==0x4000) + { + m_cartridge_secondpage = ((dec->offset & 0x0002)!=0); + if (TRACE_WRITE) logerror("%s: Set cartridge page %02x\n", tag(), m_cartridge_secondpage); + set_wait(1); + return; + } + else + { + // writing into cartridge rom space (no bankswitching) + if ((((dec->offset & 0x1000)==0x0000) && !m_cartridge6_writable) + || (((dec->offset & 0x1000)==0x1000) && !m_cartridge7_writable)) + { + logerror("%s: Writing to protected cartridge space %04x ignored\n", tag(), dec->offset); + return; + } + else + // TODO: Check whether secondpage is really ignored + dec->physaddr = 0x06c000; + } + } + else + dec->physaddr = (m_map[page] << 13); + } + + dec->physaddr |= dec->offset & 0x1fff; + + if (!m_genmod) + { + if ((dec->physaddr & 0x180000)==0x000000) + { + dec->function = MPGDRAM; + dec->physaddr = dec->physaddr & 0x07ffff; + set_wait(1); + return; + } + if ((dec->physaddr & 0x180000)==0x080000) + { + dec->function = MPGEXP; + set_wait(1); + return; + } + + if ((dec->physaddr & 0x1e0000)==0x1e0000) + { + dec->function = MPGEPROM; + set_wait(0); // EPROM + return; + } + if ((dec->physaddr & 0x180000)==0x180000) + { + dec->function = MPGSRAM; + set_wait(0); // SRAM + return; + } + + // Route everything else to the P-Box + // Add a wait state + + // only AMA, AMB, AMC are used; AMD and AME are not used + dec->function = MPGBOX; + dec->physaddr = (dec->physaddr & 0x0007ffff); // 19 bit address + m_peribox->setaddress_dbin(space, dec->physaddr, read_mode); + set_wait(1); + } + else + { + // GenMod mode + if ((dec->physaddr & 0x1e0000)==0x1e0000) + { // EPROM, ignore (unless PFM) + dec->function = MPGMEPROM; + set_wait(0); + return; + } + + if (m_timode && ((dec->physaddr & 0x180000)==0x000000)) + { + dec->function = MPGMDRAM; + dec->physaddr = dec->physaddr & 0x07ffff; + if (!m_turbo) set_wait(1); + return; + } + + // Route everything else to the P-Box + dec->function = MPGMBOX; + dec->physaddr = (dec->physaddr & 0x001fffff); // 21 bit address for Genmod + m_peribox->setaddress_dbin(space, dec->physaddr, read_mode); + if (!m_turbo) set_wait(1); + } + } +} + +/* + Read from PFM. +*/ +READ8_MEMBER( geneve_mapper_device::read_from_pfm ) +{ + UINT8 value = 0; + if (!m_pfm_output_enable) return 0; + + int address = (offset & 0x01ffff) | (m_pfm_bank<<17); + + switch (m_pfm_mode) + { + case 1: + value = m_pfm512->read(space, address, mem_mask); + break; + case 2: + value = m_pfm512a->read(space, address, mem_mask); + break; + default: + logerror("%s: Illegal mode for reading PFM: %d\n", tag(), m_pfm_mode); + return 0; + } + + if (TRACE_PFM) logerror("%s: Reading from PFM at address %05x -> %02x\n", tag(), address, value); + return value; +} + +WRITE8_MEMBER( geneve_mapper_device::write_to_pfm ) +{ + // Nota bene: The PFM must be write protected on startup, or the RESET + // of the 9995 will attempt to write the return vector into the flash EEPROM + int address = (offset & 0x01ffff) | (m_pfm_bank<<17); + if (TRACE_PFM) logerror("%s: Writing to PFM at address %05x <- %02x\n", tag(), address, data); + + switch (m_pfm_mode) + { + case 1: + m_pfm512->write(space, address, data, mem_mask); + break; + case 2: + m_pfm512a->write(space, address, data, mem_mask); + break; + default: + logerror("%s: Illegal mode for writing to PFM: %d\n", tag(), m_pfm_mode); + } +} + + +/* + Accept the address passed over the address bus and decode it appropriately. + This decoding will later be used in the READ/WRITE member functions. Also, + we initiate wait state creation here. +*/ +SETOFFSET_MEMBER( geneve_mapper_device::setoffset ) +{ + if (TRACE_DETAIL) logerror("%s: setoffset = %04x\n", tag(), offset); + m_debug_no_ws = false; + decode(space, offset, m_read_mode, &m_decoded); +} + +/* + The mapper is connected to the clock line in order to operate + the wait state counter. + The wait counter is decremented on each rising clock edge; when 0, the + READY line is asserted. However, there is a second counter which is used for + video wait states. + The READY line must be asserted when the wait counter reaches 0, but must be + cleared immediately again if the video counter has not reached 0. + (See comments at the file header: The additional video wait states do not + affect the video access itself but become effective after the access; if + the code runs on the chip, these wait states are ignored.) +*/ +WRITE_LINE_MEMBER( geneve_mapper_device::clock_in ) +{ + if (state==ASSERT_LINE) + { + // Rising edge + if (!m_ready_asserted) + { + if (m_waitcount > 0) + { + m_waitcount--; + if (m_waitcount == 0) + { + if (TRACE_CLOCK) logerror("%s: clock, READY asserted\n", tag()); + m_ready(ASSERT_LINE); + m_ready_asserted = true; + } + else + { + if (TRACE_CLOCK) logerror("%s: clock\n", tag()); + } + } + else + { + if (m_ext_waitcount > 0) + { + m_ext_waitcount--; + if (m_ext_waitcount == 0) + { + if (TRACE_CLOCK) logerror("%s: clock, READY asserted after video\n", tag()); + m_ready(ASSERT_LINE); + m_ready_asserted = true; + } + else + { + if (TRACE_CLOCK) logerror("%s: vclock, ew=%d\n", tag(), m_ext_waitcount); + } + } + } + } + } + else + { + // Falling edge + // Do we have video wait states? In that case, clear the line again + if ((m_waitcount == 0) && (m_ext_waitcount > 0) && m_ready_asserted) + { + if (TRACE_CLOCK) logerror("%s: clock, READY cleared for video\n", tag()); + m_ready(CLEAR_LINE); + m_ready_asserted = false; + } + } +} + +/* + We need the DBIN line for the setoffset operation. +*/ +WRITE_LINE_MEMBER( geneve_mapper_device::dbin_in ) +{ + m_read_mode = (state==ASSERT_LINE); + if (TRACE_DETAIL) logerror("%s: dbin = %02x\n", tag(), m_read_mode? 1:0); +} + +/* + PFM expansion: Setting the bank. +*/ +WRITE_LINE_MEMBER( geneve_mapper_device::pfm_select_lsb ) +{ + if (state==ASSERT_LINE) m_pfm_bank |= 1; + else m_pfm_bank &= 0xfe; + if (TRACE_PFM) logerror("%s: Setting bank (l) = %d\n", tag(), m_pfm_bank); +} + +WRITE_LINE_MEMBER( geneve_mapper_device::pfm_select_msb ) +{ + if (state==ASSERT_LINE) m_pfm_bank |= 2; + else m_pfm_bank &= 0xfd; + if (TRACE_PFM) logerror("%s: Setting bank (u) = %d\n", tag(), m_pfm_bank); +} + +WRITE_LINE_MEMBER( geneve_mapper_device::pfm_output_enable ) +{ + // Negative logic + m_pfm_output_enable = (state==CLEAR_LINE); + if (TRACE_PFM) logerror("%s: PFM output %s\n", tag(), m_pfm_output_enable? "enable" : "disable"); +} + +//==================================================================== +// Common device lifecycle +//==================================================================== + +void geneve_mapper_device::device_start() +{ + // Get pointers + m_peribox = machine().device(PERIBOX_TAG); + m_keyboard = machine().device(GKEYBOARD_TAG); + m_video = machine().device(VIDEO_SYSTEM_TAG); + m_sound = machine().device(TISOUND_TAG); + m_clock = machine().device(GCLOCK_TAG); + + // PFM expansion + m_pfm512 = machine().device(PFM512_TAG); + m_pfm512a = machine().device(PFM512A_TAG); + + m_ready.resolve(); + + m_sram = machine().root_device().memregion(SRAM_TAG)->base(); + m_dram = machine().root_device().memregion(DRAM_TAG)->base(); + m_cpu = static_cast(machine().device("maincpu")); + + m_geneve_mode = false; + m_direct_mode = true; +} + +void geneve_mapper_device::device_reset() +{ + m_extra_waitstates = false; + m_video_waitstates = true; + m_read_mode = false; + m_waitcount = 0; + m_ext_waitcount = 0; + m_ready_asserted = true; + + m_geneve_mode =false; + m_direct_mode = true; + m_cartridge_size = 0x4000; + m_cartridge_secondpage = false; + m_cartridge6_writable = false; + m_cartridge7_writable = false; + m_grom_address = 0; + m_pfm_bank = 0; + m_pfm_output_enable = true; + + // Clear map + for (int i=0; i < 8; i++) m_map[i] = 0; + + m_genmod = false; + + // Check which boot EPROM we are using (or PFM) + set_boot_rom(machine().root_device().ioport("BOOTROM")->read()); + + // Check for GenMod. We assume that GenMod can be combined with PFM. + if (machine().root_device().ioport("MODE")->read()!=0) + { + logerror("%s: Using GenMod modification\n", tag()); + m_eprom = machine().root_device().memregion("maincpu")->base() + 0x8000; + if (m_eprom[0] != 0xf0) + { + fatalerror("genboard: GenMod boot ROM missing\n"); + } + m_genmod = true; + m_turbo = ((machine().root_device().ioport("GENMODDIPS")->read() & GM_TURBO)!=0); + m_timode = ((machine().root_device().ioport("GENMODDIPS")->read() & GM_TIM)!=0); + } + + switch (machine().root_device().ioport("SRAM")->read()) + { +/* 1 100. .... .... .... .... on-board sram (128K) -+ + 1 101. .... .... .... .... on-board sram (128K) -+-- maximum SRAM expansion + 1 1100 .... .... .... .... on-board sram (64K) --+ + 1 1101 0... .... .... .... on-board sram (32K) - additional 32 KiB required for MDOS 2.50s and higher + 1 1101 1... .... .... .... on-board sram (32K) - standard setup +*/ + case 0: // 32 KiB + m_sram_mask = 0x1f8000; + m_sram_val = 0x1d8000; + break; + case 1: // 64 KiB + m_sram_mask = 0x1f0000; + m_sram_val = 0x1d0000; + break; + case 2: // 384 KiB (actually 512 KiB, but the EPROM masks the upper 128 KiB) + m_sram_mask = 0x180000; + m_sram_val = 0x180000; + break; + } +} + +const device_type GENEVE_MAPPER = &device_creator; + +/**************************************************************************** + Keyboard support +****************************************************************************/ + +static const char *const KEYNAMES[] = { "KEY0", "KEY1", "KEY2", "KEY3", "KEY4", "KEY5", "KEY6", "KEY7" }; + +static const UINT8 MF1_CODE[0xe] = +{ + /* extended keys that are equivalent to non-extended keys */ + 0x1c, /* keypad enter */ + 0x1d, /* right control */ + 0x38, /* alt gr */ + // extra codes are 0x5b for Left Windows, 0x5c for Right Windows, 0x5d + // for Menu, 0x5e for power, 0x5f for sleep, 0x63 for wake, but I doubt + // any Geneve program would take advantage of these. */ + + // extended key that is equivalent to a non-extended key + // with shift off + 0x35, /* pad slash */ + + // extended keys that are equivalent to non-extended keys + // with numlock off + 0x47, /* home */ + 0x48, /* up */ + 0x49, /* page up */ + 0x4b, /* left */ + 0x4d, /* right */ + 0x4f, /* end */ + 0x50, /* down */ + 0x51, /* page down */ + 0x52, /* insert */ + 0x53 /* delete */ +}; + +geneve_keyboard_device::geneve_keyboard_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) +: device_t(mconfig, GENEVE_KEYBOARD, "Geneve XT-style keyboard", tag, owner, clock, "geneve_keyboard", __FILE__), + m_interrupt(*this) +{ +} + +void geneve_keyboard_device::post_in_key_queue(int keycode) +{ + m_key_queue[(m_key_queue_head + m_key_queue_length) % KEYQUEUESIZE] = keycode; + m_key_queue_length++; + + if (TRACE_KEYBOARD) logerror("%s: Posting keycode %02x\n", tag(), keycode); +} + +void geneve_keyboard_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + poll(); +} + +void geneve_keyboard_device::poll() +{ + UINT32 keystate; + UINT32 key_transitions; + int i, j; + int keycode; + int pressed; + if (TRACE_KEYBOARD) logerror("%s: Poll keyboard\n", tag()); + if (m_key_reset) return; + + /* Poll keyboard */ + for (i = 0; (i < 4) && (m_key_queue_length <= (KEYQUEUESIZE-MAXKEYMSGLENGTH)); i++) + { + keystate = ioport(KEYNAMES[2*i])->read() | (ioport(KEYNAMES[2*i + 1])->read() << 16); + key_transitions = keystate ^ m_key_state_save[i]; + if (key_transitions) + { + for (j = 0; (j < 32) && (m_key_queue_length <= (KEYQUEUESIZE-MAXKEYMSGLENGTH)); j++) + { + if ((key_transitions >> j) & 1) + { + keycode = (i << 5) | j; + pressed = ((keystate >> j) & 1); + if (pressed) + m_key_state_save[i] |= (1 << j); + else + m_key_state_save[i] &= ~ (1 << j); + + /* Update auto-repeat */ + if (pressed) + { + m_key_autorepeat_key = keycode; + m_key_autorepeat_timer = KEYAUTOREPEATDELAY+1; + } + else /*if (keycode == m_key_autorepeat_key)*/ + m_key_autorepeat_key = 0; + + // Release Fake Shift/Unshift if another key is pressed + // We do so if a key is released, though it is actually + // required only if it is a modifier key + /*if (pressed)*/ + //{ + if (m_key_fake_shift_state) + { + /* Fake shift release */ + post_in_key_queue(0xe0); + post_in_key_queue(0xaa); + m_key_fake_shift_state = false; + } + if (m_key_fake_unshift_state) + { + /* Fake shift press */ + post_in_key_queue(0xe0); + post_in_key_queue(0x2a); + m_key_fake_unshift_state = false; + } + //} + + /* update shift and numlock state */ + if ((keycode == 0x2a) || (keycode == 0x36)) + m_key_real_shift_state = m_key_real_shift_state + (pressed ? +1 : -1); + if ((keycode == 0x1d) || (keycode == 0x61)) + m_key_ctrl_state = m_key_ctrl_state + (pressed ? +1 : -1); + if ((keycode == 0x38) || (keycode == 0x62)) + m_key_alt_state = m_key_alt_state + (pressed ? +1 : -1); + if ((keycode == 0x45) && pressed) + m_key_numlock_state = !m_key_numlock_state; + + if ((keycode >= 0x60) && (keycode < 0x6e)) + { /* simpler extended keys */ + /* these keys are emulated */ + + if ((keycode >= 0x63) && pressed) + { + /* Handle shift state */ + if (keycode == 0x63) + { /* non-shifted key */ + if (m_key_real_shift_state!=0) + /* Fake shift unpress */ + m_key_fake_unshift_state = true; + } + else /*if (keycode >= 0x64)*/ + { /* non-numlock mode key */ + if (m_key_numlock_state & (m_key_real_shift_state==0)) + /* Fake shift press if numlock is active */ + m_key_fake_shift_state = true; + else if ((!m_key_numlock_state) & (m_key_real_shift_state!=0)) + /* Fake shift unpress if shift is down */ + m_key_fake_unshift_state = true; + } + + if (m_key_fake_shift_state) + { + post_in_key_queue(0xe0); + post_in_key_queue(0x2a); + } + + if (m_key_fake_unshift_state) + { + post_in_key_queue(0xe0); + post_in_key_queue(0xaa); + } + } + + keycode = MF1_CODE[keycode-0x60]; + if (!pressed) keycode |= 0x80; + post_in_key_queue(0xe0); + post_in_key_queue(keycode); + } + else if (keycode == 0x6e) + { /* emulate Print Screen / System Request (F13) key */ + /* this is a bit complex, as Alt+PrtScr -> SysRq */ + /* Additionally, Ctrl+PrtScr involves no fake shift press */ + if (m_key_alt_state!=0) + { + /* SysRq */ + keycode = 0x54; + if (!pressed) keycode |= 0x80; + post_in_key_queue(keycode); + } + else + { + /* Handle shift state */ + if (pressed && (m_key_real_shift_state==0) && (m_key_ctrl_state==0)) + { /* Fake shift press */ + post_in_key_queue(0xe0); + post_in_key_queue(0x2a); + m_key_fake_shift_state = true; + } + + keycode = 0x37; + if (!pressed) keycode |= 0x80; + post_in_key_queue(0xe0); + post_in_key_queue(keycode); + } + } + else if (keycode == 0x6f) + { // emulate pause (F15) key + // this is a bit complex, as Pause -> Ctrl+NumLock and + // Ctrl+Pause -> Ctrl+ScrLock. Furthermore, there is no + // repeat or release. + if (pressed) + { + if (m_key_ctrl_state!=0) + { + post_in_key_queue(0xe0); + post_in_key_queue(0x46); + post_in_key_queue(0xe0); + post_in_key_queue(0xc6); + } + else + { + post_in_key_queue(0xe1); + post_in_key_queue(0x1d); + post_in_key_queue(0x45); + post_in_key_queue(0xe1); + post_in_key_queue(0x9d); + post_in_key_queue(0xc5); + } + } + } + else + { + if (!pressed) keycode |= 0x80; + post_in_key_queue(keycode); + } + signal_when_key_available(); + } + } + } + } + + /* Handle auto-repeat */ + if ((m_key_queue_length <= (KEYQUEUESIZE-MAXKEYMSGLENGTH)) && (m_key_autorepeat_key!=0) && (--m_key_autorepeat_timer == 0)) + { + if ((m_key_autorepeat_key >= 0x60) && (m_key_autorepeat_key < 0x6e)) + { + post_in_key_queue(0xe0); + post_in_key_queue(MF1_CODE[m_key_autorepeat_key-0x60]); + } + else if (m_key_autorepeat_key == 0x6e) + { + if (m_key_alt_state!=0) + post_in_key_queue(0x54); + else + { + post_in_key_queue(0xe0); + post_in_key_queue(0x37); + } + } + else if (m_key_autorepeat_key == 0x6f) + ; + else + { + post_in_key_queue(m_key_autorepeat_key); + } + signal_when_key_available(); + m_key_autorepeat_timer = KEYAUTOREPEATRATE; + } +} + +UINT8 geneve_keyboard_device::get_recent_key() +{ + if (m_key_in_buffer) return m_key_queue[m_key_queue_head]; + else return 0; +} + +void geneve_keyboard_device::signal_when_key_available() +{ + // if keyboard reset is not asserted, and key clock is enabled, and key + // buffer clear is disabled, and key queue is not empty. */ + if ((!m_key_reset) && (m_keyboard_clock) && (m_keep_keybuf) && (m_key_queue_length != 0)) + { + if (TRACE_KEYBOARD) logerror("%s: Signalling key available\n", tag()); + m_interrupt(ASSERT_LINE); + m_key_in_buffer = true; + } +} + +WRITE_LINE_MEMBER( geneve_keyboard_device::clock_control ) +{ + bool rising_edge = (!m_keyboard_clock && (state==ASSERT_LINE)); + m_keyboard_clock = (state==ASSERT_LINE); + if (TRACE_KEYBOARD) logerror("%s: Keyboard clock_control state=%d\n", tag(), m_keyboard_clock); + if (rising_edge) + signal_when_key_available(); +} + +WRITE_LINE_MEMBER( geneve_keyboard_device::send_scancodes ) +{ + bool rising_edge = (!m_keep_keybuf && (state==ASSERT_LINE)); + bool falling_edge = (m_keep_keybuf && (state==CLEAR_LINE)); + m_keep_keybuf = (state==ASSERT_LINE); + + if (rising_edge) signal_when_key_available(); + else + { + if (falling_edge) + { + if (m_key_queue_length != 0) + { + m_key_queue_head = (m_key_queue_head + 1) % KEYQUEUESIZE; + m_key_queue_length--; + } + /* clear keyboard interrupt */ + m_interrupt(CLEAR_LINE); + m_key_in_buffer = false; + } + } +} + +WRITE_LINE_MEMBER( geneve_keyboard_device::reset_line ) +{ + m_key_reset = !(state==ASSERT_LINE); + + if (m_key_reset) + { + /* reset -> clear keyboard key queue, but not geneve key buffer */ + m_key_queue_length = (m_key_in_buffer)? 1 : 0; + m_key_queue_head = 0; + memset(m_key_state_save, 0, sizeof(m_key_state_save)); + m_key_numlock_state = false; + m_key_ctrl_state = 0; + m_key_alt_state = 0; + m_key_real_shift_state = 0; + m_key_fake_shift_state = false; + m_key_fake_unshift_state = false; + m_key_autorepeat_key = 0; + } +} + +void geneve_keyboard_device::device_start() +{ + m_timer = timer_alloc(0); + m_interrupt.resolve(); +} + +void geneve_keyboard_device::device_reset() +{ + m_key_in_buffer = false; + reset_line(CLEAR_LINE); + m_key_queue_length = 0; + m_key_reset = true; + m_keyboard_clock = false; + m_keep_keybuf = false; + m_timer->adjust(attotime::from_usec(1), 0, attotime::from_hz(120)); +} + +INPUT_PORTS_START( genkeys ) + PORT_START("KEY0") /* IN3 */ + PORT_BIT ( 0x0001, 0x0000, IPT_UNUSED ) /* unused scancode 0 */ + PORT_BIT(0x0002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Esc") PORT_CODE(KEYCODE_ESC) /* Esc 01 81 */ + PORT_BIT(0x0004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("1 !") PORT_CODE(KEYCODE_1) /* 1 02 82 */ + PORT_BIT(0x0008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("2 @") PORT_CODE(KEYCODE_2) /* 2 03 83 */ + PORT_BIT(0x0010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("3 #") PORT_CODE(KEYCODE_3) /* 3 04 84 */ + PORT_BIT(0x0020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("4 $") PORT_CODE(KEYCODE_4) /* 4 05 85 */ + PORT_BIT(0x0040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("5 %") PORT_CODE(KEYCODE_5) /* 5 06 86 */ + PORT_BIT(0x0080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("6 ^") PORT_CODE(KEYCODE_6) /* 6 07 87 */ + PORT_BIT(0x0100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("7 &") PORT_CODE(KEYCODE_7) /* 7 08 88 */ + PORT_BIT(0x0200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("8 *") PORT_CODE(KEYCODE_8) /* 8 09 89 */ + PORT_BIT(0x0400, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("9 (") PORT_CODE(KEYCODE_9) /* 9 0A 8A */ + PORT_BIT(0x0800, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("0 )") PORT_CODE(KEYCODE_0) /* 0 0B 8B */ + PORT_BIT(0x1000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("- _") PORT_CODE(KEYCODE_MINUS) /* - 0C 8C */ + PORT_BIT(0x2000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("= +") PORT_CODE(KEYCODE_EQUALS) /* = 0D 8D */ + PORT_BIT(0x4000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Backspace") PORT_CODE(KEYCODE_BACKSPACE) /* Backspace 0E 8E */ + PORT_BIT(0x8000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Tab") PORT_CODE(KEYCODE_TAB) /* Tab 0F 8F */ + + PORT_START("KEY1") /* IN4 */ + PORT_BIT(0x0001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Q") PORT_CODE(KEYCODE_Q) /* Q 10 90 */ + PORT_BIT(0x0002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("W") PORT_CODE(KEYCODE_W) /* W 11 91 */ + PORT_BIT(0x0004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("E") PORT_CODE(KEYCODE_E) /* E 12 92 */ + PORT_BIT(0x0008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("R") PORT_CODE(KEYCODE_R) /* R 13 93 */ + PORT_BIT(0x0010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("T") PORT_CODE(KEYCODE_T) /* T 14 94 */ + PORT_BIT(0x0020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Y") PORT_CODE(KEYCODE_Y) /* Y 15 95 */ + PORT_BIT(0x0040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("U") PORT_CODE(KEYCODE_U) /* U 16 96 */ + PORT_BIT(0x0080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("I") PORT_CODE(KEYCODE_I) /* I 17 97 */ + PORT_BIT(0x0100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("O") PORT_CODE(KEYCODE_O) /* O 18 98 */ + PORT_BIT(0x0200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("P") PORT_CODE(KEYCODE_P) /* P 19 99 */ + PORT_BIT(0x0400, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("[ {") PORT_CODE(KEYCODE_OPENBRACE) /* [ 1A 9A */ + PORT_BIT(0x0800, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("] }") PORT_CODE(KEYCODE_CLOSEBRACE) /* ] 1B 9B */ + PORT_BIT(0x1000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Enter") PORT_CODE(KEYCODE_ENTER) /* Enter 1C 9C */ + PORT_BIT(0x2000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("L-Ctrl") PORT_CODE(KEYCODE_LCONTROL) /* Left Ctrl 1D 9D */ + PORT_BIT(0x4000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("A") PORT_CODE(KEYCODE_A) /* A 1E 9E */ + PORT_BIT(0x8000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("S") PORT_CODE(KEYCODE_S) /* S 1F 9F */ + + PORT_START("KEY2") /* IN5 */ + PORT_BIT(0x0001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("D") PORT_CODE(KEYCODE_D) /* D 20 A0 */ + PORT_BIT(0x0002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F") PORT_CODE(KEYCODE_F) /* F 21 A1 */ + PORT_BIT(0x0004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("G") PORT_CODE(KEYCODE_G) /* G 22 A2 */ + PORT_BIT(0x0008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("H") PORT_CODE(KEYCODE_H) /* H 23 A3 */ + PORT_BIT(0x0010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("J") PORT_CODE(KEYCODE_J) /* J 24 A4 */ + PORT_BIT(0x0020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("K") PORT_CODE(KEYCODE_K) /* K 25 A5 */ + PORT_BIT(0x0040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("L") PORT_CODE(KEYCODE_L) /* L 26 A6 */ + PORT_BIT(0x0080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("; :") PORT_CODE(KEYCODE_COLON) /* ; 27 A7 */ + PORT_BIT(0x0100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("' \"") PORT_CODE(KEYCODE_QUOTE) /* ' 28 A8 */ + PORT_BIT(0x0200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("` ~") PORT_CODE(KEYCODE_TILDE) /* ` 29 A9 */ + PORT_BIT(0x0400, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("L-Shift") PORT_CODE(KEYCODE_LSHIFT) /* Left Shift 2A AA */ + PORT_BIT(0x0800, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("\\ |") PORT_CODE(KEYCODE_BACKSLASH) /* \ 2B AB */ + PORT_BIT(0x1000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Z") PORT_CODE(KEYCODE_Z) /* Z 2C AC */ + PORT_BIT(0x2000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("X") PORT_CODE(KEYCODE_X) /* X 2D AD */ + PORT_BIT(0x4000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("C") PORT_CODE(KEYCODE_C) /* C 2E AE */ + PORT_BIT(0x8000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("V") PORT_CODE(KEYCODE_V) /* V 2F AF */ + + PORT_START("KEY3") /* IN6 */ + PORT_BIT(0x0001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("B") PORT_CODE(KEYCODE_B) /* B 30 B0 */ + PORT_BIT(0x0002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("N") PORT_CODE(KEYCODE_N) /* N 31 B1 */ + PORT_BIT(0x0004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("M") PORT_CODE(KEYCODE_M) /* M 32 B2 */ + PORT_BIT(0x0008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME(", <") PORT_CODE(KEYCODE_COMMA) /* , 33 B3 */ + PORT_BIT(0x0010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME(". >") PORT_CODE(KEYCODE_STOP) /* . 34 B4 */ + PORT_BIT(0x0020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("/ ?") PORT_CODE(KEYCODE_SLASH) /* / 35 B5 */ + PORT_BIT(0x0040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("R-Shift") PORT_CODE(KEYCODE_RSHIFT) /* Right Shift 36 B6 */ + PORT_BIT(0x0080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("KP * (PrtScr)") PORT_CODE(KEYCODE_ASTERISK ) /* Keypad * (PrtSc) 37 B7 */ + PORT_BIT(0x0100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Alt") PORT_CODE(KEYCODE_LALT) /* Left Alt 38 B8 */ + PORT_BIT(0x0200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Space") PORT_CODE(KEYCODE_SPACE) /* Space 39 B9 */ + PORT_BIT(0x0400, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Caps") PORT_CODE(KEYCODE_CAPSLOCK) /* Caps Lock 3A BA */ + PORT_BIT(0x0800, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F1") PORT_CODE(KEYCODE_F1) /* F1 3B BB */ + PORT_BIT(0x1000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F2") PORT_CODE(KEYCODE_F2) /* F2 3C BC */ + PORT_BIT(0x2000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F3") PORT_CODE(KEYCODE_F3) /* F3 3D BD */ + PORT_BIT(0x4000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F4") PORT_CODE(KEYCODE_F4) /* F4 3E BE */ + PORT_BIT(0x8000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F5") PORT_CODE(KEYCODE_F5) /* F5 3F BF */ + + PORT_START("KEY4") /* IN7 */ + PORT_BIT(0x0001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F6") PORT_CODE(KEYCODE_F6) /* F6 40 C0 */ + PORT_BIT(0x0002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F7") PORT_CODE(KEYCODE_F7) /* F7 41 C1 */ + PORT_BIT(0x0004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F8") PORT_CODE(KEYCODE_F8) /* F8 42 C2 */ + PORT_BIT(0x0008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F9") PORT_CODE(KEYCODE_F9) /* F9 43 C3 */ + PORT_BIT(0x0010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F10") PORT_CODE(KEYCODE_F10) /* F10 44 C4 */ + PORT_BIT(0x0020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("NumLock") PORT_CODE(KEYCODE_NUMLOCK) /* Num Lock 45 C5 */ + PORT_BIT(0x0040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("ScrLock (F14)") PORT_CODE(KEYCODE_SCRLOCK) /* Scroll Lock 46 C6 */ + PORT_BIT(0x0080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("KP 7 (Home)") PORT_CODE(KEYCODE_7_PAD ) /* Keypad 7 (Home) 47 C7 */ + PORT_BIT(0x0100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("KP 8 (Up)") PORT_CODE(KEYCODE_8_PAD ) /* Keypad 8 (Up arrow) 48 C8 */ + PORT_BIT(0x0200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("KP 9 (PgUp)") PORT_CODE(KEYCODE_9_PAD ) /* Keypad 9 (PgUp) 49 C9 */ + PORT_BIT(0x0400, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("KP -") PORT_CODE(KEYCODE_MINUS_PAD) /* Keypad - 4A CA */ + PORT_BIT(0x0800, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("KP 4 (Left)") PORT_CODE(KEYCODE_4_PAD ) /* Keypad 4 (Left arrow) 4B CB */ + PORT_BIT(0x1000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("KP 5") PORT_CODE(KEYCODE_5_PAD) /* Keypad 5 4C CC */ + PORT_BIT(0x2000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("KP 6 (Right)") PORT_CODE(KEYCODE_6_PAD ) /* Keypad 6 (Right arrow) 4D CD */ + PORT_BIT(0x4000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("KP +") PORT_CODE(KEYCODE_PLUS_PAD) /* Keypad + 4E CE */ + PORT_BIT(0x8000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("KP 1 (End)") PORT_CODE(KEYCODE_1_PAD ) /* Keypad 1 (End) 4F CF */ + + PORT_START("KEY5") /* IN8 */ + PORT_BIT(0x0001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("KP 2 (Down)") PORT_CODE(KEYCODE_2_PAD ) /* Keypad 2 (Down arrow) 50 D0 */ + PORT_BIT(0x0002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("KP 3 (PgDn)") PORT_CODE(KEYCODE_3_PAD ) /* Keypad 3 (PgDn) 51 D1 */ + PORT_BIT(0x0004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("KP 0 (Ins)") PORT_CODE(KEYCODE_0_PAD ) /* Keypad 0 (Ins) 52 D2 */ + PORT_BIT(0x0008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("KP . (Del)") PORT_CODE(KEYCODE_DEL_PAD ) /* Keypad . (Del) 53 D3 */ + PORT_BIT ( 0x0030, 0x0000, IPT_UNUSED ) + PORT_BIT(0x0040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("(84/102)\\") PORT_CODE(KEYCODE_BACKSLASH2) /* Backslash 2 56 D6 */ + PORT_BIT(0x0080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("(101)F11") PORT_CODE(KEYCODE_F11) /* F11 57 D7 */ + PORT_BIT(0x0100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("(101)F12") PORT_CODE(KEYCODE_F12) /* F12 58 D8 */ + PORT_BIT ( 0xfe00, 0x0000, IPT_UNUSED ) + + PORT_START("KEY6") /* IN9 */ + PORT_BIT(0x0001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("(101)KP Enter") PORT_CODE(KEYCODE_ENTER_PAD) /* PAD Enter 60 e0 */ + PORT_BIT(0x0002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("(101)R-Control") PORT_CODE(KEYCODE_RCONTROL) /* Right Control 61 e1 */ + PORT_BIT(0x0004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("(101)ALTGR") PORT_CODE(KEYCODE_RALT) /* ALTGR 64 e4 */ + + PORT_BIT(0x0008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("(101)KP /") PORT_CODE(KEYCODE_SLASH_PAD) /* PAD Slash 62 e2 */ + + PORT_BIT(0x0010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("(101)Home") PORT_CODE(KEYCODE_HOME) /* Home 66 e6 */ + PORT_BIT(0x0020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("(101)Cursor Up") PORT_CODE(KEYCODE_UP) /* Up 67 e7 */ + PORT_BIT(0x0040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("(101)Page Up") PORT_CODE(KEYCODE_PGUP) /* Page Up 68 e8 */ + PORT_BIT(0x0080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("(101)Cursor Left") PORT_CODE(KEYCODE_LEFT) /* Left 69 e9 */ + PORT_BIT(0x0100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("(101)Cursor Right") PORT_CODE(KEYCODE_RIGHT) /* Right 6a ea */ + PORT_BIT(0x0200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("(101)End") PORT_CODE(KEYCODE_END) /* End 6b eb */ + PORT_BIT(0x0400, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("(101)Cursor Down") PORT_CODE(KEYCODE_DOWN) /* Down 6c ec */ + PORT_BIT(0x0800, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("(101)Page Down") PORT_CODE(KEYCODE_PGDN) /* Page Down 6d ed */ + PORT_BIT(0x1000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("(101)Insert") PORT_CODE(KEYCODE_INSERT) /* Insert 6e ee */ + PORT_BIT(0x2000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("(101)Delete") PORT_CODE(KEYCODE_DEL) /* Delete 6f ef */ + + PORT_BIT(0x4000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("(101)PrtScr (F13)") PORT_CODE(KEYCODE_PRTSCR) /* Print Screen 63 e3 */ + PORT_BIT(0x8000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("(101)Pause (F15)") PORT_CODE(KEYCODE_PAUSE) /* Pause 65 e5 */ + + PORT_START("KEY7") /* IN10 */ + PORT_BIT ( 0xffff, 0x0000, IPT_UNUSED ) +#if 0 + PORT_BIT(0x0001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Print Screen") PORT_CODE(KEYCODE_PRTSCR) /* Print Screen alternate 77 f7 */ + PORT_BIT(0x2000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Left Win") /* Left Win 7d fd */ + PORT_BIT(0x4000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Right Win") /* Right Win 7e fe */ + PORT_BIT(0x8000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Menu") /* Menu 7f ff */ +#endif +INPUT_PORTS_END + +ioport_constructor geneve_keyboard_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( genkeys ); +} + +const device_type GENEVE_KEYBOARD = &device_creator; + +/**************************************************************************** + Mouse support +****************************************************************************/ + +geneve_mouse_device::geneve_mouse_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) +: device_t(mconfig, GENEVE_MOUSE, "Geneve mouse", tag, owner, clock, "geneve_mouse", __FILE__) +{ +} + +line_state geneve_mouse_device::left_button() +{ + return ((ioport("MOUSE0")->read() & 0x04)!=0)? ASSERT_LINE : CLEAR_LINE; +} + +void geneve_mouse_device::poll() +{ + int new_mx, new_my; + int delta_x, delta_y, buttons; + + buttons = ioport("MOUSE0")->read(); + new_mx = ioport("MOUSEX")->read(); + new_my = ioport("MOUSEY")->read(); + + /* compute x delta */ + delta_x = new_mx - m_last_mx; + + /* check for wrap */ + if (delta_x > 0x80) + delta_x = 0x100-delta_x; + if (delta_x < -0x80) + delta_x = -0x100-delta_x; + + m_last_mx = new_mx; + + /* compute y delta */ + delta_y = new_my - m_last_my; + + /* check for wrap */ + if (delta_y > 0x80) + delta_y = 0x100-delta_y; + if (delta_y < -0x80) + delta_y = -0x100-delta_y; + + m_last_my = new_my; + + // only middle and right button go to V9938 + m_v9938->update_mouse_state(delta_x, delta_y, buttons & 0x03); +} + +INPUT_PORTS_START( genmouse ) + PORT_START("MOUSEX") /* Mouse - X AXIS */ + PORT_BIT( 0xff, 0x00, IPT_TRACKBALL_X) PORT_SENSITIVITY(100) PORT_KEYDELTA(0) PORT_PLAYER(1) + + PORT_START("MOUSEY") /* Mouse - Y AXIS */ + PORT_BIT( 0xff, 0x00, IPT_TRACKBALL_Y) PORT_SENSITIVITY(100) PORT_KEYDELTA(0) PORT_PLAYER(1) + + PORT_START("MOUSE0") /* mouse buttons */ + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_BUTTON1) PORT_NAME("Left mouse button") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_BUTTON2) PORT_NAME("Right mouse button") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_BUTTON3) PORT_NAME("Middle mouse button") +INPUT_PORTS_END + +void geneve_mouse_device::device_start() +{ + m_v9938 = machine().device(VDP_TAG); +} + +void geneve_mouse_device::device_reset() +{ + m_last_mx = 0; + m_last_my = 0; +} + +ioport_constructor geneve_mouse_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( genmouse ); +} + +const device_type GENEVE_MOUSE = &device_creator; diff --git a/src/devices/bus/ti99x/genboard.h b/src/devices/bus/ti99x/genboard.h new file mode 100644 index 00000000000..d9905ba9168 --- /dev/null +++ b/src/devices/bus/ti99x/genboard.h @@ -0,0 +1,220 @@ +// license:LGPL-2.1+ +// copyright-holders:Michael Zapf +/**************************************************************************** + + Geneve main board components. + See genboard.c for documentation. + + Michael Zapf + + February 2012: Rewritten as class + +*****************************************************************************/ +#ifndef __GENBOARD__ +#define __GENBOARD__ + +#include "emu.h" +#include "ti99defs.h" +#include "machine/mm58274c.h" +#include "video/v9938.h" +#include "cpu/tms9900/tms9995.h" +#include "machine/at29x.h" + +extern const device_type GENEVE_MOUSE; +extern const device_type GENEVE_KEYBOARD; +extern const device_type GENEVE_MAPPER; + +/*****************************************************************************/ + +class geneve_mouse_device : public device_t +{ +public: + geneve_mouse_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + void poll(); + line_state left_button(); // left button is not connected to the V9938 but to a TMS9901 pin + +protected: + virtual void device_start(); + virtual void device_reset(); + virtual ioport_constructor device_input_ports() const; + +private: + v9938_device* m_v9938; + int m_last_mx; + int m_last_my; +}; + +#define MCFG_GENEVE_MOUSE_ADD(_tag ) \ + MCFG_DEVICE_ADD(_tag, GENEVE_MOUSE, 0) + +/*****************************************************************************/ + +#define KEYQUEUESIZE 256 +#define MAXKEYMSGLENGTH 10 +#define KEYAUTOREPEATDELAY 30 +#define KEYAUTOREPEATRATE 6 + +class geneve_keyboard_device : public device_t +{ +public: + geneve_keyboard_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + DECLARE_WRITE_LINE_MEMBER( reset_line ); + DECLARE_WRITE_LINE_MEMBER( send_scancodes ); + DECLARE_WRITE_LINE_MEMBER( clock_control ); + UINT8 get_recent_key(); + + template static devcb_base &static_set_int_callback(device_t &device, _Object object) { return downcast(device).m_interrupt.set_callback(object); } + +protected: + void device_start(); + void device_reset(); + ioport_constructor device_input_ports() const; + devcb_write_line m_interrupt; // Keyboard interrupt to console + void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + +private: + void post_in_key_queue(int keycode); + void signal_when_key_available(); + void poll(); + + bool m_key_reset; + int m_key_queue_length; + UINT8 m_key_queue[KEYQUEUESIZE]; + int m_key_queue_head; + bool m_key_in_buffer; + UINT32 m_key_state_save[4]; + bool m_key_numlock_state; + + int m_key_ctrl_state; + int m_key_alt_state; + int m_key_real_shift_state; + + bool m_key_fake_shift_state; + bool m_key_fake_unshift_state; + + int m_key_autorepeat_key; + int m_key_autorepeat_timer; + + bool m_keep_keybuf; + bool m_keyboard_clock; + + emu_timer* m_timer; +}; + +#define MCFG_GENEVE_KBINT_HANDLER( _intcallb ) \ + devcb = &geneve_keyboard_device::static_set_int_callback( *device, DEVCB_##_intcallb ); + +/*****************************************************************************/ + +class geneve_mapper_device : public device_t +{ +public: + geneve_mapper_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + void set_geneve_mode(bool geneve); + void set_direct_mode(bool direct); + void set_cartridge_size(int size); + void set_cartridge_writable(int base, bool write); + void set_video_waitstates(bool wait); + void set_extra_waitstates(bool wait); + + DECLARE_READ8_MEMBER( readm ); + DECLARE_WRITE8_MEMBER( writem ); + DECLARE_SETOFFSET_MEMBER( setoffset ); + + DECLARE_INPUT_CHANGED_MEMBER( settings_changed ); + + DECLARE_WRITE_LINE_MEMBER( clock_in ); + DECLARE_WRITE_LINE_MEMBER( dbin_in ); + + // PFM support + DECLARE_WRITE_LINE_MEMBER( pfm_select_lsb ); + DECLARE_WRITE_LINE_MEMBER( pfm_select_msb ); + DECLARE_WRITE_LINE_MEMBER( pfm_output_enable ); + + template static devcb_base &static_set_ready_callback(device_t &device, _Object object) { return downcast(device).m_ready.set_callback(object); } + +protected: + void device_start(); + void device_reset(); + +private: + // GROM simulation + bool m_gromwaddr_LSB; + bool m_gromraddr_LSB; + int m_grom_address; + DECLARE_READ8_MEMBER( read_grom ); + DECLARE_WRITE8_MEMBER( write_grom ); + + // wait states + void set_wait(int min); + void set_ext_wait(int min); + bool m_video_waitstates; + bool m_extra_waitstates; + bool m_ready_asserted; + + bool m_read_mode; + + bool m_debug_no_ws; + + // Mapper function + typedef struct + { + int function; + offs_t offset; + offs_t physaddr; + } decdata; + + bool m_geneve_mode; + bool m_direct_mode; + int m_cartridge_size; + bool m_cartridge_secondpage; + bool m_cartridge6_writable; + bool m_cartridge7_writable; + int m_map[8]; + + void decode(address_space& space, offs_t offset, bool read_mode, decdata* dec); + decdata m_decoded; + + // Genmod modifications + bool m_turbo; + bool m_genmod; + bool m_timode; + + // PFM mod (0 = none, 1 = AT29C040, 2 = AT29C040A) + DECLARE_READ8_MEMBER( read_from_pfm ); + DECLARE_WRITE8_MEMBER( write_to_pfm ); + void set_boot_rom(int selection); + int m_pfm_mode; + int m_pfm_bank; + bool m_pfm_output_enable; + + // SRAM access + int m_sram_mask; + int m_sram_val; + + // Ready line to the CPU + devcb_write_line m_ready; + + // Counter for the wait states. + int m_waitcount; + int m_ext_waitcount; + + // Devices + mm58274c_device* m_clock; + tms9995_device* m_cpu; + at29c040_device* m_pfm512; + at29c040a_device* m_pfm512a; + + geneve_keyboard_device* m_keyboard; + bus8z_device* m_video; + bus8z_device* m_peribox; + bus8z_device* m_sound; + UINT8* m_eprom; + UINT8* m_sram; + UINT8* m_dram; +}; + +#define MCFG_GENEVE_READY_HANDLER( _intcallb ) \ + devcb = &geneve_mapper_device::static_set_ready_callback( *device, DEVCB_##_intcallb ); + +#endif diff --git a/src/devices/bus/ti99x/grom.c b/src/devices/bus/ti99x/grom.c new file mode 100644 index 00000000000..3c20eeb35d7 --- /dev/null +++ b/src/devices/bus/ti99x/grom.c @@ -0,0 +1,269 @@ +// license:LGPL-2.1+ +// copyright-holders:Michael Zapf +/*************************************************************************** + + GROM emulation (aka TMC0430) + + +----+--+----+ + AD7 |1 G 16| Vss + AD6 |2 R 15| GR + AD5 |3 O 14| Vdd + AD4 |4 M 13| GRC + AD3 |5 12| M + AD2 |6 11| MO + AD1 |7 10| GS* + AD0 |8 9| Vcc + +------------+ + + GR = GROM Ready. Should be connected to processor's READY/HOLD*. + GRC = GROM clock. Typically in the range of 400-500 kHz. + M = Direction. 1=read, 0=write + MO = Mode. 1=address counter access, 0=data access + GS* = GROM select. 0=select, 1=deselect + + GROMs are slow ROM devices, which are + interfaced via a 8-bit data bus, and include an internal address pointer + which is incremented after each read. This implies that accesses are + faster when reading consecutive bytes, although the address pointer can be + read and written at any time. + + GROMs are generally used to store programs written in GPL (Graphic Programming + Language): a proprietary, interpreted language. The GPL interpreter takes + most space of the TI-99/4A system ROMs. + + Both TI-99/4 and TI-99/4A include three GROMs, with some start-up code, + system routines and TI-Basic. TI99/4 includes an additional Equation + Editor. According to the preliminary schematics found on ftp.whtech.com, + TI-99/8 includes the three standard GROMs and 16 GROMs for the UCSD + p-system. TI99/2 does not include GROMs at all, and was not designed to + support any, although it should be relatively easy to create an expansion + card with the GPL interpreter and a /4a cartridge port. + + Communication with GROM is done by writing and reading data over the + AD0-AD7 lines. Within the TI-99 systems, the address bus is decoded for + the M, GS*, and MO lines: Writing a byte to address 9c02 asserts the GS* and + MO line, and clears the M line, which means the transmitted byte is put into + the internal address register. Two bytes must be written to set up the + complete address. + + It was obviously planned to offer GRAM circuits as well, since the + programming manuals refer to writing to a special address, clearing the MO + line. Although the TI-99 systems reserve a port in the memory space, no one + has ever seen a GRAM circuit in the wild. However, third-party products like + HSGPL or GRAM Kracker simulate GRAMs using conventional RAM with some + addressing circuitry, usually in a custom chip. + + Each GROM is logically 8 KiB long. Original TI-built GROM are 6 KiB long; + the extra 2kb can be read, and follow the following formula: + + GROM[0x1800+offset] = GROM[0x0800+offset] | GROM[0x1000+offset]; + + (sounds like address decoding is incomplete - we are lucky we don't burn + any silicon when doing so... Needless to say, some hackers simulated 8kb + GRAMs and GROMs with normal RAM/PROM chips and glue logic.) + + The address pointer is incremented after each GROM operation, but it will + always remain within the bounds of the currently selected GROM (e.g. after + 0x3fff comes 0x2000). + + Since address are 16-bit long, you can have up to 8 GROMs. Accordingly, + a cartridge may include up to 5 GROMs. + + Every GROM has an internal ID which represents the high-order three + address bits. The address counter can be set to any value from 0 + to 0xffff; the GROM will only react when selected and when the current + address counter's high-order bits match the ID of the chip. + Example: When the ID is 6, the GROM will react when the address + counter contains a value from 0xc000 to 0xdfff. + + CHECK: Reading the address increases the counter only once. The first access + returns the MSB, the second (and all following accesses) return the LSB. + + Michael Zapf, August 2010 + January 2012: rewritten as class + +***************************************************************************/ + +#include "emu.h" +#include "grom.h" + +#define TRACE_ADDRESS 0 + +/* + Constructor. +*/ +ti99_grom_device::ti99_grom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) +: bus8z_device(mconfig, GROM, "TI-99 GROM device", tag, owner, clock, "ti99_grom", __FILE__), + m_gromready(*this) +{ +} + +/* + Reading from the chip. Represents an access with M=1, GS*=0. The MO bit is + defined by the offset (0 or 1). This is the enhanced read function with + Z state. +*/ +READ8Z_MEMBER( ti99_grom_device::readz ) +{ + // Prevent debugger access + if (space.debugger_access()) return; + + if (offset & 2) + { + // GROMs generally answer the address read request + // (important if GROM simulators do not serve the request but rely on + // the console GROMs) so we don't check the ident + + /* When reading, reset the hi/lo flag byte for writing. */ + /* TODO: Verify this with a real machine. */ + m_waddr_LSB = false; + + /* Address reading is done in two steps; first, the high byte */ + /* is transferred, then the low byte. */ + if (m_raddr_LSB) + { + /* second pass */ + *value = m_address & 0x00ff; + m_raddr_LSB = false; + } + else + { + /* first pass */ + *value = (m_address & 0xff00)>>8; + m_raddr_LSB = true; + } + } + else + { + if (((m_address >> 13)&0x07)==m_ident) + { + // GROMs are buffered. Data is retrieved from a buffer, + // while the buffer is replaced with the next cell content. + if (TRACE_ADDRESS) if (m_ident==0) logerror("grom0: %04x = %02x\n", m_address-1, m_buffer); + *value = m_buffer; + // Get next value, put it in buffer. Note that the GROM + // wraps at 8K boundaries. + UINT16 addr = m_address-(m_ident<<13); + + if (m_size == 0x1800 && ((m_address&0x1fff)>=0x1800)) + m_buffer = m_memptr[addr-0x1000] | m_memptr[addr-0x0800]; + else + m_buffer = m_memptr[addr]; + } + // Note that all GROMs update their address counter. + // TODO: Check this on a real console + m_address = (m_address & 0xE000) | ((m_address + 1)&0x1FFF); + + // Reset the read and write address flipflops. + m_raddr_LSB = m_waddr_LSB = false; + + // Maybe the timer is also required for address reading/setting, but + // we don't have such technical details on GROMs. + clear_ready(); + } +} + +/* + Writing to the chip. Represents an access with M=0, GS*=0. The MO bit is + defined by the offset (0 or 1). +*/ +WRITE8_MEMBER( ti99_grom_device::write ) +{ + // Prevent debugger access + if (space.debugger_access()) return; + + if (offset & 2) + { + /* write GROM address */ + /* see comments above */ + m_raddr_LSB = false; + + /* Implements the internal flipflop. */ + /* The Editor/Assembler manuals says that the current address */ + /* plus one is returned. This effect is properly emulated */ + /* by using a read-ahead buffer. */ + if (m_waddr_LSB) + { + /* Accept low byte (2nd write) */ + m_address = (m_address & 0xFF00) | data; + /* Setting the address causes a new prefetch */ + if (is_selected()) + { + m_buffer = m_memptr[m_address-(m_ident<<13)]; + } + m_waddr_LSB = false; + if (TRACE_ADDRESS) if (m_ident==0) logerror("grom0: %04x\n", m_address); + } + else + { + /* Accept high byte (1st write). Do not advance the address conter. */ + m_address = (data << 8) | (m_address & 0xFF); + m_waddr_LSB = true; + return; + } + } + else + { + /* write GRAM data */ + if ((((m_address >> 13)&0x07)==m_ident) && m_writable) + { + UINT16 write_addr; + // We need to rewind by 1 because the read address has already advanced. + // However, do not change the address counter! + write_addr = (m_address & 0xE000) | ((m_address - 1)&0x1FFF); + + // UINT16 addr = m_address-(m_ident<<13); + if (m_size > 0x1800 || ((m_address&0x1fff)<0x1800)) + m_memptr[write_addr-(m_ident<<13)] = data; + } + m_raddr_LSB = m_waddr_LSB = false; + clear_ready(); + } + m_address = (m_address & 0xE000) | ((m_address + 1)&0x1FFF); +} + +/* + Timing. We assume that each data read results in READY going down for + one cycle at the given frequency. +*/ +void ti99_grom_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + m_gromready(ASSERT_LINE); +} + +void ti99_grom_device::clear_ready() +{ + m_gromready(CLEAR_LINE); + m_timer->adjust(attotime::from_hz(m_clockrate)); +} + +/*************************************************************************** + DEVICE FUNCTIONS +***************************************************************************/ + +void ti99_grom_device::device_start(void) +{ + const ti99grom_config *conf = reinterpret_cast(static_config()); + + m_memptr = owner()->memregion(conf->regionname)->base(); + assert (m_memptr!=NULL); + m_memptr += conf->offset_reg; + + m_size = conf->size; + m_clockrate = conf->clockrate; + m_writable = conf->writable; + m_ident = conf->ident; + m_gromready.resolve_safe(); + + m_timer = timer_alloc(0); +} + +void ti99_grom_device::device_reset(void) +{ + m_address = 0; + m_raddr_LSB = false; + m_waddr_LSB = false; + m_buffer = 0; +} + +const device_type GROM = &device_creator; diff --git a/src/devices/bus/ti99x/grom.h b/src/devices/bus/ti99x/grom.h new file mode 100644 index 00000000000..19a9a973b81 --- /dev/null +++ b/src/devices/bus/ti99x/grom.h @@ -0,0 +1,108 @@ +// license:LGPL-2.1+ +// copyright-holders:Michael Zapf +/*************************************************************************** + + GROM emulation + See grom.c for documentation, + + Michael Zapf + + February 2012: Rewritten as class + +***************************************************************************/ +#ifndef __TI99GROM__ +#define __TI99GROM__ + +#include "ti99defs.h" + +struct ti99grom_config +{ + bool writable; + int ident; + const char *regionname; + offs_t offset_reg; + int size; + int clockrate; +}; + +#define GROM_CONFIG(name) \ + const ti99grom_config(name) = + +#define MCFG_GROM_READY_CALLBACK(_write) \ + devcb = &ti99_grom_device::set_ready_wr_callback(*device, DEVCB_##_write); + +extern const device_type GROM; + +/* + ti99_grom. For bus8z_device see ti99defs.h +*/ +class ti99_grom_device : public bus8z_device, ti99grom_config +{ +public: + ti99_grom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + template static devcb_base &set_ready_wr_callback(device_t &device, _Object object) { return downcast(device).m_gromready.set_callback(object); } + + DECLARE_READ8Z_MEMBER(readz); + DECLARE_WRITE8_MEMBER(write); + +private: + // Is this a GRAM (never seen actually, but obviously planned) + bool m_writable; + + // Identification of this GROM (0-7) + int m_ident; + + // If the GROM has only 6 KiB, the remaining 2 KiB are filled with a + // specific byte pattern which is created by a logical OR of lower + // regions + int m_size; + + // Ready callback. This line is usually connected to the READY pin of the CPU. + devcb_write_line m_gromready; + + // Frequency of the incoming GROM clock. In most application cases the + // GROM gets its clock from the video display processor (TMS9918) + int m_clockrate; + + /* Address pointer. */ + // This value is always expected to be in the range 0x0000 - 0xffff, even + // when this GROM is not addressed. + UINT16 m_address; + + /* GROM data buffer. */ + UINT8 m_buffer; + + /* Internal flip-flop. Used when retrieving the address counter. */ + bool m_raddr_LSB; + + /* Internal flip-flops. Used when writing the address counter.*/ + bool m_waddr_LSB; + + /* Pointer to the memory region contained in this GROM. */ + UINT8 *m_memptr; + + // Timer for READY line operation + emu_timer *m_timer; + + /* Indicates whether this device will react on the next read/write data access. */ + inline int is_selected() + { + return (((m_address >> 13)&0x07)==m_ident); + } + + // Calling this method causes the READY line to be cleared, which puts the + // CPU into wait state mode. A timer is set to raise READY again. + void clear_ready(); + + virtual void device_start(void); + virtual void device_reset(void); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); +}; + + +#define MCFG_GROM_ADD(_tag, _config) \ + MCFG_DEVICE_ADD(_tag, GROM, 0) \ + MCFG_DEVICE_CONFIG(_config) + +#endif diff --git a/src/devices/bus/ti99x/gromport.c b/src/devices/bus/ti99x/gromport.c new file mode 100644 index 00000000000..2119a93c348 --- /dev/null +++ b/src/devices/bus/ti99x/gromport.c @@ -0,0 +1,2509 @@ +// license:LGPL-2.1+ +// copyright-holders:Michael Zapf +/*************************************************************************** + GROM port - the cartridge port of the TI-99/4, TI-99/4A, and + TI-99/8 console. + + The name refers to the main intended application scenario, that is, + to host cartridges with GROMs. The second, wider port of the console is + called I/O port and connects to the Peripheral Expansion System + (see peribox.h). + + LEFT + + /RESET 1||2 GND + D7 3||4 CRUCLK + D6 5||6 CRUIN + D5 7||8 A15/CRUOUT + D4 9||10 A13 + D3 11||12 A12 + D2 13||14 A11 + D1 15||16 A10 + D0 17||18 A9 + +5V 19||20 A8 + /GS 21||22 A7 + A14 23||24 A3 + DBIN 25||26 A6 + GRMCLK 27||28 A5 + -5V 29||30 A4 + READY 31||32 /WE + GND 33||34 /ROMG + GND 35||36 GND + + RIGHT + + Address bus line ordering, according to TI convention, is A0 (MSB) ... A15 (LSB). + A0, A1, and A2 are not delivered to the port but decoded in the console: + + /ROMG is asserted for A0/A1/A2 = 011 (addresses 6000 - 7fff) + /GS is asserted for A0...A5 = 100110 (addresses 9800 - 9bff) + + This means that a maximum of 8 KiB of direct memory space can be accessed. + The /GS line is used to enable GROM circuits on the board (serial ROMs with + own address counter, see grom.h). + + When a cartridge is inserted the /RESET line is pulled to ground, which + via a R/C component pulls down the /RESET input of the timer circuit for + a short time, which in turn resets the CPU. In order to dump cartridges, + a common procedure was to tape the /RESET line of the cartridge. However, + inserting a cartridge without resetting often caused so much data bus noise + that the console usually locked up. + + ---------------- + + The TI-99/4A computer was strictly designed for cartridge usage. The basic + console had only little directly accessible RAM and offered no ways to + write machine language programs; cartridges were intended to add various + capabilities, or just for running games. + + Beside the seemingly simple handling, Texas Instruments had own intentions + behind their cartridge strategy. With only 8 KiB of direct access memory, a + major part of the cartridge code had to be stored in GROMs, which had to be + licensed from Texas Instruments. Thus they kept firm control over all + software development. + + Over the years, and with the increasingly difficult market situations, + TI's policies seem to have changed. This may be the reason that the built-in + operating system actually allowed for running ROM-only cartridges until TI + clipped out this part in the OS, banning cartridges without GROMs. Consoles + with this modification were produced in 1983, TI's last year in the home + computer business. + + Although only 8 KiB were available for direct addressing, clever techniques + were invented by third-party manufacturers. The first extension was utilized + by TI themselves in the Extended Basic cartridge which offers two banks + of ROM contents. Switching between the banks is achieved by writing a value + to the ROM space at 6000 or 6002. Later, cartridges with much more memory + space were created, up to the Super Space II cartridge with 128 KiB of + buffered SRAM. + + ---------------- + + From the console case layout the GROM port was intended for a single + cartridge only. Although never officially released, the operating system + of the TI console supported a multi-cartridge extender with software + switching. There were also extenders based on hardware switching (like + the Navarone Widget). + + This emulation offers both variants as slot options: + + -gromport single : default single cartridge connector + -gromport multi : software-switchable 4-slot cartridge extender + -gromport gkracker : GRAM Kracker + + The last option enables another popular device, the GRAM Kracker. This is + a device to be plugged into the cartridge slot with five manual switches + at the front and an own cartridge slot at its top. It contains buffered + SRAM, a built-in ROM, and a GROM simulator which simulates GROM behaviour + when accessing the buffered RAM. Its main use is to provide editable + storage for the read-only cartridge contents. Cartridges can be plugged + into its slot; their contents can be read and written to disk, modified as + needed, and loaded into the buffered RAM. Even the console GROMs can be + copied into the device; despite running in parallel, the GROM simulator + is able to override the console GROMs, thus allowing the user to install + a customized OS. + + (Emulation detail: Take care when changing something in this emulation - + this overrun is emulated by the sequence in which the devices on the datamux + are executed.) + + Michael Zapf, July 2012 + +***************************************************************************/ +#include "gromport.h" + +#define TRACE_RPK 0 +#define TRACE_CHANGE 0 +#define TRACE_ILLWRITE 0 +#define TRACE_CONFIG 0 +#define TRACE_READ 0 +#define TRACE_GROM 0 +#define TRACE_GKRACKER 0 +#define TRACE_CRU 0 + +#define GROM3_TAG "grom3" +#define GROM4_TAG "grom4" +#define GROM5_TAG "grom5" +#define GROM6_TAG "grom6" +#define GROM7_TAG "grom7" + +#define CARTGROM_TAG "grom_contents" +#define CARTROM_TAG "rom_contents" +#define GKRACKER_ROM_TAG "gkracker_rom" +#define GKRACKER_NVRAM_TAG "gkracker_nvram" + +gromport_device::gromport_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : bus8z_device(mconfig, GROMPORT, "Cartridge port", tag, owner, clock, "gromport", __FILE__), + device_slot_interface(mconfig, *this), + m_connector(NULL), + m_reset_on_insert(true), + m_console_ready(*this), + m_console_reset(*this) { } + +/* Only called for addresses 6000-7fff and GROM addresses (see datamux config) */ +READ8Z_MEMBER(gromport_device::readz) +{ + if (m_connector != NULL) + m_connector->readz(space, offset, value); +} + +WRITE8_MEMBER(gromport_device::write) +{ + if (m_connector != NULL) + m_connector->write(space, offset, data); +} + +READ8Z_MEMBER(gromport_device::crureadz) +{ + if (m_connector != NULL) + m_connector->crureadz(space, offset, value); +} + +WRITE8_MEMBER(gromport_device::cruwrite) +{ + if (m_connector != NULL) + m_connector->cruwrite(space, offset, data); +} + +WRITE_LINE_MEMBER(gromport_device::ready_line) +{ + m_console_ready(state); +} + +void gromport_device::device_start() +{ + m_console_ready.resolve(); + m_console_reset.resolve(); +} + +void gromport_device::device_reset() +{ + m_reset_on_insert = (ioport("CARTRESET")->read()==0x01); +} + +void gromport_device::set_grom_base(UINT16 grombase, UINT16 grommask) +{ + m_grombase = grombase; + m_grommask = grommask; +} + +/* + Shall we reset the console when a cartridge has been inserted? + This is triggered by the cartridge by pulling down /RESET via a capacitor. + Accordingly, when we put a tape over the /RESET contact we can avoid the + reset, which is useful when we want to swap the cartridges while a program + is runnning. +*/ +void gromport_device::cartridge_inserted() +{ + if (m_reset_on_insert) + { + m_console_reset(ASSERT_LINE); + m_console_reset(CLEAR_LINE); + } +} + +void gromport_device::device_config_complete() +{ + m_connector = static_cast(first_subdevice()); + set_grom_base(0x9800, 0xf800); +} + +SLOT_INTERFACE_START( gromport ) + SLOT_INTERFACE("single", GROMPORT_SINGLE) + SLOT_INTERFACE("multi", GROMPORT_MULTI) + SLOT_INTERFACE("gkracker", GROMPORT_GK) +SLOT_INTERFACE_END + + +INPUT_PORTS_START(gromport) + PORT_START( "CARTRESET" ) + PORT_CONFNAME( 0x01, 0x01, "RESET on cartridge insert" ) + PORT_CONFSETTING( 0x00, DEF_STR( Off ) ) + PORT_CONFSETTING( 0x01, DEF_STR( On ) ) +INPUT_PORTS_END + +ioport_constructor gromport_device::device_input_ports() const +{ + return INPUT_PORTS_NAME(gromport); +} + +const device_type GROMPORT = &device_creator; + +/*************************************************************************** + Different versions of cartridge connections + + single: the standard console connector, one cartridge + multi: a multi-cart expander, up to 4 cartridges with software selection + gkracker: GRAMKracker, a device with NVRAM which allows the user to copy + the contents of the cartridge plugged into its slot into the NVRAM + and to modify it. + +***************************************************************************/ + +const device_type GROMPORT_SINGLE = &device_creator; +const device_type GROMPORT_MULTI = &device_creator; +const device_type GROMPORT_GK = &device_creator; + +ti99_cartridge_connector_device::ti99_cartridge_connector_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : bus8z_device(mconfig, type, name, tag, owner, clock, shortname, source), + m_gromport(NULL) +{ +} + +WRITE_LINE_MEMBER( ti99_cartridge_connector_device::ready_line ) +{ + m_gromport->ready_line(state); +} + +void ti99_cartridge_connector_device::device_config_complete() +{ + m_gromport = static_cast(owner()); +} + +UINT16 ti99_cartridge_connector_device::grom_base() +{ + return m_gromport->get_grom_base(); +} + +UINT16 ti99_cartridge_connector_device::grom_mask() +{ + return m_gromport->get_grom_mask(); +} + +single_conn_device::single_conn_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : ti99_cartridge_connector_device(mconfig, GROMPORT_SINGLE, "Standard cartridge connector", tag, owner, clock, "single", __FILE__), + m_cartridge(NULL) +{ +} + +READ8Z_MEMBER(single_conn_device::readz) +{ + // Pass through + m_cartridge->readz(space, offset, value); +} + +WRITE8_MEMBER(single_conn_device::write) +{ + // Pass through + m_cartridge->write(space, offset, data); +} + +READ8Z_MEMBER(single_conn_device::crureadz) +{ + // Pass through + m_cartridge->crureadz(space, offset, value); +} + +WRITE8_MEMBER(single_conn_device::cruwrite) +{ + // Pass through + m_cartridge->cruwrite(space, offset, data); +} + +void single_conn_device::device_start() +{ + m_cartridge = static_cast(first_subdevice()); +} + +void single_conn_device::device_reset() +{ + m_cartridge->set_slot(0); +} + +static MACHINE_CONFIG_FRAGMENT( single_slot ) + MCFG_DEVICE_ADD("cartridge", TI99CART, 0) +MACHINE_CONFIG_END + +machine_config_constructor single_conn_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( single_slot ); +} + +/********************************************************/ + +/* + The multi-cartridge extender + + This is a somewhat mythical device which was never available for the normal + customer, but there are reports of the existence of such a device + in development labs or demonstrations. + + The interesting thing about this is that the OS of the console + fully supports this multi-cartridge extender, providing a selection + option on the screen to switch between different plugged-in + cartridges. + + The switching is possible by decoding address lines that are reserved + for GROM access. GROMs are accessed via four separate addresses + 9800, 9802, 9C00, 9C02. The addressing scheme looks like this: + + 1001 1Wxx xxxx xxM0 W = write(1), read(0), M = address(1), data(0) + + This leaves 8 bits (256 options) which are not decoded inside the + console. As the complete address is routed to the port, some circuit + just needs to decode the xxx lines and turn on the respective slot. + + One catch must be considered: Some cartridges contain ROMs which are + directly accessed and not via ports. This means that the ROMs must + be activated according to the slot that is selected. + + Another issue: Each GROM contains an own address counter and an ID. + According to the ID the GROM only delivers data if the address counter + is within the ID area (0 = 0000-1fff, 1=2000-3fff ... 7=e000-ffff). + Thus it is essential that all GROMs stay in sync with their address + counters. We have to route all address settings to all slots and their + GROMs, even when the slot has not been selected before. The selected + just shows its effect when data is read. In this case, only the + data from the selected slot will be delivered. + + This may be considered as a design flaw within the complete cartridge system + which eventually led to TI not manufacturing that device for the broad + market. +*/ + +#define AUTO -1 + +multi_conn_device::multi_conn_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : ti99_cartridge_connector_device(mconfig, GROMPORT_MULTI, "Multi-cartridge extender", tag, owner, clock, "multi", __FILE__), + m_active_slot(0), + m_fixed_slot(0), + m_next_free_slot(0) +{ +} + +/* + Activates a slot in the multi-cartridge extender. + Setting the slot is done by accessing the GROM ports using a + specific address: + + slot 0: 0x9800 (0x9802, 0x9c00, 0x9c02) : cartridge1 + slot 1: 0x9804 (0x9806, 0x9c04, 0x9c06) : cartridge2 + ... + slot 15: 0x983c (0x983e, 0x9c3c, 0x9c3e) : cartridge16 + + Scheme: + + 1001 1Wxx xxxx xxM0 (M=mode; M=0: data, M=1: address; W=write) + + The following addresses are theoretically available, but the + built-in OS does not use them; i.e. cartridges will not be + included in the selection list, and their features will not be + found by lookup, but they could be accessed directly by user + programs. + slot 16: 0x9840 (0x9842, 0x9c40, 0x9c42) + ... + slot 255: 0x9bfc (0x9bfe, 0x9ffc, 0x9ffe) + + Setting the GROM base should select one cartridge, but the ROMs in the + CPU space must also be switched. As there is no known special mechanism + we assume that by switching the GROM base, the ROM is automatically + switched. + + Caution: This means that cartridges which do not have at least one + GROM cannot be switched with this mechanism. + + We assume that the slot number is already calculated in the caller: + slotnumber>=0 && slotnumber<=255 + + NOTE: The OS will stop searching when it finds slots 1 and 2 empty. + Interestingly, cartridge subroutines are found nevertheless, even when + the cartridge is plugged into a higher slot. +*/ +void multi_conn_device::set_slot(int slotnumber) +{ + if (TRACE_CHANGE) + if (m_active_slot != slotnumber) logerror("%s: Setting cartslot to %d\n", tag(), slotnumber); + + if (m_fixed_slot==AUTO) + m_active_slot = slotnumber; + else + m_active_slot = m_fixed_slot; +} + +int multi_conn_device::get_active_slot(bool changebase, offs_t offset) +{ + int slot; + if (changebase) + { + if ((offset & grom_mask()) == grom_base()) + { + set_slot((offset>>2) & 0x00ff); + } + } + slot = m_active_slot; + return slot; +} + +void multi_conn_device::insert(int index, ti99_cartridge_device* cart) +{ + if (TRACE_CHANGE) logerror("%s: Insert slot %d\n", tag(), index); + m_cartridge[index] = cart; + m_gromport->cartridge_inserted(); +} + +void multi_conn_device::remove(int index) +{ + if (TRACE_CHANGE) logerror("%s: Remove slot %d\n", tag(), index); + m_cartridge[index] = NULL; +} + +READ8Z_MEMBER(multi_conn_device::readz) +{ + int slot = get_active_slot(true, offset); + + // If we have a GROM access, we need to send the read request to all + // attached cartridges so the slot is irrelevant here. Each GROM + // contains an internal address counter, and we must make sure they all stay in sync. + if ((offset & grom_mask()) == grom_base()) + { + for (int i=0; i < NUMBER_OF_CARTRIDGE_SLOTS; i++) + { + if (m_cartridge[i] != NULL) + { + UINT8 newval = *value; + m_cartridge[i]->readz(space, offset, &newval, mem_mask); + if (i==slot) + { + *value = newval; + } + } + } + } + else + { + if (slot < NUMBER_OF_CARTRIDGE_SLOTS && m_cartridge[slot] != NULL) + { + m_cartridge[slot]->readz(space, offset, value, mem_mask); + } + } +} + +WRITE8_MEMBER(multi_conn_device::write) +{ + int slot = get_active_slot(true, offset); + + // Same issue as above (read) + // We don't have GRAM cartridges, anyway, so it's just used for setting the address. + if ((offset & grom_mask()) == grom_base()) + { + for (int i=0; i < NUMBER_OF_CARTRIDGE_SLOTS; i++) + { + if (m_cartridge[i] != NULL) + { + m_cartridge[i]->write(space, offset, data, mem_mask); + } + } + } + else + { + if (slot < NUMBER_OF_CARTRIDGE_SLOTS && m_cartridge[slot] != NULL) + { + // logerror("%s: try it on slot %d\n", tag(), slot); + m_cartridge[slot]->write(space, offset, data, mem_mask); + } + } +} + +READ8Z_MEMBER(multi_conn_device::crureadz) +{ + int slot = get_active_slot(false, offset); + /* Sanity check. Higher slots are always empty. */ + if (slot >= NUMBER_OF_CARTRIDGE_SLOTS) + return; + + if (m_cartridge[slot] != NULL) + { + m_cartridge[slot]->crureadz(space, offset, value); + } +} + +WRITE8_MEMBER(multi_conn_device::cruwrite) +{ + int slot = get_active_slot(true, offset); + + /* Sanity check. Higher slots are always empty. */ + if (slot >= NUMBER_OF_CARTRIDGE_SLOTS) + return; + + if (m_cartridge[slot] != NULL) + { + m_cartridge[slot]->cruwrite(space, offset, data); + } +} + +void multi_conn_device::device_start() +{ + m_next_free_slot = 0; + m_active_slot = 0; + for (int i=0; i < NUMBER_OF_CARTRIDGE_SLOTS; i++) + { + m_cartridge[i] = NULL; + } +} + +void multi_conn_device::device_reset(void) +{ + m_active_slot = 0; + m_fixed_slot = ioport("CARTSLOT")->read() - 1; +} + +static MACHINE_CONFIG_FRAGMENT( multi_slot ) + MCFG_DEVICE_ADD("cartridge1", TI99CART, 0) + MCFG_DEVICE_ADD("cartridge2", TI99CART, 0) + MCFG_DEVICE_ADD("cartridge3", TI99CART, 0) + MCFG_DEVICE_ADD("cartridge4", TI99CART, 0) +MACHINE_CONFIG_END + +machine_config_constructor multi_conn_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( multi_slot ); +} + +INPUT_PORTS_START(multi_slot) + PORT_START( "CARTSLOT" ) + PORT_DIPNAME( 0x0f, 0x00, "Multi-cartridge slot" ) + PORT_DIPSETTING( 0x00, "Auto" ) + PORT_DIPSETTING( 0x01, "Slot 1" ) + PORT_DIPSETTING( 0x02, "Slot 2" ) + PORT_DIPSETTING( 0x03, "Slot 3" ) + PORT_DIPSETTING( 0x04, "Slot 4" ) +INPUT_PORTS_END + +ioport_constructor multi_conn_device::device_input_ports() const +{ + return INPUT_PORTS_NAME(multi_slot); +} + +/************************************************************************** + + The GRAM Kracker was manufactured by Miller's Graphics and designed to + fit into the cartridge slot. + + It offers one own cartridge slot at the top side and a row of switches + at its front. It contains buffered SRAM circuits; the base version has + 56 KiB, and the extended version has 80 KiB. + + The operation of the GRAM Kracker is a bit complex and most likely + bound to fail when you have no manual. Accordingly, this emulation is + neither simpler nor more difficult to use. + + Concept of operation: + + Loader: The GRAM Kracker contains a small loader utility + which allows you to dump cartridges and to load the contents into the + SRAM of the GK. This loader utility is active when the switch 5 is put + into "Loader on" state. The activated loader hides the TI BASIC + interpreter in the console. + + Cartridges: When a cartridge is plugged into the GK the contents may be + dumped and saved to disk by the loader. They cannot be directly copied + into the GK because the memory locations are hidden by the cartridge. + + Loading the cartridge into the SRAM: With the cartridge unplugged, dumps + can be loaded into the SRAM using the loader. This is one major use case + of the GK, that is, to load dumps from disk, and in particular modified + dumps. (There is no checksum, so contents may be freely changed.) + + Console dump: The GK is also able to dump the console GROMs and also to + load them into the SRAM (only in the extended version). Due to a + peculiarity of the TI console design it is possible to override the + console GROMs with the contents in the cartridge slot. + + A standard procedure for use with the GK: + + Save cartridge: + + - Put switches to [Normal | OpSys | TI BASIC | W/P | Loader On] + - Insert a disk image into disk drive 1 + - Plug in a cartridge + - Reset the console (done automatically here) + - Visit the option screen, press 1 for GRAM KRACKER + - In the GK loader, select 2 for Save Module + - Follow the on-screen instructions. Switches are set via the dip switch menu. + - Enter a target file name + - Saving is complete when the Save operation has been unmarked. + + Load cartridge: + + - Put switches to [Normal | OpSys | TI BASIC | W/P | Loader On] + - Insert a disk image into disk drive 1 + - Make sure no cartridge is plugged in + - Press 1 for GRAM KRACKER + - Press 3 for Init Module space; follow instructions + - Press 1 for Load Module; specify file name on disk + - Loading is complete when the Load operation has been unmarked. + + Memory organisation: + + The console has three GROMs with 6 KiB size and occupying 8 KiB of address + space each. These are called GROMs 0, 1, and 2. GROM 0 contains the common + routines for the computer operation; GROMs 1 and 2 contain TI BASIC. + + Memory locations 6000-7fff are assigned to cartridge ROMs; in some + cartridges, a second ROM bank can be used by writing a value to a special + ROM access. This way, instead of 8 KiB we often have 16 KiB at these + locations. + + Each cartridge can host up to 5 GROMs (called GROM 3, 4, 5, 6, and 7). + As in the console, each one occupies 6 KiB in an 8 KiB window. + + The GRAM Kracker offers + + - a loader in an own GROM 1 (which hides the console GROM 1 when active, + so we have no BASIC anymore). The contents of the loader must be found + by the emulator in a file named ti99_gkracker.zip. + + - a complete set of 8 (simulated) GRAMs with full 8 KiB each (done by a + simple addressing circuit); the basic version only offered GRAMs 3-7 + + - 16 KiB of RAM memory space for the 6000-7fff area (called "bank 1" and "bank 2") + + Notes: + + - it is mandatory to turn off the loader when loading into GRAM 1, but only + after prompted in the on-screen instructions, or the loader will crash + - GRAM0 must be properly loaded if switch 2 is set to GRAM0 and the computer is reset + - Switch 4 must not be in W/P position (write protect) when loading data + into the GK (either other position will do). + + +***************************************************************************/ +enum +{ + GK_OFF = 0, + GK_NORMAL = 1, + GK_GRAM0 = 0, + GK_OPSYS = 1, + GK_GRAM12 = 0, + GK_TIBASIC = 1, + GK_BANK1 = 0, + GK_WP = 1, + GK_BANK2 = 2, + GK_LDON = 0, + GK_LDOFF = 1 +}; + +#define GKSWITCH1_TAG "GKSWITCH1" +#define GKSWITCH2_TAG "GKSWITCH2" +#define GKSWITCH3_TAG "GKSWITCH3" +#define GKSWITCH4_TAG "GKSWITCH4" +#define GKSWITCH5_TAG "GKSWITCH5" + +gkracker_device::gkracker_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : ti99_cartridge_connector_device(mconfig, GROMPORT_GK, "GRAMKracker", tag, owner, clock, "ti99_gkracker", __FILE__), + device_nvram_interface(mconfig, *this), + m_ram_page(0), + m_grom_address(0), + m_ram_ptr(NULL), + m_grom_ptr(NULL), + m_waddr_LSB(false), + m_cartridge(NULL) +{ +} + +READ8Z_MEMBER(gkracker_device::readz) +{ + if ((offset & grom_mask()) == grom_base()) + { + // Reads from the GRAM space of the GRAM Kracker. + + // The GK does not have a readable address counter, but the console + // GROMs will keep our address counter up to date. That is + // exactly what happens in the real machine. + // (The console GROMs are not accessed here but directly via the datamux + // so we can just return without doing anything) + if ((offset & 0x0002)!=0) return; + + int id = ((m_grom_address & 0xe000)>>13)&0x07; + switch (id) + { + case 0: + // GRAM 0. Only return a value if switch 2 is in GRAM0 position. + if (m_gk_switch[2]==GK_GRAM0) + *value = m_ram_ptr[m_grom_address]; + break; + case 1: + // If the loader is turned on, return loader contents. + if (m_gk_switch[5]==GK_LDON) + { + // The only ROM contained in the GK box is the loader + // Adjust the address + *value = m_grom_ptr[m_grom_address & 0x1fff]; + } + else + { + // Loader off + // GRAM 1. Only return a value if switch 3 is in GRAM12 position. + // Otherwise, the console GROM 1 will respond (not here; it is the grom_device + // whose output would then not be overwritten) + if (m_gk_switch[3]==GK_GRAM12) + *value = m_ram_ptr[m_grom_address]; + } + break; + case 2: + // GRAM 2. Only return a value if switch 3 is in GRAM12 position. + if (m_gk_switch[3]==GK_GRAM12) + *value = m_ram_ptr[m_grom_address]; + break; + default: + // Cartridge space (0x6000 - 0xffff) + // When a cartridge is installed, it overrides the GK contents + // but only if it has GROMs + bool guest_has_grom = false; + + if (m_cartridge != NULL) + { + guest_has_grom = m_cartridge->has_grom(); + // Note that we only have ONE real cartridge and the GK; + // we need not access all slots. + if (guest_has_grom) + { + m_cartridge->readz(space, offset, value, mem_mask); // read from guest + } + } + if (!guest_has_grom && (m_gk_switch[1]==GK_NORMAL)) + *value = m_ram_ptr[m_grom_address]; // use the GK memory + } + + // The GK GROM emulation does not wrap at 8K boundaries. + m_grom_address = (m_grom_address + 1) & 0xffff; + + // Reset the write address flipflop. + m_waddr_LSB = false; + } + else + { + if (m_cartridge != NULL) + { + // Read from the guest cartridge. + m_cartridge->readz(space, offset, value, mem_mask); + } + else + { + // Reads from the RAM space of the GRAM Kracker. + if (m_gk_switch[1] == GK_OFF) return; // just don't do anything + switch (m_gk_switch[4]) + { + // RAM is stored behind the GRAM area + case GK_BANK1: + *value = m_ram_ptr[offset+0x10000 - 0x6000]; + break; + case GK_BANK2: + *value = m_ram_ptr[offset+0x12000 - 0x6000]; + break; + + default: + // Switch in middle position (WP, implies auto-select according to the page flag) + if (m_ram_page==0) + *value = m_ram_ptr[offset+0x10000 - 0x6000]; + else + *value = m_ram_ptr[offset+0x12000 - 0x6000]; + break; + } + } + } + if (TRACE_READ) logerror("%s: Read %04x -> %02x\n", tag(), offset, *value); +} + +WRITE8_MEMBER(gkracker_device::write) +{ + // write to the guest cartridge if present + if (m_cartridge != NULL) + { + m_cartridge->write(space, offset, data, mem_mask); + } + + if ((offset & grom_mask()) == grom_base()) + { + // Write to the GRAM space of the GRAM Kracker. + if ((offset & 0x0002)==0x0002) + { + // Set address + if (m_waddr_LSB == true) + { + // Accept low address byte (second write) + m_grom_address = (m_grom_address & 0xff00) | data; + m_waddr_LSB = false; + if (TRACE_GROM) logerror("%s: Set grom address %04x\n", tag(), m_grom_address); + } + else + { + // Accept high address byte (first write) + m_grom_address = (m_grom_address & 0x00ff) | (data << 8); + m_waddr_LSB = true; + } + } + else + { + // Write data byte to GRAM area. + if (TRACE_GROM) logerror("%s: gwrite %04x(%04x) <- %02x\n", tag(), offset, m_grom_address, data); + + // According to manual: + // Writing to GRAM 0: switch 2 set to GRAM 0 + Write protect switch (4) in 1 or 2 position + // Writing to GRAM 1: switch 3 set to GRAM 1-2 + Loader off (5); write prot has no effect + // Writing to GRAM 2: switch 3 set to GRAM 1-2 (write prot has no effect) + // Writing to GRAM 3-7: switch 1 set to GK_NORMAL, no cartridge inserted + // GK_NORMAL switch has no effect on GRAM 0-2 + int id = ((m_grom_address & 0xe000)>>13)&0x07; + switch (id) + { + case 0: + if (m_gk_switch[2]==GK_GRAM0 && m_gk_switch[4]!=GK_WP) + m_ram_ptr[m_grom_address] = data; + break; + case 1: + if (m_gk_switch[3]==GK_GRAM12 && m_gk_switch[5]==GK_LDOFF) + m_ram_ptr[m_grom_address] = data; + break; + case 2: + if (m_gk_switch[3]==GK_GRAM12) + m_ram_ptr[m_grom_address] = data; + break; + default: + if (m_gk_switch[1]==GK_NORMAL && m_cartridge == NULL) + m_ram_ptr[m_grom_address] = data; + break; + } + // The GK GROM emulation does not wrap at 8K boundaries. + m_grom_address = (m_grom_address + 1) & 0xffff; + + // Reset the write address flipflop. + m_waddr_LSB = false; + } + } + else + { + // Write to the RAM space of the GRAM Kracker + // (only if no cartridge is present) + if (TRACE_GROM) logerror("%s: write %04x <- %02x\n", tag(), offset, data); + if (m_cartridge == NULL) + { + if (m_gk_switch[1] == GK_OFF) return; // just don't do anything + switch (m_gk_switch[4]) + { + // RAM is stored behind the GRAM area + case GK_BANK1: + m_ram_ptr[offset+0x10000 - 0x6000] = data; + break; + + case GK_BANK2: + m_ram_ptr[offset+0x12000 - 0x6000] = data; + break; + + default: + // Switch in middle position (WP, implies auto-select according to the page flag) + // This is handled like in Extended Basic (using addresses) + m_ram_page = (offset >> 1) & 1; + break; + } + } + } +} + +READ8Z_MEMBER( gkracker_device::crureadz ) +{ + if (m_cartridge != NULL) m_cartridge->crureadz(space, offset, value); +} + +WRITE8_MEMBER( gkracker_device::cruwrite ) +{ + if (m_cartridge != NULL) m_cartridge->cruwrite(space, offset, data); +} + +INPUT_CHANGED_MEMBER( gkracker_device::gk_changed ) +{ + if (TRACE_GKRACKER) logerror("%s: Input changed %d - %d\n", tag(), (int)((UINT64)param & 0x07), newval); + m_gk_switch[(UINT64)param & 0x07] = newval; +} + +void gkracker_device::insert(int index, ti99_cartridge_device* cart) +{ + if (TRACE_CHANGE) logerror("%s: Insert cartridge\n", tag()); + m_cartridge = cart; + // Switch 1 has a third location for resetting. We do the reset by default + // here. It can be turned off in the configuration. + m_gromport->cartridge_inserted(); +} + +void gkracker_device::remove(int index) +{ + if (TRACE_CHANGE) logerror("%s: Remove cartridge\n", tag()); + m_cartridge = NULL; +} + +void gkracker_device::gk_install_menu(const char* menutext, int len, int ptr, int next, int start) +{ + const int base = 0x0000; + m_ram_ptr[base + ptr] = (UINT8)((next >> 8) & 0xff); + m_ram_ptr[base + ptr+1] = (UINT8)(next & 0xff); + m_ram_ptr[base + ptr+2] = (UINT8)((start >> 8) & 0xff); + m_ram_ptr[base + ptr+3] = (UINT8)(start & 0xff); + + m_ram_ptr[base + ptr+4] = (UINT8)(len & 0xff); + memcpy(m_ram_ptr + base + ptr+5, menutext, len); +} + +/* + Define the default for the GRAM Kracker device. The memory is preset with + some sample entries which shall indicate that the memory has been tested + by the manufacturer. +*/ +void gkracker_device::nvram_default() +{ + if (TRACE_GKRACKER) logerror("%s: Creating default NVRAM\n", tag()); + memset(m_ram_ptr, 0, 81920); + + m_ram_ptr[0x6000] = 0xaa; + m_ram_ptr[0x6001] = 0x01; + m_ram_ptr[0x6002] = 0x01; + + m_ram_ptr[0x6006] = 0x60; + m_ram_ptr[0x6007] = 0x20; + + gk_install_menu("GROM 3 OK", 9, 0x60e0, 0, 0x6100); + gk_install_menu("GROM 4 OK", 9, 0x60c0, 0x60e0, 0x6100); + gk_install_menu("GROM 5 OK", 9, 0x60a0, 0x60c0, 0x6100); + gk_install_menu("GROM 6 OK", 9, 0x6080, 0x60a0, 0x6100); + gk_install_menu("PROM OK", 9, 0x6060, 0x6080, 0x6100); + gk_install_menu("RAMS OK", 9, 0x6040, 0x6060, 0x6100); + gk_install_menu("OPTION GRAMS OK", 15, 0x6020, 0x6040, 0x6100); + + m_ram_ptr[0x6100] = 0x0b; // GPL EXIT +} + +void gkracker_device::nvram_read(emu_file &file) +{ + int readsize = file.read(m_ram_ptr, 81920); + if (TRACE_GKRACKER) logerror("%s: Reading NVRAM\n", tag()); + // If we increased the size, fill the remaining parts with 0 + if (readsize < 81920) + { + memset(m_ram_ptr + readsize, 0, 81920-readsize); + } +} + +void gkracker_device::nvram_write(emu_file &file) +{ + if (TRACE_GKRACKER) logerror("%s: Writing NVRAM\n", tag()); + file.write(m_ram_ptr, 81920); +} + +void gkracker_device::device_start() +{ + m_ram_ptr = memregion(GKRACKER_NVRAM_TAG)->base(); + m_grom_ptr = memregion(GKRACKER_ROM_TAG)->base(); + m_cartridge = NULL; + for (int i=1; i < 6; i++) m_gk_switch[i] = 0; +} + +void gkracker_device::device_reset() +{ + m_gk_switch[1] = ioport(GKSWITCH1_TAG)->read(); + m_gk_switch[2] = ioport(GKSWITCH2_TAG)->read(); + m_gk_switch[3] = ioport(GKSWITCH3_TAG)->read(); + m_gk_switch[4] = ioport(GKSWITCH4_TAG)->read(); + m_gk_switch[5] = ioport(GKSWITCH5_TAG)->read(); + m_grom_address = 0; // for the GROM emulation + m_ram_page = 0; + m_waddr_LSB = false; +} + +static MACHINE_CONFIG_FRAGMENT( gkracker_slot ) + MCFG_DEVICE_ADD("cartridge", TI99CART, 0) +MACHINE_CONFIG_END + +/* + The GRAMKracker ROM +*/ +ROM_START( gkracker_rom ) + ROM_REGION(0x14000, GKRACKER_NVRAM_TAG, ROMREGION_ERASE00) + ROM_REGION(0x2000, GKRACKER_ROM_TAG, 0) + ROM_LOAD("gkracker.bin", 0x0000, 0x2000, CRC(86eaaf9f) SHA1(a3bd5257c63e190800921b52dbe3ffa91ad91113)) +ROM_END + +const rom_entry *gkracker_device::device_rom_region() const +{ + return ROM_NAME( gkracker_rom ); +} + +machine_config_constructor gkracker_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( gkracker_slot ); +} + +INPUT_PORTS_START(gkracker) + PORT_START( GKSWITCH1_TAG ) + PORT_DIPNAME( 0x01, 0x01, "GK switch 1" ) PORT_CHANGED_MEMBER(DEVICE_SELF, gkracker_device, gk_changed, 1) + PORT_DIPSETTING( 0x00, "GK Off" ) + PORT_DIPSETTING( 0x01, DEF_STR( Normal ) ) + + PORT_START( GKSWITCH2_TAG ) + PORT_DIPNAME( 0x01, 0x01, "GK switch 2" ) PORT_CHANGED_MEMBER(DEVICE_SELF, gkracker_device, gk_changed, 2) + PORT_DIPSETTING( 0x00, "GRAM 0" ) + PORT_DIPSETTING( 0x01, "Op Sys" ) + + PORT_START( GKSWITCH3_TAG ) + PORT_DIPNAME( 0x01, 0x01, "GK switch 3" ) PORT_CHANGED_MEMBER(DEVICE_SELF, gkracker_device, gk_changed, 3) + PORT_DIPSETTING( 0x00, "GRAM 1-2" ) + PORT_DIPSETTING( 0x01, "TI BASIC" ) + + PORT_START( GKSWITCH4_TAG ) + PORT_DIPNAME( 0x03, 0x01, "GK switch 4" ) PORT_CHANGED_MEMBER(DEVICE_SELF, gkracker_device, gk_changed, 4) + PORT_DIPSETTING( 0x00, "Bank 1" ) + PORT_DIPSETTING( 0x01, "W/P" ) + PORT_DIPSETTING( 0x02, "Bank 2" ) + + PORT_START( GKSWITCH5_TAG ) + PORT_DIPNAME( 0x01, 0x00, "GK switch 5" ) PORT_CHANGED_MEMBER(DEVICE_SELF, gkracker_device, gk_changed, 5) + PORT_DIPSETTING( 0x00, "Loader On" ) + PORT_DIPSETTING( 0x01, "Loader Off" ) +INPUT_PORTS_END + +ioport_constructor gkracker_device::device_input_ports() const +{ + return INPUT_PORTS_NAME(gkracker); +} + +/*************************************************************************** + Cartridge implementation + + Every cartridge is an instance of ti99_cartridge_device, implementing the + device_image_interface. This means it is capable of loading cartridge + data into its memory locations. All memory locations are organised as + regions. + + The different cartridge versions are realised by different PCB instances. + All PCBs are subclassed from ti99_cartridge_pcb. + +***************************************************************************/ +enum +{ + PCB_STANDARD=1, + PCB_PAGED, + PCB_MINIMEM, + PCB_SUPER, + PCB_MBX, + PCB_PAGED379I, + PCB_PAGED378, + PCB_PAGED377, + PCB_PAGEDCRU, + PCB_GROMEMU +}; + +static const pcb_type pcbdefs[] = +{ + { PCB_STANDARD, "standard" }, + { PCB_PAGED, "paged" }, + { PCB_MINIMEM, "minimem" }, + { PCB_SUPER, "super" }, + { PCB_MBX, "mbx" }, + { PCB_PAGED379I, "paged379i" }, + { PCB_PAGED378, "paged378" }, + { PCB_PAGED377, "paged377" }, + { PCB_PAGEDCRU, "pagedcru" }, + { PCB_GROMEMU, "gromemu" }, + { 0, NULL} +}; + +// Softlists do not support the cartridges with RAM yet +static const pcb_type sw_pcbdefs[] = +{ + { PCB_STANDARD, "standard" }, + { PCB_PAGED, "paged" }, + { PCB_GROMEMU, "gromemu" }, + { 0, NULL} +}; + +ti99_cartridge_device::ti99_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) +: bus8z_device(mconfig, TI99CART, "TI-99 cartridge", tag, owner, clock, "cartridge", __FILE__), + device_image_interface(mconfig, *this), + m_softlist(false), + m_pcbtype(0), + m_slot(0), + m_pcb(NULL), + m_connector(NULL), + m_rpk(NULL) +{ +} + +void ti99_cartridge_device::prepare_cartridge() +{ + int rom2_length; + + UINT8* grom_ptr; + UINT8* rom_ptr; + + memory_region *regg; + memory_region *regr; + + // Initialize some values. + m_pcb->m_rom_page = 0; + m_pcb->m_rom_ptr = NULL; + m_pcb->m_ram_size = 0; + m_pcb->m_ram_ptr = NULL; + m_pcb->m_ram_page = 0; + + for (int i=0; i < 5; i++) m_pcb->m_grom[i] = NULL; + + m_pcb->m_grom_size = m_softlist? get_software_region_length("grom_socket") : m_rpk->get_resource_length("grom_socket"); + if (TRACE_CONFIG) logerror("%s: grom_socket.size=0x%04x\n", tag(), m_pcb->m_grom_size); + + if (m_pcb->m_grom_size > 0) + { + regg = memregion(CARTGROM_TAG); + grom_ptr = m_softlist? get_software_region("grom_socket") : m_rpk->get_contents_of_socket("grom_socket"); + memcpy(regg->base(), grom_ptr, m_pcb->m_grom_size); + m_pcb->m_grom_ptr = regg->base(); // for gromemu + m_pcb->m_grom_address = 0; // for gromemu + + // Find the GROMs and keep their pointers + m_pcb->set_grom_pointer(0, subdevice(GROM3_TAG)); + if (m_pcb->m_grom_size > 0x2000) m_pcb->set_grom_pointer(1, subdevice(GROM4_TAG)); + if (m_pcb->m_grom_size > 0x4000) m_pcb->set_grom_pointer(2, subdevice(GROM5_TAG)); + if (m_pcb->m_grom_size > 0x6000) m_pcb->set_grom_pointer(3, subdevice(GROM6_TAG)); + if (m_pcb->m_grom_size > 0x8000) m_pcb->set_grom_pointer(4, subdevice(GROM7_TAG)); + } + + m_pcb->m_rom_size = m_softlist? get_software_region_length("rom_socket") : m_rpk->get_resource_length("rom_socket"); + if (m_pcb->m_rom_size > 0) + { + if (TRACE_CONFIG) logerror("%s: rom_socket.size=0x%04x\n", tag(), m_pcb->m_rom_size); + regr = memregion(CARTROM_TAG); + rom_ptr = m_softlist? get_software_region("rom_socket") : m_rpk->get_contents_of_socket("rom_socket"); + memcpy(regr->base(), rom_ptr, m_pcb->m_rom_size); + // Set both pointers to the same region for now + m_pcb->m_rom_ptr = regr->base(); + } + + rom2_length = m_softlist? get_software_region_length("rom2_socket") : m_rpk->get_resource_length("rom2_socket"); + if (rom2_length > 0) + { + // sizes do not differ between rom and rom2 + // We use the large cartrom space for the second bank as well + regr = memregion(CARTROM_TAG); + rom_ptr = m_softlist? get_software_region("rom2_socket") : m_rpk->get_contents_of_socket("rom2_socket"); + memcpy(regr->base() + 0x2000, rom_ptr, rom2_length); + } + + // NVRAM cartridges are not supported by softlists (we need to find a way to load the nvram contents first) + if (!m_softlist) + { + m_pcb->m_ram_size = m_rpk->get_resource_length("ram_socket"); + if (m_pcb->m_ram_size > 0) + { + // TODO: Consider to use a region as well. If so, do not forget to memcpy. + m_pcb->m_ram_ptr = m_rpk->get_contents_of_socket("ram_socket"); + } + } +} + +/* + Find the index of the cartridge name. We assume the format + , i.e. the number is the longest string from the right + which can be interpreted as a number. Subtract 1. +*/ +int ti99_cartridge_device::get_index_from_tagname() +{ + const char *mytag = tag(); + int maxlen = strlen(mytag); + int i; + + for (i=maxlen-1; i >=0; i--) + if (mytag[i] < 48 || mytag[i] > 57) break; + + if (i==maxlen-1) return 0; + return atoi(mytag+i+1)-1; +} + +bool ti99_cartridge_device::has_grom() +{ + return m_pcb->m_grom_size>0; +} + +UINT16 ti99_cartridge_device::grom_base() +{ + return m_connector->grom_base(); +} + +UINT16 ti99_cartridge_device::grom_mask() +{ + return m_connector->grom_mask(); +} + +bool ti99_cartridge_device::call_load() +{ + // File name is in m_basename + // return true = error + if (TRACE_CHANGE) logerror("%s: Loading %s in slot %s\n", tag(), m_basename.c_str(), tag()); + + if (m_softlist) + { + if (TRACE_CONFIG) logerror("%s: Using softlists\n", tag()); + int i = 0; + const char* pcb = get_feature("pcb"); + do + { + if (strcmp(pcb, sw_pcbdefs[i].name)==0) + { + m_pcbtype = sw_pcbdefs[i].id; + break; + } + i++; + } while (sw_pcbdefs[i].id != 0); + if (TRACE_CONFIG) logerror("%s: Cartridge type is %s (%d)\n", tag(), pcb, m_pcbtype); + } + else + { + rpk_reader *reader = new rpk_reader(pcbdefs); + try + { + m_rpk = reader->open(machine().options(), filename(), machine().system().name); + m_pcbtype = m_rpk->get_type(); + } + catch (rpk_exception& err) + { + logerror("%s: Failed to load cartridge '%s': %s\n", tag(), basename(), err.to_string()); + m_rpk = NULL; + m_err = IMAGE_ERROR_INVALIDIMAGE; + return true; + } + } + + switch (m_pcbtype) + { + case PCB_STANDARD: + if (TRACE_CONFIG) logerror("%s: Standard PCB\n", tag()); + m_pcb = new ti99_standard_cartridge(); + break; + case PCB_PAGED: + if (TRACE_CONFIG) logerror("%s: Paged PCB\n", tag()); + m_pcb = new ti99_paged_cartridge(); + break; + case PCB_MINIMEM: + if (TRACE_CONFIG) logerror("%s: Minimem PCB\n", tag()); + m_pcb = new ti99_minimem_cartridge(); + break; + case PCB_SUPER: + if (TRACE_CONFIG) logerror("%s: Superspace PCB\n", tag()); + m_pcb = new ti99_super_cartridge(); + break; + case PCB_MBX: + if (TRACE_CONFIG) logerror("%s: MBX PCB\n", tag()); + m_pcb = new ti99_mbx_cartridge(); + break; + case PCB_PAGED379I: + if (TRACE_CONFIG) logerror("%s: Paged379i PCB\n", tag()); + m_pcb = new ti99_paged379i_cartridge(); + break; + case PCB_PAGED378: + if (TRACE_CONFIG) logerror("%s: Paged378 PCB\n", tag()); + m_pcb = new ti99_paged378_cartridge(); + break; + case PCB_PAGED377: + if (TRACE_CONFIG) logerror("%s: Paged377 PCB\n", tag()); + m_pcb = new ti99_paged377_cartridge(); + break; + case PCB_PAGEDCRU: + if (TRACE_CONFIG) logerror("%s: PagedCRU PCB\n", tag()); + m_pcb = new ti99_pagedcru_cartridge(); + break; + case PCB_GROMEMU: + if (TRACE_CONFIG) logerror("%s: Grom Emulation PCB\n", tag()); + m_pcb = new ti99_gromemu_cartridge(); + break; + } + + prepare_cartridge(); + m_pcb->set_cartridge(this); + m_pcb->set_tag(tag()); + m_slot = get_index_from_tagname(); + m_connector->insert(m_slot, this); + return false; +} + +void ti99_cartridge_device::call_unload() +{ + if (TRACE_CHANGE) logerror("%s: Unload\n", tag()); + if (m_rpk != NULL) + { + m_rpk->close(); // will write NVRAM contents + delete m_rpk; + } + + delete m_pcb; + m_pcb = NULL; + m_connector->remove(m_slot); +} + +void ti99_cartridge_device::set_slot(int i) +{ + m_slot = i; +} + +bool ti99_cartridge_device::call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry) +{ + if (TRACE_CONFIG) logerror("%s: swlist = %s, swname = %s\n", tag(), swlist.list_name(), swname); + load_software_part_region(*this, swlist, swname, start_entry); + m_softlist = true; + m_rpk = NULL; + return true; +} + +READ8Z_MEMBER(ti99_cartridge_device::readz) +{ + if (m_pcb != NULL) m_pcb->readz(space, offset, value); +} + +WRITE8_MEMBER(ti99_cartridge_device::write) +{ + if (m_pcb != NULL) m_pcb->write(space, offset, data); +} + +READ8Z_MEMBER(ti99_cartridge_device::crureadz) +{ + if (m_pcb != NULL) m_pcb->crureadz(space, offset, value); +} + +WRITE8_MEMBER(ti99_cartridge_device::cruwrite) +{ + if (m_pcb != NULL) m_pcb->cruwrite(space, offset, data); +} + +WRITE_LINE_MEMBER( ti99_cartridge_device::ready_line ) +{ + m_connector->ready_line(state); +} + +void ti99_cartridge_device::device_config_complete() +{ + update_names(); + m_softlist = false; + m_connector = static_cast(owner()); +} + +static GROM_CONFIG(grom3_config) +{ + false, 3, CARTGROM_TAG, 0x0000, 0x1800, GROMFREQ +}; +static GROM_CONFIG(grom4_config) +{ + false, 4, CARTGROM_TAG, 0x2000, 0x1800, GROMFREQ +}; +static GROM_CONFIG(grom5_config) +{ + false, 5, CARTGROM_TAG, 0x4000, 0x1800, GROMFREQ +}; +static GROM_CONFIG(grom6_config) +{ + false, 6, CARTGROM_TAG, 0x6000, 0x1800, GROMFREQ +}; +static GROM_CONFIG(grom7_config) +{ + false, 7, CARTGROM_TAG, 0x8000, 0x1800, GROMFREQ +}; + +/* + 5 GROMs that may be contained in a cartridge +*/ +static MACHINE_CONFIG_FRAGMENT( ti99_cartridge ) + MCFG_GROM_ADD( GROM3_TAG, grom3_config ) + MCFG_GROM_READY_CALLBACK(WRITELINE(ti99_cartridge_device, ready_line)) + MCFG_GROM_ADD( GROM4_TAG, grom4_config ) + MCFG_GROM_READY_CALLBACK(WRITELINE(ti99_cartridge_device, ready_line)) + MCFG_GROM_ADD( GROM5_TAG, grom5_config ) + MCFG_GROM_READY_CALLBACK(WRITELINE(ti99_cartridge_device, ready_line)) + MCFG_GROM_ADD( GROM6_TAG, grom6_config ) + MCFG_GROM_READY_CALLBACK(WRITELINE(ti99_cartridge_device, ready_line)) + MCFG_GROM_ADD( GROM7_TAG, grom7_config ) + MCFG_GROM_READY_CALLBACK(WRITELINE(ti99_cartridge_device, ready_line)) +MACHINE_CONFIG_END + +machine_config_constructor ti99_cartridge_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( ti99_cartridge ); +} + +/* + Memory area for one cartridge. For most cartridges we only need 8 KiB for + ROM contents, but cartridges of the "paged377" type have up to 2 MiB + organised as selectable banks, so we must be sure there is enough space. +*/ +ROM_START( cartridge_memory ) + ROM_REGION(0xa000, CARTGROM_TAG, ROMREGION_ERASE00) + ROM_REGION(0x200000, CARTROM_TAG, ROMREGION_ERASE00) +ROM_END + +const rom_entry *ti99_cartridge_device::device_rom_region() const +{ + return ROM_NAME( cartridge_memory ); +} + +const device_type TI99CART = &device_creator; + +/*************************************************************************** + Cartridge types + Cartridges differ by the circuits on their PCB which hosts the ROMs. + Some cartridges also have RAM, and some allow for switching between + ROMs. + + Unlike in the previous implementation we do not model it as a full device. +***************************************************************************/ + +ti99_cartridge_pcb::ti99_cartridge_pcb() +{ +} + +UINT16 ti99_cartridge_pcb::grom_base() +{ + return m_cart->grom_base(); +} + +UINT16 ti99_cartridge_pcb::grom_mask() +{ + return m_cart->grom_mask(); +} + +void ti99_cartridge_pcb::set_cartridge(ti99_cartridge_device *cart) +{ + m_cart = cart; +} + +READ8Z_MEMBER(ti99_cartridge_pcb::gromreadz) +{ + for (int i=0; i < 5; i++) + { + if (m_grom[i] != NULL) + { + m_grom[i]->readz(space, offset, value, mem_mask); + } + } +} + +WRITE8_MEMBER(ti99_cartridge_pcb::gromwrite) +{ + for (int i=0; i < 5; i++) + { + if (m_grom[i] != NULL) + { + m_grom[i]->write(space, offset, data, mem_mask); + } + } +} + +READ8Z_MEMBER(ti99_cartridge_pcb::readz) +{ + if ((offset & grom_mask())==grom_base()) + gromreadz(space, offset, value, mem_mask); + else + { + if (m_rom_ptr!=NULL) + { + // For TI-99/8 we should plan for 16K cartridges. However, none was ever produced. + // Well, forget about that. + *value = m_rom_ptr[offset & 0x1fff]; + // logerror("%s: read cartridge rom space %04x = %02x\n", tag(), offset, *value); + } + } +} + +WRITE8_MEMBER(ti99_cartridge_pcb::write) +{ + // logerror("%s: write standard\n", tag()); + if ((offset & grom_mask())==grom_base()) + gromwrite(space, offset, data, mem_mask); + else + { + if (TRACE_ILLWRITE) logerror("%s: Cannot write to ROM space at %04x\n", tag(), offset); + } +} + +READ8Z_MEMBER(ti99_cartridge_pcb::crureadz) +{ +} + +WRITE8_MEMBER(ti99_cartridge_pcb::cruwrite) +{ +} + +inline void ti99_cartridge_pcb::set_grom_pointer(int number, device_t *dev) +{ + m_grom[number] = static_cast(dev); +} + +/***************************************************************************** + Cartridge type: Paged (Extended Basic) + This cartridge consists of GROM memory and 2 pages of standard ROM. + The page is set by writing any value to a location in + the address area, where an even word offset sets the page to 0 and an + odd word offset sets the page to 1 (e.g. 6000 = bank 0, and + 6002 = bank 1). +******************************************************************************/ + +READ8Z_MEMBER(ti99_paged_cartridge::readz) +{ + if ((offset & grom_mask())==grom_base()) + gromreadz(space, offset, value, mem_mask); + else + { + *value = m_rom_ptr[(offset & 0x1fff) | (m_rom_page << 13)]; + } +} + +WRITE8_MEMBER(ti99_paged_cartridge::write) +{ + // logerror("%s: write standard\n", tag()); + if ((offset & grom_mask())==grom_base()) + gromwrite(space, offset, data, mem_mask); + + else { + m_rom_page = (offset >> 1) & 1; + } +} + +/***************************************************************************** + Cartridge type: Mini Memory + GROM: 6 KiB (occupies G>6000 to G>7800) + ROM: 4 KiB (romfile is actually 8 K long, second half with zeros, 0x6000-0x6fff) + persistent RAM: 4 KiB (0x7000-0x7fff) +******************************************************************************/ + +/* Read function for the minimem cartridge. */ +READ8Z_MEMBER(ti99_minimem_cartridge::readz) +{ + if ((offset & grom_mask())==grom_base()) + gromreadz(space, offset, value, mem_mask); + + else + { + if ((offset & 0x1000)==0x0000) + { + if (m_rom_ptr!=NULL) // Super-Minimem seems to have no ROM + { + *value = m_rom_ptr[offset & 0x0fff]; + } + } + else + { + *value = m_ram_ptr[offset & 0x0fff]; + } + } +} + +/* Write function for the minimem cartridge. */ +WRITE8_MEMBER(ti99_minimem_cartridge::write) +{ + // logerror("%s: write standard\n", tag()); + if ((offset & grom_mask())==grom_base()) + gromwrite(space, offset, data, mem_mask); + + else + { + if ((offset & 0x1000)==0x0000) + { + if (TRACE_ILLWRITE) logerror("%s: Write access to cartridge ROM at address %04x ignored", tag(), offset); + } + else + { + m_ram_ptr[offset & 0x0fff] = data; + } + } +} + +/***************************************************************************** + Cartridge type: SuperSpace II + + SuperSpace is intended as a user-definable blank cartridge containing + buffered RAM. It has an Editor/Assembler GROM which helps the user to load + the user program into the cartridge. If the user program has a suitable + header, the console recognizes the cartridge as runnable, and + assigns a number in the selection screen. Switching the RAM banks in this + cartridge is achieved by setting CRU bits (the system serial interface). + + GROM: Editor/Assembler GROM + ROM: none + persistent RAM: 32 KiB (0x6000-0x7fff, 4 banks) + Banking: via CRU write +******************************************************************************/ + +/* Read function for the super cartridge. */ +READ8Z_MEMBER(ti99_super_cartridge::readz) +{ + if ((offset & grom_mask())==grom_base()) + gromreadz(space, offset, value, mem_mask); + else + { + if (m_ram_ptr != NULL) + { + *value = m_ram_ptr[(m_ram_page << 13) | (offset & 0x1fff)]; + } + } +} + +/* Write function for the super cartridge. */ +WRITE8_MEMBER(ti99_super_cartridge::write) +{ + if ((offset & grom_mask())==grom_base()) + gromwrite(space, offset, data, mem_mask); + else + { + m_ram_ptr[(m_ram_page << 13) | (offset & 0x1fff)] = data; + } +} + +READ8Z_MEMBER(ti99_super_cartridge::crureadz) +{ + // offset is the bit number. The CRU base address is already divided by 2. + + // ram_page contains the bank number. We have a maximum of + // 4 banks; the Super Space II manual says: + // + // Banks are selected by writing a bit pattern to CRU address >0800: + // + // Bank # Value + // 0 >02 = 0000 0010 + // 1 >08 = 0000 1000 + // 2 >20 = 0010 0000 + // 3 >80 = 1000 0000 + // + // With the bank number (0, 1, 2, or 3) in R0: + // + // BNKSW LI R12,>0800 Set CRU address + // LI R1,2 Load Shift Bit + // SLA R0,1 Align Bank Number + // JEQ BNKS1 Skip shift if Bank 0 + // SLA R1,0 Align Shift Bit + // BNKS1 LDCR R1,0 Switch Banks + // SRL R0,1 Restore Bank Number (optional) + // RT + + // Our implementation in MESS always gets 8 bits in one go. Also, the address + // is twice the bit number. That is, the offset value is always a multiple + // of 0x10. + + if ((offset & 0xfff0) == 0x0800) + { + if (TRACE_CRU) logerror("%s: CRU accessed at %04x\n", tag(), offset); + UINT8 val = 0x02 << (m_ram_page << 1); + *value = (val >> ((offset - 0x0800)>>1)) & 0xff; + } +} + +WRITE8_MEMBER(ti99_super_cartridge::cruwrite) +{ + if ((offset & 0xfff0) == 0x0800) + { + if (TRACE_CRU) logerror("%s: CRU accessed at %04x\n", tag(), offset); + if (data != 0) + m_ram_page = (offset-0x0802)>>2; + } +} + +/***************************************************************************** + Cartridge type: MBX + GROM: up to 40 KiB + ROM: up to 16 KiB (in up to 2 banks of 8KiB each) + RAM: 1022 B (0x6c00-0x6ffd, overrides ROM in that area) + ROM mapper: 6ffe + + TODO: Some MBX cartridges assume the presence of the MBX system + (special user interface box with speech input/output) + and will not run without it. This MBX hardware is not emulated yet. +******************************************************************************/ + +/* Read function for the mbx cartridge. */ +READ8Z_MEMBER(ti99_mbx_cartridge::readz) +{ + if ((offset & grom_mask())==grom_base()) + gromreadz(space, offset, value, mem_mask); + else + { + if ((offset & 0x1c00)==0x0c00) + { + // This is the RAM area which overrides any ROM. There is no + // known banking behavior for the RAM, so we must assume that + // there is only one bank. + if (m_ram_ptr != NULL) + *value = m_ram_ptr[offset & 0x03ff]; + } + else + { + if (m_rom_ptr!=NULL) + *value = m_rom_ptr[(offset & 0x1fff) | (m_rom_page<<13)]; + } + } +} + +/* Write function for the mbx cartridge. */ +WRITE8_MEMBER(ti99_mbx_cartridge::write) +{ + if ((offset & grom_mask())==grom_base()) + gromwrite(space, offset, data, mem_mask); + else + { + if (offset == 0x6ffe) + { + m_rom_page = data & 1; + return; + } + + if ((offset & 0x1c00)==0x0c00) + { + if (m_ram_ptr == NULL) return; + m_ram_ptr[offset & 0x03ff] = data; + } + } +} + +/***************************************************************************** + Cartridge type: paged379i + This cartridge consists of one 16 KiB, 32 KiB, 64 KiB, or 128 KiB EEPROM + which is organised in 2, 4, 8, or 16 pages of 8 KiB each. The complete + memory contents must be stored in one dump file. + The pages are selected by writing a value to some memory locations. Due to + using the inverted outputs of the LS379 latch, setting the inputs of the + latch to all 0 selects the highest bank, while setting to all 1 selects the + lowest. There are some cartridges (16 KiB) which are using this scheme, and + there are new hardware developments mainly relying on this scheme. + + Writing to selects page (16K/32K/64K/128K) + >6000 1 / 3 / 7 / 15 + >6002 0 / 2 / 6 / 14 + >6004 1 / 1 / 5 / 13 + >6006 0 / 0 / 4 / 12 + >6008 1 / 3 / 3 / 11 + >600A 0 / 2 / 2 / 10 + >600C 1 / 1 / 1 / 9 + >600E 0 / 0 / 0 / 8 + >6010 1 / 3 / 7 / 7 + >6012 0 / 2 / 6 / 6 + >6014 1 / 1 / 5 / 5 + >6016 0 / 0 / 4 / 4 + >6018 1 / 3 / 3 / 3 + >601A 0 / 2 / 2 / 2 + >601C 1 / 1 / 1 / 1 + >601E 0 / 0 / 0 / 0 + + The paged379i cartrige does not have any GROMs. +******************************************************************************/ + +/* + Determines which bank to set, depending on the size of the ROM. This is + some magic code that actually represents different PCB versions. +*/ +int ti99_paged379i_cartridge::get_paged379i_bank(int rompage) +{ + int mask = 0; + if (m_rom_size > 16384) + { + if (m_rom_size > 32768) + { + if (m_rom_size > 65536) + mask = 15; + else + mask = 7; + } + else + mask = 3; + } + else + mask = 1; + + return rompage & mask; +} + + +/* Read function for the paged379i cartridge. */ +READ8Z_MEMBER(ti99_paged379i_cartridge::readz) +{ + if ((offset & 0xe000)==0x6000) + *value = m_rom_ptr[(m_rom_page<<13) | (offset & 0x1fff)]; +} + +/* Write function for the paged379i cartridge. Only used to set the bank. */ +WRITE8_MEMBER(ti99_paged379i_cartridge::write) +{ + // Bits: 0110 0000 000b bbbx + // x = don't care, bbbb = bank + if ((offset & 0xffe0)==0x6000) + { + // Set bank + m_rom_page = get_paged379i_bank(15 - ((offset>>1) & 15)); + } +} + +/***************************************************************************** + Cartridge type: paged378 + This type is intended for high-capacity cartridges of up to 512 KiB + plus GROM space of 120KiB (not supported yet) + + Due to its huge GROM space it is also called the "UberGROM" + + The cartridge may also be used without GROM. + + The selection scheme is much simpler than in the 379i type. + +******************************************************************************/ + +/* Read function for the paged378 cartridge. */ +READ8Z_MEMBER(ti99_paged378_cartridge::readz) +{ + if ((offset & 0xe000)==0x6000) + *value = m_rom_ptr[(m_rom_page<<13) | (offset & 0x1fff)]; +} + +/* Write function for the paged378 cartridge. Only used to set the bank. */ +WRITE8_MEMBER(ti99_paged378_cartridge::write) +{ + // Bits: 0110 0000 0bbb bbbx + // x = don't care, bbbb = bank + if ((offset & 0xff80)==0x6000) + { + // Set bank + m_rom_page = ((offset >> 1)&0x003f); + } +} + +/***************************************************************************** + Cartridge type: paged377 + This type is intended for high-capacity cartridges of up to 2 MiB + + The paged379i cartrige does not have any GROMs. +******************************************************************************/ + +/* Read function for the paged377 cartridge. */ +READ8Z_MEMBER(ti99_paged377_cartridge::readz) +{ + if ((offset & 0xe000)==0x6000) + *value = m_rom_ptr[(m_rom_page<<13) | (offset & 0x1fff)]; +} + +/* Write function for the paged377 cartridge. Only used to set the bank. */ +WRITE8_MEMBER(ti99_paged377_cartridge::write) +{ + // Bits: 0110 000b bbbb bbbx + // x = don't care, bbbb = bank + if ((offset & 0xfe00)==0x6000) + { + // Set bank + m_rom_page = ((offset >> 1)&0x00ff); + } +} + +/***************************************************************************** + Cartridge type: pagedcru + This cartridge consists of one 16 KiB, 32 KiB, or 64 KiB EEPROM which is + organised in 2, 4, or 8 pages of 8 KiB each. We assume there is only one + dump file of the respective size. + The pages are selected by writing a value to the CRU. This scheme is + similar to the one used for the SuperSpace cartridge, with the exception + that we are using ROM only, and we can have up to 8 pages. + + Bank Value written to CRU>0800 + 0 >0002 = 0000 0000 0000 0010 + 1 >0008 = 0000 0000 0000 1000 + 2 >0020 = 0000 0000 0010 0000 + 3 >0080 = 0000 0000 1000 0000 + 4 >0200 = 0000 0010 0000 0000 + 5 >0800 = 0000 1000 0000 0000 + 6 >2000 = 0010 0000 0000 0000 + 7 >8000 = 1000 0000 0000 0000 + + No GROMs used in this type. +******************************************************************************/ + +/* Read function for the pagedcru cartridge. */ +READ8Z_MEMBER(ti99_pagedcru_cartridge::readz) +{ + if ((offset & 0xe000)==0x6000) + *value = m_rom_ptr[(m_rom_page<<13) | (offset & 0x1fff)]; +} + +/* Write function for the pagedcru cartridge. No effect. */ +WRITE8_MEMBER(ti99_pagedcru_cartridge::write) +{ + return; +} + +READ8Z_MEMBER(ti99_pagedcru_cartridge::crureadz) +{ + int page = m_rom_page; + if ((offset & 0xf800)==0x0800) + { + int bit = (offset & 0x001e)>>1; + if (bit != 0) + { + page = page-(bit/2); // 4 page flags per 8 bits + } + *value = 1 << (page*2+1); + } +} + +WRITE8_MEMBER(ti99_pagedcru_cartridge::cruwrite) +{ + if ((offset & 0xf800)==0x0800) + { + int bit = (offset & 0x001e)>>1; + if (data != 0 && bit > 0) + { + m_rom_page = (bit-1)/2; + } + } +} + +/***************************************************************************** + Cartridge type: GROM emulation/paged + + This cartridge offers GROM address space without real GROM circuits. The GROMs + are emulated by a normal EPROM with a circuits that mimics GROM behavior. + Each simulated GROM offers 8K (real GROMs only offer 6K). + + Some assumptions: + - No readable address counter. This means the parallel console GROMs + will deliver the address when reading. + - No wait states. Reading is generally faster than with real GROMs. + - No wrapping at 8K boundaries. + - Two pages of ROM at address 6000 + + If any of these fails, the cartridge will crash, so we'll see. + + Typical cartridges: RXB, Super Extended Basic + + For the sake of simplicity, we register GROMs like the other PCB types, but + we implement special access methods for the GROM space. + + Still not working: + rxb1002 (Set page to 1 (6372 <- 00), lockup) + rxb237 (immediate reset) + rxbv555 (repeating reset on Master Title Screen) + superxb (lockup, fix: add RAM at 7c00) + + Super-MiniMemory is also included here. We assume a RAM area at addresses + 7000-7fff for this cartridge. + +******************************************************************************/ + +READ8Z_MEMBER(ti99_gromemu_cartridge::readz) +{ + if ((offset & grom_mask())==grom_base()) + gromemureadz(space, offset, value, mem_mask); + else + { + if (m_ram_ptr != NULL) + { + // Variant of the cartridge which emulates MiniMemory. We don't introduce + // another type for this single cartridge. + if ((offset & 0x1fff)==0x1000) { + *value = m_ram_ptr[offset & 0x0fff]; + return; + } + } + + if (m_rom_ptr == NULL) return; + *value = m_rom_ptr[(offset & 0x1fff) | (m_rom_page << 13)]; + } +} + +WRITE8_MEMBER(ti99_gromemu_cartridge::write) +{ + // logerror("%s: write standard\n", tag()); + if ((offset & grom_mask())==grom_base()) + gromemuwrite(space, offset, data, mem_mask); + + else { + if (m_ram_ptr != NULL) + { + // Lines for Super-Minimem; see above + if ((offset & 0x1fff)==0x1000) { + m_ram_ptr[offset & 0x0fff] = data; + } + return; // no paging + } + + m_rom_page = (offset >> 1) & 1; + } +} + +READ8Z_MEMBER(ti99_gromemu_cartridge::gromemureadz) +{ + // Similar to the GKracker implemented above, we do not have a readable + // GROM address counter but use the one from the console GROMs. + if ((offset & 0x0002)!=0) return; + int id = ((m_grom_address & 0xe000)>>13)&0x07; + if (id > 2) { + // Cartridge space (0x6000 - 0xffff) + *value = m_grom_ptr[m_grom_address-0x6000]; // use the GROM memory + } + + // The GROM emulation does not wrap at 8K boundaries. + m_grom_address = (m_grom_address + 1) & 0xffff; + + // Reset the write address flipflop. + m_waddr_LSB = false; +} + +WRITE8_MEMBER(ti99_gromemu_cartridge::gromemuwrite) +{ + // Set GROM address + if ((offset & 0x0002)==0x0002) { + if (m_waddr_LSB == true) + { + // Accept low address byte (second write) + m_grom_address = (m_grom_address & 0xff00) | data; + m_waddr_LSB = false; + if (TRACE_GROM) logerror("%s: Set grom address %04x\n", tag(), m_grom_address); + } + else + { + // Accept high address byte (first write) + m_grom_address = (m_grom_address & 0x00ff) | (data << 8); + m_waddr_LSB = true; + } + } + else { + if (TRACE_ILLWRITE) logerror("%s: Ignoring write to GROM area at address %04x\n", tag(), m_grom_address); + } +} + +/**************************************************************************** + + RPK loader + + RPK format support + + A RPK file ("rompack") contains a collection of dump files and a layout + file that defines the kind of circuit board (PCB) used in the cartridge + and the mapping of dumps to sockets on the board. + +Example: + + + + + + + + + + + + +DTD: + + + + + + + + + + + + + + + + + + + + +****************************************************************************/ + +#include "unzip.h" +#include "xmlfile.h" + +/**************************************** + RPK class +****************************************/ +/* + Constructor. +*/ +rpk::rpk(emu_options& options, const char* sysname) + :m_options(options) + //,m_system_name(sysname) +{ + m_sockets.reset(); +} + +rpk::~rpk() +{ + if (TRACE_RPK) logerror("gromport/RPK: Destroy RPK\n"); +} + +/* + Deliver the contents of the socket by name of the socket. +*/ +UINT8* rpk::get_contents_of_socket(const char *socket_name) +{ + rpk_socket *socket = m_sockets.find(socket_name); + if (socket==NULL) return NULL; + return socket->get_contents(); +} + +/* + Deliver the length of the contents of the socket by name of the socket. +*/ +int rpk::get_resource_length(const char *socket_name) +{ + rpk_socket *socket = m_sockets.find(socket_name); + if (socket==NULL) return 0; + return socket->get_content_length(); +} + +void rpk::add_socket(const char* id, rpk_socket *newsock) +{ + m_sockets.append(id, *newsock); +} + +/*------------------------------------------------- + rpk_close - closes a rpk + Saves the contents of the NVRAMs and frees all memory. +-------------------------------------------------*/ + +void rpk::close() +{ + // Save the NVRAM contents + rpk_socket *socket = m_sockets.first(); + while (socket != NULL) + { + if (socket->persistent_ram()) + { + image_battery_save_by_name(m_options, socket->get_pathname(), socket->get_contents(), socket->get_content_length()); + } + socket->cleanup(); + socket = socket->m_next; + } +} + +/************************************************************** + RPK socket (location in the PCB where a chip is plugged in; + not a network socket) +***************************************************************/ + +rpk_socket::rpk_socket(const char* id, int length, UINT8* contents, const char *pathname) +: m_id(id), m_length(length), m_next(NULL), m_contents(contents), m_pathname(pathname) +{ +} + +rpk_socket::rpk_socket(const char* id, int length, UINT8* contents) +: m_id(id), m_length(length), m_next(NULL), m_contents(contents), m_pathname(NULL) +{ +} + +/* + Locate a file in the ZIP container +*/ +const zip_file_header* rpk_reader::find_file(zip_file *zip, const char *filename, UINT32 crc) +{ + const zip_file_header *header; + for (header = zip_file_first_file(zip); header != NULL; header = zip_file_next_file(zip)) + { + // We don't check for CRC == 0. + if (crc != 0) + { + // if the CRC and name both match, we're good + // if the CRC matches and the name doesn't, we're still good + if (header->crc == crc) + return header; + } + else + { + if (core_stricmp(header->filename, filename)==0) + { + return header; + } + } + } + return NULL; +} + +/* + Load a rom resource and put it in a pcb socket instance. +*/ +rpk_socket* rpk_reader::load_rom_resource(zip_file* zip, xml_data_node* rom_resource_node, const char* socketname) +{ + const char* file; + const char* crcstr; + const char* sha1; + zip_error ziperr; + UINT32 crc; + int length; + UINT8* contents; + const zip_file_header *header; + + // find the file attribute (required) + file = xml_get_attribute_string(rom_resource_node, "file", NULL); + if (file == NULL) throw rpk_exception(RPK_INVALID_LAYOUT, " must have a 'file' attribute"); + + if (TRACE_RPK) logerror("gromport/RPK: Loading ROM contents for socket '%s' from file %s\n", socketname, file); + + // check for crc + crcstr = xml_get_attribute_string(rom_resource_node, "crc", NULL); + if (crcstr==NULL) + { + // no CRC, just find the file in the RPK + header = find_file(zip, file, 0); + } + else + { + crc = strtoul(crcstr, NULL, 16); + header = find_file(zip, file, crc); + } + if (header == NULL) throw rpk_exception(RPK_INVALID_FILE_REF, "File not found or CRC check failed"); + + length = header->uncompressed_length; + + // Allocate storage + contents = global_alloc_array_clear(UINT8, length); + if (contents==NULL) throw rpk_exception(RPK_OUT_OF_MEMORY); + + // and unzip file from the zip file + ziperr = zip_file_decompress(zip, contents, length); + if (ziperr != ZIPERR_NONE) + { + if (ziperr == ZIPERR_UNSUPPORTED) throw rpk_exception(RPK_ZIP_UNSUPPORTED); + else throw rpk_exception(RPK_ZIP_ERROR); + } + + // check for sha1 + sha1 = xml_get_attribute_string(rom_resource_node, "sha1", NULL); + if (sha1 != NULL) + { + hash_collection actual_hashes; + actual_hashes.compute((const UINT8 *)contents, length, hash_collection::HASH_TYPES_CRC_SHA1); + + hash_collection expected_hashes; + expected_hashes.add_from_string(hash_collection::HASH_SHA1, sha1, strlen(sha1)); + + if (actual_hashes != expected_hashes) throw rpk_exception(RPK_INVALID_FILE_REF, "SHA1 check failed"); + } + + // Create a socket instance + return new rpk_socket(socketname, length, contents); +} + +/* + Load a ram resource and put it in a pcb socket instance. +*/ +rpk_socket* rpk_reader::load_ram_resource(emu_options &options, xml_data_node* ram_resource_node, const char* socketname, const char* system_name) +{ + const char* length_string; + const char* ram_type; + const char* ram_filename; + const char* ram_pname; + unsigned int length; + UINT8* contents; + + // find the length attribute + length_string = xml_get_attribute_string(ram_resource_node, "length", NULL); + if (length_string == NULL) throw rpk_exception(RPK_MISSING_RAM_LENGTH); + + // parse it + char suffix = '\0'; + sscanf(length_string, "%u%c", &length, &suffix); + switch(tolower(suffix)) + { + case 'k': // kilobytes + length *= 1024; + break; + + case 'm': + /* megabytes */ + length *= 1024*1024; + break; + + case '\0': + break; + + default: // failed + throw rpk_exception(RPK_INVALID_RAM_SPEC); + } + + // Allocate memory for this resource + contents = global_alloc_array_clear(UINT8, length); + if (contents==NULL) throw rpk_exception(RPK_OUT_OF_MEMORY); + + if (TRACE_RPK) logerror("gromport/RPK: Allocating RAM buffer (%d bytes) for socket '%s'\n", length, socketname); + + ram_pname = NULL; + + // That's it for pure RAM. Now check whether the RAM is "persistent", i.e. NVRAM. + // In that case we must load it from the NVRAM directory. + // The file name is given in the RPK file; the subdirectory is the system name. + ram_type = xml_get_attribute_string(ram_resource_node, "type", NULL); + if (ram_type != NULL) + { + if (strcmp(ram_type, "persistent")==0) + { + // Get the file name (required if persistent) + ram_filename = xml_get_attribute_string(ram_resource_node, "file", NULL); + if (ram_filename==NULL) + { + global_free_array(contents); + throw rpk_exception(RPK_INVALID_RAM_SPEC, " must have a 'file' attribute"); + } + std::string ram_pathname = std::string(system_name).append(PATH_SEPARATOR).append(ram_filename); + ram_pname = core_strdup(ram_pathname.c_str()); + // load, and fill rest with 00 + if (TRACE_RPK) logerror("gromport/RPK: Loading NVRAM contents from '%s'\n", ram_pname); + image_battery_load_by_name(options, ram_pname, contents, length, 0x00); + } + } + + // Create a socket instance + return new rpk_socket(socketname, length, contents, ram_pname); +} + +/*------------------------------------------------- + rpk_open - open a RPK file + options - parameters from the settings; we need it only for the NVRAM directory + system_name - name of the driver (also just for NVRAM handling) +-------------------------------------------------*/ + +rpk* rpk_reader::open(emu_options &options, const char *filename, const char *system_name) +{ + zip_error ziperr; + + const zip_file_header *header; + const char *pcb_type; + const char *id; + const char *uses_name; + const char *resource_name; + + zip_file* zipfile; + + std::vector layout_text; + xml_data_node *layout_xml = NULL; + xml_data_node *romset_node; + xml_data_node *configuration_node; + xml_data_node *resources_node; + xml_data_node *resource_node; + xml_data_node *socket_node; + xml_data_node *pcb_node; + + rpk_socket *newsock; + + int i; + + rpk *newrpk = new rpk(options, system_name); + + try + { + /* open the ZIP file */ + ziperr = zip_file_open(filename, &zipfile); + if (ziperr != ZIPERR_NONE) throw rpk_exception(RPK_NOT_ZIP_FORMAT); + + /* find the layout.xml file */ + header = find_file(zipfile, "layout.xml", 0); + if (header == NULL) throw rpk_exception(RPK_MISSING_LAYOUT); + + /* reserve space for the layout file contents (+1 for the termination) */ + layout_text.resize(header->uncompressed_length + 1); + + /* uncompress the layout text */ + ziperr = zip_file_decompress(zipfile, &layout_text[0], header->uncompressed_length); + if (ziperr != ZIPERR_NONE) + { + if (ziperr == ZIPERR_UNSUPPORTED) throw rpk_exception(RPK_ZIP_UNSUPPORTED); + else throw rpk_exception(RPK_ZIP_ERROR); + } + + layout_text[header->uncompressed_length] = '\0'; // Null-terminate + + /* parse the layout text */ + layout_xml = xml_string_read(&layout_text[0], NULL); + if (layout_xml == NULL) throw rpk_exception(RPK_XML_ERROR); + + // Now we work within the XML tree + + // romset is the root node + romset_node = xml_get_sibling(layout_xml->child, "romset"); + if (romset_node==NULL) throw rpk_exception(RPK_INVALID_LAYOUT, "document element must be "); + + // resources is a child of romset + resources_node = xml_get_sibling(romset_node->child, "resources"); + if (resources_node==NULL) throw rpk_exception(RPK_INVALID_LAYOUT, " must have a child"); + + // configuration is a child of romset; we're actually interested in ... + configuration_node = xml_get_sibling(romset_node->child, "configuration"); + if (configuration_node==NULL) throw rpk_exception(RPK_INVALID_LAYOUT, " must have a child"); + + // ... pcb, which is a child of configuration + pcb_node = xml_get_sibling(configuration_node->child, "pcb"); + if (pcb_node==NULL) throw rpk_exception(RPK_INVALID_LAYOUT, " must have a child"); + + // We'll try to find the PCB type on the provided type list. + pcb_type = xml_get_attribute_string(pcb_node, "type", NULL); + if (pcb_type==NULL) throw rpk_exception(RPK_INVALID_LAYOUT, " must have a 'type' attribute"); + if (TRACE_RPK) logerror("gromport/RPK: Cartridge says it has PCB type '%s'\n", pcb_type); + + i=0; + do + { + if (strcmp(pcb_type, m_types[i].name)==0) + { + newrpk->m_type = m_types[i].id; + break; + } + i++; + } while (m_types[i].id != 0); + + if (m_types[i].id==0) throw rpk_exception(RPK_UNKNOWN_PCB_TYPE); + + // Find the sockets and load their respective resource + for (socket_node = pcb_node->child; socket_node != NULL; socket_node = socket_node->next) + { + if (strcmp(socket_node->name, "socket")!=0) throw rpk_exception(RPK_INVALID_LAYOUT, " element has only children"); + id = xml_get_attribute_string(socket_node, "id", NULL); + if (id == NULL) throw rpk_exception(RPK_INVALID_LAYOUT, " must have an 'id' attribute"); + uses_name = xml_get_attribute_string(socket_node, "uses", NULL); + if (uses_name == NULL) throw rpk_exception(RPK_INVALID_LAYOUT, " must have a 'uses' attribute"); + + bool found = false; + // Locate the resource node + for (resource_node = resources_node->child; resource_node != NULL; resource_node = resource_node->next) + { + resource_name = xml_get_attribute_string(resource_node, "id", NULL); + if (resource_name == NULL) throw rpk_exception(RPK_INVALID_LAYOUT, "resource node must have an 'id' attribute"); + + if (strcmp(resource_name, uses_name)==0) + { + // found it + if (strcmp(resource_node->name, "rom")==0) + { + newsock = load_rom_resource(zipfile, resource_node, id); + newrpk->add_socket(id, newsock); + } + else + { + if (strcmp(resource_node->name, "ram")==0) + { + newsock = load_ram_resource(options, resource_node, id, system_name); + newrpk->add_socket(id, newsock); + } + else throw rpk_exception(RPK_INVALID_LAYOUT, "resource node must be or "); + } + found = true; + } + } + if (!found) throw rpk_exception(RPK_INVALID_RESOURCE_REF, uses_name); + } + } + catch (rpk_exception &exp) + { + newrpk->close(); + if (layout_xml != NULL) xml_file_free(layout_xml); + if (zipfile != NULL) zip_file_close(zipfile); + + // rethrow the exception + throw exp; + } + + if (layout_xml != NULL) xml_file_free(layout_xml); + if (zipfile != NULL) zip_file_close(zipfile); + + return newrpk; +} diff --git a/src/devices/bus/ti99x/gromport.h b/src/devices/bus/ti99x/gromport.h new file mode 100644 index 00000000000..a6c0c1c3c8f --- /dev/null +++ b/src/devices/bus/ti99x/gromport.h @@ -0,0 +1,547 @@ +// license:LGPL-2.1+ +// copyright-holders:Michael Zapf +/*************************************************************************** + Gromport of the TI-99 consoles + + For details see gromport.c + + Michael Zapf, July 2012 +***************************************************************************/ + +#ifndef __GROMPORT__ +#define __GROMPORT__ + +#include "emu.h" +#include "ti99defs.h" +#include "grom.h" + +extern const device_type GROMPORT; + +class ti99_cartridge_connector_device; + +class gromport_device : public bus8z_device, public device_slot_interface +{ +public: + gromport_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + DECLARE_READ8Z_MEMBER(readz); + DECLARE_WRITE8_MEMBER(write); + DECLARE_READ8Z_MEMBER(crureadz); + DECLARE_WRITE8_MEMBER(cruwrite); + DECLARE_WRITE_LINE_MEMBER(ready_line); + + template static devcb_base &static_set_ready_callback(device_t &device, _Object object) { return downcast(device).m_console_ready.set_callback(object); } + template static devcb_base &static_set_reset_callback(device_t &device, _Object object) { return downcast(device).m_console_reset.set_callback(object); } + + void cartridge_inserted(); + void set_grom_base(UINT16 grombase, UINT16 grommask); + UINT16 get_grom_base() { return m_grombase; } + UINT16 get_grom_mask() { return m_grommask; } + +protected: + virtual void device_start(); + virtual void device_reset(); + virtual void device_config_complete(); + virtual ioport_constructor device_input_ports() const; + +private: + ti99_cartridge_connector_device* m_connector; + bool m_reset_on_insert; + devcb_write_line m_console_ready; + devcb_write_line m_console_reset; + UINT16 m_grombase; + UINT16 m_grommask; +}; + +SLOT_INTERFACE_EXTERN(gromport); + +#define MCFG_TI99_GROMPORT_ADD( _tag ) \ + MCFG_DEVICE_ADD(_tag, GROMPORT, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(gromport, "single", false) + +#define MCFG_GROMPORT_READY_HANDLER( _ready ) \ + devcb = &gromport_device::static_set_ready_callback( *device, DEVCB_##_ready ); + +#define MCFG_GROMPORT_RESET_HANDLER( _reset ) \ + devcb = &gromport_device::static_set_reset_callback( *device, DEVCB_##_reset ); + +/****************************************************************************/ + +class rpk; +class ti99_cartridge_pcb; + +class ti99_cartridge_device : public bus8z_device, public device_image_interface +{ +public: + ti99_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + DECLARE_READ8Z_MEMBER(readz); + DECLARE_WRITE8_MEMBER(write); + DECLARE_READ8Z_MEMBER(crureadz); + DECLARE_WRITE8_MEMBER(cruwrite); + + DECLARE_WRITE_LINE_MEMBER(ready_line); + bool is_available() { return m_pcb != NULL; } + bool has_grom(); + void set_slot(int i); + UINT16 grom_base(); + UINT16 grom_mask(); + +protected: + virtual void device_start() { }; + virtual void device_config_complete(); + virtual machine_config_constructor device_mconfig_additions() const; + virtual const rom_entry* device_rom_region() const; + + // Image handling: implementation of methods which are abstract in the parent + bool call_load(); + void call_unload(); + bool call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry); + + void prepare_cartridge(); + + // device_image_interface + iodevice_t image_type() const { return IO_CARTSLOT; } + bool is_readable() const { return true; } + bool is_writeable() const { return false; } + bool is_creatable() const { return false; } + bool must_be_loaded() const { return false; } + bool is_reset_on_load() const { return false; } + const char *image_interface() const { return "ti99_cart"; } + const char *file_extensions() const { return "rpk"; } + const option_guide *create_option_guide() const { return NULL; } + +private: + bool m_softlist; + int m_pcbtype; + int m_slot; + int get_index_from_tagname(); + + ti99_cartridge_pcb* m_pcb; // inbound + ti99_cartridge_connector_device* m_connector; // outbound + + // RPK which is associated to this cartridge + // When we close it, the contents are saved to NVRAM if available + rpk *m_rpk; +}; + +extern const device_type TI99CART; + +/****************************************************************************/ + +class ti99_cartridge_connector_device : public bus8z_device +{ +public: + virtual DECLARE_READ8Z_MEMBER(readz) =0; + virtual DECLARE_WRITE8_MEMBER(write) =0; + virtual DECLARE_READ8Z_MEMBER(crureadz) = 0; + virtual DECLARE_WRITE8_MEMBER(cruwrite) = 0; + + DECLARE_WRITE_LINE_MEMBER(ready_line); + + virtual void insert(int index, ti99_cartridge_device* cart) { m_gromport->cartridge_inserted(); }; + virtual void remove(int index) { }; + UINT16 grom_base(); + UINT16 grom_mask(); + +protected: + ti99_cartridge_connector_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + virtual void device_config_complete(); + + gromport_device* m_gromport; +}; + +/* + Single cartridge connector. +*/ +class single_conn_device : public ti99_cartridge_connector_device +{ +public: + single_conn_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + DECLARE_READ8Z_MEMBER(readz); + DECLARE_WRITE8_MEMBER(write); + DECLARE_READ8Z_MEMBER(crureadz); + DECLARE_WRITE8_MEMBER(cruwrite); + +protected: + virtual void device_start(); + virtual void device_reset(); + virtual machine_config_constructor device_mconfig_additions() const; + +private: + ti99_cartridge_device *m_cartridge; +}; + +/* + Multi cartridge connector. +*/ + +/* We set the number of slots to 4, although we may have up to 16. From a + logical point of view we could have 256, but the operating system only checks + the first 16 banks. */ +#define NUMBER_OF_CARTRIDGE_SLOTS 4 + +class multi_conn_device : public ti99_cartridge_connector_device +{ +public: + multi_conn_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + DECLARE_READ8Z_MEMBER(readz); + DECLARE_WRITE8_MEMBER(write); + DECLARE_READ8Z_MEMBER(crureadz); + DECLARE_WRITE8_MEMBER(cruwrite); + + void insert(int index, ti99_cartridge_device* cart); + void remove(int index); + +protected: + virtual void device_start(); + virtual void device_reset(); + virtual machine_config_constructor device_mconfig_additions() const; + virtual ioport_constructor device_input_ports() const; + +private: + int m_active_slot; + int m_fixed_slot; + int m_next_free_slot; + ti99_cartridge_device* m_cartridge[NUMBER_OF_CARTRIDGE_SLOTS]; + + void set_slot(int slotnumber); + int get_active_slot(bool changebase, offs_t offset); + void change_slot(bool inserted, int index); +}; + +/* + GRAM Kracker. +*/ +class gkracker_device : public ti99_cartridge_connector_device, public device_nvram_interface +{ +public: + gkracker_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + DECLARE_READ8Z_MEMBER(readz); + DECLARE_WRITE8_MEMBER(write); + DECLARE_READ8Z_MEMBER(crureadz); + DECLARE_WRITE8_MEMBER(cruwrite); + + void insert(int index, ti99_cartridge_device* cart); + void remove(int index); + DECLARE_INPUT_CHANGED_MEMBER( gk_changed ); + +protected: + virtual void device_start(); + virtual void device_reset(); + + virtual machine_config_constructor device_mconfig_additions() const; + virtual const rom_entry* device_rom_region() const; + virtual ioport_constructor device_input_ports() const; + + // device_nvram_interface + void nvram_default(); + void nvram_read(emu_file &file); + void nvram_write(emu_file &file); + +private: + int m_gk_switch[6]; // Used to cache the switch settings. + + int m_ram_page; + int m_grom_address; + UINT8* m_ram_ptr; + UINT8* m_grom_ptr; + + bool m_waddr_LSB; + + ti99_cartridge_device *m_cartridge; // guest cartridge + + // Just for proper initialization + void gk_install_menu(const char* menutext, int len, int ptr, int next, int start); +}; + +extern const device_type GROMPORT_SINGLE; +extern const device_type GROMPORT_MULTI; +extern const device_type GROMPORT_GK; + +/****************************************************************************/ + +class ti99_cartridge_pcb +{ + friend class ti99_cartridge_device; +public: + ti99_cartridge_pcb(); + virtual ~ti99_cartridge_pcb() { }; + +protected: + virtual DECLARE_READ8Z_MEMBER(readz); + virtual DECLARE_WRITE8_MEMBER(write); + virtual DECLARE_READ8Z_MEMBER(crureadz); + virtual DECLARE_WRITE8_MEMBER(cruwrite); + + DECLARE_READ8Z_MEMBER(gromreadz); + DECLARE_WRITE8_MEMBER(gromwrite); + inline void set_grom_pointer(int number, device_t *dev); + void set_cartridge(ti99_cartridge_device *cart); + UINT16 grom_base(); + UINT16 grom_mask(); + const char* tag() { return m_tag; } + void set_tag(const char* tag) { m_tag = tag; } + + ti99_cartridge_device* m_cart; + ti99_grom_device* m_grom[5]; + int m_grom_size; + int m_rom_size; + int m_ram_size; + + UINT8* m_rom_ptr; + UINT8* m_ram_ptr; + int m_rom_page; // for some cartridge types + UINT8* m_grom_ptr; // for gromemu + int m_grom_address; // for gromemu + int m_ram_page; // for super + const char* m_tag; +private: +}; + +/******************** Standard cartridge ******************************/ + +class ti99_standard_cartridge : public ti99_cartridge_pcb +{ +public: + ~ti99_standard_cartridge() { }; +}; + +/*********** Paged cartridge (like Extended Basic) ********************/ + +class ti99_paged_cartridge : public ti99_cartridge_pcb +{ +public: + ~ti99_paged_cartridge() { }; + DECLARE_READ8Z_MEMBER(readz); + DECLARE_WRITE8_MEMBER(write); +}; + +/********************** Mini Memory ***********************************/ + +class ti99_minimem_cartridge : public ti99_cartridge_pcb +{ +public: + ~ti99_minimem_cartridge() { }; + DECLARE_READ8Z_MEMBER(readz); + DECLARE_WRITE8_MEMBER(write); +}; + +/********************* Super Space II *********************************/ + +class ti99_super_cartridge : public ti99_cartridge_pcb +{ +public: + ~ti99_super_cartridge() { }; + DECLARE_READ8Z_MEMBER(readz); + DECLARE_WRITE8_MEMBER(write); + DECLARE_READ8Z_MEMBER(crureadz); + DECLARE_WRITE8_MEMBER(cruwrite); +}; + +/************************* MBX ***************************************/ + +class ti99_mbx_cartridge : public ti99_cartridge_pcb +{ +public: + ~ti99_mbx_cartridge() { }; + DECLARE_READ8Z_MEMBER(readz); + DECLARE_WRITE8_MEMBER(write); +}; + +/********************** Paged 379i ************************************/ + +class ti99_paged379i_cartridge : public ti99_cartridge_pcb +{ +public: + ~ti99_paged379i_cartridge() { }; + DECLARE_READ8Z_MEMBER(readz); + DECLARE_WRITE8_MEMBER(write); +private: + int get_paged379i_bank(int rompage); +}; + +/********************** Paged 378 ************************************/ + +class ti99_paged378_cartridge : public ti99_cartridge_pcb +{ +public: + ~ti99_paged378_cartridge() { }; + DECLARE_READ8Z_MEMBER(readz); + DECLARE_WRITE8_MEMBER(write); +private: + int get_paged378_bank(int rompage); +}; + +/********************** Paged 377 ************************************/ + +class ti99_paged377_cartridge : public ti99_cartridge_pcb +{ +public: + ~ti99_paged377_cartridge() { }; + DECLARE_READ8Z_MEMBER(readz); + DECLARE_WRITE8_MEMBER(write); +private: + int get_paged377_bank(int rompage); +}; + +/********************** Paged CRU ************************************/ + +class ti99_pagedcru_cartridge : public ti99_cartridge_pcb +{ +public: + ~ti99_pagedcru_cartridge() { }; + DECLARE_READ8Z_MEMBER(readz); + DECLARE_WRITE8_MEMBER(write); + DECLARE_READ8Z_MEMBER(crureadz); + DECLARE_WRITE8_MEMBER(cruwrite); +}; + +/********************** GROM emulation cartridge ************************************/ + +class ti99_gromemu_cartridge : public ti99_cartridge_pcb +{ +public: + ti99_gromemu_cartridge() { m_grom_address = 0; } + ~ti99_gromemu_cartridge() { }; + DECLARE_READ8Z_MEMBER(readz); + DECLARE_WRITE8_MEMBER(write); + DECLARE_READ8Z_MEMBER(gromemureadz); + DECLARE_WRITE8_MEMBER(gromemuwrite); +private: + bool m_waddr_LSB; +}; + + +struct pcb_type +{ + int id; + const char* name; +}; + +/************************************************************************* + RPK support +*************************************************************************/ +class rpk; + +class rpk_socket +{ + friend class simple_list; + friend class rpk; + +public: + rpk_socket(const char *id, int length, UINT8 *contents); + rpk_socket(const char *id, int length, UINT8 *contents, const char *pathname); + + const char* id() { return m_id; } + int get_content_length() { return m_length; } + UINT8* get_contents() { return m_contents; } + bool persistent_ram() { return m_pathname != NULL; } + const char* get_pathname() { return m_pathname; } + void cleanup() { if (m_contents != NULL) global_free_array(m_contents); } + +private: + const char* m_id; + UINT32 m_length; + rpk_socket* m_next; + UINT8* m_contents; + const char* m_pathname; +}; + +class rpk_reader +{ +public: + rpk_reader(const pcb_type *types) + : m_types(types) { }; + + rpk *open(emu_options &options, const char *filename, const char *system_name); + +private: + const zip_file_header* find_file(zip_file *zip, const char *filename, UINT32 crc); + rpk_socket* load_rom_resource(zip_file* zip, xml_data_node* rom_resource_node, const char* socketname); + rpk_socket* load_ram_resource(emu_options &options, xml_data_node* ram_resource_node, const char* socketname, const char* system_name); + const pcb_type* m_types; +}; + +class rpk +{ + friend class rpk_reader; +public: + rpk(emu_options& options, const char* sysname); + ~rpk(); + + int get_type(void) { return m_type; } + UINT8* get_contents_of_socket(const char *socket_name); + int get_resource_length(const char *socket_name); + void close(); + +private: + emu_options& m_options; // need this to find the path to the nvram files + int m_type; + //const char* m_system_name; // need this to find the path to the nvram files + tagged_list m_sockets; + + void add_socket(const char* id, rpk_socket *newsock); +}; + +enum rpk_open_error +{ + RPK_OK, + RPK_NOT_ZIP_FORMAT, + RPK_CORRUPT, + RPK_OUT_OF_MEMORY, + RPK_XML_ERROR, + RPK_INVALID_FILE_REF, + RPK_ZIP_ERROR, + RPK_ZIP_UNSUPPORTED, + RPK_MISSING_RAM_LENGTH, + RPK_INVALID_RAM_SPEC, + RPK_UNKNOWN_RESOURCE_TYPE, + RPK_INVALID_RESOURCE_REF, + RPK_INVALID_LAYOUT, + RPK_MISSING_LAYOUT, + RPK_NO_PCB_OR_RESOURCES, + RPK_UNKNOWN_PCB_TYPE +}; + +static const char error_text[16][30] = +{ + "No error", + "Not a RPK (zip) file", + "Module definition corrupt", + "Out of memory", + "XML format error", + "Invalid file reference", + "Zip file error", + "Unsupported zip version", + "Missing RAM length", + "Invalid RAM specification", + "Unknown resource type", + "Invalid resource reference", + "layout.xml not valid", + "Missing layout", + "No pcb or resource found", + "Unknown pcb type" +}; + +class rpk_exception +{ +public: + rpk_exception(rpk_open_error value): m_err(value), m_detail(NULL) { }; + rpk_exception(rpk_open_error value, const char* detail): m_err(value), m_detail(detail) { }; + + const char* to_string() + { + if (m_detail==NULL) return error_text[(int)m_err]; + std::string errormsg = std::string(error_text[(int)m_err]).append(": ").append(m_detail); + return core_strdup(errormsg.c_str()); + } + +private: + rpk_open_error m_err; + const char* m_detail; +}; + +#endif diff --git a/src/devices/bus/ti99x/handset.c b/src/devices/bus/ti99x/handset.c new file mode 100644 index 00000000000..4b41ea0bd06 --- /dev/null +++ b/src/devices/bus/ti99x/handset.c @@ -0,0 +1,530 @@ +// license:LGPL-2.1+ +// copyright-holders:Michael Zapf +/**************************************************************************** + + TI-99/4 Handset support (TI99/4 only) + + The ti99/4 was intended to support some so-called "IR remote handsets". + This feature was canceled at the last minute (reportedly ten minutes before + the introductory press conference in June 1979), but the first thousands of + 99/4 units had the required port, and the support code was seemingly not + deleted from ROMs until the introduction of the ti99/4a in 1981. You could + connect up to 4 20-key keypads, and up to 4 joysticks with a maximum + resolution of 15 levels on each axis. + + The keyboard DSR was able to couple two 20-key keypads together to emulate + a full 40-key keyboard. Keyboard modes 0, 1 and 2 would select either the + console keyboard with its two wired remote controllers (i.e. joysticks), or + remote handsets 1 and 2 with their associated IR remote controllers (i.e. + joysticks), according to which was currently active. + + Originally written by R. Nabet + + ************************************************** + + TI-99/4(A) Twin Joystick + + This file also contains the implementation of the twin joystick; + actually, no big deal, as it contains no logic but only switches. + + ************************************************** + + Michael Zapf + 2010-10-24 Rewriten as device + + January 2012: Rewritten as class + +*****************************************************************************/ + +#include "handset.h" +#include "machine/tms9901.h" + +#define LOG logerror +#define VERBOSE 1 + +static const char *const joynames[2][4] = +{ + { "JOY0", "JOY2", "JOY4", "JOY6" }, // X axis + { "JOY1", "JOY3", "JOY5", "JOY7" } // Y axis +}; + +static const char *const keynames[] = { "KP0", "KP1", "KP2", "KP3", "KP4" }; + +ti99_handset_device::ti99_handset_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) +: joyport_attached_device(mconfig, HANDSET, "TI-99/4 IR handset", tag, owner, clock, "handset", __FILE__) +{ +} + +#define POLL_TIMER 1 +#define DELAY_TIMER 2 + +/*****************************************************************************/ + +/* + Return the status of the handset via the joystick port. + B = bus + C = clock + I = int (neg logic) + + answer = |0|I|C|1|B|B|B|B| +*/ +UINT8 ti99_handset_device::read_dev() +{ + return (m_buf & 0xf) | 0x10 | (m_clock_high? 0x20:0) | ( m_buflen==3? 0x00:0x40); +} + +void ti99_handset_device::write_dev(UINT8 data) +{ + if (VERBOSE>7) LOG("ti99_handset_device: Set ack %d\n", data); + set_acknowledge(data); +} + +/* + Handle data acknowledge sent by the ti-99/4 handset ISR (through tms9901 + line P0). This function is called by a delayed timer 30us after the state + of P0 is changed, because, in one occasion, the ISR asserts the line before + it reads the data, so we need to delay the acknowledge process. +*/ +void ti99_handset_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + m_clock_high = !m_clock_high; + m_buf >>= 4; + m_buflen--; + + // Clear the INT12 line + m_joyport->set_interrupt(CLEAR_LINE); + + if (m_buflen == 1) + { + // Unless I am missing something, the third and last nibble of the + // message is not acknowledged by the DSR in any way, and the first nibble + // of next message is not requested for either, so we need to decide on + // our own when we can post a new event. Currently, we wait for 1000us + // after the DSR acknowledges the second nybble. + m_delay_timer->adjust(attotime::from_usec(1000)); + } + + if (m_buflen == 0) + /* See if we need to post a new event */ + do_task(); +} + +/* + Handler for tms9901 P0 pin (handset data acknowledge) +*/ +void ti99_handset_device::set_acknowledge(int data) +{ + if ((m_buflen !=0) && (data != m_ack)) + { + m_ack = data; + if ((data!=0) == m_clock_high) + { + // I don't know what the real delay is, but 30us apears to be enough + m_delay_timer->adjust(attotime::from_usec(30)); + } + } +} + +/* + post_message() + + Post a 12-bit message: trigger an interrupt on the tms9901, and store the + message in the I/R receiver buffer so that the handset ISR will read this + message. + + message: 12-bit message to post (only the 12 LSBits are meaningful) +*/ +void ti99_handset_device::post_message(int message) +{ + /* post message and assert interrupt */ + m_clock_high = true; + m_buf = ~message; + m_buflen = 3; + if (VERBOSE>5) LOG("ti99_handset_device: trigger interrupt\n"); + m_joyport->set_interrupt(ASSERT_LINE); +} + +/* + poll_keyboard() + Poll the current state of one given handset keypad. + num: number of the keypad to poll (0-3) + Returns TRUE if the handset state has changed and a message was posted. +*/ +bool ti99_handset_device::poll_keyboard(int num) +{ + UINT32 key_buf; + UINT8 current_key; + int i; + + /* read current key state */ + key_buf = (ioport(keynames[num])->read() | (ioport(keynames[num + 1])->read() << 16) ) >> (4*num); + + // If a key was previously pressed, this key was not shift, and this key is + // still down, then don't change the current key press. + if (previous_key[num] !=0 && (previous_key[num] != 0x24) + && (key_buf & (1 << (previous_key[num] & 0x1f)))) + { + /* check the shift modifier state */ + if (((previous_key[num] & 0x20) != 0) == ((key_buf & 0x0008) != 0)) + /* the shift modifier state has not changed */ + return false; + else + { + // The shift modifier state has changed: we need to update the + // keyboard state + if (key_buf & 0x0008) + { /* shift has been pressed down */ + previous_key[num] = current_key = previous_key[num] | 0x20; + } + else + { + previous_key[num] = current_key = previous_key[num] & ~0x20; + } + /* post message */ + post_message((((unsigned)current_key) << 4) | (num << 1)); + return true; + } + } + + current_key = 0; /* default value if no key is down */ + for (i=0; i<20; i++) + { + if (key_buf & (1 << i)) + { + current_key = i + 1; + if (key_buf & 0x0008) + current_key |= 0x20; /* set shift flag */ + + if (current_key != 0x24) + // If this is the shift key, any other key we may find will + // have higher priority; otherwise, we may exit the loop and keep + // the key we have just found. + break; + } + } + + if (current_key != previous_key[num]) + { + previous_key[num] = current_key; + + /* post message */ + post_message((((unsigned) current_key) << 4) | (num << 1)); + return true; + } + return false; +} + +/* + poll_joystick() + + Poll the current state of one given handset joystick. + num: number of the joystick to poll (0-3) + Returns TRUE if the handset state has changed and a message was posted. +*/ +bool ti99_handset_device::poll_joystick(int num) +{ + UINT8 current_joy; + int current_joy_x, current_joy_y; + int message; + /* read joystick position */ + current_joy_x = ioport(joynames[0][num])->read(); + current_joy_y = ioport(joynames[1][num])->read(); + + /* compare with last saved position */ + current_joy = current_joy_x | (current_joy_y << 4); + if (current_joy != previous_joy[num]) + { + /* save position */ + previous_joy[num] = current_joy; + + /* transform position to signed quantity */ + current_joy_x -= 7; + current_joy_y -= 7; + + message = 0; + + /* set sign */ + // note that we set the sign if the joystick position is 0 to work + // around a bug in the ti99/4 ROMs + if (current_joy_x <= 0) + { + message |= 0x040; + current_joy_x = - current_joy_x; + } + + if (current_joy_y <= 0) + { + message |= 0x400; + current_joy_y = - current_joy_y; + } + + /* convert absolute values to Gray code and insert in message */ + if (current_joy_x & 4) + current_joy_x ^= 3; + if (current_joy_x & 2) + current_joy_x ^= 1; + message |= current_joy_x << 3; + + if (current_joy_y & 4) + current_joy_y ^= 3; + if (current_joy_y & 2) + current_joy_y ^= 1; + message |= current_joy_y << 7; + + /* set joystick address */ + message |= (num << 1) | 0x1; + + /* post message */ + post_message(message); + return true; + } + return false; +} + +/* + ti99_handset_task() + Manage handsets, posting an event if the state of any handset has changed. +*/ +void ti99_handset_device::do_task() +{ + int i; + + if (m_buflen == 0) + { + /* poll every handset */ + for (i=0; i < MAX_HANDSETS; i++) + if (poll_joystick(i)==true) return; + for (i=0; i < MAX_HANDSETS; i++) + if (poll_keyboard(i)==true) return; + } + else if (m_buflen == 3) + { /* update messages after they have been posted */ + if (m_buf & 1) + { /* keyboard */ + poll_keyboard((~(m_buf >> 1)) & 0x3); + } + else + { /* joystick */ + poll_joystick((~(m_buf >> 1)) & 0x3); + } + } +} + +void ti99_handset_device::pulse_clock() +{ + logerror("handset: pulse_clock\n"); + do_task(); +} + +void ti99_handset_device::device_start(void) +{ + m_delay_timer = timer_alloc(DELAY_TIMER); +} + +void ti99_handset_device::device_reset(void) +{ + if (VERBOSE>5) LOG("ti99_handset_device: Reset\n"); + m_delay_timer->enable(true); + m_buf = 0; + m_buflen = 0; + m_clock_high = false; + m_ack = 0; +} + +#define JOYSTICK_DELTA 10 +#define JOYSTICK_SENSITIVITY 100 + +INPUT_PORTS_START( handset ) + /* 13 pseudo-ports for IR remote handsets */ + + /* 8 pseudo-ports for the 4 IR joysticks */ + PORT_START("JOY0") /* joystick 1, X axis */ + PORT_BIT( 0xf, 0x7, IPT_AD_STICK_X) PORT_SENSITIVITY(JOYSTICK_SENSITIVITY) PORT_KEYDELTA(JOYSTICK_DELTA) PORT_MINMAX(0,0xe) PORT_PLAYER(1) + + PORT_START("JOY1") /* joystick 1, Y axis */ + PORT_BIT( 0xf, 0x7, IPT_AD_STICK_Y) PORT_SENSITIVITY(JOYSTICK_SENSITIVITY) PORT_KEYDELTA(JOYSTICK_DELTA) PORT_MINMAX(0,0xe) PORT_PLAYER(1) PORT_REVERSE + + PORT_START("JOY2") /* joystick 2, X axis */ + PORT_BIT( 0xf, 0x7, IPT_AD_STICK_X) PORT_SENSITIVITY(JOYSTICK_SENSITIVITY) PORT_KEYDELTA(JOYSTICK_DELTA) PORT_MINMAX(0,0xe) PORT_PLAYER(2) + + PORT_START("JOY3") /* joystick 2, Y axis */ + PORT_BIT( 0xf, 0x7, IPT_AD_STICK_Y) PORT_SENSITIVITY(JOYSTICK_SENSITIVITY) PORT_KEYDELTA(JOYSTICK_DELTA) PORT_MINMAX(0,0xe) PORT_PLAYER(2) PORT_REVERSE + + PORT_START("JOY4") /* joystick 3, X axis */ + PORT_BIT( 0xf, 0x7, IPT_AD_STICK_X) PORT_SENSITIVITY(JOYSTICK_SENSITIVITY) PORT_KEYDELTA(JOYSTICK_DELTA) PORT_MINMAX(0,0xe) PORT_PLAYER(3) + + PORT_START("JOY5") /* joystick 3, Y axis */ + PORT_BIT( 0xf, 0x7, IPT_AD_STICK_Y) PORT_SENSITIVITY(JOYSTICK_SENSITIVITY) PORT_KEYDELTA(JOYSTICK_DELTA) PORT_MINMAX(0,0xe) PORT_PLAYER(3) PORT_REVERSE + + PORT_START("JOY6") /* joystick 4, X axis */ + PORT_BIT( 0xf, 0x7, IPT_AD_STICK_X) PORT_SENSITIVITY(JOYSTICK_SENSITIVITY) PORT_KEYDELTA(JOYSTICK_DELTA) PORT_MINMAX(0,0xe) PORT_PLAYER(4) + + PORT_START("JOY7") /* joystick 4, Y axis */ + PORT_BIT( 0xf, 0x7, IPT_AD_STICK_Y) PORT_SENSITIVITY(JOYSTICK_SENSITIVITY) PORT_KEYDELTA(JOYSTICK_DELTA) PORT_MINMAX(0,0xe) PORT_PLAYER(4) PORT_REVERSE + + /* 5 pseudo-ports for the 4 IR remote keypads */ + PORT_START("KP0") /* keypad 1, keys 1 to 16 */ + PORT_BIT(0x0001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("1: CLR") PORT_CODE(KEYCODE_1) PORT_PLAYER(1) + PORT_BIT(0x0002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("1: GO") PORT_CODE(KEYCODE_Q) PORT_PLAYER(1) + PORT_BIT(0x0004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("1: SET") PORT_CODE(KEYCODE_SPACE) PORT_PLAYER(1) + PORT_BIT(0x0008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("1: NEXT") PORT_CODE(KEYCODE_LSHIFT) PORT_PLAYER(1) + PORT_BIT(0x0010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("1: 7") PORT_CODE(KEYCODE_2) PORT_PLAYER(1) + PORT_BIT(0x0020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("1: 4") PORT_CODE(KEYCODE_W) PORT_PLAYER(1) + PORT_BIT(0x0040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("1: 1") PORT_CODE(KEYCODE_A) PORT_PLAYER(1) + PORT_BIT(0x0080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("1: STOP") PORT_CODE(KEYCODE_Z) PORT_PLAYER(1) + PORT_BIT(0x0100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("1: 8") PORT_CODE(KEYCODE_3) PORT_PLAYER(1) + PORT_BIT(0x0200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("1: 5") PORT_CODE(KEYCODE_E) PORT_PLAYER(1) + PORT_BIT(0x0400, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("1: 2") PORT_CODE(KEYCODE_S) PORT_PLAYER(1) + PORT_BIT(0x0800, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("1: 0") PORT_CODE(KEYCODE_X) PORT_PLAYER(1) + PORT_BIT(0x1000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("1: 9") PORT_CODE(KEYCODE_4) PORT_PLAYER(1) + PORT_BIT(0x2000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("1: 6") PORT_CODE(KEYCODE_R) PORT_PLAYER(1) + PORT_BIT(0x4000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("1: 3") PORT_CODE(KEYCODE_D) PORT_PLAYER(1) + PORT_BIT(0x8000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("1: E =") PORT_CODE(KEYCODE_C) PORT_PLAYER(1) + + PORT_START("KP1") /* keypad 1, keys 17 to 20 */ + PORT_BIT(0x0001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("1: (div)") PORT_CODE(KEYCODE_5) PORT_PLAYER(1) + PORT_BIT(0x0002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("1: (mul)") PORT_CODE(KEYCODE_T) PORT_PLAYER(1) + PORT_BIT(0x0004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("1: NO -") PORT_CODE(KEYCODE_F) PORT_PLAYER(1) + PORT_BIT(0x0008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("1: YES +") PORT_CODE(KEYCODE_V) PORT_PLAYER(1) + /* keypad 2, keys 1 to 12 */ + PORT_BIT(0x0010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("2: CLR") PORT_CODE(KEYCODE_6) PORT_PLAYER(2) + PORT_BIT(0x0020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("2: GO") PORT_CODE(KEYCODE_Y) PORT_PLAYER(2) + PORT_BIT(0x0040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("2: SET") PORT_CODE(KEYCODE_G) PORT_PLAYER(2) + PORT_BIT(0x0080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("2: NEXT") PORT_CODE(KEYCODE_B) PORT_PLAYER(2) + PORT_BIT(0x0100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("2: 7") PORT_CODE(KEYCODE_7) PORT_PLAYER(2) + PORT_BIT(0x0200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("2: 4") PORT_CODE(KEYCODE_U) PORT_PLAYER(2) + PORT_BIT(0x0400, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("2: 1") PORT_CODE(KEYCODE_H) PORT_PLAYER(2) + PORT_BIT(0x0800, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("2: STOP") PORT_CODE(KEYCODE_N) PORT_PLAYER(2) + PORT_BIT(0x1000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("2: 8") PORT_CODE(KEYCODE_8) PORT_PLAYER(2) + PORT_BIT(0x2000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("2: 5") PORT_CODE(KEYCODE_I) PORT_PLAYER(2) + PORT_BIT(0x4000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("2: 2") PORT_CODE(KEYCODE_J) PORT_PLAYER(2) + PORT_BIT(0x8000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("2: 0") PORT_CODE(KEYCODE_M) PORT_PLAYER(2) + + PORT_START("KP2") /* keypad 2, keys 13 to 20 */ + PORT_BIT(0x0001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("2: 9") PORT_CODE(KEYCODE_9) PORT_PLAYER(2) + PORT_BIT(0x0002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("2: 6") PORT_CODE(KEYCODE_O) PORT_PLAYER(2) + PORT_BIT(0x0004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("2: 3") PORT_CODE(KEYCODE_K) PORT_PLAYER(2) + PORT_BIT(0x0008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("2: E =") PORT_CODE(KEYCODE_STOP) PORT_PLAYER(2) + PORT_BIT(0x0010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("2: (div)") PORT_CODE(KEYCODE_0) PORT_PLAYER(2) + PORT_BIT(0x0020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("2: (mul)") PORT_CODE(KEYCODE_P) PORT_PLAYER(2) + PORT_BIT(0x0040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("2: NO -") PORT_CODE(KEYCODE_L) PORT_PLAYER(2) + PORT_BIT(0x0080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("2: YES +") PORT_CODE(KEYCODE_ENTER) PORT_PLAYER(2) + /* keypad 3, keys 1 to 8 */ + PORT_BIT(0x0100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("3: CLR") PORT_CODE(KEYCODE_1) PORT_PLAYER(3) + PORT_BIT(0x0200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("3: GO") PORT_CODE(KEYCODE_Q) PORT_PLAYER(3) + PORT_BIT(0x0400, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("3: SET") PORT_CODE(KEYCODE_SPACE) PORT_PLAYER(3) + PORT_BIT(0x0800, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("3: NEXT") PORT_CODE(KEYCODE_LSHIFT) PORT_PLAYER(3) + PORT_BIT(0x1000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("3: 7") PORT_CODE(KEYCODE_2) PORT_PLAYER(3) + PORT_BIT(0x2000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("3: 4") PORT_CODE(KEYCODE_W) PORT_PLAYER(3) + PORT_BIT(0x4000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("3: 1") PORT_CODE(KEYCODE_A) PORT_PLAYER(3) + PORT_BIT(0x8000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("3: STOP") PORT_CODE(KEYCODE_Z) PORT_PLAYER(3) + + PORT_START("KP3") /* keypad 3, keys 9 to 20 */ + PORT_BIT(0x0001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("3: 8") PORT_CODE(KEYCODE_3) PORT_PLAYER(3) + PORT_BIT(0x0002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("3: 5") PORT_CODE(KEYCODE_E) PORT_PLAYER(3) + PORT_BIT(0x0004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("3: 2") PORT_CODE(KEYCODE_S) PORT_PLAYER(3) + PORT_BIT(0x0008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("3: 0") PORT_CODE(KEYCODE_X) PORT_PLAYER(3) + PORT_BIT(0x0010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("3: 9") PORT_CODE(KEYCODE_4) PORT_PLAYER(3) + PORT_BIT(0x0020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("3: 6") PORT_CODE(KEYCODE_R) PORT_PLAYER(3) + PORT_BIT(0x0040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("3: 3") PORT_CODE(KEYCODE_D) PORT_PLAYER(3) + PORT_BIT(0x0080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("3: E =") PORT_CODE(KEYCODE_C) PORT_PLAYER(3) + PORT_BIT(0x0100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("3: (div)") PORT_CODE(KEYCODE_5) PORT_PLAYER(3) + PORT_BIT(0x0200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("3: (mul)") PORT_CODE(KEYCODE_T) PORT_PLAYER(3) + PORT_BIT(0x0400, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("3: NO -") PORT_CODE(KEYCODE_F) PORT_PLAYER(3) + PORT_BIT(0x0800, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("3: YES +") PORT_CODE(KEYCODE_V) PORT_PLAYER(3) + /* keypad 4, keys 1 to 4 */ + PORT_BIT(0x1000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("4: CLR") PORT_CODE(KEYCODE_6) PORT_PLAYER(4) + PORT_BIT(0x2000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("4: GO") PORT_CODE(KEYCODE_Y) PORT_PLAYER(4) + PORT_BIT(0x4000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("4: SET") PORT_CODE(KEYCODE_G) PORT_PLAYER(4) + PORT_BIT(0x8000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("4: NEXT") PORT_CODE(KEYCODE_B) PORT_PLAYER(4) + + PORT_START("KP4") /* keypad 4, keys 5 to 20 */ + PORT_BIT(0x0001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("4: 7") PORT_CODE(KEYCODE_7) PORT_PLAYER(4) + PORT_BIT(0x0002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("4: 4") PORT_CODE(KEYCODE_U) PORT_PLAYER(4) + PORT_BIT(0x0004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("4: 1") PORT_CODE(KEYCODE_H) PORT_PLAYER(4) + PORT_BIT(0x0008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("4: STOP") PORT_CODE(KEYCODE_N) PORT_PLAYER(4) + PORT_BIT(0x0010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("4: 8") PORT_CODE(KEYCODE_8) PORT_PLAYER(4) + PORT_BIT(0x0020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("4: 5") PORT_CODE(KEYCODE_I) PORT_PLAYER(4) + PORT_BIT(0x0040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("4: 2") PORT_CODE(KEYCODE_J) PORT_PLAYER(4) + PORT_BIT(0x0080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("4: 0") PORT_CODE(KEYCODE_M) PORT_PLAYER(4) + PORT_BIT(0x0100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("4: 9") PORT_CODE(KEYCODE_9) PORT_PLAYER(4) + PORT_BIT(0x0200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("4: 6") PORT_CODE(KEYCODE_O) PORT_PLAYER(4) + PORT_BIT(0x0400, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("4: 3") PORT_CODE(KEYCODE_K) PORT_PLAYER(4) + PORT_BIT(0x0800, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("4: E =") PORT_CODE(KEYCODE_STOP) PORT_PLAYER(4) + PORT_BIT(0x1000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("4: (div)") PORT_CODE(KEYCODE_0) PORT_PLAYER(4) + PORT_BIT(0x2000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("4: (mul)") PORT_CODE(KEYCODE_P) PORT_PLAYER(4) + PORT_BIT(0x4000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("4: NO -") PORT_CODE(KEYCODE_L) PORT_PLAYER(4) + PORT_BIT(0x8000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("4: YES +") PORT_CODE(KEYCODE_ENTER) PORT_PLAYER(4) +INPUT_PORTS_END + +ioport_constructor ti99_handset_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( handset ); +} + +const device_type HANDSET = &device_creator; + +/****************************************************************************** + Twin Joystick +******************************************************************************/ + +/* col 6: "wired handset 1" (= joystick 1) */ +/* col 7: "wired handset 2" (= joystick 2) */ + +INPUT_PORTS_START( joysticks ) + PORT_START("JOY1") + PORT_BIT(0xE0, IP_ACTIVE_LOW, IPT_UNUSED) + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_JOYSTICK_UP/*, "(1UP)", CODE_NONE, OSD_JOY_UP*/) PORT_PLAYER(1) + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN/*, "(1DOWN)", CODE_NONE, OSD_JOY_DOWN, 0*/) PORT_PLAYER(1) + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT/*, "(1RIGHT)", CODE_NONE, OSD_JOY_RIGHT, 0*/) PORT_PLAYER(1) + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT/*, "(1LEFT)", CODE_NONE, OSD_JOY_LEFT, 0*/) PORT_PLAYER(1) + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_BUTTON1/*, "(1FIRE)", CODE_NONE, OSD_JOY_FIRE, 0*/) PORT_PLAYER(1) + + PORT_START("JOY2") + PORT_BIT(0xE0, IP_ACTIVE_LOW, IPT_UNUSED) + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_JOYSTICK_UP/*, "(2UP)", CODE_NONE, OSD_JOY2_UP, 0*/) PORT_PLAYER(2) + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN/*, "(2DOWN)", CODE_NONE, OSD_JOY2_DOWN, 0*/) PORT_PLAYER(2) + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT/*, "(2RIGHT)", CODE_NONE, OSD_JOY2_RIGHT, 0*/) PORT_PLAYER(2) + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT/*, "(2LEFT)", CODE_NONE, OSD_JOY2_LEFT, 0*/) PORT_PLAYER(2) + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_BUTTON1/*, "(2FIRE)", CODE_NONE, OSD_JOY2_FIRE, 0*/) PORT_PLAYER(2) +INPUT_PORTS_END + +ti99_twin_joystick::ti99_twin_joystick(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) +: joyport_attached_device(mconfig, HANDSET, "TI-99/4(A) Twin Joystick", tag, owner, clock, "twinjoy", __FILE__) +{ +} + +void ti99_twin_joystick::device_start(void) +{ +} + +/* + Return the status of the joysticks. + + answer = |0|0|0|U|D|R|L|B| +*/ +UINT8 ti99_twin_joystick::read_dev() +{ + UINT8 value; + if (m_joystick==1) value = ioport("JOY1")->read(); + else + { + if (m_joystick==2) value = ioport("JOY2")->read(); + else value = 0xff; + } + if (VERBOSE>6) LOG("ti99_twin_joystick: joy%d = %02x\n", m_joystick, value); + return value; +} + +void ti99_twin_joystick::write_dev(UINT8 data) +{ + if (VERBOSE>7) LOG("ti99_twin_joystick: Select joystick %d\n", data); + m_joystick = data & 0x03; +} + +ioport_constructor ti99_twin_joystick::device_input_ports() const +{ + return INPUT_PORTS_NAME( joysticks ); +} + +const device_type TI99_JOYSTICK = &device_creator; diff --git a/src/devices/bus/ti99x/handset.h b/src/devices/bus/ti99x/handset.h new file mode 100644 index 00000000000..ccecd741034 --- /dev/null +++ b/src/devices/bus/ti99x/handset.h @@ -0,0 +1,93 @@ +// license:LGPL-2.1+ +// copyright-holders:Michael Zapf +/**************************************************************************** + + TI-99/4 handset + See handset.c for documentation. + + This file also contains the implementation of the twin joystick; + actually, no big deal, as it contains no logic but only switches. + + Michael Zapf, October 2010 + February 2012: Rewritten as class + June 2012: Added joystick + +*****************************************************************************/ + +#ifndef __HANDSET__ +#define __HANDSET__ + +#include "emu.h" +#include "joyport.h" + +#define MAX_HANDSETS 4 + +extern const device_type HANDSET; + +class ti99_handset_device : public joyport_attached_device +{ +public: + ti99_handset_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + UINT8 read_dev(); + void write_dev(UINT8 data); + + void pulse_clock(); + +protected: + virtual void device_start(void); + virtual void device_reset(void); + virtual ioport_constructor device_input_ports() const; + + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + +private: + void do_task(); + void post_message(int message); + bool poll_keyboard(int num); + bool poll_joystick(int num); + void set_acknowledge(int data); + + int m_ack; + bool m_clock_high; + int m_buf; + int m_buflen; + UINT8 previous_joy[MAX_HANDSETS]; + UINT8 previous_key[MAX_HANDSETS]; + + emu_timer *m_delay_timer; +}; + +#define MCFG_HANDSET_ADD(_tag, _intf, _clock ) \ + MCFG_DEVICE_ADD(_tag, HANDSET, _clock) \ + MCFG_DEVICE_CONFIG(_intf) + +#define TI99_HANDSET_INTERFACE(name) \ + const ti99_handset_intf(name) = + +/****************************************************************************/ + +extern const device_type TI99_JOYSTICK; + +class ti99_twin_joystick : public joyport_attached_device +{ +public: + ti99_twin_joystick(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + DECLARE_READ8_MEMBER( read ); + virtual void device_start(void); + + UINT8 read_dev(); + void write_dev(UINT8 data); + +protected: + virtual ioport_constructor device_input_ports() const; + +private: + // Which joystick is selected? + // In reality this is no latch but GND is put on one of the selector lines + // and then routed back to the port via the joystick + int m_joystick; +}; + + +#endif diff --git a/src/devices/bus/ti99x/joyport.c b/src/devices/bus/ti99x/joyport.c new file mode 100644 index 00000000000..d49345e0b0a --- /dev/null +++ b/src/devices/bus/ti99x/joyport.c @@ -0,0 +1,115 @@ +// license:LGPL-2.1+ +// copyright-holders:Michael Zapf +/**************************************************************************** + + Joystick port + + Now explicitly implemented as a slot device + A joystick port allows for plugging in digital devices like joysticks or + a Mechatronics mouse, and the TI-99/4 (prototype) also offered IR handsets + driven over this port. The 99/4 had an additional line for triggering an + interrupt. + + +-----------+ + | 1 2 3 4 5 | + \ 6 7 8 9 / + +-------+ + + Getting the joystick directions and button is pretty simple: The TMS9901 in + the TI console lowers the select line, and the joystick shorts a line for + the respective action. The lines go back to the inputs of the TMS9901. + + pin 1 nc + 2 select joystick 2 + 3 up + 4 button + 5 left + 6 nc + 7 select joystick 1 + 8 down + 9 right + + Michael Zapf + + June 2012 + +*****************************************************************************/ + +#include "joyport.h" +#include "handset.h" +#include "mecmouse.h" + +joyport_device::joyport_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, JOYPORT, "Joystick port", tag, owner, clock, "ti99_joyport", __FILE__), + device_slot_interface(mconfig, *this), + m_interrupt(*this) +{ +} + +/* + Reads a value from the port. +*/ +UINT8 joyport_device::read_port() +{ + return m_connected->read_dev(); +} + +/* + This is used to select the device at the port. The device should keep this + value until read() is called. +*/ +void joyport_device::write_port(int data) +{ + m_connected->write_dev(data); +} + +/* + This is only used for the handset device of the TI-99/4. It is driven by the VDP interrupt. +*/ +void joyport_device::pulse_clock() +{ + m_connected->pulse_clock(); +} + +/* + Propagate the interrupt to the defined target. Only used for the handset + at the prototype 99/4. +*/ +WRITE_LINE_MEMBER( joyport_device::set_interrupt ) +{ + m_interrupt(state); +} + +void joyport_device::device_start() +{ + m_interrupt.resolve(); +} + +void joyport_device::device_config_complete() +{ + m_connected = static_cast(first_subdevice()); +} + +/*****************************************************************************/ + +void joyport_attached_device::device_config_complete() +{ + m_joyport = static_cast(owner()); +} + +SLOT_INTERFACE_START( joystick_port ) + SLOT_INTERFACE("twinjoy", TI99_JOYSTICK) + SLOT_INTERFACE("mecmouse", MECMOUSE) +SLOT_INTERFACE_END + +SLOT_INTERFACE_START( joystick_port_gen ) + SLOT_INTERFACE("twinjoy", TI99_JOYSTICK) +SLOT_INTERFACE_END + +SLOT_INTERFACE_START( joystick_port_994 ) + SLOT_INTERFACE("twinjoy", TI99_JOYSTICK) + SLOT_INTERFACE("mecmouse", MECMOUSE) + SLOT_INTERFACE("handset", HANDSET) +SLOT_INTERFACE_END + +const device_type JOYPORT = &device_creator; diff --git a/src/devices/bus/ti99x/joyport.h b/src/devices/bus/ti99x/joyport.h new file mode 100644 index 00000000000..6d19148fad7 --- /dev/null +++ b/src/devices/bus/ti99x/joyport.h @@ -0,0 +1,89 @@ +// license:LGPL-2.1+ +// copyright-holders:Michael Zapf +/**************************************************************************** + + Joystick port + + Now explicitly implemented as a slot device + A joystick port allows for plugging in a single or twin joystick, or + a Mechatronics mouse. + + The TI-99/4 also offers an infrared handset, connected to this port. For + this reason we also need an interrupt line. + + Michael Zapf + + June 2012 + +*****************************************************************************/ + +#ifndef __JOYPORT__ +#define __JOYPORT__ + +#include "emu.h" + +extern const device_type JOYPORT; + +class joyport_device; + +/******************************************************************** + Common parent class of all devices attached to the joystick port +********************************************************************/ +class joyport_attached_device : public device_t +{ +public: + joyport_attached_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source) { } + + virtual UINT8 read_dev() =0; + virtual void write_dev(UINT8 data) =0; + virtual void pulse_clock() { }; + +protected: + virtual void device_config_complete(); + joyport_device* m_joyport; +}; + +/******************************************************************** + Joystick port +********************************************************************/ +class joyport_device : public device_t, public device_slot_interface +{ +public: + joyport_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + UINT8 read_port(); + void write_port(int data); + void set_interrupt(int state); + void pulse_clock(); + + template static devcb_base &static_set_int_callback(device_t &device, _Object object) { return downcast(device).m_interrupt.set_callback(object); } + +protected: + void device_start(); + void device_config_complete(); + +private: + devcb_write_line m_interrupt; + joyport_attached_device* m_connected; +}; + +SLOT_INTERFACE_EXTERN(joystick_port); +SLOT_INTERFACE_EXTERN(joystick_port_994); +SLOT_INTERFACE_EXTERN(joystick_port_gen); + +#define MCFG_JOYPORT_INT_HANDLER( _intcallb ) \ + devcb = &joyport_device::static_set_int_callback( *device, DEVCB_##_intcallb ); + +#define MCFG_GENEVE_JOYPORT_ADD( _tag ) \ + MCFG_DEVICE_ADD(_tag, JOYPORT, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(joystick_port_gen, "twinjoy", false) + +#define MCFG_TI_JOYPORT4A_ADD( _tag ) \ + MCFG_DEVICE_ADD(_tag, JOYPORT, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(joystick_port, "twinjoy", false) + +#define MCFG_TI_JOYPORT4_ADD( _tag ) \ + MCFG_DEVICE_ADD(_tag, JOYPORT, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(joystick_port_994, "twinjoy", false) + +#endif /* __JOYPORT__ */ diff --git a/src/devices/bus/ti99x/mecmouse.c b/src/devices/bus/ti99x/mecmouse.c new file mode 100644 index 00000000000..6afcec642d4 --- /dev/null +++ b/src/devices/bus/ti99x/mecmouse.c @@ -0,0 +1,209 @@ +// license:LGPL-2.1+ +// copyright-holders:Michael Zapf +/**************************************************************************** + + TI-99 Mechatronic mouse with adapter + + The Mechatronic mouse is connected to the joystick port and occupies + both joystick select lines and the switch lines. From these five + lines, left/right/down are used for the motion (i.e. 3 motion steps + for positive and four for negative motion and one for rest), + the fire line is used for the secondary mouse button, and the up + line is used for the primary button. + The mouse motion is delivered by the same lines for both directions; + this requires swapping the axes. According to the source code of + the accompanying mouse driver, the readout of the current axis is + done by selecting joystick 1, then joystick 2. The axis swapping is + achieved by selecting stick 1 again. When selecting stick 2, the + second axis is seen on the input lines. + Interrupting this sequence will lead to swapped axes. This is + prevented by resetting the toggle when the mouse is deselected + (neither 1 nor 2 are selected). + + The joystick lines are selected as follows: + TI-99/4: Stick 1: P4=1, P3=0, P2=1 (5) + Stick 2: P4=1, P3=1, P2=0 (6) + + TI-99/4A: Stick 1: P4=1, P3=1, P2=0 (6) + Stick 2: P4=1, P3=1, P2=1 (7) + + TI-99/8: Stick 1: P3=1, P2=1, P1=1, P0=0 (14) + Stick 2: P3=1, P2=1, P1=1, P0=1 (15) + + Geneve: n/a, has own mouse handling via v9938 + + As we can only deliver at max 3 steps positive and 4 steps negative, + we split the delta so that subsequent queries add up to the actual + delta. That is, one delta of +10 yields a 3+3+3+1. + + mecmouse_x holds the current delta to be counted down for x + (y accordingly) + + mecmouse_x_buf is the current step count reported to CRU + + Michael Zapf, 2008-01-22 + + 2010-10-22 Rewriten as device + February 2012: Rewritten as class + +*****************************************************************************/ + +#include "mecmouse.h" + +#define POLL_TIMER 1 + +mecmouse_device::mecmouse_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : joyport_attached_device(mconfig, MECMOUSE, "Mechatronics Mouse", tag, owner, clock, "mecmouse", __FILE__) +{ +} + + +UINT8 mecmouse_device::read_dev() +{ + int answer; + int buttons = ioport("MOUSE0")->read() & 3; + + answer = (m_read_y_axis? m_y_buf : m_x_buf) << 1; + + if ((buttons & 1)==0) + /* action button */ + answer |= 0x01; + if ((buttons & 2)==0) + /* home button */ + answer |= 0x10; + + // answer: |0|0|0|B2|V|V|V|B1| + + return answer; +} + +/* + Used to select lines. data = 0x01 (Joy1), 0x02 (Joy2) +*/ +void mecmouse_device::write_dev(UINT8 data) +{ + if (data == 0x02) { + if (m_last_select == 0x01) { + if (!m_read_y_axis) + { + /* Sample x motion. */ + if (m_x < -4) + m_x_buf = -4; + else if (m_x > 3) + m_x_buf = 3; + else + m_x_buf = m_x; + m_x -= m_x_buf; + m_x_buf = (m_x_buf-1) & 7; + } + else + { + /* Sample y motion. */ + if (m_y < -4) + m_y_buf = -4; + else if (m_y > 3) + m_y_buf = 3; + else + m_y_buf = m_y; + m_y -= m_y_buf; + m_y_buf = (m_y_buf-1) & 7; + } + } + m_last_select = data; + } + else if (data == 0x01) + { + if (m_last_select == 0x02) + { + /* Swap the axes. */ + m_read_y_axis = !m_read_y_axis; + } + m_last_select = data; + } + else + { + // Reset the axis toggle when the mouse is deselected + m_read_y_axis = false; + } +} + +void mecmouse_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + // Poll the movement + int new_mx, new_my; + int delta_x, delta_y; + + new_mx = ioport("MOUSEX")->read(); + new_my = ioport("MOUSEY")->read(); + + // compute x delta + delta_x = new_mx - m_last_mx; + + // check for wrap + if (delta_x > 0x80) + delta_x = -0x100+delta_x; + if (delta_x < -0x80) + delta_x = 0x100+delta_x; + + // Prevent unplausible values at startup. + if (delta_x > 100 || delta_x<-100) delta_x = 0; + + m_last_mx = new_mx; + + // compute y delta + delta_y = new_my - m_last_my; + + // check for wrap + if (delta_y > 0x80) + delta_y = -0x100+delta_y; + if (delta_y < -0x80) + delta_y = 0x100+delta_y; + + if (delta_y > 100 || delta_y<-100) delta_y = 0; + + m_last_my = new_my; + + // update state + m_x += delta_x; + m_y += delta_y; +} + +void mecmouse_device::device_start(void) +{ + m_poll_timer = timer_alloc(POLL_TIMER); + // The poll time cannot depend on the console settings, since the TI-99/4A + // has no clock line on the joystick port. The rate is not mentioned in + // the specs; however, if it is too low, the mouse pointer will do jumps + m_poll_timer->adjust(attotime::from_hz(100), 0, attotime::from_hz(100)); +} + +void mecmouse_device::device_reset(void) +{ + m_poll_timer->enable(true); + m_last_select = 0; + m_read_y_axis = false; + m_x = 0; + m_y = 0; + m_last_mx = 0; + m_last_my = 0; +} + +INPUT_PORTS_START( mecmouse ) + /* 3 ports for mouse */ + PORT_START("MOUSEX") /* Mouse - X AXIS */ + PORT_BIT( 0xff, 0x00, IPT_TRACKBALL_X) PORT_SENSITIVITY(100) PORT_KEYDELTA(0) PORT_PLAYER(1) + + PORT_START("MOUSEY") /* Mouse - Y AXIS */ + PORT_BIT( 0xff, 0x00, IPT_TRACKBALL_Y) PORT_SENSITIVITY(100) PORT_KEYDELTA(0) PORT_PLAYER(1) + + PORT_START("MOUSE0") /* Mouse - buttons */ + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_BUTTON1) PORT_NAME("Mouse Button 1") PORT_PLAYER(1) + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_BUTTON2) PORT_NAME("Mouse Button 2") PORT_PLAYER(1) +INPUT_PORTS_END + +ioport_constructor mecmouse_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( mecmouse ); +} + +const device_type MECMOUSE = &device_creator; diff --git a/src/devices/bus/ti99x/mecmouse.h b/src/devices/bus/ti99x/mecmouse.h new file mode 100644 index 00000000000..8a915b681ab --- /dev/null +++ b/src/devices/bus/ti99x/mecmouse.h @@ -0,0 +1,48 @@ +// license:LGPL-2.1+ +// copyright-holders:Michael Zapf +/**************************************************************************** + + TI-99 Mechatronic mouse with adapter + See mecmouse.c for documentation + + Michael Zapf + October 2010 + January 2012: rewritten as class + +*****************************************************************************/ + +#ifndef __MECMOUSE__ +#define __MECMOUSE__ + +#include "emu.h" +#include "joyport.h" + +extern const device_type MECMOUSE; + +class mecmouse_device : public joyport_attached_device +{ +public: + mecmouse_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + UINT8 read_dev(); + void write_dev(UINT8 data); + +protected: + virtual void device_start(void); + virtual void device_reset(void); + virtual ioport_constructor device_input_ports() const; + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + +private: + int m_last_select; + bool m_read_y_axis; + int m_x; + int m_y; + int m_x_buf; + int m_y_buf; + int m_last_mx; + int m_last_my; + + emu_timer *m_poll_timer; +}; +#endif diff --git a/src/devices/bus/ti99x/ti99defs.h b/src/devices/bus/ti99x/ti99defs.h new file mode 100644 index 00000000000..543b5ad04ba --- /dev/null +++ b/src/devices/bus/ti99x/ti99defs.h @@ -0,0 +1,116 @@ +// license:LGPL-2.1+ +// copyright-holders:Michael Zapf +/**************************************************************************** + + Common definitions for TI family + Should be included in each component. + + Michael Zapf + +*****************************************************************************/ + +#ifndef __TI99DEFS__ +#define __TI99DEFS__ + +// TI-99/4(A) +#define region_grom "cons_grom" +#define region_grom_cart "cart_grom" +#define TMS9901_TAG "tms9901" +#define TIBOARD_TAG "ti_board" +#define DATAMUX_TAG "datamux_16_8" +#define VIDEO_SYSTEM_TAG "video" +#define SCREEN_TAG "screen" +#define TISOUNDCHIP_TAG "soundchip" +#define TISOUND_TAG "tisound" +#define GROMPORT_TAG "gromport" +#define GROM0_TAG "console_grom_0" +#define GROM1_TAG "console_grom_1" +#define GROM2_TAG "console_grom_2" +#define PERIBOX_TAG "peb" +#define MECMOUSE_TAG "mecmouse" +#define HANDSET_TAG "handset" +#define JOYPORT_TAG "joyport" +#define VDP_TAG "vdp" +#define DSRROM "dsrrom" + +#define VDPFREQ XTAL_10_738635MHz +#define GROMFREQ VDPFREQ/24 + +// TI-99/8 +#define SRAM_TAG "sram8" +#define DRAM_TAG "dram8" +#define MAPPER_TAG "mapper" +#define MAINBOARD8_TAG "mainboard8" +#define SPEECH_TAG "speech" +#define ROM0_TAG "rom0" +#define ROM1_TAG "rom1" +#define PCODEROM_TAG "pcode" + +// Geneve +#define GKEYBOARD_TAG "gkeyboard" +#define GMAPPER_TAG "gmapper" +#define GMOUSE_TAG "gmouse" +#define GCLOCK_TAG "mm58274c" +#define PFM512_TAG "pfm512" +#define PFM512A_TAG "pfm512a" + +#define READ16Z_MEMBER(name) void name(ATTR_UNUSED address_space &space, ATTR_UNUSED offs_t offset, ATTR_UNUSED UINT16 *value, ATTR_UNUSED UINT16 mem_mask) +#define DECLARE_READ16Z_MEMBER(name) void name(ATTR_UNUSED address_space &space, ATTR_UNUSED offs_t offset, ATTR_UNUSED UINT16 *value, ATTR_UNUSED UINT16 mem_mask = 0xffff) +#define READ8Z_MEMBER(name) void name(ATTR_UNUSED address_space &space, ATTR_UNUSED offs_t offset, ATTR_UNUSED UINT8 *value, ATTR_UNUSED UINT8 mem_mask) +#define DECLARE_READ8Z_MEMBER(name) void name(ATTR_UNUSED address_space &space, ATTR_UNUSED offs_t offset, ATTR_UNUSED UINT8 *value, ATTR_UNUSED UINT8 mem_mask = 0xff) + +/* + For almost all applications of setoffset, we also need the data bus + direction. This line is called DBIN on the TI CPUs, but as we do not assume + that this is a general rule, we use new macros here which contain the + DBIN setting. +*/ +#define SETADDRESS_DBIN_MEMBER(name) void name(ATTR_UNUSED address_space &space, ATTR_UNUSED offs_t offset, ATTR_UNUSED int state) +#define DECLARE_SETADDRESS_DBIN_MEMBER(name) void name(ATTR_UNUSED address_space &space, ATTR_UNUSED offs_t offset, ATTR_UNUSED int state) + +#define GENMOD 0x01 + +/* + Base class for all devices that have a special read method. This read + methods differs from the standard READ8/16 by allowing for a "high-impedance" + state "Z" which means that the bus lines are not changed. That way, we can + built busses with parallel devices as in the real machine, and only the + active device changes the bus lines. +*/ +class bus8z_device : public device_t +{ +public: + bus8z_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source) { } + virtual DECLARE_READ8Z_MEMBER(readz) =0; + virtual DECLARE_WRITE8_MEMBER(write) =0; + virtual DECLARE_SETADDRESS_DBIN_MEMBER( setaddress_dbin ) { }; +}; + +class bus16z_device : device_t +{ +public: + virtual DECLARE_READ16Z_MEMBER(read16z) =0; + virtual DECLARE_WRITE16_MEMBER(write16) =0; + virtual DECLARE_SETADDRESS_DBIN_MEMBER( setaddress_dbin ) { }; +}; + +/**************************************************************************** + Constants +****************************************************************************/ + +enum +{ + GM_TURBO = 1, + GM_TIM = 2 +}; + +enum +{ + GENEVE_098 = 0, + GENEVE_100, + GENEVE_PFM512, + GENEVE_PFM512A +}; + +#endif diff --git a/src/devices/bus/ti99x/videowrp.c b/src/devices/bus/ti99x/videowrp.c new file mode 100644 index 00000000000..d42349947f8 --- /dev/null +++ b/src/devices/bus/ti99x/videowrp.c @@ -0,0 +1,258 @@ +// license:LGPL-2.1+ +// copyright-holders:Michael Zapf +/**************************************************************************** + + TI-99/4(A) and /8 Video subsystem + This device actually wraps the naked video chip implementation + + EVPC (Enhanced Video Processor Card) from SNUG + based on v9938 (may also be equipped with v9958) + Can be used with TI-99/4A as an add-on card; internal VDP must be removed + + The SGCPU ("TI-99/4P") only runs with EVPC + + We also include a class wrapper for the sound chip here. + + Michael Zapf + + October 2010 + February 2012: Rewritten as class + +*****************************************************************************/ + +#include "emu.h" +#include "videowrp.h" +#include "sound/sn76496.h" + +/* + Constructors +*/ +ti_video_device::ti_video_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) +: bus8z_device(mconfig, type, name, tag, owner, clock, shortname, source) +{ +} + +ti_std_video_device::ti_std_video_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : ti_video_device(mconfig, TI99VIDEO, "TI99 STD Video subsystem", tag, owner, clock, "ti99_video", __FILE__) +{ +} + +ti_exp_video_device::ti_exp_video_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : ti_video_device(mconfig, V9938VIDEO, "TI99 EXP Video subsystem", tag, owner, clock, "v9938_video", __FILE__) +{ +} + +ti_sound_sn94624_device::ti_sound_sn94624_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : ti_sound_system_device(mconfig, TISOUND_94624, "Onboard sound (SN94624)", tag, owner, clock, "ti_sound_sn94624", __FILE__) +{ +} + +ti_sound_sn76496_device::ti_sound_sn76496_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : ti_sound_system_device(mconfig, TISOUND_76496, "Onboard sound (SN76496)", tag, owner, clock, "ti_sound_sn76496", __FILE__) +{ +} + +/*****************************************************************************/ +/* + Memory access (TI-99/4A and TI-99/8) +*/ +READ8Z_MEMBER( ti_std_video_device::readz ) +{ + if (space.debugger_access()) return; + + if (offset & 2) + { /* read VDP status */ + *value = m_tms9928a->register_read(space, 0); + } + else + { /* read VDP RAM */ + *value = m_tms9928a->vram_read(space, 0); + } +} + +WRITE8_MEMBER( ti_std_video_device::write ) +{ + if (space.debugger_access()) return; + + if (offset & 2) + { /* write VDP address */ + m_tms9928a->register_write(space, 0, data); + } + else + { /* write VDP data */ + m_tms9928a->vram_write(space, 0, data); + } +} + +/*****************************************************************************/ + +/* + Memory access (EVPC) via 16 bit bus +*/ +READ16_MEMBER( ti_exp_video_device::read16 ) +{ + if (space.debugger_access()) return 0; + + if (offset & 1) + { /* read VDP status */ + return ((int) m_v9938->status_r()) << 8; + } + else + { /* read VDP RAM */ + return ((int) m_v9938->vram_r()) << 8; + } +} + +WRITE16_MEMBER( ti_exp_video_device::write16 ) +{ + if (space.debugger_access()) return; + + switch (offset & 3) + { + case 0: + /* write VDP data */ + m_v9938->vram_w((data >> 8) & 0xff); + break; + case 1: + /* write VDP address */ + m_v9938->command_w((data >> 8) & 0xff); + break; + case 2: + /* write VDP palette */ + m_v9938->palette_w((data >> 8) & 0xff); + break; + case 3: + /* write VDP register pointer (indirect access) */ + m_v9938->register_w((data >> 8) & 0xff); + break; + } +} + +/******************************************************************************/ + +/* + Video read (Geneve) via 8 bit bus +*/ +READ8Z_MEMBER( ti_exp_video_device::readz ) +{ + if (space.debugger_access()) return; + + if (offset & 2) + { /* read VDP status */ + *value = m_v9938->status_r(); + } + else + { /* read VDP RAM */ + *value = m_v9938->vram_r(); + } +} + +/* + Video write (Geneve) +*/ +WRITE8_MEMBER( ti_exp_video_device::write ) +{ + if (space.debugger_access()) return; + + switch (offset & 6) + { + case 0: + /* write VDP data */ + m_v9938->vram_w(data); + break; + case 2: + /* write VDP address */ + m_v9938->command_w(data); + break; + case 4: + /* write VDP palette */ + m_v9938->palette_w(data); + break; + case 6: + /* write VDP register pointer (indirect access) */ + m_v9938->register_w(data); + break; + } +} + +/**************************************************************************/ +// Interfacing to mouse attached to v9938 + +void ti_exp_video_device::video_update_mouse(int delta_x, int delta_y, int buttons) +{ + m_v9938->update_mouse_state(delta_x, delta_y, buttons & 3); +} + +/**************************************************************************/ + +void ti_video_device::device_start(void) +{ + m_tms9928a = static_cast(machine().device(VDP_TAG)); +} + +void ti_exp_video_device::device_start(void) +{ + m_v9938 = static_cast(machine().device(VDP_TAG)); +} + +void ti_video_device::device_reset(void) +{ +} + +/**************************************************************************/ + +/* + Sound subsystem. + TODO: Seriously consider to simplify this by connecting to the datamux + directly. We don't do anything reasonable here. +*/ + +WRITE8_MEMBER( ti_sound_system_device::write ) +{ + if (space.debugger_access()) return; + m_sound_chip->write(space, 0, data); +} + +void ti_sound_system_device::device_start(void) +{ + m_console_ready.resolve(); + m_sound_chip = subdevice(TISOUNDCHIP_TAG); +} + +WRITE_LINE_MEMBER( ti_sound_system_device::sound_ready ) +{ + m_console_ready(state); +} + +MACHINE_CONFIG_FRAGMENT( sn94624 ) + MCFG_SPEAKER_STANDARD_MONO("sound_out") + + MCFG_SOUND_ADD(TISOUNDCHIP_TAG, SN94624, 3579545/8) /* 3.579545 MHz */ + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "sound_out", 0.75) + MCFG_SN76496_READY_HANDLER(WRITELINE(ti_sound_system_device, sound_ready)) +MACHINE_CONFIG_END + +MACHINE_CONFIG_FRAGMENT( sn76496 ) + MCFG_SPEAKER_STANDARD_MONO("sound_out") + + MCFG_SOUND_ADD(TISOUNDCHIP_TAG, SN76496, 3579545) /* 3.579545 MHz */ + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "sound_out", 0.75) + MCFG_SN76496_READY_HANDLER(WRITELINE(ti_sound_system_device, sound_ready)) +MACHINE_CONFIG_END + +machine_config_constructor ti_sound_sn94624_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( sn94624 ); +} + +machine_config_constructor ti_sound_sn76496_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( sn76496 ); +} + +/**************************************************************************/ + +const device_type TI99VIDEO = &device_creator; +const device_type V9938VIDEO = &device_creator; +const device_type TISOUND_94624 = &device_creator; +const device_type TISOUND_76496 = &device_creator; diff --git a/src/devices/bus/ti99x/videowrp.h b/src/devices/bus/ti99x/videowrp.h new file mode 100644 index 00000000000..c38a8e7f152 --- /dev/null +++ b/src/devices/bus/ti99x/videowrp.h @@ -0,0 +1,187 @@ +// license:LGPL-2.1+ +// copyright-holders:Michael Zapf +/**************************************************************************** + + TI-99/4(A) and /8 Video subsystem + See videowrp.c for documentation + + Michael Zapf + October 2010 + January 2012: Rewritten as class + +*****************************************************************************/ + +#ifndef __TIVIDEO__ +#define __TIVIDEO__ + +#include "video/tms9928a.h" +#include "video/v9938.h" +#include "ti99defs.h" +#include "sound/sn76496.h" + +class ti_video_device : public bus8z_device +{ +public: + virtual void reset_vdp(int state) =0; + +protected: + tms9928a_device *m_tms9928a; + + /* Constructor */ + ti_video_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + virtual void device_start(void); + virtual void device_reset(void); + virtual DECLARE_READ8Z_MEMBER(readz) { }; + virtual DECLARE_WRITE8_MEMBER(write) { }; +}; + +/* + Used in the TI-99/4A and TI-99/8 +*/ +class ti_std_video_device : public ti_video_device +{ +public: + ti_std_video_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + DECLARE_READ8Z_MEMBER(readz); + DECLARE_WRITE8_MEMBER(write); + + void reset_vdp(int state) { m_tms9928a->reset_line(state); } +}; + +/* + Used in the EVPC and Geneve +*/ +class ti_exp_video_device : public ti_video_device +{ +public: + ti_exp_video_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + void video_update_mouse(int delta_x, int delta_y, int buttons); + DECLARE_READ8Z_MEMBER(readz); + DECLARE_WRITE8_MEMBER(write); + DECLARE_READ16_MEMBER(read16); + DECLARE_WRITE16_MEMBER(write16); + void reset_vdp(int state) { m_v9938->reset_line(state); } + +protected: + virtual void device_start(void); + v9938_device *m_v9938; +}; + +extern const device_type TI99VIDEO; +extern const device_type V9938VIDEO; + +/****************************************************************************/ +/* + Sound device +*/ + +extern const device_type TISOUND_94624; +extern const device_type TISOUND_76496; + +#define TI_SOUND_CONFIG(name) \ + const ti_sound_config(name) = + +class ti_sound_system_device : public bus8z_device +{ +public: + ti_sound_system_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : bus8z_device(mconfig, type, name, tag, owner, clock, shortname, source), + m_console_ready(*this) { }; + + // Cannot read from sound; just ignore silently + DECLARE_READ8Z_MEMBER(readz) { }; + DECLARE_WRITE8_MEMBER(write); + DECLARE_WRITE_LINE_MEMBER( sound_ready ); // connect to console READY + + template static devcb_base &static_set_int_callback(device_t &device, _Object object) { return downcast(device).m_console_ready.set_callback(object); } + +protected: + virtual void device_start(void); + virtual machine_config_constructor device_mconfig_additions() const =0; + +private: + sn76496_base_device* m_sound_chip; + devcb_write_line m_console_ready; +}; + +/* + The version that sits in the TI-99/4A +*/ +class ti_sound_sn94624_device : public ti_sound_system_device +{ +public: + ti_sound_sn94624_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual machine_config_constructor device_mconfig_additions() const; +}; + +/* + The version that sits in the TI-99/8 and Geneve +*/ +class ti_sound_sn76496_device : public ti_sound_system_device +{ +public: + ti_sound_sn76496_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual machine_config_constructor device_mconfig_additions() const; +}; + + +/****************************************************************************/ + +#define MCFG_TI_TMS991x_ADD_NTSC(_tag, _chip, _vsize, _class, _int) \ + MCFG_DEVICE_ADD(_tag, TI99VIDEO, 0) \ + MCFG_DEVICE_ADD( VDP_TAG, _chip, XTAL_10_738635MHz / 2 ) \ + MCFG_TMS9928A_VRAM_SIZE(_vsize) \ + MCFG_TMS9928A_OUT_INT_LINE_CB(WRITELINE(_class,_int)) \ + MCFG_TMS9928A_SCREEN_ADD_NTSC( SCREEN_TAG ) \ + MCFG_SCREEN_UPDATE_DEVICE( VDP_TAG, tms9928a_device, screen_update ) + +#define MCFG_TI_TMS991x_ADD_PAL(_tag, _chip, _vsize, _class, _int) \ + MCFG_DEVICE_ADD(_tag, TI99VIDEO, 0) \ + MCFG_DEVICE_ADD( VDP_TAG, _chip, XTAL_10_738635MHz / 2 ) \ + MCFG_TMS9928A_VRAM_SIZE(_vsize) \ + MCFG_TMS9928A_OUT_INT_LINE_CB(WRITELINE(_class,_int)) \ + MCFG_TMS9928A_SCREEN_ADD_PAL( SCREEN_TAG ) \ + MCFG_SCREEN_UPDATE_DEVICE( VDP_TAG, tms9928a_device, screen_update ) + +#define MCFG_TI998_ADD_NTSC(_tag, _chip, _vsize, _class, _int) \ + MCFG_DEVICE_ADD(_tag, TI99VIDEO, 0) \ + MCFG_DEVICE_ADD( VDP_TAG, _chip, XTAL_10_738635MHz / 2 ) \ + MCFG_TMS9928A_VRAM_SIZE(_vsize) \ + MCFG_TMS9928A_OUT_INT_LINE_CB(WRITELINE(_class,_int)) \ + MCFG_TMS9928A_SCREEN_ADD_NTSC( SCREEN_TAG ) \ + MCFG_SCREEN_UPDATE_DEVICE( VDP_TAG, tms9928a_device, screen_update ) + +#define MCFG_TI998_ADD_PAL(_tag, _chip, _vsize, _class, _int) \ + MCFG_DEVICE_ADD(_tag, TI99VIDEO, 0) \ + MCFG_DEVICE_ADD( VDP_TAG, _chip, XTAL_10_738635MHz / 2 ) \ + MCFG_TMS9928A_VRAM_SIZE(_vsize) \ + MCFG_TMS9928A_OUT_INT_LINE_CB(WRITELINE(_class,_int)) \ + MCFG_TMS9928A_SCREEN_ADD_PAL( SCREEN_TAG ) \ + MCFG_SCREEN_UPDATE_DEVICE( VDP_TAG, tms9928a_device, screen_update ) + +#define MCFG_TI_V9938_ADD(_tag, _rate, _screen, _blank, _x, _y, _class, _int) \ + MCFG_DEVICE_ADD(_tag, V9938VIDEO, 0) \ + MCFG_V9938_ADD(VDP_TAG, _screen, 0x20000, XTAL_21_4772MHz) /* typical 9938 clock, not verified */ \ + MCFG_V99X8_INTERRUPT_CALLBACK(WRITELINE(_class, _int)) \ + MCFG_SCREEN_ADD(_screen, RASTER) \ + MCFG_SCREEN_REFRESH_RATE(_rate) \ + MCFG_SCREEN_UPDATE_DEVICE(VDP_TAG, v9938_device, screen_update) \ + MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(_blank)) \ + MCFG_SCREEN_SIZE(_x, _y) \ + MCFG_SCREEN_VISIBLE_AREA(0, _x - 1, 0, _y - 1) \ + MCFG_SCREEN_PALETTE(VDP_TAG ":palette") + +#define MCFG_TI_SOUND_94624_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, TISOUND_94624, 0) + +#define MCFG_TI_SOUND_76496_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, TISOUND_76496, 0) + +#define MCFG_TI_SOUND_READY_HANDLER( _ready ) \ + devcb = &ti_sound_system_device::static_set_int_callback( *device, DEVCB_##_ready ); + +#endif /* __TIVIDEO__ */ diff --git a/src/devices/bus/tvc/hbf.c b/src/devices/bus/tvc/hbf.c new file mode 100644 index 00000000000..760226a2cfb --- /dev/null +++ b/src/devices/bus/tvc/hbf.c @@ -0,0 +1,178 @@ +// license:BSD-3-Clause +// copyright-holders:Sandro Ronco +/*************************************************************************** + + hbf.c + +***************************************************************************/ + +#include "emu.h" +#include "hbf.h" + + +/*************************************************************************** + IMPLEMENTATION +***************************************************************************/ + +FLOPPY_FORMATS_MEMBER( tvc_hbf_device::floppy_formats ) + FLOPPY_TVC_FORMAT +FLOPPY_FORMATS_END + +static SLOT_INTERFACE_START( tvc_hbf_floppies ) + SLOT_INTERFACE( "525qd", FLOPPY_525_QD ) +SLOT_INTERFACE_END + +static MACHINE_CONFIG_FRAGMENT(tvc_hbf) + MCFG_FD1793_ADD("fdc", XTAL_16MHz / 16) + MCFG_FLOPPY_DRIVE_ADD("fdc:0", tvc_hbf_floppies, "525qd", tvc_hbf_device::floppy_formats) + MCFG_FLOPPY_DRIVE_ADD("fdc:1", tvc_hbf_floppies, "525qd", tvc_hbf_device::floppy_formats) +MACHINE_CONFIG_END + +ROM_START( tvc_hbf ) + ROM_REGION(0x4000, "hbf", 0) + ROM_DEFAULT_BIOS("basic") + ROM_SYSTEM_BIOS( 0, "basic", "BASIC" ) + ROMX_LOAD("hbf.rom", 0x0000, 0x4000, CRC(ae34982b) SHA1(96c4154c04086c537ae1272fe051a256d2f5be3f), ROM_BIOS(1)) + ROM_SYSTEM_BIOS( 1, "upm", "UPM" ) + ROMX_LOAD("d_tvcupm.128", 0x0000, 0x4000, CRC(b3a567ad) SHA1(f92df6074b07f5f19e8c96ff1315da0cfeec9f74), ROM_BIOS(2)) + ROM_SYSTEM_BIOS( 2, "vtdos11", "VT-DOS v1.1" ) + ROMX_LOAD("d_tvcdos.128", 0x0000, 0x4000, CRC(2acf8477) SHA1(07bf39b633a564f98dd4b2e93bd889501b341550), ROM_BIOS(3)) + ROM_SYSTEM_BIOS( 3, "vtdos12", "VT-DOS v1.2" ) + ROMX_LOAD("d_dos12.128", 0x0000, 0x4000, CRC(f5c35597) SHA1(2fa44ad089a51f453b580e0b13e3be96a0f14649), ROM_BIOS(4)) + + ROM_REGION(0x1000, "ram", ROMREGION_ERASE) +ROM_END + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type TVC_HBF = &device_creator; + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// tvc_hbf_device - constructor +//------------------------------------------------- + +tvc_hbf_device::tvc_hbf_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, TVC_HBF, "HBF floppy interface", tag, owner, clock, "tvc_hbf", __FILE__), + device_tvcexp_interface( mconfig, *this ), + m_fdc(*this, "fdc") +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void tvc_hbf_device::device_start() +{ + m_rom = memregion("hbf")->base(); + m_ram = memregion("ram")->base(); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void tvc_hbf_device::device_reset() +{ + m_rom_bank = 0; +} + +//------------------------------------------------- +// device_mconfig_additions +//------------------------------------------------- + +machine_config_constructor tvc_hbf_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( tvc_hbf ); +} + +//------------------------------------------------- +// device_rom_region +//------------------------------------------------- + +const rom_entry *tvc_hbf_device::device_rom_region() const +{ + return ROM_NAME( tvc_hbf ); +} + +/*------------------------------------------------- + read +-------------------------------------------------*/ +READ8_MEMBER(tvc_hbf_device::read) +{ + if (offset>=0x1000) + return m_ram[offset& 0x0fff]; + else + return m_rom[(m_rom_bank<<12) + (offset & 0x0fff)]; +} + +//------------------------------------------------- +// write +//------------------------------------------------- + +WRITE8_MEMBER(tvc_hbf_device::write) +{ + if (offset>=0x1000) + m_ram[offset & 0x0fff] = data; + else + logerror("'%s': unmapped write to %04x %02x\n", tag(), offset, data); +} + + +//------------------------------------------------- +// IO read +//------------------------------------------------- + +READ8_MEMBER(tvc_hbf_device::io_read) +{ + switch((offset>>2) & 0x03) + { + case 0x00: + return m_fdc->read(space, offset & 3); + case 0x01: + return (m_fdc->drq_r()<<7) | (m_fdc->intrq_r() ? 0x01 : 0x00); + default: + return 0x00; + } +} + +//------------------------------------------------- +// IO write +//------------------------------------------------- + +WRITE8_MEMBER(tvc_hbf_device::io_write) +{ + switch((offset>>2) & 0x03) + { + case 0x00: + m_fdc->write(space, offset & 3, data); + break; + case 0x01: + { + // bit 0-3 drive select + // bit 5 DDEN + // bit 6 floppy motor + // bit 7 side select + floppy_image_device *floppy = NULL; + + if (BIT(data, 0)) floppy = subdevice("fdc:0")->get_device(); + if (BIT(data, 1)) floppy = subdevice("fdc:1")->get_device(); + m_fdc->set_floppy(floppy); + m_fdc->dden_w(BIT(data, 5)); + if (floppy) floppy->mon_w(!BIT(data, 6)); + if (floppy) floppy->ss_w(BIT(data, 7)); + break; + } + case 0x02: + m_rom_bank = (data>>4) & 0x03; + break; + } +} diff --git a/src/devices/bus/tvc/hbf.h b/src/devices/bus/tvc/hbf.h new file mode 100644 index 00000000000..6a321ae5599 --- /dev/null +++ b/src/devices/bus/tvc/hbf.h @@ -0,0 +1,59 @@ +// license:BSD-3-Clause +// copyright-holders:Sandro Ronco +#pragma once + +#ifndef __TVC_HBF_H__ +#define __TVC_HBF_H__ + +#include "emu.h" +#include "tvc.h" +#include "machine/wd_fdc.h" +#include "formats/tvc_dsk.h" + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> tvc_hbf_device + +class tvc_hbf_device : + public device_t, + public device_tvcexp_interface +{ +public: + // construction/destruction + tvc_hbf_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual const rom_entry *device_rom_region() const; + + DECLARE_FLOPPY_FORMATS( floppy_formats ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // tvcexp_interface overrides + virtual UINT8 id_r() { return 0x02; } // ID_A to GND, ID_B to VCC + virtual DECLARE_READ8_MEMBER(read); + virtual DECLARE_WRITE8_MEMBER(write); + virtual DECLARE_READ8_MEMBER(io_read); + virtual DECLARE_WRITE8_MEMBER(io_write); + +private: + // internal state + required_device m_fdc; + + UINT8 * m_rom; + UINT8 * m_ram; + UINT8 m_rom_bank; // A12 and A13 +}; + + +// device type definition +extern const device_type TVC_HBF; + +#endif /* __TVC_HBF_H__ */ diff --git a/src/devices/bus/tvc/tvc.c b/src/devices/bus/tvc/tvc.c new file mode 100644 index 00000000000..54ea47c9149 --- /dev/null +++ b/src/devices/bus/tvc/tvc.c @@ -0,0 +1,167 @@ +// license:BSD-3-Clause +// copyright-holders:Sandro Ronco +/********************************************************************* + + tvc.c + +*********************************************************************/ + +#include "emu.h" +#include "tvc.h" +#include "emuopts.h" + + +/*************************************************************************** + PARAMETERS +***************************************************************************/ + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type TVCEXP_SLOT = &device_creator; + + +//************************************************************************** +// TVC Expansion Interface +//************************************************************************** + +//------------------------------------------------- +// device_tvcexp_interface - constructor +//------------------------------------------------- + +device_tvcexp_interface::device_tvcexp_interface(const machine_config &mconfig, device_t &device) + : device_slot_card_interface(mconfig, device) +{ +} + + +//------------------------------------------------- +// ~device_tvcexp_interface - destructor +//------------------------------------------------- + +device_tvcexp_interface::~device_tvcexp_interface() +{ +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// tvcexp_slot_device - constructor +//------------------------------------------------- +tvcexp_slot_device::tvcexp_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, TVCEXP_SLOT, "TVC64 Expansion Slot", tag, owner, clock, "tvcexp_slot", __FILE__), + device_slot_interface(mconfig, *this), + m_out_irq_cb(*this), + m_out_nmi_cb(*this) +{ +} + +//------------------------------------------------- +// tvcexp_slot_device - destructor +//------------------------------------------------- + +tvcexp_slot_device::~tvcexp_slot_device() +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void tvcexp_slot_device::device_start() +{ + m_cart = dynamic_cast(get_card_device()); + + // resolve callbacks + m_out_irq_cb.resolve_safe(); + m_out_nmi_cb.resolve_safe(); +} + +/*------------------------------------------------- + module id read +-------------------------------------------------*/ + +UINT8 tvcexp_slot_device::id_r() +{ + UINT8 result = 0x00; + + if (m_cart) + result = m_cart->id_r() & 0x03; + + return result; +} + +/*------------------------------------------------- + module interrupt ack +-------------------------------------------------*/ + +void tvcexp_slot_device::int_ack() +{ + if (m_cart) + m_cart->int_ack(); +} + +/*------------------------------------------------- + module int read +-------------------------------------------------*/ + +UINT8 tvcexp_slot_device::int_r() +{ + UINT8 result = 1; + + if (m_cart) + result = m_cart->int_r() & 0x01; + + return result; +} + + +/*------------------------------------------------- + read +-------------------------------------------------*/ + +READ8_MEMBER(tvcexp_slot_device::read) +{ + if (m_cart) + return m_cart->read(space, offset); + else + return 0x00; +} + + +/*------------------------------------------------- + write +-------------------------------------------------*/ + +WRITE8_MEMBER(tvcexp_slot_device::write) +{ + if (m_cart) + m_cart->write(space, offset, data); +} + +/*------------------------------------------------- + IO read +-------------------------------------------------*/ + +READ8_MEMBER(tvcexp_slot_device::io_read) +{ + if (m_cart) + return m_cart->io_read(space, offset); + else + return 0x00; +} + + +/*------------------------------------------------- + IO write +-------------------------------------------------*/ + +WRITE8_MEMBER(tvcexp_slot_device::io_write) +{ + if (m_cart) + m_cart->io_write(space, offset, data); +} diff --git a/src/devices/bus/tvc/tvc.h b/src/devices/bus/tvc/tvc.h new file mode 100644 index 00000000000..181806f8195 --- /dev/null +++ b/src/devices/bus/tvc/tvc.h @@ -0,0 +1,128 @@ +// license:BSD-3-Clause +// copyright-holders:Sandro Ronco +/********************************************************************* + + tvc.h + +********************************************************************** + + +----------+ + GND | A01 B01 | GND + +5V | A02 B02 | +5V + +12V | A03 B03 | +12V + -12V | A04 B04 | -12V + N.C. | A05 B05 | N.C. + N.C. | A06 B06 | /HSYNC + 3.125 CLK | A07 B07 | /VSYNC + DMA | A08 B08 | BORDER + LPEN | A09 B09 | N.C. + DEB | A10 B10 | MUX + 6.25 CLK | A11 B11 | A3 + A1 | A12 B12 | EC3 + EC0 | A13 B13 | EC1 + /EXTC | A14 B14 | EC2 + /PHANTOM | A15 B15 | TXRXCLK + N.C. | A16 B16 | SOUND + BD0 | A17 B17 | N.C. + BD1 | A18 B18 | N.C. + BD2 | A19 B19 | N.C. + BD3 | A20 B20 | N.C. + BD4 | A21 B21 | N.C. + BD5 | A22 B22 | N.C. + BD6 | A23 B23 | N.C. + BD7 | A24 B24 | A15 + A17 | A25 B25 | A5 + A8 | A26 B26 | A12 + A7 | A27 B27 | A6 + A9 | A28 B28 | A11 + A4 | A29 B29 | A10 + A13 | A30 B30 | A2 + /VIDLSB | A31 B31 | A0 + /EXP | A32 B32 | P3 + N.C. | A33 B33 | /BUSRQ + /P2 | A34 B34 | N.C. + /CLRINT | A35 B35 | RESET + IDA | A36 B36 | /NMI + /INT | A37 B37 | /WAIT + IDB | A38 B38 | /INT + /EXP | A39 B39 | N.C. + /BM | A40 B40 | /BIORQ + /BRESET | A41 B41 | /B0 + /BWR | A42 B42 | /BMREQ + /WRD | A43 B43 | /BRFSH + +----------+ +*********************************************************************/ + +#ifndef __TVCEXP_H__ +#define __TVCEXP_H__ + + +/*************************************************************************** + TYPE DEFINITIONS +***************************************************************************/ + +// ======================> device_tvcexp_interface + +class device_tvcexp_interface : public device_slot_card_interface +{ +public: + // construction/destruction + device_tvcexp_interface(const machine_config &mconfig, device_t &device); + virtual ~device_tvcexp_interface(); + + // reading and writing + virtual UINT8 id_r() { return 0x00; } // ID_A and ID_B lines + virtual void int_ack() { } + virtual UINT8 int_r() { return 1; } + virtual DECLARE_READ8_MEMBER(read) { return 0x00; } + virtual DECLARE_WRITE8_MEMBER(write) {} + virtual DECLARE_READ8_MEMBER(io_read) { return 0x00; } + virtual DECLARE_WRITE8_MEMBER(io_write) {} +}; + +// ======================> tvcexp_slot_device + +class tvcexp_slot_device : public device_t, + public device_slot_interface +{ +public: + // construction/destruction + tvcexp_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual ~tvcexp_slot_device(); + + template static devcb_base &set_out_irq_callback(device_t &device, _Object object) { return downcast(device).m_out_irq_cb.set_callback(object); } + template static devcb_base &set_out_nmi_callback(device_t &device, _Object object) { return downcast(device).m_out_nmi_cb.set_callback(object); } + + // device-level overrides + virtual void device_start(); + + // reading and writing + virtual UINT8 id_r(); + virtual void int_ack(); + virtual UINT8 int_r(); + virtual DECLARE_READ8_MEMBER(read); + virtual DECLARE_WRITE8_MEMBER(write); + virtual DECLARE_READ8_MEMBER(io_read); + virtual DECLARE_WRITE8_MEMBER(io_write); + + devcb_write_line m_out_irq_cb; + devcb_write_line m_out_nmi_cb; + + device_tvcexp_interface* m_cart; +}; + +// device type definition +extern const device_type TVCEXP_SLOT; + + +/*************************************************************************** + DEVICE CONFIGURATION MACROS +***************************************************************************/ + +#define MCFG_TVCEXP_SLOT_OUT_IRQ_CB(_devcb) \ + devcb = &tvcexp_slot_device::set_out_irq_callback(*device, DEVCB_##_devcb); + +#define MCFG_TVCEXP_SLOT_OUT_NMI_CB(_devcb) \ + devcb = &tvcexp_slot_device::set_out_nmi_callback(*device, DEVCB_##_devcb); + +#endif /* __TVCEXP_H__ */ diff --git a/src/devices/bus/vboy/rom.c b/src/devices/bus/vboy/rom.c new file mode 100644 index 00000000000..587be158610 --- /dev/null +++ b/src/devices/bus/vboy/rom.c @@ -0,0 +1,61 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + Nintendo Virtual Boy cart emulation + + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "rom.h" + + +//------------------------------------------------- +// vboy_rom_device - constructor +//------------------------------------------------- + +const device_type VBOY_ROM_STD = &device_creator; +const device_type VBOY_ROM_EEPROM = &device_creator; + + +vboy_rom_device::vboy_rom_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_vboy_cart_interface( mconfig, *this ) +{ +} + +vboy_rom_device::vboy_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, VBOY_ROM_STD, "Nintendo Virtual Boy Carts", tag, owner, clock, "vboy_rom", __FILE__), + device_vboy_cart_interface( mconfig, *this ) +{ +} + +vboy_eeprom_device::vboy_eeprom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : vboy_rom_device(mconfig, VBOY_ROM_EEPROM, "Nintendo Virtual Boy Carts + EEPROM", tag, owner, clock, "vboy_eeprom", __FILE__) +{ +} + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +READ32_MEMBER(vboy_rom_device::read_cart) +{ + return m_rom[offset & m_rom_mask]; +} + + +READ32_MEMBER(vboy_eeprom_device::read_eeprom) +{ + return m_eeprom[offset]; +} + + +WRITE32_MEMBER(vboy_eeprom_device::write_eeprom) +{ + COMBINE_DATA(&m_eeprom[offset]); +} diff --git a/src/devices/bus/vboy/rom.h b/src/devices/bus/vboy/rom.h new file mode 100644 index 00000000000..0f26468892b --- /dev/null +++ b/src/devices/bus/vboy/rom.h @@ -0,0 +1,47 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __VBOY_ROM_H +#define __VBOY_ROM_H + +#include "slot.h" + + +// ======================> vboy_rom_device + +class vboy_rom_device : public device_t, + public device_vboy_cart_interface +{ +public: + // construction/destruction + vboy_rom_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + vboy_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start() {} + + // reading and writing + virtual DECLARE_READ32_MEMBER(read_cart); +}; + +// ======================> vboy_eeprom_device + +class vboy_eeprom_device : public vboy_rom_device +{ +public: + // construction/destruction + vboy_eeprom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // reading and writing + virtual DECLARE_READ32_MEMBER(read_eeprom); + virtual DECLARE_WRITE32_MEMBER(write_eeprom); +}; + + + +// device type definition +extern const device_type VBOY_ROM_STD; +extern const device_type VBOY_ROM_EEPROM; + + + +#endif diff --git a/src/devices/bus/vboy/slot.c b/src/devices/bus/vboy/slot.c new file mode 100644 index 00000000000..da00aeaca04 --- /dev/null +++ b/src/devices/bus/vboy/slot.c @@ -0,0 +1,273 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + Nintendo Virtual Boy cart emulation + (through slot devices) + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "slot.h" + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type VBOY_CART_SLOT = &device_creator; + +//************************************************************************** +// vboy cartridges Interface +//************************************************************************** + +//------------------------------------------------- +// device_vboy_cart_interface - constructor +//------------------------------------------------- + +device_vboy_cart_interface::device_vboy_cart_interface(const machine_config &mconfig, device_t &device) + : device_slot_card_interface(mconfig, device), + m_rom(NULL), + m_rom_size(0), + m_rom_mask(0) +{ +} + + +//------------------------------------------------- +// ~device_vboy_cart_interface - destructor +//------------------------------------------------- + +device_vboy_cart_interface::~device_vboy_cart_interface() +{ +} + +//------------------------------------------------- +// rom_alloc - alloc the space for the cart +//------------------------------------------------- + +void device_vboy_cart_interface::rom_alloc(UINT32 size, const char *tag) +{ + if (m_rom == NULL) + { + m_rom = (UINT32 *)device().machine().memory().region_alloc(std::string(tag).append(VBOYSLOT_ROM_REGION_TAG).c_str(), size, 4, ENDIANNESS_LITTLE)->base(); + m_rom_size = size/4; + m_rom_mask = m_rom_size - 1; + } +} + + +//------------------------------------------------- +// ram_alloc - alloc the space for the ram +//------------------------------------------------- + +void device_vboy_cart_interface::eeprom_alloc(UINT32 size) +{ + m_eeprom.resize(size/sizeof(UINT32)); +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// vboy_cart_slot_device - constructor +//------------------------------------------------- +vboy_cart_slot_device::vboy_cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, VBOY_CART_SLOT, "Nintendo Virtual Boy Cartridge Slot", tag, owner, clock, "vboy_cart_slot", __FILE__), + device_image_interface(mconfig, *this), + device_slot_interface(mconfig, *this), + m_type(VBOY_STD) +{ +} + + +//------------------------------------------------- +// vboy_cart_slot_device - destructor +//------------------------------------------------- + +vboy_cart_slot_device::~vboy_cart_slot_device() +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void vboy_cart_slot_device::device_start() +{ + m_cart = dynamic_cast(get_card_device()); +} + +//------------------------------------------------- +// device_config_complete - perform any +// operations now that the configuration is +// complete +//------------------------------------------------- + +void vboy_cart_slot_device::device_config_complete() +{ + // set brief and instance name + update_names(); +} + + +//------------------------------------------------- +// vboy PCB +//------------------------------------------------- + +struct vboy_slot +{ + int pcb_id; + const char *slot_option; +}; + +// Here, we take the feature attribute from .xml (i.e. the PCB name) and we assign a unique ID to it +static const vboy_slot slot_list[] = +{ + { VBOY_STD, "vb_rom" }, + { VBOY_EEPROM, "vb_eeprom" } +}; + +static int vboy_get_pcb_id(const char *slot) +{ + for (int i = 0; i < ARRAY_LENGTH(slot_list); i++) + { + if (!core_stricmp(slot_list[i].slot_option, slot)) + return slot_list[i].pcb_id; + } + + return 0; +} + +#if 0 +static const char *vboy_get_slot(int type) +{ + for (int i = 0; i < ARRAY_LENGTH(slot_list); i++) + { + if (slot_list[i].pcb_id == type) + return slot_list[i].slot_option; + } + + return "vb_rom"; +} +#endif + +/*------------------------------------------------- + call load + -------------------------------------------------*/ + +bool vboy_cart_slot_device::call_load() +{ + if (m_cart) + { + UINT8 *ROM; + UINT32 len = (software_entry() == NULL) ? length() : get_software_region_length("rom"); + bool has_eeprom = (software_entry() != NULL) && get_software_region("eeprom"); + + if (len > 0x200000) + { + seterror(IMAGE_ERROR_UNSPECIFIED, "Unsupported cartridge size"); + return IMAGE_INIT_FAIL; + } + + // always alloc 0x200000 so to be able to directly map the region + // to the address map (speeding up emulation a bit) + m_cart->rom_alloc(0x200000, tag()); + if (has_eeprom) + m_cart->eeprom_alloc(get_software_region_length("eeprom")); + + ROM = (UINT8 *)m_cart->get_rom_base(); + + if (software_entry() == NULL) + fread(ROM, len); + else + memcpy(ROM, get_software_region("rom"), len); + + if (len < 0x080000) { memcpy(ROM + 0x040000, ROM, 0x040000); } + if (len < 0x100000) { memcpy(ROM + 0x080000, ROM, 0x080000); } + if (len < 0x200000) { memcpy(ROM + 0x100000, ROM, 0x100000); } + + if (software_entry() == NULL) + m_type = vboy_get_pcb_id("vb_rom"); + else + { + const char *pcb_name = get_feature("slot"); + if (pcb_name) + m_type = vboy_get_pcb_id(pcb_name); + } + + //printf("Type: %s\n", vboy_get_slot(m_type)); + + return IMAGE_INIT_PASS; + } + + return IMAGE_INIT_PASS; +} + + +/*------------------------------------------------- + call_unload + -------------------------------------------------*/ + +void vboy_cart_slot_device::call_unload() +{ + if (m_cart && m_cart->get_eeprom_base() && m_cart->get_eeprom_size()) + battery_save(m_cart->get_eeprom_base(), m_cart->get_eeprom_size() * 4); +} + +/*------------------------------------------------- + call softlist load + -------------------------------------------------*/ + +bool vboy_cart_slot_device::call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry) +{ + load_software_part_region(*this, swlist, swname, start_entry); + return TRUE; +} + + + +/*------------------------------------------------- + get default card software + -------------------------------------------------*/ + +void vboy_cart_slot_device::get_default_card_software(std::string &result) +{ + software_get_default_slot(result, "vb_rom"); +} + +/*------------------------------------------------- + read + -------------------------------------------------*/ + +READ32_MEMBER(vboy_cart_slot_device::read_cart) +{ + if (m_cart) + return m_cart->read_cart(space, offset, mem_mask); + else + return 0xffffffff; +} + +/*------------------------------------------------- + read + -------------------------------------------------*/ + +READ32_MEMBER(vboy_cart_slot_device::read_eeprom) +{ + if (m_cart) + return m_cart->read_eeprom(space, offset, mem_mask); + else + return 0xffffffff; +} + +/*------------------------------------------------- + write + -------------------------------------------------*/ + +WRITE32_MEMBER(vboy_cart_slot_device::write_eeprom) +{ + if (m_cart) + m_cart->write_eeprom(space, offset, data, mem_mask); +} diff --git a/src/devices/bus/vboy/slot.h b/src/devices/bus/vboy/slot.h new file mode 100644 index 00000000000..e865eece213 --- /dev/null +++ b/src/devices/bus/vboy/slot.h @@ -0,0 +1,115 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __VBOY_SLOT_H +#define __VBOY_SLOT_H + +/*************************************************************************** + TYPE DEFINITIONS + ***************************************************************************/ + + +/* PCB */ +enum +{ + VBOY_STD = 0, + VBOY_EEPROM +}; + + +// ======================> device_vboy_cart_interface + +class device_vboy_cart_interface : public device_slot_card_interface +{ +public: + // construction/destruction + device_vboy_cart_interface(const machine_config &mconfig, device_t &device); + virtual ~device_vboy_cart_interface(); + + // reading and writing + virtual DECLARE_READ32_MEMBER(read_cart) { return 0xffffffff; } + virtual DECLARE_READ32_MEMBER(read_eeprom) { return 0xffffffff; } + virtual DECLARE_WRITE32_MEMBER(write_eeprom) {} + + void rom_alloc(UINT32 size, const char *tag); + void eeprom_alloc(UINT32 size); + UINT32* get_rom_base() { return m_rom; } + UINT32* get_eeprom_base() { return &m_eeprom[0]; } + UINT32 get_rom_size() { return m_rom_size; } + UINT32 get_eeprom_size() { return m_eeprom.size(); } + + void save_eeprom() { device().save_item(NAME(m_eeprom)); } + +protected: + // internal state + UINT32 *m_rom; + UINT32 m_rom_size; + UINT32 m_rom_mask; + std::vector m_eeprom; +}; + + +// ======================> vboy_cart_slot_device + +class vboy_cart_slot_device : public device_t, + public device_image_interface, + public device_slot_interface +{ +public: + // construction/destruction + vboy_cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual ~vboy_cart_slot_device(); + + // device-level overrides + virtual void device_start(); + virtual void device_config_complete(); + + // image-level overrides + virtual bool call_load(); + virtual void call_unload(); + virtual bool call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry); + + int get_type() { return m_type; } + int get_cart_type(UINT8 *ROM, UINT32 len); + + void save_eeprom() { if (m_cart && m_cart->get_eeprom_size()) m_cart->save_eeprom(); } + + virtual iodevice_t image_type() const { return IO_CARTSLOT; } + virtual bool is_readable() const { return 1; } + virtual bool is_writeable() const { return 0; } + virtual bool is_creatable() const { return 0; } + virtual bool must_be_loaded() const { return 1; } + virtual bool is_reset_on_load() const { return 1; } + virtual const option_guide *create_option_guide() const { return NULL; } + virtual const char *image_interface() const { return "vboy_cart"; } + virtual const char *file_extensions() const { return "vb,bin"; } + + // slot interface overrides + virtual void get_default_card_software(std::string &result); + + // reading and writing + virtual DECLARE_READ32_MEMBER(read_cart); + virtual DECLARE_READ32_MEMBER(read_eeprom); + virtual DECLARE_WRITE32_MEMBER(write_eeprom); + +protected: + + int m_type; + device_vboy_cart_interface* m_cart; +}; + + + +// device type definition +extern const device_type VBOY_CART_SLOT; + + +/*************************************************************************** + DEVICE CONFIGURATION MACROS + ***************************************************************************/ + +#define VBOYSLOT_ROM_REGION_TAG ":cart:rom" + +#define MCFG_VBOY_CARTRIDGE_ADD(_tag,_slot_intf,_def_slot) \ + MCFG_DEVICE_ADD(_tag, VBOY_CART_SLOT, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) +#endif diff --git a/src/devices/bus/vc4000/rom.c b/src/devices/bus/vc4000/rom.c new file mode 100644 index 00000000000..5c8ebf5c7bb --- /dev/null +++ b/src/devices/bus/vc4000/rom.c @@ -0,0 +1,269 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + Interton Electronic VC 4000 cart emulation + + + ***********************************************************************************************************/ + + +/* Game List and Emulation Status + + When you load a game it will normally appear to be unresponsive. Most carts contain a number of variants + of each game (e.g. Difficulty, Player1 vs Player2 or Player1 vs Computer, etc). + + Press F2 (if needed) to select which game variant you would like to play. The variant number will increment + on-screen. When you've made your choice, press F1 to start. The main keys are unlabelled, because an overlay + is provided with each cart. See below for a guide. You need to read the instructions that come with each game. + + In some games, the joystick is used like 4 buttons, and other games like a paddle. The two modes are + incompatible when using a keyboard. Therefore (in the emulation) a config dipswitch is used. The preferred + setting is listed below. + + (AC = Auto-centre, NAC = no auto-centre, 90 = turn controller 90 degrees). + + The list is rather incomplete, information will be added as it becomes available. + + The game names and numbers were obtained from the Amigan Software site. + + Cart Num Name + ---------------------------------------------- + 1. Grand Prix / Car Races / Autosport / Motor Racing / Road Race + Config: Paddle, NAC + Status: Working + Controls: Left-Right: Steer; Up: Accelerate + + 2. Black Jack + Status: Not working (some digits missing; indicator missing; dealer's cards missing) + Controls: set bet with S and D; A to deal; 1 to hit, 2 to stay; Q accept insurance, E to decline; double-up (unknown key) + Indicator: E make a bet then deal; I choose insurance; - you lost; + you won; X hit or stay + + 3. Olympics / Paddle Games / Bat & Ball / Pro Sport 60 / Sportsworld + Config: Paddle, NAC + Status: Working + + 4. Tank Battle / Combat + Config: Button, 90 + Status: Working + Controls: Left-Right: Steer; Up: Accelerate; Fire: Shoot + + 5. Maths 1 + Status: Working + Controls: Z difficulty; X = addition or subtraction; C ask question; A=1;S=2;D=3;Q=4;W=5;E=6;1=7;2=8;3=9;0=0; C enter + + 6. Maths 2 + Status: Not working + Controls: Same as above. + + 7. Air Sea Attack / Air Sea Battle + Config: Button, 90 + Status: Working + Controls: Left-Right: Move; Fire: Shoot + + 8. Treasure Hunt / Capture the Flag / Concentration / Memory Match + Config: Buttons + Status: Working + + 9. Labyrinth / Maze / Intelligence 1 + Config: Buttons + Status: Working + + 10. Winter Sports + Notes: Background colours should be Cyan and White instead of Red and Black + + 11. Hippodrome / Horse Race + + 12. Hunting / Shooting Gallery + + 13. Chess 1 + Status: Can't see what you're typing, wrong colours + + 14. Moto-cros + + 15. Four in a row / Intelligence 2 + Config: Buttons + Status: Working + Notes: Seems the unused squares should be black. The screen jumps about while the computer is "thinking". + + 16. Code Breaker / Master Mind / Intelligence 3 / Challenge + + 17. Circus + STatus: severe gfx issues + + 18. Boxing / Prize Fight + + 19. Outer Space / Spacewar / Space Attack / Outer Space Combat + + 20. Melody Simon / Musical Memory / Follow the Leader / Musical Games / Electronic Music / Face the Music + + 21. Capture / Othello / Reversi / Attack / Intelligence 4 + Config: Buttons + Status: Working + Notes: Seems the unused squares should be black + + 22. Chess 2 + Status: Can't see what you're typing, wrong colours + + 23. Pinball / Flipper / Arcade + Status: gfx issues + + 24. Soccer + + 25. Bowling / NinePins + Config: Paddle, rotated 90 degrees, up/down autocentre, left-right does not + Status: Working + + 26. Draughts + + 27. Golf + Status: gfx issues + + 28. Cockpit + Status: gfx issues + + 29. Metropolis / Hangman + Status: gfx issues + + 30. Solitaire + + 31. Casino + Status: gfx issues, items missing and unplayable + Controls: 1 or 3=START; q=GO; E=STOP; D=$; Z=^; X=tens; C=units + + 32. Invaders / Alien Invasion / Earth Invasion + Status: Works + Config: Buttons + + 33. Super Invaders + Status: Stars are missing, colours are wrong + Config: Buttons (90) + + 36. BackGammon + Status: Not all counters are visible, Dice & game number not visible. + Controls: Fire=Exec; 1=D+; 3=D-; Q,W,E=4,5,6; A,S,D=1,2,3; Z=CL; X=STOP; C=SET + + 37. Monster Man / Spider's Web + Status: Works + Config: Buttons + + 38. Hyperspace + Status: Works + Config: Buttons (90) + Controls: 3 - status button; Q,W,E,A,S,D,Z,X,C selects which galaxy to visit + + + 40. Super Space + Status: Works, some small gfx issues near the bottom + Config: Buttons + + + + Acetronic: (dumps are compatible) + ------------ + + * Shooting Gallery + Status: works but screen flickers + Config: Buttons + + * Planet Defender + Status: Works + Config: Paddle (NAC) + + * Laser Attack + Status: Works + Config: Buttons + + + + Public Domain: (written for emulators, may not work on real hardware) + --------------- + * Picture (no controls) - works + * Wincadia Stub (no controls) - works, small graphic error */ + + + +#include "emu.h" +#include "rom.h" + + +//------------------------------------------------- +// vc4000_rom_device - constructor +//------------------------------------------------- + +const device_type VC4000_ROM_STD = &device_creator; +const device_type VC4000_ROM_ROM4K = &device_creator; +const device_type VC4000_ROM_RAM1K = &device_creator; +const device_type VC4000_ROM_CHESS2 = &device_creator; + + +vc4000_rom_device::vc4000_rom_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_vc4000_cart_interface( mconfig, *this ) +{ +} + +vc4000_rom_device::vc4000_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, VC4000_ROM_STD, "VC 4000 Standard Carts", tag, owner, clock, "vc4000_rom", __FILE__), + device_vc4000_cart_interface( mconfig, *this ) +{ +} + +vc4000_rom4k_device::vc4000_rom4k_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : vc4000_rom_device(mconfig, VC4000_ROM_ROM4K, "VC 4000 Carts w/4K ROM", tag, owner, clock, "vc4000_rom4k", __FILE__) +{ +} + +vc4000_ram1k_device::vc4000_ram1k_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : vc4000_rom_device(mconfig, VC4000_ROM_RAM1K, "VC 4000 Carts w/1K RAM", tag, owner, clock, "vc4000_ram1k", __FILE__) +{ +} + +vc4000_chess2_device::vc4000_chess2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : vc4000_rom_device(mconfig, VC4000_ROM_CHESS2, "VC 4000 Chess II Cart", tag, owner, clock, "vc4000_chess2", __FILE__) +{ +} + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +READ8_MEMBER(vc4000_rom_device::read_rom) +{ + if (offset < m_rom_size) + return m_rom[offset]; + else + return 0xff; +} + + +READ8_MEMBER(vc4000_ram1k_device::read_ram) +{ + return m_ram[offset & (m_ram.size() - 1)]; +} + +WRITE8_MEMBER(vc4000_ram1k_device::write_ram) +{ + m_ram[offset & (m_ram.size() - 1)] = data; +} + + +READ8_MEMBER(vc4000_chess2_device::extra_rom) +{ + if (offset < (m_rom_size - 0x2000)) + return m_rom[offset + 0x2000]; + else + return 0xff; +} + +READ8_MEMBER(vc4000_chess2_device::read_ram) +{ + return m_ram[offset & (m_ram.size() - 1)]; +} + +WRITE8_MEMBER(vc4000_chess2_device::write_ram) +{ + m_ram[offset & (m_ram.size() - 1)] = data; +} diff --git a/src/devices/bus/vc4000/rom.h b/src/devices/bus/vc4000/rom.h new file mode 100644 index 00000000000..ae4502f57a2 --- /dev/null +++ b/src/devices/bus/vc4000/rom.h @@ -0,0 +1,74 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __VC4000_ROM_H +#define __VC4000_ROM_H + +#include "slot.h" + + +// ======================> vc4000_rom_device + +class vc4000_rom_device : public device_t, + public device_vc4000_cart_interface +{ +public: + // construction/destruction + vc4000_rom_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + vc4000_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start() {} + virtual void device_reset() {} + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_rom); +}; + +// ======================> vc4000_rom4k_device + +class vc4000_rom4k_device : public vc4000_rom_device +{ +public: + // construction/destruction + vc4000_rom4k_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +// ======================> vc4000_ram1k_device + +class vc4000_ram1k_device : public vc4000_rom_device +{ +public: + // construction/destruction + vc4000_ram1k_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_ram); + virtual DECLARE_WRITE8_MEMBER(write_ram); +}; + +// ======================> vc4000_chess2_device + +class vc4000_chess2_device : public vc4000_rom_device +{ +public: + // construction/destruction + vc4000_chess2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // reading and writing + virtual DECLARE_READ8_MEMBER(extra_rom); + virtual DECLARE_READ8_MEMBER(read_ram); + virtual DECLARE_WRITE8_MEMBER(write_ram); +}; + + + + + +// device type definition +extern const device_type VC4000_ROM_STD; +extern const device_type VC4000_ROM_ROM4K; +extern const device_type VC4000_ROM_RAM1K; +extern const device_type VC4000_ROM_CHESS2; + + +#endif diff --git a/src/devices/bus/vc4000/slot.c b/src/devices/bus/vc4000/slot.c new file mode 100644 index 00000000000..2c353ef90b6 --- /dev/null +++ b/src/devices/bus/vc4000/slot.c @@ -0,0 +1,295 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + Interton Electronic VC 4000 cart emulation + (through slot devices) + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "slot.h" + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type VC4000_CART_SLOT = &device_creator; + +//************************************************************************** +// VC4000 Cartridges Interface +//************************************************************************** + +//------------------------------------------------- +// device_vc4000_cart_interface - constructor +//------------------------------------------------- + +device_vc4000_cart_interface::device_vc4000_cart_interface(const machine_config &mconfig, device_t &device) + : device_slot_card_interface(mconfig, device), + m_rom(NULL), + m_rom_size(0) +{ +} + + +//------------------------------------------------- +// ~device_vc4000_cart_interface - destructor +//------------------------------------------------- + +device_vc4000_cart_interface::~device_vc4000_cart_interface() +{ +} + +//------------------------------------------------- +// rom_alloc - alloc the space for the cart +//------------------------------------------------- + +void device_vc4000_cart_interface::rom_alloc(UINT32 size, const char *tag) +{ + if (m_rom == NULL) + { + m_rom = device().machine().memory().region_alloc(std::string(tag).append(VC4000SLOT_ROM_REGION_TAG).c_str(), size, 1, ENDIANNESS_LITTLE)->base(); + m_rom_size = size; + } +} + + +//------------------------------------------------- +// ram_alloc - alloc the space for the ram +//------------------------------------------------- + +void device_vc4000_cart_interface::ram_alloc(UINT32 size) +{ + m_ram.resize(size); +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// vc4000_cart_slot_device - constructor +//------------------------------------------------- +vc4000_cart_slot_device::vc4000_cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, VC4000_CART_SLOT, "Interton VC 4000 Cartridge Slot", tag, owner, clock, "vc4000_cart_slot", __FILE__), + device_image_interface(mconfig, *this), + device_slot_interface(mconfig, *this), + m_type(VC4000_STD) +{ +} + + +//------------------------------------------------- +// vc4000_cart_slot_device - destructor +//------------------------------------------------- + +vc4000_cart_slot_device::~vc4000_cart_slot_device() +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void vc4000_cart_slot_device::device_start() +{ + m_cart = dynamic_cast(get_card_device()); +} + +//------------------------------------------------- +// device_config_complete - perform any +// operations now that the configuration is +// complete +//------------------------------------------------- + +void vc4000_cart_slot_device::device_config_complete() +{ + // set brief and instance name + update_names(); +} + + +//------------------------------------------------- +// VC4000 PCB +//------------------------------------------------- + +struct vc4000_slot +{ + int pcb_id; + const char *slot_option; +}; + +// Here, we take the feature attribute from .xml (i.e. the PCB name) and we assign a unique ID to it +static const vc4000_slot slot_list[] = +{ + { VC4000_STD, "std" }, + { VC4000_ROM4K, "rom4k" }, + { VC4000_RAM1K, "ram1k" }, + { VC4000_CHESS2, "chess2" } +}; + +static int vc4000_get_pcb_id(const char *slot) +{ + for (int i = 0; i < ARRAY_LENGTH(slot_list); i++) + { + if (!core_stricmp(slot_list[i].slot_option, slot)) + return slot_list[i].pcb_id; + } + + return 0; +} + +static const char *vc4000_get_slot(int type) +{ + for (int i = 0; i < ARRAY_LENGTH(slot_list); i++) + { + if (slot_list[i].pcb_id == type) + return slot_list[i].slot_option; + } + + return "std"; +} + + +/*------------------------------------------------- + call load + -------------------------------------------------*/ + +bool vc4000_cart_slot_device::call_load() +{ + if (m_cart) + { + UINT32 size = (software_entry() == NULL) ? length() : get_software_region_length("rom"); + + if (size > 0x1800) + { + seterror(IMAGE_ERROR_UNSPECIFIED, "Image extends beyond the expected size for a VC4000 cart"); + return IMAGE_INIT_FAIL; + } + + m_cart->rom_alloc(size, tag()); + + if (software_entry() == NULL) + fread(m_cart->get_rom_base(), size); + else + memcpy(m_cart->get_rom_base(), get_software_region("rom"), size); + + if (software_entry() == NULL) + { + m_type = VC4000_STD; + // attempt to identify the non-standard types + if (size > 0x1000) // 6k rom + 1k ram - Chess2 only + m_type = VC4000_CHESS2; + else if (size > 0x0800) // some 4k roms have 1k of mirrored ram (those who don't still work with RAM emulated luckily) + m_type = VC4000_RAM1K; + + if (m_type == VC4000_RAM1K || m_type == VC4000_CHESS2) + m_cart->ram_alloc(0x400); + } + else + { + const char *pcb_name = get_feature("slot"); + if (pcb_name) + m_type = vc4000_get_pcb_id(pcb_name); + + if (get_software_region("ram")) + m_cart->ram_alloc(get_software_region_length("ram")); + } + + //printf("Type: %s\n", vc4000_get_slot(m_type)); + + return IMAGE_INIT_PASS; + } + + return IMAGE_INIT_PASS; +} + + +/*------------------------------------------------- + call softlist load + -------------------------------------------------*/ + +bool vc4000_cart_slot_device::call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry) +{ + load_software_part_region(*this, swlist, swname, start_entry); + return TRUE; +} + + +/*------------------------------------------------- + get default card software + -------------------------------------------------*/ + +void vc4000_cart_slot_device::get_default_card_software(std::string &result) +{ + if (open_image_file(mconfig().options())) + { + const char *slot_string = "std"; + UINT32 size = core_fsize(m_file); + int type = VC4000_STD; + + // attempt to identify the non-standard types + if (size > 0x1000) // 6k rom + 1k ram - Chess2 only + type = VC4000_CHESS2; + else if (size > 0x0800) // some 4k roms have 1k of mirrored ram + type = VC4000_RAM1K; + + slot_string = vc4000_get_slot(type); + + //printf("type: %s\n", slot_string); + clear(); + + result.assign(slot_string); + return; + } + + software_get_default_slot(result, "std"); +} + +/*------------------------------------------------- + read + -------------------------------------------------*/ + +READ8_MEMBER(vc4000_cart_slot_device::read_rom) +{ + if (m_cart) + return m_cart->read_rom(space, offset); + else + return 0xff; +} + +/*------------------------------------------------- + read + -------------------------------------------------*/ + +READ8_MEMBER(vc4000_cart_slot_device::extra_rom) +{ + if (m_cart) + return m_cart->extra_rom(space, offset); + else + return 0xff; +} + +/*------------------------------------------------- + read + -------------------------------------------------*/ + +READ8_MEMBER(vc4000_cart_slot_device::read_ram) +{ + if (m_cart) + return m_cart->read_ram(space, offset); + else + return 0xff; +} + +/*------------------------------------------------- + write + -------------------------------------------------*/ + +WRITE8_MEMBER(vc4000_cart_slot_device::write_ram) +{ + if (m_cart) + m_cart->write_ram(space, offset, data); +} diff --git a/src/devices/bus/vc4000/slot.h b/src/devices/bus/vc4000/slot.h new file mode 100644 index 00000000000..62cf4655f89 --- /dev/null +++ b/src/devices/bus/vc4000/slot.h @@ -0,0 +1,117 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __VC4000_SLOT_H +#define __VC4000_SLOT_H + +/*************************************************************************** + TYPE DEFINITIONS + ***************************************************************************/ + + +/* PCB */ +enum +{ + VC4000_STD = 0, + VC4000_ROM4K, + VC4000_RAM1K, + VC4000_CHESS2 +}; + + +// ======================> device_vc4000_cart_interface + +class device_vc4000_cart_interface : public device_slot_card_interface +{ +public: + // construction/destruction + device_vc4000_cart_interface(const machine_config &mconfig, device_t &device); + virtual ~device_vc4000_cart_interface(); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_rom) { return 0xff; } + virtual DECLARE_READ8_MEMBER(extra_rom) { return 0xff; } + virtual DECLARE_READ8_MEMBER(read_ram) { return 0xff; } + virtual DECLARE_WRITE8_MEMBER(write_ram) {} + + void rom_alloc(UINT32 size, const char *tag); + void ram_alloc(UINT32 size); + UINT8* get_rom_base() { return m_rom; } + UINT8* get_ram_base() { return &m_ram[0]; } + UINT32 get_rom_size() { return m_rom_size; } + UINT32 get_ram_size() { return m_ram.size(); } + + void save_ram() { device().save_item(NAME(m_ram)); } + +protected: + // internal state + UINT8 *m_rom; + UINT32 m_rom_size; + dynamic_buffer m_ram; +}; + + +// ======================> vc4000_cart_slot_device + +class vc4000_cart_slot_device : public device_t, + public device_image_interface, + public device_slot_interface +{ +public: + // construction/destruction + vc4000_cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual ~vc4000_cart_slot_device(); + + // device-level overrides + virtual void device_start(); + virtual void device_config_complete(); + + // image-level overrides + virtual bool call_load(); + virtual void call_unload() {} + virtual bool call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry); + + int get_type() { return m_type; } + + void save_ram() { if (m_cart && m_cart->get_ram_size()) m_cart->save_ram(); } + + virtual iodevice_t image_type() const { return IO_CARTSLOT; } + virtual bool is_readable() const { return 1; } + virtual bool is_writeable() const { return 0; } + virtual bool is_creatable() const { return 0; } + virtual bool must_be_loaded() const { return 0; } + virtual bool is_reset_on_load() const { return 1; } + virtual const option_guide *create_option_guide() const { return NULL; } + virtual const char *image_interface() const { return "vc4000_cart"; } + virtual const char *file_extensions() const { return "bin,rom"; } + + // slot interface overrides + virtual void get_default_card_software(std::string &result); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_rom); + virtual DECLARE_READ8_MEMBER(extra_rom); + virtual DECLARE_READ8_MEMBER(read_ram); + virtual DECLARE_WRITE8_MEMBER(write_ram); + +protected: + + int m_type; + device_vc4000_cart_interface* m_cart; +}; + + + +// device type definition +extern const device_type VC4000_CART_SLOT; + + +/*************************************************************************** + DEVICE CONFIGURATION MACROS + ***************************************************************************/ + +#define VC4000SLOT_ROM_REGION_TAG ":cart:rom" + +#define MCFG_VC4000_CARTRIDGE_ADD(_tag,_slot_intf,_def_slot) \ + MCFG_DEVICE_ADD(_tag, VC4000_CART_SLOT, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) +#endif diff --git a/src/devices/bus/vcs/compumat.c b/src/devices/bus/vcs/compumat.c new file mode 100644 index 00000000000..4fc7d9cba5b --- /dev/null +++ b/src/devices/bus/vcs/compumat.c @@ -0,0 +1,53 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*************************************************************************** + + Atari 2600 cart Spectravideo Compumate (Cart + keyboard!) + + This is tricky to implement and it is only a skeleton ATM. + The device needs to interface with both the TIA and the RIOT. + +***************************************************************************/ + + +#include "emu.h" +#include "compumat.h" + +const device_type A26_ROM_COMPUMATE = &device_creator; + + +a26_rom_cm_device::a26_rom_cm_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : a26_rom_f6_device(mconfig, A26_ROM_COMPUMATE, "Atari 2600 ROM Cart Compumate", tag, owner, clock, "a2600_cm", __FILE__) +{ +} + +//------------------------------------------------- +// mapper specific start/reset +//------------------------------------------------- + +void a26_rom_cm_device::device_start() +{ + save_item(NAME(m_base_bank)); +} + +void a26_rom_cm_device::device_reset() +{ + m_base_bank = 3; +} + + +static INPUT_PORTS_START( keyboard ) +INPUT_PORTS_END + + +ioport_constructor a26_rom_cm_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( keyboard ); +} + + + +READ8_MEMBER(a26_rom_cm_device::read_rom) +{ + return m_rom[offset + (m_base_bank * 0x1000)]; +} diff --git a/src/devices/bus/vcs/compumat.h b/src/devices/bus/vcs/compumat.h new file mode 100644 index 00000000000..80f1df069fd --- /dev/null +++ b/src/devices/bus/vcs/compumat.h @@ -0,0 +1,35 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __VCS_COMPUMAT_H +#define __VCS_COMPUMAT_H + +#include "rom.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> a26_rom_cm_device + +class a26_rom_cm_device : public a26_rom_f6_device +{ +public: + // construction/destruction + a26_rom_cm_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual ioport_constructor device_input_ports() const; + virtual void device_reset(); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_rom); + +private: +}; + + +// device type definition +extern const device_type A26_ROM_COMPUMATE; + +#endif diff --git a/src/devices/bus/vcs/dpc.c b/src/devices/bus/vcs/dpc.c new file mode 100644 index 00000000000..f0787b6bcb4 --- /dev/null +++ b/src/devices/bus/vcs/dpc.c @@ -0,0 +1,300 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*************************************************************************** + + + Atari 2600 cart with DPC chip (Pitfall II) + +***************************************************************************/ + + +#include "emu.h" +#include "dpc.h" + + +// DPC device + +const device_type ATARI_DPC = &device_creator; + + +dpc_device::dpc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, ATARI_DPC, "Atari DCP", tag, owner, clock, "atari_dcp", __FILE__), + m_displaydata(NULL) +{ +} + + +void dpc_device::device_start() +{ + m_oscillator = timer_alloc(TIMER_OSC); + m_oscillator->reset(); + + for (int i = 0; i < 8; i++) + { + save_item(NAME(m_df[i].top), i); + save_item(NAME(m_df[i].bottom), i); + save_item(NAME(m_df[i].low), i); + save_item(NAME(m_df[i].high), i); + save_item(NAME(m_df[i].flag), i); + save_item(NAME(m_df[i].music_mode), i); + save_item(NAME(m_df[i].osc_clk), i); + } + + save_item(NAME(m_movamt)); + save_item(NAME(m_latch_62)); + save_item(NAME(m_latch_64)); + save_item(NAME(m_dlc)); + save_item(NAME(m_shift_reg)); +} + +void dpc_device::device_reset() +{ + for (int data_fetcher = 0; data_fetcher < 8; data_fetcher++) + { + m_df[data_fetcher].osc_clk = 0; + m_df[data_fetcher].flag = 0; + m_df[data_fetcher].music_mode = 0; + } + m_oscillator->adjust(attotime::from_hz(18400), 0, attotime::from_hz(18400)); + +} + +void dpc_device::check_flag(UINT8 data_fetcher) +{ + /* Set flag when low counter equals top */ + if (m_df[data_fetcher].low == m_df[data_fetcher].top) + m_df[data_fetcher].flag = 1; + + /* Reset flag when low counter equals bottom */ + if (m_df[data_fetcher].low == m_df[data_fetcher].bottom) + m_df[data_fetcher].flag = 0; +} + +void dpc_device::decrement_counter(UINT8 data_fetcher) +{ + m_df[data_fetcher].low -= 1; + if (m_df[data_fetcher].low == 0xff) + { + m_df[data_fetcher].high -= 1; + if (data_fetcher > 4 && m_df[data_fetcher].music_mode) + m_df[data_fetcher].low = m_df[data_fetcher].top; + } + + check_flag(data_fetcher); +} + + +//------------------------------------------------- +// device_timer - handler timer events +//------------------------------------------------- + +void dpc_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + if (id == TIMER_OSC) + { + // callback + for (int data_fetcher = 5; data_fetcher < 8; data_fetcher++) + { + if (m_df[data_fetcher].osc_clk) + { + decrement_counter(data_fetcher); + } + } + } +} + + +//------------------------------------------------- +// Read / Write accesses +//------------------------------------------------- + +READ8_MEMBER(dpc_device::read) +{ + static const UINT8 dpc_amplitude[8] = { 0x00, 0x04, 0x05, 0x09, 0x06, 0x0a, 0x0b, 0x0f }; + UINT8 data_fetcher = offset & 0x07; + UINT8 data = 0xff; + + //logerror("%04X: Read from DPC offset $%02X\n", machine().device("maincpu")->pc(), offset); + if (offset < 0x08) + { + switch(offset & 0x06) + { + case 0x00: // Random number generator + case 0x02: + return m_shift_reg; + case 0x04: // Sound value, MOVAMT value AND'd with Draw Line Carry; with Draw Line Add + m_latch_62 = m_latch_64; + case 0x06: // Sound value, MOVAMT value AND'd with Draw Line Carry; without Draw Line Add + m_latch_64 = m_latch_62 + m_df[4].top; + m_dlc = (m_latch_62 + m_df[4].top > 0xff) ? 1 : 0; + data = 0; + if (m_df[5].music_mode && m_df[5].flag) + data |= 0x01; + + if (m_df[6].music_mode && m_df[6].flag) + data |= 0x02; + + if (m_df[7].music_mode && m_df[7].flag) + data |= 0x04; + + return (m_dlc ? m_movamt & 0xf0 : 0) | dpc_amplitude[data]; + } + } + else + { + UINT8 display_data = m_displaydata[(~((m_df[data_fetcher].low | (m_df[data_fetcher].high << 8))) & 0x7ff)]; + + switch (offset & 0x38) + { + case 0x08: // display data + data = display_data; + break; + case 0x10: // display data AND'd w/flag + data = m_df[data_fetcher].flag ? display_data : 0x00; + break; + case 0x18: // display data AND'd w/flag, nibbles swapped + data = m_df[data_fetcher].flag ? BITSWAP8(display_data,3,2,1,0,7,6,5,4) : 0x00; + break; + case 0x20: // display data AND'd w/flag, byte reversed + data = m_df[data_fetcher].flag ? BITSWAP8(display_data,0,1,2,3,4,5,6,7) : 0x00; + break; + case 0x28: // display data AND'd w/flag, rotated right + data = m_df[data_fetcher].flag ? (display_data >> 1) : 0x00; + break; + case 0x30: // display data AND'd w/flag, rotated left + data = m_df[data_fetcher].flag ? (display_data << 1) : 0x00; + break; + case 0x38: // flag + data = m_df[data_fetcher].flag ? 0xff : 0x00; + break; + } + + if (data_fetcher < 5 || !m_df[data_fetcher].osc_clk) + { + decrement_counter(data_fetcher); + } + } + return data; +} + +WRITE8_MEMBER(dpc_device::write) +{ + UINT8 data_fetcher = offset & 0x07; + + switch (offset & 0x38) + { + case 0x00: // Top count + m_df[data_fetcher].top = data; + m_df[data_fetcher].flag = 0; + check_flag(data_fetcher); + break; + case 0x08: // Bottom count + m_df[data_fetcher].bottom = data; + check_flag(data_fetcher); + break; + case 0x10: // Counter low + m_df[data_fetcher].low = data; + if (data_fetcher == 4) + m_latch_64 = data; + + if (data_fetcher > 4 && m_df[data_fetcher].music_mode) + m_df[data_fetcher].low = m_df[data_fetcher].top; + + check_flag(data_fetcher); + break; + case 0x18: // Counter high + m_df[data_fetcher].high = data; + m_df[data_fetcher].music_mode = data & 0x10; + m_df[data_fetcher].osc_clk = data & 0x20; + if (data_fetcher > 4 && m_df[data_fetcher].music_mode && m_df[data_fetcher].low == 0xff) + { + m_df[data_fetcher].low = m_df[data_fetcher].top; + check_flag(data_fetcher); + } + break; + case 0x20: // Draw line movement value / MOVAMT + m_movamt = data; + break; + case 0x28: // Not used + logerror("%04X: Write to unused DPC register $%02X, data $%02X\n", machine().device("maincpu")->pc(), offset, data); + break; + case 0x30: // Random number generator reset + m_shift_reg = 0; + break; + case 0x38: // Not used + logerror("%04X: Write to unused DPC register $%02X, data $%02X\n", machine().device("maincpu")->pc(), offset, data); + break; + } +} + + + +// cart device + +const device_type A26_ROM_DPC = &device_creator; + + +a26_rom_dpc_device::a26_rom_dpc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : a26_rom_f8_device(mconfig, A26_ROM_DPC, "Atari 2600 ROM Cart Pitfall II", tag, owner, clock, "a2600_dcp", __FILE__), + m_dpc(*this, "dpc") +{ +} + +//------------------------------------------------- +// mapper specific start/reset +//------------------------------------------------- + +void a26_rom_dpc_device::device_start() +{ + save_item(NAME(m_base_bank)); +} + +void a26_rom_dpc_device::device_reset() +{ + m_base_bank = 0; +} + +void a26_rom_dpc_device::setup_addon_ptr(UINT8 *ptr) +{ + m_dpc->set_display_data(ptr); +} + + +static MACHINE_CONFIG_FRAGMENT( a26_dpc ) + MCFG_DEVICE_ADD("dpc", ATARI_DPC, 0) +MACHINE_CONFIG_END + +machine_config_constructor a26_rom_dpc_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( a26_dpc ); +} + + +READ8_MEMBER(a26_rom_dpc_device::read_rom) +{ + if (offset < 0x40) + return m_dpc->read(space, offset); + else + return a26_rom_f8_device::read_rom(space, offset); +} + +WRITE8_MEMBER(a26_rom_dpc_device::write_bank) +{ + if (offset >= 0x40 && offset < 0x80) + m_dpc->write(space, offset, data); + else + a26_rom_f8_device::write_bank(space, offset, data); +} + +DIRECT_UPDATE_MEMBER(a26_rom_dpc_device::cart_opbase) +{ + if (!direct.space().debugger_access()) + { + UINT8 new_bit; + new_bit = (m_dpc->m_shift_reg & 0x80) ^ ((m_dpc->m_shift_reg & 0x20) << 2); + new_bit = new_bit ^ (((m_dpc->m_shift_reg & 0x10) << 3) ^ ((m_dpc->m_shift_reg & 0x08) << 4)); + new_bit = new_bit ^ 0x80; + m_dpc->m_shift_reg = new_bit | (m_dpc->m_shift_reg >> 1); + } + return address; +} diff --git a/src/devices/bus/vcs/dpc.h b/src/devices/bus/vcs/dpc.h new file mode 100644 index 00000000000..9e04ddb2e67 --- /dev/null +++ b/src/devices/bus/vcs/dpc.h @@ -0,0 +1,95 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __VCS_DCP_H +#define __VCS_DCP_H + +#include "rom.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// TO DO: DPC should be made a separate device! + +struct df_t { + UINT8 top; + UINT8 bottom; + UINT8 low; + UINT8 high; + UINT8 flag; + UINT8 music_mode; /* Only used by data fetchers 5,6, and 7 */ + UINT8 osc_clk; /* Only used by data fetchers 5,6, and 7 */ +}; + +// m_dpc.oscillator = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(a2600_state::modeDPC_timer_callback),this)); + +class dpc_device : public device_t +{ +public: + // construction/destruction + dpc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + df_t m_df[8]; + UINT8 m_movamt; + UINT8 m_latch_62; + UINT8 m_latch_64; + UINT8 m_dlc; + UINT8 m_shift_reg; + UINT8 *m_displaydata; + void set_display_data(UINT8 *data) { m_displaydata = data; } + + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + virtual DECLARE_READ8_MEMBER(read); + virtual DECLARE_WRITE8_MEMBER(write); + +private: + + void decrement_counter(UINT8 data_fetcher); + void check_flag(UINT8 data_fetcher); + + static const device_timer_id TIMER_OSC = 0; + emu_timer *m_oscillator; +}; + + +// device type definition +extern const device_type ATARI_DPC; + + + +// ======================> a26_rom_dpc_device + +class a26_rom_dpc_device : public a26_rom_f8_device +{ +public: + // construction/destruction + a26_rom_dpc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual machine_config_constructor device_mconfig_additions() const; + virtual void device_reset(); + + required_device m_dpc; + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_rom); + virtual DECLARE_WRITE8_MEMBER(write_bank); + virtual DECLARE_DIRECT_UPDATE_MEMBER(cart_opbase); + + virtual void setup_addon_ptr(UINT8 *ptr); + +protected: +// int m_reset_bank; +}; + + +// device type definition +extern const device_type A26_ROM_DPC; + +#endif diff --git a/src/devices/bus/vcs/rom.c b/src/devices/bus/vcs/rom.c new file mode 100755 index 00000000000..b689db7094e --- /dev/null +++ b/src/devices/bus/vcs/rom.c @@ -0,0 +1,1050 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + A2600 VCS ROM cart emulation + Simple cart hardware with no additional hw + + Mapper implementation based on the wonderful docs by Kevtris + http://blog.kevtris.org/blogfiles/Atari%202600%20Mappers.txt + + (also inspired by previous work by Wilbert Pol et al.) + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "rom.h" + + +//------------------------------------------------- +// a26_rom_*k_device - constructor +//------------------------------------------------- + +const device_type A26_ROM_2K = &device_creator; +const device_type A26_ROM_4K = &device_creator; +const device_type A26_ROM_F4 = &device_creator; +const device_type A26_ROM_F6 = &device_creator; +const device_type A26_ROM_F8 = &device_creator; +const device_type A26_ROM_F8_SW = &device_creator; +const device_type A26_ROM_FA = &device_creator; +const device_type A26_ROM_FE = &device_creator; +const device_type A26_ROM_3E = &device_creator; +const device_type A26_ROM_3F = &device_creator; +const device_type A26_ROM_E0 = &device_creator; +const device_type A26_ROM_E7 = &device_creator; +const device_type A26_ROM_UA = &device_creator; +const device_type A26_ROM_CV = &device_creator; +const device_type A26_ROM_DC = &device_creator; +const device_type A26_ROM_FV = &device_creator; +const device_type A26_ROM_JVP = &device_creator; +const device_type A26_ROM_4IN1 = &device_creator; +const device_type A26_ROM_8IN1 = &device_creator; +const device_type A26_ROM_32IN1 = &device_creator; + + +a26_rom_2k_device::a26_rom_2k_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_vcs_cart_interface( mconfig, *this ) +{ +} + +a26_rom_2k_device::a26_rom_2k_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, A26_ROM_2K, "Atari VCS 2600 2K ROM Carts", tag, owner, clock, "vcs_2k", __FILE__), + device_vcs_cart_interface( mconfig, *this ) +{ +} + + +a26_rom_4k_device::a26_rom_4k_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : a26_rom_2k_device(mconfig, A26_ROM_4K, "Atari VCS 2600 4K ROM Carts", tag, owner, clock, "vcs_4k", __FILE__) +{ +} + + +a26_rom_f6_device::a26_rom_f6_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : a26_rom_2k_device(mconfig, type, name, tag, owner, clock, shortname, source), + m_base_bank(-1) // set to -1 to help the Xin1 multicart... +{ +} + +a26_rom_f6_device::a26_rom_f6_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : a26_rom_2k_device(mconfig, A26_ROM_F6, "Atari VCS 2600 ROM Carts w/F6 bankswitch", tag, owner, clock, "vcs_f6", __FILE__), + m_base_bank(-1) // set to -1 to help the Xin1 multicart... +{ +} + + +a26_rom_f4_device::a26_rom_f4_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : a26_rom_f6_device(mconfig, A26_ROM_F4, "Atari VCS 2600 ROM Carts w/F4 bankswitch", tag, owner, clock, "vcs_f4", __FILE__) +{ +} + + +a26_rom_f8_device::a26_rom_f8_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : a26_rom_f6_device(mconfig, type, name, tag, owner, clock, shortname, source) +{ +} + +a26_rom_f8_device::a26_rom_f8_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : a26_rom_f6_device(mconfig, A26_ROM_F8, "Atari VCS 2600 ROM Carts w/F8 bankswitch", tag, owner, clock, "vcs_f8", __FILE__) +{ +} + +a26_rom_f8_sw_device::a26_rom_f8_sw_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : a26_rom_f8_device(mconfig, A26_ROM_F8_SW, "Atari VCS 2600 ROM Cart Snow White", tag, owner, clock, "vcs_f8_sw", __FILE__) +{ +} + +a26_rom_fa_device::a26_rom_fa_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : a26_rom_f6_device(mconfig, A26_ROM_FA, "Atari VCS 2600 ROM Carts w/FA bankswitch", tag, owner, clock, "vcs_fa", __FILE__) +{ +} + + +a26_rom_fe_device::a26_rom_fe_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : a26_rom_2k_device(mconfig, A26_ROM_FE, "Atari VCS 2600 ROM Carts w/FE bankswitch", tag, owner, clock, "vcs_fe", __FILE__) +{ +} + + +a26_rom_3e_device::a26_rom_3e_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : a26_rom_f6_device(mconfig, A26_ROM_3E, "Atari VCS 2600 ROM Carts w/3E bankswitch", tag, owner, clock, "vcs_3e", __FILE__) +{ +} + + +a26_rom_3f_device::a26_rom_3f_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : a26_rom_f6_device(mconfig, A26_ROM_3F, "Atari VCS 2600 ROM Carts w/3F bankswitch", tag, owner, clock, "vcs_3f", __FILE__) +{ +} + + +a26_rom_e0_device::a26_rom_e0_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : a26_rom_f6_device(mconfig, A26_ROM_E0, "Atari VCS 2600 ROM Carts w/E0 bankswitch", tag, owner, clock, "vcs_e0", __FILE__) +{ +} + + +a26_rom_e7_device::a26_rom_e7_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : a26_rom_f6_device(mconfig, A26_ROM_E7, "Atari VCS 2600 ROM Carts w/E7 bankswitch", tag, owner, clock, "vcs_e7", __FILE__) +{ +} + + +a26_rom_ua_device::a26_rom_ua_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : a26_rom_f6_device(mconfig, A26_ROM_UA, "Atari VCS 2600 ROM Carts w/UA bankswitch", tag, owner, clock, "vcs_ua", __FILE__) +{ +} + + +a26_rom_cv_device::a26_rom_cv_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : a26_rom_2k_device(mconfig, A26_ROM_CV, "Atari VCS 2600 ROM Carts w/Commavid bankswitch", tag, owner, clock, "vcs_cv", __FILE__) +{ +} + + +a26_rom_dc_device::a26_rom_dc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : a26_rom_f6_device(mconfig, A26_ROM_DC, "Atari VCS 2600 ROM Carts w/Dynacom bankswitch", tag, owner, clock, "vcs_dc", __FILE__) +{ +} + + +a26_rom_fv_device::a26_rom_fv_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : a26_rom_f6_device(mconfig, A26_ROM_FV, "Atari VCS 2600 ROM Carts w/FV bankswitch", tag, owner, clock, "vcs_fv", __FILE__) +{ +} + + +a26_rom_jvp_device::a26_rom_jvp_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : a26_rom_f6_device(mconfig, A26_ROM_JVP, "Atari VCS 2600 ROM Carts w/JVP bankswitch", tag, owner, clock, "vcs_jvp", __FILE__) +{ +} + + +a26_rom_4in1_device::a26_rom_4in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : a26_rom_f6_device(mconfig, A26_ROM_4IN1, "Atari VCS 2600 ROM Cart 4 in 1", tag, owner, clock, "vcs_4in1", __FILE__) +{ +} + + +a26_rom_8in1_device::a26_rom_8in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : a26_rom_f8_device(mconfig, A26_ROM_8IN1, "Atari VCS 2600 ROM Cart 8 in 1", tag, owner, clock, "vcs_8in1", __FILE__) +{ +} + + +a26_rom_32in1_device::a26_rom_32in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : a26_rom_f6_device(mconfig, A26_ROM_32IN1, "Atari VCS 2600 ROM Cart 32 in 1", tag, owner, clock, "vcs_32in1", __FILE__) +{ +} + + +void a26_rom_2k_device::device_start() +{ +} + +void a26_rom_2k_device::device_reset() +{ +} + +void a26_rom_f6_device::device_start() +{ + save_item(NAME(m_base_bank)); +} + +void a26_rom_f6_device::device_reset() +{ + m_base_bank = 0; +} + +void a26_rom_f4_device::device_reset() +{ + m_base_bank = 7; +} + +void a26_rom_f8_sw_device::device_reset() +{ + // Snow White proto starts from bank 1!!! + m_base_bank = 1; +} + +void a26_rom_fe_device::device_start() +{ + save_item(NAME(m_base_bank)); + save_item(NAME(m_trigger_on_next_access)); +} + +void a26_rom_fe_device::device_reset() +{ + m_base_bank = 0; + m_trigger_on_next_access = 0; +} + +void a26_rom_3e_device::device_start() +{ + save_item(NAME(m_base_bank)); + save_item(NAME(m_ram_bank)); + save_item(NAME(m_ram_enable)); +} + +void a26_rom_3e_device::device_reset() +{ + m_num_bank = m_rom_size / 0x800; + m_base_bank = m_num_bank - 1; + m_ram_bank = 0; + m_ram_enable = 0; +} + +void a26_rom_3f_device::device_reset() +{ + m_num_bank = m_rom_size / 0x800; + m_base_bank = m_num_bank - 1; +} + +void a26_rom_e0_device::device_start() +{ + save_item(NAME(m_base_banks)); +} + +void a26_rom_e0_device::device_reset() +{ + m_base_banks[0] = 4; + m_base_banks[1] = 5; + m_base_banks[2] = 6; + m_base_banks[3] = 7; +} + +void a26_rom_e7_device::device_start() +{ + save_item(NAME(m_base_bank)); + save_item(NAME(m_ram_bank)); +} + +void a26_rom_e7_device::device_reset() +{ + m_base_bank = 0; + m_ram_bank = 0; +} + +void a26_rom_ua_device::device_reset() +{ + m_base_bank = 0; +} + +void a26_rom_fv_device::device_start() +{ + save_item(NAME(m_base_bank)); + save_item(NAME(m_locked)); +} + +void a26_rom_fv_device::device_reset() +{ + m_base_bank = 0; + m_locked = 0; +} + + +void a26_rom_4in1_device::device_reset() +{ + m_base_bank++; + m_base_bank &= 3; +} + + +void a26_rom_8in1_device::device_start() +{ + save_item(NAME(m_base_bank)); + save_item(NAME(m_reset_bank)); +} + +void a26_rom_8in1_device::device_reset() +{ + // we use here two different bank counter: the main one for the 8x8K chunks, + // and the usual one (m_base_bank) for the 4K bank of the current game + m_reset_bank++; + m_reset_bank &= 7; + m_base_bank = 0; +} + + +void a26_rom_32in1_device::device_reset() +{ + m_base_bank++; + m_base_bank &= 0x1f; +} + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +/*------------------------------------------------- + BASE 2K & 4K Carts: + no bankswitch + + GAMES: a large majority + -------------------------------------------------*/ + +READ8_MEMBER(a26_rom_2k_device::read_rom) +{ + // Super Chip RAM reads are mapped in 0x1080-0x10ff + if (!m_ram.empty() && offset >= 0x80 && offset < 0x100) + { + return m_ram[offset & (m_ram.size() - 1)]; + } + + return m_rom[offset & (m_rom_size - 1)]; +} + +/*------------------------------------------------- + "F4 Bankswitch" Carts: + read/write access to 0x1ff4-0x1ffb determines the + 4K ROM bank to be read + + GAMES: Fatal Run + -------------------------------------------------*/ + +READ8_MEMBER(a26_rom_f4_device::read_rom) +{ + // Super Chip RAM reads are mapped in 0x1080-0x10ff + if (!m_ram.empty() && offset >= 0x80 && offset < 0x100) + { + return m_ram[offset & (m_ram.size() - 1)]; + } + + // update banks + if (!space.debugger_access()) + { + switch (offset) + { + case 0x0ff4: + case 0x0ff5: + case 0x0ff6: + case 0x0ff7: + case 0x0ff8: + case 0x0ff9: + case 0x0ffa: + case 0x0ffb: + m_base_bank = offset - 0x0ff4; + break; + } + } + + return m_rom[offset + (m_base_bank * 0x1000)]; +} + +WRITE8_MEMBER(a26_rom_f4_device::write_bank) +{ + // Super Chip RAM writes are mapped in 0x1000-0x107f + if (!m_ram.empty() && offset < 0x80) + { + m_ram[offset & (m_ram.size() - 1)] = data; + return; + } + + switch (offset) + { + case 0x0ff4: + case 0x0ff5: + case 0x0ff6: + case 0x0ff7: + case 0x0ff8: + case 0x0ff9: + case 0x0ffa: + case 0x0ffb: + m_base_bank = offset - 0x0ff4; + break; + default: + logerror("Write Bank outside expected range (0x%X).\n", offset + 0x1000); + break; + } +} + +/*------------------------------------------------- + "F6 Bankswitch" Carts: + read/write access to 0x1ff6-0x1ff9 determines the + 4K ROM bank to be read + + GAMES: Atari 16K games, like Crossbow, Crystal + Castles and the 2-in-1 carts + + -------------------------------------------------*/ + +READ8_MEMBER(a26_rom_f6_device::read_rom) +{ + // Super Chip RAM reads are mapped in 0x1080-0x10ff + if (!m_ram.empty() && offset >= 0x80 && offset < 0x100) + { + return m_ram[offset & (m_ram.size() - 1)]; + } + + // update banks + if (!space.debugger_access()) + { + switch (offset) + { + case 0x0ff6: + case 0x0ff7: + case 0x0ff8: + case 0x0ff9: + m_base_bank = offset - 0x0ff6; + break; + } + } + + return m_rom[offset + (m_base_bank * 0x1000)]; +} + +WRITE8_MEMBER(a26_rom_f6_device::write_bank) +{ + // Super Chip RAM writes are mapped in 0x1000-0x107f + if (!m_ram.empty() && offset < 0x80) + { + m_ram[offset & (m_ram.size() - 1)] = data; + return; + } + + switch (offset) + { + case 0x0ff6: + case 0x0ff7: + case 0x0ff8: + case 0x0ff9: + m_base_bank = offset - 0x0ff6; + break; + default: + logerror("Write Bank outside expected range (0x%X).\n", offset + 0x1000); + break; + } +} + +DIRECT_UPDATE_MEMBER(a26_rom_f6_device::cart_opbase) +{ + if ((address & 0x1fff) >= 0x1ff6 && (address & 0x1fff) <= 0x1ff9) + { + if (!direct.space().debugger_access()) + write_bank(direct.space(), (address & 0x1fff) - 0x1ff6, 0); + } + return address; +} + +/*------------------------------------------------- + "F8 Bankswitch" Carts: + read/write access to 0x1ff8-0x1ff9 determines the + 4K ROM bank to be read + + GAMES: Atari 8K games, like Asteroids, Battlezone + and Taz + + -------------------------------------------------*/ + +READ8_MEMBER(a26_rom_f8_device::read_rom) +{ + // Super Chip RAM reads are mapped in 0x1080-0x10ff + if (!m_ram.empty() && offset >= 0x80 && offset < 0x100) + { + return m_ram[offset & (m_ram.size() - 1)]; + } + + // update banks + if (!space.debugger_access()) + { + switch (offset) + { + case 0x0ff8: + case 0x0ff9: + m_base_bank = offset - 0x0ff8; + break; + } + } + + return m_rom[offset + (m_base_bank * 0x1000)]; +} + +WRITE8_MEMBER(a26_rom_f8_device::write_bank) +{ + // Super Chip RAM writes are mapped in 0x1000-0x107f + if (!m_ram.empty() && offset < 0x80) + { + m_ram[offset & (m_ram.size() - 1)] = data; + return; + } + + switch (offset) + { + case 0x0ff8: + case 0x0ff9: + m_base_bank = offset - 0x0ff8; + break; + default: + logerror("Write Bank outside expected range (0x%X).\n", offset + 0x1000); + break; + } +} + +/*------------------------------------------------- + "FA Bankswitch" Carts: + read/write access to 0x1ff8-0x1ffa determines the + 4K ROM bank to be read + These games contained the CBS RAM+ chip (256bytes + of RAM) + + GAMES: CBS RAM Plus games like Omega Race and Tunnel + Runner + + -------------------------------------------------*/ + +READ8_MEMBER(a26_rom_fa_device::read_rom) +{ + // CBS RAM+ reads are mapped in 0x1100-0x11ff + if (!m_ram.empty() && offset >= 0x100 && offset < 0x200) + { + return m_ram[offset & (m_ram.size() - 1)]; + } + + // update banks + if (!space.debugger_access()) + { + switch (offset) + { + case 0x0ff8: + case 0x0ff9: + case 0x0ffa: + m_base_bank = offset - 0x0ff8; + break; + } + } + + return m_rom[offset + (m_base_bank * 0x1000)]; +} + +WRITE8_MEMBER(a26_rom_fa_device::write_bank) +{ + // CBS RAM+ writes are mapped in 0x1000-0x10ff + if (!m_ram.empty() && offset < 0x100) + { + m_ram[offset & (m_ram.size() - 1)] = data; + } + + switch (offset) + { + case 0x0ff8: + case 0x0ff9: + case 0x0ffa: + m_base_bank = offset - 0x0ff8; + break; + default: + logerror("Write Bank outside expected range (0x%X).\n", offset + 0x1000); + break; + } +} + +/*------------------------------------------------- + "FE Bankswitch" Carts: + read/write access to 0x01fe-0x1ff determines the + 4K ROM bank to be read + + GAMES: Activision 8K games like Decathlon + + -------------------------------------------------*/ +/* + + There seems to be a kind of lag between the writing to address 0x1FE and the + Activision switcher springing into action. It waits for the next byte to arrive + on the data bus, which is the new PCH in the case of a JSR, and the PCH of the + stored PC on the stack in the case of an RTS. + + depending on last byte & 0x20 -> 0x00 -> switch to bank #1 + -> 0x20 -> switch to bank #0 + + */ + +READ8_MEMBER(a26_rom_fe_device::read_rom) +{ + UINT8 data; + + // Super Chip RAM reads are mapped in 0x1080-0x10ff + if (!m_ram.empty() && offset >= 0x80 && offset < 0x100) + { + return m_ram[offset & (m_ram.size() - 1)]; + } + + data = m_rom[offset + (m_base_bank * 0x1000)]; + + if (!space.debugger_access()) + { + if (m_trigger_on_next_access) + { + m_base_bank = BIT(data, 5) ? 0 : 1; + m_trigger_on_next_access = 0; + } + } + + return data; +} + +WRITE8_MEMBER(a26_rom_fe_device::write_ram) +{ + // Super Chip RAM writes are mapped in 0x1000-0x107f + if (!m_ram.empty() && offset < 0x80) + { + m_ram[offset & (m_ram.size() - 1)] = data; + } +} + +READ8_MEMBER(a26_rom_fe_device::read_bank) +{ + UINT8 data = space.read_byte(0xfe + offset); + + if (!space.debugger_access()) + { + switch (offset & 1) + { + case 0: + // The next byte on the data bus determines which bank to switch to + m_trigger_on_next_access = 1; + break; + + case 1: + if (m_trigger_on_next_access) + { + m_base_bank = BIT(data, 5) ? 0 : 1; + m_trigger_on_next_access = 0; + } + break; + } + } + return data; +} + +WRITE8_MEMBER(a26_rom_fe_device::write_bank) +{ + space.write_byte(0xfe, data); + if (!space.debugger_access()) + { + // The next byte on the data bus determines which bank to switch to + m_trigger_on_next_access = 1; + } +} + +/*------------------------------------------------- + "3E Bankswitch" Carts: + write access to 0x3e determines the 2K ROM bank to + be read, write access to 0x3f determines the RAM bank + to be read + + GAMES: Boulder Dash (Homebrew) + + -------------------------------------------------*/ + +READ8_MEMBER(a26_rom_3e_device::read_rom) +{ + if (!m_ram.empty() && m_ram_enable && offset < 0x400) + return m_ram[offset + (m_ram_bank * 0x400)]; + + if (offset >= 0x800) + return m_rom[(offset & 0x7ff) + (m_num_bank - 1) * 0x800]; + else + return m_rom[offset + m_base_bank * 0x800]; +} + +WRITE8_MEMBER(a26_rom_3e_device::write_bank) +{ + if (offset == 0x3f) + { + m_base_bank = data & (m_num_bank - 1); + m_ram_enable = 0; + } + else if (offset == 0x3e) + { + m_ram_bank = data & 0x1f; + m_ram_enable = 1; + } +} + +WRITE8_MEMBER(a26_rom_3e_device::write_ram) +{ + if (!m_ram.empty() && m_ram_enable && offset >= 0x400 && offset < 0x800) + m_ram[(offset & 0x3ff) + (m_ram_bank * 0x400)] = data; +} + + +/*------------------------------------------------- + "3F Bankswitch" Carts: + write access to 0x00-0x3f determines the 2K ROM bank + to be read + + GAMES: Tigervision 8K games like Espial and Miner + 2049er. Extended version with bankswitch up to 512K + shall be supported as well (but we lack a test case) + + -------------------------------------------------*/ + +READ8_MEMBER(a26_rom_3f_device::read_rom) +{ + if (offset >= 0x800) + return m_rom[(offset & 0x7ff) + (m_num_bank - 1) * 0x800]; + else + return m_rom[offset + m_base_bank * 0x800]; +} + +WRITE8_MEMBER(a26_rom_3f_device::write_bank) +{ + m_base_bank = data & (m_num_bank - 1); +} + +/*------------------------------------------------- + "E0 Bankswitch" Carts: + read/write access to 0x1fe0-0x1ff8 determines the + 1K ROM bank to be read in each 1K chunk (0x1c00-0x1fff + always points to the last 1K of the ROM) + + GAMES: Parker Bros. 8K games like Gyruss and Popeye + + -------------------------------------------------*/ + +READ8_MEMBER(a26_rom_e0_device::read_rom) +{ + // update banks + if (!space.debugger_access()) + { + if (offset >= 0xfe0 && offset <= 0xff8) + m_base_banks[(offset >> 3) & 3] = offset & 7; + } + + return m_rom[(offset & 0x3ff) + (m_base_banks[(offset >> 10) & 3] * 0x400)]; +} + +WRITE8_MEMBER(a26_rom_e0_device::write_bank) +{ + if (offset >= 0xfe0 && offset <= 0xff8) + m_base_banks[(offset >> 3) & 3] = offset & 7; +} + + +/*------------------------------------------------- + "E7 Bankswitch" Carts: + this PCB can handle up to 16K of ROM and 2K of RAM, + with the following layout + 1000-17ff is selectable bank + 1800-19ff is RAM + 1a00-1fff is fixed to the last 0x600 of ROM + + The selectable bank can be ROM (if selected by + 0x1fe0-0x1fe6 access) or a first 1K of RAM (if + selected by 0x1fe7 access). + The other 256byte RAM bank can be one of the + four different chunks forming the other 1K of RAM + (the bank is selected by accessing 0x1fe8-0x1feb) + + GAMES: M Network 16K games like Burgertime and + Bump'n Jump + + -------------------------------------------------*/ + +READ8_MEMBER(a26_rom_e7_device::read_rom) +{ + // update banks + if (!space.debugger_access()) + { + if (offset >= 0xfe0 && offset <= 0xfe7) + m_base_bank = offset - 0xfe0; + if (offset >= 0xfe8 && offset <= 0xfeb) + m_ram_bank = offset - 0xfe8; + } + + if (!m_ram.empty()) + { + // 1K of RAM + if (m_base_bank == 0x07 && offset >= 0x400 && offset < 0x800) + return m_ram[0x400 + (offset & 0x3ff)]; + // the other 1K of RAM + if (offset >= 0x900 && offset < 0xa00) + { + offset -= 0x900; + return m_ram[offset + (m_ram_bank * 0x100)]; + } + } + + if (offset > 0x800) + return m_rom[(offset & 0x7ff) + 0x3800]; + else + return m_rom[(offset & 0x7ff) + (m_base_bank * 0x800)]; +} + +WRITE8_MEMBER(a26_rom_e7_device::write_bank) +{ + if (offset >= 0xfe0 && offset <= 0xfe7) + m_base_bank = offset - 0xfe0; + if (offset >= 0xfe8 && offset <= 0xfeb) + m_ram_bank = offset - 0xfe8; + + if (!m_ram.empty()) + { + // 1K of RAM + if (m_base_bank == 0x07 && offset < 0x400) + m_ram[0x400 + (offset & 0x3ff)] = data; + // the other 1K of RAM + if (offset >= 0x800 && offset < 0x900) + { + offset -= 0x800; + m_ram[offset + (m_ram_bank * 0x100)] = data; + } + } +} + +/*------------------------------------------------- + "UA Bankswitch" Carts: + read/write access to 0x200-0x27f determines the + 4K ROM bank to be read (0x220-0x23f for low 4K, + 0x240-0x27f for high 4K) + + GAMES: UA Ltd. 8K games like Funky Flash and + Pleaides + + -------------------------------------------------*/ + +READ8_MEMBER(a26_rom_ua_device::read_rom) +{ + return m_rom[(offset + (m_base_bank * 0x1000)) & (m_rom_size - 1)]; +} + +READ8_MEMBER(a26_rom_ua_device::read_bank) +{ + if (!space.debugger_access()) + m_base_bank = offset >> 6; + + return 0; +} + +WRITE8_MEMBER(a26_rom_ua_device::write_bank) +{ + m_base_bank = offset >> 6; +} + + +/*------------------------------------------------- + Commavid Carts: + It allows for both ROM and RAM on the cartridge, + without using bankswitching. There's 2K of ROM + and 1K of RAM. + + GAMES: Magicard and Video Life by Commavid + + -------------------------------------------------*/ + +READ8_MEMBER(a26_rom_cv_device::read_rom) +{ + if (!m_ram.empty() && offset < 0x400) + { + return m_ram[offset & (m_ram.size() - 1)]; + } + + // games shall not read from 0x1400-0x17ff (RAM write) + // but we fall back to ROM just in case... + return m_rom[offset & 0x7ff]; +} + +WRITE8_MEMBER(a26_rom_cv_device::write_bank) +{ + if (!m_ram.empty() && offset >= 0x400 && offset < 0x800) + { + m_ram[offset & (m_ram.size() - 1)] = data; + } +} + + +/*------------------------------------------------- + Dynacom Megaboy Carts (aka "F0 Banswitch"): + read/write access to 0x1ff0 determines the 4K ROM + bank to be read (each access increases the bank index + up to 16, since the cart was 64K wide) + + GAMES: Megaboy by Dynacom + + -------------------------------------------------*/ + +READ8_MEMBER(a26_rom_dc_device::read_rom) +{ + if (!space.debugger_access()) + { + if (offset == 0xff0) + m_base_bank = (m_base_bank + 1) & 0x0f; + } + + if (offset == 0xfec) + return m_base_bank; + + return m_rom[offset + (m_base_bank * 0x1000)]; +} + +WRITE8_MEMBER(a26_rom_dc_device::write_bank) +{ + if (offset == 0xff0) + m_base_bank = (m_base_bank + 1) & 0x0f; +} + + +/*------------------------------------------------- + "FV Bankswitch" Carts: + The first access to 0x1fd0 switch the bank, but + only if pc() & 0x1f00 == 0x1f00! + + GAMES: Challenge by HES + + -------------------------------------------------*/ + +READ8_MEMBER(a26_rom_fv_device::read_rom) +{ + if (!space.debugger_access()) + { + if (offset == 0xfd0) + { + if (!m_locked && (machine().device("maincpu")->pc() & 0x1f00) == 0x1f00) + { + m_locked = 1; + m_base_bank = m_base_bank ^ 0x01; + } + } + } + + return m_rom[offset + (m_base_bank * 0x1000)]; +} + +WRITE8_MEMBER(a26_rom_fv_device::write_bank) +{ + if (offset == 0xfd0) + { + if (!m_locked && (machine().device("maincpu")->pc() & 0x1f00) == 0x1f00) + { + m_locked = 1; + m_base_bank = m_base_bank ^ 0x01; + } + } +} + + +/*------------------------------------------------- + "JVP Bankswitch" Carts: + read/write access to 0x0fa0-0x0fc0 determines the + 4K ROM bank to be read (notice that this overlaps + the RIOT, currently handled in the main driver until + I can better investigate the behavior) + + GAMES: No test case!?! + + -------------------------------------------------*/ + +READ8_MEMBER(a26_rom_jvp_device::read_rom) +{ + return m_rom[offset + (m_base_bank * 0x1000)]; +} + +WRITE8_MEMBER(a26_rom_jvp_device::write_bank) +{ + switch (offset) + { + case 0x00: + case 0x20: + m_base_bank ^= 1; + break; + default: + //printf("%04X: write to unknown mapper address %02X\n", m_maincpu->pc(), 0xfa0 + offset); + break; + } +} + + +/*------------------------------------------------- + 4 in 1 Carts (Reset based): + the 4K bank changes at each reset + + GAMES: 4 in 1 carts + + -------------------------------------------------*/ + +READ8_MEMBER(a26_rom_4in1_device::read_rom) +{ + return m_rom[offset + (m_base_bank * 0x1000)]; +} + + +/*------------------------------------------------- + 8 in 1 Carts (Reset based): + the 8K banks change at each reset, and internally + each game runs as a F8-bankswitched cart + + GAMES: 8 in 1 cart + + -------------------------------------------------*/ + +READ8_MEMBER(a26_rom_8in1_device::read_rom) +{ + if (!space.debugger_access()) + { + switch (offset) + { + case 0x0ff8: + case 0x0ff9: + m_base_bank = offset - 0x0ff8; + break; + } + } + + return m_rom[offset + (m_base_bank * 0x1000) + (m_reset_bank * 0x2000)]; +} + + +/*------------------------------------------------- + 32 in 1 Carts (Reset based): + the 2K banks change at each reset + + GAMES: 32 in 1 cart + + -------------------------------------------------*/ + +READ8_MEMBER(a26_rom_32in1_device::read_rom) +{ + return m_rom[(offset & 0x7ff) + (m_base_bank * 0x800)]; +} diff --git a/src/devices/bus/vcs/rom.h b/src/devices/bus/vcs/rom.h new file mode 100755 index 00000000000..2d7b73586be --- /dev/null +++ b/src/devices/bus/vcs/rom.h @@ -0,0 +1,391 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __VCS_ROM_H +#define __VCS_ROM_H + +#include "vcs_slot.h" + + +// ======================> a26_rom_2k_device + +class a26_rom_2k_device : public device_t, + public device_vcs_cart_interface +{ +public: + // construction/destruction + a26_rom_2k_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + a26_rom_2k_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_rom); +}; + + +// ======================> a26_rom_4k_device + +class a26_rom_4k_device : public a26_rom_2k_device +{ +public: + // construction/destruction + a26_rom_4k_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // reading and writing + + // accesses just use the 2K ones, since it is just direct access to ROM/RAM + // masked with its size! +}; + + +// ======================> a26_rom_f6_device + +class a26_rom_f6_device : public a26_rom_2k_device +{ +public: + // construction/destruction + a26_rom_f6_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + a26_rom_f6_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_rom); + virtual DECLARE_WRITE8_MEMBER(write_bank); + virtual DECLARE_DIRECT_UPDATE_MEMBER(cart_opbase); + +protected: + int m_base_bank; +}; + + +// ======================> a26_rom_f4_device + +class a26_rom_f4_device : public a26_rom_f6_device +{ +public: + // construction/destruction + a26_rom_f4_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_reset(); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_rom); + virtual DECLARE_WRITE8_MEMBER(write_bank); +}; + + +// ======================> a26_rom_f8_device + +class a26_rom_f8_device : public a26_rom_f6_device +{ +public: + // construction/destruction + a26_rom_f8_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + a26_rom_f8_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_rom); + virtual DECLARE_WRITE8_MEMBER(write_bank); +}; + + +// ======================> a26_rom_f8_sw_device + +class a26_rom_f8_sw_device : public a26_rom_f8_device +{ +public: + // construction/destruction + a26_rom_f8_sw_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_reset(); +}; + + +// ======================> a26_rom_fa_device + +class a26_rom_fa_device : public a26_rom_f6_device +{ +public: + // construction/destruction + a26_rom_fa_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_rom); + virtual DECLARE_WRITE8_MEMBER(write_bank); +}; + + +// ======================> a26_rom_fe_device + +class a26_rom_fe_device : public a26_rom_2k_device +{ +public: + // construction/destruction + a26_rom_fe_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_rom); + virtual DECLARE_READ8_MEMBER(read_bank); + virtual DECLARE_WRITE8_MEMBER(write_ram); + virtual DECLARE_WRITE8_MEMBER(write_bank); + +protected: + int m_base_bank; + int m_trigger_on_next_access; +}; + + +// ======================> a26_rom_3e_device + +class a26_rom_3e_device : public a26_rom_f6_device +{ +public: + // construction/destruction + a26_rom_3e_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_rom); + virtual DECLARE_WRITE8_MEMBER(write_bank); + virtual DECLARE_WRITE8_MEMBER(write_ram); + +protected: + int m_num_bank; + int m_ram_bank; + int m_ram_enable; +}; + + +// ======================> a26_rom_3f_device + +class a26_rom_3f_device : public a26_rom_f6_device +{ +public: + // construction/destruction + a26_rom_3f_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_reset(); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_rom); + virtual DECLARE_WRITE8_MEMBER(write_bank); + +protected: + int m_num_bank; +}; + + +// ======================> a26_rom_e0_device + +class a26_rom_e0_device : public a26_rom_f6_device +{ +public: + // construction/destruction + a26_rom_e0_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_rom); + virtual DECLARE_WRITE8_MEMBER(write_bank); + +protected: + int m_base_banks[4]; +}; + + +// ======================> a26_rom_e7_device + +class a26_rom_e7_device : public a26_rom_f6_device +{ +public: + // construction/destruction + a26_rom_e7_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_rom); + virtual DECLARE_WRITE8_MEMBER(write_bank); + +protected: + int m_ram_bank; +}; + + +// ======================> a26_rom_ua_device + +class a26_rom_ua_device : public a26_rom_f6_device +{ +public: + // construction/destruction + a26_rom_ua_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_reset(); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_rom); + virtual DECLARE_READ8_MEMBER(read_bank); + virtual DECLARE_WRITE8_MEMBER(write_bank); +}; + + +// ======================> a26_rom_cv_device + +class a26_rom_cv_device : public a26_rom_2k_device +{ +public: + // construction/destruction + a26_rom_cv_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_rom); + virtual DECLARE_WRITE8_MEMBER(write_bank); +}; + + +// ======================> a26_rom_dc_device + +class a26_rom_dc_device : public a26_rom_f6_device +{ +public: + // construction/destruction + a26_rom_dc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_rom); + virtual DECLARE_WRITE8_MEMBER(write_bank); +}; + + +// ======================> a26_rom_fv_device + +class a26_rom_fv_device : public a26_rom_f6_device +{ +public: + // construction/destruction + a26_rom_fv_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_rom); + virtual DECLARE_WRITE8_MEMBER(write_bank); + +protected: + int m_locked; +}; + + +// ======================> a26_rom_jvp_device + +class a26_rom_jvp_device : public a26_rom_f6_device +{ +public: + // construction/destruction + a26_rom_jvp_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_rom); + virtual DECLARE_WRITE8_MEMBER(write_bank); +}; + + +// ======================> a26_rom_4in1_device + +class a26_rom_4in1_device : public a26_rom_f6_device +{ +public: + // construction/destruction + a26_rom_4in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_reset(); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_rom); +}; + + +// ======================> a26_rom_8in1_device + +class a26_rom_8in1_device : public a26_rom_f8_device +{ +public: + // construction/destruction + a26_rom_8in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_rom); + +protected: + int m_reset_bank; +}; + + +// ======================> a26_rom_32in1_device + +class a26_rom_32in1_device : public a26_rom_f6_device +{ +public: + // construction/destruction + a26_rom_32in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_reset(); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_rom); +}; + + +// device type definition +extern const device_type A26_ROM_2K; +extern const device_type A26_ROM_4K; +extern const device_type A26_ROM_F4; +extern const device_type A26_ROM_F6; +extern const device_type A26_ROM_F8; +extern const device_type A26_ROM_F8_SW; +extern const device_type A26_ROM_FA; +extern const device_type A26_ROM_FE; +extern const device_type A26_ROM_3E; +extern const device_type A26_ROM_3F; +extern const device_type A26_ROM_E0; +extern const device_type A26_ROM_E7; +extern const device_type A26_ROM_UA; +extern const device_type A26_ROM_CV; +extern const device_type A26_ROM_DC; +extern const device_type A26_ROM_FV; +extern const device_type A26_ROM_JVP; +extern const device_type A26_ROM_4IN1; +extern const device_type A26_ROM_8IN1; +extern const device_type A26_ROM_32IN1; + + +#endif diff --git a/src/devices/bus/vcs/scharger.c b/src/devices/bus/vcs/scharger.c new file mode 100644 index 00000000000..a3d90391ce9 --- /dev/null +++ b/src/devices/bus/vcs/scharger.c @@ -0,0 +1,214 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*************************************************************************** + + Atari 2600 cart Starpath Supercharger (Cart + Tape drive!) + + + + From kevtris notes ( http://blog.kevtris.org/blogfiles/Atari%202600%20Mappers.txt ): + + + - Control register [0x1ff8] + + 7 0 + --------- + 1FF8: DDDB BBWE + + D: write delay (see below) + B: bankswitching mode (see below) + W: RAM write enable (1 = enabled, 0 = disabled) + E: ROM power enable (0 = enabled, 1 = turn off ROM) + + - Audio input register [0x1ff9] + + 7 0 + --------- + 1FF9: 0000 000A + + A: Supercharger audio data. 0 = low input, 1 = high input. + + +***************************************************************************/ + + +#include "emu.h" +#include "scharger.h" +#include "sound/wave.h" +#include "formats/a26_cas.h" + +const device_type A26_ROM_SUPERCHARGER = &device_creator; + + +a26_rom_ss_device::a26_rom_ss_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : a26_rom_f6_device(mconfig, A26_ROM_SUPERCHARGER, "Atari 2600 ROM Cart Supercharger", tag, owner, clock, "a2600_ss", __FILE__), + m_cassette(*this, "cassette") +{ +} + +//------------------------------------------------- +// mapper specific start/reset +//------------------------------------------------- + +void a26_rom_ss_device::device_start() +{ + m_maincpu = machine().device("maincpu"); + + save_item(NAME(m_base_banks)); + save_item(NAME(m_reg)); + save_item(NAME(m_write_delay)); + save_item(NAME(m_ram_write_enabled)); + save_item(NAME(m_rom_enabled)); + save_item(NAME(m_byte_started)); + save_item(NAME(m_last_address)); + save_item(NAME(m_diff_adjust)); +} + +void a26_rom_ss_device::device_reset() +{ + // banks = 0, 1, 2 are 2K chunk of RAM (of the available 6K), banks = 3 is ROM! + m_base_banks[0] = 2; + m_base_banks[1] = 3; + m_ram_write_enabled = 0; + m_byte_started = 0; + m_reg = 0; + m_write_delay = 0; + m_rom_enabled = 1; + m_last_address = 0; + m_diff_adjust = 0; +} + + +static MACHINE_CONFIG_FRAGMENT( a26_ss ) + MCFG_CASSETTE_ADD("cassette") + MCFG_CASSETTE_FORMATS(a26_cassette_formats) + MCFG_CASSETTE_DEFAULT_STATE(CASSETTE_STOPPED | CASSETTE_MOTOR_ENABLED | CASSETTE_SPEAKER_ENABLED) + MCFG_CASSETTE_INTERFACE("a2600_cass") + +// MCFG_SOUND_WAVE_ADD(WAVE_TAG, "cassette") +// MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.25) +MACHINE_CONFIG_END + +machine_config_constructor a26_rom_ss_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( a26_ss ); +} + +inline UINT8 a26_rom_ss_device::read_byte(UINT32 offset) +{ + if (offset < 0x800) + return m_ram[(offset & 0x7ff) + (m_base_banks[0] * 0x800)]; + else if (m_base_banks[1] != 3) + return m_ram[(offset & 0x7ff) + (m_base_banks[1] * 0x800)]; + else if (m_rom_enabled) + return m_rom[offset & 0x7ff]; + else + return 0xff; +} + +READ8_MEMBER(a26_rom_ss_device::read_rom) +{ + if (space.debugger_access()) + return read_byte(offset); + + // Bankswitch + if (offset == 0xff8) + { + //logerror("%04X: Access to control register data = %02X\n", m_maincpu->pc(), m_modeSS_byte); + m_write_delay = m_reg >> 5; + m_ram_write_enabled = BIT(m_reg, 1); + m_rom_enabled = !BIT(m_reg, 0); + + // compensate time spent in this access to avoid spurious RAM write + m_byte_started -= 5; + + // handle bankswitch + switch (m_reg & 0x1c) + { + case 0x00: + m_base_banks[0] = 2; + m_base_banks[1] = 3; + break; + case 0x04: + m_base_banks[0] = 0; + m_base_banks[1] = 3; + break; + case 0x08: + m_base_banks[0] = 2; + m_base_banks[1] = 0; + break; + case 0x0c: + m_base_banks[0] = 0; + m_base_banks[1] = 2; + break; + case 0x10: + m_base_banks[0] = 2; + m_base_banks[1] = 3; + break; + case 0x14: + m_base_banks[0] = 1; + m_base_banks[1] = 3; + break; + case 0x18: + m_base_banks[0] = 2; + m_base_banks[1] = 1; + break; + case 0x1c: + m_base_banks[0] = 1; + m_base_banks[1] = 2; + break; + } + + return read_byte(offset); + } + // Cassette port read + else if (offset == 0xff9) + { + //logerror("%04X: Cassette port read, tap_val = %f\n", m_maincpu->pc(), tap_val); + double tap_val = m_cassette->input(); + + // compensate time spent in this access to avoid spurious RAM write + m_byte_started -= 5; + + if (tap_val < 0) + return 0x00; + else + return 0x01; + } + // Possible RAM write + else + { + if (m_ram_write_enabled) + { + /* Check for dummy read from same address */ + if (m_last_address == offset) + m_diff_adjust++; + + int diff = m_maincpu->total_cycles() - m_byte_started; + //logerror("%04X: offset = %04X, %d\n", m_maincpu->pc(), offset, diff); + + if (diff - m_diff_adjust == 5) + { + //logerror("%04X: RAM write offset = %04X, data = %02X\n", m_maincpu->pc(), offset, m_modeSS_byte ); + if (offset < 0x800) + m_ram[(offset & 0x7ff) + (m_base_banks[0] * 0x800)] = m_reg; + else if (m_base_banks[1] != 3) + m_ram[(offset & 0x7ff) + (m_base_banks[1] * 0x800)] = m_reg; + } + else if (offset < 0x0100) + { + m_reg = offset; + m_byte_started = m_maincpu->total_cycles(); + m_diff_adjust = 0; + } + } + else if (offset < 0x0100) + { + m_reg = offset; + m_byte_started = m_maincpu->total_cycles(); + m_diff_adjust = 0; + } + m_last_address = offset; + return read_byte(offset); + } +} diff --git a/src/devices/bus/vcs/scharger.h b/src/devices/bus/vcs/scharger.h new file mode 100644 index 00000000000..d2f669b0bbd --- /dev/null +++ b/src/devices/bus/vcs/scharger.h @@ -0,0 +1,47 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __VCS_SCHARGER_H +#define __VCS_SCHARGER_H + +#include "rom.h" +#include "imagedev/cassette.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> a26_rom_ss_device + +class a26_rom_ss_device : public a26_rom_f6_device +{ +public: + // construction/destruction + a26_rom_ss_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual machine_config_constructor device_mconfig_additions() const; + virtual void device_reset(); + + required_device m_cassette; + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_rom); + +private: + cpu_device *m_maincpu; + inline UINT8 read_byte(UINT32 offset); + + int m_base_banks[2]; + UINT8 m_reg; + UINT8 m_write_delay, m_ram_write_enabled, m_rom_enabled; + UINT32 m_byte_started; + UINT16 m_last_address; + UINT32 m_diff_adjust; +}; + + +// device type definition +extern const device_type A26_ROM_SUPERCHARGER; + +#endif diff --git a/src/devices/bus/vcs/vcs_slot.c b/src/devices/bus/vcs/vcs_slot.c new file mode 100755 index 00000000000..d04f45a195e --- /dev/null +++ b/src/devices/bus/vcs/vcs_slot.c @@ -0,0 +1,853 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli,Cowering +/*********************************************************************************************************** + + + Atari VCS 2600 cart emulation + (through slot devices) + + Emulation of the cartslot for Atari 2600 + Several banking schemes have been used for larger roms, + and some carts contained RAM (so called "Special Chip") + + Mapper identification routines based on Cowering's code. + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "vcs_slot.h" + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type VCS_CART_SLOT = &device_creator; + + +//------------------------------------------------- +// device_vcs_cart_interface - constructor +//------------------------------------------------- + +device_vcs_cart_interface::device_vcs_cart_interface(const machine_config &mconfig, device_t &device) + : device_slot_card_interface(mconfig, device), + m_rom(NULL), + m_rom_size(0) +{ +} + + +//------------------------------------------------- +// ~device_vcs_cart_interface - destructor +//------------------------------------------------- + +device_vcs_cart_interface::~device_vcs_cart_interface() +{ +} + +//------------------------------------------------- +// rom_alloc - alloc the space for the cart +//------------------------------------------------- + +void device_vcs_cart_interface::rom_alloc(UINT32 size, const char *tag) +{ + if (m_rom == NULL) + { + m_rom = device().machine().memory().region_alloc(std::string(tag).append(A26SLOT_ROM_REGION_TAG).c_str(), size, 1, ENDIANNESS_LITTLE)->base(); + m_rom_size = size; + } +} + +//------------------------------------------------- +// ram_alloc - alloc the space for the on-cart RAM +//------------------------------------------------- + +void device_vcs_cart_interface::ram_alloc(UINT32 size) +{ + m_ram.resize(size); + device().save_item(NAME(m_ram)); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// vcs_cart_slot_device - constructor +//------------------------------------------------- +vcs_cart_slot_device::vcs_cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, VCS_CART_SLOT, "Atari VCS 2600 Cartridge Slot", tag, owner, clock, "vcs_cart_slot", __FILE__), + device_image_interface(mconfig, *this), + device_slot_interface(mconfig, *this) +{ +} + + +//------------------------------------------------- +// vcs_cart_slot_device - destructor +//------------------------------------------------- + +vcs_cart_slot_device::~vcs_cart_slot_device() +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void vcs_cart_slot_device::device_start() +{ + m_cart = dynamic_cast(get_card_device()); +} + +//------------------------------------------------- +// device_config_complete - perform any +// operations now that the configuration is +// complete +//------------------------------------------------- + +void vcs_cart_slot_device::device_config_complete() +{ + // set brief and instance name + update_names(); +} + + + +/*------------------------------------------------- + call load + -------------------------------------------------*/ + +//------------------------------------------------- +// VCS PCBs +//------------------------------------------------- + +struct vcs_slot +{ + int pcb_id; + const char *slot_option; +}; + +// Here, we take the feature attribute from .xml (i.e. the PCB name) and we assign a unique ID to it +static const vcs_slot slot_list[] = +{ + { A26_2K, "a26_2k" }, + { A26_4K, "a26_4k" }, + { A26_F4, "a26_f4" }, + { A26_F6, "a26_f6" }, + { A26_F8, "a26_f8" }, + { A26_F8SW, "a26_f8sw" }, + { A26_FA, "a26_fa" }, + { A26_FE, "a26_fe" }, + { A26_E0, "a26_e0" }, + { A26_E7, "a26_e7" }, + { A26_3E, "a26_3e" }, + { A26_3F, "a26_3f" }, + { A26_UA, "a26_ua" }, + { A26_CV, "a26_cv" }, + { A26_DC, "a26_dc" }, + { A26_FV, "a26_fv" }, + { A26_JVP, "a26_jvp" }, + { A26_CM, "a26_cm" }, + { A26_SS, "a26_ss" }, + { A26_DPC, "a26_dpc" }, + { A26_4IN1, "a26_4in1" }, + { A26_8IN1, "a26_8in1" }, + { A26_32IN1, "a26_32in1" }, +}; + +static int vcs_get_pcb_id(const char *slot) +{ + for (int i = 0; i < ARRAY_LENGTH(slot_list); i++) + { + if (!core_stricmp(slot_list[i].slot_option, slot)) + return slot_list[i].pcb_id; + } + + return 0; +} + +static const char *vcs_get_slot(int type) +{ + for (int i = 0; i < ARRAY_LENGTH(slot_list); i++) + { + if (slot_list[i].pcb_id == type) + return slot_list[i].slot_option; + } + + return "a26_4k"; +} + +bool vcs_cart_slot_device::call_load() +{ + if (m_cart) + { + UINT8 *ROM; + UINT32 len; + + if (software_entry() != NULL) + len = get_software_region_length("rom"); + else + len = length(); + + //printf("Size: 0x%X\n", len); + + // check that filesize is among the supported ones + switch (len) + { + case 0x00800: + case 0x01000: + case 0x02000: + case 0x028ff: + case 0x02900: + case 0x03000: + case 0x04000: + case 0x08000: + case 0x10000: + case 0x80000: + break; + + default: + seterror(IMAGE_ERROR_UNSUPPORTED, "Invalid rom file size" ); + return IMAGE_INIT_FAIL; + } + + m_cart->rom_alloc(len, tag()); + ROM = m_cart->get_rom_base(); + + if (software_entry() != NULL) + { + const char *pcb_name; + bool has_ram = get_software_region("ram") ? TRUE : FALSE; + memcpy(ROM, get_software_region("rom"), len); + + if ((pcb_name = get_feature("slot")) != NULL) + m_type = vcs_get_pcb_id(pcb_name); + else + { + // identify type based on size + switch (len) + { + case 0x800: + m_type = A26_2K; + break; + case 0x1000: + m_type = A26_4K; + break; + case 0x2000: + m_type = A26_F8; + break; + case 0x28ff: + case 0x2900: + m_type = A26_DPC; + break; + case 0x3000: + m_type = A26_FA; + break; + case 0x4000: + m_type = A26_F6; + break; + case 0x8000: + m_type = A26_F4; + break; + case 0x10000: + m_type = A26_32IN1; + break; + case 0x80000: + m_type = A26_3F; + break; + default: + m_type = A26_4K; + printf("Unrecognized cart type!\n"); + break; + } + } + + if (has_ram) + m_cart->ram_alloc(get_software_region_length("ram")); + } + else + { + fread(ROM, len); + m_type = identify_cart_type(ROM, len); + + // check for Special Chip (128bytes of RAM) + if (len == 0x2000 || len == 0x4000 || len == 0x8000) + if (detect_super_chip(ROM, len)) + { + m_cart->ram_alloc(0x80); + //printf("Super Chip detected!\n"); + } + // Super chip games: + // dig dig, crystal castles, millipede, stargate, defender ii, jr. Pac Man, + // desert falcon, dark chambers, super football, sprintmaster, fatal run, + // off the wall, shooting arcade, secret quest, radar lock, save mary, klax + + // add CBS RAM+ (256bytes of RAM) + if (m_type == A26_FA) + m_cart->ram_alloc(0x100); + // add M Network RAM + else if (m_type == A26_E7) + m_cart->ram_alloc(0x800); + // add Commavid RAM + else if (m_type == A26_CV) + m_cart->ram_alloc(0x400); + // add Starpath Superchager RAM + else if (m_type == A26_SS) + m_cart->ram_alloc(0x1800); + // add Boulder Dash RAM + else if (m_type == A26_3E) + m_cart->ram_alloc(0x8000); + } + + //printf("Type: %s\n", vcs_get_slot(m_type)); + + // pass a pointer to the now allocated ROM for the DPC chip + if (m_type == A26_DPC) + m_cart->setup_addon_ptr((UINT8 *)m_cart->get_rom_base() + 0x2000); + + return IMAGE_INIT_PASS; + } + + return IMAGE_INIT_PASS; +} + + +/*------------------------------------------------- + call_unload + -------------------------------------------------*/ + +void vcs_cart_slot_device::call_unload() +{ +} + + + +/*------------------------------------------------- + call softlist load + -------------------------------------------------*/ + +bool vcs_cart_slot_device::call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry) +{ + load_software_part_region(*this, swlist, swname, start_entry ); + return TRUE; +} + + +/*------------------------------------------------- + detection helper routines + -------------------------------------------------*/ + +int vcs_cart_slot_device::detect_modeDC(UINT8 *cart, UINT32 len) +{ + int numfound = 0; + // signature is also in 'video reflex'.. maybe figure out that controller port someday... + static const unsigned char signature[3] = { 0x8d, 0xf0, 0xff }; + + if (len == 0x10000) + { + for (int i = 0; i < len - sizeof signature; i++) + { + if (!memcmp(&cart[i], signature, sizeof signature)) + { + numfound = 1; + } + } + } + if (numfound) + return 1; + return 0; +} + +int vcs_cart_slot_device::detect_modeF6(UINT8 *cart, UINT32 len) +{ + int numfound = 0; + static const unsigned char signature[3] = { 0x8d, 0xf6, 0xff }; + + if (len == 0x4000) + { + for (int i = 0; i < len - sizeof signature; i++) + { + if (!memcmp(&cart[i], signature, sizeof signature)) + { + numfound = 1; + } + } + } + if (numfound) + return 1; + return 0; +} + +int vcs_cart_slot_device::detect_snowhite(UINT8 *cart, UINT32 len) +{ + static const unsigned char snowwhite[] = { 0x10, 0xd0, 0xff, 0xff }; // Snow White Proto + + if (len == 0x2000 && !memcmp(&cart[0x1ffc], snowwhite, sizeof(snowwhite))) + return 1; + return 0; +} + +int vcs_cart_slot_device::detect_mode3E(UINT8 *cart, UINT32 len) +{ + // this one is a little hacky... looks for STY $3e, which is unique to + // 'not boulderdash', but is the only example I have (cow) + // Would have used STA $3e, but 'Alien' and 'Star Raiders' do that for unknown reasons + int numfound = 0; + static const unsigned char signature[3] = { 0x84, 0x3e, 0x9d }; + + if (len == 0x0800 || len == 0x1000) + { + for (int i = 0; i < len - sizeof signature; i++) + { + if (!memcmp(&cart[i], signature, sizeof signature)) + { + numfound = 1; + } + } + } + if (numfound) + return 1; + return 0; +} + +int vcs_cart_slot_device::detect_modeSS(UINT8 *cart, UINT32 len) +{ + int numfound = 0; + static const unsigned char signature[5] = { 0xbd, 0xe5, 0xff, 0x95, 0x81 }; + + if (len == 0x0800 || len == 0x1000) + { + for (int i = 0; i < len - sizeof signature; i++) + { + if (!memcmp(&cart[i], signature, sizeof signature)) + { + numfound = 1; + } + } + } + if (numfound) + return 1; + return 0; +} + +int vcs_cart_slot_device::detect_modeFE(UINT8 *cart, UINT32 len) +{ + int numfound = 0; + static const unsigned char signatures[][5] = { + { 0x20, 0x00, 0xd0, 0xc6, 0xc5 }, + { 0x20, 0xc3, 0xf8, 0xa5, 0x82 }, + { 0xd0, 0xfb, 0x20, 0x73, 0xfe }, + { 0x20, 0x00, 0xf0, 0x84, 0xd6 } + }; + + if (len == 0x2000) + { + for (int i = 0; i < len - sizeof signatures[0]; i++) + { + for (int j = 0; j < (sizeof signatures/sizeof signatures[0]) && !numfound; j++) + { + if (!memcmp(&cart[i], &signatures[j], sizeof signatures[0])) + { + numfound = 1; + } + } + } + } + if (numfound) + return 1; + return 0; +} + +int vcs_cart_slot_device::detect_modeE0(UINT8 *cart, UINT32 len) +{ + int numfound = 0; + static const unsigned char signatures[][3] = { + { 0x8d, 0xe0, 0x1f }, + { 0x8d, 0xe0, 0x5f }, + { 0x8d, 0xe9, 0xff }, + { 0xad, 0xe9, 0xff }, + { 0xad, 0xed, 0xff }, + { 0xad, 0xf3, 0xbf } + }; + + if (len == 0x2000) + { + for (int i = 0; i < len - sizeof signatures[0]; i++) + { + for (int j = 0; j < (sizeof signatures/sizeof signatures[0]) && !numfound; j++) + { + if (!memcmp(&cart[i], &signatures[j], sizeof signatures[0])) + { + numfound = 1; + } + } + } + } + if (numfound) + return 1; + return 0; +} + +int vcs_cart_slot_device::detect_modeCV(UINT8 *cart, UINT32 len) +{ + int numfound = 0; + static const unsigned char signatures[][3] = { + { 0x9d, 0xff, 0xf3 }, + { 0x99, 0x00, 0xf4 } + }; + + if (len == 0x0800 || len == 0x1000) + { + for (int i = 0; i < len - sizeof signatures[0]; i++) + { + for (int j = 0; j < (sizeof signatures/sizeof signatures[0]) && !numfound; j++) + { + if (!memcmp(&cart[i], &signatures[j], sizeof signatures[0])) + { + numfound = 1; + } + } + } + } + if (numfound) + return 1; + return 0; +} + +int vcs_cart_slot_device::detect_modeFV(UINT8 *cart, UINT32 len) +{ + int numfound = 0; + static const unsigned char signatures[][3] = { { 0x2c, 0xd0, 0xff } }; + + if (len == 0x2000) + { + for (int i = 0; i < len - sizeof signatures[0]; i++) + { + for (int j = 0; j < (sizeof signatures/sizeof signatures[0]) && !numfound; j++) + { + if (!memcmp(&cart[i], &signatures[j], sizeof signatures[0])) + { + numfound = 1; + } + } + } + } + if (numfound) + return 1; + return 0; +} + +int vcs_cart_slot_device::detect_modeJVP(UINT8 *cart, UINT32 len) +{ + int numfound = 0; + static const unsigned char signatures[][4] = { + { 0x2c, 0xc0, 0xef, 0x60 }, + { 0x8d, 0xa0, 0x0f, 0xf0 } + }; + + if (len == 0x4000 || len == 0x2000) + { + for (int i = 0; i < len - sizeof signatures[0]; i++) + { + for (int j = 0; j < (sizeof signatures/sizeof signatures[0]) && !numfound; j++) + { + if (!memcmp(&cart[i], &signatures[j], sizeof signatures[0])) + { + numfound = 1; + } + } + } + } + if (numfound) + return 1; + return 0; +} + +int vcs_cart_slot_device::detect_modeE7(UINT8 *cart, UINT32 len) +{ + int numfound = 0; + static const unsigned char signatures[][3] = { + { 0xad, 0xe5, 0xff }, + { 0x8d, 0xe7, 0xff } + }; + + if (len == 0x2000 || len == 0x4000) + { + for (int i = 0; i < len - sizeof signatures[0]; i++) + { + for (int j = 0; j < (sizeof signatures/sizeof signatures[0]) && !numfound; j++) + { + if (!memcmp(&cart[i], &signatures[j], sizeof signatures[0])) + { + numfound = 1; + } + } + } + } + if (numfound) + return 1; + return 0; +} + +int vcs_cart_slot_device::detect_modeUA(UINT8 *cart, UINT32 len) +{ + int numfound = 0; + static const unsigned char signature[3] = { 0x8d, 0x40, 0x02 }; + + if (len == 0x2000) + { + for (int i = 0; i < len - sizeof signature; i++) + { + if (!memcmp(&cart[i], signature, sizeof signature)) + { + numfound = 1; + } + } + } + if (numfound) + return 1; + return 0; +} + +int vcs_cart_slot_device::detect_8K_mode3F(UINT8 *cart, UINT32 len) +{ + int numfound = 0; + static const unsigned char signature1[4] = { 0xa9, 0x01, 0x85, 0x3f }; + static const unsigned char signature2[4] = { 0xa9, 0x02, 0x85, 0x3f }; + // have to look for two signatures because 'not boulderdash' gives false positive otherwise + + if (len == 0x2000) + { + for (int i = 0; i < len - sizeof signature1; i++) + { + if (!memcmp(&cart[i], signature1, sizeof signature1)) + { + numfound |= 0x01; + } + if (!memcmp(&cart[i], signature2, sizeof signature2)) + { + numfound |= 0x02; + } + } + } + if (numfound == 0x03) + return 1; + return 0; +} + +int vcs_cart_slot_device::detect_32K_mode3F(UINT8 *cart, UINT32 len) +{ + int numfound = 0; + static const unsigned char signature[4] = { 0xa9, 0x0e, 0x85, 0x3f }; + + if (len >= 0x8000) + { + for (int i = 0; i < len - sizeof signature; i++) + { + if (!memcmp(&cart[i], signature, sizeof signature)) + { + numfound++; + } + } + } + if (numfound > 1) + return 1; + return 0; +} + +int vcs_cart_slot_device::detect_super_chip(UINT8 *cart, UINT32 len) +{ + static const unsigned char signatures[][5] = { + { 0xa2, 0x7f, 0x9d, 0x00, 0xf0 }, // dig dug + { 0xae, 0xf6, 0xff, 0x4c, 0x00 } // off the wall + }; + + if (len == 0x4000) + { + for (int i = 0; i < len - sizeof signatures[0]; i++) + { + for (int j = 0; j < (sizeof signatures/sizeof signatures[0]); j++) + { + if (!memcmp(&cart[i], &signatures[j], sizeof signatures[0])) + { + return 1; + } + } + } + } + for (int i = 0x1000; i < len; i += 0x1000) + { + if (memcmp(cart, cart + i, 0x100)) + { + return 0; + } + } + /* Check the reset vector does not point into the super chip RAM area */ + if ((((cart[0x0ffd] << 8) | cart[0x0ffc]) & 0x0fff) < 0x0100) + { + return 0; + } + return 1; +} + + +/*------------------------------------------------- + identify_cart_type - code to detect cart type from + fullpath + -------------------------------------------------*/ + +// 4in1 & 8in1 are not currently detected from fullpath... +int vcs_cart_slot_device::identify_cart_type(UINT8 *ROM, UINT32 len) +{ + int type = 0xff; + + // auto-detect bank mode + if (detect_modeDC(ROM, len)) + type = A26_DC; + else if (detect_mode3E(ROM, len)) + type = A26_3E; + else if (detect_modeFE(ROM, len)) + type = A26_FE; + else if (detect_modeSS(ROM, len)) + type = A26_SS; + else if (detect_modeE0(ROM, len)) + type = A26_E0; + else if (detect_modeCV(ROM, len)) + type = A26_CV; + else if (detect_modeFV(ROM, len)) + type = A26_FV; + else if (detect_modeJVP(ROM, len)) + type = A26_JVP; + else if (detect_modeUA(ROM, len)) + type = A26_UA; + else if (detect_8K_mode3F(ROM, len)) + type = A26_3F; + else if (detect_32K_mode3F(ROM, len)) + type = A26_3F; + else if (detect_modeE7(ROM, len)) + type = A26_E7; + else if (detect_snowhite(ROM, len)) + type = A26_F8SW; + + // otherwise, choose based on size + if (type == 0xff) + { + switch (len) + { + case 0x800: + type = A26_2K; + break; + case 0x1000: + type = A26_4K; + break; + case 0x2000: + type = A26_F8; + break; + case 0x28ff: + case 0x2900: + type = A26_DPC; + break; + case 0x3000: + type = A26_FA; + break; + case 0x4000: + type = A26_F6; + break; + case 0x8000: + type = A26_F4; + break; + case 0x10000: + type = A26_32IN1; + break; + case 0x80000: + type = A26_3F; + break; + default: + type = A26_4K; + printf("Unrecognized cart type!\n"); + break; + } + } + + return type; +} + +/*------------------------------------------------- + get default card software + -------------------------------------------------*/ + +void vcs_cart_slot_device::get_default_card_software(std::string &result) +{ + if (open_image_file(mconfig().options())) + { + const char *slot_string = "a26_4k"; + UINT32 len = core_fsize(m_file); + dynamic_buffer rom(len); + int type; + + core_fread(m_file, &rom[0], len); + + type = identify_cart_type(&rom[0], len); + slot_string = vcs_get_slot(type); + + clear(); + + result.assign(slot_string); + } + else + software_get_default_slot(result, "a26_4k"); +} + + +/*------------------------------------------------- + read + -------------------------------------------------*/ + +READ8_MEMBER(vcs_cart_slot_device::read_rom) +{ + if (m_cart) + return m_cart->read_rom(space, offset, mem_mask); + else + return 0xff; +} + +READ8_MEMBER(vcs_cart_slot_device::read_bank) +{ + if (m_cart) + return m_cart->read_bank(space, offset, mem_mask); + else + return 0xff; +} + + +/*------------------------------------------------- + write + -------------------------------------------------*/ + +WRITE8_MEMBER(vcs_cart_slot_device::write_bank) +{ + if (m_cart) + m_cart->write_bank(space, offset, data, mem_mask); +} + +WRITE8_MEMBER(vcs_cart_slot_device::write_ram) +{ + if (m_cart) + m_cart->write_ram(space, offset, data, mem_mask); +} + + +/*------------------------------------------------- + direct update + -------------------------------------------------*/ + +DIRECT_UPDATE_MEMBER(vcs_cart_slot_device::cart_opbase) +{ + if (m_cart) + return m_cart->cart_opbase(direct, address); + else + return address; +} diff --git a/src/devices/bus/vcs/vcs_slot.h b/src/devices/bus/vcs/vcs_slot.h new file mode 100755 index 00000000000..9b087988d80 --- /dev/null +++ b/src/devices/bus/vcs/vcs_slot.h @@ -0,0 +1,160 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __VCS_SLOT_H +#define __VCS_SLOT_H + + +/*************************************************************************** + TYPE DEFINITIONS + ***************************************************************************/ + + +/* PCB */ +enum +{ + A26_2K = 0, + A26_4K, + A26_F4, + A26_F6, + A26_F8, + A26_F8SW, + A26_FA, + A26_FE, + A26_3E, // to test + A26_3F, + A26_E0, + A26_E7, + A26_UA, + A26_DC, + A26_CV, + A26_FV, + A26_JVP, // to test + A26_32IN1, + A26_8IN1, + A26_4IN1, + A26_DPC, + A26_SS, + A26_CM +}; + + +// ======================> device_vcs_cart_interface + +class device_vcs_cart_interface : public device_slot_card_interface +{ +public: + // construction/destruction + device_vcs_cart_interface(const machine_config &mconfig, device_t &device); + virtual ~device_vcs_cart_interface(); + + // reading from ROM + virtual DECLARE_READ8_MEMBER(read_rom) { return 0xff; } + // writing to RAM chips (sometimes it is in a different range than write_bank!) + virtual DECLARE_WRITE8_MEMBER(write_ram) {} + + // read/write to bankswitch address + virtual DECLARE_READ8_MEMBER(read_bank) { return 0xff; } + virtual DECLARE_WRITE8_MEMBER(write_bank) {} + + // direct update handler + virtual DECLARE_DIRECT_UPDATE_MEMBER(cart_opbase) { return address; } + + virtual void setup_addon_ptr(UINT8 *ptr) {} + + void rom_alloc(UINT32 size, const char *tag); + void ram_alloc(UINT32 size); + UINT8* get_rom_base() { return m_rom; } + UINT8* get_ram_base() { return &m_ram[0]; } + UINT32 get_rom_size() { return m_rom_size; } + UINT32 get_ram_size() { return m_ram.size(); } + +protected: + // internal state + UINT8 *m_rom; + UINT32 m_rom_size; + dynamic_buffer m_ram; +}; + + +// ======================> vcs_cart_slot_device + +class vcs_cart_slot_device : public device_t, + public device_image_interface, + public device_slot_interface +{ +public: + // construction/destruction + vcs_cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual ~vcs_cart_slot_device(); + + // device-level overrides + virtual void device_start(); + virtual void device_config_complete(); + + // image-level overrides + virtual bool call_load(); + virtual void call_unload(); + virtual bool call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry); + + int get_cart_type() { return m_type; }; + int identify_cart_type(UINT8 *ROM, UINT32 len); + + virtual iodevice_t image_type() const { return IO_CARTSLOT; } + virtual bool is_readable() const { return 1; } + virtual bool is_writeable() const { return 0; } + virtual bool is_creatable() const { return 0; } + virtual bool must_be_loaded() const { return 1; } + virtual bool is_reset_on_load() const { return 1; } + virtual const option_guide *create_option_guide() const { return NULL; } + virtual const char *image_interface() const { return "a2600_cart"; } + virtual const char *file_extensions() const { return "bin,a26"; } + + // slot interface overrides + virtual void get_default_card_software(std::string &result); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_rom); + virtual DECLARE_READ8_MEMBER(read_bank); + virtual DECLARE_WRITE8_MEMBER(write_bank); + virtual DECLARE_WRITE8_MEMBER(write_ram); + virtual DECLARE_DIRECT_UPDATE_MEMBER(cart_opbase); + +private: + device_vcs_cart_interface* m_cart; + int m_type; + + int detect_snowhite(UINT8 *cart, UINT32 len); + int detect_modeDC(UINT8 *cart, UINT32 len); + int detect_modeF6(UINT8 *cart, UINT32 len); + int detect_mode3E(UINT8 *cart, UINT32 len); + int detect_modeSS(UINT8 *cart, UINT32 len); + int detect_modeFE(UINT8 *cart, UINT32 len); + int detect_modeE0(UINT8 *cart, UINT32 len); + int detect_modeCV(UINT8 *cart, UINT32 len); + int detect_modeFV(UINT8 *cart, UINT32 len); + int detect_modeJVP(UINT8 *cart, UINT32 len); + int detect_modeE7(UINT8 *cart, UINT32 len); + int detect_modeUA(UINT8 *cart, UINT32 len); + int detect_8K_mode3F(UINT8 *cart, UINT32 len); + int detect_32K_mode3F(UINT8 *cart, UINT32 len); + int detect_super_chip(UINT8 *cart, UINT32 len); +}; + + +// device type definition +extern const device_type VCS_CART_SLOT; + + +/*************************************************************************** + DEVICE CONFIGURATION MACROS + ***************************************************************************/ + +#define A26SLOT_ROM_REGION_TAG ":cart:rom" + + +#define MCFG_VCS_CARTRIDGE_ADD(_tag,_slot_intf,_def_slot) \ + MCFG_DEVICE_ADD(_tag, VCS_CART_SLOT, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) + + +#endif diff --git a/src/devices/bus/vcs_ctrl/ctrl.c b/src/devices/bus/vcs_ctrl/ctrl.c new file mode 100644 index 00000000000..07afbb93cb1 --- /dev/null +++ b/src/devices/bus/vcs_ctrl/ctrl.c @@ -0,0 +1,83 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Atari Video Computer System controller port emulation + +**********************************************************************/ + +#include "ctrl.h" + + + +//************************************************************************** +// DEVICE DEFINITION +//************************************************************************** + +const device_type VCS_CONTROL_PORT = &device_creator; + + + +//************************************************************************** +// CARD INTERFACE +//************************************************************************** + +//------------------------------------------------- +// device_vcs_control_port_interface - constructor +//------------------------------------------------- + +device_vcs_control_port_interface::device_vcs_control_port_interface(const machine_config &mconfig, device_t &device) : + device_slot_card_interface(mconfig, device) +{ + m_port = dynamic_cast(device.owner()); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// vcs_control_port_device - constructor +//------------------------------------------------- + +vcs_control_port_device::vcs_control_port_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, VCS_CONTROL_PORT, "Atari VCS control port", tag, owner, clock, "vcs_control_port", __FILE__), + device_slot_interface(mconfig, *this), + m_write_trigger(*this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void vcs_control_port_device::device_start() +{ + m_device = dynamic_cast(get_card_device()); + + m_write_trigger.resolve_safe(); +} + + +//------------------------------------------------- +// SLOT_INTERFACE( vcs_control_port_devices ) +//------------------------------------------------- + +#include "joybooster.h" +#include "joystick.h" +#include "keypad.h" +#include "lightpen.h" +#include "paddles.h" +#include "wheel.h" + +SLOT_INTERFACE_START( vcs_control_port_devices ) + SLOT_INTERFACE("joy", VCS_JOYSTICK) + SLOT_INTERFACE("pad", VCS_PADDLES) + SLOT_INTERFACE("lp", VCS_LIGHTPEN) + SLOT_INTERFACE("joybstr", VCS_JOYSTICK_BOOSTER) + SLOT_INTERFACE("wheel", VCS_WHEEL) + SLOT_INTERFACE("keypad", VCS_KEYPAD) +SLOT_INTERFACE_END diff --git a/src/devices/bus/vcs_ctrl/ctrl.h b/src/devices/bus/vcs_ctrl/ctrl.h new file mode 100644 index 00000000000..50f817a2a01 --- /dev/null +++ b/src/devices/bus/vcs_ctrl/ctrl.h @@ -0,0 +1,124 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Atari Video Computer System controller port emulation + +********************************************************************** + + +**********************************************************************/ + +#pragma once + +#ifndef __VCS_CONTROL_PORT__ +#define __VCS_CONTROL_PORT__ + +#include "emu.h" + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_VCS_CONTROL_PORT_ADD(_tag, _slot_intf, _def_slot) \ + MCFG_DEVICE_ADD(_tag, VCS_CONTROL_PORT, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) + + +#define MCFG_VCS_CONTROL_PORT_TRIGGER_CALLBACK(_write) \ + devcb = &vcs_control_port_device::set_trigger_wr_callback(*device, DEVCB_##_write); + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class vcs_control_port_device; + + +// ======================> device_vcs_control_port_interface + +class device_vcs_control_port_interface : public device_slot_card_interface +{ +public: + // construction/destruction + device_vcs_control_port_interface(const machine_config &mconfig, device_t &device); + virtual ~device_vcs_control_port_interface() { } + + virtual UINT8 vcs_joy_r() { return 0xff; }; + virtual UINT8 vcs_pot_x_r() { return 0xff; }; + virtual UINT8 vcs_pot_y_r() { return 0xff; }; + virtual void vcs_joy_w(UINT8 data) { }; + + virtual bool has_pot_x() { return false; } + virtual bool has_pot_y() { return false; } + +protected: + vcs_control_port_device *m_port; +}; + + +// ======================> vcs_control_port_device + +class vcs_control_port_device : public device_t, + public device_slot_interface +{ +public: + // construction/destruction + vcs_control_port_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual ~vcs_control_port_device() { } + + // static configuration helpers + template static devcb_base &set_trigger_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_trigger.set_callback(object); } + + // computer interface + + // Data returned by the joy_r methods: + // bit 0 - pin 1 - Up + // bit 1 - pin 2 - Down + // bit 2 - pin 3 - Left + // bit 3 - pin 4 - Right + // bit 4 - pin 5 - + // bit 5 - pin 6 - Button + // pin 7 - +5V + // pin 8 - GND + // bit 6 - pin 9 - + // + UINT8 joy_r() { UINT8 data = 0xff; if (exists()) data = m_device->vcs_joy_r(); return data; } + DECLARE_READ8_MEMBER( joy_r ) { return joy_r(); } + UINT8 pot_x_r() { UINT8 data = 0xff; if (exists()) data = m_device->vcs_pot_x_r(); return data; } + DECLARE_READ8_MEMBER( pot_x_r ) { return pot_x_r(); } + UINT8 pot_y_r() { UINT8 data = 0xff; if (exists()) data = m_device->vcs_pot_y_r(); return data; } + DECLARE_READ8_MEMBER( pot_y_r ) { return pot_y_r(); } + + void joy_w( UINT8 data ) { if ( exists() ) m_device->vcs_joy_w( data ); } + DECLARE_WRITE8_MEMBER( joy_w ); + + bool exists() { return m_device != NULL; } + bool has_pot_x() { return exists() && m_device->has_pot_x(); } + bool has_pot_y() { return exists() && m_device->has_pot_y(); } + + void trigger_w(int state) { m_write_trigger(state); } + +protected: + // device-level overrides + virtual void device_start(); + + device_vcs_control_port_interface *m_device; + +private: + devcb_write_line m_write_trigger; +}; + + +// device type definition +extern const device_type VCS_CONTROL_PORT; + +SLOT_INTERFACE_EXTERN( vcs_control_port_devices ); + + + +#endif diff --git a/src/devices/bus/vcs_ctrl/joybooster.c b/src/devices/bus/vcs_ctrl/joybooster.c new file mode 100644 index 00000000000..e1fbfec7c90 --- /dev/null +++ b/src/devices/bus/vcs_ctrl/joybooster.c @@ -0,0 +1,95 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Atari Video Computer System digital joystick emulation with + boostergrip adapter + +**********************************************************************/ + +#include "joybooster.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type VCS_JOYSTICK_BOOSTER = &device_creator; + + +static INPUT_PORTS_START( vcs_joystick_booster ) + PORT_START("JOY") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_8WAY // Pin 1 + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_8WAY // Pin 2 + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_8WAY // Pin 3 + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_8WAY // Pin 4 + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_BUTTON1 ) // Pin 6 + PORT_BIT( 0xd0, IP_ACTIVE_LOW, IPT_UNUSED ) + + // Pin 5 + PORT_START("POTX") + PORT_BIT(0xff, IP_ACTIVE_LOW, IPT_BUTTON2 ) + + // Pin 9 + PORT_START("POTY") + PORT_BIT(0xff, IP_ACTIVE_LOW, IPT_BUTTON3 ) +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor vcs_joystick_booster_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( vcs_joystick_booster ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// vcs_joystick_booster_device - constructor +//------------------------------------------------- + +vcs_joystick_booster_device::vcs_joystick_booster_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, VCS_JOYSTICK_BOOSTER, "Atari / CBM Digital joystick with Boostergrip", tag, owner, clock, "vcs_joystick_booster", __FILE__), + device_vcs_control_port_interface(mconfig, *this), + m_joy(*this, "JOY"), + m_potx(*this, "POTX"), + m_poty(*this, "POTY") +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void vcs_joystick_booster_device::device_start() +{ +} + + +//------------------------------------------------- +// vcs_joy_r - joystick read +//------------------------------------------------- + +UINT8 vcs_joystick_booster_device::vcs_joy_r() +{ + return m_joy->read(); +} + +UINT8 vcs_joystick_booster_device::vcs_pot_x_r() +{ + return m_potx->read(); +} + +UINT8 vcs_joystick_booster_device::vcs_pot_y_r() +{ + return m_poty->read(); +} diff --git a/src/devices/bus/vcs_ctrl/joybooster.h b/src/devices/bus/vcs_ctrl/joybooster.h new file mode 100644 index 00000000000..3b08f8b9577 --- /dev/null +++ b/src/devices/bus/vcs_ctrl/joybooster.h @@ -0,0 +1,59 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Atari Video Computer System digital joystick emulation with + boostergrip adapter + +**********************************************************************/ + +#pragma once + +#ifndef __VCS_JOYSTICKBOOSTER__ +#define __VCS_JOYSTICKBOOSTER__ + +#include "emu.h" +#include "ctrl.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> vcs_joystick_booster_device + +class vcs_joystick_booster_device : public device_t, + public device_vcs_control_port_interface +{ +public: + // construction/destruction + vcs_joystick_booster_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual ioport_constructor device_input_ports() const; + +protected: + // device-level overrides + virtual void device_start(); + + // device_vcs_control_port_interface overrides + virtual UINT8 vcs_joy_r(); + virtual UINT8 vcs_pot_x_r(); + virtual UINT8 vcs_pot_y_r(); + + virtual bool has_pot_x() { return true; } + virtual bool has_pot_y() { return true; } + +private: + required_ioport m_joy; + required_ioport m_potx; + required_ioport m_poty; +}; + + +// device type definition +extern const device_type VCS_JOYSTICK_BOOSTER; + + +#endif diff --git a/src/devices/bus/vcs_ctrl/joystick.c b/src/devices/bus/vcs_ctrl/joystick.c new file mode 100644 index 00000000000..f1539eabeef --- /dev/null +++ b/src/devices/bus/vcs_ctrl/joystick.c @@ -0,0 +1,74 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Atari Video Computer System digital joystick emulation + +**********************************************************************/ + +#include "joystick.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type VCS_JOYSTICK = &device_creator; + + +static INPUT_PORTS_START( vcs_joystick ) + PORT_START("JOY") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_8WAY + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_8WAY + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_8WAY + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_8WAY + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_BUTTON1 ) + PORT_BIT( 0xd0, IP_ACTIVE_LOW, IPT_UNUSED ) +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor vcs_joystick_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( vcs_joystick ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// vcs_joystick_device - constructor +//------------------------------------------------- + +vcs_joystick_device::vcs_joystick_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, VCS_JOYSTICK, "Atari / CBM Digital joystick", tag, owner, clock, "vcs_joystick", __FILE__), + device_vcs_control_port_interface(mconfig, *this), + m_joy(*this, "JOY") +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void vcs_joystick_device::device_start() +{ +} + + +//------------------------------------------------- +// vcs_joy_r - joystick read +//------------------------------------------------- + +UINT8 vcs_joystick_device::vcs_joy_r() +{ + return m_joy->read(); +} diff --git a/src/devices/bus/vcs_ctrl/joystick.h b/src/devices/bus/vcs_ctrl/joystick.h new file mode 100644 index 00000000000..9e4d6eebed5 --- /dev/null +++ b/src/devices/bus/vcs_ctrl/joystick.h @@ -0,0 +1,51 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Atari Video Computer System digital joystick emulation + +**********************************************************************/ + +#pragma once + +#ifndef __VCS_JOYSTICK__ +#define __VCS_JOYSTICK__ + +#include "emu.h" +#include "ctrl.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> vcs_joystick_device + +class vcs_joystick_device : public device_t, + public device_vcs_control_port_interface +{ +public: + // construction/destruction + vcs_joystick_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual ioport_constructor device_input_ports() const; + +protected: + // device-level overrides + virtual void device_start(); + + // device_vcs_control_port_interface overrides + virtual UINT8 vcs_joy_r(); + +private: + required_ioport m_joy; +}; + + +// device type definition +extern const device_type VCS_JOYSTICK; + + +#endif diff --git a/src/devices/bus/vcs_ctrl/keypad.c b/src/devices/bus/vcs_ctrl/keypad.c new file mode 100644 index 00000000000..0ef8b6b4db3 --- /dev/null +++ b/src/devices/bus/vcs_ctrl/keypad.c @@ -0,0 +1,139 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Atari Video Computer System keypad emulation + +**********************************************************************/ + +#include "keypad.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type VCS_KEYPAD = &device_creator; + + +static INPUT_PORTS_START( vcs_keypad ) + PORT_START("KEYPAD") + PORT_BIT( 0x0001, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("keypad 1") PORT_CODE(KEYCODE_7_PAD) + PORT_BIT( 0x0002, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("keypad 2") PORT_CODE(KEYCODE_8_PAD) + PORT_BIT( 0x0004, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("keypad 3") PORT_CODE(KEYCODE_9_PAD) + PORT_BIT( 0x0008, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("keypad 4") PORT_CODE(KEYCODE_4_PAD) + PORT_BIT( 0x0010, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("keypad 5") PORT_CODE(KEYCODE_5_PAD) + PORT_BIT( 0x0020, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("keypad 6") PORT_CODE(KEYCODE_6_PAD) + PORT_BIT( 0x0040, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("keypad 7") PORT_CODE(KEYCODE_1_PAD) + PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("keypad 8") PORT_CODE(KEYCODE_2_PAD) + PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("keypad 9") PORT_CODE(KEYCODE_3_PAD) + PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("keypad *") PORT_CODE(KEYCODE_0_PAD) + PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("keypad 0") PORT_CODE(KEYCODE_DEL_PAD) + PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("keypad #") PORT_CODE(KEYCODE_ENTER_PAD) +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor vcs_keypad_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( vcs_keypad ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// vcs_keypad_device - constructor +//------------------------------------------------- + +vcs_keypad_device::vcs_keypad_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, VCS_KEYPAD, "Atari / CBM Keypad", tag, owner, clock, "vcs_keypad", __FILE__), + device_vcs_control_port_interface(mconfig, *this), + m_keypad(*this, "KEYPAD") +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void vcs_keypad_device::device_start() +{ + m_column = 0; + save_item(NAME(m_column)); +} + + +//------------------------------------------------- +// vcs_joy_w - joystick write +//------------------------------------------------- + +UINT8 vcs_keypad_device::vcs_joy_r() +{ + for ( int i = 0; i < 4; i++ ) + { + if ( ! ( ( m_column >> i ) & 0x01 ) ) + { + if ( ( m_keypad->read() >> 3*i ) & 0x04 ) + { + return 0xff; + } + else + { + return 0; + } + } + } + return 0xff; +} + +void vcs_keypad_device::vcs_joy_w( UINT8 data ) +{ + m_column = data & 0x0F; +} + +UINT8 vcs_keypad_device::vcs_pot_x_r() +{ + for ( int i = 0; i < 4; i++ ) + { + if ( ! ( ( m_column >> i ) & 0x01 ) ) + { + if ( ( m_keypad->read() >> 3*i ) & 0x01 ) + { + return 0; + } + else + { + return 0xff; + } + } + } + return 0; +} + +UINT8 vcs_keypad_device::vcs_pot_y_r() +{ + for ( int i = 0; i < 4; i++ ) + { + if ( ! ( ( m_column >> i ) & 0x01 ) ) + { + if ( ( m_keypad->read() >> 3*i ) & 0x02 ) + { + return 0; + } + else + { + return 0xff; + } + } + } + return 0; +} diff --git a/src/devices/bus/vcs_ctrl/keypad.h b/src/devices/bus/vcs_ctrl/keypad.h new file mode 100644 index 00000000000..8c1cc25dbee --- /dev/null +++ b/src/devices/bus/vcs_ctrl/keypad.h @@ -0,0 +1,59 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Atari Video Computer System Keypad emulation + +**********************************************************************/ + +#pragma once + +#ifndef __VCS_KEYPAD__ +#define __VCS_KEYPAD__ + +#include "emu.h" +#include "ctrl.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> vcs_keypad_device + +class vcs_keypad_device : public device_t, + public device_vcs_control_port_interface +{ +public: + // construction/destruction + vcs_keypad_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual ioport_constructor device_input_ports() const; + +protected: + // device-level overrides + virtual void device_start(); + + // device_vcs_control_port_interface overrides + virtual UINT8 vcs_joy_r(); + virtual void vcs_joy_w( UINT8 data ); + virtual UINT8 vcs_pot_x_r(); + virtual UINT8 vcs_pot_y_r(); + + virtual bool has_pot_x() { return true; } + virtual bool has_pot_y() { return true; } + +private: + required_ioport m_keypad; + + UINT8 m_column; +}; + + +// device type definition +extern const device_type VCS_KEYPAD; + + +#endif diff --git a/src/devices/bus/vcs_ctrl/lightpen.c b/src/devices/bus/vcs_ctrl/lightpen.c new file mode 100644 index 00000000000..8531930b2a1 --- /dev/null +++ b/src/devices/bus/vcs_ctrl/lightpen.c @@ -0,0 +1,85 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Atari Video Computer System lightpen emulation + +**********************************************************************/ + +#include "lightpen.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type VCS_LIGHTPEN = &device_creator; + + +INPUT_CHANGED_MEMBER( vcs_lightpen_device::trigger ) +{ + // TODO trigger timer at correct screen position + m_port->trigger_w(newval); +} + + +static INPUT_PORTS_START( vcs_lightpen ) + PORT_START("JOY") + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_CHANGED_MEMBER(DEVICE_SELF, vcs_lightpen_device, trigger, 0) + PORT_BIT( 0xdf, IP_ACTIVE_LOW, IPT_UNUSED ) + + PORT_START("LIGHTX") + PORT_BIT( 0xff, 0x00, IPT_LIGHTGUN_X) PORT_CROSSHAIR(X, 1.0, 0.0, 0) PORT_SENSITIVITY(45) PORT_KEYDELTA(15) + + PORT_START("LIGHTY") + PORT_BIT( 0xff, 0x00, IPT_LIGHTGUN_Y) PORT_CROSSHAIR(Y, 1.0, 0.0, 0) PORT_SENSITIVITY(45) PORT_KEYDELTA(15) +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor vcs_lightpen_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( vcs_lightpen ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// vcs_lightpen_device - constructor +//------------------------------------------------- + +vcs_lightpen_device::vcs_lightpen_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, VCS_LIGHTPEN, "Atari / CBM Light Pen", tag, owner, clock, "vcs_lightpen", __FILE__), + device_vcs_control_port_interface(mconfig, *this), + m_joy(*this, "JOY"), + m_lightx(*this, "LIGHTX"), + m_lighty(*this, "LIGHTY") +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void vcs_lightpen_device::device_start() +{ +} + + +//------------------------------------------------- +// vcs_joy_r - lightpen read +//------------------------------------------------- + +UINT8 vcs_lightpen_device::vcs_joy_r() +{ + return m_joy->read(); +} diff --git a/src/devices/bus/vcs_ctrl/lightpen.h b/src/devices/bus/vcs_ctrl/lightpen.h new file mode 100644 index 00000000000..61849e789ad --- /dev/null +++ b/src/devices/bus/vcs_ctrl/lightpen.h @@ -0,0 +1,55 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Atari Video Computer System lightpen emulation + +**********************************************************************/ + +#pragma once + +#ifndef __VCS_LIGHTPEN__ +#define __VCS_LIGHTPEN__ + +#include "emu.h" +#include "ctrl.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> vcs_lightpen_device + +class vcs_lightpen_device : public device_t, + public device_vcs_control_port_interface +{ +public: + // construction/destruction + vcs_lightpen_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual ioport_constructor device_input_ports() const; + + DECLARE_INPUT_CHANGED_MEMBER( trigger ); + +protected: + // device-level overrides + virtual void device_start(); + + // device_vcs_control_port_interface overrides + virtual UINT8 vcs_joy_r(); + +private: + required_ioport m_joy; + required_ioport m_lightx; + required_ioport m_lighty; +}; + + +// device type definition +extern const device_type VCS_LIGHTPEN; + + +#endif diff --git a/src/devices/bus/vcs_ctrl/paddles.c b/src/devices/bus/vcs_ctrl/paddles.c new file mode 100644 index 00000000000..b8a4f4a6de5 --- /dev/null +++ b/src/devices/bus/vcs_ctrl/paddles.c @@ -0,0 +1,99 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Atari Video Computer System analog paddles emulation + +**********************************************************************/ + +#include "paddles.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type VCS_PADDLES = &device_creator; + + +static INPUT_PORTS_START( vcs_paddles ) + PORT_START("JOY") + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(1) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(2) + PORT_BIT( 0xf3, IP_ACTIVE_LOW, IPT_UNUSED ) + + PORT_START("POTX") + PORT_BIT( 0xff, 0x80, IPT_PADDLE) PORT_PLAYER(1) PORT_SENSITIVITY(30) PORT_KEYDELTA(20) PORT_MINMAX(0, 255) + + PORT_START("POTY") + PORT_BIT( 0xff, 0x80, IPT_PADDLE) PORT_PLAYER(2) PORT_SENSITIVITY(30) PORT_KEYDELTA(20) PORT_MINMAX(0, 255) +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor vcs_paddles_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( vcs_paddles ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// vcs_paddles_device - constructor +//------------------------------------------------- + +vcs_paddles_device::vcs_paddles_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, VCS_PADDLES, "Atari / CBM Digital paddles", tag, owner, clock, "vcs_paddles", __FILE__), + device_vcs_control_port_interface(mconfig, *this), + m_joy(*this, "JOY"), + m_potx(*this, "POTX"), + m_poty(*this, "POTY") +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void vcs_paddles_device::device_start() +{ +} + + +//------------------------------------------------- +// vcs_joy_r - joystick read +//------------------------------------------------- + +UINT8 vcs_paddles_device::vcs_joy_r() +{ + return m_joy->read(); +} + + +//------------------------------------------------- +// vcs_pot_x_r - potentiometer X read +//------------------------------------------------- + +UINT8 vcs_paddles_device::vcs_pot_x_r() +{ + return m_potx->read(); +} + + +//------------------------------------------------- +// vcs_pot_y_r - potentiometer Y read +//------------------------------------------------- + +UINT8 vcs_paddles_device::vcs_pot_y_r() +{ + return m_poty->read(); +} diff --git a/src/devices/bus/vcs_ctrl/paddles.h b/src/devices/bus/vcs_ctrl/paddles.h new file mode 100644 index 00000000000..90e8dc910ab --- /dev/null +++ b/src/devices/bus/vcs_ctrl/paddles.h @@ -0,0 +1,58 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Atari Video Computer System analog paddles emulation + +**********************************************************************/ + +#pragma once + +#ifndef __VCS_PADDLES__ +#define __VCS_PADDLES__ + +#include "emu.h" +#include "ctrl.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> vcs_paddles_device + +class vcs_paddles_device : public device_t, + public device_vcs_control_port_interface +{ +public: + // construction/destruction + vcs_paddles_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual ioport_constructor device_input_ports() const; + +protected: + // device-level overrides + virtual void device_start(); + + // device_vcs_control_port_interface overrides + virtual UINT8 vcs_joy_r(); + virtual UINT8 vcs_pot_x_r(); + virtual UINT8 vcs_pot_y_r(); + + virtual bool has_pot_x() { return true; } + virtual bool has_pot_y() { return true; } + +private: + required_ioport m_joy; + required_ioport m_potx; + required_ioport m_poty; +}; + + +// device type definition +extern const device_type VCS_PADDLES; + + +#endif diff --git a/src/devices/bus/vcs_ctrl/wheel.c b/src/devices/bus/vcs_ctrl/wheel.c new file mode 100644 index 00000000000..9d1f3009596 --- /dev/null +++ b/src/devices/bus/vcs_ctrl/wheel.c @@ -0,0 +1,76 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Atari Video Computer System Driving Wheel emulation + +**********************************************************************/ + +#include "wheel.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type VCS_WHEEL = &device_creator; + + +static INPUT_PORTS_START( vcs_wheel ) + PORT_START("JOY") + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_BUTTON1 ) // Pin 6 + PORT_BIT( 0xdc, IP_ACTIVE_LOW, IPT_UNUSED ) + + PORT_START("WHEEL") + PORT_BIT( 0xff, 0x00, IPT_TRACKBALL_X ) PORT_SENSITIVITY(40) PORT_KEYDELTA(5) +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor vcs_wheel_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( vcs_wheel ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// vcs_wheel_device - constructor +//------------------------------------------------- + +vcs_wheel_device::vcs_wheel_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, VCS_WHEEL, "Atari / CBM Driving Wheel", tag, owner, clock, "vcs_wheel", __FILE__), + device_vcs_control_port_interface(mconfig, *this), + m_joy(*this, "JOY"), + m_wheel(*this, "WHEEL") +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void vcs_wheel_device::device_start() +{ +} + + +//------------------------------------------------- +// vcs_joy_r - joystick read +//------------------------------------------------- + +UINT8 vcs_wheel_device::vcs_joy_r() +{ + static const UINT8 driving_lookup[4] = { 0x00, 0x02, 0x03, 0x01 }; + + return m_joy->read() | driving_lookup[ ( m_wheel->read() & 0x18 ) >> 3 ]; +} diff --git a/src/devices/bus/vcs_ctrl/wheel.h b/src/devices/bus/vcs_ctrl/wheel.h new file mode 100644 index 00000000000..5ae4fc8a9d7 --- /dev/null +++ b/src/devices/bus/vcs_ctrl/wheel.h @@ -0,0 +1,52 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Atari Video Computer System Driving Wheel emulation + +**********************************************************************/ + +#pragma once + +#ifndef __VCS_WHEEL__ +#define __VCS_WHEEL__ + +#include "emu.h" +#include "ctrl.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> vcs_wheel_device + +class vcs_wheel_device : public device_t, + public device_vcs_control_port_interface +{ +public: + // construction/destruction + vcs_wheel_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual ioport_constructor device_input_ports() const; + +protected: + // device-level overrides + virtual void device_start(); + + // device_vcs_control_port_interface overrides + virtual UINT8 vcs_joy_r(); + +private: + required_ioport m_joy; + required_ioport m_wheel; +}; + + +// device type definition +extern const device_type VCS_WHEEL; + + +#endif diff --git a/src/devices/bus/vectrex/rom.c b/src/devices/bus/vectrex/rom.c new file mode 100644 index 00000000000..866fd741f9a --- /dev/null +++ b/src/devices/bus/vectrex/rom.c @@ -0,0 +1,88 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + + GCE Vectrex cart emulation + + TODO: + - better understand how much SRAM is expected to be present by the homebrew using + this cart type and use a RAM array instead of the ROM region for writes + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "rom.h" + + +//------------------------------------------------- +// vectrex_rom_device - constructor +//------------------------------------------------- + +const device_type VECTREX_ROM_STD = &device_creator; +const device_type VECTREX_ROM_64K = &device_creator; +const device_type VECTREX_ROM_SRAM = &device_creator; + + +vectrex_rom_device::vectrex_rom_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_vectrex_cart_interface(mconfig, *this) +{ +} + +vectrex_rom_device::vectrex_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, VECTREX_ROM_STD, "Vectrex Standard Carts", tag, owner, clock, "vectrex_rom", __FILE__), + device_vectrex_cart_interface(mconfig, *this) +{ +} + +vectrex_rom64k_device::vectrex_rom64k_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : vectrex_rom_device(mconfig, VECTREX_ROM_64K, "Vectrex Carts w/ Bankswitch", tag, owner, clock, "vectrex_64k", __FILE__) +{ +} + +vectrex_sram_device::vectrex_sram_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : vectrex_rom_device(mconfig, VECTREX_ROM_SRAM, "Vectrex Carts w/ SRAM", tag, owner, clock, "vectrex_sram", __FILE__) +{ +} + + +void vectrex_rom64k_device::device_start() +{ + save_item(NAME(m_bank)); +} + +void vectrex_rom64k_device::device_reset() +{ + m_bank = 0; +} + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +READ8_MEMBER(vectrex_rom_device::read_rom) +{ + if (offset < m_rom_size) + return m_rom[offset]; + else + return 0xff; +} + + +READ8_MEMBER(vectrex_rom64k_device::read_rom) +{ + return m_rom[(offset + m_bank * 0x8000) & (m_rom_size - 1)]; +} + +WRITE8_MEMBER(vectrex_rom64k_device::write_bank) +{ + m_bank = data >> 6; +} + +WRITE8_MEMBER(vectrex_sram_device::write_ram) +{ + m_rom[offset & (m_rom_size - 1)] = data; +} diff --git a/src/devices/bus/vectrex/rom.h b/src/devices/bus/vectrex/rom.h new file mode 100644 index 00000000000..eac8ef812f3 --- /dev/null +++ b/src/devices/bus/vectrex/rom.h @@ -0,0 +1,67 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __VECTREX_ROM_H +#define __VECTREX_ROM_H + +#include "slot.h" + + +// ======================> vectrex_rom_device + +class vectrex_rom_device : public device_t, + public device_vectrex_cart_interface +{ +public: + // construction/destruction + vectrex_rom_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + vectrex_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start() {} + virtual void device_reset() {} + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_rom); +}; + +// ======================> vectrex_rom64k_device + +class vectrex_rom64k_device : public vectrex_rom_device +{ +public: + // construction/destruction + vectrex_rom64k_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_rom); + virtual DECLARE_WRITE8_MEMBER(write_bank); + +private: + int m_bank; +}; + +// ======================> vectrex_sram_device + +class vectrex_sram_device : public vectrex_rom_device +{ +public: + // construction/destruction + vectrex_sram_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // reading and writing + virtual DECLARE_WRITE8_MEMBER(write_ram); +}; + + + +// device type definition +extern const device_type VECTREX_ROM_STD; +extern const device_type VECTREX_ROM_64K; +extern const device_type VECTREX_ROM_SRAM; + + +#endif diff --git a/src/devices/bus/vectrex/slot.c b/src/devices/bus/vectrex/slot.c new file mode 100644 index 00000000000..932248c22ce --- /dev/null +++ b/src/devices/bus/vectrex/slot.c @@ -0,0 +1,278 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*********************************************************************************************************** + + GCE Vectrex cart emulation + (through slot devices) + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "slot.h" + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type VECTREX_CART_SLOT = &device_creator; + +//************************************************************************** +// Vectrex Cartridges Interface +//************************************************************************** + +//------------------------------------------------- +// device_vectrex_cart_interface - constructor +//------------------------------------------------- + +device_vectrex_cart_interface::device_vectrex_cart_interface(const machine_config &mconfig, device_t &device) + : device_slot_card_interface(mconfig, device), + m_rom(NULL), + m_rom_size(0) +{ +} + + +//------------------------------------------------- +// ~device_vectrex_cart_interface - destructor +//------------------------------------------------- + +device_vectrex_cart_interface::~device_vectrex_cart_interface() +{ +} + +//------------------------------------------------- +// rom_alloc - alloc the space for the cart +//------------------------------------------------- + +void device_vectrex_cart_interface::rom_alloc(UINT32 size, const char *tag) +{ + if (m_rom == NULL) + { + m_rom = device().machine().memory().region_alloc(std::string(tag).append(VECSLOT_ROM_REGION_TAG).c_str(), size, 1, ENDIANNESS_LITTLE)->base(); + m_rom_size = size; + } +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// vectrex_cart_slot_device - constructor +//------------------------------------------------- +vectrex_cart_slot_device::vectrex_cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, VECTREX_CART_SLOT, "GCE Vectrex Cartridge Slot", tag, owner, clock, "vectrex_cart_slot", __FILE__), + device_image_interface(mconfig, *this), + device_slot_interface(mconfig, *this), + m_type(VECTREX_STD), + m_vec3d(VEC3D_NONE) +{ +} + + +//------------------------------------------------- +// vectrex_cart_slot_device - destructor +//------------------------------------------------- + +vectrex_cart_slot_device::~vectrex_cart_slot_device() +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void vectrex_cart_slot_device::device_start() +{ + m_cart = dynamic_cast(get_card_device()); +} + +//------------------------------------------------- +// device_config_complete - perform any +// operations now that the configuration is +// complete +//------------------------------------------------- + +void vectrex_cart_slot_device::device_config_complete() +{ + // set brief and instance name + update_names(); +} + + +//------------------------------------------------- +// Vectrex PCB +//------------------------------------------------- + +struct vectrex_slot +{ + int pcb_id; + const char *slot_option; +}; + +// Here, we take the feature attribute from .xml (i.e. the PCB name) and we assign a unique ID to it +static const vectrex_slot slot_list[] = +{ + { VECTREX_STD, "vec_rom" }, + { VECTREX_64K, "vec_rom64k" }, + { VECTREX_SRAM, "vec_sram" } +}; + +#if 0 +static int vectrex_get_pcb_id(const char *slot) +{ + for (int i = 0; i < ARRAY_LENGTH(slot_list); i++) + { + if (!core_stricmp(slot_list[i].slot_option, slot)) + return slot_list[i].pcb_id; + } + + return 0; +} +#endif + +static const char *vectrex_get_slot(int type) +{ + for (int i = 0; i < ARRAY_LENGTH(slot_list); i++) + { + if (slot_list[i].pcb_id == type) + return slot_list[i].slot_option; + } + + return "vec_rom"; +} + +/*------------------------------------------------- + call load + -------------------------------------------------*/ + +bool vectrex_cart_slot_device::call_load() +{ + if (m_cart) + { + UINT32 size = (software_entry() == NULL) ? length() : get_software_region_length("rom"); + UINT8 *ROM; + + if (size > 0x10000) + { + seterror(IMAGE_ERROR_UNSPECIFIED, "Unsupported cartridge size"); + return IMAGE_INIT_FAIL; + } + + m_cart->rom_alloc((size < 0x1000) ? 0x1000 : size, tag()); + ROM = m_cart->get_rom_base(); + + if (software_entry() == NULL) + fread(ROM, size); + else + memcpy(ROM, get_software_region("rom"), size); + + // Verify the file is accepted by the Vectrex bios + if (memcmp(ROM, "g GCE", 5)) + { + seterror(IMAGE_ERROR_UNSPECIFIED, "Invalid image"); + return IMAGE_INIT_FAIL; + } + + // determine type + m_type = VECTREX_STD; + if (!memcmp(ROM + 0x06, "SRAM", 4)) + m_type = VECTREX_SRAM; + if (size > 0x8000) + m_type = VECTREX_64K; + + //printf("Type: %s\n", vectrex_get_slot(m_type)); + + // determine 3D setup (to help video setup at machine_start) + if (!memcmp(ROM + 0x11, "NARROW", 6) && (ROM[0x39] == 0x0c)) + m_vec3d = VEC3D_NARROW; + + if (!memcmp(ROM + 0x11, "CRAZY COASTER", 13)) + m_vec3d = VEC3D_CCOAST; + + if (!memcmp(ROM + 0x11, "3D MINE STORM", 13)) + m_vec3d = VEC3D_MINEST; + + return IMAGE_INIT_PASS; + } + + return IMAGE_INIT_PASS; +} + + +/*------------------------------------------------- + call softlist load + -------------------------------------------------*/ + +bool vectrex_cart_slot_device::call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry) +{ + load_software_part_region(*this, swlist, swname, start_entry); + return TRUE; +} + + +/*------------------------------------------------- + get default card software + -------------------------------------------------*/ + +void vectrex_cart_slot_device::get_default_card_software(std::string &result) +{ + if (open_image_file(mconfig().options())) + { + const char *slot_string = "vec_rom"; + UINT32 size = core_fsize(m_file); + dynamic_buffer rom(size); + int type = VECTREX_STD; + + core_fread(m_file, &rom[0], size); + + if (!memcmp(&rom[0x06], "SRAM", 4)) + type = VECTREX_SRAM; + if (size > 0x8000) + type = VECTREX_64K; + + slot_string = vectrex_get_slot(type); + + //printf("type: %s\n", slot_string); + clear(); + + result.assign(slot_string); + return; + } + + software_get_default_slot(result, "vec_rom"); +} + +/*------------------------------------------------- + read_rom + -------------------------------------------------*/ + +READ8_MEMBER(vectrex_cart_slot_device::read_rom) +{ + if (m_cart) + return m_cart->read_rom(space, offset); + else + return 0xff; +} + +/*------------------------------------------------- + write_ram + -------------------------------------------------*/ + +WRITE8_MEMBER(vectrex_cart_slot_device::write_ram) +{ + if (m_cart) + m_cart->write_ram(space, offset, data); +} + +/*------------------------------------------------- + write_bank + -------------------------------------------------*/ + +WRITE8_MEMBER(vectrex_cart_slot_device::write_bank) +{ + if (m_cart) + m_cart->write_bank(space, offset, data); +} diff --git a/src/devices/bus/vectrex/slot.h b/src/devices/bus/vectrex/slot.h new file mode 100644 index 00000000000..e2f5d3cdbe5 --- /dev/null +++ b/src/devices/bus/vectrex/slot.h @@ -0,0 +1,115 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +#ifndef __VECTREX_SLOT_H +#define __VECTREX_SLOT_H + +/*************************************************************************** + TYPE DEFINITIONS + ***************************************************************************/ + + +/* PCB */ +enum +{ + VECTREX_STD = 0, + VECTREX_64K, + VECTREX_SRAM +}; + +// 3D setup +enum +{ + VEC3D_NONE = 0, + VEC3D_MINEST, + VEC3D_CCOAST, + VEC3D_NARROW +}; + +// ======================> device_vectrex_cart_interface + +class device_vectrex_cart_interface : public device_slot_card_interface +{ +public: + // construction/destruction + device_vectrex_cart_interface(const machine_config &mconfig, device_t &device); + virtual ~device_vectrex_cart_interface(); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_rom) { return 0xff; } + virtual DECLARE_WRITE8_MEMBER(write_ram) {} + virtual DECLARE_WRITE8_MEMBER(write_bank) {} + + void rom_alloc(UINT32 size, const char *tag); + UINT8* get_rom_base() { return m_rom; } + UINT32 get_rom_size() { return m_rom_size; } + +protected: + // internal state + UINT8 *m_rom; + UINT32 m_rom_size; +}; + + +// ======================> vectrex_cart_slot_device + +class vectrex_cart_slot_device : public device_t, + public device_image_interface, + public device_slot_interface +{ +public: + // construction/destruction + vectrex_cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual ~vectrex_cart_slot_device(); + + // device-level overrides + virtual void device_start(); + virtual void device_config_complete(); + + // image-level overrides + virtual bool call_load(); + virtual void call_unload() {} + virtual bool call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry); + + int get_type() { return m_type; } + int get_vec3d() { return m_vec3d; } + + virtual iodevice_t image_type() const { return IO_CARTSLOT; } + virtual bool is_readable() const { return 1; } + virtual bool is_writeable() const { return 0; } + virtual bool is_creatable() const { return 0; } + virtual bool must_be_loaded() const { return 0; } + virtual bool is_reset_on_load() const { return 1; } + virtual const option_guide *create_option_guide() const { return NULL; } + virtual const char *image_interface() const { return "vectrex_cart"; } + virtual const char *file_extensions() const { return "bin,gam,vec"; } + + // slot interface overrides + virtual void get_default_card_software(std::string &result); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_rom); + virtual DECLARE_WRITE8_MEMBER(write_ram); + virtual DECLARE_WRITE8_MEMBER(write_bank); + +protected: + + int m_type, m_vec3d; + device_vectrex_cart_interface* m_cart; +}; + + + +// device type definition +extern const device_type VECTREX_CART_SLOT; + + +/*************************************************************************** + DEVICE CONFIGURATION MACROS + ***************************************************************************/ + +#define VECSLOT_ROM_REGION_TAG ":cart:rom" + +#define MCFG_VECTREX_CARTRIDGE_ADD(_tag,_slot_intf,_def_slot) \ + MCFG_DEVICE_ADD(_tag, VECTREX_CART_SLOT, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) +#endif diff --git a/src/devices/bus/vic10/exp.c b/src/devices/bus/vic10/exp.c new file mode 100644 index 00000000000..c6d7a43c6bb --- /dev/null +++ b/src/devices/bus/vic10/exp.c @@ -0,0 +1,243 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Commodore VIC-10 Expansion Port emulation + +**********************************************************************/ + +#include "emu.h" +#include "emuopts.h" +#include "exp.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type VIC10_EXPANSION_SLOT = &device_creator; + + + +//************************************************************************** +// DEVICE VIC10_EXPANSION CARD INTERFACE +//************************************************************************** + +//------------------------------------------------- +// device_vic10_expansion_card_interface - constructor +//------------------------------------------------- + +device_vic10_expansion_card_interface::device_vic10_expansion_card_interface(const machine_config &mconfig, device_t &device) + : device_slot_card_interface(mconfig,device), + m_lorom(*this, "lorom"), + m_exram(*this, "exram"), + m_uprom(*this, "uprom") +{ + m_slot = dynamic_cast(device.owner()); +} + + +//------------------------------------------------- +// ~device_vic10_expansion_card_interface - destructor +//------------------------------------------------- + +device_vic10_expansion_card_interface::~device_vic10_expansion_card_interface() +{ +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// vic10_expansion_slot_device - constructor +//------------------------------------------------- + +vic10_expansion_slot_device::vic10_expansion_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, VIC10_EXPANSION_SLOT, "VIC-10 expansion port", tag, owner, clock, "vic10_expansion_slot", __FILE__), + device_slot_interface(mconfig, *this), + device_image_interface(mconfig, *this), + m_write_irq(*this), + m_write_res(*this), + m_write_cnt(*this), + m_write_sp(*this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void vic10_expansion_slot_device::device_start() +{ + m_card = dynamic_cast(get_card_device()); + + // resolve callbacks + m_write_irq.resolve_safe(); + m_write_res.resolve_safe(); + m_write_cnt.resolve_safe(); + m_write_sp.resolve_safe(); + + // inherit bus clock + if (clock() == 0) + { + vic10_expansion_slot_device *root = machine().device(VIC10_EXPANSION_SLOT_TAG); + assert(root); + set_unscaled_clock(root->clock()); + } +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void vic10_expansion_slot_device::device_reset() +{ + if (get_card_device()) + { + get_card_device()->reset(); + } +} + + +//------------------------------------------------- +// call_load - +//------------------------------------------------- + +bool vic10_expansion_slot_device::call_load() +{ + if (m_card) + { + size_t size = 0; + + if (software_entry() == NULL) + { + size = length(); + + if (!core_stricmp(filetype(), "80")) + { + fread(m_card->m_lorom, 0x2000); + + if (size == 0x4000) + { + fread(m_card->m_uprom, 0x2000); + } + } + else if (!core_stricmp(filetype(), "e0")) + { + fread(m_card->m_uprom, size); + } + else if (!core_stricmp(filetype(), "crt")) + { + size_t roml_size = 0; + size_t romh_size = 0; + int exrom = 1; + int game = 1; + + if (cbm_crt_read_header(m_file, &roml_size, &romh_size, &exrom, &game)) + { + UINT8 *roml = NULL; + UINT8 *romh = NULL; + + m_card->m_lorom.allocate(roml_size); + m_card->m_uprom.allocate(romh_size); + + if (roml_size) roml = m_card->m_lorom; + if (romh_size) romh = m_card->m_lorom; + + cbm_crt_read_data(m_file, roml, romh); + } + } + } + else + { + load_software_region("lorom", m_card->m_lorom); + load_software_region("exram", m_card->m_exram); + load_software_region("uprom", m_card->m_uprom); + } + } + + return IMAGE_INIT_PASS; +} + + +//------------------------------------------------- +// call_softlist_load - +//------------------------------------------------- + +bool vic10_expansion_slot_device::call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry) +{ + load_software_part_region(*this, swlist, swname, start_entry); + + return true; +} + + +//------------------------------------------------- +// get_default_card_software - +//------------------------------------------------- + +void vic10_expansion_slot_device::get_default_card_software(std::string &result) +{ + if (open_image_file(mconfig().options())) + { + if (!core_stricmp(filetype(), "crt")) + { + cbm_crt_get_card(result, m_file); + return; + } + + clear(); + } + + software_get_default_slot(result, "standard"); +} + + +//------------------------------------------------- +// cd_r - cartridge data read +//------------------------------------------------- + +UINT8 vic10_expansion_slot_device::cd_r(address_space &space, offs_t offset, UINT8 data, int lorom, int uprom, int exram) +{ + if (m_card != NULL) + { + data = m_card->vic10_cd_r(space, offset, data, lorom, uprom, exram); + } + + return data; +} + + +//------------------------------------------------- +// cd_w - cartridge data write +//------------------------------------------------- + +void vic10_expansion_slot_device::cd_w(address_space &space, offs_t offset, UINT8 data, int lorom, int uprom, int exram) +{ + if (m_card != NULL) + { + m_card->vic10_cd_w(space, offset, data, lorom, uprom, exram); + } +} + +READ_LINE_MEMBER( vic10_expansion_slot_device::p0_r ) { int state = 0; if (m_card != NULL) state = m_card->vic10_p0_r(); return state; } +WRITE_LINE_MEMBER( vic10_expansion_slot_device::p0_w ) { if (m_card != NULL) m_card->vic10_p0_w(state); } + + +//------------------------------------------------- +// SLOT_INTERFACE( vic10_expansion_cards ) +//------------------------------------------------- + +// slot devices +#include "std.h" + +SLOT_INTERFACE_START( vic10_expansion_cards ) + // the following need ROMs from the software list + SLOT_INTERFACE_INTERNAL("standard", VIC10_STD) +SLOT_INTERFACE_END diff --git a/src/devices/bus/vic10/exp.h b/src/devices/bus/vic10/exp.h new file mode 100644 index 00000000000..26e5f6c1e45 --- /dev/null +++ b/src/devices/bus/vic10/exp.h @@ -0,0 +1,184 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Commodore VIC-10 Expansion Port emulation + +********************************************************************** + + GND 1 A GND + +5V 2 B _UPROM + +5V 3 C _RESET + _IRQ 4 D _NMI + _CR/W 5 E Sphi2 + SP 6 F CA15 + _EXRAM 7 H CA14 + CNT 8 J CA13 + _CIA 9 K CA12 + _CIA PLA 10 L CA11 + _LOROM 11 M CA10 + BA 12 N CA9 + R/_W PLA 13 P CA8 + CD7 14 R CA7 + CD6 15 S CA6 + CD5 16 T CA5 + CD4 17 U CA4 + CD3 18 V CA3 + CD2 19 W CA2 + CD1 20 X CA1 + CD0 21 Y CA0 + P2 22 Z GND + +**********************************************************************/ + +#pragma once + +#ifndef __VIC10_EXPANSION_SLOT__ +#define __VIC10_EXPANSION_SLOT__ + +#include "emu.h" +#include "formats/cbm_crt.h" + + + +//************************************************************************** +// CONSTANTS +//************************************************************************** + +#define VIC10_EXPANSION_SLOT_TAG "exp" + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_VIC10_EXPANSION_SLOT_ADD(_tag, _clock, _slot_intf, _def_slot) \ + MCFG_DEVICE_ADD(_tag, VIC10_EXPANSION_SLOT, _clock) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) + + +#define MCFG_VIC10_EXPANSION_SLOT_IRQ_CALLBACK(_write) \ + devcb = &vic10_expansion_slot_device::set_irq_wr_callback(*device, DEVCB_##_write); + +#define MCFG_VIC10_EXPANSION_SLOT_RES_CALLBACK(_write) \ + devcb = &vic10_expansion_slot_device::set_res_wr_callback(*device, DEVCB_##_write); + +#define MCFG_VIC10_EXPANSION_SLOT_CNT_CALLBACK(_write) \ + devcb = &vic10_expansion_slot_device::set_cnt_wr_callback(*device, DEVCB_##_write); + +#define MCFG_VIC10_EXPANSION_SLOT_SP_CALLBACK(_write) \ + devcb = &vic10_expansion_slot_device::set_sp_wr_callback(*device, DEVCB_##_write); + + +#define MCFG_VIC10_EXPANSION_SLOT_IRQ_CALLBACKS(_irq, _res) \ + downcast(device)->set_irq_callbacks(DEVCB_##_irq, DEVCB_##_res); + +#define MCFG_VIC10_EXPANSION_SLOT_SERIAL_CALLBACKS(_cnt, _sp) \ + downcast(device)->set_serial_callbacks(DEVCB_##_cnt, DEVCB_##_sp); + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> vic10_expansion_slot_device + +class device_vic10_expansion_card_interface; + +class vic10_expansion_slot_device : public device_t, + public device_slot_interface, + public device_image_interface +{ +public: + // construction/destruction + vic10_expansion_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + template static devcb_base &set_irq_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_irq.set_callback(object); } + template static devcb_base &set_res_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_res.set_callback(object); } + template static devcb_base &set_cnt_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_cnt.set_callback(object); } + template static devcb_base &set_sp_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_sp.set_callback(object); } + + // computer interface + UINT8 cd_r(address_space &space, offs_t offset, UINT8 data, int lorom, int uprom, int exram); + void cd_w(address_space &space, offs_t offset, UINT8 data, int lorom, int uprom, int exram); + DECLARE_READ_LINE_MEMBER( p0_r ); + DECLARE_WRITE_LINE_MEMBER( p0_w ); + + // cartridge interface + DECLARE_WRITE_LINE_MEMBER( irq_w ) { m_write_irq(state); } + DECLARE_WRITE_LINE_MEMBER( res_w ) { m_write_res(state); } + DECLARE_WRITE_LINE_MEMBER( cnt_w ) { m_write_cnt(state); } + DECLARE_WRITE_LINE_MEMBER( sp_w ) { m_write_sp(state); } + +protected: + // device-level overrides + virtual void device_config_complete() { update_names(); } + virtual void device_start(); + virtual void device_reset(); + + // image-level overrides + virtual bool call_load(); + virtual bool call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry); + + virtual iodevice_t image_type() const { return IO_CARTSLOT; } + + virtual bool is_readable() const { return 1; } + virtual bool is_writeable() const { return 0; } + virtual bool is_creatable() const { return 0; } + virtual bool must_be_loaded() const { return 1; } + virtual bool is_reset_on_load() const { return 1; } + virtual const char *image_interface() const { return "vic10_cart"; } + virtual const char *file_extensions() const { return "80,e0"; } + virtual const option_guide *create_option_guide() const { return NULL; } + + // slot interface overrides + virtual void get_default_card_software(std::string &result); + + devcb_write_line m_write_irq; + devcb_write_line m_write_res; + devcb_write_line m_write_cnt; + devcb_write_line m_write_sp; + + device_vic10_expansion_card_interface *m_card; +}; + + +// ======================> device_vic10_expansion_card_interface + +// class representing interface-specific live vic10_expansion card +class device_vic10_expansion_card_interface : public device_slot_card_interface +{ + friend class vic10_expansion_slot_device; + +public: + // construction/destruction + device_vic10_expansion_card_interface(const machine_config &mconfig, device_t &device); + virtual ~device_vic10_expansion_card_interface(); + + virtual UINT8 vic10_cd_r(address_space &space, offs_t offset, UINT8 data, int lorom, int uprom, int exram) { return data; }; + virtual void vic10_cd_w(address_space &space, offs_t offset, UINT8 data, int lorom, int uprom, int exram) { }; + virtual int vic10_p0_r() { return 0; }; + virtual void vic10_p0_w(int state) { }; + virtual void vic10_sp_w(int state) { }; + virtual void vic10_cnt_w(int state) { }; + +protected: + optional_shared_ptr m_lorom; + optional_shared_ptr m_exram; + optional_shared_ptr m_uprom; + + vic10_expansion_slot_device *m_slot; +}; + + +// device type definition +extern const device_type VIC10_EXPANSION_SLOT; + + +SLOT_INTERFACE_EXTERN( vic10_expansion_cards ); + + + +#endif diff --git a/src/devices/bus/vic10/std.c b/src/devices/bus/vic10/std.c new file mode 100644 index 00000000000..a0cd1aa67cf --- /dev/null +++ b/src/devices/bus/vic10/std.c @@ -0,0 +1,78 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Commodore VIC-10 Standard 8K/16K ROM Cartridge emulation + +**********************************************************************/ + +#include "std.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type VIC10_STD = &device_creator; + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// vic10_standard_cartridge_device - constructor +//------------------------------------------------- + +vic10_standard_cartridge_device::vic10_standard_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, VIC10_STD, "VIC-10 Standard Cartridge", tag, owner, clock, "vic10_standard", __FILE__), + device_vic10_expansion_card_interface(mconfig, *this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void vic10_standard_cartridge_device::device_start() +{ +} + + +//------------------------------------------------- +// vic10_cd_r - cartridge data read +//------------------------------------------------- + +UINT8 vic10_standard_cartridge_device::vic10_cd_r(address_space &space, offs_t offset, UINT8 data, int lorom, int uprom, int exram) +{ + if (!lorom && m_lorom.bytes()) + { + data = m_lorom[offset & m_lorom.mask()]; + } + else if (!exram && m_exram.bytes()) + { + data = m_exram[offset & m_exram.mask()]; + } + else if (!uprom && m_uprom.bytes()) + { + data = m_uprom[offset & m_uprom.mask()]; + } + + return data; +} + + +//------------------------------------------------- +// vic10_cd_w - cartridge data write +//------------------------------------------------- + +void vic10_standard_cartridge_device::vic10_cd_w(address_space &space, offs_t offset, UINT8 data, int lorom, int uprom, int exram) +{ + if (!exram && m_exram.bytes()) + { + m_exram[offset & m_exram.mask()] = data; + } +} diff --git a/src/devices/bus/vic10/std.h b/src/devices/bus/vic10/std.h new file mode 100644 index 00000000000..cdbaef140de --- /dev/null +++ b/src/devices/bus/vic10/std.h @@ -0,0 +1,47 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Commodore VIC-10 Standard 8K/16K ROM Cartridge emulation + +**********************************************************************/ + +#pragma once + +#ifndef __VIC10_STD__ +#define __VIC10_STD__ + +#include "emu.h" +#include "exp.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> vic10_standard_cartridge_device + +class vic10_standard_cartridge_device : public device_t, + public device_vic10_expansion_card_interface +{ +public: + // construction/destruction + vic10_standard_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // device-level overrides + virtual void device_start(); + + // device_vic10_expansion_card_interface overrides + virtual UINT8 vic10_cd_r(address_space &space, offs_t offset, UINT8 data, int lorom, int uprom, int exram); + virtual void vic10_cd_w(address_space &space, offs_t offset, UINT8 data, int lorom, int uprom, int exram); +}; + + +// device type definition +extern const device_type VIC10_STD; + + + +#endif diff --git a/src/devices/bus/vic20/4cga.c b/src/devices/bus/vic20/4cga.c new file mode 100644 index 00000000000..67901823065 --- /dev/null +++ b/src/devices/bus/vic20/4cga.c @@ -0,0 +1,113 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/********************************************************************** + + Classical Games/Protovision 4 Player Interface emulation + + http://www.protovision-online.com/hardw/4_player.htm + http://hitmen.c02.at/html/hardware.html + +**********************************************************************/ + +#include "4cga.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type C64_4CGA = &device_creator; + + +static INPUT_PORTS_START( c64_4player ) + PORT_START("JOY3") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_8WAY PORT_PLAYER(1) PORT_WRITE_LINE_DEVICE_MEMBER(DEVICE_SELF, c64_4cga_device, write_joy3_0) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_8WAY PORT_PLAYER(1) PORT_WRITE_LINE_DEVICE_MEMBER(DEVICE_SELF, c64_4cga_device, write_joy3_1) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_8WAY PORT_PLAYER(1) PORT_WRITE_LINE_DEVICE_MEMBER(DEVICE_SELF, c64_4cga_device, write_joy3_2) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_8WAY PORT_PLAYER(1) PORT_WRITE_LINE_DEVICE_MEMBER(DEVICE_SELF, c64_4cga_device, write_joy3_3) + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(1) PORT_WRITE_LINE_DEVICE_MEMBER(DEVICE_SELF, device_pet_user_port_interface, output_h) + PORT_BIT( 0xe0, IP_ACTIVE_LOW, IPT_UNUSED ) + + PORT_START("JOY4") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_8WAY PORT_PLAYER(2) PORT_WRITE_LINE_DEVICE_MEMBER(DEVICE_SELF, c64_4cga_device, write_joy4_0) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_8WAY PORT_PLAYER(2) PORT_WRITE_LINE_DEVICE_MEMBER(DEVICE_SELF, c64_4cga_device, write_joy4_1) + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_8WAY PORT_PLAYER(2) PORT_WRITE_LINE_DEVICE_MEMBER(DEVICE_SELF, c64_4cga_device, write_joy4_2) + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_8WAY PORT_PLAYER(2) PORT_WRITE_LINE_DEVICE_MEMBER(DEVICE_SELF, c64_4cga_device, write_joy4_3) + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(2) PORT_WRITE_LINE_DEVICE_MEMBER(DEVICE_SELF, device_pet_user_port_interface, output_j) + PORT_BIT( 0xe0, IP_ACTIVE_LOW, IPT_UNUSED ) +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor c64_4cga_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( c64_4player ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// c64_4cga_device - constructor +//------------------------------------------------- + +c64_4cga_device::c64_4cga_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, C64_4CGA, "C64 Protovision 4 Player Interface", tag, owner, clock, "c64_4cga", __FILE__), + device_pet_user_port_interface(mconfig, *this), + m_port(0), + m_joy3(0xf), + m_joy4(0xf) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void c64_4cga_device::device_start() +{ + // state saving + save_item(NAME(m_port)); +} + +//------------------------------------------------- +// update_output +//------------------------------------------------- + +void c64_4cga_device::update_output() +{ + UINT8 data; + + if (m_port) + { + data = m_joy3; + } + else + { + data = m_joy4; + } + + output_c((data>>0)&1); + output_d((data>>1)&1); + output_e((data>>2)&1); + output_f((data>>3)&1); +} + + +//------------------------------------------------- +// c64_pb_w - port B write +//------------------------------------------------- + +WRITE_LINE_MEMBER( c64_4cga_device::input_l ) +{ + m_port = state; + update_output(); +} diff --git a/src/devices/bus/vic20/4cga.h b/src/devices/bus/vic20/4cga.h new file mode 100644 index 00000000000..b852c5e0958 --- /dev/null +++ b/src/devices/bus/vic20/4cga.h @@ -0,0 +1,66 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Classical Games/Protovision 4 Player Interface emulation + +**********************************************************************/ + +#pragma once + +#ifndef __C64_4CGA__ +#define __C64_4CGA__ + + +#include "emu.h" +#include "user.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> c64_4cga_device + +class c64_4cga_device : public device_t, + public device_pet_user_port_interface +{ +public: + // construction/destruction + c64_4cga_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual ioport_constructor device_input_ports() const; + + DECLARE_WRITE_LINE_MEMBER(write_joy3_0) { if (state) m_joy3 |= 1; else m_joy3 &= ~1; update_output(); } + DECLARE_WRITE_LINE_MEMBER(write_joy3_1) { if (state) m_joy3 |= 2; else m_joy3 &= ~2; update_output(); } + DECLARE_WRITE_LINE_MEMBER(write_joy3_2) { if (state) m_joy3 |= 4; else m_joy3 &= ~4; update_output(); } + DECLARE_WRITE_LINE_MEMBER(write_joy3_3) { if (state) m_joy3 |= 8; else m_joy3 &= ~8; update_output(); } + + DECLARE_WRITE_LINE_MEMBER(write_joy4_0) { if (state) m_joy4 |= 1; else m_joy4 &= ~1; update_output(); } + DECLARE_WRITE_LINE_MEMBER(write_joy4_1) { if (state) m_joy4 |= 2; else m_joy4 &= ~2; update_output(); } + DECLARE_WRITE_LINE_MEMBER(write_joy4_2) { if (state) m_joy4 |= 4; else m_joy4 &= ~4; update_output(); } + DECLARE_WRITE_LINE_MEMBER(write_joy4_3) { if (state) m_joy4 |= 8; else m_joy4 &= ~8; update_output(); } + +protected: + // device-level overrides + virtual void device_start(); + + // device_pet_user_port_interface overrides + virtual DECLARE_WRITE_LINE_MEMBER( input_l ); + +private: + void update_output(); + + int m_port; + UINT8 m_joy3; + UINT8 m_joy4; +}; + + +// device type definition +extern const device_type C64_4CGA; + + +#endif diff --git a/src/devices/bus/vic20/exp.c b/src/devices/bus/vic20/exp.c new file mode 100644 index 00000000000..bab88756ff5 --- /dev/null +++ b/src/devices/bus/vic20/exp.c @@ -0,0 +1,229 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Commodore VIC-20 Expansion Port emulation + +**********************************************************************/ + +#include "exp.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type VIC20_EXPANSION_SLOT = &device_creator; + + + +//************************************************************************** +// DEVICE VIC20_EXPANSION CARD INTERFACE +//************************************************************************** + +//------------------------------------------------- +// device_vic20_expansion_card_interface - constructor +//------------------------------------------------- + +device_vic20_expansion_card_interface::device_vic20_expansion_card_interface(const machine_config &mconfig, device_t &device) + : device_slot_card_interface(mconfig, device), + m_blk1(*this, "blk1"), + m_blk2(*this, "blk2"), + m_blk3(*this, "blk3"), + m_blk5(*this, "blk5"), + m_nvram(*this, "nvram") +{ + m_slot = dynamic_cast(device.owner()); +} + + +//------------------------------------------------- +// ~device_vic20_expansion_card_interface - destructor +//------------------------------------------------- + +device_vic20_expansion_card_interface::~device_vic20_expansion_card_interface() +{ +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// vic20_expansion_slot_device - constructor +//------------------------------------------------- + +vic20_expansion_slot_device::vic20_expansion_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, VIC20_EXPANSION_SLOT, "VIC-20 expansion port", tag, owner, clock, "vic20_expansion_slot", __FILE__), + device_slot_interface(mconfig, *this), + device_image_interface(mconfig, *this), + m_write_irq(*this), + m_write_nmi(*this), + m_write_res(*this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void vic20_expansion_slot_device::device_start() +{ + m_card = dynamic_cast(get_card_device()); + + // resolve callbacks + m_write_irq.resolve_safe(); + m_write_nmi.resolve_safe(); + m_write_res.resolve_safe(); + + // inherit bus clock + if (clock() == 0) + { + vic20_expansion_slot_device *root = machine().device(VIC20_EXPANSION_SLOT_TAG); + assert(root); + set_unscaled_clock(root->clock()); + } +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void vic20_expansion_slot_device::device_reset() +{ + if (get_card_device()) + { + get_card_device()->reset(); + } +} + + +//------------------------------------------------- +// call_load - +//------------------------------------------------- + +bool vic20_expansion_slot_device::call_load() +{ + if (m_card) + { + if (software_entry() == NULL) + { + if (!core_stricmp(filetype(), "20")) fread(m_card->m_blk1, 0x2000); + else if (!core_stricmp(filetype(), "40")) fread(m_card->m_blk2, 0x2000); + else if (!core_stricmp(filetype(), "60")) fread(m_card->m_blk3, 0x2000); + else if (!core_stricmp(filetype(), "70")) fread(m_card->m_blk3, 0x2000, 0x1000); + else if (!core_stricmp(filetype(), "a0")) fread(m_card->m_blk5, 0x2000); + else if (!core_stricmp(filetype(), "b0")) fread(m_card->m_blk5, 0x2000, 0x1000); + else if (!core_stricmp(filetype(), "crt")) + { + // read the header + UINT8 header[2]; + fread(&header, 2); + UINT16 address = (header[1] << 8) | header[0]; + + switch (address) + { + case 0x2000: fread(m_card->m_blk1, 0x2000); break; + case 0x4000: fread(m_card->m_blk2, 0x2000); break; + case 0x6000: fread(m_card->m_blk3, 0x2000); break; + case 0x7000: fread(m_card->m_blk3, 0x2000, 0x1000); break; + case 0xa000: fread(m_card->m_blk5, 0x2000); break; + case 0xb000: fread(m_card->m_blk5, 0x2000, 0x1000); break; + default: return IMAGE_INIT_FAIL; + } + } + } + else + { + load_software_region("blk1", m_card->m_blk1); + load_software_region("blk2", m_card->m_blk2); + load_software_region("blk3", m_card->m_blk3); + load_software_region("blk5", m_card->m_blk5); + } + } + + return IMAGE_INIT_PASS; +} + + +//------------------------------------------------- +// call_softlist_load - +//------------------------------------------------- + +bool vic20_expansion_slot_device::call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry) +{ + load_software_part_region(*this, swlist, swname, start_entry); + + return true; +} + + +//------------------------------------------------- +// get_default_card_software - +//------------------------------------------------- + +void vic20_expansion_slot_device::get_default_card_software(std::string &result) +{ + software_get_default_slot(result, "standard"); +} + + +//------------------------------------------------- +// cd_r - cartridge data read +//------------------------------------------------- + +UINT8 vic20_expansion_slot_device::cd_r(address_space &space, offs_t offset, UINT8 data, int ram1, int ram2, int ram3, int blk1, int blk2, int blk3, int blk5, int io2, int io3) +{ + if (m_card != NULL) + { + data = m_card->vic20_cd_r(space, offset, data, ram1, ram2, ram3, blk1, blk2, blk3, blk5, io2, io3); + } + + return data; +} + + +//------------------------------------------------- +// cd_w - cartridge data write +//------------------------------------------------- + +void vic20_expansion_slot_device::cd_w(address_space &space, offs_t offset, UINT8 data, int ram1, int ram2, int ram3, int blk1, int blk2, int blk3, int blk5, int io2, int io3) +{ + if (m_card != NULL) + { + m_card->vic20_cd_w(space, offset, data, ram1, ram2, ram3, blk1, blk2, blk3, blk5, io2, io3); + } +} + + +//------------------------------------------------- +// SLOT_INTERFACE( vic20_expansion_cards ) +//------------------------------------------------- + +// slot devices +#include "fe3.h" +#include "megacart.h" +#include "std.h" +#include "vic1010.h" +#include "vic1110.h" +#include "vic1111.h" +#include "vic1112.h" +#include "vic1210.h" + +SLOT_INTERFACE_START( vic20_expansion_cards ) + SLOT_INTERFACE("exp", VIC1010) + SLOT_INTERFACE("3k", VIC1210) + SLOT_INTERFACE("8k", VIC1110) + SLOT_INTERFACE("16k", VIC1111) + SLOT_INTERFACE("fe3", VIC20_FE3) + + // the following need ROMs from the software list + SLOT_INTERFACE_INTERNAL("standard", VIC20_STD) + SLOT_INTERFACE_INTERNAL("ieee488", VIC1112) + SLOT_INTERFACE_INTERNAL("megacart", VIC20_MEGACART) +SLOT_INTERFACE_END diff --git a/src/devices/bus/vic20/exp.h b/src/devices/bus/vic20/exp.h new file mode 100644 index 00000000000..8dfd840fa22 --- /dev/null +++ b/src/devices/bus/vic20/exp.h @@ -0,0 +1,172 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Commodore VIC-20 Expansion Port emulation + +********************************************************************** + + GND 1 A GND + CD0 2 B CA0 + CD1 3 C CA1 + CD2 4 D CA2 + CD3 5 E CA3 + CD4 6 F CA4 + CD5 7 H CA5 + CD6 8 J CA6 + CD7 9 K CA7 + _BLK1 10 L CA8 + _BLK2 11 M CA9 + _BLK3 12 N CA10 + _BLK5 13 P CA11 + _RAM1 14 R CA12 + _RAM2 15 S CA13 + _RAM3 16 T _I/O2 + VR/_W 17 U _I/O3 + CR/_W 18 V Sphi2 + _IRQ 19 W _NMI + N.C. 20 X _RES + +5V 21 Y N.C. + GND 22 Z GND + +**********************************************************************/ + +#pragma once + +#ifndef __VIC20_EXPANSION_SLOT__ +#define __VIC20_EXPANSION_SLOT__ + +#include "emu.h" + + + +//************************************************************************** +// CONSTANTS +//************************************************************************** + +#define VIC20_EXPANSION_SLOT_TAG "exp" + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_VIC20_EXPANSION_SLOT_ADD(_tag, _clock, _slot_intf, _def_slot) \ + MCFG_DEVICE_ADD(_tag, VIC20_EXPANSION_SLOT, _clock) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) + +#define MCFG_VIC20_PASSTHRU_EXPANSION_SLOT_ADD(_tag) \ + MCFG_VIC20_EXPANSION_SLOT_ADD(_tag, 0, vic20_expansion_cards, NULL) \ + MCFG_VIC20_EXPANSION_SLOT_IRQ_CALLBACK(DEVWRITELINE(DEVICE_SELF_OWNER, vic20_expansion_slot_device, irq_w)) \ + MCFG_VIC20_EXPANSION_SLOT_NMI_CALLBACK(DEVWRITELINE(DEVICE_SELF_OWNER, vic20_expansion_slot_device, nmi_w)) \ + MCFG_VIC20_EXPANSION_SLOT_RES_CALLBACK(DEVWRITELINE(DEVICE_SELF_OWNER, vic20_expansion_slot_device, res_w)) + + +#define MCFG_VIC20_EXPANSION_SLOT_IRQ_CALLBACK(_write) \ + devcb = &vic20_expansion_slot_device::set_irq_wr_callback(*device, DEVCB_##_write); + +#define MCFG_VIC20_EXPANSION_SLOT_NMI_CALLBACK(_write) \ + devcb = &vic20_expansion_slot_device::set_nmi_wr_callback(*device, DEVCB_##_write); + +#define MCFG_VIC20_EXPANSION_SLOT_RES_CALLBACK(_write) \ + devcb = &vic20_expansion_slot_device::set_res_wr_callback(*device, DEVCB_##_write); + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> vic20_expansion_slot_device + +class device_vic20_expansion_card_interface; + +class vic20_expansion_slot_device : public device_t, + public device_slot_interface, + public device_image_interface +{ +public: + // construction/destruction + vic20_expansion_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + template static devcb_base &set_irq_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_irq.set_callback(object); } + template static devcb_base &set_nmi_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_nmi.set_callback(object); } + template static devcb_base &set_res_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_res.set_callback(object); } + + // computer interface + UINT8 cd_r(address_space &space, offs_t offset, UINT8 data, int ram1, int ram2, int ram3, int blk1, int blk2, int blk3, int blk5, int io2, int io3); + void cd_w(address_space &space, offs_t offset, UINT8 data, int ram1, int ram2, int ram3, int blk1, int blk2, int blk3, int blk5, int io2, int io3); + + // cartridge interface + DECLARE_WRITE_LINE_MEMBER( irq_w ) { m_write_irq(state); } + DECLARE_WRITE_LINE_MEMBER( nmi_w ) { m_write_nmi(state); } + DECLARE_WRITE_LINE_MEMBER( res_w ) { m_write_res(state); } + +protected: + // device-level overrides + virtual void device_config_complete() { update_names(); } + virtual void device_start(); + virtual void device_reset(); + + // image-level overrides + virtual bool call_load(); + virtual bool call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry); + + virtual iodevice_t image_type() const { return IO_CARTSLOT; } + + virtual bool is_readable() const { return 1; } + virtual bool is_writeable() const { return 0; } + virtual bool is_creatable() const { return 0; } + virtual bool must_be_loaded() const { return 0; } + virtual bool is_reset_on_load() const { return 1; } + virtual const char *image_interface() const { return "vic1001_cart"; } + virtual const char *file_extensions() const { return "20,40,60,70,a0,b0,crt"; } + virtual const option_guide *create_option_guide() const { return NULL; } + + // slot interface overrides + virtual void get_default_card_software(std::string &result); + + devcb_write_line m_write_irq; + devcb_write_line m_write_nmi; + devcb_write_line m_write_res; + + device_vic20_expansion_card_interface *m_card; +}; + + +// ======================> device_vic20_expansion_card_interface + +// class representing interface-specific live vic20_expansion card +class device_vic20_expansion_card_interface : public device_slot_card_interface +{ + friend class vic20_expansion_slot_device; + +public: + // construction/destruction + device_vic20_expansion_card_interface(const machine_config &mconfig, device_t &device); + virtual ~device_vic20_expansion_card_interface(); + + virtual UINT8 vic20_cd_r(address_space &space, offs_t offset, UINT8 data, int ram1, int ram2, int ram3, int blk1, int blk2, int blk3, int blk5, int io2, int io3) { return data; }; + virtual void vic20_cd_w(address_space &space, offs_t offset, UINT8 data, int ram1, int ram2, int ram3, int blk1, int blk2, int blk3, int blk5, int io2, int io3) { }; + +protected: + optional_shared_ptr m_blk1; + optional_shared_ptr m_blk2; + optional_shared_ptr m_blk3; + optional_shared_ptr m_blk5; + optional_shared_ptr m_nvram; + + vic20_expansion_slot_device *m_slot; +}; + + +// device type definition +extern const device_type VIC20_EXPANSION_SLOT; + + +SLOT_INTERFACE_EXTERN( vic20_expansion_cards ); + + + +#endif diff --git a/src/devices/bus/vic20/fe3.c b/src/devices/bus/vic20/fe3.c new file mode 100644 index 00000000000..6b9cc319cd4 --- /dev/null +++ b/src/devices/bus/vic20/fe3.c @@ -0,0 +1,638 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Final Expansion v3 cartridge emulation + +**********************************************************************/ + +/* + + TODO: + + - fe3diag register error#2 hp=5592 (same error in VICE) + - SD card + - RTC + +*/ + +#include "fe3.h" + + + +//************************************************************************** +// MACROS/CONSTANTS +//************************************************************************** + +#define AM29F040_TAG "ic1" +#define ATMEGA1284_TAG "ic5" +#define ATF1504AS_TAG "ic4" + +#define REG1_BANK \ + ((m_reg1 & 0x7f) << 15) + +#define LORAM_HIDDEN \ + (m_reg2 & REG2_BLK0) + +#define BLK1_HIDDEN \ + (m_reg2 & REG2_BLK1) + +#define BLK2_HIDDEN \ + (m_reg2 & REG2_BLK2) + +#define BLK3_HIDDEN \ + (m_reg2 & REG2_BLK3) + +#define BLK5_HIDDEN \ + (m_reg2 & REG2_BLK5) + +#define REGISTERS_HIDDEN \ + ((m_lockbit && ((m_reg1 & REG1_MODE_MASK) == REG1_START)) || (m_reg2 & REG2_IO3)) + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type VIC20_FE3 = &device_creator; + + +//------------------------------------------------- +// ROM( vic20_fe3 ) +//------------------------------------------------- + +ROM_START( vic20_fe3 ) + ROM_REGION( 0x80000, AM29F040_TAG, 0 ) + ROM_LOAD( "fe3r022d.ic1", 0x00000, 0x80000, CRC(f4ff4aee) SHA1(1a389120159dee09c0f03ecb8fcd51ea2a2d2306) ) + + ROM_REGION( 0x10b6, ATF1504AS_TAG, 0 ) + ROM_LOAD( "vc20final-v3-2.ic4", 0x000, 0x10b6, CRC(975b7197) SHA1(e64d69870b757a409abeb5f19e34866eef37ab18) ) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *vic20_final_expansion_3_t::device_rom_region() const +{ + return ROM_NAME( vic20_fe3 ); +} + + +//------------------------------------------------- +// MACHINE_DRIVER( vic20_fe3 ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( vic20_fe3 ) + MCFG_AMD_29F040_ADD(AM29F040_TAG) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor vic20_final_expansion_3_t::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( vic20_fe3 ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// vic20_final_expansion_3_t - constructor +//------------------------------------------------- + +vic20_final_expansion_3_t::vic20_final_expansion_3_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, VIC20_FE3, "Final Expansion v3", tag, owner, clock, "vic20_fe3", __FILE__), + device_vic20_expansion_card_interface(mconfig, *this), + m_flash_rom(*this, AM29F040_TAG), + m_ram(*this, "sram") +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void vic20_final_expansion_3_t::device_start() +{ + m_ram.allocate(0x80000); + + // state saving + save_item(NAME(m_reg1)); + save_item(NAME(m_reg2)); + save_item(NAME(m_lockbit)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void vic20_final_expansion_3_t::device_reset() +{ + m_reg1 = 0; + m_reg2 = 0; +} + + +//------------------------------------------------- +// vic20_cd_r - cartridge data read +//------------------------------------------------- + +UINT8 vic20_final_expansion_3_t::vic20_cd_r(address_space &space, offs_t offset, UINT8 data, int ram1, int ram2, int ram3, int blk1, int blk2, int blk3, int blk5, int io2, int io3) +{ + switch (m_reg1 & REG1_MODE_MASK) + { + case REG1_START: + // read from ROM + if (!blk5) + { + data = m_flash_rom->read(get_address(0, 3, offset)); + + m_lockbit = 1; + } + + // read from registers + if (!io3 && !REGISTERS_HIDDEN && BIT(offset, 1)) + { + data = read_register(BIT(offset, 0)); + } + break; + + case REG1_SUPER_ROM: + // read from RAM bank 0 + if ((!ram1 || !ram2 || !ram3) && !LORAM_HIDDEN) + { + data = m_ram[get_address(0, 0, offset)]; + } + + // read from ROM + if (!blk1 && !BLK1_HIDDEN) + { + data = m_flash_rom->read(get_address(REG1_BANK, 0, offset)); + } + if (!blk2 && !BLK2_HIDDEN) + { + data = m_flash_rom->read(get_address(REG1_BANK, 1, offset)); + } + if (!blk3 && !BLK3_HIDDEN) + { + data = m_flash_rom->read(get_address(REG1_BANK, 2, offset)); + } + if (!blk5 && !BLK5_HIDDEN) + { + data = m_flash_rom->read(get_address(REG1_BANK, 3, offset)); + } + + // read from registers + if (!io3 && !REGISTERS_HIDDEN && BIT(offset, 1)) + { + data = read_register(BIT(offset, 0)); + } + break; + + case REG1_RAM_1: + // read from RAM bank 0 + if ((!ram1 || !ram2 || !ram3) && !LORAM_HIDDEN) + { + data = m_ram[get_address(0, 0, offset)]; + } + + // read from RAM bank 1 + if (!blk1 && !BLK1_HIDDEN) + { + data = m_ram[get_address(1, 0, offset)]; + } + if (!blk2 && !BLK2_HIDDEN) + { + data = m_ram[get_address(1, 1, offset)]; + } + if (!blk3 && !BLK3_HIDDEN) + { + data = m_ram[get_address(1, 2, offset)]; + } + if (!blk5 && !BLK5_HIDDEN) + { + data = m_ram[get_address(1, 3, offset)]; + } + + // read from registers + if (!io3 && !REGISTERS_HIDDEN && BIT(offset, 1)) + { + data = read_register(BIT(offset, 0)); + } + break; + + case REG1_RAM_2: + // read from RAM bank 0 + if ((!ram1 || !ram2 || !ram3) && !LORAM_HIDDEN) + { + data = m_ram[get_address(0, 0, offset)]; + } + + // read from RAM bank 1 or 2 + if (!blk1 && !BLK1_HIDDEN) + { + data = m_ram[get_address((m_reg1 & REG1_BLK1) ? 2 : 1, 0, offset)]; + } + if (!blk2 && !BLK2_HIDDEN) + { + data = m_ram[get_address((m_reg1 & REG1_BLK2) ? 2 : 1, 1, offset)]; + } + if (!blk3 && !BLK3_HIDDEN) + { + data = m_ram[get_address((m_reg1 & REG1_BLK3) ? 2 : 1, 2, offset)]; + } + if (!blk5 && !BLK5_HIDDEN) + { + data = m_ram[get_address((m_reg1 & REG1_BLK5) ? 2 : 1, 3, offset)]; + } + + // read from registers + if (!io3 && !REGISTERS_HIDDEN && BIT(offset, 1)) + { + data = read_register(BIT(offset, 0)); + } + break; + + case REG1_SUPER_RAM: + // read from RAM bank 0 + if ((!ram1 || !ram2 || !ram3) && !LORAM_HIDDEN) + { + data = m_ram[get_address(0, 0, offset)]; + } + + // read from any RAM bank + if (!blk1 && !BLK1_HIDDEN) + { + data = m_ram[get_address(REG1_BANK, 0, offset)]; + } + if (!blk2 && !BLK2_HIDDEN) + { + data = m_ram[get_address(REG1_BANK, 1, offset)]; + } + if (!blk3 && !BLK3_HIDDEN) + { + data = m_ram[get_address(REG1_BANK, 2, offset)]; + } + if (!blk5 && !BLK5_HIDDEN) + { + data = m_ram[get_address(REG1_BANK, 3, offset)]; + } + + // read from registers + if (!io3 && !REGISTERS_HIDDEN && BIT(offset, 1)) + { + data = read_register(BIT(offset, 0)); + } + break; + + case REG1_RAM_ROM: + // read from RAM bank 0 + if ((!ram1 || !ram2 || !ram3) && !LORAM_HIDDEN) + { + data = m_ram[get_address(0, 0, offset)]; + } + + // read from ROM bank 0 or RAM bank 1 + if (!blk1 && !BLK1_HIDDEN) + { + data = (m_reg1 & REG1_BLK1) ? m_flash_rom->read(get_address(0, 0, offset)) : m_ram[get_address(1, 0, offset)]; + } + if (!blk2 && !BLK2_HIDDEN) + { + data = (m_reg1 & REG1_BLK2) ? m_flash_rom->read(get_address(0, 1, offset)) : m_ram[get_address(1, 1, offset)]; + } + if (!blk3 && !BLK3_HIDDEN) + { + data = (m_reg1 & REG1_BLK3) ? m_flash_rom->read(get_address(0, 2, offset)) : m_ram[get_address(1, 2, offset)]; + } + if (!blk5 && !BLK5_HIDDEN) + { + data = (m_reg1 & REG1_BLK5) ? m_flash_rom->read(get_address(0, 3, offset)) : m_ram[get_address(1, 3, offset)]; + } + + // read from registers + if (!io3 && !REGISTERS_HIDDEN && BIT(offset, 1)) + { + data = read_register(BIT(offset, 0)); + } + break; + + case REG1_FLASH: + // read from RAM bank 0 + if ((!ram1 || !ram2 || !ram3) && !LORAM_HIDDEN) + { + data = m_ram[get_address(0, 0, offset)]; + } + + // read from ROM + if (!blk1 && !BLK1_HIDDEN) + { + data = m_flash_rom->read(get_address(REG1_BANK, 0, offset)); + } + if (!blk2 && !BLK2_HIDDEN) + { + data = m_flash_rom->read(get_address(REG1_BANK, 1, offset)); + } + if (!blk3 && !BLK3_HIDDEN) + { + data = m_flash_rom->read(get_address(REG1_BANK, 2, offset)); + } + if (!blk5 && !BLK5_HIDDEN) + { + data = m_flash_rom->read(get_address(REG1_BANK, 3, offset)); + } + + // read from registers + if (!io3 && !REGISTERS_HIDDEN && BIT(offset, 1)) + { + data = read_register(BIT(offset, 0)); + } + break; + } + + return data; +} + + +//------------------------------------------------- +// vic20_cd_w - cartridge data write +//------------------------------------------------- + +void vic20_final_expansion_3_t::vic20_cd_w(address_space &space, offs_t offset, UINT8 data, int ram1, int ram2, int ram3, int blk1, int blk2, int blk3, int blk5, int io2, int io3) +{ + switch (m_reg1 & REG1_MODE_MASK) + { + case REG1_START: + // write to RAM bank 1 + if (!blk5) + { + m_ram[get_address(1, 3, offset)] = data; + + m_lockbit = 0; + } + + // write to registers + if (!io3 && !REGISTERS_HIDDEN && BIT(offset, 1)) + { + write_register(BIT(offset, 0), data); + } + break; + + case REG1_SUPER_ROM: + // write to RAM bank 0 + if ((!ram1 || !ram2 || !ram3) && !LORAM_HIDDEN) + { + m_ram[get_address(0, 0, offset)] = data; + } + + // write to RAM bank 1 + if (!blk1 && !BLK1_HIDDEN) + { + m_ram[get_address(1, 0, offset)] = data; + } + if (!blk2 && !BLK2_HIDDEN) + { + m_ram[get_address(1, 1, offset)] = data; + } + if (!blk3 && !BLK3_HIDDEN) + { + m_ram[get_address(1, 2, offset)] = data; + } + if (!blk5 && !BLK5_HIDDEN) + { + m_ram[get_address(1, 3, offset)] = data; + } + + // write to registers + if (!io3 && !REGISTERS_HIDDEN && BIT(offset, 1)) + { + write_register(BIT(offset, 0), data); + } + break; + + case REG1_RAM_1: + // write to RAM bank 0 + if ((!ram1 || !ram2 || !ram3) && !LORAM_HIDDEN && REG1_BLK0) + { + m_ram[get_address(0, 0, offset)] = data; + } + + // write to RAM bank 1 or 2 + if (!blk1 && !BLK1_HIDDEN) + { + m_ram[get_address((m_reg1 & REG1_BLK1) ? 2 : 1, 0, offset)] = data; + } + if (!blk2 && !BLK2_HIDDEN) + { + m_ram[get_address((m_reg1 & REG1_BLK2) ? 2 : 1, 1, offset)] = data; + } + if (!blk3 && !BLK3_HIDDEN) + { + m_ram[get_address((m_reg1 & REG1_BLK3) ? 2 : 1, 2, offset)] = data; + } + if (!blk5 && !BLK5_HIDDEN) + { + m_ram[get_address((m_reg1 & REG1_BLK5) ? 2 : 1, 3, offset)] = data; + } + + // write to registers + if (!io3 && !REGISTERS_HIDDEN && BIT(offset, 1)) + { + write_register(BIT(offset, 0), data); + } + break; + + case REG1_RAM_2: + // write to RAM bank 0 + if ((!ram1 || !ram2 || !ram3) && !LORAM_HIDDEN && REG1_BLK0) + { + m_ram[get_address(0, 0, offset)] = data; + } + + // write to RAM bank 1 + if (!blk1 && !BLK1_HIDDEN) + { + m_ram[get_address(1, 0, offset)] = data; + } + if (!blk2 && !BLK2_HIDDEN) + { + m_ram[get_address(1, 1, offset)] = data; + } + if (!blk3 && !BLK3_HIDDEN) + { + m_ram[get_address(1, 2, offset)] = data; + } + if (!blk5 && !BLK5_HIDDEN) + { + m_ram[get_address(1, 3, offset)] = data; + } + + // write to registers + if (!io3 && !REGISTERS_HIDDEN && BIT(offset, 1)) + { + write_register(BIT(offset, 0), data); + } + break; + + case REG1_SUPER_RAM: + // write to RAM bank 0 + if ((!ram1 || !ram2 || !ram3) && !LORAM_HIDDEN) + { + m_ram[get_address(0, 0, offset)] = data; + } + + // write whole RAM + if (!blk1 && !BLK1_HIDDEN) + { + m_ram[get_address(REG1_BANK, 0, offset)] = data; + } + if (!blk2 && !BLK2_HIDDEN) + { + m_ram[get_address(REG1_BANK, 1, offset)] = data; + } + if (!blk3 && !BLK3_HIDDEN) + { + m_ram[get_address(REG1_BANK, 2, offset)] = data; + } + if (!blk5 && !BLK5_HIDDEN) + { + m_ram[get_address(REG1_BANK, 3, offset)] = data; + } + + // write to registers + if (!io3 && !REGISTERS_HIDDEN && BIT(offset, 1)) + { + write_register(BIT(offset, 0), data); + } + break; + + case REG1_RAM_ROM: + // write to RAM bank 0 + if ((!ram1 || !ram2 || !ram3) && !LORAM_HIDDEN && REG1_BLK0) + { + m_ram[get_address(0, 0, offset)] = data; + } + + // write to RAM bank 1 or 2 + if (!blk1 && !BLK1_HIDDEN) + { + m_ram[get_address((m_reg1 & REG1_BLK1) ? 2 : 1, 0, offset)] = data; + } + if (!blk2 && !BLK2_HIDDEN) + { + m_ram[get_address((m_reg1 & REG1_BLK2) ? 2 : 1, 1, offset)] = data; + } + if (!blk3 && !BLK3_HIDDEN) + { + m_ram[get_address((m_reg1 & REG1_BLK3) ? 2 : 1, 2, offset)] = data; + } + if (!blk5 && !BLK5_HIDDEN) + { + m_ram[get_address((m_reg1 & REG1_BLK5) ? 2 : 1, 3, offset)] = data; + } + + // write to registers + if (!io3 && !REGISTERS_HIDDEN && BIT(offset, 1)) + { + write_register(BIT(offset, 0), data); + } + break; + + case REG1_FLASH: + // write to RAM bank 0 + if ((!ram1 || !ram2 || !ram3) && !LORAM_HIDDEN) + { + m_ram[get_address(0, 0, offset)] = data; + } + + // write to ROM + if (!blk1 && !BLK1_HIDDEN) + { + m_flash_rom->write(get_address(REG1_BANK, 0, offset), data); + } + if (!blk2 && !BLK2_HIDDEN) + { + m_flash_rom->write(get_address(REG1_BANK, 1, offset), data); + } + if (!blk3 && !BLK3_HIDDEN) + { + m_flash_rom->write(get_address(REG1_BANK, 2, offset), data); + } + if (!blk5 && !BLK5_HIDDEN) + { + m_flash_rom->write(get_address(REG1_BANK, 3, offset), data); + } + + // write to registers + if (!io3 && !REGISTERS_HIDDEN && BIT(offset, 1)) + { + write_register(BIT(offset, 0), data); + } + } +} + + +//------------------------------------------------- +// get_address - +//------------------------------------------------- + +offs_t vic20_final_expansion_3_t::get_address(int bank, int block, offs_t offset) +{ + block ^= (m_reg2 >> 5) & 0x03; + + return bank << 15 | block << 13 | offset; +} + + +//------------------------------------------------- +// read_register - +//------------------------------------------------- + +UINT8 vic20_final_expansion_3_t::read_register(offs_t offset) +{ + UINT8 data = 0; + + switch (offset) + { + case 0: + data = m_reg1; + break; + + case 1: + data = m_reg2; + break; + } + + return data; +} + + +//------------------------------------------------- +// write_register - +//------------------------------------------------- + +void vic20_final_expansion_3_t::write_register(offs_t offset, UINT8 data) +{ + switch (offset) + { + case 0: + m_reg1 = data; + break; + + case 1: + m_reg2 = data; + break; + } +} diff --git a/src/devices/bus/vic20/fe3.h b/src/devices/bus/vic20/fe3.h new file mode 100644 index 00000000000..f42ae0e2f94 --- /dev/null +++ b/src/devices/bus/vic20/fe3.h @@ -0,0 +1,94 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Final Expansion v3 cartridge emulation + +**********************************************************************/ + +#pragma once + +#ifndef __VIC20_FE3__ +#define __VIC20_FE3__ + +#include "emu.h" +#include "exp.h" +#include "machine/intelfsh.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> vic20_final_expansion_3_t + +class vic20_final_expansion_3_t : public device_t, + public device_vic20_expansion_card_interface +{ +public: + // construction/destruction + vic20_final_expansion_3_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_vic20_expansion_card_interface overrides + virtual UINT8 vic20_cd_r(address_space &space, offs_t offset, UINT8 data, int ram1, int ram2, int ram3, int blk1, int blk2, int blk3, int blk5, int io2, int io3); + virtual void vic20_cd_w(address_space &space, offs_t offset, UINT8 data, int ram1, int ram2, int ram3, int blk1, int blk2, int blk3, int blk5, int io2, int io3); + +private: + enum + { + REG1_BLK0 = 0x01, + REG1_BLK1 = 0x02, + REG1_BLK2 = 0x04, + REG1_BLK3 = 0x08, + REG1_BLK5 = 0x10, + REG1_START = 0x00, + REG1_SUPER_ROM = 0x40, + REG1_RAM_1 = 0x80, + REG1_RAM_2 = 0xc0, + REG1_SUPER_RAM = 0xa0, + REG1_RAM_ROM = 0x60, + REG1_FLASH = 0x20, + REG1_MODE_MASK = 0xe0 + }; + + enum + { + REG2_BLK0 = 0x01, + REG2_BLK1 = 0x02, + REG2_BLK2 = 0x04, + REG2_BLK3 = 0x08, + REG2_BLK5 = 0x10, + REG2_A13 = 0x20, + REG2_A14 = 0x40, + REG2_IO3 = 0x80 + }; + + offs_t get_address(int bank, int block, offs_t offset); + UINT8 read_register(offs_t offset); + void write_register(offs_t offset, UINT8 data); + + required_device m_flash_rom; + optional_shared_ptr m_ram; + + UINT8 m_reg1; + UINT8 m_reg2; + int m_lockbit; +}; + + +// device type definition +extern const device_type VIC20_FE3; + + + +#endif diff --git a/src/devices/bus/vic20/megacart.c b/src/devices/bus/vic20/megacart.c new file mode 100644 index 00000000000..e92e1dbbc55 --- /dev/null +++ b/src/devices/bus/vic20/megacart.c @@ -0,0 +1,130 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Mega-Cart cartridge emulation + +**********************************************************************/ + +#include "megacart.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type VIC20_MEGACART = &device_creator; + + +//------------------------------------------------- +// MACHINE_DRIVER( vic20_megacart ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( vic20_megacart ) + +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor vic20_megacart_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( vic20_megacart ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// vic20_megacart_device - constructor +//------------------------------------------------- + +vic20_megacart_device::vic20_megacart_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, VIC20_MEGACART, "Mega-Cart", tag, owner, clock, "megacart", __FILE__), + device_vic20_expansion_card_interface(mconfig, *this), + device_nvram_interface(mconfig, *this), + m_nvram_en(0) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void vic20_megacart_device::device_start() +{ + m_nvram.allocate(0x2000); + + // state saving + save_item(NAME(m_nvram_en)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void vic20_megacart_device::device_reset() +{ +} + + +//------------------------------------------------- +// vic20_cd_r - cartridge data read +//------------------------------------------------- + +UINT8 vic20_megacart_device::vic20_cd_r(address_space &space, offs_t offset, UINT8 data, int ram1, int ram2, int ram3, int blk1, int blk2, int blk3, int blk5, int io2, int io3) +{ + if (!ram1 || !ram2 || !ram3 || !io2 || !io3) + { + if (m_nvram_en) + { + data = m_nvram[offset & 0x1fff]; + } + } + else if (!blk1 || !blk2 || !blk3) + { + } + else if (!blk5) + { + } + + return data; +} + + +//------------------------------------------------- +// vic20_cd_w - cartridge data write +//------------------------------------------------- + +void vic20_megacart_device::vic20_cd_w(address_space &space, offs_t offset, UINT8 data, int ram1, int ram2, int ram3, int blk1, int blk2, int blk3, int blk5, int io2, int io3) +{ + if (!ram1 || !ram2 || !ram3 || !io2) + { + if (m_nvram_en) + { + m_nvram[offset & 0x1fff] = data; + } + } + else if (!blk1 || !blk2 || !blk3) + { + } + else if (!blk5) + { + } + else if (!io3) + { + if (m_nvram_en) + { + m_nvram[offset & 0x1fff] = data; + } + } +} diff --git a/src/devices/bus/vic20/megacart.h b/src/devices/bus/vic20/megacart.h new file mode 100644 index 00000000000..5e9f82b10bf --- /dev/null +++ b/src/devices/bus/vic20/megacart.h @@ -0,0 +1,60 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Mega-Cart cartridge emulation + +**********************************************************************/ + +#pragma once + +#ifndef __VIC20_MEGACART__ +#define __VIC20_MEGACART__ + +#include "emu.h" +#include "exp.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> vic20_megacart_device + +class vic20_megacart_device : public device_t, + public device_vic20_expansion_card_interface, + public device_nvram_interface +{ +public: + // construction/destruction + vic20_megacart_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_nvram_interface overrides + virtual void nvram_default() { } + virtual void nvram_read(emu_file &file) { file.read(m_nvram, m_nvram.bytes()); } + virtual void nvram_write(emu_file &file) { file.write(m_nvram, m_nvram.bytes()); } + + // device_vic20_expansion_card_interface overrides + virtual UINT8 vic20_cd_r(address_space &space, offs_t offset, UINT8 data, int ram1, int ram2, int ram3, int blk1, int blk2, int blk3, int blk5, int io2, int io3); + virtual void vic20_cd_w(address_space &space, offs_t offset, UINT8 data, int ram1, int ram2, int ram3, int blk1, int blk2, int blk3, int blk5, int io2, int io3); + +private: + int m_nvram_en; +}; + + +// device type definition +extern const device_type VIC20_MEGACART; + + + +#endif diff --git a/src/devices/bus/vic20/std.c b/src/devices/bus/vic20/std.c new file mode 100644 index 00000000000..4757470b093 --- /dev/null +++ b/src/devices/bus/vic20/std.c @@ -0,0 +1,69 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Commodore VIC-20 Standard 8K/16K ROM Cartridge emulation + +**********************************************************************/ + +#include "std.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type VIC20_STD = &device_creator; + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// vic20_standard_cartridge_device - constructor +//------------------------------------------------- + +vic20_standard_cartridge_device::vic20_standard_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, VIC20_STD, "VIC-20 Standard Cartridge", tag, owner, clock, "vic20_standard", __FILE__), + device_vic20_expansion_card_interface(mconfig, *this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void vic20_standard_cartridge_device::device_start() +{ +} + + +//------------------------------------------------- +// vic20_cd_r - cartridge data read +//------------------------------------------------- + +UINT8 vic20_standard_cartridge_device::vic20_cd_r(address_space &space, offs_t offset, UINT8 data, int ram1, int ram2, int ram3, int blk1, int blk2, int blk3, int blk5, int io2, int io3) +{ + if (!blk1 && (m_blk1 != NULL)) + { + data = m_blk1[offset]; + } + else if (!blk2 && (m_blk2 != NULL)) + { + data = m_blk2[offset]; + } + else if (!blk3 && (m_blk3 != NULL)) + { + data = m_blk3[offset]; + } + else if (!blk5 && (m_blk5 != NULL)) + { + data = m_blk5[offset]; + } + + return data; +} diff --git a/src/devices/bus/vic20/std.h b/src/devices/bus/vic20/std.h new file mode 100644 index 00000000000..e7a70d338e5 --- /dev/null +++ b/src/devices/bus/vic20/std.h @@ -0,0 +1,46 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Commodore VIC-20 Standard 8K/16K ROM Cartridge emulation + +**********************************************************************/ + +#pragma once + +#ifndef __VIC20_STD__ +#define __VIC20_STD__ + +#include "emu.h" +#include "exp.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> vic20_standard_cartridge_device + +class vic20_standard_cartridge_device : public device_t, + public device_vic20_expansion_card_interface +{ +public: + // construction/destruction + vic20_standard_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // device-level overrides + virtual void device_start(); + + // device_vic20_expansion_card_interface overrides + virtual UINT8 vic20_cd_r(address_space &space, offs_t offset, UINT8 data, int ram1, int ram2, int ram3, int blk1, int blk2, int blk3, int blk5, int io2, int io3); +}; + + +// device type definition +extern const device_type VIC20_STD; + + + +#endif diff --git a/src/devices/bus/vic20/user.c b/src/devices/bus/vic20/user.c new file mode 100644 index 00000000000..f810cddc46e --- /dev/null +++ b/src/devices/bus/vic20/user.c @@ -0,0 +1,22 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/********************************************************************** + + Commodore VIC-20 User Port emulation + +**********************************************************************/ + +#include "user.h" + +//------------------------------------------------- +// SLOT_INTERFACE( vic20_user_port_cards ) +//------------------------------------------------- + +// slot devices +#include "4cga.h" +#include "vic1011.h" + +SLOT_INTERFACE_START( vic20_user_port_cards ) + SLOT_INTERFACE("4cga", C64_4CGA) + SLOT_INTERFACE("rs232", VIC1011) +SLOT_INTERFACE_END diff --git a/src/devices/bus/vic20/user.h b/src/devices/bus/vic20/user.h new file mode 100644 index 00000000000..2273a744917 --- /dev/null +++ b/src/devices/bus/vic20/user.h @@ -0,0 +1,33 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/********************************************************************** + + Commodore VIC-20 User Port emulation + +********************************************************************** + + GND 1 A GND + +5V 2 B CB1 + /RESET 3 C PB0 + JOY0 4 D PB1 + JOY1 5 E PB2 + JOY2 6 F PB3 + LIGHT PEN 7 H PB4 + CASSETTE SWITCH 8 J PB5 + ATN 9 K PB6 + +9VAC 10 L PB7 + +9VAC 11 M CB2 + GND 12 N GND + +**********************************************************************/ + +#pragma once + +#ifndef __VIC20_USER_PORT__ +#define __VIC20_USER_PORT__ + +#include "bus/pet/user.h" + +SLOT_INTERFACE_EXTERN( vic20_user_port_cards ); + +#endif diff --git a/src/devices/bus/vic20/vic1010.c b/src/devices/bus/vic20/vic1010.c new file mode 100644 index 00000000000..98fd3552afa --- /dev/null +++ b/src/devices/bus/vic20/vic1010.c @@ -0,0 +1,126 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Commodore VIC-1010 Expansion Module emulation + +**********************************************************************/ + +#include "vic1010.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type VIC1010 = &device_creator; + + +//------------------------------------------------- +// MACHINE_DRIVER( vic1010 ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( vic1010 ) + MCFG_VIC20_PASSTHRU_EXPANSION_SLOT_ADD("slot1") + MCFG_VIC20_PASSTHRU_EXPANSION_SLOT_ADD("slot2") + MCFG_VIC20_PASSTHRU_EXPANSION_SLOT_ADD("slot3") + MCFG_VIC20_PASSTHRU_EXPANSION_SLOT_ADD("slot4") + MCFG_VIC20_PASSTHRU_EXPANSION_SLOT_ADD("slot5") + MCFG_VIC20_PASSTHRU_EXPANSION_SLOT_ADD("slot6") +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor vic1010_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( vic1010 ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// vic1010_device - constructor +//------------------------------------------------- + +vic1010_device::vic1010_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, VIC1010, "VIC1010", tag, owner, clock, "vic1010", __FILE__), + device_vic20_expansion_card_interface(mconfig, *this), + m_slot1(*this, "slot1"), + m_slot2(*this, "slot2"), + m_slot3(*this, "slot3"), + m_slot4(*this, "slot4"), + m_slot5(*this, "slot5"), + m_slot6(*this, "slot6") +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void vic1010_device::device_start() +{ + // find devices + m_expansion_slot[0] = m_slot1; + m_expansion_slot[1] = m_slot2; + m_expansion_slot[2] = m_slot3; + m_expansion_slot[3] = m_slot4; + m_expansion_slot[4] = m_slot5; + m_expansion_slot[5] = m_slot6; +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void vic1010_device::device_reset() +{ + for (int i = 0; i < MAX_SLOTS; i++) + { + m_expansion_slot[i]->reset(); + } +} + + +//------------------------------------------------- +// vic20_cd_r - cartridge data read +//------------------------------------------------- + +UINT8 vic1010_device::vic20_cd_r(address_space &space, offs_t offset, UINT8 data, int ram1, int ram2, int ram3, int blk1, int blk2, int blk3, int blk5, int io2, int io3) +{ + for (int i = 0; i < MAX_SLOTS; i++) + { + UINT8 slot_data = m_expansion_slot[i]->cd_r(space, offset, data, ram1, ram2, ram3, blk1, blk2, blk3, blk5, io2, io3); + + if (data != slot_data) + { + data = slot_data; + } + } + + return data; +} + + +//------------------------------------------------- +// vic20_cd_w - cartridge data write +//------------------------------------------------- + +void vic1010_device::vic20_cd_w(address_space &space, offs_t offset, UINT8 data, int ram1, int ram2, int ram3, int blk1, int blk2, int blk3, int blk5, int io2, int io3) +{ + for (int i = 0; i < MAX_SLOTS; i++) + { + m_expansion_slot[i]->cd_w(space, offset, data, ram1, ram2, ram3, blk1, blk2, blk3, blk5, io2, io3); + } +} diff --git a/src/devices/bus/vic20/vic1010.h b/src/devices/bus/vic20/vic1010.h new file mode 100644 index 00000000000..56f194635b8 --- /dev/null +++ b/src/devices/bus/vic20/vic1010.h @@ -0,0 +1,69 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Commodore VIC-1010 Expansion Module emulation + +**********************************************************************/ + +#pragma once + +#ifndef __VIC1010__ +#define __VIC1010__ + +#include "emu.h" +#include "exp.h" + + + +//************************************************************************** +// MACROS/CONSTANTS +//************************************************************************** + +#define MAX_SLOTS 6 + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> vic1010_device + +class vic1010_device : public device_t, + public device_vic20_expansion_card_interface +{ +public: + // construction/destruction + vic1010_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_vic20_expansion_card_interface overrides + virtual UINT8 vic20_cd_r(address_space &space, offs_t offset, UINT8 data, int ram1, int ram2, int ram3, int blk1, int blk2, int blk3, int blk5, int io2, int io3); + virtual void vic20_cd_w(address_space &space, offs_t offset, UINT8 data, int ram1, int ram2, int ram3, int blk1, int blk2, int blk3, int blk5, int io2, int io3); + +private: + required_device m_slot1; + required_device m_slot2; + required_device m_slot3; + required_device m_slot4; + required_device m_slot5; + required_device m_slot6; + + vic20_expansion_slot_device *m_expansion_slot[MAX_SLOTS]; +}; + + +// device type definition +extern const device_type VIC1010; + + + +#endif diff --git a/src/devices/bus/vic20/vic1011.c b/src/devices/bus/vic20/vic1011.c new file mode 100644 index 00000000000..402a44f41df --- /dev/null +++ b/src/devices/bus/vic20/vic1011.c @@ -0,0 +1,101 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/********************************************************************** + + Commodore VIC-1011A/B RS-232C Adapter emulation + +**********************************************************************/ + +#include "vic1011.h" + + + +//************************************************************************** +// MACROS/CONSTANTS +//************************************************************************** + +#define RS232_TAG "rs232" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type VIC1011 = &device_creator; + + +//------------------------------------------------- +// MACHINE_DRIVER( vic1011 ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( vic1011 ) + MCFG_RS232_PORT_ADD(RS232_TAG, default_rs232_devices, NULL) + MCFG_RS232_RXD_HANDLER(DEVWRITELINE(DEVICE_SELF, vic1011_device, output_rxd)) + MCFG_RS232_DCD_HANDLER(DEVWRITELINE(DEVICE_SELF, vic1011_device, output_h)) MCFG_DEVCB_XOR(1) + MCFG_RS232_CTS_HANDLER(DEVWRITELINE(DEVICE_SELF, vic1011_device, output_k)) MCFG_DEVCB_XOR(1) + MCFG_RS232_DSR_HANDLER(DEVWRITELINE(DEVICE_SELF, vic1011_device, output_l)) MCFG_DEVCB_XOR(1) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor vic1011_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( vic1011 ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// vic1011_device - constructor +//------------------------------------------------- + +vic1011_device::vic1011_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, VIC1011, "VIC1011", tag, owner, clock, "vic1011", __FILE__), + device_pet_user_port_interface(mconfig, *this), + m_rs232(*this, RS232_TAG) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void vic1011_device::device_start() +{ +} + +WRITE_LINE_MEMBER( vic1011_device::output_rxd ) +{ + output_b(state); + output_c(state); +} + +void vic1011_device::input_d(int state) +{ + m_rs232->write_rts(!state); +} + +void vic1011_device::input_e(int state) +{ + m_rs232->write_dtr(!state); +} + +void vic1011_device::input_j(int state) +{ + /// dcdout +} + +void vic1011_device::input_m(int state) +{ + m_rs232->write_txd(state); +} diff --git a/src/devices/bus/vic20/vic1011.h b/src/devices/bus/vic20/vic1011.h new file mode 100644 index 00000000000..9ec16e5fd2a --- /dev/null +++ b/src/devices/bus/vic20/vic1011.h @@ -0,0 +1,57 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/********************************************************************** + + Commodore VIC-1011A/B RS-232C Adapter emulation + +**********************************************************************/ + +#pragma once + +#ifndef __VIC1011__ +#define __VIC1011__ + +#include "user.h" +#include "bus/rs232/rs232.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> vic1011_device + +class vic1011_device : public device_t, + public device_pet_user_port_interface +{ +public: + // construction/destruction + vic1011_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + + // device_pet_user_port_interface overrides + virtual DECLARE_WRITE_LINE_MEMBER( input_d ); + virtual DECLARE_WRITE_LINE_MEMBER( input_e ); + virtual DECLARE_WRITE_LINE_MEMBER( input_j ); + virtual DECLARE_WRITE_LINE_MEMBER( input_m ); + + DECLARE_WRITE_LINE_MEMBER( output_rxd ); + +protected: + // device-level overrides + virtual void device_start(); + +private: + required_device m_rs232; +}; + + +// device type definition +extern const device_type VIC1011; + + + +#endif diff --git a/src/devices/bus/vic20/vic1110.c b/src/devices/bus/vic20/vic1110.c new file mode 100644 index 00000000000..c8d9acb1398 --- /dev/null +++ b/src/devices/bus/vic20/vic1110.c @@ -0,0 +1,117 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Commodore VIC-1110 8K RAM Expansion Cartridge emulation + +**********************************************************************/ + +#include "vic1110.h" + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +enum +{ + BLK1 = 0x07, + BLK2 = 0x0b, + BLK3 = 0x0d, + BLK5 = 0x0e +}; + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type VIC1110 = &device_creator; + + + +//------------------------------------------------- +// INPUT_PORTS( vic1110 ) +//------------------------------------------------- + +INPUT_PORTS_START( vic1110 ) + PORT_START("SW") + PORT_DIPNAME( 0x0f, BLK1, "Memory Location" ) PORT_DIPLOCATION("SW:1,2,3,4") + PORT_DIPSETTING( BLK1, "$2000-$3FFF" ) + PORT_DIPSETTING( BLK2, "$4000-$5FFF" ) + PORT_DIPSETTING( BLK3, "$6000-$7FFF" ) + PORT_DIPSETTING( BLK5, "$A000-B3FFF" ) +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor vic1110_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( vic1110 ); +} + + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// vic1110_device - constructor +//------------------------------------------------- + +vic1110_device::vic1110_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, VIC1110, "VIC1110", tag, owner, clock, "vic1110", __FILE__), + device_vic20_expansion_card_interface(mconfig, *this), + m_ram(*this, "ram"), + m_sw(*this, "SW") +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void vic1110_device::device_start() +{ + // allocate memory + m_ram.allocate(0x2000); +} + + +//------------------------------------------------- +// vic20_cd_r - cartridge data read +//------------------------------------------------- + +UINT8 vic1110_device::vic20_cd_r(address_space &space, offs_t offset, UINT8 data, int ram1, int ram2, int ram3, int blk1, int blk2, int blk3, int blk5, int io2, int io3) +{ + UINT8 sw = m_sw->read(); + + if ((!blk1 && (sw == BLK1)) || (!blk2 && (sw == BLK2)) || (!blk3 && (sw == BLK3)) || (!blk5 && (sw == BLK5))) + { + data = m_ram[offset & 0x1fff]; + } + + return data; +} + + +//------------------------------------------------- +// vic20_cd_w - cartridge data write +//------------------------------------------------- + +void vic1110_device::vic20_cd_w(address_space &space, offs_t offset, UINT8 data, int ram1, int ram2, int ram3, int blk1, int blk2, int blk3, int blk5, int io2, int io3) +{ + UINT8 sw = m_sw->read(); + + if ((!blk1 && (sw == BLK1)) || (!blk2 && (sw == BLK2)) || (!blk3 && (sw == BLK3)) || (!blk5 && (sw == BLK5))) + { + m_ram[offset & 0x1fff] = data; + } +} diff --git a/src/devices/bus/vic20/vic1110.h b/src/devices/bus/vic20/vic1110.h new file mode 100644 index 00000000000..4b6aecebd5a --- /dev/null +++ b/src/devices/bus/vic20/vic1110.h @@ -0,0 +1,54 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Commodore VIC-1110 8K RAM Expansion Cartridge emulation + +**********************************************************************/ + +#pragma once + +#ifndef __VIC1110__ +#define __VIC1110__ + +#include "emu.h" +#include "exp.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> vic1110_device + +class vic1110_device : public device_t, + public device_vic20_expansion_card_interface +{ +public: + // construction/destruction + vic1110_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual ioport_constructor device_input_ports() const; + +protected: + // device-level overrides + virtual void device_start(); + + // device_vic20_expansion_card_interface overrides + virtual UINT8 vic20_cd_r(address_space &space, offs_t offset, UINT8 data, int ram1, int ram2, int ram3, int blk1, int blk2, int blk3, int blk5, int io2, int io3); + virtual void vic20_cd_w(address_space &space, offs_t offset, UINT8 data, int ram1, int ram2, int ram3, int blk1, int blk2, int blk3, int blk5, int io2, int io3); + +private: + optional_shared_ptr m_ram; + required_ioport m_sw; +}; + + +// device type definition +extern const device_type VIC1110; + + + +#endif diff --git a/src/devices/bus/vic20/vic1111.c b/src/devices/bus/vic20/vic1111.c new file mode 100644 index 00000000000..770d5639d8f --- /dev/null +++ b/src/devices/bus/vic20/vic1111.c @@ -0,0 +1,81 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Commodore VIC-1111 16K RAM Expansion Cartridge emulation + +**********************************************************************/ + +#include "vic1111.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type VIC1111 = &device_creator; + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// vic1111_device - constructor +//------------------------------------------------- + +vic1111_device::vic1111_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, VIC1111, "VIC1111", tag, owner, clock, "vic1111", __FILE__), + device_vic20_expansion_card_interface(mconfig, *this), + m_ram(*this, "ram") +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void vic1111_device::device_start() +{ + // allocate memory + m_ram.allocate(0x4000); +} + + +//------------------------------------------------- +// vic20_cd_r - cartridge data read +//------------------------------------------------- + +UINT8 vic1111_device::vic20_cd_r(address_space &space, offs_t offset, UINT8 data, int ram1, int ram2, int ram3, int blk1, int blk2, int blk3, int blk5, int io2, int io3) +{ + if (!blk1) + { + data = m_ram[offset]; + } + else if (!blk2) + { + data = m_ram[0x2000 + offset]; + } + + return data; +} + + +//------------------------------------------------- +// vic20_cd_w - cartridge data write +//------------------------------------------------- + +void vic1111_device::vic20_cd_w(address_space &space, offs_t offset, UINT8 data, int ram1, int ram2, int ram3, int blk1, int blk2, int blk3, int blk5, int io2, int io3) +{ + if (!blk1) + { + m_ram[offset] = data; + } + else if (!blk2) + { + m_ram[0x2000 + offset] = data; + } +} diff --git a/src/devices/bus/vic20/vic1111.h b/src/devices/bus/vic20/vic1111.h new file mode 100644 index 00000000000..e20dc4a8e2d --- /dev/null +++ b/src/devices/bus/vic20/vic1111.h @@ -0,0 +1,50 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Commodore VIC-1111 16K RAM Expansion Cartridge emulation + +**********************************************************************/ + +#pragma once + +#ifndef __VIC1111__ +#define __VIC1111__ + +#include "emu.h" +#include "exp.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> vic1111_device + +class vic1111_device : public device_t, + public device_vic20_expansion_card_interface +{ +public: + // construction/destruction + vic1111_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // device-level overrides + virtual void device_start(); + + // device_vic20_expansion_card_interface overrides + virtual UINT8 vic20_cd_r(address_space &space, offs_t offset, UINT8 data, int ram1, int ram2, int ram3, int blk1, int blk2, int blk3, int blk5, int io2, int io3); + virtual void vic20_cd_w(address_space &space, offs_t offset, UINT8 data, int ram1, int ram2, int ram3, int blk1, int blk2, int blk3, int blk5, int io2, int io3); + +private: + optional_shared_ptr m_ram; +}; + + +// device type definition +extern const device_type VIC1111; + + + +#endif diff --git a/src/devices/bus/vic20/vic1112.c b/src/devices/bus/vic20/vic1112.c new file mode 100644 index 00000000000..482f7f01b03 --- /dev/null +++ b/src/devices/bus/vic20/vic1112.c @@ -0,0 +1,216 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Commodore VIC-1112 IEEE-488 Interface Cartridge emulation + +**********************************************************************/ + +#include "vic1112.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define M6522_0_TAG "u4" +#define M6522_1_TAG "u5" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type VIC1112 = &device_creator; + + +WRITE_LINE_MEMBER( vic1112_device::via0_irq_w ) +{ + m_via0_irq = state; + + m_slot->irq_w(m_via0_irq | m_via1_irq); +} + +READ8_MEMBER( vic1112_device::via0_pb_r ) +{ + /* + + bit description + + PB0 + PB1 + PB2 + PB3 _EOI + PB4 _DAV IN + PB5 _NRFD IN + PB6 _NDAC IN + PB7 _ATN IN + + */ + + UINT8 data = 0; + + data |= m_bus->eoi_r() << 3; + data |= m_bus->dav_r() << 4; + data |= m_bus->nrfd_r() << 5; + data |= m_bus->ndac_r() << 6; + data |= m_bus->atn_r() << 7; + + return data; +} + +WRITE8_MEMBER( vic1112_device::via0_pb_w ) +{ + /* + + bit description + + PB0 _DAV OUT + PB1 _NRFD OUT + PB2 _NDAC OUT + PB3 + PB4 + PB5 + PB6 + PB7 + + */ + + m_bus->dav_w(BIT(data, 0)); + m_bus->nrfd_w(BIT(data, 1)); + m_bus->ndac_w(BIT(data, 2)); +} + + +WRITE_LINE_MEMBER( vic1112_device::via1_irq_w ) +{ + m_via1_irq = state; + + m_slot->irq_w(m_via0_irq | m_via1_irq); +} + + +//------------------------------------------------- +// MACHINE_DRIVER( vic1112 ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( vic1112 ) + MCFG_DEVICE_ADD(M6522_0_TAG, VIA6522, 0) + MCFG_VIA6522_READPB_HANDLER(READ8(vic1112_device, via0_pb_r)) + MCFG_VIA6522_WRITEPB_HANDLER(WRITE8(vic1112_device, via0_pb_w)) + MCFG_VIA6522_IRQ_HANDLER(WRITELINE(vic1112_device, via0_irq_w)) + + MCFG_DEVICE_ADD(M6522_1_TAG, VIA6522, 0) + MCFG_VIA6522_READPB_HANDLER(DEVREAD8(IEEE488_TAG, ieee488_device, dio_r)) + MCFG_VIA6522_WRITEPA_HANDLER(DEVWRITE8(IEEE488_TAG, ieee488_device, dio_w)) + MCFG_VIA6522_CA2_HANDLER(DEVWRITELINE(IEEE488_TAG, ieee488_device, atn_w)) + MCFG_VIA6522_CB2_HANDLER(DEVWRITELINE(IEEE488_TAG, ieee488_device, eoi_w)) + MCFG_VIA6522_IRQ_HANDLER(WRITELINE(vic1112_device, via1_irq_w)) + + MCFG_CBM_IEEE488_ADD(NULL) + MCFG_IEEE488_SRQ_CALLBACK(DEVWRITELINE(M6522_1_TAG, via6522_device, write_cb1)) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor vic1112_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( vic1112 ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// vic1112_device - constructor +//------------------------------------------------- + +vic1112_device::vic1112_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, VIC1112, "VIC1112", tag, owner, clock, "vic1112", __FILE__), + device_vic20_expansion_card_interface(mconfig, *this), + m_via0(*this, M6522_0_TAG), + m_via1(*this, M6522_1_TAG), + m_bus(*this, IEEE488_TAG) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void vic1112_device::device_start() +{ + // state saving + save_item(NAME(m_via0_irq)); + save_item(NAME(m_via1_irq)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void vic1112_device::device_reset() +{ + m_bus->ifc_w(0); + m_bus->ifc_w(1); +} + + +//------------------------------------------------- +// vic20_cd_r - cartridge data read +//------------------------------------------------- + +UINT8 vic1112_device::vic20_cd_r(address_space &space, offs_t offset, UINT8 data, int ram1, int ram2, int ram3, int blk1, int blk2, int blk3, int blk5, int io2, int io3) +{ + if (!io2) + { + if (offset & 0x10) + { + data = m_via1->read(space, offset & 0x0f); + } + else + { + data = m_via0->read(space, offset & 0x0f); + } + } + else if (!blk5) + { + if (offset & 0x1000) + { + data = m_blk5[offset & 0x17ff]; + } + } + + return data; +} + + +//------------------------------------------------- +// vic20_cd_w - cartridge data write +//------------------------------------------------- + +void vic1112_device::vic20_cd_w(address_space &space, offs_t offset, UINT8 data, int ram1, int ram2, int ram3, int blk1, int blk2, int blk3, int blk5, int io2, int io3) +{ + if (!io2) + { + if (offset & 0x10) + { + m_via1->write(space, offset & 0x0f, data); + } + else + { + m_via0->write(space, offset & 0x0f, data); + } + } +} diff --git a/src/devices/bus/vic20/vic1112.h b/src/devices/bus/vic20/vic1112.h new file mode 100644 index 00000000000..6149866c020 --- /dev/null +++ b/src/devices/bus/vic20/vic1112.h @@ -0,0 +1,72 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Commodore VIC-1112 IEEE-488 Interface Cartridge emulation + + SYS 45065 to start + +**********************************************************************/ + +#pragma once + +#ifndef __VIC1112__ +#define __VIC1112__ + +#include "emu.h" +#include "exp.h" +#include "bus/ieee488/ieee488.h" +#include "cpu/m6502/m6502.h" +#include "machine/6522via.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> vic1112_device + +class vic1112_device : public device_t, + public device_vic20_expansion_card_interface +{ +public: + // construction/destruction + vic1112_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + + // not really public + DECLARE_WRITE_LINE_MEMBER( via0_irq_w ); + DECLARE_READ8_MEMBER( via0_pb_r ); + DECLARE_WRITE8_MEMBER( via0_pb_w ); + DECLARE_WRITE_LINE_MEMBER( via1_irq_w ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_vic20_expansion_card_interface overrides + virtual UINT8 vic20_cd_r(address_space &space, offs_t offset, UINT8 data, int ram1, int ram2, int ram3, int blk1, int blk2, int blk3, int blk5, int io2, int io3); + virtual void vic20_cd_w(address_space &space, offs_t offset, UINT8 data, int ram1, int ram2, int ram3, int blk1, int blk2, int blk3, int blk5, int io2, int io3); + +private: + required_device m_via0; + required_device m_via1; + required_device m_bus; + + //UINT8 *m_rom; + + int m_via0_irq; + int m_via1_irq; +}; + + +// device type definition +extern const device_type VIC1112; + + + +#endif diff --git a/src/devices/bus/vic20/vic1210.c b/src/devices/bus/vic20/vic1210.c new file mode 100644 index 00000000000..5acb518cd08 --- /dev/null +++ b/src/devices/bus/vic20/vic1210.c @@ -0,0 +1,78 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Commodore VIC-1210 3K RAM Expansion Cartridge emulation + Commodore VIC-1211A Super Expander with 3K RAM Cartridge emulation + +**********************************************************************/ + +#include "vic1210.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type VIC1210 = &device_creator; + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// vic1210_device - constructor +//------------------------------------------------- + +vic1210_device::vic1210_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, VIC1210, "VIC1210", tag, owner, clock, "vic1210", __FILE__), + device_vic20_expansion_card_interface(mconfig, *this), + m_ram(*this, "ram") +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void vic1210_device::device_start() +{ + // allocate memory + m_ram.allocate(0xc00); +} + + +//------------------------------------------------- +// vic20_cd_r - cartridge data read +//------------------------------------------------- + +UINT8 vic1210_device::vic20_cd_r(address_space &space, offs_t offset, UINT8 data, int ram1, int ram2, int ram3, int blk1, int blk2, int blk3, int blk5, int io2, int io3) +{ + if (!ram1 || !ram2 || !ram3) + { + data = m_ram[offset & 0xbff]; + } + else if (!blk5 && m_blk5) + { + data = m_blk5[offset & 0xfff]; + } + + return data; +} + + +//------------------------------------------------- +// vic20_cd_w - cartridge data write +//------------------------------------------------- + +void vic1210_device::vic20_cd_w(address_space &space, offs_t offset, UINT8 data, int ram1, int ram2, int ram3, int blk1, int blk2, int blk3, int blk5, int io2, int io3) +{ + if (!ram1 || !ram2 || !ram3) + { + m_ram[offset & 0xbff] = data; + } +} diff --git a/src/devices/bus/vic20/vic1210.h b/src/devices/bus/vic20/vic1210.h new file mode 100644 index 00000000000..904336dd6c0 --- /dev/null +++ b/src/devices/bus/vic20/vic1210.h @@ -0,0 +1,51 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Commodore VIC-1210 3K RAM Expansion Cartridge emulation + Commodore VIC-1211A Super Expander with 3K RAM Cartridge emulation + +**********************************************************************/ + +#pragma once + +#ifndef __VIC1210__ +#define __VIC1210__ + +#include "emu.h" +#include "exp.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> vic1210_device + +class vic1210_device : public device_t, + public device_vic20_expansion_card_interface +{ +public: + // construction/destruction + vic1210_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // device-level overrides + virtual void device_start(); + + // device_vic20_expansion_card_interface overrides + virtual UINT8 vic20_cd_r(address_space &space, offs_t offset, UINT8 data, int ram1, int ram2, int ram3, int blk1, int blk2, int blk3, int blk5, int io2, int io3); + virtual void vic20_cd_w(address_space &space, offs_t offset, UINT8 data, int ram1, int ram2, int ram3, int blk1, int blk2, int blk3, int blk5, int io2, int io3); + +private: + optional_shared_ptr m_ram; +}; + + +// device type definition +extern const device_type VIC1210; + + + +#endif diff --git a/src/devices/bus/vidbrain/exp.c b/src/devices/bus/vidbrain/exp.c new file mode 100644 index 00000000000..e3634283efa --- /dev/null +++ b/src/devices/bus/vidbrain/exp.c @@ -0,0 +1,206 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + VideoBrain Expansion Port emulation + +**********************************************************************/ + +#include "exp.h" + + + +//************************************************************************** +// MACROS/CONSTANTS +//************************************************************************** + +#define LOG 0 + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type VIDEOBRAIN_EXPANSION_SLOT = &device_creator; + + + +//************************************************************************** +// DEVICE VIDEOBRAIN_EXPANSION CARD INTERFACE +//************************************************************************** + +//------------------------------------------------- +// device_videobrain_expansion_card_interface - constructor +//------------------------------------------------- + +device_videobrain_expansion_card_interface::device_videobrain_expansion_card_interface(const machine_config &mconfig, device_t &device) : + device_slot_card_interface(mconfig, device), + m_rom_mask(0), + m_ram_mask(0) +{ + m_slot = dynamic_cast(device.owner()); +} + + +//------------------------------------------------- +// videobrain_roml_pointer - get low ROM pointer +//------------------------------------------------- + +UINT8* device_videobrain_expansion_card_interface::videobrain_rom_pointer(running_machine &machine, size_t size) +{ + if (m_rom.empty()) + { + m_rom.resize(size); + + m_rom_mask = size - 1; + } + + return &m_rom[0]; +} + + +//------------------------------------------------- +// videobrain_ram_pointer - get RAM pointer +//------------------------------------------------- + +UINT8* device_videobrain_expansion_card_interface::videobrain_ram_pointer(running_machine &machine, size_t size) +{ + if (m_ram.empty()) + { + m_ram.resize(size); + + m_ram_mask = size - 1; + } + + return &m_ram[0]; +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// videobrain_expansion_slot_device - constructor +//------------------------------------------------- + +videobrain_expansion_slot_device::videobrain_expansion_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, VIDEOBRAIN_EXPANSION_SLOT, "VideoBrain expansion port", tag, owner, clock, "videobrain_expansion_slot", __FILE__), + device_slot_interface(mconfig, *this), + device_image_interface(mconfig, *this), + m_write_extres(*this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void videobrain_expansion_slot_device::device_start() +{ + m_cart = dynamic_cast(get_card_device()); + + // resolve callbacks + m_write_extres.resolve_safe(); +} + + +//------------------------------------------------- +// call_load - +//------------------------------------------------- + +bool videobrain_expansion_slot_device::call_load() +{ + if (m_cart) + { + size_t size = 0; + + if (software_entry() == NULL) + { + size = length(); + + fread(m_cart->videobrain_rom_pointer(machine(), size), size); + } + else + { + size = get_software_region_length("rom"); + if (size) memcpy(m_cart->videobrain_rom_pointer(machine(), size), get_software_region("rom"), size); + + size = get_software_region_length("ram"); + if (size) memset(m_cart->videobrain_ram_pointer(machine(), size), 0, size); + } + } + + return IMAGE_INIT_PASS; +} + + +//------------------------------------------------- +// call_softlist_load - +//------------------------------------------------- + +bool videobrain_expansion_slot_device::call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry) +{ + load_software_part_region(*this, swlist, swname, start_entry); + + return true; +} + + +//------------------------------------------------- +// get_default_card_software - +//------------------------------------------------- + +void videobrain_expansion_slot_device::get_default_card_software(std::string &result) +{ + software_get_default_slot(result, "standard"); +} + + +//------------------------------------------------- +// bo_r - cartridge data read +//------------------------------------------------- + +UINT8 videobrain_expansion_slot_device::bo_r(address_space &space, offs_t offset, int cs1, int cs2) +{ + UINT8 data = 0; + + if (m_cart != NULL) + { + data = m_cart->videobrain_bo_r(space, offset, cs1, cs2); + } + + return data; +} + + +//------------------------------------------------- +// bo_w - cartridge data write +//------------------------------------------------- + +void videobrain_expansion_slot_device::bo_w(address_space &space, offs_t offset, UINT8 data, int cs1, int cs2) +{ + if (m_cart != NULL) + { + m_cart->videobrain_bo_w(space, offset, data, cs1, cs2); + } +} + + +//------------------------------------------------- +// SLOT_INTERFACE_START( vidbrain_expansion_cards ) +//------------------------------------------------- + +// slot devices +#include "std.h" +#include "money_minder.h" +#include "timeshare.h" + +SLOT_INTERFACE_START( vidbrain_expansion_cards ) + SLOT_INTERFACE_INTERNAL("standard", VB_STD) + SLOT_INTERFACE_INTERNAL("moneyminder", VB_MONEY_MINDER) + SLOT_INTERFACE_INTERNAL("timeshare", VB_TIMESHARE) +SLOT_INTERFACE_END diff --git a/src/devices/bus/vidbrain/exp.h b/src/devices/bus/vidbrain/exp.h new file mode 100644 index 00000000000..8e6064dbc94 --- /dev/null +++ b/src/devices/bus/vidbrain/exp.h @@ -0,0 +1,169 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + VideoBrain Expansion Port emulation + +********************************************************************** + + GND 1 2 BO2 + BO1 3 4 BO0 + BA0 5 6 BA1 + BA2 7 8 BA3 + BA4 9 10 BA5 + BA6 11 12 BA7 + +5V 13 14 BA8 + BA9 15 16 _CS1 + BA10 17 18 BO7 + BO6 19 20 BO5 + BO4 21 22 BO3 + BA11 23 24 BA12 + BRC 25 26 ? + EXTRES 27 28 _CS2 + ? 29 30 UV202/35 + HBLANK 31 32 UV201/5 + UV201/2 33 34 UV201/4 + UV201/3 35 36 BISTROBE + UV202/1 37 38 BA13 + UV202/18 39 40 ? + R/W 41 42 +5V + GND 43 44 GND + GND 45 46 N/C + ? 47 48 N/C + N/C 49 50 N/C + +**********************************************************************/ + +#pragma once + +#ifndef __VIDEOBRAIN_EXPANSION_SLOT__ +#define __VIDEOBRAIN_EXPANSION_SLOT__ + +#include "emu.h" + + + +//************************************************************************** +// CONSTANTS +//************************************************************************** + +#define VIDEOBRAIN_EXPANSION_SLOT_TAG "exp" + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_VIDEOBRAIN_EXPANSION_SLOT_ADD(_tag, _slot_intf, _def_slot) \ + MCFG_DEVICE_ADD(_tag, VIDEOBRAIN_EXPANSION_SLOT, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) + + +#define MCFG_VIDEOBRAIN_EXPANSION_SLOT_EXTRES_CALLBACK(_write) \ + devcb = &videobrain_expansion_slot_device::set_extres_wr_callback(*device, DEVCB_##_write); + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class videobrain_expansion_slot_device; + +// ======================> device_videobrain_expansion_card_interface + +class device_videobrain_expansion_card_interface : public device_slot_card_interface +{ + friend class videobrain_expansion_slot_device; + +public: + // construction/destruction + device_videobrain_expansion_card_interface(const machine_config &mconfig, device_t &device); + virtual ~device_videobrain_expansion_card_interface() { } + +protected: + // initialization + virtual UINT8* videobrain_rom_pointer(running_machine &machine, size_t size); + virtual UINT8* videobrain_ram_pointer(running_machine &machine, size_t size); + + // runtime + virtual UINT8 videobrain_bo_r(address_space &space, offs_t offset, int cs1, int cs2) { return 0; }; + virtual void videobrain_bo_w(address_space &space, offs_t offset, UINT8 data, int cs1, int cs2) { }; + virtual void videobrain_extres_w() { }; + + videobrain_expansion_slot_device *m_slot; + + dynamic_buffer m_rom; + dynamic_buffer m_ram; + + size_t m_rom_mask; + size_t m_ram_mask; +}; + + +// ======================> videobrain_expansion_slot_device + +class videobrain_expansion_slot_device : public device_t, + public device_slot_interface, + public device_image_interface +{ +public: + // construction/destruction + videobrain_expansion_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual ~videobrain_expansion_slot_device() { } + + template static devcb_base &set_extres_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_extres.set_callback(object); } + + // computer interface + UINT8 bo_r(address_space &space, offs_t offset, int cs1, int cs2); + void bo_w(address_space &space, offs_t offset, UINT8 data, int cs1, int cs2); + + DECLARE_READ8_MEMBER( cs1_r ) { return bo_r(space, offset + 0x1000, 0, 1); } + DECLARE_WRITE8_MEMBER( cs1_w ) { bo_w(space, offset + 0x1000, data, 0, 1); } + DECLARE_READ8_MEMBER( cs2_r ) { return bo_r(space, offset + 0x1800, 1, 0); } + DECLARE_WRITE8_MEMBER( cs2_w ) { bo_w(space, offset + 0x1800, data, 1, 0); } + DECLARE_READ8_MEMBER( unmap_r ) { return bo_r(space, offset + 0x3000, 1, 0); } + DECLARE_WRITE8_MEMBER( unmap_w ) { bo_w(space, offset + 0x3000, data, 1, 0); } + + // cartridge interface + DECLARE_WRITE_LINE_MEMBER( extres_w ) { m_write_extres(state); } + +protected: + // device-level overrides + virtual void device_config_complete() { update_names(); } + virtual void device_start(); + + // image-level overrides + virtual bool call_load(); + virtual bool call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry); + + virtual iodevice_t image_type() const { return IO_CARTSLOT; } + + virtual bool is_readable() const { return 1; } + virtual bool is_writeable() const { return 0; } + virtual bool is_creatable() const { return 0; } + virtual bool must_be_loaded() const { return 0; } + virtual bool is_reset_on_load() const { return 1; } + virtual const char *image_interface() const { return "vidbrain_cart"; } + virtual const char *file_extensions() const { return "bin"; } + virtual const option_guide *create_option_guide() const { return NULL; } + + // slot interface overrides + virtual void get_default_card_software(std::string &result); + + devcb_write_line m_write_extres; + + device_videobrain_expansion_card_interface *m_cart; +}; + + +// device type definition +extern const device_type VIDEOBRAIN_EXPANSION_SLOT; + + +SLOT_INTERFACE_EXTERN( vidbrain_expansion_cards ); + + + +#endif diff --git a/src/devices/bus/vidbrain/money_minder.c b/src/devices/bus/vidbrain/money_minder.c new file mode 100644 index 00000000000..f5fa70bd868 --- /dev/null +++ b/src/devices/bus/vidbrain/money_minder.c @@ -0,0 +1,76 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + VideoBrain Money Minder cartridge emulation + +**********************************************************************/ + +#include "money_minder.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type VB_MONEY_MINDER = &device_creator; + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// videobrain_money_minder_cartridge_device - constructor +//------------------------------------------------- + +videobrain_money_minder_cartridge_device::videobrain_money_minder_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, VB_MONEY_MINDER, "VideoBrain Money Minder cartridge", tag, owner, clock, "vb_money_minder", __FILE__), + device_videobrain_expansion_card_interface(mconfig, *this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void videobrain_money_minder_cartridge_device::device_start() +{ +} + + +//------------------------------------------------- +// videobrain_cd_r - cartridge data read +//------------------------------------------------- + +UINT8 videobrain_money_minder_cartridge_device::videobrain_bo_r(address_space &space, offs_t offset, int cs1, int cs2) +{ + UINT8 data = 0; + + if (!cs1 || !cs2) + { + data = m_rom[offset & m_rom_mask]; + } + else if (offset >= 0x3800) + { + data = m_ram[offset & m_ram_mask]; + } + + return data; +} + + +//------------------------------------------------- +// videobrain_bo_w - cartridge data write +//------------------------------------------------- + +void videobrain_money_minder_cartridge_device::videobrain_bo_w(address_space &space, offs_t offset, UINT8 data, int cs1, int cs2) +{ + if (offset >= 0x3800) + { + m_ram[offset & m_ram_mask] = data; + } +} diff --git a/src/devices/bus/vidbrain/money_minder.h b/src/devices/bus/vidbrain/money_minder.h new file mode 100644 index 00000000000..9cdd6c8f4e6 --- /dev/null +++ b/src/devices/bus/vidbrain/money_minder.h @@ -0,0 +1,46 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + VideoBrain Money Minder cartridge emulation + +**********************************************************************/ + +#pragma once + +#ifndef __VIDEOBRAIN_MONEY_MINDER_CARTRIDGE__ +#define __VIDEOBRAIN_MONEY_MINDER_CARTRIDGE__ + +#include "emu.h" +#include "exp.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> videobrain_money_minder_cartridge_device + +class videobrain_money_minder_cartridge_device : public device_t, + public device_videobrain_expansion_card_interface +{ +public: + // construction/destruction + videobrain_money_minder_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // device-level overrides + virtual void device_start(); + + // device_videobrain_expansion_card_interface overrides + virtual UINT8 videobrain_bo_r(address_space &space, offs_t offset, int cs1, int cs2); + virtual void videobrain_bo_w(address_space &space, offs_t offset, UINT8 data, int cs1, int cs2); +}; + + +// device type definition +extern const device_type VB_MONEY_MINDER; + + +#endif diff --git a/src/devices/bus/vidbrain/std.c b/src/devices/bus/vidbrain/std.c new file mode 100644 index 00000000000..f56f5fd9d9f --- /dev/null +++ b/src/devices/bus/vidbrain/std.c @@ -0,0 +1,62 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + VideoBrain Standard 2K/4K cartridge emulation + +**********************************************************************/ + +#include "std.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type VB_STD = &device_creator; + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// videobrain_standard_cartridge_device - constructor +//------------------------------------------------- + +videobrain_standard_cartridge_device::videobrain_standard_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, VB_STD, "VideoBrain standard cartridge", tag, owner, clock, "vb_std", __FILE__), + device_videobrain_expansion_card_interface(mconfig, *this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void videobrain_standard_cartridge_device::device_start() +{ +} + + +//------------------------------------------------- +// videobrain_bo_r - cartridge data read +//------------------------------------------------- + +UINT8 videobrain_standard_cartridge_device::videobrain_bo_r(address_space &space, offs_t offset, int cs1, int cs2) +{ + UINT8 data = 0; + + if (!cs1) + { + data = m_rom[offset & m_rom_mask]; + } + else if (!cs2) + { + data = m_rom[offset & m_rom_mask]; + } + return data; +} diff --git a/src/devices/bus/vidbrain/std.h b/src/devices/bus/vidbrain/std.h new file mode 100644 index 00000000000..74e9b4096e8 --- /dev/null +++ b/src/devices/bus/vidbrain/std.h @@ -0,0 +1,45 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + VideoBrain Standard 2K/4K cartridge emulation + +**********************************************************************/ + +#pragma once + +#ifndef __VIDEOBRAIN_STANDARD_CARTRIDGE__ +#define __VIDEOBRAIN_STANDARD_CARTRIDGE__ + +#include "emu.h" +#include "exp.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> videobrain_standard_cartridge_device + +class videobrain_standard_cartridge_device : public device_t, + public device_videobrain_expansion_card_interface +{ +public: + // construction/destruction + videobrain_standard_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // device-level overrides + virtual void device_start(); + + // device_videobrain_expansion_card_interface overrides + virtual UINT8 videobrain_bo_r(address_space &space, offs_t offset, int cs1, int cs2); +}; + + +// device type definition +extern const device_type VB_STD; + + +#endif diff --git a/src/devices/bus/vidbrain/timeshare.c b/src/devices/bus/vidbrain/timeshare.c new file mode 100644 index 00000000000..196bf66db2e --- /dev/null +++ b/src/devices/bus/vidbrain/timeshare.c @@ -0,0 +1,75 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + VideoBrain Timeshare cartridge emulation + +**********************************************************************/ + +#include "timeshare.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type VB_TIMESHARE = &device_creator; + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// videobrain_timeshare_cartridge_device - constructor +//------------------------------------------------- + +videobrain_timeshare_cartridge_device::videobrain_timeshare_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, VB_TIMESHARE, "VideoBrain Timeshare cartridge", tag, owner, clock, "vb_timeshare", __FILE__), + device_videobrain_expansion_card_interface(mconfig, *this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void videobrain_timeshare_cartridge_device::device_start() +{ +} + + +//------------------------------------------------- +// videobrain_bo_r - cartridge data read +//------------------------------------------------- + +UINT8 videobrain_timeshare_cartridge_device::videobrain_bo_r(address_space &space, offs_t offset, int cs1, int cs2) +{ + UINT8 data = 0; + + if (!cs1) + { + data = m_rom[offset & m_rom_mask]; + } + else if (!cs2) + { + data = m_ram[offset & m_ram_mask]; + } + return data; +} + + +//------------------------------------------------- +// videobrain_bo_w - cartridge data write +//------------------------------------------------- + +void videobrain_timeshare_cartridge_device::videobrain_bo_w(address_space &space, offs_t offset, UINT8 data, int cs1, int cs2) +{ + if (!cs2) + { + m_ram[offset & m_ram_mask] = data; + } +} diff --git a/src/devices/bus/vidbrain/timeshare.h b/src/devices/bus/vidbrain/timeshare.h new file mode 100644 index 00000000000..6f57c04d32f --- /dev/null +++ b/src/devices/bus/vidbrain/timeshare.h @@ -0,0 +1,46 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + VideoBrain Timeshare cartridge emulation + +**********************************************************************/ + +#pragma once + +#ifndef __VIDEOBRAIN_TIMESHARE_CARTRIDGE__ +#define __VIDEOBRAIN_TIMESHARE_CARTRIDGE__ + +#include "emu.h" +#include "exp.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> videobrain_timeshare_cartridge_device + +class videobrain_timeshare_cartridge_device : public device_t, + public device_videobrain_expansion_card_interface +{ +public: + // construction/destruction + videobrain_timeshare_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // device-level overrides + virtual void device_start(); + + // device_videobrain_expansion_card_interface overrides + virtual UINT8 videobrain_bo_r(address_space &space, offs_t offset, int cs1, int cs2); + virtual void videobrain_bo_w(address_space &space, offs_t offset, UINT8 data, int cs1, int cs2); +}; + + +// device type definition +extern const device_type VB_TIMESHARE; + + +#endif diff --git a/src/devices/bus/vip/byteio.c b/src/devices/bus/vip/byteio.c new file mode 100644 index 00000000000..bdebad76dba --- /dev/null +++ b/src/devices/bus/vip/byteio.c @@ -0,0 +1,88 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + RCA Cosmac VIP Byte Input/Output port emulation + +**********************************************************************/ + +#include "byteio.h" + + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type VIP_BYTEIO_PORT = &device_creator; + + + +//************************************************************************** +// CARD INTERFACE +//************************************************************************** + +//------------------------------------------------- +// device_vip_byteio_port_interface - constructor +//------------------------------------------------- + +device_vip_byteio_port_interface::device_vip_byteio_port_interface(const machine_config &mconfig, device_t &device) + : device_slot_card_interface(mconfig,device) +{ + m_slot = dynamic_cast(device.owner()); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// vip_byteio_port_device - constructor +//------------------------------------------------- + +vip_byteio_port_device::vip_byteio_port_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, VIP_BYTEIO_PORT, "VIP byte I/O port", tag, owner, clock, "vip_byteio_port", __FILE__), + device_slot_interface(mconfig, *this), + m_write_inst(*this) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void vip_byteio_port_device::device_start() +{ + m_cart = dynamic_cast(get_card_device()); + + // resolve callbacks + m_write_inst.resolve_safe(); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void vip_byteio_port_device::device_reset() +{ +} + + +UINT8 vip_byteio_port_device::in_r() { UINT8 data = 0xff; if (m_cart != NULL) data = m_cart->vip_in_r(); return data; } +void vip_byteio_port_device::out_w(UINT8 data) { if (m_cart != NULL) m_cart->vip_out_w(data); } +READ_LINE_MEMBER( vip_byteio_port_device::ef3_r ) { int state = CLEAR_LINE; if (m_cart != NULL) state = m_cart->vip_ef3_r(); return state; } +READ_LINE_MEMBER( vip_byteio_port_device::ef4_r ) { int state = CLEAR_LINE; if (m_cart != NULL) state = m_cart->vip_ef4_r(); return state; } +WRITE_LINE_MEMBER( vip_byteio_port_device::q_w ) { if (m_cart != NULL) m_cart->vip_q_w(state); } + + +//------------------------------------------------- +// SLOT_INTERFACE( vip_byteio_cards ) +//------------------------------------------------- + +SLOT_INTERFACE_START( vip_byteio_cards ) + //SLOT_INTERFACE("exp2", VP576_BYTEIO) + SLOT_INTERFACE("ascii", VP620) +SLOT_INTERFACE_END diff --git a/src/devices/bus/vip/byteio.h b/src/devices/bus/vip/byteio.h new file mode 100644 index 00000000000..fd696975c7c --- /dev/null +++ b/src/devices/bus/vip/byteio.h @@ -0,0 +1,133 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + RCA Cosmac VIP Byte Input/Output port emulation + +********************************************************************** + + A IN 0 + B IN 1 + C IN 2 + D IN 3 + E IN 4 + F IN 5 + H IN 6 + J IN 7 + K INST + L _EF4 + M OUT 0 + N OUT 1 + P OUT 2 + R OUT 3 + S OUT 4 + T OUT 5 + U OUT 6 + V OUT 7 + W Q + X _EF3 + Y +5 V + Z GND + +**********************************************************************/ + +#pragma once + +#ifndef __VIP_BYTEIO_PORT__ +#define __VIP_BYTEIO_PORT__ + +#include "emu.h" + + + +//************************************************************************** +// CONSTANTS +//************************************************************************** + +#define VIP_BYTEIO_PORT_TAG "byteio" + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_VIP_BYTEIO_PORT_ADD(_tag, _slot_intf, _def_slot, _inst) \ + MCFG_DEVICE_ADD(_tag, VIP_BYTEIO_PORT, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) \ + downcast(device)->set_inst_callback(DEVCB_##_inst); + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> vip_byteio_port_device + +class device_vip_byteio_port_interface; + +class vip_byteio_port_device : public device_t, + public device_slot_interface +{ +public: + // construction/destruction + vip_byteio_port_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + template void set_inst_callback(_inst inst) { m_write_inst.set_callback(inst); } + + // computer interface + UINT8 in_r(); + void out_w(UINT8 data); + DECLARE_READ_LINE_MEMBER( ef3_r ); + DECLARE_READ_LINE_MEMBER( ef4_r ); + DECLARE_WRITE_LINE_MEMBER( q_w ); + + // cartridge interface + DECLARE_WRITE_LINE_MEMBER( inst_w ) { m_write_inst(state); } + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + devcb_write_line m_write_inst; + + device_vip_byteio_port_interface *m_cart; +}; + + +// ======================> device_vip_byteio_port_interface + +// class representing interface-specific live c64_expansion card +class device_vip_byteio_port_interface : public device_slot_card_interface +{ +public: + // construction/destruction + device_vip_byteio_port_interface(const machine_config &mconfig, device_t &device); + + virtual UINT8 vip_in_r() { return 0xff; }; + virtual void vip_out_w(UINT8 data) { }; + + virtual int vip_ef3_r() { return CLEAR_LINE; } + virtual int vip_ef4_r() { return CLEAR_LINE; } + + virtual void vip_q_w(int state) { }; + +protected: + vip_byteio_port_device *m_slot; +}; + + +// device type definition +extern const device_type VIP_BYTEIO_PORT; + + +// slot devices +#include "vp620.h" + +SLOT_INTERFACE_EXTERN( vip_byteio_cards ); + + + +#endif diff --git a/src/devices/bus/vip/exp.c b/src/devices/bus/vip/exp.c new file mode 100644 index 00000000000..4d83df7119a --- /dev/null +++ b/src/devices/bus/vip/exp.c @@ -0,0 +1,217 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + RCA Cosmac VIP Expansion Interface emulation + +**********************************************************************/ + +#include "exp.h" + + + +//************************************************************************** +// MACROS/CONSTANTS +//************************************************************************** + +#define LOG 0 + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type VIP_EXPANSION_SLOT = &device_creator; + + + +//************************************************************************** +// DEVICE VIP_EXPANSION CARD INTERFACE +//************************************************************************** + +//------------------------------------------------- +// device_vip_expansion_card_interface - constructor +//------------------------------------------------- + +device_vip_expansion_card_interface::device_vip_expansion_card_interface(const machine_config &mconfig, device_t &device) + : device_slot_card_interface(mconfig, device) +{ + m_slot = dynamic_cast(device.owner()); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// vip_expansion_slot_device - constructor +//------------------------------------------------- + +vip_expansion_slot_device::vip_expansion_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, VIP_EXPANSION_SLOT, "VIP expansion port", tag, owner, clock, "vip_expansion_slot", __FILE__), + device_slot_interface(mconfig, *this), + m_write_int(*this), + m_write_dma_out(*this), + m_write_dma_in(*this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void vip_expansion_slot_device::device_start() +{ + m_card = dynamic_cast(get_card_device()); + + // resolve callbacks + m_write_int.resolve_safe(); + m_write_dma_out.resolve_safe(); + m_write_dma_in.resolve_safe(); +} + + +//------------------------------------------------- +// program_r - program read +//------------------------------------------------- + +UINT8 vip_expansion_slot_device::program_r(address_space &space, offs_t offset, int cs, int cdef, int *minh) +{ + UINT8 data = 0; + + if (m_card != NULL) + { + data = m_card->vip_program_r(space, offset, cs, cdef, minh); + } + + return data; +} + + +//------------------------------------------------- +// program_w - program write +//------------------------------------------------- + +void vip_expansion_slot_device::program_w(address_space &space, offs_t offset, UINT8 data, int cdef, int *minh) +{ + if (m_card != NULL) + { + m_card->vip_program_w(space, offset, data, cdef, minh); + } +} + + +//------------------------------------------------- +// io_r - io read +//------------------------------------------------- + +UINT8 vip_expansion_slot_device::io_r(address_space &space, offs_t offset) +{ + UINT8 data = 0; + + if (m_card != NULL) + { + data = m_card->vip_io_r(space, offset); + } + + return data; +} + + +//------------------------------------------------- +// io_w - io write +//------------------------------------------------- + +void vip_expansion_slot_device::io_w(address_space &space, offs_t offset, UINT8 data) +{ + if (m_card != NULL) + { + m_card->vip_io_w(space, offset, data); + } +} + + +//------------------------------------------------- +// dma_r - dma read +//------------------------------------------------- + +UINT8 vip_expansion_slot_device::dma_r(address_space &space, offs_t offset) +{ + UINT8 data = 0; + + if (m_card != NULL) + { + data = m_card->vip_dma_r(space, offset); + } + + return data; +} + + +//------------------------------------------------- +// dma_w - dma write +//------------------------------------------------- + +void vip_expansion_slot_device::dma_w(address_space &space, offs_t offset, UINT8 data) +{ + if (m_card != NULL) + { + m_card->vip_dma_w(space, offset, data); + } +} + + +//------------------------------------------------- +// screen_update - +//------------------------------------------------- + +UINT32 vip_expansion_slot_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + bool value = false; + + if (m_card != NULL) + { + value = m_card->vip_screen_update(screen, bitmap, cliprect); + } + + return value; +} + +READ_LINE_MEMBER( vip_expansion_slot_device::ef1_r ) { int state = CLEAR_LINE; if (m_card != NULL) state = m_card->vip_ef1_r(); return state; } +READ_LINE_MEMBER( vip_expansion_slot_device::ef3_r ) { int state = CLEAR_LINE; if (m_card != NULL) state = m_card->vip_ef3_r(); return state; } +READ_LINE_MEMBER( vip_expansion_slot_device::ef4_r ) { int state = CLEAR_LINE; if (m_card != NULL) state = m_card->vip_ef4_r(); return state; } +void vip_expansion_slot_device::sc_w(int data) { if (m_card != NULL) m_card->vip_sc_w(data); } +WRITE_LINE_MEMBER( vip_expansion_slot_device::q_w ) { if (m_card != NULL) m_card->vip_q_w(state); } +WRITE_LINE_MEMBER( vip_expansion_slot_device::run_w ) { if (m_card != NULL) m_card->vip_run_w(state); } + + + +//------------------------------------------------- +// SLOT_INTERFACE vip_expansion_cards ) +//------------------------------------------------- + +// slot devices +#include "vp550.h" +#include "vp570.h" +#include "vp575.h" +#include "vp585.h" +#include "vp590.h" +#include "vp595.h" +#include "vp700.h" + +SLOT_INTERFACE_START( vip_expansion_cards ) + SLOT_INTERFACE("super", VP550) + //SLOT_INTERFACE("eprom", VP560) + //SLOT_INTERFACE("eprommer", VP565) + SLOT_INTERFACE("ram", VP570) + SLOT_INTERFACE("exp", VP575) + //SLOT_INTERFACE("exp2", VP576_EXP) + SLOT_INTERFACE("keypad", VP585) + SLOT_INTERFACE("color", VP590) + SLOT_INTERFACE("simple", VP595) + SLOT_INTERFACE("basic", VP700) +SLOT_INTERFACE_END diff --git a/src/devices/bus/vip/exp.h b/src/devices/bus/vip/exp.h new file mode 100644 index 00000000000..37a33482db8 --- /dev/null +++ b/src/devices/bus/vip/exp.h @@ -0,0 +1,167 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + RCA Cosmac VIP Expansion Interface emulation + +********************************************************************** + + CLOCK 1 A _MWR + _EF4 2 B TPA + _EF3 3 C MA0 + XTAL 4 D MA1 + _EF1 5 E MA2 + N0 6 F MA3 + N1 7 H MA4 + N2 8 J MA5 + SPOT 9 K MA6 + _SYNC 10 L MA7 + TPB 11 M BUS 0 + SC0 12 N BUS 1 + _INTERRUPT 13 P BUS 2 + SC1 14 R BUS 3 + _DMA-OUT 15 S BUS 4 + Q 16 T BUS 5 + _DMA-IN 17 U BUS 6 + RUN 18 V BUS 7 + MINH 19 W _MRD + _CDEF 20 X CS + +5 V 21 Y +5 V + GND 22 Z GND + +**********************************************************************/ + +#pragma once + +#ifndef __VIP_EXPANSION_SLOT__ +#define __VIP_EXPANSION_SLOT__ + +#include "emu.h" + + + +//************************************************************************** +// CONSTANTS +//************************************************************************** + +#define VIP_EXPANSION_SLOT_TAG "exp" + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_VIP_EXPANSION_SLOT_ADD(_tag, _clock, _slot_intf, _def_slot) \ + MCFG_DEVICE_ADD(_tag, VIP_EXPANSION_SLOT, _clock) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) + + +#define MCFG_VIP_EXPANSION_SLOT_INT_CALLBACK(_write) \ + devcb = &vip_expansion_slot_device::set_int_wr_callback(*device, DEVCB_##_write); + +#define MCFG_VIP_EXPANSION_SLOT_DMA_OUT_CALLBACK(_write) \ + devcb = &vip_expansion_slot_device::set_dma_out_wr_callback(*device, DEVCB_##_write); + +#define MCFG_VIP_EXPANSION_SLOT_DMA_IN_CALLBACK(_write) \ + devcb = &vip_expansion_slot_device::set_dma_in_wr_callback(*device, DEVCB_##_write); + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> vip_expansion_slot_device + +class device_vip_expansion_card_interface; + +class vip_expansion_slot_device : public device_t, + public device_slot_interface +{ +public: + // construction/destruction + vip_expansion_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + template static devcb_base &set_int_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_int.set_callback(object); } + template static devcb_base &set_dma_out_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_dma_out.set_callback(object); } + template static devcb_base &set_dma_in_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_dma_in.set_callback(object); } + + // computer interface + UINT8 program_r(address_space &space, offs_t offset, int cs, int cdef, int *minh); + void program_w(address_space &space, offs_t offset, UINT8 data, int cdef, int *minh); + UINT8 io_r(address_space &space, offs_t offset); + void io_w(address_space &space, offs_t offset, UINT8 data); + UINT8 dma_r(address_space &space, offs_t offset); + void dma_w(address_space &space, offs_t offset, UINT8 data); + UINT32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); + DECLARE_READ_LINE_MEMBER( ef1_r ); + DECLARE_READ_LINE_MEMBER( ef3_r ); + DECLARE_READ_LINE_MEMBER( ef4_r ); + void sc_w(int data); + DECLARE_WRITE_LINE_MEMBER( q_w ); + DECLARE_WRITE_LINE_MEMBER( run_w ); + + // cartridge interface + DECLARE_WRITE_LINE_MEMBER( interrupt_w ) { m_write_int(state); } + DECLARE_WRITE_LINE_MEMBER( dma_out_w ) { m_write_dma_out(state); } + DECLARE_WRITE_LINE_MEMBER( dma_in_w ) { m_write_dma_in(state); } + +protected: + // device-level overrides + virtual void device_start(); + + devcb_write_line m_write_int; + devcb_write_line m_write_dma_out; + devcb_write_line m_write_dma_in; + + device_vip_expansion_card_interface *m_card; +}; + + +// ======================> device_vip_expansion_card_interface + +class device_vip_expansion_card_interface : public device_slot_card_interface +{ + friend class vip_expansion_slot_device; + +public: + // construction/destruction + device_vip_expansion_card_interface(const machine_config &mconfig, device_t &device); + +protected: + // runtime + virtual UINT8 vip_program_r(address_space &space, offs_t offset, int cs, int cdef, int *minh) { return 0xff; }; + virtual void vip_program_w(address_space &space, offs_t offset, UINT8 data, int cdef, int *minh) { }; + + virtual UINT8 vip_io_r(address_space &space, offs_t offset) { return 0xff; }; + virtual void vip_io_w(address_space &space, offs_t offset, UINT8 data) { }; + + virtual UINT8 vip_dma_r(address_space &space, offs_t offset) { return 0xff; }; + virtual void vip_dma_w(address_space &space, offs_t offset, UINT8 data) { }; + + virtual UINT32 vip_screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) { return 0; } + + virtual int vip_ef1_r() { return CLEAR_LINE; } + virtual int vip_ef3_r() { return CLEAR_LINE; } + virtual int vip_ef4_r() { return CLEAR_LINE; } + + virtual void vip_sc_w(int data) { }; + + virtual void vip_q_w(int state) { }; + + virtual void vip_run_w(int state) { }; + + vip_expansion_slot_device *m_slot; +}; + + +// device type definition +extern const device_type VIP_EXPANSION_SLOT; + + +SLOT_INTERFACE_EXTERN( vip_expansion_cards ); + + + +#endif diff --git a/src/devices/bus/vip/vp550.c b/src/devices/bus/vip/vp550.c new file mode 100644 index 00000000000..c5f4ed201e4 --- /dev/null +++ b/src/devices/bus/vip/vp550.c @@ -0,0 +1,249 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + RCA VIP Super Sound System VP550 emulation + +**********************************************************************/ + +/* + + TODO: + + - VP551 + +*/ + +#include "vp550.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define LOG 0 + + +#define CDP1863_A_TAG "u1" +#define CDP1863_B_TAG "u2" + + +enum +{ + CHANNEL_A = 0, + CHANNEL_B +}; + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type VP550 = &device_creator; + + +//------------------------------------------------- +// MACHINE_CONFIG_FRAGMENT( vp550 ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( vp550 ) + MCFG_SPEAKER_STANDARD_MONO("mono") + + MCFG_CDP1863_ADD(CDP1863_A_TAG, 0, 0) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 1.00) + + MCFG_CDP1863_ADD(CDP1863_B_TAG, 0, 0) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 1.00) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor vp550_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( vp550 ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// vp550_device - constructor +//------------------------------------------------- + +vp550_device::vp550_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, VP550, "VP550", tag, owner, clock, "vp550", __FILE__), + device_vip_expansion_card_interface(mconfig, *this), + m_pfg_a(*this, CDP1863_A_TAG), + m_pfg_b(*this, CDP1863_B_TAG) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void vp550_device::device_start() +{ + // allocate timers + m_sync_timer = timer_alloc(); + m_sync_timer->adjust(attotime::from_hz(50), 0, attotime::from_hz(50)); + m_sync_timer->enable(0); +} + + +//------------------------------------------------- +// device_timer - handler timer events +//------------------------------------------------- + +void vp550_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + if (LOG) logerror("VP550 '%s' Interrupt\n", tag()); + + m_slot->interrupt_w(ASSERT_LINE); +} + + +//------------------------------------------------- +// vip_program_w - program write +//------------------------------------------------- + +void vp550_device::vip_program_w(address_space &space, offs_t offset, UINT8 data, int cdef, int *minh) +{ + if (BIT(offset, 15)) + { + *minh = 1; + + switch (offset & 0x03) + { + case 1: m_pfg_a->str_w(data); break; + case 2: m_pfg_b->str_w(data); break; + case 3: octave_w(space, offset, data); break; + } + + switch ((offset >> 4) & 0x03) + { + case 1: vlmna_w(space, offset, data); break; + case 2: vlmnb_w(space, offset, data); break; + case 3: sync_w(space, offset, data); break; + } + } +} + + +//------------------------------------------------- +// vip_sc_w - status code write +//------------------------------------------------- + +void vp550_device::vip_sc_w(int data) +{ + if (BIT(data, 1)) + { + if (LOG) logerror("VP550 '%s' Clear Interrupt\n", tag()); + + m_slot->interrupt_w(CLEAR_LINE); + } +} + + +//------------------------------------------------- +// vip_q_w - Q write +//------------------------------------------------- + +void vp550_device::vip_q_w(int state) +{ + m_pfg_a->oe_w(state); + m_pfg_b->oe_w(state); +} + + +//------------------------------------------------- +// vip_run_w - RUN write +//------------------------------------------------- + +void vp550_device::vip_run_w(int state) +{ + if (!state) + { + m_pfg_a->reset(); + m_pfg_b->reset(); + } +} + + +//------------------------------------------------- +// octave_w - octave select write +//------------------------------------------------- + +WRITE8_MEMBER( vp550_device::octave_w ) +{ + int channel = (data >> 2) & 0x03; + int clock2 = 0; + + if (data & 0x10) + { + switch (data & 0x03) + { + case 0: clock2 = m_slot->clock() / 8; break; + case 1: clock2 = m_slot->clock() / 4; break; + case 2: clock2 = m_slot->clock() / 2; break; + case 3: clock2 = m_slot->clock(); break; + } + } + + switch (channel) + { + case CHANNEL_A: m_pfg_a->set_clk2(clock2); break; + case CHANNEL_B: m_pfg_b->set_clk2(clock2); break; + } + + if (LOG) logerror("VP550 '%s' Clock %c: %u Hz\n", tag(), 'A' + channel, clock2); +} + + +//------------------------------------------------- +// vlmna_w - channel A amplitude write +//------------------------------------------------- + +WRITE8_MEMBER( vp550_device::vlmna_w ) +{ + if (LOG) logerror("VP550 '%s' A Volume: %u\n", tag(), data & 0x0f); + + float gain = (data & 0x0f) * 0.0666; + + m_pfg_a->set_output_gain(0, gain); +} + + +//------------------------------------------------- +// vlmnb_w - channel B amplitude write +//------------------------------------------------- + +WRITE8_MEMBER( vp550_device::vlmnb_w ) +{ + if (LOG) logerror("VP550 '%s' B Volume: %u\n", tag(), data & 0x0f); + + float gain = (data & 0x0f) * 0.0666; + + m_pfg_b->set_output_gain(0, gain); +} + + +//------------------------------------------------- +// sync_w - interrupt enable write +//------------------------------------------------- + +WRITE8_MEMBER( vp550_device::sync_w ) +{ + if (LOG) logerror("VP550 '%s' Interrupt Enable: %u\n", tag(), BIT(data, 0)); + + m_sync_timer->enable(BIT(data, 0)); +} diff --git a/src/devices/bus/vip/vp550.h b/src/devices/bus/vip/vp550.h new file mode 100644 index 00000000000..1045871b5d7 --- /dev/null +++ b/src/devices/bus/vip/vp550.h @@ -0,0 +1,66 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + RCA VIP Super Sound System VP550 emulation + +**********************************************************************/ + +#pragma once + +#ifndef __VP550__ +#define __VP550__ + +#include "emu.h" +#include "exp.h" +#include "sound/cdp1863.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> vp550_device + +class vp550_device : public device_t, + public device_vip_expansion_card_interface +{ +public: + // construction/destruction + vp550_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + + // not really public + DECLARE_WRITE8_MEMBER( octave_w ); + DECLARE_WRITE8_MEMBER( vlmna_w ); + DECLARE_WRITE8_MEMBER( vlmnb_w ); + DECLARE_WRITE8_MEMBER( sync_w ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + // device_vip_expansion_card_interface overrides + virtual void vip_program_w(address_space &space, offs_t offset, UINT8 data, int cdef, int *minh); + virtual void vip_sc_w(int data); + virtual void vip_q_w(int state); + virtual void vip_run_w(int state); + +private: + required_device m_pfg_a; + required_device m_pfg_b; + + // timers + emu_timer *m_sync_timer; +}; + + +// device type definition +extern const device_type VP550; + + +#endif diff --git a/src/devices/bus/vip/vp570.c b/src/devices/bus/vip/vp570.c new file mode 100644 index 00000000000..42ec4119c21 --- /dev/null +++ b/src/devices/bus/vip/vp570.c @@ -0,0 +1,120 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + RCA VIP Expansion Board VP-570 emulation + +**********************************************************************/ + +#include "vp570.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type VP570 = &device_creator; + + +//------------------------------------------------- +// INPUT_PORTS( vp570 ) +//------------------------------------------------- + +static INPUT_PORTS_START( vp570 ) + PORT_START("BASE") + PORT_DIPNAME( 0x07, 0x01, "Address Range" ) + PORT_DIPSETTING( 0x00, "0000 thru 0FFF" ) + PORT_DIPSETTING( 0x01, "1000 thru 1FFF" ) + PORT_DIPSETTING( 0x02, "2000 thru 2FFF" ) + PORT_DIPSETTING( 0x03, "3000 thru 3FFF" ) + PORT_DIPSETTING( 0x04, "4000 thru 4FFF" ) + PORT_DIPSETTING( 0x05, "5000 thru 50FFF" ) + PORT_DIPSETTING( 0x06, "6000 thru 6FFF" ) + PORT_DIPSETTING( 0x07, "7000 thru 7FFF" ) + + PORT_START("SW1") + PORT_DIPNAME( 0x01, 0x01, "Write Protect" ) + PORT_DIPSETTING( 0x01, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x00, DEF_STR( On ) ) +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor vp570_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( vp570 ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// vp570_device - constructor +//------------------------------------------------- + +vp570_device::vp570_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, VP570, "VP570", tag, owner, clock, "vp570", __FILE__), + device_vip_expansion_card_interface(mconfig, *this), + m_ram(*this, "ram"), + m_base(*this, "BASE"), + m_sw1(*this, "SW1") +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void vp570_device::device_start() +{ + m_ram.allocate(0x1000); +} + + +//------------------------------------------------- +// vip_program_r - program read +//------------------------------------------------- + +UINT8 vp570_device::vip_program_r(address_space &space, offs_t offset, int cs, int cdef, int *minh) +{ + UINT8 data = 0xff; + + offs_t base = m_base->read() << 12; + + if (offset >= base && offset < base + 0x1000) + { + *minh = 1; + + data = m_ram[offset & 0xfff]; + } + + return data; +} + + +//------------------------------------------------- +// vip_program_w - program write +//------------------------------------------------- + +void vp570_device::vip_program_w(address_space &space, offs_t offset, UINT8 data, int cdef, int *minh) +{ + offs_t base = m_base->read() << 12; + + if (offset >= base && offset < base + 0x1000) + { + *minh = 1; + + if (m_sw1->read()) + { + m_ram[offset & 0xfff] = data; + } + } +} diff --git a/src/devices/bus/vip/vp570.h b/src/devices/bus/vip/vp570.h new file mode 100644 index 00000000000..2a382a064f5 --- /dev/null +++ b/src/devices/bus/vip/vp570.h @@ -0,0 +1,54 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + RCA VIP Memory Expansion Board VP-570 emulation + +**********************************************************************/ + +#pragma once + +#ifndef __VP570__ +#define __VP570__ + +#include "emu.h" +#include "exp.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> vp570_device + +class vp570_device : public device_t, + public device_vip_expansion_card_interface +{ +public: + // construction/destruction + vp570_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual ioport_constructor device_input_ports() const; + +protected: + // device-level overrides + virtual void device_start(); + + // device_vip_expansion_card_interface overrides + virtual UINT8 vip_program_r(address_space &space, offs_t offset, int cs, int cdef, int *minh); + virtual void vip_program_w(address_space &space, offs_t offset, UINT8 data, int cdef, int *minh); + +private: + optional_shared_ptr m_ram; + required_ioport m_base; + required_ioport m_sw1; +}; + + +// device type definition +extern const device_type VP570; + + +#endif diff --git a/src/devices/bus/vip/vp575.c b/src/devices/bus/vip/vp575.c new file mode 100644 index 00000000000..c7801e9c414 --- /dev/null +++ b/src/devices/bus/vip/vp575.c @@ -0,0 +1,317 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + RCA VIP Expansion Board VP-575 emulation + +**********************************************************************/ + +#include "vp575.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type VP575 = &device_creator; + + +//------------------------------------------------- +// VIP_EXPANSION_INTERFACE( expansion_intf ) +//------------------------------------------------- + +void vp575_device::update_interrupts() +{ + int interrupt = CLEAR_LINE; + int dma_out = CLEAR_LINE; + int dma_in = CLEAR_LINE; + + for (int i = 0; i < MAX_SLOTS; i++) + { + interrupt |= m_int[i]; + dma_out |= m_dma_out[i]; + dma_in |= m_dma_in[i]; + } + + m_slot->interrupt_w(interrupt); + m_slot->dma_out_w(dma_out); + m_slot->dma_in_w(dma_in); +} + + +//------------------------------------------------- +// MACHINE_CONFIG_FRAGMENT( vp575 ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( vp575 ) + MCFG_VIP_EXPANSION_SLOT_ADD("exp1", XTAL_3_52128MHz/2, vip_expansion_cards, NULL) + MCFG_VIP_EXPANSION_SLOT_INT_CALLBACK(WRITELINE(vp575_device, exp1_int_w)) + MCFG_VIP_EXPANSION_SLOT_DMA_OUT_CALLBACK(WRITELINE(vp575_device, exp1_dma_out_w)) + MCFG_VIP_EXPANSION_SLOT_DMA_IN_CALLBACK(WRITELINE(vp575_device, exp1_dma_in_w)) + + MCFG_VIP_EXPANSION_SLOT_ADD("exp2", XTAL_3_52128MHz/2, vip_expansion_cards, NULL) + MCFG_VIP_EXPANSION_SLOT_INT_CALLBACK(WRITELINE(vp575_device, exp2_int_w)) + MCFG_VIP_EXPANSION_SLOT_DMA_OUT_CALLBACK(WRITELINE(vp575_device, exp2_dma_out_w)) + MCFG_VIP_EXPANSION_SLOT_DMA_IN_CALLBACK(WRITELINE(vp575_device, exp2_dma_in_w)) + + MCFG_VIP_EXPANSION_SLOT_ADD("exp3", XTAL_3_52128MHz/2, vip_expansion_cards, NULL) + MCFG_VIP_EXPANSION_SLOT_INT_CALLBACK(WRITELINE(vp575_device, exp3_int_w)) + MCFG_VIP_EXPANSION_SLOT_DMA_OUT_CALLBACK(WRITELINE(vp575_device, exp3_dma_out_w)) + MCFG_VIP_EXPANSION_SLOT_DMA_IN_CALLBACK(WRITELINE(vp575_device, exp3_dma_in_w)) + + MCFG_VIP_EXPANSION_SLOT_ADD("exp4", XTAL_3_52128MHz/2, vip_expansion_cards, NULL) + MCFG_VIP_EXPANSION_SLOT_INT_CALLBACK(WRITELINE(vp575_device, exp4_int_w)) + MCFG_VIP_EXPANSION_SLOT_DMA_OUT_CALLBACK(WRITELINE(vp575_device, exp4_dma_out_w)) + MCFG_VIP_EXPANSION_SLOT_DMA_IN_CALLBACK(WRITELINE(vp575_device, exp4_dma_in_w)) + + MCFG_VIP_EXPANSION_SLOT_ADD("exp5", XTAL_3_52128MHz/2, vip_expansion_cards, NULL) + MCFG_VIP_EXPANSION_SLOT_INT_CALLBACK(WRITELINE(vp575_device, exp5_int_w)) + MCFG_VIP_EXPANSION_SLOT_DMA_OUT_CALLBACK(WRITELINE(vp575_device, exp5_dma_out_w)) + MCFG_VIP_EXPANSION_SLOT_DMA_IN_CALLBACK(WRITELINE(vp575_device, exp5_dma_in_w)) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor vp575_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( vp575 ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// vp575_device - constructor +//------------------------------------------------- + +vp575_device::vp575_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, VP575, "VP575", tag, owner, clock, "vp575", __FILE__), + device_vip_expansion_card_interface(mconfig, *this) +{ + for (int i = 0; i < MAX_SLOTS; i++) + { + m_int[i] = CLEAR_LINE; + m_dma_out[i] = CLEAR_LINE; + m_dma_in[i] = CLEAR_LINE; + } +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void vp575_device::device_start() +{ + // find devices + m_expansion_slot[0] = dynamic_cast(subdevice("exp1")); + m_expansion_slot[1] = dynamic_cast(subdevice("exp2")); + m_expansion_slot[2] = dynamic_cast(subdevice("exp3")); + m_expansion_slot[3] = dynamic_cast(subdevice("exp4")); + m_expansion_slot[4] = dynamic_cast(subdevice("exp5")); +} + + +//------------------------------------------------- +// vip_program_r - program read +//------------------------------------------------- + +UINT8 vp575_device::vip_program_r(address_space &space, offs_t offset, int cs, int cdef, int *minh) +{ + UINT8 data = 0xff; + + for (int i = 0; i < MAX_SLOTS; i++) + { + data &= m_expansion_slot[i]->program_r(space, offset, cs, cdef, minh); + } + + return data; +} + + +//------------------------------------------------- +// vip_program_w - program write +//------------------------------------------------- + +void vp575_device::vip_program_w(address_space &space, offs_t offset, UINT8 data, int cdef, int *minh) +{ + for (int i = 0; i < MAX_SLOTS; i++) + { + m_expansion_slot[i]->program_w(space, offset, data, cdef, minh); + } +} + + +//------------------------------------------------- +// vip_io_r - I/O read +//------------------------------------------------- + +UINT8 vp575_device::vip_io_r(address_space &space, offs_t offset) +{ + UINT8 data = 0xff; + + for (int i = 0; i < MAX_SLOTS; i++) + { + data &= m_expansion_slot[i]->io_r(space, offset); + } + + return data; +} + + +//------------------------------------------------- +// vip_io_w - I/O write +//------------------------------------------------- + +void vp575_device::vip_io_w(address_space &space, offs_t offset, UINT8 data) +{ + for (int i = 0; i < MAX_SLOTS; i++) + { + m_expansion_slot[i]->io_w(space, offset, data); + } +} + + +//------------------------------------------------- +// vip_dma_r - DMA read +//------------------------------------------------- + +UINT8 vp575_device::vip_dma_r(address_space &space, offs_t offset) +{ + UINT8 data = 0xff; + + for (int i = 0; i < MAX_SLOTS; i++) + { + data &= m_expansion_slot[i]->dma_r(space, offset); + } + + return data; +} + + +//------------------------------------------------- +// vip_dma_w - DMA write +//------------------------------------------------- + +void vp575_device::vip_dma_w(address_space &space, offs_t offset, UINT8 data) +{ + for (int i = 0; i < MAX_SLOTS; i++) + { + m_expansion_slot[i]->dma_w(space, offset, data); + } +} + + +//------------------------------------------------- +// vip_screen_update - screen update +//------------------------------------------------- + +UINT32 vp575_device::vip_screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + UINT32 data = 0; + + for (int i = 0; i < MAX_SLOTS; i++) + { + data |= m_expansion_slot[i]->screen_update(screen, bitmap, cliprect); + } + + return data; +} + + +//------------------------------------------------- +// vip_ef1_r - EF1 flag read +//------------------------------------------------- + +int vp575_device::vip_ef1_r() +{ + int state = CLEAR_LINE; + + for (int i = 0; i < MAX_SLOTS; i++) + { + state |= m_expansion_slot[i]->ef1_r(); + } + + return state; +} + + +//------------------------------------------------- +// vip_ef3_r - EF3 flag read +//------------------------------------------------- + +int vp575_device::vip_ef3_r() +{ + int state = CLEAR_LINE; + + for (int i = 0; i < MAX_SLOTS; i++) + { + state |= m_expansion_slot[i]->ef3_r(); + } + + return state; +} + + +//------------------------------------------------- +// vip_ef4_r - EF4 flag read +//------------------------------------------------- + +int vp575_device::vip_ef4_r() +{ + int state = CLEAR_LINE; + + for (int i = 0; i < MAX_SLOTS; i++) + { + state |= m_expansion_slot[i]->ef4_r(); + } + + return state; +} + + +//------------------------------------------------- +// vip_sc_w - status code write +//------------------------------------------------- + +void vp575_device::vip_sc_w(int data) +{ + for (int i = 0; i < MAX_SLOTS; i++) + { + m_expansion_slot[i]->sc_w(data); + } +} + + +//------------------------------------------------- +// vip_q_w - Q write +//------------------------------------------------- + +void vp575_device::vip_q_w(int state) +{ + for (int i = 0; i < MAX_SLOTS; i++) + { + m_expansion_slot[i]->q_w(state); + } +} + + +//------------------------------------------------- +// vip_run_w - RUN write +//------------------------------------------------- + +void vp575_device::vip_run_w(int state) +{ + for (int i = 0; i < MAX_SLOTS; i++) + { + m_expansion_slot[i]->run_w(state); + } +} diff --git a/src/devices/bus/vip/vp575.h b/src/devices/bus/vip/vp575.h new file mode 100644 index 00000000000..83ea31fd277 --- /dev/null +++ b/src/devices/bus/vip/vp575.h @@ -0,0 +1,96 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + RCA VIP Expansion Board VP-575 emulation + +**********************************************************************/ + +#pragma once + +#ifndef __VP575__ +#define __VP575__ + +#include "emu.h" +#include "exp.h" + + + +//************************************************************************** +// MACROS/CONSTANTS +//************************************************************************** + +#define MAX_SLOTS 5 + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> vp575_device + +class vp575_device : public device_t, + public device_vip_expansion_card_interface +{ +public: + // construction/destruction + vp575_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + + // not really public + DECLARE_WRITE_LINE_MEMBER( exp1_int_w ) { m_int[0] = state; update_interrupts(); } + DECLARE_WRITE_LINE_MEMBER( exp2_int_w ) { m_int[1] = state; update_interrupts(); } + DECLARE_WRITE_LINE_MEMBER( exp3_int_w ) { m_int[2] = state; update_interrupts(); } + DECLARE_WRITE_LINE_MEMBER( exp4_int_w ) { m_int[3] = state; update_interrupts(); } + DECLARE_WRITE_LINE_MEMBER( exp5_int_w ) { m_int[4] = state; update_interrupts(); } + + DECLARE_WRITE_LINE_MEMBER( exp1_dma_out_w ) { m_dma_out[0] = state; update_interrupts(); } + DECLARE_WRITE_LINE_MEMBER( exp2_dma_out_w ) { m_dma_out[1] = state; update_interrupts(); } + DECLARE_WRITE_LINE_MEMBER( exp3_dma_out_w ) { m_dma_out[2] = state; update_interrupts(); } + DECLARE_WRITE_LINE_MEMBER( exp4_dma_out_w ) { m_dma_out[3] = state; update_interrupts(); } + DECLARE_WRITE_LINE_MEMBER( exp5_dma_out_w ) { m_dma_out[4] = state; update_interrupts(); } + + DECLARE_WRITE_LINE_MEMBER( exp1_dma_in_w ) { m_dma_in[0] = state; update_interrupts(); } + DECLARE_WRITE_LINE_MEMBER( exp2_dma_in_w ) { m_dma_in[1] = state; update_interrupts(); } + DECLARE_WRITE_LINE_MEMBER( exp3_dma_in_w ) { m_dma_in[2] = state; update_interrupts(); } + DECLARE_WRITE_LINE_MEMBER( exp4_dma_in_w ) { m_dma_in[3] = state; update_interrupts(); } + DECLARE_WRITE_LINE_MEMBER( exp5_dma_in_w ) { m_dma_in[4] = state; update_interrupts(); } + + void update_interrupts(); + +protected: + // device-level overrides + virtual void device_start(); + + // device_vip_expansion_card_interface overrides + virtual UINT8 vip_program_r(address_space &space, offs_t offset, int cs, int cdef, int *minh); + virtual void vip_program_w(address_space &space, offs_t offset, UINT8 data, int cdef, int *minh); + virtual UINT8 vip_io_r(address_space &space, offs_t offset); + virtual void vip_io_w(address_space &space, offs_t offset, UINT8 data); + virtual UINT8 vip_dma_r(address_space &space, offs_t offset); + virtual void vip_dma_w(address_space &space, offs_t offset, UINT8 data); + virtual UINT32 vip_screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); + virtual int vip_ef1_r(); + virtual int vip_ef3_r(); + virtual int vip_ef4_r(); + virtual void vip_sc_w(int data); + virtual void vip_q_w(int state); + virtual void vip_run_w(int state); + +private: + vip_expansion_slot_device *m_expansion_slot[MAX_SLOTS]; + + int m_int[MAX_SLOTS]; + int m_dma_out[MAX_SLOTS]; + int m_dma_in[MAX_SLOTS]; +}; + + +// device type definition +extern const device_type VP575; + + +#endif diff --git a/src/devices/bus/vip/vp585.c b/src/devices/bus/vip/vp585.c new file mode 100644 index 00000000000..dd51edebcff --- /dev/null +++ b/src/devices/bus/vip/vp585.c @@ -0,0 +1,132 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + RCA VIP Expansion Keypad Interface Board VP585 emulation + +**********************************************************************/ + +#include "vp585.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type VP585 = &device_creator; + + +//------------------------------------------------- +// INPUT_PORTS( vp585 ) +//------------------------------------------------- + +static INPUT_PORTS_START( vp585 ) + PORT_START("J1") + PORT_BIT( 0x0001, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Player 1 Keypad 0") + PORT_BIT( 0x0002, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Player 1 Keypad 1") + PORT_BIT( 0x0004, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Player 1 Keypad 2") + PORT_BIT( 0x0008, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Player 1 Keypad 3") + PORT_BIT( 0x0010, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Player 1 Keypad 4") + PORT_BIT( 0x0020, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Player 1 Keypad 5") + PORT_BIT( 0x0040, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Player 1 Keypad 6") + PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Player 1 Keypad 7") + PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Player 1 Keypad 8") + PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Player 1 Keypad 9") + PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Player 1 Keypad A") + PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Player 1 Keypad B") + PORT_BIT( 0x1000, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Player 1 Keypad C") + PORT_BIT( 0x2000, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Player 1 Keypad D") + PORT_BIT( 0x4000, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Player 1 Keypad E") + PORT_BIT( 0x8000, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Player 1 Keypad F") + + PORT_START("J2") + PORT_BIT( 0x0001, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Player 2 Keypad 0") + PORT_BIT( 0x0002, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Player 2 Keypad 1") + PORT_BIT( 0x0004, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Player 2 Keypad 2") + PORT_BIT( 0x0008, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Player 2 Keypad 3") + PORT_BIT( 0x0010, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Player 2 Keypad 4") + PORT_BIT( 0x0020, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Player 2 Keypad 5") + PORT_BIT( 0x0040, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Player 2 Keypad 6") + PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Player 2 Keypad 7") + PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Player 2 Keypad 8") + PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Player 2 Keypad 9") + PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Player 2 Keypad A") + PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Player 2 Keypad B") + PORT_BIT( 0x1000, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Player 2 Keypad C") + PORT_BIT( 0x2000, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Player 2 Keypad D") + PORT_BIT( 0x4000, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Player 2 Keypad E") + PORT_BIT( 0x8000, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Player 2 Keypad F") +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor vp585_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( vp585 ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// vp585_device - constructor +//------------------------------------------------- + +vp585_device::vp585_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, VP585, "VP585", tag, owner, clock, "vp585", __FILE__), + device_vip_expansion_card_interface(mconfig, *this), + m_j1(*this, "J1"), + m_j2(*this, "J2") +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void vp585_device::device_start() +{ + // state saving + save_item(NAME(m_keylatch)); +} + + +//------------------------------------------------- +// vip_io_w - I/O write +//------------------------------------------------- + +void vp585_device::vip_io_w(address_space &space, offs_t offset, UINT8 data) +{ + if (offset == 0x02) + { + m_keylatch = data & 0x0f; + } +} + + +//------------------------------------------------- +// vip_ef3_r - EF3 read +//------------------------------------------------- + +int vp585_device::vip_ef3_r() +{ + return BIT(m_j1->read(), m_keylatch) ? CLEAR_LINE : ASSERT_LINE; +} + + +//------------------------------------------------- +// vip_ef4_r - EF4 read +//------------------------------------------------- + +int vp585_device::vip_ef4_r() +{ + return BIT(m_j2->read(), m_keylatch) ? CLEAR_LINE : ASSERT_LINE; +} diff --git a/src/devices/bus/vip/vp585.h b/src/devices/bus/vip/vp585.h new file mode 100644 index 00000000000..2bda8647c57 --- /dev/null +++ b/src/devices/bus/vip/vp585.h @@ -0,0 +1,56 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + RCA VIP Expansion Keypad Interface Board VP585 emulation + +**********************************************************************/ + +#pragma once + +#ifndef __VP585__ +#define __VP585__ + +#include "emu.h" +#include "exp.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> vp585_device + +class vp585_device : public device_t, + public device_vip_expansion_card_interface +{ +public: + // construction/destruction + vp585_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual ioport_constructor device_input_ports() const; + +protected: + // device-level overrides + virtual void device_start(); + + // device_vip_expansion_card_interface overrides + virtual void vip_io_w(address_space &space, offs_t offset, UINT8 data); + virtual int vip_ef3_r(); + virtual int vip_ef4_r(); + +private: + required_ioport m_j1; + required_ioport m_j2; + + UINT8 m_keylatch; +}; + + +// device type definition +extern const device_type VP585; + + +#endif diff --git a/src/devices/bus/vip/vp590.c b/src/devices/bus/vip/vp590.c new file mode 100644 index 00000000000..e4a045388dd --- /dev/null +++ b/src/devices/bus/vip/vp590.c @@ -0,0 +1,261 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + RCA VIP Color Board VP590 emulation + +**********************************************************************/ + +#include "vp590.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define CDP1862_TAG "u2" +#define SCREEN_TAG ":screen" // hijack the VIP's screen since the CDP1861 chip would be removed from the PCB on real hardware + +#define COLOR_RAM_SIZE 0x100 + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type VP590 = &device_creator; + + +//------------------------------------------------- +// CDP1862_INTERFACE( cgc_intf ) +//------------------------------------------------- + +READ_LINE_MEMBER( vp590_device::rd_r ) +{ + return BIT(m_color, 1); +} + +READ_LINE_MEMBER( vp590_device::bd_r ) +{ + return BIT(m_color, 2); +} + +READ_LINE_MEMBER( vp590_device::gd_r ) +{ + return BIT(m_color, 3); +} + + +//------------------------------------------------- +// MACHINE_CONFIG_FRAGMENT( vp590 ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( vp590 ) + MCFG_DEVICE_ADD(CDP1862_TAG, CDP1862, CPD1862_CLOCK) + MCFG_CDP1861_RD_CALLBACK(DEVREADLINE(DEVICE_SELF, vp590_device, rd_r)) + MCFG_CDP1861_BD_CALLBACK(DEVREADLINE(DEVICE_SELF, vp590_device, bd_r)) + MCFG_CDP1861_GD_CALLBACK(DEVREADLINE(DEVICE_SELF, vp590_device, gd_r)) + MCFG_CDP1862_LUMINANCE(RES_R(510), RES_R(360), RES_K(1), RES_K(1.5)) // R3, R4, R5, R6 + MCFG_CDP1862_CHROMINANCE(RES_K(3.9), RES_K(10), RES_K(2), RES_K(3.3)) // R7, R8, R9, R10 + MCFG_VIDEO_SET_SCREEN(SCREEN_TAG) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor vp590_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( vp590 ); +} + + +//------------------------------------------------- +// INPUT_PORTS( vp590 ) +//------------------------------------------------- + +static INPUT_PORTS_START( vp590 ) + PORT_START("J1") + PORT_BIT( 0x0001, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Player 1 Keypad 0") + PORT_BIT( 0x0002, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Player 1 Keypad 1") + PORT_BIT( 0x0004, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Player 1 Keypad 2") + PORT_BIT( 0x0008, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Player 1 Keypad 3") + PORT_BIT( 0x0010, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Player 1 Keypad 4") + PORT_BIT( 0x0020, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Player 1 Keypad 5") + PORT_BIT( 0x0040, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Player 1 Keypad 6") + PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Player 1 Keypad 7") + PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Player 1 Keypad 8") + PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Player 1 Keypad 9") + PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Player 1 Keypad A") + PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Player 1 Keypad B") + PORT_BIT( 0x1000, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Player 1 Keypad C") + PORT_BIT( 0x2000, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Player 1 Keypad D") + PORT_BIT( 0x4000, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Player 1 Keypad E") + PORT_BIT( 0x8000, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Player 1 Keypad F") + + PORT_START("J2") + PORT_BIT( 0x0001, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Player 2 Keypad 0") + PORT_BIT( 0x0002, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Player 2 Keypad 1") + PORT_BIT( 0x0004, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Player 2 Keypad 2") + PORT_BIT( 0x0008, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Player 2 Keypad 3") + PORT_BIT( 0x0010, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Player 2 Keypad 4") + PORT_BIT( 0x0020, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Player 2 Keypad 5") + PORT_BIT( 0x0040, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Player 2 Keypad 6") + PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Player 2 Keypad 7") + PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Player 2 Keypad 8") + PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Player 2 Keypad 9") + PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Player 2 Keypad A") + PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Player 2 Keypad B") + PORT_BIT( 0x1000, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Player 2 Keypad C") + PORT_BIT( 0x2000, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Player 2 Keypad D") + PORT_BIT( 0x4000, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Player 2 Keypad E") + PORT_BIT( 0x8000, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Player 2 Keypad F") +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor vp590_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( vp590 ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// vp590_device - constructor +//------------------------------------------------- + +vp590_device::vp590_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, VP590, "VP590", tag, owner, clock, "vp590", __FILE__), + device_vip_expansion_card_interface(mconfig, *this), + m_cgc(*this, CDP1862_TAG), + m_color_ram(*this, "color_ram"), + m_j1(*this, "J1"), + m_j2(*this, "J2") +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void vp590_device::device_start() +{ + // allocate memory + m_color_ram.allocate(COLOR_RAM_SIZE); + + // state saving + save_item(NAME(m_a12)); + save_item(NAME(m_color)); + save_item(NAME(m_keylatch)); +} + + +//------------------------------------------------- +// vip_program_w - program write +//------------------------------------------------- + +void vp590_device::vip_program_w(address_space &space, offs_t offset, UINT8 data, int cdef, int *minh) +{ + if (offset >= 0xc000 && offset < 0xe000) + { + UINT8 mask = 0xff; + + m_a12 = (offset & 0x1000) ? 1 : 0; + + if (!m_a12) + { + // mask out A4 and A3 + mask = 0xe7; + } + + // write to CDP1822 + m_color_ram[offset & mask] = data << 1; + + m_cgc->con_w(0); + } +} + + +//------------------------------------------------- +// vip_io_w - I/O write +//------------------------------------------------- + +void vp590_device::vip_io_w(address_space &space, offs_t offset, UINT8 data) +{ + switch (offset) + { + case 0x02: + m_keylatch = data & 0x0f; + break; + + case 0x05: + m_cgc->bkg_w(1); + m_cgc->bkg_w(0); + break; + } +} + + +//------------------------------------------------- +// vip_dma_w - DMA write +//------------------------------------------------- + +void vp590_device::vip_dma_w(address_space &space, offs_t offset, UINT8 data) +{ + UINT8 mask = 0xff; + + if (!m_a12) + { + // mask out A4 and A3 + mask = 0xe7; + } + + m_color = m_color_ram[offset & mask]; + + m_cgc->dma_w(space, offset, data); +} + + +//------------------------------------------------- +// vip_screen_update - screen update +//------------------------------------------------- + +UINT32 vp590_device::vip_screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + m_cgc->screen_update(screen, bitmap, cliprect); + + return 0; +} + + +//------------------------------------------------- +// vip_ef3_r - EF3 read +//------------------------------------------------- + +int vp590_device::vip_ef3_r() +{ + return BIT(m_j1->read(), m_keylatch) ? CLEAR_LINE : ASSERT_LINE; +} + + +//------------------------------------------------- +// vip_ef4_r - EF4 read +//------------------------------------------------- + +int vp590_device::vip_ef4_r() +{ + return BIT(m_j2->read(), m_keylatch) ? CLEAR_LINE : ASSERT_LINE; +} diff --git a/src/devices/bus/vip/vp590.h b/src/devices/bus/vip/vp590.h new file mode 100644 index 00000000000..e4be2ab48fa --- /dev/null +++ b/src/devices/bus/vip/vp590.h @@ -0,0 +1,71 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + RCA VIP Color Board VP590 emulation + +**********************************************************************/ + +#pragma once + +#ifndef __VP590__ +#define __VP590__ + +#include "emu.h" +#include "machine/rescap.h" +#include "exp.h" +#include "video/cdp1862.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> vp590_device + +class vp590_device : public device_t, + public device_vip_expansion_card_interface +{ +public: + // construction/destruction + vp590_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual ioport_constructor device_input_ports() const; + + // not really public + DECLARE_READ_LINE_MEMBER( rd_r ); + DECLARE_READ_LINE_MEMBER( bd_r ); + DECLARE_READ_LINE_MEMBER( gd_r ); + +protected: + // device-level overrides + virtual void device_start(); + + // device_vip_expansion_card_interface overrides + virtual void vip_program_w(address_space &space, offs_t offset, UINT8 data, int cdef, int *minh); + virtual void vip_io_w(address_space &space, offs_t offset, UINT8 data); + virtual void vip_dma_w(address_space &space, offs_t offset, UINT8 data); + virtual UINT32 vip_screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); + virtual int vip_ef3_r(); + virtual int vip_ef4_r(); + +private: + required_device m_cgc; + optional_shared_ptr m_color_ram; + required_ioport m_j1; + required_ioport m_j2; + + int m_a12; + UINT8 m_color; + UINT8 m_keylatch; +}; + + +// device type definition +extern const device_type VP590; + + +#endif diff --git a/src/devices/bus/vip/vp595.c b/src/devices/bus/vip/vp595.c new file mode 100644 index 00000000000..d2ed10de18d --- /dev/null +++ b/src/devices/bus/vip/vp595.c @@ -0,0 +1,100 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + RCA VIP Simple Sound Board VP595 emulation + +**********************************************************************/ + +#include "vp595.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define CDP1863_TAG "u1" +#define CDP1863_XTAL 440560 + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type VP595 = &device_creator; + + +//------------------------------------------------- +// MACHINE_CONFIG_FRAGMENT( vp595 ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( vp595 ) + MCFG_SPEAKER_STANDARD_MONO("mono") + + MCFG_CDP1863_ADD(CDP1863_TAG, 0, CDP1863_XTAL) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.25) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor vp595_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( vp595 ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// vp595_device - constructor +//------------------------------------------------- + +vp595_device::vp595_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, VP595, "VP595", tag, owner, clock, "vp595", __FILE__), + device_vip_expansion_card_interface(mconfig, *this), + m_pfg(*this, CDP1863_TAG) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void vp595_device::device_start() +{ +} + + +//------------------------------------------------- +// vip_io_w - I/O write +//------------------------------------------------- + +void vp595_device::vip_io_w(address_space &space, offs_t offset, UINT8 data) +{ + if (offset == 0x03) + { + if (!data) data = 0x80; + + m_pfg->str_w(data); + } +} + + +//------------------------------------------------- +// vip_q_w - Q write +//------------------------------------------------- + +void vp595_device::vip_q_w(int state) +{ + m_pfg->oe_w(state); +} diff --git a/src/devices/bus/vip/vp595.h b/src/devices/bus/vip/vp595.h new file mode 100644 index 00000000000..bd7bcdbdbe7 --- /dev/null +++ b/src/devices/bus/vip/vp595.h @@ -0,0 +1,53 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + RCA VIP Simple Sound Board VP595 emulation + +**********************************************************************/ + +#pragma once + +#ifndef __VP595__ +#define __VP595__ + +#include "emu.h" +#include "exp.h" +#include "sound/cdp1863.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> vp595_device + +class vp595_device : public device_t, + public device_vip_expansion_card_interface +{ +public: + // construction/destruction + vp595_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + +protected: + // device-level overrides + virtual void device_start(); + + // device_vip_expansion_card_interface overrides + virtual void vip_io_w(address_space &space, offs_t offset, UINT8 data); + virtual void vip_q_w(int state); + +private: + required_device m_pfg; +}; + + +// device type definition +extern const device_type VP595; + + +#endif diff --git a/src/devices/bus/vip/vp620.c b/src/devices/bus/vip/vp620.c new file mode 100644 index 00000000000..42a00b37444 --- /dev/null +++ b/src/devices/bus/vip/vp620.c @@ -0,0 +1,103 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + RCA VIP ASCII Keyboard Interface VP-620 emulation + +**********************************************************************/ + +#include "vp620.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type VP620 = &device_creator; + + +//------------------------------------------------- +// ASCII_KEYBOARD_INTERFACE( kb_intf ) +//------------------------------------------------- + +WRITE8_MEMBER( vp620_device::kb_w ) +{ + m_keydata = data; + + m_slot->inst_w(0); + m_slot->inst_w(1); + + m_keystb = ASSERT_LINE; +} + +//------------------------------------------------- +// MACHINE_CONFIG_FRAGMENT( vp620 ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( vp620 ) + MCFG_DEVICE_ADD("keyboard", GENERIC_KEYBOARD, 0) + MCFG_GENERIC_KEYBOARD_CB(WRITE8(vp620_device, kb_w)) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor vp620_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( vp620 ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// vp620_device - constructor +//------------------------------------------------- + +vp620_device::vp620_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, VP620, "VP620", tag, owner, clock, "vp620", __FILE__), + device_vip_byteio_port_interface(mconfig, *this), + m_keydata(0), + m_keystb(CLEAR_LINE) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void vp620_device::device_start() +{ +} + + +//------------------------------------------------- +// vip_in_r - byte input read +//------------------------------------------------- + +UINT8 vp620_device::vip_in_r() +{ + return m_keydata; +} + + +//------------------------------------------------- +// vip_ef3_r - EF3 flag read +//------------------------------------------------- + +int vp620_device::vip_ef4_r() +{ + int state = m_keystb; + + m_keystb = CLEAR_LINE; + + return state; +} diff --git a/src/devices/bus/vip/vp620.h b/src/devices/bus/vip/vp620.h new file mode 100644 index 00000000000..67400cd2304 --- /dev/null +++ b/src/devices/bus/vip/vp620.h @@ -0,0 +1,57 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + RCA VIP ASCII Keyboard Interface VP-620 emulation + +**********************************************************************/ + +#pragma once + +#ifndef __VP620__ +#define __VP620__ + +#include "emu.h" +#include "byteio.h" +#include "machine/keyboard.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> vp620_device + +class vp620_device : public device_t, + public device_vip_byteio_port_interface +{ +public: + // construction/destruction + vp620_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + + // not really public + DECLARE_WRITE8_MEMBER( kb_w ); + +protected: + // device-level overrides + virtual void device_start(); + + // device_vip_byteio_port_interface overrides + virtual UINT8 vip_in_r(); + virtual int vip_ef4_r(); + +private: + UINT8 m_keydata; + int m_keystb; +}; + + +// device type definition +extern const device_type VP620; + + +#endif diff --git a/src/devices/bus/vip/vp700.c b/src/devices/bus/vip/vp700.c new file mode 100644 index 00000000000..7d9b32536a7 --- /dev/null +++ b/src/devices/bus/vip/vp700.c @@ -0,0 +1,81 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + RCA VIP Tiny BASIC VP-700 emulation + +**********************************************************************/ + +#include "vp700.h" + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type VP700 = &device_creator; + + +//------------------------------------------------- +// ROM( vp700 ) +//------------------------------------------------- + +ROM_START( vp700 ) + ROM_REGION( 0x1000, "vp700", 0 ) + ROM_LOAD( "vp700.bin", 0x0000, 0x1000, CRC(3f2b8524) SHA1(8fa88740cae82d8d62ea34891a657d3ca1fb732a) ) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *vp700_device::device_rom_region() const +{ + return ROM_NAME( vp700 ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// vp700_device - constructor +//------------------------------------------------- + +vp700_device::vp700_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, VP700, "VP700", tag, owner, clock, "vp700", __FILE__), + device_vip_expansion_card_interface(mconfig, *this), + m_rom(*this, "vp700") +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void vp700_device::device_start() +{ +} + + +//------------------------------------------------- +// vip_program_r - program read +//------------------------------------------------- + +UINT8 vp700_device::vip_program_r(address_space &space, offs_t offset, int cs, int cdef, int *minh) +{ + UINT8 data = 0xff; + + if (offset < 0x1000) + { + *minh = 1; + + data = m_rom->base()[offset & 0xfff]; + } + + return data; +} diff --git a/src/devices/bus/vip/vp700.h b/src/devices/bus/vip/vp700.h new file mode 100644 index 00000000000..8f521199d76 --- /dev/null +++ b/src/devices/bus/vip/vp700.h @@ -0,0 +1,52 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + RCA VIP Tiny BASIC VP-700 emulation + +**********************************************************************/ + +#pragma once + +#ifndef __VP700__ +#define __VP700__ + +#include "emu.h" +#include "exp.h" +#include "sound/cdp1863.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> vp700_device + +class vp700_device : public device_t, + public device_vip_expansion_card_interface +{ +public: + // construction/destruction + vp700_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + +protected: + // device-level overrides + virtual void device_start(); + + // device_vip_expansion_card_interface overrides + virtual UINT8 vip_program_r(address_space &space, offs_t offset, int cs, int cdef, int *minh); + +private: + required_memory_region m_rom; +}; + + +// device type definition +extern const device_type VP700; + + +#endif diff --git a/src/devices/bus/vtech/ioexp/carts.c b/src/devices/bus/vtech/ioexp/carts.c new file mode 100644 index 00000000000..5bdd6aca63f --- /dev/null +++ b/src/devices/bus/vtech/ioexp/carts.c @@ -0,0 +1,14 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best +/*************************************************************************** + + VTech Laser/VZ I/O Expansion Slot Devices + +***************************************************************************/ + +#include "carts.h" + +SLOT_INTERFACE_START( ioexp_slot_carts ) + SLOT_INTERFACE("joystick", JOYSTICK_INTERFACE) + SLOT_INTERFACE("printer", PRINTER_INTERFACE) +SLOT_INTERFACE_END diff --git a/src/devices/bus/vtech/ioexp/carts.h b/src/devices/bus/vtech/ioexp/carts.h new file mode 100644 index 00000000000..ef9125b5e7b --- /dev/null +++ b/src/devices/bus/vtech/ioexp/carts.h @@ -0,0 +1,21 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best +/*************************************************************************** + + VTech Laser/VZ I/O Expansion Slot Devices + +***************************************************************************/ + +#pragma once + +#ifndef __VTECH_IOEXP_CARTS_H__ +#define __VTECH_IOEXP_CARTS_H__ + +#include "emu.h" + +#include "joystick.h" +#include "printer.h" + +SLOT_INTERFACE_EXTERN( ioexp_slot_carts ); + +#endif // __VTECH_IOEXP_CARTS_H__ diff --git a/src/devices/bus/vtech/ioexp/ioexp.c b/src/devices/bus/vtech/ioexp/ioexp.c new file mode 100644 index 00000000000..3028ffd5226 --- /dev/null +++ b/src/devices/bus/vtech/ioexp/ioexp.c @@ -0,0 +1,91 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best +/*************************************************************************** + + VTech Laser/VZ I/O Expansion Slot + + 30-pin slot + +***************************************************************************/ + +#include "ioexp.h" + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type IOEXP_SLOT = &device_creator; + + +//************************************************************************** +// SLOT DEVICE +//************************************************************************** + +//------------------------------------------------- +// ioexp_slot_device - constructor +//------------------------------------------------- + +ioexp_slot_device::ioexp_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, IOEXP_SLOT, "Peripheral Expansion Slot", tag, owner, clock, "ioexp_slot", __FILE__), + device_slot_interface(mconfig, *this), + m_io(NULL), + m_cart(NULL) +{ +} + +//------------------------------------------------- +// ioexp_slot_device - destructor +//------------------------------------------------- + +ioexp_slot_device::~ioexp_slot_device() +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void ioexp_slot_device::device_start() +{ +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void ioexp_slot_device::device_reset() +{ +} + +//------------------------------------------------- +// set_io_space - set address space we are attached to +//------------------------------------------------- + +void ioexp_slot_device::set_io_space(address_space *io) +{ + m_io = io; +} + + +//************************************************************************** +// CARTRIDGE INTERFACE +//************************************************************************** + +//------------------------------------------------- +// device_ioexp_interface - constructor +//------------------------------------------------- + +device_ioexp_interface::device_ioexp_interface(const machine_config &mconfig, device_t &device) : + device_slot_card_interface(mconfig, device) +{ + m_slot = dynamic_cast(device.owner()); +} + +//------------------------------------------------- +// ~device_ioexp_interface - destructor +//------------------------------------------------- + +device_ioexp_interface::~device_ioexp_interface() +{ +} diff --git a/src/devices/bus/vtech/ioexp/ioexp.h b/src/devices/bus/vtech/ioexp/ioexp.h new file mode 100644 index 00000000000..7948a9ae932 --- /dev/null +++ b/src/devices/bus/vtech/ioexp/ioexp.h @@ -0,0 +1,87 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best +/*************************************************************************** + + VTech Laser/VZ I/O Expansion Slot + + 30-pin slot + + 15 GND 16 NC + 14 /WR 17 NC + 13 A3 18 NC + 12 A6 19 +5VDC + 11 A2 20 NC + 10 A5 21 D4 + 9 D0 22 D5 + 8 D2 23 D7 + 7 D6 24 D1 + 6 D3 25 /RD + 5 /IORQ 26 A1 + 4 +5VDC 27 A4 + 3 NC 28 A0 + 2 NC 29 A7 + 1 NC 30 NC + +***************************************************************************/ + +#pragma once + +#ifndef __VTECH_IOEXP_H__ +#define __VTECH_IOEXP_H__ + +#include "emu.h" + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_IOEXP_SLOT_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, IOEXP_SLOT, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(ioexp_slot_carts, NULL, false) + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class device_ioexp_interface; + +class ioexp_slot_device : public device_t, public device_slot_interface +{ +public: + // construction/destruction + ioexp_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual ~ioexp_slot_device(); + + void set_io_space(address_space *io); + + address_space *m_io; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + device_ioexp_interface *m_cart; +}; + +// class representing interface-specific live ioexp device +class device_ioexp_interface : public device_slot_card_interface +{ +public: + // construction/destruction + device_ioexp_interface(const machine_config &mconfig, device_t &device); + virtual ~device_ioexp_interface(); + +protected: + ioexp_slot_device *m_slot; +}; + +// device type definition +extern const device_type IOEXP_SLOT; + +// include here so drivers don't need to +#include "carts.h" + +#endif // __VTECH_IOEXP_H__ diff --git a/src/devices/bus/vtech/ioexp/joystick.c b/src/devices/bus/vtech/ioexp/joystick.c new file mode 100644 index 00000000000..38e9732d17a --- /dev/null +++ b/src/devices/bus/vtech/ioexp/joystick.c @@ -0,0 +1,109 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best +/*************************************************************************** + + VTech Laser/VZ Joystick Interface + + VTech Laser JS 20 + Dick Smith Electronics X-7315 + +***************************************************************************/ + +#include "joystick.h" + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type JOYSTICK_INTERFACE = &device_creator; + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +static INPUT_PORTS_START( joystick ) + PORT_START("joystick_0") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_JOYSTICK_UP) PORT_PLAYER(1) + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN) PORT_PLAYER(1) + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT) PORT_PLAYER(1) + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT) PORT_PLAYER(1) + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_BUTTON1) PORT_PLAYER(1) + PORT_BIT(0xe0, IP_ACTIVE_LOW, IPT_UNUSED) + + PORT_START("joystick_0_arm") + PORT_BIT(0x0f, IP_ACTIVE_LOW, IPT_UNUSED) + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_BUTTON2) PORT_PLAYER(1) + PORT_BIT(0xe0, IP_ACTIVE_LOW, IPT_UNUSED) + + PORT_START("joystick_1") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_JOYSTICK_UP) PORT_PLAYER(2) + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN) PORT_PLAYER(2) + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT) PORT_PLAYER(2) + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT) PORT_PLAYER(2) + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_BUTTON1) PORT_PLAYER(2) + PORT_BIT(0xe0, IP_ACTIVE_LOW, IPT_UNUSED) + + PORT_START("joystick_1_arm") + PORT_BIT(0x0f, IP_ACTIVE_LOW, IPT_UNUSED) + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_BUTTON2) PORT_PLAYER(2) + PORT_BIT(0xe0, IP_ACTIVE_LOW, IPT_UNUSED) +INPUT_PORTS_END + +ioport_constructor joystick_interface_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( joystick ); +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// joystick_interface_device - constructor +//------------------------------------------------- + +joystick_interface_device::joystick_interface_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, JOYSTICK_INTERFACE, "Laser/VZ Joystick Interface", tag, owner, clock, "joystick", __FILE__), + device_ioexp_interface(mconfig, *this), + m_joy0(*this, "joystick_0"), + m_joy0_arm(*this, "joystick_0_arm"), + m_joy1(*this, "joystick_1"), + m_joy1_arm(*this, "joystick_1_arm") +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void joystick_interface_device::device_start() +{ +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void joystick_interface_device::device_reset() +{ + m_slot->m_io->install_read_handler(0x20, 0x2f, read8_delegate(FUNC(joystick_interface_device::joystick_r), this)); +} + + +//************************************************************************** +// IMPLEMENTATION +//************************************************************************** + +READ8_MEMBER( joystick_interface_device::joystick_r ) +{ + UINT8 data = 0xff; + + if (!BIT(offset, 0)) data &= m_joy0->read(); + if (!BIT(offset, 1)) data &= m_joy0_arm->read(); + if (!BIT(offset, 2)) data &= m_joy1->read(); + if (!BIT(offset, 3)) data &= m_joy1_arm->read(); + + return data; +} diff --git a/src/devices/bus/vtech/ioexp/joystick.h b/src/devices/bus/vtech/ioexp/joystick.h new file mode 100644 index 00000000000..7c6612fc3fc --- /dev/null +++ b/src/devices/bus/vtech/ioexp/joystick.h @@ -0,0 +1,50 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best +/*************************************************************************** + + VTech Laser Joystick Interface + + VTech Laser JS 20 + Dick Smith Electronics X-7315 + +***************************************************************************/ + +#pragma once + +#ifndef __VTECH_IOEXP_JOYSTICK_H__ +#define __VTECH_IOEXP_JOYSTICK_H__ + +#include "emu.h" +#include "ioexp.h" + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> joystick_interface_device + +class joystick_interface_device : public device_t, public device_ioexp_interface +{ +public: + // construction/destruction + joystick_interface_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + DECLARE_READ8_MEMBER( joystick_r ); + +protected: + virtual ioport_constructor device_input_ports() const; + virtual void device_start(); + virtual void device_reset(); + +private: + required_ioport m_joy0; + required_ioport m_joy0_arm; + required_ioport m_joy1; + required_ioport m_joy1_arm; +}; + +// device type definition +extern const device_type JOYSTICK_INTERFACE; + +#endif // __VTECH_IOEXP_JOYSTICK_H__ diff --git a/src/devices/bus/vtech/ioexp/printer.c b/src/devices/bus/vtech/ioexp/printer.c new file mode 100644 index 00000000000..a122c9fa2c7 --- /dev/null +++ b/src/devices/bus/vtech/ioexp/printer.c @@ -0,0 +1,93 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best +/*************************************************************************** + + VTech Laser/VZ Printer Interface + + VTech PI 20 + Dick Smith Electronics X-7320 + +***************************************************************************/ + +#include "printer.h" + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type PRINTER_INTERFACE = &device_creator; + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( printer_interface ) + MCFG_CENTRONICS_ADD("centronics", centronics_devices, "printer") + MCFG_CENTRONICS_BUSY_HANDLER(WRITELINE(printer_interface_device, busy_w)) + MCFG_CENTRONICS_OUTPUT_LATCH_ADD("latch", "centronics") +MACHINE_CONFIG_END + +machine_config_constructor printer_interface_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( printer_interface ); +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// printer_interface_device - constructor +//------------------------------------------------- + +printer_interface_device::printer_interface_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, PRINTER_INTERFACE, "Laser/VZ Printer Interface", tag, owner, clock, "printer", __FILE__), + device_ioexp_interface(mconfig, *this), + m_centronics(*this, "centronics"), + m_latch(*this, "latch"), + m_centronics_busy(0) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void printer_interface_device::device_start() +{ +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void printer_interface_device::device_reset() +{ + m_slot->m_io->install_read_handler(0x00, 0x00, read8_delegate(FUNC(printer_interface_device::busy_r), this)); + m_slot->m_io->install_write_handler(0x0d, 0x0d, write8_delegate(FUNC(printer_interface_device::strobe_w), this)); + m_slot->m_io->install_write_handler(0x0e, 0x0e, write8_delegate(FUNC(output_latch_device::write), m_latch.target())); +} + + +//************************************************************************** +// IMPLEMENTATION +//************************************************************************** + +WRITE_LINE_MEMBER( printer_interface_device::busy_w ) +{ + m_centronics_busy = state; +} + +READ8_MEMBER( printer_interface_device::busy_r ) +{ + return 0xfe | m_centronics_busy; +} + +WRITE8_MEMBER( printer_interface_device::strobe_w ) +{ + m_centronics->write_strobe(1); + m_centronics->write_strobe(0); +} diff --git a/src/devices/bus/vtech/ioexp/printer.h b/src/devices/bus/vtech/ioexp/printer.h new file mode 100644 index 00000000000..ddf2ce9726c --- /dev/null +++ b/src/devices/bus/vtech/ioexp/printer.h @@ -0,0 +1,52 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best +/*************************************************************************** + + VTech Laser/VZ Printer Interface + + Dick Smith Electronics X-7320 + +***************************************************************************/ + +#pragma once + +#ifndef __VTECH_IOEXP_PRINTER_H__ +#define __VTECH_IOEXP_PRINTER_H__ + +#include "emu.h" +#include "ioexp.h" +#include "bus/centronics/ctronics.h" + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> printer_interface_device + +class printer_interface_device : public device_t, public device_ioexp_interface +{ +public: + // construction/destruction + printer_interface_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + DECLARE_WRITE_LINE_MEMBER( busy_w ); + DECLARE_READ8_MEMBER( busy_r ); + DECLARE_WRITE8_MEMBER( strobe_w ); + +protected: + virtual machine_config_constructor device_mconfig_additions() const; + virtual void device_start(); + virtual void device_reset(); + +private: + required_device m_centronics; + required_device m_latch; + + int m_centronics_busy; +}; + +// device type definition +extern const device_type PRINTER_INTERFACE; + +#endif // __VTECH_IOEXP_PRINTER_H__ diff --git a/src/devices/bus/vtech/memexp/carts.c b/src/devices/bus/vtech/memexp/carts.c new file mode 100644 index 00000000000..dc40d0e8a57 --- /dev/null +++ b/src/devices/bus/vtech/memexp/carts.c @@ -0,0 +1,19 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best +/*************************************************************************** + + VTech Laser/VZ Memory Expansion Slot Devices + +***************************************************************************/ + +#include "carts.h" + +SLOT_INTERFACE_START( memexp_slot_carts ) + SLOT_INTERFACE("floppy", FLOPPY_CONTROLLER) + SLOT_INTERFACE("laser110_16k", LASER110_16K) + SLOT_INTERFACE("laser210_16k", LASER210_16K) + SLOT_INTERFACE("laser310_16k", LASER310_16K) + SLOT_INTERFACE("laser_64k", LASER_64K) + SLOT_INTERFACE("rs232", RS232_INTERFACE) + SLOT_INTERFACE("wordpro", WORDPRO) +SLOT_INTERFACE_END diff --git a/src/devices/bus/vtech/memexp/carts.h b/src/devices/bus/vtech/memexp/carts.h new file mode 100644 index 00000000000..a1e86987a31 --- /dev/null +++ b/src/devices/bus/vtech/memexp/carts.h @@ -0,0 +1,23 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best +/*************************************************************************** + + VTech Laser/VZ Memory Expansion Slot Devices + +***************************************************************************/ + +#pragma once + +#ifndef __VTECH_MEMEXP_CARTS_H__ +#define __VTECH_MEMEXP_CARTS_H__ + +#include "emu.h" + +#include "floppy.h" +#include "memory.h" +#include "rs232.h" +#include "wordpro.h" + +SLOT_INTERFACE_EXTERN( memexp_slot_carts ); + +#endif // __VTECH_MEMEXP_CARTS_H__ diff --git a/src/devices/bus/vtech/memexp/floppy.c b/src/devices/bus/vtech/memexp/floppy.c new file mode 100644 index 00000000000..ef169703035 --- /dev/null +++ b/src/devices/bus/vtech/memexp/floppy.c @@ -0,0 +1,298 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best, Olivier Galibert +/*************************************************************************** + + VTech Laser/VZ Floppy Controller Cartridge + + Laser DD 20 + Dick Smith Electronics X-7304 + +***************************************************************************/ + +#include "floppy.h" + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type FLOPPY_CONTROLLER = &device_creator; + +DEVICE_ADDRESS_MAP_START(map, 8, floppy_controller_device) + AM_RANGE(0, 0) AM_WRITE(latch_w) + AM_RANGE(1, 1) AM_READ(shifter_r) + AM_RANGE(2, 2) AM_READ(rd_r) + AM_RANGE(3, 3) AM_READ(wpt_r) +ADDRESS_MAP_END + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +ROM_START( floppy ) + ROM_REGION(0x3000, "software", 0) + ROM_LOAD("vzdos.rom", 0x0000, 0x2000, CRC(b6ed6084) SHA1(59d1cbcfa6c5e1906a32704fbf0d9670f0d1fd8b)) +ROM_END + +const rom_entry *floppy_controller_device::device_rom_region() const +{ + return ROM_NAME( floppy ); +} + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +static SLOT_INTERFACE_START( laser_floppies ) + SLOT_INTERFACE("525", FLOPPY_525_SSSD) +SLOT_INTERFACE_END + +static MACHINE_CONFIG_FRAGMENT( floppy_controller ) + MCFG_MEMEXP_SLOT_ADD("mem") + MCFG_FLOPPY_DRIVE_ADD("0", laser_floppies, "525", floppy_image_device::default_floppy_formats) + MCFG_FLOPPY_DRIVE_ADD("1", laser_floppies, "525", floppy_image_device::default_floppy_formats) +MACHINE_CONFIG_END + +machine_config_constructor floppy_controller_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( floppy_controller ); +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// floppy_controller_device - constructor +//------------------------------------------------- + +floppy_controller_device::floppy_controller_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, FLOPPY_CONTROLLER, "Laser/VZ Floppy Disk Controller", tag, owner, clock, "laserfdc", __FILE__), + device_memexp_interface(mconfig, *this), + m_memexp(*this, "mem"), + m_floppy0(*this, "0"), + m_floppy1(*this, "1") +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void floppy_controller_device::device_start() +{ + save_item(NAME(m_latch)); + save_item(NAME(m_shifter)); + save_item(NAME(m_latching_inverter)); + save_item(NAME(m_current_cyl)); + save_item(NAME(m_last_latching_inverter_update_time)); + save_item(NAME(m_write_start_time)); + save_item(NAME(m_write_position)); + + // TODO: save m_write_buffer and rebuild m_floppy after load + + UINT8 *bios = memregion("software")->base(); + + // Obvious bugs... must have worked by sheer luck and very subtle + // timings. Our current z80 is not subtle enough. + + bios[0x1678] = 0x75; + bios[0x1688] = 0x85; +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void floppy_controller_device::device_reset() +{ + m_memexp->set_io_space(m_slot->m_io); + m_memexp->set_program_space(m_slot->m_program); + + m_slot->m_program->install_rom(0x4000, 0x5fff, memregion("software")->base()); + + m_slot->m_io->install_device(0x10, 0x1f, *this, &floppy_controller_device::map); + + m_latch = 0x00; + m_floppy = NULL; + m_current_cyl = 0; + m_shifter = 0x00; + m_latching_inverter = false; + m_last_latching_inverter_update_time = machine().time(); + m_write_start_time = attotime::never; + m_write_position = 0; + memset(m_write_buffer, 0, sizeof(m_write_buffer)); +} + + +//************************************************************************** +// IMPLEMENTATION +//************************************************************************** + +// latch at +0 is linked to: +// bits 0-3: track step motor phases +// bit 5: write data (flux reversal on every level change) +// bit 6: !write request +// bits 4,7: floppy select + +WRITE8_MEMBER(floppy_controller_device::latch_w) +{ + UINT8 diff = m_latch ^ data; + m_latch = data; + + floppy_image_device *newflop = NULL; + if(m_latch & 0x10) + newflop = m_floppy0->get_device(); + else if(m_latch & 0x80) + newflop = m_floppy1->get_device(); + + if(newflop != m_floppy) { + update_latching_inverter(); + flush_writes(); + if(m_floppy) { + m_floppy->mon_w(1); + m_floppy->setup_index_pulse_cb(floppy_image_device::index_pulse_cb()); + } + if(newflop) { + newflop->set_rpm(85); + newflop->mon_w(0); + newflop->setup_index_pulse_cb(floppy_image_device::index_pulse_cb(FUNC(floppy_controller_device::index_callback), this)); + m_current_cyl = newflop->get_cyl() << 1; + } + m_floppy = newflop; + } + + if(m_floppy) { + int cph = m_current_cyl & 3; + int pcyl = m_current_cyl; + if(!(m_latch & (1 << cph))) { + if(m_current_cyl < 84*2 && (m_latch & (1 << ((cph+1) & 3)))) + m_current_cyl++; + if(m_current_cyl && (m_latch & (1 << ((cph+3) & 3)))) + m_current_cyl--; + if(m_current_cyl != pcyl && !(m_current_cyl & 1)) { + m_floppy->dir_w(m_current_cyl < pcyl); + m_floppy->stp_w(true); + m_floppy->stp_w(false); + m_floppy->stp_w(true); + } + } + } + + if(diff & 0x40) { + if(!(m_latch & 0x40)) { + m_write_start_time = machine().time(); + m_write_position = 0; + if(m_floppy) + m_floppy->set_write_splice(m_write_start_time); + + } else { + update_latching_inverter(); + flush_writes(); + m_write_start_time = attotime::never; + } + } + if(!(m_latch & 0x40) && (diff & 0x20)) { + if(m_write_position == ARRAY_LENGTH(m_write_buffer)) { + update_latching_inverter(); + flush_writes(true); + } + m_write_buffer[m_write_position++] = machine().time(); + } +} + + +// The read data line is connected to a flip/flop with inverted input +// connected to the input. That means it inverts its value on every +// floppy flux reversal. We'll call it a latching inverter. +// +// The latching inverter is connected to a 8-bits shift register. On +// reading the shifter address we get: +// - the inverted inverter output is shifted through the lsb of the shift register +// - the inverter is cleared + +READ8_MEMBER(floppy_controller_device::shifter_r) +{ + update_latching_inverter(); + m_shifter = (m_shifter << 1) | !m_latching_inverter; + m_latching_inverter = false; + return m_shifter; +} + + +// Linked to the latching inverter on bit 7, rest is floating +READ8_MEMBER(floppy_controller_device::rd_r) +{ + update_latching_inverter(); + return m_latching_inverter ? 0x80 : 0x00; +} + + +// Linked to wp signal on bit 7, rest is floating +READ8_MEMBER(floppy_controller_device::wpt_r) +{ + return m_floppy && m_floppy->wpt_r() ? 0x80 : 0x00; +} + +void floppy_controller_device::update_latching_inverter() +{ + attotime now = machine().time(); + if(!m_floppy) { + m_last_latching_inverter_update_time = now; + return; + } + + attotime when = m_last_latching_inverter_update_time; + for(;;) { + when = m_floppy->get_next_transition(when); + if(when == attotime::never || when > now) + break; + m_latching_inverter = !m_latching_inverter; + } + m_last_latching_inverter_update_time = now; +} + +void floppy_controller_device::index_callback(floppy_image_device *floppy, int state) +{ + update_latching_inverter(); + flush_writes(true); +} + +void floppy_controller_device::flush_writes(bool keep_margin) +{ + if(!m_floppy || m_write_start_time == attotime::never) + return; + + // Beware of time travel. Index pulse callback (which flushes) + // can be called with a machine().time() inferior to the last + // m_write_buffer value if the calling cpu instructions are not + // suspendable. + + attotime limit = machine().time(); + int kept_pos = m_write_position; + int kept_count = 0; + while(kept_pos > 0 && m_write_buffer[kept_pos-1] >= limit) { + kept_pos--; + kept_count++; + } + + if(keep_margin) { + attotime last = kept_pos ? m_write_buffer[kept_pos-1] : m_write_start_time; + attotime delta = limit-last; + delta = delta / 2; + limit = limit - delta; + } + m_write_position -= kept_count; + if(m_write_position && m_write_buffer[0] == m_write_start_time) { + if(m_write_position) + memmove(m_write_buffer, m_write_buffer+1, sizeof(m_write_buffer[0])*(m_write_position-1)); + m_write_position--; + } + m_floppy->write_flux(m_write_start_time, limit, m_write_position, m_write_buffer); + m_write_start_time = limit; + + if(kept_count != 0) + memmove(m_write_buffer, m_write_buffer+kept_pos, kept_count*sizeof(m_write_buffer[0])); + m_write_position = kept_count; +} diff --git a/src/devices/bus/vtech/memexp/floppy.h b/src/devices/bus/vtech/memexp/floppy.h new file mode 100644 index 00000000000..91c332332c1 --- /dev/null +++ b/src/devices/bus/vtech/memexp/floppy.h @@ -0,0 +1,66 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best, Olivier Galibert +/*************************************************************************** + + VTech Laser/VZ Floppy Controller Cartridge + + Laser DD 20 + Dick Smith Electronics X-7304 + +***************************************************************************/ + +#pragma once + +#ifndef __VTECH_MEMEXP_FLOPPY_H__ +#define __VTECH_MEMEXP_FLOPPY_H__ + +#include "emu.h" +#include "memexp.h" +#include "imagedev/floppy.h" + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> floppy_controller_device + +class floppy_controller_device : public device_t, public device_memexp_interface +{ +public: + // construction/destruction + floppy_controller_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + DECLARE_ADDRESS_MAP(map, 8); + + DECLARE_WRITE8_MEMBER(latch_w); + DECLARE_READ8_MEMBER(shifter_r); + DECLARE_READ8_MEMBER(rd_r); + DECLARE_READ8_MEMBER(wpt_r); + +protected: + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + virtual void device_start(); + virtual void device_reset(); + + required_device m_memexp; + required_device m_floppy0, m_floppy1; + floppy_image_device *m_floppy; + + UINT8 m_latch, m_shifter; + bool m_latching_inverter; + int m_current_cyl; + attotime m_last_latching_inverter_update_time; + attotime m_write_start_time, m_write_buffer[32]; + int m_write_position; + + void index_callback(floppy_image_device *floppy, int state); + void update_latching_inverter(); + void flush_writes(bool keep_margin = false); +}; + +// device type definition +extern const device_type FLOPPY_CONTROLLER; + +#endif // __VTECH_MEMEXP_FLOPPY_H__ diff --git a/src/devices/bus/vtech/memexp/memexp.c b/src/devices/bus/vtech/memexp/memexp.c new file mode 100644 index 00000000000..d41b2d073b7 --- /dev/null +++ b/src/devices/bus/vtech/memexp/memexp.c @@ -0,0 +1,108 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best +/*************************************************************************** + + VTech Laser/VZ Memory Expansion Slot + + 44-pin slot + +***************************************************************************/ + +#include "memexp.h" + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type MEMEXP_SLOT = &device_creator; + + +//************************************************************************** +// SLOT DEVICE +//************************************************************************** + +//------------------------------------------------- +// memexp_slot_device - constructor +//------------------------------------------------- + +memexp_slot_device::memexp_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, MEMEXP_SLOT, "Memory Expansion Slot", tag, owner, clock, "memexp_slot", __FILE__), + device_slot_interface(mconfig, *this), + m_program(NULL), + m_io(NULL), + m_cart(NULL), + m_int_handler(*this), + m_nmi_handler(*this), + m_reset_handler(*this) +{ +} + +//------------------------------------------------- +// memexp_slot_device - destructor +//------------------------------------------------- + +memexp_slot_device::~memexp_slot_device() +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void memexp_slot_device::device_start() +{ + // resolve callbacks + m_int_handler.resolve_safe(); + m_nmi_handler.resolve_safe(); + m_reset_handler.resolve_safe(); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void memexp_slot_device::device_reset() +{ +} + +//------------------------------------------------- +// set_program_space - set address space we are attached to +//------------------------------------------------- + +void memexp_slot_device::set_program_space(address_space *program) +{ + m_program = program; +} + +//------------------------------------------------- +// set_io_space - set address space we are attached to +//------------------------------------------------- + +void memexp_slot_device::set_io_space(address_space *io) +{ + m_io = io; +} + + +//************************************************************************** +// CARTRIDGE INTERFACE +//************************************************************************** + +//------------------------------------------------- +// device_memexp_interface - constructor +//------------------------------------------------- + +device_memexp_interface::device_memexp_interface(const machine_config &mconfig, device_t &device) : + device_slot_card_interface(mconfig, device) +{ + m_slot = dynamic_cast(device.owner()); +} + +//------------------------------------------------- +// ~device_memexp_interface - destructor +//------------------------------------------------- + +device_memexp_interface::~device_memexp_interface() +{ +} diff --git a/src/devices/bus/vtech/memexp/memexp.h b/src/devices/bus/vtech/memexp/memexp.h new file mode 100644 index 00000000000..d0de2049b5b --- /dev/null +++ b/src/devices/bus/vtech/memexp/memexp.h @@ -0,0 +1,125 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best +/*************************************************************************** + + VTech Laser/VZ Memory Expansion Slot + + 44-pin slot + + 22 GND 23 NC + 21 +5VDC 24 A11 + 20 /IORQ 25 A12 + 19 /RD 26 A13 + 18 /NMI 27 A14 + 17 /WAIT 28 A15 + 16 /MI 29 CLK + 15 /RFSH 30 D4 + 14 D7 31 D3 + 13 D2 32 D5 + 12 A1 33 D6 + 11 A2 34 NC + 10 A3 35 A0 + 9 A4 36 D0 + 8 A5 37 D1 + 7 A6 38 /INT + 6 A7 39 /HALT + 5 A8 40 /MERQ + 4 A9 41 /WR + 3 A10 42 /NC + 2 /RESET 43 +9VDC + 1 GND 44 NC + +***************************************************************************/ + +#pragma once + +#ifndef __VTECH_MEMEXP_H__ +#define __VTECH_MEMEXP_H__ + +#include "emu.h" + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_MEMEXP_SLOT_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, MEMEXP_SLOT, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(memexp_slot_carts, NULL, false) + +#define MCFG_MEMEXP_SLOT_INT_HANDLER(_devcb) \ + devcb = &memexp_device::set_int_handler(*device, DEVCB_##_devcb); + +#define MCFG_MEMEXP_SLOT_NMI_HANDLER(_devcb) \ + devcb = &memexp_device::set_nmi_handler(*device, DEVCB_##_devcb); + +#define MCFG_MEMEXP_SLOT_RESET_HANDLER(_devcb) \ + devcb = &memexp_device::set_reset_handler(*device, DEVCB_##_devcb); + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class device_memexp_interface; + +class memexp_slot_device : public device_t, public device_slot_interface +{ +public: + // construction/destruction + memexp_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual ~memexp_slot_device(); + + void set_program_space(address_space *program); + void set_io_space(address_space *io); + + // callbacks + template static devcb_base &set_int_handler(device_t &device, _Object object) + { return downcast(device).m_int_handler.set_callback(object); } + + template static devcb_base &set_nmi_handler(device_t &device, _Object object) + { return downcast(device).m_nmi_handler.set_callback(object); } + + template static devcb_base &set_reset_handler(device_t &device, _Object object) + { return downcast(device).m_reset_handler.set_callback(object); } + + // called from cart device + DECLARE_WRITE_LINE_MEMBER( int_w ) { m_int_handler(state); } + DECLARE_WRITE_LINE_MEMBER( nmi_w ) { m_nmi_handler(state); } + DECLARE_WRITE_LINE_MEMBER( reset_w ) { m_reset_handler(state); } + + address_space *m_program; + address_space *m_io; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + device_memexp_interface *m_cart; + +private: + devcb_write_line m_int_handler; + devcb_write_line m_nmi_handler; + devcb_write_line m_reset_handler; +}; + +// class representing interface-specific live memexp device +class device_memexp_interface : public device_slot_card_interface +{ +public: + // construction/destruction + device_memexp_interface(const machine_config &mconfig, device_t &device); + virtual ~device_memexp_interface(); + +protected: + memexp_slot_device *m_slot; +}; + +// device type definition +extern const device_type MEMEXP_SLOT; + +// include here so drivers don't need to +#include "carts.h" + +#endif // __VTECH_MEMEXP_H__ diff --git a/src/devices/bus/vtech/memexp/memory.c b/src/devices/bus/vtech/memexp/memory.c new file mode 100644 index 00000000000..5b4b9d71701 --- /dev/null +++ b/src/devices/bus/vtech/memexp/memory.c @@ -0,0 +1,166 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best +/*************************************************************************** + + VTech Laser/VZ Laser Memory Expansions + +***************************************************************************/ + +#include "memory.h" + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type LASER110_16K = &device_creator; +const device_type LASER210_16K = &device_creator; +const device_type LASER310_16K = &device_creator; +const device_type LASER_64K = &device_creator; + + +//************************************************************************** +// LASER 110 16K DEVICE +//************************************************************************** + +//------------------------------------------------- +// laser110_16k_device - constructor +//------------------------------------------------- + +laser110_16k_device::laser110_16k_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, LASER110_16K, "Laser 110/200/VZ-200 16k Memory", tag, owner, clock, "laser110_16k", __FILE__), + device_memexp_interface(mconfig, *this) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void laser110_16k_device::device_start() +{ + m_ram.resize(16 * 1024); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void laser110_16k_device::device_reset() +{ + m_slot->m_program->install_ram(0x8000, 0xbfff, &m_ram[0]); +} + + +//************************************************************************** +// LASER 210 16K DEVICE +//************************************************************************** + +//------------------------------------------------- +// laser210_16k_device - constructor +//------------------------------------------------- + +laser210_16k_device::laser210_16k_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, LASER210_16K, "Laser 210/VZ-200 (DSE) 16k Memory", tag, owner, clock, "laser210_16k", __FILE__), + device_memexp_interface(mconfig, *this) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void laser210_16k_device::device_start() +{ + m_ram.resize(16 * 1024); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void laser210_16k_device::device_reset() +{ + m_slot->m_program->install_ram(0x9000, 0xcfff, &m_ram[0]); +} + + +//************************************************************************** +// VZ300 16K DEVICE +//************************************************************************** + +//------------------------------------------------- +// laser310_16k_device - constructor +//------------------------------------------------- + +laser310_16k_device::laser310_16k_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, LASER310_16K, "Laser 310/VZ-300 16k Memory", tag, owner, clock, "laser310_16k", __FILE__), + device_memexp_interface(mconfig, *this) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void laser310_16k_device::device_start() +{ + m_ram.resize(16 * 1024); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void laser310_16k_device::device_reset() +{ + m_slot->m_program->install_ram(0xb800, 0xf7ff, &m_ram[0]); +} + + +//************************************************************************** +// VZ300 64K DEVICE +//************************************************************************** + +//------------------------------------------------- +// laser_64k_device - constructor +//------------------------------------------------- + +laser_64k_device::laser_64k_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, LASER_64K, "Laser/VZ 64k Memory", tag, owner, clock, "laser_64k", __FILE__), + device_memexp_interface(mconfig, *this) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void laser_64k_device::device_start() +{ + m_ram.resize(64 * 1024); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void laser_64k_device::device_reset() +{ + // fixed first bank + m_slot->m_program->install_ram(0x8000, 0xbfff, &m_ram[0]); + + // other banks + m_slot->m_program->install_readwrite_bank(0xc000, 0xffff, tag()); + + membank(tag())->configure_entries(0, 4, &m_ram[0], 0x4000); + membank(tag())->set_entry(1); + + // bank switch + m_slot->m_io->install_write_handler(0x70, 0x7f, write8_delegate(FUNC(laser_64k_device::bankswitch_w), this)); +} + +WRITE8_MEMBER( laser_64k_device::bankswitch_w ) +{ + membank(tag())->set_entry(data & 0x03); +} diff --git a/src/devices/bus/vtech/memexp/memory.h b/src/devices/bus/vtech/memexp/memory.h new file mode 100644 index 00000000000..e45d65c83fe --- /dev/null +++ b/src/devices/bus/vtech/memexp/memory.h @@ -0,0 +1,94 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best +/*************************************************************************** + + VTech Laser/VZ Memory Expansions + +***************************************************************************/ + +#pragma once + +#ifndef __VTECH_MEMEXP_MEMORY__ +#define __VTECH_MEMEXP_MEMORY__ + +#include "emu.h" +#include "memexp.h" + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> laser110_16k_device + +class laser110_16k_device : public device_t, public device_memexp_interface +{ +public: + // construction/destruction + laser110_16k_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual void device_start(); + virtual void device_reset(); + +private: + std::vector m_ram; +}; + +// ======================> laser210_16k_device + +class laser210_16k_device : public device_t, public device_memexp_interface +{ +public: + // construction/destruction + laser210_16k_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual void device_start(); + virtual void device_reset(); + +private: + std::vector m_ram; +}; + +// ======================> laser310_16k_device + +class laser310_16k_device : public device_t, public device_memexp_interface +{ +public: + // construction/destruction + laser310_16k_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual void device_start(); + virtual void device_reset(); + +private: + std::vector m_ram; +}; + +// ======================> laser_64k_device + +class laser_64k_device : public device_t, public device_memexp_interface +{ +public: + // construction/destruction + laser_64k_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + DECLARE_WRITE8_MEMBER( bankswitch_w ); + +protected: + virtual void device_start(); + virtual void device_reset(); + +private: + std::vector m_ram; +}; + +// device type definition +extern const device_type LASER110_16K; +extern const device_type LASER210_16K; +extern const device_type LASER310_16K; +extern const device_type LASER_64K; + +#endif // __VTECH_MEMEXP_MEMORY__ diff --git a/src/devices/bus/vtech/memexp/rs232.c b/src/devices/bus/vtech/memexp/rs232.c new file mode 100644 index 00000000000..bd74662c9f5 --- /dev/null +++ b/src/devices/bus/vtech/memexp/rs232.c @@ -0,0 +1,104 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best +/*************************************************************************** + + Dick Smith VZ-200/300 RS-232 Cartridge + +***************************************************************************/ + +#include "rs232.h" + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type RS232_INTERFACE = &device_creator; + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +ROM_START( rs232 ) + ROM_REGION(0x800, "software", 0) + ROM_LOAD("rs232_v15.ic2", 0x000, 0x800, CRC(6545260d) SHA1(4042f6f1e09e383f3c92f628c6187dc5f072fdb2)) +ROM_END + +const rom_entry *rs232_interface_device::device_rom_region() const +{ + return ROM_NAME( rs232 ); +} + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( rs232 ) + MCFG_RS232_PORT_ADD("rs232", default_rs232_devices, NULL) + MCFG_RS232_RXD_HANDLER(WRITELINE(rs232_interface_device, rs232_rx_w)) +MACHINE_CONFIG_END + +machine_config_constructor rs232_interface_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( rs232 ); +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// wordpro_device - constructor +//------------------------------------------------- + +rs232_interface_device::rs232_interface_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, RS232_INTERFACE, "DSE VZ-200/300 RS-232 Interface", tag, owner, clock, "vz_rs232", __FILE__), + device_memexp_interface(mconfig, *this), + m_rs232(*this, "rs232"), + m_rx(1) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void rs232_interface_device::device_start() +{ +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void rs232_interface_device::device_reset() +{ + // program + m_slot->m_program->install_rom(0x4000, 0x47ff, 0, 0x800, memregion("software")->base()); + + // data + m_slot->m_program->install_read_handler(0x5000, 0x57ff, read8_delegate(FUNC(rs232_interface_device::receive_data_r), this)); + m_slot->m_program->install_write_handler(0x5800, 0x5fff, write8_delegate(FUNC(rs232_interface_device::transmit_data_w), this)); +} + + +//************************************************************************** +// IMPLEMENTATION +//************************************************************************** + +WRITE_LINE_MEMBER( rs232_interface_device::rs232_rx_w ) +{ + m_rx = state; +} + +READ8_MEMBER( rs232_interface_device::receive_data_r ) +{ + return 0x7f | (m_rx << 7); +} + +WRITE8_MEMBER( rs232_interface_device::transmit_data_w ) +{ + m_rs232->write_txd(!BIT(data, 7)); +} diff --git a/src/devices/bus/vtech/memexp/rs232.h b/src/devices/bus/vtech/memexp/rs232.h new file mode 100644 index 00000000000..c89133e5a33 --- /dev/null +++ b/src/devices/bus/vtech/memexp/rs232.h @@ -0,0 +1,50 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best +/*************************************************************************** + + Dick Smith VZ-200/300 RS-232 Cartridge + +***************************************************************************/ + +#pragma once + +#ifndef __VTECH_MEMEXP_RS232_H__ +#define __VTECH_MEMEXP_RS232_H__ + +#include "emu.h" +#include "memexp.h" +#include "bus/rs232/rs232.h" + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> rs232_interface_device + +class rs232_interface_device : public device_t, public device_memexp_interface +{ +public: + // construction/destruction + rs232_interface_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + DECLARE_WRITE_LINE_MEMBER( rs232_rx_w ); + DECLARE_READ8_MEMBER( receive_data_r ); + DECLARE_WRITE8_MEMBER( transmit_data_w ); + +protected: + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + virtual void device_start(); + virtual void device_reset(); + +private: + required_device m_rs232; + + int m_rx; +}; + +// device type definition +extern const device_type RS232_INTERFACE; + +#endif // __VTECH_MEMEXP_RS232_H__ diff --git a/src/devices/bus/vtech/memexp/wordpro.c b/src/devices/bus/vtech/memexp/wordpro.c new file mode 100644 index 00000000000..1a038bcf0ac --- /dev/null +++ b/src/devices/bus/vtech/memexp/wordpro.c @@ -0,0 +1,65 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best +/*************************************************************************** + + Dick Smith VZ-300 WordPro Cartridge + +***************************************************************************/ + +#include "wordpro.h" + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type WORDPRO = &device_creator; + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +ROM_START( wordpro ) + ROM_REGION(0x3000, "software", 0) + ROM_LOAD("wordpro.u3", 0x0000, 0x1000, CRC(c37ea780) SHA1(03f56711e08d88e7b523c0ef9c2a5af83ee7ad05)) + ROM_LOAD("wordpro.u4", 0x1000, 0x1000, CRC(2e3a8c45) SHA1(a9d48d809f39a3478496a6d3ddd728bd0b4efc37)) + ROM_LOAD("wordpro.u5", 0x2000, 0x1000, CRC(2a336802) SHA1(b4de50f943243f18a2bfabef354b76d77178c189)) +ROM_END + +const rom_entry *wordpro_device::device_rom_region() const +{ + return ROM_NAME( wordpro ); +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// wordpro_device - constructor +//------------------------------------------------- + +wordpro_device::wordpro_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, WORDPRO, "DSE VZ-300 WordPro", tag, owner, clock, "wordpro", __FILE__), + device_memexp_interface(mconfig, *this) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void wordpro_device::device_start() +{ +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void wordpro_device::device_reset() +{ + m_slot->m_program->install_rom(0x6000, 0x67ff, memregion("software")->base()); + m_slot->m_program->install_rom(0xd000, 0xffff, memregion("software")->base()); +} diff --git a/src/devices/bus/vtech/memexp/wordpro.h b/src/devices/bus/vtech/memexp/wordpro.h new file mode 100644 index 00000000000..8626787f16e --- /dev/null +++ b/src/devices/bus/vtech/memexp/wordpro.h @@ -0,0 +1,39 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best +/*************************************************************************** + + Dick Smith VZ-300 WordPro Cartridge + +***************************************************************************/ + +#pragma once + +#ifndef __VTECH_MEMEXP_WORDPRO_H__ +#define __VTECH_MEMEXP_WORDPRO_H__ + +#include "emu.h" +#include "memexp.h" + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> wordpro_device + +class wordpro_device : public device_t, public device_memexp_interface +{ +public: + // construction/destruction + wordpro_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual const rom_entry *device_rom_region() const; + virtual void device_start(); + virtual void device_reset(); +}; + +// device type definition +extern const device_type WORDPRO; + +#endif // __VTECH_MEMEXP_WORDPRO_H__ diff --git a/src/devices/bus/wangpc/emb.c b/src/devices/bus/wangpc/emb.c new file mode 100644 index 00000000000..e53b8ea2308 --- /dev/null +++ b/src/devices/bus/wangpc/emb.c @@ -0,0 +1,175 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Wang PC-PM031-B Extended Memory Board emulation + +**********************************************************************/ + +#include "emb.h" + + + +//************************************************************************** +// MACROS/CONSTANTS +//************************************************************************** + +#define LOG 0 + +#define OPTION_ID 0x3f + +#define RAM_SIZE 0x40000 + +#define A19_A18_A17 ((offset >> 16) & 0x07) +#define BASE(bank) ((m_option >> (bank * 4)) & 0x07) +#define ENABLE(bank) BIT(m_option, (bank * 4) + 3) +#define RAM_BANK(bank) m_ram[(bank * 0x10000) | (offset & 0xffff)] + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type WANGPC_EMB = &device_creator; + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// wangpc_emb_device - constructor +//------------------------------------------------- + +wangpc_emb_device::wangpc_emb_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, WANGPC_EMB, "Wang PC-PM031-B", tag, owner, clock, "wangpc_emb", __FILE__), + device_wangpcbus_card_interface(mconfig, *this), + m_ram(*this, "ram") +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void wangpc_emb_device::device_start() +{ + // allocate memory + m_ram.allocate(RAM_SIZE); + + // state saving + save_item(NAME(m_option)); + save_item(NAME(m_parity_error)); + save_item(NAME(m_parity_odd)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void wangpc_emb_device::device_reset() +{ + m_option = 0; + m_parity_error = 0; + m_parity_odd = 1; +} + + +//------------------------------------------------- +// wangpcbus_mrdc_r - memory read +//------------------------------------------------- + +UINT16 wangpc_emb_device::wangpcbus_mrdc_r(address_space &space, offs_t offset, UINT16 mem_mask) +{ + UINT16 data = 0xffff; + + for (int bank = 0; bank < 4; bank++) + { + if (ENABLE(bank) && (A19_A18_A17 == BASE(bank))) + { + data &= RAM_BANK(bank); + } + } + + return data; +} + + +//------------------------------------------------- +// wangpcbus_amwc_w - memory write +//------------------------------------------------- + +void wangpc_emb_device::wangpcbus_amwc_w(address_space &space, offs_t offset, UINT16 mem_mask, UINT16 data) +{ + for (int bank = 0; bank < 4; bank++) + { + if (ENABLE(bank) && (A19_A18_A17 == BASE(bank))) + { + RAM_BANK(bank) = data; + } + } +} + + +//------------------------------------------------- +// wangpcbus_iorc_r - I/O read +//------------------------------------------------- + +UINT16 wangpc_emb_device::wangpcbus_iorc_r(address_space &space, offs_t offset, UINT16 mem_mask) +{ + UINT16 data = 0xffff; + + if (sad(offset)) + { + switch (offset & 0x7f) + { + case 0xc0/2: + data = m_option; + break; + + case 0xfe/2: + data = 0xfc00 | (m_parity_odd << 9) | (m_parity_error << 8) | OPTION_ID; + break; + } + + logerror("emb read %06x:%02x\n", offset*2, data); + } + + return data; +} + + +//------------------------------------------------- +// wangpcbus_aiowc_w - I/O write +//------------------------------------------------- + +void wangpc_emb_device::wangpcbus_aiowc_w(address_space &space, offs_t offset, UINT16 mem_mask, UINT16 data) +{ + if (sad(offset)) + { + logerror("emb write %06x:%02x\n", offset*2, data); + + switch (offset & 0x7f) + { + case 0xc0/2: + m_option = data; + break; + + case 0xce/2: + m_parity_error = 0; + break; + + case 0xfc/2: + device_reset(); + break; + + case 0xfe/2: + m_parity_odd = BIT(data, 9); + break; + } + } +} diff --git a/src/devices/bus/wangpc/emb.h b/src/devices/bus/wangpc/emb.h new file mode 100644 index 00000000000..169cb68a428 --- /dev/null +++ b/src/devices/bus/wangpc/emb.h @@ -0,0 +1,55 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Wang PC-PM031-B Extended Memory Board emulation + +**********************************************************************/ + +#pragma once + +#ifndef __WANGPC_EMB__ +#define __WANGPC_EMB__ + +#include "emu.h" +#include "wangpc.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> wangpc_emb_device + +class wangpc_emb_device : public device_t, + public device_wangpcbus_card_interface +{ +public: + // construction/destruction + wangpc_emb_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_wangpcbus_card_interface overrides + virtual UINT16 wangpcbus_mrdc_r(address_space &space, offs_t offset, UINT16 mem_mask); + virtual void wangpcbus_amwc_w(address_space &space, offs_t offset, UINT16 mem_mask, UINT16 data); + virtual UINT16 wangpcbus_iorc_r(address_space &space, offs_t offset, UINT16 mem_mask); + virtual void wangpcbus_aiowc_w(address_space &space, offs_t offset, UINT16 mem_mask, UINT16 data); + +private: + optional_shared_ptr m_ram; + UINT16 m_option; + int m_parity_error; + int m_parity_odd; +}; + + +// device type definition +extern const device_type WANGPC_EMB; + + +#endif diff --git a/src/devices/bus/wangpc/lic.c b/src/devices/bus/wangpc/lic.c new file mode 100644 index 00000000000..cebc359a942 --- /dev/null +++ b/src/devices/bus/wangpc/lic.c @@ -0,0 +1,159 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Wang PC Network card emulation + +**********************************************************************/ + +#include "lic.h" + + + +//************************************************************************** +// MACROS/CONSTANTS +//************************************************************************** + +#define OPTION_ID 0x30 + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type WANGPC_LIC = &device_creator; + + +//------------------------------------------------- +// ROM( wangpc_lic ) +//------------------------------------------------- + +ROM_START( wangpc_lic ) + ROM_REGION( 0x1000, "network", 0 ) + ROM_LOAD( "7025.l22", 0x0000, 0x1000, CRC(487e5f04) SHA1(81e52e70e0c6e34715119b121ec19a7758cd6772) ) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *wangpc_lic_device::device_rom_region() const +{ + return ROM_NAME( wangpc_lic ); +} + + +//------------------------------------------------- +// MACHINE_CONFIG_FRAGMENT( wangpc_lic ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( wangpc_lic ) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor wangpc_lic_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( wangpc_lic ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// wangpc_lic_device - constructor +//------------------------------------------------- + +wangpc_lic_device::wangpc_lic_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, WANGPC_LIC, "Wang PC-PM070", tag, owner, clock, "wangpc_lic", __FILE__), + device_wangpcbus_card_interface(mconfig, *this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void wangpc_lic_device::device_start() +{ +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void wangpc_lic_device::device_reset() +{ +} + + +//------------------------------------------------- +// wangpcbus_mrdc_r - memory read +//------------------------------------------------- + +UINT16 wangpc_lic_device::wangpcbus_mrdc_r(address_space &space, offs_t offset, UINT16 mem_mask) +{ + UINT16 data = 0xffff; + + return data; +} + + +//------------------------------------------------- +// wangpcbus_amwc_w - memory write +//------------------------------------------------- + +void wangpc_lic_device::wangpcbus_amwc_w(address_space &space, offs_t offset, UINT16 mem_mask, UINT16 data) +{ +} + + +//------------------------------------------------- +// wangpcbus_iorc_r - I/O read +//------------------------------------------------- + +UINT16 wangpc_lic_device::wangpcbus_iorc_r(address_space &space, offs_t offset, UINT16 mem_mask) +{ + UINT16 data = 0xffff; + + if (sad(offset)) + { + switch (offset & 0x7f) + { + case 0xfe/2: + data = 0xff00 | OPTION_ID; + break; + } + } + + return data; +} + + +//------------------------------------------------- +// wangpcbus_aiowc_w - I/O write +//------------------------------------------------- + +void wangpc_lic_device::wangpcbus_aiowc_w(address_space &space, offs_t offset, UINT16 mem_mask, UINT16 data) +{ + if (sad(offset)) + { + switch (offset & 0x7f) + { + case 0xfc/2: + device_reset(); + break; + } + } +} diff --git a/src/devices/bus/wangpc/lic.h b/src/devices/bus/wangpc/lic.h new file mode 100644 index 00000000000..5fb1d792bcd --- /dev/null +++ b/src/devices/bus/wangpc/lic.h @@ -0,0 +1,53 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Wang PC-PM070 Local Interconnect option card emulation + +**********************************************************************/ + +#pragma once + +#ifndef __WANGPC_LIC__ +#define __WANGPC_LIC__ + +#include "emu.h" +#include "wangpc.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> wangpc_lic_device + +class wangpc_lic_device : public device_t, + public device_wangpcbus_card_interface +{ +public: + // construction/destruction + wangpc_lic_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_wangpcbus_card_interface overrides + virtual UINT16 wangpcbus_mrdc_r(address_space &space, offs_t offset, UINT16 mem_mask); + virtual void wangpcbus_amwc_w(address_space &space, offs_t offset, UINT16 mem_mask, UINT16 data); + virtual UINT16 wangpcbus_iorc_r(address_space &space, offs_t offset, UINT16 mem_mask); + virtual void wangpcbus_aiowc_w(address_space &space, offs_t offset, UINT16 mem_mask, UINT16 data); +}; + + +// device type definition +extern const device_type WANGPC_LIC; + + +#endif diff --git a/src/devices/bus/wangpc/lvc.c b/src/devices/bus/wangpc/lvc.c new file mode 100644 index 00000000000..fb0ef5e9325 --- /dev/null +++ b/src/devices/bus/wangpc/lvc.c @@ -0,0 +1,340 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Wang PC Low-Resolution Video Controller emulation + +**********************************************************************/ + +/* + + TODO: + + - cursor + - scroll + - option bit 1? + +*/ + +#include "lvc.h" + + + +//************************************************************************** +// MACROS/CONSTANTS +//************************************************************************** + +#define LOG 0 + +#define OPTION_ID 0x10 + +#define MC6845_TAG "mc6845" +#define SCREEN_TAG "screen" + +#define RAM_SIZE 0x8000 + +#define OPTION_VRAM BIT(m_option, 0) +#define OPTION_UNKNOWN BIT(m_option, 1) +#define OPTION_80_COL BIT(m_option, 2) +#define OPTION_VSYNC BIT(m_option, 3) + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type WANGPC_LVC = &device_creator; + + +//------------------------------------------------- +// mc6845 +//------------------------------------------------- + +MC6845_UPDATE_ROW( wangpc_lvc_device::crtc_update_row ) +{ + offs_t scroll_y = (((m_scroll >> 8) + 0x15) & 0xff) * 0x80; + + if (OPTION_80_COL) + { + for (int column = 0; column < x_count; column++) + { + offs_t addr = scroll_y + (m_scroll & 0x3f) + ((ma / 80) * 0x480) + (((ra & 0x0f) << 7) | (column & 0x7f)); + UINT16 data = m_video_ram[addr & 0x7fff]; + + for (int bit = 0; bit < 8; bit++) + { + int x = (column * 8) + bit; + int color = (BIT(data, 15) << 1) | BIT(data, 7); + + if (column == cursor_x) color = 0x03; + + bitmap.pix32(vbp + y, hbp + x) = de ? m_palette[color] : rgb_t::black; + + data <<= 1; + } + } + } + else + { + //offs_t addr = scroll_y + ((m_scroll & 0x3f) << 1) + ((ma / 40) * 0x480) + (((ra & 0x0f) << 7)); + offs_t addr = scroll_y + ((m_scroll & 0x3f) << 1) + (y * 0x80); + + for (int column = 0; column < x_count; column++) + { + UINT32 data = (m_video_ram[(addr + 1) & 0x7fff] << 16) | m_video_ram[addr & 0x7fff]; + + for (int bit = 0; bit < 8; bit++) + { + int x = (column * 8) + bit; + int color = (BIT(data, 31) << 3) | (BIT(data, 23) << 2) | (BIT(data, 15) << 1) | BIT(data, 7); + + if (column == cursor_x) color = 0x03; + + bitmap.pix32(vbp + y, hbp + x) = de ? m_palette[color] : rgb_t::black; + + data <<= 1; + } + + addr += 2; + } + } +} + +WRITE_LINE_MEMBER( wangpc_lvc_device::vsync_w ) +{ + if (OPTION_VSYNC && state) + { + set_irq(ASSERT_LINE); + } +} + +//------------------------------------------------- +// MACHINE_CONFIG_FRAGMENT( wangpc_lvc ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( wangpc_lvc ) + MCFG_SCREEN_ADD(SCREEN_TAG, RASTER) + MCFG_SCREEN_UPDATE_DEVICE(MC6845_TAG, mc6845_device, screen_update) + MCFG_SCREEN_SIZE(80*8, 25*9) + MCFG_SCREEN_VISIBLE_AREA(0, 80*8-1, 0, 25*9-1) + MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(2500)) + MCFG_SCREEN_REFRESH_RATE(60) + + MCFG_MC6845_ADD(MC6845_TAG, MC6845_1, SCREEN_TAG, XTAL_14_31818MHz/16) + MCFG_MC6845_SHOW_BORDER_AREA(true) + MCFG_MC6845_CHAR_WIDTH(8) + MCFG_MC6845_UPDATE_ROW_CB(wangpc_lvc_device, crtc_update_row) + MCFG_MC6845_OUT_VSYNC_CB(WRITELINE(wangpc_lvc_device, vsync_w)) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor wangpc_lvc_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( wangpc_lvc ); +} + + + +//************************************************************************** +// INLINE HELPERS +//************************************************************************** + +//------------------------------------------------- +// set_irq - +//------------------------------------------------- + +inline void wangpc_lvc_device::set_irq(int state) +{ + m_irq = state; + + m_bus->irq3_w(m_irq); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// wangpc_lvc_device - constructor +//------------------------------------------------- + +wangpc_lvc_device::wangpc_lvc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, WANGPC_LVC, "Wang PC Low Resolution Video Card", tag, owner, clock, "wangpc_lvc", __FILE__), + device_wangpcbus_card_interface(mconfig, *this), + m_crtc(*this, MC6845_TAG), + m_video_ram(*this, "video_ram"), + m_option(0), + m_irq(CLEAR_LINE) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void wangpc_lvc_device::device_start() +{ + // allocate memory + m_video_ram.allocate(RAM_SIZE); + + // state saving + save_item(NAME(m_option)); + save_item(NAME(m_scroll)); + save_item(NAME(m_irq)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void wangpc_lvc_device::device_reset() +{ + m_option = 0; + + set_irq(CLEAR_LINE); +} + + +//------------------------------------------------- +// wangpcbus_mrdc_r - memory read +//------------------------------------------------- + +UINT16 wangpc_lvc_device::wangpcbus_mrdc_r(address_space &space, offs_t offset, UINT16 mem_mask) +{ + UINT16 data = 0xffff; + + if (OPTION_VRAM && (offset >= 0xe0000/2) && (offset < 0xf0000/2)) + { + offs_t addr = offset & 0x7fff; + + data = m_video_ram[addr]; + } + + return data; +} + + +//------------------------------------------------- +// wangpcbus_amwc_w - memory write +//------------------------------------------------- + +void wangpc_lvc_device::wangpcbus_amwc_w(address_space &space, offs_t offset, UINT16 mem_mask, UINT16 data) +{ + if (OPTION_VRAM && (offset >= 0xe0000/2) && (offset < 0xf0000/2)) + { + offs_t addr = offset & 0x7fff; + + m_video_ram[addr] = data; + } +} + + +//------------------------------------------------- +// wangpcbus_iorc_r - I/O read +//------------------------------------------------- + +UINT16 wangpc_lvc_device::wangpcbus_iorc_r(address_space &space, offs_t offset, UINT16 mem_mask) +{ + UINT16 data = 0xffff; + + if (sad(offset)) + { + switch (offset & 0x7f) + { + case 0x02/2: + data = 0xff00 | m_crtc->register_r(space, 0); + break; + + case 0x30/2: + data = 0xffe3; + data |= m_crtc->de_r() << 2; + data |= m_crtc->vsync_r() << 3; + data |= m_crtc->hsync_r() << 4; + break; + + case 0xfe/2: + data = 0xff00 | (m_irq << 7) | OPTION_ID; + break; + } + } + + return data; +} + + +//------------------------------------------------- +// wangpcbus_aiowc_w - I/O write +//------------------------------------------------- + +void wangpc_lvc_device::wangpcbus_aiowc_w(address_space &space, offs_t offset, UINT16 mem_mask, UINT16 data) +{ + if (sad(offset)) + { + switch (offset & 0x7f) + { + case 0x00/2: + if (ACCESSING_BITS_0_7) + { + m_crtc->address_w(space, 0, data & 0xff); + } + break; + + case 0x02/2: + if (ACCESSING_BITS_0_7) + { + m_crtc->register_w(space, 0, data & 0xff); + } + break; + + case 0x10/2: + if (ACCESSING_BITS_0_7) + { + if (LOG) logerror("LVC option %02x\n", data & 0xff); + m_option = data & 0xff; + + if (OPTION_80_COL) + { + m_crtc->set_clock(XTAL_14_31818MHz / 8); + } + else + { + m_crtc->set_clock(XTAL_14_31818MHz / 16); + } + } + break; + + case 0x20/2: + if (LOG) logerror("LVC scroll %04x\n", data); + m_scroll = data; + break; + + case 0x40/2: case 0x42/2: case 0x44/2: case 0x46/2: case 0x48/2: case 0x4a/2: case 0x4c/2: case 0x4e/2: + case 0x50/2: case 0x52/2: case 0x55/2: case 0x56/2: case 0x58/2: case 0x5a/2: case 0x5c/2: case 0x5e/2: + { + offs_t index = offset & 0x0f; + + int i = BIT(data, 15); + int r = BIT(data, 11) ? (i ? 0xff : 0x80) : 0; + int g = BIT(data, 7) ? (i ? 0xff : 0x80) : 0; + int b = BIT(data, 3) ? (i ? 0xff : 0x80) : 0; + + m_palette[index] = rgb_t(r, g, b); + } + break; + + case 0x70/2: + set_irq(CLEAR_LINE); + break; + } + } +} diff --git a/src/devices/bus/wangpc/lvc.h b/src/devices/bus/wangpc/lvc.h new file mode 100644 index 00000000000..9f758f24c06 --- /dev/null +++ b/src/devices/bus/wangpc/lvc.h @@ -0,0 +1,68 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Wang PC Low-Resolution Video Controller emulation + +**********************************************************************/ + +#pragma once + +#ifndef __WANGPC_LVC__ +#define __WANGPC_LVC__ + +#include "emu.h" +#include "wangpc.h" +#include "video/mc6845.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> wangpc_lvc_device + +class wangpc_lvc_device : public device_t, + public device_wangpcbus_card_interface +{ +public: + // construction/destruction + wangpc_lvc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + + // not really public + MC6845_UPDATE_ROW( crtc_update_row ); + DECLARE_WRITE_LINE_MEMBER( vsync_w ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_wangpcbus_card_interface overrides + virtual UINT16 wangpcbus_mrdc_r(address_space &space, offs_t offset, UINT16 mem_mask); + virtual void wangpcbus_amwc_w(address_space &space, offs_t offset, UINT16 mem_mask, UINT16 data); + virtual UINT16 wangpcbus_iorc_r(address_space &space, offs_t offset, UINT16 mem_mask); + virtual void wangpcbus_aiowc_w(address_space &space, offs_t offset, UINT16 mem_mask, UINT16 data); + +private: + inline void set_irq(int state); + + required_device m_crtc; + optional_shared_ptr m_video_ram; + + rgb_t m_palette[16]; + UINT8 m_option; + UINT16 m_scroll; + int m_irq; +}; + + +// device type definition +extern const device_type WANGPC_LVC; + + +#endif diff --git a/src/devices/bus/wangpc/mcc.c b/src/devices/bus/wangpc/mcc.c new file mode 100644 index 00000000000..35a664201b9 --- /dev/null +++ b/src/devices/bus/wangpc/mcc.c @@ -0,0 +1,265 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Wang PC-PM043 Multiport Communications Controller emulation + +**********************************************************************/ + +/* + + TODO: + + - all + +*/ + +#include "mcc.h" + + + +//************************************************************************** +// MACROS/CONSTANTS +//************************************************************************** + +#define LOG 0 + +#define OPTION_ID 0x1f + +#define Z80SIO2_TAG "z80sio2" +#define Z80DART_TAG "z80dart" + +#define FUNCTION_PORT1_EXT_CLK BIT(m_option, 0) +#define FUNCTION_PORT1_NRZI BIT(m_option, 1) +#define FUNCTION_PORT1_RI_IE BIT(m_option, 2) +#define FUNCTION_PORT2_EXT_CLK BIT(m_option, 3) +#define FUNCTION_PORT2_NRZI BIT(m_option, 4) +#define FUNCTION_PORT2_RI_IE BIT(m_option, 5) +#define FUNCTION_IRQ_MASK (m_option & 0xc0) +#define FUNCTION_IRQ2 0x00 +#define FUNCTION_IRQ3 0x40 +#define FUNCTION_IRQ4 0x80 +#define FUNCTION_IRQ_INVALID 0xc0 + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type WANGPC_MCC = &device_creator; + + +//------------------------------------------------- +// MACHINE_CONFIG_FRAGMENT( wangpc_mcc ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( wangpc_mcc ) + MCFG_Z80SIO2_ADD(Z80SIO2_TAG, 4000000, 0, 0, 0, 0) + MCFG_Z80DART_ADD(Z80DART_TAG, 4000000, 0, 0, 0, 0) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor wangpc_mcc_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( wangpc_mcc ); +} + + + +//************************************************************************** +// INLINE HELPERS +//************************************************************************** + +//------------------------------------------------- +// set_irq - +//------------------------------------------------- + +inline void wangpc_mcc_device::set_irq(int state) +{ + m_irq = state; + + switch (FUNCTION_IRQ_MASK) + { + case FUNCTION_IRQ2: m_bus->irq2_w(m_irq); break; + case FUNCTION_IRQ3: m_bus->irq3_w(m_irq); break; + case FUNCTION_IRQ4: m_bus->irq4_w(m_irq); break; + } +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// wangpc_mcc_device - constructor +//------------------------------------------------- + +wangpc_mcc_device::wangpc_mcc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, WANGPC_MCC, "Wang PC-PM043", tag, owner, clock, "wangpc_mcc", __FILE__), + device_wangpcbus_card_interface(mconfig, *this), + m_sio(*this, Z80SIO2_TAG), + m_dart(*this, Z80DART_TAG) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void wangpc_mcc_device::device_start() +{ + // state saving + save_item(NAME(m_option)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void wangpc_mcc_device::device_reset() +{ + m_option = 0; + + set_irq(CLEAR_LINE); +} + + +//------------------------------------------------- +// wangpcbus_iorc_r - I/O read +//------------------------------------------------- + +UINT16 wangpc_mcc_device::wangpcbus_iorc_r(address_space &space, offs_t offset, UINT16 mem_mask) +{ + UINT16 data = 0xffff; + + if (sad(offset)) + { + switch (offset & 0x7f) + { + case 0x00/2: + case 0x02/2: + case 0x04/2: + case 0x06/2: + if (ACCESSING_BITS_0_7) + { + data = 0xff00 | m_sio->cd_ba_r(space, offset >> 1); + } + break; + + case 0x08/2: + case 0x0a/2: + case 0x0c/2: + case 0x0e/2: + if (ACCESSING_BITS_0_7) + { + data = 0xff00 | m_dart->cd_ba_r(space, offset >> 1); + } + break; + + case 0x10/2: + // board status + /* + + bit description + + 0 SIO channel A WAIT/RDY + 1 SIO channel B WAIT/RDY + 2 SIO channel A DSR + 3 SIO channel B DSR + 4 SIO channel A RI + 5 SIO channel B RI + 6 DART channel A WAIT/RDY + 7 DART channel A DSR + 8 DART channel B WAIT/RDY + 9 0 (1 for PC-PM042) + 10 0 (1 for PC-PM042) + 11 0 (1 for PC-PM042) + 12 1 + 13 1 + 14 1 + 15 1 + + */ + data = 0xf000; + break; + + case 0xfe/2: + data = 0xff00 | (m_irq << 7) | OPTION_ID; + break; + } + } + + return data; +} + + +//------------------------------------------------- +// wangpcbus_aiowc_w - I/O write +//------------------------------------------------- + +void wangpc_mcc_device::wangpcbus_aiowc_w(address_space &space, offs_t offset, UINT16 mem_mask, UINT16 data) +{ + if (sad(offset) && ACCESSING_BITS_0_7) + { + switch (offset & 0x7f) + { + case 0x00/2: + case 0x02/2: + case 0x04/2: + case 0x06/2: + m_sio->cd_ba_w(space, offset >> 1, data & 0xff); + break; + + case 0x08/2: + case 0x0a/2: + case 0x0c/2: + case 0x0e/2: + m_dart->cd_ba_w(space, offset >> 1, data & 0xff); + break; + + case 0x12/2: + // port 1 baud rate + break; + + case 0x14/2: + // port 2 baud rate + break; + + case 0x16/2: + { + // ports 1 and 2 function + bool irq = (m_irq == ASSERT_LINE); + bool changed = (FUNCTION_IRQ_MASK != (data & 0xc0)); + + if (irq && changed) set_irq(CLEAR_LINE); + + m_option = data & 0xff; + + if (irq && changed) set_irq(ASSERT_LINE); + } + break; + + case 0x18/2: + // port 3 channel A baud rate + break; + + case 0x1a/2: + // port 3 channel B baud rate + break; + + case 0xfc/2: + device_reset(); + break; + } + } +} diff --git a/src/devices/bus/wangpc/mcc.h b/src/devices/bus/wangpc/mcc.h new file mode 100644 index 00000000000..a87be116251 --- /dev/null +++ b/src/devices/bus/wangpc/mcc.h @@ -0,0 +1,60 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Wang PC-PM043 Multiport Communications Controller emulation + +**********************************************************************/ + +#pragma once + +#ifndef __WANGPC_MCC__ +#define __WANGPC_MCC__ + +#include "emu.h" +#include "wangpc.h" +#include "machine/z80dart.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> wangpc_mcc_device + +class wangpc_mcc_device : public device_t, + public device_wangpcbus_card_interface +{ +public: + // construction/destruction + wangpc_mcc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_wangpcbus_card_interface overrides + virtual UINT16 wangpcbus_iorc_r(address_space &space, offs_t offset, UINT16 mem_mask); + virtual void wangpcbus_aiowc_w(address_space &space, offs_t offset, UINT16 mem_mask, UINT16 data); + +private: + inline void set_irq(int state); + + required_device m_sio; + required_device m_dart; + + UINT8 m_option; + int m_irq; +}; + + +// device type definition +extern const device_type WANGPC_MCC; + + +#endif diff --git a/src/devices/bus/wangpc/mvc.c b/src/devices/bus/wangpc/mvc.c new file mode 100644 index 00000000000..9a2e74a0f4a --- /dev/null +++ b/src/devices/bus/wangpc/mvc.c @@ -0,0 +1,333 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Wang PC PM-001B Medium-Resolution Video Controller emulation + +**********************************************************************/ + +/* + + TODO: + + - character clock + - blink + +*/ + +#include "mvc.h" + + + +//************************************************************************** +// MACROS/CONSTANTS +//************************************************************************** + +#define LOG 0 + +#define OPTION_ID 0x15 + +#define MC6845_TAG "mc6845" +#define SCREEN_TAG "screen" + +#define VIDEO_RAM_SIZE 0x800 +#define CHAR_RAM_SIZE 0x1000 +#define BITMAP_RAM_SIZE 0x4000 + +#define OPTION_VRAM BIT(m_option, 0) +#define OPTION_VSYNC BIT(m_option, 3) + +#define ATTR_BLINK BIT(attr, 0) +#define ATTR_REVERSE BIT(attr, 1) +#define ATTR_BLANK BIT(attr, 2) +#define ATTR_BOLD BIT(attr, 3) +#define ATTR_OVERSCORE BIT(attr, 4) +#define ATTR_UNDERSCORE BIT(attr, 5) +#define ATTR_SUBSCRIPT BIT(attr, 6) +#define ATTR_SUPERSCRIPT BIT(attr, 7) + +static const rgb_t PALETTE_MVC[] = +{ + rgb_t::black, + rgb_t(0x00, 0x80, 0x00), + rgb_t(0x00, 0xff, 0x00) +}; + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type WANGPC_MVC = &device_creator; + + +//------------------------------------------------- +// mc6845 +//------------------------------------------------- + +MC6845_UPDATE_ROW( wangpc_mvc_device::crtc_update_row ) +{ + for (int sx = 0; sx < 50; sx++) + { + offs_t addr = (y * 50) + sx; + UINT16 data = m_bitmap_ram[addr]; + + for (int bit = 0; bit < 16; bit++) + { + int x = (sx * 16) + bit; + int color = BIT(data, 15) && de; + + bitmap.pix32(vbp + y, hbp + x) = PALETTE_MVC[color]; + + data <<= 1; + } + } + + for (int column = 0; column < x_count; column++) + { + UINT16 code = m_video_ram[((ma + column) & 0x7ff)]; + UINT8 attr = code & 0xff; + + UINT8 new_ra = ra + 1; + + if (ATTR_SUPERSCRIPT) + { + new_ra = ra + 3; + } + else if (ATTR_SUBSCRIPT) + { + new_ra = ra; + } + + offs_t addr = ((code >> 8) << 4) | (new_ra & 0x0f); + UINT16 data = m_char_ram[addr & 0xfff]; + + if ((column == cursor_x) || (!ra && ATTR_OVERSCORE) || ((ra == 9) && ATTR_UNDERSCORE)) + { + data = 0xffff; + } + + for (int bit = 0; bit < 10; bit++) + { + int x = (column * 10) + bit; + int color = ((BIT(data, 9) & !ATTR_BLANK) ^ ATTR_REVERSE); + + if ((color | bitmap.pix32(vbp + y, hbp + x)) & ATTR_BOLD) color = 2; + if (color) bitmap.pix32(vbp + y, hbp + x) = de ? PALETTE_MVC[color] : rgb_t::black; + + data <<= 1; + } + } +} + +WRITE_LINE_MEMBER( wangpc_mvc_device::vsync_w ) +{ + if (OPTION_VSYNC && state) + { + set_irq(ASSERT_LINE); + } +} + +//------------------------------------------------- +// MACHINE_CONFIG_FRAGMENT( wangpc_mvc ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( wangpc_mvc ) + MCFG_SCREEN_ADD(SCREEN_TAG, RASTER) + MCFG_SCREEN_UPDATE_DEVICE(MC6845_TAG, mc6845_device, screen_update) + MCFG_SCREEN_SIZE(80*10, 25*12) + MCFG_SCREEN_VISIBLE_AREA(0, 80*10-1, 0, 25*12-1) + MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(2500)) + MCFG_SCREEN_REFRESH_RATE(60) + + MCFG_MC6845_ADD(MC6845_TAG, MC6845_1, SCREEN_TAG, XTAL_14_31818MHz/16) + MCFG_MC6845_SHOW_BORDER_AREA(true) + MCFG_MC6845_CHAR_WIDTH(10) + MCFG_MC6845_UPDATE_ROW_CB(wangpc_mvc_device, crtc_update_row) + MCFG_MC6845_OUT_VSYNC_CB(WRITELINE(wangpc_mvc_device, vsync_w)) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor wangpc_mvc_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( wangpc_mvc ); +} + + + +//************************************************************************** +// INLINE HELPERS +//************************************************************************** + +//------------------------------------------------- +// set_irq - +//------------------------------------------------- + +inline void wangpc_mvc_device::set_irq(int state) +{ + m_irq = state; + + m_bus->irq3_w(m_irq); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// wangpc_mvc_device - constructor +//------------------------------------------------- + +wangpc_mvc_device::wangpc_mvc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, WANGPC_MVC, "Wang PC Medium Resolution Video Card", tag, owner, clock, "wangpc_mvc", __FILE__), + device_wangpcbus_card_interface(mconfig, *this), + m_crtc(*this, MC6845_TAG), + m_video_ram(*this, "video_ram"), + m_char_ram(*this, "char_ram"), + m_bitmap_ram(*this, "bitmap_ram"), + m_option(0), + m_irq(CLEAR_LINE) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void wangpc_mvc_device::device_start() +{ + // allocate memory + m_video_ram.allocate(VIDEO_RAM_SIZE); + m_char_ram.allocate(CHAR_RAM_SIZE); + m_bitmap_ram.allocate(BITMAP_RAM_SIZE); + + // state saving + save_item(NAME(m_option)); + save_item(NAME(m_irq)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void wangpc_mvc_device::device_reset() +{ + m_option = 0; + + set_irq(CLEAR_LINE); +} + + +//------------------------------------------------- +// wangpcbus_mrdc_r - memory read +//------------------------------------------------- + +UINT16 wangpc_mvc_device::wangpcbus_mrdc_r(address_space &space, offs_t offset, UINT16 mem_mask) +{ + UINT16 data = 0xffff; + + if (OPTION_VRAM) + { + if (offset >= 0xe0000/2 && offset < 0xe8000/2) + { + data = m_bitmap_ram[offset & 0x3fff]; + } + else if (offset >= 0xf0000/2 && offset < 0xf1000/2) + { + data = m_video_ram[offset & 0x7ff]; + } + else if (offset >= 0xf2000/2 && offset < 0xf4000/2) + { + data = m_char_ram[offset & 0xfff]; + } + } + + return data; +} + + +//------------------------------------------------- +// wangpcbus_amwc_w - memory write +//------------------------------------------------- + +void wangpc_mvc_device::wangpcbus_amwc_w(address_space &space, offs_t offset, UINT16 mem_mask, UINT16 data) +{ + if (OPTION_VRAM) + { + if (offset >= 0xe0000/2 && offset < 0xe8000/2) + { + m_bitmap_ram[offset & 0x3fff] = data; + } + else if (offset >= 0xf0000/2 && offset < 0xf1000/2) + { + m_video_ram[offset & 0x7ff] = data; + } + else if (offset >= 0xf2000/2 && offset < 0xf4000/2) + { + m_char_ram[offset & 0xfff] = data; + } + } +} + + +//------------------------------------------------- +// wangpcbus_iorc_r - I/O read +//------------------------------------------------- + +UINT16 wangpc_mvc_device::wangpcbus_iorc_r(address_space &space, offs_t offset, UINT16 mem_mask) +{ + UINT16 data = 0xffff; + + if (sad(offset)) + { + switch (offset & 0x7f) + { + case 0xfe/2: + data = 0xff00 | (m_irq << 7) | OPTION_ID; + + set_irq(CLEAR_LINE); + break; + } + } + + return data; +} + + +//------------------------------------------------- +// wangpcbus_aiowc_w - I/O write +//------------------------------------------------- + +void wangpc_mvc_device::wangpcbus_aiowc_w(address_space &space, offs_t offset, UINT16 mem_mask, UINT16 data) +{ + if (sad(offset) && ACCESSING_BITS_0_7) + { + switch (offset & 0x7f) + { + case 0x00/2: + m_crtc->address_w(space, 0, data & 0xff); + break; + + case 0x02/2: + m_crtc->register_w(space, 0, data & 0xff); + break; + + case 0x10/2: + case 0x12/2: + if (LOG) logerror("MVC option %02x\n", data & 0xff); + + m_option = data & 0xff; + break; + } + } +} diff --git a/src/devices/bus/wangpc/mvc.h b/src/devices/bus/wangpc/mvc.h new file mode 100644 index 00000000000..6521aee33a4 --- /dev/null +++ b/src/devices/bus/wangpc/mvc.h @@ -0,0 +1,68 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Wang PC PM-001B Medium-Resolution Video Controller emulation + +**********************************************************************/ + +#pragma once + +#ifndef __WANGPC_MVC__ +#define __WANGPC_MVC__ + +#include "emu.h" +#include "wangpc.h" +#include "video/mc6845.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> wangpc_mvc_device + +class wangpc_mvc_device : public device_t, + public device_wangpcbus_card_interface +{ +public: + // construction/destruction + wangpc_mvc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + + // not really public + MC6845_UPDATE_ROW( crtc_update_row ); + DECLARE_WRITE_LINE_MEMBER( vsync_w ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_wangpcbus_card_interface overrides + virtual UINT16 wangpcbus_mrdc_r(address_space &space, offs_t offset, UINT16 mem_mask); + virtual void wangpcbus_amwc_w(address_space &space, offs_t offset, UINT16 mem_mask, UINT16 data); + virtual UINT16 wangpcbus_iorc_r(address_space &space, offs_t offset, UINT16 mem_mask); + virtual void wangpcbus_aiowc_w(address_space &space, offs_t offset, UINT16 mem_mask, UINT16 data); + +private: + inline void set_irq(int state); + + required_device m_crtc; + optional_shared_ptr m_video_ram; + optional_shared_ptr m_char_ram; + optional_shared_ptr m_bitmap_ram; + + UINT8 m_option; + int m_irq; +}; + + +// device type definition +extern const device_type WANGPC_MVC; + + +#endif diff --git a/src/devices/bus/wangpc/rtc.c b/src/devices/bus/wangpc/rtc.c new file mode 100644 index 00000000000..2f2ea7a073f --- /dev/null +++ b/src/devices/bus/wangpc/rtc.c @@ -0,0 +1,278 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Wang PC-PM040-B Remote Telecommunication controller emulation + +**********************************************************************/ + +#include "rtc.h" + + + +//************************************************************************** +// MACROS/CONSTANTS +//************************************************************************** + +#define OPTION_ID 0x1c + +#define Z80_TAG "z80" +#define AM9517A_TAG "am9517" +#define Z80CTC_0_TAG "z80ctc_0" +#define Z80CTC_1_TAG "z80ctc_1" +#define Z80SIO_TAG "z80sio" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type WANGPC_RTC = &device_creator; + + +//------------------------------------------------- +// ROM( wangpc_rtc ) +//------------------------------------------------- + +ROM_START( wangpc_rtc ) + ROM_REGION( 0x1000, Z80_TAG, 0 ) + ROM_LOAD( "remotecomms-l28.bin", 0x0000, 0x1000, CRC(c05a1bee) SHA1(6b3f0d787d014b1fd3925812c905ddb63c5055f1) ) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *wangpc_rtc_device::device_rom_region() const +{ + return ROM_NAME( wangpc_rtc ); +} + + +//------------------------------------------------- +// ADDRESS_MAP( wangpc_rtc_mem ) +//------------------------------------------------- + +static ADDRESS_MAP_START( wangpc_rtc_mem, AS_PROGRAM, 8, wangpc_rtc_device ) + AM_RANGE(0x0000, 0x0fff) AM_ROM AM_REGION(Z80_TAG, 0) + AM_RANGE(0x1000, 0xffff) AM_RAM +ADDRESS_MAP_END + + +//------------------------------------------------- +// ADDRESS_MAP( wangpc_rtc_io ) +//------------------------------------------------- + +static ADDRESS_MAP_START( wangpc_rtc_io, AS_IO, 8, wangpc_rtc_device ) + ADDRESS_MAP_GLOBAL_MASK(0xff) + AM_RANGE(0x00, 0x03) AM_DEVREADWRITE(Z80SIO_TAG, z80sio0_device, cd_ba_r, cd_ba_w) + AM_RANGE(0x10, 0x1f) AM_DEVREADWRITE(AM9517A_TAG, am9517a_device, read, write) + AM_RANGE(0x20, 0x23) AM_DEVREADWRITE(Z80CTC_0_TAG, z80ctc_device, read, write) + AM_RANGE(0x30, 0x30) //AM_WRITE(clear_char_w) + AM_RANGE(0x31, 0x31) //AM_WRITE(set_char_w) + AM_RANGE(0x40, 0x40) AM_READ_PORT("SW1") //AM_WRITE(control_w) + AM_RANGE(0x44, 0x44) //AM_READ(i8086_status_r) AM_WRITE(reset_w) + AM_RANGE(0x48, 0x48) //AM_WRITE(dte_ready_w) + AM_RANGE(0x4c, 0x4c) //AM_READWRITE(8232_acu_r, 8232_acu_w) + AM_RANGE(0x50, 0x50) //AM_READ(outbound_data_r) + AM_RANGE(0x51, 0x52) //AM_WRITE(status_w) + AM_RANGE(0x54, 0x54) //AM_WRITE(enable_inbound_data_w) + AM_RANGE(0x51, 0x52) //AM_WRITE(inbound_data_w) + AM_RANGE(0x60, 0x63) AM_DEVREADWRITE(Z80CTC_1_TAG, z80ctc_device, read, write) + AM_RANGE(0x70, 0x70) //AM_READWRITE(led_toggle_r, odd_parity_w) + AM_RANGE(0x71, 0x71) //AM_WRITE(even_parity_w) +ADDRESS_MAP_END + + +//------------------------------------------------- +// z80_daisy_config wangpc_rtc_daisy_chain +//------------------------------------------------- + +static const z80_daisy_config wangpc_rtc_daisy_chain[] = +{ + { Z80SIO_TAG }, + { Z80CTC_0_TAG }, + { Z80CTC_1_TAG }, + { NULL } +}; + +//------------------------------------------------- +// MACHINE_CONFIG_FRAGMENT( wangpc_rtc ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( wangpc_rtc ) + MCFG_CPU_ADD(Z80_TAG, Z80, 2000000) + MCFG_CPU_CONFIG(wangpc_rtc_daisy_chain) + MCFG_CPU_PROGRAM_MAP(wangpc_rtc_mem) + MCFG_CPU_IO_MAP(wangpc_rtc_io) + + MCFG_DEVICE_ADD(AM9517A_TAG, AM9517A, 2000000) + + MCFG_DEVICE_ADD(Z80CTC_0_TAG, Z80CTC, 2000000) + MCFG_Z80CTC_INTR_CB(INPUTLINE(Z80_TAG, INPUT_LINE_IRQ0)) + + MCFG_DEVICE_ADD(Z80CTC_1_TAG, Z80CTC, 2000000) + MCFG_Z80CTC_INTR_CB(INPUTLINE(Z80_TAG, INPUT_LINE_IRQ0)) + + MCFG_Z80SIO0_ADD(Z80SIO_TAG, 2000000, 0, 0, 0, 0) + MCFG_Z80DART_OUT_INT_CB(INPUTLINE(Z80_TAG, INPUT_LINE_IRQ0)) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor wangpc_rtc_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( wangpc_rtc ); +} + + +//------------------------------------------------- +// INPUT_PORTS( wangpc_rtc ) +//------------------------------------------------- + +INPUT_PORTS_START( wangpc_rtc ) + PORT_START("SW1") + PORT_DIPNAME( 0x01, 0x01, DEF_STR( Unknown ) ) PORT_DIPLOCATION("SW1:1") + PORT_DIPSETTING( 0x01, DEF_STR( On ) ) + PORT_DIPSETTING( 0x00, DEF_STR( Off ) ) + PORT_DIPNAME( 0x02, 0x02, DEF_STR( Unknown ) ) PORT_DIPLOCATION("SW1:2") + PORT_DIPSETTING( 0x02, DEF_STR( On ) ) + PORT_DIPSETTING( 0x00, DEF_STR( Off ) ) + PORT_DIPNAME( 0x04, 0x04, DEF_STR( Unknown ) ) PORT_DIPLOCATION("SW1:3") + PORT_DIPSETTING( 0x04, DEF_STR( On ) ) + PORT_DIPSETTING( 0x00, DEF_STR( Off ) ) + PORT_DIPNAME( 0x08, 0x08, DEF_STR( Unknown ) ) PORT_DIPLOCATION("SW1:4") + PORT_DIPSETTING( 0x08, DEF_STR( On ) ) + PORT_DIPSETTING( 0x00, DEF_STR( Off ) ) + PORT_DIPNAME( 0x10, 0x10, DEF_STR( Unknown ) ) PORT_DIPLOCATION("SW1:5") + PORT_DIPSETTING( 0x10, DEF_STR( On ) ) + PORT_DIPSETTING( 0x00, DEF_STR( Off ) ) + PORT_DIPNAME( 0x20, 0x20, DEF_STR( Unknown ) ) PORT_DIPLOCATION("SW1:6") + PORT_DIPSETTING( 0x20, DEF_STR( On ) ) + PORT_DIPSETTING( 0x00, DEF_STR( Off ) ) + PORT_DIPNAME( 0x40, 0x40, DEF_STR( Unknown ) ) PORT_DIPLOCATION("SW1:7") + PORT_DIPSETTING( 0x40, DEF_STR( On ) ) + PORT_DIPSETTING( 0x00, DEF_STR( Off ) ) + PORT_DIPNAME( 0x80, 0x80, DEF_STR( Unknown ) ) PORT_DIPLOCATION("SW1:8") + PORT_DIPSETTING( 0x80, DEF_STR( On ) ) + PORT_DIPSETTING( 0x00, DEF_STR( Off ) ) +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor wangpc_rtc_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( wangpc_rtc ); +} + + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// wangpc_rtc_device - constructor +//------------------------------------------------- + +wangpc_rtc_device::wangpc_rtc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, WANGPC_RTC, "Wang PC-PM040-B", tag, owner, clock, "wangpc_rtc", __FILE__), + device_wangpcbus_card_interface(mconfig, *this), + m_maincpu(*this, Z80_TAG), + m_dmac(*this, AM9517A_TAG), + m_ctc0(*this, Z80CTC_0_TAG), + m_ctc1(*this, Z80CTC_1_TAG), + m_sio(*this, Z80SIO_TAG), + m_char_ram(*this, "char_ram") +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void wangpc_rtc_device::device_start() +{ + m_char_ram.allocate(0x100); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void wangpc_rtc_device::device_reset() +{ +} + + +//------------------------------------------------- +// wangpcbus_mrdc_r - memory read +//------------------------------------------------- + +UINT16 wangpc_rtc_device::wangpcbus_mrdc_r(address_space &space, offs_t offset, UINT16 mem_mask) +{ + UINT16 data = 0xffff; + + return data; +} + + +//------------------------------------------------- +// wangpcbus_amwc_w - memory write +//------------------------------------------------- + +void wangpc_rtc_device::wangpcbus_amwc_w(address_space &space, offs_t offset, UINT16 mem_mask, UINT16 data) +{ +} + + +//------------------------------------------------- +// wangpcbus_iorc_r - I/O read +//------------------------------------------------- + +UINT16 wangpc_rtc_device::wangpcbus_iorc_r(address_space &space, offs_t offset, UINT16 mem_mask) +{ + UINT16 data = 0xffff; + + if (sad(offset)) + { + switch (offset & 0x7f) + { + case 0xfe/2: + data = 0xff00 | OPTION_ID; + break; + } + } + + return data; +} + + +//------------------------------------------------- +// wangpcbus_aiowc_w - I/O write +//------------------------------------------------- + +void wangpc_rtc_device::wangpcbus_aiowc_w(address_space &space, offs_t offset, UINT16 mem_mask, UINT16 data) +{ + if (sad(offset)) + { + switch (offset & 0x7f) + { + case 0xfc/2: + device_reset(); + break; + } + } +} diff --git a/src/devices/bus/wangpc/rtc.h b/src/devices/bus/wangpc/rtc.h new file mode 100644 index 00000000000..1162c743f23 --- /dev/null +++ b/src/devices/bus/wangpc/rtc.h @@ -0,0 +1,66 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Wang PC-PM040-B Remote Telecommunication controller emulation + +**********************************************************************/ + +#pragma once + +#ifndef __WANGPC_RTC__ +#define __WANGPC_RTC__ + +#include "emu.h" +#include "wangpc.h" +#include "cpu/z80/z80.h" +#include "machine/am9517a.h" +#include "machine/z80ctc.h" +#include "machine/z80dart.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> wangpc_rtc_device + +class wangpc_rtc_device : public device_t, + public device_wangpcbus_card_interface +{ +public: + // construction/destruction + wangpc_rtc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + virtual ioport_constructor device_input_ports() const; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_wangpcbus_card_interface overrides + virtual UINT16 wangpcbus_mrdc_r(address_space &space, offs_t offset, UINT16 mem_mask); + virtual void wangpcbus_amwc_w(address_space &space, offs_t offset, UINT16 mem_mask, UINT16 data); + virtual UINT16 wangpcbus_iorc_r(address_space &space, offs_t offset, UINT16 mem_mask); + virtual void wangpcbus_aiowc_w(address_space &space, offs_t offset, UINT16 mem_mask, UINT16 data); + +private: + required_device m_maincpu; + required_device m_dmac; + required_device m_ctc0; + required_device m_ctc1; + required_device m_sio; + optional_shared_ptr m_char_ram; +}; + + +// device type definition +extern const device_type WANGPC_RTC; + + +#endif diff --git a/src/devices/bus/wangpc/tig.c b/src/devices/bus/wangpc/tig.c new file mode 100644 index 00000000000..a2b7214c054 --- /dev/null +++ b/src/devices/bus/wangpc/tig.c @@ -0,0 +1,324 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Wang PC Text/Image/Graphics controller emulation + +**********************************************************************/ + +/* + + TODO: + + - all + +*/ + +#include "tig.h" + + + +//************************************************************************** +// MACROS/CONSTANTS +//************************************************************************** + +#define LOG 1 + +#define OPTION_ID_0 0x13 +#define OPTION_ID_1 0x17 + +#define UPD7720_0_TAG "upd7220_0" +#define UPD7720_1_TAG "upd7220_1" +#define SCREEN_TAG "screen" + +#define DMA_GRAPHICS BIT(m_option, 0) +#define DMA_DREQ1 BIT(m_option, 1) +#define DMA_DREQ2 BIT(m_option, 2) +#define DMA_DREQ3 BIT(m_option, 3) +#define DMA_ID BIT(m_option, 4) + +#define ATTR_ALT_FONT BIT(data, 8) +#define ATTR_UNDERSCORE BIT(data, 9) +#define ATTR_BLINK BIT(data, 10) +#define ATTR_REVERSE BIT(data, 11) +#define ATTR_BLANK BIT(data, 12) +#define ATTR_BOLD BIT(data, 13) +#define ATTR_SUBSCRIPT BIT(data, 14) +#define ATTR_SUPERSCRIPT BIT(data, 15) + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type WANGPC_TIG = &device_creator; + + +//------------------------------------------------- +// ROM( wangpc_tig ) +//------------------------------------------------- + +ROM_START( wangpc_tig ) + ROM_REGION( 0x100, "plds", 0 ) + ROM_LOAD( "377-3072.l26", 0x000, 0x100, NO_DUMP ) // PAL10L8 + ROM_LOAD( "377-3073.l16", 0x000, 0x100, NO_DUMP ) // PAL10L8 +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *wangpc_tig_device::device_rom_region() const +{ + return ROM_NAME( wangpc_tig ); +} + + +//------------------------------------------------- +// UPD7220_INTERFACE( hgdc0_intf ) +//------------------------------------------------- + +static ADDRESS_MAP_START( upd7220_0_map, AS_0, 16, wangpc_tig_device ) + ADDRESS_MAP_GLOBAL_MASK(0x7fff) + AM_RANGE(0x0000, 0x0fff) AM_MIRROR(0x1000) AM_RAM // frame buffer + AM_RANGE(0x4000, 0x7fff) AM_RAM // font memory +ADDRESS_MAP_END + +UPD7220_DRAW_TEXT_LINE_MEMBER( wangpc_tig_device::hgdc_draw_text ) +{ +} + + +//------------------------------------------------- +// UPD7220_INTERFACE( hgdc1_intf ) +//------------------------------------------------- + +static ADDRESS_MAP_START( upd7220_1_map, AS_0, 16, wangpc_tig_device ) + ADDRESS_MAP_GLOBAL_MASK(0xffff) + AM_RANGE(0x0000, 0xffff) AM_RAM // graphics memory +ADDRESS_MAP_END + +UPD7220_DISPLAY_PIXELS_MEMBER( wangpc_tig_device::hgdc_display_pixels ) +{ +} + + +//------------------------------------------------- +// MACHINE_CONFIG_FRAGMENT( wangpc_tig ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( wangpc_tig ) + MCFG_SCREEN_ADD(SCREEN_TAG, RASTER) + MCFG_SCREEN_UPDATE_DEVICE(DEVICE_SELF, wangpc_tig_device, screen_update) + MCFG_SCREEN_SIZE(80*10, 25*12) + MCFG_SCREEN_VISIBLE_AREA(0, 80*10-1, 0, 25*12-1) + MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(2500)) + MCFG_SCREEN_REFRESH_RATE(60) + + MCFG_PALETTE_ADD_MONOCHROME_GREEN_HIGHLIGHT("palette") + + MCFG_DEVICE_ADD(UPD7720_0_TAG, UPD7220, XTAL_52_832MHz/28) + MCFG_DEVICE_ADDRESS_MAP(AS_0, upd7220_0_map) + MCFG_UPD7220_DRAW_TEXT_CALLBACK_OWNER(wangpc_tig_device, hgdc_draw_text) + MCFG_VIDEO_SET_SCREEN(SCREEN_TAG) + + MCFG_DEVICE_ADD(UPD7720_1_TAG, UPD7220, XTAL_52_832MHz/28) + MCFG_DEVICE_ADDRESS_MAP(AS_0, upd7220_1_map) + MCFG_UPD7220_DISPLAY_PIXELS_CALLBACK_OWNER(wangpc_tig_device, hgdc_display_pixels) + MCFG_VIDEO_SET_SCREEN(SCREEN_TAG) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor wangpc_tig_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( wangpc_tig ); +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// wangpc_tig_device - constructor +//------------------------------------------------- + +wangpc_tig_device::wangpc_tig_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, WANGPC_TIG, "Wang PC TIG Controller", tag, owner, clock, "wangpc_tig", __FILE__), + device_wangpcbus_card_interface(mconfig, *this), + m_hgdc0(*this, UPD7720_0_TAG), + m_hgdc1(*this, UPD7720_1_TAG), + m_option(0), + m_palette(*this, "palette") +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void wangpc_tig_device::device_start() +{ + // state saving + save_item(NAME(m_option)); + save_item(NAME(m_attr)); + save_item(NAME(m_underline)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void wangpc_tig_device::device_reset() +{ + m_option = 0; +} + + +//------------------------------------------------- +// screen_update - +//------------------------------------------------- + +UINT32 wangpc_tig_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + m_hgdc0->screen_update(screen, bitmap, cliprect); + m_hgdc1->screen_update(screen, bitmap, cliprect); + + return 0; +} + + +//------------------------------------------------- +// wangpcbus_iorc_r - I/O read +//------------------------------------------------- + +UINT16 wangpc_tig_device::wangpcbus_iorc_r(address_space &space, offs_t offset, UINT16 mem_mask) +{ + UINT16 data = 0xffff; + + if (sad(offset)) + { + switch (offset & 0x7f) + { + case 0x20/2: + case 0x22/2: + data = m_hgdc0->read(space, offset); + break; + + case 0x24/2: + case 0x26/2: + data = m_hgdc1->read(space, offset); + break; + + case 0xfe/2: + data = 0xff00 | (DMA_ID ? OPTION_ID_1 : OPTION_ID_0); + break; + } + } + + return data; +} + + +//------------------------------------------------- +// wangpcbus_aiowc_w - I/O write +//------------------------------------------------- + +void wangpc_tig_device::wangpcbus_aiowc_w(address_space &space, offs_t offset, UINT16 mem_mask, UINT16 data) +{ + if (sad(offset) && ACCESSING_BITS_0_7) + { + switch (offset & 0x7f) + { + case 0x00/2: case 0x02/2: case 0x04/2: case 0x06/2: case 0x08/2: case 0x0a/2: case 0x0c/2: case 0x0e/2: + case 0x10/2: case 0x12/2: case 0x14/2: case 0x16/2: case 0x18/2: case 0x1a/2: case 0x1c/2: case 0x1e/2: + if (LOG) logerror("TIG attribute %u: %02x\n", offset, data & 0xff); + + m_attr[offset] = data & 0xff; + break; + + case 0x20/2: + case 0x22/2: + m_hgdc0->write(space, offset, data); + break; + + case 0x24/2: + case 0x26/2: + m_hgdc1->write(space, offset, data); + break; + + case 0x28/2: + if (LOG) logerror("TIG underline %02x\n", data & 0xff); + + m_underline = data & 0xff; + break; + + case 0x2a/2: + if (LOG) logerror("TIG option %02x\n", data & 0xff); + + m_option = data & 0xff; + break; + + case 0xfc/2: + device_reset(); + break; + } + } +} + + +//------------------------------------------------- +// wangpcbus_dack_r - DMA read +//------------------------------------------------- + +UINT8 wangpc_tig_device::wangpcbus_dack_r(address_space &space, int line) +{ + UINT8 data = 0; + + if (DMA_GRAPHICS) + { + data = m_hgdc1->dack_r(space, 0); + } + else + { + data = m_hgdc0->dack_r(space, 0); + } + + return data; +} + + +//------------------------------------------------- +// wangpcbus_dack_w - DMA write +//------------------------------------------------- + +void wangpc_tig_device::wangpcbus_dack_w(address_space &space, int line, UINT8 data) +{ + if (DMA_GRAPHICS) + { + m_hgdc1->dack_w(space, 0, data); + } + else + { + m_hgdc0->dack_w(space, 0, data); + } +} + + +//------------------------------------------------- +// wangpcbus_have_dack - DMA acknowledge +//------------------------------------------------- + +bool wangpc_tig_device::wangpcbus_have_dack(int line) +{ + return (line == 1 && DMA_DREQ1) || (line == 2 && DMA_DREQ2) || (line == 3 && DMA_DREQ3); +} diff --git a/src/devices/bus/wangpc/tig.h b/src/devices/bus/wangpc/tig.h new file mode 100644 index 00000000000..66b29c0ad3d --- /dev/null +++ b/src/devices/bus/wangpc/tig.h @@ -0,0 +1,69 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Wang PC PM-001B Medium-Resolution Video Controller emulation + +**********************************************************************/ + +#pragma once + +#ifndef __WANGPC_TIG__ +#define __WANGPC_TIG__ + +#include "emu.h" +#include "wangpc.h" +#include "video/upd7220.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> wangpc_tig_device + +class wangpc_tig_device : public device_t, + public device_wangpcbus_card_interface +{ +public: + // construction/destruction + wangpc_tig_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + UINT32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); + + UPD7220_DRAW_TEXT_LINE_MEMBER( hgdc_draw_text ); + UPD7220_DISPLAY_PIXELS_MEMBER( hgdc_display_pixels ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_wangpcbus_card_interface overrides + virtual UINT16 wangpcbus_iorc_r(address_space &space, offs_t offset, UINT16 mem_mask); + virtual void wangpcbus_aiowc_w(address_space &space, offs_t offset, UINT16 mem_mask, UINT16 data); + virtual UINT8 wangpcbus_dack_r(address_space &space, int line); + virtual void wangpcbus_dack_w(address_space &space, int line, UINT8 data); + virtual bool wangpcbus_have_dack(int line); + +private: + // internal state + required_device m_hgdc0; + required_device m_hgdc1; + + UINT8 m_option; + UINT8 m_attr[16]; + UINT8 m_underline; + required_device m_palette; +}; + + +// device type definition +extern const device_type WANGPC_TIG; + + +#endif diff --git a/src/devices/bus/wangpc/wangpc.c b/src/devices/bus/wangpc/wangpc.c new file mode 100644 index 00000000000..d5773f8e283 --- /dev/null +++ b/src/devices/bus/wangpc/wangpc.c @@ -0,0 +1,278 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Wang Professional Computer bus emulation + +**********************************************************************/ + +#include "wangpc.h" + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type WANGPC_BUS = &device_creator; +const device_type WANGPC_BUS_SLOT = &device_creator; + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// wangpcbus_slot_device - constructor +//------------------------------------------------- + +wangpcbus_slot_device::wangpcbus_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, WANGPC_BUS_SLOT, "Wang PC bus slot", tag, owner, clock, "wangpcbus_slot", __FILE__), + device_slot_interface(mconfig, *this) +{ +} + +void wangpcbus_slot_device::static_set_wangpcbus_slot(device_t &device, int sid) +{ + wangpcbus_slot_device &wangpcbus_card = dynamic_cast(device); + wangpcbus_card.m_sid = sid; +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void wangpcbus_slot_device::device_start() +{ + m_bus = machine().device(WANGPC_BUS_TAG); + device_wangpcbus_card_interface *dev = dynamic_cast(get_card_device()); + if (dev) m_bus->add_card(dev, m_sid); +} + + +//------------------------------------------------- +// wangpcbus_device - constructor +//------------------------------------------------- + +wangpcbus_device::wangpcbus_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, WANGPC_BUS, "Wang PC bus", tag, owner, clock, "wangpcbus", __FILE__), + m_write_irq2(*this), + m_write_irq3(*this), + m_write_irq4(*this), + m_write_irq5(*this), + m_write_irq6(*this), + m_write_irq7(*this), + m_write_drq1(*this), + m_write_drq2(*this), + m_write_drq3(*this), + m_write_ioerror(*this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void wangpcbus_device::device_start() +{ + // resolve callbacks + m_write_irq2.resolve_safe(); + m_write_irq3.resolve_safe(); + m_write_irq4.resolve_safe(); + m_write_irq5.resolve_safe(); + m_write_irq6.resolve_safe(); + m_write_irq7.resolve_safe(); + m_write_drq1.resolve_safe(); + m_write_drq2.resolve_safe(); + m_write_drq3.resolve_safe(); + m_write_ioerror.resolve_safe(); +} + + +//------------------------------------------------- +// add_card - add card +//------------------------------------------------- + +void wangpcbus_device::add_card(device_wangpcbus_card_interface *card, int sid) +{ + m_device_list.append(*card); + + card->m_bus = this; + card->m_sid = sid; +} + + +//------------------------------------------------- +// mrdc_r - memory read +//------------------------------------------------- + +READ16_MEMBER( wangpcbus_device::mrdc_r ) +{ + UINT16 data = 0xffff; + + device_wangpcbus_card_interface *entry = m_device_list.first(); + + while (entry) + { + data &= entry->wangpcbus_mrdc_r(space, offset + 0x40000/2, mem_mask); + entry = entry->next(); + } + + return data; +} + + +//------------------------------------------------- +// amwc_w - memory write +//------------------------------------------------- + +WRITE16_MEMBER( wangpcbus_device::amwc_w ) +{ + device_wangpcbus_card_interface *entry = m_device_list.first(); + + while (entry) + { + entry->wangpcbus_amwc_w(space, offset + 0x40000/2, mem_mask, data); + entry = entry->next(); + } +} + + +//------------------------------------------------- +// sad_r - I/O read +//------------------------------------------------- + +READ16_MEMBER( wangpcbus_device::sad_r ) +{ + UINT16 data = 0xffff; + + device_wangpcbus_card_interface *entry = m_device_list.first(); + + while (entry) + { + data &= entry->wangpcbus_iorc_r(space, offset + 0x1100/2, mem_mask); + entry = entry->next(); + } + + return data; +} + + +//------------------------------------------------- +// sad_w - I/O write +//------------------------------------------------- + +WRITE16_MEMBER( wangpcbus_device::sad_w ) +{ + device_wangpcbus_card_interface *entry = m_device_list.first(); + + while (entry) + { + entry->wangpcbus_aiowc_w(space, offset + 0x1100/2, mem_mask, data); + entry = entry->next(); + } +} + + +//------------------------------------------------- +// dack_r - DMA read +//------------------------------------------------- + +UINT8 wangpcbus_device::dack_r(address_space &space, int line) +{ + UINT8 retVal = 0xff; + device_wangpcbus_card_interface *entry = m_device_list.first(); + + while (entry) + { + if (entry->wangpcbus_have_dack(line)) + { + retVal = entry->wangpcbus_dack_r(space, line); + break; + } + + entry = entry->next(); + } + + return retVal; +} + + +//------------------------------------------------- +// dack_w - DMA write +//------------------------------------------------- + +void wangpcbus_device::dack_w(address_space &space, int line, UINT8 data) +{ + device_wangpcbus_card_interface *entry = m_device_list.first(); + + while (entry) + { + if (entry->wangpcbus_have_dack(line)) + { + entry->wangpcbus_dack_w(space, line, data); + } + + entry = entry->next(); + } +} + + +//------------------------------------------------- +// tc_w - terminal count +//------------------------------------------------- + +WRITE_LINE_MEMBER( wangpcbus_device::tc_w ) +{ + device_wangpcbus_card_interface *entry = m_device_list.first(); + + while (entry) + { + entry->wangpcbus_tc_w(state); + entry = entry->next(); + } +} + + + +//************************************************************************** +// DEVICE WANG PC BUS CARD INTERFACE +//************************************************************************** + +//------------------------------------------------- +// device_wangpcbus_card_interface - constructor +//------------------------------------------------- + +device_wangpcbus_card_interface::device_wangpcbus_card_interface(const machine_config &mconfig, device_t &device) : + device_slot_card_interface(mconfig, device) +{ + m_slot = dynamic_cast(device.owner()); +} + + +//------------------------------------------------- +// SLOT_INTERFACE( wangpc_cards ) +//------------------------------------------------- + +// slot devices +#include "emb.h" +#include "lic.h" +#include "lvc.h" +#include "mcc.h" +#include "mvc.h" +#include "rtc.h" +#include "tig.h" +#include "wdc.h" + +SLOT_INTERFACE_START( wangpc_cards ) + SLOT_INTERFACE("emb", WANGPC_EMB) // extended memory board + SLOT_INTERFACE("lic", WANGPC_LIC) // local interconnect option card + SLOT_INTERFACE("lvc", WANGPC_LVC) // low-resolution video controller + SLOT_INTERFACE("mcc", WANGPC_MCC) // multiport communications controller + SLOT_INTERFACE("mvc", WANGPC_MVC) // medium-resolution video controller + SLOT_INTERFACE("rtc", WANGPC_RTC) // remote telecommunications controller + SLOT_INTERFACE("tig", WANGPC_TIG) // text/image/graphics controller + SLOT_INTERFACE("wdc", WANGPC_WDC) // Winchester disk controller +SLOT_INTERFACE_END diff --git a/src/devices/bus/wangpc/wangpc.h b/src/devices/bus/wangpc/wangpc.h new file mode 100644 index 00000000000..2870a4e4ec5 --- /dev/null +++ b/src/devices/bus/wangpc/wangpc.h @@ -0,0 +1,228 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Wang Professional Computer bus emulation + +********************************************************************** + + +**********************************************************************/ + +#pragma once + +#ifndef __WANGPC_BUS__ +#define __WANGPC_BUS__ + +#include "emu.h" + + + +//************************************************************************** +// CONSTANTS +//************************************************************************** + +#define WANGPC_BUS_TAG "wangpcbus" + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_WANGPC_BUS_ADD() \ + MCFG_DEVICE_ADD(WANGPC_BUS_TAG, WANGPC_BUS, 0) + +#define MCFG_WANGPC_BUS_SLOT_ADD(_tag, _sid, _slot_intf, _def_slot) \ + MCFG_DEVICE_ADD(_tag, WANGPC_BUS_SLOT, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) \ + wangpcbus_slot_device::static_set_wangpcbus_slot(*device, _sid); + + +#define MCFG_WANGPC_BUS_IRQ2_CALLBACK(_write) \ + devcb = &wangpcbus_device::set_irq2_wr_callback(*device, DEVCB_##_write); + +#define MCFG_WANGPC_BUS_IRQ3_CALLBACK(_write) \ + devcb = &wangpcbus_device::set_irq3_wr_callback(*device, DEVCB_##_write); + +#define MCFG_WANGPC_BUS_IRQ4_CALLBACK(_write) \ + devcb = &wangpcbus_device::set_irq4_wr_callback(*device, DEVCB_##_write); + +#define MCFG_WANGPC_BUS_IRQ5_CALLBACK(_write) \ + devcb = &wangpcbus_device::set_irq5_wr_callback(*device, DEVCB_##_write); + +#define MCFG_WANGPC_BUS_IRQ6_CALLBACK(_write) \ + devcb = &wangpcbus_device::set_irq6_wr_callback(*device, DEVCB_##_write); + +#define MCFG_WANGPC_BUS_IRQ7_CALLBACK(_write) \ + devcb = &wangpcbus_device::set_irq7_wr_callback(*device, DEVCB_##_write); + +#define MCFG_WANGPC_BUS_DRQ1_CALLBACK(_write) \ + devcb = &wangpcbus_device::set_drq1_wr_callback(*device, DEVCB_##_write); + +#define MCFG_WANGPC_BUS_DRQ2_CALLBACK(_write) \ + devcb = &wangpcbus_device::set_drq2_wr_callback(*device, DEVCB_##_write); + +#define MCFG_WANGPC_BUS_DRQ3_CALLBACK(_write) \ + devcb = &wangpcbus_device::set_drq3_wr_callback(*device, DEVCB_##_write); + +#define MCFG_WANGPC_BUS_IOERROR_CALLBACK(_write) \ + devcb = &wangpcbus_device::set_ioerror_wr_callback(*device, DEVCB_##_write); + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> wangpcbus_slot_device + +class wangpcbus_device; + +class wangpcbus_slot_device : public device_t, + public device_slot_interface +{ +public: + // construction/destruction + wangpcbus_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + + // inline configuration + static void static_set_wangpcbus_slot(device_t &device, int sid); + +private: + // configuration + wangpcbus_device *m_bus; + int m_sid; +}; + + +// device type definition +extern const device_type WANGPC_BUS_SLOT; + + +class device_wangpcbus_card_interface; + + +// ======================> wangpcbus_device + +class wangpcbus_device : public device_t +{ +public: + // construction/destruction + wangpcbus_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + ~wangpcbus_device() { m_device_list.detach_all(); } + + template static devcb_base &set_irq2_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_irq2.set_callback(object); } + template static devcb_base &set_irq3_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_irq3.set_callback(object); } + template static devcb_base &set_irq4_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_irq4.set_callback(object); } + template static devcb_base &set_irq5_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_irq5.set_callback(object); } + template static devcb_base &set_irq6_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_irq6.set_callback(object); } + template static devcb_base &set_irq7_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_irq7.set_callback(object); } + template static devcb_base &set_drq1_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_drq1.set_callback(object); } + template static devcb_base &set_drq2_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_drq2.set_callback(object); } + template static devcb_base &set_drq3_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_drq3.set_callback(object); } + template static devcb_base &set_ioerror_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_ioerror.set_callback(object); } + + void add_card(device_wangpcbus_card_interface *card, int sid); + + // computer interface + DECLARE_READ16_MEMBER( mrdc_r ); + DECLARE_WRITE16_MEMBER( amwc_w ); + + DECLARE_READ16_MEMBER( sad_r ); + DECLARE_WRITE16_MEMBER( sad_w ); + + UINT8 dack_r(address_space &space, int line); + void dack_w(address_space &space, int line, UINT8 data); + + DECLARE_READ8_MEMBER( dack0_r ) { return dack_r(space, 0); } + DECLARE_WRITE8_MEMBER( dack0_w ) { dack_w(space, 0, data); } + DECLARE_READ8_MEMBER( dack1_r ) { return dack_r(space, 1); } + DECLARE_WRITE8_MEMBER( dack1_w ) { dack_w(space, 1, data); } + DECLARE_READ8_MEMBER( dack2_r ) { return dack_r(space, 2); } + DECLARE_WRITE8_MEMBER( dack2_w ) { dack_w(space, 2, data); } + DECLARE_READ8_MEMBER( dack3_r ) { return dack_r(space, 3); } + DECLARE_WRITE8_MEMBER( dack3_w ) { dack_w(space, 3, data); } + + DECLARE_WRITE_LINE_MEMBER( tc_w ); + + // peripheral interface + DECLARE_WRITE_LINE_MEMBER( irq2_w ) { m_write_irq2(state); } + DECLARE_WRITE_LINE_MEMBER( irq3_w ) { m_write_irq3(state); } + DECLARE_WRITE_LINE_MEMBER( irq4_w ) { m_write_irq4(state); } + DECLARE_WRITE_LINE_MEMBER( irq5_w ) { m_write_irq5(state); } + DECLARE_WRITE_LINE_MEMBER( irq6_w ) { m_write_irq6(state); } + DECLARE_WRITE_LINE_MEMBER( irq7_w ) { m_write_irq7(state); } + DECLARE_WRITE_LINE_MEMBER( drq1_w ) { m_write_drq1(state); } + DECLARE_WRITE_LINE_MEMBER( drq2_w ) { m_write_drq2(state); } + DECLARE_WRITE_LINE_MEMBER( drq3_w ) { m_write_drq3(state); } + DECLARE_WRITE_LINE_MEMBER( ioerror_w ) { m_write_ioerror(state); } + +protected: + // device-level overrides + virtual void device_start(); + +private: + devcb_write_line m_write_irq2; + devcb_write_line m_write_irq3; + devcb_write_line m_write_irq4; + devcb_write_line m_write_irq5; + devcb_write_line m_write_irq6; + devcb_write_line m_write_irq7; + devcb_write_line m_write_drq1; + devcb_write_line m_write_drq2; + devcb_write_line m_write_drq3; + devcb_write_line m_write_ioerror; + + simple_list m_device_list; +}; + + +// device type definition +extern const device_type WANGPC_BUS; + + +// ======================> device_wangpcbus_card_interface + +// class representing interface-specific live wangpcbus card +class device_wangpcbus_card_interface : public device_slot_card_interface +{ + friend class wangpcbus_device; + +public: + // construction/destruction + device_wangpcbus_card_interface(const machine_config &mconfig, device_t &device); + virtual ~device_wangpcbus_card_interface() { } + + device_wangpcbus_card_interface *next() const { return m_next; } + + // memory access + virtual UINT16 wangpcbus_mrdc_r(address_space &space, offs_t offset, UINT16 mem_mask) { return 0; }; + virtual void wangpcbus_amwc_w(address_space &space, offs_t offset, UINT16 mem_mask, UINT16 data) { }; + + // I/O access + virtual UINT16 wangpcbus_iorc_r(address_space &space, offs_t offset, UINT16 mem_mask) { return 0; }; + virtual void wangpcbus_aiowc_w(address_space &space, offs_t offset, UINT16 mem_mask, UINT16 data) { }; + bool sad(offs_t offset) { return ((offset & 0xf80) == (0x800 | (m_sid << 7))) ? true : false; } + + // DMA + virtual UINT8 wangpcbus_dack_r(address_space &space, int line) { return 0; } + virtual void wangpcbus_dack_w(address_space &space, int line, UINT8 data) { } + virtual void wangpcbus_tc_w(int state) { } + virtual bool wangpcbus_have_dack(int line) { return false; } + + wangpcbus_device *m_bus; + wangpcbus_slot_device *m_slot; + + int m_sid; + device_wangpcbus_card_interface *m_next; +}; + + +SLOT_INTERFACE_EXTERN( wangpc_cards ); + + + +#endif diff --git a/src/devices/bus/wangpc/wdc.c b/src/devices/bus/wangpc/wdc.c new file mode 100644 index 00000000000..4e4e8fb92bc --- /dev/null +++ b/src/devices/bus/wangpc/wdc.c @@ -0,0 +1,342 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Wang PC-PM001 Winchester Disk Controller emulation + +**********************************************************************/ + +#include "wdc.h" +#include "bus/scsi/scsihd.h" + + + +//************************************************************************** +// MACROS/CONSTANTS +//************************************************************************** + +#define OPTION_ID 0x01 + +#define Z80_TAG "l53" +#define MK3882_TAG "l07" + +#define OPTION_DREQ1 BIT(m_option, 1) +#define OPTION_DREQ2 BIT(m_option, 2) +#define OPTION_DREQ3 BIT(m_option, 3) + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type WANGPC_WDC = &device_creator; + + +//------------------------------------------------- +// ROM( wangpc_wdc ) +//------------------------------------------------- + +ROM_START( wangpc_wdc ) + ROM_REGION( 0x1000, Z80_TAG, 0 ) + ROM_LOAD( "378-9040 r9.l19", 0x0000, 0x1000, CRC(282770d2) SHA1(a0e3bad5041e0dfd6087907015b07a093b576bc0) ) + + ROM_REGION( 0x1000, "address", 0 ) + ROM_LOAD( "378-9041.l54", 0x0000, 0x1000, CRC(94e9a17d) SHA1(060c576d70069ece2d0dbce86ffc448df2b169e7) ) + + ROM_REGION( 0x100, "prom", 0 ) + ROM_LOAD( "376-8002.l66", 0x000, 0x100, NO_DUMP ) // DL2212-105 +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *wangpc_wdc_device::device_rom_region() const +{ + return ROM_NAME( wangpc_wdc ); +} + + +//------------------------------------------------- +// ADDRESS_MAP( wangpc_wdc_mem ) +//------------------------------------------------- + +static ADDRESS_MAP_START( wangpc_wdc_mem, AS_PROGRAM, 8, wangpc_wdc_device ) + AM_RANGE(0x0000, 0x0fff) AM_ROM AM_REGION(Z80_TAG, 0) + AM_RANGE(0x1000, 0x17ff) AM_RAM + AM_RANGE(0x2000, 0x27ff) AM_RAM +ADDRESS_MAP_END + + +//------------------------------------------------- +// ADDRESS_MAP( wangpc_wdc_io ) +//------------------------------------------------- + +static ADDRESS_MAP_START( wangpc_wdc_io, AS_IO, 8, wangpc_wdc_device ) + ADDRESS_MAP_GLOBAL_MASK(0xff) + AM_RANGE(0x01, 0x01) AM_READ(port_r) + AM_RANGE(0x03, 0x03) AM_WRITE(status_w) + AM_RANGE(0x10, 0x10) AM_READWRITE(ctc_ch0_r, ctc_ch0_w) + AM_RANGE(0x14, 0x14) AM_READWRITE(ctc_ch1_r, ctc_ch1_w) + AM_RANGE(0x18, 0x18) AM_READWRITE(ctc_ch2_r, ctc_ch2_w) + AM_RANGE(0x1c, 0x1c) AM_READWRITE(ctc_ch3_r, ctc_ch3_w) +ADDRESS_MAP_END + + +//------------------------------------------------- +// MACHINE_CONFIG_FRAGMENT( wangpc_wdc ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( wangpc_wdc ) + MCFG_CPU_ADD(Z80_TAG, Z80, 2000000) // XTAL_10MHz / ? + //MCFG_CPU_CONFIG(wangpc_wdc_daisy_chain) + MCFG_CPU_PROGRAM_MAP(wangpc_wdc_mem) + MCFG_CPU_IO_MAP(wangpc_wdc_io) + + MCFG_DEVICE_ADD(MK3882_TAG, Z80CTC, 2000000) + MCFG_Z80CTC_INTR_CB(INPUTLINE(Z80_TAG, INPUT_LINE_IRQ0)) + + MCFG_DEVICE_ADD("harddisk0", SCSIHD, 0) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor wangpc_wdc_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( wangpc_wdc ); +} + + + +//************************************************************************** +// INLINE HELPERS +//************************************************************************** + +//------------------------------------------------- +// set_irq - +//------------------------------------------------- + +inline void wangpc_wdc_device::set_irq(int state) +{ + m_irq = state; + + if (OPTION_DREQ1) m_bus->irq5_w(m_irq); + if (OPTION_DREQ2) m_bus->irq6_w(m_irq); + if (OPTION_DREQ3) m_bus->irq7_w(m_irq); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// wangpc_wdc_device - constructor +//------------------------------------------------- + +wangpc_wdc_device::wangpc_wdc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, WANGPC_WDC, "Wang PC-PM001", tag, owner, clock, "wangpc_wdc", __FILE__), + device_wangpcbus_card_interface(mconfig, *this), + m_maincpu(*this, Z80_TAG), + m_ctc(*this, MK3882_TAG) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void wangpc_wdc_device::device_start() +{ + // state saving + save_item(NAME(m_status)); + save_item(NAME(m_option)); + save_item(NAME(m_irq)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void wangpc_wdc_device::device_reset() +{ + m_status = 0; + m_option = 0; + + set_irq(CLEAR_LINE); +} + + +//------------------------------------------------- +// wangpcbus_mrdc_r - memory read +//------------------------------------------------- + +UINT16 wangpc_wdc_device::wangpcbus_mrdc_r(address_space &space, offs_t offset, UINT16 mem_mask) +{ + UINT16 data = 0xffff; + + return data; +} + + +//------------------------------------------------- +// wangpcbus_amwc_w - memory write +//------------------------------------------------- + +void wangpc_wdc_device::wangpcbus_amwc_w(address_space &space, offs_t offset, UINT16 mem_mask, UINT16 data) +{ +} + + +//------------------------------------------------- +// wangpcbus_iorc_r - I/O read +//------------------------------------------------- + +UINT16 wangpc_wdc_device::wangpcbus_iorc_r(address_space &space, offs_t offset, UINT16 mem_mask) +{ + UINT16 data = 0xffff; + + if (sad(offset)) + { + switch (offset & 0x7f) + { + case 0x00/2: + data = m_status; + break; + + case 0x02/2: + // TODO operation status register + break; + + case 0x04/2: + set_irq(CLEAR_LINE); + break; + + case 0xfe/2: + data = 0xff00 | (m_irq << 7) | OPTION_ID; + break; + } + } + + return data; +} + + +//------------------------------------------------- +// wangpcbus_aiowc_w - I/O write +//------------------------------------------------- + +void wangpc_wdc_device::wangpcbus_aiowc_w(address_space &space, offs_t offset, UINT16 mem_mask, UINT16 data) +{ + if (sad(offset) && ACCESSING_BITS_0_7) + { + switch (offset & 0x7f) + { + case 0x02/2: + // TODO command register + break; + + case 0xfc/2: + device_reset(); + break; + + case 0xfe/2: + { + bool irq = (m_irq == ASSERT_LINE); + bool changed = ((m_option & 0x0e) != (data & 0x0e)); + + if (irq && changed) set_irq(CLEAR_LINE); + + m_option = data & 0xff; + + if (irq && changed) set_irq(ASSERT_LINE); + } + break; + } + } +} + + +//------------------------------------------------- +// wangpcbus_dack_r - DMA acknowledge read +//------------------------------------------------- + +UINT8 wangpc_wdc_device::wangpcbus_dack_r(address_space &space, int line) +{ + return 0; +} + + +//------------------------------------------------- +// wangpcbus_dack_r - DMA acknowledge write +//------------------------------------------------- + +void wangpc_wdc_device::wangpcbus_dack_w(address_space &space, int line, UINT8 data) +{ +} + + +//------------------------------------------------- +// wangpcbus_have_dack - +//------------------------------------------------- + +bool wangpc_wdc_device::wangpcbus_have_dack(int line) +{ + return (OPTION_DREQ1 && (line == 1)) || (OPTION_DREQ2 && (line == 2)) || (OPTION_DREQ3 && (line == 3)); +} + + +//------------------------------------------------- +// port_r - +//------------------------------------------------- + +READ8_MEMBER( wangpc_wdc_device::port_r ) +{ + /* + + bit description + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + + */ + + return 0x72; // TODO +} + + +//------------------------------------------------- +// status_w - status register write +//------------------------------------------------- + +WRITE8_MEMBER( wangpc_wdc_device::status_w ) +{ + logerror("WDC status %02x\n", data); + + m_status = data; +} + + +READ8_MEMBER( wangpc_wdc_device::ctc_ch0_r ) { return m_ctc->read(space, 0); } +WRITE8_MEMBER( wangpc_wdc_device::ctc_ch0_w ) { m_ctc->write(space, 0, data); } +READ8_MEMBER( wangpc_wdc_device::ctc_ch1_r ) { return m_ctc->read(space, 1); } +WRITE8_MEMBER( wangpc_wdc_device::ctc_ch1_w ) { m_ctc->write(space, 1, data); } +READ8_MEMBER( wangpc_wdc_device::ctc_ch2_r ) { return m_ctc->read(space, 2); } +WRITE8_MEMBER( wangpc_wdc_device::ctc_ch2_w ) { m_ctc->write(space, 2, data); } +READ8_MEMBER( wangpc_wdc_device::ctc_ch3_r ) { return m_ctc->read(space, 3); } +WRITE8_MEMBER( wangpc_wdc_device::ctc_ch3_w ) { m_ctc->write(space, 3, data); } diff --git a/src/devices/bus/wangpc/wdc.h b/src/devices/bus/wangpc/wdc.h new file mode 100644 index 00000000000..156dc4c10a9 --- /dev/null +++ b/src/devices/bus/wangpc/wdc.h @@ -0,0 +1,81 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Wang PC-PM001 Winchester Disk Controller emulation + +**********************************************************************/ + +#pragma once + +#ifndef __WANGPC_WDC__ +#define __WANGPC_WDC__ + +#include "emu.h" +#include "wangpc.h" +#include "cpu/z80/z80.h" +#include "imagedev/harddriv.h" +#include "machine/z80ctc.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> wangpc_wdc_device + +class wangpc_wdc_device : public device_t, + public device_wangpcbus_card_interface +{ +public: + // construction/destruction + wangpc_wdc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + + // not really public + DECLARE_READ8_MEMBER( port_r ); + DECLARE_WRITE8_MEMBER( status_w ); + DECLARE_READ8_MEMBER( ctc_ch0_r ); + DECLARE_WRITE8_MEMBER( ctc_ch0_w ); + DECLARE_READ8_MEMBER( ctc_ch1_r ); + DECLARE_WRITE8_MEMBER( ctc_ch1_w ); + DECLARE_READ8_MEMBER( ctc_ch2_r ); + DECLARE_WRITE8_MEMBER( ctc_ch2_w ); + DECLARE_READ8_MEMBER( ctc_ch3_r ); + DECLARE_WRITE8_MEMBER( ctc_ch3_w ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_wangpcbus_card_interface overrides + virtual UINT16 wangpcbus_mrdc_r(address_space &space, offs_t offset, UINT16 mem_mask); + virtual void wangpcbus_amwc_w(address_space &space, offs_t offset, UINT16 mem_mask, UINT16 data); + virtual UINT16 wangpcbus_iorc_r(address_space &space, offs_t offset, UINT16 mem_mask); + virtual void wangpcbus_aiowc_w(address_space &space, offs_t offset, UINT16 mem_mask, UINT16 data); + virtual UINT8 wangpcbus_dack_r(address_space &space, int line); + virtual void wangpcbus_dack_w(address_space &space, int line, UINT8 data); + virtual bool wangpcbus_have_dack(int line); + +private: + inline void set_irq(int state); + + required_device m_maincpu; + required_device m_ctc; + + UINT8 m_status; + UINT8 m_option; + int m_irq; +}; + + +// device type definition +extern const device_type WANGPC_WDC; + + +#endif diff --git a/src/devices/bus/wswan/rom.c b/src/devices/bus/wswan/rom.c new file mode 100644 index 00000000000..de57f954b8c --- /dev/null +++ b/src/devices/bus/wswan/rom.c @@ -0,0 +1,524 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +/*********************************************************************************************************** + + + Bandai Wonderswan / Wonderswan Color cart emulation + + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "rom.h" + +enum +{ + EEPROM_1K, EEPROM_8K, EEPROM_16K +}; + +//------------------------------------------------- +// ws_rom_device - constructor +//------------------------------------------------- + +const device_type WS_ROM_STD = &device_creator; +const device_type WS_ROM_SRAM = &device_creator; +const device_type WS_ROM_EEPROM = &device_creator; + + +ws_rom_device::ws_rom_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_ws_cart_interface( mconfig, *this ) +{ +} + +ws_rom_device::ws_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, WS_ROM_STD, "Wonderswan Standard Carts", tag, owner, clock, "ws_rom", __FILE__), + device_ws_cart_interface( mconfig, *this ) +{ +} + +ws_rom_sram_device::ws_rom_sram_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : ws_rom_device(mconfig, WS_ROM_SRAM, "Wonderswan Carts w/SRAM", tag, owner, clock, "ws_sram", __FILE__) +{ +} + + +ws_rom_eeprom_device::ws_rom_eeprom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : ws_rom_device(mconfig, WS_ROM_EEPROM, "Wonderswan Carts w/EEPROM", tag, owner, clock, "ws_eeprom", __FILE__) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void ws_rom_device::device_start() +{ + save_item(NAME(m_base20)); + save_item(NAME(m_base30)); + save_item(NAME(m_base40)); + save_item(NAME(m_io_regs)); + + // Set up RTC timer + if (m_has_rtc) + { + rtc_timer = timer_alloc(TIMER_RTC); + rtc_timer->adjust(attotime::zero, 0, attotime::from_seconds(1)); + } + + save_item(NAME(m_rtc_setting)); + save_item(NAME(m_rtc_year)); + save_item(NAME(m_rtc_month)); + save_item(NAME(m_rtc_day)); + save_item(NAME(m_rtc_day_of_week)); + save_item(NAME(m_rtc_hour)); + save_item(NAME(m_rtc_minute)); + save_item(NAME(m_rtc_second)); + save_item(NAME(m_rtc_index)); +} + +void ws_rom_device::device_reset() +{ + m_base20 = ((0xff & m_bank_mask) << 16) & (m_rom_size - 1); + m_base30 = ((0xff & m_bank_mask) << 16) & (m_rom_size - 1); + m_base40 = (((0xf0 & m_bank_mask) | 4) << 16) & (m_rom_size - 1); + + memset(m_io_regs, 0, sizeof(m_io_regs)); + + // Initialize RTC + m_rtc_index = 0; + m_rtc_year = 0; + m_rtc_month = 0; + m_rtc_day = 0; + m_rtc_day_of_week = 0; + m_rtc_hour = 0; + m_rtc_minute = 0; + m_rtc_second = 0; + m_rtc_setting = 0xff; +} + +void ws_rom_sram_device::device_start() +{ + save_item(NAME(m_nvram_base)); + ws_rom_device::device_start(); +} + +void ws_rom_sram_device::device_reset() +{ + m_nvram_base = 0; + ws_rom_device::device_reset(); +} + +void ws_rom_eeprom_device::device_start() +{ + ws_rom_device::device_start(); + + save_item(NAME(m_eeprom_address)); + save_item(NAME(m_eeprom_command)); + save_item(NAME(m_eeprom_start)); + save_item(NAME(m_eeprom_write_enabled)); +} + +void ws_rom_eeprom_device::device_reset() +{ + m_eeprom_address = 0; + m_eeprom_command = 0; + m_eeprom_start = 0; + m_eeprom_write_enabled = 0; + switch (m_nvram.size()) + { + case 0x80: + m_eeprom_mode = EEPROM_1K; + break; + case 0x400: + m_eeprom_mode = EEPROM_8K; + break; + case 0x800: + m_eeprom_mode = EEPROM_16K; + break; + } + ws_rom_device::device_reset(); +} + + + +//------------------------------------------------- +// device_timer - handler timer events +//------------------------------------------------- + +void ws_rom_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + if (id == TIMER_RTC) + { + // a second passed + m_rtc_second++; + if ((m_rtc_second & 0x0f) > 9) + m_rtc_second = (m_rtc_second & 0xf0) + 0x10; + + // check for minute passed + if (m_rtc_second >= 0x60) + { + m_rtc_second = 0; + m_rtc_minute++; + if ((m_rtc_minute & 0x0f) > 9) + m_rtc_minute = (m_rtc_minute & 0xf0) + 0x10; + } + + // check for hour passed + if (m_rtc_minute >= 0x60) + { + m_rtc_minute = 0; + m_rtc_hour++; + if ((m_rtc_hour & 0x0f) > 9) + m_rtc_hour = (m_rtc_hour & 0xf0) + 0x10; + if (m_rtc_hour == 0x12) + m_rtc_hour |= 0x80; + } + + // check for day passed + if (m_rtc_hour >= 0x24) + { + m_rtc_hour = 0; + m_rtc_day++; + } + } +} + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +READ8_MEMBER(ws_rom_device::read_rom20) +{ + return m_rom[offset + m_base20]; +} + + +READ8_MEMBER(ws_rom_device::read_rom30) +{ + return m_rom[offset + m_base30]; +} + + +READ8_MEMBER(ws_rom_device::read_rom40) +{ + // we still need to mask in some cases, e.g. when game is 512K + return m_rom[(offset + m_base40) & (m_rom_size - 1)]; +} + + +READ8_MEMBER(ws_rom_device::read_io) +{ + UINT8 value = m_io_regs[offset]; + + switch (offset) + { + case 0x0b: // RTC data + if (!m_has_rtc) + break; + + if (m_io_regs[0x0a] == 0x95 && (m_rtc_index < 7)) + { + switch (m_rtc_index) + { + case 0: value = m_rtc_year; break; + case 1: value = m_rtc_month; break; + case 2: value = m_rtc_day; break; + case 3: value = m_rtc_day_of_week; break; + case 4: value = m_rtc_hour; break; + case 5: value = m_rtc_minute; break; + case 6: value = m_rtc_second; break; + } + m_rtc_index++; + } + break; + } + + return value; +} + +WRITE8_MEMBER(ws_rom_device::write_io) +{ + switch (offset) + { + case 0x00: + // Bit 0-3 - ROM bank base register for segments 3-15 + // Bit 4-7 - Unknown + data = ((data & 0x0f) << 4) | 4; + m_base40 = ((data & m_bank_mask) << 16) & (m_rom_size - 1); + break; + case 0x02: // ROM bank for segment 2 (0x20000 - 0x2ffff) + m_base20 = ((data & m_bank_mask) << 16) & (m_rom_size - 1); + break; + case 0x03: // ROM bank for segment 3 (0x30000 - 0x3ffff) + m_base30 = ((data & m_bank_mask) << 16) & (m_rom_size - 1); + break; + case 0x0a: // RTC Command + // Bit 0-4 - RTC command + // 10000 - Reset + // 10010 - Write timer settings (alarm) + // 10011 - Read timer settings (alarm) + // 10100 - Set time/date + // 10101 - Get time/date + // Bit 5-6 - Unknown + // Bit 7 - Command done (read only) + if (!m_has_rtc) + break; + + switch (data) + { + case 0x10: // Reset + m_rtc_index = 8; + m_rtc_year = 0; + m_rtc_month = 1; + m_rtc_day = 1; + m_rtc_day_of_week = 0; + m_rtc_hour = 0; + m_rtc_minute = 0; + m_rtc_second = 0; + m_rtc_setting = 0xff; + data |= 0x80; + break; + case 0x12: // Write Timer Settings (Alarm) + m_rtc_index = 8; + m_rtc_setting = m_io_regs[0x0b]; + data |= 0x80; + break; + case 0x13: // Read Timer Settings (Alarm) + m_rtc_index = 8; + m_io_regs[0x0b] = m_rtc_setting; + data |= 0x80; + break; + case 0x14: // Set Time/Date + m_rtc_year = m_io_regs[0x0b]; + m_rtc_index = 1; + data |= 0x80; + break; + case 0x15: // Get Time/Date + m_rtc_index = 0; + data |= 0x80; + m_io_regs[0x0b] = m_rtc_year; + break; + default: + logerror( "Unknown RTC command (%X) requested\n", data); + } + break; + case 0x0b: // RTC Data + if (!m_has_rtc) + break; + + if (m_io_regs[0x0a] == 0x94 && m_rtc_index < 7) + { + switch (m_rtc_index) + { + case 0: m_rtc_year = data; break; + case 1: m_rtc_month = data; break; + case 2: m_rtc_day = data; break; + case 3: m_rtc_day_of_week = data; break; + case 4: m_rtc_hour = data; break; + case 5: m_rtc_minute = data; break; + case 6: m_rtc_second = data; break; + } + m_rtc_index++; + } + break; + } + + m_io_regs[offset] = data; +} + +READ8_MEMBER(ws_rom_sram_device::read_ram) +{ + return m_nvram[m_nvram_base + offset]; +} + +WRITE8_MEMBER(ws_rom_sram_device::write_ram) +{ + m_nvram[m_nvram_base + offset] = data; +} + +WRITE8_MEMBER(ws_rom_sram_device::write_io) +{ + switch (offset) + { + case 0x01: // SRAM bank to select + m_nvram_base = (data * 0x10000) & (m_nvram.size() - 1); + default: + ws_rom_device::write_io(space, offset, data); + break; + } +} + + +READ8_MEMBER(ws_rom_eeprom_device::read_io) +{ + UINT8 value = m_io_regs[offset]; + + switch (offset) + { + case 0x04: + case 0x05: + case 0x06: + case 0x07: + case 0x08: + // EEPROM reads, taken from regs + break; + default: + value = ws_rom_device::read_io(space, offset); + break; + } + + return value; +} + +WRITE8_MEMBER(ws_rom_eeprom_device::write_io) +{ + switch (offset) + { + case 0x06: /* EEPROM address lower bits port/EEPROM address and command port + 1KBit EEPROM: + Bit 0-5 - EEPROM address bit 1-6 + Bit 6-7 - Command + 00 - Extended command address bit 4-5: + 00 - Write disable + 01 - Write all + 10 - Erase all + 11 - Write enable + 01 - Write + 10 - Read + 11 - Erase + 16KBit EEPROM: + Bit 0-7 - EEPROM address bit 1-8 + */ + switch (m_eeprom_mode) + { + case EEPROM_1K: + m_eeprom_address = data & 0x3f; + m_eeprom_command = data >> 4; + if ((m_eeprom_command & 0x0c) != 0x00) + m_eeprom_command = m_eeprom_command & 0x0c; + break; + + case EEPROM_8K: + case EEPROM_16K: + m_eeprom_address = (m_eeprom_address & 0xff00) | data; + break; + + default: + logerror( "Write EEPROM address/register register C6 for unsupported EEPROM type\n" ); + break; + } + break; + + case 0x07: /* EEPROM higher bits/command bits port + 1KBit EEPROM: + Bit 0 - Start + Bit 1-7 - Unknown + 16KBit EEPROM: + Bit 0-1 - EEPROM address bit 9-10 + Bit 2-3 - Command + 00 - Extended command address bit 0-1: + 00 - Write disable + 01 - Write all + 10 - Erase all + 11 - Write enable + 01 - Write + 10 - Read + 11 - Erase + Bit 4 - Start + Bit 5-7 - Unknown + */ + switch (m_eeprom_mode) + { + case EEPROM_1K: + m_eeprom_start = data & 0x01; + break; + + case EEPROM_8K: + m_eeprom_address = ((data & 0x01) << 8) | (m_eeprom_address & 0xff); + m_eeprom_command = data & 0x0f; + if ((m_eeprom_command & 0x0c) != 0x00) + m_eeprom_command = m_eeprom_command & 0x0c; + m_eeprom_start = (data >> 4) & 0x01; + break; + + case EEPROM_16K: + m_eeprom_address = ((data & 0x03) << 8) | (m_eeprom_address & 0xff); + m_eeprom_command = data & 0x0f; + if ((m_eeprom_command & 0x0c) != 0x00) + m_eeprom_command = m_eeprom_command & 0x0c; + m_eeprom_start = (data >> 4) & 0x01; + break; + + default: + logerror( "Write EEPROM address/command register C7 for unsupported EEPROM type\n" ); + break; + } + break; + + case 0x08: /* EEPROM command + Bit 0 - Read complete (read only) + Bit 1 - Write complete (read only) + Bit 2-3 - Unknown + Bit 4 - Read + Bit 5 - Write + Bit 6 - Protect + Bit 7 - Initialize + */ + if (data & 0x80) // Initialize + logerror("Unsupported EEPROM command 'Initialize'\n"); + + if (data & 0x40) // Protect + { + switch (m_eeprom_command) + { + case 0x00: + m_eeprom_write_enabled = 0; + data |= 0x02; + break; + case 0x03: + m_eeprom_write_enabled = 1; + data |= 0x02; + break; + default: + logerror("Unsupported 'Protect' command %X\n", m_eeprom_command); + break; + } + } + + if (data & 0x20) // Write + { + if (m_eeprom_write_enabled) + { + switch (m_eeprom_command) + { + case 0x04: + m_nvram[(m_eeprom_address << 1) + 1] = m_io_regs[0x04]; + m_nvram[m_eeprom_address << 1] = m_io_regs[0x05]; + data |= 0x02; + break; + default: + logerror("Unsupported 'Write' command %X\n", m_eeprom_command); + break; + } + } + } + + if (data & 0x10) // Read + { + m_io_regs[0x04] = m_nvram[(m_eeprom_address << 1) + 1]; + m_io_regs[0x05] = m_nvram[m_eeprom_address << 1]; + data |= 0x01; + } + break; + + default: + ws_rom_device::write_io(space, offset, data); + break; + } + + m_io_regs[offset] = data; +} diff --git a/src/devices/bus/wswan/rom.h b/src/devices/bus/wswan/rom.h new file mode 100644 index 00000000000..e3ac0134c84 --- /dev/null +++ b/src/devices/bus/wswan/rom.h @@ -0,0 +1,105 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +#ifndef __WS_ROM_H +#define __WS_ROM_H + +#include "slot.h" + + +// ======================> ws_rom_device + +class ws_rom_device : public device_t, + public device_ws_cart_interface +{ +public: + // construction/destruction + ws_rom_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + ws_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_rom20); + virtual DECLARE_READ8_MEMBER(read_rom30); + virtual DECLARE_READ8_MEMBER(read_rom40); + virtual DECLARE_READ8_MEMBER(read_io); + virtual DECLARE_WRITE8_MEMBER(write_io); + +protected: + UINT8 m_io_regs[0x10]; + UINT32 m_base20, m_base30, m_base40; + + // RTC + UINT8 m_rtc_setting; /* Timer setting byte */ + UINT8 m_rtc_year; /* Year */ + UINT8 m_rtc_month; /* Month */ + UINT8 m_rtc_day; /* Day */ + UINT8 m_rtc_day_of_week; /* Day of the week */ + UINT8 m_rtc_hour; /* Hour, high bit = 0 => AM, high bit = 1 => PM */ + UINT8 m_rtc_minute; /* Minute */ + UINT8 m_rtc_second; /* Second */ + UINT8 m_rtc_index; /* index for reading/writing of current of alarm time */ + + static const device_timer_id TIMER_RTC = 0; + emu_timer *rtc_timer; +}; + + +// ======================> ws_rom_sram_device + +class ws_rom_sram_device : public ws_rom_device +{ +public: + // construction/destruction + ws_rom_sram_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_ram); + virtual DECLARE_WRITE8_MEMBER(write_ram); + virtual DECLARE_WRITE8_MEMBER(write_io); + +private: + UINT32 m_nvram_base; +}; + + +// ======================> ws_rom_eeprom_device + +class ws_rom_eeprom_device : public ws_rom_device +{ +public: + // construction/destruction + ws_rom_eeprom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_io); + virtual DECLARE_WRITE8_MEMBER(write_io); + +private: + UINT8 m_eeprom_mode; /* eeprom mode */ + UINT16 m_eeprom_address; /* Read/write address */ + UINT8 m_eeprom_command; /* Commands: 00, 01, 02, 03, 04, 08, 0C */ + UINT8 m_eeprom_start; /* start bit */ + UINT8 m_eeprom_write_enabled; /* write enabled yes/no */ +}; + + + +// device type definition +extern const device_type WS_ROM_STD; +extern const device_type WS_ROM_SRAM; +extern const device_type WS_ROM_EEPROM; + + +#endif diff --git a/src/devices/bus/wswan/slot.c b/src/devices/bus/wswan/slot.c new file mode 100644 index 00000000000..8da5f6e694d --- /dev/null +++ b/src/devices/bus/wswan/slot.c @@ -0,0 +1,457 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +/*********************************************************************************************************** + + Bandai Wonderswan / Wonderswan Color cart emulation + (through slot devices) + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "slot.h" + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type WS_CART_SLOT = &device_creator; + +//************************************************************************** +// Wonderswan Cartridges Interface +//************************************************************************** + +//------------------------------------------------- +// device_ws_cart_interface - constructor +//------------------------------------------------- + +device_ws_cart_interface::device_ws_cart_interface(const machine_config &mconfig, device_t &device) + : device_slot_card_interface(mconfig, device), + m_rom(NULL), + m_rom_size(0), + m_bank_mask(0), + m_has_rtc(false), + m_is_rotated(false) +{ +} + + +//------------------------------------------------- +// ~device_ws_cart_interface - destructor +//------------------------------------------------- + +device_ws_cart_interface::~device_ws_cart_interface() +{ +} + +//------------------------------------------------- +// rom_alloc - alloc the space for the cart +//------------------------------------------------- + +void device_ws_cart_interface::rom_alloc(UINT32 size, const char *tag) +{ + if (m_rom == NULL) + { + m_rom = device().machine().memory().region_alloc(std::string(tag).append(WSSLOT_ROM_REGION_TAG).c_str(), size, 1, ENDIANNESS_LITTLE)->base(); + m_rom_size = size; + m_bank_mask = ((m_rom_size >> 16) - 1); + } +} + + +//------------------------------------------------- +// nvram_alloc - alloc the space for the ram +//------------------------------------------------- + +void device_ws_cart_interface::nvram_alloc(UINT32 size) +{ + m_nvram.resize(size); +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// ws_cart_slot_device - constructor +//------------------------------------------------- +ws_cart_slot_device::ws_cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, WS_CART_SLOT, "Wonderswan Cartridge Slot", tag, owner, clock, "ws_cart_slot", __FILE__), + device_image_interface(mconfig, *this), + device_slot_interface(mconfig, *this), + m_type(WS_STD) +{ +} + + +//------------------------------------------------- +// ws_cart_slot_device - destructor +//------------------------------------------------- + +ws_cart_slot_device::~ws_cart_slot_device() +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void ws_cart_slot_device::device_start() +{ + m_cart = dynamic_cast(get_card_device()); +} + +//------------------------------------------------- +// device_config_complete - perform any +// operations now that the configuration is +// complete +//------------------------------------------------- + +void ws_cart_slot_device::device_config_complete() +{ + // set brief and instance name + update_names(); +} + + +//------------------------------------------------- +// WSWAN PCB +//------------------------------------------------- + +struct ws_slot +{ + int pcb_id; + const char *slot_option; +}; + +// Here, we take the feature attribute from .xml (i.e. the PCB name) and we assign a unique ID to it +static const ws_slot slot_list[] = +{ + { WS_STD, "ws_rom" }, + { WS_SRAM, "ws_sram" }, + { WS_EEPROM, "ws_eeprom" } +}; + +static int ws_get_pcb_id(const char *slot) +{ + for (int i = 0; i < ARRAY_LENGTH(slot_list); i++) + { + if (!core_stricmp(slot_list[i].slot_option, slot)) + return slot_list[i].pcb_id; + } + + return 0; +} + +static const char *ws_get_slot(int type) +{ + for (int i = 0; i < ARRAY_LENGTH(slot_list); i++) + { + if (slot_list[i].pcb_id == type) + return slot_list[i].slot_option; + } + + return "std"; +} + + +/*------------------------------------------------- + call load + -------------------------------------------------*/ + +bool ws_cart_slot_device::call_load() +{ + if (m_cart) + { + UINT8 *ROM; + UINT32 size = (software_entry() == NULL) ? length() : get_software_region_length("rom"); + UINT32 nvram_size = 0; + + m_cart->rom_alloc(size, tag()); + ROM = m_cart->get_rom_base(); + + if (software_entry() == NULL) + fread(ROM, size); + else + memcpy(ROM, get_software_region("rom"), size); + + if (software_entry() == NULL) + { + int chunks = size / 0x10000; + // get cart type and nvram length + m_type = get_cart_type(ROM, size, nvram_size); + + if (ROM[(chunks - 1) * 0x10000 + 0xfffd]) + m_cart->set_has_rtc(true); + if (ROM[(chunks - 1) * 0x10000 + 0xfffc] & 0x01) + m_cart->set_is_rotated(true); + } + else + { + const char *pcb_name = get_feature("slot"); + if (pcb_name) + m_type = ws_get_pcb_id(pcb_name); + + if (m_type == WS_SRAM) + nvram_size = get_software_region_length("sram"); + if (m_type == WS_EEPROM) + nvram_size = get_software_region_length("eeprom"); + + if (get_feature("rtc")) + { + if (!core_stricmp(get_feature("rtc"), "yes")) + m_cart->set_has_rtc(true); + } + if (get_feature("rotated")) + { + if (!core_stricmp(get_feature("rotated"), "yes")) + m_cart->set_is_rotated(true); + } + } + + //printf("Type: %s\n", ws_get_slot(m_type)); + + if (nvram_size) + { + // allocate NVRAM + m_cart->nvram_alloc(nvram_size); + // and load possible battery save + battery_load(m_cart->get_nvram_base(), m_cart->get_nvram_size(), 0x00); + } + + internal_header_logging(ROM, ((size >> 16) - 1) << 16, size); + } + + return IMAGE_INIT_PASS; +} + +/*------------------------------------------------- + call_unload + -------------------------------------------------*/ + +void ws_cart_slot_device::call_unload() +{ + if (m_cart && m_cart->get_nvram_base() && m_cart->get_nvram_size()) + battery_save(m_cart->get_nvram_base(), m_cart->get_nvram_size()); +} + + +/*------------------------------------------------- + call softlist load + -------------------------------------------------*/ + +bool ws_cart_slot_device::call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry) +{ + load_software_part_region(*this, swlist, swname, start_entry); + return TRUE; +} + + +/*------------------------------------------------- + get cart type from cart file + -------------------------------------------------*/ + +int ws_cart_slot_device::get_cart_type(UINT8 *ROM, UINT32 len, UINT32 &nvram_len) +{ + int chunks = len / 0x10000; + int type = WS_STD; + + switch (ROM[(chunks - 1) * 0x10000 + 0xfffb]) + { + case 0x00: + break; + case 0x01: // SRAM 64Kbit + type = WS_SRAM; + nvram_len = 0x2000; + break; + case 0x02: // SRAM 256Kbit + type = WS_SRAM; + nvram_len = 0x8000; + break; + case 0x05: // SRAM 512Kbit + type = WS_SRAM; + nvram_len = 0x10000; + break; + case 0x03: // SRAM 1Mbit + type = WS_SRAM; + nvram_len = 0x20000; + break; + case 0x04: // SRAM 2Mbit + type = WS_SRAM; + nvram_len = 0x40000; + break; + case 0x10: // EEPROM 1Kbit + type = WS_EEPROM; + nvram_len = 0x80; + break; + case 0x50: // EEPROM 8Kbit + type = WS_EEPROM; + nvram_len = 0x400; + break; + case 0x20: // EEPROM 16Kbit + type = WS_EEPROM; + nvram_len = 0x800; + break; + default: + printf("Unknown RAM size [0x%X]\n", ROM[(chunks - 1) * 0x10000 + 0xfffb]); + logerror("Unknown RAM size [0x%X]\n", ROM[(chunks - 1) * 0x10000 + 0xfffb]); + break; + } + + return type; +} + +/*------------------------------------------------- + get default card software + -------------------------------------------------*/ + +void ws_cart_slot_device::get_default_card_software(std::string &result) +{ + if (open_image_file(mconfig().options())) + { + const char *slot_string = "ws_rom"; + UINT32 size = core_fsize(m_file); + dynamic_buffer rom(size); + int type; + UINT32 nvram; + + core_fread(m_file, &rom[0], size); + + // nvram size is not really used here, but we set it up nevertheless + type = get_cart_type(&rom[0], size, nvram); + slot_string = ws_get_slot(type); + + //printf("type: %s\n", slot_string); + clear(); + + result.assign(slot_string); + return; + } + + software_get_default_slot(result, "ws_rom"); +} + +/*------------------------------------------------- + read_rom20 + -------------------------------------------------*/ + +READ8_MEMBER(ws_cart_slot_device::read_rom20) +{ + if (m_cart) + return m_cart->read_rom20(space, offset); + else + return 0xff; +} + +/*------------------------------------------------- + read_rom30 + -------------------------------------------------*/ + +READ8_MEMBER(ws_cart_slot_device::read_rom30) +{ + if (m_cart) + return m_cart->read_rom30(space, offset); + else + return 0xff; +} + +/*------------------------------------------------- + read_rom40 + -------------------------------------------------*/ + +READ8_MEMBER(ws_cart_slot_device::read_rom40) +{ + if (m_cart) + return m_cart->read_rom40(space, offset); + else + return 0xff; +} + +/*------------------------------------------------- + read_ram + -------------------------------------------------*/ + +READ8_MEMBER(ws_cart_slot_device::read_ram) +{ + if (m_cart) + return m_cart->read_ram(space, offset); + else + return 0xff; +} + +/*------------------------------------------------- + write_ram + -------------------------------------------------*/ + +WRITE8_MEMBER(ws_cart_slot_device::write_ram) +{ + if (m_cart) + m_cart->write_ram(space, offset, data); +} + +/*------------------------------------------------- + read_io + -------------------------------------------------*/ + +READ8_MEMBER(ws_cart_slot_device::read_io) +{ + if (m_cart) + return m_cart->read_io(space, offset); + else + return 0xff; +} + +/*------------------------------------------------- + write_io + -------------------------------------------------*/ + +WRITE8_MEMBER(ws_cart_slot_device::write_io) +{ + if (m_cart) + m_cart->write_io(space, offset, data); +} + + + +/*------------------------------------------------- + Internal header logging + -------------------------------------------------*/ + +static const char *const sram_str[] = { "none", "64Kbit SRAM", "256Kbit SRAM", "512Kbit SRAM", "1Mbit SRAM", "2Mbit SRAM" }; +static const char *const eeprom_str[] = { "none", "1Kbit EEPROM", "16Kbit EEPROM", "Unknown", "Unknown", "8Kbit EEPROM" }; +static const char *const romsize_str[] = { "Unknown", "Unknown", "4Mbit", "8Mbit", "16Mbit", "Unknown", "32Mbit", "Unknown", "64Mbit", "128Mbit" }; + +void ws_cart_slot_device::internal_header_logging(UINT8 *ROM, UINT32 offs, UINT32 len) +{ + int sum = 0, banks = len / 0x10000; + UINT8 romsize, ramtype, ramsize; + romsize = ROM[offs + 0xfffa]; + ramtype = (ROM[offs + 0xfffb] & 0xf0) ? 1 : 0; // 1 = EEPROM, 0 = SRAM + ramsize = ramtype ? ((ROM[offs + 0xfffb] & 0xf0) >> 4) : (ROM[offs + 0xfffb] & 0x0f); + + + logerror( "ROM DETAILS\n" ); + logerror( "===========\n\n" ); + logerror("\tDeveloper ID: %X\n", ROM[offs + 0xfff6]); + logerror("\tMinimum system: %s\n", ROM[offs + 0xfff7] ? "WonderSwan Color" : "WonderSwan"); + logerror("\tCart ID: %X\n", ROM[offs + 0xfff8]); + logerror("\tROM size: %s\n", romsize_str[romsize]); + if (ramtype) + logerror("\tEEPROM size: %s\n", (ramsize < 6) ? eeprom_str[ramsize] : "Unknown"); + else + logerror("\tSRAM size: %s\n", (ramsize < 6) ? sram_str[ramsize] : "Unknown"); + logerror("\tFeatures: %X\n", ROM[offs + 0xfffc]); + logerror("\tRTC: %s\n", ROM[offs + 0xfffd] ? "yes" : "no"); + for (int i = 0; i < banks; i++) + { + for (int count = 0; count < 0x10000; count++) + { + sum += ROM[(i * 0x10000) + count]; + } + } + sum -= ROM[offs + 0xffff]; + sum -= ROM[offs + 0xfffe]; + sum &= 0xffff; + logerror("\tChecksum: %.2X%.2X (calculated: %04X)\n", ROM[offs + 0xffff], ROM[offs + 0xfffe], sum); +} diff --git a/src/devices/bus/wswan/slot.h b/src/devices/bus/wswan/slot.h new file mode 100644 index 00000000000..87ac47a2a97 --- /dev/null +++ b/src/devices/bus/wswan/slot.h @@ -0,0 +1,131 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +#ifndef __WS_SLOT_H +#define __WS_SLOT_H + +/*************************************************************************** + TYPE DEFINITIONS + ***************************************************************************/ + + +/* PCB */ +enum +{ + WS_STD = 0, + WS_SRAM, + WS_EEPROM +}; + + +// ======================> device_ws_cart_interface + +class device_ws_cart_interface : public device_slot_card_interface +{ +public: + // construction/destruction + device_ws_cart_interface(const machine_config &mconfig, device_t &device); + virtual ~device_ws_cart_interface(); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_rom20) { return 0xff; } + virtual DECLARE_READ8_MEMBER(read_rom30) { return 0xff; } + virtual DECLARE_READ8_MEMBER(read_rom40) { return 0xff; } + virtual DECLARE_READ8_MEMBER(read_ram) { return 0xff; } + virtual DECLARE_WRITE8_MEMBER(write_ram) {} + virtual DECLARE_READ8_MEMBER(read_io) { return 0xff; } + virtual DECLARE_WRITE8_MEMBER(write_io) {} + + void rom_alloc(UINT32 size, const char *tag); + void nvram_alloc(UINT32 size); + UINT8* get_rom_base() { return m_rom; } + UINT8* get_nvram_base() { return &m_nvram[0]; } + UINT32 get_rom_size() { return m_rom_size; } + UINT32 get_nvram_size() { return m_nvram.size(); } + + void save_nvram() { device().save_item(NAME(m_nvram)); } + void set_has_rtc(bool val) { m_has_rtc = val; } + void set_is_rotated(bool val) { m_is_rotated = val; } + int get_is_rotated() { return m_is_rotated ? 1 : 0; } + +protected: + // internal state + UINT8 *m_rom; + UINT32 m_rom_size; + dynamic_buffer m_nvram; + int m_bank_mask; + + bool m_has_rtc, m_is_rotated; +}; + + +// ======================> ws_cart_slot_device + +class ws_cart_slot_device : public device_t, + public device_image_interface, + public device_slot_interface +{ +public: + // construction/destruction + ws_cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual ~ws_cart_slot_device(); + + // device-level overrides + virtual void device_start(); + virtual void device_config_complete(); + + // image-level overrides + virtual bool call_load(); + virtual void call_unload(); + virtual bool call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry); + + int get_type() { return m_type; } + int get_is_rotated() { return m_cart->get_is_rotated(); } + int get_cart_type(UINT8 *ROM, UINT32 len, UINT32 &nvram_len); + void internal_header_logging(UINT8 *ROM, UINT32 offs, UINT32 len); + + void save_nvram() { if (m_cart && m_cart->get_nvram_size()) m_cart->save_nvram(); } + + virtual iodevice_t image_type() const { return IO_CARTSLOT; } + virtual bool is_readable() const { return 1; } + virtual bool is_writeable() const { return 0; } + virtual bool is_creatable() const { return 0; } + virtual bool must_be_loaded() const { return 1; } + virtual bool is_reset_on_load() const { return 1; } + virtual const option_guide *create_option_guide() const { return NULL; } + virtual const char *image_interface() const { return "wswan_cart"; } + virtual const char *file_extensions() const { return "ws,wsc,bin"; } + + // slot interface overrides + virtual void get_default_card_software(std::string &result); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read_rom20); + virtual DECLARE_READ8_MEMBER(read_rom30); + virtual DECLARE_READ8_MEMBER(read_rom40); + virtual DECLARE_READ8_MEMBER(read_ram); + virtual DECLARE_WRITE8_MEMBER(write_ram); + virtual DECLARE_READ8_MEMBER(read_io); + virtual DECLARE_WRITE8_MEMBER(write_io); + +protected: + + int m_type; + device_ws_cart_interface* m_cart; +}; + + + +// device type definition +extern const device_type WS_CART_SLOT; + + +/*************************************************************************** + DEVICE CONFIGURATION MACROS + ***************************************************************************/ + +#define WSSLOT_ROM_REGION_TAG ":cart:rom" + +#define MCFG_WSWAN_CARTRIDGE_ADD(_tag,_slot_intf,_def_slot) \ + MCFG_DEVICE_ADD(_tag, WS_CART_SLOT, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) +#endif diff --git a/src/devices/bus/x68k/x68k_neptunex.c b/src/devices/bus/x68k/x68k_neptunex.c new file mode 100644 index 00000000000..affb3ead65c --- /dev/null +++ b/src/devices/bus/x68k/x68k_neptunex.c @@ -0,0 +1,149 @@ +// license:BSD-3-Clause +// copyright-holders:Barry Rodewald +/* + * x68k_neptunex.c + */ + +#include "emu.h" +#include "machine/dp8390.h" +#include "x68k_neptunex.h" + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type X68K_NEPTUNEX = &device_creator; + +// device machine config +static MACHINE_CONFIG_FRAGMENT( x68k_neptunex ) + MCFG_DEVICE_ADD("dp8390d", DP8390D, 0) + MCFG_DP8390D_IRQ_CB(WRITELINE(x68k_neptune_device, x68k_neptune_irq_w)) + MCFG_DP8390D_MEM_READ_CB(READ8(x68k_neptune_device, x68k_neptune_mem_read)) + MCFG_DP8390D_MEM_WRITE_CB(WRITE8(x68k_neptune_device, x68k_neptune_mem_write)) +MACHINE_CONFIG_END + +machine_config_constructor x68k_neptune_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( x68k_neptunex ); +} + +x68k_neptune_device::x68k_neptune_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, X68K_NEPTUNEX, "Neptune-X", tag, owner, clock, "x68k_neptunex", __FILE__), + device_x68k_expansion_card_interface(mconfig, *this), + m_dp8390(*this, "dp8390d") +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void x68k_neptune_device::device_start() +{ + device_t* cpu = machine().device("maincpu"); + char mac[7]; + UINT32 num = rand(); + address_space& space = cpu->memory().space(AS_PROGRAM); + m_slot = dynamic_cast(owner()); + memset(m_prom, 0x57, 16); + sprintf(mac+2, "\x1b%c%c%c", (num >> 16) & 0xff, (num >> 8) & 0xff, num & 0xff); + mac[0] = 0; mac[1] = 0; // avoid gcc warning + memcpy(m_prom, mac, 6); + m_dp8390->set_mac(mac); + space.install_readwrite_handler(0xece000,0xece3ff,read16_delegate(FUNC(x68k_neptune_device::x68k_neptune_port_r),this),write16_delegate(FUNC(x68k_neptune_device::x68k_neptune_port_w),this),0xffffffff); +} + +void x68k_neptune_device::device_reset() { + memcpy(m_prom, m_dp8390->get_mac(), 6); +} + +READ16_MEMBER(x68k_neptune_device::x68k_neptune_port_r) +{ + UINT16 data; + + if(offset >= 0x100+32 || offset < 0x100) + return 0xffff; + if(offset < 0x100+16) + { + m_dp8390->dp8390_cs(CLEAR_LINE); + return (m_dp8390->dp8390_r(space, offset, 0xff) << 8)| + m_dp8390->dp8390_r(space, offset+1, 0xff); + } + //if(mem_mask == 0x00ff) offset++; + switch(offset) + { + case 0x100+16: + m_dp8390->dp8390_cs(ASSERT_LINE); + data = m_dp8390->dp8390_r(space, offset, mem_mask); + data = ((data & 0x00ff) << 8) | ((data & 0xff00) >> 8); + return data; + case 0x100+31: + m_dp8390->dp8390_reset(CLEAR_LINE); + return 0; + default: + logerror("x68k_neptune: invalid register read %02X\n", offset); + } + return 0; +} + +WRITE16_MEMBER(x68k_neptune_device::x68k_neptune_port_w) +{ + if(offset >= 0x100+32 || offset < 0x100) + return; + if(offset < 0x100+16) + { + m_dp8390->dp8390_cs(CLEAR_LINE); + if(mem_mask == 0x00ff) + { + data <<= 8; + offset++; + } + m_dp8390->dp8390_w(space, offset, data>>8, 0xff); + if(mem_mask == 0xffff) m_dp8390->dp8390_w(space, offset+1, data & 0xff, 0xff); + return; + } + //if(mem_mask == 0x00ff) offset++; + switch(offset) + { + case 0x100+16: + m_dp8390->dp8390_cs(ASSERT_LINE); + data = ((data & 0x00ff) << 8) | ((data & 0xff00) >> 8); + m_dp8390->dp8390_w(space, offset, data, mem_mask); + return; + case 0x100+31: + m_dp8390->dp8390_reset(ASSERT_LINE); + return; + default: + logerror("x68k_neptune: invalid register write %02X\n", offset); + } + return; +} + +READ8_MEMBER(x68k_neptune_device::x68k_neptune_mem_read) +{ + if(offset < 32) return m_prom[offset>>1]; + if((offset < (16*1024)) || (offset >= (32*1024))) + { + logerror("x68k_neptune: invalid memory read %04X\n", offset); + return 0xff; + } + return m_board_ram[offset - (16*1024)]; +} + +WRITE8_MEMBER(x68k_neptune_device::x68k_neptune_mem_write) +{ + if((offset < (16*1024)) || (offset >= (32*1024))) + { + logerror("x68k_neptune: invalid memory write %04X\n", offset); + return; + } + m_board_ram[offset - (16*1024)] = data; +} + +WRITE_LINE_MEMBER(x68k_neptune_device::x68k_neptune_irq_w) +{ + machine().device("maincpu")->execute().set_input_line_vector(2, NEPTUNE_IRQ_VECTOR); + m_slot->irq2_w(state); + logerror("Neptune: IRQ2 set to %i\n",state); +} diff --git a/src/devices/bus/x68k/x68k_neptunex.h b/src/devices/bus/x68k/x68k_neptunex.h new file mode 100644 index 00000000000..ad6f1b9560c --- /dev/null +++ b/src/devices/bus/x68k/x68k_neptunex.h @@ -0,0 +1,54 @@ +// license:BSD-3-Clause +// copyright-holders:Barry Rodewald +/* + * x68k_neptunex.h + * + * Neptune-X NE2000-based ethernet board for the X68000 + * + * Map: + * 0xECE000-0xECE3FF: "Y0" + * 0xECE400-0xECE7FF: "Y1" + */ + +#ifndef X68K_NEPTUNEX_H_ +#define X68K_NEPTUNEX_H_ + +#include "emu.h" +#include "machine/dp8390.h" +#include "x68kexp.h" + +#define NEPTUNE_IRQ_VECTOR 0xf9 + +class x68k_neptune_device : public device_t, + public device_x68k_expansion_card_interface +{ +public: + // construction/destruction + x68k_neptune_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + + void x68k_neptune_irq_w(int state); + DECLARE_READ8_MEMBER(x68k_neptune_mem_read); + DECLARE_WRITE8_MEMBER(x68k_neptune_mem_write); + DECLARE_READ16_MEMBER(x68k_neptune_port_r); + DECLARE_WRITE16_MEMBER(x68k_neptune_port_w); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + +private: + x68k_expansion_slot_device *m_slot; + + required_device m_dp8390; + UINT8 m_board_ram[16*1024]; + UINT8 m_prom[16]; +}; + +// device type definition +extern const device_type X68K_NEPTUNEX; + +#endif /* X68K_NEPTUNEX_H_ */ diff --git a/src/devices/bus/x68k/x68k_scsiext.c b/src/devices/bus/x68k/x68k_scsiext.c new file mode 100644 index 00000000000..b3490cda74d --- /dev/null +++ b/src/devices/bus/x68k/x68k_scsiext.c @@ -0,0 +1,101 @@ +// license:BSD-3-Clause +// copyright-holders:Barry Rodewald +/* + * x68k_scsiext.c + * + * Sharp CZ-6BS1 SCSI-1 controller + * + * Created on: 5/06/2012 + */ + +#include "emu.h" +#include "bus/scsi/scsi.h" +#include "bus/scsi/scsihd.h" +#include "machine/mb89352.h" +#include "x68k_scsiext.h" + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type X68K_SCSIEXT = &device_creator; + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +ROM_START( x68k_cz6bs1 ) + ROM_REGION( 0x10000, "scsiexrom", 0 ) + ROM_LOAD16_WORD_SWAP( "scsiexrom.bin", 0x0000, 0x2000, CRC(7be488de) SHA1(49616c09a8986ffe6a12ad600febe512f7ba8ae4) ) +ROM_END + +const rom_entry *x68k_scsiext_device::device_rom_region() const +{ + return ROM_NAME( x68k_cz6bs1 ); +} + +// device machine config +static MACHINE_CONFIG_FRAGMENT( x68k_scsiext ) + MCFG_DEVICE_ADD("scsi", SCSI_PORT, 0) + MCFG_SCSIDEV_ADD("scsi:" SCSI_PORT_DEVICE1, "harddisk", SCSIHD, SCSI_ID_0) + MCFG_SCSIDEV_ADD("scsi:" SCSI_PORT_DEVICE2, "harddisk", SCSIHD, SCSI_ID_1) + MCFG_SCSIDEV_ADD("scsi:" SCSI_PORT_DEVICE3, "harddisk", SCSIHD, SCSI_ID_2) + MCFG_SCSIDEV_ADD("scsi:" SCSI_PORT_DEVICE4, "harddisk", SCSIHD, SCSI_ID_3) + MCFG_SCSIDEV_ADD("scsi:" SCSI_PORT_DEVICE5, "harddisk", SCSIHD, SCSI_ID_4) + MCFG_SCSIDEV_ADD("scsi:" SCSI_PORT_DEVICE6, "harddisk", SCSIHD, SCSI_ID_5) + MCFG_SCSIDEV_ADD("scsi:" SCSI_PORT_DEVICE7, "harddisk", SCSIHD, SCSI_ID_6) + + MCFG_DEVICE_ADD("mb89352", MB89352A, 0) + MCFG_LEGACY_SCSI_PORT("scsi") + MCFG_MB89352A_IRQ_CB(WRITELINE(x68k_scsiext_device, irq_w)) + MCFG_MB89352A_DRQ_CB(WRITELINE(x68k_scsiext_device, drq_w)) +MACHINE_CONFIG_END + +machine_config_constructor x68k_scsiext_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( x68k_scsiext ); +} + +x68k_scsiext_device::x68k_scsiext_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, X68K_SCSIEXT, "Sharp CZ-6BS1 SCSI-1", tag, owner, clock, "x68k_cz6bs1", __FILE__), + device_x68k_expansion_card_interface(mconfig, *this), + m_spc(*this, "mb89352") +{ +} + +void x68k_scsiext_device::device_start() +{ + device_t* cpu = machine().device("maincpu"); + UINT8* ROM; + address_space& space = cpu->memory().space(AS_PROGRAM); + m_slot = dynamic_cast(owner()); + space.install_read_bank(0xea0020,0xea1fff,0,0,"scsi_ext"); + space.unmap_write(0xea0020,0xea1fff,0,0); + ROM = machine().root_device().memregion(subtag("scsiexrom").c_str())->base(); + machine().root_device().membank("scsi_ext")->set_base(ROM); + space.install_readwrite_handler(0xea0000,0xea001f,0,0,read8_delegate(FUNC(x68k_scsiext_device::register_r),this),write8_delegate(FUNC(x68k_scsiext_device::register_w),this),0x00ff00ff); +} + +void x68k_scsiext_device::device_reset() +{ +} + +void x68k_scsiext_device::irq_w(int state) +{ + m_slot->irq2_w(state); // correct? Or perhaps selectable? +} + +void x68k_scsiext_device::drq_w(int state) +{ + // TODO +} + +READ8_MEMBER(x68k_scsiext_device::register_r) +{ + return m_spc->mb89352_r(space,offset); +} + +WRITE8_MEMBER(x68k_scsiext_device::register_w) +{ + m_spc->mb89352_w(space,offset,data); +} diff --git a/src/devices/bus/x68k/x68k_scsiext.h b/src/devices/bus/x68k/x68k_scsiext.h new file mode 100644 index 00000000000..93f6fa24b79 --- /dev/null +++ b/src/devices/bus/x68k/x68k_scsiext.h @@ -0,0 +1,46 @@ +// license:BSD-3-Clause +// copyright-holders:Barry Rodewald +/* + * x68k_scsiext.h + * + * Created on: 5/06/2012 + */ + +#ifndef X68K_SCSIEXT_H_ +#define X68K_SCSIEXT_H_ + +#include "emu.h" +#include "machine/mb89352.h" +#include "x68kexp.h" + +class x68k_scsiext_device : public device_t, + public device_x68k_expansion_card_interface +{ +public: + // construction/destruction + x68k_scsiext_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual const rom_entry *device_rom_region() const; + + void irq_w(int state); + void drq_w(int state); + DECLARE_READ8_MEMBER(register_r); + DECLARE_WRITE8_MEMBER(register_w); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); +private: + x68k_expansion_slot_device *m_slot; + + required_device m_spc; +}; + +// device type definition +extern const device_type X68K_SCSIEXT; + + +#endif /* X68K_SCSIEXT_H_ */ diff --git a/src/devices/bus/x68k/x68kexp.c b/src/devices/bus/x68k/x68kexp.c new file mode 100644 index 00000000000..3aaf03bdd3a --- /dev/null +++ b/src/devices/bus/x68k/x68kexp.c @@ -0,0 +1,79 @@ +// license:BSD-3-Clause +// copyright-holders:Barry Rodewald +/* + * x68kexp.c + */ + +#include "emu.h" +#include "emuopts.h" +#include "x68kexp.h" + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type X68K_EXPANSION_SLOT = &device_creator; + + +//************************************************************************** +// DEVICE CPC_EXPANSION CARD INTERFACE +//************************************************************************** + + +device_x68k_expansion_card_interface::device_x68k_expansion_card_interface(const machine_config &mconfig, device_t &device) + : device_slot_card_interface(mconfig, device) +{ +} + + +device_x68k_expansion_card_interface::~device_x68k_expansion_card_interface() +{ +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +x68k_expansion_slot_device::x68k_expansion_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, X68K_EXPANSION_SLOT, "Sharp X680x0 expansion slot", tag, owner, clock, "x68k_expansion_slot", __FILE__), + device_slot_interface(mconfig, *this), + m_out_irq2_cb(*this), + m_out_irq4_cb(*this), + m_out_nmi_cb(*this), + m_out_reset_cb(*this) +{ +} + +x68k_expansion_slot_device::~x68k_expansion_slot_device() +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void x68k_expansion_slot_device::device_start() +{ + m_card = dynamic_cast(get_card_device()); + + // resolve callbacks + m_out_irq2_cb.resolve_safe(); + m_out_irq4_cb.resolve_safe(); + m_out_nmi_cb.resolve_safe(); + m_out_reset_cb.resolve_safe(); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void x68k_expansion_slot_device::device_reset() +{ +} + + +WRITE_LINE_MEMBER( x68k_expansion_slot_device::irq2_w ) { m_out_irq2_cb(state); } +WRITE_LINE_MEMBER( x68k_expansion_slot_device::irq4_w ) { m_out_irq4_cb(state); } +WRITE_LINE_MEMBER( x68k_expansion_slot_device::nmi_w ) { m_out_nmi_cb(state); } +WRITE_LINE_MEMBER( x68k_expansion_slot_device::reset_w ) { m_out_reset_cb(state); } diff --git a/src/devices/bus/x68k/x68kexp.h b/src/devices/bus/x68k/x68kexp.h new file mode 100644 index 00000000000..9a016b7ebbe --- /dev/null +++ b/src/devices/bus/x68k/x68kexp.h @@ -0,0 +1,149 @@ +// license:BSD-3-Clause +// copyright-holders:Barry Rodewald +/* + * x68kexp.h + * + * Expansion slots for the X680x0 series + * + * Pinout: (from http://www.amy.hi-ho.ne.jp/shimada/neptune/x68k.html) + +-----+ + GND B1 |[] []| A1 GND + 10MHz B2 |[] []| A2 20MHz + #10MHz B3 |[] []| A3 GND + E B4 |[] []| A4 DB0 + AB1 B5 |[] []| A5 DB1 + AB2 B6 |[] []| A6 DB2 + AB3 B7 |[] []| A7 DB3 + AB4 B8 |[] []| A8 DB4 + AB5 B9 |[] []| A9 DB5 + AB6 B10 |[] []| A10 DB6 + GND B11 |[] []| A11 GND + AB7 B12 |[] []| A12 DB7 + AB8 B13 |[] []| A13 DB8 + AB9 B14 |[] []| A14 DB9 + AB10 B15 |[] []| A15 DB10 + AB11 B16 |[] []| A16 DB11 + AB12 B17 |[] []| A17 DB12 + AB13 B18 |[] []| A18 DB13 + AB14 B19 |[] []| A19 DB14 + AB15 B20 |[] []| A20 DB15 + GND B21 |[] []| A21 GND + AB16 B22 |[] []| A22 +12V + AB17 B23 |[] []| A23 +12V + AB18 B24 |[] []| A24 FC0 + AB19 B25 |[] []| A25 FC1 + AB20 B26 |[] []| A26 FC2 + AB21 B27 |[] []| A27 #AS + AB22 B28 |[] []| A28 #LDS + AB23 B29 |[] []| A29 #UDS + IDDIR B30 |[] []| A30 R/#W + N.C. B31 |[] []| A31 N.C. + HSYNC B32 |[] []| A32 -12V + VSYNC B33 |[] []| A33 -12V + #DONE B34 |[] []| A34 #VMA + #DTC B35 |[] []| A35 #EXVPA + #EXREQ B36 |[] []| A36 #DTACK + #EXACK B37 |[] []| A37 #EXRESET + #EXPCL B38 |[] []| A38 #HALT + #EXOWN B39 |[] []| A39 #EXBERR + #EXNMI B40 |[] []| A40 #EXPWON + GND B41 |[] []| A41 GND + #IRQ2 B42 |[] []| A42 Vcc2 + #IRQ4 B43 |[] []| A43 Vcc2 + #IACK2 B44 |[] []| A44 SELEN + #IACK4 B45 |[] []| A45 CASRDEN + #BR B46 |[] []| A46 CASWRL + #BG B47 |[] []| A47 CASWRU + #BGACK B48 |[] []| A48 INH2 + Vcc1 B49 |[] []| A49 Vcc1 + Vcc1 B50 |[] []| A50 Vcc1 + +-----+ + * + */ + +#ifndef X68KEXP_H_ +#define X68KEXP_H_ + +#include "emu.h" + +//************************************************************************** +// CONSTANTS +//************************************************************************** + +#define X68K_EXP_SLOT_TAG "x68kexp" + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_X68K_EXPANSION_SLOT_OUT_IRQ2_CB(_devcb) \ + devcb = &x68k_expansion_slot_device::set_out_irq2_callback(*device, DEVCB_##_devcb); + +#define MCFG_X68K_EXPANSION_SLOT_OUT_IRQ4_CB(_devcb) \ + devcb = &x68k_expansion_slot_device::set_out_irq4_callback(*device, DEVCB_##_devcb); + +#define MCFG_X68K_EXPANSION_SLOT_OUT_NMI_CB(_devcb) \ + devcb = &x68k_expansion_slot_device::set_out_nmi_callback(*device, DEVCB_##_devcb); + +#define MCFG_X68K_EXPANSION_SLOT_OUT_RESET_CB(_devcb) \ + devcb = &x68k_expansion_slot_device::set_out_reset_callback(*device, DEVCB_##_devcb); + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> device_x68k_expansion_card_interface + +// class representing interface-specific live x68k_expansion card +class device_x68k_expansion_card_interface : public device_slot_card_interface +{ +public: + // construction/destruction + device_x68k_expansion_card_interface(const machine_config &mconfig, device_t &device); + virtual ~device_x68k_expansion_card_interface(); + + // reset + virtual void x68k_reset_w() { }; +}; + + +// ======================> x68k_expansion_slot_device + +class x68k_expansion_slot_device : public device_t, + public device_slot_interface +{ +public: + // construction/destruction + x68k_expansion_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual ~x68k_expansion_slot_device(); + + template static devcb_base &set_out_irq2_callback(device_t &device, _Object object) { return downcast(device).m_out_irq2_cb.set_callback(object); } + template static devcb_base &set_out_irq4_callback(device_t &device, _Object object) { return downcast(device).m_out_irq4_cb.set_callback(object); } + template static devcb_base &set_out_nmi_callback(device_t &device, _Object object) { return downcast(device).m_out_nmi_cb.set_callback(object); } + template static devcb_base &set_out_reset_callback(device_t &device, _Object object) { return downcast(device).m_out_reset_cb.set_callback(object); } + + + DECLARE_WRITE_LINE_MEMBER( irq2_w ); + DECLARE_WRITE_LINE_MEMBER( irq4_w ); + DECLARE_WRITE_LINE_MEMBER( nmi_w ); + DECLARE_WRITE_LINE_MEMBER( reset_w ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + devcb_write_line m_out_irq2_cb; + devcb_write_line m_out_irq4_cb; + devcb_write_line m_out_nmi_cb; + devcb_write_line m_out_reset_cb; + + device_x68k_expansion_card_interface *m_card; +}; + + +// device type definition +extern const device_type X68K_EXPANSION_SLOT; + +#endif /* X68KEXP_H_ */ diff --git a/src/devices/bus/z88/flash.c b/src/devices/bus/z88/flash.c new file mode 100644 index 00000000000..0793f126c18 --- /dev/null +++ b/src/devices/bus/z88/flash.c @@ -0,0 +1,94 @@ +// license:BSD-3-Clause +// copyright-holders:Sandro Ronco +/*************************************************************************** + + flash.c + + Z88 Flash cartridges emulation + +***************************************************************************/ + +#include "emu.h" +#include "flash.h" + + +//************************************************************************** +// MACROS/CONSTANTS +//************************************************************************** + +#define FLASH_TAG "flash" + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type Z88_1024K_FLASH = &device_creator; + +//------------------------------------------------- +// MACHINE_CONFIG_FRAGMENT( z88_flash ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT(z88_flash) + MCFG_INTEL_E28F008SA_ADD(FLASH_TAG) +MACHINE_CONFIG_END + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// z88_1024k_flash_device - constructor +//------------------------------------------------- + +z88_1024k_flash_device::z88_1024k_flash_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, Z88_1024K_FLASH, "Z88 1024KB Flash", tag, owner, clock, "z88_1024k_flash", __FILE__), + device_z88cart_interface( mconfig, *this ), + m_flash(*this, FLASH_TAG) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void z88_1024k_flash_device::device_start() +{ +} + + +//------------------------------------------------- +// device_mconfig_additions +//------------------------------------------------- + +machine_config_constructor z88_1024k_flash_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( z88_flash ); +} + +/*------------------------------------------------- + get_cart_base +-------------------------------------------------*/ + +UINT8* z88_1024k_flash_device::get_cart_base() +{ + return (UINT8*)m_flash->space().get_read_ptr(0); +} + +/*------------------------------------------------- + read +-------------------------------------------------*/ + +READ8_MEMBER(z88_1024k_flash_device::read) +{ + return m_flash->read(offset & (get_cart_size() - 1)); +} + +/*------------------------------------------------- + write +-------------------------------------------------*/ + +WRITE8_MEMBER(z88_1024k_flash_device::write) +{ + m_flash->write(offset & (get_cart_size() - 1), data); +} diff --git a/src/devices/bus/z88/flash.h b/src/devices/bus/z88/flash.h new file mode 100644 index 00000000000..8ea09040e39 --- /dev/null +++ b/src/devices/bus/z88/flash.h @@ -0,0 +1,46 @@ +// license:BSD-3-Clause +// copyright-holders:Sandro Ronco +#pragma once + +#ifndef __Z88_FLASH_H__ +#define __Z88_FLASH_H__ + +#include "emu.h" +#include "z88.h" +#include "machine/intelfsh.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> z88_1024k_flash_device + +class z88_1024k_flash_device : public device_t, + public device_z88cart_interface +{ +public: + // construction/destruction + z88_1024k_flash_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + +protected: + // device-level overrides + virtual void device_start(); + + // z88cart_interface overrides + virtual DECLARE_READ8_MEMBER(read); + virtual DECLARE_WRITE8_MEMBER(write); + virtual UINT8* get_cart_base(); + virtual UINT32 get_cart_size() { return 0x100000; } + +private: + required_device m_flash; +}; + +// device type definition +extern const device_type Z88_1024K_FLASH; + + +#endif /* __Z88_FLASH_H__ */ diff --git a/src/devices/bus/z88/ram.c b/src/devices/bus/z88/ram.c new file mode 100644 index 00000000000..d35f3d81ccd --- /dev/null +++ b/src/devices/bus/z88/ram.c @@ -0,0 +1,110 @@ +// license:BSD-3-Clause +// copyright-holders:Sandro Ronco +/*************************************************************************** + + z88.c + + Z88 RAM cartridges emulation + +***************************************************************************/ + +#include "emu.h" +#include "ram.h" + +/*************************************************************************** + IMPLEMENTATION +***************************************************************************/ + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type Z88_32K_RAM = &device_creator; +const device_type Z88_128K_RAM = &device_creator; +const device_type Z88_512K_RAM = &device_creator; +const device_type Z88_1024K_RAM = &device_creator; + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// z88_32k_ram_device - constructor +//------------------------------------------------- + +z88_32k_ram_device::z88_32k_ram_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, Z88_32K_RAM, "Z88 32KB RAM", tag, owner, clock, "z88_32k_ram", __FILE__), + device_z88cart_interface( mconfig, *this ) +{ +} + +z88_32k_ram_device::z88_32k_ram_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_z88cart_interface( mconfig, *this ) +{ +} + +//------------------------------------------------- +// z88_128k_ram_device - constructor +//------------------------------------------------- + +z88_128k_ram_device::z88_128k_ram_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : z88_32k_ram_device(mconfig, Z88_128K_RAM, "Z88 128KB RAM", tag, owner, clock, "z88_128k_ram", __FILE__) +{ +} + +//------------------------------------------------- +// z88_512k_ram_device - constructor +//------------------------------------------------- + +z88_512k_ram_device::z88_512k_ram_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : z88_32k_ram_device(mconfig, Z88_512K_RAM, "Z88 512KB RAM", tag, owner, clock, "z88_512k_ram", __FILE__) +{ +} + +//------------------------------------------------- +// z88_1024k_ram_device - constructor +//------------------------------------------------- + +z88_1024k_ram_device::z88_1024k_ram_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : z88_32k_ram_device(mconfig, Z88_1024K_RAM, "Z88 1024KB RAM", tag, owner, clock, "z88_1024k_ram", __FILE__) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void z88_32k_ram_device::device_start() +{ + m_ram = machine().memory().region_alloc(tag(), get_cart_size(), 1, ENDIANNESS_LITTLE)->base(); + memset(m_ram, 0, get_cart_size()); +} + +/*------------------------------------------------- + get_cart_base +-------------------------------------------------*/ + +UINT8* z88_32k_ram_device::get_cart_base() +{ + return m_ram; +} + +/*------------------------------------------------- + read +-------------------------------------------------*/ + +READ8_MEMBER(z88_32k_ram_device::read) +{ + return m_ram[offset & (get_cart_size() - 1)]; +} + +/*------------------------------------------------- + write +-------------------------------------------------*/ + +WRITE8_MEMBER(z88_32k_ram_device::write) +{ + m_ram[offset & (get_cart_size() - 1)] = data; +} diff --git a/src/devices/bus/z88/ram.h b/src/devices/bus/z88/ram.h new file mode 100644 index 00000000000..0f8dc4a4ff7 --- /dev/null +++ b/src/devices/bus/z88/ram.h @@ -0,0 +1,85 @@ +// license:BSD-3-Clause +// copyright-holders:Sandro Ronco +#pragma once + +#ifndef __Z88_RAM_H__ +#define __Z88_RAM_H__ + +#include "emu.h" +#include "z88.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> z88_32k_ram_device + +class z88_32k_ram_device : public device_t, + public device_z88cart_interface +{ +public: + // construction/destruction + z88_32k_ram_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + z88_32k_ram_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + +protected: + // device-level overrides + virtual void device_start(); + + // z88cart_interface overrides + virtual DECLARE_READ8_MEMBER(read); + virtual DECLARE_WRITE8_MEMBER(write); + virtual UINT8* get_cart_base(); + virtual UINT32 get_cart_size() { return 0x8000; } + +protected: + // internal state + UINT8 * m_ram; +}; + +// ======================> z88_128k_ram_device + +class z88_128k_ram_device : public z88_32k_ram_device +{ +public: + // construction/destruction + z88_128k_ram_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // z88cart_interface overrides + virtual UINT32 get_cart_size() { return 0x20000; } +}; + +// ======================> z88_512k_ram_device + +class z88_512k_ram_device : public z88_32k_ram_device +{ +public: + // construction/destruction + z88_512k_ram_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // z88cart_interface overrides + virtual UINT32 get_cart_size() { return 0x80000; } +}; + +// ======================> z88_1024k_ram_device + +class z88_1024k_ram_device : public z88_32k_ram_device +{ +public: + // construction/destruction + z88_1024k_ram_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // z88cart_interface overrides + virtual UINT32 get_cart_size() { return 0x100000; } +}; + +// device type definition +extern const device_type Z88_32K_RAM; +extern const device_type Z88_128K_RAM; +extern const device_type Z88_512K_RAM; +extern const device_type Z88_1024K_RAM; + +#endif /* __Z88_RAM_H__ */ diff --git a/src/devices/bus/z88/rom.c b/src/devices/bus/z88/rom.c new file mode 100644 index 00000000000..4ebdef5fc85 --- /dev/null +++ b/src/devices/bus/z88/rom.c @@ -0,0 +1,89 @@ +// license:BSD-3-Clause +// copyright-holders:Sandro Ronco +/*************************************************************************** + + rom.c + + Z88 ROM cartridges emulation + +***************************************************************************/ + +#include "emu.h" +#include "rom.h" + +/*************************************************************************** + IMPLEMENTATION +***************************************************************************/ + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type Z88_32K_ROM = &device_creator; +const device_type Z88_128K_ROM = &device_creator; +const device_type Z88_256K_ROM = &device_creator; + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// z88_32k_rom_device - constructor +//------------------------------------------------- + +z88_32k_rom_device::z88_32k_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, Z88_32K_ROM, "Z88 32KB ROM", tag, owner, clock, "z88_32k_rom", __FILE__), + device_z88cart_interface( mconfig, *this ) +{ +} + +z88_32k_rom_device::z88_32k_rom_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_z88cart_interface( mconfig, *this ) +{ +} + +//------------------------------------------------- +// z88_128k_rom_device - constructor +//------------------------------------------------- + +z88_128k_rom_device::z88_128k_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : z88_32k_rom_device(mconfig, Z88_128K_ROM, "Z88 128KB ROM", tag, owner, clock, "z88_128k_rom", __FILE__) +{ +} + +//------------------------------------------------- +// z88_256k_rom_device - constructor +//------------------------------------------------- + +z88_256k_rom_device::z88_256k_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : z88_32k_rom_device(mconfig, Z88_256K_ROM, "Z88 256KB ROM", tag, owner, clock, "z88_256k_rom", __FILE__) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void z88_32k_rom_device::device_start() +{ + m_rom = machine().memory().region_alloc(tag(), get_cart_size(), 1, ENDIANNESS_LITTLE)->base(); +} + +/*------------------------------------------------- + get_cart_base +-------------------------------------------------*/ + +UINT8* z88_32k_rom_device::get_cart_base() +{ + return m_rom; +} + +/*------------------------------------------------- + read +-------------------------------------------------*/ + +READ8_MEMBER(z88_32k_rom_device::read) +{ + return m_rom[offset & (get_cart_size() - 1)]; +} diff --git a/src/devices/bus/z88/rom.h b/src/devices/bus/z88/rom.h new file mode 100644 index 00000000000..41cdbc4a771 --- /dev/null +++ b/src/devices/bus/z88/rom.h @@ -0,0 +1,70 @@ +// license:BSD-3-Clause +// copyright-holders:Sandro Ronco +#pragma once + +#ifndef __Z88_ROM_H__ +#define __Z88_ROM_H__ + +#include "emu.h" +#include "z88.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> z88_32k_rom_device + +class z88_32k_rom_device : public device_t, + public device_z88cart_interface +{ +public: + // construction/destruction + z88_32k_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + z88_32k_rom_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + +protected: + // device-level overrides + virtual void device_start(); + + // z88cart_interface overrides + virtual DECLARE_READ8_MEMBER(read); + virtual UINT8* get_cart_base(); + virtual UINT32 get_cart_size() { return 0x8000; } + +protected: + // internal state + UINT8 * m_rom; +}; + +// ======================> z88_128k_rom_device + +class z88_128k_rom_device : public z88_32k_rom_device +{ +public: + // construction/destruction + z88_128k_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // z88cart_interface overrides + virtual UINT32 get_cart_size() { return 0x20000; } +}; + +// ======================> z88_256k_rom_device + +class z88_256k_rom_device : public z88_32k_rom_device +{ +public: + // construction/destruction + z88_256k_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // z88cart_interface overrides + virtual UINT32 get_cart_size() { return 0x200000; } +}; + +// device type definition +extern const device_type Z88_32K_ROM; +extern const device_type Z88_128K_ROM; +extern const device_type Z88_256K_ROM; + +#endif /* __Z88_ROM_H__ */ diff --git a/src/devices/bus/z88/z88.c b/src/devices/bus/z88/z88.c new file mode 100644 index 00000000000..b1c13865fb7 --- /dev/null +++ b/src/devices/bus/z88/z88.c @@ -0,0 +1,212 @@ +// license:BSD-3-Clause +// copyright-holders:Sandro Ronco +/********************************************************************* + + z88.c + + Z88 cartridge slots emulation + +*********************************************************************/ + +#include "emu.h" +#include "z88.h" +#include "emuopts.h" + + +/*************************************************************************** + PARAMETERS +***************************************************************************/ + +#define CLOSE_FLAP_TIME attotime::from_msec(200) + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type Z88CART_SLOT = &device_creator; + + +//************************************************************************** +// Z88 cartridges Interface +//************************************************************************** + +//------------------------------------------------- +// device_z88cart_interface - constructor +//------------------------------------------------- + +device_z88cart_interface::device_z88cart_interface(const machine_config &mconfig, device_t &device) + : device_slot_card_interface(mconfig, device) +{ +} + + +//------------------------------------------------- +// ~device_z88cart_interface - destructor +//------------------------------------------------- + +device_z88cart_interface::~device_z88cart_interface() +{ +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// z88cart_slot_device - constructor +//------------------------------------------------- +z88cart_slot_device::z88cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, Z88CART_SLOT, "Z88 Cartridge Slot", tag, owner, clock, "z88cart_slot", __FILE__), + device_image_interface(mconfig, *this), + device_slot_interface(mconfig, *this), + m_out_flp_cb(*this) +{ +} + +//------------------------------------------------- +// z88cart_slot_device - destructor +//------------------------------------------------- + +z88cart_slot_device::~z88cart_slot_device() +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void z88cart_slot_device::device_start() +{ + m_cart = dynamic_cast(get_card_device()); + + // resolve callbacks + m_out_flp_cb.resolve_safe(); + + m_flp_timer = timer_alloc(TIMER_FLP_CLEAR); + m_flp_timer->reset(); +} + +//------------------------------------------------- +// device_config_complete - perform any +// operations now that the configuration is +// complete +//------------------------------------------------- + +void z88cart_slot_device::device_config_complete() +{ + // set brief and instance name + update_names(); +} + + +//------------------------------------------------- +// device_timer - handler timer events +//------------------------------------------------- + +void z88cart_slot_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + if (id == TIMER_FLP_CLEAR) + { + // close the flap + m_out_flp_cb(CLEAR_LINE); + } +} + +/*------------------------------------------------- + call load +-------------------------------------------------*/ + +bool z88cart_slot_device::call_load() +{ + if (m_cart) + { + offs_t read_length = 0; + UINT8 *cart_base = m_cart->get_cart_base(); + + if (cart_base != NULL) + { + if (software_entry() == NULL) + { + read_length = length(); + fread(cart_base + (m_cart->get_cart_size() - read_length), read_length); + } + else + { + read_length = get_software_region_length("rom"); + memcpy(cart_base + (m_cart->get_cart_size() - read_length), get_software_region("rom"), read_length); + } + } + else + return IMAGE_INIT_FAIL; + } + + // open the flap + m_out_flp_cb(ASSERT_LINE); + + // setup the timer for close the flap + m_flp_timer->adjust(CLOSE_FLAP_TIME); + + return IMAGE_INIT_PASS; +} + + +/*------------------------------------------------- + call_unload +-------------------------------------------------*/ + +void z88cart_slot_device::call_unload() +{ + if (m_cart) + memset(m_cart->get_cart_base(), 0xff, m_cart->get_cart_size()); + + // open the flap + m_out_flp_cb(ASSERT_LINE); + + // setup the timer for close the flap + m_flp_timer->adjust(CLOSE_FLAP_TIME); +} + + +/*------------------------------------------------- + call softlist load +-------------------------------------------------*/ + +bool z88cart_slot_device::call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry) +{ + load_software_part_region(*this, swlist, swname, start_entry ); + return TRUE; +} + +/*------------------------------------------------- + get default card software +-------------------------------------------------*/ + +void z88cart_slot_device::get_default_card_software(std::string &result) +{ + software_get_default_slot(result, "128krom"); +} + + +/*------------------------------------------------- + read +-------------------------------------------------*/ + +READ8_MEMBER(z88cart_slot_device::read) +{ + if (m_cart) + return m_cart->read(space, offset); + else + return 0xff; +} + + +/*------------------------------------------------- + write +-------------------------------------------------*/ + +WRITE8_MEMBER(z88cart_slot_device::write) +{ + if (m_cart) + m_cart->write(space, offset, data); +} diff --git a/src/devices/bus/z88/z88.h b/src/devices/bus/z88/z88.h new file mode 100644 index 00000000000..bcba1671941 --- /dev/null +++ b/src/devices/bus/z88/z88.h @@ -0,0 +1,138 @@ +// license:BSD-3-Clause +// copyright-holders:Sandro Ronco +/********************************************************************* + + z88.h + + Z88 cartridge slots emulation + +********************************************************************** + + pins Slot 1 Slot 2 Slot 3 + + 1 A16 A16 A16 + 2 A15 A15 A15 + 3 A12 A12 A12 + 4 A7 A7 A7 + 5 A6 A6 A6 + 6 A5 A5 A5 + 7 A4 A4 A4 + 8 A3 A3 A3 + 9 A2 A2 A2 + 10 A1 A1 A1 + 11 A0 A0 A0 + 12 D0 D0 D0 + 13 D1 D1 D1 + 14 D2 D2 D2 + 15 SNSL SNSL SNSL + 16 GND GND GND + 17 GND GND GND + 18 A14 A14 A14 + 19 VCC VCC VPP + 20 VCC VCC VCC + 21 VCC VCC VCC + 22 WEL WEL PGML + 23 A13 A13 A13 + 24 A8 A8 A8 + 25 A9 A9 A9 + 26 A11 A11 A11 + 27 POE POE POE + 28 ROE ROE EOE + 29 A10 A10 A10 + 30 SE1 SE2 SE3 + 31 D7 D7 D7 + 32 D6 D6 D6 + 33 D3 D3 D3 + 34 D4 D4 D4 + 35 D5 D5 D5 + 36 A17 A17 A17 + 37 A18 A18 A18 + 38 A19 A19 A19 + +*********************************************************************/ + +#ifndef __Z88CART_H__ +#define __Z88CART_H__ + +/*************************************************************************** + TYPE DEFINITIONS +***************************************************************************/ + +// ======================> device_z88cart_interface + +class device_z88cart_interface : public device_slot_card_interface +{ +public: + // construction/destruction + device_z88cart_interface(const machine_config &mconfig, device_t &device); + virtual ~device_z88cart_interface(); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read) { return 0xff; } + virtual DECLARE_WRITE8_MEMBER(write) { } + virtual UINT8* get_cart_base() { return NULL; } + virtual UINT32 get_cart_size() { return 0; } +}; + + +// ======================> z88cart_slot_device + +class z88cart_slot_device : public device_t, + public device_image_interface, + public device_slot_interface +{ +public: + // construction/destruction + z88cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual ~z88cart_slot_device(); + + template static devcb_base &set_out_flp_callback(device_t &device, _Object object) { return downcast(device).m_out_flp_cb.set_callback(object); } + + // device-level overrides + virtual void device_start(); + virtual void device_config_complete(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + // image-level overrides + virtual bool call_load(); + virtual void call_unload(); + virtual bool call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry); + + virtual iodevice_t image_type() const { return IO_CARTSLOT; } + virtual bool is_readable() const { return 1; } + virtual bool is_writeable() const { return 1; } + virtual bool is_creatable() const { return 1; } + virtual bool must_be_loaded() const { return 0; } + virtual bool is_reset_on_load() const { return 0; } + virtual const char *image_interface() const { return "z88_cart"; } + virtual const char *file_extensions() const { return "epr,bin"; } + virtual const option_guide *create_option_guide() const { return NULL; } + + // slot interface overrides + virtual void get_default_card_software(std::string &result); + + // reading and writing + virtual DECLARE_READ8_MEMBER(read); + virtual DECLARE_WRITE8_MEMBER(write); + +private: + static const device_timer_id TIMER_FLP_CLEAR = 0; + + devcb_write_line m_out_flp_cb; + device_z88cart_interface* m_cart; + emu_timer * m_flp_timer; +}; + + +// device type definition +extern const device_type Z88CART_SLOT; + + +/*************************************************************************** + DEVICE CONFIGURATION MACROS +***************************************************************************/ + +#define MCFG_Z88CART_SLOT_OUT_FLP_CB(_devcb) \ + devcb = &z88cart_slot_device::set_out_flp_callback(*device, DEVCB_##_devcb); + +#endif /* __Z88CART_H__ */ diff --git a/src/devices/cpu/8x300/8x300.c b/src/devices/cpu/8x300/8x300.c new file mode 100644 index 00000000000..bf6a5148ca5 --- /dev/null +++ b/src/devices/cpu/8x300/8x300.c @@ -0,0 +1,559 @@ +// license:BSD-3-Clause +// copyright-holders:Barry Rodewald +/* + * 8x300.c + * + * Implementation of the Scientific Micro Systems SMS300 / Signetics 8X300 CPU + * Created on: 18/12/2013 + * + * Written by Barry Rodewald + */ + +#include "debugger.h" +#include "8x300.h" + +#define FETCHOP(a) (m_direct->read_word(a)) +#define CYCLES(x) do { m_icount -= (x); } while (0) +#define READPORT(a) (m_io->read_byte(a)) +#define WRITEPORT(a,v) (m_io->write_byte((a), (v))) + +#define SRC ((opcode & 0x1f00) >> 8) +#define DST (opcode & 0x001f) +#define ROTLEN ((opcode & 0x00e0) >> 5) +#define IMM8 (opcode & 0x00ff) +#define IMM5 (opcode & 0x001f) +#define ADDR (opcode & 0x1fff) +#define OP ((opcode & 0xe000) >> 13) +#define SRC_IS_RIGHT_BANK (opcode & 0x0800) +#define DST_IS_RIGHT_BANK (opcode & 0x0008) +#define SRC_LSB ((opcode & 0x0700) >> 8) +#define DST_LSB (opcode & 0x0007) +#define SET_PC(x) do { m_PC = (x); m_AR = m_PC; m_genPC = m_PC << 1; } while (0) +// for XEC intruction, which sets the AR, but not PC, so that after the instruction at the relative address is done, execution +// returns back to next instruction after XEC, unless a JMP or successful NZT is there. +#define SET_AR(x) do { m_AR = (x); m_genPC = m_AR << 1; m_PC--;} while (0) +#define SRC_LATCH do { if(SRC_IS_RIGHT_BANK) m_right_IV = READPORT(m_IVR+0x100); else m_left_IV = READPORT(m_IVL); } while (0) +#define DST_LATCH do { if(DST_IS_RIGHT_BANK) m_right_IV = READPORT(m_IVR+0x100); else m_left_IV = READPORT(m_IVL); } while (0) +#define SET_OVF do { if(result & 0xff00) m_OVF = 1; else m_OVF = 0; } while (0) + +const device_type N8X300 = &device_creator; + + +n8x300_cpu_device::n8x300_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : cpu_device(mconfig, N8X300, "Signetics 8X300", tag, owner, clock, "8x300", __FILE__) + , m_program_config("program", ENDIANNESS_BIG, 16, 14, 0) + , m_io_config("io", ENDIANNESS_BIG, 8, 9, 0) +{ +} + +void n8x300_cpu_device::set_reg(UINT8 reg, UINT8 val) +{ + switch(reg) + { + case 0x00: m_AUX = val; break; + case 0x01: m_R1 = val; break; + case 0x02: m_R2 = val; break; + case 0x03: m_R3 = val; break; + case 0x04: m_R4 = val; break; + case 0x05: m_R5 = val; break; + case 0x06: m_R6 = val; break; + case 0x07: m_IVL = val; break; +// OVF is read-only + case 0x09: m_R11 = val; break; + case 0x0f: m_IVR = val; break; + default: logerror("8X300: Invalid register %02x written to.\n",reg); break; + } +} + +UINT8 n8x300_cpu_device::get_reg(UINT8 reg) +{ + switch(reg) + { + case 0x00: return m_AUX; + case 0x01: return m_R1; + case 0x02: return m_R2; + case 0x03: return m_R3; + case 0x04: return m_R4; + case 0x05: return m_R5; + case 0x06: return m_R6; +// IVL is write-only + case 0x08: return m_OVF; + case 0x09: return m_R11; +// IVR is write-only + default: logerror("8X300: Invalid register %02x read.\n",reg); return 0; + } +} + +void n8x300_cpu_device::device_start() +{ + m_program = &space(AS_PROGRAM); + m_direct = &m_program->direct(); + m_io = &space(AS_IO); + + save_item(NAME(m_PC)); + save_item(NAME(m_AR)); + save_item(NAME(m_IR)); + save_item(NAME(m_R1)); + save_item(NAME(m_R2)); + save_item(NAME(m_R3)); + save_item(NAME(m_R4)); + save_item(NAME(m_R5)); + save_item(NAME(m_R6)); + save_item(NAME(m_R11)); + save_item(NAME(m_AUX)); + save_item(NAME(m_IVL)); + save_item(NAME(m_IVR)); + save_item(NAME(m_OVF)); + save_item(NAME(m_left_IV)); + save_item(NAME(m_right_IV)); + + // reset registers here, since they are unchanged when /RESET goes low. + m_R1 = 0; + m_R2 = 0; + m_R3 = 0; + m_R4 = 0; + m_R5 = 0; + m_R6 = 0; + m_R11 = 0; + m_IVL = 0; + m_IVR = 0; + m_AUX = 0; + + m_PC = 0; + m_AR = 0; + m_IR = 0; + m_OVF = 0; + m_genPC = 0; + + // Register state for debugger + state_add( _8X300_PC, "PC", m_PC).mask(0x1fff).formatstr("%04X"); + state_add( _8X300_AR, "AR", m_AR).mask(0x1fff).formatstr("%04X"); + state_add( _8X300_IR, "IR", m_IR).mask(0xffff).formatstr("%04X"); + state_add( _8X300_AUX, "AUX", m_AUX).mask(0xff).formatstr("%02X"); + state_add( _8X300_R1, "R1", m_R1).mask(0xff).formatstr("%02X"); + state_add( _8X300_R2, "R2", m_R2).mask(0xff).formatstr("%02X"); + state_add( _8X300_R3, "R3", m_R3).mask(0xff).formatstr("%02X"); + state_add( _8X300_R4, "R4", m_R4).mask(0xff).formatstr("%02X"); + state_add( _8X300_R5, "R5", m_R5).mask(0xff).formatstr("%02X"); + state_add( _8X300_R6, "R6", m_R6).mask(0xff).formatstr("%02X"); + state_add( _8X300_R11, "R11", m_R11).mask(0xff).formatstr("%02X"); + state_add( _8X300_OVF, "OVF", m_OVF).mask(0x01).formatstr("%01X"); + state_add( _8X300_IVL, "IVL", m_IVL).mask(0xff).formatstr("%02X"); + state_add( _8X300_IVR, "IVR", m_IVR).mask(0xff).formatstr("%02X"); + state_add(STATE_GENPC, "curpc", m_genPC).noshow(); + + m_icountptr = &m_icount; +} + +void n8x300_cpu_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + switch (entry.index()) + { +// case STATE_GENFLAGS: +// string.printf("%c%c%c%c%c%c", +// break; + } +} + +void n8x300_cpu_device::device_reset() +{ + /* zero registers */ + m_PC = 0; + m_AR = 0; + m_IR = 0; +} + +void n8x300_cpu_device::execute_run() +{ + do + { + UINT16 opcode; + UINT8 src = 0; + UINT8 dst; + UINT8 rotlen; // rotate amount or I/O field length + UINT8 mask; + UINT16 result; + + /* fetch the opcode */ + debugger_instruction_hook(this, m_genPC); + opcode = FETCHOP(m_genPC); + m_PC++; + m_PC &= 0x1fff; + m_AR = m_PC; + m_IR = opcode; + m_genPC = m_PC << 1; + + switch (OP) + { + case 0x00: // MOVE + rotlen = ROTLEN; + if(is_rot(opcode)) // MOVE reg,reg + { + src = get_reg(SRC); + dst = rotate(src,rotlen); + set_reg(DST,dst); + } + else + { + if(rotlen == 0) + rotlen = 8; // 0 = 8-bit I/O field length + if(is_src_reg(opcode) && !(is_dst_reg(opcode))) + { // MOVE reg,IV + DST_LATCH; + mask = ((1 << rotlen)-1); + src = (get_reg(SRC)) << (7-DST_LSB); + mask <<= (7-DST_LSB); + if(DST_IS_RIGHT_BANK) + { + dst = (m_right_IV & ~mask) | (src & mask); + m_right_IV = dst; + WRITEPORT(m_IVR+0x100,m_right_IV); + } + else + { + dst = (m_left_IV & ~mask) | (src & mask); + m_left_IV = dst; + WRITEPORT(m_IVL,m_left_IV); + } + } + else if(!(is_src_reg(opcode)) && is_dst_reg(opcode)) + { // MOVE IV,reg + SRC_LATCH; + if(SRC_IS_RIGHT_BANK) + src = rotate(m_right_IV,7-SRC_LSB); + else + src = rotate(m_left_IV,7-SRC_LSB); + mask = ((1 << rotlen)-1); + dst = src & mask; + set_reg(DST,dst); + } + else if(!(is_src_reg(opcode)) && !(is_dst_reg(opcode))) + { // MOVE IV,IV + SRC_LATCH; + if(SRC_IS_RIGHT_BANK) + src = rotate(m_right_IV,7-SRC_LSB); + else + src = rotate(m_left_IV,7-SRC_LSB); + mask = ((1 << rotlen)-1); + dst = src & mask; + dst <<= (7-DST_LSB); + mask <<= (7-DST_LSB); + if(SRC_IS_RIGHT_BANK) // untouched source IV bits are preserved and sent to destination IV + { + dst = (m_right_IV & ~mask) | (dst & mask); + m_right_IV = dst; + WRITEPORT(m_IVR+0x100,m_right_IV); + } + else + { + dst = (m_left_IV & ~mask) | (dst & mask); + m_left_IV = dst; + WRITEPORT(m_IVL,m_left_IV); + } + } + } + break; + case 0x01: // ADD + rotlen = ROTLEN; + if(is_rot(opcode)) + { // ADD reg,reg + src = rotate(get_reg(SRC),rotlen); + result = src + m_AUX; + set_reg(DST,result & 0xff); + SET_OVF; + } + else + { + if(rotlen == 0) + rotlen = 8; // 0 = 8-bit I/O field length + if(is_src_reg(opcode) && !(is_dst_reg(opcode))) + { // ADD reg,IV + DST_LATCH; + result = get_reg(SRC) + m_AUX; + mask = ((1 << rotlen)-1); + dst = (result & 0xff) << DST_LSB; + mask <<= DST_LSB; + SET_OVF; + if(DST_IS_RIGHT_BANK) + { + dst = (m_right_IV & ~mask) | (dst & mask); + m_right_IV = dst; + WRITEPORT(m_IVR+0x100,m_right_IV); + } + else + { + dst = (m_left_IV & ~mask) | (dst & mask); + m_left_IV = dst; + WRITEPORT(m_IVL,m_left_IV); + } + } + else if(!(is_src_reg(opcode)) && is_dst_reg(opcode)) + { // ADD IV,reg + SRC_LATCH; + mask = ((1 << rotlen)-1); + if(SRC_IS_RIGHT_BANK) + src = rotate(m_right_IV,7-SRC_LSB) & mask; + else + src = rotate(m_left_IV,7-SRC_LSB) & mask; + result = src + m_AUX; + SET_OVF; + set_reg(DST,result & 0xff); + } + else if(!(is_src_reg(opcode)) && !(is_dst_reg(opcode))) + { // ADD IV,IV + SRC_LATCH; + DST_LATCH; + mask = ((1 << rotlen)-1); + if(SRC_IS_RIGHT_BANK) + src = rotate(m_right_IV,7-SRC_LSB) & mask; + else + src = rotate(m_left_IV,7-SRC_LSB) & mask; + result = src + m_AUX; + SET_OVF; + dst = (result << (7-DST_LSB)) & 0xff; + mask <<= (7-DST_LSB); + if(SRC_IS_RIGHT_BANK) // unused destination IV data is not preserved, is merged with input IV data + { + dst = (m_right_IV & ~mask) | (dst & mask); + m_right_IV = dst; + WRITEPORT(m_IVR+0x100,m_right_IV); + } + else + { + dst = (m_left_IV & ~mask) | (dst & mask); + m_left_IV = dst; + WRITEPORT(m_IVL,m_left_IV); + } + } + } + break; + case 0x02: // AND + rotlen = ROTLEN; + if(is_rot(opcode)) + { // AND reg,reg + src = rotate(get_reg(SRC),rotlen); + dst = src & m_AUX; + set_reg(DST,dst); + } + else + { + if(rotlen == 0) + rotlen = 8; // 0 = 8-bit I/O field length + if(is_src_reg(opcode) && !(is_dst_reg(opcode))) + { // AND reg,IV + DST_LATCH; + src = get_reg(SRC) & m_AUX; + mask = ((1 << rotlen)-1); + src <<= (7-DST_LSB); + mask <<= (7-DST_LSB); + if(DST_IS_RIGHT_BANK) + { + dst = (m_right_IV & ~mask) | (src & mask); + m_right_IV = dst; + WRITEPORT(m_IVR+0x100,m_right_IV); + } + else + { + dst = (m_left_IV & ~mask) | (src & mask); + m_left_IV = dst; + WRITEPORT(m_IVL,m_left_IV); + } + } + else if(!(is_src_reg(opcode)) && is_dst_reg(opcode)) + { // AND IV,reg + SRC_LATCH; + mask = ((1 << rotlen)-1); + if(SRC_IS_RIGHT_BANK) + src = rotate(m_right_IV,7-SRC_LSB) & mask; + else + src = rotate(m_left_IV,7-SRC_LSB) & mask; + src &= mask; + dst = src & m_AUX; + set_reg(DST,dst); + } + else if(!(is_src_reg(opcode)) && !(is_dst_reg(opcode))) + { // AND IV,IV + SRC_LATCH; + DST_LATCH; + mask = ((1 << rotlen)-1); + if(SRC_IS_RIGHT_BANK) + src = rotate(m_right_IV,7-SRC_LSB) & mask; + else + src = rotate(m_left_IV,7-SRC_LSB) & mask; + src &= mask; + dst = src & m_AUX; + dst <<= (7-DST_LSB); + mask <<= (7-DST_LSB); + if(SRC_IS_RIGHT_BANK) + { + dst = (m_right_IV & ~mask) | (src & mask); + m_right_IV = dst; + WRITEPORT(m_IVR+0x100,m_right_IV); + } + else + { + dst = (m_left_IV & ~mask) | (src & mask); + m_left_IV = dst; + WRITEPORT(m_IVL,m_left_IV); + } + } + } + break; + case 0x03: // XOR + rotlen = ROTLEN; + if(is_rot(opcode)) + { // AND reg,reg + src = rotate(get_reg(SRC),rotlen); + dst = src ^ m_AUX; + set_reg(DST,dst); + } + else + { + if(rotlen == 0) + rotlen = 8; // 0 = 8-bit I/O field length + if(is_src_reg(opcode) && !(is_dst_reg(opcode))) + { // AND reg,IV + DST_LATCH; + src = get_reg(SRC) ^ m_AUX; + mask = ((1 << rotlen)-1); + src <<= (7-DST_LSB); + mask <<= (7-DST_LSB); + if(DST_IS_RIGHT_BANK) + { + dst = (m_right_IV & ~mask) | (src & mask); + m_right_IV = dst; + WRITEPORT(m_IVR+0x100,m_right_IV); + } + else + { + dst = (m_left_IV & ~mask) | (src & mask); + m_left_IV = dst; + WRITEPORT(m_IVL,m_left_IV); + } + } + else if(!(is_src_reg(opcode)) && is_dst_reg(opcode)) + { // AND IV,reg + SRC_LATCH; + mask = ((1 << rotlen)-1); + if(SRC_IS_RIGHT_BANK) + src = rotate(m_right_IV,7-SRC_LSB) & mask; + else + src = rotate(m_left_IV,7-SRC_LSB) & mask; + src &= mask; + dst = src ^ m_AUX; + set_reg(DST,dst); + } + else if(!(is_src_reg(opcode)) && !(is_dst_reg(opcode))) + { // AND IV,IV + SRC_LATCH; + DST_LATCH; + mask = ((1 << rotlen)-1); + if(SRC_IS_RIGHT_BANK) + src = rotate(m_right_IV,7-SRC_LSB) & mask; + else + src = rotate(m_left_IV,7-SRC_LSB) & mask; + src &= mask; + dst = src ^ m_AUX; + dst <<= (7-DST_LSB); + mask <<= (7-DST_LSB); + if(SRC_IS_RIGHT_BANK) + { + dst = (m_right_IV & ~mask) | (src & mask); + m_right_IV = dst; + WRITEPORT(m_IVR+0x100,m_right_IV); + } + else + { + dst = (m_left_IV & ~mask) | (src & mask); + m_left_IV = dst; + WRITEPORT(m_IVL,m_left_IV); + } + } + } + break; + case 0x04: // XEC (Execute) + if(is_src_reg(opcode)) + { + src = get_reg(SRC); + src += IMM8; + SET_AR((m_AR & 0x1f00) | src); + } + else + { + SRC_LATCH; + rotlen = ROTLEN; + if(rotlen == 0) + rotlen = 8; // 0 = 8-bit I/O field length + mask = ((1 << rotlen)-1); + if(SRC_IS_RIGHT_BANK) + src = rotate(m_right_IV,7-SRC_LSB); + else + src = rotate(m_left_IV,7-SRC_LSB); + src &= mask; + src += IMM5; + SET_AR((m_AR & 0x1fe0) | (src & 0x1f)); + } + break; + case 0x05: // NZT (Non-zero transfer) + if(is_src_reg(opcode)) + { + src = get_reg(SRC); + if(src != 0) + SET_PC((m_PC & 0x1f00) | IMM8); + } + else + { + SRC_LATCH; + rotlen = ROTLEN; + if(rotlen == 0) + rotlen = 8; // 0 = 8-bit I/O field length + mask = ((1 << rotlen)-1); + if(SRC_IS_RIGHT_BANK) + src = rotate(m_right_IV,7-SRC_LSB); + else + src = rotate(m_left_IV,7-SRC_LSB); + rotate(src,SRC_LSB); + src &= mask; + if(src != 0) + SET_PC((m_PC & 0x1fe0) | IMM5); + } + break; + case 0x06: // XMIT (Transmit) + // the source is actually the destination for this instruction + if(is_src_reg(opcode)) + set_reg(SRC,IMM8); + else + { + SRC_LATCH; + rotlen = ROTLEN; + if(rotlen == 0) + rotlen = 8; // 0 = 8-bit I/O field length + mask = ((1 << rotlen)-1); + dst = IMM5; + mask <<= (7-SRC_LSB); + dst <<= (7-SRC_LSB); + if(SRC_IS_RIGHT_BANK) + { + m_right_IV = (m_right_IV & ~mask) | (dst & mask); + WRITEPORT(m_IVR+0x100,m_right_IV); + } + else + { + m_left_IV = (m_left_IV & ~mask) | (dst & mask); + WRITEPORT(m_IVL,m_left_IV); + } + } + break; + case 0x07: // JMP + SET_PC(ADDR); + break; + } + CYCLES(1); // all instructions take 1 cycle (250ns) + } while (m_icount > 0); +} + +offs_t n8x300_cpu_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( n8x300 ); + return CPU_DISASSEMBLE_NAME(n8x300)(this, buffer, pc, oprom, opram, options); +} diff --git a/src/devices/cpu/8x300/8x300.h b/src/devices/cpu/8x300/8x300.h new file mode 100644 index 00000000000..274f161c889 --- /dev/null +++ b/src/devices/cpu/8x300/8x300.h @@ -0,0 +1,136 @@ +// license:BSD-3-Clause +// copyright-holders:Barry Rodewald +/* + * 8x300.h + * + * Implementation of the Scientific Micro Systems SMS300 / Signetics 8X300 Microcontroller + * Created on: 18/12/2013 + */ + +#ifndef _8X300_H_ +#define _8X300_H_ + +// Register enumeration +enum +{ + _8X300_PC = 1, + _8X300_AR, + _8X300_IR, + _8X300_AUX, + _8X300_R1, + _8X300_R2, + _8X300_R3, + _8X300_R4, + _8X300_R5, + _8X300_R6, + _8X300_IVL, + _8X300_OVF, + _8X300_R11, + _8X300_UNUSED12, + _8X300_UNUSED13, + _8X300_UNUSED14, + _8X300_UNUSED15, + _8X300_UNUSED16, + _8X300_IVR, + _8X300_LIV, + _8X300_RIV, + _8X300_GENPC +}; + +class n8x300_cpu_device : public cpu_device +{ +public: + // construction/destruction + n8x300_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_execute_interface overrides + virtual UINT32 execute_min_cycles() const { return 1; } + virtual UINT32 execute_max_cycles() const { return 1; } + virtual UINT32 execute_input_lines() const { return 0; } + virtual void execute_run(); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const + { + switch (spacenum) + { + case AS_PROGRAM: return &m_program_config; + case AS_IO: return &m_io_config; + default: return NULL; + } + } + + // device_state_interface overrides + void state_string_export(const device_state_entry &entry, std::string &str); + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const { return 2; } + virtual UINT32 disasm_max_opcode_bytes() const { return 2; } + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + + address_space_config m_program_config; + address_space_config m_io_config; + + int m_icount; + + address_space *m_program; + direct_read_data *m_direct; + address_space *m_io; + + UINT16 m_PC; // Program Counter + UINT16 m_AR; // Address Register + UINT16 m_IR; // Instruction Register + UINT8 m_AUX; // Auxiliary Register (second operand for AND, ADD, XOR) + UINT8 m_R1; + UINT8 m_R2; + UINT8 m_R3; + UINT8 m_R4; + UINT8 m_R5; + UINT8 m_R6; + UINT8 m_R11; + UINT8 m_IVL; // Interface vector (I/O) left bank (write-only) + UINT8 m_IVR; // Interface vector (I/O) right bank (write-only) + UINT8 m_OVF; // Overflow register (read-only) + UINT16 m_genPC; + + UINT8 m_left_IV; // IV bank contents, these are latched when IVL or IVR are set + UINT8 m_right_IV; + +private: + inline bool is_rot(UINT16 opcode) + { + if((opcode & 0x1000) || (opcode & 0x0010)) + return false; + else + return true; + } + inline bool is_src_reg(UINT16 opcode) + { + if((opcode & 0x1000)) + return false; + else + return true; + } + inline bool is_dst_reg(UINT16 opcode) + { + if((opcode & 0x0010)) + return false; + else + return true; + } + inline UINT8 rotate(UINT8 s, UINT8 n) // right rotate + { + return ((s & ((UINT8)0xff << n)) >> n) | ((s & ((UINT8)0xff >> (8-n))) << (8-n)); + } + void set_reg(UINT8 reg,UINT8 val); + UINT8 get_reg(UINT8 reg); +}; + +extern const device_type N8X300; + +#endif /* 8X300_H_ */ diff --git a/src/devices/cpu/8x300/8x300dasm.c b/src/devices/cpu/8x300/8x300dasm.c new file mode 100644 index 00000000000..e35b2b7cb41 --- /dev/null +++ b/src/devices/cpu/8x300/8x300dasm.c @@ -0,0 +1,151 @@ +// license:BSD-3-Clause +// copyright-holders:Barry Rodewald +/* + * 8x300dasm.c + * Implementation of the Scientific Micro Systems SMS300 / Signetics 8X300 Microcontroller + * + * Created on: 18/12/2013 + */ + +#include "emu.h" +#include "8x300.h" + +#define SRC ((opcode & 0x1f00) >> 8) +#define DST (opcode & 0x001f) +#define ROTLEN ((opcode & 0x00e0) >> 5) +#define IMM8 (opcode & 0x00ff) +#define IMM5 (opcode & 0x001f) + +static const char *reg_names[32] = +{ + "AUX", "R1", "R2", "R3", "R4", "R5", "R6", "IVL", "OVF", "R11", + "Unused12", "Unused13", "Unused14", "Unused15", "Unused16", "IVR", + "LIV0", "LIV1", "LIV2", "LIV3", "LIV4", "LIV5", "LIV6", "LIV7", + "RIV0", "RIV1", "RIV2", "RIV3", "RIV4", "RIV5", "RIV6", "RIV7" +}; + +// determines if right rotate or I/O field length is to be used +INLINE bool is_rot(UINT16 opcode) +{ + if((opcode & 0x1000) || (opcode & 0x0010)) + return false; + else + return true; +} + +INLINE bool is_src_rot(UINT16 opcode) +{ + if((opcode & 0x1000)) + return false; + else + return true; +} + +CPU_DISASSEMBLE( n8x300 ) +{ + char tmp[16]; + unsigned startpc = pc; + UINT16 opcode = (oprom[pc - startpc] << 8) | oprom[pc+1 - startpc]; + UINT8 inst = opcode >> 13; + pc+=2; + + // determine instruction + switch (inst) + { + case 0x00: + sprintf(buffer,"MOVE "); + strcat(buffer,reg_names[SRC]); + if(is_rot(opcode)) + sprintf(tmp,"(%i),",ROTLEN); + else + sprintf(tmp,",%i,",ROTLEN); + strcat(buffer,tmp); + strcat(buffer,reg_names[DST]); + break; + case 0x01: + sprintf(buffer,"ADD "); + strcat(buffer,reg_names[SRC]); + if(is_rot(opcode)) + sprintf(tmp,"(%i),",ROTLEN); + else + sprintf(tmp,",%i,",ROTLEN); + strcat(buffer,tmp); + strcat(buffer,reg_names[DST]); + break; + case 0x02: + sprintf(buffer,"AND "); + strcat(buffer,reg_names[SRC]); + if(is_rot(opcode)) + sprintf(tmp,"(%i),",ROTLEN); + else + sprintf(tmp,",%i,",ROTLEN); + strcat(buffer,tmp); + strcat(buffer,reg_names[DST]); + break; + case 0x03: + sprintf(buffer,"XOR "); + strcat(buffer,reg_names[SRC]); + if(is_rot(opcode)) + sprintf(tmp,"(%i),",ROTLEN); + else + sprintf(tmp,",%i,",ROTLEN); + strcat(buffer,tmp); + strcat(buffer,reg_names[DST]); + break; + case 0x04: + sprintf(buffer,"XEC "); + strcat(buffer,reg_names[SRC]); + if(is_src_rot(opcode)) + { + sprintf(tmp,",%02XH",IMM8); + strcat(buffer,tmp); + } + else + { + sprintf(tmp,",%i",ROTLEN); + strcat(buffer,tmp); + sprintf(tmp,",%02XH",IMM5); + strcat(buffer,tmp); + } + break; + case 0x05: + sprintf(buffer,"NZT "); + strcat(buffer,reg_names[SRC]); + if(is_src_rot(opcode)) + { + sprintf(tmp,",%02XH",IMM8); + strcat(buffer,tmp); + } + else + { + sprintf(tmp,",%i",ROTLEN); + strcat(buffer,tmp); + sprintf(tmp,",%02XH",IMM5); + strcat(buffer,tmp); + } + break; + case 0x06: + sprintf(buffer,"XMIT "); + if(is_src_rot(opcode)) + { + sprintf(tmp,"%02XH,",IMM8); + strcat(buffer,tmp); + strcat(buffer,reg_names[SRC]); + } + else + { + sprintf(tmp,"%02XH,",IMM5); + strcat(buffer,tmp); + strcat(buffer,reg_names[SRC]); + sprintf(tmp,",%i",ROTLEN); + strcat(buffer,tmp); + } + break; + case 0x07: + sprintf(buffer,"JMP %04XH",opcode & 0x1fff); + break; + } + + + return (pc - startpc); +} diff --git a/src/devices/cpu/adsp2100/2100dasm.c b/src/devices/cpu/adsp2100/2100dasm.c new file mode 100644 index 00000000000..47d8ad8e800 --- /dev/null +++ b/src/devices/cpu/adsp2100/2100dasm.c @@ -0,0 +1,553 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +#include "emu.h" +#include "adsp2100.h" + +static const char *const flag_change[] = { "", "TOGGLE %s ", "RESET %s ", "SET %s " }; +static const char *const mode_change[] = { "", "", "DIS %s ", "ENA %s " }; + +static const char *const alu_xop[] = { "AX0", "AX1", "AR", "MR0", "MR1", "MR2", "SR0", "SR1" }; +static const char *const alu_yop[] = { "AY0", "AY1", "AF", "0" }; +static const char *const alu_dst[] = { "AR", "AF", "NONE" }; + +static const char *const mac_xop[] = { "MX0", "MX1", "AR", "MR0", "MR1", "MR2", "SR0", "SR1" }; +static const char *const mac_yop[] = { "MY0", "MY1", "MF", "0" }; +static const char *const mac_dst[] = { "MR", "MF", "NONE" }; + +static const char *const shift_xop[] = { "SI", "??", "AR", "MR0", "MR1", "MR2", "SR0", "SR1" }; + +static const char *const reg_grp[][16] = +{ + { "AX0", "AX1", "MX0", "MX1", "AY0", "AY1", "MY0", "MY1", "SI", "SE", "AR", "MR0", "MR1", "MR2", "SR0", "SR1" }, + { "I0", "I1", "I2", "I3", "M0", "M1", "M2", "M3", "L0", "L1", "L2", "L3", "??", "??", "??", "??" }, + { "I4", "I5", "I6", "I7", "M4", "M5", "M6", "M7", "L4", "L5", "L6", "L7", "??", "??", "??", "??" }, + { "ASTAT", "MSTAT", "SSTAT", "IMASK", "ICNTL", "CNTR", "SB", "PX", "RX0", "TX0", "RX1", "TX1", "IFC", "OWRCNTR", "??", "??" } +}; +static const char *const dual_xreg[] = { "AX0", "AX1", "MX0", "MX1" }; +static const char *const dual_yreg[] = { "AY0", "AY1", "MY0", "MY1" }; + +static const char *const condition[] = +{ + "IF EQ ", + "IF NE ", + "IF GT ", + "IF LE ", + "IF LT ", + "IF GE ", + "IF AV ", + "IF NOT AV ", + "IF AC ", + "IF NOT AC ", + "IF NEG ", + "IF POS ", + "IF MV ", + "IF NOT MV ", + "IF NOT CE ", + "" +}; + +static const char *const do_condition[] = +{ + "NE", + "EQ", + "LE", + "GT", + "GE", + "LT", + "NOT AV", + "AV", + "NOT AC", + "AC", + "POS", + "NEG", + "NOT MV", + "MV", + "CE", + "FOREVER" +}; + +static const char *const alumac_op[][2] = +{ + { "", "" }, + { "%s = %s * %s (RND)", "%s = %s * %s (RND)" }, + { "%s = MR + %s * %s (RND)", "%s = MR + %s * %s (RND)" }, + { "%s = MR - %s * %s (RND)", "%s = MR - %s * %s (RND)" }, + { "%s = %s * %s (SS)", "%s = 0" }, + { "%s = %s * %s (SU)", "%s = %s * %s (SU)" }, + { "%s = %s * %s (US)", "%s = %s * %s (US)" }, + { "%s = %s * %s (UU)", "%s = %s * %s (UU)" }, + { "%s = MR + %s * %s (SS)", "%s = MR + %s * %s (SS)" }, + { "%s = MR + %s * %s (SU)", "%s = MR + %s * %s (SU)" }, + { "%s = MR + %s * %s (US)", "%s = MR + %s * %s (US)" }, + { "%s = MR + %s * %s (UU)", "%s = MR + %s * %s (UU)" }, + { "%s = MR - %s * %s (SS)", "%s = MR - %s * %s (SS)" }, + { "%s = MR - %s * %s (SS)", "%s = MR - %s * %s (SS)" }, + { "%s = MR - %s * %s (US)", "%s = MR - %s * %s (US)" }, + { "%s = MR - %s * %s (UU)", "%s = MR - %s * %s (UU)" }, + + { "!%s = %s", "%s = 0" }, + { "!%s = %s + 1", "%s = 1" }, + { "%s = %s + %s + C", "%s = %s + %s + C" }, + { "%s = %s + %s", "%s = %s" }, + { "!%s = NOT %s", "!%s = NOT %s" }, + { "!%s = -%s", "!%s = -%s" }, + { "%s = %s - %s + C - 1", "%s = %s + C - 1" }, + { "%s = %s - %s", "%s = %s - %s" }, + { "!%s = %s - 1", "%s = -1" }, + { "!%s = %s - %s", "%s = -%s" }, + { "!%s = %s - %s + C - 1", "%s = -%s + C - 1" }, + { "%s = NOT %s", "%s = NOT %s" }, + { "%s = %s AND %s", "%s = %s AND %s" }, + { "%s = %s OR %s", "%s = %s OR %s" }, + { "%s = %s XOR %s", "%s = %s XOR %s" }, + { "%s = ABS %s", "%s = ABS %s" } +}; + +static const char *const shift_op[] = +{ + "SR = LSHIFT %s (HI)", + "SR = SR OR LSHIFT %s (HI)", + "SR = LSHIFT %s (LO)", + "SR = SR OR LSHIFT %s (LO)", + "SR = ASHIFT %s (HI)", + "SR = SR OR ASHIFT %s (HI)", + "SR = ASHIFT %s (LO)", + "SR = SR OR ASHIFT %s (LO)", + "SR = NORM %s (HI)", + "SR = SR OR NORM %s (HI)", + "SR = NORM %s (LO)", + "SR = SR OR NORM %s (LO)", + "SE = EXP %s (HI)", + "SE = EXP %s (HIX)", + "SE = EXP %s (LO)", + "SB = EXPADJ %s", +}; + +static const char *const shift_by_op[] = +{ + "SR = LSHIFT %s BY %d (HI)", + "SR = SR OR LSHIFT %s BY %d (HI)", + "SR = LSHIFT %s BY %d (LO)", + "SR = SR OR LSHIFT %s BY %d (LO)", + "SR = ASHIFT %s BY %d (HI)", + "SR = SR OR ASHIFT %s BY %d (HI)", + "SR = ASHIFT %s BY %d (LO)", + "SR = SR OR ASHIFT %s BY %d (LO)", + "???", + "???", + "???", + "???", + "???", + "???", + "???", + "???" +}; + +static const char *const constants[] = +{ + "$0001", + "$FFFE", + "$0002", + "$FFFD", + "$0004", + "$FFFB", + "$0008", + "$FFF7", + "$0010", + "$FFEF", + "$0020", + "$FFDF", + "$0040", + "$FFBF", + "$0080", + "$FF7F", + "$0100", + "$FEFF", + "$0200", + "$FDFF", + "$0400", + "$FBFF", + "$0800", + "$F7FF", + "$1000", + "$EFFF", + "$2000", + "$DFFF", + "$4000", + "$BFFF", + "$8000", + "$7FFF" +}; + + + + +static int alumac(char *buffer, int dest, int op) +{ + int opindex = (op >> 13) & 31; + const char *xop, *yop, *dst, *opstring; + + if (opindex & 16) + { + xop = alu_xop[(op >> 8) & 7]; + yop = alu_yop[(op >> 11) & 3]; + dst = alu_dst[dest]; + } + else + { + xop = mac_xop[(op >> 8) & 7]; + yop = mac_yop[(op >> 11) & 3]; + dst = mac_dst[dest]; + } + opstring = alumac_op[opindex][((op >> 11) & 3) == 3]; + if (opstring[0] == '!') + return sprintf(buffer, opstring + 1, dst, yop, xop); + else + return sprintf(buffer, opstring, dst, xop, yop); +} + + +static int aluconst(char *buffer, int dest, int op) +{ + int opindex = (op >> 13) & 31; + const char *xop, *dst, *cval, *opstring; + + if (opindex & 16) + { + xop = alu_xop[(op >> 8) & 7]; + cval = constants[((op >> 5) & 0x07) | ((op >> 8) & 0x18)]; + dst = alu_dst[dest]; + } + else + { + xop = mac_xop[(op >> 8) & 7]; + cval = xop; + dst = mac_dst[dest]; + } + opstring = alumac_op[opindex][((op >> 11) & 3) == 3]; + if (opstring[0] == '!') + return sprintf(buffer, opstring + 1, dst, cval, xop); + else + return sprintf(buffer, opstring, dst, xop, cval); +} + + +/* execute instructions on this CPU until icount expires */ +CPU_DISASSEMBLE( adsp21xx ) +{ + unsigned int op = oprom[0] | (oprom[1] << 8) | (oprom[2] << 16); + unsigned dasmflags = 0; + int temp; + + switch ((op >> 16) & 0xff) + { + case 0x00: + /* 00000000 00000000 00000000 NOP */ + sprintf(buffer, "%s", "NOP"); + break; + case 0x01: + /* 00000000 0xxxxxxx xxxxxxxx dst = IO(x) */ + /* 00000000 1xxxxxxx xxxxxxxx IO(x) = dst */ + /* ADSP-218x only */ + if ((op & 0x008000) == 0x000000) + buffer += sprintf(buffer, "%s = IO($%X)", reg_grp[0][op & 15], (op >> 4) & 0x7ff); + else + buffer += sprintf(buffer, "IO($%X) = %s", (op >> 4) & 0x7ff, reg_grp[0][op & 15]); + break; + case 0x02: + /* 00000010 0000xxxx xxxxxxxx modify flag out */ + if ((op & 0x00f000) == 0x000000) + { + buffer += sprintf(buffer, "%s", condition[op & 15]); + buffer += sprintf(buffer, flag_change[(op >> 4) & 3], "FLAG_OUT"); + buffer += sprintf(buffer, flag_change[(op >> 6) & 3], "FL0"); + buffer += sprintf(buffer, flag_change[(op >> 8) & 3], "FL1"); + buffer += sprintf(buffer, flag_change[(op >> 10) & 3], "FL2"); + } + /* 00000010 10000000 00000000 idle */ + /* 00000010 10000000 0000xxxx idle (n) */ + else if ((op & 0x00fff0) == 0x008000) + { + } + else + buffer += sprintf(buffer, "??? (%06X)", op); + break; + case 0x03: + /* 00000011 xxxxxxxx xxxxxxxx call or jump on flag in */ + if (op & 2) + buffer += sprintf(buffer, "%s", "IF FLAG_IN "); + else + buffer += sprintf(buffer, "%s", "IF NOT FLAG_IN "); + if (op & 1) + { + buffer += sprintf(buffer, "%s", "CALL "); + dasmflags = DASMFLAG_STEP_OVER; + } + else + buffer += sprintf(buffer, "%s", "JUMP "); + temp = ((op >> 4) & 0x0fff) | ((op << 10) & 0x3000); + buffer += sprintf(buffer, "$%04X", temp); + break; + case 0x04: + /* 00000100 00000000 000xxxxx stack control */ + if ((op & 0x00ffe0) == 0x000000) + { + if (op & 0x000010) + { + buffer += sprintf(buffer, "%s", "POP PC "); + dasmflags = DASMFLAG_STEP_OUT; + } + if (op & 0x000008) buffer += sprintf(buffer, "%s", "POP LOOP "); + if (op & 0x000004) buffer += sprintf(buffer, "%s", "POP CNTR "); + if ((op & 0x000003) == 0x000002) buffer += sprintf(buffer, "%s", "PUSH STAT "); + else if ((op & 0x000003) == 0x000003) buffer += sprintf(buffer, "%s", "POP STAT "); + } + else + buffer += sprintf(buffer, "??? (%06X)", op); + break; + case 0x05: + /* 00000101 00000000 00000000 saturate MR */ + if ((op & 0x00ffff) == 0x000000) + buffer += sprintf(buffer, "%s", "IF MV SAT MR"); + else + buffer += sprintf(buffer, "??? (%06X)", op); + break; + case 0x06: + /* 00000110 000xxxxx 00000000 DIVS */ + if ((op & 0x00e0ff) == 0x000000) + buffer += sprintf(buffer, "DIVS %s,%s", alu_yop[(op >> 11) & 3], alu_xop[(op >> 8) & 7]); + else + buffer += sprintf(buffer, "??? (%06X)", op); + break; + case 0x07: + /* 00000111 00010xxx 00000000 DIVQ */ + if ((op & 0x00f8ff) == 0x001000) + buffer += sprintf(buffer, "DIVQ %s", alu_xop[(op >> 8) & 7]); + else + buffer += sprintf(buffer, "??? (%06X)", op); + break; + case 0x08: + /* 00001000 00000000 0000xxxx reserved */ + buffer += sprintf(buffer, "??? (%06X)", op); + break; + case 0x09: + /* 00001001 00000000 000xxxxx modify address register */ + if ((op & 0x00ffe0) == 0x000000) + { + temp = (op >> 2) & 4; + buffer += sprintf(buffer, "MODIFY (I%d,M%d)", temp + ((op >> 2) & 3), temp + (op & 3)); + } + else + buffer += sprintf(buffer, "??? (%06X)", op); + break; + case 0x0a: + /* 00001010 00000000 0000xxxx conditional return */ + if ((op & 0x00ffe0) == 0x000000) + { + buffer += sprintf(buffer, "%s", condition[op & 15]); + if (op & 0x000010) + buffer += sprintf(buffer, "%s", "RTI"); + else + buffer += sprintf(buffer, "%s", "RTS"); + dasmflags = DASMFLAG_STEP_OUT; + } + else + buffer += sprintf(buffer, "??? (%06X)", op); + break; + case 0x0b: + /* 00001011 00000000 xx00xxxx conditional jump (indirect address) */ + if ((op & 0x00ff00) == 0x000000) + { + buffer += sprintf(buffer, "%s", condition[op & 15]); + if (op & 0x000010) + { + buffer += sprintf(buffer, "CALL (I%d)", 4 + ((op >> 6) & 3)); + dasmflags = DASMFLAG_STEP_OVER; + } + else + buffer += sprintf(buffer, "JUMP (I%d)", 4 + ((op >> 6) & 3)); + } + else + buffer += sprintf(buffer, "??? (%06X)", op); + break; + case 0x0c: + /* 00001100 xxxxxxxx xxxxxxxx mode control */ + buffer += sprintf(buffer, mode_change[(op >> 4) & 3], "SEC_REG"); + buffer += sprintf(buffer, mode_change[(op >> 6) & 3], "BIT_REV"); + buffer += sprintf(buffer, mode_change[(op >> 8) & 3], "AV_LATCH"); + buffer += sprintf(buffer, mode_change[(op >> 10) & 3], "AR_SAT"); + buffer += sprintf(buffer, mode_change[(op >> 12) & 3], "M_MODE"); + buffer += sprintf(buffer, mode_change[(op >> 14) & 3], "TIMER"); + buffer += sprintf(buffer, mode_change[(op >> 2) & 3], "G_MODE"); + break; + case 0x0d: + /* 00001101 0000xxxx xxxxxxxx internal data move */ + if ((op & 0x00f000) == 0x000000) + buffer += sprintf(buffer, "%s = %s", reg_grp[(op >> 10) & 3][(op >> 4) & 15], reg_grp[(op >> 8) & 3][op & 15]); + else + buffer += sprintf(buffer, "??? (%06X)", op); + break; + case 0x0e: + /* 00001110 0xxxxxxx xxxxxxxx conditional shift */ + if ((op & 0x0080f0) == 0x000000) + { + buffer += sprintf(buffer, "%s", condition[op & 15]); + buffer += sprintf(buffer, shift_op[(op >> 11) & 15], shift_xop[(op >> 8) & 7]); + } + else + buffer += sprintf(buffer, "??? (%06X)", op); + break; + case 0x0f: + /* 00001111 0xxxxxxx xxxxxxxx shift immediate */ + if ((op & 0x008000) == 0x000000) + buffer += sprintf(buffer, shift_by_op[(op >> 11) & 15], shift_xop[(op >> 8) & 7], (signed char)op); + else + buffer += sprintf(buffer, "??? (%06X)", op); + break; + case 0x10: + /* 00010000 0xxxxxxx xxxxxxxx shift with internal data register move */ + if ((op & 0x008000) == 0x000000) + { + buffer += sprintf(buffer, shift_op[(op >> 11) & 15], shift_xop[(op >> 8) & 7]); + buffer += sprintf(buffer, ", %s = %s", reg_grp[0][(op >> 4) & 15], reg_grp[0][op & 15]); + } + else + buffer += sprintf(buffer, "??? (%06X)", op); + break; + case 0x11: + /* 00010001 0xxxxxxx xxxxxxxx shift with pgm memory read/write */ + buffer += sprintf(buffer, shift_op[(op >> 11) & 15], shift_xop[(op >> 8) & 7]); + if (op & 0x008000) + buffer += sprintf(buffer, ", PM(I%d,M%d) = %s", 4 + ((op >> 2) & 3), 4 + (op & 3), reg_grp[0][(op >> 4) & 15]); + else + buffer += sprintf(buffer, ", %s = PM(I%d,M%d)", reg_grp[0][(op >> 4) & 15], 4 + ((op >> 2) & 3), 4 + (op & 3)); + break; + case 0x12: case 0x13: + /* 0001001x 0xxxxxxx xxxxxxxx shift with data memory read/write */ + buffer += sprintf(buffer, shift_op[(op >> 11) & 15], shift_xop[(op >> 8) & 7]); + temp = (op >> 14) & 4; + if (op & 0x008000) + buffer += sprintf(buffer, ", DM(I%d,M%d) = %s", temp + ((op >> 2) & 3), temp + (op & 3), reg_grp[0][(op >> 4) & 15]); + else + buffer += sprintf(buffer, ", %s = DM(I%d,M%d)", reg_grp[0][(op >> 4) & 15], temp + ((op >> 2) & 3), temp + (op & 3)); + break; + case 0x14: case 0x15: case 0x16: case 0x17: + /* 000101xx xxxxxxxx xxxxxxxx do until */ + buffer += sprintf(buffer, "DO $%04X UNTIL %s", (op >> 4) & 0x3fff, do_condition[op & 15]); + break; + case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f: + /* 00011xxx xxxxxxxx xxxxxxxx conditional jump (immediate addr) */ + if (op & 0x040000) + { + buffer += sprintf(buffer, "%sCALL $%04X", condition[op & 15], (op >> 4) & 0x3fff); + dasmflags = DASMFLAG_STEP_OVER; + } + else + buffer += sprintf(buffer, "%sJUMP $%04X", condition[op & 15], (op >> 4) & 0x3fff); + break; + case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27: + /* 00100xxx xxxxxxxx xxxxxxxx conditional ALU/MAC */ + buffer += sprintf(buffer, "%s", condition[op & 15]); + if (!(op & 0x10)) + buffer += alumac(buffer, (op >> 18) & 1, op); + else + { + /* ADSP-218x only */ + buffer += aluconst(buffer, (op >> 18) & 1, op); + } + break; + case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: case 0x2f: + /* 00101xxx xxxxxxxx xxxxxxxx ALU/MAC with internal data register move */ + if ((op & 0x0600ff) == 0x0200aa) + { + /* ADSP-218x only */ + buffer += alumac(buffer, 2, op); + } + else + { + if ((op & 0x03e000) != 0) + { + buffer += alumac(buffer, (op >> 18) & 1, op); + buffer += sprintf(buffer, ", "); + } + buffer += sprintf(buffer, "%s = %s", reg_grp[0][(op >> 4) & 15], reg_grp[0][op & 15]); + } + break; + case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37: + case 0x38: case 0x39: case 0x3a: case 0x3b: case 0x3c: case 0x3d: case 0x3e: case 0x3f: + /* 0011xxxx xxxxxxxx xxxxxxxx load non-data register immediate */ + buffer += sprintf(buffer, "%s = $%04X", reg_grp[(op >> 18) & 3][op & 15], (op >> 4) & 0x3fff); + break; + case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: case 0x46: case 0x47: + case 0x48: case 0x49: case 0x4a: case 0x4b: case 0x4c: case 0x4d: case 0x4e: case 0x4f: + /* 0100xxxx xxxxxxxx xxxxxxxx load data register immediate */ + buffer += sprintf(buffer, "%s = $%04X", reg_grp[0][op & 15], (op >> 4) & 0xffff); + break; + case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x55: case 0x56: case 0x57: + case 0x58: case 0x59: case 0x5a: case 0x5b: case 0x5c: case 0x5d: case 0x5e: case 0x5f: + /* 0101xxxx xxxxxxxx xxxxxxxx ALU/MAC with pgm memory read/write */ + if ((op & 0x03e000) != 0) + { + buffer += alumac(buffer, (op >> 18) & 1, op); + buffer += sprintf(buffer, ", "); + } + if (op & 0x080000) + buffer += sprintf(buffer, "PM(I%d,M%d) = %s", 4 + ((op >> 2) & 3), 4 + (op & 3), reg_grp[0][(op >> 4) & 15]); + else + buffer += sprintf(buffer, "%s = PM(I%d,M%d)", reg_grp[0][(op >> 4) & 15], 4 + ((op >> 2) & 3), 4 + (op & 3)); + break; + case 0x60: case 0x61: case 0x62: case 0x63: case 0x64: case 0x65: case 0x66: case 0x67: + case 0x68: case 0x69: case 0x6a: case 0x6b: case 0x6c: case 0x6d: case 0x6e: case 0x6f: + case 0x70: case 0x71: case 0x72: case 0x73: case 0x74: case 0x75: case 0x76: case 0x77: + case 0x78: case 0x79: case 0x7a: case 0x7b: case 0x7c: case 0x7d: case 0x7e: case 0x7f: + /* 011xxxxx xxxxxxxx xxxxxxxx ALU/MAC with data memory read/write */ + if ((op & 0x03e000) != 0) + { + buffer += alumac(buffer, (op >> 18) & 1, op); + buffer += sprintf(buffer, ", "); + } + temp = (op >> 18) & 4; + if (op & 0x080000) + buffer += sprintf(buffer, "DM(I%d,M%d) = %s", temp + ((op >> 2) & 3), temp + (op & 3), reg_grp[0][(op >> 4) & 15]); + else + buffer += sprintf(buffer, "%s = DM(I%d,M%d)", reg_grp[0][(op >> 4) & 15], temp + ((op >> 2) & 3), temp + (op & 3)); + break; + case 0x80: case 0x81: case 0x82: case 0x83: case 0x84: case 0x85: case 0x86: case 0x87: + case 0x88: case 0x89: case 0x8a: case 0x8b: case 0x8c: case 0x8d: case 0x8e: case 0x8f: + case 0x90: case 0x91: case 0x92: case 0x93: case 0x94: case 0x95: case 0x96: case 0x97: + case 0x98: case 0x99: case 0x9a: case 0x9b: case 0x9c: case 0x9d: case 0x9e: case 0x9f: + /* 100xxxxx xxxxxxxx xxxxxxxx read/write data memory (immediate addr) */ + if (op & 0x100000) + buffer += sprintf(buffer, "DM($%04X) = %s", (op >> 4) & 0x3fff, reg_grp[(op >> 18) & 3][op & 15]); + else + buffer += sprintf(buffer, "%s = DM($%04X)", reg_grp[(op >> 18) & 3][op & 15], (op >> 4) & 0x3fff); + break; + case 0xa0: case 0xa1: case 0xa2: case 0xa3: case 0xa4: case 0xa5: case 0xa6: case 0xa7: + case 0xa8: case 0xa9: case 0xaa: case 0xab: case 0xac: case 0xad: case 0xae: case 0xaf: + case 0xb0: case 0xb1: case 0xb2: case 0xb3: case 0xb4: case 0xb5: case 0xb6: case 0xb7: + case 0xb8: case 0xb9: case 0xba: case 0xbb: case 0xbc: case 0xbd: case 0xbe: case 0xbf: + /* 101xxxxx xxxxxxxx xxxxxxxx data memory write (immediate) */ + temp = (op >> 18) & 4; + buffer += sprintf(buffer, "DM(I%d,M%d) = $%04X", temp + ((op >> 2) & 3), temp + (op & 3), (op >> 4) & 0xffff); + break; + case 0xc0: case 0xc1: case 0xc2: case 0xc3: case 0xc4: case 0xc5: case 0xc6: case 0xc7: + case 0xc8: case 0xc9: case 0xca: case 0xcb: case 0xcc: case 0xcd: case 0xce: case 0xcf: + case 0xd0: case 0xd1: case 0xd2: case 0xd3: case 0xd4: case 0xd5: case 0xd6: case 0xd7: + case 0xd8: case 0xd9: case 0xda: case 0xdb: case 0xdc: case 0xdd: case 0xde: case 0xdf: + case 0xe0: case 0xe1: case 0xe2: case 0xe3: case 0xe4: case 0xe5: case 0xe6: case 0xe7: + case 0xe8: case 0xe9: case 0xea: case 0xeb: case 0xec: case 0xed: case 0xee: case 0xef: + case 0xf0: case 0xf1: case 0xf2: case 0xf3: case 0xf4: case 0xf5: case 0xf6: case 0xf7: + case 0xf8: case 0xf9: case 0xfa: case 0xfb: case 0xfc: case 0xfd: case 0xfe: case 0xff: + /* 11xxxxxx xxxxxxxx xxxxxxxx ALU/MAC with data & pgm memory read */ + if ((op & 0x03e000) != 0) + { + buffer += alumac(buffer, 0, op); + buffer += sprintf(buffer, ", "); + } + buffer += sprintf(buffer, "%s = DM(I%d,M%d), %s = PM(I%d,M%d)", dual_xreg[(op >> 18) & 3], (op >> 2) & 3, op & 3, + dual_yreg[(op >> 20) & 3], 4 + ((op >> 6) & 3), 4 + ((op >> 4) & 3)); + break; + } + + return 1 | dasmflags | DASMFLAG_SUPPORTED; +} diff --git a/src/devices/cpu/adsp2100/2100ops.inc b/src/devices/cpu/adsp2100/2100ops.inc new file mode 100644 index 00000000000..31cae1ae59b --- /dev/null +++ b/src/devices/cpu/adsp2100/2100ops.inc @@ -0,0 +1,2232 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*=========================================================================== + ASTAT -- ALU/MAC status register +===========================================================================*/ + +/* extracts flags */ +#define GET_SS (m_astat & SSFLAG) +#define GET_MV (m_astat & MVFLAG) +#define GET_Q (m_astat & QFLAG) +#define GET_S (m_astat & SFLAG) +#define GET_C (m_astat & CFLAG) +#define GET_V (m_astat & VFLAG) +#define GET_N (m_astat & NFLAG) +#define GET_Z (m_astat & ZFLAG) + +/* clears flags */ +#define CLR_SS (m_astat &= ~SSFLAG) +#define CLR_MV (m_astat &= ~MVFLAG) +#define CLR_Q (m_astat &= ~QFLAG) +#define CLR_S (m_astat &= ~SFLAG) +#define CLR_C (m_astat &= ~CFLAG) +#define CLR_V (m_astat &= ~VFLAG) +#define CLR_N (m_astat &= ~NFLAG) +#define CLR_Z (m_astat &= ~ZFLAG) + +/* sets flags */ +#define SET_SS (m_astat |= SSFLAG) +#define SET_MV (m_astat |= MVFLAG) +#define SET_Q (m_astat |= QFLAG) +#define SET_S (m_astat |= SFLAG) +#define SET_C (m_astat |= CFLAG) +#define SET_V (m_astat |= VFLAG) +#define SET_Z (m_astat |= ZFLAG) +#define SET_N (m_astat |= NFLAG) + +/* flag clearing; must be done before setting */ +#define CLR_FLAGS (m_astat &= m_astat_clear) + +/* compute flags */ +#define CALC_Z(r) (m_astat |= ((r & 0xffff) == 0)) +#define CALC_N(r) (m_astat |= (r >> 14) & 0x02) +#define CALC_V(s,d,r) (m_astat |= ((s ^ d ^ r ^ (r >> 1)) >> 13) & 0x04) +#define CALC_C(r) (m_astat |= (r >> 13) & 0x08) +#define CALC_C_SUB(r) (m_astat |= (~r >> 13) & 0x08) +#define CALC_NZ(r) CLR_FLAGS; CALC_N(r); CALC_Z(r) +#define CALC_NZV(s,d,r) CLR_FLAGS; CALC_N(r); CALC_Z(r); CALC_V(s,d,r) +#define CALC_NZVC(s,d,r) CLR_FLAGS; CALC_N(r); CALC_Z(r); CALC_V(s,d,r); CALC_C(r) +#define CALC_NZVC_SUB(s,d,r) CLR_FLAGS; CALC_N(r); CALC_Z(r); CALC_V(s,d,r); CALC_C_SUB(r) + +/* ADSP-218x constants */ +static const INT32 constants[] = +{ + 0x0001, 0xfffe, 0x0002, 0xfffd, 0x0004, 0xfffb, 0x0008, 0xfff7, + 0x0010, 0xffef, 0x0020, 0xffdf, 0x0040, 0xffbf, 0x0080, 0xff7f, + 0x0100, 0xfeff, 0x0200, 0xfdff, 0x0400, 0xfbff, 0x0800, 0xf7ff, + 0x1000, 0xefff, 0x2000, 0xdfff, 0x4000, 0xbfff, 0x8000, 0x7fff +}; + + + +/*=========================================================================== + MSTAT -- ALU/MAC control register +===========================================================================*/ + +/* flag definitions */ +#define MSTAT_BANK 0x01 /* register bank select */ +#define MSTAT_REVERSE 0x02 /* bit-reverse addressing enable (DAG1) */ +#define MSTAT_STICKYV 0x04 /* sticky ALU overflow enable */ +#define MSTAT_SATURATE 0x08 /* AR saturation mode enable */ +#define MSTAT_INTEGER 0x10 /* MAC result placement; 0=fractional, 1=integer */ +#define MSTAT_TIMER 0x20 /* timer enable */ +#define MSTAT_GOMODE 0x40 /* go mode enable */ + +/* you must call this in order to change MSTAT */ +inline void adsp21xx_device::update_mstat() +{ + if ((m_mstat ^ m_mstat_prev) & MSTAT_BANK) + { + adsp_core temp = m_core; + m_core = m_alt; + m_alt = temp; + } + if ((m_mstat ^ m_mstat_prev) & MSTAT_TIMER) + if (!m_timer_fired_cb.isnull()) + m_timer_fired_cb((m_mstat & MSTAT_TIMER) != 0); + if (m_mstat & MSTAT_STICKYV) + m_astat_clear = ~(CFLAG | NFLAG | ZFLAG); + else + m_astat_clear = ~(CFLAG | VFLAG | NFLAG | ZFLAG); + m_mstat_prev = m_mstat; +} + + +/*=========================================================================== + SSTAT -- stack status register +===========================================================================*/ + +/* flag definitions */ +#define PC_EMPTY 0x01 /* PC stack empty */ +#define PC_OVER 0x02 /* PC stack overflow */ +#define COUNT_EMPTY 0x04 /* count stack empty */ +#define COUNT_OVER 0x08 /* count stack overflow */ +#define STATUS_EMPTY 0x10 /* status stack empty */ +#define STATUS_OVER 0x20 /* status stack overflow */ +#define LOOP_EMPTY 0x40 /* loop stack empty */ +#define LOOP_OVER 0x80 /* loop stack overflow */ + + + +/*=========================================================================== + PC stack handlers +===========================================================================*/ + +inline UINT32 adsp21xx_device::pc_stack_top() +{ + if (m_pc_sp > 0) + return m_pc_stack[m_pc_sp - 1]; + else + return m_pc_stack[0]; +} + +inline void adsp21xx_device::set_pc_stack_top(UINT32 top) +{ + if (m_pc_sp > 0) + m_pc_stack[m_pc_sp - 1] = top; + else + m_pc_stack[0] = top; +} + +inline void adsp21xx_device::pc_stack_push() +{ + if (m_pc_sp < PC_STACK_DEPTH) + { + m_pc_stack[m_pc_sp] = m_pc; + m_pc_sp++; + m_sstat &= ~PC_EMPTY; + } + else + m_sstat |= PC_OVER; +} + +inline void adsp21xx_device::pc_stack_push_val(UINT32 val) +{ + if (m_pc_sp < PC_STACK_DEPTH) + { + m_pc_stack[m_pc_sp] = val; + m_pc_sp++; + m_sstat &= ~PC_EMPTY; + } + else + m_sstat |= PC_OVER; +} + +inline void adsp21xx_device::pc_stack_pop() +{ + if (m_pc_sp > 0) + { + m_pc_sp--; + if (m_pc_sp == 0) + m_sstat |= PC_EMPTY; + } + m_pc = m_pc_stack[m_pc_sp]; +} + +inline UINT32 adsp21xx_device::pc_stack_pop_val() +{ + if (m_pc_sp > 0) + { + m_pc_sp--; + if (m_pc_sp == 0) + m_sstat |= PC_EMPTY; + } + return m_pc_stack[m_pc_sp]; +} + + +/*=========================================================================== + CNTR stack handlers +===========================================================================*/ + +inline UINT32 adsp21xx_device::cntr_stack_top() +{ + if (m_cntr_sp > 0) + return m_cntr_stack[m_cntr_sp - 1]; + else + return m_cntr_stack[0]; +} + +inline void adsp21xx_device::cntr_stack_push() +{ + if (m_cntr_sp < CNTR_STACK_DEPTH) + { + m_cntr_stack[m_cntr_sp] = m_cntr; + m_cntr_sp++; + m_sstat &= ~COUNT_EMPTY; + } + else + m_sstat |= COUNT_OVER; +} + +inline void adsp21xx_device::cntr_stack_pop() +{ + if (m_cntr_sp > 0) + { + m_cntr_sp--; + if (m_cntr_sp == 0) + m_sstat |= COUNT_EMPTY; + } + m_cntr = m_cntr_stack[m_cntr_sp]; +} + + +/*=========================================================================== + LOOP stack handlers +===========================================================================*/ + +inline UINT32 adsp21xx_device::loop_stack_top() +{ + if (m_loop_sp > 0) + return m_loop_stack[m_loop_sp - 1]; + else + return m_loop_stack[0]; +} + +inline void adsp21xx_device::loop_stack_push(UINT32 value) +{ + if (m_loop_sp < LOOP_STACK_DEPTH) + { + m_loop_stack[m_loop_sp] = value; + m_loop_sp++; + m_loop = value >> 4; + m_loop_condition = value & 15; + m_sstat &= ~LOOP_EMPTY; + } + else + m_sstat |= LOOP_OVER; +} + +inline void adsp21xx_device::loop_stack_pop() +{ + if (m_loop_sp > 0) + { + m_loop_sp--; + if (m_loop_sp == 0) + { + m_loop = 0xffff; + m_loop_condition = 0; + m_sstat |= LOOP_EMPTY; + } + else + { + m_loop = m_loop_stack[m_loop_sp -1] >> 4; + m_loop_condition = m_loop_stack[m_loop_sp - 1] & 15; + } + } +} + + +/*=========================================================================== + STAT stack handlers +===========================================================================*/ + +inline void adsp21xx_device::stat_stack_push() +{ + if (m_stat_sp < STAT_STACK_DEPTH) + { + m_stat_stack[m_stat_sp][0] = m_mstat; + m_stat_stack[m_stat_sp][1] = m_imask; + m_stat_stack[m_stat_sp][2] = m_astat; + m_stat_sp++; + m_sstat &= ~STATUS_EMPTY; + } + else + m_sstat |= STATUS_OVER; +} + +inline void adsp21xx_device::stat_stack_pop() +{ + if (m_stat_sp > 0) + { + m_stat_sp--; + if (m_stat_sp == 0) + m_sstat |= STATUS_EMPTY; + } + m_mstat = m_stat_stack[m_stat_sp][0]; + update_mstat(); + m_imask = m_stat_stack[m_stat_sp][1]; + m_astat = m_stat_stack[m_stat_sp][2]; + check_irqs(); +} + + + +/*=========================================================================== + condition code checking +===========================================================================*/ + +// gcc doesn't want to inline this, so we use a macro +#define condition(c) (((c) != 14) ? (m_condition_table[((c) << 8) | m_astat]) : slow_condition()) + +/* +inline int adsp21xx_device::condition(int c) +{ + if (c != 14) + return m_condition_table[((c) << 8) | m_astat]; + else + return slow_condition(c); +} +*/ + +int adsp21xx_device::slow_condition() +{ + if ((INT32)--m_cntr > 0) + return 1; + else + { + cntr_stack_pop(); + return 0; + } +} + + + +/*=========================================================================== + register writing +===========================================================================*/ + +inline void adsp21xx_device::update_i(int which) +{ + m_base[which] = m_i[which] & m_lmask[which]; +} + +inline void adsp21xx_device::update_l(int which) +{ + m_lmask[which] = m_mask_table[m_l[which] & 0x3fff]; + m_base[which] = m_i[which] & m_lmask[which]; +} + +void adsp21xx_device::write_reg0(int regnum, INT32 val) +{ + switch (regnum) + { + case 0x00: m_core.ax0.s = val; break; + case 0x01: m_core.ax1.s = val; break; + case 0x02: m_core.mx0.s = val; break; + case 0x03: m_core.mx1.s = val; break; + case 0x04: m_core.ay0.s = val; break; + case 0x05: m_core.ay1.s = val; break; + case 0x06: m_core.my0.s = val; break; + case 0x07: m_core.my1.s = val; break; + case 0x08: m_core.si.s = val; break; + case 0x09: m_core.se.s = (INT8)val; break; + case 0x0a: m_core.ar.s = val; break; + case 0x0b: m_core.mr.mrx.mr0.s = val; break; + case 0x0c: m_core.mr.mrx.mr1.s = val; m_core.mr.mrx.mr2.s = (INT16)val >> 15; break; + case 0x0d: m_core.mr.mrx.mr2.s = (INT8)val; break; + case 0x0e: m_core.sr.srx.sr0.s = val; break; + case 0x0f: m_core.sr.srx.sr1.s = val; break; + } +} + +void adsp21xx_device::write_reg1(int regnum, INT32 val) +{ + int index = regnum & 3; + switch (regnum >> 2) + { + case 0: + m_i[index] = val & 0x3fff; + update_i(index); + break; + + case 1: + m_m[index] = (INT32)(val << 18) >> 18; + break; + + case 2: + m_l[index] = val & 0x3fff; + update_l(index); + break; + + case 3: + logerror("ADSP %04x: Writing to an invalid register!\n", m_ppc); + break; + } +} + +void adsp21xx_device::write_reg2(int regnum, INT32 val) +{ + int index = 4 + (regnum & 3); + switch (regnum >> 2) + { + case 0: + m_i[index] = val & 0x3fff; + update_i(index); + break; + + case 1: + m_m[index] = (INT32)(val << 18) >> 18; + break; + + case 2: + m_l[index] = val & 0x3fff; + update_l(index); + break; + + case 3: + logerror("ADSP %04x: Writing to an invalid register!\n", m_ppc); + break; + } +} + +void adsp21xx_device::write_reg3(int regnum, INT32 val) +{ + switch (regnum) + { + case 0x00: m_astat = val & 0x00ff; break; + case 0x01: m_mstat = val & m_mstat_mask; update_mstat(); break; + case 0x03: m_imask = val & m_imask_mask; check_irqs(); break; + case 0x04: m_icntl = val & 0x001f; check_irqs(); break; + case 0x05: cntr_stack_push(); m_cntr = val & 0x3fff; break; + case 0x06: m_core.sb.s = (INT32)(val << 27) >> 27; break; + case 0x07: m_px = val; break; + case 0x09: if (!m_sport_tx_cb.isnull()) m_sport_tx_cb(0, val, 0xffff); break; + case 0x0b: if (!m_sport_tx_cb.isnull()) m_sport_tx_cb(1, val, 0xffff); break; + case 0x0c: + m_ifc = val; + if (m_chip_type >= CHIP_TYPE_ADSP2181) + { + /* clear timer */ + if (val & 0x0002) m_irq_latch[ADSP2181_IRQ0] = 0; + if (val & 0x0004) m_irq_latch[ADSP2181_IRQ1] = 0; + /* clear BDMA */ + if (val & 0x0010) m_irq_latch[ADSP2181_IRQE] = 0; + if (val & 0x0020) m_irq_latch[ADSP2181_SPORT0_RX] = 0; + if (val & 0x0040) m_irq_latch[ADSP2181_SPORT0_TX] = 0; + if (val & 0x0080) m_irq_latch[ADSP2181_IRQ2] = 0; + /* force timer */ + if (val & 0x0200) m_irq_latch[ADSP2181_IRQ0] = 1; + if (val & 0x0400) m_irq_latch[ADSP2181_IRQ1] = 1; + /* force BDMA */ + if (val & 0x1000) m_irq_latch[ADSP2181_IRQE] = 1; + if (val & 0x2000) m_irq_latch[ADSP2181_SPORT0_RX] = 1; + if (val & 0x4000) m_irq_latch[ADSP2181_SPORT0_TX] = 1; + if (val & 0x8000) m_irq_latch[ADSP2181_IRQ2] = 1; + } + else + { + /* clear timer */ + if (val & 0x002) m_irq_latch[ADSP2101_IRQ0] = 0; + if (val & 0x004) m_irq_latch[ADSP2101_IRQ1] = 0; + if (val & 0x008) m_irq_latch[ADSP2101_SPORT0_RX] = 0; + if (val & 0x010) m_irq_latch[ADSP2101_SPORT0_TX] = 0; + if (val & 0x020) m_irq_latch[ADSP2101_IRQ2] = 0; + /* set timer */ + if (val & 0x080) m_irq_latch[ADSP2101_IRQ0] = 1; + if (val & 0x100) m_irq_latch[ADSP2101_IRQ1] = 1; + if (val & 0x200) m_irq_latch[ADSP2101_SPORT0_RX] = 1; + if (val & 0x400) m_irq_latch[ADSP2101_SPORT0_TX] = 1; + if (val & 0x800) m_irq_latch[ADSP2101_IRQ2] = 1; + } + check_irqs(); + break; + case 0x0d: m_cntr = val & 0x3fff; break; + case 0x0f: pc_stack_push_val(val & 0x3fff); break; + default: logerror("ADSP %04x: Writing to an invalid register!\n", m_ppc); break; + } +} + +#define WRITE_REG(adsp,grp,reg,val) ((this->*wr_reg[grp][reg])(val)) + + + +/*=========================================================================== + register reading +===========================================================================*/ + +INT32 adsp21xx_device::read_reg0(int regnum) +{ + return *m_read0_ptr[regnum]; +} + +INT32 adsp21xx_device::read_reg1(int regnum) +{ + return *m_read1_ptr[regnum]; +} + +INT32 adsp21xx_device::read_reg2(int regnum) +{ + return *m_read2_ptr[regnum]; +} + +INT32 adsp21xx_device::read_reg3(int regnum) +{ + switch (regnum) + { + case 0x00: return m_astat; + case 0x01: return m_mstat; + case 0x02: return m_sstat; + case 0x03: return m_imask; + case 0x04: return m_icntl; + case 0x05: return m_cntr; + case 0x06: return m_core.sb.s; + case 0x07: return m_px; + case 0x08: if (!m_sport_rx_cb.isnull()) return m_sport_rx_cb(0); else return 0; + case 0x0a: if (!m_sport_rx_cb.isnull()) return m_sport_rx_cb(1); else return 0; + case 0x0f: return pc_stack_pop_val(); + default: logerror("ADSP %04x: Reading from an invalid register!\n", m_ppc); return 0; + } +} + + + +/*=========================================================================== + Modulus addressing logic +===========================================================================*/ + +inline void adsp21xx_device::modify_address(UINT32 ireg, UINT32 mreg) +{ + UINT32 base = m_base[ireg]; + UINT32 i = m_i[ireg]; + UINT32 l = m_l[ireg]; + + i += m_m[mreg]; + if (i < base) i += l; + else if (i >= base + l) i -= l; + m_i[ireg] = i; +} + + + +/*=========================================================================== + Data memory accessors +===========================================================================*/ + +inline void adsp21xx_device::data_write_dag1(UINT32 op, INT32 val) +{ + UINT32 ireg = (op >> 2) & 3; + UINT32 mreg = op & 3; + UINT32 base = m_base[ireg]; + UINT32 i = m_i[ireg]; + UINT32 l = m_l[ireg]; + + if ( m_mstat & MSTAT_REVERSE ) + { + UINT32 ir = m_reverse_table[ i & 0x3fff ]; + data_write(ir, val); + } + else + data_write(i, val); + + i += m_m[mreg]; + if (i < base) i += l; + else if (i >= base + l) i -= l; + m_i[ireg] = i; +} + + +inline UINT32 adsp21xx_device::data_read_dag1(UINT32 op) +{ + UINT32 ireg = (op >> 2) & 3; + UINT32 mreg = op & 3; + UINT32 base = m_base[ireg]; + UINT32 i = m_i[ireg]; + UINT32 l = m_l[ireg]; + UINT32 res; + + if (m_mstat & MSTAT_REVERSE) + { + UINT32 ir = m_reverse_table[i & 0x3fff]; + res = data_read(ir); + } + else + res = data_read(i); + + i += m_m[mreg]; + if (i < base) i += l; + else if (i >= base + l) i -= l; + m_i[ireg] = i; + + return res; +} + +inline void adsp21xx_device::data_write_dag2(UINT32 op, INT32 val) +{ + UINT32 ireg = 4 + ((op >> 2) & 3); + UINT32 mreg = 4 + (op & 3); + UINT32 base = m_base[ireg]; + UINT32 i = m_i[ireg]; + UINT32 l = m_l[ireg]; + + data_write(i, val); + + i += m_m[mreg]; + if (i < base) i += l; + else if (i >= base + l) i -= l; + m_i[ireg] = i; +} + + +inline UINT32 adsp21xx_device::data_read_dag2(UINT32 op) +{ + UINT32 ireg = 4 + ((op >> 2) & 3); + UINT32 mreg = 4 + (op & 3); + UINT32 base = m_base[ireg]; + UINT32 i = m_i[ireg]; + UINT32 l = m_l[ireg]; + + UINT32 res = data_read(i); + + i += m_m[mreg]; + if (i < base) i += l; + else if (i >= base + l) i -= l; + m_i[ireg] = i; + + return res; +} + +/*=========================================================================== + Program memory accessors +===========================================================================*/ + +inline void adsp21xx_device::pgm_write_dag2(UINT32 op, INT32 val) +{ + UINT32 ireg = 4 + ((op >> 2) & 3); + UINT32 mreg = 4 + (op & 3); + UINT32 base = m_base[ireg]; + UINT32 i = m_i[ireg]; + UINT32 l = m_l[ireg]; + + program_write(i, (val << 8) | m_px); + + i += m_m[mreg]; + if (i < base) i += l; + else if (i >= base + l) i -= l; + m_i[ireg] = i; +} + + +inline UINT32 adsp21xx_device::pgm_read_dag2(UINT32 op) +{ + UINT32 ireg = 4 + ((op >> 2) & 3); + UINT32 mreg = 4 + (op & 3); + UINT32 base = m_base[ireg]; + UINT32 i = m_i[ireg]; + UINT32 l = m_l[ireg]; + UINT32 res; + + res = program_read(i); + m_px = res; + res >>= 8; + + i += m_m[mreg]; + if (i < base) i += l; + else if (i >= base + l) i -= l; + m_i[ireg] = i; + + return res; +} + + + +/*=========================================================================== + register reading +===========================================================================*/ + +#define ALU_GETXREG_UNSIGNED(x) (*(UINT16 *)m_alu_xregs[x]) +#define ALU_GETYREG_UNSIGNED(y) (*(UINT16 *)m_alu_yregs[y]) + +#define MAC_GETXREG_UNSIGNED(x) (*(UINT16 *)m_mac_xregs[x]) +#define MAC_GETXREG_SIGNED(x) (*( INT16 *)m_mac_xregs[x]) +#define MAC_GETYREG_UNSIGNED(y) (*(UINT16 *)m_mac_yregs[y]) +#define MAC_GETYREG_SIGNED(y) (*( INT16 *)m_mac_yregs[y]) + +#define SHIFT_GETXREG_UNSIGNED(x) (*(UINT16 *)m_shift_xregs[x]) +#define SHIFT_GETXREG_SIGNED(x) (*( INT16 *)m_shift_xregs[x]) + + + +/*=========================================================================== + ALU operations (result in AR) +===========================================================================*/ + +void adsp21xx_device::alu_op_ar(int op) +{ + INT32 xop = (op >> 8) & 7; + INT32 yop = (op >> 11) & 3; + INT32 res; + + switch (op & (15<<13)) /*JB*/ + { + case 0x00<<13: + /* Y Clear when y = 0 */ + res = ALU_GETYREG_UNSIGNED(yop); + CALC_NZ(res); + break; + case 0x01<<13: + /* Y + 1 PASS 1 when y = 0 */ + yop = ALU_GETYREG_UNSIGNED(yop); + res = yop + 1; + CALC_NZ(res); + if (yop == 0x7fff) SET_V; + else if (yop == 0xffff) SET_C; + break; + case 0x02<<13: + /* X + Y + C */ + xop = ALU_GETXREG_UNSIGNED(xop); + yop = ALU_GETYREG_UNSIGNED(yop); + yop += GET_C >> 3; + res = xop + yop; + CALC_NZVC(xop, yop, res); + break; + case 0x03<<13: + /* X + Y X when y = 0 */ + xop = ALU_GETXREG_UNSIGNED(xop); + yop = ALU_GETYREG_UNSIGNED(yop); + res = xop + yop; + CALC_NZVC(xop, yop, res); + break; + case 0x04<<13: + /* NOT Y */ + res = ALU_GETYREG_UNSIGNED(yop) ^ 0xffff; + CALC_NZ(res); + break; + case 0x05<<13: + /* -Y */ + yop = ALU_GETYREG_UNSIGNED(yop); + res = -yop; + CALC_NZ(res); + if (yop == 0x8000) SET_V; + if (yop == 0x0000) SET_C; + break; + case 0x06<<13: + /* X - Y + C - 1 X + C - 1 when y = 0 */ + xop = ALU_GETXREG_UNSIGNED(xop); + yop = ALU_GETYREG_UNSIGNED(yop); + res = xop - yop + (GET_C >> 3) - 1; + CALC_NZVC_SUB(xop, yop, res); + break; + case 0x07<<13: + /* X - Y */ + xop = ALU_GETXREG_UNSIGNED(xop); + yop = ALU_GETYREG_UNSIGNED(yop); + res = xop - yop; + CALC_NZVC_SUB(xop, yop, res); + break; + case 0x08<<13: + /* Y - 1 PASS -1 when y = 0 */ + yop = ALU_GETYREG_UNSIGNED(yop); + res = yop - 1; + CALC_NZ(res); + if (yop == 0x8000) SET_V; + else if (yop == 0x0000) SET_C; + break; + case 0x09<<13: + /* Y - X -X when y = 0 */ + xop = ALU_GETXREG_UNSIGNED(xop); + yop = ALU_GETYREG_UNSIGNED(yop); + res = yop - xop; + CALC_NZVC_SUB(yop, xop, res); + break; + case 0x0a<<13: + /* Y - X + C - 1 -X + C - 1 when y = 0 */ + xop = ALU_GETXREG_UNSIGNED(xop); + yop = ALU_GETYREG_UNSIGNED(yop); + res = yop - xop + (GET_C >> 3) - 1; + CALC_NZVC_SUB(yop, xop, res); + break; + case 0x0b<<13: + /* NOT X */ + res = ALU_GETXREG_UNSIGNED(xop) ^ 0xffff; + CALC_NZ(res); + break; + case 0x0c<<13: + /* X AND Y */ + xop = ALU_GETXREG_UNSIGNED(xop); + yop = ALU_GETYREG_UNSIGNED(yop); + res = xop & yop; + CALC_NZ(res); + break; + case 0x0d<<13: + /* X OR Y */ + xop = ALU_GETXREG_UNSIGNED(xop); + yop = ALU_GETYREG_UNSIGNED(yop); + res = xop | yop; + CALC_NZ(res); + break; + case 0x0e<<13: + /* X XOR Y */ + xop = ALU_GETXREG_UNSIGNED(xop); + yop = ALU_GETYREG_UNSIGNED(yop); + res = xop ^ yop; + CALC_NZ(res); + break; + case 0x0f<<13: + /* ABS X */ + xop = ALU_GETXREG_UNSIGNED(xop); + res = (xop & 0x8000) ? -xop : xop; + CLR_FLAGS; + if (xop == 0) SET_Z; + if (xop == 0x8000) SET_N, SET_V; + if (xop & 0x8000) SET_S; + break; + default: + res = 0; /* just to keep the compiler happy */ + break; + } + + /* saturate */ + if ((m_mstat & MSTAT_SATURATE) && GET_V) res = GET_C ? -32768 : 32767; + + /* set the final value */ + m_core.ar.u = res; +} + + + +/*=========================================================================== + ALU operations (result in AR, constant yop) +===========================================================================*/ + +void adsp21xx_device::alu_op_ar_const(int op) +{ + INT32 xop = (op >> 8) & 7; + INT32 yop = constants[((op >> 5) & 0x07) | ((op >> 8) & 0x18)]; + INT32 res; + + switch (op & (15<<13)) /*JB*/ + { + case 0x00<<13: + /* Y Clear when y = 0 */ + res = yop; + CALC_NZ(res); + break; + case 0x01<<13: + /* Y + 1 PASS 1 when y = 0 */ + res = yop + 1; + CALC_NZ(res); + if (yop == 0x7fff) SET_V; + else if (yop == 0xffff) SET_C; + break; + case 0x02<<13: + /* X + Y + C */ + xop = ALU_GETXREG_UNSIGNED(xop); + yop += GET_C >> 3; + res = xop + yop; + CALC_NZVC(xop, yop, res); + break; + case 0x03<<13: + /* X + Y X when y = 0 */ + xop = ALU_GETXREG_UNSIGNED(xop); + res = xop + yop; + CALC_NZVC(xop, yop, res); + break; + case 0x04<<13: + /* NOT Y */ + res = yop ^ 0xffff; + CALC_NZ(res); + break; + case 0x05<<13: + /* -Y */ + res = -yop; + CALC_NZ(res); + if (yop == 0x8000) SET_V; + if (yop == 0x0000) SET_C; + break; + case 0x06<<13: + /* X - Y + C - 1 X + C - 1 when y = 0 */ + xop = ALU_GETXREG_UNSIGNED(xop); + res = xop - yop + (GET_C >> 3) - 1; + CALC_NZVC_SUB(xop, yop, res); + break; + case 0x07<<13: + /* X - Y */ + xop = ALU_GETXREG_UNSIGNED(xop); + res = xop - yop; + CALC_NZVC_SUB(xop, yop, res); + break; + case 0x08<<13: + /* Y - 1 PASS -1 when y = 0 */ + res = yop - 1; + CALC_NZ(res); + if (yop == 0x8000) SET_V; + else if (yop == 0x0000) SET_C; + break; + case 0x09<<13: + /* Y - X -X when y = 0 */ + xop = ALU_GETXREG_UNSIGNED(xop); + res = yop - xop; + CALC_NZVC_SUB(yop, xop, res); + break; + case 0x0a<<13: + /* Y - X + C - 1 -X + C - 1 when y = 0 */ + xop = ALU_GETXREG_UNSIGNED(xop); + res = yop - xop + (GET_C >> 3) - 1; + CALC_NZVC_SUB(yop, xop, res); + break; + case 0x0b<<13: + /* NOT X */ + res = ALU_GETXREG_UNSIGNED(xop) ^ 0xffff; + CALC_NZ(res); + break; + case 0x0c<<13: + /* X AND Y */ + xop = ALU_GETXREG_UNSIGNED(xop); + res = xop & yop; + CALC_NZ(res); + break; + case 0x0d<<13: + /* X OR Y */ + xop = ALU_GETXREG_UNSIGNED(xop); + res = xop | yop; + CALC_NZ(res); + break; + case 0x0e<<13: + /* X XOR Y */ + xop = ALU_GETXREG_UNSIGNED(xop); + res = xop ^ yop; + CALC_NZ(res); + break; + case 0x0f<<13: + /* ABS X */ + xop = ALU_GETXREG_UNSIGNED(xop); + res = (xop & 0x8000) ? -xop : xop; + CLR_FLAGS; + if (xop == 0) SET_Z; + if (xop == 0x8000) SET_N, SET_V; + if (xop & 0x8000) SET_S; + break; + default: + res = 0; /* just to keep the compiler happy */ + break; + } + + /* saturate */ + if ((m_mstat & MSTAT_SATURATE) && GET_V) res = GET_C ? -32768 : 32767; + + /* set the final value */ + m_core.ar.u = res; +} + + + +/*=========================================================================== + ALU operations (result in AF) +===========================================================================*/ + +void adsp21xx_device::alu_op_af(int op) +{ + INT32 xop = (op >> 8) & 7; + INT32 yop = (op >> 11) & 3; + INT32 res; + + switch (op & (15<<13)) /*JB*/ + { + case 0x00<<13: + /* Y Clear when y = 0 */ + res = ALU_GETYREG_UNSIGNED(yop); + CALC_NZ(res); + break; + case 0x01<<13: + /* Y + 1 PASS 1 when y = 0 */ + yop = ALU_GETYREG_UNSIGNED(yop); + res = yop + 1; + CALC_NZ(res); + if (yop == 0x7fff) SET_V; + else if (yop == 0xffff) SET_C; + break; + case 0x02<<13: + /* X + Y + C */ + xop = ALU_GETXREG_UNSIGNED(xop); + yop = ALU_GETYREG_UNSIGNED(yop); + yop += GET_C >> 3; + res = xop + yop; + CALC_NZVC(xop, yop, res); + break; + case 0x03<<13: + /* X + Y X when y = 0 */ + xop = ALU_GETXREG_UNSIGNED(xop); + yop = ALU_GETYREG_UNSIGNED(yop); + res = xop + yop; + CALC_NZVC(xop, yop, res); + break; + case 0x04<<13: + /* NOT Y */ + res = ALU_GETYREG_UNSIGNED(yop) ^ 0xffff; + CALC_NZ(res); + break; + case 0x05<<13: + /* -Y */ + yop = ALU_GETYREG_UNSIGNED(yop); + res = -yop; + CALC_NZ(res); + if (yop == 0x8000) SET_V; + if (yop == 0x0000) SET_C; + break; + case 0x06<<13: + /* X - Y + C - 1 X + C - 1 when y = 0 */ + xop = ALU_GETXREG_UNSIGNED(xop); + yop = ALU_GETYREG_UNSIGNED(yop); + res = xop - yop + (GET_C >> 3) - 1; + CALC_NZVC_SUB(xop, yop, res); + break; + case 0x07<<13: + /* X - Y */ + xop = ALU_GETXREG_UNSIGNED(xop); + yop = ALU_GETYREG_UNSIGNED(yop); + res = xop - yop; + CALC_NZVC_SUB(xop, yop, res); + break; + case 0x08<<13: + /* Y - 1 PASS -1 when y = 0 */ + yop = ALU_GETYREG_UNSIGNED(yop); + res = yop - 1; + CALC_NZ(res); + if (yop == 0x8000) SET_V; + else if (yop == 0x0000) SET_C; + break; + case 0x09<<13: + /* Y - X -X when y = 0 */ + xop = ALU_GETXREG_UNSIGNED(xop); + yop = ALU_GETYREG_UNSIGNED(yop); + res = yop - xop; + CALC_NZVC_SUB(yop, xop, res); + break; + case 0x0a<<13: + /* Y - X + C - 1 -X + C - 1 when y = 0 */ + xop = ALU_GETXREG_UNSIGNED(xop); + yop = ALU_GETYREG_UNSIGNED(yop); + res = yop - xop + (GET_C >> 3) - 1; + CALC_NZVC_SUB(yop, xop, res); + break; + case 0x0b<<13: + /* NOT X */ + res = ALU_GETXREG_UNSIGNED(xop) ^ 0xffff; + CALC_NZ(res); + break; + case 0x0c<<13: + /* X AND Y */ + xop = ALU_GETXREG_UNSIGNED(xop); + yop = ALU_GETYREG_UNSIGNED(yop); + res = xop & yop; + CALC_NZ(res); + break; + case 0x0d<<13: + /* X OR Y */ + xop = ALU_GETXREG_UNSIGNED(xop); + yop = ALU_GETYREG_UNSIGNED(yop); + res = xop | yop; + CALC_NZ(res); + break; + case 0x0e<<13: + /* X XOR Y */ + xop = ALU_GETXREG_UNSIGNED(xop); + yop = ALU_GETYREG_UNSIGNED(yop); + res = xop ^ yop; + CALC_NZ(res); + break; + case 0x0f<<13: + /* ABS X */ + xop = ALU_GETXREG_UNSIGNED(xop); + res = (xop & 0x8000) ? -xop : xop; + CLR_FLAGS; + if (xop == 0) SET_Z; + if (xop == 0x8000) SET_N, SET_V; + if (xop & 0x8000) SET_S; + break; + default: + res = 0; /* just to keep the compiler happy */ + break; + } + + /* set the final value */ + m_core.af.u = res; +} + + + +/*=========================================================================== + ALU operations (result in AF, constant yop) +===========================================================================*/ + +void adsp21xx_device::alu_op_af_const(int op) +{ + INT32 xop = (op >> 8) & 7; + INT32 yop = constants[((op >> 5) & 0x07) | ((op >> 8) & 0x18)]; + INT32 res; + + switch (op & (15<<13)) /*JB*/ + { + case 0x00<<13: + /* Y Clear when y = 0 */ + res = yop; + CALC_NZ(res); + break; + case 0x01<<13: + /* Y + 1 PASS 1 when y = 0 */ + res = yop + 1; + CALC_NZ(res); + if (yop == 0x7fff) SET_V; + else if (yop == 0xffff) SET_C; + break; + case 0x02<<13: + /* X + Y + C */ + xop = ALU_GETXREG_UNSIGNED(xop); + yop += GET_C >> 3; + res = xop + yop; + CALC_NZVC(xop, yop, res); + break; + case 0x03<<13: + /* X + Y X when y = 0 */ + xop = ALU_GETXREG_UNSIGNED(xop); + res = xop + yop; + CALC_NZVC(xop, yop, res); + break; + case 0x04<<13: + /* NOT Y */ + res = yop ^ 0xffff; + CALC_NZ(res); + break; + case 0x05<<13: + /* -Y */ + res = -yop; + CALC_NZ(res); + if (yop == 0x8000) SET_V; + if (yop == 0x0000) SET_C; + break; + case 0x06<<13: + /* X - Y + C - 1 X + C - 1 when y = 0 */ + xop = ALU_GETXREG_UNSIGNED(xop); + res = xop - yop + (GET_C >> 3) - 1; + CALC_NZVC_SUB(xop, yop, res); + break; + case 0x07<<13: + /* X - Y */ + xop = ALU_GETXREG_UNSIGNED(xop); + res = xop - yop; + CALC_NZVC_SUB(xop, yop, res); + break; + case 0x08<<13: + /* Y - 1 PASS -1 when y = 0 */ + res = yop - 1; + CALC_NZ(res); + if (yop == 0x8000) SET_V; + else if (yop == 0x0000) SET_C; + break; + case 0x09<<13: + /* Y - X -X when y = 0 */ + xop = ALU_GETXREG_UNSIGNED(xop); + res = yop - xop; + CALC_NZVC_SUB(yop, xop, res); + break; + case 0x0a<<13: + /* Y - X + C - 1 -X + C - 1 when y = 0 */ + xop = ALU_GETXREG_UNSIGNED(xop); + res = yop - xop + (GET_C >> 3) - 1; + CALC_NZVC_SUB(yop, xop, res); + break; + case 0x0b<<13: + /* NOT X */ + res = ALU_GETXREG_UNSIGNED(xop) ^ 0xffff; + CALC_NZ(res); + break; + case 0x0c<<13: + /* X AND Y */ + xop = ALU_GETXREG_UNSIGNED(xop); + res = xop & yop; + CALC_NZ(res); + break; + case 0x0d<<13: + /* X OR Y */ + xop = ALU_GETXREG_UNSIGNED(xop); + res = xop | yop; + CALC_NZ(res); + break; + case 0x0e<<13: + /* X XOR Y */ + xop = ALU_GETXREG_UNSIGNED(xop); + res = xop ^ yop; + CALC_NZ(res); + break; + case 0x0f<<13: + /* ABS X */ + xop = ALU_GETXREG_UNSIGNED(xop); + res = (xop & 0x8000) ? -xop : xop; + CLR_FLAGS; + if (xop == 0) SET_Z; + if (xop == 0x8000) SET_N, SET_V; + if (xop & 0x8000) SET_S; + break; + default: + res = 0; /* just to keep the compiler happy */ + break; + } + + /* set the final value */ + m_core.af.u = res; +} + + + +/*=========================================================================== + ALU operations (no result) +===========================================================================*/ + +void adsp21xx_device::alu_op_none(int op) +{ + INT32 xop = (op >> 8) & 7; + INT32 yop = (op >> 11) & 3; + INT32 res; + + switch (op & (15<<13)) /*JB*/ + { + case 0x00<<13: + /* Y Clear when y = 0 */ + res = ALU_GETYREG_UNSIGNED(yop); + CALC_NZ(res); + break; + case 0x01<<13: + /* Y + 1 PASS 1 when y = 0 */ + yop = ALU_GETYREG_UNSIGNED(yop); + res = yop + 1; + CALC_NZ(res); + if (yop == 0x7fff) SET_V; + else if (yop == 0xffff) SET_C; + break; + case 0x02<<13: + /* X + Y + C */ + xop = ALU_GETXREG_UNSIGNED(xop); + yop = ALU_GETYREG_UNSIGNED(yop); + yop += GET_C >> 3; + res = xop + yop; + CALC_NZVC(xop, yop, res); + break; + case 0x03<<13: + /* X + Y X when y = 0 */ + xop = ALU_GETXREG_UNSIGNED(xop); + yop = ALU_GETYREG_UNSIGNED(yop); + res = xop + yop; + CALC_NZVC(xop, yop, res); + break; + case 0x04<<13: + /* NOT Y */ + res = ALU_GETYREG_UNSIGNED(yop) ^ 0xffff; + CALC_NZ(res); + break; + case 0x05<<13: + /* -Y */ + yop = ALU_GETYREG_UNSIGNED(yop); + res = -yop; + CALC_NZ(res); + if (yop == 0x8000) SET_V; + if (yop == 0x0000) SET_C; + break; + case 0x06<<13: + /* X - Y + C - 1 X + C - 1 when y = 0 */ + xop = ALU_GETXREG_UNSIGNED(xop); + yop = ALU_GETYREG_UNSIGNED(yop); + res = xop - yop + (GET_C >> 3) - 1; + CALC_NZVC_SUB(xop, yop, res); + break; + case 0x07<<13: + /* X - Y */ + xop = ALU_GETXREG_UNSIGNED(xop); + yop = ALU_GETYREG_UNSIGNED(yop); + res = xop - yop; + CALC_NZVC_SUB(xop, yop, res); + break; + case 0x08<<13: + /* Y - 1 PASS -1 when y = 0 */ + yop = ALU_GETYREG_UNSIGNED(yop); + res = yop - 1; + CALC_NZ(res); + if (yop == 0x8000) SET_V; + else if (yop == 0x0000) SET_C; + break; + case 0x09<<13: + /* Y - X -X when y = 0 */ + xop = ALU_GETXREG_UNSIGNED(xop); + yop = ALU_GETYREG_UNSIGNED(yop); + res = yop - xop; + CALC_NZVC_SUB(yop, xop, res); + break; + case 0x0a<<13: + /* Y - X + C - 1 -X + C - 1 when y = 0 */ + xop = ALU_GETXREG_UNSIGNED(xop); + yop = ALU_GETYREG_UNSIGNED(yop); + res = yop - xop + (GET_C >> 3) - 1; + CALC_NZVC_SUB(yop, xop, res); + break; + case 0x0b<<13: + /* NOT X */ + res = ALU_GETXREG_UNSIGNED(xop) ^ 0xffff; + CALC_NZ(res); + break; + case 0x0c<<13: + /* X AND Y */ + xop = ALU_GETXREG_UNSIGNED(xop); + yop = ALU_GETYREG_UNSIGNED(yop); + res = xop & yop; + CALC_NZ(res); + break; + case 0x0d<<13: + /* X OR Y */ + xop = ALU_GETXREG_UNSIGNED(xop); + yop = ALU_GETYREG_UNSIGNED(yop); + res = xop | yop; + CALC_NZ(res); + break; + case 0x0e<<13: + /* X XOR Y */ + xop = ALU_GETXREG_UNSIGNED(xop); + yop = ALU_GETYREG_UNSIGNED(yop); + res = xop ^ yop; + CALC_NZ(res); + break; + case 0x0f<<13: + /* ABS X */ + xop = ALU_GETXREG_UNSIGNED(xop); + res = (xop & 0x8000) ? -xop : xop; + CLR_FLAGS; + if (xop == 0) SET_Z; + if (xop == 0x8000) SET_N, SET_V; + if (xop & 0x8000) SET_S; + break; + } +} + + + +/*=========================================================================== + MAC operations (result in MR) +===========================================================================*/ + +void adsp21xx_device::mac_op_mr(int op) +{ + INT8 shift = ((m_mstat & MSTAT_INTEGER) >> 4) ^ 1; + INT32 xop = (op >> 8) & 7; + INT32 yop = (op >> 11) & 3; + INT32 temp; + INT64 res; + + switch (op & (15<<13)) /*JB*/ + { + case 0x00<<13: + /* no-op */ + return; + case 0x01<<13: + /* X * Y (RND) */ + xop = MAC_GETXREG_SIGNED(xop); + yop = MAC_GETYREG_SIGNED(yop); + temp = (xop * yop) << shift; + res = (INT64)temp; +#if 0 + if ((res & 0xffff) == 0x8000) res &= ~((UINT64)0x10000); + else res += (res & 0x8000) << 1; +#else + temp &= 0xffff; + res += 0x8000; + if ( temp == 0x8000 ) + res &= ~((UINT64)0x10000); +#endif + break; + case 0x02<<13: + /* MR + X * Y (RND) */ + xop = MAC_GETXREG_SIGNED(xop); + yop = MAC_GETYREG_SIGNED(yop); + temp = (xop * yop) << shift; + res = m_core.mr.mr + (INT64)temp; +#if 0 + if ((res & 0xffff) == 0x8000) res &= ~((UINT64)0x10000); + else res += (res & 0x8000) << 1; +#else + temp &= 0xffff; + res += 0x8000; + if ( temp == 0x8000 ) + res &= ~((UINT64)0x10000); +#endif + break; + case 0x03<<13: + /* MR - X * Y (RND) */ + xop = MAC_GETXREG_SIGNED(xop); + yop = MAC_GETYREG_SIGNED(yop); + temp = (xop * yop) << shift; + res = m_core.mr.mr - (INT64)temp; +#if 0 + if ((res & 0xffff) == 0x8000) res &= ~((UINT64)0x10000); + else res += (res & 0x8000) << 1; +#else + temp &= 0xffff; + res += 0x8000; + if ( temp == 0x8000 ) + res &= ~((UINT64)0x10000); +#endif + break; + case 0x04<<13: + /* X * Y (SS) Clear when y = 0 */ + xop = MAC_GETXREG_SIGNED(xop); + yop = MAC_GETYREG_SIGNED(yop); + temp = (xop * yop) << shift; + res = (INT64)temp; + break; + case 0x05<<13: + /* X * Y (SU) */ + xop = MAC_GETXREG_SIGNED(xop); + yop = MAC_GETYREG_UNSIGNED(yop); + temp = (xop * yop) << shift; + res = (INT64)temp; + break; + case 0x06<<13: + /* X * Y (US) */ + xop = MAC_GETXREG_UNSIGNED(xop); + yop = MAC_GETYREG_SIGNED(yop); + temp = (xop * yop) << shift; + res = (INT64)temp; + break; + case 0x07<<13: + /* X * Y (UU) */ + xop = MAC_GETXREG_UNSIGNED(xop); + yop = MAC_GETYREG_UNSIGNED(yop); + temp = (xop * yop) << shift; + res = (INT64)temp; + break; + case 0x08<<13: + /* MR + X * Y (SS) */ + xop = MAC_GETXREG_SIGNED(xop); + yop = MAC_GETYREG_SIGNED(yop); + temp = (xop * yop) << shift; + res = m_core.mr.mr + (INT64)temp; + break; + case 0x09<<13: + /* MR + X * Y (SU) */ + xop = MAC_GETXREG_SIGNED(xop); + yop = MAC_GETYREG_UNSIGNED(yop); + temp = (xop * yop) << shift; + res = m_core.mr.mr + (INT64)temp; + break; + case 0x0a<<13: + /* MR + X * Y (US) */ + xop = MAC_GETXREG_UNSIGNED(xop); + yop = MAC_GETYREG_SIGNED(yop); + temp = (xop * yop) << shift; + res = m_core.mr.mr + (INT64)temp; + break; + case 0x0b<<13: + /* MR + X * Y (UU) */ + xop = MAC_GETXREG_UNSIGNED(xop); + yop = MAC_GETYREG_UNSIGNED(yop); + temp = (xop * yop) << shift; + res = m_core.mr.mr + (INT64)temp; + break; + case 0x0c<<13: + /* MR - X * Y (SS) */ + xop = MAC_GETXREG_SIGNED(xop); + yop = MAC_GETYREG_SIGNED(yop); + temp = (xop * yop) << shift; + res = m_core.mr.mr - (INT64)temp; + break; + case 0x0d<<13: + /* MR - X * Y (SU) */ + xop = MAC_GETXREG_SIGNED(xop); + yop = MAC_GETYREG_UNSIGNED(yop); + temp = (xop * yop) << shift; + res = m_core.mr.mr - (INT64)temp; + break; + case 0x0e<<13: + /* MR - X * Y (US) */ + xop = MAC_GETXREG_UNSIGNED(xop); + yop = MAC_GETYREG_SIGNED(yop); + temp = (xop * yop) << shift; + res = m_core.mr.mr - (INT64)temp; + break; + case 0x0f<<13: + /* MR - X * Y (UU) */ + xop = MAC_GETXREG_UNSIGNED(xop); + yop = MAC_GETYREG_UNSIGNED(yop); + temp = (xop * yop) << shift; + res = m_core.mr.mr - (INT64)temp; + break; + default: + res = 0; /* just to keep the compiler happy */ + break; + } + + /* set the final value */ + temp = (res >> 31) & 0x1ff; + CLR_MV; + if (temp != 0x000 && temp != 0x1ff) SET_MV; + m_core.mr.mr = res; +} + + + +/*=========================================================================== + MAC operations (result in MR, yop == xop) +===========================================================================*/ + +void adsp21xx_device::mac_op_mr_xop(int op) +{ + INT8 shift = ((m_mstat & MSTAT_INTEGER) >> 4) ^ 1; + INT32 xop = (op >> 8) & 7; + INT32 temp; + INT64 res; + + switch (op & (15<<13)) /*JB*/ + { + case 0x00<<13: + /* no-op */ + return; + case 0x01<<13: + /* X * Y (RND) */ + xop = MAC_GETXREG_SIGNED(xop); + temp = (xop * xop) << shift; + res = (INT64)temp; +#if 0 + if ((res & 0xffff) == 0x8000) res &= ~((UINT64)0x10000); + else res += (res & 0x8000) << 1; +#else + temp &= 0xffff; + res += 0x8000; + if ( temp == 0x8000 ) + res &= ~((UINT64)0x10000); +#endif + break; + case 0x02<<13: + /* MR + X * Y (RND) */ + xop = MAC_GETXREG_SIGNED(xop); + temp = (xop * xop) << shift; + res = m_core.mr.mr + (INT64)temp; +#if 0 + if ((res & 0xffff) == 0x8000) res &= ~((UINT64)0x10000); + else res += (res & 0x8000) << 1; +#else + temp &= 0xffff; + res += 0x8000; + if ( temp == 0x8000 ) + res &= ~((UINT64)0x10000); +#endif + break; + case 0x03<<13: + /* MR - X * Y (RND) */ + xop = MAC_GETXREG_SIGNED(xop); + temp = (xop * xop) << shift; + res = m_core.mr.mr - (INT64)temp; +#if 0 + if ((res & 0xffff) == 0x8000) res &= ~((UINT64)0x10000); + else res += (res & 0x8000) << 1; +#else + temp &= 0xffff; + res += 0x8000; + if ( temp == 0x8000 ) + res &= ~((UINT64)0x10000); +#endif + break; + case 0x04<<13: + /* X * Y (SS) Clear when y = 0 */ + xop = MAC_GETXREG_SIGNED(xop); + temp = (xop * xop) << shift; + res = (INT64)temp; + break; + case 0x05<<13: + /* X * Y (SU) */ + xop = MAC_GETXREG_SIGNED(xop); + temp = (xop * xop) << shift; + res = (INT64)temp; + break; + case 0x06<<13: + /* X * Y (US) */ + xop = MAC_GETXREG_UNSIGNED(xop); + temp = (xop * xop) << shift; + res = (INT64)temp; + break; + case 0x07<<13: + /* X * Y (UU) */ + xop = MAC_GETXREG_UNSIGNED(xop); + temp = (xop * xop) << shift; + res = (INT64)temp; + break; + case 0x08<<13: + /* MR + X * Y (SS) */ + xop = MAC_GETXREG_SIGNED(xop); + temp = (xop * xop) << shift; + res = m_core.mr.mr + (INT64)temp; + break; + case 0x09<<13: + /* MR + X * Y (SU) */ + xop = MAC_GETXREG_SIGNED(xop); + temp = (xop * xop) << shift; + res = m_core.mr.mr + (INT64)temp; + break; + case 0x0a<<13: + /* MR + X * Y (US) */ + xop = MAC_GETXREG_UNSIGNED(xop); + temp = (xop * xop) << shift; + res = m_core.mr.mr + (INT64)temp; + break; + case 0x0b<<13: + /* MR + X * Y (UU) */ + xop = MAC_GETXREG_UNSIGNED(xop); + temp = (xop * xop) << shift; + res = m_core.mr.mr + (INT64)temp; + break; + case 0x0c<<13: + /* MR - X * Y (SS) */ + xop = MAC_GETXREG_SIGNED(xop); + temp = (xop * xop) << shift; + res = m_core.mr.mr - (INT64)temp; + break; + case 0x0d<<13: + /* MR - X * Y (SU) */ + xop = MAC_GETXREG_SIGNED(xop); + temp = (xop * xop) << shift; + res = m_core.mr.mr - (INT64)temp; + break; + case 0x0e<<13: + /* MR - X * Y (US) */ + xop = MAC_GETXREG_UNSIGNED(xop); + temp = (xop * xop) << shift; + res = m_core.mr.mr - (INT64)temp; + break; + case 0x0f<<13: + /* MR - X * Y (UU) */ + xop = MAC_GETXREG_UNSIGNED(xop); + temp = (xop * xop) << shift; + res = m_core.mr.mr - (INT64)temp; + break; + default: + res = 0; /* just to keep the compiler happy */ + break; + } + + /* set the final value */ + temp = (res >> 31) & 0x1ff; + CLR_MV; + if (temp != 0x000 && temp != 0x1ff) SET_MV; + m_core.mr.mr = res; +} + + + +/*=========================================================================== + MAC operations (result in MF) +===========================================================================*/ + +void adsp21xx_device::mac_op_mf(int op) +{ + INT8 shift = ((m_mstat & MSTAT_INTEGER) >> 4) ^ 1; + INT32 xop = (op >> 8) & 7; + INT32 yop = (op >> 11) & 3; + INT32 temp; + INT64 res; + + switch (op & (15<<13)) /*JB*/ + { + case 0x00<<13: + /* no-op */ + return; + case 0x01<<13: + /* X * Y (RND) */ + xop = MAC_GETXREG_SIGNED(xop); + yop = MAC_GETYREG_SIGNED(yop); + temp = (xop * yop) << shift; + res = (INT64)temp; +#if 0 + if ((res & 0xffff) == 0x8000) res &= ~((UINT64)0x10000); + else res += (res & 0x8000) << 1; +#else + temp &= 0xffff; + res += 0x8000; + if ( temp == 0x8000 ) + res &= ~((UINT64)0x10000); +#endif + break; + case 0x02<<13: + /* MR + X * Y (RND) */ + xop = MAC_GETXREG_SIGNED(xop); + yop = MAC_GETYREG_SIGNED(yop); + temp = (xop * yop) << shift; + res = m_core.mr.mr + (INT64)temp; +#if 0 + if ((res & 0xffff) == 0x8000) res &= ~((UINT64)0x10000); + else res += (res & 0x8000) << 1; +#else + temp &= 0xffff; + res += 0x8000; + if ( temp == 0x8000 ) + res &= ~((UINT64)0x10000); +#endif + break; + case 0x03<<13: + /* MR - X * Y (RND) */ + xop = MAC_GETXREG_SIGNED(xop); + yop = MAC_GETYREG_SIGNED(yop); + temp = (xop * yop) << shift; + res = m_core.mr.mr - (INT64)temp; +#if 0 + if ((res & 0xffff) == 0x8000) res &= ~((UINT64)0x10000); + else res += (res & 0x8000) << 1; +#else + temp &= 0xffff; + res += 0x8000; + if ( temp == 0x8000 ) + res &= ~((UINT64)0x10000); +#endif + break; + case 0x04<<13: + /* X * Y (SS) Clear when y = 0 */ + xop = MAC_GETXREG_SIGNED(xop); + yop = MAC_GETYREG_SIGNED(yop); + temp = (xop * yop) << shift; + res = (INT64)temp; + break; + case 0x05<<13: + /* X * Y (SU) */ + xop = MAC_GETXREG_SIGNED(xop); + yop = MAC_GETYREG_UNSIGNED(yop); + temp = (xop * yop) << shift; + res = (INT64)temp; + break; + case 0x06<<13: + /* X * Y (US) */ + xop = MAC_GETXREG_UNSIGNED(xop); + yop = MAC_GETYREG_SIGNED(yop); + temp = (xop * yop) << shift; + res = (INT64)temp; + break; + case 0x07<<13: + /* X * Y (UU) */ + xop = MAC_GETXREG_UNSIGNED(xop); + yop = MAC_GETYREG_UNSIGNED(yop); + temp = (xop * yop) << shift; + res = (INT64)temp; + break; + case 0x08<<13: + /* MR + X * Y (SS) */ + xop = MAC_GETXREG_SIGNED(xop); + yop = MAC_GETYREG_SIGNED(yop); + temp = (xop * yop) << shift; + res = m_core.mr.mr + (INT64)temp; + break; + case 0x09<<13: + /* MR + X * Y (SU) */ + xop = MAC_GETXREG_SIGNED(xop); + yop = MAC_GETYREG_UNSIGNED(yop); + temp = (xop * yop) << shift; + res = m_core.mr.mr + (INT64)temp; + break; + case 0x0a<<13: + /* MR + X * Y (US) */ + xop = MAC_GETXREG_UNSIGNED(xop); + yop = MAC_GETYREG_SIGNED(yop); + temp = (xop * yop) << shift; + res = m_core.mr.mr + (INT64)temp; + break; + case 0x0b<<13: + /* MR + X * Y (UU) */ + xop = MAC_GETXREG_UNSIGNED(xop); + yop = MAC_GETYREG_UNSIGNED(yop); + temp = (xop * yop) << shift; + res = m_core.mr.mr + (INT64)temp; + break; + case 0x0c<<13: + /* MR - X * Y (SS) */ + xop = MAC_GETXREG_SIGNED(xop); + yop = MAC_GETYREG_SIGNED(yop); + temp = (xop * yop) << shift; + res = m_core.mr.mr - (INT64)temp; + break; + case 0x0d<<13: + /* MR - X * Y (SU) */ + xop = MAC_GETXREG_SIGNED(xop); + yop = MAC_GETYREG_UNSIGNED(yop); + temp = (xop * yop) << shift; + res = m_core.mr.mr - (INT64)temp; + break; + case 0x0e<<13: + /* MR - X * Y (US) */ + xop = MAC_GETXREG_UNSIGNED(xop); + yop = MAC_GETYREG_SIGNED(yop); + temp = (xop * yop) << shift; + res = m_core.mr.mr - (INT64)temp; + break; + case 0x0f<<13: + /* MR - X * Y (UU) */ + xop = MAC_GETXREG_UNSIGNED(xop); + yop = MAC_GETYREG_UNSIGNED(yop); + temp = (xop * yop) << shift; + res = m_core.mr.mr - (INT64)temp; + break; + default: + res = 0; /* just to keep the compiler happy */ + break; + } + + /* set the final value */ + m_core.mf.u = (UINT32)res >> 16; +} + + + +/*=========================================================================== + MAC operations (result in MF, yop == xop) +===========================================================================*/ + +void adsp21xx_device::mac_op_mf_xop(int op) +{ + INT8 shift = ((m_mstat & MSTAT_INTEGER) >> 4) ^ 1; + INT32 xop = (op >> 8) & 7; + INT32 temp; + INT64 res; + + switch (op & (15<<13)) /*JB*/ + { + case 0x00<<13: + /* no-op */ + return; + case 0x01<<13: + /* X * Y (RND) */ + xop = MAC_GETXREG_SIGNED(xop); + temp = (xop * xop) << shift; + res = (INT64)temp; +#if 0 + if ((res & 0xffff) == 0x8000) res &= ~((UINT64)0x10000); + else res += (res & 0x8000) << 1; +#else + temp &= 0xffff; + res += 0x8000; + if ( temp == 0x8000 ) + res &= ~((UINT64)0x10000); +#endif + break; + case 0x02<<13: + /* MR + X * Y (RND) */ + xop = MAC_GETXREG_SIGNED(xop); + temp = (xop * xop) << shift; + res = m_core.mr.mr + (INT64)temp; +#if 0 + if ((res & 0xffff) == 0x8000) res &= ~((UINT64)0x10000); + else res += (res & 0x8000) << 1; +#else + temp &= 0xffff; + res += 0x8000; + if ( temp == 0x8000 ) + res &= ~((UINT64)0x10000); +#endif + break; + case 0x03<<13: + /* MR - X * Y (RND) */ + xop = MAC_GETXREG_SIGNED(xop); + temp = (xop * xop) << shift; + res = m_core.mr.mr - (INT64)temp; +#if 0 + if ((res & 0xffff) == 0x8000) res &= ~((UINT64)0x10000); + else res += (res & 0x8000) << 1; +#else + temp &= 0xffff; + res += 0x8000; + if ( temp == 0x8000 ) + res &= ~((UINT64)0x10000); +#endif + break; + case 0x04<<13: + /* X * Y (SS) Clear when y = 0 */ + xop = MAC_GETXREG_SIGNED(xop); + temp = (xop * xop) << shift; + res = (INT64)temp; + break; + case 0x05<<13: + /* X * Y (SU) */ + xop = MAC_GETXREG_SIGNED(xop); + temp = (xop * xop) << shift; + res = (INT64)temp; + break; + case 0x06<<13: + /* X * Y (US) */ + xop = MAC_GETXREG_UNSIGNED(xop); + temp = (xop * xop) << shift; + res = (INT64)temp; + break; + case 0x07<<13: + /* X * Y (UU) */ + xop = MAC_GETXREG_UNSIGNED(xop); + temp = (xop * xop) << shift; + res = (INT64)temp; + break; + case 0x08<<13: + /* MR + X * Y (SS) */ + xop = MAC_GETXREG_SIGNED(xop); + temp = (xop * xop) << shift; + res = m_core.mr.mr + (INT64)temp; + break; + case 0x09<<13: + /* MR + X * Y (SU) */ + xop = MAC_GETXREG_SIGNED(xop); + temp = (xop * xop) << shift; + res = m_core.mr.mr + (INT64)temp; + break; + case 0x0a<<13: + /* MR + X * Y (US) */ + xop = MAC_GETXREG_UNSIGNED(xop); + temp = (xop * xop) << shift; + res = m_core.mr.mr + (INT64)temp; + break; + case 0x0b<<13: + /* MR + X * Y (UU) */ + xop = MAC_GETXREG_UNSIGNED(xop); + temp = (xop * xop) << shift; + res = m_core.mr.mr + (INT64)temp; + break; + case 0x0c<<13: + /* MR - X * Y (SS) */ + xop = MAC_GETXREG_SIGNED(xop); + temp = (xop * xop) << shift; + res = m_core.mr.mr - (INT64)temp; + break; + case 0x0d<<13: + /* MR - X * Y (SU) */ + xop = MAC_GETXREG_SIGNED(xop); + temp = (xop * xop) << shift; + res = m_core.mr.mr - (INT64)temp; + break; + case 0x0e<<13: + /* MR - X * Y (US) */ + xop = MAC_GETXREG_UNSIGNED(xop); + temp = (xop * xop) << shift; + res = m_core.mr.mr - (INT64)temp; + break; + case 0x0f<<13: + /* MR - X * Y (UU) */ + xop = MAC_GETXREG_UNSIGNED(xop); + temp = (xop * xop) << shift; + res = m_core.mr.mr - (INT64)temp; + break; + default: + res = 0; /* just to keep the compiler happy */ + break; + } + + /* set the final value */ + m_core.mf.u = (UINT32)res >> 16; +} + + + +/*=========================================================================== + SHIFT operations (result in SR/SE/SB) +===========================================================================*/ + +void adsp21xx_device::shift_op(int op) +{ + INT8 sc = m_core.se.s; + INT32 xop = (op >> 8) & 7; + UINT32 res; + + switch (op & (15<<11)) /*JB*/ + { + case 0x00<<11: + /* LSHIFT (HI) */ + xop = SHIFT_GETXREG_UNSIGNED(xop) << 16; + if (sc > 0) res = (sc < 32) ? (xop << sc) : 0; + else res = (sc > -32) ? ((UINT32)xop >> -sc) : 0; + m_core.sr.sr = res; + break; + case 0x01<<11: + /* LSHIFT (HI, OR) */ + xop = SHIFT_GETXREG_UNSIGNED(xop) << 16; + if (sc > 0) res = (sc < 32) ? (xop << sc) : 0; + else res = (sc > -32) ? ((UINT32)xop >> -sc) : 0; + m_core.sr.sr |= res; + break; + case 0x02<<11: + /* LSHIFT (LO) */ + xop = SHIFT_GETXREG_UNSIGNED(xop); + if (sc > 0) res = (sc < 32) ? (xop << sc) : 0; + else res = (sc > -32) ? (xop >> -sc) : 0; + m_core.sr.sr = res; + break; + case 0x03<<11: + /* LSHIFT (LO, OR) */ + xop = SHIFT_GETXREG_UNSIGNED(xop); + if (sc > 0) res = (sc < 32) ? (xop << sc) : 0; + else res = (sc > -32) ? (xop >> -sc) : 0; + m_core.sr.sr |= res; + break; + case 0x04<<11: + /* ASHIFT (HI) */ + xop = SHIFT_GETXREG_SIGNED(xop) << 16; + if (sc > 0) res = (sc < 32) ? (xop << sc) : 0; + else res = (sc > -32) ? (xop >> -sc) : (xop >> 31); + m_core.sr.sr = res; + break; + case 0x05<<11: + /* ASHIFT (HI, OR) */ + xop = SHIFT_GETXREG_SIGNED(xop) << 16; + if (sc > 0) res = (sc < 32) ? (xop << sc) : 0; + else res = (sc > -32) ? (xop >> -sc) : (xop >> 31); + m_core.sr.sr |= res; + break; + case 0x06<<11: + /* ASHIFT (LO) */ + xop = SHIFT_GETXREG_SIGNED(xop); + if (sc > 0) res = (sc < 32) ? (xop << sc) : 0; + else res = (sc > -32) ? (xop >> -sc) : (xop >> 31); + m_core.sr.sr = res; + break; + case 0x07<<11: + /* ASHIFT (LO, OR) */ + xop = SHIFT_GETXREG_SIGNED(xop); + if (sc > 0) res = (sc < 32) ? (xop << sc) : 0; + else res = (sc > -32) ? (xop >> -sc) : (xop >> 31); + m_core.sr.sr |= res; + break; + case 0x08<<11: + /* NORM (HI) */ + xop = SHIFT_GETXREG_SIGNED(xop) << 16; + if (sc > 0) + { + xop = ((UINT32)xop >> 1) | ((m_astat & CFLAG) << 28); + res = xop >> (sc - 1); + } + else res = (sc > -32) ? (xop << -sc) : 0; + m_core.sr.sr = res; + break; + case 0x09<<11: + /* NORM (HI, OR) */ + xop = SHIFT_GETXREG_SIGNED(xop) << 16; + if (sc > 0) + { + xop = ((UINT32)xop >> 1) | ((m_astat & CFLAG) << 28); + res = xop >> (sc - 1); + } + else res = (sc > -32) ? (xop << -sc) : 0; + m_core.sr.sr |= res; + break; + case 0x0a<<11: + /* NORM (LO) */ + xop = SHIFT_GETXREG_UNSIGNED(xop); + if (sc > 0) res = (sc < 32) ? (xop >> sc) : 0; + else res = (sc > -32) ? (xop << -sc) : 0; + m_core.sr.sr = res; + break; + case 0x0b<<11: + /* NORM (LO, OR) */ + xop = SHIFT_GETXREG_UNSIGNED(xop); + if (sc > 0) res = (sc < 32) ? (xop >> sc) : 0; + else res = (sc > -32) ? (xop << -sc) : 0; + m_core.sr.sr |= res; + break; + case 0x0c<<11: + /* EXP (HI) */ + xop = SHIFT_GETXREG_SIGNED(xop) << 16; + res = 0; + if (xop < 0) + { + SET_SS; + while ((xop & 0x40000000) != 0) res++, xop <<= 1; + } + else + { + CLR_SS; + xop |= 0x8000; + while ((xop & 0x40000000) == 0) res++, xop <<= 1; + } + m_core.se.s = -res; + break; + case 0x0d<<11: + /* EXP (HIX) */ + xop = SHIFT_GETXREG_SIGNED(xop) << 16; + if (GET_V) + { + m_core.se.s = 1; + if (xop < 0) CLR_SS; + else SET_SS; + } + else + { + res = 0; + if (xop < 0) + { + SET_SS; + while ((xop & 0x40000000) != 0) res++, xop <<= 1; + } + else + { + CLR_SS; + xop |= 0x8000; + while ((xop & 0x40000000) == 0) res++, xop <<= 1; + } + m_core.se.s = -res; + } + break; + case 0x0e<<11: + /* EXP (LO) */ + if (m_core.se.s == -15) + { + xop = SHIFT_GETXREG_SIGNED(xop); + res = 15; + if (GET_SS) + while ((xop & 0x8000) != 0) res++, xop <<= 1; + else + { + xop = (xop << 1) | 1; + while ((xop & 0x10000) == 0) res++, xop <<= 1; + } + m_core.se.s = -res; + } + break; + case 0x0f<<11: + /* EXPADJ */ + xop = SHIFT_GETXREG_SIGNED(xop) << 16; + res = 0; + if (xop < 0) + while ((xop & 0x40000000) != 0) res++, xop <<= 1; + else + { + xop |= 0x8000; + while ((xop & 0x40000000) == 0) res++, xop <<= 1; + } + if (res < -m_core.sb.s) + m_core.sb.s = -res; + break; + } +} + + + +/*=========================================================================== + Immediate SHIFT operations (result in SR/SE/SB) +===========================================================================*/ + +void adsp21xx_device::shift_op_imm(int op) +{ + INT8 sc = (INT8)op; + INT32 xop = (op >> 8) & 7; + UINT32 res; + + switch (op & (15<<11)) /*JB*/ + { + case 0x00<<11: + /* LSHIFT (HI) */ + xop = SHIFT_GETXREG_UNSIGNED(xop) << 16; + if (sc > 0) res = (sc < 32) ? (xop << sc) : 0; + else res = (sc > -32) ? ((UINT32)xop >> -sc) : 0; + m_core.sr.sr = res; + break; + case 0x01<<11: + /* LSHIFT (HI, OR) */ + xop = SHIFT_GETXREG_UNSIGNED(xop) << 16; + if (sc > 0) res = (sc < 32) ? (xop << sc) : 0; + else res = (sc > -32) ? ((UINT32)xop >> -sc) : 0; + m_core.sr.sr |= res; + break; + case 0x02<<11: + /* LSHIFT (LO) */ + xop = SHIFT_GETXREG_UNSIGNED(xop); + if (sc > 0) res = (sc < 32) ? (xop << sc) : 0; + else res = (sc > -32) ? (xop >> -sc) : 0; + m_core.sr.sr = res; + break; + case 0x03<<11: + /* LSHIFT (LO, OR) */ + xop = SHIFT_GETXREG_UNSIGNED(xop); + if (sc > 0) res = (sc < 32) ? (xop << sc) : 0; + else res = (sc > -32) ? (xop >> -sc) : 0; + m_core.sr.sr |= res; + break; + case 0x04<<11: + /* ASHIFT (HI) */ + xop = SHIFT_GETXREG_SIGNED(xop) << 16; + if (sc > 0) res = (sc < 32) ? (xop << sc) : 0; + else res = (sc > -32) ? (xop >> -sc) : (xop >> 31); + m_core.sr.sr = res; + break; + case 0x05<<11: + /* ASHIFT (HI, OR) */ + xop = SHIFT_GETXREG_SIGNED(xop) << 16; + if (sc > 0) res = (sc < 32) ? (xop << sc) : 0; + else res = (sc > -32) ? (xop >> -sc) : (xop >> 31); + m_core.sr.sr |= res; + break; + case 0x06<<11: + /* ASHIFT (LO) */ + xop = SHIFT_GETXREG_SIGNED(xop); + if (sc > 0) res = (sc < 32) ? (xop << sc) : 0; + else res = (sc > -32) ? (xop >> -sc) : (xop >> 31); + m_core.sr.sr = res; + break; + case 0x07<<11: + /* ASHIFT (LO, OR) */ + xop = SHIFT_GETXREG_SIGNED(xop); + if (sc > 0) res = (sc < 32) ? (xop << sc) : 0; + else res = (sc > -32) ? (xop >> -sc) : (xop >> 31); + m_core.sr.sr |= res; + break; + case 0x08<<11: + /* NORM (HI) */ + xop = SHIFT_GETXREG_SIGNED(xop) << 16; + if (sc > 0) + { + xop = ((UINT32)xop >> 1) | ((m_astat & CFLAG) << 28); + res = xop >> (sc - 1); + } + else res = (sc > -32) ? (xop << -sc) : 0; + m_core.sr.sr = res; + break; + case 0x09<<11: + /* NORM (HI, OR) */ + xop = SHIFT_GETXREG_SIGNED(xop) << 16; + if (sc > 0) + { + xop = ((UINT32)xop >> 1) | ((m_astat & CFLAG) << 28); + res = xop >> (sc - 1); + } + else res = (sc > -32) ? (xop << -sc) : 0; + m_core.sr.sr |= res; + break; + case 0x0a<<11: + /* NORM (LO) */ + xop = SHIFT_GETXREG_UNSIGNED(xop); + if (sc > 0) res = (sc < 32) ? (xop >> sc) : 0; + else res = (sc > -32) ? (xop << -sc) : 0; + m_core.sr.sr = res; + break; + case 0x0b<<11: + /* NORM (LO, OR) */ + xop = SHIFT_GETXREG_UNSIGNED(xop); + if (sc > 0) res = (sc < 32) ? (xop >> sc) : 0; + else res = (sc > -32) ? (xop << -sc) : 0; + m_core.sr.sr |= res; + break; + } +} diff --git a/src/devices/cpu/adsp2100/adsp2100.c b/src/devices/cpu/adsp2100/adsp2100.c new file mode 100644 index 00000000000..8142a6a7a34 --- /dev/null +++ b/src/devices/cpu/adsp2100/adsp2100.c @@ -0,0 +1,1908 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + ADSP2100.c + + ADSP-21xx series emulator. + +**************************************************************************** + + For ADSP-2101, ADSP-2111 + ------------------------ + + MMAP = 0 MMAP = 1 + + Automatic boot loading No auto boot loading + + Program Space: Program Space: + 0000-07ff = 2k Internal RAM (booted) 0000-37ff = 14k External access + 0800-3fff = 14k External access 3800-3fff = 2k Internal RAM + + Data Space: Data Space: + 0000-03ff = 1k External DWAIT0 0000-03ff = 1k External DWAIT0 + 0400-07ff = 1k External DWAIT1 0400-07ff = 1k External DWAIT1 + 0800-2fff = 10k External DWAIT2 0800-2fff = 10k External DWAIT2 + 3000-33ff = 1k External DWAIT3 3000-33ff = 1k External DWAIT3 + 3400-37ff = 1k External DWAIT4 3400-37ff = 1k External DWAIT4 + 3800-3bff = 1k Internal RAM 3800-3bff = 1k Internal RAM + 3c00-3fff = 1k Internal Control regs 3c00-3fff = 1k Internal Control regs + + + For ADSP-2105, ADSP-2115 + ------------------------ + + MMAP = 0 MMAP = 1 + + Automatic boot loading No auto boot loading + + Program Space: Program Space: + 0000-03ff = 1k Internal RAM (booted) 0000-37ff = 14k External access + 0400-07ff = 1k Reserved 3800-3bff = 1k Internal RAM + 0800-3fff = 14k External access 3c00-3fff = 1k Reserved + + Data Space: Data Space: + 0000-03ff = 1k External DWAIT0 0000-03ff = 1k External DWAIT0 + 0400-07ff = 1k External DWAIT1 0400-07ff = 1k External DWAIT1 + 0800-2fff = 10k External DWAIT2 0800-2fff = 10k External DWAIT2 + 3000-33ff = 1k External DWAIT3 3000-33ff = 1k External DWAIT3 + 3400-37ff = 1k External DWAIT4 3400-37ff = 1k External DWAIT4 + 3800-39ff = 512 Internal RAM 3800-39ff = 512 Internal RAM + 3a00-3bff = 512 Reserved 3a00-3bff = 512 Reserved + 3c00-3fff = 1k Internal Control regs 3c00-3fff = 1k Internal Control regs + + + For ADSP-2104 + ------------- + + MMAP = 0 MMAP = 1 + + Automatic boot loading No auto boot loading + + Program Space: Program Space: + 0000-01ff = 512 Internal RAM (booted) 0000-37ff = 14k External access + 0400-07ff = 1k Reserved 3800-3bff = 1k Internal RAM + 0800-3fff = 14k External access 3c00-3fff = 1k Reserved + + Data Space: Data Space: + 0000-03ff = 1k External DWAIT0 0000-03ff = 1k External DWAIT0 + 0400-07ff = 1k External DWAIT1 0400-07ff = 1k External DWAIT1 + 0800-2fff = 10k External DWAIT2 0800-2fff = 10k External DWAIT2 + 3000-33ff = 1k External DWAIT3 3000-33ff = 1k External DWAIT3 + 3400-37ff = 1k External DWAIT4 3400-37ff = 1k External DWAIT4 + 3800-38ff = 256 Internal RAM 3800-38ff = 256 Internal RAM + 3a00-3bff = 512 Reserved 3a00-3bff = 512 Reserved + 3c00-3fff = 1k Internal Control regs 3c00-3fff = 1k Internal Control regs + + + For ADSP-2181 + ------------- + + MMAP = 0 MMAP = 1 + + Program Space: Program Space: + 0000-1fff = 8k Internal RAM 0000-1fff = 8k External access + 2000-3fff = 8k Internal RAM or Overlay 2000-3fff = 8k Internal + + Data Space: Data Space: + 0000-1fff = 8k Internal RAM or Overlay 0000-1fff = 8k Internal RAM or Overlay + 2000-3fdf = 8k-32 Internal RAM 2000-3fdf = 8k-32 Internal RAM + 3fe0-3fff = 32 Internal Control regs 3fe0-3fff = 32 Internal Control regs + + I/O Space: I/O Space: + 0000-01ff = 512 External IOWAIT0 0000-01ff = 512 External IOWAIT0 + 0200-03ff = 512 External IOWAIT1 0200-03ff = 512 External IOWAIT1 + 0400-05ff = 512 External IOWAIT2 0400-05ff = 512 External IOWAIT2 + 0600-07ff = 512 External IOWAIT3 0600-07ff = 512 External IOWAIT3 + +***************************************************************************/ + +#include "emu.h" +#include "debugger.h" +#include "adsp2100.h" + + +// device type definitions +const device_type ADSP2100 = &device_creator; +const device_type ADSP2101 = &device_creator; +const device_type ADSP2104 = &device_creator; +const device_type ADSP2105 = &device_creator; +const device_type ADSP2115 = &device_creator; +const device_type ADSP2181 = &device_creator; + + +//************************************************************************** +// DEVICE INTERFACE +//************************************************************************** + +//------------------------------------------------- +// adsp21xx_device - constructor +//------------------------------------------------- + +adsp21xx_device::adsp21xx_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, UINT32 chiptype, const char *shortname, const char *source) + : cpu_device(mconfig, type, name, tag, owner, clock, shortname, source), + m_program_config("program", ENDIANNESS_LITTLE, 32, 14, -2), + m_data_config("data", ENDIANNESS_LITTLE, 16, 14, -1), + m_chip_type(chiptype), + m_pc(0), + m_ppc(0), + m_loop(0), + m_loop_condition(0), + m_cntr(0), + m_astat(0), + m_sstat(0), + m_mstat(0), + m_mstat_prev(0), + m_astat_clear(0), + m_idle(0), + m_px(0), + m_pc_sp(0), + m_cntr_sp(0), + m_stat_sp(0), + m_loop_sp(0), + m_flagout(0), + m_flagin(0), + m_fl0(0), + m_fl1(0), + m_fl2(0), + m_idma_addr(0), + m_idma_cache(0), + m_idma_offs(0), + m_imask(0), + m_icntl(0), + m_ifc(0), + m_icount(0), + m_mstat_mask((m_chip_type >= CHIP_TYPE_ADSP2101) ? 0x7f : 0x0f), + m_imask_mask((m_chip_type >= CHIP_TYPE_ADSP2181) ? 0x3ff : + (m_chip_type >= CHIP_TYPE_ADSP2101) ? 0x3f : 0x0f), + m_sport_rx_cb(*this), + m_sport_tx_cb(*this), + m_timer_fired_cb(*this) +{ + // initialize remaining state + memset(&m_core, 0, sizeof(m_core)); + memset(&m_alt, 0, sizeof(m_alt)); + memset(&m_i, 0, sizeof(m_i)); + memset(&m_m, 0, sizeof(m_m)); + memset(&m_l, 0, sizeof(m_l)); + memset(&m_lmask, 0, sizeof(m_lmask)); + memset(&m_base, 0, sizeof(m_base)); + memset(&m_loop_stack, 0, sizeof(m_loop_stack)); + memset(&m_cntr_stack, 0, sizeof(m_cntr_stack)); + memset(&m_pc_stack, 0, sizeof(m_pc_stack)); + memset(&m_stat_stack, 0, sizeof(m_stat_stack)); + memset(&m_irq_state, 0, sizeof(m_irq_state)); + memset(&m_irq_latch, 0, sizeof(m_irq_latch)); + + // create the tables + create_tables(); + + // set up read register group 0 pointers + m_read0_ptr[0x00] = &m_core.ax0.s; + m_read0_ptr[0x01] = &m_core.ax1.s; + m_read0_ptr[0x02] = &m_core.mx0.s; + m_read0_ptr[0x03] = &m_core.mx1.s; + m_read0_ptr[0x04] = &m_core.ay0.s; + m_read0_ptr[0x05] = &m_core.ay1.s; + m_read0_ptr[0x06] = &m_core.my0.s; + m_read0_ptr[0x07] = &m_core.my1.s; + m_read0_ptr[0x08] = &m_core.si.s; + m_read0_ptr[0x09] = &m_core.se.s; + m_read0_ptr[0x0a] = &m_core.ar.s; + m_read0_ptr[0x0b] = &m_core.mr.mrx.mr0.s; + m_read0_ptr[0x0c] = &m_core.mr.mrx.mr1.s; + m_read0_ptr[0x0d] = &m_core.mr.mrx.mr2.s; + m_read0_ptr[0x0e] = &m_core.sr.srx.sr0.s; + m_read0_ptr[0x0f] = &m_core.sr.srx.sr1.s; + + // set up read register group 1 + 2 pointers + for (int index = 0; index < 4; index++) + { + m_read1_ptr[0x00 + index] = &m_i[0 + index]; + m_read1_ptr[0x04 + index] = (UINT32 *)&m_m[0 + index]; + m_read1_ptr[0x08 + index] = &m_l[0 + index]; + m_read1_ptr[0x0c + index] = &m_l[0 + index]; + m_read2_ptr[0x00 + index] = &m_i[4 + index]; + m_read2_ptr[0x04 + index] = (UINT32 *)&m_m[4 + index]; + m_read2_ptr[0x08 + index] = &m_l[4 + index]; + m_read2_ptr[0x0c + index] = &m_l[4 + index]; + } + + // set up ALU register pointers + m_alu_xregs[0] = &m_core.ax0; + m_alu_xregs[1] = &m_core.ax1; + m_alu_xregs[2] = &m_core.ar; + m_alu_xregs[3] = &m_core.mr.mrx.mr0; + m_alu_xregs[4] = &m_core.mr.mrx.mr1; + m_alu_xregs[5] = &m_core.mr.mrx.mr2; + m_alu_xregs[6] = &m_core.sr.srx.sr0; + m_alu_xregs[7] = &m_core.sr.srx.sr1; + m_alu_yregs[0] = &m_core.ay0; + m_alu_yregs[1] = &m_core.ay1; + m_alu_yregs[2] = &m_core.af; + m_alu_yregs[3] = &m_core.zero; + + // set up MAC register pointers + m_mac_xregs[0] = &m_core.mx0; + m_mac_xregs[1] = &m_core.mx1; + m_mac_xregs[2] = &m_core.ar; + m_mac_xregs[3] = &m_core.mr.mrx.mr0; + m_mac_xregs[4] = &m_core.mr.mrx.mr1; + m_mac_xregs[5] = &m_core.mr.mrx.mr2; + m_mac_xregs[6] = &m_core.sr.srx.sr0; + m_mac_xregs[7] = &m_core.sr.srx.sr1; + m_mac_yregs[0] = &m_core.my0; + m_mac_yregs[1] = &m_core.my1; + m_mac_yregs[2] = &m_core.mf; + m_mac_yregs[3] = &m_core.zero; + + // set up shift register pointers + m_shift_xregs[0] = &m_core.si; + m_shift_xregs[1] = &m_core.si; + m_shift_xregs[2] = &m_core.ar; + m_shift_xregs[3] = &m_core.mr.mrx.mr0; + m_shift_xregs[4] = &m_core.mr.mrx.mr1; + m_shift_xregs[5] = &m_core.mr.mrx.mr2; + m_shift_xregs[6] = &m_core.sr.srx.sr0; + m_shift_xregs[7] = &m_core.sr.srx.sr1; +} + +adsp2100_device::adsp2100_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : adsp21xx_device(mconfig, ADSP2100, "ADSP-2100", tag, owner, clock, CHIP_TYPE_ADSP2100, "adsp2100", __FILE__) { } + +adsp2101_device::adsp2101_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : adsp21xx_device(mconfig, ADSP2101, "ADSP-2101", tag, owner, clock, CHIP_TYPE_ADSP2101, "adsp2101", __FILE__) { } + +adsp2101_device::adsp2101_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, UINT32 chiptype, const char *shortname, const char *source) + : adsp21xx_device(mconfig, type, name, tag, owner, clock, chiptype, shortname, source) { } + +adsp2104_device::adsp2104_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : adsp2101_device(mconfig, ADSP2104, "ADSP-2104", tag, owner, clock, CHIP_TYPE_ADSP2104, "adsp2104", __FILE__) { } + +adsp2105_device::adsp2105_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : adsp2101_device(mconfig, ADSP2105, "ADSP-2105", tag, owner, clock, CHIP_TYPE_ADSP2105, "adsp2105", __FILE__) { } + +adsp2115_device::adsp2115_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : adsp2101_device(mconfig, ADSP2115, "ADSP-2115", tag, owner, clock, CHIP_TYPE_ADSP2115, "adsp2115", __FILE__) { } + +adsp2181_device::adsp2181_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : adsp21xx_device(mconfig, ADSP2181, "ADSP-2181", tag, owner, clock, CHIP_TYPE_ADSP2181, "adsp2181", __FILE__), + m_io_config("I/O", ENDIANNESS_LITTLE, 16, 11, -1) { } + + +//------------------------------------------------- +// ~adsp21xx_device - destructor +//------------------------------------------------- + +adsp21xx_device::~adsp21xx_device() +{ +#if ADSP_TRACK_HOTSPOTS + FILE *log = fopen("adsp.hot", "w"); + while (1) + { + int maxindex = 0, i; + for (i = 1; i < 0x4000; i++) + if (m_pcbucket[i] > m_pcbucket[maxindex]) + maxindex = i; + if (m_pcbucket[maxindex] == 0) + break; + fprintf(log, "PC=%04X (%10d hits)\n", maxindex, pcbucket[maxindex]); + m_pcbucket[maxindex] = 0; + } + fclose(log); +#endif +} + + +//------------------------------------------------- +// load_boot_data - load the boot data from an +// 8-bit ROM +//------------------------------------------------- + +void adsp21xx_device::load_boot_data(UINT8 *srcdata, UINT32 *dstdata) +{ + // see how many words we need to copy + int pagelen = (srcdata[3] + 1) * 8; + for (int i = 0; i < pagelen; i++) + { + UINT32 opcode = (srcdata[i*4+0] << 16) | (srcdata[i*4+1] << 8) | srcdata[i*4+2]; + dstdata[i] = opcode; + } +} + + +//------------------------------------------------- +// idma_addr_w - write the IDMA address register +//------------------------------------------------- + +void adsp2181_device::idma_addr_w(UINT16 data) +{ + m_idma_addr = data; + m_idma_offs = 0; +} + + +//------------------------------------------------- +// idma_addr_r - read the IDMA address register +//------------------------------------------------- + +UINT16 adsp2181_device::idma_addr_r() +{ + return m_idma_addr; +} + + +//------------------------------------------------- +// idma_data_w - write the IDMA data register +//------------------------------------------------- + +void adsp2181_device::idma_data_w(UINT16 data) +{ + // program memory? + if (!(m_idma_addr & 0x4000)) + { + // upper 16 bits + if (m_idma_offs == 0) + { + m_idma_cache = data; + m_idma_offs = 1; + } + + // lower 8 bits + else + { + program_write(m_idma_addr++ & 0x3fff, (m_idma_cache << 8) | (data & 0xff)); + m_idma_offs = 0; + } + } + + // data memory + else + data_write(m_idma_addr++ & 0x3fff, data); +} + + +//------------------------------------------------- +// idma_data_r - read the IDMA data register +//------------------------------------------------- + +UINT16 adsp2181_device::idma_data_r() +{ + UINT16 result = 0xffff; + + // program memory? + if (!(m_idma_addr & 0x4000)) + { + // upper 16 bits + if (m_idma_offs == 0) + { + result = program_read(m_idma_addr & 0x3fff) >> 8; + m_idma_offs = 1; + } + + // lower 8 bits + else + { + result = program_read(m_idma_addr++ & 0x3fff) & 0xff; + m_idma_offs = 0; + } + } + + // data memory + else + result = data_read(m_idma_addr++ & 0x3fff); + + return result; +} + + +//------------------------------------------------- +// device_start - start up the device +//------------------------------------------------- + +void adsp21xx_device::device_start() +{ + m_sport_rx_cb.resolve(); + m_sport_tx_cb.resolve(); + m_timer_fired_cb.resolve(); + + // get our address spaces + m_program = &space(AS_PROGRAM); + m_direct = &m_program->direct(); + m_data = &space(AS_DATA); + m_io = has_space(AS_IO) ? &space(AS_IO) : NULL; + + // "core" + save_item(NAME(m_core.ax0.u)); + save_item(NAME(m_core.ax1.u)); + save_item(NAME(m_core.ay0.u)); + save_item(NAME(m_core.ay1.u)); + save_item(NAME(m_core.ar.u)); + save_item(NAME(m_core.af.u)); + save_item(NAME(m_core.mx0.u)); + save_item(NAME(m_core.mx1.u)); + save_item(NAME(m_core.my0.u)); + save_item(NAME(m_core.my1.u)); + save_item(NAME(m_core.mr.mr)); + save_item(NAME(m_core.mf.u)); + save_item(NAME(m_core.si.u)); + save_item(NAME(m_core.se.u)); + save_item(NAME(m_core.sb.u)); + save_item(NAME(m_core.sr.sr)); + save_item(NAME(m_core.zero.u)); + + // "alt" + save_item(NAME(m_alt.ax0.u)); + save_item(NAME(m_alt.ax1.u)); + save_item(NAME(m_alt.ay0.u)); + save_item(NAME(m_alt.ay1.u)); + save_item(NAME(m_alt.ar.u)); + save_item(NAME(m_alt.af.u)); + save_item(NAME(m_alt.mx0.u)); + save_item(NAME(m_alt.mx1.u)); + save_item(NAME(m_alt.my0.u)); + save_item(NAME(m_alt.my1.u)); + save_item(NAME(m_alt.mr.mr)); + save_item(NAME(m_alt.mf.u)); + save_item(NAME(m_alt.si.u)); + save_item(NAME(m_alt.se.u)); + save_item(NAME(m_alt.sb.u)); + save_item(NAME(m_alt.sr.sr)); + save_item(NAME(m_alt.zero.u)); + + save_item(NAME(m_i)); + save_item(NAME(m_m)); + save_item(NAME(m_l)); + save_item(NAME(m_lmask)); + save_item(NAME(m_base)); + save_item(NAME(m_px)); + + save_item(NAME(m_pc)); + save_item(NAME(m_ppc)); + save_item(NAME(m_loop)); + save_item(NAME(m_loop_condition)); + save_item(NAME(m_cntr)); + save_item(NAME(m_astat)); + save_item(NAME(m_sstat)); + save_item(NAME(m_mstat)); + save_item(NAME(m_mstat_prev)); + save_item(NAME(m_astat_clear)); + save_item(NAME(m_idle)); + + save_item(NAME(m_loop_stack)); + save_item(NAME(m_cntr_stack)); + save_item(NAME(m_pc_stack)); + save_item(NAME(m_stat_stack)); + + save_item(NAME(m_pc_sp)); + save_item(NAME(m_cntr_sp)); + save_item(NAME(m_stat_sp)); + save_item(NAME(m_loop_sp)); + + save_item(NAME(m_flagout)); + save_item(NAME(m_flagin)); + save_item(NAME(m_fl0)); + save_item(NAME(m_fl1)); + save_item(NAME(m_fl2)); + save_item(NAME(m_idma_addr)); + save_item(NAME(m_idma_cache)); + save_item(NAME(m_idma_offs)); + + save_item(NAME(m_imask)); + save_item(NAME(m_icntl)); + save_item(NAME(m_ifc)); + save_item(NAME(m_irq_state)); + save_item(NAME(m_irq_latch)); + + // register state with the debugger + state_add(ADSP2100_PC, "PC", m_pc); + state_add(STATE_GENPC, "GENPC", m_pc).noshow(); + state_add(STATE_GENPCBASE, "GENPCBASE", m_ppc).noshow(); + state_add(STATE_GENFLAGS, "GENFLAGS", m_astat).mask(0xff).noshow().formatstr("%8s"); + + state_add(ADSP2100_AX0, "AX0", m_core.ax0.u); + state_add(ADSP2100_AX1, "AX1", m_core.ax1.u); + state_add(ADSP2100_AY0, "AY0", m_core.ay0.u); + state_add(ADSP2100_AY1, "AY1", m_core.ay1.u); + state_add(ADSP2100_AR, "AR", m_core.ar.u); + state_add(ADSP2100_AF, "AF", m_core.af.u); + + state_add(ADSP2100_MX0, "MX0", m_core.mx0.u); + state_add(ADSP2100_MX1, "MX1", m_core.mx1.u); + state_add(ADSP2100_MY0, "MY0", m_core.my0.u); + state_add(ADSP2100_MY1, "MY1", m_core.my1.u); + state_add(ADSP2100_MR0, "MR0", m_core.mr.mrx.mr0.u); + state_add(ADSP2100_MR1, "MR1", m_core.mr.mrx.mr1.u); + state_add(ADSP2100_MR2, "MR2", m_core.mr.mrx.mr2.u).signed_mask(0xff); + state_add(ADSP2100_MF, "MF", m_core.mf.u); + + state_add(ADSP2100_SI, "SI", m_core.si.u); + state_add(ADSP2100_SE, "SE", m_core.se.u).signed_mask(0xff); + state_add(ADSP2100_SB, "SB", m_core.sb.u).signed_mask(0x1f); + state_add(ADSP2100_SR0, "SR0", m_core.sr.srx.sr0.u); + state_add(ADSP2100_SR1, "SR1", m_core.sr.srx.sr1.u); + + state_add(ADSP2100_AX0_SEC, "AX0_SEC", m_alt.ax0.u); + state_add(ADSP2100_AX1_SEC, "AX1_SEC", m_alt.ax1.u); + state_add(ADSP2100_AY0_SEC, "AY0_SEC", m_alt.ay0.u); + state_add(ADSP2100_AY1_SEC, "AY1_SEC", m_alt.ay1.u); + state_add(ADSP2100_AR_SEC, "AR_SEC", m_alt.ar.u); + state_add(ADSP2100_AF_SEC, "AF_SEC", m_alt.af.u); + + state_add(ADSP2100_MX0_SEC, "MX0_SEC", m_alt.mx0.u); + state_add(ADSP2100_MX1_SEC, "MX1_SEC", m_alt.mx1.u); + state_add(ADSP2100_MY0_SEC, "MY0_SEC", m_alt.my0.u); + state_add(ADSP2100_MY1_SEC, "MY1_SEC", m_alt.my1.u); + state_add(ADSP2100_MR0_SEC, "MR0_SEC", m_alt.mr.mrx.mr0.u); + state_add(ADSP2100_MR1_SEC, "MR1_SEC", m_alt.mr.mrx.mr1.u); + state_add(ADSP2100_MR2_SEC, "MR2_SEC", m_alt.mr.mrx.mr2.u).signed_mask(0xff); + state_add(ADSP2100_MF_SEC, "MF_SEC", m_alt.mf.u); + + state_add(ADSP2100_SI_SEC, "SI_SEC", m_alt.si.u); + state_add(ADSP2100_SE_SEC, "SE_SEC", m_alt.se.u).signed_mask(0xff); + state_add(ADSP2100_SB_SEC, "SB_SEC", m_alt.sb.u).signed_mask(0x1f); + state_add(ADSP2100_SR0_SEC, "SR0_SEC", m_alt.sr.srx.sr0.u); + state_add(ADSP2100_SR1_SEC, "SR1_SEC", m_alt.sr.srx.sr1.u); + + std::string tempstring; + for (int ireg = 0; ireg < 8; ireg++) + state_add(ADSP2100_I0 + ireg, strformat(tempstring, "I%d", ireg).c_str(), m_i[ireg]).mask(0x3fff).callimport(); + + for (int lreg = 0; lreg < 8; lreg++) + state_add(ADSP2100_L0 + lreg, strformat(tempstring, "L%d", lreg).c_str(), m_l[lreg]).mask(0x3fff).callimport(); + + for (int mreg = 0; mreg < 8; mreg++) + state_add(ADSP2100_M0 + mreg, strformat(tempstring, "M%d", mreg).c_str(), m_m[mreg]).signed_mask(0x3fff); + + state_add(ADSP2100_PX, "PX", m_px); + state_add(ADSP2100_CNTR, "CNTR", m_cntr).mask(0x3fff); + state_add(ADSP2100_ASTAT, "ASTAT", m_astat).mask(0xff); + state_add(ADSP2100_SSTAT, "SSTAT", m_sstat).mask(0xff); + state_add(ADSP2100_MSTAT, "MSTAT", m_mstat).mask((m_chip_type == CHIP_TYPE_ADSP2100) ? 0x0f : 0x7f).callimport(); + + state_add(ADSP2100_PCSP, "PCSP", m_pc_sp).mask(0xff); + state_add(STATE_GENSP, "GENSP", m_pc_sp).mask(0xff).noshow(); + state_add(ADSP2100_CNTRSP, "CNTRSP", m_cntr_sp).mask(0xf); + state_add(ADSP2100_STATSP, "STATSP", m_stat_sp).mask(0xf); + state_add(ADSP2100_LOOPSP, "LOOPSP", m_loop_sp).mask(0xf); + + state_add(ADSP2100_IMASK, "IMASK", m_imask).mask((m_chip_type == CHIP_TYPE_ADSP2100) ? 0x00f : (m_chip_type == CHIP_TYPE_ADSP2181) ? 0x3ff : 0x07f).callimport(); + state_add(ADSP2100_ICNTL, "ICNTL", m_icntl).mask(0x1f).callimport(); + + for (int irqnum = 0; irqnum < 4; irqnum++) + if (irqnum < 4 || m_chip_type == CHIP_TYPE_ADSP2100) + state_add(ADSP2100_IRQSTATE0 + irqnum, strformat(tempstring, "IRQ%d", irqnum).c_str(), m_irq_state[irqnum]).mask(1).callimport(); + + state_add(ADSP2100_FLAGIN, "FLAGIN", m_flagin).mask(1); + state_add(ADSP2100_FLAGOUT, "FLAGOUT", m_flagout).mask(1); + state_add(ADSP2100_FL0, "FL0", m_fl0).mask(1); + state_add(ADSP2100_FL1, "FL1", m_fl1).mask(1); + state_add(ADSP2100_FL2, "FL2", m_fl2).mask(1); + + // set our instruction counter + m_icountptr = &m_icount; +} + + +//------------------------------------------------- +// device_reset - reset the device +//------------------------------------------------- + +void adsp21xx_device::device_reset() +{ + // ensure that zero is zero + m_core.zero.u = m_alt.zero.u = 0; + + // recompute the memory registers with their current values + write_reg1(0x08, m_l[0]); write_reg1(0x00, m_i[0]); + write_reg1(0x09, m_l[1]); write_reg1(0x01, m_i[1]); + write_reg1(0x0a, m_l[2]); write_reg1(0x02, m_i[2]); + write_reg1(0x0b, m_l[3]); write_reg1(0x03, m_i[3]); + write_reg2(0x08, m_l[4]); write_reg2(0x00, m_i[4]); + write_reg2(0x09, m_l[5]); write_reg2(0x01, m_i[5]); + write_reg2(0x0a, m_l[6]); write_reg2(0x02, m_i[6]); + write_reg2(0x0b, m_l[7]); write_reg2(0x03, m_i[7]); + + // reset PC and loops + m_pc = (m_chip_type >= CHIP_TYPE_ADSP2101) ? 0 : 4; + m_ppc = -1; + m_loop = 0xffff; + m_loop_condition = 0; + + // reset status registers + m_astat_clear = ~(CFLAG | VFLAG | NFLAG | ZFLAG); + m_mstat = 0; + m_sstat = 0x55; + m_idle = 0; + update_mstat(); + + // reset stacks + m_pc_sp = 0; + m_cntr_sp = 0; + m_stat_sp = 0; + m_loop_sp = 0; + + // reset external I/O + m_flagout = 0; + m_flagin = 0; + m_fl0 = 0; + m_fl1 = 0; + m_fl2 = 0; + + // reset interrupts + m_imask = 0; + for (int irq = 0; irq < 8; irq++) + m_irq_state[irq] = m_irq_latch[irq] = CLEAR_LINE; +} + + +//------------------------------------------------- +// memory_space_config - return the configuration +// of the specified address space, or NULL if +// the space doesn't exist +//------------------------------------------------- + +const address_space_config *adsp2100_device::memory_space_config(address_spacenum spacenum) const +{ + return (spacenum == AS_PROGRAM) ? &m_program_config : + (spacenum == AS_DATA) ? &m_data_config : + NULL; +} + +const address_space_config *adsp2101_device::memory_space_config(address_spacenum spacenum) const +{ + return (spacenum == AS_PROGRAM) ? &m_program_config : + (spacenum == AS_DATA) ? &m_data_config : + NULL; +} + +const address_space_config *adsp2181_device::memory_space_config(address_spacenum spacenum) const +{ + return (spacenum == AS_PROGRAM) ? &m_program_config : + (spacenum == AS_DATA) ? &m_data_config : + (spacenum == AS_IO) ? &m_io_config : + NULL; +} + + +//------------------------------------------------- +// state_import - import state into the device, +// after it has been set +//------------------------------------------------- + +void adsp21xx_device::state_import(const device_state_entry &entry) +{ + switch (entry.index()) + { + case ADSP2100_MSTAT: + update_mstat(); + break; + + case ADSP2100_IMASK: + case ADSP2100_ICNTL: + case ADSP2100_IRQSTATE0: + case ADSP2100_IRQSTATE1: + case ADSP2100_IRQSTATE2: + case ADSP2100_IRQSTATE3: + check_irqs(); + break; + + case ADSP2100_I0: + case ADSP2100_I1: + case ADSP2100_I2: + case ADSP2100_I3: + case ADSP2100_I4: + case ADSP2100_I5: + case ADSP2100_I6: + case ADSP2100_I7: + update_i(entry.index() - ADSP2100_I0); + break; + + case ADSP2100_L0: + case ADSP2100_L1: + case ADSP2100_L2: + case ADSP2100_L3: + case ADSP2100_L4: + case ADSP2100_L5: + case ADSP2100_L6: + case ADSP2100_L7: + update_l(entry.index() - ADSP2100_L0); + break; + + default: + fatalerror("CPU_IMPORT_STATE(adsp21xx) called for unexpected value\n"); + } +} + + +//------------------------------------------------- +// state_string_export - export state as a string +// for the debugger +//------------------------------------------------- + +void adsp21xx_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + switch (entry.index()) + { + case STATE_GENFLAGS: + strprintf(str, "%c%c%c%c%c%c%c%c", + m_astat & 0x80 ? 'X':'.', + m_astat & 0x40 ? 'M':'.', + m_astat & 0x20 ? 'Q':'.', + m_astat & 0x10 ? 'S':'.', + m_astat & 0x08 ? 'C':'.', + m_astat & 0x04 ? 'V':'.', + m_astat & 0x02 ? 'N':'.', + m_astat & 0x01 ? 'Z':'.'); + break; + } +} + + +//------------------------------------------------- +// disasm_min_opcode_bytes - return the length +// of the shortest instruction, in bytes +//------------------------------------------------- + +UINT32 adsp21xx_device::disasm_min_opcode_bytes() const +{ + return 4; +} + + +//------------------------------------------------- +// disasm_max_opcode_bytes - return the length +// of the longest instruction, in bytes +//------------------------------------------------- + +UINT32 adsp21xx_device::disasm_max_opcode_bytes() const +{ + return 4; +} + + +//------------------------------------------------- +// disasm_disassemble - call the disassembly +// helper function +//------------------------------------------------- + +offs_t adsp21xx_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( adsp21xx ); + return CPU_DISASSEMBLE_NAME(adsp21xx)(this, buffer, pc, oprom, opram, options); +} + + + + +/*************************************************************************** + MEMORY ACCESSORS +***************************************************************************/ + +inline UINT16 adsp21xx_device::data_read(UINT32 addr) +{ + return m_data->read_word(addr << 1); +} + +inline void adsp21xx_device::data_write(UINT32 addr, UINT16 data) +{ + m_data->write_word(addr << 1, data); +} + +inline UINT16 adsp21xx_device::io_read(UINT32 addr) +{ + return m_io->read_word(addr << 1); +} + +inline void adsp21xx_device::io_write(UINT32 addr, UINT16 data) +{ + m_io->write_word(addr << 1, data); +} + +inline UINT32 adsp21xx_device::program_read(UINT32 addr) +{ + return m_program->read_dword(addr << 2); +} + +inline void adsp21xx_device::program_write(UINT32 addr, UINT32 data) +{ + m_program->write_dword(addr << 2, data & 0xffffff); +} + +inline UINT32 adsp21xx_device::opcode_read() +{ + return m_direct->read_dword(m_pc << 2); +} + + +/*************************************************************************** + IMPORT CORE UTILITIES +***************************************************************************/ + +#include "2100ops.inc" + + + +/*************************************************************************** + IRQ HANDLING +***************************************************************************/ + +bool adsp2100_device::generate_irq(int which, int indx) +{ + // skip if masked + if (!(m_imask & (1 << which))) + return false; + + // clear the latch + m_irq_latch[which] = 0; + + // push the PC and the status + pc_stack_push(); + stat_stack_push(); + + // vector to location & stop idling + m_pc = indx; + m_idle = 0; + + // mask other interrupts based on the nesting bit + if (m_icntl & 0x10) m_imask &= ~((2 << which) - 1); + else m_imask &= ~0xf; + + return true; +} + + +bool adsp2101_device::generate_irq(int which, int indx) +{ + // skip if masked + if (!(m_imask & (0x20 >> indx))) + return false; + + // clear the latch + m_irq_latch[which] = 0; + + // push the PC and the status + pc_stack_push(); + stat_stack_push(); + + // vector to location & stop idling + m_pc = 0x04 + indx * 4; + m_idle = 0; + + // mask other interrupts based on the nesting bit + if (m_icntl & 0x10) m_imask &= ~(0x3f >> indx); + else m_imask &= ~0x3f; + + return true; +} + + +bool adsp2181_device::generate_irq(int which, int indx) +{ + // skip if masked + if (!(m_imask & (0x200 >> indx))) + return false; + + // clear the latch + m_irq_latch[which] = 0; + + // push the PC and the status + pc_stack_push(); + stat_stack_push(); + + // vector to location & stop idling + m_pc = 0x04 + indx * 4; + m_idle = 0; + + // mask other interrupts based on the nesting bit + if (m_icntl & 0x10) m_imask &= ~(0x3ff >> indx); + else m_imask &= ~0x3ff; + + return true; +} + + +void adsp2100_device::check_irqs() +{ + UINT8 check; + + // check IRQ3 + check = (m_icntl & 8) ? m_irq_latch[ADSP2100_IRQ3] : m_irq_state[ADSP2100_IRQ3]; + if (check && generate_irq(ADSP2100_IRQ3, 3)) + return; + + // check IRQ2 + check = (m_icntl & 4) ? m_irq_latch[ADSP2100_IRQ2] : m_irq_state[ADSP2100_IRQ2]; + if (check && generate_irq(ADSP2100_IRQ2, 2)) + return; + + // check IRQ1 + check = (m_icntl & 2) ? m_irq_latch[ADSP2100_IRQ1] : m_irq_state[ADSP2100_IRQ1]; + if (check && generate_irq(ADSP2100_IRQ1, 1)) + return; + + // check IRQ0 + check = (m_icntl & 1) ? m_irq_latch[ADSP2100_IRQ0] : m_irq_state[ADSP2100_IRQ0]; + if (check && generate_irq(ADSP2100_IRQ0, 0)) + return; +} + + +void adsp2101_device::check_irqs() +{ + UINT8 check; + + // check IRQ2 + check = (m_icntl & 4) ? m_irq_latch[ADSP2101_IRQ2] : m_irq_state[ADSP2101_IRQ2]; + if (check && generate_irq(ADSP2101_IRQ2, 0)) + return; + + // check SPORT0 transmit + check = m_irq_latch[ADSP2101_SPORT0_TX]; + if (check && generate_irq(ADSP2101_SPORT0_TX, 1)) + return; + + // check SPORT0 receive + check = m_irq_latch[ADSP2101_SPORT0_RX]; + if (check && generate_irq(ADSP2101_SPORT0_RX, 2)) + return; + + // check IRQ1/SPORT1 transmit + check = (m_icntl & 2) ? m_irq_latch[ADSP2101_IRQ1] : m_irq_state[ADSP2101_IRQ1]; + if (check && generate_irq(ADSP2101_IRQ1, 3)) + return; + + // check IRQ0/SPORT1 receive + check = (m_icntl & 1) ? m_irq_latch[ADSP2101_IRQ0] : m_irq_state[ADSP2101_IRQ0]; + if (check && generate_irq(ADSP2101_IRQ0, 4)) + return; + + // check timer + check = m_irq_latch[ADSP2101_TIMER]; + if (check && generate_irq(ADSP2101_TIMER, 5)) + return; +} + + +void adsp2181_device::check_irqs() +{ + UINT8 check; + + // check IRQ2 + check = (m_icntl & 4) ? m_irq_latch[ADSP2181_IRQ2] : m_irq_state[ADSP2181_IRQ2]; + if (check && generate_irq(ADSP2181_IRQ2, 0)) + return; + + // check IRQL1 + check = m_irq_state[ADSP2181_IRQL1]; + if (check && generate_irq(ADSP2181_IRQL1, 1)) + return; + + // check IRQL2 + check = m_irq_state[ADSP2181_IRQL2]; + if (check && generate_irq(ADSP2181_IRQL2, 2)) + return; + + // check SPORT0 transmit + check = m_irq_latch[ADSP2181_SPORT0_TX]; + if (check && generate_irq(ADSP2181_SPORT0_TX, 3)) + return; + + // check SPORT0 receive + check = m_irq_latch[ADSP2181_SPORT0_RX]; + if (check && generate_irq(ADSP2181_SPORT0_RX, 4)) + return; + + // check IRQE + check = m_irq_latch[ADSP2181_IRQE]; + if (check && generate_irq(ADSP2181_IRQE, 5)) + return; + + // check BDMA interrupt + + // check IRQ1/SPORT1 transmit + check = (m_icntl & 2) ? m_irq_latch[ADSP2181_IRQ1] : m_irq_state[ADSP2181_IRQ1]; + if (check && generate_irq(ADSP2181_IRQ1, 7)) + return; + + // check IRQ0/SPORT1 receive + check = (m_icntl & 1) ? m_irq_latch[ADSP2181_IRQ0] : m_irq_state[ADSP2181_IRQ0]; + if (check && generate_irq(ADSP2181_IRQ0, 8)) + return; + + // check timer + check = m_irq_latch[ADSP2181_TIMER]; + if (check && generate_irq(ADSP2181_TIMER, 9)) + return; +} + + + +/*************************************************************************** + INITIALIZATION AND SHUTDOWN +***************************************************************************/ + +void adsp21xx_device::create_tables() +{ + // initialize the bit reversing table + for (int i = 0; i < 0x4000; i++) + { + UINT16 data = 0; + + data |= (i >> 13) & 0x0001; + data |= (i >> 11) & 0x0002; + data |= (i >> 9) & 0x0004; + data |= (i >> 7) & 0x0008; + data |= (i >> 5) & 0x0010; + data |= (i >> 3) & 0x0020; + data |= (i >> 1) & 0x0040; + data |= (i << 1) & 0x0080; + data |= (i << 3) & 0x0100; + data |= (i << 5) & 0x0200; + data |= (i << 7) & 0x0400; + data |= (i << 9) & 0x0800; + data |= (i << 11) & 0x1000; + data |= (i << 13) & 0x2000; + + m_reverse_table[i] = data; + } + + // initialize the mask table + for (int i = 0; i < 0x4000; i++) + { + if (i > 0x2000) m_mask_table[i] = 0x0000; + else if (i > 0x1000) m_mask_table[i] = 0x2000; + else if (i > 0x0800) m_mask_table[i] = 0x3000; + else if (i > 0x0400) m_mask_table[i] = 0x3800; + else if (i > 0x0200) m_mask_table[i] = 0x3c00; + else if (i > 0x0100) m_mask_table[i] = 0x3e00; + else if (i > 0x0080) m_mask_table[i] = 0x3f00; + else if (i > 0x0040) m_mask_table[i] = 0x3f80; + else if (i > 0x0020) m_mask_table[i] = 0x3fc0; + else if (i > 0x0010) m_mask_table[i] = 0x3fe0; + else if (i > 0x0008) m_mask_table[i] = 0x3ff0; + else if (i > 0x0004) m_mask_table[i] = 0x3ff8; + else if (i > 0x0002) m_mask_table[i] = 0x3ffc; + else if (i > 0x0001) m_mask_table[i] = 0x3ffe; + else m_mask_table[i] = 0x3fff; + } + + // initialize the condition table + for (int i = 0; i < 0x100; i++) + { + int az = ((i & ZFLAG) != 0); + int an = ((i & NFLAG) != 0); + int av = ((i & VFLAG) != 0); + int ac = ((i & CFLAG) != 0); + int mv = ((i & MVFLAG) != 0); + int as = ((i & SFLAG) != 0); + + m_condition_table[i | 0x000] = az; + m_condition_table[i | 0x100] = !az; + m_condition_table[i | 0x200] = !((an ^ av) | az); + m_condition_table[i | 0x300] = (an ^ av) | az; + m_condition_table[i | 0x400] = an ^ av; + m_condition_table[i | 0x500] = !(an ^ av); + m_condition_table[i | 0x600] = av; + m_condition_table[i | 0x700] = !av; + m_condition_table[i | 0x800] = ac; + m_condition_table[i | 0x900] = !ac; + m_condition_table[i | 0xa00] = as; + m_condition_table[i | 0xb00] = !as; + m_condition_table[i | 0xc00] = mv; + m_condition_table[i | 0xd00] = !mv; + m_condition_table[i | 0xf00] = 1; + } +} + + + +/*************************************************************************** + CORE EXECUTION LOOP +***************************************************************************/ + +//------------------------------------------------- +// execute_min_cycles - return minimum number of +// cycles it takes for one instruction to execute +//------------------------------------------------- + +UINT32 adsp21xx_device::execute_min_cycles() const +{ + return 1; +} + + +//------------------------------------------------- +// execute_max_cycles - return maximum number of +// cycles it takes for one instruction to execute +//------------------------------------------------- + +UINT32 adsp21xx_device::execute_max_cycles() const +{ + return 1; +} + + +//------------------------------------------------- +// execute_input_lines - return the number of +// input/interrupt lines +//------------------------------------------------- + +UINT32 adsp2100_device::execute_input_lines() const +{ + return 4; +} + +UINT32 adsp2101_device::execute_input_lines() const +{ + return 5; +} + +UINT32 adsp2181_device::execute_input_lines() const +{ + return 9; +} + + +void adsp21xx_device::execute_set_input(int inputnum, int state) +{ + // update the latched state + if (state != CLEAR_LINE && m_irq_state[inputnum] == CLEAR_LINE) + m_irq_latch[inputnum] = 1; + + // update the absolute state + m_irq_state[inputnum] = state; +} + + +void adsp21xx_device::execute_run() +{ + bool check_debugger = ((device_t::machine().debug_flags & DEBUG_FLAG_ENABLED) != 0); + + check_irqs(); + + do + { + // debugging + m_ppc = m_pc; // copy PC to previous PC + if (check_debugger) + debugger_instruction_hook(this, m_pc); + +#if ADSP_TRACK_HOTSPOTS + m_pcbucket[m_pc & 0x3fff]++; +#endif + + // instruction fetch + UINT32 op = opcode_read(); + + // advance to the next instruction + if (m_pc != m_loop) + m_pc++; + + // handle looping + else + { + // condition not met, keep looping + if (condition(m_loop_condition)) + m_pc = pc_stack_top(); + + // condition met; pop the PC and loop stacks and fall through + else + { + loop_stack_pop(); + pc_stack_pop_val(); + m_pc++; + } + } + + // parse the instruction + UINT32 temp; + switch ((op >> 16) & 0xff) + { + case 0x00: + // 00000000 00000000 00000000 NOP + break; + case 0x01: + // 00000001 0xxxxxxx xxxxxxxx dst = IO(x) + // 00000001 1xxxxxxx xxxxxxxx IO(x) = dst + // ADSP-218x only + if (m_chip_type >= CHIP_TYPE_ADSP2181) + { + if ((op & 0x008000) == 0x000000) + write_reg0(op & 15, io_read((op >> 4) & 0x7ff)); + else + io_write((op >> 4) & 0x7ff, read_reg0(op & 15)); + } + break; + case 0x02: + // 00000010 0000xxxx xxxxxxxx modify flag out + // 00000010 10000000 00000000 idle + // 00000010 10000000 0000xxxx idle (n) + if (op & 0x008000) + { + m_idle = 1; + m_icount = 0; + } + else + { + if (condition(op & 15)) + { + if (op & 0x020) m_flagout = 0; + if (op & 0x010) m_flagout ^= 1; + if (m_chip_type >= CHIP_TYPE_ADSP2101) + { + if (op & 0x080) m_fl0 = 0; + if (op & 0x040) m_fl0 ^= 1; + if (op & 0x200) m_fl1 = 0; + if (op & 0x100) m_fl1 ^= 1; + if (op & 0x800) m_fl2 = 0; + if (op & 0x400) m_fl2 ^= 1; + } + } + } + break; + case 0x03: + // 00000011 xxxxxxxx xxxxxxxx call or jump on flag in + if (op & 0x000002) + { + if (m_flagin) + { + if (op & 0x000001) + pc_stack_push(); + m_pc = ((op >> 4) & 0x0fff) | ((op << 10) & 0x3000); + } + } + else + { + if (!m_flagin) + { + if (op & 0x000001) + pc_stack_push(); + m_pc = ((op >> 4) & 0x0fff) | ((op << 10) & 0x3000); + } + } + break; + case 0x04: + // 00000100 00000000 000xxxxx stack control + if (op & 0x000010) pc_stack_pop_val(); + if (op & 0x000008) loop_stack_pop(); + if (op & 0x000004) cntr_stack_pop(); + if (op & 0x000002) + { + if (op & 0x000001) stat_stack_pop(); + else stat_stack_push(); + } + break; + case 0x05: + // 00000101 00000000 00000000 saturate MR + if (GET_MV) + { + if (m_core.mr.mrx.mr2.u & 0x80) + m_core.mr.mrx.mr2.u = 0xffff, m_core.mr.mrx.mr1.u = 0x8000, m_core.mr.mrx.mr0.u = 0x0000; + else + m_core.mr.mrx.mr2.u = 0x0000, m_core.mr.mrx.mr1.u = 0x7fff, m_core.mr.mrx.mr0.u = 0xffff; + } + break; + case 0x06: + // 00000110 000xxxxx 00000000 DIVS + { + int xop = (op >> 8) & 7; + int yop = (op >> 11) & 3; + + xop = ALU_GETXREG_UNSIGNED(xop); + yop = ALU_GETYREG_UNSIGNED(yop); + + temp = xop ^ yop; + m_astat = (m_astat & ~QFLAG) | ((temp >> 10) & QFLAG); + m_core.af.u = (yop << 1) | (m_core.ay0.u >> 15); + m_core.ay0.u = (m_core.ay0.u << 1) | (temp >> 15); + } + break; + case 0x07: + // 00000111 00010xxx 00000000 DIVQ + { + int xop = (op >> 8) & 7; + int res; + + xop = ALU_GETXREG_UNSIGNED(xop); + + if (GET_Q) + res = m_core.af.u + xop; + else + res = m_core.af.u - xop; + + temp = res ^ xop; + m_astat = (m_astat & ~QFLAG) | ((temp >> 10) & QFLAG); + m_core.af.u = (res << 1) | (m_core.ay0.u >> 15); + m_core.ay0.u = (m_core.ay0.u << 1) | ((~temp >> 15) & 0x0001); + } + break; + case 0x08: + // 00001000 00000000 0000xxxx reserved + break; + case 0x09: + // 00001001 00000000 000xxxxx modify address register + temp = (op >> 2) & 4; + modify_address(temp + ((op >> 2) & 3), temp + (op & 3)); + break; + case 0x0a: + // 00001010 00000000 000xxxxx conditional return + if (condition(op & 15)) + { + pc_stack_pop(); + + // RTI case + if (op & 0x000010) + stat_stack_pop(); + } + break; + case 0x0b: + // 00001011 00000000 xxxxxxxx conditional jump (indirect address) + if (condition(op & 15)) + { + if (op & 0x000010) + pc_stack_push(); + m_pc = m_i[4 + ((op >> 6) & 3)] & 0x3fff; + } + break; + case 0x0c: + // 00001100 xxxxxxxx xxxxxxxx mode control + if (m_chip_type >= CHIP_TYPE_ADSP2101) + { + if (op & 0x000008) m_mstat = (m_mstat & ~MSTAT_GOMODE) | ((op << 5) & MSTAT_GOMODE); + if (op & 0x002000) m_mstat = (m_mstat & ~MSTAT_INTEGER) | ((op >> 8) & MSTAT_INTEGER); + if (op & 0x008000) m_mstat = (m_mstat & ~MSTAT_TIMER) | ((op >> 9) & MSTAT_TIMER); + } + if (op & 0x000020) m_mstat = (m_mstat & ~MSTAT_BANK) | ((op >> 4) & MSTAT_BANK); + if (op & 0x000080) m_mstat = (m_mstat & ~MSTAT_REVERSE) | ((op >> 5) & MSTAT_REVERSE); + if (op & 0x000200) m_mstat = (m_mstat & ~MSTAT_STICKYV) | ((op >> 6) & MSTAT_STICKYV); + if (op & 0x000800) m_mstat = (m_mstat & ~MSTAT_SATURATE) | ((op >> 7) & MSTAT_SATURATE); + update_mstat(); + break; + case 0x0d: + // 00001101 0000xxxx xxxxxxxx internal data move + switch ((op >> 8) & 15) + { + case 0x00: write_reg0((op >> 4) & 15, read_reg0(op & 15)); break; + case 0x01: write_reg0((op >> 4) & 15, read_reg1(op & 15)); break; + case 0x02: write_reg0((op >> 4) & 15, read_reg2(op & 15)); break; + case 0x03: write_reg0((op >> 4) & 15, read_reg3(op & 15)); break; + case 0x04: write_reg1((op >> 4) & 15, read_reg0(op & 15)); break; + case 0x05: write_reg1((op >> 4) & 15, read_reg1(op & 15)); break; + case 0x06: write_reg1((op >> 4) & 15, read_reg2(op & 15)); break; + case 0x07: write_reg1((op >> 4) & 15, read_reg3(op & 15)); break; + case 0x08: write_reg2((op >> 4) & 15, read_reg0(op & 15)); break; + case 0x09: write_reg2((op >> 4) & 15, read_reg1(op & 15)); break; + case 0x0a: write_reg2((op >> 4) & 15, read_reg2(op & 15)); break; + case 0x0b: write_reg2((op >> 4) & 15, read_reg3(op & 15)); break; + case 0x0c: write_reg3((op >> 4) & 15, read_reg0(op & 15)); break; + case 0x0d: write_reg3((op >> 4) & 15, read_reg1(op & 15)); break; + case 0x0e: write_reg3((op >> 4) & 15, read_reg2(op & 15)); break; + case 0x0f: write_reg3((op >> 4) & 15, read_reg3(op & 15)); break; + } + break; + case 0x0e: + // 00001110 0xxxxxxx xxxxxxxx conditional shift + if (condition(op & 15)) shift_op(op); + break; + case 0x0f: + // 00001111 0xxxxxxx xxxxxxxx shift immediate + shift_op_imm(op); + break; + case 0x10: + // 00010000 0xxxxxxx xxxxxxxx shift with internal data register move + shift_op(op); + temp = read_reg0(op & 15); + write_reg0((op >> 4) & 15, temp); + break; + case 0x11: + // 00010001 xxxxxxxx xxxxxxxx shift with pgm memory read/write + if (op & 0x8000) + { + pgm_write_dag2(op, read_reg0((op >> 4) & 15)); + shift_op(op); + } + else + { + shift_op(op); + write_reg0((op >> 4) & 15, pgm_read_dag2(op)); + } + break; + case 0x12: + // 00010010 xxxxxxxx xxxxxxxx shift with data memory read/write DAG1 + if (op & 0x8000) + { + data_write_dag1(op, read_reg0((op >> 4) & 15)); + shift_op(op); + } + else + { + shift_op(op); + write_reg0((op >> 4) & 15, data_read_dag1(op)); + } + break; + case 0x13: + // 00010011 xxxxxxxx xxxxxxxx shift with data memory read/write DAG2 + if (op & 0x8000) + { + data_write_dag2(op, read_reg0((op >> 4) & 15)); + shift_op(op); + } + else + { + shift_op(op); + write_reg0((op >> 4) & 15, data_read_dag2(op)); + } + break; + case 0x14: case 0x15: case 0x16: case 0x17: + // 000101xx xxxxxxxx xxxxxxxx do until + loop_stack_push(op & 0x3ffff); + pc_stack_push(); + break; + case 0x18: case 0x19: case 0x1a: case 0x1b: + // 000110xx xxxxxxxx xxxxxxxx conditional jump (immediate addr) + if (condition(op & 15)) + { + m_pc = (op >> 4) & 0x3fff; + // check for a busy loop + if (m_pc == m_ppc) + m_icount = 0; + } + break; + case 0x1c: case 0x1d: case 0x1e: case 0x1f: + // 000111xx xxxxxxxx xxxxxxxx conditional call (immediate addr) + if (condition(op & 15)) + { + pc_stack_push(); + m_pc = (op >> 4) & 0x3fff; + } + break; + case 0x20: case 0x21: + // 0010000x xxxxxxxx xxxxxxxx conditional MAC to MR + if (condition(op & 15)) + { + if (m_chip_type >= CHIP_TYPE_ADSP2181 && (op & 0x0018f0) == 0x000010) + mac_op_mr_xop(op); + else + mac_op_mr(op); + } + break; + case 0x22: case 0x23: + // 0010001x xxxxxxxx xxxxxxxx conditional ALU to AR + if (condition(op & 15)) + { + if (m_chip_type >= CHIP_TYPE_ADSP2181 && (op & 0x000010) == 0x000010) + alu_op_ar_const(op); + else + alu_op_ar(op); + } + break; + case 0x24: case 0x25: + // 0010010x xxxxxxxx xxxxxxxx conditional MAC to MF + if (condition(op & 15)) + { + if (m_chip_type >= CHIP_TYPE_ADSP2181 && (op & 0x0018f0) == 0x000010) + mac_op_mf_xop(op); + else + mac_op_mf(op); + } + break; + case 0x26: case 0x27: + // 0010011x xxxxxxxx xxxxxxxx conditional ALU to AF + if (condition(op & 15)) + { + if (m_chip_type >= CHIP_TYPE_ADSP2181 && (op & 0x000010) == 0x000010) + alu_op_af_const(op); + else + alu_op_af(op); + } + break; + case 0x28: case 0x29: + // 0010100x xxxxxxxx xxxxxxxx MAC to MR with internal data register move + temp = read_reg0(op & 15); + mac_op_mr(op); + write_reg0((op >> 4) & 15, temp); + break; + case 0x2a: case 0x2b: + // 0010101x xxxxxxxx xxxxxxxx ALU to AR with internal data register move + if (m_chip_type >= CHIP_TYPE_ADSP2181 && (op & 0x0000ff) == 0x0000aa) + alu_op_none(op); + else + { + temp = read_reg0(op & 15); + alu_op_ar(op); + write_reg0((op >> 4) & 15, temp); + } + break; + case 0x2c: case 0x2d: + // 0010110x xxxxxxxx xxxxxxxx MAC to MF with internal data register move + temp = read_reg0(op & 15); + mac_op_mf(op); + write_reg0((op >> 4) & 15, temp); + break; + case 0x2e: case 0x2f: + // 0010111x xxxxxxxx xxxxxxxx ALU to AF with internal data register move + temp = read_reg0(op & 15); + alu_op_af(op); + write_reg0((op >> 4) & 15, temp); + break; + case 0x30: case 0x31: case 0x32: case 0x33: + // 001100xx xxxxxxxx xxxxxxxx load non-data register immediate (group 0) + write_reg0(op & 15, (INT32)(op << 14) >> 18); + break; + case 0x34: case 0x35: case 0x36: case 0x37: + // 001101xx xxxxxxxx xxxxxxxx load non-data register immediate (group 1) + write_reg1(op & 15, (INT32)(op << 14) >> 18); + break; + case 0x38: case 0x39: case 0x3a: case 0x3b: + // 001110xx xxxxxxxx xxxxxxxx load non-data register immediate (group 2) + write_reg2(op & 15, (INT32)(op << 14) >> 18); + break; + case 0x3c: case 0x3d: case 0x3e: case 0x3f: + // 001111xx xxxxxxxx xxxxxxxx load non-data register immediate (group 3) + write_reg3(op & 15, (INT32)(op << 14) >> 18); + break; + case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: case 0x46: case 0x47: + case 0x48: case 0x49: case 0x4a: case 0x4b: case 0x4c: case 0x4d: case 0x4e: case 0x4f: + // 0100xxxx xxxxxxxx xxxxxxxx load data register immediate + write_reg0(op & 15, (op >> 4) & 0xffff); + break; + case 0x50: case 0x51: + // 0101000x xxxxxxxx xxxxxxxx MAC to MR with pgm memory read + mac_op_mr(op); + write_reg0((op >> 4) & 15, pgm_read_dag2(op)); + break; + case 0x52: case 0x53: + // 0101001x xxxxxxxx xxxxxxxx ALU to AR with pgm memory read + alu_op_ar(op); + write_reg0((op >> 4) & 15, pgm_read_dag2(op)); + break; + case 0x54: case 0x55: + // 0101010x xxxxxxxx xxxxxxxx MAC to MF with pgm memory read + mac_op_mf(op); + write_reg0((op >> 4) & 15, pgm_read_dag2(op)); + break; + case 0x56: case 0x57: + // 0101011x xxxxxxxx xxxxxxxx ALU to AF with pgm memory read + alu_op_af(op); + write_reg0((op >> 4) & 15, pgm_read_dag2(op)); + break; + case 0x58: case 0x59: + // 0101100x xxxxxxxx xxxxxxxx MAC to MR with pgm memory write + pgm_write_dag2(op, read_reg0((op >> 4) & 15)); + mac_op_mr(op); + break; + case 0x5a: case 0x5b: + // 0101101x xxxxxxxx xxxxxxxx ALU to AR with pgm memory write + pgm_write_dag2(op, read_reg0((op >> 4) & 15)); + alu_op_ar(op); + break; + case 0x5c: case 0x5d: + // 0101110x xxxxxxxx xxxxxxxx ALU to MR with pgm memory write + pgm_write_dag2(op, read_reg0((op >> 4) & 15)); + mac_op_mf(op); + break; + case 0x5e: case 0x5f: + // 0101111x xxxxxxxx xxxxxxxx ALU to MF with pgm memory write + pgm_write_dag2(op, read_reg0((op >> 4) & 15)); + alu_op_af(op); + break; + case 0x60: case 0x61: + // 0110000x xxxxxxxx xxxxxxxx MAC to MR with data memory read DAG1 + mac_op_mr(op); + write_reg0((op >> 4) & 15, data_read_dag1(op)); + break; + case 0x62: case 0x63: + // 0110001x xxxxxxxx xxxxxxxx ALU to AR with data memory read DAG1 + alu_op_ar(op); + write_reg0((op >> 4) & 15, data_read_dag1(op)); + break; + case 0x64: case 0x65: + // 0110010x xxxxxxxx xxxxxxxx MAC to MF with data memory read DAG1 + mac_op_mf(op); + write_reg0((op >> 4) & 15, data_read_dag1(op)); + break; + case 0x66: case 0x67: + // 0110011x xxxxxxxx xxxxxxxx ALU to AF with data memory read DAG1 + alu_op_af(op); + write_reg0((op >> 4) & 15, data_read_dag1(op)); + break; + case 0x68: case 0x69: + // 0110100x xxxxxxxx xxxxxxxx MAC to MR with data memory write DAG1 + data_write_dag1(op, read_reg0((op >> 4) & 15)); + mac_op_mr(op); + break; + case 0x6a: case 0x6b: + // 0110101x xxxxxxxx xxxxxxxx ALU to AR with data memory write DAG1 + data_write_dag1(op, read_reg0((op >> 4) & 15)); + alu_op_ar(op); + break; + case 0x6c: case 0x6d: + // 0111110x xxxxxxxx xxxxxxxx MAC to MF with data memory write DAG1 + data_write_dag1(op, read_reg0((op >> 4) & 15)); + mac_op_mf(op); + break; + case 0x6e: case 0x6f: + // 0111111x xxxxxxxx xxxxxxxx ALU to AF with data memory write DAG1 + data_write_dag1(op, read_reg0((op >> 4) & 15)); + alu_op_af(op); + break; + case 0x70: case 0x71: + // 0111000x xxxxxxxx xxxxxxxx MAC to MR with data memory read DAG2 + mac_op_mr(op); + write_reg0((op >> 4) & 15, data_read_dag2(op)); + break; + case 0x72: case 0x73: + // 0111001x xxxxxxxx xxxxxxxx ALU to AR with data memory read DAG2 + alu_op_ar(op); + write_reg0((op >> 4) & 15, data_read_dag2(op)); + break; + case 0x74: case 0x75: + // 0111010x xxxxxxxx xxxxxxxx MAC to MF with data memory read DAG2 + mac_op_mf(op); + write_reg0((op >> 4) & 15, data_read_dag2(op)); + break; + case 0x76: case 0x77: + // 0111011x xxxxxxxx xxxxxxxx ALU to AF with data memory read DAG2 + alu_op_af(op); + write_reg0((op >> 4) & 15, data_read_dag2(op)); + break; + case 0x78: case 0x79: + // 0111100x xxxxxxxx xxxxxxxx MAC to MR with data memory write DAG2 + data_write_dag2(op, read_reg0((op >> 4) & 15)); + mac_op_mr(op); + break; + case 0x7a: case 0x7b: + // 0111101x xxxxxxxx xxxxxxxx ALU to AR with data memory write DAG2 + data_write_dag2(op, read_reg0((op >> 4) & 15)); + alu_op_ar(op); + break; + case 0x7c: case 0x7d: + // 0111110x xxxxxxxx xxxxxxxx MAC to MF with data memory write DAG2 + data_write_dag2(op, read_reg0((op >> 4) & 15)); + mac_op_mf(op); + break; + case 0x7e: case 0x7f: + // 0111111x xxxxxxxx xxxxxxxx ALU to AF with data memory write DAG2 + data_write_dag2(op, read_reg0((op >> 4) & 15)); + alu_op_af(op); + break; + case 0x80: case 0x81: case 0x82: case 0x83: + // 100000xx xxxxxxxx xxxxxxxx read data memory (immediate addr) to reg group 0 + write_reg0(op & 15, data_read((op >> 4) & 0x3fff)); + break; + case 0x84: case 0x85: case 0x86: case 0x87: + // 100001xx xxxxxxxx xxxxxxxx read data memory (immediate addr) to reg group 1 + write_reg1(op & 15, data_read((op >> 4) & 0x3fff)); + break; + case 0x88: case 0x89: case 0x8a: case 0x8b: + // 100010xx xxxxxxxx xxxxxxxx read data memory (immediate addr) to reg group 2 + write_reg2(op & 15, data_read((op >> 4) & 0x3fff)); + break; + case 0x8c: case 0x8d: case 0x8e: case 0x8f: + // 100011xx xxxxxxxx xxxxxxxx read data memory (immediate addr) to reg group 3 + write_reg3(op & 15, data_read((op >> 4) & 0x3fff)); + break; + case 0x90: case 0x91: case 0x92: case 0x93: + // 1001xxxx xxxxxxxx xxxxxxxx write data memory (immediate addr) from reg group 0 + data_write((op >> 4) & 0x3fff, read_reg0(op & 15)); + break; + case 0x94: case 0x95: case 0x96: case 0x97: + // 1001xxxx xxxxxxxx xxxxxxxx write data memory (immediate addr) from reg group 1 + data_write((op >> 4) & 0x3fff, read_reg1(op & 15)); + break; + case 0x98: case 0x99: case 0x9a: case 0x9b: + // 1001xxxx xxxxxxxx xxxxxxxx write data memory (immediate addr) from reg group 2 + data_write((op >> 4) & 0x3fff, read_reg2(op & 15)); + break; + case 0x9c: case 0x9d: case 0x9e: case 0x9f: + // 1001xxxx xxxxxxxx xxxxxxxx write data memory (immediate addr) from reg group 3 + data_write((op >> 4) & 0x3fff, read_reg3(op & 15)); + break; + case 0xa0: case 0xa1: case 0xa2: case 0xa3: case 0xa4: case 0xa5: case 0xa6: case 0xa7: + case 0xa8: case 0xa9: case 0xaa: case 0xab: case 0xac: case 0xad: case 0xae: case 0xaf: + // 1010xxxx xxxxxxxx xxxxxxxx data memory write (immediate) DAG1 + data_write_dag1(op, (op >> 4) & 0xffff); + break; + case 0xb0: case 0xb1: case 0xb2: case 0xb3: case 0xb4: case 0xb5: case 0xb6: case 0xb7: + case 0xb8: case 0xb9: case 0xba: case 0xbb: case 0xbc: case 0xbd: case 0xbe: case 0xbf: + // 1011xxxx xxxxxxxx xxxxxxxx data memory write (immediate) DAG2 + data_write_dag2(op, (op >> 4) & 0xffff); + break; + case 0xc0: case 0xc1: + // 1100000x xxxxxxxx xxxxxxxx MAC to MR with data read to AX0 & pgm read to AY0 + mac_op_mr(op); + m_core.ax0.u = data_read_dag1(op); + m_core.ay0.u = pgm_read_dag2(op >> 4); + break; + case 0xc2: case 0xc3: + // 1100001x xxxxxxxx xxxxxxxx ALU to AR with data read to AX0 & pgm read to AY0 + alu_op_ar(op); + m_core.ax0.u = data_read_dag1(op); + m_core.ay0.u = pgm_read_dag2(op >> 4); + break; + case 0xc4: case 0xc5: + // 1100010x xxxxxxxx xxxxxxxx MAC to MR with data read to AX1 & pgm read to AY0 + mac_op_mr(op); + m_core.ax1.u = data_read_dag1(op); + m_core.ay0.u = pgm_read_dag2(op >> 4); + break; + case 0xc6: case 0xc7: + // 1100011x xxxxxxxx xxxxxxxx ALU to AR with data read to AX1 & pgm read to AY0 + alu_op_ar(op); + m_core.ax1.u = data_read_dag1(op); + m_core.ay0.u = pgm_read_dag2(op >> 4); + break; + case 0xc8: case 0xc9: + // 1100100x xxxxxxxx xxxxxxxx MAC to MR with data read to MX0 & pgm read to AY0 + mac_op_mr(op); + m_core.mx0.u = data_read_dag1(op); + m_core.ay0.u = pgm_read_dag2(op >> 4); + break; + case 0xca: case 0xcb: + // 1100101x xxxxxxxx xxxxxxxx ALU to AR with data read to MX0 & pgm read to AY0 + alu_op_ar(op); + m_core.mx0.u = data_read_dag1(op); + m_core.ay0.u = pgm_read_dag2(op >> 4); + break; + case 0xcc: case 0xcd: + // 1100110x xxxxxxxx xxxxxxxx MAC to MR with data read to MX1 & pgm read to AY0 + mac_op_mr(op); + m_core.mx1.u = data_read_dag1(op); + m_core.ay0.u = pgm_read_dag2(op >> 4); + break; + case 0xce: case 0xcf: + // 1100111x xxxxxxxx xxxxxxxx ALU to AR with data read to MX1 & pgm read to AY0 + alu_op_ar(op); + m_core.mx1.u = data_read_dag1(op); + m_core.ay0.u = pgm_read_dag2(op >> 4); + break; + case 0xd0: case 0xd1: + // 1101000x xxxxxxxx xxxxxxxx MAC to MR with data read to AX0 & pgm read to AY1 + mac_op_mr(op); + m_core.ax0.u = data_read_dag1(op); + m_core.ay1.u = pgm_read_dag2(op >> 4); + break; + case 0xd2: case 0xd3: + // 1101001x xxxxxxxx xxxxxxxx ALU to AR with data read to AX0 & pgm read to AY1 + alu_op_ar(op); + m_core.ax0.u = data_read_dag1(op); + m_core.ay1.u = pgm_read_dag2(op >> 4); + break; + case 0xd4: case 0xd5: + // 1101010x xxxxxxxx xxxxxxxx MAC to MR with data read to AX1 & pgm read to AY1 + mac_op_mr(op); + m_core.ax1.u = data_read_dag1(op); + m_core.ay1.u = pgm_read_dag2(op >> 4); + break; + case 0xd6: case 0xd7: + // 1101011x xxxxxxxx xxxxxxxx ALU to AR with data read to AX1 & pgm read to AY1 + alu_op_ar(op); + m_core.ax1.u = data_read_dag1(op); + m_core.ay1.u = pgm_read_dag2(op >> 4); + break; + case 0xd8: case 0xd9: + // 1101100x xxxxxxxx xxxxxxxx MAC to MR with data read to MX0 & pgm read to AY1 + mac_op_mr(op); + m_core.mx0.u = data_read_dag1(op); + m_core.ay1.u = pgm_read_dag2(op >> 4); + break; + case 0xda: case 0xdb: + // 1101101x xxxxxxxx xxxxxxxx ALU to AR with data read to MX0 & pgm read to AY1 + alu_op_ar(op); + m_core.mx0.u = data_read_dag1(op); + m_core.ay1.u = pgm_read_dag2(op >> 4); + break; + case 0xdc: case 0xdd: + // 1101110x xxxxxxxx xxxxxxxx MAC to MR with data read to MX1 & pgm read to AY1 + mac_op_mr(op); + m_core.mx1.u = data_read_dag1(op); + m_core.ay1.u = pgm_read_dag2(op >> 4); + break; + case 0xde: case 0xdf: + // 1101111x xxxxxxxx xxxxxxxx ALU to AR with data read to MX1 & pgm read to AY1 + alu_op_ar(op); + m_core.mx1.u = data_read_dag1(op); + m_core.ay1.u = pgm_read_dag2(op >> 4); + break; + case 0xe0: case 0xe1: + // 1110000x xxxxxxxx xxxxxxxx MAC to MR with data read to AX0 & pgm read to MY0 + mac_op_mr(op); + m_core.ax0.u = data_read_dag1(op); + m_core.my0.u = pgm_read_dag2(op >> 4); + break; + case 0xe2: case 0xe3: + // 1110001x xxxxxxxx xxxxxxxx ALU to AR with data read to AX0 & pgm read to MY0 + alu_op_ar(op); + m_core.ax0.u = data_read_dag1(op); + m_core.my0.u = pgm_read_dag2(op >> 4); + break; + case 0xe4: case 0xe5: + // 1110010x xxxxxxxx xxxxxxxx MAC to MR with data read to AX1 & pgm read to MY0 + mac_op_mr(op); + m_core.ax1.u = data_read_dag1(op); + m_core.my0.u = pgm_read_dag2(op >> 4); + break; + case 0xe6: case 0xe7: + // 1110011x xxxxxxxx xxxxxxxx ALU to AR with data read to AX1 & pgm read to MY0 + alu_op_ar(op); + m_core.ax1.u = data_read_dag1(op); + m_core.my0.u = pgm_read_dag2(op >> 4); + break; + case 0xe8: case 0xe9: + // 1110100x xxxxxxxx xxxxxxxx MAC to MR with data read to MX0 & pgm read to MY0 + mac_op_mr(op); + m_core.mx0.u = data_read_dag1(op); + m_core.my0.u = pgm_read_dag2(op >> 4); + break; + case 0xea: case 0xeb: + // 1110101x xxxxxxxx xxxxxxxx ALU to AR with data read to MX0 & pgm read to MY0 + alu_op_ar(op); + m_core.mx0.u = data_read_dag1(op); + m_core.my0.u = pgm_read_dag2(op >> 4); + break; + case 0xec: case 0xed: + // 1110110x xxxxxxxx xxxxxxxx MAC to MR with data read to MX1 & pgm read to MY0 + mac_op_mr(op); + m_core.mx1.u = data_read_dag1(op); + m_core.my0.u = pgm_read_dag2(op >> 4); + break; + case 0xee: case 0xef: + // 1110111x xxxxxxxx xxxxxxxx ALU to AR with data read to MX1 & pgm read to MY0 + alu_op_ar(op); + m_core.mx1.u = data_read_dag1(op); + m_core.my0.u = pgm_read_dag2(op >> 4); + break; + case 0xf0: case 0xf1: + // 1111000x xxxxxxxx xxxxxxxx MAC to MR with data read to AX0 & pgm read to MY1 + mac_op_mr(op); + m_core.ax0.u = data_read_dag1(op); + m_core.my1.u = pgm_read_dag2(op >> 4); + break; + case 0xf2: case 0xf3: + // 1111001x xxxxxxxx xxxxxxxx ALU to AR with data read to AX0 & pgm read to MY1 + alu_op_ar(op); + m_core.ax0.u = data_read_dag1(op); + m_core.my1.u = pgm_read_dag2(op >> 4); + break; + case 0xf4: case 0xf5: + // 1111010x xxxxxxxx xxxxxxxx MAC to MR with data read to AX1 & pgm read to MY1 + mac_op_mr(op); + m_core.ax1.u = data_read_dag1(op); + m_core.my1.u = pgm_read_dag2(op >> 4); + break; + case 0xf6: case 0xf7: + // 1111011x xxxxxxxx xxxxxxxx ALU to AR with data read to AX1 & pgm read to MY1 + alu_op_ar(op); + m_core.ax1.u = data_read_dag1(op); + m_core.my1.u = pgm_read_dag2(op >> 4); + break; + case 0xf8: case 0xf9: + // 1111100x xxxxxxxx xxxxxxxx MAC to MR with data read to MX0 & pgm read to MY1 + mac_op_mr(op); + m_core.mx0.u = data_read_dag1(op); + m_core.my1.u = pgm_read_dag2(op >> 4); + break; + case 0xfa: case 0xfb: + // 1111101x xxxxxxxx xxxxxxxx ALU to AR with data read to MX0 & pgm read to MY1 + alu_op_ar(op); + m_core.mx0.u = data_read_dag1(op); + m_core.my1.u = pgm_read_dag2(op >> 4); + break; + case 0xfc: case 0xfd: + // 1111110x xxxxxxxx xxxxxxxx MAC to MR with data read to MX1 & pgm read to MY1 + mac_op_mr(op); + m_core.mx1.u = data_read_dag1(op); + m_core.my1.u = pgm_read_dag2(op >> 4); + break; + case 0xfe: case 0xff: + // 1111111x xxxxxxxx xxxxxxxx ALU to AR with data read to MX1 & pgm read to MY1 + alu_op_ar(op); + m_core.mx1.u = data_read_dag1(op); + m_core.my1.u = pgm_read_dag2(op >> 4); + break; + } + + m_icount--; + } while (m_icount > 0); +} diff --git a/src/devices/cpu/adsp2100/adsp2100.h b/src/devices/cpu/adsp2100/adsp2100.h new file mode 100644 index 00000000000..4b84d6e1b2a --- /dev/null +++ b/src/devices/cpu/adsp2100/adsp2100.h @@ -0,0 +1,586 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + adsp2100.h + + ADSP-21xx series emulator. + +***************************************************************************/ + +#pragma once + +#ifndef __ADSP2100_H__ +#define __ADSP2100_H__ + + +//************************************************************************** +// DEBUGGING +//************************************************************************** + +#define ADSP_TRACK_HOTSPOTS 0 + + + +//************************************************************************** +// CONSTANTS +//************************************************************************** + +// ADSP-2100 IRQs +const int ADSP2100_IRQ0 = 0; // IRQ0 +const int ADSP2100_SPORT1_RX = 0; // SPORT1 receive IRQ +const int ADSP2100_IRQ1 = 1; // IRQ1 +const int ADSP2100_SPORT1_TX = 1; // SPORT1 transmit IRQ +const int ADSP2100_IRQ2 = 2; // IRQ2 +const int ADSP2100_IRQ3 = 3; // IRQ3 + +// ADSP-2101 IRQs +const int ADSP2101_IRQ0 = 0; // IRQ0 +const int ADSP2101_SPORT1_RX = 0; // SPORT1 receive IRQ +const int ADSP2101_IRQ1 = 1; // IRQ1 +const int ADSP2101_SPORT1_TX = 1; // SPORT1 transmit IRQ +const int ADSP2101_IRQ2 = 2; // IRQ2 +const int ADSP2101_SPORT0_RX = 3; // SPORT0 receive IRQ +const int ADSP2101_SPORT0_TX = 4; // SPORT0 transmit IRQ +const int ADSP2101_TIMER = 5; // internal timer IRQ + +// ADSP-2104 IRQs +const int ADSP2104_IRQ0 = 0; // IRQ0 +const int ADSP2104_SPORT1_RX = 0; // SPORT1 receive IRQ +const int ADSP2104_IRQ1 = 1; // IRQ1 +const int ADSP2104_SPORT1_TX = 1; // SPORT1 transmit IRQ +const int ADSP2104_IRQ2 = 2; // IRQ2 +const int ADSP2104_SPORT0_RX = 3; // SPORT0 receive IRQ +const int ADSP2104_SPORT0_TX = 4; // SPORT0 transmit IRQ +const int ADSP2104_TIMER = 5; // internal timer IRQ + +// ADSP-2105 IRQs +const int ADSP2105_IRQ0 = 0; // IRQ0 +const int ADSP2105_SPORT1_RX = 0; // SPORT1 receive IRQ +const int ADSP2105_IRQ1 = 1; // IRQ1 +const int ADSP2105_SPORT1_TX = 1; // SPORT1 transmit IRQ +const int ADSP2105_IRQ2 = 2; // IRQ2 +const int ADSP2105_TIMER = 5; // internal timer IRQ + +// ADSP-2115 IRQs +const int ADSP2115_IRQ0 = 0; // IRQ0 +const int ADSP2115_SPORT1_RX = 0; // SPORT1 receive IRQ +const int ADSP2115_IRQ1 = 1; // IRQ1 +const int ADSP2115_SPORT1_TX = 1; // SPORT1 transmit IRQ +const int ADSP2115_IRQ2 = 2; // IRQ2 +const int ADSP2115_SPORT0_RX = 3; // SPORT0 receive IRQ +const int ADSP2115_SPORT0_TX = 4; // SPORT0 transmit IRQ +const int ADSP2115_TIMER = 5; // internal timer IRQ + +// ADSP-2181 IRQs +const int ADSP2181_IRQ0 = 0; // IRQ0 +const int ADSP2181_SPORT1_RX = 0; // SPORT1 receive IRQ +const int ADSP2181_IRQ1 = 1; // IRQ1 +const int ADSP2181_SPORT1_TX = 1; // SPORT1 transmit IRQ +const int ADSP2181_IRQ2 = 2; // IRQ2 +const int ADSP2181_SPORT0_RX = 3; // SPORT0 receive IRQ +const int ADSP2181_SPORT0_TX = 4; // SPORT0 transmit IRQ +const int ADSP2181_TIMER = 5; // internal timer IRQ +const int ADSP2181_IRQE = 6; // IRQE +const int ADSP2181_IRQL1 = 7; // IRQL1 +const int ADSP2181_IRQL2 = 8; // IRQL2 + +// register enumeration +enum +{ + ADSP2100_PC, + ADSP2100_AX0, + ADSP2100_AX1, + ADSP2100_AY0, + ADSP2100_AY1, + ADSP2100_AR, + ADSP2100_AF, + ADSP2100_MX0, + ADSP2100_MX1, + ADSP2100_MY0, + ADSP2100_MY1, + ADSP2100_MR0, + ADSP2100_MR1, + ADSP2100_MR2, + ADSP2100_MF, + ADSP2100_SI, + ADSP2100_SE, + ADSP2100_SB, + ADSP2100_SR0, + ADSP2100_SR1, + ADSP2100_I0, + ADSP2100_I1, + ADSP2100_I2, + ADSP2100_I3, + ADSP2100_I4, + ADSP2100_I5, + ADSP2100_I6, + ADSP2100_I7, + ADSP2100_L0, + ADSP2100_L1, + ADSP2100_L2, + ADSP2100_L3, + ADSP2100_L4, + ADSP2100_L5, + ADSP2100_L6, + ADSP2100_L7, + ADSP2100_M0, + ADSP2100_M1, + ADSP2100_M2, + ADSP2100_M3, + ADSP2100_M4, + ADSP2100_M5, + ADSP2100_M6, + ADSP2100_M7, + ADSP2100_PX, + ADSP2100_CNTR, + ADSP2100_ASTAT, + ADSP2100_SSTAT, + ADSP2100_MSTAT, + ADSP2100_PCSP, + ADSP2100_CNTRSP, + ADSP2100_STATSP, + ADSP2100_LOOPSP, + ADSP2100_IMASK, + ADSP2100_ICNTL, + ADSP2100_IRQSTATE0, + ADSP2100_IRQSTATE1, + ADSP2100_IRQSTATE2, + ADSP2100_IRQSTATE3, + ADSP2100_FLAGIN, + ADSP2100_FLAGOUT, + ADSP2100_FL0, + ADSP2100_FL1, + ADSP2100_FL2, + ADSP2100_AX0_SEC, + ADSP2100_AX1_SEC, + ADSP2100_AY0_SEC, + ADSP2100_AY1_SEC, + ADSP2100_AR_SEC, + ADSP2100_AF_SEC, + ADSP2100_MX0_SEC, + ADSP2100_MX1_SEC, + ADSP2100_MY0_SEC, + ADSP2100_MY1_SEC, + ADSP2100_MR0_SEC, + ADSP2100_MR1_SEC, + ADSP2100_MR2_SEC, + ADSP2100_MF_SEC, + ADSP2100_SI_SEC, + ADSP2100_SE_SEC, + ADSP2100_SB_SEC, + ADSP2100_SR0_SEC, + ADSP2100_SR1_SEC, + + ADSP2100_GENPC = STATE_GENPC, + ADSP2100_GENSP = STATE_GENSP, + ADSP2100_GENPCBASE = STATE_GENPCBASE +}; + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_ADSP21XX_SPORT_RX_CB(_devcb) \ + devcb = &adsp21xx_device::set_sport_rx_callback(*device, DEVCB_##_devcb); + +#define MCFG_ADSP21XX_SPORT_TX_CB(_devcb) \ + devcb = &adsp21xx_device::set_sport_tx_callback(*device, DEVCB_##_devcb); + +#define MCFG_ADSP21XX_TIMER_FIRED_CB(_devcb) \ + devcb = &adsp21xx_device::set_timer_fired_callback(*device, DEVCB_##_devcb); + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> adsp21xx_device + +class adsp21xx_device : public cpu_device +{ +protected: + enum + { + CHIP_TYPE_ADSP2100, + CHIP_TYPE_ADSP2101, + CHIP_TYPE_ADSP2104, + CHIP_TYPE_ADSP2105, + CHIP_TYPE_ADSP2115, + CHIP_TYPE_ADSP2181 + }; + + // construction/destruction + adsp21xx_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, UINT32 chiptype, const char *shortname, const char *source); + virtual ~adsp21xx_device(); + +public: + // inline configuration helpers + template static devcb_base &set_sport_rx_callback(device_t &device, _Object object) { return downcast(device).m_sport_rx_cb.set_callback(object); } + template static devcb_base &set_sport_tx_callback(device_t &device, _Object object) { return downcast(device).m_sport_tx_cb.set_callback(object); } + template static devcb_base &set_timer_fired_callback(device_t &device, _Object object) { return downcast(device).m_timer_fired_cb.set_callback(object); } + + // public interfaces + void load_boot_data(UINT8 *srcdata, UINT32 *dstdata); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_execute_interface overrides + virtual UINT32 execute_min_cycles() const; + virtual UINT32 execute_max_cycles() const; + virtual void execute_run(); + virtual void execute_set_input(int inputnum, int state); + + // device_state_interface overrides + virtual void state_import(const device_state_entry &entry); + virtual void state_string_export(const device_state_entry &entry, std::string &str); + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const; + virtual UINT32 disasm_max_opcode_bytes() const; + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + + // helpers + void create_tables(); + inline void update_mstat(); + inline UINT32 pc_stack_top(); + inline void set_pc_stack_top(UINT32 top); + inline void pc_stack_push(); + inline void pc_stack_push_val(UINT32 val); + inline void pc_stack_pop(); + inline UINT32 pc_stack_pop_val(); + inline UINT32 cntr_stack_top(); + inline void cntr_stack_push(); + inline void cntr_stack_pop(); + inline UINT32 loop_stack_top(); + inline void loop_stack_push(UINT32 value); + inline void loop_stack_pop(); + inline void stat_stack_push(); + inline void stat_stack_pop(); +// inline int condition(int c); + int slow_condition(); + inline void modify_address(UINT32 ireg, UINT32 mreg); + inline void data_write_dag1(UINT32 op, INT32 val); + inline UINT32 data_read_dag1(UINT32 op); + inline void data_write_dag2(UINT32 op, INT32 val); + inline UINT32 data_read_dag2(UINT32 op); + inline void pgm_write_dag2(UINT32 op, INT32 val); + inline UINT32 pgm_read_dag2(UINT32 op); + void alu_op_ar(int op); + void alu_op_ar_const(int op); + void alu_op_af(int op); + void alu_op_af_const(int op); + void alu_op_none(int op); + void mac_op_mr(int op); + void mac_op_mr_xop(int op); + void mac_op_mf(int op); + void mac_op_mf_xop(int op); + void shift_op(int op); + void shift_op_imm(int op); + + // memory access + inline UINT16 data_read(UINT32 addr); + inline void data_write(UINT32 addr, UINT16 data); + inline UINT16 io_read(UINT32 addr); + inline void io_write(UINT32 addr, UINT16 data); + inline UINT32 program_read(UINT32 addr); + inline void program_write(UINT32 addr, UINT32 data); + inline UINT32 opcode_read(); + + // register read/write + inline void update_i(int which); + inline void update_l(int which); + inline void write_reg0(int regnum, INT32 val); + inline void write_reg1(int regnum, INT32 val); + inline void write_reg2(int regnum, INT32 val); + inline void write_reg3(int regnum, INT32 val); + inline INT32 read_reg0(int regnum); + inline INT32 read_reg1(int regnum); + inline INT32 read_reg2(int regnum); + inline INT32 read_reg3(int regnum); + + // interrupts + virtual bool generate_irq(int which, int indx = 0) = 0; + virtual void check_irqs() = 0; + + // internal state + static const int PC_STACK_DEPTH = 16; + static const int CNTR_STACK_DEPTH = 4; + static const int STAT_STACK_DEPTH = 4; + static const int LOOP_STACK_DEPTH = 4; + + // 16-bit registers that can be loaded signed or unsigned + union adsp_reg16 + { + UINT16 u; + INT16 s; + }; + + // the SHIFT result register is 32 bits + union adsp_shift + { +#ifdef LSB_FIRST + struct { adsp_reg16 sr0, sr1; } srx; +#else + struct { adsp_reg16 sr1, sr0; } srx; +#endif + UINT32 sr; + }; + + // the MAC result register is 40 bits + union adsp_mac + { +#ifdef LSB_FIRST + struct { adsp_reg16 mr0, mr1, mr2, mrzero; } mrx; + struct { UINT32 mr0, mr1; } mry; +#else + struct { adsp_reg16 mrzero, mr2, mr1, mr0; } mrx; + struct { UINT32 mr1, mr0; } mry; +#endif + UINT64 mr; + }; + + // core registers which are replicated + struct adsp_core + { + // ALU registers + adsp_reg16 ax0, ax1; + adsp_reg16 ay0, ay1; + adsp_reg16 ar; + adsp_reg16 af; + + // MAC registers + adsp_reg16 mx0, mx1; + adsp_reg16 my0, my1; + adsp_mac mr; + adsp_reg16 mf; + + // SHIFT registers + adsp_reg16 si; + adsp_reg16 se; + adsp_reg16 sb; + adsp_shift sr; + + // dummy registers + adsp_reg16 zero; + }; + + // configuration + const address_space_config m_program_config; + const address_space_config m_data_config; + UINT32 m_chip_type; + + // other CPU registers + UINT32 m_pc; + UINT32 m_ppc; + UINT32 m_loop; + UINT32 m_loop_condition; + UINT32 m_cntr; + + // status registers + UINT32 m_astat; + UINT32 m_sstat; + UINT32 m_mstat; + UINT32 m_mstat_prev; + UINT32 m_astat_clear; + UINT32 m_idle; + + // live set of core registers + adsp_core m_core; + + // memory addressing registers + UINT32 m_i[8]; + INT32 m_m[8]; + UINT32 m_l[8]; + UINT32 m_lmask[8]; + UINT32 m_base[8]; + UINT8 m_px; + + // stacks + UINT32 m_loop_stack[LOOP_STACK_DEPTH]; + UINT32 m_cntr_stack[CNTR_STACK_DEPTH]; + UINT32 m_pc_stack[PC_STACK_DEPTH]; + UINT16 m_stat_stack[STAT_STACK_DEPTH][3]; + INT32 m_pc_sp; + INT32 m_cntr_sp; + INT32 m_stat_sp; + INT32 m_loop_sp; + + // external I/O + UINT8 m_flagout; + UINT8 m_flagin; + UINT8 m_fl0; + UINT8 m_fl1; + UINT8 m_fl2; + UINT16 m_idma_addr; + UINT16 m_idma_cache; + UINT8 m_idma_offs; + + // interrupt handling + UINT16 m_imask; + UINT8 m_icntl; + UINT16 m_ifc; + UINT8 m_irq_state[9]; + UINT8 m_irq_latch[9]; + + // other internal states + int m_icount; + int m_mstat_mask; + int m_imask_mask; + + // register maps + INT16 * m_read0_ptr[16]; + UINT32 * m_read1_ptr[16]; + UINT32 * m_read2_ptr[16]; + void * m_alu_xregs[8]; + void * m_alu_yregs[4]; + void * m_mac_xregs[8]; + void * m_mac_yregs[4]; + void * m_shift_xregs[8]; + + // alternate core registers (at end for performance) + adsp_core m_alt; + + // address spaces + address_space * m_program; + address_space * m_data; + address_space * m_io; + direct_read_data * m_direct; + + // tables + UINT8 m_condition_table[0x1000]; + UINT16 m_mask_table[0x4000]; + UINT16 m_reverse_table[0x4000]; + + devcb_read32 m_sport_rx_cb; // callback for serial receive + devcb_write32 m_sport_tx_cb; // callback for serial transmit + devcb_write_line m_timer_fired_cb; // callback for timer fired + + // debugging +#if ADSP_TRACK_HOTSPOTS + UINT32 m_pcbucket[0x4000]; +#endif + + // flag definitions + static const int SSFLAG = 0x80; + static const int MVFLAG = 0x40; + static const int QFLAG = 0x20; + static const int SFLAG = 0x10; + static const int CFLAG = 0x08; + static const int VFLAG = 0x04; + static const int NFLAG = 0x02; + static const int ZFLAG = 0x01; +}; + + +// ======================> adsp2100_device + +class adsp2100_device : public adsp21xx_device +{ +public: + // construction/destruction + adsp2100_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // device_execute_interface overrides + virtual UINT32 execute_input_lines() const; + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const; + + // interrupts + virtual bool generate_irq(int which, int indx); + virtual void check_irqs(); +}; + + +// ======================> adsp2101_device + +class adsp2101_device : public adsp21xx_device +{ +public: + // construction/destruction + adsp2101_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + adsp2101_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, UINT32 chiptype, const char *shortname, const char *source); + + // device_execute_interface overrides + virtual UINT32 execute_input_lines() const; + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const; + + // interrupts + virtual bool generate_irq(int which, int indx); + virtual void check_irqs(); +}; + + +// ======================> adsp2181_device + +class adsp2181_device : public adsp21xx_device +{ +public: + // construction/destruction + adsp2181_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // device_execute_interface overrides + virtual UINT32 execute_input_lines() const; + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const; + + // interrupts + virtual bool generate_irq(int which, int indx); + virtual void check_irqs(); + + // address spaces + const address_space_config m_io_config; + +public: + // public interfaces + void idma_addr_w(UINT16 data); + UINT16 idma_addr_r(); + void idma_data_w(UINT16 data); + UINT16 idma_data_r(); +}; + + +// ======================> trivial variants + +class adsp2104_device : public adsp2101_device +{ +public: + adsp2104_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class adsp2105_device : public adsp2101_device +{ +public: + adsp2105_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class adsp2115_device : public adsp2101_device +{ +public: + adsp2115_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + + +// device type definition +extern const device_type ADSP2100; +extern const device_type ADSP2101; +extern const device_type ADSP2104; +extern const device_type ADSP2105; +extern const device_type ADSP2115; +extern const device_type ADSP2181; + + +#endif /* __ADSP2100_H__ */ diff --git a/src/devices/cpu/alph8201/8201dasm.c b/src/devices/cpu/alph8201/8201dasm.c new file mode 100644 index 00000000000..c22a4316ea4 --- /dev/null +++ b/src/devices/cpu/alph8201/8201dasm.c @@ -0,0 +1,404 @@ +// license:BSD-3-Clause +// copyright-holders:Tatsuyuki Satoh +/**************************************************************************** + Alpha 8201/8301 Disassembler + + Copyright Tatsuyuki Satoh + Originally written for the MAME project. + +****************************************************************************/ + +#include "emu.h" + +#include + +typedef unsigned char byte; + +#define FMT(a,b) a, b +#define PTRS_PER_FORMAT 2 + +/**************************************************** + +8201 CONFIRMED OPCODES: + +opcode mnemonic function flags +-------- ------------ ------------- ----- +00000000 NOP - -- +00000001 RORA ror A -C +00000010 ROLA rol A -C +00000011 INC RXB RXB+=2 ZC +00000100 DEC RXB RXB-=2 ZC (C=1 means No Borrow: RXB>=2) +00000101 INC A A++ ZC +00000110 DEC A A-- ZC (C=1 means No Borrow: A>=1) +00000110 CPL A A^=$FF -- +00001aaa LD A,(IX0+i) A=[IX0+i] -- +00010aaa LD A,(IX1+i) A=[IX1+i] -- +00011aaa LD (IX2+i),A [IX2+i]=A -- +00111aaa BIT R0.n ZF=R0 bit n Z- +0100aaa0 LD A,Rn A=Rn Z- [1] +0100aaa1 LD Rn,A Rn=A -- +0101aaa0 ADD A,Rn A+=Rn ZC +0101aaa1 SUB A,Rn A-=Rn ZC (C=1 means No Borrow: A>=Rn) +0110aaa0 AND A,Rn A&=Rn Z- +0110aaa1 OR A,Rn A|=Rn Z- +0111aaaa ADD IX0,i IX0+=i -- +1000aaaa ADD IX1,i IX1+=i -- +1001aaaa ADD IX2,i IX2+=i -- +1010aaaa LD RB,i RB=i -- Note: no bounds checking. Can set bank up to F. +1011-0aa LD MB,i set after-jump page +1011-1-- STOP +11000000 imm LD IX0,imm IX0=imm -- +11000001 imm LD IX1,imm IX1=imm -- +11000010 imm LD IX2,imm IX2=imm -- +11000011 imm LD A,imm A=imm -- +11000100 imm LD LP0,imm LP0=imm -- +11000101 imm LD LP1,imm LP1=imm -- +11000110 imm LD LP2,imm LP2=imm -- +11000111 imm LD RXB,imm RXB=imm -- +11001000 imm ADD A,imm A+=imm ZC +11001001 imm SUB A,imm A-=imm ZC (C=1 means No Borrow: A>=imm) +11001010 imm AND A,imm A&=imm Z- +11001011 imm OR A,imm A|=imm Z- +11001100 imm DJNZ LP0,imm LP0--,branch -- +11001101 imm DJNZ LP1,imm LP1--,branch -- +11001110 imm DJNZ LP2,imm LP2--,branch -- +11001111 imm JNZ imm branch if !Z -- +1101--00 imm JNC imm branch if !C -- +1101--01 imm JZ imm branch if Z -- +1101--1- imm J imm branch -- +1110--xx mirror for the above +1111--xx mirror for the above + +Notes: +[1] bug: the Z flag is not updated correctly after a LD A,Rn instruction. Fixed in 8302 (possibly 8301). + + +8302 CONFIRMED OPCODES: +---------------------- +all of the 8201 ones, with stricter decoding for the following: + +11010-00 imm JNC imm branch if !C -- +11010-01 imm JZ imm branch if Z -- +11010-1- imm J imm branch -- + +and these new opcodes: + +opcode mnemonic function flags +-------- ------------ --------------- ----- +11011000 imm LD A,(imm) A=MB:[imm] -- +11011001 imm LD (imm),A MB:[imm]=A -- +11011010 imm CMP A,imm temp=A-imm ZC +11011011 imm XOR A,imm A^=imm Z0 +11011100 imm LD A,R(imm) A=reg(imm) -- +11011101 imm LD R(imm),A reg(imm)=A -- +11011110 imm JC imm branch if C -- +11011111 imm CALL $xx save PC, branch -- + +11100000 EXG A,IX0 A<->IX0 -- +11100001 EXG A,IX1 A<->IX1 -- +11100010 EXG A,IX2 A<->IX2 -- +11100011 EXG A,LP1 A<->LP1 -- +11100100 EXG A,LP2 A<->LP2 -- +11100101 EXG A,RXB A<->RXB -- +11100110 EXG A,LP0 A<->LP0 -- +11100111 EXG A,RB A<->RB -- +11101000 LD IX0,A IX0=A -- +11101001 LD IX1,A IX1=A -- +11101010 LD IX2,A IX2=A -- +11101011 LD LP1,A LP1=A -- +11101100 LD LP2,A LP2=A -- +11101101 LD RXB,A RXB=A -- +11101110 LD LP0,A LP0=A -- +11101111 LD RB,A RB=A -- +11110000 EXG IX0,IX1 IX0<->IX1 -- +11110001 EXG IX0,IX2 IX0<->IX2 -- +11110010 REP LD (IX2),(RXB) equivalent to LD (IX2),(RXB); INC RXB; DJNZ LP0 +11110011 REP LD (RXB),(IX0) equivalent to LD (RXB),(IX0); INC RXB; DJNZ LP0 +11110100 SAVE ZC save ZC -- +11110101 REST ZC restore ZC ZC +11110110 LD (RXB),A reg(RXB)=A -- +11110111 LD A,(RXB) A=reg(RXB) -- +11111000 CMP A,(RXB) temp=A-reg(RXB) ZC +11111001 XOR A,(RXB) A^=reg(RXB) Z0 +11111010 ADD A,CF if (C) A++ ZC +11111011 SUB A,!CF if (!C) A-- ZC +11111100 TST A A==0? Z- +11111101 CLR A A=0 -- +11111110 LD A,(IX0+A) A=[IX0+A] -- +11111111 RET restore PC -- + + +8303 CONFIRMED OPCODES: +---------------------- +all of the 8302 ones, with stricter decoding for the following: + +11010000 imm JNC imm branch if !C -- +11010001 imm JZ imm branch if Z -- +1101001- imm J imm branch -- + +additionally, this opcode is modified to support 11-bit instead of 10-bit +external addressing, this wasn't used in games however. + +1011-0aa LD MB,i modified so that bit 3 is shifted to bit 2 before loading MB. + +and these new opcodes are added: + +110101-- +11010100 imm LD A,(R77:$%02X) +11010101 imm LD (R77:$%02X),A +11010110 imm LD PC,(R77:$%02X) [1] +11010111 imm LD (R77:$%02X),PC [2] + +Notes: +[1] appears to be LD PC,x in the disassembly, however it's LD LP0,x for kouyakyu + which uses a 8304, so the opcode was probably changed again. +[2] appears to be LD x,PC in the disassembly, however it's LD x,LP0 for hvoltage + which uses a 8304 (or 8404?), so the opcode was probably changed again. + +****************************************************/ + + +/****************************************************/ + +static const char *const Formats[] = { + FMT("0000_0000", "NOP"), // 00 + FMT("0000_0001", "RRCA"), // 01 + FMT("0000_0010", "RLCA"), // 02 + FMT("0000_0011", "INC RXB"), // 03 : shougi $360 to $377; splndrbt + FMT("0000_0100", "DEC RXB"), // 04 : not found + FMT("0000_0101", "INC A"), // 05 + FMT("0000_0110", "DEC A"), // 06 + FMT("0000_0111", "CPL A"), // 07 + FMT("0000_1aaa", "LD A,(IX0+%X)"), // 08-0F + FMT("0001_0aaa", "LD A,(IX1+%X)"), // 10-17 + FMT("0001_1aaa", "LD (IX2+%X),A"), // 18-1F + FMT("0010_0aaa", "LD (RXB),(IX0+%X)"),// 20-27 : shougi $360 to $377 + FMT("0010_1aaa", "LD (RXB),(IX1+%X)"),// 28-2f : not found + FMT("0011_0aaa", "LD (IX2+%X),(RXB)"),// 30-37 : not found + FMT("0011_1aaa", "BIT R0.%d"), // 38-3F ZF = R0.a (bit test) + FMT("0100_aaa0", "LD A,R%X"), // 40-4E + FMT("0100_aaa1", "LD R%X,A"), // 41-4F + FMT("0101_aaa0", "ADD A,R%X"), // 50-5E + FMT("0101_aaa1", "SUB A,R%X"), // 51-5F + FMT("0110_aaa0", "AND A,R%X"), // 60-6E + FMT("0110_aaa1", "OR A,R%X"), // 61-6F + FMT("0111_aaaa", "ADD IX0,$%X"), // 70-7f + FMT("1000_aaaa", "ADD IX1,$%X"), // 80-8f + FMT("1001_aaaa", "ADD IX2,$%X"), // 90-9f + FMT("1010_aaaa", "LD RB,%X"), // A0-AF + FMT("1011_x0aa", "LD MB,%X"), // B0-B3 (+ mirrors) + FMT("1011_x1xx", "STOP"), // B4 (+ mirrors) + + FMT("1100_0000 I", "LD IX0,$%02X"), // C0 + FMT("1100_0001 I", "LD IX1,$%02X"), // C1 + FMT("1100_0010 I", "LD IX2,$%02X"), // C2 + FMT("1100_0011 I", "LD A,$%02X"), // C3 + FMT("1100_0100 I", "LD LP0,$%02X"), // C4 + FMT("1100_0101 I", "LD LP1,$%02X"), // C5 + FMT("1100_0110 I", "LD LP2,$%02X"), // C6 + FMT("1100_0111 I", "LD RXB,$%02X"), // C7 : shougi, splndrbt, equites + FMT("1100_1000 I", "ADD A,$%02X"), // C8 + FMT("1100_1001 I", "SUB A,$%02X"), // C9 + FMT("1100_1010 I", "AND A,$%02X"), // CA + FMT("1100_1011 I", "OR A,$%02X"), // CB + FMT("1100_1100 I", "DJNZ LP0,$%02X"), // CC + FMT("1100_1101 I", "DJNZ LP1,$%02X"), // CD + FMT("1100_1110 I", "DJNZ LP2,$%02X"), // CE + FMT("1100_1111 I", "JNZ $%02X"), // CF + FMT("1101_0000 I", "JNC $%02X"), // D0 + FMT("1101_0001 I", "JZ $%02X"), // D1 + FMT("1101_001x I", "J $%02X"), // D2 (+ mirror) + + /* -------------- 830x only ------------- */ + + FMT("1101_0100 I", "LD A,(R77:$%02X)"), // D4 : 8303+ only. exctscc2, bullfgtr + FMT("1101_0101 I", "LD (R77:$%02X),A"), // D5 : 8303+ only. exctscc2, bullfgtr, kouyakyu + FMT("1101_0110 I", "LD LP0,(R77:$%02X)"), // D6 : 8303+ only. kouyakyu + FMT("1101_0111 I", "LD (R77:$%02X),LP0"), // D7 : 8303+ only. hvoltage + FMT("1101_1000 I", "LD A,($%02X)"), // D8 : equites + FMT("1101_1001 I", "LD ($%02X),A"), // D9 : equites + FMT("1101_1010 I", "CMP A,$%02X"), // DA : + FMT("1101_1011 I", "XOR A,$%02X"), // DB : equites splndrbt + FMT("1101_1100 I", "LD A,R($%02X)"), // DC : not found + FMT("1101_1101 I", "LD R($%02X),A"), // DD : equites, splndrbt + FMT("1101_1110 I", "JC $%02X"), // DE : not found + FMT("1101_1111 I", "CALL $%02X"), // DF : + + FMT("1110_0000", "EXG A,IX0"), // E0 : exctsccr + FMT("1110_0001", "EXG A,IX1"), // E1 : not found + FMT("1110_0010", "EXG A,IX2"), // E2 : not found + FMT("1110_0011", "EXG A,LP1"), // E3 : exctsccr in pair with EB + FMT("1110_0100", "EXG A,LP2"), // E4 : not found + FMT("1110_0101", "EXG A,RXB"), // E5 : splndrbt + FMT("1110_0110", "EXG A,LP0"), // E6 : splndrbt, bullfgtr, kouyakyu. EXG, not LD: see splndrbt $3ba to $3d3 + FMT("1110_0111", "EXG A,RB"), // E7 : not found + FMT("1110_1000", "LD IX0,A"), // E8 : + FMT("1110_1001", "LD IX1,A"), // E9 : not found + FMT("1110_1010", "LD IX2,A"), // EA : + FMT("1110_1011", "LD LP1,A"), // EB : exctsccr in pair with E3 + FMT("1110_1100", "LP LP2,A"), // EC : not found + FMT("1110_1101", "LD RXB,A"), // ED : splndrbt + FMT("1110_1110", "LD LP0,A"), // EE : splndrbt, bullfgtr + FMT("1110_1111", "LD RB,A"), // EF : not found + FMT("1111_0000", "EXG IX0,IX1"), // F0 : not found + FMT("1111_0001", "EXG IX0,IX2"), // F1 : splndrbt $2e to $38, equites $40 to $4a + FMT("1111_0010", "REP LD (IX2),(RXB)"),// F2 : splndrbt LD (IX2),(RXB); INC RXB; DJNZ LP0 + FMT("1111_0011", "REP LD (RXB),(IX0)"),// F3 : not found LD (RXB),(IX0); INC RXB; DJNZ LP0 + FMT("1111_0100", "SAVE ZC"), // F4 : not found + FMT("1111_0101", "REST ZC"), // F5 : not found + FMT("1111_0110", "LD (RXB),A"), // F6 : exctsccr + FMT("1111_0111", "LD A,(RXB)"), // F7 : not found + FMT("1111_1000", "CMP A,(RXB)"), // F8 : exctsccr + FMT("1111_1001", "XOR A,(RXB)"), // F9 : exctsccr + FMT("1111_1010", "ADD A,CF"), // FA : + FMT("1111_1011", "SUB A,!CF"), // FB : not found + FMT("1111_1100", "TST A"), // FC : + FMT("1111_1101", "CLR A"), // FD : + FMT("1111_1110", "LD A,(IX0+A)"), // FE : + FMT("1111_1111", "RET"), // FF : + NULL +}; + +#define MAX_OPS ((ARRAY_LENGTH(Formats) - 1) / PTRS_PER_FORMAT) + +struct AD8201Opcode { + byte mask; + byte bits; + byte type; + byte pmask; + byte pdown; + const char *fmt; +}; + +static AD8201Opcode Op[MAX_OPS+1]; +static int OpInizialized = 0; + +static void InitDasm8201(void) +{ + const char *p; + byte mask, bits; + int bit; + int i; + char chr , type; + int pmask , pdown; + + for(i=0;(p=Formats[i*2])!=NULL;i++) + { + mask = 0; + bits = 0; + pmask = 0; + pdown = 0; + type = 0; + bit = 7; + while (*p && bit >= 0) { + chr = *p++; + switch (chr) { + case '1': bits |= 1<> Op[op].pdown; + } + + if (Op[op].type & 0x02) + sprintf(buffer, Op[op].fmt,disp,disp); + else if (Op[op].type & 0x01) + sprintf(buffer, Op[op].fmt,disp); + else + sprintf(buffer, "%s",Op[op].fmt); + + switch (code) + { + case 0xcc: + case 0xcd: + case 0xce: + case 0xdf: + dasmflags = DASMFLAG_STEP_OVER; + break; + + case 0xff: + dasmflags = DASMFLAG_STEP_OUT; + break; + } + + return cnt | dasmflags | DASMFLAG_SUPPORTED; +} diff --git a/src/devices/cpu/alph8201/alph8201.c b/src/devices/cpu/alph8201/alph8201.c new file mode 100644 index 00000000000..e575f149d34 --- /dev/null +++ b/src/devices/cpu/alph8201/alph8201.c @@ -0,0 +1,649 @@ +// license:BSD-3-Clause +// copyright-holders:Tatsuyuki Satoh +/**************************************************************************** + Alpha8201 Emulator + + Copyright Tatsuyuki Satoh + Originally written for the MAME project. + + +The Alpha8201/830x isn't a real CPU. It is a Hitachi HD44801 4-bit MCU, +programmed to interpret an external program using a custom instruction set. +Alpha8301 has an expanded instruction set, backwards compatible with Alpha8201 + +The internal ROM hasn't been read (yet), so here we provide a simulation of +the behaviour. + + +Game Year MCU +------------------------ ---- ---- +Shougi 1982? 8201 (pcb) +Shougi 2 1982? 8201 (pcb) +Talbot 1982 8201? +Champion Base Ball 1983 8201 (schematics) +Exciting Soccer 1983 8302 (pcb) +Champion Base Ball II 1983 8302 (pcb, unofficial schematics) +Exciting Soccer II 1984 8303 (uses 8303+ opcodes) +Equites 1984 8303 (post) +Bull Fighter 1984 8303 (post) +Splendor Blast 1985 8303 (post) +Gekisou 1985 8304 (post) +The Koukouyakyuh 1985 8304 (post) +High Voltage 1985 8404?(post says 8404, but readme says 8304) + +alpha8201: "44801A75" -> HD44801 , ROM code = A75 +ALPHA8302: "44801B35" -> HD44801 , ROM code = B35 +ALPHA8303: "44801B42" -> HD44801 , ROM code = B42 +ALPHA8304: ? + + + Notes : + some unknown instruction are not emulated. + + Because there was no information, opcode-syntax was created. + + TODO: + verify with real chip or analyze more. + -A lot of 8301 opcode. + -memory address 000 specification + -memory address 001 bit 7-5 specification + -write value after HALT operation to ODD of vector memory. + -operation cycle(execution speed). + +****************************************************************************/ + +/**************************************************************************** + +----------------------- +package / pin assign +----------------------- +ALPHA 8201 DIP 42 + +pin HD44801 Alpha +--- ------- ----- +1 : D3 WR +2-4 : D4-D6 n.c. +5-7 : D7-D9 GND in shougi , n.c. in champbas +8-13 : D10-D15 n.c. +14 : n.c. n.c. +15 : RESET RESET +16 : GND GND +17 : OSC1 (champbas=384KHz) +18 : OSC2 n.c. +19 : !HLT Vcc +20 : !TEST Vcc +21 : Vcc Vcc +22-25: R00-R03 DB4-DB7 +26-29: R10-R13 DB0-DB3 +30 : INT0 GO (input) +31 : INT1 n.c. +32-35: R20-R23 A4-A7 +36-39: R30-R33 A0-A3 +40-41: D0-D1 A8-A9 +42 : D2 /RD + + +----------------------- +Register Set +----------------------- + +PC : 10bit Program Pointer + A lower 8bits are loaded from the immidate. + A higher 2bits are loaded from the MB register. + +MB : 2bit memory bank register, load PC[9:8] after branch + load high to higher 2bit of PC after branch. + +RB : 3bit register bank select register + +R0-R7 : internal? RAM register 8bitx8 (x8 bank) + +A : 8bit + +cpustate->IX0/1 : memory indirect 'read' access pointer + +cpustate->IX2 : memory indirect 'write' access pointer + +RXB : unknown , looks index register + +cpustate->LP0/1/2 : loop count register used by DJNZ operation + +cpustate->cf : carry flag +cpustate->zf : zero flag + +----------------------- +Memoy Space +----------------------- + +000 : unknown ... +001 : bit4..0 = pointer of current entry , bit7..6 = unknown +002-003 : entrypoint1 vector +004-005 : entrypoint2 vector +006-007 : entrypoint3 vector +008-009 : entrypoint4 vector +00A-00B : entrypoint5 vector +00C-00D : entrypoint6 vector +00E-00F : entrypoint7 vector +010-011 : entrypoint8 vector +012-013 : entrypoint9 vector +014-015 : entrypoint10 vector +016-017 : entrypoint11 vector +018-019 : entrypoint12 vector +01A-01B : entrypoint13 vector +01C-01D : entrypoint14 vector +01E-01F : entrypoint15 vector +020-0FF : bank 0, program / data memory +100-1FF : bank 1, program / data memory +200-2FF : bank 2, program / data memory +300-3FF : bank 3, program / data memory + +The even address is the lower byte of the entry address. +The odd-address of entry point is a MB and status. + Bit 0 and 1 are a memory bank. + Bit 2 is HALT.At the time of set, it doesn't execute entry address. + After EXIT operation, Bit2 is set. + +----------------------- +Timming +----------------------- + +****************************************************************************/ + +#include "emu.h" +#include "debugger.h" +#include "alph8201.h" + + +const device_type ALPHA8201 = &device_creator; +const device_type ALPHA8301 = &device_creator; + + +/* instruction cycle count */ +#define C1 16 +#define C2 32 + +/* debug option */ +#define TRACE_PC 0 +#define SHOW_ENTRY_POINT 0 +#define SHOW_MESSAGE_CONSOLE 0 +#define BREAK_ON_UNKNOWN_OPCODE 0 +#define BREAK_ON_UNCERTAIN_OPCODE 0 + + +#define FN(x) &alpha8201_cpu_device::x + + +alpha8201_cpu_device::alpha8201_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : cpu_device(mconfig, ALPHA8201, "ALPHA-8201", tag, owner, clock, "alpha8201", __FILE__) + , m_program_config("program", ENDIANNESS_LITTLE, 8, 10, 0) + , m_io_config("io", ENDIANNESS_LITTLE, 8, 6, 0) + , m_opmap(opcode_8201) +{ +} + + +alpha8201_cpu_device::alpha8201_cpu_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : cpu_device(mconfig, type, name, tag, owner, clock, shortname, source) + , m_program_config("program", ENDIANNESS_LITTLE, 8, 10, 0) + , m_io_config("io", ENDIANNESS_LITTLE, 8, 6, 0) + , m_opmap(opcode_8201) +{ +} + +alpha8301_cpu_device::alpha8301_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : alpha8201_cpu_device(mconfig, ALPHA8301, "ALPHA-8301", tag, owner, clock, "alpha8301", __FILE__) +{ + m_opmap = opcode_8301; +} + + +/* Get next opcode argument and increment program counter */ +unsigned alpha8201_cpu_device::M_RDMEM_OPCODE() +{ + unsigned retval; + retval=M_RDOP_ARG(m_pc.w.l); + m_pc.b.l++; + return retval; +} + +void alpha8201_cpu_device::M_ADD(UINT8 dat) +{ + UINT16 temp = m_A + dat; + m_A = temp & 0xff; + m_zf = (m_A==0); + m_cf = temp>>8; +} + +void alpha8201_cpu_device::M_ADDB(UINT8 dat) +{ + UINT16 temp = m_B + dat; + m_B = temp & 0xff; + m_zf = (m_B==0); + m_cf = temp>>8; +} + +void alpha8201_cpu_device::M_SUB(UINT8 dat) +{ + m_cf = (m_A>=dat); // m_cf is No Borrow + m_A -= dat; + m_zf = (m_A==0); +} + +void alpha8201_cpu_device::M_AND(UINT8 dat) +{ + m_A &= dat; + m_zf = (m_A==0); +} + +void alpha8201_cpu_device::M_OR(UINT8 dat) +{ + m_A |= dat; + m_zf = (m_A==0); +} + +void alpha8201_cpu_device::M_XOR(UINT8 dat) +{ + m_A ^= dat; + m_zf = (m_A==0); + m_cf = 0; +} + +void alpha8201_cpu_device::M_JMP(UINT8 dat) +{ + m_pc.b.l = dat; + /* update pc page */ + m_pc.b.h = m_ix0.b.h = m_ix1.b.h = m_ix2.b.h = m_mb & 3; +} + +void alpha8201_cpu_device::M_UNDEFINED() +{ + logerror("alpha8201: PC = %03x, Unimplemented opcode = %02x\n", m_pc.w.l-1, M_RDMEM(m_pc.w.l-1)); +#if SHOW_MESSAGE_CONSOLE + osd_printf_debug("alpha8201: PC = %03x, Unimplemented opcode = %02x\n", m_pc.w.l-1, M_RDMEM(m_pc.w.l-1)); +#endif +#if BREAK_ON_UNKNOWN_OPCODE + debugger_break(machine()); +#endif +} + +void alpha8201_cpu_device::M_UNDEFINED2() +{ + UINT8 op = M_RDOP(m_pc.w.l-1); + UINT8 imm = M_RDMEM_OPCODE(); + logerror("alpha8201: PC = %03x, Unimplemented opcode = %02x,%02x\n", m_pc.w.l-2, op,imm); +#if SHOW_MESSAGE_CONSOLE + osd_printf_debug("alpha8201: PC = %03x, Unimplemented opcode = %02x,%02x\n", m_pc.w.l-2, op,imm); +#endif +#if BREAK_ON_UNKNOWN_OPCODE + debugger_break(machine()); +#endif +} + + +void alpha8201_cpu_device::stop() +{ + UINT8 pcptr = M_RDMEM(0x001) & 0x1f; + M_WRMEM(pcptr,(M_RDMEM(pcptr)&0xf)+0x08); /* mark entry point ODD to HALT */ + m_mb |= 0x08; /* mark internal HALT state */ +} + + +const alpha8201_cpu_device::s_opcode alpha8201_cpu_device::opcode_8201[256]= +{ + {C1, FN(nop) },{C1,FN(rora) },{C1, FN(rola) },{C1,FN(inc_b) },{C1,FN(dec_b) },{C1, FN(inc_a) },{C1, FN(dec_a) },{C1, FN(cpl) }, + {C2,FN(ld_a_ix0_0) },{C2,FN(ld_a_ix0_1)},{C2, FN(ld_a_ix0_2)},{C2,FN(ld_a_ix0_3)},{C2,FN(ld_a_ix0_4)},{C2,FN(ld_a_ix0_5)},{C2,FN(ld_a_ix0_6)},{C2,FN(ld_a_ix0_7)}, + {C2,FN(ld_a_ix1_0) },{C2,FN(ld_a_ix1_1)},{C2, FN(ld_a_ix1_2)},{C2,FN(ld_a_ix1_3)},{C2,FN(ld_a_ix1_4)},{C2,FN(ld_a_ix1_5)},{C2,FN(ld_a_ix1_6)},{C2,FN(ld_a_ix1_7)}, + {C2,FN(ld_ix2_0_a) },{C2,FN(ld_ix2_1_a)},{C2, FN(ld_ix2_2_a)},{C2,FN(ld_ix2_3_a)},{C2,FN(ld_ix2_4_a)},{C2,FN(ld_ix2_5_a)},{C2,FN(ld_ix2_6_a)},{C2,FN(ld_ix2_7_a)}, +/* 20 */ + {C2,FN(ld_ix0_0_b) },{C2,FN(ld_ix0_1_b)},{C2, FN(ld_ix0_2_b)},{C2,FN(ld_ix0_3_b)},{C2,FN(ld_ix0_4_b)},{C2,FN(ld_ix0_5_b)},{C2,FN(ld_ix0_6_b)},{C2,FN(ld_ix0_7_b)}, + {C2,FN(undefined) },{C2,FN(undefined) },{C2, FN(undefined) },{C2,FN(undefined) },{C2,FN(undefined) },{C2,FN(undefined) },{C2,FN(undefined) },{C2,FN(undefined) }, + {C2,FN(undefined) },{C2,FN(undefined) },{C2, FN(undefined) },{C2,FN(undefined) },{C2,FN(undefined) },{C2,FN(undefined) },{C2,FN(undefined) },{C2,FN(undefined) }, + {C2,FN(bit_r0_0) },{C2,FN(bit_r0_1) },{C2, FN(bit_r0_2) },{C2, FN(bit_r0_3) },{C2, FN(bit_r0_4) },{C2, FN(bit_r0_5) },{C2, FN(bit_r0_6) },{C2, FN(bit_r0_7) }, +/* 40 : 8201 */ + {C2, FN(ld_a_r0) },{C2, FN(ld_r0_a) },{C2, FN(ld_a_r1) },{C2, FN(ld_r1_a) },{C2, FN(ld_a_r2) },{C2, FN(ld_r2_a) },{C2, FN(ld_a_r3) },{C2, FN(ld_r3_a) }, + {C2, FN(ld_a_r4) },{C2, FN(ld_r4_a) },{C2, FN(ld_a_r5) },{C2, FN(ld_r5_a) },{C2, FN(ld_a_r6) },{C2, FN(ld_r6_a) },{C2, FN(ld_a_r7) },{C2, FN(ld_r7_a) }, + {C1, FN(add_a_r0) },{C1, FN(sub_a_r0) },{C1, FN(add_a_r1) },{C1, FN(sub_a_r1) },{C1, FN(add_a_r2) },{C1, FN(sub_a_r2) },{C1, FN(add_a_r3) },{C1, FN(sub_a_r3) }, + {C1, FN(add_a_r4) },{C1, FN(sub_a_r4) },{C1, FN(add_a_r5) },{C1, FN(sub_a_r5) },{C1, FN(add_a_r6) },{C1, FN(sub_a_r6) },{C1, FN(add_a_r7) },{C1, FN(sub_a_r7) }, + {C1, FN(and_a_r0) },{C1, FN(or_a_r0) },{C1, FN(and_a_r1) },{C1, FN(or_a_r1) },{C1, FN(and_a_r2) },{C1, FN(or_a_r2) },{C1, FN(and_a_r3) },{C1, FN(or_a_r3) }, + {C1, FN(and_a_r4) },{C1, FN(or_a_r4) },{C1, FN(and_a_r5) },{C1, FN(or_a_r5) },{C1, FN(and_a_r6) },{C1, FN(or_a_r6) },{C1, FN(and_a_r7) },{C1, FN(or_a_r7) }, + {C1, FN(add_ix0_0) },{C1, FN(add_ix0_1)},{C1, FN(add_ix0_2)},{C1, FN(add_ix0_3)},{C1, FN(add_ix0_4)},{C1, FN(add_ix0_5)},{C1, FN(add_ix0_6)},{C1, FN(add_ix0_7)}, + {C1, FN(add_ix0_8) },{C1, FN(add_ix0_9)},{C1, FN(add_ix0_a)},{C1, FN(add_ix0_b)},{C1, FN(add_ix0_c)},{C1, FN(add_ix0_d)},{C1, FN(add_ix0_e)},{C1, FN(add_ix0_f)}, +/* 80 : 8201 */ + {C1, FN(add_ix1_0) },{C1, FN(add_ix1_1)},{C1, FN(add_ix1_2)},{C1, FN(add_ix1_3)},{C1, FN(add_ix1_4)},{C1, FN(add_ix1_5)},{C1, FN(add_ix1_6)},{C1, FN(add_ix1_7)}, + {C1, FN(add_ix1_8) },{C1, FN(add_ix1_9)},{C1, FN(add_ix1_a)},{C1, FN(add_ix1_b)},{C1, FN(add_ix1_c)},{C1, FN(add_ix1_d)},{C1, FN(add_ix1_e)},{C1, FN(add_ix1_f)}, + {C1, FN(add_ix2_0) },{C1, FN(add_ix2_1)},{C1, FN(add_ix2_2)},{C1, FN(add_ix2_3)},{C1, FN(add_ix2_4)},{C1, FN(add_ix2_5)},{C1, FN(add_ix2_6)},{C1, FN(add_ix2_7)}, + {C1, FN(add_ix2_8) },{C1, FN(add_ix2_9)},{C1, FN(add_ix2_a)},{C1, FN(add_ix2_b)},{C1, FN(add_ix2_c)},{C1, FN(add_ix2_d)},{C1, FN(add_ix2_e)},{C1, FN(add_ix2_f)}, + {C1, FN(ld_base_0) },{C1, FN(ld_base_1)},{C1, FN(ld_base_2)},{C1, FN(ld_base_3)},{C1, FN(ld_base_4)},{C1, FN(ld_base_5)},{C1, FN(ld_base_6)},{C1, FN(ld_base_7)}, + {C1, FN(undefined) },{C1, FN(undefined)},{C1, FN(undefined)},{C1, FN(undefined)},{C1, FN(undefined)},{C1, FN(undefined)},{C1, FN(undefined)},{C1, FN(undefined)}, + {C1, FN(ld_bank_0) },{C1, FN(ld_bank_1)},{C1, FN(ld_bank_2)},{C1, FN(ld_bank_3)},{C2, FN(stop) },{C1, FN(undefined)},{C1, FN(undefined)},{C1, FN(undefined)}, + {C1, FN(undefined) },{C1, FN(undefined)},{C1, FN(undefined)},{C1, FN(undefined)},{C1, FN(undefined)},{C1, FN(undefined)},{C1, FN(undefined)},{C1, FN(undefined)}, +/* c0 : 8201 */ + {C2, FN(ld_ix0_n) },{C2, FN(ld_ix1_n) },{C2, FN(ld_ix2_n) },{C2, FN(ld_a_n) },{C2, FN(ld_lp0_n) },{C2, FN(ld_lp1_n) },{C2, FN(ld_lp2_n) },{C2, FN(ld_b_n) }, + {C2, FN(add_a_n) },{C2, FN(sub_a_n) },{C2, FN(and_a_n) },{C2, FN(or_a_n) },{C2, FN(djnz_lp0) },{C2, FN(djnz_lp1) },{C2, FN(djnz_lp2) },{C2, FN(jnz) }, + {C2, FN(jnc) },{C2, FN(jz) },{C2, FN(jmp) },{C2,FN(undefined2)},{C2,FN(undefined2)},{C2,FN(undefined2)},{C2,FN(undefined2)},{C2, FN(undefined2)}, + {C2, FN(undefined2) },{C2,FN(undefined2)},{C2,FN(undefined2)},{C2,FN(undefined2)},{C2,FN(undefined2)},{C2,FN(undefined2)},{C2,FN(undefined2)},{C2, FN(undefined2)}, +/* E0 : 8201*/ + {C1, FN(undefined) },{C1, FN(undefined)},{C1, FN(undefined)},{C1, FN(undefined)},{C1, FN(undefined)},{C1, FN(undefined)},{C1, FN(undefined)},{C1, FN(undefined)}, + {C1, FN(undefined) },{C1, FN(undefined)},{C1, FN(undefined)},{C1, FN(undefined)},{C1, FN(undefined)},{C1, FN(undefined)},{C1, FN(undefined)},{C1, FN(undefined)}, + {C1, FN(undefined) },{C1, FN(undefined)},{C1, FN(undefined)},{C1, FN(undefined)},{C1, FN(undefined)},{C1, FN(undefined)},{C1, FN(undefined)},{C1, FN(undefined)}, + {C1, FN(undefined) },{C1, FN(undefined)},{C1, FN(undefined)},{C1, FN(undefined)},{C1, FN(undefined)},{C1, FN(undefined)},{C1, FN(undefined)},{C1, FN(undefined) } +}; + + +const alpha8201_cpu_device::s_opcode alpha8201_cpu_device::opcode_8301[256]= +{ + {C1, FN(nop) },{C1,FN(rora) },{C1, FN(rola) },{C1,FN(inc_b) },{C1,FN(dec_b) },{C1, FN(inc_a) },{C1, FN(dec_a) },{C1, FN(cpl) }, + {C2,FN(ld_a_ix0_0) },{C2,FN(ld_a_ix0_1)},{C2, FN(ld_a_ix0_2)},{C2,FN(ld_a_ix0_3)},{C2,FN(ld_a_ix0_4)},{C2,FN(ld_a_ix0_5)},{C2,FN(ld_a_ix0_6)},{C2,FN(ld_a_ix0_7)}, + {C2,FN(ld_a_ix1_0) },{C2,FN(ld_a_ix1_1)},{C2, FN(ld_a_ix1_2)},{C2,FN(ld_a_ix1_3)},{C2,FN(ld_a_ix1_4)},{C2,FN(ld_a_ix1_5)},{C2,FN(ld_a_ix1_6)},{C2,FN(ld_a_ix1_7)}, + {C2,FN(ld_ix2_0_a) },{C2,FN(ld_ix2_1_a)},{C2, FN(ld_ix2_2_a)},{C2,FN(ld_ix2_3_a)},{C2,FN(ld_ix2_4_a)},{C2,FN(ld_ix2_5_a)},{C2,FN(ld_ix2_6_a)},{C2,FN(ld_ix2_7_a)}, +/* 20 : 8301 */ + {C2,FN(ld_ix0_0_b) },{C2,FN(ld_ix0_1_b)},{C2, FN(ld_ix0_2_b)},{C2,FN(ld_ix0_3_b)},{C2,FN(ld_ix0_4_b)},{C2,FN(ld_ix0_5_b)},{C2,FN(ld_ix0_6_b)},{C2,FN(ld_ix0_7_b)}, + {C2,FN(undefined) },{C2,FN(undefined) },{C2, FN(undefined) },{C2,FN(undefined) },{C2,FN(undefined) },{C2,FN(undefined) },{C2,FN(undefined) },{C2,FN(undefined) }, + {C2,FN(undefined) },{C2,FN(undefined) },{C2, FN(undefined) },{C2,FN(undefined) },{C2,FN(undefined) },{C2,FN(undefined) },{C2,FN(undefined) },{C2,FN(undefined) }, + {C2,FN(bit_r0_0) },{C2,FN(bit_r0_1) },{C2, FN(bit_r0_2) },{C2, FN(bit_r0_3) },{C2, FN(bit_r0_4) },{C2, FN(bit_r0_5) },{C2, FN(bit_r0_6) },{C2, FN(bit_r0_7) }, +/* 40 : 8301 */ + {C2, FN(ld_a_r0) },{C2, FN(ld_r0_a) },{C2, FN(ld_a_r1) },{C2, FN(ld_r1_a) },{C2, FN(ld_a_r2) },{C2, FN(ld_r2_a) },{C2, FN(ld_a_r3) },{C2, FN(ld_r3_a) }, + {C2, FN(ld_a_r4) },{C2, FN(ld_r4_a) },{C2, FN(ld_a_r5) },{C2, FN(ld_r5_a) },{C2, FN(ld_a_r6) },{C2, FN(ld_r6_a) },{C2, FN(ld_a_r7) },{C2, FN(ld_r7_a) }, + {C1, FN(add_a_r0) },{C1, FN(sub_a_r0) },{C1, FN(add_a_r1) },{C1, FN(sub_a_r1) },{C1, FN(add_a_r2) },{C1, FN(sub_a_r2) },{C1, FN(add_a_r3) },{C1, FN(sub_a_r3) }, + {C1, FN(add_a_r4) },{C1, FN(sub_a_r4) },{C1, FN(add_a_r5) },{C1, FN(sub_a_r5) },{C1, FN(add_a_r6) },{C1, FN(sub_a_r6) },{C1, FN(add_a_r7) },{C1, FN(sub_a_r7) }, +/* 60 : 8301 */ + {C1, FN(and_a_r0) },{C1, FN(or_a_r0) },{C1, FN(and_a_r1) },{C1, FN(or_a_r1) },{C1, FN(and_a_r2) },{C1, FN(or_a_r2) },{C1, FN(and_a_r3) },{C1, FN(or_a_r3) }, + {C1, FN(and_a_r4) },{C1, FN(or_a_r4) },{C1, FN(and_a_r5) },{C1, FN(or_a_r5) },{C1, FN(and_a_r6) },{C1, FN(or_a_r6) },{C1, FN(and_a_r7) },{C1, FN(or_a_r7) }, + {C1, FN(add_ix0_0) },{C1, FN(add_ix0_1)},{C1, FN(add_ix0_2)},{C1, FN(add_ix0_3)},{C1, FN(add_ix0_4)},{C1, FN(add_ix0_5)},{C1, FN(add_ix0_6)},{C1, FN(add_ix0_7)}, + {C1, FN(add_ix0_8) },{C1, FN(add_ix0_9)},{C1, FN(add_ix0_a)},{C1, FN(add_ix0_b)},{C1, FN(add_ix0_c)},{C1, FN(add_ix0_d)},{C1, FN(add_ix0_e)},{C1, FN(add_ix0_f)}, +/* 80 : 8301 */ + {C1, FN(add_ix1_0) },{C1, FN(add_ix1_1)},{C1, FN(add_ix1_2)},{C1, FN(add_ix1_3)},{C1, FN(add_ix1_4)},{C1, FN(add_ix1_5)},{C1, FN(add_ix1_6)},{C1, FN(add_ix1_7)}, + {C1, FN(add_ix1_8) },{C1, FN(add_ix1_9)},{C1, FN(add_ix1_a)},{C1, FN(add_ix1_b)},{C1, FN(add_ix1_c)},{C1, FN(add_ix1_d)},{C1, FN(add_ix1_e)},{C1, FN(add_ix1_f)}, + {C1, FN(add_ix2_0) },{C1, FN(add_ix2_1)},{C1, FN(add_ix2_2)},{C1, FN(add_ix2_3)},{C1, FN(add_ix2_4)},{C1, FN(add_ix2_5)},{C1, FN(add_ix2_6)},{C1, FN(add_ix2_7)}, + {C1, FN(add_ix2_8) },{C1, FN(add_ix2_9)},{C1, FN(add_ix2_a)},{C1, FN(add_ix2_b)},{C1, FN(add_ix2_c)},{C1, FN(add_ix2_d)},{C1, FN(add_ix2_e)},{C1, FN(add_ix2_f)}, +/* A0 : 8301 */ + {C1, FN(ld_base_0) },{C1, FN(ld_base_1)},{C1, FN(ld_base_2)},{C1, FN(ld_base_3)},{C1, FN(ld_base_4)},{C1, FN(ld_base_5)},{C1, FN(ld_base_6)},{C1, FN(ld_base_7)}, + {C1, FN(undefined) },{C1, FN(undefined)},{C1, FN(undefined)},{C1, FN(undefined)},{C1, FN(undefined)},{C1, FN(undefined)},{C1, FN(undefined)},{C1, FN(undefined)}, + {C1, FN(ld_bank_0) },{C1, FN(ld_bank_1)},{C1, FN(ld_bank_2)},{C1, FN(ld_bank_3)},{C2, FN(stop) },{C1, FN(undefined)},{C1, FN(undefined)},{C1, FN(undefined)}, + {C1, FN(undefined) },{C1, FN(undefined)},{C1, FN(undefined)},{C1, FN(undefined)},{C1, FN(undefined)},{C1, FN(undefined)},{C1, FN(undefined)},{C1, FN(undefined)}, +/* c0 : 8301 */ + {C2, FN(ld_ix0_n) },{C2, FN(ld_ix1_n)},{C2, FN(ld_ix2_n) },{C2, FN(ld_a_n) },{C2, FN(ld_lp0_n) },{C2, FN(ld_lp1_n) },{C2, FN(ld_lp2_n) },{C2, FN(ld_b_n) }, + {C2, FN(add_a_n) },{C2, FN(sub_a_n) },{C2, FN(and_a_n) },{C2, FN(or_a_n) },{C2, FN(djnz_lp0) },{C2, FN(djnz_lp1) },{C2, FN(djnz_lp2) },{C2, FN(jnz) }, + {C2, FN(jnc) },{C2, FN(jz) },{C2, FN(jmp) },{C2,FN(undefined2)},{C2, FN(op_d4) },{C2, FN(op_d5) },{C2, FN(op_d6) },{C2, FN(op_d7) }, + {C2, FN(ld_a_abs) },{C2, FN(ld_abs_a)},{C2,FN(cmp_a_n) },{C2,FN(xor_a_n) },{C2, FN(ld_a_r) },{C2, FN(ld_r_a) },{C2, FN(jc) },{C2, FN(call)}, +/* E0 : 8301 */ + {C1, FN(exg_a_ix0) },{C1, FN(exg_a_ix1)},{C1, FN(exg_a_ix2)},{C1, FN(exg_a_lp1)},{C1, FN(exg_a_lp2)},{C1, FN(exg_a_b) },{C1, FN(exg_a_lp0)},{C1, FN(exg_a_rb) }, + {C1, FN(ld_ix0_a) },{C1, FN(ld_ix1_a) },{C1, FN(ld_ix2_a) },{C1, FN(ld_lp1_a) },{C1, FN(ld_lp2_a) },{C1, FN(ld_b_a) },{C1, FN(ld_lp0_a) },{C1, FN(ld_rb_a) }, + {C1,FN(exg_ix0_ix1)},{C1,FN(exg_ix0_ix2)},{C1,FN(op_rep_ld_ix2_b)},{C1, FN(op_rep_ld_b_ix0)},{C1, FN(save_zc)},{C1, FN(rest_zc)},{C1, FN(ld_rxb_a) },{C1, FN(ld_a_rxb) }, + {C1, FN(cmp_a_rxb) },{C1, FN(xor_a_rxb)},{C1, FN(add_a_cf) },{C1, FN(sub_a_cf) },{C1, FN(tst_a) },{C1, FN(clr_a) },{C1, FN(ld_a_ix0_a)},{C1, FN(ret) } +}; + + +/**************************************************************************** + * Initialize emulation + ****************************************************************************/ +void alpha8201_cpu_device::device_start() +{ + m_program = &space(AS_PROGRAM); + m_direct = &m_program->direct(); + + state_add( ALPHA8201_PC, "PC", m_pc.w.l ).mask(0x3ff).formatstr("%03X"); + state_add( ALPHA8201_SP, "SP", m_sp ).callimport().callexport().formatstr("%02X"); + state_add( ALPHA8201_RB, "RB", m_regPtr ).mask(0x7); + state_add( ALPHA8201_MB, "MB", m_mb ).mask(0x3); + state_add( ALPHA8201_CF, "CF", m_cf ).mask(0x1); + state_add( ALPHA8201_ZF, "ZF", m_zf ).mask(0x1); + state_add( ALPHA8201_IX0, "IX0", m_ix0.b.l ); + state_add( ALPHA8201_IX1, "IX1", m_ix1.b.l ); + state_add( ALPHA8201_IX2, "IX2", m_ix2.b.l ); + state_add( ALPHA8201_LP0, "LP0", m_lp0 ); + state_add( ALPHA8201_LP1, "LP1", m_lp1 ); + state_add( ALPHA8201_LP2, "LP2", m_lp2 ); + state_add( ALPHA8201_A, "A", m_A ); + state_add( ALPHA8201_B, "B", m_B ); + state_add( ALPHA8201_R0, "R0", m_R[0] ).callimport().callexport().formatstr("%02X"); + state_add( ALPHA8201_R1, "R1", m_R[1] ).callimport().callexport().formatstr("%02X"); + state_add( ALPHA8201_R2, "R2", m_R[2] ).callimport().callexport().formatstr("%02X"); + state_add( ALPHA8201_R3, "R3", m_R[3] ).callimport().callexport().formatstr("%02X"); + state_add( ALPHA8201_R4, "R4", m_R[4] ).callimport().callexport().formatstr("%02X"); + state_add( ALPHA8201_R5, "R5", m_R[5] ).callimport().callexport().formatstr("%02X"); + state_add( ALPHA8201_R6, "R6", m_R[6] ).callimport().callexport().formatstr("%02X"); + state_add( ALPHA8201_R7, "R7", m_R[7] ).callimport().callexport().formatstr("%02X"); + + save_item(NAME(m_RAM)); + save_item(NAME(m_PREVPC)); + save_item(NAME(m_pc.w.l)); + save_item(NAME(m_regPtr)); + save_item(NAME(m_zf)); + save_item(NAME(m_cf)); + save_item(NAME(m_mb)); + save_item(NAME(m_halt)); + save_item(NAME(m_ix0.b.l)); + save_item(NAME(m_ix1.b.l)); + save_item(NAME(m_ix2.b.l)); + save_item(NAME(m_lp0)); + save_item(NAME(m_lp1)); + save_item(NAME(m_lp2)); + save_item(NAME(m_A)); + save_item(NAME(m_B)); + save_item(NAME(m_retptr)); + save_item(NAME(m_savec)); + save_item(NAME(m_savez)); + + m_icountptr = &m_icount; +} + + +void alpha8201_cpu_device::state_import(const device_state_entry &entry) +{ + switch (entry.index()) + { + case ALPHA8201_SP: + M_WRMEM(0x001, m_sp); + break; + + case ALPHA8201_R0: + WR_REG(0, m_R[0]); + break; + + case ALPHA8201_R1: + WR_REG(1, m_R[1]); + break; + + case ALPHA8201_R2: + WR_REG(2, m_R[2]); + break; + + case ALPHA8201_R3: + WR_REG(3, m_R[3]); + break; + + case ALPHA8201_R4: + WR_REG(4, m_R[4]); + break; + + case ALPHA8201_R5: + WR_REG(5, m_R[5]); + break; + + case ALPHA8201_R6: + WR_REG(6, m_R[6]); + break; + + case ALPHA8201_R7: + WR_REG(7, m_R[7]); + break; + } +} + + +void alpha8201_cpu_device::state_export(const device_state_entry &entry) +{ + switch (entry.index()) + { + case ALPHA8201_SP: + m_sp = M_RDMEM(0x001); + break; + + case ALPHA8201_R0: + m_R[0] = RD_REG(0); + break; + + case ALPHA8201_R1: + m_R[1] = RD_REG(1); + break; + + case ALPHA8201_R2: + m_R[2] = RD_REG(2); + break; + + case ALPHA8201_R3: + m_R[3] = RD_REG(3); + break; + + case ALPHA8201_R4: + m_R[4] = RD_REG(4); + break; + + case ALPHA8201_R5: + m_R[5] = RD_REG(5); + break; + + case ALPHA8201_R6: + m_R[6] = RD_REG(6); + break; + + case ALPHA8201_R7: + m_R[7] = RD_REG(7); + break; + } +} + + +void alpha8201_cpu_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + switch (entry.index()) + { + case STATE_GENFLAGS: + strprintf(str, "%c%c", m_cf ? 'C' : '.', m_zf ? 'Z' : '.'); + break; + } +} + +/**************************************************************************** + * Reset registers to their initial values + ****************************************************************************/ +void alpha8201_cpu_device::device_reset() +{ + m_pc.w.l = 0; + m_regPtr = 0; + m_zf = 0; + m_cf = 0; + m_mb = 0; + m_ix0.w.l = 0; + m_ix1.w.l = 0; + m_ix2.w.l = 0; + m_lp0 = 0; + m_lp1 = 0; + m_lp2 = 0; + m_A = 0; + m_B = 0; + m_halt = 0; +} + + +/**************************************************************************** + * Execute cycles CPU cycles. Return number of cycles really executed + ****************************************************************************/ + +void alpha8201_cpu_device::execute_run() +{ + unsigned opcode; + UINT8 pcptr; + + if(m_halt) + { + m_icount = 0; + return; + } + + /* setup address bank & fall safe */ + m_ix0.b.h = + m_ix1.b.h = + m_ix2.b.h = (m_pc.b.h &= 3); + + /* reset start hack */ + if(m_pc.w.l<0x20) + m_mb |= 0x08; + + do + { + if(m_mb & 0x08) + { + pcptr = M_RDMEM(0x001) & 0x1f; /* pointer of entry point */ + m_icount -= C1; + + /* entry point scan phase */ + if( (pcptr&1) == 0) + { + /* EVEN , get PC low */ + m_pc.b.l = M_RDMEM(pcptr); +//osd_printf_debug("alpha8201 load PCL ENTRY=%02X PCL=%02X\n",pcptr, m_pc.b.l); + m_icount -= C1; + M_WRMEM(0x001,pcptr+1); + continue; + } + + /* ODD , check HALT flag */ + m_mb = M_RDMEM(pcptr) & (0x08|0x03); + m_icount -= C1; + + /* not entryaddress 000,001 */ + if(pcptr<2) m_mb |= 0x08; + + if(m_mb & 0x08) + { + /* HALTED current entry point . next one */ + pcptr = (pcptr+1)&0x1f; + M_WRMEM(0x001,pcptr); + m_icount -= C1; + continue; + } + + /* goto run phase */ + M_JMP(m_pc.b.l); + +#if SHOW_ENTRY_POINT +logerror("alpha8201 START ENTRY=%02X PC=%03X\n",pcptr,m_pc.w.l); +osd_printf_debug("alpha8201 START ENTRY=%02X PC=%03X\n",pcptr,m_pc.w.l); +#endif + } + + /* run */ + m_PREVPC = m_pc.w.l; + debugger_instruction_hook(this, m_pc.w.l); + opcode =M_RDOP(m_pc.w.l); +#if TRACE_PC +osd_printf_debug("alpha8201: PC = %03x, opcode = %02x\n", m_pc.w.l, opcode); +#endif + m_pc.b.l++; + m_inst_cycles = m_opmap[opcode].cycles; + (this->*m_opmap[opcode].opcode_func)(); + m_icount -= m_inst_cycles; + } while (m_icount>0); +} + + +/**************************************************************************** + * Set IRQ line state + ****************************************************************************/ +void alpha8201_cpu_device::execute_set_input(int inputnum, int state) +{ + if(inputnum == INPUT_LINE_HALT) + { + m_halt = (state==ASSERT_LINE) ? 1 : 0; +/* osd_printf_debug("alpha8201 HALT %d\n",m_halt); */ + } +} + + +offs_t alpha8201_cpu_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( alpha8201 ); + return CPU_DISASSEMBLE_NAME(alpha8201)(this, buffer, pc, oprom, opram, options); +} diff --git a/src/devices/cpu/alph8201/alph8201.h b/src/devices/cpu/alph8201/alph8201.h new file mode 100644 index 00000000000..16555803988 --- /dev/null +++ b/src/devices/cpu/alph8201/alph8201.h @@ -0,0 +1,408 @@ +// license:BSD-3-Clause +// copyright-holders:Tatsuyuki Satoh + /**************************************************************************\ + * Alpha8201 Emulator * + * * + * Copyright Tatsuyuki Satoh * + * Originally written for the MAME project. * + * * + * * + \**************************************************************************/ + +#pragma once + +#ifndef __ALPH8201_H__ +#define __ALPH8201_H__ + +enum +{ + ALPHA8201_PC=1, + ALPHA8201_SP, + ALPHA8201_RB, + ALPHA8201_MB, +// + ALPHA8201_CF, + ALPHA8201_ZF, +// + ALPHA8201_IX0, + ALPHA8201_IX1, + ALPHA8201_IX2, + ALPHA8201_LP0, + ALPHA8201_LP1, + ALPHA8201_LP2, + ALPHA8201_A, + ALPHA8201_B, +// + ALPHA8201_R0,ALPHA8201_R1,ALPHA8201_R2,ALPHA8201_R3, + ALPHA8201_R4,ALPHA8201_R5,ALPHA8201_R6,ALPHA8201_R7 +}; + + +class alpha8201_cpu_device : public cpu_device +{ +public: + // construction/destruction + alpha8201_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + alpha8201_cpu_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_execute_interface overrides + virtual UINT32 execute_min_cycles() const { return 1; } + virtual UINT32 execute_max_cycles() const { return 16; } + virtual UINT32 execute_input_lines() const { return 1; } + virtual void execute_run(); + virtual void execute_set_input(int inputnum, int state); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const { return (spacenum == AS_PROGRAM) ? &m_program_config : ( (spacenum == AS_IO) ? &m_io_config : NULL ); } + + // device_state_interface overrides + virtual void state_import(const device_state_entry &entry); + virtual void state_export(const device_state_entry &entry); + void state_string_export(const device_state_entry &entry, std::string &str); + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const { return 1; } + virtual UINT32 disasm_max_opcode_bytes() const { return 4; } + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + + UINT8 M_RDMEM(UINT16 A) { return m_program->read_byte(A); } + void M_WRMEM(UINT16 A,UINT8 V) { m_program->write_byte(A, V); } + UINT8 M_RDOP(UINT16 A) { return m_direct->read_byte(A); } + UINT8 M_RDOP_ARG(UINT16 A) { return m_direct->read_byte(A); } + UINT8 RD_REG(UINT8 x) { return m_RAM[(m_regPtr<<3)+(x)]; } + void WR_REG(UINT8 x, UINT8 d) { m_RAM[(m_regPtr<<3)+(x)]=(d); } + + unsigned M_RDMEM_OPCODE(); + void M_ADD(UINT8 dat); + void M_ADDB(UINT8 dat); + void M_SUB(UINT8 dat); + void M_AND(UINT8 dat); + void M_OR(UINT8 dat); + void M_XOR(UINT8 dat); + void M_JMP(UINT8 dat); + void M_UNDEFINED(); + void M_UNDEFINED2(); + + void undefined() { M_UNDEFINED(); } + void undefined2() { M_UNDEFINED2(); } + + void nop() { } + void rora() { m_cf = m_A &1; m_A = (m_A>>1) | (m_A<<7); } + void rola() { m_cf = (m_A>>7)&1; m_A = (m_A<<1) | (m_A>>7); } + void inc_b() { M_ADDB(0x02); } + void dec_b() { M_ADDB(0xfe); } + void inc_a() { M_ADD(0x01); } + void dec_a() { M_ADD(0xff); } + void cpl() { m_A ^= 0xff; }; + + void ld_a_ix0_0() { m_A = M_RDMEM(m_ix0.w.l+0); } + void ld_a_ix0_1() { m_A = M_RDMEM(m_ix0.w.l+1); } + void ld_a_ix0_2() { m_A = M_RDMEM(m_ix0.w.l+2); } + void ld_a_ix0_3() { m_A = M_RDMEM(m_ix0.w.l+3); } + void ld_a_ix0_4() { m_A = M_RDMEM(m_ix0.w.l+4); } + void ld_a_ix0_5() { m_A = M_RDMEM(m_ix0.w.l+5); } + void ld_a_ix0_6() { m_A = M_RDMEM(m_ix0.w.l+6); } + void ld_a_ix0_7() { m_A = M_RDMEM(m_ix0.w.l+7); } + + void ld_a_ix1_0() { m_A = M_RDMEM(m_ix1.w.l+0); } + void ld_a_ix1_1() { m_A = M_RDMEM(m_ix1.w.l+1); } + void ld_a_ix1_2() { m_A = M_RDMEM(m_ix1.w.l+2); } + void ld_a_ix1_3() { m_A = M_RDMEM(m_ix1.w.l+3); } + void ld_a_ix1_4() { m_A = M_RDMEM(m_ix1.w.l+4); } + void ld_a_ix1_5() { m_A = M_RDMEM(m_ix1.w.l+5); } + void ld_a_ix1_6() { m_A = M_RDMEM(m_ix1.w.l+6); } + void ld_a_ix1_7() { m_A = M_RDMEM(m_ix1.w.l+7); } + + void ld_ix2_0_a() { M_WRMEM(m_ix2.w.l+0,m_A); } + void ld_ix2_1_a() { M_WRMEM(m_ix2.w.l+1,m_A); } + void ld_ix2_2_a() { M_WRMEM(m_ix2.w.l+2,m_A); } + void ld_ix2_3_a() { M_WRMEM(m_ix2.w.l+3,m_A); } + void ld_ix2_4_a() { M_WRMEM(m_ix2.w.l+4,m_A); } + void ld_ix2_5_a() { M_WRMEM(m_ix2.w.l+5,m_A); } + void ld_ix2_6_a() { M_WRMEM(m_ix2.w.l+6,m_A); } + void ld_ix2_7_a() { M_WRMEM(m_ix2.w.l+7,m_A); } + + void ld_ix0_0_b() { m_RAM[(m_B>>1)&0x3f] = M_RDMEM(m_ix0.w.l+0); } + void ld_ix0_1_b() { m_RAM[(m_B>>1)&0x3f] = M_RDMEM(m_ix0.w.l+1); } + void ld_ix0_2_b() { m_RAM[(m_B>>1)&0x3f] = M_RDMEM(m_ix0.w.l+2); } + void ld_ix0_3_b() { m_RAM[(m_B>>1)&0x3f] = M_RDMEM(m_ix0.w.l+3); } + void ld_ix0_4_b() { m_RAM[(m_B>>1)&0x3f] = M_RDMEM(m_ix0.w.l+4); } + void ld_ix0_5_b() { m_RAM[(m_B>>1)&0x3f] = M_RDMEM(m_ix0.w.l+5); } + void ld_ix0_6_b() { m_RAM[(m_B>>1)&0x3f] = M_RDMEM(m_ix0.w.l+6); } + void ld_ix0_7_b() { m_RAM[(m_B>>1)&0x3f] = M_RDMEM(m_ix0.w.l+7); } + + void bit_r0_0() { m_zf = RD_REG(0)&(1<<0)?0:1; } + void bit_r0_1() { m_zf = RD_REG(0)&(1<<1)?0:1; } + void bit_r0_2() { m_zf = RD_REG(0)&(1<<2)?0:1; } + void bit_r0_3() { m_zf = RD_REG(0)&(1<<3)?0:1; } + void bit_r0_4() { m_zf = RD_REG(0)&(1<<4)?0:1; } + void bit_r0_5() { m_zf = RD_REG(0)&(1<<5)?0:1; } + void bit_r0_6() { m_zf = RD_REG(0)&(1<<6)?0:1; } + void bit_r0_7() { m_zf = RD_REG(0)&(1<<7)?0:1; } + + void ld_a_n() { m_A = M_RDMEM_OPCODE(); } + + void ld_a_r0() { m_A = RD_REG(0); m_zf = (m_A==0); } + void ld_a_r1() { m_A = RD_REG(1); m_zf = (m_A==0); } + void ld_a_r2() { m_A = RD_REG(2); m_zf = (m_A==0); } + void ld_a_r3() { m_A = RD_REG(3); m_zf = (m_A==0); } + void ld_a_r4() { m_A = RD_REG(4); m_zf = (m_A==0); } + void ld_a_r5() { m_A = RD_REG(5); m_zf = (m_A==0); } + void ld_a_r6() { m_A = RD_REG(6); m_zf = (m_A==0); } + void ld_a_r7() { m_A = RD_REG(7); m_zf = (m_A==0); } + + void ld_r0_a() { WR_REG(0,m_A); } + void ld_r1_a() { WR_REG(1,m_A); } + void ld_r2_a() { WR_REG(2,m_A); } + void ld_r3_a() { WR_REG(3,m_A); } + void ld_r4_a() { WR_REG(4,m_A); } + void ld_r5_a() { WR_REG(5,m_A); } + void ld_r6_a() { WR_REG(6,m_A); } + void ld_r7_a() { WR_REG(7,m_A); } + + void add_a_n() { M_ADD(M_RDMEM_OPCODE()); } + + void add_a_r0() { M_ADD(RD_REG(0)); } + void add_a_r1() { M_ADD(RD_REG(1)); } + void add_a_r2() { M_ADD(RD_REG(2)); } + void add_a_r3() { M_ADD(RD_REG(3)); } + void add_a_r4() { M_ADD(RD_REG(4)); } + void add_a_r5() { M_ADD(RD_REG(5)); } + void add_a_r6() { M_ADD(RD_REG(6)); } + void add_a_r7() { M_ADD(RD_REG(7)); } + + void sub_a_n() { M_SUB(M_RDMEM_OPCODE()); } + + void sub_a_r0() { M_SUB(RD_REG(0)); } + void sub_a_r1() { M_SUB(RD_REG(1)); } + void sub_a_r2() { M_SUB(RD_REG(2)); } + void sub_a_r3() { M_SUB(RD_REG(3)); } + void sub_a_r4() { M_SUB(RD_REG(4)); } + void sub_a_r5() { M_SUB(RD_REG(5)); } + void sub_a_r6() { M_SUB(RD_REG(6)); } + void sub_a_r7() { M_SUB(RD_REG(7)); } + + void and_a_n() { M_AND(M_RDMEM_OPCODE()); } + + void and_a_r0() { M_AND(RD_REG(0)); } + void and_a_r1() { M_AND(RD_REG(1)); } + void and_a_r2() { M_AND(RD_REG(2)); } + void and_a_r3() { M_AND(RD_REG(3)); } + void and_a_r4() { M_AND(RD_REG(4)); } + void and_a_r5() { M_AND(RD_REG(5)); } + void and_a_r6() { M_AND(RD_REG(6)); } + void and_a_r7() { M_AND(RD_REG(7)); } + + void or_a_n() { M_OR(M_RDMEM_OPCODE()); } + + void or_a_r0() { M_OR(RD_REG(0)); } + void or_a_r1() { M_OR(RD_REG(1)); } + void or_a_r2() { M_OR(RD_REG(2)); } + void or_a_r3() { M_OR(RD_REG(3)); } + void or_a_r4() { M_OR(RD_REG(4)); } + void or_a_r5() { M_OR(RD_REG(5)); } + void or_a_r6() { M_OR(RD_REG(6)); } + void or_a_r7() { M_OR(RD_REG(7)); } + + void add_ix0_0() { } + void add_ix0_1() { m_ix0.b.l += 1; } + void add_ix0_2() { m_ix0.b.l += 2; } + void add_ix0_3() { m_ix0.b.l += 3; } + void add_ix0_4() { m_ix0.b.l += 4; } + void add_ix0_5() { m_ix0.b.l += 5; } + void add_ix0_6() { m_ix0.b.l += 6; } + void add_ix0_7() { m_ix0.b.l += 7; } + void add_ix0_8() { m_ix0.b.l += 8; } + void add_ix0_9() { m_ix0.b.l += 9; } + void add_ix0_a() { m_ix0.b.l += 10; } + void add_ix0_b() { m_ix0.b.l += 11; } + void add_ix0_c() { m_ix0.b.l += 12; } + void add_ix0_d() { m_ix0.b.l += 13; } + void add_ix0_e() { m_ix0.b.l += 14; } + void add_ix0_f() { m_ix0.b.l += 15; } + + void add_ix1_0() { } + void add_ix1_1() { m_ix1.b.l += 1; } + void add_ix1_2() { m_ix1.b.l += 2; } + void add_ix1_3() { m_ix1.b.l += 3; } + void add_ix1_4() { m_ix1.b.l += 4; } + void add_ix1_5() { m_ix1.b.l += 5; } + void add_ix1_6() { m_ix1.b.l += 6; } + void add_ix1_7() { m_ix1.b.l += 7; } + void add_ix1_8() { m_ix1.b.l += 8; } + void add_ix1_9() { m_ix1.b.l += 9; } + void add_ix1_a() { m_ix1.b.l += 10; } + void add_ix1_b() { m_ix1.b.l += 11; } + void add_ix1_c() { m_ix1.b.l += 12; } + void add_ix1_d() { m_ix1.b.l += 13; } + void add_ix1_e() { m_ix1.b.l += 14; } + void add_ix1_f() { m_ix1.b.l += 15; } + + void add_ix2_0() { } + void add_ix2_1() { m_ix2.b.l += 1; } + void add_ix2_2() { m_ix2.b.l += 2; } + void add_ix2_3() { m_ix2.b.l += 3; } + void add_ix2_4() { m_ix2.b.l += 4; } + void add_ix2_5() { m_ix2.b.l += 5; } + void add_ix2_6() { m_ix2.b.l += 6; } + void add_ix2_7() { m_ix2.b.l += 7; } + void add_ix2_8() { m_ix2.b.l += 8; } + void add_ix2_9() { m_ix2.b.l += 9; } + void add_ix2_a() { m_ix2.b.l += 10; } + void add_ix2_b() { m_ix2.b.l += 11; } + void add_ix2_c() { m_ix2.b.l += 12; } + void add_ix2_d() { m_ix2.b.l += 13; } + void add_ix2_e() { m_ix2.b.l += 14; } + void add_ix2_f() { m_ix2.b.l += 15; } + + void ld_base_0() { m_regPtr = 0; } + void ld_base_1() { m_regPtr = 1; } + void ld_base_2() { m_regPtr = 2; } + void ld_base_3() { m_regPtr = 3; } + void ld_base_4() { m_regPtr = 4; } + void ld_base_5() { m_regPtr = 5; } + void ld_base_6() { m_regPtr = 6; } + void ld_base_7() { m_regPtr = 7; } + + void ld_bank_0() { m_mb = 0; } + void ld_bank_1() { m_mb = 1; } + void ld_bank_2() { m_mb = 2; } + void ld_bank_3() { m_mb = 3; } + + void ld_ix0_n() { m_ix0.b.l = M_RDMEM_OPCODE(); } + void ld_ix1_n() { m_ix1.b.l = M_RDMEM_OPCODE(); } + void ld_ix2_n() { m_ix2.b.l = M_RDMEM_OPCODE(); } + void ld_lp0_n() { m_lp0 = M_RDMEM_OPCODE(); } + void ld_lp1_n() { m_lp1 = M_RDMEM_OPCODE(); } + void ld_lp2_n() { m_lp2 = M_RDMEM_OPCODE(); } + void ld_b_n() { m_B = M_RDMEM_OPCODE(); } + + void djnz_lp0() { UINT8 i=M_RDMEM_OPCODE(); m_lp0--; if (m_lp0 != 0) M_JMP(i); } + void djnz_lp1() { UINT8 i=M_RDMEM_OPCODE(); m_lp1--; if (m_lp1 != 0) M_JMP(i); } + void djnz_lp2() { UINT8 i=M_RDMEM_OPCODE(); m_lp2--; if (m_lp2 != 0) M_JMP(i); } + void jnz() { UINT8 i=M_RDMEM_OPCODE(); if (!m_zf) M_JMP(i); } + void jnc() { UINT8 i=M_RDMEM_OPCODE(); if (!m_cf) M_JMP(i);} + void jz() { UINT8 i=M_RDMEM_OPCODE(); if ( m_zf) M_JMP(i); } + void jc() { UINT8 i=M_RDMEM_OPCODE(); if ( m_cf) M_JMP(i);} + void jmp() { M_JMP(M_RDMEM_OPCODE() ); } + + void stop(); + + /* ALPHA 8301 : added instruction */ + void exg_a_ix0() { UINT8 t=m_A; m_A = m_ix0.b.l; m_ix0.b.l = t; } + void exg_a_ix1() { UINT8 t=m_A; m_A = m_ix1.b.l; m_ix1.b.l = t; } + void exg_a_ix2() { UINT8 t=m_A; m_A = m_ix2.b.l; m_ix2.b.l = t; } + void exg_a_lp0() { UINT8 t=m_A; m_A = m_lp0; m_lp0 = t; } + void exg_a_lp1() { UINT8 t=m_A; m_A = m_lp1; m_lp1 = t; } + void exg_a_lp2() { UINT8 t=m_A; m_A = m_lp2; m_lp2 = t; } + void exg_a_b() { UINT8 t=m_A; m_A = m_B; m_B = t; } + void exg_a_rb() { UINT8 t=m_A; m_A = m_regPtr; m_regPtr = t; } + + void ld_ix0_a() { m_ix0.b.l = m_A; } + void ld_ix1_a() { m_ix1.b.l = m_A; } + void ld_ix2_a() { m_ix2.b.l = m_A; } + void ld_lp0_a() { m_lp0 = m_A; } + void ld_lp1_a() { m_lp1 = m_A; } + void ld_lp2_a() { m_lp2 = m_A; } + void ld_b_a() { m_B = m_A; } + void ld_rb_a() { m_regPtr = m_A; } + + void exg_ix0_ix1() { UINT8 t=m_ix1.b.l; m_ix1.b.l = m_ix0.b.l; m_ix0.b.l = t; } + void exg_ix0_ix2() { UINT8 t=m_ix2.b.l; m_ix2.b.l = m_ix0.b.l; m_ix0.b.l = t; } + + void op_d4() { m_A = M_RDMEM( ((m_RAM[(7<<3)+7] & 3) << 8) | M_RDMEM_OPCODE() ); } + void op_d5() { M_WRMEM( ((m_RAM[(7<<3)+7] & 3) << 8) | M_RDMEM_OPCODE(), m_A ); } + void op_d6() { m_lp0 = M_RDMEM( ((m_RAM[(7<<3)+7] & 3) << 8) | M_RDMEM_OPCODE() ); } + void op_d7() { M_WRMEM( ((m_RAM[(7<<3)+7] & 3) << 8) | M_RDMEM_OPCODE(), m_lp0 ); } + + void ld_a_abs() { m_A = M_RDMEM( ((m_mb & 3) << 8) | M_RDMEM_OPCODE() ); } + void ld_abs_a() { M_WRMEM( ((m_mb & 3) << 8) | M_RDMEM_OPCODE(), m_A ); } + + void ld_a_r() { m_A = m_RAM[(M_RDMEM_OPCODE()>>1)&0x3f]; } + void ld_r_a() { m_RAM[(M_RDMEM_OPCODE()>>1)&0x3f] = m_A; } + void op_rep_ld_ix2_b() { do { M_WRMEM(m_ix2.w.l, m_RAM[(m_B>>1)&0x3f]); m_ix2.b.l++; m_B+=2; m_lp0--; } while (m_lp0 != 0); } + void op_rep_ld_b_ix0() { do { m_RAM[(m_B>>1)&0x3f] = M_RDMEM(m_ix0.w.l); m_ix0.b.l++; m_B+=2; m_lp0--; } while (m_lp0 != 0); } + void ld_rxb_a() { m_RAM[(m_B>>1)&0x3f] = m_A; } + void ld_a_rxb() { m_A = m_RAM[(m_B>>1)&0x3f]; } + void cmp_a_rxb() { UINT8 i=m_RAM[(m_B>>1)&0x3f]; m_zf = (m_A==i); m_cf = (m_A>=i); } + void xor_a_rxb() { M_XOR(m_RAM[(m_B>>1)&0x3f] ); } + + void add_a_cf() { if (m_cf) inc_a(); } + void sub_a_cf() { if (m_cf) dec_a(); } + void tst_a() { m_zf = (m_A==0); } + void clr_a() { m_A = 0; m_zf = (m_A==0); } + void cmp_a_n() { UINT8 i=M_RDMEM_OPCODE(); m_zf = (m_A==i); m_cf = (m_A>=i); } + void xor_a_n() { M_XOR(M_RDMEM_OPCODE() ); } + void call() { UINT8 i=M_RDMEM_OPCODE(); m_retptr.w.l = m_pc.w.l; M_JMP(i); }; + void ld_a_ix0_a() { m_A = M_RDMEM(m_ix0.w.l+m_A); } + void ret() { m_mb = m_retptr.b.h; M_JMP( m_retptr.b.l ); }; + void save_zc() { m_savez = m_zf; m_savec = m_cf; }; + void rest_zc() { m_zf = m_savez; m_cf = m_savec; }; + + typedef void ( alpha8201_cpu_device::*opcode_fun ) (); + + /* The opcode table now is a combination of cycle counts and function pointers */ + struct s_opcode { + unsigned cycles; + opcode_fun opcode_func; + }; + + static const s_opcode opcode_8201[256]; + static const s_opcode opcode_8301[256]; + + address_space_config m_program_config; + address_space_config m_io_config; + + UINT8 m_RAM[8*8]; /* internal GP register 8 * 8bank */ + unsigned m_PREVPC; + PAIR m_retptr; /* for 8301, return address of CALL */ + PAIR m_pc; /* 2bit+8bit program counter */ + UINT8 m_regPtr; /* RB register base */ + UINT8 m_mb; /* MB memory bank reg. latch after Branch */ + UINT8 m_cf; /* C flag */ + UINT8 m_zf; /* Z flag */ + UINT8 m_savec; /* for 8301, save flags */ + UINT8 m_savez; /* for 8301, save flags */ +// + PAIR m_ix0; /* 8bit memory read index reg. */ + PAIR m_ix1; /* 8bitmemory read index reg. */ + PAIR m_ix2; /* 8bitmemory write index reg. */ + UINT8 m_lp0; /* 8bit loop reg. */ + UINT8 m_lp1; /* 8bit loop reg. */ + UINT8 m_lp2; /* 8bit loop reg. */ + UINT8 m_A; /* 8bit accumerator */ + UINT8 m_B; /* 8bit regiser */ +// + UINT8 m_halt; /* halt input line */ + + address_space *m_program; + direct_read_data *m_direct; + int m_icount; + int m_inst_cycles; + + const s_opcode *m_opmap; + + // Used for import/export only + UINT8 m_sp; + UINT8 m_R[8]; +}; + + +class alpha8301_cpu_device : public alpha8201_cpu_device +{ +public: + // construction/destruction + alpha8301_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +extern const device_type ALPHA8201; +extern const device_type ALPHA8301; + + +#endif /* __ALPH8201_H__ */ diff --git a/src/devices/cpu/alto2/a2curt.c b/src/devices/cpu/alto2/a2curt.c new file mode 100644 index 00000000000..c5d9353f768 --- /dev/null +++ b/src/devices/cpu/alto2/a2curt.c @@ -0,0 +1,88 @@ +// license:BSD-3-Clause +// copyright-holders:Juergen Buchmueller +/***************************************************************************** + * + * Xerox AltoII cursor task + * + *****************************************************************************/ +#include "alto2cpu.h" + +/** + * @brief disable the cursor task and set the curt_blocks flag + */ +void alto2_cpu_device::f1_early_curt_block() +{ + m_dsp.curt_blocks = true; + m_task_wakeup &= ~(1 << m_task); + LOG((LOG_CURT,2," BLOCK %s\n", task_name(m_task))); +} + +/** + * @brief f2_load_xpreg late: load the x position register from BUS[6-15] + */ +void alto2_cpu_device::f2_late_load_xpreg() +{ + m_dsp.xpreg = X_RDBITS(m_bus,16,6,15); + LOG((LOG_CURT, 9," XPREG<- BUS[6-15] (%#o)\n", m_dsp.xpreg)); +} + +/** + * @brief f2_load_csr late: load the cursor shift register from BUS[0-15] + * + * Shift CSR to xpreg % 16 position to make it easier to + * to handle the word xor in unload_word(). + *
+ * xpreg % 16   cursor bits
+ *              [ first word   ][  second word ]
+ * ----------------------------------------------
+ *     0        xxxxxxxxxxxxxxxx0000000000000000
+ *     1        0xxxxxxxxxxxxxxxx000000000000000
+ *     2        00xxxxxxxxxxxxxxxx00000000000000
+ * ...
+ *    14        00000000000000xxxxxxxxxxxxxxxx00
+ *    15        000000000000000xxxxxxxxxxxxxxxx0
+ * 
+ */ +void alto2_cpu_device::f2_late_load_csr() +{ + m_dsp.csr = m_bus; + LOG((LOG_CURT, m_dsp.csr ? 2 : 9," CSR<- BUS (%#o)\n", m_dsp.csr)); +} + +/** + * @brief curt_activate: called by the CPU when the cursor task becomes active + */ +void alto2_cpu_device::activate_curt() +{ + m_task_wakeup &= ~(1 << m_task); + m_dsp.curt_wakeup = false; + + int x = 01777 - m_dsp.xpreg; + UINT32 bits = m_dsp.csr << (16 - (x & 15)); + m_dsp.cursor0 = static_cast(bits >> 16); + m_dsp.cursor1 = static_cast(bits); + m_dsp.curxpos = x / 16; +} + +/** @brief initialize the cursor task F1 and F2 functions */ +void alto2_cpu_device::init_curt(int task) +{ + set_f1(task, f1_block, &alto2_cpu_device::f1_early_curt_block, 0); + set_f2(task, f2_curt_load_xpreg, 0, &alto2_cpu_device::f2_late_load_xpreg); + set_f2(task, f2_curt_load_csr, 0, &alto2_cpu_device::f2_late_load_csr); + m_active_callback[task] = &alto2_cpu_device::activate_curt; +} + +void alto2_cpu_device::exit_curt() +{ + // nothing to do yet +} + +void alto2_cpu_device::reset_curt() +{ + m_dsp.curt_blocks = false; + m_dsp.xpreg = 0; + m_dsp.csr = 0; + m_dsp.curxpos = 0; + m_dsp.cursor0 = m_dsp.cursor1 = 0; +} diff --git a/src/devices/cpu/alto2/a2curt.h b/src/devices/cpu/alto2/a2curt.h new file mode 100644 index 00000000000..cdfc6a22973 --- /dev/null +++ b/src/devices/cpu/alto2/a2curt.h @@ -0,0 +1,28 @@ +// license:BSD-3-Clause +// copyright-holders:Juergen Buchmueller +/***************************************************************************** + * + * Xerox AltoII cursor task (CURT) + * + *****************************************************************************/ +#ifdef ALTO2_DEFINE_CONSTANTS + +#else // ALTO2_DEFINE_CONSTANTS +#ifndef _A2CURT_H_ +#define _A2CURT_H_ + +//! F2 functions for cursor task +enum { + f2_curt_load_xpreg = f2_task_10, //!< f2 10: load x position register + f2_curt_load_csr = f2_task_11 //!< f2 11: load cursor shift register +}; + +void f1_early_curt_block(); //!< f1_curt_block early: disable the cursor task and set the curt_blocks flag +void f2_late_load_xpreg(); //!< f2_load_xpreg late: load the x position register from BUS[6-15] +void f2_late_load_csr(); //!< f2_load_csr late: load the cursor shift register from BUS[0-15] +void activate_curt(); //!< curt_activate: called by the CPU when the cursor task becomes active +void init_curt(int task = task_curt); //!< initialize cursor task +void exit_curt(); //!< deinitialize cursor task +void reset_curt(); //!< reset cursor task +#endif // _A2CURT_H_ +#endif // ALTO2_DEFINE_CONSTANTS diff --git a/src/devices/cpu/alto2/a2dht.c b/src/devices/cpu/alto2/a2dht.c new file mode 100644 index 00000000000..3b70d371259 --- /dev/null +++ b/src/devices/cpu/alto2/a2dht.c @@ -0,0 +1,67 @@ +// license:BSD-3-Clause +// copyright-holders:Juergen Buchmueller +/***************************************************************************** + * + * Xerox AltoII display horizontal task + * + *****************************************************************************/ +#include "alto2cpu.h" + +/** + * @brief f1_dht_block early: disable the display word task + */ +void alto2_cpu_device::f1_early_dht_block() +{ + m_dsp.dht_blocks = true; + // clear the wakeup for the display horizontal task + m_task_wakeup &= ~(1 << m_task); + LOG((LOG_DHT,2," BLOCK %s\n", task_name(m_task))); +} + +/** + * @brief f2_dht_setmode late: set the next scanline's mode inverse and half clock and branch + * + * BUS[0] selects the pixel clock (0), or half pixel clock (1) + * BUS[1] selects normal mode (0), or inverse mode (1) + * + * The current BUS[0] drives the NEXT[09] line, i.e. branches to 0 or 1 + */ +void alto2_cpu_device::f2_late_dht_setmode() +{ + UINT16 r = X_RDBITS(m_bus,16,0,0); + m_dsp.setmode = m_bus; + LOG((LOG_DHT,2," SETMODE<- BUS (%#o), branch on BUS[0] (%#o | %#o)\n", m_bus, m_next2, r)); + m_next2 |= r; +} + +/** + * @brief called by the CPU when the display horizontal task becomes active + */ +void alto2_cpu_device::activate_dht() +{ + m_task_wakeup &= ~(1 << m_task); +} + +/** + * @brief initialize the display horizontal task + * + * @param task task number + */ +void alto2_cpu_device::init_dht(int task) +{ + set_f1(task, f1_block, &alto2_cpu_device::f1_early_dht_block, 0); + set_f2(task, f2_dht_evenfield, 0, &alto2_cpu_device::f2_late_evenfield); + set_f2(task, f2_dht_setmode, 0, &alto2_cpu_device::f2_late_dht_setmode); + m_active_callback[task] = &alto2_cpu_device::activate_dht; +} + +void alto2_cpu_device::exit_dht() +{ + // nothing to do yet +} + +void alto2_cpu_device::reset_dht() +{ + m_dsp.dht_blocks = true; + m_dsp.setmode = 0; +} diff --git a/src/devices/cpu/alto2/a2dht.h b/src/devices/cpu/alto2/a2dht.h new file mode 100644 index 00000000000..9ff7acc17f4 --- /dev/null +++ b/src/devices/cpu/alto2/a2dht.h @@ -0,0 +1,27 @@ +// license:BSD-3-Clause +// copyright-holders:Juergen Buchmueller +/***************************************************************************** + * + * Xerox AltoII display horizontal task (DHT) + * + *****************************************************************************/ +#ifdef ALTO2_DEFINE_CONSTANTS + +#else // ALTO2_DEFINE_CONSTANTS +#ifndef _A2DHT_H_ +#define _A2DHT_H_ + +//! F2 functions for display horizontal task +enum { + f2_dht_evenfield = f2_task_10, //!< f2 10: load even field + f2_dht_setmode = f2_task_11 //!< f2 11: set mode +}; + +void f1_early_dht_block(); //!< F1 func: disable the display word task +void f2_late_dht_setmode(); //!< F2 func: set the next scanline's mode inverse and half clock and branch +void activate_dht(); //!< called by the CPU when the display horizontal task becomes active +void init_dht(int task = task_dht); //!< initialize display horizontal task +void exit_dht(); //!< deinitialize display horizontal task +void reset_dht(); //!< reset the display horizontal task +#endif // _A2DHT_H_ +#endif // ALTO2_DEFINE_CONSTANTS diff --git a/src/devices/cpu/alto2/a2disk.c b/src/devices/cpu/alto2/a2disk.c new file mode 100644 index 00000000000..1a8736962bb --- /dev/null +++ b/src/devices/cpu/alto2/a2disk.c @@ -0,0 +1,1895 @@ +// license:BSD-3-Clause +// copyright-holders:Juergen Buchmueller +/***************************************************************************** + * + * Xerox AltoII disk interface + * + *****************************************************************************/ +#include "alto2cpu.h" + +#define GET_KADDR_SECTOR(kaddr) X_RDBITS(kaddr,16, 0, 3) //!< get sector number from address register +#define PUT_KADDR_SECTOR(kaddr,val) X_WRBITS(kaddr,16, 0, 3,val) //!< put sector number into address register +#define GET_KADDR_CYLINDER(kaddr) X_RDBITS(kaddr,16, 4,12) //!< get cylinder number from address register +#define PUT_KADDR_CYLINDER(kaddr,val) X_WRBITS(kaddr,16, 4,12,val) //!< put cylinder number int address register +#define GET_KADDR_HEAD(kaddr) X_RDBITS(kaddr,16,13,13) //!< get head number from address register +#define PUT_KADDR_HEAD(kaddr,val) X_WRBITS(kaddr,16,13,13,val) //!< put head number into address register +#define GET_KADDR_DRIVE(kaddr) X_RDBITS(kaddr,16,14,14) //!< get drive (unit) number from address register +#define PUT_KADDR_DRIVE(kaddr,val) X_WRBITS(kaddr,16,14,14,val) //!< put drive (unit) number into address register +#define GET_KADDR_RESTORE(kaddr) X_RDBITS(kaddr,16,15,15) //!< get restore flag from address register +#define PUT_KADDR_RESTORE(kaddr,val) X_WRBITS(kaddr,16,15,15,val) //!< putt restore flag into address register + +#define GET_KADR_SEAL(kadr) X_RDBITS(kadr,16, 0, 7) //!< get command seal from command register +#define PUT_KADR_SEAL(kadr,val) X_WRBITS(kadr,16, 0, 7,val) //!< put command seal into command register +#define GET_KADR_HEADER(kadr) X_RDBITS(kadr,16, 8, 9) //!< get r/w/c for header from command register +#define PUT_KADR_HEADER(kadr,val) X_WRBITS(kadr,16, 8, 9,val) //!< put r/w/c for header from command register +#define GET_KADR_LABEL(kadr) X_RDBITS(kadr,16,10,11) //!< get r/w/c for label from command register +#define PUT_KADR_LABEL(kadr,val) X_WRBITS(kadr,16,10,11,val) //!< put r/w/c for label into command register +#define GET_KADR_DATA(kadr) X_RDBITS(kadr,16,12,13) //!< get r/w/c for data from command register +#define PUT_KADR_DATA(kadr,val) X_WRBITS(kadr,16,12,13,val) //!< put r/w/c for data into command register +#define GET_KADR_NOXFER(kadr) X_RDBITS(kadr,16,14,14) //!< get no transfer flag from command register +#define PUT_KADR_NOXFER(kadr,val) X_WRBITS(kadr,16,14,14,val) //!< put no transfer flag into command register +#define GET_KADR_UNUSED(kadr) X_RDBITS(kadr,16,15,15) //!< get unused (drive?) flag from command register +#define PUT_KADR_UNUSED(kadr,val) X_WRBITS(kadr,16,15,15,val) //!< put unused (drive?) flag into command register + +#define GET_KSTAT_SECTOR(kstat) X_RDBITS(kstat,16,0,3) //!< get current sector number from status register +#define PUT_KSTAT_SECTOR(kstat,val) X_WRBITS(kstat,16,0,3,val) //!< put current sector number into status register +#define GET_KSTAT_DONE(kstat) X_RDBITS(kstat,16,4,7) //!< get 'done' field from status register (017) +#define PUT_KSTAT_DONE(kstat,val) X_WRBITS(kstat,16,4,7,val) //!< put 'done' field int status register (017) +#define GET_KSTAT_SEEKFAIL(kstat) X_RDBITS(kstat,16,8,8) //!< get seek fail flag from status register +#define PUT_KSTAT_SEEKFAIL(kstat,val) X_WRBITS(kstat,16,8,8,val) //!< put seek fail flag into status register +#define GET_KSTAT_SEEK(kstat) X_RDBITS(kstat,16,9,9) //!< get seek busy flag (strobe) from status register +#define PUT_KSTAT_SEEK(kstat,val) X_WRBITS(kstat,16,9,9,val) //!< put seek busy flag (strobe) into status register +#define GET_KSTAT_NOTRDY(kstat) X_RDBITS(kstat,16,10,10) //!< get drive not ready flag from status register +#define PUT_KSTAT_NOTRDY(kstat,val) X_WRBITS(kstat,16,10,10,val) //!< put drive not ready flag into status register +#define GET_KSTAT_DATALATE(kstat) X_RDBITS(kstat,16,11,11) //!< get data late flag from status register +#define PUT_KSTAT_DATALATE(kstat,val) X_WRBITS(kstat,16,11,11,val) //!< put data late flag into status register +#define GET_KSTAT_IDLE(kstat) X_RDBITS(kstat,16,12,12) //!< get idle flag from status register (idle is a software flag) +#define PUT_KSTAT_IDLE(kstat,val) X_WRBITS(kstat,16,12,12,val) //!< put idle flag into status register (idle is a software flag) +#define GET_KSTAT_CKSUM(kstat) X_RDBITS(kstat,16,13,13) //!< get checksum flag from status register (checksum is a software flag; it is ORed when 0) +#define PUT_KSTAT_CKSUM(kstat,val) X_WRBITS(kstat,16,13,13,val) //!< put checksum flag into status register (checksum is a software flag; it is ORed when 0) +#define GET_KSTAT_COMPLETION(kstat) X_RDBITS(kstat,16,14,15) //!< get completion code from status register (completion is a 2-bit software latch) +#define PUT_KSTAT_COMPLETION(kstat,val) X_WRBITS(kstat,16,14,15,val) //!< put completion code into status register (completion is a 2-bit software latch) + +#define GET_KCOM_XFEROFF(kcom) X_RDBITS(kcom,16,1,1) //!< get transfer off flag from controller command (hardware command register) +#define PUT_KCOM_XFEROFF(kcom,val) X_WRBITS(kcom,16,1,1,val) //!< put transfer off flag into controller command (hardware command register) +#define GET_KCOM_WDINHIB(kcom) X_RDBITS(kcom,16,2,2) //!< get word task inhibit flag from controller command (hardware command register) +#define PUT_KCOM_WDINHIB(kcom,val) X_WRBITS(kcom,16,2,2,val) //!< put word task inhibit flag into controller command (hardware command register) +#define GET_KCOM_BCLKSRC(kcom) X_RDBITS(kcom,16,3,3) //!< get bit clock source flag from controller command (hardware command register) +#define PUT_KCOM_BCLKSRC(kcom,val) X_WRBITS(kcom,16,3,3,val) //!< put bit clock source flag into controller command (hardware command register) +#define GET_KCOM_WFFO(kcom) X_RDBITS(kcom,16,4,4) //!< get write fixed frequency oscillator flag from controller command (hardware command register) +#define PUT_KCOM_WFFO(kcom,val) X_WRBITS(kcom,16,4,4,val) //!< put write fixed frequency oscillator flag into controller command (hardware command register) +#define GET_KCOM_SENDADR(kcom) X_RDBITS(kcom,16,5,5) //!< get send address flag from controller command (hardware command register) +#define PUT_KCOM_SENDADR(kcom,val) X_WRBITS(kcom,16,5,5,val) //!< put send address flag into controller command (hardware command register) + +#if defined(ALTO2_FAKE_STATUS_H) && (ALTO2_FAKE_STATUS_H > 0) +#define STATUS_DP0 48 +#define STATUS_DP1 78 +#define STATUS_RGATE 0, "%c" +#define STATUS_WGATE 1, "%c" +#define STATUS_KWRC 2, "%c" +#define STATUS_CYL 4, "C%-3d" +#define STATUS_HEAD 9, "H%d" +#define STATUS_SECT 12, "S%-2d" +#define STATUS_PAGE 16, "[%-4d]" +#define FAKE_STATUS(_unit,_which,...) do { \ + int x = (_unit) ? STATUS_DP1 : STATUS_DP0; \ + fake_status_printf(x + _which, __VA_ARGS__); \ +} while (0) +#endif + +/** @brief completion codes (only for documentation, since this is microcode defined) */ +enum { + STATUS_COMPLETION_GOOD, + STATUS_COMPLETION_HARDWARE_ERROR, + STATUS_COMPLETION_CHECK_ERROR, + STATUS_COMPLETION_ILLEGAL_SECTOR +}; + +/** @brief record numbers per sector in INCRECNO order */ +enum { + RECNO_HEADER, + RECNO_NOTHING, + RECNO_LABEL, + RECNO_DATA +}; + + +/** @brief read/write/check numbers */ +enum { + RWC_READ, + RWC_CHECK, + RWC_WRITE, + RWC_WRITE2 +}; + +#if ALTO2_DEBUG +/** @brief human readable names for the KADR<- modes */ +static const char *rwc_name[4] = {"read", "check", "write", "write2"}; +static const char* raise_lower[2] = {"/","\\"}; +#endif + +/** + *
+ * SECTOR, ERROR WAKEUPS
+ *
+ *
+ * Monoflop pulse duration:
+ * tW = K * Rt * Cext * (1 + 0.7/Rt)
+ * K = 0.28 for 74123
+ * Rt = kOhms
+ * Cext = pF
+ *
+ *                     +------+
+ *  CLRSTAT' >---------oS'    | 15k, .47uF (=470000pF)
+ *                     | MONO | 2066120ns ~= 2ms
+ *                     | FLOP |
+ *                     |      | Q'     +----+
+ *  READY'   >---------oC'    o--------|NAND|    ERRWAKE'
+ *                     +------+        |    o----+
+ *  RDYLAT'  >-------------------------|    |    |
+ *                                     +----+    |
+ *                                               |
+ *                                               |
+ *                         .---------------------+
+ *                         |
+ *                     +---o--+ Q            +------+
+ *               +-----|J  S' |----+---------|S     | 30k, .01uF (=10000pF)
+ *               |     |      |    |         | MONO | 85960ns ~= 86us
+ *   SECT[4] >---|-----|CLK   |    |         | FLOP |
+ *               |     |   21a|    |         |      | Q'
+ *               | 1 >-|K' C' |    |     1 >-|C'    |--------------------> SECLATE
+ *               |     +---o--+    |         +------+
+ *               |         |       |
+ *               +---------+-------|-----------------------------------.
+ *                                 |                                   |
+ *                 +---------------+                                   |
+ *                 |                                                   |
+ *                 |       1                 1   RESET' >------+       |
+ *                 |       |                 |                 |       |
+ *                 |   +---o--+ Q        +---o--+ Q        +---o--+ Q  |
+ *                 +---|J  S' |----------|J  S' |----------|J  S' |------> STSKENA
+ *                     |      |          |      |          |      |    |
+ *  SYSCLKB' >--+------|CLK   |  .-------|CLK   |  +-------|CLK   |    |
+ *              |      |   21b|  |       |   22a|  |       |   22b| Q' |
+ *              |  1 >-|K' C' |  |   1 >-|K' C' |  |   +---|K' C' |----+-> WAKEST'
+ *              |      +---o--+  |       +---o--+  |   |   +---o--+    |
+ *              |          |     |           |     |   |       1       |
+ *              |          +-----|-----------+-----|---|---------------+
+ *              |                |                 |   |
+ *              +----------------+-----------------+   |
+ *                                                     |
+ *                                     +----+          |
+ *   BLOCK   >-------------------------|NAND|          |
+ *                                     |    o----------+
+ *  STSKACT  >-------------------------|    |
+ *                                     +----+
+ *
+ * A CLRSTAT starts the monoflop, and READY', i.e. the ready signal from the disk
+ * drive, clears it. The Q' output is thus 0 for some time after CLRSTAT, and as
+ * long as the disk signals being ready.
+ *
+ * If the disk is not ready, i.e. the Q' being 1, and if RDYLAT' - the READY' state
+ * latched at the most recent CLRSTAT - is also 1, the ERRWAKE' signal will go 0.
+ *
+ * Each new sector (SECT[4]' going 1) will clock the FF 21a, which changes
+ * its Q output depending on WAKEST' (K' is always 1):
+ *   if J and K' are both 1, sets its Q to 1.
+ *   if J is 0, and K' is 1, keeps Q as is.
+ * So Q becomes 0 by WAKEST' going 0, and it becomes 1 with the next sector, if
+ * WAKEST' is 1.
+ *
+ * The mono-flop to the right will generate a SECLATE signal, if WAKEST' was
+ * not 0 when the disk signalled a new sector.
+ *
+ * The three J-K FFs at the bottom are all clocked with the rising edge of
+ * SYSCLKB' (i.e falling edge of SYSCLKB).
+ *
+ * The left JK-FF propagates the current state of the upper JK-FF's Q output
+ * to its own Q. The middle propagates the previous state of the left one,
+ * and the JK-FF to the right delays the wandering Q for a third SYSCLKB'
+ * rising edge, but only in one case:
+ * 1)  if J and K' are both 1, set its Q to 1.
+ * 2)  if J is 1, and K' is 0, toggle Q.
+ * 3)  if J is 0, and K' is 1, keep Q as is.
+ * 4)  if J and K' are both 0, set its Q to 0.
+ *
+ * The right FF's K' is 0 whenever the BLOCK signal (see DISK WORD TIMING)
+ * and the sector task active signal (STSKACT) are 1 at the same time.
+ *
+ * Case 1) is the normal case, and it wakes the KSECT on the third SYSCLKB'
+ * positive edge. It resets at that same time the left, middle, and upper
+ * J-K FFs .
+ *
+ * Case 2) is due, when the sector task is already active the moment
+ * the BLOCK signal arrives. This toggles the output, i.e. removes the
+ * wake.
+ *
+ * Case 3) is for an active sector task without a new sector.
+ *
+ * And finally case 4) happens when an active sector task sees no new
+ * sector, and BLOCK rises.
+ *
+ * (This is like the video timing's dwt_blocks and dht_blocks signals)
+ * 
+ */ + +/** + * @brief monoflop 31a pulse duration + * Rt = 15k, Cext = .47uF (=470000pF) => 2066120ns (~2ms) + */ +#define TW_READY 2066120 + +/** + * @brief monoflop 31b pulse duration + * Rt = 30k, Cext = .01uF (=10000pF) => 86960ns (~85us) + * + * There's something wrong with this, or the KSEC would never ever + * be able to commence the KWD. The SECLATE monoflop ouput has to go + * high some time into the KSEC task microcode, before the sequence + * error state is checked. + * + * TW_SECLATE (85960 nsec) + * TW_SECLATE (46*ALTO2_UCYCLE) + * TW_SECLATE 8596 + */ +#define TW_SECLATE 8596 + +/** @brief monoflop 52b pulse duration + * Rt = 20k, Cext = 0.01uF (=10000pF) => 57960ns (~58us) + */ +#define TW_STROBON 57960 + +/** + *
+ * DISK WORD TIMING
+ *
+ *
+ *                       SECLATE ----+  +-+-+-+---< 1
+ *                                   |  | | | |
+ *                                +--o-----------+ CARRY +---+
+ *                                | CLR 1 2 4 8  |-------|INVo-----> WDDONE'
+ *                +---+  BITCLK'  |              |       +---+
+ *    BITCLK >----|INVo----+------|CLK/   74161  |
+ *                +---+    |      +----o---------+
+ *                         |           |LOAD'
+ *              +----------+           |
+ *              |  +----+              |
+ *              +--|NAND|              |
+ *                 |    o----+         |
+ *  HIORDBIT >-----|    |    |         |
+ *                 +----+    |         |
+ *                           |         |
+ *                       +---o--+ Q    |
+ *    BUS[4] >--------+--|J  S' |------+
+ *                    |  |      |                               +----+
+ *    LDCOM' >--------|--|CLK   |                        +------|NAND|
+ *                    |  |   67b|                        |      |    o----> WAKEWDT'
+ *                    +--|K' C' |                        |   +--|    |
+ *                       +---o--+                        |   |  +----+
+ *                           |                           |   |
+ *                           1                           |   +----------+
+ *                                                       |              |
+ * OK TO RUN >---------------+                 1         |       1      |
+ * (1 in AltoI)              |                 |         |       |      |
+ *                       +---o--+ Q        +---o--+ Q    |   +---o--+ Q |
+ *                   1 >-|J  S' |----------|J  S' |------+---|J  S' |---+
+ *                       |      |          |      |      |   |      |
+ *   WDDONE' >-----------|CLK   |  +-------|CLK   |   .--|---|CLK   |
+ *                       |   43b|  |       |   53a|   |  |   |   43a|
+ *                   1 >-|K' C' |  | +-----|K' C' |   |  `---|K' C' o---+
+ *                       +---o--+  | |     +---o--+   |      +---o--+ Q'|
+ *                           |     | |         |      |          |      |
+ *                           +-----|-|---------|------|----------|------+
+ *                                 | |         |      |          |
+ *  SYSCLKA' >---------------------|-|---------|------+          |
+ *                                 | |         |                 |
+ *  WDALLOW  >---------------------|-|---------+-----------------+
+ *                                 | |         |
+ *  SYSCLKB' >---------------------+ |     +---o--+ Q
+ *                                 | | 0 >-|J  S' |-------------> WDINIT
+ *                                 | |     |      |
+ *              +----+             +-|-----|CLK   |
+ *     BLOCK >--|NAND|               |     |   53b|
+ *              |    o---------------+-----|K  C' |
+ *  WDTSKACT >--|    |                     +---o--+
+ *              +----+                         |
+ *                                             1
+ *
+ *
+ * If SECLATE is 0, WDDONE' never goes low (counter's clear has precedence).
+ *
+ * If SECLATE is 1, WDDONE', the counter will count:
+ *
+ * If HIORDBIT is 1 at the falling edge of BITCLK, it sets the J-K flip-flop 67b, and
+ * thus takes away the LOAD' assertion from the counter. It has been loaded with
+ * 15, so it counts to 16 on the next rising edge and makes WDDONE' go to 0.
+ *
+ * If HIORDBIT is 0 at the falling edge of BITCLK, counting continues as it was
+ * preset with BUS[4] at the last KCOM<- load:
+ *
+ * If BUS[4] was 1, both J and K' of the FF (74109) will be 1 at the rising edge
+ * of LDCOM' (at the end of KCOM<-) and Q will be 1 => LOAD' is deasserted.
+ *
+ * If BUS[4] was 0, both J and K' will be 0, and Q will be 0 => LOAD' asserted.
+ *
+ * WDDONE' going from 0 to 1 will make the Q output of FF 43b go to 1.
+ * The FF is also set, as long as OK TO RUN is 0.
+ *
+ * The FF 53a is clocked with falling edge of SYSCLKB (rising of SYSCLKB'),
+ * and will:
+ *   if J and K' are both 1, set its Q to 1.
+ *   if J is 1, and K' is 0, toggle Q.
+ *   if J is 0, and K' is 1, keep Q as is.
+ *   if J and K' are both 0, set its Q to 0.
+ * J is = Q of the FF 43b.
+ * K is = 0, if both BLOCK and WDTASKACT are 1, and 1 otherwise.
+ *
+ * The FF 43a is clocked with falling edge of SYSCLKA (rising of SYSCLKA').
+ * Its J and K' inputs are the Q output of the previous (middle) FF, thus
+ * it will propagate the middle FF's Q to its own Q when SYSCLKA goes 0.
+ *
+ * If Q (53a) and Q (43a) are both 1, the WAKEKWDT' is 0 and the
+ * word task wakeup signal is sent.
+ *
+ * WDALLOW going 0 asynchronously resets the 53a and 43a FFs, and thus
+ * deasserts the WAKEKWD'. It also asynchronously sets the FF 53b, and
+ * its output Q is the WDINIT signal.
+ *
+ * WDINIT is also deasserted with SYSCLKB going high, whenever both BLOCK
+ * and WDTSKACT are 1.
+ *
+ * Whoa there! :-)
+ * 
+ */ +#define WDALLOW (!GET_KCOM_WDINHIB(m_dsk.kcom)) +#define WDINIT ((m_dsk.ff_53b & JKFF_Q) ? 1 : 0) +#define RDYLAT ((m_dsk.ff_45a & JKFF_Q) ? 1 : 0) +#define SEQERR ((m_task == task_ksec && m_dsk.seclate == 0) || (m_task == task_kwd && m_dsk.bitcount == 15)) +#define ERRWAKE (RDYLAT | m_dsk.ready_mf31a) +#define SEEKOK (m_dsk.seekok) + +/** + * @brief disk word timing + * + * Implement the FIFOs and gates in the description above. + * + * @param bitclk the current bitclk level + * @param datin the level of the bit read from the disk + * @param block contains the task number of a blocking task, or 0 otherwise + */ +void alto2_cpu_device::kwd_timing(int bitclk, int datin, int block) +{ + diablo_hd_device* dhd = m_drive[m_dsk.drive]; + int wddone = m_dsk.wddone; // get previous state of word-done + int i; + UINT8 s0, s1; + + LOG((LOG_DISK,9," *** KWD timing bitclk:%d datin:%d block:%d\n", bitclk, datin, block)); + if (0 == m_dsk.seclate) + { + // if SECLATE is 0, WDDONE' never goes low (counter's clear has precedence). + if (m_dsk.bitcount) { + LOG((LOG_DISK,7," SECLATE:0 clears bitcount:0\n")); + m_dsk.bitcount = 0; + } + } + else + { + // SECLATE is 1 + if (m_dsk.bitclk && !bitclk) + { + // on the falling edge of bitclk the counter will count or be loaded + if ((m_dsk.shiftin & (1 << 16)) && !GET_KCOM_WFFO(m_dsk.kcom)) { + /* + * If HIORDBIT is 1 at the falling edge of BITCLK, it sets the + * JK-FF 67b, and thus takes away the LOAD' assertion from the + * counter. It has been loaded with 15, so it counts to 16 on + * the next rising edge and makes WDDONE' go to 0. + */ + LOG((LOG_DISK,7," HIORDBIT:1 sets WFFO:1\n")); + PUT_KCOM_WFFO(m_dsk.kcom, 1); + // TODO: show disk indicators + } + /* + * Falling edge of BITCLK, counting continues as it was preset + * with BUS[4] (WFFO) at the last KCOM<- load, or as set by a + * 1 bit being read in HIORDBIT. + */ + if (GET_KCOM_WFFO(m_dsk.kcom)) { + /* + * If BUS[4] (WFFO) was 1, both J and K' of the FF (74109) will + * be 1 at the rising edge of LDCOM' (at the end of KCOM<-) + * and Q will be 1. LOAD' is deassterted: count on clock. + */ + m_dsk.bitcount = (m_dsk.bitcount + 1) % 16; + LOG((LOG_DISK,6," WFFO:1 count bitcount:%2d\n", m_dsk.bitcount)); + } else { + /* + * If BUS[4] (WFFO) was 0, both J and K' will be 0, and Q + * will be 0. LOAD' is asserted and will load on rising bitclock (now) + */ + m_dsk.bitcount = 15; + LOG((LOG_DISK,6," WFFO:0 load bitcount:%2d\n", m_dsk.bitcount)); + } + } + if (!m_dsk.bitclk && bitclk) { + // rising edge of bitclk + m_dsk.shiftin = (m_dsk.shiftin << 1) | datin; // clock the input shift register + m_dsk.shiftout = m_dsk.shiftout << 1; // and the output shift register too + } + } + + if (m_dsk.wddone != wddone) { + LOG((LOG_DISK,8," WDDONE':%d->%d\n", m_dsk.wddone, wddone)); + } + + if (15 == m_dsk.bitcount) { + /* CARRY = 1 -> WDDONE' = 0 */ + wddone = 0; + if (m_dsk.wddone == 0) { + /* + * Latch a new data word while WDDONE is 0 + * Note: The shifter outputs for bits 0 to 14 are connected + * to the latches inputs 1 to 15, while input bit 0 comes + * from the current datin. + * Shifter output 15 is the HIORDBIT signal. + */ + m_dsk.datain = m_dsk.shiftin & 0177777; + /* load the output shift register */ + m_dsk.shiftout = m_dsk.dataout; + LOG((LOG_DISK,8," LATCH in:%06o (0x%04x) out:%06o (0x%04x)\n", m_dsk.datain, m_dsk.datain, m_dsk.dataout, m_dsk.dataout)); + } + } else { + /* CARRY = 0 -> WDDONE' = 1 */ + wddone = 1; + } + + // remember previous state of word-done + m_dsk.wddone = wddone; + + /** + * JK flip-flop 43b (word task) + *
+	 * CLK  WDDONE'
+	 * J    1
+	 * K'   1
+	 * S'   1
+	 * C'   WDTSKENA
+	 * Q    to 53a J
+	 * 
+ */ + s0 = m_dsk.ff_43b; + s1 = wddone ? JKFF_CLK : JKFF_0; + s1 |= JKFF_J; + s1 |= JKFF_K; + if (m_dsk.ok_to_run) + s1 |= JKFF_S; + if (!(m_dsk.ff_43a & JKFF_Q)) + s1 |= JKFF_C; + m_dsk.ff_43b = update_jkff(s0, s1, "43b KWD "); + + // loop over the 4 stages of sysclka and sysclkb transitions + for (i = 0; i < 4; i++) { +#if ALTO2_DEBUG + if (m_sysclka0[i] != m_sysclka1[i]) { + LOG((LOG_DISK,9," SYSCLKA' %s\n", raise_lower[m_sysclka1[i]])); + } + if (m_sysclkb0[i] != m_sysclkb1[i]) { + LOG((LOG_DISK,9," SYSCLKB' %s\n", raise_lower[m_sysclkb1[i]])); + } +#endif + + /** + * JK flip-flop 53b (word task) + *
+		 * CLK  SYSCLKB'
+		 * J    0
+		 * K'   (BLOCK & WDTSKACT)'
+		 * S'   WDALLOW
+		 * C'   1
+		 * Q    WDINIT
+		 * 
+ */ + s0 = m_dsk.ff_53b; + s1 = m_sysclkb1[i]; + if (block != task_kwd) + s1 |= JKFF_K; // (BLOCK & WDTSKACT)' + if (WDALLOW) + s1 |= JKFF_S; + s1 |= JKFF_C; + m_dsk.ff_53b = update_jkff(s0, s1, "53b KWD "); + + /** + * JK flip-flop 53a (word task) + *
+		 * CLK  SYSCLKB'
+		 * J    from 43b Q
+		 * K'   (BLOCK & WDTSKACT)'
+		 * S'   1
+		 * C'   WDALLOW
+		 * Q    to 43a J and K'
+		 * 
+ */ + s0 = m_dsk.ff_53a; + s1 = m_sysclkb1[i]; + if (m_dsk.ff_43b & JKFF_Q) + s1 |= JKFF_J; + if (block != task_kwd) + s1 |= JKFF_K; + s1 |= JKFF_S; + if (WDALLOW) + s1 |= JKFF_C; + m_dsk.ff_53a = update_jkff(s0, s1, "53a KWD "); + + /** + * JK flip-flop 43a (word task) + *
+		 * CLK  SYSCLKA'
+		 * J    from 53a Q
+		 * K'   from 53a Q
+		 * S'   1
+		 * C'   WDALLOW
+		 * Q    WDTSKENA', Q' WDTSKENA
+		 * 
+ */ + s0 = m_dsk.ff_43a; + s1 = m_sysclka1[i]; + if (m_dsk.ff_53a & JKFF_Q) + s1 |= JKFF_J; + if (m_dsk.ff_53a & JKFF_Q) + s1 |= JKFF_K; + s1 |= JKFF_S; + if (WDALLOW) + s1 |= JKFF_C; + m_dsk.ff_43a = update_jkff(s0, s1, "43a KWD "); + + /** + * JK flip-flop 45a (ready latch) + *
+		 * CLK  SYSCLKA'
+		 * J    READY' from drive
+		 * K'   1
+		 * S'   1
+		 * C'   CLRSTAT'
+		 * Q    RDYLAT'
+		 * 
+ */ + s0 = m_dsk.ff_45a; + s1 = m_sysclka1[i]; + if (dhd->get_ready_0()) + s1 |= JKFF_J; + s1 |= JKFF_K; + s1 |= JKFF_S; + s1 |= JKFF_C; // FIXME: CLRSTAT' ? + m_dsk.ff_45a = update_jkff(s0, s1, "45a RDYLAT"); + + /** + * sets the seqerr flip-flop 45b (Q' is SEQERR) + * JK flip-flop 45b (seqerr latch) + *
+		 * CLK  SYSCLKA'
+		 * J    1
+		 * K'   SEQERR'
+		 * S'   CLRSTAT'
+		 * C'   1
+		 * Q    to KSTAT[11] DATALATE
+		 * 
+ */ + s0 = m_dsk.ff_45b; + s1 = m_sysclka1[i]; + s1 |= JKFF_J; + if (SEQERR) + s1 |= JKFF_K; + s1 |= JKFF_S; // FIXME: CLRSTAT' ? + s1 |= JKFF_C; + m_dsk.ff_45b = update_jkff(s0, s1, "45b SEQERR"); + + /** + * JK flip-flop 22b (sector task) + *
+		 * CLK  SYSCLKB'
+		 * J    from 22a Q
+		 * K'   (BLOCK & STSKACT)'
+		 * S'   1 (really it's RESET')
+		 * C'   1
+		 * Q    STSKENA; Q' WAKEKST'
+		 * 
+ */ + s0 = m_dsk.ff_22b; + s1 = m_sysclkb1[i]; + if (m_dsk.ff_22a & JKFF_Q) + s1 |= JKFF_J; + if (block != task_ksec) + s1 |= JKFF_K; + s1 |= JKFF_S; // FIXME: RESET' ? + s1 |= JKFF_C; + m_dsk.ff_22b = update_jkff(s0, s1, "22b KSEC "); + + /** + * JK flip-flop 22a (sector task) + *
+		 * CLK  SYSCLKB'
+		 * J    from 21b Q
+		 * K'   1
+		 * S'   1
+		 * C'   WAKEST'
+		 * Q    to 22b J
+		 * 
+ */ + s0 = m_dsk.ff_22a; + s1 = m_sysclkb1[i]; + if (m_dsk.ff_21b & JKFF_Q) + s1 |= JKFF_J; + s1 |= JKFF_K; + s1 |= JKFF_S; + if (!(m_dsk.ff_22b & JKFF_Q)) + s1 |= JKFF_C; + m_dsk.ff_22a = update_jkff(s0, s1, "22a KSEC "); + + /** + * JK flip-flop 21b (sector task) + *
+		 * CLK  SYSCLKB'
+		 * J    from 21a Q
+		 * K'   1
+		 * S'   1
+		 * C'   WAKEST'
+		 * Q    to 22a J
+		 * 
+ */ + s0 = m_dsk.ff_21b; + s1 = m_sysclkb1[i]; + if (m_dsk.ff_21a & JKFF_Q) + s1 |= JKFF_J; + s1 |= JKFF_K; + s1 |= JKFF_S; + if (!(m_dsk.ff_22b & JKFF_Q)) + s1 |= JKFF_C; + m_dsk.ff_21b = update_jkff(s0, s1, "21b KSEC "); + } + + // The 53b FF Q output is the WDINIT signal. + if (WDINIT != m_dsk.wdinit) { + m_dsk.wdinit0 = m_dsk.wdinit; + // rising edge immediately + if ((m_dsk.wdinit = WDINIT) == 1) + m_dsk.wdinit0 = 1; + LOG((LOG_DISK,8," WDINIT:%d\n", m_dsk.wdinit)); + } + + /* + * If Q (53a) and Q (43a) are both 1, the WAKEKWDT' + * output is 0 and the disk word task wakeup signal is asserted. + */ + if ((m_dsk.ff_53a & JKFF_Q) && (m_dsk.ff_43a & JKFF_Q)) { + if (m_dsk.wdtskena == 1) { + LOG((LOG_DISK,2," WDTSKENA':0 and WAKEKWDT':0 wake KWD\n")); + m_dsk.wdtskena = 0; + m_task_wakeup |= 1 << task_kwd; + } + } else if (m_dsk.ff_43a & JKFF_Q) { + /* + * If Q (43a) is 1, the WDTSKENA' signal is deasserted. + */ + if (m_dsk.wdtskena == 0) { + LOG((LOG_DISK,2," WDTSKENA':1\n")); + m_dsk.wdtskena = 1; + m_task_wakeup &= ~(1 << task_kwd); + } + } + + if (0 != m_dsk.kfer) { + // no fatal error: ready AND not seqerr AND seekok + if (!RDYLAT && !SEQERR && SEEKOK) { + LOG((LOG_DISK,6," reset KFER\n")); + m_dsk.kfer = 0; + } + } else { + // fatal error: not ready OR seqerr OR not seekok + if (RDYLAT) { + LOG((LOG_DISK,6," RDYLAT sets KFER\n")); + m_dsk.kfer = 1; + } + if (SEQERR) { + LOG((LOG_DISK,6," SEQERR sets KFER\n")); + m_dsk.kfer = 1; + } + if (!SEEKOK) { + LOG((LOG_DISK,6," not SEEKOK sets KFER\n")); + m_dsk.kfer = 1; + } + } + + /* + * The FF 22b Q output is the STSKENA (sector task enable) + * signal, the Q' is the WAKEKST' signal. + */ + if (m_dsk.ff_22b & JKFF_Q) { + if (0 == (m_task_wakeup & (1 << task_ksec))) { + LOG((LOG_DISK,6," STSKENA:1; WAKEST':0 wake KSEC\n")); + m_task_wakeup |= 1 << task_ksec; + } + } else { + if (0 != (m_task_wakeup & (1 << task_ksec))) { + LOG((LOG_DISK,6," STSKENA:0; WAKEST':1\n")); + m_task_wakeup &= ~(1 << task_ksec); + } + } + + /** + * JK flip-flop 21a (sector task) + *
+	 * CLK  SECT4 (inverted sector mark from drive)
+	 * J    WAKEST'
+	 * K'   1
+	 * S'   ERRWAKE'
+	 * C'   WAKEST'
+	 * Q    to seclate monoflop
+	 * 
+ */ + s0 = m_dsk.ff_21a; + s1 = dhd->get_sector_mark_0() ? JKFF_CLK : JKFF_0; + if (!(m_dsk.ff_22b & JKFF_Q)) + s1 |= JKFF_J; + s1 |= JKFF_K; + if (!ERRWAKE) + s1 |= JKFF_S; + if (!(m_dsk.ff_22b & JKFF_Q)) + s1 |= JKFF_C; + m_dsk.ff_21a = update_jkff(s0, s1, "21a KSEC "); + + // If the KSEC FF 21a Q goes 1, pulse the SECLATE signal for some time. + if (!(m_dsk.ff_21a_old & JKFF_Q) && (m_dsk.ff_21a & JKFF_Q)) { + m_dsk.seclate_timer->adjust(attotime::from_nsec(TW_SECLATE), 1); + if (m_dsk.seclate) { + m_dsk.seclate = 0; + LOG((LOG_DISK,6," SECLATE -> 0 pulse until cycle %lld\n", cycle() + TW_SECLATE / ALTO2_UCYCLE)); + } + } + + // check if write and erase gate, or read gate are changed + if ((m_task_wakeup & (1 << task_ksec)) || GET_KCOM_XFEROFF(m_dsk.kcom) || m_dsk.kfer) { +#if ALTO2_DEBUG + if (0 == m_dsk.egate || 0 == m_dsk.wrgate || 0 == m_dsk.rdgate) { + // log the reason why gates are deasserted + LOG((LOG_DISK,6," deassert gates because of")); + if (m_task_wakeup & (1 << task_ksec)) { + LOG((LOG_DISK,6," KSECWAKE")); + } + if (GET_KCOM_XFEROFF(m_dsk.kcom)) { + LOG((LOG_DISK,6," XFEROFF")); + } + if (m_dsk.kfer) { + LOG((LOG_DISK,6," KFER")); + } + LOG((LOG_DISK,6,"\n")); + } +#endif + // sector task is active OR xferoff is set OR fatal error + dhd->set_egate(m_dsk.egate = 1); + dhd->set_wrgate(m_dsk.wrgate = 1); + dhd->set_rdgate(m_dsk.rdgate = 1); + FAKE_STATUS(m_dsk.drive, STATUS_WGATE, '-'); + FAKE_STATUS(m_dsk.drive, STATUS_RGATE, '-'); + } else { + if (m_dsk.krwc & RWC_WRITE) { + if (m_dsk.ok_to_run) { +#if ALTO2_DEBUG + if (1 == m_dsk.egate || 1 == m_dsk.wrgate) { + LOG((LOG_DISK,6," assert ")); + if (m_dsk.egate) { + LOG((LOG_DISK,6," EGATE")); + } + if (m_dsk.wrgate) { + LOG((LOG_DISK,6," WRGATE")); + } + LOG((LOG_DISK,6,"\n")); + } +#endif + // assert erase and write gates + dhd->set_egate(m_dsk.egate = 0); + dhd->set_wrgate(m_dsk.wrgate = 0); + FAKE_STATUS(m_dsk.drive, STATUS_WGATE, 'W'); + } + } else { +#if ALTO2_DEBUG + if (1 == m_dsk.rdgate) { + LOG((LOG_DISK,6," assert RDGATE\n")); + } +#endif + // assert read gate + dhd->set_rdgate(m_dsk.rdgate = 0); + FAKE_STATUS(m_dsk.drive, STATUS_RGATE, 'R'); + } + } + + m_dsk.ff_21a_old = m_dsk.ff_21a; + m_dsk.bitclk = bitclk; + m_dsk.datin = datin; +} + + +/** + * @brief timer callback to take away the SECLATE pulse (monoflop) + * @param ptr some unused pointer + * @param arg contains the seclate value + */ +void alto2_cpu_device::disk_seclate(void* ptr, INT32 arg) +{ + (void)ptr; + LOG((LOG_DISK,2," SECLATE -> %d\n", arg)); + m_dsk.seclate = arg; + m_dsk.seclate_timer->enable(false); +} + +/** + * @brief timer callback to take away the OK TO RUN pulse (reset) + * @param ptr some unused pointer + * @param arg contains the ok_to_run value + */ +void alto2_cpu_device::disk_ok_to_run(void* ptr, INT32 arg) +{ + (void)ptr; + LOG((LOG_DISK,2," OK TO RUN -> %d\n", arg)); + m_dsk.ok_to_run = arg; + m_dsk.ok_to_run_timer->enable(false); +} + +/** + * @brief timer callback to pulse the STROBE' signal to the drive + * + * STROBE' pulses are sent to the drive at a rate that depends on + * the monoflop 52b external resistor and capacitor. + * + * The drive compares the cylinder number that is presented on + * its inputs against the current cylinder, and if they don't + * match steps into the corresponding direction. + * + * On the falling edge of a strobe, the drive sets the log_addx_interlock + * flag 0 (LAI, active low). On the rising edge of the strobe the drive then + * indicates seek completion by setting addx_acknowledge to 0 (ADDRACK, active low). + * If the seek is not yet complete, it instead keeps the seek_incomplete + * flag 0 (SKINC, active low). If the seek would go beyond the last cylinder, + * the drive deasserts seek_incomplete, but does not assert the addx_acknowledge. + * + * @param ptr some unused pointer + * @param arg contains the drive, cylinder, and restore flag + */ +void alto2_cpu_device::disk_strobon(void* ptr, INT32 arg) +{ + (void)ptr; + int unit = arg % 2; + int restore = (arg / 2) % 2; + int cylinder = arg / 4; + + diablo_hd_device* dhd = m_drive[unit]; + LOG((LOG_DISK,2," STROBE #%d restore:%d cylinder:%d dhd:%p\n", unit, restore, cylinder, dhd)); + + dhd->set_cylinder(cylinder); + dhd->set_restore(restore); + // This is really monoflop 52a generating a very short 0 pulse + for (int strobe = 0; strobe < 2; strobe++) { + UINT8 s0, s1; + dhd->set_strobe(strobe); // pulse the strobe signal to the unit + + int lai = dhd->get_log_addx_interlock_0(); + LOG((LOG_DISK,6," LAI':%d\n", lai)); + /** + * JK flip-flop 44a (LAI' clocked) + *
+		 * CLK  LAI
+		 * J    1
+		 * K'   1
+		 * S'   1
+		 * C'   CLRSTAT' (not now)
+		 * Q    to seekok
+		 * 
+ */ + s0 = m_dsk.ff_44a; + s1 = lai ? JKFF_CLK : JKFF_0; + s1 |= JKFF_J; + s1 |= JKFF_K; + s1 |= JKFF_S; + s1 |= JKFF_C; + m_dsk.ff_44a = update_jkff(s0, s1, "44a LAI "); + if (dhd->get_addx_acknowledge_0() == 0 && (m_dsk.ff_44a & JKFF_Q)) { + /* if address is acknowledged, and Q' of FF 44a, clear the strobe */ + m_dsk.strobe = 0; + } + } + + if (dhd->get_addx_acknowledge_0()) { + /* no acknowledge yet */ + + } else { + /* clear the monoflop 52b, i.e. no timer restart */ + LOG((LOG_DISK,2," STROBON:%d\n", m_dsk.strobe)); + /* update the seekok status: SKINC' && LAI' && Q' of FF 44a */ + int seekok = dhd->get_seek_incomplete_0(); + if (seekok != m_dsk.seekok) { + m_dsk.seekok = seekok; + LOG((LOG_DISK,2," SEEKOK:%d\n", m_dsk.seekok)); + } + } + + LOG((LOG_DISK,2," current cylinder:%d\n", dhd->get_cylinder())); + + /* if the strobe is still set, restart the timer */ + if (m_dsk.strobe) { + m_dsk.strobon_timer->adjust(attotime::from_nsec(TW_STROBON), arg); + } else { + m_dsk.strobon_timer->reset(); + } + FAKE_STATUS(unit, STATUS_CYL, dhd->get_cylinder()); + FAKE_STATUS(unit, STATUS_HEAD, dhd->get_head()); +} + +/** @brief timer callback to change the READY monoflop 31a */ +void alto2_cpu_device::disk_ready_mf31a(void* ptr, INT32 arg) +{ + diablo_hd_device* dhd = m_drive[m_dsk.drive]; + m_dsk.ready_mf31a = arg & dhd->get_ready_0(); + /* log the not ready result with level 0, else 2 */ + LOG((LOG_DISK,m_dsk.ready_mf31a ? 0 : 2," mf31a:%d %sready\n", m_dsk.ready_mf31a, m_dsk.ready_mf31a ? "not " : "")); +} + +/** + * @brief called if one of the disk tasks (task_kwd or task_ksec) blocks + * + * @param task task that blocks (either task_ksec or task_kwd) + */ +void alto2_cpu_device::disk_block(int task) +{ + kwd_timing(m_dsk.bitclk, m_dsk.datin, task); +} + +/** + * @brief bs_read_kstat early: bus driven by disk status register KSTAT + *
+ * Part of the KSTAT register is made of two 4 bit latches S8T10 (Signetics).
+ * The signals BUS[8-11] are the current state of:
+ *     BUS[0-3]   SECT[0-3]; from the Winchester drive (inverted)
+ *     BUS[8]     SEEKOK'
+ *     BUS[9]     SRWRDY' from the Winchester drive
+ *     BUS[10]    RDYLAT' (latched READY' at last CLRSTAT, FF 45a output Q)
+ *     BUS[11]    SEQERR (latched SEQERR at last CLRSTAT, FF 45b output Q')
+ * The signals BUS[12,14-15] are just as they were loaded at KSTAT<- time.
+ *     BUS[13]    CHSEMERROR (FF 44b output Q' inverted)
+ * 
+ */ +void alto2_cpu_device::bs_early_read_kstat() +{ + diablo_hd_device* dhd = m_drive[m_dsk.drive]; + UINT16 r; + + /* KSTAT[4-7] bus is open */ + PUT_KSTAT_DONE(m_dsk.kstat, 017); + + /* KSTAT[8] latch the inverted seekok status */ + PUT_KSTAT_SEEKFAIL(m_dsk.kstat, m_dsk.seekok ? 0 : 1); + + /* KSTAT[9] latch the drive seek/read/write status */ + PUT_KSTAT_SEEK(m_dsk.kstat, dhd->get_seek_read_write_0()); + + /* KSTAT[10] latch the latched (FF 45a at CLRSTAT) ready status (Q) */ + PUT_KSTAT_NOTRDY(m_dsk.kstat, m_dsk.ff_45a & JKFF_Q ? 1 : 0); + + /* KSTAT[11] latch the latched (FF 45b at CLRSTAT) seqerr status (Q') */ + PUT_KSTAT_DATALATE(m_dsk.kstat, m_dsk.ff_45b & JKFF_Q ? 0 : 1); + + /* KSTAT[13] latch the latched (FF 44b at CLRSTAT/KSTAT<-) checksum status */ + PUT_KSTAT_CKSUM(m_dsk.kstat, m_dsk.ff_44b & JKFF_Q ? 1 : 0); + + r = m_dsk.kstat; + + LOG((LOG_DISK,1," <-KSTAT; BUS &= %#o\n", r)); + LOG((LOG_DISK,2," SECTOR : %#o\n", GET_KSTAT_SECTOR(m_dsk.kstat))); + LOG((LOG_DISK,2," DONE : %#o\n", GET_KSTAT_DONE(m_dsk.kstat))); + LOG((LOG_DISK,2," SEEKFAIL : %d\n", GET_KSTAT_SEEKFAIL(m_dsk.kstat))); + LOG((LOG_DISK,2," SEEK : %d\n", GET_KSTAT_SEEK(m_dsk.kstat))); + LOG((LOG_DISK,2," NOTRDY : %d\n", GET_KSTAT_NOTRDY(m_dsk.kstat))); + LOG((LOG_DISK,2," DATALATE : %d\n", GET_KSTAT_DATALATE(m_dsk.kstat))); + LOG((LOG_DISK,2," IDLE : %d\n", GET_KSTAT_IDLE(m_dsk.kstat))); + LOG((LOG_DISK,2," CKSUM : %d\n", GET_KSTAT_CKSUM(m_dsk.kstat))); + LOG((LOG_DISK,2," COMPLETION : %#o\n", GET_KSTAT_COMPLETION(m_dsk.kstat))); + + m_bus &= r; +} + +/** + * @brief bs_read_kdata early: bus driven by disk data register KDATA input + * + * The input data register is a latch that latches the contents of + * the lower 15 bits of a 16 bit shift register in its more significant + * 15 bits, and the current read data bit is the least significant + * bit. This is handled in kwd_timing. + */ +void alto2_cpu_device::bs_early_read_kdata() +{ + UINT16 r; + /* get the current word from the drive */ + r = m_dsk.datain; + LOG((LOG_DISK,1," <-KDATA (%#o)\n", r)); + m_bus &= r; +} + +/** + * @brief f1_strobe late: initiates a disk seek + * + * Initiates a disk seek operation. The KDATA register must have + * been loaded previously, and the SENDADR bit of the KCOM + * register previously set to 1. + */ +void alto2_cpu_device::f1_late_strobe() +{ + if (GET_KCOM_SENDADR(m_dsk.kcom)) { + LOG((LOG_DISK,1," STROBE (SENDADR:1)\n")); + /* Set the STROBON flag and start the STROBON monoflop */ + m_dsk.strobe = 1; + disk_strobon(0, + 4 * GET_KADDR_CYLINDER(m_dsk.kaddr) + + 2 * GET_KADDR_RESTORE(m_dsk.kaddr) + + m_dsk.drive); + } else { + LOG((LOG_DISK,1," STROBE (w/o SENDADR)\n")); + /* FIXME: what to do if SENDADR isn't set? */ + } +} + +/** + * @brief f1_load_kstat late: load disk status register + * + * KSTAT[12-15] are loaded from BUS[12-15], except that BUS[13] is + * ORed into KSTAT[13]. + * + * NB: The 4 bits are just software, not changed by hardware + */ +void alto2_cpu_device::f1_late_load_kstat() +{ + LOG((LOG_DISK,1," KSTAT<-; BUS[12-15] %#o\n", m_bus)); + LOG((LOG_DISK,2," IDLE : %d\n", GET_KSTAT_IDLE(m_bus))); + LOG((LOG_DISK,2," CKSUM : %d\n", GET_KSTAT_CKSUM(m_bus))); + LOG((LOG_DISK,2," COMPLETION : %#o\n", GET_KSTAT_COMPLETION(m_bus))); + + /* KSTAT[12] is just taken from BUS[12] */ + PUT_KSTAT_IDLE(m_dsk.kstat, GET_KSTAT_IDLE(m_bus)); + + /* KSTAT[14-15] are just taken from BUS[14-15] */ + PUT_KSTAT_COMPLETION(m_dsk.kstat, GET_KSTAT_COMPLETION(m_bus)); + + /* May set the CKSUM flip-flop 44b + * JK flip-flop 44b (KSTAT<- clocked) + * CLK SYSCLKA' + * J !BUS[13] + * K' 1 + * S' 1 + * C' CLRSTAT' (not now) + * Q Q' inverted to BUS[13] on <-KSTAT + */ + for (int i = 0; i < 2; i++) { + UINT8 s0, s1; + s0 = m_dsk.ff_44b; + s1 = i ? JKFF_CLK : JKFF_0; + if (!GET_KSTAT_CKSUM(m_bus)) + s1 |= JKFF_J; + s1 |= JKFF_K; + s1 |= JKFF_S; + s1 |= JKFF_C; + m_dsk.ff_44b = update_jkff(s0, s1, "44b CKSUM "); + } +} + +/** + * @brief f1_load_kdata late: load data out register, or the disk address register + * + * KDATA is loaded from BUS. + */ +void alto2_cpu_device::f1_late_load_kdata() +{ + m_dsk.dataout = m_bus; + if (GET_KCOM_SENDADR(m_dsk.kcom)) { + PUT_KADDR_SECTOR(m_dsk.kaddr, GET_KADDR_SECTOR(m_bus)); + PUT_KADDR_CYLINDER(m_dsk.kaddr, GET_KADDR_CYLINDER(m_bus)); + PUT_KADDR_HEAD(m_dsk.kaddr, GET_KADDR_HEAD(m_bus)); + PUT_KADDR_DRIVE(m_dsk.kaddr, GET_KADDR_DRIVE(m_bus)); + PUT_KADDR_RESTORE(m_dsk.kaddr, GET_KADDR_RESTORE(m_bus)); + PUT_KADDR_DRIVE(m_dsk.kaddr, GET_KADDR_DRIVE(m_bus)); + m_dsk.drive = GET_KADDR_DRIVE(m_dsk.kaddr); + + LOG((LOG_DISK,1," KDATA<-; BUS (%#o) (drive:%d restore:%d %d/%d/%02d)\n", + m_bus, + GET_KADDR_DRIVE(m_dsk.kaddr), + GET_KADDR_RESTORE(m_dsk.kaddr), + GET_KADDR_CYLINDER(m_dsk.kaddr), + GET_KADDR_HEAD(m_dsk.kaddr), + GET_KADDR_SECTOR(m_dsk.kaddr))); +#if 0 + /* printing changes in the disk address */ + { + static int last_kaddr; + if (m_dsk.kaddr != last_kaddr) { + int c = GET_KADDR_CYLINDER(m_dsk.kaddr); + int h = GET_KADDR_HEAD(m_dsk.kaddr); + int s = GET_KADDR_SECTOR(m_dsk.kaddr); + int page = DRIVE_PAGE(c,h,s); + last_kaddr = m_dsk.kaddr; + printf(" unit:%d restore:%d %d/%d/%02d page:%d\n", + GET_KADDR_DRIVE(m_dsk.kaddr), + GET_KADDR_RESTORE(m_dsk.kaddr), + c, h, s, page); + } + } +#endif + } else { + LOG((LOG_DISK,1," KDATA<-; BUS %#o (%#x)\n", m_bus, m_bus)); + } +} + +/** + * @brief f1_increcno late: advances shift registers holding KADR + * + * Advances the shift registers holding the KADR register so that they + * present the number and read/write/check status of the next record + * to the hardware. + * + *
+ * Sheet 10, shifter (74195) parts #36 and #37
+ *
+ * Vcc, BUS[08], BUS[10], BUS[12] go to #36 A,B,C,D
+ * Vcc, BUS[09], BUS[11], BUS[13] go to #37 A,B,C,D
+ * A is connected to ground on both chips;
+ * both shifters are loaded with KADR<-
+ *
+ * The QA outputs are #36 -> RECNO(0) and #37 -> RECNO(1)
+ *
+ * RECNO(0) (QA of #37) goes to J and K' of #36
+ * RECNO(1) (QA of #36) is inverted and goes to J and K' of #37
+ *
+ *  shift/   RECNO(0)    RECNO(1)     R/W/C presented
+ *   load      #37         #36        to the drive
+ * ---------------------------------------------------
+ *   load       0           0         HEADER
+ * 1st shift    1           0         LABEL
+ * 2nd shift    1           1         DATA
+ * 3rd shift    0           1         (none) 0 = read
+ * [ 4th        0           0         (none) 2 = write ]
+ * [ 5th        1           0         (none) 3 = write ]
+ * [ 6th        1           1         (none) 1 = check ]
+ * 
+ */ +void alto2_cpu_device::f1_late_increcno() +{ + switch (m_dsk.krecno) { + case RECNO_HEADER: + m_dsk.krecno = RECNO_LABEL; + m_dsk.krwc = GET_KADR_LABEL(m_dsk.kadr); + LOG((LOG_DISK,2," INCRECNO; HEADER -> LABEL (%o, rwc:%o)\n", m_dsk.krecno, m_dsk.krwc)); + break; + case RECNO_NOTHING: + m_dsk.krecno = RECNO_HEADER; + m_dsk.krwc = GET_KADR_HEADER(m_dsk.kadr); + LOG((LOG_DISK,2," INCRECNO; NOTHING -> HEADER (%o, rwc:%o)\n", m_dsk.krecno, m_dsk.krwc)); + break; + case RECNO_LABEL: + m_dsk.krecno = RECNO_DATA; + m_dsk.krwc = GET_KADR_DATA(m_dsk.kadr); + LOG((LOG_DISK,2," INCRECNO; LABEL -> DATA (%o, rwc:%o)\n", m_dsk.krecno, m_dsk.krwc)); + break; + case RECNO_DATA: + m_dsk.krecno = RECNO_NOTHING; + m_dsk.krwc = 0; /* read (?) */ + LOG((LOG_DISK,2," INCRECNO; DATA -> NOTHING (%o, rwc:%o)\n", m_dsk.krecno, m_dsk.krwc)); + break; + } + // TODO: show disk indicator + FAKE_STATUS(m_dsk.drive, STATUS_KWRC, "HPLD"[m_dsk.krecno]); +} + +/** + * @brief f1_clrstat late: reset all error latches + * + * Causes all error latches in the disk controller hardware to reset, + * clears KSTAT[13]. + * + * NB: IDLE (KSTAT[12]) and COMPLETION (KSTAT[14-15]) are not cleared + */ +void alto2_cpu_device::f1_late_clrstat() +{ + diablo_hd_device* dhd = m_drive[m_dsk.drive]; + UINT8 s0, s1; + + /* clears the LAI clocked flip-flop 44a + * JK flip-flop 44a (LAI' clocked) + * CLK (LAI')' + * J 1 + * K' 1 + * S' 1 + * C' CLRSTAT' + * Q to seekok + */ + s0 = m_dsk.ff_44a; + s1 = m_dsk.ff_44a & JKFF_CLK; + s1 |= JKFF_J; + s1 |= JKFF_K; + s1 |= JKFF_S; + s1 &= ~JKFF_C; + m_dsk.ff_44a = update_jkff(s0, s1, "44a LAI "); + + /* clears the CKSUM flip-flop 44b + * JK flip-flop 44b (KSTAT<- clocked) + * CLK SYSCLKA' (not used here, just clearing) + * J 1 (BUS[13] during KSTAT<-) + * K' 1 + * S' 1 + * C' CLRSTAT' + * Q to seekok + */ + s0 = m_dsk.ff_44b; + s1 = m_dsk.ff_44b & JKFF_CLK; + s1 |= m_dsk.ff_44b & JKFF_J; + s1 |= JKFF_K; + s1 |= JKFF_S; + s1 &= ~JKFF_C; + m_dsk.ff_44b = update_jkff(s0, s1, "44b CKSUM "); + + /* clears the rdylat flip-flop 45a + * JK flip-flop 45a (ready latch) + * CLK SYSCLKA' + * J READY' from drive + * K' 1 + * S' 1 + * C' CLRSTAT' + * Q RDYLAT' + */ + s0 = m_dsk.ff_45a; + s1 = m_dsk.ff_45a & JKFF_CLK; + if (dhd->get_ready_0()) + s1 |= JKFF_J; + s1 |= JKFF_K; + s1 |= JKFF_S; + s1 &= ~JKFF_C; + m_dsk.ff_45a = update_jkff(s0, s1, "45a RDYLAT"); + + /* sets the seqerr flip-flop 45b (Q' is SEQERR) + * JK flip-flop 45b (seqerr latch) + * CLK SYSCLKA' + * J 1 + * K' SEQERR' + * S' CLRSTAT' + * C' 1 + * Q to KSTAT[11] DATALATE + */ + s0 = m_dsk.ff_45b; + s1 = m_dsk.ff_45b & JKFF_CLK; + s1 |= JKFF_J; + if (!SEQERR) + s1 |= JKFF_K; + s1 &= ~JKFF_S; + s1 |= JKFF_C; + m_dsk.ff_45b = update_jkff(s0, s1, "45b SEQERR"); + + /* set or reset monoflop 31a, depending on drive READY' */ + m_dsk.ready_mf31a = dhd->get_ready_0(); + + /* start monoflop 31a, which resets ready_mf31a */ + m_dsk.ready_timer->adjust(attotime::from_nsec(TW_READY), 1); + + LOG((LOG_DISK,1," CLRSTAT (44a:%d 44b:%d 45a:%d 45b:%d 31a:%d)\n", + m_dsk.ff_44a & JKFF_Q ? 1 : 0, m_dsk.ff_44b & JKFF_Q ? 1 : 0, + m_dsk.ff_45a & JKFF_Q ? 1 : 0, m_dsk.ff_45b & JKFF_Q ? 1 : 0, + m_dsk.ready_mf31a)); +} + +/** + * @brief f1_load_kcom late: load the KCOM register from bus + *
+ * This causes the KCOM register to be loaded from BUS[1-5]. The
+ * KCOM register has the following interpretation:
+ *  (1) XFEROFF = 1 inhibits data transmission to/from the m_dsk.
+ *  (2) WDINHIB = 1 prevents the disk word task from awakening.
+ *  (3) BCLKSRC = 0 takes bit clock from disk input or crystal clock, as appropriate.
+ *      BCLKSRC = 1 force use of crystal clock.
+ *  (4) WFFO = 0 holds the disk bit counter at -1 until a 1 bit is read.
+ *      WFFO = 1 allows the bit counter to proceed normally.
+ *  (5) SENDADR = 1 causes KDATA[4-12] and KDATA[15] to be signalled to disk unit as track address.
+ *      SENDADR = 0 inhibits such signalling.
+ * 
+ */ +void alto2_cpu_device::f1_late_load_kcom() +{ + UINT16 change = m_dsk.kcom ^ m_bus; + m_dsk.kcom = m_bus; + LOG((LOG_DISK,2," KCOM<-; BUS %06o\n", m_dsk.kcom)); + LOG((LOG_DISK,2," XFEROFF : %d\n", GET_KCOM_XFEROFF(m_dsk.kcom))); + LOG((LOG_DISK,2," WDINHIB : %d\n", GET_KCOM_WDINHIB(m_dsk.kcom))); + LOG((LOG_DISK,2," BCLKSRC : %d\n", GET_KCOM_BCLKSRC(m_dsk.kcom))); + LOG((LOG_DISK,2," WFFO : %d\n", GET_KCOM_WFFO(m_dsk.kcom))); + LOG((LOG_DISK,2," SENDADR : %d\n", GET_KCOM_SENDADR(m_dsk.kcom))); + if (GET_KCOM_WDINHIB(change)) { + // WDALLOW going 0: should asynchronously reset 43a and 53a and set 53b + if (m_task == task_kwd) { + UINT8 s0, s1; + /** + * JK flip-flop 53b (word task) + *
+			 * CLK  SYSCLKB'
+			 * J    0
+			 * K'   (BLOCK & WDTSKACT)'
+			 * S'   WDALLOW
+			 * C'   1
+			 * Q    WDINIT
+			 * 
+ */ + s0 = m_dsk.ff_53b; + s1 = JKFF_0; + if (WDALLOW) + s1 |= JKFF_S; + s1 |= JKFF_C; + m_dsk.ff_53b = update_jkff(s0, s1, "53b KWD "); + + /** + * JK flip-flop 53a (word task) + *
+			 * CLK  SYSCLKB'
+			 * J    from 43b Q
+			 * K'   (BLOCK & WDTSKACT)'
+			 * S'   1
+			 * C'   WDALLOW
+			 * Q    to 43a J and K'
+			 * 
+ */ + s0 = m_dsk.ff_53a; + s1 = JKFF_0; + if (m_dsk.ff_43b & JKFF_Q) + s1 |= JKFF_J; + s1 |= JKFF_S; + if (WDALLOW) + s1 |= JKFF_C; + m_dsk.ff_53a = update_jkff(s0, s1, "53a KWD "); + + /** + * JK flip-flop 43a (word task) + *
+			 * CLK  SYSCLKA'
+			 * J    from 53a Q
+			 * K'   from 53a Q
+			 * S'   1
+			 * C'   WDALLOW
+			 * Q    WDTSKENA', Q' WDTSKENA
+			 * 
+ */ + s0 = m_dsk.ff_43a; + s1 = JKFF_0; + if (m_dsk.ff_53a & JKFF_Q) + s1 |= JKFF_J; + if (m_dsk.ff_53a & JKFF_Q) + s1 |= JKFF_K; + s1 |= JKFF_S; + if (WDALLOW) + s1 |= JKFF_C; + m_dsk.ff_43a = update_jkff(s0, s1, "43a KWD "); + } + } + // TODO: show disk indicator in the GUI? +} + +/** + * @brief f1_load_kadr late: load the KADR register from bus + * + * The KADR register is loaded from BUS[8-14]. This register has the format + * of word C in section 6.0 above. In addition, it causes the head address + * bit to be loaded from KDATA[13]. + * + * NB: the record numer RECNO(0) and RECNO(1) is reset to 0 + */ +void alto2_cpu_device::f1_late_load_kadr() +{ + /* store into the separate fields of KADR */ + PUT_KADR_SEAL(m_dsk.kadr, GET_KADR_SEAL(m_bus)); + PUT_KADR_HEADER(m_dsk.kadr, GET_KADR_HEADER(m_bus)); + PUT_KADR_LABEL(m_dsk.kadr, GET_KADR_LABEL(m_bus)); + PUT_KADR_DATA(m_dsk.kadr, GET_KADR_DATA(m_bus)); + PUT_KADR_NOXFER(m_dsk.kadr, GET_KADR_NOXFER(m_bus)); + PUT_KADR_UNUSED(m_dsk.kadr, GET_KADR_UNUSED(m_bus)); + + int unit = GET_KADDR_DRIVE(m_dsk.kaddr); // get selected drive from DATA[14] output (FF 67a really) + int head = GET_KADDR_HEAD(m_dsk.dataout); // latch head from DATA[13] + PUT_KADDR_HEAD(m_dsk.kaddr, head); // store in KADDR + + // select drive unit + diablo_hd_device* dhd = m_drive[unit]; + dhd->select(unit); + // set selected head + dhd->set_head(head); + + // On KDAR<- load bit 0 of parts #36 and #37 is reset to 0, i.e. recno = 0 + m_dsk.krecno = 0; + // current read/write/check is that for the header + m_dsk.krwc = GET_KADR_HEADER(m_dsk.kadr); + + LOG((LOG_DISK,1," KADR<-; BUS[8-14] #%o\n", m_dsk.kadr)); + LOG((LOG_DISK,2," SEAL : %d\n", GET_KADR_SEAL(m_dsk.kadr))); + LOG((LOG_DISK,2," HEADER : %s (%#o)\n", rwc_name[GET_KADR_HEADER(m_dsk.kadr)], GET_KADR_HEADER(m_dsk.kadr))); + LOG((LOG_DISK,2," LABEL : %s (%#o)\n", rwc_name[GET_KADR_LABEL(m_dsk.kadr)], GET_KADR_LABEL(m_dsk.kadr))); + LOG((LOG_DISK,2," DATA : %s (%#o)\n", rwc_name[GET_KADR_DATA(m_dsk.kadr)], GET_KADR_DATA(m_dsk.kadr))); + LOG((LOG_DISK,2," NOXFER : %d\n", GET_KADR_NOXFER(m_dsk.kadr))); + LOG((LOG_DISK,2," unused : %d (drive?)\n", GET_KADR_UNUSED(m_dsk.kadr))); + // TODO: show disk indicator in the GUI? +} + +/** + * @brief branch on disk word task active and init + * + * NEXT <- NEXT OR (WDTASKACT && WDINIT ? 037 : 0) + */ +void alto2_cpu_device::f2_late_init() +{ + // INIT = current task == KWD and WDINIT + UINT16 r = (m_task == task_kwd && m_dsk.wdinit0) ? 037 : 0; + LOG((LOG_DISK,1," INIT; %sbranch (%#o | %#o)\n", r ? "" : "no ", m_next2, r)); + m_next2 |= r; + m_dsk.wdinit0 = 0; +} + +/** + * @brief branch on read/write/check state of the current record + *
+ * NEXT <- NEXT OR (current record to be written ? 3 : current record to be checked ? 2 : 0);
+ *
+ * NB: note how krecno counts 0,2,3,1 ... etc.
+ * on 0: it presents the RWC for HEADER
+ * on 2: it presents the RWC for LABEL
+ * on 3: it presents the RWC for DATA
+ * on 1: it presents the RWC 0, i.e. READ
+ *
+ * -NEXT[08] = -CHECK = RWC[0] | RWC[1]
+ * -NEXT[09] = W/R = RWC[0]
+ *
+ *  rwc   | -next
+ * -------+------
+ *  0  0  |  0
+ *  0  1  |  2
+ *  1  0  |  3
+ *  1  1  |  3
+ * 
+ */ +void alto2_cpu_device::f2_late_rwc() +{ + UINT16 r; + UINT16 init = (m_task == task_kwd && m_dsk.wdinit0) ? 037 : 0; + + switch (m_dsk.krwc & 3) { + case 0: // read + r = 0; + break; + case 1: // check + r = 2; + break; + default: // write + r = 3; + } + + switch (m_dsk.krecno) { + case RECNO_HEADER: + LOG((LOG_DISK,1," RWC; %sbranch header(%d):%s (%#o|%#o|%#o)\n", + (r | init) ? "" : "no ", m_dsk.krecno, + rwc_name[m_dsk.krwc], m_next2, r, init)); + break; + case RECNO_NOTHING: + LOG((LOG_DISK,1," RWC; %sbranch pageno(%d):%s (%#o|%#o|%#o)\n", + (r | init) ? "" : "no ", m_dsk.krecno, + rwc_name[m_dsk.krwc], m_next2, r, init)); + break; + case RECNO_LABEL: + LOG((LOG_DISK,1," RWC; %sbranch label(%d):%s (%#o|%#o|%#o)\n", + (r | init) ? "" : "no ", m_dsk.krecno, + rwc_name[m_dsk.krwc], m_next2, r, init)); + break; + case RECNO_DATA: + LOG((LOG_DISK,1," RWC; %sbranch data(%d):%s (%#o|%#o|%#o)\n", + (r | init) ? "" : "no ", m_dsk.krecno, + rwc_name[m_dsk.krwc], m_next2, r, init)); + break; + } + m_next2 |= r | init; + m_dsk.wdinit0 = 0; +} + +/** + * @brief f2_recno late: branch on the current record number by a lookup table + *
+ * NEXT <- NEXT OR MAP (current record number) where
+ *   MAP(0) = 0     (header)
+ *   MAP(1) = 2     (label)
+ *   MAP(2) = 3     (pageno)
+ *   MAP(3) = 1     (data)
+ * 
+ * NB: The map isn't needed, because m_dsk.krecno counts exactly this way. + */ +void alto2_cpu_device::f2_late_recno() +{ + UINT16 r = m_dsk.krecno; + UINT16 init = (m_task == task_kwd && m_dsk.wdinit0) ? 037 : 0; + LOG((LOG_DISK,1," RECNO; %sbranch recno:%d (%#o|%#o|%#o)\n", (r | init) ? "" : "no ", m_dsk.krecno, m_next2, r, init)); + m_next2 |= r | init; + m_dsk.wdinit0 = 0; +} + +/** + * @brief branch on the data transfer state + * + * NEXT <- NEXT OR (if current command wants data transfer ? 1 : 0) + */ +void alto2_cpu_device::f2_late_xfrdat() +{ + UINT16 r = GET_KADR_NOXFER(m_dsk.kadr) ? 0 : 1; + UINT16 init = (m_task == task_kwd && m_dsk.wdinit0) ? 037 : 0; + LOG((LOG_DISK,1," XFRDAT; %sbranch (%#o|%#o|%#o)\n", (r | init) ? "" : "no ", m_next2, r, init)); + m_next2 |= r | init; + m_dsk.wdinit0 = 0; +} + +/** + * @brief branch on the disk ready signal + * + * NEXT <- NEXT OR (if disk not ready to accept command ? 1 : 0) + */ +void alto2_cpu_device::f2_late_swrnrdy() +{ + diablo_hd_device* dhd = m_drive[m_dsk.drive]; + UINT16 r = dhd->get_seek_read_write_0(); + UINT16 init = (m_task == task_kwd && m_dsk.wdinit0) ? 037 : 0; + + LOG((LOG_DISK,1," SWRNRDY; %sbranch (%#o|%#o|%#o)\n", (r | init) ? "" : "no ", m_next2, r, init)); + m_next2 |= r | init; + m_dsk.wdinit0 = 0; +} + +/** + * @brief branch on the disk fatal error condition + * + * NEXT <- NEXT OR (if fatal error in latches ? 0 : 1) + */ +void alto2_cpu_device::f2_late_nfer() +{ + UINT16 r = m_dsk.kfer ? 0 : 1; + UINT16 init = (m_task == task_kwd && m_dsk.wdinit0) ? 037 : 0; + + LOG((LOG_DISK,1," NFER; %sbranch (%#o|%#o|%#o)\n", (r | init) ? "" : "no ", m_next2, r, init)); + m_next2 |= r | init; + m_dsk.wdinit0 = 0; +} + +/** + * @brief f2_strobon late: branch on the seek busy status + * + * NEXT <- NEXT OR (if seek strobe still on ? 1 : 0) + *
+ * The STROBE signal is elongated with the help of two monoflops.
+ * The first one has a rather short pulse duration:
+ *  tW = K * Rt * Cext * (1 + 0.7/Rt)
+ *  K = 0.28 for 74123
+ *  Rt = kOhms
+ *  Cext = pF
+ * Rt = 20k, Cext = 150pf => 870ns
+ *
+ * The first one triggers the second, which will be cleared
+ * by ADDRACK' from the drive going 0.
+ * Its duration is:
+ * Rt = 20k, Cext = 0.01uF (=10000pF) => 57960ns (~= 58us)
+ * 
+ */ +void alto2_cpu_device::f2_late_strobon() +{ + UINT16 r = m_dsk.strobe; + UINT16 init = (m_task == task_kwd && m_dsk.wdinit0) ? 037 : 0; + + LOG((LOG_DISK,2," STROBON; %sbranch (%#o|%#o|%#o)\n", (r | init) ? "" : "no ", m_next2, r, init)); + m_next2 |= r | init; + m_dsk.wdinit0 = 0; +} + +/** + * @brief update the disk controller with a new bitclk + * + * @param id timer id + * @param arg bit number + */ +void alto2_cpu_device::disk_bitclk(void* ptr, INT32 arg) +{ + (void)ptr; + diablo_hd_device* dhd = m_drive[m_dsk.drive]; + int clk = arg & 1; + int bit = 0; + + /** + * The source for BITCLK and DATAIN depends on disk controller part #65 + *
+	 *  BCLKSRC  W/R | BITCLK | DATAIN
+	 * --------------+--------+---------
+	 *    0       0  |  RDCLK | RDDATA
+	 *    0       1  |  CLK/2 | DATOUT
+	 *    1       0  |  CLK/2 | RDDATA
+	 *    1       1  |  CLK/2 | DATOUT
+	 * 
+ */ + if (m_dsk.krwc & RWC_WRITE) { + if (GET_KCOM_XFEROFF(m_dsk.kcom)) { + /* do anything, if the transfer is off? */ + kwd_timing(clk, 1, 0); + } else { + bit = (m_dsk.shiftout >> 15) & 1; + kwd_timing(clk, bit, 0); + LOG((LOG_DISK,8," BITCLK#%d bit:%d (write) @%lldns\n", arg, bit, ntime())); + if (clk) + dhd->wr_data(arg, bit); + else + dhd->wr_data(arg, 1); + } + } else if (GET_KCOM_BCLKSRC(m_dsk.kcom)) { + /* always select the crystal clock */ + bit = dhd->rd_data(arg); + LOG((LOG_DISK,8," BITCLK#%d bit:%d (read, crystal) @%lldns\n", arg, bit, ntime())); + kwd_timing(clk, bit, 0); + } else { + /* if XFEROFF is set, keep the bit at 1 (RDGATE' is high) */ + if (GET_KCOM_XFEROFF(m_dsk.kcom)) { + bit = 1; + } else { + clk = dhd->rd_clock(arg); + bit = dhd->rd_data(arg); + LOG((LOG_DISK,8," BITCLK#%d bit:%d (read, driveclk) @%lldns\n", arg, bit, ntime())); + } + kwd_timing(clk, bit, 0); + } + +#if USE_BITCLK_TIMER + /* more bits to clock? */ + if (++arg < dhd->bits_per_sector()) { + m_dsk.bitclk_timer->adjust(dhd->bit_time(), arg); + } else { + m_dsk.bitclk_timer->reset(); + } +#else + if (++arg < dhd->bits_per_sector()) { + m_bitclk_time += m_dsk.bitclk_time[m_dsk.drive]; + m_bitclk_index = arg; + } else { + // stop the bitclock timer + m_bitclk_time = -1; + } +#endif +} + +/** + * @brief callback is called by the drive timer whenever a new sector starts + * + * @param unit the unit number + */ +void alto2_cpu_device::next_sector(int unit) +{ + diablo_hd_device* dhd = m_drive[unit]; + LOG((LOG_DISK,0,"%s dhd=%p\n", __FUNCTION__, dhd)); + // get bit time in pico seconds + m_dsk.bitclk_time[unit] = static_cast(dhd->bit_time().as_attoseconds() / 1000000); +#if USE_BITCLK_TIMER + LOG((LOG_DISK,0," unit #%d stop bitclk\n", unit)); + m_dsk.bitclk_timer->enable(false); +#else + if (m_bitclk_time >= 0) { + LOG((LOG_DISK,0," unit #%d stop bitclk\n", unit)); + m_bitclk_time = -1; + m_bitclk_index = -1; + } +#endif + + /* KSTAT[0-3] update the current sector in the kstat field */ + PUT_KSTAT_SECTOR(m_dsk.kstat, dhd->get_sector()); + + /* clear input and output shift registers (?) */ + m_dsk.shiftin = 0; + m_dsk.shiftout = 0; + + LOG((LOG_DISK,1," unit #%d sector %d start\n", unit, GET_KSTAT_SECTOR(m_dsk.kstat))); + +#if USE_BITCLK_TIMER + // HACK: no command, no bit clock + if (debug_read_mem(0521)) + /* start a timer chain for the bit clock */ + disk_bitclk(0, 0); +#else + // TODO: verify current sector == requested sector and only then run the bitclk? + // HACK: no command, no bit clock + if (debug_read_mem(0521)) + { + // Make the CPU execution loop call disk_bitclk + m_bitclk_time = 0; + m_bitclk_index = 0; + } +#endif +#if defined(ALTO2_FAKE_STATUS_H) && (ALTO2_FAKE_STATUS_H > 0) + if (debug_read_mem(0521) && unit == GET_KADDR_DRIVE(debug_read_mem(0523))) + { + FAKE_STATUS(unit, STATUS_SECT, dhd->get_sector()); + FAKE_STATUS(unit, STATUS_PAGE, dhd->get_page()); + } +#endif +} + +/** + * @brief initialize the disk context and insert a disk wort timer + * + * @result returns 0 on success, fatal() on error + */ +void alto2_cpu_device::init_disk() +{ + memset(&m_dsk, 0, sizeof(m_dsk)); + save_item(NAME(m_dsk.drive)); + save_item(NAME(m_dsk.kaddr)); + save_item(NAME(m_dsk.kadr)); + save_item(NAME(m_dsk.kstat)); + save_item(NAME(m_dsk.kcom)); + save_item(NAME(m_dsk.krecno)); + save_item(NAME(m_dsk.shiftin)); + save_item(NAME(m_dsk.shiftout)); + save_item(NAME(m_dsk.datain)); + save_item(NAME(m_dsk.dataout)); + save_item(NAME(m_dsk.krwc)); + save_item(NAME(m_dsk.kfer)); + save_item(NAME(m_dsk.wdtskena)); + save_item(NAME(m_dsk.wdinit0)); + save_item(NAME(m_dsk.wdinit)); + save_item(NAME(m_dsk.strobe)); + save_item(NAME(m_dsk.bitclk)); + save_item(NAME(m_dsk.datin)); + save_item(NAME(m_dsk.bitcount)); + save_item(NAME(m_dsk.carry)); + save_item(NAME(m_dsk.seclate)); + save_item(NAME(m_dsk.seekok)); + save_item(NAME(m_dsk.ok_to_run)); + save_item(NAME(m_dsk.ready_mf31a)); + save_item(NAME(m_dsk.seclate_mf31b)); +#if 0 + save_item(NAME(m_dsk.ff_21a)); + save_item(NAME(m_dsk.ff_21a_old)); + save_item(NAME(m_dsk.ff_21b)); + save_item(NAME(m_dsk.ff_22a)); + save_item(NAME(m_dsk.ff_22b)); + save_item(NAME(m_dsk.ff_43b)); + save_item(NAME(m_dsk.ff_53a)); + save_item(NAME(m_dsk.ff_43a)); + save_item(NAME(m_dsk.ff_53b)); + save_item(NAME(m_dsk.ff_44a)); + save_item(NAME(m_dsk.ff_44b)); + save_item(NAME(m_dsk.ff_45a)); + save_item(NAME(m_dsk.ff_45b)); +#endif + + /** @brief simulate previous sysclka */ + m_sysclka0[0] = JKFF_CLK; + m_sysclka0[1] = JKFF_0; + m_sysclka0[2] = JKFF_0; + m_sysclka0[3] = JKFF_CLK; + + /** @brief simulate current sysclka */ + m_sysclka1[0] = JKFF_0; + m_sysclka1[1] = JKFF_0; + m_sysclka1[2] = JKFF_CLK; + m_sysclka1[3] = JKFF_CLK; + + /** @brief simulate previous sysclkb */ + m_sysclkb0[0] = JKFF_CLK; + m_sysclkb0[1] = JKFF_CLK; + m_sysclkb0[2] = JKFF_0; + m_sysclkb0[3] = JKFF_0; + + /** @brief simulate current sysclkb */ + m_sysclkb1[0] = JKFF_CLK; + m_sysclkb1[1] = JKFF_0; + m_sysclkb1[2] = JKFF_0; + m_sysclkb1[3] = JKFF_CLK; + + m_dsk.wdtskena = 1; + m_dsk.egate = 1; + m_dsk.wrgate = 1; + m_dsk.rdgate = 1; + + m_dsk.seclate = 0; + m_dsk.ok_to_run = 0; + + m_dsk.kcom = 066000; + +#if USE_BITCLK_TIMER + m_dsk.bitclk_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(alto2_cpu_device::disk_bitclk),this)); +#endif + + m_dsk.strobon_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(alto2_cpu_device::disk_strobon),this)); + m_dsk.strobon_timer->reset(); + + m_dsk.seclate_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(alto2_cpu_device::disk_seclate),this)); + m_dsk.seclate_timer->reset(); + + m_dsk.ok_to_run_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(alto2_cpu_device::disk_ok_to_run),this)); + m_dsk.ok_to_run_timer->adjust(attotime::from_nsec(35 * ALTO2_UCYCLE / 1000), 1); + + m_dsk.ready_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(alto2_cpu_device::disk_ready_mf31a),this)); + m_dsk.ready_timer->reset(); + + m_dsk.bitclk_time[0] = static_cast(attotime::from_nsec(300).as_attoseconds() / 1000000); + m_dsk.bitclk_time[1] = static_cast(attotime::from_nsec(300).as_attoseconds() / 1000000); +} + +/** + * @brief exit disk controller - free all timers? + */ +void alto2_cpu_device::exit_disk() +{ + // nothing to do yet +} + +void alto2_cpu_device::reset_disk() +{ + m_dsk.drive = 0; + m_dsk.kaddr = 0; + m_dsk.kadr = 0; + m_dsk.kstat = 0; + m_dsk.kcom = 066000; + m_dsk.krecno = 0; + m_dsk.egate = 1; + m_dsk.wrgate = 1; + m_dsk.rdgate = 1; + m_dsk.shiftin = 0; + m_dsk.shiftout = 0; + m_dsk.datain = 0; + m_dsk.dataout = 0; + m_dsk.krwc = 0; + m_dsk.kfer = 0; + m_dsk.wdtskena = 1; + m_dsk.wddone = 0; + m_dsk.wdinit0 = 0; + m_dsk.wdinit = 0; + m_dsk.strobe = 0; + m_dsk.strobon_timer->reset(); + m_dsk.bitclk = 0; +#if USE_BITCLK_TIMER + m_dsk.bitclk_timer->reset(); +#else + m_dsk.bitclk_time[0] = static_cast(attotime::from_nsec(300).as_attoseconds() / 1000000); + m_dsk.bitclk_time[1] = static_cast(attotime::from_nsec(300).as_attoseconds() / 1000000); +#endif + m_dsk.datin = 0; + m_dsk.bitcount = 0; + m_dsk.seclate = 0; + m_dsk.seclate_timer->reset(); + m_dsk.seekok = 0; + m_dsk.ok_to_run = 0; + m_dsk.ok_to_run_timer->adjust(attotime::from_nsec(35 * ALTO2_UCYCLE / 1000), 1); + m_dsk.ready_mf31a = 0; + m_dsk.ready_timer->reset(); + m_dsk.seclate_mf31b = 0; + m_dsk.ff_21a = JKFF_0; + m_dsk.ff_21a_old = JKFF_0; + m_dsk.ff_21b = JKFF_0; + m_dsk.ff_22a = JKFF_0; + m_dsk.ff_22b = JKFF_0; + m_dsk.ff_43b = JKFF_0; + m_dsk.ff_53a = JKFF_0; + m_dsk.ff_43a = JKFF_0; + m_dsk.ff_53b = JKFF_0; + m_dsk.ff_44a = JKFF_0; + m_dsk.ff_44b = JKFF_0; + m_dsk.ff_45a = JKFF_0; + m_dsk.ff_45b = JKFF_0; + +#if defined(ALTO2_FAKE_STATUS_H) && (ALTO2_FAKE_STATUS_H > 0) + for (int unit = 0; unit < 2; unit++) { + FAKE_STATUS(unit, STATUS_RGATE, '-'); + FAKE_STATUS(unit, STATUS_WGATE, '-'); + FAKE_STATUS(unit, STATUS_KWRC, '-'); + FAKE_STATUS(unit, STATUS_CYL, 0); + FAKE_STATUS(unit, STATUS_HEAD, 0); + FAKE_STATUS(unit, STATUS_SECT, 0); + FAKE_STATUS(unit, STATUS_PAGE, 0); + } +#endif +} diff --git a/src/devices/cpu/alto2/a2disk.h b/src/devices/cpu/alto2/a2disk.h new file mode 100644 index 00000000000..5fd994f654e --- /dev/null +++ b/src/devices/cpu/alto2/a2disk.h @@ -0,0 +1,107 @@ +// license:BSD-3-Clause +// copyright-holders:Juergen Buchmueller +/***************************************************************************** + * + * Xerox AltoII disk controller block + * + *****************************************************************************/ +#ifdef ALTO2_DEFINE_CONSTANTS + +#else // ALTO2_DEFINE_CONSTANTS +#ifndef _A2DISK_H_ +#define _A2DISK_H_ + +diablo_hd_device* m_drive[2]; //!< two diablo_hd_device drives + +//! disk controller context +struct { + UINT8 drive; //!< selected drive from KADDR[14] (written to data out with SENDADR) + UINT16 kaddr; //!< A[0-15] disk hardware address (sector, cylinder, head, drive, restore) + UINT16 kadr; //!< C[0-15] with read/write/check modes for header, label and data + UINT16 kstat; //!< S[0-15] disk status + UINT16 kcom; //!< disk command (5 bits kcom[1-5]) + UINT8 krecno; //!< record number (2 bits indexing header, label, data, -/-) + UINT8 egate; //!< current erase gate signal to the DIABLO hd + UINT8 wrgate; //!< current write gate signal to the DIABLO hd + UINT8 rdgate; //!< current read gate signal to the DIABLO hd + UINT32 shiftin; //!< input shift register + UINT32 shiftout; //!< output shift register + UINT32 datain; //!< disk data in latch + UINT32 dataout; //!< disk data out latch + UINT8 krwc; //!< read/write/check for current record + UINT8 kfer; //!< disk fatal error signal state + UINT8 wdtskena; //!< disk word task enable (active low) + UINT8 wddone; //!< previous state of WDDONE + UINT8 wdinit0; //!< disk word task init at the early microcycle + UINT8 wdinit; //!< disk word task init at the late microcycle + UINT8 strobe; //!< strobe (still) active + emu_timer* strobon_timer; //!< set strobe on timer + UINT8 bitclk; //!< current bitclk state (either crystal clock, or rdclk from the drive) +#if USE_BITCLK_TIMER + emu_timer* bitclk_timer; //!< bit clock timer +#else + int bitclk_time[2]; //!< per drive time in clocks per bit +#endif + UINT8 datin; //!< current datin from the drive + UINT8 bitcount; //!< bit counter + UINT8 carry; //!< carry output of the bitcounter + UINT8 seclate; //!< sector late (monoflop output) + emu_timer* seclate_timer; //!< sector late timer + UINT8 seekok; //!< seekok state (SKINC' & LAI' & ff_44a.Q') + UINT8 ok_to_run; //!< ok to run signal (set to 1 some time after reset) + emu_timer* ok_to_run_timer; //!< ok to run timer + UINT8 ready_mf31a; //!< ready monoflop 31a + emu_timer* ready_timer; //!< ready timer + UINT8 seclate_mf31b; //!< seclate monoflop 31b + jkff_t ff_21a; //!< JK flip-flop 21a (sector task) + jkff_t ff_21a_old; //!< -"- previous state + jkff_t ff_21b; //!< JK flip-flop 21b (sector task) + jkff_t ff_22a; //!< JK flip-flop 22a (sector task) + jkff_t ff_22b; //!< JK flip-flop 22b (sector task) + jkff_t ff_43b; //!< JK flip-flop 43b (word task) + jkff_t ff_53a; //!< JK flip-flop 53a (word task) + jkff_t ff_43a; //!< JK flip-flop 43a (word task) + jkff_t ff_53b; //!< brief JK flip-flop 53b (word task) + jkff_t ff_44a; //!< JK flip-flop 44a (LAI' clocked) + jkff_t ff_44b; //!< JK flip-flop 44b (CKSUM) + jkff_t ff_45a; //!< JK flip-flop 45a (ready latch) + jkff_t ff_45b; //!< JK flip-flop 45b (seqerr latch) +} m_dsk; + +jkff_t m_sysclka0[4]; //!< simulate previous sysclka +jkff_t m_sysclka1[4]; //!< simulate current sysclka +jkff_t m_sysclkb0[4]; //!< simulate previous sysclkb +jkff_t m_sysclkb1[4]; //!< simulate current sysclkb + +void kwd_timing(int bitclk, int datin, int block); //!< disk word timing +TIMER_CALLBACK_MEMBER( disk_seclate ); //!< timer callback to take away the SECLATE pulse (monoflop) +TIMER_CALLBACK_MEMBER( disk_ok_to_run ); //!< timer callback to take away the OK TO RUN pulse (reset) +TIMER_CALLBACK_MEMBER( disk_strobon ); //!< timer callback to pulse the STROBE' signal to the drive +TIMER_CALLBACK_MEMBER( disk_ready_mf31a ); //!< timer callback to change the READY monoflop 31a +#if USE_BITCLK_TIMER +TIMER_CALLBACK_MEMBER( disk_bitclk ); //!< callback to update the disk controller with a new bitclk +#else +void disk_bitclk(void *ptr, int arg); //!< function to update the disk controller with a new bitclk +#endif +void disk_block(int task); //!< called if one of the disk tasks (task_kwd or task_ksec) blocks +void bs_early_read_kstat(); //!< bus source: bus driven by disk status register KSTAT +void bs_early_read_kdata(); //!< bus source: bus driven by disk data register KDATA input +void f1_late_strobe(); //!< F1 func: initiates a disk seek +void f1_late_load_kstat(); //!< F1 func: load disk status register +void f1_late_load_kdata(); //!< F1 func: load data out register, or the disk address register +void f1_late_increcno(); //!< F1 func: advances shift registers holding KADR +void f1_late_clrstat(); //!< F1 func: reset all error latches +void f1_late_load_kcom(); //!< F1 func: load the KCOM register from bus +void f1_late_load_kadr(); //!< F1 func: load the KADR register from bus +void f2_late_init(); //!< F2 func: branch on disk word task active and init +void f2_late_rwc(); //!< F2 func: branch on read/write/check state of the current record +void f2_late_recno(); //!< F2 func: branch on the current record number by a lookup table +void f2_late_xfrdat(); //!< F2 func: branch on the data transfer state +void f2_late_swrnrdy(); //!< F2 func: branch on the disk ready signal +void f2_late_nfer(); //!< f2_nfer late: branch on the disk fatal error condition +void f2_late_strobon(); //!< f2_strobon late: branch on the seek busy status +void init_disk(); //!< initialize the disk controller +void exit_disk(); //!< deinitialize the disk controller +void reset_disk(); //!< reset the disk controller +#endif // _A2DISK_H_ +#endif // ALTO2_DEFINE_CONSTANTS diff --git a/src/devices/cpu/alto2/a2disp.c b/src/devices/cpu/alto2/a2disp.c new file mode 100644 index 00000000000..3f902431efa --- /dev/null +++ b/src/devices/cpu/alto2/a2disp.c @@ -0,0 +1,874 @@ +// license:BSD-3-Clause +// copyright-holders:Juergen Buchmueller +/***************************************************************************** + * + * Xerox AltoII display interface + * + *****************************************************************************/ +#include "alto2cpu.h" +#include "a2roms.h" + +/** + * @brief PROM a38 contains the STOPWAKE' and MBEMBPTY' signals for the FIFO + *
+ * The inputs to a38 are the UNLOAD counter RA[0-3] and the DDR<- counter
+ * WA[0-3], and the designer decided to reverse the address lines :-)
+ *
+ *  a38  counter
+ *  -------------
+ *   A0  RA[0]
+ *   A1  RA[1]
+ *   A2  RA[2]
+ *   A3  RA[3]
+ *   A4  WA[0]
+ *   A5  WA[1]
+ *   A6  WA[2]
+ *   A7  WA[3]
+ *
+ * Only two bits of a38 are used:
+ *  O1 (002) = STOPWAKE'
+ *  O3 (010) = MBEMPTY'
+ * 
+ */ + +//! P3601 256x4 BPROM; display FIFO control: STOPWAKE, MBEMPTY +static const prom_load_t pl_displ_a38 = +{ + "displ.a38", + 0, + "fd30beb7", + "65e4a19ba4ff748d525122128c514abedd55d866", + /* size */ 0400, + /* amap */ AMAP_REVERSE_0_7, // reverse address lines A0-A7 + /* axor */ 0, + /* dxor */ 0, + /* width */ 4, + /* shift */ 0, + /* dmap */ DMAP_DEFAULT, + /* dand */ ZERO, + /* type */ sizeof(UINT8) +}; + +//! PROM a38 bit O1 is STOPWAKE' (stop DWT if bit is zero) +#define FIFO_STOPWAKE(a38) (0 == (a38 & disp_a38_STOPWAKE) ? true : false) + +//! PROM a38 bit O3 is MBEMPTY' (FIFO is empty if bit is zero) +#define FIFO_MBEMPTY(a38) (0 == (a38 & disp_a38_MBEMPTY) ? true : false) + +/** + * @brief emulation of PROM a63 in the display schematics page 8 + *
+ * The PROM's address lines are driven by a clock CLK, which is
+ * pixel clock / 24, and an inverted half-scanline signal H[1]'.
+ *
+ * It is 32x8 bits and its output bits (B) are connected to the
+ * signals, as well as its own address lines (A) through a latch
+ * of the type SN74774 like this:
+ *
+ *  PROM  174   A   others
+ *  ------------------------
+ *  B0    D5    -   HBLANK
+ *  B1    D0    -   HSYNC
+ *  B2    D4    A0  -
+ *  B3    D1    A1  -
+ *  B4    D3    A2  -
+ *  B5    D2    A3  -
+ *  B6    -     -   SCANEND
+ *  B7    -     -   HLCGATE
+ *  ------------------------
+ *  H[1]' -     A4  -
+ *
+ * The display_state_machine() is called at a rate of pixelclock/24.
+ *
+ * Decoded states of this PROM:
+ *
+ *  STATE  PROM   binary   HBLANK  HSYNC NEXT SCANEND HLCGATE
+ *  ----------------------------------------------------------
+ *    000  0007  00000111     1      1    001    0       0
+ *    001  0013  00001011     1      1    002    0       0
+ *    002  0015  00001101     1      0    003    0       0
+ *    003  0021  00010001     1      0    004    0       0
+ *    004  0024  00010100     0      0    005    0       0
+ *    005  0030  00011000     0      0    006    0       0
+ *    006  0034  00011100     0      0    007    0       0
+ *    007  0040  00100000     0      0    010    0       0
+ *    010  0044  00100100     0      0    011    0       0
+ *    011  0050  00101000     0      0    012    0       0
+ *    012  0054  00101100     0      0    013    0       0
+ *    013  0060  00110000     0      0    014    0       0
+ *    014  0064  00110100     0      0    015    0       0
+ *    015  0070  00111000     0      0    016    0       0
+ *    016  0074  00111100     0      0    017    0       0
+ *    017  0200  10000000     0      0    000    0       1
+ *    020  0004  00000100     0      0    001    0       0
+ *    021  0010  00001000     0      0    002    0       0
+ *    022  0014  00001100     0      0    003    0       0
+ *    023  0020  00010000     0      0    004    0       0
+ *    024  0024  00010100     0      0    005    0       0
+ *    025  0030  00011000     0      0    006    0       0
+ *    026  0034  00011100     0      0    007    0       0
+ *    027  0040  00100000     0      0    010    0       0
+ *    030  0044  00100100     0      0    011    0       0
+ *    031  0050  00101000     0      0    012    0       0
+ *    032  0054  00101100     0      0    013    0       0
+ *    033  0060  00110000     0      0    014    0       0
+ *    034  0064  00110100     0      0    015    0       0
+ *    035  0070  00111000     0      0    016    0       0
+ *    036  0175  01111101     1      0    017    1       0
+ *    037  0203  10000011     1      1    000    0       1
+ * 
+ */ + +//! 82S23 32x8 BPROM; display HBLANK, HSYNC, SCANEND, HLCGATE ... +static const prom_load_t pl_displ_a63 = +{ + "displ.a63", + 0, + "82a20d60", + "39d90703568be5419ada950e112d99227873fdea", + /* size */ 0040, + /* amap */ AMAP_DEFAULT, + /* axor */ 0, + /* dxor */ 0, + /* width */ 8, + /* shift */ 0, + /* dmap */ DMAP_DEFAULT, + /* dand */ ZERO, + /* type */ sizeof(UINT8) +}; + +//!< test the HBLANK (horizontal blanking) signal in PROM a63 being high +#define A63_HBLANK(a) ((a & disp_a63_HBLANK) ? true : false) + +//!< test the HSYNC (horizontal synchonisation) signal in PROM a63 being high +#define A63_HSYNC(a) ((a & disp_a63_HSYNC) ? true : false) + +//!< test the SCANEND (scanline end) signal in PROM a63 being high +#define A63_SCANEND(a) ((a & disp_a63_SCANEND) ? true : false) + +//!< test the HLCGATE (horz. line counter gate) signal in PROM a63 being high +#define A63_HLCGATE(a) ((a & disp_a63_HLCGATE) ? true : false) + +/** + * @brief PROM a66 is a 256x4 bit (type 3601) + *
+ * Address lines are driven by H[1] to H[128] of the horz. line counters.
+ * PROM is enabled when H[256] and H[512] are both 0.
+ *
+ * Q1 is VSYNC for the odd field (with H1024=0)
+ * Q2 is VSYNC for the even field (with H1024=1)
+ * Q3 is VBLANK for the odd field (with H1024=0)
+ * Q4 is VBLANK for the even field (with H1024=1)
+ * 
+ */ + +//! P3601 256x4 BPROM; display VSYNC and VBLANK +static const prom_load_t pl_displ_a66 = +{ + "displ.a66", + 0, + "9f91aad9", + "69b1d4c71f4e18103112e8601850c2654e9265cf", + /* size */ 0400, + /* amap */ AMAP_DEFAULT, + /* axor */ 0, + /* dxor */ 0, + /* width */ 4, + /* shift */ 0, + /* dmap */ DMAP_DEFAULT, + /* dand */ ZERO, + /* type */ sizeof(UINT8) +}; + +//! test the VSYNC (vertical synchronisation) signal in PROM a66 being high +#define A66_VSYNC(a) (a & (HLC1024 ? disp_a66_VSYNC_ODD : disp_a66_VSYNC_EVEN) ? false : true) + +//! test the VBLANK (vertical blanking) signal in PROM a66 being high +#define A66_VBLANK(a) (a & (HLC1024 ? disp_a66_VBLANK_ODD : disp_a66_VBLANK_EVEN) ? false : true) + +/** + * @brief double the bits for a byte (left and right of display word) to a word + */ +static const UINT16 double_bits[256] = { + 0x0000,0x0003,0x000c,0x000f,0x0030,0x0033,0x003c,0x003f, + 0x00c0,0x00c3,0x00cc,0x00cf,0x00f0,0x00f3,0x00fc,0x00ff, + 0x0300,0x0303,0x030c,0x030f,0x0330,0x0333,0x033c,0x033f, + 0x03c0,0x03c3,0x03cc,0x03cf,0x03f0,0x03f3,0x03fc,0x03ff, + 0x0c00,0x0c03,0x0c0c,0x0c0f,0x0c30,0x0c33,0x0c3c,0x0c3f, + 0x0cc0,0x0cc3,0x0ccc,0x0ccf,0x0cf0,0x0cf3,0x0cfc,0x0cff, + 0x0f00,0x0f03,0x0f0c,0x0f0f,0x0f30,0x0f33,0x0f3c,0x0f3f, + 0x0fc0,0x0fc3,0x0fcc,0x0fcf,0x0ff0,0x0ff3,0x0ffc,0x0fff, + 0x3000,0x3003,0x300c,0x300f,0x3030,0x3033,0x303c,0x303f, + 0x30c0,0x30c3,0x30cc,0x30cf,0x30f0,0x30f3,0x30fc,0x30ff, + 0x3300,0x3303,0x330c,0x330f,0x3330,0x3333,0x333c,0x333f, + 0x33c0,0x33c3,0x33cc,0x33cf,0x33f0,0x33f3,0x33fc,0x33ff, + 0x3c00,0x3c03,0x3c0c,0x3c0f,0x3c30,0x3c33,0x3c3c,0x3c3f, + 0x3cc0,0x3cc3,0x3ccc,0x3ccf,0x3cf0,0x3cf3,0x3cfc,0x3cff, + 0x3f00,0x3f03,0x3f0c,0x3f0f,0x3f30,0x3f33,0x3f3c,0x3f3f, + 0x3fc0,0x3fc3,0x3fcc,0x3fcf,0x3ff0,0x3ff3,0x3ffc,0x3fff, + 0xc000,0xc003,0xc00c,0xc00f,0xc030,0xc033,0xc03c,0xc03f, + 0xc0c0,0xc0c3,0xc0cc,0xc0cf,0xc0f0,0xc0f3,0xc0fc,0xc0ff, + 0xc300,0xc303,0xc30c,0xc30f,0xc330,0xc333,0xc33c,0xc33f, + 0xc3c0,0xc3c3,0xc3cc,0xc3cf,0xc3f0,0xc3f3,0xc3fc,0xc3ff, + 0xcc00,0xcc03,0xcc0c,0xcc0f,0xcc30,0xcc33,0xcc3c,0xcc3f, + 0xccc0,0xccc3,0xcccc,0xcccf,0xccf0,0xccf3,0xccfc,0xccff, + 0xcf00,0xcf03,0xcf0c,0xcf0f,0xcf30,0xcf33,0xcf3c,0xcf3f, + 0xcfc0,0xcfc3,0xcfcc,0xcfcf,0xcff0,0xcff3,0xcffc,0xcfff, + 0xf000,0xf003,0xf00c,0xf00f,0xf030,0xf033,0xf03c,0xf03f, + 0xf0c0,0xf0c3,0xf0cc,0xf0cf,0xf0f0,0xf0f3,0xf0fc,0xf0ff, + 0xf300,0xf303,0xf30c,0xf30f,0xf330,0xf333,0xf33c,0xf33f, + 0xf3c0,0xf3c3,0xf3cc,0xf3cf,0xf3f0,0xf3f3,0xf3fc,0xf3ff, + 0xfc00,0xfc03,0xfc0c,0xfc0f,0xfc30,0xfc33,0xfc3c,0xfc3f, + 0xfcc0,0xfcc3,0xfccc,0xfccf,0xfcf0,0xfcf3,0xfcfc,0xfcff, + 0xff00,0xff03,0xff0c,0xff0f,0xff30,0xff33,0xff3c,0xff3f, + 0xffc0,0xffc3,0xffcc,0xffcf,0xfff0,0xfff3,0xfffc,0xffff +}; + +#define HLC1 ((m_dsp.hlc >> 0) & 1) //!< horizontal line counter bit 0 (mid of the scanline) +#define HLC2 ((m_dsp.hlc >> 1) & 1) //!< horizontal line counter bit 1 +#define HLC4 ((m_dsp.hlc >> 2) & 1) //!< horizontal line counter bit 2 +#define HLC8 ((m_dsp.hlc >> 3) & 1) //!< horizontal line counter bit 3 +#define HLC16 ((m_dsp.hlc >> 4) & 1) //!< horizontal line counter bit 4 +#define HLC32 ((m_dsp.hlc >> 5) & 1) //!< horizontal line counter bit 5 +#define HLC64 ((m_dsp.hlc >> 6) & 1) //!< horizontal line counter bit 6 +#define HLC128 ((m_dsp.hlc >> 7) & 1) //!< horizontal line counter bit 7 +#define HLC256 ((m_dsp.hlc >> 8) & 1) //!< horizontal line counter bit 8 +#define HLC512 ((m_dsp.hlc >> 9) & 1) //!< horizontal line counter bit 9 +#define HLC1024 ((m_dsp.hlc >> 10) & 1) //!< horizontal line counter bit 10 (odd/even field) + +#define GET_SETMODE_SPEEDY(mode) X_RDBITS(mode,16,0,0) //!< get the pixel clock speed from a SETMODE<- bus value +#define GET_SETMODE_INVERSE(mode) X_RDBITS(mode,16,1,1) //!< get the inverse video flag from a SETMODE<- bus value + +//!< helper to extract A3-A0 from a PROM a63 value +#define A63_NEXT(n) ((n >> 2) & 017) + +//! update the internal bitmap to a byte array +void alto2_cpu_device::update_bitmap_word(UINT16* bitmap, int x, int y, UINT16 word) +{ + // mixing with the cursor + if (x == m_dsp.curxpos + 0) + word ^= m_dsp.cursor0; + if (x == m_dsp.curxpos + 1) + word ^= m_dsp.cursor1; + // no change? + if (word == bitmap[x]) + return; + bitmap[x] = word; + UINT8* pix = m_dsp.scanline[y] + x * 16; + *pix++ = (word >> 15) & 1; + *pix++ = (word >> 14) & 1; + *pix++ = (word >> 13) & 1; + *pix++ = (word >> 12) & 1; + *pix++ = (word >> 11) & 1; + *pix++ = (word >> 10) & 1; + *pix++ = (word >> 9) & 1; + *pix++ = (word >> 8) & 1; + *pix++ = (word >> 7) & 1; + *pix++ = (word >> 6) & 1; + *pix++ = (word >> 5) & 1; + *pix++ = (word >> 4) & 1; + *pix++ = (word >> 3) & 1; + *pix++ = (word >> 2) & 1; + *pix++ = (word >> 1) & 1; + *pix++ = (word >> 0) & 1; +} + +/** + * @brief unload the next word from the display FIFO and shift it to the screen + */ +void alto2_cpu_device::unload_word() +{ + int x = m_unload_word; + int y = ((m_dsp.hlc - m_dsp.vblank) & ~02001) ^ HLC1024; + + if (y < 0 || y >= ALTO2_DISPLAY_HEIGHT || x >= ALTO2_DISPLAY_VISIBLE_WORDS) + { + m_unload_time = -1; + return; + } + UINT16* bitmap = m_dsp.raw_bitmap + y * ALTO2_DISPLAY_SCANLINE_WORDS; + UINT16 word = m_dsp.inverse; + UINT8 a38 = m_disp_a38[m_dsp.ra * 16 + m_dsp.wa]; + if (FIFO_MBEMPTY(a38)) + { + LOG((LOG_DISPL,1, " DSP FIFO underrun y:%d x:%d\n", y, x)); + } + else + { + word ^= m_dsp.fifo[m_dsp.ra]; + m_dsp.ra = (m_dsp.ra + 1) % ALTO2_DISPLAY_FIFO; + LOG((LOG_DISPL,3, " DSP pull %04x from FIFO[%02o] y:%d x:%d\n", + word, (m_dsp.ra - 1) & (ALTO2_DISPLAY_FIFO - 1), y, x)); + } + + if (m_dsp.halfclock) + { + UINT16 word1 = double_bits[word / 256]; + UINT16 word2 = double_bits[word % 256]; + update_bitmap_word(bitmap, x, y, word1); + x++; + if (x < ALTO2_DISPLAY_VISIBLE_WORDS) + { + update_bitmap_word(bitmap, x, y, word2); + x++; + } + m_unload_time += ALTO2_DISPLAY_BITTIME(32); + } + else + { + update_bitmap_word(bitmap, x, y, word); + x++; + m_unload_time += ALTO2_DISPLAY_BITTIME(16); + } + if (x < ALTO2_DISPLAY_VISIBLE_WORDS) + m_unload_word = x; + else + m_unload_time = -1; +} + + +/** + * @brief function called by the CPU to enter the next display state + * + * There are 32 states per scanline and 875 scanlines per frame. + */ +void alto2_cpu_device::display_state_machine() +{ + LOG((LOG_DISPL,5,"DSP%03o:", m_dsp.state)); + if (020 == m_dsp.state) + { + LOG((LOG_DISPL,2," HLC=%d", m_dsp.hlc)); + } + + UINT8 a63 = m_disp_a63[m_dsp.state]; + if (A63_HLCGATE(a63)) + { + // count horizontal line counters and wrap + m_dsp.hlc += 1; + if (m_dsp.hlc > ALTO2_DISPLAY_HLC_END) + m_dsp.hlc = ALTO2_DISPLAY_HLC_START; + // wake up the memory refresh task _twice_ on each scanline + m_task_wakeup |= 1 << task_mrt; + } + // PROM a66 is disabled, if any of HLC256 or HLC512 are high + UINT8 a66 = (HLC256 || HLC512) ? 017 : m_disp_a66[m_dsp.hlc & 0377]; + + // next address from PROM a63, use A4 from HLC1 + UINT8 next = ((HLC1 ^ 1) << 4) | A63_NEXT(a63); + + if (A66_VBLANK(a66)) + { + // Rising edge of VBLANK: remember HLC[1-10] where the VBLANK starts + m_dsp.vblank = m_dsp.hlc & ~02000; + + LOG((LOG_DISPL,1, " VBLANK")); + + // VSYNC is always within VBLANK, thus we handle it only here + if (A66_VSYNC(a66)) + { + if (!A66_VSYNC(m_dsp.a66)) + { + LOG((LOG_DISPL,1, " VSYNC/ (wake DVT)")); + /* + * The display vertical task DVT is woken once per field + * at the beginning of vertical retrace. + */ + m_task_wakeup |= 1 << task_dvt; + // TODO: upade odd or even field of the internal bitmap now? + } + } + } + else + { + // Falling edge of VBLANK? + if (A66_VBLANK(m_dsp.a66)) + { + /* + * VBLANKPULSE: + * The display horizontal task DHT is woken once at the + * beginning of each field, and thereafter whenever the + * display word task blocks. + * + * The DHT can block itself, in which case neither it nor + * the word task can be woken until the start of the + * next field. + */ + LOG((LOG_DISPL,1, " VBLANKPULSE (wake DHT)")); + m_dsp.dht_blocks = false; + m_dsp.dwt_blocks = false; + m_task_wakeup |= 1 << task_dht; + /* + * VBLANKPULSE also resets the cursor task block flip flop, + * which is built from two NAND gates a40c and a40d (74H01). + */ + m_dsp.curt_blocks = false; + } + if (!A63_HBLANK(a63) && A63_HBLANK(m_dsp.a63)) + { + // Falling edge of a63 HBLANK starts unloading of FIFO words + LOG((LOG_DISPL,1, " HBLANK\\ UNLOAD")); + m_unload_time = ALTO2_DISPLAY_BITTIME(m_dsp.halfclock ? 32 : 16); + m_unload_word = 0; + } + } + + /* + * The wakeup request for the display word task (DWT) is controlled by + * the state of the 16 word FIFO. If DWT has not executed a BLOCK, + * if DHT is not blocked, and if the buffer is not full, DWT wakeups + * are generated. + */ + UINT8 a38 = m_disp_a38[m_dsp.ra * 16 + m_dsp.wa]; + if (!m_dsp.dwt_blocks && !m_dsp.dht_blocks && !FIFO_STOPWAKE(a38)) + { + m_task_wakeup |= 1 << task_dwt; + LOG((LOG_DISPL,1, " (wake DWT)")); + } + + // Stop waking up the DWT when SCANEND is active + if (A63_SCANEND(a63)) + { + m_task_wakeup &= ~(1 << task_dwt); + LOG((LOG_DISPL,1, " SCANEND")); + } + + LOG((LOG_DISPL,1, "%s", A63_HBLANK(a63) ? " HBLANK": "")); + + if (A63_HSYNC(a63)) + { + // Active HSYNC + if (!A63_HSYNC(m_dsp.a63)) + { + // Rising edge of HSYNC => CLRBUF + LOG((LOG_DISPL,1, " HSYNC/ (CLRBUF)")); + /* + * The hardware sets the buffer empty and clears the DWT block + * flip-flop at the beginning of horizontal retrace for + * every scanline. + */ + m_dsp.wa = 0; + m_dsp.ra = 0; + m_dsp.dwt_blocks = false; + // now take the new values from the last SETMODE<- + m_dsp.inverse = GET_SETMODE_INVERSE(m_dsp.setmode) ? 0xffff : 0x0000; + m_dsp.halfclock = GET_SETMODE_SPEEDY(m_dsp.setmode) ? true : false; + // stop the CPU execution loop from calling unload_word() + m_unload_time = -1; + } + else + { + LOG((LOG_DISPL,1, " HSYNC")); + } + } + else + // Falling edge of HSYNC? + if (A63_HSYNC(m_dsp.a63)) + { + /* + * CLRBUF' also resets the 2nd cursor task block flip flop, + * which is built from two NAND gates a30c and a30d (74H00). + * If both flip flops are reset, the NOR gate a20d (74S02) + * decodes this as WAKECURT signal. + */ + m_dsp.curt_wakeup = true; + if (!m_dsp.curt_blocks) + m_task_wakeup |= 1 << task_curt; + } + + LOG((LOG_DISPL,1, " NEXT:%03o\n", next)); + + m_dsp.a63 = a63; + m_dsp.a66 = a66; + m_dsp.state = next; + m_dsp_time += ALTO2_DISPLAY_BITTIME(32); +} + +/** + * @brief branch on evenfield + * + * NEXT(09) = even field ? 1 : 0 + */ +void alto2_cpu_device::f2_late_evenfield() +{ + UINT16 r = HLC1024 ^ 1; + LOG((LOG_DISPL,2," EVENFIELD branch (%#o | %#o)\n", m_next2, r)); + m_next2 |= r; +} + +/** + * @brief initialize the display context to useful values + * + * Zap the display context to all 0s. + * Allocate a bitmap array to save blitting to the screen when + * there is no change in the data words. + */ +void alto2_cpu_device::init_disp() +{ + memset(&m_dsp, 0, sizeof(m_dsp)); + save_item(NAME(m_dsp.state)); + save_item(NAME(m_dsp.hlc)); + save_item(NAME(m_dsp.setmode)); + save_item(NAME(m_dsp.inverse)); + save_item(NAME(m_dsp.halfclock)); + save_item(NAME(m_dsp.fifo)); + save_item(NAME(m_dsp.wa)); + save_item(NAME(m_dsp.ra)); + save_item(NAME(m_dsp.a63)); + save_item(NAME(m_dsp.a66)); + save_item(NAME(m_dsp.dht_blocks)); + save_item(NAME(m_dsp.dwt_blocks)); + save_item(NAME(m_dsp.curt_blocks)); + save_item(NAME(m_dsp.curt_wakeup)); + save_item(NAME(m_dsp.vblank)); + save_item(NAME(m_dsp.xpreg)); + save_item(NAME(m_dsp.csr)); + save_item(NAME(m_dsp.curxpos)); + save_item(NAME(m_dsp.cursor0)); + save_item(NAME(m_dsp.cursor1)); + + m_disp_a38 = prom_load(machine(), &pl_displ_a38, memregion("displ_a38")->base()); + m_disp_a63 = prom_load(machine(), &pl_displ_a63, memregion("displ_a63")->base()); + m_disp_a66 = prom_load(machine(), &pl_displ_a66, memregion("displ_a66")->base()); + + m_dsp.hlc = ALTO2_DISPLAY_HLC_START; + + m_dsp.raw_bitmap = auto_alloc_array(machine(), UINT16, ALTO2_DISPLAY_HEIGHT * ALTO2_DISPLAY_SCANLINE_WORDS); + m_dsp.scanline = auto_alloc_array(machine(), UINT8*, ALTO2_DISPLAY_HEIGHT + ALTO2_FAKE_STATUS_H); + for (int y = 0; y < ALTO2_DISPLAY_HEIGHT + ALTO2_FAKE_STATUS_H; y++) + m_dsp.scanline[y] = auto_alloc_array(machine(), UINT8, ALTO2_DISPLAY_TOTAL_WIDTH); + + m_dsp.bitmap = auto_bitmap_ind16_alloc(machine(), ALTO2_DISPLAY_WIDTH, ALTO2_DISPLAY_HEIGHT + ALTO2_FAKE_STATUS_H); + m_dsp.state = 0; +} + +void alto2_cpu_device::exit_disp() +{ + // nothing to do yet +} + +void alto2_cpu_device::reset_disp() +{ + m_dsp.state = 0; + m_dsp.hlc = ALTO2_DISPLAY_HLC_START; + m_dsp.a63 = 0; + m_dsp.a66 = 0; + m_dsp.setmode = 0; + m_dsp.inverse = 0; + m_dsp.halfclock = false; + m_dsp.wa = 0; + m_dsp.ra = 0; + m_dsp.dht_blocks = false; + m_dsp.dwt_blocks = false; + m_dsp.curt_blocks = false; + m_dsp.curt_wakeup = false; + m_dsp.vblank = 0; + m_dsp.xpreg = 0; + m_dsp.csr = 0; + m_dsp.curxpos = 0; + m_dsp.cursor0 = 0; + m_dsp.cursor1 = 0; + memset(m_dsp.raw_bitmap, 0, sizeof(UINT16) * ALTO2_DISPLAY_HEIGHT * ALTO2_DISPLAY_SCANLINE_WORDS); + for (int y = 0; y < ALTO2_DISPLAY_HEIGHT; y++) + memset(m_dsp.scanline[y], 0, sizeof(UINT8) * ALTO2_DISPLAY_TOTAL_WIDTH); + m_dsp.odd_frame = false; + + for (int y = ALTO2_DISPLAY_HEIGHT; y < ALTO2_DISPLAY_HEIGHT + ALTO2_FAKE_STATUS_H; y++) + memset(m_dsp.scanline[y], 1, sizeof(UINT8) * ALTO2_DISPLAY_TOTAL_WIDTH); + fake_status_printf(1, "* Fake Status *"); +} + +/* Video update */ +UINT32 alto2_cpu_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) +{ + pen_t palette_bw[2]; + palette_bw[0] = screen.palette()->white_pen(); + palette_bw[1] = screen.palette()->black_pen(); + // copy even or odd field + for (int y = m_dsp.odd_frame ? 0 : 1; y < ALTO2_DISPLAY_HEIGHT; y += 2) + draw_scanline8(*m_dsp.bitmap, 0, y, ALTO2_DISPLAY_WIDTH, m_dsp.scanline[y], palette_bw); + // copy fake status scanlines + for (int y = ALTO2_DISPLAY_HEIGHT; y < ALTO2_DISPLAY_HEIGHT + ALTO2_FAKE_STATUS_H; y++) + draw_scanline8(*m_dsp.bitmap, 0, y, ALTO2_DISPLAY_WIDTH, m_dsp.scanline[y], palette_bw); + // copy bitmap + copybitmap(bitmap, *m_dsp.bitmap, 0, 0, 0, 0, cliprect); + return 0; +} + +void alto2_cpu_device::screen_eof(screen_device &screen, bool state) +{ + if (state) + m_dsp.odd_frame = !m_dsp.odd_frame; +} + +/***************************************************************************** + * + * FAKE STATUS LINE + * + *****************************************************************************/ + +typedef struct { + UINT8 code; + UINT8 bits[10]; +} bdf_6x10_t; + +/** + * STARTFONT 2.1 + * COMMENT "$ucs-fonts: 6x10.bdf,v 1.34 2002-11-10 19:12:30+00 mgk25 Rel $" + * COMMENT "Send bug reports to Markus Kuhn " + * FONT -Misc-Fixed-Medium-R-Normal--10-100-75-75-C-60-ISO10646-1 + * SIZE 10 75 75 + * FONTBOUNDINGBOX 6 10 0 -2 + * STARTPROPERTIES 22 + * FONTNAME_REGISTRY "" + * FOUNDRY "Misc" + * FAMILY_NAME "Fixed" + * WEIGHT_NAME "Medium" + * SLANT "R" + * SETWIDTH_NAME "Normal" + * ADD_STYLE_NAME "" + * PIXEL_SIZE 10 + * POINT_SIZE 100 + * RESOLUTION_X 75 + * RESOLUTION_Y 75 + * SPACING "C" + * AVERAGE_WIDTH 60 + * CHARSET_REGISTRY "ISO10646" + * CHARSET_ENCODING "1" + * FONT_ASCENT 8 + * FONT_DESCENT 2 + * DEFAULT_CHAR 0 + * COPYRIGHT "Public domain terminal emulator font. Share and enjoy." + * _XMBDFED_INFO "Edited with xmbdfed 4.5." + * CAP_HEIGHT 7 + * X_HEIGHT 5 + * ENDPROPERTIES + * CHARS 1597 + */ +static const bdf_6x10_t bdf_6x10[] = { +/* space */ { 32, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }}, +/* exclam */ { 33, {0x00, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x20, 0x00, 0x00 }}, +/* quotedbl */ { 34, {0x00, 0x50, 0x50, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }}, +/* numbersign */ { 35, {0x00, 0x50, 0x50, 0xF8, 0x50, 0xF8, 0x50, 0x50, 0x00, 0x00 }}, +/* dollar */ { 36, {0x00, 0x20, 0x70, 0xA0, 0x70, 0x28, 0x70, 0x20, 0x00, 0x00 }}, +/* percent */ { 37, {0x00, 0x48, 0xA8, 0x50, 0x20, 0x50, 0xA8, 0x90, 0x00, 0x00 }}, +/* ampersand */ { 38, {0x00, 0x40, 0xA0, 0xA0, 0x40, 0xA8, 0x90, 0x68, 0x00, 0x00 }}, +/* quotesingle */ { 39, {0x00, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }}, +/* parenleft */ { 40, {0x00, 0x10, 0x20, 0x40, 0x40, 0x40, 0x20, 0x10, 0x00, 0x00 }}, +/* parenright */ { 41, {0x00, 0x40, 0x20, 0x10, 0x10, 0x10, 0x20, 0x40, 0x00, 0x00 }}, +/* asterisk */ { 42, {0x00, 0x00, 0x88, 0x50, 0xF8, 0x50, 0x88, 0x00, 0x00, 0x00 }}, +/* plus */ { 43, {0x00, 0x00, 0x20, 0x20, 0xF8, 0x20, 0x20, 0x00, 0x00, 0x00 }}, +/* comma */ { 44, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x20, 0x40, 0x00 }}, +/* hyphen */ { 45, {0x00, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00 }}, +/* period */ { 46, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x70, 0x20, 0x00 }}, +/* slash */ { 47, {0x00, 0x08, 0x08, 0x10, 0x20, 0x40, 0x80, 0x80, 0x00, 0x00 }}, +/* zero */ { 48, {0x00, 0x20, 0x50, 0x88, 0x88, 0x88, 0x50, 0x20, 0x00, 0x00 }}, +/* one */ { 49, {0x00, 0x20, 0x60, 0xA0, 0x20, 0x20, 0x20, 0xF8, 0x00, 0x00 }}, +/* two */ { 50, {0x00, 0x70, 0x88, 0x08, 0x30, 0x40, 0x80, 0xF8, 0x00, 0x00 }}, +/* three */ { 51, {0x00, 0xF8, 0x08, 0x10, 0x30, 0x08, 0x88, 0x70, 0x00, 0x00 }}, +/* four */ { 52, {0x00, 0x10, 0x30, 0x50, 0x90, 0xF8, 0x10, 0x10, 0x00, 0x00 }}, +/* five */ { 53, {0x00, 0xF8, 0x80, 0xB0, 0xC8, 0x08, 0x88, 0x70, 0x00, 0x00 }}, +/* six */ { 54, {0x00, 0x30, 0x40, 0x80, 0xB0, 0xC8, 0x88, 0x70, 0x00, 0x00 }}, +/* seven */ { 55, {0x00, 0xF8, 0x08, 0x10, 0x10, 0x20, 0x40, 0x40, 0x00, 0x00 }}, +/* eight */ { 56, {0x00, 0x70, 0x88, 0x88, 0x70, 0x88, 0x88, 0x70, 0x00, 0x00 }}, +/* nine */ { 57, {0x00, 0x70, 0x88, 0x98, 0x68, 0x08, 0x10, 0x60, 0x00, 0x00 }}, +/* colon */ { 58, {0x00, 0x00, 0x20, 0x70, 0x20, 0x00, 0x20, 0x70, 0x20, 0x00 }}, +/* semicolon */ { 59, {0x00, 0x00, 0x20, 0x70, 0x20, 0x00, 0x30, 0x20, 0x40, 0x00 }}, +/* less */ { 60, {0x00, 0x08, 0x10, 0x20, 0x40, 0x20, 0x10, 0x08, 0x00, 0x00 }}, +/* equal */ { 61, {0x00, 0x00, 0x00, 0xF8, 0x00, 0xF8, 0x00, 0x00, 0x00, 0x00 }}, +/* greater */ { 62, {0x00, 0x40, 0x20, 0x10, 0x08, 0x10, 0x20, 0x40, 0x00, 0x00 }}, +/* question */ { 63, {0x00, 0x70, 0x88, 0x10, 0x20, 0x20, 0x00, 0x20, 0x00, 0x00 }}, +/* at */ { 64, {0x00, 0x70, 0x88, 0x98, 0xA8, 0xB0, 0x80, 0x70, 0x00, 0x00 }}, +/* A */ { 65, {0x00, 0x20, 0x50, 0x88, 0x88, 0xF8, 0x88, 0x88, 0x00, 0x00 }}, +/* B */ { 66, {0x00, 0xF0, 0x48, 0x48, 0x70, 0x48, 0x48, 0xF0, 0x00, 0x00 }}, +/* C */ { 67, {0x00, 0x70, 0x88, 0x80, 0x80, 0x80, 0x88, 0x70, 0x00, 0x00 }}, +/* D */ { 68, {0x00, 0xF0, 0x48, 0x48, 0x48, 0x48, 0x48, 0xF0, 0x00, 0x00 }}, +/* E */ { 69, {0x00, 0xF8, 0x80, 0x80, 0xF0, 0x80, 0x80, 0xF8, 0x00, 0x00 }}, +/* F */ { 70, {0x00, 0xF8, 0x80, 0x80, 0xF0, 0x80, 0x80, 0x80, 0x00, 0x00 }}, +/* G */ { 71, {0x00, 0x70, 0x88, 0x80, 0x80, 0x98, 0x88, 0x70, 0x00, 0x00 }}, +/* H */ { 72, {0x00, 0x88, 0x88, 0x88, 0xF8, 0x88, 0x88, 0x88, 0x00, 0x00 }}, +/* I */ { 73, {0x00, 0x70, 0x20, 0x20, 0x20, 0x20, 0x20, 0x70, 0x00, 0x00 }}, +/* J */ { 74, {0x00, 0x38, 0x10, 0x10, 0x10, 0x10, 0x90, 0x60, 0x00, 0x00 }}, +/* K */ { 75, {0x00, 0x88, 0x90, 0xA0, 0xC0, 0xA0, 0x90, 0x88, 0x00, 0x00 }}, +/* L */ { 76, {0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xF8, 0x00, 0x00 }}, +/* M */ { 77, {0x00, 0x88, 0x88, 0xD8, 0xA8, 0x88, 0x88, 0x88, 0x00, 0x00 }}, +/* N */ { 78, {0x00, 0x88, 0x88, 0xC8, 0xA8, 0x98, 0x88, 0x88, 0x00, 0x00 }}, +/* O */ { 79, {0x00, 0x70, 0x88, 0x88, 0x88, 0x88, 0x88, 0x70, 0x00, 0x00 }}, +/* P */ { 80, {0x00, 0xF0, 0x88, 0x88, 0xF0, 0x80, 0x80, 0x80, 0x00, 0x00 }}, +/* Q */ { 81, {0x00, 0x70, 0x88, 0x88, 0x88, 0x88, 0xA8, 0x70, 0x08, 0x00 }}, +/* R */ { 82, {0x00, 0xF0, 0x88, 0x88, 0xF0, 0xA0, 0x90, 0x88, 0x00, 0x00 }}, +/* S */ { 83, {0x00, 0x70, 0x88, 0x80, 0x70, 0x08, 0x88, 0x70, 0x00, 0x00 }}, +/* T */ { 84, {0x00, 0xF8, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00 }}, +/* U */ { 85, {0x00, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x70, 0x00, 0x00 }}, +/* V */ { 86, {0x00, 0x88, 0x88, 0x88, 0x50, 0x50, 0x50, 0x20, 0x00, 0x00 }}, +/* W */ { 87, {0x00, 0x88, 0x88, 0x88, 0xA8, 0xA8, 0xD8, 0x88, 0x00, 0x00 }}, +/* X */ { 88, {0x00, 0x88, 0x88, 0x50, 0x20, 0x50, 0x88, 0x88, 0x00, 0x00 }}, +/* Y */ { 89, {0x00, 0x88, 0x88, 0x50, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00 }}, +/* Z */ { 90, {0x00, 0xF8, 0x08, 0x10, 0x20, 0x40, 0x80, 0xF8, 0x00, 0x00 }}, +/* bracketleft */ { 91, {0x00, 0x70, 0x40, 0x40, 0x40, 0x40, 0x40, 0x70, 0x00, 0x00 }}, +/* backslash */ { 92, {0x00, 0x80, 0x80, 0x40, 0x20, 0x10, 0x08, 0x08, 0x00, 0x00 }}, +/* bracketright */ { 93, {0x00, 0x70, 0x10, 0x10, 0x10, 0x10, 0x10, 0x70, 0x00, 0x00 }}, +/* asciicircum */ { 94, {0x00, 0x20, 0x50, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }}, +/* underscore */ { 95, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x00 }}, +/* grave */ { 96, {0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }}, +/* a */ { 97, {0x00, 0x00, 0x00, 0x70, 0x08, 0x78, 0x88, 0x78, 0x00, 0x00 }}, +/* b */ { 98, {0x00, 0x80, 0x80, 0xB0, 0xC8, 0x88, 0xC8, 0xB0, 0x00, 0x00 }}, +/* c */ { 99, {0x00, 0x00, 0x00, 0x70, 0x88, 0x80, 0x88, 0x70, 0x00, 0x00 }}, +/* d */ { 100, {0x00, 0x08, 0x08, 0x68, 0x98, 0x88, 0x98, 0x68, 0x00, 0x00 }}, +/* e */ { 101, {0x00, 0x00, 0x00, 0x70, 0x88, 0xF8, 0x80, 0x70, 0x00, 0x00 }}, +/* f */ { 102, {0x00, 0x30, 0x48, 0x40, 0xF0, 0x40, 0x40, 0x40, 0x00, 0x00 }}, +/* g */ { 103, {0x00, 0x00, 0x00, 0x78, 0x88, 0x88, 0x78, 0x08, 0x88, 0x70 }}, +/* h */ { 104, {0x00, 0x80, 0x80, 0xB0, 0xC8, 0x88, 0x88, 0x88, 0x00, 0x00 }}, +/* i */ { 105, {0x00, 0x20, 0x00, 0x60, 0x20, 0x20, 0x20, 0x70, 0x00, 0x00 }}, +/* j */ { 106, {0x00, 0x08, 0x00, 0x18, 0x08, 0x08, 0x08, 0x48, 0x48, 0x30 }}, +/* k */ { 107, {0x00, 0x80, 0x80, 0x88, 0x90, 0xE0, 0x90, 0x88, 0x00, 0x00 }}, +/* l */ { 108, {0x00, 0x60, 0x20, 0x20, 0x20, 0x20, 0x20, 0x70, 0x00, 0x00 }}, +/* m */ { 109, {0x00, 0x00, 0x00, 0xD0, 0xA8, 0xA8, 0xA8, 0x88, 0x00, 0x00 }}, +/* n */ { 110, {0x00, 0x00, 0x00, 0xB0, 0xC8, 0x88, 0x88, 0x88, 0x00, 0x00 }}, +/* o */ { 111, {0x00, 0x00, 0x00, 0x70, 0x88, 0x88, 0x88, 0x70, 0x00, 0x00 }}, +/* p */ { 112, {0x00, 0x00, 0x00, 0xB0, 0xC8, 0x88, 0xC8, 0xB0, 0x80, 0x80 }}, +/* q */ { 113, {0x00, 0x00, 0x00, 0x68, 0x98, 0x88, 0x98, 0x68, 0x08, 0x08 }}, +/* r */ { 114, {0x00, 0x00, 0x00, 0xB0, 0xC8, 0x80, 0x80, 0x80, 0x00, 0x00 }}, +/* s */ { 115, {0x00, 0x00, 0x00, 0x70, 0x80, 0x70, 0x08, 0xF0, 0x00, 0x00 }}, +/* t */ { 116, {0x00, 0x40, 0x40, 0xF0, 0x40, 0x40, 0x48, 0x30, 0x00, 0x00 }}, +/* u */ { 117, {0x00, 0x00, 0x00, 0x88, 0x88, 0x88, 0x98, 0x68, 0x00, 0x00 }}, +/* v */ { 118, {0x00, 0x00, 0x00, 0x88, 0x88, 0x50, 0x50, 0x20, 0x00, 0x00 }}, +/* w */ { 119, {0x00, 0x00, 0x00, 0x88, 0x88, 0xA8, 0xA8, 0x50, 0x00, 0x00 }}, +/* x */ { 120, {0x00, 0x00, 0x00, 0x88, 0x50, 0x20, 0x50, 0x88, 0x00, 0x00 }}, +/* y */ { 121, {0x00, 0x00, 0x00, 0x88, 0x88, 0x98, 0x68, 0x08, 0x88, 0x70 }}, +/* z */ { 122, {0x00, 0x00, 0x00, 0xF8, 0x10, 0x20, 0x40, 0xF8, 0x00, 0x00 }}, +/* braceleft */ { 123, {0x00, 0x18, 0x20, 0x10, 0x60, 0x10, 0x20, 0x18, 0x00, 0x00 }}, +/* bar */ { 124, {0x00, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00 }}, +/* braceright */ { 125, {0x00, 0x60, 0x10, 0x20, 0x18, 0x20, 0x10, 0x60, 0x00, 0x00 }}, +/* asciitilde */ { 126, {0x00, 0x48, 0xA8, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }}, +/* space */ { 160, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }}, +/* exclamdown */ { 161, {0x00, 0x20, 0x00, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00 }}, +/* cent */ { 162, {0x00, 0x00, 0x20, 0x78, 0xA0, 0xA0, 0xA0, 0x78, 0x20, 0x00 }}, +/* sterling */ { 163, {0x00, 0x30, 0x48, 0x40, 0xE0, 0x40, 0x48, 0xB0, 0x00, 0x00 }}, +/* currency */ { 164, {0x00, 0x00, 0x00, 0x88, 0x70, 0x50, 0x70, 0x88, 0x00, 0x00 }}, +/* yen */ { 165, {0x00, 0x88, 0x88, 0x50, 0x20, 0xF8, 0x20, 0x20, 0x20, 0x00 }}, +/* brokenbar */ { 166, {0x00, 0x20, 0x20, 0x20, 0x00, 0x20, 0x20, 0x20, 0x00, 0x00 }}, +/* section */ { 167, {0x00, 0x70, 0x80, 0xE0, 0x90, 0x48, 0x38, 0x08, 0x70, 0x00 }}, +/* dieresis */ { 168, {0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }}, +/* copyright */ { 169, {0x00, 0x70, 0x88, 0xA8, 0xC8, 0xA8, 0x88, 0x70, 0x00, 0x00 }}, +/* ordfeminine */ { 170, {0x00, 0x38, 0x48, 0x58, 0x28, 0x00, 0x78, 0x00, 0x00, 0x00 }}, +/* guillemotleft */ { 171, {0x00, 0x00, 0x00, 0x24, 0x48, 0x90, 0x48, 0x24, 0x00, 0x00 }}, +/* logicalnot */ { 172, {0x00, 0x00, 0x00, 0x00, 0x78, 0x08, 0x00, 0x00, 0x00, 0x00 }}, +/* hyphen */ { 173, {0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00 }}, +/* registered */ { 174, {0x00, 0x70, 0x88, 0xE8, 0xC8, 0xC8, 0x88, 0x70, 0x00, 0x00 }}, +/* macron */ { 175, {0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }}, +/* degree */ { 176, {0x00, 0x20, 0x50, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }}, +/* plusminus */ { 177, {0x00, 0x00, 0x20, 0x20, 0xF8, 0x20, 0x20, 0xF8, 0x00, 0x00 }}, +/* twosuperior */ { 178, {0x30, 0x48, 0x10, 0x20, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00 }}, +/* threesuperior */ { 179, {0x70, 0x08, 0x30, 0x08, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00 }}, +/* acute */ { 180, {0x10, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }}, +/* mu */ { 181, {0x00, 0x00, 0x00, 0x88, 0x88, 0x88, 0xC8, 0xB0, 0x80, 0x00 }}, +/* paragraph */ { 182, {0x00, 0x78, 0xE8, 0xE8, 0x68, 0x28, 0x28, 0x28, 0x00, 0x00 }}, +/* periodcentered */ { 183, {0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00 }}, +/* cedilla */ { 184, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x20 }}, +/* onesuperior */ { 185, {0x20, 0x60, 0x20, 0x20, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00 }}, +/* ordmasculine */ { 186, {0x00, 0x30, 0x48, 0x48, 0x30, 0x00, 0x78, 0x00, 0x00, 0x00 }}, +/* guillemotright */ { 187, {0x00, 0x00, 0x00, 0x90, 0x48, 0x24, 0x48, 0x90, 0x00, 0x00 }}, +/* onequarter */ { 188, {0x40, 0xC0, 0x40, 0x40, 0xE4, 0x0C, 0x14, 0x3C, 0x04, 0x00 }}, +/* onehalf */ { 189, {0x40, 0xC0, 0x40, 0x40, 0xE8, 0x14, 0x04, 0x08, 0x1C, 0x00 }}, +/* threequarters */ { 190, {0xC0, 0x20, 0x40, 0x20, 0xC8, 0x18, 0x28, 0x78, 0x08, 0x00 }}, +/* questiondown */ { 191, {0x00, 0x20, 0x00, 0x20, 0x20, 0x40, 0x88, 0x70, 0x00, 0x00 }}, +/* Agrave */ { 192, {0x40, 0x20, 0x70, 0x88, 0x88, 0xF8, 0x88, 0x88, 0x00, 0x00 }}, +/* Aacute */ { 193, {0x10, 0x20, 0x70, 0x88, 0x88, 0xF8, 0x88, 0x88, 0x00, 0x00 }}, +/* Acircumflex */ { 194, {0x20, 0x50, 0x70, 0x88, 0x88, 0xF8, 0x88, 0x88, 0x00, 0x00 }}, +/* Atilde */ { 195, {0x48, 0xB0, 0x70, 0x88, 0x88, 0xF8, 0x88, 0x88, 0x00, 0x00 }}, +/* Adieresis */ { 196, {0x50, 0x00, 0x70, 0x88, 0x88, 0xF8, 0x88, 0x88, 0x00, 0x00 }}, +/* Aring */ { 197, {0x20, 0x50, 0x70, 0x88, 0x88, 0xF8, 0x88, 0x88, 0x00, 0x00 }}, +/* AE */ { 198, {0x00, 0x3C, 0x50, 0x90, 0x9C, 0xF0, 0x90, 0x9C, 0x00, 0x00 }}, +/* Ccedilla */ { 199, {0x00, 0x70, 0x88, 0x80, 0x80, 0x80, 0x88, 0x70, 0x20, 0x40 }}, +/* Egrave */ { 200, {0x40, 0xF8, 0x80, 0x80, 0xF0, 0x80, 0x80, 0xF8, 0x00, 0x00 }}, +/* Eacute */ { 201, {0x10, 0xF8, 0x80, 0x80, 0xF0, 0x80, 0x80, 0xF8, 0x00, 0x00 }}, +/* Ecircumflex */ { 202, {0x20, 0xF8, 0x80, 0x80, 0xF0, 0x80, 0x80, 0xF8, 0x00, 0x00 }}, +/* Edieresis */ { 203, {0x50, 0xF8, 0x80, 0x80, 0xF0, 0x80, 0x80, 0xF8, 0x00, 0x00 }}, +/* Igrave */ { 204, {0x40, 0x20, 0x70, 0x20, 0x20, 0x20, 0x20, 0x70, 0x00, 0x00 }}, +/* Iacute */ { 205, {0x10, 0x20, 0x70, 0x20, 0x20, 0x20, 0x20, 0x70, 0x00, 0x00 }}, +/* Icircumflex */ { 206, {0x20, 0x50, 0x70, 0x20, 0x20, 0x20, 0x20, 0x70, 0x00, 0x00 }}, +/* Idieresis */ { 207, {0x50, 0x00, 0x70, 0x20, 0x20, 0x20, 0x20, 0x70, 0x00, 0x00 }}, +/* Eth */ { 208, {0x00, 0xF0, 0x48, 0x48, 0xE8, 0x48, 0x48, 0xF0, 0x00, 0x00 }}, +/* Ntilde */ { 209, {0x28, 0x50, 0x88, 0xC8, 0xA8, 0x98, 0x88, 0x88, 0x00, 0x00 }}, +/* Ograve */ { 210, {0x40, 0x20, 0x70, 0x88, 0x88, 0x88, 0x88, 0x70, 0x00, 0x00 }}, +/* Oacute */ { 211, {0x10, 0x20, 0x70, 0x88, 0x88, 0x88, 0x88, 0x70, 0x00, 0x00 }}, +/* Ocircumflex */ { 212, {0x20, 0x50, 0x70, 0x88, 0x88, 0x88, 0x88, 0x70, 0x00, 0x00 }}, +/* Otilde */ { 213, {0x28, 0x50, 0x70, 0x88, 0x88, 0x88, 0x88, 0x70, 0x00, 0x00 }}, +/* Odieresis */ { 214, {0x50, 0x00, 0x70, 0x88, 0x88, 0x88, 0x88, 0x70, 0x00, 0x00 }}, +/* multiply */ { 215, {0x00, 0x00, 0x00, 0x88, 0x50, 0x20, 0x50, 0x88, 0x00, 0x00 }}, +/* Oslash */ { 216, {0x00, 0x70, 0x98, 0x98, 0xA8, 0xC8, 0xC8, 0x70, 0x00, 0x00 }}, +/* Ugrave */ { 217, {0x40, 0x20, 0x88, 0x88, 0x88, 0x88, 0x88, 0x70, 0x00, 0x00 }}, +/* Uacute */ { 218, {0x10, 0x20, 0x88, 0x88, 0x88, 0x88, 0x88, 0x70, 0x00, 0x00 }}, +/* Ucircumflex */ { 219, {0x20, 0x50, 0x00, 0x88, 0x88, 0x88, 0x88, 0x70, 0x00, 0x00 }}, +/* Udieresis */ { 220, {0x50, 0x00, 0x88, 0x88, 0x88, 0x88, 0x88, 0x70, 0x00, 0x00 }}, +/* Yacute */ { 221, {0x10, 0x20, 0x88, 0x88, 0x50, 0x20, 0x20, 0x20, 0x00, 0x00 }}, +/* Thorn */ { 222, {0x00, 0x80, 0xF0, 0x88, 0xF0, 0x80, 0x80, 0x80, 0x00, 0x00 }}, +/* germandbls */ { 223, {0x00, 0x70, 0x88, 0x90, 0xA0, 0x90, 0x88, 0xB0, 0x00, 0x00 }}, +/* agrave */ { 224, {0x40, 0x20, 0x00, 0x70, 0x08, 0x78, 0x88, 0x78, 0x00, 0x00 }}, +/* aacute */ { 225, {0x10, 0x20, 0x00, 0x70, 0x08, 0x78, 0x88, 0x78, 0x00, 0x00 }}, +/* acircumflex */ { 226, {0x20, 0x50, 0x00, 0x70, 0x08, 0x78, 0x88, 0x78, 0x00, 0x00 }}, +/* atilde */ { 227, {0x28, 0x50, 0x00, 0x70, 0x08, 0x78, 0x88, 0x78, 0x00, 0x00 }}, +/* adieresis */ { 228, {0x00, 0x50, 0x00, 0x70, 0x08, 0x78, 0x88, 0x78, 0x00, 0x00 }}, +/* aring */ { 229, {0x20, 0x50, 0x20, 0x70, 0x08, 0x78, 0x88, 0x78, 0x00, 0x00 }}, +/* ae */ { 230, {0x00, 0x00, 0x00, 0x78, 0x14, 0x7C, 0x90, 0x7C, 0x00, 0x00 }}, +/* ccedilla */ { 231, {0x00, 0x00, 0x00, 0x70, 0x88, 0x80, 0x88, 0x70, 0x20, 0x40 }}, +/* egrave */ { 232, {0x40, 0x20, 0x00, 0x70, 0x88, 0xF8, 0x80, 0x70, 0x00, 0x00 }}, +/* eacute */ { 233, {0x10, 0x20, 0x00, 0x70, 0x88, 0xF8, 0x80, 0x70, 0x00, 0x00 }}, +/* ecircumflex */ { 234, {0x20, 0x50, 0x00, 0x70, 0x88, 0xF8, 0x80, 0x70, 0x00, 0x00 }}, +/* edieresis */ { 235, {0x00, 0x50, 0x00, 0x70, 0x88, 0xF8, 0x80, 0x70, 0x00, 0x00 }}, +/* igrave */ { 236, {0x40, 0x20, 0x00, 0x60, 0x20, 0x20, 0x20, 0x70, 0x00, 0x00 }}, +/* iacute */ { 237, {0x20, 0x40, 0x00, 0x60, 0x20, 0x20, 0x20, 0x70, 0x00, 0x00 }}, +/* icircumflex */ { 238, {0x20, 0x50, 0x00, 0x60, 0x20, 0x20, 0x20, 0x70, 0x00, 0x00 }}, +/* idieresis */ { 239, {0x00, 0x50, 0x00, 0x60, 0x20, 0x20, 0x20, 0x70, 0x00, 0x00 }}, +/* eth */ { 240, {0x00, 0xC0, 0x30, 0x70, 0x88, 0x88, 0x88, 0x70, 0x00, 0x00 }}, +/* ntilde */ { 241, {0x28, 0x50, 0x00, 0xB0, 0xC8, 0x88, 0x88, 0x88, 0x00, 0x00 }}, +/* ograve */ { 242, {0x40, 0x20, 0x00, 0x70, 0x88, 0x88, 0x88, 0x70, 0x00, 0x00 }}, +/* oacute */ { 243, {0x10, 0x20, 0x00, 0x70, 0x88, 0x88, 0x88, 0x70, 0x00, 0x00 }}, +/* ocircumflex */ { 244, {0x20, 0x50, 0x00, 0x70, 0x88, 0x88, 0x88, 0x70, 0x00, 0x00 }}, +/* otilde */ { 245, {0x28, 0x50, 0x00, 0x70, 0x88, 0x88, 0x88, 0x70, 0x00, 0x00 }}, +/* odieresis */ { 246, {0x00, 0x50, 0x00, 0x70, 0x88, 0x88, 0x88, 0x70, 0x00, 0x00 }}, +/* divide */ { 247, {0x00, 0x00, 0x20, 0x00, 0xF8, 0x00, 0x20, 0x00, 0x00, 0x00 }}, +/* oslash */ { 248, {0x00, 0x00, 0x00, 0x78, 0x98, 0xA8, 0xC8, 0xF0, 0x00, 0x00 }}, +/* ugrave */ { 249, {0x40, 0x20, 0x00, 0x88, 0x88, 0x88, 0x98, 0x68, 0x00, 0x00 }}, +/* uacute */ { 250, {0x10, 0x20, 0x00, 0x88, 0x88, 0x88, 0x98, 0x68, 0x00, 0x00 }}, +/* ucircumflex */ { 251, {0x20, 0x50, 0x00, 0x88, 0x88, 0x88, 0x98, 0x68, 0x00, 0x00 }}, +/* udieresis */ { 252, {0x00, 0x50, 0x00, 0x88, 0x88, 0x88, 0x98, 0x68, 0x00, 0x00 }}, +/* yacute */ { 253, {0x00, 0x10, 0x20, 0x88, 0x88, 0x98, 0x68, 0x08, 0x88, 0x70 }}, +/* thorn */ { 254, {0x00, 0x00, 0x80, 0xF0, 0x88, 0x88, 0x88, 0xF0, 0x80, 0x80 }}, +/* ydieresis */ { 255, {0x00, 0x50, 0x00, 0x88, 0x88, 0x98, 0x68, 0x08, 0x88, 0x70 }}, +/* char0 */ { 0, {0x00, 0xA8, 0x00, 0x88, 0x00, 0x88, 0x00, 0xA8, 0x00, 0x00 }} +}; + +void alto2_cpu_device::fake_status_putch(int x, UINT8 ch) +{ + const bdf_6x10_t* pf = bdf_6x10; + while (pf->code != ch && pf->code != 0) + pf++; + int dx = 6 * x; + if (dx >= ALTO2_DISPLAY_WIDTH) + return; + for (int dy = 0; dy < 10; dy++) + { + UINT8* pix = m_dsp.scanline[ALTO2_DISPLAY_HEIGHT + 1 + dy] + dx; + UINT8 bits = ~pf->bits[dy]; + pix[0] = (bits >> 7) & 1; + pix[1] = (bits >> 6) & 1; + pix[2] = (bits >> 5) & 1; + pix[3] = (bits >> 4) & 1; + pix[4] = (bits >> 3) & 1; + pix[5] = (bits >> 2) & 1; + } + +} + +void alto2_cpu_device::fake_status_printf(int x, const char* format, ...) +{ + static char buff[256]; + va_list ap; + va_start(ap, format); + vsnprintf(buff, sizeof(buff), format, ap); + va_end(ap); + char* src = buff; + while (*src) + fake_status_putch(x++, *src++); +} diff --git a/src/devices/cpu/alto2/a2disp.h b/src/devices/cpu/alto2/a2disp.h new file mode 100644 index 00000000000..80454eb4896 --- /dev/null +++ b/src/devices/cpu/alto2/a2disp.h @@ -0,0 +1,301 @@ +// license:BSD-3-Clause +// copyright-holders:Juergen Buchmueller +/***************************************************************************** + * + * Xerox AltoII display block + * + *****************************************************************************/ +#ifdef ALTO2_DEFINE_CONSTANTS + +/** + * @brief start value for the horizontal line counter + * + * This value is loaded into the three 4 bit counters (type 9316) + * with numbers 65, 67, and 75. + * 65: A=0 B=1 C=1 D=0 + * 67: A=1 B=0 C=0 D=1 + * 75: A=0 B=0 C=0 D=0 + * + * The value is 150 + */ +#define ALTO2_DISPLAY_HLC_START (2+4+16+128) + +/** + * @brief end value for the horizontal line counter + * + * This is decoded by H30, an 8 input NAND gate. + * The value is 1899; horz. line count range 150...1899 = 1750. + * + * There are 1750 / 2 = 875 total scanlines. + */ +#define ALTO2_DISPLAY_HLC_END (1+2+8+32+64+256+512+1024) + +/** + * @brief display total height, including overscan (vertical blanking and synch) + * + * The display is interleaved in two fields, alternatingly drawing the even and odd + * scanlines to the monitor. The frame rate is 60Hz, which is actually the rate + * of the half-frames. The rate for full frames is thus 30Hz. + */ +#define ALTO2_DISPLAY_TOTAL_HEIGHT ((ALTO2_DISPLAY_HLC_END + 1 - ALTO2_DISPLAY_HLC_START) / 2) + +/** + * @brief display total width, including horizontal blanking + * + * Known facts: + * + * We have 606x808 visible pixels, and the pixel clock is said to be 50ns + * (20MHz), while the crystal in the schematics is labeled 20.16 MHz, + * so the pixel clock would actually be 49.6031ns. + * + * The total number of scanlines is, according to the docs, 875. + * + * 875 scanlines at 30 frames per second, thus the scanline rate is 26.250 kHz. + * + * If I divide 20.16 MHz by 26.250 kHz, I get 768 pixels for the total width + * of a scanline in pixels. + * + * The horizontal blanking period would then be 768 - 606 = 162 pixels, and + * thus 162 * 49.6031ns ~= 8036ns = 8.036us for the HBLANK time. + * + * In the display schematics there is a divide by 24 logic, and when + * dividing the 768 pixels per scanline by 24, we have 32 phases of a scanline. + * + * A S8223 PROM (a63) with 32x8 bits contains the status of the HBLANK and + * HSYNC signals for these phases, the SCANEND and HLCGATE signals, as well + * as its own next address A0-A3! + * + */ +#define ALTO2_DISPLAY_TOTAL_WIDTH 768 + + +#define ALTO2_DISPLAY_FIFO 16 //!< the display fifo has 16 words +#define ALTO2_DISPLAY_SCANLINE_WORDS (ALTO2_DISPLAY_TOTAL_WIDTH/16) //!< words per scanline +#define ALTO2_DISPLAY_HEIGHT 808 //!< number of visible scanlines per frame; 808 really, but there are some empty lines? +#define ALTO2_DISPLAY_WIDTH 606 //!< visible width of the display; 38 x 16 bit words - 2 pixels +#define ALTO2_DISPLAY_VISIBLE_WORDS ((ALTO2_DISPLAY_WIDTH+15)/16) //!< visible words per scanline +#define ALTO2_DISPLAY_BITCLOCK 20160000ll //!< display bit clock in Hertz (20.16MHz) +#define ALTO2_DISPLAY_BITTIME(n) (U64(1000000000000)*(n)/ALTO2_DISPLAY_BITCLOCK) //!< display bit time in pico seconds (~= 49.6031ns) +#define ALTO2_DISPLAY_SCANLINE_TIME ALTO2_DISPLAY_BITTIME(ALTO2_DISPLAY_TOTAL_WIDTH)//!< time for a scanline in pico seconds (768 * 49.6031ns ~= 38095.1808ns) +#define ALTO2_DISPLAY_VISIBLE_TIME ALTO2_DISPLAY_BITTIME(ALTO2_DISPLAY_WIDTH) //!< time of the visible part of a scanline in pico seconds (606 * 49.6031ns ~= 30059.4786ns) +#define ALTO2_DISPLAY_WORD_TIME ALTO2_DISPLAY_BITTIME(16) //!< time for a word in pico seconds (16 pixels * 49.6031ns ~= 793.6496ns) +#define ALTO2_DISPLAY_VBLANK_TIME ((ALTO2_DISPLAY_TOTAL_HEIGHT-ALTO2_DISPLAY_HEIGHT)*HZ_TO_ATTOSECONDS(26250)/2) + +#else // ALTO2_DEFINE_CONSTANTS +/** + * @brief structure of the display context + * + * Schematics of the task clear and wakeup signal generators + *
+ * A quote (') appended to a signal name means inverted signal.
+ *
+ *  AND |     NAND|      NOR |       FF | Q    N174
+ * -----+--- -----+---  -----+---  -----+---   -----
+ *  0 0 | 0   0 0 | 1    0 0 | 1    S'\0| 1    delay
+ *  0 1 | 0   0 1 | 1    0 1 | 0    R'\0| 0
+ *  1 0 | 0   1 0 | 1    1 0 | 0
+ *  1 1 | 1   1 1 | 0    1 1 | 0
+ *
+ *
+ *                                                       DVTAC'
+ *                                                      >-------+  +-----+
+ *                                                              |  |  FF |
+ * VBLANK'+----+ DELVBLANK' +---+  DELVBLANK   +----+           +--|S'   |
+ * >------|N174|------+-----|inv|--------------|NAND| VBLANKPULSE  |     |              WAKEDVT'
+ *        +----+      |     +---+              |    o--+-----------|R'  Q|---------------------->
+ *                    |                      +-|    |  |           |     |
+ *        +----+      |     DDELVBLANK'      | +----+  |           +-----+
+ *      +-|N174|-----------------------------+         |      +---+
+ *      | +----+      |                                +------oAND|
+ *      |             |                      DSP07.01  |      |   o----------+
+ *      +-------------+                      >---------|------o   |          |
+ *                                                     |      +---+          |
+ *                                                     |                     |
+ *                                                     | +-----+             |
+ *                                                     | |  FF |             |  +-----+
+ *        DHTAC'       +---+                           | |     |             |  |  FF |
+ *      >--------------oNOR|  *07.25       +----+      +-|S'   |   DHTBLK'   |  |     |
+ *        BLOCK'       |   |---------------|NAND|        |    Q|--+----------|--|S1'  | WAKEDHT'
+ *      >--------------o   |     DCSYSCLK  |    o--------|R'   |  | >--------|--|S2' Q|--------->
+ *                     +---+     >---------|    |        +-----+  |  DHTAC'  +--|R'   |
+ *                                         +----+                 |             +-----+
+ *                                                   +------------+
+ *                                                   |
+ *        DWTAC'       +---+                         |   +-----+
+ *      >--------------oNOR|  *07.26 +----+          |   |  FF |
+ *        BLOCK'       |   |---------|NAND| DSP07.01 |   |     |
+ *      >--------------o   | DCSYSCLK|    o----------|---|S1'  | DWTCN' +---+        DWTCN
+ *                     +---+ >-------|    |          +---|S2' Q|--------|inv|-----------+----
+ *                                   +----+          +---|R'   |        +---+           |
+ *                                                   |   +-----+                        |
+ *                 SCANEND     +----+                |                                  |
+ *               >-------------|NAND|  CLRBUF'       |           .----------------------+
+ *                 DCLK        |    o----------------+           |
+ *               >-------------|    |                            |  +-----+
+ *                             +----+                            +--| NAND|
+ *                                                       STOPWAKE'  |     |preWake +----+ WAKEDWT'
+ *                                                      >-----------|     o--------|N174|--------->
+ *                                                        VBLANK'   |     |        +----+
+ *                                                      >-----------|     |
+ *                                                                  +-----+
+ *                                                     a40c
+ *                                        VBLANKPULSE +----+
+ *                                       -------------|NAND|
+ *                                                    |    o--+
+ *                                                 +--|    |  |
+ *                                                 |  +----+  |
+ *                                                 +----------|-+
+ *                                                 +----------+ |
+ *        CURTAC'      +---+                       |  +----+    |     a20d
+ *      >--------------oNOR|  *07.27 +----+        +--|NAND|    |    +----+
+ *        BLOCK'       |   |---------|NAND| DSP07.07  |    o----+----o NOR| preWK  +----+ WAKECURT'
+ *      >--------------o   | DCSYSCLK|    o-----------|    |         |    |--------|N174|--------->
+ *                     +---+ >-------|    |           +----+    +----o    |        +----+
+ *                                   +----+            a40d     |    +----+
+ *                                          a30c                |
+ *                              CURTAC'    +----+               |
+ *                            >------------|NAND|    DSP07.03   |
+ *                                         |    o--+------------+
+ *                                      +--|    |  |
+ *                                      |  +----+  |
+ *                                      +----------|-+
+ *                                      +----------+ |
+ *                                      |  +----+    |
+ *                                      +--|NAND|    |
+ *                              CLRBUF'    |    o----+
+ *                            >------------|    |
+ *                                         +----+
+ *                                          a30d
+ * 
+ */ + +#ifndef _A2DISP_H_ +#define _A2DISP_H_ +struct { + UINT16 state; //!< current state of the display_state_machine() + UINT16 hlc; //!< horizontal line counter + UINT16 setmode; //!< value written by last SETMODE<- + UINT16 inverse; //!< set to 0xffff if line is inverse, 0x0000 otherwise + bool halfclock; //!< set 0 for normal pixel clock, 1 for half pixel clock + UINT16 fifo[ALTO2_DISPLAY_FIFO]; //!< display word fifo + UINT8 wa; //!< fifo input pointer (write address; 4-bit) + UINT8 ra; //!< fifo output pointer (read address; 4-bit) + UINT8 a63; //!< most recent value read from the PROM a63 + UINT8 a66; //!< most recent value read from the PROM a66 + bool dht_blocks; //!< set non-zero, if the DHT executed BLOCK + bool dwt_blocks; //!< set non-zero, if the DWT executed BLOCK + bool curt_blocks; //!< set non-zero, if the CURT executed BLOCK + bool curt_wakeup; //!< set non-zero, if CURT wakeups are generated + UINT16 vblank; //!< most recent HLC with VBLANK still high (11-bit) + UINT16 xpreg; //!< cursor cursor x position register (10-bit) + UINT16 csr; //!< cursor shift register (16-bit) + UINT32 curxpos; //!< helper: first cursor word in scanline + UINT16 cursor0; //!< helper: shifted cursor data for left word + UINT16 cursor1; //!< helper: shifted cursor data for right word + UINT16 *raw_bitmap; //!< array of words of the raw bitmap that is displayed + UINT8 **scanline; //!< array of scanlines with 1 byte per pixel + bitmap_ind16 *bitmap; //!< MAME bitmap with 16 bit indices + bool odd_frame; //!< true, if odd frame is drawn +} m_dsp; + +/** + * @brief PROM a38 contains the STOPWAKE' and MBEMBPTY' signals for the FIFO + *
+ * The inputs to a38 are the UNLOAD counter RA[0-3] and the DDR<- counter
+ * WA[0-3], and the designer decided to reverse the address lines :-)
+ *
+ *  a38  counter FIFO counter
+ *  --------------------------
+ *   A0  RA[0]   fifo_rd
+ *   A1  RA[1]
+ *   A2  RA[2]
+ *   A3  RA[3]
+ *   A4  WA[0]   fifo_wr
+ *   A5  WA[1]
+ *   A6  WA[2]
+ *   A7  WA[3]
+ *
+ * Only two bits of a38 are used:
+ *  O1 (002) = STOPWAKE'
+ *  O3 (010) = MBEMPTY'
+ * 
+ */ +UINT8* m_disp_a38; + +//! output bits of PROM A38 +enum { + disp_a38_STOPWAKE = (1 << 1), + disp_a38_MBEMPTY = (1 << 3) +}; + +/** + * @brief emulation of PROM a63 in the display schematics page 8 + *
+ * The PROM's address lines are driven by a clock CLK, which is
+ * pixel clock / 24, and an inverted half-scanline signal H[1]'.
+ *
+ * It is 32x8 bits and its output bits (B) are connected to the
+ * signals, as well as its own address lines (A) through a latch
+ * of the type SN74774 like this:
+ *
+ * B    174     A   others
+ * ------------------------
+ * 0     5      -   HBLANK
+ * 1     0      -   HSYNC
+ * 2     4      0
+ * 3     1      1
+ * 4     3      2
+ * 5     2      3
+ * 6     -      -   SCANEND
+ * 7     -      -   HLCGATE
+ * ------------------------
+ * H[1]' -      4
+ *
+ * The display_state_machine() is called by the CPU at a rate of pixelclock/24,
+ * which happens to be very close to every 7th CPU micrcocycle.
+ * 
+ */ +UINT8* m_disp_a63; + +enum { + disp_a63_HBLANK = (1 << 0), //!< PROM a63 B0 is latched as HBLANK signal + disp_a63_HSYNC = (1 << 1), //!< PROM a63 B1 is latched as HSYNC signal + disp_a63_A0 = (1 << 2), //!< PROM a63 B2 is the latched next address bit A0 + disp_a63_A1 = (1 << 3), //!< PROM a63 B3 is the latched next address bit A1 + disp_a63_A2 = (1 << 4), //!< PROM a63 B4 is the latched next address bit A2 + disp_a63_A3 = (1 << 5), //!< PROM a63 B5 is the latched next address bit A3 + disp_a63_SCANEND = (1 << 6), //!< PROM a63 B6 SCANEND signal, which resets the FIFO counters + disp_a63_HLCGATE = (1 << 7) //!< PROM a63 B7 HLCGATE signal, which enables counting the HLC +}; + +/** + * @brief vertical blank and synch PROM + * + * PROM a66 is a 256x4 bit (type 3601), containing the vertical blank + synch. + * Address lines are driven by H[1] to H[128] of the horz. line counters. + * The PROM is enabled whenever H[256] and H[512] are both 0. + */ +UINT8* m_disp_a66; + +enum { + disp_a66_VSYNC_ODD = (1 << 0), //!< Q1 (001) is VSYNC for the odd field (with H1024=1) + disp_a66_VSYNC_EVEN = (1 << 1), //!< Q2 (002) is VSYNC for the even field (with H1024=0) + disp_a66_VBLANK_ODD = (1 << 2), //!< Q3 (004) is VBLANK for the odd field (with H1024=1) + disp_a66_VBLANK_EVEN = (1 << 3) //!< Q4 (010) is VBLANK for the even field (with H1024=0) +}; + +void update_bitmap_word(UINT16* bitmap, int x, int y, UINT16 word); //!< update a word in the screen bitmap +void unload_word(); //!< unload the next word from the display FIFO and shift it to the screen +void display_state_machine(); //!< function called by the CPU to enter the next display state + +void f2_late_evenfield(void); //!< branch on the evenfield flip-flop + +void init_disp(); //!< initialize the display context +void exit_disp(); //!< deinitialize the display context +void reset_disp(); //!< reset the display context + +void fake_status_putch(int x, UINT8 ch); +void fake_status_printf(int x, const char* format, ...); + +#endif // _A2DISP_H_ +#endif // ALTO2_DEFINE_CONSTANTS diff --git a/src/devices/cpu/alto2/a2dvt.c b/src/devices/cpu/alto2/a2dvt.c new file mode 100644 index 00000000000..acb51d92e7c --- /dev/null +++ b/src/devices/cpu/alto2/a2dvt.c @@ -0,0 +1,46 @@ +// license:BSD-3-Clause +// copyright-holders:Juergen Buchmueller +/***************************************************************************** + * + * Xerox AltoII display vertical task + * + *****************************************************************************/ +#include "alto2cpu.h" + +/** + * @brief f1_dvt_block early: disable the display word task + */ +void alto2_cpu_device::f1_early_dvt_block() +{ +// m_task_wakeup &= ~(1 << m_task); + LOG((LOG_DVT,2," BLOCK %s\n", task_name(m_task))); +} + + +/** + * @brief called by the CPU when the display vertical task becomes active + */ +void alto2_cpu_device::activate_dvt() +{ + m_task_wakeup &= ~(1 << m_task); +} + +/** + * @brief initialize display vertical task + */ +void alto2_cpu_device::init_dvt(int task) +{ + set_f1(task, f1_block, &alto2_cpu_device::f1_early_dvt_block, 0); + set_f2(task, f2_dvt_evenfield, 0, &alto2_cpu_device::f2_late_evenfield); + m_active_callback[task] = &alto2_cpu_device::activate_dvt; +} + +void alto2_cpu_device::exit_dvt() +{ + // nothing to do yet +} + +void alto2_cpu_device::reset_dvt() +{ + // nothing to do yet +} diff --git a/src/devices/cpu/alto2/a2dvt.h b/src/devices/cpu/alto2/a2dvt.h new file mode 100644 index 00000000000..3b73ac7bf7e --- /dev/null +++ b/src/devices/cpu/alto2/a2dvt.h @@ -0,0 +1,25 @@ +// license:BSD-3-Clause +// copyright-holders:Juergen Buchmueller +/***************************************************************************** + * + * Xerox AltoII display vertical task (DVT) + * + *****************************************************************************/ +#ifdef ALTO2_DEFINE_CONSTANTS + +#else // ALTO2_DEFINE_CONSTANTS +#ifndef _A2DVT_H_ +#define _A2DVT_H_ + +//! F2 functions for display vertical task +enum { + f2_dvt_evenfield = f2_task_10 //!< f2 10: load even field +}; + +void f1_early_dvt_block(); //!< F1 func: disable the display word task +void activate_dvt(); //!< called by the CPU when the display vertical task becomes active +void init_dvt(int task = task_dvt); //!< initialize the display vertical task +void exit_dvt(); //!< deinitialize the display vertical task +void reset_dvt(); //!< reset the display vertical task +#endif // _A2DVT_H_ +#endif // ALTO2_DEFINE_CONSTANTS diff --git a/src/devices/cpu/alto2/a2dwt.c b/src/devices/cpu/alto2/a2dwt.c new file mode 100644 index 00000000000..19831e3fd46 --- /dev/null +++ b/src/devices/cpu/alto2/a2dwt.c @@ -0,0 +1,62 @@ +// license:BSD-3-Clause +// copyright-holders:Juergen Buchmueller +/***************************************************************************** + * + * Xerox AltoII display word task + * + *****************************************************************************/ +#include "alto2cpu.h" + +//! PROM a38 bit O1 is STOPWAKE' (stop DWT if bit is zero) +#define FIFO_STOPWAKE(a38) (0 == (a38 & disp_a38_STOPWAKE) ? true : false) + +/** + * @brief block the display word task + */ +void alto2_cpu_device::f1_early_dwt_block() +{ + m_dsp.dwt_blocks = true; + + /* clear the wakeup for the display word task */ + m_task_wakeup &= ~(1 << m_task); + LOG((LOG_DWT,2," BLOCK %s\n", task_name(m_task))); + + /* wakeup the display horizontal task, if it didn't block itself */ + if (!m_dsp.dht_blocks) + m_task_wakeup |= 1 << task_dht; +} + +/** + * @brief load the display data register + */ +void alto2_cpu_device::f2_late_dwt_load_ddr() +{ + LOG((LOG_DWT,2," DDR<- BUS (%#o)\n", m_bus)); + m_dsp.fifo[m_dsp.wa] = m_bus; + m_dsp.wa = (m_dsp.wa + 1) % ALTO2_DISPLAY_FIFO; + UINT8 a38 = m_disp_a38[m_dsp.ra * 16 + m_dsp.wa]; + if (FIFO_STOPWAKE(a38)) + m_task_wakeup &= ~(1 << task_dwt); + LOG((LOG_DWT,2, " DWT push %04x into FIFO[%02o]%s\n", + m_bus, (m_dsp.wa - 1) & (ALTO2_DISPLAY_FIFO - 1), + FIFO_STOPWAKE(a38) ? " STOPWAKE" : "")); +} + +void alto2_cpu_device::init_dwt(int task) +{ + set_f1(task, f1_block, &alto2_cpu_device::f1_early_dwt_block, 0); + set_f2(task, f2_dwt_load_ddr, 0, &alto2_cpu_device::f2_late_dwt_load_ddr); +} + +void alto2_cpu_device::exit_dwt() +{ + // nothing to do yet +} + +void alto2_cpu_device::reset_dwt() +{ + m_dsp.dwt_blocks = false; + memset(m_dsp.fifo, 0, sizeof(m_dsp.fifo)); + m_dsp.wa = 0; + m_dsp.ra = 0; +} diff --git a/src/devices/cpu/alto2/a2dwt.h b/src/devices/cpu/alto2/a2dwt.h new file mode 100644 index 00000000000..74c6c94939b --- /dev/null +++ b/src/devices/cpu/alto2/a2dwt.h @@ -0,0 +1,25 @@ +// license:BSD-3-Clause +// copyright-holders:Juergen Buchmueller +/***************************************************************************** + * + * Xerox AltoII display word task (DWT) + * + *****************************************************************************/ +#ifdef ALTO2_DEFINE_CONSTANTS + +#else // ALTO2_DEFINE_CONSTANTS +#ifndef _A2DWT_H_ +#define _A2DWT_H_ + +//! F2 functions for display word task +enum { + f2_dwt_load_ddr = f2_task_10 //!< f2 10: load display data register +}; + +void f1_early_dwt_block(); //!< F1 func: block the display word task +void f2_late_dwt_load_ddr(); //!< F2 func: load the display data register +void init_dwt(int task = task_dwt); //!< initialize the display word task +void exit_dwt(); //!< deinitialize the display word task +void reset_dwt(); //!< reset the display word task +#endif // _A2DWT_H_ +#endif // ALTO2_DEFINE_CONSTANTS diff --git a/src/devices/cpu/alto2/a2emu.c b/src/devices/cpu/alto2/a2emu.c new file mode 100644 index 00000000000..fd30fa1d0f8 --- /dev/null +++ b/src/devices/cpu/alto2/a2emu.c @@ -0,0 +1,688 @@ +// license:BSD-3-Clause +// copyright-holders:Juergen Buchmueller +/***************************************************************************** + * + * Xerox AltoII emulator task + * + *****************************************************************************/ +#include "alto2cpu.h" + +/** @brief CTL2K_U3 address line for F2 function */ +#define CTL2K_U3(f2) (f2 == f2_emu_idisp ? 0x80 : 0x00) + +/** + * width,from,to of the 16 bit instruction register + * 1 1 1 1 1 1 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 + * ============================================================= + * x - - - - - - - - - - - - - - - arithmetic operation + * 0 m m - - - - - - - - - - - - - memory function + * 0 0 0 - - - - - - - - - - - - - jump functions + * 0 0 1 d d - - - - - - - - - - - LDA dstAC + * 0 1 0 d d - - - - - - - - - - - STA dstAC + * 0 1 1 - - - - - - - - - - - - - augmented functions + * 1 s s - - - - - - - - - - - - - source accumulator (0-3) + * 1 - - d d - - - - - - - - - - - destination accumulator (0-3) + * 1 s s d d x x x - - - - - - - - accumulator function + * 1 s s d d 0 0 0 - - - - - - - - COM dstAC, srcAC + * 1 s s d d 0 0 1 - - - - - - - - NEG dstAC, srcAC + * 1 s s d d 0 1 0 - - - - - - - - MOV dstAC, srcAC + * 1 s s d d 0 1 1 - - - - - - - - INC dstAC, srcAC + * 1 s s d d 1 0 0 - - - - - - - - ADC dstAC, srcAC + * 1 s s d d 1 0 1 - - - - - - - - SUB dstAC, srcAC + * 1 s s d d 1 1 0 - - - - - - - - ADD dstAC, srcAC + * 1 s s d d 1 1 1 - - - - - - - - AND dstAC, srcAC + * 1 - - - - - - - x x - - - - - - shift operation + * 1 - - - - - - - 0 0 - - - - - - nothing + * 1 - - - - - - - 0 1 - - - - - - rotate left through carry + * 1 - - - - - - - 1 0 - - - - - - rotate right through carry + * 1 - - - - - - - 1 1 - - - - - - swap byte halves + * 1 - - - - - - - - - x x - - - - carry in mode + * 1 - - - - - - - - - 0 0 - - - - nothing + * 1 - - - - - - - - - 0 1 - - - - Z carry in is zero + * 1 - - - - - - - - - 1 0 - - - - O carry in is one + * 1 - - - - - - - - - 1 1 - - - - C carry in is complemented carry + * 1 - - - - - - - - - - - x - - - NL + * - - - - - - - - - - - - - x x x conditional execution + * - - - - - - - - - - - - - 0 0 0 NVR never skip + * - - - - - - - - - - - - - 0 0 1 SKP always skip + * - - - - - - - - - - - - - 0 1 0 SZC skip if carry result is zero + * - - - - - - - - - - - - - 0 1 1 SNC skip if carry result is non-zero + * - - - - - - - - - - - - - 1 0 0 SZR skip if 16 bit result is zero + * - - - - - - - - - - - - - 1 0 1 SNR skip if 16 bit result is non-zero + * - - - - - - - - - - - - - 1 1 0 SEZ skip if either result is zero + * - - - - - - - - - - - - - 1 1 1 SBN skip if both results are non-zero + */ +#define IR_ARITH(ir) X_RDBITS(ir,16, 0, 0) +#define IR_SrcAC(ir) X_RDBITS(ir,16, 1, 2) +#define IR_DstAC(ir) X_RDBITS(ir,16, 3, 4) +#define IR_AFunc(ir) X_RDBITS(ir,16, 5, 7) +#define IR_SH(ir) X_RDBITS(ir,16, 8, 9) +#define IR_CY(ir) X_RDBITS(ir,16,10,11) +#define IR_NL(ir) X_RDBITS(ir,16,12,12) +#define IR_SK(ir) X_RDBITS(ir,16,13,15) + +#define IR_MFunc(ir) X_RDBITS(ir,16, 1, 2) +#define IR_JFunc(ir) X_RDBITS(ir,16, 3, 4) +#define IR_I(ir) X_RDBITS(ir,16, 5, 5) +#define IR_X(ir) X_RDBITS(ir,16, 6, 7) +#define IR_DISP(ir) X_RDBITS(ir,16, 8,15) +#define IR_AUGFUNC(ir) X_RDBITS(ir,16, 3, 7) + +#define op_MFUNC_MASK 0060000 //!< instruction register memory function mask +#define op_MFUNC_JUMP 0000000 //!< jump functions value +#define op_JUMP_MASK 0014000 //!< jump functions mask +#define op_JMP 0000000 //!< jump +#define op_JSR 0004000 //!< jump to subroutine +#define op_ISZ 0010000 //!< increment and skip if zero +#define op_DSZ 0014000 //!< decrement and skip if zero +#define op_LDA 0020000 //!< load accu functions value +#define op_STA 0040000 //!< store accu functions value +#define op_AUGMENTED 0060000 //!< store accu functions value +#define op_AUGM_MASK 0077400 //!< mask covering all augmented functions +#define op_AUGM_NODISP 0061000 //!< augmented functions w/o displacement +#define op_AUGM_SUBFUNC 0000037 //!< mask for augmented subfunctions in DISP +#define op_CYCLE 0060000 //!< cycle AC0 +#define op_NODISP 0061000 //!< NODISP: opcodes without displacement +#define op_DIR 0061000 //!< disable interrupts +#define op_EIR 0061001 //!< enable interrupts +#define op_BRI 0061002 //!< branch and return from interrupt +#define op_RCLK 0061003 //!< read clock to AC0, AC1 +#define op_SIO 0061004 //!< start I/O +#define op_BLT 0061005 //!< block transfer +#define op_BLKS 0061006 //!< block set value +#define op_SIT 0061007 //!< start interval timer +#define op_JMPRAM 0061010 //!< jump to microcode RAM (actually ROM, too) +#define op_RDRAM 0061011 //!< read microcode RAM +#define op_WRTRAM 0061012 //!< write microcode RAM +#define op_DIRS 0061013 //!< disable interrupts, and skip, if already disabled +#define op_VERS 0061014 //!< get microcode version in AC0 +#define op_DREAD 0061015 //!< double word read (Alto II) +#define op_DWRITE 0061016 //!< double word write (Alto II) +#define op_DEXCH 0061017 //!< double word exchange (Alto II) +#define op_MUL 0061020 //!< unsigned multiply +#define op_DIV 0061021 //!< unsigned divide +#define op_DIAGNOSE1 0061022 //!< write two different accus in fast succession +#define op_DIAGNOSE2 0061023 //!< write Hamming code and memory +#define op_BITBLT 0061024 //!< bit-aligned block transfer +#define op_XMLDA 0061025 //!< load accu AC0 from extended memory (Alto II/XM) +#define op_XMSTA 0061026 //!< store accu AC0 to extended memory (Alto II/XM) +#define op_JSRII 0064400 //!< jump to subroutine PC relative, doubly indirect +#define op_JSRIS 0065000 //!< jump to subroutine AC2 relative, doubly indirect +#define op_CONVERT 0067000 //!< convert bitmapped font to bitmap +#define op_ARITH_MASK 0103400 //!< mask for arithmetic functions +#define op_COM 0100000 //!< one's complement +#define op_NEG 0100400 //!< two's complement +#define op_MOV 0101000 //!< accu transfer +#define op_INC 0101400 //!< increment +#define op_ADC 0102000 //!< add one's complement +#define op_SUB 0102400 //!< subtract by adding two's complement +#define op_ADD 0103000 //!< add +#define op_AND 0103400 //!< logical and + +#define ea_DIRECT 0000000 //!< effective address is direct +#define ea_INDIRECT 0002000 //!< effective address is indirect +#define ea_MASK 0001400 //!< mask for effective address modes +#define ea_PAGE0 0000000 //!< e is page 0 address +#define ea_PCREL 0000400 //!< e is PC + signed displacement +#define ea_AC2REL 0001000 //!< e is AC2 + signed displacement +#define ea_AC3REL 0001400 //!< e is AC3 + signed displacement + + +#define sh_MASK 0000300 //!< shift mode mask (do novel shifts) +#define sh_L 0000100 //!< rotate left through carry +#define sh_R 0000200 //!< rotate right through carry +#define sh_S 0000300 //!< swap byte halves + +#define cy_MASK 0000060 //!< carry in mode mask +#define cy_Z 0000020 //!< carry in is zero +#define cy_O 0000040 //!< carry in is one +#define cy_C 0000060 //!< carry in is complemented carry + +#define nl_MASK 0000010 //!< no-load mask +#define nl_NONE 0000010 //!< do not load DstAC nor carry + +#define sk_MASK 0000007 //!< skip mask +#define sk_NVR 0000000 //!< never skip +#define sk_SKP 0000001 //!< always skip +#define sk_SZC 0000002 //!< skip if carry result is zero +#define sk_SNC 0000003 //!< skip if carry result is non-zero +#define sk_SZR 0000004 //!< skip if 16-bit result is zero +#define sk_SNR 0000005 //!< skip if 16-bit result is non-zero +#define sk_SEZ 0000006 //!< skip if either result is zero +#define sk_SBN 0000007 //!< skip if both results are non-zero + +/** + * @brief register selection + * + *
+ * From the schematics: 08_ALU, page 6 (PDF page 4)
+ *
+ * EMACT            emulator task active
+ * F2[0-2]=111b     <-ACSOURCE and F2_17
+ * F2[0-2]=101b     DNS<- and ACDEST<-
+ *
+ *  u49 (8 input NAND 74S30)
+ *  ----------------------------------------------
+ *  F2[0] & F2[2] & F2[1]' & IR[03]' & EMACT
+ *
+ *      F2[0-2] IR[03]  EMACT   output u49pin8
+ *      --------------------------------------
+ *      101     0       1       0
+ *      all others              1
+ *
+ *
+ *  u59 (8 input NAND 74S30)
+ *  ----------------------------------------------
+ *  F2[0] & F2[2] & F2[1] & IR[01]' & EMACT
+ *
+ *      F2[0-2] IR[01] EMACT    output u59pin8
+ *      --------------------------------------
+ *      111     0      1        0
+ *      all others              1
+ *
+ *  u70d (2 input NOR 74S02 used as inverter)
+ *  ---------------------------------------------
+ *  RSEL3 -> RSEL3'
+ *
+ *  u79b (3 input NAND 74S10)
+ *  ---------------------------------------------
+ *      u49pin8 u59pin8 RSEL3'  output 6RA3
+ *      -------------------------------------
+ *      1       1       1       0
+ *      0       x       x       1
+ *      x       0       x       1
+ *      x       x       0       1
+ *
+ *
+ *  u60 (8 input NAND 74S30)
+ *  ----------------------------------------------
+ *  F2[0] & F2[2] & F2[1]' & IR[02]' & EMACT
+ *
+ *      F2[0-2] IR[02]  EMACT   output u60pin8
+ *      --------------------------------------
+ *      101     0       1       0
+ *      all others              1
+ *
+ *  u50 (8 input NAND 74S30)
+ *  ----------------------------------------------
+ *  F2[0] & F2[2] & F2[1] & IR[04]' & EMACT
+ *
+ *      F2[0-2] IR[04]  EMACT   output u50pin8
+ *      --------------------------------------
+ *      111     0       1       0
+ *      all others              1
+ *
+ *  u70c (2 input NOR 74S02 used as inverter)
+ *  ---------------------------------------------
+ *  RSEL4 -> RSEL4'
+ *
+ *
+ *  u79c (3 input NAND 74S10)
+ *  ---------------------------------------------
+ *  u60pin8 u50pin8 RSEL4'  output 8RA4
+ *  -------------------------------------
+ *  1       1       1       0
+ *  0       x       x       1
+ *  x       0       x       1
+ *  x       x       0       1
+ *
+ * BUG?: schematics seem to have swapped IR(04)' and IR(02)' inputs for the
+ * RA4 decoding, because SrcAC is selected from IR[1-2]?
+ * 
+ */ + +/** + * @brief bs_disp early: drive bus by IR[8-15], possibly sign extended + * + * The high order bits of IR cannot be read directly, but the + * displacement field of IR (8 low order bits) may be read with + * the <-DISP bus source. If the X field of the instruction is + * zero (i.e., it specifies page 0 addressing), then the DISP + * field of the instruction is put on BUS[8-15] and BUS[0-7] + * is zeroed. If the X field of the instruction is non-zero + * (i.e. it specifies PC-relative or base-register addressing) + * then the DISP field is sign-extended and put on the bus. + * + */ +void alto2_cpu_device::bs_early_emu_disp() +{ + UINT16 r = IR_DISP(m_emu.ir); + if (IR_X(m_emu.ir)) { + r = ((signed char)r) & 0177777; + } + LOG((LOG_EMU,2, " <-DISP (%06o)\n", r)); + m_bus &= r; +} + +/** + * @brief f1_block early: block task + * + * The task request for the active task is cleared + */ +void alto2_cpu_device::f1_early_emu_block() +{ +#if 0 + CPU_CLR_TASK_WAKEUP(m_task); + LOG((LOG_EMU,2, " BLOCK %02o:%s\n", m_task, task_name(m_task))); +#elif 0 + fatal(1, "Emulator task want's to BLOCK.\n" \ + "%s-%04o: r:%02o af:%02o bs:%02o f1:%02o f2:%02o" \ + " t:%o l:%o next:%05o next2:%05o cycle:%lld\n", + task_name(m_task), m_mpc, + m_rsel, m_daluf, m_dbs, m_df1, mdf2, + m_dloadt, m_dloatl, m_next, m_next2, + ntime() / CPU_MICROCYCLE_TIME); +#else + /* just ignore (?) */ +#endif +} + +/** + * @brief f1_load_rmr late: load the reset mode register + */ +void alto2_cpu_device::f1_late_emu_load_rmr() +{ + LOG((LOG_EMU,2," RMR<-; BUS (%#o)\n", m_bus)); + m_reset_mode = m_bus; +} + +/** + * @brief f1_load_esrb late: load the extended S register bank from BUS[12-14] + */ +void alto2_cpu_device::f1_late_emu_load_esrb() +{ + LOG((LOG_EMU,2," ESRB<-; BUS[12-14] (%#o)\n", m_bus)); + m_s_reg_bank[m_task] = X_RDBITS(m_bus,16,12,14); +} + +/** + * @brief f1_rsnf early: drive the bus from the Ethernet node ID + * + * TODO: move this to the Ethernet code? It's really a emulator + * specific function that is decoded by the Ethernet card. + */ +void alto2_cpu_device::f1_early_rsnf() +{ + UINT16 r = 0177400 | m_ether_id; + LOG((LOG_EMU,2," <-RSNF; (%#o)\n", r)); + m_bus &= r; +} + +/** + * @brief f1_startf early: defines commands for for I/O hardware, including Ethernet + *
+ * (SIO) Start I/O is included to facilitate I/O control, It places the contents of
+ * AC0 on the processor bus and executes the STARTF function (F1 = 17B). By convention,
+ * bits of AC0 must be "1" in order to signal devices. See Appendix C for a summary of
+ * assigned bits.
+ *    Bit 0  100000B   Standard Alto: Software boot feature
+ *    Bit 14 000002B   Standard Alto: Ethernet
+ *    Bit 15 000001B   Standard Alto: Ethernet
+ * If bit 0 of AC0 is 1, and if an Ethernet board is plugged into the Alto, the machine
+ * will boot, just as if the "boot button" were pressed (see sections 3.4, 8.4 and 9.2.2
+ * for discussions of bootstrapping).
+ *
+ * SIO also returns a result in AC0. If the Ethernet hardware is installed, the serial
+ * number and/or Ethernet host address of the machine (0-377B) is loaded into AC0[8-15].
+ * (On Alto I, the serial number and Ethernet host address are equivalent; on Alto II,
+ * the value loaded into AC0 is the Ethernet host address only.) If Ethernet hardware
+ * is missing, AC0[8-15] = 377B. Microcode installed after June 1976, which this manual
+ * describes, returns AC0[0] = 0. Microcode installed prior to June 1976 returns
+ * AC0[0] = 1; this is a quick way to acquire the approximate vintage of a machine's
+ * microcode.
+ * 
+ * + * TODO: move this to the Ethernet code? It's really a emulator + * specific function that is decoded by the Ethernet card. + */ +void alto2_cpu_device::f1_early_startf() +{ + LOG((LOG_EMU,2," STARTF (BUS is %06o)\n", m_bus)); + /* TODO: what do we do here? reset the CPU on bit 0? */ + if (X_BIT(m_bus,16,0)) { + LOG((LOG_EMU,2,"**** Software boot feature\n")); + soft_reset(); + } else { + LOG((LOG_EMU,2,"**** Ethernet start function\n")); + eth_startf(); + } +} + +/** + * @brief branch on odd bus + */ +void alto2_cpu_device::f2_late_busodd() +{ + UINT16 r = m_bus & 1; + LOG((LOG_EMU,2," BUSODD; %sbranch (%#o|%#o)\n", r ? "" : "no ", m_next2, r)); + m_next2 |= r; +} + +/** + * @brief f2_magic late: shift and use T[0] or T[15] for bit 15 or 0 + */ +void alto2_cpu_device::f2_late_magic() +{ + int XC; + switch (m_d_f1) { + case f1_l_lsh_1: // <-L MLSH 1 + XC = (m_t >> 15) & 1; + m_shifter = (m_l << 1) | XC; + LOG((LOG_EMU,2," <-L MLSH 1 (shifer:%06o XC:%o)", m_shifter, XC)); + break; + case f1_l_rsh_1: // <-L MRSH 1 + XC = (m_t & 1) << 15; + m_shifter = (m_l >> 1) | XC; + LOG((LOG_EMU,2," <-L MRSH 1 (shifter:%06o XC:%o)", m_shifter, XC)); + break; + case f1_l_lcy_8: // <-L LCY 8 + m_shifter = (m_l >> 8) | (m_l << 8); + break; + default: // other + m_shifter = m_l; + break; + } +} + +/** + * @brief do novel shifts: modify RESELECT with DstAC = (3 - IR[3-4]) + */ +void alto2_cpu_device::f2_early_load_dns() +{ + X_WRBITS(m_rsel, 5, 3, 4, IR_DstAC(m_emu.ir) ^ 3); + LOG((LOG_EMU,2," DNS<-; rsel := DstAC (%#o %s)\n", m_rsel, r_name(m_rsel))); +} + +/** + * @brief do novel shifts + * + *
+ * New emulator carry is selected by instruction register
+ * bits CY = IR[10-11]. R register and emulator carry are
+ * loaded only if NL = IR[12] is 0 (NL = no load).
+ * SKIP is set according to SK = IR[13-15].
+ *
+ *  CARRY     = !m_emu.cy
+ *  exorB     = IR11 ^ IR10
+ *  ORA       = !(exorB | CARRY)
+ *            = (exorB | CARRY) ^ 1
+ *  exorC     = ORA ^ !IR11
+ *            = ORA ^ IR11 ^ 1
+ *  exorD     = exorC ^ LALUC0
+ *  XC        = !(!(DNS & exorD) & !(MAGIC & OUTza))
+ *            = (DNS & exorD) | (MAGIC & OUTza)
+ *            = exorD, because this is DNS
+ *  NEWCARRY  = [XC, L(00), L(15), XC] for F1 = no shift, <-L RSH 1, <-L LSH 1, LCY 8
+ *  SHZERO    = shifter == 0
+ *  DCARRY    = !((!IR12 & NEWCARRY) | (IR12 & CARRY))
+ *            = (((IR12 ^ 1) & NEWCARRY) | (IR12 & CARRY)) ^ 1
+ *  DSKIP     = !((!NEWCARRY & IR14) | (SHZERO & IR13)) ^ !IR15
+ *            = ((((NEWCARRY ^ 1) & IR14) | (SHZERO & IR13)) ^ 1) ^ (IR15 ^ 1)
+ *            = (((NEWCARRY ^ 1) & IR14) | (SHZERO & IR13)) ^ IR15
+ * 
+ */ +void alto2_cpu_device::f2_late_load_dns() +{ + UINT8 IR10 = X_BIT(m_emu.ir,16,10); + UINT8 IR11 = X_BIT(m_emu.ir,16,11); + UINT8 IR12 = X_BIT(m_emu.ir,16,12); + UINT8 IR13 = X_BIT(m_emu.ir,16,13); + UINT8 IR14 = X_BIT(m_emu.ir,16,14); + UINT8 IR15 = X_BIT(m_emu.ir,16,15); + UINT8 exorB = IR11 ^ IR10; + UINT8 CARRY = m_emu.cy ^ 1; + UINT8 ORA = (exorB | CARRY) ^ 1; + UINT8 exorC = ORA ^ (IR11 ^ 1); + UINT8 exorD = exorC ^ m_laluc0; + UINT8 XC = exorD; + UINT8 NEWCARRY; + UINT8 DCARRY; + UINT8 DSKIP; + UINT8 SHZERO; + + switch (m_d_f1) { + case f1_l_rsh_1: // <-L RSH 1 + NEWCARRY = m_l & 1; + m_shifter = ((m_l >> 1) | (XC << 15)) & 0177777; + LOG((LOG_EMU,2," DNS; <-L RSH 1 (shifter:%06o XC:%o NEWCARRY:%o)", m_shifter, XC, NEWCARRY)); + break; + case f1_l_lsh_1: // <-L LSH 1 + NEWCARRY = (m_l >> 15) & 1; + m_shifter = ((m_l << 1) | XC) & 0177777; + LOG((LOG_EMU,2," DNS; <-L LSH 1 (shifter:%06o XC:%o NEWCARRY:%o)", m_shifter, XC, NEWCARRY)); + break; + case f1_l_lcy_8: // <-L LCY 8 + NEWCARRY = XC; + m_shifter = (m_l >> 8) | (m_l << 8); + LOG((LOG_EMU,2," DNS; (shifter:%06o NEWCARRY:%o)", m_shifter, NEWCARRY)); + break; + default: // other + NEWCARRY = XC; + m_shifter = m_l; + LOG((LOG_EMU,2," DNS; (shifter:%06o NEWCARRY:%o)", m_shifter, NEWCARRY)); + break; + } + SHZERO = (m_shifter == 0); + DCARRY = (((IR12 ^ 1) & NEWCARRY) | (IR12 & CARRY)) ^ 1; + DSKIP = (((NEWCARRY ^ 1) & IR14) | (SHZERO & IR13)) ^ IR15; + + m_emu.cy = DCARRY; // DCARRY is latched as new m_emu.cy + m_emu.skip = DSKIP; // DSKIP is latched as new m_emu.skip + + /* !(IR12 & DNS) -> WR' = 0 for the register file */ + if (!IR12) { + m_r[m_rsel] = m_shifter; + } +} + +/** + * @brief destiantion accu: modify RSELECT with DstAC = (3 - IR[3-4]) + */ +void alto2_cpu_device::f2_early_acdest() +{ + X_WRBITS(m_rsel, 5, 3, 4, IR_DstAC(m_emu.ir) ^ 3); + LOG((LOG_EMU,2," ACDEST<-; mux (rsel:%#o %s)\n", m_rsel, r_name(m_rsel))); +} + +#if ALTO2_DEBUG +void alto2_cpu_device::bitblt_info() +{ + static const char *type_name[4] = {"bitmap","complement","and gray","gray"}; + static const char *oper_name[4] = {"replace","paint","invert","erase"}; + int bbt = m_r[rsel_ac2]; + int val = debug_read_mem(bbt); + + LOG((LOG_EMU,3," BITBLT AC1:%06o AC2:%06o\n", m_r[rsel_ac1], m_r[rsel_ac2])); + LOG((LOG_EMU,3," function : %06o\n", val)); + LOG((LOG_EMU,3," src extRAM: %o\n", X_BIT(val,16,10))); + LOG((LOG_EMU,3," dst extRAM: %o\n", X_BIT(val,16,11))); + LOG((LOG_EMU,3," src type : %o (%s)\n", X_RDBITS(val,16,12,13), type_name[X_RDBITS(val,16,12,13)])); + LOG((LOG_EMU,3," operation : %o (%s)\n", X_RDBITS(val,16,14,15), oper_name[X_RDBITS(val,16,14,15)])); + val = debug_read_mem(bbt+1); + LOG((LOG_EMU,3," unused AC2: %06o (%d)\n", val, val)); + val = debug_read_mem(bbt+2); + LOG((LOG_EMU,3," DBCA : %06o (%d)\n", val, val)); + val = debug_read_mem(bbt+3); + LOG((LOG_EMU,3," DBMR : %06o (%d words)\n", val, val)); + val = debug_read_mem(bbt+4); + LOG((LOG_EMU,3," DLX : %06o (%d bits)\n", val, val)); + val = debug_read_mem(bbt+5); + LOG((LOG_EMU,3," DTY : %06o (%d scanlines)\n", val, val)); + val = debug_read_mem(bbt+6); + LOG((LOG_EMU,3," DW : %06o (%d bits)\n", val, val)); + val = debug_read_mem(bbt+7); + LOG((LOG_EMU,3," DH : %06o (%d scanlines)\n", val, val)); + val = debug_read_mem(bbt+8); + LOG((LOG_EMU,3," SBCA : %06o (%d)\n", val, val)); + val = debug_read_mem(bbt+9); + LOG((LOG_EMU,3," SBMR : %06o (%d words)\n", val, val)); + val = debug_read_mem(bbt+10); + LOG((LOG_EMU,3," SLX : %06o (%d bits)\n", val, val)); + val = debug_read_mem(bbt+11); + LOG((LOG_EMU,3," STY : %06o (%d scanlines)\n", val, val)); + LOG((LOG_EMU,3," GRAY0-3 : %06o %06o %06o %06o\n", + debug_read_mem(bbt+12), debug_read_mem(bbt+13), + debug_read_mem(bbt+14), debug_read_mem(bbt+15))); +} +#endif /* DEBUG */ + +/** + * @brief load instruction register IR and branch on IR[0,5-7] + * + * Loading the IR clears the skip latch. + */ +void alto2_cpu_device::f2_late_load_ir() +{ + UINT16 r = (X_BIT(m_bus,16,0) << 3) | X_RDBITS(m_bus,16,5,7); + +#if ALTO2_DEBUG + /* special logging of some opcodes */ + switch (m_bus) { + case op_CYCLE: + LOG((LOG_EMU,3," CYCLE AC0:#o\n", m_r[rsel_ac0])); + break; + case op_CYCLE + 1: case op_CYCLE + 2: case op_CYCLE + 3: case op_CYCLE + 4: + case op_CYCLE + 5: case op_CYCLE + 6: case op_CYCLE + 7: case op_CYCLE + 8: + case op_CYCLE + 9: case op_CYCLE +10: case op_CYCLE +11: case op_CYCLE +12: + case op_CYCLE +13: case op_CYCLE +14: case op_CYCLE +15: + LOG((LOG_EMU,3," CYCLE %#o\n", m_bus - op_CYCLE)); + break; + case op_BLT: + LOG((LOG_EMU,3," BLT dst:%#o src:%#o size:%#o\n", + (m_r[rsel_ac1] + m_r[rsel_ac3] + 1) & 0177777, + (m_r[rsel_ac0] + 1) & 017777, -m_r[rsel_ac3] & 0177777)); + break; + case op_BLKS: + LOG((LOG_EMU,3," BLKS dst:%#o val:%#o size:%#o\n", + (m_r[rsel_ac1] + m_r[rsel_ac3] + 1) & 0177777, + m_r[rsel_ac0], -m_r[rsel_ac3] & 0177777)); + break; + case op_DIAGNOSE1: + LOG((LOG_EMU,3," DIAGNOSE1 AC0:%06o AC1:%06o AC2:%06o AC3:%06o\n", + m_r[rsel_ac0], m_r[rsel_ac1], + m_r[rsel_ac2], m_r[rsel_ac3])); + break; + case op_DIAGNOSE2: + LOG((LOG_EMU,3," DIAGNOSE2 AC0:%06o AC1:%06o AC2:%06o AC3:%06o\n", + m_r[rsel_ac0], m_r[rsel_ac1], + m_r[rsel_ac2], m_r[rsel_ac3])); + break; + case op_BITBLT: + bitblt_info(); + break; + case op_RDRAM: + LOG((LOG_EMU,3," RDRAM addr:%#o\n", m_r[rsel_ac1])); + break; + case op_WRTRAM: + LOG((LOG_EMU,3," WRTAM addr:%#o upper:%06o lower:%06o\n", m_r[rsel_ac1], m_r[rsel_ac0], m_r[rsel_ac3])); + break; + case op_JMPRAM: + LOG((LOG_EMU,3," JMPRAM addr:%#o\n", m_r[rsel_ac1])); + break; + case op_XMLDA: + LOG((LOG_EMU,3," XMLDA AC0 = [bank:%o AC1:#o]\n", m_bank_reg[m_task] & 3, m_r[rsel_ac1])); + break; + case op_XMSTA: + LOG((LOG_EMU,3," XMSTA [bank:%o AC1:#o] = AC0 (%#o)\n", m_bank_reg[m_task] & 3, m_r[rsel_ac1], m_r[rsel_ac0])); + break; + } +#endif + m_emu.ir = m_bus; + m_emu.skip = 0; + m_next2 |= r; +} + + +/** + * @brief branch on: arithmetic IR_SH, others PROM ctl2k_u3[IR[1-7]] + */ +void alto2_cpu_device::f2_late_idisp() +{ + UINT16 r; + + if (IR_ARITH(m_emu.ir)) { + /* 1xxxxxxxxxxxxxxx */ + r = IR_SH(m_emu.ir) ^ 3; /* complement of SH */ + LOG((LOG_EMU,2," IDISP<-; branch on SH^3 (%#o|%#o)\n", m_next2, r)); + } else { + int addr = CTL2K_U3(f2_emu_idisp) + X_RDBITS(m_emu.ir,16,1,7); + /* 0???????xxxxxxxx */ + r = m_ctl2k_u3[addr]; + LOG((LOG_EMU,2," IDISP<-; IR (%#o) branch on PROM ctl2k_u3[%03o] (%#o|%#o)\n", m_emu.ir, addr, m_next2, r)); + } + m_next2 |= r; +} + +/** + * @brief source accu: modify RSELECT with SrcAC = (3 - IR[1-2]) + */ +void alto2_cpu_device::f2_early_acsource() +{ + X_WRBITS(m_rsel, 5, 3, 4, IR_SrcAC(m_emu.ir) ^ 3); + LOG((LOG_EMU,2," <-ACSOURCE; rsel := SrcAC (%#o %s)\n", m_rsel, r_name(m_rsel))); +} + +/** + * @brief branch on: arithmetic IR_SH, others PROM ctl2k_u3[IR[1-7]] + */ +void alto2_cpu_device::f2_late_acsource() +{ + UINT16 r; + + if (IR_ARITH(m_emu.ir)) { + /* 1xxxxxxxxxxxxxxx */ + r = IR_SH(m_emu.ir) ^ 3; /* complement of SH */ + LOG((LOG_EMU,2," <-ACSOURCE; branch on SH^3 (%#o|%#o)\n", m_next2, r)); + } else { + int addr = CTL2K_U3(f2_emu_acsource) + X_RDBITS(m_emu.ir,16,1,7); + /* 0???????xxxxxxxx */ + r = m_ctl2k_u3[addr]; + LOG((LOG_EMU,2," <-ACSOURCE; branch on PROM ctl2k_u3[%03o] (%#o|%#o)\n", addr, m_next2, r)); + } + m_next2 |= r; +} + +void alto2_cpu_device::init_emu(int task) +{ + memset(&m_emu, 0, sizeof(m_emu)); + save_item(NAME(m_emu.ir)); + save_item(NAME(m_emu.skip)); + save_item(NAME(m_emu.cy)); + + init_ram(task); + + set_bs(task, bs_emu_read_sreg, &alto2_cpu_device::bs_early_read_sreg, 0); + set_bs(task, bs_emu_load_sreg, &alto2_cpu_device::bs_early_load_sreg, &alto2_cpu_device::bs_late_load_sreg); + set_bs(task, bs_disp, &alto2_cpu_device::bs_early_emu_disp, 0); + + set_f1(task, f1_block, &alto2_cpu_device::f1_early_emu_block, 0); // catch the emulator task trying to block (wrong branch) + set_f1(task, f1_emu_swmode, 0, &alto2_cpu_device::f1_late_swmode); + set_f1(task, f1_emu_wrtram, 0, &alto2_cpu_device::f1_late_wrtram); + set_f1(task, f1_emu_rdram, 0, &alto2_cpu_device::f1_late_rdram); + set_f1(task, f1_emu_load_rmr, 0, &alto2_cpu_device::f1_late_emu_load_rmr); + set_f1(task, f1_task_14, 0, 0); // F1 014 is undefined (?) + set_f1(task, f1_emu_load_esrb, 0, &alto2_cpu_device::f1_late_emu_load_esrb); + set_f1(task, f1_emu_rsnf, &alto2_cpu_device::f1_early_rsnf, 0); + set_f1(task, f1_emu_startf, &alto2_cpu_device::f1_early_startf, 0); + + set_f2(task, f2_emu_busodd, 0, &alto2_cpu_device::f2_late_busodd); + set_f2(task, f2_emu_magic, 0, &alto2_cpu_device::f2_late_magic); + set_f2(task, f2_emu_load_dns, &alto2_cpu_device::f2_early_load_dns, &alto2_cpu_device::f2_late_load_dns); + set_f2(task, f2_emu_acdest, &alto2_cpu_device::f2_early_acdest, 0); + set_f2(task, f2_emu_load_ir, 0, &alto2_cpu_device::f2_late_load_ir); + set_f2(task, f2_emu_idisp, 0, &alto2_cpu_device::f2_late_idisp); + set_f2(task, f2_emu_acsource, &alto2_cpu_device::f2_early_acsource, &alto2_cpu_device::f2_late_acsource); +} + +void alto2_cpu_device::exit_emu() +{ + // nothing to do yet +} + +void alto2_cpu_device::reset_emu() +{ + m_emu.ir = 0; + m_emu.skip = 0; + m_emu.cy = 0; +} diff --git a/src/devices/cpu/alto2/a2emu.h b/src/devices/cpu/alto2/a2emu.h new file mode 100644 index 00000000000..344c7ff2c71 --- /dev/null +++ b/src/devices/cpu/alto2/a2emu.h @@ -0,0 +1,69 @@ +// license:BSD-3-Clause +// copyright-holders:Juergen Buchmueller +/***************************************************************************** + * + * Xerox AltoII emulator task (EMU) + * + *****************************************************************************/ +#ifdef ALTO2_DEFINE_CONSTANTS + +#else // ALTO2_DEFINE_CONSTANTS +#ifndef _A2EMU_H_ +#define _A2EMU_H_ + +//! BUS source for emulator task +enum { + bs_emu_read_sreg = bs_task_3, //!< bus source: read S register + bs_emu_load_sreg = bs_task_4 //!< bus source: load S register from BUS +}; + +//! F1 functions for emulator task +enum { + f1_emu_swmode = f1_task_10, //!< f1 (1000): switch mode; branch to ROM/RAM microcode + f1_emu_wrtram = f1_task_11, //!< f1 (1001): write microcode RAM cycle + f1_emu_rdram = f1_task_12, //!< f1 (1010): read microcode RAM cycle + f1_emu_load_rmr = f1_task_13, //!< f1 (1011): load reset mode register + //!< f1 (1100): undefined + f1_emu_load_esrb = f1_task_15, //!< f1 (1101): load extended S register bank + f1_emu_rsnf = f1_task_16, //!< f1 (1110): read serial number (Ethernet ID) + f1_emu_startf = f1_task_17 //!< f1 (1111): start I/O hardware (Ethernet) +}; + +//! F2 functions for emulator task +enum { + f2_emu_busodd = f2_task_10, //!< f2 (1000): branch on bus odd + f2_emu_magic = f2_task_11, //!< f2 (1001): magic shifter (MRSH 1: shifter[15]=T[0], MLSH 1: shifter[015]) + f2_emu_load_dns = f2_task_12, //!< f2 (1010): do novel shift (RSH 1: shifter[15]=XC, LSH 1: shifer[0]=XC) + f2_emu_acdest = f2_task_13, //!< f2 (1011): destination accu + f2_emu_load_ir = f2_task_14, //!< f2 (1100): load instruction register and branch + f2_emu_idisp = f2_task_15, //!< f2 (1101): load instruction displacement and branch + f2_emu_acsource = f2_task_16 //!< f2 (1110): source accu + //!< f2 (1111): undefined +}; + +struct { + UINT16 ir; //!< emulator instruction register + UINT8 skip; //!< emulator skip + UINT8 cy; //!< emulator carry +} m_emu; +void bs_early_emu_disp(); //!< bus source: drive bus by IR[8-15], possibly sign extended +void f1_early_emu_block(); //!< F1 func: block task +void f1_late_emu_load_rmr(); //!< F1 func: load the reset mode register +void f1_late_emu_load_esrb(); //!< F1 func: load the extended S register bank from BUS[12-14] +void f1_early_rsnf(); //!< F1 func: drive the bus from the Ethernet node ID +void f1_early_startf(); //!< F1 func: defines commands for for I/O hardware, including Ethernet +void f2_late_busodd(); //!< F2 func: branch on odd bus +void f2_late_magic(); //!< F2 func: shift and use T +void f2_early_load_dns(); //!< F2 func: modify RESELECT with DstAC = (3 - IR[3-4]) +void f2_late_load_dns(); //!< F2 func: do novel shifts +void f2_early_acdest(); //!< F2 func: modify RSELECT with DstAC = (3 - IR[3-4]) +void bitblt_info(); //!< debug bitblt opcode +void f2_late_load_ir(); //!< F2 func: load instruction register IR and branch on IR[0,5-7] +void f2_late_idisp(); //!< F2 func: branch on: arithmetic IR_SH, others PROM ctl2k_u3[IR[1-7]] +void f2_early_acsource(); //!< F2 func: modify RSELECT with SrcAC = (3 - IR[1-2]) +void f2_late_acsource(); //!< F2 func: branch on arithmetic IR_SH, others PROM ctl2k_u3[IR[1-7]] +void init_emu(int task = task_emu); //!< initialize the emulator task +void exit_emu(); //!< deinitialize the emulator task +void reset_emu(); //!< reset the emulator task +#endif // _A2EMU_H_ +#endif // ALTO2_DEFINE_CONSTANTS diff --git a/src/devices/cpu/alto2/a2ether.c b/src/devices/cpu/alto2/a2ether.c new file mode 100644 index 00000000000..32d8a716f49 --- /dev/null +++ b/src/devices/cpu/alto2/a2ether.c @@ -0,0 +1,1380 @@ +// license:BSD-3-Clause +// copyright-holders:Juergen Buchmueller +/***************************************************************************** + * + * Xerox AltoII ethernet task + * + *****************************************************************************/ +#include "alto2cpu.h" +#include "a2roms.h" + +#define DEBUG_PACKETS 1 + + +/** + * @brief BPROMs P3601-1; 256x4; enet.a41 "PE1" and enet.a42 "PE2" + * + * Phase encoder + * + * a41: P3601-1; 256x4; "PE1" + * a42: P3601-1; 256x4; "PE2" + * + * PE1/PE2 inputs + * ---------------- + * A0 (5) OUTGO + * A1 (6) XDATA + * A2 (7) OSDATAG + * A3 (4) XCLOCK + * A4 (3) OCNTR0 + * A5 (2) OCNTR1 + * A6 (1) OCNTR2 + * A7 (15) OCNTR3 + * + * PE1 outputs + * ---------------- + * D0 (12) OCNTR0 + * D1 (11) OCNTR1 + * D2 (10) OCNTR2 + * D3 (9) OCNTR3 + * + * PE2 outputs + * ---------------- + * D0 (12) n.c. + * D1 (11) to OSLOAD flip flop J and K' + * D2 (10) XDATA + * D3 (9) XCLOCK + */ +static const prom_load_t pl_enet_a41 = +{ /* P3601 256x4 BPROM; Ethernet phase encoder 1 "PE1" */ + "enet.a41", + 0, + "d5de8d86", + "c134a4c898c73863124361a9b0218f7a7f00082a", + /* size */ 0400, + /* amap */ AMAP_DEFAULT, + /* axor */ 0, + /* dxor */ 0, + /* width */ 4, + /* shift */ 0, + /* dmap */ DMAP_DEFAULT, + /* dand */ ZERO, + /* type */ sizeof(UINT8) +}; + +static const prom_load_t pl_enet_a42 = +{ /* P3601 256x4 BPROM; Ethernet phase encoder 2 "PE2" */ + "enet.a42", + 0, + "9d5c81bd", + "ac7e63332a3dad0bef7cd0349b24e156a96a4bf0", + /* size */ 0400, + /* amap */ AMAP_DEFAULT, + /* axor */ 0, + /* dxor */ 0, + /* width */ 4, + /* shift */ 0, + /* dmap */ DMAP_DEFAULT, + /* dand */ ZERO, + /* type */ sizeof(UINT8) +}; + +/** + * @brief BPROM; P3601-1; 265x4 enet.a49 "AFIFO" + * + * FIFO control + * + * a49: P3601-1; 256x4; "AFIFO" + * + * inputs + * ---------------- + * A0 (5) fifo_wr[0] + * A1 (6) fifo_wr[1] + * A2 (7) fifo_wr[2] + * A3 (4) fifo_wr[3] + * A4 (3) fifo_rd[0] + * A5 (2) fifo_rd[1] + * A6 (1) fifo_rd[2] + * A7 (15) fifo_rd[3] + * + * outputs active low + * ---------------------------- + * D0 (12) BE' (buffer empty) + * D1 (11) BNE' (buffer nearly empty) + * D2 (10) BNNE' (buffer next nearly empty) + * D3 (9) BF' (buffer full) + */ +static const prom_load_t pl_enet_a49 = +{ /* P3601 256x4 BPROM; Ethernet FIFO control "AFIFO" */ + "enet.a49", + 0, + "4d2dcdb2", + "583327a7d70cd02702c941c0e43c1e9408ff7fd0", + /* size */ 0400, + /* amap */ AMAP_REVERSE_0_7, // reverse address lines A0-A7 + /* axor */ 0, + /* dxor */ 0, + /* width */ 4, + /* shift */ 0, + /* dmap */ DMAP_DEFAULT, + /* dand */ ZERO, + /* type */ sizeof(UINT8) +}; + +#define GET_ETH_WLF(st) X_BIT(st,16,4) //!< hardware status: write latch full/filled (? set by EODFCT) +#define PUT_ETH_WLF(st,val) X_WRBITS(st,16,4,4,val) + +#define GET_ETH_OEOT(st) X_BIT(st,16,5) //!< hardware status: output end of transmission (set by EEFCT) +#define PUT_ETH_OEOT(st,val) X_WRBITS(st,16,5,5,val) + +#define GET_ETH_IGONE(st) X_BIT(st,16,6) //!< hardware status: input gone +#define PUT_ETH_IGONE(st,val) X_WRBITS(st,16,6,6,val) + +#define GET_ETH_IBUSY(st) X_BIT(st,16,7) //!< hardware status: input busy (set by EISFCT, bit isn't visible to microcode) +#define PUT_ETH_IBUSY(st,val) X_WRBITS(st,16,7,7,val) + +#define GET_ETH_OGONE(st) X_BIT(st,16,8) //!< hardware status: output gone +#define PUT_ETH_OGONE(st,val) X_WRBITS(st,16,8,8,val) + +#define GET_ETH_OBUSY(st) X_BIT(st,16,9) //!< hardware status: output busy (set by EOSFCT, bit isn't visible to microcode) +#define PUT_ETH_OBUSY(st,val) X_WRBITS(st,16,9,9,val) + +#define GET_ETH_IDL(st) X_BIT(st,16,10) //!< hardware status: input data late +#define PUT_ETH_IDL(st,val) X_WRBITS(st,16,10,10,val) + +#define GET_ETH_COLL(st) X_BIT(st,16,11) //!< hardware status: collision +#define PUT_ETH_COLL(st,val) X_WRBITS(st,16,11,11,val) + +#define GET_ETH_CRC(st) X_BIT(st,16,12) //!< hardware status: CRC error +#define PUT_ETH_CRC(st,val) X_WRBITS(st,16,12,12,val) + +#define GET_ETH_ICMD(st) X_BIT(st,16,13) //!< hardware status: input command (set from BUS[14] on SIO, reset by EPFCT) +#define PUT_ETH_ICMD(st,val) X_WRBITS(st,16,13,13,val) + +#define GET_ETH_OCMD(st) X_BIT(st,16,14) //!< hardware status: output command (set from BUS[15] on SIO, reset by EPFCT) +#define PUT_ETH_OCMD(st,val) X_WRBITS(st,16,14,14,val) + +#define GET_ETH_IT(st) X_BIT(st,16,15) //!< hardware status: IT flip flop & ISRFULL' +#define PUT_ETH_IT(st,val) X_WRBITS(st,16,15,15,val) + +#define BE(a49) ((a49 & ether_a49_BE) ? 1 : 0) //! buffer empty +#define BNE(a49) ((a49 & ether_a49_BNE) ? 1 : 0) //! buffer next empty +#define BNNE(a49) ((a49 & ether_a49_BNNE) ? 1 : 0) //! buffer next next empty +#define BF(a49) ((a49 & ether_a49_BF) ? 1 : 0) //! buffer full + +#define BREATHLEN ALTO2_ETHER_PACKET_SIZE //!< ethernet packet length +#define BREATHADDR (0377<<8) //!< destination (0377) and source (0000) +#define BREATHTYPE 0602 //!< ethernet packet type +static const UINT16 breath_of_life_data[BREATHLEN] = +{ + BREATHADDR, /* 3MB destination and source */ + BREATHTYPE, /* ether packet type */ + /* the rest is the contents of a breath of life packet. + * see etherboot.dm (etherboot.asm) for the + * Alto assembly code. + */ + 0022574, 0100000, 0040437, 0102000, 0034431, 0164000, + 0061005, 0102460, 0024567, 0034572, 0061006, 0024565, 0034570, 0061006, + 0024564, 0034566, 0061006, 0020565, 0034565, 0061005, 0125220, 0046573, + 0020576, 0061004, 0123400, 0030551, 0041211, 0004416, 0000000, 0001000, + 0000026, 0000244, 0000000, 0000000, 0000000, 0000000, 0000004, 0000000, + 0000000, 0000020, 0177777, 0055210, 0025400, 0107000, 0045400, 0041411, + 0020547, 0041207, 0020544, 0061004, 0006531, 0034517, 0030544, 0051606, + 0020510, 0041605, 0042526, 0102460, 0041601, 0020530, 0061004, 0021601, + 0101014, 0000414, 0061020, 0014737, 0000773, 0014517, 0000754, 0020517, + 0061004, 0030402, 0002402, 0000000, 0000732, 0034514, 0162414, 0000746, + 0021001, 0024511, 0106414, 0000742, 0021003, 0163400, 0035005, 0024501, + 0106415, 0175014, 0000733, 0021000, 0042465, 0034457, 0056445, 0055775, + 0055776, 0101300, 0041400, 0020467, 0041401, 0020432, 0041402, 0121400, + 0041403, 0021006, 0041411, 0021007, 0041412, 0021010, 0041413, 0021011, + 0041406, 0021012, 0041407, 0021013, 0041410, 0015414, 0006427, 0012434, + 0006426, 0020421, 0024437, 0134000, 0030417, 0002422, 0177035, 0000026, + 0000415, 0000427, 0000567, 0000607, 0000777, 0177751, 0177641, 0177600, + 0000225, 0177624, 0001013, 0000764, 0000431, 0000712, 0000634, 0000735, + 0000611, 0000567, 0000564, 0000566, 0000036, 0000002, 0000003, 0000015, + 0000030, 0000377, 0001000, 0177764, 0000436, 0054731, 0050750, 0020753, + 0040745, 0102460, 0040737, 0020762, 0061004, 0020734, 0105304, 0000406, + 0020743, 0101014, 0014741, 0000772, 0002712, 0034754, 0167700, 0116415, + 0024752, 0021001, 0106414, 0000754, 0021000, 0024703, 0106414, 0000750, + 0021003, 0163400, 0024736, 0106405, 0000404, 0121400, 0101404, 0000740, + 0044714, 0021005, 0042732, 0024664, 0122405, 0000404, 0101405, 0004404, + 0000727, 0010656, 0034654, 0024403, 0120500, 0101404, 0000777, 0040662, + 0040664, 0040664, 0102520, 0061004, 0020655, 0101015, 0000776, 0106415, + 0001400, 0014634, 0000761, 0020673, 0061004, 0000400, 0061005, 0102000, + 0143000, 0034672, 0024667, 0166400, 0061005, 0004670, 0020663, 0034664, + 0164000, 0147000, 0061005, 0024762, 0132414, 0133000, 0020636, 0034416, + 0101015, 0156415, 0131001, 0000754, 0024643, 0044625, 0101015, 0000750, + 0014623, 0004644, 0020634, 0061004, 0002000, 0176764, 0001401, 0041002 +}; + +#if DEBUG_PACKETS +static void dump_ascii(const UINT16 *src, size_t size) +{ + logerror(" ["); + for (size_t offs = 0; offs < size; offs++) { + char ch1 = src[offs] / 256; + char ch2 = src[offs] % 256; + logerror("%c", ch1 < 32 || ch1 > 126 ? '.' : ch1); + logerror("%c", ch2 < 32 || ch2 > 126 ? '.' : ch2); + } + logerror("]\n"); +} + +static void dump_packet(const char* name, const UINT16 *src, size_t addr, size_t size) +{ + size_t offs; + for (offs = 0; offs < size; offs++) { + UINT16 word = src[offs]; + if (offs % 8) { + logerror(" %06o", word); + } else { + if (offs > 0) + dump_ascii(&src[offs-8], 8); + logerror("%s\t%05o: %06o", name, static_cast(addr + offs), word); + } + } + if (offs % 8) { + dump_ascii(&src[offs - (offs % 8)], offs % 8); + } else if (offs > 0) { + dump_ascii(&src[offs - 8], 8); + } +} +#endif + +/** + * @brief check for the various reasons to wakeup the ethernet task + */ +void alto2_cpu_device::eth_wakeup() +{ + register int st = m_eth.status; + LOG((LOG_ETH,0,"IBUSY=%d OBUSY=%d ", GET_ETH_IBUSY(st), GET_ETH_OBUSY(st))); + UINT8 busy = GET_ETH_IBUSY(st) | GET_ETH_OBUSY(st); + if (0 == busy) { + // if not busy, reset the FIFO read and write counters + m_eth.fifo_rd = 0; + m_eth.fifo_wr = 0; + } + + /* + * POST conditions to wakeup the Ether task: + * input data late + * output command + * input command + * output gone + * input gone + */ + if (GET_ETH_IDL(st)) { + LOG((LOG_ETH,0,"POST (input data late)\n")); + m_task_wakeup |= 1 << task_ether; + return; + } + if (GET_ETH_OCMD(st)) { + LOG((LOG_ETH,0,"POST (output command)\n")); + m_task_wakeup |= 1 << task_ether; + return; + } + if (GET_ETH_ICMD(st)) { + LOG((LOG_ETH,0,"POST (input command)\n")); + m_task_wakeup |= 1 << task_ether; + return; + } + if (GET_ETH_OGONE(st)) { + LOG((LOG_ETH,0,"POST (output gone)\n")); + m_task_wakeup |= 1 << task_ether; + return; + } + if (GET_ETH_IGONE(st)) { + LOG((LOG_ETH,0,"POST (input gone)\n")); + m_task_wakeup |= 1 << task_ether; + return; + } + + /** + * IDR (input data ready) conditions to wakeup the Ether task + * signal meaining + * -------------------------------------- + * IBUSY input busy + * BNNE buffer next nearly empty + * BNE buffer nearly empty + * ETAC ether task active + * + ************************************************************ + * +----+ + * BNE' >----|NAND| (i1) +----+ + * | o-------|NAND| (i2) +----+ + * ETAC' >----| | | o-------|NAND| + * +----+ +---| | | o-----> IDR' + * | +----+ +---| | + * +---+ | | +----+ + * BNNE' >----|INVo----+ | + * +---+ | + * | + * IBUSY >--------------------------+ + * + ************************************************************ + */ + UINT8 a49 = m_ether_a49[16 * m_eth.fifo_wr + m_eth.fifo_rd]; + UINT8 ETAC = m_task == task_ether ? 0 : 1; + UINT8 i1 = ~(BNE(a49) & ETAC); + UINT8 i2 = ~(~BNNE(a49) & i1); + UINT8 IDR = ~(GET_ETH_IBUSY(st) & i2); + if (0 == IDR) { + m_task_wakeup |= 1 << task_ether; + LOG((LOG_ETH,0,"IDR (input data ready)\n")); + return; + } + + /** + * ODR (output data ready) conditions to wakeup the Ether task + * signal meaining + * -------------------------------------- + * WLF write latch full(?) + * BF buffer (FIFO) full + * OEOT output end of transmission + * OBUSY output busy + ************************************************************ + * +----+ + * WLF' >----|NAND| (o1) +----+ + * | o---------|NAND| + * BF' >----| | | | + * +----+ +------| o----> ODR' + * | | | + * | +---| | + * OEOT' >------------+ | +----+ + * | + * | + * OBUSY >---------------+ + * + ************************************************************ + */ + UINT8 o1 = ~(~GET_ETH_WLF(st) & BF(a49)); + UINT8 ODR = ~(GET_ETH_OBUSY(st) & ~GET_ETH_OEOT(st) & o1); + if (0 == ODR) { + m_task_wakeup |= 1 << task_ether; + LOG((LOG_ETH,0,"ODR (output data ready)\n")); + return; + } + + /* + * EWFCT (ether wake function) conditions to wakeup the Ether task: + * EWFCT flip flop set by the F1 EWFCT + * The task is activated by the display code together with the + * next wakeup of the memory refresh task (MRT). + */ + if (m_ewfct) { + m_task_wakeup |= 1 << task_ether; + LOG((LOG_ETH,0,"EWFCT (ether wake function)\n")); + return; + } + + // otherwise no more wakeups for the ether task + LOG((LOG_ETH,0,"stop wake\n")); + m_task_wakeup &= ~(1 << task_ether); +} + +/** + * @brief F9401 CRC checker + *
+ *
+ * The F9401 looks similiar to the SN74F401. However, in the schematics
+ * there is a connection from pin 9 (labeled D9) to pin 2 (labeled Q8).
+ * See below for the difference:
+ *
+ *           SN74F401                       F9401
+ *         +---+-+---+                   +---+-+---+
+ *         |   +-+   |                   |   +-+   |
+ *    CP' -|1      14|-  Vcc       CLK' -|1      14|-  Vcc
+ *         |         |                   |         |
+ *     P' -|2      13|-  ER          P' -|2      13|-  CRCZ'
+ *         |         |                   |         |
+ *    S0  -|3      12|-  Q           Z  -|3      12|-  CRCDATA
+ *         |         |                   |         |
+ *    MR  -|4      11|-  D          MR  -|4      11|-  SDI
+ *         |         |                   |         |
+ *    S1  -|5      10|-  CWE         Y  -|5      10|-  SR
+ *         |         |                   |         |
+ *    NC  -|6       9|-  NC         D1  -|6       9|-  D9
+ *         |         |                   |         |
+ *   GND  -|7       8|-  S2        GND  -|7       8|-  X
+ *         |         |                   |         |
+ *         +---------+                   +---------+
+ *
+ * Functional description (SN74F401)
+ *
+ * The 'F401 is a 16-bit programmable device which operates on serial data
+ * streams and provides a means of detecting transmission errors. Cyclic
+ * encoding and decoding schemes for error detection are based on polynomial
+ * manipulation in modulo arithmetic. For encoding, the data stream (message
+ * polynomial) is divided by a selected polynomial. This division results
+ * in a remainder which is appended to the message as check bits. For error
+ * checking, the bit stream containing both data and check bits is divided
+ * by the same selected polynomial. If there are no detectable errors, this
+ * division results in a zero remainder. Although it is possible to choose
+ * many generating polynomials of a given degree, standards exist that
+ * specify a small number of useful polynomials. The 'F401 implements the
+ * polynomials listed in Tabel I by applying the appropriate logic levels
+ * to the select pins S0, S1 and S2.
+ *
+ * The 'F401 consists of a 16-bit register, a Read Only Memory (ROM) and
+ * associated control circuitry as shown in the block diagram. The
+ * polynomial control code presented at inputs S0, S1 and S2 is decoded
+ * by the ROM, selecting the desired polynomial by establishing shift
+ * mode operation on the register with Exclusive OR gates at appropriate
+ * inputs. To generate check bits, the data stream is entered via the
+ * Data inputs (D), using the HIGH-to-LOW transition of the Clock input
+ * (CP'). This data is gated with the most significant output (Q) of
+ * the register, and controls the Exclusive OR gates (Figure 1). The
+ * Check Word Enable (CWE) must be held HIGH while the data is being
+ * entered. After the last data bit is entered, the CWE is brought LOW
+ * and the check bits are shifted out of the register and appended to
+ * the data bits using external gating (Figure 2).
+ *
+ * To check an incoming message for errors, both the data and check bits
+ * are entered through the D input with the CWE input held HIGH. The
+ * 'F401 is not in the data path, but only monitors the message. The
+ * Error output becomes valid after the last check bit has been entered
+ * into the 'F401 by a HIGH-to-LOW transition of CP'. If no detectable
+ * errors have occurred during the transmission, the resultant internal
+ * register bits are all LOW and the Error Output (ER) is LOW.
+ * If a detectable error has occurred, ER is HIGH.
+ *
+ * A HIGH on the Master Reset input (MR) asynchronously clears the
+ * register. A LOW on the Preset input (P') asynchronously sets the
+ * entire register if the control code inputs specify a 16-bit
+ * polynomial; in the case of 12- or 8-bit check polynomials only the
+ * most significant 12 or 8 register bits are set and the remaining
+ * bits are cleared.
+ *
+ * [Table I]
+ *
+ * S2 S1 S0 polynomial                      remarks
+ * ----------------------------------------------------------------
+ * L  L  L  x^16+x^15+x^2+1                 CRC16
+ * L  L  H  x^16+x^14+x+1                   CRC16 reverse
+ * L  H  L  x^16+x^15+x^13+x^7+x^4+x^2+x+1  -/-
+ * L  H  H  x^12+x^11+x^3+x^2+x+1           CRC-12
+ * H  L  L  x^8+x^7+x^5+x^4+x+1             -/-
+ * H  L  H  x^8+1                           LRC-8
+ * H  H  L  X^16+x^12+x^5+1                 CRC-CCITT
+ * H  H  H  X^16+x^11+x^4+1                 CRC-CCITT reverse
+ *
+ * 
+ * The Alto ethernet interface seems to be using the last one of the polynomials, + * or perhaps something entirely different? + * + * TODO: verify polynomial generator; build a lookup table to make it faster. + * + * @param crc previous CRC value + * @param data 16 bit data + * @return new CRC value after 16 bits + */ +UINT32 f9401_7(UINT32 crc, UINT32 data) +{ + static const UINT32 XOR = (1 << 10) | (1 << 3) | (1 << 0); + crc ^= data; + for (int i = 0; i < 16; i++) + crc = (crc >> 1) ^ ((crc & 1) ? XOR : 0); + return crc & 0177777; +} + +/** + * @brief HACK: pull the next word from the breath_of_life_data in the fifo + * + * This is probably lacking the updates to one or more of + * the status flip flops. + */ +void alto2_cpu_device::rx_breath_of_life(void* ptr, INT32 arg) +{ + UINT32 data; + + if (arg == 0) { + // on the first word set the IBUSY flip flop + PUT_ETH_IBUSY(m_eth.status, 1); + m_eth.rx_count = 0; + } + + if (arg >= BREATHLEN) { + // CRC after the data + data = m_eth.rx_crc; + arg++; + } else { + // next data word + data = breath_of_life_data[arg++]; + } + m_eth.rx_crc = f9401_7(m_eth.rx_crc, data); + m_eth.fifo[m_eth.fifo_wr] = data; + m_eth.fifo_wr = (m_eth.fifo_wr + 1) % ALTO2_ETHER_FIFO_SIZE; + + PUT_ETH_IT(m_eth.status, 1); // set IT (input shift register full ...)? + + UINT8 a49 = m_ether_a49[16 * m_eth.fifo_wr + m_eth.fifo_rd]; + if (0 == BF(a49)) + PUT_ETH_IDL(m_eth.status, 1); // fifo is overrun: set input data late flip flop + + if (arg > BREATHLEN) { + /* + * TODO: if data comes from some other source, + * compare our CRC with the next word received + * and set the CRC error flag if they differ. + */ + m_eth.rx_crc = 0; + PUT_ETH_IGONE(m_eth.status, 1); // set the IGONE flip flop + m_eth.rx_timer->adjust(attotime::from_seconds(m_eth.breath_of_life), 0); + } else { + // receive at a rate of 5.44us per word + m_eth.rx_timer->adjust(attotime::from_usec(5.44), arg); + } + eth_wakeup(); +} + +/** + * @brief transmit data from the FIFO to + * + * @param ptr unused pointer + * @param arg word count if >= 0, -1 if CRC is to be transmitted (last word) + */ +void alto2_cpu_device::tx_packet(void* ptr, INT32 arg) +{ + UINT32 data; + + // the last word sent is the CRC + if (-1 == arg) { + m_eth.tx_timer->reset(); + LOG((LOG_ETH,0," CRC:%06o\n", m_eth.tx_crc)); + // TODO: send the CRC as final word of the packet + m_eth.tx_crc = 0; + PUT_ETH_OGONE(m_eth.status, 1); // set the OGONE flip flop + eth_wakeup(); + return; + } + + data = m_eth.fifo[m_eth.fifo_rd]; + m_eth.tx_crc = f9401_7(m_eth.tx_crc, data); + m_eth.fifo_rd = (m_eth.fifo_rd + 1) % ALTO2_ETHER_FIFO_SIZE; + + UINT8 a49 = m_ether_a49[16 * m_eth.fifo_wr + m_eth.fifo_rd]; + if (0 == BE(a49)) { + // the FIFO is empty now: clear the OBUSY and WLF flip flops + PUT_ETH_OBUSY(m_eth.status, 0); + PUT_ETH_WLF(m_eth.status, 0); + m_eth.tx_timer->adjust(attotime::from_usec(5.44), -1); + } else { + // transmit the next word after 5.44us + m_eth.tx_timer->adjust(attotime::from_usec(5.44), arg + 1); + } + eth_wakeup(); +} + +/** + * @brief ethernet start function - called from the emulator task + */ +void alto2_cpu_device::eth_startf() +{ +#if 0 // FIXME: does not yet work + for (int sysclk = 0; sysclk < 2; sysclk++) + update_sysclk(sysclk); + PUT_ETH_OCMD(m_eth.status, m_eth.ff_35a & JKFF_Q ? 1 : 0); + PUT_ETH_ICMD(m_eth.status, m_eth.ff_35b & JKFF_Q ? 1 : 0); +#else + PUT_ETH_ICMD(m_eth.status, X_BIT(m_bus,16,14)); + PUT_ETH_OCMD(m_eth.status, X_BIT(m_bus,16,15)); +#endif + LOG((LOG_ETH,3, " STARTF; ICMD=%u OCMD=%u\n", GET_ETH_ICMD(m_eth.status), GET_ETH_ICMD(m_eth.status))); + eth_wakeup(); +} + +/** + * @brief ethernet input data function + * + * Gates the contents of the FIFO to BUS[0-15], and increments + * the read pointer at the end of the cycle. + */ +void alto2_cpu_device::bs_early_eidfct() +{ + UINT16 r = m_eth.fifo[m_eth.fifo_rd]; + LOG((LOG_ETH,3, " <-EIDFCT; pull %06o from FIFO[%02o]\n", r, m_eth.fifo_rd)); + m_eth.fifo_rd = (m_eth.fifo_rd + 1) % ALTO2_ETHER_FIFO_SIZE; + m_bus &= r; + +#if DEBUG_PACKETS + if (m_eth.rx_count < ALTO2_ETHER_PACKET_SIZE) + m_eth.rx_packet[m_eth.rx_count] = r; + m_eth.rx_count++; + if (ALTO2_ETHER_PACKET_SIZE == m_eth.rx_count) { + dump_packet("RX", m_eth.rx_packet, 0, m_eth.rx_count); + m_eth.rx_count = 0; + } +#endif + eth_wakeup(); +} + +/** + * @brief block the ethernet task + */ +void alto2_cpu_device::f1_early_eth_block() +{ + LOG((LOG_ETH,2," BLOCK %s\n", task_name(m_task))); + m_task_wakeup &= ~(1 << task_ether); +} + +/** + * @brief ethernet input look function + * + * Gates the contents of the FIFO to BUS[0-15], but does not + * increment the read pointer + */ +void alto2_cpu_device::f1_early_eilfct() +{ + UINT16 r = m_eth.fifo[m_eth.fifo_rd]; + LOG((LOG_ETH,3, " <-EILFCT; %06o at FIFO[%02o]\n", r, m_eth.fifo_rd)); + m_bus &= r; +} + +/** + * @brief ethernet post function + * + * Gates the interface status to BUS[8-15]. Resets the interface + * at the end of the function. + * + * The schematics suggest that just BUS[10-15] is modified. + * + * Also a comment from the microcode suggests this: + *
+ * ;Ether Post Function - EPFCT.  Gate the hardware status
+ * ;(LOW TRUE) to Bus [10:15], reset interface.
+ *
+ */ +void alto2_cpu_device::f1_early_epfct() +{ + UINT16 r = 0177777; + UINT16 st = m_eth.status; + m_eth.status = 0; + m_eth.tx_count = 0; + + X_WRBITS(r,16,10,10,~GET_ETH_IDL(st)); // BUS[10] = IDL (input data late) + X_WRBITS(r,16,11,11,~GET_ETH_COLL(st)); // BUS[11] = COLL (collision) + X_WRBITS(r,16,12,12,~GET_ETH_CRC(st)); // BUS[12] = CRC (CRC error) + X_WRBITS(r,16,13,13,~GET_ETH_ICMD(st)); // BUS[13] = ICMD (input command) + X_WRBITS(r,16,14,14,~GET_ETH_OCMD(st)); // BUS[13] = OCMD (output command) + X_WRBITS(r,16,15,15,~GET_ETH_IT(st)); // BUS[13] = IT (input ???) + m_bus &= r; + + LOG((LOG_ETH,3, " <-EPFCT; BUS[8-15] = STATUS (%#o)\n", r)); + LOG((LOG_ETH,5, " IDL' : %u\n", GET_ETH_IDL(r))); + LOG((LOG_ETH,5, " COLL' : %u\n", GET_ETH_COLL(r))); + LOG((LOG_ETH,5, " CRC' : %u\n", GET_ETH_CRC(r))); + LOG((LOG_ETH,5, " ICMD' : %u\n", GET_ETH_ICMD(r))); + LOG((LOG_ETH,5, " OCMD' : %u\n", GET_ETH_OCMD(r))); + LOG((LOG_ETH,5, " IT' : %u\n", GET_ETH_IT(r))); + eth_wakeup(); +} + +/** + * @brief ethernet countdown wakeup function + * + * Sets a flip flop in the interface that will cause a wakeup to the + * Ether task on the next tick of SWAKMRT (memory refresh task). + * This function must be issued in the instruction after a TASK. + * The resulting wakeup is cleared when the Ether task next runs. + */ +void alto2_cpu_device::f1_late_ewfct() +{ + /* + * Set a flag in the CPU to handle the next task switch + * to the task_mrt by also waking up the task_ether. + */ + m_ewfct = m_ether_enable; +} + +/** + * @brief ethernet output data function + * + * Loads the FIFO from BUS[0-15], then increments the write + * pointer at the end of the cycle. + * + * Comment from the micro code: + *
+ * Ether Output Data Function - EODFCT.  Copy the bus into the
+ * interface data buffer, increment the write pointer, clears wakeup
+ * request if the buffer is now nearly full (one slot available).
+ *
+ */ +void alto2_cpu_device::f2_late_eodfct() +{ + LOG((LOG_ETH,3, " EODFCT<-; push %06o into FIFO[%02o]\n", m_bus, m_eth.fifo_wr)); + m_eth.fifo[m_eth.fifo_wr] = m_bus; + m_eth.fifo_wr = (m_eth.fifo_wr + 1) % ALTO2_ETHER_FIFO_SIZE; + +#if DEBUG_PACKETS + if (m_eth.tx_count < ALTO2_ETHER_PACKET_SIZE) + m_eth.tx_packet[m_eth.tx_count] = m_bus; + m_eth.tx_count++; + if (ALTO2_ETHER_PACKET_SIZE == m_eth.tx_count) { + dump_packet("TX", m_eth.tx_packet, 0, m_eth.tx_count); + m_eth.tx_count = 0; + } +#endif + + PUT_ETH_WLF(m_eth.status, 1); // set WLF (write latch full) + PUT_ETH_OBUSY(m_eth.status, 1); // set OBUSY (output busy) + eth_wakeup(); + // if the FIFO is full, stop wakeup and kick off the timer + UINT8 a49 = m_ether_a49[16 * m_eth.fifo_wr + m_eth.fifo_rd]; + if (0 == BF(a49)) { + m_task_wakeup &= ~(1 << task_ether); + m_eth.tx_timer->adjust(attotime::from_usec(5.44), 0); + } +} + +/** + * @brief ethernet output start function + * + * Sets the OBUSY flip flop in the interface, starting data + * wakeups to fill the FIFO for output. When the FIFO is full, + * or EEFCT has been issued, the interface will wait for silence + * on the Ether and begin transmitting. + */ +void alto2_cpu_device::f2_late_eosfct() +{ + LOG((LOG_ETH,3, " EOSFCT\n")); + PUT_ETH_WLF(m_eth.status, 1); + PUT_ETH_OBUSY(m_eth.status, 1); + eth_wakeup(); +} + +/** + * @brief ethernet reset branch function + * + * This command dispatch function merges the ICMD and OCMD flip flops + * into NEXT[6-7]. These flip flops are the means of communication + * between the emulator task and the ethernet task. The emulator + * task sets them up from BUS[14-15] with the STARTF function, + * causing the ethernet task to wakeup, dispatch on them and then + * reset them with EPFCT. + */ +void alto2_cpu_device::f2_late_erbfct() +{ + UINT16 r = 0; + X_WRBITS(r,10,6,6,GET_ETH_ICMD(m_eth.status)); + X_WRBITS(r,10,7,7,GET_ETH_OCMD(m_eth.status)); + LOG((LOG_ETH,3, " ERBFCT; NEXT[6-7] = ICMD,OCMD (%#o | %#o)\n", m_next2, r)); + m_next2 |= r; + eth_wakeup(); +} + +/** + * @brief ethernet end of transmission function + * + * This function is issued when all of the main memory output buffer + * has been transferred to the FIFO. EEFCT disables further data + * wakeups. + */ +void alto2_cpu_device::f2_late_eefct() +{ + PUT_ETH_OBUSY(m_eth.status, 1); + PUT_ETH_OEOT(m_eth.status, 1); + // end transmitting the packet + m_eth.tx_timer->adjust(attotime::from_usec(5.44), -1); + eth_wakeup(); +} + +/** + * @brief ethernet branch function + * + * ORs a 1 into NEXT[6] if a collision is detected. + * ORs a 1 into NEXT[7] if + * an input data late is detected, + * or a SIO with AC0[14-15] non-zero is issued (ICMD or OCMD), + * or if the receiver is gone (IGONE) + * or if the transmitter is gone (OGONE). + */ +void alto2_cpu_device::f2_late_ebfct() +{ + UINT16 r = 0; + X_WRBITS(r,10,6,6, GET_ETH_COLL(m_eth.status)); + X_WRBITS(r,10,7,7, + GET_ETH_IDL(m_eth.status) | + GET_ETH_ICMD(m_eth.status) | + GET_ETH_OCMD(m_eth.status) | + GET_ETH_IGONE(m_eth.status) | + GET_ETH_OGONE(m_eth.status)); + LOG((LOG_ETH,3, " EBFCT; NEXT ... (%#o | %#o)\n", m_next2, r)); + m_next2 |= r; +} + +/** + * @brief ethernet countdown branch function + * + * The BE' (buffer empty) signal is output D0 of PROM a49 + * ORs a one into NEXT[7] if the FIFO is not empty. + */ +void alto2_cpu_device::f2_late_ecbfct() +{ + UINT16 r = 0; + UINT8 a49 = m_ether_a49[16 * m_eth.fifo_wr + m_eth.fifo_rd]; + X_WRBITS(r,10,7,7,~BE(a49)); + LOG((LOG_ETH,3, " ECBFCT; NEXT[7] = FIFO %sempty (%#o | %#o)\n", r ? "not " : "is ", m_next2, r)); + m_next2 |= r; +} + +/** + * @brief ethernet input start function + * + * Sets the IBUSY flip flop in the interface, causing it to hunt + * for the beginning of a packet: silence on the Ether followed + * by a transition. When the interface has collected two words, + * it will begin generating data wakeups to the microcode. + */ +void alto2_cpu_device::f2_late_eisfct() +{ + LOG((LOG_ETH,3, " EISFCT\n")); + PUT_ETH_IBUSY(m_eth.status, 1); + eth_wakeup(); +} + +/** @brief called by the CPU when the ethernet task becomes active + * + * Reset the Ether wake flip flop + */ +void alto2_cpu_device::activate_eth() +{ + m_ewfct = 0; +} + +/** + * @brief update the ethernet circuit JK flip-flops that depend on SYSCLK + * @param sysclk current SYSCLK level 0 or 1 + */ +void alto2_cpu_device::update_sysclk(int sysclk) +{ + UINT8 s0, s1; + + /* + * JK flip-flop 35a (SIO' and SYSCLK clocked) + * (Sheet 7) + * + * Note: SIO is the emulator F1 STARTF + * + * CLK (SIO & SYSCLK)' + * J BUS[15] + * K' 1 + * S' 1 + * C' ERESET' + * Q OCMD + * Q' OCMD' + */ + s0 = m_eth.ff_35a; + s1 = (m_d_f1 == f1_emu_startf && sysclk) ? JKFF_CLK : JKFF_0; + if (X_BIT(m_bus,16,15)) + s1 |= JKFF_J; + s1 |= JKFF_K; + s1 |= JKFF_C; // ERESET' not now + m_eth.ff_35a = update_jkff(s0, s1, "35a OCMD "); + + /* + * JK flip-flop 35b (SIO' and SYSCLK clocked) + * (Sheet 7) + * + * Note: SIO is the emulator F1 STARTF + * + * CLK (SIO & SYSCLK)' + * J BUS[14] + * K' 1 + * S' 1 + * C' ERESET' + * Q ICMD + * Q' ICMD' + */ + s0 = m_eth.ff_35b; + s1 = (m_d_f1 == f1_emu_startf && sysclk) ? JKFF_CLK : JKFF_0; + if (X_BIT(m_bus,16,14)) + s1 |= JKFF_J; + s1 |= JKFF_K; + s1 |= JKFF_C; // ERESET' not now + m_eth.ff_35b = update_jkff(s0, s1, "35b ICMD "); + + /* + * JK flip-flop 10a IBUSY (Sheet 13) + * + * CLK SYSCLK' + * J 0 + * K' EISFCT' + * S' ERESET' + * C' 1 + * Q IBUSY' + * Q' IBUSY + */ + s0 = m_eth.ff_10a; + s1 = sysclk ? JKFF_CLK : JKFF_0; + if (m_d_f2 != f2_ether_eisfct) + s1 |= JKFF_K; + s1 |= JKFF_C; + m_eth.ff_10a = update_jkff(s0, s1, "10a IBUSY "); + + /* + * DEMUX 74S157 76 + * 1A (SYSCLK & EODFCT)' + * 2A OSLOAD' + * 3A OSLOAD + * 4A (SYSCLK & EODFCT)' + * 1B ISRFULL + * 2B (SYSCLK & EIDFCT)' + * 3B EILDFCTA = (EIDFCT' & EILFCT')' + * 4B WLF' + * SEL IBUSY + * 1Y WLLOAD + * 2Y RDCNT' + * 3Y RR + * 4Y WLL' + */ + UINT8 WLLOAD; + UINT8 RDCNT0; + UINT8 RR; + UINT8 WLL0; + if (m_eth.ff_10a & JKFF_Q) { + WLLOAD = ~(sysclk & (m_d_f2 == f2_ether_eodfct)) & 1; + RDCNT0 = m_eth.ff_52b & JKFF_Q ? 1 : 0; + RR = m_eth.ff_52b & JKFF_Q0 ? 1 : 0; + WLL0 = ~(sysclk & (m_d_f2 == f2_ether_eodfct)) & 1; + } else { + // ISRFULL + WLLOAD = (m_eth.serin >> 1) & 1; + RDCNT0 = ~(sysclk & (m_d_bs == bs_ether_eidfct)) & 1; + RR = m_d_bs == bs_ether_eidfct || m_d_f1 == f1_ether_eilfct; + WLL0 = m_eth.ff_77b & JKFF_Q0 ? 1 : 0; + } + // TODO: use the signals + (void)RDCNT0; + (void)RR; + (void)WLL0; + + /* + * JK flip-flop 10b OBUSY (Sheet 13) + * + * CLK SYSCLK' + * J 0 + * K' EOSFCT' + * S' ERESET' + * C' 1 + * Q OBUSY' + * Q' OBUSY + */ + s0 = m_eth.ff_10b; + s1 = sysclk ? JKFF_CLK : JKFF_0; + if (m_d_f2 != f2_ether_eosfct) + s1 |= JKFF_K; + m_eth.ff_10b = update_jkff(s0, s1, "10b OBUSY "); + + /* + * JK flip-flop 51a EWFCT latch (Sheet 19) + * + * CLK SYSCLK' + * J OCDW + * K' EWFCT' + * S' ERESET' + * C' 1 + * Q EWFCT latch(?) + * Q' --- + */ + s0 = m_eth.ff_51a; + s1 = sysclk ? JKFF_CLK : JKFF_0; + m_eth.ff_51a = update_jkff(s0, s1, "51a EWFCT_L "); + + /* + * JK flip-flop 31b OEOT (Sheet 19) + * + * CLK SYSCLK' + * J 0 + * K' EEFCT' + * S' ERESET' + * C' 1 + * Q OEOT' + * Q' --- + */ + s0 = m_eth.ff_31b; + s1 = sysclk ? JKFF_CLK : JKFF_0; + m_eth.ff_31b = update_jkff(s0, s1, "31b OEOT "); + + /* + * JK flip-flop 69a IT (Sheet 14) + * + * CLK ARC' + * J (BNE & ILOC & IMID & WR') + * K' 1 + * S' 1 + * C' ERESET' + * Q INGONE + * Q' INGONE' + */ + s0 = m_eth.ff_69a; + s1 = JKFF_CLK; + m_eth.ff_69a = update_jkff(s0, s1, "69a IT "); + + /* + * JK flip-flop 65a IDL (Sheet 10) + * + * CLK ARC' + * J 65b Q + * K' 1 + * S' 1 + * C' ERESET' + * Q IDL + * Q' IDL' + */ + s0 = m_eth.ff_65a; + s1 = JKFF_CLK; + m_eth.ff_65a = update_jkff(s0, s1, "65a IDL "); + + /* + * JK flip-flop 65b IO (Sheet 10) + * + * CLK ISRFULL + * J WLF + * K' 1 + * S' 1 + * C' ERESET + * Q to 65a J + * Q' --- + */ + s0 = m_eth.ff_65b; + s1 = JKFF_CLK; + m_eth.ff_65b = update_jkff(s0, s1, "65b IO "); + + /* + * JK flip-flop 77b WLF (Sheet 10) + * + * CLK WLLOAD + * J 1 + * K' 1 + * S' 1 + * C' (BUSY | WE') + * Q WLF + * Q' WLF' + */ + s0 = m_eth.ff_77b; + s1 = WLLOAD ? JKFF_CLK : JKFF_0; + m_eth.ff_77b = update_jkff(s0, s1, "77b WLF "); + + /* + * JK flip-flop 77a WR (Sheet 10) + * + * CLK ARC' + * J RW' + * K' (WLF & BF')' + * S' BUSY + * C' 1 + * Q WR' + * Q' WR + */ + s0 = m_eth.ff_77a; + s1 = JKFF_CLK; + if (m_eth.ff_77b) + m_eth.ff_77a = update_jkff(s0, s1, "77a WR "); + + /* + * JK flip-flop 69b INON (Sheet 14) + * + * CLK ARC' + * J CARRIER' + * K' (IMID' & ILOC)' + * S' 1 + * C' IBUSY + * Q INON + * Q' INON' + */ + s0 = m_eth.ff_69b; + s1 = JKFF_CLK; + m_eth.ff_69b = update_jkff(s0, s1, "69b INON "); + + /* + * JK flip-flop 70b ILOC (Sheet 14) + * + * CLK CARRIER' + * J 1 + * K' 1 + * S' 1 + * C' INON + * Q ILOC + * Q' ILOC' + */ + s0 = m_eth.ff_70b; + s1 = JKFF_CLK; + m_eth.ff_70b = update_jkff(s0, s1, "70b ILOC "); + + /* + * JK flip-flop 51b OCDW (Sheet 19) + * + * CLK ARC' + * J (EWFCT latch | SWAKMRT')' + * K' ETAC' + * S' 1 + * C' ERESET' + * Q OCDW + * Q' OCDW' + */ + s0 = m_eth.ff_51b; + s1 = JKFF_CLK; + m_eth.ff_51b = update_jkff(s0, s1, "51b OCDW "); + + /* + * JK flip-flop 21a OUTON (Sheet 19) + * + * CLK OTHER' + * J OUTON + * K' 1 + * S' 1 + * C' OBUSY + * Q to FF 21b J and K' + * Q' --- + */ + s0 = m_eth.ff_21a; + s1 = JKFF_CLK; + m_eth.ff_21a = update_jkff(s0, s1, "21a OUTON "); + + /* + * JK flip-flop 21b COLL (Sheet 19) + * + * CLK ARC' + * J from FF 21a Q + * K' dito + * S' 1 + * C' OBUSY + * Q COLL + * Q' COLL' + */ + s0 = m_eth.ff_21b; + s1 = JKFF_CLK; + m_eth.ff_21b = update_jkff(s0, s1, "21b COLL "); + + /* + * JK flip-flop 31a OUTGONE (Sheet 19) + * + * CLK OUTON' + * J 1 + * K' 1 + * S' 1 + * C' OBUSY + * Q OUTGONE + * Q' OUTGONE' + */ + s0 = m_eth.ff_31a; + s1 = JKFF_CLK; + m_eth.ff_31a = update_jkff(s0, s1, "31a OUTGONE "); +} + +/** + * @brief update the ethernet circuit JK flip-flops that depend on RCLK + * @param rclk current RCLK level 0 or 1 + */ +void alto2_cpu_device::update_rclk(int rclk) +{ + UINT8 s0, s1; + + /* + * JK flip-flop 70a IMID (Sheet 14) + * + * CLK RCLK + * J ISR00 + * K' 1 + * S' 1 + * C' INON + * Q IMID + * Q' IMID' + */ + s0 = m_eth.ff_70a; + s1 = rclk ? JKFF_CLK : JKFF_0; + m_eth.ff_70a = update_jkff(s0, s1, "70a IMID "); + + /* + * JK flip-flop 47a OUTON (Sheet 15) + * + * CLK RCLK + * J (ISR15 | ISRFULL)' + * K' dito + * S' INON + * C' 1 + * Q --- + * Q' ISR14 + */ + s0 = m_eth.ff_47a; + s1 = rclk ? JKFF_CLK : JKFF_0; + m_eth.ff_47a = update_jkff(s0, s1, "47a ISR14 "); + + /* + * JK flip-flop 47b COLL (Sheet 15) + * + * CLK RCLK + * J RDATA + * K' dito + * S' 1 + * C' INON + * Q ISR15 + * Q' --- + */ + s0 = m_eth.ff_47b; + s1 = rclk ? JKFF_CLK : JKFF_0; + m_eth.ff_47b = update_jkff(s0, s1, "47b ISR15 "); +} + +/** + * @brief update the ethernet circuit JK flip-flops that depend on TCLK + * @param tclk current TCLK level 0 or 1 + */ +void alto2_cpu_device::update_tclk(int tclk) +{ + UINT8 s0, s1; + + /* + * JK flip-flop 52b OSLOAD (Sheet 17) + * + * CLK TCLK' + * J PROM a42 O2 + * K' dito + * S' 1 + * C' 1 + * Q OSLOAD' + * Q' OSLOAD + */ + s0 = m_eth.ff_52b; + s1 = tclk ? JKFF_0 : JKFF_CLK; + m_eth.ff_52b = update_jkff(s0, s1, "52b OSLOAD "); + + /* + * JK flip-flop 61a CRCGO (Sheet 21) + * + * CLK TCLK' + * J (OSLOAD & BE) + * K' 1 + * S' 1 + * C' OUTEND' + * Q CRCGO + * Q' CRCGO' + */ + s0 = m_eth.ff_61a; + s1 = tclk ? JKFF_0 : JKFF_CLK; + m_eth.ff_61a = update_jkff(s0, s1, "61a CRCGO "); + + /* + * JK flip-flop 61b OUTRGO (Sheet 21) + * + * CLK TCLK' + * J OUTGO + * K' dito + * S' 1 + * C' OUTEND' + * Q OUTRGO + * Q' --- + */ + s0 = m_eth.ff_61b; + s1 = tclk ? JKFF_0 : JKFF_CLK; + m_eth.ff_61b = update_jkff(s0, s1, "61b OUTRGO "); + + /* + * JK flip-flop 62a OUTGO (Sheet 21) + * + * CLK TCLK' + * J OUTON + * K' 1 + * S' 1 + * C' OUTEND' + * Q OUTGO + * Q' --- + */ + s0 = m_eth.ff_62a; + s1 = tclk ? JKFF_0 : JKFF_CLK; + m_eth.ff_62a = update_jkff(s0, s1, "62a OUTGO "); + + /* + * JK flip-flop 62b OUTON (Sheet 21) + * + * CLK TCLK' + * J (FEOT' | OOK')' + * K' (CRCGO & OSLOAD)' + * S' 1 + * C' PESTOP' + * Q OUTON + * Q' OUTON' + */ + s0 = m_eth.ff_62b; + s1 = tclk ? JKFF_0 : JKFF_CLK; + m_eth.ff_62b = update_jkff(s0, s1, "62b OUTON "); +} + + +/** + * @brief ethernet task slot initialization + */ +void alto2_cpu_device::init_ether(int task) +{ + // intialize all ethernet variables + memset(&m_eth, 0, sizeof(m_eth)); + save_item(NAME(m_eth.fifo)); + save_item(NAME(m_eth.fifo_rd)); + save_item(NAME(m_eth.fifo_wr)); + save_item(NAME(m_eth.status)); + save_item(NAME(m_eth.rx_crc)); + save_item(NAME(m_eth.tx_crc)); + save_item(NAME(m_eth.rx_count)); + save_item(NAME(m_eth.tx_count)); + save_item(NAME(m_eth.breath_of_life)); + + m_ether_a41 = prom_load(machine(), &pl_enet_a41, memregion("ether_a41")->base()); + m_ether_a42 = prom_load(machine(), &pl_enet_a42, memregion("ether_a42")->base()); + m_ether_a49 = prom_load(machine(), &pl_enet_a49, memregion("ether_a49")->base()); + + set_bs(task, bs_ether_eidfct, &alto2_cpu_device::bs_early_eidfct, 0); + + set_f1(task, f1_block, &alto2_cpu_device::f1_early_eth_block, 0); + set_f1(task, f1_ether_eilfct, &alto2_cpu_device::f1_early_eilfct, 0); + set_f1(task, f1_ether_epfct, &alto2_cpu_device::f1_early_epfct, 0); + set_f1(task, f1_ether_ewfct, 0, &alto2_cpu_device::f1_late_ewfct); + + set_f2(task, f2_ether_eodfct, 0, &alto2_cpu_device::f2_late_eodfct); + set_f2(task, f2_ether_eosfct, 0, &alto2_cpu_device::f2_late_eosfct); + set_f2(task, f2_ether_erbfct, 0, &alto2_cpu_device::f2_late_erbfct); + set_f2(task, f2_ether_eefct, 0, &alto2_cpu_device::f2_late_eefct); + set_f2(task, f2_ether_ebfct, 0, &alto2_cpu_device::f2_late_ebfct); + set_f2(task, f2_ether_ecbfct, 0, &alto2_cpu_device::f2_late_ecbfct); + set_f2(task, f2_ether_eisfct, 0, &alto2_cpu_device::f2_late_eisfct); + + m_active_callback[task] = &alto2_cpu_device::activate_eth; + + m_eth.rx_packet = auto_alloc_array(machine(), UINT16, sizeof(UINT16)*ALTO2_ETHER_PACKET_SIZE); + m_eth.tx_packet = auto_alloc_array(machine(), UINT16, sizeof(UINT16)*ALTO2_ETHER_PACKET_SIZE); + + m_eth.tx_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(alto2_cpu_device::tx_packet),this)); + m_eth.tx_timer->reset(); + + m_eth.rx_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(alto2_cpu_device::rx_breath_of_life),this)); + m_eth.rx_timer->reset(); +} + +void alto2_cpu_device::exit_ether() +{ + // nothing to do yet +} + +//! delay between two breath_of_lifes in seconds +static const int breath_of_life_sec[8] = { + 0, 5, 10, 15, 30, 60, 90, 120 +}; +void alto2_cpu_device::reset_ether() +{ + memset(m_eth.fifo, 0, sizeof(m_eth.fifo)); + m_eth.fifo_rd = 0; + m_eth.fifo_wr = 0; + m_eth.status = 0; + m_eth.rx_crc = 0; + m_eth.tx_crc = 0; + m_eth.rx_count = 0; + m_eth.tx_count = 0; + m_eth.breath_of_life = 0; + m_eth.rx_timer->reset(); + m_eth.tx_timer->reset(); + ioport_port* config = ioport(":CONFIG"); + // config should be valid, unless the driver doesn't define it + if (config) + m_eth.breath_of_life = breath_of_life_sec[(config->read() >> 4) & 7]; + logerror("Ethernet breath_of_life %d sec\n", m_eth.breath_of_life); + if (m_eth.breath_of_life) + m_eth.rx_timer->adjust(attotime::from_seconds(m_eth.breath_of_life), 0); +} diff --git a/src/devices/cpu/alto2/a2ether.h b/src/devices/cpu/alto2/a2ether.h new file mode 100644 index 00000000000..6bdbd24ce3e --- /dev/null +++ b/src/devices/cpu/alto2/a2ether.h @@ -0,0 +1,116 @@ +// license:BSD-3-Clause +// copyright-holders:Juergen Buchmueller +/***************************************************************************** + * + * Xerox AltoII ethernet task (ETHER) + * + *****************************************************************************/ +#ifdef ALTO2_DEFINE_CONSTANTS + +#define ALTO2_ETHER_FIFO_SIZE 16 //!< number of words in the ethernet FIFO +#define ALTO2_ETHER_PACKET_SIZE 0400 //!< size of a packet in words + +#else // ALTO2_DEFINE_CONSTANTS +#ifndef _A2ETHER_H_ +#define _A2ETHER_H_ +//! BUS source for ethernet task +enum { + bs_ether_eidfct = bs_task_3 //!< ethernet task: Ethernet input data function +}; + +//! F1 functions for ethernet task +enum { + f1_ether_eilfct = f1_task_13, //!< f1 (1011): ethernet input look function + f1_ether_epfct = f1_task_14, //!< f1 (1100): ethernet post function + f1_ether_ewfct = f1_task_15 //!< f1 (1101): ethernet countdown wakeup function +}; + +//! F2 functions for ethernet task +enum { + f2_ether_eodfct = f2_task_10, //!< f2 (1000): ethernet output data function + f2_ether_eosfct = f2_task_11, //!< f2 (1001): ethernet output start function + f2_ether_erbfct = f2_task_12, //!< f2 (1010): ethernet reset branch function + f2_ether_eefct = f2_task_13, //!< f2 (1011): ethernet end of transmission function + f2_ether_ebfct = f2_task_14, //!< f2 (1100): ethernet branch function + f2_ether_ecbfct = f2_task_15, //!< f2 (1101): ethernet countdown branch function + f2_ether_eisfct = f2_task_16 //!< f2 (1110): ethernet input start function + //!< f2 (1111): undefined +}; + +UINT8* m_ether_a41; //!< BPROM; P3601-1; 256x4; enet.a41 "PE1" +UINT8* m_ether_a42; //!< BPROM; P3601-1; 256x4; enet.a42 "PE2" +UINT8* m_ether_a49; //!< BPROM; P3601-1; 265x4 enet.a49 "AFIFO" +enum { + ether_a49_BE = (1 << 0), //!< buffer empty + ether_a49_BNE = (1 << 1), //!< buffer next empty + ether_a49_BNNE = (1 << 2), //!< buffer next next empty + ether_a49_BF = (1 << 3) //!< buffer full +}; + +struct { + UINT32 serin; //!< serial input shift registers 74164 #37 and #33 + UINT16 fifo[ALTO2_ETHER_FIFO_SIZE]; //!< FIFO buffer + UINT16 fifo_rd; //!< FIFO input pointer + UINT16 fifo_wr; //!< FIFO output pointer + UINT16 status; //!< status word + UINT16 rx_crc; //!< receiver CRC + UINT16 tx_crc; //!< transmitter CRC + UINT32 rx_count; //!< received words count + UINT32 tx_count; //!< transmitted words count + UINT16* rx_packet; //!< buffer to collect received words + UINT16* tx_packet; //!< buffer to collect transmitted words + emu_timer* rx_timer; //!< receiver timer + emu_timer* tx_timer; //!< transmitter timer + jkff_t ff_10a; //!< JK flip-flop 10a IBUSY (Sheet 13) + jkff_t ff_10b; //!< JK flip-flop 10b OBUSY (Sheet 13) + jkff_t ff_21a; //!< JK flip-flop 21a OUTON (Sheet 19) + jkff_t ff_21b; //!< JK flip-flop 21b COLL (Sheet 19) + jkff_t ff_31a; //!< JK flip-flop 31a OUTGONE (Sheet 19) + jkff_t ff_31b; //!< JK flip-flop 31b OEOT (Sheet 19) + jkff_t ff_35a; //!< JK flip-flop 35a OCMD (Sheet 7) + jkff_t ff_35b; //!< JK flip-flop 35b ICMD (Sheet 7) + jkff_t ff_47a; //!< JK flip-flop 47a ISR14 (Sheet 15) + jkff_t ff_47b; //!< JK flip-flop 47b ISR15 (Sheet 15) + jkff_t ff_51a; //!< JK flip-flop 51a EWFCT latch (Sheet 19) + jkff_t ff_51b; //!< JK flip-flop 51b OCDW (Sheet 19) + jkff_t ff_52b; //!< JK flip-flop 52b OSLOAD (Sheet 17) + jkff_t ff_61a; //!< JK flip-flop 61a CRCGO (Sheet 21) + jkff_t ff_61b; //!< JK flip-flop 61b OUTRGO (Sheet 21) + jkff_t ff_62a; //!< JK flip-flop 62a OUTON (Sheet 21) + jkff_t ff_62b; //!< JK flip-flop 62b OUTGO (Sheet 21) + jkff_t ff_65a; //!< JK flip-flop 65a IDL (Sheet 10) + jkff_t ff_65b; //!< JK flip-flop 65b IO (Sheet 10) + jkff_t ff_69a; //!< JK flip-flop 69a IT (Sheet 14) + jkff_t ff_69b; //!< JK flip-flop 69b INON (Sheet 14) + jkff_t ff_70a; //!< JK flip-flop 70a IMID (Sheet 14) + jkff_t ff_70b; //!< JK flip-flop 70b ILOC (Sheet 14) + jkff_t ff_77a; //!< JK flip-flop 77a WR (Sheet 10) + jkff_t ff_77b; //!< JK flip-flop 77b WLF (Sheet 10) + int breath_of_life; //!< if non-zero, interval in seconds at which to broadcast the breath-of-life +} m_eth; + +TIMER_CALLBACK_MEMBER( rx_breath_of_life ); //!< HACK: pull the next word from the breath-of-life in the fifo +TIMER_CALLBACK_MEMBER( tx_packet ); //!< transmit data from the FIFO to +void eth_wakeup(); //!< check for the various reasons to wakeup the Ethernet task +void eth_startf(); //!< start input or output depending on m_bus +void bs_early_eidfct(); //!< bus source: Ethernet input data function +void f1_early_eth_block(); //!< F1 func: block the Ether task +void f1_early_eilfct(); //!< F1 func: Ethernet input look function +void f1_early_epfct(); //!< F1 func: Ethernet post function +void f1_late_ewfct(); //!< F1 func: Ethernet countdown wakeup function +void f2_late_eodfct(); //!< F2 func: Ethernet output data function +void f2_late_eosfct(); //!< F2 func: Ethernet output start function +void f2_late_erbfct(); //!< F2 func: Ethernet reset branch function +void f2_late_eefct(); //!< F2 func: Ethernet end of transmission function +void f2_late_ebfct(); //!< F2 func: Ethernet branch function +void f2_late_ecbfct(); //!< F2 func: Ethernet countdown branch function +void f2_late_eisfct(); //!< F2 func: Ethernet input start function +void activate_eth(); //!< called by the CPU when the Ethernet task becomes active +void update_sysclk(int sysclk); //!< update all JK flip-flops for one cycle of SYSCLK +void update_rclk(int rclk); //!< update all JK flip-flops for one cycle of RCLK +void update_tclk(int tclk); //!< update all JK flip-flops for one cycle of TCLK +void init_ether(int task = task_ether); //!< initialize the ethernet task +void exit_ether(); //!< deinitialize the ethernet task +void reset_ether(); //!< reset the ethernet task +#endif // _A2ETHER_H_ +#endif // ALTO2_DEFINE_CONSTANTS diff --git a/src/devices/cpu/alto2/a2hw.c b/src/devices/cpu/alto2/a2hw.c new file mode 100644 index 00000000000..cc8a77c3f54 --- /dev/null +++ b/src/devices/cpu/alto2/a2hw.c @@ -0,0 +1,422 @@ +// license:BSD-3-Clause +// copyright-holders:Juergen Buchmueller +/***************************************************************************** + * + * Xerox AltoII memory mapped I/O hardware + * + *****************************************************************************/ +#include "alto2cpu.h" +#include "a2roms.h" + +/** + * @brief read printer paper ready bit + * Paper ready bit. 0 when the printer is ready for a paper scrolling operation. + */ +READ16_MEMBER ( alto2_cpu_device::pprdy_r ) { return X_RDBITS(m_hw.utilin,16,0,0); } + +/** + * @brief read printer check bit + * Printer check bit bit. + * Should the printer find itself in an abnormal state, it sets this bit to 0 + */ +READ16_MEMBER ( alto2_cpu_device::pcheck_r ) { return X_RDBITS(m_hw.utilin,16,1,1); } + +/** + * @brief read unused bit 2 + */ +READ16_MEMBER ( alto2_cpu_device::unused2_r ) { return X_RDBITS(m_hw.utilin,16,2,2); } + +/** + * @brief read printer daisy ready bit + * Daisy ready bit. 0 when the printer is ready to print a character. + */ +READ16_MEMBER ( alto2_cpu_device::pchrdy_r ) { return X_RDBITS(m_hw.utilin,16,3,3); } + +/** + * @brief read printer carriage ready bit + * Carriage ready bit. 0 when the printer is ready for horizontal positioning. + */ +READ16_MEMBER ( alto2_cpu_device::parrdy_r ) { return X_RDBITS(m_hw.utilin,16,4,4); } + +/** + * @brief read printer ready bit + * Ready bit. Both this bit and the appropriate other ready bit (carriage, + * daisy, etc.) must be 0 before attempting any output operation. + */ +READ16_MEMBER ( alto2_cpu_device::pready_r ) { return X_RDBITS(m_hw.utilin,16,5,5); } + +/** + * @brief memory configuration switch + */ +READ16_MEMBER ( alto2_cpu_device::memconfig_r ) { return X_RDBITS(m_hw.utilin,16,6,6); } + +/** + * @brief get unused bit 7 + */ +READ16_MEMBER ( alto2_cpu_device::unused7_r ) { return X_RDBITS(m_hw.utilin,16,7,7); } + +/** + * @brief get key set key 0 + */ +READ16_MEMBER ( alto2_cpu_device::keyset_key0_r ) { return X_RDBITS(m_hw.utilin,16,8,8); } + +/** + * @brief get key set key 1 + */ +READ16_MEMBER ( alto2_cpu_device::keyset_key1_r ) { return X_RDBITS(m_hw.utilin,16,9,9); } + +/** + * @brief get key set key 2 + */ +READ16_MEMBER ( alto2_cpu_device::keyset_key2_r ) { return X_RDBITS(m_hw.utilin,16,10,10); } + +/** + * @brief get key set key 3 + */ +READ16_MEMBER ( alto2_cpu_device::keyset_key3_r ) { return X_RDBITS(m_hw.utilin,16,11,11); } + +/** + * @brief get key set key 4 + */ +READ16_MEMBER ( alto2_cpu_device::keyset_key4_r ) { return X_RDBITS(m_hw.utilin,16,12,12); } + +/** + * @brief get mouse red button bit + */ +READ16_MEMBER ( alto2_cpu_device::mouse_red_r ) { return X_RDBITS(m_hw.utilin,16,13,13); } + +/** + * @brief get mouse blue button bit + */ +READ16_MEMBER ( alto2_cpu_device::mouse_blue_r ) { return X_RDBITS(m_hw.utilin,16,14,14); } + +/** + * @brief get mouse yellow button bit + */ +READ16_MEMBER ( alto2_cpu_device::mouse_yellow_r ) { return X_RDBITS(m_hw.utilin,16,15,15); } + +/** + * @brief write printer paper ready bit + */ +WRITE16_MEMBER( alto2_cpu_device::pprdy_w ) { X_WRBITS(m_hw.utilin,16,0,0,data); } + +/** + * @brief write printer check bit + */ +WRITE16_MEMBER( alto2_cpu_device::pcheck_w ) { X_WRBITS(m_hw.utilin,16,1,1,data); } + +/** + * @brief read unused bit 2 + */ +WRITE16_MEMBER( alto2_cpu_device::unused2_w ) { X_WRBITS(m_hw.utilin,16,2,2,data); } + +/** + * @brief write printer daisy ready bit + */ +WRITE16_MEMBER( alto2_cpu_device::pchrdy_w ) { X_WRBITS(m_hw.utilin,16,3,3,data); } + +/** + * @brief write printer carriage ready bit + */ +WRITE16_MEMBER( alto2_cpu_device::parrdy_w ) { X_WRBITS(m_hw.utilin,16,4,4,data); } + +/** + * @brief write printer ready bit + */ +WRITE16_MEMBER( alto2_cpu_device::pready_w ) { X_WRBITS(m_hw.utilin,16,5,5,data); } + +/** + * @brief write memory configuration switch + */ +WRITE16_MEMBER( alto2_cpu_device::memconfig_w ) { X_WRBITS(m_hw.utilin,16,6,6,data); } + +/** + * @brief write unused bit 7 + */ +WRITE16_MEMBER( alto2_cpu_device::unused7_w ) { X_WRBITS(m_hw.utilin,16,7,7,data); } + +/** + * @brief write key set key 0 + */ +WRITE16_MEMBER( alto2_cpu_device::keyset_key0_w ) { X_WRBITS(m_hw.utilin,16,8,8,data); } + +/** + * @brief write key set key 1 + */ +WRITE16_MEMBER( alto2_cpu_device::keyset_key1_w ) { X_WRBITS(m_hw.utilin,16,9,9,data); } + +/** + * @brief write key set key 2 + */ +WRITE16_MEMBER( alto2_cpu_device::keyset_key2_w ) { X_WRBITS(m_hw.utilin,16,10,10,data); } + +/** + * @brief write key set key 3 + */ +WRITE16_MEMBER( alto2_cpu_device::keyset_key3_w ) { X_WRBITS(m_hw.utilin,16,11,11,data); } + +/** + * @brief write key set key 4 + */ +WRITE16_MEMBER( alto2_cpu_device::keyset_key4_w ) { X_WRBITS(m_hw.utilin,16,12,12,data); } + +/** + * @brief write mouse red button bit + */ +WRITE16_MEMBER( alto2_cpu_device::mouse_red_w ) { X_WRBITS(m_hw.utilin,16,13,13,data); } + +/** + * @brief write mouse blue button bit + */ +WRITE16_MEMBER( alto2_cpu_device::mouse_blue_w ) { X_WRBITS(m_hw.utilin,16,14,14,data); } + +/** + * @brief write mouse yellow button bit + */ +WRITE16_MEMBER( alto2_cpu_device::mouse_yellow_w ) { X_WRBITS(m_hw.utilin,16,15,15,data); } + +/** + * @brief write mouse buttons bits + */ +WRITE16_MEMBER( alto2_cpu_device::mouse_buttons_w ) { X_WRBITS(m_hw.utilin,16,13,15,data); } + +/** + * @brief printer paper strobe bit + * Paper strobe bit. Toggling this bit causes a paper scrolling operation. + */ +//static inline UINT16 GET_PPPSTR(UINT16 utilout) { return X_RDBITS(utilout,16,0,0); } + +/** + * @brief printer retstore bit + * Restore bit. Toggling this bit resets the printer (including clearing + * the "check" condition if present) and moves the carriage to the + * left margin. + */ +//static inline UINT16 GET_PREST(UINT16 utilout) { return X_RDBITS(utilout,16,1,1); } + +/** + * @brief printer ribbon bit + * Ribbon bit. When this bit is 1 the ribbon is up (in printing + * position); when 0, it is down. + */ +//static inline UINT16 GET_PRIB(UINT16 utilout) { return X_RDBITS(utilout,16,2,2); } + +/** + * @brief printer daisy strobe bit + * Daisy strobe bit. Toggling this bit causes a character to be printed. + */ +//static inline UINT16 GET_PCHSTR(UINT16 utilout) { return X_RDBITS(utilout,16,3,3); } + +/** + * @brief printer carriage strobe bit + * Carriage strobe bit. Toggling this bit causes a horizontal position operation. + */ +//static inline UINT16 GET_PCARSTR(UINT16 utilout) { return X_RDBITS(utilout,16,4,4); } + +/** + * @brief printer data + * Argument to various output operations: + * 1. Printing characters. When the daisy bit is toggled bits 9-15 of this field + * are interpreted as an ASCII character code to be printed (it should be noted + * that all codes less than 040 print as lower case "w"). + * 2. For paper and carriage operations the field is interpreted as a displacement + * (-1024 to +1023), in units of 1/48 inch for paper and 1/60 inch for carriage. + * Positive is down or to the right, negative up or to the left. The value is + * represented as sign-magnitude (i.e., bit 5 is 1 for negative numbers, 0 for + * positive; bits 6-15 are the absolute value of the number). + */ +//static inline UINT16 GET_PDATA(UINT16 utilout) { return X_RDBITS(utilout,16,5,15); } + +/** + * @brief read the UTILIN port + * + * @param addr memory mapped I/O address to be read + * @return current value on the UTILIN port + */ +READ16_MEMBER( alto2_cpu_device::utilin_r ) +{ + UINT16 data; + // FIXME: update the printer status + // printer_read(); + + data = m_hw.utilin; + + if (!space.debugger_access()) { + LOG((LOG_HW,2," UTILIN rd %#o (%#o)\n", offset, data)); + } + return data; +} + +/** + * @brief read the XBUS port + * + * @param addr memory mapped I/O address to be read + * @return current value on the XBUS port latch + */ +READ16_MEMBER( alto2_cpu_device::xbus_r ) +{ + UINT16 data = m_hw.xbus[offset & 3]; + + if (!space.debugger_access()) { + LOG((LOG_HW,2," XBUS[%d] rd %#o (%#o)\n", offset & 3, offset, data)); + } + return data; +} + +/** + * @brief write the XBUS port + * + * The actual outputs are active-low. + * + * @param addr memory mapped I/O address to be read + * @param data value to write to the XBUS port latch + */ +WRITE16_MEMBER( alto2_cpu_device::xbus_w ) +{ + if (!space.debugger_access()) { + LOG((LOG_HW,2," XBUS[%d] wr %#o (%#o)\n", offset & 3, offset, data)); + } + m_hw.xbus[offset&3] = data; +} + +/** + * @brief read the UTILOUT port + * + * @param addr memory mapped I/O address to be read + * @return current value on the UTILOUT port latch + */ +READ16_MEMBER( alto2_cpu_device::utilout_r ) +{ + UINT16 data = m_hw.utilout ^ 0177777; + if (!space.debugger_access()) { + LOG((0,2," UTILOUT rd %#o (%#o)\n", offset, data)); + } + return data; +} + +/** + * @brief write the UTILOUT port + * + * The actual outputs are active-low. + * + * @param addr memory mapped I/O address to be read + * @param data value to write to the UTILOUT port latch + */ +WRITE16_MEMBER( alto2_cpu_device::utilout_w ) +{ + if (!space.debugger_access()) { + LOG((LOG_HW,2," UTILOUT wr %#o (%#o)\n", offset, data)); + } + m_hw.utilout = data ^ 0177777; + + // FIXME: write printer data + // printer_write(); +} + +/** + *
+ * TODO: use madr.a65 and madr.a64 to determine the actual I/O address ranges
+ *
+ * madr.a65
+ *  address line    connected to
+ *  -------------------------------
+ *  A0      MAR[11]
+ *  A1      KEYSEL
+ *  A2      MAR[7-10] == 0
+ *  A3      MAR[12]
+ *  A4      MAR[13]
+ *  A5      MAR[14]
+ *  A6      MAR[15]
+ *  A7      IOREF (MAR[0-6] == 1)
+ *
+ *  output data connected to
+ *  -------------------------------
+ *  D0      IOSEL0
+ *  D1      IOSEL1
+ *  D2      IOSEL2
+ *  D3      INTIO
+ *
+ * madr.a64
+ *  address line    connected to
+ *  -------------------------------
+ *  A0      STORE
+ *  A1      MAR[11]
+ *  A2      MAR[7-10] == 0
+ *  A3      MAR[12]
+ *  A4      MAR[13]
+ *  A5      MAR[14]
+ *  A6      MAR[15]
+ *  A7      IOREF (MAR[0-6] == 1)
+ *
+ *  output data connected to
+ *  -------------------------------
+ *  D0      & MISYSCLK -> SELP
+ *  D1      ^ INTIO -> INTIOX
+ *  "       ^ 1 -> NERRSEL
+ *  "       & WRTCLK -> NRSTE
+ *  D2      XREG'
+ *  D3      & MISYSCLK -> LOADERC
+ * 
+ */ + +static const prom_load_t pl_madr_a64 = +{ + "madr.a64", + 0, + "a66b0eda", + "4d9088f592caa3299e90966b17765be74e523144", + /* size */ 0400, + /* amap */ AMAP_DEFAULT, + /* axor */ 0, + /* dxor */ 017, // invert D0-D3 + /* width */ 4, + /* shift */ 0, + /* dmap */ DMAP_DEFAULT, + /* dand */ ZERO, + /* type */ sizeof(UINT8) +}; + +static const prom_load_t pl_madr_a65 = +{ + "madr.a65", + 0, + "ba37febd", + "82e9db1cb65f451755295f0d179e6f8fe3349d4d", + /* size */ 0400, + /* amap */ AMAP_DEFAULT, + /* axor */ 0, + /* dxor */ 017, // invert D0-D3 + /* width */ 4, + /* shift */ 0, + /* dmap */ DMAP_DEFAULT, + /* dand */ ZERO, + /* type */ sizeof(UINT8) +}; + +/** + * @brief clear all keys and install the mmio handler for KBDAD to KBDAD+3 + */ +void alto2_cpu_device::init_hw() +{ + memset(&m_hw, 0, sizeof(m_hw)); + m_madr_a64 = prom_load(machine(), &pl_madr_a64, memregion("madr_a64")->base()); + m_madr_a65 = prom_load(machine(), &pl_madr_a65, memregion("madr_a65")->base()); +} + +void alto2_cpu_device::exit_hw() +{ + // nothing to do yet +} + +void alto2_cpu_device::reset_hw() +{ + m_hw.eia = 0; + m_hw.utilout = 0; + // open inputs on the XBUS (?) + m_hw.xbus[0] = 0177777; + m_hw.xbus[1] = 0177777; + m_hw.xbus[2] = 0177777; + m_hw.xbus[3] = 0177777; + // open inputs on UTILIN + m_hw.utilin = 0177777; +} diff --git a/src/devices/cpu/alto2/a2hw.h b/src/devices/cpu/alto2/a2hw.h new file mode 100644 index 00000000000..49d20ff5e30 --- /dev/null +++ b/src/devices/cpu/alto2/a2hw.h @@ -0,0 +1,66 @@ +// license:BSD-3-Clause +// copyright-holders:Juergen Buchmueller +/***************************************************************************** + * + * Xerox AltoII memory mapped i/o stuff (HW) + * + *****************************************************************************/ +#ifdef ALTO2_DEFINE_CONSTANTS + +#else // ALTO2_DEFINE_CONSTANTS +#ifndef _A2HW_H_ +#define _A2HW_H_ +//! miscellaneous hardware registers in the memory mapped I/O range +struct { + UINT16 eia; //!< the EIA port at 0177001 + UINT16 utilout; //!< the UTILOUT port at 0177016 (active-low outputs) + UINT16 xbus[4]; //!< the XBUS port at 0177020 to 0177023 + UINT16 utilin; //!< the UTILIN port at 0177030 to 0177033 (same value on all addresses) +} m_hw; + +DECLARE_READ16_MEMBER ( pprdy_r ); //!< read UTILIN[0] printer paper ready bit +DECLARE_READ16_MEMBER ( pcheck_r ); //!< read UTILIN[1] printer check bit +DECLARE_READ16_MEMBER ( unused2_r ); //!< read UTILIN[2] unused bit +DECLARE_READ16_MEMBER ( pchrdy_r ); //!< read UTILIN[3] printer daisy ready bit +DECLARE_READ16_MEMBER ( parrdy_r ); //!< read UTILIN[4] printer carriage ready bit +DECLARE_READ16_MEMBER ( pready_r ); //!< read UTILIN[5] printer ready bit +DECLARE_READ16_MEMBER ( memconfig_r ); //!< read UTILIN[6] memory config switch +DECLARE_READ16_MEMBER ( unused7_r ); //!< read UTILIN[7] unused bit +DECLARE_READ16_MEMBER ( keyset_key0_r ); //!< read UTILIN[8] keyset key #0 +DECLARE_READ16_MEMBER ( keyset_key1_r ); //!< read UTILIN[9] keyset key #1 +DECLARE_READ16_MEMBER ( keyset_key2_r ); //!< read UTILIN[10] keyset key #2 +DECLARE_READ16_MEMBER ( keyset_key3_r ); //!< read UTILIN[11] keyset key #3 +DECLARE_READ16_MEMBER ( keyset_key4_r ); //!< read UTILIN[12] keyset key #4 +DECLARE_READ16_MEMBER ( mouse_red_r ); //!< read UTILIN[13] mouse red button bit +DECLARE_READ16_MEMBER ( mouse_blue_r ); //!< read UTILIN[14] mouse blue button bit +DECLARE_READ16_MEMBER ( mouse_yellow_r ); //!< read UTILIN[15] mouse yellow button bit + +DECLARE_WRITE16_MEMBER( pprdy_w ); //!< write UTILIN[0] printer paper ready bit +DECLARE_WRITE16_MEMBER( pcheck_w ); //!< write UTILIN[1] printer check bit +DECLARE_WRITE16_MEMBER( unused2_w ); //!< write UTILIN[2] unused bit +DECLARE_WRITE16_MEMBER( pchrdy_w ); //!< write UTILIN[3] printer daisy ready bit +DECLARE_WRITE16_MEMBER( parrdy_w ); //!< write UTILIN[4] carriage ready bit +DECLARE_WRITE16_MEMBER( pready_w ); //!< write UTILIN[5] printer ready bit +DECLARE_WRITE16_MEMBER( memconfig_w ); //!< write UTILIN[6] memory config switch +DECLARE_WRITE16_MEMBER( unused7_w ); //!< write UTILIN[7] unused bit +DECLARE_WRITE16_MEMBER( keyset_key0_w ); //!< write UTILIN[8] keyset key #0 +DECLARE_WRITE16_MEMBER( keyset_key1_w ); //!< write UTILIN[9] keyset key #1 +DECLARE_WRITE16_MEMBER( keyset_key2_w ); //!< write UTILIN[10] keyset key #2 +DECLARE_WRITE16_MEMBER( keyset_key3_w ); //!< write UTILIN[11] keyset key #3 +DECLARE_WRITE16_MEMBER( keyset_key4_w ); //!< write UTILIN[12] keyset key #4 +DECLARE_WRITE16_MEMBER( mouse_red_w ); //!< write UTILIN[13] mouse red button bit +DECLARE_WRITE16_MEMBER( mouse_blue_w ); //!< write UTILIN[14] mouse blue button bit +DECLARE_WRITE16_MEMBER( mouse_yellow_w ); //!< write UTILIN[15] mouse yellow button bit +DECLARE_WRITE16_MEMBER( mouse_buttons_w ); //!< write UTILIN[13-15] mouse buttons bits + +DECLARE_READ16_MEMBER ( utilin_r ); //!< read an UTILIN address +DECLARE_READ16_MEMBER ( utilout_r ); //!< read the UTILOUT address +DECLARE_WRITE16_MEMBER( utilout_w ); //!< write the UTILOUT address +DECLARE_READ16_MEMBER ( xbus_r ); //!< read an XBUS address +DECLARE_WRITE16_MEMBER( xbus_w ); //!< write an XBUS address (?) + +void init_hw(); //!< initialize miscellaneous hardware +void exit_hw(); //!< deinitialize miscellaneous hardware +void reset_hw(); //!< reset miscellaneous hardware +#endif // _A2HW_H_ +#endif // ALTO2_DEFINE_CONSTANTS diff --git a/src/devices/cpu/alto2/a2jkff.h b/src/devices/cpu/alto2/a2jkff.h new file mode 100644 index 00000000000..687313607b1 --- /dev/null +++ b/src/devices/cpu/alto2/a2jkff.h @@ -0,0 +1,192 @@ +// license:BSD-3-Clause +// copyright-holders:Juergen Buchmueller +/***************************************************************************** + * + * Xerox AltoII Dual J/K flip-flop 74109 emulation + * + *****************************************************************************/ +#ifdef ALTO2_DEFINE_CONSTANTS + +#define JKFF_DEBUG 0 //!< define 1 to debug the transitions + +/** + * @brief enumeration of the inputs and outputs of a JK flip-flop type 74109 + *
+ * 74109
+ * Dual J-/K flip-flops with set and reset.
+ *
+ *       +----------+           +-----------------------------+
+ * /1RST |1  +--+ 16| VCC       | J |/K |CLK|/SET|/RST| Q |/Q |
+ *    1J |2       15| /2RST     |---+---+---+----+----+---+---|
+ *   /1K |3       14| 2J        | X | X | X |  0 |  0 | 1 | 1 |
+ *  1CLK |4   74  13| /2K       | X | X | X |  0 |  1 | 1 | 0 |
+ * /1SET |5  109  12| 2CLK      | X | X | X |  1 |  0 | 0 | 1 |
+ *    1Q |6       11| /2SET     | 0 | 0 | / |  1 |  1 | 0 | 1 |
+ *   /1Q |7       10| 2Q        | 0 | 1 | / |  1 |  1 | - | - |
+ *   GND |8        9| /2Q       | 1 | 0 | / |  1 |  1 |/Q | Q |
+ *       +----------+           | 1 | 1 | / |  1 |  1 | 1 | 0 |
+ *                              | X | X |!/ |  1 |  1 | - | - |
+ *                              +-----------------------------+
+ *
+ * [This information is part of the GIICM]
+ * 
+ */ +typedef enum { + JKFF_0, //!< no inputs or outputs + JKFF_CLK = (1 << 0), //!< clock signal + JKFF_J = (1 << 1), //!< J input + JKFF_K = (1 << 2), //!< K' input + JKFF_S = (1 << 3), //!< S' input + JKFF_C = (1 << 4), //!< C' input + JKFF_Q = (1 << 5), //!< Q output + JKFF_Q0 = (1 << 6) //!< Q' output +} jkff_t; + +#else // ALTO2_DEFINE_CONSTANTS + +#ifndef _A2JKFF_H_ +#define _A2JKFF_H_ + +#if JKFF_DEBUG +/** + * @brief simulate a 74109 J-K flip-flop with set and reset inputs + * + * @param s0 is the previous state of the FF's in- and outputs + * @param s1 is the next state + * @return returns the next state and probably modified Q output + */ +static inline jkff_t update_jkff(UINT8 s0, UINT8 s1, const char* jkff_name) +{ + switch (s1 & (JKFF_C | JKFF_S)) + { + case JKFF_C | JKFF_S: /* C' is 1, and S' is 1 */ + if (((s0 ^ s1) & s1) & JKFF_CLK) { + /* rising edge of the clock */ + switch (s1 & (JKFF_J | JKFF_K)) + { + case 0: + /* both J and K' are 0: set Q to 0, Q' to 1 */ + s1 = (s1 & ~JKFF_Q) | JKFF_Q0; + if (s0 & JKFF_Q) { + LOG((LOG_DISK,9,"\t\t%s J:0 K':0 -> Q:0\n", jkff_name)); + } + break; + case JKFF_J: + /* J is 1, and K' is 0: toggle Q */ + if (s0 & JKFF_Q) + s1 = (s1 & ~JKFF_Q) | JKFF_Q0; + else + s1 = (s1 | JKFF_Q) & ~JKFF_Q0; + LOG((LOG_DISK,9,"\t\t%s J:0 K':1 flip-flop Q:%d\n", jkff_name, (s1 & JKFF_Q) ? 1 : 0)); + break; + case JKFF_K: + if ((s0 ^ s1) & JKFF_Q) { + LOG((LOG_DISK,9,"\t\t%s J:0 K':1 keep Q:%d\n", jkff_name, (s1 & JKFF_Q) ? 1 : 0)); + } + /* J is 0, and K' is 1: keep Q as is */ + if (s0 & JKFF_Q) + s1 = (s1 | JKFF_Q) & ~JKFF_Q0; + else + s1 = (s1 & ~JKFF_Q) | JKFF_Q0; + break; + case JKFF_J | JKFF_K: + /* both J and K' are 1: set Q to 1 */ + s1 = (s1 | JKFF_Q) & ~JKFF_Q0; + if (!(s0 & JKFF_Q)) { + LOG((LOG_DISK,9,"\t\t%s J:1 K':1 -> Q:1\n", jkff_name)); + } + break; + } + } else { + /* keep Q */ + s1 = (s1 & ~JKFF_Q) | (s0 & JKFF_Q); + } + break; + case JKFF_S: + /* S' is 1, C' is 0: set Q to 0, Q' to 1 */ + s1 = (s1 & ~JKFF_Q) | JKFF_Q0; + if (s0 & JKFF_Q) { + LOG((LOG_DISK,9,"\t\t%s C':0 -> Q:0\n", jkff_name)); + } + break; + case JKFF_C: + /* S' is 0, C' is 1: set Q to 1, Q' to 0 */ + s1 = (s1 | JKFF_Q) & ~JKFF_Q0; + if (!(s0 & JKFF_Q)) { + LOG((LOG_DISK,9,"\t\t%s S':0 -> Q:1\n", jkff_name)); + } + break; + case 0: + default: + /* unstable state (what to do?) */ + s1 = s1 | JKFF_Q | JKFF_Q0; + LOG((LOG_DISK,9,"\t\t%s C':0 S':0 -> Q:1 and Q':1 \n", jkff_name)); + break; + } + return static_cast(s1); +} +#else // JKFF_DEBUG +/** + * @brief simulate a 74109 J-K flip-flop with set and reset inputs + * + * @param s0 is the previous state of the FF's in- and outputs + * @param s1 is the next state + * @return returns the next state and probably modified Q output + */ +static inline jkff_t update_jkff(UINT8 s0, UINT8 s1, const char*) +{ + switch (s1 & (JKFF_C | JKFF_S)) + { + case JKFF_C | JKFF_S: /* C' is 1, and S' is 1 */ + if (((s0 ^ s1) & s1) & JKFF_CLK) { + /* rising edge of the clock */ + switch (s1 & (JKFF_J | JKFF_K)) + { + case 0: + /* both J and K' are 0: set Q to 0, Q' to 1 */ + s1 = (s1 & ~JKFF_Q) | JKFF_Q0; + break; + case JKFF_J: + /* J is 1, and K' is 0: toggle Q */ + if (s0 & JKFF_Q) + s1 = (s1 & ~JKFF_Q) | JKFF_Q0; + else + s1 = (s1 | JKFF_Q) & ~JKFF_Q0; + break; + case JKFF_K: + /* J is 0, and K' is 1: keep Q as is */ + if (s0 & JKFF_Q) + s1 = (s1 | JKFF_Q) & ~JKFF_Q0; + else + s1 = (s1 & ~JKFF_Q) | JKFF_Q0; + break; + case JKFF_J | JKFF_K: + /* both J and K' are 1: set Q to 1 */ + s1 = (s1 | JKFF_Q) & ~JKFF_Q0; + break; + } + } else { + /* keep Q */ + s1 = (s1 & ~JKFF_Q) | (s0 & JKFF_Q); + } + break; + case JKFF_S: + /* S' is 1, C' is 0: set Q to 0, Q' to 1 */ + s1 = (s1 & ~JKFF_Q) | JKFF_Q0; + break; + case JKFF_C: + /* S' is 0, C' is 1: set Q to 1, Q' to 0 */ + s1 = (s1 | JKFF_Q) & ~JKFF_Q0; + break; + case 0: + default: + /* unstable state (what to do?) */ + s1 = s1 | JKFF_Q | JKFF_Q0; + break; + } + return static_cast(s1); +} +#endif // JKFF_DEBUG + +#endif // _A2JKFF_H_ +#endif // ALTO2_DEFINE_CONSTANTS diff --git a/src/devices/cpu/alto2/a2kbd.c b/src/devices/cpu/alto2/a2kbd.c new file mode 100644 index 00000000000..fa1bb5f9596 --- /dev/null +++ b/src/devices/cpu/alto2/a2kbd.c @@ -0,0 +1,63 @@ +// license:BSD-3-Clause +// copyright-holders:Juergen Buchmueller +/***************************************************************************** + * + * Xerox AltoII memory mapped I/O keyboard + * + *****************************************************************************/ +#include "alto2cpu.h" + +/** + * @brief read the keyboard address matrix + * + * @param addr memory mapped I/O address to be read + * @return keyboard matrix value for address modulo 4 + */ +READ16_MEMBER( alto2_cpu_device::kbd_ad_r ) +{ + UINT16 data = 0177777; + switch (offset & 3) { + case 0: + data = machine().root_device().ioport("ROW0")->read(); + break; + case 1: + data = machine().root_device().ioport("ROW1")->read(); + break; + case 2: + data = machine().root_device().ioport("ROW2")->read(); + break; + case 3: + data = machine().root_device().ioport("ROW3")->read(); + break; + } + m_kbd.matrix[offset & 03] = data; + if (!space.debugger_access()) { + LOG((LOG_KBD,2," read KBDAD+%o (%#o)\n", offset & 3, data)); + } + if (0 == (offset & 3) && (m_kbd.bootkey != 0177777)) { + if (!space.debugger_access()) { + LOG((0,2," boot keys (%#o & %#o)\n", data, m_kbd.bootkey)); + } + data &= m_kbd.bootkey; + m_kbd.bootkey = 0177777; + } + return data; +} + +void alto2_cpu_device::init_kbd(UINT16 bootkey) +{ + m_kbd.bootkey = bootkey; +} + +void alto2_cpu_device::exit_kbd() +{ + // nothing to do yet +} + +void alto2_cpu_device::reset_kbd() +{ + m_kbd.matrix[0] = 0177777; + m_kbd.matrix[1] = 0177777; + m_kbd.matrix[2] = 0177777; + m_kbd.matrix[3] = 0177777; +} diff --git a/src/devices/cpu/alto2/a2kbd.h b/src/devices/cpu/alto2/a2kbd.h new file mode 100644 index 00000000000..b7bf6607ee2 --- /dev/null +++ b/src/devices/cpu/alto2/a2kbd.h @@ -0,0 +1,109 @@ +// license:BSD-3-Clause +// copyright-holders:Juergen Buchmueller +/***************************************************************************** + * + * Xerox AltoII keyboard hardware (KBD) + * + *****************************************************************************/ +#ifdef ALTO2_DEFINE_CONSTANTS + +//! make an Xerox AltoII key bit mask +#define MAKE_KEY(a,b) (1 << (b)) + +#define A2_KEY_5 MAKE_KEY(0,017) //!< normal: 5 shifted: % +#define A2_KEY_4 MAKE_KEY(0,016) //!< normal: 4 shifted: $ +#define A2_KEY_6 MAKE_KEY(0,015) //!< normal: 6 shifted: ~ +#define A2_KEY_E MAKE_KEY(0,014) //!< normal: e shifted: E +#define A2_KEY_7 MAKE_KEY(0,013) //!< normal: 7 shifted: & +#define A2_KEY_D MAKE_KEY(0,012) //!< normal: d shifted: D +#define A2_KEY_U MAKE_KEY(0,011) //!< normal: u shifted: U +#define A2_KEY_V MAKE_KEY(0,010) //!< normal: v shifted: V +#define A2_KEY_0 MAKE_KEY(0,007) //!< normal: 0 shifted: ) +#define A2_KEY_K MAKE_KEY(0,006) //!< normal: k shifted: K +#define A2_KEY_MINUS MAKE_KEY(0,005) //!< normal: - shifted: _ +#define A2_KEY_P MAKE_KEY(0,004) //!< normal: p shifted: P +#define A2_KEY_SLASH MAKE_KEY(0,003) //!< normal: / shifted: ? +#define A2_KEY_BACKSLASH MAKE_KEY(0,002) //!< normal: \ shifted: | +#define A2_KEY_LF MAKE_KEY(0,001) //!< normal: LF +#define A2_KEY_BS MAKE_KEY(0,000) //!< normal: BS + +#define A2_KEY_3 MAKE_KEY(1,017) //!< normal: 3 shifted: # +#define A2_KEY_2 MAKE_KEY(1,016) //!< normal: 2 shifted: @ +#define A2_KEY_W MAKE_KEY(1,015) //!< normal: w shifted: W +#define A2_KEY_Q MAKE_KEY(1,014) //!< normal: q shifted: Q +#define A2_KEY_S MAKE_KEY(1,013) //!< normal: s shifted: S +#define A2_KEY_A MAKE_KEY(1,012) //!< normal: a shifted: A +#define A2_KEY_9 MAKE_KEY(1,011) //!< normal: 9 shifted: ( +#define A2_KEY_I MAKE_KEY(1,010) //!< normal: i shifted: I +#define A2_KEY_X MAKE_KEY(1,007) //!< normal: x shifted: X +#define A2_KEY_O MAKE_KEY(1,006) //!< normal: o shifted: O +#define A2_KEY_L MAKE_KEY(1,005) //!< normal: l shifted: L +#define A2_KEY_COMMA MAKE_KEY(1,004) //!< normal: , shifted: < +#define A2_KEY_QUOTE MAKE_KEY(1,003) //!< normal: ' shifted: " +#define A2_KEY_RBRACKET MAKE_KEY(1,002) //!< normal: ] shifted: } +#define A2_KEY_BLANK_MID MAKE_KEY(1,001) //!< middle blank key +#define A2_KEY_BLANK_TOP MAKE_KEY(1,000) //!< top blank key + +#define A2_KEY_1 MAKE_KEY(2,017) //!< normal: 1 shifted: ! +#define A2_KEY_ESCAPE MAKE_KEY(2,016) //!< normal: ESC shifted: ? +#define A2_KEY_TAB MAKE_KEY(2,015) //!< normal: TAB shifted: ? +#define A2_KEY_F MAKE_KEY(2,014) //!< normal: f shifted: F +#define A2_KEY_CTRL MAKE_KEY(2,013) //!< CTRL +#define A2_KEY_C MAKE_KEY(2,012) //!< normal: c shifted: C +#define A2_KEY_J MAKE_KEY(2,011) //!< normal: j shifted: J +#define A2_KEY_B MAKE_KEY(2,010) //!< normal: b shifted: B +#define A2_KEY_Z MAKE_KEY(2,007) //!< normal: z shifted: Z +#define A2_KEY_LSHIFT MAKE_KEY(2,006) //!< LSHIFT +#define A2_KEY_PERIOD MAKE_KEY(2,005) //!< normal: . shifted: > +#define A2_KEY_SEMICOLON MAKE_KEY(2,004) //!< normal: ; shifted: : +#define A2_KEY_RETURN MAKE_KEY(2,003) //!< RETURN +#define A2_KEY_LEFTARROW MAKE_KEY(2,002) //!< normal: <- shifted: ^ (caret?) +#define A2_KEY_DEL MAKE_KEY(2,001) //!< normal: DEL +#define A2_KEY_MSW_2_17 MAKE_KEY(2,000) //!< unused on Microswitch KDB + +#define A2_KEY_R MAKE_KEY(3,017) //!< normal: r shifted: R +#define A2_KEY_T MAKE_KEY(3,016) //!< normal: t shifted: T +#define A2_KEY_G MAKE_KEY(3,015) //!< normal: g shifted: G +#define A2_KEY_Y MAKE_KEY(3,014) //!< normal: y shifted: Y +#define A2_KEY_H MAKE_KEY(3,013) //!< normal: h shifted: H +#define A2_KEY_8 MAKE_KEY(3,012) //!< normal: 8 shifted: * +#define A2_KEY_N MAKE_KEY(3,011) //!< normal: n shifted: N +#define A2_KEY_M MAKE_KEY(3,010) //!< normal: m shifted: M +#define A2_KEY_LOCK MAKE_KEY(3,007) //!< LOCK +#define A2_KEY_SPACE MAKE_KEY(3,006) //!< SPACE +#define A2_KEY_LBRACKET MAKE_KEY(3,005) //!< normal: [ shifted: { +#define A2_KEY_EQUALS MAKE_KEY(3,004) //!< normal: = shifted: + +#define A2_KEY_RSHIFT MAKE_KEY(3,003) //!< RSHIFT +#define A2_KEY_BLANK_BOT MAKE_KEY(3,002) //!< bottom blank key +#define A2_KEY_MSW_3_16 MAKE_KEY(3,001) //!< unused on Microswitch KDB +#define A2_KEY_MSW_3_17 MAKE_KEY(3,000) //!< unused on Microswitch KDB + +#define A2_KEY_FR2 MAKE_KEY(0,002) //!< ADL right function key 2 +#define A2_KEY_FL2 MAKE_KEY(0,001) //!< ADL left function key 1 + +#define A2_KEY_FR4 MAKE_KEY(1,001) //!< ADL right funtion key 4 +#define A2_KEY_BW MAKE_KEY(1,000) //!< ADL BW (?) + +#define A2_KEY_FR3 MAKE_KEY(2,002) //!< ADL right function key 3 +#define A2_KEY_FL1 MAKE_KEY(2,001) //!< ADL left function key 1 +#define A2_KEY_FL3 MAKE_KEY(2,000) //!< ADL left function key 3 + +#define A2_KEY_FR1 MAKE_KEY(3,002) //!< ADL right function key 4 +#define A2_KEY_FL4 MAKE_KEY(3,001) //!< ADL left function key 4 +#define A2_KEY_FR5 MAKE_KEY(3,000) //!< ADL right function key 5 + +#else // ALTO2_DEFINE_CONSTANTS +#ifndef _A2KBD_H_ +#define _A2KBD_H_ +struct { + UINT16 bootkey; //!< boot key - key code pressed before power on + UINT16 matrix[4]; //!< a bit map of the keys pressed (ioports ROW0 ... ROW3) +} m_kbd; + +DECLARE_READ16_MEMBER( kbd_ad_r ); //!< read the keyboard matrix + +void init_kbd(UINT16 bootkey = 0177777); //!< initialize the keyboard hardware, optinally set the boot key +void exit_kbd(); //!< deinitialize the keyboard hardware +void reset_kbd(); //!< reset the keyboard hardware +#endif // _A2KBD_H_ +#endif // ALTO2_DEFINE_CONSTANTS diff --git a/src/devices/cpu/alto2/a2ksec.c b/src/devices/cpu/alto2/a2ksec.c new file mode 100644 index 00000000000..b6ca5359dc6 --- /dev/null +++ b/src/devices/cpu/alto2/a2ksec.c @@ -0,0 +1,54 @@ +// license:BSD-3-Clause +// copyright-holders:Juergen Buchmueller +/***************************************************************************** + * + * Xerox AltoII disk sector task + * + *****************************************************************************/ +#include "alto2cpu.h" + +//! f1_ksec_block early: block the disk sector task +void alto2_cpu_device::f1_early_ksec_block() +{ + LOG((LOG_KSEC,2," BLOCK %s\n", task_name(m_task))); + disk_block(m_task); +} + +//! disk sector task slot initialization +void alto2_cpu_device::init_ksec(int task) +{ + set_bs(task, bs_ksec_read_kstat, &alto2_cpu_device::bs_early_read_kstat, 0); + set_bs(task, bs_ksec_read_kdata, &alto2_cpu_device::bs_early_read_kdata, 0); + + set_f1(task, f1_block, &alto2_cpu_device::f1_early_ksec_block, 0); + + set_f1(task, f1_task_10, 0, 0); + set_f1(task, f1_ksec_strobe, 0, &alto2_cpu_device::f1_late_strobe); + set_f1(task, f1_ksec_load_kstat, 0, &alto2_cpu_device::f1_late_load_kstat); + set_f1(task, f1_ksec_increcno, 0, &alto2_cpu_device::f1_late_increcno); + set_f1(task, f1_ksec_clrstat, 0, &alto2_cpu_device::f1_late_clrstat); + set_f1(task, f1_ksec_load_kcom, 0, &alto2_cpu_device::f1_late_load_kcom); + set_f1(task, f1_ksec_load_kadr, 0, &alto2_cpu_device::f1_late_load_kadr); + set_f1(task, f1_ksec_load_kdata, 0, &alto2_cpu_device::f1_late_load_kdata); + + set_f2(task, f2_ksec_init, 0, &alto2_cpu_device::f2_late_init); + set_f2(task, f2_ksec_rwc, 0, &alto2_cpu_device::f2_late_rwc); + set_f2(task, f2_ksec_recno, 0, &alto2_cpu_device::f2_late_recno); + set_f2(task, f2_ksec_xfrdat, 0, &alto2_cpu_device::f2_late_xfrdat); + set_f2(task, f2_ksec_swrnrdy, 0, &alto2_cpu_device::f2_late_swrnrdy); + set_f2(task, f2_ksec_nfer, 0, &alto2_cpu_device::f2_late_nfer); + set_f2(task, f2_ksec_strobon, 0, &alto2_cpu_device::f2_late_strobon); + set_f2(task, f2_task_17, 0, 0); + + m_task_wakeup |= 1 << task; +} + +void alto2_cpu_device::exit_ksec() +{ + // nothing to do yet +} + +void alto2_cpu_device::reset_ksec() +{ + // nothing to do yet +} diff --git a/src/devices/cpu/alto2/a2ksec.h b/src/devices/cpu/alto2/a2ksec.h new file mode 100644 index 00000000000..96c2530a2a5 --- /dev/null +++ b/src/devices/cpu/alto2/a2ksec.h @@ -0,0 +1,48 @@ +// license:BSD-3-Clause +// copyright-holders:Juergen Buchmueller +/***************************************************************************** + * + * Xerox AltoII disk sector task (KSEC) + * + *****************************************************************************/ +#ifdef ALTO2_DEFINE_CONSTANTS + +#else // ALTO2_DEFINE_CONSTANTS +#ifndef _A2KSEC_H_ +#define _A2KSEC_H_ +//! BUS source for disk sector task +enum { + bs_ksec_read_kstat = bs_task_3, //!< bus source: read disk status register + bs_ksec_read_kdata = bs_task_4 //!< bus source: read disk data register +}; + +//! F1 functions for disk sector task +enum { + //!< f1 10: undefined + f1_ksec_strobe = f1_task_11, //!< f1 11: strobe + f1_ksec_load_kstat = f1_task_12, //!< f1 12: load kstat register + f1_ksec_increcno = f1_task_13, //!< f1 13: increment record number + f1_ksec_clrstat = f1_task_14, //!< f1 14: clear status register + f1_ksec_load_kcom = f1_task_15, //!< f1 15: load kcom register + f1_ksec_load_kadr = f1_task_16, //!< f1 16: load kadr register + f1_ksec_load_kdata = f1_task_17 //!< f1 17: load kdata register +}; + +//! F2 functions for disk sector task +enum { + f2_ksec_init = f2_task_10, //!< f2 10: branches NEXT[5-9] on WDTASKACT && WDINIT + f2_ksec_rwc = f2_task_11, //!< f2 11: branches NEXT[8-9] on READ/WRITE/CHECK for record + f2_ksec_recno = f2_task_12, //!< f2 12: branches NEXT[8-9] on RECNO[0-1] + f2_ksec_xfrdat = f2_task_13, //!< f2 13: branches NEXT[9] on !SEEKONLY + f2_ksec_swrnrdy = f2_task_14, //!< f2 14: branches NEXT[9] on !SWRDY + f2_ksec_nfer = f2_task_15, //!< f2 15: branches NEXT[9] on !KFER + f2_ksec_strobon = f2_task_16 //!< f2 16: branches NEXT[9] on STROBE + //!< f2 17: undefined +}; + +void f1_early_ksec_block(void); //!< block ksec task +void init_ksec(int task = task_ksec); //!< initialize the disk sector task +void exit_ksec(); //!< deinitialize the disk sector task +void reset_ksec(); //!< reset the disk sector task +#endif // _A2KSEC_H_ +#endif // ALTO2_DEFINE_CONSTANTS diff --git a/src/devices/cpu/alto2/a2kwd.c b/src/devices/cpu/alto2/a2kwd.c new file mode 100644 index 00000000000..1eb060258a8 --- /dev/null +++ b/src/devices/cpu/alto2/a2kwd.c @@ -0,0 +1,52 @@ +// license:BSD-3-Clause +// copyright-holders:Juergen Buchmueller +/***************************************************************************** + * + * Xerox AltoII disk word task + * + *****************************************************************************/ +#include "alto2cpu.h" + +//! f1_kwd_block early: block the disk word task +void alto2_cpu_device::f1_early_kwd_block() +{ + LOG((LOG_KWD,2," BLOCK %s\n", task_name(m_task))); + disk_block(m_task); +} + +//! disk word task slot initialization +void alto2_cpu_device::init_kwd(int task) +{ + set_bs(task, bs_kwd_read_kstat, &alto2_cpu_device::bs_early_read_kstat, 0); + set_bs(task, bs_kwd_read_kdata, &alto2_cpu_device::bs_early_read_kdata, 0); + + set_f1(task, f1_block, &alto2_cpu_device::f1_early_kwd_block, 0); + + set_f1(task, f1_task_10, 0, 0); + set_f1(task, f1_kwd_strobe, 0, &alto2_cpu_device::f1_late_strobe); + set_f1(task, f1_kwd_load_kstat, 0, &alto2_cpu_device::f1_late_load_kstat); + set_f1(task, f1_kwd_increcno, 0, &alto2_cpu_device::f1_late_increcno); + set_f1(task, f1_kwd_clrstat, 0, &alto2_cpu_device::f1_late_clrstat); + set_f1(task, f1_kwd_load_kcom, 0, &alto2_cpu_device::f1_late_load_kcom); + set_f1(task, f1_kwd_load_kadr, 0, &alto2_cpu_device::f1_late_load_kadr); + set_f1(task, f1_kwd_load_kdata, 0, &alto2_cpu_device::f1_late_load_kdata); + + set_f2(task, f2_kwd_init, 0, &alto2_cpu_device::f2_late_init); + set_f2(task, f2_kwd_rwc, 0, &alto2_cpu_device::f2_late_rwc); + set_f2(task, f2_kwd_recno, 0, &alto2_cpu_device::f2_late_recno); + set_f2(task, f2_kwd_xfrdat, 0, &alto2_cpu_device::f2_late_xfrdat); + set_f2(task, f2_kwd_swrnrdy, 0, &alto2_cpu_device::f2_late_swrnrdy); + set_f2(task, f2_kwd_nfer, 0, &alto2_cpu_device::f2_late_nfer); + set_f2(task, f2_kwd_strobon, 0, &alto2_cpu_device::f2_late_strobon); + set_f2(task, f2_task_17, 0, 0); +} + +void alto2_cpu_device::exit_kwd() +{ + // nothing to do yet +} + +void alto2_cpu_device::reset_kwd() +{ + // nothing to do yet +} diff --git a/src/devices/cpu/alto2/a2kwd.h b/src/devices/cpu/alto2/a2kwd.h new file mode 100644 index 00000000000..678408501d2 --- /dev/null +++ b/src/devices/cpu/alto2/a2kwd.h @@ -0,0 +1,49 @@ +// license:BSD-3-Clause +// copyright-holders:Juergen Buchmueller +/***************************************************************************** + * + * Xerox AltoII disk word task (KWD) + * + *****************************************************************************/ +#ifdef ALTO2_DEFINE_CONSTANTS + +#else // ALTO2_DEFINE_CONSTANTS +#ifndef _A2KWD_H_ +#define _A2KWD_H_ + +//! BUS source for disk word task +enum { + bs_kwd_read_kstat = bs_task_3, //!< bus source: read disk status register + bs_kwd_read_kdata = bs_task_4 //!< bus source: read disk data register +}; + +//! F1 functions for disk word task +enum { + //!< f1 10: undefined + f1_kwd_strobe = f1_task_11, //!< f1 11: strobe + f1_kwd_load_kstat = f1_task_12, //!< f1 12: load kstat register + f1_kwd_increcno = f1_task_13, //!< f1 13: increment record number + f1_kwd_clrstat = f1_task_14, //!< f1 14: clear status register + f1_kwd_load_kcom = f1_task_15, //!< f1 15: load kcom register + f1_kwd_load_kadr = f1_task_16, //!< f1 16: load kadr register + f1_kwd_load_kdata = f1_task_17 //!< f1 17: load kdata register +}; + +//! F2 functions for disk word task +enum { + f2_kwd_init = f2_task_10, //!< f2 10: branches NEXT[5-9] on WDTASKACT && WDINIT + f2_kwd_rwc = f2_task_11, //!< f2 11: branches NEXT[8-9] on READ/WRITE/CHECK for record + f2_kwd_recno = f2_task_12, //!< f2 12: branches NEXT[8-9] on RECNO[0-1] + f2_kwd_xfrdat = f2_task_13, //!< f2 13: branches NEXT[9] on !SEEKONLY + f2_kwd_swrnrdy = f2_task_14, //!< f2 14: branches NEXT[9] on !SWRDY + f2_kwd_nfer = f2_task_15, //!< f2 15: branches NEXT[9] on !KFER + f2_kwd_strobon = f2_task_16 //!< f2 16: branches NEXT[9] on STROBE + //!< f2 17: undefined +}; + +void f1_early_kwd_block(); //!< F1 func: disable the disk word task +void init_kwd(int task = task_kwd); //!< initialize the disk word task +void exit_kwd(); //!< deinitialize the disk word task +void reset_kwd(); //!< reset the disk word task +#endif // _A2KWD_H_ +#endif // ALTO2_DEFINE_CONSTANTS diff --git a/src/devices/cpu/alto2/a2mem.c b/src/devices/cpu/alto2/a2mem.c new file mode 100644 index 00000000000..b84653ebdd9 --- /dev/null +++ b/src/devices/cpu/alto2/a2mem.c @@ -0,0 +1,877 @@ +// license:BSD-3-Clause +// copyright-holders:Juergen Buchmueller +/***************************************************************************** + * + * Xerox AltoII memory interface + * + *****************************************************************************/ +#include "alto2cpu.h" + +#define PUT_EVEN(dword,word) X_WRBITS(dword,32, 0,15,word) +#define GET_EVEN(dword) X_RDBITS(dword,32, 0,15) +#define PUT_ODD(dword,word) X_WRBITS(dword,32,16,31,word) +#define GET_ODD(dword) X_RDBITS(dword,32,16,31) + +#define GET_MESR_HAMMING(mesr) X_RDBITS(mesr,16,0,5) +#define PUT_MESR_HAMMING(mesr,val) X_WRBITS(mesr,16,0,5,val) +#define GET_MESR_PERR(mesr) X_RDBITS(mesr,16,6,6) +#define PUT_MESR_PERR(mesr,val) X_WRBITS(mesr,16,6,6,val) +#define GET_MESR_PARITY(mesr) X_RDBITS(mesr,16,7,7) +#define PUT_MESR_PARITY(mesr,val) X_WRBITS(mesr,16,7,7,val) +#define GET_MESR_SYNDROME(mesr) X_RDBITS(mesr,16,8,13) +#define PUT_MESR_SYNDROME(mesr,val) X_WRBITS(mesr,16,8,13,val) +#define GET_MESR_BANK(mesr) X_RDBITS(mesr,16,14,15) +#define PUT_MESR_BANK(mesr,val) X_WRBITS(mesr,16,14,15,val) + +#define GET_MECR_SPARE1(mecr,val) X_RDBITS(mecr,16,0,3) +#define PUT_MECR_SPARE1(mecr,val) X_WRBITS(mecr,16,0,3,val) +#define GET_MECR_TEST_CODE(mecr) X_RDBITS(mecr,16,4,10) +#define PUT_MECR_TEST_CODE(mecr,val) X_WRBITS(mecr,16,4,10,val) +#define GET_MECR_TEST_MODE(mecr) X_RDBITS(mecr,16,11,11) +#define PUT_MECR_TEST_MODE(mecr,val) X_WRBITS(mecr,16,11,11,val) +#define GET_MECR_INT_SBERR(mecr) X_RDBITS(mecr,16,12,12) +#define PUT_MECR_INT_SBERR(mecr,val) X_WRBITS(mecr,16,12,12,val) +#define GET_MECR_INT_DBERR(mecr) X_RDBITS(mecr,16,13,13) +#define PUT_MECR_INT_DBERR(mecr,val) X_WRBITS(mecr,16,13,13,val) +#define GET_MECR_ERRCORR(mecr) X_RDBITS(mecr,16,14,14) +#define PUT_MECR_ERRCORR(mecr,val) X_WRBITS(mecr,16,14,14,val) +#define GET_MECR_SPARE2(mecr) X_RDBITS(mecr,16,15,15) +#define PUT_MECR_SPARE2(mecr,val) X_WRBITS(mecr,16,15,15,val) + +/** + *
+ * AltoII Memory
+ *
+ * Address mapping
+ *
+ * The mapping of addresses to memory chips can be altered by the setting of
+ * the "memory configuration switch". This switch is located at the top of the
+ * backplane of the AltoII. If the switch is in the alternate position, the
+ * first and second 32K portions of memory are exchanged.
+ *
+ * The AltoII memory system is organized around 32-bit doublewords. Stored
+ * along with each doubleword is 6 bits of Hamming code and a Parity bit for
+ * a total of 39 bits:
+ *
+ *  bits 0-15   even data word
+ *  bits 16-31  odd data word
+ *  bits 32-37  Hamming code
+ *  bit 38      Parity bit
+ *
+ * Things are further complicated by the fact that two types of memory chips
+ * are used: 16K chips in machines with extended memory and 4K chips for all
+ * others.
+ *
+ * The bits in a 1-word deep slice of memory are called a group. A group
+ * contains 4K oder 16K doublewords, depending on the chip type. The bits of
+ * a group on a single board are called a subgroup. Thus a subgroup contains
+ * 10 of the 40 bits in a group. There are 8 subgroups on a memory board.
+ * Subgroups are numbered from the high 3 bits of the address; for 4K chips
+ * this means MAR[0-2]; for 16K chips (i.e., an Alto with extended memory)
+ * this means BANK,MAR[0]:
+ *
+ *  Subgroup    Chip Positions
+ *     7          81-90
+ *     6          71-80
+ *     5          61-70
+ *     4          51-60
+ *     3          41-50
+ *     2          31-40
+ *     1          21-30
+ *     0          11-20
+ *
+ * The location of the bits in group 0 is:
+ *
+ *  CARD 1          CARD2           CARD3           CARD4
+ *  32 24 16 08 00  33 25 17 09 01  34 26 18 10 02  35 27 19 11 03
+ *  36 28 20 12 04  37 29 21 13 05  38 30 22 14 06  xx 31 23 25 07
+ *
+ * Chips 15, 25, 35, 45, 65, 75 and 85 on board 4 aren't used. If you are out
+ * of replacement memory chips, you can use one of these, but then the board
+ * with the missing chips will only work in Slot 4.
+ *
+ *  o  WORD = 16 BITS
+ *  o  ACCESS -> 2 WORDS AT A TIME
+ *  o  -> 32 BITS + 6 BITS EC + PARITY + SPARE = 40 BITS
+ *  o  10 BITS/MODULE    80 DRAMS/MODULE
+ *  o  4 MODULES/ALTO   320 DRAMS/ALTO
+ *
+ *  ADDRESS A0-6, WE, CAS'
+ *      | TO ALL DEVICES
+ *      v
+ *      +-----------------------------------------+
+ *      | ^ 8 DEVICES (32K OR 128K FOR XM)        |
+ *      | |                                       | CARD 1
+ *     /| v  <------------ DATA OUT ---------->   |
+ *    / |  0   1   2   3   4   5   6   7   8   9  |
+ *   /  +-----------------------------------------+
+ *  |      H4  H0  28  24  20  16  12  8   4   0
+ *  |
+ *  |   +-----------------------------------------+
+ *  |  /|                                         | CARD 2
+ *  | / +-----------------------------------------+
+ * RAS     H5  H1  29  25  21  17  13  9   5   1
+ * 0-7
+ *  | \ +-----------------------------------------+
+ *  |  \|                                         | CARD 3
+ *  |   +-----------------------------------------+
+ *  |      P   H2  30  26  22  18  14  10  6   2
+ *   \
+ *    \ +-----------------------------------------+
+ *     \|                                         | CARD 4
+ *      +-----------------------------------------+
+ *         X   H3  31  27  23  19  15  11  7   3
+ *
+ *                 [  ODD WORD  ]  [ EVEN WORD ]
+ *
+ * 
+ * + * 32K x 10 STORAGE MODULE + * + * Table I + * + * +-------+-------+-------+---------------+-------+ + * |CIRCUIT| INPUT | SIGNAL| INVERTER | | + * | NO. | PINS | NAME | DEF?? ??? |RESIST.| + * +-------+-------+-------+---------------+-------+ + * | | 71 | RAS0 | A1 1 -> 2 | ?? R2 | + * | 1 +-------+-------+---------------+-------+ + * | | 110 | CS0 | A1 3 -> 4 | ?? R3 | + * +-------+-------+-------+---------------+-------+ + * | | 79 | RAS1 | A2 1 -> 2 | ?? R4 | + * | 2 +-------+-------+---------------+-------+ + * | | 110 | CS1 | A2 3 -> 4 | ?? R5 | + * +-------+-------+-------+---------------+-------+ + * | | 90 | RAS2 | A3 1 -> 2 | ?? R7 | + * | 3 +-------+-------+---------------+-------+ + * | | 110 | CS2 | A3 3 -> 4 | ?? R8 | + * +-------+-------+-------+---------------+-------+ + * | | 86 | RAS3 | A3 11 -> 10 | ?? R9 | + * | 4 +-------+-------+---------------+-------+ + * | | 110 | CS3 | A4 11 -> 10 | ?? R7 | + * +-------+-------+-------+---------------+-------+ + * | | 102 | RAS4 | A4 1 -> 2 | ?? R4 | + * | 5 +-------+-------+---------------+-------+ + * | | 110 | CS4 | A3 13 -> 12 | ?? R5 | + * +-------+-------+-------+---------------+-------+ + * | | 106 | RAS5 | A5 11 -> 10 | ?? R3 | + * | 6 +-------+-------+---------------+-------+ + * | | 110 | CS5 | A5 3 -> 4 | ?? R2 | + * +-------+-------+-------+---------------+-------+ + * | | 111 | RAS6 | A5 1 -> 2 | ?? R8 | + * | 7 +-------+-------+---------------+-------+ + * | | 110 | CS6 | A5 13 -> 12 | ?? R9 | + * +-------+-------+-------+---------------+-------+ + * | | 99 | RAS7 | A4 13 -> 12 | ?? R5 | + * | 8 +-------+-------+---------------+-------+ + * | | 110 | CS7 | A4 3 -> 4 | ?? R5 | + * +-------+-------+-------+---------------+-------+ + * + * Table II + * + * MEMORY CHIP REFERENCE DESIGNATOR + * + * CIRCUIT NO. + * ROW NO. 1 2 3 4 5 6 7 8 + * +-------+-------+-------+-------+-------+-------+-------+-------+-------+ + * | 1 | 15 20 | 25 30 | 35 40 | 45 50 | 55 60 | 65 70 | 75 80 | 85 90 | + * +-------+-------+-------+-------+-------+-------+-------+-------+-------+ + * | 2 | 14 19 | 24 29 | 34 39 | 44 49 | 54 59 | 64 69 | 64 79 | 84 89 | + * +-------+-------+-------+-------+-------+-------+-------+-------+-------+ + * | 3 | 13 18 | 23 28 | 33 38 | 43 48 | 53 58 | 63 68 | 73 78 | 83 88 | + * +-------+-------+-------+-------+-------+-------+-------+-------+-------+ + * | 4 | 12 17 | 22 27 | 32 37 | 42 47 | 52 57 | 62 67 | 72 77 | 82 87 | + * +-------+-------+-------+-------+-------+-------+-------+-------+-------+ + * | 5 | 11 16 | 21 26 | 31 36 | 41 46 | 52 56 | 61 66 | 71 76 | 81 86 | + * +-------+-------+-------+-------+-------+-------+-------+-------+-------+ + * + * + * The Hamming code generator: + * + * WDxx is write data bit xx. + * H(x) is Hammming code bit x. + * HC(x) is generated Hamming code bit x. + * HC(x/y) is an intermediate value. + * HC(x)A and HC(x)B are also intermediate values. + * + * Chips used are: + * 74S280 9-bit parity generator (A-I inputs, even and odd outputs) + * 74S135 EX-OR/EX-NOR gates (5 inputs, 2 outputs) + * 74S86 EX-OR gates (2 inputs, 1 output) + * + * chip A B C D E F G H I even odd + * --------------------------------------------------------------------------------- + * a75: WD01 WD04 WD08 WD11 WD15 WD19 WD23 WD26 WD30 --- HC(0)A + * a76: WD00 WD03 WD06 WD10 WD13 WD17 WD21 WD25 WD28 HC(0B1) --- + * a86: WD02 WD05 WD09 WD12 WD16 WD20 WD24 WD27 WD31 HC(1)A --- + * a64: WD01 WD02 WD03 WD07 WD08 WD09 WD10 WD14 WD15 --- HC(2)A + * a85: WD16 WD17 WD22 WD23 WD24 WD25 WD29 WD30 WD31 HC(2)B --- + * + * H(0) ^ HC(0)A ^ HC(0B1) -> HC(0) + * H(1) ^ HC(1)A ^ HC(0B1) -> HC(1) + * HC(2)A ^ HC(2)B ^ H(2) -> HC(2) + * H(0) ^ H(1) ^ H(2) -> H(0/2) + * + * chip A B C D E F G H I even odd + * --------------------------------------------------------------------------------- + * a66: WD04 WD05 WD06 WD07 WD08 WD09 WD10 H(3) 0 --- HC(3)A + * a84: WD18 WD19 WD20 WD21 WD22 WD23 WD24 WD25 0 HC(3/4) HCPA + * a63: WD11 WD12 WD13 WD14 WD15 WD16 WD17 H(4) 0 --- HC(4)A + * a87: WD26 WD27 WD28 WD29 WD30 WD31 H(5) 0 0 HC(5) HCPB + * + * HC(3)A ^ HC(3/4) -> HC(3) + * HC(4)A ^ HC(3/4) -> HC(4) + * + * WD00 ^ WD01 -> XX01 + * + * chip A B C D E F G H I even odd + * --------------------------------------------------------------------------------- + * a54: HC(3)A HC(4)A HCPA HCPB H(0/2) XX01 WD02 WD03 RP PERR --- + * a65: WD00 WD01 WD02 WD04 WD05 WD07 WD10 WD11 WD12 --- PCA + * a74: WD14 WD17 WD18 WD21 WD23 WD24 WD26 WD27 WD29 PCB --- + * + * PCA ^ PCB -> PC + * + * Whoa ;-) + *
+ */ +#if USE_HAMMING_CHECK + +#define WD(x) (1ul<<(31-x)) + +/* a75: WD01 WD04 WD08 WD11 WD15 WD19 WD23 WD26 WD30 --- HC(0)A */ +#define A75 (WD( 1)|WD( 4)|WD( 8)|WD(11)|WD(15)|WD(19)|WD(23)|WD(26)|WD(30)) + +/* a76: WD00 WD03 WD06 WD10 WD13 WD17 WD21 WD25 WD29 HC(0B1) --- */ +#define A76 (WD( 0)|WD( 3)|WD( 6)|WD(10)|WD(13)|WD(17)|WD(21)|WD(25)|WD(28)) + +/* a86: WD02 WD05 WD09 WD12 WD16 WD20 WD24 WD27 WD31 HC(1)A --- */ +#define A86 (WD( 2)|WD( 5)|WD( 9)|WD(12)|WD(16)|WD(20)|WD(24)|WD(27)|WD(31)) + +/* a64: WD01 WD02 WD03 WD07 WD08 WD09 WD10 WD14 WD15 --- HC(2)A */ +#define A64 (WD( 1)|WD( 2)|WD( 3)|WD( 7)|WD( 8)|WD( 9)|WD(10)|WD(14)|WD(15)) + +/* a85: WD16 WD17 WD22 WD23 WD24 WD25 WD29 WD30 WD31 HC(2)B --- */ +#define A85 (WD(16)|WD(17)|WD(22)|WD(23)|WD(24)|WD(25)|WD(29)|WD(30)|WD(31)) + +/* a66: WD04 WD05 WD06 WD07 WD08 WD09 WD10 H(3) 0 --- HC(3)A */ +#define A66 (WD( 4)|WD( 5)|WD( 6)|WD( 7)|WD( 8)|WD( 9)|WD(10)) + +/* a84: WD18 WD19 WD20 WD21 WD22 WD23 WD24 WD25 0 HC(3/4) HCPA */ +#define A84 (WD(18)|WD(19)|WD(20)|WD(21)|WD(22)|WD(23)|WD(24)|WD(25)) + +/* a63: WD11 WD12 WD13 WD14 WD15 WD16 WD17 H(4) 0 --- HC(4)A */ +#define A63 (WD(11)|WD(12)|WD(13)|WD(14)|WD(15)|WD(16)|WD(17)) + +/* a87: WD26 WD27 WD28 WD29 WD30 WD31 H(5) 0 0 HC(5) HCPB */ +#define A87 (WD(26)|WD(27)|WD(28)|WD(29)|WD(30)|WD(31)) + +/* a54: HC(3)A HC(4)A HCPA HCPB H(0/2) XX01 WD02 WD03 P PERR --- */ +#define A54 (WD( 2)|WD( 3)) + +/* a65: WD00 WD01 WD02 WD04 WD05 WD07 WD10 WD11 WD12 --- PCA */ +#define A65 (WD( 0)|WD( 1)|WD( 2)|WD( 4)|WD( 5)|WD( 7)|WD(10)|WD(11)|WD(12)) + +/* a74: WD14 WD17 WD18 WD21 WD23 WD24 WD26 WD27 WD29 PCB --- */ +#define A74 (WD(14)|WD(17)|WD(18)|WD(21)|WD(23)|WD(24)|WD(26)|WD(27)|WD(29)) + +#define H0(hpb) X_BIT(hpb,8,0) //!< get Hamming code bit 0 from hpb data (really bit 32) +#define H1(hpb) X_BIT(hpb,8,1) //!< get Hamming code bit 1 from hpb data (really bit 33) +#define H2(hpb) X_BIT(hpb,8,2) //!< get Hamming code bit 2 from hpb data (really bit 34) +#define H3(hpb) X_BIT(hpb,8,3) //!< get Hamming code bit 3 from hpb data (really bit 35) +#define H4(hpb) X_BIT(hpb,8,4) //!< get Hamming code bit 4 from hpb data (really bit 36) +#define H5(hpb) X_BIT(hpb,8,5) //!< get Hamming code bit 5 from hpb data (really bit 37) +#define RH(hpb) X_RDBITS(hpb,8,0,5) //!< get Hamming code from hpb data (bits 32 to 37) +#define RP(hpb) X_BIT(hpb,8,6) //!< get parity bit from hpb data (really bit 38) + +/** @brief return even parity of a (masked) 32 bit value */ +static __inline UINT8 parity_even(UINT32 val) +{ + val -= ((val >> 1) & 0x55555555); + val = (((val >> 2) & 0x33333333) + (val & 0x33333333)); + val = (((val >> 4) + val) & 0x0f0f0f0f); + val += (val >> 8); + val += (val >> 16); + return (val & 1); +} + +/** @brief return odd parity of a (masked) 32 bit value */ +#define parity_odd(val) (parity_even(val)^1) + +/** + * @brief lookup table to convert a Hamming syndrome into a bit number to correct + */ +static const int hamming_lut[64] = { + -1, -1, -1, 0, -1, 1, 2, 3, /* A69: HR(5):0 HR(4):0 HR(3):0 */ + -1, 4, 5, 6, 7, 8, 9, 10, /* A79: HR(5):0 HR(4):0 HR(3):1 */ + -1, 11, 12, 13, 14, 15, 16, 17, /* A67: HR(5):0 HR(4):1 HR(3):0 */ + -1, -1, -1, -1, -1, 1, -1, -1, /* non chip selected */ + -1, 26, 27, 28, 29, 30, 31, -1, /* A68: HR(5):1 HR(4):0 HR(3):0 */ + -1, -1, -1, -1, -1, 1, -1, -1, /* non chip selected */ + 18, 19, 20, 21, 22, 23, 24, 25, /* A78: HR(5):1 HR(4):1 HR(3):0 */ + -1, -1, -1, -1, -1, 1, -1, -1 /* non chip selected */ +}; + +/** + * @brief read or write a memory double-word and caluclate its Hamming code + * + * Hamming code generation according to the schematics described above. + * It's certainly overkill to do this on a modern PC, but I think we'll + * need it for perfect emulation anyways (Hamming code hardware checking). + * + * @param write non-zero if this is a memory write (don't check for error) + * @param dw_addr the double-word address + * @param dw_data the double-word data to write + * @return dw_data + */ +UINT32 alto2_cpu_device::hamming_code(int write, UINT32 dw_addr, UINT32 dw_data) +{ + register UINT8 hpb = write ? 0 : m_mem.hpb[dw_addr]; + register UINT8 hc_0_a; + register UINT8 hc_0b1; + register UINT8 hc_1_a; + register UINT8 hc_2_a; + register UINT8 hc_2_b; + register UINT8 hc_0; + register UINT8 hc_1; + register UINT8 hc_2; + register UINT8 h_0_2; + register UINT8 hc_3_a; + register UINT8 hc_3_4; + register UINT8 hcpa; + register UINT8 hc_4_a; + register UINT8 hc_3; + register UINT8 hc_4; + register UINT8 hc_5; + register UINT8 hcpb; + register UINT8 perr; + register UINT8 pca; + register UINT8 pcb; + register UINT8 pc; + register int syndrome; + + /* a75: WD01 WD04 WD08 WD11 WD15 WD19 WD23 WD26 WD30 --- HC(0)A */ + hc_0_a = parity_odd (dw_data & A75); + /* a76: WD00 WD03 WD06 WD10 WD13 WD17 WD21 WD25 WD29 HC(0B1) --- */ + hc_0b1 = parity_even(dw_data & A76); + /* a86: WD02 WD05 WD09 WD12 WD16 WD20 WD24 WD27 WD31 HC(1)A --- */ + hc_1_a = parity_even(dw_data & A86); + /* a64: WD01 WD02 WD03 WD07 WD08 WD09 WD10 WD14 WD15 --- HC(2)A */ + hc_2_a = parity_odd (dw_data & A64); + /* a85: WD16 WD17 WD22 WD23 WD24 WD25 WD29 WD30 WD31 HC(2)B --- */ + hc_2_b = parity_even(dw_data & A85); + + hc_0 = H0(hpb) ^ hc_0_a ^ hc_0b1; + hc_1 = H1(hpb) ^ hc_1_a ^ hc_0b1; + hc_2 = hc_2_a ^ hc_2_b ^ H2(hpb); + h_0_2 = H0(hpb) ^ H1(hpb) ^ H2(hpb); + + /* a66: WD04 WD05 WD06 WD07 WD08 WD09 WD10 H(3) 0 --- HC(3)A */ + hc_3_a = parity_odd ((dw_data & A66) ^ H3(hpb)); + /* a84: WD18 WD19 WD20 WD21 WD22 WD23 WD24 WD25 0 HC(3/4) HCPA */ + hcpa = parity_odd (dw_data & A84); + hc_3_4 = hcpa ^ 1; + /* a63: WD11 WD12 WD13 WD14 WD15 WD16 WD17 H(4) 0 --- HC(4)A */ + hc_4_a = parity_odd ((dw_data & A63) ^ H4(hpb)); + + /* a87: WD26 WD27 WD28 WD29 WD30 WD31 H(5) 0 0 HC(5) HCPB */ + hcpb = parity_odd ((dw_data & A87) ^ H5(hpb)); + hc_3 = hc_3_a ^ hc_3_4; + hc_4 = hc_4_a ^ hc_3_4; + hc_5 = hcpb ^ 1; + + syndrome = (hc_0<<5)|(hc_1<<4)|(hc_2<<3)|(hc_3<<2)|(hc_4<<1)|(hc_5); + + /* + * Note: Here I XOR all the non dw_data inputs into bit 0, + * which has the same effect as spreading them over some bits + * and then counting them... I hope ;-) + */ + /* a54: HC(3)A HC(4)A HCPA HCPB H(0/2) XX01 WD02 WD03 P PERR --- */ + perr = parity_even( + hc_3_a ^ + hc_4_a ^ + hcpa ^ + hcpb ^ + h_0_2 ^ + (X_RDBITS(dw_data,32,0,0) ^ X_RDBITS(dw_data,32,1,1)) ^ + (dw_data & A54) ^ + RP(hpb) ^ + 1); + + /* a65: WD00 WD01 WD02 WD04 WD05 WD07 WD10 WD11 WD12 --- PCA */ + pca = parity_odd (dw_data & A65); + /* a74: WD14 WD17 WD18 WD21 WD23 WD24 WD26 WD27 WD29 PCB --- */ + pcb = parity_even(dw_data & A74); + pc = pca ^ pcb; + + if (write) { + /* update the hamming code and parity bit store */ + m_mem.hpb[dw_addr] = (syndrome << 2) | (pc << 1); + return dw_data; + + } + + /** + *
+	 * A22 (74H30) 8-input NAND to check for error
+	 *  input   signal
+	 *  -------------------------
+	 *  1   POK = PERR'
+	 *  4   NER(08) = HC(0)'
+	 *  3   NER(09) = HC(1)'
+	 *  2   NER(10) = HC(2)'
+	 *  6   NER(11) = HC(3)'
+	 *  5   NER(12) = HC(4)'
+	 *  12  NER(13) = HC(5)'
+	 *  11  1 (VPUL3)
+	 *
+	 *  output  signal
+	 *  -------------------------
+	 *  8   ERROR
+	 *
+	 * Remembering De Morgan this can be simplified:
+	 * ERROR is 0, whenever all of PERR and HC(0) to HC(5) are 0.
+	 * Or the other way round: any of perr or syndrome non-zero means ERROR=1.
+	 * 
+ */ + if (perr || syndrome) { + /* latch data on the first error */ + if (!m_mem.error) { + m_mem.error = true; + PUT_MESR_HAMMING(m_mem.mesr, RH(hpb)); + PUT_MESR_PERR(m_mem.mesr, perr); + PUT_MESR_PARITY(m_mem.mesr, RP(hpb)); + PUT_MESR_SYNDROME(m_mem.mesr, syndrome); + PUT_MESR_BANK(m_mem.mesr, (dw_addr >> 15)); + /* latch memory address register */ + m_mem.mear = m_mem.mar & 0177777; + LOG((LOG_MEM,5," memory error at dword addr:%07o data:%011o check:%03o\n", dw_addr * 2, dw_data, hpb)); + LOG((LOG_MEM,6," MEAR: %06o\n", m_mem.mear)); + LOG((LOG_MEM,6," MESR: %06o\n", m_mem.mesr ^ 0177777)); + LOG((LOG_MEM,7," Hamming code read : %#o\n", GET_MESR_HAMMING(m_mem.mesr))); + LOG((LOG_MEM,7," Parity error : %o\n", GET_MESR_PERR(m_mem.mesr))); + LOG((LOG_MEM,7," Memory parity bit : %o\n", GET_MESR_PARITY(m_mem.mesr))); + LOG((LOG_MEM,7," Hamming syndrome : %#o (bit #%d)\n", GET_MESR_SYNDROME(m_mem.mesr), hamming_lut[GET_MESR_SYNDROME(m_mem.mesr)])); + LOG((LOG_MEM,7," Memory bank : %#o\n", GET_MESR_BANK(m_mem.mesr))); + LOG((LOG_MEM,6," MECR: %06o\n", m_mem.mecr ^ 0177777)); + LOG((LOG_MEM,7," Test Hamming code : %#o\n", GET_MECR_TEST_CODE(m_mem.mecr))); + LOG((LOG_MEM,7," Test mode : %s\n", GET_MECR_TEST_MODE(m_mem.mecr) ? "on" : "off")); + LOG((LOG_MEM,7," INT on single-bit err: %s\n", GET_MECR_INT_SBERR(m_mem.mecr) ? "on" : "off")); + LOG((LOG_MEM,7," INT on double-bit err: %s\n", GET_MECR_INT_DBERR(m_mem.mecr) ? "on" : "off")); + LOG((LOG_MEM,7," Error correction : %s\n", GET_MECR_ERRCORR(m_mem.mecr) ? "off" : "on")); + } + if (-1 == hamming_lut[syndrome]) { + /* double-bit error: wake task_part, if we're told so */ + if (GET_MECR_INT_DBERR(m_mem.mecr)) + m_task_wakeup |= 1 << task_part; + } else { + /* single-bit error: wake task_part, if we're told so */ + if (GET_MECR_INT_SBERR(m_mem.mecr)) + m_task_wakeup |= 1 << task_part; + /* should we correct the single bit error ? */ + if (0 == GET_MECR_ERRCORR(m_mem.mecr)) { + LOG((LOG_MEM,0," correct bit #%d addr:%07o data:%011o check:%03o\n", hamming_lut[syndrome], dw_addr * 2, dw_data, hpb)); + dw_data ^= 1ul << hamming_lut[syndrome]; + } + } + } + return dw_data; +} +#endif /* USE_HAMMING_CHECK */ + +/** + * @brief memory error address register read + * + * This register is a 'shadow MAR'; it holds the address of the + * first error since the error status was last reset. If no error + * has occurred, MEAR reports the address of the most recent + * memory access. Note that MEAR is set whenever an error of + * _any kind_ (single-bit or double-bit) is detected. + */ +READ16_MEMBER( alto2_cpu_device::mear_r ) +{ + int data = m_mem.error ? m_mem.mear : m_mem.mar; + if (!space.debugger_access()) { + LOG((LOG_MEM,2," MEAR read %07o\n", data)); + } + return data; +} + +/** + * @brief memory error status register read + * + * This register reports specifics of the first error that + * occurred since MESR was last reset. Storing anything into + * this register resets the error logic and enables it to + * detect a new error. Bits are "low true", i.e. if the bit + * is 0, the conidition is true. + *
+ * MESR[0-5]    Hamming code reported from error
+ * MESR[6]  Parity error
+ * MESR[7]  Memory parity bit
+ * MESR[8-13]   Syndrome bits
+ * MESR[14-15]  Bank number in which error occurred
+ * 
+ */ +READ16_MEMBER( alto2_cpu_device::mesr_r ) +{ + UINT16 data = m_mem.mesr ^ 0177777; + if (!space.debugger_access()) { + LOG((LOG_MEM,2," MESR read %07o\n", data)); + LOG((LOG_MEM,6," Hamming code read : %#o\n", GET_MESR_HAMMING(data))); + LOG((LOG_MEM,6," Parity error : %o\n", GET_MESR_PERR(data))); + LOG((LOG_MEM,6," Memory parity bit : %o\n", GET_MESR_PARITY(data))); +#if USE_HAMMING_CHECK + LOG((LOG_MEM,6," Hamming syndrome : %#o (bit #%d)\n", GET_MESR_SYNDROME(data), hamming_lut[GET_MESR_SYNDROME(data)])); +#else + LOG((LOG_MEM,6," Hamming syndrome : %#o\n", GET_MESR_SYNDROME(data))); +#endif + LOG((LOG_MEM,6," Memory bank : %#o\n", GET_MESR_BANK(data))); + } + return data; +} + +WRITE16_MEMBER( alto2_cpu_device::mesr_w ) +{ + if (!space.debugger_access()) { + LOG((LOG_MEM,2," MESR write %07o (clear MESR; was %07o)\n", data, m_mem.mesr)); + } + m_mem.mesr = 0; // set all bits to 0 + m_mem.error = 0; // reset the error flag + m_task_wakeup &= ~(1 << task_part); // clear the task wakeup for the parity error task +} + +/** + * @brief memory error control register write + * + * Storing into this register is the means for controlling + * the memory error logic. This register is set to all ones + * (disable all interrupts) when the alto is bootstrapped + * and when the parity error task first detects an error. + * When an error has occurred, MEAR and MESR should be read + * before setting MECR. Bits are "low true", i.e. a 0 bit + * enables the condition. + * + *
+ * MECR[0-3]    Spare
+ * MECR[4-10]   Test hamming code (used only for special diagnostics)
+ * MECR[11] Test mode (used only for special diagnostics)
+ * MECR[12] Cause interrupt on single-bit errors if zero
+ * MECR[13] Cause interrupt on double-bit errors if zero
+ * MECR[14] Do not use error correction if zero
+ * MECR[15] Spare
+ * 
+ */ +WRITE16_MEMBER( alto2_cpu_device::mecr_w ) +{ + m_mem.mecr = data ^ 0177777; + X_WRBITS(m_mem.mecr,16, 0, 3,0); + X_WRBITS(m_mem.mecr,16,15,15,0); + if (!space.debugger_access()) { + LOG((LOG_MEM,2," MECR write %07o\n", data)); + LOG((LOG_MEM,6," Test Hamming code : %#o\n", GET_MECR_TEST_CODE(m_mem.mecr))); + LOG((LOG_MEM,6," Test mode : %s\n", GET_MECR_TEST_MODE(m_mem.mecr) ? "on" : "off")); + LOG((LOG_MEM,6," INT on single-bit err: %s\n", GET_MECR_INT_SBERR(m_mem.mecr) ? "on" : "off")); + LOG((LOG_MEM,6," INT on double-bit err: %s\n", GET_MECR_INT_DBERR(m_mem.mecr) ? "on" : "off")); + LOG((LOG_MEM,6," Error correction : %s\n", GET_MECR_ERRCORR(m_mem.mecr) ? "off" : "on")); + } +} + +/** + * @brief memory error control register read + */ +READ16_MEMBER( alto2_cpu_device::mecr_r ) +{ + UINT16 data = m_mem.mecr ^ 0177777; + /* set all spare bits */ + if (!space.debugger_access()) { + LOG((LOG_MEM,2," MECR read %07o\n", data)); + LOG((LOG_MEM,6," Test Hamming code : %#o\n", GET_MECR_TEST_CODE(data))); + LOG((LOG_MEM,6," Test mode : %s\n", GET_MECR_TEST_MODE(data) ? "on" : "off")); + LOG((LOG_MEM,6," INT on single-bit err: %s\n", GET_MECR_INT_SBERR(data) ? "on" : "off")); + LOG((LOG_MEM,6," INT on double-bit err: %s\n", GET_MECR_INT_DBERR(data) ? "on" : "off")); + LOG((LOG_MEM,6," Error correction : %s\n", GET_MECR_ERRCORR(data) ? "off" : "on")); + } + return data; +} + +//! read i/o space RAM +READ16_MEMBER ( alto2_cpu_device::ioram_r ) +{ + offs_t dword_addr = offset / 2; + return static_cast(offset & 1 ? GET_ODD(m_mem.ram[dword_addr]) : GET_EVEN(m_mem.ram[dword_addr])); +} + +//! write i/o space RAM +WRITE16_MEMBER( alto2_cpu_device::ioram_w ) +{ + offs_t dword_addr = offset / 2; + if (offset & 1) + PUT_ODD(m_mem.ram[dword_addr], data); + else + PUT_EVEN(m_mem.ram[dword_addr], data); +} + +/** + * @brief load the memory address register with some value + * + * @param rsel selected register (to detect refresh cycles) + * @param addr memory address + */ +void alto2_cpu_device::load_mar(UINT8 rsel, UINT32 addr) +{ + if (rsel == 037) { + /* + * starting a memory refresh cycle + * currently we don't do anything special + */ + LOG((LOG_MEM,5, " MAR<-; refresh cycle @ %#o\n", addr)); + m_mem.mar = addr; + m_mem.access = ALTO2_MEM_REFRESH; + m_mem.cycle = cycle(); + return; + } + + m_mem.mar = addr; + if (addr < m_mem.size) { + LOG((LOG_MEM,2, " MAR<-; mar = %#o\n", addr)); + m_mem.access = ALTO2_MEM_RAM; + // fetch the memory double-word to the read/write latches + m_mem.rmdd = m_mem.wmdd = m_mem.ram[m_mem.mar/2]; + // keep track of the current CPU cycle + m_mem.cycle = cycle(); + } else { + m_mem.access = ALTO2_MEM_INVALID; + m_mem.rmdd = m_mem.wmdd = ~0; + } +} + +/** + * @brief read memory or memory mapped I/O from the address in mar to md + * + * @result returns value from memory (RAM or MMIO) + */ +UINT16 alto2_cpu_device::read_mem() +{ + UINT32 base_addr; + + if (ALTO2_MEM_NONE == m_mem.access) { + LOG((LOG_MEM,0," fatal: mem read with no preceding address\n")); + return 0177777; + } + + if (cycle() > m_mem.cycle + 4) { + LOG((LOG_MEM,0," fatal: mem read (MAR %#o) too late (+%lld cyc)\n", m_mem.mar, cycle() - m_mem.cycle)); + m_mem.access = ALTO2_MEM_NONE; + return 0177777; + } + + base_addr = m_mem.mar & 0177777; + if (base_addr >= ALTO2_IO_PAGE_BASE && m_mem.mar < ALTO2_RAM_SIZE) { + m_mem.md = m_iomem->read_word(m_iomem->address_to_byte(base_addr)); + LOG((LOG_MEM,6," MD = MMIO[%#o] (%#o)\n", base_addr, m_mem.md)); + m_mem.access = ALTO2_MEM_NONE; +#if ALTO2_DEBUG + watch_read(m_mem.mar, m_mem.md); +#endif + return m_mem.md; + } + +#if USE_HAMMING_CHECK + /* check for errors on the first access */ + if (!(m_mem.access & ALTO2_MEM_ODD)) + m_mem.rmdd = hamming_code(0, m_mem.mar/2, m_mem.rmdd); +#endif + m_mem.md = (m_mem.mar & ALTO2_MEM_ODD) ? GET_ODD(m_mem.rmdd) : GET_EVEN(m_mem.rmdd); + LOG((LOG_MEM,6," MD = RAM[%#o] (%#o)\n", m_mem.mar, m_mem.md)); + +#if ALTO2_DEBUG + watch_read(m_mem.mar, m_mem.md); +#endif + + if (m_mem.access & ALTO2_MEM_ODD) { + // after reading the odd word, reset the access flag + m_mem.access = ALTO2_MEM_NONE; + } else { + // after reading the even word word, toggle access flag (and address) to the odd word + m_mem.mar ^= ALTO2_MEM_ODD; + m_mem.access ^= ALTO2_MEM_ODD; + // extend the read succeeds window by one cycle + m_mem.cycle++; + } + return m_mem.md; +} + +/** + * @brief write memory or memory mapped I/O from md to the address in mar + * + * @param data data to write to RAM or MMIO + */ +void alto2_cpu_device::write_mem(UINT16 data) +{ + int base_addr; + + m_mem.md = data & 0177777; + if (ALTO2_MEM_NONE == m_mem.access) { + LOG((LOG_MEM,0," fatal: mem write with no preceding address\n")); + return; + } + + if (cycle() > m_mem.cycle + 4) { + LOG((LOG_MEM,0," fatal: mem write (MAR %#o, data %#o) too late (+%lld cyc)\n", m_mem.mar, data, cycle() - m_mem.cycle)); + m_mem.access = ALTO2_MEM_NONE; + return; + } + + base_addr = m_mem.mar & 0177777; + if (base_addr >= ALTO2_IO_PAGE_BASE && m_mem.mar < ALTO2_RAM_SIZE) { + m_iomem->write_word(m_iomem->address_to_byte(base_addr), m_mem.md); + LOG((LOG_MEM,6, " MMIO[%#o] = MD (%#o)\n", base_addr, m_mem.md)); + m_mem.access = ALTO2_MEM_NONE; +#if ALTO2_DEBUG + watch_write(m_mem.mar, m_mem.md); +#endif + return; + } + + LOG((LOG_MEM,6, " RAM[%#o] = MD (%#o)\n", m_mem.mar, m_mem.md)); + if (m_mem.mar & ALTO2_MEM_ODD) + PUT_ODD(m_mem.wmdd, m_mem.md); + else + PUT_EVEN(m_mem.wmdd, m_mem.md); + +#if USE_HAMMING_CHECK + if (m_mem.access & ALTO2_MEM_RAM) + m_mem.ram[m_mem.mar/2] = hamming_code(1, m_mem.mar/2, m_mem.wmdd); +#else + if (m_mem.access & ALTO2_MEM_RAM) + m_mem.ram[m_mem.mar/2] = m_mem.wmdd; +#endif + +#if ALTO2_DEBUG + watch_write(m_mem.mar, m_mem.md); +#endif + // Toggle the odd/even word access flag + // NB: don't reset mem.access to permit double word exchange + m_mem.mar ^= ALTO2_MEM_ODD; + m_mem.access ^= ALTO2_MEM_ODD; + // extend the write succeeds window by one cycle + m_mem.cycle++; +} + +/** + * @brief debugger interface to read memory + * + * @param addr address to read + * @return memory contents at address (16 bits) + */ +UINT16 alto2_cpu_device::debug_read_mem(UINT32 addr) +{ + space(AS_2).set_debugger_access(true); + int base_addr = addr & 0177777; + int data = 0177777; + if (base_addr >= ALTO2_IO_PAGE_BASE && addr < ALTO2_RAM_SIZE) { + data = m_iomem->read_word(m_iomem->address_to_byte(base_addr)); + } else { + data = (addr & ALTO2_MEM_ODD) ? GET_ODD(m_mem.ram[addr/2]) : GET_EVEN(m_mem.ram[addr/2]); + } + space(AS_2).set_debugger_access(false); + return data; +} + +/** + * @brief debugger interface to write memory + * + * @param addr address to write + * @param data data to write (16 bits used) + */ +void alto2_cpu_device::debug_write_mem(UINT32 addr, UINT16 data) +{ + space(AS_2).set_debugger_access(true); + int base_addr = addr & 0177777; + if (base_addr >= ALTO2_IO_PAGE_BASE && addr < ALTO2_RAM_SIZE) { + m_iomem->write_word(m_iomem->address_to_byte(base_addr), data); + } else if (addr & ALTO2_MEM_ODD) { + PUT_ODD(m_mem.ram[addr/2], data); + } else { + PUT_EVEN(m_mem.ram[addr/2], data); + } + space(AS_2).set_debugger_access(false); +} + +/** + * @brief initialize the memory system + * + * Zeroes the memory context, including RAM and installs dummy + * handlers for the memory mapped I/O area. + * Sets handlers for access to the memory error address, status, + * and control registers at 0177024 to 0177026. + */ +void alto2_cpu_device::init_memory() +{ + memset(&m_mem, 0, sizeof(m_mem)); + save_item(NAME(m_mem.mar)); + save_item(NAME(m_mem.rmdd)); + save_item(NAME(m_mem.wmdd)); + save_item(NAME(m_mem.md)); + save_item(NAME(m_mem.cycle)); + save_item(NAME(m_mem.access)); + save_item(NAME(m_mem.error)); + save_item(NAME(m_mem.mear)); + save_item(NAME(m_mem.mecr)); +} + +void alto2_cpu_device::exit_memory() +{ + // no need for this since it free on exit by itself + // if (m_mem.ram) { + // auto_free(machine(), m_mem.ram); + // m_mem.ram = 0; + // } + // if (m_mem.hpb) { + // auto_free(machine(), m_mem.hpb); + // m_mem.hpb = 0; + // } +} + +void alto2_cpu_device::reset_memory() +{ + if (m_mem.ram) { + auto_free(machine(), m_mem.ram); + m_mem.ram = 0; + } + if (m_mem.hpb) { + auto_free(machine(), m_mem.hpb); + m_mem.hpb = 0; + } + // allocate 64K or 128K words of main memory + ioport_port* config = ioport(":CONFIG"); + // config should be valid, unless the driver doesn't define it + if (config) + m_mem.size = config->read() & 1 ? ALTO2_RAM_SIZE : 2 * ALTO2_RAM_SIZE; + else + m_mem.size = ALTO2_RAM_SIZE; + logerror("Main memory %u KiB\n", static_cast(sizeof(UINT16) * m_mem.size / 1024)); + + m_mem.ram = auto_alloc_array_clear(machine(), UINT32, sizeof(UINT16) * m_mem.size); + m_mem.hpb = auto_alloc_array_clear(machine(), UINT8, sizeof(UINT16) * m_mem.size); + +#if USE_HAMMING_CHECK + // Initialize the hamming codes and parity bit + for (UINT32 addr = 0; addr < ALTO2_IO_PAGE_BASE; addr++) { + hamming_code(1, addr, 0); + hamming_code(1, 0200000 + addr, 0); + } +#endif + m_mem.mar = 0; + m_mem.rmdd = 0; + m_mem.wmdd = 0; + m_mem.md = 0; + m_mem.cycle = 0; + m_mem.access = 0; + m_mem.error = false; + m_mem.mear = 0; + m_mem.mesr = 0; + m_mem.mecr = 0; +} diff --git a/src/devices/cpu/alto2/a2mem.h b/src/devices/cpu/alto2/a2mem.h new file mode 100644 index 00000000000..c450693a22b --- /dev/null +++ b/src/devices/cpu/alto2/a2mem.h @@ -0,0 +1,138 @@ +// license:BSD-3-Clause +// copyright-holders:Juergen Buchmueller +/***************************************************************************** + * + * Xerox AltoII memory block (MEM) + * + *****************************************************************************/ +#ifdef ALTO2_DEFINE_CONSTANTS + +#define ALTO2_RAM_SIZE 0200000 //!< size of main memory in words +#define ALTO2_IO_PAGE_BASE 0177000 //!< base address of the memory mapped io range +#define ALTO2_IO_PAGE_SIZE 0001000 //!< size of the memory mapped io range + +#else // ALTO2_DEFINE_CONSTANTS +#ifndef _A2MEM_H_ +#define _A2MEM_H_ +//! memory access mode +enum { + ALTO2_MEM_NONE, + ALTO2_MEM_ODD = (1 << 0), + ALTO2_MEM_RAM = (1 << 1), + ALTO2_MEM_REFRESH = (1 << 2), + ALTO2_MEM_INVALID = (1 << 3) +}; + +struct { + UINT32 size; //!< main memory size (64K or 128K) + UINT32* ram; //!< main memory organized as double-words + UINT8* hpb; //!< Hamming Code bits (6) and Parity bits (1) per double word + UINT32 mar; //!< memory address register + UINT32 rmdd; //!< read memory data double-word + UINT32 wmdd; //!< write memory data double-word + UINT16 md; //!< memory data register + UINT64 cycle; //!< cycle when the memory address register was loaded + + /** + * @brief memory access under the way if non-zero + * 0: no memory access (MEM_NONE) + * 1: invalid + * 2: memory access even word (MEM_RAM) + * 3: memory access odd word (MEM_RAM | MEM_ODD) + */ + int access; + bool error; //!< non-zero after a memory error was detected + UINT32 mear; //!< memory error address register + UINT16 mesr; //!< memory error status register + UINT16 mecr; //!< memory error control register +} m_mem; + +/** + * @brief check if memory address register load is yet possible + * suspend if accessing RAM and previous MAR<- was less than 5 cycles ago + * + * 1. MAR<- ANY + * 2. REQUIRED + * 3. MD<- whatever + * 4. SUSPEND + * 5. SUSPEND + * 6. MAR<- ANY + * + * @return false, if memory address can be loaded + */ +inline bool check_mem_load_mar_stall(UINT8 rsel) { + if (ALTO2_MEM_NONE == m_mem.access) + return false; + return cycle() < m_mem.cycle+5; +} + +/** + * @brief check if memory read is yet possible + * MAR<- = cycle #1, earliest read at cycle #5, i.e. + 4 + * + * 1. MAR<- ANY + * 2. REQUIRED + * 3. SUSPEND + * 4. SUSPEND + * 5. whereever <-MD + * + * @return false, if memory can be read without wait cycle + */ +inline bool check_mem_read_stall() { + if (ALTO2_MEM_NONE == m_mem.access) + return false; + return cycle() < m_mem.cycle+4; +} + +/** + * @brief check if memory write is yet possible + * MAR<- = cycle #1, earliest write at cycle #3, i.e. + 2 + * + * 1. MAR<- ANY + * 2. REQUIRED + * 3. OPTIONAL + * 4. MD<- whatever + * + * @return false, if memory can be written without wait cycle + */ +inline bool check_mem_write_stall() { + if (ALTO2_MEM_NONE == m_mem.access) + return false; + return cycle() < m_mem.cycle+2; +} + + +DECLARE_READ16_MEMBER ( mear_r ); //!< memory error address register read +DECLARE_READ16_MEMBER ( mesr_r ); //!< memory error status register read +DECLARE_WRITE16_MEMBER( mesr_w ); //!< memory error status register write (clear) +DECLARE_READ16_MEMBER ( mecr_r ); //!< memory error control register read +DECLARE_WRITE16_MEMBER( mecr_w ); //!< memory error control register write + +//! read or write a memory double-word and caluclate its Hamming code +UINT32 hamming_code(int write, UINT32 dw_addr, UINT32 dw_data); + +//! load the memory address register with some value +void load_mar(UINT8 rsel, UINT32 addr); + +//! read memory or memory mapped I/O from the address in mar to md +UINT16 read_mem(); + +//! write memory or memory mapped I/O from md to the address in mar +void write_mem(UINT16 data); + +//! debugger interface to read memory +UINT16 debug_read_mem(UINT32 addr); + +//! debugger interface to write memory +void debug_write_mem(UINT32 addr, UINT16 data); + +#if ALTO2_DEBUG +void watch_write(UINT32 addr, UINT32 data); +void watch_read(UINT32 addr, UINT32 data); +#endif + +void init_memory(); //!< initialize the memory system +void exit_memory(); //!< deinitialize the memory system +void reset_memory(); //!< reset the memory system +#endif // _A2MEM_H_ +#endif // ALTO2_DEFINE_CONSTANTS diff --git a/src/devices/cpu/alto2/a2mouse.c b/src/devices/cpu/alto2/a2mouse.c new file mode 100644 index 00000000000..0844d45de6d --- /dev/null +++ b/src/devices/cpu/alto2/a2mouse.c @@ -0,0 +1,271 @@ +// license:BSD-3-Clause +// copyright-holders:Juergen Buchmueller +/***************************************************************************** + * + * Xerox AltoII mouse interface + * + *****************************************************************************/ +#include "alto2cpu.h" +#include "a2roms.h" + +#define MOUSE_DIRTY_HACK 0 + +enum { + MX1 = (1<<0), //!< MX1 signal is bit 0 (latch bit 1) + LMX1 = (1<<1), + MX2 = (1<<2), //!< MX2 signal is bit 2 (latch bit 3) + LMX2 = (1<<3), + MY1 = (1<<4), //!< MY1 signal is bit 4 (latch bit 5) + LMY1 = (1<<5), + MY2 = (1<<6), //!< MY2 signal is bit 6 (latch bit 7) + LMY2 = (1<<7), + MACTIVE = (MX1|MX2|MY1|MY2), //!< mask for the active bits + MLATCH = (LMX1|LMX2|LMY1|LMY2) //!< mask for the latched bits +}; + +/** + *
+ * The mouse inputs from the shutters are connected to a quad
+ * 2/3 input RS flip flop (SN74279).
+ *
+ *          74279
+ *       +---+--+---+
+ *       |   +--+   |
+ *   R1 -|1       16|- Vcc
+ *       |          |
+ *  S1a -|2       15|- S4
+ *       |          |
+ *  S1b -|3       14|- R4
+ *       |          |
+ *   Q1 -|4       13|- Q4
+ *       |          |
+ *   R2 -|5       12|- S3a
+ *       |          |
+ *   S2 -|6       11|- S3b
+ *       |          |
+ *   Q2 -|7       10|- R3
+ *       |          |
+ *  GND -|8        9|- Q3
+ *       |          |
+ *       +----------+
+ *
+ * The 'Y' Encoder signals are connected to IC1:
+ *  shutter pin(s)  R/S     output
+ *  ------------------------------------
+ *  0       2,3     S1a,b   Q1 MX2 -> 1
+ *  1       1       R1      Q1 MX2 -> 0
+ *  2       5       R2      Q2 MX1 -> 0
+ *  3       6       S2      Q2 MX1 -> 1
+ *
+ * The 'X' Encoder signals are connected to IC2:
+ *  shutter pin(s)  R/S     output
+ *  ------------------------------------
+ *  0       2,3     S1a,b   Q1 MY2 -> 1
+ *  1       1       R1      Q1 MY2 -> 0
+ *  2       5       R2      Q2 MY1 -> 0
+ *  3       6       S2      Q2 MY1 -> 1
+ *
+ *
+ * The pulse train generated by a left or up rotation is:
+ *
+ *             +---+   +---+   +---+
+ * MX1/MY1     |   |   |   |   |   |
+ *          ---+   +---+   +---+   +---
+ *
+ *           +---+   +---+   +---+   +-
+ * MX2/MY2   |   |   |   |   |   |   |
+ *          -+   +---+   +---+   +---+
+ *
+ *
+ * The pulse train generated by a right or down rotation is:
+ *
+ *           +---+   +---+   +---+   +-
+ * MX1/MY1   |   |   |   |   |   |   |
+ *          -+   +---+   +---+   +---+
+ *
+ *             +---+   +---+   +---+
+ * MX2/MY2     |   |   |   |   |   |
+ *          ---+   +---+   +---+   +---
+ *
+ * In order to simulate the shutter sequence for the mouse motions
+ * we have to generate a sequence of pulses on MX1/MX2 and MY1/MY2
+ * that have their phases shifted by 90 degree.
+ * 
+ */ + + +#define MOVEX(x) ((((x) < 0) ? MY2 : ((x) > 0) ? MY1 : 0)) +#define MOVEY(y) ((((y) < 0) ? MX2 : ((y) > 0) ? MX1 : 0)) +#define SIGN(a) ((a) < 0 ? -1 : (a) > 0 ? 1 : 0) + +/** + * @brief return the mouse motion flags + * + * Advance the mouse x and y coordinates to the dx and dy + * coordinates by either toggling MX2 or MX1 first for a + * y movement, or MY2 or MY1 for x movement. + * There are four read phases counted by m_mouse.phase + * + * @return lookup value from madr_a32 + */ +UINT16 alto2_cpu_device::mouse_read() +{ + UINT16 data; + + m_mouse.latch = (m_mouse.latch << 1) & MLATCH; + data = m_madr_a32[m_mouse.latch]; + + switch (m_mouse.phase) { + case 0: + m_mouse.latch |= MOVEX(m_mouse.dx - m_mouse.x); + m_mouse.latch |= MOVEY(m_mouse.dy - m_mouse.y); + break; + case 1: + m_mouse.latch |= MACTIVE; + m_mouse.x -= SIGN(m_mouse.x - m_mouse.dx); + m_mouse.y -= SIGN(m_mouse.y - m_mouse.dy); + break; + case 2: + m_mouse.latch ^= MOVEX(m_mouse.dx - m_mouse.x); + m_mouse.latch ^= MOVEY(m_mouse.dy - m_mouse.y); + break; + default: + m_mouse.latch &= ~MACTIVE; + m_mouse.x -= SIGN(m_mouse.x - m_mouse.dx); + m_mouse.y -= SIGN(m_mouse.y - m_mouse.dy); + } + m_mouse.phase = (m_mouse.phase + 1) % 4; + return data; +} + +/** + * @brief register a mouse motion in x direction + * @param ioport_field reference to the field + * @param param pointer passed in PORT_CHANGED_MEMBER last parameter + * @param oldval the old ioport_value + * @param newval the new ioport_value + */ +INPUT_CHANGED_MEMBER( alto2_cpu_device::mouse_motion_x ) +{ + // set new destination (absolute) mouse x coordinate + INT32 x = m_mouse.dx + newval - oldval; + x = x < 0 ? 0 : x > 605 ? 605 : x; + m_mouse.dx = x; +#if MOUSE_DIRTY_HACK + /* XXX: dirty, dirty, hack */ +#if USE_HAMMING_CHECK + m_mem.ram[0424/2] = hamming_code(1, 0424 / 2, (m_mouse.dx << 16) | m_mouse.dy); +#else + m_mem.ram[0424/2] = (m_mouse.dx << 16) | m_mouse.dy; +#endif +#endif +} + +/** + * @brief register a mouse motion in y direction + * @param ioport_field reference to the field + * @param param pointer passed in PORT_CHANGED_MEMBER last parameter + * @param oldval the old ioport_value + * @param newval the new ioport_value + */ +INPUT_CHANGED_MEMBER( alto2_cpu_device::mouse_motion_y ) +{ + // set new destination (absolute) mouse y coordinate + INT32 y = m_mouse.dy + newval - oldval; + y = y < 0 ? 0 : y > 807 ? 807 : y; + m_mouse.dy = y; +#if MOUSE_DIRTY_HACK + /* XXX: dirty, dirty, hack */ +#if USE_HAMMING_CHECK + m_mem.ram[0424/2] = hamming_code(1, 0424 / 2, (m_mouse.dx << 16) | m_mouse.dy); +#else + m_mem.ram[0424/2] = (m_mouse.dx << 16) | m_mouse.dy; +#endif +#endif +} + +/** + * @brief register a mouse button change + * + * convert button bit to UTILIN[13-15] + * + * @param ioport_field reference to the field + * @param param pointer passed in PORT_CHANGED_MEMBER last parameter + * @param oldval the old ioport_value + * @param newval the new ioport_value + */ +INPUT_CHANGED_MEMBER( alto2_cpu_device::mouse_button_0 ) +{ + X_WRBITS(m_hw.utilin,16,13,13,newval); +} + +INPUT_CHANGED_MEMBER( alto2_cpu_device::mouse_button_1 ) +{ + X_WRBITS(m_hw.utilin,16,14,14,newval); +} + +INPUT_CHANGED_MEMBER( alto2_cpu_device::mouse_button_2 ) +{ + X_WRBITS(m_hw.utilin,16,15,15,newval); +} + +static const prom_load_t pl_madr_a32 = +{ + "madr.a32", + 0, + "a0e3b4a7", + "24e50afdeb637a6a8588f8d3a3493c9188b8da2c", + /* size */ 0400, + /* amap */ AMAP_DEFAULT, + /* axor */ 0, + /* dxor */ 017, // invert D0-D3 + /* width */ 4, + /* shift */ 0, + /* dmap */ DMAP_REVERSE_0_3, // reverse D0-D3 to D3-D0 + /* dand */ ZERO, + /* type */ sizeof(UINT8) +}; + +/** + * @brief initialize the mouse context to useful values + * + * From the Alto Hardware Manual: + *
+ * The mouse is a hand-held pointing device which contains two encoders
+ * which digitize its position as it is rolled over a table-top. It also
+ * has three buttons which may be read as the three low order bits of
+ * memory location UTILIN (0177030), iin the manner of the keyboard.
+ * The bit/button correspondence in UTILIN are (depressed keys
+ * correspond to 0's in memory):
+ *
+ *      UTILIN[13]      TOP or LEFT button (RED)
+ *      UTILIN[14]      BOTTOM or RIGHT button (BLUE)
+ *      UTILIN[15]      MIDDLE button (YELLOW)
+ *
+ * The mouse coordinates are maintained by the MRT microcode in locations
+ * MOUSELOC(0424)=X and MOUSELOC+1(0425)=Y in page one of the Alto memory.
+ * These coordinates are relative, i.e., the hardware only increments and
+ * decrements them. The resolution of the mouse is approximately 100 points
+ * per inch.
+ * 
+ */ +void alto2_cpu_device::init_mouse() +{ + memset(&m_mouse, 0, sizeof(m_mouse)); + m_madr_a32 = prom_load(machine(), &pl_madr_a32, memregion("madr_a32")->base()); +} + +void alto2_cpu_device::exit_mouse() +{ + // nothing to do yet +} + +void alto2_cpu_device::reset_mouse() +{ + m_mouse.x = 0; + m_mouse.y = 0; + m_mouse.dx = 0; + m_mouse.dy = 0; + m_mouse.latch = 0; + m_mouse.phase = 0; +} diff --git a/src/devices/cpu/alto2/a2mouse.h b/src/devices/cpu/alto2/a2mouse.h new file mode 100644 index 00000000000..29d5e88ca5b --- /dev/null +++ b/src/devices/cpu/alto2/a2mouse.h @@ -0,0 +1,71 @@ +// license:BSD-3-Clause +// copyright-holders:Juergen Buchmueller +/***************************************************************************** + * + * Xerox AltoII mouse hardware (MOUSE) + * + *****************************************************************************/ +#ifdef ALTO2_DEFINE_CONSTANTS + +#else // ALTO2_DEFINE_CONSTANTS +#ifndef _A2MOUSE_H_ +#define _A2MOUSE_H_ +/** + * @brief PROM madr.a32 contains a lookup table to translate mouse motions + * + *
+ * The 4 mouse motion signals MX1, MX2, MY1, and MY2 are connected
+ * to a 256x4 PROM's (3601, SN74387) address lines A0, A2, A4, and A6.
+ * The previous (latched) state of the 4 signals is connected to the
+ * address lines A1, A3, A5, and A7.
+ *
+ *                  SN74387
+ *               +---+--+---+
+ *               |   +--+   |
+ *  MY2     A6  -|1       16|-  Vcc
+ *               |          |
+ *  LMY1    A5  -|2       15|-  A7     LMY2
+ *               |          |
+ *  MY1     A4  -|3       14|-  FE1'   0
+ *               |          |
+ *  LMX2    A3  -|4       13|-  FE2'   0
+ *               |          |
+ *  MX1     A0  -|5       12|-  D0     BUS[12]
+ *               |          |
+ *  LMX1    A1  -|6       11|-  D1     BUS[13]
+ *               |          |
+ *  MX2     A2  -|7       10|-  D2     BUS[14]
+ *               |          |
+ *         GND  -|8        9|-  D3     BUS[15]
+ *               |          |
+ *               +----------+
+ *
+ * A motion to the west will first toggle MX2, then MX1.
+ * sequence: 04 -> 0d -> 0b -> 02
+ * A motion to the east will first toggle MX1, then MX2.
+ * sequence: 01 -> 07 -> 0e -> 08
+ *
+ * A motion to the north will first toggle MY2, then MY1.
+ * sequence: 40 -> d0 -> b0 -> 20
+ * A motion to the south will first toggle MY1, then MY2.
+ * sequence: 10 -> 70 -> e0 -> 80
+ * 
+ */ +UINT8* m_madr_a32; + +//! mouse context +struct { + int x; //!< current X coordinate + int y; //!< current Y coordinate + int dx; //!< destination X coordinate (real mouse X) + int dy; //!< destination Y coordinate (real mouse Y) + UINT8 latch; //!< current latch value + UINT8 phase; //!< current read latch phase +} m_mouse; + +UINT16 mouse_read(); //!< return the mouse motion flags +void init_mouse(); //!< initialize the mouse context +void exit_mouse(); //!< deinitialize the mouse context +void reset_mouse(); //!< reset the mouse context +#endif // _A2MOUSE_H_ +#endif // ALTO2_DEFINE_CONSTANTS diff --git a/src/devices/cpu/alto2/a2mrt.c b/src/devices/cpu/alto2/a2mrt.c new file mode 100644 index 00000000000..c57cd85728f --- /dev/null +++ b/src/devices/cpu/alto2/a2mrt.c @@ -0,0 +1,45 @@ +// license:BSD-3-Clause +// copyright-holders:Juergen Buchmueller +/***************************************************************************** + * + * Xerox AltoII memory refresh task + * + *****************************************************************************/ +#include "alto2cpu.h" + +//! f1_mrt_block early: block the display word task +void alto2_cpu_device::f1_early_mrt_block() +{ + /* clear the wakeup for the memory refresh task */ + m_task_wakeup &= ~(1 << m_task); + LOG((LOG_MRT,2," BLOCK %s\n", task_name(m_task))); +} + +//! called by the CPU when MRT becomes active +void alto2_cpu_device::activate_mrt() +{ + m_task_wakeup &= ~(1 << m_task); + if (m_ewfct) + { + // The Ether task wants a wakeup, too + m_task_wakeup |= 1 << task_ether; + } +} + + //! memory refresh task slots initialization +void alto2_cpu_device::init_mrt(int task) +{ + set_f1(task, f1_block, &alto2_cpu_device::f1_early_mrt_block, 0); + /* auto block */ + m_active_callback[task] = &alto2_cpu_device::activate_mrt; +} + +void alto2_cpu_device::exit_mrt() +{ + // nothing to do yet +} + +void alto2_cpu_device::reset_mrt() +{ + // nothing to do yet +} diff --git a/src/devices/cpu/alto2/a2mrt.h b/src/devices/cpu/alto2/a2mrt.h new file mode 100644 index 00000000000..20b00724fc9 --- /dev/null +++ b/src/devices/cpu/alto2/a2mrt.h @@ -0,0 +1,19 @@ +// license:BSD-3-Clause +// copyright-holders:Juergen Buchmueller +/***************************************************************************** + * + * Xerox AltoII memory refresh task (MRT) + * + *****************************************************************************/ +#ifdef ALTO2_DEFINE_CONSTANTS + +#else // ALTO2_DEFINE_CONSTANTS +#ifndef _A2MRT_H_ +#define _A2MRT_H_ +void f1_early_mrt_block(); //!< F1 func: block the display word task +void activate_mrt(); //!< called by the CPU when MRT becomes active +void init_mrt(int task = task_mrt); //!< initialize the memory refresh task +void exit_mrt(); //!< deinitialize the memory refresh task +void reset_mrt(); //!< reset the memory refresh task +#endif // _A2MRT_H_ +#endif // ALTO2_DEFINE_CONSTANTS diff --git a/src/devices/cpu/alto2/a2part.c b/src/devices/cpu/alto2/a2part.c new file mode 100644 index 00000000000..ecf9da51ea5 --- /dev/null +++ b/src/devices/cpu/alto2/a2part.c @@ -0,0 +1,30 @@ +// license:BSD-3-Clause +// copyright-holders:Juergen Buchmueller +/***************************************************************************** + * + * Xerox AltoII parity task + * + *****************************************************************************/ +#include "alto2cpu.h" + +//! called by the CPU when the parity task becomes active +void alto2_cpu_device::activate_part() +{ + m_task_wakeup &= ~(1 << m_task); +} + +//! parity task slots initialization +void alto2_cpu_device::init_part(int task) +{ + m_active_callback[task] = &alto2_cpu_device::activate_part; +} + +void alto2_cpu_device::exit_part() +{ + // nothing to do yet +} + +void alto2_cpu_device::reset_part() +{ + // nothing to do yet +} diff --git a/src/devices/cpu/alto2/a2part.h b/src/devices/cpu/alto2/a2part.h new file mode 100644 index 00000000000..0bc8583bbbc --- /dev/null +++ b/src/devices/cpu/alto2/a2part.h @@ -0,0 +1,18 @@ +// license:BSD-3-Clause +// copyright-holders:Juergen Buchmueller +/***************************************************************************** + * + * Xerox AltoII parity task (PART) + * + *****************************************************************************/ +#ifdef ALTO2_DEFINE_CONSTANTS + +#else // ALTO2_DEFINE_CONSTANTS +#ifndef _A2PART_H_ +#define _A2PART_H_ +void activate_part(); +void init_part(int task = task_part); //!< initialize the parity task +void exit_part(); //!< deinitialize the parity task +void reset_part(); //!< reset the parity task +#endif // _A2PART_H_ +#endif // ALTO2_DEFINE_CONSTANTS diff --git a/src/devices/cpu/alto2/a2ram.c b/src/devices/cpu/alto2/a2ram.c new file mode 100644 index 00000000000..92986996270 --- /dev/null +++ b/src/devices/cpu/alto2/a2ram.c @@ -0,0 +1,438 @@ +// license:BSD-3-Clause +// copyright-holders:Juergen Buchmueller +/***************************************************************************** + * + * Xerox AltoII RAM related functions + * + *****************************************************************************/ +#include "alto2cpu.h" + +#define DEBUG_WRTRAM 0 //!< define to 1 to printf disassembled CRAM writes + +//! direct read access to the microcode CRAM +#define RD_CRAM(addr) (*reinterpret_cast(m_ucode_cram + addr * 4)) + +//! direct write access to the microcode CRAM +#define WR_CRAM(addr,data) do { \ + *reinterpret_cast(m_ucode_cram + addr * 4) = data; \ +} while (0) + +/** + * @brief read the microcode ROM/RAM halfword + * + * Note: HALFSEL is selecting the even (0) or odd (1) half of the + * microcode RAM 32-bit word. Here's how the demultiplexers (74298) + * u8, u18, u28 and u38 select the bits: + * + * SN74298 + * +---+-+---+ + * | +-+ | + * B2 -|1 16|- Vcc + * | | + * A2 -|2 15|- QA + * | | + * A1 -|3 14|- QB + * | | + * B1 -|4 13|- QC + * | | + * C2 -|5 12|- QD + * | | + * D2 -|6 11|- CLK + * | | + * D1 -|7 10|- SEL + * | | + * GND -|8 9|- C1 + * | | + * +---------+ + * + * chip out pin BUS in pin HSEL=0 in pin HSEL=1 + * -------------------------------------------------------------- + * u8 QA 15 0 A1 3 DRSEL(0)' A2 2 DF2(0) + * u8 QB 14 1 B1 4 DRSEL(1)' B2 1 DF2(1)' + * u8 QC 13 2 C1 9 DRSEL(2)' C2 5 DF2(2)' + * u8 QD 12 3 D1 7 DRSEL(3)' D2 6 DF2(3)' + * + * u18 QA 15 4 A1 3 DRSEL(4)' A2 2 LOADT' + * u18 QB 14 5 B1 4 DALUF(0)' B2 1 LOADL + * u18 QC 13 6 C1 9 DALUF(1)' C2 5 NEXT(00)' + * u18 QD 12 7 D1 7 DALUF(2)' D2 6 NEXT(01)' + * + * u28 QA 15 8 A1 3 DALUF(3)' A2 2 NEXT(02)' + * u28 QB 14 9 B1 4 DBS(0)' B2 1 NEXT(03)' + * u28 QC 13 10 C1 9 DBS(1)' C2 5 NEXT(04)' + * u28 QD 12 11 D1 7 DBS(2)' D2 6 NEXT(05)' + * + * u38 QA 15 12 A1 3 DF1(0) A2 2 NEXT(06)' + * u38 QB 14 13 B1 4 DF1(1)' B2 1 NEXT(07)' + * u38 QC 13 14 C1 9 DF1(2)' C2 5 NEXT(08)' + * u38 QD 12 15 D1 7 DF1(3)' D2 6 NEXT(09)' + * + * The HALFSEL signal to the demultiplexers is the inverted bit BUS(5): + * BUS(5)=1, HALFSEL=0, A1,B1,C1,D1 inputs, upper half of the 32-bit word + * BUS(5)=0, HALFSEL=1, A2,B2,C2,D2 inputs, lower half of the 32-bit word + */ +void alto2_cpu_device::rdram() +{ + UINT32 addr, value; + UINT32 bank = GET_CRAM_BANKSEL(m_cram_addr); + UINT32 wordaddr = GET_CRAM_WORDADDR(m_cram_addr); + + if (GET_CRAM_RAMROM(m_cram_addr)) { + /* read CROM 0 at current mpc */ + addr = m_mpc & ALTO2_UCODE_PAGE_MASK; + LOG((LOG_CPU,0," rdram: ROM [%05o] ", addr)); + } else { + /* read CRAM[bank] */ + addr = bank * ALTO2_UCODE_PAGE_SIZE + wordaddr; + LOG((LOG_CPU,0," rdram: RAM%d [%04o] ", bank, wordaddr)); + } + + m_rdram_flag = false; + if (ALTO2_UCODE_RAM_BASE + addr >= ALTO2_UCODE_SIZE) { + value = 0177777; /* ??? */ + LOG((LOG_CPU,0,"invalid address (%06o)\n", addr)); + return; + } + value = RD_CRAM(addr) ^ ALTO2_UCODE_INVERTED; + if (GET_CRAM_HALFSEL(m_cram_addr)) { + value = value >> 16; + LOG((LOG_CPU,0,"upper:%06o\n", value & 0177777)); + } else { + LOG((LOG_CPU,0,"lower:%06o\n", value & 0177777)); + } + m_bus &= value; +} + +/** + * @brief write the microcode RAM from M register and ALU + * + * Note: M is a latch (MYL, i.e. memory L) on the CRAM board that latches + * the ALU whenever LOADL and GOODTASK are met. GOODTASK is the Emulator + * task and something I have not yet found out about: TASKA' and TASKB'. + * + * There's also an undumped PROM u21 which is addressed by GOODTASK and + * 7 other signals... + */ +void alto2_cpu_device::wrtram() +{ + UINT32 bank = GET_CRAM_BANKSEL(m_cram_addr); + UINT32 wordaddr = GET_CRAM_WORDADDR(m_cram_addr); + UINT32 value = ((m_m << 16) | m_alu) ^ ALTO2_UCODE_INVERTED; + + UINT32 addr = bank * ALTO2_UCODE_PAGE_SIZE + wordaddr; // write RAM 0,1,2 + LOG((LOG_CPU,0," wrtram: RAM%d [%04o] upper:%06o lower:%06o", bank, wordaddr, m_m, m_alu)); + +#if DEBUG_WRTRAM + char buff[128]; + UINT8 oprom[4]; + oprom[0] = m_m / 256; + oprom[1] = m_m % 256; + oprom[2] = m_m / 256; + oprom[3] = m_m % 256; + disasm_disassemble(buff, addr, oprom, oprom, 0); + printf("WR CRAM_BANKSEL=%d RAM%d [%04o] upper:%06o lower:%06o *** %s\n", + GET_CRAM_BANKSEL(m_cram_addr), bank, wordaddr, m_m, m_alu, buff); +#endif + + m_wrtram_flag = false; + if (ALTO2_UCODE_RAM_BASE + addr >= ALTO2_UCODE_SIZE) { + LOG((LOG_CPU,0," invalid address %06o\n", addr)); + return; + } + LOG((LOG_CPU,0,"\n")); + WR_CRAM(addr, value); +} + +/** + * @brief bs_read_sreg early: drive bus by S register or M (MYL), if rsel is = 0 + * + * Note: RSEL == 0 can't be read, because it is decoded as + * access to the M register (MYL latch access, LREF' in the schematics) + */ +void alto2_cpu_device::bs_early_read_sreg() +{ + UINT16 r; + + if (m_d_rsel) { + UINT8 bank = m_s_reg_bank[m_task]; + r = m_s[bank][m_d_rsel]; + LOG((LOG_RAM,2," <-S%02o; bus &= S[%o][%02o] (%#o)\n", m_d_rsel, bank, m_d_rsel, r)); + } else { + r = m_m; + LOG((LOG_RAM,2," <-S%02o; bus &= M (%#o)\n", m_d_rsel, r)); + } + m_bus &= r; +} + +/** + * @brief bs_load_sreg early: load S register puts garbage on the bus + */ +void alto2_cpu_device::bs_early_load_sreg() +{ + int r = 0; /* ??? */ + LOG((LOG_RAM,2," S%02o<- BUS &= garbage (%#o)\n", m_d_rsel, r)); + m_bus &= r; +} + +/** + * @brief bs_load_sreg late: load S register from M + */ +void alto2_cpu_device::bs_late_load_sreg() +{ + UINT8 bank = m_s_reg_bank[m_task]; + m_s[bank][m_d_rsel] = m_m; + LOG((LOG_RAM,2," S%02o<- S[%o][%02o] := %#o\n", m_d_rsel, bank, m_d_rsel, m_m)); +} + +/** + * @brief branch to ROM page + */ +void alto2_cpu_device::branch_ROM(const char *from, int page) +{ + (void)from; + m_next2 = (m_next2 & ALTO2_UCODE_PAGE_MASK) + page * ALTO2_UCODE_PAGE_SIZE; + LOG((LOG_RAM,2," SWMODE: branch from %s to ROM%d (%#o)\n", from, page, m_next2)); +} + +/** + * @brief branch to RAM page + */ +void alto2_cpu_device::branch_RAM(const char *from, int page) +{ + (void)from; + m_next2 = (m_next2 & ALTO2_UCODE_PAGE_MASK) + ALTO2_UCODE_RAM_BASE + page * ALTO2_UCODE_PAGE_SIZE; + LOG((LOG_RAM,2," SWMODE: branch from %s to RAM%d\n", from, page, m_next2)); +} + +/** + * @brief f1_swmode early: switch to micro program counter BUS[6-15] in other bank + * + * Note: Jumping to uninitialized CRAM + * + * When jumping to uninitialized RAM, which, because of the inverted bits of the + * microcode words F1(0), F2(0) and LOADL, it is then read as F1=010 (SWMODE), + * F2=010 (BUSODD) and LOADL=1, loading the M register (MYL latch), too. + * This causes control to go back to the Emulator task at 0, because the + * NEXT[0-9] of uninitialized RAM is 0. + * + */ +void alto2_cpu_device::f1_late_swmode() +{ + /* currently executing in what page? */ + UINT16 current = m_mpc / ALTO2_UCODE_PAGE_SIZE; + +#if (ALTO2_UCODE_ROM_PAGES == 1 && ALTO2_UCODE_RAM_PAGES == 1) + switch (current) { + case 0: + branch_RAM("ROM0", 0); + break; + case 1: + branch_ROM("RAM0", 0); + break; + default: + fatal(1, "Impossible current mpc %d\n", current); + } +#endif +#if (ALTO2_UCODE_ROM_PAGES == 2 && ALTO2_UCODE_RAM_PAGES == 1) + UINT16 next = X_RDBITS(m_next2,10,1,1); + + switch (current) { + case 0: /* ROM0 to RAM0 or ROM1 */ + switch (next) { + case 0: + branch_RAM("ROM0", 0); + break; + case 1: + branch_ROM("ROM0", 1); + break; + default: + fatal(1, "Impossible next %d\n", next); + } + break; + case 1: /* ROM1 to ROM0 or RAM0 */ + switch (next) { + case 0: + branch_ROM("ROM1", 0); + break; + case 1: + branch_RAM("ROM1", 0); + break; + default: + fatal(1, "Impossible next %d\n", next); + } + break; + case 2: /* RAM0 to ROM0 or ROM1 */ + switch (next) { + case 0: + branch_ROM("RAM0", 0); + break; + case 1: + branch_ROM("RAM0", 1); + break; + default: + fatal(1, "Impossible next %d\n", next); + } + break; + default: + fatal(1, "Impossible current mpc %d\n", current); + } +#endif +#if (ALTO2_UCODE_ROM_PAGES == 1 && ALTO2_UCODE_RAM_PAGES == 3) + UINT16 next = X_RDBITS(m_next2,10,1,2); + + switch (current) { + case 0: /* ROM0 to RAM0, RAM2, RAM1, RAM0 */ + switch (next) { + case 0: + branch_RAM("ROM0", 0); + break; + case 1: + branch_RAM("ROM0", 2); + break; + case 2: + branch_RAM("ROM0", 1); + break; + case 3: + branch_RAM("ROM0", 0); + break; + default: + fatal(1, "Impossible next %d\n", next); + } + break; + case 1: /* RAM0 to ROM0, RAM2, RAM1, RAM1 */ + switch (next) { + case 0: + branch_ROM("RAM0", 0); + break; + case 1: + branch_RAM("RAM0", 2); + break; + case 2: + branch_RAM("RAM0", 1); + break; + case 3: + branch_RAM("RAM0", 1); + break; + default: + fatal(1, "Impossible next %d\n", next); + } + break; + case 2: /* RAM1 to ROM0, RAM2, RAM0, RAM0 */ + switch (next) { + case 0: + branch_ROM("RAM1", 0); + break; + case 1: + branch_RAM("RAM1", 2); + break; + case 2: + branch_RAM("RAM1", 0); + break; + case 3: + branch_RAM("RAM1", 0); + break; + default: + fatal(1, "Impossible next %d\n", next); + } + break; + case 3: /* RAM2 to ROM0, RAM1, RAM0, RAM0 */ + switch (next) { + case 0: + branch_ROM("RAM2", 0); + break; + case 1: + branch_RAM("RAM2", 1); + break; + case 2: + branch_RAM("RAM2", 0); + break; + case 3: + branch_RAM("RAM2", 0); + break; + default: + fatal(1, "Impossible next %d\n", next); + } + break; + default: + fatal(1, "Impossible current mpc %d\n", current); + } +#else + fatal(1, "Impossible control ROM/RAM combination %d/%d\n", ALTO2_UCODE_ROM_PAGES, ALTO2_UCODE_RAM_PAGES); +#endif +} + +/** + * @brief f1_wrtram late: start WRTRAM cycle + */ +void alto2_cpu_device::f1_late_wrtram() +{ + m_wrtram_flag = true; + LOG((LOG_RAM,2," WRTRAM\n")); +} + +/** + * @brief f1_rdram late: start RDRAM cycle + */ +void alto2_cpu_device::f1_late_rdram() +{ + m_rdram_flag = true; + LOG((LOG_RAM,2," RDRAM\n")); +} + +#if (ALTO2_UCODE_RAM_PAGES == 3) + +/** + * @brief f1_load_rmr late: load the reset mode register + * + * F1=013 corresponds to RMR<- in the emulator. In Altos with the 3K + * RAM option, F1=013 performs RMR<- in all RAM-related tasks, including + * the emulator. + */ +void alto2_cpu_device::f1_late_load_rmr() +{ + LOG((LOG_RAM,2," RMR<-; BUS (%#o)\n", m_bus)); + m_reset_mode = m_bus; +} +#else // ALTO2_UCODE_RAM_PAGES != 3 +/** + * @brief f1_load_srb late: load the S register bank from BUS[12-14] + */ +void alto2_cpu_device::f1_late_load_srb() +{ + m_s_reg_bank[m_task] = X_RDBITS(m_bus,16,12,14) % ALTO2_SREG_BANKS; + LOG((LOG_RAM,2," SRB<-; srb[%d] := %#o\n", m_task, m_s_reg_bank[m_task])); +} +#endif + +/** + * @brief RAM related task slots initialization + */ +void alto2_cpu_device::init_ram(int task) +{ + m_ram_related[task] = true; + + set_bs(task, bs_ram_read_slocation, &alto2_cpu_device::bs_early_read_sreg, 0); + set_bs(task, bs_ram_load_slocation, &alto2_cpu_device::bs_early_load_sreg, &alto2_cpu_device::bs_late_load_sreg); + + set_f1(task, f1_ram_swmode, 0, &alto2_cpu_device::f1_late_swmode); + set_f1(task, f1_ram_wrtram, 0, &alto2_cpu_device::f1_late_wrtram); + set_f1(task, f1_ram_rdram, 0, &alto2_cpu_device::f1_late_rdram); +#if (ALTO2_UCODE_RAM_PAGES == 3) + set_f1(task, f1_ram_load_rmr, 0, &alto2_cpu_device::f1_late_load_rmr); +#else // ALTO2_UCODE_RAM_PAGES != 3 + set_f1(task, f1_ram_load_srb, 0, &alto2_cpu_device::f1_late_load_srb); +#endif +} + +void alto2_cpu_device::exit_ram() +{ + // nothing to do yet +} + +void alto2_cpu_device::reset_ram() +{ + m_rdram_flag = false; + m_wrtram_flag = false; + m_m = 0; + memset(m_s, 0, sizeof(m_s)); +} diff --git a/src/devices/cpu/alto2/a2ram.h b/src/devices/cpu/alto2/a2ram.h new file mode 100644 index 00000000000..0077ded7a99 --- /dev/null +++ b/src/devices/cpu/alto2/a2ram.h @@ -0,0 +1,78 @@ +// license:BSD-3-Clause +// copyright-holders:Juergen Buchmueller +/***************************************************************************** + * + * Xerox AltoII RAM related tasks + * + *****************************************************************************/ +#ifdef ALTO2_DEFINE_CONSTANTS + +#if (ALTO2_CRAM_CONFIG==1) +#define ALTO2_UCODE_ROM_PAGES 1 //!< number of microcode ROM pages +#define ALTO2_UCODE_RAM_PAGES 1 //!< number of microcode RAM pages +#elif (ALTO2_CRAM_CONFIG==2) +#define ALTO2_UCODE_ROM_PAGES 2 //!< number of microcode ROM pages +#define ALTO2_UCODE_RAM_PAGES 1 //!< number of microcode RAM pages +#elif (ALTO2_CRAM_CONFIG==3) +#define ALTO2_UCODE_ROM_PAGES 1 //!< number of microcode ROM pages +#define ALTO2_UCODE_RAM_PAGES 3 //!< number of microcode RAM pages +#else +#error "Undefined CROM/CRAM configuration" +#endif + +/** + * \brief number of S register banks + * This depends on the number of RAM pages + * 8 pages in 3K CRAM configuration + * 1 page in 1K CRAM configurations + */ +#if (ALTO2_UCODE_RAM_PAGES == 3) +#define ALTO2_SREG_BANKS 8 +#else +#define ALTO2_SREG_BANKS 1 +#endif + +#define ALTO2_UCODE_PAGE_SIZE 02000 //!< number of words of microcode +#define ALTO2_UCODE_PAGE_MASK (ALTO2_UCODE_PAGE_SIZE-1) //!< mask for microcode ROM/RAM address +#define ALTO2_UCODE_SIZE ((ALTO2_UCODE_ROM_PAGES + ALTO2_UCODE_RAM_PAGES) * ALTO2_UCODE_PAGE_SIZE) //!< total number of words of microcode +#define ALTO2_UCODE_RAM_BASE (ALTO2_UCODE_ROM_PAGES * ALTO2_UCODE_PAGE_SIZE) //!< base offset for the RAM page(s) + +#else // ALTO2_DEFINE_CONSTANTS +#ifndef _A2RAM_H_ +#define _A2RAM_H_ +//! BUS source for RAM related tasks +enum { + bs_ram_read_slocation= bs_task_3, //!< ram related: read S register + bs_ram_load_slocation= bs_task_4 //!< ram related: load S register +}; + +//!< F1 functions for RAM related tasks +enum { + f1_ram_swmode = f1_task_10, //!< f1 10: switch mode to CROM/CRAM in same page + f1_ram_wrtram = f1_task_11, //!< f1 11: start WRTRAM cycle + f1_ram_rdram = f1_task_12, //!< f1 12: start RDRAM cycle +#if (ALTO2_UCODE_RAM_PAGES == 3) + f1_ram_load_rmr = f1_task_13, //!< f1 13: load the reset mode register +#else // ALTO2_UCODE_RAM_PAGES != 3 + f1_ram_load_srb = f1_task_13 //!< f1 14: load the S register bank from BUS[12-14] +#endif +}; + +void bs_early_read_sreg(); //!< bus source: drive bus by S register or M (MYL), if rsel is = 0 +void bs_early_load_sreg(); //!< bus source: load S register puts garbage on the bus +void bs_late_load_sreg(); //!< bus source: load S register from M +void branch_ROM(const char *from, int page); //!< branch to ROM page +void branch_RAM(const char *from, int page); //!< branch to RAM page +void f1_late_swmode(); //!< F1 func: switch to micro program counter BUS[6-15] in other bank +void f1_late_wrtram(); //!< F1 func: start WRTRAM cycle +void f1_late_rdram(); //!< F1 func: start RDRAM cycle +#if (ALTO2_UCODE_RAM_PAGES == 3) +void f1_late_load_rmr(); //!< F1 func: load the reset mode register +#else // ALTO2_UCODE_RAM_PAGES != 3 +void f1_late_load_srb(); //!< F1 func: load the S register bank from BUS[12-14] +#endif +void init_ram(int task); //!< called by RAM related tasks +void exit_ram(); //!< deinitialize the RAM related tasks +void reset_ram(); //!< reset the RAM related tasks +#endif // A2RAM_H +#endif // ALTO2_DEFINE_CONSTANTS diff --git a/src/devices/cpu/alto2/a2roms.c b/src/devices/cpu/alto2/a2roms.c new file mode 100644 index 00000000000..1b859aa07aa --- /dev/null +++ b/src/devices/cpu/alto2/a2roms.c @@ -0,0 +1,196 @@ +// license:BSD-3-Clause +// copyright-holders:Juergen Buchmueller +/***************************************************************************** + * + * Xerox AltoII PROM loading and decoding + * + *****************************************************************************/ +#include "alto2cpu.h" +#include "a2roms.h" + +#define DEBUG_PROM_LOAD 0 //!< define to 1 to dump PROMs after loading + +/** + * @brief return number of 1 bits in a 32 bit value + * + * 32-bit recursive reduction using SWAR, + * but first step is mapping 2-bit values + * into sum of 2 1-bit values in sneaky way. + */ +static UINT32 ones_u32(UINT32 val) +{ + val -= ((val >> 1) & 0x55555555); + val = (((val >> 2) & 0x33333333) + (val & 0x33333333)); + val = (((val >> 4) + val) & 0x0f0f0f0f); + val += (val >> 8); + val += (val >> 16); + return (val & 0x0000003f); +} + +/** + * @brief return the log2 of an integer value + */ +static UINT32 log2_u32(UINT32 val) +{ + val |= (val >> 1); + val |= (val >> 2); + val |= (val >> 4); + val |= (val >> 8); + val |= (val >> 16); + return ones_u32(val >> 1); +} + +/** + * @brief map a number of data or address lines using a lookup table + * + * @param map pointer to an array of values, or NULL for default + * @param lines number of data or address lines + * @param val value to map + * @result returns the remapped value, or just val, if map was NULL + */ +static UINT32 map_lines(const UINT8 *map, int lines, UINT32 val) +{ + if (NULL == map) + return val; + + UINT32 res = 0; + for (int i = 0; i < lines; i++) + if (val & (1 << i)) + res |= 1 << map[i]; + return res; +} + +/** + * @brief write to a ROM base + address of type 'type', ANDing with and, ORing with or + * + * @param base ROM base address in memory + * @param type one of 1 for UINT8, 2 for UINT16, 4 for UINT32 + * @param addr address offset into base + * @param dand value to AND to contents before XORing + * @param dxor value to XOR before writing back + */ +static void write_type_and_xor(void *base, int type, UINT32 addr, UINT32 dand, UINT32 dxor) +{ + switch (type) { + case sizeof(UINT8): + { + UINT8 *base8 = reinterpret_cast(base); + base8[addr] = (base8[addr] & dand) ^ dxor; + } + break; + case sizeof(UINT16): + { + UINT16 *base16 = reinterpret_cast(base); + base16[addr] = (base16[addr] & dand) ^ dxor; + } + break; + case sizeof(UINT32): + { + UINT32 *base32 = reinterpret_cast(base); + base32[addr] = (base32[addr] & dand) ^ dxor; + } + break; + default: + fatalerror("write_type_and_xor() invalid type size (%d) in ROM definitions\n", type); + } +} + +/** + * @brief load a PROM from a (list of) source region(s) shifting, swapping and inverting address and data bits + * @param prom PROM loading definition + * @param src source ROM region where to load data from + * @param pages number of pages of definitions + * @param segments number of segments in one page of the result + * @return pointer to the newly allocated memory filled with source bits + */ +UINT8* prom_load(running_machine& machine, const prom_load_t* prom, const UINT8* src, int pages, int segments) +{ + void* array = 0; + size_t type = prom->type; + size_t size = prom->size; +#if DEBUG_PROM_LOAD + UINT8 width = prom->width; +#endif + + switch (type) { + case sizeof(UINT8): + array = auto_alloc_array(machine, UINT8, pages * size); + break; + case sizeof(UINT16): + array = auto_alloc_array(machine, UINT16, pages * size); + break; + case sizeof(UINT32): + array = auto_alloc_array(machine, UINT32, pages * size); + break; + } + + UINT8* base = reinterpret_cast(array); + for (int page = 0; page < pages; page++) + { + UINT8* dst = base + (prom->type * prom->size * page); + for (int segment = 0; segment < segments; segment++, prom++) + { + for (UINT32 src_addr = 0; src_addr < prom->size; src_addr++) + { + // map destination address lines + UINT32 dst_addr = map_lines(prom->amap, log2_u32(prom->size) + 1, src_addr); + // fetch data bits + UINT32 data = src[src_addr ^ prom->axor] ^ prom->dxor; + // mask width bits + data = data & ((1 << prom->width) - 1); + // map destination data lines + data = map_lines(prom->dmap, prom->width, data); + // shift to destination position + data = data << prom->shift; + // and destination width dand then xor data + write_type_and_xor(dst, prom->type, dst_addr, prom->dand, data); + } + src += prom->size; + } + } + +#if DEBUG_PROM_LOAD + switch (type) { + case sizeof(UINT8): + { + UINT8* data = reinterpret_cast(array); + for (int addr = 0; addr < pages*size; addr++) { + if (0 == (addr % 16)) + printf("%04x:", addr); + if (width <= 4) + printf(" %x", data[addr]); + else + printf(" %02x", data[addr]); + if (15 == (addr % 16)) + printf("\n"); + } + } + break; + case sizeof(UINT16): + { + UINT16* data = reinterpret_cast(array); + for (int addr = 0; addr < pages*size; addr++) { + if (0 == (addr % 8)) + printf("%04x:", addr); + printf(" %04x", data[addr]); + if (7 == (addr % 8)) + printf("\n"); + } + } + break; + case sizeof(UINT32): + { + UINT32* data = reinterpret_cast(array); + for (int addr = 0; addr < pages*size; addr++) { + if (0 == (addr % 4)) + printf("%04x:", addr); + printf(" %08x", data[addr]); + if (3 == (addr % 4)) + printf("\n"); + } + } + break; + } +#endif + return reinterpret_cast(array); +} diff --git a/src/devices/cpu/alto2/a2roms.h b/src/devices/cpu/alto2/a2roms.h new file mode 100644 index 00000000000..abd218344c9 --- /dev/null +++ b/src/devices/cpu/alto2/a2roms.h @@ -0,0 +1,43 @@ +// license:BSD-3-Clause +// copyright-holders:Juergen Buchmueller +/***************************************************************************** + * + * Xerox AltoII RAM PROM loading and decoding + * + *****************************************************************************/ +#ifndef _CPU_A2ROMS_H_ +#define _CPU_A2ROMS_H_ + +#include "emu.h" + +/** + * @brief structure to define a ROM's or PROM's loading options + */ +typedef struct { + const char *name; //!< default filename of the ROM image + const char *altname; //!< alternate filename of the ROM image + const char *crc32; //!< CRC32 hash of the file + const char *sha1; //!< SHA1 hash of the file + size_t size; //!< size of the file, and elements in destination memory + const UINT8 amap[16]; //!< address bit mapping + UINT32 axor; //!< address XOR mask (applied to source address) + UINT32 dxor; //!< data XOR mask (applied before shifting and mapping) + UINT8 width; //!< width in bits + UINT8 shift; //!< left shift in bits + const UINT8 dmap[16]; //!< data bit mapping + UINT32 dand; //!< ANDing destination with this value, before XORing the data + size_t type; //!< type of the destination, i.e. sizeof(type) +} prom_load_t; + +#define ZERO 0 +#define KEEP ~0U + +#define AMAP_DEFAULT {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15} +#define AMAP_CONST_PROM {3,2,1,4,5,6,7,0,} +#define AMAP_REVERSE_0_7 {7,6,5,4,3,2,1,0,} + +#define DMAP_DEFAULT {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15} +#define DMAP_REVERSE_0_3 {3,2,1,0,} + +extern UINT8* prom_load(running_machine& machine, const prom_load_t* prom, const UINT8* src, int pages = 1, int segments = 1); +#endif // _CPU_A2ROMS_H_ diff --git a/src/devices/cpu/alto2/alto2cpu.c b/src/devices/cpu/alto2/alto2cpu.c new file mode 100644 index 00000000000..9c62096b5dd --- /dev/null +++ b/src/devices/cpu/alto2/alto2cpu.c @@ -0,0 +1,2816 @@ +// license:BSD-3-Clause +// copyright-holders:Juergen Buchmueller +/***************************************************************************** + * + * Xerox AltoII CPU core + * + *****************************************************************************/ +#include "alto2cpu.h" +#include "a2roms.h" + +#define DEBUG_UCODE_CONST_DATA 0 //!< define to 1 to dump decoded micro code and constants + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type ALTO2 = &device_creator; + +//************************************************************************** +// LOGGING AND DEBUGGING +//************************************************************************** +#if ALTO2_DEBUG +int g_log_types = LOG_DISK | LOG_ETH; +int g_log_level = 8; +bool g_log_newline = true; + +void logprintf(int type, int level, const char* format, ...) +{ + static const char* type_name[] = { + "[CPU]", + "[EMU]", + "[T01]", + "[T02]", + "[T03]", + "[KSEC]", + "[T05]", + "[T06]", + "[ETH]", + "[MRT]", + "[DWT]", + "[CURT]", + "[DHT]", + "[DVT]", + "[PART]", + "[KWD]", + "[T17]", + "[MEM]", + "[RAM]", + "[DRIVE]", + "[DISK]", + "[DISPL]", + "[MOUSE]", + "[HW]", + "[KBD]" + }; + if (!(g_log_types & type)) + return; + if (level > g_log_level) + return; + if (g_log_newline) { + // last line had a \n - print type name + for (int i = 0; i < sizeof(type_name)/sizeof(type_name[0]); i++) + if (type & (1 << i)) + logerror("%-7s ", type_name[i]); + } + va_list ap; + va_start(ap, format); + vlogerror(format, ap); + va_end(ap); + g_log_newline = format[strlen(format) - 1] == '\n'; +} +#endif + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +DEVICE_ADDRESS_MAP_START( ucode_map, 32, alto2_cpu_device ) + AM_RANGE(0, ALTO2_UCODE_RAM_BASE - 1) AM_READ ( crom_r ) + AM_RANGE(ALTO2_UCODE_RAM_BASE, ALTO2_UCODE_SIZE - 1) AM_READWRITE( cram_r, cram_w ) +ADDRESS_MAP_END + +DEVICE_ADDRESS_MAP_START( const_map, 16, alto2_cpu_device ) + AM_RANGE(0, ALTO2_CONST_SIZE - 1) AM_READ ( const_r ) +ADDRESS_MAP_END + +DEVICE_ADDRESS_MAP_START( iomem_map, 16, alto2_cpu_device ) + AM_RANGE(0, ALTO2_IO_PAGE_BASE - 1) AM_READWRITE( ioram_r, ioram_w ) + // page 0376 + AM_RANGE(0177000, 0177015) AM_READWRITE( noop_r, noop_w ) // UNUSED RANGE + AM_RANGE(0177016, 0177016) AM_READWRITE( utilout_r, utilout_w ) // UTILOUT register + AM_RANGE(0177017, 0177017) AM_READWRITE( noop_r, noop_w ) // unused range + AM_RANGE(0177020, 0177023) AM_READWRITE( xbus_r, xbus_w ) // XBUS[0-3] registers + AM_RANGE(0177024, 0177024) AM_READ ( mear_r ) // MEAR (memory error address register) + AM_RANGE(0177025, 0177025) AM_READWRITE( mesr_r, mesr_w ) // MESR (memory error status register) + AM_RANGE(0177026, 0177026) AM_READWRITE( mecr_r, mecr_w ) // MECR (memory error control register) + AM_RANGE(0177027, 0177027) AM_READWRITE( noop_r, noop_w ) // UNUSED RANGE + AM_RANGE(0177030, 0177033) AM_READ ( utilin_r ) // UTILIN register + AM_RANGE(0177034, 0177037) AM_READ ( kbd_ad_r ) // KBD_AD[0-3] matrix + AM_RANGE(0177040, 0177057) AM_READWRITE( bank_reg_r, bank_reg_w ) // BANK[0-17] registers (4 bit) + AM_RANGE(0177060, 0177077) AM_READWRITE( noop_r, noop_w ) // UNUSED RANGE + AM_RANGE(0177100, 0177101) AM_READWRITE( noop_r, noop_w ) // { Summagraphics tablet X, Y } + AM_RANGE(0177102, 0177137) AM_READWRITE( noop_r, noop_w ) // UNUSED RANGE + AM_RANGE(0177140, 0177157) AM_READWRITE( noop_r, noop_w ) // { Organ keyboard } + AM_RANGE(0177160, 0177177) AM_READWRITE( noop_r, noop_w ) // UNUSED RANGE + AM_RANGE(0177200, 0177204) AM_READWRITE( noop_r, noop_w ) // { PROM programmer } + AM_RANGE(0177205, 0177233) AM_READWRITE( noop_r, noop_w ) // UNUSED RANGE + AM_RANGE(0177234, 0177237) AM_READWRITE( noop_r, noop_w ) // { Experimental cursor control } + AM_RANGE(0177240, 0177257) AM_READWRITE( noop_r, noop_w ) // { Alto-II debugger } +// AM_RANGE(0177244, 0177247) AM_READWRITE( noop_r, noop_w ) // { Graphics keyboard } + AM_RANGE(0177260, 0177377) AM_READWRITE( noop_r, noop_w ) // UNUSED RANGE + // page 0377 +// AM_RANGE(0177400, 0177405) AM_READWRITE( noop_r, noop_w ) // { Maxc2 maintenance interface } + AM_RANGE(0177400, 0177400) AM_READWRITE( noop_r, noop_w ) // { Alto DLS input } + AM_RANGE(0177401, 0177417) AM_READWRITE( noop_r, noop_w ) // UNUSED RANGE + AM_RANGE(0177420, 0177420) AM_READWRITE( noop_r, noop_w ) // { "" } + AM_RANGE(0177421, 0177437) AM_READWRITE( noop_r, noop_w ) // UNUSED RANGE + AM_RANGE(0177440, 0177440) AM_READWRITE( noop_r, noop_w ) // { "" } + AM_RANGE(0177441, 0177457) AM_READWRITE( noop_r, noop_w ) // UNUSED RANGE + AM_RANGE(0177460, 0177460) AM_READWRITE( noop_r, noop_w ) // { "" } + AM_RANGE(0177461, 0177577) AM_READWRITE( noop_r, noop_w ) // UNUSED RANGE + AM_RANGE(0177600, 0177677) AM_READWRITE( noop_r, noop_w ) // { Alto DLS output } + AM_RANGE(0177700, 0177700) AM_READWRITE( noop_r, noop_w ) // { EIA interface output bit } + AM_RANGE(0177701, 0177701) AM_READWRITE( noop_r, noop_w ) // { EIA interface input bit } + AM_RANGE(0177702, 0177717) AM_READWRITE( noop_r, noop_w ) // UNUSED RANGE + AM_RANGE(0177720, 0177737) AM_READWRITE( noop_r, noop_w ) // { TV camera interface } + AM_RANGE(0177740, 0177763) AM_READWRITE( noop_r, noop_w ) // UNUSED RANGE + AM_RANGE(0177764, 0177773) AM_READWRITE( noop_r, noop_w ) // { Redactron tape drive } + AM_RANGE(0177774, 0177775) AM_READWRITE( noop_r, noop_w ) // UNUSED RANGE + AM_RANGE(0177776, 0177776) AM_READWRITE( noop_r, noop_w ) // { Digital-Analog Converter, Joystick } + AM_RANGE(0177777, 0177777) AM_READWRITE( noop_r, noop_w ) // { Digital-Analog Converter, Joystick } + + AM_RANGE(0200000, 0377777) AM_READWRITE( ioram_r, ioram_w ) +ADDRESS_MAP_END + +//------------------------------------------------- +// alto2_cpu_device - constructor +//------------------------------------------------- + +alto2_cpu_device::alto2_cpu_device(const machine_config& mconfig, const char* tag, device_t* owner, UINT32 clock) : + cpu_device(mconfig, ALTO2, "Xerox Alto-II", tag, owner, clock, "alto2_cpu", __FILE__), + m_ucode_config("ucode", ENDIANNESS_BIG, 32, 12, -2 ), + m_const_config("const", ENDIANNESS_BIG, 16, 8, -1 ), + m_iomem_config("iomem", ENDIANNESS_BIG, 16, 17, -1 ), + m_ucode_crom(0), + m_const_data(0), + m_icount(0), + m_task(0), + m_next_task(0), + m_next2_task(0), + m_mpc(0), + m_mir(0), + m_rsel(0), + m_d_rsel(0), + m_d_aluf(0), + m_d_bs(0), + m_d_f1(0), + m_d_f2(0), + m_d_loadt(0), + m_d_loadl(0), + m_next(0), + m_next2(0), + m_bus(0), + m_t(0), + m_alu(0), + m_aluc0(0), + m_l(0), + m_shifter(0), + m_laluc0(0), + m_m(0), + m_cram_addr(0), + m_task_wakeup(0), + m_reset_mode(0xffff), + m_rdram_flag(false), + m_wrtram_flag(false), + m_ether_enable(false), + m_ewfct(false), + m_dsp_time(0), + m_unload_time(0), + m_unload_word(0), + m_bitclk_time(0), + m_bitclk_index(0), + m_ctl2k_u3(0), + m_ctl2k_u38(0), + m_ctl2k_u76(0), + m_cram3k_a37(0), + m_madr_a64(0), + m_madr_a65(0), + m_madr_a90(0), + m_madr_a91(0), + m_cycle(0), + m_ether_id(0), + m_hw(), + m_mouse(), + m_dsk(), + m_dsp(), + m_disp_a38(0), + m_disp_a63(0), + m_disp_a66(0), + m_mem(), + m_emu(), + m_ether_a41(0), + m_ether_a42(0), + m_ether_a49(0), + m_eth() +{ + m_is_octal = true; + memset(m_task_mpc, 0x00, sizeof(m_task_mpc)); + memset(m_task_next2, 0x00, sizeof(m_task_next2)); + memset(m_r, 0x00, sizeof(m_r)); + memset(m_s, 0x00, sizeof(m_s)); + memset(m_active_callback, 0x00, sizeof(m_active_callback)); + memset(m_s_reg_bank, 0x00, sizeof(m_s_reg_bank)); + memset(m_bank_reg, 0x00, sizeof(m_bank_reg)); + memset(m_bs, 0x00, sizeof(m_bs)); + memset(m_f1, 0x00, sizeof(m_f1)); + memset(m_f2, 0x00, sizeof(m_f2)); + memset(m_ram_related, 0x00, sizeof(m_ram_related)); + memset(m_drive, 0x00, sizeof(m_drive)); + memset(m_sysclka0, 0x00, sizeof(m_sysclka0)); + memset(m_sysclka1, 0x00, sizeof(m_sysclka1)); + memset(m_sysclkb0, 0x00, sizeof(m_sysclkb0)); + memset(m_sysclkb1, 0x00, sizeof(m_sysclkb1)); +} + +alto2_cpu_device::~alto2_cpu_device() +{ + // call all subdevice's exit code + exit_kwd(); + exit_part(); + exit_dvt(); + exit_dht(); + exit_curt(); + exit_dwt(); + exit_mrt(); + exit_ether(); + exit_ksec(); + exit_emu(); + exit_hw(); + exit_mouse(); + exit_kbd(); + exit_disp(); + exit_disk(); + exit_memory(); +} + +//------------------------------------------------- +// driver interface to set diablo_hd_device +//------------------------------------------------- + +void alto2_cpu_device::set_diablo(int unit, diablo_hd_device* ptr) +{ + logerror("%s: unit=%d diablo_hd_device=%p\n", __FUNCTION__, unit, (void *) ptr); + m_drive[unit] = ptr; +} + +//------------------------------------------------- +// device_rom_region - device-specific (P)ROMs +//------------------------------------------------- + +ROM_START( alto2_cpu ) + ROM_REGION( 16 * 02000, "ucode_proms", 0 ) + ROM_LOAD( "55x.3", 0*02000, 0x400, CRC(de870d75) SHA1(2b98cc769d8302cb39948711424d987d94e4159b) ) //!< 00000-01777 RSEL(0)',RSEL(1)',RSEL(2)',RSEL(3)' + ROM_LOAD( "64x.3", 1*02000, 0x400, CRC(51b444c0) SHA1(8756e51f7f3253a55d75886465beb7ee1be6e1c4) ) //!< 00000-01777 RSEL(4)',ALUF(0)',ALUF(1)',ALUF(2)' + ROM_LOAD( "65x.3", 2*02000, 0x400, CRC(741d1437) SHA1(01f7cf07c2173ac93799b2475180bfbbe7e0149b) ) //!< 00000-01777 ALUF(3)',BS(0)',BS(1)',BS(2)' + ROM_LOAD( "63x.3", 3*02000, 0x400, CRC(f22d5028) SHA1(c65a42baef702d4aff2d9ad8e363daec27de6801) ) //!< 00000-01777 F1(0),F1(1)',F1(2)',F1(3)' + ROM_LOAD( "53x.3", 4*02000, 0x400, CRC(3c89a740) SHA1(95d812d489b2bde03884b2f126f961caa6c8ec45) ) //!< 00000-01777 F2(0),F2(1)',F2(2)',F2(3)' + ROM_LOAD( "60x.3", 5*02000, 0x400, CRC(a35de0bf) SHA1(7fa4aead44dcf5393bbfd1706c0ada24aa6fd3ac) ) //!< 00000-01777 LOADT',LOADL,NEXT(0)',NEXT(1)' + ROM_LOAD( "61x.3", 6*02000, 0x400, CRC(f25bcb2d) SHA1(acb57f3104a8dc4ba750dd1bf22ccc81cce9f084) ) //!< 00000-01777 NEXT(2)',NEXT(3)',NEXT(4)',NEXT(5)' + ROM_LOAD( "62x.3", 7*02000, 0x400, CRC(1b20a63f) SHA1(41dc86438e91c12b0fe42ffcce6b2ac2eb9e714a) ) //!< 00000-01777 NEXT(6)',NEXT(7)',NEXT(8)',NEXT(9)' + + // extended memory Mesa 5.1 micro code PROMs, 8 x 4bit + ROM_LOAD( "xm51.u54", 8*02000, 02000, CRC(11086ae9) SHA1(c394e3fadbfb91801ddc1a70cb25dc6f606c4f76) ) //!< 00000-01777 RSEL(0)',RSEL(1)',RSEL(2)',RSEL(3)' + ROM_LOAD( "xm51.u74", 9*02000, 02000, CRC(be8224f2) SHA1(ea9abcc3832b26a094319796901237e1e3f238b6) ) //!< 00000-01777 RSEL(4)',ALUF(0)',ALUF(1)',ALUF(2)' + ROM_LOAD( "xm51.u75", 10*02000, 02000, CRC(dfe3e3ac) SHA1(246fd29f92150a5d5d7627fbb4f2504c7b6cd5ec) ) //!< 00000-01777 ALUF(3)',BS(0)',BS(1)',BS(2)' + ROM_LOAD( "xm51.u73", 11*02000, 02000, CRC(6c20fa46) SHA1(a054330c65048011f12209aaed5c6da73d95f029) ) //!< 00000-01777 F1(0),F1(1)',F1(2)',F1(3)' + ROM_LOAD( "xm51.u52", 12*02000, 02000, CRC(0a31eec8) SHA1(4e2ad5daa5e6a6f2143ee4de00c7b625d096fb02) ) //!< 00000-01777 F2(0),F2(1)',F2(2)',F2(3)' + ROM_LOAD( "xm51.u70", 13*02000, 02000, CRC(5c64ee54) SHA1(0eb16d1b5e5967be7c1bf8c8ef6efdf0518a752c) ) //!< 00000-01777 LOADT',LOADL,NEXT(0)',NEXT(1)' + ROM_LOAD( "xm51.u71", 14*02000, 02000, CRC(7283bf71) SHA1(819fdcc407ed0acdd8f12b02db6efbcab7bec19a) ) //!< 00000-01777 NEXT(2)',NEXT(3)',NEXT(4)',NEXT(5)' + ROM_LOAD( "xm51.u72", 15*02000, 02000, CRC(a28e5251) SHA1(44dd8ad4ad56541b5394d30ce3521b4d1d561394) ) //!< 00000-01777 NEXT(6)',NEXT(7)',NEXT(8)',NEXT(9)' + + // constant PROMs, 4 x 4bit + // UINT16 src = BITS(addr, 3,2,1,4,5,6,7,0); + ROM_REGION( 4 * 0400, "const_proms", 0 ) + ROM_LOAD( "madr.a6", 0*00400, 00400, CRC(c2c196b2) SHA1(8b2a599ac839ec2a070dbfef2f1626e645c858ca) ) //!< 0000-0377 C(00)',C(01)',C(02)',C(03)' + ROM_LOAD( "madr.a5", 1*00400, 00400, CRC(42336101) SHA1(c77819cf40f063af3abf66ea43f17cc1a62e928b) ) //!< 0000-0377 C(04)',C(05)',C(06)',C(07)' + ROM_LOAD( "madr.a4", 2*00400, 00400, CRC(b957e490) SHA1(c72660ad3ada4ca0ed8697c6bb6275a4fe703184) ) //!< 0000-0377 C(08)',C(09)',C(10)',C(11)' + ROM_LOAD( "madr.a3", 3*00400, 00400, CRC(e0992757) SHA1(5c45ea824970663cb9ee672dc50861539c860249) ) //!< 0000-0377 C(12)',C(13)',C(14)',C(15)' + + // extended memory Mesa 4.1 (?) micro code PROMs, 8 x 4bit (unused) + ROM_REGION( 8 * 02000, "xm_mesa_4.1", 0 ) + ROM_LOAD( "xm654.41", 0*02000, 02000, CRC(beace302) SHA1(0002fea03a0261f57365095c4b87385d833f7063) ) //!< 00000-01777 RSEL(0)',RSEL(1)',RSEL(2)',RSEL(3)' + ROM_LOAD( "xm674.41", 1*02000, 02000, CRC(7db5c097) SHA1(364bc41951baa3ad274031bd49abec1cf5b7a980) ) //!< 00000-01777 RSEL(4)',ALUF(0)',ALUF(1)',ALUF(2)' + ROM_LOAD( "xm675.41", 2*02000, 02000, CRC(26eac1e7) SHA1(9220a1386afae8de96bdb2cf084afbadeeb61d42) ) //!< 00000-01777 ALUF(3)',BS(0)',BS(1)',BS(2)' + ROM_LOAD( "xm673.41", 3*02000, 02000, CRC(8173d7e3) SHA1(7fbacf6dccb60dfe9cef88a248c3a1660efddcf4) ) //!< 00000-01777 F1(0),F1(1)',F1(2)',F1(3)' + ROM_LOAD( "xm652.41", 4*02000, 02000, CRC(ddfa94bb) SHA1(38625e269400aaf38cd07b5dbf36c0087a0f1b92) ) //!< 00000-01777 F2(0),F2(1)',F2(2)',F2(3)' + ROM_LOAD( "xm670.41", 5*02000, 02000, CRC(1cd187f3) SHA1(0fd5eff7c6b5c2383aa20148a795b80286554675) ) //!< 00000-01777 LOADT',LOADL,NEXT(0)',NEXT(1)' + ROM_LOAD( "xm671.41", 6*02000, 02000, CRC(f21b1ad7) SHA1(1e18bdb35de7802892ac373c128f900786d40886) ) //!< 00000-01777 NEXT(2)',NEXT(3)',NEXT(4)',NEXT(5)' + ROM_LOAD( "xm672.41", 7*02000, 02000, CRC(110ee075) SHA1(bb72fceba5ce9e5e8c8a0024915006bdd011a3f3) ) //!< 00000-01777 NEXT(6)',NEXT(7)',NEXT(8)',NEXT(9)' + + ROM_REGION( 0400, "2kctl_u3", 0 ) + ROM_LOAD( "2kctl.u3", 00000, 00400, CRC(5f8d89e8) SHA1(487cd944ab074290aea73425e81ef4900d92e250) ) //!< 3601-1 256x4 BPROM; Emulator address modifier + + ROM_REGION( 0400, "2kctl_u38", 0 ) + ROM_LOAD( "2kctl.u38", 00000, 00040, CRC(fc51b1d1) SHA1(e36c2a12a5da377394264899b5ae504e2ffda46e) ) //!< 82S23 32x8 BPROM; task priority and initial address + + ROM_REGION( 0400, "2kctl_u76", 0 ) + ROM_LOAD( "2kctl.u76", 00000, 00400, CRC(1edef867) SHA1(928b8a15ac515a99109f32672441832173883b81) ) //!< 3601-1 256x4 BPROM; 2KCTL replacement for u51 (1KCTL) + + ROM_REGION( 0040, "alu_a10", 0 ) + ROM_LOAD( "alu.a10", 00000, 00040, CRC(e0857892) SHA1(dcd389767139f0acc1f87cf074459115abc5b90b) ) + + ROM_REGION( 0400, "3kcram_a37", 0 ) + ROM_LOAD( "3kcram.a37", 00000, 00400, CRC(9417360d) SHA1(bfcdbc56ee4ffafd0f2f672c0c869a55d6dd194b) ) + + ROM_REGION( 0400, "madr_a32", 0 ) + ROM_LOAD( "madr.a32", 00000, 00400, CRC(a0e3b4a7) SHA1(24e50afdeb637a6a8588f8d3a3493c9188b8da2c) ) //! P3601 256x4 BPROM; mouse motion signals MX1, MX2, MY1, MY2 + + ROM_REGION( 0400, "madr_a64", 0 ) + ROM_LOAD( "madr.a64", 00000, 00400, CRC(a66b0eda) SHA1(4d9088f592caa3299e90966b17765be74e523144) ) //! P3601 256x4 BPROM; memory addressing + + ROM_REGION( 0400, "madr_a65", 0 ) + ROM_LOAD( "madr.a65", 00000, 00400, CRC(ba37febd) SHA1(82e9db1cb65f451755295f0d179e6f8fe3349d4d) ) //! P3601 256x4 BPROM; memory addressing + + ROM_REGION( 0400, "madr_a90", 0 ) + ROM_LOAD( "madr.a90", 00000, 00400, CRC(7a2d8799) SHA1(c3760dba147740729d33b9b88e59088a4cc7437a) ) + + ROM_REGION( 0400, "madr_a91", 0 ) + ROM_LOAD( "madr.a91", 00000, 00400, CRC(dd556aeb) SHA1(900f333a091e3ccde0843019c25f25fba62e6023) ) + + ROM_REGION( 0400, "displ_a38", 0 ) + ROM_LOAD( "displ.a38", 00000, 00400, CRC(fd30beb7) SHA1(65e4a19ba4ff748d525122128c514abedd55d866) ) //!< P3601 256x4 BPROM; display FIFO control: STOPWAKE, MBEMPTY + + ROM_REGION( 0040, "displ_a63", 0 ) + ROM_LOAD( "displ.a63", 00000, 00040, CRC(82a20d60) SHA1(39d90703568be5419ada950e112d99227873fdea) ) //!< 82S23 32x8 BPROM; display HBLANK, HSYNC, SCANEND, HLCGATE ... + + ROM_REGION( 0400, "displ_a66", 0 ) + ROM_LOAD( "displ.a66", 00000, 00400, CRC(9f91aad9) SHA1(69b1d4c71f4e18103112e8601850c2654e9265cf) ) //!< P3601 256x4 BPROM; display VSYNC and VBLANK + + ROM_REGION( 0400, "ether_a41", 0 ) + ROM_LOAD( "enet.a41", 00000, 00400, CRC(d5de8d86) SHA1(c134a4c898c73863124361a9b0218f7a7f00082a) ) + + ROM_REGION( 0400, "ether_a42", 0 ) + ROM_LOAD( "enet.a42", 00000, 00400, CRC(9d5c81bd) SHA1(ac7e63332a3dad0bef7cd0349b24e156a96a4bf0) ) + + ROM_REGION( 0400, "ether_a49", 0 ) + ROM_LOAD( "enet.a49", 00000, 00400, CRC(4d2dcdb2) SHA1(583327a7d70cd02702c941c0e43c1e9408ff7fd0) ) +ROM_END + +const rom_entry *alto2_cpu_device::device_rom_region() const +{ + return ROM_NAME( alto2_cpu ); +} + +/** + * @brief list of microcode PROM loading options + */ +static const prom_load_t pl_ucode[] = { + { // 0000-01777 RSEL(0)',RSEL(1)',RSEL(2)',RSEL(3)' + "55x.3", + 0, + "de870d75", + "2b98cc769d8302cb39948711424d987d94e4159b", +/* size */ ALTO2_UCODE_PAGE_SIZE, +/* amap */ AMAP_DEFAULT, +/* axor */ ALTO2_UCODE_PAGE_MASK, +/* dxor */ 017, // invert D0-D3 +/* width */ 4, +/* shift */ 28, +/* dmap */ DMAP_DEFAULT, +/* dand */ ZERO, +/* type */ sizeof(UINT32) + }, + { // 0000-01777 RSEL(4)',ALUF(0)',ALUF(1)',ALUF(2)' + "64x.3", + 0, + "51b444c0", + "8756e51f7f3253a55d75886465beb7ee1be6e1c4", +/* size */ ALTO2_UCODE_PAGE_SIZE, +/* amap */ AMAP_DEFAULT, +/* axor */ ALTO2_UCODE_PAGE_MASK, +/* dxor */ 017, // invert D0-D3 +/* width */ 4, +/* shift */ 24, +/* dmap */ DMAP_DEFAULT, +/* dand */ KEEP, +/* type */ sizeof(UINT32) + }, + { // 0000-01777 ALUF(3)',BS(0)',BS(1)',BS(2)' + "65x.3", + 0, + "741d1437", + "01f7cf07c2173ac93799b2475180bfbbe7e0149b", +/* size */ ALTO2_UCODE_PAGE_SIZE, +/* amap */ AMAP_DEFAULT, +/* axor */ ALTO2_UCODE_PAGE_MASK, +/* dxor */ 017, // invert D0-D3 +/* width */ 4, +/* shift */ 20, +/* dmap */ DMAP_DEFAULT, +/* dand */ KEEP, +/* type */ sizeof(UINT32) + }, + { // 0000-01777 F1(0),F1(1)',F1(2)',F1(3)' + "63x.3", + 0, + "f22d5028", + "c65a42baef702d4aff2d9ad8e363daec27de6801", +/* size */ ALTO2_UCODE_PAGE_SIZE, +/* amap */ AMAP_DEFAULT, +/* axor */ ALTO2_UCODE_PAGE_MASK, +/* dxor */ 007, // keep D0, invert D1-D3 +/* width */ 4, +/* shift */ 16, +/* dmap */ DMAP_DEFAULT, +/* dand */ KEEP, +/* type */ sizeof(UINT32) + }, + { // 0000-01777 F2(0),F2(1)',F2(2)',F2(3)' + "53x.3", + 0, + "3c89a740", + "95d812d489b2bde03884b2f126f961caa6c8ec45", +/* size */ ALTO2_UCODE_PAGE_SIZE, +/* amap */ AMAP_DEFAULT, +/* axor */ ALTO2_UCODE_PAGE_MASK, +/* dxor */ 007, // keep D0, invert D1-D3 +/* width */ 4, +/* shift */ 12, +/* dmap */ DMAP_DEFAULT, +/* dand */ KEEP, +/* type */ sizeof(UINT32) + }, + { // 0000-01777 LOADT',LOADL,NEXT(0)',NEXT(1)' + "60x.3", + 0, + "a35de0bf", + "7fa4aead44dcf5393bbfd1706c0ada24aa6fd3ac", +/* size */ ALTO2_UCODE_PAGE_SIZE, +/* amap */ AMAP_DEFAULT, +/* axor */ ALTO2_UCODE_PAGE_MASK, +/* dxor */ 013, // invert D0 and D2-D3 +/* width */ 4, +/* shift */ 8, +/* dmap */ DMAP_DEFAULT, +/* dand */ KEEP, +/* type */ sizeof(UINT32) + }, + { // 0000-01777 NEXT(2)',NEXT(3)',NEXT(4)',NEXT(5)' + "61x.3", + 0, + "f25bcb2d", + "acb57f3104a8dc4ba750dd1bf22ccc81cce9f084", +/* size */ ALTO2_UCODE_PAGE_SIZE, +/* amap */ AMAP_DEFAULT, +/* axor */ ALTO2_UCODE_PAGE_MASK, +/* dxor */ 017, // invert D0-D3 +/* width */ 4, +/* shift */ 4, +/* dmap */ DMAP_DEFAULT, +/* dand */ KEEP, +/* type */ sizeof(UINT32) + }, + { // 0000-01777 NEXT(6)',NEXT(7)',NEXT(8)',NEXT(9)' + "62x.3", + 0, + "1b20a63f", + "41dc86438e91c12b0fe42ffcce6b2ac2eb9e714a", +/* size */ ALTO2_UCODE_PAGE_SIZE, +/* amap */ AMAP_DEFAULT, +/* axor */ ALTO2_UCODE_PAGE_MASK, +/* dxor */ 017, // invert D0-D3 +/* width */ 4, +/* shift */ 0, +/* dmap */ DMAP_DEFAULT, +/* dand */ KEEP, +/* type */ sizeof(UINT32) + } + +#if (ALTO2_UCODE_ROM_PAGES > 1) + , + { // 02000-03777 RSEL(0)',RSEL(1)',RSEL(2)',RSEL(3)' + "xm51.u54", + 0, + "11086ae9", + "c394e3fadbfb91801ddc1a70cb25dc6f606c4f76", +/* size */ ALTO2_UCODE_PAGE_SIZE, +/* amap */ AMAP_DEFAULT, +/* axor */ ALTO2_UCODE_PAGE_MASK, +/* dxor */ 017, // invert D0-D3 +/* width */ 4, +/* shift */ 28, +/* dmap */ DMAP_DEFAULT, +/* dand */ ZERO, +/* type */ sizeof(UINT32) + }, + { // 02000-03777 RSEL(4)',ALUF(0)',ALUF(1)',ALUF(2)' + "xm51.u74", + 0, + "be8224f2", + "ea9abcc3832b26a094319796901237e1e3f238b6", +/* size */ ALTO2_UCODE_PAGE_SIZE, +/* amap */ AMAP_DEFAULT, +/* axor */ ALTO2_UCODE_PAGE_MASK, +/* dxor */ 017, // invert D0-D3 +/* width */ 4, +/* shift */ 24, +/* dmap */ DMAP_DEFAULT, +/* dand */ KEEP, +/* type */ sizeof(UINT32) + }, + { // 02000-03777 ALUF(3)',BS(0)',BS(1)',BS(2)' + "xm51.u75", + 0, + "dfe3e3ac", + "246fd29f92150a5d5d7627fbb4f2504c7b6cd5ec", +/* size */ ALTO2_UCODE_PAGE_SIZE, +/* amap */ AMAP_DEFAULT, +/* axor */ ALTO2_UCODE_PAGE_MASK, +/* dxor */ 017, // invert D0-D3 +/* width */ 4, +/* shift */ 20, +/* dmap */ DMAP_DEFAULT, +/* dand */ KEEP, +/* type */ sizeof(UINT32) + }, + { // 02000-03777 F1(0),F1(1)',F1(2)',F1(3)' + "xm51.u73", + 0, + "6c20fa46", + "a054330c65048011f12209aaed5c6da73d95f029", +/* size */ ALTO2_UCODE_PAGE_SIZE, +/* amap */ AMAP_DEFAULT, +/* axor */ ALTO2_UCODE_PAGE_MASK, +/* dxor */ 007, // keep D0, invert D1-D3 +/* width */ 4, +/* shift */ 16, +/* dmap */ DMAP_DEFAULT, +/* dand */ KEEP, +/* type */ sizeof(UINT32) + }, + { // 02000-03777 F2(0),F2(1)',F2(2)',F2(3)' + "xm51.u52", + 0, + "0a31eec8", + "4e2ad5daa5e6a6f2143ee4de00c7b625d096fb02", +/* size */ ALTO2_UCODE_PAGE_SIZE, +/* amap */ AMAP_DEFAULT, +/* axor */ ALTO2_UCODE_PAGE_MASK, +/* dxor */ 007, // keep D0, invert D1-D3 +/* width */ 4, +/* shift */ 12, +/* dmap */ DMAP_DEFAULT, +/* dand */ KEEP, +/* type */ sizeof(UINT32) + }, + { // 02000-03777 LOADT',LOADL,NEXT(0)',NEXT(1)' + "xm51.u70", + 0, + "5c64ee54", + "0eb16d1b5e5967be7c1bf8c8ef6efdf0518a752c", +/* size */ ALTO2_UCODE_PAGE_SIZE, +/* amap */ AMAP_DEFAULT, +/* axor */ ALTO2_UCODE_PAGE_MASK, +/* dxor */ 013, // invert D0 and D2-D3 +/* width */ 4, +/* shift */ 8, +/* dmap */ DMAP_DEFAULT, +/* dand */ KEEP, +/* type */ sizeof(UINT32) + }, + { // 02000-03777 NEXT(2)',NEXT(3)',NEXT(4)',NEXT(5)' + "xm51.u71", + 0, + "7283bf71", + "819fdcc407ed0acdd8f12b02db6efbcab7bec19a", +/* size */ ALTO2_UCODE_PAGE_SIZE, +/* amap */ AMAP_DEFAULT, +/* axor */ ALTO2_UCODE_PAGE_MASK, +/* dxor */ 017, // invert D0-D3 +/* width */ 4, +/* shift */ 4, +/* dmap */ DMAP_DEFAULT, +/* dand */ KEEP, +/* type */ sizeof(UINT32) + }, + { // 02000-03777 NEXT(6)',NEXT(7)',NEXT(8)',NEXT(9)' + "xm51.u72", + 0, + "a28e5251", + "44dd8ad4ad56541b5394d30ce3521b4d1d561394", +/* size */ ALTO2_UCODE_PAGE_SIZE, +/* amap */ AMAP_DEFAULT, +/* axor */ ALTO2_UCODE_PAGE_MASK, +/* dxor */ 017, // invert D0-D3 +/* width */ 4, +/* shift */ 0, +/* dmap */ DMAP_DEFAULT, +/* dand */ KEEP, +/* type */ sizeof(UINT32) + } +#endif // (UCODE_ROM_PAGES > 1) +}; + +/** + * @brief list of constant PROM loading options + */ +static const prom_load_t pl_const[] = { + { // constant prom D0-D3 + "madr.a6", + "c3.3", + "c2c196b2", + "8b2a599ac839ec2a070dbfef2f1626e645c858ca", +/* size */ ALTO2_CONST_SIZE, +/* amap */ AMAP_CONST_PROM, // descramble constant address +/* axor */ 0, +/* dxor */ 017, // invert D0-D3 +/* width */ 4, +/* shift */ 0, +/* dmap */ DMAP_REVERSE_0_3, // reverse D0-D3 to D3-D0 +/* dand */ ZERO, +/* type */ sizeof(UINT16) + }, + { // constant prom D4-D7 + "madr.a5", + "c2.3", + "42336101", + "c77819cf40f063af3abf66ea43f17cc1a62e928b", +/* size */ ALTO2_CONST_SIZE, +/* amap */ AMAP_CONST_PROM, // descramble constant address +/* axor */ 0, +/* dxor */ 017, // invert D0-D3 +/* width */ 4, +/* shift */ 4, +/* dmap */ DMAP_REVERSE_0_3, // reverse D0-D3 to D3-D0 +/* dand */ KEEP, +/* type */ sizeof(UINT16) + }, + { // constant prom D8-D11 + "madr.a4", + "c1.3", + "b957e490", + "c72660ad3ada4ca0ed8697c6bb6275a4fe703184", +/* size */ ALTO2_CONST_SIZE, +/* amap */ AMAP_CONST_PROM, // descramble constant address +/* axor */ 0, +/* dxor */ 017, // invert D0-D3 +/* width */ 4, +/* shift */ 8, +/* dmap */ DMAP_REVERSE_0_3, // reverse D0-D3 to D3-D0 +/* dand */ KEEP, +/* type */ sizeof(UINT16) + }, + { // constant PROM D12-D15 + "madr.a3", + "c0.3", + "e0992757", + "5c45ea824970663cb9ee672dc50861539c860249", +/* size */ ALTO2_CONST_SIZE, +/* amap */ AMAP_CONST_PROM, // descramble constant address +/* axor */ 0, +/* dxor */ 017, // invert D0-D3 +/* width */ 4, +/* shift */ 12, +/* dmap */ DMAP_REVERSE_0_3, // reverse D0-D3 to D3-D0 +/* dand */ KEEP, +/* type */ sizeof(UINT16) + } +}; + +//! 3601-1 256x4 BPROM; Emulator address modifier +static const prom_load_t pl_2kctl_u3 = +{ + "2kctl.u3", + 0, + "5f8d89e8", + "487cd944ab074290aea73425e81ef4900d92e250", + /* size */ 0400, + /* amap */ AMAP_REVERSE_0_7, // reverse address lines A0-A7 + /* axor */ 0377, // invert address lines A0-A7 + /* dxor */ 017, // invert data lines D0-D3 + /* width */ 4, + /* shift */ 0, + /* dmap */ DMAP_DEFAULT, + /* dand */ ZERO, + /* type */ sizeof(UINT8) +}; + +//! 82S23 32x8 BPROM; task priority and initial address +static const prom_load_t pl_2kctl_u38 = +{ + "2kctl.u38", + 0, + "fc51b1d1", + "e36c2a12a5da377394264899b5ae504e2ffda46e", + /* size */ 0040, + /* amap */ AMAP_DEFAULT, + /* axor */ 0, + /* dxor */ 0, + /* width */ 8, + /* shift */ 0, + /* dmap */ DMAP_DEFAULT, + /* dand */ ZERO, + /* type */ sizeof(UINT8) +}; + +//! 3601-1 256x4 BPROM; 2KCTL replacement for u51 (1KCTL) +static const prom_load_t pl_2kctl_u76 = +{ + "2kctl.u76", + 0, + "1edef867", + "928b8a15ac515a99109f32672441832173883b81", + /* size */ 0400, + /* amap */ AMAP_DEFAULT, + /* axor */ 0077, // invert address lines A0-A5 + /* dxor */ 0, + /* width */ 4, + /* shift */ 0, + /* dmap */ DMAP_DEFAULT, + /* dand */ ZERO, + /* type */ sizeof(UINT8) +}; + +//! ALUF to ALU 741818 functions and carry in mapper +static const prom_load_t pl_alu_a10 = +{ + "alu.a10", + 0, + "e0857892", + "dcd389767139f0acc1f87cf074459115abc5b90b", + /* size */ 0040, + /* amap */ AMAP_DEFAULT, + /* axor */ 0, + /* dxor */ 0372, // invert D7-D3 and D1 + /* width */ 8, + /* shift */ 0, + /* dmap */ DMAP_DEFAULT, + /* dand */ ZERO, + /* type */ sizeof(UINT8) +}; + +static const prom_load_t pl_3kcram_a37 = +{ + "3kcram.a37", + 0, + "9417360d", + "bfcdbc56ee4ffafd0f2f672c0c869a55d6dd194b", + /* size */ 0400, + /* amap */ AMAP_DEFAULT, + /* axor */ 0, + /* dxor */ 017, // invert D0-D3 + /* width */ 4, + /* shift */ 0, + /* dmap */ DMAP_DEFAULT, + /* dand */ ZERO, + /* type */ sizeof(UINT8) +}; + +static const prom_load_t pl_madr_a90 = +{ + "madr.a90", + 0, + "7a2d8799", + "c3760dba147740729d33b9b88e59088a4cc7437a", + /* size */ 0400, + /* amap */ AMAP_DEFAULT, + /* axor */ 0, + /* dxor */ 017, // invert D0-D3 + /* width */ 4, + /* shift */ 0, + /* dmap */ DMAP_DEFAULT, + /* dand */ ZERO, + /* type */ sizeof(UINT8) +}; + +static const prom_load_t pl_madr_a91 = +{ + "madr.a91", + 0, + "dd556aeb", + "900f333a091e3ccde0843019c25f25fba62e6023", + /* size */ 0400, + /* amap */ AMAP_DEFAULT, + /* axor */ 0, + /* dxor */ 017, // invert D0-D3 + /* width */ 4, + /* shift */ 0, + /* dmap */ DMAP_DEFAULT, + /* dand */ ZERO, + /* type */ sizeof(UINT8) +}; + +//------------------------------------------------- +// device_memory_interface overrides +//------------------------------------------------- + +const address_space_config*alto2_cpu_device::memory_space_config(address_spacenum spacenum) const +{ + if (AS_0 == spacenum) + return &m_ucode_config; + if (AS_1 == spacenum) + return &m_const_config; + if (AS_2 == spacenum) + return &m_iomem_config; + return NULL; +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void alto2_cpu_device::device_start() +{ + // get a pointer to the IO address space + m_iomem = &space(AS_2); + + // decode ALTO2_UCODE_PAGES = 1 or 2 pages of micro code PROMs to CROM + m_ucode_crom = prom_load(machine(), pl_ucode, memregion("ucode_proms")->base(), ALTO2_UCODE_ROM_PAGES, 8); + + // allocate micro code CRAM + m_ucode_cram = auto_alloc_array(machine(), UINT8, sizeof(UINT32) * ALTO2_UCODE_RAM_PAGES * ALTO2_UCODE_PAGE_SIZE); + // fill with the micro code inverted bits value + for (offs_t offset = 0; offset < ALTO2_UCODE_RAM_PAGES * ALTO2_UCODE_PAGE_SIZE; offset++) + *reinterpret_cast(m_ucode_cram + offset * 4) = ALTO2_UCODE_INVERTED; + + // decode constant PROMs to m_const_data + m_const_data = prom_load(machine(), pl_const, memregion("const_proms")->base(), 1, 4); + + m_ctl2k_u3 = prom_load(machine(), &pl_2kctl_u3, memregion("2kctl_u3")->base()); + m_ctl2k_u38 = prom_load(machine(), &pl_2kctl_u38, memregion("2kctl_u38")->base()); + m_ctl2k_u76 = prom_load(machine(), &pl_2kctl_u76, memregion("2kctl_u76")->base()); + m_alu_a10 = prom_load(machine(), &pl_alu_a10, memregion("alu_a10")->base()); + m_cram3k_a37 = prom_load(machine(), &pl_3kcram_a37, memregion("3kcram_a37")->base()); + m_madr_a90 = prom_load(machine(), &pl_madr_a90, memregion("madr_a90")->base()); + m_madr_a91 = prom_load(machine(), &pl_madr_a91, memregion("madr_a91")->base()); + +#if 0 // dump ALU a10 PROM after loading + for (UINT8 i = 0; i < 32; i++) { + UINT8 a = m_alu_a10[i]; + printf("%03o: S3-S0:%u%u%u%u M:%u CI:%u T:%u ?:%u\n", + i, (a >> 7) & 1, (a >> 6) & 1, (a >> 5) & 1, (a >> 4) & 1, + (a >> 3) & 1, (a >> 2) & 1, (a >> 1) & 1, (a >> 0) & 1); + } +#endif + save_item(NAME(m_task_mpc)); + save_item(NAME(m_task_next2)); + save_item(NAME(m_task)); + save_item(NAME(m_next_task)); + save_item(NAME(m_next2_task)); + save_item(NAME(m_mpc)); + save_item(NAME(m_mir)); + save_item(NAME(m_rsel)); + save_item(NAME(m_next)); + save_item(NAME(m_next2)); + save_item(NAME(m_r)); + save_item(NAME(m_s)); + save_item(NAME(m_bus)); + save_item(NAME(m_t)); + save_item(NAME(m_alu)); + save_item(NAME(m_aluc0)); + save_item(NAME(m_l)); + save_item(NAME(m_shifter)); + save_item(NAME(m_laluc0)); + save_item(NAME(m_m)); + save_item(NAME(m_cram_addr)); + save_item(NAME(m_task_wakeup)); + save_item(NAME(m_reset_mode)); + save_item(NAME(m_rdram_flag)); + save_item(NAME(m_wrtram_flag)); + save_item(NAME(m_s_reg_bank)); + save_item(NAME(m_bank_reg)); + save_item(NAME(m_ether_enable)); + save_item(NAME(m_ewfct)); + save_item(NAME(m_dsp_time)); + save_item(NAME(m_unload_time)); + save_item(NAME(m_unload_word)); +#if (USE_BITCLK_TIMER == 0) + save_item(NAME(m_bitclk_time)); + save_item(NAME(m_bitclk_index)); +#endif + save_item(NAME(m_mouse.x)); + save_item(NAME(m_mouse.y)); + save_item(NAME(m_mouse.dx)); + save_item(NAME(m_mouse.dy)); + save_item(NAME(m_mouse.latch)); + + hard_reset(); + + state_add( A2_TASK, "TASK", m_task).callimport().formatstr("%6s"); + state_add( A2_MPC, "MPC", m_mpc).formatstr("%06O"); + state_add( A2_NEXT, "NEXT", m_next).formatstr("%06O"); + state_add( A2_NEXT2, "NEXT2", m_next2).formatstr("%06O"); + state_add( A2_BUS, "BUS", m_bus).formatstr("%06O"); + state_add( A2_T, "T", m_t).formatstr("%06O"); + state_add( A2_ALU, "ALU", m_alu).formatstr("%06O"); + state_add( A2_ALUC0, "ALUC0", m_aluc0).mask(1); + state_add( A2_L, "L", m_l).formatstr("%06O"); + state_add( A2_SHIFTER, "SHIFTER", m_shifter).formatstr("%06O"); + state_add( A2_LALUC0, "LALUC0", m_laluc0).mask(1); + state_add( A2_M, "M", m_m).formatstr("%06O"); + state_add_divider(-1); + state_add( A2_AC3, "AC(3)", m_r[000]).formatstr("%06O"); + state_add( A2_AC2, "AC(2)", m_r[001]).formatstr("%06O"); + state_add( A2_AC1, "AC(1)", m_r[002]).formatstr("%06O"); + state_add( A2_AC0, "AC(0)", m_r[003]).formatstr("%06O"); + state_add( A2_R04, "R04", m_r[004]).formatstr("%06O"); + state_add( A2_R05, "R05", m_r[005]).formatstr("%06O"); + state_add( A2_PC, "PC", m_r[006]).formatstr("%06O"); + state_add( A2_R07, "R07", m_r[007]).formatstr("%06O"); + state_add( A2_R10, "R10", m_r[010]).formatstr("%06O"); + state_add( A2_R11, "R11", m_r[011]).formatstr("%06O"); + state_add( A2_R12, "R12", m_r[012]).formatstr("%06O"); + state_add( A2_R13, "R13", m_r[013]).formatstr("%06O"); + state_add( A2_R14, "R14", m_r[014]).formatstr("%06O"); + state_add( A2_R15, "R15", m_r[015]).formatstr("%06O"); + state_add( A2_R16, "R16", m_r[016]).formatstr("%06O"); + state_add( A2_R17, "R17", m_r[017]).formatstr("%06O"); + state_add( A2_R20, "R20", m_r[020]).formatstr("%06O"); + state_add( A2_R21, "R21", m_r[021]).formatstr("%06O"); + state_add( A2_R22, "R22", m_r[022]).formatstr("%06O"); + state_add( A2_R23, "R23", m_r[023]).formatstr("%06O"); + state_add( A2_R24, "R24", m_r[024]).formatstr("%06O"); + state_add( A2_R25, "R25", m_r[025]).formatstr("%06O"); + state_add( A2_R26, "R26", m_r[026]).formatstr("%06O"); + state_add( A2_R27, "R27", m_r[027]).formatstr("%06O"); + state_add( A2_R30, "R30", m_r[030]).formatstr("%06O"); + state_add( A2_R31, "R31", m_r[031]).formatstr("%06O"); + state_add( A2_R32, "R32", m_r[032]).formatstr("%06O"); + state_add( A2_R33, "R33", m_r[033]).formatstr("%06O"); + state_add( A2_R34, "R34", m_r[034]).formatstr("%06O"); + state_add( A2_R35, "R35", m_r[035]).formatstr("%06O"); + state_add( A2_R36, "R36", m_r[036]).formatstr("%06O"); + state_add( A2_R37, "R37", m_r[037]).formatstr("%06O"); + state_add_divider(-1); + state_add( A2_S00, "R40", m_s[0][000]).formatstr("%06O"); + state_add( A2_S01, "R41", m_s[0][001]).formatstr("%06O"); + state_add( A2_S02, "R42", m_s[0][002]).formatstr("%06O"); + state_add( A2_S03, "R43", m_s[0][003]).formatstr("%06O"); + state_add( A2_S04, "R44", m_s[0][004]).formatstr("%06O"); + state_add( A2_S05, "R45", m_s[0][005]).formatstr("%06O"); + state_add( A2_S06, "R46", m_s[0][006]).formatstr("%06O"); + state_add( A2_S07, "R47", m_s[0][007]).formatstr("%06O"); + state_add( A2_S10, "R50", m_s[0][010]).formatstr("%06O"); + state_add( A2_S11, "R51", m_s[0][011]).formatstr("%06O"); + state_add( A2_S12, "R52", m_s[0][012]).formatstr("%06O"); + state_add( A2_S13, "R53", m_s[0][013]).formatstr("%06O"); + state_add( A2_S14, "R54", m_s[0][014]).formatstr("%06O"); + state_add( A2_S15, "R55", m_s[0][015]).formatstr("%06O"); + state_add( A2_S16, "R56", m_s[0][016]).formatstr("%06O"); + state_add( A2_S17, "R57", m_s[0][017]).formatstr("%06O"); + state_add( A2_S20, "R60", m_s[0][020]).formatstr("%06O"); + state_add( A2_S21, "R61", m_s[0][021]).formatstr("%06O"); + state_add( A2_S22, "R62", m_s[0][022]).formatstr("%06O"); + state_add( A2_S23, "R63", m_s[0][023]).formatstr("%06O"); + state_add( A2_S24, "R64", m_s[0][024]).formatstr("%06O"); + state_add( A2_S25, "R65", m_s[0][025]).formatstr("%06O"); + state_add( A2_S26, "R66", m_s[0][026]).formatstr("%06O"); + state_add( A2_S27, "R67", m_s[0][027]).formatstr("%06O"); + state_add( A2_S30, "R70", m_s[0][030]).formatstr("%06O"); + state_add( A2_S31, "R71", m_s[0][031]).formatstr("%06O"); + state_add( A2_S32, "R72", m_s[0][032]).formatstr("%06O"); + state_add( A2_S33, "R73", m_s[0][033]).formatstr("%06O"); + state_add( A2_S34, "R74", m_s[0][034]).formatstr("%06O"); + state_add( A2_S35, "R75", m_s[0][035]).formatstr("%06O"); + state_add( A2_S36, "R76", m_s[0][036]).formatstr("%06O"); + state_add( A2_S37, "R77", m_s[0][037]).formatstr("%06O"); + state_add_divider(-1); + state_add( A2_DRIVE, "DRIVE", m_dsk.drive).formatstr("%1u"); + state_add( A2_KADDR, "KADDR", m_dsk.kaddr).formatstr("%06O"); + state_add( A2_KADR, "KADR", m_dsk.kadr).formatstr("%06O"); + state_add( A2_KSTAT, "KSTAT", m_dsk.kstat).formatstr("%06O"); + state_add( A2_KCOM, "KCOM", m_dsk.kcom).formatstr("%06O"); + state_add( A2_KRECNO, "KRECNO", m_dsk.krecno).formatstr("%02O"); + state_add( A2_SHIFTIN, "SHIFTIN", m_dsk.shiftin).formatstr("%06O"); + state_add( A2_SHIFTOUT,"SHIFTOUT",m_dsk.shiftout).formatstr("%06O"); + state_add( A2_DATAIN, "DATAIN", m_dsk.datain).formatstr("%06O"); + state_add( A2_DATAOUT, "DATAOUT", m_dsk.dataout).formatstr("%06O"); + state_add( A2_KRWC, "KRWC", m_dsk.krwc).formatstr("%1u"); + state_add( A2_KFER, "KFER", m_dsk.kfer).formatstr("%1u"); + state_add( A2_WDTSKENA,"WDTSKENA",m_dsk.wdtskena).formatstr("%1u"); + state_add( A2_WDINIT0, "WDINIT0", m_dsk.wdinit0).formatstr("%1u"); + state_add( A2_WDINIT, "WDINIT", m_dsk.wdinit).formatstr("%1u"); + state_add( A2_STROBE, "STROBE", m_dsk.strobe).formatstr("%1u"); + state_add( A2_BITCLK, "BITCLK", m_dsk.bitclk).formatstr("%1u"); + state_add( A2_DATIN, "DATIN", m_dsk.datin).formatstr("%06O"); + state_add( A2_BITCNT, "BITCNT", m_dsk.bitcount).formatstr("%02O"); + state_add( A2_CARRY, "CARRY", m_dsk.carry).formatstr("%1u"); + state_add( A2_SECLATE, "SECLATE", m_dsk.seclate).formatstr("%1u"); + state_add( A2_SEEKOK, "SEEKOK", m_dsk.seekok).formatstr("%1u"); + state_add( A2_OKTORUN, "OKTORUN", m_dsk.ok_to_run).formatstr("%1u"); + state_add( A2_READY, "READY", m_dsk.kstat).formatstr("%1u"); + + state_add(STATE_GENPC, "curpc", m_mpc).formatstr("%03X").noshow(); + state_add(STATE_GENFLAGS, "GENFLAGS", m_aluc0).formatstr("%5s").noshow(); + + m_icountptr = &m_icount; +} + +//------------------------------------------------- +// state_string_export - export state as a string +// for the debugger +//------------------------------------------------- + +void alto2_cpu_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + switch (entry.index()) + { + case A2_TASK: + strprintf(str, "%s", task_name(m_task)); + break; + case STATE_GENFLAGS: + strprintf(str, "%s%s%s%s", + m_aluc0 ? "C":"-", + m_laluc0 ? "c":"-", + m_shifter == 0 ? "0":"-", + static_cast(m_shifter) < 0 ? "<":"-"); + break; + } +} + +//! read microcode CROM +READ32_MEMBER ( alto2_cpu_device::crom_r ) +{ + return *reinterpret_cast(m_ucode_crom + offset * 4); +} + +//! read microcode CRAM +READ32_MEMBER ( alto2_cpu_device::cram_r ) +{ + return *reinterpret_cast(m_ucode_cram + offset * 4); +} + +//! write microcode CRAM +WRITE32_MEMBER( alto2_cpu_device::cram_w ) +{ + *reinterpret_cast(m_ucode_cram + offset * 4) = data; +} + +//! read constants PROM +READ16_MEMBER ( alto2_cpu_device::const_r ) +{ + return *reinterpret_cast(m_const_data + offset * 2); +} + +//! direct read access to the microcode CROM or CRAM +#define RD_UCODE(addr) (addr < ALTO2_UCODE_RAM_BASE ? \ + *reinterpret_cast(m_ucode_crom + addr * 4) : \ + *reinterpret_cast(m_ucode_cram + (addr - ALTO2_UCODE_RAM_BASE) * 4)) + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void alto2_cpu_device::device_reset() +{ + soft_reset(); + // get the configured ethernet id + ioport_port* etherid = ioport(":ETHERID"); + if (etherid) + m_ether_id = etherid->read() & 0377; + // call all sub-devices' reset_... + reset_memory(); + reset_disp(); + reset_disk(); + reset_hw(); + reset_kbd(); + reset_mouse(); + + reset_emu(); + reset_ksec(); + reset_ether(); + reset_mrt(); + reset_dwt(); + reset_curt(); + reset_dht(); + reset_dvt(); + reset_part(); + reset_kwd();} + +/** + * @brief callback is called by the drive timer whenever a new sector starts + * + * @param unit the unit number + */ +static void disk_sector_start(void* cookie, int unit) +{ + alto2_cpu_device* cpu = reinterpret_cast(cookie); + cpu->next_sector(unit); +} + +void alto2_cpu_device::interface_post_reset() +{ + // set the disk unit sector callbacks + for (int unit = 0; unit < diablo_hd_device::DIABLO_UNIT_MAX; unit++) { + diablo_hd_device* dhd = m_drive[unit]; + dhd->set_sector_callback(this, &disk_sector_start); + } +} + +//------------------------------------------------- +// execute_set_input - act on a changed input/ +// interrupt line +//------------------------------------------------- + +// FIXME +void alto2_cpu_device::execute_set_input(int inputnum, int state) +{ +} + +void alto2_cpu_device::fatal(int exitcode, const char *format, ...) +{ + va_list ap; + va_start(ap, format); + emu_fatalerror error(exitcode, format, ap); + va_end(ap); +} + +/** @brief task names */ +const char* alto2_cpu_device::task_name(int task) +{ + switch (task) { + case 000: return "emu"; + case 001: return "task01"; + case 002: return "task02"; + case 003: return "task03"; + case 004: return "ksec"; + case 005: return "task05"; + case 006: return "task06"; + case 007: return "ether"; + case 010: return "mrt"; + case 011: return "dwt"; + case 012: return "curt"; + case 013: return "dht"; + case 014: return "dvt"; + case 015: return "part"; + case 016: return "kwd"; + case 017: return "task17"; + } + return "???"; +} + +/** @brief register names (as used by the microcode) */ +const char* alto2_cpu_device::r_name(UINT8 reg) +{ + switch (reg) { + case 000: return "ac(3)"; + case 001: return "ac(2)"; + case 002: return "ac(1)"; + case 003: return "ac(0)"; + case 004: return "nww"; + case 005: return "r05"; + case 006: return "pc"; + case 007: return "r07"; + case 010: return "xh"; + case 011: return "r11"; + case 012: return "ecntr"; + case 013: return "epntr"; + case 014: return "r14"; + case 015: return "r15"; + case 016: return "r16"; + case 017: return "r17"; + case 020: return "curx"; + case 021: return "curdata"; + case 022: return "cba"; + case 023: return "aecl"; + case 024: return "slc"; + case 025: return "mtemp"; + case 026: return "htab"; + case 027: return "ypos"; + case 030: return "dwa"; + case 031: return "kwdctw"; + case 032: return "cksumrw"; + case 033: return "knmarw"; + case 034: return "dcbr"; + case 035: return "dwax"; + case 036: return "mask"; + case 037: return "r37"; + } + return "???"; +} + +/** @brief ALU function names */ +const char* alto2_cpu_device::aluf_name(UINT8 aluf) +{ + switch (aluf) { + case 000: return "bus"; + case 001: return "t"; + case 002: return "bus or t"; + case 003: return "bus and t"; + case 004: return "bus xor t"; + case 005: return "bus + 1"; + case 006: return "bus - 1"; + case 007: return "bus + t"; + case 010: return "bus - t"; + case 011: return "bus - t - 1"; + case 012: return "bus + t + 1"; + case 013: return "bus + skip"; + case 014: return "bus, t"; + case 015: return "bus and not t"; + case 016: return "0 (undef)"; + case 017: return "0 (undef)"; + } + return "???"; +} + +/** @brief BUS source names */ +const char* alto2_cpu_device::bs_name(UINT8 bs) +{ + switch (bs) { + case 000: return "read_r"; + case 001: return "load_r"; + case 002: return "no_source"; + case 003: return "task_3"; + case 004: return "task_4"; + case 005: return "read_md"; + case 006: return "mouse"; + case 007: return "disp"; + } + return "???"; +} + +/** @brief F1 function names */ +const char* alto2_cpu_device::f1_name(UINT8 f1) +{ + switch (f1) { + case 000: return "nop"; + case 001: return "load_mar"; + case 002: return "task"; + case 003: return "block"; + case 004: return "l_lsh_1"; + case 005: return "l_rsh_1"; + case 006: return "l_lcy_8"; + case 007: return "const"; + case 010: return "task_10"; + case 011: return "task_11"; + case 012: return "task_12"; + case 013: return "task_13"; + case 014: return "task_14"; + case 015: return "task_15"; + case 016: return "task_16"; + case 017: return "task_17"; + } + return "???"; +} + +/** @brief F2 function names */ +const char* alto2_cpu_device::f2_name(UINT8 f2) +{ + switch (f2) { + case 000: return "nop"; + case 001: return "bus=0"; + case 002: return "shifter<0"; + case 003: return "shifter=0"; + case 004: return "bus"; + case 005: return "alucy"; + case 006: return "load_md"; + case 007: return "const"; + case 010: return "task_10"; + case 011: return "task_11"; + case 012: return "task_12"; + case 013: return "task_13"; + case 014: return "task_14"; + case 015: return "task_15"; + case 016: return "task_16"; + case 017: return "task_17"; + } + return "???"; +} + +#if ALTO2_DEBUG +void alto2_cpu_device::watch_read(UINT32 addr, UINT32 data) +{ + LOG((LOG_MEM,0,"mem: rd[%06o] = %06o\n", addr, data)); +} + +void alto2_cpu_device::watch_write(UINT32 addr, UINT32 data) +{ + LOG((LOG_MEM,0,"mem: wr[%06o] = %06o\n", addr, data)); +} +#endif + +/** @brief fatal exit on unitialized dynamic phase BUS source */ +void alto2_cpu_device::fn_bs_bad_0() +{ + fatal(9,"fatal: bad early bus source pointer for task %s, mpc:%05o bs:%s\n", + task_name(m_task), m_mpc, bs_name(m_d_bs)); +} + +/** @brief fatal exit on unitialized latching phase BUS source */ +void alto2_cpu_device::fn_bs_bad_1() +{ + fatal(9,"fatal: bad late bus source pointer for task %s, mpc:%05o bs: %s\n", + task_name(m_task), m_mpc, bs_name(m_d_bs)); +} + +/** @brief fatal exit on unitialized dynamic phase F1 function */ +void alto2_cpu_device::fn_f1_bad_0() +{ + fatal(9,"fatal: bad early f1 function pointer for task %s, mpc:%05o f1: %s\n", + task_name(m_task), m_mpc, f1_name(m_d_f1)); +} + +/** @brief fatal exit on unitialized latching phase F1 function */ +void alto2_cpu_device::fn_f1_bad_1() +{ + fatal(9,"fatal: bad late f1 function pointer for task %s, mpc:%05o f1: %s\n", + task_name(m_task), m_mpc, f1_name(m_d_f1)); +} + +/** @brief fatal exit on unitialized dynamic phase F2 function */ +void alto2_cpu_device::fn_f2_bad_0() +{ + fatal(9,"fatal: bad early f2 function pointer for task %s, mpc:%05o f2: %s\n", + task_name(m_task), m_mpc, f2_name(m_d_f2)); +} + +/** @brief fatal exit on unitialized latching phase F2 function */ +void alto2_cpu_device::fn_f2_bad_1() +{ + fatal(9,"fatal: bad late f2 function pointer for task %s, mpc:%05o f2: %s\n", + task_name(m_task), m_mpc, f2_name(m_d_f2)); +} + +#if ALTO2_DEBUG +typedef struct { + UINT16 first, last; + const char* name; +} memory_range_name_t; + +memory_range_name_t memory_range_name_table[] = { + {0177016, 0177017, "UTILOUT Printer output (Std. Hardware)"}, + {0177020, 0177023, "XBUS Utility input bus (Alto II Std. Hardware)"}, + {0177024, 0177024, "MEAR Memory Error Address Register (Alto II Std. Hardware)"}, + {0177025, 0177025, "MESR Memory error status register (Alto II Std. Hardware)"}, + {0177026, 0177026, "MECR Memory error control register (Alto II Std. Hardware)"}, + {0177030, 0177033, "UTILIN Printer status, mouse, keyset (all 4 locations return same thing)"}, + {0177034, 0177037, "KBDAD Undecoded keyboard (Std. Hardware)"}, + {0177740, 0177757, "BANKREGS Extended memory option bank registers"}, + {0177100, 0177100, "- Sumagraphics tablet X"}, + {0177101, 0177101, "- Sumagraphics tablet Y"}, + {0177140, 0177157, "- Organ keyboard"}, + {0177200, 0177204, "- PROM programmer"}, + {0177234, 0177237, "- Experimental ursor control"}, + {0177240, 0177257, "- Alto II debugger"}, + {0177244, 0177247, "- Graphics keyboard"}, + {0177400, 0177405, "- Maxc2 maintenance interface"}, + {0177400, 0177400, "- Alto DLS input (0)"}, + {0177420, 0177420, "- Alto DLS input (1)"}, + {0177440, 0177440, "- Alto DLS input (2)"}, + {0177460, 0177460, "- Alto DLS input (3)"}, + {0177600, 0177677, "- Alto DLS output"}, + {0177700, 0177700, "- EIA interface output bit"}, + {0177701, 0177701, "EIALOC EIA interface input bit"}, + {0177720, 0177737, "- TV Camera Interface"}, + {0177764, 0177773, "- Redactron tape drive"}, + {0177776, 0177776, "- Digital-Analog Converter, Joystick"}, + {0177777, 0177777, "- Digital-Analog Converter, Joystick"} +}; + +static const char* memory_range_name(offs_t offset) +{ + int _min = 0; + int _max = sizeof(memory_range_name_table) / sizeof(memory_range_name_table[0]) - 1; + int _mid; + + offset %= ALTO2_IO_PAGE_SIZE; + offset += ALTO2_IO_PAGE_BASE; + + /* binary search in table of memory ranges */ + while (_max >= _min) + { + _mid = (_min + _max) / 2; + if (memory_range_name_table[_mid].last < offset) + _min = _mid + 1; + else if (memory_range_name_table[_mid].first > offset) + _max = _mid - 1; + else if (memory_range_name_table[_mid].first <= offset && + memory_range_name_table[_mid].last >= offset) + return memory_range_name_table[_mid].name; + } + return "- UNUSED"; +} + +#endif + +/** + * @brief read the open bus for unused MMIO range + */ +READ16_MEMBER( alto2_cpu_device::noop_r ) +{ + LOG((LOG_CPU,0," MMIO rd %s\n", memory_range_name(offset))); + return 0177777; +} + +/** + * @brief write nowhere for unused MMIO range + */ +WRITE16_MEMBER( alto2_cpu_device::noop_w ) +{ + LOG((LOG_CPU,0," MMIO wr %s\n", memory_range_name(offset))); +} + +/** + * @brief read bank register in memory mapped I/O range + * + * The bank registers are stored in a 16x4-bit RAM 74S189. + */ +READ16_MEMBER( alto2_cpu_device::bank_reg_r ) +{ + int task = offset & 017; + int bank = m_bank_reg[task] | 0177760; + return bank; +} + +/** + * @brief write bank register in memory mapped I/O range + * + * The bank registers are stored in a 16x4-bit RAM 74S189. + */ +WRITE16_MEMBER( alto2_cpu_device::bank_reg_w ) +{ + int task = offset & 017; + m_bank_reg[task] = data & 017; + LOG((LOG_CPU,0," write bank[%02o]=%#o normal:%o extended:%o (%s)\n", + task, data, + GET_BANK_NORMAL(data), + GET_BANK_EXTENDED(data), + task_name(task))); +} + +/** + * @brief bs_read_r early: drive bus by R register + */ +void alto2_cpu_device::bs_early_read_r() +{ + UINT16 r = m_r[m_rsel]; + LOG((LOG_CPU,2," <-R%02o; %s (%#o)\n", m_rsel, r_name(m_rsel), r)); + m_bus &= r; +} + +/** + * @brief bs_load_r early: load R places 0 on the BUS + */ +void alto2_cpu_device::bs_early_load_r() +{ + UINT16 r = 0; + LOG((LOG_CPU,2," R%02o<-; %s (BUS&=0)\n", m_rsel, r_name(m_rsel))); + m_bus &= r; +} + +/** + * @brief bs_load_r late: load R from SHIFTER + */ +void alto2_cpu_device::bs_late_load_r() +{ + if (m_d_f2 != f2_emu_load_dns) { + m_r[m_rsel] = m_shifter; + LOG((LOG_CPU,2," R%02o<-; %s = SHIFTER (%#o)\n", m_rsel, r_name(m_rsel), m_shifter)); +#if 0 + /* HACK: programs writing r37 with xxx3 make the cursor + * display go nuts. Until I found the real reason for this + * obviously buggy display, I just clear the two + * least significant bits of r37 if they are set at once. + */ + if (m_rsel == 037 && ((m_shifter & 3) == 3)) { + printf("writing r37 = %#o\n", m_shifter); + m_r[037] &= ~3; + } +#endif + } +} + +/** + * @brief bs_read_md early: drive BUS from read memory data + */ +void alto2_cpu_device::bs_early_read_md() +{ +#if ALTO2_DEBUG + UINT32 mar = m_mem.mar; +#endif + UINT16 md = read_mem(); + LOG((LOG_CPU,2," <-MD; BUS&=MD (%#o=[%#o])\n", md, mar)); + m_bus &= md; +} + +/** + * @brief bs_mouse early: drive bus by mouse + */ +void alto2_cpu_device::bs_early_mouse() +{ + UINT16 r = mouse_read(); + LOG((LOG_CPU,2," <-MOUSE; BUS&=MOUSE (%#o)\n", r)); + m_bus &= r; +} + +/** + * @brief bs_disp early: drive bus by displacement (which?) + */ +void alto2_cpu_device::bs_early_disp() +{ + UINT16 r = 0177777; + LOG((LOG_CPU,0,"BS <-DISP not handled by task %s mpc:%04x\n", task_name(m_task), m_mpc)); + LOG((LOG_CPU,2," <-DISP; BUS&=DISP ?? (%#o)\n", r)); + m_bus &= r; +} + +/** + * @brief f1_load_mar late: load memory address register + * + * Load memory address register from the ALU output; + * start main memory reference (see section 2.3). + */ +void alto2_cpu_device::f1_late_load_mar() +{ + UINT8 bank = m_bank_reg[m_task]; + UINT32 msb; + if (m_d_f2 == f2_load_md) { + msb = GET_BANK_EXTENDED(bank) << 16; + LOG((LOG_CPU,7, " XMAR %#o\n", msb | m_alu)); + } else { + msb = GET_BANK_NORMAL(bank) << 16; + + } + load_mar(m_rsel, msb | m_alu); +} + +#if USE_PRIO_F9318 +/** @brief F9318 input lines */ +typedef enum { + PRIO_IN_EI = (1<<8), + PRIO_IN_I7 = (1<<7), + PRIO_IN_I6 = (1<<6), + PRIO_IN_I5 = (1<<5), + PRIO_IN_I4 = (1<<4), + PRIO_IN_I3 = (1<<3), + PRIO_IN_I2 = (1<<2), + PRIO_IN_I1 = (1<<1), + PRIO_IN_I0 = (1<<0), + /* masks */ + PRIO_I7 = PRIO_IN_I7, + PRIO_I6_I7 = (PRIO_IN_I6 | PRIO_IN_I7), + PRIO_I5_I7 = (PRIO_IN_I5 | PRIO_IN_I6 | PRIO_IN_I7), + PRIO_I4_I7 = (PRIO_IN_I4 | PRIO_IN_I5 | PRIO_IN_I6 | PRIO_IN_I7), + PRIO_I3_I7 = (PRIO_IN_I3 | PRIO_IN_I4 | PRIO_IN_I5 | PRIO_IN_I6 | PRIO_IN_I7), + PRIO_I2_I7 = (PRIO_IN_I2 | PRIO_IN_I3 | PRIO_IN_I4 | PRIO_IN_I5 | PRIO_IN_I6 | PRIO_IN_I7), + PRIO_I1_I7 = (PRIO_IN_I1 | PRIO_IN_I2 | PRIO_IN_I3 | PRIO_IN_I4 | PRIO_IN_I5 | PRIO_IN_I6 | PRIO_IN_I7), + PRIO_I0_I7 = (PRIO_IN_I0 | PRIO_IN_I1 | PRIO_IN_I2 | PRIO_IN_I3 | PRIO_IN_I4 | PRIO_IN_I5 | PRIO_IN_I6 | PRIO_IN_I7), +} f9318_in_t; + +/** @brief F9318 output lines */ +typedef enum { + PRIO_OUT_Q0 = (1<<0), + PRIO_OUT_Q1 = (1<<1), + PRIO_OUT_Q2 = (1<<2), + PRIO_OUT_EO = (1<<3), + PRIO_OUT_GS = (1<<4), + /* masks */ + PRIO_OUT_QZ = (PRIO_OUT_Q0 | PRIO_OUT_Q1 | PRIO_OUT_Q2) +} f9318_out_t; + +/** + * @brief F9318 priority encoder 8 to 3-bit + * + * Emulation of the F9318 chip (pin compatible with 74348). + * + *
+ *            F9318
+ *         +---+-+---+
+ *         |   +-+   |         +---------------------------------+----------------+
+ *    I4' -|1      16|-  Vcc   |              input              |     output     |
+ *         |         |         +---------------------------------+----------------+
+ *    I5' -|2      15|-  EO'   |      EI I0 I1 I2 I3 I4 I5 I6 I7 | GS Q0 Q1 Q2 EO |
+ *         |         |         +---------------------------------+----------------+
+ *    I6' -|3      14|-  GS'   | (a)  H  x  x  x  x  x  x  x  x  | H  H  H  H  H  |
+ *         |         |         | (b)  L  H  H  H  H  H  H  H  H  | H  H  H  H  L  |
+ *    I7' -|4      13|-  I3'   +---------------------------------+----------------+
+ *         |         |         | (c)  L  x  x  x  x  x  x  x  L  | L  L  L  L  H  |
+ *    EI' -|5      12|-  I2'   | (d)  L  x  x  x  x  x  x  L  H  | L  H  L  L  H  |
+ *         |         |         | (e)  L  x  x  x  x  x  L  H  H  | L  L  H  L  H  |
+ *    Q2' -|6      11|-  I1'   | (f)  L  x  x  x  x  L  H  H  H  | L  H  H  L  H  |
+ *         |         |         | (g)  L  x  x  x  L  H  H  H  H  | L  L  L  H  H  |
+ *    Q1' -|7      10|-  I0'   | (h)  L  x  x  L  H  H  H  H  H  | L  H  L  H  H  |
+ *         |         |         | (i)  L  x  L  H  H  H  H  H  H  | L  L  H  H  H  |
+ *   GND  -|8       9|-  Q0'   | (j)  L  L  H  H  H  H  H  H  H  | L  H  H  H  H  |
+ *         |         |         +---------------------------------+----------------+
+ *         +---------+
+ * 
+ */ +static __inline f9318_out_t f9318(f9318_in_t in) +{ + f9318_out_t out; + + if (in & PRIO_IN_EI) { + out = PRIO_OUT_EO | PRIO_OUT_GS | PRIO_OUT_QZ; + LOG((LOG_CPU,2," f9318 case (a) in:%#o out:%#o\n", in, out)); + return out; + } + + if (0 == (in & PRIO_I7)) { + out = PRIO_OUT_EO; + LOG((LOG_CPU,2," f9318 case (c) in:%#o out:%#o\n", in, out)); + return out; + } + + if (PRIO_I7 == (in & PRIO_I6_I7)) { + out = PRIO_OUT_EO | PRIO_OUT_Q0; + LOG((LOG_CPU,2," f9318 case (d) in:%#o out:%#o\n", in, out)); + return out; + } + + if (PRIO_I6_I7 == (in & PRIO_I5_I7)) { + out = PRIO_OUT_EO | PRIO_OUT_Q1; + LOG((LOG_CPU,2," f9318 case (e) in:%#o out:%#o\n", in, out)); + return out; + } + + if (PRIO_I5_I7 == (in & PRIO_I4_I7)) { + out = PRIO_OUT_EO | PRIO_OUT_Q0 | PRIO_OUT_Q1; + LOG((LOG_CPU,2," f9318 case (f) in:%#o out:%#o\n", in, out)); + return out; + } + + if (PRIO_I4_I7 == (in & PRIO_I3_I7)) { + out = PRIO_OUT_EO | PRIO_OUT_Q2; + LOG((LOG_CPU,2," f9318 case (g) in:%#o out:%#o\n", in, out)); + return out; + } + + if (PRIO_I3_I7 == (in & PRIO_I2_I7)) { + out = PRIO_OUT_EO | PRIO_OUT_Q0 | PRIO_OUT_Q2; + LOG((LOG_CPU,2," f9318 case (h) in:%#o out:%#o\n", in, out)); + return out; + } + + if (PRIO_I2_I7 == (in & PRIO_I1_I7)) { + out = PRIO_OUT_EO | PRIO_OUT_Q1 | PRIO_OUT_Q2; + LOG((LOG_CPU,2," f9318 case (i) in:%#o out:%#o\n", in, out)); + return out; + } + + if (PRIO_I1_I7 == (in & PRIO_I0_I7)) { + out = PRIO_OUT_EO | PRIO_OUT_Q0 | PRIO_OUT_Q1 | PRIO_OUT_Q2; + LOG((LOG_CPU,2," f9318 case (j) in:%#o out:%#o\n", in, out)); + return out; + } + + out = PRIO_OUT_QZ | PRIO_OUT_GS; + LOG((LOG_CPU,2," f9318 case (b) in:%#o out:%#o\n", in, out)); + return out; +} +#endif + +/** + * @brief f1_task early: task switch + * + * The priority encoder finds the highest task requesting service + * and switches the task number after the next cycle. + * + *
+ *  CT       PROM    NEXT'     RDCT'
+ *  1 2 4 8  DATA   6 7 8 9   1 2 4 8
+ *  ---------------------------------
+ *  0 0 0 0  0367   1 1 1 1   0 1 1 1
+ *  1 0 0 0  0353   1 1 1 0   1 0 1 1
+ *  0 1 0 0  0323   1 1 0 1   0 0 1 1
+ *  1 1 0 0  0315   1 1 0 0   1 1 0 1
+ *  0 0 1 0  0265   1 0 1 1   0 1 0 1
+ *  1 0 1 0  0251   1 0 1 0   1 0 0 1
+ *  0 1 1 0  0221   1 0 0 1   0 0 0 1
+ *  1 1 1 0  0216   1 0 0 0   1 1 1 0
+ *  0 0 0 1  0166   0 1 1 1   0 1 1 0
+ *  1 0 0 1  0152   0 1 1 0   1 0 1 0
+ *  0 1 0 1  0122   0 1 0 1   0 0 1 0
+ *  1 1 0 1  0114   0 1 0 0   1 1 0 0
+ *  0 0 1 1  0064   0 0 1 1   0 1 0 0
+ *  1 0 1 1  0050   0 0 1 0   1 0 0 0
+ *  0 1 1 1  0020   0 0 0 1   0 0 0 0
+ *  1 1 1 1  0017   0 0 0 0   1 1 1 1
+ *
+ * The various task wakeups are encoded using two 8:3-bit priority encoders F9318,
+ * which are pin-compatible to the 74348 (inverted inputs and outputs).
+ * Their part numbers are U1 and U2.
+ * The two encoders are chained (EO of U1 goes to EI of U2):
+ *
+ * The outputs are fed into some NAND gates (74H10 and 74H00) to decode
+ * the task number to latch (CT1-CT4) after a F1 TASK. The case where all
+ * of RDCT1' to RDCT8' are high (1) is decoded as RESET'.
+ *
+ * signal   function
+ * --------------------------------------------------
+ * CT1      (U1.Q0' & U2.Q0' & RDCT1')'
+ * CT2      (U1.Q1' & U2.Q1' & RDCT2')'
+ * CT4      (U1.Q2' & U2.Q2' & RDCT4')'
+ * CT8      (U1.GS' & RDCT8')'
+ * RESET'   RDCT1' & RDCT2' & RDCT4' & RDCT8'
+ *
+ * In the tables below "x" is RDCTx' of current task
+ *
+ * signal          input   output, if first 0        CT1  CT2  CT4  CT8
+ * ----------------------------------------------------------------------------------------
+ * WAKE17' (T19?)   4 I7   Q2:0 Q1:0 Q0:0 GS:0 EO:1  1    1    1    1
+ * WAKEKWDT'        3 I6   Q2:0 Q1:0 Q0:1 GS:0 EO:1  x    1    1    1
+ * WAKEPART'        2 I5   Q2:0 Q1:1 Q0:0 GS:0 EO:1  1    x    1    1
+ * WAKEDVT'         1 I4   Q2:0 Q1:1 Q0:1 GS:0 EO:1  x    x    1    1
+ * WAKEDHT'        13 I3   Q2:1 Q1:0 Q0:0 GS:0 EO:1  1    1    x    1
+ * WAKECURT'       12 I2   Q2:1 Q1:0 Q0:1 GS:0 EO:1  x    1    x    1
+ * WAKEDWT'        11 I1   Q2:1 Q1:1 Q0:0 GS:0 EO:1  1    x    x    1
+ * WAKEMRT'        10 I0   Q2:1 Q1:1 Q0:1 GS:0 EO:1  x    x    x    1
+ * otherwise               Q2:1 Q1:1 Q0:1 GS:1 EO:0  x    x    x    x
+ *
+ * signal          input   output, if first 0
+ * ----------------------------------------------------------------------------------------
+ * WAKEET'          4 I7   Q2:0 Q1:0 Q0:0 GS:0 EO:1  1    1    1    x
+ * WAKE6'           3 I6   Q2:0 Q1:0 Q0:1 GS:0 EO:1  x    1    1    x
+ * WAKE5'           2 I5   Q2:0 Q1:1 Q0:0 GS:0 EO:1  1    x    1    x
+ * WAKEKST'         1 I4   Q2:0 Q1:1 Q0:1 GS:0 EO:1  x    x    1    x
+ * WAKE3' (T23?)   13 I3   Q2:1 Q1:0 Q0:0 GS:0 EO:1  1    1    x    x
+ * WAKE2'          12 I2   Q2:1 Q1:0 Q0:1 GS:0 EO:1  x    1    x    x
+ * WAKE1'          11 I1   Q2:1 Q1:1 Q0:0 GS:0 EO:1  1    x    x    x
+ * 0 (GND)         10 I0   Q2:1 Q1:1 Q0:1 GS:0 EO:1  x    x    x    x
+ * 
+ */ +void alto2_cpu_device::f1_early_task() +{ +#if USE_PRIO_F9318 + /* Doesn't work yet */ + register f9318_in_t wakeup_hi; + register f9318_out_t u1; + register f9318_in_t wakeup_lo; + register f9318_out_t u2; + register int addr = 017; + register int rdct1, rdct2, rdct4, rdct8; + register int ct1, ct2, ct4, ct8; + register int wakeup, ct; + + LOG((LOG_CPU,2, " TASK %02o:%s\n", m_task, task_name(m_task))); + + if (m_task > task_emu && (m_task_wakeup & (1 << m_task))) + addr = m_task; + LOG((LOG_CPU,2," ctl2k_u38[%02o] = %04o\n", addr, ctl2k_u38[addr] & 017)); + + rdct1 = (ctl2k_u38[addr] >> U38_RDCT1) & 1; + rdct2 = (ctl2k_u38[addr] >> U38_RDCT2) & 1; + rdct4 = (ctl2k_u38[addr] >> U38_RDCT4) & 1; + rdct8 = (ctl2k_u38[addr] >> U38_RDCT8) & 1; + + /* wakeup signals are active low */ + wakeup = ~m_task_wakeup; + + /* U1 + * task wakeups 017 to 010 on I7 to I0 + * EI is 0 (would be 1 at reset) + */ + wakeup_hi = (wakeup >> 8) & PRIO_I0_I7; + u1 = f9318(wakeup_hi); + + /* U2 + * task wakeups 007 to 001 on I7 to I1, I0 is 0 + * EO of U1 chained to EI + */ + wakeup_lo = wakeup & PRIO_I0_I7; + if (u1 & PRIO_OUT_EO) + wakeup_lo |= PRIO_IN_EI; + u2 = f9318(wakeup_lo); + + /* CT1 = (U1.Q0' & U2.Q0' & RDCT1')' */ + ct1 = !((u1 & PRIO_OUT_Q0) && (u2 & PRIO_OUT_Q0) && rdct1); + LOG((LOG_CPU,2," CT1:%o U1.Q0':%o U2.Q0':%o RDCT1':%o\n", + ct1, (u1 & PRIO_OUT_Q0)?1:0, (u2 & PRIO_OUT_Q0)?1:0, rdct1)); + /* CT2 = (U1.Q1' & U2.Q1' & RDCT2')' */ + ct2 = !((u1 & PRIO_OUT_Q1) && (u2 & PRIO_OUT_Q1) && rdct2); + LOG((LOG_CPU,2," CT2:%o U1.Q1':%o U2.Q1':%o RDCT2':%o\n", + ct2, (u1 & PRIO_OUT_Q1)?1:0, (u2 & PRIO_OUT_Q1)?1:0, rdct2)); + /* CT4 = (U1.Q2' & U2.Q2' & RDCT4')' */ + ct4 = !((u1 & PRIO_OUT_Q2) && (u2 & PRIO_OUT_Q2) && rdct4); + LOG((LOG_CPU,2," CT4:%o U1.Q2':%o U2.Q2':%o RDCT4':%o\n", + ct4, (u1 & PRIO_OUT_Q2)?1:0, (u2 & PRIO_OUT_Q2)?1:0, rdct4)); + /* CT8 */ + ct8 = !((u1 & PRIO_OUT_GS) && rdct8); + LOG((LOG_CPU,2," CT8:%o U1.GS':%o RDCT8':%o\n", + ct8, (u1 & PRIO_OUT_GS)?1:0, rdct8)); + + ct = 8*ct8 + 4*ct4 + 2*ct2 + ct1; + + if (ct != m_next_task) { + LOG((LOG_CPU,2, " switch to %02o\n", ct)); + m_next2_task = ct; + } else { + LOG((LOG_CPU,2, " no switch\n")); + } +#else /* USE_PRIO_F9318 */ + LOG((LOG_CPU,2, " TASK %02o:%s", m_task, task_name(m_task))); + for (int i = 15; i >= 0; i--) { + if (m_task_wakeup & (1 << i)) { + m_next2_task = i; + if (m_next2_task != m_next_task) { + LOG((LOG_CPU,2, " switch to %02o:%s\n", m_next2_task, task_name(m_next2_task))); + } else { + LOG((LOG_CPU,2, " no switch\n")); + } + return; + } + } + fatal(3, "no tasks requesting service\n"); +#endif /* !USE_PRIO_F9318 */ +} + +/** + * @brief block task + * + * The task wakeup for the active task is cleared + */ +void alto2_cpu_device::f1_early_block() +{ + m_task_wakeup &= ~(1 << m_task); + LOG((LOG_CPU,2, " BLOCK %02o:%s\n", m_task, task_name(m_task))); +} + +/** + * @brief SHIFTER = L shifted left once + */ +void alto2_cpu_device::f1_late_l_lsh_1() +{ + m_shifter = m_l << 1; + LOG((LOG_CPU,2," SHIFTER <-L LSH 1 (%#o := %#o<<1)\n", m_shifter, m_l)); +} + +/** + * @brief SHIFTER = L shifted right once + */ +void alto2_cpu_device::f1_late_l_rsh_1() +{ + m_shifter = m_l >> 1; + LOG((LOG_CPU,2," SHIFTER <-L RSH 1 (%#o := %#o>>1)\n", m_shifter, m_l)); +} + +/** + * @brief SHIFTER = L cycled 8 times (byte swap) + */ +void alto2_cpu_device::f1_late_l_lcy_8() +{ + m_shifter = (m_l >> 8) | (m_l << 8); + LOG((LOG_CPU,2," SHIFTER <-L LCY 8 (%#o := bswap %#o)\n", m_shifter, m_l)); +} + +/** + * @brief f2_bus_eq_zero late: branch on bus equals zero + */ +void alto2_cpu_device::f2_late_bus_eq_zero() +{ + UINT16 r = m_bus == 0 ? 1 : 0; + LOG((LOG_CPU,2, " BUS=0; %sbranch (%#o|%#o)\n", r ? "" : "no ", m_next2, r)); + m_next2 |= r; +} + +/** + * @brief branch on shifter less than zero + */ +void alto2_cpu_device::f2_late_shifter_lt_zero() +{ + UINT16 r = (m_shifter & 0100000) ? 1 : 0; + LOG((LOG_CPU,2, " SH<0; %sbranch (%#o|%#o)\n", r ? "" : "no ", m_next2, r)); + m_next2 |= r; +} + +/** + * @brief branch on shifter equals zero + */ +void alto2_cpu_device::f2_late_shifter_eq_zero() +{ + UINT16 r = m_shifter == 0 ? 1 : 0; + LOG((LOG_CPU,2, " SH=0; %sbranch (%#o|%#o)\n", r ? "" : "no ", m_next2, r)); + m_next2 |= r; +} + +/** + * @brief f2_bus late: branch on bus bits BUS[6-15] + */ +void alto2_cpu_device::f2_late_bus() +{ + UINT16 r = X_RDBITS(m_bus,16,6,15); + LOG((LOG_CPU,2, " BUS; %sbranch (%#o|%#o)\n", r ? "" : "no ", m_next2, r)); + m_next2 |= r; +} + +/** + * @brief f2_alucy late: branch on latched ALU carry + */ +void alto2_cpu_device::f2_late_alucy() +{ + UINT16 r = m_laluc0; + LOG((LOG_CPU,2, " ALUCY; %sbranch (%#o|%#o)\n", r ? "" : "no ", m_next2, r)); + m_next2 |= r; +} + +/** + * @brief f2_load_md late: load memory data + * + * Deliver BUS data to memory. + */ +void alto2_cpu_device::f2_late_load_md() +{ +#if ALTO2_DEBUG + UINT16 mar = m_mem.mar; +#endif + if (m_d_f1 == f1_load_mar) { + /* part of an XMAR */ + LOG((LOG_CPU,2, " XMAR %#o (%#o)\n", mar, m_bus)); + } else { + write_mem(m_bus); + LOG((LOG_CPU,2, " MD<- BUS ([%#o]=%#o)\n", mar, m_bus)); + } +} + +#if USE_ALU_74181 +/** + *
+ * Functional description of the 4-bit ALU 74181
+ *
+ * The 74181 is a 4-bit high speed parallel Arithmetic Logic Unit (ALU).
+ * Controlled by four Function Select inputs (S0-S3) and the Mode Control
+ * input (M), it can perform all the 16 possible logic operations or 16
+ * different arithmetic operations on active HIGH or active LOW operands.
+ * The Function Table lists these operations.
+ *
+ * When the Mode Control input (M) is HIGH, all internal carries are
+ * inhibited and the device performs logic operations on the individual
+ * bits as listed. When the Mode Control input is LOW, the carries are
+ * enabled and the device performs arithmetic operations on the two 4-bit
+ * words. The device incorporates full internal carry lookahead and
+ * provides for either ripple carry between devices using the Cn+4 output,
+ * or for carry lookahead between packages using the signals P' (Carry
+ * Propagate) and G' (Carry Generate). In the ADD mode, P' indicates that
+ * F' is 15 or more, while G' indicates that F' is 16 or more. In the
+ * SUBTRACT mode, P' indicates that F' is zero or less, while G' indicates
+ * that F' is less than zero. P' and G' are not affected by carry in.
+ * When speed requirements are not stringent, it can be used in a simple
+ * ripple carry mode by connecting the Carry output (Cn+4) signal to the
+ * Carry input (Cn) of the next unit. For high speed operation the device
+ * is used in conjunction with the 74182 carry lookahead circuit. One
+ * carry lookahead package is required for each group of four 74181 devices.
+ * Carry lookahead can be provided at various levels and offers high speed
+ * capability over extremely long word lengths.
+ *
+ * The A=B output from the device goes HIGH when all four F' outputs are
+ * HIGH and can be used to indicate logic equivalence over four bits when
+ * the unit is in the subtract mode. The A=B output is open collector and
+ * can be wired-AND with other A=B outputs to give a comparison for more
+ * than four bits. The A=B signal can also be used with the Cn+4 signal
+ * to indicated A>B and A
+ */
+
+//! S function, M flag and C carry in
+#define SMC(s3,s2,s1,s0,m,ci) (s3*A10_ALUS3 + s2*A10_ALUS2 + s1*A10_ALUS1 + s0*A10_ALUS0 + m*A10_ALUM + ci*A10_ALUCI)
+
+/**
+ * @brief Compute the 74181 ALU operation smc for inputs a and b
+ *
+ * The function, arithmetic / logic flag and carry in define the
+ * ALU operation. The carry in is irrelevant for the logic operations.
+ * The result is 17 bit, where bit #16 is the carry out.
+ *
+ * @param smc S function [0-15], M arithmetic/logic flag, C carry
+ * @return resulting ALU output
+ */
+#if 1
+UINT32 alto2_cpu_device::alu_74181(UINT32 a, UINT32 b, UINT8 smc)
+{
+	register UINT32 f;
+	register const UINT32 cout = 1 << 16;
+
+	switch (smc & A10_ALUIN) {
+	case SMC(0,0,0,0, 0, 0): // 0000: A + 1
+		f = a + 1;
+		break;
+
+	case SMC(0,0,0,0, 0, 1): // 0000: A
+		f = a;
+		break;
+
+	case SMC(0,0,0,0, 1, 0): // 0000: A'
+	case SMC(0,0,0,0, 1, 1):
+		f = (~a) | cout;
+		break;
+
+	case SMC(0,0,0,1, 0, 0): // 0001: (A | B) + 1
+		f = (a | b) + 1;
+		break;
+
+	case SMC(0,0,0,1, 0, 1): // 0001: A | B
+		f = a | b;
+		break;
+
+	case SMC(0,0,0,1, 1, 0): // 0001: A' | B'
+	case SMC(0,0,0,1, 1, 1):
+		f = (~a | ~b) | cout;
+		break;
+
+	case SMC(0,0,1,0, 0, 0): // 0010: (A | B') + 1
+		f = (a | ~b) + 1;
+		break;
+
+	case SMC(0,0,1,0, 0, 1): // 0010: A | B'
+		f = a | ~b;
+		break;
+
+	case SMC(0,0,1,0, 1, 0): // 0010: A' & B
+	case SMC(0,0,1,0, 1, 1):
+		f = (~a & b) | cout;
+		break;
+
+	case SMC(0,0,1,1, 0, 0): // 0011: -1 + 1
+		f = (-1 + 1) | cout;
+		break;
+
+	case SMC(0,0,1,1, 0, 1): // 0011: -1
+		f = (-1) | cout;
+		break;
+
+	case SMC(0,0,1,1, 1, 0): // 0011: logic 0
+	case SMC(0,0,1,1, 1, 1):
+		f = cout;
+		break;
+
+	case SMC(0,1,0,0, 0, 0): // 0100: A + (A & B') + 1
+		f = a + (a & ~b) + 1;
+		break;
+
+	case SMC(0,1,0,0, 0, 1): // 0100: A + (A & B')
+		f = a + (a & ~b);
+		break;
+
+	case SMC(0,1,0,0, 1, 0): // 0100: (A & B)'
+	case SMC(0,1,0,0, 1, 1):
+		f = ~(a & b) | cout;
+		break;
+
+	case SMC(0,1,0,1, 0, 0): // 0101: (A | B) + (A & B') + 1
+		f = (a | b) + (a & ~b) + 1;
+		break;
+
+	case SMC(0,1,0,1, 0, 1): // 0101: (A | B) + (A & B')
+		f = (a | b) + (a & ~b);
+		break;
+
+	case SMC(0,1,0,1, 1, 0): // 0101: B'
+	case SMC(0,1,0,1, 1, 1):
+		f = (~b) | cout;
+		break;
+
+	case SMC(0,1,1,0, 0, 0): // 0110: A - B - 1 + 1
+		f = (a - b - 1 + 1)  ^ cout;
+		break;
+
+	case SMC(0,1,1,0, 0, 1): // 0110: A - B - 1
+		f = (a - b - 1) ^ cout;
+		break;
+
+	case SMC(0,1,1,0, 1, 0): // 0110: A ^ B
+	case SMC(0,1,1,0, 1, 1):
+		f = (a ^ b) | cout;
+		break;
+
+	case SMC(0,1,1,1, 0, 0): // 0111: (A & B) - 1 + 1
+		f = ((a & b) - 1 + 1) ^ cout;
+		break;
+
+	case SMC(0,1,1,1, 0, 1): // 0111: (A & B) - 1
+		f = ((a & b) - 1) ^ cout;
+		break;
+
+	case SMC(0,1,1,1, 1, 0): // 0111: A & B'
+	case SMC(0,1,1,1, 1, 1):
+		f = (a & ~b) | cout;
+		break;
+
+	case SMC(1,0,0,0, 0, 0): // 1000: A + (A & B) + 1
+		f = a + (a & b) + 1;
+		break;
+
+	case SMC(1,0,0,0, 0, 1): // 1000: A + (A & B)
+		f = a + (a & b);
+		break;
+
+	case SMC(1,0,0,0, 1, 0): // 1000: A' | B
+	case SMC(1,0,0,0, 1, 1):
+		f = (~a | b) | cout;
+		break;
+
+	case SMC(1,0,0,1, 0, 0): // 1001: A + B + 1
+		f = a + b + 1;
+		break;
+
+	case SMC(1,0,0,1, 0, 1): // 1001: A + B
+		f = a + b;
+		break;
+
+	case SMC(1,0,0,1, 1, 0): // 1001: A' ^ B'
+	case SMC(1,0,0,1, 1, 1):
+		f = (~a ^ ~b) | cout;
+		break;
+
+	case SMC(1,0,1,0, 0, 0): // 1010: (A | B') + (A & B) + 1
+		f = (a | ~b) + (a & b) + 1;
+		break;
+
+	case SMC(1,0,1,0, 0, 1): // 1010: (A | B') + (A & B)
+		f = (a | ~b) + (a & b);
+		break;
+
+	case SMC(1,0,1,0, 1, 0): // 1010: B
+	case SMC(1,0,1,0, 1, 1):
+		f = (b) | cout;
+		break;
+
+	case SMC(1,0,1,1, 0, 0): // 1011: (A & B) - 1 + 1
+		f = ((a & b) - 1 + 1) ^ cout;
+		break;
+
+	case SMC(1,0,1,1, 0, 1): // 1011: (A & B) - 1
+		f = ((a & b) - 1)  ^ cout;
+		break;
+
+	case SMC(1,0,1,1, 1, 0): // 1011: A & B
+	case SMC(1,0,1,1, 1, 1):
+		f = (a & b) | cout;
+		break;
+
+	case SMC(1,1,0,0, 0, 0): // 1100: A + A + 1
+		f = a + a + 1;
+		break;
+
+	case SMC(1,1,0,0, 0, 1): // 1100: A + A
+		f = a + a;
+		break;
+
+	case SMC(1,1,0,0, 1, 0): // 1100: logic 1
+	case SMC(1,1,0,0, 1, 1):
+		f = (~0) | cout;
+		break;
+
+	case SMC(1,1,0,1, 0, 0): // 1101: (A | B) + A + 1
+		f = (a | b) + a + 1;
+		break;
+
+	case SMC(1,1,0,1, 0, 1): // 1101: (A | B) + A
+		f = (a | b) + a;
+		break;
+
+	case SMC(1,1,0,1, 1, 0): // 1101: A | B'
+	case SMC(1,1,0,1, 1, 1):
+		f = (a | ~b) | cout;
+		break;
+
+	case SMC(1,1,1,0, 0, 0): // 1110: (A | B') + A + 1
+		f = (a | ~b) + a + 1;
+		break;
+
+	case SMC(1,1,1,0, 0, 1): // 1110: (A | B') + A
+		f = (a | ~b) + a;
+		break;
+
+	case SMC(1,1,1,0, 1, 0): // 1110: A | B
+	case SMC(1,1,1,0, 1, 1):
+		f = (a | b) | cout;
+		break;
+
+	case SMC(1,1,1,1, 0, 0): // 1111: A - 1 + 1
+		f = (a - 1 + 1) ^ cout;
+		break;
+
+	case SMC(1,1,1,1, 0, 1): // 1111: A - 1
+		f = (a - 1) ^ cout;
+		break;
+
+	case SMC(1,1,1,1, 1, 0): // 1111: A
+	case SMC(1,1,1,1, 1, 1):
+		f = (a) | cout;
+		break;
+
+	default:
+		f = 0;
+		break;
+	}
+	return f;
+}
+#else
+
+#define DO_74181(ci,mp,s0,s1,s2,s3,a,b,_b0,_b1,_b2,_b3,f,co) do { \
+	int a0 = BIT(a,_b0), a1 = BIT(a,_b1), a2 = BIT(a,_b2), a3 = BIT(a,_b3); \
+	int b0 = BIT(b,_b0), b1 = BIT(b,_b1), b2 = BIT(b,_b2), b3 = BIT(b,_b3); \
+	int ap0 = !(a0 | (b0 & s0) | (s1 & !b0)); \
+	int bp0 = !(((!b0) & s2 & a0) | (a0 & b0 & s3)); \
+	int ap1 = !(a1 | (b1 & s0) | (s1 & !b1)); \
+	int bp1 = !(((!b1) & s2 & a1) | (a1 & b1 & s3)); \
+	int ap2 = !(a2 | (b2 & s0) | (s1 & !b2)); \
+	int bp2 = !(((!b2) & s2 & a2) | (a2 & b2 & s3)); \
+	int ap3 = !(a3 | (b3 & s0) | (s1 & !b3)); \
+	int bp3 = !(((!b3) & s2 & a3) | (a3 & b3 & s3)); \
+	int fp0 = !(ci & mp) ^ ((!ap0) & bp0); \
+	int fp1 = (!((mp & ap0) | (mp & bp0 & ci))) ^ ((!ap1) & bp1); \
+	int fp2 = (!((mp & ap1) | (mp & ap0 & bp1) | (mp & ci & bp0 & bp1))) ^ ((!ap2) & bp2); \
+	int fp3 = (!((mp & ap2) | (mp & ap1 & bp2) | (mp & ap0 & bp1 & bp2) | (mp & ci & bp0 & bp1 & bp2))) ^ ((!ap3) & bp3); \
+	f |= (fp0 << _b0) | (fp1 << _b1) | (fp2 << _b2) | (fp3 << _b3); \
+	int g = !((ap0 & bp1 & bp2 & bp3) | (ap1 & bp2 & bp3) | (ap2 & bp3) | ap3); \
+	co = (!(ci & bp0 & bp1 & bp2 & bp3)) | g; \
+} while (0)
+
+
+UINT32 alto2_cpu_device::alu_74181(UINT32 a, UINT32 b, UINT8 smc)
+{
+	// inputs
+	int ci = !BIT(smc, 2);
+	int mp = !BIT(smc, 3);
+	int s0 = !BIT(smc, 4), s1 = !BIT(smc, 5), s2 = !BIT(smc, 6), s3 = !BIT(smc, 7);
+
+	// outputs
+	UINT32 f = 0;
+	int cn_x;
+	DO_74181(ci,  mp,s0,s1,s2,s3,a,b, 0, 1, 2, 3,f,cn_x);   // 74181 #1
+	int cn_y;
+	DO_74181(cn_x,mp,s0,s1,s2,s3,a,b, 4, 5, 6, 7,f,cn_y);   // 74181 #2
+	int cn_z;
+	DO_74181(cn_y,mp,s0,s1,s2,s3,a,b, 8, 9,10,11,f,cn_z);   // 74181 #3
+	int co;
+	DO_74181(cn_z,mp,s0,s1,s2,s3,a,b,12,13,14,15,f,co);     // 74181 #4
+	f |= co << 16;
+	return f;
+}
+#endif  // 0
+#endif
+
+/** @brief flag that tells whether to load the T register from BUS or ALU */
+#define TSELECT A10_TSELECT
+
+/** @brief flag that tells wheter operation was 0: arithmetic (M=0) or 1: logic (M=1) */
+#define ALUM    A10_ALUM
+
+/** @brief execute the CPU for at most nsecs nano seconds */
+void alto2_cpu_device::execute_run()
+{
+	m_next = m_task_mpc[m_task];        // get current task's next mpc and address modifier
+	m_next2 = m_task_next2[m_task];
+
+	do {
+		int do_bs, flags;
+
+		m_mpc = m_next;             // next instruction's micro program counter
+		m_mir = RD_UCODE(m_mpc);    // fetch the micro code
+
+		// extract the bit fields
+		m_d_rsel = m_rsel = X_RDBITS(m_mir, 32, DRSEL0, DRSEL4);
+		m_d_aluf = X_RDBITS(m_mir, 32, DALUF0, DALUF3);
+		m_d_bs = X_RDBITS(m_mir, 32, DBS0, DBS2);
+		m_d_f1 = X_RDBITS(m_mir, 32, DF1_0, DF1_3);
+		m_d_f2 = X_RDBITS(m_mir, 32, DF2_0, DF2_3);
+		m_d_loadt = X_BIT(m_mir, 32, DLOADT);
+		m_d_loadl = X_BIT(m_mir, 32, DLOADL);
+
+		debugger_instruction_hook(this, m_mpc);
+		m_cycle++;
+
+
+		if (m_d_f1 == f1_load_mar && check_mem_load_mar_stall(m_rsel)) {
+			LOG((LOG_CPU,3, "   MAR<- stall\n"));
+			continue;
+		}
+		if (m_d_f2 == f2_load_md && check_mem_write_stall()) {
+			LOG((LOG_CPU,3, "   MD<- stall\n"));
+			continue;
+		}
+		/*
+		 * Bus source decoding is not performed if f1 == f1_const
+		 * or f2 == f2_const. These functions use the MIR BS field to
+		 * provide a part of the address to the constant ROM instead.
+		 */
+		do_bs = !(m_d_f1 == f1_const || m_d_f2 == f2_const);
+		if (do_bs && m_d_bs == bs_read_md && check_mem_read_stall()) {
+			LOG((LOG_CPU,3, "   <-MD stall\n"));
+			continue;
+		}
+		// now read the next instruction field from the MIR and modify it
+		m_next = X_RDBITS(m_mir, 32, NEXT0, NEXT9) | m_next2;
+		// prefetch the next instruction's next field as next2
+		m_next2 = X_RDBITS(RD_UCODE(m_next), 32, NEXT0, NEXT9) | (m_next2 & ~ALTO2_UCODE_PAGE_MASK);
+		LOG((LOG_CPU,2,"%s-%04o: %011o r:%02o aluf:%02o bs:%02o f1:%02o f2:%02o t:%o l:%o next:%05o next2:%05o\n",
+			task_name(m_task), m_mpc, m_mir, m_rsel, m_d_aluf, m_d_bs, m_d_f1, m_d_f2, m_d_loadt, m_d_loadl, m_next, m_next2));
+
+		// BUS is all ones at the start of each cycle
+		m_bus = 0177777;
+
+		if (m_rdram_flag)
+			rdram();
+
+		// The constant memory is gated to the bus by F1 == f1_const, F2 == f2_const, or BS >= 4
+		if (!do_bs || m_d_bs >= bs_task_4) {
+			UINT32 addr = 8 * m_rsel + m_d_bs;
+			// FIXME: is the format of m_const_data endian safe?
+			UINT16 data = m_const_data[2*addr] | (m_const_data[2*addr+1] << 8);
+			m_bus &= data;
+			LOG((LOG_CPU,2,"    %#o; BUS &= %#o CONST[%03o]\n", m_bus, data, addr));
+		}
+
+		/*
+		 * early F2 function has to be called before early BS,
+		 * because the emulator task F2 acsource or acdest may
+		 * change the m_rsel
+		 */
+		((*this).*m_f2[0][m_task][m_d_f2])();
+
+		// early BS function can be done now
+		if (do_bs)
+			((*this).*m_bs[0][m_task][m_d_bs])();
+
+		// early F1 function
+		((*this).*m_f1[0][m_task][m_d_f1])();
+
+#if USE_ALU_74181
+		/**
+		 * The ALU a10 PROM address lines are
+		 * A4:SKIP      A3:ALUF0     A2:ALUF1     A1:ALUF2     A0:ALUF3
+		 * The PROM output lines are
+		 * B0: unused   B1: TSELECT  B2: ALUCI'   B3: ALUM'
+		 * B4: ALUS0'   B5: ALUS1'   B6: ALUS2'   B7: ALUS3'
+		 *
+		 * B1 and B3-B7 are inverted on loading the PROM
+		 */
+		UINT8 a10 = m_alu_a10[(m_emu.skip << 4) | m_d_aluf];
+		UINT32 alu = alu_74181(m_bus, m_t, a10);
+		m_aluc0 = (alu >> 16) & 1;
+		flags = a10 & (TSELECT | ALUM);
+		m_alu = static_cast(alu);
+#else
+		UINT32 alu;
+		/* compute the ALU function */
+		switch (m_d_aluf) {
+		/**
+		 * 00: ALU <- BUS
+		 * PROM data for S3-0:1111 M:1 C:0 T:0
+		 * 74181 function F=A
+		 * T source is BUS
+		 */
+		case aluf_bus__alut:
+			alu = m_bus;
+			m_aluc0 = 1;
+			flags = ALUM;
+			LOG((LOG_CPU,2,"    ALU<- BUS (%#o := %#o)\n", alu, m_bus));
+			break;
+
+		/**
+		 * 01: ALU <- T
+		 * PROM data for S3-0:1010 M:1 C:0 T:0
+		 * 74181 function F=B
+		 * T source is BUS
+		 */
+		case aluf_treg:
+			alu = m_t;
+			m_aluc0 = 1;
+			flags = ALUM;
+			LOG((LOG_CPU,2,"    ALU<- T (%#o := %#o)\n", alu, m_t));
+			break;
+
+		/**
+		 * 02: ALU <- BUS | T
+		 * PROM data for S3-0:1110 M:1 C:0 T:1
+		 * 74181 function F=A|B
+		 * T source is ALU
+		 */
+		case aluf_bus_or_t__alut:
+			alu = m_bus | m_t;
+			m_aluc0 = 1;
+			flags = ALUM | TSELECT;
+			LOG((LOG_CPU,2,"    ALU<- BUS OR T (%#o := %#o | %#o)\n", alu, m_bus, m_t));
+			break;
+
+		/**
+		 * 03: ALU <- BUS & T
+		 * PROM data for S3-0:1011 M:1 C:0 T:0
+		 * 74181 function F=A&B
+		 * T source is BUS
+		 */
+		case aluf_bus_and_t:
+			alu = m_bus & m_t;
+			m_aluc0 = 1;
+			flags = ALUM;
+			LOG((LOG_CPU,2,"    ALU<- BUS AND T (%#o := %#o & %#o)\n", alu, m_bus, m_t));
+			break;
+
+		/**
+		 * 04: ALU <- BUS ^ T
+		 * PROM data for S3-0:0110 M:1 C:0 T:0
+		 * 74181 function F=A^B
+		 * T source is BUS
+		 */
+		case aluf_bus_xor_t:
+			alu = m_bus ^ m_t;
+			m_aluc0 = 1;
+			flags = ALUM;
+			LOG((LOG_CPU,2,"    ALU<- BUS XOR T (%#o := %#o ^ %#o)\n", alu, m_bus, m_t));
+			break;
+
+		/**
+		 * 05: ALU <- BUS + 1
+		 * PROM data for S3-0:0000 M:0 C:0 T:1
+		 * 74181 function F=A+1
+		 * T source is ALU
+		 */
+		case aluf_bus_plus_1__alut:
+			alu = m_bus + 1;
+			m_aluc0 = (alu >> 16) & 1;
+			flags = TSELECT;
+			LOG((LOG_CPU,2,"    ALU<- BUS + 1 (%#o := %#o + 1)\n", alu, m_bus));
+			break;
+
+		/**
+		 * 06: ALU <- BUS - 1
+		 * PROM data for S3-0:1111 M:0 C:1 T:1
+		 * 74181 function F=A-1
+		 * T source is ALU
+		 */
+		case aluf_bus_minus_1__alut:
+			alu = m_bus + 0177777;
+			m_aluc0 = (~alu >> 16) & 1;
+			flags = TSELECT;
+			LOG((LOG_CPU,2,"    ALU<- BUS - 1 (%#o := %#o - 1)\n", alu, m_bus));
+			break;
+
+		/**
+		 * 07: ALU <- BUS + T
+		 * PROM data for S3-0:1001 M:0 C:1 T:0
+		 * 74181 function F=A+B
+		 * T source is BUS
+		 */
+		case aluf_bus_plus_t:
+			alu = m_bus + m_t;
+			m_aluc0 = (alu >> 16) & 1;
+			flags = 0;
+			LOG((LOG_CPU,2,"    ALU<- BUS + T (%#o := %#o + %#o)\n", alu, m_bus, m_t));
+			break;
+
+		/**
+		 * 10: ALU <- BUS - T
+		 * PROM data for S3-0:0110 M:0 C:0 T:0
+		 * 74181 function F=A-B
+		 * T source is BUS
+		 */
+		case aluf_bus_minus_t:
+			alu = m_bus + ~m_t + 1;
+			m_aluc0 = (~alu >> 16) & 1;
+			flags = 0;
+			LOG((LOG_CPU,2,"    ALU<- BUS - T (%#o := %#o - %#o)\n", alu, m_bus, m_t));
+			break;
+
+		/**
+		 * 11: ALU <- BUS - T - 1
+		 * PROM data for S3-0:0110 M:0 C:1 T:0
+		 * 74181 function F=A-B-1
+		 * T source is BUS
+		 */
+		case aluf_bus_minus_t_minus_1:
+			alu = m_bus + ~m_t;
+			m_aluc0 = (~alu >> 16) & 1;
+			flags = 0;
+			LOG((LOG_CPU,2,"    ALU<- BUS - T - 1 (%#o := %#o - %#o - 1)\n", alu, m_bus, m_t));
+			break;
+
+		/**
+		 * 12: ALU <- BUS + T + 1
+		 * PROM data for S3-0:1001 M:0 C:0 T:1
+		 * 74181 function F=A+B+1
+		 * T source is ALU
+		 */
+		case aluf_bus_plus_t_plus_1__alut:
+			alu = m_bus + m_t + 1;
+			m_aluc0 = (alu >> 16) & 1;
+			flags = TSELECT;
+			LOG((LOG_CPU,2,"    ALU<- BUS + T + 1 (%#o := %#o + %#o + 1)\n", alu, m_bus, m_t));
+			break;
+
+		/**
+		 * 13: ALU <- BUS + SKIP
+		 * PROM data for S3-0:0000 M:0 C:SKIP T:1
+		 * 74181 function F=A (SKIP=1) or F=A+1 (SKIP=0)
+		 * T source is ALU
+		 */
+		case aluf_bus_plus_skip__alut:
+			alu = m_bus + m_emu.skip;
+			m_aluc0 = (alu >> 16) & 1;
+			flags = TSELECT;
+			LOG((LOG_CPU,2,"    ALU<- BUS + SKIP (%#o := %#o + %#o)\n", alu, m_bus, m_emu.skip));
+			break;
+
+		/**
+		 * 14: ALU <- BUS,T
+		 * PROM data for S3-0:1011 M:1 C:0 T:1
+		 * 74181 function F=A&B
+		 * T source is ALU
+		 */
+		case aluf_bus_and_t__alut:
+			alu = m_bus & m_t;
+			m_aluc0 = 1;
+			flags = ALUM | TSELECT;
+			LOG((LOG_CPU,2,"    ALU<- BUS,T (%#o := %#o & %#o)\n", alu, m_bus, m_t));
+			break;
+
+		/**
+		 * 15: ALU <- BUS & ~T
+		 * PROM data for S3-0:0111 M:1 C:0 T:0
+		 * 74181 function F=A&~B
+		 * T source is BUS
+		 */
+		case aluf_bus_and_not_t:
+			alu = m_bus & ~m_t;
+			m_aluc0 = 1;
+			flags = ALUM;
+			LOG((LOG_CPU,2,"    ALU<- BUS AND NOT T (%#o := %#o & ~%#o)\n", alu, m_bus, m_t));
+			break;
+
+		/**
+		 * 16: ALU <- BUS
+		 * PROM data for S3-0:1111 M:1 C:0 T:1
+		 * 74181 function F=A
+		 * T source is ALU
+		 */
+		case aluf_undef_16:
+			alu = m_bus;
+			m_aluc0 = 1;
+			flags = ALUM | TSELECT;
+			LOG((LOG_CPU,0,"    ALU<- 0 (illegal aluf in task %s, mpc:%05o aluf:%02o)\n", task_name(m_task), m_mpc, m_d_aluf));
+			break;
+
+		/**
+		 * 17: ALU <- BUS
+		 * PROM data for S3-0:1111 M:1 C:0 T:1
+		 * 74181 function F=A
+		 * T source is ALU
+		 */
+		case aluf_undef_17:
+		default:
+			alu = m_bus;
+			m_aluc0 = 1;
+			flags = ALUM | TSELECT;
+			LOG((LOG_CPU,0,"    ALU<- 0 (illegal aluf in task %s, mpc:%05o aluf:%02o)\n", task_name(m_task), m_mpc, m_d_aluf));
+		}
+		m_alu = static_cast(alu);
+#endif
+
+		// WRTRAM must happen now before L is changed
+		if (m_wrtram_flag)
+			wrtram();
+
+		// shifter passes L, if F1 is not one of L LSH 1, L RSH 1 or L LCY 8
+		m_shifter = m_l;
+
+		// late F1 function call now
+		((*this).*m_f1[1][m_task][m_d_f1])();
+
+		// late F2 function call now
+		((*this).*m_f2[1][m_task][m_d_f2])();
+
+		// late BS function call now, if no constant was put on the bus
+		if (do_bs)
+			((*this).*m_bs[1][m_task][m_d_bs])();
+
+		// update T register, if LOADT is set
+		if (m_d_loadt) {
+			m_cram_addr = m_alu;    // latch CRAM address
+			if (flags & TSELECT) {
+				m_t = m_alu;        // T source is ALU
+				LOG((LOG_CPU,2, "   T<- ALU (%#o)\n", m_alu));
+			} else {
+				m_t = m_bus;        // T source is BUS
+				LOG((LOG_CPU,2, "   T<- BUS (%#o)\n", m_bus));
+			}
+		}
+
+		// update L register and LALUC0 if LOADL is set
+		if (m_d_loadl) {
+			m_l = m_alu;            // load L from ALU
+			if (flags & ALUM) {
+				m_laluc0 = 0;       // logic operation - put 0 into latched carry
+				LOG((LOG_CPU,2, "   L<- ALU (%#o); LALUC0<- %o\n", m_alu, 0));
+			} else {
+				m_laluc0 = m_aluc0; // arithmethic operation - put ALU carry into latched carry
+				LOG((LOG_CPU,2, "   L<- ALU (%#o); LALUC0<- ALUC0 (%o)\n", m_alu, m_aluc0));
+			}
+			// update M (MYL) register, if a RAM related task is active
+			if (m_ram_related[m_task]) {
+				m_m = m_alu;        // load M from ALU, if 'GOODTASK'
+				m_s[m_s_reg_bank[m_task]][0] = m_alu;   // also writes to S[bank][0], which can't be read
+				LOG((LOG_CPU,2, "   M<- ALU (%#o)\n", m_alu));
+			}
+		}
+
+		// handle task switching
+		if (m_task != m_next2_task) {
+			// switch now?
+			if (m_task == m_next_task) {
+				// one more microinstruction
+				m_next_task = m_next2_task;
+			} else {
+				// save this task's next and next2
+				m_task_mpc[m_task] = m_next;
+				m_task_next2[m_task] = m_next2;
+				m_task = m_next_task;
+				LOG((LOG_CPU,1, "task switch to %02o:%s (cycle %lld)\n", m_task, task_name(m_task), cycle()));
+				m_next = m_task_mpc[m_task];    // get new task's mpc
+				m_next2 = m_task_next2[m_task]; // get address modifier after task switch (needed?)
+
+				// let the task know it becomes active now and (most probably) reset the wakeup
+				((*this).*m_active_callback[m_task])();
+			}
+		}
+
+		/**
+		 * Subtract the microcycle time from the display time accu.
+		 * If it underflows, call the display state machine and add
+		 * the time for 32(!) pixel clocks to the accu.
+		 * This is very close to every seventh CPU cycle (really?)
+		 */
+		if (m_dsp_time >= 0) {
+			m_dsp_time -= ALTO2_UCYCLE;
+			if (m_dsp_time < 0)
+				display_state_machine();
+		}
+		if (m_unload_time >= 0) {
+			/**
+			 * Subtract the microcycle time from the unload time accu.
+			 * If it underflows, call the unload word function which adds
+			 * the time for 16 or 32 pixel clocks to the accu, or ends
+			 * the unloading by leaving m_unload_time at -1.
+			 */
+			m_unload_time -= ALTO2_UCYCLE;
+			if (m_unload_time < 0)
+				unload_word();
+		}
+#if (USE_BITCLK_TIMER == 0)
+		if (m_bitclk_time >= 0) {
+			/*
+			 * Subtract the microcycle time from the bitclk time accu.
+			 * If it underflows, call the disk bitclk function which adds
+			 * the time for one bit as clocks to the accu, or ends
+			 * the bitclk sequence by leaving m_bitclk_time at -1.
+			 */
+			m_bitclk_time -= ALTO2_UCYCLE;
+			disk_bitclk(0, m_bitclk_index);
+		}
+#endif
+	} while (m_icount-- > 0);
+
+	/* save this task's mpc and address modifier */
+	m_task_mpc[m_task] = m_next;
+	m_task_next2[m_task] = m_next2;
+}
+
+/** @brief reset the various registers */
+void alto2_cpu_device::hard_reset()
+{
+	/* all tasks start in ROM0 */
+	m_reset_mode = 0xffff;
+
+	memset(&m_ram_related, 0, sizeof(m_ram_related));
+
+	// install standard handlers in all tasks
+	for (int task = 0; task < ALTO2_TASKS; task++) {
+		// every task starts at mpc = task number, in either ROM0 or RAM0
+		m_task_mpc[task] = (m_ctl2k_u38[task] >> 4) ^ 017;
+		m_active_callback[task] = &alto2_cpu_device::noop;
+		if (0 == (m_reset_mode & (1 << task)))
+			m_task_mpc[task] |= ALTO2_UCODE_RAM_BASE;
+
+		set_bs(task, bs_read_r,         &alto2_cpu_device::bs_early_read_r, 0);
+		set_bs(task, bs_load_r,         &alto2_cpu_device::bs_early_load_r, &alto2_cpu_device::bs_late_load_r);
+		set_bs(task, bs_no_source,      0, 0);
+		set_bs(task, bs_task_3,         &alto2_cpu_device::fn_bs_bad_0, &alto2_cpu_device::fn_bs_bad_1);    // task specific
+		set_bs(task, bs_task_4,         &alto2_cpu_device::fn_bs_bad_0, &alto2_cpu_device::fn_bs_bad_1);    // task specific
+		set_bs(task, bs_read_md,        &alto2_cpu_device::bs_early_read_md, 0);
+		set_bs(task, bs_mouse,          &alto2_cpu_device::bs_early_mouse, 0);
+		set_bs(task, bs_disp,           &alto2_cpu_device::bs_early_disp, 0);
+
+		set_f1(task, f1_nop,            0, 0);
+		set_f1(task, f1_load_mar,       0, &alto2_cpu_device::f1_late_load_mar);
+		set_f1(task, f1_task,           &alto2_cpu_device::f1_early_task, 0);
+		set_f1(task, f1_block,          &alto2_cpu_device::fn_f1_bad_0, &alto2_cpu_device::fn_f1_bad_1);    // not all tasks have the f1_block
+		set_f1(task, f1_l_lsh_1,        0, &alto2_cpu_device::f1_late_l_lsh_1);
+		set_f1(task, f1_l_rsh_1,        0, &alto2_cpu_device::f1_late_l_rsh_1);
+		set_f1(task, f1_l_lcy_8,        0, &alto2_cpu_device::f1_late_l_lcy_8);
+		set_f1(task, f1_const,          0, 0);
+		set_f1(task, f1_task_10,        &alto2_cpu_device::fn_f1_bad_0, &alto2_cpu_device::fn_f1_bad_1);    // f1_task_10 to f1_task_17 are task specific
+		set_f1(task, f1_task_11,        &alto2_cpu_device::fn_f1_bad_0, &alto2_cpu_device::fn_f1_bad_1);    // f1_task_10 to f1_task_17 are task specific
+		set_f1(task, f1_task_12,        &alto2_cpu_device::fn_f1_bad_0, &alto2_cpu_device::fn_f1_bad_1);    // f1_task_10 to f1_task_17 are task specific
+		set_f1(task, f1_task_13,        &alto2_cpu_device::fn_f1_bad_0, &alto2_cpu_device::fn_f1_bad_1);    // f1_task_10 to f1_task_17 are task specific
+		set_f1(task, f1_task_14,        &alto2_cpu_device::fn_f1_bad_0, &alto2_cpu_device::fn_f1_bad_1);    // f1_task_10 to f1_task_17 are task specific
+		set_f1(task, f1_task_15,        &alto2_cpu_device::fn_f1_bad_0, &alto2_cpu_device::fn_f1_bad_1);    // f1_task_10 to f1_task_17 are task specific
+		set_f1(task, f1_task_16,        &alto2_cpu_device::fn_f1_bad_0, &alto2_cpu_device::fn_f1_bad_1);    // f1_task_10 to f1_task_17 are task specific
+		set_f1(task, f1_task_17,        &alto2_cpu_device::fn_f1_bad_0, &alto2_cpu_device::fn_f1_bad_1);    // f1_task_10 to f1_task_17 are task specific
+
+		set_f2(task, f2_nop,            0, 0);
+		set_f2(task, f2_bus_eq_zero,    0, &alto2_cpu_device::f2_late_bus_eq_zero);
+		set_f2(task, f2_shifter_lt_zero,0, &alto2_cpu_device::f2_late_shifter_lt_zero);
+		set_f2(task, f2_shifter_eq_zero,0, &alto2_cpu_device::f2_late_shifter_eq_zero);
+		set_f2(task, f2_bus,            0, &alto2_cpu_device::f2_late_bus);
+		set_f2(task, f2_alucy,          0, &alto2_cpu_device::f2_late_alucy);
+		set_f2(task, f2_load_md,        0, &alto2_cpu_device::f2_late_load_md);
+		set_f2(task, f2_const,          0, 0);
+		set_f2(task, f2_task_10,        &alto2_cpu_device::fn_f2_bad_0, &alto2_cpu_device::fn_f2_bad_1);    // f2_task_10 to f2_task_17 are task specific
+		set_f2(task, f2_task_11,        &alto2_cpu_device::fn_f2_bad_0, &alto2_cpu_device::fn_f2_bad_1);    // f2_task_10 to f2_task_17 are task specific
+		set_f2(task, f2_task_12,        &alto2_cpu_device::fn_f2_bad_0, &alto2_cpu_device::fn_f2_bad_1);    // f2_task_10 to f2_task_17 are task specific
+		set_f2(task, f2_task_13,        &alto2_cpu_device::fn_f2_bad_0, &alto2_cpu_device::fn_f2_bad_1);    // f2_task_10 to f2_task_17 are task specific
+		set_f2(task, f2_task_14,        &alto2_cpu_device::fn_f2_bad_0, &alto2_cpu_device::fn_f2_bad_1);    // f2_task_10 to f2_task_17 are task specific
+		set_f2(task, f2_task_15,        &alto2_cpu_device::fn_f2_bad_0, &alto2_cpu_device::fn_f2_bad_1);    // f2_task_10 to f2_task_17 are task specific
+		set_f2(task, f2_task_16,        &alto2_cpu_device::fn_f2_bad_0, &alto2_cpu_device::fn_f2_bad_1);    // f2_task_10 to f2_task_17 are task specific
+		set_f2(task, f2_task_17,        &alto2_cpu_device::fn_f2_bad_0, &alto2_cpu_device::fn_f2_bad_1);    // f2_task_10 to f2_task_17 are task specific
+	}
+
+	init_memory();
+	init_disk();
+	init_disp();
+	init_kbd();
+	init_mouse();
+	init_hw();
+
+	init_emu();
+	init_ksec();
+	init_ether();
+	init_mrt();
+	init_dwt();
+	init_curt();
+	init_dht();
+	init_dvt();
+	init_part();
+	init_kwd();
+
+	m_dsp_time = 0;                 // reset the display state timing
+	m_task = task_emu;              // start with task 0 (emulator)
+	m_task_wakeup |= 1 << task_emu; // set wakeup flag
+}
+
+/** @brief software initiated reset (STARTF) */
+void alto2_cpu_device::soft_reset()
+{
+	for (int task = 0; task < ALTO2_TASKS; task++) {
+		// every task starts at mpc = task number, in either ROM0 or RAM0
+		m_task_mpc[task] = (m_ctl2k_u38[task] >> 4) ^ 017;
+		if (0 == (m_reset_mode & (1 << task)))
+			m_task_mpc[task] |= ALTO2_UCODE_RAM_BASE;
+	}
+	m_next2_task = task_emu;        // switch to task 0 (emulator)
+	m_reset_mode = 0xffff;          // all tasks start in ROM0 again
+	m_task = task_emu;              // set current task to emulator
+	m_task_wakeup = 1 << task_emu;  // set only the emulator task wakeup flag
+
+	m_dsp_time = 0;                 // reset the display state machine timing accu
+	m_unload_time = 0;              // reset the word unload timing accu
+#if (USE_BITCLK_TIMER == 0)
+	m_bitclk_time = 0;              // reset the bitclk timing accu
+#endif
+}
diff --git a/src/devices/cpu/alto2/alto2cpu.h b/src/devices/cpu/alto2/alto2cpu.h
new file mode 100644
index 00000000000..1e2640e6ac0
--- /dev/null
+++ b/src/devices/cpu/alto2/alto2cpu.h
@@ -0,0 +1,946 @@
+// license:BSD-3-Clause
+// copyright-holders:Juergen Buchmueller
+/*****************************************************************************
+ *
+ *   Xerox AltoII CPU core interface
+ *
+ *****************************************************************************/
+#ifndef _CPU_ALTO2_H_
+#define _CPU_ALTO2_H_
+
+#define ALTO2_TAG "alto2"
+
+#include "emu.h"
+#include "debugger.h"
+#include "machine/diablo_hd.h"
+
+/**
+ * \brief AltoII register names
+ */
+enum {
+	// micro code task, micro program counter, next and next2
+	A2_TASK, A2_MPC, A2_NEXT, A2_NEXT2,
+	// BUS, ALU, temp, latch, memory latch and carry flags
+	A2_BUS, A2_T, A2_ALU, A2_ALUC0, A2_L, A2_SHIFTER, A2_LALUC0, A2_M,
+	A2_R,   // 32 R registers
+	A2_AC3 = A2_R, A2_AC2, A2_AC1, A2_AC0, A2_R04, A2_R05, A2_PC,  A2_R07,
+	A2_R10, A2_R11, A2_R12, A2_R13, A2_R14, A2_R15, A2_R16, A2_R17,
+	A2_R20, A2_R21, A2_R22, A2_R23, A2_R24, A2_R25, A2_R26, A2_R27,
+	A2_R30, A2_R31, A2_R32, A2_R33, A2_R34, A2_R35, A2_R36, A2_R37,
+	A2_S,   // 32 S registers
+	A2_S00 = A2_S, A2_S01, A2_S02, A2_S03, A2_S04, A2_S05, A2_S06, A2_S07,
+	A2_S10, A2_S11, A2_S12, A2_S13, A2_S14, A2_S15, A2_S16, A2_S17,
+	A2_S20, A2_S21, A2_S22, A2_S23, A2_S24, A2_S25, A2_S26, A2_S27,
+	A2_S30, A2_S31, A2_S32, A2_S33, A2_S34, A2_S35, A2_S36, A2_S37,
+	// DISK controller registers
+	A2_DRIVE, A2_KADDR, A2_KADR, A2_KSTAT, A2_KCOM, A2_KRECNO,
+	A2_SHIFTIN, A2_SHIFTOUT, A2_DATAIN, A2_DATAOUT, A2_KRWC,
+	A2_KFER, A2_WDTSKENA, A2_WDINIT0, A2_WDINIT, A2_STROBE,
+	A2_BITCLK, A2_DATIN, A2_BITCNT, A2_CARRY, A2_SECLATE,
+	A2_SEEKOK, A2_OKTORUN, A2_READY
+};
+
+#ifndef ALTO2_DEBUG
+#define ALTO2_DEBUG             1           //!< define to 1 to enable logerror() output
+#endif
+
+#ifndef ALTO2_CRAM_CONFIG
+#define ALTO2_CRAM_CONFIG       2           //!< use default CROM/CRAM configuration 2
+#endif
+
+#define ALTO2_FAKE_STATUS_H     12          //!< number of extra scanlines to display some status info
+
+#define USE_PRIO_F9318          0           //!< define to 1 to use the F9318 priority encoder code
+#define USE_ALU_74181           1           //!< define to 1 to use the SN74181 ALU code
+#define USE_BITCLK_TIMER        0           //!< define to 1 to use a very high rate timer for the disk bit clock
+#define USE_HAMMING_CHECK       1           //!< define to 1 to use the Hamming code and Parity check in a2mem
+
+#define ALTO2_TASKS             16          //!< 16 task slots
+#define ALTO2_REGS              32          //!< 32 16-bit words in the R register file
+#define ALTO2_ALUF              16          //!< 16 ALU functions (74181)
+#define ALTO2_BUSSRC            8           //!< 8 bus sources
+#define ALTO2_F1MAX             16          //!< 16 F1 functions
+#define ALTO2_F2MAX             16          //!< 16 F2 functions
+#define ALTO2_UCYCLE            169542      //!< time in pico seconds for a CPU micro cycle: 29.4912MHz/5 -> 5.898240Hz ~= 169.542ns/clock
+
+#define ALTO2_CONST_SIZE        256         //!< number words in the constant ROM
+
+//! inverted bits in the micro instruction 32 bit word
+#define ALTO2_UCODE_INVERTED    ((1 << 10) | (1 << 15) | (1 << 19))
+
+/********************************************************************************
+ * Bit field primitives
+ * These are some macros to make it easier to access variable by the bit-
+ * reversed notation that the Xerox Alto documents use all over the place.
+ * Bit number 0 is the most significant there,
+ * and bit number (width - 1) is the least significant.
+ * The X_ is for Xerox and to avoid collisions with MAME generic macros.
+ ********************************************************************************/
+
+//! get the left shift required to access bit %to in a word of %width bits
+#define X_BITSHIFT(width,to) ((width) - 1 - (to))
+
+//! build a least significant bit mask for bits %from to %to (inclusive)
+#define X_BITMASK(from,to) ((1ul << ((to) + 1 - (from))) - 1)
+
+//! get a single bit number %bit value from %reg, a word of %width bits
+#define X_BIT(reg,width,bit) (((reg) >> X_BITSHIFT(width,bit)) & 1)
+
+//! get a bit field from %reg, a word of %width bits, starting at bit %from until bit %to
+#define X_RDBITS(reg,width,from,to) (((reg) >> X_BITSHIFT(width,to)) & X_BITMASK(from,to))
+
+//! put a value %val into %reg, a word of %width bits, starting at bit %from until bit %to
+#define X_WRBITS(reg,width,from,to,val) do { \
+	UINT32 mask = X_BITMASK(from,to) << X_BITSHIFT(width,to); \
+	reg = ((reg) & ~mask) | (((val) << X_BITSHIFT(width,to)) & mask); \
+} while (0)
+
+#if ALTO2_DEBUG
+	enum LOG_TYPE_ENUM {
+		LOG_0,
+		LOG_CPU     = (1 <<  0),
+		LOG_EMU     = (1 <<  1),
+		LOG_T01     = (1 <<  2),
+		LOG_T02     = (1 <<  3),
+		LOG_T03     = (1 <<  4),
+		LOG_KSEC    = (1 <<  5),
+		LOG_T05     = (1 <<  6),
+		LOG_T06     = (1 <<  7),
+		LOG_ETH     = (1 <<  8),
+		LOG_MRT     = (1 <<  9),
+		LOG_DWT     = (1 << 10),
+		LOG_CURT    = (1 << 11),
+		LOG_DHT     = (1 << 12),
+		LOG_DVT     = (1 << 13),
+		LOG_PART    = (1 << 14),
+		LOG_KWD     = (1 << 15),
+		LOG_T17     = (1 << 16),
+		LOG_MEM     = (1 << 17),
+		LOG_RAM     = (1 << 18),
+		LOG_DRIVE   = (1 << 19),
+		LOG_DISK    = (1 << 20),
+		LOG_DISPL   = (1 << 21),
+		LOG_MOUSE   = (1 << 22),
+		LOG_HW      = (1 << 23),
+		LOG_KBD     = (1 << 24),
+		LOG_ALL     = ((1 << 25) - 1)
+	};
+	extern int m_log_types;
+	extern int m_log_level;
+	extern bool m_log_newline;
+	void logprintf(int type, int level, const char* format, ...);
+#   define  LOG(x) logprintf x
+#else
+#   define  LOG(x)
+#endif
+
+//*******************************************
+// define constants from the sub-devices
+//*******************************************
+#define ALTO2_DEFINE_CONSTANTS 1
+#include "a2jkff.h"
+#include "a2ram.h"
+#include "a2hw.h"
+#include "a2kbd.h"
+#include "a2mouse.h"
+#include "a2disk.h"
+#include "a2disp.h"
+#include "a2mem.h"
+#include "a2emu.h"
+#include "a2ksec.h"
+#include "a2ether.h"
+#include "a2mrt.h"
+#include "a2dwt.h"
+#include "a2curt.h"
+#include "a2dht.h"
+#include "a2dvt.h"
+#include "a2part.h"
+#include "a2dwt.h"
+#include "a2kwd.h"
+#undef ALTO2_DEFINE_CONSTANTS
+
+class alto2_cpu_device :  public cpu_device
+{
+public:
+	// construction/destruction
+	alto2_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+	~alto2_cpu_device();
+
+	//! driver interface to set diablo_hd_device
+	void set_diablo(int unit, diablo_hd_device* ptr);
+
+	//! call in for the next sector callback
+	void next_sector(int unit);
+
+	//! update the screen bitmap
+	UINT32 screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
+
+	//! screen VBLANK handler
+	void screen_eof(screen_device &screen, bool state);
+
+	DECLARE_ADDRESS_MAP( ucode_map, 32 );
+	DECLARE_ADDRESS_MAP( const_map, 16 );
+	DECLARE_ADDRESS_MAP( iomem_map, 16 );
+
+	//! register a mouse motion in x direction
+	DECLARE_INPUT_CHANGED_MEMBER( mouse_motion_x );
+	//! register a mouse motion in y direction
+	DECLARE_INPUT_CHANGED_MEMBER( mouse_motion_y );
+	//! register a mouse button change
+	DECLARE_INPUT_CHANGED_MEMBER( mouse_button_0 );
+	DECLARE_INPUT_CHANGED_MEMBER( mouse_button_1 );
+	DECLARE_INPUT_CHANGED_MEMBER( mouse_button_2 );
+
+protected:
+	//! device-level override for start
+	virtual void device_start();
+	//! device-level override for reset
+	virtual void device_reset();
+
+	//! device-level override for post reset
+	void interface_post_reset();
+
+	//! device_execute_interface overrides
+	virtual UINT32 execute_min_cycles() const { return 1; }
+	virtual UINT32 execute_max_cycles() const { return 1; }
+	virtual UINT32 execute_input_lines() const { return 1; }
+	virtual void execute_run();
+	virtual void execute_set_input(int inputnum, int state);
+
+	//! device_memory_interface overrides
+	virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const;
+
+	//! device (P)ROMs
+	virtual const rom_entry *device_rom_region() const;
+	//! device_state_interface overrides
+	void state_string_export(const device_state_entry &entry, std::string &str);
+
+	//! device_disasm_interface overrides
+	virtual UINT32 disasm_min_opcode_bytes() const { return 4; }
+	virtual UINT32 disasm_max_opcode_bytes() const { return 4; }
+	virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options);
+
+private:
+
+	void fatal(int level, const char *format, ...);
+
+	address_space_config m_ucode_config;
+	address_space_config m_const_config;
+	address_space_config m_iomem_config;
+
+	address_space* m_iomem;
+
+	UINT8* m_ucode_crom;
+	UINT8* m_ucode_cram;
+	UINT8* m_const_data;
+
+	//! read microcode CROM
+	DECLARE_READ32_MEMBER ( crom_r );
+
+	//! read microcode CRAM
+	DECLARE_READ32_MEMBER ( cram_r );
+
+	//! write microcode CRAM
+	DECLARE_WRITE32_MEMBER( cram_w );
+
+	//! read constants PROM
+	DECLARE_READ16_MEMBER ( const_r );
+
+	//! read i/o space RAM
+	DECLARE_READ16_MEMBER ( ioram_r );
+
+	//!< write i/o space RAM
+	DECLARE_WRITE16_MEMBER( ioram_w );
+
+	//!< read memory mapped i/o
+	DECLARE_READ16_MEMBER ( mmio_r );
+
+	//!< write memory mapped i/o
+	DECLARE_WRITE16_MEMBER( mmio_w );
+
+	int m_icount;
+
+	typedef void (alto2_cpu_device::*a2func)();
+
+	//! task numbers
+	enum {
+		task_emu,       //!< emulator task
+		task_1,         //!< unused
+		task_2,         //!< unused
+		task_3,         //!< unused
+		task_ksec,      //!< disk sector task
+		task_5,         //!< unused
+		task_6,         //!< unused
+		task_ether,     //!< ethernet task
+		task_mrt,       //!< memory refresh task
+		task_dwt,       //!< display word task
+		task_curt,      //!< cursor task
+		task_dht,       //!< display horizontal task
+		task_dvt,       //!< display vertical task
+		task_part,      //!< parity task
+		task_kwd,       //!< disk word task
+		task_17         //!< unused task slot 017
+	};
+
+	//! register select values accessing R (Note: register numbers are octal)
+	enum {
+		rsel_ac3,       //!< AC3 used by emulator as accu 3. Also used by Mesa emulator to keep bytecode to execute after breakpoint
+		rsel_ac2,       //!< AC2 used by emulator as accu 2. Also used by Mesa emulator as x register for xfer
+		rsel_ac1,       //!< AC1 used by emulator as accu 1. Also used by Mesa emulator as r-temporary for return indices and values
+		rsel_ac0,       //!< AC0 used by emulator as accu 0. Also used by Mesa emulator as new field bits for WF and friends
+		rsel_r04,       //!< NWW state of the interrupt system
+		rsel_r05,       //!< SAD. Also used by Mesa emulator as scratch R-register for counting
+		rsel_pc,        //!< PC used by emulator as program counter
+		rsel_r07,       //!< XREG. Also used by Mesa emulator as task hole, i.e. pigeonhole for saving things across tasks.
+		rsel_r10,       //!< XH. Also used by Mesa emulator as instruction byte register
+		rsel_r11,       //!< CLOCKTEMP - used in the MRT
+		rsel_r12,       //!< ECNTR remaining words in buffer - ETHERNET
+		rsel_r13,       //!< EPNTR points BEFORE next word in buffer - ETHERNET
+		rsel_r14,
+		rsel_r15,       //!< MPC. Used by the Mesa emulator as program counter
+		rsel_r16,       //!< STKP. Used by the Mesa emulator as stack pointer [0-10] 0 empty, 10 full
+		rsel_r17,       //!< XTSreg. Used by the Mesa emulator to xfer trap state
+		rsel_r20,       //!< CURX. Holds cursor X; used by the cursor task
+		rsel_r21,       //!< CURDATA. Holds the cursor data; used by the cursor task
+		rsel_r22,       //!< CBA. Holds the address of the currently active DCB+1
+		rsel_r23,       //!< AECL. Holds the address of the end of the current scanline's bitmap
+		rsel_r24,       //!< SLC. Holds the number of scanlines remaining in currently active DCB
+		rsel_r25,       //!< MTEMP. Holds the temporary cell
+		rsel_r26,       //!< HTAB. Holds the number of tab words remaining on current scanline
+		rsel_r27,       //!< YPOS
+		rsel_r30,       //!< DWA. Holds the address of the bit map doubleword currently being fetched for transmission to the hardware buffer.
+		rsel_r31,       //!< KWDCT. Used by the disk tasks as word counter
+		rsel_r32,       //!< CKSUMR. Used by the disk tasks as checksum register (and *amble counter?)
+		rsel_r33,       //!< KNMAR. Used by the disk tasks as transfer memory address register
+		rsel_r34,       //!< DCBR. Used by the disk tasks to keep the current device control block
+		rsel_r35,       //!< TEMP. Used by the Mesa emulator, and also by BITBLT
+		rsel_r36,       //!< TEMP2. Used by the Mesa emulator, and also by BITBLT
+		rsel_r37        //!< CLOCKREG. Low order bits of the real time clock
+	};
+
+	//! ALU function numbers
+	enum {
+		/**
+		 * \brief 00: ALU <- BUS
+		 * PROM data for S3-0,M,C,T: 1111/1/0/0
+		 * function F=A
+		 * T source is ALU
+		 */
+		aluf_bus__alut,
+		/**
+		 * \brief 01: ALU <- T
+		 * PROM data for S3-0,M,C,T: 1010/1/0/0
+		 * function F=B
+		 * T source is BUS
+		 */
+		aluf_treg,
+		/**
+		 * \brief 02: ALU <- BUS | T
+		 * PROM data for S3-0,M,C,T: 1110/1/0/1
+		 * function F=A|B
+		 * T source is ALU
+		 */
+		aluf_bus_or_t__alut,
+		/**
+		 * \brief 03: ALU <- BUS & T
+		 * PROM data for S3-0,M,C,T: 1011/1/0/0
+		 * function F=A&B
+		 * T source is BUS
+		 */
+		aluf_bus_and_t,
+		/**
+		 * \brief 04: ALU <- BUS ^ T
+		 * PROM data for S3-0,M,C,T: 0110/1/0/0
+		 * function F=A^B
+		 * T source is BUS
+		 */
+		aluf_bus_xor_t,
+		/**
+		 * \brief 05: ALU <- BUS + 1
+		 * PROM data for S3-0,M,C,T: 0000/0/0/1
+		 * function F=A+1
+		 * T source is ALU
+		 */
+		aluf_bus_plus_1__alut,
+		/**
+		 * \brief 06: ALU <- BUS - 1
+		 * PROM data for S3-0,M,C,T: 1111/0/1/1
+		 * function F=A-1
+		 * T source is ALU
+		 */
+		aluf_bus_minus_1__alut,
+		/**
+		 * \brief 07: ALU <- BUS + T
+		 * PROM data for S3-0,M,C,T: 1001/0/1/0
+		 * function F=A+B
+		 * T source is BUS
+		 */
+		aluf_bus_plus_t,
+		/**
+		 * \brief 10: ALU <- BUS - T
+		 * PROM data for S3-0,M,C,T: 0110/0/0/0
+		 * function F=A-B
+		 * T source is BUS
+		 */
+		aluf_bus_minus_t,
+		/**
+		 * \brief 11: ALU <- BUS - T - 1
+		 * PROM data for S3-0,M,C,T: 0110/0/1/0
+		 * function F=A-B-1
+		 * T source is BUS
+		 */
+		aluf_bus_minus_t_minus_1,
+		/**
+		 * \brief 12: ALU <- BUS + T + 1
+		 * PROM data for S3-0,M,C: 1001/0/0
+		 * function F=A+B+1
+		 * T source is ALU
+		 */
+		aluf_bus_plus_t_plus_1__alut,
+		/**
+		 * \brief 13: ALU <- BUS + SKIP
+		 * PROM data for S3-0,M,C,T: 0000/0/SKIP/1
+		 * function F=A (SKIP=1) or F=A+1 (SKIP=0)
+		 * T source is ALU
+		 */
+		aluf_bus_plus_skip__alut,
+		/**
+		 * \brief 14: ALU <- BUS & T
+		 * PROM data for S3-0,M,C,T: 1011/1/0/1
+		 * function F=A&B
+		 * T source is ALU
+		 */
+		aluf_bus_and_t__alut,
+		/**
+		 * \brief 15: ALU <- BUS & ~T
+		 * PROM data for S3-0,M,C,T: 0111/1/0/0
+		 * function F=A&~B
+		 * T source is BUS
+		 */
+		aluf_bus_and_not_t,
+		/**
+		 * \brief 16: ALU <- BUS
+		 * PROM data for S3-0,M,C,T: 1111/1/0/1
+		 * function F=A
+		 * T source is ALU
+		 */
+		aluf_undef_16,
+		/**
+		 * \brief 17: ALU <- BUS
+		 * PROM data for S3-0,M,C,T: 1111/1/0/1
+		 * function F=A
+		 * T source is ALU
+		 */
+		aluf_undef_17
+	};
+
+	//! BUS source selection numbers
+	enum {
+		bs_read_r,                          //!< BUS source is R register
+		bs_load_r,                          //!< load R register from BUS
+		bs_no_source,                       //!< BUS is open (0177777)
+		bs_task_3,                          //!< BUS source is task specific
+		bs_task_4,                          //!< BUS source is task specific
+		bs_read_md,                         //!< BUS source is memory data
+		bs_mouse,                           //!< BUS source is mouse data
+		bs_disp                             //!< BUS source displacement (emulator task)
+	};
+
+	//! Function 1 numbers
+	enum {
+		f1_nop,                             //!< f1 00 no operation
+		f1_load_mar,                        //!< f1 01 load memory address register
+		f1_task,                            //!< f1 02 task switch
+		f1_block,                           //!< f1 03 task block
+		f1_l_lsh_1,                         //!< f1 04 left shift L once
+		f1_l_rsh_1,                         //!< f1 05 right shift L once
+		f1_l_lcy_8,                         //!< f1 06 cycle L 8 times
+		f1_const,                           //!< f1 07 constant from PROM
+
+		f1_task_10,                         //!< f1 10 task specific
+		f1_task_11,                         //!< f1 11 task specific
+		f1_task_12,                         //!< f1 12 task specific
+		f1_task_13,                         //!< f1 13 task specific
+		f1_task_14,                         //!< f1 14 task specific
+		f1_task_15,                         //!< f1 15 task specific
+		f1_task_16,                         //!< f1 16 task specific
+		f1_task_17                          //!< f1 17 task specific
+	};
+
+	//! Function 2 numbers
+	enum {
+		f2_nop,                             //!< f2 00 no operation
+		f2_bus_eq_zero,                     //!< f2 01 branch on bus equals 0
+		f2_shifter_lt_zero,                 //!< f2 02 branch on shifter less than 0
+		f2_shifter_eq_zero,                 //!< f2 03 branch on shifter equals 0
+		f2_bus,                             //!< f2 04 branch on BUS[6-15]
+		f2_alucy,                           //!< f2 05 branch on (latched) ALU carry
+		f2_load_md,                         //!< f2 06 load memory data
+		f2_const,                           //!< f2 07 constant from PROM
+
+		f2_task_10,                         //!< f2 10 task specific
+		f2_task_11,                         //!< f2 11 task specific
+		f2_task_12,                         //!< f2 12 task specific
+		f2_task_13,                         //!< f2 13 task specific
+		f2_task_14,                         //!< f2 14 task specific
+		f2_task_15,                         //!< f2 15 task specific
+		f2_task_16,                         //!< f2 16 task specific
+		f2_task_17                          //!< f2 17 task specific
+	};
+
+	//! enumeration of the micro code word bits
+	//! Note: The Alto documents enumerate bits from left (MSB = 0) to right (LSB = 31)
+	enum {
+		DRSEL0, DRSEL1, DRSEL2, DRSEL3, DRSEL4,
+		DALUF0, DALUF1, DALUF2, DALUF3,
+		DBS0, DBS1, DBS2,
+		DF1_0, DF1_1, DF1_2, DF1_3,
+		DF2_0, DF2_1, DF2_2, DF2_3,
+		DLOADT,
+		DLOADL,
+		NEXT0, NEXT1, NEXT2, NEXT3, NEXT4, NEXT5, NEXT6, NEXT7, NEXT8, NEXT9
+	};
+
+	//! get the normally accessed bank number from a bank register
+	static inline UINT16 GET_BANK_NORMAL(UINT16 breg) { return X_RDBITS(breg,16,12,13); }
+
+	//! get the extended bank number (accessed via XMAR) from a bank register
+	static inline UINT16 GET_BANK_EXTENDED(UINT16 breg) { return X_RDBITS(breg,16,14,15); }
+
+	//! get an ignored bit field from a control RAM address
+	static inline UINT16 GET_CRAM_IGNORE(UINT16 addr) { return X_RDBITS(addr,16,0,1); }
+
+	//! get the bank select bit field from a control RAM address
+	static inline UINT16 GET_CRAM_BANKSEL(UINT16 addr) { return X_RDBITS(addr,16,2,3); }
+
+	//! get the ROM/RAM flag from a control RAM address
+	static inline UINT16 GET_CRAM_RAMROM(UINT16 addr) { return X_RDBITS(addr,16,4,4); }
+
+	//! get the half select flag from a control RAM address
+	static inline UINT16 GET_CRAM_HALFSEL(UINT16 addr) { return X_RDBITS(addr,16,5,5); }
+
+	//! get the word address bit field from a control RAM address
+	static inline UINT16 GET_CRAM_WORDADDR(UINT16 addr) { return X_RDBITS(addr,16,6,15); }
+
+	UINT16 m_task_mpc[ALTO2_TASKS];                 //!< per task micro program counter
+	UINT16 m_task_next2[ALTO2_TASKS];               //!< per task address modifier
+	UINT8 m_task;                                   //!< active task
+	UINT8 m_next_task;                              //!< next micro instruction's task
+	UINT8 m_next2_task;                             //!< next but one micro instruction's task
+	UINT16 m_mpc;                                   //!< micro program counter
+	UINT32 m_mir;                                   //!< micro instruction register
+
+	/**
+	 * \brief current micro instruction's register selection
+	 * The emulator F2s ACSOURCE and ACDEST modify this.
+	 * Note: The S registers are addressed by the original RSEL[0-4],
+	 * even when the emulator modifies this.
+	 */
+	UINT8 m_rsel;
+	UINT8 m_d_rsel;                                 //!< decoded RSEL[0-4]
+	UINT8 m_d_aluf;                                 //!< decoded ALUF[0-3] function
+	UINT8 m_d_bs;                                   //!< decoded BS[0-2] bus source
+	UINT8 m_d_f1;                                   //!< decoded F1[0-3] function
+	UINT8 m_d_f2;                                   //!< decoded F2[0-3] function
+	UINT8 m_d_loadt;                                    //!< decoded LOADT flag
+	UINT8 m_d_loadl;                                    //!< decoded LOADL flag
+	UINT16 m_next;                                  //!< current micro instruction's next
+	UINT16 m_next2;                                 //!< next micro instruction's next
+	UINT16 m_r[ALTO2_REGS];                         //!< R register file
+	UINT16 m_s[ALTO2_SREG_BANKS][ALTO2_REGS];       //!< S register file(s)
+	UINT16 m_bus;                                   //!< wired-AND bus
+	UINT16 m_t;                                     //!< T register
+	UINT16 m_alu;                                   //!< the current ALU
+	UINT16 m_aluc0;                                 //!< the current ALU carry output
+	UINT16 m_l;                                     //!< L register
+	UINT16 m_shifter;                               //!< shifter output
+	UINT16 m_laluc0;                                //!< the latched ALU carry output
+	UINT16 m_m;                                     //!< M register of RAM related tasks (MYL latch in the schematics)
+	UINT16 m_cram_addr;                             //!< constant RAM address
+	UINT16 m_task_wakeup;                           //!< task wakeup: bit 1<
+	 * PROM u3 is 256x4 type 3601-1, looks like SN74387, and it
+	 * controls NEXT[6-9]', i.e. the outputs are wire-AND to NEXT
+	 *
+	 *           SN74387
+	 *         +---+-+---+
+	 *         |   +-+   |
+	 *    A6  -|1      16|-  Vcc
+	 *         |         |
+	 *    A5  -|2      15|-  A7
+	 *         |         |
+	 *    A4  -|3      14|-  FE1'
+	 *         |         |
+	 *    A3  -|4      13|-  FE2'
+	 *         |         |
+	 *    A0  -|5      12|-  D0
+	 *         |         |
+	 *    A1  -|6      11|-  D1
+	 *         |         |
+	 *    A2  -|7      10|-  D2
+	 *         |         |
+	 *   GND  -|8       9|-  D3
+	 *         |         |
+	 *         +---------+
+	 *
+	 *
+	 * It is enabled whenever the Emulator task is active and:
+	 *  both F2[0] and F2[1] are 1  F2 functions 014, 015, 016, 017
+	 *  F2=14 is 0                  not for F2 = 14 (load IR<-)
+	 *  IR[0] is 0                  not for arithmetic group
+	 *
+	 * This means it controls the F2 functions 015:IDISP<- and 016:<-ACSOURCE
+	 *
+	 * Its address lines are:
+	 *  line   pin   connected to         load swap
+	 *  -------------------------------------------------------------------
+	 *  A0     5     F2[2] (i.e. MIR[18]) IR[07]
+	 *  A1     6     IR[01]               IR[06]
+	 *  A2     7     IR[02]               IR[05]
+	 *  A3     4     IR[03]               IR[04]
+	 *  A4     3     IR[04]               IR[03]
+	 *  A5     2     IR[05]               IR[02]
+	 *  A6     1     IR[06]               IR[01]
+	 *  A7     15    IR[07]               F2[2]
+	 *
+	 * Its data lines are:
+	 *  line   pin   connected to         load
+	 *  -------------------------------------------------------------------
+	 *  D3     9     NEXT[06]'            NEXT[06]
+	 *  D2     10    NEXT[07]'            NEXT[07]
+	 *  D1     11    NEXT[08]'            NEXT[08]
+	 *  D0     12    NEXT[09]'            NEXT[09]
+	 *
+	 * Its address lines are reversed at load time to make it easier to
+	 * access it. Also both, address and data lines, are inverted.
+	 * 
+ */ + UINT8* m_ctl2k_u3; + + /** + * @brief 2KCTL PROM u38; 82S23; 32x8 bit + *
+	 *
+	 *            82S23
+	 *         +---+-+---+
+	 *         |   +-+   |
+	 *    B0  -|1      16|-  Vcc
+	 *         |         |
+	 *    B1  -|2      15|-  EN'
+	 *         |         |
+	 *    B2  -|3      14|-  A4
+	 *         |         |
+	 *    B3  -|4      13|-  A3
+	 *         |         |
+	 *    B4  -|5      12|-  A2
+	 *         |         |
+	 *    B5  -|6      11|-  A1
+	 *         |         |
+	 *    B6  -|7      10|-  A0
+	 *         |         |
+	 *   GND  -|8       9|-  B7
+	 *         |         |
+	 *         +---------+
+	 *
+	 * Task priority encoder
+	 *
+	 *  line   pin    signal
+	 *  -------------------------------
+	 *  A0     10     CT1 (current task LSB)
+	 *  A1     11     CT2
+	 *  A2     12     CT4
+	 *  A3     13     CT8 (current task MSB)
+	 *  A4     14     0 (GND)
+	 *
+	 *  line   pin    signal
+	 *  -------------------------------
+	 *  B0     1      RDCT8'
+	 *  B1     2      RDCT4'
+	 *  B2     3      RDCT2'
+	 *  B3     4      RDCT1'
+	 *  B4     5      NEXT[09]'
+	 *  B5     6      NEXT[08]'
+	 *  B6     7      NEXT[07]'
+	 *  B7     9      NEXT[06]'
+	 * 
+ */ + UINT8* m_ctl2k_u38; + + //! output lines of the 2KCTL U38 PROM + enum { + U38_RDCT8, + U38_RDCT4, + U38_RDCT2, + U38_RDCT1, + U38_NEXT09, + U38_NEXT08, + U38_NEXT07, + U38_NEXT06 + }; + + /** + * @brief 2KCTL PROM u76; P3601-1; 256x4; PC0I and PC1I decoding + *
+	 * Replacement for u51, which is used in 1KCTL
+	 *
+	 *           SN74387
+	 *         +---+-+---+
+	 *         |   +-+   |
+	 *    A6  -|1      16|-  Vcc
+	 *         |         |
+	 *    A5  -|2      15|-  A7
+	 *         |         |
+	 *    A4  -|3      14|-  FE1'
+	 *         |         |
+	 *    A3  -|4      13|-  FE2'
+	 *         |         |
+	 *    A0  -|5      12|-  D0
+	 *         |         |
+	 *    A1  -|6      11|-  D1
+	 *         |         |
+	 *    A2  -|7      10|-  D2
+	 *         |         |
+	 *   GND  -|8       9|-  D3
+	 *         |         |
+	 *         +---------+
+	 *
+	 *  input line    signal
+	 *  ----------------------------
+	 *  A7    15      EMACT'
+	 *  A6    1       F1(0)
+	 *  A5    2       F1(1)'
+	 *  A4    3       F1(2)'
+	 *  A3    4       F1(3)'
+	 *  A2    7       0 (GND)
+	 *  A1    6       PC1O
+	 *  A0    5       PC0O
+	 *
+	 *  output line   signal
+	 *  ----------------------------
+	 *  D0     12     PC1T
+	 *  D1     11     PC1F
+	 *  D2     10     PC0T
+	 *  D3     9      PC0F
+	 *
+	 * The outputs are connected to a dual 4:1 demultiplexer 74S153, so that
+	 * depending on NEXT01' and RESET the following signals are passed through:
+	 *
+	 *  RESET  NEXT[01]'  PC0I    PC1I
+	 *  --------------------------------------
+	 *  0      0          PC0T    PC1T
+	 *  0      1          PC0F    PC1F
+	 *  1      0          PC0I4   T14 (?)
+	 *  1      1          -"-     -"-
+	 *
+	 * This selects the microcode "page" to jump to on SWMODE (F1 = 010)
+	 * depending on the current NEXT[01]' level.
+	 * 
+ */ + UINT8* m_ctl2k_u76; + + /** + * @brief 3k CRAM PROM a37 + */ + UINT8* m_cram3k_a37; + + /** + * @brief memory addressing PROM a64 + */ + UINT8* m_madr_a64; + + /** + * @brief memory addressing PROM a65 + */ + UINT8* m_madr_a65; + + /** + * @brief unused PROM a90 + * Data sheet 05a_AIM.pdf page 14 + * inputs A0-A7 from R0-R7 (?) + * output signal + * ------------------- + * Q0 KP3 + * Q1 KP4 + * Q2 KP5 + * Q3 unused + * + * I haven't found yet where KP3-KP5 are used + */ + UINT8* m_madr_a90; + + /** + * @brief unused PROM a91 + * Data sheet 05a_AIM.pdf page 14 + * inputs A0-A7 from R0-R7 (?) + * + * Output Signal + * ------------------- + * Q0 KP0 + * Q1 KP1 + * Q2 KP2 + * Q3 unused + * KP0-KP3 are decoded using 7442 a78 to select + * the keyboard row enable + * + * Enable Key[0] Key[1] Key[2] Key[3] Key[4] Key[5] Key[6] Key[7] + * ------------------------------------------------------------------------ + * KE(0) KB(R) KB(1) KB(3) KB(5) KB(T) KB(ESC) KB(2) KB(4) + * KE(1) KB(G) KB(TAB) KB(W) KB(6) KB(Y) KB(F) KB(0) KB(E) + * KE(2) KB(H) KB(CTL) KB(S) KB(7) KB(8) KB(C) KB(A) KB(D) + * KE(3) KB(N) KB(J) KB(9) KB(U) KB(M) KB(B) KB(I) KB(V) + * KE(4) KB(LCK) KB(Z) KB(X) KB(Q) KB(SPC) KB(^R) KB(O) KB(K) + * KE(5) KB([) KB(.) KB(L) KB(-) KB(+) KB(;) KB(,) KB(P) + * KE(6) KB(^L) KB(RTN) KB(") KB(/) KB(S3) KB(<-) KB(]) KB(\) + * KE(7) KB(S1) KB(DEL) KB(S2) KB(LF) KB(S4) KB(S5) KB(BW) KB(BS) + */ + UINT8* m_madr_a91; + + /** + * @brief ALU function to 74181 operation lookup PROM + */ + UINT8* m_alu_a10; + + //! output lines of the ALU a10 PROM + enum { + A10_UNUSED = (1 << 0), + A10_TSELECT = (1 << 1), + A10_ALUCI = (1 << 2), + A10_ALUM = (1 << 3), + A10_ALUS0 = (1 << 4), + A10_ALUS1 = (1 << 5), + A10_ALUS2 = (1 << 6), + A10_ALUS3 = (1 << 7), + A10_ALUIN = (A10_ALUM|A10_ALUCI|A10_ALUS0|A10_ALUS1|A10_ALUS2|A10_ALUS3) + }; + + //! no operating function to put in the m_bs, m_f1 and m_f2 slots + void noop() {} + + //! per task bus source function pointers, early (0) and late (1) + a2func m_bs[2][ALTO2_TASKS][ALTO2_BUSSRC]; + void set_bs(UINT8 task, UINT8 fn, a2func f0, a2func f1) { + m_bs[0][task][fn] = f0 ? f0 : &alto2_cpu_device::noop; + m_bs[1][task][fn] = f1 ? f1 : &alto2_cpu_device::noop; + } + + //! per task f1 function pointers, early (0) and late (1) + a2func m_f1[2][ALTO2_TASKS][ALTO2_F1MAX]; + void set_f1(UINT8 task, UINT8 fn, a2func f0, a2func f1) { + m_f1[0][task][fn] = f0 ? f0 : &alto2_cpu_device::noop; + m_f1[1][task][fn] = f1 ? f1 : &alto2_cpu_device::noop; + } + + //! per task f2 function pointers, early (0) and late (1) + a2func m_f2[2][ALTO2_TASKS][ALTO2_F2MAX]; + void set_f2(UINT8 task, UINT8 fn, a2func f0, a2func f1) { + m_f2[0][task][fn] = f0 ? f0 : &alto2_cpu_device::noop; + m_f2[1][task][fn] = f1 ? f1 : &alto2_cpu_device::noop; + } + + bool m_ram_related[ALTO2_TASKS]; //!< set when task is RAM related + + UINT64 m_cycle; //!< number of cycles executed in the current slice + + UINT64 cycle() { return m_cycle; } //!< return the current CPU cycle + UINT64 ntime() { return m_cycle*ALTO2_UCYCLE/1000; } //!< return the current nano seconds + + void hard_reset(); //!< reset the various registers + void soft_reset(); //!< soft reset + + void fn_bs_bad_0(); //! bs dummy early function + void fn_bs_bad_1(); //! bs dummy late function + + void fn_f1_bad_0(); //! f1 dummy early function + void fn_f1_bad_1(); //! f1 dummy late function + + void fn_f2_bad_0(); //! f2 dummy early function + void fn_f2_bad_1(); //! f2 dummy late function + + DECLARE_READ16_MEMBER( noop_r ); //!< read open bus (0177777) + DECLARE_WRITE16_MEMBER( noop_w ); //!< write open bus + + DECLARE_READ16_MEMBER( bank_reg_r ); //!< read bank register in memory mapped I/O range + DECLARE_WRITE16_MEMBER( bank_reg_w ); //!< write bank register in memory mapped I/O range + + void bs_early_read_r(); //!< bus source: drive bus by R register + void bs_early_load_r(); //!< bus source: load R places 0 on the BUS + void bs_late_load_r(); //!< bus source: load R from SHIFTER + void bs_early_read_md(); //!< bus source: drive BUS from read memory data + void bs_early_mouse(); //!< bus source: drive bus by mouse + void bs_early_disp(); //!< bus source: drive bus by displacement (which?) + void f1_early_block(); //!< F1 func: block active task + void f1_late_load_mar(); //!< F1 func: load memory address register + void f1_early_task(); //!< F1 func: task switch + void f1_late_l_lsh_1(); //!< F1 func: SHIFTER = left shift L once + void f1_late_l_rsh_1(); //!< F1 func: SHIFTER = right shift L once + void f1_late_l_lcy_8(); //!< F1 func: SHIFTER = byte swap L + void f2_late_bus_eq_zero(); //!< F2 func: branch on bus equals zero + void f2_late_shifter_lt_zero(); //!< F2 func: branch on shifter less than zero + void f2_late_shifter_eq_zero(); //!< F2 func: branch on shifter equals zero + void f2_late_bus(); //!< F2 func: branch on bus bits BUS[6-15] + void f2_late_alucy(); //!< F2 func: branch on latched ALU carry + void f2_late_load_md(); //!< F2 func: load memory data + +#if USE_ALU_74181 + UINT32 alu_74181(UINT32 a, UINT32 b, UINT8 smc); +#endif + void rdram(); //!< read the microcode ROM/RAM halfword + void wrtram(); //!< write the microcode RAM from M register and ALU + + UINT8 m_ether_id; //!< configured Ethernet ID for this machine + +//******************************************* +// inline the sub-devices +//******************************************* +#include "a2jkff.h" +#include "a2ram.h" +#include "a2hw.h" +#include "a2kbd.h" +#include "a2mouse.h" +#include "a2disk.h" +#include "a2disp.h" +#include "a2mem.h" +#include "a2emu.h" +#include "a2ksec.h" +#include "a2ether.h" +#include "a2mrt.h" +#include "a2dwt.h" +#include "a2curt.h" +#include "a2dht.h" +#include "a2dvt.h" +#include "a2part.h" +#include "a2dwt.h" +#include "a2kwd.h" +}; + +extern const device_type ALTO2; + + +#endif /* _CPU_ALTO2_H_ */ diff --git a/src/devices/cpu/alto2/alto2dsm.c b/src/devices/cpu/alto2/alto2dsm.c new file mode 100644 index 00000000000..121ab50b398 --- /dev/null +++ b/src/devices/cpu/alto2/alto2dsm.c @@ -0,0 +1,390 @@ +// license:BSD-3-Clause +// copyright-holders:Juergen Buchmueller +/********************************************************** + * Xerox AltoII disassembler + * + **********************************************************/ +#include "alto2cpu.h" + +#define loc_DASTART 0000420 // display list header +#define loc_DVIBITS 0000421 // display vertical field interrupt bitword +#define loc_ITQUAN 0000422 // interval timer stored quantity +#define loc_ITBITS 0000423 // interval timer bitword +#define loc_MOUSEX 0000424 // mouse X coordinate +#define loc_MOUSEY 0000425 // mouse Y coordinate +#define loc_CURSORX 0000426 // cursor X coordinate +#define loc_CURSORY 0000427 // cursor Y coordinate +#define loc_RTC 0000430 // real time clock +#define loc_CURMAP 0000431 // cursor bitmap (16 words up to 00450) +#define loc_WW 0000452 // interrupt wakeups waiting +#define loc_ACTIVE 0000453 // active interrupt bitword +#define loc_MASKTAB 0000460 // mask table for convert +#define loc_PCLOC 0000500 // saved interrupt PC +#define loc_INTVEC 0000501 // interrupt transfer vector (15 words up to 00517) +#define loc_KBLK 0000521 // disk command block address +#define loc_KSTAT 0000522 // disk status at start of current sector +#define loc_KADDR 0000523 // disk address of latest disk command +#define loc_KSIBITS 0000524 // sector interrupt bit mask +#define loc_ITTIME 0000525 // interval timer timer +#define loc_TRAPPC 0000527 // trap saved PC +#define loc_TRAPVEC 0000530 // trap vectors (up to 0567) +#define loc_TIMERDATA 0000570 // timer data (OS; up to 0577) +#define loc_EPLOC 0000600 // ethernet post location +#define loc_EBLOC 0000601 // ethernet interrupt bitmask +#define loc_EELOC 0000602 // ethernet ending count +#define loc_ELLOC 0000603 // ethernet load location +#define loc_EICLOC 0000604 // ethernet input buffer count +#define loc_EIPLOC 0000605 // ethernet input buffer pointer +#define loc_EOCLOC 0000606 // ethernet output buffer count +#define loc_EOPLOC 0000607 // ethernet output buffer pointer +#define loc_EHLOC 0000610 // ethernet host address +#define loc_ERSVD 0000611 // reserved for ethernet expansion (up to 00612) +#define loc_ALTOV 0000613 // Alto I/II indication that microcode caninterrogate (0 = Alto I, -1 = Alto II) +#define loc_DCBR 0000614 // posted by parity task (main memory parity error) +#define loc_KNMAR 0000615 // -"- +#define loc_DWA 0000616 // -"- +#define loc_CBA 0000617 // -"- +#define loc_PC 0000620 // -"- +#define loc_SAD 0000621 // -"- +#define loc_SWATR 0000700 // saved registers (Swat; up to 00707) +#define loc_UTILOUT 0177016 // printer output (up to 177017) +#define loc_XBUS 0177020 // untility input bus (up to 177023) +#define loc_MEAR 0177024 // memory error address register +#define loc_MESR 0177025 // memory error status register +#define loc_MECR 0177026 // memory error control register +#define loc_UTILIN 0177030 // printer status, mouse keyset +#define loc_KBDAD 0177034 // undecoded keyboard (up to 177037) +#define loc_BANKREGS 0177740 // extended memory option bank registers + +/** + * @brief Microcode and constants PROM size + */ +#define MCODE_PAGE 1024 +#define MCODE_SIZE (2*MCODE_PAGE) /* Alto II may have 2 pages (or even 4?) */ +#define MCODE_MASK (MCODE_SIZE - 1) +#define PROM_SIZE 256 + +/** + * @brief short names for the 16 tasks + */ +static const char *taskname[16] = { + "EMU", // emulator task + "T01", + "T02", + "T03", + "DSC", // disk sector task + "T05", + "T06", + "ETH", // ethernet task + "MRT", // memory refresh task + "DWT", // display word task + "CUR", // cursor task + "DHT", // display horizontal task + "DVT", // display vertical task + "PAR", // parity task + "DWD", // disk word task + "T17" +}; + +/** + * @brief names for the 32 R registers + */ +static const char *regname[32] = { + "AC(3)", // emulator accu 3 + "AC(2)", // emulator accu 2 + "AC(1)", // emulator accu 1 + "AC(0)", // emulator accu 0 + "R04", + "R05", + "PC", // emulator program counter + "R07", + "R10", + "R11", + "R12", + "R13", + "R14", + "R15", + "R16", + "R17", + "R20", + "R21", + "CBA", // address of the currently active DCB+1 + "AECL", // address of end of current scanline's bitmap + "SLC", // scan line count + "HTAB", // number of tab words remaining on current scanline + "DWA", // address of the bit map double word being fetched + "MTEMP", // temporary cell + "R30", + "R31", + "R32", + "R33", + "R34", + "R35", + "R36", + "R37" +}; + +//! for ALUF which is the value loaded into T, if t flags is set +static const char* t_bus_alu[16] = { + "ALU", + "BUS", + "ALU", + "BUS", + "BUS", + "ALU", + "ALU", + "BUS", + "BUS", + "BUS", + "ALU", + "ALU", + "ALU", + "BUS", + "BUS", + "BUS", +}; + +/** + * @brief copy of the constant PROM, which this disassembler may not have access to + */ +static UINT16 const_prom[PROM_SIZE] = { + /* 0000 */ 0x0000, 0x0001, 0x0002, 0xfffe, 0xffff, 0xffff, 0x000f, 0xffff, + /* 0008 */ 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0xfff8, 0xfff8, + /* 0010 */ 0x0010, 0x001f, 0x0020, 0x003f, 0x0040, 0x007f, 0x0080, 0x0007, + /* 0018 */ 0x00ff, 0xff00, 0x0400, 0x0100, 0x0110, 0x0151, 0x0114, 0x000f, + /* 0020 */ 0x0116, 0x0118, 0x0ffa, 0xf000, 0x4000, 0xfffc, 0xfff6, 0xffeb, + /* 0028 */ 0x4800, 0x6c00, 0x0800, 0x1000, 0xfe00, 0x7fff, 0x7fe0, 0x7f00, + /* 0030 */ 0xffbd, 0x0f00, 0x0f0f, 0xf0f0, 0x6048, 0x3000, 0x7159, 0x2109, + /* 0038 */ 0x6a3c, 0x4213, 0xa5a5, 0xfe1c, 0x3f00, 0xffc0, 0x012a, 0x0140, + /* 0040 */ 0x8000, 0xffe0, 0x00bf, 0xfff9, 0xfff0, 0xfffd, 0x0970, 0x5d20, + /* 0048 */ 0x3844, 0x6814, 0xfc00, 0xfe20, 0xfe22, 0x0083, 0x00f0, 0xff80, + /* 0050 */ 0xf800, 0xe000, 0xc000, 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, + /* 0058 */ 0x3fff, 0x0200, 0x2000, 0xfff1, 0x0156, 0x0157, 0x0138, 0x0c00, + /* 0060 */ 0x0130, 0x1813, 0x0180, 0x0181, 0x0182, 0x0183, 0x0184, 0x0185, + /* 0068 */ 0x0186, 0x0187, 0x0188, 0x018a, 0x0112, 0x0113, 0x0102, 0xfff0, + /* 0070 */ 0x0153, 0x0154, 0xffef, 0xffe4, 0xfffb, 0x000a, 0xffc1, 0x001f, + /* 0078 */ 0x0e00, 0x007e, 0xff7e, 0x0018, 0x000d, 0x03f8, 0x83f9, 0xffe0, + /* 0080 */ 0xfbff, 0x0009, 0x000b, 0x000c, 0x000e, 0x0030, 0x01fe, 0xff7f, + /* 0088 */ 0x81ff, 0xffbf, 0xffcc, 0x0557, 0x0041, 0x0198, 0x0199, 0x01a2, + /* 0090 */ 0xfe72, 0xfe58, 0x0012, 0x0014, 0x00dd, 0x02ff, 0x0101, 0x0001, + /* 0098 */ 0x0401, 0x0011, 0x0013, 0x0015, 0x0016, 0x0017, 0x0019, 0x0003, + /* 00a0 */ 0x03bd, 0x01de, 0xfe50, 0x00c0, 0x0c01, 0x6200, 0x6300, 0x0008, + /* 00a8 */ 0x6400, 0x6500, 0x6e00, 0x6700, 0x6900, 0x6d00, 0x6600, 0x000c, + /* 00b0 */ 0x6b00, 0x6b01, 0x6b02, 0x6b03, 0x6b04, 0x6b05, 0x6b06, 0x0010, + /* 00b8 */ 0x6b07, 0x6b08, 0x6b09, 0x6b0a, 0x6b0b, 0x6b0c, 0x6b0d, 0x0020, + /* 00c0 */ 0x6b0e, 0x6b0f, 0xfff3, 0xfe14, 0xfe15, 0xfe16, 0x0ffc, 0x0040, + /* 00c8 */ 0x04ff, 0x05ff, 0x06ff, 0x013f, 0x017e, 0xfe7d, 0xffff, 0x0080, + /* 00d0 */ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x00c0, + /* 00d8 */ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x00ff, + /* 00e0 */ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + /* 00e8 */ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + /* 00f0 */ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + /* 00f8 */ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff +}; + +/** + * @brief print a symbolic name for an mpc address + * + * @param a microcode address (mpc) + * @return pointer to const string with the address or symbolic name + */ +static const char *addrname(int a) +{ + static char buffer[4][32]; + static int which = 0; + char *dst; + + which = (which + 1) % 4; + dst = buffer[which]; + + if (a < 020) { + // start value for mpc per task is the task number + snprintf(dst, sizeof(buffer[0]), "*%s", taskname[a]); + } else { + snprintf(dst, sizeof(buffer[0]), "%04o", a); + } + return dst; +} + +offs_t alto2_cpu_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + size_t len = 128; + + UINT32 mir = (static_cast(oprom[0]) << 24) | + (static_cast(oprom[1]) << 16) | + (static_cast(oprom[2]) << 8) | + (static_cast(oprom[3]) << 0); + UINT8 rsel = static_cast((mir >> 27) & 31); + UINT8 aluf = static_cast((mir >> 23) & 15); + UINT8 bs = static_cast((mir >> 20) & 7); + UINT8 f1 = static_cast((mir >> 16) & 15); + UINT8 f2 = static_cast((mir >> 12) & 15); + UINT8 t = static_cast((mir >> 11) & 1); + UINT8 l = static_cast((mir >> 10) & 1); + offs_t next = static_cast(mir & 1023); + const UINT8* src = oprom - 4 * pc + 4 * next; + UINT32 next2 = (static_cast(src[0]) << 24) | + (static_cast(src[1]) << 16) | + (static_cast(src[2]) << 8) | + (static_cast(src[3]) << 0); + UINT16 prefetch = next2 & 1023; + char *dst = buffer; + offs_t result = 1 | DASMFLAG_SUPPORTED; + UINT8 pa; + + if (next != pc + 1) + result |= DASMFLAG_STEP_OUT; + + if (t) + dst += snprintf(dst, len - (size_t)(dst - buffer), "T<-%s ", t_bus_alu[aluf]); + if (l) + dst += snprintf(dst, len - (size_t)(dst - buffer), "L<- "); + if (bs == 1) + dst += snprintf(dst, len - (size_t)(dst - buffer), "%s<- ", regname[rsel]); + switch (aluf) { + case 0: // T?: BUS + // this is somehow redundant and just wasting space + dst += snprintf(dst, len - (size_t)(dst - buffer), "ALUF(BUS) "); + break; + case 1: // : T + dst += snprintf(dst, len - (size_t)(dst - buffer), "ALUF(T) "); + break; + case 2: // T?: BUS OR T + dst += snprintf(dst, len - (size_t)(dst - buffer), "ALUF(BUS|T) "); + break; + case 3: // : BUS AND T + dst += snprintf(dst, len - (size_t)(dst - buffer), "ALUF(BUS&T) "); + break; + case 4: // : BUS XOR T + dst += snprintf(dst, len - (size_t)(dst - buffer), "ALUF(BUS^T) "); + break; + case 5: // T?: BUS + 1 + dst += snprintf(dst, len - (size_t)(dst - buffer), "ALUF(BUS+1) "); + break; + case 6: // T?: BUS - 1 + dst += snprintf(dst, len - (size_t)(dst - buffer), "ALUF(BUS-1) "); + break; + case 7: // : BUS + T + dst += snprintf(dst, len - (size_t)(dst - buffer), "ALUF(BUS+T) "); + break; + case 8: // : BUS - T + dst += snprintf(dst, len - (size_t)(dst - buffer), "ALUF(BUS-T) "); + break; + case 9: // : BUS - T - 1 + dst += snprintf(dst, len - (size_t)(dst - buffer), "ALUF(BUS-T-1) "); + break; + case 10: // T?: BUS + T + 1 + dst += snprintf(dst, len - (size_t)(dst - buffer), "ALUF(BUS+T+1) "); + break; + case 11: // T?: BUS + SKIP + dst += snprintf(dst, len - (size_t)(dst - buffer), "ALUF(BUS+SKIP) "); + break; + case 12: // T?: BUS, T (AND) + dst += snprintf(dst, len - (size_t)(dst - buffer), "ALUF(BUS,T) "); + break; + case 13: // : BUS AND NOT T + dst += snprintf(dst, len - (size_t)(dst - buffer), "ALUF(BUS&~T) "); + break; + case 14: // : undefined + dst += snprintf(dst, len - (size_t)(dst - buffer), "*ALUF(BUS) "); + break; + case 15: // : undefined + dst += snprintf(dst, len - (size_t)(dst - buffer), "*ALUF(BUS) "); + break; + } + + switch (bs) { + case 0: // read R + dst += snprintf(dst, len - (size_t)(dst - buffer), "BUS<-%s ", regname[rsel]); + break; + case 1: // load R from shifter output + // dst += snprintf(dst, len - (size_t)(dst - buffer), "; %s<-", regname[rsel]); + break; + case 2: // enables no source to the BUS, leaving it all ones + dst += snprintf(dst, len - (size_t)(dst - buffer), "BUS<-177777 "); + break; + case 3: // performs different functions in different tasks + dst += snprintf(dst, len - (size_t)(dst - buffer), "BUS<-BS3 "); + break; + case 4: // performs different functions in different tasks + dst += snprintf(dst, len - (size_t)(dst - buffer), "BUS<-BS4 "); + break; + case 5: // memory data + dst += snprintf(dst, len - (size_t)(dst - buffer), "BUS<-MD "); + break; + case 6: // BUS[3-0] <- MOUSE; BUS[15-4] <- -1 + dst += snprintf(dst, len - (size_t)(dst - buffer), "BUS<-MOUSE "); + break; + case 7: // IR[7-0], possibly sign extended + dst += snprintf(dst, len - (size_t)(dst - buffer), "BUS<-DISP "); + break; + } + + + switch (f1) { + case 0: // no operation + break; + case 1: // load MAR from ALU output; start main memory reference + dst += snprintf(dst, len - (size_t)(dst - buffer), "MAR<-ALU "); + break; + case 2: // switch tasks if higher priority wakeup is pending + dst += snprintf(dst, len - (size_t)(dst - buffer), "TASK "); + break; + case 3: // disable the current task until re-enabled by a hardware-generated condition + dst += snprintf(dst, len - (size_t)(dst - buffer), "BLOCK "); + break; + case 4: // SHIFTER output will be L shifted left one place + dst += snprintf(dst, len - (size_t)(dst - buffer), "SHIFTER<-L(LSH1) "); + break; + case 5: // SHIFTER output will be L shifted right one place + dst += snprintf(dst, len - (size_t)(dst - buffer), "SHIFTER<-L(RSH1) "); + break; + case 6: // SHIFTER output will be L rotated left 8 places + dst += snprintf(dst, len - (size_t)(dst - buffer), "SHIFTER<-L(LCY8) "); + break; + case 7: // put the constant from PROM (RSELECT,BS) on the bus + pa = (rsel << 3) | bs; + dst += snprintf(dst, len - (size_t)(dst - buffer), "BUS<-%05o CONST[%03o]", const_prom[pa], pa); + break; + default: + dst += snprintf(dst, len - (size_t)(dst - buffer), "F1_%02o ", f1); + break; + } + + switch (f2) { + case 0: // no operation + break; + case 1: // NEXT <- NEXT OR (BUS==0 ? 1 : 0) + dst += snprintf(dst, len - (size_t)(dst - buffer), "[BUS==0 ? %s:%s] ", + addrname((prefetch | 1) & MCODE_MASK), addrname(prefetch & MCODE_MASK)); + break; + case 2: // NEXT <- NEXT OR (SHIFTER==0 ? 1 : 0) + dst += snprintf(dst, len - (size_t)(dst - buffer), "[SH==0 ? %s:%s] ", + addrname((prefetch | 1) & MCODE_MASK), addrname(prefetch & MCODE_MASK)); + break; + case 3: // NEXT <- NEXT OR (SHIFTER<0 ? 1 : 0) + dst += snprintf(dst, len - (size_t)(dst - buffer), "[SH<0 ? %s:%s] ", + addrname((prefetch | 1) & MCODE_MASK), addrname(prefetch & MCODE_MASK)); + break; + case 4: // NEXT <- NEXT OR BUS + dst += snprintf(dst, len - (size_t)(dst - buffer), "NEXT<-BUS "); + break; + case 5: // NEXT <- NEXT OR ALUC0. ALUC0 is the carry produced by last L loading microinstruction. + dst += snprintf(dst, len - (size_t)(dst - buffer), "[ALUC0 ? %s:%s] ", + addrname((prefetch | 1) & MCODE_MASK), addrname(prefetch & MCODE_MASK)); + break; + case 6: // deliver BUS data to memory + dst += snprintf(dst, len - (size_t)(dst - buffer), "MD<-BUS "); + break; + case 7: // put on the bus the constant from PROM (RSELECT,BS) + if (f1 != 7) { + pa = 8 * rsel + bs; + dst += snprintf(dst, len - (size_t)(dst - buffer), "BUS<-%05o CONST[%03o]", const_prom[pa], pa); + } + break; + default: + dst += snprintf(dst, len - (size_t)(dst - buffer), "BUS<-F2_%02o ", f2); + break; + } + return result; +} diff --git a/src/devices/cpu/am29000/am29000.c b/src/devices/cpu/am29000/am29000.c new file mode 100644 index 00000000000..27924fa163f --- /dev/null +++ b/src/devices/cpu/am29000/am29000.c @@ -0,0 +1,679 @@ +// license:BSD-3-Clause +// copyright-holders:Philip Bennett +/*************************************************************************** + + am29000.c + Core implementation of the Am29000 emulator + + Written by Philip Bennett + + Features missing: + * MMU + * Some instructions + * Various exceptions + +***************************************************************************/ + +#include "emu.h" +#include "debugger.h" +#include "am29000.h" + + +const device_type AM29000 = &device_creator; + + +/*************************************************************************** + CONSTANTS +***************************************************************************/ + +#define PFLAG_FETCH_EN (1 << 0) +#define PFLAG_DECODE_EN (1 << 1) +#define PFLAG_EXECUTE_EN (1 << 2) +#define PFLAG_WRITEBACK_EN (1 << 3) +#define PFLAG_IRQ (1 << 4) +#define PFLAG_LOADSTORE (1 << 5) +#define PFLAG_MULTI_LOADSTORE (1 << 6) +#define PFLAG_JUMP (1 << 7) +#define PFLAG_JUMP2 (1 << 8) +#define PFLAG_IRET (1 << 9) +#define PFLAG_TIMER_LOADED (1 << 10) + +#define PFLAG_RA_DEPENDENCY (1 << 26) +#define PFLAG_RB_DEPENDENCY (1 << 27) + +#define PFLAG_MEM_MULTIPLE (1 << 29) +#define PFLAG_REG_WRITEBACK (1 << 30) +#define PFLAG_MEM_WRITEBACK (1 << 31) + +#define MMU_PROGRAM_ACCESS (0) +#define MMU_DATA_ACCESS (1) + +#define FREEZE_MODE (m_cps & CPS_FZ) +#define SUPERVISOR_MODE (m_cps & CPS_SM) +#define USER_MODE (~m_cps & CPS_SM) +#define REGISTER_IS_PROTECTED(x) (m_rbp & (1 << ((x) >> 4))) + +#define INST_RB_FIELD(x) ((x) & 0xff) +#define INST_RA_FIELD(x) (((x) >> 8) & 0xff) +#define INST_RC_FIELD(x) (((x) >> 16) & 0xff) +#define INST_SA_FIELD(x) (((x) >> 8) & 0xff) + +#define FIELD_RA 0 +#define FIELD_RB 1 +#define FIELD_RC 2 + +#define SIGNAL_EXCEPTION(x) (signal_exception(x)) + + +#define GET_ALU_FC ((m_alu >> ALU_FC_SHIFT) & ALU_FC_MASK) +#define GET_ALU_BP ((m_alu >> ALU_BP_SHIFT) & ALU_BP_MASK) +#define GET_CHC_CR ((m_chc >> CHC_CR_SHIFT) & CHC_CR_MASK) + +#define SET_ALU_FC(x) do { m_alu &= ~(ALU_FC_MASK << ALU_FC_SHIFT); m_alu |= ((x) & ALU_FC_MASK) << ALU_FC_SHIFT; } while(0) +#define SET_ALU_BP(x) do { m_alu &= ~(ALU_BP_MASK << ALU_BP_SHIFT); m_alu |= ((x) & ALU_BP_MASK) << ALU_BP_SHIFT; } while(0) +#define SET_CHC_CR(x) do { m_chc &= ~(CHC_CR_MASK << CHC_CR_SHIFT); m_chc |= ((x) & CHC_CR_MASK) << CHC_CR_SHIFT; } while(0) + + +/*************************************************************************** + STATE ACCESSORS +***************************************************************************/ + +am29000_cpu_device::am29000_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : cpu_device(mconfig, AM29000, "AMD Am29000", tag, owner, clock, "am29000", __FILE__) + , m_program_config("program", ENDIANNESS_BIG, 32, 32, 0) + , m_io_config("io", ENDIANNESS_BIG, 32, 32, 0) + , m_data_config("data", ENDIANNESS_BIG, 32, 32, 0) +{ + memset( m_r, 0, sizeof(m_r) ); + memset( m_tlb, 0, sizeof(m_tlb) ); + m_vab = 0; + m_ops = 0; + m_cha = 0; + m_chd = 0; + m_chc = 0; + m_rbp = 0; + m_tmc = 0; + m_tmr = 0; + m_pc0 = 0; + m_pc1 = 0; + m_pc2 = 0; + m_mmu = 0; + m_lru = 0; + m_ipc = 0; + m_ipa = 0; + m_ipb = 0; + m_q = 0; + m_alu = 0; + m_fpe = 0; + m_inte = 0; + m_fps = 0; + memset( m_exception_queue, 0, sizeof( m_exception_queue) );; + m_irq_active = 0; + m_irq_lines = 0; + m_exec_ir = 0; + m_next_ir = 0; + m_pl_flags = 0; + m_iret_pc = 0; + m_exec_pc = 0; + m_next_pc = 0; +} + + +void am29000_cpu_device::device_start() +{ + m_program = &space(AS_PROGRAM); + m_direct = &m_program->direct(); + m_data = &space(AS_DATA); + m_datadirect = &m_data->direct(); + m_io = &space(AS_IO); + m_cfg = (PRL_AM29000 | PRL_REV_D) << CFG_PRL_SHIFT; + + /* Register state for saving */ + save_item(NAME(m_pc)); + save_item(NAME(m_r)); + save_item(NAME(m_tlb)); + + save_item(NAME(m_vab)); + save_item(NAME(m_ops)); + save_item(NAME(m_cps)); + save_item(NAME(m_cfg)); + save_item(NAME(m_cha)); + save_item(NAME(m_chd)); + save_item(NAME(m_chc)); + save_item(NAME(m_rbp)); + save_item(NAME(m_tmc)); + save_item(NAME(m_tmr)); + save_item(NAME(m_pc0)); + save_item(NAME(m_pc1)); + save_item(NAME(m_pc2)); + save_item(NAME(m_mmu)); + save_item(NAME(m_lru)); + + save_item(NAME(m_ipc)); + save_item(NAME(m_ipa)); + save_item(NAME(m_ipb)); + save_item(NAME(m_q)); + + save_item(NAME(m_alu)); + save_item(NAME(m_fpe)); + save_item(NAME(m_inte)); + save_item(NAME(m_fps)); + + save_item(NAME(m_exceptions)); + save_item(NAME(m_exception_queue)); + + save_item(NAME(m_irq_active)); + save_item(NAME(m_irq_lines)); + + save_item(NAME(m_exec_ir)); + save_item(NAME(m_next_ir)); + + save_item(NAME(m_pl_flags)); + save_item(NAME(m_next_pl_flags)); + + save_item(NAME(m_iret_pc)); + save_item(NAME(m_exec_pc)); + save_item(NAME(m_next_pc)); + + // Register state for debugger + state_add( AM29000_PC, "PC", m_pc ).formatstr("%08X"); + state_add( AM29000_VAB, "VAB", m_vab ).formatstr("%08X"); + state_add( AM29000_OPS, "OPS", m_ops ).formatstr("%08X"); + state_add( AM29000_CPS, "CPS", m_cps ).formatstr("%08X"); + state_add( AM29000_CFG, "CFG", m_cfg ).formatstr("%08X"); + state_add( AM29000_CHA, "CHA", m_cha ).formatstr("%08X"); + state_add( AM29000_CHD, "CHD", m_chd ).formatstr("%08X"); + state_add( AM29000_CHC, "CHC", m_chc ).formatstr("%08X"); + state_add( AM29000_RBP, "RBP", m_rbp ).formatstr("%08X"); + state_add( AM29000_TMC, "TMC", m_tmc ).formatstr("%08X"); + state_add( AM29000_TMR, "TMR", m_tmr ).formatstr("%08X"); + state_add( AM29000_PC0, "PC0", m_pc0 ).formatstr("%08X"); + state_add( AM29000_PC1, "PC1", m_pc1 ).formatstr("%08X"); + state_add( AM29000_PC2, "PC2", m_pc2 ).formatstr("%08X"); + state_add( AM29000_MMU, "MMU", m_mmu ).formatstr("%08X"); + state_add( AM29000_LRU, "LRU", m_lru ).formatstr("%08X"); + state_add( AM29000_IPC, "IPC", m_ipc ).formatstr("%08X"); + state_add( AM29000_IPA, "IPA", m_ipa ).formatstr("%08X"); + state_add( AM29000_IPB, "IPB", m_ipb ).formatstr("%08X"); + state_add( AM29000_Q, "Q", m_q ).formatstr("%08X"); + state_add( AM29000_ALU, "ALU", m_alu ).formatstr("%08X"); +// state_add( AM29000_BP, "BP", GET_ALU_BP).formatstr("%08X"); +// state_add( AM29000_FC, "FC", GET_ALU_FC).formatstr("%08X"); +// state_add( AM29000_CR, "CR", GET_CHC_CR).formatstr("%08X"); + state_add( AM29000_FPE, "FPE", m_fpe ).formatstr("%08X"); + state_add( AM29000_INTE, "INTE", m_inte ).formatstr("%08X"); + state_add( AM29000_FPS, "FPS", m_fps ).formatstr("%08X"); + state_add( AM29000_R1, "R1", m_r[1] ).formatstr("%08X"); + state_add( AM29000_R64, "R64", m_r[64] ).formatstr("%08X"); + state_add( AM29000_R65, "R65", m_r[65] ).formatstr("%08X"); + state_add( AM29000_R66, "R66", m_r[66] ).formatstr("%08X"); + state_add( AM29000_R67, "R67", m_r[67] ).formatstr("%08X"); + state_add( AM29000_R68, "R68", m_r[68] ).formatstr("%08X"); + state_add( AM29000_R69, "R69", m_r[69] ).formatstr("%08X"); + state_add( AM29000_R70, "R70", m_r[70] ).formatstr("%08X"); + state_add( AM29000_R71, "R71", m_r[71] ).formatstr("%08X"); + state_add( AM29000_R72, "R72", m_r[72] ).formatstr("%08X"); + state_add( AM29000_R73, "R73", m_r[73] ).formatstr("%08X"); + state_add( AM29000_R74, "R74", m_r[74] ).formatstr("%08X"); + state_add( AM29000_R75, "R75", m_r[75] ).formatstr("%08X"); + state_add( AM29000_R76, "R76", m_r[76] ).formatstr("%08X"); + state_add( AM29000_R77, "R77", m_r[77] ).formatstr("%08X"); + state_add( AM29000_R78, "R78", m_r[78] ).formatstr("%08X"); + state_add( AM29000_R79, "R79", m_r[79] ).formatstr("%08X"); + state_add( AM29000_R80, "R80", m_r[80] ).formatstr("%08X"); + state_add( AM29000_R81, "R81", m_r[81] ).formatstr("%08X"); + state_add( AM29000_R82, "R82", m_r[82] ).formatstr("%08X"); + state_add( AM29000_R83, "R83", m_r[83] ).formatstr("%08X"); + state_add( AM29000_R84, "R84", m_r[84] ).formatstr("%08X"); + state_add( AM29000_R85, "R85", m_r[85] ).formatstr("%08X"); + state_add( AM29000_R86, "R86", m_r[86] ).formatstr("%08X"); + state_add( AM29000_R87, "R87", m_r[87] ).formatstr("%08X"); + state_add( AM29000_R88, "R88", m_r[88] ).formatstr("%08X"); + state_add( AM29000_R89, "R89", m_r[89] ).formatstr("%08X"); + state_add( AM29000_R90, "R90", m_r[90] ).formatstr("%08X"); + state_add( AM29000_R91, "R91", m_r[91] ).formatstr("%08X"); + state_add( AM29000_R92, "R92", m_r[92] ).formatstr("%08X"); + state_add( AM29000_R93, "R93", m_r[93] ).formatstr("%08X"); + state_add( AM29000_R94, "R94", m_r[94] ).formatstr("%08X"); + state_add( AM29000_R95, "R95", m_r[95] ).formatstr("%08X"); + state_add( AM29000_R96, "R96", m_r[96] ).formatstr("%08X"); + state_add( AM29000_R97, "R97", m_r[97] ).formatstr("%08X"); + state_add( AM29000_R98, "R98", m_r[98] ).formatstr("%08X"); + state_add( AM29000_R99, "R99", m_r[99] ).formatstr("%08X"); + state_add( AM29000_R100, "R100", m_r[100] ).formatstr("%08X"); + state_add( AM29000_R101, "R101", m_r[101] ).formatstr("%08X"); + state_add( AM29000_R102, "R102", m_r[102] ).formatstr("%08X"); + state_add( AM29000_R103, "R103", m_r[103] ).formatstr("%08X"); + state_add( AM29000_R104, "R104", m_r[104] ).formatstr("%08X"); + state_add( AM29000_R105, "R105", m_r[105] ).formatstr("%08X"); + state_add( AM29000_R106, "R106", m_r[106] ).formatstr("%08X"); + state_add( AM29000_R107, "R107", m_r[107] ).formatstr("%08X"); + state_add( AM29000_R108, "R108", m_r[108] ).formatstr("%08X"); + state_add( AM29000_R109, "R109", m_r[109] ).formatstr("%08X"); + state_add( AM29000_R110, "R110", m_r[110] ).formatstr("%08X"); + state_add( AM29000_R111, "R111", m_r[111] ).formatstr("%08X"); + state_add( AM29000_R112, "R112", m_r[112] ).formatstr("%08X"); + state_add( AM29000_R113, "R113", m_r[113] ).formatstr("%08X"); + state_add( AM29000_R114, "R114", m_r[114] ).formatstr("%08X"); + state_add( AM29000_R115, "R115", m_r[115] ).formatstr("%08X"); + state_add( AM29000_R116, "R116", m_r[116] ).formatstr("%08X"); + state_add( AM29000_R117, "R117", m_r[117] ).formatstr("%08X"); + state_add( AM29000_R118, "R118", m_r[118] ).formatstr("%08X"); + state_add( AM29000_R119, "R119", m_r[119] ).formatstr("%08X"); + state_add( AM29000_R120, "R120", m_r[120] ).formatstr("%08X"); + state_add( AM29000_R121, "R121", m_r[121] ).formatstr("%08X"); + state_add( AM29000_R122, "R122", m_r[122] ).formatstr("%08X"); + state_add( AM29000_R123, "R123", m_r[123] ).formatstr("%08X"); + state_add( AM29000_R124, "R124", m_r[124] ).formatstr("%08X"); + state_add( AM29000_R125, "R125", m_r[125] ).formatstr("%08X"); + state_add( AM29000_R126, "R126", m_r[126] ).formatstr("%08X"); + state_add( AM29000_R127, "R127", m_r[127] ).formatstr("%08X"); + state_add( AM29000_R128, "R128", m_r[128] ).formatstr("%08X"); + state_add( AM29000_R129, "R129", m_r[129] ).formatstr("%08X"); + state_add( AM29000_R130, "R130", m_r[130] ).formatstr("%08X"); + state_add( AM29000_R131, "R131", m_r[131] ).formatstr("%08X"); + state_add( AM29000_R132, "R132", m_r[132] ).formatstr("%08X"); + state_add( AM29000_R133, "R133", m_r[133] ).formatstr("%08X"); + state_add( AM29000_R134, "R134", m_r[134] ).formatstr("%08X"); + state_add( AM29000_R135, "R135", m_r[135] ).formatstr("%08X"); + state_add( AM29000_R136, "R136", m_r[136] ).formatstr("%08X"); + state_add( AM29000_R137, "R137", m_r[137] ).formatstr("%08X"); + state_add( AM29000_R138, "R138", m_r[138] ).formatstr("%08X"); + state_add( AM29000_R139, "R139", m_r[139] ).formatstr("%08X"); + state_add( AM29000_R140, "R140", m_r[140] ).formatstr("%08X"); + state_add( AM29000_R141, "R141", m_r[141] ).formatstr("%08X"); + state_add( AM29000_R142, "R142", m_r[142] ).formatstr("%08X"); + state_add( AM29000_R143, "R143", m_r[143] ).formatstr("%08X"); + state_add( AM29000_R144, "R144", m_r[144] ).formatstr("%08X"); + state_add( AM29000_R145, "R145", m_r[145] ).formatstr("%08X"); + state_add( AM29000_R146, "R146", m_r[146] ).formatstr("%08X"); + state_add( AM29000_R147, "R147", m_r[147] ).formatstr("%08X"); + state_add( AM29000_R148, "R148", m_r[148] ).formatstr("%08X"); + state_add( AM29000_R149, "R149", m_r[149] ).formatstr("%08X"); + state_add( AM29000_R150, "R150", m_r[150] ).formatstr("%08X"); + state_add( AM29000_R151, "R151", m_r[151] ).formatstr("%08X"); + state_add( AM29000_R152, "R152", m_r[152] ).formatstr("%08X"); + state_add( AM29000_R153, "R153", m_r[153] ).formatstr("%08X"); + state_add( AM29000_R154, "R154", m_r[154] ).formatstr("%08X"); + state_add( AM29000_R155, "R155", m_r[155] ).formatstr("%08X"); + state_add( AM29000_R156, "R156", m_r[156] ).formatstr("%08X"); + state_add( AM29000_R157, "R157", m_r[157] ).formatstr("%08X"); + state_add( AM29000_R158, "R158", m_r[158] ).formatstr("%08X"); + state_add( AM29000_R159, "R159", m_r[159] ).formatstr("%08X"); + state_add( AM29000_R160, "R160", m_r[160] ).formatstr("%08X"); + state_add( AM29000_R161, "R161", m_r[161] ).formatstr("%08X"); + state_add( AM29000_R162, "R162", m_r[162] ).formatstr("%08X"); + state_add( AM29000_R163, "R163", m_r[163] ).formatstr("%08X"); + state_add( AM29000_R164, "R164", m_r[164] ).formatstr("%08X"); + state_add( AM29000_R165, "R165", m_r[165] ).formatstr("%08X"); + state_add( AM29000_R166, "R166", m_r[166] ).formatstr("%08X"); + state_add( AM29000_R167, "R167", m_r[167] ).formatstr("%08X"); + state_add( AM29000_R168, "R168", m_r[168] ).formatstr("%08X"); + state_add( AM29000_R169, "R169", m_r[169] ).formatstr("%08X"); + state_add( AM29000_R170, "R170", m_r[170] ).formatstr("%08X"); + state_add( AM29000_R171, "R171", m_r[171] ).formatstr("%08X"); + state_add( AM29000_R172, "R172", m_r[172] ).formatstr("%08X"); + state_add( AM29000_R173, "R173", m_r[173] ).formatstr("%08X"); + state_add( AM29000_R174, "R174", m_r[174] ).formatstr("%08X"); + state_add( AM29000_R175, "R175", m_r[175] ).formatstr("%08X"); + state_add( AM29000_R176, "R176", m_r[176] ).formatstr("%08X"); + state_add( AM29000_R177, "R177", m_r[177] ).formatstr("%08X"); + state_add( AM29000_R178, "R178", m_r[178] ).formatstr("%08X"); + state_add( AM29000_R179, "R179", m_r[179] ).formatstr("%08X"); + state_add( AM29000_R180, "R180", m_r[180] ).formatstr("%08X"); + state_add( AM29000_R181, "R181", m_r[181] ).formatstr("%08X"); + state_add( AM29000_R182, "R182", m_r[182] ).formatstr("%08X"); + state_add( AM29000_R183, "R183", m_r[183] ).formatstr("%08X"); + state_add( AM29000_R184, "R184", m_r[184] ).formatstr("%08X"); + state_add( AM29000_R185, "R185", m_r[185] ).formatstr("%08X"); + state_add( AM29000_R186, "R186", m_r[186] ).formatstr("%08X"); + state_add( AM29000_R187, "R187", m_r[187] ).formatstr("%08X"); + state_add( AM29000_R188, "R188", m_r[188] ).formatstr("%08X"); + state_add( AM29000_R189, "R189", m_r[189] ).formatstr("%08X"); + state_add( AM29000_R190, "R190", m_r[190] ).formatstr("%08X"); + state_add( AM29000_R191, "R191", m_r[191] ).formatstr("%08X"); + state_add( AM29000_R192, "R192", m_r[192] ).formatstr("%08X"); + state_add( AM29000_R193, "R193", m_r[193] ).formatstr("%08X"); + state_add( AM29000_R194, "R194", m_r[194] ).formatstr("%08X"); + state_add( AM29000_R195, "R195", m_r[195] ).formatstr("%08X"); + state_add( AM29000_R196, "R196", m_r[196] ).formatstr("%08X"); + state_add( AM29000_R197, "R197", m_r[197] ).formatstr("%08X"); + state_add( AM29000_R198, "R198", m_r[198] ).formatstr("%08X"); + state_add( AM29000_R199, "R199", m_r[199] ).formatstr("%08X"); + state_add( AM29000_R200, "R200", m_r[200] ).formatstr("%08X"); + state_add( AM29000_R201, "R201", m_r[201] ).formatstr("%08X"); + state_add( AM29000_R202, "R202", m_r[202] ).formatstr("%08X"); + state_add( AM29000_R203, "R203", m_r[203] ).formatstr("%08X"); + state_add( AM29000_R204, "R204", m_r[204] ).formatstr("%08X"); + state_add( AM29000_R205, "R205", m_r[205] ).formatstr("%08X"); + state_add( AM29000_R206, "R206", m_r[206] ).formatstr("%08X"); + state_add( AM29000_R207, "R207", m_r[207] ).formatstr("%08X"); + state_add( AM29000_R208, "R208", m_r[208] ).formatstr("%08X"); + state_add( AM29000_R209, "R209", m_r[209] ).formatstr("%08X"); + state_add( AM29000_R210, "R210", m_r[210] ).formatstr("%08X"); + state_add( AM29000_R211, "R211", m_r[211] ).formatstr("%08X"); + state_add( AM29000_R212, "R212", m_r[212] ).formatstr("%08X"); + state_add( AM29000_R213, "R213", m_r[213] ).formatstr("%08X"); + state_add( AM29000_R214, "R214", m_r[214] ).formatstr("%08X"); + state_add( AM29000_R215, "R215", m_r[215] ).formatstr("%08X"); + state_add( AM29000_R216, "R216", m_r[216] ).formatstr("%08X"); + state_add( AM29000_R217, "R217", m_r[217] ).formatstr("%08X"); + state_add( AM29000_R218, "R218", m_r[218] ).formatstr("%08X"); + state_add( AM29000_R219, "R219", m_r[219] ).formatstr("%08X"); + state_add( AM29000_R220, "R220", m_r[220] ).formatstr("%08X"); + state_add( AM29000_R221, "R221", m_r[221] ).formatstr("%08X"); + state_add( AM29000_R222, "R222", m_r[222] ).formatstr("%08X"); + state_add( AM29000_R223, "R223", m_r[223] ).formatstr("%08X"); + state_add( AM29000_R224, "R224", m_r[224] ).formatstr("%08X"); + state_add( AM29000_R225, "R225", m_r[225] ).formatstr("%08X"); + state_add( AM29000_R226, "R226", m_r[226] ).formatstr("%08X"); + state_add( AM29000_R227, "R227", m_r[227] ).formatstr("%08X"); + state_add( AM29000_R228, "R228", m_r[228] ).formatstr("%08X"); + state_add( AM29000_R229, "R229", m_r[229] ).formatstr("%08X"); + state_add( AM29000_R230, "R230", m_r[230] ).formatstr("%08X"); + state_add( AM29000_R231, "R231", m_r[231] ).formatstr("%08X"); + state_add( AM29000_R232, "R232", m_r[232] ).formatstr("%08X"); + state_add( AM29000_R233, "R233", m_r[233] ).formatstr("%08X"); + state_add( AM29000_R234, "R234", m_r[234] ).formatstr("%08X"); + state_add( AM29000_R235, "R235", m_r[235] ).formatstr("%08X"); + state_add( AM29000_R236, "R236", m_r[236] ).formatstr("%08X"); + state_add( AM29000_R237, "R237", m_r[237] ).formatstr("%08X"); + state_add( AM29000_R238, "R238", m_r[238] ).formatstr("%08X"); + state_add( AM29000_R239, "R239", m_r[239] ).formatstr("%08X"); + state_add( AM29000_R240, "R240", m_r[240] ).formatstr("%08X"); + state_add( AM29000_R241, "R241", m_r[241] ).formatstr("%08X"); + state_add( AM29000_R242, "R242", m_r[242] ).formatstr("%08X"); + state_add( AM29000_R243, "R243", m_r[243] ).formatstr("%08X"); + state_add( AM29000_R244, "R244", m_r[244] ).formatstr("%08X"); + state_add( AM29000_R245, "R245", m_r[245] ).formatstr("%08X"); + state_add( AM29000_R246, "R246", m_r[246] ).formatstr("%08X"); + state_add( AM29000_R247, "R247", m_r[247] ).formatstr("%08X"); + state_add( AM29000_R248, "R248", m_r[248] ).formatstr("%08X"); + state_add( AM29000_R249, "R249", m_r[249] ).formatstr("%08X"); + state_add( AM29000_R250, "R250", m_r[250] ).formatstr("%08X"); + state_add( AM29000_R251, "R251", m_r[251] ).formatstr("%08X"); + state_add( AM29000_R252, "R252", m_r[252] ).formatstr("%08X"); + state_add( AM29000_R253, "R253", m_r[253] ).formatstr("%08X"); + state_add( AM29000_R254, "R254", m_r[254] ).formatstr("%08X"); + state_add( AM29000_R255, "R255", m_r[255] ).formatstr("%08X"); + + state_add(STATE_GENPC, "curpc", m_pc).formatstr("%08X").noshow(); + state_add(STATE_GENFLAGS, "GENFLAGS", m_alu).formatstr("%13s").noshow(); + + m_icountptr = &m_icount; +} + + +void am29000_cpu_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + switch (entry.index()) + { + case STATE_GENFLAGS: + strprintf(str, "%c%c%c%c%c%c%c%c%c|%3d", m_alu & ALU_V ? 'V' : '.', + m_alu & ALU_Z ? 'Z' : '.', + m_alu & ALU_N ? 'N' : '.', + m_alu & ALU_C ? 'C' : '.', + m_cps & CPS_IP ? 'I' : '.', + m_cps & CPS_FZ ? 'F' : '.', + m_cps & CPS_SM ? 'S' : 'U', + m_cps & CPS_DI ? 'I' : '.', + m_cps & CPS_DA ? 'D' : '.', + (m_r[1] >> 2) & 0x7f); + break; + } +} + + +void am29000_cpu_device::device_reset() +{ + m_cps = CPS_FZ | CPS_RE | CPS_PD | CPS_PI | CPS_SM | CPS_DI | CPS_DA; + m_cfg &= ~(CFG_DW | CFG_CD); + m_chc &= ~CHC_CV; + + m_pc = 0; + m_next_pl_flags = 0; + m_exceptions = 0; + m_irq_lines = 0; +} + + +void am29000_cpu_device::signal_exception(UINT32 type) +{ + m_exception_queue[m_exceptions++] = type; +} + + +void am29000_cpu_device::external_irq_check() +{ + int mask = (m_cps >> CPS_IM_SHIFT) & CPS_IM_MASK; + int irq_en = !(m_cps & CPS_DI) && !(m_cps & CPS_DA); + int i; + + /* Clear interrupt pending bit to begin with */ + m_cps &= ~CPS_IP; + + for (i = 0; i < 4; ++i) + { + if (!(m_irq_active & (1 << i)) && (m_irq_lines & (1 << i))) + { + if (irq_en) + { + if (i <= mask) + { + m_irq_active |= (1 << i); + signal_exception(EXCEPTION_INTR0 + i); + m_pl_flags |= PFLAG_IRQ; + return; + } + } + /* Set interrupt pending bit if interrupt was disabled */ + m_cps |= CPS_IP; + } + else + m_irq_active &= ~(1 << i); + } +} + + +UINT32 am29000_cpu_device::read_program_word(UINT32 address) +{ + /* TODO: ROM enable? */ + if (m_cps & CPS_PI || m_cps & CPS_RE) + return m_direct->read_dword(address); + else + { + fatalerror("Am29000 instruction MMU translation enabled!\n"); + } + // never executed + //return 0; +} + +/*************************************************************************** + HELPER FUNCTIONS +***************************************************************************/ + +UINT32 am29000_cpu_device::get_abs_reg(UINT8 r, UINT32 iptr) +{ + if (r & 0x80) + { + /* Stack pointer access */ + r = ((m_r[1] >> 2) & 0x7f) + (r & 0x7f); + r |= 0x80; + } + else if (r == 0) + { + /* Indirect pointer access */ + r = (iptr >> IPX_SHIFT) & 0xff; + } + else if (r > 1 && r < 64) + { + fatalerror("Am29000: Undefined register access (%d)\n", r); + } + return r; +} + + +/*************************************************************************** + CORE INCLUDE +***************************************************************************/ + +#include "am29ops.h" + + +/*************************************************************************** + PIPELINE STAGES +***************************************************************************/ + +void am29000_cpu_device::fetch_decode() +{ + UINT32 inst; + UINT32 op_flags; + + inst = read_program_word(m_pc); + m_next_ir = inst; + + op_flags = op_table[inst >> 24].flags; + + /* Illegal instruction */ + /* TODO: This should be checked at this point */ +#if 0 + if (op_flags & IFLAG_ILLEGAL) + { + fatalerror("Illegal instruction: %x PC:%x PC0:%x PC1:%x\n", inst, m_pc, m_pc0, m_pc1); + SIGNAL_EXCEPTION(EXCEPTION_ILLEGAL_OPCODE); + return; + } +#endif + + /* Privledge violations */ + if (USER_MODE) + { + if ((op_flags & IFLAG_SUPERVISOR_ONLY)) + { + signal_exception(EXCEPTION_PROTECTION_VIOLATION); + return; + } + + if ((op_flags & IFLAG_SPR_ACCESS)) + { + /* TODO: Is this the right place to check this? */ + if (INST_SA_FIELD(inst) < 128) + { + SIGNAL_EXCEPTION(EXCEPTION_PROTECTION_VIOLATION); + return; + } + } + + /* Register bank protection */ + if ((op_flags & IFLAG_RA_PRESENT) && REGISTER_IS_PROTECTED(INST_RA_FIELD(inst))) + { + SIGNAL_EXCEPTION(EXCEPTION_PROTECTION_VIOLATION); + return; + } + + if ((op_flags & IFLAG_RB_PRESENT) && REGISTER_IS_PROTECTED(INST_RB_FIELD(inst))) + { + SIGNAL_EXCEPTION(EXCEPTION_PROTECTION_VIOLATION); + return; + } + + if ((op_flags & IFLAG_RC_PRESENT) && REGISTER_IS_PROTECTED(INST_RC_FIELD(inst))) + { + SIGNAL_EXCEPTION(EXCEPTION_PROTECTION_VIOLATION); + return; + } + } + + if (m_pl_flags & PFLAG_IRET) + m_next_pc = m_iret_pc; + else + m_next_pc += 4; +} + +/*************************************************************************** + CORE EXECUTION LOOP +***************************************************************************/ + +void am29000_cpu_device::execute_run() +{ + UINT32 call_debugger = (machine().debug_flags & DEBUG_FLAG_ENABLED) != 0; + + external_irq_check(); + + do + { + m_next_pl_flags = PFLAG_EXECUTE_EN; + + if (!FREEZE_MODE) + { + m_pc1 = m_pc0; + m_pc0 = m_pc; + } + + if (m_exceptions) + { + m_ops = m_cps; + m_cps &= ~(CPS_TE | CPS_TP | CPS_TU | CPS_FZ | CPS_LK | CPS_WM | CPS_PD | CPS_PI | CPS_SM | CPS_DI | CPS_DA); + m_cps |= (CPS_FZ | CPS_PD | CPS_PI | CPS_SM | CPS_DI | CPS_DA); + + if (m_pl_flags & PFLAG_IRET) + { + m_pc0 = m_iret_pc; + m_pc1 = m_next_pc; + } + + + if (m_cfg & CFG_VF) + { + UINT32 vaddr = m_vab | m_exception_queue[0] * 4; + UINT32 vect = m_datadirect->read_dword(vaddr); + + m_pc = vect & ~3; + m_next_pc = m_pc; + } + else + { + fatalerror("Am29000: Non vectored interrupt fetch!\n"); + } + + m_exceptions = 0; + m_pl_flags = 0; + } + + if (call_debugger) + debugger_instruction_hook(this, m_pc); + + fetch_decode(); + + if (m_pl_flags & PFLAG_EXECUTE_EN) + { + if (!FREEZE_MODE) + m_pc2 = m_pc1; + + (this->*op_table[m_exec_ir >> 24].opcode)(); + } + + m_exec_ir = m_next_ir; + m_pl_flags = m_next_pl_flags; + m_exec_pc = m_pc; + m_pc = m_next_pc; + } while (--m_icount > 0); +} + + +void am29000_cpu_device::execute_set_input(int inputnum, int state) +{ + if (state) + m_irq_lines |= (1 << inputnum); + else + m_irq_lines &= ~(1 << inputnum); + + // TODO : CHECK IRQs +} + + +offs_t am29000_cpu_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( am29000 ); + return CPU_DISASSEMBLE_NAME(am29000)(this, buffer, pc, oprom, opram, options); +} diff --git a/src/devices/cpu/am29000/am29000.h b/src/devices/cpu/am29000/am29000.h new file mode 100644 index 00000000000..c47d87fd7ce --- /dev/null +++ b/src/devices/cpu/am29000/am29000.h @@ -0,0 +1,660 @@ +// license:BSD-3-Clause +// copyright-holders:Philip Bennett +/*************************************************************************** + + am29000.h + Interface file for the portable AMD Am29000 emulator. + Written by Phil Bennett + +***************************************************************************/ + +#pragma once + +#ifndef __AM29000_H__ +#define __AM29000_H__ + + +/*************************************************************************** + REGISTER ENUMERATION +***************************************************************************/ + +enum +{ + AM29000_PC = 1, + AM29000_VAB, + AM29000_OPS, + AM29000_CPS, + AM29000_CFG, + AM29000_CHA, + AM29000_CHD, + AM29000_CHC, + AM29000_RBP, + AM29000_TMC, + AM29000_TMR, + AM29000_PC0, + AM29000_PC1, + AM29000_PC2, + AM29000_MMU, + AM29000_LRU, + AM29000_IPC, + AM29000_IPA, + AM29000_IPB, + AM29000_Q, + AM29000_ALU, + AM29000_BP, + AM29000_FC, + AM29000_CR, + AM29000_FPE, + AM29000_INTE, + AM29000_FPS, + AM29000_R1, + AM29000_R64, + AM29000_R65, + AM29000_R66, + AM29000_R67, + AM29000_R68, + AM29000_R69, + AM29000_R70, + AM29000_R71, + AM29000_R72, + AM29000_R73, + AM29000_R74, + AM29000_R75, + AM29000_R76, + AM29000_R77, + AM29000_R78, + AM29000_R79, + AM29000_R80, + AM29000_R81, + AM29000_R82, + AM29000_R83, + AM29000_R84, + AM29000_R85, + AM29000_R86, + AM29000_R87, + AM29000_R88, + AM29000_R89, + AM29000_R90, + AM29000_R91, + AM29000_R92, + AM29000_R93, + AM29000_R94, + AM29000_R95, + AM29000_R96, + AM29000_R97, + AM29000_R98, + AM29000_R99, + AM29000_R100, + AM29000_R101, + AM29000_R102, + AM29000_R103, + AM29000_R104, + AM29000_R105, + AM29000_R106, + AM29000_R107, + AM29000_R108, + AM29000_R109, + AM29000_R110, + AM29000_R111, + AM29000_R112, + AM29000_R113, + AM29000_R114, + AM29000_R115, + AM29000_R116, + AM29000_R117, + AM29000_R118, + AM29000_R119, + AM29000_R120, + AM29000_R121, + AM29000_R122, + AM29000_R123, + AM29000_R124, + AM29000_R125, + AM29000_R126, + AM29000_R127, + AM29000_R128, + AM29000_R129, + AM29000_R130, + AM29000_R131, + AM29000_R132, + AM29000_R133, + AM29000_R134, + AM29000_R135, + AM29000_R136, + AM29000_R137, + AM29000_R138, + AM29000_R139, + AM29000_R140, + AM29000_R141, + AM29000_R142, + AM29000_R143, + AM29000_R144, + AM29000_R145, + AM29000_R146, + AM29000_R147, + AM29000_R148, + AM29000_R149, + AM29000_R150, + AM29000_R151, + AM29000_R152, + AM29000_R153, + AM29000_R154, + AM29000_R155, + AM29000_R156, + AM29000_R157, + AM29000_R158, + AM29000_R159, + AM29000_R160, + AM29000_R161, + AM29000_R162, + AM29000_R163, + AM29000_R164, + AM29000_R165, + AM29000_R166, + AM29000_R167, + AM29000_R168, + AM29000_R169, + AM29000_R170, + AM29000_R171, + AM29000_R172, + AM29000_R173, + AM29000_R174, + AM29000_R175, + AM29000_R176, + AM29000_R177, + AM29000_R178, + AM29000_R179, + AM29000_R180, + AM29000_R181, + AM29000_R182, + AM29000_R183, + AM29000_R184, + AM29000_R185, + AM29000_R186, + AM29000_R187, + AM29000_R188, + AM29000_R189, + AM29000_R190, + AM29000_R191, + AM29000_R192, + AM29000_R193, + AM29000_R194, + AM29000_R195, + AM29000_R196, + AM29000_R197, + AM29000_R198, + AM29000_R199, + AM29000_R200, + AM29000_R201, + AM29000_R202, + AM29000_R203, + AM29000_R204, + AM29000_R205, + AM29000_R206, + AM29000_R207, + AM29000_R208, + AM29000_R209, + AM29000_R210, + AM29000_R211, + AM29000_R212, + AM29000_R213, + AM29000_R214, + AM29000_R215, + AM29000_R216, + AM29000_R217, + AM29000_R218, + AM29000_R219, + AM29000_R220, + AM29000_R221, + AM29000_R222, + AM29000_R223, + AM29000_R224, + AM29000_R225, + AM29000_R226, + AM29000_R227, + AM29000_R228, + AM29000_R229, + AM29000_R230, + AM29000_R231, + AM29000_R232, + AM29000_R233, + AM29000_R234, + AM29000_R235, + AM29000_R236, + AM29000_R237, + AM29000_R238, + AM29000_R239, + AM29000_R240, + AM29000_R241, + AM29000_R242, + AM29000_R243, + AM29000_R244, + AM29000_R245, + AM29000_R246, + AM29000_R247, + AM29000_R248, + AM29000_R249, + AM29000_R250, + AM29000_R251, + AM29000_R252, + AM29000_R253, + AM29000_R254, + AM29000_R255 +}; + + +/*************************************************************************** + SPECIAL PURPOSE REGISTER INDICES +***************************************************************************/ + +enum +{ SPR_VAB = 0, + SPR_OPS = 1, + SPR_CPS = 2, + SPR_CFG = 3, + SPR_CHA = 4, + SPR_CHD = 5, + SPR_CHC = 6, + SPR_RBP = 7, + SPR_TMC = 8, + SPR_TMR = 9, + SPR_PC0 = 10, + SPR_PC1 = 11, + SPR_PC2 = 12, + SPR_MMU = 13, + SPR_LRU = 14, + SPR_IPC = 128, + SPR_IPA = 129, + SPR_IPB = 130, + SPR_Q = 131, + SPR_ALU = 132, + SPR_BP = 133, + SPR_FC = 134, + SPR_CR = 135, + SPR_FPE = 160, + SPR_INTE = 161, + SPR_FPS = 162 +}; + + +enum +{ + SPACE_INSTRUCTION = 0, + SPACE_DATA, + SPACE_IO, + SPACE_COPROCESSOR +}; + + +/*************************************************************************** + EXCEPTION VECTORS +***************************************************************************/ + +enum +{ + EXCEPTION_ILLEGAL_OPCODE = 0, + EXCEPTION_UNALIGNED_ACCESS = 1, + EXCEPTION_OUT_OF_RANGE = 2, + EXCEPTION_COPRO_NOT_PRESENT = 3, + EXCEPTION_COPRO_EXCEPTION = 4, + EXCEPTION_PROTECTION_VIOLATION = 5, + EXCEPTION_INST_ACCESS_VIOLATION = 6, + EXCEPTION_DATA_ACCESS_VIOLATION = 7, + EXCEPTION_USER_INST_TLB_MISS = 8, + EXCEPTION_USER_DATA_TLB_MISS = 9, + EXCEPTION_SUPER_INST_TLB_MISS = 10, + EXCEPTION_SUPER_DATA_TLB_MISS = 11, + EXCEPTION_INST_TLB_PROT_VIOLATION = 12, + EXCEPTION_DATA_TLB_PROT_VIOLATION = 13, + EXCEPTION_TIMER = 14, + EXCEPTION_TRACE = 15, + EXCEPTION_INTR0 = 16, + EXCEPTION_INTR1 = 17, + EXCEPTION_INTR2 = 18, + EXCEPTION_INTR3 = 19, + EXCEPTION_TRAP0 = 20, + EXCEPTION_TRAP1 = 21, + EXCEPTION_FLOATING_POINT_EXCEPTION = 22, + EXCEPTION_MULTM = 30, + EXCEPTION_MULTMU = 31, + EXCEPTION_MULTIPLY = 32, + EXCEPTION_DIVIDE = 33, + EXCEPTION_MULTIPLU = 44 // TODO: FINISH ME +}; + + +/*************************************************************************** + SPECIAL PURPOSE REGISTER FIELDS +***************************************************************************/ + +#define PRL_AM29000 (0 << 3) +#define PRL_AM29050 (1 << 3) +#define PRL_REV_A (0) +#define PRL_REV_B (1) +#define PRL_REV_C (2) +#define PRL_REV_D (3) + +#define PROCESSOR_REL_FIELD (PRL_AM29000 | PRL_REV_D) + +#define VAB_SHIFT (16) +#define VAB_MASK (0xffff) + +#define CPS_CA (1 << 15) +#define CPS_IP (1 << 14) +#define CPS_TE (1 << 13) +#define CPS_TP (1 << 12) +#define CPS_TU (1 << 11) +#define CPS_FZ (1 << 10) +#define CPS_LK (1 << 9) +#define CPS_RE (1 << 8) +#define CPS_WM (1 << 7) +#define CPS_PD (1 << 6) +#define CPS_PI (1 << 5) +#define CPS_SM (1 << 4) +#define CPS_IM_SHIFT (2) +#define CPS_IM_MASK (3) +#define CPS_DI (1 << 1) +#define CPS_DA (1 << 0) + +#define CFG_PRL_MASK (0xff) +#define CFG_PRL_SHIFT (24) +#define CFG_DW (1 << 5) +#define CFG_VF (1 << 4) +#define CFG_RV (1 << 3) +#define CFG_BO (1 << 2) +#define CFG_CP (1 << 1) +#define CFG_CD (1 << 0) + +#define CHC_CE_CNTL_MASK (0xff) +#define CHC_CE_CNTL_SHIFT (24) +#define CHC_CR_MASK (0xff) +#define CHC_CR_SHIFT (16) +#define CHC_LS (1 << 15) +#define CHC_ML (1 << 14) +#define CHC_ST (1 << 13) +#define CHC_LA (1 << 12) +#define CHC_TF (1 << 11) +#define CHC_TR_MASK (0xff) +#define CHC_TR_SHIFT (2) +#define CHC_NN (1 << 1) +#define CHC_CV (1 << 0) + +#define RBP_MASK (0xffff) + +#define TCV_MASK (0x00ffffff) +#define TCV_SHIFT (0) + +#define TMR_OV (1 << 26) +#define TMR_IN (1 << 25) +#define TMR_IE (1 << 24) +#define TMR_TRV_MASK (0x00ffffff) +#define TMR_TRV_SHIFT (0) + +#define PC_MASK (0xfffffffc) + +#define MMU_PS_MASK (3) +#define MMU_PS_SHIFT (8) +#define MMU_PID_MASK (0xff) +#define MMU_PID_SHIFT (0) + +#define LRU_MASK (0x3f) +#define LRU_SHIFT (1) + +#define ALU_DF_SHIFT (11) +#define ALU_DF (1 << 11) +#define ALU_V_SHIFT (10) +#define ALU_V (1 << 10) +#define ALU_N_SHIFT (9) +#define ALU_N (1 << 9) +#define ALU_Z_SHIFT (8) +#define ALU_Z (1 << 8) +#define ALU_C_SHIFT (7) +#define ALU_C (1 << 7) +#define ALU_BP_MASK (3) +#define ALU_BP_SHIFT (5) +#define ALU_FC_MASK (0x1f) +#define ALU_FC_SHIFT (0) + +#define IPX_MASK (0xff) +#define IPX_SHIFT (2) + + + + +/*************************************************************************** + INTERRUPT CONSTANTS +***************************************************************************/ + +#define AM29000_INTR0 0 +#define AM29000_INTR1 1 +#define AM29000_INTR2 2 +#define AM29000_INTR3 3 + + +class am29000_cpu_device : public cpu_device +{ +public: + // construction/destruction + am29000_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_execute_interface overrides + virtual UINT32 execute_min_cycles() const { return 1; } + virtual UINT32 execute_max_cycles() const { return 2; } + virtual UINT32 execute_input_lines() const { return 1; } + virtual void execute_run(); + virtual void execute_set_input(int inputnum, int state); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const + { + switch (spacenum) + { + case AS_PROGRAM: return &m_program_config; + case AS_IO: return &m_io_config; + case AS_DATA: return &m_data_config; + default: return NULL; + } + } + + // device_state_interface overrides + void state_string_export(const device_state_entry &entry, std::string &str); + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const { return 4; } + virtual UINT32 disasm_max_opcode_bytes() const { return 4; } + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + + void signal_exception(UINT32 type); + void external_irq_check(); + UINT32 read_program_word(UINT32 address); + UINT32 get_abs_reg(UINT8 r, UINT32 iptr); + void fetch_decode(); + UINT32 read_spr(UINT32 idx); + void write_spr(UINT32 idx, UINT32 val); + void ADD(); + void ADDS(); + void ADDU(); + void ADDC(); + void ADDCS(); + void ADDCU(); + void SUB(); + void SUBS(); + void SUBU(); + void SUBC(); + void SUBCS(); + void SUBCU(); + void SUBR(); + void SUBRS(); + void SUBRU(); + void SUBRC(); + void SUBRCS(); + void SUBRCU(); + void MULTIPLU(); + void MULTIPLY(); + void MUL(); + void MULL(); + void MULU(); + void DIVIDE(); + void DIVIDU(); + void DIV0(); + void DIV(); + void DIVL(); + void DIVREM(); + void CPEQ(); + void CPNEQ(); + void CPLT(); + void CPLTU(); + void CPLE(); + void CPLEU(); + void CPGT(); + void CPGTU(); + void CPGE(); + void CPGEU(); + void CPBYTE(); + void ASEQ(); + void ASNEQ(); + void ASLT(); + void ASLTU(); + void ASLE(); + void ASLEU(); + void ASGT(); + void ASGTU(); + void ASGE(); + void ASGEU(); + void AND(); + void ANDN(); + void NAND(); + void OR(); + void NOR(); + void XOR(); + void XNOR(); + void SLL(); + void SRL(); + void SRA(); + void EXTRACT(); + void LOAD(); + void LOADL(); + void LOADSET(); + void LOADM(); + void STORE(); + void STOREL(); + void STOREM(); + void EXBYTE(); + void EXHW(); + void EXHWS(); + void INBYTE(); + void INHW(); + void MFSR(); + void MFTLB(); + void MTSR(); + void MTSRIM(); + void MTTLB(); + void CONST(); + void CONSTH(); + void CONSTN(); + void CALL(); + void CALLI(); + void JMP(); + void JMPI(); + void JMPT(); + void JMPTI(); + void JMPF(); + void JMPFI(); + void JMPFDEC(); + void CLZ(); + void SETIP(); + void EMULATE(); + void INV(); + void IRET(); + void IRETINV(); + void HALT(); + void ILLEGAL(); + void CONVERT(); + void SQRT(); + void CLASS(); + void MULTM(); + void MULTMU(); + + address_space_config m_program_config; + address_space_config m_io_config; + address_space_config m_data_config; + + INT32 m_icount; + UINT32 m_pc; + + /* General purpose */ + UINT32 m_r[256]; // TODO: There's only 192 implemented! + + /* TLB */ + UINT32 m_tlb[128]; + + /* Protected SPRs */ + UINT32 m_vab; + UINT32 m_ops; + UINT32 m_cps; + UINT32 m_cfg; + UINT32 m_cha; + UINT32 m_chd; + UINT32 m_chc; + UINT32 m_rbp; + UINT32 m_tmc; + UINT32 m_tmr; + UINT32 m_pc0; + UINT32 m_pc1; + UINT32 m_pc2; + UINT32 m_mmu; + UINT32 m_lru; + + /* Unprotected SPRs */ + UINT32 m_ipc; + UINT32 m_ipa; + UINT32 m_ipb; + UINT32 m_q; + UINT32 m_alu; + UINT32 m_fpe; + UINT32 m_inte; + UINT32 m_fps; + + /* Pipeline state */ + UINT32 m_exceptions; + UINT32 m_exception_queue[4]; + + UINT8 m_irq_active; + UINT8 m_irq_lines; + + UINT32 m_exec_ir; + UINT32 m_next_ir; + + UINT32 m_pl_flags; + UINT32 m_next_pl_flags; + + UINT32 m_iret_pc; + + UINT32 m_exec_pc; + UINT32 m_next_pc; + + address_space *m_program; + direct_read_data *m_direct; + address_space *m_data; + direct_read_data *m_datadirect; + address_space *m_io; + + typedef void ( am29000_cpu_device::*opcode_func ) (); + struct op_info { + opcode_func opcode; + UINT32 flags; + }; + + static const op_info op_table[256]; +}; + + +extern const device_type AM29000; + + +#endif /* __AM29000_H__ */ diff --git a/src/devices/cpu/am29000/am29dasm.c b/src/devices/cpu/am29000/am29dasm.c new file mode 100644 index 00000000000..bd8c6712fd2 --- /dev/null +++ b/src/devices/cpu/am29000/am29dasm.c @@ -0,0 +1,259 @@ +// license:BSD-3-Clause +// copyright-holders:Philip Bennett +/*************************************************************************** + + am29dasm.c + Disassembler for the portable Am29000 emulator. + Written by Phil Bennett + +***************************************************************************/ + +#include "emu.h" +#include "am29000.h" + + +/*************************************************************************** + DEFINES AND MACROS +***************************************************************************/ + +#define OP_M_BIT (1 << 24) +#define OP_RC ((op >> 16) & 0xff) +#define OP_RA ((op >> 8) & 0xff) +#define OP_RB (op & 0xff) +#define OP_I8 (op & 0xff) +#define OP_SA ((op >> 8) & 0xff) +#define OP_I16 (((op >> 8) & 0xff00) | (op & 0xff)) +#define OP_IJMP (OP_I16 << 2) +#define OP_VN ((op >> 16) & 0xff) + +#define OP_CE ((op >> 23) & 1) +#define OP_CNTL ((op >> 16) & 0x7f) + +#define OP_SJMP ((INT32)(INT16)OP_I16 << 2) + + +/*************************************************************************** + CODE +***************************************************************************/ + +static const char *dasm_type1(UINT32 op) +{ + static char buf[32]; + + if (op & OP_M_BIT) + sprintf(buf, "r%d, r%d, $%.2x", OP_RC, OP_RA, OP_I8); + else + sprintf(buf, "r%d, r%d, r%d", OP_RC, OP_RA, OP_RB); + + return buf; +} + +static const char *dasm_type2(UINT32 op) +{ + static char buf[32]; + + sprintf(buf, "r%d, r%d, r%d", OP_RC, OP_RA, OP_RB); + + return buf; +} + +static const char *dasm_type3(UINT32 op) +{ + static char buf[32]; + + sprintf(buf, "r%d, $%.4x", OP_RA, OP_I16); + + return buf; +} + +static const char *dasm_type4(UINT32 op, UINT32 pc) +{ + static char buf[32]; + + if (op & OP_M_BIT) + sprintf(buf, "r%d, $%.4x", OP_RA, OP_IJMP); + else + sprintf(buf, "r%d, $%.4x", OP_RA, pc + OP_SJMP); + + return buf; +} + +static const char *dasm_type5(UINT32 op) +{ + static char buf[32]; + + if (op & OP_M_BIT) + sprintf(buf, "trap%d, r%d, $%.2x", OP_VN, OP_RA, OP_I8); + else + sprintf(buf, "trap%d, r%d, r%d", OP_VN, OP_RA, OP_RB); + + return buf; +} + +static const char *dasm_type6(UINT32 op) +{ + static char buf[32]; + + if (op & OP_M_BIT) + sprintf(buf, "%d, %x, r%d, $%.2x", OP_CE, OP_CNTL, OP_RA, OP_I8); + else + sprintf(buf, "%d, %x, r%d, r%d", OP_CE, OP_CNTL, OP_RA, OP_RB); + + return buf; +} + +#define TYPE_1 dasm_type1(op) +#define TYPE_2 dasm_type2(op) +#define TYPE_3 dasm_type3(op) +#define TYPE_4 dasm_type4(op, pc) +#define TYPE_5 dasm_type5(op) +#define TYPE_6 dasm_type6(op) + + +static const char* get_spr(int spid) +{ + switch (spid) + { + case 0: return "VAB"; + case 1: return "OPS"; + case 2: return "CPS"; + case 3: return "CFG"; + case 4: return "CHA"; + case 5: return "CHD"; + case 6: return "CHC"; + case 7: return "RBP"; + case 8: return "TMC"; + case 9: return "TMR"; + case 10: return "PC0"; + case 11: return "PC1"; + case 12: return "PC2"; + case 13: return "MMU"; + case 14: return "LRU"; + case 128: return "IPC"; + case 129: return "IPA"; + case 130: return "IPB"; + case 131: return "Q"; + case 132: return "ALU"; + case 133: return "BP"; + case 134: return "FC"; + case 135: return "CR"; + case 160: return "FPE"; + case 161: return "INTE"; + case 162: return "FPS"; + case 164: return "EXOP"; + default: return "????"; + } +} + +CPU_DISASSEMBLE( am29000 ) +{ + UINT32 op = (oprom[0] << 24) | (oprom[1] << 16) | (oprom[2] << 8) | oprom[3]; + UINT32 flags = 0; + + switch (op >> 24) + { + case 0x01: sprintf(buffer, "constn %s", TYPE_3); break; + case 0x02: sprintf(buffer, "consth %s", TYPE_3); break; + case 0x03: sprintf(buffer, "const %s", TYPE_3); break; + case 0x04: sprintf(buffer, "mtsrim %s, $%.4x", get_spr(OP_SA), OP_I16); break; + case 0x06: case 0x07: sprintf(buffer, "loadl %s", TYPE_6); break; + case 0x08: sprintf(buffer, "clz r%d, %d", OP_RC, OP_RB); break; + case 0x09: sprintf(buffer, "clz %d, %.2x", OP_RC, OP_I8); break; + case 0x0a: case 0x0b: sprintf(buffer, "exbyte %s", TYPE_1); break; + case 0x0c: case 0x0d: sprintf(buffer, "inbyte %s", TYPE_1); break; + case 0x0e: case 0x0f: sprintf(buffer, "storel %s", TYPE_6); break; + case 0x10: case 0x11: sprintf(buffer, "adds %s", TYPE_1); break; + case 0x12: case 0x13: sprintf(buffer, "addu %s", TYPE_1); break; + case 0x14: case 0x15: sprintf(buffer, "add %s", TYPE_1); break; + case 0x16: case 0x17: sprintf(buffer, "load %s", TYPE_6); break; + case 0x18: case 0x19: sprintf(buffer, "addcs %s", TYPE_1); break; + case 0x1a: case 0x1b: sprintf(buffer, "addcu %s", TYPE_1); break; + case 0x1c: case 0x1d: sprintf(buffer, "addc %s", TYPE_1); break; + case 0x1e: case 0x1f: sprintf(buffer, "store %s", TYPE_6); break; + case 0x20: case 0x21: sprintf(buffer, "subs %s", TYPE_1); break; + case 0x22: case 0x23: sprintf(buffer, "subu %s", TYPE_1); break; + case 0x24: case 0x25: sprintf(buffer, "sub %s", TYPE_1); break; + case 0x26: case 0x27: sprintf(buffer, "loadset %s", TYPE_6); break; + case 0x28: case 0x29: sprintf(buffer, "subcs %s", TYPE_1); break; + case 0x2a: case 0x2b: sprintf(buffer, "subcu %s", TYPE_1); break; + case 0x2c: case 0x2d: sprintf(buffer, "subc %s", TYPE_1); break; + case 0x2e: case 0x2f: sprintf(buffer, "cpbyte %s", TYPE_1); break; + case 0x30: case 0x31: sprintf(buffer, "subrs %s", TYPE_1); break; + case 0x32: case 0x33: sprintf(buffer, "subru %s", TYPE_1); break; + case 0x34: case 0x35: sprintf(buffer, "subr %s", TYPE_1); break; + case 0x36: case 0x37: sprintf(buffer, "loadm %s", TYPE_6); break; + case 0x38: case 0x39: sprintf(buffer, "subrcs %s", TYPE_1); break; + case 0x3a: case 0x3b: sprintf(buffer, "subrcu %s", TYPE_1); break; + case 0x3c: case 0x3d: sprintf(buffer, "subrc %s", TYPE_1); break; + case 0x3e: case 0x3f: sprintf(buffer, "storem %s", TYPE_6); break; + case 0x40: case 0x41: sprintf(buffer, "cplt %s", TYPE_1); break; + case 0x42: case 0x43: sprintf(buffer, "cpltu %s", TYPE_1); break; + case 0x44: case 0x45: sprintf(buffer, "cple %s", TYPE_1); break; + case 0x46: case 0x47: sprintf(buffer, "cpleu %s", TYPE_1); break; + case 0x48: case 0x49: sprintf(buffer, "cpgt %s", TYPE_1); break; + case 0x4a: case 0x4b: sprintf(buffer, "cpgtu %s", TYPE_1); break; + case 0x4c: case 0x4d: sprintf(buffer, "cpge %s", TYPE_1); break; + case 0x4e: case 0x4f: sprintf(buffer, "cpgeu %s", TYPE_1); break; + case 0x50: case 0x51: sprintf(buffer, "aslt %s", TYPE_5); break; + case 0x52: case 0x53: sprintf(buffer, "asltu %s", TYPE_5); break; + case 0x54: case 0x55: sprintf(buffer, "asle %s", TYPE_5); break; + case 0x56: case 0x57: sprintf(buffer, "asleu %s", TYPE_5); break; + case 0x58: case 0x59: sprintf(buffer, "asgt %s", TYPE_5); break; + case 0x5a: case 0x5b: sprintf(buffer, "asgtu %s", TYPE_5); break; + case 0x5c: case 0x5d: sprintf(buffer, "asge %s", TYPE_5); break; + case 0x5e: case 0x5f: sprintf(buffer, "asgeu %s", TYPE_5); break; + case 0x60: case 0x61: sprintf(buffer, "cpeq %s", TYPE_1); break; + case 0x62: case 0x63: sprintf(buffer, "cpneq %s", TYPE_1); break; + case 0x64: case 0x65: sprintf(buffer, "mul %s", TYPE_1); break; + case 0x66: case 0x67: sprintf(buffer, "mull %s", TYPE_1); break; + case 0x68: sprintf(buffer, "div0 r%d, r%d", OP_RC, OP_RB); break; + case 0x69: sprintf(buffer, "div0 r%d, %.2x", OP_RC, OP_I8); break; + case 0x6a: case 0x6b: sprintf(buffer, "div %s", TYPE_1); break; + case 0x6c: case 0x6d: sprintf(buffer, "divl %s", TYPE_1); break; + case 0x6e: case 0x6f: sprintf(buffer, "divrem %s", TYPE_1); break; + case 0x70: case 0x71: sprintf(buffer, "aseq %s", TYPE_5); break; + case 0x72: case 0x73: sprintf(buffer, "asneq %s", TYPE_5); break; + case 0x74: case 0x75: sprintf(buffer, "mulu %s", TYPE_1); break; + case 0x78: case 0x79: sprintf(buffer, "inhw %s", TYPE_1); break; + case 0x7a: case 0x7b: sprintf(buffer, "extract %s", TYPE_1); break; + case 0x7c: case 0x7d: sprintf(buffer, "exhw %s", TYPE_1); break; + case 0x7e: sprintf(buffer, "exhws %s", TYPE_1); break; + case 0x80: case 0x81: sprintf(buffer, "sll %s", TYPE_1); break; + case 0x82: case 0x83: sprintf(buffer, "srl %s", TYPE_1); break; + case 0x86: case 0x87: sprintf(buffer, "sra %s", TYPE_1); break; + case 0x88: sprintf(buffer, "iret"); break; + case 0x89: sprintf(buffer, "halt"); break; + case 0x8c: sprintf(buffer, "iretinv"); break; + case 0x90: case 0x91: sprintf(buffer, "and %s", TYPE_1); break; + case 0x92: case 0x93: sprintf(buffer, "or %s", TYPE_1); break; + case 0x94: case 0x95: sprintf(buffer, "xor %s", TYPE_1); break; + case 0x96: case 0x97: sprintf(buffer, "xnor %s", TYPE_1); break; + case 0x98: case 0x99: sprintf(buffer, "nor %s", TYPE_1); break; + case 0x9a: case 0x9b: sprintf(buffer, "nand %s", TYPE_1); break; + case 0x9c: case 0x9d: sprintf(buffer, "andn %s", TYPE_1); break; + case 0x9e: sprintf(buffer, "setip %s", TYPE_2); break; + case 0x9f: sprintf(buffer, "inv"); break; + case 0xa0: sprintf(buffer, "jmp $%.4x", pc + OP_SJMP); break; + case 0xa1: sprintf(buffer, "jmp $%.4x", OP_IJMP); break; + case 0xa4: case 0xa5: sprintf(buffer, "jmpf %s", TYPE_4); break; + case 0xa8: case 0xa9: sprintf(buffer, "call %s", TYPE_4); break; + case 0xac: case 0xad: sprintf(buffer, "jmpt %s", TYPE_4); break; + case 0xb4: case 0xb5: sprintf(buffer, "jmpfdec %s", TYPE_4); break; + case 0xb6: sprintf(buffer, "mftlb r%d, r%d", OP_RC, OP_RA); break; + case 0xbe: sprintf(buffer, "mttlb r%d, r%d", OP_RA, OP_RB); break; + case 0xc0: sprintf(buffer, "jmpi r%d", OP_RB); break; + case 0xc4: sprintf(buffer, "jmpfi r%d, r%d", OP_RA, OP_RB); break; + case 0xc6: sprintf(buffer, "mfsr r%d, %s", OP_RC, get_spr(OP_SA)); break; + case 0xc8: sprintf(buffer, "calli r%d, r%d", OP_RA, OP_RB); break; + case 0xcc: sprintf(buffer, "jmpti r%d, r%d", OP_RA, OP_RB); break; + case 0xce: sprintf(buffer, "mtsr %s, r%d", get_spr(OP_SA), OP_RB); break; + case 0xd7: sprintf(buffer, "emulate %s", TYPE_5); break; + case 0xde: sprintf(buffer, "multm %s", TYPE_2); break; + case 0xdf: sprintf(buffer, "multmu %s", TYPE_2); break; + + case 0xe0: sprintf(buffer, "multiply %s", TYPE_2); break; + case 0xe1: sprintf(buffer, "divide %s", TYPE_2); break; + default: sprintf(buffer, "??????"); break; + } + return 4 | flags | DASMFLAG_SUPPORTED; +} diff --git a/src/devices/cpu/am29000/am29ops.h b/src/devices/cpu/am29000/am29ops.h new file mode 100644 index 00000000000..bd3602391e6 --- /dev/null +++ b/src/devices/cpu/am29000/am29ops.h @@ -0,0 +1,1716 @@ +// license:BSD-3-Clause +// copyright-holders:Philip Bennett +/*************************************************************************** + + am29ops.h + Am29000 instructions + +***************************************************************************/ + +/*************************************************************************** + DEFINES +***************************************************************************/ + +#define IFLAG_ILLEGAL (1 << 0) +#define IFLAG_SUPERVISOR_ONLY (1 << 1) +#define IFLAG_RA_PRESENT (1 << 2) +#define IFLAG_RB_PRESENT (1 << 3) +#define IFLAG_RC_PRESENT (1 << 4) + +#define IFLAG_SPR_ACCESS (1 << 6) +#define IFLAG_MEMORY_ACCESS (1 << 8) +#define IFLAG_CONTROL (1 << 9) + + +#define GET_RA_VAL (m_r[RA]) +#define GET_RB_VAL (m_r[RB]) + +#define RA (get_abs_reg(m_exec_ir >> 8, m_ipa)) +#define RB (get_abs_reg(m_exec_ir >> 0, m_ipb)) +#define RC (get_abs_reg(m_exec_ir >> 16, m_ipc)) + +#define INST_SA ((m_exec_ir >> 8) & 0xff) +#define INST_VN ((m_exec_ir >> 16) & 0xff) +#define INST_M_BIT (m_exec_ir & (1 << 24)) +#define INST_CE_BIT (m_exec_ir & (1 << 23)) +#define INST_AS_BIT (m_exec_ir & (1 << 22)) +#define INST_PA_BIT (m_exec_ir & (1 << 21)) +#define INST_SB_BIT (m_exec_ir & (1 << 20)) +#define INST_UA_BIT (m_exec_ir & (1 << 19)) +#define INST_OPT_MASK (7) +#define INST_OPT_SHIFT (16) +#define INST_OPT_FIELD (((m_exec_ir) >> INST_OPT_SHIFT) & INST_OPT_MASK) +#define INST_CNTL_MASK (0x7f) +#define INST_CNTL_SHIFT (16) + +#define I8 (m_exec_ir & 0xff) +#define I16 (((m_exec_ir >> 8) & 0xff00) | (m_exec_ir & 0xff)) +#define I16_ZEX ((UINT32)(I16)) +#define I16_SEX ((INT32)(INT16)I16) +#define I16_OEX (0xffff0000 | I16) + +#define JMP_ZEX (I16 << 2) +#define JMP_SEX ((INT32)(INT16)(((m_exec_ir >> 8) & 0xff00) | (m_exec_ir & 0xff)) << 2) + +#define BOOLEAN_MASK (1 << 31) +#define BOOLEAN_TRUE (1 << 31) +#define BOOLEAN_FALSE (0) + +#define UNHANDLED_OP fatalerror("Am29000: Unhandled inst %s at %x\n", __FUNCTION__, m_exec_pc); + + +/*************************************************************************** + ALU FLAG CALCULATION +***************************************************************************/ + +#define SET_ALU_Z(r) m_alu &= ~ALU_Z; \ + m_alu |= (r == 0) << ALU_Z_SHIFT; + +#define SET_ALU_N(r) m_alu &= ~ALU_N; \ + m_alu |= ((UINT32)r & 0x80000000) >> (31 - ALU_N_SHIFT); + +#define CALC_C_ADD(r, a) ((UINT32)(r) < (UINT32)(a)) + +#define SET_ALU_C_ADD(r, a) m_alu &= ~ALU_C; \ + m_alu |= CALC_C_ADD(r, a) << ALU_C_SHIFT; + +#define CALC_C_SUB(a, b) (!((UINT32)(a) < (UINT32)(b))) + +#define SET_ALU_C_SUB(a, b) m_alu &= ~ALU_C; \ + m_alu |= CALC_C_SUB(a, b) << ALU_C_SHIFT; + +#define SET_ALU_V_ADD(r, a, b) m_alu &= ~ALU_V; \ + m_alu |= (((INT32)(~((a) ^ (b)) & ((a) ^ (r))) < 0)) << ALU_V_SHIFT; + +#define SET_ALU_V_SUB(r, a, b) m_alu &= ~ALU_V; \ + m_alu |= ((INT32)(((a) ^ (b)) & ((a) ^ (r))) < 0) << ALU_V_SHIFT; + +#define GET_CARRY ((m_alu >> ALU_C_SHIFT) & 1) + + + +UINT32 am29000_cpu_device::read_spr(UINT32 idx) +{ + UINT32 val = 0; + + switch (idx) + { + case SPR_VAB: val = m_vab; break; + case SPR_OPS: val = m_ops; break; + case SPR_CPS: val = m_cps; break; + case SPR_CFG: val = m_cfg; break; + case SPR_CHA: val = m_cha; break; + case SPR_CHD: val = m_chd; break; + case SPR_CHC: val = m_chc; break; + case SPR_RBP: val = m_rbp; break; + case SPR_TMC: val = m_tmc; break; + case SPR_TMR: val = m_tmr; break; + case SPR_PC0: val = m_pc0; break; + case SPR_PC1: val = m_pc1; break; + case SPR_PC2: val = m_pc2; break; + case SPR_MMU: val = m_mmu; break; + case SPR_LRU: val = m_lru; break; + case SPR_IPC: val = m_ipc; break; + case SPR_IPA: val = m_ipa; break; + case SPR_IPB: val = m_ipb; break; + case SPR_Q: val = m_q; break; + case SPR_ALU: val = m_alu; break; + case SPR_BP: val = GET_ALU_BP; break; + case SPR_FC: val = GET_ALU_FC; break; + case SPR_CR: val = GET_CHC_CR; break; + case SPR_FPE: val = m_fpe; break; + case SPR_INTE: val = m_inte; break; + case SPR_FPS: val = m_fps; break; + default: + logerror("Unknown SPR read (%d)\n", idx); + } + + return val; +} + + +void am29000_cpu_device::write_spr(UINT32 idx, UINT32 val) +{ + switch (idx) + { + case SPR_VAB: m_vab = val & (VAB_MASK << VAB_SHIFT); + break; + case SPR_OPS: m_ops = val & (CPS_CA | CPS_IP | CPS_TE | CPS_TP | CPS_TU | CPS_FZ | CPS_LK | CPS_RE | + CPS_WM | CPS_PD | CPS_PI | CPS_SM | (CPS_IM_MASK << CPS_IM_SHIFT) | CPS_DI | CPS_DA); + break; + case SPR_CPS: m_cps = val & (CPS_CA | CPS_IP | CPS_TE | CPS_TP | CPS_TU | CPS_FZ | CPS_LK | CPS_RE | + CPS_WM | CPS_PD | CPS_PI | CPS_SM | (CPS_IM_MASK << CPS_IM_SHIFT) | CPS_DI | CPS_DA); + break; + case SPR_CFG: m_cfg = val & (CFG_DW | CFG_VF | CFG_RV | CFG_BO | CFG_CP | CFG_CD); + m_cfg |= PROCESSOR_REL_FIELD << CFG_PRL_SHIFT; + break; + case SPR_CHA: m_cha = val; + break; + case SPR_CHD: m_chd = val; + break; + case SPR_CHC: m_chc = val; + break; + case SPR_RBP: m_rbp = val & RBP_MASK; + break; + case SPR_TMC: m_tmc = val & TCV_MASK; + break; + case SPR_TMR: m_tmr = val & (TMR_OV | TMR_IN | TMR_IE | TMR_TRV_MASK); + break; + case SPR_PC0: m_pc0 = val & PC_MASK; + break; + case SPR_PC1: m_pc1 = val & PC_MASK; + break; + case SPR_PC2: m_pc2 = val & PC_MASK; + break; + case SPR_MMU: m_mmu = val & ((MMU_PS_MASK << MMU_PS_SHIFT) | MMU_PID_MASK); + break; + case SPR_LRU: m_lru = val & (LRU_MASK << LRU_SHIFT); + break; + case SPR_IPC: m_ipc = val;// & IPX_MASK; + break; + case SPR_IPA: m_ipa = val;// & IPX_MASK; + break; + case SPR_IPB: m_ipb = val;// & IPX_MASK; + break; + case SPR_Q: m_q = val; + break; + case SPR_ALU: m_alu = val & (ALU_DF | ALU_V | ALU_N | ALU_Z | ALU_C | (ALU_BP_MASK << ALU_BP_SHIFT) | (ALU_FC_MASK << ALU_FC_SHIFT)); + break; + case SPR_BP: m_alu &= ~(ALU_BP_MASK << ALU_BP_SHIFT); + m_alu |= (val & ALU_BP_MASK) << ALU_BP_SHIFT; + break; + case SPR_FC: m_alu &= ~(ALU_FC_MASK << ALU_FC_SHIFT); + m_alu |= (val & ALU_FC_MASK) << ALU_FC_SHIFT; + break; + case SPR_CR: m_chc &= ~(CHC_CR_MASK << CHC_CR_SHIFT); + m_chc |= (val & CHC_CR_MASK) << CHC_CR_SHIFT; + break; +// case SPR_FPE: +// case SPR_INTE: +// case SPR_FPS: + default: logerror("Unhandled SPR write (%d)\n", idx); + } +} + + +/*************************************************************************** + INSTRUCTIONS +***************************************************************************/ + +/*************************************************************************** + INTEGER ARITHMETIC +***************************************************************************/ + +void am29000_cpu_device::ADD() +{ + UINT32 a = GET_RA_VAL; + UINT32 b = INST_M_BIT ? I8: GET_RB_VAL; + UINT32 r = a + b; + + if (!FREEZE_MODE) + { + SET_ALU_V_ADD(r, a, b); + SET_ALU_Z(r); + SET_ALU_N(r); + SET_ALU_C_ADD(r, a); + } + + m_r[RC] = r; +} + +void am29000_cpu_device::ADDS() +{ + UNHANDLED_OP; +} + +void am29000_cpu_device::ADDU() +{ + UNHANDLED_OP; +} + +void am29000_cpu_device::ADDC() +{ + UNHANDLED_OP; +} + +void am29000_cpu_device::ADDCS() +{ + UINT32 a = GET_RA_VAL; + UINT32 b = INST_M_BIT ? I8: GET_RB_VAL; + UINT32 r = a + b + GET_CARRY; + + if (!FREEZE_MODE) + { + UINT32 carry = GET_CARRY; + UINT32 tmp = a + b; + + SET_ALU_V_ADD(r, a, b); + SET_ALU_Z(r); + SET_ALU_N(r); + + carry = CALC_C_ADD(tmp, a) || CALC_C_ADD(tmp + carry, carry); + m_alu &= ~ALU_C; + m_alu |= carry << ALU_C_SHIFT; + } + + // TODO: Trap on signed overflow + m_r[RC] = r; +} + +void am29000_cpu_device::ADDCU() +{ + UNHANDLED_OP; +} + +void am29000_cpu_device::SUB() +{ + UINT32 a = GET_RA_VAL; + UINT32 b = INST_M_BIT ? I8 : GET_RB_VAL; + UINT32 r = a - b; + + if (!FREEZE_MODE) + { + SET_ALU_V_SUB(r, a, b); + SET_ALU_Z(r); + SET_ALU_N(r); + SET_ALU_C_SUB(a, b); + } + + // TODO: Trap on unsigned overflow + m_r[RC] = r; +} + +void am29000_cpu_device::SUBS() +{ + UINT32 a = GET_RA_VAL; + UINT32 b = INST_M_BIT ? I8 : GET_RB_VAL; + UINT32 r = a - b; + + if (!FREEZE_MODE) + { + SET_ALU_V_SUB(r, a, b); + SET_ALU_Z(r); + SET_ALU_N(r); + SET_ALU_C_SUB(a, b); + } + + if ((INT32)(((a) ^ (b)) & ((a) ^ (r))) < 0) + SIGNAL_EXCEPTION(EXCEPTION_OUT_OF_RANGE); + + m_r[RC] = r; +} + +void am29000_cpu_device::SUBU() +{ + UNHANDLED_OP; +} + +void am29000_cpu_device::SUBC() +{ + UNHANDLED_OP; +} + +void am29000_cpu_device::SUBCS() +{ + UNHANDLED_OP; +} + +void am29000_cpu_device::SUBCU() +{ + UNHANDLED_OP; +} + +void am29000_cpu_device::SUBR() +{ + UINT32 a = GET_RA_VAL; + UINT32 b = INST_M_BIT ? I8 : GET_RB_VAL; + UINT32 r = b - a; + + if (!FREEZE_MODE) + { + SET_ALU_V_SUB(r, a, b); + SET_ALU_Z(r); + SET_ALU_N(r); + SET_ALU_C_SUB(a, b); + } + + m_r[RC] = r; +} + +void am29000_cpu_device::SUBRS() +{ + UNHANDLED_OP; +} + +void am29000_cpu_device::SUBRU() +{ + UNHANDLED_OP; +} + +void am29000_cpu_device::SUBRC() +{ + UINT32 a = GET_RA_VAL; + UINT32 b = INST_M_BIT ? I8 : GET_RB_VAL; + UINT32 r = b - a - 1 + GET_CARRY; + + if (!FREEZE_MODE) + { + SET_ALU_V_SUB(r, a, b); + SET_ALU_Z(r); + SET_ALU_N(r); + SET_ALU_C_SUB(a, b); + } + + m_r[RC] = r; +} + +void am29000_cpu_device::SUBRCS() +{ + UNHANDLED_OP; +} + +void am29000_cpu_device::SUBRCU() +{ + UNHANDLED_OP; +} + +void am29000_cpu_device::MULTIPLU() +{ + UNHANDLED_OP; +} + +void am29000_cpu_device::MULTIPLY() +{ + UNHANDLED_OP; +} + +void am29000_cpu_device::MUL() +{ + /* TODO: Zero/Neg flags ? */ + UINT32 a = GET_RA_VAL; + UINT32 b = INST_M_BIT ? I8 : GET_RB_VAL; + UINT32 r; + UINT64 v; + UINT32 sign; + + if (m_q & 1) + { + r = a + b; + sign = (r >> 31) ^ (((INT32)(~((a) ^ (b)) & ((a) ^ (r))) < 0)); + } + else + { + r = b; + sign = b >> 31; + } + + v = ((((UINT64)r << 32) | m_q) >> 1) | ((UINT64)sign << 63); + m_q = v & 0xffffffff; + + m_r[RC] = v >> 32; +} + +void am29000_cpu_device::MULL() +{ + /* TODO: Zero/Neg flags ? */ + UINT32 a = GET_RA_VAL; + UINT32 b = INST_M_BIT ? I8 : GET_RB_VAL; + UINT32 r; + UINT64 v; + UINT32 sign; + + if (m_q & 1) + { + r = b - a; + sign = (r >> 31) ^ ((INT32)(((a) ^ (b)) & ((a) ^ (r))) < 0); + } + else + { + r = b; + sign = b >> 31; + } + + v = ((((UINT64)r << 32) | m_q) >> 1) | ((UINT64)sign << 63); + m_q = v & 0xffffffff; + + m_r[RC] = v >> 32; +} + +void am29000_cpu_device::MULU() +{ + /* TODO: Zero/Neg flags ? */ + UINT32 a = GET_RA_VAL; + UINT32 b = INST_M_BIT ? I8 : GET_RB_VAL; + UINT32 r; + UINT64 v; + UINT32 c; + + if (m_q & 1) + { + r = a + b; + c = (UINT32)(r) < (UINT32)(a); + } + else + { + r = b; + c = 0; + } + + v = ((((UINT64)r << 32) | m_q) >> 1) | ((UINT64)c << 63); + m_q = v & 0xffffffff; + + m_r[RC] = v >> 32; +} + +void am29000_cpu_device::DIVIDE() +{ + m_ipa = RA << IPX_SHIFT; + m_ipb = RB << IPX_SHIFT; + m_ipc = RC << IPX_SHIFT; + + SIGNAL_EXCEPTION(EXCEPTION_DIVIDE); +} + +void am29000_cpu_device::DIVIDU() +{ + UNHANDLED_OP; +} + +void am29000_cpu_device::DIV0() +{ + UINT32 b = INST_M_BIT ? I8: GET_RB_VAL; + UINT64 v; + + if (!FREEZE_MODE) + { + m_alu |= ALU_DF; + SET_ALU_N(b); + } + + v = (((UINT64)b << 32) | m_q) << 1; + + m_q = v & 0xffffffff; + + m_r[RC] = v >> 32; +} + +void am29000_cpu_device::DIV() +{ + UINT32 a = GET_RA_VAL; + UINT32 b = INST_M_BIT ? I8: GET_RB_VAL; + UINT32 c; + UINT32 r; + UINT64 r64; + UINT32 df; + + if (m_alu & ALU_DF) + { + r = a - b; + c = !((UINT32)(a) < (UINT32)(b)); + } + else + { + r = a + b; + c = (UINT32)(r) < (UINT32)(a); + } + + + df = (~(c ^ (m_alu >> ALU_DF_SHIFT) ^ (m_alu >> ALU_N_SHIFT)) & 1); + + if (!FREEZE_MODE) + { + m_alu &= ~ALU_DF; + m_alu |= df << ALU_DF_SHIFT; + SET_ALU_N(r); + } + + r64 = ((((UINT64)r << 32) | m_q) << 1) | df; + m_q = r64 & 0xffffffff; + + m_r[RC] = r64 >> 32; +} + +void am29000_cpu_device::DIVL() +{ + UINT32 a = GET_RA_VAL; + UINT32 b = INST_M_BIT ? I8: GET_RB_VAL; + UINT32 c; + UINT32 r; + UINT32 df; + + if (m_alu & ALU_DF) + { + r = a - b; + c = !((UINT32)(a) < (UINT32)(b)); + } + else + { + r = a + b; + c = (UINT32)(r) < (UINT32)(a); + } + + df = (~(c ^ (m_alu >> ALU_DF_SHIFT) ^ (m_alu >> ALU_N_SHIFT)) & 1); + + if (!FREEZE_MODE) + { + m_alu &= ~ALU_DF; + m_alu |= df << ALU_DF_SHIFT; + SET_ALU_N(r); + } + + m_q = (m_q << 1) | df; + m_r[RC] = r; +} + +void am29000_cpu_device::DIVREM() +{ + UINT32 a = GET_RA_VAL; + UINT32 b = INST_M_BIT ? I8: GET_RB_VAL; + + if (m_alu & ALU_DF) + m_r[RC] = a; + else + m_r[RC] = a + b; +} + + +/*************************************************************************** + COMPARE +***************************************************************************/ + +void am29000_cpu_device::CPEQ() +{ + UINT32 a = GET_RA_VAL; + UINT32 b = INST_M_BIT ? I8: GET_RB_VAL; + UINT32 r = a == b ? BOOLEAN_TRUE : BOOLEAN_FALSE; + + m_r[RC] = r; +} + +void am29000_cpu_device::CPNEQ() +{ + UINT32 a = GET_RA_VAL; + UINT32 b = INST_M_BIT ? I8: GET_RB_VAL; + UINT32 r = a != b ? BOOLEAN_TRUE : BOOLEAN_FALSE; + + m_r[RC] = r; +} + +void am29000_cpu_device::CPLT() +{ + UINT32 a = GET_RA_VAL; + UINT32 b = INST_M_BIT ? I8: GET_RB_VAL; + UINT32 r = (INT32)a < (INT32)b ? BOOLEAN_TRUE : BOOLEAN_FALSE; + + m_r[RC] = r; +} + +void am29000_cpu_device::CPLTU() +{ + UINT32 a = GET_RA_VAL; + UINT32 b = INST_M_BIT ? I8: GET_RB_VAL; + UINT32 r = (UINT32)a < (UINT32)b ? BOOLEAN_TRUE : BOOLEAN_FALSE; + + m_r[RC] = r; +} + +void am29000_cpu_device::CPLE() +{ + UINT32 a = GET_RA_VAL; + UINT32 b = INST_M_BIT ? I8: GET_RB_VAL; + UINT32 r = (INT32)a <= (INT32)b ? BOOLEAN_TRUE : BOOLEAN_FALSE; + + m_r[RC] = r; +} + +void am29000_cpu_device::CPLEU() +{ + UINT32 a = GET_RA_VAL; + UINT32 b = INST_M_BIT ? I8: GET_RB_VAL; + UINT32 r = (UINT32)a <= (UINT32)b ? BOOLEAN_TRUE : BOOLEAN_FALSE; + + m_r[RC] = r; +} + +void am29000_cpu_device::CPGT() +{ + UINT32 a = GET_RA_VAL; + UINT32 b = INST_M_BIT ? I8: GET_RB_VAL; + UINT32 r = (INT32)a > (INT32)b ? BOOLEAN_TRUE : BOOLEAN_FALSE; + + m_r[RC] = r; +} + +void am29000_cpu_device::CPGTU() +{ + UINT32 a = GET_RA_VAL; + UINT32 b = INST_M_BIT ? I8: GET_RB_VAL; + UINT32 r = (UINT32)a > (UINT32)b ? BOOLEAN_TRUE : BOOLEAN_FALSE; + + m_r[RC] = r; +} + +void am29000_cpu_device::CPGE() +{ + UINT32 a = GET_RA_VAL; + UINT32 b = INST_M_BIT ? I8: GET_RB_VAL; + UINT32 r = (INT32)a >= (INT32)b ? BOOLEAN_TRUE : BOOLEAN_FALSE; + + m_r[RC] = r; +} + +void am29000_cpu_device::CPGEU() +{ + UINT32 a = GET_RA_VAL; + UINT32 b = INST_M_BIT ? I8: GET_RB_VAL; + UINT32 r = (UINT32)a >= (UINT32)b ? BOOLEAN_TRUE : BOOLEAN_FALSE; + + m_r[RC] = r; +} + +void am29000_cpu_device::CPBYTE() +{ + UINT32 a = GET_RA_VAL; + UINT32 b = INST_M_BIT ? I8 : GET_RB_VAL; + UINT32 r = + ((a & 0xff000000) == (b & 0xff000000)) || + ((a & 0x00ff0000) == (b & 0x00ff0000)) || + ((a & 0x0000ff00) == (b & 0x0000ff00)) || + ((a & 0x000000ff) == (b & 0x000000ff)) + ? BOOLEAN_TRUE : BOOLEAN_FALSE; + + m_r[RC] = r; +} + +void am29000_cpu_device::ASEQ() +{ + if (USER_MODE && INST_VN < 64) + SIGNAL_EXCEPTION(EXCEPTION_PROTECTION_VIOLATION); + else if (!(GET_RA_VAL == GET_RB_VAL)) + SIGNAL_EXCEPTION(INST_VN); +} + +void am29000_cpu_device::ASNEQ() +{ + if (USER_MODE && INST_VN < 64) + SIGNAL_EXCEPTION(EXCEPTION_PROTECTION_VIOLATION); + else if (!(GET_RA_VAL != GET_RB_VAL)) + SIGNAL_EXCEPTION(INST_VN); +} + +void am29000_cpu_device::ASLT() +{ + if (USER_MODE && INST_VN < 64) + SIGNAL_EXCEPTION(EXCEPTION_PROTECTION_VIOLATION); + else if (!((INT32)GET_RA_VAL < (INT32)GET_RB_VAL)) + SIGNAL_EXCEPTION(INST_VN); +} + +void am29000_cpu_device::ASLTU() +{ + if (USER_MODE && INST_VN < 64) + SIGNAL_EXCEPTION(EXCEPTION_PROTECTION_VIOLATION); + else if (!((UINT32)GET_RA_VAL < (UINT32)GET_RB_VAL)) + SIGNAL_EXCEPTION(INST_VN); +} + +void am29000_cpu_device::ASLE() +{ + if (USER_MODE && INST_VN < 64) + SIGNAL_EXCEPTION(EXCEPTION_PROTECTION_VIOLATION); + else if (!((INT32)GET_RA_VAL <= (INT32)GET_RB_VAL)) + SIGNAL_EXCEPTION(INST_VN); +} + +void am29000_cpu_device::ASLEU() +{ + if (USER_MODE && INST_VN < 64) + SIGNAL_EXCEPTION(EXCEPTION_PROTECTION_VIOLATION); + else if (!((UINT32)GET_RA_VAL <= (UINT32)GET_RB_VAL)) + SIGNAL_EXCEPTION(INST_VN); +} + +void am29000_cpu_device::ASGT() +{ + if (USER_MODE && INST_VN < 64) + SIGNAL_EXCEPTION(EXCEPTION_PROTECTION_VIOLATION); + else if (!((INT32)GET_RA_VAL > (INT32)GET_RB_VAL)) + SIGNAL_EXCEPTION(INST_VN); +} + +void am29000_cpu_device::ASGTU() +{ + if (USER_MODE && INST_VN < 64) + SIGNAL_EXCEPTION(EXCEPTION_PROTECTION_VIOLATION); + else if (!((UINT32)GET_RA_VAL > (UINT32)GET_RB_VAL)) + SIGNAL_EXCEPTION(INST_VN); +} + +void am29000_cpu_device::ASGE() +{ + if (USER_MODE && INST_VN < 64) + SIGNAL_EXCEPTION(EXCEPTION_PROTECTION_VIOLATION); + else if (!((INT32)GET_RA_VAL >= (INT32)GET_RB_VAL)) + SIGNAL_EXCEPTION(INST_VN); +} + +void am29000_cpu_device::ASGEU() +{ + if (USER_MODE && INST_VN < 64) + SIGNAL_EXCEPTION(EXCEPTION_PROTECTION_VIOLATION); + else if (!((UINT32)GET_RA_VAL >= (UINT32)GET_RB_VAL)) + SIGNAL_EXCEPTION(INST_VN); +} + + +/*************************************************************************** + LOGICAL +***************************************************************************/ + +void am29000_cpu_device::AND() +{ + UINT32 a = GET_RA_VAL; + UINT32 b = INST_M_BIT ? I8: GET_RB_VAL; + UINT32 r = a & b; + + if (!FREEZE_MODE) + { + SET_ALU_Z(r); + SET_ALU_N(r); + } + + m_r[RC] = r; +} + +void am29000_cpu_device::ANDN() +{ + UINT32 a = GET_RA_VAL; + UINT32 b = INST_M_BIT ? I8: GET_RB_VAL; + UINT32 r = a & ~b; + + if (!FREEZE_MODE) + { + SET_ALU_Z(r); + SET_ALU_N(r); + } + + m_r[RC] = r; +} + +void am29000_cpu_device::NAND() +{ + UINT32 a = GET_RA_VAL; + UINT32 b = INST_M_BIT ? I8: GET_RB_VAL; + UINT32 r = ~(a & b); + + if (!FREEZE_MODE) + { + SET_ALU_Z(r); + SET_ALU_N(r); + } + + m_r[RC] = r; +} + +void am29000_cpu_device::OR() +{ + UINT32 a = GET_RA_VAL; + UINT32 b = INST_M_BIT ? I8: GET_RB_VAL; + UINT32 r = a | b; + + if (!FREEZE_MODE) + { + SET_ALU_Z(r); + SET_ALU_N(r); + } + + m_r[RC] = r; +} + +void am29000_cpu_device::NOR() +{ + UINT32 a = GET_RA_VAL; + UINT32 b = INST_M_BIT ? I8: GET_RB_VAL; + UINT32 r = ~(a | b); + + if (!FREEZE_MODE) + { + SET_ALU_Z(r); + SET_ALU_N(r); + } + + m_r[RC] = r; +} + +void am29000_cpu_device::XOR() +{ + UINT32 a = GET_RA_VAL; + UINT32 b = INST_M_BIT ? I8: GET_RB_VAL; + UINT32 r = a ^ b; + + if (!FREEZE_MODE) + { + SET_ALU_Z(r); + SET_ALU_N(r); + } + + m_r[RC] = r; +} + +void am29000_cpu_device::XNOR() +{ + UINT32 a = GET_RA_VAL; + UINT32 b = INST_M_BIT ? I8: GET_RB_VAL; + UINT32 r = ~(a ^ b); + + if (!FREEZE_MODE) + { + SET_ALU_Z(r); + SET_ALU_N(r); + } + + m_r[RC] = r; +} + + +/*************************************************************************** + SHIFT +***************************************************************************/ + +void am29000_cpu_device::SLL() +{ + UINT32 a = GET_RA_VAL; + UINT32 b = (INST_M_BIT ? I8: GET_RB_VAL) & 0x1f; + UINT32 r = a << b; + + m_r[RC] = r; +} + +void am29000_cpu_device::SRL() +{ + UINT32 a = GET_RA_VAL; + UINT32 b = (INST_M_BIT ? I8: GET_RB_VAL) & 0x1f; + UINT32 r = a >> b; + + m_r[RC] = r; +} + +void am29000_cpu_device::SRA() +{ + INT32 a = GET_RA_VAL; + UINT32 b = (INST_M_BIT ? I8: GET_RB_VAL) & 0x1f; + UINT32 r = a >> b; + + m_r[RC] = r; +} + +void am29000_cpu_device::EXTRACT() +{ + INT32 a = GET_RA_VAL; + UINT32 b = (INST_M_BIT ? I8: GET_RB_VAL); + UINT64 r; + + r = (((UINT64)a << 32) | b) << GET_ALU_FC; + + m_r[RC] = r >> 32; +} + + +/*************************************************************************** + DATA MOVEMENT +***************************************************************************/ + +void am29000_cpu_device::LOAD() +{ + UINT32 addr = INST_M_BIT ? I8: GET_RB_VAL; + UINT32 r; + + if (INST_UA_BIT) + fatalerror("Am29000: UA bit set on LOAD\n"); + + if (INST_CE_BIT) + { + logerror("Am29000: Attempting a co-processor LOAD!\n"); + r = 0; + } + else + { + if (!INST_PA_BIT && !(m_cps & CPS_PD)) + { + fatalerror("Am29000: Address translation on LOAD\n"); + } + else + { + if (USER_MODE) + { + SIGNAL_EXCEPTION(EXCEPTION_PROTECTION_VIOLATION); + return; + } + + r = m_data->read_dword(addr); + } + } + +// if (opt & 2) +// logerror("Am29000: Half word LOAD\n"); + + if (!FREEZE_MODE) + { + m_chc = ((m_exec_ir << 8) & 0xff) | + CHC_LS | + RA << CHC_TR_SHIFT | + CHC_CV; + + m_cha = addr; + m_chd = r; + + if (!(m_cfg & CFG_DW) && (m_exec_ir & INST_SB_BIT)) + SET_ALU_BP(addr & 3); + } + + m_r[RA] = r; + + if (m_cfg & CFG_DW) + logerror("DW ON A STORE"); +} + +void am29000_cpu_device::LOADL() +{ + UNHANDLED_OP; +} + +void am29000_cpu_device::LOADSET() +{ + UNHANDLED_OP; +} + +void am29000_cpu_device::LOADM() +{ + UINT32 addr = INST_M_BIT ? I8: GET_RB_VAL; + UINT32 r; + + if (INST_UA_BIT) + fatalerror("Am29000: UA bit set on LOAD\n"); + + if (INST_CE_BIT) + { + logerror("Am29000: Attempting a co-processor LOAD!\n"); + r = 0; + } + else + { + if (!INST_PA_BIT && !(m_cps & CPS_PD)) + { + fatalerror("Am29000: Address translation on LOAD\n"); + } + else + { + if (USER_MODE) + { + SIGNAL_EXCEPTION(EXCEPTION_PROTECTION_VIOLATION); + return; + } + + r = m_data->read_dword(addr); + } + } + + if (!FREEZE_MODE) + { + // TODO + m_chc &= (CHC_CR_MASK << CHC_CR_SHIFT); + m_chc |= ((m_exec_ir << 8) & 0xff) | + RA << CHC_TR_SHIFT | + CHC_CV; + + m_cha = addr; + m_chd = r; // ????? + + if (!(m_cfg & CFG_DW) && (m_exec_ir & INST_SB_BIT)) + SET_ALU_BP(addr & 3); + } + + r = RA; + + { + int cnt; + for (cnt = 0; cnt <= GET_CHC_CR; ++cnt) + { + m_r[r] = m_data->read_dword(addr); + +// SET_CHC_CR(cnt - 1); + addr += 4; + + if (++r == 256) + r = 128; + } + } +} + +void am29000_cpu_device::STORE() +{ + UINT32 addr = INST_M_BIT ? I8: GET_RB_VAL; +// UINT32 r; + + if (INST_UA_BIT) + fatalerror("Am29000: UA bit set on LOAD\n"); + + if (INST_CE_BIT) + { + logerror("Am29000: Attempting a co-processor LOAD!\n"); +// r = 0; + } + else + { + if (!INST_PA_BIT && !(m_cps & CPS_PD)) + { + fatalerror("Am29000: Address translation on LOAD\n"); + } + else + { + if (USER_MODE) + { + SIGNAL_EXCEPTION(EXCEPTION_PROTECTION_VIOLATION); + return; + } + + } + } + + m_data->write_dword(addr, m_r[RA]); + + if (!FREEZE_MODE) + { + m_chc = ((m_exec_ir << 8) & 0xff) | + RA << CHC_TR_SHIFT | + CHC_CV; + + m_cha = addr; + + if (!(m_cfg & CFG_DW) && (m_exec_ir & INST_SB_BIT)) + SET_ALU_BP(addr & 3); + } + + if (m_cfg & CFG_DW) + logerror("DW ON A STORE"); +} + +void am29000_cpu_device::STOREL() +{ + UNHANDLED_OP; +} + +void am29000_cpu_device::STOREM() +{ + UINT32 addr = INST_M_BIT ? I8: GET_RB_VAL; + UINT32 r; + + if (INST_UA_BIT) + fatalerror("Am29000: UA bit set on LOAD\n"); + + if (INST_CE_BIT) + { + logerror("Am29000: Attempting a co-processor LOAD!\n"); + r = 0; + } + else + { + if (!INST_PA_BIT && !(m_cps & CPS_PD)) + { + fatalerror("Am29000: Address translation on LOAD\n"); + } + else + { + if (USER_MODE) + { + SIGNAL_EXCEPTION(EXCEPTION_PROTECTION_VIOLATION); + return; + } + + } + } + + if (!FREEZE_MODE) + { + // TODO + m_chc &= (CHC_CR_MASK << CHC_CR_SHIFT); + m_chc |= ((m_exec_ir << 8) & 0xff) | + RA << CHC_TR_SHIFT | + CHC_CV; + + m_cha = addr; + + if (!(m_cfg & CFG_DW) && (m_exec_ir & INST_SB_BIT)) + SET_ALU_BP(addr & 3); + } + + r = RA; + + { + int cnt; + for (cnt = 0; cnt <= GET_CHC_CR; ++cnt) + { + m_data->write_dword(addr, m_r[r]); + +// SET_CHC_CR(cnt - 1); + addr += 4; + + if (++r == 256) + r = 128; + } + } +} + +void am29000_cpu_device::EXBYTE() +{ + UINT32 a = GET_RA_VAL; + UINT32 b = INST_M_BIT ? I8: GET_RB_VAL; + UINT32 bp = GET_ALU_BP; + UINT8 srcbyte; + UINT32 r; + + if (m_cfg & CFG_BO) + srcbyte = a >> 8 * bp; + else + srcbyte = a >> (8 * (3 - bp)); + + r = (b & 0xffffff00) | srcbyte; + + m_r[RC] = r; +} + +void am29000_cpu_device::EXHW() +{ + UINT32 a = GET_RA_VAL; + UINT32 b = INST_M_BIT ? I8: GET_RB_VAL; + UINT32 wp = ((m_alu >> ALU_BP_SHIFT) & ALU_BP_MASK) >> 1; + UINT16 srcword; + UINT32 r; + + if (m_cfg & CFG_BO) + srcword = a >> 16 * wp; + else + srcword = a >> (16 * (1 - wp)); + + r = (b & 0xffff0000) | srcword; + + m_r[RC] = r; +} + +void am29000_cpu_device::EXHWS() +{ + UINT32 a = GET_RA_VAL; + UINT32 wp = ((m_alu >> ALU_BP_SHIFT) & ALU_BP_MASK) >> 1; + UINT16 srcword; + UINT32 r; + + if (m_cfg & CFG_BO) + srcword = a >> 16 * wp; + else + srcword = a >> (16 * (1 - wp)); + + r = (INT32)(INT16)srcword; + + m_r[RC] = r; +} + +void am29000_cpu_device::INBYTE() +{ + UINT32 a = GET_RA_VAL; + UINT32 b = INST_M_BIT ? I8: GET_RB_VAL; + UINT32 bp = GET_ALU_BP; + UINT8 shift = (m_cfg & CFG_BO) ? 8 * bp : (8 * (3 - bp)); + UINT32 r; + + r = (a & ~(0xff << shift)) | ((b & 0xff) << shift); + + m_r[RC] = r; +} + +void am29000_cpu_device::INHW() +{ + UINT32 a = GET_RA_VAL; + UINT32 b = INST_M_BIT ? I8: GET_RB_VAL; + UINT32 wp = ((m_alu >> ALU_BP_SHIFT) & ALU_BP_MASK) >> 1; + UINT32 shift = (m_cfg & CFG_BO) ? 16 * wp : (16 * (1 - wp)); + UINT32 r; + + r = (a & ~(0xffff << shift)) | ((b & 0xffff) << shift); + + m_r[RC] = r; +} + +void am29000_cpu_device::MFSR() +{ + m_r[RC] = read_spr(INST_SA); +} + +void am29000_cpu_device::MFTLB() +{ + m_r[RC] = m_tlb[GET_RA_VAL & 0x7f]; +} + +void am29000_cpu_device::MTSR() +{ + write_spr(INST_SA, GET_RB_VAL); +} + +void am29000_cpu_device::MTSRIM() +{ + write_spr(INST_SA, I16_ZEX); +} + +void am29000_cpu_device::MTTLB() +{ + m_tlb[GET_RA_VAL & 0x7f] = GET_RB_VAL; +} + + +/*************************************************************************** + CONSTANT +***************************************************************************/ + +void am29000_cpu_device::CONST() +{ + m_r[RA] = I16_ZEX; +} + +void am29000_cpu_device::CONSTH() +{ + m_r[RA] = (I16 << 16) | GET_RA_VAL; +} + +void am29000_cpu_device::CONSTN() +{ + m_r[RA] = I16_OEX; +} + + +/*************************************************************************** + BRANCH INSTRUCTIONS +***************************************************************************/ + +void am29000_cpu_device::CALL() +{ + UINT32 ret = m_next_pc; + + if (INST_M_BIT) + m_next_pc = JMP_ZEX; + else + m_next_pc = m_exec_pc + JMP_SEX; + + m_r[RA] = ret; +m_next_pl_flags |= PFLAG_JUMP; +} + +void am29000_cpu_device::CALLI() +{ + UINT32 ret = m_next_pc; + m_next_pc = GET_RB_VAL; + m_r[RA] = ret; + m_next_pl_flags |= PFLAG_JUMP; +} + +void am29000_cpu_device::JMP() +{ + if (INST_M_BIT) + m_next_pc = JMP_ZEX; + else + m_next_pc = m_exec_pc + JMP_SEX; + + m_next_pl_flags |= PFLAG_JUMP; +} + +void am29000_cpu_device::JMPI() +{ + m_next_pc = GET_RB_VAL; + + m_next_pl_flags |= PFLAG_JUMP; +} + +void am29000_cpu_device::JMPT() +{ + if ((GET_RA_VAL & BOOLEAN_MASK) == BOOLEAN_TRUE) + { + if (INST_M_BIT) + m_next_pc = JMP_ZEX; + else + m_next_pc = m_exec_pc + JMP_SEX; + + m_next_pl_flags |= PFLAG_JUMP; + } +} + +void am29000_cpu_device::JMPTI() +{ + if ((GET_RA_VAL & BOOLEAN_MASK) == BOOLEAN_TRUE) + { + m_next_pc = GET_RB_VAL; + m_next_pl_flags |= PFLAG_JUMP; + } +} + +void am29000_cpu_device::JMPF() +{ + if ((GET_RA_VAL & BOOLEAN_MASK) == BOOLEAN_FALSE) + { + if (INST_M_BIT) + m_next_pc = JMP_ZEX; + else + m_next_pc = m_exec_pc + JMP_SEX; + + m_next_pl_flags |= PFLAG_JUMP; + } +} + +void am29000_cpu_device::JMPFI() +{ + if ((GET_RA_VAL & BOOLEAN_MASK) == BOOLEAN_FALSE) + { + m_next_pc = GET_RB_VAL; + m_next_pl_flags |= PFLAG_JUMP; + } +} + +void am29000_cpu_device::JMPFDEC() +{ + UINT32 a = GET_RA_VAL; + + if ((a & BOOLEAN_MASK) == BOOLEAN_FALSE) + { + if (INST_M_BIT) + m_next_pc = JMP_ZEX; + else + m_next_pc = m_exec_pc + JMP_SEX; + + m_next_pl_flags |= PFLAG_JUMP; + } + + m_r[RA] = a - 1; +} + + +/*************************************************************************** + MISCELLANEOUS INSTRUCTIONS +***************************************************************************/ + +void am29000_cpu_device::CLZ() +{ + UINT32 b = INST_M_BIT ? I8: GET_RB_VAL; + + m_r[RC] = count_leading_zeros(b); +} + +void am29000_cpu_device::SETIP() +{ + m_ipa = RA << IPX_SHIFT; + m_ipb = RB << IPX_SHIFT; + m_ipc = RC << IPX_SHIFT; +} + +void am29000_cpu_device::EMULATE() +{ + UNHANDLED_OP; +} + +void am29000_cpu_device::INV() +{ + /* Nothing to do yet */ +} + +void am29000_cpu_device::IRET() +{ + m_iret_pc = m_pc0; + m_next_pc = m_pc1; + m_cps = m_ops; + m_next_pl_flags = PFLAG_IRET; +} + +void am29000_cpu_device::IRETINV() +{ + UNHANDLED_OP; +} + +void am29000_cpu_device::HALT() +{ + UNHANDLED_OP; +} + + +void am29000_cpu_device::ILLEGAL() +{ + fatalerror("Am29000: Executed illegal instruction - this should never happen! %x (%x)\n", m_pc2, m_exec_pc); +} + + + +/*************************************************************************** + UNHANDLED +***************************************************************************/ + +void am29000_cpu_device::CONVERT() +{ + UNHANDLED_OP; +} + +void am29000_cpu_device::SQRT() +{ + UNHANDLED_OP; +} + +void am29000_cpu_device::CLASS() +{ + UNHANDLED_OP; +} + +void am29000_cpu_device::MULTM() +{ + UNHANDLED_OP; +} + +void am29000_cpu_device::MULTMU() +{ + UNHANDLED_OP; +} + + +const am29000_cpu_device::op_info am29000_cpu_device::op_table[256] = +{ + { &am29000_cpu_device::ILLEGAL, IFLAG_ILLEGAL }, + { &am29000_cpu_device::CONSTN, IFLAG_RA_PRESENT }, + { &am29000_cpu_device::CONSTH, IFLAG_RA_PRESENT }, + { &am29000_cpu_device::CONST, IFLAG_RA_PRESENT }, + { &am29000_cpu_device::MTSRIM, 0 }, + { &am29000_cpu_device::ILLEGAL, IFLAG_ILLEGAL }, + { &am29000_cpu_device::LOADL, 0 }, + { &am29000_cpu_device::LOADL, 0 }, + { &am29000_cpu_device::CLZ, IFLAG_RC_PRESENT | IFLAG_RB_PRESENT }, + { &am29000_cpu_device::CLZ, IFLAG_RC_PRESENT }, + { &am29000_cpu_device::EXBYTE, IFLAG_RC_PRESENT | IFLAG_RB_PRESENT | IFLAG_RA_PRESENT }, + { &am29000_cpu_device::EXBYTE, IFLAG_RC_PRESENT | IFLAG_RA_PRESENT }, + { &am29000_cpu_device::INBYTE, IFLAG_RC_PRESENT | IFLAG_RB_PRESENT | IFLAG_RA_PRESENT }, + { &am29000_cpu_device::INBYTE, IFLAG_RC_PRESENT | IFLAG_RA_PRESENT }, + { &am29000_cpu_device::STOREL, 0 }, + { &am29000_cpu_device::STOREL, 0 }, + { &am29000_cpu_device::ADDS, 0 }, + { &am29000_cpu_device::ADDS, 0 }, + { &am29000_cpu_device::ADDU, 0 }, + { &am29000_cpu_device::ADDU, 0 }, + { &am29000_cpu_device::ADD, IFLAG_RC_PRESENT | IFLAG_RB_PRESENT | IFLAG_RA_PRESENT }, + { &am29000_cpu_device::ADD, IFLAG_RC_PRESENT | IFLAG_RA_PRESENT }, + { &am29000_cpu_device::LOAD, IFLAG_RA_PRESENT | IFLAG_RB_PRESENT }, + { &am29000_cpu_device::LOAD, IFLAG_RA_PRESENT }, + { &am29000_cpu_device::ADDCS, IFLAG_RC_PRESENT | IFLAG_RB_PRESENT | IFLAG_RA_PRESENT }, + { &am29000_cpu_device::ADDCS, IFLAG_RC_PRESENT | IFLAG_RA_PRESENT }, + { &am29000_cpu_device::ADDCU, 0 }, + { &am29000_cpu_device::ADDCU, 0 }, + { &am29000_cpu_device::ADDC, 0 }, + { &am29000_cpu_device::ADDC, 0 }, + { &am29000_cpu_device::STORE, IFLAG_RA_PRESENT | IFLAG_RB_PRESENT }, + { &am29000_cpu_device::STORE, IFLAG_RA_PRESENT }, + { &am29000_cpu_device::SUBS, IFLAG_RC_PRESENT | IFLAG_RB_PRESENT | IFLAG_RA_PRESENT }, + { &am29000_cpu_device::SUBS, IFLAG_RC_PRESENT | IFLAG_RA_PRESENT }, + { &am29000_cpu_device::SUBU, 0 }, + { &am29000_cpu_device::SUBU, 0 }, + { &am29000_cpu_device::SUB, IFLAG_RC_PRESENT | IFLAG_RB_PRESENT | IFLAG_RA_PRESENT }, + { &am29000_cpu_device::SUB, IFLAG_RC_PRESENT | IFLAG_RA_PRESENT }, + { &am29000_cpu_device::LOADSET, 0 }, + { &am29000_cpu_device::LOADSET, 0 }, + { &am29000_cpu_device::SUBCS, 0 }, + { &am29000_cpu_device::SUBCS, 0 }, + { &am29000_cpu_device::SUBCU, 0 }, + { &am29000_cpu_device::SUBCU, 0 }, + { &am29000_cpu_device::SUBC, 0 }, + { &am29000_cpu_device::SUBC, 0 }, + { &am29000_cpu_device::CPBYTE, IFLAG_RC_PRESENT | IFLAG_RB_PRESENT | IFLAG_RA_PRESENT }, + { &am29000_cpu_device::CPBYTE, IFLAG_RC_PRESENT | IFLAG_RA_PRESENT }, + { &am29000_cpu_device::SUBRS, 0 }, + { &am29000_cpu_device::SUBRS, 0 }, + { &am29000_cpu_device::SUBRU, 0 }, + { &am29000_cpu_device::SUBRU, 0 }, + { &am29000_cpu_device::SUBR, IFLAG_RC_PRESENT | IFLAG_RB_PRESENT | IFLAG_RA_PRESENT }, + { &am29000_cpu_device::SUBR, IFLAG_RC_PRESENT | IFLAG_RA_PRESENT }, + { &am29000_cpu_device::LOADM, IFLAG_RA_PRESENT | IFLAG_RB_PRESENT }, + { &am29000_cpu_device::LOADM, IFLAG_RA_PRESENT }, + { &am29000_cpu_device::SUBRCS, 0 }, + { &am29000_cpu_device::SUBRCS, 0 }, + { &am29000_cpu_device::SUBRCU, 0 }, + { &am29000_cpu_device::SUBRCU, 0 }, + { &am29000_cpu_device::SUBRC, IFLAG_RC_PRESENT | IFLAG_RB_PRESENT | IFLAG_RA_PRESENT }, + { &am29000_cpu_device::SUBRC, IFLAG_RC_PRESENT | IFLAG_RA_PRESENT }, + { &am29000_cpu_device::STOREM, IFLAG_RA_PRESENT | IFLAG_RB_PRESENT }, + { &am29000_cpu_device::STOREM, IFLAG_RA_PRESENT }, + { &am29000_cpu_device::CPLT, IFLAG_RC_PRESENT | IFLAG_RB_PRESENT | IFLAG_RA_PRESENT }, + { &am29000_cpu_device::CPLT, IFLAG_RC_PRESENT | IFLAG_RA_PRESENT }, + { &am29000_cpu_device::CPLTU, IFLAG_RC_PRESENT | IFLAG_RB_PRESENT | IFLAG_RA_PRESENT }, + { &am29000_cpu_device::CPLTU, IFLAG_RC_PRESENT | IFLAG_RA_PRESENT }, + { &am29000_cpu_device::CPLE, IFLAG_RC_PRESENT | IFLAG_RB_PRESENT | IFLAG_RA_PRESENT }, + { &am29000_cpu_device::CPLE, IFLAG_RC_PRESENT | IFLAG_RA_PRESENT }, + { &am29000_cpu_device::CPLEU, IFLAG_RC_PRESENT | IFLAG_RB_PRESENT | IFLAG_RA_PRESENT }, + { &am29000_cpu_device::CPLEU, IFLAG_RC_PRESENT | IFLAG_RA_PRESENT }, + { &am29000_cpu_device::CPGT, IFLAG_RC_PRESENT | IFLAG_RB_PRESENT | IFLAG_RA_PRESENT }, + { &am29000_cpu_device::CPGT, IFLAG_RC_PRESENT | IFLAG_RA_PRESENT }, + { &am29000_cpu_device::CPGTU, IFLAG_RC_PRESENT | IFLAG_RB_PRESENT | IFLAG_RA_PRESENT }, + { &am29000_cpu_device::CPGTU, IFLAG_RC_PRESENT | IFLAG_RA_PRESENT }, + { &am29000_cpu_device::CPGE, IFLAG_RC_PRESENT | IFLAG_RB_PRESENT | IFLAG_RA_PRESENT }, + { &am29000_cpu_device::CPGE, IFLAG_RC_PRESENT | IFLAG_RA_PRESENT }, + { &am29000_cpu_device::CPGEU, IFLAG_RC_PRESENT | IFLAG_RB_PRESENT | IFLAG_RA_PRESENT }, + { &am29000_cpu_device::CPGEU, IFLAG_RC_PRESENT | IFLAG_RA_PRESENT }, + { &am29000_cpu_device::ASLT, IFLAG_RA_PRESENT | IFLAG_RB_PRESENT }, + { &am29000_cpu_device::ASLT, IFLAG_RA_PRESENT }, + { &am29000_cpu_device::ASLTU, IFLAG_RA_PRESENT | IFLAG_RB_PRESENT }, + { &am29000_cpu_device::ASLTU, IFLAG_RA_PRESENT }, + { &am29000_cpu_device::ASLE, IFLAG_RA_PRESENT | IFLAG_RB_PRESENT }, + { &am29000_cpu_device::ASLE, IFLAG_RA_PRESENT }, + { &am29000_cpu_device::ASLEU, IFLAG_RA_PRESENT | IFLAG_RB_PRESENT }, + { &am29000_cpu_device::ASLEU, IFLAG_RA_PRESENT }, + { &am29000_cpu_device::ASGT, IFLAG_RA_PRESENT | IFLAG_RB_PRESENT }, + { &am29000_cpu_device::ASGT, IFLAG_RA_PRESENT }, + { &am29000_cpu_device::ASGTU, IFLAG_RA_PRESENT | IFLAG_RB_PRESENT }, + { &am29000_cpu_device::ASGTU, IFLAG_RA_PRESENT }, + { &am29000_cpu_device::ASGE, IFLAG_RA_PRESENT | IFLAG_RB_PRESENT }, + { &am29000_cpu_device::ASGE, IFLAG_RA_PRESENT }, + { &am29000_cpu_device::ASGEU, IFLAG_RA_PRESENT | IFLAG_RB_PRESENT }, + { &am29000_cpu_device::ASGEU, IFLAG_RA_PRESENT }, + { &am29000_cpu_device::CPEQ, IFLAG_RC_PRESENT | IFLAG_RB_PRESENT | IFLAG_RA_PRESENT }, + { &am29000_cpu_device::CPEQ, IFLAG_RC_PRESENT | IFLAG_RA_PRESENT }, + { &am29000_cpu_device::CPNEQ, IFLAG_RC_PRESENT | IFLAG_RB_PRESENT | IFLAG_RA_PRESENT }, + { &am29000_cpu_device::CPNEQ, IFLAG_RC_PRESENT | IFLAG_RA_PRESENT }, + { &am29000_cpu_device::MUL, IFLAG_RC_PRESENT | IFLAG_RA_PRESENT | IFLAG_RB_PRESENT }, + { &am29000_cpu_device::MUL, IFLAG_RC_PRESENT | IFLAG_RA_PRESENT }, + { &am29000_cpu_device::MULL, IFLAG_RC_PRESENT | IFLAG_RA_PRESENT | IFLAG_RB_PRESENT }, + { &am29000_cpu_device::MULL, IFLAG_RC_PRESENT | IFLAG_RA_PRESENT }, + { &am29000_cpu_device::DIV0, IFLAG_RC_PRESENT | IFLAG_RB_PRESENT }, + { &am29000_cpu_device::DIV0, IFLAG_RC_PRESENT }, + { &am29000_cpu_device::DIV, IFLAG_RC_PRESENT | IFLAG_RA_PRESENT | IFLAG_RB_PRESENT }, + { &am29000_cpu_device::DIV, IFLAG_RC_PRESENT | IFLAG_RA_PRESENT }, + { &am29000_cpu_device::DIVL, IFLAG_RC_PRESENT | IFLAG_RA_PRESENT | IFLAG_RB_PRESENT }, + { &am29000_cpu_device::DIVL, IFLAG_RC_PRESENT | IFLAG_RA_PRESENT }, + { &am29000_cpu_device::DIVREM, IFLAG_RC_PRESENT | IFLAG_RA_PRESENT | IFLAG_RB_PRESENT }, + { &am29000_cpu_device::DIVREM, IFLAG_RC_PRESENT | IFLAG_RA_PRESENT }, + { &am29000_cpu_device::ASEQ, IFLAG_RA_PRESENT | IFLAG_RB_PRESENT }, + { &am29000_cpu_device::ASEQ, IFLAG_RA_PRESENT }, + { &am29000_cpu_device::ASNEQ, IFLAG_RA_PRESENT | IFLAG_RB_PRESENT }, + { &am29000_cpu_device::ASNEQ, IFLAG_RA_PRESENT }, + { &am29000_cpu_device::MULU, IFLAG_RC_PRESENT | IFLAG_RA_PRESENT | IFLAG_RB_PRESENT }, + { &am29000_cpu_device::MULU, IFLAG_RC_PRESENT | IFLAG_RA_PRESENT }, + { &am29000_cpu_device::ILLEGAL, IFLAG_ILLEGAL }, + { &am29000_cpu_device::ILLEGAL, IFLAG_ILLEGAL }, + { &am29000_cpu_device::INHW, IFLAG_RC_PRESENT | IFLAG_RB_PRESENT | IFLAG_RA_PRESENT }, + { &am29000_cpu_device::INHW, IFLAG_RC_PRESENT | IFLAG_RA_PRESENT }, + { &am29000_cpu_device::EXTRACT, IFLAG_RC_PRESENT | IFLAG_RB_PRESENT | IFLAG_RA_PRESENT }, + { &am29000_cpu_device::EXTRACT, IFLAG_RC_PRESENT | IFLAG_RA_PRESENT }, + { &am29000_cpu_device::EXHW, IFLAG_RC_PRESENT | IFLAG_RB_PRESENT | IFLAG_RA_PRESENT }, + { &am29000_cpu_device::EXHW, IFLAG_RC_PRESENT | IFLAG_RA_PRESENT }, + { &am29000_cpu_device::EXHWS, IFLAG_RC_PRESENT | IFLAG_RA_PRESENT }, + { &am29000_cpu_device::ILLEGAL, IFLAG_ILLEGAL }, + { &am29000_cpu_device::SLL, IFLAG_RC_PRESENT | IFLAG_RB_PRESENT | IFLAG_RA_PRESENT }, + { &am29000_cpu_device::SLL, IFLAG_RC_PRESENT | IFLAG_RA_PRESENT }, + { &am29000_cpu_device::SRL, IFLAG_RC_PRESENT | IFLAG_RB_PRESENT | IFLAG_RA_PRESENT }, + { &am29000_cpu_device::SRL, IFLAG_RC_PRESENT | IFLAG_RA_PRESENT }, + { &am29000_cpu_device::ILLEGAL, IFLAG_ILLEGAL }, + { &am29000_cpu_device::ILLEGAL, IFLAG_ILLEGAL }, + { &am29000_cpu_device::SRA, IFLAG_RC_PRESENT | IFLAG_RB_PRESENT | IFLAG_RA_PRESENT }, + { &am29000_cpu_device::SRA, IFLAG_RC_PRESENT | IFLAG_RA_PRESENT }, + { &am29000_cpu_device::IRET, IFLAG_SUPERVISOR_ONLY }, + { &am29000_cpu_device::HALT, IFLAG_SUPERVISOR_ONLY }, + { &am29000_cpu_device::ILLEGAL, IFLAG_ILLEGAL }, + { &am29000_cpu_device::ILLEGAL, IFLAG_ILLEGAL }, + { &am29000_cpu_device::IRETINV, IFLAG_SUPERVISOR_ONLY }, + { &am29000_cpu_device::ILLEGAL, IFLAG_ILLEGAL }, + { &am29000_cpu_device::ILLEGAL, IFLAG_ILLEGAL }, + { &am29000_cpu_device::ILLEGAL, IFLAG_ILLEGAL }, + { &am29000_cpu_device::AND, IFLAG_RC_PRESENT | IFLAG_RB_PRESENT | IFLAG_RA_PRESENT }, + { &am29000_cpu_device::AND, IFLAG_RC_PRESENT | IFLAG_RA_PRESENT }, + { &am29000_cpu_device::OR, IFLAG_RC_PRESENT | IFLAG_RB_PRESENT | IFLAG_RA_PRESENT }, + { &am29000_cpu_device::OR, IFLAG_RC_PRESENT | IFLAG_RA_PRESENT }, + { &am29000_cpu_device::XOR, IFLAG_RC_PRESENT | IFLAG_RB_PRESENT | IFLAG_RA_PRESENT }, + { &am29000_cpu_device::XOR, IFLAG_RC_PRESENT | IFLAG_RA_PRESENT }, + { &am29000_cpu_device::XNOR, IFLAG_RC_PRESENT | IFLAG_RB_PRESENT | IFLAG_RA_PRESENT }, + { &am29000_cpu_device::XNOR, IFLAG_RC_PRESENT | IFLAG_RA_PRESENT }, + { &am29000_cpu_device::NOR, IFLAG_RC_PRESENT | IFLAG_RB_PRESENT | IFLAG_RA_PRESENT }, + { &am29000_cpu_device::NOR, IFLAG_RC_PRESENT | IFLAG_RA_PRESENT }, + { &am29000_cpu_device::NAND, IFLAG_RC_PRESENT | IFLAG_RB_PRESENT | IFLAG_RA_PRESENT }, + { &am29000_cpu_device::NAND, IFLAG_RC_PRESENT | IFLAG_RA_PRESENT }, + { &am29000_cpu_device::ANDN, IFLAG_RC_PRESENT | IFLAG_RB_PRESENT | IFLAG_RA_PRESENT }, + { &am29000_cpu_device::ANDN, IFLAG_RC_PRESENT | IFLAG_RA_PRESENT }, + { &am29000_cpu_device::SETIP, IFLAG_RA_PRESENT | IFLAG_RB_PRESENT | IFLAG_RC_PRESENT }, + { &am29000_cpu_device::INV, IFLAG_SUPERVISOR_ONLY }, + { &am29000_cpu_device::JMP, 0 }, + { &am29000_cpu_device::JMP, 0 }, + { &am29000_cpu_device::ILLEGAL, IFLAG_ILLEGAL }, + { &am29000_cpu_device::ILLEGAL, IFLAG_ILLEGAL }, + { &am29000_cpu_device::JMPF, IFLAG_RA_PRESENT }, + { &am29000_cpu_device::JMPF, IFLAG_RA_PRESENT }, + { &am29000_cpu_device::ILLEGAL, IFLAG_ILLEGAL }, + { &am29000_cpu_device::ILLEGAL, IFLAG_ILLEGAL }, + { &am29000_cpu_device::CALL, IFLAG_RA_PRESENT }, + { &am29000_cpu_device::CALL, IFLAG_RA_PRESENT }, + { &am29000_cpu_device::ILLEGAL, IFLAG_ILLEGAL }, + { &am29000_cpu_device::ILLEGAL, IFLAG_ILLEGAL }, + { &am29000_cpu_device::JMPT, IFLAG_RA_PRESENT }, + { &am29000_cpu_device::JMPT, IFLAG_RA_PRESENT }, + { &am29000_cpu_device::ILLEGAL, IFLAG_ILLEGAL }, + { &am29000_cpu_device::ILLEGAL, IFLAG_ILLEGAL }, + { &am29000_cpu_device::ILLEGAL, IFLAG_ILLEGAL }, + { &am29000_cpu_device::ILLEGAL, IFLAG_ILLEGAL }, + { &am29000_cpu_device::ILLEGAL, IFLAG_ILLEGAL }, + { &am29000_cpu_device::ILLEGAL, IFLAG_ILLEGAL }, + { &am29000_cpu_device::JMPFDEC, IFLAG_RA_PRESENT }, + { &am29000_cpu_device::JMPFDEC, IFLAG_RA_PRESENT }, + { &am29000_cpu_device::MFTLB, IFLAG_SUPERVISOR_ONLY | IFLAG_RC_PRESENT | IFLAG_RA_PRESENT }, + { &am29000_cpu_device::ILLEGAL, IFLAG_ILLEGAL }, + { &am29000_cpu_device::ILLEGAL, IFLAG_ILLEGAL }, + { &am29000_cpu_device::ILLEGAL, IFLAG_ILLEGAL }, + { &am29000_cpu_device::ILLEGAL, IFLAG_ILLEGAL }, + { &am29000_cpu_device::ILLEGAL, IFLAG_ILLEGAL }, + { &am29000_cpu_device::ILLEGAL, IFLAG_ILLEGAL }, + { &am29000_cpu_device::ILLEGAL, IFLAG_ILLEGAL }, + { &am29000_cpu_device::MTTLB, IFLAG_SUPERVISOR_ONLY | IFLAG_RA_PRESENT | IFLAG_RB_PRESENT }, + { &am29000_cpu_device::ILLEGAL, IFLAG_ILLEGAL }, + { &am29000_cpu_device::JMPI, IFLAG_RB_PRESENT }, + { &am29000_cpu_device::ILLEGAL, IFLAG_ILLEGAL }, + { &am29000_cpu_device::ILLEGAL, IFLAG_ILLEGAL }, + { &am29000_cpu_device::ILLEGAL, IFLAG_ILLEGAL }, + { &am29000_cpu_device::JMPFI, IFLAG_RA_PRESENT | IFLAG_RB_PRESENT }, + { &am29000_cpu_device::ILLEGAL, IFLAG_ILLEGAL }, + { &am29000_cpu_device::MFSR, IFLAG_RC_PRESENT }, + { &am29000_cpu_device::ILLEGAL, IFLAG_ILLEGAL }, + { &am29000_cpu_device::CALLI, IFLAG_RA_PRESENT | IFLAG_RB_PRESENT }, + { &am29000_cpu_device::ILLEGAL, IFLAG_ILLEGAL }, + { &am29000_cpu_device::ILLEGAL, IFLAG_ILLEGAL }, + { &am29000_cpu_device::ILLEGAL, IFLAG_ILLEGAL }, + { &am29000_cpu_device::JMPTI, IFLAG_RA_PRESENT | IFLAG_RB_PRESENT }, + { &am29000_cpu_device::ILLEGAL, IFLAG_ILLEGAL }, + { &am29000_cpu_device::MTSR, IFLAG_RB_PRESENT }, + { &am29000_cpu_device::ILLEGAL, IFLAG_ILLEGAL }, + { &am29000_cpu_device::ILLEGAL, IFLAG_ILLEGAL }, + { &am29000_cpu_device::ILLEGAL, IFLAG_ILLEGAL }, + { &am29000_cpu_device::ILLEGAL, IFLAG_ILLEGAL }, + { &am29000_cpu_device::ILLEGAL, IFLAG_ILLEGAL }, + { &am29000_cpu_device::ILLEGAL, IFLAG_ILLEGAL }, + { &am29000_cpu_device::ILLEGAL, IFLAG_ILLEGAL }, + { &am29000_cpu_device::ILLEGAL, IFLAG_ILLEGAL }, + { &am29000_cpu_device::EMULATE, 0 }, + { &am29000_cpu_device::ILLEGAL, IFLAG_ILLEGAL }, + { &am29000_cpu_device::ILLEGAL, IFLAG_ILLEGAL }, + { &am29000_cpu_device::ILLEGAL, IFLAG_ILLEGAL }, + { &am29000_cpu_device::ILLEGAL, IFLAG_ILLEGAL }, + { &am29000_cpu_device::ILLEGAL, IFLAG_ILLEGAL }, + { &am29000_cpu_device::ILLEGAL, IFLAG_ILLEGAL }, + { &am29000_cpu_device::MULTM, 0 }, + { &am29000_cpu_device::MULTMU, 0 }, + { &am29000_cpu_device::MULTIPLY, 0 }, + { &am29000_cpu_device::DIVIDE, 0 }, + { &am29000_cpu_device::MULTIPLU, 0 }, + { &am29000_cpu_device::DIVIDU, 0 }, + { &am29000_cpu_device::CONVERT, 0 }, + { &am29000_cpu_device::SQRT, 0 }, + { &am29000_cpu_device::CLASS, 0 }, + { &am29000_cpu_device::ILLEGAL, IFLAG_ILLEGAL }, + { &am29000_cpu_device::ILLEGAL, IFLAG_ILLEGAL }, + { &am29000_cpu_device::ILLEGAL, IFLAG_ILLEGAL }, + // FEQ + // DEQ + // TODO! etc +}; diff --git a/src/devices/cpu/amis2000/amis2000.c b/src/devices/cpu/amis2000/amis2000.c new file mode 100644 index 00000000000..3082b09f14b --- /dev/null +++ b/src/devices/cpu/amis2000/amis2000.c @@ -0,0 +1,324 @@ +// license:BSD-3-Clause +// copyright-holders:hap +/* + + American Microsystems, Inc.(AMI) S2000-family 4-bit MCU cores, introduced late 1970s + Overall functionality is similar to (and probably derived from) NEC uCOM-4. + + References: + - AMI MOS Products Catalog 1979/1980 + - AMI S2000 Programming Manual (rev. 2) + + TODO: + - unemulated opcodes (need more testing material) + - is K/I input handling correct? + - support external program map + - add 50/60hz timer + - add S2200/S2400 + +*/ + +#include "amis2000.h" +#include "debugger.h" + + +// S2000 is the most basic one, 64 nibbles internal RAM and 1KB internal ROM +// S2150 increased RAM to 80 nibbles and ROM to 1.5KB +// high-voltage output versions of these chips (S2000A and S2150A) are identical overall +const device_type AMI_S2000 = &device_creator; +const device_type AMI_S2150 = &device_creator; + +// S2152 is an extension to S2150, removing the K pins and adding a better timer +const device_type AMI_S2152 = &device_creator; + + +// internal memory maps +static ADDRESS_MAP_START(program_1k, AS_PROGRAM, 8, amis2000_base_device) + AM_RANGE(0x0000, 0x03ff) AM_ROM +ADDRESS_MAP_END + +static ADDRESS_MAP_START(program_1_5k, AS_PROGRAM, 8, amis2000_base_device) + AM_RANGE(0x0000, 0x03ff) AM_ROM + AM_RANGE(0x0400, 0x05ff) AM_NOP // 0x00 + AM_RANGE(0x0600, 0x07ff) AM_ROM +ADDRESS_MAP_END + + +static ADDRESS_MAP_START(data_64x4, AS_DATA, 8, amis2000_base_device) + AM_RANGE(0x00, 0x3f) AM_RAM +ADDRESS_MAP_END + +static ADDRESS_MAP_START(data_80x4, AS_DATA, 8, amis2000_base_device) + AM_RANGE(0x00, 0x3f) AM_RAM + AM_RANGE(0x40, 0x4f) AM_RAM +ADDRESS_MAP_END + + +// device definitions +amis2000_cpu_device::amis2000_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : amis2000_base_device(mconfig, AMI_S2000, "AMI S2000", tag, owner, clock, 2, 10, 3, 13, ADDRESS_MAP_NAME(program_1k), 6, ADDRESS_MAP_NAME(data_64x4), "amis2000", __FILE__) +{ } + +amis2150_cpu_device::amis2150_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : amis2000_base_device(mconfig, AMI_S2150, "AMI S2150", tag, owner, clock, 3, 11, 3, 13, ADDRESS_MAP_NAME(program_1_5k), 7, ADDRESS_MAP_NAME(data_80x4), "amis2150", __FILE__) +{ } + +amis2152_cpu_device::amis2152_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : amis2000_base_device(mconfig, AMI_S2152, "AMI S2152", tag, owner, clock, 3, 11, 3, 13, ADDRESS_MAP_NAME(program_1_5k), 7, ADDRESS_MAP_NAME(data_80x4), "amis2152", __FILE__) +{ } + + + +// disasm +void amis2000_base_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + switch (entry.index()) + { + case STATE_GENFLAGS: + strprintf(str, "%c%c%c%c%c%c", + m_f & 0x20 ? '6':'.', + m_f & 0x10 ? '5':'.', + m_f & 0x08 ? '4':'.', + m_f & 0x04 ? '3':'.', + m_f & 0x02 ? '2':'.', + m_f & 0x01 ? '1':'.' + ); + break; + + default: break; + } +} + +offs_t amis2000_base_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE(amis2000); + return CPU_DISASSEMBLE_NAME(amis2000)(this, buffer, pc, oprom, opram, options); +} + + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +enum +{ + S2000_PC=1, S2000_BL, S2000_BU, + S2000_ACC, S2000_E, S2000_CY +}; + +void amis2000_base_device::device_start() +{ + m_program = &space(AS_PROGRAM); + m_data = &space(AS_DATA); + + m_read_k.resolve_safe(0xf); + m_read_i.resolve_safe(0xf); + m_read_d.resolve_safe(0); + m_write_d.resolve_safe(); + m_write_a.resolve_safe(); + m_write_f.resolve_safe(); + + m_bu_mask = (1 << m_bu_bits) - 1; + m_callstack_mask = (1 << m_callstack_bits) - 1; + + // zerofill + memset(m_callstack, 0, sizeof(m_callstack)); + m_pc = 0; + m_ppr = 0; + m_pbr = 0; + m_skip = false; + m_op = 0; + m_prev_op = 0; + m_f = 0; + m_carry = 0; + m_bl = 0; + m_bu = 0; + m_acc = 0; + m_e = 0; + m_ki_mask = 0; + m_d = 0; + m_d_active = false; + m_d_polarity = 0; + m_a = 0; + + // register for savestates + save_item(NAME(m_callstack)); + save_item(NAME(m_pc)); + save_item(NAME(m_ppr)); + save_item(NAME(m_pbr)); + save_item(NAME(m_skip)); + save_item(NAME(m_op)); + save_item(NAME(m_prev_op)); + save_item(NAME(m_f)); + save_item(NAME(m_carry)); + save_item(NAME(m_bl)); + save_item(NAME(m_bu)); + save_item(NAME(m_acc)); + save_item(NAME(m_e)); + save_item(NAME(m_ki_mask)); + save_item(NAME(m_d)); + save_item(NAME(m_d_active)); + save_item(NAME(m_d_polarity)); + save_item(NAME(m_a)); + + // register state for debugger + state_add(S2000_PC, "PC", m_pc ).formatstr("%04X"); + state_add(S2000_BL, "BL", m_bl ).formatstr("%01X"); + state_add(S2000_BU, "BU", m_bu ).formatstr("%01X"); + state_add(S2000_ACC, "ACC", m_acc ).formatstr("%01X"); + state_add(S2000_E, "E", m_e ).formatstr("%01X"); + state_add(S2000_CY, "CY", m_carry ).formatstr("%01X"); + + state_add(STATE_GENPC, "curpc", m_pc).formatstr("%04X").noshow(); + state_add(STATE_GENFLAGS, "GENFLAGS", m_f).formatstr("%6s").noshow(); + + m_icountptr = &m_icount; +} + + +void amis2152_cpu_device::device_start() +{ + amis2000_base_device::device_start(); + + m_d2f_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(amis2152_cpu_device::d2f_timer_cb), this)); + + // zerofill + m_d2f_latch = 0; + m_fout_state = 0; + + // register for savestates + save_item(NAME(m_d2f_latch)); + save_item(NAME(m_fout_state)); +} + + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void amis2000_base_device::device_reset() +{ + m_pc = 0; + m_op = 0; + m_skip = false; + + // clear i/o + m_a = 0x1fff; + m_write_a(0, m_a, 0xffff); + m_d_polarity = 0; + m_d = 0; + d_latch_out(false); +} + + +void amis2152_cpu_device::device_reset() +{ + amis2000_base_device::device_reset(); + + // start d2f timer + m_write_f(0); + d2f_timer_clock(); +} + + + +//------------------------------------------------- +// execute +//------------------------------------------------- + +void amis2000_base_device::execute_run() +{ + while (m_icount > 0) + { + m_icount--; + + // remember previous opcode + m_prev_op = m_op; + + debugger_instruction_hook(this, m_pc); + m_op = m_program->read_byte(m_pc); + m_pc = (m_pc + 1) & 0x1fff; + + if (m_skip) + { + // always skip over PP prefix + m_skip = ((m_op & 0xf0) == 0x60); + m_op = 0; // nop + } + + switch (m_op & 0xf0) + { + case 0x50: op_adis(); break; + case 0x60: op_pp(); break; + case 0x70: op_lai(); break; + + case 0x80: case 0x90: case 0xa0: case 0xb0: op_jms(); break; + case 0xc0: case 0xd0: case 0xe0: case 0xf0: op_jmp(); break; + + default: + switch (m_op) + { + case 0x00: op_nop(); break; + case 0x01: op_halt(); break; + case 0x02: op_rt(); break; + case 0x03: op_rts(); break; + case 0x04: op_psh(); break; + case 0x05: op_psl(); break; + case 0x06: op_and(); break; + case 0x07: op_sos(); break; + case 0x08: op_sbe(); break; + case 0x09: op_szc(); break; + case 0x0a: op_stc(); break; + case 0x0b: op_rsc(); break; + case 0x0c: op_lae(); break; + case 0x0d: op_xae(); break; + case 0x0e: op_inp(); break; + case 0x0f: op_eur(); break; + case 0x10: op_cma(); break; + case 0x11: op_xabu(); break; + case 0x12: op_lab(); break; + case 0x13: op_xab(); break; + case 0x14: op_adcs(); break; + case 0x15: op_xor(); break; + case 0x16: op_add(); break; + case 0x17: op_sam(); break; + case 0x18: op_disb(); break; + case 0x19: op_mvs(); break; + case 0x1a: op_out(); break; + case 0x1b: op_disn(); break; + + case 0x28: op_szk(); break; + case 0x29: op_szi(); break; + case 0x2a: op_rf1(); break; + case 0x2b: op_sf1(); break; + case 0x2c: op_rf2(); break; + case 0x2d: op_sf2(); break; + case 0x2e: op_tf1(); break; + case 0x2f: op_tf2(); break; + + default: + switch (m_op & 0xfc) + { + case 0x1c: op_szm(); break; + case 0x20: op_stm(); break; + case 0x24: op_rsm(); break; + + case 0x30: op_xci(); break; + case 0x34: op_xcd(); break; + case 0x38: op_xc(); break; + case 0x3c: op_lam(); break; + case 0x40: op_lbz(); break; + case 0x44: op_lbf(); break; + case 0x48: op_lbe(); break; + case 0x4c: op_lbep(); break; + } + break; // 0xfc + + } + break; // 0xff + + } // big switch + } +} diff --git a/src/devices/cpu/amis2000/amis2000.h b/src/devices/cpu/amis2000/amis2000.h new file mode 100644 index 00000000000..d04127eec16 --- /dev/null +++ b/src/devices/cpu/amis2000/amis2000.h @@ -0,0 +1,244 @@ +// license:BSD-3-Clause +// copyright-holders:hap +/* + + AMI S2000-family MCU cores + +*/ + +#ifndef _AMIS2000_H_ +#define _AMIS2000_H_ + +#include "emu.h" + + +// generic input pins (4 bits each) +#define MCFG_AMI_S2000_READ_K_CB(_devcb) \ + amis2000_base_device::set_read_k_callback(*device, DEVCB_##_devcb); + +#define MCFG_AMI_S2000_READ_I_CB(_devcb) \ + amis2000_base_device::set_read_i_callback(*device, DEVCB_##_devcb); + +// 8-bit external databus coupled as input/output pins +#define MCFG_AMI_S2000_READ_D_CB(_devcb) \ + amis2000_base_device::set_read_d_callback(*device, DEVCB_##_devcb); + +#define MCFG_AMI_S2000_WRITE_D_CB(_devcb) \ + amis2000_base_device::set_write_d_callback(*device, DEVCB_##_devcb); + +// 13-bit external addressbus coupled as output pins +#define MCFG_AMI_S2000_WRITE_A_CB(_devcb) \ + amis2000_base_device::set_write_a_callback(*device, DEVCB_##_devcb); + +// F_out pin (only for S2152) +#define MCFG_AMI_S2152_FOUT_CB(_devcb) \ + amis2000_base_device::set_write_f_callback(*device, DEVCB_##_devcb); + +// S2000 has a hardcoded 7seg table, that (unlike S2200) is officially +// uncustomizable, but wildfire proves to be an exception to that rule. +#define MCFG_AMI_S2000_7SEG_DECODER(_ptr) \ + amis2000_base_device::set_7seg_table(*device, _ptr); + + +class amis2000_base_device : public cpu_device +{ +public: + // construction/destruction + amis2000_base_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, UINT8 bu_bits, UINT8 callstack_bits, UINT8 callstack_depth, int prgwidth, address_map_constructor program, int datawidth, address_map_constructor data, const char *shortname, const char *source) + : cpu_device(mconfig, type, name, tag, owner, clock, shortname, source) + , m_program_config("program", ENDIANNESS_BIG, 8, prgwidth, 0, program) + , m_data_config("data", ENDIANNESS_BIG, 8, datawidth, 0, data) + , m_bu_bits(bu_bits) + , m_callstack_bits(callstack_bits) + , m_callstack_depth(callstack_depth) + , m_7seg_table(NULL) + , m_read_k(*this) + , m_read_i(*this) + , m_read_d(*this) + , m_write_d(*this) + , m_write_a(*this) + , m_write_f(*this) + { } + + // static configuration helpers + template static devcb_base &set_read_k_callback(device_t &device, _Object object) { return downcast(device).m_read_k.set_callback(object); } + template static devcb_base &set_read_i_callback(device_t &device, _Object object) { return downcast(device).m_read_i.set_callback(object); } + template static devcb_base &set_read_d_callback(device_t &device, _Object object) { return downcast(device).m_read_d.set_callback(object); } + template static devcb_base &set_write_d_callback(device_t &device, _Object object) { return downcast(device).m_write_d.set_callback(object); } + template static devcb_base &set_write_a_callback(device_t &device, _Object object) { return downcast(device).m_write_a.set_callback(object); } + template static devcb_base &set_write_f_callback(device_t &device, _Object object) { return downcast(device).m_write_f.set_callback(object); } + static void set_7seg_table(device_t &device, const UINT8 *ptr) { downcast(device).m_7seg_table = ptr; } + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_execute_interface overrides + virtual UINT64 execute_clocks_to_cycles(UINT64 clocks) const { return (clocks + 4 - 1) / 4; } // 4 cycles per machine cycle + virtual UINT64 execute_cycles_to_clocks(UINT64 cycles) const { return (cycles * 4); } // " + virtual UINT32 execute_min_cycles() const { return 1; } + virtual UINT32 execute_max_cycles() const { return 2; } + virtual UINT32 execute_input_lines() const { return 1; } + virtual void execute_run(); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const { return(spacenum == AS_PROGRAM) ? &m_program_config : ((spacenum == AS_DATA) ? &m_data_config : NULL); } + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const { return 1; } + virtual UINT32 disasm_max_opcode_bytes() const { return 1; } + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + void state_string_export(const device_state_entry &entry, std::string &str); + + address_space_config m_program_config; + address_space_config m_data_config; + address_space *m_program; + address_space *m_data; + + UINT8 m_bu_bits; + UINT16 m_bu_mask; + UINT8 m_callstack_bits; // number of program counter bits held in callstack + UINT16 m_callstack_mask; + UINT8 m_callstack_depth; // callstack levels: 3 on 2000/2150, 5 on 2200/2400 + UINT16 m_callstack[5]; // max 5 + int m_icount; + UINT16 m_pc; // 13-bit program counter + UINT8 m_ppr; // prepared page register (PP 1) + UINT8 m_pbr; // prepared bank register (PP 2) + bool m_skip; // skip next opcode, including PP prefixes + UINT8 m_op; + UINT8 m_prev_op; // previous opcode, needed for PP, LAI, LB* + UINT8 m_f; // generic flags: 2 on 2000/2150, 6 on 2200/2400 + UINT8 m_carry; // carry flag + UINT8 m_bl; // 4-bit ram index x + UINT8 m_bu; // 2/3-bit ram index y + UINT8 m_acc; // 4-bit accumulator + UINT8 m_e; // 4-bit generic register + UINT8 m_ki_mask; // 4-bit k/i-pins select latch + UINT8 m_d; // 8-bit d-pins latch + bool m_d_active; // d-pins available for direct i/o(floating), or outputting d-latch + UINT8 m_d_polarity; // invert d-latch output + UINT16 m_a; // 13-bit a-pins latch (master strobe latch) + + // i/o handlers + const UINT8 *m_7seg_table; + devcb_read8 m_read_k; + devcb_read8 m_read_i; + devcb_read8 m_read_d; + devcb_write8 m_write_d; + devcb_write16 m_write_a; + devcb_write_line m_write_f; + + // misc internal helpers + UINT8 ram_r(); + void ram_w(UINT8 data); + void pop_callstack(); + void push_callstack(); + void d_latch_out(bool active); + + // opcode handlers + virtual void op_lai(); + virtual void op_lab(); + virtual void op_lae(); + virtual void op_xab(); + virtual void op_xabu(); + virtual void op_xae(); + virtual void op_lbe(); + virtual void op_lbep(); + virtual void op_lbz(); + virtual void op_lbf(); + + virtual void op_lam(); + virtual void op_xc(); + virtual void op_xci(); + virtual void op_xcd(); + virtual void op_stm(); + virtual void op_rsm(); + + virtual void op_inp(); + virtual void op_out(); + virtual void op_disb(); + virtual void op_disn(); + virtual void op_mvs(); + virtual void op_psh(); + virtual void op_psl(); + virtual void op_eur(); + + virtual void op_pp(); + virtual void op_jmp(); + virtual void op_jms(); + virtual void op_rt(); + virtual void op_rts(); + virtual void op_nop(); + virtual void op_halt(); + + virtual void op_szc(); + virtual void op_szm(); + virtual void op_szi(); + virtual void op_szk(); + virtual void op_sbe(); + virtual void op_sam(); + virtual void op_sos(); + virtual void op_tf1(); + virtual void op_tf2(); + + virtual void op_adcs(); + virtual void op_adis(); + virtual void op_add(); + virtual void op_and(); + virtual void op_xor(); + virtual void op_stc(); + virtual void op_rsc(); + virtual void op_cma(); + virtual void op_sf1(); + virtual void op_rf1(); + virtual void op_sf2(); + virtual void op_rf2(); +}; + + +class amis2000_cpu_device : public amis2000_base_device +{ +public: + amis2000_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +class amis2150_cpu_device : public amis2000_base_device +{ +public: + amis2150_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +class amis2152_cpu_device : public amis2000_base_device +{ +public: + amis2152_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // digital-to-frequency converter + UINT8 m_d2f_latch; + emu_timer *m_d2f_timer; + int m_fout_state; + + void d2f_timer_clock(); + TIMER_CALLBACK_MEMBER(d2f_timer_cb); + + // opcode handlers + virtual void op_szk(); +}; + + + +extern const device_type AMI_S2000; +extern const device_type AMI_S2150; +extern const device_type AMI_S2152; + + +#endif /* _AMIS2000_H_ */ diff --git a/src/devices/cpu/amis2000/amis2000d.c b/src/devices/cpu/amis2000/amis2000d.c new file mode 100644 index 00000000000..27077170402 --- /dev/null +++ b/src/devices/cpu/amis2000/amis2000d.c @@ -0,0 +1,133 @@ +// license:BSD-3-Clause +// copyright-holders:hap +/* + + AMI S2000-family disassembler + +*/ + +#include "emu.h" +#include "debugger.h" +#include "amis2000.h" + + +enum e_mnemonics +{ + mLAB = 0, mLAE, mLAI, mLBE, mLBEP, mLBF, mLBZ, mXAB, mXABU, mXAE, + mLAM, mXC, mXCI, mXCD, mSTM, mRSM, + mADD, mADCS, mADIS, mAND, mXOR, mCMA, mSTC, mRSC, mSF1, mRF1, mSF2, mRF2, + mSAM, mSZM, mSBE, mSZC, mSOS, mSZK, mSZI, mTF1, mTF2, + mPP, mJMP, mJMS, mRT, mRTS, mNOP, mHALT, + mINP, mOUT, mDISB, mDISN, mMVS, mPSH, mPSL, mEUR +}; + +static const char *const s_mnemonics[] = +{ + "LAB", "LAE", "LAI", "LBE", "LBEP", "LBF", "LBZ", "XAB", "XABU", "XAE", + "LAM", "XC", "XCI", "XCD", "STM", "RSM", + "ADD", "ADCS", "ADIS", "AND", "XOR", "CMA", "STC", "RSC", "SF1", "RF1", "SF2", "RF2", + "SAM", "SZM", "SBE", "SZC", "SOS", "SZK", "SZI", "TF1", "TF2", + "PP", "JMP", "JMS", "RT", "RTS", "NOP", "HALT", + "INP", "OUT", "DISB", "DISN", "MVS", "PSH", "PSL", "EUR" +}; + +// number of bits per opcode parameter, negative indicates complement +static const INT8 s_bits[] = +{ + 0, 0, 4, 2, 2, 2, 2, 0, 0, 0, + -2, -2, -2, -2, 2, 2, + 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 2, 0, 0, 0, 0, 0, 0, 0, + -4, 6, 6, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 +}; + +#define _OVER DASMFLAG_STEP_OVER +#define _OUT DASMFLAG_STEP_OUT + +static const UINT32 s_flags[] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, _OVER, _OUT, _OUT, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 +}; + + +static const UINT8 s2000_mnemonic[0x100] = +{ + /* 0x00 */ + mNOP, mHALT, mRT, mRTS, mPSH, mPSL, mAND, mSOS, + mSBE, mSZC, mSTC, mRSC, mLAE, mXAE, mINP, mEUR, + /* 0x10 */ + mCMA, mXABU, mLAB, mXAB, mADCS, mXOR, mADD, mSAM, + mDISB, mMVS, mOUT, mDISN, mSZM, mSZM, mSZM, mSZM, + /* 0x20 */ + mSTM, mSTM, mSTM, mSTM, mRSM, mRSM, mRSM, mRSM, + mSZK, mSZI, mRF1, mSF1, mRF2, mSF2, mTF1, mTF2, + mXCI, mXCI, mXCI, mXCI, mXCD, mXCD, mXCD, mXCD, + mXC, mXC, mXC, mXC, mLAM, mLAM, mLAM, mLAM, + /* 0x40 */ + mLBZ, mLBZ, mLBZ, mLBZ, mLBF, mLBF, mLBF, mLBF, + mLBE, mLBE, mLBE, mLBE, mLBEP, mLBEP, mLBEP, mLBEP, + mADIS, mADIS, mADIS, mADIS, mADIS, mADIS, mADIS, mADIS, + mADIS, mADIS, mADIS, mADIS, mADIS, mADIS, mADIS, mADIS, + mPP, mPP, mPP, mPP, mPP, mPP, mPP, mPP, + mPP, mPP, mPP, mPP, mPP, mPP, mPP, mPP, + mLAI, mLAI, mLAI, mLAI, mLAI, mLAI, mLAI, mLAI, + mLAI, mLAI, mLAI, mLAI, mLAI, mLAI, mLAI, mLAI, + /* 0x80 */ + mJMS, mJMS, mJMS, mJMS, mJMS, mJMS, mJMS, mJMS, + mJMS, mJMS, mJMS, mJMS, mJMS, mJMS, mJMS, mJMS, + mJMS, mJMS, mJMS, mJMS, mJMS, mJMS, mJMS, mJMS, + mJMS, mJMS, mJMS, mJMS, mJMS, mJMS, mJMS, mJMS, + mJMS, mJMS, mJMS, mJMS, mJMS, mJMS, mJMS, mJMS, + mJMS, mJMS, mJMS, mJMS, mJMS, mJMS, mJMS, mJMS, + mJMS, mJMS, mJMS, mJMS, mJMS, mJMS, mJMS, mJMS, + mJMS, mJMS, mJMS, mJMS, mJMS, mJMS, mJMS, mJMS, + /* 0xc0 */ + mJMP, mJMP, mJMP, mJMP, mJMP, mJMP, mJMP, mJMP, + mJMP, mJMP, mJMP, mJMP, mJMP, mJMP, mJMP, mJMP, + mJMP, mJMP, mJMP, mJMP, mJMP, mJMP, mJMP, mJMP, + mJMP, mJMP, mJMP, mJMP, mJMP, mJMP, mJMP, mJMP, + mJMP, mJMP, mJMP, mJMP, mJMP, mJMP, mJMP, mJMP, + mJMP, mJMP, mJMP, mJMP, mJMP, mJMP, mJMP, mJMP, + mJMP, mJMP, mJMP, mJMP, mJMP, mJMP, mJMP, mJMP, + mJMP, mJMP, mJMP, mJMP, mJMP, mJMP, mJMP, mJMP +}; + + + +CPU_DISASSEMBLE( amis2000 ) +{ + int pos = 0; + UINT8 op = oprom[pos++]; + UINT8 instr = s2000_mnemonic[op]; + + char *dst = buffer; + dst += sprintf(dst, "%-5s ", s_mnemonics[instr]); + + // opcode parameter + int mask = s_bits[instr]; + bool complement = (mask < 0); + if (mask < 0) + mask = -mask; + mask = (1 << mask) - 1; + + if (mask != 0) + { + UINT8 param = op; + if (complement) + param = ~param; + param &= mask; + + if (mask < 0x10) + dst += sprintf(dst, "%d", param); + else + dst += sprintf(dst, "$%02X", param); + } + + return pos | s_flags[instr] | DASMFLAG_SUPPORTED; +} diff --git a/src/devices/cpu/amis2000/amis2000op.c b/src/devices/cpu/amis2000/amis2000op.c new file mode 100644 index 00000000000..02f23ebed0a --- /dev/null +++ b/src/devices/cpu/amis2000/amis2000op.c @@ -0,0 +1,524 @@ +// license:BSD-3-Clause +// copyright-holders:hap + +// AMI S2000 opcode handlers + +#include "amis2000.h" + + +// internal helpers + +inline UINT8 amis2000_base_device::ram_r() +{ + UINT16 address = m_bu << 4 | m_bl; + return m_data->read_byte(address) & 0xf; +} + +inline void amis2000_base_device::ram_w(UINT8 data) +{ + UINT16 address = m_bu << 4 | m_bl; + m_data->write_byte(address, data & 0xf); +} + +void amis2000_base_device::pop_callstack() +{ + m_pc = (m_pc & ~m_callstack_mask) | (m_callstack[0] & m_callstack_mask); + for (int i = 0; i < m_callstack_depth-1; i++) + m_callstack[i] = m_callstack[i+1]; +} + +void amis2000_base_device::push_callstack() +{ + for (int i = m_callstack_depth-1; i >= 1; i--) + m_callstack[i] = m_callstack[i-1]; + m_callstack[0] = m_pc & m_callstack_mask; +} + +void amis2000_base_device::d_latch_out(bool active) +{ + m_write_d(0, active ? (m_d ^ m_d_polarity) : 0, 0xff); + m_d_active = active; +} + + +// Register Instructions + +void amis2000_base_device::op_lai() +{ + // LAI X: load ACC with X, select I and K inputs + // note: only execute the first one in a sequence of LAI + if ((m_prev_op & 0xf0) != (m_op & 0xf0)) + { + UINT8 param = m_op & 0x0f; + m_acc = param; + m_ki_mask = param; + } +} + +void amis2000_base_device::op_lab() +{ + // LAB: load ACC with BL + m_acc = m_bl; +} + +void amis2000_base_device::op_lae() +{ + // LAE: load ACC with E + m_acc = m_e; +} + +void amis2000_base_device::op_xab() +{ + // XAB: exchange ACC with BL + UINT8 old_acc = m_acc; + m_acc = m_bl; + m_bl = old_acc; +} + +void amis2000_base_device::op_xabu() +{ + // XABU: exchange ACC with BU + UINT8 old_acc = m_acc; + m_acc = (m_acc & ~m_bu_mask) | (m_bu & m_bu_mask); + m_bu = old_acc & m_bu_mask; +} + +void amis2000_base_device::op_xae() +{ + // XAE: exchange ACC with E + UINT8 old_acc = m_acc; + m_acc = m_e; + m_e = old_acc; +} + +void amis2000_base_device::op_lbe() +{ + // LBE Y: load BU with Y, load BL with E + // note: only execute the first one in a sequence of LB* + if ((m_prev_op & 0xf0) != (m_op & 0xf0)) + { + UINT8 param = m_op & 0x03; + m_bu = param & m_bu_mask; + m_bl = m_e; + } +} + +void amis2000_base_device::op_lbep() +{ + // LBEP Y: load BU with Y, load BL with E+1 + // note: only execute the first one in a sequence of LB* + if ((m_prev_op & 0xf0) != (m_op & 0xf0)) + { + UINT8 param = m_op & 0x03; + m_bu = param & m_bu_mask; + m_bl = (m_e + 1) & 0xf; + } +} + +void amis2000_base_device::op_lbz() +{ + // LBZ Y: load BU with Y, load BL with 0 + // note: only execute the first one in a sequence of LB* + if ((m_prev_op & 0xf0) != (m_op & 0xf0)) + { + UINT8 param = m_op & 0x03; + m_bu = param & m_bu_mask; + m_bl = 0; + } +} + +void amis2000_base_device::op_lbf() +{ + // LBF Y: load BU with Y, load BL with 15 + // note: only execute the first one in a sequence of LB* + if ((m_prev_op & 0xf0) != (m_op & 0xf0)) + { + UINT8 param = m_op & 0x03; + m_bu = param & m_bu_mask; + m_bl = 0xf; + } +} + + +// RAM Instructions + +void amis2000_base_device::op_lam() +{ + // LAM _Y: load ACC with RAM, xor BU with _Y + m_acc = ram_r(); + UINT8 param = ~m_op & 0x03; + m_bu ^= (param & m_bu_mask); +} + +void amis2000_base_device::op_xc() +{ + // XC _Y: exchange ACC with RAM, xor BU with _Y + UINT8 old_acc = m_acc; + m_acc = ram_r(); + ram_w(old_acc); + UINT8 param = ~m_op & 0x03; + m_bu ^= (param & m_bu_mask); +} + +void amis2000_base_device::op_xci() +{ + // XCI _Y: exchange ACC with RAM, increment BL(skip next on carry), xor BU with _Y + op_xc(); + m_bl = (m_bl + 1) & 0xf; + m_skip = (m_bl == 0); +} + +void amis2000_base_device::op_xcd() +{ + // XCD _Y: exchange ACC with RAM, decrement BL(skip next on carry), xor BU with _Y + op_xc(); + m_bl = (m_bl - 1) & 0xf; + m_skip = (m_bl == 0xf); +} + +void amis2000_base_device::op_stm() +{ + // STM Z: set RAM bit Z + UINT8 param = 1 << (m_op & 0x03); + ram_w(ram_r() | param); +} + +void amis2000_base_device::op_rsm() +{ + // RSM Z: reset RAM bit Z + UINT8 param = 1 << (m_op & 0x03); + ram_w(ram_r() & ~param); +} + + +// Input/Output Instructions + +void amis2000_base_device::op_inp() +{ + // INP: input D-pins to ACC and RAM + UINT8 in = m_d_active ? m_d : m_read_d(0, 0xff); + m_acc = in & 0xf; + ram_w(in >> 4 & 0xf); +} + +void amis2000_base_device::op_out() +{ + // OUT: pulse output ACC and RAM to D-pins + logerror("%s unknown opcode $%02X at $%04X\n", tag(), m_op, m_pc); +} + +void amis2000_base_device::op_disb() +{ + // DISB: set D-latch to ACC and RAM directly + m_d = m_acc | ram_r() << 4; + d_latch_out(true); +} + +void amis2000_base_device::op_disn() +{ + // DISN: set D-latch to ACC+carry via on-die segment decoder + static const UINT8 lut_segment_decoder[0x10] = + { + // 0-F digits in bit order [DP]abcdefg + 0x7e, 0x30, 0x6d, 0x79, 0x33, 0x5b, 0x5f, 0x70, 0x7f, 0x7b, 0x77, 0x1f, 0x4e, 0x3d, 0x4f, 0x47 + }; + const UINT8 *ptr = (m_7seg_table != NULL) ? m_7seg_table : lut_segment_decoder; + m_d = ptr[m_acc] | (m_carry ? 0x80 : 0x00); + d_latch_out(true); +} + +void amis2000_base_device::op_mvs() +{ + // MVS: output master strobe latch to A-pins + d_latch_out(false); + m_write_a(0, m_a, 0xffff); +} + +void amis2000_base_device::op_psh() +{ + // PSH: preset high(BL) master strobe latch + switch (m_bl) + { + case 0xd: + // set multiplex operation + // ? + break; + + case 0xe: + // exit from floating mode on D-pins + d_latch_out(true); + break; + + case 0xf: + // set all latch bits high + m_a = 0x1fff; + break; + + default: + // set selected latch bit high + m_a |= (1 << m_bl); + break; + } +} + +void amis2000_base_device::op_psl() +{ + // PSL: preset low(BL) master strobe latch + switch (m_bl) + { + case 0xd: + // set static operation + // ? + break; + + case 0xe: + // enter floating mode on D-pins + d_latch_out(false); + break; + + case 0xf: + // set all latch bits low + m_a = 0; + break; + + default: + // set selected latch bit low + m_a &= ~(1 << m_bl); + break; + } +} + +void amis2000_base_device::op_eur() +{ + // EUR: set timer frequency(European) and D-latch polarity, via ACC + m_d_polarity = (m_acc & 1) ? 0x00 : 0xff; + d_latch_out(m_d_active); // refresh +} + + +// Program Control Instructions + +void amis2000_base_device::op_pp() +{ + // PP _X: prepare page/bank with _X + UINT8 param = ~m_op & 0x0f; + if ((m_prev_op & 0xf0) != (m_op & 0xf0)) + m_ppr = param; + else + m_pbr = param & 7; +} + +void amis2000_base_device::op_jmp() +{ + // JMP X: jump to X(+PP) + UINT16 mask = 0x3f; + UINT16 param = m_op & mask; + + // if previous opcode was PP, change PC high bits too + if ((m_prev_op & 0xf0) == 0x60) + { + param |= (m_ppr << 6) | (m_pbr << 10); + mask = 0x1fff; + } + m_pc = (m_pc & ~mask) | param; +} + +void amis2000_base_device::op_jms() +{ + // JMS X: call to X(+PP) + m_icount--; + push_callstack(); + op_jmp(); + + // subroutines default location is page 15 + if ((m_prev_op & 0xf0) != 0x60) + m_pc |= 0x3c0; +} + +void amis2000_base_device::op_rt() +{ + // RT: return from subroutine + pop_callstack(); +} + +void amis2000_base_device::op_rts() +{ + // RTS: return from subroutine and skip next + op_rt(); + m_skip = true; +} + +void amis2000_base_device::op_nop() +{ + // NOP: no operation +} + +void amis2000_base_device::op_halt() +{ + // HALT: debugger breakpoint for devkit-use + logerror("%s unknown opcode $%02X at $%04X\n", tag(), m_op, m_pc); +} + + +// Skip Instructions + +void amis2000_base_device::op_szc() +{ + // SZC: skip next on zero(no) carry + m_skip = !m_carry; +} + +void amis2000_base_device::op_szm() +{ + // SZM Z: skip next on zero RAM bit Z + UINT8 param = 1 << (m_op & 0x03); + m_skip = !(ram_r() & param); +} + +void amis2000_base_device::op_szi() +{ + // SZI: skip next on I pin(s) + m_skip = ((~m_read_i(0, 0xff) & m_ki_mask) != 0); +} + +void amis2000_base_device::op_szk() +{ + // SZK: skip next on K pin(s) + m_skip = ((~m_read_k(0, 0xff) & m_ki_mask) != 0); +} + +void amis2000_base_device::op_sbe() +{ + // SBE: skip next on BL equals E + m_skip = (m_bl == m_e); +} + +void amis2000_base_device::op_sam() +{ + // SAM: skip next on ACC equals RAM + m_skip = (m_acc == ram_r()); +} + +void amis2000_base_device::op_sos() +{ + // SOS: skip next on SF(timer output), clear SF + logerror("%s unknown opcode $%02X at $%04X\n", tag(), m_op, m_pc); +} + +void amis2000_base_device::op_tf1() +{ + // TF1: skip next on flag 1 + m_skip = ((m_f & 0x01) != 0); +} + +void amis2000_base_device::op_tf2() +{ + // TF2: skip next on flag 2 + m_skip = ((m_f & 0x02) != 0); +} + + +// Arithmetic and Logical Instructions + +void amis2000_base_device::op_adcs() +{ + // ADCS: add RAM to ACC+carry, skip next on not carry + m_acc += ram_r() + m_carry; + m_carry = m_acc >> 4 & 1; + m_skip = !m_carry; + m_acc &= 0xf; +} + +void amis2000_base_device::op_adis() +{ + // ADIS X: add X to ACC, skip next on not carry + UINT8 param = m_op & 0x0f; + m_acc += param; + m_skip = !(m_acc & 0x10); + m_acc &= 0xf; +} + +void amis2000_base_device::op_add() +{ + // ADD: add RAM to ACC + m_acc = (m_acc + ram_r()) & 0xf; +} + +void amis2000_base_device::op_and() +{ + // AND: and ACC with RAM + m_acc &= ram_r(); +} + +void amis2000_base_device::op_xor() +{ + // XOR: xor ACC with RAM + m_acc ^= ram_r(); +} + +void amis2000_base_device::op_stc() +{ + // STC: set carry + m_carry = 1; +} + +void amis2000_base_device::op_rsc() +{ + // RSC: reset carry + m_carry = 0; +} + +void amis2000_base_device::op_cma() +{ + // CMA: complement ACC + m_acc ^= 0xf; +} + +void amis2000_base_device::op_sf1() +{ + // SF1: set flag 1 + m_f |= 0x01; +} + +void amis2000_base_device::op_rf1() +{ + // RF1: reset flag 1 + m_f &= ~0x01; +} + +void amis2000_base_device::op_sf2() +{ + // SF2: set flag 2 + m_f |= 0x02; +} + +void amis2000_base_device::op_rf2() +{ + // RF2: reset flag 2 + m_f &= ~0x02; +} + + + +// AMI S2152 specific handlers + +void amis2152_cpu_device::d2f_timer_clock() +{ + // schedule next timeout (frequency is guessed) + attotime base = attotime::from_ticks(4 * 64, unscaled_clock()); + m_d2f_timer->adjust(base * (0x10 - m_d2f_latch)); +} + +TIMER_CALLBACK_MEMBER(amis2152_cpu_device::d2f_timer_cb) +{ + m_write_f(m_fout_state); + m_fout_state ^= 1; + + d2f_timer_clock(); +} + +void amis2152_cpu_device::op_szk() +{ + // instead of SZK: ???: load d2f latch with ACC(?) + m_d2f_latch = m_acc; +} diff --git a/src/devices/cpu/apexc/apexc.c b/src/devices/cpu/apexc/apexc.c new file mode 100644 index 00000000000..77e5c919f44 --- /dev/null +++ b/src/devices/cpu/apexc/apexc.c @@ -0,0 +1,866 @@ +// license:BSD-3-Clause +// copyright-holders:Raphael Nabet +/* + cpu/apexc/apexc.c: APE(X)C CPU emulation + + By Raphael Nabet + + APE(X)C (All Purpose Electronic X-ray Computer) was a computer built by Andrew D. Booth + and others for the Birkbeck College, in London, which was used to compute cristal + structure using X-ray diffraction. + + It was one of the APEC series of computer, which were simple electronic computers + built in the early 1950s for various British Universities. Known members of this series + are: + * APE(X)C: Birkbeck College, London (before 1953 (1951?)) + * APE(N)C: Board of Mathematical Machines, Oslo + * APE(H)C: British Tabulating Machine Company + * APE(R)C: British Rayon Research Association + * UCC: University College, London (circa january 1956) + * MAC (Magnetic Automatic Calculator): "built by Wharf Engineering Laboratories" + (february 1955), which used some germanium diodes + * The HEC (built by the British Tabulating Machine Company), a commercial machine sold + in two models at least (HEC 2M and HEC 4) (before 1955) + + References: + * Andrew D. Booth & Kathleen H. V. Booth: Automatic Digital Calculators, 2nd edition + (Buttersworth Scientific Publications, 1956) (referred to as 'Booth&Booth') + * Kathleen H. V. Booth: Programming for an Automatic Digital Calculator + (Buttersworth Scientific Publications, 1958) (referred to as 'Booth') + * Digital Engineering Newsletter vol 7 nb 1 p 60 and vol 8 nb 1 p 60-61 provided some + dates +*/ + +/* + Generals specs: + * 32-bit data word size (10-bit addresses): uses fixed-point, 2's complement arithmetic + * CPU has one accumulator (A) and one register (R), plus a Control Register (this is + what we would call an "instruction register" nowadays). No Program Counter, each + instruction contains the address of the next instruction (!). + * memory is composed of 256 (maximal value only found on the UCC - APE(X)C only has + 32 tracks) circular magnetic tracks of 32 words: only 32 tracks can + be accessed at a time (the 16 first ones, plus 16 others chosen by the programmer), + and the rotation rate is 3750rpm (62.5 rotations per second). + * two I/O units: tape reader and tape puncher. A teletyper was designed to read + specially-encoded punched tapes and print decoded text. (See /systems/apexc.c) + * machine code has 15 instructions (!), including add, substract, shift, multiply (!), + test and branch, input and punch. A so-called vector mode allow to repeat the same + operation 32 times with 32 successive memory locations. Note the lack of bitwise + and/or/xor (!) . + * 1 kIPS, although memory access times make this figure fairly theorical (drum rotation + time: 16ms, which would allow about 60IPS when no optimization is made) + * there is no indirect addressing whatever, although dynamic modification of opcodes (!) + allows to simulate it... + * a control panel allows operation and debugging of the machine. (See /systems/apexc.c) + + Conventions: + Bits are numbered in big-endian order, starting with 1: bit #1 is the + MSBit, and bit #32 is the LSBit. + + References: + * Andrew D. Booth & Kathleen H. V. Booth: Automatic Digital Calculators, 2nd edition + (Buttersworth Scientific Publications, 1956) + * Kathleen H. V. Booth: Programming for an Automatic Digital Calculator + (Buttersworth Scientific Publications, 1958) +*/ + +/* + Machine code (reference: Booth): + + Format of a machine instruction: +bits: 1-5 6-10 11-15 16-20 21-25 26-31 32 +field: X address X address Y address Y address Function C6 Vector + (track) (location) (track) (location) + + Meaning of fields: + X: address of an operand, or immediate, or meaningless, depending on Function + (When X is meaningless, it should be a duplicate of Y. Maybe this is because + X is unintentionnally loaded into the memory address register, and if track # is + different, we add unneeded track switch delays (this theory is either wrong or + incomplete, since it cannot be true for B or X)) + Y: address of the next instruction + Function: code for the actual instruction executed + C6: immediate value used by shift, multiply and store operations + Vector: repeat operation 32 times (on all 32 consecutive locations of a track, + starting with the location given by the X field) + + Function code: + # Mnemonic C6 Description + + 0 Stop + + 2 I(y) Input. A 5-bit word is read from tape and loaded + into the 5 MSBits of R. (These bits of R must be + cleared initially.) + + 4 P(y) Punch. The 5 MSBits of R are punched onto the + output tape. + + 6 B<(x)>=(y) Branch. If A<0, next instruction is fetched from @x, whereas + if A>=0, next instruction is fetched from @y + + 8 l (y) n Shift left: the 64 bits of A and R are rotated left n times. + n + + 10 r (y) 64-n Shift right: the 64 bits of A and R are shifted right n times. + n The sign bit of A is duplicated. + + 14 X (x)(y) 33-n Multiply the contents of *track* x by the last n digits of the + n number in R, sending the 32 MSBs to A and 31 LSBs to R + + 16 +c(x)(y) A <- (x) + + 18 -c(x)(y) A <- -(x) + + 20 +(x)(y) A <- A+(x) + + 22 -(x)(y) A <- A-(x) + + 24 T(x)(y) R <- (x) + + 26 R (x)(y) 32+n Store first or last bits of R into (x). The remaining bits of (x) + 1-n are unaffected. "The contents of R are filled with 0s or 1s + according as the original contents were positive or negative". + R (x)(y) n-1 + n-32 + + 28 A (x)(y) 32+n Same as 26, except that source is A, and the contents of A are + 1-n not modified. + + A (x)(y) n-1 + n-32 + + 30 S(x)(y) Block Head switch. This enables the block of heads specified + in x to be loaded into the working store. + + Note: Mnemonics use subscripts (!), which I tried to render the best I could. Also, + ">=" is actually one single character. Last, "1-n" and "n-32" in store mnemonics + are the actual sequences "1 *DASH* " and " *DASH* 32" + (these are NOT formulas with substract signs). + + Note2: Short-hand notations: X stands for X , A for A , and R for R . + 32 1-32 1-32 + + Note3: Vectors instruction are notated with a subscript 'v' following the basic + mnemonic. For instance: + + A (x)(y), + (x)(y) + v v + + are the vector counterparts of A(x)(y) and +(x)(y). + + + + + Note that the code has been presented so far as it was in 1957. It appears that + it was somewhat different in 1953 (Booth&Booth): + + Format of a machine instruction: + Format for r, l, A: +bits: 1-9 10-15 16-17 18-21 22-30 31-32 +field: X address C6 spare Function Y address spare + Format for other instructions: +bits: 1-9 10-17 18-21 22-30 31-32 +field: X address D Function Y address D (part 2) + + Meaning of fields: + D (i.e. drum #): MSBs for the address of the X operand. I don't know whether this feature + was actually implemented, since it is said in Booth&Booth that the APE(X)C does + not use this feature (it had only one drum of 16 tracks at the time, hence the 9 + address bits). + + Function code: + # Mnemonic C6 Description + + 1 A (x)(y) 32+n(?) record first bits of A in (x). The remaining bits of x + 1-n are unaffected. + + 2 +c(x)(y) A <- (x) + + 3 -c(x)(y) A <- -(x) + + 4 +(x)(y) A <- A+(x) + + 5 -(x)(y) A <- A-(x) + + 6 T(x)(y) R <- (x) + + 7 X (x)(y) Multiply the contents of (x) by the number in R, + sending the 32 MSBs to A and 31 LSBs to R + + 8 r (y) 64-n(?) Shift right: the 64 bits of A and R are shifted right n times. + n The sign bit of A is duplicated. + + 9 l (y) n(?) Shift left: the 64 bits of A and R are rotated left n times. + n + + 10 R (x)(y) 32+n record R into (x). + 1-n "the contents of R are filled with 0s or 1s + according as the original contents were positive or negative". + + 11 B<(x)>=(y) Branch. If A<0, next instruction is read from @x, whereas + if A>=0, next instruction is read from @y + + 12 Print(y) Punch. Contents of A are printed. + + 13 C(d+x) branch ("switch Control") to instruction located in position + (D:X) + + 14 Stop + + You will notice the absence of input instruction. It seems that program and data were + meant to be entered with a teletyper or a card reader located on the control panel. + + I don't know whether this computer really was in operation with this code. Handle + these info with caution. +*/ + +/* + memory interface: + + Data is exchanged on a 1-bit (!) data bus, 10-bit address bus. + + While the bus is 1-bit wide, read/write operation can only be take place on word + (i.e. 32 bit) boundaries. However, it is possible to store only the n first bits or + n last bits of a word, leaving other bits in memory unaffected. + + The LSBits are transferred first, since this enables to perform bit-per-bit add and + substract. Otherwise, the CPU would need an additionnal register to store the second + operand, and it would be probably slower, since the operation could only + take place after all the data has been transfered. + + Memory operations are synchronous with 2 clocks found on the memory controller: + * word clock: a pulse on each word boundary (3750rpm*32 -> 2kHz) + * bit clock: a pulse when a bit is present on the bus (word clock * 32 -> 64kHz) + + CPU operation is synchronous with these clocks, too. For instance, the AU does bit-per-bit + addition and substraction with a memory operand, synchronously with bit clock, + starting and stopping on word clock boundaries. Similar thing with a Fetch operation. + + There is a 10-bit memory location (i.e. address) register on the memory controller. + It is loaded with the contents of X after when instruction fetch is complete, and + with the contents of Y when instruction execution is complete, so that the next fetch + can be executed correctly. +*/ + +/* + Instruction timings: + + + References: Booth p. 14 for the table below + + + Mnemonic delay in word clock cycles + + I 32 + + P 32 + + B 0 + + l 1 if n>=32 (i.e. C6>=32) (see 4.) + n 2 if n<32 (i.e. C6<32) + + r 1 if n<=32 (i.e. C6>=32) (see 4.) + n 2 if n>32 (i.e. C6<32) + + X 32 + + +c, -c, +, -, T 0 + + R , R , A , A 1 (see 1. & 4.) + 1-n n-32 1-n n-32 + + track switch 6 (see 2.) + + vector 12 (see 3.) + + + (S and stop are missing in the table) + + + Note that you must add the fetch delay (at least 1 cycle), and, when applicable, the + operand read/write delay (at least 1 cycle). + + + Notes: + + 1. The delay is applied after the store is done (from the analysis of the example + in Booth p.52) + + 2. I guess that the memory controller needs 6 cycles to stabilize whenever track + switching occurs, i.e. when X does not refer to the current track, and then when Y + does not refer to the same track as X. This matches various examples in Booth, + although it appears that this delay is not applied when X is not read (cf cross-track + B in Booth p. 49). + However, and here comes the wacky part, analysis of Booth p. 55 shows that + no additionnal delay is caused by an X instruction having its X operand + on another track. Maybe, just maybe, this is related to the fact that X does not + need to take the word count into account, any word in track is as good as any (yet, + this leaves the question of why this optimization could not be applied to vector + operations unanswered). + + 3. This is an ambiguous statement. Analysis of Booth p. 55 shows that + an instance of an Av instruction with its destination on another track takes no more + than 45 cycles, as follow: + * 1 cycle for fetch + * 6-cycle delay (at most) before write starts (-> track switch) + * 32 memory cycles + * 6-cycle delay (at most) after write completion (-> track switch) + It appears that the delay associated with the vector mode is not distinguishable from + the delay caused by track switch and even the delay associated to the Av instruction. + Is there really a specific delay associated with the vector mode? To know this, we + would need to see a vector instruction on the same track as its operands, which is + unlikely to be seen (the only reasonnable application I can see is running a '+_v' + to compute the checksum of the current track). + + 4. Example in Booth p. 76 ("20/4 A (27/27) (21/2)") seems to imply that + when doing a store with a destination on a track other than the track where next + instruction is located, the 1-cycle post-store delay is merged with the 6-cycle track + switch delay. (I assume this because there is lots of room on track 21, and if + the delays were not merged, it should be easy to move the instruction forward + to speed up loop execution time. + Similarly, example in Booth p. 49-50 ("4/24 l 32 (5/31)") seems to show that + a similar delay merge occurs when doing a shift with the next instruction located on + another track. +*/ + +#include "emu.h" +#include "debugger.h" +#include "apexc.h" + + +const device_type APEXC = &device_creator; + + +/* decrement ICount by n */ +#define DELAY(n) {m_icount -= (n); m_current_word = (m_current_word + (n)) & 0x1f;} + + +apexc_cpu_device::apexc_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : cpu_device(mconfig, APEXC, "APEXC", tag, owner, clock, "apexc_cpu", __FILE__) + , m_program_config("program", ENDIANNESS_BIG, 32, 15, 0) + , m_io_config("io", ENDIANNESS_BIG, 8, 1, 0) + , m_a(0) + , m_r(0) + , m_cr(0) + , m_ml(0) + , m_working_store(1) + , m_running(0) + , m_pc(0) + , m_ml_full(0) +{ +} + + +/* + word accessor functions + + take a 10-bit word address + 5 bits (MSBs): track address within working store + 5 bits (LSBs): word position within track + + 'special' flag: if true, read first word found in track (used by X instruction only) + + 'mask': one bit is set for each bit to write (used by store instructions) + + memory latency delays are taken into account, but not track switching delays +*/ + +/* compute complete word address (i.e. translate a logical track address (expressed +in current working store) to an absolute track address) */ +UINT32 apexc_cpu_device::effective_address(UINT32 address) +{ + if (address & 0x200) + { + address = (address & 0x1FF) | (m_working_store) << 9; + } + + return address; +} + +/* read word */ +UINT32 apexc_cpu_device::word_read(UINT32 address, UINT32 special) +{ + UINT32 result; + + /* compute absolute track address */ + address = effective_address(address); + + if (special) + { + /* ignore word position in x - use current position instead */ + address = (address & ~ 0x1f) | m_current_word; + } + else + { + /* wait for requested word to appear under the heads */ + DELAY(((address /*& 0x1f*/) - m_current_word) & 0x1f); + } + + /* read 32 bits */ + result = apexc_readmem(address); + + /* read takes one memory cycle */ + DELAY(1); + + return result; +} + +/* write word (or part of a word, according to mask) */ +void apexc_cpu_device::word_write(UINT32 address, UINT32 data, UINT32 mask) +{ + /* compute absolute track address */ + address = effective_address(address); + + /* wait for requested word to appear under the heads */ + DELAY(((address /*& 0x1f*/) - m_current_word) & 0x1f); + + /* write 32 bits according to mask */ + apexc_writemem_masked(address, data, mask); + + /* write takes one memory cycle (2, actually, but the 2nd cycle is taken into + account in execute) */ + DELAY(1); +} + +/* + I/O accessors + + no address is used, these functions just punch or read 5 bits +*/ + +UINT8 apexc_cpu_device::papertape_read() +{ + return m_io->read_byte(0) & 0x1f; +} + +void apexc_cpu_device::papertape_punch(UINT8 data) +{ + m_io->write_byte(0, data); +} + +/* + now for emulation code +*/ + +/* + set the memory location (i.e. address) register, and compute the associated delay +*/ +UINT32 apexc_cpu_device::load_ml(UINT32 address, UINT32 vector) +{ + int delay; + + /* additionnal delay appears if we switch tracks */ + if (((m_ml & 0x3E0) != (address & 0x3E0)) /*|| vector*/) + delay = 6; /* if tracks are different, delay to allow for track switching */ + else + delay = 0; /* else, no problem */ + + m_ml = address; /* save ml */ + + return delay; +} + +/* + execute one instruction + + TODO: + * test!!! + + NOTE: + * I do not know whether we should fetch instructions at the beginning or the end of the + instruction cycle. Either solution is roughly equivalent to the other, but changes + the control panel operation (and I know virtually nothing on the control panel). + Currently, I fetch each instruction right after executing the previous instruction, so that + the user may enter an instruction into the control register with the control panel, then + execute it. + This solution makes timing simulation much simpler, too. +*/ +void apexc_cpu_device::execute() +{ + int x, y, function, c6, vector; /* instruction fields */ + int i = 0; /* misc counter */ + int has_operand; /* true if instruction is an AU operation with an X operand */ + static const char has_operand_table[32] = /* table for has_operand - one entry for each function code */ + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0 + }; + int delay1; /* pre-operand-access delay */ + int delay2; /* post-operation delay */ + int delay3; /* pre-operand-fetch delay */ + + /* first isolate the instruction fields */ + x = (m_cr >> 22) & 0x3FF; + y = (m_cr >> 12) & 0x3FF; + function = (m_cr >> 7) & 0x1F; + c6 = (m_cr >> 1) & 0x3F; + vector = m_cr & 1; + m_pc = y<<2; + + function &= 0x1E; /* this is a mere guess - the LSBit is reserved for future additions */ + + /* determinates if we need to read an operand*/ + has_operand = has_operand_table[function]; + + if (has_operand) + { + /* load ml with X */ + delay1 = load_ml(x, vector); + /* burn pre-operand-access delay if needed */ + if (delay1) + { + DELAY(delay1); + } + } + + delay2 = 0; /* default */ + + do + { + switch (function) + { + case 0: + /* stop */ + + m_running = FALSE; + + /* BTW, I don't know whether stop loads y into ml or not, and whether + subsequent fetch is done */ + break; + + case 2: + /* I */ + /* I do not know whether the CPU does an OR or whatever, but since docs say that + the 5 bits must be cleared initially, an OR kind of makes sense */ + m_r |= papertape_read() << 27; + delay2 = 32; /* no idea whether this should be counted as an absolute delay + or as a value in delay2 */ + break; + + case 4: + /* P */ + papertape_punch((m_r >> 27) & 0x1f); + delay2 = 32; /* no idea whether this should be counted as an absolute delay + or as a value in delay2 */ + break; + + case 6: + /* B<(x)>=(y) */ + /* I have no idea what we should do if the vector bit is set */ + if (m_a & 0x80000000UL) + { + /* load ml with X */ + delay1 = load_ml(x, vector); + m_pc = x<<2; + /* burn pre-fetch delay if needed */ + if (delay1) + { + DELAY(delay1); + } + /* and do fetch at X */ + goto special_fetch; + } + /* else, the instruction ends with a normal fetch */ + break; + + case 8: + /* l_n */ + delay2 = (c6 & 0x20) ? 1 : 2; /* if more than 32 shifts, it takes more time */ + + /* Yes, this code is inefficient, but this must be the way the APEXC does it ;-) */ + while (c6 != 0) + { + int shifted_bit = 0; + + /* shift and increment c6 */ + shifted_bit = m_r & 1; + m_r >>= 1; + if (m_a & 1) + m_r |= 0x80000000UL; + m_a >>= 1; + if (shifted_bit) + m_a |= 0x80000000UL; + + c6 = (c6+1) & 0x3f; + } + + break; + + case 10: + /* r_n */ + delay2 = (c6 & 0x20) ? 1 : 2; /* if more than 32 shifts, it takes more time */ + + /* Yes, this code is inefficient, but this must be the way the APEXC does it ;-) */ + while (c6 != 0) + { + /* shift and increment c6 */ + m_r >>= 1; + if (m_a & 1) + m_r |= 0x80000000UL; + m_a = ((INT32) m_a) >> 1; + + c6 = (c6+1) & 0x3f; + } + + break; + + case 12: + /* unused function code. I assume this results into a NOP, for lack of any + specific info... */ + + break; + + case 14: + /* X_n(x) */ + + /* Yes, this code is inefficient, but this must be the way the APEXC does it ;-) */ + /* algorithm found in Booth&Booth, p. 45-48 */ + { + int shifted_bit; + + m_a = 0; + shifted_bit = 0; + while (1) + { + /* note we read word at current word position */ + if (shifted_bit && ! (m_r & 1)) + m_a += word_read(x, 1); + else if ((! shifted_bit) && (m_r & 1)) + m_a -= word_read(x, 1); + else + /* Even if we do not read anything, the loop still takes 1 cycle of + the memory word clock. */ + /* Anyway, maybe we still read the data even if we do not use it. */ + DELAY(1); + + /* exit if c6 reached 32 ("c6 & 0x20" is simpler to implement and + essentially equivalent, so this is most likely the actual implementation) */ + if (c6 & 0x20) + break; + + /* else increment c6 and shift */ + c6 = (c6+1) & 0x3f; + + /* shift */ + shifted_bit = m_r & 1; + m_r >>= 1; + if (m_a & 1) + m_r |= 0x80000000UL; + m_a = ((INT32) m_a) >> 1; + } + } + + //DELAY(32); /* mmmh... we have already counted 32 wait states */ + /* actually, if (n < 32) (which is an untypical case), we do not have 32 wait + states. Question is: do we really have 32 wait states if (n < 32), or is + the timing table incomplete? */ + break; + + case 16: + /* +c(x) */ + m_a = + word_read(m_ml, 0); + break; + + case 18: + /* -c(x) */ + m_a = - word_read(m_ml, 0); + break; + + case 20: + /* +(x) */ + m_a += word_read(m_ml, 0); + break; + + case 22: + /* -(x) */ + m_a -= word_read(m_ml, 0); + break; + + case 24: + /* T(x) */ + m_r = word_read(m_ml, 0); + break; + + case 26: + /* R_(1-n)(x) & R_(n-32)(x) */ + + { + UINT32 mask; + + if (c6 & 0x20) + mask = 0xFFFFFFFFUL << (64 - c6); + else + mask = 0xFFFFFFFFUL >> c6; + + word_write(m_ml, m_r, mask); + } + + m_r = (m_r & 0x80000000UL) ? 0xFFFFFFFFUL : 0; + + delay2 = 1; + break; + + case 28: + /* A_(1-n)(x) & A_(n-32)(x) */ + + { + UINT32 mask; + + if (c6 & 0x20) + mask = 0xFFFFFFFFUL << (64 - c6); + else + mask = 0xFFFFFFFFUL >> c6; + + word_write(m_ml, m_a, mask); + } + + delay2 = 1; + break; + + case 30: + /* S(x) */ + m_working_store = (x >> 5) & 0xf; /* or is it (x >> 6)? */ + DELAY(32); /* no idea what the value is... All I know is that it takes much + more time than track switching (which takes 6 cycles) */ + break; + } + if (vector) + /* increment word position in vector operations */ + m_ml = (m_ml & 0x3E0) | ((m_ml + 1) & 0x1F); + } while (vector && has_operand && (++i < 32)); /* iterate 32 times if vector bit is set */ + /* the has_operand is a mere guess */ + + /* load ml with Y */ + delay3 = load_ml(y, 0); + + /* compute max(delay2, delay3) */ + if (delay2 > delay3) + delay3 = delay2; + + /* burn pre-fetch delay if needed */ + if (delay3) + { + DELAY(delay3); + } + + /* entry point after a successful Branch (which alters the normal instruction sequence, + in order not to load ml with Y) */ +special_fetch: + + /* fetch current instruction into control register */ + m_cr = word_read(m_ml, 0); +} + + +void apexc_cpu_device::device_start() +{ + m_program = &space(AS_PROGRAM); + m_io = &space(AS_IO); + + save_item(NAME(m_a)); + save_item(NAME(m_r)); + save_item(NAME(m_cr)); + save_item(NAME(m_ml)); + save_item(NAME(m_working_store)); + save_item(NAME(m_current_word)); + save_item(NAME(m_running)); + save_item(NAME(m_pc)); + + state_add( APEXC_CR, "CR", m_cr ).formatstr("%08X"); + state_add( APEXC_A, "A", m_a ).formatstr("%08X"); + state_add( APEXC_R, "R", m_r ).formatstr("%08X"); + state_add( APEXC_ML, "ML", m_ml ).mask(0xfff).formatstr("%03X"); + state_add( APEXC_WS, "WS", m_working_store ).mask(0x01); + state_add( APEXC_STATE, "CPU state", m_running ).mask(0x01); + state_add( APEXC_PC, "PC", m_pc ).callimport().callexport().formatstr("%03X"); + state_add( APEXC_ML_FULL, "ML_FULL", m_ml_full ).callimport().callexport().noshow(); + + m_icountptr = &m_icount; +} + + +void apexc_cpu_device::state_import(const device_state_entry &entry) +{ + switch (entry.index()) + { + case APEXC_PC: + /* keep address 9 LSBits - 10th bit depends on whether we are accessing the permanent + track group or a switchable one */ + m_ml = m_pc & 0x1ff; + if (m_pc & 0x1e00) + { /* we are accessing a switchable track group */ + m_ml |= 0x200; /* set 10th bit */ + + if (((m_pc >> 9) & 0xf) != m_working_store) + { /* we need to do a store switch */ + m_working_store = ((m_pc >> 9) & 0xf); + } + } + break; + } +} + + +void apexc_cpu_device::state_export(const device_state_entry &entry) +{ + switch (entry.index()) + { + case APEXC_ML_FULL: + m_ml_full = effective_address(m_ml); + break; + } +} + + +void apexc_cpu_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + switch (entry.index()) + { + case STATE_GENFLAGS: + strprintf(str, "%c", m_running ? 'R' : 'S'); + break; + } +} + + +void apexc_cpu_device::device_reset() +{ + /* mmmh... I don't know what happens on reset with an actual APEXC. */ + + m_working_store = 1; /* mere guess */ + m_current_word = 0; /* well, we do have to start somewhere... */ + + /* next two lines are just the product of my bold fantasy */ + m_cr = 0; /* first instruction executed will be a stop */ + m_running = TRUE; /* this causes the CPU to load the instruction at 0/0, + which enables easy booting (just press run on the panel) */ + m_a = 0; + m_r = 0; + m_pc = 0; + m_ml = 0; +} + + +void apexc_cpu_device::execute_run() +{ + do + { + debugger_instruction_hook(this, m_pc); + + if (m_running) + execute(); + else + { + DELAY(m_icount); /* burn cycles once for all */ + } + } while (m_icount > 0); +} + + +offs_t apexc_cpu_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( apexc ); + return CPU_DISASSEMBLE_NAME(apexc)(this, buffer, pc, oprom, opram, options); +} diff --git a/src/devices/cpu/apexc/apexc.h b/src/devices/cpu/apexc/apexc.h new file mode 100644 index 00000000000..538d903ab44 --- /dev/null +++ b/src/devices/cpu/apexc/apexc.h @@ -0,0 +1,94 @@ +// license:BSD-3-Clause +// copyright-holders:Raphael Nabet +/* register names for apexc_get_reg & apexc_set_reg */ +#pragma once + +#ifndef __APEXC_H__ +#define __APEXC_H__ + +enum +{ + APEXC_CR =1, /* control register */ + APEXC_A, /* acumulator */ + APEXC_R, /* register */ + APEXC_ML, /* memory location */ + APEXC_WS, /* working store */ + APEXC_STATE, /* whether CPU is running */ + + APEXC_ML_FULL, /* read-only pseudo-register for exclusive use by the control panel code + in the apexc driver : enables it to get the complete address computed + from the contents of ML and WS */ + APEXC_PC /* doesn't actually exist; is there for the disassembler */ +}; + +class apexc_cpu_device : public cpu_device +{ +public: + // construction/destruction + apexc_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_execute_interface overrides + virtual UINT32 execute_min_cycles() const { return 2; } + virtual UINT32 execute_max_cycles() const { return 75; } + virtual UINT32 execute_input_lines() const { return 0; } + virtual void execute_run(); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const { return (spacenum == AS_PROGRAM) ? &m_program_config : ( (spacenum == AS_IO) ? &m_io_config : NULL ); } + + // device_state_interface overrides + virtual void state_import(const device_state_entry &entry); + virtual void state_export(const device_state_entry &entry); + void state_string_export(const device_state_entry &entry, std::string &str); + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const { return 4; } + virtual UINT32 disasm_max_opcode_bytes() const { return 4; } + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + + inline UINT32 apexc_readmem(UINT32 address) { return m_program->read_dword((address)<<2); } + inline void apexc_writemem(UINT32 address, UINT32 data) { m_program->write_dword((address)<<2, (data)); } + inline void apexc_writemem_masked(UINT32 address, UINT32 data, UINT32 mask) { apexc_writemem((address), (apexc_readmem(address) & ~(mask)) | ((data) & (mask))); } + + UINT32 effective_address(UINT32 address); + UINT32 word_read(UINT32 address, UINT32 special); + void word_write(UINT32 address, UINT32 data, UINT32 mask); + UINT8 papertape_read(); + void papertape_punch(UINT8 data); + + UINT32 load_ml(UINT32 address, UINT32 vector); + void execute(); + + address_space_config m_program_config; + address_space_config m_io_config; + + UINT32 m_a; /* accumulator */ + UINT32 m_r; /* register */ + UINT32 m_cr; /* control register (i.e. instruction register) */ + int m_ml; /* memory location (current track in working store, and requested word position within track) (10 bits) */ + int m_working_store; /* current working store (group of 16 tracks) (1-15) */ + int m_current_word; /* current word position within track (0-31) */ + + int m_running; /* 1 flag: */ + /* running: flag implied by the existence of the stop instruction */ + UINT32 m_pc; /* address of next instruction for the disassembler */ + + address_space *m_program; + address_space *m_io; + int m_icount; + + // For state + UINT32 m_ml_full; + UINT32 m_genpc; +}; + + +extern const device_type APEXC; + + +#endif /* __APEXC_H__ */ diff --git a/src/devices/cpu/apexc/apexcdsm.c b/src/devices/cpu/apexc/apexcdsm.c new file mode 100644 index 00000000000..81effc58b0e --- /dev/null +++ b/src/devices/cpu/apexc/apexcdsm.c @@ -0,0 +1,184 @@ +// license:BSD-3-Clause +// copyright-holders:Raphael Nabet +/* + cpu/apexc/apexcsm.c : APE(X)C CPU disassembler + + By Raphael Nabet + + see cpu/apexc.c for background and tech info +*/ + + +#include "emu.h" +#include "debugger.h" + +#include "apexc.h" + +/* + Here is the format used for debugger output. + + Since the only assembler for the APEXC that I know of uses numerical data + (yes, mnemonics are numbers), I do not know if there is an official way of writing + APEXC assembly on a text terminal. The format I chose is closely inspired by + the assembly format found in Booth, but was slightly adapted to accommodate + the lack of subscripts and of a 'greater or equal' character. + + Printed format Name + 0 1 2 + 012345678901234567890123456 + Stop (##/##) one_address + I (##/##) one_address + P (##/##) one_address + B <(##/##) >=(##/##) branch + l (##) (##/##) shiftl + r (##) (##/##) shiftr + Illegal (##/##) one_address + X (##) (##) (##/##) multiply + X (##) (##/##) multiply + +c (##/##) (##/##) two_address + -c (##/##) (##/##) two_address + + (##/##) (##/##) two_address + - (##/##) (##/##) two_address + T (##/##) (##/##) two_address + R (1-##) (##/##) (##/##) store + R (##-32) (##/##) (##/##) store + R (##/##) (##/##) store + A (1-##) (##/##) (##/##) store + A (##-32) (##/##) (##/##) store + A (##/##) (##/##) store + S (##) (##/##) swap + +--------++--------++-----+ + mnemonic X field Y field + field + + For vector instructions, replace the first space on the right of the mnemonic + with a 'v'. + + 01-Feb-2010 (Robbbert): + I've added the actual address, (as shown in the extreme left of the debugger + output), so that you can see much easier how the program will flow. Example: + + +C XXX(##/##) XXX(##/##) + + The X value shows where the data word is located, and the Y value is the + address of the next instruction. +*/ +enum format_type {branch, shiftl, shiftr, multiply, store, swap, one_address, two_address}; + +struct instr_desc +{ + const char *mnemonic; + format_type format; /* -> X and Y are format */ +}; + +static const instr_desc instructions[16] = +{ + { "Stop", one_address }, { "I", one_address }, + { "P", one_address }, { "B", branch }, + { "l", shiftl }, { "r", shiftr }, + { "Illegal",one_address }, { "X", multiply }, + { "+c", two_address }, { "-c", two_address }, + { "+", two_address }, { "-", two_address }, + { "T", two_address }, { "R", store }, + { "A", store }, { "S", swap } +}; + +CPU_DISASSEMBLE( apexc ) +{ + UINT32 instruction; /* 32-bit machine instruction */ + int x, y, function, c6, vector; /* instruction fields */ + int n; /* 'friendly', instruction-dependant interpretation of C6 */ + const instr_desc *the_desc; /* pointer to the relevant entry in the instructions array */ + char mnemonic[9]; /* storage for generated mnemonic */ + + /* read the instruction to disassemble */ + instruction = oprom[0] << 24 | oprom[1] << 16 | oprom[2] << 8 | oprom[3]; + + /* isolate the instruction fields */ + x = (instruction >> 22) & 0x3FF; + y = (instruction >> 12) & 0x3FF; + function = (instruction >> 7) & 0x1F; + c6 = (instruction >> 1) & 0x3F; + vector = instruction & 1; + + /* get the relevant entry in instructions */ + the_desc = & instructions[function >> 1]; + + /* generate mnemonic : append a 'v' to the basic mnemonic if it is a vector instruction */ + sprintf(mnemonic, "%.*s%c", (int)sizeof(mnemonic)-2, the_desc->mnemonic, vector ? 'v' : ' '); + + /* print mnemonic and n immediate */ + switch (the_desc->format) + { + case one_address: + case two_address: + case branch: + case swap: + buffer += sprintf(buffer, " %-10s", mnemonic); /* 10 chars*/ + break; + + case shiftl: + case shiftr: + if (the_desc->format == shiftl) + n = c6; + else + n = 64-c6; + buffer += sprintf(buffer, " %-2s(%2d) ", mnemonic, n); /* 10 chars */ + break; + + case multiply: + n = 33-c6; + if (n == 32) + /* case "32" : do not show bit specifier */ + buffer += sprintf(buffer, " %-10s", mnemonic); /* 10 chars */ + else + buffer += sprintf(buffer, " %-2s(%2d) ", mnemonic, n); /* 10 chars */ + break; + + case store: + if (c6 == 0) + { /* case "1-32" : do not show bit specifier */ + buffer += sprintf(buffer, " %-10s", mnemonic); /* 10 chars*/ + } + else if (c6 & 0x20) + { /* case "1-n" */ + n = c6-32; + buffer += sprintf(buffer, " %-2s (1-%02d) ", mnemonic, n); /* 10 chars */ + } + else + { /* case "n-32" */ + n = c6+1; + buffer += sprintf(buffer, " %-2s(%02d-32) ", mnemonic, n); /* 8 chars */ + } + } + + /* print X address */ + switch (the_desc->format) + { + case branch: + buffer--; /* eat last char */ + buffer += sprintf(buffer, "<%03X(%02d/%02d) >=", x<<2, (x >> 5) & 0x1f, x & 0x1f); /* 10+1 chars */ + break; + + case multiply: + case swap: + buffer += sprintf(buffer, " (%02d) ", (x >> 5) & 0x1f); /* 10 chars */ + break; + + case one_address: + case shiftl: + case shiftr: + buffer += sprintf(buffer, " "); /* 10 chars */ + break; + + case two_address: + case store: + buffer += sprintf(buffer, "%03X(%02d/%02d) ", x<<2, (x >> 5) & 0x1f, x & 0x1f); /* 10 chars */ + break; + } + + /* print Y address */ + buffer += sprintf(buffer, "%03X(%02d/%02d)", y<<2, (y >> 5) & 0x1f, y & 0x1f); /* 7 chars */ + + return 4; +} diff --git a/src/devices/cpu/arc/arc.c b/src/devices/cpu/arc/arc.c new file mode 100644 index 00000000000..2fe40ae9bd6 --- /dev/null +++ b/src/devices/cpu/arc/arc.c @@ -0,0 +1,123 @@ +// license:BSD-3-Clause +// copyright-holders:David Haywood +/*********************************\ + + ARCtangent (A4) core + ARC == Argonaut RISC Core + + (this is a skeleton core) + +\*********************************/ + +#include "emu.h" +#include "debugger.h" +#include "arc.h" + + +const device_type ARC = &device_creator; + + +arc_device::arc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : cpu_device(mconfig, ARC, "ARCtangent A4", tag, owner, clock, "arc", __FILE__) + , m_program_config("program", ENDIANNESS_BIG, 32, 24, 0) // some docs describe these as 'middle endian'?! +{ +} + + +offs_t arc_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( arc ); + return CPU_DISASSEMBLE_NAME(arc)(this, buffer, pc, oprom, opram, options); +} + + +/*****************************************************************************/ + +/*****************************************************************************/ + +void arc_device::unimplemented_opcode(UINT16 op) +{ + fatalerror("arc: unknown opcode %04x at %04x\n", op, m_pc << 2); +} + +/*****************************************************************************/ + +UINT32 arc_device::READ32(UINT32 address) +{ + return m_program->read_dword(address << 2); +} + +void arc_device::WRITE32(UINT32 address, UINT32 data) +{ + m_program->write_dword(address << 2, data); +} + +/*****************************************************************************/ + +void arc_device::device_start() +{ + m_pc = 0; + + m_debugger_temp = 0; + + m_program = &space(AS_PROGRAM); + + state_add( 0, "PC", m_debugger_temp).callimport().callexport().formatstr("%08X"); + state_add(STATE_GENPC, "GENPC", m_debugger_temp).callexport().noshow(); + + m_icountptr = &m_icount; +} + +void arc_device::state_export(const device_state_entry &entry) +{ + switch (entry.index()) + { + case 0: + m_debugger_temp = m_pc << 2; + break; + + case STATE_GENPC: + m_debugger_temp = m_pc << 2; + break; + } +} + +void arc_device::state_import(const device_state_entry &entry) +{ + switch (entry.index()) + { + case 0: + m_pc = (m_debugger_temp & 0xfffffffc) >> 2; + break; + } +} + +void arc_device::device_reset() +{ + m_pc = 0x00000000; +} + +/*****************************************************************************/ + +void arc_device::execute_set_input(int irqline, int state) +{ +} + + +void arc_device::execute_run() +{ + //UINT32 lres; + //lres = 0; + + while (m_icount > 0) + { + debugger_instruction_hook(this, m_pc<<2); + + //UINT32 op = READ32(m_pc); + + m_pc++; + + m_icount--; + } + +} diff --git a/src/devices/cpu/arc/arc.h b/src/devices/cpu/arc/arc.h new file mode 100644 index 00000000000..80ed03280bc --- /dev/null +++ b/src/devices/cpu/arc/arc.h @@ -0,0 +1,75 @@ +// license:BSD-3-Clause +// copyright-holders:David Haywood +/*********************************\ + + ARCtangent (A4) core + ARC == Argonaut RISC Core + +\*********************************/ + +#pragma once + +#ifndef __ARC_H__ +#define __ARC_H__ + +class arc_device : public cpu_device +{ +public: + // construction/destruction + arc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_execute_interface overrides + virtual UINT32 execute_min_cycles() const { return 5; } + virtual UINT32 execute_max_cycles() const { return 5; } + virtual UINT32 execute_input_lines() const { return 0; } + virtual void execute_run(); + virtual void execute_set_input(int inputnum, int state); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const { return (spacenum == AS_PROGRAM) ? &m_program_config : NULL; } + + // device_state_interface overrides + virtual void state_import(const device_state_entry &entry); + virtual void state_export(const device_state_entry &entry); + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const { return 4; } + virtual UINT32 disasm_max_opcode_bytes() const { return 4; } + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + +private: + address_space_config m_program_config; + + // 0 - 28 = r00 - r28 (General Purpose Registers) + // 29 = r29 (ILINK1) + // 30 = r30 (ILINE2) + // 31 = r31 (BLINK) + // 32- 59 = r32 - r59 (Reserved Registers) + // 60 = LPCOUNT + // 61 = Short Immediate Data Indicator Settings Flag + // 62 = Long Immediate Data Indicator + // 63 = Short Immediate Data Indicator NOT Settings Flag + UINT32 m_pc; + //UINT32 m_r[64]; + + + address_space *m_program; + int m_icount; + + UINT32 m_debugger_temp; + + void unimplemented_opcode(UINT16 op); + inline UINT32 READ32(UINT32 address); + inline void WRITE32(UINT32 address, UINT32 data); +}; + + +extern const device_type ARC; + + +#endif /* __ARC_H__ */ diff --git a/src/devices/cpu/arc/arcdasm.c b/src/devices/cpu/arc/arcdasm.c new file mode 100644 index 00000000000..7a525d6cb61 --- /dev/null +++ b/src/devices/cpu/arc/arcdasm.c @@ -0,0 +1,224 @@ +// license:BSD-3-Clause +// copyright-holders:David Haywood +/*********************************\ + + ARCtangent A4 disassembler + +\*********************************/ + +#include "emu.h" +#include + +static char *output; + +static void ATTR_PRINTF(1,2) print(const char *fmt, ...) +{ + va_list vl; + + va_start(vl, fmt); + vsprintf(output, fmt, vl); + va_end(vl); +} + +/*****************************************************************************/ + + + +/*****************************************************************************/ + +static const char *basic[0x20] = +{ + /* 00 */ "LD r+r", + /* 01 */ "LD r+o", + /* 02 */ "ST r+o", + /* 03 */ "extended", + /* 04 */ "B", + /* 05 */ "BL", + /* 06 */ "LPcc", + /* 07 */ "Jcc JLcc", + /* 08 */ "ADD", + /* 09 */ "ADC", + /* 0a */ "SUB", + /* 0b */ "SBC", + /* 0c */ "AND", + /* 0d */ "OR", + /* 0e */ "BIC", + /* 0f */ "XOR", + /* 10 */ "ASL", + /* 11 */ "LSR", + /* 12 */ "ASR", + /* 13 */ "ROR", + /* 14 */ "MUL64", + /* 15 */ "MULU64", + /* 16 */ "undefined", + /* 17 */ "undefined", + /* 18 */ "undefined", + /* 19 */ "undefined", + /* 1a */ "undefined", + /* 1b */ "undefined", + /* 1c */ "undefined", + /* 1d */ "undefined", + /* 1e */ "MAX", + /* 1f */ "MIN" +}; + +static const char *conditions[0x20] = +{ + /* 00 */ "AL", // (aka RA - Always) + /* 01 */ "EQ", // (aka Z - Zero + /* 02 */ "NE", // (aka NZ - Non-Zero) + /* 03 */ "PL", // (aka P - Positive) + /* 04 */ "MI", // (aka N - Negative) + /* 05 */ "CS", // (aka C, LO - Carry set / Lower than) (unsigned) + /* 06 */ "CC", // (aka CC, NC, HS - Carry Clear / Higher or Same) (unsigned) + /* 07 */ "VS", // (aka V - Overflow set) + /* 08 */ "VC", // (aka NV - Overflow clear) + /* 09 */ "GT", // ( - Greater than) (signed) + /* 0a */ "GE", // ( - Greater than or Equal) (signed) + /* 0b */ "LT", // ( - Less than) (signed) + /* 0c */ "LE", // ( - Less than or Equal) (signed) + /* 0d */ "HI", // ( - Higher than) (unsigned) + /* 0e */ "LS", // ( - Lower or Same) (unsigned) + /* 0f */ "PNZ",// ( - Positive non-0 value) + /* 10 */ "0x10 Reserved", // possible CPU implementation specifics + /* 11 */ "0x11 Reserved", + /* 12 */ "0x12 Reserved", + /* 13 */ "0x13 Reserved", + /* 14 */ "0x14 Reserved", + /* 15 */ "0x15 Reserved", + /* 16 */ "0x16 Reserved", + /* 17 */ "0x17 Reserved", + /* 18 */ "0x18 Reserved", + /* 19 */ "0x19 Reserved", + /* 1a */ "0x1a Reserved", + /* 1b */ "0x1b Reserved", + /* 1c */ "0x1c Reserved", + /* 1d */ "0x1d Reserved", + /* 1e */ "0x1e Reserved", + /* 1f */ "0x1f Reserved" +}; + +static const char *delaytype[0x4] = +{ + "ND", // NO DELAY - execute next instruction only when NOT jumping + "D", // always execute next instruction + "JD", // only execute next instruction when jumping + "Res!", // reserved / invalid +}; + +static const char *regnames[0x40] = +{ + /* 0x00 */ "r00", + /* 0x01 */ "r01", + /* 0x02 */ "r02", + /* 0x03 */ "r03", + /* 0x04 */ "r04", + /* 0x05 */ "r05", + /* 0x06 */ "r06", + /* 0x07 */ "r07", + /* 0x08 */ "r08", + /* 0x09 */ "r09", + /* 0x0a */ "r10", + /* 0x0b */ "r11", + /* 0x0c */ "r12", + /* 0x0d */ "r13", + /* 0x0e */ "r14", + /* 0x0f */ "r15", + + /* 0x10 */ "r16", + /* 0x11 */ "r17", + /* 0x12 */ "r18", + /* 0x13 */ "r19", + /* 0x14 */ "r20", + /* 0x15 */ "r21", + /* 0x16 */ "r22", + /* 0x17 */ "r23", + /* 0x18 */ "r24", + /* 0x19 */ "r25", + /* 0x1a */ "r26", + /* 0x1b */ "r27", + /* 0x1c */ "r28", + /* 0x1d */ "ILINK1", + /* 0x1e */ "ILINK2", + /* 0x1f */ "BLINK", + + /* 0x20 */ "r32res", // reserved for manufacturer specific extensions + /* 0x21 */ "r33res", + /* 0x22 */ "r34res", + /* 0x23 */ "r35res", + /* 0x24 */ "r36res", + /* 0x25 */ "r37res", + /* 0x26 */ "r38res", + /* 0x27 */ "r39res", + /* 0x28 */ "r40res", + /* 0x29 */ "r41res", + /* 0x2a */ "r42res", + /* 0x2b */ "r43res", + /* 0x2c */ "r44res", + /* 0x2d */ "r45res", + /* 0x2e */ "r46res", + /* 0x2f */ "r47res", + + /* 0x30 */ "r48res", + /* 0x31 */ "r49res", + /* 0x32 */ "r50res", + /* 0x33 */ "r51res", + /* 0x34 */ "r52res", + /* 0x35 */ "r53res", + /* 0x36 */ "r54res", + /* 0x37 */ "r55res", + /* 0x38 */ "r56res", + /* 0x39 */ "r57res", + /* 0x3a */ "r58res", + /* 0x3b */ "r59res", + /* 0x3c */ "LPCOUNT", + /* 0x3d */ "sImm F", + /* 0x3e */ "lImm", + /* 0x3f */ "sImm NF", +}; + +#define ARC_CONDITION ((op & 0x0000001f) >> 0 ) // aka Q + +// used in jumps +#define ARC_BRANCH_DELAY ((op & 0x00000060) >> 5 ) // aka N +#define ARC_BRANCH_ADDR ((op & 0x07ffff80) >> 7 ) // aka L + +#define ARC_OPERATION ((op & 0xf8000000) >> 27) + +#define ARC_REGOP_DEST ((op & 0x07e00000) >> 21 ) // aka A +#define ARC_REGOP_OP1 ((op & 0x001f8000) >> 15 ) // aka B +#define ARC_REGOP_OP2 ((op & 0x00007e00) >> 9 ) // aka C +#define ARC_REGOP_SHIMM ((op & 0x000001ff) >> 0 ) // aka D + + +CPU_DISASSEMBLE(arc) +{ + UINT32 op = oprom[0] | (oprom[1] << 8) | (oprom[2] << 16) | (oprom[3] << 24); + op = BIG_ENDIANIZE_INT32(op); + + output = buffer; + + UINT8 opcode = ARC_OPERATION; + + switch (opcode) + { + case 0x04: // B + case 0x05: // BL + print("%s(%s)(%s) %08x", basic[opcode], conditions[ARC_CONDITION], delaytype[ARC_BRANCH_DELAY], (ARC_BRANCH_ADDR<<2)+pc+4); + break; + + case 0x08: // ADD + // todo, short / long immediate formats + print("%s %s , %s , %s (%08x)", basic[opcode], regnames[ARC_REGOP_DEST], regnames[ARC_REGOP_OP1], regnames[ARC_REGOP_OP2], op &~ 0xfffffe00); + break; + + + default: + print("%s (%08x)", basic[opcode], op &~ 0xf8000000); + break; + } + + + + return 4 | DASMFLAG_SUPPORTED; +} diff --git a/src/devices/cpu/arcompact/arcompact.c b/src/devices/cpu/arcompact/arcompact.c new file mode 100644 index 00000000000..dca1bf9fd91 --- /dev/null +++ b/src/devices/cpu/arcompact/arcompact.c @@ -0,0 +1,194 @@ +// license:BSD-3-Clause +// copyright-holders:David Haywood +/*********************************\ + + ARCompact Core + + The following procesors use the ARCompact instruction set + + - ARCtangent-A5 + - ARC 600 + - ARC 700 + + (this is a skeleton core) + + ARCompact is a 32-bit CPU that freely mixes 32-bit and 16-bit instructions + various user customizations could be made as with the ARC A4 based processors + these include custom instructions and registers. + +\*********************************/ + +#include "emu.h" +#include "debugger.h" +#include "arcompact.h" +#include "arcompact_common.h" + + +const device_type ARCA5 = &device_creator; + + +READ32_MEMBER( arcompact_device::arcompact_auxreg002_LPSTART_r) { return m_LP_START&0xfffffffe; } +WRITE32_MEMBER(arcompact_device::arcompact_auxreg002_LPSTART_w) { m_LP_START = data&0xfffffffe; } +READ32_MEMBER( arcompact_device::arcompact_auxreg003_LPEND_r) { return m_LP_END&0xfffffffe; } +WRITE32_MEMBER(arcompact_device::arcompact_auxreg003_LPEND_w) { m_LP_END = data&0xfffffffe; } + +READ32_MEMBER( arcompact_device::arcompact_auxreg00a_STATUS32_r) { return 0xffffdead; /*m_status32;*/ } + +READ32_MEMBER( arcompact_device::arcompact_auxreg025_INTVECTORBASE_r) { return m_INTVECTORBASE&0xfffffc00; } +WRITE32_MEMBER(arcompact_device::arcompact_auxreg025_INTVECTORBASE_w) { m_INTVECTORBASE = data&0xfffffc00; } + + + + +static ADDRESS_MAP_START( arcompact_auxreg_map, AS_IO, 32, arcompact_device ) + AM_RANGE(0x000000008, 0x00000000b) AM_READWRITE(arcompact_auxreg002_LPSTART_r, arcompact_auxreg002_LPSTART_w) + AM_RANGE(0x00000000c, 0x00000000f) AM_READWRITE(arcompact_auxreg003_LPEND_r, arcompact_auxreg003_LPEND_w) + AM_RANGE(0x000000028, 0x00000002b) AM_READ(arcompact_auxreg00a_STATUS32_r) // r/o + AM_RANGE(0x000000094, 0x000000097) AM_READWRITE(arcompact_auxreg025_INTVECTORBASE_r, arcompact_auxreg025_INTVECTORBASE_w) +ADDRESS_MAP_END + +//#define AUX_SPACE_ADDRESS_WIDTH 34 // IO space is 32 bits of dwords, so 34-bits +#define AUX_SPACE_ADDRESS_WIDTH 64 // but the MAME core requires us to use power of 2 values for >32 + +arcompact_device::arcompact_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : cpu_device(mconfig, ARCA5, "ARCtangent-A5", tag, owner, clock, "arca5", __FILE__) + , m_program_config("program", ENDIANNESS_LITTLE, 32, 32, 0) // some docs describe these as 'middle endian'?! + , m_io_config( "io", ENDIANNESS_LITTLE, 32, AUX_SPACE_ADDRESS_WIDTH, 0, ADDRESS_MAP_NAME( arcompact_auxreg_map ) ) +{ +} + + +offs_t arcompact_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( arcompact ); + return CPU_DISASSEMBLE_NAME(arcompact)(this, buffer, pc, oprom, opram, options); +} + + +/*****************************************************************************/ + +/*****************************************************************************/ + +void arcompact_device::unimplemented_opcode(UINT16 op) +{ + fatalerror("ARCOMPACT: unknown opcode %04x at %04x\n", op, m_pc << 2); +} + +/*****************************************************************************/ + + +/*****************************************************************************/ + +void arcompact_device::device_start() +{ + m_pc = 0; + + m_debugger_temp = 0; + + m_program = &space(AS_PROGRAM); + m_io = &space(AS_IO); + + state_add( 0, "PC", m_debugger_temp).callimport().callexport().formatstr("%08X"); + + state_add( 0x10, "STATUS32", m_debugger_temp).callimport().callexport().formatstr("%08X"); + state_add( 0x11, "LP_START", m_debugger_temp).callimport().callexport().formatstr("%08X"); + state_add( 0x12, "LP_END", m_debugger_temp).callimport().callexport().formatstr("%08X"); + + state_add(STATE_GENPC, "GENPC", m_debugger_temp).callexport().noshow(); + + for (int i = 0x100; i < 0x140; i++) + { + state_add(i, regnames[i-0x100], m_debugger_temp).callimport().callexport().formatstr("%08X"); + } + + + m_icountptr = &m_icount; +} + +void arcompact_device::state_export(const device_state_entry &entry) +{ + int index = entry.index(); + + switch (index) + { + case 0: + m_debugger_temp = m_pc; + break; + + case 0x10: + m_debugger_temp = m_status32; + break; + case 0x11: + m_debugger_temp = m_LP_START; + break; + case 0x12: + m_debugger_temp = m_LP_END; + break; + + case STATE_GENPC: + m_debugger_temp = m_pc; + break; + + default: + if ((index >= 0x100) && (index < 0x140)) + { + m_debugger_temp = m_regs[index - 0x100]; + } + break; + + } +} + +void arcompact_device::state_import(const device_state_entry &entry) +{ + int index = entry.index(); + + switch (index) + { + case 0: + m_pc = (m_debugger_temp & 0xfffffffe); + break; + + case 0x10: + m_status32 = m_debugger_temp; + break; + case 0x11: + m_LP_START = m_debugger_temp; + break; + case 0x12: + m_LP_END = m_debugger_temp; + break; + + default: + if ((index >= 0x100) && (index < 0x140)) + { + m_regs[index - 0x100] = m_debugger_temp; + } + break; + } +} + +void arcompact_device::device_reset() +{ + m_pc = 0x00000000; + + m_delayactive = 0; + m_delayjump = 0x00000000; + + for (int i = 0; i < 0x40; i++) + m_regs[i] = 0; + + m_status32 = 0; + m_LP_START = 0; + m_LP_END = 0; + m_INTVECTORBASE = 0; + +} + + +/*****************************************************************************/ + + +void arcompact_device::execute_set_input(int irqline, int state) +{ +} diff --git a/src/devices/cpu/arcompact/arcompact.h b/src/devices/cpu/arcompact/arcompact.h new file mode 100644 index 00000000000..09f1cf708c2 --- /dev/null +++ b/src/devices/cpu/arcompact/arcompact.h @@ -0,0 +1,891 @@ +// license:BSD-3-Clause +// copyright-holders:David Haywood +/*********************************\ + + ARCompact Core + +\*********************************/ + +#pragma once + +#ifndef __ARCOMPACT_H__ +#define __ARCOMPACT_H__ + +#define ARCOMPACT_RETTYPE UINT32 +#define OPS_32 UINT32 op +#define OPS_16 UINT16 op +#define PARAMS op +#define LIMM_REG 62 +#define ARCOMPACT_OPERATION ((op & 0xf800) >> 11) + + +#define ARCOMPACT_HANDLER04_P11_TYPE(name) \ +ARCOMPACT_RETTYPE arcompact_handle##name##_p11(OPS_32) \ +{ \ + int M = (op & 0x00000020) >> 5; \ + \ + switch (M) \ + { \ + case 0x00: return arcompact_handle##name##_p11_m0(PARAMS); \ + case 0x01: return arcompact_handle##name##_p11_m1(PARAMS); \ + } \ + \ + return 0; \ +} +#define ARCOMPACT_HANDLER04_TYPE(name) \ +ARCOMPACT_RETTYPE arcompact_handle##name(OPS_32) \ +{ \ + int p = (op & 0x00c00000) >> 22; \ + \ + switch (p) \ + { \ + case 0x00: return arcompact_handle##name##_p00(PARAMS); \ + case 0x01: return arcompact_handle##name##_p01(PARAMS); \ + case 0x02: return arcompact_handle##name##_p10(PARAMS); \ + case 0x03: return arcompact_handle##name##_p11(PARAMS); \ + } \ + \ + return 0; \ +} + +#define ARCOMPACT_HANDLER04_TYPE_PM(name) \ + ARCOMPACT_RETTYPE arcompact_handle##name##_p00(OPS_32); \ + ARCOMPACT_RETTYPE arcompact_handle##name##_p01(OPS_32); \ + ARCOMPACT_RETTYPE arcompact_handle##name##_p10(OPS_32); \ + ARCOMPACT_RETTYPE arcompact_handle##name##_p11_m0(OPS_32); \ + ARCOMPACT_RETTYPE arcompact_handle##name##_p11_m1(OPS_32); \ + ARCOMPACT_HANDLER04_P11_TYPE(name); \ + ARCOMPACT_HANDLER04_TYPE(name); + +class arcompact_device : public cpu_device +{ +public: + // construction/destruction + arcompact_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + DECLARE_READ32_MEMBER( arcompact_auxreg002_LPSTART_r); + DECLARE_WRITE32_MEMBER(arcompact_auxreg002_LPSTART_w); + DECLARE_READ32_MEMBER( arcompact_auxreg003_LPEND_r); + DECLARE_WRITE32_MEMBER(arcompact_auxreg003_LPEND_w); + + DECLARE_READ32_MEMBER( arcompact_auxreg00a_STATUS32_r); + DECLARE_READ32_MEMBER( arcompact_auxreg025_INTVECTORBASE_r); + DECLARE_WRITE32_MEMBER( arcompact_auxreg025_INTVECTORBASE_w); + + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_execute_interface overrides + virtual UINT32 execute_min_cycles() const { return 5; } + virtual UINT32 execute_max_cycles() const { return 5; } + virtual UINT32 execute_input_lines() const { return 0; } + virtual void execute_run(); + virtual void execute_set_input(int inputnum, int state); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const { return (spacenum == AS_PROGRAM) ? &m_program_config : ( (spacenum == AS_IO) ? &m_io_config : NULL ); } + + // device_state_interface overrides + virtual void state_import(const device_state_entry &entry); + virtual void state_export(const device_state_entry &entry); + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const { return 2; } + virtual UINT32 disasm_max_opcode_bytes() const { return 8; } + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + + + + // Dispatch + ARCOMPACT_RETTYPE arcompact_handle00(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle01(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle01_00(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle01_01(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle01_01_00(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle01_01_01(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_3f(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05(OPS_32); + + ARCOMPACT_RETTYPE arcompact_handle05_2f(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_3f(OPS_32); + + ARCOMPACT_RETTYPE arcompact_handle0c(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle0d(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle0e(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle0f(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle0f_00(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle0f_00_07(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle17(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle18(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle18_05(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle18_06(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle18_07(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle19(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle1c(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle1d(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle1e(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle1e_03(OPS_16); + + // Handler + + ARCOMPACT_RETTYPE arcompact_handle00_00(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle00_01(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle01_00_00dasm(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle01_00_01dasm(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle01_01_00_00(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle01_01_00_01(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle01_01_00_02(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle01_01_00_03(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle01_01_00_04(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle01_01_00_05(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle01_01_00_0e(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle01_01_00_0f(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle01_01_01_00(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle01_01_01_01(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle01_01_01_02(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle01_01_01_03(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle01_01_01_04(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle01_01_01_05(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle01_01_01_0e(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle01_01_01_0f(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle02(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle03(OPS_32); +// ARCOMPACT_RETTYPE arcompact_handle04_00(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_01(OPS_32); +// ARCOMPACT_RETTYPE arcompact_handle04_02(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_03(OPS_32); +// ARCOMPACT_RETTYPE arcompact_handle04_04(OPS_32); +// ARCOMPACT_RETTYPE arcompact_handle04_05(OPS_32); +// ARCOMPACT_RETTYPE arcompact_handle04_06(OPS_32); +// ARCOMPACT_RETTYPE arcompact_handle04_07(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_08(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_09(OPS_32); +// ARCOMPACT_RETTYPE arcompact_handle04_0a(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_0b(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_0c(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_0d(OPS_32); +// ARCOMPACT_RETTYPE arcompact_handle04_0e(OPS_32); +// ARCOMPACT_RETTYPE arcompact_handle04_0f(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_10(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_11(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_12(OPS_32); +// ARCOMPACT_RETTYPE arcompact_handle04_13(OPS_32); +// ARCOMPACT_RETTYPE arcompact_handle04_14(OPS_32); +// ARCOMPACT_RETTYPE arcompact_handle04_15(OPS_32); +// ARCOMPACT_RETTYPE arcompact_handle04_16(OPS_32); +// ARCOMPACT_RETTYPE arcompact_handle04_17(OPS_32); +// ARCOMPACT_RETTYPE arcompact_handle04_18(OPS_32); +// ARCOMPACT_RETTYPE arcompact_handle04_19(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_1a(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_1b(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_1c(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_1d(OPS_32); +// ARCOMPACT_RETTYPE arcompact_handle04_20(OPS_32); +// ARCOMPACT_RETTYPE arcompact_handle04_21(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_22(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_23(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_28(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_29(OPS_32); +// ARCOMPACT_RETTYPE arcompact_handle04_2a(OPS_32); +// ARCOMPACT_RETTYPE arcompact_handle04_2b(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_00(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_01(OPS_32); +// ARCOMPACT_RETTYPE arcompact_handle04_2f_02(OPS_32); +// ARCOMPACT_RETTYPE arcompact_handle04_2f_03(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_04(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_05(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_06(OPS_32); +// ARCOMPACT_RETTYPE arcompact_handle04_2f_07(OPS_32); +// ARCOMPACT_RETTYPE arcompact_handle04_2f_08(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_09(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_0a(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_0b(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_0c(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_3f_01(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_3f_02(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_3f_03(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_3f_04(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_3f_05(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_30(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_31(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_32(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_33(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_34(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_35(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_36(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_37(OPS_32); + //ARCOMPACT_RETTYPE arcompact_handle05_00(OPS_32); + //ARCOMPACT_RETTYPE arcompact_handle05_01(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_02(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_03(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_04(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_05(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_06(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_07(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_08(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_0a(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_0b(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_28(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_29(OPS_32); + + ARCOMPACT_RETTYPE arcompact_handle06(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle07(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle08(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle09(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle0a(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle0b(OPS_32); + + ARCOMPACT_RETTYPE arcompact_handle0c_00(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle0c_01(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle0c_02(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle0c_03(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle0d_00(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle0d_01(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle0d_02(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle0d_03(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle0e_00(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle0e_01(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle0e_02(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle0e_03(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle0f_00_00(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle0f_00_01(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle0f_00_02(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle0f_00_03(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle0f_00_06(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle0f_00_07_00(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle0f_00_07_01(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle0f_00_07_04(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle0f_00_07_05(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle0f_00_07_06(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle0f_00_07_07(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle0f_02(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle0f_04(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle0f_05(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle0f_06(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle0f_07(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle0f_0b(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle0f_0c(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle0f_0d(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle0f_0e(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle0f_0f(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle0f_10(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle0f_11(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle0f_12(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle0f_13(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle0f_14(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle0f_15(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle0f_16(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle0f_18(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle0f_19(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle0f_1a(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle0f_1b(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle0f_1c(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle0f_1d(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle0f_1e(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle0f_1f(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle10(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle11(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle12(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle13(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle14(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle15(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle16(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle17_00(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle17_01(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle17_02(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle17_03(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle17_04(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle17_05(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle17_06(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle17_07(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle18_00(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle18_01(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle18_02(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle18_03(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle18_04(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle18_05_00(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle18_05_01(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle18_06_01(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle18_06_11(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle18_07_01(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle18_07_11(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle19_00(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle19_01(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle19_02(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle19_03(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle1a(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle1b(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle1c_00(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle1c_01(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle1d_00(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle1d_01(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle1e_00(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle1e_01(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle1e_02(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle1e_03_00(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle1e_03_01(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle1e_03_02(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle1e_03_03(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle1e_03_04(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle1e_03_05(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle1e_03_06(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle1e_03_07(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle1f(OPS_16); + + /************************************************************************************************************************************ + * * + * illegal opcode handlers (disassembly) * + * * + ************************************************************************************************************************************/ + + ARCOMPACT_RETTYPE arcompact_handle01_01_00_06(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle01_01_00_07(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle01_01_00_08(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle01_01_00_09(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle01_01_00_0a(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle01_01_00_0b(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle01_01_00_0c(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle01_01_00_0d(OPS_32); + + ARCOMPACT_RETTYPE arcompact_handle01_01_01_06(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle01_01_01_07(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle01_01_01_08(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle01_01_01_09(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle01_01_01_0a(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle01_01_01_0b(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle01_01_01_0c(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle01_01_01_0d(OPS_32); + + + ARCOMPACT_RETTYPE arcompact_handle04_1e(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_1f(OPS_32); + + ARCOMPACT_RETTYPE arcompact_handle04_24(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_25(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_26(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_27(OPS_32); + + ARCOMPACT_RETTYPE arcompact_handle04_2c(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2d(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2e(OPS_32); + + ARCOMPACT_RETTYPE arcompact_handle04_2f_0d(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_0e(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_0f(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_10(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_11(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_12(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_13(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_14(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_15(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_16(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_17(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_18(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_19(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_1a(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_1b(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_1c(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_1d(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_1e(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_1f(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_20(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_21(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_22(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_23(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_24(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_25(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_26(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_27(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_28(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_29(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_2a(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_2b(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_2c(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_2d(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_2e(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_2f(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_30(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_31(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_32(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_33(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_34(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_35(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_36(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_37(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_38(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_39(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_3a(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_3b(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_3c(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_3d(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_3e(OPS_32); + + ARCOMPACT_RETTYPE arcompact_handle04_2f_3f_00(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_3f_06(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_3f_07(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_3f_08(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_3f_09(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_3f_0a(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_3f_0b(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_3f_0c(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_3f_0d(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_3f_0e(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_3f_0f(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_3f_10(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_3f_11(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_3f_12(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_3f_13(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_3f_14(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_3f_15(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_3f_16(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_3f_17(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_3f_18(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_3f_19(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_3f_1a(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_3f_1b(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_3f_1c(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_3f_1d(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_3f_1e(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_3f_1f(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_3f_20(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_3f_21(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_3f_22(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_3f_23(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_3f_24(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_3f_25(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_3f_26(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_3f_27(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_3f_28(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_3f_29(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_3f_2a(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_3f_2b(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_3f_2c(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_3f_2d(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_3f_2e(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_3f_2f(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_3f_30(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_3f_31(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_3f_32(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_3f_33(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_3f_34(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_3f_35(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_3f_36(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_3f_37(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_3f_38(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_3f_39(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_3f_3a(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_3f_3b(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_3f_3c(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_3f_3d(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_3f_3e(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_2f_3f_3f(OPS_32); + + ARCOMPACT_RETTYPE arcompact_handle05_2f_00(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_01(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_02(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_03(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_04(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_05(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_06(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_07(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_08(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_09(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_0a(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_0b(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_0c(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_0d(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_0e(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_0f(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_10(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_11(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_12(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_13(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_14(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_15(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_16(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_17(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_18(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_19(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_1a(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_1b(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_1c(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_1d(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_1e(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_1f(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_20(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_21(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_22(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_23(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_24(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_25(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_26(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_27(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_28(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_29(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_2a(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_2b(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_2c(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_2d(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_2e(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_2f(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_30(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_31(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_32(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_33(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_34(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_35(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_36(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_37(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_38(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_39(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_3a(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_3b(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_3c(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_3d(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_3e(OPS_32); + + ARCOMPACT_RETTYPE arcompact_handle05_2f_3f_00(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_3f_01(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_3f_02(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_3f_03(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_3f_04(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_3f_05(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_3f_06(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_3f_07(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_3f_08(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_3f_09(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_3f_0a(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_3f_0b(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_3f_0c(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_3f_0d(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_3f_0e(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_3f_0f(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_3f_10(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_3f_11(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_3f_12(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_3f_13(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_3f_14(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_3f_15(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_3f_16(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_3f_17(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_3f_18(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_3f_19(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_3f_1a(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_3f_1b(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_3f_1c(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_3f_1d(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_3f_1e(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_3f_1f(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_3f_20(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_3f_21(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_3f_22(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_3f_23(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_3f_24(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_3f_25(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_3f_26(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_3f_27(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_3f_28(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_3f_29(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_3f_2a(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_3f_2b(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_3f_2c(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_3f_2d(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_3f_2e(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_3f_2f(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_3f_30(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_3f_31(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_3f_32(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_3f_33(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_3f_34(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_3f_35(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_3f_36(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_3f_37(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_3f_38(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_3f_39(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_3f_3a(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_3f_3b(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_3f_3c(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_3f_3d(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_3f_3e(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2f_3f_3f(OPS_32); + + + ARCOMPACT_RETTYPE arcompact_handle04_38(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_39(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_3a(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_3b(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_3c(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_3d(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_3e(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle04_3f(OPS_32); + + ARCOMPACT_RETTYPE arcompact_handle05_09(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_0c(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_0d(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_0e(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_0f(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_10(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_11(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_12(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_13(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_14(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_15(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_16(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_17(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_18(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_19(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_1a(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_1b(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_1c(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_1d(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_1e(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_1f(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_20(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_21(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_22(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_23(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_24(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_25(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_26(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_27(OPS_32); + + ARCOMPACT_RETTYPE arcompact_handle05_2a(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2b(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2c(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2d(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_2e(OPS_32); + + ARCOMPACT_RETTYPE arcompact_handle05_30(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_31(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_32(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_33(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_34(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_35(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_36(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_37(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_38(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_39(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_3a(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_3b(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_3c(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_3d(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_3e(OPS_32); + ARCOMPACT_RETTYPE arcompact_handle05_3f(OPS_32); + + ARCOMPACT_RETTYPE arcompact_handle0f_00_04(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle0f_00_05(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle0f_00_07_02(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle0f_00_07_03(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle0f_01(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle0f_03(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle0f_08(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle0f_09(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle0f_0a(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle0f_17(OPS_16); + + ARCOMPACT_RETTYPE arcompact_handle18_05_02(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle18_05_03(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle18_05_04(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle18_05_05(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle18_05_06(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle18_05_07(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle18_06_00(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle18_06_02(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle18_06_03(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle18_06_04(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle18_06_05(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle18_06_06(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle18_06_07(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle18_06_08(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle18_06_09(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle18_06_0a(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle18_06_0b(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle18_06_0c(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle18_06_0d(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle18_06_0e(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle18_06_0f(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle18_06_10(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle18_06_12(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle18_06_13(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle18_06_14(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle18_06_15(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle18_06_16(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle18_06_17(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle18_06_18(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle18_06_19(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle18_06_1a(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle18_06_1b(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle18_06_1c(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle18_06_1d(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle18_06_1e(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle18_06_1f(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle18_07_00(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle18_07_02(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle18_07_03(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle18_07_04(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle18_07_05(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle18_07_06(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle18_07_07(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle18_07_08(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle18_07_09(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle18_07_0a(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle18_07_0b(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle18_07_0c(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle18_07_0d(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle18_07_0e(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle18_07_0f(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle18_07_10(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle18_07_12(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle18_07_13(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle18_07_14(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle18_07_15(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle18_07_16(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle18_07_17(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle18_07_18(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle18_07_19(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle18_07_1a(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle18_07_1b(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle18_07_1c(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle18_07_1d(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle18_07_1e(OPS_16); + ARCOMPACT_RETTYPE arcompact_handle18_07_1f(OPS_16); + + ARCOMPACT_RETTYPE arcompact_01_01_00_helper(OPS_32, const char* optext); + ARCOMPACT_RETTYPE arcompact_01_01_01_helper(OPS_32, const char* optext); + ARCOMPACT_RETTYPE arcompact_handle04_helper(OPS_32, const char* optext, int ignore_dst, int b_reserved); + ARCOMPACT_RETTYPE arcompact_handle04_2f_helper(OPS_32, const char* optext); + ARCOMPACT_RETTYPE arcompact_handle04_3x_helper(OPS_32, int dsize, int extend); + ARCOMPACT_RETTYPE arcompact_handle05_2f_0x_helper(OPS_32, const char* optext); + ARCOMPACT_RETTYPE arcompact_handle0c_helper(OPS_16, const char* optext); + ARCOMPACT_RETTYPE arcompact_handle0d_helper(OPS_16, const char* optext); + ARCOMPACT_RETTYPE arcompact_handle0e_0x_helper(OPS_16, const char* optext, int revop); + ARCOMPACT_RETTYPE arcompact_handle0f_00_0x_helper(OPS_16, const char* optext); + ARCOMPACT_RETTYPE arcompact_handle0f_0x_helper(OPS_16, const char* optext, int nodst); + ARCOMPACT_RETTYPE arcompact_handle_ld_helper(OPS_16, const char* optext, int shift, int swap); + ARCOMPACT_RETTYPE arcompact_handle_l7_0x_helper(OPS_16, const char* optext); + ARCOMPACT_RETTYPE arcompact_handle18_0x_helper(OPS_16, const char* optext, int st); + ARCOMPACT_RETTYPE arcompact_handle19_0x_helper(OPS_16, const char* optext, int shift, int format); + ARCOMPACT_RETTYPE arcompact_handle1e_0x_helper(OPS_16, const char* optext); + ARCOMPACT_RETTYPE arcompact_handle1e_03_0x_helper(OPS_16, const char* optext); + + + UINT32 handle_jump_to_addr(int delay, int link, UINT32 address, UINT32 next_addr); + UINT32 handle_jump_to_register(int delay, int link, UINT32 reg, UINT32 next_addr, int flag); + + ARCOMPACT_RETTYPE get_insruction(OPS_32); + + ARCOMPACT_HANDLER04_TYPE_PM(04_00) + ARCOMPACT_HANDLER04_TYPE_PM(04_02) + ARCOMPACT_HANDLER04_TYPE_PM(04_04) + ARCOMPACT_HANDLER04_TYPE_PM(04_05) + ARCOMPACT_HANDLER04_TYPE_PM(04_06) + ARCOMPACT_HANDLER04_TYPE_PM(04_07) + ARCOMPACT_HANDLER04_TYPE_PM(04_0a) + ARCOMPACT_HANDLER04_TYPE_PM(04_0e) + ARCOMPACT_HANDLER04_TYPE_PM(04_0f) + ARCOMPACT_HANDLER04_TYPE_PM(04_13) + ARCOMPACT_HANDLER04_TYPE_PM(04_14) + ARCOMPACT_HANDLER04_TYPE_PM(04_15) + ARCOMPACT_HANDLER04_TYPE_PM(04_16) + ARCOMPACT_HANDLER04_TYPE_PM(04_17) + ARCOMPACT_HANDLER04_TYPE_PM(04_18) + ARCOMPACT_HANDLER04_TYPE_PM(04_19) + ARCOMPACT_HANDLER04_TYPE_PM(04_20) + ARCOMPACT_HANDLER04_TYPE_PM(04_21) + ARCOMPACT_HANDLER04_TYPE_PM(04_2a) + ARCOMPACT_HANDLER04_TYPE_PM(04_2b) + + ARCOMPACT_HANDLER04_TYPE_PM(04_2f_02) + ARCOMPACT_HANDLER04_TYPE_PM(04_2f_03) + ARCOMPACT_HANDLER04_TYPE_PM(04_2f_07) + ARCOMPACT_HANDLER04_TYPE_PM(04_2f_08) + + ARCOMPACT_HANDLER04_TYPE_PM(05_00) + ARCOMPACT_HANDLER04_TYPE_PM(05_01) + + +private: + const address_space_config m_program_config; + const address_space_config m_io_config; + + UINT32 m_pc; + + address_space *m_program; + address_space *m_io; + + int m_icount; + + UINT32 m_debugger_temp; + + void unimplemented_opcode(UINT16 op); + + inline UINT32 READ32(UINT32 address) { return m_program->read_dword(address << 2); } + inline void WRITE32(UINT32 address, UINT32 data) { m_program->write_dword(address << 2, data); } + inline UINT16 READ16(UINT32 address) { return m_program->read_word(address << 1); } + inline void WRITE16(UINT32 address, UINT16 data){ m_program->write_word(address << 1, data); } + inline UINT8 READ8(UINT32 address) { return m_program->read_byte(address << 0); } + inline void WRITE8(UINT32 address, UINT8 data){ m_program->write_byte(address << 0, data); } + + inline UINT64 READAUX(UINT64 address) { return m_io->read_dword(address *4); } + inline void WRITEAUX(UINT64 address, UINT32 data) { m_io->write_dword(address *4, data); } + + + int check_condition(UINT8 condition); + + UINT32 m_regs[0x40]; + + int m_delayactive; + int m_delaylinks; + UINT32 m_delayjump; + +// f e d c| b a 9 8| 7 6 5 4| 3 2 1 0 +// - - - L| Z N C V| U DE AE A2|A1 E2 E1 H + UINT32 m_status32; + + UINT32 m_LP_START; + UINT32 m_LP_END; + UINT32 m_INTVECTORBASE; + +}; + +#define V_OVERFLOW_FLAG (0x00000100) +#define C_CARRY_FLAG (0x00000200) +#define N_NEGATIVE_FLAG (0x00000400) +#define Z_ZERO_FLAG (0x00000800) + +// V = overflow (set if signed operation would overflow) +#define STATUS32_SET_V (m_status32 |= V_OVERFLOW_FLAG) +#define STATUS32_CLEAR_V (m_status32 &= ~V_OVERFLOW_FLAG) +#define STATUS32_CHECK_V (m_status32 & V_OVERFLOW_FLAG) + +// C = carry (unsigned op, carry set is same condition as LO Lower Than, carry clear is same condition as HS Higher Same) +#define STATUS32_SET_C (m_status32 |= C_CARRY_FLAG) +#define STATUS32_CLEAR_C (m_status32 &= ~C_CARRY_FLAG) +#define STATUS32_CHECK_C (m_status32 & C_CARRY_FLAG) + +// N = negative (set if most significant bit of result is set) +#define STATUS32_SET_N (m_status32 |= N_NEGATIVE_FLAG) +#define STATUS32_CLEAR_N (m_status32 &= ~N_NEGATIVE_FLAG) +#define STATUS32_CHECK_N (m_status32 & N_NEGATIVE_FLAG) + +// Z = zero (set if result is zero, ie both values the same for CMP) +#define STATUS32_SET_Z (m_status32 |= Z_ZERO_FLAG) +#define STATUS32_CLEAR_Z (m_status32 &= ~Z_ZERO_FLAG) +#define STATUS32_CHECK_Z (m_status32 & Z_ZERO_FLAG) + +// Condition 0x0c (LE) +#define CONDITION_LE ((STATUS32_CHECK_Z) || (STATUS32_CHECK_N && !STATUS32_CHECK_V) || (!STATUS32_CHECK_N && STATUS32_CHECK_V)) // Z or (N and /V) or (/N and V) +#define CONDITION_EQ (STATUS32_CHECK_Z) +#define CONDITION_CS (STATUS32_CHECK_C) +#define CONDITION_LT ((STATUS32_CHECK_N && !STATUS32_CHECK_V) || (!STATUS32_CHECK_N && STATUS32_CHECK_V)) +#define CONDITION_MI (STATUS32_CHECK_N) + +extern const device_type ARCA5; + + +#endif /* __ARCOMPACT_H__ */ diff --git a/src/devices/cpu/arcompact/arcompact_common.c b/src/devices/cpu/arcompact/arcompact_common.c new file mode 100644 index 00000000000..f9b74683461 --- /dev/null +++ b/src/devices/cpu/arcompact/arcompact_common.c @@ -0,0 +1,527 @@ +// license:BSD-3-Clause +// copyright-holders:David Haywood +/*********************************\ + + ARCompact Core + +\*********************************/ + +// condition codes (basic ones are the same as arc +const char *conditions[0x20] = +{ + /* 00 */ "AL", // (aka RA - Always) + /* 01 */ "EQ", // (aka Z - Zero + /* 02 */ "NE", // (aka NZ - Non-Zero) + /* 03 */ "PL", // (aka P - Positive) + /* 04 */ "MI", // (aka N - Negative) + /* 05 */ "CS", // (aka C, LO - Carry set / Lower than) (unsigned) + /* 06 */ "CC", // (aka CC, NC, HS - Carry Clear / Higher or Same) (unsigned) + /* 07 */ "VS", // (aka V - Overflow set) + /* 08 */ "VC", // (aka NV - Overflow clear) + /* 09 */ "GT", // ( - Greater than) (signed) + /* 0a */ "GE", // ( - Greater than or Equal) (signed) + /* 0b */ "LT", // ( - Less than) (signed) + /* 0c */ "LE", // ( - Less than or Equal) (signed) + /* 0d */ "HI", // ( - Higher than) (unsigned) + /* 0e */ "LS", // ( - Lower or Same) (unsigned) + /* 0f */ "PNZ",// ( - Positive non-0 value) + /* 10 */ "0x10 Reserved", // possible CPU implementation specifics + /* 11 */ "0x11 Reserved", + /* 12 */ "0x12 Reserved", + /* 13 */ "0x13 Reserved", + /* 14 */ "0x14 Reserved", + /* 15 */ "0x15 Reserved", + /* 16 */ "0x16 Reserved", + /* 17 */ "0x17 Reserved", + /* 18 */ "0x18 Reserved", + /* 19 */ "0x19 Reserved", + /* 1a */ "0x1a Reserved", + /* 1b */ "0x1b Reserved", + /* 1c */ "0x1c Reserved", + /* 1d */ "0x1d Reserved", + /* 1e */ "0x1e Reserved", + /* 1f */ "0x1f Reserved" +}; + +#define UNUSED_REG "unusedreg" + +#define AUX_UNUSED_16 \ + /* 0xxx0 */ UNUSED_REG, /* 0xxx1 */ UNUSED_REG, /* 0xxx2 */ UNUSED_REG, /* 0xxx3 */ UNUSED_REG, /* 0xxx4 */ UNUSED_REG, /* 0xxx5 */ UNUSED_REG, /* 0xxx6 */ UNUSED_REG, /* 0xxx7 */ UNUSED_REG, /* 0xxx8 */ UNUSED_REG, /* 0xxx9 */ UNUSED_REG, /* 0xxxa */ UNUSED_REG, /* 0xxxb */ UNUSED_REG, /* 0xxxc */ UNUSED_REG, /* 0xxxd */ UNUSED_REG, /* 0xxxe */ UNUSED_REG, /* 0xxxf */ UNUSED_REG, + +// the Auxiliary Register set is actually a 2^32 dword address space (so 16 GB / 34-bit) +// this table just allows us to improve the debugger display for some of the common core / internal ones +const char *auxregnames[0x420] = +{ + /* 0x000 */ "STATUS", + /* 0x001 */ "SEMAPHOR", + /* 0x002 */ "LP_START", + /* 0x003 */ "LP_END", + /* 0x004 */ "IDENTITY", + /* 0x005 */ "DEBUG", + /* 0x006 */ "PC", + /* 0x007 */ UNUSED_REG, + /* 0x008 */ UNUSED_REG, + /* 0x009 */ UNUSED_REG, + /* 0x00a */ "STATUS32", + /* 0x00b */ "STATUS32_L1", + /* 0x00c */ "STATUS32_L2", + /* 0x00d */ UNUSED_REG, + /* 0x00e */ UNUSED_REG, + /* 0x00f */ UNUSED_REG, + + /* 0x010 */ UNUSED_REG, + /* 0x011 */ UNUSED_REG, + /* 0x012 */ "MULHI", // extension register + /* 0x013 */ UNUSED_REG, + /* 0x014 */ UNUSED_REG, + /* 0x015 */ UNUSED_REG, + /* 0x016 */ UNUSED_REG, + /* 0x017 */ UNUSED_REG, + /* 0x018 */ UNUSED_REG, + /* 0x019 */ UNUSED_REG, + /* 0x01a */ UNUSED_REG, + /* 0x01b */ UNUSED_REG, + /* 0x01c */ UNUSED_REG, + /* 0x01d */ UNUSED_REG, + /* 0x01e */ UNUSED_REG, + /* 0x01f */ UNUSED_REG, + + /* 0x020 */ UNUSED_REG, + /* 0x021 */ "COUNT0", + /* 0x022 */ "CONTROL0", + /* 0x023 */ "LIMIT0", + /* 0x024 */ UNUSED_REG, + /* 0x025 */ "INT_VECTOR_BASE", + /* 0x026 */ UNUSED_REG, + /* 0x027 */ UNUSED_REG, + /* 0x028 */ UNUSED_REG, + /* 0x029 */ UNUSED_REG, + /* 0x02a */ UNUSED_REG, + /* 0x02b */ UNUSED_REG, + /* 0x02c */ UNUSED_REG, + /* 0x02d */ UNUSED_REG, + /* 0x02e */ UNUSED_REG, + /* 0x02f */ UNUSED_REG, + AUX_UNUSED_16 /* 0x030 - 0x03f */ + /* 0x040 */ UNUSED_REG, + /* 0x041 */ "AUX_MACMODE", + /* 0x042 */ UNUSED_REG, + /* 0x043 */ "AUX_IRQLV12", + /* 0x044 */ UNUSED_REG, + /* 0x045 */ UNUSED_REG, + /* 0x046 */ UNUSED_REG, + /* 0x047 */ UNUSED_REG, + /* 0x048 */ UNUSED_REG, + /* 0x049 */ UNUSED_REG, + /* 0x04a */ UNUSED_REG, + /* 0x04b */ UNUSED_REG, + /* 0x04c */ UNUSED_REG, + /* 0x04d */ UNUSED_REG, + /* 0x04e */ UNUSED_REG, + /* 0x04f */ UNUSED_REG, + AUX_UNUSED_16 /* 0x050 - 0x05f */ + // build configuration registers 0x060 - 0x07f + /* 0x060 */ "RESERVED AUX 0x60",/* 0x061 */ "RESERVED AUX 0x61",/* 0x062 */ "RESERVED AUX 0x62",/* 0x063 */ "RESERVED AUX 0x63",/* 0x064 */ "RESERVED AUX 0x64",/* 0x065 */ "RESERVED AUX 0x65",/* 0x066 */ "RESERVED AUX 0x66",/* 0x067 */ "RESERVED AUX 0x67",/* 0x068 */ "RESERVED AUX 0x68",/* 0x069 */ "RESERVED AUX 0x69",/* 0x06a */ "RESERVED AUX 0x6a",/* 0x06b */ "RESERVED AUX 0x6b",/* 0x06c */ "RESERVED AUX 0x6c",/* 0x06d */ "RESERVED AUX 0x6d",/* 0x06e */ "RESERVED AUX 0x6e",/* 0x06f */ "RESERVED AUX 0x6f", + /* 0x070 */ "RESERVED AUX 0x70",/* 0x071 */ "RESERVED AUX 0x71",/* 0x072 */ "RESERVED AUX 0x72",/* 0x073 */ "RESERVED AUX 0x73",/* 0x074 */ "RESERVED AUX 0x74",/* 0x075 */ "RESERVED AUX 0x75",/* 0x076 */ "RESERVED AUX 0x76",/* 0x077 */ "RESERVED AUX 0x77",/* 0x078 */ "RESERVED AUX 0x78",/* 0x079 */ "RESERVED AUX 0x79",/* 0x07a */ "RESERVED AUX 0x7a",/* 0x07b */ "RESERVED AUX 0x7b",/* 0x07c */ "RESERVED AUX 0x7c",/* 0x07d */ "RESERVED AUX 0x7d",/* 0x07e */ "RESERVED AUX 0x7e",/* 0x07f */ "RESERVED AUX 0x7f", + AUX_UNUSED_16 /* 0x080 - 0x08f */ + AUX_UNUSED_16 /* 0x090 - 0x09f */ + AUX_UNUSED_16 /* 0x0a0 - 0x0af */ + AUX_UNUSED_16 /* 0x0b0 - 0x0bf */ + // build configuration registers 0x0c0 - 0x0ff + /* 0x0c0 */ "RESERVED AUX 0xc0",/* 0x0c1 */ "RESERVED AUX 0xc1",/* 0x0c2 */ "RESERVED AUX 0xc2",/* 0x0c3 */ "RESERVED AUX 0xc3",/* 0x0c4 */ "RESERVED AUX 0xc4",/* 0x0c5 */ "RESERVED AUX 0xc5",/* 0x0c6 */ "RESERVED AUX 0xc6",/* 0x0c7 */ "RESERVED AUX 0xc7",/* 0x0c8 */ "RESERVED AUX 0xc8",/* 0x0c9 */ "RESERVED AUX 0xc9",/* 0x0ca */ "RESERVED AUX 0xca",/* 0x0cb */ "RESERVED AUX 0xcb",/* 0x0cc */ "RESERVED AUX 0xcc",/* 0x0cd */ "RESERVED AUX 0xcd",/* 0x0ce */ "RESERVED AUX 0xce",/* 0x0cf */ "RESERVED AUX 0xcf", + /* 0x0d0 */ "RESERVED AUX 0xd0",/* 0x0d1 */ "RESERVED AUX 0xd1",/* 0x0d2 */ "RESERVED AUX 0xd2",/* 0x0d3 */ "RESERVED AUX 0xd3",/* 0x0d4 */ "RESERVED AUX 0xd4",/* 0x0d5 */ "RESERVED AUX 0xd5",/* 0x0d6 */ "RESERVED AUX 0xd6",/* 0x0d7 */ "RESERVED AUX 0xd7",/* 0x0d8 */ "RESERVED AUX 0xd8",/* 0x0d9 */ "RESERVED AUX 0xd9",/* 0x0da */ "RESERVED AUX 0xda",/* 0x0db */ "RESERVED AUX 0xdb",/* 0x0dc */ "RESERVED AUX 0xdc",/* 0x0dd */ "RESERVED AUX 0xdd",/* 0x0de */ "RESERVED AUX 0xde",/* 0x0df */ "RESERVED AUX 0xdf", + /* 0x0e0 */ "RESERVED AUX 0xe0",/* 0x0e1 */ "RESERVED AUX 0xe1",/* 0x0e2 */ "RESERVED AUX 0xe2",/* 0x0e3 */ "RESERVED AUX 0xe3",/* 0x0e4 */ "RESERVED AUX 0xe4",/* 0x0e5 */ "RESERVED AUX 0xe5",/* 0x0e6 */ "RESERVED AUX 0xe6",/* 0x0e7 */ "RESERVED AUX 0xe7",/* 0x0e8 */ "RESERVED AUX 0xe8",/* 0x0e9 */ "RESERVED AUX 0xe9",/* 0x0ea */ "RESERVED AUX 0xea",/* 0x0eb */ "RESERVED AUX 0xeb",/* 0x0ec */ "RESERVED AUX 0xec",/* 0x0ed */ "RESERVED AUX 0xed",/* 0x0ee */ "RESERVED AUX 0xee",/* 0x0ef */ "RESERVED AUX 0xef", + /* 0x0f0 */ "RESERVED AUX 0xf0",/* 0x0f1 */ "RESERVED AUX 0xf1",/* 0x0f2 */ "RESERVED AUX 0xf2",/* 0x0f3 */ "RESERVED AUX 0xf3",/* 0x0f4 */ "RESERVED AUX 0xf4",/* 0x0f5 */ "RESERVED AUX 0xf5",/* 0x0f6 */ "RESERVED AUX 0xf6",/* 0x0f7 */ "RESERVED AUX 0xf7",/* 0x0f8 */ "RESERVED AUX 0xf8",/* 0x0f9 */ "RESERVED AUX 0xf9",/* 0x0fa */ "RESERVED AUX 0xfa",/* 0x0fb */ "RESERVED AUX 0xfb",/* 0x0fc */ "RESERVED AUX 0xfc",/* 0x0fd */ "RESERVED AUX 0xfd",/* 0x0fe */ "RESERVED AUX 0xfe",/* 0x0ff */ "RESERVED AUX 0xff", + /* 0x100 */ "COUNT1", + /* 0x101 */ "CONTROL1", + /* 0x102 */ "LIMIT1", + /* 0x103 */ UNUSED_REG, + /* 0x104 */ UNUSED_REG, + /* 0x105 */ UNUSED_REG, + /* 0x106 */ UNUSED_REG, + /* 0x107 */ UNUSED_REG, + /* 0x108 */ UNUSED_REG, + /* 0x109 */ UNUSED_REG, + /* 0x10a */ UNUSED_REG, + /* 0x10b */ UNUSED_REG, + /* 0x10c */ UNUSED_REG, + /* 0x10d */ UNUSED_REG, + /* 0x10e */ UNUSED_REG, + /* 0x10f */ UNUSED_REG, + AUX_UNUSED_16 /* 0x110 - 0x11f */ + AUX_UNUSED_16 /* 0x120 - 0x12f */ + AUX_UNUSED_16 /* 0x130 - 0x13f */ + AUX_UNUSED_16 /* 0x140 - 0x14f */ + AUX_UNUSED_16 /* 0x150 - 0x15f */ + AUX_UNUSED_16 /* 0x160 - 0x16f */ + AUX_UNUSED_16 /* 0x170 - 0x17f */ + AUX_UNUSED_16 /* 0x180 - 0x18f */ + AUX_UNUSED_16 /* 0x190 - 0x19f */ + AUX_UNUSED_16 /* 0x1a0 - 0x1af */ + AUX_UNUSED_16 /* 0x1b0 - 0x1bf */ + AUX_UNUSED_16 /* 0x1c0 - 0x1cf */ + AUX_UNUSED_16 /* 0x1d0 - 0x1df */ + AUX_UNUSED_16 /* 0x1e0 - 0x1ef */ + AUX_UNUSED_16 /* 0x1f0 - 0x1ff */ + /* 0x200 */ "AUX_IRQ_LEV", + /* 0x201 */ "AUX_IRQ_HINT", + /* 0x203 */ UNUSED_REG, + /* 0x203 */ UNUSED_REG, + /* 0x204 */ UNUSED_REG, + /* 0x205 */ UNUSED_REG, + /* 0x206 */ UNUSED_REG, + /* 0x207 */ UNUSED_REG, + /* 0x208 */ UNUSED_REG, + /* 0x209 */ UNUSED_REG, + /* 0x20a */ UNUSED_REG, + /* 0x20b */ UNUSED_REG, + /* 0x20c */ UNUSED_REG, + /* 0x20d */ UNUSED_REG, + /* 0x20e */ UNUSED_REG, + /* 0x20f */ UNUSED_REG, + AUX_UNUSED_16 /* 0x210 - 0x21f */ + AUX_UNUSED_16 /* 0x220 - 0x22f */ + AUX_UNUSED_16 /* 0x230 - 0x23f */ + AUX_UNUSED_16 /* 0x240 - 0x24f */ + AUX_UNUSED_16 /* 0x250 - 0x25f */ + AUX_UNUSED_16 /* 0x260 - 0x26f */ + AUX_UNUSED_16 /* 0x270 - 0x27f */ + AUX_UNUSED_16 /* 0x280 - 0x28f */ + AUX_UNUSED_16 /* 0x290 - 0x29f */ + AUX_UNUSED_16 /* 0x2a0 - 0x2af */ + AUX_UNUSED_16 /* 0x2b0 - 0x2bf */ + AUX_UNUSED_16 /* 0x2c0 - 0x2cf */ + AUX_UNUSED_16 /* 0x2d0 - 0x2df */ + AUX_UNUSED_16 /* 0x2e0 - 0x2ef */ + AUX_UNUSED_16 /* 0x2f0 - 0x2ff */ + + AUX_UNUSED_16 /* 0x300 - 0x30f */ + AUX_UNUSED_16 /* 0x310 - 0x31f */ + AUX_UNUSED_16 /* 0x320 - 0x32f */ + AUX_UNUSED_16 /* 0x330 - 0x33f */ + AUX_UNUSED_16 /* 0x340 - 0x34f */ + AUX_UNUSED_16 /* 0x350 - 0x35f */ + AUX_UNUSED_16 /* 0x360 - 0x36f */ + AUX_UNUSED_16 /* 0x370 - 0x37f */ + AUX_UNUSED_16 /* 0x380 - 0x38f */ + AUX_UNUSED_16 /* 0x390 - 0x39f */ + AUX_UNUSED_16 /* 0x3a0 - 0x3af */ + AUX_UNUSED_16 /* 0x3b0 - 0x3bf */ + AUX_UNUSED_16 /* 0x3c0 - 0x3cf */ + AUX_UNUSED_16 /* 0x3d0 - 0x3df */ + AUX_UNUSED_16 /* 0x3e0 - 0x3ef */ + AUX_UNUSED_16 /* 0x3f0 - 0x3ff */ + + /* 0x400 */ "ERET", + /* 0x401 */ "ERBTA", + /* 0x403 */ "ERSTATUS", + /* 0x403 */ "ECR", + /* 0x404 */ "EFA", + /* 0x405 */ UNUSED_REG, + /* 0x406 */ UNUSED_REG, + /* 0x407 */ UNUSED_REG, + /* 0x408 */ UNUSED_REG, + /* 0x409 */ UNUSED_REG, + /* 0x40a */ "ICAUSE1", + /* 0x40b */ "ICAUSE2", + /* 0x40c */ "AUX_IENABLE", + /* 0x40d */ "AUX_ITRIGGER", + /* 0x40e */ UNUSED_REG, + /* 0x40f */ UNUSED_REG, + + /* 0x410 */ "XPU", + /* 0x411 */ UNUSED_REG, + /* 0x412 */ "BTA", + /* 0x413 */ "BTA_L1", + /* 0x414 */ "BTA_L2", + /* 0x415 */ "AUX_IRQ_PULSE_CANCEL", + /* 0x416 */ "AUX_IRQ_PENDING", + /* 0x417 */ UNUSED_REG, + /* 0x418 */ UNUSED_REG, + /* 0x419 */ UNUSED_REG, + /* 0x41a */ UNUSED_REG, + /* 0x41b */ UNUSED_REG, + /* 0x41c */ UNUSED_REG, + /* 0x41d */ UNUSED_REG, + /* 0x41e */ UNUSED_REG, + /* 0x41f */ UNUSED_REG +}; + +//#define EXPLICIT_EXTENSIONS + +const char *datasize[0x4] = +{ +#ifdef EXPLICIT_EXTENSIONS + /* 00 */ ".L", // Dword (default) (can use no extension, using .L to be explicit) +#else + /* 00 */ "",// Dword (default) +#endif + /* 01 */ ".B", // Byte + /* 02 */ ".W", // Word + /* 03 */ "." +}; + +const char *dataextend[0x2] = +{ +#ifdef EXPLICIT_EXTENSIONS + /* 00 */ ".ZX", // Zero Extend (can use no extension, using .ZX to be explicit) +#else + /* 00 */ "", // Zero Extend +#endif + /* 01 */ ".X" // Sign Extend +}; + +const char *addressmode[0x4] = +{ +#ifdef EXPLICIT_EXTENSIONS + /* 00 */ ".AN", // No Writeback (can use no extension, using .AN to be explicit) +#else + /* 00 */ "", // No Writeback +#endif + /* 01 */ ".AW", // Writeback pre memory access + /* 02 */ ".AB", // Writeback post memory access + /* 03 */ ".AS" // scaled +}; + +const char *cachebit[0x2] = +{ +#ifdef EXPLICIT_EXTENSIONS + /* 00 */ ".EN", // Data Cache Enabled (can use no extension, using .EN to be explicit) +#else + /* 00 */ "", // Data Cache Enabled +#endif + /* 01 */ ".DI" // Direct to Memory (Cache Bypass) +}; + +const char *flagbit[0x2] = +{ +#ifdef EXPLICIT_EXTENSIONS + /* 00 */ ".NF", // Don't Set Flags (can use no extension, using .NF to be explicit) +#else + /* 00 */ "", // Don't Set Flags +#endif + /* 01 */ ".F" // Set Flags +}; + +const char *delaybit[0x2] = +{ + /* 00 */ ".ND", // Don't execute opcode in delay slot + /* 01 */ ".D" // Execute Opcode in delay slot +}; + + +const char *regnames[0x40] = +{ + /* 00 */ "r0", + /* 01 */ "r1", + /* 02 */ "r2", + /* 03 */ "r3", + /* 04 */ "r4", + /* 05 */ "r5", + /* 06 */ "r6", + /* 07 */ "r7", + /* 08 */ "r8", + /* 09 */ "r9", + /* 0a */ "r10", + /* 0b */ "r11", + /* 0c */ "r12", + /* 0d */ "r13", + /* 0e */ "r14", + /* 0f */ "r15", + + /* 10 */ "r16", + /* 11 */ "r17", + /* 12 */ "r18", + /* 13 */ "r19", + /* 14 */ "r20", + /* 15 */ "r21", + /* 16 */ "r22", + /* 17 */ "r23", + /* 18 */ "r24", + /* 19 */ "r25", + /* 1a */ "r26_GP", + /* 1b */ "r27_FP", + /* 1c */ "r28_SP", + /* 1d */ "r29_ILINK1", + /* 1e */ "r30_ILINK2", + /* 1f */ "r31_BLINK", + + /* 20 */ "r32(ext)", + /* 21 */ "r33(ext)", + /* 22 */ "r34(ext)", + /* 23 */ "r35(ext)", + /* 24 */ "r36(ext)", + /* 25 */ "r37(ext)", + /* 26 */ "r38(ext)", + /* 27 */ "r39(ext)", + /* 28 */ "r40(ext)", + /* 29 */ "r41(ext)", + /* 2a */ "r42(ext)", + /* 2b */ "r43(ext)", + /* 2c */ "r44(ext)", + /* 2d */ "r45(ext)", + /* 2e */ "r46(ext)", + /* 2f */ "r47(ext)", + + /* 30 */ "r48(ext)", + /* 31 */ "r49(ext)", + /* 32 */ "r50(ext)", + /* 33 */ "r51(ext)", + /* 34 */ "r52(ext)", + /* 35 */ "r53(ext)", + /* 36 */ "r54(ext)", + /* 37 */ "r55(ext)", + /* 38 */ "r56(ext)", + /* 39 */ "r57(M-LO)", // MLO (result registers for optional multply functions) + /* 3a */ "r58(M-MID)", // MMID + /* 3b */ "r59(M-HI)", // MHI + /* 3c */ "r60(LP_COUNT)", + /* 3d */ "r61(reserved)", + /* 3e */ "r62(LIMM)", // use Long Immediate Data instead of register + /* 3f */ "r63(PCL)" +}; + +#if 0 +const char *opcodes_temp[0x40] = +{ + /* 00 */ "0x00", + /* 01 */ "0x01", + /* 02 */ "0x02", + /* 03 */ "0x03", + /* 04 */ "0x04", + /* 05 */ "0x05", + /* 06 */ "0x06", + /* 07 */ "0x07", + /* 08 */ "0x08", + /* 09 */ "0x09", + /* 0a */ "0x0a", + /* 0b */ "0x0b", + /* 0c */ "0x0c", + /* 0d */ "0x0d", + /* 0e */ "0x0e", + /* 0f */ "0x0f", + + /* 10 */ "0x10", + /* 11 */ "0x11", + /* 12 */ "0x12", + /* 13 */ "0x13", + /* 14 */ "0x14", + /* 15 */ "0x15", + /* 16 */ "0x16", + /* 17 */ "0x17", + /* 18 */ "0x18", + /* 19 */ "0x19", + /* 1a */ "0x1a", + /* 1b */ "0x1b", + /* 1c */ "0x1c", + /* 1d */ "0x1d", + /* 1e */ "0x1e", + /* 1f */ "0x1f", + + /* 20 */ "0x20", + /* 21 */ "0x21", + /* 22 */ "0x22", + /* 23 */ "0x23", + /* 24 */ "0x24", + /* 25 */ "0x25", + /* 26 */ "0x26", + /* 27 */ "0x27", + /* 28 */ "0x28", + /* 29 */ "0x29", + /* 2a */ "0x2a", + /* 2b */ "0x2b", + /* 2c */ "0x2c", + /* 2d */ "0x2d", + /* 2e */ "0x2e", + /* 2f */ "0x2f", + + /* 30 */ "0x30", + /* 31 */ "0x31", + /* 32 */ "0x32", + /* 33 */ "0x33", + /* 34 */ "0x34", + /* 35 */ "0x35", + /* 36 */ "0x36", + /* 37 */ "0x37", + /* 38 */ "0x38", + /* 39 */ "0x39", + /* 3a */ "0x3a", + /* 3b */ "0x3b", + /* 3c */ "0x3c", + /* 3d */ "0x3d", + /* 3e */ "0x3e", + /* 3f */ "0x3f", +}; +#endif + + +const char *opcodes_04[0x40] = +{ + /* 00 */ "ADD", + /* 01 */ "ADC", + /* 02 */ "SUB", + /* 03 */ "SBC", + /* 04 */ "AND", + /* 05 */ "OR", + /* 06 */ "BIC", + /* 07 */ "XOR", + /* 08 */ "MAX", + /* 09 */ "MIN", + /* 0a */ "MOV", + /* 0b */ "TST", + /* 0c */ "CMP", + /* 0d */ "RCMP", + /* 0e */ "RSUB", + /* 0f */ "BSET", + + /* 10 */ "BCLR", + /* 11 */ "BTST", + /* 12 */ "BXOR", + /* 13 */ "BSMK", + /* 14 */ "ADD1", + /* 15 */ "ADD2", + /* 16 */ "ADD3", + /* 17 */ "SUB1", + /* 18 */ "SUB2", + /* 19 */ "SUB3", + /* 1a */ "MPY", + /* 1b */ "MPYH", + /* 1c */ "MPYHU", + /* 1d */ "MPYU", + /* 1e */ "0x1e", + /* 1f */ "0x1f", + + /* 20 */ "Jcc", + /* 21 */ "Jcc.D", + /* 22 */ "JLcc", + /* 23 */ "JLcc.D", + /* 24 */ "0x24", + /* 25 */ "0x25", + /* 26 */ "0x26", + /* 27 */ "0x27", + /* 28 */ "LPcc", + /* 29 */ "FLAG", + /* 2a */ "LR", + /* 2b */ "SR", + /* 2c */ "0x2c", + /* 2d */ "0x2d", + /* 2e */ "0x2e", + /* 2f */ "SOP table", + + /* 30 */ "LD", + /* 31 */ "LD", + /* 32 */ "LD", + /* 33 */ "LD", + /* 34 */ "LD", + /* 35 */ "LD", + /* 36 */ "LD", + /* 37 */ "LD", + /* 38 */ "0x38", + /* 39 */ "0x39", + /* 3a */ "0x3a", + /* 3b */ "0x3b", + /* 3c */ "0x3c", + /* 3d */ "0x3d", + /* 3e */ "0x3e", + /* 3f */ "0x3f", +}; diff --git a/src/devices/cpu/arcompact/arcompact_common.h b/src/devices/cpu/arcompact/arcompact_common.h new file mode 100644 index 00000000000..86259ba2972 --- /dev/null +++ b/src/devices/cpu/arcompact/arcompact_common.h @@ -0,0 +1,24 @@ +// license:BSD-3-Clause +// copyright-holders:David Haywood +/*********************************\ + + ARCompact Core + +\*********************************/ + +extern const char *conditions[0x20]; +extern const char *auxregnames[0x420]; +extern const char *datasize[0x4]; +extern const char *dataextend[0x2]; +extern const char *addressmode[0x4]; +extern const char *cachebit[0x2]; +extern const char *flagbit[0x2]; +extern const char *delaybit[0x2]; +extern const char *regnames[0x40]; +extern const char *opcodes_04[0x40]; + +#define REG_BLINK (0x1f) // r31 +#define REG_SP (0x1c) // r28 +#define REG_ILINK1 (0x1d) // r29 +#define REG_ILINK2 (0x1e) // r30 +#define REG_LP_COUNT (0x3c) // r60 diff --git a/src/devices/cpu/arcompact/arcompact_execute.c b/src/devices/cpu/arcompact/arcompact_execute.c new file mode 100644 index 00000000000..ae241987190 --- /dev/null +++ b/src/devices/cpu/arcompact/arcompact_execute.c @@ -0,0 +1,3697 @@ +// license:BSD-3-Clause +// copyright-holders:David Haywood + +#include "emu.h" +#include "debugger.h" +#include "arcompact.h" +#include "arcompact_common.h" + +#define ARCOMPACT_LOGGING 1 + +#define arcompact_fatal if (ARCOMPACT_LOGGING) fatalerror +#define arcompact_log if (ARCOMPACT_LOGGING) fatalerror + + +void arcompact_device::execute_run() +{ + //UINT32 lres; + //lres = 0; + + while (m_icount > 0) + { + debugger_instruction_hook(this, m_pc); + +// printf("new pc %04x\n", m_pc); + + if (m_delayactive) + { + UINT16 op = READ16((m_pc + 0) >> 1); + m_pc = get_insruction(op); + if (m_delaylinks) m_regs[REG_BLINK] = m_pc; + + m_pc = m_delayjump; + m_delayactive = 0; m_delaylinks = 0; + } + else + { + UINT16 op = READ16((m_pc + 0) >> 1); + m_pc = get_insruction(op); + } + + // hardware loops + if (m_pc == m_LP_END) + { + if (m_regs[REG_LP_COUNT] != 1) + { + m_pc = m_LP_START; + } + m_regs[REG_LP_COUNT]--; + + } + + m_icount--; + } + +} + + +#define GET_01_01_01_BRANCH_ADDR \ + INT32 address = (op & 0x00fe0000) >> 17; \ + address |= ((op & 0x00008000) >> 15) << 7; \ + if (address & 0x80) address = -0x80 + (address & 0x7f); + +#define GROUP_0e_GET_h \ + h = ((op & 0x0007) << 3); \ + h |= ((op & 0x00e0) >> 5); +#define COMMON32_GET_breg \ + int b_temp = (op & 0x07000000) >> 24; \ + int B_temp = (op & 0x00007000) >> 12; \ + int breg = b_temp | (B_temp << 3); +#define COMMON32_GET_creg \ + int creg = (op & 0x00000fc0) >> 6; +#define COMMON32_GET_u6 \ + int u = (op & 0x00000fc0) >> 6; +#define COMMON32_GET_areg \ + int areg = (op & 0x0000003f) >> 0; +#define COMMON32_GET_areg_reserved \ + int ares = (op & 0x0000003f) >> 0; +#define COMMON32_GET_F \ + int F = (op & 0x00008000) >> 15; +#define COMMON32_GET_p \ + int p = (op & 0x00c00000) >> 22; + +#define COMMON32_GET_s12 \ + int S_temp = (op & 0x0000003f) >> 0; \ + int s_temp = (op & 0x00000fc0) >> 6; \ + INT32 S = s_temp | (S_temp<<6); \ + if (S & 0x800) S = -0x800 + (S&0x7ff); /* sign extend */ +#define COMMON32_GET_CONDITION \ + UINT8 condition = op & 0x0000001f; + + +#define COMMON16_GET_breg \ + breg = ((op & 0x0700) >>8); +#define COMMON16_GET_creg \ + creg = ((op & 0x00e0) >>5); +#define COMMON16_GET_areg \ + areg = ((op & 0x0007) >>0); +#define COMMON16_GET_u3 \ + u = ((op & 0x0007) >>0); +#define COMMON16_GET_u5 \ + u = ((op & 0x001f) >>0); +#define COMMON16_GET_u8 \ + u = ((op & 0x00ff) >>0); +#define COMMON16_GET_u7 \ + u = ((op & 0x007f) >>0); +#define COMMON16_GET_s9 \ + s = ((op & 0x01ff) >>0); +// registers used in 16-bit opcodes hae a limited range +// and can only address registers r0-r3 and r12-r15 + +#define REG_16BIT_RANGE(_reg_) \ + if (_reg_>3) _reg_+= 8; + +#define GET_LIMM_32 \ + limm = (READ16((m_pc + 4) >> 1) << 16); \ + limm |= READ16((m_pc + 6) >> 1); +#define GET_LIMM_16 \ + limm = (READ16((m_pc + 2) >> 1) << 16); \ + limm |= READ16((m_pc + 4) >> 1); + +#define PC_ALIGNED32 \ + (m_pc&0xfffffffc) + +int arcompact_device::check_condition(UINT8 condition) +{ + switch (condition & 0x1f) + { + case 0x00: return 1; // AL + case 0x01: return CONDITION_EQ; + case 0x02: return !CONDITION_EQ; // NE + case 0x03: fatalerror("unhandled condition check %s", conditions[condition]); return -1; + case 0x04: return CONDITION_MI; // MI (N) + case 0x05: return CONDITION_CS; // CS (Carry Set / Lower than) + case 0x06: fatalerror("unhandled condition check %s", conditions[condition]); return -1; + case 0x07: fatalerror("unhandled condition check %s", conditions[condition]); return -1; + case 0x08: fatalerror("unhandled condition check %s", conditions[condition]); return -1; + case 0x09: fatalerror("unhandled condition check %s", conditions[condition]); return -1; + case 0x0a: fatalerror("unhandled condition check %s", conditions[condition]); return -1; + case 0x0b: fatalerror("unhandled condition check %s", conditions[condition]); return -1; + case 0x0c: fatalerror("unhandled condition check %s", conditions[condition]); return -1; + case 0x0d: fatalerror("unhandled condition check %s", conditions[condition]); return -1; + case 0x0e: fatalerror("unhandled condition check %s", conditions[condition]); return -1; + case 0x0f: fatalerror("unhandled condition check %s", conditions[condition]); return -1; + case 0x10: fatalerror("unhandled condition check %s", conditions[condition]); return -1; + case 0x11: fatalerror("unhandled condition check %s", conditions[condition]); return -1; + case 0x12: fatalerror("unhandled condition check %s", conditions[condition]); return -1; + case 0x13: fatalerror("unhandled condition check %s", conditions[condition]); return -1; + case 0x14: fatalerror("unhandled condition check %s", conditions[condition]); return -1; + case 0x15: fatalerror("unhandled condition check %s", conditions[condition]); return -1; + case 0x16: fatalerror("unhandled condition check %s", conditions[condition]); return -1; + case 0x17: fatalerror("unhandled condition check %s", conditions[condition]); return -1; + case 0x18: fatalerror("unhandled condition check %s", conditions[condition]); return -1; + case 0x19: fatalerror("unhandled condition check %s", conditions[condition]); return -1; + case 0x1a: fatalerror("unhandled condition check %s", conditions[condition]); return -1; + case 0x1b: fatalerror("unhandled condition check %s", conditions[condition]); return -1; + case 0x1c: fatalerror("unhandled condition check %s", conditions[condition]); return -1; + case 0x1d: fatalerror("unhandled condition check %s", conditions[condition]); return -1; + case 0x1e: fatalerror("unhandled condition check %s", conditions[condition]); return -1; + case 0x1f: fatalerror("unhandled condition check %s", conditions[condition]); return -1; + } + + return -1; + +} + + +ARCOMPACT_RETTYPE arcompact_device::get_insruction(OPS_32) +{ + UINT8 instruction = ARCOMPACT_OPERATION; + + if (instruction < 0x0c) + { + op <<= 16; + op |= READ16((m_pc + 2) >> 1); + + switch (instruction) // 32-bit instructions (with optional extra dword for immediate data) + { + case 0x00: return arcompact_handle00(PARAMS); // Bcc + case 0x01: return arcompact_handle01(PARAMS); // BLcc/BRcc + case 0x02: return arcompact_handle02(PARAMS); // LD r+o + case 0x03: return arcompact_handle03(PARAMS); // ST r+o + case 0x04: return arcompact_handle04(PARAMS); // op a,b,c (basecase) + case 0x05: return arcompact_handle05(PARAMS); // op a,b,c (05 ARC ext) + case 0x06: return arcompact_handle06(PARAMS); // op a,b,c (06 ARC ext) + case 0x07: return arcompact_handle07(PARAMS); // op a,b,c (07 User ext) + case 0x08: return arcompact_handle08(PARAMS); // op a,b,c (08 User ext) + case 0x09: return arcompact_handle09(PARAMS); // op a,b,c (09 Market ext) + case 0x0a: return arcompact_handle0a(PARAMS); // op a,b,c (0a Market ext) + case 0x0b: return arcompact_handle0b(PARAMS); // op a,b,c (0b Market ext) + } + } + else + { + switch (instruction) // 16-bit instructions + { + case 0x0c: return arcompact_handle0c(PARAMS); // Load/Add reg-reg + case 0x0d: return arcompact_handle0d(PARAMS); // Add/Sub/Shft imm + case 0x0e: return arcompact_handle0e(PARAMS); // Mov/Cmp/Add + case 0x0f: return arcompact_handle0f(PARAMS); // op_S b,b,c (single 16-bit ops) + case 0x10: return arcompact_handle10(PARAMS); // LD_S + case 0x11: return arcompact_handle11(PARAMS); // LDB_S + case 0x12: return arcompact_handle12(PARAMS); // LDW_S + case 0x13: return arcompact_handle13(PARAMS); // LSW_S.X + case 0x14: return arcompact_handle14(PARAMS); // ST_S + case 0x15: return arcompact_handle15(PARAMS); // STB_S + case 0x16: return arcompact_handle16(PARAMS); // STW_S + case 0x17: return arcompact_handle17(PARAMS); // Shift/Sub/Bit + case 0x18: return arcompact_handle18(PARAMS); // Stack Instr + case 0x19: return arcompact_handle19(PARAMS); // GP Instr + case 0x1a: return arcompact_handle1a(PARAMS); // PCL Instr + case 0x1b: return arcompact_handle1b(PARAMS); // MOV_S + case 0x1c: return arcompact_handle1c(PARAMS); // ADD_S/CMP_S + case 0x1d: return arcompact_handle1d(PARAMS); // BRcc_S + case 0x1e: return arcompact_handle1e(PARAMS); // Bcc_S + case 0x1f: return arcompact_handle1f(PARAMS); // BL_S + } + } + + return 0; +} + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle00(OPS_32) +{ + UINT8 subinstr = (op & 0x00010000) >> 16; + + switch (subinstr) + { + case 0x00: return arcompact_handle00_00(PARAMS); // Branch Conditionally + case 0x01: return arcompact_handle00_01(PARAMS); // Branch Unconditionally Far + } + + return 0; +} + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle01(OPS_32) +{ + UINT8 subinstr = (op & 0x00010000) >> 16; + + switch (subinstr) + { + case 0x00: return arcompact_handle01_00(PARAMS); // Branh & Link + case 0x01: return arcompact_handle01_01(PARAMS); // Branch on Compare + } + + return 0; +} + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle01_00(OPS_32) +{ + UINT8 subinstr2 = (op & 0x00020000) >> 17; + + switch (subinstr2) + { + case 0x00: return arcompact_handle01_00_00dasm(PARAMS); // Branch and Link Conditionally + case 0x01: return arcompact_handle01_00_01dasm(PARAMS); // Branch and Link Unconditional Far + } + + return 0; +} + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle01_01(OPS_32) +{ + UINT8 subinstr2 = (op & 0x00000010) >> 4; + + switch (subinstr2) + { + case 0x00: return arcompact_handle01_01_00(PARAMS); // Branch on Compare Register-Register + case 0x01: return arcompact_handle01_01_01(PARAMS); // Branch on Compare/Bit Test Register-Immediate + } + + return 0; +} + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle01_01_00(OPS_32) +{ + UINT8 subinstr3 = (op & 0x0000000f) >> 0; + + switch (subinstr3) + { + case 0x00: return arcompact_handle01_01_00_00(PARAMS); // BREQ (reg-reg) + case 0x01: return arcompact_handle01_01_00_01(PARAMS); // BRNE (reg-reg) + case 0x02: return arcompact_handle01_01_00_02(PARAMS); // BRLT (reg-reg) + case 0x03: return arcompact_handle01_01_00_03(PARAMS); // BRGE (reg-reg) + case 0x04: return arcompact_handle01_01_00_04(PARAMS); // BRLO (reg-reg) + case 0x05: return arcompact_handle01_01_00_05(PARAMS); // BRHS (reg-reg) + case 0x06: return arcompact_handle01_01_00_06(PARAMS); // reserved + case 0x07: return arcompact_handle01_01_00_07(PARAMS); // reserved + case 0x08: return arcompact_handle01_01_00_08(PARAMS); // reserved + case 0x09: return arcompact_handle01_01_00_09(PARAMS); // reserved + case 0x0a: return arcompact_handle01_01_00_0a(PARAMS); // reserved + case 0x0b: return arcompact_handle01_01_00_0b(PARAMS); // reserved + case 0x0c: return arcompact_handle01_01_00_0c(PARAMS); // reserved + case 0x0d: return arcompact_handle01_01_00_0d(PARAMS); // reserved + case 0x0e: return arcompact_handle01_01_00_0e(PARAMS); // BBIT0 (reg-reg) + case 0x0f: return arcompact_handle01_01_00_0f(PARAMS); // BBIT1 (reg-reg) + } + + return 0; +} + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle01_01_01(OPS_32) // Branch on Compare/Bit Test Register-Immediate +{ + UINT8 subinstr3 = (op & 0x0000000f) >> 0; + + switch (subinstr3) + { + case 0x00: return arcompact_handle01_01_01_00(PARAMS); // BREQ (reg-imm) + case 0x01: return arcompact_handle01_01_01_01(PARAMS); // BRNE (reg-imm) + case 0x02: return arcompact_handle01_01_01_02(PARAMS); // BRLT (reg-imm) + case 0x03: return arcompact_handle01_01_01_03(PARAMS); // BRGE (reg-imm) + case 0x04: return arcompact_handle01_01_01_04(PARAMS); // BRLO (reg-imm) + case 0x05: return arcompact_handle01_01_01_05(PARAMS); // BRHS (reg-imm) + case 0x06: return arcompact_handle01_01_01_06(PARAMS); // reserved + case 0x07: return arcompact_handle01_01_01_07(PARAMS); // reserved + case 0x08: return arcompact_handle01_01_01_08(PARAMS); // reserved + case 0x09: return arcompact_handle01_01_01_09(PARAMS); // reserved + case 0x0a: return arcompact_handle01_01_01_0a(PARAMS); // reserved + case 0x0b: return arcompact_handle01_01_01_0b(PARAMS); // reserved + case 0x0c: return arcompact_handle01_01_01_0c(PARAMS); // reserved + case 0x0d: return arcompact_handle01_01_01_0d(PARAMS); // reserved + case 0x0e: return arcompact_handle01_01_01_0e(PARAMS); // BBIT0 (reg-imm) + case 0x0f: return arcompact_handle01_01_01_0f(PARAMS); // BBIT1 (reg-imm) + } + + return 0; +} + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04(OPS_32) +{ + UINT8 subinstr = (op & 0x003f0000) >> 16; + + switch (subinstr) + { + case 0x00: return arcompact_handle04_00(PARAMS); // ADD + case 0x01: return arcompact_handle04_01(PARAMS); // ADC + case 0x02: return arcompact_handle04_02(PARAMS); // SUB + case 0x03: return arcompact_handle04_03(PARAMS); // SBC + case 0x04: return arcompact_handle04_04(PARAMS); // AND + case 0x05: return arcompact_handle04_05(PARAMS); // OR + case 0x06: return arcompact_handle04_06(PARAMS); // BIC + case 0x07: return arcompact_handle04_07(PARAMS); // XOR + case 0x08: return arcompact_handle04_08(PARAMS); // MAX + case 0x09: return arcompact_handle04_09(PARAMS); // MIN + case 0x0a: return arcompact_handle04_0a(PARAMS); // MOV + case 0x0b: return arcompact_handle04_0b(PARAMS); // TST + case 0x0c: return arcompact_handle04_0c(PARAMS); // CMP + case 0x0d: return arcompact_handle04_0d(PARAMS); // RCMP + case 0x0e: return arcompact_handle04_0e(PARAMS); // RSUB + case 0x0f: return arcompact_handle04_0f(PARAMS); // BSET + case 0x10: return arcompact_handle04_10(PARAMS); // BCLR + case 0x11: return arcompact_handle04_11(PARAMS); // BTST + case 0x12: return arcompact_handle04_12(PARAMS); // BXOR + case 0x13: return arcompact_handle04_13(PARAMS); // BMSK + case 0x14: return arcompact_handle04_14(PARAMS); // ADD1 + case 0x15: return arcompact_handle04_15(PARAMS); // ADD2 + case 0x16: return arcompact_handle04_16(PARAMS); // ADD3 + case 0x17: return arcompact_handle04_17(PARAMS); // SUB1 + case 0x18: return arcompact_handle04_18(PARAMS); // SUB2 + case 0x19: return arcompact_handle04_19(PARAMS); // SUB3 + case 0x1a: return arcompact_handle04_1a(PARAMS); // MPY * + case 0x1b: return arcompact_handle04_1b(PARAMS); // MPYH * + case 0x1c: return arcompact_handle04_1c(PARAMS); // MPYHU * + case 0x1d: return arcompact_handle04_1d(PARAMS); // MPYU * + case 0x1e: return arcompact_handle04_1e(PARAMS); // illegal + case 0x1f: return arcompact_handle04_1f(PARAMS); // illegal + case 0x20: return arcompact_handle04_20(PARAMS); // Jcc + case 0x21: return arcompact_handle04_21(PARAMS); // Jcc.D + case 0x22: return arcompact_handle04_22(PARAMS); // JLcc + case 0x23: return arcompact_handle04_23(PARAMS); // JLcc.D + case 0x24: return arcompact_handle04_24(PARAMS); // illegal + case 0x25: return arcompact_handle04_25(PARAMS); // illegal + case 0x26: return arcompact_handle04_26(PARAMS); // illegal + case 0x27: return arcompact_handle04_27(PARAMS); // illegal + case 0x28: return arcompact_handle04_28(PARAMS); // LPcc + case 0x29: return arcompact_handle04_29(PARAMS); // FLAG + case 0x2a: return arcompact_handle04_2a(PARAMS); // LR + case 0x2b: return arcompact_handle04_2b(PARAMS); // SR + case 0x2c: return arcompact_handle04_2c(PARAMS); // illegal + case 0x2d: return arcompact_handle04_2d(PARAMS); // illegal + case 0x2e: return arcompact_handle04_2e(PARAMS); // illegal + case 0x2f: return arcompact_handle04_2f(PARAMS); // Sub Opcode + case 0x30: return arcompact_handle04_30(PARAMS); // LD r-r + case 0x31: return arcompact_handle04_31(PARAMS); // LD r-r + case 0x32: return arcompact_handle04_32(PARAMS); // LD r-r + case 0x33: return arcompact_handle04_33(PARAMS); // LD r-r + case 0x34: return arcompact_handle04_34(PARAMS); // LD r-r + case 0x35: return arcompact_handle04_35(PARAMS); // LD r-r + case 0x36: return arcompact_handle04_36(PARAMS); // LD r-r + case 0x37: return arcompact_handle04_37(PARAMS); // LD r-r + case 0x38: return arcompact_handle04_38(PARAMS); // illegal + case 0x39: return arcompact_handle04_39(PARAMS); // illegal + case 0x3a: return arcompact_handle04_3a(PARAMS); // illegal + case 0x3b: return arcompact_handle04_3b(PARAMS); // illegal + case 0x3c: return arcompact_handle04_3c(PARAMS); // illegal + case 0x3d: return arcompact_handle04_3d(PARAMS); // illegal + case 0x3e: return arcompact_handle04_3e(PARAMS); // illegal + case 0x3f: return arcompact_handle04_3f(PARAMS); // illegal + } + + return 0; +} + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f(OPS_32) +{ + UINT8 subinstr2 = (op & 0x0000003f) >> 0; + + switch (subinstr2) + { + case 0x00: return arcompact_handle04_2f_00(PARAMS); // ASL + case 0x01: return arcompact_handle04_2f_01(PARAMS); // ASR + case 0x02: return arcompact_handle04_2f_02(PARAMS); // LSR + case 0x03: return arcompact_handle04_2f_03(PARAMS); // ROR + case 0x04: return arcompact_handle04_2f_04(PARAMS); // RCC + case 0x05: return arcompact_handle04_2f_05(PARAMS); // SEXB + case 0x06: return arcompact_handle04_2f_06(PARAMS); // SEXW + case 0x07: return arcompact_handle04_2f_07(PARAMS); // EXTB + case 0x08: return arcompact_handle04_2f_08(PARAMS); // EXTW + case 0x09: return arcompact_handle04_2f_09(PARAMS); // ABS + case 0x0a: return arcompact_handle04_2f_0a(PARAMS); // NOT + case 0x0b: return arcompact_handle04_2f_0b(PARAMS); // RLC + case 0x0c: return arcompact_handle04_2f_0c(PARAMS); // EX + case 0x0d: return arcompact_handle04_2f_0d(PARAMS); // illegal + case 0x0e: return arcompact_handle04_2f_0e(PARAMS); // illegal + case 0x0f: return arcompact_handle04_2f_0f(PARAMS); // illegal + case 0x10: return arcompact_handle04_2f_10(PARAMS); // illegal + case 0x11: return arcompact_handle04_2f_11(PARAMS); // illegal + case 0x12: return arcompact_handle04_2f_12(PARAMS); // illegal + case 0x13: return arcompact_handle04_2f_13(PARAMS); // illegal + case 0x14: return arcompact_handle04_2f_14(PARAMS); // illegal + case 0x15: return arcompact_handle04_2f_15(PARAMS); // illegal + case 0x16: return arcompact_handle04_2f_16(PARAMS); // illegal + case 0x17: return arcompact_handle04_2f_17(PARAMS); // illegal + case 0x18: return arcompact_handle04_2f_18(PARAMS); // illegal + case 0x19: return arcompact_handle04_2f_19(PARAMS); // illegal + case 0x1a: return arcompact_handle04_2f_1a(PARAMS); // illegal + case 0x1b: return arcompact_handle04_2f_1b(PARAMS); // illegal + case 0x1c: return arcompact_handle04_2f_1c(PARAMS); // illegal + case 0x1d: return arcompact_handle04_2f_1d(PARAMS); // illegal + case 0x1e: return arcompact_handle04_2f_1e(PARAMS); // illegal + case 0x1f: return arcompact_handle04_2f_1f(PARAMS); // illegal + case 0x20: return arcompact_handle04_2f_20(PARAMS); // illegal + case 0x21: return arcompact_handle04_2f_21(PARAMS); // illegal + case 0x22: return arcompact_handle04_2f_22(PARAMS); // illegal + case 0x23: return arcompact_handle04_2f_23(PARAMS); // illegal + case 0x24: return arcompact_handle04_2f_24(PARAMS); // illegal + case 0x25: return arcompact_handle04_2f_25(PARAMS); // illegal + case 0x26: return arcompact_handle04_2f_26(PARAMS); // illegal + case 0x27: return arcompact_handle04_2f_27(PARAMS); // illegal + case 0x28: return arcompact_handle04_2f_28(PARAMS); // illegal + case 0x29: return arcompact_handle04_2f_29(PARAMS); // illegal + case 0x2a: return arcompact_handle04_2f_2a(PARAMS); // illegal + case 0x2b: return arcompact_handle04_2f_2b(PARAMS); // illegal + case 0x2c: return arcompact_handle04_2f_2c(PARAMS); // illegal + case 0x2d: return arcompact_handle04_2f_2d(PARAMS); // illegal + case 0x2e: return arcompact_handle04_2f_2e(PARAMS); // illegal + case 0x2f: return arcompact_handle04_2f_2f(PARAMS); // illegal + case 0x30: return arcompact_handle04_2f_30(PARAMS); // illegal + case 0x31: return arcompact_handle04_2f_31(PARAMS); // illegal + case 0x32: return arcompact_handle04_2f_32(PARAMS); // illegal + case 0x33: return arcompact_handle04_2f_33(PARAMS); // illegal + case 0x34: return arcompact_handle04_2f_34(PARAMS); // illegal + case 0x35: return arcompact_handle04_2f_35(PARAMS); // illegal + case 0x36: return arcompact_handle04_2f_36(PARAMS); // illegal + case 0x37: return arcompact_handle04_2f_37(PARAMS); // illegal + case 0x38: return arcompact_handle04_2f_38(PARAMS); // illegal + case 0x39: return arcompact_handle04_2f_39(PARAMS); // illegal + case 0x3a: return arcompact_handle04_2f_3a(PARAMS); // illegal + case 0x3b: return arcompact_handle04_2f_3b(PARAMS); // illegal + case 0x3c: return arcompact_handle04_2f_3c(PARAMS); // illegal + case 0x3d: return arcompact_handle04_2f_3d(PARAMS); // illegal + case 0x3e: return arcompact_handle04_2f_3e(PARAMS); // illegal + case 0x3f: return arcompact_handle04_2f_3f(PARAMS); // ZOPs (Zero Operand Opcodes) + } + + return 0; +} + + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f(OPS_32) +{ + UINT8 subinstr2 = (op & 0x0000003f) >> 0; + + switch (subinstr2) + { + case 0x00: return arcompact_handle05_2f_00(PARAMS); // SWAP + case 0x01: return arcompact_handle05_2f_01(PARAMS); // NORM + case 0x02: return arcompact_handle05_2f_02(PARAMS); // SAT16 + case 0x03: return arcompact_handle05_2f_03(PARAMS); // RND16 + case 0x04: return arcompact_handle05_2f_04(PARAMS); // ABSSW + case 0x05: return arcompact_handle05_2f_05(PARAMS); // ABSS + case 0x06: return arcompact_handle05_2f_06(PARAMS); // NEGSW + case 0x07: return arcompact_handle05_2f_07(PARAMS); // NEGS + case 0x08: return arcompact_handle05_2f_08(PARAMS); // NORMW + case 0x09: return arcompact_handle05_2f_09(PARAMS); // illegal + case 0x0a: return arcompact_handle05_2f_0a(PARAMS); // illegal + case 0x0b: return arcompact_handle05_2f_0b(PARAMS); // illegal + case 0x0c: return arcompact_handle05_2f_0c(PARAMS); // illegal + case 0x0d: return arcompact_handle05_2f_0d(PARAMS); // illegal + case 0x0e: return arcompact_handle05_2f_0e(PARAMS); // illegal + case 0x0f: return arcompact_handle05_2f_0f(PARAMS); // illegal + case 0x10: return arcompact_handle05_2f_10(PARAMS); // illegal + case 0x11: return arcompact_handle05_2f_11(PARAMS); // illegal + case 0x12: return arcompact_handle05_2f_12(PARAMS); // illegal + case 0x13: return arcompact_handle05_2f_13(PARAMS); // illegal + case 0x14: return arcompact_handle05_2f_14(PARAMS); // illegal + case 0x15: return arcompact_handle05_2f_15(PARAMS); // illegal + case 0x16: return arcompact_handle05_2f_16(PARAMS); // illegal + case 0x17: return arcompact_handle05_2f_17(PARAMS); // illegal + case 0x18: return arcompact_handle05_2f_18(PARAMS); // illegal + case 0x19: return arcompact_handle05_2f_19(PARAMS); // illegal + case 0x1a: return arcompact_handle05_2f_1a(PARAMS); // illegal + case 0x1b: return arcompact_handle05_2f_1b(PARAMS); // illegal + case 0x1c: return arcompact_handle05_2f_1c(PARAMS); // illegal + case 0x1d: return arcompact_handle05_2f_1d(PARAMS); // illegal + case 0x1e: return arcompact_handle05_2f_1e(PARAMS); // illegal + case 0x1f: return arcompact_handle05_2f_1f(PARAMS); // illegal + case 0x20: return arcompact_handle05_2f_20(PARAMS); // illegal + case 0x21: return arcompact_handle05_2f_21(PARAMS); // illegal + case 0x22: return arcompact_handle05_2f_22(PARAMS); // illegal + case 0x23: return arcompact_handle05_2f_23(PARAMS); // illegal + case 0x24: return arcompact_handle05_2f_24(PARAMS); // illegal + case 0x25: return arcompact_handle05_2f_25(PARAMS); // illegal + case 0x26: return arcompact_handle05_2f_26(PARAMS); // illegal + case 0x27: return arcompact_handle05_2f_27(PARAMS); // illegal + case 0x28: return arcompact_handle05_2f_28(PARAMS); // illegal + case 0x29: return arcompact_handle05_2f_29(PARAMS); // illegal + case 0x2a: return arcompact_handle05_2f_2a(PARAMS); // illegal + case 0x2b: return arcompact_handle05_2f_2b(PARAMS); // illegal + case 0x2c: return arcompact_handle05_2f_2c(PARAMS); // illegal + case 0x2d: return arcompact_handle05_2f_2d(PARAMS); // illegal + case 0x2e: return arcompact_handle05_2f_2e(PARAMS); // illegal + case 0x2f: return arcompact_handle05_2f_2f(PARAMS); // illegal + case 0x30: return arcompact_handle05_2f_30(PARAMS); // illegal + case 0x31: return arcompact_handle05_2f_31(PARAMS); // illegal + case 0x32: return arcompact_handle05_2f_32(PARAMS); // illegal + case 0x33: return arcompact_handle05_2f_33(PARAMS); // illegal + case 0x34: return arcompact_handle05_2f_34(PARAMS); // illegal + case 0x35: return arcompact_handle05_2f_35(PARAMS); // illegal + case 0x36: return arcompact_handle05_2f_36(PARAMS); // illegal + case 0x37: return arcompact_handle05_2f_37(PARAMS); // illegal + case 0x38: return arcompact_handle05_2f_38(PARAMS); // illegal + case 0x39: return arcompact_handle05_2f_39(PARAMS); // illegal + case 0x3a: return arcompact_handle05_2f_3a(PARAMS); // illegal + case 0x3b: return arcompact_handle05_2f_3b(PARAMS); // illegal + case 0x3c: return arcompact_handle05_2f_3c(PARAMS); // illegal + case 0x3d: return arcompact_handle05_2f_3d(PARAMS); // illegal + case 0x3e: return arcompact_handle05_2f_3e(PARAMS); // illegal + case 0x3f: return arcompact_handle05_2f_3f(PARAMS); // ZOPs (Zero Operand Opcodes) + } + + return 0; +} + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_3f(OPS_32) +{ + UINT8 subinstr3 = (op & 0x07000000) >> 24; + subinstr3 |= ((op & 0x00007000) >> 12) << 3; + + switch (subinstr3) + { + case 0x00: return arcompact_handle04_2f_3f_00(PARAMS); // illegal + case 0x01: return arcompact_handle04_2f_3f_01(PARAMS); // SLEEP + case 0x02: return arcompact_handle04_2f_3f_02(PARAMS); // SWI / TRAP9 + case 0x03: return arcompact_handle04_2f_3f_03(PARAMS); // SYNC + case 0x04: return arcompact_handle04_2f_3f_04(PARAMS); // RTIE + case 0x05: return arcompact_handle04_2f_3f_05(PARAMS); // BRK + case 0x06: return arcompact_handle04_2f_3f_06(PARAMS); // illegal + case 0x07: return arcompact_handle04_2f_3f_07(PARAMS); // illegal + case 0x08: return arcompact_handle04_2f_3f_08(PARAMS); // illegal + case 0x09: return arcompact_handle04_2f_3f_09(PARAMS); // illegal + case 0x0a: return arcompact_handle04_2f_3f_0a(PARAMS); // illegal + case 0x0b: return arcompact_handle04_2f_3f_0b(PARAMS); // illegal + case 0x0c: return arcompact_handle04_2f_3f_0c(PARAMS); // illegal + case 0x0d: return arcompact_handle04_2f_3f_0d(PARAMS); // illegal + case 0x0e: return arcompact_handle04_2f_3f_0e(PARAMS); // illegal + case 0x0f: return arcompact_handle04_2f_3f_0f(PARAMS); // illegal + case 0x10: return arcompact_handle04_2f_3f_10(PARAMS); // illegal + case 0x11: return arcompact_handle04_2f_3f_11(PARAMS); // illegal + case 0x12: return arcompact_handle04_2f_3f_12(PARAMS); // illegal + case 0x13: return arcompact_handle04_2f_3f_13(PARAMS); // illegal + case 0x14: return arcompact_handle04_2f_3f_14(PARAMS); // illegal + case 0x15: return arcompact_handle04_2f_3f_15(PARAMS); // illegal + case 0x16: return arcompact_handle04_2f_3f_16(PARAMS); // illegal + case 0x17: return arcompact_handle04_2f_3f_17(PARAMS); // illegal + case 0x18: return arcompact_handle04_2f_3f_18(PARAMS); // illegal + case 0x19: return arcompact_handle04_2f_3f_19(PARAMS); // illegal + case 0x1a: return arcompact_handle04_2f_3f_1a(PARAMS); // illegal + case 0x1b: return arcompact_handle04_2f_3f_1b(PARAMS); // illegal + case 0x1c: return arcompact_handle04_2f_3f_1c(PARAMS); // illegal + case 0x1d: return arcompact_handle04_2f_3f_1d(PARAMS); // illegal + case 0x1e: return arcompact_handle04_2f_3f_1e(PARAMS); // illegal + case 0x1f: return arcompact_handle04_2f_3f_1f(PARAMS); // illegal + case 0x20: return arcompact_handle04_2f_3f_20(PARAMS); // illegal + case 0x21: return arcompact_handle04_2f_3f_21(PARAMS); // illegal + case 0x22: return arcompact_handle04_2f_3f_22(PARAMS); // illegal + case 0x23: return arcompact_handle04_2f_3f_23(PARAMS); // illegal + case 0x24: return arcompact_handle04_2f_3f_24(PARAMS); // illegal + case 0x25: return arcompact_handle04_2f_3f_25(PARAMS); // illegal + case 0x26: return arcompact_handle04_2f_3f_26(PARAMS); // illegal + case 0x27: return arcompact_handle04_2f_3f_27(PARAMS); // illegal + case 0x28: return arcompact_handle04_2f_3f_28(PARAMS); // illegal + case 0x29: return arcompact_handle04_2f_3f_29(PARAMS); // illegal + case 0x2a: return arcompact_handle04_2f_3f_2a(PARAMS); // illegal + case 0x2b: return arcompact_handle04_2f_3f_2b(PARAMS); // illegal + case 0x2c: return arcompact_handle04_2f_3f_2c(PARAMS); // illegal + case 0x2d: return arcompact_handle04_2f_3f_2d(PARAMS); // illegal + case 0x2e: return arcompact_handle04_2f_3f_2e(PARAMS); // illegal + case 0x2f: return arcompact_handle04_2f_3f_2f(PARAMS); // illegal + case 0x30: return arcompact_handle04_2f_3f_30(PARAMS); // illegal + case 0x31: return arcompact_handle04_2f_3f_31(PARAMS); // illegal + case 0x32: return arcompact_handle04_2f_3f_32(PARAMS); // illegal + case 0x33: return arcompact_handle04_2f_3f_33(PARAMS); // illegal + case 0x34: return arcompact_handle04_2f_3f_34(PARAMS); // illegal + case 0x35: return arcompact_handle04_2f_3f_35(PARAMS); // illegal + case 0x36: return arcompact_handle04_2f_3f_36(PARAMS); // illegal + case 0x37: return arcompact_handle04_2f_3f_37(PARAMS); // illegal + case 0x38: return arcompact_handle04_2f_3f_38(PARAMS); // illegal + case 0x39: return arcompact_handle04_2f_3f_39(PARAMS); // illegal + case 0x3a: return arcompact_handle04_2f_3f_3a(PARAMS); // illegal + case 0x3b: return arcompact_handle04_2f_3f_3b(PARAMS); // illegal + case 0x3c: return arcompact_handle04_2f_3f_3c(PARAMS); // illegal + case 0x3d: return arcompact_handle04_2f_3f_3d(PARAMS); // illegal + case 0x3e: return arcompact_handle04_2f_3f_3e(PARAMS); // illegal + case 0x3f: return arcompact_handle04_2f_3f_3f(PARAMS); // illegal + } + + return 0; +} + + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_3f(OPS_32) // useless ZOP group, no actual opcodes +{ + UINT8 subinstr3 = (op & 0x07000000) >> 24; + subinstr3 |= ((op & 0x00007000) >> 12) << 3; + + switch (subinstr3) + { + case 0x00: return arcompact_handle05_2f_3f_00(PARAMS); // illegal + case 0x01: return arcompact_handle05_2f_3f_01(PARAMS); // illegal + case 0x02: return arcompact_handle05_2f_3f_02(PARAMS); // illegal + case 0x03: return arcompact_handle05_2f_3f_03(PARAMS); // illegal + case 0x04: return arcompact_handle05_2f_3f_04(PARAMS); // illegal + case 0x05: return arcompact_handle05_2f_3f_05(PARAMS); // illegal + case 0x06: return arcompact_handle05_2f_3f_06(PARAMS); // illegal + case 0x07: return arcompact_handle05_2f_3f_07(PARAMS); // illegal + case 0x08: return arcompact_handle05_2f_3f_08(PARAMS); // illegal + case 0x09: return arcompact_handle05_2f_3f_09(PARAMS); // illegal + case 0x0a: return arcompact_handle05_2f_3f_0a(PARAMS); // illegal + case 0x0b: return arcompact_handle05_2f_3f_0b(PARAMS); // illegal + case 0x0c: return arcompact_handle05_2f_3f_0c(PARAMS); // illegal + case 0x0d: return arcompact_handle05_2f_3f_0d(PARAMS); // illegal + case 0x0e: return arcompact_handle05_2f_3f_0e(PARAMS); // illegal + case 0x0f: return arcompact_handle05_2f_3f_0f(PARAMS); // illegal + case 0x10: return arcompact_handle05_2f_3f_10(PARAMS); // illegal + case 0x11: return arcompact_handle05_2f_3f_11(PARAMS); // illegal + case 0x12: return arcompact_handle05_2f_3f_12(PARAMS); // illegal + case 0x13: return arcompact_handle05_2f_3f_13(PARAMS); // illegal + case 0x14: return arcompact_handle05_2f_3f_14(PARAMS); // illegal + case 0x15: return arcompact_handle05_2f_3f_15(PARAMS); // illegal + case 0x16: return arcompact_handle05_2f_3f_16(PARAMS); // illegal + case 0x17: return arcompact_handle05_2f_3f_17(PARAMS); // illegal + case 0x18: return arcompact_handle05_2f_3f_18(PARAMS); // illegal + case 0x19: return arcompact_handle05_2f_3f_19(PARAMS); // illegal + case 0x1a: return arcompact_handle05_2f_3f_1a(PARAMS); // illegal + case 0x1b: return arcompact_handle05_2f_3f_1b(PARAMS); // illegal + case 0x1c: return arcompact_handle05_2f_3f_1c(PARAMS); // illegal + case 0x1d: return arcompact_handle05_2f_3f_1d(PARAMS); // illegal + case 0x1e: return arcompact_handle05_2f_3f_1e(PARAMS); // illegal + case 0x1f: return arcompact_handle05_2f_3f_1f(PARAMS); // illegal + case 0x20: return arcompact_handle05_2f_3f_20(PARAMS); // illegal + case 0x21: return arcompact_handle05_2f_3f_21(PARAMS); // illegal + case 0x22: return arcompact_handle05_2f_3f_22(PARAMS); // illegal + case 0x23: return arcompact_handle05_2f_3f_23(PARAMS); // illegal + case 0x24: return arcompact_handle05_2f_3f_24(PARAMS); // illegal + case 0x25: return arcompact_handle05_2f_3f_25(PARAMS); // illegal + case 0x26: return arcompact_handle05_2f_3f_26(PARAMS); // illegal + case 0x27: return arcompact_handle05_2f_3f_27(PARAMS); // illegal + case 0x28: return arcompact_handle05_2f_3f_28(PARAMS); // illegal + case 0x29: return arcompact_handle05_2f_3f_29(PARAMS); // illegal + case 0x2a: return arcompact_handle05_2f_3f_2a(PARAMS); // illegal + case 0x2b: return arcompact_handle05_2f_3f_2b(PARAMS); // illegal + case 0x2c: return arcompact_handle05_2f_3f_2c(PARAMS); // illegal + case 0x2d: return arcompact_handle05_2f_3f_2d(PARAMS); // illegal + case 0x2e: return arcompact_handle05_2f_3f_2e(PARAMS); // illegal + case 0x2f: return arcompact_handle05_2f_3f_2f(PARAMS); // illegal + case 0x30: return arcompact_handle05_2f_3f_30(PARAMS); // illegal + case 0x31: return arcompact_handle05_2f_3f_31(PARAMS); // illegal + case 0x32: return arcompact_handle05_2f_3f_32(PARAMS); // illegal + case 0x33: return arcompact_handle05_2f_3f_33(PARAMS); // illegal + case 0x34: return arcompact_handle05_2f_3f_34(PARAMS); // illegal + case 0x35: return arcompact_handle05_2f_3f_35(PARAMS); // illegal + case 0x36: return arcompact_handle05_2f_3f_36(PARAMS); // illegal + case 0x37: return arcompact_handle05_2f_3f_37(PARAMS); // illegal + case 0x38: return arcompact_handle05_2f_3f_38(PARAMS); // illegal + case 0x39: return arcompact_handle05_2f_3f_39(PARAMS); // illegal + case 0x3a: return arcompact_handle05_2f_3f_3a(PARAMS); // illegal + case 0x3b: return arcompact_handle05_2f_3f_3b(PARAMS); // illegal + case 0x3c: return arcompact_handle05_2f_3f_3c(PARAMS); // illegal + case 0x3d: return arcompact_handle05_2f_3f_3d(PARAMS); // illegal + case 0x3e: return arcompact_handle05_2f_3f_3e(PARAMS); // illegal + case 0x3f: return arcompact_handle05_2f_3f_3f(PARAMS); // illegal + } + + return 0; +} + + +// this is an Extension ALU group, maybe optional on some CPUs? +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05(OPS_32) +{ + UINT8 subinstr = (op & 0x003f0000) >> 16; + + switch (subinstr) + { + case 0x00: return arcompact_handle05_00(PARAMS); // ASL + case 0x01: return arcompact_handle05_01(PARAMS); // LSR + case 0x02: return arcompact_handle05_02(PARAMS); // ASR + case 0x03: return arcompact_handle05_03(PARAMS); // ROR + case 0x04: return arcompact_handle05_04(PARAMS); // MUL64 + case 0x05: return arcompact_handle05_05(PARAMS); // MULU64 + case 0x06: return arcompact_handle05_06(PARAMS); // ADDS + case 0x07: return arcompact_handle05_07(PARAMS); // SUBS + case 0x08: return arcompact_handle05_08(PARAMS); // DIVAW + case 0x09: return arcompact_handle05_09(PARAMS); // illegal + case 0x0a: return arcompact_handle05_0a(PARAMS); // ASLS + case 0x0b: return arcompact_handle05_0b(PARAMS); // ASRS + case 0x0c: return arcompact_handle05_0c(PARAMS); // illegal + case 0x0d: return arcompact_handle05_0d(PARAMS); // illegal + case 0x0e: return arcompact_handle05_0e(PARAMS); // illegal + case 0x0f: return arcompact_handle05_0f(PARAMS); // illegal + case 0x10: return arcompact_handle05_10(PARAMS); // illegal + case 0x11: return arcompact_handle05_11(PARAMS); // illegal + case 0x12: return arcompact_handle05_12(PARAMS); // illegal + case 0x13: return arcompact_handle05_13(PARAMS); // illegal + case 0x14: return arcompact_handle05_14(PARAMS); // illegal + case 0x15: return arcompact_handle05_15(PARAMS); // illegal + case 0x16: return arcompact_handle05_16(PARAMS); // illegal + case 0x17: return arcompact_handle05_17(PARAMS); // illegal + case 0x18: return arcompact_handle05_18(PARAMS); // illegal + case 0x19: return arcompact_handle05_19(PARAMS); // illegal + case 0x1a: return arcompact_handle05_1a(PARAMS); // illegal + case 0x1b: return arcompact_handle05_1b(PARAMS); // illegal + case 0x1c: return arcompact_handle05_1c(PARAMS); // illegal + case 0x1d: return arcompact_handle05_1d(PARAMS); // illegal + case 0x1e: return arcompact_handle05_1e(PARAMS); // illegal + case 0x1f: return arcompact_handle05_1f(PARAMS); // illegal + case 0x20: return arcompact_handle05_20(PARAMS); // illegal + case 0x21: return arcompact_handle05_21(PARAMS); // illegal + case 0x22: return arcompact_handle05_22(PARAMS); // illegal + case 0x23: return arcompact_handle05_23(PARAMS); // illegal + case 0x24: return arcompact_handle05_24(PARAMS); // illegal + case 0x25: return arcompact_handle05_25(PARAMS); // illegal + case 0x26: return arcompact_handle05_26(PARAMS); // illegal + case 0x27: return arcompact_handle05_27(PARAMS); // illegal + case 0x28: return arcompact_handle05_28(PARAMS); // ADDSDW + case 0x29: return arcompact_handle05_29(PARAMS); // SUBSDW + case 0x2a: return arcompact_handle05_2a(PARAMS); // illegal + case 0x2b: return arcompact_handle05_2b(PARAMS); // illegal + case 0x2c: return arcompact_handle05_2c(PARAMS); // illegal + case 0x2d: return arcompact_handle05_2d(PARAMS); // illegal + case 0x2e: return arcompact_handle05_2e(PARAMS); // illegal + case 0x2f: return arcompact_handle05_2f(PARAMS); // SOPs + case 0x30: return arcompact_handle05_30(PARAMS); // illegal + case 0x31: return arcompact_handle05_31(PARAMS); // illegal + case 0x32: return arcompact_handle05_32(PARAMS); // illegal + case 0x33: return arcompact_handle05_33(PARAMS); // illegal + case 0x34: return arcompact_handle05_34(PARAMS); // illegal + case 0x35: return arcompact_handle05_35(PARAMS); // illegal + case 0x36: return arcompact_handle05_36(PARAMS); // illegal + case 0x37: return arcompact_handle05_37(PARAMS); // illegal + case 0x38: return arcompact_handle05_38(PARAMS); // illegal + case 0x39: return arcompact_handle05_39(PARAMS); // illegal + case 0x3a: return arcompact_handle05_3a(PARAMS); // illegal + case 0x3b: return arcompact_handle05_3b(PARAMS); // illegal + case 0x3c: return arcompact_handle05_3c(PARAMS); // illegal + case 0x3d: return arcompact_handle05_3d(PARAMS); // illegal + case 0x3e: return arcompact_handle05_3e(PARAMS); // illegal + case 0x3f: return arcompact_handle05_3f(PARAMS); // illegal + } + + return 0; +} + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle0c(OPS_16) +{ + UINT8 subinstr = (op & 0x0018) >> 3; + + switch (subinstr) + { + case 0x00: return arcompact_handle0c_00(PARAMS); // LD_S + case 0x01: return arcompact_handle0c_01(PARAMS); // LDB_S + case 0x02: return arcompact_handle0c_02(PARAMS); // LDW_S + case 0x03: return arcompact_handle0c_03(PARAMS); // ADD_S + } + + return 0; +} + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle0d(OPS_16) +{ + UINT8 subinstr = (op & 0x0018) >> 3; + + switch (subinstr) + { + case 0x00: return arcompact_handle0d_00(PARAMS); // ADD_S + case 0x01: return arcompact_handle0d_01(PARAMS); // SUB_S + case 0x02: return arcompact_handle0d_02(PARAMS); // ASL_S + case 0x03: return arcompact_handle0d_03(PARAMS); // ASR_S + } + + return 0; +} + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle0e(OPS_16) +{ + UINT8 subinstr = (op & 0x0018) >> 3; + + switch (subinstr) + { + case 0x00: return arcompact_handle0e_00(PARAMS); // ADD_S + case 0x01: return arcompact_handle0e_01(PARAMS); // MOV_S + case 0x02: return arcompact_handle0e_02(PARAMS); // CMP_S + case 0x03: return arcompact_handle0e_03(PARAMS); // MOV_S + } + + return 0; +} + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle0f(OPS_16) +{ + UINT8 subinstr = (op & 0x01f) >> 0; + + switch (subinstr) + { + case 0x00: return arcompact_handle0f_00(PARAMS); // SOPs + case 0x01: return arcompact_handle0f_01(PARAMS); // 0x01 + case 0x02: return arcompact_handle0f_02(PARAMS); // SUB_S + case 0x03: return arcompact_handle0f_03(PARAMS); // 0x03 + case 0x04: return arcompact_handle0f_04(PARAMS); // AND_S + case 0x05: return arcompact_handle0f_05(PARAMS); // OR_S + case 0x06: return arcompact_handle0f_06(PARAMS); // BIC_S + case 0x07: return arcompact_handle0f_07(PARAMS); // XOR_S + case 0x08: return arcompact_handle0f_08(PARAMS); // 0x08 + case 0x09: return arcompact_handle0f_09(PARAMS); // 0x09 + case 0x0a: return arcompact_handle0f_0a(PARAMS); // 0x0a + case 0x0b: return arcompact_handle0f_0b(PARAMS); // TST_S + case 0x0c: return arcompact_handle0f_0c(PARAMS); // MUL64_S + case 0x0d: return arcompact_handle0f_0d(PARAMS); // SEXB_S + case 0x0e: return arcompact_handle0f_0e(PARAMS); // SEXW_S + case 0x0f: return arcompact_handle0f_0f(PARAMS); // EXTB_S + case 0x10: return arcompact_handle0f_10(PARAMS); // EXTW_S + case 0x11: return arcompact_handle0f_11(PARAMS); // ABS_S + case 0x12: return arcompact_handle0f_12(PARAMS); // NOT_S + case 0x13: return arcompact_handle0f_13(PARAMS); // NEG_S + case 0x14: return arcompact_handle0f_14(PARAMS); // ADD1_S + case 0x15: return arcompact_handle0f_15(PARAMS); // ADD2_S + case 0x16: return arcompact_handle0f_16(PARAMS); // ADD3_S + case 0x17: return arcompact_handle0f_17(PARAMS); // 0x17 + case 0x18: return arcompact_handle0f_18(PARAMS); // ASL_S (multiple) + case 0x19: return arcompact_handle0f_19(PARAMS); // LSR_S (multiple) + case 0x1a: return arcompact_handle0f_1a(PARAMS); // ASR_S (multiple) + case 0x1b: return arcompact_handle0f_1b(PARAMS); // ASL_S (single) + case 0x1c: return arcompact_handle0f_1c(PARAMS); // LSR_S (single) + case 0x1d: return arcompact_handle0f_1d(PARAMS); // ASR_S (single) + case 0x1e: return arcompact_handle0f_1e(PARAMS); // TRAP (not a5?) + case 0x1f: return arcompact_handle0f_1f(PARAMS); // BRK_S ( 0x7fff only? ) + + } + + return 0; +} + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle0f_00(OPS_16) +{ + UINT8 subinstr = (op & 0x00e0) >> 5; + + switch (subinstr) + { + case 0x00: return arcompact_handle0f_00_00(PARAMS); // J_S + case 0x01: return arcompact_handle0f_00_01(PARAMS); // J_S.D + case 0x02: return arcompact_handle0f_00_02(PARAMS); // JL_S + case 0x03: return arcompact_handle0f_00_03(PARAMS); // JL_S.D + case 0x04: return arcompact_handle0f_00_04(PARAMS); // 0x04 + case 0x05: return arcompact_handle0f_00_05(PARAMS); // 0x05 + case 0x06: return arcompact_handle0f_00_06(PARAMS); // SUB_S.NE + case 0x07: return arcompact_handle0f_00_07(PARAMS); // ZOPs + + } + + return 0; +} + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle0f_00_07(OPS_16) +{ + UINT8 subinstr3 = (op & 0x0700) >> 8; + + switch (subinstr3) + { + case 0x00: return arcompact_handle0f_00_07_00(PARAMS); // NOP_S + case 0x01: return arcompact_handle0f_00_07_01(PARAMS); // UNIMP_S + case 0x02: return arcompact_handle0f_00_07_02(PARAMS); // 0x02 + case 0x03: return arcompact_handle0f_00_07_03(PARAMS); // 0x03 + case 0x04: return arcompact_handle0f_00_07_04(PARAMS); // JEQ_S [BLINK] + case 0x05: return arcompact_handle0f_00_07_05(PARAMS); // JNE_S [BLINK] + case 0x06: return arcompact_handle0f_00_07_06(PARAMS); // J_S [BLINK] + case 0x07: return arcompact_handle0f_00_07_07(PARAMS); // J_S.D [BLINK] + + } + + return 0; +} + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle17(OPS_16) +{ + UINT8 subinstr = (op & 0x00e0) >> 5; + + switch (subinstr) + { + case 0x00: return arcompact_handle17_00(PARAMS); // ASL_S + case 0x01: return arcompact_handle17_01(PARAMS); // LSR_S + case 0x02: return arcompact_handle17_02(PARAMS); // ASR_S + case 0x03: return arcompact_handle17_03(PARAMS); // SUB_S + case 0x04: return arcompact_handle17_04(PARAMS); // BSET_S + case 0x05: return arcompact_handle17_05(PARAMS); // BCLR_S + case 0x06: return arcompact_handle17_06(PARAMS); // BMSK_S + case 0x07: return arcompact_handle17_07(PARAMS); // BTST_S + } + + return 0; +} + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle18(OPS_16) +{ + UINT8 subinstr = (op & 0x00e0) >> 5; + + switch (subinstr) + { + case 0x00: return arcompact_handle18_00(PARAMS); // LD_S (SP) + case 0x01: return arcompact_handle18_01(PARAMS); // LDB_S (SP) + case 0x02: return arcompact_handle18_02(PARAMS); // ST_S (SP) + case 0x03: return arcompact_handle18_03(PARAMS); // STB_S (SP) + case 0x04: return arcompact_handle18_04(PARAMS); // ADD_S (SP) + case 0x05: return arcompact_handle18_05(PARAMS); // subtable 18_05 + case 0x06: return arcompact_handle18_06(PARAMS); // subtable 18_06 + case 0x07: return arcompact_handle18_07(PARAMS); // subtable 18_07 + } + + return 0; +} + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle18_05(OPS_16) +{ + UINT8 subinstr2 = (op & 0x0700) >> 8; + + switch (subinstr2) + { + case 0x00: return arcompact_handle18_05_00(PARAMS); // ADD_S (SP) + case 0x01: return arcompact_handle18_05_01(PARAMS); // SUB_S (SP) + case 0x02: return arcompact_handle18_05_02(PARAMS); // + case 0x03: return arcompact_handle18_05_03(PARAMS); // + case 0x04: return arcompact_handle18_05_04(PARAMS); // + case 0x05: return arcompact_handle18_05_05(PARAMS); // + case 0x06: return arcompact_handle18_05_06(PARAMS); // + case 0x07: return arcompact_handle18_05_07(PARAMS); // + } + + return 0; +} + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle18_06(OPS_16) +{ + UINT8 subinstr2 = (op & 0x001f) >> 0; + + switch (subinstr2) + { + case 0x00: return arcompact_handle18_06_00(PARAMS); // + case 0x01: return arcompact_handle18_06_01(PARAMS); // POP_S b + case 0x02: return arcompact_handle18_06_02(PARAMS); // + case 0x03: return arcompact_handle18_06_03(PARAMS); // + case 0x04: return arcompact_handle18_06_04(PARAMS); // + case 0x05: return arcompact_handle18_06_05(PARAMS); // + case 0x06: return arcompact_handle18_06_06(PARAMS); // + case 0x07: return arcompact_handle18_06_07(PARAMS); // + case 0x08: return arcompact_handle18_06_08(PARAMS); // + case 0x09: return arcompact_handle18_06_09(PARAMS); // + case 0x0a: return arcompact_handle18_06_0a(PARAMS); // + case 0x0b: return arcompact_handle18_06_0b(PARAMS); // + case 0x0c: return arcompact_handle18_06_0c(PARAMS); // + case 0x0d: return arcompact_handle18_06_0d(PARAMS); // + case 0x0e: return arcompact_handle18_06_0e(PARAMS); // + case 0x0f: return arcompact_handle18_06_0f(PARAMS); // + case 0x10: return arcompact_handle18_06_10(PARAMS); // + case 0x11: return arcompact_handle18_06_11(PARAMS); // POP_S blink + case 0x12: return arcompact_handle18_06_12(PARAMS); // + case 0x13: return arcompact_handle18_06_13(PARAMS); // + case 0x14: return arcompact_handle18_06_14(PARAMS); // + case 0x15: return arcompact_handle18_06_15(PARAMS); // + case 0x16: return arcompact_handle18_06_16(PARAMS); // + case 0x17: return arcompact_handle18_06_17(PARAMS); // + case 0x18: return arcompact_handle18_06_18(PARAMS); // + case 0x19: return arcompact_handle18_06_19(PARAMS); // + case 0x1a: return arcompact_handle18_06_1a(PARAMS); // + case 0x1b: return arcompact_handle18_06_1b(PARAMS); // + case 0x1c: return arcompact_handle18_06_1c(PARAMS); // + case 0x1d: return arcompact_handle18_06_1d(PARAMS); // + case 0x1e: return arcompact_handle18_06_1e(PARAMS); // + case 0x1f: return arcompact_handle18_06_1f(PARAMS); // + } + + return 0; +} + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle18_07(OPS_16) +{ + UINT8 subinstr2 = (op & 0x001f) >> 0; + + switch (subinstr2) + { + case 0x00: return arcompact_handle18_07_00(PARAMS); // + case 0x01: return arcompact_handle18_07_01(PARAMS); // PUSH_S b + case 0x02: return arcompact_handle18_07_02(PARAMS); // + case 0x03: return arcompact_handle18_07_03(PARAMS); // + case 0x04: return arcompact_handle18_07_04(PARAMS); // + case 0x05: return arcompact_handle18_07_05(PARAMS); // + case 0x06: return arcompact_handle18_07_06(PARAMS); // + case 0x07: return arcompact_handle18_07_07(PARAMS); // + case 0x08: return arcompact_handle18_07_08(PARAMS); // + case 0x09: return arcompact_handle18_07_09(PARAMS); // + case 0x0a: return arcompact_handle18_07_0a(PARAMS); // + case 0x0b: return arcompact_handle18_07_0b(PARAMS); // + case 0x0c: return arcompact_handle18_07_0c(PARAMS); // + case 0x0d: return arcompact_handle18_07_0d(PARAMS); // + case 0x0e: return arcompact_handle18_07_0e(PARAMS); // + case 0x0f: return arcompact_handle18_07_0f(PARAMS); // + case 0x10: return arcompact_handle18_07_10(PARAMS); // + case 0x11: return arcompact_handle18_07_11(PARAMS); // PUSH_S blink + case 0x12: return arcompact_handle18_07_12(PARAMS); // + case 0x13: return arcompact_handle18_07_13(PARAMS); // + case 0x14: return arcompact_handle18_07_14(PARAMS); // + case 0x15: return arcompact_handle18_07_15(PARAMS); // + case 0x16: return arcompact_handle18_07_16(PARAMS); // + case 0x17: return arcompact_handle18_07_17(PARAMS); // + case 0x18: return arcompact_handle18_07_18(PARAMS); // + case 0x19: return arcompact_handle18_07_19(PARAMS); // + case 0x1a: return arcompact_handle18_07_1a(PARAMS); // + case 0x1b: return arcompact_handle18_07_1b(PARAMS); // + case 0x1c: return arcompact_handle18_07_1c(PARAMS); // + case 0x1d: return arcompact_handle18_07_1d(PARAMS); // + case 0x1e: return arcompact_handle18_07_1e(PARAMS); // + case 0x1f: return arcompact_handle18_07_1f(PARAMS); // + } + + return 0; +} + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle19(OPS_16) +{ + UINT8 subinstr = (op & 0x0600) >> 9; + + switch (subinstr) + { + case 0x00: return arcompact_handle19_00(PARAMS); // LD_S (GP) + case 0x01: return arcompact_handle19_01(PARAMS); // LDB_S (GP) + case 0x02: return arcompact_handle19_02(PARAMS); // LDW_S (GP) + case 0x03: return arcompact_handle19_03(PARAMS); // ADD_S (GP) + } + + return 0; +} + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle1c(OPS_16) +{ + UINT8 subinstr = (op & 0x0080) >> 7; + + switch (subinstr) + { + case 0x00: return arcompact_handle1c_00(PARAMS); // ADD_S + case 0x01: return arcompact_handle1c_01(PARAMS); // CMP_S + } + + return 0; +} + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle1d(OPS_16) +{ + UINT8 subinstr = (op & 0x0080) >> 7; + + switch (subinstr) + { + case 0x00: return arcompact_handle1d_00(PARAMS); // BREQ_S + case 0x01: return arcompact_handle1d_01(PARAMS); // BRNE_S + } + + return 0; +} + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle1e(OPS_16) +{ + UINT8 subinstr = (op & 0x0600) >> 9; + + switch (subinstr) + { + case 0x00: return arcompact_handle1e_00(PARAMS); // B_S + case 0x01: return arcompact_handle1e_01(PARAMS); // BEQ_S + case 0x02: return arcompact_handle1e_02(PARAMS); // BNE_S + case 0x03: return arcompact_handle1e_03(PARAMS); // Bcc_S + } + + return 0; +} + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle1e_03(OPS_16) +{ + UINT8 subinstr2 = (op & 0x01c0) >> 6; + + switch (subinstr2) + { + case 0x00: return arcompact_handle1e_03_00(PARAMS); // BGT_S + case 0x01: return arcompact_handle1e_03_01(PARAMS); // BGE_S + case 0x02: return arcompact_handle1e_03_02(PARAMS); // BLT_S + case 0x03: return arcompact_handle1e_03_03(PARAMS); // BLE_S + case 0x04: return arcompact_handle1e_03_04(PARAMS); // BHI_S + case 0x05: return arcompact_handle1e_03_05(PARAMS); // BHS_S + case 0x06: return arcompact_handle1e_03_06(PARAMS); // BLO_S + case 0x07: return arcompact_handle1e_03_07(PARAMS); // BLS_S + } + + return 0; +} + +// handlers + +UINT32 arcompact_device::handle_jump_to_addr(int delay, int link, UINT32 address, UINT32 next_addr) +{ + if (delay) + { + m_delayactive = 1; + m_delayjump = address; + if (link) m_delaylinks = 1; + else m_delaylinks = 0; + return next_addr; + } + else + { + if (link) m_regs[REG_BLINK] = next_addr; + return address; + } + +} + +UINT32 arcompact_device::handle_jump_to_register(int delay, int link, UINT32 reg, UINT32 next_addr, int flag) +{ + if (reg == LIMM_REG) + arcompact_fatal("handle_jump_to_register called with LIMM register, call handle_jump_to_addr instead"); + + if ((reg == REG_ILINK1) || (reg == REG_ILINK2)) + { + if (flag) + { + arcompact_fatal("jump to ILINK1/ILINK2 not supported"); + return next_addr; + } + else + { + arcompact_fatal("illegal jump to ILINK1/ILINK2 not supported"); // FLAG bit must be set + return next_addr; + } + } + else + { + if (flag) + { + arcompact_fatal("illegal jump (flag bit set)"); // FLAG bit must NOT be set + return next_addr; + } + else + { + //arcompact_fatal("jump not supported"); + UINT32 target = m_regs[reg]; + return handle_jump_to_addr(delay, link, target, next_addr); + } + } + + return 0; +} + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle00_00(OPS_32) +{ + int size = 4; + + COMMON32_GET_CONDITION + + if (!check_condition(condition)) + return m_pc + (size>>0); + + // Branch Conditionally + // 0000 0sss ssss sss0 SSSS SSSS SSNQ QQQQ + INT32 address = (op & 0x07fe0000) >> 17; + address |= ((op & 0x0000ffc0) >> 6) << 10; + if (address & 0x80000) address = -0x80000 + (address & 0x7ffff); + int n = (op & 0x00000020) >> 5; op &= ~0x00000020; + + UINT32 realaddress = PC_ALIGNED32 + (address * 2); + + if (n) + { + m_delayactive = 1; + m_delayjump = realaddress; + m_delaylinks = 0; // don't link + } + else + { + // m_regs[REG_BLINK] = m_pc + (size >> 0); // don't link + return realaddress; + } + + + return m_pc + (size>>0); +} + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle00_01(OPS_32) +{ + int size = 4; + // Branch Unconditionally Far + INT32 address = (op & 0x07fe0000) >> 17; + address |= ((op & 0x0000ffc0) >> 6) << 10; + address |= ((op & 0x0000000f) >> 0) << 20; + if (address & 0x800000) address = -0x800000 + (address & 0x7fffff); + int n = (op & 0x00000020) >> 5; op &= ~0x00000020; +// int res = (op & 0x00000010) >> 4; op &= ~0x00000010; // should be set to 0 + + UINT32 realaddress = PC_ALIGNED32 + (address * 2); + + if (n) + { + m_delayactive = 1; + m_delayjump = realaddress; + m_delaylinks = 0; // don't link + } + else + { + // m_regs[REG_BLINK] = m_pc + (size >> 0); // don't link + return realaddress; + } + + + return m_pc + (size>>0); + +} + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle01_00_00dasm(OPS_32) +{ + int size = 4; + + // Branch and Link Conditionally + arcompact_log("unimplemented BLcc %08x", op); + return m_pc + (size>>0); +} + + + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle01_00_01dasm(OPS_32) +{ + int size = 4; + // Branch and Link Unconditionally Far + // 00001 sssssssss 10 SSSSSSSSSS N R TTTT + INT32 address = (op & 0x07fc0000) >> 17; + address |= ((op & 0x0000ffc0) >> 6) << 10; + address |= ((op & 0x0000000f) >> 0) << 20; + if (address & 0x800000) address = -0x800000 + (address&0x7fffff); + int n = (op & 0x00000020) >> 5; op &= ~0x00000020; +// int res = (op & 0x00000010) >> 4; op &= ~0x00000010; + + UINT32 realaddress = PC_ALIGNED32 + (address * 2); + + if (n) + { + m_delayactive = 1; + m_delayjump = realaddress; + m_delaylinks = 1; + } + else + { + m_regs[REG_BLINK] = m_pc + (size >> 0); + return realaddress; + } + + + return m_pc + (size>>0); +} + + + +ARCOMPACT_RETTYPE arcompact_device::arcompact_01_01_00_helper(OPS_32, const char* optext) +{ + int size = 4; + + // Branch on Compare / Bit Test - Register-Register + + COMMON32_GET_creg + COMMON32_GET_breg; + //int n = (op & 0x00000020) >> 5; + + + if ((breg != LIMM_REG) && (creg != LIMM_REG)) + { + } + else + { + //UINT32 limm; + //GET_LIMM_32; + size = 8; + } + + arcompact_log("unimplemented %s %08x (reg-reg)", optext, op); + return m_pc + (size>>0); +} + + +// register - register cases + +#define BR_REGREG_SETUP \ + /* Branch on Compare / Bit Test - Register-Register */ \ + int size = 4; \ + GET_01_01_01_BRANCH_ADDR; \ + COMMON32_GET_creg; \ + COMMON32_GET_breg; \ + int n = (op & 0x00000020) >> 5; \ + UINT32 b,c; \ + if ((breg != LIMM_REG) && (creg != LIMM_REG)) \ + { \ + b = m_regs[breg]; \ + c = m_regs[creg]; \ + } \ + else \ + { \ + UINT32 limm; \ + GET_LIMM_32; \ + size = 8; \ + \ + if (breg == LIMM_REG) \ + b = limm; \ + else \ + b = m_regs[breg]; \ + \ + if (creg == LIMM_REG) \ + c = limm; \ + else \ + c = m_regs[creg]; \ + } +#define BR_TAKEJUMP \ + /* take jump */ \ + UINT32 realaddress = PC_ALIGNED32 + (address * 2); \ + \ + if (n) \ + { \ + m_delayactive = 1; \ + m_delayjump = realaddress; \ + m_delaylinks = 0; \ + } \ + else \ + { \ + return realaddress; \ + } + + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle01_01_00_00(OPS_32) // register - register BREQ +{ + BR_REGREG_SETUP + + // BREQ + if (b == c) + { + BR_TAKEJUMP + } + + return m_pc + (size>>0); +} + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle01_01_00_01(OPS_32) // register - register BRNE +{ + BR_REGREG_SETUP + + // BRNE + if (b != c) + { + BR_TAKEJUMP + } + + return m_pc + (size>>0); +} + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle01_01_00_02(OPS_32) // regiter - register BRLT +{ + BR_REGREG_SETUP + + // BRLT (signed operation) + if ((INT32)b < (INT32)c) + { + BR_TAKEJUMP + } + + return m_pc + (size>>0); + +} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle01_01_00_03(OPS_32) // register - register BRGE +{ + BR_REGREG_SETUP + + // BRGE (signed operation) + if ((INT32)b >= (INT32)c) + { + BR_TAKEJUMP + } + + return m_pc + (size>>0); +} + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle01_01_00_04(OPS_32) // register - register BRLO +{ + BR_REGREG_SETUP + + // BRLO (unsigned operation) + if (b < c) + { + BR_TAKEJUMP + } + + return m_pc + (size>>0); +} + + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle01_01_00_05(OPS_32) // register - register BRHS +{ + BR_REGREG_SETUP + + // BRHS (unsigned operation) + if (b >= c) + { + BR_TAKEJUMP + } + + return m_pc + (size>>0); +} + + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle01_01_00_0e(OPS_32) { return arcompact_01_01_00_helper( PARAMS, "BBIT0");} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle01_01_00_0f(OPS_32) { return arcompact_01_01_00_helper( PARAMS, "BBIT1");} + +ARCOMPACT_RETTYPE arcompact_device::arcompact_01_01_01_helper(OPS_32, const char* optext) +{ + int size = 4; + arcompact_log("unimplemented %s %08x (reg-imm)", optext, op); + return m_pc + (size>>0); +} + +#define BR_REGIMM_SETUP \ + int size = 4; \ + GET_01_01_01_BRANCH_ADDR \ + COMMON32_GET_u6; \ + COMMON32_GET_breg; \ + int n = (op & 0x00000020) >> 5; \ + UINT32 b,c; \ + c = u; \ + /* comparing a LIMM to an immediate is pointless, is it a valid encoding? */ \ + if ((breg != LIMM_REG)) \ + { \ + b = m_regs[breg]; \ + } \ + else \ + { \ + UINT32 limm; \ + GET_LIMM_32; \ + size = 8; \ + b = limm; \ + } + +// register -immediate cases +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle01_01_01_00(OPS_32) // BREQ reg-imm +{ + BR_REGIMM_SETUP + + // BREQ + if (b == c) + { + BR_TAKEJUMP + } + + return m_pc + (size>>0); +} + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle01_01_01_01(OPS_32) // BRNE reg-imm +{ + BR_REGIMM_SETUP + + // BRNE + if (b != c) + { + BR_TAKEJUMP + } + + return m_pc + (size>>0); +} + + + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle01_01_01_02(OPS_32) // BRLT reg-imm +{ + BR_REGIMM_SETUP + + // BRLT (signed operation) + if ((INT32)b < (INT32)c) + { + BR_TAKEJUMP + } + + return m_pc + (size>>0); + +} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle01_01_01_03(OPS_32) +{ + BR_REGIMM_SETUP + + // BRGE (signed operation) + if ((INT32)b >= (INT32)c) + { + BR_TAKEJUMP + } + + return m_pc + (size>>0); +} + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle01_01_01_04(OPS_32) // register - immediate BRLO +{ + BR_REGIMM_SETUP + + // BRLO (unsigned operation) + if (b < c) + { + BR_TAKEJUMP + } + + return m_pc + (size>>0); + +} + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle01_01_01_05(OPS_32) // register - immediate BRHS +{ + BR_REGIMM_SETUP + + // BRHS (unsigned operation) + if (b >= c) + { + BR_TAKEJUMP + } + + return m_pc + (size>>0); +} + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle01_01_01_0e(OPS_32) { return arcompact_01_01_01_helper(PARAMS, "BBIT0"); } +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle01_01_01_0f(OPS_32) { return arcompact_01_01_01_helper(PARAMS, "BBIT1"); } + + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle02(OPS_32) +{ + int size = 4; + UINT32 limm = 0; + + int S = (op & 0x00008000) >> 15;// op &= ~0x00008000; + int s = (op & 0x00ff0000) >> 16;// op &= ~0x00ff0000; + if (S) s = -0x100 + s; + + COMMON32_GET_breg; + COMMON32_GET_areg + + int X = (op & 0x00000040) >> 6; //op &= ~0x00000040; + int Z = (op & 0x00000180) >> 7; //op &= ~0x00000180; + int a = (op & 0x00000600) >> 9; //op &= ~0x00000600; +// int D = (op & 0x00000800) >> 11;// op &= ~0x00000800; // we don't use the data cache currently + + UINT32 address = m_regs[breg]; + + if (breg == LIMM_REG) + { + GET_LIMM_32; + size = 8; + + address = limm; + } + + // address manipulation + if ((a == 0) || (a == 1)) + { + address = address + s; + } + else if (a == 2) + { + //address = address; + } + else if (a == 3) + { + if (Z == 0) + { + address = address + (s << 2); + } + else if (Z == 2) + { + address = address + (s << 1); + } + else // Z == 1 and Z == 3 are invalid here + { + arcompact_fatal("zz_ illegal LD %08x (data size %d mode %d)", op, Z, a); + } + } + + UINT32 readdata = 0; + + // read data + if (Z == 0) + { + readdata = READ32(address >> 2); + + if (X) // sign extend is not supported for long reads + arcompact_fatal("illegal LD %08x (data size %d mode %d with X)", op, Z, a); + + } + else if (Z == 1) + { + readdata = READ8(address >> 0); + + if (X) // todo + arcompact_fatal("illegal LD %08x (data size %d mode %d with X)", op, Z, a); + + } + else if (Z == 2) + { + readdata = READ16(address >> 1); + + if (X) // todo + arcompact_fatal("illegal LD %08x (data size %d mode %d with X)", op, Z, a); + + } + else if (Z == 3) + { // Z == 3 is always illegal + arcompact_fatal("xx_ illegal LD %08x (data size %d mode %d)", op, Z, a); + } + + m_regs[areg] = readdata; + + // writeback / increment + if ((a == 1) || (a == 2)) + { + if (breg==LIMM_REG) + arcompact_fatal("yy_ illegal LD %08x (data size %d mode %d)", op, Z, a); // using the LIMM as the base register and an increment mode is illegal + + m_regs[breg] = m_regs[breg] + s; + } + + return m_pc + (size>>0); + +} + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle03(OPS_32) +{ + int size = 4; + UINT32 limm = 0; + int got_limm = 0; + int S = (op & 0x00008000) >> 15; + int s = (op & 0x00ff0000) >> 16; + if (S) s = -0x100 + s; + + COMMON32_GET_breg; + COMMON32_GET_creg; + +// int R = (op & 0x00000001) >> 0; // bit 0 is reserved + int Z = (op & 0x00000006) >> 1; + int a = (op & 0x00000018) >> 3; +// int D = (op & 0x00000020) >> 5; // we don't use the data cache currently + + + UINT32 address = m_regs[breg]; + + if (breg == LIMM_REG) + { + GET_LIMM_32; + size = 8; + got_limm = 1; + + address = limm; + } + + UINT32 writedata = m_regs[creg]; + + if (creg == LIMM_REG) + { + if (!got_limm) + { + GET_LIMM_32; + size = 8; + } + + writedata = limm; + } + + // are LIMM addresses with 's' offset non-0 ('a' mode 0 / 3) legal? + // not mentioned in docs.. + + // address manipulation + if ((a == 0) || (a == 1)) + { + address = address + s; + } + else if (a == 2) + { + //address = address; + } + else if (a == 3) + { + if (Z == 0) + address = address + (s << 2); + else if (Z==2) + address = address + (s << 1); + else // Z == 1 and Z == 3 are invalid here + arcompact_fatal("illegal ST %08x (data size %d mode %d)", op, Z, a); + } + + // write data + if (Z == 0) + { + WRITE32(address >> 2, writedata); + } + else if (Z == 1) + { + WRITE8(address >> 0, writedata); + } + else if (Z == 2) + { + WRITE16(address >> 1, writedata); + } + else if (Z == 3) + { // Z == 3 is always illegal + arcompact_fatal("illegal ST %08x (data size %d mode %d)", op, Z, a); + } + + // writeback / increment + if ((a == 1) || (a == 2)) + { + if (breg==LIMM_REG) + arcompact_fatal("illegal ST %08x (data size %d mode %d)", op, Z, a); // using the LIMM as the base register and an increment mode is illegal + + m_regs[breg] = m_regs[breg] + s; + } + + return m_pc + (size>>0); + +} + + + + + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_helper(OPS_32, const char* optext, int ignore_dst, int b_reserved) +{ + int size = 4; + //UINT32 limm = 0; + int got_limm = 0; + + COMMON32_GET_p; + COMMON32_GET_breg; + + if (!b_reserved) + { + if (breg == LIMM_REG) + { + //GET_LIMM_32; + size = 8; + got_limm = 1; + } + else + { + } + } + else + { + } + + + if (p == 0) + { + COMMON32_GET_creg + + if (creg == LIMM_REG) + { + if (!got_limm) + { + //GET_LIMM_32; + size = 8; + } + } + else + { + } + } + else if (p == 1) + { + } + else if (p == 2) + { + } + else if (p == 3) + { + int M = (op & 0x00000020) >> 5; + + if (M == 0) + { + COMMON32_GET_creg + + if (creg == LIMM_REG) + { + if (!got_limm) + { + //GET_LIMM_32; + size = 8; + } + } + else + { + } + + } + else if (M == 1) + { + } + + } + + arcompact_log("unimplemented %s %08x (04 type helper)", optext, op); + + return m_pc + (size>>0); +} + + +#include "cpu/arcompact/arcompact.inc" + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_01(OPS_32) +{ + return arcompact_handle04_helper(PARAMS, opcodes_04[0x01], /*"ADC"*/ 0,0); +} + + + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_03(OPS_32) +{ + return arcompact_handle04_helper(PARAMS, opcodes_04[0x03], /*"SBC"*/ 0,0); +} + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_08(OPS_32) +{ + return arcompact_handle04_helper(PARAMS, opcodes_04[0x08], /*"MAX"*/ 0,0); +} + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_09(OPS_32) +{ + return arcompact_handle04_helper(PARAMS, opcodes_04[0x09], /*"MIN"*/ 0,0); +} + + + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_0b(OPS_32) +{ + return arcompact_handle04_helper(PARAMS, opcodes_04[0x0b], /*"TST"*/ 1,0); +} + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_0c(OPS_32) +{ + return arcompact_handle04_helper(PARAMS, opcodes_04[0x0c], /*"CMP"*/ 1,0); +} + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_0d(OPS_32) +{ + return arcompact_handle04_helper(PARAMS, opcodes_04[0x0d], /*"RCMP"*/ 1,0); +} + + + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_10(OPS_32) +{ + return arcompact_handle04_helper(PARAMS, opcodes_04[0x10], /*"BCLR"*/ 0,0); +} + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_11(OPS_32) +{ + return arcompact_handle04_helper(PARAMS, opcodes_04[0x11], /*"BTST"*/ 0,0); +} + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_12(OPS_32) +{ + return arcompact_handle04_helper(PARAMS, opcodes_04[0x12], /*"BXOR"*/ 0,0); +} + + + + + + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_1a(OPS_32) +{ + return arcompact_handle04_helper(PARAMS, opcodes_04[0x1a], /*"MPY"*/ 0,0); +} // * + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_1b(OPS_32) +{ + return arcompact_handle04_helper(PARAMS, opcodes_04[0x1b], /*"MPYH"*/ 0,0); +} // * + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_1c(OPS_32) +{ + return arcompact_handle04_helper(PARAMS, opcodes_04[0x1c], /*"MPYHU"*/ 0,0); +} // * + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_1d(OPS_32) +{ + return arcompact_handle04_helper(PARAMS, opcodes_04[0x1d], /*"MPYU"*/ 0,0); +} // * + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_20_p00(OPS_32) +{ + int size = 4; + UINT32 limm = 0; + int got_limm = 0; + + COMMON32_GET_creg + COMMON32_GET_F + + if (creg == LIMM_REG) + { + // opcode iiii i--- ppII IIII F--- CCCC CC-- ---- + // J limm 0010 0RRR 0010 0000 0RRR 1111 10RR RRRR [LIMM] (creg = LIMM) + + if (!got_limm) + { + GET_LIMM_32; + size = 8; + } + + return limm; + } + else + { + // opcode iiii i--- ppII IIII F--- CCCC CC-- ---- + // J [c] 0010 0RRR 0010 0000 0RRR CCCC CCRR RRRR + // J.F [ilink1] 0010 0RRR 0010 0000 1RRR 0111 01RR RRRR (creg = ILINK1, FLAG must be set) + // J.F [ilink2] 0010 0RRR 0010 0000 1RRR 0111 10RR RRRR (creg = ILINE2, FLAG must be set) + + if (F) + { + if ((creg == REG_ILINK1) || (creg == REG_ILINK2)) + { + arcompact_log("1 unimplemented J.F %08x", op); + } + else + { + // should not use .F unless jumping to ILINK1/2 + arcompact_fatal ("illegal 1 unimplemented J.F (F should not be set) %08x", op); + } + + } + else + { + if ((creg == REG_ILINK1) || (creg == REG_ILINK2)) + { + // should only jumping to ILINK1/2 if .F is set + arcompact_fatal("illegal 1 unimplemented J (F not set) %08x", op); + } + else + { + return m_regs[creg]; + } + } + } + + return m_pc + (size>>0); +} + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_20_p01(OPS_32) +{ + // opcode iiii i--- ppII IIII F--- uuuu uu-- ---- + // J u6 0010 0RRR 0110 0000 0RRR uuuu uuRR RRRR + int size = 4; + arcompact_log("2 unimplemented J %08x", op); + return m_pc + (size>>0); +} + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_20_p10(OPS_32) +{ + // opcode iiii i--- ppII IIII F--- ssss ssSS SSSS + // J s12 0010 0RRR 1010 0000 0RRR ssss ssSS SSSS + int size = 4; + arcompact_log("3 unimplemented J %08x", op); + return m_pc + (size>>0); +} + + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_20_p11_m0(OPS_32) // Jcc (no link, no delay) +{ + int size = 4; + UINT32 limm = 0; + int got_limm = 0; + + COMMON32_GET_creg + COMMON32_GET_CONDITION; + COMMON32_GET_F + + UINT32 c = 0; + + if (creg == LIMM_REG) + { + // opcode iiii i--- ppII IIII F--- cccc ccmq qqqq + // Jcc limm 0010 0RRR 1110 0000 0RRR 1111 100Q QQQQ [LIUMM] + if (!got_limm) + { + GET_LIMM_32; + size = 8; + } + + c = limm; + + } + else + { + // opcode iiii i--- ppII IIII F--- cccc ccmq qqqq + // Jcc [c] 0010 0RRR 1110 0000 0RRR CCCC CC0Q QQQQ + // no conditional links to ILINK1, ILINK2? + + c = m_regs[creg]; + } + + if (!check_condition(condition)) + return m_pc + (size>>0); + + if (!F) + { + // if F isn't set then the destination can't be ILINK1 or ILINK2 + + if ((creg == REG_ILINK1) || (creg == REG_ILINK1)) + { + arcompact_fatal ("fatal arcompact_handle04_20_p11_m0 J %08x (F not set but ILINK1 or ILINK2 used as dst)", op); + } + else + { + UINT32 realaddress = c; + return realaddress; + } + } + + if (F) + { + // if F is set then the destination MUST be ILINK1 or ILINK2 + + if ((creg == REG_ILINK1) || (creg == REG_ILINK1)) + { + arcompact_log("unimplemented arcompact_handle04_20_p11_m0 J %08x (F set)", op); + } + else + { + arcompact_fatal ("fatal arcompact_handle04_20_p11_m0 J %08x (F set but not ILINK1 or ILINK2 used as dst)", op); + + } + } + + + return m_pc + (size>>0); +} + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_20_p11_m1(OPS_32) +{ + // opcode iiii i--- ppII IIII F--- uuuu uumq qqqq + // Jcc u6 0010 0RRR 1110 0000 0RRR uuuu uu1Q QQQQ + int size = 4; + arcompact_log("unimplemented arcompact_handle04_20_p11_m1 J %08x (u6)", op); + return m_pc + (size>>0); +} + + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_21_p00(OPS_32) +{ + int size = 4; + UINT32 limm = 0; + int got_limm = 0; + + COMMON32_GET_creg + COMMON32_GET_F + + if (creg == LIMM_REG) + { + if (!got_limm) + { + GET_LIMM_32; + size = 8; + } + + handle_jump_to_addr(1,0,limm, m_pc + (size>>0)); + } + else + { + return handle_jump_to_register(1,0,creg, m_pc + (size>>0), F); // delay, no link + } + + return m_pc + (size>>0); +} + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_21_p01(OPS_32) +{ + int size = 4; + arcompact_log("unimplemented J.D (u6 type) %08x", op); + return m_pc + (size>>0); +} + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_21_p10(OPS_32) +{ + int size = 4; + arcompact_log("unimplemented J.D (s12 type) %08x", op); + return m_pc + (size>>0); +} + + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_21_p11_m0(OPS_32) // Jcc.D (no link, delay) +{ + int size = 4; + UINT32 limm = 0; + int got_limm = 0; + + COMMON32_GET_creg + COMMON32_GET_CONDITION; + COMMON32_GET_F + + //UINT32 c = 0; + + if (creg == LIMM_REG) + { + if (!got_limm) + { + GET_LIMM_32; + size = 8; + } + + // c = limm; + + } + else + { + // opcode iiii i--- ppII IIII F--- cccc ccmq qqqq + // Jcc [c] 0010 0RRR 1110 0000 0RRR CCCC CC0Q QQQQ + // no conditional links to ILINK1, ILINK2? + + // c = m_regs[creg]; + } + + if (!check_condition(condition)) + return m_pc + (size>>0); + + if (!F) + { + // if F isn't set then the destination can't be ILINK1 or ILINK2 + + if ((creg == REG_ILINK1) || (creg == REG_ILINK1)) + { + arcompact_log("unimplemented Jcc.D (p11_m0 type, illegal) %08x", op); + } + else + { + arcompact_log("unimplemented Jcc.D (p11_m0 type, unimplemented) %08x", op); + } + } + + if (F) + { + // if F is set then the destination MUST be ILINK1 or ILINK2 + + if ((creg == REG_ILINK1) || (creg == REG_ILINK1)) + { + arcompact_log("unimplemented Jcc.D.F (p11_m0 type, unimplemented) %08x", op); + } + else + { + arcompact_log("unimplemented Jcc.D.F (p11_m0 type, illegal) %08x", op); + } + } + + + return m_pc + (size>>0); +} + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_21_p11_m1(OPS_32) +{ + int size = 4; + arcompact_log("unimplemented arcompact_handle04_21_p11_m1 J.D %08x (u6)", op); + return m_pc + (size>>0); +} + + + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_22(OPS_32) +{ + return arcompact_handle04_helper(PARAMS, opcodes_04[0x22], /*"JL"*/ 1,1); +} + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_23(OPS_32) +{ + return arcompact_handle04_helper(PARAMS, opcodes_04[0x23], /*"JL.D"*/ 1,1); +} + + + + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_28(OPS_32) // LPcc (loop setup) +{ + int size = 4; +// COMMON32_GET_breg; // breg is reserved + COMMON32_GET_p; + + if (p == 0x00) + { + arcompact_fatal("> 0); + m_LP_END = PC_ALIGNED32 + (u * 2); + return m_pc + (size>>0); + } + + } + + return m_pc + (size>>0); + +} + + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_29(OPS_32) +{ + // leapster bios uses formats for FLAG that are not defined, bug I guess work anyway (P modes 0 / 1) + return arcompact_handle04_helper(PARAMS, opcodes_04[0x29], /*"FLAG"*/ 1,1); +} + + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_helper(OPS_32, const char* optext) +{ + int size = 4; + + COMMON32_GET_p; + //COMMON32_GET_breg; + + if (p == 0) + { + COMMON32_GET_creg + + if (creg == LIMM_REG) + { + //UINT32 limm; + //GET_LIMM_32; + size = 8; + } + else + { + } + } + else if (p == 1) + { + } + else if (p == 2) + { + } + else if (p == 3) + { + } + + arcompact_log("unimplemented %s %08x (type 04_2f)", optext, op); + return m_pc + (size>>0); +} + + + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_00(OPS_32) { return arcompact_handle04_2f_helper(PARAMS, "ASL"); } // ASL +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_01(OPS_32) { return arcompact_handle04_2f_helper(PARAMS, "ASR"); } // ASR + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_04(OPS_32) { return arcompact_handle04_2f_helper(PARAMS, "RCC"); } // RCC +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_05(OPS_32) { return arcompact_handle04_2f_helper(PARAMS, "SEXB"); } // SEXB +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_06(OPS_32) { return arcompact_handle04_2f_helper(PARAMS, "SEXW"); } // SEXW + + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_09(OPS_32) { return arcompact_handle04_2f_helper(PARAMS, "ABS"); } // ABS +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_0a(OPS_32) { return arcompact_handle04_2f_helper(PARAMS, "NOT"); } // NOT +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_0b(OPS_32) { return arcompact_handle04_2f_helper(PARAMS, "RCL"); } // RLC +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_0c(OPS_32) { return arcompact_handle04_2f_helper(PARAMS, "EX"); } // EX + + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_3f_01(OPS_32) { arcompact_log("SLEEP (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_3f_02(OPS_32) { arcompact_log("SWI / TRAP0 (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_3f_03(OPS_32) { arcompact_log("SYNC (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_3f_04(OPS_32) { arcompact_log("RTIE (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_3f_05(OPS_32) { arcompact_log("BRK (%08x)", op); return m_pc + (4 >> 0);} + + + + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_3x_helper(OPS_32, int dsize, int extend) +{ + int size = 4; + //UINT32 limm=0; + int got_limm = 0; + + + COMMON32_GET_breg; + COMMON32_GET_creg + + + + if (breg == LIMM_REG) + { + //GET_LIMM_32; + size = 8; + got_limm = 1; + + } + else + { + } + + if (creg == LIMM_REG) + { + if (!got_limm) + { + //GET_LIMM_32; + size = 8; + } + + } + else + { + } + + arcompact_log("unimplemented LD %08x (type 04_3x)", op); + return m_pc + (size>>0); +} + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_30(OPS_32) { return arcompact_handle04_3x_helper(PARAMS,0,0); } +// ZZ value of 0x0 with X of 1 is illegal +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_31(OPS_32) { return arcompact_handle04_3x_helper(PARAMS,0,1); } +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_32(OPS_32) { return arcompact_handle04_3x_helper(PARAMS,1,0); } +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_33(OPS_32) { return arcompact_handle04_3x_helper(PARAMS,1,1); } +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_34(OPS_32) { return arcompact_handle04_3x_helper(PARAMS,2,0); } +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_35(OPS_32) { return arcompact_handle04_3x_helper(PARAMS,2,1); } +// ZZ value of 0x3 is illegal +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_36(OPS_32) { return arcompact_handle04_3x_helper(PARAMS,3,0); } +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_37(OPS_32) { return arcompact_handle04_3x_helper(PARAMS,3,1); } + + + + + + + + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_02(OPS_32) { return arcompact_handle04_helper(PARAMS, "ASR", 0,0); } +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_03(OPS_32) { return arcompact_handle04_helper(PARAMS, "ROR", 0,0); } +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_04(OPS_32) { return arcompact_handle04_helper(PARAMS, "MUL64", 2,0); } // special +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_05(OPS_32) { return arcompact_handle04_helper(PARAMS, "MULU64", 2,0);} // special +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_06(OPS_32) { return arcompact_handle04_helper(PARAMS, "ADDS", 0,0); } +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_07(OPS_32) { return arcompact_handle04_helper(PARAMS, "SUBS", 0,0); } +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_08(OPS_32) { return arcompact_handle04_helper(PARAMS, "DIVAW", 0,0); } + + + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_0a(OPS_32) { return arcompact_handle04_helper(PARAMS, "ASLS", 0,0); } +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_0b(OPS_32) { return arcompact_handle04_helper(PARAMS, "ASRS", 0,0); } + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_28(OPS_32) { return arcompact_handle04_helper(PARAMS, "ADDSDW", 0,0); } +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_29(OPS_32) { return arcompact_handle04_helper(PARAMS, "SUBSDW", 0,0); } + + + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_0x_helper(OPS_32, const char* optext) +{ + int size = 4; + + COMMON32_GET_p; + //COMMON32_GET_breg; + + if (p == 0) + { + COMMON32_GET_creg + + if (creg == LIMM_REG) + { + //UINT32 limm; + //GET_LIMM_32; + size = 8; + + } + else + { + } + } + else if (p == 1) + { + } + else if (p == 2) + { + } + else if (p == 3) + { + } + + arcompact_log("unimplemented %s %08x", optext, op); + return m_pc + (size>>0); +} + + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_00(OPS_32) { return arcompact_handle05_2f_0x_helper(PARAMS, "SWAP"); } +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_01(OPS_32) { return arcompact_handle05_2f_0x_helper(PARAMS, "NORM"); } +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_02(OPS_32) { return arcompact_handle05_2f_0x_helper(PARAMS, "SAT16"); } +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_03(OPS_32) { return arcompact_handle05_2f_0x_helper(PARAMS, "RND16"); } +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_04(OPS_32) { return arcompact_handle05_2f_0x_helper(PARAMS, "ABSSW"); } +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_05(OPS_32) { return arcompact_handle05_2f_0x_helper(PARAMS, "ABSS"); } +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_06(OPS_32) { return arcompact_handle05_2f_0x_helper(PARAMS, "NEGSW"); } +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_07(OPS_32) { return arcompact_handle05_2f_0x_helper(PARAMS, "NEGS"); } +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_08(OPS_32) { return arcompact_handle05_2f_0x_helper(PARAMS, "NORMW"); } + + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle06(OPS_32) +{ + arcompact_log("op a,b,c (06 ARC ext) (%08x)", op ); + return m_pc + (4 >> 0); +} + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle07(OPS_32) +{ + arcompact_log("op a,b,c (07 User ext) (%08x)", op ); + return m_pc + (4 >> 0); +} + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle08(OPS_32) +{ + arcompact_log("op a,b,c (08 User ext) (%08x)", op ); + return m_pc + (4 >> 0); +} + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle09(OPS_32) +{ + arcompact_log("op a,b,c (09 Market ext) (%08x)", op ); + return m_pc + (4 >> 0); +} + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle0a(OPS_32) +{ + arcompact_log("op a,b,c (0a Market ext) (%08x)", op ); + return m_pc + (4 >> 0); +} + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle0b(OPS_32) +{ + arcompact_log("op a,b,c (0b Market ext) (%08x)", op ); + return m_pc + (4 >> 0); +} + + + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle0c_helper(OPS_16, const char* optext) +{ + arcompact_log("unimplemented %s %04x (0x0c group)", optext, op); + return m_pc + (2 >> 0); +} + + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle0c_00(OPS_16) +{ + return arcompact_handle0c_helper(PARAMS, "LD_S"); +} + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle0c_01(OPS_16) +{ + return arcompact_handle0c_helper(PARAMS, "LDB_S"); +} + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle0c_02(OPS_16) +{ + return arcompact_handle0c_helper(PARAMS, "LDW_S"); +} + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle0c_03(OPS_16) // ADD_S a <- b + c +{ + int areg, breg, creg; + + COMMON16_GET_areg; + COMMON16_GET_breg; + COMMON16_GET_creg; + + REG_16BIT_RANGE(areg); + REG_16BIT_RANGE(breg); + REG_16BIT_RANGE(creg); + + m_regs[areg] = m_regs[breg] + m_regs[creg]; + + return m_pc + (2 >> 0); +} + + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle0d_helper(OPS_16, const char* optext) +{ + arcompact_log("unimplemented %s %04x (0x0d group)", optext, op); + return m_pc + (2 >> 0); +} + + + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle0d_03(OPS_16) +{ + return arcompact_handle0d_helper(PARAMS, "ASR_S"); +} + + + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle0e_0x_helper(OPS_16, const char* optext, int revop) +{ + int h;// , breg; + int size = 2; + + GROUP_0e_GET_h; + + if (h == LIMM_REG) + { + //UINT32 limm; + //GET_LIMM; + size = 6; + } + else + { + } + + arcompact_log("unimplemented %s %04x (0x0e_0x group)", optext, op); + + return m_pc+ (size>>0); + +} + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle0e_00(OPS_16) // ADD_s b, b, h +{ + int h,breg; + int size = 2; + + GROUP_0e_GET_h; + COMMON16_GET_breg; + REG_16BIT_RANGE(breg); + + if (h == LIMM_REG) + { + UINT32 limm; + GET_LIMM_16; + size = 6; + + m_regs[breg] = m_regs[breg] + limm; + + } + else + { + m_regs[breg] = m_regs[breg] + m_regs[h]; + } + + return m_pc+ (size>>0); +} + +// 16-bit MOV with extended register range +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle0e_01(OPS_16) // MOV_S b <- h +{ + int h,breg; + int size = 2; + + GROUP_0e_GET_h; + COMMON16_GET_breg; + REG_16BIT_RANGE(breg); + + if (h == LIMM_REG) + { + // opcode iiii ibbb hhhI Ihhh + // MOV_S b, limm 0111 0bbb 1100 1111 [LIMM] (h == LIMM) + + UINT32 limm; + GET_LIMM_16; + size = 6; + + m_regs[breg] = limm; + + } + else + { + // opcode iiii ibbb hhhI Ihhh + // MOV_S b,h 0111 0bbb hhh0 1HHH + m_regs[breg] = m_regs[h]; + } + + return m_pc+ (size>>0); +} + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle0e_02(OPS_16) +{ + return arcompact_handle0e_0x_helper(PARAMS, "CMP_S", 0); +} + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle0e_03(OPS_16) // MOV_S h <- b +{ + int h,breg; + int size = 2; + + GROUP_0e_GET_h; + COMMON16_GET_breg; + REG_16BIT_RANGE(breg); + + if (h == LIMM_REG) // no result.. + { + } + + m_regs[h] = m_regs[breg]; + + return m_pc+ (size>>0); +} + + + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle0f_00_0x_helper(OPS_16, const char* optext) +{ + arcompact_log("unimplemented %s %04x", optext, op); + return m_pc + (2 >> 0); +} + + + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle0f_00_00(OPS_16) { return arcompact_handle0f_00_0x_helper(PARAMS, "J_S"); } +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle0f_00_01(OPS_16) { return arcompact_handle0f_00_0x_helper(PARAMS, "J_S.D"); } + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle0f_00_02(OPS_16) // JL_S +{ + int breg; + + COMMON16_GET_breg; + REG_16BIT_RANGE(breg); + + m_regs[REG_BLINK] = m_pc + (2 >> 0); + + return m_regs[breg]; +} + + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle0f_00_03(OPS_16) // JL_S.D +{ + int breg; + + COMMON16_GET_breg; + REG_16BIT_RANGE(breg); + + m_delayactive = 1; + m_delayjump = m_regs[breg]; + m_delaylinks = 1; + + return m_pc + (2 >> 0); +} + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle0f_00_06(OPS_16) { return arcompact_handle0f_00_0x_helper(PARAMS, "SUB_S.NE"); } + + + + +// Zero parameters (ZOP) +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle0f_00_07_00(OPS_16) { /*arcompact_log("NOP_S");*/ return m_pc + (2 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle0f_00_07_01(OPS_16) { arcompact_log("UNIMP_S"); return m_pc + (2 >> 0);} // Unimplemented Instruction, same as illegal, but recommended to fill blank space +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle0f_00_07_04(OPS_16) { arcompact_log("JEQ_S [blink]"); return m_pc + (2 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle0f_00_07_05(OPS_16) { arcompact_log("JNE_S [blink]"); return m_pc + (2 >> 0);} + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle0f_00_07_06(OPS_16) // J_S [blink] +{ + return m_regs[REG_BLINK]; +} + + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle0f_00_07_07(OPS_16) // J_S.D [blink] +{ + m_delayactive = 1; + m_delayjump = m_regs[REG_BLINK]; + m_delaylinks = 0; + + return m_pc + (2 >> 0); +} + + + + + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle0f_0x_helper(OPS_16, const char* optext, int nodst) +{ + arcompact_log("unimplemented %s %04x (0xf_0x group)", optext, op); + return m_pc + (2 >> 0); +} + + + + + + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle0f_06(OPS_16) { return arcompact_handle0f_0x_helper(PARAMS, "BIC_S",0); } + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle0f_0b(OPS_16) { return arcompact_handle0f_0x_helper(PARAMS, "TST_S",1); } +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle0f_0c(OPS_16) { return arcompact_handle0f_0x_helper(PARAMS, "MUL64_S",2); } // actual destination is special multiply registers +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle0f_0d(OPS_16) { return arcompact_handle0f_0x_helper(PARAMS, "SEXB_S",0); } +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle0f_0e(OPS_16) { return arcompact_handle0f_0x_helper(PARAMS, "SEXW_S",0); } + + + + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle0f_11(OPS_16) { return arcompact_handle0f_0x_helper(PARAMS, "ABS_S",0); } +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle0f_12(OPS_16) { return arcompact_handle0f_0x_helper(PARAMS, "NOT_S",0); } + + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle0f_18(OPS_16) { return arcompact_handle0f_0x_helper(PARAMS, "ASL_S",0); } + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle0f_1a(OPS_16) { return arcompact_handle0f_0x_helper(PARAMS, "ASR_S",0); } + + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle0f_1c(OPS_16) { return arcompact_handle0f_0x_helper(PARAMS, "ASR1_S",0); } +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle0f_1d(OPS_16) { return arcompact_handle0f_0x_helper(PARAMS, "LSR1_S",0); } + + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle0f_1e(OPS_16) // special +{ + arcompact_log("unimplemented TRAP_S %04x", op); + return m_pc + (2 >> 0); +} + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle0f_1f(OPS_16) // special +{ + arcompact_log("unimplemented BRK_S %04x", op); + return m_pc + (2 >> 0); +} + + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle_ld_helper(OPS_16, const char* optext, int shift, int swap) +{ + arcompact_log("unimplemented %s %04x (ld/st group %d %d)", optext, op, shift, swap); + return m_pc + (2 >> 0); +} + + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle10(OPS_16) +{ // LD_S c, [b, u7] + int breg, creg, u; + + COMMON16_GET_breg; + COMMON16_GET_creg; + COMMON16_GET_u5; + + REG_16BIT_RANGE(breg); + REG_16BIT_RANGE(creg); + + u <<= 2; // check + m_regs[creg] = READ32((m_regs[breg] + u) >> 2); + + return m_pc + (2 >> 0); +} + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle11(OPS_16) +{ + // LDB_S c, [b, u5] + int breg, creg, u; + + COMMON16_GET_breg; + COMMON16_GET_creg; + COMMON16_GET_u5; + + REG_16BIT_RANGE(breg); + REG_16BIT_RANGE(creg); + +// u <<= 0; // check + m_regs[creg] = READ8((m_regs[breg] + u) >> 0); + + return m_pc + (2 >> 0); +} + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle12(OPS_16) +{ + // LDB_W c, [b, u6] + int breg, creg, u; + + COMMON16_GET_breg; + COMMON16_GET_creg; + COMMON16_GET_u5; + + REG_16BIT_RANGE(breg); + REG_16BIT_RANGE(creg); + + u <<= 1; + m_regs[creg] = READ16((m_regs[breg] + u) >> 1); + + return m_pc + (2 >> 0); +} + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle13(OPS_16) +{ + return arcompact_handle_ld_helper(PARAMS, "LDW_S.X", 1, 0); +} + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle14(OPS_16) // ST_S c, [b, u7] +{ + int breg, creg, u; + + COMMON16_GET_breg; + COMMON16_GET_creg; + COMMON16_GET_u5; + + REG_16BIT_RANGE(breg); + REG_16BIT_RANGE(creg); + + u <<= 2; + + WRITE32((m_regs[breg] + u) >> 2, m_regs[creg]); + + return m_pc + (2 >> 0); +} + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle15(OPS_16) // STB_S c. [b, u6] +{ + int breg, creg, u; + + COMMON16_GET_breg; + COMMON16_GET_creg; + COMMON16_GET_u5; + + REG_16BIT_RANGE(breg); + REG_16BIT_RANGE(creg); + +// u <<= 0; + + WRITE8((m_regs[breg] + u) >> 0, m_regs[creg]); + + return m_pc + (2 >> 0); +} + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle16(OPS_16) // STW_S c. [b, u6] +{ + int breg, creg, u; + + COMMON16_GET_breg; + COMMON16_GET_creg; + COMMON16_GET_u5; + + REG_16BIT_RANGE(breg); + REG_16BIT_RANGE(creg); + + u <<= 1; + + WRITE16((m_regs[breg] + u) >> 1, m_regs[creg]); + + return m_pc + (2 >> 0); + +} + + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle_l7_0x_helper(OPS_16, const char* optext) +{ + arcompact_log("unimplemented %s %04x (l7_0x group)", optext, op); + return m_pc + (2 >> 0); +} + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle17_05(OPS_16) +{ + return arcompact_handle_l7_0x_helper(PARAMS, "BCLR_S"); +} + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle17_07(OPS_16) +{ + return arcompact_handle_l7_0x_helper(PARAMS, "BTST_S"); +} + + + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle18_0x_helper(OPS_16, const char* optext, int st) +{ + arcompact_log("unimplemented %s %04x (0x18_0x group)", optext, op); + return m_pc + (2 >> 0); +} + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle18_00(OPS_16) // LD_S b, [SP, u7] +{ + int breg; + UINT32 u; + + COMMON16_GET_breg; + COMMON16_GET_u5; + + REG_16BIT_RANGE(breg); + + UINT32 address = m_regs[REG_SP] + (u << 2); + + m_regs[breg] = READ32(address >> 2); + + return m_pc + (2 >> 0); +} + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle18_01(OPS_16) +{ + return arcompact_handle18_0x_helper(PARAMS, "LDB_S (SP)", 0); +} + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle18_02(OPS_16) // ST_S b, [SP, u7] +{ + int breg; + UINT32 u; + + COMMON16_GET_breg; + COMMON16_GET_u5; + + REG_16BIT_RANGE(breg); + + UINT32 address = m_regs[REG_SP] + (u << 2); + + WRITE32(address >> 2, m_regs[breg]); + + return m_pc + (2 >> 0); +} + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle18_03(OPS_16) +{ + return arcompact_handle18_0x_helper(PARAMS, "STB_S (SP)", 1); +} + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle18_04(OPS_16) // ADD_S b, SP, u7 +{ + int breg; + UINT32 u; + + COMMON16_GET_breg; + COMMON16_GET_u5; + + REG_16BIT_RANGE(breg); + + m_regs[breg] = m_regs[REG_SP] + (u << 2); + + return m_pc + (2 >> 0); +} + +// op bits remaining for 0x18_05_xx subgroups 0x001f +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle18_05_00(OPS_16) +{ + int u; + COMMON16_GET_u5; + + m_regs[REG_SP] = m_regs[REG_SP] + (u << 2); + + return m_pc + (2 >> 0); +} + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle18_05_01(OPS_16) +{ + int u; + COMMON16_GET_u5; + + m_regs[REG_SP] = m_regs[REG_SP] - (u << 2); + + return m_pc + (2 >> 0); +} + +// op bits remaining for 0x18_06_xx subgroups 0x0700 +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle18_06_01(OPS_16) // POP_S b +{ + int breg; + COMMON16_GET_breg; + REG_16BIT_RANGE(breg); + + m_regs[breg] = READ32(m_regs[REG_SP] >> 2); + m_regs[REG_SP] += 4; + + return m_pc + (2 >> 0); +} + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle18_06_11(OPS_16) // POP_S blink +{ + // breg bits are reserved + m_regs[REG_BLINK] = READ32(m_regs[REG_SP] >> 2 ); + m_regs[REG_SP] += 4; + + return m_pc + (2 >> 0); +} + +// op bits remaining for 0x18_07_xx subgroups 0x0700 +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle18_07_01(OPS_16) // PUSH_S b +{ + int breg; + COMMON16_GET_breg; + REG_16BIT_RANGE(breg); + + m_regs[REG_SP] -= 4; + + WRITE32(m_regs[REG_SP] >> 2, m_regs[breg]); + + return m_pc + (2 >> 0); +} + + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle18_07_11(OPS_16) // PUSH_S [blink] +{ + // breg bits are reserved + + m_regs[REG_SP] -= 4; + + WRITE32(m_regs[REG_SP] >> 2, m_regs[REG_BLINK]); + + return m_pc + (2 >> 0); +} + + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle19_0x_helper(OPS_16, const char* optext, int shift, int format) +{ + arcompact_log("unimplemented %s %04x (0x19_0x group)", optext, op); + return m_pc + (2 >> 0); +} + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle19_00(OPS_16) { return arcompact_handle19_0x_helper(PARAMS, "LD_S", 2, 0); } +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle19_01(OPS_16) { return arcompact_handle19_0x_helper(PARAMS, "LDB_S", 0, 0); } +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle19_02(OPS_16) { return arcompact_handle19_0x_helper(PARAMS, "LDW_S", 1, 0); } +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle19_03(OPS_16) { return arcompact_handle19_0x_helper(PARAMS, "ADD_S", 2, 1); } + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle1a(OPS_16) +{ + arcompact_log("unimplemented MOV_S x, [PCL, x] %04x", op); + return m_pc + (2 >> 0); +} + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle1b(OPS_16) // MOV_S b, u8 +{ + int breg; + UINT32 u; + COMMON16_GET_breg; + COMMON16_GET_u8; + REG_16BIT_RANGE(breg); + + m_regs[breg] = u; + + return m_pc + (2 >> 0); +} + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle1c_00(OPS_16) // ADD_S b, b, u7 +{ + int breg; + UINT32 u; + COMMON16_GET_breg; + COMMON16_GET_u7; + REG_16BIT_RANGE(breg); + + m_regs[breg] = m_regs[breg] + u; + + return m_pc + (2 >> 0); +} + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle1c_01(OPS_16) // CMP b, u7 +{ + int breg; + UINT32 u; + COMMON16_GET_breg; + COMMON16_GET_u7; + REG_16BIT_RANGE(breg); + + // flag setting ALWAYS occurs on CMP operations, even 16-bit ones even without a .F opcode type + + // TODO: verify this flag setting logic + + // unsigned checks + if (m_regs[breg] == u) + { + STATUS32_SET_Z; + } + else + { + STATUS32_CLEAR_Z; + } + + if (m_regs[breg] < u) + { + STATUS32_SET_C; + } + else + { + STATUS32_CLEAR_C; + } + // signed checks + INT32 temp = (INT32)m_regs[breg] - (INT32)u; + + if (temp < 0) + { + STATUS32_SET_N; + } + else + { + STATUS32_CLEAR_N; + } + + // if signs of source values don't match, and sign of result doesn't match the first source value, then we've overflowed? + if ((m_regs[breg] & 0x80000000) != (u & 0x80000000)) + { + if ((m_regs[breg] & 0x80000000) != (temp & 0x80000000)) + { + STATUS32_SET_V; + } + else + { + STATUS32_CLEAR_V; + } + } + + // only sets flags, no result written + + return m_pc + (2 >> 0); +} + + + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle1d_00(OPS_16) // BREQ_S b,0,s8 +{ + int breg; + COMMON16_GET_breg; + REG_16BIT_RANGE(breg); + + if (!m_regs[breg]) + { + int s = (op & 0x007f) >> 0; op &= ~0x007f; + if (s & 0x40) s = -0x40 + (s & 0x3f); + UINT32 realaddress = PC_ALIGNED32 + (s * 2); + //m_regs[REG_BLINK] = m_pc + (2 >> 0); // don't link + return realaddress; + } + + return m_pc + (2 >> 0); +} + + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle1d_01(OPS_16) // BRNE_S b,0,s8 +{ + int breg; + COMMON16_GET_breg; + REG_16BIT_RANGE(breg); + + if (m_regs[breg]) + { + int s = (op & 0x007f) >> 0; op &= ~0x007f; + if (s & 0x40) s = -0x40 + (s & 0x3f); + UINT32 realaddress = PC_ALIGNED32 + (s * 2); + //m_regs[REG_BLINK] = m_pc + (2 >> 0); // don't link + return realaddress; + } + + return m_pc + (2 >> 0); +} + + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle1e_0x_helper(OPS_16, const char* optext) +{ + arcompact_log("unimplemented %s %04x (1e_0x type)", optext, op); + return m_pc + (2 >> 0); +} + + + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle1e_00(OPS_16) // B_S s10 (branch always) +{ + int s = (op & 0x01ff) >> 0; op &= ~0x01ff; + if (s & 0x100) s = -0x100 + (s & 0xff); + UINT32 realaddress = PC_ALIGNED32 + (s * 2); + //m_regs[REG_BLINK] = m_pc + (2 >> 0); // don't link + return realaddress; +} + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle1e_01(OPS_16) // BEQ_S s10 (branch is zero bit is set) +{ + if (STATUS32_CHECK_Z) + { + int s = (op & 0x01ff) >> 0; op &= ~0x01ff; + if (s & 0x100) s = -0x100 + (s & 0xff); + UINT32 realaddress = PC_ALIGNED32 + (s * 2); + //m_regs[REG_BLINK] = m_pc + (2 >> 0); // don't link + return realaddress; + } + + return m_pc + (2 >> 0); +} + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle1e_02(OPS_16) // BNE_S s10 (branch if zero bit isn't set) +{ + if (!STATUS32_CHECK_Z) + { + int s = (op & 0x01ff) >> 0; op &= ~0x01ff; + if (s & 0x100) s = -0x100 + (s & 0xff); + UINT32 realaddress = PC_ALIGNED32 + (s * 2); + //m_regs[REG_BLINK] = m_pc + (2 >> 0); // don't link + return realaddress; + } + + return m_pc + (2 >> 0); +} + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle1e_03_0x_helper(OPS_16, const char* optext) +{ + arcompact_log("unimplemented %s %04x", optext, op); + return m_pc + (2 >> 0); +} + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle1e_03_00(OPS_16) { return arcompact_handle1e_03_0x_helper(PARAMS, "BGT_S"); } +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle1e_03_01(OPS_16) { return arcompact_handle1e_03_0x_helper(PARAMS, "BGE_S"); } + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle1e_03_02(OPS_16) // BLT_S +{ + if (CONDITION_LT) + { + int s = (op & 0x003f) >> 0; op &= ~0x003f; + if (s & 0x020) s = -0x20 + (s & 0x1f); + UINT32 realaddress = PC_ALIGNED32 + (s * 2); + //m_regs[REG_BLINK] = m_pc + (2 >> 0); // don't link + return realaddress; + } + + return m_pc + (2 >> 0); +} + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle1e_03_03(OPS_16) // BLE_S +{ + if (CONDITION_LE) + { + int s = (op & 0x003f) >> 0; op &= ~0x003f; + if (s & 0x020) s = -0x20 + (s & 0x1f); + UINT32 realaddress = PC_ALIGNED32 + (s * 2); + //m_regs[REG_BLINK] = m_pc + (2 >> 0); // don't link + return realaddress; + } + + return m_pc + (2 >> 0); +} + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle1e_03_04(OPS_16) { return arcompact_handle1e_03_0x_helper(PARAMS, "BHI_S"); } +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle1e_03_05(OPS_16) { return arcompact_handle1e_03_0x_helper(PARAMS, "BHS_S"); } +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle1e_03_06(OPS_16) { return arcompact_handle1e_03_0x_helper(PARAMS, "BLO_S"); } +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle1e_03_07(OPS_16) { return arcompact_handle1e_03_0x_helper(PARAMS, "BLS_S"); } + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle1f(OPS_16) // BL_S s13 +{ + int s = (op & 0x07ff) >> 0; op &= ~0x07ff; + if (s & 0x400) s = -0x400 + (s & 0x3ff); + + UINT32 realaddress = PC_ALIGNED32 + (s * 4); + + m_regs[REG_BLINK] = m_pc + (2 >> 0); + return realaddress; +} + +/************************************************************************************************************************************ +* * +* illegal opcode handlers (disassembly) * +* * +************************************************************************************************************************************/ + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle01_01_00_06(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0); } +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle01_01_00_07(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0); } +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle01_01_00_08(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0); } +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle01_01_00_09(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0); } +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle01_01_00_0a(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0); } +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle01_01_00_0b(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0); } +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle01_01_00_0c(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0); } +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle01_01_00_0d(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0); } + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle01_01_01_06(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0); } +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle01_01_01_07(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0); } +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle01_01_01_08(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0); } +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle01_01_01_09(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0); } +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle01_01_01_0a(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0); } +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle01_01_01_0b(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0); } +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle01_01_01_0c(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0); } +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle01_01_01_0d(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0); } + + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_1e(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_1f(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_24(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_25(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_26(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_27(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2c(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2d(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2e(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_0d(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_0e(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_0f(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_10(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_11(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_12(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_13(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_14(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_15(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_16(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_17(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_18(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_19(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_1a(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_1b(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_1c(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_1d(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_1e(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_1f(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_20(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_21(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_22(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_23(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_24(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_25(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_26(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_27(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_28(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_29(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_2a(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_2b(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_2c(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_2d(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_2e(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_2f(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_30(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_31(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_32(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_33(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_34(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_35(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_36(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_37(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_38(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_39(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_3a(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_3b(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_3c(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_3d(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_3e(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} + + + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_09(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_0a(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_0b(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_0c(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_0d(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_0e(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_0f(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_10(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_11(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_12(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_13(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_14(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_15(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_16(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_17(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_18(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_19(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_1a(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_1b(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_1c(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_1d(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_1e(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_1f(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_20(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_21(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_22(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_23(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_24(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_25(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_26(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_27(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_28(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_29(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_2a(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_2b(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_2c(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_2d(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_2e(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_2f(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_30(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_31(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_32(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_33(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_34(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_35(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_36(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_37(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_38(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_39(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_3a(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_3b(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_3c(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_3d(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_3e(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} + + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_3f_00(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_3f_06(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_3f_07(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_3f_08(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_3f_09(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_3f_0a(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_3f_0b(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_3f_0c(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_3f_0d(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_3f_0e(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_3f_0f(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_3f_10(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_3f_11(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_3f_12(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_3f_13(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_3f_14(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_3f_15(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_3f_16(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_3f_17(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_3f_18(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_3f_19(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_3f_1a(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_3f_1b(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_3f_1c(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_3f_1d(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_3f_1e(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_3f_1f(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_3f_20(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_3f_21(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_3f_22(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_3f_23(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_3f_24(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_3f_25(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_3f_26(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_3f_27(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_3f_28(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_3f_29(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_3f_2a(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_3f_2b(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_3f_2c(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_3f_2d(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_3f_2e(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_3f_2f(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_3f_30(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_3f_31(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_3f_32(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_3f_33(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_3f_34(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_3f_35(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_3f_36(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_3f_37(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_3f_38(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_3f_39(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_3f_3a(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_3f_3b(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_3f_3c(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_3f_3d(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_3f_3e(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_2f_3f_3f(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_3f_00(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_3f_01(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_3f_02(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_3f_03(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_3f_04(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_3f_05(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_3f_06(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_3f_07(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_3f_08(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_3f_09(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_3f_0a(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_3f_0b(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_3f_0c(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_3f_0d(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_3f_0e(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_3f_0f(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_3f_10(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_3f_11(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_3f_12(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_3f_13(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_3f_14(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_3f_15(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_3f_16(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_3f_17(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_3f_18(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_3f_19(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_3f_1a(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_3f_1b(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_3f_1c(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_3f_1d(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_3f_1e(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_3f_1f(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_3f_20(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_3f_21(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_3f_22(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_3f_23(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_3f_24(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_3f_25(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_3f_26(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_3f_27(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_3f_28(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_3f_29(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_3f_2a(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_3f_2b(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_3f_2c(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_3f_2d(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_3f_2e(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_3f_2f(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_3f_30(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_3f_31(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_3f_32(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_3f_33(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_3f_34(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_3f_35(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_3f_36(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_3f_37(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_3f_38(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_3f_39(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_3f_3a(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_3f_3b(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_3f_3c(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_3f_3d(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_3f_3e(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2f_3f_3f(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} + + + + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_38(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_39(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_3a(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_3b(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_3c(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_3d(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_3e(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle04_3f(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} + + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_09(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_0c(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_0d(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_0e(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_0f(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_10(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_11(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_12(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_13(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_14(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_15(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_16(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_17(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_18(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_19(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_1a(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_1b(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_1c(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_1d(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_1e(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_1f(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_20(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_21(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_22(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_23(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_24(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_25(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_26(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_27(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2a(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2b(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2c(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2d(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_2e(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_30(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_31(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_32(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_33(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_34(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_35(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_36(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_37(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_38(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_39(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_3a(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_3b(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_3c(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_3d(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_3e(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle05_3f(OPS_32) { arcompact_fatal(" (%08x)", op); return m_pc + (4 >> 0);} + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle0f_00_04(OPS_16) { arcompact_fatal(" (%08x)", op); return m_pc + (2 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle0f_00_05(OPS_16) { arcompact_fatal(" (%08x)", op); return m_pc + (2 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle0f_00_07_02(OPS_16) { arcompact_fatal(" (%08x)", op); return m_pc + (2 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle0f_00_07_03(OPS_16) { arcompact_fatal(" (%08x)", op); return m_pc + (2 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle0f_01(OPS_16) { arcompact_fatal(" (%08x)", op); return m_pc + (2 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle0f_03(OPS_16) { arcompact_fatal(" (%08x)", op); return m_pc + (2 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle0f_08(OPS_16) { arcompact_fatal(" (%08x)", op); return m_pc + (2 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle0f_09(OPS_16) { arcompact_fatal(" (%08x)", op); return m_pc + (2 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle0f_0a(OPS_16) { arcompact_fatal(" (%08x)", op); return m_pc + (2 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle0f_17(OPS_16) { arcompact_fatal(" (%08x)", op); return m_pc + (2 >> 0);} + +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle18_05_02(OPS_16) { arcompact_fatal(" (%04x)", op); return m_pc + (2 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle18_05_03(OPS_16) { arcompact_fatal(" (%04x)", op); return m_pc + (2 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle18_05_04(OPS_16) { arcompact_fatal(" (%04x)", op); return m_pc + (2 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle18_05_05(OPS_16) { arcompact_fatal(" (%04x)", op); return m_pc + (2 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle18_05_06(OPS_16) { arcompact_fatal(" (%04x)", op); return m_pc + (2 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle18_05_07(OPS_16) { arcompact_fatal(" (%04x)", op); return m_pc + (2 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle18_06_00(OPS_16) { arcompact_fatal(" (%04x)", op); return m_pc + (2 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle18_06_02(OPS_16) { arcompact_fatal(" (%04x)", op); return m_pc + (2 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle18_06_03(OPS_16) { arcompact_fatal(" (%04x)", op); return m_pc + (2 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle18_06_04(OPS_16) { arcompact_fatal(" (%04x)", op); return m_pc + (2 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle18_06_05(OPS_16) { arcompact_fatal(" (%04x)", op); return m_pc + (2 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle18_06_06(OPS_16) { arcompact_fatal(" (%04x)", op); return m_pc + (2 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle18_06_07(OPS_16) { arcompact_fatal(" (%04x)", op); return m_pc + (2 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle18_06_08(OPS_16) { arcompact_fatal(" (%04x)", op); return m_pc + (2 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle18_06_09(OPS_16) { arcompact_fatal(" (%04x)", op); return m_pc + (2 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle18_06_0a(OPS_16) { arcompact_fatal(" (%04x)", op); return m_pc + (2 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle18_06_0b(OPS_16) { arcompact_fatal(" (%04x)", op); return m_pc + (2 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle18_06_0c(OPS_16) { arcompact_fatal(" (%04x)", op); return m_pc + (2 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle18_06_0d(OPS_16) { arcompact_fatal(" (%04x)", op); return m_pc + (2 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle18_06_0e(OPS_16) { arcompact_fatal(" (%04x)", op); return m_pc + (2 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle18_06_0f(OPS_16) { arcompact_fatal(" (%04x)", op); return m_pc + (2 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle18_06_10(OPS_16) { arcompact_fatal(" (%04x)", op); return m_pc + (2 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle18_06_12(OPS_16) { arcompact_fatal(" (%04x)", op); return m_pc + (2 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle18_06_13(OPS_16) { arcompact_fatal(" (%04x)", op); return m_pc + (2 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle18_06_14(OPS_16) { arcompact_fatal(" (%04x)", op); return m_pc + (2 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle18_06_15(OPS_16) { arcompact_fatal(" (%04x)", op); return m_pc + (2 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle18_06_16(OPS_16) { arcompact_fatal(" (%04x)", op); return m_pc + (2 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle18_06_17(OPS_16) { arcompact_fatal(" (%04x)", op); return m_pc + (2 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle18_06_18(OPS_16) { arcompact_fatal(" (%04x)", op); return m_pc + (2 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle18_06_19(OPS_16) { arcompact_fatal(" (%04x)", op); return m_pc + (2 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle18_06_1a(OPS_16) { arcompact_fatal(" (%04x)", op); return m_pc + (2 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle18_06_1b(OPS_16) { arcompact_fatal(" (%04x)", op); return m_pc + (2 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle18_06_1c(OPS_16) { arcompact_fatal(" (%04x)", op); return m_pc + (2 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle18_06_1d(OPS_16) { arcompact_fatal(" (%04x)", op); return m_pc + (2 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle18_06_1e(OPS_16) { arcompact_fatal(" (%04x)", op); return m_pc + (2 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle18_06_1f(OPS_16) { arcompact_fatal(" (%04x)", op); return m_pc + (2 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle18_07_00(OPS_16) { arcompact_fatal(" (%04x)", op); return m_pc + (2 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle18_07_02(OPS_16) { arcompact_fatal(" (%04x)", op); return m_pc + (2 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle18_07_03(OPS_16) { arcompact_fatal(" (%04x)", op); return m_pc + (2 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle18_07_04(OPS_16) { arcompact_fatal(" (%04x)", op); return m_pc + (2 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle18_07_05(OPS_16) { arcompact_fatal(" (%04x)", op); return m_pc + (2 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle18_07_06(OPS_16) { arcompact_fatal(" (%04x)", op); return m_pc + (2 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle18_07_07(OPS_16) { arcompact_fatal(" (%04x)", op); return m_pc + (2 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle18_07_08(OPS_16) { arcompact_fatal(" (%04x)", op); return m_pc + (2 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle18_07_09(OPS_16) { arcompact_fatal(" (%04x)", op); return m_pc + (2 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle18_07_0a(OPS_16) { arcompact_fatal(" (%04x)", op); return m_pc + (2 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle18_07_0b(OPS_16) { arcompact_fatal(" (%04x)", op); return m_pc + (2 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle18_07_0c(OPS_16) { arcompact_fatal(" (%04x)", op); return m_pc + (2 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle18_07_0d(OPS_16) { arcompact_fatal(" (%04x)", op); return m_pc + (2 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle18_07_0e(OPS_16) { arcompact_fatal(" (%04x)", op); return m_pc + (2 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle18_07_0f(OPS_16) { arcompact_fatal(" (%04x)", op); return m_pc + (2 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle18_07_10(OPS_16) { arcompact_fatal(" (%04x)", op); return m_pc + (2 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle18_07_12(OPS_16) { arcompact_fatal(" (%04x)", op); return m_pc + (2 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle18_07_13(OPS_16) { arcompact_fatal(" (%04x)", op); return m_pc + (2 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle18_07_14(OPS_16) { arcompact_fatal(" (%04x)", op); return m_pc + (2 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle18_07_15(OPS_16) { arcompact_fatal(" (%04x)", op); return m_pc + (2 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle18_07_16(OPS_16) { arcompact_fatal(" (%04x)", op); return m_pc + (2 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle18_07_17(OPS_16) { arcompact_fatal(" (%04x)", op); return m_pc + (2 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle18_07_18(OPS_16) { arcompact_fatal(" (%04x)", op); return m_pc + (2 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle18_07_19(OPS_16) { arcompact_fatal(" (%04x)", op); return m_pc + (2 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle18_07_1a(OPS_16) { arcompact_fatal(" (%04x)", op); return m_pc + (2 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle18_07_1b(OPS_16) { arcompact_fatal(" (%04x)", op); return m_pc + (2 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle18_07_1c(OPS_16) { arcompact_fatal(" (%04x)", op); return m_pc + (2 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle18_07_1d(OPS_16) { arcompact_fatal(" (%04x)", op); return m_pc + (2 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle18_07_1e(OPS_16) { arcompact_fatal(" (%04x)", op); return m_pc + (2 >> 0);} +ARCOMPACT_RETTYPE arcompact_device::arcompact_handle18_07_1f(OPS_16) { arcompact_fatal(" (%04x)", op); return m_pc + (2 >> 0);} diff --git a/src/devices/cpu/arcompact/arcompact_make.py b/src/devices/cpu/arcompact/arcompact_make.py new file mode 100644 index 00000000000..080fd72b426 --- /dev/null +++ b/src/devices/cpu/arcompact/arcompact_make.py @@ -0,0 +1,434 @@ +#!/usr/bin/python + +from __future__ import print_function +import sys + +def EmitGroup04_Handle_NZ_Flags(f, funcname, opname): + print(" if (result & 0x80000000) { STATUS32_SET_N; }", file=f) + print(" else { STATUS32_CLEAR_N; }", file=f) + print(" if (result == 0x00000000) { STATUS32_SET_Z; }", file=f) + print(" else { STATUS32_CLEAR_Z; }", file=f) + +def EmitGroup04_Handle_NZC_LSR1_Flags(f, funcname, opname): + print(" if (result & 0x80000000) { STATUS32_SET_N; }", file=f) + print(" else { STATUS32_CLEAR_N; }", file=f) + print(" if (result == 0x00000000) { STATUS32_SET_Z; }", file=f) + print(" else { STATUS32_CLEAR_Z; }", file=f) + print(" if (c == 0x00000001) { STATUS32_SET_C; }", file=f) + print(" else { STATUS32_CLEAR_C; }", file=f) + +def EmitGroup04_Handle_NZCV_ADD_Flags(f, funcname, opname): + print(" if (result & 0x80000000) { STATUS32_SET_N; }", file=f) + print(" else { STATUS32_CLEAR_N; }", file=f) + print(" if (result == 0x00000000) { STATUS32_SET_Z; }", file=f) + print(" else { STATUS32_CLEAR_Z; }", file=f) + print(" if ((b & 0x80000000) == (c & 0x80000000))", file=f) + print(" {", file=f) + print(" if ((result & 0x80000000) != (b & 0x80000000))", file=f) + print(" {", file=f) + print(" STATUS32_SET_V;", file=f) + print(" }", file=f) + print(" else", file=f) + print(" {", file=f) + print(" STATUS32_CLEAR_V;", file=f) + print(" }", file=f) + print(" }", file=f) + print(" if (b < c)", file=f) + print(" {", file=f) + print(" STATUS32_SET_C;", file=f) + print(" }", file=f) + print(" else", file=f) + print(" {", file=f) + print(" STATUS32_CLEAR_C;", file=f) + print(" }", file=f) + + +def EmitGroup04_no_Flags(f, funcname, opname): + print(" // no flag changes", file=f) + +def EmitGroup04_unsupported_Flags(f, funcname, opname): + print(" arcompact_fatal(\"arcompact_handle%s (%s) (F set)\\n\"); // not yet supported" % (funcname, opname), file=f) + +def EmitGroup04_Flaghandler(f,funcname, opname, flagcondition, flaghandler): + if flagcondition == -1: + print(" if (F)", file=f) + print(" {", file=f) + flaghandler(f, funcname, opname) + print(" }", file=f) + elif flagcondition == 0: + print(" if (0)", file=f) + print(" {", file=f) + flaghandler(f, funcname, opname) + print(" }", file=f) + elif flagcondition == 1: + print(" if (1)", file=f) + print(" {", file=f) + flaghandler(f, funcname, opname) + print(" }", file=f) + +def EmitGroup04_u5fragment(f,funcname, opname, opexecute, opwrite, opwrite_alt, ignore_a, breg_is_dst_only, flagcondition, flaghandler): + print(" int size = 4;", file=f) + + if breg_is_dst_only == 0: + print(" UINT32 limm = 0;", file=f) + + print("/* int got_limm = 0; */", file=f) + print(" ", file=f) + print(" COMMON32_GET_breg;", file=f) + + if flagcondition == -1: + print(" COMMON32_GET_F;", file=f) + + print(" COMMON32_GET_u6;", file=f) + + if ignore_a == 0: + print(" COMMON32_GET_areg;", file=f) + elif ignore_a == 1: + print(" //COMMON32_GET_areg; // areg is reserved / not used", file=f) + elif ignore_a == 2: + print(" //COMMON32_GET_areg; // areg bits already used as opcode select", file=f) + elif ignore_a == 3: + print(" //COMMON32_GET_areg; // areg bits already used as condition code select", file=f) + print(" ", file=f) + + print(" UINT32 c;", file=f) + if breg_is_dst_only == 0: + print(" UINT32 b;", file=f) + print(" ", file=f) + print(" /* is having b as LIMM valid here? LIMM vs. fixed u6 value makes no sense */", file=f) + print(" if (breg == LIMM_REG)", file=f) + print(" {", file=f) + print(" GET_LIMM_32;", file=f) + print(" size = 8;", file=f) + print("/* got_limm = 1; */", file=f) + print(" b = limm;", file=f) + print(" }", file=f) + print(" else", file=f) + print(" {", file=f) + print(" b = m_regs[breg];", file=f) + print(" }", file=f) + + print(" ", file=f) + print(" c = u;", file=f) + print(" ", file=f) + print(" /* todo: if areg = LIMM then there is no result (but since that register can never be read, I guess it doesn't matter if we store it there anyway?) */", file=f) + +def EmitGroup04(f,funcname, opname, opexecute, opwrite, opwrite_alt, ignore_a, breg_is_dst_only, flagcondition, flaghandler): + # the mode 0x00 handler + print("ARCOMPACT_RETTYPE arcompact_device::arcompact_handle%s_p00(OPS_32)" % funcname, file=f) + print("{", file=f) + print(" int size = 4;", file=f) + + print(" UINT32 limm = 0;", file=f) + + print(" int got_limm = 0;", file=f) + print(" ", file=f) + print(" COMMON32_GET_breg;", file=f) + + if flagcondition == -1: + print(" COMMON32_GET_F;", file=f) + + print(" COMMON32_GET_creg;", file=f) + + if ignore_a == 0: + print(" COMMON32_GET_areg;", file=f) + elif ignore_a == 1: + print(" //COMMON32_GET_areg; // areg is reserved / not used", file=f) + elif ignore_a == 2: + print(" //COMMON32_GET_areg; // areg bits already used as opcode select", file=f) + + print(" ", file=f) + + print(" UINT32 c;", file=f) + if breg_is_dst_only == 0: + print(" UINT32 b;", file=f) + print(" ", file=f) + print(" if (breg == LIMM_REG)", file=f) + print(" {", file=f) + print(" GET_LIMM_32;", file=f) + print(" size = 8;", file=f) + print(" got_limm = 1;", file=f) + print(" b = limm;", file=f) + print(" }", file=f) + print(" else", file=f) + print(" {", file=f) + print(" b = m_regs[breg];", file=f) + print(" }", file=f) + + print(" ", file=f) + print(" if (creg == LIMM_REG)", file=f) + print(" {", file=f) + print(" if (!got_limm)", file=f) + print(" {", file=f) + print(" GET_LIMM_32;", file=f) + print(" size = 8;", file=f) + print(" }", file=f) + print(" c = limm;", file=f) + print(" }", file=f) + print(" else", file=f) + print(" {", file=f) + print(" c = m_regs[creg];", file=f) + print(" }", file=f) + print(" /* todo: is the limm, limm syntax valid? (it's pointless.) */", file=f) + print(" /* todo: if areg = LIMM then there is no result (but since that register can never be read, I guess it doesn't matter if we store it there anyway?) */", file=f) + print(" %s" % opexecute, file=f) + print(" %s" % opwrite, file=f) + print(" ", file=f) + EmitGroup04_Flaghandler(f,funcname,opname,flagcondition,flaghandler) + print(" return m_pc + (size >> 0);", file=f) + print("}", file=f) + print("", file=f) + print("", file=f) + # the mode 0x01 handler + print("ARCOMPACT_RETTYPE arcompact_device::arcompact_handle%s_p01(OPS_32)" % funcname, file=f) + print("{", file=f) + EmitGroup04_u5fragment(f,funcname, opname, opexecute, opwrite, opwrite_alt, ignore_a, breg_is_dst_only, flagcondition, flaghandler) + print(" %s" % opexecute, file=f) + print(" %s" % opwrite, file=f) + print(" ", file=f) + EmitGroup04_Flaghandler(f,funcname,opname,flagcondition,flaghandler) + print(" return m_pc + (size >> 0);", file=f) + print("}", file=f) + print("", file=f) + print("", file=f) + # the mode 0x10 handler + print("ARCOMPACT_RETTYPE arcompact_device::arcompact_handle%s_p10(OPS_32)" % funcname, file=f) + if ignore_a == 2: + print("{", file=f) + print(" int size = 4;", file=f) + print(" arcompact_fatal(\"illegal arcompact_handle%s_p10 (ares bits already used as opcode select, can't be used as s12) (%s)\\n\");" % (funcname, opname), file=f) + print(" return m_pc + (size >> 0);", file=f) + print("}", file=f) + else: + print("{", file=f) + print(" int size = 4;", file=f) + if breg_is_dst_only == 0: + print(" UINT32 limm = 0;", file=f) + + print("/* int got_limm = 0; */", file=f) + print(" ", file=f) + print(" COMMON32_GET_breg;", file=f) + + if flagcondition == -1: + print(" COMMON32_GET_F;", file=f) + + print(" COMMON32_GET_s12;", file=f) + + # areg can't be used here, it's used for s12 bits + + print(" ", file=f) + print(" UINT32 c;", file=f) + if breg_is_dst_only == 0: + print(" UINT32 b;", file=f) + print(" ", file=f) + print(" /* is having b as LIMM valid here? LIMM vs. fixed u6 value makes no sense */", file=f) + print(" if (breg == LIMM_REG)", file=f) + print(" {", file=f) + print(" GET_LIMM_32;", file=f) + print(" size = 8;", file=f) + print("/* got_limm = 1; */", file=f) + print(" b = limm;", file=f) + print(" }", file=f) + print(" else", file=f) + print(" {", file=f) + print(" b = m_regs[breg];", file=f) + print(" }", file=f) + + print(" ", file=f) + print(" c = (UINT32)S;", file=f) + print(" ", file=f) + print(" /* todo: if areg = LIMM then there is no result (but since that register can never be read, I guess it doesn't matter if we store it there anyway?) */", file=f) + print(" %s" % opexecute, file=f) + print(" %s" % opwrite_alt, file=f) + print(" ", file=f) + EmitGroup04_Flaghandler(f,funcname,opname,flagcondition,flaghandler) + print(" return m_pc + (size >> 0);", file=f) + print("}", file=f) + print("", file=f) + print("", file=f) + # the mode 0x11 m0 handler + print("ARCOMPACT_RETTYPE arcompact_device::arcompact_handle%s_p11_m0(OPS_32)" % funcname, file=f) + if ignore_a == 2: + print("{", file=f) + print(" int size = 4;", file=f) + print(" arcompact_fatal(\"illegal arcompact_handle%s_p11_m0 (ares bits already used as opcode select, can't be used as Q condition) (%s)\\n\");" % (funcname, opname), file=f) + print(" return m_pc + (size >> 0);", file=f) + print("}", file=f) + else: + print("{", file=f) + print(" int size = 4;", file=f) + print(" arcompact_fatal(\"arcompact_handle%s_p11_m0 (%s)\\n\");" % (funcname, opname), file=f) + print(" return m_pc + (size >> 0);", file=f) + print("}", file=f) + print("", file=f) + print("", file=f) + # the mode 0x11 m1 handler + print("ARCOMPACT_RETTYPE arcompact_device::arcompact_handle%s_p11_m1(OPS_32)" % funcname, file=f) + if ignore_a == 2: + print("{", file=f) + print(" int size = 4;", file=f) + print(" arcompact_fatal(\"illegal arcompact_handle%s_p11_m1 (ares bits already used as opcode select, can't be used as Q condition) (%s)\\n\");" % (funcname, opname), file=f) + print(" return m_pc + (size >> 0);", file=f) + print("}", file=f) + else: + print("{", file=f) + EmitGroup04_u5fragment(f,funcname, opname, opexecute, opwrite, opwrite_alt, 3, breg_is_dst_only, flagcondition, flaghandler) + print(" COMMON32_GET_CONDITION;", file=f) + print(" if (!check_condition(condition))", file=f) + print(" return m_pc + (size>>0);", file=f) + print("", file=f) + print(" %s" % opexecute, file=f) + print(" %s" % opwrite_alt, file=f) + print(" ", file=f) + EmitGroup04_Flaghandler(f,funcname,opname,flagcondition,flaghandler) + print(" return m_pc + (size >> 0);", file=f) + print("}", file=f) + print("", file=f) + print("", file=f) + + +# xxx_S c, b, u3 format opcodes (note c is destination) +def EmitGroup0d(f,funcname, opname, opexecute, opwrite): + print("ARCOMPACT_RETTYPE arcompact_device::arcompact_handle%s(OPS_16)" % funcname, file=f) + print("{", file=f) + print(" int u, breg, creg;", file=f) + print("", file=f) + print(" COMMON16_GET_u3;", file=f) + print(" COMMON16_GET_breg;", file=f) + print(" COMMON16_GET_creg;", file=f) + print("", file=f) + print(" REG_16BIT_RANGE(breg);", file=f) + print(" REG_16BIT_RANGE(creg);", file=f) + print("", file=f) + print(" %s" % opexecute, file=f) + print(" %s" % opwrite, file=f) + print("", file=f) + print(" return m_pc + (2 >> 0);", file=f) + print("}", file=f) + print("", file=f) + print("", file=f) + + +# xxx_S b <- b,c format opcodes +def EmitGroup0f(f,funcname, opname, opexecute, opwrite): + print("ARCOMPACT_RETTYPE arcompact_device::arcompact_handle%s(OPS_16)"% funcname, file=f) + print("{", file=f) + print(" int breg, creg;", file=f) + print("", file=f) + print(" COMMON16_GET_breg;", file=f) + print(" COMMON16_GET_creg;", file=f) + print("", file=f) + print(" REG_16BIT_RANGE(breg);", file=f) + print(" REG_16BIT_RANGE(creg);", file=f) + print("", file=f) + print(" %s" % opexecute, file=f) + print(" %s" % opwrite, file=f) + print("", file=f) + print(" return m_pc + (2 >> 0);", file=f) + print("}", file=f) + print("", file=f) + print("", file=f) + + +# xxx_S b, b, u5 format opcodes +def EmitGroup17(f,funcname, opname, opexecute): + print("ARCOMPACT_RETTYPE arcompact_device::arcompact_handle%s(OPS_16)" % funcname, file=f) + print("{", file=f) + print(" int breg, u;", file=f) + print(" ", file=f) + print(" COMMON16_GET_breg;", file=f) + print(" COMMON16_GET_u5;", file=f) + print(" ", file=f) + print(" REG_16BIT_RANGE(breg);", file=f) + print(" ", file=f) + print(" %s" % opexecute, file=f) + print(" ", file=f) + print(" return m_pc + (2 >> 0);", file=f) + print("}", file=f) + print("", file=f) + print("", file=f) + + + +try: + f = open(sys.argv[1], "w") +except Exception: + err = sys.exc_info()[1] + sys.stderr.write("cannot write file %s [%s]\n" % (sys.argv[1], err)) + sys.exit(1) + + +EmitGroup04(f, "04_00", "ADD", "UINT32 result = b + c;", "m_regs[areg] = result;", "m_regs[breg] = result;", 0,0, -1, EmitGroup04_Handle_NZCV_ADD_Flags ) + +EmitGroup04(f, "04_02", "SUB", "UINT32 result = b - c;", "m_regs[areg] = result;", "m_regs[breg] = result;", 0,0, -1, EmitGroup04_unsupported_Flags ) + +EmitGroup04(f, "04_04", "AND", "UINT32 result = b & c;", "if (areg != LIMM_REG) { m_regs[areg] = result; }", "if (breg != LIMM_REG) { m_regs[breg] = result; }", 0,0, -1, EmitGroup04_Handle_NZ_Flags ) +EmitGroup04(f, "04_05", "OR", "UINT32 result = b | c;", "m_regs[areg] = result;", "m_regs[breg] = result;", 0,0, -1, EmitGroup04_unsupported_Flags ) +EmitGroup04(f, "04_06", "BIC", "UINT32 result = b & (~c);", "m_regs[areg] = result;", "m_regs[breg] = result;", 0,0, -1, EmitGroup04_unsupported_Flags ) +EmitGroup04(f, "04_07", "XOR", "UINT32 result = b ^ c;", "m_regs[areg] = result;", "m_regs[breg] = result;", 0,0, -1, EmitGroup04_unsupported_Flags ) + +EmitGroup04(f, "04_0a", "MOV", "UINT32 result = c;", "m_regs[breg] = result;", "m_regs[breg] = result;", 1,1, -1, EmitGroup04_Handle_NZ_Flags ) # special case, result always goes to breg + +EmitGroup04(f, "04_0e", "RSUB", "UINT32 result = c - b;", "m_regs[areg] = result;", "m_regs[breg] = result;", 0,0, -1, EmitGroup04_unsupported_Flags ) +EmitGroup04(f, "04_0f", "BSET", "UINT32 result = b | (1 << (c & 0x1f));", "m_regs[areg] = result;", "m_regs[breg] = result;", 0,0, -1, EmitGroup04_unsupported_Flags ) + +EmitGroup04(f, "04_13", "BMSK", "UINT32 result = b & ((1<<(c+1))-1);", "m_regs[areg] = result;", "m_regs[breg] = result;", 0,0, -1, EmitGroup04_unsupported_Flags ) + + +EmitGroup04(f, "04_14", "ADD1", "UINT32 result = b + (c << 1);", "m_regs[areg] = result;", "m_regs[breg] = result;", 0,0, -1, EmitGroup04_unsupported_Flags ) +EmitGroup04(f, "04_15", "ADD2", "UINT32 result = b + (c << 2);", "m_regs[areg] = result;", "m_regs[breg] = result;", 0,0, -1, EmitGroup04_unsupported_Flags ) +EmitGroup04(f, "04_16", "ADD3", "UINT32 result = b + (c << 3);", "m_regs[areg] = result;", "m_regs[breg] = result;", 0,0, -1, EmitGroup04_unsupported_Flags ) +EmitGroup04(f, "04_17", "SUB1", "UINT32 result = b - (c << 1);", "m_regs[areg] = result;", "m_regs[breg] = result;", 0,0, -1, EmitGroup04_unsupported_Flags ) +EmitGroup04(f, "04_18", "SUB2", "UINT32 result = b - (c << 2);", "m_regs[areg] = result;", "m_regs[breg] = result;", 0,0, -1, EmitGroup04_unsupported_Flags ) +EmitGroup04(f, "04_19", "SUB3", "UINT32 result = b - (c << 3);", "m_regs[areg] = result;", "m_regs[breg] = result;", 0,0, -1, EmitGroup04_unsupported_Flags ) + +EmitGroup04(f, "04_2a", "LR", "m_regs[breg] = READAUX(c);", "", "", 1,1, -1, EmitGroup04_no_Flags ) # this can't be conditional (todo) +EmitGroup04(f, "04_2b", "SR", "WRITEAUX(c,b);", "", "", 1,0, -1, EmitGroup04_no_Flags ) # this can't be conditional (todo) + + + +EmitGroup04(f, "05_00", "ASL", "UINT32 result = b << (c&0x1f);", "m_regs[areg] = result;", "m_regs[breg] = result;", 0,0, -1, EmitGroup04_unsupported_Flags ) +EmitGroup04(f, "05_01", "LSR", "UINT32 result = b >> (c&0x1f);", "m_regs[areg] = result;", "m_regs[breg] = result;", 0,0, -1, EmitGroup04_unsupported_Flags ) + +# the 04_2f subgroup uses the same encoding, but the areg is already used as sub-opcode select, so any modes relying on areg bits for other reasons (sign, condition) (modes 10, 11m0, 11m1) are illegal. the destination is also breg not areg +EmitGroup04(f, "04_2f_02", "LSR1", "UINT32 result = c >> 1;", "m_regs[breg] = result;","", 2,1, -1, EmitGroup04_Handle_NZC_LSR1_Flags ) # no alt handler (invalid path) +EmitGroup04(f, "04_2f_03", "ROR", "int shift = 1; UINT32 mask = (1 << (shift)) - 1; mask <<= (32-shift); UINT32 result = ((c >> shift) & ~mask) | ((c << (32-shift)) & mask);", "m_regs[breg] = result;","", 2,1, -1, EmitGroup04_Handle_NZC_LSR1_Flags ) + + +EmitGroup04(f, "04_2f_07", "EXTB", "UINT32 result = c & 0x000000ff;", "m_regs[breg] = result;","", 2,1, -1, EmitGroup04_unsupported_Flags ) # ^ +EmitGroup04(f, "04_2f_08", "EXTW", "UINT32 result = c & 0x0000ffff;", "m_regs[breg] = result;","", 2,1, -1, EmitGroup04_unsupported_Flags ) # ^ + +# xxx_S c, b, u3 format opcodes (note c is destination) +EmitGroup0d(f, "0d_00", "ADD_S", "UINT32 result = m_regs[breg] + u;", "m_regs[creg] = result;" ) +EmitGroup0d(f, "0d_01", "SUB_S", "UINT32 result = m_regs[breg] - u;", "m_regs[creg] = result;" ) +EmitGroup0d(f, "0d_02", "ASL_S", "UINT32 result = m_regs[breg] << u;", "m_regs[creg] = result;" ) + +# xxx_S b <- b,c format opcodes (or in some cases xxx_S b,c) +EmitGroup0f(f, "0f_02", "SUB_S", "UINT32 result = m_regs[breg] - m_regs[creg];", "m_regs[breg] = result;" ) +EmitGroup0f(f, "0f_04", "AND_S", "UINT32 result = m_regs[breg] & m_regs[creg];", "m_regs[breg] = result;" ) +EmitGroup0f(f, "0f_05", "OR_S", "UINT32 result = m_regs[breg] | m_regs[creg];", "m_regs[breg] = result;" ) +EmitGroup0f(f, "0f_07", "XOR_S", "UINT32 result = m_regs[breg] ^ m_regs[creg];", "m_regs[breg] = result;" ) +EmitGroup0f(f, "0f_0f", "EXTB_S","UINT32 result = m_regs[creg] & 0x000000ff;", "m_regs[breg] = result;" ) +EmitGroup0f(f, "0f_10", "EXTW_S","UINT32 result = m_regs[creg] & 0x0000ffff;", "m_regs[breg] = result;" ) +EmitGroup0f(f, "0f_13", "NEG_S"," UINT32 result = 0 - m_regs[creg];", "m_regs[breg] = result;" ) + +EmitGroup0f(f, "0f_14", "ADD1_S"," UINT32 result = m_regs[breg] + (m_regs[creg] <<1);", "m_regs[breg] = result;" ) +EmitGroup0f(f, "0f_15", "ADD2_S"," UINT32 result = m_regs[breg] + (m_regs[creg] <<2);", "m_regs[breg] = result;" ) +EmitGroup0f(f, "0f_16", "ADD3_S"," UINT32 result = m_regs[breg] + (m_regs[creg] <<3);", "m_regs[breg] = result;" ) + +EmitGroup0f(f, "0f_19", "LSR_S", "UINT32 result = m_regs[breg] >> (m_regs[creg]&0x1f);","m_regs[breg] = result;" ) +EmitGroup0f(f, "0f_1b", "ASL1_S","UINT32 result = m_regs[creg] << 1;", "m_regs[breg] = result;" ) + + +# xxx_S b, b, u5 format opcodes +EmitGroup17(f, "17_00", "ASL_S", "m_regs[breg] = m_regs[breg] << (u&0x1f);" ) +EmitGroup17(f, "17_01", "LSR_S", "m_regs[breg] = m_regs[breg] >> (u&0x1f);" ) +EmitGroup17(f, "17_02", "ASR_S", "INT32 temp = (INT32)m_regs[breg]; m_regs[breg] = temp >> (u&0x1f); // treat it as a signed value, so sign extension occurs during shift" ) +EmitGroup17(f, "17_03", "SUB_S", "m_regs[breg] = m_regs[breg] - u;" ) +EmitGroup17(f, "17_04", "BSET_S", "m_regs[breg] = m_regs[breg] | (1 << (u & 0x1f));" ) + +EmitGroup17(f, "17_06", "BMSK_S", "m_regs[breg] = m_regs[breg] | ((1 << (u + 1)) - 1);" ) + + + + diff --git a/src/devices/cpu/arcompact/arcompactdasm.c b/src/devices/cpu/arcompact/arcompactdasm.c new file mode 100644 index 00000000000..0b917a05d56 --- /dev/null +++ b/src/devices/cpu/arcompact/arcompactdasm.c @@ -0,0 +1,92 @@ +// license:BSD-3-Clause +// copyright-holders:David Haywood +/*********************************\ + + ARCompact disassembler + +\*********************************/ + +#include "emu.h" +#include + +#include "arcompactdasm_dispatch.h" +#include "arcompactdasm_ops.h" + + +/*****************************************************************************/ + + + +/*****************************************************************************/ + + +#define ARCOMPACT_OPERATION ((op & 0xf800) >> 11) + +extern char *output; + +CPU_DISASSEMBLE(arcompact) +{ + int size = 2; + + UINT32 op = oprom[0] | (oprom[1] << 8); + output = buffer; + + UINT8 instruction = ARCOMPACT_OPERATION; + + if (instruction < 0x0c) + { + size = 4; + op <<= 16; + op |= oprom[2] | (oprom[3] << 8); + + op &= ~0xf8000000; + + switch (instruction) // 32-bit instructions (with optional extra dword for immediate data) + { + case 0x00: size = arcompact_handle00_dasm(DASM_PARAMS); break; // Bcc + case 0x01: size = arcompact_handle01_dasm(DASM_PARAMS); break; // BLcc/BRcc + case 0x02: size = arcompact_handle02_dasm(DASM_PARAMS); break; // LD r+o + case 0x03: size = arcompact_handle03_dasm(DASM_PARAMS); break; // ST r+o + case 0x04: size = arcompact_handle04_dasm(DASM_PARAMS); break; // op a,b,c (basecase) + case 0x05: size = arcompact_handle05_dasm(DASM_PARAMS); break; // op a,b,c (05 ARC ext) + case 0x06: size = arcompact_handle06_dasm(DASM_PARAMS); break; // op a,b,c (06 ARC ext) + case 0x07: size = arcompact_handle07_dasm(DASM_PARAMS); break; // op a,b,c (07 User ext) + case 0x08: size = arcompact_handle08_dasm(DASM_PARAMS); break; // op a,b,c (08 User ext) + case 0x09: size = arcompact_handle09_dasm(DASM_PARAMS); break; // op a,b,c (09 Market ext) + case 0x0a: size = arcompact_handle0a_dasm(DASM_PARAMS); break; // op a,b,c (0a Market ext) + case 0x0b: size = arcompact_handle0b_dasm(DASM_PARAMS); break; // op a,b,c (0b Market ext) + } + } + else + { + size = 2; + op &= ~0xf800; + + + switch (instruction) // 16-bit instructions + { + case 0x0c: size = arcompact_handle0c_dasm(DASM_PARAMS); break; // Load/Add reg-reg + case 0x0d: size = arcompact_handle0d_dasm(DASM_PARAMS); break; // Add/Sub/Shft imm + case 0x0e: size = arcompact_handle0e_dasm(DASM_PARAMS); break; // Mov/Cmp/Add + case 0x0f: size = arcompact_handle0f_dasm(DASM_PARAMS); break; // op_S b,b,c (single 16-bit ops) + case 0x10: size = arcompact_handle10_dasm(DASM_PARAMS); break; // LD_S + case 0x11: size = arcompact_handle11_dasm(DASM_PARAMS); break; // LDB_S + case 0x12: size = arcompact_handle12_dasm(DASM_PARAMS); break; // LDW_S + case 0x13: size = arcompact_handle13_dasm(DASM_PARAMS); break; // LSW_S.X + case 0x14: size = arcompact_handle14_dasm(DASM_PARAMS); break; // ST_S + case 0x15: size = arcompact_handle15_dasm(DASM_PARAMS); break; // STB_S + case 0x16: size = arcompact_handle16_dasm(DASM_PARAMS); break; // STW_S + case 0x17: size = arcompact_handle17_dasm(DASM_PARAMS); break; // Shift/Sub/Bit + case 0x18: size = arcompact_handle18_dasm(DASM_PARAMS); break; // Stack Instr + case 0x19: size = arcompact_handle19_dasm(DASM_PARAMS); break; // GP Instr + case 0x1a: size = arcompact_handle1a_dasm(DASM_PARAMS); break; // PCL Instr + case 0x1b: size = arcompact_handle1b_dasm(DASM_PARAMS); break; // MOV_S + case 0x1c: size = arcompact_handle1c_dasm(DASM_PARAMS); break; // ADD_S/CMP_S + case 0x1d: size = arcompact_handle1d_dasm(DASM_PARAMS); break; // BRcc_S + case 0x1e: size = arcompact_handle1e_dasm(DASM_PARAMS); break; // Bcc_S + case 0x1f: size = arcompact_handle1f_dasm(DASM_PARAMS); break; // BL_S + } + } + + return size | DASMFLAG_SUPPORTED; +} diff --git a/src/devices/cpu/arcompact/arcompactdasm_dispatch.c b/src/devices/cpu/arcompact/arcompactdasm_dispatch.c new file mode 100644 index 00000000000..ddd809b84bc --- /dev/null +++ b/src/devices/cpu/arcompact/arcompactdasm_dispatch.c @@ -0,0 +1,990 @@ +// license:BSD-3-Clause +// copyright-holders:David Haywood +/*********************************\ + + ARCompact disassembler + +\*********************************/ + +#include "emu.h" +#include + +#include "arcompactdasm_dispatch.h" +#include "arcompactdasm_ops.h" + +int arcompact_handle00_dasm(DASM_OPS_32) +{ + int size = 4; + UINT8 subinstr = (op & 0x00010000) >> 16; + op &= ~0x00010000; + + switch (subinstr) + { + case 0x00: size = arcompact_handle00_00_dasm(DASM_PARAMS); break; // Branch Conditionally + case 0x01: size = arcompact_handle00_01_dasm(DASM_PARAMS); break; // Branch Unconditionally Far + } + + return size; +} + +int arcompact_handle01_dasm(DASM_OPS_32) +{ + int size = 4; + UINT8 subinstr = (op & 0x00010000) >> 16; + op &= ~0x00010000; + + switch (subinstr) + { + case 0x00: size = arcompact_handle01_00_dasm(DASM_PARAMS); break; // Branh & Link + case 0x01: size = arcompact_handle01_01_dasm(DASM_PARAMS); break; // Branch on Compare + } + + return size; +} + +int arcompact_handle01_00_dasm(DASM_OPS_32) +{ + int size = 4; + UINT8 subinstr2 = (op & 0x00020000) >> 17; + op &= ~0x00020000; + + switch (subinstr2) + { + case 0x00: size = arcompact_handle01_00_00dasm(DASM_PARAMS); break; // Branch and Link Conditionally + case 0x01: size = arcompact_handle01_00_01dasm(DASM_PARAMS); break; // Branch and Link Unconditional Far + } + + return size; +} + +int arcompact_handle01_01_dasm(DASM_OPS_32) +{ + int size = 4; + + UINT8 subinstr2 = (op & 0x00000010) >> 4; + op &= ~0x00000010; + + switch (subinstr2) + { + case 0x00: size = arcompact_handle01_01_00_dasm(DASM_PARAMS); break; // Branch on Compare Register-Register + case 0x01: size = arcompact_handle01_01_01_dasm(DASM_PARAMS); break; // Branch on Compare/Bit Test Register-Immediate + } + + return size; +} + +int arcompact_handle01_01_00_dasm(DASM_OPS_32) +{ + int size = 4; + UINT8 subinstr3 = (op & 0x0000000f) >> 0; + op &= ~0x0000000f; + + switch (subinstr3) + { + case 0x00: size = arcompact_handle01_01_00_00_dasm(DASM_PARAMS); break; // BREQ (reg-reg) + case 0x01: size = arcompact_handle01_01_00_01_dasm(DASM_PARAMS); break; // BRNE (reg-reg) + case 0x02: size = arcompact_handle01_01_00_02_dasm(DASM_PARAMS); break; // BRLT (reg-reg) + case 0x03: size = arcompact_handle01_01_00_03_dasm(DASM_PARAMS); break; // BRGE (reg-reg) + case 0x04: size = arcompact_handle01_01_00_04_dasm(DASM_PARAMS); break; // BRLO (reg-reg) + case 0x05: size = arcompact_handle01_01_00_05_dasm(DASM_PARAMS); break; // BRHS (reg-reg) + case 0x06: size = arcompact_handle01_01_00_06_dasm(DASM_PARAMS); break; // reserved + case 0x07: size = arcompact_handle01_01_00_07_dasm(DASM_PARAMS); break; // reserved + case 0x08: size = arcompact_handle01_01_00_08_dasm(DASM_PARAMS); break; // reserved + case 0x09: size = arcompact_handle01_01_00_09_dasm(DASM_PARAMS); break; // reserved + case 0x0a: size = arcompact_handle01_01_00_0a_dasm(DASM_PARAMS); break; // reserved + case 0x0b: size = arcompact_handle01_01_00_0b_dasm(DASM_PARAMS); break; // reserved + case 0x0c: size = arcompact_handle01_01_00_0c_dasm(DASM_PARAMS); break; // reserved + case 0x0d: size = arcompact_handle01_01_00_0d_dasm(DASM_PARAMS); break; // reserved + case 0x0e: size = arcompact_handle01_01_00_0e_dasm(DASM_PARAMS); break; // BBIT0 (reg-reg) + case 0x0f: size = arcompact_handle01_01_00_0f_dasm(DASM_PARAMS); break; // BBIT1 (reg-reg) + } + + return size; +} + +int arcompact_handle01_01_01_dasm(DASM_OPS_32) // Branch on Compare/Bit Test Register-Immediate +{ + int size = 4; + UINT8 subinstr3 = (op & 0x0000000f) >> 0; + op &= ~0x0000000f; + + switch (subinstr3) + { + case 0x00: size = arcompact_handle01_01_01_00_dasm(DASM_PARAMS); break; // BREQ (reg-imm) + case 0x01: size = arcompact_handle01_01_01_01_dasm(DASM_PARAMS); break; // BRNE (reg-imm) + case 0x02: size = arcompact_handle01_01_01_02_dasm(DASM_PARAMS); break; // BRLT (reg-imm) + case 0x03: size = arcompact_handle01_01_01_03_dasm(DASM_PARAMS); break; // BRGE (reg-imm) + case 0x04: size = arcompact_handle01_01_01_04_dasm(DASM_PARAMS); break; // BRLO (reg-imm) + case 0x05: size = arcompact_handle01_01_01_05_dasm(DASM_PARAMS); break; // BRHS (reg-imm) + case 0x06: size = arcompact_handle01_01_01_06_dasm(DASM_PARAMS); break; // reserved + case 0x07: size = arcompact_handle01_01_01_07_dasm(DASM_PARAMS); break; // reserved + case 0x08: size = arcompact_handle01_01_01_08_dasm(DASM_PARAMS); break; // reserved + case 0x09: size = arcompact_handle01_01_01_09_dasm(DASM_PARAMS); break; // reserved + case 0x0a: size = arcompact_handle01_01_01_0a_dasm(DASM_PARAMS); break; // reserved + case 0x0b: size = arcompact_handle01_01_01_0b_dasm(DASM_PARAMS); break; // reserved + case 0x0c: size = arcompact_handle01_01_01_0c_dasm(DASM_PARAMS); break; // reserved + case 0x0d: size = arcompact_handle01_01_01_0d_dasm(DASM_PARAMS); break; // reserved + case 0x0e: size = arcompact_handle01_01_01_0e_dasm(DASM_PARAMS); break; // BBIT0 (reg-imm) + case 0x0f: size = arcompact_handle01_01_01_0f_dasm(DASM_PARAMS); break; // BBIT1 (reg-imm) + } + + return size; +} + +int arcompact_handle04_dasm(DASM_OPS_32) +{ + int size = 4; + // General Operations + + // bitpos + // 11111 111 11 111111 0 000 000000 0 00000 + // fedcb a98 76 543210 f edc ba9876 5 43210 + // + // 00100 bbb 00 iiiiii F BBB CCCCCC A AAAAA General Operations *UN*Conditional Register to Register + // 00100 bbb 01 iiiiii F BBB UUUUUU A AAAAA General Operations *UN*Conditional Register (Unsigned 6-bit IMM) + // 00100 bbb 10 iiiiii F BBB ssssss S SSSSS General Operations *UN*Conditional Register (Signed 12-bit IMM) + + // 00100 bbb 11 iiiiii F BBB CCCCCC 0 QQQQQ General Operations Conditional Register + // 00100 bbb 11 iiiiii F BBB UUUUUU 1 QQQQQ General Operations Conditional Register (Unsigned 6-bit IMM) + UINT8 subinstr = (op & 0x003f0000) >> 16; + op &= ~0x003f0000; + + switch (subinstr) + { + case 0x00: size = arcompact_handle04_00_dasm(DASM_PARAMS); break; // ADD + case 0x01: size = arcompact_handle04_01_dasm(DASM_PARAMS); break; // ADC + case 0x02: size = arcompact_handle04_02_dasm(DASM_PARAMS); break; // SUB + case 0x03: size = arcompact_handle04_03_dasm(DASM_PARAMS); break; // SBC + case 0x04: size = arcompact_handle04_04_dasm(DASM_PARAMS); break; // AND + case 0x05: size = arcompact_handle04_05_dasm(DASM_PARAMS); break; // OR + case 0x06: size = arcompact_handle04_06_dasm(DASM_PARAMS); break; // BIC + case 0x07: size = arcompact_handle04_07_dasm(DASM_PARAMS); break; // XOR + case 0x08: size = arcompact_handle04_08_dasm(DASM_PARAMS); break; // MAX + case 0x09: size = arcompact_handle04_09_dasm(DASM_PARAMS); break; // MIN + case 0x0a: size = arcompact_handle04_0a_dasm(DASM_PARAMS); break; // MOV + case 0x0b: size = arcompact_handle04_0b_dasm(DASM_PARAMS); break; // TST + case 0x0c: size = arcompact_handle04_0c_dasm(DASM_PARAMS); break; // CMP + case 0x0d: size = arcompact_handle04_0d_dasm(DASM_PARAMS); break; // RCMP + case 0x0e: size = arcompact_handle04_0e_dasm(DASM_PARAMS); break; // RSUB + case 0x0f: size = arcompact_handle04_0f_dasm(DASM_PARAMS); break; // BSET + case 0x10: size = arcompact_handle04_10_dasm(DASM_PARAMS); break; // BCLR + case 0x11: size = arcompact_handle04_11_dasm(DASM_PARAMS); break; // BTST + case 0x12: size = arcompact_handle04_12_dasm(DASM_PARAMS); break; // BXOR + case 0x13: size = arcompact_handle04_13_dasm(DASM_PARAMS); break; // BMSK + case 0x14: size = arcompact_handle04_14_dasm(DASM_PARAMS); break; // ADD1 + case 0x15: size = arcompact_handle04_15_dasm(DASM_PARAMS); break; // ADD2 + case 0x16: size = arcompact_handle04_16_dasm(DASM_PARAMS); break; // ADD3 + case 0x17: size = arcompact_handle04_17_dasm(DASM_PARAMS); break; // SUB1 + case 0x18: size = arcompact_handle04_18_dasm(DASM_PARAMS); break; // SUB2 + case 0x19: size = arcompact_handle04_19_dasm(DASM_PARAMS); break; // SUB3 + case 0x1a: size = arcompact_handle04_1a_dasm(DASM_PARAMS); break; // MPY * + case 0x1b: size = arcompact_handle04_1b_dasm(DASM_PARAMS); break; // MPYH * + case 0x1c: size = arcompact_handle04_1c_dasm(DASM_PARAMS); break; // MPYHU * + case 0x1d: size = arcompact_handle04_1d_dasm(DASM_PARAMS); break; // MPYU * + case 0x1e: size = arcompact_handle04_1e_dasm(DASM_PARAMS); break; // illegal + case 0x1f: size = arcompact_handle04_1f_dasm(DASM_PARAMS); break; // illegal + case 0x20: size = arcompact_handle04_20_dasm(DASM_PARAMS); break; // Jcc + case 0x21: size = arcompact_handle04_21_dasm(DASM_PARAMS); break; // Jcc.D + case 0x22: size = arcompact_handle04_22_dasm(DASM_PARAMS); break; // JLcc + case 0x23: size = arcompact_handle04_23_dasm(DASM_PARAMS); break; // JLcc.D + case 0x24: size = arcompact_handle04_24_dasm(DASM_PARAMS); break; // illegal + case 0x25: size = arcompact_handle04_25_dasm(DASM_PARAMS); break; // illegal + case 0x26: size = arcompact_handle04_26_dasm(DASM_PARAMS); break; // illegal + case 0x27: size = arcompact_handle04_27_dasm(DASM_PARAMS); break; // illegal + case 0x28: size = arcompact_handle04_28_dasm(DASM_PARAMS); break; // LPcc + case 0x29: size = arcompact_handle04_29_dasm(DASM_PARAMS); break; // FLAG + case 0x2a: size = arcompact_handle04_2a_dasm(DASM_PARAMS); break; // LR + case 0x2b: size = arcompact_handle04_2b_dasm(DASM_PARAMS); break; // SR + case 0x2c: size = arcompact_handle04_2c_dasm(DASM_PARAMS); break; // illegal + case 0x2d: size = arcompact_handle04_2d_dasm(DASM_PARAMS); break; // illegal + case 0x2e: size = arcompact_handle04_2e_dasm(DASM_PARAMS); break; // illegal + case 0x2f: size = arcompact_handle04_2f_dasm(DASM_PARAMS); break; // Sub Opcode + case 0x30: size = arcompact_handle04_30_dasm(DASM_PARAMS); break; // LD r-r + case 0x31: size = arcompact_handle04_31_dasm(DASM_PARAMS); break; // LD r-r + case 0x32: size = arcompact_handle04_32_dasm(DASM_PARAMS); break; // LD r-r + case 0x33: size = arcompact_handle04_33_dasm(DASM_PARAMS); break; // LD r-r + case 0x34: size = arcompact_handle04_34_dasm(DASM_PARAMS); break; // LD r-r + case 0x35: size = arcompact_handle04_35_dasm(DASM_PARAMS); break; // LD r-r + case 0x36: size = arcompact_handle04_36_dasm(DASM_PARAMS); break; // LD r-r + case 0x37: size = arcompact_handle04_37_dasm(DASM_PARAMS); break; // LD r-r + case 0x38: size = arcompact_handle04_38_dasm(DASM_PARAMS); break; // illegal + case 0x39: size = arcompact_handle04_39_dasm(DASM_PARAMS); break; // illegal + case 0x3a: size = arcompact_handle04_3a_dasm(DASM_PARAMS); break; // illegal + case 0x3b: size = arcompact_handle04_3b_dasm(DASM_PARAMS); break; // illegal + case 0x3c: size = arcompact_handle04_3c_dasm(DASM_PARAMS); break; // illegal + case 0x3d: size = arcompact_handle04_3d_dasm(DASM_PARAMS); break; // illegal + case 0x3e: size = arcompact_handle04_3e_dasm(DASM_PARAMS); break; // illegal + case 0x3f: size = arcompact_handle04_3f_dasm(DASM_PARAMS); break; // illegal + } + + return size; +} + +int arcompact_handle04_2f_dasm(DASM_OPS_32) +{ + int size = 4; + UINT8 subinstr2 = (op & 0x0000003f) >> 0; + op &= ~0x0000003f; + + switch (subinstr2) + { + case 0x00: size = arcompact_handle04_2f_00_dasm(DASM_PARAMS); break; // ASL + case 0x01: size = arcompact_handle04_2f_01_dasm(DASM_PARAMS); break; // ASR + case 0x02: size = arcompact_handle04_2f_02_dasm(DASM_PARAMS); break; // LSR + case 0x03: size = arcompact_handle04_2f_03_dasm(DASM_PARAMS); break; // ROR + case 0x04: size = arcompact_handle04_2f_04_dasm(DASM_PARAMS); break; // RCC + case 0x05: size = arcompact_handle04_2f_05_dasm(DASM_PARAMS); break; // SEXB + case 0x06: size = arcompact_handle04_2f_06_dasm(DASM_PARAMS); break; // SEXW + case 0x07: size = arcompact_handle04_2f_07_dasm(DASM_PARAMS); break; // EXTB + case 0x08: size = arcompact_handle04_2f_08_dasm(DASM_PARAMS); break; // EXTW + case 0x09: size = arcompact_handle04_2f_09_dasm(DASM_PARAMS); break; // ABS + case 0x0a: size = arcompact_handle04_2f_0a_dasm(DASM_PARAMS); break; // NOT + case 0x0b: size = arcompact_handle04_2f_0b_dasm(DASM_PARAMS); break; // RLC + case 0x0c: size = arcompact_handle04_2f_0c_dasm(DASM_PARAMS); break; // EX + case 0x0d: size = arcompact_handle04_2f_0d_dasm(DASM_PARAMS); break; // illegal + case 0x0e: size = arcompact_handle04_2f_0e_dasm(DASM_PARAMS); break; // illegal + case 0x0f: size = arcompact_handle04_2f_0f_dasm(DASM_PARAMS); break; // illegal + case 0x10: size = arcompact_handle04_2f_10_dasm(DASM_PARAMS); break; // illegal + case 0x11: size = arcompact_handle04_2f_11_dasm(DASM_PARAMS); break; // illegal + case 0x12: size = arcompact_handle04_2f_12_dasm(DASM_PARAMS); break; // illegal + case 0x13: size = arcompact_handle04_2f_13_dasm(DASM_PARAMS); break; // illegal + case 0x14: size = arcompact_handle04_2f_14_dasm(DASM_PARAMS); break; // illegal + case 0x15: size = arcompact_handle04_2f_15_dasm(DASM_PARAMS); break; // illegal + case 0x16: size = arcompact_handle04_2f_16_dasm(DASM_PARAMS); break; // illegal + case 0x17: size = arcompact_handle04_2f_17_dasm(DASM_PARAMS); break; // illegal + case 0x18: size = arcompact_handle04_2f_18_dasm(DASM_PARAMS); break; // illegal + case 0x19: size = arcompact_handle04_2f_19_dasm(DASM_PARAMS); break; // illegal + case 0x1a: size = arcompact_handle04_2f_1a_dasm(DASM_PARAMS); break; // illegal + case 0x1b: size = arcompact_handle04_2f_1b_dasm(DASM_PARAMS); break; // illegal + case 0x1c: size = arcompact_handle04_2f_1c_dasm(DASM_PARAMS); break; // illegal + case 0x1d: size = arcompact_handle04_2f_1d_dasm(DASM_PARAMS); break; // illegal + case 0x1e: size = arcompact_handle04_2f_1e_dasm(DASM_PARAMS); break; // illegal + case 0x1f: size = arcompact_handle04_2f_1f_dasm(DASM_PARAMS); break; // illegal + case 0x20: size = arcompact_handle04_2f_20_dasm(DASM_PARAMS); break; // illegal + case 0x21: size = arcompact_handle04_2f_21_dasm(DASM_PARAMS); break; // illegal + case 0x22: size = arcompact_handle04_2f_22_dasm(DASM_PARAMS); break; // illegal + case 0x23: size = arcompact_handle04_2f_23_dasm(DASM_PARAMS); break; // illegal + case 0x24: size = arcompact_handle04_2f_24_dasm(DASM_PARAMS); break; // illegal + case 0x25: size = arcompact_handle04_2f_25_dasm(DASM_PARAMS); break; // illegal + case 0x26: size = arcompact_handle04_2f_26_dasm(DASM_PARAMS); break; // illegal + case 0x27: size = arcompact_handle04_2f_27_dasm(DASM_PARAMS); break; // illegal + case 0x28: size = arcompact_handle04_2f_28_dasm(DASM_PARAMS); break; // illegal + case 0x29: size = arcompact_handle04_2f_29_dasm(DASM_PARAMS); break; // illegal + case 0x2a: size = arcompact_handle04_2f_2a_dasm(DASM_PARAMS); break; // illegal + case 0x2b: size = arcompact_handle04_2f_2b_dasm(DASM_PARAMS); break; // illegal + case 0x2c: size = arcompact_handle04_2f_2c_dasm(DASM_PARAMS); break; // illegal + case 0x2d: size = arcompact_handle04_2f_2d_dasm(DASM_PARAMS); break; // illegal + case 0x2e: size = arcompact_handle04_2f_2e_dasm(DASM_PARAMS); break; // illegal + case 0x2f: size = arcompact_handle04_2f_2f_dasm(DASM_PARAMS); break; // illegal + case 0x30: size = arcompact_handle04_2f_30_dasm(DASM_PARAMS); break; // illegal + case 0x31: size = arcompact_handle04_2f_31_dasm(DASM_PARAMS); break; // illegal + case 0x32: size = arcompact_handle04_2f_32_dasm(DASM_PARAMS); break; // illegal + case 0x33: size = arcompact_handle04_2f_33_dasm(DASM_PARAMS); break; // illegal + case 0x34: size = arcompact_handle04_2f_34_dasm(DASM_PARAMS); break; // illegal + case 0x35: size = arcompact_handle04_2f_35_dasm(DASM_PARAMS); break; // illegal + case 0x36: size = arcompact_handle04_2f_36_dasm(DASM_PARAMS); break; // illegal + case 0x37: size = arcompact_handle04_2f_37_dasm(DASM_PARAMS); break; // illegal + case 0x38: size = arcompact_handle04_2f_38_dasm(DASM_PARAMS); break; // illegal + case 0x39: size = arcompact_handle04_2f_39_dasm(DASM_PARAMS); break; // illegal + case 0x3a: size = arcompact_handle04_2f_3a_dasm(DASM_PARAMS); break; // illegal + case 0x3b: size = arcompact_handle04_2f_3b_dasm(DASM_PARAMS); break; // illegal + case 0x3c: size = arcompact_handle04_2f_3c_dasm(DASM_PARAMS); break; // illegal + case 0x3d: size = arcompact_handle04_2f_3d_dasm(DASM_PARAMS); break; // illegal + case 0x3e: size = arcompact_handle04_2f_3e_dasm(DASM_PARAMS); break; // illegal + case 0x3f: size = arcompact_handle04_2f_3f_dasm(DASM_PARAMS); break; // ZOPs (Zero Operand Opcodes) + } + + return size; +} + + +int arcompact_handle05_2f_dasm(DASM_OPS_32) +{ + int size = 4; + UINT8 subinstr2 = (op & 0x0000003f) >> 0; + op &= ~0x0000003f; + + switch (subinstr2) + { + case 0x00: size = arcompact_handle05_2f_00_dasm(DASM_PARAMS); break; // SWAP + case 0x01: size = arcompact_handle05_2f_01_dasm(DASM_PARAMS); break; // NORM + case 0x02: size = arcompact_handle05_2f_02_dasm(DASM_PARAMS); break; // SAT16 + case 0x03: size = arcompact_handle05_2f_03_dasm(DASM_PARAMS); break; // RND16 + case 0x04: size = arcompact_handle05_2f_04_dasm(DASM_PARAMS); break; // ABSSW + case 0x05: size = arcompact_handle05_2f_05_dasm(DASM_PARAMS); break; // ABSS + case 0x06: size = arcompact_handle05_2f_06_dasm(DASM_PARAMS); break; // NEGSW + case 0x07: size = arcompact_handle05_2f_07_dasm(DASM_PARAMS); break; // NEGS + case 0x08: size = arcompact_handle05_2f_08_dasm(DASM_PARAMS); break; // NORMW + case 0x09: size = arcompact_handle05_2f_09_dasm(DASM_PARAMS); break; // illegal + case 0x0a: size = arcompact_handle05_2f_0a_dasm(DASM_PARAMS); break; // illegal + case 0x0b: size = arcompact_handle05_2f_0b_dasm(DASM_PARAMS); break; // illegal + case 0x0c: size = arcompact_handle05_2f_0c_dasm(DASM_PARAMS); break; // illegal + case 0x0d: size = arcompact_handle05_2f_0d_dasm(DASM_PARAMS); break; // illegal + case 0x0e: size = arcompact_handle05_2f_0e_dasm(DASM_PARAMS); break; // illegal + case 0x0f: size = arcompact_handle05_2f_0f_dasm(DASM_PARAMS); break; // illegal + case 0x10: size = arcompact_handle05_2f_10_dasm(DASM_PARAMS); break; // illegal + case 0x11: size = arcompact_handle05_2f_11_dasm(DASM_PARAMS); break; // illegal + case 0x12: size = arcompact_handle05_2f_12_dasm(DASM_PARAMS); break; // illegal + case 0x13: size = arcompact_handle05_2f_13_dasm(DASM_PARAMS); break; // illegal + case 0x14: size = arcompact_handle05_2f_14_dasm(DASM_PARAMS); break; // illegal + case 0x15: size = arcompact_handle05_2f_15_dasm(DASM_PARAMS); break; // illegal + case 0x16: size = arcompact_handle05_2f_16_dasm(DASM_PARAMS); break; // illegal + case 0x17: size = arcompact_handle05_2f_17_dasm(DASM_PARAMS); break; // illegal + case 0x18: size = arcompact_handle05_2f_18_dasm(DASM_PARAMS); break; // illegal + case 0x19: size = arcompact_handle05_2f_19_dasm(DASM_PARAMS); break; // illegal + case 0x1a: size = arcompact_handle05_2f_1a_dasm(DASM_PARAMS); break; // illegal + case 0x1b: size = arcompact_handle05_2f_1b_dasm(DASM_PARAMS); break; // illegal + case 0x1c: size = arcompact_handle05_2f_1c_dasm(DASM_PARAMS); break; // illegal + case 0x1d: size = arcompact_handle05_2f_1d_dasm(DASM_PARAMS); break; // illegal + case 0x1e: size = arcompact_handle05_2f_1e_dasm(DASM_PARAMS); break; // illegal + case 0x1f: size = arcompact_handle05_2f_1f_dasm(DASM_PARAMS); break; // illegal + case 0x20: size = arcompact_handle05_2f_20_dasm(DASM_PARAMS); break; // illegal + case 0x21: size = arcompact_handle05_2f_21_dasm(DASM_PARAMS); break; // illegal + case 0x22: size = arcompact_handle05_2f_22_dasm(DASM_PARAMS); break; // illegal + case 0x23: size = arcompact_handle05_2f_23_dasm(DASM_PARAMS); break; // illegal + case 0x24: size = arcompact_handle05_2f_24_dasm(DASM_PARAMS); break; // illegal + case 0x25: size = arcompact_handle05_2f_25_dasm(DASM_PARAMS); break; // illegal + case 0x26: size = arcompact_handle05_2f_26_dasm(DASM_PARAMS); break; // illegal + case 0x27: size = arcompact_handle05_2f_27_dasm(DASM_PARAMS); break; // illegal + case 0x28: size = arcompact_handle05_2f_28_dasm(DASM_PARAMS); break; // illegal + case 0x29: size = arcompact_handle05_2f_29_dasm(DASM_PARAMS); break; // illegal + case 0x2a: size = arcompact_handle05_2f_2a_dasm(DASM_PARAMS); break; // illegal + case 0x2b: size = arcompact_handle05_2f_2b_dasm(DASM_PARAMS); break; // illegal + case 0x2c: size = arcompact_handle05_2f_2c_dasm(DASM_PARAMS); break; // illegal + case 0x2d: size = arcompact_handle05_2f_2d_dasm(DASM_PARAMS); break; // illegal + case 0x2e: size = arcompact_handle05_2f_2e_dasm(DASM_PARAMS); break; // illegal + case 0x2f: size = arcompact_handle05_2f_2f_dasm(DASM_PARAMS); break; // illegal + case 0x30: size = arcompact_handle05_2f_30_dasm(DASM_PARAMS); break; // illegal + case 0x31: size = arcompact_handle05_2f_31_dasm(DASM_PARAMS); break; // illegal + case 0x32: size = arcompact_handle05_2f_32_dasm(DASM_PARAMS); break; // illegal + case 0x33: size = arcompact_handle05_2f_33_dasm(DASM_PARAMS); break; // illegal + case 0x34: size = arcompact_handle05_2f_34_dasm(DASM_PARAMS); break; // illegal + case 0x35: size = arcompact_handle05_2f_35_dasm(DASM_PARAMS); break; // illegal + case 0x36: size = arcompact_handle05_2f_36_dasm(DASM_PARAMS); break; // illegal + case 0x37: size = arcompact_handle05_2f_37_dasm(DASM_PARAMS); break; // illegal + case 0x38: size = arcompact_handle05_2f_38_dasm(DASM_PARAMS); break; // illegal + case 0x39: size = arcompact_handle05_2f_39_dasm(DASM_PARAMS); break; // illegal + case 0x3a: size = arcompact_handle05_2f_3a_dasm(DASM_PARAMS); break; // illegal + case 0x3b: size = arcompact_handle05_2f_3b_dasm(DASM_PARAMS); break; // illegal + case 0x3c: size = arcompact_handle05_2f_3c_dasm(DASM_PARAMS); break; // illegal + case 0x3d: size = arcompact_handle05_2f_3d_dasm(DASM_PARAMS); break; // illegal + case 0x3e: size = arcompact_handle05_2f_3e_dasm(DASM_PARAMS); break; // illegal + case 0x3f: size = arcompact_handle05_2f_3f_dasm(DASM_PARAMS); break; // ZOPs (Zero Operand Opcodes) + } + + return size; +} + +int arcompact_handle04_2f_3f_dasm(DASM_OPS_32) +{ + int size = 4; + UINT8 subinstr3 = (op & 0x07000000) >> 24; + subinstr3 |= ((op & 0x00007000) >> 12) << 3; + + op &= ~0x07007000; + + switch (subinstr3) + { + case 0x00: size = arcompact_handle04_2f_3f_00_dasm(DASM_PARAMS); break; // illegal + case 0x01: size = arcompact_handle04_2f_3f_01_dasm(DASM_PARAMS); break; // SLEEP + case 0x02: size = arcompact_handle04_2f_3f_02_dasm(DASM_PARAMS); break; // SWI / TRAP9 + case 0x03: size = arcompact_handle04_2f_3f_03_dasm(DASM_PARAMS); break; // SYNC + case 0x04: size = arcompact_handle04_2f_3f_04_dasm(DASM_PARAMS); break; // RTIE + case 0x05: size = arcompact_handle04_2f_3f_05_dasm(DASM_PARAMS); break; // BRK + case 0x06: size = arcompact_handle04_2f_3f_06_dasm(DASM_PARAMS); break; // illegal + case 0x07: size = arcompact_handle04_2f_3f_07_dasm(DASM_PARAMS); break; // illegal + case 0x08: size = arcompact_handle04_2f_3f_08_dasm(DASM_PARAMS); break; // illegal + case 0x09: size = arcompact_handle04_2f_3f_09_dasm(DASM_PARAMS); break; // illegal + case 0x0a: size = arcompact_handle04_2f_3f_0a_dasm(DASM_PARAMS); break; // illegal + case 0x0b: size = arcompact_handle04_2f_3f_0b_dasm(DASM_PARAMS); break; // illegal + case 0x0c: size = arcompact_handle04_2f_3f_0c_dasm(DASM_PARAMS); break; // illegal + case 0x0d: size = arcompact_handle04_2f_3f_0d_dasm(DASM_PARAMS); break; // illegal + case 0x0e: size = arcompact_handle04_2f_3f_0e_dasm(DASM_PARAMS); break; // illegal + case 0x0f: size = arcompact_handle04_2f_3f_0f_dasm(DASM_PARAMS); break; // illegal + case 0x10: size = arcompact_handle04_2f_3f_10_dasm(DASM_PARAMS); break; // illegal + case 0x11: size = arcompact_handle04_2f_3f_11_dasm(DASM_PARAMS); break; // illegal + case 0x12: size = arcompact_handle04_2f_3f_12_dasm(DASM_PARAMS); break; // illegal + case 0x13: size = arcompact_handle04_2f_3f_13_dasm(DASM_PARAMS); break; // illegal + case 0x14: size = arcompact_handle04_2f_3f_14_dasm(DASM_PARAMS); break; // illegal + case 0x15: size = arcompact_handle04_2f_3f_15_dasm(DASM_PARAMS); break; // illegal + case 0x16: size = arcompact_handle04_2f_3f_16_dasm(DASM_PARAMS); break; // illegal + case 0x17: size = arcompact_handle04_2f_3f_17_dasm(DASM_PARAMS); break; // illegal + case 0x18: size = arcompact_handle04_2f_3f_18_dasm(DASM_PARAMS); break; // illegal + case 0x19: size = arcompact_handle04_2f_3f_19_dasm(DASM_PARAMS); break; // illegal + case 0x1a: size = arcompact_handle04_2f_3f_1a_dasm(DASM_PARAMS); break; // illegal + case 0x1b: size = arcompact_handle04_2f_3f_1b_dasm(DASM_PARAMS); break; // illegal + case 0x1c: size = arcompact_handle04_2f_3f_1c_dasm(DASM_PARAMS); break; // illegal + case 0x1d: size = arcompact_handle04_2f_3f_1d_dasm(DASM_PARAMS); break; // illegal + case 0x1e: size = arcompact_handle04_2f_3f_1e_dasm(DASM_PARAMS); break; // illegal + case 0x1f: size = arcompact_handle04_2f_3f_1f_dasm(DASM_PARAMS); break; // illegal + case 0x20: size = arcompact_handle04_2f_3f_20_dasm(DASM_PARAMS); break; // illegal + case 0x21: size = arcompact_handle04_2f_3f_21_dasm(DASM_PARAMS); break; // illegal + case 0x22: size = arcompact_handle04_2f_3f_22_dasm(DASM_PARAMS); break; // illegal + case 0x23: size = arcompact_handle04_2f_3f_23_dasm(DASM_PARAMS); break; // illegal + case 0x24: size = arcompact_handle04_2f_3f_24_dasm(DASM_PARAMS); break; // illegal + case 0x25: size = arcompact_handle04_2f_3f_25_dasm(DASM_PARAMS); break; // illegal + case 0x26: size = arcompact_handle04_2f_3f_26_dasm(DASM_PARAMS); break; // illegal + case 0x27: size = arcompact_handle04_2f_3f_27_dasm(DASM_PARAMS); break; // illegal + case 0x28: size = arcompact_handle04_2f_3f_28_dasm(DASM_PARAMS); break; // illegal + case 0x29: size = arcompact_handle04_2f_3f_29_dasm(DASM_PARAMS); break; // illegal + case 0x2a: size = arcompact_handle04_2f_3f_2a_dasm(DASM_PARAMS); break; // illegal + case 0x2b: size = arcompact_handle04_2f_3f_2b_dasm(DASM_PARAMS); break; // illegal + case 0x2c: size = arcompact_handle04_2f_3f_2c_dasm(DASM_PARAMS); break; // illegal + case 0x2d: size = arcompact_handle04_2f_3f_2d_dasm(DASM_PARAMS); break; // illegal + case 0x2e: size = arcompact_handle04_2f_3f_2e_dasm(DASM_PARAMS); break; // illegal + case 0x2f: size = arcompact_handle04_2f_3f_2f_dasm(DASM_PARAMS); break; // illegal + case 0x30: size = arcompact_handle04_2f_3f_30_dasm(DASM_PARAMS); break; // illegal + case 0x31: size = arcompact_handle04_2f_3f_31_dasm(DASM_PARAMS); break; // illegal + case 0x32: size = arcompact_handle04_2f_3f_32_dasm(DASM_PARAMS); break; // illegal + case 0x33: size = arcompact_handle04_2f_3f_33_dasm(DASM_PARAMS); break; // illegal + case 0x34: size = arcompact_handle04_2f_3f_34_dasm(DASM_PARAMS); break; // illegal + case 0x35: size = arcompact_handle04_2f_3f_35_dasm(DASM_PARAMS); break; // illegal + case 0x36: size = arcompact_handle04_2f_3f_36_dasm(DASM_PARAMS); break; // illegal + case 0x37: size = arcompact_handle04_2f_3f_37_dasm(DASM_PARAMS); break; // illegal + case 0x38: size = arcompact_handle04_2f_3f_38_dasm(DASM_PARAMS); break; // illegal + case 0x39: size = arcompact_handle04_2f_3f_39_dasm(DASM_PARAMS); break; // illegal + case 0x3a: size = arcompact_handle04_2f_3f_3a_dasm(DASM_PARAMS); break; // illegal + case 0x3b: size = arcompact_handle04_2f_3f_3b_dasm(DASM_PARAMS); break; // illegal + case 0x3c: size = arcompact_handle04_2f_3f_3c_dasm(DASM_PARAMS); break; // illegal + case 0x3d: size = arcompact_handle04_2f_3f_3d_dasm(DASM_PARAMS); break; // illegal + case 0x3e: size = arcompact_handle04_2f_3f_3e_dasm(DASM_PARAMS); break; // illegal + case 0x3f: size = arcompact_handle04_2f_3f_3f_dasm(DASM_PARAMS); break; // illegal + } + + return size; +} + + +int arcompact_handle05_2f_3f_dasm(DASM_OPS_32) // useless ZOP group, no actual opcodes +{ + int size = 4; + UINT8 subinstr3 = (op & 0x07000000) >> 24; + subinstr3 |= ((op & 0x00007000) >> 12) << 3; + + op &= ~0x07007000; + + switch (subinstr3) + { + case 0x00: size = arcompact_handle05_2f_3f_00_dasm(DASM_PARAMS); break; // illegal + case 0x01: size = arcompact_handle05_2f_3f_01_dasm(DASM_PARAMS); break; // illegal + case 0x02: size = arcompact_handle05_2f_3f_02_dasm(DASM_PARAMS); break; // illegal + case 0x03: size = arcompact_handle05_2f_3f_03_dasm(DASM_PARAMS); break; // illegal + case 0x04: size = arcompact_handle05_2f_3f_04_dasm(DASM_PARAMS); break; // illegal + case 0x05: size = arcompact_handle05_2f_3f_05_dasm(DASM_PARAMS); break; // illegal + case 0x06: size = arcompact_handle05_2f_3f_06_dasm(DASM_PARAMS); break; // illegal + case 0x07: size = arcompact_handle05_2f_3f_07_dasm(DASM_PARAMS); break; // illegal + case 0x08: size = arcompact_handle05_2f_3f_08_dasm(DASM_PARAMS); break; // illegal + case 0x09: size = arcompact_handle05_2f_3f_09_dasm(DASM_PARAMS); break; // illegal + case 0x0a: size = arcompact_handle05_2f_3f_0a_dasm(DASM_PARAMS); break; // illegal + case 0x0b: size = arcompact_handle05_2f_3f_0b_dasm(DASM_PARAMS); break; // illegal + case 0x0c: size = arcompact_handle05_2f_3f_0c_dasm(DASM_PARAMS); break; // illegal + case 0x0d: size = arcompact_handle05_2f_3f_0d_dasm(DASM_PARAMS); break; // illegal + case 0x0e: size = arcompact_handle05_2f_3f_0e_dasm(DASM_PARAMS); break; // illegal + case 0x0f: size = arcompact_handle05_2f_3f_0f_dasm(DASM_PARAMS); break; // illegal + case 0x10: size = arcompact_handle05_2f_3f_10_dasm(DASM_PARAMS); break; // illegal + case 0x11: size = arcompact_handle05_2f_3f_11_dasm(DASM_PARAMS); break; // illegal + case 0x12: size = arcompact_handle05_2f_3f_12_dasm(DASM_PARAMS); break; // illegal + case 0x13: size = arcompact_handle05_2f_3f_13_dasm(DASM_PARAMS); break; // illegal + case 0x14: size = arcompact_handle05_2f_3f_14_dasm(DASM_PARAMS); break; // illegal + case 0x15: size = arcompact_handle05_2f_3f_15_dasm(DASM_PARAMS); break; // illegal + case 0x16: size = arcompact_handle05_2f_3f_16_dasm(DASM_PARAMS); break; // illegal + case 0x17: size = arcompact_handle05_2f_3f_17_dasm(DASM_PARAMS); break; // illegal + case 0x18: size = arcompact_handle05_2f_3f_18_dasm(DASM_PARAMS); break; // illegal + case 0x19: size = arcompact_handle05_2f_3f_19_dasm(DASM_PARAMS); break; // illegal + case 0x1a: size = arcompact_handle05_2f_3f_1a_dasm(DASM_PARAMS); break; // illegal + case 0x1b: size = arcompact_handle05_2f_3f_1b_dasm(DASM_PARAMS); break; // illegal + case 0x1c: size = arcompact_handle05_2f_3f_1c_dasm(DASM_PARAMS); break; // illegal + case 0x1d: size = arcompact_handle05_2f_3f_1d_dasm(DASM_PARAMS); break; // illegal + case 0x1e: size = arcompact_handle05_2f_3f_1e_dasm(DASM_PARAMS); break; // illegal + case 0x1f: size = arcompact_handle05_2f_3f_1f_dasm(DASM_PARAMS); break; // illegal + case 0x20: size = arcompact_handle05_2f_3f_20_dasm(DASM_PARAMS); break; // illegal + case 0x21: size = arcompact_handle05_2f_3f_21_dasm(DASM_PARAMS); break; // illegal + case 0x22: size = arcompact_handle05_2f_3f_22_dasm(DASM_PARAMS); break; // illegal + case 0x23: size = arcompact_handle05_2f_3f_23_dasm(DASM_PARAMS); break; // illegal + case 0x24: size = arcompact_handle05_2f_3f_24_dasm(DASM_PARAMS); break; // illegal + case 0x25: size = arcompact_handle05_2f_3f_25_dasm(DASM_PARAMS); break; // illegal + case 0x26: size = arcompact_handle05_2f_3f_26_dasm(DASM_PARAMS); break; // illegal + case 0x27: size = arcompact_handle05_2f_3f_27_dasm(DASM_PARAMS); break; // illegal + case 0x28: size = arcompact_handle05_2f_3f_28_dasm(DASM_PARAMS); break; // illegal + case 0x29: size = arcompact_handle05_2f_3f_29_dasm(DASM_PARAMS); break; // illegal + case 0x2a: size = arcompact_handle05_2f_3f_2a_dasm(DASM_PARAMS); break; // illegal + case 0x2b: size = arcompact_handle05_2f_3f_2b_dasm(DASM_PARAMS); break; // illegal + case 0x2c: size = arcompact_handle05_2f_3f_2c_dasm(DASM_PARAMS); break; // illegal + case 0x2d: size = arcompact_handle05_2f_3f_2d_dasm(DASM_PARAMS); break; // illegal + case 0x2e: size = arcompact_handle05_2f_3f_2e_dasm(DASM_PARAMS); break; // illegal + case 0x2f: size = arcompact_handle05_2f_3f_2f_dasm(DASM_PARAMS); break; // illegal + case 0x30: size = arcompact_handle05_2f_3f_30_dasm(DASM_PARAMS); break; // illegal + case 0x31: size = arcompact_handle05_2f_3f_31_dasm(DASM_PARAMS); break; // illegal + case 0x32: size = arcompact_handle05_2f_3f_32_dasm(DASM_PARAMS); break; // illegal + case 0x33: size = arcompact_handle05_2f_3f_33_dasm(DASM_PARAMS); break; // illegal + case 0x34: size = arcompact_handle05_2f_3f_34_dasm(DASM_PARAMS); break; // illegal + case 0x35: size = arcompact_handle05_2f_3f_35_dasm(DASM_PARAMS); break; // illegal + case 0x36: size = arcompact_handle05_2f_3f_36_dasm(DASM_PARAMS); break; // illegal + case 0x37: size = arcompact_handle05_2f_3f_37_dasm(DASM_PARAMS); break; // illegal + case 0x38: size = arcompact_handle05_2f_3f_38_dasm(DASM_PARAMS); break; // illegal + case 0x39: size = arcompact_handle05_2f_3f_39_dasm(DASM_PARAMS); break; // illegal + case 0x3a: size = arcompact_handle05_2f_3f_3a_dasm(DASM_PARAMS); break; // illegal + case 0x3b: size = arcompact_handle05_2f_3f_3b_dasm(DASM_PARAMS); break; // illegal + case 0x3c: size = arcompact_handle05_2f_3f_3c_dasm(DASM_PARAMS); break; // illegal + case 0x3d: size = arcompact_handle05_2f_3f_3d_dasm(DASM_PARAMS); break; // illegal + case 0x3e: size = arcompact_handle05_2f_3f_3e_dasm(DASM_PARAMS); break; // illegal + case 0x3f: size = arcompact_handle05_2f_3f_3f_dasm(DASM_PARAMS); break; // illegal + } + + return size; +} + + +// this is an Extension ALU group, maybe optional on some CPUs? +int arcompact_handle05_dasm(DASM_OPS_32) +{ + int size = 4; + UINT8 subinstr = (op & 0x003f0000) >> 16; + op &= ~0x003f0000; + + switch (subinstr) + { + case 0x00: size = arcompact_handle05_00_dasm(DASM_PARAMS); break; // ASL + case 0x01: size = arcompact_handle05_01_dasm(DASM_PARAMS); break; // LSR + case 0x02: size = arcompact_handle05_02_dasm(DASM_PARAMS); break; // ASR + case 0x03: size = arcompact_handle05_03_dasm(DASM_PARAMS); break; // ROR + case 0x04: size = arcompact_handle05_04_dasm(DASM_PARAMS); break; // MUL64 + case 0x05: size = arcompact_handle05_05_dasm(DASM_PARAMS); break; // MULU64 + case 0x06: size = arcompact_handle05_06_dasm(DASM_PARAMS); break; // ADDS + case 0x07: size = arcompact_handle05_07_dasm(DASM_PARAMS); break; // SUBS + case 0x08: size = arcompact_handle05_08_dasm(DASM_PARAMS); break; // DIVAW + case 0x09: size = arcompact_handle05_09_dasm(DASM_PARAMS); break; // illegal + case 0x0a: size = arcompact_handle05_0a_dasm(DASM_PARAMS); break; // ASLS + case 0x0b: size = arcompact_handle05_0b_dasm(DASM_PARAMS); break; // ASRS + case 0x0c: size = arcompact_handle05_0c_dasm(DASM_PARAMS); break; // illegal + case 0x0d: size = arcompact_handle05_0d_dasm(DASM_PARAMS); break; // illegal + case 0x0e: size = arcompact_handle05_0e_dasm(DASM_PARAMS); break; // illegal + case 0x0f: size = arcompact_handle05_0f_dasm(DASM_PARAMS); break; // illegal + case 0x10: size = arcompact_handle05_10_dasm(DASM_PARAMS); break; // illegal + case 0x11: size = arcompact_handle05_11_dasm(DASM_PARAMS); break; // illegal + case 0x12: size = arcompact_handle05_12_dasm(DASM_PARAMS); break; // illegal + case 0x13: size = arcompact_handle05_13_dasm(DASM_PARAMS); break; // illegal + case 0x14: size = arcompact_handle05_14_dasm(DASM_PARAMS); break; // illegal + case 0x15: size = arcompact_handle05_15_dasm(DASM_PARAMS); break; // illegal + case 0x16: size = arcompact_handle05_16_dasm(DASM_PARAMS); break; // illegal + case 0x17: size = arcompact_handle05_17_dasm(DASM_PARAMS); break; // illegal + case 0x18: size = arcompact_handle05_18_dasm(DASM_PARAMS); break; // illegal + case 0x19: size = arcompact_handle05_19_dasm(DASM_PARAMS); break; // illegal + case 0x1a: size = arcompact_handle05_1a_dasm(DASM_PARAMS); break; // illegal + case 0x1b: size = arcompact_handle05_1b_dasm(DASM_PARAMS); break; // illegal + case 0x1c: size = arcompact_handle05_1c_dasm(DASM_PARAMS); break; // illegal + case 0x1d: size = arcompact_handle05_1d_dasm(DASM_PARAMS); break; // illegal + case 0x1e: size = arcompact_handle05_1e_dasm(DASM_PARAMS); break; // illegal + case 0x1f: size = arcompact_handle05_1f_dasm(DASM_PARAMS); break; // illegal + case 0x20: size = arcompact_handle05_20_dasm(DASM_PARAMS); break; // illegal + case 0x21: size = arcompact_handle05_21_dasm(DASM_PARAMS); break; // illegal + case 0x22: size = arcompact_handle05_22_dasm(DASM_PARAMS); break; // illegal + case 0x23: size = arcompact_handle05_23_dasm(DASM_PARAMS); break; // illegal + case 0x24: size = arcompact_handle05_24_dasm(DASM_PARAMS); break; // illegal + case 0x25: size = arcompact_handle05_25_dasm(DASM_PARAMS); break; // illegal + case 0x26: size = arcompact_handle05_26_dasm(DASM_PARAMS); break; // illegal + case 0x27: size = arcompact_handle05_27_dasm(DASM_PARAMS); break; // illegal + case 0x28: size = arcompact_handle05_28_dasm(DASM_PARAMS); break; // ADDSDW + case 0x29: size = arcompact_handle05_29_dasm(DASM_PARAMS); break; // SUBSDW + case 0x2a: size = arcompact_handle05_2a_dasm(DASM_PARAMS); break; // illegal + case 0x2b: size = arcompact_handle05_2b_dasm(DASM_PARAMS); break; // illegal + case 0x2c: size = arcompact_handle05_2c_dasm(DASM_PARAMS); break; // illegal + case 0x2d: size = arcompact_handle05_2d_dasm(DASM_PARAMS); break; // illegal + case 0x2e: size = arcompact_handle05_2e_dasm(DASM_PARAMS); break; // illegal + case 0x2f: size = arcompact_handle05_2f_dasm(DASM_PARAMS); break; // SOPs + case 0x30: size = arcompact_handle05_30_dasm(DASM_PARAMS); break; // illegal + case 0x31: size = arcompact_handle05_31_dasm(DASM_PARAMS); break; // illegal + case 0x32: size = arcompact_handle05_32_dasm(DASM_PARAMS); break; // illegal + case 0x33: size = arcompact_handle05_33_dasm(DASM_PARAMS); break; // illegal + case 0x34: size = arcompact_handle05_34_dasm(DASM_PARAMS); break; // illegal + case 0x35: size = arcompact_handle05_35_dasm(DASM_PARAMS); break; // illegal + case 0x36: size = arcompact_handle05_36_dasm(DASM_PARAMS); break; // illegal + case 0x37: size = arcompact_handle05_37_dasm(DASM_PARAMS); break; // illegal + case 0x38: size = arcompact_handle05_38_dasm(DASM_PARAMS); break; // illegal + case 0x39: size = arcompact_handle05_39_dasm(DASM_PARAMS); break; // illegal + case 0x3a: size = arcompact_handle05_3a_dasm(DASM_PARAMS); break; // illegal + case 0x3b: size = arcompact_handle05_3b_dasm(DASM_PARAMS); break; // illegal + case 0x3c: size = arcompact_handle05_3c_dasm(DASM_PARAMS); break; // illegal + case 0x3d: size = arcompact_handle05_3d_dasm(DASM_PARAMS); break; // illegal + case 0x3e: size = arcompact_handle05_3e_dasm(DASM_PARAMS); break; // illegal + case 0x3f: size = arcompact_handle05_3f_dasm(DASM_PARAMS); break; // illegal + } + + return size; +} + +int arcompact_handle0c_dasm(DASM_OPS_16) +{ + int size = 2; + UINT8 subinstr = (op & 0x0018) >> 3; + op &= ~0x0018; + + switch (subinstr) + { + case 0x00: size = arcompact_handle0c_00_dasm(DASM_PARAMS); break; // LD_S + case 0x01: size = arcompact_handle0c_01_dasm(DASM_PARAMS); break; // LDB_S + case 0x02: size = arcompact_handle0c_02_dasm(DASM_PARAMS); break; // LDW_S + case 0x03: size = arcompact_handle0c_03_dasm(DASM_PARAMS); break; // ADD_S + } + return size; +} + +int arcompact_handle0d_dasm(DASM_OPS_16) +{ + int size = 2; + UINT8 subinstr = (op & 0x0018) >> 3; + op &= ~0x0018; + + switch (subinstr) + { + case 0x00: size = arcompact_handle0d_00_dasm(DASM_PARAMS); break; // ADD_S + case 0x01: size = arcompact_handle0d_01_dasm(DASM_PARAMS); break; // SUB_S + case 0x02: size = arcompact_handle0d_02_dasm(DASM_PARAMS); break; // ASL_S + case 0x03: size = arcompact_handle0d_03_dasm(DASM_PARAMS); break; // ASR_S + } + return size; +} + +int arcompact_handle0e_dasm(DASM_OPS_16) +{ + int size = 2; + UINT8 subinstr = (op & 0x0018) >> 3; + op &= ~0x0018; + + switch (subinstr) + { + case 0x00: size = arcompact_handle0e_00_dasm(DASM_PARAMS); break; // ADD_S + case 0x01: size = arcompact_handle0e_01_dasm(DASM_PARAMS); break; // MOV_S + case 0x02: size = arcompact_handle0e_02_dasm(DASM_PARAMS); break; // CMP_S + case 0x03: size = arcompact_handle0e_03_dasm(DASM_PARAMS); break; // MOV_S + } + return size; +} + +int arcompact_handle0f_dasm(DASM_OPS_16) +{ + int size = 2; + // General Register Instructions (16-bit) + // 0111 1bbb ccci iiii + UINT8 subinstr = (op & 0x01f) >> 0; + op &= ~0x001f; + + switch (subinstr) + { + case 0x00: size = arcompact_handle0f_00_dasm(DASM_PARAMS); break; // SOPs + case 0x01: size = arcompact_handle0f_01_dasm(DASM_PARAMS); break; // 0x01 + case 0x02: size = arcompact_handle0f_02_dasm(DASM_PARAMS); break; // SUB_S + case 0x03: size = arcompact_handle0f_03_dasm(DASM_PARAMS); break; // 0x03 + case 0x04: size = arcompact_handle0f_04_dasm(DASM_PARAMS); break; // AND_S + case 0x05: size = arcompact_handle0f_05_dasm(DASM_PARAMS); break; // OR_S + case 0x06: size = arcompact_handle0f_06_dasm(DASM_PARAMS); break; // BIC_S + case 0x07: size = arcompact_handle0f_07_dasm(DASM_PARAMS); break; // XOR_S + case 0x08: size = arcompact_handle0f_08_dasm(DASM_PARAMS); break; // 0x08 + case 0x09: size = arcompact_handle0f_09_dasm(DASM_PARAMS); break; // 0x09 + case 0x0a: size = arcompact_handle0f_0a_dasm(DASM_PARAMS); break; // 0x0a + case 0x0b: size = arcompact_handle0f_0b_dasm(DASM_PARAMS); break; // TST_S + case 0x0c: size = arcompact_handle0f_0c_dasm(DASM_PARAMS); break; // MUL64_S + case 0x0d: size = arcompact_handle0f_0d_dasm(DASM_PARAMS); break; // SEXB_S + case 0x0e: size = arcompact_handle0f_0e_dasm(DASM_PARAMS); break; // SEXW_S + case 0x0f: size = arcompact_handle0f_0f_dasm(DASM_PARAMS); break; // EXTB_S + case 0x10: size = arcompact_handle0f_10_dasm(DASM_PARAMS); break; // EXTW_S + case 0x11: size = arcompact_handle0f_11_dasm(DASM_PARAMS); break; // ABS_S + case 0x12: size = arcompact_handle0f_12_dasm(DASM_PARAMS); break; // NOT_S + case 0x13: size = arcompact_handle0f_13_dasm(DASM_PARAMS); break; // NEG_S + case 0x14: size = arcompact_handle0f_14_dasm(DASM_PARAMS); break; // ADD1_S + case 0x15: size = arcompact_handle0f_15_dasm(DASM_PARAMS); break; // ADD2_S + case 0x16: size = arcompact_handle0f_16_dasm(DASM_PARAMS); break; // ADD3_S + case 0x17: size = arcompact_handle0f_17_dasm(DASM_PARAMS); break; // 0x17 + case 0x18: size = arcompact_handle0f_18_dasm(DASM_PARAMS); break; // ASL_S (multiple) + case 0x19: size = arcompact_handle0f_19_dasm(DASM_PARAMS); break; // LSR_S (multiple) + case 0x1a: size = arcompact_handle0f_1a_dasm(DASM_PARAMS); break; // ASR_S (multiple) + case 0x1b: size = arcompact_handle0f_1b_dasm(DASM_PARAMS); break; // ASL_S (single) + case 0x1c: size = arcompact_handle0f_1c_dasm(DASM_PARAMS); break; // LSR_S (single) + case 0x1d: size = arcompact_handle0f_1d_dasm(DASM_PARAMS); break; // ASR_S (single) + case 0x1e: size = arcompact_handle0f_1e_dasm(DASM_PARAMS); break; // TRAP (not a5?) + case 0x1f: size = arcompact_handle0f_1f_dasm(DASM_PARAMS); break; // BRK_S ( 0x7fff only? ) + + } + return size; +} + +int arcompact_handle0f_00_dasm(DASM_OPS_16) +{ + int size = 2; + UINT8 subinstr = (op & 0x00e0) >> 5; + op &= ~0x00e0; + + switch (subinstr) + { + case 0x00: size = arcompact_handle0f_00_00_dasm(DASM_PARAMS); break; // J_S + case 0x01: size = arcompact_handle0f_00_01_dasm(DASM_PARAMS); break; // J_S.D + case 0x02: size = arcompact_handle0f_00_02_dasm(DASM_PARAMS); break; // JL_S + case 0x03: size = arcompact_handle0f_00_03_dasm(DASM_PARAMS); break; // JL_S.D + case 0x04: size = arcompact_handle0f_00_04_dasm(DASM_PARAMS); break; // 0x04 + case 0x05: size = arcompact_handle0f_00_05_dasm(DASM_PARAMS); break; // 0x05 + case 0x06: size = arcompact_handle0f_00_06_dasm(DASM_PARAMS); break; // SUB_S.NE + case 0x07: size = arcompact_handle0f_00_07_dasm(DASM_PARAMS); break; // ZOPs + + } + + return size; +} + +int arcompact_handle0f_00_07_dasm(DASM_OPS_16) +{ + int size = 2; + // General Operations w/o Register + // 01111 iii 111 00000 + UINT8 subinstr3 = (op & 0x0700) >> 8; + op &= ~0x0700; + + switch (subinstr3) + { + case 0x00: size = arcompact_handle0f_00_07_00_dasm(DASM_PARAMS); break; // NOP_S + case 0x01: size = arcompact_handle0f_00_07_01_dasm(DASM_PARAMS); break; // UNIMP_S + case 0x02: size = arcompact_handle0f_00_07_02_dasm(DASM_PARAMS); break; // 0x02 + case 0x03: size = arcompact_handle0f_00_07_03_dasm(DASM_PARAMS); break; // 0x03 + case 0x04: size = arcompact_handle0f_00_07_04_dasm(DASM_PARAMS); break; // JEQ_S [BLINK] + case 0x05: size = arcompact_handle0f_00_07_05_dasm(DASM_PARAMS); break; // JNE_S [BLINK] + case 0x06: size = arcompact_handle0f_00_07_06_dasm(DASM_PARAMS); break; // J_S [BLINK] + case 0x07: size = arcompact_handle0f_00_07_07_dasm(DASM_PARAMS); break; // J_S.D [BLINK] + + } + return size; +} + +int arcompact_handle17_dasm(DASM_OPS_16) +{ + int size = 2; + UINT8 subinstr = (op & 0x00e0) >> 5; + op &= ~0x00e0; + + switch (subinstr) + { + case 0x00: size = arcompact_handle17_00_dasm(DASM_PARAMS); break; // ASL_S + case 0x01: size = arcompact_handle17_01_dasm(DASM_PARAMS); break; // LSR_S + case 0x02: size = arcompact_handle17_02_dasm(DASM_PARAMS); break; // ASR_S + case 0x03: size = arcompact_handle17_03_dasm(DASM_PARAMS); break; // SUB_S + case 0x04: size = arcompact_handle17_04_dasm(DASM_PARAMS); break; // BSET_S + case 0x05: size = arcompact_handle17_05_dasm(DASM_PARAMS); break; // BCLR_S + case 0x06: size = arcompact_handle17_06_dasm(DASM_PARAMS); break; // BMSK_S + case 0x07: size = arcompact_handle17_07_dasm(DASM_PARAMS); break; // BTST_S + } + + return size; +} + +int arcompact_handle18_dasm(DASM_OPS_16) +{ + int size = 2; + // Stack Pointer Based Instructions (16-bit) + // 11000 bbb iii uuuuu + UINT8 subinstr = (op & 0x00e0) >> 5; + op &= ~0x00e0; + + switch (subinstr) + { + case 0x00: size = arcompact_handle18_00_dasm(DASM_PARAMS); break; // LD_S (SP) + case 0x01: size = arcompact_handle18_01_dasm(DASM_PARAMS); break; // LDB_S (SP) + case 0x02: size = arcompact_handle18_02_dasm(DASM_PARAMS); break; // ST_S (SP) + case 0x03: size = arcompact_handle18_03_dasm(DASM_PARAMS); break; // STB_S (SP) + case 0x04: size = arcompact_handle18_04_dasm(DASM_PARAMS); break; // ADD_S (SP) + case 0x05: size = arcompact_handle18_05_dasm(DASM_PARAMS); break; // subtable 18_05 + case 0x06: size = arcompact_handle18_06_dasm(DASM_PARAMS); break; // subtable 18_06 + case 0x07: size = arcompact_handle18_07_dasm(DASM_PARAMS); break; // subtable 18_07 + } + + return size; +} + +int arcompact_handle18_05_dasm(DASM_OPS_16) +{ + int size = 2; + UINT8 subinstr2 = (op & 0x0700) >> 8; + op &= ~0x0700; + + switch (subinstr2) + { + case 0x00: size = arcompact_handle18_05_00_dasm(DASM_PARAMS); break; // ADD_S (SP) + case 0x01: size = arcompact_handle18_05_01_dasm(DASM_PARAMS); break; // SUB_S (SP) + case 0x02: size = arcompact_handle18_05_02_dasm(DASM_PARAMS); break; // + case 0x03: size = arcompact_handle18_05_03_dasm(DASM_PARAMS); break; // + case 0x04: size = arcompact_handle18_05_04_dasm(DASM_PARAMS); break; // + case 0x05: size = arcompact_handle18_05_05_dasm(DASM_PARAMS); break; // + case 0x06: size = arcompact_handle18_05_06_dasm(DASM_PARAMS); break; // + case 0x07: size = arcompact_handle18_05_07_dasm(DASM_PARAMS); break; // + } + + return size; +} + +int arcompact_handle18_06_dasm(DASM_OPS_16) +{ + int size = 2; + UINT8 subinstr2 = (op & 0x001f) >> 0; + op &= ~0x001f; + + switch (subinstr2) + { + case 0x00: size = arcompact_handle18_06_00_dasm(DASM_PARAMS); break; // + case 0x01: size = arcompact_handle18_06_01_dasm(DASM_PARAMS); break; // POP_S b + case 0x02: size = arcompact_handle18_06_02_dasm(DASM_PARAMS); break; // + case 0x03: size = arcompact_handle18_06_03_dasm(DASM_PARAMS); break; // + case 0x04: size = arcompact_handle18_06_04_dasm(DASM_PARAMS); break; // + case 0x05: size = arcompact_handle18_06_05_dasm(DASM_PARAMS); break; // + case 0x06: size = arcompact_handle18_06_06_dasm(DASM_PARAMS); break; // + case 0x07: size = arcompact_handle18_06_07_dasm(DASM_PARAMS); break; // + case 0x08: size = arcompact_handle18_06_08_dasm(DASM_PARAMS); break; // + case 0x09: size = arcompact_handle18_06_09_dasm(DASM_PARAMS); break; // + case 0x0a: size = arcompact_handle18_06_0a_dasm(DASM_PARAMS); break; // + case 0x0b: size = arcompact_handle18_06_0b_dasm(DASM_PARAMS); break; // + case 0x0c: size = arcompact_handle18_06_0c_dasm(DASM_PARAMS); break; // + case 0x0d: size = arcompact_handle18_06_0d_dasm(DASM_PARAMS); break; // + case 0x0e: size = arcompact_handle18_06_0e_dasm(DASM_PARAMS); break; // + case 0x0f: size = arcompact_handle18_06_0f_dasm(DASM_PARAMS); break; // + case 0x10: size = arcompact_handle18_06_10_dasm(DASM_PARAMS); break; // + case 0x11: size = arcompact_handle18_06_11_dasm(DASM_PARAMS); break; // POP_S blink + case 0x12: size = arcompact_handle18_06_12_dasm(DASM_PARAMS); break; // + case 0x13: size = arcompact_handle18_06_13_dasm(DASM_PARAMS); break; // + case 0x14: size = arcompact_handle18_06_14_dasm(DASM_PARAMS); break; // + case 0x15: size = arcompact_handle18_06_15_dasm(DASM_PARAMS); break; // + case 0x16: size = arcompact_handle18_06_16_dasm(DASM_PARAMS); break; // + case 0x17: size = arcompact_handle18_06_17_dasm(DASM_PARAMS); break; // + case 0x18: size = arcompact_handle18_06_18_dasm(DASM_PARAMS); break; // + case 0x19: size = arcompact_handle18_06_19_dasm(DASM_PARAMS); break; // + case 0x1a: size = arcompact_handle18_06_1a_dasm(DASM_PARAMS); break; // + case 0x1b: size = arcompact_handle18_06_1b_dasm(DASM_PARAMS); break; // + case 0x1c: size = arcompact_handle18_06_1c_dasm(DASM_PARAMS); break; // + case 0x1d: size = arcompact_handle18_06_1d_dasm(DASM_PARAMS); break; // + case 0x1e: size = arcompact_handle18_06_1e_dasm(DASM_PARAMS); break; // + case 0x1f: size = arcompact_handle18_06_1f_dasm(DASM_PARAMS); break; // + } + + return size; +} + +int arcompact_handle18_07_dasm(DASM_OPS_16) +{ + int size = 2; + UINT8 subinstr2 = (op & 0x001f) >> 0; + op &= ~0x001f; + + switch (subinstr2) + { + case 0x00: size = arcompact_handle18_07_00_dasm(DASM_PARAMS); break; // + case 0x01: size = arcompact_handle18_07_01_dasm(DASM_PARAMS); break; // PUSH_S b + case 0x02: size = arcompact_handle18_07_02_dasm(DASM_PARAMS); break; // + case 0x03: size = arcompact_handle18_07_03_dasm(DASM_PARAMS); break; // + case 0x04: size = arcompact_handle18_07_04_dasm(DASM_PARAMS); break; // + case 0x05: size = arcompact_handle18_07_05_dasm(DASM_PARAMS); break; // + case 0x06: size = arcompact_handle18_07_06_dasm(DASM_PARAMS); break; // + case 0x07: size = arcompact_handle18_07_07_dasm(DASM_PARAMS); break; // + case 0x08: size = arcompact_handle18_07_08_dasm(DASM_PARAMS); break; // + case 0x09: size = arcompact_handle18_07_09_dasm(DASM_PARAMS); break; // + case 0x0a: size = arcompact_handle18_07_0a_dasm(DASM_PARAMS); break; // + case 0x0b: size = arcompact_handle18_07_0b_dasm(DASM_PARAMS); break; // + case 0x0c: size = arcompact_handle18_07_0c_dasm(DASM_PARAMS); break; // + case 0x0d: size = arcompact_handle18_07_0d_dasm(DASM_PARAMS); break; // + case 0x0e: size = arcompact_handle18_07_0e_dasm(DASM_PARAMS); break; // + case 0x0f: size = arcompact_handle18_07_0f_dasm(DASM_PARAMS); break; // + case 0x10: size = arcompact_handle18_07_10_dasm(DASM_PARAMS); break; // + case 0x11: size = arcompact_handle18_07_11_dasm(DASM_PARAMS); break; // PUSH_S blink + case 0x12: size = arcompact_handle18_07_12_dasm(DASM_PARAMS); break; // + case 0x13: size = arcompact_handle18_07_13_dasm(DASM_PARAMS); break; // + case 0x14: size = arcompact_handle18_07_14_dasm(DASM_PARAMS); break; // + case 0x15: size = arcompact_handle18_07_15_dasm(DASM_PARAMS); break; // + case 0x16: size = arcompact_handle18_07_16_dasm(DASM_PARAMS); break; // + case 0x17: size = arcompact_handle18_07_17_dasm(DASM_PARAMS); break; // + case 0x18: size = arcompact_handle18_07_18_dasm(DASM_PARAMS); break; // + case 0x19: size = arcompact_handle18_07_19_dasm(DASM_PARAMS); break; // + case 0x1a: size = arcompact_handle18_07_1a_dasm(DASM_PARAMS); break; // + case 0x1b: size = arcompact_handle18_07_1b_dasm(DASM_PARAMS); break; // + case 0x1c: size = arcompact_handle18_07_1c_dasm(DASM_PARAMS); break; // + case 0x1d: size = arcompact_handle18_07_1d_dasm(DASM_PARAMS); break; // + case 0x1e: size = arcompact_handle18_07_1e_dasm(DASM_PARAMS); break; // + case 0x1f: size = arcompact_handle18_07_1f_dasm(DASM_PARAMS); break; // + } + + return size; +} + +int arcompact_handle19_dasm(DASM_OPS_16) +{ + int size = 2; + UINT8 subinstr = (op & 0x0600) >> 9; + op &= ~0x0600; + + switch (subinstr) + { + case 0x00: size = arcompact_handle19_00_dasm(DASM_PARAMS); break; // LD_S (GP) + case 0x01: size = arcompact_handle19_01_dasm(DASM_PARAMS); break; // LDB_S (GP) + case 0x02: size = arcompact_handle19_02_dasm(DASM_PARAMS); break; // LDW_S (GP) + case 0x03: size = arcompact_handle19_03_dasm(DASM_PARAMS); break; // ADD_S (GP) + } + return size; +} + +int arcompact_handle1c_dasm(DASM_OPS_16) +{ + int size = 2; + UINT8 subinstr = (op & 0x0080) >> 7; + op &= ~0x0080; + + switch (subinstr) + { + case 0x00: size = arcompact_handle1c_00_dasm(DASM_PARAMS); break; // ADD_S + case 0x01: size = arcompact_handle1c_01_dasm(DASM_PARAMS); break; // CMP_S + } + return size; +} + +int arcompact_handle1d_dasm(DASM_OPS_16) +{ + int size = 2; + UINT8 subinstr = (op & 0x0080) >> 7; + op &= ~0x0080; + + switch (subinstr) + { + case 0x00: size = arcompact_handle1d_00_dasm(DASM_PARAMS); break; // BREQ_S + case 0x01: size = arcompact_handle1d_01_dasm(DASM_PARAMS); break; // BRNE_S + } + return size; +} + +int arcompact_handle1e_dasm(DASM_OPS_16) +{ + int size = 2; + UINT8 subinstr = (op & 0x0600) >> 9; + op &= ~0x0600; + + switch (subinstr) + { + case 0x00: size = arcompact_handle1e_00_dasm(DASM_PARAMS); break; // B_S + case 0x01: size = arcompact_handle1e_01_dasm(DASM_PARAMS); break; // BEQ_S + case 0x02: size = arcompact_handle1e_02_dasm(DASM_PARAMS); break; // BNE_S + case 0x03: size = arcompact_handle1e_03_dasm(DASM_PARAMS); break; // Bcc_S + } + return size; +} + +int arcompact_handle1e_03_dasm(DASM_OPS_16) +{ + int size = 2; + UINT8 subinstr2 = (op & 0x01c0) >> 6; + op &= ~0x01c0; + + switch (subinstr2) + { + case 0x00: size = arcompact_handle1e_03_00_dasm(DASM_PARAMS); break; // BGT_S + case 0x01: size = arcompact_handle1e_03_01_dasm(DASM_PARAMS); break; // BGE_S + case 0x02: size = arcompact_handle1e_03_02_dasm(DASM_PARAMS); break; // BLT_S + case 0x03: size = arcompact_handle1e_03_03_dasm(DASM_PARAMS); break; // BLE_S + case 0x04: size = arcompact_handle1e_03_04_dasm(DASM_PARAMS); break; // BHI_S + case 0x05: size = arcompact_handle1e_03_05_dasm(DASM_PARAMS); break; // BHS_S + case 0x06: size = arcompact_handle1e_03_06_dasm(DASM_PARAMS); break; // BLO_S + case 0x07: size = arcompact_handle1e_03_07_dasm(DASM_PARAMS); break; // BLS_S + } + return size; + +} diff --git a/src/devices/cpu/arcompact/arcompactdasm_dispatch.h b/src/devices/cpu/arcompact/arcompactdasm_dispatch.h new file mode 100644 index 00000000000..40cb06f2d6b --- /dev/null +++ b/src/devices/cpu/arcompact/arcompactdasm_dispatch.h @@ -0,0 +1,50 @@ +// license:BSD-3-Clause +// copyright-holders:David Haywood +/*********************************\ + + ARCompact disassembler + +\*********************************/ + +#define DASM_OPS_16 char *output, offs_t pc, UINT16 op, const UINT8* oprom +#define DASM_OPS_32 char *output, offs_t pc, UINT32 op, const UINT8* oprom +#define DASM_PARAMS output, pc, op, oprom + +#define LIMM_REG 62 + +#define GET_LIMM_32 \ + limm = oprom[6] | (oprom[7] << 8); \ + limm |= (oprom[4] << 16) | (oprom[5] << 24); + + +int arcompact_handle00_dasm(DASM_OPS_32); +int arcompact_handle01_dasm(DASM_OPS_32); +int arcompact_handle01_00_dasm(DASM_OPS_32); +int arcompact_handle01_01_dasm(DASM_OPS_32); +int arcompact_handle01_01_00_dasm(DASM_OPS_32); +int arcompact_handle01_01_01_dasm(DASM_OPS_32); +int arcompact_handle04_dasm(DASM_OPS_32); +int arcompact_handle04_2f_dasm(DASM_OPS_32); +int arcompact_handle04_2f_3f_dasm(DASM_OPS_32); +int arcompact_handle05_dasm(DASM_OPS_32); + +int arcompact_handle05_2f_dasm(DASM_OPS_32); +int arcompact_handle05_2f_3f_dasm(DASM_OPS_32); + + +int arcompact_handle0c_dasm(DASM_OPS_16); +int arcompact_handle0d_dasm(DASM_OPS_16); +int arcompact_handle0e_dasm(DASM_OPS_16); +int arcompact_handle0f_dasm(DASM_OPS_16); +int arcompact_handle0f_00_dasm(DASM_OPS_16); +int arcompact_handle0f_00_07_dasm(DASM_OPS_16); +int arcompact_handle17_dasm(DASM_OPS_16); +int arcompact_handle18_dasm(DASM_OPS_16); +int arcompact_handle18_05_dasm(DASM_OPS_16); +int arcompact_handle18_06_dasm(DASM_OPS_16); +int arcompact_handle18_07_dasm(DASM_OPS_16); +int arcompact_handle19_dasm(DASM_OPS_16); +int arcompact_handle1c_dasm(DASM_OPS_16); +int arcompact_handle1d_dasm(DASM_OPS_16); +int arcompact_handle1e_dasm(DASM_OPS_16); +int arcompact_handle1e_03_dasm(DASM_OPS_16); diff --git a/src/devices/cpu/arcompact/arcompactdasm_ops.c b/src/devices/cpu/arcompact/arcompactdasm_ops.c new file mode 100644 index 00000000000..eeac8cac2f8 --- /dev/null +++ b/src/devices/cpu/arcompact/arcompactdasm_ops.c @@ -0,0 +1,2370 @@ +// license:BSD-3-Clause +// copyright-holders:David Haywood +/*********************************\ + + ARCompact disassembler + +\*********************************/ + +#include "emu.h" +#include + +#include "arcompactdasm_ops.h" + +char *output; + +static void ATTR_PRINTF(1,2) print(const char *fmt, ...) +{ + va_list vl; + + va_start(vl, fmt); + vsprintf(output, fmt, vl); + va_end(vl); +} + + + +#define GET_01_01_01_BRANCH_ADDR \ + INT32 address = (op & 0x00fe0000) >> 17; \ + address |= ((op & 0x00008000) >> 15) << 7; \ + if (address & 0x80) address = -0x80 + (address & 0x7f); \ + op &= ~ 0x00fe800f; + + +#define GROUP_0e_GET_h \ + h = ((op & 0x0007) << 3); \ + h |= ((op & 0x00e0) >> 5); \ + op &= ~0x00e7; +#define COMMON32_GET_breg \ + int b_temp = (op & 0x07000000) >> 24; op &= ~0x07000000; \ + int B_temp = (op & 0x00007000) >> 12; op &= ~0x00007000; \ + int breg = b_temp | (B_temp << 3); +#define COMMON32_GET_creg \ + int creg = (op & 0x00000fc0) >> 6; op &= ~0x00000fc0; +#define COMMON32_GET_u6 \ + int u = (op & 0x00000fc0) >> 6; op &= ~0x00000fc0; +#define COMMON32_GET_areg \ + int areg = (op & 0x0000003f) >> 0; op &= ~0x0000003f; +#define COMMON32_GET_areg_reserved \ + int ares = (op & 0x0000003f) >> 0; op &= ~0x0000003f; +#define COMMON32_GET_F \ + int F = (op & 0x00008000) >> 15; op &= ~0x00008000; +#define COMMON32_GET_p \ + int p = (op & 0x00c00000) >> 22; op &= ~0x00c00000; + +#define COMMON32_GET_s12 \ + int S_temp = (op & 0x0000003f) >> 0; op &= ~0x0000003f; \ + int s_temp = (op & 0x00000fc0) >> 6; op &= ~0x00000fc0; \ + int S = s_temp | (S_temp<<6); +#define COMMON32_GET_CONDITION \ + UINT8 condition = op & 0x0000001f; op &= ~0x0000001f; + + +#define COMMON16_GET_breg \ + breg = ((op & 0x0700) >>8); \ + op &= ~0x0700; +#define COMMON16_GET_creg \ + creg = ((op & 0x00e0) >>5); \ + op &= ~0x00e0; +#define COMMON16_GET_areg \ + areg = ((op & 0x0007) >>0); \ + op &= ~0x0007; +#define COMMON16_GET_u3 \ + u = ((op & 0x0007) >>0); \ + op &= ~0x0007; +#define COMMON16_GET_u5 \ + u = ((op & 0x001f) >>0); \ + op &= ~0x001f; +#define COMMON16_GET_u8 \ + u = ((op & 0x00ff) >>0); \ + op &= ~0x00ff; +#define COMMON16_GET_u7 \ + u = ((op & 0x007f) >>0); \ + op &= ~0x007f; +#define COMMON16_GET_s9 \ + s = ((op & 0x01ff) >>0); \ + op &= ~0x01ff; +// registers used in 16-bit opcodes hae a limited range +// and can only address registers r0-r3 and r12-r15 + +#define REG_16BIT_RANGE(_reg_) \ + if (_reg_>3) _reg_+= 8; + +// this is as messed up as the rest of the 16-bit alignment in LE mode... + +#define GET_LIMM \ + limm = oprom[4] | (oprom[5] << 8); \ + limm |= (oprom[2] << 16) | (oprom[3] << 24); +#define PC_ALIGNED32 \ + (pc&0xfffffffc) + + +/************************************************************************************************************************************ +* * +* individual opcode handlers (disassembly) * +* * +************************************************************************************************************************************/ + +int arcompact_handle00_00_dasm(DASM_OPS_32) +{ + int size = 4; + // Branch Conditionally + // 0000 0sss ssss sss0 SSSS SSSS SSNQ QQQQ + INT32 address = (op & 0x07fe0000) >> 17; + address |= ((op & 0x0000ffc0) >> 6) << 10; + if (address & 0x80000) address = -0x80000 + (address & 0x7ffff); + int n = (op & 0x00000020) >> 5; op &= ~0x00000020; + COMMON32_GET_CONDITION + + output += sprintf( output, "B%s(%s) %08x", delaybit[n], conditions[condition], PC_ALIGNED32 + (address * 2)); + return size; +} + +int arcompact_handle00_01_dasm(DASM_OPS_32) +{ + int size = 4; + // Branch Unconditionally Far + // 0000 0sss ssss sss1 SSSS SSSS SSNR TTTT + INT32 address = (op & 0x07fe0000) >> 17; + address |= ((op & 0x0000ffc0) >> 6) << 10; + address |= ((op & 0x0000000f) >> 0) << 20; + if (address & 0x800000) address = -0x800000 + (address & 0x7fffff); + int n = (op & 0x00000020) >> 5; op &= ~0x00000020; + int res = (op & 0x00000010) >> 4; op &= ~0x00000010; + + output += sprintf( output, "B%s %08x", delaybit[n], PC_ALIGNED32 + (address * 2) ); + if (res) output += sprintf(output, "(reserved bit set)"); + + return size; +} + +int arcompact_handle01_00_00dasm(DASM_OPS_32) +{ + int size = 4; + + // Branch and Link Conditionally + // 00001 sssssssss 00 SSSSSSSSSS N QQQQQ + INT32 address = (op & 0x07fc0000) >> 17; + address |= ((op & 0x0000ffc0) >> 6) << 10; + if (address & 0x800000) address = -0x800000 + (address&0x7fffff); + int n = (op & 0x00000020) >> 5; op &= ~0x00000020; + + COMMON32_GET_CONDITION + + output += sprintf( output, "BL%s(%s) %08x", delaybit[n], conditions[condition], PC_ALIGNED32 + (address *2) ); + return size; +} + +int arcompact_handle01_00_01dasm(DASM_OPS_32) +{ + int size = 4; + // Branch and Link Unconditionally Far + // 00001 sssssssss 10 SSSSSSSSSS N R TTTT + INT32 address = (op & 0x07fc0000) >> 17; + address |= ((op & 0x0000ffc0) >> 6) << 10; + address |= ((op & 0x0000000f) >> 0) << 20; + if (address & 0x800000) address = -0x800000 + (address&0x7fffff); + int n = (op & 0x00000020) >> 5; op &= ~0x00000020; + int res = (op & 0x00000010) >> 4; op &= ~0x00000010; + + output += sprintf( output, "BL%s %08x", delaybit[n], PC_ALIGNED32 + (address *2) ); + if (res) output += sprintf(output, "(reserved bit set)"); + + return size; +} + + + +int arcompact_01_01_00_helper(DASM_OPS_32, const char* optext) +{ + int size = 4; + + // Branch on Compare / Bit Test - Register-Register + // 00001 bbb sssssss 1 S BBB CCCCCC N 0 iiii + GET_01_01_01_BRANCH_ADDR + + + COMMON32_GET_creg + COMMON32_GET_breg; + int n = (op & 0x00000020) >> 5; op &= ~0x00000020; + + op &= ~0x07007fe0; + + if ((breg != LIMM_REG) && (creg != LIMM_REG)) + { + print("%s%s %s, %s to 0x%08x", optext, delaybit[n], regnames[breg], regnames[creg], PC_ALIGNED32 + (address * 2) ); + } + else + { + UINT32 limm; + GET_LIMM_32; + size = 8; + + if ((breg == LIMM_REG) && (creg != LIMM_REG)) + { + print("%s%s 0x%08x, %s to 0x%08x", optext, delaybit[n], limm, regnames[creg], PC_ALIGNED32 + (address * 2) ); + } + else if ((creg == LIMM_REG) && (breg != LIMM_REG)) + { + print("%s%s %s, 0x%08x to 0x%08x", optext, delaybit[n], regnames[breg], limm, PC_ALIGNED32 + (address * 2) ); + } + else + { + // b and c are LIMM? invalid?? + print("%s%s 0x%08x, 0x%08x (illegal?) to 0x%08x", optext, delaybit[n], limm, limm, PC_ALIGNED32 + (address * 2) ); + + } + } + + return size; +} + + +// register - register cases +int arcompact_handle01_01_00_00_dasm(DASM_OPS_32) { return arcompact_01_01_00_helper( DASM_PARAMS, "BREQ"); } +int arcompact_handle01_01_00_01_dasm(DASM_OPS_32) { return arcompact_01_01_00_helper( DASM_PARAMS, "BRNE"); } +int arcompact_handle01_01_00_02_dasm(DASM_OPS_32) { return arcompact_01_01_00_helper( DASM_PARAMS, "BRLT"); } +int arcompact_handle01_01_00_03_dasm(DASM_OPS_32) { return arcompact_01_01_00_helper( DASM_PARAMS, "BRGE"); } +int arcompact_handle01_01_00_04_dasm(DASM_OPS_32) { return arcompact_01_01_00_helper( DASM_PARAMS, "BRLO"); } +int arcompact_handle01_01_00_05_dasm(DASM_OPS_32) { return arcompact_01_01_00_helper( DASM_PARAMS, "BRHS"); } +int arcompact_handle01_01_00_0e_dasm(DASM_OPS_32) { return arcompact_01_01_00_helper( DASM_PARAMS, "BBIT0");} +int arcompact_handle01_01_00_0f_dasm(DASM_OPS_32) { return arcompact_01_01_00_helper( DASM_PARAMS, "BBIT1");} + +int arcompact_01_01_01_helper(DASM_OPS_32, const char* optext) +{ + int size = 4; + + // using 'b' as limm here makes no sense (comparing a long immediate against a short immediate) so I assume it isn't + // valid? + + // Branch on Compare / Bit Test - Register-Immediate + // 0000 1bbb ssss sss1 SBBB uuuu uuN1 iiii + GET_01_01_01_BRANCH_ADDR + + COMMON32_GET_u6 + COMMON32_GET_breg; + int n = (op & 0x00000020) >> 5; op &= ~0x00000020; + + op &= ~0x07007fe0; + + print("%s%s %s, 0x%02x %08x (%08x)", optext, delaybit[n], regnames[breg], u, PC_ALIGNED32 + (address * 2), op & ~0xf8fe800f); + + return size; +} + +// register -immediate cases +int arcompact_handle01_01_01_00_dasm(DASM_OPS_32) { return arcompact_01_01_01_helper(DASM_PARAMS, "BREQ"); } +int arcompact_handle01_01_01_01_dasm(DASM_OPS_32) { return arcompact_01_01_01_helper(DASM_PARAMS, "BRNE"); } +int arcompact_handle01_01_01_02_dasm(DASM_OPS_32) { return arcompact_01_01_01_helper(DASM_PARAMS, "BRLT"); } +int arcompact_handle01_01_01_03_dasm(DASM_OPS_32) { return arcompact_01_01_01_helper(DASM_PARAMS, "BRGE"); } +int arcompact_handle01_01_01_04_dasm(DASM_OPS_32) { return arcompact_01_01_01_helper(DASM_PARAMS, "BRLO"); } +int arcompact_handle01_01_01_05_dasm(DASM_OPS_32) { return arcompact_01_01_01_helper(DASM_PARAMS, "BRHS"); } +int arcompact_handle01_01_01_0e_dasm(DASM_OPS_32) { return arcompact_01_01_01_helper(DASM_PARAMS, "BBIT0"); } +int arcompact_handle01_01_01_0f_dasm(DASM_OPS_32) { return arcompact_01_01_01_helper(DASM_PARAMS, "BBIT1"); } + + +int arcompact_handle02_dasm(DASM_OPS_32) +{ + // bitpos + // 1111 1111 1111 1111 0000 0000 0000 0000 + // fedc ba98 7654 3210 fedc ba98 7654 3210 + // fields + // 0001 0bbb ssss ssss SBBB DaaZ ZXAA AAAA + int size = 4; + + COMMON32_GET_areg + int X = (op & 0x00000040) >> 6; //op &= ~0x00000040; + int Z = (op & 0x00000180) >> 7; //op &= ~0x00000180; + int a = (op & 0x00000600) >> 9; //op &= ~0x00000600; + int D = (op & 0x00000800) >> 11;// op &= ~0x00000800; + int S = (op & 0x00008000) >> 15;// op &= ~0x00008000; + int s = (op & 0x00ff0000) >> 16;// op &= ~0x00ff0000; + COMMON32_GET_breg; + + int sdat = s | (S << 8); // todo - signed + + UINT32 limm = 0; + if (breg == LIMM_REG) + { + GET_LIMM_32; + size = 8; + } + + output += sprintf( output, "LD"); + output += sprintf( output, "%s", datasize[Z]); + output += sprintf( output, "%s", dataextend[X]); + output += sprintf( output, "%s", addressmode[a]); + output += sprintf( output, "%s", cachebit[D]); + output += sprintf( output, " "); + output += sprintf( output, "%s <- ", regnames[areg]); + output += sprintf( output, "["); + if (breg == LIMM_REG) output += sprintf( output, "(%08x), ", limm); + else output += sprintf( output, "%s, ", regnames[breg]); + output += sprintf( output, "%03x", sdat); + output += sprintf( output, "]"); + + return size; +} + +int arcompact_handle03_dasm(DASM_OPS_32) +{ + int size = 4; + UINT32 limm = 0; + int got_limm = 0; + // bitpos + // 1111 1111 1111 1111 0000 0000 0000 0000 + // fedc ba98 7654 3210 fedc ba98 7654 3210 + // fields + // 0001 1bbb ssss ssss SBBB CCCC CCDa aZZR + int S = (op & 0x00008000) >> 15;// op &= ~0x00008000; + int s = (op & 0x00ff0000) >> 16;// op &= ~0x00ff0000; + + COMMON32_GET_breg; + int sdat = s | (S << 8); // todo - signed + + int R = (op & 0x00000001) >> 0; op &= ~0x00000001; + int Z = (op & 0x00000006) >> 1; op &= ~0x00000006; + int a = (op & 0x00000018) >> 3; op &= ~0x00000018; + int D = (op & 0x00000020) >> 5; op &= ~0x00000020; + COMMON32_GET_creg + + if (breg == LIMM_REG) + { + GET_LIMM_32; + size = 8; + got_limm = 1; + } + + + output += sprintf( output, "ST"); + output += sprintf( output, "%s", datasize[Z]); + output += sprintf( output, "%s", addressmode[a]); + output += sprintf( output, "%s", cachebit[D]); + output += sprintf( output, " "); + + output += sprintf( output, "["); + if (breg == LIMM_REG) output += sprintf( output, "(%08x), ", limm); + else output += sprintf( output, "%s, ", regnames[breg]); + output += sprintf( output, "%03x", sdat); + output += sprintf( output, "] <- "); + + if (creg == LIMM_REG) + { + if (!got_limm) + { + GET_LIMM_32; + size = 8; + } + output += sprintf(output, "(%08x)", limm); + + } + else + { + output += sprintf(output, "%s", regnames[creg]); + } + + if (R) output += sprintf( output, "(reserved bit set)"); + + + return size; +} + +int arcompact_handle04_p00_helper_dasm(DASM_OPS_32, const char* optext, int ignore_dst, int b_reserved) +{ + // PP + // 0010 0bbb 00ii iiii FBBB CCCC CCAA AAAA + int size = 4; + UINT32 limm = 0; + int got_limm = 0; + + COMMON32_GET_breg; + COMMON32_GET_F; + COMMON32_GET_creg + COMMON32_GET_areg + + output += sprintf(output, "%s", optext); + output += sprintf(output, "%s", flagbit[F]); + // output += sprintf( output, " p(%d)", p); + + + if ((!b_reserved) && (breg == LIMM_REG)) + { + GET_LIMM_32; + size = 8; + got_limm = 1; + } + + if (creg == LIMM_REG) + { + if (!got_limm) + { + GET_LIMM_32; + size = 8; + } + } + + // areg can be LIMM too, but in that case LIMM indicates 'no destination' rather than an actual LIMM value following + + if (ignore_dst == 0) + { + if (areg != LIMM_REG) output += sprintf(output, " %s <-", regnames[areg]); + else output += sprintf(output, " <-"); + } + else if (ignore_dst == 1) // certain opcode types ignore the 'a' field entirely, it should be set to 0. + { + if (areg) output += sprintf(output, " <-", areg); + } + else if (ignore_dst == 2) // for multiply operations areg should always be set to LIMM + { + if (areg != LIMM_REG) output += sprintf(output, " <-", areg); + else output += sprintf(output, " <-"); + } + + if (!b_reserved) + { + if (breg == LIMM_REG) + output += sprintf(output, " 0x%08x,", limm); + else + output += sprintf(output, " %s,", regnames[breg]); + } + else + { + if (breg) output += sprintf(output, ",", breg); + } + + if (creg == LIMM_REG) + output += sprintf(output, " 0x%08x", limm); + else + output += sprintf(output, " %s", regnames[creg]); + + return size; +} + +// like p00 but with 'u6' istead of C +int arcompact_handle04_p01_helper_dasm(DASM_OPS_32, const char* optext, int ignore_dst, int b_reserved) +{ + // PP + // 0010 0bbb 01ii iiii FBBB uuuu uuAA AAAA + int size = 4; + UINT32 limm = 0; +// int got_limm = 0; + + COMMON32_GET_breg; + COMMON32_GET_F; + COMMON32_GET_u6 + COMMON32_GET_areg + + output += sprintf(output, "%s", optext); + output += sprintf(output, "%s", flagbit[F]); + // output += sprintf( output, " p(%d)", p); + + + if ((!b_reserved) && (breg == LIMM_REG)) + { + GET_LIMM_32; + size = 8; +// got_limm = 1; + } + + // areg can be LIMM too, but in that case LIMM indicates 'no destination' rather than an actual LIMM value following + + if (ignore_dst == 0) + { + if (areg != LIMM_REG) output += sprintf(output, " %s <-", regnames[areg]); + else output += sprintf(output, " <-"); + } + else if (ignore_dst == 1) // certain opcode types ignore the 'a' field entirely, it should be set to 0. + { + if (areg) output += sprintf(output, " <-", areg); + } + else if (ignore_dst == 2) // for multiply operations areg should always be set to LIMM + { + if (areg != LIMM_REG) output += sprintf(output, " <-", areg); + else output += sprintf(output, " <-"); + } + + if (!b_reserved) + { + if (breg == LIMM_REG) + output += sprintf(output, " 0x%08x,", limm); + else + output += sprintf(output, " %s,", regnames[breg]); + } + else + { + if (breg) output += sprintf(output, ",", breg); + } + + output += sprintf(output, " 0x%02x", u); + + return size; +} + + +int arcompact_handle04_p10_helper_dasm(DASM_OPS_32, const char* optext, int b_reserved) +{ + int size = 4; + UINT32 limm = 0; + //int got_limm = 0; + + COMMON32_GET_breg; + COMMON32_GET_F + COMMON32_GET_s12; + + output += sprintf(output, "%s", optext); + output += sprintf(output, "%s", flagbit[F]); + // output += sprintf( output, " p(%d)", p); + + + if (!b_reserved) + { + if (breg == LIMM_REG) + { + GET_LIMM_32; + size = 8; + //got_limm = 1; + output += sprintf(output, " 0x%08x ", limm); + + } + else + { + output += sprintf(output, " %s, ", regnames[breg]); + } + } + else + { + if (breg) output += sprintf(output, "reserved(%s), ", regnames[breg]); + } + + output += sprintf(output, "S(%02x)", S); + return size; +} + +int arcompact_handle04_p11_m0_helper_dasm(DASM_OPS_32, const char* optext, int b_reserved) +{ + int size = 4; + UINT32 limm = 0; + int got_limm = 0; + + COMMON32_GET_breg; + COMMON32_GET_F + COMMON32_GET_CONDITION; + COMMON32_GET_creg + + output += sprintf(output, "%s", optext); + output += sprintf(output, "%s", flagbit[F]); + // output += sprintf( output, " p(%d)", p); + + if (!b_reserved) + { + if (breg == LIMM_REG) + { + GET_LIMM_32; + size = 8; + got_limm = 1; + output += sprintf(output, " 0x%08x ", limm); + + } + else + { + output += sprintf(output, " %s, ", regnames[breg]); + } + } + else + { + if (breg) output += sprintf(output, "reserved(%s), ", regnames[breg]); + } + + + output += sprintf(output, " Cond<%s> ", conditions[condition]); + + + if (creg == LIMM_REG) + { + if (!got_limm) + { + GET_LIMM_32; + size = 8; + } + output += sprintf(output, " 0x%08x ", limm); + } + else + { + output += sprintf(output, "C(%s)", regnames[creg]); + } + + return size; +} + +int arcompact_handle04_p11_m1_helper_dasm(DASM_OPS_32, const char* optext, int b_reserved) +{ + int size = 4; + UINT32 limm = 0; + //int got_limm = 0; + + COMMON32_GET_breg; + COMMON32_GET_F + COMMON32_GET_CONDITION; + COMMON32_GET_u6 + + output += sprintf(output, "%s", optext); + output += sprintf(output, "%s", flagbit[F]); + // output += sprintf( output, " p(%d)", p); + + if (!b_reserved) + { + if (breg == LIMM_REG) + { + GET_LIMM_32; + size = 8; + //got_limm = 1; + output += sprintf(output, " 0x%08x ", limm); + + } + else + { + output += sprintf(output, " %s, ", regnames[breg]); + } + } + else + { + if (breg) output += sprintf(output, "reserved(%s), ", regnames[breg]); + } + + + output += sprintf(output, " Cond<%s> ", conditions[condition]); + + + output += sprintf(output, "U(%02x)", u); + + return size; +} + +int arcompact_handle04_p11_helper_dasm(DASM_OPS_32, const char* optext, int b_reserved) +{ + int M = (op & 0x00000020) >> 5; op &= ~0x00000020; + + switch (M) + { + case 0x00: return arcompact_handle04_p11_m0_helper_dasm(DASM_PARAMS, optext, b_reserved); + case 0x01: return arcompact_handle04_p11_m1_helper_dasm(DASM_PARAMS, optext, b_reserved); + } + return 0; +} + + +int arcompact_handle04_helper_dasm(DASM_OPS_32, const char* optext, int ignore_dst, int b_reserved) +{ + COMMON32_GET_p; + + switch (p) + { + case 0x00: return arcompact_handle04_p00_helper_dasm(DASM_PARAMS, optext, ignore_dst, b_reserved); + case 0x01: return arcompact_handle04_p01_helper_dasm(DASM_PARAMS, optext, ignore_dst, b_reserved); + case 0x02: return arcompact_handle04_p10_helper_dasm(DASM_PARAMS, optext, b_reserved); + case 0x03: return arcompact_handle04_p11_helper_dasm(DASM_PARAMS, optext, b_reserved); + } + + return 0; +} + +int arcompact_handle04_00_dasm(DASM_OPS_32) +{ + return arcompact_handle04_helper_dasm(DASM_PARAMS, "ADD", 0,0); +} + +int arcompact_handle04_01_dasm(DASM_OPS_32) +{ + return arcompact_handle04_helper_dasm(DASM_PARAMS, "ADC", 0,0); +} + +int arcompact_handle04_02_dasm(DASM_OPS_32) +{ + return arcompact_handle04_helper_dasm(DASM_PARAMS, "SUB", 0,0); +} + +int arcompact_handle04_03_dasm(DASM_OPS_32) +{ + return arcompact_handle04_helper_dasm(DASM_PARAMS, "SBC", 0,0); +} + +int arcompact_handle04_04_dasm(DASM_OPS_32) +{ + return arcompact_handle04_helper_dasm(DASM_PARAMS, "AND", 0,0); +} + +int arcompact_handle04_05_dasm(DASM_OPS_32) +{ + return arcompact_handle04_helper_dasm(DASM_PARAMS, "OR", 0,0); +} + +int arcompact_handle04_06_dasm(DASM_OPS_32) +{ + return arcompact_handle04_helper_dasm(DASM_PARAMS, "BIC", 0,0); +} + +int arcompact_handle04_07_dasm(DASM_OPS_32) +{ + return arcompact_handle04_helper_dasm(DASM_PARAMS, "XOR", 0,0); +} + +int arcompact_handle04_08_dasm(DASM_OPS_32) +{ + return arcompact_handle04_helper_dasm(DASM_PARAMS, "MAX", 0,0); +} + +int arcompact_handle04_09_dasm(DASM_OPS_32) +{ + return arcompact_handle04_helper_dasm(DASM_PARAMS, "MIN", 0,0); +} + + +int arcompact_handle04_0a_dasm(DASM_OPS_32) +{ + return arcompact_handle04_helper_dasm(DASM_PARAMS, "MOV", 1,0); +} + +int arcompact_handle04_0b_dasm(DASM_OPS_32) +{ + return arcompact_handle04_helper_dasm(DASM_PARAMS, "TST", 1,0); +} + +int arcompact_handle04_0c_dasm(DASM_OPS_32) +{ + return arcompact_handle04_helper_dasm(DASM_PARAMS, "CMP", 1,0); +} + +int arcompact_handle04_0d_dasm(DASM_OPS_32) +{ + return arcompact_handle04_helper_dasm(DASM_PARAMS, "RCMP", 1,0); +} + +int arcompact_handle04_0e_dasm(DASM_OPS_32) +{ + return arcompact_handle04_helper_dasm(DASM_PARAMS, "RSUB", 0,0); +} + +int arcompact_handle04_0f_dasm(DASM_OPS_32) +{ + return arcompact_handle04_helper_dasm(DASM_PARAMS, "BSET", 0,0); +} + +int arcompact_handle04_10_dasm(DASM_OPS_32) +{ + return arcompact_handle04_helper_dasm(DASM_PARAMS, "BCLR", 0,0); +} + +int arcompact_handle04_11_dasm(DASM_OPS_32) +{ + return arcompact_handle04_helper_dasm(DASM_PARAMS, "BTST", 0,0); +} + +int arcompact_handle04_12_dasm(DASM_OPS_32) +{ + return arcompact_handle04_helper_dasm(DASM_PARAMS, "BXOR", 0,0); +} + +int arcompact_handle04_13_dasm(DASM_OPS_32) +{ + return arcompact_handle04_helper_dasm(DASM_PARAMS, "BMSK", 0,0); +} + +int arcompact_handle04_14_dasm(DASM_OPS_32) +{ + return arcompact_handle04_helper_dasm(DASM_PARAMS, "ADD1", 0,0); +} + +int arcompact_handle04_15_dasm(DASM_OPS_32) +{ + return arcompact_handle04_helper_dasm(DASM_PARAMS, "ADD2", 0,0); +} + +int arcompact_handle04_16_dasm(DASM_OPS_32) +{ + return arcompact_handle04_helper_dasm(DASM_PARAMS, "ADD3", 0,0); +} + +int arcompact_handle04_17_dasm(DASM_OPS_32) +{ + return arcompact_handle04_helper_dasm(DASM_PARAMS, "SUB1", 0,0); +} + +int arcompact_handle04_18_dasm(DASM_OPS_32) +{ + return arcompact_handle04_helper_dasm(DASM_PARAMS, "SUB2", 0,0); +} + +int arcompact_handle04_19_dasm(DASM_OPS_32) +{ + return arcompact_handle04_helper_dasm(DASM_PARAMS, "SUB3", 0,0); +} + +int arcompact_handle04_1a_dasm(DASM_OPS_32) +{ + return arcompact_handle04_helper_dasm(DASM_PARAMS, "MPY", 0,0); +} // * + +int arcompact_handle04_1b_dasm(DASM_OPS_32) +{ + return arcompact_handle04_helper_dasm(DASM_PARAMS, "MPYH", 0,0); +} // * + +int arcompact_handle04_1c_dasm(DASM_OPS_32) +{ + return arcompact_handle04_helper_dasm(DASM_PARAMS, "MPYHU", 0,0); +} // * + +int arcompact_handle04_1d_dasm(DASM_OPS_32) +{ + return arcompact_handle04_helper_dasm(DASM_PARAMS, "MPYU", 0,0); +} // * + + + +int arcompact_handle04_20_dasm(DASM_OPS_32) +{ + return arcompact_handle04_helper_dasm(DASM_PARAMS, "J", 1,1); +} + + + +int arcompact_handle04_21_dasm(DASM_OPS_32) +{ + return arcompact_handle04_helper_dasm(DASM_PARAMS, "J.D", 1,1); +} + +int arcompact_handle04_22_dasm(DASM_OPS_32) +{ + return arcompact_handle04_helper_dasm(DASM_PARAMS, "JL", 1,1); +} + +int arcompact_handle04_23_dasm(DASM_OPS_32) +{ + return arcompact_handle04_helper_dasm(DASM_PARAMS, "JL.D", 1,1); +} + + + + +int arcompact_handle04_28_dasm(DASM_OPS_32) // LPcc (loop setup) +{ + COMMON32_GET_breg; // breg is reserved + COMMON32_GET_p; + + if (p == 0x00) + { + print(" (start %08x, end %08x)", conditions[condition], pc + 4, PC_ALIGNED32 + u*2); + + int unused = (op & 0x00000020)>>5; + if (unused==0) output += sprintf(output, "(unused bit not set)"); + + } + + if (breg) output += sprintf(output, "(reseved B bits set %02x)", breg); + + return 4; +} + +#define PRINT_AUX_REGNAME \ + if ((auxreg >= 0) && (auxreg < 0x420)) \ + { \ + if (strcmp(auxregnames[auxreg],"unusedreg")) \ + output += sprintf(output, "[%s]", auxregnames[auxreg]); \ + else \ + output += sprintf( output, "[%03x]", auxreg); \ + } \ + else \ + output += sprintf( output, "[%03x]", auxreg); +int arcompact_handle04_2a_dasm(DASM_OPS_32) // Load FROM Auxiliary register TO register +{ + // pp F + // 0010 0bbb 0010 1010 0BBB CCCC CCRR RRRR + // 0010 0bbb 0010 1010 0BBB 1111 10RR RRRR + // 0010 0bbb 0110 1010 0BBB uuuu uu00 0000 + // 0010 0bbb 1010 1010 0BBB ssss ssSS SSSS + + + int size = 4; + UINT32 limm = 0; + int got_limm = 0; + + COMMON32_GET_p; + COMMON32_GET_breg; + COMMON32_GET_F + + output += sprintf( output, "LR"); + if (F) output += sprintf( output, "."); +// output += sprintf( output, " p(%d)", p); + + + + if (breg == LIMM_REG) + { + output += sprintf( output, "" ); // illegal encoding? + } + else + { + output += sprintf(output, " %s, ", regnames[breg]); + } + + + + if (p == 0) + { + COMMON32_GET_creg + COMMON32_GET_areg_reserved + + if (creg == LIMM_REG) + { + if (!got_limm) + { + GET_LIMM_32; + size = 8; + } + + output += sprintf( output, "(%08x) ", limm ); + + } + else + { + output += sprintf( output, "C(%s) ", regnames[creg]); + } + + if (ares) output += sprintf( output, "reserved(%02x) ", ares ); + } + else if (p == 1) + { + COMMON32_GET_u6 + COMMON32_GET_areg_reserved + + int auxreg = u; + PRINT_AUX_REGNAME + + if (ares) output += sprintf( output, "reserved(%02x) ", ares ); + } + else if (p == 2) + { + COMMON32_GET_s12; + + int auxreg = S; + PRINT_AUX_REGNAME + + } + else if (p == 3) + { + output += sprintf( output, " "); + } + + return size; +} + +int arcompact_handle04_2b_dasm(DASM_OPS_32) // Store TO Auxiliary register FROM register +{ + // code at ~ 40073DFE in leapster bios is manually setting up a loop this way + // rather than using the lPcc opcode + + int size = 4; + UINT32 limm = 0; + int got_limm = 0; + + COMMON32_GET_p; + COMMON32_GET_breg; + COMMON32_GET_F + + output += sprintf( output, "SR"); + if (F) output += sprintf( output, "."); +// output += sprintf( output, " p(%d)", p); + + + + if (breg == LIMM_REG) + { + GET_LIMM_32; + size = 8; + got_limm = 1; + output += sprintf( output, " %08x -> ", limm ); + + } + else + { + output += sprintf(output, " %s -> ", regnames[breg]); + } + + + + if (p == 0) + { + COMMON32_GET_creg + COMMON32_GET_areg_reserved + + if (creg == LIMM_REG) + { + if (!got_limm) + { + GET_LIMM_32; + size = 8; + } + + output += sprintf( output, "[%08x]", limm ); + + } + else + { + output += sprintf( output, "[%s]", regnames[creg]); + + + } + + if (ares) output += sprintf( output, " (reserved %02x) ", ares ); + + + } + else if (p == 1) + { + COMMON32_GET_u6 + COMMON32_GET_areg_reserved + + int auxreg = u; + PRINT_AUX_REGNAME + + if (ares) output += sprintf( output, " (reserved %02x) ", ares ); + + + } + else if (p == 2) + { + COMMON32_GET_s12; + + int auxreg = S; + + PRINT_AUX_REGNAME + + } + else if (p == 3) + { + output += sprintf( output, " "); + } + + return size;} + + +int arcompact_handle04_29_dasm(DASM_OPS_32) +{ + // leapster bios uses formats for FLAG that are not defined, bug I guess work anyway (P modes 0 / 1) + return arcompact_handle04_helper_dasm(DASM_PARAMS, "FLAG", 1,1); +} + + +int arcompact_handle04_2f_helper_dasm(DASM_OPS_32, const char* optext) +{ + // + // 0010 0bbb pp10 1111 FBBB CCCC CCII IIII + int size = 4; + + COMMON32_GET_p; + COMMON32_GET_breg; + COMMON32_GET_F + + output += sprintf( output, "%s", optext); + output += sprintf( output, "%s", flagbit[F]); +// output += sprintf( output, " p(%d)", p); + + if (breg == LIMM_REG) + { + output += sprintf(output, " , "); + // if using the 'EX' opcode this is illegal + } + else + { + output += sprintf(output, " %s, ", regnames[breg]); + } + + if (p == 0) + { + COMMON32_GET_creg + + if (creg == LIMM_REG) + { + UINT32 limm; + GET_LIMM_32; + size = 8; + output += sprintf( output, "(%08x) ", limm ); + + } + else + { + output += sprintf( output, "C(%s) ", regnames[creg]); + } + } + else if (p == 1) + { + COMMON32_GET_u6 + + output += sprintf( output, "U(0x%02x) ", u); + } + else if (p == 2) + { + output += sprintf( output, "<04_2f illegal p=10>"); + } + else if (p == 3) + { + output += sprintf( output, "<04_2f illegal p=11>"); + } + + return size; +} + + +int arcompact_handle04_2f_00_dasm(DASM_OPS_32) { return arcompact_handle04_2f_helper_dasm(DASM_PARAMS, "ASL"); } // ASL +int arcompact_handle04_2f_01_dasm(DASM_OPS_32) { return arcompact_handle04_2f_helper_dasm(DASM_PARAMS, "ASR"); } // ASR +int arcompact_handle04_2f_02_dasm(DASM_OPS_32) { return arcompact_handle04_2f_helper_dasm(DASM_PARAMS, "LSR"); } // LSR +int arcompact_handle04_2f_03_dasm(DASM_OPS_32) { return arcompact_handle04_2f_helper_dasm(DASM_PARAMS, "ROR"); } // ROR +int arcompact_handle04_2f_04_dasm(DASM_OPS_32) { return arcompact_handle04_2f_helper_dasm(DASM_PARAMS, "RCC"); } // RCC +int arcompact_handle04_2f_05_dasm(DASM_OPS_32) { return arcompact_handle04_2f_helper_dasm(DASM_PARAMS, "SEXB"); } // SEXB +int arcompact_handle04_2f_06_dasm(DASM_OPS_32) { return arcompact_handle04_2f_helper_dasm(DASM_PARAMS, "SEXW"); } // SEXW +int arcompact_handle04_2f_07_dasm(DASM_OPS_32) { return arcompact_handle04_2f_helper_dasm(DASM_PARAMS, "EXTB"); } // EXTB + +int arcompact_handle04_2f_08_dasm(DASM_OPS_32) { return arcompact_handle04_2f_helper_dasm(DASM_PARAMS, "EXTW"); } // EXTW + + +int arcompact_handle04_2f_09_dasm(DASM_OPS_32) { return arcompact_handle04_2f_helper_dasm(DASM_PARAMS, "ABS"); } // ABS +int arcompact_handle04_2f_0a_dasm(DASM_OPS_32) { return arcompact_handle04_2f_helper_dasm(DASM_PARAMS, "NOT"); } // NOT +int arcompact_handle04_2f_0b_dasm(DASM_OPS_32) { return arcompact_handle04_2f_helper_dasm(DASM_PARAMS, "RCL"); } // RLC +int arcompact_handle04_2f_0c_dasm(DASM_OPS_32) { return arcompact_handle04_2f_helper_dasm(DASM_PARAMS, "EX"); } // EX + + +int arcompact_handle04_2f_3f_01_dasm(DASM_OPS_32) { print("SLEEP (%08x)", op); return 4;} +int arcompact_handle04_2f_3f_02_dasm(DASM_OPS_32) { print("SWI / TRAP0 (%08x)", op); return 4;} +int arcompact_handle04_2f_3f_03_dasm(DASM_OPS_32) { print("SYNC (%08x)", op); return 4;} +int arcompact_handle04_2f_3f_04_dasm(DASM_OPS_32) { print("RTIE (%08x)", op); return 4;} +int arcompact_handle04_2f_3f_05_dasm(DASM_OPS_32) { print("BRK (%08x)", op); return 4;} + + + + + +// format on these is.. + +// 0010 0bbb aa11 0ZZX DBBB CCCC CCAA AAAA +// note, bits 11 0ZZX are part of the sub-opcode # already - this is a special encoding +int arcompact_handle04_3x_helper_dasm(DASM_OPS_32, int dsize, int extend) +{ + int size = 4; + UINT32 limm=0; + int got_limm = 0; + + output += sprintf(output, "LD"); + output += sprintf(output, "%s", datasize[dsize]); + output += sprintf(output, "%s", dataextend[extend]); + + int mode = (op & 0x00c00000) >> 22; op &= ~0x00c00000; + COMMON32_GET_breg; + int D = (op & 0x00008000) >> 15; op &= ~0x00008000; + COMMON32_GET_creg + COMMON32_GET_areg + + output += sprintf(output, "%s", addressmode[mode]); + output += sprintf(output, "%s", cachebit[D]); + + output += sprintf( output, " %s. ", regnames[areg]); + + if (breg == LIMM_REG) + { + GET_LIMM_32; + size = 8; + got_limm = 1; + output += sprintf( output, "[%08x, ", limm ); + + } + else + { + output += sprintf(output, "[%s, ", regnames[breg]); + } + + if (creg == LIMM_REG) + { + if (!got_limm) + { + GET_LIMM_32; + size = 8; + } + output += sprintf( output, "(%08x)]", limm ); + + } + else + { + output += sprintf( output, "%s]", regnames[creg]); + } + + + return size; + + + +} + +int arcompact_handle04_30_dasm(DASM_OPS_32) { return arcompact_handle04_3x_helper_dasm(DASM_PARAMS,0,0); } +// ZZ value of 0x0 with X of 1 is illegal +int arcompact_handle04_31_dasm(DASM_OPS_32) { return arcompact_handle04_3x_helper_dasm(DASM_PARAMS,0,1); } +int arcompact_handle04_32_dasm(DASM_OPS_32) { return arcompact_handle04_3x_helper_dasm(DASM_PARAMS,1,0); } +int arcompact_handle04_33_dasm(DASM_OPS_32) { return arcompact_handle04_3x_helper_dasm(DASM_PARAMS,1,1); } +int arcompact_handle04_34_dasm(DASM_OPS_32) { return arcompact_handle04_3x_helper_dasm(DASM_PARAMS,2,0); } +int arcompact_handle04_35_dasm(DASM_OPS_32) { return arcompact_handle04_3x_helper_dasm(DASM_PARAMS,2,1); } +// ZZ value of 0x3 is illegal +int arcompact_handle04_36_dasm(DASM_OPS_32) { return arcompact_handle04_3x_helper_dasm(DASM_PARAMS,3,0); } +int arcompact_handle04_37_dasm(DASM_OPS_32) { return arcompact_handle04_3x_helper_dasm(DASM_PARAMS,3,1); } + + + + + + +int arcompact_handle05_00_dasm(DASM_OPS_32) { return arcompact_handle04_helper_dasm(DASM_PARAMS, "ASL", 0,0); } +int arcompact_handle05_01_dasm(DASM_OPS_32) { return arcompact_handle04_helper_dasm(DASM_PARAMS, "LSR", 0,0); } +int arcompact_handle05_02_dasm(DASM_OPS_32) { return arcompact_handle04_helper_dasm(DASM_PARAMS, "ASR", 0,0); } +int arcompact_handle05_03_dasm(DASM_OPS_32) { return arcompact_handle04_helper_dasm(DASM_PARAMS, "ROR", 0,0); } +int arcompact_handle05_04_dasm(DASM_OPS_32) { return arcompact_handle04_helper_dasm(DASM_PARAMS, "MUL64", 2,0); } // special +int arcompact_handle05_05_dasm(DASM_OPS_32) { return arcompact_handle04_helper_dasm(DASM_PARAMS, "MULU64", 2,0);} // special +int arcompact_handle05_06_dasm(DASM_OPS_32) { return arcompact_handle04_helper_dasm(DASM_PARAMS, "ADDS", 0,0); } +int arcompact_handle05_07_dasm(DASM_OPS_32) { return arcompact_handle04_helper_dasm(DASM_PARAMS, "SUBS", 0,0); } +int arcompact_handle05_08_dasm(DASM_OPS_32) { return arcompact_handle04_helper_dasm(DASM_PARAMS, "DIVAW", 0,0); } + + + +int arcompact_handle05_0a_dasm(DASM_OPS_32) { return arcompact_handle04_helper_dasm(DASM_PARAMS, "ASLS", 0,0); } +int arcompact_handle05_0b_dasm(DASM_OPS_32) { return arcompact_handle04_helper_dasm(DASM_PARAMS, "ASRS", 0,0); } + +int arcompact_handle05_28_dasm(DASM_OPS_32) { return arcompact_handle04_helper_dasm(DASM_PARAMS, "ADDSDW", 0,0); } +int arcompact_handle05_29_dasm(DASM_OPS_32) { return arcompact_handle04_helper_dasm(DASM_PARAMS, "SUBSDW", 0,0); } + + + +int arcompact_handle05_2f_0x_helper_dasm(DASM_OPS_32, const char* optext) +{ + // + // 0010 1bbb pp10 1111 FBBB CCCC CCII IIII when pp == 0x00 + // or + // 0010 1bbb pp10 1111 FBBB UUUU UUII IIII when pp == 0x01 + // otherwise invalid + + int size = 4; + + COMMON32_GET_p; + COMMON32_GET_breg; + COMMON32_GET_F + + output += sprintf( output, "%s", optext); + output += sprintf( output, "%s", flagbit[F]); +// output += sprintf( output, " p(%d)", p); + + + output += sprintf(output, " %s, ", regnames[breg]); + + if (p == 0) + { + COMMON32_GET_creg + + if (creg == LIMM_REG) + { + UINT32 limm; + GET_LIMM_32; + size = 8; + output += sprintf( output, "(%08x) ", limm ); + + } + else + { + output += sprintf( output, "C(%s) ", regnames[creg]); + } + } + else if (p == 1) + { + COMMON32_GET_u6 + output += sprintf( output, "U(0x%02x) ", u); + } + else if (p == 2) + { + output += sprintf( output, "<05_2f illegal p=10>"); + } + else if (p == 3) + { + output += sprintf( output, "<05_2f illegal p=11>"); + } + + return size; +} + + +int arcompact_handle05_2f_00_dasm(DASM_OPS_32) { return arcompact_handle05_2f_0x_helper_dasm(DASM_PARAMS, "SWAP"); } +int arcompact_handle05_2f_01_dasm(DASM_OPS_32) { return arcompact_handle05_2f_0x_helper_dasm(DASM_PARAMS, "NORM"); } +int arcompact_handle05_2f_02_dasm(DASM_OPS_32) { return arcompact_handle05_2f_0x_helper_dasm(DASM_PARAMS, "SAT16"); } +int arcompact_handle05_2f_03_dasm(DASM_OPS_32) { return arcompact_handle05_2f_0x_helper_dasm(DASM_PARAMS, "RND16"); } +int arcompact_handle05_2f_04_dasm(DASM_OPS_32) { return arcompact_handle05_2f_0x_helper_dasm(DASM_PARAMS, "ABSSW"); } +int arcompact_handle05_2f_05_dasm(DASM_OPS_32) { return arcompact_handle05_2f_0x_helper_dasm(DASM_PARAMS, "ABSS"); } +int arcompact_handle05_2f_06_dasm(DASM_OPS_32) { return arcompact_handle05_2f_0x_helper_dasm(DASM_PARAMS, "NEGSW"); } +int arcompact_handle05_2f_07_dasm(DASM_OPS_32) { return arcompact_handle05_2f_0x_helper_dasm(DASM_PARAMS, "NEGS"); } +int arcompact_handle05_2f_08_dasm(DASM_OPS_32) { return arcompact_handle05_2f_0x_helper_dasm(DASM_PARAMS, "NORMW"); } + + +int arcompact_handle06_dasm(DASM_OPS_32) +{ + print("op a,b,c (06 ARC ext) (%08x)", op ); + return 4; +} + +int arcompact_handle07_dasm(DASM_OPS_32) +{ + print("op a,b,c (07 User ext) (%08x)", op ); + return 4; +} + +int arcompact_handle08_dasm(DASM_OPS_32) +{ + print("op a,b,c (08 User ext) (%08x)", op ); + return 4; +} + +int arcompact_handle09_dasm(DASM_OPS_32) +{ + print("op a,b,c (09 Market ext) (%08x)", op ); + return 4; +} + +int arcompact_handle0a_dasm(DASM_OPS_32) +{ + print("op a,b,c (0a Market ext) (%08x)", op ); + return 4; +} + +int arcompact_handle0b_dasm(DASM_OPS_32) +{ + print("op a,b,c (0b Market ext) (%08x)", op ); + return 4; +} + + + +int arcompact_handle0c_helper_dasm(DASM_OPS_16, const char* optext, int format) +{ + int areg, breg, creg; + + COMMON16_GET_areg; + COMMON16_GET_breg; + COMMON16_GET_creg; + + REG_16BIT_RANGE(areg); + REG_16BIT_RANGE(breg); + REG_16BIT_RANGE(creg); + + + if (format==0) print("%s %s <- [%s, %s]", optext, regnames[areg], regnames[breg], regnames[creg]); + else print("%s %s <- %s, %s", optext, regnames[areg], regnames[breg], regnames[creg]); + + return 2; +} + + +int arcompact_handle0c_00_dasm(DASM_OPS_16) +{ + return arcompact_handle0c_helper_dasm(DASM_PARAMS, "LD_S", 0); +} + +int arcompact_handle0c_01_dasm(DASM_OPS_16) +{ + return arcompact_handle0c_helper_dasm(DASM_PARAMS, "LDB_S", 0); +} + +int arcompact_handle0c_02_dasm(DASM_OPS_16) +{ + return arcompact_handle0c_helper_dasm(DASM_PARAMS, "LDW_S", 0); +} + +int arcompact_handle0c_03_dasm(DASM_OPS_16) +{ + return arcompact_handle0c_helper_dasm(DASM_PARAMS, "ADD_S", 1); +} + + +int arcompact_handle0d_helper_dasm(DASM_OPS_16, const char* optext) +{ + int u, breg, creg; + + COMMON16_GET_u3; + COMMON16_GET_breg; + COMMON16_GET_creg; + + REG_16BIT_RANGE(breg); + REG_16BIT_RANGE(creg); + + print("%s %s <- [%s, 0x%02x]", optext, regnames[creg], regnames[breg], u); + return 2; +} + + +int arcompact_handle0d_00_dasm(DASM_OPS_16) +{ + return arcompact_handle0d_helper_dasm(DASM_PARAMS, "ADD_S"); +} + +int arcompact_handle0d_01_dasm(DASM_OPS_16) +{ + return arcompact_handle0d_helper_dasm(DASM_PARAMS, "SUB_S"); +} + +int arcompact_handle0d_02_dasm(DASM_OPS_16) +{ + return arcompact_handle0d_helper_dasm(DASM_PARAMS, "ASL_S"); +} + +int arcompact_handle0d_03_dasm(DASM_OPS_16) +{ + return arcompact_handle0d_helper_dasm(DASM_PARAMS, "ASR_S"); +} + + + +int arcompact_handle0e_0x_helper_dasm(DASM_OPS_16, const char* optext, int revop) +{ + int h,breg; + int size = 2; + + GROUP_0e_GET_h; + COMMON16_GET_breg; + REG_16BIT_RANGE(breg); + + if (h == LIMM_REG) + { + UINT32 limm; + GET_LIMM; + size = 6; + if (!revop) print("%s %s <- 0x%08x", optext, regnames[breg], limm); + else print("%s 0x%08x <- %s", optext, limm, regnames[breg]); + } + else + { + if (!revop) print("%s %s <- %s", optext, regnames[breg], regnames[h]); + else print("%s %s <- %s", optext, regnames[h], regnames[breg]); + + } + + return size; + +} + +int arcompact_handle0e_00_dasm(DASM_OPS_16) +{ + return arcompact_handle0e_0x_helper_dasm(DASM_PARAMS, "ADD_S", 0); +} + +int arcompact_handle0e_01_dasm(DASM_OPS_16) +{ + return arcompact_handle0e_0x_helper_dasm(DASM_PARAMS, "MOV_S", 0); +} + +int arcompact_handle0e_02_dasm(DASM_OPS_16) +{ + return arcompact_handle0e_0x_helper_dasm(DASM_PARAMS, "CMP_S", 0); +} + +int arcompact_handle0e_03_dasm(DASM_OPS_16) +{ + return arcompact_handle0e_0x_helper_dasm(DASM_PARAMS, "MOV_S", 1); +} + + + +int arcompact_handle0f_00_0x_helper_dasm(DASM_OPS_16, const char* optext) +{ + int breg; + + COMMON16_GET_breg; + REG_16BIT_RANGE(breg); + + print("%s %s", optext, regnames[breg]); + + return 2; + +} + + + +int arcompact_handle0f_00_00_dasm(DASM_OPS_16) { return arcompact_handle0f_00_0x_helper_dasm(DASM_PARAMS, "J_S"); } +int arcompact_handle0f_00_01_dasm(DASM_OPS_16) { return arcompact_handle0f_00_0x_helper_dasm(DASM_PARAMS, "J_S.D"); } +int arcompact_handle0f_00_02_dasm(DASM_OPS_16) { return arcompact_handle0f_00_0x_helper_dasm(DASM_PARAMS, "JL_S"); } +int arcompact_handle0f_00_03_dasm(DASM_OPS_16) { return arcompact_handle0f_00_0x_helper_dasm(DASM_PARAMS, "JL_S.D"); } +int arcompact_handle0f_00_06_dasm(DASM_OPS_16) { return arcompact_handle0f_00_0x_helper_dasm(DASM_PARAMS, "SUB_S.NE"); } + + + + +// Zero parameters (ZOP) +int arcompact_handle0f_00_07_00_dasm(DASM_OPS_16) { print("NOP_S"); return 2;} +int arcompact_handle0f_00_07_01_dasm(DASM_OPS_16) { print("UNIMP_S"); return 2;} // Unimplemented Instruction, same as illegal, but recommended to fill blank space +int arcompact_handle0f_00_07_04_dasm(DASM_OPS_16) { print("JEQ_S [blink]"); return 2;} +int arcompact_handle0f_00_07_05_dasm(DASM_OPS_16) { print("JNE_S [blink]"); return 2;} +int arcompact_handle0f_00_07_06_dasm(DASM_OPS_16) { print("J_S [blink]"); return 2;} +int arcompact_handle0f_00_07_07_dasm(DASM_OPS_16) { print("J_S.D [blink]"); return 2;} + + + + + +int arcompact_handle0f_0x_helper_dasm(DASM_OPS_16, const char* optext, int nodst) +{ + int breg, creg; + + COMMON16_GET_breg; + COMMON16_GET_creg; + + REG_16BIT_RANGE(breg); + REG_16BIT_RANGE(creg); + + if (nodst==0) print("%s %s <- %s", optext, regnames[breg], regnames[creg]); + else if (nodst==1) print("%s , %s, %s", optext, regnames[breg], regnames[creg]); + else if (nodst==2) print("%s , %s, %s", optext, regnames[breg], regnames[creg]); + + return 2; +} + +int arcompact_handle0f_02_dasm(DASM_OPS_16) { return arcompact_handle0f_0x_helper_dasm(DASM_PARAMS, "SUB_S",0); } +int arcompact_handle0f_04_dasm(DASM_OPS_16) { return arcompact_handle0f_0x_helper_dasm(DASM_PARAMS, "AND_S",0); } +int arcompact_handle0f_05_dasm(DASM_OPS_16) { return arcompact_handle0f_0x_helper_dasm(DASM_PARAMS, "OR_S",0); } +int arcompact_handle0f_06_dasm(DASM_OPS_16) { return arcompact_handle0f_0x_helper_dasm(DASM_PARAMS, "BIC_S",0); } +int arcompact_handle0f_07_dasm(DASM_OPS_16) { return arcompact_handle0f_0x_helper_dasm(DASM_PARAMS, "XOR_S",0); } +int arcompact_handle0f_0b_dasm(DASM_OPS_16) { return arcompact_handle0f_0x_helper_dasm(DASM_PARAMS, "TST_S",1); } +int arcompact_handle0f_0c_dasm(DASM_OPS_16) { return arcompact_handle0f_0x_helper_dasm(DASM_PARAMS, "MUL64_S",2); } // actual destination is special multiply registers +int arcompact_handle0f_0d_dasm(DASM_OPS_16) { return arcompact_handle0f_0x_helper_dasm(DASM_PARAMS, "SEXB_S",0); } +int arcompact_handle0f_0e_dasm(DASM_OPS_16) { return arcompact_handle0f_0x_helper_dasm(DASM_PARAMS, "SEXW_S",0); } +int arcompact_handle0f_0f_dasm(DASM_OPS_16) { return arcompact_handle0f_0x_helper_dasm(DASM_PARAMS, "EXTB_S",0); } +int arcompact_handle0f_10_dasm(DASM_OPS_16) { return arcompact_handle0f_0x_helper_dasm(DASM_PARAMS, "EXTW_S",0); } +int arcompact_handle0f_11_dasm(DASM_OPS_16) { return arcompact_handle0f_0x_helper_dasm(DASM_PARAMS, "ABS_S",0); } +int arcompact_handle0f_12_dasm(DASM_OPS_16) { return arcompact_handle0f_0x_helper_dasm(DASM_PARAMS, "NOT_S",0); } +int arcompact_handle0f_13_dasm(DASM_OPS_16) { return arcompact_handle0f_0x_helper_dasm(DASM_PARAMS, "NEG_S",0); } +int arcompact_handle0f_14_dasm(DASM_OPS_16) { return arcompact_handle0f_0x_helper_dasm(DASM_PARAMS, "ADD1_S",0); } +int arcompact_handle0f_15_dasm(DASM_OPS_16) { return arcompact_handle0f_0x_helper_dasm(DASM_PARAMS, "ADD2_S",0); } +int arcompact_handle0f_16_dasm(DASM_OPS_16) { return arcompact_handle0f_0x_helper_dasm(DASM_PARAMS, "ADD3_S",0); } +int arcompact_handle0f_18_dasm(DASM_OPS_16) { return arcompact_handle0f_0x_helper_dasm(DASM_PARAMS, "ASL_S",0); } +int arcompact_handle0f_19_dasm(DASM_OPS_16) { return arcompact_handle0f_0x_helper_dasm(DASM_PARAMS, "LSR_S",0); } +int arcompact_handle0f_1a_dasm(DASM_OPS_16) { return arcompact_handle0f_0x_helper_dasm(DASM_PARAMS, "ASR_S",0); } +int arcompact_handle0f_1b_dasm(DASM_OPS_16) { return arcompact_handle0f_0x_helper_dasm(DASM_PARAMS, "ASL1_S",0); } +int arcompact_handle0f_1c_dasm(DASM_OPS_16) { return arcompact_handle0f_0x_helper_dasm(DASM_PARAMS, "ASR1_S",0); } +int arcompact_handle0f_1d_dasm(DASM_OPS_16) { return arcompact_handle0f_0x_helper_dasm(DASM_PARAMS, "LSR1_S",0); } + + +int arcompact_handle0f_1e_dasm(DASM_OPS_16) // special +{ // 0111 1uuu uuu1 1110 + int u = (op & 0x07e0)>>5; + print("TRAP_S %02x",u); + return 2; +} + +int arcompact_handle0f_1f_dasm(DASM_OPS_16) // special +{ + int u = (op & 0x07e0)>>5; op &= ~0x07e0; + + if (u == 0x003f) + { + print("BRK_S"); + } + else + { + print("",u); + } + return 2; +} + + +int arcompact_handle_ld_helper_dasm(DASM_OPS_16, const char* optext, int shift, int swap) +{ + int breg, creg, u; + + COMMON16_GET_breg; + COMMON16_GET_creg; + COMMON16_GET_u5; + + REG_16BIT_RANGE(breg); + REG_16BIT_RANGE(creg); + + u <<= shift; + + if (!swap) print("%s %s, [%s, 0x%02x] (%04x)", optext, regnames[creg], regnames[breg], u, op); + else print("%s [%s, 0x%02x], %s (%04x)", optext, regnames[breg], u, regnames[creg], op); + return 2; + +} + + +int arcompact_handle10_dasm(DASM_OPS_16) +{ + return arcompact_handle_ld_helper_dasm(DASM_PARAMS, "LD_S", 2, 0); +} + +int arcompact_handle11_dasm(DASM_OPS_16) +{ + return arcompact_handle_ld_helper_dasm(DASM_PARAMS, "LDB_S", 0, 0); +} + +int arcompact_handle12_dasm(DASM_OPS_16) +{ + return arcompact_handle_ld_helper_dasm(DASM_PARAMS, "LDW_S", 1, 0); +} + +int arcompact_handle13_dasm(DASM_OPS_16) +{ + return arcompact_handle_ld_helper_dasm(DASM_PARAMS, "LDW_S.X", 1, 0); +} + +int arcompact_handle14_dasm(DASM_OPS_16) +{ + return arcompact_handle_ld_helper_dasm(DASM_PARAMS, "ST_S", 2, 1); +} + +int arcompact_handle15_dasm(DASM_OPS_16) +{ + return arcompact_handle_ld_helper_dasm(DASM_PARAMS, "STB_S", 0, 1); +} + +int arcompact_handle16_dasm(DASM_OPS_16) +{ + return arcompact_handle_ld_helper_dasm(DASM_PARAMS, "STW_S", 1, 1); +} + + +int arcompact_handle_l7_0x_helper_dasm(DASM_OPS_16, const char* optext) +{ + int breg, u; + + COMMON16_GET_breg; + COMMON16_GET_u5; + + REG_16BIT_RANGE(breg); + + print("%s %s, 0x%02x", optext, regnames[breg], u); + + return 2; + +} + +int arcompact_handle17_00_dasm(DASM_OPS_16) +{ + return arcompact_handle_l7_0x_helper_dasm(DASM_PARAMS, "ASL_S"); +} + +int arcompact_handle17_01_dasm(DASM_OPS_16) +{ + return arcompact_handle_l7_0x_helper_dasm(DASM_PARAMS, "LSR_S"); +} + +int arcompact_handle17_02_dasm(DASM_OPS_16) +{ + return arcompact_handle_l7_0x_helper_dasm(DASM_PARAMS, "ASR_S"); +} + +int arcompact_handle17_03_dasm(DASM_OPS_16) +{ + return arcompact_handle_l7_0x_helper_dasm(DASM_PARAMS, "SUB_S"); +} + +int arcompact_handle17_04_dasm(DASM_OPS_16) +{ + return arcompact_handle_l7_0x_helper_dasm(DASM_PARAMS, "BSET_S"); +} + +int arcompact_handle17_05_dasm(DASM_OPS_16) +{ + return arcompact_handle_l7_0x_helper_dasm(DASM_PARAMS, "BCLR_S"); +} + +int arcompact_handle17_06_dasm(DASM_OPS_16) +{ + return arcompact_handle_l7_0x_helper_dasm(DASM_PARAMS, "BSMK_S"); +} + +int arcompact_handle17_07_dasm(DASM_OPS_16) +{ + return arcompact_handle_l7_0x_helper_dasm(DASM_PARAMS, "BTST_S"); +} + + +// op bits remaining for 0x18_xx subgroups 0x071f + +int arcompact_handle18_0x_helper_dasm(DASM_OPS_16, const char* optext, int st, int format) +{ + int breg, u; + + COMMON16_GET_breg; + COMMON16_GET_u5; + + REG_16BIT_RANGE(breg); + + output += sprintf( output, "%s %s ", optext, regnames[breg]); + if (st==1) output += sprintf( output, "-> "); + else output += sprintf( output, "<- "); + + if (format==0) output += sprintf( output, "[SP, 0x%02x]", u*4); + else output += sprintf( output, "SP, 0x%02x", u*4); + + + return 2; +} + +int arcompact_handle18_00_dasm(DASM_OPS_16) +{ + return arcompact_handle18_0x_helper_dasm(DASM_PARAMS, "LD_S", 0,0); +} + +int arcompact_handle18_01_dasm(DASM_OPS_16) +{ + return arcompact_handle18_0x_helper_dasm(DASM_PARAMS, "LDB_S", 0,0); +} + +int arcompact_handle18_02_dasm(DASM_OPS_16) +{ + return arcompact_handle18_0x_helper_dasm(DASM_PARAMS, "ST_S", 1,0); +} + +int arcompact_handle18_03_dasm(DASM_OPS_16) +{ + return arcompact_handle18_0x_helper_dasm(DASM_PARAMS, "STB_S", 1,0); +} + +int arcompact_handle18_04_dasm(DASM_OPS_16) +{ + return arcompact_handle18_0x_helper_dasm(DASM_PARAMS, "ADD_S", 1,1); // check format +} + +// op bits remaining for 0x18_05_xx subgroups 0x001f +int arcompact_handle18_05_00_dasm(DASM_OPS_16) +{ + int u; + COMMON16_GET_u5; + + print("ADD_S SP, SP, 0x%02x", u*4); + return 2; + +} + +int arcompact_handle18_05_01_dasm(DASM_OPS_16) +{ + int u; + COMMON16_GET_u5; + + print("SUB_S SP, SP, 0x%02x", u*4); + return 2; +} + +// op bits remaining for 0x18_06_xx subgroups 0x0700 +int arcompact_handle18_06_01_dasm(DASM_OPS_16) +{ + int breg; + COMMON16_GET_breg + REG_16BIT_RANGE(breg) + + print("POP_S %s", regnames[breg]); + + return 2; +} + +int arcompact_handle18_06_11_dasm(DASM_OPS_16) +{ + int res = (op & 0x0700) >> 8; + op &= ~0x0700; // all bits now used + + if (res) + print("POP_S [BLINK] (Reserved Bits set %04x)", op); + else + print("POP_S [BLINK]"); + + return 2; +} + +// op bits remaining for 0x18_07_xx subgroups 0x0700 +int arcompact_handle18_07_01_dasm(DASM_OPS_16) +{ + int breg; + COMMON16_GET_breg + REG_16BIT_RANGE(breg) + + print("PUSH_S %s", regnames[breg]); + + return 2; +} + + +int arcompact_handle18_07_11_dasm(DASM_OPS_16) +{ + int res = (op & 0x0700) >> 8; + op &= ~0x0700; // all bits now used + + if (res) + print("PUSH_S [BLINK] (Reserved Bits set %04x)", op); + else + print("PUSH_S [BLINK]"); + + return 2; +} + + +int arcompact_handle19_0x_helper_dasm(DASM_OPS_16, const char* optext, int shift, int format) +{ + int s; + + COMMON16_GET_s9; + // todo, signed + s <<= shift; + + + output += sprintf( output, "%s %s, ", optext, regnames[0]); + if (format == 0) + { + output += sprintf( output, "[GP, %03x]", s); + } + else + { + output += sprintf( output, "GP, %03x", s); + } + + return 2; +} + +int arcompact_handle19_00_dasm(DASM_OPS_16) { return arcompact_handle19_0x_helper_dasm(DASM_PARAMS, "LD_S", 2, 0); } +int arcompact_handle19_01_dasm(DASM_OPS_16) { return arcompact_handle19_0x_helper_dasm(DASM_PARAMS, "LDB_S", 0, 0); } +int arcompact_handle19_02_dasm(DASM_OPS_16) { return arcompact_handle19_0x_helper_dasm(DASM_PARAMS, "LDW_S", 1, 0); } +int arcompact_handle19_03_dasm(DASM_OPS_16) { return arcompact_handle19_0x_helper_dasm(DASM_PARAMS, "ADD_S", 2, 1); } + +int arcompact_handle1a_dasm(DASM_OPS_16) +{ + int breg, u; + COMMON16_GET_breg; + COMMON16_GET_u8; + REG_16BIT_RANGE(breg); + + print("MOV_S %s, [PCL, %03x]", regnames[breg], u*4); + + return 2; +} + +int arcompact_handle1b_dasm(DASM_OPS_16) +{ + int breg, u; + COMMON16_GET_breg; + COMMON16_GET_u8; + REG_16BIT_RANGE(breg); + + print("MOV_S %s <- 0x%02x", regnames[breg], u); + return 2; +} + +int arcompact_handle1c_00_dasm(DASM_OPS_16) +{ + int breg, u; + COMMON16_GET_breg; + COMMON16_GET_u7; + REG_16BIT_RANGE(breg); + + print("ADD_S %s <- %s, %02x", regnames[breg], regnames[breg], u); + return 2; +} + +int arcompact_handle1c_01_dasm(DASM_OPS_16) +{ + int breg, u; + COMMON16_GET_breg; + COMMON16_GET_u7; + REG_16BIT_RANGE(breg); + + print("CMP_S %s, %02x", regnames[breg], u); + return 2; +} + +int arcompact_handle1d_helper_dasm(DASM_OPS_16, const char* optext) +{ + int breg; + COMMON16_GET_breg; + REG_16BIT_RANGE(breg); + + int s = (op & 0x007f) >> 0; op &= ~0x007f; + if (s & 0x40) s = -0x40 + (s & 0x3f); + + print("%s %s, 0 to 0x%08x", optext, regnames[breg], PC_ALIGNED32 + s*2); + return 2; +} + + +int arcompact_handle1d_00_dasm(DASM_OPS_16) { return arcompact_handle1d_helper_dasm(DASM_PARAMS,"BREQ_S"); } +int arcompact_handle1d_01_dasm(DASM_OPS_16) { return arcompact_handle1d_helper_dasm(DASM_PARAMS,"BRNE_S"); } + + +int arcompact_handle1e_0x_helper_dasm(DASM_OPS_16, const char* optext) +{ + int s = (op & 0x01ff) >> 0; op &= ~0x01ff; + if (s & 0x100) s = -0x100 + (s & 0xff); + + print("%s %08x", optext, PC_ALIGNED32 + s*2); + return 2; +} + + + +int arcompact_handle1e_00_dasm(DASM_OPS_16) { return arcompact_handle1e_0x_helper_dasm(DASM_PARAMS, "B_S"); } +int arcompact_handle1e_01_dasm(DASM_OPS_16) { return arcompact_handle1e_0x_helper_dasm(DASM_PARAMS, "BEQ_S"); } +int arcompact_handle1e_02_dasm(DASM_OPS_16) { return arcompact_handle1e_0x_helper_dasm(DASM_PARAMS, "BNE_S"); } + +int arcompact_handle1e_03_0x_helper_dasm(DASM_OPS_16, const char* optext) +{ + int s = (op & 0x003f) >> 0; op &= ~0x003f; + if (s & 0x020) s = -0x20 + (s & 0x1f); + + print("%s %08x", optext, PC_ALIGNED32 + s*2); + return 2; +} + +int arcompact_handle1e_03_00_dasm(DASM_OPS_16) { return arcompact_handle1e_03_0x_helper_dasm(DASM_PARAMS, "BGT_S"); } +int arcompact_handle1e_03_01_dasm(DASM_OPS_16) { return arcompact_handle1e_03_0x_helper_dasm(DASM_PARAMS, "BGE_S"); } +int arcompact_handle1e_03_02_dasm(DASM_OPS_16) { return arcompact_handle1e_03_0x_helper_dasm(DASM_PARAMS, "BLT_S"); } +int arcompact_handle1e_03_03_dasm(DASM_OPS_16) { return arcompact_handle1e_03_0x_helper_dasm(DASM_PARAMS, "BLE_S"); } +int arcompact_handle1e_03_04_dasm(DASM_OPS_16) { return arcompact_handle1e_03_0x_helper_dasm(DASM_PARAMS, "BHI_S"); } +int arcompact_handle1e_03_05_dasm(DASM_OPS_16) { return arcompact_handle1e_03_0x_helper_dasm(DASM_PARAMS, "BHS_S"); } +int arcompact_handle1e_03_06_dasm(DASM_OPS_16) { return arcompact_handle1e_03_0x_helper_dasm(DASM_PARAMS, "BLO_S"); } +int arcompact_handle1e_03_07_dasm(DASM_OPS_16) { return arcompact_handle1e_03_0x_helper_dasm(DASM_PARAMS, "BLS_S"); } + +int arcompact_handle1f_dasm(DASM_OPS_16) +{ + int s = (op & 0x07ff) >> 0; op &= ~0x07ff; + if (s & 0x400) s = -0x400 + (s & 0x3ff); + + print("BL_S %08x", PC_ALIGNED32 + (s*4)); + return 2; +} + +/************************************************************************************************************************************ +* * +* illegal opcode handlers (disassembly) * +* * +************************************************************************************************************************************/ + +int arcompact_handle01_01_00_06_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4; } +int arcompact_handle01_01_00_07_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4; } +int arcompact_handle01_01_00_08_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4; } +int arcompact_handle01_01_00_09_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4; } +int arcompact_handle01_01_00_0a_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4; } +int arcompact_handle01_01_00_0b_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4; } +int arcompact_handle01_01_00_0c_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4; } +int arcompact_handle01_01_00_0d_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4; } + +int arcompact_handle01_01_01_06_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4; } +int arcompact_handle01_01_01_07_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4; } +int arcompact_handle01_01_01_08_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4; } +int arcompact_handle01_01_01_09_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4; } +int arcompact_handle01_01_01_0a_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4; } +int arcompact_handle01_01_01_0b_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4; } +int arcompact_handle01_01_01_0c_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4; } +int arcompact_handle01_01_01_0d_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4; } + + +int arcompact_handle04_1e_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_1f_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} + +int arcompact_handle04_24_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_25_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_26_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_27_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} + +int arcompact_handle04_2c_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2d_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2e_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} + +int arcompact_handle04_2f_0d_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_0e_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_0f_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_10_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_11_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_12_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_13_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_14_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_15_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_16_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_17_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_18_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_19_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_1a_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_1b_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_1c_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_1d_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_1e_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_1f_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_20_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_21_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_22_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_23_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_24_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_25_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_26_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_27_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_28_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_29_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_2a_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_2b_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_2c_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_2d_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_2e_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_2f_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_30_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_31_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_32_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_33_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_34_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_35_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_36_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_37_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_38_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_39_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_3a_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_3b_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_3c_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_3d_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_3e_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} + + + +int arcompact_handle05_2f_09_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_0a_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_0b_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_0c_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_0d_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_0e_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_0f_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_10_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_11_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_12_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_13_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_14_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_15_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_16_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_17_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_18_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_19_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_1a_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_1b_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_1c_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_1d_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_1e_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_1f_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_20_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_21_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_22_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_23_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_24_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_25_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_26_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_27_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_28_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_29_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_2a_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_2b_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_2c_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_2d_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_2e_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_2f_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_30_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_31_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_32_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_33_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_34_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_35_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_36_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_37_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_38_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_39_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_3a_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_3b_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_3c_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_3d_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_3e_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} + + +int arcompact_handle04_2f_3f_00_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_3f_06_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_3f_07_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_3f_08_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_3f_09_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_3f_0a_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_3f_0b_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_3f_0c_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_3f_0d_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_3f_0e_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_3f_0f_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_3f_10_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_3f_11_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_3f_12_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_3f_13_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_3f_14_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_3f_15_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_3f_16_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_3f_17_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_3f_18_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_3f_19_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_3f_1a_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_3f_1b_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_3f_1c_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_3f_1d_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_3f_1e_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_3f_1f_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_3f_20_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_3f_21_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_3f_22_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_3f_23_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_3f_24_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_3f_25_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_3f_26_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_3f_27_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_3f_28_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_3f_29_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_3f_2a_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_3f_2b_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_3f_2c_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_3f_2d_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_3f_2e_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_3f_2f_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_3f_30_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_3f_31_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_3f_32_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_3f_33_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_3f_34_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_3f_35_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_3f_36_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_3f_37_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_3f_38_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_3f_39_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_3f_3a_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_3f_3b_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_3f_3c_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_3f_3d_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_3f_3e_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_2f_3f_3f_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} + +int arcompact_handle05_2f_3f_00_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_3f_01_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_3f_02_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_3f_03_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_3f_04_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_3f_05_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_3f_06_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_3f_07_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_3f_08_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_3f_09_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_3f_0a_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_3f_0b_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_3f_0c_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_3f_0d_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_3f_0e_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_3f_0f_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_3f_10_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_3f_11_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_3f_12_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_3f_13_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_3f_14_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_3f_15_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_3f_16_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_3f_17_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_3f_18_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_3f_19_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_3f_1a_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_3f_1b_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_3f_1c_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_3f_1d_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_3f_1e_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_3f_1f_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_3f_20_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_3f_21_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_3f_22_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_3f_23_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_3f_24_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_3f_25_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_3f_26_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_3f_27_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_3f_28_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_3f_29_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_3f_2a_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_3f_2b_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_3f_2c_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_3f_2d_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_3f_2e_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_3f_2f_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_3f_30_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_3f_31_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_3f_32_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_3f_33_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_3f_34_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_3f_35_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_3f_36_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_3f_37_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_3f_38_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_3f_39_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_3f_3a_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_3f_3b_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_3f_3c_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_3f_3d_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_3f_3e_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2f_3f_3f_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} + + + + +int arcompact_handle04_38_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_39_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_3a_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_3b_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_3c_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_3d_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_3e_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle04_3f_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} + + +int arcompact_handle05_09_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_0c_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_0d_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_0e_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_0f_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_10_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_11_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_12_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_13_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_14_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_15_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_16_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_17_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_18_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_19_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_1a_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_1b_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_1c_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_1d_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_1e_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_1f_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_20_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_21_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_22_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_23_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_24_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_25_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_26_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_27_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} + +int arcompact_handle05_2a_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2b_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2c_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2d_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_2e_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} + +int arcompact_handle05_30_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_31_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_32_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_33_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_34_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_35_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_36_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_37_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_38_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_39_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_3a_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_3b_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_3c_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_3d_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_3e_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} +int arcompact_handle05_3f_dasm(DASM_OPS_32) { print(" (%08x)", op); return 4;} + +int arcompact_handle0f_00_04_dasm(DASM_OPS_16) { print(" (%08x)", op); return 2;} +int arcompact_handle0f_00_05_dasm(DASM_OPS_16) { print(" (%08x)", op); return 2;} +int arcompact_handle0f_00_07_02_dasm(DASM_OPS_16) { print(" (%08x)", op); return 2;} +int arcompact_handle0f_00_07_03_dasm(DASM_OPS_16) { print(" (%08x)", op); return 2;} +int arcompact_handle0f_01_dasm(DASM_OPS_16) { print(" (%08x)", op); return 2;} +int arcompact_handle0f_03_dasm(DASM_OPS_16) { print(" (%08x)", op); return 2;} +int arcompact_handle0f_08_dasm(DASM_OPS_16) { print(" (%08x)", op); return 2;} +int arcompact_handle0f_09_dasm(DASM_OPS_16) { print(" (%08x)", op); return 2;} +int arcompact_handle0f_0a_dasm(DASM_OPS_16) { print(" (%08x)", op); return 2;} +int arcompact_handle0f_17_dasm(DASM_OPS_16) { print(" (%08x)", op); return 2;} + +int arcompact_handle18_05_02_dasm(DASM_OPS_16) { print(" (%04x)", op); return 2;} +int arcompact_handle18_05_03_dasm(DASM_OPS_16) { print(" (%04x)", op); return 2;} +int arcompact_handle18_05_04_dasm(DASM_OPS_16) { print(" (%04x)", op); return 2;} +int arcompact_handle18_05_05_dasm(DASM_OPS_16) { print(" (%04x)", op); return 2;} +int arcompact_handle18_05_06_dasm(DASM_OPS_16) { print(" (%04x)", op); return 2;} +int arcompact_handle18_05_07_dasm(DASM_OPS_16) { print(" (%04x)", op); return 2;} +int arcompact_handle18_06_00_dasm(DASM_OPS_16) { print(" (%04x)", op); return 2;} +int arcompact_handle18_06_02_dasm(DASM_OPS_16) { print(" (%04x)", op); return 2;} +int arcompact_handle18_06_03_dasm(DASM_OPS_16) { print(" (%04x)", op); return 2;} +int arcompact_handle18_06_04_dasm(DASM_OPS_16) { print(" (%04x)", op); return 2;} +int arcompact_handle18_06_05_dasm(DASM_OPS_16) { print(" (%04x)", op); return 2;} +int arcompact_handle18_06_06_dasm(DASM_OPS_16) { print(" (%04x)", op); return 2;} +int arcompact_handle18_06_07_dasm(DASM_OPS_16) { print(" (%04x)", op); return 2;} +int arcompact_handle18_06_08_dasm(DASM_OPS_16) { print(" (%04x)", op); return 2;} +int arcompact_handle18_06_09_dasm(DASM_OPS_16) { print(" (%04x)", op); return 2;} +int arcompact_handle18_06_0a_dasm(DASM_OPS_16) { print(" (%04x)", op); return 2;} +int arcompact_handle18_06_0b_dasm(DASM_OPS_16) { print(" (%04x)", op); return 2;} +int arcompact_handle18_06_0c_dasm(DASM_OPS_16) { print(" (%04x)", op); return 2;} +int arcompact_handle18_06_0d_dasm(DASM_OPS_16) { print(" (%04x)", op); return 2;} +int arcompact_handle18_06_0e_dasm(DASM_OPS_16) { print(" (%04x)", op); return 2;} +int arcompact_handle18_06_0f_dasm(DASM_OPS_16) { print(" (%04x)", op); return 2;} +int arcompact_handle18_06_10_dasm(DASM_OPS_16) { print(" (%04x)", op); return 2;} +int arcompact_handle18_06_12_dasm(DASM_OPS_16) { print(" (%04x)", op); return 2;} +int arcompact_handle18_06_13_dasm(DASM_OPS_16) { print(" (%04x)", op); return 2;} +int arcompact_handle18_06_14_dasm(DASM_OPS_16) { print(" (%04x)", op); return 2;} +int arcompact_handle18_06_15_dasm(DASM_OPS_16) { print(" (%04x)", op); return 2;} +int arcompact_handle18_06_16_dasm(DASM_OPS_16) { print(" (%04x)", op); return 2;} +int arcompact_handle18_06_17_dasm(DASM_OPS_16) { print(" (%04x)", op); return 2;} +int arcompact_handle18_06_18_dasm(DASM_OPS_16) { print(" (%04x)", op); return 2;} +int arcompact_handle18_06_19_dasm(DASM_OPS_16) { print(" (%04x)", op); return 2;} +int arcompact_handle18_06_1a_dasm(DASM_OPS_16) { print(" (%04x)", op); return 2;} +int arcompact_handle18_06_1b_dasm(DASM_OPS_16) { print(" (%04x)", op); return 2;} +int arcompact_handle18_06_1c_dasm(DASM_OPS_16) { print(" (%04x)", op); return 2;} +int arcompact_handle18_06_1d_dasm(DASM_OPS_16) { print(" (%04x)", op); return 2;} +int arcompact_handle18_06_1e_dasm(DASM_OPS_16) { print(" (%04x)", op); return 2;} +int arcompact_handle18_06_1f_dasm(DASM_OPS_16) { print(" (%04x)", op); return 2;} +int arcompact_handle18_07_00_dasm(DASM_OPS_16) { print(" (%04x)", op); return 2;} +int arcompact_handle18_07_02_dasm(DASM_OPS_16) { print(" (%04x)", op); return 2;} +int arcompact_handle18_07_03_dasm(DASM_OPS_16) { print(" (%04x)", op); return 2;} +int arcompact_handle18_07_04_dasm(DASM_OPS_16) { print(" (%04x)", op); return 2;} +int arcompact_handle18_07_05_dasm(DASM_OPS_16) { print(" (%04x)", op); return 2;} +int arcompact_handle18_07_06_dasm(DASM_OPS_16) { print(" (%04x)", op); return 2;} +int arcompact_handle18_07_07_dasm(DASM_OPS_16) { print(" (%04x)", op); return 2;} +int arcompact_handle18_07_08_dasm(DASM_OPS_16) { print(" (%04x)", op); return 2;} +int arcompact_handle18_07_09_dasm(DASM_OPS_16) { print(" (%04x)", op); return 2;} +int arcompact_handle18_07_0a_dasm(DASM_OPS_16) { print(" (%04x)", op); return 2;} +int arcompact_handle18_07_0b_dasm(DASM_OPS_16) { print(" (%04x)", op); return 2;} +int arcompact_handle18_07_0c_dasm(DASM_OPS_16) { print(" (%04x)", op); return 2;} +int arcompact_handle18_07_0d_dasm(DASM_OPS_16) { print(" (%04x)", op); return 2;} +int arcompact_handle18_07_0e_dasm(DASM_OPS_16) { print(" (%04x)", op); return 2;} +int arcompact_handle18_07_0f_dasm(DASM_OPS_16) { print(" (%04x)", op); return 2;} +int arcompact_handle18_07_10_dasm(DASM_OPS_16) { print(" (%04x)", op); return 2;} +int arcompact_handle18_07_12_dasm(DASM_OPS_16) { print(" (%04x)", op); return 2;} +int arcompact_handle18_07_13_dasm(DASM_OPS_16) { print(" (%04x)", op); return 2;} +int arcompact_handle18_07_14_dasm(DASM_OPS_16) { print(" (%04x)", op); return 2;} +int arcompact_handle18_07_15_dasm(DASM_OPS_16) { print(" (%04x)", op); return 2;} +int arcompact_handle18_07_16_dasm(DASM_OPS_16) { print(" (%04x)", op); return 2;} +int arcompact_handle18_07_17_dasm(DASM_OPS_16) { print(" (%04x)", op); return 2;} +int arcompact_handle18_07_18_dasm(DASM_OPS_16) { print(" (%04x)", op); return 2;} +int arcompact_handle18_07_19_dasm(DASM_OPS_16) { print(" (%04x)", op); return 2;} +int arcompact_handle18_07_1a_dasm(DASM_OPS_16) { print(" (%04x)", op); return 2;} +int arcompact_handle18_07_1b_dasm(DASM_OPS_16) { print(" (%04x)", op); return 2;} +int arcompact_handle18_07_1c_dasm(DASM_OPS_16) { print(" (%04x)", op); return 2;} +int arcompact_handle18_07_1d_dasm(DASM_OPS_16) { print(" (%04x)", op); return 2;} +int arcompact_handle18_07_1e_dasm(DASM_OPS_16) { print(" (%04x)", op); return 2;} +int arcompact_handle18_07_1f_dasm(DASM_OPS_16) { print(" (%04x)", op); return 2;} diff --git a/src/devices/cpu/arcompact/arcompactdasm_ops.h b/src/devices/cpu/arcompact/arcompactdasm_ops.h new file mode 100644 index 00000000000..a2d09d83441 --- /dev/null +++ b/src/devices/cpu/arcompact/arcompactdasm_ops.h @@ -0,0 +1,642 @@ +// license:BSD-3-Clause +// copyright-holders:David Haywood + +/************************************************************************************************************************************ +* * +* individual opcode handlers (disassembly) * +* * +************************************************************************************************************************************/ + +#include "arcompact_common.h" + +#define DASM_OPS_16 char *output, offs_t pc, UINT16 op, const UINT8* oprom +#define DASM_OPS_32 char *output, offs_t pc, UINT32 op, const UINT8* oprom +#define DASM_PARAMS output, pc, op, oprom + +#define LIMM_REG 62 + +#define GET_LIMM_32 \ + limm = oprom[6] | (oprom[7] << 8); \ + limm |= (oprom[4] << 16) | (oprom[5] << 24); + +int arcompact_handle00_00_dasm(DASM_OPS_32); +int arcompact_handle00_01_dasm(DASM_OPS_32); +int arcompact_handle01_00_00dasm(DASM_OPS_32); +int arcompact_handle01_00_01dasm(DASM_OPS_32); +int arcompact_handle01_01_00_00_dasm(DASM_OPS_32); +int arcompact_handle01_01_00_01_dasm(DASM_OPS_32); +int arcompact_handle01_01_00_02_dasm(DASM_OPS_32); +int arcompact_handle01_01_00_03_dasm(DASM_OPS_32); +int arcompact_handle01_01_00_04_dasm(DASM_OPS_32); +int arcompact_handle01_01_00_05_dasm(DASM_OPS_32); +int arcompact_handle01_01_00_0e_dasm(DASM_OPS_32); +int arcompact_handle01_01_00_0f_dasm(DASM_OPS_32); +int arcompact_handle01_01_01_00_dasm(DASM_OPS_32); +int arcompact_handle01_01_01_01_dasm(DASM_OPS_32); +int arcompact_handle01_01_01_02_dasm(DASM_OPS_32); +int arcompact_handle01_01_01_03_dasm(DASM_OPS_32); +int arcompact_handle01_01_01_04_dasm(DASM_OPS_32); +int arcompact_handle01_01_01_05_dasm(DASM_OPS_32); +int arcompact_handle01_01_01_0e_dasm(DASM_OPS_32); +int arcompact_handle01_01_01_0f_dasm(DASM_OPS_32); +int arcompact_handle02_dasm(DASM_OPS_32); +int arcompact_handle03_dasm(DASM_OPS_32); +int arcompact_handle04_00_dasm(DASM_OPS_32); +int arcompact_handle04_01_dasm(DASM_OPS_32); +int arcompact_handle04_02_dasm(DASM_OPS_32); +int arcompact_handle04_03_dasm(DASM_OPS_32); +int arcompact_handle04_04_dasm(DASM_OPS_32); +int arcompact_handle04_05_dasm(DASM_OPS_32); +int arcompact_handle04_06_dasm(DASM_OPS_32); +int arcompact_handle04_07_dasm(DASM_OPS_32); +int arcompact_handle04_08_dasm(DASM_OPS_32); +int arcompact_handle04_09_dasm(DASM_OPS_32); +int arcompact_handle04_0a_dasm(DASM_OPS_32); +int arcompact_handle04_0b_dasm(DASM_OPS_32); +int arcompact_handle04_0c_dasm(DASM_OPS_32); +int arcompact_handle04_0d_dasm(DASM_OPS_32); +int arcompact_handle04_0e_dasm(DASM_OPS_32); +int arcompact_handle04_0f_dasm(DASM_OPS_32); +int arcompact_handle04_10_dasm(DASM_OPS_32); +int arcompact_handle04_11_dasm(DASM_OPS_32); +int arcompact_handle04_12_dasm(DASM_OPS_32); +int arcompact_handle04_13_dasm(DASM_OPS_32); +int arcompact_handle04_14_dasm(DASM_OPS_32); +int arcompact_handle04_15_dasm(DASM_OPS_32); +int arcompact_handle04_16_dasm(DASM_OPS_32); +int arcompact_handle04_17_dasm(DASM_OPS_32); +int arcompact_handle04_18_dasm(DASM_OPS_32); +int arcompact_handle04_19_dasm(DASM_OPS_32); +int arcompact_handle04_1a_dasm(DASM_OPS_32); +int arcompact_handle04_1b_dasm(DASM_OPS_32); +int arcompact_handle04_1c_dasm(DASM_OPS_32); +int arcompact_handle04_1d_dasm(DASM_OPS_32); +int arcompact_handle04_20_dasm(DASM_OPS_32); +int arcompact_handle04_21_dasm(DASM_OPS_32); +int arcompact_handle04_22_dasm(DASM_OPS_32); +int arcompact_handle04_23_dasm(DASM_OPS_32); +int arcompact_handle04_28_dasm(DASM_OPS_32); +int arcompact_handle04_29_dasm(DASM_OPS_32); +int arcompact_handle04_2a_dasm(DASM_OPS_32); +int arcompact_handle04_2b_dasm(DASM_OPS_32); +int arcompact_handle04_2f_00_dasm(DASM_OPS_32); +int arcompact_handle04_2f_01_dasm(DASM_OPS_32); +int arcompact_handle04_2f_02_dasm(DASM_OPS_32); +int arcompact_handle04_2f_03_dasm(DASM_OPS_32); +int arcompact_handle04_2f_04_dasm(DASM_OPS_32); +int arcompact_handle04_2f_05_dasm(DASM_OPS_32); +int arcompact_handle04_2f_06_dasm(DASM_OPS_32); +int arcompact_handle04_2f_07_dasm(DASM_OPS_32); +int arcompact_handle04_2f_08_dasm(DASM_OPS_32); +int arcompact_handle04_2f_09_dasm(DASM_OPS_32); +int arcompact_handle04_2f_0a_dasm(DASM_OPS_32); +int arcompact_handle04_2f_0b_dasm(DASM_OPS_32); +int arcompact_handle04_2f_0c_dasm(DASM_OPS_32); +int arcompact_handle04_2f_3f_01_dasm(DASM_OPS_32); +int arcompact_handle04_2f_3f_02_dasm(DASM_OPS_32); +int arcompact_handle04_2f_3f_03_dasm(DASM_OPS_32); +int arcompact_handle04_2f_3f_04_dasm(DASM_OPS_32); +int arcompact_handle04_2f_3f_05_dasm(DASM_OPS_32); +int arcompact_handle04_30_dasm(DASM_OPS_32); +int arcompact_handle04_31_dasm(DASM_OPS_32); +int arcompact_handle04_32_dasm(DASM_OPS_32); +int arcompact_handle04_33_dasm(DASM_OPS_32); +int arcompact_handle04_34_dasm(DASM_OPS_32); +int arcompact_handle04_35_dasm(DASM_OPS_32); +int arcompact_handle04_36_dasm(DASM_OPS_32); +int arcompact_handle04_37_dasm(DASM_OPS_32); +int arcompact_handle05_00_dasm(DASM_OPS_32); +int arcompact_handle05_01_dasm(DASM_OPS_32); +int arcompact_handle05_02_dasm(DASM_OPS_32); +int arcompact_handle05_03_dasm(DASM_OPS_32); +int arcompact_handle05_04_dasm(DASM_OPS_32); +int arcompact_handle05_05_dasm(DASM_OPS_32); +int arcompact_handle05_06_dasm(DASM_OPS_32); +int arcompact_handle05_07_dasm(DASM_OPS_32); +int arcompact_handle05_08_dasm(DASM_OPS_32); +int arcompact_handle05_0a_dasm(DASM_OPS_32); +int arcompact_handle05_0b_dasm(DASM_OPS_32); +int arcompact_handle05_28_dasm(DASM_OPS_32); +int arcompact_handle05_29_dasm(DASM_OPS_32); + +int arcompact_handle06_dasm(DASM_OPS_32); +int arcompact_handle07_dasm(DASM_OPS_32); +int arcompact_handle08_dasm(DASM_OPS_32); +int arcompact_handle09_dasm(DASM_OPS_32); +int arcompact_handle0a_dasm(DASM_OPS_32); +int arcompact_handle0b_dasm(DASM_OPS_32); + +int arcompact_handle0c_00_dasm(DASM_OPS_16); +int arcompact_handle0c_01_dasm(DASM_OPS_16); +int arcompact_handle0c_02_dasm(DASM_OPS_16); +int arcompact_handle0c_03_dasm(DASM_OPS_16); +int arcompact_handle0d_00_dasm(DASM_OPS_16); +int arcompact_handle0d_01_dasm(DASM_OPS_16); +int arcompact_handle0d_02_dasm(DASM_OPS_16); +int arcompact_handle0d_03_dasm(DASM_OPS_16); +int arcompact_handle0e_00_dasm(DASM_OPS_16); +int arcompact_handle0e_01_dasm(DASM_OPS_16); +int arcompact_handle0e_02_dasm(DASM_OPS_16); +int arcompact_handle0e_03_dasm(DASM_OPS_16); +int arcompact_handle0f_00_00_dasm(DASM_OPS_16); +int arcompact_handle0f_00_01_dasm(DASM_OPS_16); +int arcompact_handle0f_00_02_dasm(DASM_OPS_16); +int arcompact_handle0f_00_03_dasm(DASM_OPS_16); +int arcompact_handle0f_00_06_dasm(DASM_OPS_16); +int arcompact_handle0f_00_07_00_dasm(DASM_OPS_16); +int arcompact_handle0f_00_07_01_dasm(DASM_OPS_16); +int arcompact_handle0f_00_07_04_dasm(DASM_OPS_16); +int arcompact_handle0f_00_07_05_dasm(DASM_OPS_16); +int arcompact_handle0f_00_07_06_dasm(DASM_OPS_16); +int arcompact_handle0f_00_07_07_dasm(DASM_OPS_16); +int arcompact_handle0f_02_dasm(DASM_OPS_16); +int arcompact_handle0f_04_dasm(DASM_OPS_16); +int arcompact_handle0f_05_dasm(DASM_OPS_16); +int arcompact_handle0f_06_dasm(DASM_OPS_16); +int arcompact_handle0f_07_dasm(DASM_OPS_16); +int arcompact_handle0f_0b_dasm(DASM_OPS_16); +int arcompact_handle0f_0c_dasm(DASM_OPS_16); +int arcompact_handle0f_0d_dasm(DASM_OPS_16); +int arcompact_handle0f_0e_dasm(DASM_OPS_16); +int arcompact_handle0f_0f_dasm(DASM_OPS_16); +int arcompact_handle0f_10_dasm(DASM_OPS_16); +int arcompact_handle0f_11_dasm(DASM_OPS_16); +int arcompact_handle0f_12_dasm(DASM_OPS_16); +int arcompact_handle0f_13_dasm(DASM_OPS_16); +int arcompact_handle0f_14_dasm(DASM_OPS_16); +int arcompact_handle0f_15_dasm(DASM_OPS_16); +int arcompact_handle0f_16_dasm(DASM_OPS_16); +int arcompact_handle0f_18_dasm(DASM_OPS_16); +int arcompact_handle0f_19_dasm(DASM_OPS_16); +int arcompact_handle0f_1a_dasm(DASM_OPS_16); +int arcompact_handle0f_1b_dasm(DASM_OPS_16); +int arcompact_handle0f_1c_dasm(DASM_OPS_16); +int arcompact_handle0f_1d_dasm(DASM_OPS_16); +int arcompact_handle0f_1e_dasm(DASM_OPS_16); +int arcompact_handle0f_1f_dasm(DASM_OPS_16); +int arcompact_handle10_dasm(DASM_OPS_16); +int arcompact_handle11_dasm(DASM_OPS_16); +int arcompact_handle12_dasm(DASM_OPS_16); +int arcompact_handle13_dasm(DASM_OPS_16); +int arcompact_handle14_dasm(DASM_OPS_16); +int arcompact_handle15_dasm(DASM_OPS_16); +int arcompact_handle16_dasm(DASM_OPS_16); +int arcompact_handle17_00_dasm(DASM_OPS_16); +int arcompact_handle17_01_dasm(DASM_OPS_16); +int arcompact_handle17_02_dasm(DASM_OPS_16); +int arcompact_handle17_03_dasm(DASM_OPS_16); +int arcompact_handle17_04_dasm(DASM_OPS_16); +int arcompact_handle17_05_dasm(DASM_OPS_16); +int arcompact_handle17_06_dasm(DASM_OPS_16); +int arcompact_handle17_07_dasm(DASM_OPS_16); +int arcompact_handle18_00_dasm(DASM_OPS_16); +int arcompact_handle18_01_dasm(DASM_OPS_16); +int arcompact_handle18_02_dasm(DASM_OPS_16); +int arcompact_handle18_03_dasm(DASM_OPS_16); +int arcompact_handle18_04_dasm(DASM_OPS_16); +int arcompact_handle18_05_00_dasm(DASM_OPS_16); +int arcompact_handle18_05_01_dasm(DASM_OPS_16); +int arcompact_handle18_06_01_dasm(DASM_OPS_16); +int arcompact_handle18_06_11_dasm(DASM_OPS_16); +int arcompact_handle18_07_01_dasm(DASM_OPS_16); +int arcompact_handle18_07_11_dasm(DASM_OPS_16); +int arcompact_handle19_00_dasm(DASM_OPS_16); +int arcompact_handle19_01_dasm(DASM_OPS_16); +int arcompact_handle19_02_dasm(DASM_OPS_16); +int arcompact_handle19_03_dasm(DASM_OPS_16); +int arcompact_handle1a_dasm(DASM_OPS_16); +int arcompact_handle1b_dasm(DASM_OPS_16); +int arcompact_handle1c_00_dasm(DASM_OPS_16); +int arcompact_handle1c_01_dasm(DASM_OPS_16); +int arcompact_handle1d_00_dasm(DASM_OPS_16); +int arcompact_handle1d_01_dasm(DASM_OPS_16); +int arcompact_handle1e_00_dasm(DASM_OPS_16); +int arcompact_handle1e_01_dasm(DASM_OPS_16); +int arcompact_handle1e_02_dasm(DASM_OPS_16); +int arcompact_handle1e_03_00_dasm(DASM_OPS_16); +int arcompact_handle1e_03_01_dasm(DASM_OPS_16); +int arcompact_handle1e_03_02_dasm(DASM_OPS_16); +int arcompact_handle1e_03_03_dasm(DASM_OPS_16); +int arcompact_handle1e_03_04_dasm(DASM_OPS_16); +int arcompact_handle1e_03_05_dasm(DASM_OPS_16); +int arcompact_handle1e_03_06_dasm(DASM_OPS_16); +int arcompact_handle1e_03_07_dasm(DASM_OPS_16); +int arcompact_handle1f_dasm(DASM_OPS_16); + +/************************************************************************************************************************************ +* * +* illegal opcode handlers (disassembly) * +* * +************************************************************************************************************************************/ + +int arcompact_handle01_01_00_06_dasm(DASM_OPS_32); +int arcompact_handle01_01_00_07_dasm(DASM_OPS_32); +int arcompact_handle01_01_00_08_dasm(DASM_OPS_32); +int arcompact_handle01_01_00_09_dasm(DASM_OPS_32); +int arcompact_handle01_01_00_0a_dasm(DASM_OPS_32); +int arcompact_handle01_01_00_0b_dasm(DASM_OPS_32); +int arcompact_handle01_01_00_0c_dasm(DASM_OPS_32); +int arcompact_handle01_01_00_0d_dasm(DASM_OPS_32); + +int arcompact_handle01_01_01_06_dasm(DASM_OPS_32); +int arcompact_handle01_01_01_07_dasm(DASM_OPS_32); +int arcompact_handle01_01_01_08_dasm(DASM_OPS_32); +int arcompact_handle01_01_01_09_dasm(DASM_OPS_32); +int arcompact_handle01_01_01_0a_dasm(DASM_OPS_32); +int arcompact_handle01_01_01_0b_dasm(DASM_OPS_32); +int arcompact_handle01_01_01_0c_dasm(DASM_OPS_32); +int arcompact_handle01_01_01_0d_dasm(DASM_OPS_32); + + +int arcompact_handle04_1e_dasm(DASM_OPS_32); +int arcompact_handle04_1f_dasm(DASM_OPS_32); + +int arcompact_handle04_24_dasm(DASM_OPS_32); +int arcompact_handle04_25_dasm(DASM_OPS_32); +int arcompact_handle04_26_dasm(DASM_OPS_32); +int arcompact_handle04_27_dasm(DASM_OPS_32); + +int arcompact_handle04_2c_dasm(DASM_OPS_32); +int arcompact_handle04_2d_dasm(DASM_OPS_32); +int arcompact_handle04_2e_dasm(DASM_OPS_32); + +int arcompact_handle04_2f_0d_dasm(DASM_OPS_32); +int arcompact_handle04_2f_0e_dasm(DASM_OPS_32); +int arcompact_handle04_2f_0f_dasm(DASM_OPS_32); +int arcompact_handle04_2f_10_dasm(DASM_OPS_32); +int arcompact_handle04_2f_11_dasm(DASM_OPS_32); +int arcompact_handle04_2f_12_dasm(DASM_OPS_32); +int arcompact_handle04_2f_13_dasm(DASM_OPS_32); +int arcompact_handle04_2f_14_dasm(DASM_OPS_32); +int arcompact_handle04_2f_15_dasm(DASM_OPS_32); +int arcompact_handle04_2f_16_dasm(DASM_OPS_32); +int arcompact_handle04_2f_17_dasm(DASM_OPS_32); +int arcompact_handle04_2f_18_dasm(DASM_OPS_32); +int arcompact_handle04_2f_19_dasm(DASM_OPS_32); +int arcompact_handle04_2f_1a_dasm(DASM_OPS_32); +int arcompact_handle04_2f_1b_dasm(DASM_OPS_32); +int arcompact_handle04_2f_1c_dasm(DASM_OPS_32); +int arcompact_handle04_2f_1d_dasm(DASM_OPS_32); +int arcompact_handle04_2f_1e_dasm(DASM_OPS_32); +int arcompact_handle04_2f_1f_dasm(DASM_OPS_32); +int arcompact_handle04_2f_20_dasm(DASM_OPS_32); +int arcompact_handle04_2f_21_dasm(DASM_OPS_32); +int arcompact_handle04_2f_22_dasm(DASM_OPS_32); +int arcompact_handle04_2f_23_dasm(DASM_OPS_32); +int arcompact_handle04_2f_24_dasm(DASM_OPS_32); +int arcompact_handle04_2f_25_dasm(DASM_OPS_32); +int arcompact_handle04_2f_26_dasm(DASM_OPS_32); +int arcompact_handle04_2f_27_dasm(DASM_OPS_32); +int arcompact_handle04_2f_28_dasm(DASM_OPS_32); +int arcompact_handle04_2f_29_dasm(DASM_OPS_32); +int arcompact_handle04_2f_2a_dasm(DASM_OPS_32); +int arcompact_handle04_2f_2b_dasm(DASM_OPS_32); +int arcompact_handle04_2f_2c_dasm(DASM_OPS_32); +int arcompact_handle04_2f_2d_dasm(DASM_OPS_32); +int arcompact_handle04_2f_2e_dasm(DASM_OPS_32); +int arcompact_handle04_2f_2f_dasm(DASM_OPS_32); +int arcompact_handle04_2f_30_dasm(DASM_OPS_32); +int arcompact_handle04_2f_31_dasm(DASM_OPS_32); +int arcompact_handle04_2f_32_dasm(DASM_OPS_32); +int arcompact_handle04_2f_33_dasm(DASM_OPS_32); +int arcompact_handle04_2f_34_dasm(DASM_OPS_32); +int arcompact_handle04_2f_35_dasm(DASM_OPS_32); +int arcompact_handle04_2f_36_dasm(DASM_OPS_32); +int arcompact_handle04_2f_37_dasm(DASM_OPS_32); +int arcompact_handle04_2f_38_dasm(DASM_OPS_32); +int arcompact_handle04_2f_39_dasm(DASM_OPS_32); +int arcompact_handle04_2f_3a_dasm(DASM_OPS_32); +int arcompact_handle04_2f_3b_dasm(DASM_OPS_32); +int arcompact_handle04_2f_3c_dasm(DASM_OPS_32); +int arcompact_handle04_2f_3d_dasm(DASM_OPS_32); +int arcompact_handle04_2f_3e_dasm(DASM_OPS_32); + +int arcompact_handle04_2f_3f_00_dasm(DASM_OPS_32); +int arcompact_handle04_2f_3f_06_dasm(DASM_OPS_32); +int arcompact_handle04_2f_3f_07_dasm(DASM_OPS_32); +int arcompact_handle04_2f_3f_08_dasm(DASM_OPS_32); +int arcompact_handle04_2f_3f_09_dasm(DASM_OPS_32); +int arcompact_handle04_2f_3f_0a_dasm(DASM_OPS_32); +int arcompact_handle04_2f_3f_0b_dasm(DASM_OPS_32); +int arcompact_handle04_2f_3f_0c_dasm(DASM_OPS_32); +int arcompact_handle04_2f_3f_0d_dasm(DASM_OPS_32); +int arcompact_handle04_2f_3f_0e_dasm(DASM_OPS_32); +int arcompact_handle04_2f_3f_0f_dasm(DASM_OPS_32); +int arcompact_handle04_2f_3f_10_dasm(DASM_OPS_32); +int arcompact_handle04_2f_3f_11_dasm(DASM_OPS_32); +int arcompact_handle04_2f_3f_12_dasm(DASM_OPS_32); +int arcompact_handle04_2f_3f_13_dasm(DASM_OPS_32); +int arcompact_handle04_2f_3f_14_dasm(DASM_OPS_32); +int arcompact_handle04_2f_3f_15_dasm(DASM_OPS_32); +int arcompact_handle04_2f_3f_16_dasm(DASM_OPS_32); +int arcompact_handle04_2f_3f_17_dasm(DASM_OPS_32); +int arcompact_handle04_2f_3f_18_dasm(DASM_OPS_32); +int arcompact_handle04_2f_3f_19_dasm(DASM_OPS_32); +int arcompact_handle04_2f_3f_1a_dasm(DASM_OPS_32); +int arcompact_handle04_2f_3f_1b_dasm(DASM_OPS_32); +int arcompact_handle04_2f_3f_1c_dasm(DASM_OPS_32); +int arcompact_handle04_2f_3f_1d_dasm(DASM_OPS_32); +int arcompact_handle04_2f_3f_1e_dasm(DASM_OPS_32); +int arcompact_handle04_2f_3f_1f_dasm(DASM_OPS_32); +int arcompact_handle04_2f_3f_20_dasm(DASM_OPS_32); +int arcompact_handle04_2f_3f_21_dasm(DASM_OPS_32); +int arcompact_handle04_2f_3f_22_dasm(DASM_OPS_32); +int arcompact_handle04_2f_3f_23_dasm(DASM_OPS_32); +int arcompact_handle04_2f_3f_24_dasm(DASM_OPS_32); +int arcompact_handle04_2f_3f_25_dasm(DASM_OPS_32); +int arcompact_handle04_2f_3f_26_dasm(DASM_OPS_32); +int arcompact_handle04_2f_3f_27_dasm(DASM_OPS_32); +int arcompact_handle04_2f_3f_28_dasm(DASM_OPS_32); +int arcompact_handle04_2f_3f_29_dasm(DASM_OPS_32); +int arcompact_handle04_2f_3f_2a_dasm(DASM_OPS_32); +int arcompact_handle04_2f_3f_2b_dasm(DASM_OPS_32); +int arcompact_handle04_2f_3f_2c_dasm(DASM_OPS_32); +int arcompact_handle04_2f_3f_2d_dasm(DASM_OPS_32); +int arcompact_handle04_2f_3f_2e_dasm(DASM_OPS_32); +int arcompact_handle04_2f_3f_2f_dasm(DASM_OPS_32); +int arcompact_handle04_2f_3f_30_dasm(DASM_OPS_32); +int arcompact_handle04_2f_3f_31_dasm(DASM_OPS_32); +int arcompact_handle04_2f_3f_32_dasm(DASM_OPS_32); +int arcompact_handle04_2f_3f_33_dasm(DASM_OPS_32); +int arcompact_handle04_2f_3f_34_dasm(DASM_OPS_32); +int arcompact_handle04_2f_3f_35_dasm(DASM_OPS_32); +int arcompact_handle04_2f_3f_36_dasm(DASM_OPS_32); +int arcompact_handle04_2f_3f_37_dasm(DASM_OPS_32); +int arcompact_handle04_2f_3f_38_dasm(DASM_OPS_32); +int arcompact_handle04_2f_3f_39_dasm(DASM_OPS_32); +int arcompact_handle04_2f_3f_3a_dasm(DASM_OPS_32); +int arcompact_handle04_2f_3f_3b_dasm(DASM_OPS_32); +int arcompact_handle04_2f_3f_3c_dasm(DASM_OPS_32); +int arcompact_handle04_2f_3f_3d_dasm(DASM_OPS_32); +int arcompact_handle04_2f_3f_3e_dasm(DASM_OPS_32); +int arcompact_handle04_2f_3f_3f_dasm(DASM_OPS_32); + +int arcompact_handle05_2f_00_dasm(DASM_OPS_32); +int arcompact_handle05_2f_01_dasm(DASM_OPS_32); +int arcompact_handle05_2f_02_dasm(DASM_OPS_32); +int arcompact_handle05_2f_03_dasm(DASM_OPS_32); +int arcompact_handle05_2f_04_dasm(DASM_OPS_32); +int arcompact_handle05_2f_05_dasm(DASM_OPS_32); +int arcompact_handle05_2f_06_dasm(DASM_OPS_32); +int arcompact_handle05_2f_07_dasm(DASM_OPS_32); +int arcompact_handle05_2f_08_dasm(DASM_OPS_32); +int arcompact_handle05_2f_09_dasm(DASM_OPS_32); +int arcompact_handle05_2f_0a_dasm(DASM_OPS_32); +int arcompact_handle05_2f_0b_dasm(DASM_OPS_32); +int arcompact_handle05_2f_0c_dasm(DASM_OPS_32); +int arcompact_handle05_2f_0d_dasm(DASM_OPS_32); +int arcompact_handle05_2f_0e_dasm(DASM_OPS_32); +int arcompact_handle05_2f_0f_dasm(DASM_OPS_32); +int arcompact_handle05_2f_10_dasm(DASM_OPS_32); +int arcompact_handle05_2f_11_dasm(DASM_OPS_32); +int arcompact_handle05_2f_12_dasm(DASM_OPS_32); +int arcompact_handle05_2f_13_dasm(DASM_OPS_32); +int arcompact_handle05_2f_14_dasm(DASM_OPS_32); +int arcompact_handle05_2f_15_dasm(DASM_OPS_32); +int arcompact_handle05_2f_16_dasm(DASM_OPS_32); +int arcompact_handle05_2f_17_dasm(DASM_OPS_32); +int arcompact_handle05_2f_18_dasm(DASM_OPS_32); +int arcompact_handle05_2f_19_dasm(DASM_OPS_32); +int arcompact_handle05_2f_1a_dasm(DASM_OPS_32); +int arcompact_handle05_2f_1b_dasm(DASM_OPS_32); +int arcompact_handle05_2f_1c_dasm(DASM_OPS_32); +int arcompact_handle05_2f_1d_dasm(DASM_OPS_32); +int arcompact_handle05_2f_1e_dasm(DASM_OPS_32); +int arcompact_handle05_2f_1f_dasm(DASM_OPS_32); +int arcompact_handle05_2f_20_dasm(DASM_OPS_32); +int arcompact_handle05_2f_21_dasm(DASM_OPS_32); +int arcompact_handle05_2f_22_dasm(DASM_OPS_32); +int arcompact_handle05_2f_23_dasm(DASM_OPS_32); +int arcompact_handle05_2f_24_dasm(DASM_OPS_32); +int arcompact_handle05_2f_25_dasm(DASM_OPS_32); +int arcompact_handle05_2f_26_dasm(DASM_OPS_32); +int arcompact_handle05_2f_27_dasm(DASM_OPS_32); +int arcompact_handle05_2f_28_dasm(DASM_OPS_32); +int arcompact_handle05_2f_29_dasm(DASM_OPS_32); +int arcompact_handle05_2f_2a_dasm(DASM_OPS_32); +int arcompact_handle05_2f_2b_dasm(DASM_OPS_32); +int arcompact_handle05_2f_2c_dasm(DASM_OPS_32); +int arcompact_handle05_2f_2d_dasm(DASM_OPS_32); +int arcompact_handle05_2f_2e_dasm(DASM_OPS_32); +int arcompact_handle05_2f_2f_dasm(DASM_OPS_32); +int arcompact_handle05_2f_30_dasm(DASM_OPS_32); +int arcompact_handle05_2f_31_dasm(DASM_OPS_32); +int arcompact_handle05_2f_32_dasm(DASM_OPS_32); +int arcompact_handle05_2f_33_dasm(DASM_OPS_32); +int arcompact_handle05_2f_34_dasm(DASM_OPS_32); +int arcompact_handle05_2f_35_dasm(DASM_OPS_32); +int arcompact_handle05_2f_36_dasm(DASM_OPS_32); +int arcompact_handle05_2f_37_dasm(DASM_OPS_32); +int arcompact_handle05_2f_38_dasm(DASM_OPS_32); +int arcompact_handle05_2f_39_dasm(DASM_OPS_32); +int arcompact_handle05_2f_3a_dasm(DASM_OPS_32); +int arcompact_handle05_2f_3b_dasm(DASM_OPS_32); +int arcompact_handle05_2f_3c_dasm(DASM_OPS_32); +int arcompact_handle05_2f_3d_dasm(DASM_OPS_32); +int arcompact_handle05_2f_3e_dasm(DASM_OPS_32); + +int arcompact_handle05_2f_3f_00_dasm(DASM_OPS_32); +int arcompact_handle05_2f_3f_01_dasm(DASM_OPS_32); +int arcompact_handle05_2f_3f_02_dasm(DASM_OPS_32); +int arcompact_handle05_2f_3f_03_dasm(DASM_OPS_32); +int arcompact_handle05_2f_3f_04_dasm(DASM_OPS_32); +int arcompact_handle05_2f_3f_05_dasm(DASM_OPS_32); +int arcompact_handle05_2f_3f_06_dasm(DASM_OPS_32); +int arcompact_handle05_2f_3f_07_dasm(DASM_OPS_32); +int arcompact_handle05_2f_3f_08_dasm(DASM_OPS_32); +int arcompact_handle05_2f_3f_09_dasm(DASM_OPS_32); +int arcompact_handle05_2f_3f_0a_dasm(DASM_OPS_32); +int arcompact_handle05_2f_3f_0b_dasm(DASM_OPS_32); +int arcompact_handle05_2f_3f_0c_dasm(DASM_OPS_32); +int arcompact_handle05_2f_3f_0d_dasm(DASM_OPS_32); +int arcompact_handle05_2f_3f_0e_dasm(DASM_OPS_32); +int arcompact_handle05_2f_3f_0f_dasm(DASM_OPS_32); +int arcompact_handle05_2f_3f_10_dasm(DASM_OPS_32); +int arcompact_handle05_2f_3f_11_dasm(DASM_OPS_32); +int arcompact_handle05_2f_3f_12_dasm(DASM_OPS_32); +int arcompact_handle05_2f_3f_13_dasm(DASM_OPS_32); +int arcompact_handle05_2f_3f_14_dasm(DASM_OPS_32); +int arcompact_handle05_2f_3f_15_dasm(DASM_OPS_32); +int arcompact_handle05_2f_3f_16_dasm(DASM_OPS_32); +int arcompact_handle05_2f_3f_17_dasm(DASM_OPS_32); +int arcompact_handle05_2f_3f_18_dasm(DASM_OPS_32); +int arcompact_handle05_2f_3f_19_dasm(DASM_OPS_32); +int arcompact_handle05_2f_3f_1a_dasm(DASM_OPS_32); +int arcompact_handle05_2f_3f_1b_dasm(DASM_OPS_32); +int arcompact_handle05_2f_3f_1c_dasm(DASM_OPS_32); +int arcompact_handle05_2f_3f_1d_dasm(DASM_OPS_32); +int arcompact_handle05_2f_3f_1e_dasm(DASM_OPS_32); +int arcompact_handle05_2f_3f_1f_dasm(DASM_OPS_32); +int arcompact_handle05_2f_3f_20_dasm(DASM_OPS_32); +int arcompact_handle05_2f_3f_21_dasm(DASM_OPS_32); +int arcompact_handle05_2f_3f_22_dasm(DASM_OPS_32); +int arcompact_handle05_2f_3f_23_dasm(DASM_OPS_32); +int arcompact_handle05_2f_3f_24_dasm(DASM_OPS_32); +int arcompact_handle05_2f_3f_25_dasm(DASM_OPS_32); +int arcompact_handle05_2f_3f_26_dasm(DASM_OPS_32); +int arcompact_handle05_2f_3f_27_dasm(DASM_OPS_32); +int arcompact_handle05_2f_3f_28_dasm(DASM_OPS_32); +int arcompact_handle05_2f_3f_29_dasm(DASM_OPS_32); +int arcompact_handle05_2f_3f_2a_dasm(DASM_OPS_32); +int arcompact_handle05_2f_3f_2b_dasm(DASM_OPS_32); +int arcompact_handle05_2f_3f_2c_dasm(DASM_OPS_32); +int arcompact_handle05_2f_3f_2d_dasm(DASM_OPS_32); +int arcompact_handle05_2f_3f_2e_dasm(DASM_OPS_32); +int arcompact_handle05_2f_3f_2f_dasm(DASM_OPS_32); +int arcompact_handle05_2f_3f_30_dasm(DASM_OPS_32); +int arcompact_handle05_2f_3f_31_dasm(DASM_OPS_32); +int arcompact_handle05_2f_3f_32_dasm(DASM_OPS_32); +int arcompact_handle05_2f_3f_33_dasm(DASM_OPS_32); +int arcompact_handle05_2f_3f_34_dasm(DASM_OPS_32); +int arcompact_handle05_2f_3f_35_dasm(DASM_OPS_32); +int arcompact_handle05_2f_3f_36_dasm(DASM_OPS_32); +int arcompact_handle05_2f_3f_37_dasm(DASM_OPS_32); +int arcompact_handle05_2f_3f_38_dasm(DASM_OPS_32); +int arcompact_handle05_2f_3f_39_dasm(DASM_OPS_32); +int arcompact_handle05_2f_3f_3a_dasm(DASM_OPS_32); +int arcompact_handle05_2f_3f_3b_dasm(DASM_OPS_32); +int arcompact_handle05_2f_3f_3c_dasm(DASM_OPS_32); +int arcompact_handle05_2f_3f_3d_dasm(DASM_OPS_32); +int arcompact_handle05_2f_3f_3e_dasm(DASM_OPS_32); +int arcompact_handle05_2f_3f_3f_dasm(DASM_OPS_32); + + +int arcompact_handle04_38_dasm(DASM_OPS_32); +int arcompact_handle04_39_dasm(DASM_OPS_32); +int arcompact_handle04_3a_dasm(DASM_OPS_32); +int arcompact_handle04_3b_dasm(DASM_OPS_32); +int arcompact_handle04_3c_dasm(DASM_OPS_32); +int arcompact_handle04_3d_dasm(DASM_OPS_32); +int arcompact_handle04_3e_dasm(DASM_OPS_32); +int arcompact_handle04_3f_dasm(DASM_OPS_32); + +int arcompact_handle05_09_dasm(DASM_OPS_32); +int arcompact_handle05_0c_dasm(DASM_OPS_32); +int arcompact_handle05_0d_dasm(DASM_OPS_32); +int arcompact_handle05_0e_dasm(DASM_OPS_32); +int arcompact_handle05_0f_dasm(DASM_OPS_32); +int arcompact_handle05_10_dasm(DASM_OPS_32); +int arcompact_handle05_11_dasm(DASM_OPS_32); +int arcompact_handle05_12_dasm(DASM_OPS_32); +int arcompact_handle05_13_dasm(DASM_OPS_32); +int arcompact_handle05_14_dasm(DASM_OPS_32); +int arcompact_handle05_15_dasm(DASM_OPS_32); +int arcompact_handle05_16_dasm(DASM_OPS_32); +int arcompact_handle05_17_dasm(DASM_OPS_32); +int arcompact_handle05_18_dasm(DASM_OPS_32); +int arcompact_handle05_19_dasm(DASM_OPS_32); +int arcompact_handle05_1a_dasm(DASM_OPS_32); +int arcompact_handle05_1b_dasm(DASM_OPS_32); +int arcompact_handle05_1c_dasm(DASM_OPS_32); +int arcompact_handle05_1d_dasm(DASM_OPS_32); +int arcompact_handle05_1e_dasm(DASM_OPS_32); +int arcompact_handle05_1f_dasm(DASM_OPS_32); +int arcompact_handle05_20_dasm(DASM_OPS_32); +int arcompact_handle05_21_dasm(DASM_OPS_32); +int arcompact_handle05_22_dasm(DASM_OPS_32); +int arcompact_handle05_23_dasm(DASM_OPS_32); +int arcompact_handle05_24_dasm(DASM_OPS_32); +int arcompact_handle05_25_dasm(DASM_OPS_32); +int arcompact_handle05_26_dasm(DASM_OPS_32); +int arcompact_handle05_27_dasm(DASM_OPS_32); + +int arcompact_handle05_2a_dasm(DASM_OPS_32); +int arcompact_handle05_2b_dasm(DASM_OPS_32); +int arcompact_handle05_2c_dasm(DASM_OPS_32); +int arcompact_handle05_2d_dasm(DASM_OPS_32); +int arcompact_handle05_2e_dasm(DASM_OPS_32); + +int arcompact_handle05_30_dasm(DASM_OPS_32); +int arcompact_handle05_31_dasm(DASM_OPS_32); +int arcompact_handle05_32_dasm(DASM_OPS_32); +int arcompact_handle05_33_dasm(DASM_OPS_32); +int arcompact_handle05_34_dasm(DASM_OPS_32); +int arcompact_handle05_35_dasm(DASM_OPS_32); +int arcompact_handle05_36_dasm(DASM_OPS_32); +int arcompact_handle05_37_dasm(DASM_OPS_32); +int arcompact_handle05_38_dasm(DASM_OPS_32); +int arcompact_handle05_39_dasm(DASM_OPS_32); +int arcompact_handle05_3a_dasm(DASM_OPS_32); +int arcompact_handle05_3b_dasm(DASM_OPS_32); +int arcompact_handle05_3c_dasm(DASM_OPS_32); +int arcompact_handle05_3d_dasm(DASM_OPS_32); +int arcompact_handle05_3e_dasm(DASM_OPS_32); +int arcompact_handle05_3f_dasm(DASM_OPS_32); + +int arcompact_handle0f_00_04_dasm(DASM_OPS_16); +int arcompact_handle0f_00_05_dasm(DASM_OPS_16); +int arcompact_handle0f_00_07_02_dasm(DASM_OPS_16); +int arcompact_handle0f_00_07_03_dasm(DASM_OPS_16); +int arcompact_handle0f_01_dasm(DASM_OPS_16); +int arcompact_handle0f_03_dasm(DASM_OPS_16); +int arcompact_handle0f_08_dasm(DASM_OPS_16); +int arcompact_handle0f_09_dasm(DASM_OPS_16); +int arcompact_handle0f_0a_dasm(DASM_OPS_16); +int arcompact_handle0f_17_dasm(DASM_OPS_16); + +int arcompact_handle18_05_02_dasm(DASM_OPS_16); +int arcompact_handle18_05_03_dasm(DASM_OPS_16); +int arcompact_handle18_05_04_dasm(DASM_OPS_16); +int arcompact_handle18_05_05_dasm(DASM_OPS_16); +int arcompact_handle18_05_06_dasm(DASM_OPS_16); +int arcompact_handle18_05_07_dasm(DASM_OPS_16); +int arcompact_handle18_06_00_dasm(DASM_OPS_16); +int arcompact_handle18_06_02_dasm(DASM_OPS_16); +int arcompact_handle18_06_03_dasm(DASM_OPS_16); +int arcompact_handle18_06_04_dasm(DASM_OPS_16); +int arcompact_handle18_06_05_dasm(DASM_OPS_16); +int arcompact_handle18_06_06_dasm(DASM_OPS_16); +int arcompact_handle18_06_07_dasm(DASM_OPS_16); +int arcompact_handle18_06_08_dasm(DASM_OPS_16); +int arcompact_handle18_06_09_dasm(DASM_OPS_16); +int arcompact_handle18_06_0a_dasm(DASM_OPS_16); +int arcompact_handle18_06_0b_dasm(DASM_OPS_16); +int arcompact_handle18_06_0c_dasm(DASM_OPS_16); +int arcompact_handle18_06_0d_dasm(DASM_OPS_16); +int arcompact_handle18_06_0e_dasm(DASM_OPS_16); +int arcompact_handle18_06_0f_dasm(DASM_OPS_16); +int arcompact_handle18_06_10_dasm(DASM_OPS_16); +int arcompact_handle18_06_12_dasm(DASM_OPS_16); +int arcompact_handle18_06_13_dasm(DASM_OPS_16); +int arcompact_handle18_06_14_dasm(DASM_OPS_16); +int arcompact_handle18_06_15_dasm(DASM_OPS_16); +int arcompact_handle18_06_16_dasm(DASM_OPS_16); +int arcompact_handle18_06_17_dasm(DASM_OPS_16); +int arcompact_handle18_06_18_dasm(DASM_OPS_16); +int arcompact_handle18_06_19_dasm(DASM_OPS_16); +int arcompact_handle18_06_1a_dasm(DASM_OPS_16); +int arcompact_handle18_06_1b_dasm(DASM_OPS_16); +int arcompact_handle18_06_1c_dasm(DASM_OPS_16); +int arcompact_handle18_06_1d_dasm(DASM_OPS_16); +int arcompact_handle18_06_1e_dasm(DASM_OPS_16); +int arcompact_handle18_06_1f_dasm(DASM_OPS_16); +int arcompact_handle18_07_00_dasm(DASM_OPS_16); +int arcompact_handle18_07_02_dasm(DASM_OPS_16); +int arcompact_handle18_07_03_dasm(DASM_OPS_16); +int arcompact_handle18_07_04_dasm(DASM_OPS_16); +int arcompact_handle18_07_05_dasm(DASM_OPS_16); +int arcompact_handle18_07_06_dasm(DASM_OPS_16); +int arcompact_handle18_07_07_dasm(DASM_OPS_16); +int arcompact_handle18_07_08_dasm(DASM_OPS_16); +int arcompact_handle18_07_09_dasm(DASM_OPS_16); +int arcompact_handle18_07_0a_dasm(DASM_OPS_16); +int arcompact_handle18_07_0b_dasm(DASM_OPS_16); +int arcompact_handle18_07_0c_dasm(DASM_OPS_16); +int arcompact_handle18_07_0d_dasm(DASM_OPS_16); +int arcompact_handle18_07_0e_dasm(DASM_OPS_16); +int arcompact_handle18_07_0f_dasm(DASM_OPS_16); +int arcompact_handle18_07_10_dasm(DASM_OPS_16); +int arcompact_handle18_07_12_dasm(DASM_OPS_16); +int arcompact_handle18_07_13_dasm(DASM_OPS_16); +int arcompact_handle18_07_14_dasm(DASM_OPS_16); +int arcompact_handle18_07_15_dasm(DASM_OPS_16); +int arcompact_handle18_07_16_dasm(DASM_OPS_16); +int arcompact_handle18_07_17_dasm(DASM_OPS_16); +int arcompact_handle18_07_18_dasm(DASM_OPS_16); +int arcompact_handle18_07_19_dasm(DASM_OPS_16); +int arcompact_handle18_07_1a_dasm(DASM_OPS_16); +int arcompact_handle18_07_1b_dasm(DASM_OPS_16); +int arcompact_handle18_07_1c_dasm(DASM_OPS_16); +int arcompact_handle18_07_1d_dasm(DASM_OPS_16); +int arcompact_handle18_07_1e_dasm(DASM_OPS_16); +int arcompact_handle18_07_1f_dasm(DASM_OPS_16); diff --git a/src/devices/cpu/arm/arm.c b/src/devices/cpu/arm/arm.c new file mode 100644 index 00000000000..8d9b420486d --- /dev/null +++ b/src/devices/cpu/arm/arm.c @@ -0,0 +1,1519 @@ +// license:BSD-3-Clause +// copyright-holders:Bryan McPhail +/* arm.c + + ARM 2/3/6 Emulation (26 bit address bus) + + Todo: + Timing - Currently very approximated, nothing relies on proper timing so far. + IRQ timing not yet correct (again, nothing is affected by this so far). + + Recent changes (2005): + Fixed software interrupts + Fixed various mode change bugs + Added preliminary co-processor support. + + By Bryan McPhail (bmcphail@tendril.co.uk) and Phil Stroffolino + +*/ + +#include "emu.h" +#include "debugger.h" +#include "arm.h" + +CPU_DISASSEMBLE( arm ); +CPU_DISASSEMBLE( arm_be ); + +#define ARM_DEBUG_CORE 0 +#define ARM_DEBUG_COPRO 0 + +enum +{ + eARM_MODE_USER = 0x0, + eARM_MODE_FIQ = 0x1, + eARM_MODE_IRQ = 0x2, + eARM_MODE_SVC = 0x3, + + kNumModes +}; + +/* There are 27 32 bit processor registers */ +enum +{ + eR0=0,eR1,eR2,eR3,eR4,eR5,eR6,eR7, + eR8,eR9,eR10,eR11,eR12, + eR13, /* Stack Pointer */ + eR14, /* Link Register (holds return address) */ + eR15, /* Program Counter */ + + /* Fast Interrupt */ + eR8_FIQ,eR9_FIQ,eR10_FIQ,eR11_FIQ,eR12_FIQ,eR13_FIQ,eR14_FIQ, + + /* IRQ */ + eR13_IRQ,eR14_IRQ, + + /* Software Interrupt */ + eR13_SVC,eR14_SVC, + + kNumRegisters +}; + +/* 16 processor registers are visible at any given time, + * banked depending on processor mode. + */ +static const int sRegisterTable[kNumModes][16] = +{ + { /* USR */ + eR0,eR1,eR2,eR3,eR4,eR5,eR6,eR7, + eR8,eR9,eR10,eR11,eR12, + eR13,eR14, + eR15 + }, + { /* FIQ */ + eR0,eR1,eR2,eR3,eR4,eR5,eR6,eR7, + eR8_FIQ,eR9_FIQ,eR10_FIQ,eR11_FIQ,eR12_FIQ, + eR13_FIQ,eR14_FIQ, + eR15 + }, + { /* IRQ */ + eR0,eR1,eR2,eR3,eR4,eR5,eR6,eR7, + eR8,eR9,eR10,eR11,eR12, + eR13_IRQ,eR14_IRQ, + eR15 + }, + { /* SVC */ + eR0,eR1,eR2,eR3,eR4,eR5,eR6,eR7, + eR8,eR9,eR10,eR11,eR12, + eR13_SVC,eR14_SVC, + eR15 + } +}; + +#define N_BIT 31 +#define Z_BIT 30 +#define C_BIT 29 +#define V_BIT 28 +#define I_BIT 27 +#define F_BIT 26 + +#define N_MASK ((UINT32)(1<> 31) + +/* Deconstructing an instruction */ + +#define INSN_COND ((UINT32) 0xf0000000u) +#define INSN_SDT_L ((UINT32) 0x00100000u) +#define INSN_SDT_W ((UINT32) 0x00200000u) +#define INSN_SDT_B ((UINT32) 0x00400000u) +#define INSN_SDT_U ((UINT32) 0x00800000u) +#define INSN_SDT_P ((UINT32) 0x01000000u) +#define INSN_BDT_L ((UINT32) 0x00100000u) +#define INSN_BDT_W ((UINT32) 0x00200000u) +#define INSN_BDT_S ((UINT32) 0x00400000u) +#define INSN_BDT_U ((UINT32) 0x00800000u) +#define INSN_BDT_P ((UINT32) 0x01000000u) +#define INSN_BDT_REGS ((UINT32) 0x0000ffffu) +#define INSN_SDT_IMM ((UINT32) 0x00000fffu) +#define INSN_MUL_A ((UINT32) 0x00200000u) +#define INSN_MUL_RM ((UINT32) 0x0000000fu) +#define INSN_MUL_RS ((UINT32) 0x00000f00u) +#define INSN_MUL_RN ((UINT32) 0x0000f000u) +#define INSN_MUL_RD ((UINT32) 0x000f0000u) +#define INSN_I ((UINT32) 0x02000000u) +#define INSN_OPCODE ((UINT32) 0x01e00000u) +#define INSN_S ((UINT32) 0x00100000u) +#define INSN_BL ((UINT32) 0x01000000u) +#define INSN_BRANCH ((UINT32) 0x00ffffffu) +#define INSN_SWI ((UINT32) 0x00ffffffu) +#define INSN_RN ((UINT32) 0x000f0000u) +#define INSN_RD ((UINT32) 0x0000f000u) +#define INSN_OP2 ((UINT32) 0x00000fffu) +#define INSN_OP2_SHIFT ((UINT32) 0x00000f80u) +#define INSN_OP2_SHIFT_TYPE ((UINT32) 0x00000070u) +#define INSN_OP2_RM ((UINT32) 0x0000000fu) +#define INSN_OP2_ROTATE ((UINT32) 0x00000f00u) +#define INSN_OP2_IMM ((UINT32) 0x000000ffu) +#define INSN_OP2_SHIFT_TYPE_SHIFT 4 +#define INSN_OP2_SHIFT_SHIFT 7 +#define INSN_OP2_ROTATE_SHIFT 8 +#define INSN_MUL_RS_SHIFT 8 +#define INSN_MUL_RN_SHIFT 12 +#define INSN_MUL_RD_SHIFT 16 +#define INSN_OPCODE_SHIFT 21 +#define INSN_RN_SHIFT 16 +#define INSN_RD_SHIFT 12 +#define INSN_COND_SHIFT 28 + +#define S_CYCLE 1 +#define N_CYCLE 1 +#define I_CYCLE 1 + +enum +{ + OPCODE_AND, /* 0000 */ + OPCODE_EOR, /* 0001 */ + OPCODE_SUB, /* 0010 */ + OPCODE_RSB, /* 0011 */ + OPCODE_ADD, /* 0100 */ + OPCODE_ADC, /* 0101 */ + OPCODE_SBC, /* 0110 */ + OPCODE_RSC, /* 0111 */ + OPCODE_TST, /* 1000 */ + OPCODE_TEQ, /* 1001 */ + OPCODE_CMP, /* 1010 */ + OPCODE_CMN, /* 1011 */ + OPCODE_ORR, /* 1100 */ + OPCODE_MOV, /* 1101 */ + OPCODE_BIC, /* 1110 */ + OPCODE_MVN /* 1111 */ +}; + +enum +{ + COND_EQ = 0, /* Z: equal */ + COND_NE, /* ~Z: not equal */ + COND_CS, COND_HS = 2, /* C: unsigned higher or same */ + COND_CC, COND_LO = 3, /* ~C: unsigned lower */ + COND_MI, /* N: negative */ + COND_PL, /* ~N: positive or zero */ + COND_VS, /* V: overflow */ + COND_VC, /* ~V: no overflow */ + COND_HI, /* C && ~Z: unsigned higher */ + COND_LS, /* ~C || Z: unsigned lower or same */ + COND_GE, /* N == V: greater or equal */ + COND_LT, /* N != V: less than */ + COND_GT, /* ~Z && (N == V): greater than */ + COND_LE, /* Z || (N != V): less than or equal */ + COND_AL, /* always */ + COND_NV /* never */ +}; + +#define LSL(v,s) ((v) << (s)) +#define LSR(v,s) ((v) >> (s)) +#define ROL(v,s) (LSL((v),(s)) | (LSR((v),32u - (s)))) +#define ROR(v,s) (LSR((v),(s)) | (LSL((v),32u - (s)))) + + +/***************************************************************************/ + +const device_type ARM = &device_creator; +const device_type ARM_BE = &device_creator; + + +arm_cpu_device::arm_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : cpu_device(mconfig, ARM, "ARM", tag, owner, clock, "arm", __FILE__) + , m_program_config("program", ENDIANNESS_LITTLE, 32, 26, 0) + , m_endian(ENDIANNESS_LITTLE) + , m_copro_type(ARM_COPRO_TYPE_UNKNOWN_CP15) +{ + memset(m_sArmRegister, 0x00, sizeof(m_sArmRegister)); +} + + +arm_cpu_device::arm_cpu_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source, endianness_t endianness) + : cpu_device(mconfig, type, name, tag, owner, clock, shortname, source) + , m_program_config("program", endianness, 32, 26, 0) + , m_endian(endianness) + , m_copro_type(ARM_COPRO_TYPE_UNKNOWN_CP15) +{ + memset(m_sArmRegister, 0x00, sizeof(m_sArmRegister)); +} + + +arm_be_cpu_device::arm_be_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : arm_cpu_device(mconfig, ARM_BE, "ARM (big endian)", tag, owner, clock, "arm be", __FILE__, ENDIANNESS_BIG) +{ +} + + + +void arm_cpu_device::cpu_write32( int addr, UINT32 data ) +{ + /* Unaligned writes are treated as normal writes */ + m_program->write_dword(addr&ADDRESS_MASK,data); + if (ARM_DEBUG_CORE && addr&3) logerror("%08x: Unaligned write %08x\n",R15,addr); +} + +void arm_cpu_device::cpu_write8( int addr, UINT8 data ) +{ + m_program->write_byte(addr,data); +} + +UINT32 arm_cpu_device::cpu_read32( int addr ) +{ + UINT32 result = m_program->read_dword(addr&ADDRESS_MASK); + + /* Unaligned reads rotate the word, they never combine words */ + if (addr&3) + { + if (ARM_DEBUG_CORE && addr&1) + logerror("%08x: Unaligned byte read %08x\n",R15,addr); + + if ((addr&3)==1) + return ((result&0x000000ff)<<24)|((result&0xffffff00)>> 8); + if ((addr&3)==2) + return ((result&0x0000ffff)<<16)|((result&0xffff0000)>>16); + if ((addr&3)==3) + return ((result&0x00ffffff)<< 8)|((result&0xff000000)>>24); + } + + return result; +} + +UINT8 arm_cpu_device::cpu_read8( int addr ) +{ + return m_program->read_byte(addr); +} + +UINT32 arm_cpu_device::GetRegister( int rIndex ) +{ + return m_sArmRegister[sRegisterTable[MODE][rIndex]]; +} + +void arm_cpu_device::SetRegister( int rIndex, UINT32 value ) +{ + m_sArmRegister[sRegisterTable[MODE][rIndex]] = value; +} + +UINT32 arm_cpu_device::GetModeRegister( int mode, int rIndex ) +{ + return m_sArmRegister[sRegisterTable[mode][rIndex]]; +} + +void arm_cpu_device::SetModeRegister( int mode, int rIndex, UINT32 value ) +{ + m_sArmRegister[sRegisterTable[mode][rIndex]] = value; +} + + +/***************************************************************************/ + +void arm_cpu_device::device_reset() +{ + for ( int i = 0; i < 27; i++ ) + { + m_sArmRegister[i] = 0; + } + for ( int i = 0; i < 16; i++ ) + { + m_coproRegister[i] = 0; + } + m_pendingIrq = 0; + m_pendingFiq = 0; + + /* start up in SVC mode with interrupts disabled. */ + R15 = eARM_MODE_SVC|I_MASK|F_MASK; +} + + +void arm_cpu_device::execute_run() +{ + UINT32 pc; + UINT32 insn; + + do + { + debugger_instruction_hook(this, R15 & ADDRESS_MASK); + + /* load instruction */ + pc = R15; + insn = m_direct->read_dword( pc & ADDRESS_MASK ); + + switch (insn >> INSN_COND_SHIFT) + { + case COND_EQ: + if (Z_IS_CLEAR(pc)) goto L_Next; + break; + case COND_NE: + if (Z_IS_SET(pc)) goto L_Next; + break; + case COND_CS: + if (C_IS_CLEAR(pc)) goto L_Next; + break; + case COND_CC: + if (C_IS_SET(pc)) goto L_Next; + break; + case COND_MI: + if (N_IS_CLEAR(pc)) goto L_Next; + break; + case COND_PL: + if (N_IS_SET(pc)) goto L_Next; + break; + case COND_VS: + if (V_IS_CLEAR(pc)) goto L_Next; + break; + case COND_VC: + if (V_IS_SET(pc)) goto L_Next; + break; + case COND_HI: + if (C_IS_CLEAR(pc) || Z_IS_SET(pc)) goto L_Next; + break; + case COND_LS: + if (C_IS_SET(pc) && Z_IS_CLEAR(pc)) goto L_Next; + break; + case COND_GE: + if (!(pc & N_MASK) != !(pc & V_MASK)) goto L_Next; /* Use x ^ (x >> ...) method */ + break; + case COND_LT: + if (!(pc & N_MASK) == !(pc & V_MASK)) goto L_Next; + break; + case COND_GT: + if (Z_IS_SET(pc) || (!(pc & N_MASK) != !(pc & V_MASK))) goto L_Next; + break; + case COND_LE: + if (Z_IS_CLEAR(pc) && (!(pc & N_MASK) == !(pc & V_MASK))) goto L_Next; + break; + case COND_NV: + goto L_Next; + } + /* Condition satisfied, so decode the instruction */ + if ((insn & 0x0fc000f0u) == 0x00000090u) /* Multiplication */ + { + HandleMul(insn); + R15 += 4; + } + else if (!(insn & 0x0c000000u)) /* Data processing */ + { + HandleALU(insn); + } + else if ((insn & 0x0c000000u) == 0x04000000u) /* Single data access */ + { + HandleMemSingle(insn); + R15 += 4; + } + else if ((insn & 0x0e000000u) == 0x08000000u ) /* Block data access */ + { + HandleMemBlock(insn); + R15 += 4; + } + else if ((insn & 0x0e000000u) == 0x0a000000u) /* Branch */ + { + HandleBranch(insn); + } + else if ((insn & 0x0f000000u) == 0x0e000000u) /* Coprocessor */ + { + if (m_copro_type == ARM_COPRO_TYPE_VL86C020) + HandleCoProVL86C020(insn); + else + HandleCoPro(insn); + + R15 += 4; + } + else if ((insn & 0x0f000000u) == 0x0f000000u) /* Software interrupt */ + { + pc=R15+4; + R15 = eARM_MODE_SVC; /* Set SVC mode so PC is saved to correct R14 bank */ + SetRegister( 14, pc ); /* save PC */ + R15 = (pc&PSR_MASK)|(pc&IRQ_MASK)|0x8|eARM_MODE_SVC|I_MASK|(pc&MODE_MASK); + m_icount -= 2 * S_CYCLE + N_CYCLE; + } + else /* Undefined */ + { + logerror("%08x: Undefined instruction\n",R15); + L_Next: + m_icount -= S_CYCLE; + R15 += 4; + } + + arm_check_irq_state(); + + } while( m_icount > 0 ); +} /* arm_execute */ + + +void arm_cpu_device::arm_check_irq_state() +{ + UINT32 pc = R15+4; /* save old pc (already incremented in pipeline) */; + + /* Exception priorities (from ARM6, not specifically ARM2/3): + + Reset + Data abort + FIRQ + IRQ + Prefetch abort + Undefined instruction + */ + + if (m_pendingFiq && (pc&F_MASK)==0) + { + R15 = eARM_MODE_FIQ; /* Set FIQ mode so PC is saved to correct R14 bank */ + SetRegister( 14, pc ); /* save PC */ + R15 = (pc&PSR_MASK)|(pc&IRQ_MASK)|0x1c|eARM_MODE_FIQ|I_MASK|F_MASK; /* Mask both IRQ & FIRQ, set PC=0x1c */ + m_pendingFiq=0; + return; + } + + if (m_pendingIrq && (pc&I_MASK)==0) + { + R15 = eARM_MODE_IRQ; /* Set IRQ mode so PC is saved to correct R14 bank */ + SetRegister( 14, pc ); /* save PC */ + R15 = (pc&PSR_MASK)|(pc&IRQ_MASK)|0x18|eARM_MODE_IRQ|I_MASK|(pc&F_MASK); /* Mask only IRQ, set PC=0x18 */ + m_pendingIrq=0; + return; + } +} + + +void arm_cpu_device::execute_set_input(int irqline, int state) +{ + switch (irqline) + { + case ARM_IRQ_LINE: /* IRQ */ + if (state && (R15&0x3)!=eARM_MODE_IRQ) /* Don't allow nested IRQs */ + m_pendingIrq=1; + else + m_pendingIrq=0; + break; + + case ARM_FIRQ_LINE: /* FIRQ */ + if (state && (R15&0x3)!=eARM_MODE_FIQ) /* Don't allow nested FIRQs */ + m_pendingFiq=1; + else + m_pendingFiq=0; + break; + } + + arm_check_irq_state(); +} + + +void arm_cpu_device::device_start() +{ + m_program = &space(AS_PROGRAM); + m_direct = &m_program->direct(); + + save_item(NAME(m_sArmRegister)); + save_item(NAME(m_coproRegister)); + save_item(NAME(m_pendingIrq)); + save_item(NAME(m_pendingFiq)); + + state_add( ARM32_PC, "PC", m_sArmRegister[15] ).mask(ADDRESS_MASK).formatstr("%08X"); + state_add( ARM32_R0, "R0", m_sArmRegister[ 0] ).formatstr("%08X"); + state_add( ARM32_R1, "R1", m_sArmRegister[ 1] ).formatstr("%08X"); + state_add( ARM32_R2, "R2", m_sArmRegister[ 2] ).formatstr("%08X"); + state_add( ARM32_R3, "R3", m_sArmRegister[ 3] ).formatstr("%08X"); + state_add( ARM32_R4, "R4", m_sArmRegister[ 4] ).formatstr("%08X"); + state_add( ARM32_R5, "R5", m_sArmRegister[ 5] ).formatstr("%08X"); + state_add( ARM32_R6, "R6", m_sArmRegister[ 6] ).formatstr("%08X"); + state_add( ARM32_R7, "R7", m_sArmRegister[ 7] ).formatstr("%08X"); + state_add( ARM32_R8, "R8", m_sArmRegister[ 8] ).formatstr("%08X"); + state_add( ARM32_R9, "R9", m_sArmRegister[ 9] ).formatstr("%08X"); + state_add( ARM32_R10, "R10", m_sArmRegister[10] ).formatstr("%08X"); + state_add( ARM32_R11, "R11", m_sArmRegister[11] ).formatstr("%08X"); + state_add( ARM32_R12, "R12", m_sArmRegister[12] ).formatstr("%08X"); + state_add( ARM32_R13, "R13", m_sArmRegister[13] ).formatstr("%08X"); + state_add( ARM32_R14, "R14", m_sArmRegister[14] ).formatstr("%08X"); + state_add( ARM32_R15, "R15", m_sArmRegister[15] ).formatstr("%08X"); + state_add( ARM32_FR8, "FR8", m_sArmRegister[eR8_FIQ] ).formatstr("%08X"); + state_add( ARM32_FR9, "FR9", m_sArmRegister[eR9_FIQ] ).formatstr("%08X"); + state_add( ARM32_FR10, "FR10", m_sArmRegister[eR10_FIQ] ).formatstr("%08X"); + state_add( ARM32_FR11, "FR11", m_sArmRegister[eR11_FIQ] ).formatstr("%08X"); + state_add( ARM32_FR12, "FR12", m_sArmRegister[eR12_FIQ] ).formatstr("%08X"); + state_add( ARM32_FR13, "FR13", m_sArmRegister[eR13_FIQ] ).formatstr("%08X"); + state_add( ARM32_FR14, "FR14", m_sArmRegister[eR14_FIQ] ).formatstr("%08X"); + state_add( ARM32_IR13, "IR13", m_sArmRegister[eR13_IRQ] ).formatstr("%08X"); + state_add( ARM32_IR14, "IR14", m_sArmRegister[eR14_IRQ] ).formatstr("%08X"); + state_add( ARM32_SR13, "SR13", m_sArmRegister[eR13_SVC] ).formatstr("%08X"); + state_add( ARM32_SR14, "SR14", m_sArmRegister[eR14_SVC] ).formatstr("%08X"); + + state_add(STATE_GENPC, "curpc", m_sArmRegister[15]).mask(ADDRESS_MASK).callimport().callexport().formatstr("%8s").noshow(); + state_add(STATE_GENFLAGS, "GENFLAGS", m_sArmRegister[15]).formatstr("%11s").noshow(); + + m_icountptr = &m_icount; +} + + +void arm_cpu_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + static const char *s[4] = { "USER", "FIRQ", "IRQ ", "SVC " }; + + switch (entry.index()) + { + case STATE_GENFLAGS: + strprintf(str, "%c%c%c%c%c%c %s", + (m_sArmRegister[15] & N_MASK) ? 'N' : '-', + (m_sArmRegister[15] & Z_MASK) ? 'Z' : '-', + (m_sArmRegister[15] & C_MASK) ? 'C' : '-', + (m_sArmRegister[15] & V_MASK) ? 'V' : '-', + (m_sArmRegister[15] & I_MASK) ? 'I' : '-', + (m_sArmRegister[15] & F_MASK) ? 'F' : '-', + s[m_sArmRegister[15] & 3] ); + break; + } +} + + +/***************************************************************************/ + +void arm_cpu_device::HandleBranch( UINT32 insn ) +{ + UINT32 off = (insn & INSN_BRANCH) << 2; + + /* Save PC into LR if this is a branch with link */ + if (insn & INSN_BL) + { + SetRegister(14,R15 + 4); + } + + /* Sign-extend the 24-bit offset in our calculations */ + if (off & 0x2000000u) + { + R15 -= ((~(off | 0xfc000000u)) + 1) - 8; + } + else + { + R15 += off + 8; + } + m_icount -= 2 * S_CYCLE + N_CYCLE; +} + + +void arm_cpu_device::HandleMemSingle( UINT32 insn ) +{ + UINT32 rn, rnv, off, rd; + + /* Fetch the offset */ + if (insn & INSN_I) + { + off = decodeShift(insn, NULL); + } + else + { + off = insn & INSN_SDT_IMM; + } + + /* Calculate Rn, accounting for PC */ + rn = (insn & INSN_RN) >> INSN_RN_SHIFT; + +// if (rn==0xf) logerror("%08x: Source R15\n",R15); + + if (insn & INSN_SDT_P) + { + /* Pre-indexed addressing */ + if (insn & INSN_SDT_U) + { + if (rn != eR15) + rnv = (GetRegister(rn) + off); + else + rnv = (R15 & ADDRESS_MASK) + off; + } + else + { + if (rn != eR15) + rnv = (GetRegister(rn) - off); + else + rnv = (R15 & ADDRESS_MASK) - off; + } + + if (insn & INSN_SDT_W) + { + SetRegister(rn,rnv); + if (ARM_DEBUG_CORE && rn == eR15) + logerror("writeback R15 %08x\n", R15); + } + else if (rn == eR15) + { + rnv = rnv + 8; + } + } + else + { + /* Post-indexed addressing */ + if (rn == eR15) + { + rnv = (R15 & ADDRESS_MASK) + 8; + } + else + { + rnv = GetRegister(rn); + } + } + + /* Do the transfer */ + rd = (insn & INSN_RD) >> INSN_RD_SHIFT; + if (insn & INSN_SDT_L) + { + /* Load */ + m_icount -= S_CYCLE + I_CYCLE + N_CYCLE; + if (insn & INSN_SDT_B) + { + if (ARM_DEBUG_CORE && rd == eR15) + logerror("read byte R15 %08x\n", R15); + SetRegister(rd,(UINT32) cpu_read8(rnv) ); + } + else + { + if (rd == eR15) + { + R15 = (cpu_read32(rnv) & ADDRESS_MASK) | (R15 & PSR_MASK) | (R15 & MODE_MASK); + + /* + The docs are explicit in that the bottom bits should be masked off + when writing to R15 in this way, however World Cup Volleyball 95 has + an example of an unaligned jump (bottom bits = 2) where execution + should definitely continue from the rounded up address. + + In other cases, 4 is subracted from R15 here to account for pipelining. + */ + if ((cpu_read32(rnv)&3)==0) + R15 -= 4; + + m_icount -= S_CYCLE + N_CYCLE; + } + else + { + SetRegister(rd, cpu_read32(rnv)); + } + } + } + else + { + /* Store */ + m_icount -= 2 * N_CYCLE; + if (insn & INSN_SDT_B) + { + if (ARM_DEBUG_CORE && rd==eR15) + logerror("Wrote R15 in byte mode\n"); + + cpu_write8(rnv, (UINT8) GetRegister(rd) & 0xffu); + } + else + { + if (ARM_DEBUG_CORE && rd==eR15) + logerror("Wrote R15 in 32bit mode\n"); + + cpu_write32(rnv, rd == eR15 ? R15 + 8 : GetRegister(rd)); + } + } + + /* Do post-indexing writeback */ + if (!(insn & INSN_SDT_P)/* && (insn&INSN_SDT_W)*/) + { + if (insn & INSN_SDT_U) + { + /* Writeback is applied in pipeline, before value is read from mem, + so writeback is effectively ignored */ + if (rd==rn) + { + SetRegister(rn,GetRegister(rd)); + } + else + { + if ((insn&INSN_SDT_W)!=0) + logerror("%08x: RegisterWritebackIncrement %d %d %d\n",R15,(insn & INSN_SDT_P)!=0,(insn&INSN_SDT_W)!=0,(insn & INSN_SDT_U)!=0); + + SetRegister(rn,(rnv + off)); + } + } + else + { + /* Writeback is applied in pipeline, before value is read from mem, + so writeback is effectively ignored */ + if (rd==rn) + { + SetRegister(rn,GetRegister(rd)); + } + else + { + SetRegister(rn,(rnv - off)); + + if ((insn&INSN_SDT_W)!=0) + logerror("%08x: RegisterWritebackDecrement %d %d %d\n",R15,(insn & INSN_SDT_P)!=0,(insn&INSN_SDT_W)!=0,(insn & INSN_SDT_U)!=0); + } + } + } +} /* HandleMemSingle */ + +#define IsNeg(i) ((i) >> 31) +#define IsPos(i) ((~(i)) >> 31) + +/* Set NZCV flags for ADDS / SUBS */ + +#define HandleALUAddFlags(rd, rn, op2) \ + if (insn & INSN_S) \ + R15 = \ + ((R15 &~ (N_MASK | Z_MASK | V_MASK | C_MASK)) \ + | (((!SIGN_BITS_DIFFER(rn, op2)) && SIGN_BITS_DIFFER(rn, rd)) \ + << V_BIT) \ + | (((~(rn)) < (op2)) << C_BIT) \ + | HandleALUNZFlags(rd)) \ + + 4; \ + else R15 += 4; + +#define HandleALUSubFlags(rd, rn, op2) \ + if (insn & INSN_S) \ + R15 = \ + ((R15 &~ (N_MASK | Z_MASK | V_MASK | C_MASK)) \ + | ((SIGN_BITS_DIFFER(rn, op2) && SIGN_BITS_DIFFER(rn, rd)) \ + << V_BIT) \ + | (((IsNeg(rn) & IsPos(op2)) | (IsNeg(rn) & IsPos(rd)) | (IsPos(op2) & IsPos(rd))) ? C_MASK : 0) \ + | HandleALUNZFlags(rd)) \ + + 4; \ + else R15 += 4; + +/* Set NZC flags for logical operations. */ + +#define HandleALUNZFlags(rd) \ + (((rd) & SIGN_BIT) | ((!(rd)) << Z_BIT)) + +#define HandleALULogicalFlags(rd, sc) \ + if (insn & INSN_S) \ + R15 = ((R15 &~ (N_MASK | Z_MASK | C_MASK)) \ + | HandleALUNZFlags(rd) \ + | (((sc) != 0) << C_BIT)) + 4; \ + else R15 += 4; + +void arm_cpu_device::HandleALU( UINT32 insn ) +{ + UINT32 op2, sc=0, rd, rn, opcode; + UINT32 by, rdn; + + opcode = (insn & INSN_OPCODE) >> INSN_OPCODE_SHIFT; + m_icount -= S_CYCLE; + + rd = 0; + rn = 0; + + /* Construct Op2 */ + if (insn & INSN_I) + { + /* Immediate constant */ + by = (insn & INSN_OP2_ROTATE) >> INSN_OP2_ROTATE_SHIFT; + if (by) + { + op2 = ROR(insn & INSN_OP2_IMM, by << 1); + sc = op2 & SIGN_BIT; + } + else + { + op2 = insn & INSN_OP2; + sc = R15 & C_MASK; + } + } + else + { + op2 = decodeShift(insn, (insn & INSN_S) ? &sc : NULL); + + if (!(insn & INSN_S)) + sc=0; + } + + /* Calculate Rn to account for pipelining */ + if ((opcode & 0xd) != 0xd) /* No Rn in MOV */ + { + if ((rn = (insn & INSN_RN) >> INSN_RN_SHIFT) == eR15) + { + if (ARM_DEBUG_CORE) + logerror("%08x: Pipelined R15 (Shift %d)\n",R15,(insn&INSN_I?8:insn&0x10u?12:12)); + + /* Docs strongly suggest the mode bits should be included here, but it breaks Captain + America, as it starts doing unaligned reads */ + rn=(R15+8)&ADDRESS_MASK; + } + else + { + rn = GetRegister(rn); + } + } + + /* Perform the operation */ + switch ((insn & INSN_OPCODE) >> INSN_OPCODE_SHIFT) + { + /* Arithmetic operations */ + case OPCODE_SBC: + rd = (rn - op2 - (R15 & C_MASK ? 0 : 1)); + HandleALUSubFlags(rd, rn, op2); + break; + case OPCODE_CMP: + case OPCODE_SUB: + rd = (rn - op2); + HandleALUSubFlags(rd, rn, op2); + break; + case OPCODE_RSC: + rd = (op2 - rn - (R15 & C_MASK ? 0 : 1)); + HandleALUSubFlags(rd, op2, rn); + break; + case OPCODE_RSB: + rd = (op2 - rn); + HandleALUSubFlags(rd, op2, rn); + break; + case OPCODE_ADC: + rd = (rn + op2 + ((R15 & C_MASK) >> C_BIT)); + HandleALUAddFlags(rd, rn, op2); + break; + case OPCODE_CMN: + case OPCODE_ADD: + rd = (rn + op2); + HandleALUAddFlags(rd, rn, op2); + break; + /* Logical operations */ + case OPCODE_AND: + case OPCODE_TST: + rd = rn & op2; + HandleALULogicalFlags(rd, sc); + break; + case OPCODE_BIC: + rd = rn &~ op2; + HandleALULogicalFlags(rd, sc); + break; + case OPCODE_TEQ: + case OPCODE_EOR: + rd = rn ^ op2; + HandleALULogicalFlags(rd, sc); + break; + case OPCODE_ORR: + rd = rn | op2; + HandleALULogicalFlags(rd, sc); + break; + case OPCODE_MOV: + rd = op2; + HandleALULogicalFlags(rd, sc); + break; + case OPCODE_MVN: + rd = (~op2); + HandleALULogicalFlags(rd, sc); + break; + } + + /* Put the result in its register if not a test */ + rdn = (insn & INSN_RD) >> INSN_RD_SHIFT; + if ((opcode & 0xc) != 0x8) + { + if (rdn == eR15 && !(insn & INSN_S)) + { + /* Merge the old NZCV flags into the new PC value */ + R15 = (rd & ADDRESS_MASK) | (R15 & PSR_MASK) | (R15 & IRQ_MASK) | (R15&MODE_MASK); + m_icount -= S_CYCLE + N_CYCLE; + } + else + { + if (rdn==eR15) + { + /* S Flag is set - update PSR & mode if in non-user mode only */ + if ((R15&MODE_MASK)!=0) + { + SetRegister(rdn,rd); + } + else + { + SetRegister(rdn,(rd&ADDRESS_MASK) | (rd&PSR_MASK) | (R15&IRQ_MASK) | (R15&MODE_MASK)); + } + m_icount -= S_CYCLE + N_CYCLE; + } + else + { + SetRegister(rdn,rd); + } + } + /* TST & TEQ can affect R15 (the condition code register) with the S bit set */ + } + else if ((rdn==eR15) && (insn & INSN_S)) + { + // update only the flags + if ((R15&MODE_MASK)!=0) + { + // combine the flags from rd with the address from R15 + rd &= ~ADDRESS_MASK; + rd |= (R15 & ADDRESS_MASK); + SetRegister(rdn,rd); + } + else + { + // combine the flags from rd with the address from R15 + rd &= ~ADDRESS_MASK; // clear address part of RD + rd |= (R15 & ADDRESS_MASK); // RD = address part of R15 + SetRegister(rdn,(rd&ADDRESS_MASK) | (rd&PSR_MASK) | (R15&IRQ_MASK) | (R15&MODE_MASK)); + } + m_icount -= S_CYCLE + N_CYCLE; + } +} + +void arm_cpu_device::HandleMul( UINT32 insn) +{ + UINT32 r; + + m_icount -= S_CYCLE + I_CYCLE; + /* should be: + Range of Rs Number of cycles + + &0 -- &1 1S + 1I + &2 -- &7 1S + 2I + &8 -- &1F 1S + 3I + &20 -- &7F 1S + 4I + &80 -- &1FF 1S + 5I + &200 -- &7FF 1S + 6I + &800 -- &1FFF 1S + 7I + &2000 -- &7FFF 1S + 8I + &8000 -- &1FFFF 1S + 9I + &20000 -- &7FFFF 1S + 10I + &80000 -- &1FFFFF 1S + 11I + &200000 -- &7FFFFF 1S + 12I + &800000 -- &1FFFFFF 1S + 13I + &2000000 -- &7FFFFFF 1S + 14I + &8000000 -- &1FFFFFFF 1S + 15I + &20000000 -- &FFFFFFFF 1S + 16I + */ + + /* Do the basic multiply of Rm and Rs */ + r = GetRegister( insn&INSN_MUL_RM ) * + GetRegister( (insn&INSN_MUL_RS)>>INSN_MUL_RS_SHIFT ); + + if (ARM_DEBUG_CORE && ((insn&INSN_MUL_RM)==0xf + || ((insn&INSN_MUL_RS)>>INSN_MUL_RS_SHIFT )==0xf + || ((insn&INSN_MUL_RN)>>INSN_MUL_RN_SHIFT)==0xf) + ) + logerror("%08x: R15 used in mult\n",R15); + + /* Add on Rn if this is a MLA */ + if (insn & INSN_MUL_A) + { + r += GetRegister((insn&INSN_MUL_RN)>>INSN_MUL_RN_SHIFT); + } + + /* Write the result */ + SetRegister((insn&INSN_MUL_RD)>>INSN_MUL_RD_SHIFT,r); + + /* Set N and Z if asked */ + if( insn & INSN_S ) + { + R15 = (R15 &~ (N_MASK | Z_MASK)) | HandleALUNZFlags(r); + } +} + + +int arm_cpu_device::loadInc(UINT32 pat, UINT32 rbv, UINT32 s) +{ + int i,result; + + result = 0; + for( i=0; i<16; i++ ) + { + if( (pat>>i)&1 ) + { + if (i==15) + { + if (s) /* Pull full contents from stack */ + SetRegister( 15, cpu_read32(rbv+=4) ); + else /* Pull only address, preserve mode & status flags */ + SetRegister( 15, (R15&PSR_MASK) | (R15&IRQ_MASK) | (R15&MODE_MASK) | ((cpu_read32(rbv+=4))&ADDRESS_MASK) ); + } + else + SetRegister( i, cpu_read32(rbv+=4) ); + + result++; + } + } + return result; +} + + +int arm_cpu_device::loadDec(UINT32 pat, UINT32 rbv, UINT32 s, UINT32* deferredR15, int* defer) +{ + int i,result; + + result = 0; + for( i=15; i>=0; i-- ) + { + if( (pat>>i)&1 ) + { + if (i==15) + { + *defer=1; + if (s) /* Pull full contents from stack */ + *deferredR15=cpu_read32(rbv-=4); + else /* Pull only address, preserve mode & status flags */ + *deferredR15=(R15&PSR_MASK) | (R15&IRQ_MASK) | (R15&MODE_MASK) | ((cpu_read32(rbv-=4))&ADDRESS_MASK); + } + else + SetRegister( i, cpu_read32(rbv -=4) ); + result++; + } + } + return result; +} + + +int arm_cpu_device::storeInc(UINT32 pat, UINT32 rbv) +{ + int i,result; + + result = 0; + for( i=0; i<16; i++ ) + { + if( (pat>>i)&1 ) + { + if (ARM_DEBUG_CORE && i==15) /* R15 is plus 12 from address of STM */ + logerror("%08x: StoreInc on R15\n",R15); + + cpu_write32( rbv += 4, GetRegister(i) ); + result++; + } + } + return result; +} /* storeInc */ + + +int arm_cpu_device::storeDec(UINT32 pat, UINT32 rbv) +{ + int i,result; + + result = 0; + for( i=15; i>=0; i-- ) + { + if( (pat>>i)&1 ) + { + if (ARM_DEBUG_CORE && i==15) /* R15 is plus 12 from address of STM */ + logerror("%08x: StoreDec on R15\n",R15); + + cpu_write32( rbv -= 4, GetRegister(i) ); + result++; + } + } + return result; +} /* storeDec */ + + +void arm_cpu_device::HandleMemBlock( UINT32 insn ) +{ + UINT32 rb = (insn & INSN_RN) >> INSN_RN_SHIFT; + UINT32 rbp = GetRegister(rb); + int result; + + if (ARM_DEBUG_CORE && insn & INSN_BDT_S) + logerror("%08x: S Bit set in MEMBLOCK\n",R15); + + if (insn & INSN_BDT_L) + { + /* Loading */ + if (insn & INSN_BDT_U) + { + int mode = MODE; + + /* Incrementing */ + if (!(insn & INSN_BDT_P)) rbp = rbp + (- 4); + + result = loadInc( insn & 0xffff, rbp, insn&INSN_BDT_S ); + + if (insn & 0x8000) + { + R15-=4; + m_icount -= S_CYCLE + N_CYCLE; + } + + if (insn & INSN_BDT_W) + { + /* Arm docs notes: The base register can always be loaded without any problems. + However, don't specify writeback if the base register is being loaded - + you can't end up with both a written-back value and a loaded value in the base register! + + However - Fighter's History does exactly that at 0x121e4 (LDMUW [R13], { R13-R15 })! + + This emulator implementation skips applying writeback in this case, which is confirmed + correct for this situation, but that is not necessarily true for all ARM hardware + implementations (the results are officially undefined). + */ + + if (ARM_DEBUG_CORE && rb==15) + logerror("%08x: Illegal LDRM writeback to r15\n",R15); + + if ((insn&(1<> INSN_OP2_SHIFT_SHIFT; + UINT32 rm = GetRegister( insn & INSN_OP2_RM ); + UINT32 t = (insn & INSN_OP2_SHIFT_TYPE) >> INSN_OP2_SHIFT_TYPE_SHIFT; + + if ((insn & INSN_OP2_RM)==0xf) + { + /* If hardwired shift, then PC is 8 bytes ahead, else if register shift + is used, then 12 bytes - TODO?? */ + rm+=8; + } + + /* All shift types ending in 1 are Rk, not #k */ + if( t & 1 ) + { +// logerror("%08x: RegShift %02x %02x\n",R15, k>>1,GetRegister(k >> 1)); + if (ARM_DEBUG_CORE && (insn&0x80)==0x80) + logerror("%08x: RegShift ERROR (p36)\n",R15); + + //see p35 for check on this + k = GetRegister(k >> 1)&0x1f; + m_icount -= S_CYCLE; + if( k == 0 ) /* Register shift by 0 is a no-op */ + { +// logerror("%08x: NO-OP Regshift\n",R15); + if (pCarry) *pCarry = R15 & C_MASK; + return rm; + } + } + /* Decode the shift type and perform the shift */ + switch (t >> 1) + { + case 0: /* LSL */ + if (pCarry) + { + *pCarry = k ? (rm & (1 << (32 - k))) : (R15 & C_MASK); + } + return k ? LSL(rm, k) : rm; + + case 1: /* LSR */ + if (k == 0 || k == 32) + { + if (pCarry) *pCarry = rm & SIGN_BIT; + return 0; + } + else if (k > 32) + { + if (pCarry) *pCarry = 0; + return 0; + } + else + { + if (pCarry) *pCarry = (rm & (1 << (k - 1))); + return LSR(rm, k); + } + + case 2: /* ASR */ + if (k == 0 || k > 32) + k = 32; + if (pCarry) *pCarry = (rm & (1 << (k - 1))); + if (k >= 32) + return rm & SIGN_BIT ? 0xffffffffu : 0; + else + { + if (rm & SIGN_BIT) + return LSR(rm, k) | (0xffffffffu << (32 - k)); + else + return LSR(rm, k); + } + + case 3: /* ROR and RRX */ + if (k) + { + while (k > 32) k -= 32; + if (pCarry) *pCarry = rm & SIGN_BIT; + return ROR(rm, k); + } + else + { + if (pCarry) *pCarry = (rm & 1); + return LSR(rm, 1) | ((R15 & C_MASK) << 2); + } + } + + logerror("%08x: Decodeshift error\n",R15); + return 0; +} /* decodeShift */ + + +UINT32 arm_cpu_device::BCDToDecimal(UINT32 value) +{ + UINT32 accumulator = 0; + UINT32 multiplier = 1; + int i; + + for(i = 0; i < 8; i++) + { + accumulator += (value & 0xF) * multiplier; + + multiplier *= 10; + value >>= 4; + } + + return accumulator; +} + + +UINT32 arm_cpu_device::DecimalToBCD(UINT32 value) +{ + UINT32 accumulator = 0; + UINT32 divisor = 10; + int i; + + for(i = 0; i < 8; i++) + { + UINT32 temp; + + temp = value % divisor; + value -= temp; + temp /= divisor / 10; + + accumulator += temp << (i * 4); + + divisor *= 10; + } + + return accumulator; +} + +void arm_cpu_device::HandleCoProVL86C020( UINT32 insn ) +{ + UINT32 rn=(insn>>12)&0xf; + UINT32 crn=(insn>>16)&0xf; + + m_icount -= S_CYCLE; + + /* MRC - transfer copro register to main register */ + if( (insn&0x0f100010)==0x0e100010 ) + { + if(crn == 0) // ID, read only + { + /* + 0x41<<24 <- Designer code, Acorn Computer Ltd. + 0x56<<16 <- Manufacturer code, VLSI Technology Inc. + 0x03<<8 <- Part type, VLC86C020 + 0x00<<0 <- Revision number, 0 + */ + SetRegister(rn, 0x41560300); + //debugger_break(machine()); + } + else + SetRegister(rn, m_coproRegister[crn]); + + } + /* MCR - transfer main register to copro register */ + else if( (insn&0x0f100010)==0x0e000010 ) + { + if(crn != 0) + m_coproRegister[crn]=GetRegister(rn); + + //printf("%08x: VL86C020 copro instruction write %08x %d %d\n", R15 & 0x3ffffff, insn,rn,crn); + } + else + { + printf("%08x: Unimplemented VL86C020 copro instruction %08x %d %d\n", R15 & 0x3ffffff, insn,rn,crn); + debugger_break(machine()); + } +} + +void arm_cpu_device::HandleCoPro( UINT32 insn ) +{ + UINT32 rn=(insn>>12)&0xf; + UINT32 crn=(insn>>16)&0xf; + + m_icount -= S_CYCLE; + + /* MRC - transfer copro register to main register */ + if( (insn&0x0f100010)==0x0e100010 ) + { + SetRegister(rn, m_coproRegister[crn]); + + if (ARM_DEBUG_COPRO) + logerror("%08x: Copro read CR%d (%08x) to R%d\n", R15, crn, m_coproRegister[crn], rn); + } + /* MCR - transfer main register to copro register */ + else if( (insn&0x0f100010)==0x0e000010 ) + { + m_coproRegister[crn]=GetRegister(rn); + + /* Data East 156 copro specific - trigger BCD operation */ + if (crn==2) + { + if (m_coproRegister[crn]==0) + { + /* Unpack BCD */ + int v0=BCDToDecimal(m_coproRegister[0]); + int v1=BCDToDecimal(m_coproRegister[1]); + + /* Repack vcd */ + m_coproRegister[5]=DecimalToBCD(v0+v1); + + if (ARM_DEBUG_COPRO) + logerror("Cmd: Add 0 + 1, result in 5 (%08x + %08x == %08x)\n", v0, v1, m_coproRegister[5]); + } + else if (m_coproRegister[crn]==1) + { + /* Unpack BCD */ + int v0=BCDToDecimal(m_coproRegister[0]); + int v1=BCDToDecimal(m_coproRegister[1]); + + /* Repack vcd */ + m_coproRegister[5]=DecimalToBCD(v0*v1); + + if (ARM_DEBUG_COPRO) + logerror("Cmd: Multiply 0 * 1, result in 5 (%08x * %08x == %08x)\n", v0, v1, m_coproRegister[5]); + } + else if (m_coproRegister[crn]==3) + { + /* Unpack BCD */ + int v0=BCDToDecimal(m_coproRegister[0]); + int v1=BCDToDecimal(m_coproRegister[1]); + + /* Repack vcd */ + m_coproRegister[5]=DecimalToBCD(v0-v1); + + if (ARM_DEBUG_COPRO) + logerror("Cmd: Sub 0 - 1, result in 5 (%08x - %08x == %08x)\n", v0, v1, m_coproRegister[5]); + } + else + { + logerror("Unknown bcd copro command %08x\n", m_coproRegister[crn]); + } + } + + if (ARM_DEBUG_COPRO) + logerror("%08x: Copro write R%d (%08x) to CR%d\n", R15, rn, GetRegister(rn), crn); + } + /* CDP - perform copro operation */ + else if( (insn&0x0f000010)==0x0e000000 ) + { + /* Data East 156 copro specific divider - result in reg 3/4 */ + if (m_coproRegister[1]) + { + m_coproRegister[3]=m_coproRegister[0] / m_coproRegister[1]; + m_coproRegister[4]=m_coproRegister[0] % m_coproRegister[1]; + } + else + { + /* Unverified */ + m_coproRegister[3]=0xffffffff; + m_coproRegister[4]=0xffffffff; + } + + if (ARM_DEBUG_COPRO) + logerror("%08x: Copro cdp (%08x) (3==> %08x, 4==> %08x)\n", R15, insn, m_coproRegister[3], m_coproRegister[4]); + } + else + { + logerror("%08x: Unimplemented copro instruction %08x\n", R15, insn); + } +} + + +offs_t arm_cpu_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( arm ); + return CPU_DISASSEMBLE_NAME(arm)(this, buffer, pc, oprom, opram, options); +} + + +offs_t arm_be_cpu_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( arm_be ); + return CPU_DISASSEMBLE_NAME(arm_be)(this, buffer, pc, oprom, opram, options); +} diff --git a/src/devices/cpu/arm/arm.h b/src/devices/cpu/arm/arm.h new file mode 100644 index 00000000000..824ac1b69db --- /dev/null +++ b/src/devices/cpu/arm/arm.h @@ -0,0 +1,124 @@ +// license:BSD-3-Clause +// copyright-holders:Bryan McPhail +#pragma once + +#ifndef __ARM_H__ +#define __ARM_H__ + +/**************************************************************************************************** + * INTERRUPT CONSTANTS + ***************************************************************************************************/ + +#define ARM_IRQ_LINE 0 +#define ARM_FIRQ_LINE 1 + +/**************************************************************************************************** + * PUBLIC FUNCTIONS + ***************************************************************************************************/ + +enum +{ + ARM_COPRO_TYPE_UNKNOWN_CP15 = 0, + ARM_COPRO_TYPE_VL86C020 +}; + +#define MCFG_ARM_COPRO(_type) \ + arm_cpu_device::set_copro_type(*device, _type); + + +enum +{ + ARM32_PC=0, + ARM32_R0, ARM32_R1, ARM32_R2, ARM32_R3, ARM32_R4, ARM32_R5, ARM32_R6, ARM32_R7, + ARM32_R8, ARM32_R9, ARM32_R10, ARM32_R11, ARM32_R12, ARM32_R13, ARM32_R14, ARM32_R15, + ARM32_FR8, ARM32_FR9, ARM32_FR10, ARM32_FR11, ARM32_FR12, ARM32_FR13, ARM32_FR14, + ARM32_IR13, ARM32_IR14, ARM32_SR13, ARM32_SR14 +}; + + +class arm_cpu_device : public cpu_device +{ +public: + // construction/destruction + arm_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + arm_cpu_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source, endianness_t endianness); + + static void set_copro_type(device_t &device, int type) { downcast(device).m_copro_type = type; } + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_execute_interface overrides + virtual UINT32 execute_min_cycles() const { return 3; } + virtual UINT32 execute_max_cycles() const { return 4; } + virtual UINT32 execute_input_lines() const { return 2; } + virtual void execute_run(); + virtual void execute_set_input(int inputnum, int state); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const { return (spacenum == AS_PROGRAM) ? &m_program_config : NULL; } + + // device_state_interface overrides + void state_string_export(const device_state_entry &entry, std::string &str); + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const { return 4; } + virtual UINT32 disasm_max_opcode_bytes() const { return 4; } + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + + address_space_config m_program_config; + + int m_icount; + UINT32 m_sArmRegister[27]; + UINT32 m_coproRegister[16]; + UINT8 m_pendingIrq; + UINT8 m_pendingFiq; + address_space *m_program; + direct_read_data *m_direct; + endianness_t m_endian; + UINT8 m_copro_type; + + void cpu_write32( int addr, UINT32 data ); + void cpu_write8( int addr, UINT8 data ); + UINT32 cpu_read32( int addr ); + UINT8 cpu_read8( int addr ); + UINT32 GetRegister( int rIndex ); + void SetRegister( int rIndex, UINT32 value ); + UINT32 GetModeRegister( int mode, int rIndex ); + void SetModeRegister( int mode, int rIndex, UINT32 value ); + void HandleALU(UINT32 insn); + void HandleMul(UINT32 insn); + void HandleBranch(UINT32 insn); + void HandleMemSingle(UINT32 insn); + void HandleMemBlock(UINT32 insn); + void HandleCoPro(UINT32 insn); + void HandleCoProVL86C020(UINT32 insn); + UINT32 decodeShift(UINT32 insn, UINT32 *pCarry); + void arm_check_irq_state(); + int loadInc(UINT32 pat, UINT32 rbv, UINT32 s); + int loadDec(UINT32 pat, UINT32 rbv, UINT32 s, UINT32* deferredR15, int* defer); + int storeInc(UINT32 pat, UINT32 rbv); + int storeDec(UINT32 pat, UINT32 rbv); + static UINT32 BCDToDecimal(UINT32 value); + static UINT32 DecimalToBCD(UINT32 value); +}; + + +class arm_be_cpu_device : public arm_cpu_device +{ +public: + // construction/destruction + arm_be_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); +}; + + +extern const device_type ARM; +extern const device_type ARM_BE; + + +#endif /* __ARM_H__ */ diff --git a/src/devices/cpu/arm/armdasm.c b/src/devices/cpu/arm/armdasm.c new file mode 100644 index 00000000000..83860b22aff --- /dev/null +++ b/src/devices/cpu/arm/armdasm.c @@ -0,0 +1,408 @@ +// license:BSD-3-Clause +// copyright-holders:Bryan McPhail,Phil Stroffolino +/* + ARM 2/3 disassembler + + (c) 2002-2006 Bryan McPhail (bmcphail@tendril.co.uk) and Phil Stroffolino +*/ + +#include "emu.h" +#include "arm.h" + +static char *WriteImmediateOperand( char *pBuf, UINT32 opcode ) +{ + /* rrrrbbbbbbbb */ + UINT32 imm; + int r; + + imm = opcode&0xff; + r = ((opcode>>8)&0xf)*2; + imm = (imm>>r)|(r?(imm<<(32-r)):0); + pBuf += sprintf( pBuf, ", #$%x", imm ); + return pBuf; +} + +static char *WriteDataProcessingOperand( char *pBuf, UINT32 opcode, int printOp0, int printOp1, int printOp2 ) +{ + /* ccccctttmmmm */ + static const char *const pRegOp[4] = { "LSL","LSR","ASR","ROR" }; + + if (printOp0) + pBuf += sprintf(pBuf,"R%d, ", (opcode>>12)&0xf); + if (printOp1) + pBuf += sprintf(pBuf,"R%d, ", (opcode>>16)&0xf); + + /* Immediate Op2 */ + if( opcode&0x02000000 ) + return WriteImmediateOperand(pBuf-2,opcode); + + /* Register Op2 */ + if (printOp2) + pBuf += sprintf(pBuf,"R%d, ", (opcode>>0)&0xf); + + pBuf += sprintf(pBuf, "%s ", pRegOp[(opcode>>5)&3] ); + + if( opcode&0x10 ) /* Shift amount specified in bottom bits of RS */ + { + pBuf += sprintf( pBuf, "R%d", (opcode>>8)&0xf ); + } + else /* Shift amount immediate 5 bit unsigned integer */ + { + int c=(opcode>>7)&0x1f; + if( c==0 ) c = 32; + pBuf += sprintf( pBuf, "#%d", c ); + } + return pBuf; +} + +static char *WriteRegisterOperand1( char *pBuf, UINT32 opcode ) +{ + /* ccccctttmmmm */ + static const char *const pRegOp[4] = { "LSL","LSR","ASR","ROR" }; + + pBuf += sprintf( + pBuf, + ", R%d %s ", /* Operand 1 register, Operand 2 register, shift type */ + (opcode>> 0)&0xf, + pRegOp[(opcode>>5)&3] ); + + if( opcode&0x10 ) /* Shift amount specified in bottom bits of RS */ + { + pBuf += sprintf( pBuf, "R%d", (opcode>>7)&0xf ); + } + else /* Shift amount immediate 5 bit unsigned integer */ + { + int c=(opcode>>7)&0x1f; + if( c==0 ) c = 32; + pBuf += sprintf( pBuf, "#%d", c ); + } + return pBuf; +} /* WriteRegisterOperand */ + + +static char *WriteBranchAddress( char *pBuf, UINT32 pc, UINT32 opcode ) +{ + opcode &= 0x00ffffff; + if( opcode&0x00800000 ) + { + opcode |= 0xff000000; /* sign-extend */ + } + pc += 8+4*opcode; + sprintf( pBuf, "$%x", pc ); + return pBuf; +} /* WriteBranchAddress */ + +static char *WritePadding( char *pBuf, const char *pBuf0 ) +{ + pBuf0 += 8; + while( pBuf>28]; + pBuf0 = pBuf; + + if( (opcode&0x0fc000f0)==0x00000090u ) + { + /* multiply */ + /* xxxx0000 00ASdddd nnnnssss 1001mmmm */ + if( opcode&0x00200000 ) + { + pBuf += sprintf( pBuf, "MLA" ); + } + else + { + pBuf += sprintf( pBuf, "MUL" ); + } + pBuf += sprintf( pBuf, "%s", pConditionCode ); + if( opcode&0x00100000 ) + { + *pBuf++ = 'S'; + } + pBuf = WritePadding( pBuf, pBuf0 ); + + pBuf += sprintf( pBuf, + "R%d, R%d, R%d", + (opcode>>16)&0xf, + (opcode&0xf), + (opcode>>8)&0xf ); + + if( opcode&0x00200000 ) + { + pBuf += sprintf( pBuf, ", R%d", (opcode>>12)&0xf ); + } + } + else if( (opcode&0x0c000000)==0 ) + { + int op=(opcode>>21)&0xf; + + /* Data Processing */ + /* xxxx001a aaaSnnnn ddddrrrr bbbbbbbb */ + /* xxxx000a aaaSnnnn ddddcccc ctttmmmm */ + + pBuf += sprintf( + pBuf, "%s%s", + pOperation[op], + pConditionCode ); + + if( (opcode&0x01000000) ) + { + *pBuf++ = 'S'; + } + + pBuf = WritePadding( pBuf, pBuf0 ); + + switch (op) { + case 0x00: + case 0x01: + case 0x02: + case 0x03: + case 0x04: + case 0x05: + case 0x06: + case 0x07: + case 0x0c: + case 0x0e: + WriteDataProcessingOperand(pBuf, opcode, 1, 1, 1); + break; + case 0x08: + case 0x09: + case 0x0a: + case 0x0b: + WriteDataProcessingOperand(pBuf, opcode, 0, 1, 1); + break; + case 0x0d: + /* look for mov pc,lr */ + if (((opcode >> 12) & 0x0f) == 15 && ((opcode >> 0) & 0x0f) == 14 && (opcode & 0x02000000) == 0) + dasmflags = DASMFLAG_STEP_OUT; + case 0x0f: + WriteDataProcessingOperand(pBuf, opcode, 1, 0, 1); + break; + } + } + else if( (opcode&0x0c000000)==0x04000000 ) + { + /* Data Transfer */ + + /* xxxx010P UBWLnnnn ddddoooo oooooooo Immediate form */ + /* xxxx011P UBWLnnnn ddddcccc ctt0mmmm Register form */ + if( opcode&0x00100000 ) + { + pBuf += sprintf( pBuf, "LDR" ); + } + else + { + pBuf += sprintf( pBuf, "STR" ); + } + pBuf += sprintf( pBuf, "%s", pConditionCode ); + + if( opcode&0x00400000 ) + { + pBuf += sprintf( pBuf, "B" ); + } + + if( opcode&0x00200000 ) + { + /* writeback addr */ + if( opcode&0x01000000 ) + { + /* pre-indexed addressing */ + pBuf += sprintf( pBuf, "!" ); + } + else + { + /* post-indexed addressing */ + pBuf += sprintf( pBuf, "T" ); + } + } + + pBuf = WritePadding( pBuf, pBuf0 ); + pBuf += sprintf( pBuf, "R%d, [R%d", + (opcode>>12)&0xf, (opcode>>16)&0xf ); + + if( opcode&0x02000000 ) + { + /* register form */ + pBuf = WriteRegisterOperand1( pBuf, opcode ); + pBuf += sprintf( pBuf, "]" ); + } + else + { + /* immediate form */ + pBuf += sprintf( pBuf, "]" ); + if( opcode&0x00800000 ) + { + pBuf += sprintf( pBuf, ", #$%x", opcode&0xfff ); + } + else + { + pBuf += sprintf( pBuf, ", -#$%x", opcode&0xfff ); + } + } + } + else if( (opcode&0x0e000000) == 0x08000000 ) + { + /* xxxx100P USWLnnnn llllllll llllllll */ + /* Block Data Transfer */ + + if( opcode&0x00100000 ) + { + pBuf += sprintf( pBuf, "LDM" ); + } + else + { + pBuf += sprintf( pBuf, "STM" ); + } + pBuf += sprintf( pBuf, "%s", pConditionCode ); + + if( opcode&0x01000000 ) + { + pBuf += sprintf( pBuf, "P" ); + } + if( opcode&0x00800000 ) + { + pBuf += sprintf( pBuf, "U" ); + } + if( opcode&0x00400000 ) + { + pBuf += sprintf( pBuf, "^" ); + } + if( opcode&0x00200000 ) + { + pBuf += sprintf( pBuf, "W" ); + } + + pBuf = WritePadding( pBuf, pBuf0 ); + pBuf += sprintf( pBuf, "[R%d], {",(opcode>>16)&0xf); + + { + int j=0,last=0,found=0; + for (j=0; j<16; j++) { + if (opcode&(1<>12)&0xf, (opcode>>16)&0xf, (opcode>>0)&0xf, (opcode>>5)&0x7); + /* Nb: full form should be o, p, R, CR, CRM, q */ + } + else if( (opcode&0x0f000010)==0x0e000000 ) + { + pBuf += sprintf( pBuf, "CDP" ); + pBuf += sprintf( pBuf, "%s", pConditionCode ); + pBuf = WritePadding( pBuf, pBuf0 ); + pBuf += sprintf( pBuf, "%08x", opcode ); + } + else + { + pBuf += sprintf( pBuf, "???" ); + } + } + else if( (opcode&0x0f000000) == 0x0f000000 ) + { + /* Software Interrupt */ + pBuf += sprintf( pBuf, "SWI%s $%x", + pConditionCode, + opcode&0x00ffffff ); + dasmflags = DASMFLAG_STEP_OVER; + } + else + { + pBuf += sprintf( pBuf, "Undefined" ); + } + + return dasmflags | DASMFLAG_SUPPORTED; +} + +CPU_DISASSEMBLE( arm ) +{ + UINT32 opcode = oprom[0] | (oprom[1] << 8) | (oprom[2] << 16) | (oprom[3] << 24); + return 4 | arm_disasm(buffer, pc, opcode); +} + +CPU_DISASSEMBLE( arm_be ) +{ + UINT32 opcode = oprom[3] | (oprom[2] << 8) | (oprom[1] << 16) | (oprom[0] << 24); + return 4 | arm_disasm(buffer, pc, opcode); +} diff --git a/src/devices/cpu/arm7/arm7.c b/src/devices/cpu/arm7/arm7.c new file mode 100644 index 00000000000..346dcb1020d --- /dev/null +++ b/src/devices/cpu/arm7/arm7.c @@ -0,0 +1,1214 @@ +// license:BSD-3-Clause +// copyright-holders:Steve Ellenoff,R. Belmont,Ryan Holtz +/***************************************************************************** + * + * arm7.c + * Portable CPU Emulator for 32-bit ARM v3/4/5/6 + * + * Copyright Steve Ellenoff, all rights reserved. + * Thumb, DSP, and MMU support and many bugfixes by R. Belmont and Ryan Holtz. + * + * This work is based on: + * #1) 'Atmel Corporation ARM7TDMI (Thumb) Datasheet - January 1999' + * #2) Arm 2/3/6 emulator By Bryan McPhail (bmcphail@tendril.co.uk) and Phil Stroffolino (MAME CORE 0.76) + * + *****************************************************************************/ + +/****************************************************************************** + * Notes: + + ** This is a plain vanilla implementation of an ARM7 cpu which incorporates my ARM7 core. + It can be used as is, or used to demonstrate how to utilize the arm7 core to create a cpu + that uses the core, since there are numerous different mcu packages that incorporate an arm7 core. + + See the notes in the arm7core.inc file itself regarding issues/limitations of the arm7 core. + ** + +TODO: +- Cleanups +- Fix and finish the DRC code, or remove it entirely + +*****************************************************************************/ +#include "emu.h" +#include "debugger.h" +#include "arm7.h" +#include "arm7core.h" //include arm7 core +#include "arm7help.h" + + +/* prototypes of coprocessor functions */ +void arm7_dt_r_callback(arm_state *arm, UINT32 insn, UINT32 *prn, UINT32 (*read32)(arm_state *arm, UINT32 addr)); +void arm7_dt_w_callback(arm_state *arm, UINT32 insn, UINT32 *prn, void (*write32)(arm_state *arm, UINT32 addr, UINT32 data)); + +// holder for the co processor Data Transfer Read & Write Callback funcs +void (*arm7_coproc_dt_r_callback)(arm_state *arm, UINT32 insn, UINT32 *prn, UINT32 (*read32)(arm_state *arm, UINT32 addr)); +void (*arm7_coproc_dt_w_callback)(arm_state *arm, UINT32 insn, UINT32 *prn, void (*write32)(arm_state *arm, UINT32 addr, UINT32 data)); + + +const device_type ARM7 = &device_creator; +const device_type ARM7_BE = &device_creator; +const device_type ARM7500 = &device_creator; +const device_type ARM9 = &device_creator; +const device_type ARM920T = &device_creator; +const device_type PXA255 = &device_creator; +const device_type SA1110 = &device_creator; + + +arm7_cpu_device::arm7_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : cpu_device(mconfig, ARM7, "ARM7", tag, owner, clock, "arm7", __FILE__) + , m_program_config("program", ENDIANNESS_LITTLE, 32, 32, 0) + , m_endian(ENDIANNESS_LITTLE) + , m_archRev(4) // ARMv4 + , m_archFlags(eARM_ARCHFLAGS_T) // has Thumb + , m_copro_id(0x41 | (1 << 23) | (7 << 12)) // <-- where did this come from? + , m_pc(0) +{ + memset(m_r, 0x00, sizeof(m_r)); +} + + +arm7_cpu_device::arm7_cpu_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source, UINT8 archRev, UINT8 archFlags, endianness_t endianness) + : cpu_device(mconfig, type, name, tag, owner, clock, shortname, source) + , m_program_config("program", endianness, 32, 32, 0) + , m_endian(endianness) + , m_archRev(archRev) + , m_archFlags(archFlags) + , m_copro_id(0x41 | (1 << 23) | (7 << 12)) // <-- where did this come from? + , m_pc(0) +{ + memset(m_r, 0x00, sizeof(m_r)); +} + + +arm7_be_cpu_device::arm7_be_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : arm7_cpu_device(mconfig, ARM7_BE, "ARM7 (big endian)", tag, owner, clock, "arm7_be", __FILE__, 4, eARM_ARCHFLAGS_T, ENDIANNESS_BIG) +{ +} + + +arm7500_cpu_device::arm7500_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : arm7_cpu_device(mconfig, ARM7500, "ARM7500", tag, owner, clock, "arm7500", __FILE__, 3, eARM_ARCHFLAGS_MODE26) +{ + m_copro_id = (0x41 << 24) | (0 << 20) | (1 << 16) | (0x710 << 4) | (0 << 0); +} + + +arm9_cpu_device::arm9_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : arm7_cpu_device(mconfig, ARM9, "ARM9", tag, owner, clock, "arm9", __FILE__, 5, eARM_ARCHFLAGS_T | eARM_ARCHFLAGS_E) + // ARMv5 + // has TE extensions +{ +} + + +arm920t_cpu_device::arm920t_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : arm7_cpu_device(mconfig, ARM920T, "ARM920T", tag, owner, clock, "arm920t", __FILE__, 4, eARM_ARCHFLAGS_T) + // ARMv4 + // has T extension +{ + m_copro_id = (0x41 << 24) | (1 << 20) | (2 << 16) | (0x920 << 4) | (0 << 0); +} + + +pxa255_cpu_device::pxa255_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : arm7_cpu_device(mconfig, PXA255, "PXA255", tag, owner, clock, "pxa255", __FILE__, 5, eARM_ARCHFLAGS_T | eARM_ARCHFLAGS_E | eARM_ARCHFLAGS_XSCALE) + // ARMv5 + // has TE and XScale extensions +{ +} + + +sa1110_cpu_device::sa1110_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : arm7_cpu_device(mconfig, SA1110, "SA1110", tag, owner, clock, "sa1110", __FILE__, 4, eARM_ARCHFLAGS_SA) + // ARMv4 + // has StrongARM, no Thumb, no Enhanced DSP +{ +} + + +void arm7_cpu_device::set_cpsr(UINT32 val) +{ + if (m_archFlags & eARM_ARCHFLAGS_MODE26) + { + if ((val & 0x10) != (m_r[eCPSR] & 0x10)) + { + if (val & 0x10) + { + // 26 -> 32 + val = (val & 0x0FFFFF3F) | (m_r[eR15] & 0xF0000000) /* N Z C V */ | ((m_r[eR15] & 0x0C000000) >> (26 - 6)) /* I F */; + m_r[eR15] = m_r[eR15] & 0x03FFFFFC; + } + else + { + // 32 -> 26 + m_r[eR15] = (m_r[eR15] & 0x03FFFFFC) /* PC */ | (val & 0xF0000000) /* N Z C V */ | ((val & 0x000000C0) << (26 - 6)) /* I F */ | (val & 0x00000003) /* M1 M0 */; + } + } + else + { + if (!(val & 0x10)) + { + // mirror bits in pc + m_r[eR15] = (m_r[eR15] & 0x03FFFFFF) | (val & 0xF0000000) /* N Z C V */ | ((val & 0x000000C0) << (26 - 6)) /* I F */; + } + } + } + else + { + val |= 0x10; // force valid mode + } + m_r[eCPSR] = val; +} + + +/************************************************************************** + * ARM TLB IMPLEMENTATION + **************************************************************************/ + +enum +{ + TLB_COARSE = 0, + TLB_FINE +}; + +enum +{ + FAULT_NONE = 0, + FAULT_DOMAIN, + FAULT_PERMISSION +}; + + +UINT32 arm7_cpu_device::arm7_tlb_get_first_level_descriptor( UINT32 vaddr ) +{ + UINT32 entry_paddr = ( m_tlbBase & COPRO_TLB_BASE_MASK ) | ( ( vaddr & COPRO_TLB_VADDR_FLTI_MASK ) >> COPRO_TLB_VADDR_FLTI_MASK_SHIFT ); + return m_program->read_dword( entry_paddr ); +} + + +// COARSE, desc_level1, vaddr +UINT32 arm7_cpu_device::arm7_tlb_get_second_level_descriptor( UINT32 granularity, UINT32 first_desc, UINT32 vaddr ) +{ + UINT32 desc_lvl2 = vaddr; + + switch( granularity ) + { + case TLB_COARSE: + desc_lvl2 = (first_desc & COPRO_TLB_CFLD_ADDR_MASK) | ((vaddr & COPRO_TLB_VADDR_CSLTI_MASK) >> COPRO_TLB_VADDR_CSLTI_MASK_SHIFT); + break; + case TLB_FINE: + desc_lvl2 = (first_desc & COPRO_TLB_FPTB_ADDR_MASK) | ((vaddr & COPRO_TLB_VADDR_FSLTI_MASK) >> COPRO_TLB_VADDR_FSLTI_MASK_SHIFT); + break; + default: + // We shouldn't be here + LOG( ( "ARM7: Attempting to get second-level TLB descriptor of invalid granularity (%d)\n", granularity ) ); + break; + } + + return m_program->read_dword( desc_lvl2 ); +} + + +int arm7_cpu_device::detect_fault(int permission, int ap, int flags) +{ + switch (permission) + { + case 0 : // "No access - Any access generates a domain fault" + { + return FAULT_DOMAIN; + } + case 1 : // "Client - Accesses are checked against the access permission bits in the section or page descriptor" + { + switch (ap) + { + case 0 : + { + int s = (m_control & COPRO_CTRL_SYSTEM) ? 1 : 0; + int r = (m_control & COPRO_CTRL_ROM) ? 1 : 0; + if (s == 0) + { + if (r == 0) // "Any access generates a permission fault" + { + return FAULT_PERMISSION; + } + else // "Any write generates a permission fault" + { + if (flags & ARM7_TLB_WRITE) + { + return FAULT_PERMISSION; + } + } + } + else + { + if (r == 0) // "Only Supervisor read permitted" + { + if (((m_r[eCPSR] & MODE_FLAG) == eARM7_MODE_USER) || (flags & ARM7_TLB_WRITE)) + { + return FAULT_PERMISSION; + } + } + else // "Reserved" -> assume same behaviour as S=0/R=0 case + { + return FAULT_PERMISSION; + } + } + } + break; + case 1 : // "Access allowed only in Supervisor mode" + { + if ((m_r[eCPSR] & MODE_FLAG) == eARM7_MODE_USER) + { + return FAULT_PERMISSION; + } + } + break; + case 2 : // "Writes in User mode cause permission fault" + { + if (((m_r[eCPSR] & MODE_FLAG) == eARM7_MODE_USER) && (flags & ARM7_TLB_WRITE)) + { + return FAULT_PERMISSION; + } + } + break; + case 3 : // "All access types permitted in both modes" + { + return FAULT_NONE; + } + } + } + break; + case 2 : // "Reserved - Reserved. Currently behaves like the no access mode" + { + return FAULT_DOMAIN; + } + case 3 : // "Manager - Accesses are not checked against the access permission bits so a permission fault cannot be generated" + { + return FAULT_NONE; + } + } + return FAULT_NONE; +} + + +bool arm7_cpu_device::arm7_tlb_translate(offs_t &addr, int flags) +{ + UINT32 desc_lvl1; + UINT32 desc_lvl2 = 0; + UINT32 paddr, vaddr = addr; + UINT8 domain, permission; + + if (vaddr < 32 * 1024 * 1024) + { + UINT32 pid = ((m_fcsePID >> 25) & 0x7F); + if (pid > 0) + { + //LOG( ( "ARM7: FCSE PID vaddr %08X -> %08X\n", vaddr, vaddr + (pid * (32 * 1024 * 1024))) ); + vaddr = vaddr + (((m_fcsePID >> 25) & 0x7F) * (32 * 1024 * 1024)); + } + } + + desc_lvl1 = arm7_tlb_get_first_level_descriptor( vaddr ); + + paddr = vaddr; + +#if ARM7_MMU_ENABLE_HACK + if ((m_r[eR15] == (m_mmu_enable_addr + 4)) || (m_r[eR15] == (m_mmu_enable_addr + 8))) + { + LOG( ( "ARM7: fetch flat, PC = %08x, vaddr = %08x\n", m_r[eR15], vaddr ) ); + *addr = vaddr; + return true; + } + else + { + m_mmu_enable_addr = 1; + } +#endif + + domain = (desc_lvl1 >> 5) & 0xF; + permission = (m_domainAccessControl >> (domain << 1)) & 3; + + switch( desc_lvl1 & 3 ) + { + case COPRO_TLB_UNMAPPED: + // Unmapped, generate a translation fault + if (flags & ARM7_TLB_ABORT_D) + { + LOG( ( "ARM7: Translation fault on unmapped virtual address, PC = %08x, vaddr = %08x\n", m_r[eR15], vaddr ) ); + m_faultStatus[0] = (5 << 0); // 5 = section translation fault + m_faultAddress = vaddr; + m_pendingAbtD = 1; + } + else if (flags & ARM7_TLB_ABORT_P) + { + LOG( ( "ARM7: Translation fault on unmapped virtual address, PC = %08x, vaddr = %08x\n", m_r[eR15], vaddr ) ); + m_pendingAbtP = 1; + } + return FALSE; + case COPRO_TLB_COARSE_TABLE: + // Entry is the physical address of a coarse second-level table + if ((permission == 1) || (permission == 3)) + { + desc_lvl2 = arm7_tlb_get_second_level_descriptor( TLB_COARSE, desc_lvl1, vaddr ); + } + else + { + fatalerror("ARM7: Not Yet Implemented: Coarse Table, Section Domain fault on virtual address, vaddr = %08x, domain = %08x, PC = %08x\n", vaddr, domain, m_r[eR15]); + } + break; + case COPRO_TLB_SECTION_TABLE: + { + // Entry is a section + UINT8 ap = (desc_lvl1 >> 10) & 3; + int fault = detect_fault(permission, ap, flags); + if (fault == FAULT_NONE) + { + paddr = ( desc_lvl1 & COPRO_TLB_SECTION_PAGE_MASK ) | ( vaddr & ~COPRO_TLB_SECTION_PAGE_MASK ); + } + else + { + if (flags & ARM7_TLB_ABORT_D) + { + LOG( ( "ARM7: Section Table, Section %s fault on virtual address, vaddr = %08x, PC = %08x\n", (fault == FAULT_DOMAIN) ? "domain" : "permission", vaddr, m_r[eR15] ) ); + m_faultStatus[0] = ((fault == FAULT_DOMAIN) ? (9 << 0) : (13 << 0)) | (domain << 4); // 9 = section domain fault, 13 = section permission fault + m_faultAddress = vaddr; + m_pendingAbtD = 1; + LOG( ( "vaddr %08X desc_lvl1 %08X domain %d permission %d ap %d s %d r %d mode %d read %d write %d\n", + vaddr, desc_lvl1, domain, permission, ap, (m_control & COPRO_CTRL_SYSTEM) ? 1 : 0, (m_control & COPRO_CTRL_ROM) ? 1 : 0, + m_r[eCPSR] & MODE_FLAG, flags & ARM7_TLB_READ ? 1 : 0, flags & ARM7_TLB_WRITE ? 1 : 0) ); + } + else if (flags & ARM7_TLB_ABORT_P) + { + LOG( ( "ARM7: Section Table, Section %s fault on virtual address, vaddr = %08x, PC = %08x\n", (fault == FAULT_DOMAIN) ? "domain" : "permission", vaddr, m_r[eR15] ) ); + m_pendingAbtP = 1; + } + return false; + } + } + break; + case COPRO_TLB_FINE_TABLE: + // Entry is the physical address of a coarse second-level table + if ((permission == 1) || (permission == 3)) + { + desc_lvl2 = arm7_tlb_get_second_level_descriptor( TLB_FINE, desc_lvl1, vaddr ); + } + else + { + fatalerror("ARM7: Not Yet Implemented: Fine Table, Section Domain fault on virtual address, vaddr = %08x, domain = %08x, PC = %08x\n", vaddr, domain, m_r[eR15]); + } + break; + default: + // Entry is the physical address of a three-legged termite-eaten table + break; + } + + if( ( desc_lvl1 & 3 ) == COPRO_TLB_COARSE_TABLE || ( desc_lvl1 & 3 ) == COPRO_TLB_FINE_TABLE ) + { + switch( desc_lvl2 & 3 ) + { + case COPRO_TLB_UNMAPPED: + // Unmapped, generate a translation fault + if (flags & ARM7_TLB_ABORT_D) + { + LOG( ( "ARM7: Translation fault on unmapped virtual address, vaddr = %08x, PC %08X\n", vaddr, m_r[eR15] ) ); + m_faultStatus[0] = (7 << 0) | (domain << 4); // 7 = page translation fault + m_faultAddress = vaddr; + m_pendingAbtD = 1; + } + else if (flags & ARM7_TLB_ABORT_P) + { + LOG( ( "ARM7: Translation fault on unmapped virtual address, vaddr = %08x, PC %08X\n", vaddr, m_r[eR15] ) ); + m_pendingAbtP = 1; + } + return FALSE; + case COPRO_TLB_LARGE_PAGE: + // Large page descriptor + paddr = ( desc_lvl2 & COPRO_TLB_LARGE_PAGE_MASK ) | ( vaddr & ~COPRO_TLB_LARGE_PAGE_MASK ); + break; + case COPRO_TLB_SMALL_PAGE: + // Small page descriptor + { + UINT8 ap = ((((desc_lvl2 >> 4) & 0xFF) >> (((vaddr >> 10) & 3) << 1)) & 3); + int fault = detect_fault(permission, ap, flags); + if (fault == FAULT_NONE) + { + paddr = ( desc_lvl2 & COPRO_TLB_SMALL_PAGE_MASK ) | ( vaddr & ~COPRO_TLB_SMALL_PAGE_MASK ); + } + else + { + if (flags & ARM7_TLB_ABORT_D) + { + // hapyfish expects a data abort when something tries to write to a read-only memory location from user mode + LOG( ( "ARM7: Page Table, Section %s fault on virtual address, vaddr = %08x, PC = %08x\n", (fault == FAULT_DOMAIN) ? "domain" : "permission", vaddr, m_r[eR15] ) ); + m_faultStatus[0] = ((fault == FAULT_DOMAIN) ? (11 << 0) : (15 << 0)) | (domain << 4); // 11 = page domain fault, 15 = page permission fault + m_faultAddress = vaddr; + m_pendingAbtD = 1; + LOG( ( "vaddr %08X desc_lvl2 %08X domain %d permission %d ap %d s %d r %d mode %d read %d write %d\n", + vaddr, desc_lvl2, domain, permission, ap, (m_control & COPRO_CTRL_SYSTEM) ? 1 : 0, (m_control & COPRO_CTRL_ROM) ? 1 : 0, + m_r[eCPSR] & MODE_FLAG, flags & ARM7_TLB_READ ? 1 : 0, flags & ARM7_TLB_WRITE ? 1 : 0) ); + } + else if (flags & ARM7_TLB_ABORT_P) + { + LOG( ( "ARM7: Page Table, Section %s fault on virtual address, vaddr = %08x, PC = %08x\n", (fault == FAULT_DOMAIN) ? "domain" : "permission", vaddr, m_r[eR15] ) ); + m_pendingAbtP = 1; + } + return false; + } + } + break; + case COPRO_TLB_TINY_PAGE: + // Tiny page descriptor + if( ( desc_lvl1 & 3 ) == 1 ) + { + LOG( ( "ARM7: It would appear that we're looking up a tiny page from a coarse TLB lookup. This is bad. vaddr = %08x\n", vaddr ) ); + } + paddr = ( desc_lvl2 & COPRO_TLB_TINY_PAGE_MASK ) | ( vaddr & ~COPRO_TLB_TINY_PAGE_MASK ); + break; + } + } + addr = paddr; + return true; +} + + +bool arm7_cpu_device::memory_translate(address_spacenum spacenum, int intention, offs_t &address) +{ + /* only applies to the program address space and only does something if the MMU's enabled */ + if( spacenum == AS_PROGRAM && ( m_control & COPRO_CTRL_MMU_EN ) ) + { + return arm7_tlb_translate(address, 0); + } + return true; +} + + +/* include the arm7 core */ +#include "arm7core.inc" + +/*************************************************************************** + * CPU SPECIFIC IMPLEMENTATIONS + **************************************************************************/ + +void arm7_cpu_device::device_start() +{ + m_program = &space(AS_PROGRAM); + m_direct = &m_program->direct(); + + save_item(NAME(m_r)); + save_item(NAME(m_pendingIrq)); + save_item(NAME(m_pendingFiq)); + save_item(NAME(m_pendingAbtD)); + save_item(NAME(m_pendingAbtP)); + save_item(NAME(m_pendingUnd)); + save_item(NAME(m_pendingSwi)); + + m_icountptr = &m_icount; + + state_add( ARM7_PC, "PC", m_pc).callexport().formatstr("%08X"); + state_add(STATE_GENPC, "GENPC", m_pc).callexport().noshow(); + /* registers shared by all operating modes */ + state_add( ARM7_R0, "R0", m_r[ 0]).formatstr("%08X"); + state_add( ARM7_R1, "R1", m_r[ 1]).formatstr("%08X"); + state_add( ARM7_R2, "R2", m_r[ 2]).formatstr("%08X"); + state_add( ARM7_R3, "R3", m_r[ 3]).formatstr("%08X"); + state_add( ARM7_R4, "R4", m_r[ 4]).formatstr("%08X"); + state_add( ARM7_R5, "R5", m_r[ 5]).formatstr("%08X"); + state_add( ARM7_R6, "R6", m_r[ 6]).formatstr("%08X"); + state_add( ARM7_R7, "R7", m_r[ 7]).formatstr("%08X"); + state_add( ARM7_R8, "R8", m_r[ 8]).formatstr("%08X"); + state_add( ARM7_R9, "R9", m_r[ 9]).formatstr("%08X"); + state_add( ARM7_R10, "R10", m_r[10]).formatstr("%08X"); + state_add( ARM7_R11, "R11", m_r[11]).formatstr("%08X"); + state_add( ARM7_R12, "R12", m_r[12]).formatstr("%08X"); + state_add( ARM7_R13, "R13", m_r[13]).formatstr("%08X"); + state_add( ARM7_R14, "R14", m_r[14]).formatstr("%08X"); + state_add( ARM7_R15, "R15", m_r[15]).formatstr("%08X"); + /* FIRQ Mode Shadowed Registers */ + state_add( ARM7_FR8, "FR8", m_r[eR8_FIQ] ).formatstr("%08X"); + state_add( ARM7_FR9, "FR9", m_r[eR9_FIQ] ).formatstr("%08X"); + state_add( ARM7_FR10, "FR10", m_r[eR10_FIQ] ).formatstr("%08X"); + state_add( ARM7_FR11, "FR11", m_r[eR11_FIQ] ).formatstr("%08X"); + state_add( ARM7_FR12, "FR12", m_r[eR12_FIQ] ).formatstr("%08X"); + state_add( ARM7_FR13, "FR13", m_r[eR13_FIQ] ).formatstr("%08X"); + state_add( ARM7_FR14, "FR14", m_r[eR14_FIQ] ).formatstr("%08X"); + state_add( ARM7_FSPSR, "FR16", m_r[eSPSR_FIQ]).formatstr("%08X"); + /* IRQ Mode Shadowed Registers */ + state_add( ARM7_IR13, "IR13", m_r[eR13_IRQ] ).formatstr("%08X"); + state_add( ARM7_IR14, "IR14", m_r[eR14_IRQ] ).formatstr("%08X"); + state_add( ARM7_ISPSR, "IR16", m_r[eSPSR_IRQ]).formatstr("%08X"); + /* Supervisor Mode Shadowed Registers */ + state_add( ARM7_SR13, "SR13", m_r[eR13_SVC] ).formatstr("%08X"); + state_add( ARM7_SR14, "SR14", m_r[eR14_SVC] ).formatstr("%08X"); + state_add( ARM7_SSPSR, "SR16", m_r[eSPSR_SVC]).formatstr("%08X"); + /* Abort Mode Shadowed Registers */ + state_add( ARM7_AR13, "AR13", m_r[eR13_ABT] ).formatstr("%08X"); + state_add( ARM7_AR14, "AR14", m_r[eR14_ABT] ).formatstr("%08X"); + state_add( ARM7_ASPSR, "AR16", m_r[eSPSR_ABT]).formatstr("%08X"); + /* Undefined Mode Shadowed Registers */ + state_add( ARM7_UR13, "UR13", m_r[eR13_UND] ).formatstr("%08X"); + state_add( ARM7_UR14, "UR14", m_r[eR14_UND] ).formatstr("%08X"); + state_add( ARM7_USPSR, "UR16", m_r[eSPSR_UND]).formatstr("%08X"); + + state_add(STATE_GENFLAGS, "GENFLAGS", m_r[eCPSR]).formatstr("%13s").noshow(); +} + + +void arm7_cpu_device::state_export(const device_state_entry &entry) +{ + switch (entry.index()) + { + case STATE_GENPC: + m_pc = GET_PC; + break; + } +} + + +void arm7_cpu_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + switch (entry.index()) + { + case STATE_GENFLAGS: + strprintf(str, "%c%c%c%c%c%c%c%c %s", + (ARM7REG(eCPSR) & N_MASK) ? 'N' : '-', + (ARM7REG(eCPSR) & Z_MASK) ? 'Z' : '-', + (ARM7REG(eCPSR) & C_MASK) ? 'C' : '-', + (ARM7REG(eCPSR) & V_MASK) ? 'V' : '-', + (ARM7REG(eCPSR) & Q_MASK) ? 'Q' : '-', + (ARM7REG(eCPSR) & I_MASK) ? 'I' : '-', + (ARM7REG(eCPSR) & F_MASK) ? 'F' : '-', + (ARM7REG(eCPSR) & T_MASK) ? 'T' : '-', + GetModeText(ARM7REG(eCPSR)) ); + break; + } +} + +void arm7_cpu_device::device_reset() +{ + memset(m_r, 0, sizeof(m_r)); + m_pendingIrq = 0; + m_pendingFiq = 0; + m_pendingAbtD = 0; + m_pendingAbtP = 0; + m_pendingUnd = 0; + m_pendingSwi = 0; + m_control = 0; + m_tlbBase = 0; + m_faultStatus[0] = 0; + m_faultStatus[1] = 0; + m_faultAddress = 0; + m_fcsePID = 0; + m_domainAccessControl = 0; + + /* start up in SVC mode with interrupts disabled. */ + m_r[eCPSR] = I_MASK | F_MASK | 0x10; + SwitchMode(eARM7_MODE_SVC); + m_r[eR15] = 0; + + m_impstate.cache_dirty = TRUE; +} + + +#define UNEXECUTED() \ + m_r[eR15] += 4; \ + m_icount +=2; /* Any unexecuted instruction only takes 1 cycle (page 193) */ + +void arm7_cpu_device::execute_run() +{ + UINT32 insn; + + do + { + UINT32 pc = GET_PC; + + debugger_instruction_hook(this, pc); + + /* handle Thumb instructions if active */ + if (T_IS_SET(m_r[eCPSR])) + { + offs_t raddr; + + pc = m_r[eR15]; + + // "In Thumb state, bit [0] is undefined and must be ignored. Bits [31:1] contain the PC." + raddr = pc & (~1); + + if ( m_control & COPRO_CTRL_MMU_EN ) + { + if (!arm7_tlb_translate(raddr, ARM7_TLB_ABORT_P | ARM7_TLB_READ)) + { + goto skip_exec; + } + } + + insn = m_direct->read_word(raddr); + (this->*thumb_handler[(insn & 0xffc0) >> 6])(pc, insn); + + } + else + { + offs_t raddr; + + /* load 32 bit instruction */ + + // "In ARM state, bits [1:0] of r15 are undefined and must be ignored. Bits [31:2] contain the PC." + raddr = pc & (~3); + + if ( m_control & COPRO_CTRL_MMU_EN ) + { + if (!arm7_tlb_translate(raddr, ARM7_TLB_ABORT_P | ARM7_TLB_READ)) + { + goto skip_exec; + } + } + +#if 0 + if (MODE26) + { + UINT32 temp1, temp2; + temp1 = GET_CPSR & 0xF00000C3; + temp2 = (R15 & 0xF0000000) | ((R15 & 0x0C000000) >> (26 - 6)) | (R15 & 0x00000003); + if (temp1 != temp2) fatalerror( "%08X: 32-bit and 26-bit modes are out of sync (%08X %08X)\n", pc, temp1, temp2); + } +#endif + + insn = m_direct->read_dword(raddr); + + /* process condition codes for this instruction */ + switch (insn >> INSN_COND_SHIFT) + { + case COND_EQ: + if (Z_IS_CLEAR(m_r[eCPSR])) + { UNEXECUTED(); goto skip_exec; } + break; + case COND_NE: + if (Z_IS_SET(m_r[eCPSR])) + { UNEXECUTED(); goto skip_exec; } + break; + case COND_CS: + if (C_IS_CLEAR(m_r[eCPSR])) + { UNEXECUTED(); goto skip_exec; } + break; + case COND_CC: + if (C_IS_SET(m_r[eCPSR])) + { UNEXECUTED(); goto skip_exec; } + break; + case COND_MI: + if (N_IS_CLEAR(m_r[eCPSR])) + { UNEXECUTED(); goto skip_exec; } + break; + case COND_PL: + if (N_IS_SET(m_r[eCPSR])) + { UNEXECUTED(); goto skip_exec; } + break; + case COND_VS: + if (V_IS_CLEAR(m_r[eCPSR])) + { UNEXECUTED(); goto skip_exec; } + break; + case COND_VC: + if (V_IS_SET(m_r[eCPSR])) + { UNEXECUTED(); goto skip_exec; } + break; + case COND_HI: + if (C_IS_CLEAR(m_r[eCPSR]) || Z_IS_SET(m_r[eCPSR])) + { UNEXECUTED(); goto skip_exec; } + break; + case COND_LS: + if (C_IS_SET(m_r[eCPSR]) && Z_IS_CLEAR(m_r[eCPSR])) + { UNEXECUTED(); goto skip_exec; } + break; + case COND_GE: + if (!(m_r[eCPSR] & N_MASK) != !(m_r[eCPSR] & V_MASK)) /* Use x ^ (x >> ...) method */ + { UNEXECUTED(); goto skip_exec; } + break; + case COND_LT: + if (!(m_r[eCPSR] & N_MASK) == !(m_r[eCPSR] & V_MASK)) + { UNEXECUTED(); goto skip_exec; } + break; + case COND_GT: + if (Z_IS_SET(m_r[eCPSR]) || (!(m_r[eCPSR] & N_MASK) != !(m_r[eCPSR] & V_MASK))) + { UNEXECUTED(); goto skip_exec; } + break; + case COND_LE: + if (Z_IS_CLEAR(m_r[eCPSR]) && (!(m_r[eCPSR] & N_MASK) == !(m_r[eCPSR] & V_MASK))) + { UNEXECUTED(); goto skip_exec; } + break; + case COND_NV: + { UNEXECUTED(); goto skip_exec; } + } + /*******************************************************************/ + /* If we got here - condition satisfied, so decode the instruction */ + /*******************************************************************/ + (this->*ops_handler[((insn & 0xF000000) >> 24)])(insn); + } + +skip_exec: + + arm7_check_irq_state(); + + /* All instructions remove 3 cycles.. Others taking less / more will have adjusted this # prior to here */ + m_icount -= 3; + } while (m_icount > 0); +} + + +void arm7_cpu_device::execute_set_input(int irqline, int state) +{ + switch (irqline) { + case ARM7_IRQ_LINE: /* IRQ */ + m_pendingIrq = state & 1; + break; + + case ARM7_FIRQ_LINE: /* FIRQ */ + m_pendingFiq = state & 1; + break; + + case ARM7_ABORT_EXCEPTION: + m_pendingAbtD = state & 1; + break; + case ARM7_ABORT_PREFETCH_EXCEPTION: + m_pendingAbtP = state & 1; + break; + + case ARM7_UNDEFINE_EXCEPTION: + m_pendingUnd = state & 1; + break; + } + + arm7_check_irq_state(); +} + + +offs_t arm7_cpu_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( arm7arm ); + extern CPU_DISASSEMBLE( arm7thumb ); + extern CPU_DISASSEMBLE( arm7arm_be ); + extern CPU_DISASSEMBLE( arm7thumb_be ); + + if (T_IS_SET(m_r[eCPSR])) + { + if ( m_endian == ENDIANNESS_BIG ) + return CPU_DISASSEMBLE_NAME(arm7thumb_be)(this, buffer, pc, oprom, opram, options); + else + return CPU_DISASSEMBLE_NAME(arm7thumb)(this, buffer, pc, oprom, opram, options); + } + else + { + if ( m_endian == ENDIANNESS_BIG ) + return CPU_DISASSEMBLE_NAME(arm7arm_be)(this, buffer, pc, oprom, opram, options); + else + return CPU_DISASSEMBLE_NAME(arm7arm)(this, buffer, pc, oprom, opram, options); + } +} + + +/* ARM system coprocessor support */ + +WRITE32_MEMBER( arm7_cpu_device::arm7_do_callback ) +{ + m_pendingUnd = 1; +} + +READ32_MEMBER( arm7_cpu_device::arm7_rt_r_callback ) +{ + UINT32 opcode = offset; + UINT8 cReg = ( opcode & INSN_COPRO_CREG ) >> INSN_COPRO_CREG_SHIFT; + UINT8 op2 = ( opcode & INSN_COPRO_OP2 ) >> INSN_COPRO_OP2_SHIFT; + UINT8 op3 = opcode & INSN_COPRO_OP3; + UINT8 cpnum = (opcode & INSN_COPRO_CPNUM) >> INSN_COPRO_CPNUM_SHIFT; + UINT32 data = 0; + +// printf("cpnum %d cReg %d op2 %d op3 %d (%x)\n", cpnum, cReg, op2, op3, GET_REGISTER(arm, 15)); + + // we only handle system copro here + if (cpnum != 15) + { + if (m_archFlags & eARM_ARCHFLAGS_XSCALE) + { + // handle XScale specific CP14 + if (cpnum == 14) + { + switch( cReg ) + { + case 1: // clock counter + data = (UINT32)total_cycles(); + break; + + default: + break; + } + } + else + { + fatalerror("XScale: Unhandled coprocessor %d (archFlags %x)\n", cpnum, m_archFlags); + } + + return data; + } + else + { + LOG( ("ARM7: Unhandled coprocessor %d (archFlags %x)\n", cpnum, m_archFlags) ); + m_pendingUnd = 1; + return 0; + } + } + + switch( cReg ) + { + case 4: + case 7: + case 8: + case 9: + case 10: + case 11: + case 12: + // RESERVED + LOG( ( "arm7_rt_r_callback CR%d, RESERVED\n", cReg ) ); + break; + case 0: // ID + switch(op2) + { + case 0: + switch (m_archRev) + { + case 3: // ARM6 32-bit + data = 0x41; + break; + + case 4: // ARM7/SA11xx + if (m_archFlags & eARM_ARCHFLAGS_SA) + { + // ARM Architecture Version 4 + // Part Number 0xB11 (SA1110) + // Stepping B5 + data = 0x69 | ( 0x01 << 16 ) | ( 0xB11 << 4 ) | 0x9; + } + else + { + data = m_copro_id; + } + break; + + case 5: // ARM9/10/XScale + data = 0x41 | (9 << 12); + if (m_archFlags & eARM_ARCHFLAGS_T) + { + if (m_archFlags & eARM_ARCHFLAGS_E) + { + if (m_archFlags & eARM_ARCHFLAGS_J) + { + data |= (6<<16); // v5TEJ + } + else + { + data |= (5<<16); // v5TE + } + } + else + { + data |= (4<<16); // v5T + } + } + + /* ID from PXA-250 manual */ + //data = 0x69052100; + break; + + case 6: // ARM11 + data = 0x41 | (10<< 12) | (7<<16); // v6 + break; + } + break; + case 1: // cache type + data = 0x0f0d2112; // HACK: value expected by ARMWrestler (probably Nintendo DS ARM9's value) + //data = (6 << 25) | (1 << 24) | (0x172 << 12) | (0x172 << 0); // ARM920T (S3C24xx) + break; + case 2: // TCM type + data = 0; + break; + case 3: // TLB type + data = 0; + break; + case 4: // MPU type + data = 0; + break; + } + LOG( ( "arm7_rt_r_callback, ID %02x (%02x) -> %08x (PC=%08x)\n",op2,m_archRev,data,GET_PC ) ); + break; + case 1: // Control + data = COPRO_CTRL | 0x70; // bits 4-6 always read back as "1" (bit 3 too in XScale) + break; + case 2: // Translation Table Base + data = COPRO_TLB_BASE; + break; + case 3: // Domain Access Control + LOG( ( "arm7_rt_r_callback, Domain Access Control\n" ) ); + data = COPRO_DOMAIN_ACCESS_CONTROL; + break; + case 5: // Fault Status + LOG( ( "arm7_rt_r_callback, Fault Status\n" ) ); + switch (op3) + { + case 0: data = COPRO_FAULT_STATUS_D; break; + case 1: data = COPRO_FAULT_STATUS_P; break; + } + break; + case 6: // Fault Address + LOG( ( "arm7_rt_r_callback, Fault Address\n" ) ); + data = COPRO_FAULT_ADDRESS; + break; + case 13: // Read Process ID (PID) + LOG( ( "arm7_rt_r_callback, Read PID\n" ) ); + data = COPRO_FCSE_PID; + break; + case 14: // Read Breakpoint + LOG( ( "arm7_rt_r_callback, Read Breakpoint\n" ) ); + break; + case 15: // Test, Clock, Idle + LOG( ( "arm7_rt_r_callback, Test / Clock / Idle \n" ) ); + break; + } + + return data; +} + +WRITE32_MEMBER( arm7_cpu_device::arm7_rt_w_callback ) +{ + UINT32 opcode = offset; + UINT8 cReg = ( opcode & INSN_COPRO_CREG ) >> INSN_COPRO_CREG_SHIFT; + UINT8 op2 = ( opcode & INSN_COPRO_OP2 ) >> INSN_COPRO_OP2_SHIFT; + UINT8 op3 = opcode & INSN_COPRO_OP3; + UINT8 cpnum = (opcode & INSN_COPRO_CPNUM) >> INSN_COPRO_CPNUM_SHIFT; + + // handle XScale specific CP14 - just eat writes for now + if (cpnum != 15) + { + if (cpnum == 14) + { + LOG( ("arm7_rt_w_callback: write %x to XScale CP14 reg %d\n", data, cReg) ); + return; + } + else + { + LOG( ("ARM7: Unhandled coprocessor %d\n", cpnum) ); + m_pendingUnd = 1; + return; + } + } + + switch( cReg ) + { + case 0: + case 4: + case 10: + case 11: + case 12: + // RESERVED + LOG( ( "arm7_rt_w_callback CR%d, RESERVED = %08x\n", cReg, data) ); + break; + case 1: // Control + LOG( ( "arm7_rt_w_callback Control = %08x (%d) (%d)\n", data, op2, op3 ) ); + LOG( ( " MMU:%d, Address Fault:%d, Data Cache:%d, Write Buffer:%d\n", + data & COPRO_CTRL_MMU_EN, ( data & COPRO_CTRL_ADDRFAULT_EN ) >> COPRO_CTRL_ADDRFAULT_EN_SHIFT, + ( data & COPRO_CTRL_DCACHE_EN ) >> COPRO_CTRL_DCACHE_EN_SHIFT, + ( data & COPRO_CTRL_WRITEBUF_EN ) >> COPRO_CTRL_WRITEBUF_EN_SHIFT ) ); + LOG( ( " Endianness:%d, System:%d, ROM:%d, Instruction Cache:%d\n", + ( data & COPRO_CTRL_ENDIAN ) >> COPRO_CTRL_ENDIAN_SHIFT, + ( data & COPRO_CTRL_SYSTEM ) >> COPRO_CTRL_SYSTEM_SHIFT, + ( data & COPRO_CTRL_ROM ) >> COPRO_CTRL_ROM_SHIFT, + ( data & COPRO_CTRL_ICACHE_EN ) >> COPRO_CTRL_ICACHE_EN_SHIFT ) ); + LOG( ( " Int Vector Adjust:%d\n", ( data & COPRO_CTRL_INTVEC_ADJUST ) >> COPRO_CTRL_INTVEC_ADJUST_SHIFT ) ); +#if ARM7_MMU_ENABLE_HACK + if (((data & COPRO_CTRL_MMU_EN) != 0) && ((COPRO_CTRL & COPRO_CTRL_MMU_EN) == 0)) + { + >m_mmu_enable_addr = R15; + } + if (((data & COPRO_CTRL_MMU_EN) == 0) && ((COPRO_CTRL & COPRO_CTRL_MMU_EN) != 0)) + { + if (!arm7_tlb_translate( R15, 0)) + { + fatalerror("ARM7_MMU_ENABLE_HACK translate failed\n"); + } + } +#endif + COPRO_CTRL = data & COPRO_CTRL_MASK; + break; + case 2: // Translation Table Base + LOG( ( "arm7_rt_w_callback TLB Base = %08x (%d) (%d)\n", data, op2, op3 ) ); + COPRO_TLB_BASE = data; + break; + case 3: // Domain Access Control + LOG( ( "arm7_rt_w_callback Domain Access Control = %08x (%d) (%d)\n", data, op2, op3 ) ); + COPRO_DOMAIN_ACCESS_CONTROL = data; + break; + case 5: // Fault Status + LOG( ( "arm7_rt_w_callback Fault Status = %08x (%d) (%d)\n", data, op2, op3 ) ); + switch (op3) + { + case 0: COPRO_FAULT_STATUS_D = data; break; + case 1: COPRO_FAULT_STATUS_P = data; break; + } + break; + case 6: // Fault Address + LOG( ( "arm7_rt_w_callback Fault Address = %08x (%d) (%d)\n", data, op2, op3 ) ); + COPRO_FAULT_ADDRESS = data; + break; + case 7: // Cache Operations +// LOG( ( "arm7_rt_w_callback Cache Ops = %08x (%d) (%d)\n", data, op2, op3 ) ); + break; + case 8: // TLB Operations + LOG( ( "arm7_rt_w_callback TLB Ops = %08x (%d) (%d)\n", data, op2, op3 ) ); + break; + case 9: // Read Buffer Operations + LOG( ( "arm7_rt_w_callback Read Buffer Ops = %08x (%d) (%d)\n", data, op2, op3 ) ); + break; + case 13: // Write Process ID (PID) + LOG( ( "arm7_rt_w_callback Write PID = %08x (%d) (%d)\n", data, op2, op3 ) ); + COPRO_FCSE_PID = data; + break; + case 14: // Write Breakpoint + LOG( ( "arm7_rt_w_callback Write Breakpoint = %08x (%d) (%d)\n", data, op2, op3 ) ); + break; + case 15: // Test, Clock, Idle + LOG( ( "arm7_rt_w_callback Test / Clock / Idle = %08x (%d) (%d)\n", data, op2, op3 ) ); + break; + } +} + + +void arm7_cpu_device::arm7_dt_r_callback(UINT32 insn, UINT32 *prn) +{ + UINT8 cpn = (insn >> 8) & 0xF; + if ((m_archFlags & eARM_ARCHFLAGS_XSCALE) && (cpn == 0)) + { + LOG( ( "arm7_dt_r_callback: DSP Coprocessor 0 (CP0) not yet emulated (PC %08x)\n", GET_PC ) ); + } + else + { + m_pendingUnd = 1; + } +} + + +void arm7_cpu_device::arm7_dt_w_callback(UINT32 insn, UINT32 *prn) +{ + UINT8 cpn = (insn >> 8) & 0xF; + if ((m_archFlags & eARM_ARCHFLAGS_XSCALE) && (cpn == 0)) + { + LOG( ( "arm7_dt_w_callback: DSP Coprocessor 0 (CP0) not yet emulated (PC %08x)\n", GET_PC ) ); + } + else + { + m_pendingUnd = 1; + } +} + + +/*************************************************************************** + * Default Memory Handlers + ***************************************************************************/ +void arm7_cpu_device::arm7_cpu_write32(UINT32 addr, UINT32 data) +{ + if( COPRO_CTRL & COPRO_CTRL_MMU_EN ) + { + if (!arm7_tlb_translate( addr, ARM7_TLB_ABORT_D | ARM7_TLB_WRITE )) + { + return; + } + } + + addr &= ~3; + m_program->write_dword(addr, data); +} + + +void arm7_cpu_device::arm7_cpu_write16(UINT32 addr, UINT16 data) +{ + if( COPRO_CTRL & COPRO_CTRL_MMU_EN ) + { + if (!arm7_tlb_translate( addr, ARM7_TLB_ABORT_D | ARM7_TLB_WRITE )) + { + return; + } + } + + addr &= ~1; + m_program->write_word(addr, data); +} + +void arm7_cpu_device::arm7_cpu_write8(UINT32 addr, UINT8 data) +{ + if( COPRO_CTRL & COPRO_CTRL_MMU_EN ) + { + if (!arm7_tlb_translate( addr, ARM7_TLB_ABORT_D | ARM7_TLB_WRITE )) + { + return; + } + } + + m_program->write_byte(addr, data); +} + +UINT32 arm7_cpu_device::arm7_cpu_read32(UINT32 addr) +{ + UINT32 result; + + if( COPRO_CTRL & COPRO_CTRL_MMU_EN ) + { + if (!arm7_tlb_translate( addr, ARM7_TLB_ABORT_D | ARM7_TLB_READ )) + { + return 0; + } + } + + if (addr & 3) + { + result = m_program->read_dword(addr & ~3); + result = (result >> (8 * (addr & 3))) | (result << (32 - (8 * (addr & 3)))); + } + else + { + result = m_program->read_dword(addr); + } + + return result; +} + +UINT16 arm7_cpu_device::arm7_cpu_read16(UINT32 addr) +{ + UINT16 result; + + if( COPRO_CTRL & COPRO_CTRL_MMU_EN ) + { + if (!arm7_tlb_translate( addr, ARM7_TLB_ABORT_D | ARM7_TLB_READ )) + { + return 0; + } + } + + result = m_program->read_word(addr & ~1); + + if (addr & 1) + { + result = ((result >> 8) & 0xff) | ((result & 0xff) << 8); + } + + return result; +} + +UINT8 arm7_cpu_device::arm7_cpu_read8(UINT32 addr) +{ + if( COPRO_CTRL & COPRO_CTRL_MMU_EN ) + { + if (!arm7_tlb_translate( addr, ARM7_TLB_ABORT_D | ARM7_TLB_READ )) + { + return 0; + } + } + + // Handle through normal 8 bit handler (for 32 bit cpu) + return m_program->read_byte(addr); +} + +#include "arm7drc.inc" diff --git a/src/devices/cpu/arm7/arm7.h b/src/devices/cpu/arm7/arm7.h new file mode 100644 index 00000000000..9b98151494f --- /dev/null +++ b/src/devices/cpu/arm7/arm7.h @@ -0,0 +1,566 @@ +// license:BSD-3-Clause +// copyright-holders:Steve Ellenoff,R. Belmont,Ryan Holtz +/***************************************************************************** + * + * arm7.h + * Portable ARM7TDMI CPU Emulator + * + * Copyright Steve Ellenoff, all rights reserved. + * + * This work is based on: + * #1) 'Atmel Corporation ARM7TDMI (Thumb) Datasheet - January 1999' + * #2) Arm 2/3/6 emulator By Bryan McPhail (bmcphail@tendril.co.uk) and Phil Stroffolino (MAME CORE 0.76) + * + ***************************************************************************** + + This file contains everything related to the arm7 cpu specific implementation. + Anything related to the arm7 core itself is defined in arm7core.h instead. + + ******************************************************************************/ + +#pragma once + +#ifndef __ARM7_H__ +#define __ARM7_H__ + +#include "cpu/drcfe.h" +#include "cpu/drcuml.h" +#include "cpu/drcumlsh.h" + + +#define ARM7_MAX_FASTRAM 4 +#define ARM7_MAX_HOTSPOTS 16 + +enum +{ + CPUINFO_INT_ARM7_DRC_OPTIONS = CPUINFO_INT_CPU_SPECIFIC, + + CPUINFO_INT_ARM7_FASTRAM_SELECT, + CPUINFO_INT_ARM7_FASTRAM_START, + CPUINFO_INT_ARM7_FASTRAM_END, + CPUINFO_INT_ARM7_FASTRAM_READONLY, + + CPUINFO_INT_ARM7_HOTSPOT_SELECT, + CPUINFO_INT_ARM7_HOTSPOT_PC, + CPUINFO_INT_ARM7_HOTSPOT_OPCODE, + CPUINFO_INT_ARM7_HOTSPOT_CYCLES, + + CPUINFO_PTR_ARM7_FASTRAM_BASE = CPUINFO_PTR_CPU_SPECIFIC +}; + +/*************************************************************************** + COMPILER-SPECIFIC OPTIONS +***************************************************************************/ + +#define ARM7DRC_STRICT_VERIFY 0x0001 /* verify all instructions */ +#define ARM7DRC_FLUSH_PC 0x0008 /* flush the PC value before each memory access */ + +#define ARM7DRC_COMPATIBLE_OPTIONS (ARM7DRC_STRICT_VERIFY | ARM7DRC_FLUSH_PC) +#define ARM7DRC_FASTEST_OPTIONS (0) + +/**************************************************************************************************** + * PUBLIC FUNCTIONS + ***************************************************************************************************/ + +class arm7_cpu_device : public cpu_device +{ +public: + // construction/destruction + arm7_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + arm7_cpu_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source, UINT8 archRev, UINT8 archFlags, endianness_t endianness = ENDIANNESS_LITTLE); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_execute_interface overrides + virtual UINT32 execute_min_cycles() const { return 3; } + virtual UINT32 execute_max_cycles() const { return 4; } + virtual UINT32 execute_input_lines() const { return 4; } /* There are actually only 2 input lines: we use 3 variants of the ABORT line while there is only 1 real one */ + virtual void execute_run(); + virtual void execute_set_input(int inputnum, int state); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const { return (spacenum == AS_PROGRAM) ? &m_program_config : NULL; } + virtual bool memory_translate(address_spacenum spacenum, int intention, offs_t &address); + + // device_state_interface overrides + virtual void state_export(const device_state_entry &entry); + void state_string_export(const device_state_entry &entry, std::string &str); + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const { return 2; } + virtual UINT32 disasm_max_opcode_bytes() const { return 4; } + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + + address_space_config m_program_config; + + UINT32 m_r[/*NUM_REGS*/37]; + UINT32 m_pendingIrq; + UINT32 m_pendingFiq; + UINT32 m_pendingAbtD; + UINT32 m_pendingAbtP; + UINT32 m_pendingUnd; + UINT32 m_pendingSwi; + int m_icount; + endianness_t m_endian; + address_space *m_program; + direct_read_data *m_direct; + + /* Coprocessor Registers */ + UINT32 m_control; + UINT32 m_tlbBase; + UINT32 m_faultStatus[2]; + UINT32 m_faultAddress; + UINT32 m_fcsePID; + UINT32 m_domainAccessControl; + + UINT8 m_archRev; // ARM architecture revision (3, 4, and 5 are valid) + UINT8 m_archFlags; // architecture flags + +//#if ARM7_MMU_ENABLE_HACK +// UINT32 mmu_enable_addr; // workaround for "MMU is enabled when PA != VA" problem +//#endif + + UINT32 m_copro_id; + + // For debugger + UINT32 m_pc; + + INT64 saturate_qbit_overflow(INT64 res); + void SwitchMode(UINT32 cpsr_mode_val); + UINT32 decodeShift(UINT32 insn, UINT32 *pCarry); + int loadInc(UINT32 pat, UINT32 rbv, UINT32 s, int mode); + int loadDec(UINT32 pat, UINT32 rbv, UINT32 s, int mode); + int storeInc(UINT32 pat, UINT32 rbv, int mode); + int storeDec(UINT32 pat, UINT32 rbv, int mode); + void HandleCoProcDO(UINT32 insn); + void HandleCoProcRT(UINT32 insn); + void HandleCoProcDT(UINT32 insn); + void HandleBranch(UINT32 insn); + void HandleMemSingle(UINT32 insn); + void HandleHalfWordDT(UINT32 insn); + void HandleSwap(UINT32 insn); + void HandlePSRTransfer(UINT32 insn); + void HandleALU(UINT32 insn); + void HandleMul(UINT32 insn); + void HandleSMulLong(UINT32 insn); + void HandleUMulLong(UINT32 insn); + void HandleMemBlock(UINT32 insn); + void arm7ops_0123(UINT32 insn); + void arm7ops_4567(UINT32 insn); + void arm7ops_89(UINT32 insn); + void arm7ops_ab(UINT32 insn); + void arm7ops_cd(UINT32 insn); + void arm7ops_e(UINT32 insn); + void arm7ops_f(UINT32 insn); + void set_cpsr(UINT32 val); + bool arm7_tlb_translate(offs_t &addr, int flags); + UINT32 arm7_tlb_get_first_level_descriptor( UINT32 vaddr ); + UINT32 arm7_tlb_get_second_level_descriptor( UINT32 granularity, UINT32 first_desc, UINT32 vaddr ); + int detect_fault(int permission, int ap, int flags); + void arm7_check_irq_state(); + void arm7_cpu_write32(UINT32 addr, UINT32 data); + void arm7_cpu_write16(UINT32 addr, UINT16 data); + void arm7_cpu_write8(UINT32 addr, UINT8 data); + UINT32 arm7_cpu_read32(UINT32 addr); + UINT16 arm7_cpu_read16(UINT32 addr); + UINT8 arm7_cpu_read8(UINT32 addr); + + // Coprocessor support + DECLARE_WRITE32_MEMBER( arm7_do_callback ); + DECLARE_READ32_MEMBER( arm7_rt_r_callback ); + DECLARE_WRITE32_MEMBER( arm7_rt_w_callback ); + void arm7_dt_r_callback(UINT32 insn, UINT32 *prn); + void arm7_dt_w_callback(UINT32 insn, UINT32 *prn); + + void tg00_0(UINT32 pc, UINT32 insn); + void tg00_1(UINT32 pc, UINT32 insn); + void tg01_0(UINT32 pc, UINT32 insn); + void tg01_10(UINT32 pc, UINT32 insn); + void tg01_11(UINT32 pc, UINT32 insn); + void tg01_12(UINT32 pc, UINT32 insn); + void tg01_13(UINT32 pc, UINT32 insn); + void tg02_0(UINT32 pc, UINT32 insn); + void tg02_1(UINT32 pc, UINT32 insn); + void tg03_0(UINT32 pc, UINT32 insn); + void tg03_1(UINT32 pc, UINT32 insn); + void tg04_00_00(UINT32 pc, UINT32 insn); + void tg04_00_01(UINT32 pc, UINT32 insn); + void tg04_00_02(UINT32 pc, UINT32 insn); + void tg04_00_03(UINT32 pc, UINT32 insn); + void tg04_00_04(UINT32 pc, UINT32 insn); + void tg04_00_05(UINT32 pc, UINT32 insn); + void tg04_00_06(UINT32 pc, UINT32 insn); + void tg04_00_07(UINT32 pc, UINT32 insn); + void tg04_00_08(UINT32 pc, UINT32 insn); + void tg04_00_09(UINT32 pc, UINT32 insn); + void tg04_00_0a(UINT32 pc, UINT32 insn); + void tg04_00_0b(UINT32 pc, UINT32 insn); + void tg04_00_0c(UINT32 pc, UINT32 insn); + void tg04_00_0d(UINT32 pc, UINT32 insn); + void tg04_00_0e(UINT32 pc, UINT32 insn); + void tg04_00_0f(UINT32 pc, UINT32 insn); + void tg04_01_00(UINT32 pc, UINT32 insn); + void tg04_01_01(UINT32 pc, UINT32 insn); + void tg04_01_02(UINT32 pc, UINT32 insn); + void tg04_01_03(UINT32 pc, UINT32 insn); + void tg04_01_10(UINT32 pc, UINT32 insn); + void tg04_01_11(UINT32 pc, UINT32 insn); + void tg04_01_12(UINT32 pc, UINT32 insn); + void tg04_01_13(UINT32 pc, UINT32 insn); + void tg04_01_20(UINT32 pc, UINT32 insn); + void tg04_01_21(UINT32 pc, UINT32 insn); + void tg04_01_22(UINT32 pc, UINT32 insn); + void tg04_01_23(UINT32 pc, UINT32 insn); + void tg04_01_30(UINT32 pc, UINT32 insn); + void tg04_01_31(UINT32 pc, UINT32 insn); + void tg04_01_32(UINT32 pc, UINT32 insn); + void tg04_01_33(UINT32 pc, UINT32 insn); + void tg04_0203(UINT32 pc, UINT32 insn); + void tg05_0(UINT32 pc, UINT32 insn); + void tg05_1(UINT32 pc, UINT32 insn); + void tg05_2(UINT32 pc, UINT32 insn); + void tg05_3(UINT32 pc, UINT32 insn); + void tg05_4(UINT32 pc, UINT32 insn); + void tg05_5(UINT32 pc, UINT32 insn); + void tg05_6(UINT32 pc, UINT32 insn); + void tg05_7(UINT32 pc, UINT32 insn); + void tg06_0(UINT32 pc, UINT32 insn); + void tg06_1(UINT32 pc, UINT32 insn); + void tg07_0(UINT32 pc, UINT32 insn); + void tg07_1(UINT32 pc, UINT32 insn); + void tg08_0(UINT32 pc, UINT32 insn); + void tg08_1(UINT32 pc, UINT32 insn); + void tg09_0(UINT32 pc, UINT32 insn); + void tg09_1(UINT32 pc, UINT32 insn); + void tg0a_0(UINT32 pc, UINT32 insn); + void tg0a_1(UINT32 pc, UINT32 insn); + void tg0b_0(UINT32 pc, UINT32 insn); + void tg0b_1(UINT32 pc, UINT32 insn); + void tg0b_2(UINT32 pc, UINT32 insn); + void tg0b_3(UINT32 pc, UINT32 insn); + void tg0b_4(UINT32 pc, UINT32 insn); + void tg0b_5(UINT32 pc, UINT32 insn); + void tg0b_6(UINT32 pc, UINT32 insn); + void tg0b_7(UINT32 pc, UINT32 insn); + void tg0b_8(UINT32 pc, UINT32 insn); + void tg0b_9(UINT32 pc, UINT32 insn); + void tg0b_a(UINT32 pc, UINT32 insn); + void tg0b_b(UINT32 pc, UINT32 insn); + void tg0b_c(UINT32 pc, UINT32 insn); + void tg0b_d(UINT32 pc, UINT32 insn); + void tg0b_e(UINT32 pc, UINT32 insn); + void tg0b_f(UINT32 pc, UINT32 insn); + void tg0c_0(UINT32 pc, UINT32 insn); + void tg0c_1(UINT32 pc, UINT32 insn); + void tg0d_0(UINT32 pc, UINT32 insn); + void tg0d_1(UINT32 pc, UINT32 insn); + void tg0d_2(UINT32 pc, UINT32 insn); + void tg0d_3(UINT32 pc, UINT32 insn); + void tg0d_4(UINT32 pc, UINT32 insn); + void tg0d_5(UINT32 pc, UINT32 insn); + void tg0d_6(UINT32 pc, UINT32 insn); + void tg0d_7(UINT32 pc, UINT32 insn); + void tg0d_8(UINT32 pc, UINT32 insn); + void tg0d_9(UINT32 pc, UINT32 insn); + void tg0d_a(UINT32 pc, UINT32 insn); + void tg0d_b(UINT32 pc, UINT32 insn); + void tg0d_c(UINT32 pc, UINT32 insn); + void tg0d_d(UINT32 pc, UINT32 insn); + void tg0d_e(UINT32 pc, UINT32 insn); + void tg0d_f(UINT32 pc, UINT32 insn); + void tg0e_0(UINT32 pc, UINT32 insn); + void tg0e_1(UINT32 pc, UINT32 insn); + void tg0f_0(UINT32 pc, UINT32 insn); + void tg0f_1(UINT32 pc, UINT32 insn); + + typedef void ( arm7_cpu_device::*arm7thumb_ophandler ) (UINT32, UINT32); + static const arm7thumb_ophandler thumb_handler[0x40*0x10]; + + typedef void ( arm7_cpu_device::*arm7ops_ophandler )(UINT32); + static const arm7ops_ophandler ops_handler[0x10]; + + // + // DRC + // + + /* fast RAM info */ + struct fast_ram_info + { + offs_t start; /* start of the RAM block */ + offs_t end; /* end of the RAM block */ + UINT8 readonly; /* TRUE if read-only */ + void * base; /* base in memory where the RAM lives */ + }; + + struct hotspot_info + { + UINT32 pc; + UINT32 opcode; + UINT32 cycles; + }; + + /* internal compiler state */ + struct compiler_state + { + UINT32 cycles; /* accumulated cycles */ + UINT8 checkints; /* need to check interrupts before next instruction */ + UINT8 checksoftints; /* need to check software interrupts before next instruction */ + uml::code_label labelnum; /* index for local labels */ + }; + + /* ARM7 registers */ + struct arm7imp_state + { + /* core state */ + drc_cache * cache; /* pointer to the DRC code cache */ + drcuml_state * drcuml; /* DRC UML generator state */ + //arm7_frontend * drcfe; /* pointer to the DRC front-end state */ + UINT32 drcoptions; /* configurable DRC options */ + + /* internal stuff */ + UINT8 cache_dirty; /* true if we need to flush the cache */ + UINT32 jmpdest; /* destination jump target */ + + /* parameters for subroutines */ + UINT64 numcycles; /* return value from gettotalcycles */ + UINT32 mode; /* current global mode */ + const char * format; /* format string for print_debug */ + UINT32 arg0; /* print_debug argument 1 */ + UINT32 arg1; /* print_debug argument 2 */ + + /* register mappings */ + uml::parameter regmap[/*NUM_REGS*/37]; /* parameter to register mappings for all 16 integer registers */ + + /* subroutines */ + uml::code_handle * entry; /* entry point */ + uml::code_handle * nocode; /* nocode exception handler */ + uml::code_handle * out_of_cycles; /* out of cycles exception handler */ + uml::code_handle * tlb_translate; /* tlb translation handler */ + uml::code_handle * detect_fault; /* tlb fault detection handler */ + uml::code_handle * check_irq; /* irq check handler */ + uml::code_handle * read8; /* read byte */ + uml::code_handle * write8; /* write byte */ + uml::code_handle * read16; /* read half */ + uml::code_handle * write16; /* write half */ + uml::code_handle * read32; /* read word */ + uml::code_handle * write32; /* write word */ + + /* fast RAM */ + UINT32 fastram_select; + fast_ram_info fastram[ARM7_MAX_FASTRAM]; + + /* hotspots */ + UINT32 hotspot_select; + hotspot_info hotspot[ARM7_MAX_HOTSPOTS]; + } m_impstate; + + typedef void ( arm7_cpu_device::*arm7thumb_drcophandler)(drcuml_block*, compiler_state*, const opcode_desc*); + static const arm7thumb_drcophandler drcthumb_handler[0x40*0x10]; + + void drctg00_0(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); /* Shift left */ + void drctg00_1(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); /* Shift right */ + void drctg01_0(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); + void drctg01_10(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); + void drctg01_11(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); /* SUB Rd, Rs, Rn */ + void drctg01_12(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); /* ADD Rd, Rs, #imm */ + void drctg01_13(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); /* SUB Rd, Rs, #imm */ + void drctg02_0(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); + void drctg02_1(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); + void drctg03_0(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); /* ADD Rd, #Offset8 */ + void drctg03_1(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); /* SUB Rd, #Offset8 */ + void drctg04_00_00(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); /* AND Rd, Rs */ + void drctg04_00_01(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); /* EOR Rd, Rs */ + void drctg04_00_02(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); /* LSL Rd, Rs */ + void drctg04_00_03(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); /* LSR Rd, Rs */ + void drctg04_00_04(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); /* ASR Rd, Rs */ + void drctg04_00_05(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); /* ADC Rd, Rs */ + void drctg04_00_06(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); /* SBC Rd, Rs */ + void drctg04_00_07(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); /* ROR Rd, Rs */ + void drctg04_00_08(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); /* TST Rd, Rs */ + void drctg04_00_09(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); /* NEG Rd, Rs */ + void drctg04_00_0a(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); /* CMP Rd, Rs */ + void drctg04_00_0b(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); /* CMN Rd, Rs - check flags, add dasm */ + void drctg04_00_0c(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); /* ORR Rd, Rs */ + void drctg04_00_0d(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); /* MUL Rd, Rs */ + void drctg04_00_0e(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); /* BIC Rd, Rs */ + void drctg04_00_0f(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); /* MVN Rd, Rs */ + void drctg04_01_00(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); + void drctg04_01_01(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); /* ADD Rd, HRs */ + void drctg04_01_02(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); /* ADD HRd, Rs */ + void drctg04_01_03(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); /* Add HRd, HRs */ + void drctg04_01_10(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); /* CMP Rd, Rs */ + void drctg04_01_11(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); /* CMP Rd, Hs */ + void drctg04_01_12(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); /* CMP Hd, Rs */ + void drctg04_01_13(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); /* CMP Hd, Hs */ + void drctg04_01_20(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); /* MOV Rd, Rs (undefined) */ + void drctg04_01_21(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); /* MOV Rd, Hs */ + void drctg04_01_22(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); /* MOV Hd, Rs */ + void drctg04_01_23(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); /* MOV Hd, Hs */ + void drctg04_01_30(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); + void drctg04_01_31(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); + void drctg04_01_32(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); + void drctg04_01_33(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); + void drctg04_0203(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); + void drctg05_0(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); /* STR Rd, [Rn, Rm] */ + void drctg05_1(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); /* STRH Rd, [Rn, Rm] */ + void drctg05_2(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); /* STRB Rd, [Rn, Rm] */ + void drctg05_3(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); /* LDSB Rd, [Rn, Rm] todo, add dasm */ + void drctg05_4(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); /* LDR Rd, [Rn, Rm] */ + void drctg05_5(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); /* LDRH Rd, [Rn, Rm] */ + void drctg05_6(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); /* LDRB Rd, [Rn, Rm] */ + void drctg05_7(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); /* LDSH Rd, [Rn, Rm] */ + void drctg06_0(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); /* Store */ + void drctg06_1(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); /* Load */ + void drctg07_0(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); /* Store */ + void drctg07_1(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); /* Load */ + void drctg08_0(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); /* Store */ + void drctg08_1(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); /* Load */ + void drctg09_0(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); /* Store */ + void drctg09_1(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); /* Load */ + void drctg0a_0(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); /* ADD Rd, PC, #nn */ + void drctg0a_1(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); /* ADD Rd, SP, #nn */ + void drctg0b_0(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); /* ADD SP, #imm */ + void drctg0b_1(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); + void drctg0b_2(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); + void drctg0b_3(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); + void drctg0b_4(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); /* PUSH {Rlist} */ + void drctg0b_5(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); /* PUSH {Rlist}{LR} */ + void drctg0b_6(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); + void drctg0b_7(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); + void drctg0b_8(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); + void drctg0b_9(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); + void drctg0b_a(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); + void drctg0b_b(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); + void drctg0b_c(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); /* POP {Rlist} */ + void drctg0b_d(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); /* POP {Rlist}{PC} */ + void drctg0b_e(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); + void drctg0b_f(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); + void drctg0c_0(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); /* Store */ + void drctg0c_1(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); /* Load */ + void drctg0d_0(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); // COND_EQ: + void drctg0d_1(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); // COND_NE: + void drctg0d_2(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); // COND_CS: + void drctg0d_3(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); // COND_CC: + void drctg0d_4(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); // COND_MI: + void drctg0d_5(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); // COND_PL: + void drctg0d_6(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); // COND_VS: + void drctg0d_7(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); // COND_VC: + void drctg0d_8(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); // COND_HI: + void drctg0d_9(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); // COND_LS: + void drctg0d_a(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); // COND_GE: + void drctg0d_b(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); // COND_LT: + void drctg0d_c(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); // COND_GT: + void drctg0d_d(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); // COND_LE: + void drctg0d_e(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); // COND_AL: + void drctg0d_f(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); // SWI (this is sort of a "hole" in the opcode encoding) + void drctg0e_0(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); + void drctg0e_1(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); + void drctg0f_0(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); + void drctg0f_1(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); /* BL */ + + void load_fast_iregs(drcuml_block *block); + void save_fast_iregs(drcuml_block *block); + void arm7_drc_init(); + void arm7_drc_exit(); + void execute_run_drc(); + void arm7drc_set_options(UINT32 options); + void arm7drc_add_fastram(offs_t start, offs_t end, UINT8 readonly, void *base); + void arm7drc_add_hotspot(offs_t pc, UINT32 opcode, UINT32 cycles); + void code_flush_cache(); + void code_compile_block(UINT8 mode, offs_t pc); + void cfunc_get_cycles(); + void cfunc_unimplemented(); + void static_generate_entry_point(); + void static_generate_check_irq(); + void static_generate_nocode_handler(); + void static_generate_out_of_cycles(); + void static_generate_detect_fault(uml::code_handle **handleptr); + void static_generate_tlb_translate(uml::code_handle **handleptr); + void static_generate_memory_accessor(int size, bool istlb, bool iswrite, const char *name, uml::code_handle **handleptr); + void generate_update_cycles(drcuml_block *block, compiler_state *compiler, uml::parameter param); + void generate_checksum_block(drcuml_block *block, compiler_state *compiler, const opcode_desc *seqhead, const opcode_desc *seqlast); + void generate_sequence_instruction(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); + void generate_delay_slot_and_branch(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, UINT8 linkreg); + + typedef bool ( arm7_cpu_device::*drcarm7ops_ophandler)(drcuml_block*, compiler_state*, const opcode_desc*, UINT32); + static const drcarm7ops_ophandler drcops_handler[0x10]; + + void saturate_qbit_overflow(drcuml_block *block); + bool drcarm7ops_0123(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, UINT32 op); + bool drcarm7ops_4567(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, UINT32 op); + bool drcarm7ops_89(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, UINT32 op); + bool drcarm7ops_ab(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, UINT32 op); + bool drcarm7ops_cd(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, UINT32 op); + bool drcarm7ops_e(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, UINT32 op); + bool drcarm7ops_f(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, UINT32 op); + int generate_opcode(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); + +}; + + +class arm7_be_cpu_device : public arm7_cpu_device +{ +public: + // construction/destruction + arm7_be_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +}; + + +class arm7500_cpu_device : public arm7_cpu_device +{ +public: + // construction/destruction + arm7500_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +}; + + +class arm9_cpu_device : public arm7_cpu_device +{ +public: + // construction/destruction + arm9_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +}; + + +class arm920t_cpu_device : public arm7_cpu_device +{ +public: + // construction/destruction + arm920t_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +}; + + +class pxa255_cpu_device : public arm7_cpu_device +{ +public: + // construction/destruction + pxa255_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +}; + + +class sa1110_cpu_device : public arm7_cpu_device +{ +public: + // construction/destruction + sa1110_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +}; + + +extern const device_type ARM7; +extern const device_type ARM7_BE; +extern const device_type ARM7500; +extern const device_type ARM9; +extern const device_type ARM920T; +extern const device_type PXA255; +extern const device_type SA1110; + +#endif /* __ARM7_H__ */ diff --git a/src/devices/cpu/arm7/arm7core.h b/src/devices/cpu/arm7/arm7core.h new file mode 100644 index 00000000000..2bdd15d7ba3 --- /dev/null +++ b/src/devices/cpu/arm7/arm7core.h @@ -0,0 +1,534 @@ +// license:BSD-3-Clause +// copyright-holders:Steve Ellenoff,R. Belmont,Ryan Holtz +/***************************************************************************** + * + * arm7core.h + * Portable ARM7TDMI Core Emulator + * + * Copyright Steve Ellenoff, all rights reserved. + * + * This work is based on: + * #1) 'Atmel Corporation ARM7TDMI (Thumb) Datasheet - January 1999' + * #2) Arm 2/3/6 emulator By Bryan McPhail (bmcphail@tendril.co.uk) and Phil Stroffolino (MAME CORE 0.76) + * + ***************************************************************************** + + This file contains everything related to the arm7 core itself, and is presumed + to be cpu implementation non-specific, ie, applies to only the core. + + ******************************************************************************/ + +#pragma once + +#ifndef __ARM7CORE_H__ +#define __ARM7CORE_H__ + +#define ARM7_MMU_ENABLE_HACK 0 +#define ARM7_DEBUG_CORE 0 + + +/**************************************************************************************************** + * INTERRUPT LINES/EXCEPTIONS + ***************************************************************************************************/ +enum +{ + ARM7_IRQ_LINE=0, ARM7_FIRQ_LINE, + ARM7_ABORT_EXCEPTION, ARM7_ABORT_PREFETCH_EXCEPTION, ARM7_UNDEFINE_EXCEPTION, + ARM7_NUM_LINES +}; +// Really there's only 1 ABORT Line.. and cpu decides whether it's during data fetch or prefetch, but we let the user specify + +/**************************************************************************************************** + * ARM7 CORE REGISTERS + ***************************************************************************************************/ +enum +{ + ARM7_PC = 0, + ARM7_R0, ARM7_R1, ARM7_R2, ARM7_R3, ARM7_R4, ARM7_R5, ARM7_R6, ARM7_R7, + ARM7_R8, ARM7_R9, ARM7_R10, ARM7_R11, ARM7_R12, ARM7_R13, ARM7_R14, ARM7_R15, + ARM7_FR8, ARM7_FR9, ARM7_FR10, ARM7_FR11, ARM7_FR12, ARM7_FR13, ARM7_FR14, + ARM7_IR13, ARM7_IR14, ARM7_SR13, ARM7_SR14, ARM7_FSPSR, ARM7_ISPSR, ARM7_SSPSR, + ARM7_CPSR, ARM7_AR13, ARM7_AR14, ARM7_ASPSR, ARM7_UR13, ARM7_UR14, ARM7_USPSR +}; + +/* There are 36 Unique - 32 bit processor registers */ +/* Each mode has 17 registers (except user & system, which have 16) */ +/* This is a list of each *unique* register */ +enum +{ + /* All modes have the following */ + eR0 = 0, eR1, eR2, eR3, eR4, eR5, eR6, eR7, + eR8, eR9, eR10, eR11, eR12, + eR13, /* Stack Pointer */ + eR14, /* Link Register (holds return address) */ + eR15, /* Program Counter */ + eCPSR, /* Current Status Program Register */ + + /* Fast Interrupt - Bank switched registers */ + eR8_FIQ, eR9_FIQ, eR10_FIQ, eR11_FIQ, eR12_FIQ, eR13_FIQ, eR14_FIQ, eSPSR_FIQ, + + /* IRQ - Bank switched registers */ + eR13_IRQ, eR14_IRQ, eSPSR_IRQ, + + /* Supervisor/Service Mode - Bank switched registers */ + eR13_SVC, eR14_SVC, eSPSR_SVC, + + /* Abort Mode - Bank switched registers */ + eR13_ABT, eR14_ABT, eSPSR_ABT, + + /* Undefined Mode - Bank switched registers */ + eR13_UND, eR14_UND, eSPSR_UND, + + NUM_REGS +}; + +/* Coprocessor-related macros */ +#define COPRO_TLB_BASE m_tlbBase +#define COPRO_TLB_BASE_MASK 0xffffc000 +#define COPRO_TLB_VADDR_FLTI_MASK 0xfff00000 +#define COPRO_TLB_VADDR_FLTI_MASK_SHIFT 18 +#define COPRO_TLB_VADDR_CSLTI_MASK 0x000ff000 +#define COPRO_TLB_VADDR_CSLTI_MASK_SHIFT 10 +#define COPRO_TLB_VADDR_FSLTI_MASK 0x000ffc00 +#define COPRO_TLB_VADDR_FSLTI_MASK_SHIFT 8 +#define COPRO_TLB_CFLD_ADDR_MASK 0xfffffc00 +#define COPRO_TLB_CFLD_ADDR_MASK_SHIFT 10 +#define COPRO_TLB_FPTB_ADDR_MASK 0xfffff000 +#define COPRO_TLB_FPTB_ADDR_MASK_SHIFT 12 +#define COPRO_TLB_SECTION_PAGE_MASK 0xfff00000 +#define COPRO_TLB_LARGE_PAGE_MASK 0xffff0000 +#define COPRO_TLB_SMALL_PAGE_MASK 0xfffff000 +#define COPRO_TLB_TINY_PAGE_MASK 0xfffffc00 +#define COPRO_TLB_UNMAPPED 0 +#define COPRO_TLB_LARGE_PAGE 1 +#define COPRO_TLB_SMALL_PAGE 2 +#define COPRO_TLB_TINY_PAGE 3 +#define COPRO_TLB_COARSE_TABLE 1 +#define COPRO_TLB_SECTION_TABLE 2 +#define COPRO_TLB_FINE_TABLE 3 + +#define COPRO_CTRL m_control +#define COPRO_CTRL_MMU_EN 0x00000001 +#define COPRO_CTRL_ADDRFAULT_EN 0x00000002 +#define COPRO_CTRL_DCACHE_EN 0x00000004 +#define COPRO_CTRL_WRITEBUF_EN 0x00000008 +#define COPRO_CTRL_ENDIAN 0x00000080 +#define COPRO_CTRL_SYSTEM 0x00000100 +#define COPRO_CTRL_ROM 0x00000200 +#define COPRO_CTRL_ICACHE_EN 0x00001000 +#define COPRO_CTRL_INTVEC_ADJUST 0x00002000 +#define COPRO_CTRL_ADDRFAULT_EN_SHIFT 1 +#define COPRO_CTRL_DCACHE_EN_SHIFT 2 +#define COPRO_CTRL_WRITEBUF_EN_SHIFT 3 +#define COPRO_CTRL_ENDIAN_SHIFT 7 +#define COPRO_CTRL_SYSTEM_SHIFT 8 +#define COPRO_CTRL_ROM_SHIFT 9 +#define COPRO_CTRL_ICACHE_EN_SHIFT 12 +#define COPRO_CTRL_INTVEC_ADJUST_SHIFT 13 +#define COPRO_CTRL_LITTLE_ENDIAN 0 +#define COPRO_CTRL_BIG_ENDIAN 1 +#define COPRO_CTRL_INTVEC_0 0 +#define COPRO_CTRL_INTVEC_F 1 +#define COPRO_CTRL_MASK 0x0000338f + +#define COPRO_DOMAIN_ACCESS_CONTROL m_domainAccessControl + +#define COPRO_FAULT_STATUS_D m_faultStatus[0] +#define COPRO_FAULT_STATUS_P m_faultStatus[1] + +#define COPRO_FAULT_ADDRESS m_faultAddress + +#define COPRO_FCSE_PID m_fcsePID + +enum +{ + eARM_ARCHFLAGS_T = 1, // Thumb present + eARM_ARCHFLAGS_E = 2, // extended DSP operations present (only for v5+) + eARM_ARCHFLAGS_J = 4, // "Jazelle" (direct execution of Java bytecode) + eARM_ARCHFLAGS_MMU = 8, // has on-board MMU (traditional ARM style like the SA1110) + eARM_ARCHFLAGS_SA = 16, // StrongARM extensions (enhanced TLB) + eARM_ARCHFLAGS_XSCALE = 32, // XScale extensions (CP14, enhanced TLB) + eARM_ARCHFLAGS_MODE26 = 64 // supports 26-bit backwards compatibility mode +}; + + +//#define ARM7_USE_DRC + +/* forward declaration of implementation-specific state */ +#ifndef ARM7_USE_DRC +struct arm7imp_state {}; +#else +struct arm7imp_state; +#endif + +/* CPU state struct */ +struct arm_state +{ + UINT32 m_r[NUM_REGS]; + UINT32 m_pendingIrq; + UINT32 m_pendingFiq; + UINT32 m_pendingAbtD; + UINT32 m_pendingAbtP; + UINT32 m_pendingUnd; + UINT32 m_pendingSwi; + int m_icount; + endianness_t m_endian; + address_space *m_program; + direct_read_data *m_direct; + + /* Coprocessor Registers */ + UINT32 m_control; + UINT32 m_tlbBase; + UINT32 m_faultStatus[2]; + UINT32 m_faultAddress; + UINT32 m_fcsePID; + UINT32 m_domainAccessControl; + + UINT8 m_archRev; // ARM architecture revision (3, 4, and 5 are valid) + UINT8 m_archFlags; // architecture flags + +#if ARM7_MMU_ENABLE_HACK + UINT32 mmu_enable_addr; // workaround for "MMU is enabled when PA != VA" problem +#endif + arm7imp_state m_impstate; +}; + +/**************************************************************************************************** + * VARIOUS INTERNAL STRUCS/DEFINES/ETC.. + ***************************************************************************************************/ +// Mode values come from bit 4-0 of CPSR, but we are ignoring bit 4 here, since bit 4 always = 1 for valid modes +enum +{ + eARM7_MODE_USER = 0x0, // Bit: 4-0 = 10000 + eARM7_MODE_FIQ = 0x1, // Bit: 4-0 = 10001 + eARM7_MODE_IRQ = 0x2, // Bit: 4-0 = 10010 + eARM7_MODE_SVC = 0x3, // Bit: 4-0 = 10011 + eARM7_MODE_ABT = 0x7, // Bit: 4-0 = 10111 + eARM7_MODE_UND = 0xb, // Bit: 4-0 = 11011 + eARM7_MODE_SYS = 0xf // Bit: 4-0 = 11111 +}; + +#define ARM7_NUM_MODES 0x10 + +static const int thumbCycles[256] = +{ +// 0 1 2 3 4 5 6 7 8 9 a b c d e f + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 3 + 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 4 + 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 5 + 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, // 6 + 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, // 7 + 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, // 8 + 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, // 9 + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // a + 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 2, 4, 1, 1, // b + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // c + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, // d + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // e + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 // f +}; + +/* 17 processor registers are visible at any given time, + * banked depending on processor mode. + */ + +static const int sRegisterTable[ARM7_NUM_MODES][18] = +{ + { /* USR */ + eR0, eR1, eR2, eR3, eR4, eR5, eR6, eR7, + eR8, eR9, eR10, eR11, eR12, + eR13, eR14, + eR15, eCPSR // No SPSR in this mode + }, + { /* FIQ */ + eR0, eR1, eR2, eR3, eR4, eR5, eR6, eR7, + eR8_FIQ, eR9_FIQ, eR10_FIQ, eR11_FIQ, eR12_FIQ, + eR13_FIQ, eR14_FIQ, + eR15, eCPSR, eSPSR_FIQ + }, + { /* IRQ */ + eR0, eR1, eR2, eR3, eR4, eR5, eR6, eR7, + eR8, eR9, eR10, eR11, eR12, + eR13_IRQ, eR14_IRQ, + eR15, eCPSR, eSPSR_IRQ + }, + { /* SVC */ + eR0, eR1, eR2, eR3, eR4, eR5, eR6, eR7, + eR8, eR9, eR10, eR11, eR12, + eR13_SVC, eR14_SVC, + eR15, eCPSR, eSPSR_SVC + }, + {0}, {0}, {0}, // values for modes 4,5,6 are not valid + { /* ABT */ + eR0, eR1, eR2, eR3, eR4, eR5, eR6, eR7, + eR8, eR9, eR10, eR11, eR12, + eR13_ABT, eR14_ABT, + eR15, eCPSR, eSPSR_ABT + }, + {0}, {0}, {0}, // values for modes 8,9,a are not valid! + { /* UND */ + eR0, eR1, eR2, eR3, eR4, eR5, eR6, eR7, + eR8, eR9, eR10, eR11, eR12, + eR13_UND, eR14_UND, + eR15, eCPSR, eSPSR_UND + }, + {0}, {0}, {0}, // values for modes c,d, e are not valid! + { /* SYS */ + eR0, eR1, eR2, eR3, eR4, eR5, eR6, eR7, + eR8, eR9, eR10, eR11, eR12, + eR13, eR14, + eR15, eCPSR // No SPSR in this mode + } +}; + +#define N_BIT 31 +#define Z_BIT 30 +#define C_BIT 29 +#define V_BIT 28 +#define Q_BIT 27 +#define I_BIT 7 +#define F_BIT 6 +#define T_BIT 5 // Thumb mode + +#define N_MASK ((UINT32)(1 << N_BIT)) /* Negative flag */ +#define Z_MASK ((UINT32)(1 << Z_BIT)) /* Zero flag */ +#define C_MASK ((UINT32)(1 << C_BIT)) /* Carry flag */ +#define V_MASK ((UINT32)(1 << V_BIT)) /* oVerflow flag */ +#define Q_MASK ((UINT32)(1 << Q_BIT)) /* signed overflow for QADD, MAC */ +#define I_MASK ((UINT32)(1 << I_BIT)) /* Interrupt request disable */ +#define F_MASK ((UINT32)(1 << F_BIT)) /* Fast interrupt request disable */ +#define T_MASK ((UINT32)(1 << T_BIT)) /* Thumb Mode flag */ + +#define N_IS_SET(pc) ((pc) & N_MASK) +#define Z_IS_SET(pc) ((pc) & Z_MASK) +#define C_IS_SET(pc) ((pc) & C_MASK) +#define V_IS_SET(pc) ((pc) & V_MASK) +#define Q_IS_SET(pc) ((pc) & Q_MASK) +#define I_IS_SET(pc) ((pc) & I_MASK) +#define F_IS_SET(pc) ((pc) & F_MASK) +#define T_IS_SET(pc) ((pc) & T_MASK) + +#define N_IS_CLEAR(pc) (!N_IS_SET(pc)) +#define Z_IS_CLEAR(pc) (!Z_IS_SET(pc)) +#define C_IS_CLEAR(pc) (!C_IS_SET(pc)) +#define V_IS_CLEAR(pc) (!V_IS_SET(pc)) +#define Q_IS_CLEAR(pc) (!Q_IS_SET(pc)) +#define I_IS_CLEAR(pc) (!I_IS_SET(pc)) +#define F_IS_CLEAR(pc) (!F_IS_SET(pc)) +#define T_IS_CLEAR(pc) (!T_IS_SET(pc)) + +/* Deconstructing an instruction */ +// todo: use these in all places (including dasm file) +#define INSN_COND ((UINT32)0xf0000000u) +#define INSN_SDT_L ((UINT32)0x00100000u) +#define INSN_SDT_W ((UINT32)0x00200000u) +#define INSN_SDT_B ((UINT32)0x00400000u) +#define INSN_SDT_U ((UINT32)0x00800000u) +#define INSN_SDT_P ((UINT32)0x01000000u) +#define INSN_BDT_L ((UINT32)0x00100000u) +#define INSN_BDT_W ((UINT32)0x00200000u) +#define INSN_BDT_S ((UINT32)0x00400000u) +#define INSN_BDT_U ((UINT32)0x00800000u) +#define INSN_BDT_P ((UINT32)0x01000000u) +#define INSN_BDT_REGS ((UINT32)0x0000ffffu) +#define INSN_SDT_IMM ((UINT32)0x00000fffu) +#define INSN_MUL_A ((UINT32)0x00200000u) +#define INSN_MUL_RM ((UINT32)0x0000000fu) +#define INSN_MUL_RS ((UINT32)0x00000f00u) +#define INSN_MUL_RN ((UINT32)0x0000f000u) +#define INSN_MUL_RD ((UINT32)0x000f0000u) +#define INSN_I ((UINT32)0x02000000u) +#define INSN_OPCODE ((UINT32)0x01e00000u) +#define INSN_S ((UINT32)0x00100000u) +#define INSN_BL ((UINT32)0x01000000u) +#define INSN_BRANCH ((UINT32)0x00ffffffu) +#define INSN_SWI ((UINT32)0x00ffffffu) +#define INSN_RN ((UINT32)0x000f0000u) +#define INSN_RD ((UINT32)0x0000f000u) +#define INSN_OP2 ((UINT32)0x00000fffu) +#define INSN_OP2_SHIFT ((UINT32)0x00000f80u) +#define INSN_OP2_SHIFT_TYPE ((UINT32)0x00000070u) +#define INSN_OP2_RM ((UINT32)0x0000000fu) +#define INSN_OP2_ROTATE ((UINT32)0x00000f00u) +#define INSN_OP2_IMM ((UINT32)0x000000ffu) +#define INSN_OP2_SHIFT_TYPE_SHIFT 4 +#define INSN_OP2_SHIFT_SHIFT 7 +#define INSN_OP2_ROTATE_SHIFT 8 +#define INSN_MUL_RS_SHIFT 8 +#define INSN_MUL_RN_SHIFT 12 +#define INSN_MUL_RD_SHIFT 16 +#define INSN_OPCODE_SHIFT 21 +#define INSN_RN_SHIFT 16 +#define INSN_RD_SHIFT 12 +#define INSN_COND_SHIFT 28 + +#define INSN_COPRO_N ((UINT32) 0x00100000u) +#define INSN_COPRO_CREG ((UINT32) 0x000f0000u) +#define INSN_COPRO_AREG ((UINT32) 0x0000f000u) +#define INSN_COPRO_CPNUM ((UINT32) 0x00000f00u) +#define INSN_COPRO_OP2 ((UINT32) 0x000000e0u) +#define INSN_COPRO_OP3 ((UINT32) 0x0000000fu) +#define INSN_COPRO_N_SHIFT 20 +#define INSN_COPRO_CREG_SHIFT 16 +#define INSN_COPRO_AREG_SHIFT 12 +#define INSN_COPRO_CPNUM_SHIFT 8 +#define INSN_COPRO_OP2_SHIFT 5 + +#define THUMB_INSN_TYPE ((UINT16)0xf000) +#define THUMB_COND_TYPE ((UINT16)0x0f00) +#define THUMB_GROUP4_TYPE ((UINT16)0x0c00) +#define THUMB_GROUP5_TYPE ((UINT16)0x0e00) +#define THUMB_GROUP5_RM ((UINT16)0x01c0) +#define THUMB_GROUP5_RN ((UINT16)0x0038) +#define THUMB_GROUP5_RD ((UINT16)0x0007) +#define THUMB_ADDSUB_RNIMM ((UINT16)0x01c0) +#define THUMB_ADDSUB_RS ((UINT16)0x0038) +#define THUMB_ADDSUB_RD ((UINT16)0x0007) +#define THUMB_INSN_CMP ((UINT16)0x0800) +#define THUMB_INSN_SUB ((UINT16)0x0800) +#define THUMB_INSN_IMM_RD ((UINT16)0x0700) +#define THUMB_INSN_IMM_S ((UINT16)0x0080) +#define THUMB_INSN_IMM ((UINT16)0x00ff) +#define THUMB_INSN_ADDSUB ((UINT16)0x0800) +#define THUMB_ADDSUB_TYPE ((UINT16)0x0600) +#define THUMB_HIREG_OP ((UINT16)0x0300) +#define THUMB_HIREG_H ((UINT16)0x00c0) +#define THUMB_HIREG_RS ((UINT16)0x0038) +#define THUMB_HIREG_RD ((UINT16)0x0007) +#define THUMB_STACKOP_TYPE ((UINT16)0x0f00) +#define THUMB_STACKOP_L ((UINT16)0x0800) +#define THUMB_STACKOP_RD ((UINT16)0x0700) +#define THUMB_ALUOP_TYPE ((UINT16)0x03c0) +#define THUMB_BLOP_LO ((UINT16)0x0800) +#define THUMB_BLOP_OFFS ((UINT16)0x07ff) +#define THUMB_SHIFT_R ((UINT16)0x0800) +#define THUMB_SHIFT_AMT ((UINT16)0x07c0) +#define THUMB_HALFOP_L ((UINT16)0x0800) +#define THUMB_HALFOP_OFFS ((UINT16)0x07c0) +#define THUMB_BRANCH_OFFS ((UINT16)0x07ff) +#define THUMB_LSOP_L ((UINT16)0x0800) +#define THUMB_LSOP_OFFS ((UINT16)0x07c0) +#define THUMB_MULTLS ((UINT16)0x0800) +#define THUMB_MULTLS_BASE ((UINT16)0x0700) +#define THUMB_RELADDR_SP ((UINT16)0x0800) +#define THUMB_RELADDR_RD ((UINT16)0x0700) +#define THUMB_INSN_TYPE_SHIFT 12 +#define THUMB_COND_TYPE_SHIFT 8 +#define THUMB_GROUP4_TYPE_SHIFT 10 +#define THUMB_GROUP5_TYPE_SHIFT 9 +#define THUMB_ADDSUB_TYPE_SHIFT 9 +#define THUMB_INSN_IMM_RD_SHIFT 8 +#define THUMB_STACKOP_TYPE_SHIFT 8 +#define THUMB_HIREG_OP_SHIFT 8 +#define THUMB_STACKOP_RD_SHIFT 8 +#define THUMB_MULTLS_BASE_SHIFT 8 +#define THUMB_RELADDR_RD_SHIFT 8 +#define THUMB_HIREG_H_SHIFT 6 +#define THUMB_HIREG_RS_SHIFT 3 +#define THUMB_ALUOP_TYPE_SHIFT 6 +#define THUMB_SHIFT_AMT_SHIFT 6 +#define THUMB_HALFOP_OFFS_SHIFT 6 +#define THUMB_LSOP_OFFS_SHIFT 6 +#define THUMB_GROUP5_RM_SHIFT 6 +#define THUMB_GROUP5_RN_SHIFT 3 +#define THUMB_GROUP5_RD_SHIFT 0 +#define THUMB_ADDSUB_RNIMM_SHIFT 6 +#define THUMB_ADDSUB_RS_SHIFT 3 +#define THUMB_ADDSUB_RD_SHIFT 0 + +enum +{ + OPCODE_AND, /* 0000 */ + OPCODE_EOR, /* 0001 */ + OPCODE_SUB, /* 0010 */ + OPCODE_RSB, /* 0011 */ + OPCODE_ADD, /* 0100 */ + OPCODE_ADC, /* 0101 */ + OPCODE_SBC, /* 0110 */ + OPCODE_RSC, /* 0111 */ + OPCODE_TST, /* 1000 */ + OPCODE_TEQ, /* 1001 */ + OPCODE_CMP, /* 1010 */ + OPCODE_CMN, /* 1011 */ + OPCODE_ORR, /* 1100 */ + OPCODE_MOV, /* 1101 */ + OPCODE_BIC, /* 1110 */ + OPCODE_MVN /* 1111 */ +}; + +enum +{ + COND_EQ = 0, /* Z equal */ + COND_NE, /* ~Z not equal */ + COND_CS, COND_HS = 2, /* C unsigned higher or same */ + COND_CC, COND_LO = 3, /* ~C unsigned lower */ + COND_MI, /* N negative */ + COND_PL, /* ~N positive or zero */ + COND_VS, /* V overflow */ + COND_VC, /* ~V no overflow */ + COND_HI, /* C && ~Z unsigned higher */ + COND_LS, /* ~C || Z unsigned lower or same */ + COND_GE, /* N == V greater or equal */ + COND_LT, /* N != V less than */ + COND_GT, /* ~Z && N == V greater than */ + COND_LE, /* Z || N != V less than or equal */ + COND_AL, /* 1 always */ + COND_NV /* 0 never */ +}; + +#define LSL(v, s) ((v) << (s)) +#define LSR(v, s) ((v) >> (s)) +#define ROL(v, s) (LSL((v), (s)) | (LSR((v), 32u - (s)))) +#define ROR(v, s) (LSR((v), (s)) | (LSL((v), 32u - (s)))) + +/* Convenience Macros */ +#define R15 m_r[eR15] +#define SPSR 17 // SPSR is always the 18th register in our 0 based array sRegisterTable[][18] +#define GET_CPSR m_r[eCPSR] +#define SET_CPSR(v) set_cpsr(v) +#define MODE_FLAG 0xF // Mode bits are 4:0 of CPSR, but we ignore bit 4. +#define GET_MODE (GET_CPSR & MODE_FLAG) +#define SIGN_BIT ((UINT32)(1 << 31)) +#define SIGN_BITS_DIFFER(a, b) (((a) ^ (b)) >> 31) +/* I really don't know why these were set to 16-bit, the thumb registers are still 32-bit ... */ +#define THUMB_SIGN_BIT ((UINT32)(1 << 31)) +#define THUMB_SIGN_BITS_DIFFER(a, b) (((a)^(b)) >> 31) + +#define SR_MODE32 0x10 + +#define MODE32 (GET_CPSR & SR_MODE32) +#define MODE26 (!(GET_CPSR & SR_MODE32)) +#define GET_PC (MODE32 ? R15 : R15 & 0x03FFFFFC) + +#define ARM7_TLB_ABORT_D (1 << 0) +#define ARM7_TLB_ABORT_P (1 << 1) +#define ARM7_TLB_READ (1 << 2) +#define ARM7_TLB_WRITE (1 << 3) + +/* At one point I thought these needed to be cpu implementation specific, but they don't.. */ +#define GET_REGISTER(reg) GetRegister(reg) +#define SET_REGISTER(reg, val) SetRegister(reg, val) +#define GET_MODE_REGISTER(mode, reg) GetModeRegister(mode, reg) +#define SET_MODE_REGISTER(mode, reg, val) SetModeRegister(mode, reg, val) +#define ARM7_CHECKIRQ arm7_check_irq_state() + + +/* ARM flavors */ +enum arm_flavor +{ + /* ARM7 variants */ + ARM_TYPE_ARM7, + ARM_TYPE_ARM7BE, + ARM_TYPE_ARM7500, + ARM_TYPE_PXA255, + ARM_TYPE_SA1110, + + /* ARM9 variants */ + ARM_TYPE_ARM9, + ARM_TYPE_ARM920T +}; + +#endif /* __ARM7CORE_H__ */ diff --git a/src/devices/cpu/arm7/arm7core.inc b/src/devices/cpu/arm7/arm7core.inc new file mode 100644 index 00000000000..736d42b0262 --- /dev/null +++ b/src/devices/cpu/arm7/arm7core.inc @@ -0,0 +1,220 @@ +// license:BSD-3-Clause +// copyright-holders:Steve Ellenoff,R. Belmont,Ryan Holtz +/***************************************************************************** + * + * arm7core.inc + * Portable ARM7TDMI Core Emulator + * + * Copyright Steve Ellenoff, all rights reserved. + * + * This work is based on: + * #1) 'Atmel Corporation ARM7TDMI (Thumb) Datasheet - January 1999' + * #2) Arm 2/3/6 emulator By Bryan McPhail (bmcphail@tendril.co.uk) and Phil Stroffolino (MAME CORE 0.76) + * #3) Thumb support by Ryan Holtz + * #4) Additional Thumb support and bugfixes by R. Belmont + * + *****************************************************************************/ + +/****************************************************************************** + * Notes: + + **This core comes from my AT91 cpu core contributed to PinMAME, + but with all the AT91 specific junk removed, + which leaves just the ARM7TDMI core itself. I further removed the CPU specific MAME stuff + so you just have the actual ARM7 core itself, since many cpu's incorporate an ARM7 core, but add on + many cpu specific functionality. + + Therefore, to use the core, you simpy include this file along with the .h file into your own cpu specific + implementation, and therefore, this file shouldn't be compiled as part of your project directly. + + For better or for worse, the code itself is very much intact from it's arm 2/3/6 origins from + Bryan & Phil's work. I contemplated merging it in, but thought the fact that the CPSR is + no longer part of the PC was enough of a change to make it annoying to merge. + ** + + Coprocessor functions are heavily implementation specific, so callback handlers are used to allow the + implementation to handle the functionality. Custom DASM handlers are included as well to allow the DASM + output to be tailored to the co-proc implementation details. + + Todo: + 26 bit compatibility mode not implemented. + Data Processing opcodes need cycle count adjustments (see page 194 of ARM7TDMI manual for instruction timing summary) + Multi-emulated cpu support untested, but probably will not work too well, as no effort was made to code for more than 1. + Could not find info on what the TEQP opcode is from page 44.. + I have no idea if user bank switching is right, as I don't fully understand it's use. + Search for Todo: tags for remaining items not done. + + + Differences from Arm 2/3 (6 also?) + -Thumb instruction support + -Full 32 bit address support + -PC no longer contains CPSR information, CPSR is own register now + -New register SPSR to store previous contents of CPSR (this register is banked in many modes) + -New opcodes for CPSR transfer, Long Multiplication, Co-Processor support, and some others + -User Bank Mode transfer using certain flags which were previously unallowed (LDM/STM with S Bit & R15) + -New operation modes? (unconfirmed) + + Based heavily on arm core from MAME 0.76: + ***************************************** + ARM 2/3/6 Emulation + + Todo: + Software interrupts unverified (nothing uses them so far, but they should be ok) + Timing - Currently very approximated, nothing relies on proper timing so far. + IRQ timing not yet correct (again, nothing is affected by this so far). + + By Bryan McPhail (bmcphail@tendril.co.uk) and Phil Stroffolino +*****************************************************************************/ + + +// convert cpsr mode num into to text +static const char modetext[ARM7_NUM_MODES][5] = { + "USER", "FIRQ", "IRQ", "SVC", "ILL1", "ILL2", "ILL3", "ABT", + "ILL4", "ILL5", "ILL6", "UND", "ILL7", "ILL8", "ILL9", "SYS" +}; +static const char *GetModeText(int cpsr) +{ + return modetext[cpsr & MODE_FLAG]; +} + + + + +/*************************************************************************** + * Main CPU Funcs + ***************************************************************************/ + +// CPU CHECK IRQ STATE +// Note: couldn't find any exact cycle counts for most of these exceptions +void arm7_cpu_device::arm7_check_irq_state() +{ + UINT32 cpsr = m_r[eCPSR]; /* save current CPSR */ + UINT32 pc = m_r[eR15] + 4; /* save old pc (already incremented in pipeline) */; + + /* Exception priorities: + + Reset + Data abort + FIRQ + IRQ + Prefetch abort + Undefined instruction + Software Interrupt + */ + + // Data Abort + if (m_pendingAbtD) { + if (MODE26) fatalerror( "pendingAbtD (todo)\n"); + SwitchMode(eARM7_MODE_ABT); /* Set ABT mode so PC is saved to correct R14 bank */ + SET_REGISTER(14, pc - 8 + 8); /* save PC to R14 */ + SET_REGISTER(SPSR, cpsr); /* Save current CPSR */ + SET_CPSR(GET_CPSR | I_MASK); /* Mask IRQ */ + SET_CPSR(GET_CPSR & ~T_MASK); + R15 = 0x10; /* IRQ Vector address */ + if ((COPRO_CTRL & COPRO_CTRL_MMU_EN) && (COPRO_CTRL & COPRO_CTRL_INTVEC_ADJUST)) R15 |= 0xFFFF0000; + m_pendingAbtD = 0; + return; + } + + // FIQ + if (m_pendingFiq && (cpsr & F_MASK) == 0) { + if (MODE26) fatalerror( "pendingFiq (todo)\n"); + SwitchMode(eARM7_MODE_FIQ); /* Set FIQ mode so PC is saved to correct R14 bank */ + SET_REGISTER(14, pc - 4 + 4); /* save PC to R14 */ + SET_REGISTER(SPSR, cpsr); /* Save current CPSR */ + SET_CPSR(GET_CPSR | I_MASK | F_MASK); /* Mask both IRQ & FIQ */ + SET_CPSR(GET_CPSR & ~T_MASK); + R15 = 0x1c; /* IRQ Vector address */ + if ((COPRO_CTRL & COPRO_CTRL_MMU_EN) && (COPRO_CTRL & COPRO_CTRL_INTVEC_ADJUST)) R15 |= 0xFFFF0000; + return; + } + + // IRQ + if (m_pendingIrq && (cpsr & I_MASK) == 0) { + SwitchMode(eARM7_MODE_IRQ); /* Set IRQ mode so PC is saved to correct R14 bank */ + SET_REGISTER(14, pc - 4 + 4); /* save PC to R14 */ + if (MODE32) + { + SET_REGISTER(SPSR, cpsr); /* Save current CPSR */ + SET_CPSR(GET_CPSR | I_MASK); /* Mask IRQ */ + SET_CPSR(GET_CPSR & ~T_MASK); + R15 = 0x18; /* IRQ Vector address */ + } + else + { + UINT32 temp; + R15 = (pc & 0xF4000000) /* N Z C V F */ | 0x18 | 0x00000002 /* IRQ */ | 0x08000000 /* I */; + temp = (GET_CPSR & 0x0FFFFF3F) /* N Z C V I F */ | (R15 & 0xF0000000) /* N Z C V */ | ((R15 & 0x0C000000) >> (26 - 6)) /* I F */; + SET_CPSR(temp); /* Mask IRQ */ + } + if ((COPRO_CTRL & COPRO_CTRL_MMU_EN) && (COPRO_CTRL & COPRO_CTRL_INTVEC_ADJUST)) R15 |= 0xFFFF0000; + return; + } + + // Prefetch Abort + if (m_pendingAbtP) { + if (MODE26) fatalerror( "pendingAbtP (todo)\n"); + SwitchMode(eARM7_MODE_ABT); /* Set ABT mode so PC is saved to correct R14 bank */ + SET_REGISTER(14, pc - 4 + 4); /* save PC to R14 */ + SET_REGISTER(SPSR, cpsr); /* Save current CPSR */ + SET_CPSR(GET_CPSR | I_MASK); /* Mask IRQ */ + SET_CPSR(GET_CPSR & ~T_MASK); + R15 = 0x0c; /* IRQ Vector address */ + if ((COPRO_CTRL & COPRO_CTRL_MMU_EN) && (COPRO_CTRL & COPRO_CTRL_INTVEC_ADJUST)) R15 |= 0xFFFF0000; + m_pendingAbtP = 0; + return; + } + + // Undefined instruction + if (m_pendingUnd) { + if (MODE26) fatalerror( "pendingUnd (todo)\n"); + SwitchMode(eARM7_MODE_UND); /* Set UND mode so PC is saved to correct R14 bank */ + // compensate for prefetch (should this also be done for normal IRQ?) + if (T_IS_SET(GET_CPSR)) + { + SET_REGISTER(14, pc - 4 + 2); /* save PC to R14 */ + } + else + { + SET_REGISTER(14, pc - 4 + 4 - 4); /* save PC to R14 */ + } + SET_REGISTER(SPSR, cpsr); /* Save current CPSR */ + SET_CPSR(GET_CPSR | I_MASK); /* Mask IRQ */ + SET_CPSR(GET_CPSR & ~T_MASK); + R15 = 0x04; /* IRQ Vector address */ + if ((COPRO_CTRL & COPRO_CTRL_MMU_EN) && (COPRO_CTRL & COPRO_CTRL_INTVEC_ADJUST)) R15 |= 0xFFFF0000; + m_pendingUnd = 0; + return; + } + + // Software Interrupt + if (m_pendingSwi) { + SwitchMode(eARM7_MODE_SVC); /* Set SVC mode so PC is saved to correct R14 bank */ + // compensate for prefetch (should this also be done for normal IRQ?) + if (T_IS_SET(GET_CPSR)) + { + SET_REGISTER(14, pc - 4 + 2); /* save PC to R14 */ + } + else + { + SET_REGISTER(14, pc - 4 + 4); /* save PC to R14 */ + } + if (MODE32) + { + SET_REGISTER(SPSR, cpsr); /* Save current CPSR */ + SET_CPSR(GET_CPSR | I_MASK); /* Mask IRQ */ + SET_CPSR(GET_CPSR & ~T_MASK); /* Go to ARM mode */ + R15 = 0x08; /* Jump to the SWI vector */ + } + else + { + UINT32 temp; + R15 = (pc & 0xF4000000) /* N Z C V F */ | 0x08 | 0x00000003 /* SVC */ | 0x08000000 /* I */; + temp = (GET_CPSR & 0x0FFFFF3F) /* N Z C V I F */ | (R15 & 0xF0000000) /* N Z C V */ | ((R15 & 0x0C000000) >> (26 - 6)) /* I F */; + SET_CPSR(temp); /* Mask IRQ */ + } + if ((COPRO_CTRL & COPRO_CTRL_MMU_EN) && (COPRO_CTRL & COPRO_CTRL_INTVEC_ADJUST)) R15 |= 0xFFFF0000; + m_pendingSwi = 0; + return; + } +} diff --git a/src/devices/cpu/arm7/arm7dasm.c b/src/devices/cpu/arm7/arm7dasm.c new file mode 100644 index 00000000000..b749d3624a2 --- /dev/null +++ b/src/devices/cpu/arm7/arm7dasm.c @@ -0,0 +1,1331 @@ +// license:BSD-3-Clause +// copyright-holders:Steve Ellenoff,R. Belmont,Ryan Holtz +/***************************************************************************** + * + * arm7dasm.c + * Portable ARM7TDMI Core Emulator - Disassembler + * + * Copyright Steve Ellenoff, all rights reserved. + * + * This work is based on: + * #1) 'Atmel Corporation ARM7TDMI (Thumb) Datasheet - January 1999' + * #2) Arm 2/3/6 emulator By Bryan McPhail (bmcphail@tendril.co.uk) and Phil Stroffolino (MAME CORE 0.76) + * + *****************************************************************************/ +/****************************************************************************** + * Notes: + * + * Because Co-Processor functions are highly specialized to the actual co-proc + * implementation being used, I've setup callback handlers to allow for custom + * dasm display of the co-proc functions so that the implementation specific + * commands/interpretation can be used. If not used, the default handlers which + * implement the ARM7TDMI guideline format is used + ******************************************************************************/ + +#include "emu.h" +#include "arm7core.h" + +static char *WritePadding( char *pBuf, const char *pBuf0 ) +{ + pBuf0 += 8; + while( pBuf>8)&0xf, (opcode>>21)&7, (opcode>>12)&0xf, (opcode>>16)&0xf, opcode&0xf ); + if((opcode>>5)&7) pBuf += sprintf( pBuf, ", %d",(opcode>>5)&7); + return pBuf; +} + +static char *DasmCoProc_DT( char *pBuf, UINT32 opcode, const char *pConditionCode, const char *pBuf0 ) +{ + /* co processor data transfer */ + /* xxxx 111P UNWL nnnn dddd pppp oooooooo */ + //todo: test this on valid instructions + + pBuf += sprintf(pBuf, "%s%s",(opcode&0x00100000)?"LDC":"STC",pConditionCode); //Bit 20 = 1 for Load, 0 for Store + //Long Operation + if(opcode & 0x400000) pBuf += sprintf(pBuf, "L"); + pBuf = WritePadding( pBuf, pBuf0 ); + + //P# & CD # + pBuf += sprintf(pBuf, "p%d, c%d, ",(opcode>>8)&0x0f,(opcode>>12)&0x0f); + + //Base Register (Rn) + pBuf += sprintf(pBuf, "[R%d%s",(opcode>>16)&0x0f,(opcode&0x1000000)?"":"]"); //If Bit 24 = 1, Pre-increment, otherwise, Post increment so close brace + + //immediate value ( 8 bit value is << 2 according to manual ) + if(opcode & 0xff) pBuf += sprintf(pBuf, ",%s#$%x",(opcode&0x800000)?"":"-",(opcode & 0xff)<<2); + + //Pre-Inc brace & Write back + pBuf += sprintf(pBuf, "%s%s",(opcode&0x1000000)?"]":"",(opcode&0x200000)?"{!}":""); + return pBuf; +} + +static char *DasmCoProc_DO( char *pBuf, UINT32 opcode, const char *pConditionCode, const char *pBuf0 ) +{ + /* co processor data operation */ + /* xxxx 1110 oooo nnnn dddd cccc ppp0 mmmm */ + pBuf += sprintf( pBuf, "CDP" ); + pBuf += sprintf( pBuf, "%s", pConditionCode ); + pBuf = WritePadding( pBuf, pBuf0 ); + //p#,CPOpc,cd,cn,cm + pBuf += sprintf( pBuf, "p%d, %d, c%d, c%d, c%d", + (opcode>>8)&0xf, (opcode>>20)&0xf, (opcode>>12)&0xf, (opcode>>16)&0xf, opcode&0xf ); + if((opcode>>5)&7) pBuf += sprintf( pBuf, ", %d",(opcode>>5)&7); + return pBuf; +} + +static char *WriteImmediateOperand( char *pBuf, UINT32 opcode ) +{ + /* rrrrbbbbbbbb */ + UINT32 imm; + int r; + + imm = opcode&0xff; + r = ((opcode>>8)&0xf)*2; + imm = (imm>>r)|(r?(imm<<(32-r)):0); + pBuf += sprintf( pBuf, ", #$%x", imm ); + return pBuf; +} + +static char *WriteDataProcessingOperand( char *pBuf, UINT32 opcode, int printOp0, int printOp1, int printOp2 ) +{ + /* ccccctttmmmm */ + static const char *const pRegOp[4] = { "LSL","LSR","ASR","ROR" }; + + if (printOp0) + pBuf += sprintf(pBuf,"R%d, ", (opcode>>12)&0xf); + if (printOp1) + pBuf += sprintf(pBuf,"R%d, ", (opcode>>16)&0xf); + + /* Immediate Op2 */ + if( opcode&0x02000000 ) + return WriteImmediateOperand(pBuf-2,opcode); + + /* Register Op2 */ + if (printOp2) +//SJE: pBuf += sprintf(pBuf,"R%d, ", (opcode>>0)&0xf); + pBuf += sprintf(pBuf,"R%d ", (opcode>>0)&0xf); + + //SJE: ignore if LSL#0 for register shift + if( ((opcode&0x2000000) == 0) && (((opcode>>4) & 0xff)==0) ) + return pBuf; + + pBuf += sprintf(pBuf, ",%s ", pRegOp[(opcode>>5)&3] ); + //SJE: pBuf += sprintf(pBuf, "%s ", pRegOp[(opcode>>5)&3] ); + + if( opcode&0x10 ) /* Shift amount specified in bottom bits of RS */ + { + pBuf += sprintf( pBuf, "R%d", (opcode>>8)&0xf ); + } + else /* Shift amount immediate 5 bit unsigned integer */ + { + int c=(opcode>>7)&0x1f; + if( c==0 ) c = 32; + pBuf += sprintf( pBuf, "#%d", c ); + } + return pBuf; +} + +static char *WriteRegisterOperand1( char *pBuf, UINT32 opcode ) +{ + /* ccccctttmmmm */ + static const char *const pRegOp[4] = { "LSL","LSR","ASR","ROR" }; + + pBuf += sprintf( + pBuf, + ", R%d", /* Operand 1 register, Operand 2 register, shift type */ + (opcode>> 0)&0xf); + + //check for LSL 0 + if( (((opcode>>5)&3)==0) && (((opcode>>7)&0xf)==0) ) + return pBuf; + else + //Add rotation type + pBuf += sprintf(pBuf," %s ",pRegOp[(opcode>>5)&3]); + + if( opcode&0x10 ) /* Shift amount specified in bottom bits of RS */ + { + pBuf += sprintf( pBuf, "R%d", (opcode>>7)&0xf ); + } + else /* Shift amount immediate 5 bit unsigned integer */ + { + int c=(opcode>>7)&0x1f; + if( c==0 ) c = 32; + pBuf += sprintf( pBuf, "#%d", c ); + } + return pBuf; +} /* WriteRegisterOperand */ + + +static char *WriteBranchAddress( char *pBuf, UINT32 pc, UINT32 opcode ) +{ + opcode &= 0x00ffffff; + if( opcode&0x00800000 ) + { + opcode |= 0xff000000; /* sign-extend */ + } + pc += 8+4*opcode; + sprintf( pBuf, "$%x", pc ); + return pBuf; +} /* WriteBranchAddress */ + +static UINT32 arm7_disasm( char *pBuf, UINT32 pc, UINT32 opcode ) +{ + const char *pBuf0; + + static const char *const pConditionCodeTable[16] = + { + "EQ","NE","CS","CC", + "MI","PL","VS","VC", + "HI","LS","GE","LT", + "GT","LE","","NV" + }; + static const char *const pOperation[16] = + { + "AND","EOR","SUB","RSB", + "ADD","ADC","SBC","RSC", + "TST","TEQ","CMP","CMN", + "ORR","MOV","BIC","MVN" + }; + const char *pConditionCode; + UINT32 dasmflags = 0; + + pConditionCode= pConditionCodeTable[opcode>>28]; + pBuf0 = pBuf; + + if( (opcode&0x0ffffff0)==0x012fff10 ) { //bits 27-4 == 000100101111111111110001 + /* Branch and Exchange (BX) */ + pBuf += sprintf( pBuf, "B"); + pBuf += sprintf( pBuf, "%sX", pConditionCode ); + pBuf = WritePadding( pBuf, pBuf0 ); + pBuf += sprintf( pBuf, "R%d",(opcode&0xf)); + if ((opcode & 0x0f) == 14) + dasmflags = DASMFLAG_STEP_OUT; + } + else if ((opcode & 0x0ff000f0) == 0x01600010) // CLZ - v5 + { + pBuf += sprintf(pBuf, "CLZ"); + pBuf = WritePadding( pBuf, pBuf0 ); + pBuf += sprintf(pBuf, "R%d, R%d", (opcode>>12)&0xf, opcode&0xf); + } + else if ((opcode & 0x0ff000f0) == 0x01000050) // QADD - v5 + { + pBuf += sprintf(pBuf, "QADD"); + pBuf = WritePadding( pBuf, pBuf0 ); + pBuf += sprintf(pBuf, "R%d, R%d, R%d", (opcode>>12)&0xf, opcode&0xf, (opcode>>16)&0xf); + } + else if ((opcode & 0x0ff000f0) == 0x01400050) // QDADD - v5 + { + pBuf += sprintf(pBuf, "QDADD"); + pBuf = WritePadding( pBuf, pBuf0 ); + pBuf += sprintf(pBuf, "R%d, R%d, R%d", (opcode>>12)&0xf, opcode&0xf, (opcode>>16)&0xf); + } + else if ((opcode & 0x0ff000f0) == 0x01200050) // QSUB - v5 + { + pBuf += sprintf(pBuf, "QSUB"); + pBuf = WritePadding( pBuf, pBuf0 ); + pBuf += sprintf(pBuf, "R%d, R%d, R%d", (opcode>>12)&0xf, opcode&0xf, (opcode>>16)&0xf); + } + else if ((opcode & 0x0ff000f0) == 0x01600050) // QDSUB - v5 + { + pBuf += sprintf(pBuf, "QDSUB"); + pBuf = WritePadding( pBuf, pBuf0 ); + pBuf += sprintf(pBuf, "R%d, R%d, R%d", (opcode>>12)&0xf, opcode&0xf, (opcode>>16)&0xf); + } + else if ((opcode & 0x0ff00090) == 0x01000080) // SMLAxy - v5 + { + pBuf += sprintf(pBuf, "SMLA%c%c", (opcode&0x20) ? 'T' : 'B', (opcode&0x40) ? 'T' : 'B'); + pBuf = WritePadding( pBuf, pBuf0 ); + pBuf += sprintf(pBuf, "R%d, R%d, R%d, R%d", (opcode>>16)&0xf, (opcode>>12)&0xf, opcode&0xf, (opcode>>8)&0xf); + } + else if ((opcode & 0x0ff00090) == 0x01400080) // SMLALxy - v5 + { + pBuf += sprintf(pBuf, "SMLAL%c%c", (opcode&0x20) ? 'T' : 'B', (opcode&0x40) ? 'T' : 'B'); + pBuf = WritePadding( pBuf, pBuf0 ); + pBuf += sprintf(pBuf, "R%d, R%d, R%d, R%d", (opcode>>16)&0xf, (opcode>>12)&0xf, opcode&0xf, (opcode>>8)&0xf); + } + else if ((opcode & 0x0ff00090) == 0x01600080) // SMULxy - v5 + { + pBuf += sprintf(pBuf, "SMUL%c%c", (opcode&0x20) ? 'T' : 'B', (opcode&0x40) ? 'T' : 'B'); + pBuf = WritePadding( pBuf, pBuf0 ); + pBuf += sprintf(pBuf, "R%d, R%d, R%d", (opcode>>16)&0xf, opcode&0xf, (opcode>>12)&0xf); + } + else if ((opcode & 0x0ff000b0) == 0x012000a0) // SMULWy - v5 + { + pBuf += sprintf(pBuf, "SMULW%c", (opcode&0x40) ? 'T' : 'B'); + pBuf = WritePadding( pBuf, pBuf0 ); + pBuf += sprintf(pBuf, "R%d, R%d, R%d", (opcode>>16)&0xf, opcode&0xf, (opcode>>8)&0xf); + } + else if ((opcode & 0x0ff000b0) == 0x01200080) // SMLAWy - v5 + { + pBuf += sprintf(pBuf, "SMLAW%c", (opcode&0x40) ? 'T' : 'B'); + pBuf = WritePadding( pBuf, pBuf0 ); + pBuf += sprintf(pBuf, "R%d, R%d, R%d, R%d", (opcode>>16)&0xf, opcode&0xf, (opcode>>8)&0xf, (opcode>>12)&0xf); + } + else if( (opcode&0x0e000000)==0 && (opcode&0x80) && (opcode&0x10) ) //bits 27-25 == 000, bit 7=1, bit 4=1 + { + /* multiply or swap or half word data transfer */ + if(opcode&0x60) + { //bits = 6-5 != 00 + /* half word data transfer */ + if (((opcode & 0x60) == 0x40) && !(opcode & 0x100000)) // bit 20 = 0, bits 5&6 = 10 is ARMv5 LDRD + { + pBuf += sprintf(pBuf, "LDRD%s", pConditionCode); + } + else if (((opcode & 0x60) == 0x60) && !(opcode & 0x100000)) // bit 20 = 0, bits 5&6 = 11 is ARMv5 STRD + { + pBuf += sprintf(pBuf, "STRD%s", pConditionCode); + } + else + { + pBuf += sprintf(pBuf, "%s%s",(opcode&0x00100000)?"LDR":"STR",pConditionCode); //Bit 20 = 1 for Load, 0 for Store + + //Signed? (if not, always unsigned half word) + if(opcode&0x40) + { + pBuf += sprintf(pBuf, "%s",(opcode&0x20)?"SH":"SB"); //Bit 5 = 1 for Half Word, 0 for Byte + } + else + { + pBuf += sprintf(pBuf, "H"); + } + } + + pBuf = WritePadding( pBuf, pBuf0 ); + + //Dest Register + pBuf += sprintf(pBuf, "R%d, ",(opcode>>12)&0x0f); + //Base Register + pBuf += sprintf(pBuf, "[R%d%s",(opcode>>16)&0x0f,(opcode&0x1000000)?"":"]"); //If Bit 24 = 1, Pre-increment, otherwise, Post increment so close brace + + //Immediate or Register Offset? + if(opcode&0x400000) { //Bit 22 - 1 = immediate, 0 = register + //immediate ( imm. value in high nibble (bits 8-11) and lo nibble (bit 0-3) ) + pBuf += sprintf(pBuf, ",%s#$%x",(opcode&0x800000)?"":"-",( (((opcode>>8)&0x0f)<<4) | (opcode&0x0f))); + } + else { + //register + pBuf += sprintf(pBuf, ",%sR%d",(opcode&0x800000)?"":"-",(opcode & 0x0f)); + } + + //Pre-Inc brace & Write back + pBuf += sprintf(pBuf, "%s%s",(opcode&0x1000000)?"]":"",(opcode&0x200000)?"{!}":""); + } + else { + if(opcode&0x01000000) { //bit 24 = 1 + /* swap */ + //todo: Test on valid instructions + /* xxxx 0001 0B00 nnnn dddd 0000 1001 mmmm */ + pBuf += sprintf( pBuf, "SWP" ); + pBuf += sprintf( pBuf, "%s%s", pConditionCode, (opcode & 0x400000)?"B":"" ); //Bit 22 = Byte/Word selection + //Rd, Rm, [Rn] + pBuf += sprintf( pBuf, "R%d, R%d, [R%d]", + (opcode>>12)&0xf, opcode&0xf, (opcode>>16)&0xf ); + } + else { + /* multiply or multiply long */ + + if( opcode&0x800000 ) //Bit 23 = 1 for Multiply Long + { + /* Multiply Long */ + /* xxxx0001 UAShhhhllllnnnn1001mmmm */ + + /* Signed? */ + if( opcode&0x00400000 ) + pBuf += sprintf( pBuf, "S" ); + else + pBuf += sprintf( pBuf, "U" ); + + /* Multiply & Accumulate? */ + if( opcode&0x00200000 ) + { + pBuf += sprintf( pBuf, "MLAL" ); + } + else + { + pBuf += sprintf( pBuf, "MULL" ); + } + pBuf += sprintf( pBuf, "%s", pConditionCode ); + + /* Set Status Flags */ + if( opcode&0x00100000 ) + { + *pBuf++ = 'S'; + } + pBuf = WritePadding( pBuf, pBuf0 ); + + //Format is RLo,RHi,Rm,Rs + pBuf += sprintf( pBuf, + "R%d, R%d, R%d, R%d", + (opcode>>12)&0xf, + (opcode>>16)&0xf, + (opcode&0xf), + (opcode>>8)&0xf); + } + else + { + /* Multiply */ + /* xxxx0000 00ASdddd nnnnssss 1001mmmm */ + + /* Multiply & Accumulate? */ + if( opcode&0x00200000 ) + { + pBuf += sprintf( pBuf, "MLA" ); + } + /* Multiply */ + else + { + pBuf += sprintf( pBuf, "MUL" ); + } + pBuf += sprintf( pBuf, "%s", pConditionCode ); + if( opcode&0x00100000 ) + { + *pBuf++ = 'S'; + } + pBuf = WritePadding( pBuf, pBuf0 ); + + pBuf += sprintf( pBuf, + "R%d, R%d, R%d", + (opcode>>16)&0xf, + (opcode&0xf), + (opcode>>8)&0xf ); + + if( opcode&0x00200000 ) + { + pBuf += sprintf( pBuf, ", R%d", (opcode>>12)&0xf ); + } + } + } + } + } + else if( (opcode&0x0c000000)==0 ) //bits 27-26 == 00 - This check can only exist properly after Multiplication check above + { + /* Data Processing OR PSR Transfer */ + + //SJE: check for MRS & MSR ( S bit must be clear, and bit 24,23 = 10 ) + if( ((opcode&0x00100000)==0) && ((opcode&0x01800000)==0x01000000) ) { + char strpsr[6]; + sprintf(strpsr, "%s",(opcode&0x400000)?"SPSR":"CPSR"); + + //MSR ( bit 21 set ) + if( (opcode&0x00200000) ) { + pBuf += sprintf(pBuf, "MSR%s",pConditionCode ); + //Flag Bits Only? (Bit 16 Clear) + if( (opcode&0x10000)==0) pBuf += sprintf(pBuf, "F"); + pBuf = WritePadding( pBuf, pBuf0 ); + pBuf += sprintf(pBuf, "%s,",strpsr); + WriteDataProcessingOperand(pBuf, opcode, (opcode&0x02000000)?1:0, 0, 1); + } + //MRS ( bit 21 clear ) + else { + pBuf += sprintf(pBuf, "MRS%s",pConditionCode ); + pBuf = WritePadding( pBuf, pBuf0 ); + pBuf += sprintf(pBuf, "R%d,",(opcode>>12)&0x0f); + pBuf += sprintf(pBuf, "%s",strpsr); + } + } + else { + /* Data Processing */ + /* xxxx001a aaaSnnnn ddddrrrr bbbbbbbb */ + /* xxxx000a aaaSnnnn ddddcccc ctttmmmm */ + int op=(opcode>>21)&0xf; + pBuf += sprintf( + pBuf, "%s%s", + pOperation[op], + pConditionCode ); + + //SJE: corrected S-Bit bug here + //if( (opcode&0x01000000) ) + if( (opcode&0x0100000) ) + { + *pBuf++ = 'S'; + } + + pBuf = WritePadding( pBuf, pBuf0 ); + + switch (op) { + case 0x00: + case 0x01: + case 0x02: + case 0x03: + case 0x04: + case 0x05: + case 0x06: + case 0x07: + case 0x0c: + case 0x0e: + WriteDataProcessingOperand(pBuf, opcode, 1, 1, 1); + break; + case 0x08: + case 0x09: + case 0x0a: + case 0x0b: + WriteDataProcessingOperand(pBuf, opcode, 0, 1, 1); + break; + case 0x0d: + /* look for mov pc,lr */ + if (((opcode >> 12) & 0x0f) == 15 && ((opcode >> 0) & 0x0f) == 14 && (opcode & 0x02000000) == 0) + dasmflags = DASMFLAG_STEP_OUT; + case 0x0f: + WriteDataProcessingOperand(pBuf, opcode, 1, 0, 1); + break; + } + } + } + else if( (opcode&0x0c000000)==0x04000000 ) //bits 27-26 == 01 + { + UINT32 rn = 0; + UINT32 rnv = 0; + + /* Data Transfer */ + + /* xxxx010P UBWLnnnn ddddoooo oooooooo Immediate form */ + /* xxxx011P UBWLnnnn ddddcccc ctt0mmmm Register form */ + if( opcode&0x00100000 ) + { + pBuf += sprintf( pBuf, "LDR" ); + } + else + { + pBuf += sprintf( pBuf, "STR" ); + } + pBuf += sprintf( pBuf, "%s", pConditionCode ); + + if( opcode&0x00400000 ) + { + pBuf += sprintf( pBuf, "B" ); + } + + if( opcode&0x00200000 ) + { + /* writeback addr */ + if( opcode&0x01000000 ) + { + /* pre-indexed addressing */ + pBuf += sprintf( pBuf, "!" ); + } + else + { + /* post-indexed addressing */ + pBuf += sprintf( pBuf, "T" ); + } + } + + pBuf = WritePadding( pBuf, pBuf0 ); + pBuf += sprintf( pBuf, "R%d, [R%d", + (opcode>>12)&0xf, (opcode>>16)&0xf ); + + //grab value of pc if used as base register + rn = (opcode>>16)&0xf; + if(rn==15) rnv = pc+8; + + if( opcode&0x02000000 ) + { + /* register form */ + pBuf += sprintf( pBuf, "%s",(opcode&0x01000000)?"":"]" ); + pBuf = WriteRegisterOperand1( pBuf, opcode ); + pBuf += sprintf( pBuf, "%s",(opcode&0x01000000)?"]":"" ); + } + else + { + /* immediate form */ + pBuf += sprintf( pBuf, "%s",(opcode&0x01000000)?"":"]" ); + //hide zero offsets + if(opcode&0xfff) { + if( opcode&0x00800000 ) + { + pBuf += sprintf( pBuf, ", #$%x", opcode&0xfff ); + rnv += (rnv)?opcode&0xfff:0; + } + else + { + pBuf += sprintf( pBuf, ", -#$%x", opcode&0xfff ); + rnv -= (rnv)?opcode&0xfff:0; + } + } + pBuf += sprintf( pBuf, "%s",(opcode&0x01000000)?"]":"" ); + //show where the read will occur if we found a value + if(rnv) pBuf += sprintf( pBuf, " (%x)",rnv); + } + } + else if( (opcode&0x0e000000) == 0x08000000 ) //bits 27-25 == 100 + { + /* xxxx100P USWLnnnn llllllll llllllll */ + /* Block Data Transfer */ + + if( opcode&0x00100000 ) + { + pBuf += sprintf( pBuf, "LDM" ); + } + else + { + pBuf += sprintf( pBuf, "STM" ); + } + pBuf += sprintf( pBuf, "%s", pConditionCode ); + + if( opcode&0x01000000 ) + { + pBuf += sprintf( pBuf, "P" ); + } + if( opcode&0x00800000 ) + { + pBuf += sprintf( pBuf, "U" ); + } + if( opcode&0x00400000 ) + { + pBuf += sprintf( pBuf, "^" ); + } + if( opcode&0x00200000 ) + { + pBuf += sprintf( pBuf, "W" ); + } + + pBuf = WritePadding( pBuf, pBuf0 ); + pBuf += sprintf( pBuf, "[R%d], {",(opcode>>16)&0xf); + + { + int j=0,last=0,found=0; + for (j=0; j<16; j++) { + if (opcode&(1<> THUMB_INSN_TYPE_SHIFT ) + { + case 0x0: /* Logical shifting */ + if( opcode & THUMB_SHIFT_R ) /* Shift right */ + { + rs = ( opcode & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT; + rd = ( opcode & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT; + offs = ( opcode & THUMB_SHIFT_AMT ) >> THUMB_SHIFT_AMT_SHIFT; + pBuf += sprintf( pBuf, "LSR R%d, R%d, %d", rd, rs, offs); + } + else /* Shift left */ + { + rs = ( opcode & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT; + rd = ( opcode & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT; + offs = ( opcode & THUMB_SHIFT_AMT ) >> THUMB_SHIFT_AMT_SHIFT; + pBuf += sprintf( pBuf, "LSL R%d, R%d, %d", rd, rs, offs); + } + break; + case 0x1: /* Arithmetic */ + if( opcode & THUMB_INSN_ADDSUB ) + { + switch( ( opcode & THUMB_ADDSUB_TYPE ) >> THUMB_ADDSUB_TYPE_SHIFT ) + { + case 0x0: /* ADD Rd, Rs, Rn */ + rn = ( opcode & THUMB_ADDSUB_RNIMM ) >> THUMB_ADDSUB_RNIMM_SHIFT; + rs = ( opcode & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT; + rd = ( opcode & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT; + pBuf += sprintf( pBuf, "ADD R%d, R%d, R%d", rd, rs, rn ); + break; + case 0x1: /* SUB Rd, Rs, Rn */ + rn = ( opcode & THUMB_ADDSUB_RNIMM ) >> THUMB_ADDSUB_RNIMM_SHIFT; + rs = ( opcode & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT; + rd = ( opcode & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT; + pBuf += sprintf( pBuf, "SUB R%d, R%d, R%d", rd, rs, rn ); + break; + case 0x2: /* ADD Rd, Rs, #imm */ + imm = ( opcode & THUMB_ADDSUB_RNIMM ) >> THUMB_ADDSUB_RNIMM_SHIFT; + rs = ( opcode & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT; + rd = ( opcode & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT; + pBuf += sprintf( pBuf, "ADD R%d, R%d, #%d", rd, rs, imm ); + break; + case 0x3: /* SUB Rd, Rs, #imm */ + imm = ( opcode & THUMB_ADDSUB_RNIMM ) >> THUMB_ADDSUB_RNIMM_SHIFT; + rs = ( opcode & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT; + rd = ( opcode & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT; + pBuf += sprintf( pBuf, "SUB R%d, R%d, #%d", rd, rs, imm ); + break; + default: + sprintf( pBuf, "INVALID %04x", opcode); + break; + } + } + else + { + rs = ( opcode & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT; + rd = ( opcode & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT; + offs = ( opcode & THUMB_SHIFT_AMT ) >> THUMB_SHIFT_AMT_SHIFT; + pBuf += sprintf( pBuf, "ASR R%d, R%d, %d", rd, rs, offs); + } + break; + case 0x2: /* CMP / MOV */ + if( opcode & THUMB_INSN_CMP ) + { + rn = ( opcode & THUMB_INSN_IMM_RD ) >> THUMB_INSN_IMM_RD_SHIFT; + op2 = ( opcode & THUMB_INSN_IMM ); + pBuf += sprintf( pBuf, "CMP R%d, %02x", rn, op2 ); + } + else + { + rd = ( opcode & THUMB_INSN_IMM_RD ) >> THUMB_INSN_IMM_RD_SHIFT; + op2 = ( opcode & THUMB_INSN_IMM ); + pBuf += sprintf( pBuf, "MOV R%d, %02x", rd, op2 ); + } + break; + case 0x3: /* ADD/SUB immediate */ + if( opcode & THUMB_INSN_SUB ) /* SUB Rd, #Offset8 */ + { + rn = ( opcode & THUMB_INSN_IMM_RD ) >> THUMB_INSN_IMM_RD_SHIFT; + op2 = ( opcode & THUMB_INSN_IMM ); + pBuf += sprintf( pBuf, "SUB R%d, %02x", rn, op2 ); // fixed, rd -> rn + } + else /* ADD Rd, #Offset8 */ + { + rn = ( opcode & THUMB_INSN_IMM_RD ) >> THUMB_INSN_IMM_RD_SHIFT; + op2 = opcode & THUMB_INSN_IMM; + pBuf += sprintf( pBuf, "ADD R%d, %02x", rn, op2 ); + } + break; + case 0x4: /* Rd & Rm instructions */ + switch( ( opcode & THUMB_GROUP4_TYPE ) >> THUMB_GROUP4_TYPE_SHIFT ) + { + case 0x0: + switch( ( opcode & THUMB_ALUOP_TYPE ) >> THUMB_ALUOP_TYPE_SHIFT ) + { + case 0x0: /* AND Rd, Rs */ + rs = ( opcode & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT; + rd = ( opcode & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT; + pBuf += sprintf( pBuf, "AND R%d, R%d", rd, rs ); + break; + case 0x1: /* EOR Rd, Rs */ + rs = ( opcode & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT; + rd = ( opcode & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT; + pBuf += sprintf( pBuf, "EOR R%d, R%d", rd, rs ); + break; + case 0x2: /* LSL Rd, Rs */ + rs = ( opcode & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT; + rd = ( opcode & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT; + pBuf += sprintf( pBuf, "LSL R%d, R%d", rd, rs ); + break; + case 0x3: /* LSR Rd, Rs */ + rs = ( opcode & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT; + rd = ( opcode & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT; + pBuf += sprintf( pBuf, "LSR R%d, R%d", rd, rs ); + break; + case 0x4: /* ASR Rd, Rs */ + rs = ( opcode & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT; + rd = ( opcode & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT; + pBuf += sprintf( pBuf, "ASR R%d, R%d", rd, rs ); + break; + case 0x5: /* ADC Rd, Rs */ + rs = ( opcode & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT; + rd = ( opcode & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT; + pBuf += sprintf( pBuf, "ADC R%d, R%d", rd, rs ); + break; + case 0x6: /* SBC Rd, Rs */ + rs = ( opcode & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT; + rd = ( opcode & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT; + pBuf += sprintf( pBuf, "SBC R%d, R%d", rd, rs ); + break; + case 0x7: /* ROR Rd, Rs */ + rs = ( opcode & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT; + rd = ( opcode & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT; + pBuf += sprintf( pBuf, "ROR R%d, R%d", rd, rs ); + break; + case 0x8: /* TST Rd, Rs */ + rs = ( opcode & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT; + rd = ( opcode & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT; + pBuf += sprintf( pBuf, "TST R%d, R%d", rd, rs ); + break; + case 0x9: /* NEG Rd, Rs */ + rs = ( opcode & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT; + rd = ( opcode & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT; + pBuf += sprintf( pBuf, "NEG R%d, R%d", rd, rs ); + break; + case 0xa: /* CMP Rd, Rs */ + rs = ( opcode & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT; + rd = ( opcode & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT; + pBuf += sprintf( pBuf, "CMP R%d, R%d", rd, rs ); + break; + case 0xb: /* CMN Rd, Rs - check flags, add dasm */ + rs = ( opcode & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT; + rd = ( opcode & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT; + pBuf += sprintf( pBuf, "CMN R%d, R%d", rd, rs ); + break; + case 0xc: /* ORR Rd, Rs */ + rs = ( opcode & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT; + rd = ( opcode & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT; + pBuf += sprintf( pBuf, "ORR R%d, R%d", rd, rs ); + break; + case 0xd: /* MUL Rd, Rs */ + rs = ( opcode & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT; + rd = ( opcode & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT; + pBuf += sprintf( pBuf, "MUL R%d, R%d", rd, rs ); + break; + case 0xe: /* MUL Rd, Rs */ + rs = ( opcode & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT; + rd = ( opcode & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT; + pBuf += sprintf( pBuf, "BIC R%d, R%d", rd, rs ); + break; + case 0xf: /* MVN Rd, Rs */ + rs = ( opcode & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT; + rd = ( opcode & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT; + pBuf += sprintf( pBuf, "MVN R%d, R%d", rd, rs ); + break; + default: + sprintf( pBuf, "INVALID %04x", opcode); + break; + } + break; + case 0x1: + switch( ( opcode & THUMB_HIREG_OP ) >> THUMB_HIREG_OP_SHIFT ) + { + case 0x0: /* ADD Rd, Rs */ + rs = ( opcode & THUMB_HIREG_RS ) >> THUMB_HIREG_RS_SHIFT; + rd = opcode & THUMB_HIREG_RD; + switch( ( opcode & THUMB_HIREG_H ) >> THUMB_HIREG_H_SHIFT ) + { + case 0x1: /* ADD Rd, HRs */ + pBuf += sprintf( pBuf, "ADD R%d, R%d", rd, rs + 8 ); + break; + case 0x2: /* ADD HRd, Rs */ + pBuf += sprintf( pBuf, "ADD R%d, R%d", rd + 8, rs ); + break; + case 0x3: /* ADD HRd, HRs */ + pBuf += sprintf( pBuf, "ADD R%d, R%d", rd + 8, rs + 8 ); + break; + default: + sprintf( pBuf, "INVALID %04x", opcode); + break; + } + break; + case 0x1: /* CMP */ + switch( ( opcode & THUMB_HIREG_H ) >> THUMB_HIREG_H_SHIFT ) + { + case 0x0: /* CMP Rd, Rs */ + rs = ( opcode & THUMB_HIREG_RS ) >> THUMB_HIREG_RS_SHIFT; + rd = opcode & THUMB_HIREG_RD; + pBuf += sprintf( pBuf, "CMP R%d, R%d", rd, rs ); + break; + case 0x1: /* CMP Rd, HRs */ + rs = ( opcode & THUMB_HIREG_RS ) >> THUMB_HIREG_RS_SHIFT; + rd = opcode & THUMB_HIREG_RD; + pBuf += sprintf( pBuf, "CMP R%d, R%d", rd, rs + 8 ); + break; + case 0x2: /* CMP Hd, Rs */ + rs = ( opcode & THUMB_HIREG_RS ) >> THUMB_HIREG_RS_SHIFT; + rd = opcode & THUMB_HIREG_RD; + pBuf += sprintf( pBuf, "CMP R%d, R%d", rd + 8, rs ); + break; + case 0x3: /* CMP Hd, Hs */ + rs = ( opcode & THUMB_HIREG_RS ) >> THUMB_HIREG_RS_SHIFT; + rd = opcode & THUMB_HIREG_RD; + pBuf += sprintf( pBuf, "CMP R%d, R%d", rd + 8, rs + 8 ); + break; + default: + sprintf( pBuf, "INVALID %04x", opcode); + break; + } + break; + case 0x2: /* MOV */ + switch( ( opcode & THUMB_HIREG_H ) >> THUMB_HIREG_H_SHIFT ) + { + case 0x0: + rs = ( opcode & THUMB_HIREG_RS ) >> THUMB_HIREG_RS_SHIFT; + rd = opcode & THUMB_HIREG_RD; + pBuf += sprintf( pBuf, "MOV R%d, R%d", rd, rs ); + break; + case 0x1: + rs = ( opcode & THUMB_HIREG_RS ) >> THUMB_HIREG_RS_SHIFT; + rd = opcode & THUMB_HIREG_RD; + pBuf += sprintf( pBuf, "MOV R%d, R%d", rd, rs + 8 ); + break; + case 0x2: + rs = ( opcode & THUMB_HIREG_RS ) >> THUMB_HIREG_RS_SHIFT; + rd = opcode & THUMB_HIREG_RD; + pBuf += sprintf( pBuf, "MOV R%d, R%d", rd + 8, rs ); + break; + case 0x3: + rs = ( opcode & THUMB_HIREG_RS ) >> THUMB_HIREG_RS_SHIFT; + rd = opcode & THUMB_HIREG_RD; + pBuf += sprintf( pBuf, "MOV R%d, R%d", rd + 8, rs + 8 ); + break; + default: + sprintf( pBuf, "INVALID %04x", opcode); + break; + } + break; + case 0x3: + switch( ( opcode & THUMB_HIREG_H ) >> THUMB_HIREG_H_SHIFT ) + { + case 0x0: + rd = ( opcode & THUMB_HIREG_RS ) >> THUMB_HIREG_RS_SHIFT; + pBuf += sprintf( pBuf, "BX R%d", rd ); + break; + case 0x1: + rd = ( ( opcode & THUMB_HIREG_RS ) >> THUMB_HIREG_RS_SHIFT ) + 8; + pBuf += sprintf( pBuf, "BX R%d", rd ); + if (rd == 14) + dasmflags = DASMFLAG_STEP_OUT; + break; + case 0x2: + rd = ( opcode & THUMB_HIREG_RS ) >> THUMB_HIREG_RS_SHIFT; + pBuf += sprintf( pBuf, "BLX R%d", rd ); + break; + default: + sprintf( pBuf, "INVALID %04x", opcode); + break; + } + break; + default: + sprintf( pBuf, "INVALID %04x", opcode); + break; + } + break; + case 0x2: + case 0x3: + rd = ( opcode & THUMB_INSN_IMM_RD ) >> THUMB_INSN_IMM_RD_SHIFT; + addr = ( opcode & THUMB_INSN_IMM ) << 2; + pBuf += sprintf( pBuf, "LDR R%d, [PC, #%03x]", rd, addr ); + break; + default: + sprintf( pBuf, "INVALID %04x", opcode); + break; + } + break; + case 0x5: /* LDR* STR* */ + switch( ( opcode & THUMB_GROUP5_TYPE ) >> THUMB_GROUP5_TYPE_SHIFT ) + { + case 0x0: /* STR Rd, [Rn, Rm] */ + rm = ( opcode & THUMB_GROUP5_RM ) >> THUMB_GROUP5_RM_SHIFT; + rn = ( opcode & THUMB_GROUP5_RN ) >> THUMB_GROUP5_RN_SHIFT; + rd = ( opcode & THUMB_GROUP5_RD ) >> THUMB_GROUP5_RD_SHIFT; + pBuf += sprintf( pBuf, "STR R%d, [R%d, R%d]", rd, rn, rm ); + break; + case 0x1: /* STRH Rd, [Rn, Rm] */ + rm = ( opcode & THUMB_GROUP5_RM ) >> THUMB_GROUP5_RM_SHIFT; + rn = ( opcode & THUMB_GROUP5_RN ) >> THUMB_GROUP5_RN_SHIFT; + rd = ( opcode & THUMB_GROUP5_RD ) >> THUMB_GROUP5_RD_SHIFT; + pBuf += sprintf( pBuf, "STRH R%d, [R%d, R%d]", rd, rn, rm ); + break; + case 0x2: /* STRB Rd, [Rn, Rm] */ /* check */ + rm = ( opcode & THUMB_GROUP5_RM ) >> THUMB_GROUP5_RM_SHIFT; + rn = ( opcode & THUMB_GROUP5_RN ) >> THUMB_GROUP5_RN_SHIFT; + rd = ( opcode & THUMB_GROUP5_RD ) >> THUMB_GROUP5_RD_SHIFT; + pBuf += sprintf( pBuf, "STRB R%d, [R%d, R%d]", rd, rn, rm ); + break; + case 0x3: /* LDRSB Rd, [Rn, Rm] */ + rm = ( opcode & THUMB_GROUP5_RM ) >> THUMB_GROUP5_RM_SHIFT; + rn = ( opcode & THUMB_GROUP5_RN ) >> THUMB_GROUP5_RN_SHIFT; + rd = ( opcode & THUMB_GROUP5_RD ) >> THUMB_GROUP5_RD_SHIFT; + pBuf += sprintf( pBuf, "LDRSB R%d, [R%d, R%d]", rd, rn, rm ); + break; + case 0x4: /* LDR Rd, [Rn, Rm] */ /* check */ + rm = ( opcode & THUMB_GROUP5_RM ) >> THUMB_GROUP5_RM_SHIFT; + rn = ( opcode & THUMB_GROUP5_RN ) >> THUMB_GROUP5_RN_SHIFT; + rd = ( opcode & THUMB_GROUP5_RD ) >> THUMB_GROUP5_RD_SHIFT; + pBuf += sprintf( pBuf, "LDR R%d, [R%d, R%d]", rd, rn, rm ); + break; + case 0x5: /* LDRH Rd, [Rn, Rm] */ + rm = ( opcode & THUMB_GROUP5_RM ) >> THUMB_GROUP5_RM_SHIFT; + rn = ( opcode & THUMB_GROUP5_RN ) >> THUMB_GROUP5_RN_SHIFT; + rd = ( opcode & THUMB_GROUP5_RD ) >> THUMB_GROUP5_RD_SHIFT; + pBuf += sprintf( pBuf, "LDRH R%d, [R%d, R%d]", rd, rn, rm ); + break; + + case 0x6: /* LDRB Rd, [Rn, Rm] */ + rm = ( opcode & THUMB_GROUP5_RM ) >> THUMB_GROUP5_RM_SHIFT; + rn = ( opcode & THUMB_GROUP5_RN ) >> THUMB_GROUP5_RN_SHIFT; + rd = ( opcode & THUMB_GROUP5_RD ) >> THUMB_GROUP5_RD_SHIFT; + pBuf += sprintf( pBuf, "LDRB R%d, [R%d, R%d]", rd, rn, rm ); + break; + case 0x7: /* LDSH Rd, [Rn, Rm] */ + rm = ( opcode & THUMB_GROUP5_RM ) >> THUMB_GROUP5_RM_SHIFT; + rn = ( opcode & THUMB_GROUP5_RN ) >> THUMB_GROUP5_RN_SHIFT; + rd = ( opcode & THUMB_GROUP5_RD ) >> THUMB_GROUP5_RD_SHIFT; + pBuf += sprintf( pBuf, "LDSH R%d, [R%d, R%d]", rd, rn, rm ); + break; + default: + sprintf( pBuf, "INVALID %04x", opcode); + break; + } + break; + case 0x6: /* Word Store w/ Immediate Offset */ + if( opcode & THUMB_LSOP_L ) /* Load */ + { + rn = ( opcode & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT; + rd = opcode & THUMB_ADDSUB_RD; + offs = ( ( opcode & THUMB_LSOP_OFFS ) >> THUMB_LSOP_OFFS_SHIFT ) << 2; + pBuf += sprintf( pBuf, "LDR R%d [R%d + #%02x]", rd, rn, offs ); + } + else /* Store */ + { + rn = ( opcode & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT; + rd = opcode & THUMB_ADDSUB_RD; + offs = ( ( opcode & THUMB_LSOP_OFFS ) >> THUMB_LSOP_OFFS_SHIFT ) << 2; + pBuf += sprintf( pBuf, "STR R%d, [R%d + #%02x] ", rd, rn, offs ); + } + break; + case 0x7: /* Byte Store w/ Immeidate Offset */ + if( opcode & THUMB_LSOP_L ) /* Load */ + { + rn = ( opcode & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT; + rd = opcode & THUMB_ADDSUB_RD; + offs = ( opcode & THUMB_LSOP_OFFS ) >> THUMB_LSOP_OFFS_SHIFT; + pBuf += sprintf( pBuf, "LDRB R%d, [R%d + #%02x]", rd, rn, offs ); + } + else /* Store */ + { + rn = ( opcode & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT; + rd = opcode & THUMB_ADDSUB_RD; + offs = ( opcode & THUMB_LSOP_OFFS ) >> THUMB_LSOP_OFFS_SHIFT; + pBuf += sprintf( pBuf, "STRB R%d, [R%d + #%02x] ", rd, rn, offs ); + } + break; + case 0x8: /* Load/Store Halfword */ + if( opcode & THUMB_HALFOP_L ) /* Load */ + { + imm = ( opcode & THUMB_HALFOP_OFFS ) >> THUMB_HALFOP_OFFS_SHIFT; + rs = ( opcode & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT; + rd = ( opcode & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT; + pBuf += sprintf( pBuf, "LDRH R%d, [R%d, #%03x]", rd, rs, imm << 1 ); + } + else /* Store */ + { + imm = ( opcode & THUMB_HALFOP_OFFS ) >> THUMB_HALFOP_OFFS_SHIFT; + rs = ( opcode & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT; + rd = ( opcode & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT; + pBuf += sprintf( pBuf, "STRH R%d, [R%d, #%03x]", rd, rs, imm << 1 ); + } + break; + case 0x9: /* Stack-Relative Load/Store */ + if( opcode & THUMB_STACKOP_L ) + { + rd = ( opcode & THUMB_STACKOP_RD ) >> THUMB_STACKOP_RD_SHIFT; + offs = (UINT8)( opcode & THUMB_INSN_IMM ); + pBuf += sprintf( pBuf, "LDR R%d, [SP, #%03x]", rd, offs << 2 ); + } + else + { + rd = ( opcode & THUMB_STACKOP_RD ) >> THUMB_STACKOP_RD_SHIFT; + offs = (UINT8)( opcode & THUMB_INSN_IMM ); + pBuf += sprintf( pBuf, "STR R%d, [SP, #%03x]", rd, offs << 2 ); + } + break; + case 0xa: /* Get relative address */ + if( opcode & THUMB_RELADDR_SP ) /* ADD Rd, SP, #nn */ + { + rd = ( opcode & THUMB_RELADDR_RD ) >> THUMB_RELADDR_RD_SHIFT; + offs = (UINT8)( opcode & THUMB_INSN_IMM ) << 2; + pBuf += sprintf( pBuf, "ADD R%d, SP, #%03x", rd, offs ); + } + else /* ADD Rd, PC, #nn */ + { + rd = ( opcode & THUMB_RELADDR_RD ) >> THUMB_RELADDR_RD_SHIFT; + offs = (UINT8)( opcode & THUMB_INSN_IMM ) << 2; + pBuf += sprintf( pBuf, "ADD R%d, PC, #%03x", rd, offs ); + } + break; + case 0xb: /* Stack-Related Opcodes */ + switch( ( opcode & THUMB_STACKOP_TYPE ) >> THUMB_STACKOP_TYPE_SHIFT ) + { + case 0x0: /* ADD SP, #imm */ + addr = ( opcode & THUMB_INSN_IMM ); + addr &= ~THUMB_INSN_IMM_S; + pBuf += sprintf( pBuf, "ADD SP, #"); + if( opcode & THUMB_INSN_IMM_S ) + { + pBuf += sprintf( pBuf, "-"); + } + pBuf += sprintf( pBuf, "%03x", addr << 2); + break; + case 0x5: /* PUSH {Rlist}{LR} */ + pBuf += sprintf( pBuf, "PUSH {LR, "); + for( offs = 7; offs >= 0; offs-- ) + { + if( opcode & ( 1 << offs ) ) + { + pBuf += sprintf( pBuf, "R%d, ", offs); + } + } + pBuf += sprintf( pBuf, "}"); + break; + case 0x4: /* PUSH {Rlist} */ + pBuf += sprintf( pBuf, "PUSH {"); + for( offs = 7; offs >= 0; offs-- ) + { + if( opcode & ( 1 << offs ) ) + { + pBuf += sprintf( pBuf, "R%d, ", offs); + } + } + pBuf += sprintf( pBuf, "}"); + break; + case 0xc: /* POP {Rlist} */ + pBuf += sprintf( pBuf, "POP {"); + for( offs = 0; offs < 8; offs++ ) + { + if( opcode & ( 1 << offs ) ) + { + pBuf += sprintf( pBuf, "R%d, ", offs); + } + } + pBuf += sprintf( pBuf, "}"); + break; + case 0xd: /* POP {Rlist}{PC} */ + pBuf += sprintf( pBuf, "POP {"); + for( offs = 0; offs < 8; offs++ ) + { + if( opcode & ( 1 << offs ) ) + { + pBuf += sprintf( pBuf, "R%d, ", offs); + } + } + pBuf += sprintf( pBuf, "PC}"); + break; + default: + sprintf( pBuf, "INVALID %04x", opcode); + break; + } + break; + case 0xc: /* Multiple Load/Store */ + if( opcode & THUMB_MULTLS ) /* Load */ + { + rd = ( opcode & THUMB_MULTLS_BASE ) >> THUMB_MULTLS_BASE_SHIFT; + pBuf += sprintf( pBuf, "LDMIA R%d!,{", rd); + for( offs = 0; offs < 8; offs++ ) + { + if( opcode & ( 1 << offs ) ) + { + pBuf += sprintf( pBuf, "R%d, ", offs); + } + } + pBuf += sprintf( pBuf, "}"); + } + else /* Store */ + { + rd = ( opcode & THUMB_MULTLS_BASE ) >> THUMB_MULTLS_BASE_SHIFT; + pBuf += sprintf( pBuf, "STMIA R%d!,{", rd); + for( offs = 7; offs >= 0; offs-- ) + { + if( opcode & ( 1 << offs ) ) + { + pBuf += sprintf( pBuf, "R%d, ", offs); + } + } + pBuf += sprintf( pBuf, "}"); + } + break; + case 0xd: /* Conditional Branch */ + offs = (INT8)( opcode & THUMB_INSN_IMM ); + switch( ( opcode & THUMB_COND_TYPE ) >> THUMB_COND_TYPE_SHIFT ) + { + case COND_EQ: + pBuf += sprintf( pBuf, "BEQ %08x (%02x)", pc + 4 + (offs << 1), offs << 1); + break; + case COND_NE: + pBuf += sprintf( pBuf, "BNE %08x (%02x)", pc + 4 + (offs << 1), offs << 1); + break; + case COND_CS: + pBuf += sprintf( pBuf, "BCS %08x (%02x)", pc + 4 + (offs << 1), offs << 1); + break; + case COND_CC: + pBuf += sprintf( pBuf, "BCC %08x (%02x)", pc + 4 + (offs << 1), offs << 1); + break; + case COND_MI: + pBuf += sprintf( pBuf, "BMI %08x (%02x)", pc + 4 + (offs << 1), offs << 1); + break; + case COND_PL: + pBuf += sprintf( pBuf, "BPL %08x (%02x)", pc + 4 + (offs << 1), offs << 1); + break; + case COND_VS: + pBuf += sprintf( pBuf, "BVS %08x (%02x)", pc + 4 + (offs << 1), offs << 1); + break; + case COND_VC: + pBuf += sprintf( pBuf, "BVC %08x (%02x)", pc + 4 + (offs << 1), offs << 1); + break; + case COND_HI: + pBuf += sprintf( pBuf, "BHI %08x (%02x)", pc + 4 + (offs << 1), offs << 1); + break; + case COND_LS: + pBuf += sprintf( pBuf, "BLS %08x (%02x)", pc + 4 + (offs << 1), offs << 1); + break; + case COND_GE: + pBuf += sprintf( pBuf, "BGE %08x (%02x)", pc + 4 + (offs << 1), offs << 1); + break; + case COND_LT: + pBuf += sprintf( pBuf, "BLT %08x (%02x)", pc + 4 + (offs << 1), offs << 1); + break; + case COND_GT: + pBuf += sprintf( pBuf, "BGT %08x (%02x)", pc + 4 + (offs << 1), offs << 1); + break; + case COND_LE: + pBuf += sprintf( pBuf, "BLE %08x (%02x)", pc + 4 + (offs << 1), offs << 1); + break; + case COND_AL: + pBuf += sprintf( pBuf, "INVALID"); + break; + case COND_NV: + pBuf += sprintf( pBuf, "SWI %02x\n", opcode & 0xff); + break; + } + break; + case 0xe: /* B #offs */ + if( opcode & THUMB_BLOP_LO ) + { + addr = ( ( opcode & THUMB_BLOP_OFFS ) << 1 ) & 0xfffc; + pBuf += sprintf( pBuf, "BLX (LO) %08x", addr ); + dasmflags = DASMFLAG_STEP_OVER; + } + else + { + offs = ( opcode & THUMB_BRANCH_OFFS ) << 1; + if( offs & 0x00000800 ) + { + offs |= 0xfffff800; + } + pBuf += sprintf( pBuf, "B #%08x (%08x)", offs, pc + 4 + offs); + } + break; + case 0xf: /* BL */ + if( opcode & THUMB_BLOP_LO ) + { + pBuf += sprintf( pBuf, "BL (LO) %08x", ( opcode & THUMB_BLOP_OFFS ) << 1 ); + dasmflags = DASMFLAG_STEP_OVER; + } + else + { + addr = ( opcode & THUMB_BLOP_OFFS ) << 12; + if( addr & ( 1 << 22 ) ) + { + addr |= 0xff800000; + } + pBuf += sprintf( pBuf, "BL (HI) %08x", addr ); + dasmflags = DASMFLAG_STEP_OVER; + } + break; + default: + sprintf( pBuf, "INVALID %04x", opcode); + break; + } + + return dasmflags | DASMFLAG_SUPPORTED; +} + +CPU_DISASSEMBLE( arm7arm ) +{ + return arm7_disasm(buffer, pc, oprom[0] | (oprom[1] << 8) | (oprom[2] << 16) | (oprom[3] << 24)) | 4; +} + +CPU_DISASSEMBLE( arm7arm_be ) +{ + return arm7_disasm(buffer, pc, oprom[3] | (oprom[2] << 8) | (oprom[1] << 16) | (oprom[0] << 24)) | 4; +} + +CPU_DISASSEMBLE( arm7thumb ) +{ + return thumb_disasm(buffer, pc, oprom[0] | (oprom[1] << 8)) | 2; +} + +CPU_DISASSEMBLE( arm7thumb_be ) +{ + return thumb_disasm(buffer, pc, oprom[1] | (oprom[0] << 8)) | 2; +} diff --git a/src/devices/cpu/arm7/arm7drc.inc b/src/devices/cpu/arm7/arm7drc.inc new file mode 100644 index 00000000000..d31eee5a632 --- /dev/null +++ b/src/devices/cpu/arm7/arm7drc.inc @@ -0,0 +1,1834 @@ +// license:BSD-3-Clause +// copyright-holders:Steve Ellenoff,R. Belmont,Ryan Holtz +/***************************************************************************** + * + * arm7drc.inc + * Portable CPU Emulator for 32-bit ARM v3/4/5/6 + * + * Copyright Steve Ellenoff, all rights reserved. + * Thumb, DSP, and MMU support and many bugfixes by R. Belmont and Ryan Holtz. + * Dyanmic Recompiler (DRC) / Just In Time Compiler (JIT) by Ryan Holtz. + * + * This work is based on: + * #1) 'Atmel Corporation ARM7TDMI (Thumb) Datasheet - January 1999' + * #2) Arm 2/3/6 emulator By Bryan McPhail (bmcphail@tendril.co.uk) and Phil Stroffolino (MAME CORE 0.76) + * + *****************************************************************************/ + +/****************************************************************************** + * Notes: + + ** This is a plain vanilla implementation of an ARM7 cpu which incorporates my ARM7 core. + It can be used as is, or used to demonstrate how to utilize the arm7 core to create a cpu + that uses the core, since there are numerous different mcu packages that incorporate an arm7 core. + + See the notes in the arm7core.c file itself regarding issues/limitations of the arm7 core. + ** +*****************************************************************************/ + + +/*************************************************************************** + DEBUGGING +***************************************************************************/ + +#define SINGLE_INSTRUCTION_MODE (0) + +/*************************************************************************** + CONSTANTS +***************************************************************************/ + +#include "arm7tdrc.inc" + +/* map variables */ +#define MAPVAR_PC uml::M0 +#define MAPVAR_CYCLES uml::M1 + +/* size of the execution code cache */ +#define CACHE_SIZE (32 * 1024 * 1024) + +/* compilation boundaries -- how far back/forward does the analysis extend? */ +#define COMPILE_BACKWARDS_BYTES 128 +#define COMPILE_FORWARDS_BYTES 512 +#define COMPILE_MAX_INSTRUCTIONS ((COMPILE_BACKWARDS_BYTES/4) + (COMPILE_FORWARDS_BYTES/4)) +#define COMPILE_MAX_SEQUENCE 64 + +/* exit codes */ +#define EXECUTE_OUT_OF_CYCLES 0 +#define EXECUTE_MISSING_CODE 1 +#define EXECUTE_UNMAPPED_CODE 2 +#define EXECUTE_RESET_CACHE 3 + + +/*************************************************************************** + INLINE FUNCTIONS +***************************************************************************/ + +/*------------------------------------------------- + epc - compute the exception PC from a + descriptor +-------------------------------------------------*/ + +INLINE UINT32 epc(const opcode_desc *desc) +{ + return desc->pc; +} + + +/*------------------------------------------------- + alloc_handle - allocate a handle if not + already allocated +-------------------------------------------------*/ + +INLINE void alloc_handle(drcuml_state *drcuml, uml::code_handle **handleptr, const char *name) +{ + if (*handleptr == NULL) + *handleptr = drcuml->handle_alloc(name); +} + + +/*------------------------------------------------- + load_fast_iregs - load any fast integer + registers +-------------------------------------------------*/ + +void arm7_cpu_device::load_fast_iregs(drcuml_block *block) +{ + int regnum; + + for (regnum = 0; regnum < ARRAY_LENGTH(m_impstate.regmap); regnum++) + if (m_impstate.regmap[regnum].is_int_register()) + UML_DMOV(block, uml::ireg(m_impstate.regmap[regnum].ireg() - uml::REG_I0), uml::mem(&m_r[regnum])); +} + + +/*------------------------------------------------- + save_fast_iregs - save any fast integer + registers +-------------------------------------------------*/ + +void arm7_cpu_device::save_fast_iregs(drcuml_block *block) +{ + int regnum; + + for (regnum = 0; regnum < ARRAY_LENGTH(m_impstate.regmap); regnum++) + if (m_impstate.regmap[regnum].is_int_register()) + UML_DMOV(block, uml::mem(&m_r[regnum]), uml::ireg(m_impstate.regmap[regnum].ireg() - uml::REG_I0)); +} + + + +/*************************************************************************** + CORE CALLBACKS +***************************************************************************/ + +/*------------------------------------------------- + arm7_init - initialize the processor +-------------------------------------------------*/ + +void arm7_cpu_device::arm7_drc_init() +{ + drc_cache *cache; + drcbe_info beinfo; + UINT32 flags = 0; + + /* allocate enough space for the cache and the core */ + cache = auto_alloc(machine(), drc_cache(CACHE_SIZE)); + if (cache == NULL) + fatalerror("Unable to allocate cache of size %d\n", (UINT32)(CACHE_SIZE)); + + /* allocate the implementation-specific state from the full cache */ + memset(&m_impstate, 0, sizeof(m_impstate)); + m_impstate.cache = cache; + + /* initialize the UML generator */ + m_impstate.drcuml = new drcuml_state(*this, *cache, flags, 1, 32, 1); + + /* add symbols for our stuff */ + m_impstate.drcuml->symbol_add(&m_icount, sizeof(m_icount), "icount"); + for (int regnum = 0; regnum < 37; regnum++) + { + char buf[10]; + sprintf(buf, "r%d", regnum); + m_impstate.drcuml->symbol_add(&m_r[regnum], sizeof(m_r[regnum]), buf); + } + m_impstate.drcuml->symbol_add(&m_impstate.mode, sizeof(m_impstate.mode), "mode"); + m_impstate.drcuml->symbol_add(&m_impstate.arg0, sizeof(m_impstate.arg0), "arg0"); + m_impstate.drcuml->symbol_add(&m_impstate.arg1, sizeof(m_impstate.arg1), "arg1"); + m_impstate.drcuml->symbol_add(&m_impstate.numcycles, sizeof(m_impstate.numcycles), "numcycles"); + //m_impstate.drcuml->symbol_add(&m_impstate.fpmode, sizeof(m_impstate.fpmode), "fpmode"); // TODO + + /* initialize the front-end helper */ + //m_impstate.drcfe = auto_alloc(machine(), arm7_frontend(this, COMPILE_BACKWARDS_BYTES, COMPILE_FORWARDS_BYTES, SINGLE_INSTRUCTION_MODE ? 1 : COMPILE_MAX_SEQUENCE)); + + /* allocate memory for cache-local state and initialize it */ + //memcpy(&m_impstate.fpmode, fpmode_source, sizeof(fpmode_source)); // TODO + + /* compute the register parameters */ + for (int regnum = 0; regnum < 37; regnum++) + { + m_impstate.regmap[regnum] = (regnum == 0) ? uml::parameter(0) : uml::parameter::make_memory(&m_r[regnum]); + } + + /* if we have registers to spare, assign r2, r3, r4 to leftovers */ + //if (!DISABLE_FAST_REGISTERS) // TODO + { + m_impstate.drcuml->get_backend_info(beinfo); + if (beinfo.direct_iregs > 4) + { // PC + m_impstate.regmap[eR15] = uml::I4; + } + if (beinfo.direct_iregs > 5) + { // Status + m_impstate.regmap[eCPSR] = uml::I5; + } + if (beinfo.direct_iregs > 6) + { // SP + m_impstate.regmap[eR13] = uml::I6; + } + } + + /* mark the cache dirty so it is updated on next execute */ + m_impstate.cache_dirty = TRUE; +} + + +/*------------------------------------------------- + arm7_execute - execute the CPU for the + specified number of cycles +-------------------------------------------------*/ + +void arm7_cpu_device::execute_run_drc() +{ + drcuml_state *drcuml = m_impstate.drcuml; + int execute_result; + + /* reset the cache if dirty */ + if (m_impstate.cache_dirty) + code_flush_cache(); + m_impstate.cache_dirty = FALSE; + + /* execute */ + do + { + /* run as much as we can */ + execute_result = drcuml->execute(*m_impstate.entry); + + /* if we need to recompile, do it */ + if (execute_result == EXECUTE_MISSING_CODE) + code_compile_block(m_impstate.mode, m_r[eR15]); + else if (execute_result == EXECUTE_UNMAPPED_CODE) + fatalerror("Attempted to execute unmapped code at PC=%08X\n", m_r[eR15]); + else if (execute_result == EXECUTE_RESET_CACHE) + code_flush_cache(); + + } while (execute_result != EXECUTE_OUT_OF_CYCLES); +} + +/*------------------------------------------------- + arm7_exit - cleanup from execution +-------------------------------------------------*/ + +void arm7_cpu_device::arm7_drc_exit() +{ + /* clean up the DRC */ + //auto_free(machine(), m_impstate.drcfe); + delete m_impstate.drcuml; + auto_free(machine(), m_impstate.cache); +} + + +/*------------------------------------------------- + arm7drc_set_options - configure DRC options +-------------------------------------------------*/ + +void arm7_cpu_device::arm7drc_set_options(UINT32 options) +{ + m_impstate.drcoptions = options; +} + + +/*------------------------------------------------- + arm7drc_add_fastram - add a new fastram + region +-------------------------------------------------*/ + +void arm7_cpu_device::arm7drc_add_fastram(offs_t start, offs_t end, UINT8 readonly, void *base) +{ + if (m_impstate.fastram_select < ARRAY_LENGTH(m_impstate.fastram)) + { + m_impstate.fastram[m_impstate.fastram_select].start = start; + m_impstate.fastram[m_impstate.fastram_select].end = end; + m_impstate.fastram[m_impstate.fastram_select].readonly = readonly; + m_impstate.fastram[m_impstate.fastram_select].base = base; + m_impstate.fastram_select++; + } +} + + +/*------------------------------------------------- + arm7drc_add_hotspot - add a new hotspot +-------------------------------------------------*/ + +void arm7_cpu_device::arm7drc_add_hotspot(offs_t pc, UINT32 opcode, UINT32 cycles) +{ + if (m_impstate.hotspot_select < ARRAY_LENGTH(m_impstate.hotspot)) + { + m_impstate.hotspot[m_impstate.hotspot_select].pc = pc; + m_impstate.hotspot[m_impstate.hotspot_select].opcode = opcode; + m_impstate.hotspot[m_impstate.hotspot_select].cycles = cycles; + m_impstate.hotspot_select++; + } +} + + + +/*************************************************************************** + CACHE MANAGEMENT +***************************************************************************/ + +/*------------------------------------------------- + code_flush_cache - flush the cache and + regenerate static code +-------------------------------------------------*/ + +void arm7_cpu_device::code_flush_cache() +{ + /* empty the transient cache contents */ + m_impstate.drcuml->reset(); + + try + { + /* generate the entry point and out-of-cycles handlers */ + static_generate_entry_point(); + static_generate_nocode_handler(); + static_generate_out_of_cycles(); + static_generate_tlb_translate(NULL); // TODO FIXME + static_generate_detect_fault(NULL); // TODO FIXME + //static_generate_tlb_mismatch(); + + /* add subroutines for memory accesses */ + static_generate_memory_accessor(1, FALSE, FALSE, "read8", &m_impstate.read8); + static_generate_memory_accessor(1, TRUE, FALSE, "write8", &m_impstate.write8); + static_generate_memory_accessor(2, FALSE, FALSE, "read16", &m_impstate.read16); + static_generate_memory_accessor(2, TRUE, FALSE, "write16", &m_impstate.write16); + static_generate_memory_accessor(4, FALSE, FALSE, "read32", &m_impstate.read32); + static_generate_memory_accessor(4, TRUE, FALSE, "write32", &m_impstate.write32); + } + catch (drcuml_block::abort_compilation &) + { + fatalerror("Unrecoverable error generating static code\n"); + } +} + + +/*------------------------------------------------- + code_compile_block - compile a block of the + given mode at the specified pc +-------------------------------------------------*/ + +void arm7_cpu_device::code_compile_block(UINT8 mode, offs_t pc) +{ + drcuml_state *drcuml = m_impstate.drcuml; + compiler_state compiler = { 0 }; + const opcode_desc *seqlast; + int override = FALSE; + + g_profiler.start(PROFILER_DRC_COMPILE); + + /* get a description of this sequence */ + // TODO FIXME + const opcode_desc *desclist = NULL; //m_impstate.drcfe->describe_code(pc); // TODO +// if (drcuml->logging() || drcuml->logging_native()) +// log_opcode_desc(drcuml, desclist, 0); + + /* if we get an error back, flush the cache and try again */ + bool succeeded = false; + while (!succeeded) + { + try + { + /* start the block */ + drcuml_block *block = drcuml->begin_block(4096); + + /* loop until we get through all instruction sequences */ + for (const opcode_desc *seqhead = desclist; seqhead != NULL; seqhead = seqlast->next()) + { + const opcode_desc *curdesc; + UINT32 nextpc; + + /* add a code log entry */ + if (drcuml->logging()) + block->append_comment("-------------------------"); // comment + + /* determine the last instruction in this sequence */ + for (seqlast = seqhead; seqlast != NULL; seqlast = seqlast->next()) + if (seqlast->flags & OPFLAG_END_SEQUENCE) + break; + assert(seqlast != NULL); + + /* if we don't have a hash for this mode/pc, or if we are overriding all, add one */ + if (override || !drcuml->hash_exists(mode, seqhead->pc)) + UML_HASH(block, mode, seqhead->pc); // hash mode,pc + + /* if we already have a hash, and this is the first sequence, assume that we */ + /* are recompiling due to being out of sync and allow future overrides */ + else if (seqhead == desclist) + { + override = TRUE; + UML_HASH(block, mode, seqhead->pc); // hash mode,pc + } + + /* otherwise, redispatch to that fixed PC and skip the rest of the processing */ + else + { + UML_LABEL(block, seqhead->pc | 0x80000000); // label seqhead->pc | 0x80000000 + UML_HASHJMP(block, 0, seqhead->pc, *m_impstate.nocode); + // hashjmp ,seqhead->pc,nocode + continue; + } + + /* validate this code block if we're not pointing into ROM */ + if (m_program->get_write_ptr(seqhead->physpc) != NULL) + generate_checksum_block(block, &compiler, seqhead, seqlast); + + /* label this instruction, if it may be jumped to locally */ + if (seqhead->flags & OPFLAG_IS_BRANCH_TARGET) + UML_LABEL(block, seqhead->pc | 0x80000000); // label seqhead->pc | 0x80000000 + + /* iterate over instructions in the sequence and compile them */ + for (curdesc = seqhead; curdesc != seqlast->next(); curdesc = curdesc->next()) + generate_sequence_instruction(block, &compiler, curdesc); + + /* if we need to return to the start, do it */ + if (seqlast->flags & OPFLAG_RETURN_TO_START) + nextpc = pc; + + /* otherwise we just go to the next instruction */ + else + nextpc = seqlast->pc + (seqlast->skipslots + 1) * 4; + + /* count off cycles and go there */ + generate_update_cycles(block, &compiler, nextpc); // + + /* if the last instruction can change modes, use a variable mode; otherwise, assume the same mode */ + /*if (seqlast->flags & OPFLAG_CAN_CHANGE_MODES) + UML_HASHJMP(block, uml::mem(&m_impstate.mode), nextpc, *m_impstate.nocode); + // hashjmp ,nextpc,nocode + else*/ if (seqlast->next() == NULL || seqlast->next()->pc != nextpc) + UML_HASHJMP(block, m_impstate.mode, nextpc, *m_impstate.nocode); + // hashjmp ,nextpc,nocode + } + + /* end the sequence */ + block->end(); + g_profiler.stop(); + succeeded = true; + } + catch (drcuml_block::abort_compilation &) + { + code_flush_cache(); + } + } +} + + +/*************************************************************************** + C FUNCTION CALLBACKS +***************************************************************************/ + +/*------------------------------------------------- + cfunc_get_cycles - compute the total number + of cycles executed so far +-------------------------------------------------*/ + +void arm7_cpu_device::cfunc_get_cycles() +{ + m_impstate.numcycles = total_cycles(); +} + + +/*------------------------------------------------- + cfunc_unimplemented - handler for + unimplemented opcdes +-------------------------------------------------*/ + +void arm7_cpu_device::cfunc_unimplemented() +{ + UINT32 opcode = m_impstate.arg0; + fatalerror("PC=%08X: Unimplemented op %08X\n", m_r[eR15], opcode); +} + + +/*************************************************************************** + STATIC CODEGEN +***************************************************************************/ + +/*------------------------------------------------- + static_generate_entry_point - generate a + static entry point +-------------------------------------------------*/ + +void arm7_cpu_device::static_generate_entry_point() +{ + drcuml_state *drcuml = m_impstate.drcuml; + uml::code_label nodabt; + uml::code_label nofiq; + uml::code_label noirq; + uml::code_label irq32; + uml::code_label nopabd; + uml::code_label nound; + uml::code_label swi32; + uml::code_label irqadjust; + uml::code_label done; + drcuml_block *block; + + block = drcuml->begin_block(110); + + /* forward references */ + //alloc_handle(drcuml, &m_impstate.exception_norecover[EXCEPTION_INTERRUPT], "interrupt_norecover"); + alloc_handle(drcuml, &m_impstate.nocode, "nocode"); + alloc_handle(drcuml, &m_impstate.detect_fault, "detect_fault"); + alloc_handle(drcuml, &m_impstate.tlb_translate, "tlb_translate"); + + alloc_handle(drcuml, &m_impstate.entry, "entry"); + UML_HANDLE(block, *m_impstate.entry); // handle entry + + /* load fast integer registers */ + load_fast_iregs(block); + + UML_CALLH(block, *m_impstate.check_irq); + + /* generate a hash jump via the current mode and PC */ + UML_HASHJMP(block, 0, uml::mem(&m_pc), *m_impstate.nocode); // hashjmp 0,,nocode + block->end(); +} + + +/*------------------------------------------------- + static_generate_check_irq - generate a handler + to check IRQs +-------------------------------------------------*/ + +void arm7_cpu_device::static_generate_check_irq() +{ + drcuml_state *drcuml = m_impstate.drcuml; + drcuml_block *block; + uml::code_label noirq; + int nodabt = 0; + int nopabt = 0; + int irqadjust = 0; + int nofiq = 0; + int irq32 = 0; + int swi32 = 0; + int done = 0; + int label = 1; + + /* begin generating */ + block = drcuml->begin_block(120); + + /* generate a hash jump via the current mode and PC */ + alloc_handle(drcuml, &m_impstate.check_irq, "check_irq"); + UML_HANDLE(block, *m_impstate.check_irq); // handle check_irq + /* Exception priorities: + + Reset + Data abort + FIRQ + IRQ + Prefetch abort + Undefined instruction + Software Interrupt + */ + + UML_ADD(block, uml::I0, uml::mem(&R15), 4); // add i0, PC, 4 ;insn pc + + // Data Abort + UML_TEST(block, uml::mem(&m_pendingAbtD), 1); // test pendingAbtD, 1 + UML_JMPc(block, uml::COND_Z, nodabt = label++); // jmpz nodabt + + UML_ROLINS(block, uml::mem(&GET_CPSR), eARM7_MODE_ABT, 0, MODE_FLAG); // rolins CPSR, eARM7_MODE_ABT, 0, MODE_FLAG + UML_MOV(block, uml::mem(&GET_REGISTER(14)), uml::I0); // mov LR, i0 + UML_MOV(block, uml::mem(&GET_REGISTER(SPSR)), uml::mem(&GET_CPSR)); // mov SPSR, CPSR + UML_OR(block, uml::mem(&GET_CPSR), uml::mem(&GET_CPSR), I_MASK); // or CPSR, CPSR, I_MASK + UML_ROLAND(block, uml::mem(&GET_CPSR), uml::mem(&GET_CPSR), 0, ~T_MASK); // roland CPSR, CPSR, 0, ~T_MASK + UML_MOV(block, uml::mem(&R15), 0x00000010); // mov PC, 0x10 (Data Abort vector address) + UML_MOV(block, uml::mem(&m_pendingAbtD), 0); // mov pendingAbtD, 0 + UML_JMP(block, irqadjust = label++); // jmp irqadjust + + UML_LABEL(block, nodabt); // nodabt: + + // FIQ + UML_TEST(block, uml::mem(&m_pendingFiq), 1); // test pendingFiq, 1 + UML_JMPc(block, uml::COND_Z, nofiq = label++); // jmpz nofiq + UML_TEST(block, uml::mem(&GET_CPSR), F_MASK); // test CPSR, F_MASK + UML_JMPc(block, uml::COND_Z, nofiq); // jmpz nofiq + + UML_MOV(block, uml::mem(&GET_REGISTER(14)), uml::I0); // mov LR, i0 + UML_MOV(block, uml::mem(&GET_REGISTER(SPSR)), uml::mem(&GET_CPSR)); // mov SPSR, CPSR + UML_OR(block, uml::mem(&GET_CPSR), uml::mem(&GET_CPSR), I_MASK | F_MASK); // or CPSR, CPSR, I_MASK | F_MASK + UML_ROLAND(block, uml::mem(&GET_CPSR), uml::mem(&GET_CPSR), 0, ~T_MASK); // roland CPSR, CPSR, 0, ~T_MASK + UML_MOV(block, uml::mem(&R15), 0x0000001c); // mov PC, 0x1c (FIQ vector address) + UML_MOV(block, uml::mem(&m_pendingFiq), 0); // mov pendingFiq, 0 + UML_JMP(block, irqadjust); // jmp irqadjust + + UML_LABEL(block, nofiq); // nofiq: + + // IRQ + UML_TEST(block, uml::mem(&m_pendingIrq), 1); // test pendingIrq, 1 + UML_JMPc(block, uml::COND_Z, noirq = label++); // jmpz noirq + UML_TEST(block, uml::mem(&GET_CPSR), I_MASK); // test CPSR, I_MASK + UML_JMPc(block, uml::COND_Z, noirq); // jmpz noirq + + UML_MOV(block, uml::mem(&GET_REGISTER(14)), uml::I0); // mov LR, i0 + UML_TEST(block, uml::mem(&GET_CPSR), SR_MODE32); // test CPSR, MODE32 + UML_JMPc(block, uml::COND_NZ, irq32 = label++); // jmpnz irq32 + UML_AND(block, uml::I1, uml::I0, 0xf4000000); // and i1, i0, 0xf4000000 + UML_OR(block, uml::mem(&R15), uml::I1, 0x0800001a); // or PC, i1, 0x0800001a + UML_AND(block, uml::I1, uml::mem(&GET_CPSR), 0x0fffff3f); // and i1, CPSR, 0x0fffff3f + UML_ROLAND(block, uml::I0, uml::mem(&R15), 32-20, 0x0000000c); // roland i0, R15, 32-20, 0x0000000c + UML_ROLINS(block, uml::I0, uml::mem(&R15), 0, 0xf0000000); // rolins i0, R15, 0, 0xf0000000 + UML_OR(block, uml::mem(&GET_CPSR), uml::I0, uml::I1); // or CPSR, i0, i1 + UML_JMP(block, irqadjust); // jmp irqadjust + + UML_LABEL(block, irq32); // irq32: + UML_MOV(block, uml::mem(&GET_REGISTER(SPSR)), uml::mem(&GET_CPSR)); // mov SPSR, CPSR + UML_OR(block, uml::mem(&GET_CPSR), uml::mem(&GET_CPSR), I_MASK); // or CPSR, CPSR, I_MASK + UML_ROLAND(block, uml::mem(&GET_CPSR), uml::mem(&GET_CPSR), 0, ~T_MASK); // roland CPSR, CPSR, 0, ~T_MASK + UML_MOV(block, uml::mem(&R15), 0x00000018); // mov PC, 0x18 (IRQ vector address) + + UML_JMP(block, irqadjust); // jmp irqadjust + + UML_LABEL(block, noirq); // noirq: + + // Prefetch Abort + UML_TEST(block, uml::mem(&m_pendingAbtP), 1); // test pendingAbtP, 1 + UML_JMPc(block, uml::COND_Z, nopabt = label++); // jmpz nopabt + + UML_ROLINS(block, uml::mem(&GET_CPSR), eARM7_MODE_ABT, 0, MODE_FLAG); // rolins CPSR, eARM7_MODE_ABT, 0, MODE_FLAG + UML_MOV(block, uml::mem(&GET_REGISTER(14)), uml::I0); // mov LR, i0 + UML_MOV(block, uml::mem(&GET_REGISTER(SPSR)), uml::mem(&GET_CPSR)); // mov SPSR, CPSR + UML_OR(block, uml::mem(&GET_CPSR), uml::mem(&GET_CPSR), I_MASK); // or CPSR, CPSR, I_MASK + UML_ROLAND(block, uml::mem(&GET_CPSR), uml::mem(&GET_CPSR), 0, ~T_MASK); // roland CPSR, CPSR, 0, ~T_MASK + UML_MOV(block, uml::mem(&R15), 0x0000000c); // mov PC, 0x0c (Prefetch Abort vector address) + UML_MOV(block, uml::mem(&m_pendingAbtP), 0); // mov pendingAbtP, 0 + UML_JMP(block, irqadjust); // jmp irqadjust + + UML_LABEL(block, nopabt); // nopabt: + + // Undefined instruction + UML_TEST(block, uml::mem(&m_pendingUnd), 1); // test pendingUnd, 1 + UML_JMPc(block, uml::COND_Z, nopabt = label++); // jmpz nound + + UML_ROLINS(block, uml::mem(&GET_CPSR), eARM7_MODE_UND, 0, MODE_FLAG); // rolins CPSR, eARM7_MODE_UND, 0, MODE_FLAG + UML_MOV(block, uml::I1, (UINT64)-4); // mov i1, -4 + UML_TEST(block, uml::mem(&GET_CPSR), T_MASK); // test CPSR, T_MASK + UML_MOVc(block, uml::COND_NZ, uml::I1, (UINT64)-2); // movnz i1, -2 + UML_ADD(block, uml::mem(&GET_REGISTER(14)), uml::I0, uml::I1); // add LR, i0, i1 + UML_MOV(block, uml::mem(&GET_REGISTER(SPSR)), uml::mem(&GET_CPSR)); // mov SPSR, CPSR + UML_OR(block, uml::mem(&GET_CPSR), uml::mem(&GET_CPSR), I_MASK); // or CPSR, CPSR, I_MASK + UML_ROLAND(block, uml::mem(&GET_CPSR), uml::mem(&GET_CPSR), 0, ~T_MASK); // roland CPSR, CPSR, 0, ~T_MASK + UML_MOV(block, uml::mem(&R15), 0x00000004); // mov PC, 0x0c (Undefined Insn vector address) + UML_MOV(block, uml::mem(&m_pendingUnd), 0); // mov pendingUnd, 0 + UML_JMP(block, irqadjust); // jmp irqadjust + + UML_LABEL(block, nopabt); // nopabt: + + // Software Interrupt + UML_TEST(block, uml::mem(&m_pendingSwi), 1); // test pendingSwi, 1 + UML_JMPc(block, uml::COND_Z, done = label++); // jmpz done + + UML_ROLINS(block, uml::mem(&GET_CPSR), eARM7_MODE_SVC, 0, MODE_FLAG); // rolins CPSR, eARM7_MODE_SVC, 0, MODE_FLAG + UML_MOV(block, uml::I1, (UINT64)-4); // mov i1, -4 + UML_TEST(block, uml::mem(&GET_CPSR), T_MASK); // test CPSR, T_MASK + UML_MOVc(block, uml::COND_NZ, uml::I1, (UINT64)-2); // movnz i1, -2 + UML_ADD(block, uml::mem(&GET_REGISTER(14)), uml::I0, uml::I1); // add LR, i0, i1 + + UML_TEST(block, uml::mem(&GET_CPSR), SR_MODE32); // test CPSR, MODE32 + UML_JMPc(block, uml::COND_NZ, swi32 = label++); // jmpnz swi32 + UML_AND(block, uml::I1, uml::I0, 0xf4000000); // and i1, i0, 0xf4000000 + UML_OR(block, uml::mem(&R15), uml::I1, 0x0800001b); // or PC, i1, 0x0800001b + UML_AND(block, uml::I1, uml::mem(&GET_CPSR), 0x0fffff3f); // and i1, CPSR, 0x0fffff3f + UML_ROLAND(block, uml::I0, uml::mem(&R15), 32-20, 0x0000000c); // roland i0, R15, 32-20, 0x0000000c + UML_ROLINS(block, uml::I0, uml::mem(&R15), 0, 0xf0000000); // rolins i0, R15, 0, 0xf0000000 + UML_OR(block, uml::mem(&GET_CPSR), uml::I0, uml::I1); // or CPSR, i0, i1 + UML_MOV(block, uml::mem(&m_pendingSwi), 0); // mov pendingSwi, 0 + UML_JMP(block, irqadjust); // jmp irqadjust + + UML_LABEL(block, swi32); // irq32: + UML_MOV(block, uml::mem(&GET_REGISTER(SPSR)), uml::mem(&GET_CPSR)); // mov SPSR, CPSR + UML_OR(block, uml::mem(&GET_CPSR), uml::mem(&GET_CPSR), I_MASK); // or CPSR, CPSR, I_MASK + UML_ROLAND(block, uml::mem(&GET_CPSR), uml::mem(&GET_CPSR), 0, ~T_MASK); // roland CPSR, CPSR, 0, ~T_MASK + UML_MOV(block, uml::mem(&R15), 0x00000008); // mov PC, 0x08 (SWI vector address) + UML_MOV(block, uml::mem(&m_pendingSwi), 0); // mov pendingSwi, 0 + UML_JMP(block, irqadjust); // jmp irqadjust + + UML_LABEL(block, irqadjust); // irqadjust: + UML_MOV(block, uml::I1, 0); // mov i1, 0 + UML_TEST(block, uml::mem(&COPRO_CTRL), COPRO_CTRL_MMU_EN | COPRO_CTRL_INTVEC_ADJUST); // test COPRO_CTRL, MMU_EN | INTVEC_ADJUST + UML_MOVc(block, uml::COND_NZ, uml::I1, 0xffff0000); // movnz i1, 0xffff0000 + UML_OR(block, uml::mem(&R15), uml::mem(&R15), uml::I1); // or PC, i1 + + UML_LABEL(block, done); // done: + + block->end(); +} + +/*------------------------------------------------- + static_generate_nocode_handler - generate an + exception handler for "out of code" +-------------------------------------------------*/ + +void arm7_cpu_device::static_generate_nocode_handler() +{ + drcuml_state *drcuml = m_impstate.drcuml; + drcuml_block *block; + + /* begin generating */ + block = drcuml->begin_block(10); + + /* generate a hash jump via the current mode and PC */ + alloc_handle(drcuml, &m_impstate.nocode, "nocode"); + UML_HANDLE(block, *m_impstate.nocode); // handle nocode + UML_GETEXP(block, uml::I0); // getexp i0 + UML_MOV(block, uml::mem(&R15), uml::I0); // mov [pc],i0 + save_fast_iregs(block); + UML_EXIT(block, EXECUTE_MISSING_CODE); // exit EXECUTE_MISSING_CODE + + block->end(); +} + + +/*------------------------------------------------- + static_generate_out_of_cycles - generate an + out of cycles exception handler +-------------------------------------------------*/ + +void arm7_cpu_device::static_generate_out_of_cycles() +{ + drcuml_state *drcuml = m_impstate.drcuml; + drcuml_block *block; + + /* begin generating */ + block = drcuml->begin_block(10); + + /* generate a hash jump via the current mode and PC */ + alloc_handle(drcuml, &m_impstate.out_of_cycles, "out_of_cycles"); + UML_HANDLE(block, *m_impstate.out_of_cycles); // handle out_of_cycles + UML_GETEXP(block, uml::I0); // getexp i0 + UML_MOV(block, uml::mem(&R15), uml::I0); // mov ,i0 + save_fast_iregs(block); + UML_EXIT(block, EXECUTE_OUT_OF_CYCLES); // exit EXECUTE_OUT_OF_CYCLES + + block->end(); +} + + +/*------------------------------------------------------------------ + static_generate_tlb_translate +------------------------------------------------------------------*/ + +void arm7_cpu_device::static_generate_detect_fault(uml::code_handle **handleptr) +{ + /* on entry, flags are in I2, vaddr is in I3, desc_lvl1 is in I4, ap is in R5 */ + /* on exit, fault result is in I6 */ + drcuml_state *drcuml = m_impstate.drcuml; + drcuml_block *block; + int donefault = 0; + int checkuser = 0; + int label = 1; + + /* begin generating */ + block = drcuml->begin_block(1024); + + /* add a global entry for this */ + alloc_handle(drcuml, &m_impstate.detect_fault, "detect_fault"); + UML_HANDLE(block, *m_impstate.detect_fault); // handle detect_fault + + UML_ROLAND(block, uml::I6, uml::I4, 32-4, 0x0f<<1); // roland i6, i4, 32-4, 0xf<<1 + UML_ROLAND(block, uml::I6, uml::mem(&COPRO_DOMAIN_ACCESS_CONTROL), uml::I6, 3);// roland i6, COPRO_DOMAIN_ACCESS_CONTROL, i6, 3 + // if permission == 3, FAULT_NONE + UML_CMP(block, uml::I6, 3); // cmp i6, 3 + UML_MOVc(block, uml::COND_E, uml::I6, FAULT_NONE); // move i6, FAULT_NONE + UML_JMPc(block, uml::COND_E, donefault = label++); // jmpe donefault + // if permission == 0 || permission == 2, FAULT_DOMAIN + UML_CMP(block, uml::I6, 1); // cmp i6, 1 + UML_MOVc(block, uml::COND_NE, uml::I6, FAULT_DOMAIN); // movne i6, FAULT_DOMAIN + UML_JMPc(block, uml::COND_NE, donefault); // jmpne donefault + + // if permission == 1 + UML_CMP(block, uml::I5, 3); // cmp i5, 3 + UML_MOVc(block, uml::COND_E, uml::I6, FAULT_NONE); // move i6, FAULT_NONE + UML_JMPc(block, uml::COND_E, donefault); // jmpe donefault + UML_CMP(block, uml::I5, 0); // cmp i5, 1 + UML_JMPc(block, uml::COND_NE, checkuser = label++); // jmpne checkuser + UML_ROLAND(block, uml::I6, uml::mem(&COPRO_CTRL), // roland i6, COPRO_CTRL, 32 - COPRO_CTRL_SYSTEM_SHIFT, + 32 - COPRO_CTRL_SYSTEM_SHIFT, // COPRO_CTRL_SYSTEM | COPRO_CTRL_ROM + COPRO_CTRL_SYSTEM | COPRO_CTRL_ROM); + // if s == 0 && r == 0, FAULT_PERMISSION + UML_CMP(block, uml::I6, 0); // cmp i6, 0 + UML_MOVc(block, uml::COND_E, uml::I6, FAULT_PERMISSION); // move i6, FAULT_PERMISSION + UML_JMPc(block, uml::COND_E, donefault); // jmpe donefault + // if s == 1 && r == 1, FAULT_PERMISSION + UML_CMP(block, uml::I6, 3); // cmp i6, 3 + UML_MOVc(block, uml::COND_E, uml::I6, FAULT_PERMISSION); // move i6, FAULT_PERMISSION + UML_JMPc(block, uml::COND_E, donefault); // jmpe donefault + // if flags & TLB_WRITE, FAULT_PERMISSION + UML_TEST(block, uml::I2, ARM7_TLB_WRITE); // test i2, ARM7_TLB_WRITE + UML_MOVc(block, uml::COND_NZ, uml::I6, FAULT_PERMISSION); // move i6, FAULT_PERMISSION + UML_JMPc(block, uml::COND_NZ, donefault); // jmpe donefault + // if r == 1 && s == 0, FAULT_NONE + UML_CMP(block, uml::I6, 2); // cmp i6, 2 + UML_MOVc(block, uml::COND_E, uml::I6, FAULT_NONE); // move i6, FAULT_NONE + UML_JMPc(block, uml::COND_E, donefault); // jmpe donefault + UML_AND(block, uml::I6, uml::mem(&GET_CPSR), MODE_FLAG); // and i6, GET_CPSR, MODE_FLAG + UML_CMP(block, uml::I6, eARM7_MODE_USER); // cmp i6, eARM7_MODE_USER + // if r == 0 && s == 1 && usermode, FAULT_PERMISSION + UML_MOVc(block, uml::COND_E, uml::I6, FAULT_PERMISSION); // move i6, FAULT_PERMISSION + UML_MOVc(block, uml::COND_NE, uml::I6, FAULT_NONE); // movne i6, FAULT_NONE + UML_JMP(block, donefault); // jmp donefault + + UML_LABEL(block, checkuser); // checkuser: + // if !write, FAULT_NONE + UML_TEST(block, uml::I2, ARM7_TLB_WRITE); // test i2, ARM7_TLB_WRITE + UML_MOVc(block, uml::COND_Z, uml::I6, FAULT_NONE); // movz i6, FAULT_NONE + UML_JMPc(block, uml::COND_Z, donefault); // jmp donefault + UML_AND(block, uml::I6, uml::mem(&GET_CPSR), MODE_FLAG); // and i6, GET_CPSR, MODE_FLAG + UML_CMP(block, uml::I6, eARM7_MODE_USER); // cmp i6, eARM7_MODE_USER + UML_MOVc(block, uml::COND_E, uml::I6, FAULT_PERMISSION); // move i6, FAULT_PERMISSION + UML_MOVc(block, uml::COND_NE, uml::I6, FAULT_NONE); // move i6, FAULT_NONE + + UML_LABEL(block, donefault); // donefault: + UML_RET(block); // ret +} + +/*------------------------------------------------------------------ + static_generate_tlb_translate +------------------------------------------------------------------*/ + +void arm7_cpu_device::static_generate_tlb_translate(uml::code_handle **handleptr) +{ + /* on entry, address is in I0 and flags are in I2 */ + /* on exit, translated address is in I0 and success/failure is in I2 */ + /* routine trashes I4-I7 */ + drcuml_state *drcuml = m_impstate.drcuml; + drcuml_block *block; + uml::code_label smallfault; + uml::code_label smallprefetch; + int nopid = 0; + int nounmapped = 0; + int nounmapped2 = 0; + int nocoarse = 0; + int nofine = 0; + int nosection = 0; + int nolargepage = 0; + int nosmallpage = 0; + int notinypage = 0; + int handlefault = 0; + int level2 = 0; + int prefetch = 0; + int prefetch2 = 0; + int label = 1; + + /* begin generating */ + block = drcuml->begin_block(170); + + alloc_handle(drcuml, &m_impstate.tlb_translate, "tlb_translate"); + UML_HANDLE(block, *m_impstate.tlb_translate); // handle tlb_translate + + // I3: vaddr + UML_CMP(block, uml::I0, 32 * 1024 * 1024); // cmp i0, 32*1024*1024 + UML_JMPc(block, uml::COND_GE, nopid = label++); // jmpge nopid + UML_AND(block, uml::I3, uml::mem(&COPRO_FCSE_PID), 0xfe000000); // and i3, COPRO_FCSE_PID, 0xfe000000 + UML_ADD(block, uml::I3, uml::I3, uml::I0); // add i3, i3, i0 + + // I4: desc_lvl1 + UML_AND(block, uml::I4, uml::mem(&COPRO_TLB_BASE), COPRO_TLB_BASE_MASK); // and i4, COPRO_TLB_BASE, COPRO_TLB_BASE_MASK + UML_ROLINS(block, uml::I4, uml::I3, 32 - COPRO_TLB_VADDR_FLTI_MASK_SHIFT, // rolins i4, i3, 32-COPRO_TLB_VADDR_FLTI_MASK_SHIFT, + COPRO_TLB_VADDR_FLTI_MASK); // COPRO_TLB_VADDR_FLTI_MASK + UML_READ(block, uml::I4, uml::I4, uml::SIZE_DWORD, uml::SPACE_PROGRAM); // read32 i4, i4, PROGRAM + + // I7: desc_lvl1 & 3 + UML_AND(block, uml::I7, uml::I4, 3); // and i7, i4, 3 + + UML_CMP(block, uml::I7, COPRO_TLB_UNMAPPED); // cmp i7, COPRO_TLB_UNMAPPED + UML_JMPc(block, uml::COND_NE, nounmapped = label++); // jmpne nounmapped + + // TLB Unmapped + UML_TEST(block, uml::I2, ARM7_TLB_ABORT_D); // test i2, ARM7_TLB_ABORT_D + UML_MOVc(block, uml::COND_E, uml::mem(&COPRO_FAULT_STATUS_D), (5 << 0)); // move COPRO_FAULT_STATUS_D, (5 << 0) + UML_MOVc(block, uml::COND_E, uml::mem(&COPRO_FAULT_ADDRESS), uml::I3); // move COPRO_FAULT_ADDRESS, i3 + UML_MOVc(block, uml::COND_E, uml::mem(&m_pendingAbtD), 1); // move pendingAbtD, 1 + UML_MOVc(block, uml::COND_E, uml::I2, 0); // move i2, 0 + UML_RETc(block, uml::COND_E); // rete + + UML_TEST(block, uml::I2, ARM7_TLB_ABORT_P); // test i2, ARM7_TLB_ABORT_P + UML_MOVc(block, uml::COND_E, uml::mem(&m_pendingAbtP), 1); // move pendingAbtP, 1 + UML_MOV(block, uml::I2, 0); // mov i2, 0 + UML_RET(block); // ret + + UML_LABEL(block, nounmapped); // nounmapped: + UML_CMP(block, uml::I7, COPRO_TLB_COARSE_TABLE); // cmp i7, COPRO_TLB_COARSE_TABLE + UML_JMPc(block, uml::COND_NE, nocoarse = label++); // jmpne nocoarse + + UML_ROLAND(block, uml::I5, uml::I4, 32-4, 0x0f<<1); // roland i5, i4, 32-4, 0xf<<1 + UML_ROLAND(block, uml::I5, uml::mem(&COPRO_DOMAIN_ACCESS_CONTROL), uml::I5, 3);// roland i5, COPRO_DOMAIN_ACCESS_CONTROL, i5, 3 + UML_CMP(block, uml::I5, 1); // cmp i5, 1 + UML_JMPc(block, uml::COND_E, level2 = label++); // jmpe level2 + UML_CMP(block, uml::I5, 3); // cmp i5, 3 + UML_JMPc(block, uml::COND_NE, nofine = label++); // jmpne nofine + UML_LABEL(block, level2); // level2: + + // I7: desc_level2 + UML_AND(block, uml::I7, uml::I4, COPRO_TLB_CFLD_ADDR_MASK); // and i7, i4, COPRO_TLB_CFLD_ADDR_MASK + UML_ROLINS(block, uml::I7, uml::I3, 32 - COPRO_TLB_VADDR_CSLTI_MASK_SHIFT,// rolins i7, i3, 32 - COPRO_TLB_VADDR_CSLTI_MASK_SHIFT + COPRO_TLB_VADDR_CSLTI_MASK); // COPRO_TLB_VADDR_CSLTI_MASK + UML_READ(block, uml::I7, uml::I7, uml::SIZE_DWORD, uml::SPACE_PROGRAM); // read32 i7, i7, PROGRAM + UML_JMP(block, nofine); // jmp nofine + + UML_LABEL(block, nocoarse); // nocoarse: + UML_CMP(block, uml::I7, COPRO_TLB_SECTION_TABLE); // cmp i7, COPRO_TLB_SECTION_TABLE + UML_JMPc(block, uml::COND_NE, nosection = label++); // jmpne nosection + + UML_ROLAND(block, uml::I5, uml::I4, 32-10, 3); // roland i7, i4, 32-10, 3 + // result in I6 + UML_CALLH(block, *m_impstate.detect_fault); // callh detect_fault + UML_CMP(block, uml::I6, FAULT_NONE); // cmp i6, FAULT_NONE + UML_JMPc(block, uml::COND_NE, handlefault = label++); // jmpne handlefault + + // no fault, return translated address + UML_AND(block, uml::I0, uml::I3, ~COPRO_TLB_SECTION_PAGE_MASK); // and i0, i3, ~COPRO_TLB_SECTION_PAGE_MASK + UML_ROLINS(block, uml::I0, uml::I4, 0, COPRO_TLB_SECTION_PAGE_MASK); // rolins i0, i4, COPRO_TLB_SECTION_PAGE_MASK + UML_MOV(block, uml::I2, 1); // mov i2, 1 + UML_RET(block); // ret + + UML_LABEL(block, handlefault); // handlefault: + UML_TEST(block, uml::I2, ARM7_TLB_ABORT_D); // test i2, ARM7_TLB_ABORT_D + UML_JMPc(block, uml::COND_Z, prefetch = label++); // jmpz prefetch + UML_MOV(block, uml::mem(&COPRO_FAULT_ADDRESS), uml::I3); // mov COPRO_FAULT_ADDRESS, i3 + UML_MOV(block, uml::mem(&m_pendingAbtD), 1); // mov m_pendingAbtD, 1 + UML_ROLAND(block, uml::I5, uml::I4, 31, 0xf0); // roland i5, i4, 31, 0xf0 + UML_CMP(block, uml::I6, FAULT_DOMAIN); // cmp i6, FAULT_DOMAIN + UML_MOVc(block, uml::COND_E, uml::I6, 9 << 0); // move i6, 9 << 0 + UML_MOVc(block, uml::COND_NE, uml::I6, 13 << 0); // movne i6, 13 << 0 + UML_OR(block, uml::mem(&COPRO_FAULT_STATUS_D), uml::I5, uml::I6); // or COPRO_FAULT_STATUS_D, i5, i6 + UML_MOV(block, uml::I2, 0); // mov i2, 0 + UML_RET(block); // ret + + UML_LABEL(block, prefetch); // prefetch: + UML_MOV(block, uml::mem(&m_pendingAbtP), 1); // mov m_pendingAbtP, 1 + UML_MOV(block, uml::I2, 0); // mov i2, 0 + UML_RET(block); // ret + + UML_LABEL(block, nosection); // nosection: + UML_CMP(block, uml::I7, COPRO_TLB_FINE_TABLE); // cmp i7, COPRO_TLB_FINE_TABLE + UML_JMPc(block, uml::COND_NE, nofine); // jmpne nofine + + // Not yet implemented + UML_MOV(block, uml::I2, 1); // mov i2, 1 + UML_RET(block); // ret + + UML_LABEL(block, nofine); // nofine: + + // I7: desc_lvl2 + UML_AND(block, uml::I6, uml::I7, 3); // and i6, i7, 3 + UML_CMP(block, uml::I6, COPRO_TLB_UNMAPPED); // cmp i6, COPRO_TLB_UNMAPPED + UML_JMPc(block, uml::COND_NE, nounmapped2 = label++); // jmpne nounmapped2 + + UML_TEST(block, uml::I2, ARM7_TLB_ABORT_D); // test i2, ARM7_TLB_ABORT_D + UML_JMPc(block, uml::COND_Z, prefetch2 = label++); // jmpz prefetch2 + UML_MOV(block, uml::mem(&COPRO_FAULT_ADDRESS), uml::I3); // mov COPRO_FAULT_ADDRESS, i3 + UML_MOV(block, uml::mem(&m_pendingAbtD), 1); // mov m_pendingAbtD, 1 + UML_ROLAND(block, uml::I5, uml::I4, 31, 0xf0); // roland i5, i4, 31, 0xf0 + UML_OR(block, uml::I5, uml::I5, 7 << 0); // or i5, i5, 7 << 0 + UML_OR(block, uml::mem(&COPRO_FAULT_STATUS_D), uml::I5, uml::I6); // or COPRO_FAULT_STATUS_D, i5, i6 + UML_MOV(block, uml::I2, 0); // mov i2, 0 + UML_RET(block); // ret + + UML_LABEL(block, prefetch2); // prefetch2: + UML_MOV(block, uml::mem(&m_pendingAbtP), 1); // mov m_pendingAbtP, 1 + UML_MOV(block, uml::I2, 0); // mov i2, 0 + UML_RET(block); // ret + + UML_LABEL(block, nounmapped2); // nounmapped2: + UML_CMP(block, uml::I6, COPRO_TLB_LARGE_PAGE); // cmp i6, COPRO_TLB_LARGE_PAGE + UML_JMPc(block, uml::COND_NE, nolargepage = label++); // jmpne nolargepage + + UML_AND(block, uml::I0, uml::I3, ~COPRO_TLB_LARGE_PAGE_MASK); // and i0, i3, ~COPRO_TLB_LARGE_PAGE_MASK + UML_ROLINS(block, uml::I0, uml::I7, 0, COPRO_TLB_LARGE_PAGE_MASK); // rolins i0, i7, 0, COPRO_TLB_LARGE_PAGE_MASK + UML_MOV(block, uml::I2, 1); // mov i2, 1 + UML_RET(block); // ret + + UML_LABEL(block, nolargepage); // nolargepage: + UML_CMP(block, uml::I6, COPRO_TLB_SMALL_PAGE); // cmp i6, COPRO_TLB_SMALL_PAGE + UML_JMPc(block, uml::COND_NE, nosmallpage = label++); // jmpne nosmallpage + + UML_ROLAND(block, uml::I5, uml::I3, 32-9, 3<<1); // roland i5, i3, 32-9, 3<<1 + UML_ROLAND(block, uml::I6, uml::I7, 32-4, 0xff); // roland i6, i7, 32-4, 0xff + UML_SHR(block, uml::I5, uml::I7, uml::I5); // shr i5, i7, i5 + UML_AND(block, uml::I5, uml::I5, 3); // and i5, i5, 3 + // result in I6 + UML_CALLH(block, *m_impstate.detect_fault); // callh detect_fault + + UML_CMP(block, uml::I6, FAULT_NONE); // cmp i6, FAULT_NONE + UML_JMPc(block, uml::COND_NE, smallfault = label++); // jmpne smallfault + UML_AND(block, uml::I0, uml::I7, COPRO_TLB_SMALL_PAGE_MASK); // and i0, i7, COPRO_TLB_SMALL_PAGE_MASK + UML_ROLINS(block, uml::I0, uml::I3, 0, ~COPRO_TLB_SMALL_PAGE_MASK); // rolins i0, i3, 0, ~COPRO_TLB_SMALL_PAGE_MASK + UML_MOV(block, uml::I2, 1); // mov i2, 1 + UML_RET(block); // ret + + UML_LABEL(block, smallfault); // smallfault: + UML_TEST(block, uml::I2, ARM7_TLB_ABORT_D); // test i2, ARM7_TLB_ABORT_D + UML_JMPc(block, uml::COND_NZ, smallprefetch = label++); // jmpnz smallprefetch + UML_MOV(block, uml::mem(&COPRO_FAULT_ADDRESS), uml::I3); // mov COPRO_FAULT_ADDRESS, i3 + UML_MOV(block, uml::mem(&m_pendingAbtD), 1); // mov pendingAbtD, 1 + UML_CMP(block, uml::I6, FAULT_DOMAIN); // cmp i6, FAULT_DOMAIN + UML_MOVc(block, uml::COND_E, uml::I5, 11 << 0); // move i5, 11 << 0 + UML_MOVc(block, uml::COND_NE, uml::I5, 15 << 0); // movne i5, 15 << 0 + UML_ROLINS(block, uml::I5, uml::I4, 31, 0xf0); // rolins i5, i4, 31, 0xf0 + UML_MOV(block, uml::mem(&COPRO_FAULT_STATUS_D), uml::I5); // mov COPRO_FAULT_STATUS_D, i5 + UML_MOV(block, uml::I2, 0); // mov i2, 0 + UML_RET(block); // ret + + UML_LABEL(block, smallprefetch); // smallprefetch: + UML_MOV(block, uml::mem(&m_pendingAbtP), 1); // mov pendingAbtP, 1 + UML_MOV(block, uml::I2, 0); // mov i2, 0 + UML_RET(block); // ret + + UML_LABEL(block, nosmallpage); // nosmallpage: + UML_CMP(block, uml::I6, COPRO_TLB_TINY_PAGE); // cmp i6, COPRO_TLB_TINY_PAGE + UML_JMPc(block, uml::COND_NE, notinypage = label++); // jmpne notinypage + + UML_AND(block, uml::I0, uml::I3, ~COPRO_TLB_TINY_PAGE_MASK); // and i0, i3, ~COPRO_TLB_TINY_PAGE_MASK + UML_ROLINS(block, uml::I0, uml::I7, 0, COPRO_TLB_TINY_PAGE_MASK); // rolins i0, i7, 0, COPRO_TLB_TINY_PAGE_MASK + UML_MOV(block, uml::I2, 1); // mov i2, 1 + UML_RET(block); // ret + + UML_LABEL(block, notinypage); // notinypage: + UML_MOV(block, uml::I0, uml::I3); // mov i0, i3 + UML_RET(block); // ret + + block->end(); +} + +/*------------------------------------------------------------------ + static_generate_memory_accessor +------------------------------------------------------------------*/ + +void arm7_cpu_device::static_generate_memory_accessor(int size, bool istlb, bool iswrite, const char *name, uml::code_handle **handleptr) +{ + /* on entry, address is in I0; data for writes is in I1, fetch type in I2 */ + /* on exit, read result is in I0 */ + /* routine trashes I0-I3 */ + drcuml_state *drcuml = m_impstate.drcuml; + drcuml_block *block; + //int tlbmiss = 0; + int label = 1; + + /* begin generating */ + block = drcuml->begin_block(1024); + + /* add a global entry for this */ + alloc_handle(drcuml, handleptr, name); + UML_HANDLE(block, **handleptr); // handle *handleptr + + if (istlb) + { + UML_TEST(block, uml::mem(&COPRO_CTRL), COPRO_CTRL_MMU_EN); // test COPRO_CTRL, COPRO_CTRL_MMU_EN + if (iswrite) + { + UML_MOVc(block, uml::COND_NZ, uml::I3, ARM7_TLB_WRITE); // movnz i3, ARM7_TLB_WRITE + } + else + { + UML_MOVc(block, uml::COND_NZ, uml::I3, ARM7_TLB_READ); // movnz i3, ARM7_TLB_READ + } + UML_OR(block, uml::I2, uml::I2, uml::I3); // or i2, i2, i3 + UML_CALLHc(block, uml::COND_NZ, *m_impstate.tlb_translate); // callhnz tlb_translate + } + + /* general case: assume paging and perform a translation */ + if ((machine().debug_flags & DEBUG_FLAG_ENABLED) == 0) + { + for (int ramnum = 0; ramnum < ARM7_MAX_FASTRAM; ramnum++) + { + if (m_impstate.fastram[ramnum].base != NULL && (!iswrite || !m_impstate.fastram[ramnum].readonly)) + { + void *fastbase = (UINT8 *)m_impstate.fastram[ramnum].base - m_impstate.fastram[ramnum].start; + UINT32 skip = label++; + if (m_impstate.fastram[ramnum].end != 0xffffffff) + { + UML_CMP(block, uml::I0, m_impstate.fastram[ramnum].end); // cmp i0, end + UML_JMPc(block, uml::COND_A, skip); // ja skip + } + if (m_impstate.fastram[ramnum].start != 0x00000000) + { + UML_CMP(block, uml::I0, m_impstate.fastram[ramnum].start); // cmp i0, fastram_start + UML_JMPc(block, uml::COND_B, skip); // jb skip + } + + if (!iswrite) + { + if (size == 1) + { + UML_XOR(block, uml::I0, uml::I0, (m_endian == ENDIANNESS_BIG) ? BYTE4_XOR_BE(0) : BYTE4_XOR_LE(0)); + // xor i0, i0, bytexor + UML_LOAD(block, uml::I0, fastbase, uml::I0, uml::SIZE_BYTE, uml::SCALE_x1); // load i0, fastbase, i0, byte + } + else if (size == 2) + { + UML_XOR(block, uml::I0, uml::I0, (m_endian == ENDIANNESS_BIG) ? WORD_XOR_BE(0) : WORD_XOR_LE(0)); + // xor i0, i0, wordxor + UML_LOAD(block, uml::I0, fastbase, uml::I0, uml::SIZE_WORD, uml::SCALE_x1); // load i0, fastbase, i0, word_x1 + } + else if (size == 4) + { + UML_LOAD(block, uml::I0, fastbase, uml::I0, uml::SIZE_DWORD, uml::SCALE_x1); // load i0, fastbase, i0, dword_x1 + } + UML_RET(block); // ret + } + else + { + if (size == 1) + { + UML_XOR(block, uml::I0, uml::I0, (m_endian == ENDIANNESS_BIG) ? BYTE4_XOR_BE(0) : BYTE4_XOR_LE(0)); + // xor i0, i0, bytexor + UML_STORE(block, fastbase, uml::I0, uml::I1, uml::SIZE_BYTE, uml::SCALE_x1); // store fastbase, i0, i1, byte + } + else if (size == 2) + { + UML_XOR(block, uml::I0, uml::I0, (m_endian == ENDIANNESS_BIG) ? WORD_XOR_BE(0) : WORD_XOR_LE(0)); + // xor i0, i0, wordxor + UML_STORE(block, fastbase, uml::I0, uml::I1, uml::SIZE_WORD, uml::SCALE_x1); // store fastbase, i0, i1, word_x1 + } + else if (size == 4) + { + UML_STORE(block, fastbase, uml::I0, uml::I1, uml::SIZE_DWORD, uml::SCALE_x1); // store fastbase,i0,i1,dword_x1 + } + UML_RET(block); // ret + } + + UML_LABEL(block, skip); // skip: + } + } + } + + switch (size) + { + case 1: + if (iswrite) + { + UML_WRITE(block, uml::I0, uml::I1, uml::SIZE_BYTE, uml::SPACE_PROGRAM); // write i0, i1, program_byte + } + else + { + UML_READ(block, uml::I0, uml::I0, uml::SIZE_BYTE, uml::SPACE_PROGRAM); // read i0, i0, program_byte + } + break; + + case 2: + if (iswrite) + { + UML_WRITE(block, uml::I0, uml::I1, uml::SIZE_WORD, uml::SPACE_PROGRAM); // write i0,i1,program_word + } + else + { + UML_READ(block, uml::I0, uml::I0, uml::SIZE_WORD, uml::SPACE_PROGRAM); // read i0,i0,program_word + } + break; + + case 4: + if (iswrite) + { + UML_WRITE(block, uml::I0, uml::I1, uml::SIZE_DWORD, uml::SPACE_PROGRAM); // write i0,i1,program_dword + } + else + { + UML_READ(block, uml::I0, uml::I0, uml::SIZE_DWORD, uml::SPACE_PROGRAM); // read i0,i0,program_dword + } + break; + } + UML_RET(block); // ret + + block->end(); +} + +/*************************************************************************** + CODE GENERATION +***************************************************************************/ + +/*------------------------------------------------- + generate_update_cycles - generate code to + subtract cycles from the icount and generate + an exception if out +-------------------------------------------------*/ + +void arm7_cpu_device::generate_update_cycles(drcuml_block *block, compiler_state *compiler, uml::parameter param) +{ + /* check full interrupts if pending */ + if (compiler->checkints) + { + uml::code_label skip; + + compiler->checkints = FALSE; + UML_CALLH(block, *m_impstate.check_irq); + } + + /* account for cycles */ + if (compiler->cycles > 0) + { + UML_SUB(block, uml::mem(&m_icount), uml::mem(&m_icount), MAPVAR_CYCLES); // sub icount,icount,cycles + UML_MAPVAR(block, MAPVAR_CYCLES, 0); // mapvar cycles,0 + UML_EXHc(block, uml::COND_S, *m_impstate.out_of_cycles, param); // exh out_of_cycles,nextpc + } + compiler->cycles = 0; +} + + +/*------------------------------------------------- + generate_checksum_block - generate code to + validate a sequence of opcodes +-------------------------------------------------*/ + +void arm7_cpu_device::generate_checksum_block(drcuml_block *block, compiler_state *compiler, const opcode_desc *seqhead, const opcode_desc *seqlast) +{ + const opcode_desc *curdesc; + if (m_impstate.drcuml->logging()) + { + block->append_comment("[Validation for %08X]", seqhead->pc); // comment + } + + /* loose verify or single instruction: just compare and fail */ + if (!(m_impstate.drcoptions & ARM7DRC_STRICT_VERIFY) || seqhead->next() == NULL) + { + if (!(seqhead->flags & OPFLAG_VIRTUAL_NOOP)) + { + UINT32 sum = seqhead->opptr.l[0]; + void *base = m_direct->read_ptr(seqhead->physpc); + UML_LOAD(block, uml::I0, base, 0, uml::SIZE_DWORD, uml::SCALE_x4); // load i0,base,0,dword + + if (seqhead->delay.first() != NULL && seqhead->physpc != seqhead->delay.first()->physpc) + { + base = m_direct->read_ptr(seqhead->delay.first()->physpc); + UML_LOAD(block, uml::I1, base, 0, uml::SIZE_DWORD, uml::SCALE_x4); // load i1,base,dword + UML_ADD(block, uml::I0, uml::I0, uml::I1); // add i0,i0,i1 + + sum += seqhead->delay.first()->opptr.l[0]; + } + + UML_CMP(block, uml::I0, sum); // cmp i0,opptr[0] + UML_EXHc(block, uml::COND_NE, *m_impstate.nocode, epc(seqhead)); // exne nocode,seqhead->pc + } + } + + /* full verification; sum up everything */ + else + { + UINT32 sum = 0; + void *base = m_direct->read_ptr(seqhead->physpc); + UML_LOAD(block, uml::I0, base, 0, uml::SIZE_DWORD, uml::SCALE_x4); // load i0,base,0,dword + sum += seqhead->opptr.l[0]; + for (curdesc = seqhead->next(); curdesc != seqlast->next(); curdesc = curdesc->next()) + if (!(curdesc->flags & OPFLAG_VIRTUAL_NOOP)) + { + base = m_direct->read_ptr(curdesc->physpc); + UML_LOAD(block, uml::I1, base, 0, uml::SIZE_DWORD, uml::SCALE_x4); // load i1,base,dword + UML_ADD(block, uml::I0, uml::I0, uml::I1); // add i0,i0,i1 + sum += curdesc->opptr.l[0]; + + if (curdesc->delay.first() != NULL && (curdesc == seqlast || (curdesc->next() != NULL && curdesc->next()->physpc != curdesc->delay.first()->physpc))) + { + base = m_direct->read_ptr(curdesc->delay.first()->physpc); + UML_LOAD(block, uml::I1, base, 0, uml::SIZE_DWORD, uml::SCALE_x4); // load i1,base,dword + UML_ADD(block, uml::I0, uml::I0, uml::I1); // add i0,i0,i1 + sum += curdesc->delay.first()->opptr.l[0]; + } + } + UML_CMP(block, uml::I0, sum); // cmp i0,sum + UML_EXHc(block, uml::COND_NE, *m_impstate.nocode, epc(seqhead)); // exne nocode,seqhead->pc + } +} + + +/*------------------------------------------------- + generate_sequence_instruction - generate code + for a single instruction in a sequence +-------------------------------------------------*/ + +void arm7_cpu_device::generate_sequence_instruction(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) +{ + //offs_t expc; + int hotnum; + + /* add an entry for the log */ + // TODO FIXME +// if (m_impstate.drcuml->logging() && !(desc->flags & OPFLAG_VIRTUAL_NOOP)) +// log_add_disasm_comment(block, desc->pc, desc->opptr.l[0]); + + /* set the PC map variable */ + //expc = (desc->flags & OPFLAG_IN_DELAY_SLOT) ? desc->pc - 3 : desc->pc; + UML_MAPVAR(block, MAPVAR_PC, desc->pc); // mapvar PC,pc + + /* accumulate total cycles */ + compiler->cycles += desc->cycles; + + /* update the icount map variable */ + UML_MAPVAR(block, MAPVAR_CYCLES, compiler->cycles); // mapvar CYCLES,compiler->cycles + + /* is this a hotspot? */ + for (hotnum = 0; hotnum < ARM7_MAX_HOTSPOTS; hotnum++) + { + if (m_impstate.hotspot[hotnum].pc != 0 && desc->pc == m_impstate.hotspot[hotnum].pc && desc->opptr.l[0] == m_impstate.hotspot[hotnum].opcode) + { + compiler->cycles += m_impstate.hotspot[hotnum].cycles; + break; + } + } + + /* update the icount map variable */ + UML_MAPVAR(block, MAPVAR_CYCLES, compiler->cycles); // mapvar CYCLES,compiler->cycles + + /* if we are debugging, call the debugger */ + if ((machine().debug_flags & DEBUG_FLAG_ENABLED) != 0) + { + UML_MOV(block, uml::mem(&R15), desc->pc); // mov [pc],desc->pc + save_fast_iregs(block); + UML_DEBUG(block, desc->pc); // debug desc->pc + } + + /* if we hit an unmapped address, fatal error */ + if (desc->flags & OPFLAG_COMPILER_UNMAPPED) + { + UML_MOV(block, uml::mem(&R15), desc->pc); // mov R15,desc->pc + save_fast_iregs(block); + UML_EXIT(block, EXECUTE_UNMAPPED_CODE); // exit EXECUTE_UNMAPPED_CODE + } + + /* otherwise, unless this is a virtual no-op, it's a regular instruction */ + else if (!(desc->flags & OPFLAG_VIRTUAL_NOOP)) + { + /* compile the instruction */ + if (!generate_opcode(block, compiler, desc)) + { + UML_MOV(block, uml::mem(&R15), desc->pc); // mov R15,desc->pc + UML_MOV(block, uml::mem(&m_impstate.arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + //UML_CALLC(block, cfunc_unimplemented, arm); // callc cfunc_unimplemented // TODO FIXME + } + } +} + + +/*------------------------------------------------------------------ + generate_delay_slot_and_branch +------------------------------------------------------------------*/ + +void arm7_cpu_device::generate_delay_slot_and_branch(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, UINT8 linkreg) +{ + compiler_state compiler_temp = *compiler; + + /* update the cycles and jump through the hash table to the target */ + if (desc->targetpc != BRANCH_TARGET_DYNAMIC) + { + generate_update_cycles(block, &compiler_temp, desc->targetpc); // + UML_HASHJMP(block, 0, desc->targetpc, *m_impstate.nocode); + // hashjmp 0,desc->targetpc,nocode + } + else + { + generate_update_cycles(block, &compiler_temp, uml::mem(&m_impstate.jmpdest)); + // + UML_HASHJMP(block, 0, uml::mem(&m_impstate.jmpdest), *m_impstate.nocode);// hashjmp 0,,nocode + } + + /* update the label */ + compiler->labelnum = compiler_temp.labelnum; + + /* reset the mapvar to the current cycles and account for skipped slots */ + compiler->cycles += desc->skipslots; + UML_MAPVAR(block, MAPVAR_CYCLES, compiler->cycles); // mapvar CYCLES,compiler->cycles +} + + +const arm7_cpu_device::drcarm7ops_ophandler arm7_cpu_device::drcops_handler[0x10] = +{ + &arm7_cpu_device::drcarm7ops_0123, &arm7_cpu_device::drcarm7ops_0123, &arm7_cpu_device::drcarm7ops_0123, &arm7_cpu_device::drcarm7ops_0123, + &arm7_cpu_device::drcarm7ops_4567, &arm7_cpu_device::drcarm7ops_4567, &arm7_cpu_device::drcarm7ops_4567, &arm7_cpu_device::drcarm7ops_4567, + &arm7_cpu_device::drcarm7ops_89, &arm7_cpu_device::drcarm7ops_89, &arm7_cpu_device::drcarm7ops_ab, &arm7_cpu_device::drcarm7ops_ab, + &arm7_cpu_device::drcarm7ops_cd, &arm7_cpu_device::drcarm7ops_cd, &arm7_cpu_device::drcarm7ops_e, &arm7_cpu_device::drcarm7ops_f, +}; + +void arm7_cpu_device::saturate_qbit_overflow(drcuml_block *block) +{ + UML_MOV(block, uml::I1, 0); + UML_DCMP(block, uml::I0, 0x000000007fffffffL); + UML_MOVc(block, uml::COND_G, uml::I1, Q_MASK); + UML_MOVc(block, uml::COND_G, uml::I0, 0x7fffffff); + UML_DCMP(block, uml::I0, U64(0xffffffff80000000)); + UML_MOVc(block, uml::COND_L, uml::I1, Q_MASK); + UML_MOVc(block, uml::COND_L, uml::I0, 0x80000000); + UML_OR(block, DRC_CPSR, DRC_CPSR, uml::I1); +} + +bool arm7_cpu_device::drcarm7ops_0123(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, UINT32 insn) +{ + uml::code_label done; + /* Branch and Exchange (BX) */ + if ((insn & 0x0ffffff0) == 0x012fff10) // bits 27-4 == 000100101111111111110001 + { + UML_MOV(block, DRC_PC, DRC_REG(insn & 0x0f)); + UML_TEST(block, DRC_PC, 1); + UML_JMPc(block, uml::COND_Z, done = compiler->labelnum++); + UML_OR(block, DRC_CPSR, DRC_CPSR, T_MASK); + UML_AND(block, DRC_PC, DRC_PC, ~1); + } + else if ((insn & 0x0ff000f0) == 0x01600010) // CLZ - v5 + { + UINT32 rm = insn&0xf; + UINT32 rd = (insn>>12)&0xf; + + UML_LZCNT(block, DRC_REG(rd), DRC_REG(rm)); + UML_ADD(block, DRC_PC, DRC_PC, 4); + } + else if ((insn & 0x0ff000f0) == 0x01000050) // QADD - v5 + { + UINT32 rm = insn&0xf; + UINT32 rn = (insn>>16)&0xf; + UINT32 rd = (insn>>12)&0xf; + UML_DSEXT(block, uml::I0, DRC_REG(rm), uml::SIZE_DWORD); + UML_DSEXT(block, uml::I1, DRC_REG(rn), uml::SIZE_DWORD); + UML_DADD(block, uml::I0, uml::I0, uml::I1); + saturate_qbit_overflow(block); + UML_MOV(block, DRC_REG(rd), uml::I0); + UML_ADD(block, DRC_PC, DRC_PC, 4); + } + else if ((insn & 0x0ff000f0) == 0x01400050) // QDADD - v5 + { + UINT32 rm = insn&0xf; + UINT32 rn = (insn>>16)&0xf; + UINT32 rd = (insn>>12)&0xf; + + UML_DSEXT(block, uml::I1, DRC_REG(rn), uml::SIZE_DWORD); + UML_DADD(block, uml::I0, uml::I1, uml::I1); + saturate_qbit_overflow(block); + + UML_DSEXT(block, uml::I0, DRC_REG(rm), uml::SIZE_DWORD); + UML_DSEXT(block, uml::I1, DRC_REG(rn), uml::SIZE_DWORD); + UML_DADD(block, uml::I1, uml::I1, uml::I1); + UML_DADD(block, uml::I0, uml::I0, uml::I1); + saturate_qbit_overflow(block); + UML_MOV(block, DRC_REG(rd), uml::I0); + + UML_ADD(block, DRC_PC, DRC_PC, 4); + } + else if ((insn & 0x0ff000f0) == 0x01200050) // QSUB - v5 + { + UINT32 rm = insn&0xf; + UINT32 rn = (insn>>16)&0xf; + UINT32 rd = (insn>>12)&0xf; + + UML_DSEXT(block, uml::I0, DRC_REG(rm), uml::SIZE_DWORD); + UML_DSEXT(block, uml::I1, DRC_REG(rn), uml::SIZE_DWORD); + UML_DSUB(block, uml::I0, uml::I0, uml::I1); + saturate_qbit_overflow(block); + UML_MOV(block, DRC_REG(rd), uml::I0); + UML_ADD(block, DRC_PC, DRC_PC, 4); + } + else if ((insn & 0x0ff000f0) == 0x01600050) // QDSUB - v5 + { + UINT32 rm = insn&0xf; + UINT32 rn = (insn>>16)&0xf; + UINT32 rd = (insn>>12)&0xf; + + UML_DSEXT(block, uml::I1, DRC_REG(rn), uml::SIZE_DWORD); + UML_DADD(block, uml::I0, uml::I1, uml::I1); + saturate_qbit_overflow(block); + + UML_DSEXT(block, uml::I0, DRC_REG(rm), uml::SIZE_DWORD); + UML_DSEXT(block, uml::I1, DRC_REG(rn), uml::SIZE_DWORD); + UML_DADD(block, uml::I1, uml::I1, uml::I1); + UML_DSUB(block, uml::I0, uml::I0, uml::I1); + saturate_qbit_overflow(block); + UML_MOV(block, DRC_REG(rd), uml::I0); + + UML_ADD(block, DRC_PC, DRC_PC, 4); + } + else if ((insn & 0x0ff00090) == 0x01000080) // SMLAxy - v5 + { + UINT32 rm = insn&0xf; + UINT32 rn = (insn>>8)&0xf; + UINT32 rd = (insn>>16)&0xf; + UINT32 ra = (insn>>12)&0xf; + + UML_MOV(block, uml::I0, DRC_REG(rm)); + UML_MOV(block, uml::I1, DRC_REG(rn)); + + // select top and bottom halves of src1/src2 and sign extend if necessary + if (insn & 0x20) + { + UML_SHR(block, uml::I0, uml::I0, 16); + } + UML_SEXT(block, uml::I0, uml::I0, uml::SIZE_WORD); + + if (insn & 0x40) + { + UML_SHR(block, uml::I1, uml::I1, 16); + } + UML_SEXT(block, uml::I0, uml::I0, uml::SIZE_WORD); + + // do the signed multiply + UML_MULS(block, uml::I0, uml::I1, uml::I0, uml::I1); + UML_DSHL(block, uml::I0, uml::I0, 32); + UML_DOR(block, uml::I0, uml::I0, uml::I1); + UML_MOV(block, uml::I1, DRC_REG(ra)); + UML_DADD(block, uml::I0, uml::I0, uml::I1); + // and the accumulate. NOTE: only the accumulate can cause an overflow, which is why we do it this way. + saturate_qbit_overflow(block); + UML_MOV(block, DRC_REG(rd), uml::I0); + UML_ADD(block, DRC_PC, DRC_PC, 4); + } + else if ((insn & 0x0ff00090) == 0x01400080) // SMLALxy - v5 + { + UINT32 rm = insn&0xf; + UINT32 rn = (insn>>8)&0xf; + UINT32 rdh = (insn>>16)&0xf; + UINT32 rdl = (insn>>12)&0xf; + + UML_DSEXT(block, uml::I0, DRC_REG(rm), uml::SIZE_DWORD); + UML_DSEXT(block, uml::I1, DRC_REG(rn), uml::SIZE_DWORD); + // do the signed multiply + UML_DMULS(block, uml::I2, uml::I3, uml::I0, uml::I1); + + UML_MOV(block, uml::I0, DRC_REG(rdh)); + UML_MOV(block, uml::I1, DRC_REG(rdl)); + UML_DSHL(block, uml::I0, uml::I0, 32); + UML_DOR(block, uml::I0, uml::I0, uml::I1); + UML_DADD(block, uml::I0, uml::I0, uml::I2); + UML_MOV(block, DRC_REG(rdl), uml::I0); + UML_DSHR(block, uml::I0, uml::I0, 32); + UML_MOV(block, DRC_REG(rdh), uml::I0); + } + else if ((insn & 0x0ff00090) == 0x01600080) // SMULxy - v5 + { + INT32 src1 = GET_REGISTER(insn&0xf); + INT32 src2 = GET_REGISTER((insn>>8)&0xf); + INT32 res; + + // select top and bottom halves of src1/src2 and sign extend if necessary + if (insn & 0x20) + { + src1 >>= 16; + } + + src1 &= 0xffff; + if (src1 & 0x8000) + { + src1 |= 0xffff0000; + } + + if (insn & 0x40) + { + src2 >>= 16; + } + + src2 &= 0xffff; + if (src2 & 0x8000) + { + src2 |= 0xffff0000; + } + + res = src1 * src2; + SET_REGISTER((insn>>16)&0xf, res); + R15 += 4; + } + else if ((insn & 0x0ff000b0) == 0x012000a0) // SMULWy - v5 + { + INT32 src1 = GET_REGISTER(insn&0xf); + INT32 src2 = GET_REGISTER((insn>>8)&0xf); + INT64 res; + + if (insn & 0x40) + { + src2 >>= 16; + } + else + { + src2 &= 0xffff; + if (src2 & 0x8000) + { + src2 |= 0xffff; + } + } + + res = (INT64)src1 * (INT64)src2; + res >>= 16; + SET_REGISTER((insn>>16)&0xf, (UINT32)res); + } + else if ((insn & 0x0ff000b0) == 0x01200080) // SMLAWy - v5 + { + INT32 src1 = GET_REGISTER(insn&0xf); + INT32 src2 = GET_REGISTER((insn>>8)&0xf); + INT32 src3 = GET_REGISTER((insn>>12)&0xf); + INT64 res; + + if (insn & 0x40) + { + src2 >>= 16; + } + else + { + src2 &= 0xffff; + if (src2 & 0x8000) + { + src2 |= 0xffff; + } + } + + res = (INT64)src1 * (INT64)src2; + res >>= 16; + + // check for overflow and set the Q bit + saturate_qbit_overflow((INT64)src3 + res); + + // do the real accumulate + src3 += (INT32)res; + + // write the result back + SET_REGISTER((insn>>16)&0xf, (UINT32)res); + } + else + /* Multiply OR Swap OR Half Word Data Transfer */ + if ((insn & 0x0e000000) == 0 && (insn & 0x80) && (insn & 0x10)) // bits 27-25=000 bit 7=1 bit 4=1 + { + /* Half Word Data Transfer */ + if (insn & 0x60) // bits = 6-5 != 00 + { + HandleHalfWordDT(insn); + } + else + /* Swap */ + if (insn & 0x01000000) // bit 24 = 1 + { + HandleSwap(insn); + } + /* Multiply Or Multiply Long */ + else + { + /* multiply long */ + if (insn & 0x800000) // Bit 23 = 1 for Multiply Long + { + /* Signed? */ + if (insn & 0x00400000) + HandleSMulLong(insn); + else + HandleUMulLong(insn); + } + /* multiply */ + else + { + HandleMul(insn); + } + R15 += 4; + } + } + /* Data Processing OR PSR Transfer */ + else if ((insn & 0x0c000000) == 0) // bits 27-26 == 00 - This check can only exist properly after Multiplication check above + { + /* PSR Transfer (MRS & MSR) */ + if (((insn & 0x00100000) == 0) && ((insn & 0x01800000) == 0x01000000)) // S bit must be clear, and bit 24,23 = 10 + { + HandlePSRTransfer(insn); + ARM7_ICOUNT += 2; // PSR only takes 1 - S Cycle, so we add + 2, since at end, we -3.. + R15 += 4; + } + /* Data Processing */ + else + { + HandleALU(insn); + } + } + + UML_LABEL(block, done); + return true; +} + +bool arm7_cpu_device::drcarm7ops_4567(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, UINT32 op) +{ + return false; +} + +bool arm7_cpu_device::drcarm7ops_89(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, UINT32 op) +{ + return false; +} + +bool arm7_cpu_device::drcarm7ops_ab(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, UINT32 op) +{ + return false; +} + +bool arm7_cpu_device::drcarm7ops_cd(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, UINT32 op) +{ + return false; +} + +bool arm7_cpu_device::drcarm7ops_e(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, UINT32 op) +{ + return false; +} + +bool arm7_cpu_device::drcarm7ops_f(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, UINT32 op) +{ + return false; +} + +/*------------------------------------------------- + generate_opcode - generate code for a specific + opcode +-------------------------------------------------*/ + +int arm7_cpu_device::generate_opcode(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) +{ + //int in_delay_slot = ((desc->flags & OPFLAG_IN_DELAY_SLOT) != 0); + UINT32 op = desc->opptr.l[0]; + UINT8 opswitch = op >> 26; + uml::code_label skip; + uml::code_label contdecode; + uml::code_label unexecuted; + + if (T_IS_SET(GET_CPSR)) + { + // "In Thumb state, bit [0] is undefined and must be ignored. Bits [31:1] contain the PC." + UML_AND(block, uml::I0, DRC_PC, ~1); + } + else + { + UML_AND(block, uml::I0, DRC_PC, ~3); + } + + UML_TEST(block, uml::mem(&COPRO_CTRL), COPRO_CTRL_MMU_EN); // test COPRO_CTRL, COPRO_CTRL_MMU_EN + UML_MOVc(block, uml::COND_NZ, uml::I2, ARM7_TLB_ABORT_P | ARM7_TLB_READ); // movnz i0, ARM7_TLB_ABORT_P | ARM7_TLB_READ + UML_CALLHc(block, uml::COND_NZ, *m_impstate.tlb_translate); // callhnz tlb_translate); + + if (T_IS_SET(GET_CPSR)) + { + //UML_CALLH(block, *m_impstate.drcthumb[(op & 0xffc0) >> 6]); // callh drcthumb[op] // TODO FIXME + return TRUE; + } + + switch (op >> INSN_COND_SHIFT) + { + case COND_EQ: + UML_TEST(block, DRC_CPSR, Z_MASK); + UML_JMPc(block, uml::COND_Z, unexecuted = compiler->labelnum++); + break; + case COND_NE: + UML_TEST(block, DRC_CPSR, Z_MASK); + UML_JMPc(block, uml::COND_NZ, unexecuted = compiler->labelnum++); + break; + case COND_CS: + UML_TEST(block, DRC_CPSR, C_MASK); + UML_JMPc(block, uml::COND_Z, unexecuted = compiler->labelnum++); + break; + case COND_CC: + UML_TEST(block, DRC_CPSR, C_MASK); + UML_JMPc(block, uml::COND_NZ, unexecuted = compiler->labelnum++); + break; + case COND_MI: + UML_TEST(block, DRC_CPSR, N_MASK); + UML_JMPc(block, uml::COND_Z, unexecuted = compiler->labelnum++); + break; + case COND_PL: + UML_TEST(block, DRC_CPSR, N_MASK); + UML_JMPc(block, uml::COND_NZ, unexecuted = compiler->labelnum++); + break; + case COND_VS: + UML_TEST(block, DRC_CPSR, V_MASK); + UML_JMPc(block, uml::COND_Z, unexecuted = compiler->labelnum++); + break; + case COND_VC: + UML_TEST(block, DRC_CPSR, V_MASK); + UML_JMPc(block, uml::COND_NZ, unexecuted = compiler->labelnum++); + break; + case COND_HI: + UML_TEST(block, DRC_CPSR, Z_MASK); + UML_JMPc(block, uml::COND_NZ, unexecuted = compiler->labelnum++); + UML_TEST(block, DRC_CPSR, C_MASK); + UML_JMPc(block, uml::COND_Z, unexecuted = compiler->labelnum++); + break; + case COND_LS: + UML_TEST(block, DRC_CPSR, Z_MASK); + UML_JMPc(block, uml::COND_NZ, contdecode = compiler->labelnum++); + UML_TEST(block, DRC_CPSR, C_MASK); + UML_JMPc(block, uml::COND_Z, contdecode); + UML_JMP(block, unexecuted); + break; + case COND_GE: + UML_TEST(block, DRC_CPSR, N_MASK); + UML_MOVc(block, uml::COND_Z, uml::I0, 0); + UML_MOVc(block, uml::COND_NZ, uml::I0, 1); + UML_TEST(block, DRC_CPSR, V_MASK); + UML_MOVc(block, uml::COND_Z, uml::I1, 0); + UML_MOVc(block, uml::COND_NZ, uml::I1, 1); + UML_CMP(block, uml::I0, uml::I1); + UML_JMPc(block, uml::COND_NE, unexecuted); + break; + case COND_LT: + UML_TEST(block, DRC_CPSR, N_MASK); + UML_MOVc(block, uml::COND_Z, uml::I0, 0); + UML_MOVc(block, uml::COND_NZ, uml::I0, 1); + UML_TEST(block, DRC_CPSR, V_MASK); + UML_MOVc(block, uml::COND_Z, uml::I1, 0); + UML_MOVc(block, uml::COND_NZ, uml::I1, 1); + UML_CMP(block, uml::I0, uml::I1); + UML_JMPc(block, uml::COND_E, unexecuted); + break; + case COND_GT: + UML_TEST(block, DRC_CPSR, Z_MASK); + UML_JMPc(block, uml::COND_NZ, unexecuted); + UML_TEST(block, DRC_CPSR, N_MASK); + UML_MOVc(block, uml::COND_Z, uml::I0, 0); + UML_MOVc(block, uml::COND_NZ, uml::I0, 1); + UML_TEST(block, DRC_CPSR, V_MASK); + UML_MOVc(block, uml::COND_Z, uml::I1, 0); + UML_MOVc(block, uml::COND_NZ, uml::I1, 1); + UML_CMP(block, uml::I0, uml::I1); + UML_JMPc(block, uml::COND_NE, unexecuted); + break; + case COND_LE: + UML_TEST(block, DRC_CPSR, N_MASK); + UML_MOVc(block, uml::COND_Z, uml::I0, 0); + UML_MOVc(block, uml::COND_NZ, uml::I0, 1); + UML_TEST(block, DRC_CPSR, V_MASK); + UML_MOVc(block, uml::COND_Z, uml::I1, 0); + UML_MOVc(block, uml::COND_NZ, uml::I1, 1); + UML_CMP(block, uml::I0, uml::I1); + UML_JMPc(block, uml::COND_NE, contdecode); + UML_TEST(block, DRC_CPSR, Z_MASK); + UML_JMPc(block, uml::COND_Z, unexecuted); + break; + case COND_NV: + UML_JMP(block, unexecuted); + break; + } + + UML_LABEL(block, contdecode); + + (this->*drcops_handler[(op & 0xF000000) >> 24])(block, compiler, desc, op); + + UML_LABEL(block, unexecuted); + UML_ADD(block, DRC_PC, DRC_PC, 4); + UML_ADD(block, MAPVAR_CYCLES, MAPVAR_CYCLES, 2); // add cycles, cycles, 2 + + UML_LABEL(block, skip); + + switch (opswitch) + { + /* ----- sub-groups ----- */ + + case 0x00: /* SPECIAL - MIPS I */ + return TRUE; + + // TODO: FINISH ME + } + + return FALSE; +} diff --git a/src/devices/cpu/arm7/arm7help.h b/src/devices/cpu/arm7/arm7help.h new file mode 100644 index 00000000000..5625318b942 --- /dev/null +++ b/src/devices/cpu/arm7/arm7help.h @@ -0,0 +1,168 @@ +// license:BSD-3-Clause +// copyright-holders:Steve Ellenoff,R. Belmont,Ryan Holtz +/* ARM7 core helper Macros / Functions */ + +/* Macros that need to be defined according to the cpu implementation specific need */ +#define ARM7REG(reg) m_r[reg] +#define ARM7_ICOUNT m_icount + + +#if 0 +#define LOG(x) osd_printf_debug x +#else +#define LOG(x) logerror x +#endif + +/*************** + * helper funcs + ***************/ + +// TODO LD: +// - SIGN_BITS_DIFFER = THUMB_SIGN_BITS_DIFFER +// - do while (0) +// - HandleALUAddFlags = HandleThumbALUAddFlags except for PC incr +// - HandleALUSubFlags = HandleThumbALUSubFlags except for PC incr + +#define IsNeg(i) ((i) >> 31) +#define IsPos(i) ((~(i)) >> 31) + +/* Set NZCV flags for ADDS / SUBS */ +#define HandleALUAddFlags(rd, rn, op2) \ + if (insn & INSN_S) \ + SET_CPSR(((GET_CPSR & ~(N_MASK | Z_MASK | V_MASK | C_MASK)) \ + | (((!SIGN_BITS_DIFFER(rn, op2)) && SIGN_BITS_DIFFER(rn, rd)) << V_BIT) \ + | (((IsNeg(rn) & IsNeg(op2)) | (IsNeg(rn) & IsPos(rd)) | (IsNeg(op2) & IsPos(rd))) ? C_MASK : 0) \ + | HandleALUNZFlags(rd))); \ + R15 += 4; + +#define HandleThumbALUAddFlags(rd, rn, op2) \ + SET_CPSR(((GET_CPSR & ~(N_MASK | Z_MASK | V_MASK | C_MASK)) \ + | (((!THUMB_SIGN_BITS_DIFFER(rn, op2)) && THUMB_SIGN_BITS_DIFFER(rn, rd)) << V_BIT) \ + | (((~(rn)) < (op2)) << C_BIT) \ + | HandleALUNZFlags(rd))); \ + R15 += 2; + +#define DRCHandleThumbALUAddFlags(rd, rn, op2) \ + UML_AND(block, DRC_CPSR, DRC_CPSR, ~(N_MASK | Z_MASK | V_MASK | C_MASK)); \ + DRCHandleALUNZFlags(rd); \ + UML_XOR(block, uml::I1, rn, ~0); \ + UML_CMP(block, uml::I1, op2); \ + UML_MOVc(block, uml::COND_B, uml::I1, C_BIT); \ + UML_MOVc(block, uml::COND_AE, uml::I1, 0); \ + UML_OR(block, uml::I0, uml::I0, uml::I1); \ + UML_XOR(block, uml::I1, rn, op2); \ + UML_XOR(block, uml::I2, rn, rd); \ + UML_AND(block, uml::I1, uml::I1, uml::I2); \ + UML_TEST(block, uml::I1, 1 << 31); \ + UML_MOVc(block, uml::COND_NZ, uml::I1, V_BIT); \ + UML_MOVc(block, uml::COND_Z, uml::I1, 0); \ + UML_OR(block, uml::I0, uml::I0, uml::I1); \ + UML_OR(block, DRC_CPSR, DRC_CPSR, uml::I0); \ + UML_ADD(block, DRC_PC, DRC_PC, 2); + +#define HandleALUSubFlags(rd, rn, op2) \ + if (insn & INSN_S) \ + SET_CPSR(((GET_CPSR & ~(N_MASK | Z_MASK | V_MASK | C_MASK)) \ + | ((SIGN_BITS_DIFFER(rn, op2) && SIGN_BITS_DIFFER(rn, rd)) << V_BIT) \ + | (((IsNeg(rn) & IsPos(op2)) | (IsNeg(rn) & IsPos(rd)) | (IsPos(op2) & IsPos(rd))) ? C_MASK : 0) \ + | HandleALUNZFlags(rd))); \ + R15 += 4; + +#define HandleThumbALUSubFlags(rd, rn, op2) \ + SET_CPSR(((GET_CPSR & ~(N_MASK | Z_MASK | V_MASK | C_MASK)) \ + | ((THUMB_SIGN_BITS_DIFFER(rn, op2) && THUMB_SIGN_BITS_DIFFER(rn, rd)) << V_BIT) \ + | (((IsNeg(rn) & IsPos(op2)) | (IsNeg(rn) & IsPos(rd)) | (IsPos(op2) & IsPos(rd))) ? C_MASK : 0) \ + | HandleALUNZFlags(rd))); \ + R15 += 2; + +#define DRCHandleThumbALUSubFlags(rd, rn, op2) \ + UML_AND(block, DRC_CPSR, DRC_CPSR, ~(N_MASK | Z_MASK | V_MASK | C_MASK)); \ + DRCHandleALUNZFlags(rd); \ + UML_XOR(block, uml::I1, rn, op2); \ + UML_XOR(block, uml::I2, rn, rd); \ + UML_AND(block, uml::I1, uml::I1, uml::I2); \ + UML_TEST(block, uml::I1, 1 << 31); \ + UML_MOVc(block, uml::COND_NZ, uml::I1, V_BIT); \ + UML_MOVc(block, uml::COND_Z, uml::I1, 0); \ + UML_OR(block, uml::I0, uml::I0, uml::I1); \ + UML_OR(block, DRC_CPSR, DRC_CPSR, uml::I0); \ + UML_AND(block, uml::I0, rd, 1 << 31); \ + UML_AND(block, uml::I1, op2, 1 << 31); \ + UML_AND(block, uml::I2, rn, 1 << 31); \ + UML_XOR(block, uml::I2, uml::I2, ~0); \ + UML_AND(block, uml::I1, uml::I1, uml::I2); \ + UML_AND(block, uml::I2, uml::I2, uml::I0); \ + UML_OR(block, uml::I1, uml::I1, uml::I2); \ + UML_AND(block, uml::I2, op2, 1 << 31); \ + UML_AND(block, uml::I2, uml::I2, uml::I0); \ + UML_OR(block, uml::I1, uml::I1, uml::I2); \ + UML_TEST(block, uml::I1, 1 << 31); \ + UML_MOVc(block, uml::COND_NZ, uml::I0, C_MASK); \ + UML_MOVc(block, uml::COND_Z, uml::I0, 0); \ + UML_OR(block, DRC_CPSR, DRC_CPSR, uml::I0); \ + UML_ADD(block, DRC_PC, DRC_PC, 2); + +/* Set NZC flags for logical operations. */ + +// This macro (which I didn't write) - doesn't make it obvious that the SIGN BIT = 31, just as the N Bit does, +// therefore, N is set by default +#define HandleALUNZFlags(rd) \ + (((rd) & SIGN_BIT) | ((!(rd)) << Z_BIT)) + +#define DRCHandleALUNZFlags(rd) \ + UML_AND(block, uml::I0, rd, SIGN_BIT); \ + UML_CMP(block, rd, 0); \ + UML_MOVc(block, uml::COND_E, uml::I1, 1); \ + UML_MOVc(block, uml::COND_NE, uml::I1, 0); \ + UML_ROLINS(block, uml::I0, uml::I1, Z_BIT, 1 << Z_BIT); + +// Long ALU Functions use bit 63 +#define HandleLongALUNZFlags(rd) \ + ((((rd) & ((UINT64)1 << 63)) >> 32) | ((!(rd)) << Z_BIT)) + +#define HandleALULogicalFlags(rd, sc) \ + if (insn & INSN_S) \ + SET_CPSR(((GET_CPSR & ~(N_MASK | Z_MASK | C_MASK)) \ + | HandleALUNZFlags(rd) \ + | (((sc) != 0) << C_BIT))); \ + R15 += 4; + +#define DRC_RD uml::mem(&GET_REGISTER(rd)) +#define DRC_RS uml::mem(&GET_REGISTER(rs)) +#define DRC_CPSR uml::mem(&GET_CPSR) +#define DRC_PC uml::mem(&R15) +#define DRC_REG(i) uml::mem(&m_r[(i)]) + +#define DRCHandleALULogicalFlags(rd, sc) \ + if (insn & INSN_S) \ + { \ + UML_AND(block, DRC_CPSR, DRC_CPSR, ~(N_MASK | Z_MASK | C_MASK); \ + DRCHandleALUNZFlags(rd); \ + UML_TEST(block, sc, ~0); \ + UML_MOVc(block, uml::COND_Z, uml::I1, C_BIT); \ + UML_MOVc(block, uml::COND_NZ, uml::I1, 0); \ + UML_OR(block, uml::I0, uml::I0, uml::I1); \ + UML_OR(block, DRC_CPSR, DRC_CPSR, uml::I0); \ + } \ + UML_ADD(block, DRC_PC, DRC_PC, 4); + + +// used to be functions, but no longer a need, so we'll use define for better speed. +#define GetRegister(rIndex) m_r[sRegisterTable[GET_MODE][rIndex]] +#define SetRegister(rIndex, value) m_r[sRegisterTable[GET_MODE][rIndex]] = value + +#define GetModeRegister(mode, rIndex) m_r[sRegisterTable[mode][rIndex]] +#define SetModeRegister(mode, rIndex, value) m_r[sRegisterTable[mode][rIndex]] = value + + +/* Macros that can be re-defined for custom cpu implementations - The core expects these to be defined */ +/* In this case, we are using the default arm7 handlers (supplied by the core) + - but simply changes these and define your own if needed for cpu implementation specific needs */ +#define READ8(addr) arm7_cpu_read8(addr) +#define WRITE8(addr,data) arm7_cpu_write8(addr,data) +#define READ16(addr) arm7_cpu_read16(addr) +#define WRITE16(addr,data) arm7_cpu_write16(addr,data) +#define READ32(addr) arm7_cpu_read32(addr) +#define WRITE32(addr,data) arm7_cpu_write32(addr,data) +#define PTR_READ32 &arm7_cpu_read32 +#define PTR_WRITE32 &arm7_cpu_write32 diff --git a/src/devices/cpu/arm7/arm7ops.c b/src/devices/cpu/arm7/arm7ops.c new file mode 100644 index 00000000000..9b96ca9054c --- /dev/null +++ b/src/devices/cpu/arm7/arm7ops.c @@ -0,0 +1,1851 @@ +// license:BSD-3-Clause +// copyright-holders:Steve Ellenoff,R. Belmont,Ryan Holtz +#include "emu.h" +#include "arm7.h" +#include "arm7core.h" +#include "arm7help.h" + +INT64 arm7_cpu_device::saturate_qbit_overflow(INT64 res) +{ + if (res > 2147483647) // INT32_MAX + { // overflow high? saturate and set Q + res = 2147483647; + SET_CPSR(GET_CPSR | Q_MASK); + } + else if (res < (-2147483647-1)) // INT32_MIN + { // overflow low? saturate and set Q + res = (-2147483647-1); + SET_CPSR(GET_CPSR | Q_MASK); + } + + return res; +} + + +void arm7_cpu_device::SwitchMode(UINT32 cpsr_mode_val) +{ + UINT32 cspr = m_r[eCPSR] & ~MODE_FLAG; + set_cpsr(cspr | cpsr_mode_val); +} + + +/* Decodes an Op2-style shifted-register form. If @carry@ is non-zero the + * shifter carry output will manifest itself as @*carry == 0@ for carry clear + * and @*carry != 0@ for carry set. + + SJE: Rules: + IF RC = 256, Result = no shift. + LSL 0 = Result = RM, Carry = Old Contents of CPSR C Bit + LSL(0,31) = Result shifted, least significant bit is in carry out + LSL 32 = Result of 0, Carry = Bit 0 of RM + LSL >32 = Result of 0, Carry out 0 + LSR 0 = LSR 32 (see below) + LSR 32 = Result of 0, Carry = Bit 31 of RM + LSR >32 = Result of 0, Carry out 0 + ASR >=32 = ENTIRE Result = bit 31 of RM + ROR 32 = Result = RM, Carry = Bit 31 of RM + ROR >32 = Same result as ROR n-32 until amount in range of 1-32 then follow rules +*/ + +UINT32 arm7_cpu_device::decodeShift(UINT32 insn, UINT32 *pCarry) +{ + UINT32 k = (insn & INSN_OP2_SHIFT) >> INSN_OP2_SHIFT_SHIFT; // Bits 11-7 + UINT32 rm = GET_REGISTER(insn & INSN_OP2_RM); + UINT32 t = (insn & INSN_OP2_SHIFT_TYPE) >> INSN_OP2_SHIFT_TYPE_SHIFT; + + if ((insn & INSN_OP2_RM) == 0xf) { + // "If a register is used to specify the shift amount the PC will be 12 bytes ahead." (instead of 8) + rm += t & 1 ? 12 : 8; + } + + /* All shift types ending in 1 are Rk, not #k */ + if (t & 1) + { +// LOG(("%08x: RegShift %02x %02x\n", R15, k >> 1, GET_REGISTER(k >> 1))); +#if ARM7_DEBUG_CORE + if ((insn & 0x80) == 0x80) + LOG(("%08x: RegShift ERROR (p36)\n", R15)); +#endif + + // see p35 for check on this + //k = GET_REGISTER(k >> 1) & 0x1f; + + // Keep only the bottom 8 bits for a Register Shift + k = GET_REGISTER(k >> 1) & 0xff; + + if (k == 0) /* Register shift by 0 is a no-op */ + { +// LOG(("%08x: NO-OP Regshift\n", R15)); + /* TODO this is wrong for at least ROR by reg with lower + * 5 bits 0 but lower 8 bits non zero */ + if (pCarry) + *pCarry = GET_CPSR & C_MASK; + return rm; + } + } + /* Decode the shift type and perform the shift */ + switch (t >> 1) + { + case 0: /* LSL */ + // LSL 32 = Result of 0, Carry = Bit 0 of RM + // LSL >32 = Result of 0, Carry out 0 + if (k >= 32) + { + if (pCarry) + *pCarry = (k == 32) ? rm & 1 : 0; + return 0; + } + else + { + if (pCarry) + { + // LSL 0 = Result = RM, Carry = Old Contents of CPSR C Bit + // LSL (0,31) = Result shifted, least significant bit is in carry out + *pCarry = k ? (rm & (1 << (32 - k))) : (GET_CPSR & C_MASK); + } + return k ? LSL(rm, k) : rm; + } + + case 1: /* LSR */ + if (k == 0 || k == 32) + { + if (pCarry) + *pCarry = rm & SIGN_BIT; + return 0; + } + else if (k > 32) + { + if (pCarry) + *pCarry = 0; + return 0; + } + else + { + if (pCarry) + *pCarry = (rm & (1 << (k - 1))); + return LSR(rm, k); + } + + case 2: /* ASR */ + if (k == 0 || k > 32) + k = 32; + + if (pCarry) + *pCarry = (rm & (1 << (k - 1))); + if (k >= 32) + return rm & SIGN_BIT ? 0xffffffffu : 0; + else + { + if (rm & SIGN_BIT) + return LSR(rm, k) | (0xffffffffu << (32 - k)); + else + return LSR(rm, k); + } + + case 3: /* ROR and RRX */ + if (k) + { + while (k > 32) + k -= 32; + if (pCarry) + *pCarry = rm & (1 << (k - 1)); + return ROR(rm, k); + } + else + { + /* RRX */ + if (pCarry) + *pCarry = (rm & 1); + return LSR(rm, 1) | ((GET_CPSR & C_MASK) << 2); + } + } + + LOG(("%08x: Decodeshift error\n", R15)); + return 0; +} /* decodeShift */ + + +int arm7_cpu_device::loadInc(UINT32 pat, UINT32 rbv, UINT32 s, int mode) +{ + int i, result; + UINT32 data; + + result = 0; + rbv &= ~3; + for (i = 0; i < 16; i++) + { + if ((pat >> i) & 1) + { + if (m_pendingAbtD == 0) // "Overwriting of registers stops when the abort happens." + { + data = READ32(rbv += 4); + if (i == 15) { + if (s) /* Pull full contents from stack */ + SET_MODE_REGISTER(mode, 15, data); + else /* Pull only address, preserve mode & status flags */ + if (MODE32) + SET_MODE_REGISTER(mode, 15, data); + else + { + SET_MODE_REGISTER(mode, 15, (GET_MODE_REGISTER(mode, 15) & ~0x03FFFFFC) | (data & 0x03FFFFFC)); + } + } else + SET_MODE_REGISTER(mode, i, data); + } + result++; + } + } + return result; +} + + +int arm7_cpu_device::loadDec(UINT32 pat, UINT32 rbv, UINT32 s, int mode) +{ + int i, result; + UINT32 data; + + result = 0; + rbv &= ~3; + for (i = 15; i >= 0; i--) + { + if ((pat >> i) & 1) + { + if (m_pendingAbtD == 0) // "Overwriting of registers stops when the abort happens." + { + data = READ32(rbv -= 4); + if (i == 15) { + if (s) /* Pull full contents from stack */ + SET_MODE_REGISTER(mode, 15, data); + else /* Pull only address, preserve mode & status flags */ + if (MODE32) + SET_MODE_REGISTER(mode, 15, data); + else + { + SET_MODE_REGISTER(mode, 15, (GET_MODE_REGISTER(mode, 15) & ~0x03FFFFFC) | (data & 0x03FFFFFC)); + } + } + else + SET_MODE_REGISTER(mode, i, data); + } + result++; + } + } + return result; +} + + +int arm7_cpu_device::storeInc(UINT32 pat, UINT32 rbv, int mode) +{ + int i, result; + + result = 0; + for (i = 0; i < 16; i++) + { + if ((pat >> i) & 1) + { +#if ARM7_DEBUG_CORE + if (i == 15) /* R15 is plus 12 from address of STM */ + LOG(("%08x: StoreInc on R15\n", R15)); +#endif + WRITE32(rbv += 4, GET_MODE_REGISTER(mode, i)); + result++; + } + } + return result; +} /* storeInc */ + + +int arm7_cpu_device::storeDec(UINT32 pat, UINT32 rbv, int mode) +{ + int i, result = 0, cnt; + + // pre-count the # of registers being stored + for (i = 15; i >= 0; i--) + { + if ((pat >> i) & 1) + { + result++; + + // starting address + rbv -= 4; + } + } + + cnt = 0; + for (i = 0; i <= 15; i++) + { + if ((pat >> i) & 1) + { +#if ARM7_DEBUG_CORE + if (i == 15) /* R15 is plus 12 from address of STM */ + LOG(("%08x: StoreDec on R15\n", R15)); +#endif + WRITE32(rbv + (cnt * 4), GET_MODE_REGISTER(mode, i)); + cnt++; + } + } + return result; +} /* storeDec */ + + +/*************************************************************************** + * OPCODE HANDLING + ***************************************************************************/ + +// Co-Processor Data Operation +void arm7_cpu_device::HandleCoProcDO(UINT32 insn) +{ + // This instruction simply instructs the co-processor to do something, no data is returned to ARM7 core + arm7_do_callback(*m_program, insn, 0, 0); // simply pass entire opcode to callback - since data format is actually dependent on co-proc implementation +} + +// Co-Processor Register Transfer - To/From Arm to Co-Proc +void arm7_cpu_device::HandleCoProcRT(UINT32 insn) +{ + /* xxxx 1110 oooL nnnn dddd cccc ppp1 mmmm */ + + // Load (MRC) data from Co-Proc to ARM7 register + if (insn & 0x00100000) // Bit 20 = Load or Store + { + UINT32 res = arm7_rt_r_callback(*m_program, insn, 0); // RT Read handler must parse opcode & return appropriate result + if (m_pendingUnd == 0) + { + SET_REGISTER((insn >> 12) & 0xf, res); + } + } + // Store (MCR) data from ARM7 to Co-Proc register + else + { + arm7_rt_w_callback(*m_program, insn, GET_REGISTER((insn >> 12) & 0xf), 0); + } +} + +/* Data Transfer - To/From Arm to Co-Proc + Loading or Storing, the co-proc function is responsible to read/write from the base register supplied + offset + 8 bit immediate value Base Offset address is << 2 to get the actual # + + issues - #1 - the co-proc function, needs direct access to memory reads or writes (ie, so we must send a pointer to a func) + - #2 - the co-proc may adjust the base address (especially if it reads more than 1 word), so a pointer to the register must be used + but the old value of the register must be restored if write back is not set.. + - #3 - when post incrementing is used, it's up to the co-proc func. to add the offset, since the transfer + address supplied in that case, is simply the base. I suppose this is irrelevant if write back not set + but if co-proc reads multiple address, it must handle the offset adjustment itself. +*/ +// todo: test with valid instructions +void arm7_cpu_device::HandleCoProcDT(UINT32 insn) +{ + UINT32 rn = (insn >> 16) & 0xf; + UINT32 rnv = GET_REGISTER(rn); // Get Address Value stored from Rn + UINT32 ornv = rnv; // Keep value of Rn + UINT32 off = (insn & 0xff) << 2; // Offset is << 2 according to manual + UINT32 *prn = &ARM7REG(rn); // Pointer to our register, so it can be changed in the callback + +#if ARM7_DEBUG_CORE + if (((insn >> 16) & 0xf) == 15 && (insn & 0x200000)) + LOG(("%08x: Illegal use of R15 as base for write back value!\n", R15)); +#endif + + // Pre-Increment base address (IF POST INCREMENT - CALL BACK FUNCTION MUST DO IT) + if ((insn & 0x1000000) && off) + { + // Up - Down bit + if (insn & 0x800000) + rnv += off; + else + rnv -= off; + } + + // Load (LDC) data from ARM7 memory to Co-Proc memory + if (insn & 0x00100000) + { + arm7_dt_r_callback(insn, prn); + } + // Store (STC) data from Co-Proc to ARM7 memory + else + { + arm7_dt_w_callback(insn, prn); + } + + if (m_pendingUnd != 0) return; + + // If writeback not used - ensure the original value of RN is restored in case co-proc callback changed value + if ((insn & 0x200000) == 0) + SET_REGISTER(rn, ornv); +} + +void arm7_cpu_device::HandleBranch(UINT32 insn) +{ + UINT32 off = (insn & INSN_BRANCH) << 2; + + /* Save PC into LR if this is a branch with link */ + if (insn & INSN_BL) + { + SET_REGISTER(14, R15 + 4); + } + + /* Sign-extend the 24-bit offset in our calculations */ + if (off & 0x2000000u) + { + if (MODE32) + R15 -= ((~(off | 0xfc000000u)) + 1) - 8; + else + R15 = ((R15 - (((~(off | 0xfc000000u)) + 1) - 8)) & 0x03FFFFFC) | (R15 & ~0x03FFFFFC); + } + else + { + if (MODE32) + R15 += off + 8; + else + R15 = ((R15 + (off + 8)) & 0x03FFFFFC) | (R15 & ~0x03FFFFFC); + } +} + +void arm7_cpu_device::HandleMemSingle(UINT32 insn) +{ + UINT32 rn, rnv, off, rd, rnv_old = 0; + + /* Fetch the offset */ + if (insn & INSN_I) + { + /* Register Shift */ + off = decodeShift(insn, NULL); + } + else + { + /* Immediate Value */ + off = insn & INSN_SDT_IMM; + } + + /* Calculate Rn, accounting for PC */ + rn = (insn & INSN_RN) >> INSN_RN_SHIFT; + + if (insn & INSN_SDT_P) + { + /* Pre-indexed addressing */ + if (insn & INSN_SDT_U) + { + if ((MODE32) || (rn != eR15)) + rnv = (GET_REGISTER(rn) + off); + else + rnv = (GET_PC + off); + } + else + { + if ((MODE32) || (rn != eR15)) + rnv = (GET_REGISTER(rn) - off); + else + rnv = (GET_PC - off); + } + + if (insn & INSN_SDT_W) + { + rnv_old = GET_REGISTER(rn); + SET_REGISTER(rn, rnv); + + // check writeback??? + } + else if (rn == eR15) + { + rnv = rnv + 8; + } + } + else + { + /* Post-indexed addressing */ + if (rn == eR15) + { + if (MODE32) + rnv = R15 + 8; + else + rnv = GET_PC + 8; + } + else + { + rnv = GET_REGISTER(rn); + } + } + + /* Do the transfer */ + rd = (insn & INSN_RD) >> INSN_RD_SHIFT; + if (insn & INSN_SDT_L) + { + /* Load */ + if (insn & INSN_SDT_B) + { + UINT32 data = READ8(rnv); + if (m_pendingAbtD == 0) + { + SET_REGISTER(rd, data); + } + } + else + { + UINT32 data = READ32(rnv); + if (m_pendingAbtD == 0) + { + if (rd == eR15) + { + if (MODE32) + R15 = data - 4; + else + R15 = (R15 & ~0x03FFFFFC) /* N Z C V I F M1 M0 */ | ((data - 4) & 0x03FFFFFC); + // LDR, PC takes 2S + 2N + 1I (5 total cycles) + ARM7_ICOUNT -= 2; + } + else + { + SET_REGISTER(rd, data); + } + } + } + } + else + { + /* Store */ + if (insn & INSN_SDT_B) + { +#if ARM7_DEBUG_CORE + if (rd == eR15) + LOG(("Wrote R15 in byte mode\n")); +#endif + + WRITE8(rnv, (UINT8) GET_REGISTER(rd) & 0xffu); + } + else + { +#if ARM7_DEBUG_CORE + if (rd == eR15) + LOG(("Wrote R15 in 32bit mode\n")); +#endif + + //WRITE32(rnv, rd == eR15 ? R15 + 8 : GET_REGISTER(rd)); + WRITE32(rnv, rd == eR15 ? R15 + 8 + 4 : GET_REGISTER(rd)); // manual says STR rd = PC, +12 + } + // Store takes only 2 N Cycles, so add + 1 + ARM7_ICOUNT += 1; + } + + if (m_pendingAbtD != 0) + { + if ((insn & INSN_SDT_P) && (insn & INSN_SDT_W)) + { + SET_REGISTER(rn, rnv_old); + } + } + else + { + /* Do post-indexing writeback */ + if (!(insn & INSN_SDT_P)/* && (insn & INSN_SDT_W)*/) + { + if (insn & INSN_SDT_U) + { + /* Writeback is applied in pipeline, before value is read from mem, + so writeback is effectively ignored */ + if (rd == rn) { + SET_REGISTER(rn, GET_REGISTER(rd)); + // todo: check for offs... ? + } + else { + if ((insn & INSN_SDT_W) != 0) + LOG(("%08x: RegisterWritebackIncrement %d %d %d\n", R15, (insn & INSN_SDT_P) != 0, (insn & INSN_SDT_W) != 0, (insn & INSN_SDT_U) != 0)); + + SET_REGISTER(rn, (rnv + off)); + } + } + else + { + /* Writeback is applied in pipeline, before value is read from mem, + so writeback is effectively ignored */ + if (rd == rn) { + SET_REGISTER(rn, GET_REGISTER(rd)); + } + else { + SET_REGISTER(rn, (rnv - off)); + + if ((insn & INSN_SDT_W) != 0) + LOG(("%08x: RegisterWritebackDecrement %d %d %d\n", R15, (insn & INSN_SDT_P) != 0, (insn & INSN_SDT_W) != 0, (insn & INSN_SDT_U) != 0)); + } + } + } + + } + +// ARM7_CHECKIRQ + +} /* HandleMemSingle */ + +void arm7_cpu_device::HandleHalfWordDT(UINT32 insn) +{ + UINT32 rn, rnv, off, rd, rnv_old = 0; + + // Immediate or Register Offset? + if (insn & 0x400000) { // Bit 22 - 1 = immediate, 0 = register + // imm. value in high nibble (bits 8-11) and lo nibble (bit 0-3) + off = (((insn >> 8) & 0x0f) << 4) | (insn & 0x0f); + } + else { + // register + off = GET_REGISTER(insn & 0x0f); + } + + /* Calculate Rn, accounting for PC */ + rn = (insn & INSN_RN) >> INSN_RN_SHIFT; + + if (insn & INSN_SDT_P) + { + /* Pre-indexed addressing */ + if (insn & INSN_SDT_U) + { + rnv = (GET_REGISTER(rn) + off); + } + else + { + rnv = (GET_REGISTER(rn) - off); + } + + if (insn & INSN_SDT_W) + { + rnv_old = GET_REGISTER(rn); + SET_REGISTER(rn, rnv); + + // check writeback??? + } + else if (rn == eR15) + { + rnv = (rnv) + 8; + } + } + else + { + /* Post-indexed addressing */ + if (rn == eR15) + { + rnv = R15 + 8; + } + else + { + rnv = GET_REGISTER(rn); + } + } + + /* Do the transfer */ + rd = (insn & INSN_RD) >> INSN_RD_SHIFT; + + /* Load */ + if (insn & INSN_SDT_L) + { + // Signed? + if (insn & 0x40) + { + UINT32 newval = 0; + + // Signed Half Word? + if (insn & 0x20) { + UINT16 signbyte, databyte; + databyte = READ16(rnv) & 0xFFFF; + signbyte = (databyte & 0x8000) ? 0xffff : 0; + newval = (UINT32)(signbyte << 16)|databyte; + } + // Signed Byte + else { + UINT8 databyte; + UINT32 signbyte; + databyte = READ8(rnv) & 0xff; + signbyte = (databyte & 0x80) ? 0xffffff : 0; + newval = (UINT32)(signbyte << 8)|databyte; + } + + if (m_pendingAbtD == 0) + { + // PC? + if (rd == eR15) + { + R15 = newval + 8; + // LDR(H,SH,SB) PC takes 2S + 2N + 1I (5 total cycles) + ARM7_ICOUNT -= 2; + + } + else + { + SET_REGISTER(rd, newval); + R15 += 4; + } + + } + else + { + R15 += 4; + } + + } + // Unsigned Half Word + else + { + UINT32 newval = READ16(rnv); + + if (m_pendingAbtD == 0) + { + if (rd == eR15) + { + R15 = newval + 8; + // extra cycles for LDR(H,SH,SB) PC (5 total cycles) + ARM7_ICOUNT -= 2; + } + else + { + SET_REGISTER(rd, newval); + R15 += 4; + } + + } + else + { + R15 += 4; + } + + } + + + } + /* Store or ARMv5+ dword insns */ + else + { + if ((insn & 0x60) == 0x40) // LDRD + { + SET_REGISTER(rd, READ32(rnv)); + SET_REGISTER(rd+1, READ32(rnv+4)); + R15 += 4; + } + else if ((insn & 0x60) == 0x60) // STRD + { + WRITE32(rnv, GET_REGISTER(rd)); + WRITE32(rnv+4, GET_REGISTER(rd+1)); + R15 += 4; + } + else + { + // WRITE16(rnv, rd == eR15 ? R15 + 8 : GET_REGISTER(rd)); + WRITE16(rnv, rd == eR15 ? R15 + 8 + 4 : GET_REGISTER(rd)); // manual says STR RD=PC, +12 of address + +// if R15 is not increased then e.g. "STRH R10, [R15,#$10]" will be executed over and over again +#if 0 + if (rn != eR15) +#endif + R15 += 4; + + // STRH takes 2 cycles, so we add + 1 + ARM7_ICOUNT += 1; + } + } + + if (m_pendingAbtD != 0) + { + if ((insn & INSN_SDT_P) && (insn & INSN_SDT_W)) + { + SET_REGISTER(rn, rnv_old); + } + } + else + { + // SJE: No idea if this writeback code works or makes sense here.. + + /* Do post-indexing writeback */ + if (!(insn & INSN_SDT_P)/* && (insn & INSN_SDT_W)*/) + { + if (insn & INSN_SDT_U) + { + /* Writeback is applied in pipeline, before value is read from mem, + so writeback is effectively ignored */ + if (rd == rn) { + SET_REGISTER(rn, GET_REGISTER(rd)); + // todo: check for offs... ? + } + else { + if ((insn & INSN_SDT_W) != 0) + LOG(("%08x: RegisterWritebackIncrement %d %d %d\n", R15, (insn & INSN_SDT_P) != 0, (insn & INSN_SDT_W) != 0, (insn & INSN_SDT_U) != 0)); + + SET_REGISTER(rn, (rnv + off)); + } + } + else + { + /* Writeback is applied in pipeline, before value is read from mem, + so writeback is effectively ignored */ + if (rd == rn) { + SET_REGISTER(rn, GET_REGISTER(rd)); + } + else { + SET_REGISTER(rn, (rnv - off)); + + if ((insn & INSN_SDT_W) != 0) + LOG(("%08x: RegisterWritebackDecrement %d %d %d\n", R15, (insn & INSN_SDT_P) != 0, (insn & INSN_SDT_W) != 0, (insn & INSN_SDT_U) != 0)); + } + } + } + + } + +} + +void arm7_cpu_device::HandleSwap(UINT32 insn) +{ + UINT32 rn, rm, rd, tmp; + + rn = GET_REGISTER((insn >> 16) & 0xf); // reg. w/read address + rm = GET_REGISTER(insn & 0xf); // reg. w/write address + rd = (insn >> 12) & 0xf; // dest reg + +#if ARM7_DEBUG_CORE + if (rn == 15 || rm == 15 || rd == 15) + LOG(("%08x: Illegal use of R15 in Swap Instruction\n", R15)); +#endif + + // can be byte or word + if (insn & 0x400000) + { + tmp = READ8(rn); + WRITE8(rn, rm); + SET_REGISTER(rd, tmp); + } + else + { + tmp = READ32(rn); + WRITE32(rn, rm); + SET_REGISTER(rd, tmp); + } + + R15 += 4; + // Instruction takes 1S+2N+1I cycles - so we subtract one more.. + ARM7_ICOUNT -= 1; +} + +void arm7_cpu_device::HandlePSRTransfer(UINT32 insn) +{ + int reg = (insn & 0x400000) ? SPSR : eCPSR; // Either CPSR or SPSR + UINT32 newval, val = 0; + int oldmode = GET_CPSR & MODE_FLAG; + + // get old value of CPSR/SPSR + newval = GET_REGISTER(reg); + + // MSR (bit 21 set) - Copy value to CPSR/SPSR + if ((insn & 0x00200000)) + { + // Immediate Value? + if (insn & INSN_I) { + // Value can be specified for a Right Rotate, 2x the value specified. + int by = (insn & INSN_OP2_ROTATE) >> INSN_OP2_ROTATE_SHIFT; + if (by) + val = ROR(insn & INSN_OP2_IMM, by << 1); + else + val = insn & INSN_OP2_IMM; + } + // Value from Register + else + { + val = GET_REGISTER(insn & 0x0f); + } + + // apply field code bits + if (reg == eCPSR) + { + if (oldmode != eARM7_MODE_USER) + { + if (insn & 0x00010000) + { + newval = (newval & 0xffffff00) | (val & 0x000000ff); + } + if (insn & 0x00020000) + { + newval = (newval & 0xffff00ff) | (val & 0x0000ff00); + } + if (insn & 0x00040000) + { + newval = (newval & 0xff00ffff) | (val & 0x00ff0000); + } + } + + // status flags can be modified regardless of mode + if (insn & 0x00080000) + { + // TODO for non ARMv5E mask should be 0xf0000000 (ie mask Q bit) + newval = (newval & 0x00ffffff) | (val & 0xf8000000); + } + } + else // SPSR has stricter requirements + { + if (((GET_CPSR & 0x1f) > 0x10) && ((GET_CPSR & 0x1f) < 0x1f)) + { + if (insn & 0x00010000) + { + newval = (newval & 0xffffff00) | (val & 0xff); + } + if (insn & 0x00020000) + { + newval = (newval & 0xffff00ff) | (val & 0xff00); + } + if (insn & 0x00040000) + { + newval = (newval & 0xff00ffff) | (val & 0xff0000); + } + if (insn & 0x00080000) + { + // TODO for non ARMv5E mask should be 0xf0000000 (ie mask Q bit) + newval = (newval & 0x00ffffff) | (val & 0xf8000000); + } + } + } + +#if 0 + // force valid mode + newval |= 0x10; +#endif + + // Update the Register + if (reg == eCPSR) + SET_CPSR(newval); + else + SET_REGISTER(reg, newval); + + // Switch to new mode if changed + if ((newval & MODE_FLAG) != oldmode) + SwitchMode(GET_MODE); + + } + // MRS (bit 21 clear) - Copy CPSR or SPSR to specified Register + else + { + SET_REGISTER((insn >> 12)& 0x0f, GET_REGISTER(reg)); + } +} + +void arm7_cpu_device::HandleALU(UINT32 insn) +{ + UINT32 op2, sc = 0, rd, rn, opcode; + UINT32 by, rdn; + + // Normal Data Processing : 1S + // Data Processing with register specified shift : 1S + 1I + // Data Processing with PC written : 2S + 1N + // Data Processing with register specified shift and PC written : 2S + 1N + 1I + + opcode = (insn & INSN_OPCODE) >> INSN_OPCODE_SHIFT; + + rd = 0; + rn = 0; + + /* --------------*/ + /* Construct Op2 */ + /* --------------*/ + + /* Immediate constant */ + if (insn & INSN_I) + { + by = (insn & INSN_OP2_ROTATE) >> INSN_OP2_ROTATE_SHIFT; + if (by) + { + op2 = ROR(insn & INSN_OP2_IMM, by << 1); + sc = op2 & SIGN_BIT; + } + else + { + op2 = insn & INSN_OP2; // SJE: Shouldn't this be INSN_OP2_IMM? + sc = GET_CPSR & C_MASK; + } + } + /* Op2 = Register Value */ + else + { + op2 = decodeShift(insn, (insn & INSN_S) ? &sc : NULL); + + // LD TODO sc will always be 0 if this applies + if (!(insn & INSN_S)) + sc = 0; + + // extra cycle (register specified shift) + ARM7_ICOUNT -= 1; + } + + // LD TODO this comment is wrong + /* Calculate Rn to account for pipelining */ + if ((opcode & 0xd) != 0xd) /* No Rn in MOV */ + { + if ((rn = (insn & INSN_RN) >> INSN_RN_SHIFT) == eR15) + { +#if ARM7_DEBUG_CORE + LOG(("%08x: Pipelined R15 (Shift %d)\n", R15, (insn & INSN_I ? 8 : insn & 0x10u ? 12 : 12))); +#endif + if (MODE32) + rn = R15 + 8; + else + rn = GET_PC + 8; + } + else + { + rn = GET_REGISTER(rn); + } + } + + /* Perform the operation */ + + switch (opcode) + { + /* Arithmetic operations */ + case OPCODE_SBC: + rd = (rn - op2 - (GET_CPSR & C_MASK ? 0 : 1)); + HandleALUSubFlags(rd, rn, op2); + break; + case OPCODE_CMP: + case OPCODE_SUB: + rd = (rn - op2); + HandleALUSubFlags(rd, rn, op2); + break; + case OPCODE_RSC: + rd = (op2 - rn - (GET_CPSR & C_MASK ? 0 : 1)); + HandleALUSubFlags(rd, op2, rn); + break; + case OPCODE_RSB: + rd = (op2 - rn); + HandleALUSubFlags(rd, op2, rn); + break; + case OPCODE_ADC: + rd = (rn + op2 + ((GET_CPSR & C_MASK) >> C_BIT)); + HandleALUAddFlags(rd, rn, op2); + break; + case OPCODE_CMN: + case OPCODE_ADD: + rd = (rn + op2); + HandleALUAddFlags(rd, rn, op2); + break; + + /* Logical operations */ + case OPCODE_AND: + case OPCODE_TST: + rd = rn & op2; + HandleALULogicalFlags(rd, sc); + break; + case OPCODE_BIC: + rd = rn & ~op2; + HandleALULogicalFlags(rd, sc); + break; + case OPCODE_TEQ: + case OPCODE_EOR: + rd = rn ^ op2; + HandleALULogicalFlags(rd, sc); + break; + case OPCODE_ORR: + rd = rn | op2; + HandleALULogicalFlags(rd, sc); + break; + case OPCODE_MOV: + rd = op2; + HandleALULogicalFlags(rd, sc); + break; + case OPCODE_MVN: + rd = (~op2); + HandleALULogicalFlags(rd, sc); + break; + } + + /* Put the result in its register if not one of the test only opcodes (TST,TEQ,CMP,CMN) */ + rdn = (insn & INSN_RD) >> INSN_RD_SHIFT; + if ((opcode & 0xc) != 0x8) + { + // If Rd = R15, but S Flag not set, Result is placed in R15, but CPSR is not affected (page 44) + if (rdn == eR15 && !(insn & INSN_S)) + { + if (MODE32) + { + R15 = rd; + } + else + { + R15 = (R15 & ~0x03FFFFFC) | (rd & 0x03FFFFFC); + } + // extra cycles (PC written) + ARM7_ICOUNT -= 2; + } + else + { + // Rd = 15 and S Flag IS set, Result is placed in R15, and current mode SPSR moved to CPSR + if (rdn == eR15) { + if (MODE32) + { + // When Rd is R15 and the S flag is set the result of the operation is placed in R15 and the SPSR corresponding to + // the current mode is moved to the CPSR. This allows state changes which automatically restore both PC and + // CPSR. --> This form of instruction should not be used in User mode. <-- + + if (GET_MODE != eARM7_MODE_USER) + { + // Update CPSR from SPSR + SET_CPSR(GET_REGISTER(SPSR)); + SwitchMode(GET_MODE); + } + + R15 = rd; + + } + else + { + UINT32 temp; + R15 = rd; //(R15 & 0x03FFFFFC) | (rd & 0xFC000003); + temp = (GET_CPSR & 0x0FFFFF20) | (rd & 0xF0000000) /* N Z C V */ | ((rd & 0x0C000000) >> (26 - 6)) /* I F */ | (rd & 0x00000003) /* M1 M0 */; + SET_CPSR( temp); + SwitchMode( temp & 3); + } + + // extra cycles (PC written) + ARM7_ICOUNT -= 2; + + /* IRQ masks may have changed in this instruction */ +// ARM7_CHECKIRQ; + } + else + /* S Flag is set - Write results to register & update CPSR (which was already handled using HandleALU flag macros) */ + SET_REGISTER(rdn, rd); + } + } + // SJE: Don't think this applies any more.. (see page 44 at bottom) + /* TST & TEQ can affect R15 (the condition code register) with the S bit set */ + else if (rdn == eR15) + { + if (insn & INSN_S) { +#if ARM7_DEBUG_CORE + LOG(("%08x: TST class on R15 s bit set\n", R15)); +#endif + if (MODE32) + R15 = rd; + else + { + UINT32 temp; + R15 = (R15 & 0x03FFFFFC) | (rd & ~0x03FFFFFC); + temp = (GET_CPSR & 0x0FFFFF20) | (rd & 0xF0000000) /* N Z C V */ | ((rd & 0x0C000000) >> (26 - 6)) /* I F */ | (rd & 0x00000003) /* M1 M0 */; + SET_CPSR( temp); + SwitchMode( temp & 3); + } + + /* IRQ masks may have changed in this instruction */ +// ARM7_CHECKIRQ; + } + else + { +#if ARM7_DEBUG_CORE + LOG(("%08x: TST class on R15 no s bit set\n", R15)); +#endif + } + // extra cycles (PC written) + ARM7_ICOUNT -= 2; + } + + // compensate for the -3 at the end + ARM7_ICOUNT += 2; +} + +void arm7_cpu_device::HandleMul(UINT32 insn) +{ + UINT32 r, rm, rs; + + // MUL takes 1S + mI and MLA 1S + (m+1)I cycles to execute, where S and I are as + // defined in 6.2 Cycle Types on page 6-2. + // m is the number of 8 bit multiplier array cycles required to complete the + // multiply, which is controlled by the value of the multiplier operand + // specified by Rs. + + rm = GET_REGISTER(insn & INSN_MUL_RM); + rs = GET_REGISTER((insn & INSN_MUL_RS) >> INSN_MUL_RS_SHIFT); + + /* Do the basic multiply of Rm and Rs */ + r = rm * rs; + +#if ARM7_DEBUG_CORE + if ((insn & INSN_MUL_RM) == 0xf || + ((insn & INSN_MUL_RS) >> INSN_MUL_RS_SHIFT) == 0xf || + ((insn & INSN_MUL_RN) >> INSN_MUL_RN_SHIFT) == 0xf) + LOG(("%08x: R15 used in mult\n", R15)); +#endif + + /* Add on Rn if this is a MLA */ + if (insn & INSN_MUL_A) + { + r += GET_REGISTER((insn & INSN_MUL_RN) >> INSN_MUL_RN_SHIFT); + // extra cycle for MLA + ARM7_ICOUNT -= 1; + } + + /* Write the result */ + SET_REGISTER((insn & INSN_MUL_RD) >> INSN_MUL_RD_SHIFT, r); + + /* Set N and Z if asked */ + if (insn & INSN_S) + { + SET_CPSR((GET_CPSR & ~(N_MASK | Z_MASK)) | HandleALUNZFlags(r)); + } + + if (rs & SIGN_BIT) rs = -rs; + if (rs < 0x00000100) ARM7_ICOUNT -= 1 + 1; + else if (rs < 0x00010000) ARM7_ICOUNT -= 1 + 2; + else if (rs < 0x01000000) ARM7_ICOUNT -= 1 + 3; + else ARM7_ICOUNT -= 1 + 4; + + ARM7_ICOUNT += 3; +} + +// todo: add proper cycle counts +void arm7_cpu_device::HandleSMulLong(UINT32 insn) +{ + INT32 rm, rs; + UINT32 rhi, rlo; + INT64 res = 0; + + // MULL takes 1S + (m+1)I and MLAL 1S + (m+2)I cycles to execute, where m is the + // number of 8 bit multiplier array cycles required to complete the multiply, which is + // controlled by the value of the multiplier operand specified by Rs. + + rm = (INT32)GET_REGISTER(insn & 0xf); + rs = (INT32)GET_REGISTER(((insn >> 8) & 0xf)); + rhi = (insn >> 16) & 0xf; + rlo = (insn >> 12) & 0xf; + +#if ARM7_DEBUG_CORE + if ((insn & 0xf) == 15 || ((insn >> 8) & 0xf) == 15 || ((insn >> 16) & 0xf) == 15 || ((insn >> 12) & 0xf) == 15) + LOG(("%08x: Illegal use of PC as a register in SMULL opcode\n", R15)); +#endif + + /* Perform the multiplication */ + res = (INT64)rm * rs; + + /* Add on Rn if this is a MLA */ + if (insn & INSN_MUL_A) + { + INT64 acum = (INT64)((((INT64)(GET_REGISTER(rhi))) << 32) | GET_REGISTER(rlo)); + res += acum; + // extra cycle for MLA + ARM7_ICOUNT -= 1; + } + + /* Write the result (upper dword goes to RHi, lower to RLo) */ + SET_REGISTER(rhi, res >> 32); + SET_REGISTER(rlo, res & 0xFFFFFFFF); + + /* Set N and Z if asked */ + if (insn & INSN_S) + { + SET_CPSR((GET_CPSR & ~(N_MASK | Z_MASK)) | HandleLongALUNZFlags(res)); + } + + if (rs < 0) rs = -rs; + if (rs < 0x00000100) ARM7_ICOUNT -= 1 + 1 + 1; + else if (rs < 0x00010000) ARM7_ICOUNT -= 1 + 2 + 1; + else if (rs < 0x01000000) ARM7_ICOUNT -= 1 + 3 + 1; + else ARM7_ICOUNT -= 1 + 4 + 1; + + ARM7_ICOUNT += 3; +} + +// todo: add proper cycle counts +void arm7_cpu_device::HandleUMulLong(UINT32 insn) +{ + UINT32 rm, rs; + UINT32 rhi, rlo; + UINT64 res = 0; + + // MULL takes 1S + (m+1)I and MLAL 1S + (m+2)I cycles to execute, where m is the + // number of 8 bit multiplier array cycles required to complete the multiply, which is + // controlled by the value of the multiplier operand specified by Rs. + + rm = (INT32)GET_REGISTER(insn & 0xf); + rs = (INT32)GET_REGISTER(((insn >> 8) & 0xf)); + rhi = (insn >> 16) & 0xf; + rlo = (insn >> 12) & 0xf; + +#if ARM7_DEBUG_CORE + if (((insn & 0xf) == 15) || (((insn >> 8) & 0xf) == 15) || (((insn >> 16) & 0xf) == 15) || (((insn >> 12) & 0xf) == 15)) + LOG(("%08x: Illegal use of PC as a register in SMULL opcode\n", R15)); +#endif + + /* Perform the multiplication */ + res = (UINT64)rm * rs; + + /* Add on Rn if this is a MLA */ + if (insn & INSN_MUL_A) + { + UINT64 acum = (UINT64)((((UINT64)(GET_REGISTER(rhi))) << 32) | GET_REGISTER(rlo)); + res += acum; + // extra cycle for MLA + ARM7_ICOUNT -= 1; + } + + /* Write the result (upper dword goes to RHi, lower to RLo) */ + SET_REGISTER(rhi, res >> 32); + SET_REGISTER(rlo, res & 0xFFFFFFFF); + + /* Set N and Z if asked */ + if (insn & INSN_S) + { + SET_CPSR((GET_CPSR & ~(N_MASK | Z_MASK)) | HandleLongALUNZFlags(res)); + } + + if (rs < 0x00000100) ARM7_ICOUNT -= 1 + 1 + 1; + else if (rs < 0x00010000) ARM7_ICOUNT -= 1 + 2 + 1; + else if (rs < 0x01000000) ARM7_ICOUNT -= 1 + 3 + 1; + else ARM7_ICOUNT -= 1 + 4 + 1; + + ARM7_ICOUNT += 3; +} + +void arm7_cpu_device::HandleMemBlock(UINT32 insn) +{ + UINT32 rb = (insn & INSN_RN) >> INSN_RN_SHIFT; + UINT32 rbp = GET_REGISTER(rb); + int result; + +#if ARM7_DEBUG_CORE + if (rbp & 3) + LOG(("%08x: Unaligned Mem Transfer @ %08x\n", R15, rbp)); +#endif + + // Normal LDM instructions take nS + 1N + 1I and LDM PC takes (n+1)S + 2N + 1I + // incremental cycles, where S,N and I are as defined in 6.2 Cycle Types on page 6-2. + // STM instructions take (n-1)S + 2N incremental cycles to execute, where n is the + // number of words transferred. + + if (insn & INSN_BDT_L) + { + /* Loading */ + if (insn & INSN_BDT_U) + { + /* Incrementing */ + if (!(insn & INSN_BDT_P)) + { + rbp = rbp + (- 4); + } + + // S Flag Set, but R15 not in list = User Bank Transfer + if (insn & INSN_BDT_S && (insn & 0x8000) == 0) + { + // !! actually switching to user mode triggers a section permission fault in Happy Fish 302-in-1 (BP C0030DF4, press F5 ~16 times) !! + // set to user mode - then do the transfer, and set back + //int curmode = GET_MODE; + //SwitchMode(eARM7_MODE_USER); + LOG(("%08x: User Bank Transfer not fully tested - please check if working properly!\n", R15)); + result = loadInc(insn & 0xffff, rbp, insn & INSN_BDT_S, eARM7_MODE_USER); + // todo - not sure if Writeback occurs on User registers also.. + //SwitchMode(curmode); + } + else + result = loadInc(insn & 0xffff, rbp, insn & INSN_BDT_S, GET_MODE); + + if ((insn & INSN_BDT_W) && (m_pendingAbtD == 0)) + { +#if ARM7_DEBUG_CORE + if (rb == 15) + LOG(("%08x: Illegal LDRM writeback to r15\n", R15)); +#endif + // "A LDM will always overwrite the updated base if the base is in the list." (also for a user bank transfer?) + // GBA "V-Rally 3" expects R0 not to be overwritten with the updated base value [BP 8077B0C] + if (((insn >> rb) & 1) == 0) + { + SET_REGISTER(rb, GET_REGISTER(rb) + result * 4); + } + } + + // R15 included? (NOTE: CPSR restore must occur LAST otherwise wrong registers restored!) + if ((insn & 0x8000) && (m_pendingAbtD == 0)) { + R15 -= 4; // SJE: I forget why i did this? + // S - Flag Set? Signals transfer of current mode SPSR->CPSR + if (insn & INSN_BDT_S) + { + if (MODE32) + { + SET_CPSR(GET_REGISTER(SPSR)); + SwitchMode(GET_MODE); + } + else + { + UINT32 temp; +// LOG(("LDM + S | R15 %08X CPSR %08X\n", R15, GET_CPSR)); + temp = (GET_CPSR & 0x0FFFFF20) | (R15 & 0xF0000000) /* N Z C V */ | ((R15 & 0x0C000000) >> (26 - 6)) /* I F */ | (R15 & 0x00000003) /* M1 M0 */; + SET_CPSR( temp); + SwitchMode(temp & 3); + } + } + // LDM PC - takes 2 extra cycles + ARM7_ICOUNT -= 2; + } + } + else + { + /* Decrementing */ + if (!(insn & INSN_BDT_P)) + { + rbp = rbp - (- 4); + } + + // S Flag Set, but R15 not in list = User Bank Transfer + if (insn & INSN_BDT_S && ((insn & 0x8000) == 0)) + { + // set to user mode - then do the transfer, and set back + //int curmode = GET_MODE; + //SwitchMode(eARM7_MODE_USER); + LOG(("%08x: User Bank Transfer not fully tested - please check if working properly!\n", R15)); + result = loadDec(insn & 0xffff, rbp, insn & INSN_BDT_S, eARM7_MODE_USER); + // todo - not sure if Writeback occurs on User registers also.. + //SwitchMode(curmode); + } + else + result = loadDec(insn & 0xffff, rbp, insn & INSN_BDT_S, GET_MODE); + + if ((insn & INSN_BDT_W) && (m_pendingAbtD == 0)) + { + if (rb == 0xf) + LOG(("%08x: Illegal LDRM writeback to r15\n", R15)); + // "A LDM will always overwrite the updated base if the base is in the list." (also for a user bank transfer?) + if (((insn >> rb) & 1) == 0) + { + SET_REGISTER(rb, GET_REGISTER(rb) - result * 4); + } + } + + // R15 included? (NOTE: CPSR restore must occur LAST otherwise wrong registers restored!) + if ((insn & 0x8000) && (m_pendingAbtD == 0)) { + R15 -= 4; // SJE: I forget why i did this? + // S - Flag Set? Signals transfer of current mode SPSR->CPSR + if (insn & INSN_BDT_S) + { + if (MODE32) + { + SET_CPSR(GET_REGISTER(SPSR)); + SwitchMode(GET_MODE); + } + else + { + UINT32 temp; +// LOG(("LDM + S | R15 %08X CPSR %08X\n", R15, GET_CPSR)); + temp = (GET_CPSR & 0x0FFFFF20) /* N Z C V I F M4 M3 M2 M1 M0 */ | (R15 & 0xF0000000) /* N Z C V */ | ((R15 & 0x0C000000) >> (26 - 6)) /* I F */ | (R15 & 0x00000003) /* M1 M0 */; + SET_CPSR( temp); + SwitchMode(temp & 3); + } + } + // LDM PC - takes 2 extra cycles + ARM7_ICOUNT -= 2; + } + } + // LDM (NO PC) takes (n)S + 1N + 1I cycles (n = # of register transfers) + ARM7_ICOUNT -= result + 1 + 1; + } /* Loading */ + else + { + /* Storing - STM */ + if (insn & (1 << eR15)) + { +#if ARM7_DEBUG_CORE + LOG(("%08x: Writing R15 in strm\n", R15)); +#endif + /* special case handling if writing to PC */ + R15 += 12; + } + if (insn & INSN_BDT_U) + { + /* Incrementing */ + if (!(insn & INSN_BDT_P)) + { + rbp = rbp + (- 4); + } + + // S Flag Set = User Bank Transfer + if (insn & INSN_BDT_S) + { + // todo: needs to be tested.. + + // set to user mode - then do the transfer, and set back + //int curmode = GET_MODE; + //SwitchMode(eARM7_MODE_USER); + LOG(("%08x: User Bank Transfer not fully tested - please check if working properly!\n", R15)); + result = storeInc(insn & 0xffff, rbp, eARM7_MODE_USER); + // todo - not sure if Writeback occurs on User registers also.. + //SwitchMode(curmode); + } + else + result = storeInc(insn & 0xffff, rbp, GET_MODE); + + if ((insn & INSN_BDT_W) && (m_pendingAbtD == 0)) + { + SET_REGISTER(rb, GET_REGISTER(rb) + result * 4); + } + } + else + { + /* Decrementing - but real CPU writes in incrementing order */ + if (!(insn & INSN_BDT_P)) + { + rbp = rbp - (-4); + } + + // S Flag Set = User Bank Transfer + if (insn & INSN_BDT_S) + { + // set to user mode - then do the transfer, and set back + //int curmode = GET_MODE; + //SwitchMode(eARM7_MODE_USER); + LOG(("%08x: User Bank Transfer not fully tested - please check if working properly!\n", R15)); + result = storeDec(insn & 0xffff, rbp, eARM7_MODE_USER); + // todo - not sure if Writeback occurs on User registers also.. + //SwitchMode(curmode); + } + else + result = storeDec(insn & 0xffff, rbp, GET_MODE); + + if ((insn & INSN_BDT_W) && (m_pendingAbtD == 0)) + { + SET_REGISTER(rb, GET_REGISTER(rb) - result * 4); + } + } + if (insn & (1 << eR15)) + R15 -= 12; + + // STM takes (n-1)S + 2N cycles (n = # of register transfers) + ARM7_ICOUNT -= (result - 1) + 2; + } + + // We will specify the cycle count for each case, so remove the -3 that occurs at the end + ARM7_ICOUNT += 3; + +} /* HandleMemBlock */ + + +const arm7_cpu_device::arm7ops_ophandler arm7_cpu_device::ops_handler[0x10] = +{ + &arm7_cpu_device::arm7ops_0123, &arm7_cpu_device::arm7ops_0123, &arm7_cpu_device::arm7ops_0123, &arm7_cpu_device::arm7ops_0123, + &arm7_cpu_device::arm7ops_4567, &arm7_cpu_device::arm7ops_4567, &arm7_cpu_device::arm7ops_4567, &arm7_cpu_device::arm7ops_4567, + &arm7_cpu_device::arm7ops_89, &arm7_cpu_device::arm7ops_89, &arm7_cpu_device::arm7ops_ab, &arm7_cpu_device::arm7ops_ab, + &arm7_cpu_device::arm7ops_cd, &arm7_cpu_device::arm7ops_cd, &arm7_cpu_device::arm7ops_e, &arm7_cpu_device::arm7ops_f, +}; + +void arm7_cpu_device::arm7ops_0123(UINT32 insn) +{ +//case 0: +//case 1: +//case 2: +//case 3: + /* Branch and Exchange (BX) */ + if ((insn & 0x0ffffff0) == 0x012fff10) // bits 27-4 == 000100101111111111110001 + { + R15 = GET_REGISTER(insn & 0x0f); + // If new PC address has A0 set, switch to Thumb mode + if (R15 & 1) { + SET_CPSR(GET_CPSR|T_MASK); + R15--; + } + } + else if ((insn & 0x0ff000f0) == 0x01600010) // CLZ - v5 + { + UINT32 rm = insn&0xf; + UINT32 rd = (insn>>12)&0xf; + + SET_REGISTER(rd, count_leading_zeros(GET_REGISTER(rm))); + + R15 += 4; + } + else if ((insn & 0x0ff000f0) == 0x01000050) // QADD - v5 + { + INT32 src1 = GET_REGISTER(insn&0xf); + INT32 src2 = GET_REGISTER((insn>>16)&0xf); + INT64 res; + + res = saturate_qbit_overflow((INT64)src1 + (INT64)src2); + + SET_REGISTER((insn>>12)&0xf, (INT32)res); + R15 += 4; + } + else if ((insn & 0x0ff000f0) == 0x01400050) // QDADD - v5 + { + INT32 src1 = GET_REGISTER(insn&0xf); + INT32 src2 = GET_REGISTER((insn>>16)&0xf); + INT64 res; + + // check if doubling operation will overflow + res = (INT64)src2 * 2; + saturate_qbit_overflow(res); + + src2 *= 2; + res = saturate_qbit_overflow((INT64)src1 + (INT64)src2); + + SET_REGISTER((insn>>12)&0xf, (INT32)res); + R15 += 4; + } + else if ((insn & 0x0ff000f0) == 0x01200050) // QSUB - v5 + { + INT32 src1 = GET_REGISTER(insn&0xf); + INT32 src2 = GET_REGISTER((insn>>16)&0xf); + INT64 res; + + res = saturate_qbit_overflow((INT64)src1 - (INT64)src2); + + SET_REGISTER((insn>>12)&0xf, (INT32)res); + R15 += 4; + } + else if ((insn & 0x0ff000f0) == 0x01600050) // QDSUB - v5 + { + INT32 src1 = GET_REGISTER(insn&0xf); + INT32 src2 = GET_REGISTER((insn>>16)&0xf); + INT64 res; + + // check if doubling operation will overflow + res = (INT64)src2 * 2; + saturate_qbit_overflow(res); + + src2 *= 2; + res = saturate_qbit_overflow((INT64)src1 - (INT64)src2); + + SET_REGISTER((insn>>12)&0xf, (INT32)res); + R15 += 4; + } + else if ((insn & 0x0ff00090) == 0x01000080) // SMLAxy - v5 + { + INT32 src1 = GET_REGISTER(insn&0xf); + INT32 src2 = GET_REGISTER((insn>>8)&0xf); + INT32 res1; + + // select top and bottom halves of src1/src2 and sign extend if necessary + if (insn & 0x20) + { + src1 >>= 16; + } + + src1 &= 0xffff; + if (src1 & 0x8000) + { + src1 |= 0xffff0000; + } + + if (insn & 0x40) + { + src2 >>= 16; + } + + src2 &= 0xffff; + if (src2 & 0x8000) + { + src2 |= 0xffff0000; + } + + // do the signed multiply + res1 = src1 * src2; + // and the accumulate. NOTE: only the accumulate can cause an overflow, which is why we do it this way. + saturate_qbit_overflow((INT64)res1 + (INT64)GET_REGISTER((insn>>12)&0xf)); + + SET_REGISTER((insn>>16)&0xf, res1 + GET_REGISTER((insn>>12)&0xf)); + R15 += 4; + } + else if ((insn & 0x0ff00090) == 0x01400080) // SMLALxy - v5 + { + INT32 src1 = GET_REGISTER(insn&0xf); + INT32 src2 = GET_REGISTER((insn>>8)&0xf); + INT64 dst; + + dst = (INT64)GET_REGISTER((insn>>12)&0xf); + dst |= (INT64)GET_REGISTER((insn>>16)&0xf)<<32; + + // do the multiply and accumulate + dst += (INT64)src1 * (INT64)src2; + + // write back the result + SET_REGISTER((insn>>12)&0xf, (UINT32)dst); + SET_REGISTER((insn>>16)&0xf, (UINT32)(dst >> 32)); + R15 += 4; + } + else if ((insn & 0x0ff00090) == 0x01600080) // SMULxy - v5 + { + INT32 src1 = GET_REGISTER(insn&0xf); + INT32 src2 = GET_REGISTER((insn>>8)&0xf); + INT32 res; + + // select top and bottom halves of src1/src2 and sign extend if necessary + if (insn & 0x20) + { + src1 >>= 16; + } + + src1 &= 0xffff; + if (src1 & 0x8000) + { + src1 |= 0xffff0000; + } + + if (insn & 0x40) + { + src2 >>= 16; + } + + src2 &= 0xffff; + if (src2 & 0x8000) + { + src2 |= 0xffff0000; + } + + res = src1 * src2; + SET_REGISTER((insn>>16)&0xf, res); + R15 += 4; + } + else if ((insn & 0x0ff000b0) == 0x012000a0) // SMULWy - v5 + { + INT32 src1 = GET_REGISTER(insn&0xf); + INT32 src2 = GET_REGISTER((insn>>8)&0xf); + INT64 res; + + if (insn & 0x40) + { + src2 >>= 16; + } + + src2 &= 0xffff; + if (src2 & 0x8000) + { + src2 |= 0xffff0000; + } + + res = (INT64)src1 * (INT64)src2; + res >>= 16; + SET_REGISTER((insn>>16)&0xf, (UINT32)res); + R15 += 4; + } + else if ((insn & 0x0ff000b0) == 0x01200080) // SMLAWy - v5 + { + INT32 src1 = GET_REGISTER(insn&0xf); + INT32 src2 = GET_REGISTER((insn>>8)&0xf); + INT32 src3 = GET_REGISTER((insn>>12)&0xf); + INT64 res; + + if (insn & 0x40) + { + src2 >>= 16; + } + + src2 &= 0xffff; + if (src2 & 0x8000) + { + src2 |= 0xffff0000; + } + + res = (INT64)src1 * (INT64)src2; + res >>= 16; + + // check for overflow and set the Q bit + saturate_qbit_overflow((INT64)src3 + res); + + // do the real accumulate + src3 += (INT32)res; + + // write the result back + SET_REGISTER((insn>>16)&0xf, (UINT32)res); + R15 += 4; + } + else + /* Multiply OR Swap OR Half Word Data Transfer */ + if ((insn & 0x0e000000) == 0 && (insn & 0x80) && (insn & 0x10)) // bits 27-25=000 bit 7=1 bit 4=1 + { + /* Half Word Data Transfer */ + if (insn & 0x60) // bits = 6-5 != 00 + { + HandleHalfWordDT(insn); + } + else + /* Swap */ + if (insn & 0x01000000) // bit 24 = 1 + { + HandleSwap(insn); + } + /* Multiply Or Multiply Long */ + else + { + /* multiply long */ + if (insn & 0x800000) // Bit 23 = 1 for Multiply Long + { + /* Signed? */ + if (insn & 0x00400000) + HandleSMulLong(insn); + else + HandleUMulLong(insn); + } + /* multiply */ + else + { + HandleMul(insn); + } + R15 += 4; + } + } + /* Data Processing OR PSR Transfer */ + else if ((insn & 0x0c000000) == 0) // bits 27-26 == 00 - This check can only exist properly after Multiplication check above + { + /* PSR Transfer (MRS & MSR) */ + if (((insn & 0x00100000) == 0) && ((insn & 0x01800000) == 0x01000000)) // S bit must be clear, and bit 24,23 = 10 + { + HandlePSRTransfer(insn); + ARM7_ICOUNT += 2; // PSR only takes 1 - S Cycle, so we add + 2, since at end, we -3.. + R15 += 4; + } + /* Data Processing */ + else + { + HandleALU(insn); + } + } +// break; +} + +void arm7_cpu_device::arm7ops_4567(UINT32 insn) /* Data Transfer - Single Data Access */ +{ +//case 4: +//case 5: +//case 6: +//case 7: + HandleMemSingle(insn); + R15 += 4; +// break; +} + +void arm7_cpu_device::arm7ops_89(UINT32 insn) /* Block Data Transfer/Access */ +{ +//case 8: +//case 9: + HandleMemBlock(insn); + R15 += 4; +// break; +} + +void arm7_cpu_device::arm7ops_ab(UINT32 insn) /* Branch or Branch & Link */ +{ +//case 0xa: +//case 0xb: + HandleBranch(insn); +// break; +} + +void arm7_cpu_device::arm7ops_cd(UINT32 insn) /* Co-Processor Data Transfer */ +{ +//case 0xc: +//case 0xd: + HandleCoProcDT(insn); + R15 += 4; +// break; +} + +void arm7_cpu_device::arm7ops_e(UINT32 insn) /* Co-Processor Data Operation or Register Transfer */ +{ +//case 0xe: + if (insn & 0x10) + HandleCoProcRT(insn); + else + HandleCoProcDO(insn); + R15 += 4; +// break; +} + +void arm7_cpu_device::arm7ops_f(UINT32 insn) /* Software Interrupt */ +{ + m_pendingSwi = 1; + ARM7_CHECKIRQ; + //couldn't find any cycle counts for SWI +// break; +} diff --git a/src/devices/cpu/arm7/arm7tdrc.inc b/src/devices/cpu/arm7/arm7tdrc.inc new file mode 100644 index 00000000000..ee0573a32e7 --- /dev/null +++ b/src/devices/cpu/arm7/arm7tdrc.inc @@ -0,0 +1,1593 @@ +// license:BSD-3-Clause +// copyright-holders:Steve Ellenoff,R. Belmont,Ryan Holtz +#include "emu.h" +#include "arm7core.h" +#include "arm7help.h" + + +const arm7_cpu_device::arm7thumb_drcophandler arm7_cpu_device::drcthumb_handler[0x40*0x10] = +{ +// #define THUMB_SHIFT_R ((UINT16)0x0800) + &arm7_cpu_device::drctg00_0, &arm7_cpu_device::drctg00_0, &arm7_cpu_device::drctg00_0, &arm7_cpu_device::drctg00_0, &arm7_cpu_device::drctg00_0, &arm7_cpu_device::drctg00_0, &arm7_cpu_device::drctg00_0, &arm7_cpu_device::drctg00_0, + &arm7_cpu_device::drctg00_0, &arm7_cpu_device::drctg00_0, &arm7_cpu_device::drctg00_0, &arm7_cpu_device::drctg00_0, &arm7_cpu_device::drctg00_0, &arm7_cpu_device::drctg00_0, &arm7_cpu_device::drctg00_0, &arm7_cpu_device::drctg00_0, + &arm7_cpu_device::drctg00_0, &arm7_cpu_device::drctg00_0, &arm7_cpu_device::drctg00_0, &arm7_cpu_device::drctg00_0, &arm7_cpu_device::drctg00_0, &arm7_cpu_device::drctg00_0, &arm7_cpu_device::drctg00_0, &arm7_cpu_device::drctg00_0, + &arm7_cpu_device::drctg00_0, &arm7_cpu_device::drctg00_0, &arm7_cpu_device::drctg00_0, &arm7_cpu_device::drctg00_0, &arm7_cpu_device::drctg00_0, &arm7_cpu_device::drctg00_0, &arm7_cpu_device::drctg00_0, &arm7_cpu_device::drctg00_0, + &arm7_cpu_device::drctg00_1, &arm7_cpu_device::drctg00_1, &arm7_cpu_device::drctg00_1, &arm7_cpu_device::drctg00_1, &arm7_cpu_device::drctg00_1, &arm7_cpu_device::drctg00_1, &arm7_cpu_device::drctg00_1, &arm7_cpu_device::drctg00_1, + &arm7_cpu_device::drctg00_1, &arm7_cpu_device::drctg00_1, &arm7_cpu_device::drctg00_1, &arm7_cpu_device::drctg00_1, &arm7_cpu_device::drctg00_1, &arm7_cpu_device::drctg00_1, &arm7_cpu_device::drctg00_1, &arm7_cpu_device::drctg00_1, + &arm7_cpu_device::drctg00_1, &arm7_cpu_device::drctg00_1, &arm7_cpu_device::drctg00_1, &arm7_cpu_device::drctg00_1, &arm7_cpu_device::drctg00_1, &arm7_cpu_device::drctg00_1, &arm7_cpu_device::drctg00_1, &arm7_cpu_device::drctg00_1, + &arm7_cpu_device::drctg00_1, &arm7_cpu_device::drctg00_1, &arm7_cpu_device::drctg00_1, &arm7_cpu_device::drctg00_1, &arm7_cpu_device::drctg00_1, &arm7_cpu_device::drctg00_1, &arm7_cpu_device::drctg00_1, &arm7_cpu_device::drctg00_1, +// #define THUMB_INSN_ADDSUB ((UINT16)0x0800) // #define THUMB_ADDSUB_TYPE ((UINT16)0x0600) + &arm7_cpu_device::drctg01_0, &arm7_cpu_device::drctg01_0, &arm7_cpu_device::drctg01_0, &arm7_cpu_device::drctg01_0, &arm7_cpu_device::drctg01_0, &arm7_cpu_device::drctg01_0, &arm7_cpu_device::drctg01_0, &arm7_cpu_device::drctg01_0, + &arm7_cpu_device::drctg01_0, &arm7_cpu_device::drctg01_0, &arm7_cpu_device::drctg01_0, &arm7_cpu_device::drctg01_0, &arm7_cpu_device::drctg01_0, &arm7_cpu_device::drctg01_0, &arm7_cpu_device::drctg01_0, &arm7_cpu_device::drctg01_0, + &arm7_cpu_device::drctg01_0, &arm7_cpu_device::drctg01_0, &arm7_cpu_device::drctg01_0, &arm7_cpu_device::drctg01_0, &arm7_cpu_device::drctg01_0, &arm7_cpu_device::drctg01_0, &arm7_cpu_device::drctg01_0, &arm7_cpu_device::drctg01_0, + &arm7_cpu_device::drctg01_0, &arm7_cpu_device::drctg01_0, &arm7_cpu_device::drctg01_0, &arm7_cpu_device::drctg01_0, &arm7_cpu_device::drctg01_0, &arm7_cpu_device::drctg01_0, &arm7_cpu_device::drctg01_0, &arm7_cpu_device::drctg01_0, + &arm7_cpu_device::drctg01_10, &arm7_cpu_device::drctg01_10, &arm7_cpu_device::drctg01_10, &arm7_cpu_device::drctg01_10, &arm7_cpu_device::drctg01_10, &arm7_cpu_device::drctg01_10, &arm7_cpu_device::drctg01_10, &arm7_cpu_device::drctg01_10, + &arm7_cpu_device::drctg01_11, &arm7_cpu_device::drctg01_11, &arm7_cpu_device::drctg01_11, &arm7_cpu_device::drctg01_11, &arm7_cpu_device::drctg01_11, &arm7_cpu_device::drctg01_11, &arm7_cpu_device::drctg01_11, &arm7_cpu_device::drctg01_11, + &arm7_cpu_device::drctg01_12, &arm7_cpu_device::drctg01_12, &arm7_cpu_device::drctg01_12, &arm7_cpu_device::drctg01_12, &arm7_cpu_device::drctg01_12, &arm7_cpu_device::drctg01_12, &arm7_cpu_device::drctg01_12, &arm7_cpu_device::drctg01_12, + &arm7_cpu_device::drctg01_13, &arm7_cpu_device::drctg01_13, &arm7_cpu_device::drctg01_13, &arm7_cpu_device::drctg01_13, &arm7_cpu_device::drctg01_13, &arm7_cpu_device::drctg01_13, &arm7_cpu_device::drctg01_13, &arm7_cpu_device::drctg01_13, +// #define THUMB_INSN_CMP ((UINT16)0x0800) + &arm7_cpu_device::drctg02_0, &arm7_cpu_device::drctg02_0, &arm7_cpu_device::drctg02_0, &arm7_cpu_device::drctg02_0, &arm7_cpu_device::drctg02_0, &arm7_cpu_device::drctg02_0, &arm7_cpu_device::drctg02_0, &arm7_cpu_device::drctg02_0, + &arm7_cpu_device::drctg02_0, &arm7_cpu_device::drctg02_0, &arm7_cpu_device::drctg02_0, &arm7_cpu_device::drctg02_0, &arm7_cpu_device::drctg02_0, &arm7_cpu_device::drctg02_0, &arm7_cpu_device::drctg02_0, &arm7_cpu_device::drctg02_0, + &arm7_cpu_device::drctg02_0, &arm7_cpu_device::drctg02_0, &arm7_cpu_device::drctg02_0, &arm7_cpu_device::drctg02_0, &arm7_cpu_device::drctg02_0, &arm7_cpu_device::drctg02_0, &arm7_cpu_device::drctg02_0, &arm7_cpu_device::drctg02_0, + &arm7_cpu_device::drctg02_0, &arm7_cpu_device::drctg02_0, &arm7_cpu_device::drctg02_0, &arm7_cpu_device::drctg02_0, &arm7_cpu_device::drctg02_0, &arm7_cpu_device::drctg02_0, &arm7_cpu_device::drctg02_0, &arm7_cpu_device::drctg02_0, + &arm7_cpu_device::drctg02_1, &arm7_cpu_device::drctg02_1, &arm7_cpu_device::drctg02_1, &arm7_cpu_device::drctg02_1, &arm7_cpu_device::drctg02_1, &arm7_cpu_device::drctg02_1, &arm7_cpu_device::drctg02_1, &arm7_cpu_device::drctg02_1, + &arm7_cpu_device::drctg02_1, &arm7_cpu_device::drctg02_1, &arm7_cpu_device::drctg02_1, &arm7_cpu_device::drctg02_1, &arm7_cpu_device::drctg02_1, &arm7_cpu_device::drctg02_1, &arm7_cpu_device::drctg02_1, &arm7_cpu_device::drctg02_1, + &arm7_cpu_device::drctg02_1, &arm7_cpu_device::drctg02_1, &arm7_cpu_device::drctg02_1, &arm7_cpu_device::drctg02_1, &arm7_cpu_device::drctg02_1, &arm7_cpu_device::drctg02_1, &arm7_cpu_device::drctg02_1, &arm7_cpu_device::drctg02_1, + &arm7_cpu_device::drctg02_1, &arm7_cpu_device::drctg02_1, &arm7_cpu_device::drctg02_1, &arm7_cpu_device::drctg02_1, &arm7_cpu_device::drctg02_1, &arm7_cpu_device::drctg02_1, &arm7_cpu_device::drctg02_1, &arm7_cpu_device::drctg02_1, +// #define THUMB_INSN_SUB ((UINT16)0x0800) + &arm7_cpu_device::drctg03_0, &arm7_cpu_device::drctg03_0, &arm7_cpu_device::drctg03_0, &arm7_cpu_device::drctg03_0, &arm7_cpu_device::drctg03_0, &arm7_cpu_device::drctg03_0, &arm7_cpu_device::drctg03_0, &arm7_cpu_device::drctg03_0, + &arm7_cpu_device::drctg03_0, &arm7_cpu_device::drctg03_0, &arm7_cpu_device::drctg03_0, &arm7_cpu_device::drctg03_0, &arm7_cpu_device::drctg03_0, &arm7_cpu_device::drctg03_0, &arm7_cpu_device::drctg03_0, &arm7_cpu_device::drctg03_0, + &arm7_cpu_device::drctg03_0, &arm7_cpu_device::drctg03_0, &arm7_cpu_device::drctg03_0, &arm7_cpu_device::drctg03_0, &arm7_cpu_device::drctg03_0, &arm7_cpu_device::drctg03_0, &arm7_cpu_device::drctg03_0, &arm7_cpu_device::drctg03_0, + &arm7_cpu_device::drctg03_0, &arm7_cpu_device::drctg03_0, &arm7_cpu_device::drctg03_0, &arm7_cpu_device::drctg03_0, &arm7_cpu_device::drctg03_0, &arm7_cpu_device::drctg03_0, &arm7_cpu_device::drctg03_0, &arm7_cpu_device::drctg03_0, + &arm7_cpu_device::drctg03_1, &arm7_cpu_device::drctg03_1, &arm7_cpu_device::drctg03_1, &arm7_cpu_device::drctg03_1, &arm7_cpu_device::drctg03_1, &arm7_cpu_device::drctg03_1, &arm7_cpu_device::drctg03_1, &arm7_cpu_device::drctg03_1, + &arm7_cpu_device::drctg03_1, &arm7_cpu_device::drctg03_1, &arm7_cpu_device::drctg03_1, &arm7_cpu_device::drctg03_1, &arm7_cpu_device::drctg03_1, &arm7_cpu_device::drctg03_1, &arm7_cpu_device::drctg03_1, &arm7_cpu_device::drctg03_1, + &arm7_cpu_device::drctg03_1, &arm7_cpu_device::drctg03_1, &arm7_cpu_device::drctg03_1, &arm7_cpu_device::drctg03_1, &arm7_cpu_device::drctg03_1, &arm7_cpu_device::drctg03_1, &arm7_cpu_device::drctg03_1, &arm7_cpu_device::drctg03_1, + &arm7_cpu_device::drctg03_1, &arm7_cpu_device::drctg03_1, &arm7_cpu_device::drctg03_1, &arm7_cpu_device::drctg03_1, &arm7_cpu_device::drctg03_1, &arm7_cpu_device::drctg03_1, &arm7_cpu_device::drctg03_1, &arm7_cpu_device::drctg03_1, +//#define THUMB_GROUP4_TYPE ((UINT16)0x0c00) //#define THUMB_ALUOP_TYPE ((UINT16)0x03c0) // #define THUMB_HIREG_OP ((UINT16)0x0300) // #define THUMB_HIREG_H ((UINT16)0x00c0) + &arm7_cpu_device::drctg04_00_00, &arm7_cpu_device::drctg04_00_01, &arm7_cpu_device::drctg04_00_02, &arm7_cpu_device::drctg04_00_03, &arm7_cpu_device::drctg04_00_04, &arm7_cpu_device::drctg04_00_05, &arm7_cpu_device::drctg04_00_06, &arm7_cpu_device::drctg04_00_07, + &arm7_cpu_device::drctg04_00_08, &arm7_cpu_device::drctg04_00_09, &arm7_cpu_device::drctg04_00_0a, &arm7_cpu_device::drctg04_00_0b, &arm7_cpu_device::drctg04_00_0c, &arm7_cpu_device::drctg04_00_0d, &arm7_cpu_device::drctg04_00_0e, &arm7_cpu_device::drctg04_00_0f, + &arm7_cpu_device::drctg04_01_00, &arm7_cpu_device::drctg04_01_01, &arm7_cpu_device::drctg04_01_02, &arm7_cpu_device::drctg04_01_03, &arm7_cpu_device::drctg04_01_10, &arm7_cpu_device::drctg04_01_11, &arm7_cpu_device::drctg04_01_12, &arm7_cpu_device::drctg04_01_13, + &arm7_cpu_device::drctg04_01_20, &arm7_cpu_device::drctg04_01_21, &arm7_cpu_device::drctg04_01_22, &arm7_cpu_device::drctg04_01_23, &arm7_cpu_device::drctg04_01_30, &arm7_cpu_device::drctg04_01_31, &arm7_cpu_device::drctg04_01_32, &arm7_cpu_device::drctg04_01_33, + &arm7_cpu_device::drctg04_0203, &arm7_cpu_device::drctg04_0203, &arm7_cpu_device::drctg04_0203, &arm7_cpu_device::drctg04_0203, &arm7_cpu_device::drctg04_0203, &arm7_cpu_device::drctg04_0203, &arm7_cpu_device::drctg04_0203, &arm7_cpu_device::drctg04_0203, + &arm7_cpu_device::drctg04_0203, &arm7_cpu_device::drctg04_0203, &arm7_cpu_device::drctg04_0203, &arm7_cpu_device::drctg04_0203, &arm7_cpu_device::drctg04_0203, &arm7_cpu_device::drctg04_0203, &arm7_cpu_device::drctg04_0203, &arm7_cpu_device::drctg04_0203, + &arm7_cpu_device::drctg04_0203, &arm7_cpu_device::drctg04_0203, &arm7_cpu_device::drctg04_0203, &arm7_cpu_device::drctg04_0203, &arm7_cpu_device::drctg04_0203, &arm7_cpu_device::drctg04_0203, &arm7_cpu_device::drctg04_0203, &arm7_cpu_device::drctg04_0203, + &arm7_cpu_device::drctg04_0203, &arm7_cpu_device::drctg04_0203, &arm7_cpu_device::drctg04_0203, &arm7_cpu_device::drctg04_0203, &arm7_cpu_device::drctg04_0203, &arm7_cpu_device::drctg04_0203, &arm7_cpu_device::drctg04_0203, &arm7_cpu_device::drctg04_0203, +//#define THUMB_GROUP5_TYPE ((UINT16)0x0e00) + &arm7_cpu_device::drctg05_0, &arm7_cpu_device::drctg05_0, &arm7_cpu_device::drctg05_0, &arm7_cpu_device::drctg05_0, &arm7_cpu_device::drctg05_0, &arm7_cpu_device::drctg05_0, &arm7_cpu_device::drctg05_0, &arm7_cpu_device::drctg05_0, + &arm7_cpu_device::drctg05_1, &arm7_cpu_device::drctg05_1, &arm7_cpu_device::drctg05_1, &arm7_cpu_device::drctg05_1, &arm7_cpu_device::drctg05_1, &arm7_cpu_device::drctg05_1, &arm7_cpu_device::drctg05_1, &arm7_cpu_device::drctg05_1, + &arm7_cpu_device::drctg05_2, &arm7_cpu_device::drctg05_2, &arm7_cpu_device::drctg05_2, &arm7_cpu_device::drctg05_2, &arm7_cpu_device::drctg05_2, &arm7_cpu_device::drctg05_2, &arm7_cpu_device::drctg05_2, &arm7_cpu_device::drctg05_2, + &arm7_cpu_device::drctg05_3, &arm7_cpu_device::drctg05_3, &arm7_cpu_device::drctg05_3, &arm7_cpu_device::drctg05_3, &arm7_cpu_device::drctg05_3, &arm7_cpu_device::drctg05_3, &arm7_cpu_device::drctg05_3, &arm7_cpu_device::drctg05_3, + &arm7_cpu_device::drctg05_4, &arm7_cpu_device::drctg05_4, &arm7_cpu_device::drctg05_4, &arm7_cpu_device::drctg05_4, &arm7_cpu_device::drctg05_4, &arm7_cpu_device::drctg05_4, &arm7_cpu_device::drctg05_4, &arm7_cpu_device::drctg05_4, + &arm7_cpu_device::drctg05_5, &arm7_cpu_device::drctg05_5, &arm7_cpu_device::drctg05_5, &arm7_cpu_device::drctg05_5, &arm7_cpu_device::drctg05_5, &arm7_cpu_device::drctg05_5, &arm7_cpu_device::drctg05_5, &arm7_cpu_device::drctg05_5, + &arm7_cpu_device::drctg05_6, &arm7_cpu_device::drctg05_6, &arm7_cpu_device::drctg05_6, &arm7_cpu_device::drctg05_6, &arm7_cpu_device::drctg05_6, &arm7_cpu_device::drctg05_6, &arm7_cpu_device::drctg05_6, &arm7_cpu_device::drctg05_6, + &arm7_cpu_device::drctg05_7, &arm7_cpu_device::drctg05_7, &arm7_cpu_device::drctg05_7, &arm7_cpu_device::drctg05_7, &arm7_cpu_device::drctg05_7, &arm7_cpu_device::drctg05_7, &arm7_cpu_device::drctg05_7, &arm7_cpu_device::drctg05_7, +//#define THUMB_LSOP_L ((UINT16)0x0800) + &arm7_cpu_device::drctg06_0, &arm7_cpu_device::drctg06_0, &arm7_cpu_device::drctg06_0, &arm7_cpu_device::drctg06_0, &arm7_cpu_device::drctg06_0, &arm7_cpu_device::drctg06_0, &arm7_cpu_device::drctg06_0, &arm7_cpu_device::drctg06_0, + &arm7_cpu_device::drctg06_0, &arm7_cpu_device::drctg06_0, &arm7_cpu_device::drctg06_0, &arm7_cpu_device::drctg06_0, &arm7_cpu_device::drctg06_0, &arm7_cpu_device::drctg06_0, &arm7_cpu_device::drctg06_0, &arm7_cpu_device::drctg06_0, + &arm7_cpu_device::drctg06_0, &arm7_cpu_device::drctg06_0, &arm7_cpu_device::drctg06_0, &arm7_cpu_device::drctg06_0, &arm7_cpu_device::drctg06_0, &arm7_cpu_device::drctg06_0, &arm7_cpu_device::drctg06_0, &arm7_cpu_device::drctg06_0, + &arm7_cpu_device::drctg06_0, &arm7_cpu_device::drctg06_0, &arm7_cpu_device::drctg06_0, &arm7_cpu_device::drctg06_0, &arm7_cpu_device::drctg06_0, &arm7_cpu_device::drctg06_0, &arm7_cpu_device::drctg06_0, &arm7_cpu_device::drctg06_0, + &arm7_cpu_device::drctg06_1, &arm7_cpu_device::drctg06_1, &arm7_cpu_device::drctg06_1, &arm7_cpu_device::drctg06_1, &arm7_cpu_device::drctg06_1, &arm7_cpu_device::drctg06_1, &arm7_cpu_device::drctg06_1, &arm7_cpu_device::drctg06_1, + &arm7_cpu_device::drctg06_1, &arm7_cpu_device::drctg06_1, &arm7_cpu_device::drctg06_1, &arm7_cpu_device::drctg06_1, &arm7_cpu_device::drctg06_1, &arm7_cpu_device::drctg06_1, &arm7_cpu_device::drctg06_1, &arm7_cpu_device::drctg06_1, + &arm7_cpu_device::drctg06_1, &arm7_cpu_device::drctg06_1, &arm7_cpu_device::drctg06_1, &arm7_cpu_device::drctg06_1, &arm7_cpu_device::drctg06_1, &arm7_cpu_device::drctg06_1, &arm7_cpu_device::drctg06_1, &arm7_cpu_device::drctg06_1, + &arm7_cpu_device::drctg06_1, &arm7_cpu_device::drctg06_1, &arm7_cpu_device::drctg06_1, &arm7_cpu_device::drctg06_1, &arm7_cpu_device::drctg06_1, &arm7_cpu_device::drctg06_1, &arm7_cpu_device::drctg06_1, &arm7_cpu_device::drctg06_1, +//#define THUMB_LSOP_L ((UINT16)0x0800) + &arm7_cpu_device::drctg07_0, &arm7_cpu_device::drctg07_0, &arm7_cpu_device::drctg07_0, &arm7_cpu_device::drctg07_0, &arm7_cpu_device::drctg07_0, &arm7_cpu_device::drctg07_0, &arm7_cpu_device::drctg07_0, &arm7_cpu_device::drctg07_0, + &arm7_cpu_device::drctg07_0, &arm7_cpu_device::drctg07_0, &arm7_cpu_device::drctg07_0, &arm7_cpu_device::drctg07_0, &arm7_cpu_device::drctg07_0, &arm7_cpu_device::drctg07_0, &arm7_cpu_device::drctg07_0, &arm7_cpu_device::drctg07_0, + &arm7_cpu_device::drctg07_0, &arm7_cpu_device::drctg07_0, &arm7_cpu_device::drctg07_0, &arm7_cpu_device::drctg07_0, &arm7_cpu_device::drctg07_0, &arm7_cpu_device::drctg07_0, &arm7_cpu_device::drctg07_0, &arm7_cpu_device::drctg07_0, + &arm7_cpu_device::drctg07_0, &arm7_cpu_device::drctg07_0, &arm7_cpu_device::drctg07_0, &arm7_cpu_device::drctg07_0, &arm7_cpu_device::drctg07_0, &arm7_cpu_device::drctg07_0, &arm7_cpu_device::drctg07_0, &arm7_cpu_device::drctg07_0, + &arm7_cpu_device::drctg07_1, &arm7_cpu_device::drctg07_1, &arm7_cpu_device::drctg07_1, &arm7_cpu_device::drctg07_1, &arm7_cpu_device::drctg07_1, &arm7_cpu_device::drctg07_1, &arm7_cpu_device::drctg07_1, &arm7_cpu_device::drctg07_1, + &arm7_cpu_device::drctg07_1, &arm7_cpu_device::drctg07_1, &arm7_cpu_device::drctg07_1, &arm7_cpu_device::drctg07_1, &arm7_cpu_device::drctg07_1, &arm7_cpu_device::drctg07_1, &arm7_cpu_device::drctg07_1, &arm7_cpu_device::drctg07_1, + &arm7_cpu_device::drctg07_1, &arm7_cpu_device::drctg07_1, &arm7_cpu_device::drctg07_1, &arm7_cpu_device::drctg07_1, &arm7_cpu_device::drctg07_1, &arm7_cpu_device::drctg07_1, &arm7_cpu_device::drctg07_1, &arm7_cpu_device::drctg07_1, + &arm7_cpu_device::drctg07_1, &arm7_cpu_device::drctg07_1, &arm7_cpu_device::drctg07_1, &arm7_cpu_device::drctg07_1, &arm7_cpu_device::drctg07_1, &arm7_cpu_device::drctg07_1, &arm7_cpu_device::drctg07_1, &arm7_cpu_device::drctg07_1, +// #define THUMB_HALFOP_L ((UINT16)0x0800) + &arm7_cpu_device::drctg08_0, &arm7_cpu_device::drctg08_0, &arm7_cpu_device::drctg08_0, &arm7_cpu_device::drctg08_0, &arm7_cpu_device::drctg08_0, &arm7_cpu_device::drctg08_0, &arm7_cpu_device::drctg08_0, &arm7_cpu_device::drctg08_0, + &arm7_cpu_device::drctg08_0, &arm7_cpu_device::drctg08_0, &arm7_cpu_device::drctg08_0, &arm7_cpu_device::drctg08_0, &arm7_cpu_device::drctg08_0, &arm7_cpu_device::drctg08_0, &arm7_cpu_device::drctg08_0, &arm7_cpu_device::drctg08_0, + &arm7_cpu_device::drctg08_0, &arm7_cpu_device::drctg08_0, &arm7_cpu_device::drctg08_0, &arm7_cpu_device::drctg08_0, &arm7_cpu_device::drctg08_0, &arm7_cpu_device::drctg08_0, &arm7_cpu_device::drctg08_0, &arm7_cpu_device::drctg08_0, + &arm7_cpu_device::drctg08_0, &arm7_cpu_device::drctg08_0, &arm7_cpu_device::drctg08_0, &arm7_cpu_device::drctg08_0, &arm7_cpu_device::drctg08_0, &arm7_cpu_device::drctg08_0, &arm7_cpu_device::drctg08_0, &arm7_cpu_device::drctg08_0, + &arm7_cpu_device::drctg08_1, &arm7_cpu_device::drctg08_1, &arm7_cpu_device::drctg08_1, &arm7_cpu_device::drctg08_1, &arm7_cpu_device::drctg08_1, &arm7_cpu_device::drctg08_1, &arm7_cpu_device::drctg08_1, &arm7_cpu_device::drctg08_1, + &arm7_cpu_device::drctg08_1, &arm7_cpu_device::drctg08_1, &arm7_cpu_device::drctg08_1, &arm7_cpu_device::drctg08_1, &arm7_cpu_device::drctg08_1, &arm7_cpu_device::drctg08_1, &arm7_cpu_device::drctg08_1, &arm7_cpu_device::drctg08_1, + &arm7_cpu_device::drctg08_1, &arm7_cpu_device::drctg08_1, &arm7_cpu_device::drctg08_1, &arm7_cpu_device::drctg08_1, &arm7_cpu_device::drctg08_1, &arm7_cpu_device::drctg08_1, &arm7_cpu_device::drctg08_1, &arm7_cpu_device::drctg08_1, + &arm7_cpu_device::drctg08_1, &arm7_cpu_device::drctg08_1, &arm7_cpu_device::drctg08_1, &arm7_cpu_device::drctg08_1, &arm7_cpu_device::drctg08_1, &arm7_cpu_device::drctg08_1, &arm7_cpu_device::drctg08_1, &arm7_cpu_device::drctg08_1, +// #define THUMB_STACKOP_L ((UINT16)0x0800) + &arm7_cpu_device::drctg09_0, &arm7_cpu_device::drctg09_0, &arm7_cpu_device::drctg09_0, &arm7_cpu_device::drctg09_0, &arm7_cpu_device::drctg09_0, &arm7_cpu_device::drctg09_0, &arm7_cpu_device::drctg09_0, &arm7_cpu_device::drctg09_0, + &arm7_cpu_device::drctg09_0, &arm7_cpu_device::drctg09_0, &arm7_cpu_device::drctg09_0, &arm7_cpu_device::drctg09_0, &arm7_cpu_device::drctg09_0, &arm7_cpu_device::drctg09_0, &arm7_cpu_device::drctg09_0, &arm7_cpu_device::drctg09_0, + &arm7_cpu_device::drctg09_0, &arm7_cpu_device::drctg09_0, &arm7_cpu_device::drctg09_0, &arm7_cpu_device::drctg09_0, &arm7_cpu_device::drctg09_0, &arm7_cpu_device::drctg09_0, &arm7_cpu_device::drctg09_0, &arm7_cpu_device::drctg09_0, + &arm7_cpu_device::drctg09_0, &arm7_cpu_device::drctg09_0, &arm7_cpu_device::drctg09_0, &arm7_cpu_device::drctg09_0, &arm7_cpu_device::drctg09_0, &arm7_cpu_device::drctg09_0, &arm7_cpu_device::drctg09_0, &arm7_cpu_device::drctg09_0, + &arm7_cpu_device::drctg09_1, &arm7_cpu_device::drctg09_1, &arm7_cpu_device::drctg09_1, &arm7_cpu_device::drctg09_1, &arm7_cpu_device::drctg09_1, &arm7_cpu_device::drctg09_1, &arm7_cpu_device::drctg09_1, &arm7_cpu_device::drctg09_1, + &arm7_cpu_device::drctg09_1, &arm7_cpu_device::drctg09_1, &arm7_cpu_device::drctg09_1, &arm7_cpu_device::drctg09_1, &arm7_cpu_device::drctg09_1, &arm7_cpu_device::drctg09_1, &arm7_cpu_device::drctg09_1, &arm7_cpu_device::drctg09_1, + &arm7_cpu_device::drctg09_1, &arm7_cpu_device::drctg09_1, &arm7_cpu_device::drctg09_1, &arm7_cpu_device::drctg09_1, &arm7_cpu_device::drctg09_1, &arm7_cpu_device::drctg09_1, &arm7_cpu_device::drctg09_1, &arm7_cpu_device::drctg09_1, + &arm7_cpu_device::drctg09_1, &arm7_cpu_device::drctg09_1, &arm7_cpu_device::drctg09_1, &arm7_cpu_device::drctg09_1, &arm7_cpu_device::drctg09_1, &arm7_cpu_device::drctg09_1, &arm7_cpu_device::drctg09_1, &arm7_cpu_device::drctg09_1, +// #define THUMB_RELADDR_SP ((UINT16)0x0800) + &arm7_cpu_device::drctg0a_0, &arm7_cpu_device::drctg0a_0, &arm7_cpu_device::drctg0a_0, &arm7_cpu_device::drctg0a_0, &arm7_cpu_device::drctg0a_0, &arm7_cpu_device::drctg0a_0, &arm7_cpu_device::drctg0a_0, &arm7_cpu_device::drctg0a_0, + &arm7_cpu_device::drctg0a_0, &arm7_cpu_device::drctg0a_0, &arm7_cpu_device::drctg0a_0, &arm7_cpu_device::drctg0a_0, &arm7_cpu_device::drctg0a_0, &arm7_cpu_device::drctg0a_0, &arm7_cpu_device::drctg0a_0, &arm7_cpu_device::drctg0a_0, + &arm7_cpu_device::drctg0a_0, &arm7_cpu_device::drctg0a_0, &arm7_cpu_device::drctg0a_0, &arm7_cpu_device::drctg0a_0, &arm7_cpu_device::drctg0a_0, &arm7_cpu_device::drctg0a_0, &arm7_cpu_device::drctg0a_0, &arm7_cpu_device::drctg0a_0, + &arm7_cpu_device::drctg0a_0, &arm7_cpu_device::drctg0a_0, &arm7_cpu_device::drctg0a_0, &arm7_cpu_device::drctg0a_0, &arm7_cpu_device::drctg0a_0, &arm7_cpu_device::drctg0a_0, &arm7_cpu_device::drctg0a_0, &arm7_cpu_device::drctg0a_0, + &arm7_cpu_device::drctg0a_1, &arm7_cpu_device::drctg0a_1, &arm7_cpu_device::drctg0a_1, &arm7_cpu_device::drctg0a_1, &arm7_cpu_device::drctg0a_1, &arm7_cpu_device::drctg0a_1, &arm7_cpu_device::drctg0a_1, &arm7_cpu_device::drctg0a_1, + &arm7_cpu_device::drctg0a_1, &arm7_cpu_device::drctg0a_1, &arm7_cpu_device::drctg0a_1, &arm7_cpu_device::drctg0a_1, &arm7_cpu_device::drctg0a_1, &arm7_cpu_device::drctg0a_1, &arm7_cpu_device::drctg0a_1, &arm7_cpu_device::drctg0a_1, + &arm7_cpu_device::drctg0a_1, &arm7_cpu_device::drctg0a_1, &arm7_cpu_device::drctg0a_1, &arm7_cpu_device::drctg0a_1, &arm7_cpu_device::drctg0a_1, &arm7_cpu_device::drctg0a_1, &arm7_cpu_device::drctg0a_1, &arm7_cpu_device::drctg0a_1, + &arm7_cpu_device::drctg0a_1, &arm7_cpu_device::drctg0a_1, &arm7_cpu_device::drctg0a_1, &arm7_cpu_device::drctg0a_1, &arm7_cpu_device::drctg0a_1, &arm7_cpu_device::drctg0a_1, &arm7_cpu_device::drctg0a_1, &arm7_cpu_device::drctg0a_1, +// #define THUMB_STACKOP_TYPE ((UINT16)0x0f00) + &arm7_cpu_device::drctg0b_0, &arm7_cpu_device::drctg0b_0, &arm7_cpu_device::drctg0b_0, &arm7_cpu_device::drctg0b_0, &arm7_cpu_device::drctg0b_1, &arm7_cpu_device::drctg0b_1, &arm7_cpu_device::drctg0b_1, &arm7_cpu_device::drctg0b_1, + &arm7_cpu_device::drctg0b_2, &arm7_cpu_device::drctg0b_2, &arm7_cpu_device::drctg0b_2, &arm7_cpu_device::drctg0b_2, &arm7_cpu_device::drctg0b_3, &arm7_cpu_device::drctg0b_3, &arm7_cpu_device::drctg0b_3, &arm7_cpu_device::drctg0b_3, + &arm7_cpu_device::drctg0b_4, &arm7_cpu_device::drctg0b_4, &arm7_cpu_device::drctg0b_4, &arm7_cpu_device::drctg0b_4, &arm7_cpu_device::drctg0b_5, &arm7_cpu_device::drctg0b_5, &arm7_cpu_device::drctg0b_5, &arm7_cpu_device::drctg0b_5, + &arm7_cpu_device::drctg0b_6, &arm7_cpu_device::drctg0b_6, &arm7_cpu_device::drctg0b_6, &arm7_cpu_device::drctg0b_6, &arm7_cpu_device::drctg0b_7, &arm7_cpu_device::drctg0b_7, &arm7_cpu_device::drctg0b_7, &arm7_cpu_device::drctg0b_7, + &arm7_cpu_device::drctg0b_8, &arm7_cpu_device::drctg0b_8, &arm7_cpu_device::drctg0b_8, &arm7_cpu_device::drctg0b_8, &arm7_cpu_device::drctg0b_9, &arm7_cpu_device::drctg0b_9, &arm7_cpu_device::drctg0b_9, &arm7_cpu_device::drctg0b_9, + &arm7_cpu_device::drctg0b_a, &arm7_cpu_device::drctg0b_a, &arm7_cpu_device::drctg0b_a, &arm7_cpu_device::drctg0b_a, &arm7_cpu_device::drctg0b_b, &arm7_cpu_device::drctg0b_b, &arm7_cpu_device::drctg0b_b, &arm7_cpu_device::drctg0b_b, + &arm7_cpu_device::drctg0b_c, &arm7_cpu_device::drctg0b_c, &arm7_cpu_device::drctg0b_c, &arm7_cpu_device::drctg0b_c, &arm7_cpu_device::drctg0b_d, &arm7_cpu_device::drctg0b_d, &arm7_cpu_device::drctg0b_d, &arm7_cpu_device::drctg0b_d, + &arm7_cpu_device::drctg0b_e, &arm7_cpu_device::drctg0b_e, &arm7_cpu_device::drctg0b_e, &arm7_cpu_device::drctg0b_e, &arm7_cpu_device::drctg0b_f, &arm7_cpu_device::drctg0b_f, &arm7_cpu_device::drctg0b_f, &arm7_cpu_device::drctg0b_f, +// #define THUMB_MULTLS ((UINT16)0x0800) + &arm7_cpu_device::drctg0c_0, &arm7_cpu_device::drctg0c_0, &arm7_cpu_device::drctg0c_0, &arm7_cpu_device::drctg0c_0, &arm7_cpu_device::drctg0c_0, &arm7_cpu_device::drctg0c_0, &arm7_cpu_device::drctg0c_0, &arm7_cpu_device::drctg0c_0, + &arm7_cpu_device::drctg0c_0, &arm7_cpu_device::drctg0c_0, &arm7_cpu_device::drctg0c_0, &arm7_cpu_device::drctg0c_0, &arm7_cpu_device::drctg0c_0, &arm7_cpu_device::drctg0c_0, &arm7_cpu_device::drctg0c_0, &arm7_cpu_device::drctg0c_0, + &arm7_cpu_device::drctg0c_0, &arm7_cpu_device::drctg0c_0, &arm7_cpu_device::drctg0c_0, &arm7_cpu_device::drctg0c_0, &arm7_cpu_device::drctg0c_0, &arm7_cpu_device::drctg0c_0, &arm7_cpu_device::drctg0c_0, &arm7_cpu_device::drctg0c_0, + &arm7_cpu_device::drctg0c_0, &arm7_cpu_device::drctg0c_0, &arm7_cpu_device::drctg0c_0, &arm7_cpu_device::drctg0c_0, &arm7_cpu_device::drctg0c_0, &arm7_cpu_device::drctg0c_0, &arm7_cpu_device::drctg0c_0, &arm7_cpu_device::drctg0c_0, + &arm7_cpu_device::drctg0c_1, &arm7_cpu_device::drctg0c_1, &arm7_cpu_device::drctg0c_1, &arm7_cpu_device::drctg0c_1, &arm7_cpu_device::drctg0c_1, &arm7_cpu_device::drctg0c_1, &arm7_cpu_device::drctg0c_1, &arm7_cpu_device::drctg0c_1, + &arm7_cpu_device::drctg0c_1, &arm7_cpu_device::drctg0c_1, &arm7_cpu_device::drctg0c_1, &arm7_cpu_device::drctg0c_1, &arm7_cpu_device::drctg0c_1, &arm7_cpu_device::drctg0c_1, &arm7_cpu_device::drctg0c_1, &arm7_cpu_device::drctg0c_1, + &arm7_cpu_device::drctg0c_1, &arm7_cpu_device::drctg0c_1, &arm7_cpu_device::drctg0c_1, &arm7_cpu_device::drctg0c_1, &arm7_cpu_device::drctg0c_1, &arm7_cpu_device::drctg0c_1, &arm7_cpu_device::drctg0c_1, &arm7_cpu_device::drctg0c_1, + &arm7_cpu_device::drctg0c_1, &arm7_cpu_device::drctg0c_1, &arm7_cpu_device::drctg0c_1, &arm7_cpu_device::drctg0c_1, &arm7_cpu_device::drctg0c_1, &arm7_cpu_device::drctg0c_1, &arm7_cpu_device::drctg0c_1, &arm7_cpu_device::drctg0c_1, +// #define THUMB_COND_TYPE ((UINT16)0x0f00) + &arm7_cpu_device::drctg0d_0, &arm7_cpu_device::drctg0d_0, &arm7_cpu_device::drctg0d_0, &arm7_cpu_device::drctg0d_0, &arm7_cpu_device::drctg0d_1, &arm7_cpu_device::drctg0d_1, &arm7_cpu_device::drctg0d_1, &arm7_cpu_device::drctg0d_1, + &arm7_cpu_device::drctg0d_2, &arm7_cpu_device::drctg0d_2, &arm7_cpu_device::drctg0d_2, &arm7_cpu_device::drctg0d_2, &arm7_cpu_device::drctg0d_3, &arm7_cpu_device::drctg0d_3, &arm7_cpu_device::drctg0d_3, &arm7_cpu_device::drctg0d_3, + &arm7_cpu_device::drctg0d_4, &arm7_cpu_device::drctg0d_4, &arm7_cpu_device::drctg0d_4, &arm7_cpu_device::drctg0d_4, &arm7_cpu_device::drctg0d_5, &arm7_cpu_device::drctg0d_5, &arm7_cpu_device::drctg0d_5, &arm7_cpu_device::drctg0d_5, + &arm7_cpu_device::drctg0d_6, &arm7_cpu_device::drctg0d_6, &arm7_cpu_device::drctg0d_6, &arm7_cpu_device::drctg0d_6, &arm7_cpu_device::drctg0d_7, &arm7_cpu_device::drctg0d_7, &arm7_cpu_device::drctg0d_7, &arm7_cpu_device::drctg0d_7, + &arm7_cpu_device::drctg0d_8, &arm7_cpu_device::drctg0d_8, &arm7_cpu_device::drctg0d_8, &arm7_cpu_device::drctg0d_8, &arm7_cpu_device::drctg0d_9, &arm7_cpu_device::drctg0d_9, &arm7_cpu_device::drctg0d_9, &arm7_cpu_device::drctg0d_9, + &arm7_cpu_device::drctg0d_a, &arm7_cpu_device::drctg0d_a, &arm7_cpu_device::drctg0d_a, &arm7_cpu_device::drctg0d_a, &arm7_cpu_device::drctg0d_b, &arm7_cpu_device::drctg0d_b, &arm7_cpu_device::drctg0d_b, &arm7_cpu_device::drctg0d_b, + &arm7_cpu_device::drctg0d_c, &arm7_cpu_device::drctg0d_c, &arm7_cpu_device::drctg0d_c, &arm7_cpu_device::drctg0d_c, &arm7_cpu_device::drctg0d_d, &arm7_cpu_device::drctg0d_d, &arm7_cpu_device::drctg0d_d, &arm7_cpu_device::drctg0d_d, + &arm7_cpu_device::drctg0d_e, &arm7_cpu_device::drctg0d_e, &arm7_cpu_device::drctg0d_e, &arm7_cpu_device::drctg0d_e, &arm7_cpu_device::drctg0d_f, &arm7_cpu_device::drctg0d_f, &arm7_cpu_device::drctg0d_f, &arm7_cpu_device::drctg0d_f, +// #define THUMB_BLOP_LO ((UINT16)0x0800) + &arm7_cpu_device::drctg0e_0, &arm7_cpu_device::drctg0e_0, &arm7_cpu_device::drctg0e_0, &arm7_cpu_device::drctg0e_0, &arm7_cpu_device::drctg0e_0, &arm7_cpu_device::drctg0e_0, &arm7_cpu_device::drctg0e_0, &arm7_cpu_device::drctg0e_0, + &arm7_cpu_device::drctg0e_0, &arm7_cpu_device::drctg0e_0, &arm7_cpu_device::drctg0e_0, &arm7_cpu_device::drctg0e_0, &arm7_cpu_device::drctg0e_0, &arm7_cpu_device::drctg0e_0, &arm7_cpu_device::drctg0e_0, &arm7_cpu_device::drctg0e_0, + &arm7_cpu_device::drctg0e_0, &arm7_cpu_device::drctg0e_0, &arm7_cpu_device::drctg0e_0, &arm7_cpu_device::drctg0e_0, &arm7_cpu_device::drctg0e_0, &arm7_cpu_device::drctg0e_0, &arm7_cpu_device::drctg0e_0, &arm7_cpu_device::drctg0e_0, + &arm7_cpu_device::drctg0e_0, &arm7_cpu_device::drctg0e_0, &arm7_cpu_device::drctg0e_0, &arm7_cpu_device::drctg0e_0, &arm7_cpu_device::drctg0e_0, &arm7_cpu_device::drctg0e_0, &arm7_cpu_device::drctg0e_0, &arm7_cpu_device::drctg0e_0, + &arm7_cpu_device::drctg0e_1, &arm7_cpu_device::drctg0e_1, &arm7_cpu_device::drctg0e_1, &arm7_cpu_device::drctg0e_1, &arm7_cpu_device::drctg0e_1, &arm7_cpu_device::drctg0e_1, &arm7_cpu_device::drctg0e_1, &arm7_cpu_device::drctg0e_1, + &arm7_cpu_device::drctg0e_1, &arm7_cpu_device::drctg0e_1, &arm7_cpu_device::drctg0e_1, &arm7_cpu_device::drctg0e_1, &arm7_cpu_device::drctg0e_1, &arm7_cpu_device::drctg0e_1, &arm7_cpu_device::drctg0e_1, &arm7_cpu_device::drctg0e_1, + &arm7_cpu_device::drctg0e_1, &arm7_cpu_device::drctg0e_1, &arm7_cpu_device::drctg0e_1, &arm7_cpu_device::drctg0e_1, &arm7_cpu_device::drctg0e_1, &arm7_cpu_device::drctg0e_1, &arm7_cpu_device::drctg0e_1, &arm7_cpu_device::drctg0e_1, + &arm7_cpu_device::drctg0e_1, &arm7_cpu_device::drctg0e_1, &arm7_cpu_device::drctg0e_1, &arm7_cpu_device::drctg0e_1, &arm7_cpu_device::drctg0e_1, &arm7_cpu_device::drctg0e_1, &arm7_cpu_device::drctg0e_1, &arm7_cpu_device::drctg0e_1, +// #define THUMB_BLOP_LO ((UINT16)0x0800) + &arm7_cpu_device::drctg0f_0, &arm7_cpu_device::drctg0f_0, &arm7_cpu_device::drctg0f_0, &arm7_cpu_device::drctg0f_0, &arm7_cpu_device::drctg0f_0, &arm7_cpu_device::drctg0f_0, &arm7_cpu_device::drctg0f_0, &arm7_cpu_device::drctg0f_0, + &arm7_cpu_device::drctg0f_0, &arm7_cpu_device::drctg0f_0, &arm7_cpu_device::drctg0f_0, &arm7_cpu_device::drctg0f_0, &arm7_cpu_device::drctg0f_0, &arm7_cpu_device::drctg0f_0, &arm7_cpu_device::drctg0f_0, &arm7_cpu_device::drctg0f_0, + &arm7_cpu_device::drctg0f_0, &arm7_cpu_device::drctg0f_0, &arm7_cpu_device::drctg0f_0, &arm7_cpu_device::drctg0f_0, &arm7_cpu_device::drctg0f_0, &arm7_cpu_device::drctg0f_0, &arm7_cpu_device::drctg0f_0, &arm7_cpu_device::drctg0f_0, + &arm7_cpu_device::drctg0f_0, &arm7_cpu_device::drctg0f_0, &arm7_cpu_device::drctg0f_0, &arm7_cpu_device::drctg0f_0, &arm7_cpu_device::drctg0f_0, &arm7_cpu_device::drctg0f_0, &arm7_cpu_device::drctg0f_0, &arm7_cpu_device::drctg0f_0, + &arm7_cpu_device::drctg0f_1, &arm7_cpu_device::drctg0f_1, &arm7_cpu_device::drctg0f_1, &arm7_cpu_device::drctg0f_1, &arm7_cpu_device::drctg0f_1, &arm7_cpu_device::drctg0f_1, &arm7_cpu_device::drctg0f_1, &arm7_cpu_device::drctg0f_1, + &arm7_cpu_device::drctg0f_1, &arm7_cpu_device::drctg0f_1, &arm7_cpu_device::drctg0f_1, &arm7_cpu_device::drctg0f_1, &arm7_cpu_device::drctg0f_1, &arm7_cpu_device::drctg0f_1, &arm7_cpu_device::drctg0f_1, &arm7_cpu_device::drctg0f_1, + &arm7_cpu_device::drctg0f_1, &arm7_cpu_device::drctg0f_1, &arm7_cpu_device::drctg0f_1, &arm7_cpu_device::drctg0f_1, &arm7_cpu_device::drctg0f_1, &arm7_cpu_device::drctg0f_1, &arm7_cpu_device::drctg0f_1, &arm7_cpu_device::drctg0f_1, + &arm7_cpu_device::drctg0f_1, &arm7_cpu_device::drctg0f_1, &arm7_cpu_device::drctg0f_1, &arm7_cpu_device::drctg0f_1, &arm7_cpu_device::drctg0f_1, &arm7_cpu_device::drctg0f_1, &arm7_cpu_device::drctg0f_1, &arm7_cpu_device::drctg0f_1, +}; + + /* Shift operations */ + +void arm7_cpu_device::drctg00_0(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) /* Shift left */ +{ + UINT32 op = desc->opptr.l[0]; + UINT32 rs = (op & THUMB_ADDSUB_RS) >> THUMB_ADDSUB_RS_SHIFT; + UINT32 rd = (op & THUMB_ADDSUB_RD) >> THUMB_ADDSUB_RD_SHIFT; + INT32 offs = (op & THUMB_SHIFT_AMT) >> THUMB_SHIFT_AMT_SHIFT; + + UML_MOV(block, uml::I0, DRC_RS); // rrs + if (offs != 0) + { + UML_SHL(block, DRC_RD, DRC_RS, offs); + UML_AND(block, DRC_CPSR, DRC_CPSR, ~C_MASK); + UML_TEST(block, uml::I0, 1 << (31 - (offs - 1))); + UML_MOVc(block, uml::COND_NZ, uml::I1, C_MASK); + UML_MOVc(block, uml::COND_Z, uml::I1, 0); + UML_OR(block, DRC_CPSR, DRC_CPSR, uml::I1); + } + else + { + UML_MOV(block, DRC_RD, DRC_RS); + } + UML_AND(block, DRC_CPSR, DRC_CPSR, ~(Z_MASK | N_MASK)); + DRCHandleALUNZFlags(DRC_RD); + UML_OR(block, DRC_CPSR, DRC_CPSR, uml::I0); + UML_ADD(block, DRC_PC, DRC_PC, 2); +} + +void arm7_cpu_device::drctg00_1(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) /* Shift right */ +{ + UINT32 op = desc->opptr.l[0]; + UINT32 rs = (op & THUMB_ADDSUB_RS) >> THUMB_ADDSUB_RS_SHIFT; + UINT32 rd = (op & THUMB_ADDSUB_RD) >> THUMB_ADDSUB_RD_SHIFT; + INT32 offs = (op & THUMB_SHIFT_AMT) >> THUMB_SHIFT_AMT_SHIFT; + + UML_MOV(block, uml::I0, DRC_RS); // rrs + if (offs != 0) + { + UML_SHR(block, DRC_RD, DRC_RS, offs); + UML_AND(block, DRC_CPSR, DRC_CPSR, ~C_MASK); + UML_TEST(block, uml::I0, 1 << (31 - (offs - 1))); + UML_MOVc(block, uml::COND_NZ, uml::I1, C_MASK); + UML_MOVc(block, uml::COND_Z, uml::I1, 0); + UML_OR(block, DRC_CPSR, DRC_CPSR, uml::I1); + } + else + { + UML_MOV(block, DRC_RD, 0); + UML_AND(block, DRC_CPSR, DRC_CPSR, ~C_MASK); + UML_TEST(block, uml::I0, 0x80000000); + UML_MOVc(block, uml::COND_NZ, uml::I1, C_MASK); + UML_MOVc(block, uml::COND_Z, uml::I1, 0); + UML_OR(block, DRC_CPSR, DRC_CPSR, uml::I1); + } + UML_AND(block, DRC_CPSR, DRC_CPSR, ~(Z_MASK | N_MASK)); + DRCHandleALUNZFlags(DRC_RD); + UML_OR(block, DRC_CPSR, DRC_CPSR, uml::I0); + UML_ADD(block, DRC_PC, DRC_PC, 2); +} + + /* Arithmetic */ + +void arm7_cpu_device::drctg01_0(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) +{ + UINT32 op = desc->opptr.l[0]; + UINT32 rs = (op & THUMB_ADDSUB_RS) >> THUMB_ADDSUB_RS_SHIFT; + UINT32 rd = (op & THUMB_ADDSUB_RD) >> THUMB_ADDSUB_RD_SHIFT; + INT32 offs = (op & THUMB_SHIFT_AMT) >> THUMB_SHIFT_AMT_SHIFT; + + /* ASR.. */ + UML_MOV(block, uml::I0, DRC_RS); + if (offs == 0) + { + offs = 32; + } + if (offs >= 32) + { + UML_AND(block, DRC_CPSR, DRC_CPSR, ~C_MASK); + UML_SHR(block, uml::I1, uml::I0, 31); + UML_TEST(block, uml::I1, ~0); + UML_MOVc(block, uml::COND_NZ, uml::I1, C_MASK); + UML_MOVc(block, uml::COND_Z, uml::I1, 0); + UML_OR(block, DRC_CPSR, DRC_CPSR, uml::I1); + UML_TEST(block, uml::I0, 0x80000000); + UML_MOVc(block, uml::COND_NZ, DRC_RD, ~0); + UML_MOVc(block, uml::COND_Z, DRC_RD, 0); + } + else + { + UML_AND(block, DRC_CPSR, DRC_CPSR, ~C_MASK); + UML_TEST(block, uml::I0, 1 << (offs - 1)); + UML_MOVc(block, uml::COND_NZ, uml::I1, C_MASK); + UML_MOVc(block, uml::COND_Z, uml::I1, 0); + UML_OR(block, DRC_CPSR, DRC_CPSR, uml::I1); + UML_SHR(block, uml::I1, uml::I0, offs); + UML_SHL(block, uml::I2, ~0, 32 - offs); + UML_TEST(block, uml::I0, 0x80000000); + UML_MOVc(block, uml::COND_Z, uml::I2, 0); + UML_OR(block, DRC_RD, uml::I1, uml::I2); + } + UML_AND(block, DRC_CPSR, DRC_CPSR, ~(Z_MASK | N_MASK)); + DRCHandleALUNZFlags(DRC_RD); + UML_OR(block, DRC_CPSR, DRC_CPSR, uml::I0); + UML_ADD(block, DRC_PC, DRC_PC, 2); +} + +void arm7_cpu_device::drctg01_10(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) +{ + UINT32 op = desc->opptr.l[0]; + UINT32 rn = (op & THUMB_ADDSUB_RNIMM) >> THUMB_ADDSUB_RNIMM_SHIFT; + UINT32 rs = (op & THUMB_ADDSUB_RS) >> THUMB_ADDSUB_RS_SHIFT; + UINT32 rd = (op & THUMB_ADDSUB_RD) >> THUMB_ADDSUB_RD_SHIFT; + UML_ADD(block, DRC_REG(rd), DRC_REG(rs), DRC_REG(rn)); + DRCHandleThumbALUAddFlags(DRC_REG(rd), DRC_REG(rs), DRC_REG(rn)); +} + +void arm7_cpu_device::drctg01_11(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) /* SUB Rd, Rs, Rn */ +{ + UINT32 op = desc->opptr.l[0]; + UINT32 rn = (op & THUMB_ADDSUB_RNIMM) >> THUMB_ADDSUB_RNIMM_SHIFT; + UINT32 rs = (op & THUMB_ADDSUB_RS) >> THUMB_ADDSUB_RS_SHIFT; + UINT32 rd = (op & THUMB_ADDSUB_RD) >> THUMB_ADDSUB_RD_SHIFT; + UML_SUB(block, DRC_REG(rd), DRC_REG(rs), DRC_REG(rn)); + DRCHandleThumbALUSubFlags(DRC_REG(rd), DRC_REG(rs), DRC_REG(rn)); +} + +void arm7_cpu_device::drctg01_12(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) /* ADD Rd, Rs, #imm */ +{ + UINT32 op = desc->opptr.l[0]; + UINT32 imm = (op & THUMB_ADDSUB_RNIMM) >> THUMB_ADDSUB_RNIMM_SHIFT; + UINT32 rs = (op & THUMB_ADDSUB_RS) >> THUMB_ADDSUB_RS_SHIFT; + UINT32 rd = (op & THUMB_ADDSUB_RD) >> THUMB_ADDSUB_RD_SHIFT; + UML_ADD(block, DRC_REG(rd), DRC_REG(rs), imm); + DRCHandleThumbALUAddFlags(DRC_REG(rd), DRC_REG(rs), imm); +} + +void arm7_cpu_device::drctg01_13(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) /* SUB Rd, Rs, #imm */ +{ + UINT32 op = desc->opptr.l[0]; + UINT32 imm = (op & THUMB_ADDSUB_RNIMM) >> THUMB_ADDSUB_RNIMM_SHIFT; + UINT32 rs = (op & THUMB_ADDSUB_RS) >> THUMB_ADDSUB_RS_SHIFT; + UINT32 rd = (op & THUMB_ADDSUB_RD) >> THUMB_ADDSUB_RD_SHIFT; + UML_SUB(block, DRC_REG(rd), DRC_REG(rs), imm); + DRCHandleThumbALUSubFlags(DRC_REG(rd), DRC_REG(rs), imm); +} + + /* CMP / MOV */ + +void arm7_cpu_device::drctg02_0(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) +{ + UINT32 op = desc->opptr.l[0]; + UINT32 rd = (op & THUMB_INSN_IMM_RD) >> THUMB_INSN_IMM_RD_SHIFT; + UINT32 op2 = (op & THUMB_INSN_IMM); + UML_MOV(block, DRC_REG(rd), op2); + UML_AND(block, DRC_CPSR, DRC_CPSR, ~(Z_MASK | N_MASK)); + DRCHandleALUNZFlags(DRC_REG(rd)); + UML_OR(block, DRC_CPSR, DRC_CPSR, uml::I0); + UML_ADD(block, DRC_PC, DRC_PC, 2); +} + +void arm7_cpu_device::drctg02_1(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) +{ + UINT32 op = desc->opptr.l[0]; + UINT32 rn = (op & THUMB_INSN_IMM_RD) >> THUMB_INSN_IMM_RD_SHIFT; + UINT32 op2 = op & THUMB_INSN_IMM; + + UML_SUB(block, uml::I3, DRC_REG(rn), op2); + DRCHandleThumbALUSubFlags(uml::I3, DRC_REG(rn), op2); +} + + /* ADD/SUB immediate */ + +void arm7_cpu_device::drctg03_0(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) /* ADD Rd, #Offset8 */ +{ + UINT32 op = desc->opptr.l[0]; + UINT32 rn = (op & THUMB_INSN_IMM_RD) >> THUMB_INSN_IMM_RD_SHIFT; + UINT32 op2 = op & THUMB_INSN_IMM; + UINT32 rd = (op & THUMB_INSN_IMM_RD) >> THUMB_INSN_IMM_RD_SHIFT; + UML_ADD(block, DRC_REG(rd), DRC_REG(rn), op2); + DRCHandleThumbALUAddFlags(DRC_REG(rd), DRC_REG(rn), op2); +} + +void arm7_cpu_device::drctg03_1(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) /* SUB Rd, #Offset8 */ +{ + UINT32 op = desc->opptr.l[0]; + UINT32 rn = (op & THUMB_INSN_IMM_RD) >> THUMB_INSN_IMM_RD_SHIFT; + UINT32 op2 = op & THUMB_INSN_IMM; + UINT32 rd = (op & THUMB_INSN_IMM_RD) >> THUMB_INSN_IMM_RD_SHIFT; + UML_SUB(block, DRC_REG(rd), DRC_REG(rn), op2); + DRCHandleThumbALUSubFlags(DRC_REG(rd), DRC_REG(rn), op2); +} + + /* Rd & Rm instructions */ + +void arm7_cpu_device::drctg04_00_00(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) /* AND Rd, Rs */ +{ + UINT32 op = desc->opptr.l[0]; + UINT32 rs = (op & THUMB_ADDSUB_RS) >> THUMB_ADDSUB_RS_SHIFT; + UINT32 rd = (op & THUMB_ADDSUB_RD) >> THUMB_ADDSUB_RD_SHIFT; + UML_AND(block, DRC_REG(rd), DRC_REG(rd), DRC_REG(rs)); + UML_AND(block, DRC_CPSR, DRC_CPSR, ~(Z_MASK | N_MASK)); + DRCHandleALUNZFlags(DRC_REG(rd)); + UML_OR(block, DRC_CPSR, DRC_CPSR, uml::I0); + UML_ADD(block, DRC_PC, DRC_PC, 2); +} + +void arm7_cpu_device::drctg04_00_01(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) /* EOR Rd, Rs */ +{ + UINT32 op = desc->opptr.l[0]; + UINT32 rs = (op & THUMB_ADDSUB_RS) >> THUMB_ADDSUB_RS_SHIFT; + UINT32 rd = (op & THUMB_ADDSUB_RD) >> THUMB_ADDSUB_RD_SHIFT; + UML_XOR(block, DRC_REG(rd), DRC_REG(rd), DRC_REG(rs)); + UML_AND(block, DRC_CPSR, DRC_CPSR, ~(Z_MASK | N_MASK)); + DRCHandleALUNZFlags(DRC_REG(rd)); + UML_OR(block, DRC_CPSR, DRC_CPSR, uml::I0); + UML_ADD(block, DRC_PC, DRC_PC, 2); +} + +void arm7_cpu_device::drctg04_00_02(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) /* LSL Rd, Rs */ +{ + UINT32 op = desc->opptr.l[0]; + UINT32 rs = (op & THUMB_ADDSUB_RS) >> THUMB_ADDSUB_RS_SHIFT; + UINT32 rd = (op & THUMB_ADDSUB_RD) >> THUMB_ADDSUB_RD_SHIFT; + uml::code_label skip; + uml::code_label offsg32; + uml::code_label offs32; + + UML_AND(block, uml::I1, DRC_REG(rs), 0xff); + UML_AND(block, DRC_CPSR, DRC_CPSR, ~(Z_MASK | N_MASK | C_MASK)); + + UML_CMP(block, uml::I1, 0); + UML_JMPc(block, uml::COND_E, skip = compiler->labelnum++); + + UML_CMP(block, uml::I1, 32); + UML_JMPc(block, uml::COND_A, offsg32 = compiler->labelnum++); + UML_JMPc(block, uml::COND_E, offs32 = compiler->labelnum++); + + UML_SHL(block, DRC_REG(rd), DRC_REG(rd), uml::I1); + UML_SUB(block, uml::I1, uml::I1, 1); + UML_SUB(block, uml::I1, 31, uml::I1); + UML_SHL(block, uml::I1, 1, uml::I1); + UML_TEST(block, DRC_REG(rd), uml::I1); + UML_MOVc(block, uml::COND_NZ, uml::I0, C_MASK); + UML_MOVc(block, uml::COND_Z, uml::I0, 0); + UML_OR(block, DRC_CPSR, DRC_CPSR, uml::I0); + UML_JMP(block, skip); + + UML_LABEL(block, offs32); + UML_TEST(block, DRC_REG(rd), 1); + UML_MOVc(block, uml::COND_NZ, uml::I0, C_MASK); + UML_MOVc(block, uml::COND_Z, uml::I0, 0); + UML_OR(block, DRC_CPSR, DRC_CPSR, uml::I0); + UML_MOV(block, DRC_REG(rd), 0); + UML_JMP(block, skip); + + UML_LABEL(block, offsg32); + UML_MOV(block, DRC_REG(rd), 0); + + UML_LABEL(block, skip); + + DRCHandleALUNZFlags(DRC_REG(rd)); + UML_OR(block, DRC_CPSR, DRC_CPSR, uml::I0); + UML_ADD(block, DRC_PC, DRC_PC, 2); +} + +void arm7_cpu_device::drctg04_00_03(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) /* LSR Rd, Rs */ +{ + UINT32 op = desc->opptr.l[0]; + UINT32 rs = (op & THUMB_ADDSUB_RS) >> THUMB_ADDSUB_RS_SHIFT; + UINT32 rd = (op & THUMB_ADDSUB_RD) >> THUMB_ADDSUB_RD_SHIFT; + uml::code_label skip; + uml::code_label offsg32; + uml::code_label offs32; + + UML_AND(block, uml::I1, DRC_REG(rs), 0xff); + UML_AND(block, DRC_CPSR, DRC_CPSR, ~(Z_MASK | N_MASK | C_MASK)); + UML_CMP(block, uml::I1, 0); + UML_JMPc(block, uml::COND_E, skip = compiler->labelnum++); + + UML_CMP(block, uml::I1, 32); + UML_JMPc(block, uml::COND_A, offsg32 = compiler->labelnum++); + UML_JMPc(block, uml::COND_E, offs32 = compiler->labelnum++); + + UML_SHR(block, DRC_REG(rd), DRC_REG(rd), uml::I1); + UML_SUB(block, uml::I1, uml::I1, 1); // WP: TODO, Check this used to be "block, I1, 1" + UML_SHL(block, uml::I1, 1, uml::I1); + UML_TEST(block, DRC_REG(rd), uml::I1); + UML_MOVc(block, uml::COND_NZ, uml::I0, C_MASK); + UML_MOVc(block, uml::COND_Z, uml::I0, 0); + UML_OR(block, DRC_CPSR, DRC_CPSR, uml::I0); + UML_JMP(block, skip); + + UML_LABEL(block, offs32); + UML_TEST(block, DRC_REG(rd), 0x80000000); + UML_MOVc(block, uml::COND_NZ, uml::I0, C_MASK); + UML_MOVc(block, uml::COND_Z, uml::I0, 0); + UML_OR(block, DRC_CPSR, DRC_CPSR, uml::I0); + UML_MOV(block, DRC_REG(rd), 0); + UML_JMP(block, skip); + + UML_LABEL(block, offsg32); + UML_MOV(block, DRC_REG(rd), 0); + + UML_LABEL(block, skip); + + DRCHandleALUNZFlags(DRC_REG(rd)); + UML_OR(block, DRC_CPSR, DRC_CPSR, uml::I0); + UML_ADD(block, DRC_PC, DRC_PC, 2); +} + +void arm7_cpu_device::drctg04_00_04(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) /* ASR Rd, Rs */ +{ + UINT32 op = desc->opptr.l[0]; + UINT32 rs = (op & THUMB_ADDSUB_RS) >> THUMB_ADDSUB_RS_SHIFT; + UINT32 rd = (op & THUMB_ADDSUB_RD) >> THUMB_ADDSUB_RD_SHIFT; + uml::code_label skip; + uml::code_label offsg32; + uml::code_label offs32; + + UML_MOV(block, uml::I0, DRC_REG(rd)); + UML_AND(block, uml::I1, DRC_REG(rs), 0xff); + UML_AND(block, DRC_CPSR, DRC_CPSR, ~(Z_MASK | N_MASK | C_MASK)); + UML_CMP(block, uml::I1, 0); + UML_JMPc(block, uml::COND_E, skip = compiler->labelnum++); + + UML_SHR(block, uml::I2, uml::I0, uml::I1); + UML_SUB(block, uml::I1, 32, uml::I1); + UML_SHL(block, uml::I1, ~0, uml::I1); + UML_TEST(block, uml::I0, 0x80000000); + UML_MOVc(block, uml::COND_NZ, DRC_REG(rd), uml::I1); + UML_MOVc(block, uml::COND_Z, DRC_REG(rd), 0); + UML_OR(block, DRC_REG(rd), DRC_REG(rd), uml::I2); + UML_JMPc(block, uml::COND_B, offs32 = compiler->labelnum++); + + UML_TEST(block, uml::I0, 0x80000000); + UML_MOVc(block, uml::COND_NZ, DRC_REG(rd), ~0); + UML_MOVc(block, uml::COND_Z, DRC_REG(rd), 0); + UML_MOVc(block, uml::COND_NZ, uml::I1, C_MASK); + UML_MOVc(block, uml::COND_Z, uml::I1, 0); + UML_OR(block, DRC_CPSR, DRC_CPSR, uml::I1); + UML_JMP(block, skip); + + UML_LABEL(block, offs32); + UML_SUB(block, uml::I1, uml::I1, 1); + UML_SHL(block, uml::I1, 1, uml::I1); + UML_TEST(block, uml::I0, uml::I1); + UML_MOVc(block, uml::COND_NZ, uml::I1, C_MASK); + UML_MOVc(block, uml::COND_Z, uml::I1, 0); + UML_OR(block, DRC_CPSR, DRC_CPSR, uml::I1); + UML_JMP(block, skip); + + UML_LABEL(block, skip); + DRCHandleALUNZFlags(DRC_REG(rd)); + UML_OR(block, DRC_CPSR, DRC_CPSR, uml::I0); + UML_ADD(block, DRC_PC, DRC_PC, 2); + +} + +void arm7_cpu_device::drctg04_00_05(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) /* ADC Rd, Rs */ +{ + UINT32 op = desc->opptr.l[0]; + UINT32 rs = (op & THUMB_ADDSUB_RS) >> THUMB_ADDSUB_RS_SHIFT; + UINT32 rd = (op & THUMB_ADDSUB_RD) >> THUMB_ADDSUB_RD_SHIFT; + UML_TEST(block, DRC_CPSR, C_MASK); + UML_MOVc(block, uml::COND_NZ, uml::I3, 1); + UML_MOVc(block, uml::COND_Z, uml::I3, 0); + UML_ADD(block, uml::I3, uml::I3, DRC_REG(rd)); + UML_ADD(block, uml::I3, uml::I3, DRC_REG(rs)); + DRCHandleThumbALUAddFlags(uml::I3, DRC_REG(rd), DRC_REG(rs)); + UML_MOV(block, DRC_REG(rd), uml::I3); +} + +void arm7_cpu_device::drctg04_00_06(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) /* SBC Rd, Rs */ +{ + UINT32 op = desc->opptr.l[0]; + UINT32 rs = (op & THUMB_ADDSUB_RS) >> THUMB_ADDSUB_RS_SHIFT; + UINT32 rd = (op & THUMB_ADDSUB_RD) >> THUMB_ADDSUB_RD_SHIFT; + UML_TEST(block, DRC_CPSR, C_MASK); + UML_MOVc(block, uml::COND_NZ, uml::I3, 0); + UML_MOVc(block, uml::COND_Z, uml::I3, 1); + UML_SUB(block, uml::I3, DRC_REG(rs), uml::I3); + UML_ADD(block, uml::I3, DRC_REG(rd), uml::I3); + DRCHandleThumbALUSubFlags(uml::I3, DRC_REG(rd), DRC_REG(rs)); + UML_MOV(block, DRC_REG(rd), uml::I3); +} + +void arm7_cpu_device::drctg04_00_07(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) /* ROR Rd, Rs */ +{ + UINT32 op = desc->opptr.l[0]; + UINT32 rs = (op & THUMB_ADDSUB_RS) >> THUMB_ADDSUB_RS_SHIFT; + UINT32 rd = (op & THUMB_ADDSUB_RD) >> THUMB_ADDSUB_RD_SHIFT; + UML_MOV(block, uml::I0, DRC_REG(rd)); + UML_AND(block, uml::I1, DRC_REG(rs), 0x1f); + UML_SHR(block, DRC_REG(rd), uml::I0, uml::I1); + UML_SUB(block, uml::I2, 32, uml::I1); + UML_SHL(block, uml::I2, uml::I0, uml::I2); + UML_OR(block, DRC_REG(rd), DRC_REG(rd), uml::I2); + UML_SUB(block, uml::I1, uml::I1, 1); + UML_SHL(block, uml::I1, 1, uml::I1); + UML_TEST(block, uml::I0, uml::I1); + UML_MOVc(block, uml::COND_NZ, uml::I0, C_MASK); + UML_MOVc(block, uml::COND_Z, uml::I0, 0); + UML_AND(block, DRC_CPSR, DRC_CPSR, ~(Z_MASK | N_MASK | C_MASK)); + DRCHandleALUNZFlags(DRC_REG(rd)); + UML_OR(block, DRC_CPSR, DRC_CPSR, uml::I0); + UML_ADD(block, DRC_PC, DRC_PC, 2); +} + +void arm7_cpu_device::drctg04_00_08(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) /* TST Rd, Rs */ +{ + UINT32 op = desc->opptr.l[0]; + UINT32 rs = (op & THUMB_ADDSUB_RS) >> THUMB_ADDSUB_RS_SHIFT; + UINT32 rd = (op & THUMB_ADDSUB_RD) >> THUMB_ADDSUB_RD_SHIFT; + UML_AND(block, DRC_CPSR, DRC_CPSR, ~(Z_MASK | N_MASK)); + UML_AND(block, uml::I2, DRC_REG(rd), DRC_REG(rs)); + DRCHandleALUNZFlags(uml::I2); + UML_OR(block, DRC_CPSR, DRC_CPSR, uml::I0); + UML_ADD(block, DRC_PC, DRC_PC, 2); +} + +void arm7_cpu_device::drctg04_00_09(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) /* NEG Rd, Rs */ +{ + UINT32 op = desc->opptr.l[0]; + UINT32 rs = (op & THUMB_ADDSUB_RS) >> THUMB_ADDSUB_RS_SHIFT; + UINT32 rd = (op & THUMB_ADDSUB_RD) >> THUMB_ADDSUB_RD_SHIFT; + UML_MOV(block, uml::I3, DRC_REG(rs)); + UML_SUB(block, DRC_REG(rd), 0, uml::I3); + DRCHandleThumbALUSubFlags(DRC_REG(rd), 0, uml::I3); +} + +void arm7_cpu_device::drctg04_00_0a(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) /* CMP Rd, Rs */ +{ + UINT32 op = desc->opptr.l[0]; + UINT32 rs = (op & THUMB_ADDSUB_RS) >> THUMB_ADDSUB_RS_SHIFT; + UINT32 rd = (op & THUMB_ADDSUB_RD) >> THUMB_ADDSUB_RD_SHIFT; + UML_SUB(block, uml::I3, DRC_REG(rd), DRC_REG(rs)); + DRCHandleThumbALUSubFlags(uml::I3, DRC_REG(rd), DRC_REG(rs)); +} + +void arm7_cpu_device::drctg04_00_0b(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) /* CMN Rd, Rs - check flags, add dasm */ +{ + UINT32 op = desc->opptr.l[0]; + UINT32 rs = (op & THUMB_ADDSUB_RS) >> THUMB_ADDSUB_RS_SHIFT; + UINT32 rd = (op & THUMB_ADDSUB_RD) >> THUMB_ADDSUB_RD_SHIFT; + UML_ADD(block, uml::I3, DRC_REG(rd), DRC_REG(rs)); + DRCHandleThumbALUAddFlags(uml::I3, DRC_REG(rd), DRC_REG(rs)); +} + +void arm7_cpu_device::drctg04_00_0c(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) /* ORR Rd, Rs */ +{ + UINT32 op = desc->opptr.l[0]; + UINT32 rs = (op & THUMB_ADDSUB_RS) >> THUMB_ADDSUB_RS_SHIFT; + UINT32 rd = (op & THUMB_ADDSUB_RD) >> THUMB_ADDSUB_RD_SHIFT; + UML_OR(block, DRC_REG(rd), DRC_REG(rd), DRC_REG(rs)); + UML_AND(block, DRC_CPSR, DRC_CPSR, ~(Z_MASK | N_MASK)); + DRCHandleALUNZFlags(DRC_REG(rd)); + UML_OR(block, DRC_CPSR, DRC_CPSR, uml::I0); + UML_ADD(block, DRC_PC, DRC_PC, 2); +} + +void arm7_cpu_device::drctg04_00_0d(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) /* MUL Rd, Rs */ +{ + UINT32 op = desc->opptr.l[0]; + UINT32 rs = (op & THUMB_ADDSUB_RS) >> THUMB_ADDSUB_RS_SHIFT; + UINT32 rd = (op & THUMB_ADDSUB_RD) >> THUMB_ADDSUB_RD_SHIFT; + UML_AND(block, DRC_CPSR, DRC_CPSR, ~(Z_MASK | N_MASK)); + UML_MULU(block, DRC_REG(rd), uml::I1, DRC_REG(rd), DRC_REG(rs)); + DRCHandleALUNZFlags(DRC_REG(rd)); + UML_OR(block, DRC_CPSR, DRC_CPSR, uml::I0); + UML_ADD(block, DRC_PC, DRC_PC, 2); +} + +void arm7_cpu_device::drctg04_00_0e(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) /* BIC Rd, Rs */ +{ + UINT32 op = desc->opptr.l[0]; + UINT32 rs = (op & THUMB_ADDSUB_RS) >> THUMB_ADDSUB_RS_SHIFT; + UINT32 rd = (op & THUMB_ADDSUB_RD) >> THUMB_ADDSUB_RD_SHIFT; + UML_AND(block, DRC_CPSR, DRC_CPSR, ~(Z_MASK | N_MASK)); + UML_XOR(block, uml::I0, DRC_REG(rs), ~0); + UML_AND(block, DRC_REG(rd), DRC_REG(rd), uml::I0); + DRCHandleALUNZFlags(DRC_REG(rd)); + UML_OR(block, DRC_CPSR, DRC_CPSR, uml::I0); + UML_ADD(block, DRC_PC, DRC_PC, 2); +} + +void arm7_cpu_device::drctg04_00_0f(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) /* MVN Rd, Rs */ +{ + UINT32 op = desc->opptr.l[0]; + UINT32 rs = (op & THUMB_ADDSUB_RS) >> THUMB_ADDSUB_RS_SHIFT; + UINT32 rd = (op & THUMB_ADDSUB_RD) >> THUMB_ADDSUB_RD_SHIFT; + UML_XOR(block, uml::I0, DRC_REG(rs), ~0); + UML_MOV(block, DRC_REG(rd), uml::I0); + UML_AND(block, DRC_CPSR, DRC_CPSR, ~(Z_MASK | N_MASK)); + DRCHandleALUNZFlags(DRC_REG(rd)); + UML_OR(block, DRC_CPSR, DRC_CPSR, uml::I0); + UML_ADD(block, DRC_PC, DRC_PC, 2); +} + + /* ADD Rd, Rs group */ + +void arm7_cpu_device::drctg04_01_00(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) +{ + UINT32 op = desc->opptr.l[0]; + UINT32 pc = desc->pc; + fatalerror("%08x: G4-1-0 Undefined Thumb instruction: %04x %x\n", pc, op, (op & THUMB_HIREG_H) >> THUMB_HIREG_H_SHIFT); +} + +void arm7_cpu_device::drctg04_01_01(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) /* ADD Rd, HRs */ +{ + UINT32 op = desc->opptr.l[0]; + UINT32 rs = (op & THUMB_HIREG_RS) >> THUMB_HIREG_RS_SHIFT; + UINT32 rd = op & THUMB_HIREG_RD; + UML_ADD(block, DRC_REG(rd), DRC_REG(rd), DRC_REG(rs+8)); + if (rs == 7) + { + UML_ADD(block, DRC_REG(rd), DRC_REG(rd), 4); + } + UML_ADD(block, DRC_PC, DRC_PC, 2); +} + +void arm7_cpu_device::drctg04_01_02(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) /* ADD HRd, Rs */ +{ + UINT32 op = desc->opptr.l[0]; + UINT32 rs = (op & THUMB_HIREG_RS) >> THUMB_HIREG_RS_SHIFT; + UINT32 rd = op & THUMB_HIREG_RD; + UML_ADD(block, DRC_REG(rd+8), DRC_REG(rd+8), DRC_REG(rs)); + if (rd == 7) + { + UML_ADD(block, DRC_REG(rd), DRC_REG(rd), 4); + } + UML_ADD(block, DRC_PC, DRC_PC, 2); +} + +void arm7_cpu_device::drctg04_01_03(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) /* Add HRd, HRs */ +{ + UINT32 op = desc->opptr.l[0]; + UINT32 rs = (op & THUMB_HIREG_RS) >> THUMB_HIREG_RS_SHIFT; + UINT32 rd = op & THUMB_HIREG_RD; + UML_ADD(block, DRC_REG(rd+8), DRC_REG(rd+8), DRC_REG(rs+8)); + // emulate the effects of pre-fetch + if (rs == 7) + { + UML_ADD(block, DRC_REG(rd+8), DRC_REG(rd+8), 4); + } + if (rd == 7) + { + UML_ADD(block, DRC_REG(rd+8), DRC_REG(rd+8), 2); + } + UML_ADD(block, DRC_PC, DRC_PC, 2); +} + +void arm7_cpu_device::drctg04_01_10(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) /* CMP Rd, Rs */ +{ + UINT32 op = desc->opptr.l[0]; + UINT32 rs = (op & THUMB_HIREG_RS) >> THUMB_HIREG_RS_SHIFT; + UINT32 rd = op & THUMB_HIREG_RD; + UML_SUB(block, uml::I3, DRC_REG(rd), DRC_REG(rs)); + DRCHandleThumbALUSubFlags(uml::I3, DRC_REG(rd), DRC_REG(rs)); +} + +void arm7_cpu_device::drctg04_01_11(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) /* CMP Rd, Hs */ +{ + UINT32 op = desc->opptr.l[0]; + UINT32 rs = (op & THUMB_HIREG_RS) >> THUMB_HIREG_RS_SHIFT; + UINT32 rd = op & THUMB_HIREG_RD; + UML_SUB(block, uml::I3, DRC_REG(rd), DRC_REG(rs+8)); + DRCHandleThumbALUSubFlags(uml::I3, DRC_REG(rd), DRC_REG(rs+8)); +} + +void arm7_cpu_device::drctg04_01_12(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) /* CMP Hd, Rs */ +{ + UINT32 op = desc->opptr.l[0]; + UINT32 rs = (op & THUMB_HIREG_RS) >> THUMB_HIREG_RS_SHIFT; + UINT32 rd = op & THUMB_HIREG_RD; + UML_SUB(block, uml::I3, DRC_REG(rd+8), DRC_REG(rs)); + DRCHandleThumbALUSubFlags(uml::I3, DRC_REG(rd+8), DRC_REG(rs)); +} + +void arm7_cpu_device::drctg04_01_13(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) /* CMP Hd, Hs */ +{ + UINT32 op = desc->opptr.l[0]; + UINT32 rs = (op & THUMB_HIREG_RS) >> THUMB_HIREG_RS_SHIFT; + UINT32 rd = op & THUMB_HIREG_RD; + UML_SUB(block, uml::I3, DRC_REG(rd+8), DRC_REG(rs+8)); + DRCHandleThumbALUSubFlags(uml::I3, DRC_REG(rd+8), DRC_REG(rs+8)); +} + + /* MOV group */ + +void arm7_cpu_device::drctg04_01_20(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) /* MOV Rd, Rs (undefined) */ +{ + UINT32 op = desc->opptr.l[0]; + UINT32 rs = (op & THUMB_HIREG_RS) >> THUMB_HIREG_RS_SHIFT; + UINT32 rd = op & THUMB_HIREG_RD; + UML_MOV(block, DRC_REG(rd), DRC_REG(rs)); + UML_ADD(block, DRC_PC, DRC_PC, 2); +} + +void arm7_cpu_device::drctg04_01_21(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) /* MOV Rd, Hs */ +{ + UINT32 op = desc->opptr.l[0]; + UINT32 rs = (op & THUMB_HIREG_RS) >> THUMB_HIREG_RS_SHIFT; + UINT32 rd = op & THUMB_HIREG_RD; + UML_MOV(block, DRC_REG(rd), DRC_REG(rs+8)); + if (rs == 7) + { + UML_ADD(block, DRC_REG(rd), DRC_REG(rd), 4); + } + UML_ADD(block, DRC_PC, DRC_PC, 2); +} + +void arm7_cpu_device::drctg04_01_22(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) /* MOV Hd, Rs */ +{ + UINT32 op = desc->opptr.l[0]; + UINT32 rs = (op & THUMB_HIREG_RS) >> THUMB_HIREG_RS_SHIFT; + UINT32 rd = op & THUMB_HIREG_RD; + UML_MOV(block, DRC_REG(rd+8), DRC_REG(rs)); + // CHECKME + if (rd != 7) + { + UML_ADD(block, DRC_PC, DRC_PC, 2); + } + else + { + UML_AND(block, DRC_PC, DRC_PC, ~1); + } +} + +void arm7_cpu_device::drctg04_01_23(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) /* MOV Hd, Hs */ +{ + UINT32 op = desc->opptr.l[0]; + UINT32 rs = (op & THUMB_HIREG_RS) >> THUMB_HIREG_RS_SHIFT; + UINT32 rd = op & THUMB_HIREG_RD; + UML_MOV(block, DRC_REG(rd+8), DRC_REG(rs+8)); + if (rs == 7) + { + UML_ADD(block, DRC_REG(rd+8), DRC_REG(rd+8), 4); + } + if (rd != 7) + { + UML_ADD(block, DRC_PC, DRC_PC, 2); + } + else + { + UML_AND(block, DRC_PC, DRC_PC, ~1); + } + +} + +void arm7_cpu_device::drctg04_01_30(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) +{ + UINT32 op = desc->opptr.l[0]; + uml::code_label switch_state; + uml::code_label done; + UINT32 rs = (op & THUMB_HIREG_RS) >> THUMB_HIREG_RS_SHIFT; + UML_MOV(block, uml::I0, DRC_REG(rs)); + UML_TEST(block, uml::I0, 1); + UML_JMPc(block, uml::COND_Z, switch_state = compiler->labelnum++); + UML_AND(block, uml::I0, uml::I0, ~1); + UML_JMP(block, done = compiler->labelnum++); + + UML_LABEL(block, switch_state); + UML_AND(block, DRC_CPSR, DRC_CPSR, ~T_MASK); + UML_TEST(block, uml::I0, 2); + UML_MOVc(block, uml::COND_NZ, uml::I1, 2); + UML_MOVc(block, uml::COND_Z, uml::I1, 0); + UML_ADD(block, uml::I0, uml::I0, uml::I1); + + UML_LABEL(block, done); + UML_MOV(block, DRC_PC, uml::I0); +} + +void arm7_cpu_device::drctg04_01_31(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) +{ + UINT32 op = desc->opptr.l[0]; + uml::code_label switch_state; + uml::code_label done; + UINT32 rs = (op & THUMB_HIREG_RS) >> THUMB_HIREG_RS_SHIFT; + UML_MOV(block, uml::I0, DRC_REG(rs+8)); + if(rs == 7) + { + UML_ADD(block, uml::I0, uml::I0, 2); + } + UML_TEST(block, uml::I0, 1); + UML_JMPc(block, uml::COND_Z, switch_state = compiler->labelnum++); + UML_AND(block, uml::I0, uml::I0, ~1); + UML_JMP(block, done = compiler->labelnum++); + + UML_LABEL(block, switch_state); + UML_AND(block, DRC_CPSR, DRC_CPSR, ~T_MASK); + UML_TEST(block, uml::I0, 2); + UML_MOVc(block, uml::COND_NZ, uml::I1, 2); + UML_MOVc(block, uml::COND_Z, uml::I1, 0); + UML_ADD(block, uml::I0, uml::I0, uml::I1); + + UML_LABEL(block, done); + UML_MOV(block, DRC_PC, uml::I0); +} + +void arm7_cpu_device::drctg04_01_32(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) +{ + UINT32 op = desc->opptr.l[0]; + UINT32 pc = desc->pc; + fatalerror("%08x: G4-3 Undefined Thumb instruction: %04x\n", pc, op); +} + +void arm7_cpu_device::drctg04_01_33(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) +{ + UINT32 op = desc->opptr.l[0]; + UINT32 pc = desc->pc; + fatalerror("%08x: G4-3 Undefined Thumb instruction: %04x\n", pc, op); +} + +void arm7_cpu_device::drctg04_0203(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) +{ + UINT32 op = desc->opptr.l[0]; + UINT32 rd = (op & THUMB_INSN_IMM_RD) >> THUMB_INSN_IMM_RD_SHIFT; + UINT32 imm = 4 + ((op & THUMB_INSN_IMM) << 2); + UML_AND(block, uml::I0, DRC_PC, ~2); + UML_ADD(block, uml::I0, uml::I0, imm); + UML_CALLH(block, *m_impstate.read32); + UML_MOV(block, DRC_REG(rd), uml::I0); + UML_ADD(block, DRC_PC, DRC_PC, 2); +} + + /* LDR* STR* group */ + +void arm7_cpu_device::drctg05_0(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) /* STR Rd, [Rn, Rm] */ +{ + UINT32 op = desc->opptr.l[0]; + UINT32 rm = (op & THUMB_GROUP5_RM) >> THUMB_GROUP5_RM_SHIFT; + UINT32 rn = (op & THUMB_GROUP5_RN) >> THUMB_GROUP5_RN_SHIFT; + UINT32 rd = (op & THUMB_GROUP5_RD) >> THUMB_GROUP5_RD_SHIFT; + UML_MOV(block, uml::I1, DRC_REG(rd)); + UML_ADD(block, uml::I0, DRC_REG(rn), DRC_REG(rm)); + UML_CALLH(block, *m_impstate.write32); + UML_ADD(block, DRC_PC, DRC_PC, 2); +} + +void arm7_cpu_device::drctg05_1(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) /* STRH Rd, [Rn, Rm] */ +{ + UINT32 op = desc->opptr.l[0]; + UINT32 rm = (op & THUMB_GROUP5_RM) >> THUMB_GROUP5_RM_SHIFT; + UINT32 rn = (op & THUMB_GROUP5_RN) >> THUMB_GROUP5_RN_SHIFT; + UINT32 rd = (op & THUMB_GROUP5_RD) >> THUMB_GROUP5_RD_SHIFT; + UML_MOV(block, uml::I1, DRC_REG(rd)); + UML_ADD(block, uml::I0, DRC_REG(rn), DRC_REG(rm)); + UML_CALLH(block, *m_impstate.write16); + UML_ADD(block, DRC_PC, DRC_PC, 2); +} + +void arm7_cpu_device::drctg05_2(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) /* STRB Rd, [Rn, Rm] */ +{ + UINT32 op = desc->opptr.l[0]; + UINT32 rm = (op & THUMB_GROUP5_RM) >> THUMB_GROUP5_RM_SHIFT; + UINT32 rn = (op & THUMB_GROUP5_RN) >> THUMB_GROUP5_RN_SHIFT; + UINT32 rd = (op & THUMB_GROUP5_RD) >> THUMB_GROUP5_RD_SHIFT; + UML_MOV(block, uml::I1, DRC_REG(rd)); + UML_ADD(block, uml::I0, DRC_REG(rn), DRC_REG(rm)); + UML_CALLH(block, *m_impstate.write16); + UML_ADD(block, DRC_PC, DRC_PC, 2); +} + +void arm7_cpu_device::drctg05_3(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) /* LDSB Rd, [Rn, Rm] todo, add dasm */ +{ + UINT32 op = desc->opptr.l[0]; + UINT32 rm = (op & THUMB_GROUP5_RM) >> THUMB_GROUP5_RM_SHIFT; + UINT32 rn = (op & THUMB_GROUP5_RN) >> THUMB_GROUP5_RN_SHIFT; + UINT32 rd = (op & THUMB_GROUP5_RD) >> THUMB_GROUP5_RD_SHIFT; + UML_ADD(block, uml::I0, DRC_REG(rn), DRC_REG(rm)); + UML_CALLH(block, *m_impstate.read8); + UML_SEXT(block, DRC_REG(rd), uml::I0, uml::SIZE_BYTE); + UML_ADD(block, DRC_PC, DRC_PC, 2); +} + +void arm7_cpu_device::drctg05_4(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) /* LDR Rd, [Rn, Rm] */ +{ + UINT32 op = desc->opptr.l[0]; + UINT32 rm = (op & THUMB_GROUP5_RM) >> THUMB_GROUP5_RM_SHIFT; + UINT32 rn = (op & THUMB_GROUP5_RN) >> THUMB_GROUP5_RN_SHIFT; + UINT32 rd = (op & THUMB_GROUP5_RD) >> THUMB_GROUP5_RD_SHIFT; + UML_ADD(block, uml::I0, DRC_REG(rn), DRC_REG(rm)); + UML_CALLH(block, *m_impstate.read32); + UML_MOV(block, DRC_REG(rd), uml::I0); + UML_ADD(block, DRC_PC, DRC_PC, 2); +} + +void arm7_cpu_device::drctg05_5(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) /* LDRH Rd, [Rn, Rm] */ +{ + UINT32 op = desc->opptr.l[0]; + UINT32 rm = (op & THUMB_GROUP5_RM) >> THUMB_GROUP5_RM_SHIFT; + UINT32 rn = (op & THUMB_GROUP5_RN) >> THUMB_GROUP5_RN_SHIFT; + UINT32 rd = (op & THUMB_GROUP5_RD) >> THUMB_GROUP5_RD_SHIFT; + UML_ADD(block, uml::I0, DRC_REG(rn), DRC_REG(rm)); + UML_CALLH(block, *m_impstate.read16); + UML_MOV(block, DRC_REG(rd), uml::I0); + UML_ADD(block, DRC_PC, DRC_PC, 2); +} + +void arm7_cpu_device::drctg05_6(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) /* LDRB Rd, [Rn, Rm] */ +{ + UINT32 op = desc->opptr.l[0]; + UINT32 rm = (op & THUMB_GROUP5_RM) >> THUMB_GROUP5_RM_SHIFT; + UINT32 rn = (op & THUMB_GROUP5_RN) >> THUMB_GROUP5_RN_SHIFT; + UINT32 rd = (op & THUMB_GROUP5_RD) >> THUMB_GROUP5_RD_SHIFT; + UML_ADD(block, uml::I0, DRC_REG(rn), DRC_REG(rm)); + UML_CALLH(block, *m_impstate.read8); + UML_MOV(block, DRC_REG(rd), uml::I0); + UML_ADD(block, DRC_PC, DRC_PC, 2); +} + +void arm7_cpu_device::drctg05_7(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) /* LDSH Rd, [Rn, Rm] */ +{ + UINT32 op = desc->opptr.l[0]; + UINT32 rm = (op & THUMB_GROUP5_RM) >> THUMB_GROUP5_RM_SHIFT; + UINT32 rn = (op & THUMB_GROUP5_RN) >> THUMB_GROUP5_RN_SHIFT; + UINT32 rd = (op & THUMB_GROUP5_RD) >> THUMB_GROUP5_RD_SHIFT; + UML_ADD(block, uml::I0, DRC_REG(rn), DRC_REG(rm)); + UML_CALLH(block, *m_impstate.read16); + UML_SEXT(block, DRC_REG(rd), uml::I0, uml::SIZE_WORD); + UML_ADD(block, DRC_PC, DRC_PC, 2); +} + + /* Word Store w/ Immediate Offset */ + +void arm7_cpu_device::drctg06_0(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) /* Store */ +{ + UINT32 op = desc->opptr.l[0]; + UINT32 rn = (op & THUMB_ADDSUB_RS) >> THUMB_ADDSUB_RS_SHIFT; + UINT32 rd = op & THUMB_ADDSUB_RD; + INT32 offs = ((op & THUMB_LSOP_OFFS) >> THUMB_LSOP_OFFS_SHIFT) << 2; + UML_ADD(block, uml::I0, DRC_REG(rn), offs); + UML_MOV(block, uml::I1, DRC_REG(rd)); + UML_CALLH(block, *m_impstate.write32); + UML_ADD(block, DRC_PC, DRC_PC, 2); +} + +void arm7_cpu_device::drctg06_1(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) /* Load */ +{ + UINT32 op = desc->opptr.l[0]; + UINT32 rn = (op & THUMB_ADDSUB_RS) >> THUMB_ADDSUB_RS_SHIFT; + UINT32 rd = op & THUMB_ADDSUB_RD; + INT32 offs = ((op & THUMB_LSOP_OFFS) >> THUMB_LSOP_OFFS_SHIFT) << 2; + UML_ADD(block, uml::I0, DRC_REG(rn), offs); + UML_CALLH(block, *m_impstate.read32); + UML_MOV(block, DRC_REG(rd), uml::I0); + UML_ADD(block, DRC_PC, DRC_PC, 2); +} + + /* Byte Store w/ Immeidate Offset */ + +void arm7_cpu_device::drctg07_0(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) /* Store */ +{ + UINT32 op = desc->opptr.l[0]; + UINT32 rn = (op & THUMB_ADDSUB_RS) >> THUMB_ADDSUB_RS_SHIFT; + UINT32 rd = op & THUMB_ADDSUB_RD; + INT32 offs = (op & THUMB_LSOP_OFFS) >> THUMB_LSOP_OFFS_SHIFT; + UML_ADD(block, uml::I0, DRC_REG(rn), offs); + UML_MOV(block, uml::I1, DRC_REG(rd)); + UML_CALLH(block, *m_impstate.write8); + UML_ADD(block, DRC_PC, DRC_PC, 2); +} + +void arm7_cpu_device::drctg07_1(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) /* Load */ +{ + UINT32 op = desc->opptr.l[0]; + UINT32 rn = (op & THUMB_ADDSUB_RS) >> THUMB_ADDSUB_RS_SHIFT; + UINT32 rd = op & THUMB_ADDSUB_RD; + INT32 offs = (op & THUMB_LSOP_OFFS) >> THUMB_LSOP_OFFS_SHIFT; + UML_ADD(block, uml::I0, DRC_REG(rn), offs); + UML_CALLH(block, *m_impstate.read8); + UML_MOV(block, DRC_REG(rd), uml::I0); + UML_ADD(block, DRC_PC, DRC_PC, 2); +} + + /* Load/Store Halfword */ + +void arm7_cpu_device::drctg08_0(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) /* Store */ +{ + UINT32 op = desc->opptr.l[0]; + UINT32 offs = (op & THUMB_HALFOP_OFFS) >> THUMB_HALFOP_OFFS_SHIFT; + UINT32 rn = (op & THUMB_ADDSUB_RS) >> THUMB_ADDSUB_RS_SHIFT; + UINT32 rd = (op & THUMB_ADDSUB_RD) >> THUMB_ADDSUB_RD_SHIFT; + UML_ADD(block, uml::I0, DRC_REG(rn), offs << 1); + UML_MOV(block, uml::I1, DRC_REG(rd)); + UML_CALLH(block, *m_impstate.write16); + UML_ADD(block, DRC_PC, DRC_PC, 2); +} + +void arm7_cpu_device::drctg08_1(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) /* Load */ +{ + UINT32 op = desc->opptr.l[0]; + UINT32 offs = (op & THUMB_HALFOP_OFFS) >> THUMB_HALFOP_OFFS_SHIFT; + UINT32 rn = (op & THUMB_ADDSUB_RS) >> THUMB_ADDSUB_RS_SHIFT; + UINT32 rd = (op & THUMB_ADDSUB_RD) >> THUMB_ADDSUB_RD_SHIFT; + UML_ADD(block, uml::I0, DRC_REG(rn), offs << 1); + UML_CALLH(block, *m_impstate.read16); + UML_MOV(block, DRC_REG(rd), uml::I0); + UML_ADD(block, DRC_PC, DRC_PC, 2); +} + + /* Stack-Relative Load/Store */ + +void arm7_cpu_device::drctg09_0(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) /* Store */ +{ + UINT32 op = desc->opptr.l[0]; + UINT32 rd = (op & THUMB_STACKOP_RD) >> THUMB_STACKOP_RD_SHIFT; + INT32 offs = (UINT8)(op & THUMB_INSN_IMM) << 2; + UML_ADD(block, uml::I0, DRC_REG(13), offs); + UML_MOV(block, uml::I1, DRC_REG(rd)); + UML_CALLH(block, *m_impstate.write32); + UML_ADD(block, DRC_PC, DRC_PC, 2); +} + +void arm7_cpu_device::drctg09_1(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) /* Load */ +{ + UINT32 op = desc->opptr.l[0]; + UINT32 rd = (op & THUMB_STACKOP_RD) >> THUMB_STACKOP_RD_SHIFT; + UINT32 offs = (UINT8)(op & THUMB_INSN_IMM) << 2; + UML_ADD(block, uml::I0, DRC_REG(13), offs); + UML_CALLH(block, *m_impstate.read32); + UML_MOV(block, DRC_REG(rd), uml::I0); + UML_ADD(block, DRC_PC, DRC_PC, 2); +} + + /* Get relative address */ + +void arm7_cpu_device::drctg0a_0(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) /* ADD Rd, PC, #nn */ +{ + UINT32 op = desc->opptr.l[0]; + UINT32 rd = (op & THUMB_RELADDR_RD) >> THUMB_RELADDR_RD_SHIFT; + INT32 offs = (UINT8)(op & THUMB_INSN_IMM) << 2; + UML_ADD(block, uml::I0, DRC_PC, 4); + UML_AND(block, uml::I0, uml::I0, ~2); + UML_ADD(block, DRC_REG(rd), uml::I0, offs); + UML_ADD(block, DRC_PC, DRC_PC, 2); +} + +void arm7_cpu_device::drctg0a_1(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) /* ADD Rd, SP, #nn */ +{ + UINT32 op = desc->opptr.l[0]; + UINT32 rd = (op & THUMB_RELADDR_RD) >> THUMB_RELADDR_RD_SHIFT; + INT32 offs = (UINT8)(op & THUMB_INSN_IMM) << 2; + UML_ADD(block, DRC_REG(rd), DRC_REG(13), offs); + UML_ADD(block, DRC_PC, DRC_PC, 2); +} + + /* Stack-Related Opcodes */ + +void arm7_cpu_device::drctg0b_0(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) /* ADD SP, #imm */ +{ + UINT32 op = desc->opptr.l[0]; + INT32 addr = (op & THUMB_INSN_IMM); + addr &= ~THUMB_INSN_IMM_S; + addr = ((op & THUMB_INSN_IMM_S) ? -(addr << 2) : (addr << 2)); + UML_ADD(block, DRC_REG(13), DRC_REG(13), addr); + UML_ADD(block, DRC_PC, DRC_PC, 2); +} + +void arm7_cpu_device::drctg0b_1(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) +{ + UINT32 op = desc->opptr.l[0]; + UINT32 pc = desc->pc; + fatalerror("%08x: Gb Undefined Thumb instruction: %04x\n", pc, op); +} + +void arm7_cpu_device::drctg0b_2(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) +{ + UINT32 op = desc->opptr.l[0]; + UINT32 pc = desc->pc; + fatalerror("%08x: Gb Undefined Thumb instruction: %04x\n", pc, op); +} + +void arm7_cpu_device::drctg0b_3(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) +{ + UINT32 op = desc->opptr.l[0]; + UINT32 pc = desc->pc; + fatalerror("%08x: Gb Undefined Thumb instruction: %04x\n", pc, op); +} + +void arm7_cpu_device::drctg0b_4(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) /* PUSH {Rlist} */ +{ + UINT32 op = desc->opptr.l[0]; + for (INT32 offs = 7; offs >= 0; offs--) + { + if (op & (1 << offs)) + { + UML_SUB(block, DRC_REG(13), DRC_REG(13), 4); + UML_MOV(block, uml::I0, DRC_REG(13)); + UML_MOV(block, uml::I1, DRC_REG(offs)); + UML_CALLH(block, *m_impstate.write32); + } + } + UML_ADD(block, DRC_PC, DRC_PC, 2); +} + +void arm7_cpu_device::drctg0b_5(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) /* PUSH {Rlist}{LR} */ +{ + UINT32 op = desc->opptr.l[0]; + UML_SUB(block, DRC_REG(13), DRC_REG(13), 4); + UML_MOV(block, uml::I0, DRC_REG(13)); + UML_MOV(block, uml::I1, DRC_REG(14)); + UML_CALLH(block, *m_impstate.write32); + for (INT32 offs = 7; offs >= 0; offs--) + { + if (op & (1 << offs)) + { + UML_SUB(block, DRC_REG(13), DRC_REG(13), 4); + UML_MOV(block, uml::I0, DRC_REG(13)); + UML_MOV(block, uml::I1, DRC_REG(offs)); + UML_CALLH(block, *m_impstate.write32); + } + } + UML_ADD(block, DRC_PC, DRC_PC, 2); +} + +void arm7_cpu_device::drctg0b_6(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) +{ + UINT32 op = desc->opptr.l[0]; + UINT32 pc = desc->pc; + fatalerror("%08x: Gb Undefined Thumb instruction: %04x\n", pc, op); +} + +void arm7_cpu_device::drctg0b_7(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) +{ + UINT32 op = desc->opptr.l[0]; + UINT32 pc = desc->pc; + fatalerror("%08x: Gb Undefined Thumb instruction: %04x\n", pc, op); +} + +void arm7_cpu_device::drctg0b_8(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) +{ + UINT32 op = desc->opptr.l[0]; + UINT32 pc = desc->pc; + fatalerror("%08x: Gb Undefined Thumb instruction: %04x\n", pc, op); +} + +void arm7_cpu_device::drctg0b_9(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) +{ + UINT32 op = desc->opptr.l[0]; + UINT32 pc = desc->pc; + fatalerror("%08x: Gb Undefined Thumb instruction: %04x\n", pc, op); +} + +void arm7_cpu_device::drctg0b_a(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) +{ + UINT32 op = desc->opptr.l[0]; + UINT32 pc = desc->pc; + fatalerror("%08x: Gb Undefined Thumb instruction: %04x\n", pc, op); +} + +void arm7_cpu_device::drctg0b_b(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) +{ + UINT32 op = desc->opptr.l[0]; + UINT32 pc = desc->pc; + fatalerror("%08x: Gb Undefined Thumb instruction: %04x\n", pc, op); +} + +void arm7_cpu_device::drctg0b_c(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) /* POP {Rlist} */ +{ + UINT32 op = desc->opptr.l[0]; + for (INT32 offs = 0; offs < 8; offs++) + { + if (op & (1 << offs)) + { + UML_MOV(block, uml::I0, DRC_REG(13)); + UML_CALLH(block, *m_impstate.read32); + UML_MOV(block, DRC_REG(offs), uml::I0); + UML_ADD(block, DRC_REG(13), DRC_REG(13), 4); + } + } + UML_ADD(block, DRC_PC, DRC_PC, 2); +} + +void arm7_cpu_device::drctg0b_d(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) /* POP {Rlist}{PC} */ +{ + UINT32 op = desc->opptr.l[0]; + uml::code_label arch5up; + uml::code_label done; + uml::code_label switch_mode; + for (INT32 offs = 0; offs < 8; offs++) + { + if (op & (1 << offs)) + { + UML_MOV(block, uml::I0, DRC_REG(13)); + UML_CALLH(block, *m_impstate.read32); + UML_MOV(block, DRC_REG(offs), uml::I0); + UML_ADD(block, DRC_REG(13), DRC_REG(13), 4); + } + } + UML_MOV(block, uml::I0, DRC_REG(13)); + UML_CALLH(block, *m_impstate.read32); + UML_CMP(block, uml::mem(&m_archRev), 4); + UML_JMPc(block, uml::COND_A, arch5up = compiler->labelnum++); + UML_AND(block, DRC_PC, uml::I0, ~1); + + UML_LABEL(block, arch5up); + + UML_TEST(block, uml::I0, 1); + UML_JMPc(block, uml::COND_Z, switch_mode = compiler->labelnum++); + + UML_AND(block, uml::I0, uml::I0, ~1); + UML_MOV(block, DRC_PC, uml::I0); + UML_JMP(block, done); + + UML_LABEL(block, switch_mode); + UML_AND(block, DRC_CPSR, DRC_CPSR, ~T_MASK); + UML_TEST(block, uml::I0, 2); + UML_MOVc(block, uml::COND_NZ, uml::I1, 2); + UML_MOVc(block, uml::COND_Z, uml::I1, 0); + UML_ADD(block, uml::I0, uml::I0, uml::I1); + UML_MOV(block, DRC_PC, uml::I0); + + UML_LABEL(block, done); + UML_ADD(block, DRC_REG(13), DRC_REG(13), 4); +} + +void arm7_cpu_device::drctg0b_e(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) +{ + UINT32 op = desc->opptr.l[0]; + UINT32 pc = desc->pc; + fatalerror("%08x: Gb Undefined Thumb instruction: %04x\n", pc, op); +} + +void arm7_cpu_device::drctg0b_f(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) +{ + UINT32 op = desc->opptr.l[0]; + UINT32 pc = desc->pc; + fatalerror("%08x: Gb Undefined Thumb instruction: %04x\n", pc, op); +} + +/* Multiple Load/Store */ + +// "The address should normally be a word aligned quantity and non-word aligned addresses do not affect the instruction." +// "However, the bottom 2 bits of the address will appear on A[1:0] and might be interpreted by the memory system." + +// GBA "BB Ball" performs an unaligned read with A[1:0] = 2 and expects A[1] not to be ignored [BP 800B90A,(R4&3)!=0] +// GBA "Gadget Racers" performs an unaligned read with A[1:0] = 1 and expects A[0] to be ignored [BP B72,(R0&3)!=0] + +void arm7_cpu_device::drctg0c_0(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) /* Store */ +{ + UINT32 op = desc->opptr.l[0]; + UINT32 rd = (op & THUMB_MULTLS_BASE) >> THUMB_MULTLS_BASE_SHIFT; + UML_MOV(block, uml::I2, DRC_REG(rd)); + for (INT32 offs = 0; offs < 8; offs++) + { + if (op & (1 << offs)) + { + UML_AND(block, uml::I0, uml::I2, ~3); + UML_MOV(block, uml::I1, DRC_REG(offs)); + UML_CALLH(block, *m_impstate.write32); + UML_ADD(block, uml::I2, uml::I2, 4); + } + } + UML_MOV(block, DRC_REG(rd), uml::I2); + UML_ADD(block, DRC_PC, DRC_PC, 2); +} + +void arm7_cpu_device::drctg0c_1(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) /* Load */ +{ + UINT32 op = desc->opptr.l[0]; + UINT32 rd = (op & THUMB_MULTLS_BASE) >> THUMB_MULTLS_BASE_SHIFT; + int rd_in_list = op & (1 << rd); + UML_MOV(block, uml::I2, DRC_REG(rd)); + for (INT32 offs = 0; offs < 8; offs++) + { + if (op & (1 << offs)) + { + UML_AND(block, uml::I0, uml::I2, ~1); + UML_CALLH(block, *m_impstate.read32); + UML_ADD(block, uml::I2, uml::I2, 4); + } + } + if (!rd_in_list) + { + UML_MOV(block, DRC_REG(rd), uml::I2); + } + UML_ADD(block, DRC_PC, DRC_PC, 2); +} + + /* Conditional Branch */ + +void arm7_cpu_device::drctg0d_0(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) // COND_EQ: +{ + UINT32 op = desc->opptr.l[0]; + INT32 offs = ((INT8)(op & THUMB_INSN_IMM) << 1) + 4; + UML_TEST(block, DRC_CPSR, Z_MASK); + UML_MOVc(block, uml::COND_NZ, uml::I0, offs); + UML_MOVc(block, uml::COND_Z, uml::I0, 2); + UML_ADD(block, DRC_PC, DRC_PC, uml::I0); +} + +void arm7_cpu_device::drctg0d_1(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) // COND_NE: +{ + UINT32 op = desc->opptr.l[0]; + INT32 offs = ((INT8)(op & THUMB_INSN_IMM) << 1) + 4; + UML_TEST(block, DRC_CPSR, Z_MASK); + UML_MOVc(block, uml::COND_Z, uml::I0, offs); + UML_MOVc(block, uml::COND_NZ, uml::I0, 2); + UML_ADD(block, DRC_PC, DRC_PC, uml::I0); +} + +void arm7_cpu_device::drctg0d_2(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) // COND_CS: +{ + UINT32 op = desc->opptr.l[0]; + INT32 offs = ((INT8)(op & THUMB_INSN_IMM) << 1) + 4; + UML_TEST(block, DRC_CPSR, C_MASK); + UML_MOVc(block, uml::COND_NZ, uml::I0, offs); + UML_MOVc(block, uml::COND_Z, uml::I0, 2); + UML_ADD(block, DRC_PC, DRC_PC, uml::I0); +} + +void arm7_cpu_device::drctg0d_3(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) // COND_CC: +{ + UINT32 op = desc->opptr.l[0]; + INT32 offs = ((INT8)(op & THUMB_INSN_IMM) << 1) + 4; + UML_TEST(block, DRC_CPSR, C_MASK); + UML_MOVc(block, uml::COND_Z, uml::I0, offs); + UML_MOVc(block, uml::COND_NZ, uml::I0, 2); + UML_ADD(block, DRC_PC, DRC_PC, uml::I0); +} + +void arm7_cpu_device::drctg0d_4(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) // COND_MI: +{ + UINT32 op = desc->opptr.l[0]; + INT32 offs = ((INT8)(op & THUMB_INSN_IMM) << 1) + 4; + UML_TEST(block, DRC_CPSR, N_MASK); + UML_MOVc(block, uml::COND_NZ, uml::I0, offs); + UML_MOVc(block, uml::COND_Z, uml::I0, 2); + UML_ADD(block, DRC_PC, DRC_PC, uml::I0); +} + +void arm7_cpu_device::drctg0d_5(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) // COND_PL: +{ + UINT32 op = desc->opptr.l[0]; + INT32 offs = ((INT8)(op & THUMB_INSN_IMM) << 1) + 4; + UML_TEST(block, DRC_CPSR, N_MASK); + UML_MOVc(block, uml::COND_Z, uml::I0, offs); + UML_MOVc(block, uml::COND_NZ, uml::I0, 2); + UML_ADD(block, DRC_PC, DRC_PC, uml::I0); +} + +void arm7_cpu_device::drctg0d_6(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) // COND_VS: +{ + UINT32 op = desc->opptr.l[0]; + INT32 offs = ((INT8)(op & THUMB_INSN_IMM) << 1) + 4; + UML_TEST(block, DRC_CPSR, V_MASK); + UML_MOVc(block, uml::COND_NZ, uml::I0, offs); + UML_MOVc(block, uml::COND_Z, uml::I0, 2); + UML_ADD(block, DRC_PC, DRC_PC, uml::I0); +} + +void arm7_cpu_device::drctg0d_7(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) // COND_VC: +{ + UINT32 op = desc->opptr.l[0]; + INT32 offs = ((INT8)(op & THUMB_INSN_IMM) << 1) + 4; + UML_TEST(block, DRC_CPSR, V_MASK); + UML_MOVc(block, uml::COND_Z, uml::I0, offs); + UML_MOVc(block, uml::COND_NZ, uml::I0, 2); + UML_ADD(block, DRC_PC, DRC_PC, uml::I0); +} + +void arm7_cpu_device::drctg0d_8(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) // COND_HI: +{ + UINT32 op = desc->opptr.l[0]; + INT32 offs = ((INT8)(op & THUMB_INSN_IMM) << 1) + 4; + UML_TEST(block, DRC_CPSR, C_MASK); + UML_MOVc(block, uml::COND_NZ, uml::I0, 1); + UML_MOVc(block, uml::COND_Z, uml::I0, 0); + UML_TEST(block, DRC_CPSR, Z_MASK); + UML_MOVc(block, uml::COND_NZ, uml::I1, 0); + UML_MOVc(block, uml::COND_Z, uml::I1, 1); + UML_AND(block, uml::I0, uml::I0, uml::I1); + UML_TEST(block, uml::I0, 1); + UML_MOVc(block, uml::COND_NZ, uml::I0, offs); + UML_MOVc(block, uml::COND_Z, uml::I0, 2); + UML_ADD(block, DRC_PC, DRC_PC, uml::I0); +} + +void arm7_cpu_device::drctg0d_9(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) // COND_LS: +{ + UINT32 op = desc->opptr.l[0]; + INT32 offs = ((INT8)(op & THUMB_INSN_IMM) << 1) + 4; + UML_TEST(block, DRC_CPSR, C_MASK); + UML_MOVc(block, uml::COND_Z, uml::I0, 1); + UML_MOVc(block, uml::COND_NZ, uml::I0, 0); + UML_TEST(block, DRC_CPSR, Z_MASK); + UML_MOVc(block, uml::COND_Z, uml::I1, 0); + UML_MOVc(block, uml::COND_NZ, uml::I1, 1); + UML_AND(block, uml::I0, uml::I0, uml::I1); + UML_TEST(block, uml::I0, 1); + UML_MOVc(block, uml::COND_NZ, uml::I0, offs); + UML_MOVc(block, uml::COND_Z, uml::I0, 2); + UML_ADD(block, DRC_PC, DRC_PC, uml::I0); +} + +void arm7_cpu_device::drctg0d_a(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) // COND_GE: +{ + UINT32 op = desc->opptr.l[0]; + INT32 offs = ((INT8)(op & THUMB_INSN_IMM) << 1) + 4; + UML_TEST(block, DRC_CPSR, N_MASK); + UML_MOVc(block, uml::COND_Z, uml::I0, 1); + UML_MOVc(block, uml::COND_NZ, uml::I0, 0); + UML_TEST(block, DRC_CPSR, V_MASK); + UML_MOVc(block, uml::COND_Z, uml::I1, 0); + UML_MOVc(block, uml::COND_NZ, uml::I1, 1); + UML_CMP(block, uml::I0, uml::I1); + UML_MOVc(block, uml::COND_E, uml::I0, offs); + UML_MOVc(block, uml::COND_NE, uml::I0, 2); + UML_ADD(block, DRC_PC, DRC_PC, uml::I0); +} + +void arm7_cpu_device::drctg0d_b(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) // COND_LT: +{ + UINT32 op = desc->opptr.l[0]; + INT32 offs = ((INT8)(op & THUMB_INSN_IMM) << 1) + 4; + UML_TEST(block, DRC_CPSR, N_MASK); + UML_MOVc(block, uml::COND_Z, uml::I0, 1); + UML_MOVc(block, uml::COND_NZ, uml::I0, 0); + UML_TEST(block, DRC_CPSR, V_MASK); + UML_MOVc(block, uml::COND_Z, uml::I1, 0); + UML_MOVc(block, uml::COND_NZ, uml::I1, 1); + UML_CMP(block, uml::I0, uml::I1); + UML_MOVc(block, uml::COND_NE, uml::I0, offs); + UML_MOVc(block, uml::COND_E, uml::I0, 2); + UML_ADD(block, DRC_PC, DRC_PC, uml::I0); +} + +void arm7_cpu_device::drctg0d_c(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) // COND_GT: +{ + UINT32 op = desc->opptr.l[0]; + INT32 offs = ((INT8)(op & THUMB_INSN_IMM) << 1) + 4; + UML_TEST(block, DRC_CPSR, N_MASK); + UML_MOVc(block, uml::COND_Z, uml::I0, 1); + UML_MOVc(block, uml::COND_NZ, uml::I0, 0); + UML_TEST(block, DRC_CPSR, V_MASK); + UML_MOVc(block, uml::COND_Z, uml::I1, 0); + UML_MOVc(block, uml::COND_NZ, uml::I1, 1); + UML_CMP(block, uml::I0, uml::I1); + UML_MOVc(block, uml::COND_E, uml::I0, 1); + UML_MOVc(block, uml::COND_NE, uml::I0, 0); + UML_TEST(block, DRC_CPSR, Z_MASK); + UML_MOVc(block, uml::COND_NZ, uml::I1, 1); + UML_MOVc(block, uml::COND_Z, uml::I1, 0); + UML_AND(block, uml::I0, uml::I0, uml::I1); + UML_TEST(block, uml::I0, 1); + UML_MOVc(block, uml::COND_NZ, uml::I0, offs); + UML_MOVc(block, uml::COND_Z, uml::I0, 2); + UML_ADD(block, DRC_PC, DRC_PC, uml::I0); +} + +void arm7_cpu_device::drctg0d_d(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) // COND_LE: +{ + UINT32 op = desc->opptr.l[0]; + INT32 offs = ((INT8)(op & THUMB_INSN_IMM) << 1) + 4; + UML_TEST(block, DRC_CPSR, N_MASK); + UML_MOVc(block, uml::COND_Z, uml::I0, 1); + UML_MOVc(block, uml::COND_NZ, uml::I0, 0); + UML_TEST(block, DRC_CPSR, V_MASK); + UML_MOVc(block, uml::COND_Z, uml::I1, 0); + UML_MOVc(block, uml::COND_NZ, uml::I1, 1); + UML_CMP(block, uml::I0, uml::I1); + UML_MOVc(block, uml::COND_NE, uml::I0, 1); + UML_MOVc(block, uml::COND_E, uml::I0, 0); + UML_TEST(block, DRC_CPSR, Z_MASK); + UML_MOVc(block, uml::COND_NZ, uml::I1, 0); + UML_MOVc(block, uml::COND_Z, uml::I1, 1); + UML_AND(block, uml::I0, uml::I0, uml::I1); + UML_TEST(block, uml::I0, 1); + UML_MOVc(block, uml::COND_NZ, uml::I0, offs); + UML_MOVc(block, uml::COND_Z, uml::I0, 2); + UML_ADD(block, DRC_PC, DRC_PC, uml::I0); +} + +void arm7_cpu_device::drctg0d_e(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) // COND_AL: +{ + UINT32 op = desc->opptr.l[0]; + UINT32 pc = desc->pc; + fatalerror("%08x: Undefined Thumb instruction: %04x (ARM9 reserved)\n", pc, op); +} + +void arm7_cpu_device::drctg0d_f(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) // SWI (this is sort of a "hole" in the opcode encoding) +{ + UML_MOV(block, uml::mem(&m_pendingSwi), 1); + UML_CALLH(block, *m_impstate.check_irq); +} + + /* B #offs */ + +void arm7_cpu_device::drctg0e_0(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) +{ + UINT32 op = desc->opptr.l[0]; + INT32 offs = (op & THUMB_BRANCH_OFFS) << 1; + if (offs & 0x00000800) + { + offs |= 0xfffff800; + } + UML_ADD(block, DRC_PC, DRC_PC, offs + 4); +} + +void arm7_cpu_device::drctg0e_1(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) +{ + UINT32 op = desc->opptr.l[0]; + UINT32 offs = (op & THUMB_BLOP_OFFS) << 1; + UML_MOV(block, uml::I0, DRC_REG(14)); + UML_ADD(block, uml::I0, uml::I0, offs); + UML_AND(block, uml::I0, uml::I0, ~3); + UML_ADD(block, DRC_REG(14), DRC_PC, 4); + UML_OR(block, DRC_REG(14), DRC_REG(14), 1); + UML_MOV(block, DRC_PC, uml::I0); +} + + /* BL */ + +void arm7_cpu_device::drctg0f_0(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) +{ + UINT32 op = desc->opptr.l[0]; + UINT32 addr = (op & THUMB_BLOP_OFFS) << 12; + if (addr & (1 << 22)) + { + addr |= 0xff800000; + } + addr += 4; + UML_ADD(block, DRC_REG(14), DRC_PC, addr); + UML_ADD(block, DRC_PC, DRC_PC, 2); +} + +void arm7_cpu_device::drctg0f_1(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) /* BL */ +{ + UINT32 op = desc->opptr.l[0]; + UINT32 addr = (op & THUMB_BLOP_OFFS) << 1; + UML_AND(block, uml::I0, DRC_REG(14), ~1); + UML_ADD(block, uml::I0, uml::I0, addr); + UML_ADD(block, DRC_REG(14), DRC_PC, 2); + UML_OR(block, DRC_REG(14), DRC_REG(14), 1); + UML_MOV(block, DRC_PC, uml::I0); +} diff --git a/src/devices/cpu/arm7/arm7thmb.c b/src/devices/cpu/arm7/arm7thmb.c new file mode 100644 index 00000000000..3dfd46094aa --- /dev/null +++ b/src/devices/cpu/arm7/arm7thmb.c @@ -0,0 +1,1587 @@ +// license:BSD-3-Clause +// copyright-holders:Steve Ellenoff,R. Belmont,Ryan Holtz +#include "emu.h" +#include "arm7.h" +#include "arm7core.h" +#include "arm7help.h" + +// this is our master dispatch jump table for THUMB mode, representing [(INSN & 0xffc0) >> 6] bits of the 16-bit decoded instruction +const arm7_cpu_device::arm7thumb_ophandler arm7_cpu_device::thumb_handler[0x40*0x10] = +{ +// #define THUMB_SHIFT_R ((UINT16)0x0800) + &arm7_cpu_device::tg00_0, &arm7_cpu_device::tg00_0, &arm7_cpu_device::tg00_0, &arm7_cpu_device::tg00_0, + &arm7_cpu_device::tg00_0, &arm7_cpu_device::tg00_0, &arm7_cpu_device::tg00_0, &arm7_cpu_device::tg00_0, + &arm7_cpu_device::tg00_0, &arm7_cpu_device::tg00_0, &arm7_cpu_device::tg00_0, &arm7_cpu_device::tg00_0, + &arm7_cpu_device::tg00_0, &arm7_cpu_device::tg00_0, &arm7_cpu_device::tg00_0, &arm7_cpu_device::tg00_0, + &arm7_cpu_device::tg00_0, &arm7_cpu_device::tg00_0, &arm7_cpu_device::tg00_0, &arm7_cpu_device::tg00_0, + &arm7_cpu_device::tg00_0, &arm7_cpu_device::tg00_0, &arm7_cpu_device::tg00_0, &arm7_cpu_device::tg00_0, + &arm7_cpu_device::tg00_0, &arm7_cpu_device::tg00_0, &arm7_cpu_device::tg00_0, &arm7_cpu_device::tg00_0, + &arm7_cpu_device::tg00_0, &arm7_cpu_device::tg00_0, &arm7_cpu_device::tg00_0, &arm7_cpu_device::tg00_0, + &arm7_cpu_device::tg00_1, &arm7_cpu_device::tg00_1, &arm7_cpu_device::tg00_1, &arm7_cpu_device::tg00_1, + &arm7_cpu_device::tg00_1, &arm7_cpu_device::tg00_1, &arm7_cpu_device::tg00_1, &arm7_cpu_device::tg00_1, + &arm7_cpu_device::tg00_1, &arm7_cpu_device::tg00_1, &arm7_cpu_device::tg00_1, &arm7_cpu_device::tg00_1, + &arm7_cpu_device::tg00_1, &arm7_cpu_device::tg00_1, &arm7_cpu_device::tg00_1, &arm7_cpu_device::tg00_1, + &arm7_cpu_device::tg00_1, &arm7_cpu_device::tg00_1, &arm7_cpu_device::tg00_1, &arm7_cpu_device::tg00_1, + &arm7_cpu_device::tg00_1, &arm7_cpu_device::tg00_1, &arm7_cpu_device::tg00_1, &arm7_cpu_device::tg00_1, + &arm7_cpu_device::tg00_1, &arm7_cpu_device::tg00_1, &arm7_cpu_device::tg00_1, &arm7_cpu_device::tg00_1, + &arm7_cpu_device::tg00_1, &arm7_cpu_device::tg00_1, &arm7_cpu_device::tg00_1, &arm7_cpu_device::tg00_1, +// #define THUMB_INSN_ADDSUB ((UINT16)0x0800) // #define THUMB_ADDSUB_TYPE ((UINT16)0x0600) + &arm7_cpu_device::tg01_0, &arm7_cpu_device::tg01_0, &arm7_cpu_device::tg01_0, &arm7_cpu_device::tg01_0, + &arm7_cpu_device::tg01_0, &arm7_cpu_device::tg01_0, &arm7_cpu_device::tg01_0, &arm7_cpu_device::tg01_0, + &arm7_cpu_device::tg01_0, &arm7_cpu_device::tg01_0, &arm7_cpu_device::tg01_0, &arm7_cpu_device::tg01_0, + &arm7_cpu_device::tg01_0, &arm7_cpu_device::tg01_0, &arm7_cpu_device::tg01_0, &arm7_cpu_device::tg01_0, + &arm7_cpu_device::tg01_0, &arm7_cpu_device::tg01_0, &arm7_cpu_device::tg01_0, &arm7_cpu_device::tg01_0, + &arm7_cpu_device::tg01_0, &arm7_cpu_device::tg01_0, &arm7_cpu_device::tg01_0, &arm7_cpu_device::tg01_0, + &arm7_cpu_device::tg01_0, &arm7_cpu_device::tg01_0, &arm7_cpu_device::tg01_0, &arm7_cpu_device::tg01_0, + &arm7_cpu_device::tg01_0, &arm7_cpu_device::tg01_0, &arm7_cpu_device::tg01_0, &arm7_cpu_device::tg01_0, + &arm7_cpu_device::tg01_10, &arm7_cpu_device::tg01_10, &arm7_cpu_device::tg01_10, &arm7_cpu_device::tg01_10, + &arm7_cpu_device::tg01_10, &arm7_cpu_device::tg01_10, &arm7_cpu_device::tg01_10, &arm7_cpu_device::tg01_10, + &arm7_cpu_device::tg01_11, &arm7_cpu_device::tg01_11, &arm7_cpu_device::tg01_11, &arm7_cpu_device::tg01_11, + &arm7_cpu_device::tg01_11, &arm7_cpu_device::tg01_11, &arm7_cpu_device::tg01_11, &arm7_cpu_device::tg01_11, + &arm7_cpu_device::tg01_12, &arm7_cpu_device::tg01_12, &arm7_cpu_device::tg01_12, &arm7_cpu_device::tg01_12, + &arm7_cpu_device::tg01_12, &arm7_cpu_device::tg01_12, &arm7_cpu_device::tg01_12, &arm7_cpu_device::tg01_12, + &arm7_cpu_device::tg01_13, &arm7_cpu_device::tg01_13, &arm7_cpu_device::tg01_13, &arm7_cpu_device::tg01_13, + &arm7_cpu_device::tg01_13, &arm7_cpu_device::tg01_13, &arm7_cpu_device::tg01_13, &arm7_cpu_device::tg01_13, +// #define THUMB_INSN_CMP ((UINT16)0x0800) + &arm7_cpu_device::tg02_0, &arm7_cpu_device::tg02_0, &arm7_cpu_device::tg02_0, &arm7_cpu_device::tg02_0, + &arm7_cpu_device::tg02_0, &arm7_cpu_device::tg02_0, &arm7_cpu_device::tg02_0, &arm7_cpu_device::tg02_0, + &arm7_cpu_device::tg02_0, &arm7_cpu_device::tg02_0, &arm7_cpu_device::tg02_0, &arm7_cpu_device::tg02_0, + &arm7_cpu_device::tg02_0, &arm7_cpu_device::tg02_0, &arm7_cpu_device::tg02_0, &arm7_cpu_device::tg02_0, + &arm7_cpu_device::tg02_0, &arm7_cpu_device::tg02_0, &arm7_cpu_device::tg02_0, &arm7_cpu_device::tg02_0, + &arm7_cpu_device::tg02_0, &arm7_cpu_device::tg02_0, &arm7_cpu_device::tg02_0, &arm7_cpu_device::tg02_0, + &arm7_cpu_device::tg02_0, &arm7_cpu_device::tg02_0, &arm7_cpu_device::tg02_0, &arm7_cpu_device::tg02_0, + &arm7_cpu_device::tg02_0, &arm7_cpu_device::tg02_0, &arm7_cpu_device::tg02_0, &arm7_cpu_device::tg02_0, + &arm7_cpu_device::tg02_1, &arm7_cpu_device::tg02_1, &arm7_cpu_device::tg02_1, &arm7_cpu_device::tg02_1, + &arm7_cpu_device::tg02_1, &arm7_cpu_device::tg02_1, &arm7_cpu_device::tg02_1, &arm7_cpu_device::tg02_1, + &arm7_cpu_device::tg02_1, &arm7_cpu_device::tg02_1, &arm7_cpu_device::tg02_1, &arm7_cpu_device::tg02_1, + &arm7_cpu_device::tg02_1, &arm7_cpu_device::tg02_1, &arm7_cpu_device::tg02_1, &arm7_cpu_device::tg02_1, + &arm7_cpu_device::tg02_1, &arm7_cpu_device::tg02_1, &arm7_cpu_device::tg02_1, &arm7_cpu_device::tg02_1, + &arm7_cpu_device::tg02_1, &arm7_cpu_device::tg02_1, &arm7_cpu_device::tg02_1, &arm7_cpu_device::tg02_1, + &arm7_cpu_device::tg02_1, &arm7_cpu_device::tg02_1, &arm7_cpu_device::tg02_1, &arm7_cpu_device::tg02_1, + &arm7_cpu_device::tg02_1, &arm7_cpu_device::tg02_1, &arm7_cpu_device::tg02_1, &arm7_cpu_device::tg02_1, +// #define THUMB_INSN_SUB ((UINT16)0x0800) + &arm7_cpu_device::tg03_0, &arm7_cpu_device::tg03_0, &arm7_cpu_device::tg03_0, &arm7_cpu_device::tg03_0, + &arm7_cpu_device::tg03_0, &arm7_cpu_device::tg03_0, &arm7_cpu_device::tg03_0, &arm7_cpu_device::tg03_0, + &arm7_cpu_device::tg03_0, &arm7_cpu_device::tg03_0, &arm7_cpu_device::tg03_0, &arm7_cpu_device::tg03_0, + &arm7_cpu_device::tg03_0, &arm7_cpu_device::tg03_0, &arm7_cpu_device::tg03_0, &arm7_cpu_device::tg03_0, + &arm7_cpu_device::tg03_0, &arm7_cpu_device::tg03_0, &arm7_cpu_device::tg03_0, &arm7_cpu_device::tg03_0, + &arm7_cpu_device::tg03_0, &arm7_cpu_device::tg03_0, &arm7_cpu_device::tg03_0, &arm7_cpu_device::tg03_0, + &arm7_cpu_device::tg03_0, &arm7_cpu_device::tg03_0, &arm7_cpu_device::tg03_0, &arm7_cpu_device::tg03_0, + &arm7_cpu_device::tg03_0, &arm7_cpu_device::tg03_0, &arm7_cpu_device::tg03_0, &arm7_cpu_device::tg03_0, + &arm7_cpu_device::tg03_1, &arm7_cpu_device::tg03_1, &arm7_cpu_device::tg03_1, &arm7_cpu_device::tg03_1, + &arm7_cpu_device::tg03_1, &arm7_cpu_device::tg03_1, &arm7_cpu_device::tg03_1, &arm7_cpu_device::tg03_1, + &arm7_cpu_device::tg03_1, &arm7_cpu_device::tg03_1, &arm7_cpu_device::tg03_1, &arm7_cpu_device::tg03_1, + &arm7_cpu_device::tg03_1, &arm7_cpu_device::tg03_1, &arm7_cpu_device::tg03_1, &arm7_cpu_device::tg03_1, + &arm7_cpu_device::tg03_1, &arm7_cpu_device::tg03_1, &arm7_cpu_device::tg03_1, &arm7_cpu_device::tg03_1, + &arm7_cpu_device::tg03_1, &arm7_cpu_device::tg03_1, &arm7_cpu_device::tg03_1, &arm7_cpu_device::tg03_1, + &arm7_cpu_device::tg03_1, &arm7_cpu_device::tg03_1, &arm7_cpu_device::tg03_1, &arm7_cpu_device::tg03_1, + &arm7_cpu_device::tg03_1, &arm7_cpu_device::tg03_1, &arm7_cpu_device::tg03_1, &arm7_cpu_device::tg03_1, +//#define THUMB_GROUP4_TYPE ((UINT16)0x0c00) //#define THUMB_ALUOP_TYPE ((UINT16)0x03c0) // #define THUMB_HIREG_OP ((UINT16)0x0300) // #define THUMB_HIREG_H ((UINT16)0x00c0) + &arm7_cpu_device::tg04_00_00, &arm7_cpu_device::tg04_00_01, &arm7_cpu_device::tg04_00_02, &arm7_cpu_device::tg04_00_03, + &arm7_cpu_device::tg04_00_04, &arm7_cpu_device::tg04_00_05, &arm7_cpu_device::tg04_00_06, &arm7_cpu_device::tg04_00_07, + &arm7_cpu_device::tg04_00_08, &arm7_cpu_device::tg04_00_09, &arm7_cpu_device::tg04_00_0a, &arm7_cpu_device::tg04_00_0b, + &arm7_cpu_device::tg04_00_0c, &arm7_cpu_device::tg04_00_0d, &arm7_cpu_device::tg04_00_0e, &arm7_cpu_device::tg04_00_0f, + &arm7_cpu_device::tg04_01_00, &arm7_cpu_device::tg04_01_01, &arm7_cpu_device::tg04_01_02, &arm7_cpu_device::tg04_01_03, + &arm7_cpu_device::tg04_01_10, &arm7_cpu_device::tg04_01_11, &arm7_cpu_device::tg04_01_12, &arm7_cpu_device::tg04_01_13, + &arm7_cpu_device::tg04_01_20, &arm7_cpu_device::tg04_01_21, &arm7_cpu_device::tg04_01_22, &arm7_cpu_device::tg04_01_23, + &arm7_cpu_device::tg04_01_30, &arm7_cpu_device::tg04_01_31, &arm7_cpu_device::tg04_01_32, &arm7_cpu_device::tg04_01_33, + &arm7_cpu_device::tg04_0203, &arm7_cpu_device::tg04_0203, &arm7_cpu_device::tg04_0203, &arm7_cpu_device::tg04_0203, + &arm7_cpu_device::tg04_0203, &arm7_cpu_device::tg04_0203, &arm7_cpu_device::tg04_0203, &arm7_cpu_device::tg04_0203, + &arm7_cpu_device::tg04_0203, &arm7_cpu_device::tg04_0203, &arm7_cpu_device::tg04_0203, &arm7_cpu_device::tg04_0203, + &arm7_cpu_device::tg04_0203, &arm7_cpu_device::tg04_0203, &arm7_cpu_device::tg04_0203, &arm7_cpu_device::tg04_0203, + &arm7_cpu_device::tg04_0203, &arm7_cpu_device::tg04_0203, &arm7_cpu_device::tg04_0203, &arm7_cpu_device::tg04_0203, + &arm7_cpu_device::tg04_0203, &arm7_cpu_device::tg04_0203, &arm7_cpu_device::tg04_0203, &arm7_cpu_device::tg04_0203, + &arm7_cpu_device::tg04_0203, &arm7_cpu_device::tg04_0203, &arm7_cpu_device::tg04_0203, &arm7_cpu_device::tg04_0203, + &arm7_cpu_device::tg04_0203, &arm7_cpu_device::tg04_0203, &arm7_cpu_device::tg04_0203, &arm7_cpu_device::tg04_0203, +//#define THUMB_GROUP5_TYPE ((UINT16)0x0e00) + &arm7_cpu_device::tg05_0, &arm7_cpu_device::tg05_0, &arm7_cpu_device::tg05_0, &arm7_cpu_device::tg05_0, + &arm7_cpu_device::tg05_0, &arm7_cpu_device::tg05_0, &arm7_cpu_device::tg05_0, &arm7_cpu_device::tg05_0, + &arm7_cpu_device::tg05_1, &arm7_cpu_device::tg05_1, &arm7_cpu_device::tg05_1, &arm7_cpu_device::tg05_1, + &arm7_cpu_device::tg05_1, &arm7_cpu_device::tg05_1, &arm7_cpu_device::tg05_1, &arm7_cpu_device::tg05_1, + &arm7_cpu_device::tg05_2, &arm7_cpu_device::tg05_2, &arm7_cpu_device::tg05_2, &arm7_cpu_device::tg05_2, + &arm7_cpu_device::tg05_2, &arm7_cpu_device::tg05_2, &arm7_cpu_device::tg05_2, &arm7_cpu_device::tg05_2, + &arm7_cpu_device::tg05_3, &arm7_cpu_device::tg05_3, &arm7_cpu_device::tg05_3, &arm7_cpu_device::tg05_3, + &arm7_cpu_device::tg05_3, &arm7_cpu_device::tg05_3, &arm7_cpu_device::tg05_3, &arm7_cpu_device::tg05_3, + &arm7_cpu_device::tg05_4, &arm7_cpu_device::tg05_4, &arm7_cpu_device::tg05_4, &arm7_cpu_device::tg05_4, + &arm7_cpu_device::tg05_4, &arm7_cpu_device::tg05_4, &arm7_cpu_device::tg05_4, &arm7_cpu_device::tg05_4, + &arm7_cpu_device::tg05_5, &arm7_cpu_device::tg05_5, &arm7_cpu_device::tg05_5, &arm7_cpu_device::tg05_5, + &arm7_cpu_device::tg05_5, &arm7_cpu_device::tg05_5, &arm7_cpu_device::tg05_5, &arm7_cpu_device::tg05_5, + &arm7_cpu_device::tg05_6, &arm7_cpu_device::tg05_6, &arm7_cpu_device::tg05_6, &arm7_cpu_device::tg05_6, + &arm7_cpu_device::tg05_6, &arm7_cpu_device::tg05_6, &arm7_cpu_device::tg05_6, &arm7_cpu_device::tg05_6, + &arm7_cpu_device::tg05_7, &arm7_cpu_device::tg05_7, &arm7_cpu_device::tg05_7, &arm7_cpu_device::tg05_7, + &arm7_cpu_device::tg05_7, &arm7_cpu_device::tg05_7, &arm7_cpu_device::tg05_7, &arm7_cpu_device::tg05_7, +//#define THUMB_LSOP_L ((UINT16)0x0800) + &arm7_cpu_device::tg06_0, &arm7_cpu_device::tg06_0, &arm7_cpu_device::tg06_0, &arm7_cpu_device::tg06_0, + &arm7_cpu_device::tg06_0, &arm7_cpu_device::tg06_0, &arm7_cpu_device::tg06_0, &arm7_cpu_device::tg06_0, + &arm7_cpu_device::tg06_0, &arm7_cpu_device::tg06_0, &arm7_cpu_device::tg06_0, &arm7_cpu_device::tg06_0, + &arm7_cpu_device::tg06_0, &arm7_cpu_device::tg06_0, &arm7_cpu_device::tg06_0, &arm7_cpu_device::tg06_0, + &arm7_cpu_device::tg06_0, &arm7_cpu_device::tg06_0, &arm7_cpu_device::tg06_0, &arm7_cpu_device::tg06_0, + &arm7_cpu_device::tg06_0, &arm7_cpu_device::tg06_0, &arm7_cpu_device::tg06_0, &arm7_cpu_device::tg06_0, + &arm7_cpu_device::tg06_0, &arm7_cpu_device::tg06_0, &arm7_cpu_device::tg06_0, &arm7_cpu_device::tg06_0, + &arm7_cpu_device::tg06_0, &arm7_cpu_device::tg06_0, &arm7_cpu_device::tg06_0, &arm7_cpu_device::tg06_0, + &arm7_cpu_device::tg06_1, &arm7_cpu_device::tg06_1, &arm7_cpu_device::tg06_1, &arm7_cpu_device::tg06_1, + &arm7_cpu_device::tg06_1, &arm7_cpu_device::tg06_1, &arm7_cpu_device::tg06_1, &arm7_cpu_device::tg06_1, + &arm7_cpu_device::tg06_1, &arm7_cpu_device::tg06_1, &arm7_cpu_device::tg06_1, &arm7_cpu_device::tg06_1, + &arm7_cpu_device::tg06_1, &arm7_cpu_device::tg06_1, &arm7_cpu_device::tg06_1, &arm7_cpu_device::tg06_1, + &arm7_cpu_device::tg06_1, &arm7_cpu_device::tg06_1, &arm7_cpu_device::tg06_1, &arm7_cpu_device::tg06_1, + &arm7_cpu_device::tg06_1, &arm7_cpu_device::tg06_1, &arm7_cpu_device::tg06_1, &arm7_cpu_device::tg06_1, + &arm7_cpu_device::tg06_1, &arm7_cpu_device::tg06_1, &arm7_cpu_device::tg06_1, &arm7_cpu_device::tg06_1, + &arm7_cpu_device::tg06_1, &arm7_cpu_device::tg06_1, &arm7_cpu_device::tg06_1, &arm7_cpu_device::tg06_1, +//#define THUMB_LSOP_L ((UINT16)0x0800) + &arm7_cpu_device::tg07_0, &arm7_cpu_device::tg07_0, &arm7_cpu_device::tg07_0, &arm7_cpu_device::tg07_0, + &arm7_cpu_device::tg07_0, &arm7_cpu_device::tg07_0, &arm7_cpu_device::tg07_0, &arm7_cpu_device::tg07_0, + &arm7_cpu_device::tg07_0, &arm7_cpu_device::tg07_0, &arm7_cpu_device::tg07_0, &arm7_cpu_device::tg07_0, + &arm7_cpu_device::tg07_0, &arm7_cpu_device::tg07_0, &arm7_cpu_device::tg07_0, &arm7_cpu_device::tg07_0, + &arm7_cpu_device::tg07_0, &arm7_cpu_device::tg07_0, &arm7_cpu_device::tg07_0, &arm7_cpu_device::tg07_0, + &arm7_cpu_device::tg07_0, &arm7_cpu_device::tg07_0, &arm7_cpu_device::tg07_0, &arm7_cpu_device::tg07_0, + &arm7_cpu_device::tg07_0, &arm7_cpu_device::tg07_0, &arm7_cpu_device::tg07_0, &arm7_cpu_device::tg07_0, + &arm7_cpu_device::tg07_0, &arm7_cpu_device::tg07_0, &arm7_cpu_device::tg07_0, &arm7_cpu_device::tg07_0, + &arm7_cpu_device::tg07_1, &arm7_cpu_device::tg07_1, &arm7_cpu_device::tg07_1, &arm7_cpu_device::tg07_1, + &arm7_cpu_device::tg07_1, &arm7_cpu_device::tg07_1, &arm7_cpu_device::tg07_1, &arm7_cpu_device::tg07_1, + &arm7_cpu_device::tg07_1, &arm7_cpu_device::tg07_1, &arm7_cpu_device::tg07_1, &arm7_cpu_device::tg07_1, + &arm7_cpu_device::tg07_1, &arm7_cpu_device::tg07_1, &arm7_cpu_device::tg07_1, &arm7_cpu_device::tg07_1, + &arm7_cpu_device::tg07_1, &arm7_cpu_device::tg07_1, &arm7_cpu_device::tg07_1, &arm7_cpu_device::tg07_1, + &arm7_cpu_device::tg07_1, &arm7_cpu_device::tg07_1, &arm7_cpu_device::tg07_1, &arm7_cpu_device::tg07_1, + &arm7_cpu_device::tg07_1, &arm7_cpu_device::tg07_1, &arm7_cpu_device::tg07_1, &arm7_cpu_device::tg07_1, + &arm7_cpu_device::tg07_1, &arm7_cpu_device::tg07_1, &arm7_cpu_device::tg07_1, &arm7_cpu_device::tg07_1, +// #define THUMB_HALFOP_L ((UINT16)0x0800) + &arm7_cpu_device::tg08_0, &arm7_cpu_device::tg08_0, &arm7_cpu_device::tg08_0, &arm7_cpu_device::tg08_0, + &arm7_cpu_device::tg08_0, &arm7_cpu_device::tg08_0, &arm7_cpu_device::tg08_0, &arm7_cpu_device::tg08_0, + &arm7_cpu_device::tg08_0, &arm7_cpu_device::tg08_0, &arm7_cpu_device::tg08_0, &arm7_cpu_device::tg08_0, + &arm7_cpu_device::tg08_0, &arm7_cpu_device::tg08_0, &arm7_cpu_device::tg08_0, &arm7_cpu_device::tg08_0, + &arm7_cpu_device::tg08_0, &arm7_cpu_device::tg08_0, &arm7_cpu_device::tg08_0, &arm7_cpu_device::tg08_0, + &arm7_cpu_device::tg08_0, &arm7_cpu_device::tg08_0, &arm7_cpu_device::tg08_0, &arm7_cpu_device::tg08_0, + &arm7_cpu_device::tg08_0, &arm7_cpu_device::tg08_0, &arm7_cpu_device::tg08_0, &arm7_cpu_device::tg08_0, + &arm7_cpu_device::tg08_0, &arm7_cpu_device::tg08_0, &arm7_cpu_device::tg08_0, &arm7_cpu_device::tg08_0, + &arm7_cpu_device::tg08_1, &arm7_cpu_device::tg08_1, &arm7_cpu_device::tg08_1, &arm7_cpu_device::tg08_1, + &arm7_cpu_device::tg08_1, &arm7_cpu_device::tg08_1, &arm7_cpu_device::tg08_1, &arm7_cpu_device::tg08_1, + &arm7_cpu_device::tg08_1, &arm7_cpu_device::tg08_1, &arm7_cpu_device::tg08_1, &arm7_cpu_device::tg08_1, + &arm7_cpu_device::tg08_1, &arm7_cpu_device::tg08_1, &arm7_cpu_device::tg08_1, &arm7_cpu_device::tg08_1, + &arm7_cpu_device::tg08_1, &arm7_cpu_device::tg08_1, &arm7_cpu_device::tg08_1, &arm7_cpu_device::tg08_1, + &arm7_cpu_device::tg08_1, &arm7_cpu_device::tg08_1, &arm7_cpu_device::tg08_1, &arm7_cpu_device::tg08_1, + &arm7_cpu_device::tg08_1, &arm7_cpu_device::tg08_1, &arm7_cpu_device::tg08_1, &arm7_cpu_device::tg08_1, + &arm7_cpu_device::tg08_1, &arm7_cpu_device::tg08_1, &arm7_cpu_device::tg08_1, &arm7_cpu_device::tg08_1, +// #define THUMB_STACKOP_L ((UINT16)0x0800) + &arm7_cpu_device::tg09_0, &arm7_cpu_device::tg09_0, &arm7_cpu_device::tg09_0, &arm7_cpu_device::tg09_0, + &arm7_cpu_device::tg09_0, &arm7_cpu_device::tg09_0, &arm7_cpu_device::tg09_0, &arm7_cpu_device::tg09_0, + &arm7_cpu_device::tg09_0, &arm7_cpu_device::tg09_0, &arm7_cpu_device::tg09_0, &arm7_cpu_device::tg09_0, + &arm7_cpu_device::tg09_0, &arm7_cpu_device::tg09_0, &arm7_cpu_device::tg09_0, &arm7_cpu_device::tg09_0, + &arm7_cpu_device::tg09_0, &arm7_cpu_device::tg09_0, &arm7_cpu_device::tg09_0, &arm7_cpu_device::tg09_0, + &arm7_cpu_device::tg09_0, &arm7_cpu_device::tg09_0, &arm7_cpu_device::tg09_0, &arm7_cpu_device::tg09_0, + &arm7_cpu_device::tg09_0, &arm7_cpu_device::tg09_0, &arm7_cpu_device::tg09_0, &arm7_cpu_device::tg09_0, + &arm7_cpu_device::tg09_0, &arm7_cpu_device::tg09_0, &arm7_cpu_device::tg09_0, &arm7_cpu_device::tg09_0, + &arm7_cpu_device::tg09_1, &arm7_cpu_device::tg09_1, &arm7_cpu_device::tg09_1, &arm7_cpu_device::tg09_1, + &arm7_cpu_device::tg09_1, &arm7_cpu_device::tg09_1, &arm7_cpu_device::tg09_1, &arm7_cpu_device::tg09_1, + &arm7_cpu_device::tg09_1, &arm7_cpu_device::tg09_1, &arm7_cpu_device::tg09_1, &arm7_cpu_device::tg09_1, + &arm7_cpu_device::tg09_1, &arm7_cpu_device::tg09_1, &arm7_cpu_device::tg09_1, &arm7_cpu_device::tg09_1, + &arm7_cpu_device::tg09_1, &arm7_cpu_device::tg09_1, &arm7_cpu_device::tg09_1, &arm7_cpu_device::tg09_1, + &arm7_cpu_device::tg09_1, &arm7_cpu_device::tg09_1, &arm7_cpu_device::tg09_1, &arm7_cpu_device::tg09_1, + &arm7_cpu_device::tg09_1, &arm7_cpu_device::tg09_1, &arm7_cpu_device::tg09_1, &arm7_cpu_device::tg09_1, + &arm7_cpu_device::tg09_1, &arm7_cpu_device::tg09_1, &arm7_cpu_device::tg09_1, &arm7_cpu_device::tg09_1, +// #define THUMB_RELADDR_SP ((UINT16)0x0800) + &arm7_cpu_device::tg0a_0, &arm7_cpu_device::tg0a_0, &arm7_cpu_device::tg0a_0, &arm7_cpu_device::tg0a_0, + &arm7_cpu_device::tg0a_0, &arm7_cpu_device::tg0a_0, &arm7_cpu_device::tg0a_0, &arm7_cpu_device::tg0a_0, + &arm7_cpu_device::tg0a_0, &arm7_cpu_device::tg0a_0, &arm7_cpu_device::tg0a_0, &arm7_cpu_device::tg0a_0, + &arm7_cpu_device::tg0a_0, &arm7_cpu_device::tg0a_0, &arm7_cpu_device::tg0a_0, &arm7_cpu_device::tg0a_0, + &arm7_cpu_device::tg0a_0, &arm7_cpu_device::tg0a_0, &arm7_cpu_device::tg0a_0, &arm7_cpu_device::tg0a_0, + &arm7_cpu_device::tg0a_0, &arm7_cpu_device::tg0a_0, &arm7_cpu_device::tg0a_0, &arm7_cpu_device::tg0a_0, + &arm7_cpu_device::tg0a_0, &arm7_cpu_device::tg0a_0, &arm7_cpu_device::tg0a_0, &arm7_cpu_device::tg0a_0, + &arm7_cpu_device::tg0a_0, &arm7_cpu_device::tg0a_0, &arm7_cpu_device::tg0a_0, &arm7_cpu_device::tg0a_0, + &arm7_cpu_device::tg0a_1, &arm7_cpu_device::tg0a_1, &arm7_cpu_device::tg0a_1, &arm7_cpu_device::tg0a_1, + &arm7_cpu_device::tg0a_1, &arm7_cpu_device::tg0a_1, &arm7_cpu_device::tg0a_1, &arm7_cpu_device::tg0a_1, + &arm7_cpu_device::tg0a_1, &arm7_cpu_device::tg0a_1, &arm7_cpu_device::tg0a_1, &arm7_cpu_device::tg0a_1, + &arm7_cpu_device::tg0a_1, &arm7_cpu_device::tg0a_1, &arm7_cpu_device::tg0a_1, &arm7_cpu_device::tg0a_1, + &arm7_cpu_device::tg0a_1, &arm7_cpu_device::tg0a_1, &arm7_cpu_device::tg0a_1, &arm7_cpu_device::tg0a_1, + &arm7_cpu_device::tg0a_1, &arm7_cpu_device::tg0a_1, &arm7_cpu_device::tg0a_1, &arm7_cpu_device::tg0a_1, + &arm7_cpu_device::tg0a_1, &arm7_cpu_device::tg0a_1, &arm7_cpu_device::tg0a_1, &arm7_cpu_device::tg0a_1, + &arm7_cpu_device::tg0a_1, &arm7_cpu_device::tg0a_1, &arm7_cpu_device::tg0a_1, &arm7_cpu_device::tg0a_1, +// #define THUMB_STACKOP_TYPE ((UINT16)0x0f00) + &arm7_cpu_device::tg0b_0, &arm7_cpu_device::tg0b_0, &arm7_cpu_device::tg0b_0, &arm7_cpu_device::tg0b_0, + &arm7_cpu_device::tg0b_1, &arm7_cpu_device::tg0b_1, &arm7_cpu_device::tg0b_1, &arm7_cpu_device::tg0b_1, + &arm7_cpu_device::tg0b_2, &arm7_cpu_device::tg0b_2, &arm7_cpu_device::tg0b_2, &arm7_cpu_device::tg0b_2, + &arm7_cpu_device::tg0b_3, &arm7_cpu_device::tg0b_3, &arm7_cpu_device::tg0b_3, &arm7_cpu_device::tg0b_3, + &arm7_cpu_device::tg0b_4, &arm7_cpu_device::tg0b_4, &arm7_cpu_device::tg0b_4, &arm7_cpu_device::tg0b_4, + &arm7_cpu_device::tg0b_5, &arm7_cpu_device::tg0b_5, &arm7_cpu_device::tg0b_5, &arm7_cpu_device::tg0b_5, + &arm7_cpu_device::tg0b_6, &arm7_cpu_device::tg0b_6, &arm7_cpu_device::tg0b_6, &arm7_cpu_device::tg0b_6, + &arm7_cpu_device::tg0b_7, &arm7_cpu_device::tg0b_7, &arm7_cpu_device::tg0b_7, &arm7_cpu_device::tg0b_7, + &arm7_cpu_device::tg0b_8, &arm7_cpu_device::tg0b_8, &arm7_cpu_device::tg0b_8, &arm7_cpu_device::tg0b_8, + &arm7_cpu_device::tg0b_9, &arm7_cpu_device::tg0b_9, &arm7_cpu_device::tg0b_9, &arm7_cpu_device::tg0b_9, + &arm7_cpu_device::tg0b_a, &arm7_cpu_device::tg0b_a, &arm7_cpu_device::tg0b_a, &arm7_cpu_device::tg0b_a, + &arm7_cpu_device::tg0b_b, &arm7_cpu_device::tg0b_b, &arm7_cpu_device::tg0b_b, &arm7_cpu_device::tg0b_b, + &arm7_cpu_device::tg0b_c, &arm7_cpu_device::tg0b_c, &arm7_cpu_device::tg0b_c, &arm7_cpu_device::tg0b_c, + &arm7_cpu_device::tg0b_d, &arm7_cpu_device::tg0b_d, &arm7_cpu_device::tg0b_d, &arm7_cpu_device::tg0b_d, + &arm7_cpu_device::tg0b_e, &arm7_cpu_device::tg0b_e, &arm7_cpu_device::tg0b_e, &arm7_cpu_device::tg0b_e, + &arm7_cpu_device::tg0b_f, &arm7_cpu_device::tg0b_f, &arm7_cpu_device::tg0b_f, &arm7_cpu_device::tg0b_f, +// #define THUMB_MULTLS ((UINT16)0x0800) + &arm7_cpu_device::tg0c_0, &arm7_cpu_device::tg0c_0, &arm7_cpu_device::tg0c_0, &arm7_cpu_device::tg0c_0, + &arm7_cpu_device::tg0c_0, &arm7_cpu_device::tg0c_0, &arm7_cpu_device::tg0c_0, &arm7_cpu_device::tg0c_0, + &arm7_cpu_device::tg0c_0, &arm7_cpu_device::tg0c_0, &arm7_cpu_device::tg0c_0, &arm7_cpu_device::tg0c_0, + &arm7_cpu_device::tg0c_0, &arm7_cpu_device::tg0c_0, &arm7_cpu_device::tg0c_0, &arm7_cpu_device::tg0c_0, + &arm7_cpu_device::tg0c_0, &arm7_cpu_device::tg0c_0, &arm7_cpu_device::tg0c_0, &arm7_cpu_device::tg0c_0, + &arm7_cpu_device::tg0c_0, &arm7_cpu_device::tg0c_0, &arm7_cpu_device::tg0c_0, &arm7_cpu_device::tg0c_0, + &arm7_cpu_device::tg0c_0, &arm7_cpu_device::tg0c_0, &arm7_cpu_device::tg0c_0, &arm7_cpu_device::tg0c_0, + &arm7_cpu_device::tg0c_0, &arm7_cpu_device::tg0c_0, &arm7_cpu_device::tg0c_0, &arm7_cpu_device::tg0c_0, + &arm7_cpu_device::tg0c_1, &arm7_cpu_device::tg0c_1, &arm7_cpu_device::tg0c_1, &arm7_cpu_device::tg0c_1, + &arm7_cpu_device::tg0c_1, &arm7_cpu_device::tg0c_1, &arm7_cpu_device::tg0c_1, &arm7_cpu_device::tg0c_1, + &arm7_cpu_device::tg0c_1, &arm7_cpu_device::tg0c_1, &arm7_cpu_device::tg0c_1, &arm7_cpu_device::tg0c_1, + &arm7_cpu_device::tg0c_1, &arm7_cpu_device::tg0c_1, &arm7_cpu_device::tg0c_1, &arm7_cpu_device::tg0c_1, + &arm7_cpu_device::tg0c_1, &arm7_cpu_device::tg0c_1, &arm7_cpu_device::tg0c_1, &arm7_cpu_device::tg0c_1, + &arm7_cpu_device::tg0c_1, &arm7_cpu_device::tg0c_1, &arm7_cpu_device::tg0c_1, &arm7_cpu_device::tg0c_1, + &arm7_cpu_device::tg0c_1, &arm7_cpu_device::tg0c_1, &arm7_cpu_device::tg0c_1, &arm7_cpu_device::tg0c_1, + &arm7_cpu_device::tg0c_1, &arm7_cpu_device::tg0c_1, &arm7_cpu_device::tg0c_1, &arm7_cpu_device::tg0c_1, +// #define THUMB_COND_TYPE ((UINT16)0x0f00) + &arm7_cpu_device::tg0d_0, &arm7_cpu_device::tg0d_0, &arm7_cpu_device::tg0d_0, &arm7_cpu_device::tg0d_0, + &arm7_cpu_device::tg0d_1, &arm7_cpu_device::tg0d_1, &arm7_cpu_device::tg0d_1, &arm7_cpu_device::tg0d_1, + &arm7_cpu_device::tg0d_2, &arm7_cpu_device::tg0d_2, &arm7_cpu_device::tg0d_2, &arm7_cpu_device::tg0d_2, + &arm7_cpu_device::tg0d_3, &arm7_cpu_device::tg0d_3, &arm7_cpu_device::tg0d_3, &arm7_cpu_device::tg0d_3, + &arm7_cpu_device::tg0d_4, &arm7_cpu_device::tg0d_4, &arm7_cpu_device::tg0d_4, &arm7_cpu_device::tg0d_4, + &arm7_cpu_device::tg0d_5, &arm7_cpu_device::tg0d_5, &arm7_cpu_device::tg0d_5, &arm7_cpu_device::tg0d_5, + &arm7_cpu_device::tg0d_6, &arm7_cpu_device::tg0d_6, &arm7_cpu_device::tg0d_6, &arm7_cpu_device::tg0d_6, + &arm7_cpu_device::tg0d_7, &arm7_cpu_device::tg0d_7, &arm7_cpu_device::tg0d_7, &arm7_cpu_device::tg0d_7, + &arm7_cpu_device::tg0d_8, &arm7_cpu_device::tg0d_8, &arm7_cpu_device::tg0d_8, &arm7_cpu_device::tg0d_8, + &arm7_cpu_device::tg0d_9, &arm7_cpu_device::tg0d_9, &arm7_cpu_device::tg0d_9, &arm7_cpu_device::tg0d_9, + &arm7_cpu_device::tg0d_a, &arm7_cpu_device::tg0d_a, &arm7_cpu_device::tg0d_a, &arm7_cpu_device::tg0d_a, + &arm7_cpu_device::tg0d_b, &arm7_cpu_device::tg0d_b, &arm7_cpu_device::tg0d_b, &arm7_cpu_device::tg0d_b, + &arm7_cpu_device::tg0d_c, &arm7_cpu_device::tg0d_c, &arm7_cpu_device::tg0d_c, &arm7_cpu_device::tg0d_c, + &arm7_cpu_device::tg0d_d, &arm7_cpu_device::tg0d_d, &arm7_cpu_device::tg0d_d, &arm7_cpu_device::tg0d_d, + &arm7_cpu_device::tg0d_e, &arm7_cpu_device::tg0d_e, &arm7_cpu_device::tg0d_e, &arm7_cpu_device::tg0d_e, + &arm7_cpu_device::tg0d_f, &arm7_cpu_device::tg0d_f, &arm7_cpu_device::tg0d_f, &arm7_cpu_device::tg0d_f, +// #define THUMB_BLOP_LO ((UINT16)0x0800) + &arm7_cpu_device::tg0e_0, &arm7_cpu_device::tg0e_0, &arm7_cpu_device::tg0e_0, &arm7_cpu_device::tg0e_0, + &arm7_cpu_device::tg0e_0, &arm7_cpu_device::tg0e_0, &arm7_cpu_device::tg0e_0, &arm7_cpu_device::tg0e_0, + &arm7_cpu_device::tg0e_0, &arm7_cpu_device::tg0e_0, &arm7_cpu_device::tg0e_0, &arm7_cpu_device::tg0e_0, + &arm7_cpu_device::tg0e_0, &arm7_cpu_device::tg0e_0, &arm7_cpu_device::tg0e_0, &arm7_cpu_device::tg0e_0, + &arm7_cpu_device::tg0e_0, &arm7_cpu_device::tg0e_0, &arm7_cpu_device::tg0e_0, &arm7_cpu_device::tg0e_0, + &arm7_cpu_device::tg0e_0, &arm7_cpu_device::tg0e_0, &arm7_cpu_device::tg0e_0, &arm7_cpu_device::tg0e_0, + &arm7_cpu_device::tg0e_0, &arm7_cpu_device::tg0e_0, &arm7_cpu_device::tg0e_0, &arm7_cpu_device::tg0e_0, + &arm7_cpu_device::tg0e_0, &arm7_cpu_device::tg0e_0, &arm7_cpu_device::tg0e_0, &arm7_cpu_device::tg0e_0, + &arm7_cpu_device::tg0e_1, &arm7_cpu_device::tg0e_1, &arm7_cpu_device::tg0e_1, &arm7_cpu_device::tg0e_1, + &arm7_cpu_device::tg0e_1, &arm7_cpu_device::tg0e_1, &arm7_cpu_device::tg0e_1, &arm7_cpu_device::tg0e_1, + &arm7_cpu_device::tg0e_1, &arm7_cpu_device::tg0e_1, &arm7_cpu_device::tg0e_1, &arm7_cpu_device::tg0e_1, + &arm7_cpu_device::tg0e_1, &arm7_cpu_device::tg0e_1, &arm7_cpu_device::tg0e_1, &arm7_cpu_device::tg0e_1, + &arm7_cpu_device::tg0e_1, &arm7_cpu_device::tg0e_1, &arm7_cpu_device::tg0e_1, &arm7_cpu_device::tg0e_1, + &arm7_cpu_device::tg0e_1, &arm7_cpu_device::tg0e_1, &arm7_cpu_device::tg0e_1, &arm7_cpu_device::tg0e_1, + &arm7_cpu_device::tg0e_1, &arm7_cpu_device::tg0e_1, &arm7_cpu_device::tg0e_1, &arm7_cpu_device::tg0e_1, + &arm7_cpu_device::tg0e_1, &arm7_cpu_device::tg0e_1, &arm7_cpu_device::tg0e_1, &arm7_cpu_device::tg0e_1, +// #define THUMB_BLOP_LO ((UINT16)0x0800) + &arm7_cpu_device::tg0f_0, &arm7_cpu_device::tg0f_0, &arm7_cpu_device::tg0f_0, &arm7_cpu_device::tg0f_0, + &arm7_cpu_device::tg0f_0, &arm7_cpu_device::tg0f_0, &arm7_cpu_device::tg0f_0, &arm7_cpu_device::tg0f_0, + &arm7_cpu_device::tg0f_0, &arm7_cpu_device::tg0f_0, &arm7_cpu_device::tg0f_0, &arm7_cpu_device::tg0f_0, + &arm7_cpu_device::tg0f_0, &arm7_cpu_device::tg0f_0, &arm7_cpu_device::tg0f_0, &arm7_cpu_device::tg0f_0, + &arm7_cpu_device::tg0f_0, &arm7_cpu_device::tg0f_0, &arm7_cpu_device::tg0f_0, &arm7_cpu_device::tg0f_0, + &arm7_cpu_device::tg0f_0, &arm7_cpu_device::tg0f_0, &arm7_cpu_device::tg0f_0, &arm7_cpu_device::tg0f_0, + &arm7_cpu_device::tg0f_0, &arm7_cpu_device::tg0f_0, &arm7_cpu_device::tg0f_0, &arm7_cpu_device::tg0f_0, + &arm7_cpu_device::tg0f_0, &arm7_cpu_device::tg0f_0, &arm7_cpu_device::tg0f_0, &arm7_cpu_device::tg0f_0, + &arm7_cpu_device::tg0f_1, &arm7_cpu_device::tg0f_1, &arm7_cpu_device::tg0f_1, &arm7_cpu_device::tg0f_1, + &arm7_cpu_device::tg0f_1, &arm7_cpu_device::tg0f_1, &arm7_cpu_device::tg0f_1, &arm7_cpu_device::tg0f_1, + &arm7_cpu_device::tg0f_1, &arm7_cpu_device::tg0f_1, &arm7_cpu_device::tg0f_1, &arm7_cpu_device::tg0f_1, + &arm7_cpu_device::tg0f_1, &arm7_cpu_device::tg0f_1, &arm7_cpu_device::tg0f_1, &arm7_cpu_device::tg0f_1, + &arm7_cpu_device::tg0f_1, &arm7_cpu_device::tg0f_1, &arm7_cpu_device::tg0f_1, &arm7_cpu_device::tg0f_1, + &arm7_cpu_device::tg0f_1, &arm7_cpu_device::tg0f_1, &arm7_cpu_device::tg0f_1, &arm7_cpu_device::tg0f_1, + &arm7_cpu_device::tg0f_1, &arm7_cpu_device::tg0f_1, &arm7_cpu_device::tg0f_1, &arm7_cpu_device::tg0f_1, + &arm7_cpu_device::tg0f_1, &arm7_cpu_device::tg0f_1, &arm7_cpu_device::tg0f_1, &arm7_cpu_device::tg0f_1, +}; + + /* Shift operations */ + +void arm7_cpu_device::tg00_0(UINT32 pc, UINT32 op) /* Shift left */ +{ + UINT32 rs, rd, rrs; + INT32 offs; + + SET_CPSR(GET_CPSR & ~(N_MASK | Z_MASK)); + + rs = (op & THUMB_ADDSUB_RS) >> THUMB_ADDSUB_RS_SHIFT; + rd = (op & THUMB_ADDSUB_RD) >> THUMB_ADDSUB_RD_SHIFT; + rrs = GET_REGISTER(rs); + offs = (op & THUMB_SHIFT_AMT) >> THUMB_SHIFT_AMT_SHIFT; + if (offs != 0) + { + SET_REGISTER(rd, rrs << offs); + if (rrs & (1 << (31 - (offs - 1)))) + { + SET_CPSR(GET_CPSR | C_MASK); + } + else + { + SET_CPSR(GET_CPSR & ~C_MASK); + } + } + else + { + SET_REGISTER(rd, rrs); + } + SET_CPSR(GET_CPSR & ~(Z_MASK | N_MASK)); + SET_CPSR(GET_CPSR | HandleALUNZFlags(GET_REGISTER(rd))); + R15 += 2; +} + +void arm7_cpu_device::tg00_1(UINT32 pc, UINT32 op) /* Shift right */ +{ + UINT32 rs, rd, rrs; + INT32 offs; + + rs = (op & THUMB_ADDSUB_RS) >> THUMB_ADDSUB_RS_SHIFT; + rd = (op & THUMB_ADDSUB_RD) >> THUMB_ADDSUB_RD_SHIFT; + rrs = GET_REGISTER(rs); + offs = (op & THUMB_SHIFT_AMT) >> THUMB_SHIFT_AMT_SHIFT; + if (offs != 0) + { + SET_REGISTER(rd, rrs >> offs); + if (rrs & (1 << (offs - 1))) + { + SET_CPSR(GET_CPSR | C_MASK); + } + else + { + SET_CPSR(GET_CPSR & ~C_MASK); + } + } + else + { + SET_REGISTER(rd, 0); + if (rrs & 0x80000000) + { + SET_CPSR(GET_CPSR | C_MASK); + } + else + { + SET_CPSR(GET_CPSR & ~C_MASK); + } + } + SET_CPSR(GET_CPSR & ~(Z_MASK | N_MASK)); + SET_CPSR(GET_CPSR | HandleALUNZFlags(GET_REGISTER(rd))); + R15 += 2; +} + + /* Arithmetic */ + +void arm7_cpu_device::tg01_0(UINT32 pc, UINT32 op) +{ + UINT32 rs, rd, rrs; + INT32 offs; + /* ASR.. */ + //if (op & THUMB_SHIFT_R) /* Shift right */ + { + rs = (op & THUMB_ADDSUB_RS) >> THUMB_ADDSUB_RS_SHIFT; + rd = (op & THUMB_ADDSUB_RD) >> THUMB_ADDSUB_RD_SHIFT; + rrs = GET_REGISTER(rs); + offs = (op & THUMB_SHIFT_AMT) >> THUMB_SHIFT_AMT_SHIFT; + if (offs == 0) + { + offs = 32; + } + if (offs >= 32) + { + if (rrs >> 31) + { + SET_CPSR(GET_CPSR | C_MASK); + } + else + { + SET_CPSR(GET_CPSR & ~C_MASK); + } + SET_REGISTER(rd, (rrs & 0x80000000) ? 0xFFFFFFFF : 0x00000000); + } + else + { + if ((rrs >> (offs - 1)) & 1) + { + SET_CPSR(GET_CPSR | C_MASK); + } + else + { + SET_CPSR(GET_CPSR & ~C_MASK); + } + SET_REGISTER(rd, + (rrs & 0x80000000) + ? ((0xFFFFFFFF << (32 - offs)) | (rrs >> offs)) + : (rrs >> offs)); + } + SET_CPSR(GET_CPSR & ~(N_MASK | Z_MASK)); + SET_CPSR(GET_CPSR | HandleALUNZFlags(GET_REGISTER(rd))); + R15 += 2; + } +} + +void arm7_cpu_device::tg01_10(UINT32 pc, UINT32 op) /* ADD Rd, Rs, Rn */ +{ + UINT32 rn = GET_REGISTER((op & THUMB_ADDSUB_RNIMM) >> THUMB_ADDSUB_RNIMM_SHIFT); + UINT32 rs = GET_REGISTER((op & THUMB_ADDSUB_RS) >> THUMB_ADDSUB_RS_SHIFT); + UINT32 rd = (op & THUMB_ADDSUB_RD) >> THUMB_ADDSUB_RD_SHIFT; + SET_REGISTER(rd, rs + rn); + HandleThumbALUAddFlags(GET_REGISTER(rd), rs, rn); + +} + +void arm7_cpu_device::tg01_11(UINT32 pc, UINT32 op) /* SUB Rd, Rs, Rn */ +{ + UINT32 rn = GET_REGISTER((op & THUMB_ADDSUB_RNIMM) >> THUMB_ADDSUB_RNIMM_SHIFT); + UINT32 rs = GET_REGISTER((op & THUMB_ADDSUB_RS) >> THUMB_ADDSUB_RS_SHIFT); + UINT32 rd = (op & THUMB_ADDSUB_RD) >> THUMB_ADDSUB_RD_SHIFT; + SET_REGISTER(rd, rs - rn); + HandleThumbALUSubFlags(GET_REGISTER(rd), rs, rn); + +} + +void arm7_cpu_device::tg01_12(UINT32 pc, UINT32 op) /* ADD Rd, Rs, #imm */ +{ + UINT32 imm = (op & THUMB_ADDSUB_RNIMM) >> THUMB_ADDSUB_RNIMM_SHIFT; + UINT32 rs = GET_REGISTER((op & THUMB_ADDSUB_RS) >> THUMB_ADDSUB_RS_SHIFT); + UINT32 rd = (op & THUMB_ADDSUB_RD) >> THUMB_ADDSUB_RD_SHIFT; + SET_REGISTER(rd, rs + imm); + HandleThumbALUAddFlags(GET_REGISTER(rd), rs, imm); + +} + +void arm7_cpu_device::tg01_13(UINT32 pc, UINT32 op) /* SUB Rd, Rs, #imm */ +{ + UINT32 imm = (op & THUMB_ADDSUB_RNIMM) >> THUMB_ADDSUB_RNIMM_SHIFT; + UINT32 rs = GET_REGISTER((op & THUMB_ADDSUB_RS) >> THUMB_ADDSUB_RS_SHIFT); + UINT32 rd = (op & THUMB_ADDSUB_RD) >> THUMB_ADDSUB_RD_SHIFT; + SET_REGISTER(rd, rs - imm); + HandleThumbALUSubFlags(GET_REGISTER(rd), rs,imm); + +} + + /* CMP / MOV */ + +void arm7_cpu_device::tg02_0(UINT32 pc, UINT32 op) +{ + UINT32 rd = (op & THUMB_INSN_IMM_RD) >> THUMB_INSN_IMM_RD_SHIFT; + UINT32 op2 = (op & THUMB_INSN_IMM); + SET_REGISTER(rd, op2); + SET_CPSR(GET_CPSR & ~(Z_MASK | N_MASK)); + SET_CPSR(GET_CPSR | HandleALUNZFlags(GET_REGISTER(rd))); + R15 += 2; +} + +void arm7_cpu_device::tg02_1(UINT32 pc, UINT32 op) +{ + UINT32 rn = GET_REGISTER((op & THUMB_INSN_IMM_RD) >> THUMB_INSN_IMM_RD_SHIFT); + UINT32 op2 = op & THUMB_INSN_IMM; + UINT32 rd = rn - op2; + HandleThumbALUSubFlags(rd, rn, op2); +} + + /* ADD/SUB immediate */ + +void arm7_cpu_device::tg03_0(UINT32 pc, UINT32 op) /* ADD Rd, #Offset8 */ +{ + UINT32 rn = GET_REGISTER((op & THUMB_INSN_IMM_RD) >> THUMB_INSN_IMM_RD_SHIFT); + UINT32 op2 = op & THUMB_INSN_IMM; + UINT32 rd = rn + op2; + SET_REGISTER((op & THUMB_INSN_IMM_RD) >> THUMB_INSN_IMM_RD_SHIFT, rd); + HandleThumbALUAddFlags(rd, rn, op2); +} + +void arm7_cpu_device::tg03_1(UINT32 pc, UINT32 op) /* SUB Rd, #Offset8 */ +{ + UINT32 rn = GET_REGISTER((op & THUMB_INSN_IMM_RD) >> THUMB_INSN_IMM_RD_SHIFT); + UINT32 op2 = op & THUMB_INSN_IMM; + UINT32 rd = rn - op2; + SET_REGISTER((op & THUMB_INSN_IMM_RD) >> THUMB_INSN_IMM_RD_SHIFT, rd); + HandleThumbALUSubFlags(rd, rn, op2); +} + + /* Rd & Rm instructions */ + +void arm7_cpu_device::tg04_00_00(UINT32 pc, UINT32 op) /* AND Rd, Rs */ +{ + UINT32 rs = (op & THUMB_ADDSUB_RS) >> THUMB_ADDSUB_RS_SHIFT; + UINT32 rd = (op & THUMB_ADDSUB_RD) >> THUMB_ADDSUB_RD_SHIFT; + SET_REGISTER(rd, GET_REGISTER(rd) & GET_REGISTER(rs)); + SET_CPSR(GET_CPSR & ~(Z_MASK | N_MASK)); + SET_CPSR(GET_CPSR | HandleALUNZFlags(GET_REGISTER(rd))); + R15 += 2; +} + +void arm7_cpu_device::tg04_00_01(UINT32 pc, UINT32 op) /* EOR Rd, Rs */ +{ + UINT32 rs = (op & THUMB_ADDSUB_RS) >> THUMB_ADDSUB_RS_SHIFT; + UINT32 rd = (op & THUMB_ADDSUB_RD) >> THUMB_ADDSUB_RD_SHIFT; + SET_REGISTER(rd, GET_REGISTER(rd) ^ GET_REGISTER(rs)); + SET_CPSR(GET_CPSR & ~(Z_MASK | N_MASK)); + SET_CPSR(GET_CPSR | HandleALUNZFlags(GET_REGISTER(rd))); + R15 += 2; +} + +void arm7_cpu_device::tg04_00_02(UINT32 pc, UINT32 op) /* LSL Rd, Rs */ +{ + UINT32 rs = (op & THUMB_ADDSUB_RS) >> THUMB_ADDSUB_RS_SHIFT; + UINT32 rd = (op & THUMB_ADDSUB_RD) >> THUMB_ADDSUB_RD_SHIFT; + UINT32 rrd = GET_REGISTER(rd); + INT32 offs = GET_REGISTER(rs) & 0x000000ff; + if (offs > 0) + { + if (offs < 32) + { + SET_REGISTER(rd, rrd << offs); + if (rrd & (1 << (31 - (offs - 1)))) + { + SET_CPSR(GET_CPSR | C_MASK); + } + else + { + SET_CPSR(GET_CPSR & ~C_MASK); + } + } + else if (offs == 32) + { + SET_REGISTER(rd, 0); + if (rrd & 1) + { + SET_CPSR(GET_CPSR | C_MASK); + } + else + { + SET_CPSR(GET_CPSR & ~C_MASK); + } + } + else + { + SET_REGISTER(rd, 0); + SET_CPSR(GET_CPSR & ~C_MASK); + } + } + SET_CPSR(GET_CPSR & ~(Z_MASK | N_MASK)); + SET_CPSR(GET_CPSR | HandleALUNZFlags(GET_REGISTER(rd))); + R15 += 2; +} + +void arm7_cpu_device::tg04_00_03(UINT32 pc, UINT32 op) /* LSR Rd, Rs */ +{ + UINT32 rs = (op & THUMB_ADDSUB_RS) >> THUMB_ADDSUB_RS_SHIFT; + UINT32 rd = (op & THUMB_ADDSUB_RD) >> THUMB_ADDSUB_RD_SHIFT; + UINT32 rrd = GET_REGISTER(rd); + INT32 offs = GET_REGISTER(rs) & 0x000000ff; + if (offs > 0) + { + if (offs < 32) + { + SET_REGISTER(rd, rrd >> offs); + if (rrd & (1 << (offs - 1))) + { + SET_CPSR(GET_CPSR | C_MASK); + } + else + { + SET_CPSR(GET_CPSR & ~C_MASK); + } + } + else if (offs == 32) + { + SET_REGISTER(rd, 0); + if (rrd & 0x80000000) + { + SET_CPSR(GET_CPSR | C_MASK); + } + else + { + SET_CPSR(GET_CPSR & ~C_MASK); + } + } + else + { + SET_REGISTER(rd, 0); + SET_CPSR(GET_CPSR & ~C_MASK); + } + } + SET_CPSR(GET_CPSR & ~(Z_MASK | N_MASK)); + SET_CPSR(GET_CPSR | HandleALUNZFlags(GET_REGISTER(rd))); + R15 += 2; +} + +void arm7_cpu_device::tg04_00_04(UINT32 pc, UINT32 op) /* ASR Rd, Rs */ +{ + UINT32 rs = (op & THUMB_ADDSUB_RS) >> THUMB_ADDSUB_RS_SHIFT; + UINT32 rd = (op & THUMB_ADDSUB_RD) >> THUMB_ADDSUB_RD_SHIFT; + UINT32 rrs = GET_REGISTER(rs)&0xff; + UINT32 rrd = GET_REGISTER(rd); + if (rrs != 0) + { + if (rrs >= 32) + { + if (rrd >> 31) + { + SET_CPSR(GET_CPSR | C_MASK); + } + else + { + SET_CPSR(GET_CPSR & ~C_MASK); + } + SET_REGISTER(rd, (GET_REGISTER(rd) & 0x80000000) ? 0xFFFFFFFF : 0x00000000); + } + else + { + if ((rrd >> (rrs-1)) & 1) + { + SET_CPSR(GET_CPSR | C_MASK); + } + else + { + SET_CPSR(GET_CPSR & ~C_MASK); + } + SET_REGISTER(rd, (rrd & 0x80000000) + ? ((0xFFFFFFFF << (32 - rrs)) | (rrd >> rrs)) + : (rrd >> rrs)); + } + } + SET_CPSR(GET_CPSR & ~(N_MASK | Z_MASK)); + SET_CPSR(GET_CPSR | HandleALUNZFlags(GET_REGISTER(rd))); + R15 += 2; +} + +void arm7_cpu_device::tg04_00_05(UINT32 pc, UINT32 op) /* ADC Rd, Rs */ +{ + UINT32 rs = (op & THUMB_ADDSUB_RS) >> THUMB_ADDSUB_RS_SHIFT; + UINT32 rd = (op & THUMB_ADDSUB_RD) >> THUMB_ADDSUB_RD_SHIFT; + UINT32 op2 = (GET_CPSR & C_MASK) ? 1 : 0; + UINT32 rn = GET_REGISTER(rd) + GET_REGISTER(rs) + op2; + HandleThumbALUAddFlags(rn, GET_REGISTER(rd), (GET_REGISTER(rs))); // ? + SET_REGISTER(rd, rn); +} + +void arm7_cpu_device::tg04_00_06(UINT32 pc, UINT32 op) /* SBC Rd, Rs */ +{ + UINT32 rs = (op & THUMB_ADDSUB_RS) >> THUMB_ADDSUB_RS_SHIFT; + UINT32 rd = (op & THUMB_ADDSUB_RD) >> THUMB_ADDSUB_RD_SHIFT; + UINT32 op2 = (GET_CPSR & C_MASK) ? 0 : 1; + UINT32 rn = GET_REGISTER(rd) - GET_REGISTER(rs) - op2; + HandleThumbALUSubFlags(rn, GET_REGISTER(rd), (GET_REGISTER(rs))); //? + SET_REGISTER(rd, rn); +} + +void arm7_cpu_device::tg04_00_07(UINT32 pc, UINT32 op) /* ROR Rd, Rs */ +{ + UINT32 rs = (op & THUMB_ADDSUB_RS) >> THUMB_ADDSUB_RS_SHIFT; + UINT32 rd = (op & THUMB_ADDSUB_RD) >> THUMB_ADDSUB_RD_SHIFT; + UINT32 rrd = GET_REGISTER(rd); + UINT32 imm = GET_REGISTER(rs) & 0x0000001f; + SET_REGISTER(rd, (rrd >> imm) | (rrd << (32 - imm))); + if (rrd & (1 << (imm - 1))) + { + SET_CPSR(GET_CPSR | C_MASK); + } + else + { + SET_CPSR(GET_CPSR & ~C_MASK); + } + SET_CPSR(GET_CPSR & ~(Z_MASK | N_MASK)); + SET_CPSR(GET_CPSR | HandleALUNZFlags(GET_REGISTER(rd))); + R15 += 2; +} + +void arm7_cpu_device::tg04_00_08(UINT32 pc, UINT32 op) /* TST Rd, Rs */ +{ + UINT32 rs = (op & THUMB_ADDSUB_RS) >> THUMB_ADDSUB_RS_SHIFT; + UINT32 rd = (op & THUMB_ADDSUB_RD) >> THUMB_ADDSUB_RD_SHIFT; + SET_CPSR(GET_CPSR & ~(Z_MASK | N_MASK)); + SET_CPSR(GET_CPSR | HandleALUNZFlags(GET_REGISTER(rd) & GET_REGISTER(rs))); + R15 += 2; +} + +void arm7_cpu_device::tg04_00_09(UINT32 pc, UINT32 op) /* NEG Rd, Rs */ +{ + UINT32 rs = (op & THUMB_ADDSUB_RS) >> THUMB_ADDSUB_RS_SHIFT; + UINT32 rd = (op & THUMB_ADDSUB_RD) >> THUMB_ADDSUB_RD_SHIFT; + UINT32 rrs = GET_REGISTER(rs); + SET_REGISTER(rd, 0 - rrs); + HandleThumbALUSubFlags(GET_REGISTER(rd), 0, rrs); +} + +void arm7_cpu_device::tg04_00_0a(UINT32 pc, UINT32 op) /* CMP Rd, Rs */ +{ + UINT32 rs = (op & THUMB_ADDSUB_RS) >> THUMB_ADDSUB_RS_SHIFT; + UINT32 rd = (op & THUMB_ADDSUB_RD) >> THUMB_ADDSUB_RD_SHIFT; + UINT32 rn = GET_REGISTER(rd) - GET_REGISTER(rs); + HandleThumbALUSubFlags(rn, GET_REGISTER(rd), GET_REGISTER(rs)); +} + +void arm7_cpu_device::tg04_00_0b(UINT32 pc, UINT32 op) /* CMN Rd, Rs - check flags, add dasm */ +{ + UINT32 rs = (op & THUMB_ADDSUB_RS) >> THUMB_ADDSUB_RS_SHIFT; + UINT32 rd = (op & THUMB_ADDSUB_RD) >> THUMB_ADDSUB_RD_SHIFT; + UINT32 rn = GET_REGISTER(rd) + GET_REGISTER(rs); + HandleThumbALUAddFlags(rn, GET_REGISTER(rd), GET_REGISTER(rs)); +} + +void arm7_cpu_device::tg04_00_0c(UINT32 pc, UINT32 op) /* ORR Rd, Rs */ +{ + UINT32 rs = (op & THUMB_ADDSUB_RS) >> THUMB_ADDSUB_RS_SHIFT; + UINT32 rd = (op & THUMB_ADDSUB_RD) >> THUMB_ADDSUB_RD_SHIFT; + SET_REGISTER(rd, GET_REGISTER(rd) | GET_REGISTER(rs)); + SET_CPSR(GET_CPSR & ~(Z_MASK | N_MASK)); + SET_CPSR(GET_CPSR | HandleALUNZFlags(GET_REGISTER(rd))); + R15 += 2; +} + +void arm7_cpu_device::tg04_00_0d(UINT32 pc, UINT32 op) /* MUL Rd, Rs */ +{ + UINT32 rs = (op & THUMB_ADDSUB_RS) >> THUMB_ADDSUB_RS_SHIFT; + UINT32 rd = (op & THUMB_ADDSUB_RD) >> THUMB_ADDSUB_RD_SHIFT; + UINT32 rn = GET_REGISTER(rd) * GET_REGISTER(rs); + SET_CPSR(GET_CPSR & ~(Z_MASK | N_MASK)); + SET_REGISTER(rd, rn); + SET_CPSR(GET_CPSR | HandleALUNZFlags(rn)); + R15 += 2; +} + +void arm7_cpu_device::tg04_00_0e(UINT32 pc, UINT32 op) /* BIC Rd, Rs */ +{ + UINT32 rs = (op & THUMB_ADDSUB_RS) >> THUMB_ADDSUB_RS_SHIFT; + UINT32 rd = (op & THUMB_ADDSUB_RD) >> THUMB_ADDSUB_RD_SHIFT; + SET_REGISTER(rd, GET_REGISTER(rd) & (~GET_REGISTER(rs))); + SET_CPSR(GET_CPSR & ~(Z_MASK | N_MASK)); + SET_CPSR(GET_CPSR | HandleALUNZFlags(GET_REGISTER(rd))); + R15 += 2; +} + +void arm7_cpu_device::tg04_00_0f(UINT32 pc, UINT32 op) /* MVN Rd, Rs */ +{ + UINT32 rs = (op & THUMB_ADDSUB_RS) >> THUMB_ADDSUB_RS_SHIFT; + UINT32 rd = (op & THUMB_ADDSUB_RD) >> THUMB_ADDSUB_RD_SHIFT; + UINT32 op2 = GET_REGISTER(rs); + SET_REGISTER(rd, ~op2); + SET_CPSR(GET_CPSR & ~(Z_MASK | N_MASK)); + SET_CPSR(GET_CPSR | HandleALUNZFlags(GET_REGISTER(rd))); + R15 += 2; +} + +/* ADD Rd, Rs group */ + +void arm7_cpu_device::tg04_01_00(UINT32 pc, UINT32 op) +{ + fatalerror("%08x: G4-1-0 Undefined Thumb instruction: %04x %x\n", pc, op, (op & THUMB_HIREG_H) >> THUMB_HIREG_H_SHIFT); +} + +void arm7_cpu_device::tg04_01_01(UINT32 pc, UINT32 op) /* ADD Rd, HRs */ +{ + UINT32 rs = (op & THUMB_HIREG_RS) >> THUMB_HIREG_RS_SHIFT; + UINT32 rd = op & THUMB_HIREG_RD; + SET_REGISTER(rd, GET_REGISTER(rd) + GET_REGISTER(rs+8)); + // emulate the effects of pre-fetch + if (rs == 7) + { + SET_REGISTER(rd, GET_REGISTER(rd) + 4); + } + + R15 += 2; +} + +void arm7_cpu_device::tg04_01_02(UINT32 pc, UINT32 op) /* ADD HRd, Rs */ +{ + UINT32 rs = (op & THUMB_HIREG_RS) >> THUMB_HIREG_RS_SHIFT; + UINT32 rd = op & THUMB_HIREG_RD; + SET_REGISTER(rd+8, GET_REGISTER(rd+8) + GET_REGISTER(rs)); + if (rd == 7) + { + R15 += 2; + } + + R15 += 2; +} + +void arm7_cpu_device::tg04_01_03(UINT32 pc, UINT32 op) /* Add HRd, HRs */ +{ + UINT32 rs = (op & THUMB_HIREG_RS) >> THUMB_HIREG_RS_SHIFT; + UINT32 rd = op & THUMB_HIREG_RD; + SET_REGISTER(rd+8, GET_REGISTER(rd+8) + GET_REGISTER(rs+8)); + // emulate the effects of pre-fetch + if (rs == 7) + { + SET_REGISTER(rd+8, GET_REGISTER(rd+8) + 4); + } + if (rd == 7) + { + R15 += 2; + } + + R15 += 2; +} + +void arm7_cpu_device::tg04_01_10(UINT32 pc, UINT32 op) /* CMP Rd, Rs */ +{ + UINT32 rs = GET_REGISTER(((op & THUMB_HIREG_RS) >> THUMB_HIREG_RS_SHIFT)); + UINT32 rd = GET_REGISTER(op & THUMB_HIREG_RD); + UINT32 rn = rd - rs; + HandleThumbALUSubFlags(rn, rd, rs); +} + +void arm7_cpu_device::tg04_01_11(UINT32 pc, UINT32 op) /* CMP Rd, Hs */ +{ + UINT32 rs = GET_REGISTER(((op & THUMB_HIREG_RS) >> THUMB_HIREG_RS_SHIFT) + 8); + UINT32 rd = GET_REGISTER(op & THUMB_HIREG_RD); + UINT32 rn = rd - rs; + HandleThumbALUSubFlags(rn, rd, rs); +} + +void arm7_cpu_device::tg04_01_12(UINT32 pc, UINT32 op) /* CMP Hd, Rs */ +{ + UINT32 rs = GET_REGISTER(((op & THUMB_HIREG_RS) >> THUMB_HIREG_RS_SHIFT)); + UINT32 rd = GET_REGISTER((op & THUMB_HIREG_RD) + 8); + UINT32 rn = rd - rs; + HandleThumbALUSubFlags(rn, rd, rs); +} + +void arm7_cpu_device::tg04_01_13(UINT32 pc, UINT32 op) /* CMP Hd, Hs */ +{ + UINT32 rs = GET_REGISTER(((op & THUMB_HIREG_RS) >> THUMB_HIREG_RS_SHIFT) + 8); + UINT32 rd = GET_REGISTER((op & THUMB_HIREG_RD) + 8); + UINT32 rn = rd - rs; + HandleThumbALUSubFlags(rn, rd, rs); +} + +/* MOV group */ + +// "The action of H1 = 0, H2 = 0 for Op = 00 (ADD), Op = 01 (CMP) and Op = 10 (MOV) is undefined, and should not be used." +void arm7_cpu_device::tg04_01_20(UINT32 pc, UINT32 op) /* MOV Rd, Rs (undefined) */ +{ + UINT32 rs = (op & THUMB_HIREG_RS) >> THUMB_HIREG_RS_SHIFT; + UINT32 rd = op & THUMB_HIREG_RD; + SET_REGISTER(rd, GET_REGISTER(rs)); + R15 += 2; +} + +void arm7_cpu_device::tg04_01_21(UINT32 pc, UINT32 op) /* MOV Rd, Hs */ +{ + UINT32 rs = (op & THUMB_HIREG_RS) >> THUMB_HIREG_RS_SHIFT; + UINT32 rd = op & THUMB_HIREG_RD; + SET_REGISTER(rd, GET_REGISTER(rs + 8)); + if (rs == 7) + { + SET_REGISTER(rd, GET_REGISTER(rd) + 4); + } + R15 += 2; +} + +void arm7_cpu_device::tg04_01_22(UINT32 pc, UINT32 op) /* MOV Hd, Rs */ +{ + UINT32 rs = (op & THUMB_HIREG_RS) >> THUMB_HIREG_RS_SHIFT; + UINT32 rd = op & THUMB_HIREG_RD; + SET_REGISTER(rd + 8, GET_REGISTER(rs)); + if (rd != 7) + { + R15 += 2; + } + else + { + R15 &= ~1; + } +} + +void arm7_cpu_device::tg04_01_23(UINT32 pc, UINT32 op) /* MOV Hd, Hs */ +{ + UINT32 rs = (op & THUMB_HIREG_RS) >> THUMB_HIREG_RS_SHIFT; + UINT32 rd = op & THUMB_HIREG_RD; + if (rs == 7) + { + SET_REGISTER(rd + 8, GET_REGISTER(rs+8)+4); + } + else + { + SET_REGISTER(rd + 8, GET_REGISTER(rs+8)); + } + if (rd != 7) + { + R15 += 2; + } + else + { + R15 &= ~1; + } +} + +void arm7_cpu_device::tg04_01_30(UINT32 pc, UINT32 op) +{ + UINT32 rd = (op & THUMB_HIREG_RS) >> THUMB_HIREG_RS_SHIFT; + UINT32 addr = GET_REGISTER(rd); + if (addr & 1) + { + addr &= ~1; + } + else + { + SET_CPSR(GET_CPSR & ~T_MASK); + if (addr & 2) + { + addr += 2; + } + } + R15 = addr; +} + +void arm7_cpu_device::tg04_01_31(UINT32 pc, UINT32 op) +{ + UINT32 rs = (op & THUMB_HIREG_RS) >> THUMB_HIREG_RS_SHIFT; + UINT32 addr = GET_REGISTER(rs+8); + if (rs == 7) + { + addr += 2; + } + if (addr & 1) + { + addr &= ~1; + } + else + { + SET_CPSR(GET_CPSR & ~T_MASK); + if (addr & 2) + { + addr += 2; + } + } + R15 = addr; +} + +/* BLX */ +void arm7_cpu_device::tg04_01_32(UINT32 pc, UINT32 op) +{ + UINT32 addr = GET_REGISTER((op & THUMB_HIREG_RS) >> THUMB_HIREG_RS_SHIFT); + SET_REGISTER(14, (R15 + 2) | 1); + + // are we also switching to ARM mode? + if (!(addr & 1)) + { + SET_CPSR(GET_CPSR & ~T_MASK); + if (addr & 2) + { + addr += 2; + } + } + else + { + addr &= ~1; + } + + R15 = addr; +} + +void arm7_cpu_device::tg04_01_33(UINT32 pc, UINT32 op) +{ + fatalerror("%08x: G4-3 Undefined Thumb instruction: %04x\n", pc, op); +} + +void arm7_cpu_device::tg04_0203(UINT32 pc, UINT32 op) +{ + UINT32 readword = READ32((R15 & ~2) + 4 + ((op & THUMB_INSN_IMM) << 2)); + SET_REGISTER((op & THUMB_INSN_IMM_RD) >> THUMB_INSN_IMM_RD_SHIFT, readword); + R15 += 2; +} + +/* LDR* STR* group */ + +void arm7_cpu_device::tg05_0(UINT32 pc, UINT32 op) /* STR Rd, [Rn, Rm] */ +{ + UINT32 rm = (op & THUMB_GROUP5_RM) >> THUMB_GROUP5_RM_SHIFT; + UINT32 rn = (op & THUMB_GROUP5_RN) >> THUMB_GROUP5_RN_SHIFT; + UINT32 rd = (op & THUMB_GROUP5_RD) >> THUMB_GROUP5_RD_SHIFT; + UINT32 addr = GET_REGISTER(rn) + GET_REGISTER(rm); + WRITE32(addr, GET_REGISTER(rd)); + R15 += 2; +} + +void arm7_cpu_device::tg05_1(UINT32 pc, UINT32 op) /* STRH Rd, [Rn, Rm] */ +{ + UINT32 rm = (op & THUMB_GROUP5_RM) >> THUMB_GROUP5_RM_SHIFT; + UINT32 rn = (op & THUMB_GROUP5_RN) >> THUMB_GROUP5_RN_SHIFT; + UINT32 rd = (op & THUMB_GROUP5_RD) >> THUMB_GROUP5_RD_SHIFT; + UINT32 addr = GET_REGISTER(rn) + GET_REGISTER(rm); + WRITE16(addr, GET_REGISTER(rd)); + R15 += 2; +} + +void arm7_cpu_device::tg05_2(UINT32 pc, UINT32 op) /* STRB Rd, [Rn, Rm] */ +{ + UINT32 rm = (op & THUMB_GROUP5_RM) >> THUMB_GROUP5_RM_SHIFT; + UINT32 rn = (op & THUMB_GROUP5_RN) >> THUMB_GROUP5_RN_SHIFT; + UINT32 rd = (op & THUMB_GROUP5_RD) >> THUMB_GROUP5_RD_SHIFT; + UINT32 addr = GET_REGISTER(rn) + GET_REGISTER(rm); + WRITE8(addr, GET_REGISTER(rd)); + R15 += 2; +} + +void arm7_cpu_device::tg05_3(UINT32 pc, UINT32 op) /* LDSB Rd, [Rn, Rm] todo, add dasm */ +{ + UINT32 rm = (op & THUMB_GROUP5_RM) >> THUMB_GROUP5_RM_SHIFT; + UINT32 rn = (op & THUMB_GROUP5_RN) >> THUMB_GROUP5_RN_SHIFT; + UINT32 rd = (op & THUMB_GROUP5_RD) >> THUMB_GROUP5_RD_SHIFT; + UINT32 addr = GET_REGISTER(rn) + GET_REGISTER(rm); + UINT32 op2 = READ8(addr); + if (op2 & 0x00000080) + { + op2 |= 0xffffff00; + } + SET_REGISTER(rd, op2); + R15 += 2; +} + +void arm7_cpu_device::tg05_4(UINT32 pc, UINT32 op) /* LDR Rd, [Rn, Rm] */ +{ + UINT32 rm = (op & THUMB_GROUP5_RM) >> THUMB_GROUP5_RM_SHIFT; + UINT32 rn = (op & THUMB_GROUP5_RN) >> THUMB_GROUP5_RN_SHIFT; + UINT32 rd = (op & THUMB_GROUP5_RD) >> THUMB_GROUP5_RD_SHIFT; + UINT32 addr = GET_REGISTER(rn) + GET_REGISTER(rm); + UINT32 op2 = READ32(addr); + SET_REGISTER(rd, op2); + R15 += 2; +} + +void arm7_cpu_device::tg05_5(UINT32 pc, UINT32 op) /* LDRH Rd, [Rn, Rm] */ +{ + UINT32 rm = (op & THUMB_GROUP5_RM) >> THUMB_GROUP5_RM_SHIFT; + UINT32 rn = (op & THUMB_GROUP5_RN) >> THUMB_GROUP5_RN_SHIFT; + UINT32 rd = (op & THUMB_GROUP5_RD) >> THUMB_GROUP5_RD_SHIFT; + UINT32 addr = GET_REGISTER(rn) + GET_REGISTER(rm); + UINT32 op2 = READ16(addr); + SET_REGISTER(rd, op2); + R15 += 2; +} + +void arm7_cpu_device::tg05_6(UINT32 pc, UINT32 op) /* LDRB Rd, [Rn, Rm] */ +{ + UINT32 rm = (op & THUMB_GROUP5_RM) >> THUMB_GROUP5_RM_SHIFT; + UINT32 rn = (op & THUMB_GROUP5_RN) >> THUMB_GROUP5_RN_SHIFT; + UINT32 rd = (op & THUMB_GROUP5_RD) >> THUMB_GROUP5_RD_SHIFT; + UINT32 addr = GET_REGISTER(rn) + GET_REGISTER(rm); + UINT32 op2 = READ8(addr); + SET_REGISTER(rd, op2); + R15 += 2; +} + +void arm7_cpu_device::tg05_7(UINT32 pc, UINT32 op) /* LDSH Rd, [Rn, Rm] */ +{ + UINT32 rm = (op & THUMB_GROUP5_RM) >> THUMB_GROUP5_RM_SHIFT; + UINT32 rn = (op & THUMB_GROUP5_RN) >> THUMB_GROUP5_RN_SHIFT; + UINT32 rd = (op & THUMB_GROUP5_RD) >> THUMB_GROUP5_RD_SHIFT; + UINT32 addr = GET_REGISTER(rn) + GET_REGISTER(rm); + UINT32 op2 = READ16(addr); + if (op2 & 0x00008000) + { + op2 |= 0xffff0000; + } + SET_REGISTER(rd, op2); + R15 += 2; +} + + /* Word Store w/ Immediate Offset */ + +void arm7_cpu_device::tg06_0(UINT32 pc, UINT32 op) /* Store */ +{ + UINT32 rn = (op & THUMB_ADDSUB_RS) >> THUMB_ADDSUB_RS_SHIFT; + UINT32 rd = op & THUMB_ADDSUB_RD; + INT32 offs = ((op & THUMB_LSOP_OFFS) >> THUMB_LSOP_OFFS_SHIFT) << 2; + WRITE32(GET_REGISTER(rn) + offs, GET_REGISTER(rd)); + R15 += 2; +} + +void arm7_cpu_device::tg06_1(UINT32 pc, UINT32 op) /* Load */ +{ + UINT32 rn = (op & THUMB_ADDSUB_RS) >> THUMB_ADDSUB_RS_SHIFT; + UINT32 rd = op & THUMB_ADDSUB_RD; + INT32 offs = ((op & THUMB_LSOP_OFFS) >> THUMB_LSOP_OFFS_SHIFT) << 2; + SET_REGISTER(rd, READ32(GET_REGISTER(rn) + offs)); // fix + R15 += 2; +} + +/* Byte Store w/ Immeidate Offset */ + +void arm7_cpu_device::tg07_0(UINT32 pc, UINT32 op) /* Store */ +{ + UINT32 rn = (op & THUMB_ADDSUB_RS) >> THUMB_ADDSUB_RS_SHIFT; + UINT32 rd = op & THUMB_ADDSUB_RD; + INT32 offs = (op & THUMB_LSOP_OFFS) >> THUMB_LSOP_OFFS_SHIFT; + WRITE8(GET_REGISTER(rn) + offs, GET_REGISTER(rd)); + R15 += 2; +} + +void arm7_cpu_device::tg07_1(UINT32 pc, UINT32 op) /* Load */ +{ + UINT32 rn = (op & THUMB_ADDSUB_RS) >> THUMB_ADDSUB_RS_SHIFT; + UINT32 rd = op & THUMB_ADDSUB_RD; + INT32 offs = (op & THUMB_LSOP_OFFS) >> THUMB_LSOP_OFFS_SHIFT; + SET_REGISTER(rd, READ8(GET_REGISTER(rn) + offs)); + R15 += 2; +} + +/* Load/Store Halfword */ + +void arm7_cpu_device::tg08_0(UINT32 pc, UINT32 op) /* Store */ +{ + UINT32 imm = (op & THUMB_HALFOP_OFFS) >> THUMB_HALFOP_OFFS_SHIFT; + UINT32 rs = (op & THUMB_ADDSUB_RS) >> THUMB_ADDSUB_RS_SHIFT; + UINT32 rd = (op & THUMB_ADDSUB_RD) >> THUMB_ADDSUB_RD_SHIFT; + WRITE16(GET_REGISTER(rs) + (imm << 1), GET_REGISTER(rd)); + R15 += 2; +} + +void arm7_cpu_device::tg08_1(UINT32 pc, UINT32 op) /* Load */ +{ + UINT32 imm = (op & THUMB_HALFOP_OFFS) >> THUMB_HALFOP_OFFS_SHIFT; + UINT32 rs = (op & THUMB_ADDSUB_RS) >> THUMB_ADDSUB_RS_SHIFT; + UINT32 rd = (op & THUMB_ADDSUB_RD) >> THUMB_ADDSUB_RD_SHIFT; + SET_REGISTER(rd, READ16(GET_REGISTER(rs) + (imm << 1))); + R15 += 2; +} + +/* Stack-Relative Load/Store */ + +void arm7_cpu_device::tg09_0(UINT32 pc, UINT32 op) /* Store */ +{ + UINT32 rd = (op & THUMB_STACKOP_RD) >> THUMB_STACKOP_RD_SHIFT; + INT32 offs = (UINT8)(op & THUMB_INSN_IMM); + WRITE32(GET_REGISTER(13) + ((UINT32)offs << 2), GET_REGISTER(rd)); + R15 += 2; +} + +void arm7_cpu_device::tg09_1(UINT32 pc, UINT32 op) /* Load */ +{ + UINT32 rd = (op & THUMB_STACKOP_RD) >> THUMB_STACKOP_RD_SHIFT; + INT32 offs = (UINT8)(op & THUMB_INSN_IMM); + UINT32 readword = READ32(GET_REGISTER(13) + ((UINT32)offs << 2)); + SET_REGISTER(rd, readword); + R15 += 2; +} + +/* Get relative address */ + +void arm7_cpu_device::tg0a_0(UINT32 pc, UINT32 op) /* ADD Rd, PC, #nn */ +{ + UINT32 rd = (op & THUMB_RELADDR_RD) >> THUMB_RELADDR_RD_SHIFT; + INT32 offs = (UINT8)(op & THUMB_INSN_IMM) << 2; + SET_REGISTER(rd, ((R15 + 4) & ~2) + offs); + R15 += 2; +} + +void arm7_cpu_device::tg0a_1(UINT32 pc, UINT32 op) /* ADD Rd, SP, #nn */ +{ + UINT32 rd = (op & THUMB_RELADDR_RD) >> THUMB_RELADDR_RD_SHIFT; + INT32 offs = (UINT8)(op & THUMB_INSN_IMM) << 2; + SET_REGISTER(rd, GET_REGISTER(13) + offs); + R15 += 2; +} + + /* Stack-Related Opcodes */ + +void arm7_cpu_device::tg0b_0(UINT32 pc, UINT32 op) /* ADD SP, #imm */ +{ + UINT32 addr = (op & THUMB_INSN_IMM); + addr &= ~THUMB_INSN_IMM_S; + SET_REGISTER(13, GET_REGISTER(13) + ((op & THUMB_INSN_IMM_S) ? -(addr << 2) : (addr << 2))); + R15 += 2; +} + +void arm7_cpu_device::tg0b_1(UINT32 pc, UINT32 op) +{ + fatalerror("%08x: Gb Undefined Thumb instruction: %04x\n", pc, op); +} + +void arm7_cpu_device::tg0b_2(UINT32 pc, UINT32 op) +{ + fatalerror("%08x: Gb Undefined Thumb instruction: %04x\n", pc, op); +} + +void arm7_cpu_device::tg0b_3(UINT32 pc, UINT32 op) +{ + fatalerror("%08x: Gb Undefined Thumb instruction: %04x\n", pc, op); +} + +void arm7_cpu_device::tg0b_4(UINT32 pc, UINT32 op) /* PUSH {Rlist} */ +{ + for (INT32 offs = 7; offs >= 0; offs--) + { + if (op & (1 << offs)) + { + SET_REGISTER(13, GET_REGISTER(13) - 4); + WRITE32(GET_REGISTER(13), GET_REGISTER(offs)); + } + } + R15 += 2; +} + +void arm7_cpu_device::tg0b_5(UINT32 pc, UINT32 op) /* PUSH {Rlist}{LR} */ +{ + SET_REGISTER(13, GET_REGISTER(13) - 4); + WRITE32(GET_REGISTER(13), GET_REGISTER(14)); + for (INT32 offs = 7; offs >= 0; offs--) + { + if (op & (1 << offs)) + { + SET_REGISTER(13, GET_REGISTER(13) - 4); + WRITE32(GET_REGISTER(13), GET_REGISTER(offs)); + } + } + R15 += 2; +} + +void arm7_cpu_device::tg0b_6(UINT32 pc, UINT32 op) +{ + fatalerror("%08x: Gb Undefined Thumb instruction: %04x\n", pc, op); +} + +void arm7_cpu_device::tg0b_7(UINT32 pc, UINT32 op) +{ + fatalerror("%08x: Gb Undefined Thumb instruction: %04x\n", pc, op); +} + +void arm7_cpu_device::tg0b_8(UINT32 pc, UINT32 op) +{ + fatalerror("%08x: Gb Undefined Thumb instruction: %04x\n", pc, op); +} + +void arm7_cpu_device::tg0b_9(UINT32 pc, UINT32 op) +{ + fatalerror("%08x: Gb Undefined Thumb instruction: %04x\n", pc, op); +} + +void arm7_cpu_device::tg0b_a(UINT32 pc, UINT32 op) +{ + fatalerror("%08x: Gb Undefined Thumb instruction: %04x\n", pc, op); +} + +void arm7_cpu_device::tg0b_b(UINT32 pc, UINT32 op) +{ + fatalerror("%08x: Gb Undefined Thumb instruction: %04x\n", pc, op); +} + +void arm7_cpu_device::tg0b_c(UINT32 pc, UINT32 op) /* POP {Rlist} */ +{ + for (INT32 offs = 0; offs < 8; offs++) + { + if (op & (1 << offs)) + { + SET_REGISTER(offs, READ32(GET_REGISTER(13))); + SET_REGISTER(13, GET_REGISTER(13) + 4); + } + } + R15 += 2; +} + +void arm7_cpu_device::tg0b_d(UINT32 pc, UINT32 op) /* POP {Rlist}{PC} */ +{ + for (INT32 offs = 0; offs < 8; offs++) + { + if (op & (1 << offs)) + { + SET_REGISTER(offs, READ32(GET_REGISTER(13))); + SET_REGISTER(13, GET_REGISTER(13) + 4); + } + } + UINT32 addr = READ32(GET_REGISTER(13)); + if (m_archRev < 5) + { + R15 = addr & ~1; + } + else + { + if (addr & 1) + { + addr &= ~1; + } + else + { + SET_CPSR(GET_CPSR & ~T_MASK); + if (addr & 2) + { + addr += 2; + } + } + + R15 = addr; + } + SET_REGISTER(13, GET_REGISTER(13) + 4); +} + +void arm7_cpu_device::tg0b_e(UINT32 pc, UINT32 op) +{ + fatalerror("%08x: Gb Undefined Thumb instruction: %04x\n", pc, op); +} + +void arm7_cpu_device::tg0b_f(UINT32 pc, UINT32 op) +{ + fatalerror("%08x: Gb Undefined Thumb instruction: %04x\n", pc, op); +} + +/* Multiple Load/Store */ + +// "The address should normally be a word aligned quantity and non-word aligned addresses do not affect the instruction." +// "However, the bottom 2 bits of the address will appear on A[1:0] and might be interpreted by the memory system." + +// GBA "BB Ball" performs an unaligned read with A[1:0] = 2 and expects A[1] not to be ignored [BP 800B90A,(R4&3)!=0] +// GBA "Gadget Racers" performs an unaligned read with A[1:0] = 1 and expects A[0] to be ignored [BP B72,(R0&3)!=0] + +void arm7_cpu_device::tg0c_0(UINT32 pc, UINT32 op) /* Store */ +{ + UINT32 rd = (op & THUMB_MULTLS_BASE) >> THUMB_MULTLS_BASE_SHIFT; + UINT32 ld_st_address = GET_REGISTER(rd); + for (INT32 offs = 0; offs < 8; offs++) + { + if (op & (1 << offs)) + { + WRITE32(ld_st_address & ~3, GET_REGISTER(offs)); + ld_st_address += 4; + } + } + SET_REGISTER(rd, ld_st_address); + R15 += 2; +} + +void arm7_cpu_device::tg0c_1(UINT32 pc, UINT32 op) /* Load */ +{ + UINT32 rd = (op & THUMB_MULTLS_BASE) >> THUMB_MULTLS_BASE_SHIFT; + int rd_in_list = op & (1 << rd); + UINT32 ld_st_address = GET_REGISTER(rd); + for (INT32 offs = 0; offs < 8; offs++) + { + if (op & (1 << offs)) + { + SET_REGISTER(offs, READ32(ld_st_address & ~1)); + ld_st_address += 4; + } + } + if (!rd_in_list) + { + SET_REGISTER(rd, ld_st_address); + } + R15 += 2; +} + +/* Conditional Branch */ + +void arm7_cpu_device::tg0d_0(UINT32 pc, UINT32 op) // COND_EQ: +{ + INT32 offs = (INT8)(op & THUMB_INSN_IMM); + if (Z_IS_SET(GET_CPSR)) + { + R15 += 4 + (offs << 1); + } + else + { + R15 += 2; + } + +} + +void arm7_cpu_device::tg0d_1(UINT32 pc, UINT32 op) // COND_NE: +{ + INT32 offs = (INT8)(op & THUMB_INSN_IMM); + if (Z_IS_CLEAR(GET_CPSR)) + { + R15 += 4 + (offs << 1); + } + else + { + R15 += 2; + } +} + +void arm7_cpu_device::tg0d_2(UINT32 pc, UINT32 op) // COND_CS: +{ + INT32 offs = (INT8)(op & THUMB_INSN_IMM); + if (C_IS_SET(GET_CPSR)) + { + R15 += 4 + (offs << 1); + } + else + { + R15 += 2; + } +} + +void arm7_cpu_device::tg0d_3(UINT32 pc, UINT32 op) // COND_CC: +{ + INT32 offs = (INT8)(op & THUMB_INSN_IMM); + if (C_IS_CLEAR(GET_CPSR)) + { + R15 += 4 + (offs << 1); + } + else + { + R15 += 2; + } +} + +void arm7_cpu_device::tg0d_4(UINT32 pc, UINT32 op) // COND_MI: +{ + INT32 offs = (INT8)(op & THUMB_INSN_IMM); + if (N_IS_SET(GET_CPSR)) + { + R15 += 4 + (offs << 1); + } + else + { + R15 += 2; + } +} + +void arm7_cpu_device::tg0d_5(UINT32 pc, UINT32 op) // COND_PL: +{ + INT32 offs = (INT8)(op & THUMB_INSN_IMM); + if (N_IS_CLEAR(GET_CPSR)) + { + R15 += 4 + (offs << 1); + } + else + { + R15 += 2; + } +} + +void arm7_cpu_device::tg0d_6(UINT32 pc, UINT32 op) // COND_VS: +{ + INT32 offs = (INT8)(op & THUMB_INSN_IMM); + if (V_IS_SET(GET_CPSR)) + { + R15 += 4 + (offs << 1); + } + else + { + R15 += 2; + } +} + +void arm7_cpu_device::tg0d_7(UINT32 pc, UINT32 op) // COND_VC: +{ + INT32 offs = (INT8)(op & THUMB_INSN_IMM); + if (V_IS_CLEAR(GET_CPSR)) + { + R15 += 4 + (offs << 1); + } + else + { + R15 += 2; + } +} + +void arm7_cpu_device::tg0d_8(UINT32 pc, UINT32 op) // COND_HI: +{ + INT32 offs = (INT8)(op & THUMB_INSN_IMM); + if (C_IS_SET(GET_CPSR) && Z_IS_CLEAR(GET_CPSR)) + { + R15 += 4 + (offs << 1); + } + else + { + R15 += 2; + } +} + +void arm7_cpu_device::tg0d_9(UINT32 pc, UINT32 op) // COND_LS: +{ + INT32 offs = (INT8)(op & THUMB_INSN_IMM); + if (C_IS_CLEAR(GET_CPSR) || Z_IS_SET(GET_CPSR)) + { + R15 += 4 + (offs << 1); + } + else + { + R15 += 2; + } +} + +void arm7_cpu_device::tg0d_a(UINT32 pc, UINT32 op) // COND_GE: +{ + INT32 offs = (INT8)(op & THUMB_INSN_IMM); + if (!(GET_CPSR & N_MASK) == !(GET_CPSR & V_MASK)) + { + R15 += 4 + (offs << 1); + } + else + { + R15 += 2; + } +} + +void arm7_cpu_device::tg0d_b(UINT32 pc, UINT32 op) // COND_LT: +{ + INT32 offs = (INT8)(op & THUMB_INSN_IMM); + if (!(GET_CPSR & N_MASK) != !(GET_CPSR & V_MASK)) + { + R15 += 4 + (offs << 1); + } + else + { + R15 += 2; + } +} + +void arm7_cpu_device::tg0d_c(UINT32 pc, UINT32 op) // COND_GT: +{ + INT32 offs = (INT8)(op & THUMB_INSN_IMM); + if (Z_IS_CLEAR(GET_CPSR) && !(GET_CPSR & N_MASK) == !(GET_CPSR & V_MASK)) + { + R15 += 4 + (offs << 1); + } + else + { + R15 += 2; + } +} + +void arm7_cpu_device::tg0d_d(UINT32 pc, UINT32 op) // COND_LE: +{ + INT32 offs = (INT8)(op & THUMB_INSN_IMM); + if (Z_IS_SET(GET_CPSR) || !(GET_CPSR & N_MASK) != !(GET_CPSR & V_MASK)) + { + R15 += 4 + (offs << 1); + } + else + { + R15 += 2; + } +} + +void arm7_cpu_device::tg0d_e(UINT32 pc, UINT32 op) // COND_AL: +{ + fatalerror("%08x: Undefined Thumb instruction: %04x (ARM9 reserved)\n", pc, op); +} + +void arm7_cpu_device::tg0d_f(UINT32 pc, UINT32 op) // COND_NV: // SWI (this is sort of a "hole" in the opcode encoding) +{ + m_pendingSwi = 1; + ARM7_CHECKIRQ; +} + +/* B #offs */ + +void arm7_cpu_device::tg0e_0(UINT32 pc, UINT32 op) +{ + INT32 offs = (op & THUMB_BRANCH_OFFS) << 1; + if (offs & 0x00000800) + { + offs |= 0xfffff800; + } + R15 += 4 + offs; +} + +void arm7_cpu_device::tg0e_1(UINT32 pc, UINT32 op) +{ + UINT32 addr = GET_REGISTER(14); + addr += (op & THUMB_BLOP_OFFS) << 1; + addr &= 0xfffffffc; + SET_REGISTER(14, (R15 + 4) | 1); + R15 = addr; +} + + /* BL */ + +void arm7_cpu_device::tg0f_0(UINT32 pc, UINT32 op) +{ + UINT32 addr = (op & THUMB_BLOP_OFFS) << 12; + if (addr & (1 << 22)) + { + addr |= 0xff800000; + } + addr += R15 + 4; + SET_REGISTER(14, addr); + R15 += 2; +} + +void arm7_cpu_device::tg0f_1(UINT32 pc, UINT32 op) /* BL */ +{ + UINT32 addr = GET_REGISTER(14) & ~1; + addr += (op & THUMB_BLOP_OFFS) << 1; + SET_REGISTER(14, (R15 + 2) | 1); + R15 = addr; + //R15 += 2; +} diff --git a/src/devices/cpu/asap/asap.c b/src/devices/cpu/asap/asap.c new file mode 100644 index 00000000000..21133e46975 --- /dev/null +++ b/src/devices/cpu/asap/asap.c @@ -0,0 +1,1685 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + asap.c + + Core implementation for the portable ASAP emulator. + ASAP = Atari Simplified Architecture Processor + + Special thanks to Mike Albaugh for clarification on a couple of fine points. + +***************************************************************************/ + +#include "emu.h" +#include "debugger.h" +#include "asap.h" + + +//************************************************************************** +// CONSTANTS +//************************************************************************** + +const UINT32 PS_CFLAG = 0x00000001; +const UINT32 PS_VFLAG = 0x00000002; +const UINT32 PS_ZFLAG = 0x00000004; +const UINT32 PS_NFLAG = 0x00000008; +const UINT32 PS_IFLAG = 0x00000010; +const UINT32 PS_PFLAG = 0x00000020; + +//const int EXCEPTION_RESET = 0; +const int EXCEPTION_TRAP0 = 1; +const int EXCEPTION_TRAPF = 2; +const int EXCEPTION_INTERRUPT = 3; + +const int REGBASE = 0xffe0; + + + +//************************************************************************** +// MACROS +//************************************************************************** + +#define SET_C_ADD(a,b) (m_cflag = (UINT32)(b) > (UINT32)(~(a))) +#define SET_C_SUB(a,b) (m_cflag = (UINT32)(b) <= (UINT32)(a)) +#define SET_V_ADD(r,a,b) (m_vflag = ~((a) ^ (b)) & ((a) ^ (r))) +#define SET_V_SUB(r,a,b) (m_vflag = ((a) ^ (b)) & ((a) ^ (r))) +#define SET_ZN(r) (m_znflag = (r)) +#define SET_ZNCV_ADD(r,a,b) SET_ZN(r); SET_C_ADD(a,b); SET_V_ADD(r,a,b) +#define SET_ZNCV_SUB(r,a,b) SET_ZN(r); SET_C_SUB(a,b); SET_V_SUB(r,a,b) + +#define SET_VFLAG(val) (m_vflag = (val) << 31) +#define SET_CFLAG(val) (m_cflag = (val)) + +#define GET_FLAGS() (m_cflag | \ + ((m_vflag >> 30) & PS_VFLAG) | \ + ((m_znflag == 0) << 2) | \ + ((m_znflag >> 28) & PS_NFLAG) | \ + (m_iflag << 4) | \ + (m_pflag << 5)) + +#define SET_FLAGS(v) do { \ + m_cflag = (v) & PS_CFLAG; \ + m_vflag = ((v) & PS_VFLAG) << 30; \ + m_znflag = ((v) & PS_ZFLAG) ? 0 : ((v) & PS_NFLAG) ? -1 : 1; \ + m_iflag = ((v) & PS_IFLAG) >> 4; \ + m_pflag = ((v) & PS_PFLAG) >> 5; \ + } while (0); + +#define OPCODE (m_op >> 27) +#define DSTREG ((m_op >> 22) & 31) +#define DSTVAL m_src2val[REGBASE + DSTREG] +#define SRC1REG ((m_op >> 16) & 31) +#define SRC1VAL m_src2val[REGBASE + SRC1REG] +#define SRC2VAL m_src2val[m_op & 0xffff] + + + +//************************************************************************** +// STATIC OPCODE TABLES +//************************************************************************** + +const asap_device::ophandler asap_device::s_opcodetable[32][4] = +{ + { &asap_device::trap0, &asap_device::trap0, &asap_device::trap0, &asap_device::trap0 }, + { &asap_device::noop, &asap_device::noop, &asap_device::noop, &asap_device::noop }, + { &asap_device::bsr, &asap_device::bsr_0, &asap_device::bsr, &asap_device::bsr_0 }, + { &asap_device::lea, &asap_device::noop, &asap_device::lea_c, &asap_device::lea_c0 }, + { &asap_device::leah, &asap_device::noop, &asap_device::leah_c, &asap_device::leah_c0 }, + { &asap_device::subr, &asap_device::noop, &asap_device::subr_c, &asap_device::subr_c0 }, + { &asap_device::xor_, &asap_device::noop, &asap_device::xor_c, &asap_device::xor_c0 }, + { &asap_device::xorn, &asap_device::noop, &asap_device::xorn_c, &asap_device::xorn_c0 }, + { &asap_device::add, &asap_device::noop, &asap_device::add_c, &asap_device::add_c0 }, + { &asap_device::sub, &asap_device::noop, &asap_device::sub_c, &asap_device::sub_c0 }, + { &asap_device::addc, &asap_device::noop, &asap_device::addc_c, &asap_device::addc_c0 }, + { &asap_device::subc, &asap_device::noop, &asap_device::subc_c, &asap_device::subc_c0 }, + { &asap_device::and_, &asap_device::noop, &asap_device::and_c, &asap_device::and_c0 }, + { &asap_device::andn, &asap_device::noop, &asap_device::andn_c, &asap_device::andn_c0 }, + { &asap_device::or_, &asap_device::noop, &asap_device::or_c, &asap_device::or_c0 }, + { &asap_device::orn, &asap_device::noop, &asap_device::orn_c, &asap_device::orn_c0 }, + { &asap_device::ld, &asap_device::ld_0, &asap_device::ld_c, &asap_device::ld_c0 }, + { &asap_device::ldh, &asap_device::ldh_0, &asap_device::ldh_c, &asap_device::ldh_c0 }, + { &asap_device::lduh, &asap_device::lduh_0, &asap_device::lduh_c, &asap_device::lduh_c0 }, + { &asap_device::sth, &asap_device::sth_0, &asap_device::sth_c, &asap_device::sth_c0 }, + { &asap_device::st, &asap_device::st_0, &asap_device::st_c, &asap_device::st_c0 }, + { &asap_device::ldb, &asap_device::ldb_0, &asap_device::ldb_c, &asap_device::ldb_c0 }, + { &asap_device::ldub, &asap_device::ldub_0, &asap_device::ldub_c, &asap_device::ldub_c0 }, + { &asap_device::stb, &asap_device::stb_0, &asap_device::stb_c, &asap_device::stb_c0 }, + { &asap_device::ashr, &asap_device::noop, &asap_device::ashr_c, &asap_device::ashr_c0 }, + { &asap_device::lshr, &asap_device::noop, &asap_device::lshr_c, &asap_device::lshr_c0 }, + { &asap_device::ashl, &asap_device::noop, &asap_device::ashl_c, &asap_device::ashl_c0 }, + { &asap_device::rotl, &asap_device::noop, &asap_device::rotl_c, &asap_device::rotl_c0 }, + { &asap_device::getps, &asap_device::noop, &asap_device::getps, &asap_device::noop }, + { &asap_device::putps, &asap_device::putps, &asap_device::putps, &asap_device::putps }, + { &asap_device::jsr, &asap_device::jsr_0, &asap_device::jsr_c, &asap_device::jsr_c0 }, + { &asap_device::trapf, &asap_device::trapf, &asap_device::trapf, &asap_device::trapf } +}; + +const asap_device::ophandler asap_device::s_conditiontable[16] = +{ + &asap_device::bsp, &asap_device::bmz, &asap_device::bgt, &asap_device::ble, + &asap_device::bge, &asap_device::blt, &asap_device::bhi, &asap_device::bls, + &asap_device::bcc, &asap_device::bcs, &asap_device::bpl, &asap_device::bmi, + &asap_device::bne, &asap_device::beq, &asap_device::bvc, &asap_device::bvs +}; + + + +//************************************************************************** +// DEVICE INTERFACE +//************************************************************************** + +// device type definition +const device_type ASAP = &device_creator; + +//------------------------------------------------- +// asap_device - constructor +//------------------------------------------------- + +asap_device::asap_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : cpu_device(mconfig, ASAP, "ASAP", tag, owner, clock, "asap", __FILE__), + m_program_config("program", ENDIANNESS_LITTLE, 32, 32), + m_pc(0), + m_pflag(0), + m_iflag(0), + m_cflag(0), + m_vflag(0), + m_znflag(0), + m_flagsio(0), + m_op(0), + m_ppc(0), + m_nextpc(0), + m_irq_state(0), + m_icount(0), + m_program(NULL), + m_direct(NULL) +{ + // initialize the src2val table to contain immediates for low values + for (int i = 0; i < REGBASE; i++) + m_src2val[i] = i; + + // build the opcode table + for (int op = 0; op < 32; op++) + for (int dst = 0; dst < 32; dst++) + for (int cond = 0; cond < 2; cond++) + if (op == 1) + m_opcode[(op << 6) + (dst << 1) + cond] = s_conditiontable[dst & 15]; + else if (cond && dst == 0) + m_opcode[(op << 6) + (dst << 1) + cond] = s_opcodetable[op][3]; + else if (cond) + m_opcode[(op << 6) + (dst << 1) + cond] = s_opcodetable[op][2]; + else if (dst == 0) + m_opcode[(op << 6) + (dst << 1) + cond] = s_opcodetable[op][1]; + else + m_opcode[(op << 6) + (dst << 1) + cond] = s_opcodetable[op][0]; +} + + +//------------------------------------------------- +// device_start - start up the device +//------------------------------------------------- + +void asap_device::device_start() +{ + // get our address spaces + m_program = &space(AS_PROGRAM); + m_direct = &m_program->direct(); + + // register our state for the debugger + std::string tempstr; + state_add(STATE_GENPC, "GENPC", m_pc).noshow(); + state_add(STATE_GENPCBASE, "GENPCBASE", m_ppc).noshow(); + state_add(STATE_GENSP, "GENSP", m_src2val[REGBASE + 31]).noshow(); + state_add(STATE_GENFLAGS, "GENFLAGS", m_flagsio).callimport().callexport().formatstr("%6s").noshow(); + state_add(ASAP_PC, "PC", m_pc); + state_add(ASAP_PS, "PS", m_flagsio).callimport().callexport(); + for (int regnum = 0; regnum < 32; regnum++) + state_add(ASAP_R0 + regnum, strformat(tempstr, "R%d", regnum).c_str(), m_src2val[REGBASE + regnum]); + + // register our state for saving + save_item(NAME(m_pc)); + save_item(NAME(m_pflag)); + save_item(NAME(m_iflag)); + save_item(NAME(m_cflag)); + save_item(NAME(m_vflag)); + save_item(NAME(m_znflag)); + save_item(NAME(m_op)); + save_item(NAME(m_ppc)); + save_item(NAME(m_nextpc)); + save_item(NAME(m_irq_state)); + + // set our instruction counter + m_icountptr = &m_icount; +} + + +//------------------------------------------------- +// device_reset - reset the device +//------------------------------------------------- + +void asap_device::device_reset() +{ + // initialize the state + m_src2val[REGBASE + 0] = 0; + m_pc = 0; + m_iflag = 0; + + m_ppc = 0; + m_nextpc = ~0; + m_irq_state = 0; +} + + +//------------------------------------------------- +// memory_space_config - return the configuration +// of the specified address space, or NULL if +// the space doesn't exist +//------------------------------------------------- + +const address_space_config *asap_device::memory_space_config(address_spacenum spacenum) const +{ + return (spacenum == AS_PROGRAM) ? &m_program_config : NULL; +} + + +//------------------------------------------------- +// state_import - import state into the device, +// after it has been set +//------------------------------------------------- + +void asap_device::state_import(const device_state_entry &entry) +{ + switch (entry.index()) + { + case STATE_GENFLAGS: + case ASAP_PS: + SET_FLAGS(m_flagsio); + break; + } +} + + +//------------------------------------------------- +// state_export - export state from the device, +// to a known location where it can be read +//------------------------------------------------- + +void asap_device::state_export(const device_state_entry &entry) +{ + switch (entry.index()) + { + case STATE_GENFLAGS: + case ASAP_PS: + m_flagsio = GET_FLAGS(); + break; + } +} + + +//------------------------------------------------- +// state_string_export - export state as a string +// for the debugger +//------------------------------------------------- + +void asap_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + switch (entry.index()) + { + case STATE_GENFLAGS: + strprintf(str, "%c%c%c%c%c%c", + m_pflag ? 'P' : '.', + m_iflag ? 'I' : '.', + ((INT32)m_znflag < 0) ? 'N' : '.', + (m_znflag == 0) ? 'Z' : '.', + ((m_vflag >> 30) & PS_VFLAG) ? 'V' : '.', + m_cflag ? 'C' : '.'); + break; + } +} + + +//------------------------------------------------- +// disasm_min_opcode_bytes - return the length +// of the shortest instruction, in bytes +//------------------------------------------------- + +UINT32 asap_device::disasm_min_opcode_bytes() const +{ + return 4; +} + + +//------------------------------------------------- +// disasm_max_opcode_bytes - return the length +// of the longest instruction, in bytes +//------------------------------------------------- + +UINT32 asap_device::disasm_max_opcode_bytes() const +{ + return 12; +} + + +//------------------------------------------------- +// disasm_disassemble - call the disassembly +// helper function +//------------------------------------------------- + +offs_t asap_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( asap ); + return CPU_DISASSEMBLE_NAME(asap)(this, buffer, pc, oprom, opram, options); +} + + + +//************************************************************************** +// INLINE HELPERS +//************************************************************************** + +//------------------------------------------------- +// readop - read an opcode at the given address +//------------------------------------------------- + +inline UINT32 asap_device::readop(offs_t pc) +{ + return m_direct->read_dword(pc); +} + + +//------------------------------------------------- +// readbyte - read a byte at the given address +//------------------------------------------------- + +inline UINT8 asap_device::readbyte(offs_t address) +{ + // no alignment issues with bytes + return m_program->read_byte(address); +} + + +//------------------------------------------------- +// readword - read a word at the given address +//------------------------------------------------- + +inline UINT16 asap_device::readword(offs_t address) +{ + // aligned reads are easy + if (!(address & 1)) + return m_program->read_word(address); + + // misaligned reads are tricky + return m_program->read_dword(address & ~3) >> (address & 3); +} + + +//------------------------------------------------- +// readlong - read a long at the given address +//------------------------------------------------- + +inline UINT32 asap_device::readlong(offs_t address) +{ + // aligned reads are easy + if (!(address & 3)) + return m_program->read_dword(address); + + // misaligned reads are tricky + return m_program->read_dword(address & ~3) >> (address & 3); +} + + +//------------------------------------------------- +// writebyte - write a byte at the given address +//------------------------------------------------- + +inline void asap_device::writebyte(offs_t address, UINT8 data) +{ + // no alignment issues with bytes + m_program->write_byte(address, data); +} + + +//------------------------------------------------- +// writeword - write a word at the given address +//------------------------------------------------- + +inline void asap_device::writeword(offs_t address, UINT16 data) +{ + // aligned writes are easy + if (!(address & 1)) + { + m_program->write_word(address, data); + return; + } + + // misaligned writes are tricky + if (!(address & 2)) + { + m_program->write_byte(address + 1, data); + m_program->write_byte(address + 2, data >> 8); + } + else + m_program->write_byte(address + 1, data); +} + + +//------------------------------------------------- +// writelong - write a long at the given address +//------------------------------------------------- + +inline void asap_device::writelong(offs_t address, UINT32 data) +{ + // aligned writes are easy + if (!(address & 3)) + { + m_program->write_dword(address, data); + return; + } + + // misaligned writes are tricky + switch (address & 3) + { + case 1: + m_program->write_byte(address, data); + m_program->write_word(address + 1, data >> 8); + break; + case 2: + m_program->write_word(address, data); + break; + case 3: + m_program->write_byte(address, data); + break; + } +} + + +//------------------------------------------------- +// generate_exception - generate an exception of +// the requested type +//------------------------------------------------- + +inline void asap_device::generate_exception(int exception) +{ + m_pflag = m_iflag; + m_iflag = 0; + + m_src2val[REGBASE + 30] = m_pc; + m_src2val[REGBASE + 31] = (m_nextpc == ~0) ? m_pc + 4 : m_nextpc; + + m_pc = 0x40 * exception; + m_nextpc = ~0; + + m_icount--; +} + + +//------------------------------------------------- +// check_irqs - check for pending IRQs +//------------------------------------------------- + +inline void asap_device::check_irqs() +{ + if (m_irq_state && m_iflag) + { + generate_exception(EXCEPTION_INTERRUPT); + standard_irq_callback(ASAP_IRQ0); + } +} + + + +//************************************************************************** +// CORE EXECUTION +//************************************************************************** + +inline void asap_device::fetch_instruction() +{ + // debugging + m_ppc = m_pc; + + // instruction fetch + m_op = readop(m_pc); + m_pc += 4; +} + +inline void asap_device::fetch_instruction_debug() +{ + // debugging + m_ppc = m_pc; + debugger_instruction_hook(this, m_pc); + + // instruction fetch + m_op = readop(m_pc); + m_pc += 4; +} + +inline void asap_device::execute_instruction() +{ + // parse the instruction + (this->*m_opcode[m_op >> 21])(); +} + + +//------------------------------------------------- +// execute_min_cycles - return minimum number of +// cycles it takes for one instruction to execute +//------------------------------------------------- + +UINT32 asap_device::execute_min_cycles() const +{ + return 1; +} + + +//------------------------------------------------- +// execute_max_cycles - return maximum number of +// cycles it takes for one instruction to execute +//------------------------------------------------- + +UINT32 asap_device::execute_max_cycles() const +{ + return 2; +} + + +//------------------------------------------------- +// execute_input_lines - return the number of +// input/interrupt lines +//------------------------------------------------- + +UINT32 asap_device::execute_input_lines() const +{ + return 1; +} + + +void asap_device::execute_set_input(int inputnum, int state) +{ + m_irq_state = (state != CLEAR_LINE); +} + + +void asap_device::execute_run() +{ + // check for IRQs + check_irqs(); + + // core execution loop + if ((device_t::machine().debug_flags & DEBUG_FLAG_ENABLED) == 0) + { + do + { + // fetch and execute the next instruction + fetch_instruction(); + execute_instruction(); + + // fetch and execute the next instruction + fetch_instruction(); + execute_instruction(); + + // fetch and execute the next instruction + fetch_instruction(); + execute_instruction(); + + // fetch and execute the next instruction + fetch_instruction(); + execute_instruction(); + + m_icount -= 4; + + } while (m_icount > 0); + } + else + { + do + { + // fetch and execute the next instruction + fetch_instruction_debug(); + execute_instruction(); + + // fetch and execute the next instruction + fetch_instruction_debug(); + execute_instruction(); + + // fetch and execute the next instruction + fetch_instruction_debug(); + execute_instruction(); + + // fetch and execute the next instruction + fetch_instruction_debug(); + execute_instruction(); + + m_icount -= 4; + + } while (m_icount > 0); + } +} + + + +//************************************************************************** +// OPCODE IMPLEMENTATIONS +//************************************************************************** + +void asap_device::noop() +{ +} + +/**************************** TRAP 0 ******************************/ + +void asap_device::trap0() +{ + generate_exception(EXCEPTION_TRAP0); +} + +/**************************** Bcc ******************************/ + +void asap_device::bsp() +{ + if ((INT32)m_znflag > 0) + { + m_nextpc = m_ppc + ((INT32)(m_op << 10) >> 8); + + fetch_instruction(); + m_pc = m_nextpc; + m_nextpc = ~0; + + execute_instruction(); + m_icount--; + } +} + +void asap_device::bmz() +{ + if ((INT32)m_znflag <= 0) + { + m_nextpc = m_ppc + ((INT32)(m_op << 10) >> 8); + + fetch_instruction(); + m_pc = m_nextpc; + m_nextpc = ~0; + + execute_instruction(); + m_icount--; + } +} + +void asap_device::bgt() +{ + if (m_znflag != 0 && (INT32)(m_znflag ^ m_vflag) >= 0) + { + m_nextpc = m_ppc + ((INT32)(m_op << 10) >> 8); + + fetch_instruction(); + m_pc = m_nextpc; + m_nextpc = ~0; + + execute_instruction(); + m_icount--; + } +} + +void asap_device::ble() +{ + if (m_znflag == 0 || (INT32)(m_znflag ^ m_vflag) < 0) + { + m_nextpc = m_ppc + ((INT32)(m_op << 10) >> 8); + + fetch_instruction(); + m_pc = m_nextpc; + m_nextpc = ~0; + + execute_instruction(); + m_icount--; + } +} + +void asap_device::bge() +{ + if ((INT32)(m_znflag ^ m_vflag) >= 0) + { + m_nextpc = m_ppc + ((INT32)(m_op << 10) >> 8); + + fetch_instruction(); + m_pc = m_nextpc; + m_nextpc = ~0; + + execute_instruction(); + m_icount--; + } +} + +void asap_device::blt() +{ + if ((INT32)(m_znflag ^ m_vflag) < 0) + { + m_nextpc = m_ppc + ((INT32)(m_op << 10) >> 8); + + fetch_instruction(); + m_pc = m_nextpc; + m_nextpc = ~0; + + execute_instruction(); + m_icount--; + } +} + +void asap_device::bhi() +{ + if (m_znflag != 0 && m_cflag) + { + m_nextpc = m_ppc + ((INT32)(m_op << 10) >> 8); + + fetch_instruction(); + m_pc = m_nextpc; + m_nextpc = ~0; + + execute_instruction(); + m_icount--; + } +} + +void asap_device::bls() +{ + if (m_znflag == 0 || !m_cflag) + { + m_nextpc = m_ppc + ((INT32)(m_op << 10) >> 8); + + fetch_instruction(); + m_pc = m_nextpc; + m_nextpc = ~0; + + execute_instruction(); + m_icount--; + } +} + +void asap_device::bcc() +{ + if (!m_cflag) + { + m_nextpc = m_ppc + ((INT32)(m_op << 10) >> 8); + + fetch_instruction(); + m_pc = m_nextpc; + m_nextpc = ~0; + + execute_instruction(); + m_icount--; + } +} + +void asap_device::bcs() +{ + if (m_cflag) + { + m_nextpc = m_ppc + ((INT32)(m_op << 10) >> 8); + + fetch_instruction(); + m_pc = m_nextpc; + m_nextpc = ~0; + + execute_instruction(); + m_icount--; + } +} + +void asap_device::bpl() +{ + if ((INT32)m_znflag >= 0) + { + m_nextpc = m_ppc + ((INT32)(m_op << 10) >> 8); + + fetch_instruction(); + m_pc = m_nextpc; + m_nextpc = ~0; + + execute_instruction(); + m_icount--; + } +} + +void asap_device::bmi() +{ + if ((INT32)m_znflag < 0) + { + m_nextpc = m_ppc + ((INT32)(m_op << 10) >> 8); + + fetch_instruction(); + m_pc = m_nextpc; + m_nextpc = ~0; + + execute_instruction(); + m_icount--; + } +} + +void asap_device::bne() +{ + if (m_znflag != 0) + { + m_nextpc = m_ppc + ((INT32)(m_op << 10) >> 8); + + fetch_instruction(); + m_pc = m_nextpc; + m_nextpc = ~0; + + execute_instruction(); + m_icount--; + } +} + +void asap_device::beq() +{ + if (m_znflag == 0) + { + m_nextpc = m_ppc + ((INT32)(m_op << 10) >> 8); + + fetch_instruction(); + m_pc = m_nextpc; + m_nextpc = ~0; + + execute_instruction(); + m_icount--; + } +} + +void asap_device::bvc() +{ + if ((INT32)m_vflag >= 0) + { + m_nextpc = m_ppc + ((INT32)(m_op << 10) >> 8); + + fetch_instruction(); + m_pc = m_nextpc; + m_nextpc = ~0; + + execute_instruction(); + m_icount--; + } +} + +void asap_device::bvs() +{ + if ((INT32)m_vflag < 0) + { + m_nextpc = m_ppc + ((INT32)(m_op << 10) >> 8); + + fetch_instruction(); + m_pc = m_nextpc; + m_nextpc = ~0; + + execute_instruction(); + m_icount--; + } +} + +/**************************** BSR ******************************/ + +void asap_device::bsr() +{ + DSTVAL = m_pc + 4; + m_nextpc = m_ppc + ((INT32)(m_op << 10) >> 8); + + fetch_instruction(); + m_pc = m_nextpc; + m_nextpc = ~0; + + execute_instruction(); + m_icount--; +} + +void asap_device::bsr_0() +{ + m_nextpc = m_ppc + ((INT32)(m_op << 10) >> 8); + + fetch_instruction(); + m_pc = m_nextpc; + m_nextpc = ~0; + + execute_instruction(); + m_icount--; +} + +/**************************** LEA ******************************/ + +void asap_device::lea() +{ + DSTVAL = SRC1VAL + (SRC2VAL << 2); +} + +void asap_device::lea_c() +{ + UINT32 src1 = SRC1VAL; + UINT32 src2 = SRC2VAL; + UINT32 dst = src1 + (src2 << 2); + + SET_ZNCV_ADD(dst, src1, src2); + if (src1 & 0xc0000000) + SET_CFLAG(1); + if (((src1 ^ (src1 >> 1)) & 0x20000000) || (src1 ^ (src1 >> 2)) & 0x20000000) + SET_VFLAG(1); + DSTVAL = dst; +} + +void asap_device::lea_c0() +{ + UINT32 src1 = SRC1VAL; + UINT32 src2 = SRC2VAL; + UINT32 dst = src1 + (src2 << 2); + + SET_ZNCV_ADD(dst, src1, src2); + if (src1 & 0xc0000000) + SET_CFLAG(1); + if (((src1 ^ (src1 >> 1)) & 0x20000000) || (src1 ^ (src1 >> 2)) & 0x20000000) + SET_VFLAG(1); +} + +/**************************** LEAH ******************************/ + +void asap_device::leah() +{ + DSTVAL = SRC1VAL + (SRC2VAL << 1); +} + +void asap_device::leah_c() +{ + UINT32 src1 = SRC1VAL; + UINT32 src2 = SRC2VAL; + UINT32 dst = src1 + (src2 << 1); + + SET_ZNCV_ADD(dst, src1, src2); + if (src1 & 0x80000000) + SET_CFLAG(1); + if ((src1 ^ (src1 >> 1)) & 0x40000000) + SET_VFLAG(1); + DSTVAL = dst; +} + +void asap_device::leah_c0() +{ + UINT32 src1 = SRC1VAL; + UINT32 src2 = SRC2VAL; + UINT32 dst = src1 + (src2 << 1); + + SET_ZNCV_ADD(dst, src1, src2); + if (src1 & 0x80000000) + SET_CFLAG(1); + if ((src1 ^ (src1 >> 1)) & 0x40000000) + SET_VFLAG(1); +} + +/**************************** SUBR ******************************/ + +void asap_device::subr() +{ + DSTVAL = SRC2VAL - SRC1VAL; +} + +void asap_device::subr_c() +{ + UINT32 src1 = SRC1VAL; + UINT32 src2 = SRC2VAL; + UINT32 dst = src2 - src1; + + SET_ZNCV_SUB(dst, src2, src1); + DSTVAL = dst; +} + +void asap_device::subr_c0() +{ + UINT32 src1 = SRC1VAL; + UINT32 src2 = SRC2VAL; + UINT32 dst = src2 - src1; + + SET_ZNCV_SUB(dst, src2, src1); +} + +/**************************** XOR ******************************/ + +void asap_device::xor_() +{ + DSTVAL = SRC1VAL ^ SRC2VAL; +} + +void asap_device::xor_c() +{ + UINT32 dst = SRC1VAL ^ SRC2VAL; + SET_ZN(dst); + DSTVAL = dst; +} + +void asap_device::xor_c0() +{ + UINT32 dst = SRC1VAL ^ SRC2VAL; + SET_ZN(dst); +} + +/**************************** XOR ******************************/ + +void asap_device::xorn() +{ + DSTVAL = SRC1VAL ^ ~SRC2VAL; +} + +void asap_device::xorn_c() +{ + UINT32 dst = SRC1VAL ^ ~SRC2VAL; + SET_ZN(dst); + DSTVAL = dst; +} + +void asap_device::xorn_c0() +{ + UINT32 dst = SRC1VAL ^ ~SRC2VAL; + SET_ZN(dst); +} + +/**************************** ADD ******************************/ + +void asap_device::add() +{ + DSTVAL = SRC1VAL + SRC2VAL; +} + +void asap_device::add_c() +{ + UINT32 src1 = SRC1VAL; + UINT32 src2 = SRC2VAL; + UINT32 dst = src1 + src2; + + SET_ZNCV_ADD(dst, src1, src2); + DSTVAL = dst; +} + +void asap_device::add_c0() +{ + UINT32 src1 = SRC1VAL; + UINT32 src2 = SRC2VAL; + UINT32 dst = src1 + src2; + + SET_ZNCV_ADD(dst, src1, src2); +} + +/**************************** ADD ******************************/ + +void asap_device::sub() +{ + DSTVAL = SRC1VAL - SRC2VAL; +} + +void asap_device::sub_c() +{ + UINT32 src1 = SRC1VAL; + UINT32 src2 = SRC2VAL; + UINT32 dst = src1 - src2; + + SET_ZNCV_SUB(dst, src1, src2); + DSTVAL = dst; +} + +void asap_device::sub_c0() +{ + UINT32 src1 = SRC1VAL; + UINT32 src2 = SRC2VAL; + UINT32 dst = src1 - src2; + + SET_ZNCV_SUB(dst, src1, src2); +} + +/**************************** ADDC ******************************/ + +void asap_device::addc() +{ + DSTVAL = SRC1VAL + SRC2VAL + m_cflag; +} + +void asap_device::addc_c() +{ + UINT32 src1 = SRC1VAL; + UINT32 src2 = SRC2VAL; + UINT32 dst = src1 + src2 + m_cflag; + + SET_ZNCV_ADD(dst, src1, src2); + DSTVAL = dst; +} + +void asap_device::addc_c0() +{ + UINT32 src1 = SRC1VAL; + UINT32 src2 = SRC2VAL; + UINT32 dst = src1 + src2 + m_cflag; + + SET_ZNCV_ADD(dst, src1, src2); +} + +/**************************** SUBC ******************************/ + +void asap_device::subc() +{ + DSTVAL = SRC1VAL - SRC2VAL - 1 + m_cflag; +} + +void asap_device::subc_c() +{ + UINT32 src1 = SRC1VAL; + UINT32 src2 = SRC2VAL; + UINT32 dst = src1 - src2 - 1 + m_cflag; + + SET_ZNCV_SUB(dst, src1, src2); + DSTVAL = dst; +} + +void asap_device::subc_c0() +{ + UINT32 src1 = SRC1VAL; + UINT32 src2 = SRC2VAL; + UINT32 dst = src1 - src2 - 1 + m_cflag; + + SET_ZNCV_SUB(dst, src1, src2); +} + +/**************************** AND ******************************/ + +void asap_device::and_() +{ + DSTVAL = SRC1VAL & SRC2VAL; +} + +void asap_device::and_c() +{ + UINT32 dst = SRC1VAL & SRC2VAL; + SET_ZN(dst); + DSTVAL = dst; +} + +void asap_device::and_c0() +{ + UINT32 dst = SRC1VAL & SRC2VAL; + SET_ZN(dst); +} + +/**************************** ANDN ******************************/ + +void asap_device::andn() +{ + DSTVAL = SRC1VAL & ~SRC2VAL; +} + +void asap_device::andn_c() +{ + UINT32 dst = SRC1VAL & ~SRC2VAL; + SET_ZN(dst); + DSTVAL = dst; +} + +void asap_device::andn_c0() +{ + UINT32 dst = SRC1VAL & ~SRC2VAL; + SET_ZN(dst); +} + +/**************************** OR ******************************/ + +void asap_device::or_() +{ + DSTVAL = SRC1VAL | SRC2VAL; +} + +void asap_device::or_c() +{ + UINT32 dst = SRC1VAL | SRC2VAL; + SET_ZN(dst); + DSTVAL = dst; +} + +void asap_device::or_c0() +{ + UINT32 dst = SRC1VAL | SRC2VAL; + SET_ZN(dst); +} + +/**************************** ORN ******************************/ + +void asap_device::orn() +{ + DSTVAL = SRC1VAL | ~SRC2VAL; +} + +void asap_device::orn_c() +{ + UINT32 dst = SRC1VAL | ~SRC2VAL; + SET_ZN(dst); + DSTVAL = dst; +} + +void asap_device::orn_c0() +{ + UINT32 dst = SRC1VAL | ~SRC2VAL; + SET_ZN(dst); +} + +/**************************** LD ******************************/ + +void asap_device::ld() +{ + DSTVAL = readlong(SRC1VAL + (SRC2VAL << 2)); +} + +void asap_device::ld_0() +{ + readlong(SRC1VAL + (SRC2VAL << 2)); +} + +void asap_device::ld_c() +{ + UINT32 dst = readlong(SRC1VAL + (SRC2VAL << 2)); + SET_ZN(dst); + DSTVAL = dst; +} + +void asap_device::ld_c0() +{ + UINT32 dst = readlong(SRC1VAL + (SRC2VAL << 2)); + SET_ZN(dst); +} + +/**************************** LDH ******************************/ + +void asap_device::ldh() +{ + DSTVAL = (INT16)readword(SRC1VAL + (SRC2VAL << 1)); +} + +void asap_device::ldh_0() +{ + readword(SRC1VAL + (SRC2VAL << 1)); +} + +void asap_device::ldh_c() +{ + UINT32 dst = (INT16)readword(SRC1VAL + (SRC2VAL << 1)); + SET_ZN(dst); + DSTVAL = dst; +} + +void asap_device::ldh_c0() +{ + UINT32 dst = (INT16)readword(SRC1VAL + (SRC2VAL << 1)); + SET_ZN(dst); +} + +/**************************** LDUH ******************************/ + +void asap_device::lduh() +{ + DSTVAL = readword(SRC1VAL + (SRC2VAL << 1)); +} + +void asap_device::lduh_0() +{ + readword(SRC1VAL + (SRC2VAL << 1)); +} + +void asap_device::lduh_c() +{ + UINT32 dst = readword(SRC1VAL + (SRC2VAL << 1)); + SET_ZN(dst); + DSTVAL = dst; +} + +void asap_device::lduh_c0() +{ + UINT32 dst = readword(SRC1VAL + (SRC2VAL << 1)); + SET_ZN(dst); +} + +/**************************** STH ******************************/ + +void asap_device::sth() +{ + writeword(SRC1VAL + (SRC2VAL << 1), DSTVAL); +} + +void asap_device::sth_0() +{ + writeword(SRC1VAL + (SRC2VAL << 1), 0); +} + +void asap_device::sth_c() +{ + UINT32 dst = (UINT16)DSTVAL; + SET_ZN(dst); + writeword(SRC1VAL + (SRC2VAL << 1), dst); +} + +void asap_device::sth_c0() +{ + SET_ZN(0); + writeword(SRC1VAL + (SRC2VAL << 1), 0); +} + +/**************************** ST ******************************/ + +void asap_device::st() +{ + writelong(SRC1VAL + (SRC2VAL << 2), DSTVAL); +} + +void asap_device::st_0() +{ + writelong(SRC1VAL + (SRC2VAL << 2), 0); +} + +void asap_device::st_c() +{ + UINT32 dst = DSTVAL; + SET_ZN(dst); + writelong(SRC1VAL + (SRC2VAL << 2), dst); +} + +void asap_device::st_c0() +{ + SET_ZN(0); + writelong(SRC1VAL + (SRC2VAL << 2), 0); +} + +/**************************** LDB ******************************/ + +void asap_device::ldb() +{ + DSTVAL = (INT8)readbyte(SRC1VAL + SRC2VAL); +} + +void asap_device::ldb_0() +{ + readbyte(SRC1VAL + SRC2VAL); +} + +void asap_device::ldb_c() +{ + UINT32 dst = (INT8)readbyte(SRC1VAL + SRC2VAL); + SET_ZN(dst); + DSTVAL = dst; +} + +void asap_device::ldb_c0() +{ + UINT32 dst = (INT8)readbyte(SRC1VAL + SRC2VAL); + SET_ZN(dst); +} + +/**************************** LDUB ******************************/ + +void asap_device::ldub() +{ + DSTVAL = readbyte(SRC1VAL + SRC2VAL); +} + +void asap_device::ldub_0() +{ + readbyte(SRC1VAL + SRC2VAL); +} + +void asap_device::ldub_c() +{ + UINT32 dst = readbyte(SRC1VAL + SRC2VAL); + SET_ZN(dst); + DSTVAL = dst; +} + +void asap_device::ldub_c0() +{ + UINT32 dst = readbyte(SRC1VAL + SRC2VAL); + SET_ZN(dst); +} + +/**************************** STB ******************************/ + +void asap_device::stb() +{ + writebyte(SRC1VAL + SRC2VAL, DSTVAL); +} + +void asap_device::stb_0() +{ + writebyte(SRC1VAL + SRC2VAL, 0); +} + +void asap_device::stb_c() +{ + UINT32 dst = (UINT8)DSTVAL; + SET_ZN(dst); + writebyte(SRC1VAL + SRC2VAL, dst); +} + +void asap_device::stb_c0() +{ + SET_ZN(0); + writebyte(SRC1VAL + SRC2VAL, 0); +} + +/**************************** ASHR ******************************/ + +void asap_device::ashr() +{ + UINT32 src2 = SRC2VAL; + DSTVAL = (src2 < 32) ? ((INT32)SRC1VAL >> src2) : ((INT32)SRC1VAL >> 31); +} + +void asap_device::ashr_c() +{ + UINT32 src2 = SRC2VAL; + m_cflag = 0; + if (src2 < 32) + { + UINT32 src1 = SRC1VAL; + UINT32 dst = (INT32)src1 >> src2; + SET_ZN(dst); + if (src2 != 0) + { + src1 = src1 << (32 - src2); + m_cflag = src1 >> 31; + } + DSTVAL = dst; + } + else + { + UINT32 dst = (INT32)SRC1VAL >> 31; + SET_ZN(dst); + DSTVAL = dst; + } +} + +void asap_device::ashr_c0() +{ + UINT32 src2 = SRC2VAL; + m_cflag = 0; + if (src2 < 32) + { + UINT32 src1 = SRC1VAL; + UINT32 dst = (INT32)src1 >> src2; + SET_ZN(dst); + if (src2 != 0) + { + src1 = src1 << (32 - src2); + m_cflag = src1 >> 31; + } + } + else + { + UINT32 dst = (INT32)SRC1VAL >> 31; + SET_ZN(dst); + } +} + +/**************************** LSHR ******************************/ + +void asap_device::lshr() +{ + UINT32 src2 = SRC2VAL; + DSTVAL = (src2 < 32) ? (SRC1VAL >> src2) : (SRC1VAL >> 31); +} + +void asap_device::lshr_c() +{ + UINT32 src2 = SRC2VAL; + m_cflag = 0; + if (src2 < 32) + { + UINT32 src1 = SRC1VAL; + UINT32 dst = src1 >> src2; + SET_ZN(dst); + if (src2 != 0) + { + src1 = src1 << (32 - src2); + m_cflag = src1 >> 31; + } + DSTVAL = dst; + } + else + { + UINT32 dst = SRC1VAL >> 31; + SET_ZN(dst); + DSTVAL = dst; + } +} + +void asap_device::lshr_c0() +{ + UINT32 src2 = SRC2VAL; + m_cflag = 0; + if (src2 < 32) + { + UINT32 src1 = SRC1VAL; + UINT32 dst = src1 >> src2; + SET_ZN(dst); + if (src2 != 0) + { + src1 = src1 << (32 - src2); + m_cflag = src1 >> 31; + } + } + else + { + SET_ZN(0); + DSTVAL = 0; + } +} + +/**************************** ASHL ******************************/ + +void asap_device::ashl() +{ + UINT32 src2 = SRC2VAL; + DSTVAL = (src2 < 32) ? (SRC1VAL << src2) : 0; +} + +void asap_device::ashl_c() +{ + UINT32 src2 = SRC2VAL; + m_cflag = m_vflag = 0; + if (src2 < 32) + { + UINT32 src1 = SRC1VAL; + UINT32 dst = src1 << src2; + SET_ZN(dst); + if (src2 != 0) + { + src1 = (INT32)src1 >> (32 - src2); + m_cflag = src1 & PS_CFLAG; + m_vflag = (src1 != ((INT32)dst >> 31)) << 31; + } + DSTVAL = dst; + } + else + { + SET_ZN(0); + DSTVAL = 0; + } +} + +void asap_device::ashl_c0() +{ + UINT32 src2 = SRC2VAL; + m_cflag = m_vflag = 0; + if (src2 < 32) + { + UINT32 src1 = SRC1VAL; + UINT32 dst = src1 << src2; + SET_ZN(dst); + if (src2 != 0) + { + src1 = (INT32)src1 >> (32 - src2); + m_cflag = src1 & PS_CFLAG; + m_vflag = (src1 != ((INT32)dst >> 31)) << 31; + } + } + else + SET_ZN(0); +} + +/**************************** ROTL ******************************/ + +void asap_device::rotl() +{ + UINT32 src1 = SRC1VAL; + UINT32 src2 = SRC2VAL & 31; + DSTVAL = (src1 << src2) | (src1 >> (32 - src2)); +} + +void asap_device::rotl_c() +{ + UINT32 src1 = SRC1VAL; + UINT32 src2 = SRC2VAL & 31; + UINT32 dst = (src1 << src2) | (src1 >> (32 - src2)); + SET_ZN(dst); + DSTVAL = dst; +} + +void asap_device::rotl_c0() +{ + UINT32 src1 = SRC1VAL; + UINT32 src2 = SRC2VAL & 31; + UINT32 dst = (src1 << src2) | (src1 >> (32 - src2)); + SET_ZN(dst); +} + +/**************************** GETPS ******************************/ + +void asap_device::getps() +{ + DSTVAL = GET_FLAGS(); +} + +/**************************** PUTPS ******************************/ + +void asap_device::putps() +{ + UINT32 src2 = SRC2VAL & 0x3f; + SET_FLAGS(src2); + check_irqs(); +} + +/**************************** JSR ******************************/ + +void asap_device::jsr() +{ + DSTVAL = m_pc + 4; + m_nextpc = SRC1VAL + (SRC2VAL << 2); + + fetch_instruction(); + m_pc = m_nextpc; + m_nextpc = ~0; + + execute_instruction(); + m_icount--; +} + +void asap_device::jsr_0() +{ + m_nextpc = SRC1VAL + (SRC2VAL << 2); + + fetch_instruction(); + m_pc = m_nextpc; + m_nextpc = ~0; + + execute_instruction(); + m_icount--; +} + +void asap_device::jsr_c() +{ + DSTVAL = m_pc + 4; + m_nextpc = SRC1VAL + (SRC2VAL << 2); + m_iflag = m_pflag; + + fetch_instruction(); + m_pc = m_nextpc; + m_nextpc = ~0; + + execute_instruction(); + m_icount--; + check_irqs(); +} + +void asap_device::jsr_c0() +{ + m_nextpc = SRC1VAL + (SRC2VAL << 2); + m_iflag = m_pflag; + + fetch_instruction(); + m_pc = m_nextpc; + m_nextpc = ~0; + + execute_instruction(); + m_icount--; + check_irqs(); +} + +/**************************** TRAP F ******************************/ + +void asap_device::trapf() +{ + generate_exception(EXCEPTION_TRAPF); +} diff --git a/src/devices/cpu/asap/asap.h b/src/devices/cpu/asap/asap.h new file mode 100644 index 00000000000..6cac9ee4c36 --- /dev/null +++ b/src/devices/cpu/asap/asap.h @@ -0,0 +1,276 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + asap.h + + Core implementation for the portable ASAP emulator. + ASAP = Atari Simplified Architecture Processor + +***************************************************************************/ + +#pragma once + +#ifndef __ASAP_H__ +#define __ASAP_H__ + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + + +// ======================> asap_device + +class asap_device : public cpu_device +{ +public: + // construction/destruction + asap_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // public interfaces + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_execute_interface overrides + virtual UINT32 execute_min_cycles() const; + virtual UINT32 execute_max_cycles() const; + virtual UINT32 execute_input_lines() const; + virtual void execute_run(); + virtual void execute_set_input(int inputnum, int state); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const; + + // device_state_interface overrides + virtual void state_import(const device_state_entry &entry); + virtual void state_export(const device_state_entry &entry); + virtual void state_string_export(const device_state_entry &entry, std::string &str); + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const; + virtual UINT32 disasm_max_opcode_bytes() const; + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + + // helpers + inline UINT32 readop(offs_t pc); + inline UINT8 readbyte(offs_t address); + inline UINT16 readword(offs_t address); + inline UINT32 readlong(offs_t address); + inline void writebyte(offs_t address, UINT8 data); + inline void writeword(offs_t address, UINT16 data); + inline void writelong(offs_t address, UINT32 data); + inline void generate_exception(int exception); + inline void check_irqs(); + inline void fetch_instruction(); + inline void fetch_instruction_debug(); + inline void execute_instruction(); + + // condition handlers + void bsp(); + void bmz(); + void bgt(); + void ble(); + void bge(); + void blt(); + void bhi(); + void bls(); + void bcc(); + void bcs(); + void bpl(); + void bmi(); + void bne(); + void beq(); + void bvc(); + void bvs(); + + // opcode handlers + void noop(); + void trap0(); + void bsr(); + void bsr_0(); + void lea(); + void lea_c(); + void lea_c0(); + void leah(); + void leah_c(); + void leah_c0(); + void subr(); + void subr_c(); + void subr_c0(); + void xor_(); + void xor_c(); + void xor_c0(); + void xorn(); + void xorn_c(); + void xorn_c0(); + void add(); + void add_c(); + void add_c0(); + void sub(); + void sub_c(); + void sub_c0(); + void addc(); + void addc_c(); + void addc_c0(); + void subc(); + void subc_c(); + void subc_c0(); + void and_(); + void and_c(); + void and_c0(); + void andn(); + void andn_c(); + void andn_c0(); + void or_(); + void or_c(); + void or_c0(); + void orn(); + void orn_c(); + void orn_c0(); + void ld(); + void ld_0(); + void ld_c(); + void ld_c0(); + void ldh(); + void ldh_0(); + void ldh_c(); + void ldh_c0(); + void lduh(); + void lduh_0(); + void lduh_c(); + void lduh_c0(); + void sth(); + void sth_0(); + void sth_c(); + void sth_c0(); + void st(); + void st_0(); + void st_c(); + void st_c0(); + void ldb(); + void ldb_0(); + void ldb_c(); + void ldb_c0(); + void ldub(); + void ldub_0(); + void ldub_c(); + void ldub_c0(); + void stb(); + void stb_0(); + void stb_c(); + void stb_c0(); + void ashr(); + void ashr_c(); + void ashr_c0(); + void lshr(); + void lshr_c(); + void lshr_c0(); + void ashl(); + void ashl_c(); + void ashl_c0(); + void rotl(); + void rotl_c(); + void rotl_c0(); + void getps(); + void putps(); + void jsr(); + void jsr_0(); + void jsr_c(); + void jsr_c0(); + void trapf(); + + // internal state + const address_space_config m_program_config; + UINT32 m_pc; + + // expanded flags + UINT32 m_pflag; + UINT32 m_iflag; + UINT32 m_cflag; + UINT32 m_vflag; + UINT32 m_znflag; + UINT32 m_flagsio; + + // internal stuff + UINT32 m_op; + UINT32 m_ppc; + UINT32 m_nextpc; + UINT8 m_irq_state; + int m_icount; + address_space * m_program; + direct_read_data * m_direct; + + // src2val table, registers are at the end + UINT32 m_src2val[65536]; + + // opcode/condition tables + typedef void (asap_device::*ophandler)(); + + ophandler m_opcode[32 * 32 * 2]; + + static const ophandler s_opcodetable[32][4]; + static const ophandler s_conditiontable[16]; +}; + + + +//************************************************************************** +// ENUMERATIONS +//************************************************************************** + +// registers +enum +{ + ASAP_PC = 1, + ASAP_PS, + ASAP_R0, + ASAP_R1, + ASAP_R2, + ASAP_R3, + ASAP_R4, + ASAP_R5, + ASAP_R6, + ASAP_R7, + ASAP_R8, + ASAP_R9, + ASAP_R10, + ASAP_R11, + ASAP_R12, + ASAP_R13, + ASAP_R14, + ASAP_R15, + ASAP_R16, + ASAP_R17, + ASAP_R18, + ASAP_R19, + ASAP_R20, + ASAP_R21, + ASAP_R22, + ASAP_R23, + ASAP_R24, + ASAP_R25, + ASAP_R26, + ASAP_R27, + ASAP_R28, + ASAP_R29, + ASAP_R30, + ASAP_R31 +}; + +// input lines +enum +{ + ASAP_IRQ0 +}; + + + +// device type definition +extern const device_type ASAP; + + +#endif /* __ASAP_H__ */ diff --git a/src/devices/cpu/asap/asapdasm.c b/src/devices/cpu/asap/asapdasm.c new file mode 100644 index 00000000000..eb16985da1b --- /dev/null +++ b/src/devices/cpu/asap/asapdasm.c @@ -0,0 +1,144 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + asapdasm.c + Disassembler for the portable ASAP emulator. + Written by Aaron Giles + +***************************************************************************/ + +#include "emu.h" +#include "asap.h" + + +static const char *const reg[32] = +{ + "0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", + "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", + "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", + "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31" +}; + +static const char *const setcond[2] = +{ + " ", ".c" +}; + +static const char *const condition[16] = +{ + "sp", "mz", "gt", "le", "ge", "lt", "hi", "ls", "cc", "cs", "pl", "mi", "ne", "eq", "vc", "vs" +}; + + +/*************************************************************************** + CODE CODE +***************************************************************************/ + +INLINE char *src2(UINT32 op, int scale) +{ + static char temp[20]; + if ((op & 0xffe0) == 0xffe0) + sprintf(temp, "%s", reg[op & 31]); + else + sprintf(temp, "$%x", (op & 0xffff) << scale); + return temp; +} + +CPU_DISASSEMBLE( asap ) +{ + UINT32 op = oprom[0] | (oprom[1] << 8) | (oprom[2] << 16) | (oprom[3] << 24); + int opcode = op >> 27; + int cond = (op >> 21) & 1; + int rdst = (op >> 22) & 31; + int rsrc1 = (op >> 16) & 31; + int rsrc2 = op & 0xffff; + int rsrc2_iszero = (!rsrc2 || rsrc2 == 0xffe0); + UINT32 flags = 0; + + switch (opcode) + { + case 0x00: sprintf(buffer, "trap $00"); flags = DASMFLAG_STEP_OVER; break; + case 0x01: sprintf(buffer, "b%s $%08x", condition[rdst & 15], pc + ((INT32)(op << 10) >> 8)); break; + case 0x02: if ((op & 0x003fffff) == 3) + { + UINT32 nextop = oprom[4] | (oprom[5] << 8) | (oprom[6] << 16) | (oprom[7] << 24); + if ((nextop >> 27) == 0x10 && ((nextop >> 22) & 31) == rdst && (nextop & 0xffff) == 0) + { + UINT32 nextnextop = oprom[8] | (oprom[9] << 8) | (oprom[10] << 16) | (oprom[11] << 24); + sprintf(buffer, "llit%s $%08x,%s", setcond[cond], nextnextop, reg[rdst]); + return 12 | DASMFLAG_STEP_OVER | DASMFLAG_SUPPORTED; + } + } + if (rdst) + { + flags = DASMFLAG_STEP_OVER | DASMFLAG_STEP_OVER_EXTRA(1); + sprintf(buffer, "bsr %s,$%08x", reg[rdst], pc + ((INT32)(op << 10) >> 8)); + } + else + sprintf(buffer, "bra $%08x", pc + ((INT32)(op << 10) >> 8)); + break; + case 0x03: sprintf(buffer, "lea%s %s[%s],%s", setcond[cond], reg[rsrc1], src2(op,2), reg[rdst]); break; + case 0x04: sprintf(buffer, "leah%s %s[%s],%s", setcond[cond], reg[rsrc1], src2(op,1), reg[rdst]); break; + case 0x05: sprintf(buffer, "subr%s %s,%s,%s", setcond[cond], reg[rsrc1], src2(op,0), reg[rdst]); break; + case 0x06: sprintf(buffer, "xor%s %s,%s,%s", setcond[cond], reg[rsrc1], src2(op,0), reg[rdst]); break; + case 0x07: sprintf(buffer, "xorn%s %s,%s,%s", setcond[cond], reg[rsrc1], src2(op,0), reg[rdst]); break; + case 0x08: if (!rsrc1 && !rdst && rsrc2_iszero) + sprintf(buffer, "nop"); + else if (!rsrc1) + sprintf(buffer, "mov%s %s,%s", setcond[cond], src2(op,0), reg[rdst]); + else if (rsrc2_iszero) + sprintf(buffer, "mov%s %s,%s", setcond[cond], reg[rsrc1], reg[rdst]); + else + sprintf(buffer, "add%s %s,%s,%s", setcond[cond], reg[rsrc1], src2(op,0), reg[rdst]); break; + case 0x09: sprintf(buffer, "sub%s %s,%s,%s", setcond[cond], reg[rsrc1], src2(op,0), reg[rdst]); break; + case 0x0a: sprintf(buffer, "addc%s %s,%s,%s", setcond[cond], reg[rsrc1], src2(op,0), reg[rdst]); break; + case 0x0b: sprintf(buffer, "subc%s %s,%s,%s", setcond[cond], reg[rsrc1], src2(op,0), reg[rdst]); break; + case 0x0c: sprintf(buffer, "and%s %s,%s,%s", setcond[cond], reg[rsrc1], src2(op,0), reg[rdst]); break; + case 0x0d: sprintf(buffer, "andn%s %s,%s,%s", setcond[cond], reg[rsrc1], src2(op,0), reg[rdst]); break; + case 0x0e: if (!rsrc1 && !rdst && rsrc2_iszero) + sprintf(buffer, "nop"); + else if (!rsrc1) + sprintf(buffer, "mov%s %s,%s", setcond[cond], src2(op,0), reg[rdst]); + else if (rsrc2_iszero) + sprintf(buffer, "mov%s %s,%s", setcond[cond], reg[rsrc1], reg[rdst]); + else + sprintf(buffer, "or%s %s,%s,%s", setcond[cond], reg[rsrc1], src2(op,0), reg[rdst]); break; + case 0x0f: sprintf(buffer, "orn%s %s,%s,%s", setcond[cond], reg[rsrc1], src2(op,0), reg[rdst]); break; + case 0x10: sprintf(buffer, "ld%s %s[%s],%s", setcond[cond], reg[rsrc1], src2(op,2), reg[rdst]); break; + case 0x11: sprintf(buffer, "ldh%s %s[%s],%s", setcond[cond], reg[rsrc1], src2(op,1), reg[rdst]); break; + case 0x12: sprintf(buffer, "lduh%s %s[%s],%s", setcond[cond], reg[rsrc1], src2(op,1), reg[rdst]); break; + case 0x13: sprintf(buffer, "sth%s %s[%s],%s", setcond[cond], reg[rsrc1], src2(op,1), reg[rdst]); break; + case 0x14: sprintf(buffer, "st%s %s[%s],%s", setcond[cond], reg[rsrc1], src2(op,2), reg[rdst]); break; + case 0x15: sprintf(buffer, "ldb%s %s[%s],%s", setcond[cond], reg[rsrc1], src2(op,0), reg[rdst]); break; + case 0x16: sprintf(buffer, "ldub%s %s[%s],%s", setcond[cond], reg[rsrc1], src2(op,0), reg[rdst]); break; + case 0x17: sprintf(buffer, "stb%s %s[%s],%s", setcond[cond], reg[rsrc1], src2(op,0), reg[rdst]); break; + case 0x18: sprintf(buffer, "ashr%s %s,%s,%s", setcond[cond], reg[rsrc1], src2(op,0), reg[rdst]); break; + case 0x19: sprintf(buffer, "lshr%s %s,%s,%s", setcond[cond], reg[rsrc1], src2(op,0), reg[rdst]); break; + case 0x1a: sprintf(buffer, "ashl%s %s,%s,%s", setcond[cond], reg[rsrc1], src2(op,0), reg[rdst]); break; + case 0x1b: sprintf(buffer, "rotl%s %s,%s,%s", setcond[cond], reg[rsrc1], src2(op,0), reg[rdst]); break; + case 0x1c: sprintf(buffer, "getps %s", reg[rdst]); break; + case 0x1d: sprintf(buffer, "putps %s", src2(op,0)); break; + case 0x1e: if (rdst && rsrc2_iszero) + { + flags = DASMFLAG_STEP_OVER | DASMFLAG_STEP_OVER_EXTRA(1); + sprintf(buffer, "jsr%s %s,%s", setcond[cond], reg[rdst], reg[rsrc1]); + } + else if (rdst) + { + flags = DASMFLAG_STEP_OVER | DASMFLAG_STEP_OVER_EXTRA(1); + sprintf(buffer, "jsr%s %s,%s[%s]", setcond[cond], reg[rdst], reg[rsrc1], src2(op,2)); + } + else if (rsrc2_iszero) + { + if (rsrc1 == 28) + flags = DASMFLAG_STEP_OUT; + sprintf(buffer, "jmp%s %s", setcond[cond], reg[rsrc1]); + } + else + sprintf(buffer, "jmp%s %s[%s]", setcond[cond], reg[rsrc1], src2(op,2)); + break; + case 0x1f: sprintf(buffer, "trap $1f"); flags = DASMFLAG_STEP_OVER; break; + } + return 4 | flags | DASMFLAG_SUPPORTED; +} diff --git a/src/devices/cpu/avr8/avr8.c b/src/devices/cpu/avr8/avr8.c new file mode 100644 index 00000000000..0f15c655cb4 --- /dev/null +++ b/src/devices/cpu/avr8/avr8.c @@ -0,0 +1,3930 @@ +// license:BSD-3-Clause +// copyright-holders:Ryan Holtz, Sandro Ronco, Felipe Sanches +/*************************************************************************** + + Atmel 8-bit AVR simulator + + - Notes - + Cycle counts are generally considered to be 100% accurate per-instruction, does not support mid-instruction + interrupts although no software has been countered yet that requires it. Evidence of cycle accuracy is given + in the form of the demoscene 'wild' demo, Craft, by [lft], which uses an ATmega88 to write video out a 6-bit + RGB DAC pixel-by-pixel, synchronously with the frame timing. Intentionally modifying the timing of any of + the existing opcodes has been shown to wildly corrupt the video output in Craft, so one can assume that the + existing timing is 100% correct. + + Unimplemented opcodes: SPM, SPM Z+, SLEEP, BREAK, WDR, EICALL, JMP, CALL + + - Changelist - + 05 Jul. 2015 [Felipe Sanches] + - Implemented EIJMP instruction + + 29 Dec. 2013 [Felipe Sanches] + - Added crude boilerplate code for Timer/Counter #4 + + 25 Dec. 2013 [Felipe Sanches] + - Updated AVR8_REGIDX_* enum based on ATMEGA640/1280/2560 datasheet + + 24 Dec. 2013 [Felipe Sanches] + - update data memory mapping so that all 0x200 register addresses are accessible + + 23 Dec. 2013 [Felipe Sanches] + - Added ELPM instructions + - Added fuse bits macros + - Added reset logic to decide initial program counter based on fuse bits configuration + - Added initial support for ATMEGA1280 and ATMEGA2560 + - Use register names in the disassembly of IN and OUT instructions + + 23 Dec. 2012 [Sandro Ronco] + - Added CPSE, LD Z+, ST -Z/-Y/-X and ICALL opcodes + - Fixed Z flag in CPC, SBC and SBCI opcodes + - Fixed V and C flags in SBIW opcode + + 30 Oct. 2012 + - Added FMUL, FMULS, FMULSU opcodes [MooglyGuy] + - Fixed incorrect flag calculation in ROR opcode [MooglyGuy] + - Fixed incorrect bit testing in SBIC/SBIS opcodes [MooglyGuy] + + 25 Oct. 2012 + - Added MULS, ANDI, STI Z+, LD -Z, LD -Y, LD -X, LD Y+q, LD Z+q, SWAP, ASR, ROR and SBIS opcodes [MooglyGuy] + - Corrected cycle counts for LD and ST opcodes [MooglyGuy] + - Moved opcycles init into inner while loop, fixes 2-cycle and 3-cycle opcodes effectively forcing + all subsequent 1-cycle opcodes to be 2 or 3 cycles [MooglyGuy] + - Fixed register behavior in MULSU, LD -Z, and LD -Y opcodes [MooglyGuy] + + 18 Oct. 2012 + - Added OR, SBCI, ORI, ST Y+, ADIQ opcodes [MooglyGuy] + - Fixed COM, NEG, LSR opcodes [MooglyGuy] + +*/ + +#include "emu.h" +#include "debugger.h" +#include "avr8.h" + +#define VERBOSE_LEVEL (0) + +#define ENABLE_VERBOSE_LOG (0) + +#if ENABLE_VERBOSE_LOG +INLINE void ATTR_PRINTF(3,4) verboselog(UINT16 pc, int n_level, const char *s_fmt, ...) +{ + if( VERBOSE_LEVEL >= n_level ) + { + va_list v; + char buf[ 32768 ]; + va_start( v, s_fmt ); + vsprintf( buf, s_fmt, v ); + va_end( v ); + logerror( "%05x: %s", pc << 1, buf ); + } +} +#else +#define verboselog(x,y,z, ...) +#endif + +//************************************************************************** +// ENUMS AND MACROS +//************************************************************************** + +enum +{ + AVR8_SREG_C = 0, + AVR8_SREG_Z, + AVR8_SREG_N, + AVR8_SREG_V, + AVR8_SREG_S, + AVR8_SREG_H, + AVR8_SREG_T, + AVR8_SREG_I +}; + +// I/O Enums +enum +{ + WGM1_NORMAL = 0, + WGM1_PWM_8_PC, + WGM1_PWM_9_PC, + WGM1_PWM_10_PC, + WGM1_CTC_OCR, + WGM1_FAST_PWM_8, + WGM1_FAST_PWM_9, + WGM1_FAST_PWM_10, + WGM1_PWM_PFC_ICR, + WGM1_PWM_PFC_OCR, + WGM1_PWM_PC_ICR, + WGM1_PWM_PC_OCR, + WGM1_CTC_ICR, + WGM1_RESERVED, + WGM1_FAST_PWM_ICR, + WGM1_FAST_PWM_OCR +}; + +enum +{ + WGM02_NORMAL = 0, + WGM02_PWM_PC, + WGM02_CTC_CMP, + WGM02_FAST_PWM, + WGM02_RESERVED0, + WGM02_PWM_PC_CMP, + WGM02_RESERVED1, + WGM02_FAST_PWM_CMP +}; + +enum +{ + WGM4_NORMAL = 0, + WGM4_PWM_8_PC, + WGM4_PWM_9_PC, + WGM4_PWM_10_PC, + WGM4_CTC_OCR, + WGM4_FAST_PWM_8, + WGM4_FAST_PWM_9, + WGM4_FAST_PWM_10, + WGM4_PWM_PFC_ICR, + WGM4_PWM_PFC_OCR, + WGM4_PWM_PC_ICR, + WGM4_PWM_PC_OCR, + WGM4_CTC_ICR, + WGM4_RESERVED, + WGM4_FAST_PWM_ICR, + WGM4_FAST_PWM_OCR +}; + +enum +{ + WGM5_NORMAL = 0, + WGM5_PWM_8_PC, + WGM5_PWM_9_PC, + WGM5_PWM_10_PC, + WGM5_CTC_OCR, + WGM5_FAST_PWM_8, + WGM5_FAST_PWM_9, + WGM5_FAST_PWM_10, + WGM5_PWM_PFC_ICR, + WGM5_PWM_PFC_OCR, + WGM5_PWM_PC_ICR, + WGM5_PWM_PC_OCR, + WGM5_CTC_ICR, + WGM5_RESERVED, + WGM5_FAST_PWM_ICR, + WGM5_FAST_PWM_OCR +}; + +//static const char avr8_reg_name[4] = { 'A', 'B', 'C', 'D' }; + +#define SREG_R(b) ((m_r[AVR8_REGIDX_SREG] & (1 << (b))) >> (b)) +#define SREG_W(b,v) m_r[AVR8_REGIDX_SREG] = (m_r[AVR8_REGIDX_SREG] & ~(1 << (b))) | ((v) << (b)) +#define NOT(x) (1 - (x)) + +// Opcode-Parsing Defines +#define RD2(op) (((op) >> 4) & 0x0003) +#define RD3(op) (((op) >> 4) & 0x0007) +#define RD4(op) (((op) >> 4) & 0x000f) +#define RD5(op) (((op) >> 4) & 0x001f) +#define RR3(op) ((op) & 0x0007) +#define RR4(op) ((op) & 0x000f) +#define RR5(op) ((((op) >> 5) & 0x0010) | ((op) & 0x000f)) +#define DCONST(op) (((op) >> 4) & 0x0003) +#define KCONST6(op) ((((op) >> 2) & 0x0030) | ((op) & 0x000f)) +#define KCONST7(op) (((op) >> 3) & 0x007f) +#define KCONST8(op) ((((op) >> 4) & 0x00f0) | ((op) & 0x000f)) +#define KCONST22(op) (((((UINT32)(op) >> 3) & 0x003e) | ((UINT32)(op) & 0x0001)) << 16) +#define QCONST6(op) ((((op) >> 8) & 0x0020) | (((op) >> 7) & 0x0018) | ((op) & 0x0007)) +#define ACONST5(op) (((op) >> 3) & 0x001f) +#define ACONST6(op) ((((op) >> 5) & 0x0030) | ((op) & 0x000f)) +#define MULCONST2(op) ((((op) >> 6) & 0x0002) | (((op) >> 3) & 0x0001)) + +// Register Defines +#define XREG ((m_r[27] << 8) | m_r[26]) +#define YREG ((m_r[29] << 8) | m_r[28]) +#define ZREG ((m_r[31] << 8) | m_r[30]) +#define SPREG ((m_r[AVR8_REGIDX_SPH] << 8) | m_r[AVR8_REGIDX_SPL]) + +// I/O Defines +#define AVR8_OCR1CH (m_r[AVR8_REGIDX_OCR1CH]) +#define AVR8_OCR1CL (m_r[AVR8_REGIDX_OCR1CL]) +#define AVR8_OCR1BH (m_r[AVR8_REGIDX_OCR1BH]) +#define AVR8_OCR1BL (m_r[AVR8_REGIDX_OCR1BL]) +#define AVR8_OCR1AH (m_r[AVR8_REGIDX_OCR1AH]) +#define AVR8_OCR1AL (m_r[AVR8_REGIDX_OCR1AL]) +#define AVR8_ICR1H (m_r[AVR8_REGIDX_ICR1H]) +#define AVR8_ICR1L (m_r[AVR8_REGIDX_ICR1L]) +#define AVR8_TCNT1H (m_r[AVR8_REGIDX_TCNT1H]) +#define AVR8_TCNT1L (m_r[AVR8_REGIDX_TCNT1L]) + +#define AVR8_OCR3CH (m_r[AVR8_REGIDX_OCR3CH]) +#define AVR8_OCR3CL (m_r[AVR8_REGIDX_OCR3CL]) +#define AVR8_OCR3BH (m_r[AVR8_REGIDX_OCR3BH]) +#define AVR8_OCR3BL (m_r[AVR8_REGIDX_OCR3BL]) +#define AVR8_OCR3AH (m_r[AVR8_REGIDX_OCR3AH]) +#define AVR8_OCR3AL (m_r[AVR8_REGIDX_OCR3AL]) +#define AVR8_ICR3H (m_r[AVR8_REGIDX_ICR3H]) +#define AVR8_ICR3L (m_r[AVR8_REGIDX_ICR3L]) +#define AVR8_TCNT3H (m_r[AVR8_REGIDX_TCNT3H]) +#define AVR8_TCNT3L (m_r[AVR8_REGIDX_TCNT3L]) + +#define AVR8_OCR4CH (m_r[AVR8_REGIDX_OCR4CH]) +#define AVR8_OCR4CL (m_r[AVR8_REGIDX_OCR4CL]) +#define AVR8_OCR4BH (m_r[AVR8_REGIDX_OCR4BH]) +#define AVR8_OCR4BL (m_r[AVR8_REGIDX_OCR4BL]) +#define AVR8_OCR4AH (m_r[AVR8_REGIDX_OCR4AH]) +#define AVR8_OCR4AL (m_r[AVR8_REGIDX_OCR4AL]) +#define AVR8_ICR4H (m_r[AVR8_REGIDX_ICR4H]) +#define AVR8_ICR4L (m_r[AVR8_REGIDX_ICR4L]) +#define AVR8_TCNT4H (m_r[AVR8_REGIDX_TCNT4H]) +#define AVR8_TCNT4L (m_r[AVR8_REGIDX_TCNT4L]) + +#define AVR8_OCR5CH (m_r[AVR8_REGIDX_OCR5CH]) +#define AVR8_OCR5CL (m_r[AVR8_REGIDX_OCR5CL]) +#define AVR8_OCR5BH (m_r[AVR8_REGIDX_OCR5BH]) +#define AVR8_OCR5BL (m_r[AVR8_REGIDX_OCR5BL]) +#define AVR8_OCR5AH (m_r[AVR8_REGIDX_OCR5AH]) +#define AVR8_OCR5AL (m_r[AVR8_REGIDX_OCR5AL]) +#define AVR8_ICR5H (m_r[AVR8_REGIDX_ICR5H]) +#define AVR8_ICR5L (m_r[AVR8_REGIDX_ICR5L]) +#define AVR8_TCNT5H (m_r[AVR8_REGIDX_TCNT5H]) +#define AVR8_TCNT5L (m_r[AVR8_REGIDX_TCNT5L]) + +#define AVR8_TCCR0B (m_r[AVR8_REGIDX_TCCR0B]) +#define AVR8_TCCR0B_FOC0A_MASK 0x80 +#define AVR8_TCCR0B_FOC0A_SHIFT 7 +#define AVR8_TCCR0B_FOC0B_MASK 0x40 +#define AVR8_TCCR0B_FOC0B_SHIFT 6 +#define AVR8_TCCR0B_WGM0_2_MASK 0x08 +#define AVR8_TCCR0B_WGM0_2_SHIFT 3 +#define AVR8_TCCR0B_CS_MASK 0x07 +#define AVR8_TCCR0B_CS_SHIFT 0 +#define AVR8_TIMER0_CLOCK_SELECT (AVR8_TCCR0B & AVR8_TCCR0B_CS_MASK) + +#define AVR8_TCCR0A (m_r[AVR8_REGIDX_TCCR0A]) +#define AVR8_TCCR0A_COM0A_MASK 0xc0 +#define AVR8_TCCR0A_COM0A_SHIFT 6 +#define AVR8_TCCR0A_COM0B_MASK 0x30 +#define AVR8_TCCR0A_COM0B_SHIFT 4 +#define AVR8_TCCR0A_WGM0_10_MASK 0x03 +#define AVR8_TCCR0A_WGM0_10_SHIFT 0 +#define AVR8_TCCR0A_COM0A ((AVR8_TCCR0A & AVR8_TCCR0A_COM0A_MASK) >> AVR8_TCCR0A_COM0A_SHIFT) +#define AVR8_TCCR0A_COM0B ((AVR8_TCCR0A & AVR8_TCCR0A_COM0B_MASK) >> AVR8_TCCR0A_COM0B_SHIFT) +#define AVR8_TCCR0A_WGM0_10 (AVR8_TCCR0A & AVR8_TCCR0A_WGM0_10_MASK) + +#define AVR8_TIMSK0 (m_r[AVR8_REGIDX_TIMSK0]) +#define AVR8_TIMSK0_OCIE0B_MASK 0x04 +#define AVR8_TIMSK0_OCIE0A_MASK 0x02 +#define AVR8_TIMSK0_TOIE0_MASK 0x01 +#define AVR8_TIMSK0_OCIE0B ((AVR8_TIMSK0 & AVR8_TIMSK0_OCIE0B_MASK) >> 2) +#define AVR8_TIMSK0_OCIE0A ((AVR8_TIMSK0 & AVR8_TIMSK0_OCIE0A_MASK) >> 1) +#define AVR8_TIMSK0_TOIE0 (AVR8_TIMSK0 & AVR8_TIMSK0_TOIE0_MASK) + +#define AVR8_TIFR0 (m_r[AVR8_REGIDX_TIFR0]) +#define AVR8_TIFR0_OCF0B_MASK 0x04 +#define AVR8_TIFR0_OCF0B_SHIFT 2 +#define AVR8_TIFR0_OCF0A_MASK 0x02 +#define AVR8_TIFR0_OCF0A_SHIFT 1 +#define AVR8_TIFR0_TOV0_MASK 0x01 +#define AVR8_TIFR0_TOV0_SHIFT 0 +#define AVR8_TIFR0_MASK (AVR8_TIFR0_TOV0_MASK | AVR8_TIFR0_OCF0B_MASK | AVR8_TIFR0_OCF0A_MASK) + +#define AVR8_TCCR1B (m_r[AVR8_REGIDX_TCCR1B]) +#define AVR8_TCCR1B_ICNC1_MASK 0x80 +#define AVR8_TCCR1B_ICNC1_SHIFT 7 +#define AVR8_TCCR1B_ICES1_MASK 0x40 +#define AVR8_TCCR1B_ICES1_SHIFT 6 +#define AVR8_TCCR1B_WGM1_32_MASK 0x18 +#define AVR8_TCCR1B_WGM1_32_SHIFT 3 +#define AVR8_TCCR1B_CS_MASK 0x07 +#define AVR8_TCCR1B_CS_SHIFT 0 +#define AVR8_TIMER1_CLOCK_SELECT (AVR8_TCCR1B & AVR8_TCCR1B_CS_MASK) + +#define AVR8_TCCR1A (m_r[AVR8_REGIDX_TCCR1A]) +#define AVR8_TCCR1A_COM1A_MASK 0xc0 +#define AVR8_TCCR1A_COM1A_SHIFT 6 +#define AVR8_TCCR1A_COM1B_MASK 0x30 +#define AVR8_TCCR1A_COM1B_SHIFT 4 +#define AVR8_TCCR1A_WGM1_10_MASK 0x03 +#define AVR8_TCCR1A_WGM1_10_SHIFT 0 +#define AVR8_TCCR1A_COM1A ((AVR8_TCCR1A & AVR8_TCCR1A_COM1A_MASK) >> AVR8_TCCR1A_COM1A_SHIFT) +#define AVR8_TCCR1A_COM1B ((AVR8_TCCR1A & AVR8_TCCR1A_COM1B_MASK) >> AVR8_TCCR1A_COM1B_SHIFT) +#define AVR8_TCCR1A_WGM1_10 (AVR8_TCCR1A & AVR8_TCCR1A_WGM1_10_MASK) + +#define AVR8_TIMSK1 (m_r[AVR8_REGIDX_TIMSK1]) +#define AVR8_TIMSK1_ICIE1_MASK 0x20 +#define AVR8_TIMSK1_OCIE1B_MASK 0x04 +#define AVR8_TIMSK1_OCIE1A_MASK 0x02 +#define AVR8_TIMSK1_TOIE1_MASK 0x01 +#define AVR8_TIMSK1_ICIE1 ((AVR8_TIMSK1 & AVR8_TIMSK1_ICIE1_MASK) >> 5) +#define AVR8_TIMSK1_OCIE1B ((AVR8_TIMSK1 & AVR8_TIMSK1_OCIE1B_MASK) >> 2) +#define AVR8_TIMSK1_OCIE1A ((AVR8_TIMSK1 & AVR8_TIMSK1_OCIE1A_MASK) >> 1) +#define AVR8_TIMSK1_TOIE1 (AVR8_TIMSK1 & AVR8_TIMSK1_TOIE1_MASK) + +#define AVR8_TIFR1 (m_r[AVR8_REGIDX_TIFR1]) +#define AVR8_TIFR1_ICF1_MASK 0x20 +#define AVR8_TIFR1_ICF1_SHIFT 5 +#define AVR8_TIFR1_OCF1B_MASK 0x04 +#define AVR8_TIFR1_OCF1B_SHIFT 2 +#define AVR8_TIFR1_OCF1A_MASK 0x02 +#define AVR8_TIFR1_OCF1A_SHIFT 1 +#define AVR8_TIFR1_TOV1_MASK 0x01 +#define AVR8_TIFR1_TOV1_SHIFT 0 +#define AVR8_TIFR1_MASK (AVR8_TIFR1_ICF1_MASK | AVR8_TIFR1_TOV1_MASK | \ + AVR8_TIFR1_OCF1B_MASK | AVR8_TIFR1_OCF1A_MASK) + +#define AVR8_TCCR2B (m_r[AVR8_REGIDX_TCCR2B]) +#define AVR8_TCCR2B_FOC2A_MASK 0x80 +#define AVR8_TCCR2B_FOC2A_SHIFT 7 +#define AVR8_TCCR2B_FOC2B_MASK 0x40 +#define AVR8_TCCR2B_FOC2B_SHIFT 6 +#define AVR8_TCCR2B_WGM2_2_MASK 0x08 +#define AVR8_TCCR2B_WGM2_2_SHIFT 3 +#define AVR8_TCCR2B_CS_MASK 0x07 +#define AVR8_TCCR2B_CS_SHIFT 0 +#define AVR8_TIMER2_CLOCK_SELECT (AVR8_TCCR2B & AVR8_TCCR2B_CS_MASK) + +#define AVR8_TCCR2A (m_r[AVR8_REGIDX_TCCR2A]) +#define AVR8_TCCR2A_COM2A_MASK 0xc0 +#define AVR8_TCCR2A_COM2A_SHIFT 6 +#define AVR8_TCCR2A_COM2B_MASK 0x30 +#define AVR8_TCCR2A_COM2B_SHIFT 4 +#define AVR8_TCCR2A_WGM2_10_MASK 0x03 +#define AVR8_TCCR2A_WGM2_10_SHIFT 0 +#define AVR8_TCCR2A_COM2A ((AVR8_TCCR2A & AVR8_TCCR2A_COM2A_MASK) >> AVR8_TCCR2A_COM2A_SHIFT) +#define AVR8_TCCR2A_COM2B ((AVR8_TCCR2A & AVR8_TCCR2A_COM2B_MASK) >> AVR8_TCCR2A_COM2B_SHIFT) +#define AVR8_TCCR2A_WGM2_10 (AVR8_TCCR2A & AVR8_TCCR2A_WGM2_10_MASK) + +#define AVR8_TIMSK2 (m_r[AVR8_REGIDX_TIMSK2]) +#define AVR8_TIMSK2_OCIE2B_MASK 0x04 +#define AVR8_TIMSK2_OCIE2A_MASK 0x02 +#define AVR8_TIMSK2_TOIE2_MASK 0x01 +#define AVR8_TIMSK2_OCIE2B ((AVR8_TIMSK2 & AVR8_TIMSK2_OCIE2B_MASK) >> 2) +#define AVR8_TIMSK2_OCIE2A ((AVR8_TIMSK2 & AVR8_TIMSK2_OCIE2A_MASK) >> 1) +#define AVR8_TIMSK2_TOIE2 (AVR8_TIMSK2 & AVR8_TIMSK2_TOIE2_MASK) + +#define AVR8_TIFR2 (m_r[AVR8_REGIDX_TIFR2]) +#define AVR8_TIFR2_OCF2B_MASK 0x04 +#define AVR8_TIFR2_OCF2B_SHIFT 2 +#define AVR8_TIFR2_OCF2A_MASK 0x02 +#define AVR8_TIFR2_OCF2A_SHIFT 1 +#define AVR8_TIFR2_TOV2_MASK 0x01 +#define AVR8_TIFR2_TOV2_SHIFT 0 +#define AVR8_TIFR2_MASK (AVR8_TIFR2_TOV2_MASK | AVR8_TIFR2_OCF2B_MASK | AVR8_TIFR2_OCF2A_MASK) + +#define AVR8_TIMSK3 (m_r[AVR8_REGIDX_TIMSK3]) +#define AVR8_TIMSK3_OCIE3C_MASK 0x08 +#define AVR8_TIMSK3_OCIE3B_MASK 0x04 +#define AVR8_TIMSK3_OCIE3A_MASK 0x02 +#define AVR8_TIMSK3_TOIE3_MASK 0x01 +#define AVR8_TIMSK3_OCIE3C ((AVR8_TIMSK3 & AVR8_TIMSK3_OCIE3C_MASK) >> 3) +#define AVR8_TIMSK3_OCIE3B ((AVR8_TIMSK3 & AVR8_TIMSK3_OCIE3B_MASK) >> 2) +#define AVR8_TIMSK3_OCIE3A ((AVR8_TIMSK3 & AVR8_TIMSK3_OCIE3A_MASK) >> 1) +#define AVR8_TIMSK3_TOIE3 ((AVR8_TIMSK3 & AVR8_TIMSK3_TOIE3_MASK) >> 0) + +#define AVR8_TCCR4C (m_r[AVR8_REGIDX_TCCR4C]) + +#define AVR8_TCCR4B (m_r[AVR8_REGIDX_TCCR4B]) +#define AVR8_TCCR4B_FOC4A_MASK 0x80 +#define AVR8_TCCR4B_FOC4A_SHIFT 7 +#define AVR8_TCCR4B_FOC4B_MASK 0x40 +#define AVR8_TCCR4B_FOC4B_SHIFT 6 +#define AVR8_TCCR4B_FOC4C_MASK 0x20 +#define AVR8_TCCR4B_FOC4C_SHIFT 5 +#define AVR8_TCCR4B_WGM4_32_MASK 0x18 +#define AVR8_TCCR4B_WGM4_32_SHIFT 3 +#define AVR8_TCCR4B_CS_MASK 0x07 +#define AVR8_TCCR4B_CS_SHIFT 0 +#define AVR8_TIMER4_CLOCK_SELECT ((AVR8_TCCR4B & AVR8_TCCR4B_CS_MASK) >> AVR8_TCCR4B_CS_SHIFT) + +#define AVR8_TCCR4A (m_r[AVR8_REGIDX_TCCR4A]) +#define AVR8_TCCR4A_COM4A_MASK 0xc0 +#define AVR8_TCCR4A_COM4A_SHIFT 6 +#define AVR8_TCCR4A_COM4B_MASK 0x30 +#define AVR8_TCCR4A_COM4B_SHIFT 4 +#define AVR8_TCCR4A_COM4C_MASK 0x0c +#define AVR8_TCCR4A_COM4C_SHIFT 2 +#define AVR8_TCCR4A_WGM4_10_MASK 0x03 +#define AVR8_TCCR4A_WGM4_10_SHIFT 0 +#define AVR8_TCCR4A_COM4A ((AVR8_TCCR4A & AVR8_TCCR4A_COM4A_MASK) >> AVR8_TCCR4A_COM4A_SHIFT) +#define AVR8_TCCR4A_COM4B ((AVR8_TCCR4A & AVR8_TCCR4A_COM4B_MASK) >> AVR8_TCCR4A_COM4B_SHIFT) +#define AVR8_TCCR4A_COM4C ((AVR8_TCCR4A & AVR8_TCCR4A_COM4C_MASK) >> AVR8_TCCR4A_COM4C_SHIFT) +#define AVR8_TCCR4A_WGM2_10 (AVR8_TCCR4A & AVR8_TCCR4A_WGM2_10_MASK) + +#define AVR8_WGM4_32 ((AVR8_TCCR4B & AVR8_TCCR4B_WGM4_32_MASK) >> AVR8_TCCR4B_WGM4_32_SHIFT) +#define AVR8_WGM4_10 ((AVR8_TCCR4A & AVR8_TCCR4A_WGM4_10_MASK) >> AVR8_TCCR4A_WGM4_10_SHIFT) +#define AVR8_WGM4 ((AVR8_WGM4_32 << 2) | AVR8_WGM4_10) + +#define AVR8_TIMSK4 (m_r[AVR8_REGIDX_TIMSK4]) +#define AVR8_TIMSK4_OCIE4B_MASK 0x04 +#define AVR8_TIMSK4_OCIE4A_MASK 0x02 +#define AVR8_TIMSK4_TOIE4_MASK 0x01 +#define AVR8_TIMSK4_OCIE4B ((AVR8_TIMSK4 & AVR8_TIMSK4_OCIE4B_MASK) >> 2) +#define AVR8_TIMSK4_OCIE4A ((AVR8_TIMSK4 & AVR8_TIMSK4_OCIE4A_MASK) >> 1) +#define AVR8_TIMSK4_TOIE4 (AVR8_TIMSK4 & AVR8_TIMSK4_TOIE4_MASK) + +#define AVR8_TIFR4 (m_r[AVR8_REGIDX_TIFR4]) +#define AVR8_TIFR4_OCF4B_MASK 0x04 +#define AVR8_TIFR4_OCF4B_SHIFT 2 +#define AVR8_TIFR4_OCF4A_MASK 0x02 +#define AVR8_TIFR4_OCF4A_SHIFT 1 +#define AVR8_TIFR4_TOV4_MASK 0x01 +#define AVR8_TIFR4_TOV4_SHIFT 0 +#define AVR8_TIFR4_MASK (AVR8_TIFR4_TOV4_MASK | AVR8_TIFR4_OCF4B_MASK | AVR8_TIFR4_OCF4A_MASK) + +//--------------------------------------------------------------- +#define AVR8_TCCR5C (m_r[AVR8_REGIDX_TCCR5C]) +#define AVR8_TCCR5C_FOC5A_MASK 0x80 +#define AVR8_TCCR5C_FOC5A_SHIFT 7 +#define AVR8_TCCR5C_FOC5B_MASK 0x40 +#define AVR8_TCCR5C_FOC5B_SHIFT 6 +#define AVR8_TCCR5C_FOC5C_MASK 0x20 +#define AVR8_TCCR5C_FOC5C_SHIFT 5 + +#define AVR8_TCCR5B (m_r[AVR8_REGIDX_TCCR5B]) +#define AVR8_TCCR5B_ICNC5_MASK 0x80 +#define AVR8_TCCR5B_ICNC5_SHIFT 7 +#define AVR8_TCCR5B_ICES5_MASK 0x40 +#define AVR8_TCCR5B_ICES5_SHIFT 6 +#define AVR8_TCCR5B_WGM5_32_MASK 0x18 +#define AVR8_TCCR5B_WGM5_32_SHIFT 3 +#define AVR8_TCCR5B_CS_MASK 0x07 +#define AVR8_TCCR5B_CS_SHIFT 0 +#define AVR8_TIMER5_CLOCK_SELECT ((AVR8_TCCR5B & AVR8_TCCR5B_CS_MASK) >> AVR8_TCCR5B_CS_SHIFT) + +#define AVR8_TCCR5A (m_r[AVR8_REGIDX_TCCR4A]) +#define AVR8_TCCR5A_COM5A_MASK 0xc0 +#define AVR8_TCCR5A_COM5A_SHIFT 6 +#define AVR8_TCCR5A_COM5B_MASK 0x30 +#define AVR8_TCCR5A_COM5B_SHIFT 4 +#define AVR8_TCCR5A_COM5C_MASK 0x0c +#define AVR8_TCCR5A_COM5C_SHIFT 2 +#define AVR8_TCCR5A_WGM5_10_MASK 0x03 +#define AVR8_TCCR5A_WGM5_10_SHIFT 0 +#define AVR8_TCCR5A_COM5A ((AVR8_TCCR5A & AVR8_TCCR5A_COM5A_MASK) >> AVR8_TCCR5A_COM5A_SHIFT) +#define AVR8_TCCR5A_COM5B ((AVR8_TCCR5A & AVR8_TCCR5A_COM5B_MASK) >> AVR8_TCCR5A_COM5B_SHIFT) +#define AVR8_TCCR5A_COM5C ((AVR8_TCCR5A & AVR8_TCCR5A_COM5C_MASK) >> AVR8_TCCR5A_COM5C_SHIFT) +#define AVR8_TCCR5A_WGM5_10 (AVR8_TCCR5A & AVR8_TCCR5A_WGM5_10_MASK) + +#define AVR8_WGM5_32 ((AVR8_TCCR5B & AVR8_TCCR5B_WGM5_32_MASK) >> AVR8_TCCR5B_WGM5_32_SHIFT) +#define AVR8_WGM5_10 ((AVR8_TCCR5A & AVR8_TCCR5A_WGM5_10_MASK) >> AVR8_TCCR5A_WGM5_10_SHIFT) +#define AVR8_WGM5 ((AVR8_WGM5_32 << 2) | AVR8_WGM5_10) + +#define AVR8_TIMSK5 (m_r[AVR8_REGIDX_TIMSK5]) +#define AVR8_TIMSK5_ICIE5_MASK 0x20 +#define AVR8_TIMSK5_OCIE5C_MASK 0x08 +#define AVR8_TIMSK5_OCIE5B_MASK 0x04 +#define AVR8_TIMSK5_OCIE5A_MASK 0x02 +#define AVR8_TIMSK5_TOIE5_MASK 0x01 + +#define AVR8_TIMSK5_ICIE5C ((AVR8_TIMSK5 & AVR8_TIMSK5_ICIE5C_MASK) >> 5) +#define AVR8_TIMSK5_OCIE5C ((AVR8_TIMSK5 & AVR8_TIMSK5_OCIE5C_MASK) >> 3) +#define AVR8_TIMSK5_OCIE5B ((AVR8_TIMSK5 & AVR8_TIMSK5_OCIE5B_MASK) >> 2) +#define AVR8_TIMSK5_OCIE5A ((AVR8_TIMSK5 & AVR8_TIMSK5_OCIE5A_MASK) >> 1) +#define AVR8_TIMSK5_TOIE5 (AVR8_TIMSK5 & AVR8_TIMSK5_TOIE5_MASK) + +#define AVR8_TIFR5 (m_r[AVR8_REGIDX_TIFR5]) +#define AVR8_TIFR5_ICF5_MASK 0x20 +#define AVR8_TIFR5_ICF5_SHIFT 5 +#define AVR8_TIFR5_OCF5C_MASK 0x08 +#define AVR8_TIFR5_OCF5C_SHIFT 3 +#define AVR8_TIFR5_OCF5B_MASK 0x04 +#define AVR8_TIFR5_OCF5B_SHIFT 2 +#define AVR8_TIFR5_OCF5A_MASK 0x02 +#define AVR8_TIFR5_OCF5A_SHIFT 1 +#define AVR8_TIFR5_TOV5_MASK 0x01 +#define AVR8_TIFR5_TOV5_SHIFT 0 +#define AVR8_TIFR5_MASK (AVR8_TIFR5_ICF5_MASK | AVR8_TIFR5_OCF5C_MASK | AVR8_TIFR5_OCF5B_MASK | AVR8_TIFR5_OCF5A_MASK | AVR8_TIFR5_TOV5_MASK) + + +#define AVR8_TIFR5_ICF5 ((AVR8_TIFR5 & AVR8_TIFR5_ICF5_MASK) >> AVR8_TIFR5_ICF5_SHIFT) +#define AVR8_TIFR5_OCF5C ((AVR8_TIFR5 & AVR8_TIFR5_OCF5C_MASK) >> AVR8_TIFR5_OCF5C_SHIFT) +#define AVR8_TIFR5_OCF5B ((AVR8_TIFR5 & AVR8_TIFR5_OCF5B_MASK) >> AVR8_TIFR5_OCF5B_SHIFT) +#define AVR8_TIFR5_OCF5A ((AVR8_TIFR5 & AVR8_TIFR5_OCF5A_MASK) >> AVR8_TIFR5_OCF5A_SHIFT) +#define AVR8_TIFR5_TOV5 ((AVR8_TIFR5 & AVR8_TIFR5_TOV5_MASK) >> AVR8_TIFR5_TOV5_SHIFT) + +//--------------------------------------------------------------- + +#define AVR8_OCR0A m_r[AVR8_REGIDX_OCR0A] +#define AVR8_OCR0B m_r[AVR8_REGIDX_OCR0B] +#define AVR8_TCNT0 m_r[AVR8_REGIDX_TCNT0] +#define AVR8_WGM0 (((AVR8_TCCR0B & 0x08) >> 1) | (AVR8_TCCR0A & 0x03)) + +#define AVR8_OCR1A ((AVR8_OCR1AH << 8) | AVR8_OCR1AL) +#define AVR8_OCR1B ((AVR8_OCR1BH << 8) | AVR8_OCR1BL) +#define AVR8_OCR1C ((AVR8_OCR1CH << 8) | AVR8_OCR1CL) +#define AVR8_ICR1 ((AVR8_ICR1H << 8) | AVR8_ICR1L) +#define AVR8_TCNT1 ((AVR8_TCNT1H << 8) | AVR8_TCNT1L) +#define AVR8_WGM1 (((AVR8_TCCR1B & 0x18) >> 1) | (AVR8_TCCR1A & 0x03)) +#define AVR8_TCNT1_DIR (state->m_tcnt1_direction) + +#define AVR8_OCR2A m_r[AVR8_REGIDX_OCR2A] +#define AVR8_OCR2B m_r[AVR8_REGIDX_OCR2B] +#define AVR8_TCNT2 m_r[AVR8_REGIDX_TCNT2] +#define AVR8_WGM2 (((AVR8_TCCR2B & 0x08) >> 1) | (AVR8_TCCR2A & 0x03)) + +#define AVR8_ICR3 ((AVR8_ICR3H << 8) | AVR8_ICR3L) +#define AVR8_OCR3A ((AVR8_OCR3AH << 8) | AVR8_OCR3AL) + +#define AVR8_ICR4 ((AVR8_ICR4H << 8) | AVR8_ICR4L) +#define AVR8_ICR4H (m_r[AVR8_REGIDX_ICR4H]) +#define AVR8_ICR4L (m_r[AVR8_REGIDX_ICR4L]) +#define AVR8_OCR4A ((AVR8_OCR4AH << 8) | AVR8_OCR4AL) +#define AVR8_OCR4B m_r[AVR8_REGIDX_OCR4B] +#define AVR8_TCNT4 m_r[AVR8_REGIDX_TCNT4] + +#define AVR8_ICR5 ((AVR8_ICR5H << 8) | AVR8_ICR5L) +#define AVR8_OCR5A ((AVR8_OCR5AH << 8) | AVR8_OCR5AL) + +#define AVR8_GTCCR_PSRASY_MASK 0x02 +#define AVR8_GTCCR_PSRASY_SHIFT 1 + +#define AVR8_SPSR (m_r[AVR8_REGIDX_SPSR]) +#define AVR8_SPSR_SPR2X (AVR8_SPSR & AVR8_SPSR_SPR2X_MASK) + +#define AVR8_SPCR (m_r[AVR8_REGIDX_SPCR]) +#define AVR8_SPCR_SPIE ((AVR8_SPCR & AVR8_SPCR_SPIE_MASK) >> 7) +#define AVR8_SPCR_SPE ((AVR8_SPCR & AVR8_SPCR_SPE_MASK) >> 6) +#define AVR8_SPCR_DORD ((AVR8_SPCR & AVR8_SPCR_DORD_MASK) >> 5) +#define AVR8_SPCR_MSTR ((AVR8_SPCR & AVR8_SPCR_MSTR_MASK) >> 4) +#define AVR8_SPCR_CPOL ((AVR8_SPCR & AVR8_SPCR_CPOL_MASK) >> 3) +#define AVR8_SPCR_CPHA ((AVR8_SPCR & AVR8_SPCR_CPHA_MASK) >> 2) +#define AVR8_SPCR_SPR (AVR8_SPCR & AVR8_SPCR_SPR_MASK) + +#define AVR8_SPI_RATE ((AVR8_SPSR_SPR2X << 2) | AVR8_SPCR_SPR) + +#define AVR8_PORTB_MOSI 0x08 + +#define AVR8_EECR m_r[AVR8_REGIDX_EECR] & 0x3F; //bits 6 and 7 are reserved and will always read as zero +#define AVR8_EECR_EEPM_MASK 0x30 +#define AVR8_EECR_EERIE_MASK 0x08 +#define AVR8_EECR_EEMPE_MASK 0x04 +#define AVR8_EECR_EEPE_MASK 0x02 +#define AVR8_EECR_EERE_MASK 0x01 +#define AVR8_EECR_EEPM ((AVR8_EECR & AVR8_EECR_EEPM_MASK) >> 4) +#define AVR8_EECR_EERIE ((AVR8_EECR & AVR8_EECR_EERIE_MASK) >> 3) +#define AVR8_EECR_EEMPE ((AVR8_EECR & AVR8_EECR_EEMPE_MASK) >> 2) +#define AVR8_EECR_EEPE ((AVR8_EECR & AVR8_EECR_EEPE_MASK) >> 1) +#define AVR8_EECR_EERE ((AVR8_EECR & AVR8_EECR_EERE_MASK) >> 0) + +//************************************************************************** +// DEVICE INTERFACE +//************************************************************************** + +const device_type ATMEGA88 = &device_creator; +const device_type ATMEGA644 = &device_creator; +const device_type ATMEGA1280 = &device_creator; +const device_type ATMEGA2560 = &device_creator; + +//************************************************************************** +// INTERNAL ADDRESS MAP +//************************************************************************** + +static ADDRESS_MAP_START( atmega88_internal_map, AS_DATA, 8, atmega88_device ) + AM_RANGE(0x0000, 0x00ff) AM_READWRITE( regs_r, regs_w ) +ADDRESS_MAP_END + +static ADDRESS_MAP_START( atmega644_internal_map, AS_DATA, 8, atmega644_device ) + AM_RANGE(0x0000, 0x00ff) AM_READWRITE( regs_r, regs_w ) +ADDRESS_MAP_END + +static ADDRESS_MAP_START( atmega1280_internal_map, AS_DATA, 8, atmega1280_device ) + AM_RANGE(0x0000, 0x01ff) AM_READWRITE( regs_r, regs_w ) +ADDRESS_MAP_END + +static ADDRESS_MAP_START( atmega2560_internal_map, AS_DATA, 8, atmega2560_device ) + AM_RANGE(0x0000, 0x01ff) AM_READWRITE( regs_r, regs_w ) +ADDRESS_MAP_END + +//------------------------------------------------- +// atmega88_device - constructor +//------------------------------------------------- + +atmega88_device::atmega88_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : avr8_device(mconfig, "ATMEGA88", tag, owner, clock, ATMEGA88, 0x0fff, ADDRESS_MAP_NAME(atmega88_internal_map), CPU_TYPE_ATMEGA88, "atmega88", __FILE__) +{ +} + +//------------------------------------------------- +// atmega644_device - constructor +//------------------------------------------------- + +atmega644_device::atmega644_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : avr8_device(mconfig, "ATMEGA644", tag, owner, clock, ATMEGA644, 0xffff, ADDRESS_MAP_NAME(atmega644_internal_map), CPU_TYPE_ATMEGA644, "atmega644", __FILE__) +{ +} + +//------------------------------------------------- +// atmega1280_device - constructor +//------------------------------------------------- + +atmega1280_device::atmega1280_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : avr8_device(mconfig, "ATMEGA1280", tag, owner, clock, ATMEGA1280, 0x1ffff, ADDRESS_MAP_NAME(atmega1280_internal_map), CPU_TYPE_ATMEGA1280, "atmega1280", __FILE__) +{ +} + +//------------------------------------------------- +// atmega2560_device - constructor +//------------------------------------------------- + +atmega2560_device::atmega2560_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : avr8_device(mconfig, "ATMEGA2560", tag, owner, clock, ATMEGA2560, 0x1ffff, ADDRESS_MAP_NAME(atmega2560_internal_map), CPU_TYPE_ATMEGA2560, "atmega2560", __FILE__) +{ +} + +//------------------------------------------------- +// avr8_device - constructor +//------------------------------------------------- + +avr8_device::avr8_device(const machine_config &mconfig, const char *name, const char *tag, device_t *owner, UINT32 clock, const device_type type, UINT32 addr_mask, address_map_constructor internal_map, UINT8 cpu_type, const char *shortname, const char *source) + : cpu_device(mconfig, type, name, tag, owner, clock, shortname, source), + m_shifted_pc(0), + m_program_config("program", ENDIANNESS_LITTLE, 8, 22), + m_data_config("data", ENDIANNESS_LITTLE, 8, 16, 0, internal_map), + m_io_config("io", ENDIANNESS_LITTLE, 8, 4), + m_eeprom_tag(NULL), + m_eeprom(NULL), + m_cpu_type(cpu_type), + m_lfuses(0x62), + m_hfuses(0x99), + m_efuses(0xFF), + m_lock_bits(0xFF), + m_pc(0), + m_spi_active(false), + m_spi_prescale(0), + m_spi_prescale_count(0), + m_addr_mask(addr_mask), + m_interrupt_pending(false), + m_elapsed_cycles(0) +{ + // Allocate & setup + + for (int t=0; t<=5; t++){ + m_timer_top[t] = 0; + m_timer_increment[t] = 1; + m_timer_prescale[t] = 0; + m_timer_prescale_count[t] = 0; + } +} + + +//------------------------------------------------- +// static_set_low_fuses +//------------------------------------------------- + +void avr8_device::set_low_fuses(const UINT8 byte) +{ + m_lfuses = byte; +} + +//------------------------------------------------- +// static_set_high_fuses +//------------------------------------------------- + +void avr8_device::set_high_fuses(const UINT8 byte) +{ + m_hfuses = byte; +} + +//------------------------------------------------- +// static_set_extended_fuses +//------------------------------------------------- + +void avr8_device::set_extended_fuses(const UINT8 byte) +{ + m_efuses = byte; +} + +//------------------------------------------------- +// static_set_lock_bits +//------------------------------------------------- + +void avr8_device::set_lock_bits(const UINT8 byte) +{ + m_lock_bits = byte; +} + +//------------------------------------------------- +// unimplemented_opcode - bail on unspuported +// instruction +//------------------------------------------------- + +void avr8_device::unimplemented_opcode(UINT32 op) +{ +// debugger_break(machine()); + fatalerror("AVR8: unknown opcode (%08x) at %08x\n", op, m_shifted_pc); +} + + +//------------------------------------------------- +// is_long_opcode - returns true if opcode is 4 +// bytes long +//------------------------------------------------- + +inline bool avr8_device::is_long_opcode(UINT16 op) +{ + if((op & 0xf000) == 0x9000) + { + if((op & 0x0f00) < 0x0400) + { + if((op & 0x000f) == 0x0000) + { + return true; + } + } + else if((op & 0x0f00) < 0x0600) + { + if((op & 0x000f) >= 0x000c) + { + return true; + } + } + } + return false; +} + +//------------------------------------------------- +// device_start - start up the device +//------------------------------------------------- + +void avr8_device::device_start() +{ + m_pc = 0; + + m_program = &space(AS_PROGRAM); + m_data = &space(AS_DATA); + m_io = &space(AS_IO); + + // register our state for the debugger + std::string tempstr; + state_add(STATE_GENPC, "GENPC", m_shifted_pc).noshow(); + state_add(STATE_GENFLAGS, "GENFLAGS", m_r[AVR8_REGIDX_SREG]).callimport().callexport().formatstr("%8s").noshow(); + state_add(AVR8_SREG, "STATUS", m_r[AVR8_REGIDX_SREG]).mask(0xff); + state_add(AVR8_PC, "PC", m_shifted_pc).mask(m_addr_mask); + state_add(AVR8_SPH, "SPH", m_r[AVR8_REGIDX_SPH]).mask(0xff); + state_add(AVR8_SPL, "SPL", m_r[AVR8_REGIDX_SPL]).mask(0xff); + state_add(AVR8_R0, "R0", m_r[ 0]).mask(0xff); + state_add(AVR8_R1, "R1", m_r[ 1]).mask(0xff); + state_add(AVR8_R2, "R2", m_r[ 2]).mask(0xff); + state_add(AVR8_R3, "R3", m_r[ 3]).mask(0xff); + state_add(AVR8_R4, "R4", m_r[ 4]).mask(0xff); + state_add(AVR8_R5, "R5", m_r[ 5]).mask(0xff); + state_add(AVR8_R6, "R6", m_r[ 6]).mask(0xff); + state_add(AVR8_R7, "R7", m_r[ 7]).mask(0xff); + state_add(AVR8_R8, "R8", m_r[ 8]).mask(0xff); + state_add(AVR8_R9, "R9", m_r[ 9]).mask(0xff); + state_add(AVR8_R10, "R10", m_r[10]).mask(0xff); + state_add(AVR8_R11, "R11", m_r[11]).mask(0xff); + state_add(AVR8_R12, "R12", m_r[12]).mask(0xff); + state_add(AVR8_R13, "R13", m_r[13]).mask(0xff); + state_add(AVR8_R14, "R14", m_r[14]).mask(0xff); + state_add(AVR8_R15, "R15", m_r[15]).mask(0xff); + state_add(AVR8_R16, "R16", m_r[16]).mask(0xff); + state_add(AVR8_R17, "R17", m_r[17]).mask(0xff); + state_add(AVR8_R18, "R18", m_r[18]).mask(0xff); + state_add(AVR8_R19, "R19", m_r[19]).mask(0xff); + state_add(AVR8_R20, "R20", m_r[20]).mask(0xff); + state_add(AVR8_R21, "R21", m_r[21]).mask(0xff); + state_add(AVR8_R22, "R22", m_r[22]).mask(0xff); + state_add(AVR8_R23, "R23", m_r[23]).mask(0xff); + state_add(AVR8_R24, "R24", m_r[24]).mask(0xff); + state_add(AVR8_R25, "R25", m_r[25]).mask(0xff); + state_add(AVR8_R26, "R26", m_r[26]).mask(0xff); + state_add(AVR8_R27, "R27", m_r[27]).mask(0xff); + state_add(AVR8_R28, "R28", m_r[28]).mask(0xff); + state_add(AVR8_R29, "R29", m_r[29]).mask(0xff); + state_add(AVR8_R30, "R30", m_r[30]).mask(0xff); + state_add(AVR8_R31, "R31", m_r[31]).mask(0xff); + + // register our state for saving + save_item(NAME(m_pc)); + save_item(NAME(m_r)); + save_item(NAME(m_timer_top[0])); + save_item(NAME(m_timer_increment[0])); + save_item(NAME(m_timer_prescale[0])); + save_item(NAME(m_timer_prescale_count[0])); + save_item(NAME(m_timer_top[1])); + save_item(NAME(m_timer_increment[1])); + save_item(NAME(m_timer_prescale[1])); + save_item(NAME(m_timer_prescale_count[1])); + save_item(NAME(m_timer_top[2])); + save_item(NAME(m_timer_increment[2])); + save_item(NAME(m_timer_prescale[2])); + save_item(NAME(m_timer_prescale_count[2])); + save_item(NAME(m_timer_top[3])); + save_item(NAME(m_timer_increment[3])); + save_item(NAME(m_timer_prescale[3])); + save_item(NAME(m_timer_prescale_count[3])); + save_item(NAME(m_timer_top[4])); + save_item(NAME(m_timer_increment[4])); + save_item(NAME(m_timer_prescale[4])); + save_item(NAME(m_timer_prescale_count[4])); + save_item(NAME(m_timer_top[5])); + save_item(NAME(m_timer_increment[5])); + save_item(NAME(m_timer_prescale[5])); + save_item(NAME(m_timer_prescale_count[5])); + save_item(NAME(m_addr_mask)); + save_item(NAME(m_interrupt_pending)); + save_item(NAME(m_elapsed_cycles)); + + // set our instruction counter + m_icountptr = &m_icount; + + m_eeprom = machine().root_device().memregion(m_eeprom_tag)->base(); +} + +//------------------------------------------------- +// device_reset - reset the device +//------------------------------------------------- + +void avr8_device::device_reset() +{ + logerror("AVR low fuse bits: 0x%02X\n", m_lfuses); + logerror("AVR high fuse bits: 0x%02X\n", m_hfuses); + logerror("AVR extended fuse bits: 0x%02X\n", m_efuses); + logerror("AVR lock bits: 0x%02X\n", m_lock_bits); + + switch ((m_hfuses & (BOOTSZ1|BOOTSZ0)) >> 1){ + case 0: m_boot_size = 4096; break; + case 1: m_boot_size = 2048; break; + case 2: m_boot_size = 1024; break; + case 3: m_boot_size = 512; break; + default: break; + } + + if (m_hfuses & BOOTRST){ + m_shifted_pc = 0x0000; + logerror("Booting AVR core from address 0x0000\n"); + } else { + m_shifted_pc = (m_addr_mask + 1) - 2*m_boot_size; + logerror("AVR Boot loader section size: %d words\n", m_boot_size); + } + + for (int i = 0; i < 0x200; i++) + { + m_r[i] = 0; + } + + m_spi_active = false; + m_spi_prescale = 0; + m_spi_prescale_count = 0; + + for (int t=0; t<=5; t++){ + m_timer_top[t] = 0; + m_timer_increment[t] = 1; + m_timer_prescale[t] = 0; + m_timer_prescale_count[t] = 0; + } + + m_ocr2_not_reached_yet = true; + m_interrupt_pending = false; + m_elapsed_cycles = 0; +} + +//------------------------------------------------- +// memory_space_config - return the configuration +// of the specified address space, or NULL if +// the space doesn't exist +//------------------------------------------------- + +const address_space_config *avr8_device::memory_space_config(address_spacenum spacenum) const +{ + if (spacenum == AS_PROGRAM) + { + return &m_program_config; + } + else if (spacenum == AS_DATA) + { + return &m_data_config; + } + else if (spacenum == AS_IO) + { + return &m_io_config; + } + return NULL; +} + + +//------------------------------------------------- +// state_string_export - export state as a string +// for the debugger +//------------------------------------------------- + +void avr8_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + switch (entry.index()) + { + case STATE_GENFLAGS: + strprintf(str, "%c%c%c%c%c%c%c%c", + (m_r[AVR8_REGIDX_SREG] & 0x80) ? 'I' : '-', + (m_r[AVR8_REGIDX_SREG] & 0x40) ? 'T' : '-', + (m_r[AVR8_REGIDX_SREG] & 0x20) ? 'H' : '-', + (m_r[AVR8_REGIDX_SREG] & 0x10) ? 'S' : '-', + (m_r[AVR8_REGIDX_SREG] & 0x08) ? 'V' : '-', + (m_r[AVR8_REGIDX_SREG] & 0x04) ? 'N' : '-', + (m_r[AVR8_REGIDX_SREG] & 0x02) ? 'Z' : '-', + (m_r[AVR8_REGIDX_SREG] & 0x01) ? 'C' : '-'); + break; + } +} + + +//------------------------------------------------- +// disasm_min_opcode_bytes - return the length +// of the shortest instruction, in bytes +//------------------------------------------------- + +UINT32 avr8_device::disasm_min_opcode_bytes() const +{ + return 2; +} + + +//------------------------------------------------- +// disasm_max_opcode_bytes - return the length +// of the longest instruction, in bytes +//------------------------------------------------- + +UINT32 avr8_device::disasm_max_opcode_bytes() const +{ + return 4; +} + + +//------------------------------------------------- +// disasm_disassemble - call the disassembly +// helper function +//------------------------------------------------- + +offs_t avr8_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( avr8 ); + return CPU_DISASSEMBLE_NAME(avr8)(this, buffer, pc, oprom, opram, options); +} + + +//************************************************************************** +// MEMORY ACCESSORS +//************************************************************************** + +inline void avr8_device::push(UINT8 val) +{ + UINT16 sp = SPREG; + m_data->write_byte(sp, val); + sp--; + m_r[AVR8_REGIDX_SPL] = sp & 0x00ff; + m_r[AVR8_REGIDX_SPH] = (sp >> 8) & 0x00ff; +} + +inline UINT8 avr8_device::pop() +{ + UINT16 sp = SPREG; + sp++; + m_r[AVR8_REGIDX_SPL] = sp & 0x00ff; + m_r[AVR8_REGIDX_SPH] = (sp >> 8) & 0x00ff; + return m_data->read_byte(sp); +} + +//************************************************************************** +// IRQ HANDLING +//************************************************************************** + +void avr8_device::set_irq_line(UINT16 vector, int state) +{ + // Horrible hack, not accurate + if(state) + { + if(SREG_R(AVR8_SREG_I)) + { + SREG_W(AVR8_SREG_I, 0); + push(m_pc & 0x00ff); + push((m_pc >> 8) & 0x00ff); + m_pc = vector; + m_shifted_pc = vector << 1; + } + else + { + m_interrupt_pending = true; + } + } +} + +class CInterruptCondition +{ + public: + UINT8 m_intindex; + UINT8 m_intreg; + UINT8 m_intmask; + UINT8 m_regindex; + UINT8 m_regmask; +}; + +static const CInterruptCondition s_int_conditions[AVR8_INTIDX_COUNT] = +{ + { AVR8_INT_SPI_STC, AVR8_REGIDX_SPCR, AVR8_SPCR_SPIE_MASK, AVR8_REGIDX_SPSR, AVR8_SPSR_SPIF_MASK }, + { AVR8_INT_T0COMPB, AVR8_REGIDX_TIMSK0, AVR8_TIMSK0_OCIE0B_MASK, AVR8_REGIDX_TIFR0, AVR8_TIFR0_OCF0B_MASK }, + { AVR8_INT_T0COMPA, AVR8_REGIDX_TIMSK0, AVR8_TIMSK0_OCIE0A_MASK, AVR8_REGIDX_TIFR0, AVR8_TIFR0_OCF0A_MASK }, + { AVR8_INT_T0OVF, AVR8_REGIDX_TIMSK0, AVR8_TIMSK0_TOIE0_MASK, AVR8_REGIDX_TIFR0, AVR8_TIFR0_TOV0_MASK }, + { AVR8_INT_T1CAPT, AVR8_REGIDX_TIMSK1, AVR8_TIMSK1_ICIE1_MASK, AVR8_REGIDX_TIFR1, AVR8_TIFR1_ICF1_MASK }, + { AVR8_INT_T1COMPB, AVR8_REGIDX_TIMSK1, AVR8_TIMSK1_OCIE1B_MASK, AVR8_REGIDX_TIFR1, AVR8_TIFR1_OCF1B_MASK }, + { AVR8_INT_T1COMPA, AVR8_REGIDX_TIMSK1, AVR8_TIMSK1_OCIE1A_MASK, AVR8_REGIDX_TIFR1, AVR8_TIFR1_OCF1A_MASK }, + { AVR8_INT_T1OVF, AVR8_REGIDX_TIMSK1, AVR8_TIMSK1_TOIE1_MASK, AVR8_REGIDX_TIFR1, AVR8_TIFR1_TOV1_MASK }, + { AVR8_INT_T2COMPB, AVR8_REGIDX_TIMSK2, AVR8_TIMSK2_OCIE2B_MASK, AVR8_REGIDX_TIFR2, AVR8_TIFR2_OCF2B_MASK }, + { AVR8_INT_T2COMPA, AVR8_REGIDX_TIMSK2, AVR8_TIMSK2_OCIE2A_MASK, AVR8_REGIDX_TIFR2, AVR8_TIFR2_OCF2A_MASK }, + { AVR8_INT_T2OVF, AVR8_REGIDX_TIMSK2, AVR8_TIMSK2_TOIE2_MASK, AVR8_REGIDX_TIFR2, AVR8_TIFR2_TOV2_MASK } +}; + +void avr8_device::update_interrupt(int source) +{ + const CInterruptCondition &condition = s_int_conditions[source]; + + int intstate = 0; + if (m_r[condition.m_intreg] & condition.m_intmask) + intstate = (m_r[condition.m_regindex] & condition.m_regmask) ? 1 : 0; + + set_irq_line(condition.m_intindex, intstate); + + if (intstate) + { + m_r[condition.m_regindex] &= ~condition.m_regmask; + } +} + + +static const CInterruptCondition s_mega644_int_conditions[AVR8_INTIDX_COUNT] = +{ + { ATMEGA644_INT_SPI_STC, AVR8_REGIDX_SPCR, AVR8_SPCR_SPIE_MASK, AVR8_REGIDX_SPSR, AVR8_SPSR_SPIF_MASK }, + { ATMEGA644_INT_T0COMPB, AVR8_REGIDX_TIMSK0, AVR8_TIMSK0_OCIE0B_MASK, AVR8_REGIDX_TIFR0, AVR8_TIFR0_OCF0B_MASK }, + { ATMEGA644_INT_T0COMPA, AVR8_REGIDX_TIMSK0, AVR8_TIMSK0_OCIE0A_MASK, AVR8_REGIDX_TIFR0, AVR8_TIFR0_OCF0A_MASK }, + { ATMEGA644_INT_T0OVF, AVR8_REGIDX_TIMSK0, AVR8_TIMSK0_TOIE0_MASK, AVR8_REGIDX_TIFR0, AVR8_TIFR0_TOV0_MASK }, + { ATMEGA644_INT_T1CAPT, AVR8_REGIDX_TIMSK1, AVR8_TIMSK1_ICIE1_MASK, AVR8_REGIDX_TIFR1, AVR8_TIFR1_ICF1_MASK }, + { ATMEGA644_INT_T1COMPB, AVR8_REGIDX_TIMSK1, AVR8_TIMSK1_OCIE1B_MASK, AVR8_REGIDX_TIFR1, AVR8_TIFR1_OCF1B_MASK }, + { ATMEGA644_INT_T1COMPA, AVR8_REGIDX_TIMSK1, AVR8_TIMSK1_OCIE1A_MASK, AVR8_REGIDX_TIFR1, AVR8_TIFR1_OCF1A_MASK }, + { ATMEGA644_INT_T1OVF, AVR8_REGIDX_TIMSK1, AVR8_TIMSK1_TOIE1_MASK, AVR8_REGIDX_TIFR1, AVR8_TIFR1_TOV1_MASK }, + { ATMEGA644_INT_T2COMPB, AVR8_REGIDX_TIMSK2, AVR8_TIMSK2_OCIE2B_MASK, AVR8_REGIDX_TIFR2, AVR8_TIFR2_OCF2B_MASK }, + { ATMEGA644_INT_T2COMPA, AVR8_REGIDX_TIMSK2, AVR8_TIMSK2_OCIE2A_MASK, AVR8_REGIDX_TIFR2, AVR8_TIFR2_OCF2A_MASK }, + { ATMEGA644_INT_T2OVF, AVR8_REGIDX_TIMSK2, AVR8_TIMSK2_TOIE2_MASK, AVR8_REGIDX_TIFR2, AVR8_TIFR2_TOV2_MASK } +}; + +void atmega644_device::update_interrupt(int source) +{ + const CInterruptCondition &condition = s_mega644_int_conditions[source]; + + int intstate = 0; + if (m_r[condition.m_intreg] & condition.m_intmask) + intstate = (m_r[condition.m_regindex] & condition.m_regmask) ? 1 : 0; + + set_irq_line(condition.m_intindex << 1, intstate); + + if (intstate) + { + m_r[condition.m_regindex] &= ~condition.m_regmask; + } +} + +//TODO: review this! +void atmega1280_device::update_interrupt(int source) +{ + const CInterruptCondition &condition = s_mega644_int_conditions[source]; + + int intstate = 0; + if (m_r[condition.m_intreg] & condition.m_intmask) + intstate = (m_r[condition.m_regindex] & condition.m_regmask) ? 1 : 0; + + set_irq_line(condition.m_intindex << 1, intstate); + + if (intstate) + { + m_r[condition.m_regindex] &= ~condition.m_regmask; + } +} + +//TODO: review this! +void atmega2560_device::update_interrupt(int source) +{ + const CInterruptCondition &condition = s_mega644_int_conditions[source]; + + int intstate = 0; + if (m_r[condition.m_intreg] & condition.m_intmask) + intstate = (m_r[condition.m_regindex] & condition.m_regmask) ? 1 : 0; + + set_irq_line(condition.m_intindex << 1, intstate); + + if (intstate) + { + m_r[condition.m_regindex] &= ~condition.m_regmask; + } +} + + +//************************************************************************** +// REGISTER HANDLING +//************************************************************************** +void avr8_device::timer_tick(int cycles) +{ + for(int count = 0; count < cycles; count++) + { + m_elapsed_cycles++; + + if (m_spi_active && m_spi_prescale > 0 && m_spi_prescale_countdown >= 0) + { + m_spi_prescale_count++; + if (m_spi_prescale_count >= m_spi_prescale) + { + UINT8 out_bit = (m_r[AVR8_REGIDX_SPDR] & (1 << m_spi_prescale_countdown)) >> m_spi_prescale_countdown; + m_spi_prescale_countdown--; + m_io->write_byte(AVR8_IO_PORTB, (m_r[AVR8_REGIDX_PORTB] &~ AVR8_PORTB_MOSI) | (out_bit ? AVR8_PORTB_MOSI : 0)); + m_r[AVR8_REGIDX_PORTB] = (m_r[AVR8_REGIDX_PORTB] &~ AVR8_PORTB_MOSI) | (out_bit ? AVR8_PORTB_MOSI : 0); + m_spi_prescale_count -= m_spi_prescale; + } + } + + for (int t=0; t<=5; t++){ + if (m_timer_prescale[t] != 0) + { + m_timer_prescale_count[t]++; + if (m_timer_prescale_count[t] >= m_timer_prescale[t]) + { + switch (t){ + case 0: timer0_tick(); break; + case 1: timer1_tick(); break; + case 2: timer2_tick(); break; + case 3: timer3_tick(); break; + case 4: timer4_tick(); break; + case 5: timer5_tick(); break; + } + m_timer_prescale_count[t] -= m_timer_prescale[t]; + } + } + } + + } +} + +// UINT8 ocr0[2] = { m_r[AVR8_REGIDX_OCR0A], m_r[AVR8_REGIDX_OCR0B] }; +//TODO UINT8 ocf0[2] = { (1 << AVR8_TIFR0_OCF0A_SHIFT), (1 << AVR8_TIFR4_OCF0B_SHIFT) }; +//TODO UINT8 int0[2] = { AVR8_INTIDX_OCF0A, AVR8_INTIDX_OCF0B }; + +#define LOG_TIMER_0 0 +#define LOG_TIMER_5 0 +// Timer 0 Handling +void avr8_device::timer0_tick() +{ +#if LOG_TIMER_0 + printf("AVR8_WGM0: %d\n", AVR8_WGM0); + printf("AVR8_TCCR0A_COM0B: %d\n", AVR8_TCCR0A_COM0B); +#endif + + UINT8 count = m_r[AVR8_REGIDX_TCNT0]; + INT32 increment = m_timer_increment[0]; + + switch(AVR8_WGM0) + { + case WGM02_NORMAL: + //printf("WGM02_NORMAL: Unimplemented timer#0 waveform generation mode\n"); + break; + + case WGM02_PWM_PC: + //printf("WGM02_PWM_PC: Unimplemented timer#0 waveform generation mode\n"); + break; + + case WGM02_CTC_CMP: + switch(AVR8_TCCR0A_COM0B){ + case 0: /* Normal Operation */ + if (count == m_timer_top[0]){ + m_timer_top[0] = 0; + } + break; + case 1: /* Toggle OC0B on compare match */ + if (count == m_timer_top[0]){ + m_timer_top[0] = 0; +#if LOG_TIMER_0 + printf("[0] Toggle OC0B\n"); +#endif + m_io->write_byte(AVR8_IO_PORTG, m_io->read_byte(AVR8_IO_PORTG) ^ (1 << 5)); + } + break; + case 2: /* Clear OC0B on compare match */ + if (count == m_timer_top[0]){ + m_timer_top[0] = 0; + //Clear OC0B +#if LOG_TIMER_0 + printf("[0] Clear OC0B\n"); +#endif + m_io->write_byte(AVR8_IO_PORTG, m_io->read_byte(AVR8_IO_PORTG) & ~(1 << 5)); + } + break; + case 3: /* Set OC0B on compare match */ + if (count == m_timer_top[0]){ + m_timer_top[0] = 0; +#if LOG_TIMER_0 + printf("[0] Set OC0B\n"); +#endif + m_io->write_byte(AVR8_IO_PORTG, m_io->read_byte(AVR8_IO_PORTG) | (1 << 5)); + } + break; + } + break; + + case WGM02_FAST_PWM: + printf("WGM02_FAST_PWM: Unimplemented timer#0 waveform generation mode\n"); + break; + + case WGM02_PWM_PC_CMP: + printf("WGM02_PWM_PC_CMP: Unimplemented timer#0 waveform generation mode\n"); + break; + + case WGM02_FAST_PWM_CMP: + printf("WGM02_FAST_PWM_CMP: Unimplemented timer#0 waveform generation mode\n"); + break; + + default: + verboselog(m_pc, 0, "update_timer0_compare_mode: Unknown waveform generation mode: %02x\n", AVR8_WGM0); + break; + } + + count = count & 0xff; + + count += increment; + m_r[AVR8_REGIDX_TCNT0] = count & 0xff; +} + +void avr8_device::changed_tccr0a(UINT8 data) +{ + UINT8 oldtccr = AVR8_TCCR0A; + UINT8 newtccr = data; + UINT8 changed = newtccr ^ oldtccr; + + AVR8_TCCR0A = data; + + if(changed & AVR8_TCCR0A_WGM0_10_MASK) + { + update_timer_waveform_gen_mode(0, AVR8_WGM0); + } +} + +void avr8_device::timer0_force_output_compare(int reg) +{ + // TODO + verboselog(m_pc, 0, "timer0_force_output_compare: TODO; should be forcing OC0%c\n", avr8_reg_name[reg]); +} + +void avr8_device::changed_tccr0b(UINT8 data) +{ + if (VERBOSE_LEVEL) printf("changed_tccr0b: data=0x%02X\n", data); + + UINT8 oldtccr = AVR8_TCCR0B; + UINT8 newtccr = data; + UINT8 changed = newtccr ^ oldtccr; + + AVR8_TCCR0B = data; + + if(changed & AVR8_TCCR0B_FOC0A_MASK) + { + // TODO + timer0_force_output_compare(AVR8_REG_A); + } + + if(changed & AVR8_TCCR0B_FOC0B_MASK) + { + // TODO + timer0_force_output_compare(AVR8_REG_B); + } + + if(changed & AVR8_TCCR0B_WGM0_2_MASK) + { + update_timer_waveform_gen_mode(0, AVR8_WGM0); + } + + if(changed & AVR8_TCCR0B_CS_MASK) + { + update_timer_clock_source(0, AVR8_TIMER0_CLOCK_SELECT); + } +} + +void avr8_device::update_ocr0(UINT8 newval, UINT8 reg) +{ + m_r[(reg == AVR8_REG_A) ? AVR8_REGIDX_OCR0A : AVR8_REGIDX_OCR0B] = newval; +} + +// Timer 1 Handling + +void avr8_device::timer1_tick() +{ + /* TODO: Handle comparison, setting OC1x pins, detection of BOTTOM and TOP */ + + UINT16 count = (m_r[AVR8_REGIDX_TCNT1H] << 8) | m_r[AVR8_REGIDX_TCNT1L]; + INT32 wgm1 = ((m_r[AVR8_REGIDX_TCCR1B] & AVR8_TCCR1B_WGM1_32_MASK) >> 1) | + (m_r[AVR8_REGIDX_TCCR1A] & AVR8_TCCR1A_WGM1_10_MASK); + + // Cache things in array form to avoid a compare+branch inside a potentially high-frequency timer + //UINT8 compare_mode[2] = { (m_r[AVR8_REGIDX_TCCR1A] & AVR8_TCCR1A_COM1A_MASK) >> AVR8_TCCR1A_COM1A_SHIFT, + //(m_r[AVR8_REGIDX_TCCR1A] & AVR8_TCCR1A_COM1B_MASK) >> AVR8_TCCR1A_COM1B_SHIFT }; + UINT16 ocr1[2] = { (m_r[AVR8_REGIDX_OCR1AH] << 8) | m_r[AVR8_REGIDX_OCR1AL], + (m_r[AVR8_REGIDX_OCR1BH] << 8) | m_r[AVR8_REGIDX_OCR1BL] }; + UINT8 ocf1[2] = { (1 << AVR8_TIFR1_OCF1A_SHIFT), (1 << AVR8_TIFR1_OCF1B_SHIFT) }; + UINT8 int1[2] = { AVR8_INTIDX_OCF1A, AVR8_INTIDX_OCF1B }; + INT32 increment = m_timer_increment[1]; + + for(INT32 reg = AVR8_REG_A; reg <= AVR8_REG_B; reg++) + { + switch(wgm1) + { + case WGM1_CTC_OCR: + if (count == 0xffff) + { + m_r[AVR8_REGIDX_TIFR1] |= AVR8_TIFR1_TOV1_MASK; + update_interrupt(AVR8_INTIDX_TOV1); + count = 0; + increment = 0; + } + + if (count == ocr1[reg]) + { + if (reg == 0) + { + count = 0; + increment = 0; + } + m_r[AVR8_REGIDX_TIFR1] |= ocf1[reg]; + update_interrupt(int1[reg]); + } + else if (count == 0) + { + if (reg == 0) + { + m_r[AVR8_REGIDX_TIFR1] &= ~AVR8_TIFR1_TOV1_MASK; + update_interrupt(AVR8_INTIDX_TOV1); + } + + m_r[AVR8_REGIDX_TIFR1] &= ~ocf1[reg]; + update_interrupt(int1[reg]); + } + break; + + case WGM1_FAST_PWM_OCR: + if(count == ocr1[reg]) + { + if (reg == 0) + { + m_r[AVR8_REGIDX_TIFR1] |= AVR8_TIFR1_TOV1_MASK; + update_interrupt(AVR8_INTIDX_TOV1); + count = 0; + increment = 0; + } + + m_r[AVR8_REGIDX_TIFR1] |= ocf1[reg]; + update_interrupt(int1[reg]); + } + else if(count == 0) + { + if (reg == 0) + { + m_r[AVR8_REGIDX_TIFR1] &= ~AVR8_TIFR1_TOV1_MASK; + update_interrupt(AVR8_INTIDX_TOV1); + } + + m_r[AVR8_REGIDX_TIFR1] &= ~ocf1[reg]; + update_interrupt(int1[reg]); + } + break; + + default: + verboselog(m_pc, 0, "update_timer1_compare_mode: Unknown waveform generation mode: %02x\n", wgm1); + break; + } + /* + switch(compare_mode[reg]) + { + case 0: + //verboselog(m_pc, 0, "update_timer1_compare_mode: Normal port operation (OC1 disconnected)\n"); + break; + + case 1: + case 2: + // TODO + break; + + case 3: + break; + } + */ + } + + count += increment; + m_r[AVR8_REGIDX_TCNT1H] = (count >> 8) & 0xff; + m_r[AVR8_REGIDX_TCNT1L] = count & 0xff; +} + +void avr8_device::update_timer_waveform_gen_mode(UINT8 t, UINT8 mode) +{ + INT32 oc_val = -1, ic_val = -1; + + switch (t){ + case 0: + oc_val = AVR8_OCR0A; + ic_val = -1; + break; + case 1: + oc_val = AVR8_OCR1A; + ic_val = AVR8_ICR1; + break; + case 2: + oc_val = AVR8_OCR2A; + ic_val = -1; + break; + case 3: + oc_val = AVR8_OCR3A; + ic_val = AVR8_ICR3; + break; + case 4: + oc_val = AVR8_OCR4A; + ic_val = AVR8_ICR4; + break; + case 5: + oc_val = AVR8_OCR5A; + ic_val = AVR8_ICR5; + break; + } + + INT32 top_values_02[8] = {0xFF, 0xFF, oc_val, 0xFF, -1, oc_val, -1, oc_val}; //table 20-8 + + INT32 top_values_1345[16] = {0xFFFF, 0x00FF, 0x01FF, 0x03FF, + oc_val, 0x00FF, 0x01FF, 0x03FF, + ic_val, oc_val, ic_val, oc_val, + ic_val, -1, ic_val, oc_val}; //table 17-2 + + switch(t){ + case 0: + case 2: + m_timer_top[t] = top_values_02[mode]; + break; + case 1: + case 3: + case 4: + case 5: + m_timer_top[t] = top_values_1345[mode]; + break; + } + + if (m_timer_top[t] == -1){ + m_timer_top[t] = 0; + printf("update_timer_waveform_gen_mode: Timer #%d - Unsupported waveform generation type: %d\n", t, mode); + } +} + +void avr8_device::changed_tccr1a(UINT8 data) +{ + UINT8 oldtccr = AVR8_TCCR1A; + UINT8 newtccr = data; + UINT8 changed = newtccr ^ oldtccr; + + m_r[AVR8_REGIDX_TCCR1A] = newtccr; + + if(changed & AVR8_TCCR1A_WGM1_10_MASK) + { + update_timer_waveform_gen_mode(1, AVR8_WGM1); + } +} + +void avr8_device::update_timer1_input_noise_canceler() +{ + // TODO +} + +void avr8_device::update_timer1_input_edge_select() +{ + // TODO + //verboselog(m_pc, 0, "update_timer1_input_edge_select: TODO; Clocking edge is %s\n", "test"); +} + +void avr8_device::changed_tccr1b(UINT8 data) +{ + if (VERBOSE_LEVEL) printf("changed_tccr1b: data=0x%02X\n", data); + + UINT8 oldtccr = AVR8_TCCR1B; + UINT8 newtccr = data; + UINT8 changed = newtccr ^ oldtccr; + + m_r[AVR8_REGIDX_TCCR1B] = newtccr; + + if(changed & AVR8_TCCR1B_ICNC1_MASK) + { + // TODO + update_timer1_input_noise_canceler(); + } + + if(changed & AVR8_TCCR1B_ICES1_MASK) + { + // TODO + update_timer1_input_edge_select(); + } + + if(changed & AVR8_TCCR1B_WGM1_32_MASK) + { + update_timer_waveform_gen_mode(1, AVR8_WGM1); + } + + if(changed & AVR8_TCCR1B_CS_MASK) + { + update_timer_clock_source(1, AVR8_TIMER1_CLOCK_SELECT); + } +} + +void avr8_device::update_ocr1(UINT16 newval, UINT8 reg) +{ + UINT8 *p_reg_h = (reg == AVR8_REG_A) ? &m_r[AVR8_REGIDX_OCR1AH] : &m_r[AVR8_REGIDX_OCR1BH]; + UINT8 *p_reg_l = (reg == AVR8_REG_A) ? &m_r[AVR8_REGIDX_OCR1AL] : &m_r[AVR8_REGIDX_OCR1BL]; + *p_reg_h = (UINT8)(newval >> 8); + *p_reg_l = (UINT8)newval; + + // Nothing needs to be done? All handled in timer callback +} + +// Timer 2 Handling + +void avr8_device::timer2_tick() +{ + UINT16 count = m_r[AVR8_REGIDX_TCNT2]; + INT32 wgm2 = ((m_r[AVR8_REGIDX_TCCR2B] & AVR8_TCCR2B_WGM2_2_MASK) >> 1) | + (m_r[AVR8_REGIDX_TCCR2A] & AVR8_TCCR2A_WGM2_10_MASK); + + // Cache things in array form to avoid a compare+branch inside a potentially high-frequency timer + //UINT8 compare_mode[2] = { (m_r[AVR8_REGIDX_TCCR2A] & AVR8_TCCR2A_COM2A_MASK) >> AVR8_TCCR2A_COM2A_SHIFT, + //(m_r[AVR8_REGIDX_TCCR2A] & AVR8_TCCR2A_COM2B_MASK) >> AVR8_TCCR2A_COM2B_SHIFT }; + UINT8 ocr2[2] = { m_r[AVR8_REGIDX_OCR2A], m_r[AVR8_REGIDX_OCR2B] }; + UINT8 ocf2[2] = { (1 << AVR8_TIFR2_OCF2A_SHIFT), (1 << AVR8_TIFR2_OCF2B_SHIFT) }; + INT32 increment = m_timer_increment[2]; + + for(INT32 reg = AVR8_REG_A; reg <= AVR8_REG_B; reg++) + { + switch(wgm2) + { + case WGM02_FAST_PWM: + if (reg==0) + { + if (count >= m_r[AVR8_REGIDX_OCR2A]) + { + if (count >= 0xFF) + { + //Turn on + m_io->write_byte(AVR8_IO_PORTD, m_io->read_byte(AVR8_IO_PORTD) | (1 << 7)); + m_r[AVR8_REGIDX_TCNT2] = 0; + m_ocr2_not_reached_yet = true; + } + else + { + if (m_ocr2_not_reached_yet) + { + //Turn off + m_io->write_byte(AVR8_IO_PORTD, m_io->read_byte(AVR8_IO_PORTD) & ~(1 << 7)); + m_ocr2_not_reached_yet = false; + } + } + } + } + break; + + case WGM02_FAST_PWM_CMP: + if(count == ocr2[reg]) + { + if (reg == 0) + { + m_r[AVR8_REGIDX_TIFR2] |= AVR8_TIFR2_TOV2_MASK; + count = 0; + increment = 0; + } + + m_r[AVR8_REGIDX_TIFR2] |= ocf2[reg]; + } + else if (count == 0) + { + if (reg == 0) + { + m_r[AVR8_REGIDX_TIFR2] &= ~AVR8_TIFR2_TOV2_MASK; + } + } + break; + + default: + // TODO + break; + } + /* + switch(compare_mode[reg]) + { + case 0: + //verboselog(m_pc, 0, "update_timer2_compare_mode: Normal port operation (OC2 disconnected)\n"); + break; + + case 1: + case 2: + // TODO + break; + + case 3: + break; + } + */ + } + + m_r[AVR8_REGIDX_TCNT2] += increment; + + update_interrupt(AVR8_INTIDX_OCF2A); + update_interrupt(AVR8_INTIDX_OCF2B); + update_interrupt(AVR8_INTIDX_TOV2); +} + +void avr8_device::changed_tccr2a(UINT8 data) +{ + UINT8 oldtccr = AVR8_TCCR2A; + UINT8 newtccr = data; + UINT8 changed = newtccr ^ oldtccr; + + AVR8_TCCR2A = data; + + if(changed & AVR8_TCCR2A_WGM2_10_MASK) + { + // TODO + update_timer_waveform_gen_mode(2, AVR8_WGM2); + } +} + +void avr8_device::timer2_force_output_compare(int reg) +{ + // TODO + verboselog(m_pc, 0, "force_output_compare: TODO; should be forcing OC2%c\n", avr8_reg_name[reg]); +} + +void avr8_device::changed_tccr2b(UINT8 data) +{ + if (VERBOSE_LEVEL) printf("changed_tccr2b: data=0x%02X\n", data); + + UINT8 oldtccr = AVR8_TCCR2B; + UINT8 newtccr = data; + UINT8 changed = newtccr ^ oldtccr; + + AVR8_TCCR2B = data; + + if(changed & AVR8_TCCR2B_FOC2A_MASK) + { + // TODO + timer2_force_output_compare(AVR8_REG_A); + } + + if(changed & AVR8_TCCR2B_FOC2B_MASK) + { + // TODO + timer2_force_output_compare(AVR8_REG_B); + } + + if(changed & AVR8_TCCR2B_WGM2_2_MASK) + { + update_timer_waveform_gen_mode(2, AVR8_WGM2); + } + + if(changed & AVR8_TCCR2B_CS_MASK) + { + update_timer_clock_source(2, AVR8_TIMER2_CLOCK_SELECT); + } +} + +void avr8_device::update_ocr2(UINT8 newval, UINT8 reg) +{ + m_r[(reg == AVR8_REG_A) ? AVR8_REGIDX_OCR2A : AVR8_REGIDX_OCR2B] = newval; + + // Nothing needs to be done? All handled in timer callback +} + +/************************************************************************************************/ + +// Timer 3 Handling +void avr8_device::timer3_tick() +{ +} + +/************************************************************************************************/ + +void avr8_device::timer4_tick() +{ + /* TODO: Handle comparison, setting OC1x pins, detection of BOTTOM and TOP */ +// printf("AVR8_WGM4: %d\n", AVR8_WGM4); +// printf("AVR8_TCCR4A_COM4B: %d\n", AVR8_TCCR4A_COM4B); + + UINT16 count = (m_r[AVR8_REGIDX_TCNT4H] << 8) | m_r[AVR8_REGIDX_TCNT4L]; + + // Cache things in array form to avoid a compare+branch inside a potentially high-frequency timer + //UINT8 compare_mode[2] = { (m_r[AVR8_REGIDX_TCCR1A] & AVR8_TCCR1A_COM1A_MASK) >> AVR8_TCCR1A_COM1A_SHIFT, + //(m_r[AVR8_REGIDX_TCCR1A] & AVR8_TCCR1A_COM1B_MASK) >> AVR8_TCCR1A_COM1B_SHIFT }; + UINT16 ocr4[2] = { (m_r[AVR8_REGIDX_OCR4AH] << 8) | m_r[AVR8_REGIDX_OCR4AL], + (m_r[AVR8_REGIDX_OCR4BH] << 8) | m_r[AVR8_REGIDX_OCR4BL] }; +//TODO UINT8 ocf4[2] = { (1 << AVR8_TIFR4_OCF4A_SHIFT), (1 << AVR8_TIFR4_OCF4B_SHIFT) }; +//TODO UINT8 int4[2] = { AVR8_INTIDX_OCF4A, AVR8_INTIDX_OCF4B }; + INT32 increment = m_timer_increment[4]; + + switch(AVR8_WGM4) + { + case WGM4_FAST_PWM_8: + case WGM4_FAST_PWM_9: + case WGM4_FAST_PWM_10: + switch(AVR8_TCCR4A_COM4B){ + case 0: /* Normal Operation */ + break; + case 1: /* TODO */ + break; + case 2: /* Non-inverting mode */ + if (count == m_timer_top[4]){ + //Clear OC0B + printf("[2] Clear OC0B\n"); + m_io->write_byte(AVR8_IO_PORTG, m_io->read_byte(AVR8_IO_PORTG) & ~(1 << 5)); + } else if (count == 0){ + //Set OC0B + printf("[2] Set OC0B\n"); + m_io->write_byte(AVR8_IO_PORTG, m_io->read_byte(AVR8_IO_PORTG) | (1 << 5)); + } + break; + case 3: /* Inverting mode */ + if (count == m_timer_top[4]){ + //Set OC0B + printf("[3] Set OC0B\n"); + m_io->write_byte(AVR8_IO_PORTG, m_io->read_byte(AVR8_IO_PORTG) | (1 << 5)); + } else if (count == 0){ + //Clear OC0B + printf("[3] Clear OC0B\n"); + m_io->write_byte(AVR8_IO_PORTG, m_io->read_byte(AVR8_IO_PORTG) & ~(1 << 5)); + } + break; + } + break; + + case WGM4_CTC_OCR: + //printf("[T4] tick WGM4_CTC_OCR: %d\n", count); + if (count == 0xffff) + { + m_r[AVR8_REGIDX_TIFR4] |= AVR8_TIFR4_TOV4_MASK; + update_interrupt(AVR8_INTIDX_TOV4); + count = 0; + increment = 0; + } + + if (count == ocr4[0]) /*TODO: test for all 3 register*/ + {} + else if (count == 0) + {} + break; + + case WGM1_FAST_PWM_OCR: + if(count == ocr4[0]) /*TODO: test for all 3 register*/ + {} + else if(count == 0) + {} + break; + + default: + verboselog(m_pc, 0, "update_timer4_compare_mode: Unknown waveform generation mode: %02x\n", wgm4); + break; + } + + count += increment; + m_r[AVR8_REGIDX_TCNT4H] = (count >> 8) & 0xff; + m_r[AVR8_REGIDX_TCNT4L] = count & 0xff; +} + +void avr8_device::update_timer_clock_source(UINT8 t, UINT8 clock_select) +{ + int prescale_values[8] = {0, 1, 8, 64, 256, 1024, -1, -1}; + m_timer_prescale[t] = prescale_values[clock_select]; + + if (VERBOSE_LEVEL) printf("update_timer_clock_source: t=%d cs=%d\n", t, clock_select); + + if (m_timer_prescale[t] == 0xFFFF){ + printf("[Timer #%d]: update_timer_clock_source: External trigger mode not implemented yet\n", t); + m_timer_prescale[t] = 0; + } + + if (m_timer_prescale_count[t] > m_timer_prescale[t]) + m_timer_prescale_count[t] = m_timer_prescale[t] - 1; +} + +void avr8_device::changed_tccr3a(UINT8 data) +{ + //TODO: Implement-me +// AVR8_TCCR3A = data; +} + +void avr8_device::changed_tccr3b(UINT8 data) +{ + printf("IMPLEMENT-ME: changed_tccr4b: data=0x%02X\n", data); +} + +void avr8_device::changed_tccr3c(UINT8 data) +{ +// UINT8 oldtccr = AVR8_TCCR3C; +// UINT8 newtccr = data; +// UINT8 changed = newtccr ^ oldtccr; + printf("IMPLEMENT-ME: changed_tccr3c: data=0x%02X\n", data); + +// AVR8_TCCR3C = data; + + //TODO: Implement-me +} + +void avr8_device::changed_tccr4a(UINT8 data) +{ + UINT8 oldtccr = AVR8_TCCR4A; + UINT8 newtccr = data; + UINT8 changed = newtccr ^ oldtccr; + + AVR8_TCCR4A = data; + + if(changed & AVR8_TCCR4A_WGM4_10_MASK) + { + update_timer_waveform_gen_mode(4, AVR8_WGM4); + } +} + +void avr8_device::changed_tccr4b(UINT8 data) +{ + printf("changed_tccr4b: data=0x%02X\n", data); + + UINT8 oldtccr = AVR8_TCCR4B; + UINT8 newtccr = data; + UINT8 changed = newtccr ^ oldtccr; + + AVR8_TCCR4B = data; + + if(changed & AVR8_TCCR4B_FOC4A_MASK) + { + // TODO +// timer4_force_output_compare(AVR8_REG_A); + } + + if(changed & AVR8_TCCR4B_FOC4B_MASK) + { + // TODO +// timer4_force_output_compare(AVR8_REG_B); + } + + if(changed & AVR8_TCCR4B_WGM4_32_MASK) + { + update_timer_waveform_gen_mode(4, AVR8_WGM4); + } + + if(changed & AVR8_TCCR4B_CS_MASK) + { + update_timer_clock_source(4, AVR8_TIMER4_CLOCK_SELECT); + } +} + +void avr8_device::changed_tccr4c(UINT8 data) +{ +// UINT8 oldtccr = AVR8_TCCR4C; +// UINT8 newtccr = data; +// UINT8 changed = newtccr ^ oldtccr; + + AVR8_TCCR4C = data; + + //TODO: Implement-me +} + +/************************************************************************************************/ + +// Timer 5 Handling +void avr8_device::timer5_tick() +{ +#if LOG_TIMER_5 + printf("AVR8_WGM5: %d\n", AVR8_WGM5); + printf("AVR8_TCCR5A_COM5B: %d\n", AVR8_TCCR5A_COM5B); +#endif + + UINT16 count = (AVR8_TCNT5H << 8) + AVR8_TCNT5L; + INT32 increment = m_timer_increment[5]; + + switch(AVR8_WGM5) + { + case WGM5_NORMAL: + case WGM5_PWM_8_PC: + case WGM5_PWM_9_PC: + case WGM5_PWM_10_PC: +// case WGM5_CTC_OCR: + case WGM5_FAST_PWM_8: + case WGM5_FAST_PWM_9: + case WGM5_FAST_PWM_10: + case WGM5_PWM_PFC_ICR: + case WGM5_PWM_PFC_OCR: + case WGM5_PWM_PC_ICR: + case WGM5_PWM_PC_OCR: + case WGM5_CTC_ICR: + case WGM5_FAST_PWM_ICR: + case WGM5_FAST_PWM_OCR: +#if LOG_TIMER_5 + printf("Unimplemented timer#5 waveform generation mode: AVR8_WGM5 = 0x%02X\n", AVR8_WGM5); +#endif + break; + + case WGM5_CTC_OCR: + //TODO: verify this! Can be very wrong!!! + switch(AVR8_TCCR5A_COM5B){ + case 0: /* Normal Operation */ + if (count == m_timer_top[5]){ + m_timer_top[5] = 0; + } + break; + case 1: /* Toggle OC5B on compare match */ + if (count == m_timer_top[5]){ + m_timer_top[5] = 0; +#if LOG_TIMER_5 + printf("[5] Toggle OC5B\n"); +#endif + m_io->write_byte(AVR8_IO_PORTL, m_io->read_byte(AVR8_IO_PORTL) ^ (1 << 4)); + } + break; + case 2: /* Clear OC5B on compare match */ + if (count == m_timer_top[5]){ + m_timer_top[5] = 0; + //Clear OC5B +#if LOG_TIMER_5 + printf("[5] Clear OC5B\n"); +#endif + m_io->write_byte(AVR8_IO_PORTL, m_io->read_byte(AVR8_IO_PORTL) & ~(1 << 4)); + } + break; + case 3: /* Set OC5B on compare match */ + if (count == m_timer_top[5]){ + m_timer_top[5] = 0; +#if LOG_TIMER_5 + printf("[5] Set OC5B\n"); +#endif + m_io->write_byte(AVR8_IO_PORTL, m_io->read_byte(AVR8_IO_PORTL) | (1 << 4)); + } + break; + } + break; + + default: + printf("Timer #5: Unknown waveform generation mode: %02x\n", AVR8_WGM5); + break; + } + + count += increment; + m_r[AVR8_REGIDX_TCNT5H] = (count >> 8) & 0xff; + m_r[AVR8_REGIDX_TCNT5L] = count & 0xff; +} + +void avr8_device::changed_tccr5a(UINT8 data) +{ + UINT8 oldtccr = AVR8_TCCR5A; + UINT8 newtccr = data; + UINT8 changed = newtccr ^ oldtccr; + + AVR8_TCCR5A = data; + + if(changed & AVR8_TCCR5A_WGM5_10_MASK) + { + update_timer_waveform_gen_mode(5, AVR8_WGM5); + } +} + +void avr8_device::changed_tccr5b(UINT8 data) +{ + printf("changed_tccr5b: data=0x%02X\n", data); + + UINT8 oldtccr = AVR8_TCCR5B; + UINT8 newtccr = data; + UINT8 changed = newtccr ^ oldtccr; + + AVR8_TCCR5B = data; + + if(changed & AVR8_TCCR5C_FOC5A_MASK) + { + // TODO +// timer5_force_output_compare(AVR8_REG_A); + } + + if(changed & AVR8_TCCR5C_FOC5B_MASK) + { + // TODO +// timer5_force_output_compare(AVR8_REG_B); + } + + if(changed & AVR8_TCCR5C_FOC5C_MASK) + { + // TODO +// timer5_force_output_compare(AVR8_REG_C); + } + + if(changed & AVR8_TCCR5B_WGM5_32_MASK) + { + update_timer_waveform_gen_mode(5, AVR8_WGM5); + } + + if(changed & AVR8_TCCR5B_CS_MASK) + { + update_timer_clock_source(5, AVR8_TIMER5_CLOCK_SELECT); + } +} + +/************************************************************************************************/ + + +/****************/ +/* SPI Handling */ +/****************/ + +void avr8_device::enable_spi() +{ + // TODO +} + +void avr8_device::disable_spi() +{ + // TODO +} + +void avr8_device::spi_update_masterslave_select() +{ + // TODO +} + +void avr8_device::spi_update_clock_polarity() +{ + // TODO +} + +void avr8_device::spi_update_clock_phase() +{ + // TODO +} + +const UINT8 avr8_device::spi_clock_divisor[8] = { 4, 16, 64, 128, 2, 8, 32, 64 }; + +void avr8_device::spi_update_clock_rate() +{ + m_spi_prescale = spi_clock_divisor[AVR8_SPI_RATE]; + m_spi_prescale_count &= m_spi_prescale - 1; +} + +void avr8_device::change_spcr(UINT8 data) +{ + UINT8 oldspcr = AVR8_SPCR; + UINT8 newspcr = data; + UINT8 changed = newspcr ^ oldspcr; + UINT8 high_to_low = ~newspcr & oldspcr; + UINT8 low_to_high = newspcr & ~oldspcr; + + AVR8_SPCR = data; + + if(changed & AVR8_SPCR_SPIE_MASK) + { + // Check for SPI interrupt condition + update_interrupt(AVR8_INTIDX_SPI); + } + + if(low_to_high & AVR8_SPCR_SPE_MASK) + { + enable_spi(); + } + else if(high_to_low & AVR8_SPCR_SPE_MASK) + { + disable_spi(); + } + + if(changed & AVR8_SPCR_MSTR_MASK) + { + spi_update_masterslave_select(); + } + + if(changed & AVR8_SPCR_CPOL_MASK) + { + spi_update_clock_polarity(); + } + + if(changed & AVR8_SPCR_CPHA_MASK) + { + spi_update_clock_phase(); + } + + if(changed & AVR8_SPCR_SPR_MASK) + { + spi_update_clock_rate(); + } +} + +void avr8_device::change_spsr(UINT8 data) +{ + UINT8 oldspsr = AVR8_SPSR; + UINT8 newspsr = data; + UINT8 changed = newspsr ^ oldspsr; + + AVR8_SPSR &= ~1; + AVR8_SPSR |= data & 1; + + if(changed & AVR8_SPSR_SPR2X_MASK) + { + spi_update_clock_rate(); + } +} + +/*****************************************************************************/ + +WRITE8_MEMBER( avr8_device::regs_w ) +{ + //printf("<<< WRITE offset [%04x]=%02x >>>\n", offset, data); + + switch( offset ) + { + case AVR8_REGIDX_R0: + case AVR8_REGIDX_R1: + case AVR8_REGIDX_R2: + case AVR8_REGIDX_R3: + case AVR8_REGIDX_R4: + case AVR8_REGIDX_R5: + case AVR8_REGIDX_R6: + case AVR8_REGIDX_R7: + case AVR8_REGIDX_R8: + case AVR8_REGIDX_R9: + case AVR8_REGIDX_R10: + case AVR8_REGIDX_R11: + case AVR8_REGIDX_R12: + case AVR8_REGIDX_R13: + case AVR8_REGIDX_R14: + case AVR8_REGIDX_R15: + case AVR8_REGIDX_R16: + case AVR8_REGIDX_R17: + case AVR8_REGIDX_R18: + case AVR8_REGIDX_R19: + case AVR8_REGIDX_R20: + case AVR8_REGIDX_R21: + case AVR8_REGIDX_R22: + case AVR8_REGIDX_R23: + case AVR8_REGIDX_R24: + case AVR8_REGIDX_R25: + case AVR8_REGIDX_R26: + case AVR8_REGIDX_R27: + case AVR8_REGIDX_R28: + case AVR8_REGIDX_R29: + case AVR8_REGIDX_R30: + case AVR8_REGIDX_R31: + m_r[offset] = data; + break; + + case AVR8_REGIDX_PORTA: + m_io->write_byte(AVR8_IO_PORTA, data); + m_r[AVR8_REGIDX_PORTA] = data; + break; + + case AVR8_REGIDX_PORTB: + m_io->write_byte(AVR8_IO_PORTB, data); + m_r[AVR8_REGIDX_PORTB] = data; + break; + + case AVR8_REGIDX_PORTC: + m_io->write_byte(AVR8_IO_PORTC, data); + m_r[AVR8_REGIDX_PORTC] = data; + break; + + case AVR8_REGIDX_PORTD: + m_io->write_byte(AVR8_IO_PORTD, data); + m_r[AVR8_REGIDX_PORTD] = data; + break; + + case AVR8_REGIDX_PORTE: + m_io->write_byte(AVR8_IO_PORTE, data); + m_r[AVR8_REGIDX_PORTE] = data; + break; + + case AVR8_REGIDX_PORTF: + m_io->write_byte(AVR8_IO_PORTF, data); + m_r[AVR8_REGIDX_PORTF] = data; + break; + + case AVR8_REGIDX_PORTG: + m_io->write_byte(AVR8_IO_PORTG, data); + m_r[AVR8_REGIDX_PORTG] = data; + break; + + case AVR8_REGIDX_PORTH: + m_io->write_byte(AVR8_IO_PORTH, data); + m_r[AVR8_REGIDX_PORTH] = data; + break; + + case AVR8_REGIDX_PORTJ: + m_io->write_byte(AVR8_IO_PORTJ, data); + m_r[AVR8_REGIDX_PORTJ] = data; + break; + + case AVR8_REGIDX_PORTK: + m_io->write_byte(AVR8_IO_PORTK, data); + m_r[AVR8_REGIDX_PORTK] = data; + break; + + case AVR8_REGIDX_PORTL: + m_io->write_byte(AVR8_IO_PORTL, data); + m_r[AVR8_REGIDX_PORTL] = data; + break; + + case AVR8_REGIDX_DDRA: + case AVR8_REGIDX_DDRB: + case AVR8_REGIDX_DDRC: + case AVR8_REGIDX_DDRD: + case AVR8_REGIDX_SREG: + case AVR8_REGIDX_RAMPZ: + case AVR8_REGIDX_SPH: + case AVR8_REGIDX_SPL: + m_r[offset] = data; + break; + + case AVR8_REGIDX_TCCR0B: + verboselog(m_pc, 0, "AVR8: TCCR0B = %02x\n", data ); + changed_tccr0b(data); + break; + + case AVR8_REGIDX_TCCR0A: + verboselog(m_pc, 0, "AVR8: TCCR0A = %02x\n", data ); + changed_tccr0a(data); + break; + + case AVR8_REGIDX_OCR0A: + verboselog(m_pc, 0, "AVR8: OCR0A = %02x\n", data); + update_ocr0(AVR8_OCR0A, AVR8_REG_A); + break; + + case AVR8_REGIDX_OCR0B: + verboselog(m_pc, 0, "AVR8: OCR0B = %02x\n", data ); + update_ocr0(AVR8_OCR0B, AVR8_REG_B); + break; + + case AVR8_REGIDX_TIFR0: + verboselog(m_pc, 0, "AVR8: TIFR0 = %02x\n", data ); + m_r[AVR8_REGIDX_TIFR0] &= ~(data & AVR8_TIFR0_MASK); + update_interrupt(AVR8_INTIDX_OCF0A); + update_interrupt(AVR8_INTIDX_OCF0B); + update_interrupt(AVR8_INTIDX_TOV0); + break; + + case AVR8_REGIDX_TCNT0: + AVR8_TCNT0 = data; + break; + + case AVR8_REGIDX_TIFR1: + verboselog(m_pc, 0, "AVR8: TIFR1 = %02x\n", data ); + m_r[AVR8_REGIDX_TIFR1] &= ~(data & AVR8_TIFR1_MASK); + update_interrupt(AVR8_INTIDX_ICF1); + update_interrupt(AVR8_INTIDX_OCF1A); + update_interrupt(AVR8_INTIDX_OCF1B); + update_interrupt(AVR8_INTIDX_TOV1); + break; + + case AVR8_REGIDX_TIFR2: + verboselog(m_pc, 0, "AVR8: TIFR2 = %02x\n", data ); + m_r[AVR8_REGIDX_TIFR2] &= ~(data & AVR8_TIFR2_MASK); + update_interrupt(AVR8_INTIDX_OCF2A); + update_interrupt(AVR8_INTIDX_OCF2B); + update_interrupt(AVR8_INTIDX_TOV2); + break; + + case AVR8_REGIDX_GTCCR: + if (data & AVR8_GTCCR_PSRASY_MASK) + { + data &= ~AVR8_GTCCR_PSRASY_MASK; + m_timer_prescale_count[2] = 0; + } + break; + +// EEPROM registers: + case AVR8_REGIDX_EEARL: + case AVR8_REGIDX_EEARH: + case AVR8_REGIDX_EEDR: + m_r[offset] = data; + break; + + case AVR8_REGIDX_EECR: + m_r[offset] = data; + + if (data & AVR8_EECR_EERE_MASK) + { + UINT16 addr = (m_r[AVR8_REGIDX_EEARH] & AVR8_EEARH_MASK) << 8; + addr |= m_r[AVR8_REGIDX_EEARL]; + m_r[AVR8_REGIDX_EEDR] = m_eeprom[addr]; + if (VERBOSE_LEVEL) printf("EEPROM read @ 0x%04x data = 0x%02x\n", addr, m_eeprom[addr]); + } + if ((data & AVR8_EECR_EEPE_MASK) && (data & AVR8_EECR_EEMPE_MASK)) + { + UINT16 addr = (m_r[AVR8_REGIDX_EEARH] & AVR8_EEARH_MASK) << 8; + addr |= m_r[AVR8_REGIDX_EEARL]; + m_eeprom[addr] = m_r[AVR8_REGIDX_EEDR]; + if (VERBOSE_LEVEL) printf("EEPROM write @ 0x%04x data = 0x%02x ('%c')\n", addr, m_eeprom[addr], m_eeprom[addr]); + + m_r[offset] = data & ~AVR8_EECR_EEPE_MASK; //indicates that we've finished writing a value to the EEPROM. + //TODO: shouldn't this happen only after a certain dalay? + } + break; + + case AVR8_REGIDX_GPIOR0: + verboselog(m_pc, 1, "AVR8: GPIOR0 Write: %02x\n", data); + m_r[AVR8_REGIDX_GPIOR0] = data; + break; + + case AVR8_REGIDX_GPIOR1: + case AVR8_REGIDX_GPIOR2: + m_r[offset] = data; + break; + + case AVR8_REGIDX_SPSR: + change_spsr(data); + break; + + case AVR8_REGIDX_SPCR: + change_spcr(data); + break; + + case AVR8_REGIDX_SPDR: + { + m_r[AVR8_REGIDX_SPDR] = data; + m_spi_active = true; + m_spi_prescale_countdown = 7; + m_spi_prescale_count = 0; + break; + } + + case AVR8_REGIDX_WDTCSR: + verboselog(m_pc, 0, "AVR8: WDTCSR = %02x\n", data ); + //TODO: changed_wdtcsr(data); + break; + + case AVR8_REGIDX_CLKPR: + verboselog(m_pc, 0, "AVR8: CLKPR = %02x\n", data ); + //TODO: changed_clkpr(data); + break; + + case AVR8_REGIDX_PRR0: + verboselog(m_pc, 0, "AVR8: PRR0 = %02x\n", data ); + //TODO: changed_prr0(data); + break; + + case AVR8_REGIDX_PRR1: + verboselog(m_pc, 0, "AVR8: PRR1 = %02x\n", data ); + //TODO: changed_prr1(data); + break; + + case AVR8_REGIDX_OSCCAL: + verboselog(m_pc, 0, "AVR8: OSCCAL = %02x\n", data ); + //TODO: changed_osccal(data); + break; + + case AVR8_REGIDX_PCICR: + verboselog(m_pc, 0, "AVR8: PCICR = %02x\n", data ); + //TODO: changed_pcicr(data); + break; + + case AVR8_REGIDX_EICRA: + verboselog(m_pc, 0, "AVR8: EICRA = %02x\n", data ); + //TODO: changed_eicra(data); + break; + + case AVR8_REGIDX_EICRB: + verboselog(m_pc, 0, "AVR8: EICRB = %02x\n", data ); + //TODO: changed_eicrb(data); + break; + + case AVR8_REGIDX_PCMSK0: + verboselog(m_pc, 0, "AVR8: PCMSK0 = %02x\n", data ); + //TODO: changed_pcmsk0(data); + break; + + case AVR8_REGIDX_PCMSK1: + verboselog(m_pc, 0, "AVR8: PCMSK1 = %02x\n", data ); + //TODO: changed_pcmsk1(data); + break; + + case AVR8_REGIDX_PCMSK2: + verboselog(m_pc, 0, "AVR8: PCMSK2 = %02x\n", data ); + //TODO: changed_pcmsk2(data); + break; + + case AVR8_REGIDX_TIMSK0: + verboselog(m_pc, 0, "AVR8: TIMSK0 = %02x\n", data ); + m_r[AVR8_REGIDX_TIMSK0] = data; + update_interrupt(AVR8_INTIDX_OCF0A); + update_interrupt(AVR8_INTIDX_OCF0B); + update_interrupt(AVR8_INTIDX_TOV0); + break; + + case AVR8_REGIDX_TIMSK1: + verboselog(m_pc, 0, "AVR8: TIMSK1 = %02x\n", data ); + m_r[AVR8_REGIDX_TIMSK1] = data; + update_interrupt(AVR8_INTIDX_ICF1); + update_interrupt(AVR8_INTIDX_OCF1A); + update_interrupt(AVR8_INTIDX_OCF1B); + update_interrupt(AVR8_INTIDX_TOV1); + break; + + case AVR8_REGIDX_TIMSK2: + verboselog(m_pc, 0, "AVR8: TIMSK2 = %02x\n", data ); + m_r[AVR8_REGIDX_TIMSK2] = data; + update_interrupt(AVR8_INTIDX_OCF2A); + update_interrupt(AVR8_INTIDX_OCF2B); + update_interrupt(AVR8_INTIDX_TOV2); + break; + + case AVR8_REGIDX_TIMSK3: + verboselog(m_pc, 0, "AVR8: TIMSK3 = %02x\n", data ); + m_r[AVR8_REGIDX_TIMSK3] = data; + update_interrupt(AVR8_INTIDX_OCF3A); + update_interrupt(AVR8_INTIDX_OCF3B); + update_interrupt(AVR8_INTIDX_TOV3); + break; + + case AVR8_REGIDX_TIMSK4: + verboselog(m_pc, 0, "AVR8: TIMSK4 = %02x\n", data ); + m_r[AVR8_REGIDX_TIMSK4] = data; + update_interrupt(AVR8_INTIDX_OCF4A); + update_interrupt(AVR8_INTIDX_OCF4B); + update_interrupt(AVR8_INTIDX_TOV4); + break; + + case AVR8_REGIDX_TIMSK5: + verboselog(m_pc, 0, "AVR8: TIMSK5 = %02x\n", data ); + m_r[AVR8_REGIDX_TIMSK5] = data; + update_interrupt(AVR8_INTIDX_OCF5A); + update_interrupt(AVR8_INTIDX_OCF5B); + update_interrupt(AVR8_INTIDX_TOV5); + break; + + case AVR8_REGIDX_XMCRA: + verboselog(m_pc, 0, "AVR8: XMCRA = %02x\n", data ); + //TODO: changed_xmcra(data); + break; + + case AVR8_REGIDX_XMCRB: + verboselog(m_pc, 0, "AVR8: XMCRB = %02x\n", data ); + //TODO: changed_xmcrb(data); + break; + + case AVR8_REGIDX_ADCL: + verboselog(m_pc, 0, "AVR8: ADCL = %02x\n", data ); + //TODO: changed_adcl(data); + break; + + case AVR8_REGIDX_ADCH: + verboselog(m_pc, 0, "AVR8: ADCH = %02x\n", data ); + //TODO: changed_adch(data); + break; + + case AVR8_REGIDX_ADCSRA: + verboselog(m_pc, 0, "AVR8: ADCSRA = %02x\n", data ); + //TODO: changed_adcsra(data); + break; + + case AVR8_REGIDX_ADCSRB: + verboselog(m_pc, 0, "AVR8: ADCSRB = %02x\n", data ); + //TODO: changed_adcsrb(data); + break; + + case AVR8_REGIDX_ADMUX: + verboselog(m_pc, 0, "AVR8: ADMUX = %02x\n", data ); + //TODO: changed_admux(data); + break; + + case AVR8_REGIDX_DIDR0: + verboselog(m_pc, 0, "AVR8: DIDR0 = %02x\n", data ); + //TODO: changed_didr0(data); + break; + + case AVR8_REGIDX_DIDR1: + verboselog(m_pc, 0, "AVR8: DIDR1 = %02x\n", data ); + //TODO: changed_didr1(data); + break; + + case AVR8_REGIDX_DIDR2: + verboselog(m_pc, 0, "AVR8: DIDR2 = %02x\n", data ); + //TODO: changed_didr2(data); + break; + + case AVR8_REGIDX_TCCR1A: + verboselog(m_pc, 0, "AVR8: TCCR1A = %02x\n", data ); + changed_tccr1a(data); + break; + + case AVR8_REGIDX_TCCR1B: + verboselog(m_pc, 0, "AVR8: TCCR1B = %02x\n", data ); + changed_tccr1b(data); + break; + + case AVR8_REGIDX_TCCR1C: + verboselog(m_pc, 0, "AVR8: TCCR1C = %02x\n", data ); + //TODO: changed_tccr1c(data); + break; + + case AVR8_REGIDX_TCNT1L: + AVR8_TCNT1L = data; + break; + + case AVR8_REGIDX_TCNT1H: + AVR8_TCNT1H = data; + break; + + case AVR8_REGIDX_ICR1L: + AVR8_ICR1L = data; + break; + + case AVR8_REGIDX_ICR1H: + AVR8_ICR1H = data; + break; + + case AVR8_REGIDX_OCR1AL: + verboselog(m_pc, 0, "AVR8: OCR1AL = %02x\n", data ); + update_ocr1((AVR8_OCR1A & 0xff00) | data, AVR8_REG_A); + break; + + case AVR8_REGIDX_OCR1AH: + verboselog(m_pc, 0, "AVR8: OCR1AH = %02x\n", data ); + update_ocr1((AVR8_OCR1A & 0x00ff) | (data << 8), AVR8_REG_A); + break; + + case AVR8_REGIDX_OCR1BL: + verboselog(m_pc, 0, "AVR8: OCR1BL = %02x\n", data ); + update_ocr1((AVR8_OCR1B & 0xff00) | data, AVR8_REG_B); + break; + + case AVR8_REGIDX_OCR1BH: + verboselog(m_pc, 0, "AVR8: OCR1BH = %02x\n", data ); + update_ocr1((AVR8_OCR1B & 0x00ff) | (data << 8), AVR8_REG_B); + break; + + case AVR8_REGIDX_OCR1CL: + verboselog(m_pc, 0, "AVR8: OCR1CL = %02x\n", data ); + update_ocr1((AVR8_OCR1C & 0xff00) | data, AVR8_REG_C); + break; + + case AVR8_REGIDX_OCR1CH: + verboselog(m_pc, 0, "AVR8: OCR1CH = %02x\n", data ); + update_ocr1((AVR8_OCR1C & 0x00ff) | (data << 8), AVR8_REG_C); + break; + + case AVR8_REGIDX_TCCR2A: + verboselog(m_pc, 0, "AVR8: TCCR2A = %02x\n", data ); + changed_tccr2a(data); + break; + + case AVR8_REGIDX_TCCR2B: + verboselog(m_pc, 0, "AVR8: TCCR2B = %02x\n", data ); + changed_tccr2b(data); + break; + + case AVR8_REGIDX_TCNT2: + AVR8_TCNT2 = data; + break; + + case AVR8_REGIDX_OCR2A: + update_ocr2(data, AVR8_REG_A); + break; + + case AVR8_REGIDX_OCR2B: + update_ocr2(data, AVR8_REG_B); + break; + + case AVR8_REGIDX_TCCR3A: + verboselog(m_pc, 0, "AVR8: TCCR3A = %02x\n", data ); + changed_tccr3a(data); + break; + + case AVR8_REGIDX_TCCR3B: + verboselog(m_pc, 0, "AVR8: TCCR3B = %02x\n", data ); + changed_tccr3b(data); + break; + + case AVR8_REGIDX_TCCR3C: + verboselog(m_pc, 0, "AVR8: TCCR3C = %02x\n", data ); + changed_tccr3c(data); + break; + + case AVR8_REGIDX_TCNT3L: + AVR8_TCNT3L = data; + break; + + case AVR8_REGIDX_TCNT3H: + AVR8_TCNT3H = data; + break; + + case AVR8_REGIDX_ICR3L: + AVR8_ICR3L = data; + break; + + case AVR8_REGIDX_ICR3H: + AVR8_ICR3H = data; + break; + + case AVR8_REGIDX_OCR3AL: + AVR8_OCR3AL = data; + break; + + case AVR8_REGIDX_OCR3AH: + AVR8_OCR3AH = data; + break; + + case AVR8_REGIDX_OCR3BL: + AVR8_OCR3BL = data; + break; + + case AVR8_REGIDX_OCR3BH: + AVR8_OCR3BH = data; + break; + + case AVR8_REGIDX_OCR3CL: + AVR8_OCR3CL = data; + break; + + case AVR8_REGIDX_OCR3CH: + AVR8_OCR3CH = data; + break; + + case AVR8_REGIDX_TCCR4A: + verboselog(m_pc, 0, "AVR8: TCCR4A = %02x\n", data ); + changed_tccr4a(data); + break; + + case AVR8_REGIDX_TCCR4B: + verboselog(m_pc, 0, "AVR8: TCCR4B = %02x\n", data ); + changed_tccr4b(data); + break; + + case AVR8_REGIDX_TCCR4C: + verboselog(m_pc, 0, "AVR8: TCCR4C = %02x\n", data ); + changed_tccr4c(data); + break; + + case AVR8_REGIDX_TCNT4L: + AVR8_TCNT4L = data; + break; + + case AVR8_REGIDX_TCNT4H: + AVR8_TCNT4H = data; + break; + + case AVR8_REGIDX_ICR4L: + AVR8_ICR4L = data; + break; + + case AVR8_REGIDX_ICR4H: + AVR8_ICR4H = data; + break; + + case AVR8_REGIDX_OCR4AL: + AVR8_OCR4AL = data; + break; + + case AVR8_REGIDX_OCR4AH: + AVR8_OCR4AH = data; + break; + + case AVR8_REGIDX_OCR4BL: + AVR8_OCR4BL = data; + break; + + case AVR8_REGIDX_OCR4BH: + AVR8_OCR4BH = data; + break; + + case AVR8_REGIDX_OCR4CL: + AVR8_OCR4CL = data; + break; + + case AVR8_REGIDX_OCR4CH: + AVR8_OCR4CH = data; + break; + + case AVR8_REGIDX_TCCR5A: + verboselog(m_pc, 0, "AVR8: TCCR5A = %02x\n", data ); + changed_tccr5a(data); + break; + + case AVR8_REGIDX_TCCR5B: + verboselog(m_pc, 0, "AVR8: TCCR5B = %02x\n", data ); + changed_tccr5b(data); + break; + + case AVR8_REGIDX_ASSR: + verboselog(m_pc, 0, "AVR8: ASSR = %02x\n", data ); + //TODO: changed_assr(data); + break; + + case AVR8_REGIDX_TWBR: + verboselog(m_pc, 0, "AVR8: TWBR = %02x\n", data ); + //TODO: changed_twbr(data); + break; + + case AVR8_REGIDX_TWSR: + verboselog(m_pc, 0, "AVR8: TWSR = %02x\n", data ); + //TODO: changed_twsr(data); + break; + + case AVR8_REGIDX_TWAR: + verboselog(m_pc, 0, "AVR8: TWAR = %02x\n", data ); + //TODO: changed_twar(data); + break; + + case AVR8_REGIDX_TWDR: + verboselog(m_pc, 0, "AVR8: TWDR = %02x\n", data ); + //TODO: changed_twdr(data); + break; + + case AVR8_REGIDX_TWCR: + verboselog(m_pc, 0, "AVR8: TWCR = %02x\n", data ); + //TODO: changed_twcr(data); + m_r[AVR8_REGIDX_TWCR] = data; + break; + + case AVR8_REGIDX_TWAMR: + verboselog(m_pc, 0, "AVR8: TWAMR = %02x\n", data ); + //TODO: changed_twamr(data); + break; + + case AVR8_REGIDX_UCSR0A: + verboselog(m_pc, 0, "AVR8: UCSR0A = %02x\n", data ); + //TODO: changed_ucsr0a(data); + break; + + case AVR8_REGIDX_UCSR0B: + verboselog(m_pc, 0, "AVR8: UCSR0B = %02x\n", data ); + //TODO: changed_ucsr0b(data); + break; + + case AVR8_REGIDX_UCSR0C: + verboselog(m_pc, 0, "AVR8: UCSR0C = %02x\n", data ); + //TODO: changed_ucsr0c(data); + break; +/* + case AVR8_REGIDX_: + verboselog(m_pc, 0, "AVR8: = %02x\n", data ); + //TODO: changed_(data); + break; +*/ + default: + verboselog(m_pc, 0, "AVR8: Unknown Register Write: %03x = %02x\n", offset, data); + break; + } +} + +READ8_MEMBER( avr8_device::regs_r ) +{ +// printf("--- READ offset %04x ---\n", offset); + + switch( offset ) + { + case AVR8_REGIDX_R0: + case AVR8_REGIDX_R1: + case AVR8_REGIDX_R2: + case AVR8_REGIDX_R3: + case AVR8_REGIDX_R4: + case AVR8_REGIDX_R5: + case AVR8_REGIDX_R6: + case AVR8_REGIDX_R7: + case AVR8_REGIDX_R8: + case AVR8_REGIDX_R9: + case AVR8_REGIDX_R10: + case AVR8_REGIDX_R11: + case AVR8_REGIDX_R12: + case AVR8_REGIDX_R13: + case AVR8_REGIDX_R14: + case AVR8_REGIDX_R15: + case AVR8_REGIDX_R16: + case AVR8_REGIDX_R17: + case AVR8_REGIDX_R18: + case AVR8_REGIDX_R19: + case AVR8_REGIDX_R20: + case AVR8_REGIDX_R21: + case AVR8_REGIDX_R22: + case AVR8_REGIDX_R23: + case AVR8_REGIDX_R24: + case AVR8_REGIDX_R25: + case AVR8_REGIDX_R26: + case AVR8_REGIDX_R27: + case AVR8_REGIDX_R28: + case AVR8_REGIDX_R29: + case AVR8_REGIDX_R30: + case AVR8_REGIDX_R31: + return m_r[offset]; + + case AVR8_REGIDX_PINA: + // TODO: consider the DDRA + return m_io->read_byte(AVR8_REG_A); + + case AVR8_REGIDX_PINB: + // TODO: consider the DDRB + return m_io->read_byte(AVR8_REG_B); + + case AVR8_REGIDX_PINC: + // TODO: consider the DDRC + return m_io->read_byte(AVR8_REG_C); + + case AVR8_REGIDX_PIND: + // TODO: consider the DDRD + return m_io->read_byte(AVR8_REG_D); + + case AVR8_REGIDX_PINE: + // TODO: consider the DDRE + return m_io->read_byte(AVR8_REG_E); + + case AVR8_REGIDX_PINF: + // TODO: consider the DDRF + return m_io->read_byte(AVR8_REG_F); + + case AVR8_REGIDX_PING: + // TODO: consider the DDRG + return m_io->read_byte(AVR8_REG_G); + + case AVR8_REGIDX_PINH: + // TODO: consider the DDRH + return m_io->read_byte(AVR8_REG_H); + + case AVR8_REGIDX_PINJ: + // TODO: consider the DDRJ + return m_io->read_byte(AVR8_REG_J); + + case AVR8_REGIDX_PINK: + // TODO: consider the DDRK + return m_io->read_byte(AVR8_REG_K); + + case AVR8_REGIDX_PINL: + // TODO: consider the DDRL + return m_io->read_byte(AVR8_REG_L); + + case AVR8_REGIDX_PORTA: + case AVR8_REGIDX_PORTB: + case AVR8_REGIDX_PORTC: + case AVR8_REGIDX_PORTD: + case AVR8_REGIDX_PORTE: + case AVR8_REGIDX_PORTF: + case AVR8_REGIDX_PORTG: + case AVR8_REGIDX_PORTH: + case AVR8_REGIDX_PORTJ: + case AVR8_REGIDX_PORTK: + case AVR8_REGIDX_PORTL: + return m_r[offset]; + + case AVR8_REGIDX_DDRA: + case AVR8_REGIDX_DDRB: + case AVR8_REGIDX_DDRC: + case AVR8_REGIDX_DDRD: + case AVR8_REGIDX_DDRE: + case AVR8_REGIDX_DDRF: + case AVR8_REGIDX_DDRG: + case AVR8_REGIDX_DDRH: + case AVR8_REGIDX_DDRJ: + case AVR8_REGIDX_DDRK: + case AVR8_REGIDX_DDRL: + return m_r[offset]; + +// EEPROM registers: + case AVR8_REGIDX_EECR: + case AVR8_REGIDX_EEDR: + return m_r[offset]; + +/* Misc. registers. + TODO: implement all registers reads */ + + case AVR8_REGIDX_GPIOR0: + case AVR8_REGIDX_GPIOR1: + case AVR8_REGIDX_GPIOR2: +// case AVR8_REGIDX_UCSR0B:/*TODO: needed for Replicator 1 */ + case AVR8_REGIDX_SPDR: /*TODO: needed for Replicator 1 */ + case AVR8_REGIDX_SPSR: /*TODO: needed for Replicator 1 */ +// case AVR8_REGIDX_ADCSRA: /*TODO: needed for Replicator 1 */ +// case AVR8_REGIDX_ADCSRB: /*TODO: needed for Replicator 1 */ + case AVR8_REGIDX_SPL: + case AVR8_REGIDX_SPH: + case AVR8_REGIDX_SREG: + case AVR8_REGIDX_TIMSK0: + case AVR8_REGIDX_TIMSK1: + case AVR8_REGIDX_TIMSK2: +// case AVR8_REGIDX_TIMSK3: /*TODO: needed for Replicator 1 */ + case AVR8_REGIDX_TIMSK4: + case AVR8_REGIDX_TIMSK5: + return m_r[offset]; + +/* Two-wire registers: */ + case AVR8_REGIDX_TWCR: + /*TODO: needed for Replicator 1 + BLOQUEIA PROGRESSO DA EXECU??O DO FIRMWARE no endere?o 105EC*/ + return m_r[offset]; + + case AVR8_REGIDX_TWSR: + //quick hack: by returning a value != 0x08 we induce an error state that makes the object code jump out of the wait loop and continue execution failing the 2-wire write operation. + //TODO: implement-me! + return 0x00; /*TODO: needed for Replicator 1 */ + + + case AVR8_REGIDX_TCNT1L: + case AVR8_REGIDX_TCNT1H: + case AVR8_REGIDX_TCNT2: + case AVR8_REGIDX_UCSR0A: + return m_r[offset]; + + default: + printf("[%08X] AVR8: Unknown Register Read: 0x%03X\n", m_shifted_pc, offset); +// debugger_break(machine()); + return 0; + } +} + + +//************************************************************************** +// CORE EXECUTION LOOP +//************************************************************************** + +//------------------------------------------------- +// execute_min_cycles - return minimum number of +// cycles it takes for one instruction to execute +//------------------------------------------------- + +UINT32 avr8_device::execute_min_cycles() const +{ + return 1; +} + + +//------------------------------------------------- +// execute_max_cycles - return maximum number of +// cycles it takes for one instruction to execute +//------------------------------------------------- + +UINT32 avr8_device::execute_max_cycles() const +{ + return 4; +} + + +//------------------------------------------------- +// execute_input_lines - return the number of +// input/interrupt lines +//------------------------------------------------- + +UINT32 avr8_device::execute_input_lines() const +{ + return 0; +} + + +void avr8_device::execute_set_input(int inputnum, int state) +{ +} + + +//------------------------------------------------- +// execute_run - execute a timeslice's worth of +// opcodes +//------------------------------------------------- + +void avr8_device::execute_run() +{ + UINT32 op = 0; + INT32 offs = 0; + UINT8 rd = 0; + UINT8 rr = 0; + UINT8 res = 0; + UINT16 pd = 0; + UINT32 pd32 = 0; + INT16 sd = 0; + INT32 opcycles = 1; + + while (m_icount > 0) + { + opcycles = 1; + + m_pc &= m_addr_mask; + m_shifted_pc &= (m_addr_mask << 1) | 1; + + debugger_instruction_hook(this, m_shifted_pc); + + op = (UINT32)m_program->read_word(m_shifted_pc); + + switch(op & 0xf000) + { + case 0x0000: + switch(op & 0x0f00) + { + case 0x0000: // NOP + break; + case 0x0100: // MOVW Rd+1:Rd,Rr+1:Rd + m_r[(RD4(op) << 1) + 1] = m_r[(RR4(op) << 1) + 1]; + m_r[RD4(op) << 1] = m_r[RR4(op) << 1]; + break; + case 0x0200: // MULS Rd,Rr + sd = (INT8)m_r[16 + RD4(op)] * (INT8)m_r[16 + RR4(op)]; + m_r[1] = (sd >> 8) & 0x00ff; + m_r[0] = sd & 0x00ff; + SREG_W(AVR8_SREG_C, (sd & 0x8000) ? 1 : 0); + SREG_W(AVR8_SREG_Z, (sd == 0) ? 1 : 0); + opcycles = 2; + break; + case 0x0300: // Multiplicatn + switch(MULCONST2(op)) + { + case 0x0000: // MULSU Rd,Rr + sd = (INT8)m_r[16 + RD3(op)] * (UINT8)m_r[16 + RR3(op)]; + m_r[1] = (sd >> 8) & 0x00ff; + m_r[0] = sd & 0x00ff; + SREG_W(AVR8_SREG_C, (sd & 0x8000) ? 1 : 0); + SREG_W(AVR8_SREG_Z, (sd == 0) ? 1 : 0); + opcycles = 2; + break; + case 0x0001: // FMUL Rd,Rr + sd = (UINT8)m_r[16 + RD3(op)] * (UINT8)m_r[16 + RR3(op)]; + sd <<= 1; + m_r[1] = (sd >> 8) & 0x00ff; + m_r[0] = sd & 0x00ff; + SREG_W(AVR8_SREG_C, (sd & 0x8000) ? 1 : 0); + SREG_W(AVR8_SREG_Z, (sd == 0) ? 1 : 0); + opcycles = 2; + break; + case 0x0002: // FMULS Rd,Rr + sd = (INT8)m_r[16 + RD3(op)] * (INT8)m_r[16 + RR3(op)]; + sd <<= 1; + m_r[1] = (sd >> 8) & 0x00ff; + m_r[0] = sd & 0x00ff; + SREG_W(AVR8_SREG_C, (sd & 0x8000) ? 1 : 0); + SREG_W(AVR8_SREG_Z, (sd == 0) ? 1 : 0); + opcycles = 2; + break; + case 0x0003: // FMULSU Rd,Rr + sd = (INT8)m_r[16 + RD3(op)] * (UINT8)m_r[16 + RR3(op)]; + sd <<= 1; + m_r[1] = (sd >> 8) & 0x00ff; + m_r[0] = sd & 0x00ff; + SREG_W(AVR8_SREG_C, (sd & 0x8000) ? 1 : 0); + SREG_W(AVR8_SREG_Z, (sd == 0) ? 1 : 0); + opcycles = 2; + break; + } + break; + case 0x0400: + case 0x0500: + case 0x0600: + case 0x0700: // CPC Rd,Rr + rd = m_r[RD5(op)]; + rr = m_r[RR5(op)]; + res = rd - (rr + SREG_R(AVR8_SREG_C)); + SREG_W(AVR8_SREG_H, (NOT(BIT(rd,3)) & BIT(rr,3)) | (BIT(rr,3) & BIT(res,3)) | (BIT(res,3) & NOT(BIT(rd,3)))); + SREG_W(AVR8_SREG_V, (BIT(rd,7) & NOT(BIT(rr,7)) & NOT(BIT(res,7))) | (NOT(BIT(rd,7)) & BIT(rr,7) & BIT(res,7))); + SREG_W(AVR8_SREG_N, BIT(res,7)); + SREG_W(AVR8_SREG_S, SREG_R(AVR8_SREG_N) ^ SREG_R(AVR8_SREG_V)); + SREG_W(AVR8_SREG_Z, (res == 0) ? SREG_R(AVR8_SREG_Z) : 0); + SREG_W(AVR8_SREG_C, (NOT(BIT(rd,7)) & BIT(rr,7)) | (BIT(rr,7) & BIT(res,7)) | (BIT(res,7) & NOT(BIT(rd,7)))); + break; + case 0x0800: + case 0x0900: + case 0x0a00: + case 0x0b00: // SBC Rd,Rr + rd = m_r[RD5(op)]; + rr = m_r[RR5(op)]; + res = rd - (rr + SREG_R(AVR8_SREG_C)); + m_r[RD5(op)] = res; + SREG_W(AVR8_SREG_H, (NOT(BIT(rd,3)) & BIT(rr,3)) | (BIT(rr,3) & BIT(res,3)) | (BIT(res,3) & NOT(BIT(rd,3)))); + SREG_W(AVR8_SREG_V, (BIT(rd,7) & NOT(BIT(rr,7)) & NOT(BIT(res,7))) | (NOT(BIT(rd,7)) & BIT(rr,7) & BIT(res,7))); + SREG_W(AVR8_SREG_N, BIT(res,7)); + SREG_W(AVR8_SREG_S, SREG_R(AVR8_SREG_N) ^ SREG_R(AVR8_SREG_V)); + SREG_W(AVR8_SREG_Z, (res == 0) ? SREG_R(AVR8_SREG_Z) : 0); + SREG_W(AVR8_SREG_C, (NOT(BIT(rd,7)) & BIT(rr,7)) | (BIT(rr,7) & BIT(res,7)) | (BIT(res,7) & NOT(BIT(rd,7)))); + break; + case 0x0c00: + case 0x0d00: + case 0x0e00: + case 0x0f00: // ADD Rd,Rr + rd = m_r[RD5(op)]; + rr = m_r[RR5(op)]; + res = rd + rr; + m_r[RD5(op)] = res; + SREG_W(AVR8_SREG_H, (BIT(rd,3) & BIT(rr,3)) | (BIT(rr,3) & NOT(BIT(res,3))) | (NOT(BIT(res,3)) & BIT(rd,3))); + SREG_W(AVR8_SREG_V, (BIT(rd,7) & BIT(rr,7) & NOT(BIT(res,7))) | (NOT(BIT(rd,7)) & NOT(BIT(rr,7)) & BIT(res,7))); + SREG_W(AVR8_SREG_N, BIT(res,7)); + SREG_W(AVR8_SREG_S, SREG_R(AVR8_SREG_N) ^ SREG_R(AVR8_SREG_V)); + SREG_W(AVR8_SREG_Z, (res == 0) ? 1 : 0); + SREG_W(AVR8_SREG_C, (BIT(rd,7) & BIT(rr,7)) | (BIT(rr,7) & NOT(BIT(res,7))) | (NOT(BIT(res,7)) & BIT(rd,7))); + break; + } + break; + case 0x1000: + switch(op & 0x0c00) + { + case 0x0000: // CPSE Rd,Rr + rd = m_r[RD5(op)]; + rr = m_r[RR5(op)]; + if (rd == rr) + { + op = (UINT32)m_program->read_word(m_shifted_pc + 2); + opcycles += is_long_opcode(op) ? 2 : 1; + m_pc += is_long_opcode(op) ? 2 : 1; + } + break; + case 0x0400: // CP Rd,Rr + rd = m_r[RD5(op)]; + rr = m_r[RR5(op)]; + res = rd - rr; + SREG_W(AVR8_SREG_H, (NOT(BIT(rd,3)) & BIT(rr,3)) | (BIT(rr,3) & BIT(res,3)) | (BIT(res,3) & NOT(BIT(rd,3)))); + SREG_W(AVR8_SREG_V, (BIT(rd,7) & NOT(BIT(rr,7)) & NOT(BIT(res,7))) | (NOT(BIT(rd,7)) & BIT(rr,7) & BIT(res,7))); + SREG_W(AVR8_SREG_N, BIT(res,7)); + SREG_W(AVR8_SREG_S, SREG_R(AVR8_SREG_N) ^ SREG_R(AVR8_SREG_V)); + SREG_W(AVR8_SREG_Z, (res == 0) ? 1 : 0); + SREG_W(AVR8_SREG_C, (NOT(BIT(rd,7)) & BIT(rr,7)) | (BIT(rr,7) & BIT(res,7)) | (BIT(res,7) & NOT(BIT(rd,7)))); + break; + case 0x0800: // SUB Rd,Rr + rd = m_r[RD5(op)]; + rr = m_r[RR5(op)]; + res = rd - rr; + m_r[RD5(op)] = res; + SREG_W(AVR8_SREG_H, (NOT(BIT(rd,3)) & BIT(rr,3)) | (BIT(rr,3) & BIT(res,3)) | (BIT(res,3) & NOT(BIT(rd,3)))); + SREG_W(AVR8_SREG_V, (BIT(rd,7) & NOT(BIT(rr,7)) & NOT(BIT(res,7))) | (NOT(BIT(rd,7)) & BIT(rr,7) & BIT(res,7))); + SREG_W(AVR8_SREG_N, BIT(res,7)); + SREG_W(AVR8_SREG_S, SREG_R(AVR8_SREG_N) ^ SREG_R(AVR8_SREG_V)); + SREG_W(AVR8_SREG_Z, (res == 0) ? 1 : 0); + SREG_W(AVR8_SREG_C, (NOT(BIT(rd,7)) & BIT(rr,7)) | (BIT(rr,7) & BIT(res,7)) | (BIT(res,7) & NOT(BIT(rd,7)))); + break; + case 0x0c00: // ADC Rd,Rr + rd = m_r[RD5(op)]; + rr = m_r[RR5(op)]; + res = rd + rr + SREG_R(AVR8_SREG_C); + m_r[RD5(op)] = res; + SREG_W(AVR8_SREG_H, (BIT(rd,3) & BIT(rr,3)) | (BIT(rr,3) & NOT(BIT(res,3))) | (NOT(BIT(res,3)) & BIT(rd,3))); + SREG_W(AVR8_SREG_V, (BIT(rd,7) & BIT(rr,7) & NOT(BIT(res,7))) | (NOT(BIT(rd,7)) & NOT(BIT(rr,7)) & BIT(res,7))); + SREG_W(AVR8_SREG_N, BIT(res,7)); + SREG_W(AVR8_SREG_S, SREG_R(AVR8_SREG_N) ^ SREG_R(AVR8_SREG_V)); + SREG_W(AVR8_SREG_Z, (res == 0) ? 1 : 0); + SREG_W(AVR8_SREG_C, (BIT(rd,7) & BIT(rr,7)) | (BIT(rr,7) & NOT(BIT(res,7))) | (NOT(BIT(res,7)) & BIT(rd,7))); + break; + } + break; + case 0x2000: + switch(op & 0x0c00) + { + case 0x0000: // AND Rd,Rr + rd = m_r[RD5(op)]; + rr = m_r[RR5(op)]; + rd &= rr; + SREG_W(AVR8_SREG_V, 0); + SREG_W(AVR8_SREG_N, BIT(rd,7)); + SREG_W(AVR8_SREG_S, SREG_R(AVR8_SREG_N) ^ SREG_R(AVR8_SREG_V)); + SREG_W(AVR8_SREG_Z, (rd == 0) ? 1 : 0); + m_r[RD5(op)] = rd; + break; + case 0x0400: // EOR Rd,Rr + rd = m_r[RD5(op)]; + rr = m_r[RR5(op)]; + rd ^= rr; + SREG_W(AVR8_SREG_V, 0); + SREG_W(AVR8_SREG_N, BIT(rd,7)); + SREG_W(AVR8_SREG_S, SREG_R(AVR8_SREG_N) ^ SREG_R(AVR8_SREG_V)); + SREG_W(AVR8_SREG_Z, (rd == 0) ? 1 : 0); + m_r[RD5(op)] = rd; + break; + case 0x0800: // OR Rd,Rr + rd = m_r[RD5(op)]; + rr = m_r[RR5(op)]; + rd |= rr; + SREG_W(AVR8_SREG_V, 0); + SREG_W(AVR8_SREG_N, BIT(rd,7)); + SREG_W(AVR8_SREG_S, SREG_R(AVR8_SREG_N) ^ SREG_R(AVR8_SREG_V)); + SREG_W(AVR8_SREG_Z, (rd == 0) ? 1 : 0); + m_r[RD5(op)] = rd; + break; + case 0x0c00: // MOV Rd,Rr + m_r[RD5(op)] = m_r[RR5(op)]; + break; + } + break; + case 0x3000: // CPI Rd,K + rd = m_r[16 + RD4(op)]; + rr = KCONST8(op); + res = rd - rr; + SREG_W(AVR8_SREG_H, (NOT(BIT(rd,3)) & BIT(rr,3)) | (BIT(rr,3) & BIT(res,3)) | (BIT(res,3) & NOT(BIT(rd,3)))); + SREG_W(AVR8_SREG_V, (BIT(rd,7) & NOT(BIT(rr,7)) & NOT(BIT(res,7))) | (NOT(BIT(rd,7)) & BIT(rr,7) & BIT(res,7))); + SREG_W(AVR8_SREG_N, BIT(res,7)); + SREG_W(AVR8_SREG_S, SREG_R(AVR8_SREG_N) ^ SREG_R(AVR8_SREG_V)); + SREG_W(AVR8_SREG_Z, (res == 0) ? 1 : 0); + SREG_W(AVR8_SREG_C, (NOT(BIT(rd,7)) & BIT(rr,7)) | (BIT(rr,7) & BIT(res,7)) | (BIT(res,7) & NOT(BIT(rd,7)))); + break; + case 0x4000: // SBCI Rd,K + rd = m_r[16 + RD4(op)]; + rr = KCONST8(op); + res = rd - (rr + SREG_R(AVR8_SREG_C)); + m_r[16 + RD4(op)] = res; + SREG_W(AVR8_SREG_H, (NOT(BIT(rd,3)) & BIT(rr,3)) | (BIT(rr,3) & BIT(res,3)) | (BIT(res,3) & NOT(BIT(rd,3)))); + SREG_W(AVR8_SREG_V, (BIT(rd,7) & NOT(BIT(rr,7)) & NOT(BIT(res,7))) | (NOT(BIT(rd,7)) & BIT(rr,7) & BIT(res,7))); + SREG_W(AVR8_SREG_N, BIT(res,7)); + SREG_W(AVR8_SREG_S, SREG_R(AVR8_SREG_N) ^ SREG_R(AVR8_SREG_V)); + SREG_W(AVR8_SREG_Z, (res == 0) ? SREG_R(AVR8_SREG_Z) : 0); + SREG_W(AVR8_SREG_C, (NOT(BIT(rd,7)) & BIT(rr,7)) | (BIT(rr,7) & BIT(res,7)) | (BIT(res,7) & NOT(BIT(rd,7)))); + break; + case 0x5000: // SUBI Rd,K + rd = m_r[16 + RD4(op)]; + rr = KCONST8(op); + res = rd - rr; + m_r[16 + RD4(op)] = res; + SREG_W(AVR8_SREG_H, (NOT(BIT(rd,3)) & BIT(rr,3)) | (BIT(rr,3) & BIT(res,3)) | (BIT(res,3) & NOT(BIT(rd,3)))); + SREG_W(AVR8_SREG_V, (BIT(rd,7) & NOT(BIT(rr,7)) & NOT(BIT(res,7))) | (NOT(BIT(rd,7)) & BIT(rr,7) & BIT(res,7))); + SREG_W(AVR8_SREG_N, BIT(res,7)); + SREG_W(AVR8_SREG_S, SREG_R(AVR8_SREG_N) ^ SREG_R(AVR8_SREG_V)); + SREG_W(AVR8_SREG_Z, (res == 0) ? 1 : 0); + SREG_W(AVR8_SREG_C, (NOT(BIT(rd,7)) & BIT(rr,7)) | (BIT(rr,7) & BIT(res,7)) | (BIT(res,7) & NOT(BIT(rd,7)))); + break; + case 0x6000: // ORI Rd,K + rd = m_r[16 + RD4(op)]; + rr = KCONST8(op); + rd |= rr; + SREG_W(AVR8_SREG_V, 0); + SREG_W(AVR8_SREG_N, BIT(rd,7)); + SREG_W(AVR8_SREG_S, SREG_R(AVR8_SREG_N) ^ SREG_R(AVR8_SREG_V)); + SREG_W(AVR8_SREG_Z, (rd == 0) ? 1 : 0); + m_r[16 + RD4(op)] = rd; + break; + case 0x7000: // ANDI Rd,K + rd = m_r[16 + RD4(op)]; + rr = KCONST8(op); + rd &= rr; + SREG_W(AVR8_SREG_V, 0); + SREG_W(AVR8_SREG_N, BIT(rd,7)); + SREG_W(AVR8_SREG_S, SREG_R(AVR8_SREG_N) ^ SREG_R(AVR8_SREG_V)); + SREG_W(AVR8_SREG_Z, (rd == 0) ? 1 : 0); + m_r[16 + RD4(op)] = rd; + break; + case 0x8000: + case 0xa000: + switch(op & 0x0208) + { + case 0x0000: // LDD Rd,Z+q + m_r[RD5(op)] = m_data->read_byte(ZREG + QCONST6(op)); + opcycles = 2; + break; + case 0x0008: // LDD Rd,Y+q + m_r[RD5(op)] = m_data->read_byte(YREG + QCONST6(op)); + opcycles = 2; + break; + case 0x0200: // STD Z+q,Rr + m_data->write_byte(ZREG + QCONST6(op), m_r[RD5(op)]); + opcycles = 2; + break; + case 0x0208: // STD Y+q,Rr + m_data->write_byte(YREG + QCONST6(op), m_r[RD5(op)]); + opcycles = 2; + break; + } + break; + case 0x9000: + switch(op & 0x0f00) + { + case 0x0000: + case 0x0100: + switch(op & 0x000f) + { + case 0x0000: // LDS Rd,k + op <<= 16; + m_pc++; + m_shifted_pc += 2; + op |= m_program->read_word(m_shifted_pc); + m_r[RD5(op >> 16)] = m_data->read_byte(op & 0x0000ffff); + opcycles = 2; + break; + case 0x0001: // LD Rd,Z+ + pd = ZREG; + m_r[RD5(op)] = m_data->read_byte(pd); + pd++; + m_r[31] = (pd >> 8) & 0x00ff; + m_r[30] = pd & 0x00ff; + opcycles = 2; + break; + case 0x0002: // LD Rd,-Z + pd = ZREG; + pd--; + m_r[RD5(op)] = m_data->read_byte(pd); + m_r[31] = (pd >> 8) & 0x00ff; + m_r[30] = pd & 0x00ff; + opcycles = 2; + break; + case 0x0004: // LPM Rd,Z + m_r[RD5(op)] = m_program->read_byte(ZREG); + opcycles = 3; + break; + case 0x0005: // LPM Rd,Z+ + pd = ZREG; + m_r[RD5(op)] = m_program->read_byte(pd); + pd++; + m_r[31] = (pd >> 8) & 0x00ff; + m_r[30] = pd & 0x00ff; + opcycles = 3; + break; + case 0x0006: // ELPM Rd,Z + m_r[RD5(op)] = m_program->read_byte((m_r[AVR8_REGIDX_RAMPZ] << 16) | ZREG); + opcycles = 3; + break; + case 0x0007: // ELPM Rd,Z+ + pd32 = (m_r[AVR8_REGIDX_RAMPZ] << 16) | ZREG; + m_r[RD5(op)] = m_program->read_byte(pd32); + pd32++; + m_r[AVR8_REGIDX_RAMPZ] = (pd32 >> 16) & 0x00ff; + m_r[31] = (pd32 >> 8) & 0x00ff; + m_r[30] = pd32 & 0x00ff; + opcycles = 3; + break; + case 0x0009: // LD Rd,Y+ + pd = YREG; + m_r[RD5(op)] = m_data->read_byte(pd); + pd++; + m_r[29] = (pd >> 8) & 0x00ff; + m_r[28] = pd & 0x00ff; + opcycles = 2; + break; + case 0x000a: // LD Rd,-Y + pd = YREG; + pd--; + m_r[RD5(op)] = m_data->read_byte(pd); + m_r[29] = (pd >> 8) & 0x00ff; + m_r[28] = pd & 0x00ff; + opcycles = 2; + break; + case 0x000c: // LD Rd,X + m_r[RD5(op)] = m_data->read_byte(XREG); + opcycles = 2; + break; + case 0x000d: // LD Rd,X+ + pd = XREG; + m_r[RD5(op)] = m_data->read_byte(pd); + pd++; + m_r[27] = (pd >> 8) & 0x00ff; + m_r[26] = pd & 0x00ff; + opcycles = 2; + break; + case 0x000e: // LD Rd,-X + pd = XREG; + pd--; + m_r[RD5(op)] = m_data->read_byte(pd); + m_r[27] = (pd >> 8) & 0x00ff; + m_r[26] = pd & 0x00ff; + opcycles = 2; + break; + case 0x000f: // POP Rd + m_r[RD5(op)] = pop(); + opcycles = 2; + break; + default: + unimplemented_opcode(op); + //output += sprintf( output, "Undefined (%04x)", op ); + break; + } + break; + case 0x0200: + case 0x0300: + switch(op & 0x000f) + { + case 0x0000: // STS k,Rr + op <<= 16; + m_pc++; + m_shifted_pc += 2; + op |= m_program->read_word(m_shifted_pc); + m_data->write_byte(op & 0x0000ffff, m_r[RD5(op >> 16)]); + opcycles = 2; + break; + case 0x0001: // ST Z+,Rd + pd = ZREG; + m_data->write_byte(pd, m_r[RD5(op)]); + pd++; + m_r[31] = (pd >> 8) & 0x00ff; + m_r[30] = pd & 0x00ff; + opcycles = 2; + break; + case 0x0002: // ST -Z,Rd + pd = ZREG; + pd--; + m_data->write_byte(pd, m_r[RD5(op)]); + m_r[31] = (pd >> 8) & 0x00ff; + m_r[30] = pd & 0x00ff; + opcycles = 2; + break; + case 0x0009: // ST Y+,Rd + pd = YREG; + m_data->write_byte(pd, m_r[RD5(op)]); + pd++; + m_r[29] = (pd >> 8) & 0x00ff; + m_r[28] = pd & 0x00ff; + opcycles = 2; + break; + case 0x000a: // ST -Y,Rd + pd = YREG; + pd--; + m_data->write_byte(pd, m_r[RD5(op)]); + m_r[29] = (pd >> 8) & 0x00ff; + m_r[28] = pd & 0x00ff; + opcycles = 2; + break; + case 0x000c: // ST X,Rd + m_data->write_byte(XREG, m_r[RD5(op)]); + break; + case 0x000d: // ST X+,Rd + pd = XREG; + m_data->write_byte(pd, m_r[RD5(op)]); + pd++; + m_r[27] = (pd >> 8) & 0x00ff; + m_r[26] = pd & 0x00ff; + opcycles = 2; + break; + case 0x000e: // ST -X,Rd + pd = XREG; + pd--; + m_data->write_byte(pd, m_r[RD5(op)]); + m_r[27] = (pd >> 8) & 0x00ff; + m_r[26] = pd & 0x00ff; + opcycles = 2; + break; + case 0x000f: // PUSH Rd + push(m_r[RD5(op)]); + opcycles = 2; + break; + default: + unimplemented_opcode(op); + //output += sprintf( output, "Undefined (%04x)", op ); + break; + } + break; + case 0x0400: + switch(op & 0x000f) + { + case 0x0000: // COM Rd + rd = m_r[RD5(op)]; + res = ~rd; + SREG_W(AVR8_SREG_C, 1); + SREG_W(AVR8_SREG_Z, (res == 0) ? 1 : 0); + SREG_W(AVR8_SREG_N, BIT(res,7)); + SREG_W(AVR8_SREG_V, 0); + SREG_W(AVR8_SREG_S, SREG_R(AVR8_SREG_N) ^ SREG_R(AVR8_SREG_V)); + m_r[RD5(op)] = res; + break; + case 0x0001: // NEG Rd + rd = m_r[RD5(op)]; + res = 0 - rd; + SREG_W(AVR8_SREG_C, (res == 0) ? 0 : 1); + SREG_W(AVR8_SREG_Z, (res == 0) ? 1 : 0); + SREG_W(AVR8_SREG_N, BIT(res,7)); + SREG_W(AVR8_SREG_V, (res == 0x80) ? 1 : 0); + SREG_W(AVR8_SREG_S, SREG_R(AVR8_SREG_N) ^ SREG_R(AVR8_SREG_V)); + SREG_W(AVR8_SREG_H, BIT(res,3) | BIT(rd,3)); + m_r[RD5(op)] = res; + break; + case 0x0002: // SWAP Rd + rd = m_r[RD5(op)]; + m_r[RD5(op)] = (rd >> 4) | (rd << 4); + break; + case 0x0003: // INC Rd + rd = m_r[RD5(op)]; + res = rd + 1; + SREG_W(AVR8_SREG_V, (rd == 0x7f) ? 1 : 0); + SREG_W(AVR8_SREG_N, BIT(res,7)); + SREG_W(AVR8_SREG_S, SREG_R(AVR8_SREG_N) ^ SREG_R(AVR8_SREG_V)); + SREG_W(AVR8_SREG_Z, (res == 0) ? 1 : 0); + m_r[RD5(op)] = res; + break; + case 0x0005: // ASR Rd + rd = m_r[RD5(op)]; + res = (rd & 0x80) | (rd >> 1); + SREG_W(AVR8_SREG_C, BIT(rd,0)); + SREG_W(AVR8_SREG_Z, (res == 0) ? 1 : 0); + SREG_W(AVR8_SREG_N, BIT(rd,7)); + SREG_W(AVR8_SREG_V, SREG_R(AVR8_SREG_N) ^ SREG_R(AVR8_SREG_C)); + SREG_W(AVR8_SREG_S, SREG_R(AVR8_SREG_N) ^ SREG_R(AVR8_SREG_V)); + m_r[RD5(op)] = res; + break; + case 0x0006: // LSR Rd + rd = m_r[RD5(op)]; + res = rd >> 1; + SREG_W(AVR8_SREG_C, BIT(rd,0)); + SREG_W(AVR8_SREG_Z, (res == 0) ? 1 :0); + SREG_W(AVR8_SREG_N, 0); + SREG_W(AVR8_SREG_V, SREG_R(AVR8_SREG_N) ^ SREG_R(AVR8_SREG_C)); + SREG_W(AVR8_SREG_S, SREG_R(AVR8_SREG_N) ^ SREG_R(AVR8_SREG_V)); + m_r[RD5(op)] = res; + break; + case 0x0007: // ROR Rd + rd = m_r[RD5(op)]; + res = rd >> 1; + res |= (SREG_R(AVR8_SREG_C) << 7); + SREG_W(AVR8_SREG_C, BIT(rd,0)); + SREG_W(AVR8_SREG_Z, (res == 0) ? 1 :0); + SREG_W(AVR8_SREG_N, BIT(res,7)); + SREG_W(AVR8_SREG_V, SREG_R(AVR8_SREG_N) ^ SREG_R(AVR8_SREG_C)); + SREG_W(AVR8_SREG_S, SREG_R(AVR8_SREG_N) ^ SREG_R(AVR8_SREG_V)); + m_r[RD5(op)] = res; + break; + case 0x0008: + switch(op & 0x00f0) + { + case 0x0000: // SEC + case 0x0010: // SEZ + case 0x0020: // SEN + case 0x0030: // SEV + case 0x0040: // SES + case 0x0050: // SEH + case 0x0060: // SET + case 0x0070: // SEI + SREG_W((op >> 4) & 0x07, 1); + break; + case 0x0080: // CLC + case 0x0090: // CLZ + case 0x00a0: // CLN + case 0x00b0: // CLV + case 0x00c0: // CLS + case 0x00d0: // CLH + case 0x00e0: // CLT + case 0x00f0: // CLI + SREG_W((op >> 4) & 0x07, 0); + break; + } + break; + case 0x0009: + switch(op & 0x00f0) + { + case 0x0000: // IJMP + m_pc = ZREG - 1; + opcycles = 2; + break; + case 0x0010: // EIJMP + m_pc = (m_r[AVR8_REGIDX_EIND] << 16 | ZREG) - 1; + opcycles = 2; + break; + default: + //output += sprintf( output, "Undefined (%04x)", op ); + unimplemented_opcode(op); + break; + } + break; + case 0x000a: // DEC Rd + rd = m_r[RD5(op)]; + res = rd - 1; + SREG_W(AVR8_SREG_V, (rd == 0x7f) ? 1 : 0); + SREG_W(AVR8_SREG_N, BIT(res,7)); + SREG_W(AVR8_SREG_S, SREG_R(AVR8_SREG_N) ^ SREG_R(AVR8_SREG_V)); + SREG_W(AVR8_SREG_Z, (res == 0) ? 1 : 0); + m_r[RD5(op)] = res; + break; + case 0x000c: + case 0x000d: // JMP k + offs = KCONST22(op) << 16; + m_pc++; + m_shifted_pc += 2; + offs |= m_program->read_word(m_shifted_pc); + m_pc = offs; + m_pc--; + opcycles = 3; + break; + case 0x000e: // CALL k + case 0x000f: + push((m_pc + 2) & 0x00ff); + push(((m_pc + 2) >> 8) & 0x00ff); + offs = KCONST22(op) << 16; + m_pc++; + m_shifted_pc += 2; + offs |= m_program->read_word(m_shifted_pc); + m_pc = offs; + m_pc--; + opcycles = 4; + break; + default: + unimplemented_opcode(op); + //output += sprintf( output, "Undefined (%04x)", op ); + break; + } + break; + case 0x0500: + switch(op & 0x000f) + { + case 0x0000: // COM Rd + rd = m_r[RD5(op)]; + res = ~rd; + SREG_W(AVR8_SREG_C, 1); + SREG_W(AVR8_SREG_Z, (res == 0) ? 1 : 0); + SREG_W(AVR8_SREG_N, BIT(res,7)); + SREG_W(AVR8_SREG_V, 0); + SREG_W(AVR8_SREG_S, SREG_R(AVR8_SREG_N) ^ SREG_R(AVR8_SREG_V)); + m_r[RD5(op)] = res; + break; + case 0x0001: // NEG Rd + rd = m_r[RD5(op)]; + res = 0 - rd; + SREG_W(AVR8_SREG_C, (res == 0) ? 0 : 1); + SREG_W(AVR8_SREG_Z, (res == 0) ? 1 : 0); + SREG_W(AVR8_SREG_N, BIT(res,7)); + SREG_W(AVR8_SREG_V, (res == 0x80) ? 1 : 0); + SREG_W(AVR8_SREG_S, SREG_R(AVR8_SREG_N) ^ SREG_R(AVR8_SREG_V)); + SREG_W(AVR8_SREG_H, BIT(res,3) | BIT(rd,3)); + m_r[RD5(op)] = res; + break; + case 0x0002: // SWAP Rd + rd = m_r[RD5(op)]; + m_r[RD5(op)] = (rd >> 4) | (rd << 4); + break; + case 0x0003: // INC Rd + rd = m_r[RD5(op)]; + res = rd + 1; + SREG_W(AVR8_SREG_V, (rd == 0x7f) ? 1 : 0); + SREG_W(AVR8_SREG_N, BIT(res,7)); + SREG_W(AVR8_SREG_S, SREG_R(AVR8_SREG_N) ^ SREG_R(AVR8_SREG_V)); + SREG_W(AVR8_SREG_Z, (res == 0) ? 1 : 0); + m_r[RD5(op)] = res; + break; + case 0x0005: // ASR Rd + rd = m_r[RD5(op)]; + res = (rd & 0x80) | (rd >> 1); + SREG_W(AVR8_SREG_C, BIT(rd,0)); + SREG_W(AVR8_SREG_Z, (res == 0) ? 1 : 0); + SREG_W(AVR8_SREG_N, BIT(rd,7)); + SREG_W(AVR8_SREG_V, SREG_R(AVR8_SREG_N) ^ SREG_R(AVR8_SREG_C)); + SREG_W(AVR8_SREG_S, SREG_R(AVR8_SREG_N) ^ SREG_R(AVR8_SREG_V)); + m_r[RD5(op)] = res; + break; + case 0x0006: // LSR Rd + rd = m_r[RD5(op)]; + res = rd >> 1; + SREG_W(AVR8_SREG_C, BIT(rd,0)); + SREG_W(AVR8_SREG_Z, (res == 0) ? 1 :0); + SREG_W(AVR8_SREG_N, 0); + SREG_W(AVR8_SREG_V, SREG_R(AVR8_SREG_N) ^ SREG_R(AVR8_SREG_C)); + SREG_W(AVR8_SREG_S, SREG_R(AVR8_SREG_N) ^ SREG_R(AVR8_SREG_V)); + m_r[RD5(op)] = res; + break; + case 0x0007: // ROR Rd + rd = m_r[RD5(op)]; + res = rd >> 1; + res |= (SREG_R(AVR8_SREG_C) << 7); + SREG_W(AVR8_SREG_C, BIT(rd,0)); + SREG_W(AVR8_SREG_Z, (res == 0) ? 1 :0); + SREG_W(AVR8_SREG_N, BIT(res,7)); + SREG_W(AVR8_SREG_V, SREG_R(AVR8_SREG_N) ^ SREG_R(AVR8_SREG_C)); + SREG_W(AVR8_SREG_S, SREG_R(AVR8_SREG_N) ^ SREG_R(AVR8_SREG_V)); + m_r[RD5(op)] = res; + break; + case 0x0008: + switch(op & 0x00f0) + { + case 0x0000: // RET + m_pc = pop() << 8; + m_pc |= pop(); + m_pc--; + opcycles = 4; + break; + case 0x0010: // RETI + m_pc = pop() << 8; + m_pc |= pop(); + m_pc--; + SREG_W(AVR8_SREG_I, 1); + opcycles = 4; + break; + case 0x0080: // SLEEP + //output += sprintf( output, "SLEEP" ); + m_pc--; + opcycles = 1; + //unimplemented_opcode(op); + break; + case 0x0090: // BREAK + //output += sprintf( output, "BREAK" ); + unimplemented_opcode(op); + break; + case 0x00a0: // WDR + //output += sprintf( output, "WDR" ); + //unimplemented_opcode(op); //TODO: necessary for emulating the Replicator 1 + //printf("Watchdot Reset!\n"); + opcycles = 1; + break; + case 0x00c0: // LPM + m_r[0] = m_program->read_byte(ZREG); + opcycles = 3; + break; + case 0x00d0: // ELPM + //output += sprintf( output, "ELPM" ); + unimplemented_opcode(op); + break; + case 0x00e0: // SPM + //output += sprintf( output, "SPM" ); + unimplemented_opcode(op); + break; + case 0x00f0: // SPM Z+ + //output += sprintf( output, "SPM Z+" ); + unimplemented_opcode(op); + break; + default: + unimplemented_opcode(op); + //output += sprintf( output, "Undefined (%04x)", op ); + break; + } + break; + case 0x0009: + switch(op & 0x00f0) + { + case 0x0000: // ICALL + push((m_pc + 1) & 0x00ff); + push(((m_pc + 1) >> 8) & 0x00ff); + m_pc = ZREG; + m_pc--; + opcycles = 3; + break; + case 0x0010: // EICALL + //output += sprintf( output, "EICALL" ); + unimplemented_opcode(op); + break; + default: + unimplemented_opcode(op); + //output += sprintf( output, "Undefined (%04x)", op ); + break; + } + break; + case 0x000a: // DEC Rd + rd = m_r[RD5(op)]; + res = rd - 1; + SREG_W(AVR8_SREG_V, (rd == 0x7f) ? 1 : 0); + SREG_W(AVR8_SREG_N, BIT(res,7)); + SREG_W(AVR8_SREG_S, SREG_R(AVR8_SREG_N) ^ SREG_R(AVR8_SREG_V)); + SREG_W(AVR8_SREG_Z, (res == 0) ? 1 : 0); + m_r[RD5(op)] = res; + break; + case 0x000c: + case 0x000d: // JMP k + //op <<= 8; + //op |= oprom[pos++]; + //op <<= 8; + //op |= oprom[pos++]; + //output += sprintf( output, "JMP 0x%06x", KCONST22(op) ); + unimplemented_opcode(op); + break; + case 0x000e: + case 0x000f: // CALL k + //op <<= 8; + //op |= oprom[pos++]; + //op <<= 8; + //op |= oprom[pos++]; + //output += sprintf( output, "CALL 0x%06x", KCONST22(op) ); + unimplemented_opcode(op); + break; + } + break; + case 0x0600: // ADIW Rd+1:Rd,K + rd = m_r[24 + (DCONST(op) << 1)]; + rr = m_r[25 + (DCONST(op) << 1)]; + pd = rd; + pd |= rr << 8; + pd += KCONST6(op); + SREG_W(AVR8_SREG_V, BIT(pd,15) & NOT(BIT(rr,7))); + SREG_W(AVR8_SREG_N, BIT(pd,15)); + SREG_W(AVR8_SREG_S, SREG_R(AVR8_SREG_N) ^ SREG_R(AVR8_SREG_V)); + SREG_W(AVR8_SREG_Z, (pd == 0) ? 1 : 0); + SREG_W(AVR8_SREG_C, NOT(BIT(pd,15)) & BIT(rr,7)); + m_r[24 + (DCONST(op) << 1)] = pd & 0x00ff; + m_r[25 + (DCONST(op) << 1)] = (pd >> 8) & 0x00ff; + opcycles = 2; + break; + case 0x0700: // SBIW Rd+1:Rd,K + rd = m_r[24 + (DCONST(op) << 1)]; + rr = m_r[25 + (DCONST(op) << 1)]; + pd = rd; + pd |= rr << 8; + pd -= KCONST6(op); + SREG_W(AVR8_SREG_V, NOT(BIT(pd,15)) & BIT(rr,7)); + SREG_W(AVR8_SREG_N, BIT(pd,15)); + SREG_W(AVR8_SREG_S, SREG_R(AVR8_SREG_N) ^ SREG_R(AVR8_SREG_V)); + SREG_W(AVR8_SREG_Z, (pd == 0) ? 1 : 0); + SREG_W(AVR8_SREG_C, BIT(pd,15) & NOT(BIT(rr,7))); + m_r[24 + (DCONST(op) << 1)] = pd & 0x00ff; + m_r[25 + (DCONST(op) << 1)] = (pd >> 8) & 0x00ff; + opcycles = 2; + break; + case 0x0800: // CBI A,b + //output += sprintf( output, "CBI 0x%02x, %d", ACONST5(op), RR3(op) ); + m_data->write_byte(32 + ACONST5(op), m_data->read_byte(32 + ACONST5(op)) &~ (1 << RR3(op))); + opcycles = 2; + break; + case 0x0900: // SBIC A,b + if(NOT(BIT(m_data->read_byte(32 + ACONST5(op)), RR3(op)))) + { + op = (UINT32)m_program->read_word(m_shifted_pc + 2); + opcycles = is_long_opcode(op) ? 3 : 2; + m_pc += is_long_opcode(op) ? 2 : 1; + } + break; + case 0x0a00: // SBI A,b + m_data->write_byte(32 + ACONST5(op), m_data->read_byte(32 + ACONST5(op)) | (1 << RR3(op))); + opcycles = 2; + break; + case 0x0b00: // SBIS A,b + if(BIT(m_data->read_byte(32 + ACONST5(op)), RR3(op))) + { + op = (UINT32)m_program->read_word(m_shifted_pc + 2); + opcycles = is_long_opcode(op) ? 3 : 2; + m_pc += is_long_opcode(op) ? 2 : 1; + } + break; + case 0x0c00: + case 0x0d00: + case 0x0e00: + case 0x0f00: // MUL Rd,Rr + sd = (UINT8)m_r[RD5(op)] * (UINT8)m_r[RR5(op)]; + m_r[1] = (sd >> 8) & 0x00ff; + m_r[0] = sd & 0x00ff; + SREG_W(AVR8_SREG_C, (sd & 0x8000) ? 1 : 0); + SREG_W(AVR8_SREG_Z, (sd == 0) ? 1 : 0); + opcycles = 2; + break; + } + break; + case 0xb000: + if(op & 0x0800) // OUT A,Rr + { + m_data->write_byte(32 + ACONST6(op), m_r[RD5(op)]); + } + else // IN Rd,A + { + m_r[RD5(op)] = m_data->read_byte(0x20 + ACONST6(op)); + } + break; + case 0xc000: // RJMP k + offs = (INT32)((op & 0x0800) ? ((op & 0x0fff) | 0xfffff000) : (op & 0x0fff)); + m_pc += offs; + opcycles = 2; + break; + case 0xd000: // RCALL k + offs = (INT32)((op & 0x0800) ? ((op & 0x0fff) | 0xfffff000) : (op & 0x0fff)); + push((m_pc + 1) & 0x00ff); + push(((m_pc + 1) >> 8) & 0x00ff); + m_pc += offs; + opcycles = 3; + break; + case 0xe000: // LDI Rd,K + m_r[16 + RD4(op)] = KCONST8(op); + break; + case 0xf000: + switch(op & 0x0c00) + { + case 0x0000: // BRLO through BRIE + if(SREG_R(op & 0x0007)) + { + offs = (INT32)(KCONST7(op)); + if(offs & 0x40) + { + offs |= 0xffffff80; + } + m_pc += offs; + opcycles = 2; + } + break; + case 0x0400: // BRSH through BRID + if(SREG_R(op & 0x0007) == 0) + { + offs = (INT32)(KCONST7(op)); + if(offs & 0x40) + { + offs |= 0xffffff80; + } + m_pc += offs; + opcycles = 2; + } + break; + case 0x0800: + if(op & 0x0200) // BST Rd, b + { + SREG_W(AVR8_SREG_T, (BIT(m_r[RD5(op)], RR3(op))) ? 1 : 0); + } + else // BLD Rd, b + { + if(SREG_R(AVR8_SREG_T)) + { + m_r[RD5(op)] |= (1 << RR3(op)); + } + else + { + m_r[RD5(op)] &= ~(1 << RR3(op)); + } + } + break; + case 0x0c00: + if(op & 0x0200) // SBRS Rd, b + { + if(BIT(m_r[RD5(op)], RR3(op))) + { + op = (UINT32)m_program->read_word(m_shifted_pc + 2); + m_pc += is_long_opcode(op) ? 2 : 1; + opcycles = is_long_opcode(op) ? 3 : 2; + } + } + else // SBRC Rd, b + { + if(NOT(BIT(m_r[RD5(op)], RR3(op)))) + { + op = (UINT32)m_program->read_word(m_shifted_pc + 2); + m_pc += is_long_opcode(op) ? 2 : 1; + opcycles = is_long_opcode(op) ? 3 : 2; + } + } + break; + } + break; + } + + m_pc++; + + m_shifted_pc = m_pc << 1; + + m_icount -= opcycles; + + timer_tick(opcycles); + } +} diff --git a/src/devices/cpu/avr8/avr8.h b/src/devices/cpu/avr8/avr8.h new file mode 100644 index 00000000000..3b3cbd8f6a0 --- /dev/null +++ b/src/devices/cpu/avr8/avr8.h @@ -0,0 +1,868 @@ +// license:BSD-3-Clause +// copyright-holders:Ryan Holtz +/* + Atmel 8-bit AVR simulator + + - Notes - + Cycle counts are generally considered to be 100% accurate per-instruction, does not support mid-instruction + interrupts although no software has been countered yet that requires it. Evidence of cycle accuracy is given + in the form of the demoscene 'wild' demo, Craft, by [lft], which uses an ATmega88 to write video out a 6-bit + RGB DAC pixel-by-pixel, synchronously with the frame timing. Intentionally modifying the timing of any of + the existing opcodes has been shown to wildly corrupt the video output in Craft, so one can assume that the + existing timing is 100% correct. + + Unimplemented opcodes: ELPM, SPM, SPM Z+, EIJMP, SLEEP, BREAK, WDR, EICALL, JMP, CALL + + - Changelist - + 23 Dec. 2012 [Sandro Ronco] + - Added CPSE, LD Z+, ST -Z/-Y/-X and ICALL opcodes + - Fixed Z flag in CPC, SBC and SBCI opcodes + - Fixed V and C flags in SBIW opcode + + 30 Oct. 2012 + - Added FMUL, FMULS, FMULSU opcodes [MooglyGuy] + - Fixed incorrect flag calculation in ROR opcode [MooglyGuy] + - Fixed incorrect bit testing in SBIC/SBIS opcodes [MooglyGuy] + + 25 Oct. 2012 + - Added MULS, ANDI, STI Z+, LD -Z, LD -Y, LD -X, LD Y+q, LD Z+q, SWAP, ASR, ROR and SBIS opcodes [MooglyGuy] + - Corrected cycle counts for LD and ST opcodes [MooglyGuy] + - Moved opcycles init into inner while loop, fixes 2-cycle and 3-cycle opcodes effectively forcing + all subsequent 1-cycle opcodes to be 2 or 3 cycles [MooglyGuy] + - Fixed register behavior in MULSU, LD -Z, and LD -Y opcodes [MooglyGuy] + + 18 Oct. 2012 + - Added OR, SBCI, ORI, ST Y+, ADIQ opcodes [MooglyGuy] + - Fixed COM, NEG, LSR opcodes [MooglyGuy] + +*/ + +#pragma once + +#ifndef __AVR8_H__ +#define __AVR8_H__ + + +//************************************************************************** +// FUSE BITS CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_CPU_AVR8_LFUSE(byte) \ + ((avr8_device*) device)->set_low_fuses(byte); + +#define MCFG_CPU_AVR8_HFUSE(byte) \ + ((avr8_device*) device)->set_high_fuses(byte); + +#define MCFG_CPU_AVR8_EFUSE(byte) \ + ((avr8_device*) device)->set_extended_fuses(byte); + +#define MCFG_CPU_AVR8_LOCK(byte) \ + ((avr8_device*) device)->set_lock_bits(byte); + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_CPU_AVR8_EEPROM(_tag) \ + avr8_device::set_eeprom_tag(*device, _tag); + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class avr8_device; + +// ======================> avr8_device + +// Used by core CPU interface +class avr8_device : public cpu_device +{ +public: + // construction/destruction + avr8_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock, const device_type type, UINT32 address_mask); + + // inline configuration helpers + static void set_eeprom_tag(device_t &device, const char *tag) { downcast(device).m_eeprom_tag = tag; } + + // fuse configs + void set_low_fuses(UINT8 byte); + void set_high_fuses(UINT8 byte); + void set_extended_fuses(UINT8 byte); + void set_lock_bits(UINT8 byte); + + // public interfaces + virtual void update_interrupt(int source); + UINT64 get_elapsed_cycles() + { + return m_elapsed_cycles; + } + + // register handling + DECLARE_WRITE8_MEMBER( regs_w ); + DECLARE_READ8_MEMBER( regs_r ); + UINT32 m_shifted_pc; + +protected: + enum + { + CPU_TYPE_ATMEGA88, + CPU_TYPE_ATMEGA644, + CPU_TYPE_ATMEGA1280, + CPU_TYPE_ATMEGA2560 + }; + + avr8_device(const machine_config &mconfig, const char *name, const char *tag, device_t *owner, UINT32 clock, const device_type type, UINT32 address_mask, address_map_constructor internal_map, UINT8 cpu_type, const char *shortname, const char *source); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_execute_interface overrides + virtual UINT32 execute_min_cycles() const; + virtual UINT32 execute_max_cycles() const; + virtual UINT32 execute_input_lines() const; + virtual void execute_run(); + virtual void execute_set_input(int inputnum, int state); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const; + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const; + virtual UINT32 disasm_max_opcode_bytes() const; + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + + // device_state_interface overrides + virtual void state_string_export(const device_state_entry &entry, std::string &str); + + // address spaces + const address_space_config m_program_config; + const address_space_config m_data_config; + const address_space_config m_io_config; + const char *m_eeprom_tag; + UINT8 *m_eeprom; + + // bootloader + UINT16 m_boot_size; + UINT8 m_cpu_type; + + // Fuses + UINT8 m_lfuses; + UINT8 m_hfuses; + UINT8 m_efuses; + UINT8 m_lock_bits; + + // CPU registers + UINT32 m_pc; + UINT8 m_r[0x200]; + + // internal timers + INT32 m_timer_top[6]; + UINT8 m_timer_increment[6]; + UINT16 m_timer_prescale[6]; + UINT16 m_timer_prescale_count[6]; + bool m_ocr2_not_reached_yet; + + // SPI + bool m_spi_active; + UINT8 m_spi_prescale; + UINT8 m_spi_prescale_count; + INT8 m_spi_prescale_countdown; + static const UINT8 spi_clock_divisor[8]; + void enable_spi(); + void disable_spi(); + void spi_update_masterslave_select(); + void spi_update_clock_polarity(); + void spi_update_clock_phase(); + void spi_update_clock_rate(); + void change_spcr(UINT8 data); + void change_spsr(UINT8 data); + + // internal CPU state + UINT32 m_addr_mask; + bool m_interrupt_pending; + + // other internal states + int m_icount; + UINT64 m_elapsed_cycles; + + // memory access + inline UINT8 program_read8(UINT32 addr); + inline UINT16 program_read16(UINT32 addr); + inline void program_write8(UINT32 addr, UINT8 data); + inline void program_write16(UINT32 addr, UINT16 data); + inline UINT8 io_read8(UINT16 addr); + inline void io_write8(UINT16 addr, UINT8 data); + inline UINT16 opcode_read(); + inline void push(UINT8 val); + inline UINT8 pop(); + inline bool is_long_opcode(UINT16 op); + + // utility + void unimplemented_opcode(UINT32 op); + + // interrupts + void set_irq_line(UINT16 vector, int state); + void update_interrupt_internal(int source); + + // timers + void timer_tick(int cycles); + void update_timer_clock_source(UINT8 timer, UINT8 selection); + void update_timer_waveform_gen_mode(UINT8 timer, UINT8 mode); + + // timer 0 + void timer0_tick(); + void changed_tccr0a(UINT8 data); + void changed_tccr0b(UINT8 data); + void update_ocr0(UINT8 newval, UINT8 reg); + void timer0_force_output_compare(int reg); + + // timer 1 + void timer1_tick(); + void changed_tccr1a(UINT8 data); + void changed_tccr1b(UINT8 data); + void update_timer1_input_noise_canceler(); + void update_timer1_input_edge_select(); + void update_ocr1(UINT16 newval, UINT8 reg); + + // timer 2 + void timer2_tick(); + void changed_tccr2a(UINT8 data); + void changed_tccr2b(UINT8 data); + void update_ocr2(UINT8 newval, UINT8 reg); + void timer2_force_output_compare(int reg); + + // timer 3 + void timer3_tick(); + void changed_tccr3a(UINT8 data); + void changed_tccr3b(UINT8 data); + void changed_tccr3c(UINT8 data); +// void update_ocr3(UINT8 newval, UINT8 reg); +// void timer3_force_output_compare(int reg); + + // timer 4 + void timer4_tick(); + void changed_tccr4a(UINT8 data); + void changed_tccr4b(UINT8 data); + void changed_tccr4c(UINT8 data); + //void update_ocr4(UINT8 newval, UINT8 reg); + //void timer4_force_output_compare(int reg); + + // timer 5 + void timer5_tick(); + void changed_tccr5a(UINT8 data); + void changed_tccr5b(UINT8 data); +// void update_ocr5(UINT8 newval, UINT8 reg); +// void timer5_force_output_compare(int reg); + + // address spaces + address_space *m_program; + address_space *m_data; + address_space *m_io; +}; + +// device type definition +extern const device_type ATMEGA88; +extern const device_type ATMEGA644; +extern const device_type ATMEGA1280; +extern const device_type ATMEGA2560; + +// ======================> atmega88_device + +class atmega88_device : public avr8_device +{ +public: + // construction/destruction + atmega88_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +// ======================> atmega644_device + +class atmega644_device : public avr8_device +{ +public: + // construction/destruction + atmega644_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual void update_interrupt(int source); +}; + +// ======================> atmega1280_device + +class atmega1280_device : public avr8_device +{ +public: + // construction/destruction + atmega1280_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual void update_interrupt(int source); +}; + +// ======================> atmega2560_device + +class atmega2560_device : public avr8_device +{ +public: + // construction/destruction + atmega2560_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual void update_interrupt(int source); +}; + +/*************************************************************************** + REGISTER ENUMERATION +***************************************************************************/ + +enum +{ + AVR8_SREG = 1, + AVR8_PC, + AVR8_R0, + AVR8_R1, + AVR8_R2, + AVR8_R3, + AVR8_R4, + AVR8_R5, + AVR8_R6, + AVR8_R7, + AVR8_R8, + AVR8_R9, + AVR8_R10, + AVR8_R11, + AVR8_R12, + AVR8_R13, + AVR8_R14, + AVR8_R15, + AVR8_R16, + AVR8_R17, + AVR8_R18, + AVR8_R19, + AVR8_R20, + AVR8_R21, + AVR8_R22, + AVR8_R23, + AVR8_R24, + AVR8_R25, + AVR8_R26, + AVR8_R27, + AVR8_R28, + AVR8_R29, + AVR8_R30, + AVR8_R31, + AVR8_X, + AVR8_Y, + AVR8_Z, + AVR8_SPH, + AVR8_SPL +}; + +enum +{ + AVR8_INT_RESET = 0, + AVR8_INT_INT0, + AVR8_INT_INT1, + AVR8_INT_PCINT0, + AVR8_INT_PCINT1, + AVR8_INT_PCINT2, + AVR8_INT_WDT, + AVR8_INT_T2COMPA, + AVR8_INT_T2COMPB, + AVR8_INT_T2OVF, + AVR8_INT_T1CAPT, + AVR8_INT_T1COMPA, + AVR8_INT_T1COMPB, + AVR8_INT_T1OVF, + AVR8_INT_T0COMPA, + AVR8_INT_T0COMPB, + AVR8_INT_T0OVF, + AVR8_INT_SPI_STC, + AVR8_INT_USART_RX, + AVR8_INT_USART_UDRE, + AVR8_INT_USART_TX, + AVR8_INT_ADC, + AVR8_INT_EE_RDY, + AVR8_INT_ANALOG_COMP, + AVR8_INT_TWI, + AVR8_INT_SPM_RDY, + + // ATMEGA644 + ATMEGA644_INT_RESET = 0, + ATMEGA644_INT_INT0, + ATMEGA644_INT_INT1, + ATMEGA644_INT_INT2, + ATMEGA644_INT_PCINT0, + ATMEGA644_INT_PCINT1, + ATMEGA644_INT_PCINT2, + ATMEGA644_INT_PCINT3, + ATMEGA644_INT_WDT, + ATMEGA644_INT_T2COMPA, + ATMEGA644_INT_T2COMPB, + ATMEGA644_INT_T2OVF, + ATMEGA644_INT_T1CAPT, + ATMEGA644_INT_T1COMPA, + ATMEGA644_INT_T1COMPB, + ATMEGA644_INT_T1OVF, + ATMEGA644_INT_T0COMPA, + ATMEGA644_INT_T0COMPB, + ATMEGA644_INT_T0OVF, + ATMEGA644_INT_SPI_STC, + ATMEGA644_INT_USART_RX, + ATMEGA644_INT_USART_UDRE, + ATMEGA644_INT_USART_TX, + ATMEGA644_INT_ADC, + ATMEGA644_INT_EE_RDY, + ATMEGA644_INT_ANALOG_COMP, + ATMEGA644_INT_TWI, + ATMEGA644_INT_SPM_RDY +}; + +// Used by I/O register handling +enum +{ + AVR8_REGIDX_R0 = 0x00, + AVR8_REGIDX_R1, + AVR8_REGIDX_R2, + AVR8_REGIDX_R3, + AVR8_REGIDX_R4, + AVR8_REGIDX_R5, + AVR8_REGIDX_R6, + AVR8_REGIDX_R7, + AVR8_REGIDX_R8, + AVR8_REGIDX_R9, + AVR8_REGIDX_R10, + AVR8_REGIDX_R11, + AVR8_REGIDX_R12, + AVR8_REGIDX_R13, + AVR8_REGIDX_R14, + AVR8_REGIDX_R15, + AVR8_REGIDX_R16, + AVR8_REGIDX_R17, + AVR8_REGIDX_R18, + AVR8_REGIDX_R19, + AVR8_REGIDX_R20, + AVR8_REGIDX_R21, + AVR8_REGIDX_R22, + AVR8_REGIDX_R23, + AVR8_REGIDX_R24, + AVR8_REGIDX_R25, + AVR8_REGIDX_R26, + AVR8_REGIDX_R27, + AVR8_REGIDX_R28, + AVR8_REGIDX_R29, + AVR8_REGIDX_R30, + AVR8_REGIDX_R31, + AVR8_REGIDX_PINA = 0x20, + AVR8_REGIDX_DDRA, + AVR8_REGIDX_PORTA, + AVR8_REGIDX_PINB, + AVR8_REGIDX_DDRB, + AVR8_REGIDX_PORTB, + AVR8_REGIDX_PINC, + AVR8_REGIDX_DDRC, + AVR8_REGIDX_PORTC, + AVR8_REGIDX_PIND, + AVR8_REGIDX_DDRD, + AVR8_REGIDX_PORTD, + AVR8_REGIDX_PINE, + AVR8_REGIDX_DDRE, + AVR8_REGIDX_PORTE, + AVR8_REGIDX_PINF, + AVR8_REGIDX_DDRF, + AVR8_REGIDX_PORTF, + AVR8_REGIDX_PING, + AVR8_REGIDX_DDRG, + AVR8_REGIDX_PORTG, + AVR8_REGIDX_TIFR0 = 0x35, + AVR8_REGIDX_TIFR1, + AVR8_REGIDX_TIFR2, + AVR8_REGIDX_TIFR3, + AVR8_REGIDX_TIFR4, + AVR8_REGIDX_TIFR5, + AVR8_REGIDX_PCIFR = 0x3B, + AVR8_REGIDX_EIFR, + AVR8_REGIDX_EIMSK, + AVR8_REGIDX_GPIOR0, + AVR8_REGIDX_EECR, + AVR8_REGIDX_EEDR, + AVR8_REGIDX_EEARL, + AVR8_REGIDX_EEARH, + AVR8_REGIDX_GTCCR, + AVR8_REGIDX_TCCR0A, + AVR8_REGIDX_TCCR0B, + AVR8_REGIDX_TCNT0, + AVR8_REGIDX_OCR0A, + AVR8_REGIDX_OCR0B, + //0x49: Reserved + AVR8_REGIDX_GPIOR1 = 0x4A, + AVR8_REGIDX_GPIOR2, + AVR8_REGIDX_SPCR, + AVR8_REGIDX_SPSR, + AVR8_REGIDX_SPDR, + //0x4F: Reserved + AVR8_REGIDX_ACSR = 0x50, + AVR8_REGIDX_OCDR, + //0x52: Reserved + AVR8_REGIDX_SMCR = 0x53, + AVR8_REGIDX_MCUSR, + AVR8_REGIDX_MCUCR, + //0x56: Reserved + AVR8_REGIDX_SPMCSR = 0x57, + //0x58: Reserved + //0x59: Reserved + //0x5A: Reserved + AVR8_REGIDX_RAMPZ = 0x5B, + AVR8_REGIDX_EIND, + AVR8_REGIDX_SPL, + AVR8_REGIDX_SPH, + AVR8_REGIDX_SREG, +//-------------------------- + AVR8_REGIDX_WDTCSR = 0x60, + AVR8_REGIDX_CLKPR, + //0x62: Reserved + //0x63: Reserved + AVR8_REGIDX_PRR0 = 0x64, + AVR8_REGIDX_PRR1, + AVR8_REGIDX_OSCCAL, + //0x67: Reserved + AVR8_REGIDX_PCICR = 0x68, + AVR8_REGIDX_EICRA, + AVR8_REGIDX_EICRB, + AVR8_REGIDX_PCMSK0, + AVR8_REGIDX_PCMSK1, + AVR8_REGIDX_PCMSK2, + AVR8_REGIDX_TIMSK0, + AVR8_REGIDX_TIMSK1, + AVR8_REGIDX_TIMSK2, + AVR8_REGIDX_TIMSK3, + AVR8_REGIDX_TIMSK4, + AVR8_REGIDX_TIMSK5, + AVR8_REGIDX_XMCRA, + AVR8_REGIDX_XMCRB, + //0x76: Reserved + //0x77: Reserved + AVR8_REGIDX_ADCL = 0x78, + AVR8_REGIDX_ADCH, + AVR8_REGIDX_ADCSRA, + AVR8_REGIDX_ADCSRB, + AVR8_REGIDX_ADMUX, + AVR8_REGIDX_DIDR2, + AVR8_REGIDX_DIDR0, + AVR8_REGIDX_DIDR1, + AVR8_REGIDX_TCCR1A, + AVR8_REGIDX_TCCR1B, + AVR8_REGIDX_TCCR1C, + //0x83: Reserved + AVR8_REGIDX_TCNT1L = 0x84, + AVR8_REGIDX_TCNT1H, + AVR8_REGIDX_ICR1L, + AVR8_REGIDX_ICR1H, + AVR8_REGIDX_OCR1AL, + AVR8_REGIDX_OCR1AH, + AVR8_REGIDX_OCR1BL, + AVR8_REGIDX_OCR1BH, + AVR8_REGIDX_OCR1CL, + AVR8_REGIDX_OCR1CH, + //0x8E: Reserved + //0x8F: Reserved + AVR8_REGIDX_TCCR3A = 0x90, + AVR8_REGIDX_TCCR3B, + AVR8_REGIDX_TCCR3C, + //0x93: Reserved + AVR8_REGIDX_TCNT3L = 0x94, + AVR8_REGIDX_TCNT3H, + AVR8_REGIDX_ICR3L, + AVR8_REGIDX_ICR3H, + AVR8_REGIDX_OCR3AL, + AVR8_REGIDX_OCR3AH, + AVR8_REGIDX_OCR3BL, + AVR8_REGIDX_OCR3BH, + AVR8_REGIDX_OCR3CL, + AVR8_REGIDX_OCR3CH, + //0x9E: Reserved + //0x9F: Reserved + AVR8_REGIDX_TCCR4A = 0xA0, + AVR8_REGIDX_TCCR4B, + AVR8_REGIDX_TCCR4C, + //0xA3: Reserved + AVR8_REGIDX_TCNT4L = 0xA4, + AVR8_REGIDX_TCNT4H, + AVR8_REGIDX_ICR4L, + AVR8_REGIDX_ICR4H, + AVR8_REGIDX_OCR4AL, + AVR8_REGIDX_OCR4AH, + AVR8_REGIDX_OCR4BL, + AVR8_REGIDX_OCR4BH, + AVR8_REGIDX_OCR4CL, + AVR8_REGIDX_OCR4CH, + //0xAE: Reserved + //0xAF: Reserved + AVR8_REGIDX_TCCR2A = 0xB0, + AVR8_REGIDX_TCCR2B, + AVR8_REGIDX_TCNT2, + AVR8_REGIDX_OCR2A, + AVR8_REGIDX_OCR2B, + //0xB5: Reserved + AVR8_REGIDX_ASSR = 0xB6, + //0xB7: Reserved + AVR8_REGIDX_TWBR = 0xB8, + AVR8_REGIDX_TWSR, + AVR8_REGIDX_TWAR, + AVR8_REGIDX_TWDR, + AVR8_REGIDX_TWCR, + AVR8_REGIDX_TWAMR, + //0xBE: Reserved + //0xBF: Reserved + AVR8_REGIDX_UCSR0A = 0xC0, + AVR8_REGIDX_UCSR0B, + AVR8_REGIDX_UCSR0C, + //0xC3: Reserved + AVR8_REGIDX_UBRR0L = 0xC4, + AVR8_REGIDX_UBRR0H, + AVR8_REGIDX_UDR0, + //0xC7: Reserved + AVR8_REGIDX_UCSR1A = 0xC8, + AVR8_REGIDX_UCSR1B, + AVR8_REGIDX_UCSR1C, + //0xCB: Reserved + AVR8_REGIDX_UBRR1L = 0xCC, + AVR8_REGIDX_UBRR1H, + AVR8_REGIDX_UDR1, + //0xCF: Reserved + AVR8_REGIDX_UCSR2A = 0xD0, + AVR8_REGIDX_UCSR2B, + AVR8_REGIDX_UCSR2C, + //0xD3: Reserved + AVR8_REGIDX_UBRR2L = 0xD4, + AVR8_REGIDX_UBRR2H, + AVR8_REGIDX_UDR2, + //0xD7: Reserved + //0xD8: Reserved + //0xD9: Reserved + //0xDA: Reserved + //0xDB: Reserved + //0xDC: Reserved + //0xDD: Reserved + //0xDE: Reserved + //0xDF: Reserved + //0xE0: Reserved + //0xE1: Reserved + //0xE2: Reserved + //0xE3: Reserved + //0xE4: Reserved + //0xE5: Reserved + //0xE6: Reserved + //0xE7: Reserved + //0xE8: Reserved + //0xE9: Reserved + //0xEA: Reserved + //0xEB: Reserved + //0xEC: Reserved + //0xED: Reserved + //0xEE: Reserved + //0xEF: Reserved + //0xF0: Reserved + //0xF1: Reserved + //0xF2: Reserved + //0xF3: Reserved + //0xF4: Reserved + //0xF5: Reserved + //0xF6: Reserved + //0xF7: Reserved + //0xF8: Reserved + //0xF9: Reserved + //0xFA: Reserved + //0xFB: Reserved + //0xFC: Reserved + //0xFD: Reserved + //0xFE: Reserved + //0xFF: Reserved + AVR8_REGIDX_PINH = 0x100, + AVR8_REGIDX_DDRH, + AVR8_REGIDX_PORTH, + AVR8_REGIDX_PINJ, + AVR8_REGIDX_DDRJ, + AVR8_REGIDX_PORTJ, + AVR8_REGIDX_PINK, + AVR8_REGIDX_DDRK, + AVR8_REGIDX_PORTK, + AVR8_REGIDX_PINL, + AVR8_REGIDX_DDRL, + AVR8_REGIDX_PORTL, + //0x10C: Reserved + //0x10D: Reserved + //0x10E: Reserved + //0x10F: Reserved + //0x110: Reserved + //0x111: Reserved + //0x112: Reserved + //0x113: Reserved + //0x114: Reserved + //0x115: Reserved + //0x116: Reserved + //0x117: Reserved + //0x118: Reserved + //0x119: Reserved + //0x11A: Reserved + //0x11B: Reserved + //0x11C: Reserved + //0x11D: Reserved + //0x11E: Reserved + //0x11F: Reserved + AVR8_REGIDX_TCCR5A = 0x120, + AVR8_REGIDX_TCCR5B, + AVR8_REGIDX_TCCR5C, + //0x123: Reserved + AVR8_REGIDX_TCNT5L = 0x124, + AVR8_REGIDX_TCNT5H, + AVR8_REGIDX_ICR5L, + AVR8_REGIDX_ICR5H, + AVR8_REGIDX_OCR5AL, + AVR8_REGIDX_OCR5AH, + AVR8_REGIDX_OCR5BL, + AVR8_REGIDX_OCR5BH, + AVR8_REGIDX_OCR5CL, + AVR8_REGIDX_OCR5CH, + //0x12E: Reserved + //0x12F: Reserved + AVR8_REGIDX_UCSR3A = 0x130, + AVR8_REGIDX_UCSR3B, + AVR8_REGIDX_UCSR3C, + //0x133: Reserved + AVR8_REGIDX_UBRR3L = 0x134, + AVR8_REGIDX_UBRR3H, + AVR8_REGIDX_UDR3 + //0x137: Reserved + // . + // . up to + // . + //0x1FF: Reserved +}; + +enum { + AVR8_IO_PORTA = 0, + AVR8_IO_PORTB, + AVR8_IO_PORTC, + AVR8_IO_PORTD, + AVR8_IO_PORTE, + AVR8_IO_PORTF, + AVR8_IO_PORTG, + AVR8_IO_PORTH, + AVR8_IO_PORTJ, + AVR8_IO_PORTK, + AVR8_IO_PORTL +}; + +//TODO: AVR8_REG_* and AVR8_IO_PORT* seem to serve the same purpose and thus should be unified. Verify this! +enum +{ + AVR8_REG_A = 0, + AVR8_REG_B, + AVR8_REG_C, + AVR8_REG_D, + AVR8_REG_E, + AVR8_REG_F, + AVR8_REG_G, + AVR8_REG_H, + AVR8_REG_J, + AVR8_REG_K, + AVR8_REG_L +}; + +enum +{ + AVR8_INTIDX_SPI, + + AVR8_INTIDX_OCF0B, + AVR8_INTIDX_OCF0A, + AVR8_INTIDX_TOV0, + + AVR8_INTIDX_ICF1, + + AVR8_INTIDX_OCF1B, + AVR8_INTIDX_OCF1A, + AVR8_INTIDX_TOV1, + + AVR8_INTIDX_OCF2B, + AVR8_INTIDX_OCF2A, + AVR8_INTIDX_TOV2, + +//------ TODO: review this -------- + AVR8_INTIDX_OCF3B, + AVR8_INTIDX_OCF3A, + AVR8_INTIDX_TOV3, + + AVR8_INTIDX_OCF4B, + AVR8_INTIDX_OCF4A, + AVR8_INTIDX_TOV4, + + AVR8_INTIDX_OCF5B, + AVR8_INTIDX_OCF5A, + AVR8_INTIDX_TOV5, +//--------------------------------- + + AVR8_INTIDX_COUNT +}; + +//lock bit masks +enum +{ + LB1 = (1 << 0), + LB2 = (1 << 1), + BLB01 = (1 << 2), + BLB02 = (1 << 3), + BLB11 = (1 << 4), + BLB12 = (1 << 5) +}; + +//extended fuses bit masks +enum +{ + BODLEVEL0 = (1 << 0), + BODLEVEL1 = (1 << 1), + BODLEVEL2 = (1 << 2) +}; + +//high fuses bit masks +enum +{ + BOOTRST = (1 << 0), + BOOTSZ0 = (1 << 1), + BOOTSZ1 = (1 << 2), + EESAVE = (1 << 3), + WDTON = (1 << 4), + SPIEN = (1 << 5), + JTAGEN = (1 << 6), + OCDEN = (1 << 7) +}; + +//low fuses bit masks +enum +{ + CKSEL0 = (1 << 0), + CKSEL1 = (1 << 1), + CKSEL2 = (1 << 2), + CKSEL3 = (1 << 3), + SUT0 = (1 << 4), + SUT1 = (1 << 5), + CKOUT = (1 << 6), + CKDIV8 = (1 << 7) +}; + +#define AVR8_EEARH_MASK 0x01 + +#define AVR8_SPSR_SPIF_MASK 0x80 +#define AVR8_SPSR_SPIF_SHIFT 7 +#define AVR8_SPSR_SPR2X_MASK 0x01 + +#define AVR8_SPCR_SPIE_MASK 0x80 +#define AVR8_SPCR_SPE_MASK 0x40 +#define AVR8_SPCR_DORD_MASK 0x20 +#define AVR8_SPCR_MSTR_MASK 0x10 +#define AVR8_SPCR_CPOL_MASK 0x08 +#define AVR8_SPCR_CPHA_MASK 0x04 +#define AVR8_SPCR_SPR_MASK 0x03 + +CPU_DISASSEMBLE( avr8 ); + +#endif /* __AVR8_H__ */ diff --git a/src/devices/cpu/avr8/avr8dasm.c b/src/devices/cpu/avr8/avr8dasm.c new file mode 100644 index 00000000000..30f62779c8d --- /dev/null +++ b/src/devices/cpu/avr8/avr8dasm.c @@ -0,0 +1,674 @@ +// license:BSD-3-Clause +// copyright-holders:Ryan Holtz +/* + Atmel 8-bit AVR disassembler + + Written by MooglyGuy +*/ + +#include "emu.h" +#include "avr8.h" + +#define RD2(op) (((op) >> 4) & 0x0003) +#define RD3(op) (((op) >> 4) & 0x0007) +#define RD4(op) (((op) >> 4) & 0x000f) +#define RD5(op) (((op) >> 4) & 0x001f) +#define RR3(op) ((op) & 0x0007) +#define RR4(op) ((op) & 0x000f) +#define RR5(op) ((((op) >> 5) & 0x0010) | ((op) & 0x000f)) +#define KCONST6(op) ((((op) >> 2) & 0x0030) | ((op) & 0x000f)) +#define KCONST7(op) (((op) >> 3) & 0x007f) +#define KCONST8(op) ((((op) >> 4) & 0x00f0) | ((op) & 0x000f)) +#define KCONST22(op) (((((UINT32)(op) >> 3) & 0x003e) | ((UINT32)(op) & 0x0001)) << 16) +#define QCONST6(op) ((((op) >> 8) & 0x0020) | (((op) >> 7) & 0x0018) | ((op) & 0x0007)) +#define ACONST5(op) (((op) >> 3) & 0x001f) +#define ACONST6(op) ((((op) >> 5) & 0x0030) | ((op) & 0x000f)) +#define MULCONST2(op) ((((op) >> 6) & 0x0002) | (((op) >> 3) & 0x0001)) + +CPU_DISASSEMBLE( avr8 ) +{ + char *output = buffer; + int pos = 0; + UINT32 op = oprom[pos++]; + op |= oprom[pos++] << 8; + UINT32 addr = 0; + const char* register_names[0x40] = {"PINA", "DDRA", "PORTA", "PINB", "DDRB", "PORTB", "PINC", "DDRC", "PORTC", "PIND", "DDRD", "PORTD", "PINE", "DDRE", "PORTE", "PINF", "DDRF", "PORTF", "PING", "DDRG", "PORTG", "TIFR0", "TIFR1", "TIFR2","TIFR3", "TIFR4", "TIFR5", "PCIFR", "EIFR", "EIMSK", "GPIOR0", "EECR", "EEDR", "EEARL", "EEARH", "GTCCR", "TCCR0A", "TCCR0B", "TCNT0", "OCR0A", "OCR0B", "0x29", "GPIOR1", "GPIOR2", "SPCR", "SPSR", "SPDR", "0x2F", "ACSR", "OCDR", "0x32", "SMCR", "MCUSR", "MCUCR", "0x36", "SPMCSR", "0x38", "0x39", "0x3A", "RAMPZ", "EIND", "SPL", "SPH", "SREG"}; + + const char* register_bit_names[0x40][8] = { + /* PINA */ { "0", "1", "2", "3", "4", "5", "6", "7"}, + /* DDRA */ { "0", "1", "2", "3", "4", "5", "6", "7"}, + /* PORTA */ { "0", "1", "2", "3", "4", "5", "6", "7"}, + /* PINB */ { "0", "1", "2", "3", "4", "5", "6", "7"}, + /* DDRB */ { "0", "1", "2", "3", "4", "5", "6", "7"}, + /* PORTB */ { "0", "1", "2", "3", "4", "5", "6", "7"}, + /* PINC */ { "0", "1", "2", "3", "4", "5", "6", "7"}, + /* DDRC */ { "0", "1", "2", "3", "4", "5", "6", "7"}, + /* PORTC */ { "0", "1", "2", "3", "4", "5", "6", "7"}, + /* PIND */ { "0", "1", "2", "3", "4", "5", "6", "7"}, + /* DDRD */ { "0", "1", "2", "3", "4", "5", "6", "7"}, + /* PORTD */ { "0", "1", "2", "3", "4", "5", "6", "7"}, + /* PINE */ { "0", "1", "2", "3", "4", "5", "6", "7"}, + /* DDRE */ { "0", "1", "2", "3", "4", "5", "6", "7"}, + /* PORTE */ { "0", "1", "2", "3", "4", "5", "6", "7"}, + /* PINF */ { "0", "1", "2", "3", "4", "5", "6", "7"}, + /* DDRF */ { "0", "1", "2", "3", "4", "5", "6", "7"}, + /* PORTF */ { "0", "1", "2", "3", "4", "5", "6", "7"}, + /* PING */ { "0", "1", "2", "3", "4", "5", "6", "7"}, + /* DDRG */ { "0", "1", "2", "3", "4", "5", "6", "7"}, + /* PORTG */ { "0", "1", "2", "3", "4", "5", "6", "7"}, + /* TIFR0 */ { "TOV0", "OCF0A", "OCF0B", "3", "4", "5", "6", "7"}, + /* TIFR1 */ { "TOV1", "OCF1A", "OCF1B", "OCF1C", "4", "ICF1", "6", "7"}, + /* TIFR2 */ { "TOV2", "OCF2A", "OCF2B", "3", "4", "5", "6", "7"}, + /* TIFR3 */ { "TOV3", "OCF3A", "OCF3B", "OCF3C", "4", "ICF3", "6", "7"}, + /* TIFR4 */ { "TOV4", "OCF4A", "OCF4B", "OCF4C", "4", "ICF4", "6", "7"}, + /* TIFR5 */ { "TOV5", "OCF5A", "OCF5B", "OCF5C", "4", "ICF5", "6", "7"}, + /* PCIFR */ {"PCIF0", "PCIF1", "PCIF2", "3", "4", "5", "6", "7"}, + /* EIFR */ {"INTF0", "INTF1", "INTF2", "INTF3", "INTF4", "INTF5", "INTF6", "INTF7"}, + /* EIMSK */ { "INT0", "INT1", "INT2", "INT3", "INT4", "INT5", "INT6", "INT7"}, + /* GPIOR0 */ { "0", "1", "2", "3", "4", "5", "6", "7"}, + /* EECR */ { "EERE", "EEPE", "EEMPE", "EERIE", "EEPM0", "EEPM1", "6", "7"}, + /* EEDR */ { "0", "1", "2", "3", "4", "5", "6", "7"}, + /* EEARL */ { "0", "1", "2", "3", "4", "5", "6", "7"}, + /* EEARH */ { "0", "1", "2", "3", "4", "5", "6", "7"}, + /* GTCCR */ {"PSRSYNC", "PSRASY", "2", "3", "4", "5", "6", "TSM"}, + /* TCCR0A */ {"WGM00", "WGM01", "2", "3","COM0B0","COM0B1","COM0A0","COM0A1"}, + /* TCCR0B */ { "CS0", "CS1", "CS2", "WGM02", "4", "5", "FOC0B", "FOC0A"}, + /* TCNT0 */ { "0", "1", "2", "3", "4", "5", "6", "7"}, + /* OCR0A */ { "0", "1", "2", "3", "4", "5", "6", "7"}, + /* OCR0B */ { "0", "1", "2", "3", "4", "5", "6", "7"}, + /* 0x29 */ { "0", "1", "2", "3", "4", "5", "6", "7"}, + /* GPIOR1 */ { "0", "1", "2", "3", "4", "5", "6", "7"}, + /* GPIOR2 */ { "0", "1", "2", "3", "4", "5", "6", "7"}, + /* SPCR */ { "SPR0", "SPR1", "CPHA", "CPOL", "MSTR", "DORD", "SPE", "SPIE"}, + /* SPSR */ {"SPI2X", "1", "2", "3", "4", "5", "WCOL", "SPIF"}, + /* SPDR */ { "0", "1", "2", "3", "4", "5", "6", "7"}, + /* 0x2F */ { "0", "1", "2", "3", "4", "5", "6", "7"}, + /* ACSR */ {"ACIS0", "ACIS1", "ACIC", "ACIE", "ACI", "ACO", "ACBG", "ACD"}, + /* OCDR */ { "0", "1", "2", "3", "4", "5", "6", "7"}, + /* 0x32 */ { "0", "1", "2", "3", "4", "5", "6", "7"}, + /* SMCR */ { "SE", "SM0", "SM1", "SM2", "4", "5", "6", "7"}, + /* MCUSR */ { "PORF", "EXTRF", "BORF", "WDRF", "JTRF", "5", "6", "7"}, + /* MCUCR */ { "IVCE", "IVSEL", "2", "3", "PUD", "5", "6", "JTD"}, + /* 0x36 */ { "0", "1", "2", "3", "4", "5", "6", "7"}, + /* SPMCSR */ {"SPMEN", "PGERS", "PGWRT","BLBSET","RWWSRE", "SIGRD", "RWWSB", "SPMIE"}, + /* 0x38 */ { "0", "1", "2", "3", "4", "5", "6", "7"}, + /* 0x39 */ { "0", "1", "2", "3", "4", "5", "6", "7"}, + /* 0x3A */ { "0", "1", "2", "3", "4", "5", "6", "7"}, + /* RAMPZ */ {"RAMPZ0","RAMPZ1", "2", "3", "4", "5", "6", "7"}, + /* EIND */ {"EIND0", "1", "2", "3", "4", "5", "6", "7"}, + /* SPL */ { "SP0", "SP1", "SP2", "SP3", "SP4", "SP5", "SP6", "SP7"}, + /* SPH */ { "SP8", "SP9", "SP10", "SP11", "SP12", "SP13", "SP14", "SP15"}, + /* SREG */ { "C", "Z", "N", "V", "S", "H", "T", "I"}}; + + switch(op & 0xf000) + { + case 0x0000: + switch(op & 0x0f00) + { + case 0x0000: + output += sprintf( output, "NOP" ); + break; + case 0x0100: + output += sprintf( output, "MOVW R%d:R%d, R%d:R%d", (RD4(op) << 1)+1, RD4(op) << 1, (RR4(op) << 1)+1, RR4(op) << 1 ); + break; + case 0x0200: + output += sprintf( output, "MULS R%d, R%d", 16+RD4(op), 16+RR4(op) ); + break; + case 0x0300: + switch(MULCONST2(op)) + { + case 0: + output += sprintf( output, "MULSU R%d, R%d", 16+RD3(op), 16+RR3(op) ); + break; + case 1: + output += sprintf( output, "FMUL R%d, R%d", 16+RD3(op), 16+RR3(op) ); + break; + case 2: + output += sprintf( output, "FMULS R%d, R%d", 16+RD3(op), 16+RR3(op) ); + break; + case 3: + output += sprintf( output, "FMULSU R%d, R%d", 16+RD3(op), 16+RR3(op) ); + break; + } + break; + case 0x0400: + case 0x0500: + case 0x0600: + case 0x0700: + output += sprintf( output, "CPC R%d, R%d", RD5(op), RR5(op) ); + break; + case 0x0800: + case 0x0900: + case 0x0a00: + case 0x0b00: + output += sprintf( output, "SBC R%d, R%d", RD5(op), RR5(op) ); + break; + case 0x0c00: + case 0x0d00: + case 0x0e00: + case 0x0f00: + output += sprintf( output, "ADD R%d, R%d", RD5(op), RR5(op) ); + break; + } + break; + case 0x1000: + switch(op & 0x0c00) + { + case 0x0000: + output += sprintf( output, "CPSE R%d, R%d", RD5(op), RR5(op) ); + break; + case 0x0400: + output += sprintf( output, "CP R%d, R%d", RD5(op), RR5(op) ); + break; + case 0x0800: + output += sprintf( output, "SUB R%d, R%d", RD5(op), RR5(op) ); + break; + case 0x0c00: + output += sprintf( output, "ADC R%d, R%d", RD5(op), RR5(op) ); + break; + } + break; + case 0x2000: + switch(op & 0x0c00) + { + case 0x0000: + output += sprintf( output, "AND R%d, R%d", RD5(op), RR5(op) ); + break; + case 0x0400: + output += sprintf( output, "EOR R%d, R%d", RD5(op), RR5(op) ); + break; + case 0x0800: + output += sprintf( output, "OR R%d, R%d", RD5(op), RR5(op) ); + break; + case 0x0c00: + output += sprintf( output, "MOV R%d, R%d", RD5(op), RR5(op) ); + break; + } + break; + case 0x3000: + output += sprintf( output, "CPI R%d, 0x%02x", 16+RD4(op), KCONST8(op) ); + break; + case 0x4000: + output += sprintf( output, "SBCI R%d, 0x%02x", 16+RD4(op), KCONST8(op) ); + break; + case 0x5000: + output += sprintf( output, "SUBI R%d, 0x%02x", 16+RD4(op), KCONST8(op) ); + break; + case 0x6000: + output += sprintf( output, "ORI R%d, 0x%02x", 16+RD4(op), KCONST8(op) ); + break; + case 0x7000: + output += sprintf( output, "ANDI R%d, 0x%02x", 16+RD4(op), KCONST8(op) ); + break; + case 0x8000: + case 0xa000: + switch(op & 0x0208) + { + case 0x0000: + output += sprintf( output, "LD(D) R%d, Z+%02x", RD5(op), QCONST6(op) ); + break; + case 0x0008: + output += sprintf( output, "LD(D) R%d, Y+%02x", RD5(op), QCONST6(op) ); + break; + case 0x0200: + output += sprintf( output, "ST(D) Z+%02x, R%d", QCONST6(op), RD5(op) ); + break; + case 0x0208: + output += sprintf( output, "ST(D) Y+%02x, R%d", QCONST6(op), RD5(op) ); + break; + } + break; + case 0x9000: + switch(op & 0x0f00) + { + case 0x0000: + case 0x0100: + switch(op & 0x000f) + { + case 0x0000: + op <<= 16; + op |= oprom[pos++]; + op |= oprom[pos++] << 8; + output += sprintf( output, "LDS R%d, (0x%04x)", RD5(op >> 16), op & 0x0000ffff ); + break; + case 0x0001: + output += sprintf( output, "LD R%d, Z+", RD5(op) ); + break; + case 0x0002: + output += sprintf( output, "LD R%d,-Z", RD5(op) ); + break; + case 0x0004: + output += sprintf( output, "LPM R%d, Z", RD5(op) ); + break; + case 0x0005: + output += sprintf( output, "LPM R%d, Z+", RD5(op) ); + break; + case 0x0006: + output += sprintf( output, "ELPM R%d, Z", RD5(op) ); + break; + case 0x0007: + output += sprintf( output, "ELPM R%d, Z+", RD5(op) ); + break; + case 0x0009: + output += sprintf( output, "LD R%d, Y+", RD5(op) ); + break; + case 0x000a: + output += sprintf( output, "LD R%d,-Y", RD5(op) ); + break; + case 0x000c: + output += sprintf( output, "LD R%d, X", RD5(op) ); + break; + case 0x000d: + output += sprintf( output, "LD R%d, X+", RD5(op) ); + break; + case 0x000e: + output += sprintf( output, "LD R%d,-X", RD5(op) ); + break; + case 0x000f: + output += sprintf( output, "POP R%d", RD5(op) ); + break; + default: + output += sprintf( output, "Undefined (%08x)", op ); + break; + } + break; + case 0x0200: + case 0x0300: + switch(op & 0x000f) + { + case 0x0000: + op <<= 16; + op |= oprom[pos++]; + op |= oprom[pos++] << 8; + output += sprintf( output, "STS (0x%04x), R%d", op & 0x0000ffff, RD5(op >> 16) ); + break; + case 0x0001: + output += sprintf( output, "ST Z+, R%d", RD5(op) ); + break; + case 0x0002: + output += sprintf( output, "ST -Z , R%d", RD5(op) ); + break; + case 0x0009: + output += sprintf( output, "ST Y+, R%d", RD5(op) ); + break; + case 0x000a: + output += sprintf( output, "ST -Y , R%d", RD5(op) ); + break; + case 0x000c: + output += sprintf( output, "ST X , R%d", RD5(op) ); + break; + case 0x000d: + output += sprintf( output, "ST X+, R%d", RD5(op) ); + break; + case 0x000e: + output += sprintf( output, "ST -X , R%d", RD5(op) ); + break; + case 0x000f: + output += sprintf( output, "PUSH R%d", RD5(op) ); + break; + default: + output += sprintf( output, "Undefined (%08x)", op ); + break; + } + break; + case 0x0400: + switch(op & 0x000f) + { + case 0x0000: + output += sprintf( output, "COM R%d", RD5(op) ); + break; + case 0x0001: + output += sprintf( output, "NEG R%d", RD5(op) ); + break; + case 0x0002: + output += sprintf( output, "SWAP R%d", RD5(op) ); + break; + case 0x0003: + output += sprintf( output, "INC R%d", RD5(op) ); + break; + case 0x0005: + output += sprintf( output, "ASR R%d", RD5(op) ); + break; + case 0x0006: + output += sprintf( output, "LSR R%d", RD5(op) ); + break; + case 0x0007: + output += sprintf( output, "ROR R%d", RD5(op) ); + break; + case 0x0008: + switch(op & 0x00f0) + { + case 0x0000: + output += sprintf( output, "SEC" ); + break; + case 0x0010: + output += sprintf( output, "SEZ" ); + break; + case 0x0020: + output += sprintf( output, "SEN" ); + break; + case 0x0030: + output += sprintf( output, "SEV" ); + break; + case 0x0040: + output += sprintf( output, "SES" ); + break; + case 0x0050: + output += sprintf( output, "SEH" ); + break; + case 0x0060: + output += sprintf( output, "SET" ); + break; + case 0x0070: + output += sprintf( output, "SEI" ); + break; + case 0x0080: + output += sprintf( output, "CLC" ); + break; + case 0x0090: + output += sprintf( output, "CLZ" ); + break; + case 0x00a0: + output += sprintf( output, "CLN" ); + break; + case 0x00b0: + output += sprintf( output, "CLV" ); + break; + case 0x00c0: + output += sprintf( output, "CLS" ); + break; + case 0x00d0: + output += sprintf( output, "CLH" ); + break; + case 0x00e0: + output += sprintf( output, "CLT" ); + break; + case 0x00f0: + output += sprintf( output, "CLI" ); + break; + default: + output += sprintf( output, "Undefined (%08x)", op ); + break; + } + break; + case 0x0009: + switch(op & 0x00f0) + { + case 0x0000: + output += sprintf( output, "IJMP" ); + break; + case 0x0010: + output += sprintf( output, "EIJMP" ); + break; + default: + output += sprintf( output, "Undefined (%08x)", op ); + break; + } + break; + case 0x000a: + output += sprintf( output, "DEC R%d", RD5(op) ); + break; + case 0x000c: + case 0x000d: + addr = KCONST22(op) << 16; + addr |= oprom[pos++]; + addr |= oprom[pos++] << 8; + output += sprintf( output, "JMP 0x%06x", addr << 1 ); + break; + case 0x000e: + case 0x000f: + addr = KCONST22(op) << 16; + addr |= oprom[pos++]; + addr |= oprom[pos++] << 8; + output += sprintf( output, "CALL 0x%06x", addr << 1 ); + break; + default: + output += sprintf( output, "Undefined (%08x)", op ); + break; + } + break; + case 0x0500: + switch(op & 0x000f) + { + case 0x0000: + output += sprintf( output, "COM R%d", RD5(op) ); + break; + case 0x0001: + output += sprintf( output, "NEG R%d", RD5(op) ); + break; + case 0x0002: + output += sprintf( output, "SWAP R%d", RD5(op) ); + break; + case 0x0003: + output += sprintf( output, "INC R%d", RD5(op) ); + break; + case 0x0005: + output += sprintf( output, "ASR R%d", RD5(op) ); + break; + case 0x0006: + output += sprintf( output, "LSR R%d", RD5(op) ); + break; + case 0x0007: + output += sprintf( output, "ROR R%d", RD5(op) ); + break; + case 0x0008: + switch(op & 0x00f0) + { + case 0x0000: + output += sprintf( output, "RET" ); + break; + case 0x0010: + output += sprintf( output, "RETI" ); + break; + case 0x0080: + output += sprintf( output, "SLEEP" ); + break; + case 0x0090: + output += sprintf( output, "BREAK" ); + break; + case 0x00a0: + output += sprintf( output, "WDR" ); + break; + case 0x00c0: + output += sprintf( output, "LPM" ); + break; + case 0x00d0: + output += sprintf( output, "ELPM" ); + break; + case 0x00e0: + output += sprintf( output, "SPM" ); + break; + case 0x00f0: + output += sprintf( output, "SPM Z+" ); + break; + default: + output += sprintf( output, "Undefined (%08x)", op ); + break; + } + break; + case 0x0009: + switch(op & 0x00f0) + { + case 0x0000: + output += sprintf( output, "ICALL" ); + break; + case 0x0010: + output += sprintf( output, "EICALL" ); + break; + default: + output += sprintf( output, "Undefined (%08x)", op ); + break; + } + break; + case 0x000a: + output += sprintf( output, "DEC R%d", RD5(op) ); + break; + case 0x000c: + case 0x000d: + op <<= 16; + op |= oprom[pos++]; + op |= oprom[pos++] << 8; + output += sprintf( output, "JMP 0x%06x", KCONST22(op) << 1 ); + break; + case 0x000e: + case 0x000f: + op <<= 16; + op |= oprom[pos++]; + op |= oprom[pos++] << 8; + output += sprintf( output, "CALL 0x%06x", KCONST22(op) << 1 ); + break; + } + break; + case 0x0600: + output += sprintf( output, "ADIW R%d:R%d, 0x%02x", 24+(RD2(op) << 1)+1, 24+(RD2(op) << 1), KCONST6(op) ); + break; + case 0x0700: + output += sprintf( output, "SBIW R%d:R%d, 0x%02x", 24+(RD2(op) << 1)+1, 24+(RD2(op) << 1), KCONST6(op) ); + break; + case 0x0800: + if (ACONST5(op) < 0x20) + output += sprintf( output, "CBI %s, %s", register_names[ACONST5(op)], register_bit_names[ACONST5(op)][RR3(op)] ); + else + output += sprintf( output, "CBI 0x%02x, %d", ACONST5(op), RR3(op) ); + break; + case 0x0900: + if (ACONST5(op) < 0x20) + output += sprintf( output, "SBIC %s, %s", register_names[ACONST5(op)], register_bit_names[ACONST5(op)][RR3(op)] ); + else + output += sprintf( output, "SBIC 0x%02x, %d", ACONST5(op), RR3(op) ); + break; + case 0x0a00: + if (ACONST5(op) < 0x20) + output += sprintf( output, "SBI %s, %s", register_names[ACONST5(op)], register_bit_names[ACONST5(op)][RR3(op)] ); + else + output += sprintf( output, "SBI 0x%02x, %d", ACONST5(op), RR3(op) ); + break; + case 0x0b00: + if (ACONST5(op) < 0x20) + output += sprintf( output, "SBIS %s, %s", register_names[ACONST5(op)], register_bit_names[ACONST5(op)][RR3(op)] ); + else + output += sprintf( output, "SBIS 0x%02x, %d", ACONST5(op), RR3(op) ); + break; + case 0x0c00: + case 0x0d00: + case 0x0e00: + case 0x0f00: + output += sprintf( output, "MUL R%d, R%d", RD5(op), RR5(op) ); + break; + } + break; + case 0xb000: + if(op & 0x0800) + { + if (ACONST6(op) < 0x40 ) { + output += sprintf( output, "OUT %s, R%d", register_names[ACONST6(op)], RD5(op) ); + } else { + output += sprintf( output, "OUT 0x%02x, R%d", ACONST6(op), RD5(op) ); + } + } + else + { + if (ACONST6(op) < 0x40 ) { + output += sprintf( output, "IN R%d, %s", RD5(op), register_names[ACONST6(op)] ); + } else { + output += sprintf( output, "IN R%d, 0x%02x", RD5(op), ACONST6(op) ); + } + } + break; + case 0xc000: + //I'm not sure if this is correct. why pc + ... : pc + 8 + ... ? + output += sprintf( output, "RJMP %08x", (((op & 0x0800) ? pc + ((op & 0x0fff) | 0xfffff000) : pc + 8 + (op & 0x0fff)) << 0) ); + break; + case 0xd000: + output += sprintf( output, "RCALL %08x", (((op & 0x0800) ? ((op & 0x0fff) | 0xfffff000) : (op & 0x0fff)) << 1) ); + break; + case 0xe000: + output += sprintf( output, "LDI R%d, 0x%02x", 16 + RD4(op), KCONST8(op) ); + break; + case 0xf000: + switch(op & 0x0c00) + { + case 0x0000: + switch(op & 0x0007) + { + case 0x0000: + output += sprintf( output, "BRLO %08x", (((op & 0x0200) ? ((KCONST7(op) & 0x007f) | 0xff80) : KCONST7(op)) << 1) ); + break; + case 0x0001: + output += sprintf( output, "BREQ %08x", (((op & 0x0200) ? ((KCONST7(op) & 0x007f) | 0xff80) : KCONST7(op)) << 1) ); + break; + case 0x0002: + output += sprintf( output, "BRMI %08x", (((op & 0x0200) ? ((KCONST7(op) & 0x007f) | 0xff80) : KCONST7(op)) << 1) ); + break; + case 0x0003: + output += sprintf( output, "BRVS %08x", (((op & 0x0200) ? ((KCONST7(op) & 0x007f) | 0xff80) : KCONST7(op)) << 1) ); + break; + case 0x0004: + output += sprintf( output, "BRLT %08x", (((op & 0x0200) ? ((KCONST7(op) & 0x007f) | 0xff80) : KCONST7(op)) << 1) ); + break; + case 0x0005: + output += sprintf( output, "BRHS %08x", (((op & 0x0200) ? ((KCONST7(op) & 0x007f) | 0xff80) : KCONST7(op)) << 1) ); + break; + case 0x0006: + output += sprintf( output, "BRTS %08x", (((op & 0x0200) ? ((KCONST7(op) & 0x007f) | 0xff80) : KCONST7(op)) << 1) ); + break; + case 0x0007: + output += sprintf( output, "BRIE %08x", (((op & 0x0200) ? ((KCONST7(op) & 0x007f) | 0xff80) : KCONST7(op)) << 1) ); + break; + } + break; + case 0x0400: + switch(op & 0x0007) + { + case 0x0000: + output += sprintf( output, "BRSH %08x", (((op & 0x0200) ? ((KCONST7(op) & 0x007f) | 0xff80) : KCONST7(op)) << 1) ); + break; + case 0x0001: + output += sprintf( output, "BRNE %08x", (((op & 0x0200) ? ((KCONST7(op) & 0x007f) | 0xff80) : KCONST7(op)) << 1) ); + break; + case 0x0002: + output += sprintf( output, "BRPL %08x", (((op & 0x0200) ? ((KCONST7(op) & 0x007f) | 0xff80) : KCONST7(op)) << 1) ); + break; + case 0x0003: + output += sprintf( output, "BRVC %08x", (((op & 0x0200) ? ((KCONST7(op) & 0x007f) | 0xff80) : KCONST7(op)) << 1) ); + break; + case 0x0004: + output += sprintf( output, "BRGE %08x", (((op & 0x0200) ? ((KCONST7(op) & 0x007f) | 0xff80) : KCONST7(op)) << 1) ); + break; + case 0x0005: + output += sprintf( output, "BRHC %08x", (((op & 0x0200) ? ((KCONST7(op) & 0x007f) | 0xff80) : KCONST7(op)) << 1) ); + break; + case 0x0006: + output += sprintf( output, "BRTC %08x", (((op & 0x0200) ? ((KCONST7(op) & 0x007f) | 0xff80) : KCONST7(op)) << 1) ); + break; + case 0x0007: + output += sprintf( output, "BRID %08x", (((op & 0x0200) ? ((KCONST7(op) & 0x007f) | 0xff80) : KCONST7(op)) << 1) ); + break; + } + break; + case 0x0800: + if(op & 0x0200) + { + output += sprintf( output, "BST R%d, %d", RD5(op), RR3(op) ); + } + else + { + output += sprintf( output, "BLD R%d, %d", RD5(op), RR3(op) ); + } + break; + case 0x0c00: + if(op & 0x0200) + { + output += sprintf( output, "SBRS R%d, %d", RD5(op), RR3(op) ); + } + else + { + output += sprintf( output, "SBRC R%d, %d", RD5(op), RR3(op) ); + } + break; + } + break; + } + + return pos | DASMFLAG_SUPPORTED; +} diff --git a/src/devices/cpu/ccpu/ccpu.c b/src/devices/cpu/ccpu/ccpu.c new file mode 100644 index 00000000000..e8893580f0c --- /dev/null +++ b/src/devices/cpu/ccpu/ccpu.c @@ -0,0 +1,689 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + ccpu.c + Core implementation for the portable Cinematronics CPU emulator. + + Written by Aaron Giles + Special thanks to Zonn Moore for his detailed documentation. + +***************************************************************************/ + +#include "emu.h" +#include "debugger.h" +#include "ccpu.h" + + +const device_type CCPU = &device_creator; + + +/*************************************************************************** + MACROS +***************************************************************************/ + +#define READOP(a) (m_direct->read_byte(a)) + +#define RDMEM(a) (m_data->read_word((a) * 2) & 0xfff) +#define WRMEM(a,v) (m_data->write_word((a) * 2, (v))) + +#define READPORT(a) (m_io->read_byte(a)) +#define WRITEPORT(a,v) (m_io->write_byte((a), (v))) + +#define SET_A0 do { m_a0flag = m_A; } while (0) +#define SET_CMP_VAL(x) do { m_cmpacc = *m_acc; m_cmpval = (x) & 0xfff; } while (0) +#define SET_NC(a) do { m_ncflag = ~(a); } while (0) +#define SET_MI(a) do { m_nextnextmiflag = (a); } while (0) + +#define TEST_A0 (m_a0flag & 1) +#define TEST_NC ((m_ncflag >> 12) & 1) +#define TEST_MI ((m_miflag >> 11) & 1) +#define TEST_LT (m_cmpval < m_cmpacc) +#define TEST_EQ (m_cmpval == m_cmpacc) +#define TEST_DR (m_drflag != 0) + +#define NEXT_ACC_A do { SET_MI(*m_acc); m_acc = &m_A; } while (0) +#define NEXT_ACC_B do { SET_MI(*m_acc); if (m_acc == &m_A) m_acc = &m_B; else m_acc = &m_A; } while (0) + +#define CYCLES(x) do { m_icount -= (x); } while (0) + +#define STANDARD_ACC_OP(resexp,cmpval) \ +do { \ + UINT16 result = resexp; \ + SET_A0; /* set the A0 bit based on the previous 'A' value */ \ + SET_CMP_VAL(cmpval); /* set the compare values to the previous accumulator and the cmpval */ \ + SET_NC(result); /* set the NC flag based on the unmasked result */ \ + *m_acc = result & 0xfff; /* store the low 12 bits of the new value */ \ +} while (0) + + + +/*************************************************************************** + INITIALIZATION AND SHUTDOWN +***************************************************************************/ + +ccpu_cpu_device::ccpu_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : cpu_device(mconfig, CCPU, "Cinematronics CPU", tag, owner, clock, "ccpu", __FILE__) + , m_program_config("program", ENDIANNESS_BIG, 8, 15, 0) + , m_data_config("data", ENDIANNESS_BIG, 16, 32, -1) + , m_io_config("io", ENDIANNESS_BIG, 8, 5, 0) + , m_external_input(*this) + , m_flags(0) +{ +} + + +READ8_MEMBER( ccpu_cpu_device::read_jmi ) +{ + /* this routine is called when there is no external input */ + /* and the JMI jumper is present */ + return TEST_MI; +} + + +void ccpu_cpu_device::wdt_timer_trigger() +{ + m_waiting = FALSE; + m_watchdog++; + if (m_watchdog >= 3) + m_PC = 0; +} + + +void ccpu_cpu_device::device_start() +{ + /* copy input params */ + m_external_input.resolve_safe(0); + m_vector_callback.bind_relative_to(*owner()); + assert(!m_vector_callback.isnull()); + + m_program = &space(AS_PROGRAM); + m_direct = &m_program->direct(); + m_data = &space(AS_DATA); + m_io = &space(AS_IO); + + save_item(NAME(m_PC)); + save_item(NAME(m_A)); + save_item(NAME(m_B)); + save_item(NAME(m_I)); + save_item(NAME(m_J)); + save_item(NAME(m_P)); + save_item(NAME(m_X)); + save_item(NAME(m_Y)); + save_item(NAME(m_T)); + save_item(NAME(m_a0flag)); + save_item(NAME(m_ncflag)); + save_item(NAME(m_cmpacc)); + save_item(NAME(m_cmpval)); + save_item(NAME(m_miflag)); + save_item(NAME(m_nextmiflag)); + save_item(NAME(m_nextnextmiflag)); + save_item(NAME(m_drflag)); + save_item(NAME(m_waiting)); + save_item(NAME(m_watchdog)); + + // Register state for debugger + state_add( CCPU_PC, "PC", m_PC).formatstr("%04X"); + state_add( CCPU_A, "A", m_A).mask(0xfff).formatstr("%03X"); + state_add( CCPU_B, "B", m_B).mask(0xfff).formatstr("%03X"); + state_add( CCPU_I, "I", m_I).mask(0xfff).formatstr("%03X"); + state_add( CCPU_J, "J", m_J).mask(0xfff).formatstr("%03X"); + state_add( CCPU_P, "P", m_P).mask(0xf).formatstr("%1X"); + state_add( CCPU_X, "X", m_X).mask(0xfff).formatstr("%03X"); + state_add( CCPU_Y, "Y", m_Y).mask(0xfff).formatstr("%03X"); + state_add( CCPU_T, "T", m_T).mask(0xfff).formatstr("%03X"); + state_add(STATE_GENPC, "curpc", m_PC).noshow(); + state_add(STATE_GENFLAGS, "GENFLAGS", m_flags).formatstr("%6s").noshow(); + + m_icountptr = &m_icount; +} + + +void ccpu_cpu_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + switch (entry.index()) + { + case STATE_GENFLAGS: + strprintf(str, "%c%c%c%c%c%c", + TEST_A0 ? '0' : 'o', + TEST_NC ? 'N' : 'n', + TEST_LT ? 'L' : 'l', + TEST_EQ ? 'E' : 'e', + m_external_input() ? 'M' : 'm', + TEST_DR ? 'D' : 'd'); + break; + } +} + + +void ccpu_cpu_device::device_reset() +{ + /* zero registers */ + m_PC = 0; + m_A = 0; + m_B = 0; + m_I = 0; + m_J = 0; + m_P = 0; + m_X = 0; + m_Y = 0; + m_T = 0; + m_acc = &m_A; + + /* zero flags */ + m_a0flag = 0; + m_ncflag = 0; + m_cmpacc = 0; + m_cmpval = 1; + m_miflag = m_nextmiflag = m_nextnextmiflag = 0; + m_drflag = 0; + + m_waiting = FALSE; + m_watchdog = 0; +} + + + +/*************************************************************************** + CORE EXECUTION LOOP +***************************************************************************/ + +void ccpu_cpu_device::execute_run() +{ + if (m_waiting) + { + m_icount = 0; + return; + } + + do + { + UINT16 tempval; + UINT8 opcode; + + /* update the delayed MI flag */ + m_miflag = m_nextmiflag; + m_nextmiflag = m_nextnextmiflag; + + /* fetch the opcode */ + debugger_instruction_hook(this, m_PC); + opcode = READOP(m_PC++); + + switch (opcode) + { + /* LDAI */ + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x04: case 0x05: case 0x06: case 0x07: + case 0x08: case 0x09: case 0x0a: case 0x0b: + case 0x0c: case 0x0d: case 0x0e: case 0x0f: + tempval = (opcode & 0x0f) << 8; + STANDARD_ACC_OP(tempval, tempval); + NEXT_ACC_A; CYCLES(1); + break; + + /* INP */ + case 0x10: case 0x11: case 0x12: case 0x13: + case 0x14: case 0x15: case 0x16: case 0x17: + case 0x18: case 0x19: case 0x1a: case 0x1b: + case 0x1c: case 0x1d: case 0x1e: case 0x1f: + if (m_acc == &m_A) + tempval = READPORT(opcode & 0x0f) & 1; + else + tempval = READPORT(16 + (opcode & 0x07)) & 1; + STANDARD_ACC_OP(tempval, tempval); + NEXT_ACC_A; CYCLES(1); + break; + + /* A8I */ + case 0x20: + tempval = READOP(m_PC++); + STANDARD_ACC_OP(*m_acc + tempval, tempval); + NEXT_ACC_A; CYCLES(3); + break; + + /* A4I */ + case 0x21: case 0x22: case 0x23: + case 0x24: case 0x25: case 0x26: case 0x27: + case 0x28: case 0x29: case 0x2a: case 0x2b: + case 0x2c: case 0x2d: case 0x2e: case 0x2f: + tempval = opcode & 0x0f; + STANDARD_ACC_OP(*m_acc + tempval, tempval); + NEXT_ACC_A; CYCLES(1); + break; + + /* S8I */ + case 0x30: + tempval = READOP(m_PC++); + STANDARD_ACC_OP(*m_acc + (tempval ^ 0xfff) + 1, tempval); + NEXT_ACC_A; CYCLES(3); + break; + + /* S4I */ + case 0x31: case 0x32: case 0x33: + case 0x34: case 0x35: case 0x36: case 0x37: + case 0x38: case 0x39: case 0x3a: case 0x3b: + case 0x3c: case 0x3d: case 0x3e: case 0x3f: + tempval = opcode & 0x0f; + STANDARD_ACC_OP(*m_acc + (tempval ^ 0xfff) + 1, tempval); + NEXT_ACC_A; CYCLES(1); + break; + + /* LPAI */ + case 0x40: case 0x41: case 0x42: case 0x43: + case 0x44: case 0x45: case 0x46: case 0x47: + case 0x48: case 0x49: case 0x4a: case 0x4b: + case 0x4c: case 0x4d: case 0x4e: case 0x4f: + tempval = READOP(m_PC++); + m_J = (opcode & 0x0f) + (tempval & 0xf0) + ((tempval & 0x0f) << 8); + NEXT_ACC_A; CYCLES(3); + break; + + /* T4K */ + case 0x50: + m_PC = (m_P << 12) + m_J; + NEXT_ACC_B; CYCLES(4); + break; + + /* JMIB/JEHB */ + case 0x51: + if (m_external_input()) { m_PC = ((m_PC - 1) & 0xf000) + m_J; CYCLES(2); } + NEXT_ACC_B; CYCLES(2); + break; + + /* JVNB */ + case 0x52: + if (TEST_DR) { m_PC = ((m_PC - 1) & 0xf000) + m_J; CYCLES(2); } + NEXT_ACC_B; CYCLES(2); + break; + + /* JLTB */ + case 0x53: + if (TEST_LT) { m_PC = ((m_PC - 1) & 0xf000) + m_J; CYCLES(2); } + NEXT_ACC_B; CYCLES(2); + break; + + /* JEQB */ + case 0x54: + if (TEST_EQ) { m_PC = ((m_PC - 1) & 0xf000) + m_J; CYCLES(2); } + NEXT_ACC_B; CYCLES(2); + break; + + /* JCZB */ + case 0x55: + if (TEST_NC) { m_PC = ((m_PC - 1) & 0xf000) + m_J; CYCLES(2); } + NEXT_ACC_B; CYCLES(2); + break; + + /* JOSB */ + case 0x56: + if (TEST_A0) { m_PC = ((m_PC - 1) & 0xf000) + m_J; CYCLES(2); } + NEXT_ACC_B; CYCLES(2); + break; + + /* SSA */ + case 0x57: + NEXT_ACC_B; CYCLES(2); + break; + + /* JMP */ + case 0x58: + m_PC = ((m_PC - 1) & 0xf000) + m_J; + NEXT_ACC_A; CYCLES(4); + break; + + /* JMI/JEH */ + case 0x59: + if (m_external_input()) { m_PC = ((m_PC - 1) & 0xf000) + m_J; CYCLES(2); } + NEXT_ACC_A; CYCLES(2); + break; + + /* JVN */ + case 0x5a: + if (TEST_DR) { m_PC = ((m_PC - 1) & 0xf000) + m_J; CYCLES(2); } + NEXT_ACC_A; CYCLES(2); + break; + + /* JLT */ + case 0x5b: + if (TEST_LT) { m_PC = ((m_PC - 1) & 0xf000) + m_J; CYCLES(2); } + NEXT_ACC_A; CYCLES(2); + break; + + /* JEQ */ + case 0x5c: + if (TEST_EQ) { m_PC = ((m_PC - 1) & 0xf000) + m_J; CYCLES(2); } + NEXT_ACC_A; CYCLES(2); + break; + + /* JCZ */ + case 0x5d: + if (TEST_NC) { m_PC = ((m_PC - 1) & 0xf000) + m_J; CYCLES(2); } + NEXT_ACC_A; CYCLES(2); + break; + + /* JOS */ + case 0x5e: + if (TEST_A0) { m_PC = ((m_PC - 1) & 0xf000) + m_J; CYCLES(2); } + NEXT_ACC_A; CYCLES(2); + break; + + /* NOP */ + case 0x5f: + NEXT_ACC_A; CYCLES(2); + break; + + /* ADD */ + case 0x60: case 0x61: case 0x62: case 0x63: + case 0x64: case 0x65: case 0x66: case 0x67: + case 0x68: case 0x69: case 0x6a: case 0x6b: + case 0x6c: case 0x6d: case 0x6e: case 0x6f: + m_I = (m_P << 4) + (opcode & 0x0f); + tempval = RDMEM(m_I); + STANDARD_ACC_OP(*m_acc + tempval, tempval); + NEXT_ACC_A; CYCLES(3); + break; + + /* SUB */ + case 0x70: case 0x71: case 0x72: case 0x73: + case 0x74: case 0x75: case 0x76: case 0x77: + case 0x78: case 0x79: case 0x7a: case 0x7b: + case 0x7c: case 0x7d: case 0x7e: case 0x7f: + m_I = (m_P << 4) + (opcode & 0x0f); + tempval = RDMEM(m_I); + STANDARD_ACC_OP(*m_acc + (tempval ^ 0xfff) + 1, tempval); + NEXT_ACC_A; CYCLES(3); + break; + + /* SETP */ + case 0x80: case 0x81: case 0x82: case 0x83: + case 0x84: case 0x85: case 0x86: case 0x87: + case 0x88: case 0x89: case 0x8a: case 0x8b: + case 0x8c: case 0x8d: case 0x8e: case 0x8f: + m_P = opcode & 0x0f; + NEXT_ACC_A; CYCLES(1); + break; + + /* OUT */ + case 0x90: case 0x91: case 0x92: case 0x93: + case 0x94: case 0x95: case 0x96: case 0x97: + case 0x98: case 0x99: case 0x9a: case 0x9b: + case 0x9c: case 0x9d: case 0x9e: case 0x9f: + if (m_acc == &m_A) + WRITEPORT(opcode & 0x07, ~*m_acc & 1); + NEXT_ACC_A; CYCLES(1); + break; + + /* LDA */ + case 0xa0: case 0xa1: case 0xa2: case 0xa3: + case 0xa4: case 0xa5: case 0xa6: case 0xa7: + case 0xa8: case 0xa9: case 0xaa: case 0xab: + case 0xac: case 0xad: case 0xae: case 0xaf: + m_I = (m_P << 4) + (opcode & 0x0f); + tempval = RDMEM(m_I); + STANDARD_ACC_OP(tempval, tempval); + NEXT_ACC_A; CYCLES(3); + break; + + /* TST */ + case 0xb0: case 0xb1: case 0xb2: case 0xb3: + case 0xb4: case 0xb5: case 0xb6: case 0xb7: + case 0xb8: case 0xb9: case 0xba: case 0xbb: + case 0xbc: case 0xbd: case 0xbe: case 0xbf: + m_I = (m_P << 4) + (opcode & 0x0f); + tempval = RDMEM(m_I); + { + UINT16 result = *m_acc + (tempval ^ 0xfff) + 1; + SET_A0; + SET_CMP_VAL(tempval); + SET_NC(result); + SET_MI(result); + } + NEXT_ACC_A; CYCLES(3); + break; + + /* WS */ + case 0xc0: case 0xc1: case 0xc2: case 0xc3: + case 0xc4: case 0xc5: case 0xc6: case 0xc7: + case 0xc8: case 0xc9: case 0xca: case 0xcb: + case 0xcc: case 0xcd: case 0xce: case 0xcf: + m_I = (m_P << 4) + (opcode & 0x0f); + m_I = RDMEM(m_I) & 0xff; + NEXT_ACC_A; CYCLES(3); + break; + + /* STA */ + case 0xd0: case 0xd1: case 0xd2: case 0xd3: + case 0xd4: case 0xd5: case 0xd6: case 0xd7: + case 0xd8: case 0xd9: case 0xda: case 0xdb: + case 0xdc: case 0xdd: case 0xde: case 0xdf: + m_I = (m_P << 4) + (opcode & 0x0f); + WRMEM(m_I, *m_acc); + NEXT_ACC_A; CYCLES(3); + break; + + /* DV */ + case 0xe0: + { + INT16 stopX = (INT16)(m_A << 4) >> 4; + INT16 stopY = (INT16)(m_B << 4) >> 4; + + stopX = ((INT16)(stopX - m_X) >> m_T) + m_X; + stopY = ((INT16)(stopY - m_Y) >> m_T) + m_Y; + + m_vector_callback(m_X, m_Y, stopX, stopY, m_T); + + /* hack to make QB3 display semi-correctly during explosions */ + m_A = m_X & 0xfff; + m_B = m_Y & 0xfff; + } + NEXT_ACC_A; CYCLES(1); + break; + + /* LPAP */ + case 0xe1: + m_J = RDMEM(m_I); + NEXT_ACC_A; CYCLES(3); + break; + + /* WSP */ + case 0xf1: + m_I = RDMEM(m_I) & 0xff; + NEXT_ACC_A; CYCLES(3); + break; + + /* LKP */ + case 0xe2: + case 0xf2: + tempval = READOP(((m_PC - 1) & 0xf000) + *m_acc); + STANDARD_ACC_OP(tempval, tempval); + NEXT_ACC_A; CYCLES(7); + m_PC++; + break; + + /* MUL */ + case 0xe3: + case 0xf3: + tempval = RDMEM(m_I); + SET_A0; + m_cmpval = tempval & 0xfff; + if (m_acc == &m_A) + { + if (m_A & 1) + { + UINT16 result; + m_cmpacc = m_B; + m_A = (m_A >> 1) | ((m_B << 11) & 0x800); + m_B = ((INT16)(m_B << 4) >> 5) & 0xfff; + result = m_B + tempval; + SET_NC(result); + SET_MI(result); + m_B = result & 0xfff; + } + else + { + UINT16 result; + m_cmpacc = m_A; + result = m_A + tempval; + m_A = (m_A >> 1) | ((m_B << 11) & 0x800); + m_B = ((INT16)(m_B << 4) >> 5) & 0xfff; + SET_NC(result); + SET_MI(result); + } + } + else + { + UINT16 result; + m_cmpacc = m_B; + m_B = ((INT16)(m_B << 4) >> 5) & 0xfff; + result = m_B + tempval; + SET_NC(result); + SET_MI(result); + if (m_A & 1) + m_B = result & 0xfff; + } + NEXT_ACC_A; CYCLES(2); + break; + + /* NV */ + case 0xe4: + case 0xf4: + m_T = 0; + while (((m_A & 0xa00) == 0x000 || (m_A & 0xa00) == 0xa00) && + ((m_B & 0xa00) == 0x000 || (m_B & 0xa00) == 0xa00) && + m_T < 16) + { + m_A = (m_A << 1) & 0xfff; + m_B = (m_B << 1) & 0xfff; + m_T++; + CYCLES(1); + } + NEXT_ACC_A; CYCLES(1); + break; + + /* FRM */ + case 0xe5: + case 0xf5: + m_waiting = TRUE; + NEXT_ACC_A; + m_icount = -1; + + /* some games repeat the FRM opcode twice; it apparently does not cause + a second wait, so we make sure we skip any duplicate opcode at this + point */ + if (READOP(m_PC) == opcode) + m_PC++; + break; + + /* STAP */ + case 0xe6: + case 0xf6: + WRMEM(m_I, *m_acc); + NEXT_ACC_A; CYCLES(2); + break; + + /* CST */ + case 0xf7: + m_watchdog = 0; + /* ADDP */ + case 0xe7: + tempval = RDMEM(m_I); + STANDARD_ACC_OP(*m_acc + tempval, tempval); + NEXT_ACC_A; CYCLES(2); + break; + + /* SUBP */ + case 0xe8: + case 0xf8: + tempval = RDMEM(m_I); + STANDARD_ACC_OP(*m_acc + (tempval ^ 0xfff) + 1, tempval); + NEXT_ACC_A; CYCLES(3); + break; + + /* ANDP */ + case 0xe9: + case 0xf9: + tempval = RDMEM(m_I); + STANDARD_ACC_OP(*m_acc & tempval, tempval); + NEXT_ACC_A; CYCLES(2); + break; + + /* LDAP */ + case 0xea: + case 0xfa: + tempval = RDMEM(m_I); + STANDARD_ACC_OP(tempval, tempval); + NEXT_ACC_A; CYCLES(2); + break; + + /* SHR */ + case 0xeb: + case 0xfb: + tempval = ((m_acc == &m_A) ? (m_A >> 1) : ((INT16)(m_B << 4) >> 5)) & 0xfff; + tempval |= (*m_acc + (0xb0b | (opcode & 0xf0))) & 0x1000; + STANDARD_ACC_OP(tempval, 0xb0b | (opcode & 0xf0)); + NEXT_ACC_A; CYCLES(1); + break; + + /* SHL */ + case 0xec: + case 0xfc: + tempval = (*m_acc << 1) & 0xfff; + tempval |= (*m_acc + (0xc0c | (opcode & 0xf0))) & 0x1000; + STANDARD_ACC_OP(tempval, 0xc0c | (opcode & 0xf0)); + NEXT_ACC_A; CYCLES(1); + break; + + /* ASR */ + case 0xed: + case 0xfd: + tempval = ((INT16)(*m_acc << 4) >> 5) & 0xfff; + STANDARD_ACC_OP(tempval, 0xd0d | (opcode & 0xf0)); + NEXT_ACC_A; CYCLES(1); + break; + + /* SHRB */ + case 0xee: + case 0xfe: + if (m_acc == &m_A) + { + tempval = (m_A >> 1) | ((m_B << 11) & 0x800); + m_B = ((INT16)(m_B << 4) >> 5) & 0xfff; + } + else + tempval = ((INT16)(m_B << 4) >> 5) & 0xfff; + tempval |= (*m_acc + (0xe0e | (opcode & 0xf0))) & 0x1000; + STANDARD_ACC_OP(tempval, 0xe0e | (opcode & 0xf0)); + NEXT_ACC_A; CYCLES(1); + break; + + /* SHLB */ + case 0xef: + case 0xff: + if (m_acc == &m_A) + { + tempval = (m_A << 1) & 0xfff; + m_B = (m_B << 1) & 0xfff; + } + else + tempval = (m_B << 1) & 0xfff; + tempval |= (*m_acc + (0xf0f | (opcode & 0xf0))) & 0x1000; + STANDARD_ACC_OP(tempval, 0xf0f | (opcode & 0xf0)); + NEXT_ACC_A; CYCLES(1); + break; + + /* IV */ + case 0xf0: + m_X = (INT16)(m_A << 4) >> 4; + m_Y = (INT16)(m_B << 4) >> 4; + NEXT_ACC_A; CYCLES(1); + break; + } + } while (m_icount > 0); +} + + +offs_t ccpu_cpu_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( ccpu ); + return CPU_DISASSEMBLE_NAME(ccpu)(this, buffer, pc, oprom, opram, options); +} diff --git a/src/devices/cpu/ccpu/ccpu.h b/src/devices/cpu/ccpu/ccpu.h new file mode 100644 index 00000000000..96a0fac344a --- /dev/null +++ b/src/devices/cpu/ccpu/ccpu.h @@ -0,0 +1,131 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + ccpu.h + Core implementation for the portable Cinematronics CPU emulator. + + Written by Aaron Giles + Special thanks to Zonn Moore for his detailed documentation. + +***************************************************************************/ + +#pragma once + +#ifndef __CCPU_H__ +#define __CCPU_H__ + + +/*************************************************************************** + REGISTER ENUMERATION +***************************************************************************/ + +enum +{ + CCPU_PC=1, + CCPU_FLAGS, + CCPU_A, + CCPU_B, + CCPU_I, + CCPU_J, + CCPU_P, + CCPU_X, + CCPU_Y, + CCPU_T +}; + + +typedef device_delegate ccpu_vector_delegate; + + +#define MCFG_CCPU_EXTERNAL_FUNC(_devcb) \ + ccpu_cpu_device::set_external_func(*device, DEVCB_##_devcb); + +#define MCFG_CCPU_VECTOR_FUNC(d) \ + ccpu_cpu_device::set_vector_func(*device, d); + + +class ccpu_cpu_device : public cpu_device +{ +public: + // construction/destruction + ccpu_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // static configuration helpers + template static devcb_base &set_external_func(device_t &device, _Object object) { return downcast(device).m_external_input.set_callback(object); } + static void set_vector_func(device_t &device, ccpu_vector_delegate callback) { downcast(device).m_vector_callback = callback; } + + DECLARE_READ8_MEMBER( read_jmi ); + void wdt_timer_trigger(); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_execute_interface overrides + virtual UINT32 execute_min_cycles() const { return 1; } + virtual UINT32 execute_max_cycles() const { return 1; } + virtual UINT32 execute_input_lines() const { return 0; } + virtual void execute_run(); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const + { + switch (spacenum) + { + case AS_PROGRAM: return &m_program_config; + case AS_IO: return &m_io_config; + case AS_DATA: return &m_data_config; + default: return NULL; + } + } + + // device_state_interface overrides + void state_string_export(const device_state_entry &entry, std::string &str); + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const { return 1; } + virtual UINT32 disasm_max_opcode_bytes() const { return 3; } + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + + address_space_config m_program_config; + address_space_config m_data_config; + address_space_config m_io_config; + + UINT16 m_PC; + UINT16 m_A; + UINT16 m_B; + UINT8 m_I; + UINT16 m_J; + UINT8 m_P; + UINT16 m_X; + UINT16 m_Y; + UINT16 m_T; + UINT16 * m_acc; + + UINT16 m_a0flag, m_ncflag, m_cmpacc, m_cmpval; + UINT16 m_miflag, m_nextmiflag, m_nextnextmiflag; + UINT16 m_drflag; + + devcb_read8 m_external_input; + ccpu_vector_delegate m_vector_callback; + + UINT8 m_waiting; + UINT8 m_watchdog; + + int m_icount; + + address_space *m_program; + direct_read_data *m_direct; + address_space *m_data; + address_space *m_io; + + UINT16 m_flags; +}; + + +extern const device_type CCPU; + + +#endif /* __CCPU_H__ */ diff --git a/src/devices/cpu/ccpu/ccpudasm.c b/src/devices/cpu/ccpu/ccpudasm.c new file mode 100644 index 00000000000..e1f54d1ec00 --- /dev/null +++ b/src/devices/cpu/ccpu/ccpudasm.c @@ -0,0 +1,330 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + ccpudasm.c + Core implementation for the portable Cinematronics CPU disassembler. + + Written by Aaron Giles + Special thanks to Zonn Moore for his detailed documentation. + +***************************************************************************/ + +#include "emu.h" +#include "ccpu.h" + + +CPU_DISASSEMBLE( ccpu ) +{ + unsigned startpc = pc; + UINT8 opcode = oprom[pc++ - startpc]; + UINT8 tempval; + + switch (opcode) + { + /* LDAI */ + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x04: case 0x05: case 0x06: case 0x07: + case 0x08: case 0x09: case 0x0a: case 0x0b: + case 0x0c: case 0x0d: case 0x0e: case 0x0f: + sprintf(buffer, "LDAI $%X", opcode & 0x0f); + break; + + /* INP */ + case 0x10: case 0x11: case 0x12: case 0x13: + case 0x14: case 0x15: case 0x16: case 0x17: + case 0x18: case 0x19: case 0x1a: case 0x1b: + case 0x1c: case 0x1d: case 0x1e: case 0x1f: + sprintf(buffer, "INP $%X", opcode & 0x0f); + break; + + /* A8I */ + case 0x20: + sprintf(buffer, "A8I $%X", oprom[pc++ - startpc]); + break; + + /* A4I */ + case 0x21: case 0x22: case 0x23: + case 0x24: case 0x25: case 0x26: case 0x27: + case 0x28: case 0x29: case 0x2a: case 0x2b: + case 0x2c: case 0x2d: case 0x2e: case 0x2f: + sprintf(buffer, "A4I $%X", opcode & 0x0f); + break; + + /* S8I */ + case 0x30: + sprintf(buffer, "S8I $%X", oprom[pc++ - startpc]); + break; + + /* S4I */ + case 0x31: case 0x32: case 0x33: + case 0x34: case 0x35: case 0x36: case 0x37: + case 0x38: case 0x39: case 0x3a: case 0x3b: + case 0x3c: case 0x3d: case 0x3e: case 0x3f: + sprintf(buffer, "S4I $%X", opcode & 0x0f); + break; + + /* LPAI */ + case 0x40: case 0x41: case 0x42: case 0x43: + case 0x44: case 0x45: case 0x46: case 0x47: + case 0x48: case 0x49: case 0x4a: case 0x4b: + case 0x4c: case 0x4d: case 0x4e: case 0x4f: + tempval = oprom[pc++ - startpc]; + sprintf(buffer, "LPAI $%03X", (opcode & 0x0f) + (tempval & 0xf0) + ((tempval & 0x0f) << 8)); + break; + + /* T4K */ + case 0x50: + sprintf(buffer, "T4K"); + break; + + /* JMIB/JEHB */ + case 0x51: + sprintf(buffer, "JMIB/JEHB"); + break; + + /* JVNB */ + case 0x52: + sprintf(buffer, "JVNB"); + break; + + /* JLTB */ + case 0x53: + sprintf(buffer, "JLTB"); + break; + + /* JEQB */ + case 0x54: + sprintf(buffer, "JEQB"); + break; + + /* JCZB */ + case 0x55: + sprintf(buffer, "JCZB"); + break; + + /* JOSB */ + case 0x56: + sprintf(buffer, "JOSB"); + break; + + /* SSA */ + case 0x57: + sprintf(buffer, "SSA"); + break; + + /* JMP */ + case 0x58: + sprintf(buffer, "JMP"); + break; + + /* JMI/JEH */ + case 0x59: + sprintf(buffer, "JMI/JEH"); + break; + + /* JVN */ + case 0x5a: + sprintf(buffer, "JVN"); + break; + + /* JLT */ + case 0x5b: + sprintf(buffer, "JLT"); + break; + + /* JEQ */ + case 0x5c: + sprintf(buffer, "JEQ"); + break; + + /* JCZ */ + case 0x5d: + sprintf(buffer, "JCZ"); + break; + + /* JOS */ + case 0x5e: + sprintf(buffer, "JOS"); + break; + + /* NOP */ + case 0x5f: + sprintf(buffer, "NOP"); + break; + + /* ADD */ + case 0x60: case 0x61: case 0x62: case 0x63: + case 0x64: case 0x65: case 0x66: case 0x67: + case 0x68: case 0x69: case 0x6a: case 0x6b: + case 0x6c: case 0x6d: case 0x6e: case 0x6f: + sprintf(buffer, "ADD $%X", opcode & 0x0f); + break; + + /* SUB n */ + case 0x70: case 0x71: case 0x72: case 0x73: + case 0x74: case 0x75: case 0x76: case 0x77: + case 0x78: case 0x79: case 0x7a: case 0x7b: + case 0x7c: case 0x7d: case 0x7e: case 0x7f: + sprintf(buffer, "SUB $%X", opcode & 0x0f); + break; + + /* SETP n */ + case 0x80: case 0x81: case 0x82: case 0x83: + case 0x84: case 0x85: case 0x86: case 0x87: + case 0x88: case 0x89: case 0x8a: case 0x8b: + case 0x8c: case 0x8d: case 0x8e: case 0x8f: + sprintf(buffer, "SETP $%X", opcode & 0x0f); + break; + + /* OUT */ + case 0x90: case 0x91: case 0x92: case 0x93: + case 0x94: case 0x95: case 0x96: case 0x97: + case 0x98: case 0x99: case 0x9a: case 0x9b: + case 0x9c: case 0x9d: case 0x9e: case 0x9f: + sprintf(buffer, "OUT $%X", opcode & 0x0f); + break; + + /* LDA */ + case 0xa0: case 0xa1: case 0xa2: case 0xa3: + case 0xa4: case 0xa5: case 0xa6: case 0xa7: + case 0xa8: case 0xa9: case 0xaa: case 0xab: + case 0xac: case 0xad: case 0xae: case 0xaf: + sprintf(buffer, "LDA $%X", opcode & 0x0f); + break; + + /* CMP */ + case 0xb0: case 0xb1: case 0xb2: case 0xb3: + case 0xb4: case 0xb5: case 0xb6: case 0xb7: + case 0xb8: case 0xb9: case 0xba: case 0xbb: + case 0xbc: case 0xbd: case 0xbe: case 0xbf: + sprintf(buffer, "TST $%X", opcode & 0x0f); + break; + + /* WS */ + case 0xc0: case 0xc1: case 0xc2: case 0xc3: + case 0xc4: case 0xc5: case 0xc6: case 0xc7: + case 0xc8: case 0xc9: case 0xca: case 0xcb: + case 0xcc: case 0xcd: case 0xce: case 0xcf: + sprintf(buffer, "WS $%X", opcode & 0x0f); + break; + + /* STA n */ + case 0xd0: case 0xd1: case 0xd2: case 0xd3: + case 0xd4: case 0xd5: case 0xd6: case 0xd7: + case 0xd8: case 0xd9: case 0xda: case 0xdb: + case 0xdc: case 0xdd: case 0xde: case 0xdf: + sprintf(buffer, "STA $%X", opcode & 0x0f); + break; + + /* DV */ + case 0xe0: + sprintf(buffer, "DV"); + break; + + /* LPAP */ + case 0xe1: + sprintf(buffer, "LPAP"); + break; + + /* WSP */ + case 0xf1: + sprintf(buffer, "WSP"); + break; + + /* LKP */ + case 0xe2: + case 0xf2: + sprintf(buffer, "LKP"); + break; + + /* MUL */ + case 0xe3: + case 0xf3: + sprintf(buffer, "MUL"); + break; + + /* NV */ + case 0xe4: + case 0xf4: + sprintf(buffer, "NV"); + break; + + /* FRM */ + case 0xe5: + case 0xf5: + sprintf(buffer, "FRM"); + break; + + /* STAP */ + case 0xe6: + case 0xf6: + sprintf(buffer, "STAP"); + break; + + /* CST */ + case 0xf7: + sprintf(buffer, "CST"); + break; + + /* ADDP */ + case 0xe7: + sprintf(buffer, "ADDP"); + break; + + /* SUBP */ + case 0xe8: + case 0xf8: + sprintf(buffer, "SUBP"); + break; + + /* ANDP */ + case 0xe9: + case 0xf9: + sprintf(buffer, "ANDP"); + break; + + /* LDAP */ + case 0xea: + case 0xfa: + sprintf(buffer, "LDAP"); + break; + + /* SHR */ + case 0xeb: + case 0xfb: + sprintf(buffer, "SHR"); + break; + + /* SHL */ + case 0xec: + case 0xfc: + sprintf(buffer, "SHL"); + break; + + /* ASR */ + case 0xed: + case 0xfd: + sprintf(buffer, "ASR"); + break; + + /* SHRB */ + case 0xee: + case 0xfe: + sprintf(buffer, "SHRB"); + break; + + /* SHLB */ + case 0xef: + case 0xff: + sprintf(buffer, "SHLB"); + break; + + /* IV */ + case 0xf0: + sprintf(buffer, "IV"); + break; + } + + return (pc - startpc) | DASMFLAG_SUPPORTED; +} diff --git a/src/devices/cpu/cop400/cop400.c b/src/devices/cpu/cop400/cop400.c new file mode 100644 index 00000000000..eca60705b2c --- /dev/null +++ b/src/devices/cpu/cop400/cop400.c @@ -0,0 +1,1239 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/*************************************************************************** + + cop400.c + + National Semiconductor COP400 Emulator. + +**************************************************************************** + + Type ROM RAM G D IN + + COP410 512x8 32x4 none + COP411 512x8 32x4 0-2 0-1 none + COP401 none 32x4 none + COP413? + COP414? + COP415? + COP405? + + COP420 1024x8 64x4 + COP421 1024x8 64x4 none + COP422 1024x8 64x4 2-3 2-3 none + COP402 none 64x4 + + COP444 2048x8 128x4 + COP445 2048x8 128x4 none + COP424 1024x8 64x4 + COP425 1024x8 64x4 none + COP426 1024x8 64x4 2-3 2-3 + COP404 none none + + COP440 2048x8 160x4 + COP441 2048x8 160x4 + COP442 2048x8 160x4 + +**************************************************************************** + + Prefix Temperature Range + + COP4xx 0C ... 70C + COP3xx -40C ... +85C + COP2xx -55C ... +125C + +***************************************************************************/ + +/* + + TODO: + + - remove InstLen + - run interrupt test suite + - run production test suite + - run microbus test suite + - when is the microbus int cleared? + - opcode support for 2048x8 and 128x4/160x4 memory sizes + - CKO sync input + - save internal RAM when CKO is RAM power supply pin + - COP413/COP414/COP415/COP405 + - COP404 opcode map switching, dual timer, microbus enable + - COP440/COP441/COP442 (new registers: 2-bit N, 4-bit H, 8-bit R; some new opcodes, 2Kx8 ROM, 160x4 RAM) + +*/ + +#include "emu.h" +#include "debugger.h" +#include "cop400.h" + + +const device_type COP401 = &device_creator; +const device_type COP410 = &device_creator; +const device_type COP411 = &device_creator; +const device_type COP402 = &device_creator; +const device_type COP420 = &device_creator; +const device_type COP421 = &device_creator; +const device_type COP422 = &device_creator; +const device_type COP404 = &device_creator; +const device_type COP424 = &device_creator; +const device_type COP425 = &device_creator; +const device_type COP426 = &device_creator; +const device_type COP444 = &device_creator; +const device_type COP445 = &device_creator; + + +/*************************************************************************** + CONSTANTS +***************************************************************************/ + +/* feature masks */ +#define COP410_FEATURE 0x01 +#define COP420_FEATURE 0x02 +#define COP444_FEATURE 0x04 +#define COP440_FEATURE 0x08 + + +/*************************************************************************** + MACROS +***************************************************************************/ + +#define ROM(a) m_direct->read_byte(a) +#define RAM_R(a) m_data->read_byte(a) +#define RAM_W(a, v) m_data->write_byte(a, v) + +#define IN_G() (m_read_g(0, 0xff) & m_g_mask) +#define IN_L() m_read_l(0, 0xff) +#define IN_SI() BIT(m_read_si(), 0) +#define IN_CKO() BIT(m_read_cko(), 0) +#define IN_IN() (m_in_mask ? m_read_in(0, 0xff) : 0) + +#define OUT_G(v) m_write_g(0, (v) & m_g_mask, 0xff) +#define OUT_L(v) m_write_l(0, v, 0xff) +#define OUT_D(v) m_write_d(0, (v) & m_d_mask, 0xff) +#define OUT_SK(v) m_write_sk(v) +#define OUT_SO(v) m_write_so(v) + +#define PC m_pc +#define A m_a +#define B m_b +#define C m_c +#define G m_g +#define Q m_q +#define H m_h +#define R m_r +#define EN m_en +#define SA m_sa +#define SB m_sb +#define SC m_sc +#define SIO m_sio +#define SKL m_skl +#define T m_t +#define IL m_il + + +/*************************************************************************** + ADDRESS MAPS +***************************************************************************/ + +static ADDRESS_MAP_START( program_512b, AS_PROGRAM, 8, cop400_cpu_device ) + AM_RANGE(0x000, 0x1ff) AM_ROM +ADDRESS_MAP_END + +static ADDRESS_MAP_START( program_1kb, AS_PROGRAM, 8, cop400_cpu_device ) + AM_RANGE(0x000, 0x3ff) AM_ROM +ADDRESS_MAP_END + +static ADDRESS_MAP_START( program_2kb, AS_PROGRAM, 8, cop400_cpu_device ) + AM_RANGE(0x000, 0x7ff) AM_ROM +ADDRESS_MAP_END + +static ADDRESS_MAP_START( data_32b, AS_DATA, 8, cop400_cpu_device ) + AM_RANGE(0x00, 0x1f) AM_RAM +ADDRESS_MAP_END + +static ADDRESS_MAP_START( data_64b, AS_DATA, 8, cop400_cpu_device ) + AM_RANGE(0x00, 0x3f) AM_RAM +ADDRESS_MAP_END + +static ADDRESS_MAP_START( data_128b, AS_DATA, 8, cop400_cpu_device ) + AM_RANGE(0x00, 0x7f) AM_RAM +ADDRESS_MAP_END + +#ifdef UNUSED_CODE +static ADDRESS_MAP_START( data_160b, AS_DATA, 8, cop400_cpu_device ) + AM_RANGE(0x00, 0x9f) AM_RAM +ADDRESS_MAP_END +#endif + + +cop400_cpu_device::cop400_cpu_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source, UINT8 program_addr_bits, UINT8 data_addr_bits, UINT8 featuremask, UINT8 g_mask, UINT8 d_mask, UINT8 in_mask, bool has_counter, bool has_inil, address_map_constructor internal_map_program, address_map_constructor internal_map_data) + : cpu_device(mconfig, type, name, tag, owner, clock, shortname, source) + , m_program_config("program", ENDIANNESS_LITTLE, 8, program_addr_bits, 0, internal_map_program) + , m_data_config("data", ENDIANNESS_LITTLE, 8, data_addr_bits, 0, internal_map_data) // data width is really 4 + , m_read_l(*this) + , m_write_l(*this) + , m_read_g(*this) + , m_write_g(*this) + , m_write_d(*this) + , m_read_in(*this) + , m_read_si(*this) + , m_write_so(*this) + , m_write_sk(*this) + , m_read_cko(*this) + , m_cki(COP400_CKI_DIVISOR_16) + , m_cko(COP400_CKO_OSCILLATOR_OUTPUT) + , m_microbus(COP400_MICROBUS_DISABLED) + , m_has_counter(has_counter) + , m_has_inil(has_inil) + , m_featuremask(featuremask) + , m_g_mask(g_mask) + , m_d_mask(d_mask) + , m_in_mask(in_mask) +{ + int i; + + /* initialize instruction length array */ + for (i=0; i<256; i++) m_InstLen[i]=1; + + switch (featuremask) + { + case COP410_FEATURE: + /* select opcode map */ + m_opcode_map = COP410_OPCODE_MAP; + /* initialize instruction length array */ + m_InstLen[0x60] = m_InstLen[0x61] = m_InstLen[0x68] = + m_InstLen[0x69] = m_InstLen[0x33] = m_InstLen[0x23] = 2; + break; + + case COP420_FEATURE: + /* select opcode map */ + m_opcode_map = COP420_OPCODE_MAP; + /* initialize instruction length array */ + m_InstLen[0x60] = m_InstLen[0x61] = m_InstLen[0x62] = m_InstLen[0x63] = + m_InstLen[0x68] = m_InstLen[0x69] = m_InstLen[0x6a] = m_InstLen[0x6b] = + m_InstLen[0x33] = m_InstLen[0x23] = 2; + break; + + case COP444_FEATURE: + /* select opcode map */ + m_opcode_map = COP444_OPCODE_MAP; + /* initialize instruction length array */ + m_InstLen[0x60] = m_InstLen[0x61] = m_InstLen[0x62] = m_InstLen[0x63] = + m_InstLen[0x68] = m_InstLen[0x69] = m_InstLen[0x6a] = m_InstLen[0x6b] = + m_InstLen[0x33] = m_InstLen[0x23] = 2; + break; + + default: + fatalerror("No or unknown featuremask supplied\n"); + } +} + +cop401_cpu_device::cop401_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : cop400_cpu_device(mconfig, COP401, "COP401", tag, owner, clock, "cop401", __FILE__, 9, 5, COP410_FEATURE, 0xf, 0xf, 0, false, false, NULL, ADDRESS_MAP_NAME(data_32b)) +{ +} + +cop410_cpu_device::cop410_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : cop400_cpu_device(mconfig, COP410, "COP410", tag, owner, clock, "cop410", __FILE__, 9, 5, COP410_FEATURE, 0xf, 0xf, 0, false, false, ADDRESS_MAP_NAME(program_512b), ADDRESS_MAP_NAME(data_32b)) +{ +} + +cop411_cpu_device::cop411_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : cop400_cpu_device(mconfig, COP411, "COP411", tag, owner, clock, "cop411", __FILE__, 9, 5, COP410_FEATURE, 0x7, 0x3, 0, false, false, ADDRESS_MAP_NAME(program_512b), ADDRESS_MAP_NAME(data_32b)) +{ +} + +cop402_cpu_device::cop402_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : cop400_cpu_device(mconfig, COP402, "COP402", tag, owner, clock, "cop402", __FILE__, 10, 6, COP420_FEATURE, 0xf, 0xf, 0xf, true, true, NULL, ADDRESS_MAP_NAME(data_64b)) +{ +} + +cop420_cpu_device::cop420_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : cop400_cpu_device(mconfig, COP420, "COP420", tag, owner, clock, "cop420", __FILE__, 10, 6, COP420_FEATURE, 0xf, 0xf, 0xf, true, true, ADDRESS_MAP_NAME(program_1kb), ADDRESS_MAP_NAME(data_64b)) +{ +} + +cop421_cpu_device::cop421_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : cop400_cpu_device(mconfig, COP421, "COP421", tag, owner, clock, "cop421", __FILE__, 10, 6, COP420_FEATURE, 0xf, 0xf, 0, true, false, ADDRESS_MAP_NAME(program_1kb), ADDRESS_MAP_NAME(data_64b)) +{ +} + +cop422_cpu_device::cop422_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : cop400_cpu_device(mconfig, COP422, "COP422", tag, owner, clock, "cop422", __FILE__, 10, 6, COP420_FEATURE, 0xe, 0xe, 0, true, false, ADDRESS_MAP_NAME(program_1kb), ADDRESS_MAP_NAME(data_64b)) +{ +} + +cop404_cpu_device::cop404_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : cop400_cpu_device(mconfig, COP404, "COP404", tag, owner, clock, "cop404", __FILE__, 11, 7, COP444_FEATURE, 0xf, 0xf, 0xf, true, true, NULL, ADDRESS_MAP_NAME(data_128b)) +{ +} + +cop424_cpu_device::cop424_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : cop400_cpu_device(mconfig, COP424, "COP424", tag, owner, clock, "cop424", __FILE__, 10, 6, COP444_FEATURE, 0xf, 0xf, 0xf, true, true, ADDRESS_MAP_NAME(program_1kb), ADDRESS_MAP_NAME(data_64b)) +{ +} + +cop425_cpu_device::cop425_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : cop400_cpu_device(mconfig, COP425, "COP425", tag, owner, clock, "cop425", __FILE__, 10, 6, COP444_FEATURE, 0xf, 0xf, 0, true, false, ADDRESS_MAP_NAME(program_1kb), ADDRESS_MAP_NAME(data_64b)) +{ +} + +cop426_cpu_device::cop426_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : cop400_cpu_device(mconfig, COP426, "COP426", tag, owner, clock, "cop426", __FILE__, 10, 6, COP444_FEATURE, 0xe, 0xe, 0xf, true, true, ADDRESS_MAP_NAME(program_1kb), ADDRESS_MAP_NAME(data_64b)) +{ +} + +cop444_cpu_device::cop444_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : cop400_cpu_device(mconfig, COP444, "COP444", tag, owner, clock, "cop444", __FILE__, 11, 7, COP444_FEATURE, 0xf, 0xf, 0xf, true, true, ADDRESS_MAP_NAME(program_2kb), ADDRESS_MAP_NAME(data_128b)) +{ +} + +cop445_cpu_device::cop445_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : cop400_cpu_device(mconfig, COP445, "COP445", tag, owner, clock, "cop445", __FILE__, 11, 7, COP444_FEATURE, 0x7, 0x3, 0, true, false, ADDRESS_MAP_NAME(program_2kb), ADDRESS_MAP_NAME(data_128b)) +{ +} + +/*************************************************************************** + INLINE FUNCTIONS +***************************************************************************/ + + +void cop400_cpu_device::PUSH(UINT16 data) +{ + if (m_featuremask != COP410_FEATURE) + { + SC = SB; + } + + SB = SA; + SA = data; +} + +void cop400_cpu_device::POP() +{ + PC = SA; + SA = SB; + + if (m_featuremask != COP410_FEATURE) + { + SB = SC; + } +} + +void cop400_cpu_device::WRITE_Q(UINT8 data) +{ + Q = data; + + if (BIT(EN, 2)) + { + OUT_L(Q); + } +} + +void cop400_cpu_device::WRITE_G(UINT8 data) +{ + if (m_microbus == COP400_MICROBUS_ENABLED) + { + data = (data & 0x0e) | m_microbus_int; + } + + G = data; + + OUT_G(G); +} + +/*************************************************************************** + OPCODE HANDLERS +***************************************************************************/ + +#define INSTRUCTION(mnemonic) void (cop400_cpu_device::mnemonic)(UINT8 opcode) +#define INST(mnemonic) &cop400_cpu_device::mnemonic + +INSTRUCTION(illegal) +{ + logerror("COP400: PC = %04x, Illegal opcode = %02x\n", PC-1, ROM(PC-1)); +} + +#include "cop400op.inc" + +/*************************************************************************** + OPCODE TABLES +***************************************************************************/ + +const cop400_cpu_device::cop400_opcode_map cop400_cpu_device::COP410_OPCODE_23_MAP[256] = +{ + {1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) }, + {1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) }, + {1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) }, + {1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) }, + {1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) }, + {1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) }, + {1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) }, + {1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) }, + + {1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) }, + {1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) }, + {1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) }, + {1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) }, + {1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) }, + {1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) }, + {1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) }, + {1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) }, + + {1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) }, + {1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) }, + {1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) }, + {1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) }, + {1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) }, + {1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) }, + {1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) }, + {1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(xad) }, + + {1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) }, + {1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) }, + {1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) }, + {1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) }, + {1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) }, + {1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) }, + {1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) }, + {1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) } +}; + +void cop400_cpu_device::cop410_op23(UINT8 opcode) +{ + UINT8 opcode23 = ROM(PC++); + + (this->*COP410_OPCODE_23_MAP[opcode23].function)(opcode23); +} + +const cop400_cpu_device::cop400_opcode_map cop400_cpu_device::COP410_OPCODE_33_MAP[256] = +{ + {1, INST(illegal) },{1, INST(skgbz0) },{1, INST(illegal) },{1, INST(skgbz2) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) }, + {1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) }, + {1, INST(illegal) },{1, INST(skgbz1) },{1, INST(illegal) },{1, INST(skgbz3) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) }, + {1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) }, + {1, INST(illegal) },{1, INST(skgz) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) }, + {1, INST(illegal) },{1, INST(illegal) },{1, INST(ing) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(inl) },{1, INST(illegal) }, + {1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) }, + {1, INST(halt) },{1, INST(illegal) },{1, INST(omg) },{1, INST(illegal) },{1, INST(camq) },{1, INST(illegal) },{1, INST(obd) },{1, INST(illegal) }, + + {1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) }, + {1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) }, + {1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) }, + {1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) }, + {1, INST(lei) },{1, INST(lei) },{1, INST(lei) },{1, INST(lei) },{1, INST(lei) },{1, INST(lei) },{1, INST(lei) },{1, INST(lei) }, + {1, INST(lei) },{1, INST(lei) },{1, INST(lei) },{1, INST(lei) },{1, INST(lei) },{1, INST(lei) },{1, INST(lei) },{1, INST(lei) }, + {1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) }, + {1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) }, + + {1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) }, + {1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) }, + {1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) }, + {1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) }, + {1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) }, + {1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) }, + {1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) }, + {1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) }, + + {1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) }, + {1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) }, + {1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) }, + {1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) }, + {1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) }, + {1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) }, + {1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) }, + {1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) } +}; + +void cop400_cpu_device::cop410_op33(UINT8 opcode) +{ + UINT8 opcode33 = ROM(PC++); + + (this->*COP410_OPCODE_33_MAP[opcode33].function)(opcode33); +} + +const cop400_cpu_device::cop400_opcode_map cop400_cpu_device::COP410_OPCODE_MAP[256] = +{ + {1, INST(clra) },{1, INST(skmbz0) },{1, INST(xor_) },{1, INST(skmbz2) },{1, INST(xis) },{1, INST(ld) },{1, INST(x) },{1, INST(xds) }, + {1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) }, + {0, INST(illegal) },{1, INST(skmbz1) },{0, INST(illegal) },{1, INST(skmbz3) },{1, INST(xis) },{1, INST(ld) },{1, INST(x) },{1, INST(xds) }, + {1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) }, + {1, INST(skc) },{1, INST(ske) },{1, INST(sc) },{1, INST(cop410_op23) },{1, INST(xis) },{1, INST(ld) },{1, INST(x) },{1, INST(xds) }, + {1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) }, + {1, INST(asc) },{1, INST(add) },{1, INST(rc) },{1, INST(cop410_op33) },{1, INST(xis) },{1, INST(ld) },{1, INST(x) },{1, INST(xds) }, + {1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) }, + + {1, INST(comp) },{0, INST(illegal) },{1, INST(rmb2) },{1, INST(rmb3) },{1, INST(nop) },{1, INST(rmb1) },{1, INST(smb2) },{1, INST(smb1) }, + {1, INST(ret) },{1, INST(retsk) },{0, INST(illegal) },{1, INST(smb3) },{1, INST(rmb0) },{1, INST(smb0) },{1, INST(cba) },{1, INST(xas) }, + {1, INST(cab) },{1, INST(aisc) },{1, INST(aisc) },{1, INST(aisc) },{1, INST(aisc) },{1, INST(aisc) },{1, INST(aisc) },{1, INST(aisc) }, + {1, INST(aisc) },{1, INST(aisc) },{1, INST(aisc) },{1, INST(aisc) },{1, INST(aisc) },{1, INST(aisc) },{1, INST(aisc) },{1, INST(aisc) }, + {2, INST(jmp) },{2, INST(jmp) },{0, INST(illegal) },{0, INST(illegal) },{0, INST(illegal) },{0, INST(illegal) },{0, INST(illegal) },{0, INST(illegal) }, + {2, INST(jsr) },{2, INST(jsr) },{0, INST(illegal) },{0, INST(illegal) },{0, INST(illegal) },{0, INST(illegal) },{0, INST(illegal) },{0, INST(illegal) }, + {1, INST(stii) },{1, INST(stii) },{1, INST(stii) },{1, INST(stii) },{1, INST(stii) },{1, INST(stii) },{1, INST(stii) },{1, INST(stii) }, + {1, INST(stii) },{1, INST(stii) },{1, INST(stii) },{1, INST(stii) },{1, INST(stii) },{1, INST(stii) },{1, INST(stii) },{1, INST(stii) }, + + {1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) }, + {1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) }, + {1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) }, + {1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) }, + {1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) }, + {1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) }, + {1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) }, + {1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{2, INST(lqid) }, + + {1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) }, + {1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) }, + {1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) }, + {1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) }, + {1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) }, + {1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) }, + {1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) }, + {1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{2, INST(jid) } +}; + +const cop400_cpu_device::cop400_opcode_map cop400_cpu_device::COP420_OPCODE_23_MAP[256] = +{ + {1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) }, + {1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) }, + {1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) }, + {1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) }, + {1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) }, + {1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) }, + {1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) }, + {1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) }, + + {1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) }, + {1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) }, + {1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) }, + {1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) }, + {1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) }, + {1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) }, + {1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) }, + {1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) }, + + {1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) }, + {1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) }, + {1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) }, + {1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) }, + {1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) }, + {1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) }, + {1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) }, + {1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) }, + + {1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) }, + {1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) }, + {1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) }, + {1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) }, + {1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) }, + {1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) }, + {1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) }, + {1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) } +}; + +void cop400_cpu_device::cop420_op23(UINT8 opcode) +{ + UINT8 opcode23 = ROM(PC++); + + (this->*COP420_OPCODE_23_MAP[opcode23].function)(opcode23); +} + +const cop400_cpu_device::cop400_opcode_map cop400_cpu_device::COP420_OPCODE_33_MAP[256] = +{ + {1, INST(illegal) },{1, INST(skgbz0) },{1, INST(illegal) },{1, INST(skgbz2) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) }, + {1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) }, + {1, INST(illegal) },{1, INST(skgbz1) },{1, INST(illegal) },{1, INST(skgbz3) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) }, + {1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) }, + {1, INST(illegal) },{1, INST(skgz) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) }, + {1, INST(inin) },{1, INST(inil) },{1, INST(ing) },{1, INST(illegal) },{1, INST(cqma) },{1, INST(illegal) },{1, INST(inl) },{1, INST(illegal) }, + {1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) }, + {1, INST(illegal) },{1, INST(illegal) },{1, INST(omg) },{1, INST(illegal) },{1, INST(camq) },{1, INST(illegal) },{1, INST(obd) },{1, INST(illegal) }, + + {1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) }, + {1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) }, + {1, INST(ogi) },{1, INST(ogi) },{1, INST(ogi) },{1, INST(ogi) },{1, INST(ogi) },{1, INST(ogi) },{1, INST(ogi) },{1, INST(ogi) }, + {1, INST(ogi) },{1, INST(ogi) },{1, INST(ogi) },{1, INST(ogi) },{1, INST(ogi) },{1, INST(ogi) },{1, INST(ogi) },{1, INST(ogi) }, + {1, INST(lei) },{1, INST(lei) },{1, INST(lei) },{1, INST(lei) },{1, INST(lei) },{1, INST(lei) },{1, INST(lei) },{1, INST(lei) }, + {1, INST(lei) },{1, INST(lei) },{1, INST(lei) },{1, INST(lei) },{1, INST(lei) },{1, INST(lei) },{1, INST(lei) },{1, INST(lei) }, + {1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) }, + {1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) }, + + {1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) }, + {1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) }, + {1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) }, + {1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) }, + {1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) }, + {1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) }, + {1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) }, + {1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) }, + + {1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) }, + {1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) }, + {1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) }, + {1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) }, + {1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) }, + {1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) }, + {1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) }, + {1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) } +}; + +void cop400_cpu_device::cop420_op33(UINT8 opcode) +{ + UINT8 opcode33 = ROM(PC++); + + (this->*COP420_OPCODE_33_MAP[opcode33].function)(opcode33); +} + +const cop400_cpu_device::cop400_opcode_map cop400_cpu_device::COP420_OPCODE_MAP[256] = +{ + {1, INST(clra) },{1, INST(skmbz0) },{1, INST(xor_) },{1, INST(skmbz2) },{1, INST(xis) },{1, INST(ld) },{1, INST(x) },{1, INST(xds) }, + {1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) }, + {1, INST(casc) },{1, INST(skmbz1) },{1, INST(xabr) },{1, INST(skmbz3) },{1, INST(xis) },{1, INST(ld) },{1, INST(x) },{1, INST(xds) }, + {1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) }, + {1, INST(skc) },{1, INST(ske) },{1, INST(sc) },{1, INST(cop420_op23) },{1, INST(xis) },{1, INST(ld) },{1, INST(x) },{1, INST(xds) }, + {1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) }, + {1, INST(asc) },{1, INST(add) },{1, INST(rc) },{1, INST(cop420_op33) },{1, INST(xis) },{1, INST(ld) },{1, INST(x) },{1, INST(xds) }, + {1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) }, + + {1, INST(comp) },{1, INST(skt) },{1, INST(rmb2) },{1, INST(rmb3) },{1, INST(nop) },{1, INST(rmb1) },{1, INST(smb2) },{1, INST(smb1) }, + {1, INST(cop420_ret) },{1, INST(retsk) },{1, INST(adt) },{1, INST(smb3) },{1, INST(rmb0) },{1, INST(smb0) },{1, INST(cba) },{1, INST(xas) }, + {1, INST(cab) },{1, INST(aisc) },{1, INST(aisc) },{1, INST(aisc) },{1, INST(aisc) },{1, INST(aisc) },{1, INST(aisc) },{1, INST(aisc) }, + {1, INST(aisc) },{1, INST(aisc) },{1, INST(aisc) },{1, INST(aisc) },{1, INST(aisc) },{1, INST(aisc) },{1, INST(aisc) },{1, INST(aisc) }, + {2, INST(jmp) },{2, INST(jmp) },{2, INST(jmp) },{2, INST(jmp) },{0, INST(illegal) },{0, INST(illegal) },{0, INST(illegal) },{0, INST(illegal) }, + {2, INST(jsr) },{2, INST(jsr) },{2, INST(jsr) },{2, INST(jsr) },{0, INST(illegal) },{0, INST(illegal) },{0, INST(illegal) },{0, INST(illegal) }, + {1, INST(stii) },{1, INST(stii) },{1, INST(stii) },{1, INST(stii) },{1, INST(stii) },{1, INST(stii) },{1, INST(stii) },{1, INST(stii) }, + {1, INST(stii) },{1, INST(stii) },{1, INST(stii) },{1, INST(stii) },{1, INST(stii) },{1, INST(stii) },{1, INST(stii) },{1, INST(stii) }, + + {1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) }, + {1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) }, + {1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) }, + {1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) }, + {1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) }, + {1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) }, + {1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) }, + {1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{2, INST(lqid) }, + + {1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) }, + {1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) }, + {1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) }, + {1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) }, + {1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) }, + {1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) }, + {1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) }, + {1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{2, INST(jid) } +}; + +const cop400_cpu_device::cop400_opcode_map cop400_cpu_device::COP444_OPCODE_23_MAP[256] = +{ + {1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) }, + {1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) }, + {1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) }, + {1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) }, + {1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) }, + {1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) }, + {1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) }, + {1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) }, + + {1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) }, + {1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) }, + {1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) }, + {1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) }, + {1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) }, + {1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) }, + {1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) }, + {1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) },{1, INST(ldd) }, + + {1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) }, + {1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) }, + {1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) }, + {1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) }, + {1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) }, + {1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) }, + {1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) }, + {1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) }, + + {1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) }, + {1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) }, + {1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) }, + {1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) }, + {1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) }, + {1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) }, + {1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) }, + {1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) },{1, INST(xad) }, +}; + +void cop400_cpu_device::cop444_op23(UINT8 opcode) +{ + UINT8 opcode23 = ROM(PC++); + + (this->*COP444_OPCODE_23_MAP[opcode23].function)(opcode23); +} + +const cop400_cpu_device::cop400_opcode_map cop400_cpu_device::COP444_OPCODE_33_MAP[256] = +{ + {1, INST(illegal) },{1, INST(skgbz0) },{1, INST(illegal) },{1, INST(skgbz2) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) }, + {1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) }, + {1, INST(illegal) },{1, INST(skgbz1) },{1, INST(illegal) },{1, INST(skgbz3) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) }, + {1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) }, + {1, INST(illegal) },{1, INST(skgz) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) }, + {1, INST(inin) },{1, INST(inil) },{1, INST(ing) },{1, INST(illegal) },{1, INST(cqma) },{1, INST(illegal) },{1, INST(inl) },{1, INST(ctma) }, + {1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) }, + {1, INST(it) },{1, INST(illegal) },{1, INST(omg) },{1, INST(illegal) },{1, INST(camq) },{1, INST(illegal) },{1, INST(obd) },{1, INST(camt) }, + + {1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) }, + {1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) }, + {1, INST(ogi) },{1, INST(ogi) },{1, INST(ogi) },{1, INST(ogi) },{1, INST(ogi) },{1, INST(ogi) },{1, INST(ogi) },{1, INST(ogi) }, + {1, INST(ogi) },{1, INST(ogi) },{1, INST(ogi) },{1, INST(ogi) },{1, INST(ogi) },{1, INST(ogi) },{1, INST(ogi) },{1, INST(ogi) }, + {1, INST(lei) },{1, INST(lei) },{1, INST(lei) },{1, INST(lei) },{1, INST(lei) },{1, INST(lei) },{1, INST(lei) },{1, INST(lei) }, + {1, INST(lei) },{1, INST(lei) },{1, INST(lei) },{1, INST(lei) },{1, INST(lei) },{1, INST(lei) },{1, INST(lei) },{1, INST(lei) }, + {1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) }, + {1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) },{1, INST(illegal) }, + + {1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) }, + {1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) }, + {1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) }, + {1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) }, + {1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) }, + {1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) }, + {1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) }, + {1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) }, + + {1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) }, + {1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) }, + {1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) }, + {1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) }, + {1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) }, + {1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) }, + {1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) }, + {1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) }, +}; + +void cop400_cpu_device::cop444_op33(UINT8 opcode) +{ + UINT8 opcode33 = ROM(PC++); + + (this->*COP444_OPCODE_33_MAP[opcode33].function)(opcode33); +} + +const cop400_cpu_device::cop400_opcode_map cop400_cpu_device::COP444_OPCODE_MAP[256] = +{ + {1, INST(clra) },{1, INST(skmbz0) },{1, INST(xor_) },{1, INST(skmbz2) },{1, INST(xis) },{1, INST(ld) },{1, INST(x) },{1, INST(xds) }, + {1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) }, + {1, INST(casc) },{1, INST(skmbz1) },{1, INST(cop444_xabr)},{1, INST(skmbz3) },{1, INST(xis) },{1, INST(ld) },{1, INST(x) },{1, INST(xds) }, + {1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) }, + {1, INST(skc) },{1, INST(ske) },{1, INST(sc) },{1, INST(cop444_op23) },{1, INST(xis) },{1, INST(ld) },{1, INST(x) },{1, INST(xds) }, + {1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) }, + {1, INST(asc) },{1, INST(add) },{1, INST(rc) },{1, INST(cop444_op33) },{1, INST(xis) },{1, INST(ld) },{1, INST(x) },{1, INST(xds) }, + {1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) },{1, INST(lbi) }, + + {1, INST(comp) },{1, INST(skt) },{1, INST(rmb2) },{1, INST(rmb3) },{1, INST(nop) },{1, INST(rmb1) },{1, INST(smb2) },{1, INST(smb1) }, + {1, INST(cop420_ret) },{1, INST(retsk) },{1, INST(adt) },{1, INST(smb3) },{1, INST(rmb0) },{1, INST(smb0) },{1, INST(cba) },{1, INST(xas) }, + {1, INST(cab) },{1, INST(aisc) },{1, INST(aisc) },{1, INST(aisc) },{1, INST(aisc) },{1, INST(aisc) },{1, INST(aisc) },{1, INST(aisc) }, + {1, INST(aisc) },{1, INST(aisc) },{1, INST(aisc) },{1, INST(aisc) },{1, INST(aisc) },{1, INST(aisc) },{1, INST(aisc) },{1, INST(aisc) }, + {2, INST(jmp) },{2, INST(jmp) },{2, INST(jmp) },{2, INST(jmp) },{2, INST(jmp) },{2, INST(jmp) },{2, INST(jmp) },{2, INST(jmp) }, + {2, INST(jsr) },{2, INST(jsr) },{2, INST(jsr) },{2, INST(jsr) },{2, INST(jsr) },{2, INST(jsr) },{2, INST(jsr) },{2, INST(jsr) }, + {1, INST(stii) },{1, INST(stii) },{1, INST(stii) },{1, INST(stii) },{1, INST(stii) },{1, INST(stii) },{1, INST(stii) },{1, INST(stii) }, + {1, INST(stii) },{1, INST(stii) },{1, INST(stii) },{1, INST(stii) },{1, INST(stii) },{1, INST(stii) },{1, INST(stii) },{1, INST(stii) }, + + {1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) }, + {1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) }, + {1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) }, + {1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) }, + {1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) }, + {1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) }, + {1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) }, + {1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{2, INST(lqid) }, + + {1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) }, + {1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) }, + {1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) }, + {1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) }, + {1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) }, + {1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) }, + {1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) }, + {1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{1, INST(jp) },{2, INST(jid) } +}; + +/*************************************************************************** + TIMER CALLBACKS +***************************************************************************/ + +void cop400_cpu_device::serial_tick() +{ + if (BIT(EN, 0)) + { + /* + + SIO is an asynchronous binary counter decrementing its value by one upon each low-going pulse ("1" to "0") occurring on the SI input. + Each pulse must remain at each logic level at least two instruction cycles. SK outputs the value of the C upon the execution of an XAS + and remains latched until the execution of another XAS instruction. The SO output is equal to the value of EN3. + + */ + + // serial output + + OUT_SO(BIT(EN, 3)); + + // serial clock + + OUT_SK(SKL); + + // serial input + + m_si <<= 1; + m_si = (m_si & 0x0e) | IN_SI(); + + if ((m_si & 0x0f) == 0x0c) // 1100 + { + SIO--; + SIO &= 0x0f; + } + } + else + { + /* + + SIO is a serial shift register, shifting continuously left each instruction cycle time. The data present at SI goes into the least + significant bit of SIO: SO can be enabled to output the most significant bit of SIO each cycle time. SK output becomes a logic- + controlled clock, providing a SYNC signal each instruction time. It will start outputting a SYNC pulse upon the execution of an XAS + instruction with C = "1," stopping upon the execution of a subsequent XAS with C = "0". + + If EN0 is changed from "1" to "0" ("0" to "1") the SK output will change from "1" to SYNC (SYNC to "1") without the execution of + an XAS instruction. + + */ + + // serial output + + if (BIT(EN, 3)) + { + OUT_SO(BIT(SIO, 3)); + } + else + { + OUT_SO(0); + } + + // serial clock + + if (SKL) + { + OUT_SK(1); // SYNC + } + else + { + OUT_SK(0); + } + + // serial input + + SIO = ((SIO << 1) | IN_SI()) & 0x0f; + } +} + +void cop400_cpu_device::counter_tick() +{ + T++; + + if (T == 0) + { + m_skt_latch = 1; + + if (m_idle) + { + m_idle = 0; + m_halt = 0; + } + } +} + +void cop400_cpu_device::inil_tick() +{ + UINT8 in; + int i; + + in = IN_IN(); + + for (i = 0; i < 4; i++) + { + m_in[i] = (m_in[i] << 1) | BIT(in, i); + + if ((m_in[i] & 0x07) == 0x04) // 100 + { + IL |= (1 << i); + } + } +} + +void cop400_cpu_device::microbus_tick() +{ + UINT8 in; + + in = IN_IN(); + + if (!BIT(in, 2)) + { + // chip select + + if (!BIT(in, 1)) + { + // read strobe + + OUT_L(Q); + + m_microbus_int = 1; + } + else if (!BIT(in, 3)) + { + // write strobe + + Q = IN_L(); + + m_microbus_int = 0; + } + } +} + +/*************************************************************************** + INITIALIZATION +***************************************************************************/ + +enum { + TIMER_SERIAL, + TIMER_COUNTER, + TIMER_INIL, + TIMER_MICROBUS +}; + +void cop400_cpu_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch (id) + { + case TIMER_SERIAL: + serial_tick(); + break; + + case TIMER_COUNTER: + counter_tick(); + break; + + case TIMER_INIL: + inil_tick(); + break; + + case TIMER_MICROBUS: + microbus_tick(); + break; + } +} + + +void cop400_cpu_device::device_start() +{ + /* find address spaces */ + + m_program = &space(AS_PROGRAM); + m_direct = &m_program->direct(); + m_data = &space(AS_DATA); + + /* find i/o handlers */ + + m_read_l.resolve_safe(0); + m_write_l.resolve_safe(); + m_read_g.resolve_safe(0); + m_write_g.resolve_safe(); + m_write_d.resolve_safe(); + m_read_in.resolve_safe(0); + m_read_si.resolve_safe(0); + m_write_so.resolve_safe(); + m_write_sk.resolve_safe(); + m_read_cko.resolve_safe(0); + + /* allocate serial timer */ + + m_serial_timer = timer_alloc(TIMER_SERIAL); + m_serial_timer->adjust(attotime::zero, 0, attotime::from_ticks(16, clock())); + + /* allocate counter timer */ + + m_counter_timer = NULL; + if (m_has_counter) + { + m_counter_timer = timer_alloc(TIMER_COUNTER); + m_counter_timer->adjust(attotime::zero, 0, attotime::from_ticks(16 * 4, clock())); + } + + /* allocate IN latch timer */ + + m_inil_timer = NULL; + if (m_has_inil) + { + m_inil_timer = timer_alloc(TIMER_INIL); + m_inil_timer->adjust(attotime::zero, 0, attotime::from_ticks(16, clock())); + } + + /* allocate Microbus timer */ + + m_microbus_timer = NULL; + if (m_microbus == COP400_MICROBUS_ENABLED) + { + m_microbus_timer = timer_alloc(TIMER_MICROBUS); + m_microbus_timer->adjust(attotime::zero, 0, attotime::from_ticks(16, clock())); + } + + /* register for state saving */ + + save_item(NAME(m_pc)); + save_item(NAME(m_prevpc)); + save_item(NAME(m_n)); + save_item(NAME(m_sa)); + save_item(NAME(m_sb)); + save_item(NAME(m_sc)); + save_item(NAME(m_a)); + save_item(NAME(m_b)); + save_item(NAME(m_c)); + save_item(NAME(m_g)); + save_item(NAME(m_h)); + save_item(NAME(m_q)); + save_item(NAME(m_r)); + save_item(NAME(m_en)); + save_item(NAME(m_sio)); + save_item(NAME(m_skl)); + save_item(NAME(m_t)); + save_item(NAME(m_skip)); + save_item(NAME(m_skip_lbi)); + save_item(NAME(m_skt_latch)); + save_item(NAME(m_si)); + save_item(NAME(m_last_skip)); + save_item(NAME(m_in)); + save_item(NAME(m_microbus_int)); + save_item(NAME(m_halt)); + save_item(NAME(m_idle)); + + state_add(STATE_GENPC, "GENPC", m_pc).mask(0xfff).noshow(); + state_add(STATE_GENPCBASE, "GENPCBASE", m_prevpc).mask(0xfff).noshow(); + state_add(STATE_GENSP, "GENSP", m_n).mask(0x3).noshow(); + state_add(STATE_GENFLAGS, "GENFLAGS", m_flags).mask(0x3).callimport().callexport().noshow().formatstr("%3s"); + + state_add(COP400_PC, "PC", m_pc).mask(0xfff); + + if (m_featuremask & (COP410_FEATURE | COP420_FEATURE | COP444_FEATURE)) + { + state_add(COP400_SA, "SA", m_sa).mask(0xfff); + state_add(COP400_SB, "SB", m_sb).mask(0xfff); + if (m_featuremask & (COP420_FEATURE | COP444_FEATURE)) + { + state_add(COP400_SC, "SC", m_sc).mask(0xfff); + } + } + if (m_featuremask & COP440_FEATURE) + { + state_add(COP400_N, "N", m_n).mask(0x3); + } + + state_add(COP400_A, "A", m_a).mask(0xf); + state_add(COP400_B, "B", m_b); + state_add(COP400_C, "C", m_c).mask(0x1); + + state_add(COP400_EN, "EN", m_en).mask(0xf); + state_add(COP400_G, "G", m_g).mask(0xf); + if (m_featuremask & COP440_FEATURE) + { + state_add(COP400_H, "H", m_h).mask(0xf); + } + state_add(COP400_Q, "Q", m_q); + if (m_featuremask & COP440_FEATURE) + { + state_add(COP400_R, "R", m_r); + } + + state_add(COP400_SIO, "SIO", m_sio).mask(0xf); + state_add(COP400_SKL, "SKL", m_skl).mask(0x1); + + if (m_featuremask & (COP420_FEATURE | COP444_FEATURE | COP440_FEATURE)) + { + state_add(COP400_T, "T", m_t); + } + + m_icountptr = &m_icount; + + m_n = 0; + m_q = 0; + m_sa = 0; + m_sb = 0; + m_sc = 0; + m_sio = 0; + m_h = 0; + m_r = 0; + m_flags = 0; + m_il = 0; + m_in[0] = m_in[1] = m_in[2] = m_in[3] = 0; + m_si = 0; + m_skip_lbi = 0; + m_last_skip = 0; + m_microbus_int = 0; + m_skip = 0; +} + + +/*************************************************************************** + RESET +***************************************************************************/ + +void cop400_cpu_device::device_reset() +{ + PC = 0; + A = 0; + B = 0; + C = 0; + OUT_D(0); + EN = 0; + WRITE_G(0); + SKL = 1; + + T = 0; + m_skt_latch = 1; + + m_halt = 0; + m_idle = 0; +} + +/*************************************************************************** + EXECUTION +***************************************************************************/ + +void cop400_cpu_device::execute_run() +{ + do + { + m_prevpc = PC; + + debugger_instruction_hook(this, PC); + + if (m_cko == COP400_CKO_HALT_IO_PORT) + { + m_halt = IN_CKO(); + } + + if (m_halt) + { + m_icount -= 1; + continue; + } + + UINT8 opcode = ROM(PC); + int inst_cycles = m_opcode_map[opcode].cycles; + + PC++; + + (this->*(m_opcode_map[opcode].function))(opcode); + m_icount -= inst_cycles; + if (m_skip_lbi > 0) m_skip_lbi--; + + // check for interrupt + + if (BIT(EN, 1) && BIT(IL, 1)) + { + cop400_opcode_func function = m_opcode_map[ROM(PC)].function; + + // all successive transfer of control instructions and successive LBIs have been completed + if ((function != INST(jp)) && (function != INST(jmp)) && (function != INST(jsr)) && !m_skip_lbi) + { + // store skip logic + m_last_skip = m_skip; + m_skip = 0; + + // push next PC + PUSH(PC); + + // jump to interrupt service routine + PC = 0x0ff; + + // disable interrupt + EN &= ~0x02; + } + + IL &= ~2; + } + + // skip next instruction? + + if (m_skip) + { + cop400_opcode_func function = m_opcode_map[ROM(PC)].function; + + opcode = ROM(PC); + + if ((function == INST(lqid)) || (function == INST(jid))) + { + m_icount -= 1; + } + else + { + m_icount -= m_opcode_map[opcode].cycles; + } + + PC += m_InstLen[opcode]; + + m_skip = 0; + } + } while (m_icount > 0); +} + + +/*************************************************************************** + GENERAL CONTEXT ACCESS +***************************************************************************/ + +void cop400_cpu_device::state_import(const device_state_entry &entry) +{ + switch (entry.index()) + { + case STATE_GENFLAGS: + m_c = (m_flags >> 1) & 1; + m_skl = (m_flags >> 0) & 1; + break; + } +} + +void cop400_cpu_device::state_export(const device_state_entry &entry) +{ + switch (entry.index()) + { + case STATE_GENFLAGS: + m_flags = (m_c ? 0x02 : 0x00) | (m_skl ? 0x01 : 0x00); + break; + } +} + +void cop400_cpu_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + switch (entry.index()) + { + case STATE_GENFLAGS: + strprintf(str, "%c%c%c", + m_c ? 'C' : '.', + m_skl ? 'S' : '.', + m_skt_latch ? 'T' : '.'); + break; + } +} + + +offs_t cop400_cpu_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( cop410 ); + extern CPU_DISASSEMBLE( cop420 ); + extern CPU_DISASSEMBLE( cop444 ); + + if ( m_featuremask & COP444_FEATURE ) + { + return CPU_DISASSEMBLE_NAME(cop444)(this, buffer, pc, oprom, opram, options); + } + + if ( m_featuremask & COP420_FEATURE ) + { + return CPU_DISASSEMBLE_NAME(cop420)(this, buffer, pc, oprom, opram, options); + } + + return CPU_DISASSEMBLE_NAME(cop410)(this, buffer, pc, oprom, opram, options); +} diff --git a/src/devices/cpu/cop400/cop400.h b/src/devices/cpu/cop400/cop400.h new file mode 100644 index 00000000000..aba03516d39 --- /dev/null +++ b/src/devices/cpu/cop400/cop400.h @@ -0,0 +1,499 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/*************************************************************************** + + cop400.h + + National Semiconductor COPS Emulator. + +***************************************************************************/ + +#pragma once + +#ifndef __COP400__ +#define __COP400__ + +// i/o pins + +// L pins: 8-bit bi-directional +#define MCFG_COP400_READ_L_CB(_devcb) \ + cop400_cpu_device::set_read_l_callback(*device, DEVCB_##_devcb); +#define MCFG_COP400_WRITE_L_CB(_devcb) \ + cop400_cpu_device::set_write_l_callback(*device, DEVCB_##_devcb); + +// G pins: 4-bit bi-directional +#define MCFG_COP400_READ_G_CB(_devcb) \ + cop400_cpu_device::set_read_g_callback(*device, DEVCB_##_devcb); +#define MCFG_COP400_WRITE_G_CB(_devcb) \ + cop400_cpu_device::set_write_g_callback(*device, DEVCB_##_devcb); + +// D outputs: 4-bit general purpose output +#define MCFG_COP400_WRITE_D_CB(_devcb) \ + cop400_cpu_device::set_write_d_callback(*device, DEVCB_##_devcb); + +// IN inputs: 4-bit general purpose input +#define MCFG_COP400_READ_IN_CB(_devcb) \ + cop400_cpu_device::set_read_in_callback(*device, DEVCB_##_devcb); + +// SI/SO lines: serial in/out or counter/gen.purpose +#define MCFG_COP400_READ_SI_CB(_devcb) \ + cop400_cpu_device::set_read_si_callback(*device, DEVCB_##_devcb); +#define MCFG_COP400_WRITE_SO_CB(_devcb) \ + cop400_cpu_device::set_write_so_callback(*device, DEVCB_##_devcb); + +// SK output line: logic-controlled clock or gen.purpose +#define MCFG_COP400_WRITE_SK_CB(_devcb) \ + cop400_cpu_device::set_write_sk_callback(*device, DEVCB_##_devcb); + +// CKI/CKO lines: only CKO input here +#define MCFG_COP400_READ_CKO_CB(_devcb) \ + cop400_cpu_device::set_read_cko_callback(*device, DEVCB_##_devcb); + + +/*************************************************************************** + CONSTANTS +***************************************************************************/ + +/* register access indexes */ +enum +{ + COP400_PC, + COP400_SA, + COP400_SB, + COP400_SC, + COP400_N, + COP400_A, + COP400_B, + COP400_C, + COP400_G, + COP400_H, + COP400_Q, + COP400_R, + COP400_EN, + COP400_SIO, + COP400_SKL, + COP400_T, + COP400_GENPC = STATE_GENPC, + COP400_GENPCBASE = STATE_GENPCBASE, + COP400_GENSP = STATE_GENSP +}; + +/* input lines */ +enum +{ + /* COP420 */ + COP400_IN0 = 0, + COP400_IN1, + COP400_IN2, + COP400_IN3, + + /* COP404 */ + COP400_MB, + COP400_DUAL, + COP400_SEL10, + COP400_SEL20 +}; + +/* CKI bonding options */ +enum cop400_cki_bond { + COP400_CKI_DIVISOR_4 = 4, + COP400_CKI_DIVISOR_8 = 8, + COP400_CKI_DIVISOR_16 = 16, + COP400_CKI_DIVISOR_32 = 32 +}; + +/* CKO bonding options */ +enum cop400_cko_bond { + COP400_CKO_OSCILLATOR_OUTPUT = 0, + COP400_CKO_RAM_POWER_SUPPLY, + COP400_CKO_HALT_IO_PORT, + COP400_CKO_SYNC_INPUT, + COP400_CKO_GENERAL_PURPOSE_INPUT +}; + +/* microbus bonding options */ +enum cop400_microbus { + COP400_MICROBUS_DISABLED = 0, + COP400_MICROBUS_ENABLED +}; + + +#define MCFG_COP400_CONFIG(_cki, _cko, _microbus) \ + cop400_cpu_device::set_cki(*device, _cki); \ + cop400_cpu_device::set_cko(*device, _cko); \ + cop400_cpu_device::set_microbus(*device, _microbus); + + +class cop400_cpu_device : public cpu_device +{ +public: + // construction/destruction + cop400_cpu_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source, UINT8 program_addr_bits, UINT8 data_addr_bits, UINT8 featuremask, UINT8 g_mask, UINT8 d_mask, UINT8 in_mask, bool has_counter, bool has_inil, address_map_constructor internal_map_program, address_map_constructor internal_map_data); + + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + // static configuration helpers + template static devcb_base &set_read_l_callback(device_t &device, _Object object) { return downcast(device).m_read_l.set_callback(object); } + template static devcb_base &set_write_l_callback(device_t &device, _Object object) { return downcast(device).m_write_l.set_callback(object); } + template static devcb_base &set_read_g_callback(device_t &device, _Object object) { return downcast(device).m_read_g.set_callback(object); } + template static devcb_base &set_write_g_callback(device_t &device, _Object object) { return downcast(device).m_write_g.set_callback(object); } + template static devcb_base &set_write_d_callback(device_t &device, _Object object) { return downcast(device).m_write_d.set_callback(object); } + template static devcb_base &set_read_in_callback(device_t &device, _Object object) { return downcast(device).m_read_in.set_callback(object); } + template static devcb_base &set_read_si_callback(device_t &device, _Object object) { return downcast(device).m_read_si.set_callback(object); } + template static devcb_base &set_write_so_callback(device_t &device, _Object object) { return downcast(device).m_write_so.set_callback(object); } + template static devcb_base &set_write_sk_callback(device_t &device, _Object object) { return downcast(device).m_write_sk.set_callback(object); } + template static devcb_base &set_read_cko_callback(device_t &device, _Object object) { return downcast(device).m_read_cko.set_callback(object); } + + static void set_cki(device_t &device, cop400_cki_bond cki) { downcast(device).m_cki = cki; } + static void set_cko(device_t &device, cop400_cko_bond cko) { downcast(device).m_cko = cko; } + static void set_microbus(device_t &device, cop400_microbus microbus) { downcast(device).m_microbus = microbus; } + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_execute_interface overrides + virtual UINT64 execute_clocks_to_cycles(UINT64 clocks) const { return (clocks + m_cki - 1) / m_cki; } + virtual UINT64 execute_cycles_to_clocks(UINT64 cycles) const { return (cycles * m_cki); } + virtual UINT32 execute_min_cycles() const { return 1; } + virtual UINT32 execute_max_cycles() const { return 2; } + virtual UINT32 execute_input_lines() const { return 0; } + virtual void execute_run(); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const + { + return (spacenum == AS_PROGRAM) ? &m_program_config : ( (spacenum == AS_DATA) ? &m_data_config : NULL ); + } + + // device_state_interface overrides + virtual void state_import(const device_state_entry &entry); + virtual void state_export(const device_state_entry &entry); + void state_string_export(const device_state_entry &entry, std::string &str); + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const { return 1; } + virtual UINT32 disasm_max_opcode_bytes() const { return 2; } + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + + address_space_config m_program_config; + address_space_config m_data_config; + + // i/o handlers + devcb_read8 m_read_l; + devcb_write8 m_write_l; + devcb_read8 m_read_g; + devcb_write8 m_write_g; + devcb_write8 m_write_d; + devcb_read8 m_read_in; + devcb_read_line m_read_si; + devcb_write_line m_write_so; + devcb_write_line m_write_sk; + devcb_read_line m_read_cko; + + cop400_cki_bond m_cki; + cop400_cko_bond m_cko; + cop400_microbus m_microbus; + + bool m_has_counter; + bool m_has_inil; + + address_space *m_program; + direct_read_data *m_direct; + address_space *m_data; + + UINT8 m_featuremask; + + /* registers */ + UINT16 m_pc; /* 9/10/11-bit ROM address program counter */ + UINT16 m_prevpc; /* previous value of program counter */ + UINT8 m_a; /* 4-bit accumulator */ + UINT8 m_b; /* 5/6/7-bit RAM address register */ + int m_c; /* 1-bit carry register */ + UINT8 m_n; /* 2-bit stack pointer (COP440 only) */ + UINT8 m_en; /* 4-bit enable register */ + UINT8 m_g; /* 4-bit general purpose I/O port */ + UINT8 m_q; /* 8-bit latch for L port */ + UINT16 m_sa, m_sb, m_sc; /* subroutine save registers (not present in COP440) */ + UINT8 m_sio; /* 4-bit shift register and counter */ + int m_skl; /* 1-bit latch for SK output */ + UINT8 m_h; /* 4-bit general purpose I/O port (COP440 only) */ + UINT8 m_r; /* 8-bit general purpose I/O port (COP440 only) */ + UINT8 m_flags; // used for I/O only + + /* counter */ + UINT8 m_t; /* 8-bit timer */ + int m_skt_latch; /* timer overflow latch */ + + /* input/output ports */ + UINT8 m_g_mask; /* G port mask */ + UINT8 m_d_mask; /* D port mask */ + UINT8 m_in_mask; /* IN port mask */ + UINT8 m_il; /* IN latch */ + UINT8 m_in[4]; /* IN port shift register */ + UINT8 m_si; /* serial input */ + + /* skipping logic */ + int m_skip; /* skip next instruction */ + int m_skip_lbi; /* skip until next non-LBI instruction */ + int m_last_skip; /* last value of skip */ + int m_halt; /* halt mode */ + int m_idle; /* idle mode */ + + /* microbus */ + int m_microbus_int; /* microbus interrupt */ + + /* execution logic */ + int m_InstLen[256]; /* instruction length in bytes */ + int m_icount; /* instruction counter */ + + /* timers */ + emu_timer *m_serial_timer; + emu_timer *m_counter_timer; + emu_timer *m_inil_timer; + emu_timer *m_microbus_timer; + + typedef void ( cop400_cpu_device::*cop400_opcode_func ) (UINT8 opcode); + + /* The opcode table now is a combination of cycle counts and function pointers */ + struct cop400_opcode_map { + UINT32 cycles; + cop400_opcode_func function; + }; + + const cop400_opcode_map *m_opcode_map; + + static const cop400_opcode_map COP410_OPCODE_23_MAP[256]; + static const cop400_opcode_map COP410_OPCODE_33_MAP[256]; + static const cop400_opcode_map COP410_OPCODE_MAP[256]; + static const cop400_opcode_map COP420_OPCODE_23_MAP[256]; + static const cop400_opcode_map COP420_OPCODE_33_MAP[256]; + static const cop400_opcode_map COP420_OPCODE_MAP[256]; + static const cop400_opcode_map COP444_OPCODE_23_MAP[256]; + static const cop400_opcode_map COP444_OPCODE_33_MAP[256]; + static const cop400_opcode_map COP444_OPCODE_MAP[256]; + + void serial_tick(); + void counter_tick(); + void inil_tick(); + void microbus_tick(); + + void PUSH(UINT16 data); + void POP(); + void WRITE_Q(UINT8 data); + void WRITE_G(UINT8 data); + + void illegal(UINT8 opcode); + void asc(UINT8 opcode); + void add(UINT8 opcode); + void aisc(UINT8 opcode); + void clra(UINT8 opcode); + void comp(UINT8 opcode); + void nop(UINT8 opcode); + void rc(UINT8 opcode); + void sc(UINT8 opcode); + void xor_(UINT8 opcode); + void adt(UINT8 opcode); + void casc(UINT8 opcode); + void jid(UINT8 opcode); + void jmp(UINT8 opcode); + void jp(UINT8 opcode); + void jsr(UINT8 opcode); + void ret(UINT8 opcode); + void cop420_ret(UINT8 opcode); + void retsk(UINT8 opcode); + void halt(UINT8 opcode); + void it(UINT8 opcode); + void camq(UINT8 opcode); + void ld(UINT8 opcode); + void lqid(UINT8 opcode); + void rmb0(UINT8 opcode); + void rmb1(UINT8 opcode); + void rmb2(UINT8 opcode); + void rmb3(UINT8 opcode); + void smb0(UINT8 opcode); + void smb1(UINT8 opcode); + void smb2(UINT8 opcode); + void smb3(UINT8 opcode); + void stii(UINT8 opcode); + void x(UINT8 opcode); + void xad(UINT8 opcode); + void xds(UINT8 opcode); + void xis(UINT8 opcode); + void cqma(UINT8 opcode); + void ldd(UINT8 opcode); + void camt(UINT8 opcode); + void ctma(UINT8 opcode); + void cab(UINT8 opcode); + void cba(UINT8 opcode); + void lbi(UINT8 opcode); + void lei(UINT8 opcode); + void xabr(UINT8 opcode); + void cop444_xabr(UINT8 opcode); + void skc(UINT8 opcode); + void ske(UINT8 opcode); + void skgz(UINT8 opcode); + void skgbz0(UINT8 opcode); + void skgbz1(UINT8 opcode); + void skgbz2(UINT8 opcode); + void skgbz3(UINT8 opcode); + void skmbz0(UINT8 opcode); + void skmbz1(UINT8 opcode); + void skmbz2(UINT8 opcode); + void skmbz3(UINT8 opcode); + void skt(UINT8 opcode); + void ing(UINT8 opcode); + void inl(UINT8 opcode); + void obd(UINT8 opcode); + void omg(UINT8 opcode); + void xas(UINT8 opcode); + void inin(UINT8 opcode); + void cop402m_inin(UINT8 opcode); + void inil(UINT8 opcode); + void ogi(UINT8 opcode); + void cop410_op23(UINT8 opcode); + void cop410_op33(UINT8 opcode); + void cop420_op23(UINT8 opcode); + void cop420_op33(UINT8 opcode); + void cop444_op23(UINT8 opcode); + void cop444_op33(UINT8 opcode); + void skgbz(int bit); + void skmbz(int bit); + +}; + + +/* COP410 family */ +// COP401 is a ROMless version of the COP410 +class cop401_cpu_device : public cop400_cpu_device +{ +public: + // construction/destruction + cop401_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +class cop410_cpu_device : public cop400_cpu_device +{ +public: + // construction/destruction + cop410_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +// COP411 is a 20-pin package version of the COP410, missing D2/D3/G3/CKO +class cop411_cpu_device : public cop400_cpu_device +{ +public: + // construction/destruction + cop411_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +/* COP420 family */ +// COP402 is a ROMless version of the COP420 +class cop402_cpu_device : public cop400_cpu_device +{ +public: + // construction/destruction + cop402_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +class cop420_cpu_device : public cop400_cpu_device +{ +public: + // construction/destruction + cop420_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +// COP421 is a 24-pin package version of the COP420, lacking the IN ports +class cop421_cpu_device : public cop400_cpu_device +{ +public: + // construction/destruction + cop421_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +// COP422 is a 20-pin package version of the COP420, lacking G0/G1, D0/D1, and the IN ports +class cop422_cpu_device : public cop400_cpu_device +{ +public: + // construction/destruction + cop422_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +/* COP444 family */ +// COP404 is a ROMless version of the COP444, which can emulate a COP410C/COP411C, COP424C/COP425C, or a COP444C/COP445C +class cop404_cpu_device : public cop400_cpu_device +{ +public: + // construction/destruction + cop404_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +// COP424 is functionally equivalent to COP444, with only 1K ROM and 64x4 bytes RAM +class cop424_cpu_device : public cop400_cpu_device +{ +public: + // construction/destruction + cop424_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +// COP425 is a 24-pin package version of the COP424, lacking the IN ports +class cop425_cpu_device : public cop400_cpu_device +{ +public: + // construction/destruction + cop425_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +// COP426 is a 20-pin package version of the COP424, with only L0-L7, G2-G3, D2-D3 ports +class cop426_cpu_device : public cop400_cpu_device +{ +public: + // construction/destruction + cop426_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +class cop444_cpu_device : public cop400_cpu_device +{ +public: + // construction/destruction + cop444_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +// COP445 is a 24-pin package version of the COP444, lacking the IN ports +class cop445_cpu_device : public cop400_cpu_device +{ +public: + // construction/destruction + cop445_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +extern const device_type COP401; +extern const device_type COP410; +extern const device_type COP411; +extern const device_type COP402; +extern const device_type COP420; +extern const device_type COP421; +extern const device_type COP422; +extern const device_type COP404; +extern const device_type COP424; +extern const device_type COP425; +extern const device_type COP426; +extern const device_type COP444; +extern const device_type COP445; + + +#endif /* __COP400__ */ diff --git a/src/devices/cpu/cop400/cop400op.inc b/src/devices/cpu/cop400/cop400op.inc new file mode 100644 index 00000000000..1f1bf1bfade --- /dev/null +++ b/src/devices/cpu/cop400/cop400op.inc @@ -0,0 +1,1319 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/*************************************************************************** + + cop400op.inc + + National Semiconductor COP400 Emulator. + +***************************************************************************/ + +/*************************************************************************** + ARITHMETIC INSTRUCTIONS +***************************************************************************/ + +/* + + Mnemonic: ASC + + Hex Code: 30 + Binary: 0 0 1 1 0 0 0 0 + + Data Flow: A + C + RAM(B) -> A + Carry -> C + + Skip Conditions: Carry + + Description: Add with Carry, Skip on Carry + +*/ + +INSTRUCTION( asc ) +{ + A = A + C + RAM_R(B); + + if (A > 0xF) + { + C = 1; + m_skip = 1; + A &= 0xF; + } + else + { + C = 0; + } +} + +/* + + Mnemonic: ADD + + Hex Code: 31 + Binary: 0 0 1 1 0 0 0 1 + + Data Flow: A + RAM(B) -> A + + Description: Add RAM to A + +*/ + +INSTRUCTION( add ) +{ + A = (A + RAM_R(B)) & 0x0F; +} + +/* + + Mnemonic: AISC + + Operand: y + Hex Code: 5- + Binary: 0 1 0 1 y3 y2 y1 y0 + + Data Flow: A + y -> A + + Skip Conditions: Carry + + Description: Add Immediate, Skip on Carry (y != 0) + +*/ + +INSTRUCTION( aisc ) +{ + UINT8 y = opcode & 0x0f; + + A = A + y; + + if (A > 0x0f) + { + m_skip = 1; + A &= 0xF; + } +} + +/* + + Mnemonic: CLRA + + Hex Code: 00 + Binary: 0 0 0 0 0 0 0 0 + + Data Flow: 0 -> A + + Description: Clear A + +*/ + +INSTRUCTION( clra ) +{ + A = 0; +} + +/* + + Mnemonic: COMP + + Hex Code: 40 + Binary: 0 1 0 0 0 0 0 0 + + Data Flow: ~A -> A + + Description: Ones Complement of A to A + +*/ + +INSTRUCTION( comp ) +{ + A = A ^ 0xF; +} + +/* + + Mnemonic: NOP + + Hex Code: 44 + Binary: 0 1 0 0 0 1 0 0 + + Description: No Operation + +*/ + +INSTRUCTION( nop ) +{ + // do nothing +} + +/* + + Mnemonic: RC + + Hex Code: 32 + Binary: 0 0 1 1 0 0 1 0 + + Data Flow: "0" -> C + + Description: Reset C + +*/ + +INSTRUCTION( rc ) +{ + C = 0; +} + +/* + + Mnemonic: SC + + Hex Code: 22 + Binary: 0 0 1 0 0 0 1 0 + + Data Flow: "1" -> C + + Description: Set C + +*/ + +INSTRUCTION( sc ) +{ + C = 1; +} + +/* + + Mnemonic: XOR + + Hex Code: 02 + Binary: 0 0 0 0 0 0 1 0 + + Data Flow: A ^ RAM(B) -> A + + Description: Exclusive-OR RAM with A + +*/ + +INSTRUCTION( xor_ ) +{ + A = A ^ RAM_R(B); +} + +/* + + Mnemonic: ADT + + Hex Code: 4A + Binary: 0 1 0 0 1 0 1 0 + + Data Flow: A + 10 -> A + + Description: Add Ten to A + +*/ + +INSTRUCTION( adt ) +{ + A = (A + 10) & 0x0F; +} + +/* + + Mnemonic: CASC + + Hex Code: 10 + Binary: 0 0 0 1 0 0 0 0 + + Data Flow: ~A + RAM(B) + C -> A + Carry -> C + + Skip Conditions: Carry + + Description: Complement and Add with Carry, Skip on Carry + +*/ + +INSTRUCTION( casc ) +{ + A = (A ^ 0xF) + RAM_R(B) + C; + + if (A > 0xF) + { + C = 1; + m_skip = 1; + A &= 0xF; + } + else + { + C = 0; + } +} + +/*************************************************************************** + TRANSFER-OF-CONTROL INSTRUCTIONS +***************************************************************************/ + +/* + + Mnemonic: JID + + Hex Code: FF + Binary: 1 1 1 1 1 1 1 1 + + Data Flow: ROM(PC10:8,A,M) -> PC7:0 + + Description: Jump Indirect + +*/ + +INSTRUCTION( jid ) +{ + UINT16 addr = (PC & 0x700) | (A << 4) | RAM_R(B); + PC = (PC & 0x700) | ROM(addr); +} + +/* + + Mnemonic: JMP + + Operand: a + Hex Code: 6- -- + Binary: 0 1 1 0 0 a10 a9 a8 a7 a6 a5 a4 a3 a2 a1 a0 + + Data Flow: a -> PC + + Description: Jump + +*/ + +INSTRUCTION( jmp ) +{ + UINT16 a = ((opcode & 0x07) << 8) | ROM(PC); + + PC = a; +} + +/* + + Mnemonic: JP + + Operand: a + Hex Code: -- + Binary: 1 a6 a5 a4 a3 a2 a1 a0 + (pages 2,3 only) + + 1 1 a5 a4 a3 a2 a1 a0 + (all other pages) + + Data Flow: a -> PC6:0 + + a -> PC5:0 + + Description: Jump within Page + +*/ + +INSTRUCTION( jp ) +{ + UINT8 page = PC >> 6; + + if (page == 2 || page == 3) + { + UINT8 a = opcode & 0x7f; + PC = (PC & 0x780) | a; + } + else if ((opcode & 0xc0) == 0xc0) + { + UINT8 a = opcode & 0x3f; + PC = (PC & 0x7c0) | a; + } + else + { + // JSRP + UINT8 a = opcode & 0x3f; + PUSH(PC); + PC = 0x80 | a; + } +} + +/* + + Mnemonic: JSR + + Operand: a + Hex Code: 6- -- + Binary: 0 1 1 0 1 a10 a9 a8 a7 a6 a5 a4 a3 a2 a1 a0 + + Data Flow: PC + 1 -> SA -> SB -> SC + a -> PC + + Description: Jump to Subroutine + +*/ + +INSTRUCTION( jsr ) +{ + UINT16 a = ((opcode & 0x07) << 8) | ROM(PC); + + PUSH(PC + 1); + PC = a; +} + +/* + + Mnemonic: RET + + Hex Code: 48 + Binary: 0 1 0 0 1 0 0 0 + + Data Flow: SC -> SB -> SA -> PC + + Description: Return from Subroutine + +*/ + +INSTRUCTION( ret ) +{ + POP(); +} + +/* + + Processor: COP420 + + Mnemonic: RET + + Hex Code: 48 + Binary: 0 1 0 0 1 0 0 0 + + Data Flow: SC -> SB -> SA -> PC + + Description: Return from Subroutine, restore Skip logic + +*/ + +INSTRUCTION( cop420_ret ) +{ + POP(); + m_skip = m_last_skip; +} + +/* + + Mnemonic: RETSK + + Hex Code: 49 + Binary: 0 1 0 0 1 0 0 1 + + Data Flow: SC -> SB -> SA -> PC + + Skip Conditions: Always Skip on Return + + Description: Return from Subroutine then Skip + +*/ + +INSTRUCTION( retsk ) +{ + POP(); + m_skip = 1; +} + +/* + + Processor: COP410C/COP411C + + Mnemonic: HALT + + Hex Code: 33 38 + Binary: 0 0 1 1 0 0 1 1 0 0 1 1 1 0 0 0 + + Description: Halt processor + +*/ + +INSTRUCTION( halt ) +{ + m_halt = 1; +} + +/* + + Mnemonic: IT + + Hex Code: 33 39 + Binary: 0 0 1 1 0 0 1 1 0 0 1 1 1 0 0 1 + + Description: IDLE till Timer Overflows then Continues + +*/ + +INSTRUCTION( it ) +{ + m_halt = 1; + m_idle = 1; +} + +/*************************************************************************** + MEMORY REFERENCE INSTRUCTIONS +***************************************************************************/ + +/* + + Mnemonic: CAMQ + + Hex Code: 33 3C + Binary: 0 0 1 1 0 0 1 1 0 0 1 1 1 1 0 0 + + Data Flow: A -> Q7:4 + RAM(B) -> Q3:0 + + Description: Copy A, RAM to Q + +*/ + +INSTRUCTION( camq ) +{ + /* + + Excerpt from the COP410L data sheet: + + False states may be generated on L0-L7 during the execution of the CAMQ instruction. + The L-ports should not be used as clocks for edge sensitive devices such as flip-flops, + counters, shift registers, etc. the following short program that illustrates this situation. + + START: + CLRA ;ENABLE THE Q + LEI 4 ;REGISTER TO L LINES + LBI TEST + STII 3 + AISC 12 + LOOP: + LBI TEST ;LOAD Q WITH X'C3 + CAMQ + JP LOOP + + In this program the internal Q register is enabled onto the L lines and a steady bit + pattern of logic highs is output on L0, L1, L6, L7, and logic lows on L2-L5 via the + two-byte CAMQ instruction. Timing constraints on the device are such that the Q + register may be temporarily loaded with the second byte of the CAMQ opcode (3C) prior + to receiving the valid data pattern. If this occurs, the opcode will ripple onto the L + lines and cause negative-going glitches on L0, L1, L6, L7, and positive glitches on + L2-L5. Glitch durations are under 2 ms, although the exact value may vary due to data + patterns, processing parameters, and L line loading. These false states are peculiar + only to the CAMQ instruction and the L lines. + + */ + + UINT8 data = (A << 4) | RAM_R(B); + + WRITE_Q(data); + +#ifdef CAMQ_BUG + WRITE_Q(0x3c); + WRITE_Q(data); +#endif +} + +/* + + Mnemonic: LD + + Operand: r + Hex Code: -5 + Binary: 0 0 r1 r0 0 1 0 1 + + Data Flow: RAM(B) -> A + Br ^ r -> Br + + Description: Load RAM into A, Exclusive-OR Br with r + +*/ + +INSTRUCTION( ld ) +{ + UINT8 r = opcode & 0x30; + + A = RAM_R(B); + B = B ^ r; +} + +/* + + Mnemonic: LQID + + Hex Code: BF + Binary: 1 0 1 1 1 1 1 1 + + Data Flow: ROM(PC10:8,A,M) -> Q + SB -> SC + + Description: Load Q Indirect + +*/ + +INSTRUCTION( lqid ) +{ + PUSH(PC); + PC = (PC & 0x700) | (A << 4) | RAM_R(B); + WRITE_Q(ROM(PC)); + POP(); +} + +/* + + Mnemonic: RMB + + Operand: 0 + 1 + 2 + 3 + + Hex Code: 4C + 45 + 42 + 43 + + Binary: 0 1 0 0 1 1 0 0 + 0 1 0 0 0 1 0 1 + 0 1 0 0 0 0 1 0 + 0 1 0 0 0 0 1 1 + + Data Flow: 0 -> RAM(B)0 + 0 -> RAM(B)1 + 0 -> RAM(B)2 + 0 -> RAM(B)3 + + Description: Reset RAM Bit + +*/ + +INSTRUCTION( rmb0 ) { RAM_W(B, RAM_R(B) & 0xE); } +INSTRUCTION( rmb1 ) { RAM_W(B, RAM_R(B) & 0xD); } +INSTRUCTION( rmb2 ) { RAM_W(B, RAM_R(B) & 0xB); } +INSTRUCTION( rmb3 ) { RAM_W(B, RAM_R(B) & 0x7); } + +/* + + Mnemonic: SMB + + Operand: 0 + 1 + 2 + 3 + + Hex Code: 4D + 47 + 46 + 4B + + Binary: 0 1 0 0 1 1 0 1 + 0 1 0 0 0 1 1 1 + 0 1 0 0 0 1 1 0 + 0 1 0 0 1 0 1 1 + + Data Flow: 1 -> RAM(B)0 + 1 -> RAM(B)1 + 1 -> RAM(B)2 + 1 -> RAM(B)3 + + Description: Set RAM Bit + +*/ + +INSTRUCTION( smb0 ) { RAM_W(B, RAM_R(B) | 0x1); } +INSTRUCTION( smb1 ) { RAM_W(B, RAM_R(B) | 0x2); } +INSTRUCTION( smb2 ) { RAM_W(B, RAM_R(B) | 0x4); } +INSTRUCTION( smb3 ) { RAM_W(B, RAM_R(B) | 0x8); } + +/* + + Mnemonic: STII + + Operand: y + Hex Code: 7- + Binary: 0 1 1 1 y3 y2 y1 y0 + + Data Flow: y -> RAM(B) + Bd + 1 -> Bd + + Description: Store Memory Immediate and Increment Bd + +*/ + +INSTRUCTION( stii ) +{ + UINT8 y = opcode & 0x0f; + UINT16 Bd; + + RAM_W(B, y); + + Bd = ((B & 0x0f) + 1) & 0x0f; + B = (B & 0x70) + Bd; +} + +/* + + Mnemonic: X + + Operand: r + Hex Code: -6 + Binary: 0 0 r1 r0 0 1 1 0 + + Data Flow: RAM(B) <-> A + Br ^ r -> Br + + Description: Exchange RAM with A, Exclusive-OR Br with r + +*/ + +INSTRUCTION( x ) +{ + UINT8 r = opcode & 0x30; + UINT8 t = RAM_R(B); + + RAM_W(B, A); + + A = t; + B = B ^ r; +} + +/* + + Mnemonic: XAD + + Operand: r,d + Hex Code: 23 -- + Binary: 0 0 1 0 0 0 1 1 1 r2 r1 r0 d3 d2 d1 d0 + + Data Flow: RAM(r,d) <-> A + + Description: Exchange A with RAM pointed to directly by r,d + +*/ + +INSTRUCTION( xad ) +{ + UINT8 rd = opcode & 0x7f; + UINT8 t = A; + + A = RAM_R(rd); + + RAM_W(rd, t); +} + +/* + + Mnemonic: XDS + + Operand: r + Hex Code: -7 + Binary: 0 0 r1 r0 0 1 1 1 + + Data Flow: RAM(B) <-> A + Bd - 1 -> Bd + Br ^ r -> Br + + Skip Conditions: Bd decrements past 0 + + Description: Exchange RAM with A and Decrement Bd, Exclusive-OR Br with r + +*/ + +INSTRUCTION( xds ) +{ + UINT8 t, Bd; + UINT8 r = opcode & 0x30; + + t = RAM_R(B); + RAM_W(B, A); + A = t; + + Bd = ((B & 0x0f) - 1) & 0x0f; + B = (B & 0x70) | Bd; + + B = B ^ r; + + if (Bd == 0x0f) m_skip = 1; +} + +/* + + Mnemonic: XIS + + Operand: r + Hex Code: -4 + Binary: 0 0 r1 r0 0 1 0 0 + + Data Flow: RAM(B) <-> A + Bd + 1 -> Bd + Br ^ r -> Br + + Skip Conditions: Bd increments past 15 + + Description: Exchange RAM with A and Increment Bd, Exclusive-OR Br with r + +*/ + +INSTRUCTION( xis ) +{ + UINT8 t, Bd; + UINT8 r = opcode & 0x30; + + t = RAM_R(B); + RAM_W(B, A); + A = t; + + Bd = ((B & 0x0f) + 1) & 0x0f; + B = (B & 0x70) | Bd; + + B = B ^ r; + + if (Bd == 0x00) m_skip = 1; +} + +/* + + Mnemonic: CQMA + + Hex Code: 33 2C + Binary: 0 0 1 1 0 0 1 1 0 0 1 0 1 1 0 0 + + Data Flow: Q7:4 -> RAM(B) + Q3:0 -> A + + Description: Copy Q to RAM, A + +*/ + +INSTRUCTION( cqma ) +{ + RAM_W(B, Q >> 4); + A = Q & 0xF; +} + +/* + + Mnemonic: LDD + + Operand: r, d + Hex Code: 23 -- + Binary: 0 0 1 0 0 0 1 1 0 r2 r1 r0 d3 d2 d1 d0 + + Data Flow: RAM(r,d) -> A + + Description: Load A with RAM pointed to directly by r,d + +*/ + +INSTRUCTION( ldd ) +{ + UINT8 rd = opcode & 0x7f; + + A = RAM_R(rd); +} + +/* + + Mnemonic: CAMT + + Hex Code: 33 3F + Binary: + + Data Flow: A -> T7:4 + RAM(B) -> T3:0 + + Description: Copy A, RAM to T + +*/ + +INSTRUCTION( camt ) +{ + T = (A << 4) | RAM_R(B); +} +/* + + Mnemonic: CTMA + + Hex Code: 33 2F + Binary: + + Data Flow: T7:4 -> RAM(B) + T3:0 -> A + + Description: Copy T to RAM, A + +*/ + +INSTRUCTION( ctma ) +{ + RAM_W(B, T >> 4); + A = T & 0x0f; +} + +/*************************************************************************** + REGISTER REFERENCE INSTRUCTIONS +***************************************************************************/ + +/* + + Mnemonic: CAB + + Hex Code: 50 + Binary: 0 1 0 1 0 0 0 0 0 + + Data Flow: A -> Bd + + Description: Copy A to Bd + +*/ + +INSTRUCTION( cab ) +{ + B = (B & 0x70) | A; +} + +/* + + Mnemonic: CBA + + Hex Code: 4E + Binary: 0 1 0 0 1 1 1 0 + + Data Flow: Bd -> A + + Description: Copy Bd to A + +*/ + +INSTRUCTION( cba ) +{ + A = B & 0xF; +} + +/* + + Mnemonic: LBI + + Operand: r,d + Hex Code: -- + 33 -- + + Binary: 0 0 r1 r0 d3 d2 d1 d0 (d-1) + 0 0 1 1 0 0 1 1 1 r2 r1 r0 d3 d2 d1 d0 + + Data Flow: r,d -> B + + Skip Conditions: Skip until not a LBI + + Description: Load B Immediate with r,d + +*/ + +INSTRUCTION( lbi ) +{ + m_skip_lbi++; + if (m_skip_lbi > 1) return; + m_skip_lbi++; + + if (opcode & 0x80) + { + B = opcode & 0x7f; + } + else + { + B = (opcode & 0x30) | (((opcode & 0x0f) + 1) & 0x0f); + } +} + +/* + + Mnemonic: LEI + + Operand: y + Hex Code: 33 6- + Binary: 0 0 1 1 0 0 1 1 0 1 1 0 y3 y2 y1 y0 + + Data Flow: y -> EN + + Description: Load EN Immediate + +*/ + +INSTRUCTION( lei ) +{ + UINT8 y = opcode & 0x0f; + + EN = y; + + if (BIT(EN, 2)) + { + OUT_L(Q); + } +} + +/* + + Mnemonic: XABR + + Hex Code: 12 + Binary: 0 0 0 1 0 0 1 0 + + Data Flow: A <-> Br(0,0 -> A3,A2) + + Description: Exchange A with Br + +*/ + +INSTRUCTION( xabr ) +{ + UINT8 Br = A & 0x03; + UINT8 Bd = B & 0x0f; + + A = B >> 4; + B = (Br << 4) + Bd; +} + +/* + + Processor: COP444 + + Mnemonic: XABR + + Hex Code: 12 + Binary: 0 0 0 1 0 0 1 0 + + Data Flow: A <-> Br(0 -> A3) + + Description: Exchange A with Br + +*/ + +INSTRUCTION( cop444_xabr ) +{ + UINT8 Br = A & 0x07; + UINT8 Bd = B & 0x0f; + + A = B >> 4; + B = (Br << 4) + Bd; +} + +/*************************************************************************** + TEST INSTRUCTIONS +***************************************************************************/ + +/* + + Mnemonic: SKC + + Hex Code: 20 + Binary: 0 0 1 0 0 0 0 0 + + Skip Conditions: C = "1" + + Description: Skip if C is True + +*/ + +INSTRUCTION( skc ) +{ + if (C == 1) m_skip = 1; +} + +/* + + Mnemonic: SKE + + Hex Code: 21 + Binary: 0 0 1 0 0 0 0 1 + + Skip Conditions: A = RAM(B) + + Description: Skip if A Equals RAM + +*/ + +INSTRUCTION( ske ) +{ + if (A == RAM_R(B)) m_skip = 1; +} + +/* + + Mnemonic: SKGZ + + Hex Code: 33 21 + Binary: 00 0 1 1 0 0 1 1 0 0 1 0 0 0 0 1 + + Skip Conditions: G3:0 = 0 + + Description: Skip if G is Zero (all 4 bits) + +*/ + +INSTRUCTION( skgz ) +{ + if (IN_G() == 0) m_skip = 1; +} + +/* + + Mnemonic: SKGBZ + + Hex Code: 33 01 + 33 11 + 33 03 + 33 13 + + Binary: + + Skip Conditions: G0 = 0 + G1 = 0 + G2 = 0 + G3 = 0 + + Description: Skip if G Bit is Zero + +*/ + +void cop400_cpu_device::skgbz(int bit) +{ + if (!BIT(IN_G(), bit)) m_skip = 1; +} + +INSTRUCTION( skgbz0 ) { skgbz(0); } +INSTRUCTION( skgbz1 ) { skgbz(1); } +INSTRUCTION( skgbz2 ) { skgbz(2); } +INSTRUCTION( skgbz3 ) { skgbz(3); } + +/* + + Mnemonic: SKMBZ + + Hex Code: 01 + 11 + 03 + 13 + + Binary: + + Skip Conditions: RAM(B)0 = 0 + RAM(B)0 = 1 + RAM(B)0 = 2 + RAM(B)0 = 3 + + Description: Skip if RAM Bit is Zero + +*/ + +void cop400_cpu_device::skmbz(int bit) +{ + if (!BIT(RAM_R(B), bit)) m_skip = 1; +} + +INSTRUCTION( skmbz0 ) { skmbz(0); } +INSTRUCTION( skmbz1 ) { skmbz(1); } +INSTRUCTION( skmbz2 ) { skmbz(2); } +INSTRUCTION( skmbz3 ) { skmbz(3); } + +/* + + Mnemonic: SKT + + Hex Code: 41 + Binary: 0 1 0 0 0 0 0 1 + + Skip Conditions: A time-base counter carry has occurred since last test + + Description: Skip on Timer + +*/ + +INSTRUCTION( skt ) +{ + if (m_skt_latch) + { + m_skt_latch = 0; + m_skip = 1; + } +} + +/*************************************************************************** + INPUT/OUTPUT INSTRUCTIONS +***************************************************************************/ + +/* + + Mnemonic: ING + + Hex Code: 33 2A + Binary: + + Data Flow: G -> A + + Description: Input G Ports to A + +*/ + +INSTRUCTION( ing ) +{ + A = IN_G(); +} + +/* + + Mnemonic: INL + + Hex Code: 33 2E + Binary: + + Data Flow: L7:4 -> RAM(B) + L3:0 -> A + + Description: Input L Ports to RAM,A + +*/ + +INSTRUCTION( inl ) +{ + UINT8 L = IN_L(); + + RAM_W(B, L >> 4); + A = L & 0xF; +} + +/* + + Mnemonic: OBD + + Hex Code: 33 3E + Binary: + + Data Flow: Bd -> D + + Description: Output Bd to D Outputs + +*/ + +INSTRUCTION( obd ) +{ + OUT_D(B & 0x0f); +} + +/* + + Mnemonic: OMG + + Hex Code: 33 3A + Binary: + + Data Flow: RAM(B) -> G + + Description: Output RAM to G Ports + +*/ + +INSTRUCTION( omg ) +{ + WRITE_G(RAM_R(B)); +} + +/* + + Mnemonic: XAS + + Hex Code: 4F + Binary: 0 1 0 0 1 1 1 1 + + Data Flow: A <-> SIO + C -> SK + + Description: Exchange A with SIO + +*/ + +INSTRUCTION( xas ) +{ + UINT8 t = SIO; + SIO = A; + A = t; + + SKL = C; +} + +/* + + Mnemonic: ININ + + Hex Code: 33 28 + Binary: + + Data Flow: IN -> A + + Description: Input IN Inputs to A + +*/ + +INSTRUCTION( inin ) +{ + A = IN_IN(); +} + +/* + + Processor: COP402M + + Mnemonic: ININ + + Hex Code: 33 28 + Binary: + + Data Flow: IN -> A, A1 = "1" + + Description: Input IN Inputs to A + +*/ + +INSTRUCTION( cop402m_inin ) +{ + A = IN_IN() | 0x02; +} + +/* + + Mnemonic: INIL + + Hex Code: 33 29 + Binary: + + Data Flow: IL3,CKO,"0",IL0 -> A + + Description: Input IL Latches to A + +*/ + +INSTRUCTION( inil ) +{ + A = (IL & 0x09) | IN_CKO() << 2; + + IL = 0; +} + +/* + + Mnemonic: OGI + + Operand: y + Hex Code: 33 5- + Binary: 0 0 1 1 0 0 1 1 0 1 0 1 y3 y2 y1 y0 + + Data Flow: y -> G + + Description: Output to G Ports Immediate + +*/ + +INSTRUCTION( ogi ) +{ + UINT8 y = opcode & 0x0f; + + WRITE_G(y); +} diff --git a/src/devices/cpu/cop400/cop410ds.c b/src/devices/cpu/cop400/cop410ds.c new file mode 100644 index 00000000000..638653151d0 --- /dev/null +++ b/src/devices/cpu/cop400/cop410ds.c @@ -0,0 +1,349 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/*************************************************************************** + + cop410ds.c + + National Semiconductor COP410 Emulator. + +***************************************************************************/ + +#include "emu.h" + +CPU_DISASSEMBLE( cop410 ) +{ + UINT8 opcode = oprom[0]; + UINT8 next_opcode = oprom[1]; + UINT16 address; + UINT32 flags = 0; + int bytes = 1; + + if ((opcode >= 0x80 && opcode <= 0xBE) || (opcode >= 0xC0 && opcode <= 0xFE)) + { + if ((pc & 0x3E0) >= 0x80 && (pc & 0x3E0) < 0x100) //JP pages 2,3 + { + address = (UINT16)((pc & 0x380) | (opcode & 0x7F)); + sprintf(buffer, "JP %x", address); + } + else + { + if ((opcode & 0xC0) == 0xC0) //JP other pages + { + address = (UINT16)((pc & 0x3C0) | (opcode & 0x3F)); + sprintf(buffer, "JP %x", address); + } + else //JSRP + { + address = (UINT16)(0x80 | (opcode & 0x3F)); + sprintf(buffer, "JSRP %x", address); + flags = DASMFLAG_STEP_OVER; + } + } + } + else if (opcode >= 0x08 && opcode <= 0x0F) + { + sprintf(buffer, "LBI 0,%u", ((opcode & 0xF) + 1) & 0xF); + } + else if (opcode >= 0x18 && opcode <= 0x1F) + { + sprintf(buffer, "LBI 1,%u", ((opcode & 0xF) + 1) & 0xF); + } + else if (opcode >= 0x28 && opcode <= 0x2F) + { + sprintf(buffer, "LBI 2,%u", ((opcode & 0xF) + 1) & 0xF); + } + else if (opcode >= 0x38 && opcode <= 0x3F) + { + sprintf(buffer, "LBI 3,%u", ((opcode & 0xF) + 1) & 0xF); + } + else if (opcode >= 0x51 && opcode <= 0x5F) + { + sprintf(buffer, "AISC %u", opcode & 0xF); + } + else if (opcode >= 0x60 && opcode <= 0x61) + { + address = ((opcode & 0x01) << 8) | next_opcode; + sprintf(buffer, "JMP %x", address); + bytes = 2; + } + else if (opcode >= 0x68 && opcode <= 0x69) + { + address = ((opcode & 0x01) << 8) | next_opcode; + sprintf(buffer, "JSR %x", address); + flags = DASMFLAG_STEP_OVER; + bytes = 2; + } + else if (opcode >= 0x70 && opcode <= 0x7F) + { + sprintf(buffer, "STII %u", opcode & 0xF); + } + else + { + switch (opcode) + { + case 0: + sprintf(buffer, "CLRA"); + break; + + case 1: + sprintf(buffer, "SKMBZ 0"); + break; + + case 2: + sprintf(buffer, "XOR"); + break; + + case 3: + sprintf(buffer, "SKMBZ 2"); + break; + + case 4: + sprintf(buffer, "XIS 0"); + break; + + case 5: + sprintf(buffer, "LD 0"); + break; + + case 6: + sprintf(buffer, "X 0"); + break; + + case 7: + sprintf(buffer, "XDS 0"); + break; + + case 0x11: + sprintf(buffer, "SKMBZ 1"); + break; + + case 0x13: + sprintf(buffer, "SKMBZ 3"); + break; + + case 0x14: + sprintf(buffer, "XIS 1"); + break; + + case 0x15: + sprintf(buffer, "LD 1"); + break; + + case 0x16: + sprintf(buffer, "X 1"); + break; + + case 0x17: + sprintf(buffer, "XDS 1"); + break; + + case 0x20: + sprintf(buffer, "SKC"); + break; + + case 0x21: + sprintf(buffer, "SKE"); + break; + + case 0x22: + sprintf(buffer, "SC"); + break; + + case 0x23: + bytes = 2; + + if (next_opcode >= 0x80 && next_opcode <= 0xbf) + { + address = (UINT16)(next_opcode & 0x3F); + sprintf(buffer, "XAD %x,%x", ((address & 0x30) >> 4),address & 0x0F); + } + else + { + sprintf(buffer, "Invalid"); + } + break; + + case 0x24: + sprintf(buffer, "XIS 2"); + break; + + case 0x25: + sprintf(buffer, "LD 2"); + break; + + case 0x26: + sprintf(buffer, "X 2"); + break; + + case 0x27: + sprintf(buffer, "XDS 2"); + break; + + case 0x30: + sprintf(buffer, "ASC"); + break; + + case 0x31: + sprintf(buffer, "ADD"); + break; + + case 0x32: + sprintf(buffer, "RC"); + break; + + case 0x33: + bytes = 2; + + if (next_opcode >= 0x60 && next_opcode <= 0x6F) + { + sprintf(buffer, "LEI %x", next_opcode & 0xF); + } + else + { + switch (next_opcode) + { + case 0x01: + sprintf(buffer, "SKGBZ 0"); + break; + + case 0x03: + sprintf(buffer, "SKGBZ 2"); + break; + + case 0x11: + sprintf(buffer, "SKGBZ 1"); + break; + + case 0x13: + sprintf(buffer, "SKGBZ 3"); + break; + + case 0x21: + sprintf(buffer, "SKGZ"); + break; + + case 0x2A: + sprintf(buffer, "ING"); + break; + + case 0x2E: + sprintf(buffer, "INL"); + break; + + case 0x38: + sprintf(buffer, "HALT"); + break; + + case 0x3A: + sprintf(buffer, "OMG"); + break; + + case 0x3C: + sprintf(buffer, "CAMQ"); + break; + + case 0x3E: + sprintf(buffer, "OBD"); + break; + + default: + sprintf(buffer, "Invalid"); + break; + } + break; + } + + case 0x34: + sprintf(buffer, "XIS 3"); + break; + + case 0x35: + sprintf(buffer, "LD 3"); + break; + + case 0x36: + sprintf(buffer, "X 3"); + break; + + case 0x37: + sprintf(buffer, "XDS 3"); + break; + + case 0x40: + sprintf(buffer, "COMP"); + break; + + case 0x42: + sprintf(buffer, "RMB 2"); + break; + + case 0x43: + sprintf(buffer, "RMB 3"); + break; + + case 0x44: + sprintf(buffer, "NOP"); + break; + + case 0x45: + sprintf(buffer, "RMB 1"); + break; + + case 0x46: + sprintf(buffer, "SMB 2"); + break; + + case 0x47: + sprintf(buffer, "SMB 1"); + break; + + case 0x48: + sprintf(buffer, "RET"); + flags = DASMFLAG_STEP_OUT; + break; + + case 0x49: + sprintf(buffer, "RETSK"); + flags = DASMFLAG_STEP_OUT; + break; + + case 0x4B: + sprintf(buffer, "SMB 3"); + break; + + case 0x4C: + sprintf(buffer, "RMB 0"); + break; + + case 0x4D: + sprintf(buffer, "SMB 0"); + break; + + case 0x4E: + sprintf(buffer, "CBA"); + break; + + case 0x4F: + sprintf(buffer, "XAS"); + break; + + case 0x50: + sprintf(buffer, "CAB"); + break; + + case 0xBF: + sprintf(buffer, "LQID"); + break; + + case 0xFF: + sprintf(buffer, "JID"); + break; + + default: + sprintf(buffer, "Invalid"); + break; + } + } + + return bytes | flags | DASMFLAG_SUPPORTED; +} diff --git a/src/devices/cpu/cop400/cop420ds.c b/src/devices/cpu/cop400/cop420ds.c new file mode 100644 index 00000000000..007b9afc8c6 --- /dev/null +++ b/src/devices/cpu/cop400/cop420ds.c @@ -0,0 +1,398 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/*************************************************************************** + + cop420ds.c + + National Semiconductor COP420 Emulator. + +***************************************************************************/ + +#include "emu.h" + +CPU_DISASSEMBLE( cop420 ) +{ + UINT8 opcode = oprom[0]; + UINT8 next_opcode = oprom[1]; + UINT16 address; + UINT32 flags = 0; + int bytes = 1; + + if ((opcode >= 0x80 && opcode <= 0xBE) || (opcode >= 0xC0 && opcode <= 0xFE)) + { + if ((pc & 0x3E0) >= 0x80 && (pc & 0x3E0) < 0x100) //JP pages 2,3 + { + address = (UINT16)((pc & 0x380) | (opcode & 0x7F)); + sprintf(buffer, "JP %x", address); + } + else + { + if ((opcode & 0xC0) == 0xC0) //JP other pages + { + address = (UINT16)((pc & 0x3C0) | (opcode & 0x3F)); + sprintf(buffer, "JP %x", address); + } + else //JSRP + { + address = (UINT16)(0x80 | (opcode & 0x3F)); + sprintf(buffer, "JSRP %x", address); + flags = DASMFLAG_STEP_OVER; + } + } + } + else if (opcode >= 0x08 && opcode <= 0x0F) + { + sprintf(buffer, "LBI 0,%u", ((opcode & 0xF) + 1) & 0xF); + } + else if (opcode >= 0x18 && opcode <= 0x1F) + { + sprintf(buffer, "LBI 1,%u", ((opcode & 0xF) + 1) & 0xF); + } + else if (opcode >= 0x28 && opcode <= 0x2F) + { + sprintf(buffer, "LBI 2,%u", ((opcode & 0xF) + 1) & 0xF); + } + else if (opcode >= 0x38 && opcode <= 0x3F) + { + sprintf(buffer, "LBI 3,%u", ((opcode & 0xF) + 1) & 0xF); + } + else if (opcode >= 0x51 && opcode <= 0x5F) + { + sprintf(buffer, "AISC %u", opcode & 0xF); + } + else if (opcode >= 0x60 && opcode <= 0x63) + { + address = ((opcode & 0x03) << 8) | next_opcode; + sprintf(buffer, "JMP %x", address); + bytes = 2; + } + else if (opcode >= 0x68 && opcode <= 0x6B) + { + address = ((opcode & 0x03) << 8) | next_opcode; + sprintf(buffer, "JSR %x", address); + flags = DASMFLAG_STEP_OVER; + bytes = 2; + } + else if (opcode >= 0x70 && opcode <= 0x7F) + { + sprintf(buffer, "STII %u", opcode & 0xF); + } + else + { + switch (opcode) + { + case 0: + sprintf(buffer, "CLRA"); + break; + + case 1: + sprintf(buffer, "SKMBZ 0"); + break; + + case 2: + sprintf(buffer, "XOR"); + break; + + case 3: + sprintf(buffer, "SKMBZ 2"); + break; + + case 4: + sprintf(buffer, "XIS 0"); + break; + + case 5: + sprintf(buffer, "LD 0"); + break; + + case 6: + sprintf(buffer, "X 0"); + break; + + case 7: + sprintf(buffer, "XDS 0"); + break; + + case 0x10: + sprintf(buffer, "CASC"); + break; + + case 0x11: + sprintf(buffer, "SKMBZ 1"); + break; + + case 0x12: + sprintf(buffer, "XABR"); + break; + + case 0x13: + sprintf(buffer, "SKMBZ 3"); + break; + + case 0x14: + sprintf(buffer, "XIS 1"); + break; + + case 0x15: + sprintf(buffer, "LD 1"); + break; + + case 0x16: + sprintf(buffer, "X 1"); + break; + + case 0x17: + sprintf(buffer, "XDS 1"); + break; + + case 0x20: + sprintf(buffer, "SKC"); + break; + + case 0x21: + sprintf(buffer, "SKE"); + break; + + case 0x22: + sprintf(buffer, "SC"); + break; + + case 0x23: + bytes = 2; + + if (next_opcode <= 0x3f) + { + address = (UINT16)(next_opcode & 0x3F); + sprintf(buffer, "LDD %x,%x", ((address & 0x30) >> 4),address & 0x0F); + } + else if (next_opcode >= 0x80 && next_opcode <= 0xbf) + { + address = (UINT16)(next_opcode & 0x3F); + sprintf(buffer, "XAD %x,%x", ((address & 0x30) >> 4),address & 0x0F); + } + else + { + sprintf(buffer, "Invalid"); + } + break; + + case 0x24: + sprintf(buffer, "XIS 2"); + break; + + case 0x25: + sprintf(buffer, "LD 2"); + break; + + case 0x26: + sprintf(buffer, "X 2"); + break; + + case 0x27: + sprintf(buffer, "XDS 2"); + break; + + case 0x30: + sprintf(buffer, "ASC"); + break; + + case 0x31: + sprintf(buffer, "ADD"); + break; + + case 0x32: + sprintf(buffer, "RC"); + break; + + case 0x33: + bytes = 2; + + if (next_opcode >= 0x50 && next_opcode <= 0x5F) + { + sprintf(buffer, "OGI %u", next_opcode & 0xF); + } + else if (next_opcode >= 0x60 && next_opcode <= 0x6F) + { + sprintf(buffer, "LEI %u", next_opcode & 0xF); + } + else if (next_opcode >= 0x80 && next_opcode <= 0x8F) + { + sprintf(buffer, "LBI 0,%u", next_opcode & 0xF); + } + else if (next_opcode >= 0x90 && next_opcode <= 0x9F) + { + sprintf(buffer, "LBI 1,%u", next_opcode & 0xF); + } + else if (next_opcode >= 0xA0 && next_opcode <= 0xAF) + { + sprintf(buffer, "LBI 2,%u", next_opcode & 0xF); + } + else if (next_opcode >= 0xB0 && next_opcode <= 0xBF) + { + sprintf(buffer, "LBI 3,%u", next_opcode & 0xF); + } + else + { + switch (next_opcode) + { + case 0x01: + sprintf(buffer, "SKGBZ 0"); + break; + + case 0x03: + sprintf(buffer, "SKGBZ 2"); + break; + + case 0x11: + sprintf(buffer, "SKGBZ 1"); + break; + + case 0x13: + sprintf(buffer, "SKGBZ 3"); + break; + + case 0x21: + sprintf(buffer, "SKGZ"); + break; + + case 0x28: + sprintf(buffer, "ININ"); + break; + + case 0x29: + sprintf(buffer, "INIL"); + break; + + case 0x2A: + sprintf(buffer, "ING"); + break; + + case 0x2C: + sprintf(buffer, "CQMA"); + break; + + case 0x2E: + sprintf(buffer, "INL"); + break; + + case 0x3A: + sprintf(buffer, "OMG"); + break; + + case 0x3C: + sprintf(buffer, "CAMQ"); + break; + + case 0x3E: + sprintf(buffer, "OBD"); + break; + + default: + sprintf(buffer, "Invalid"); + break; + } + } + break; + + case 0x34: + sprintf(buffer, "XIS 3"); + break; + + case 0x35: + sprintf(buffer, "LD 3"); + break; + + case 0x36: + sprintf(buffer, "X 3"); + break; + + case 0x37: + sprintf(buffer, "XDS 3"); + break; + + case 0x40: + sprintf(buffer, "COMP"); + break; + + case 0x41: + sprintf(buffer, "SKT"); + break; + + case 0x42: + sprintf(buffer, "RMB 2"); + break; + + case 0x43: + sprintf(buffer, "RMB 3"); + break; + + case 0x44: + sprintf(buffer, "NOP"); + break; + + case 0x45: + sprintf(buffer, "RMB 1"); + break; + + case 0x46: + sprintf(buffer, "SMB 2"); + break; + + case 0x47: + sprintf(buffer, "SMB 1"); + break; + + case 0x48: + sprintf(buffer, "RET"); + flags = DASMFLAG_STEP_OUT; + break; + + case 0x49: + sprintf(buffer, "RETSK"); + flags = DASMFLAG_STEP_OUT; + break; + + case 0x4A: + sprintf(buffer, "ADT"); + break; + + case 0x4B: + sprintf(buffer, "SMB 3"); + break; + + case 0x4C: + sprintf(buffer, "RMB 0"); + break; + + case 0x4D: + sprintf(buffer, "SMB 0"); + break; + + case 0x4E: + sprintf(buffer, "CBA"); + break; + + case 0x4F: + sprintf(buffer, "XAS"); + break; + + case 0x50: + sprintf(buffer, "CAB"); + break; + + case 0xBF: + sprintf(buffer, "LQID"); + break; + + case 0xFF: + sprintf(buffer, "JID"); + break; + + default: + sprintf(buffer, "Invalid"); + break; + } + } + + return bytes | flags | DASMFLAG_SUPPORTED; +} diff --git a/src/devices/cpu/cop400/cop440ds.c b/src/devices/cpu/cop400/cop440ds.c new file mode 100644 index 00000000000..4af02d3c481 --- /dev/null +++ b/src/devices/cpu/cop400/cop440ds.c @@ -0,0 +1,415 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/*************************************************************************** + + cop440ds.c + + National Semiconductor COP420 Emulator. + +***************************************************************************/ + +#include "emu.h" + +CPU_DISASSEMBLE( cop444 ) +{ + UINT8 opcode = oprom[0]; + UINT8 next_opcode = oprom[1]; + UINT16 address; + UINT32 flags = 0; + int bytes = 1; + + if ((opcode >= 0x80 && opcode <= 0xBE) || (opcode >= 0xC0 && opcode <= 0xFE)) + { + if ((pc & 0x3E0) >= 0x80 && (pc & 0x3E0) < 0x100) //JP pages 2,3 + { + address = (UINT16)((pc & 0x380) | (opcode & 0x7F)); + sprintf(buffer, "JP %x", address); + } + else + { + if ((opcode & 0xC0) == 0xC0) //JP other pages + { + address = (UINT16)((pc & 0x3C0) | (opcode & 0x3F)); + sprintf(buffer, "JP %x", address); + } + else //JSRP + { + address = (UINT16)(0x80 | (opcode & 0x3F)); + sprintf(buffer, "JSRP %x", address); + flags = DASMFLAG_STEP_OVER; + } + } + } + else if (opcode >= 0x08 && opcode <= 0x0F) + { + sprintf(buffer, "LBI 0,%u", ((opcode & 0xF) + 1) & 0xF); + } + else if (opcode >= 0x18 && opcode <= 0x1F) + { + sprintf(buffer, "LBI 1,%u", ((opcode & 0xF) + 1) & 0xF); + } + else if (opcode >= 0x28 && opcode <= 0x2F) + { + sprintf(buffer, "LBI 2,%u", ((opcode & 0xF) + 1) & 0xF); + } + else if (opcode >= 0x38 && opcode <= 0x3F) + { + sprintf(buffer, "LBI 3,%u", ((opcode & 0xF) + 1) & 0xF); + } + else if (opcode >= 0x51 && opcode <= 0x5F) + { + sprintf(buffer, "AISC %u", opcode & 0xF); + } + else if (opcode >= 0x60 && opcode <= 0x63) + { + address = ((opcode & 0x03) << 8) | next_opcode; + sprintf(buffer, "JMP %x", address); + bytes = 2; + } + else if (opcode >= 0x68 && opcode <= 0x6B) + { + address = ((opcode & 0x03) << 8) | next_opcode; + sprintf(buffer, "JSR %x", address); + flags = DASMFLAG_STEP_OVER; + bytes = 2; + } + else if (opcode >= 0x70 && opcode <= 0x7F) + { + sprintf(buffer, "STII %u", opcode & 0xF); + } + else + { + switch (opcode) + { + case 0: + sprintf(buffer, "CLRA"); + break; + + case 1: + sprintf(buffer, "SKMBZ 0"); + break; + + case 2: + sprintf(buffer, "XOR"); + break; + + case 3: + sprintf(buffer, "SKMBZ 2"); + break; + + case 4: + sprintf(buffer, "XIS 0"); + break; + + case 5: + sprintf(buffer, "LD 0"); + break; + + case 6: + sprintf(buffer, "X 0"); + break; + + case 7: + sprintf(buffer, "XDS 0"); + break; + + case 0x10: + sprintf(buffer, "CASC"); + break; + + case 0x11: + sprintf(buffer, "SKMBZ 1"); + break; + + case 0x12: + sprintf(buffer, "XABR"); + break; + + case 0x13: + sprintf(buffer, "SKMBZ 3"); + break; + + case 0x14: + sprintf(buffer, "XIS 1"); + break; + + case 0x15: + sprintf(buffer, "LD 1"); + break; + + case 0x16: + sprintf(buffer, "X 1"); + break; + + case 0x17: + sprintf(buffer, "XDS 1"); + break; + + case 0x20: + sprintf(buffer, "SKC"); + break; + + case 0x21: + sprintf(buffer, "SKE"); + break; + + case 0x22: + sprintf(buffer, "SC"); + break; + + case 0x23: + bytes = 2; + + if (next_opcode <= 0x3f) + { + address = (UINT16)(next_opcode & 0x3F); + sprintf(buffer, "LDD %x,%x", ((address & 0x30) >> 4),address & 0x0F); + } + else if (next_opcode >= 0x80 && next_opcode <= 0xbf) + { + address = (UINT16)(next_opcode & 0x3F); + sprintf(buffer, "XAD %x,%x", ((address & 0x30) >> 4),address & 0x0F); + } + else + { + sprintf(buffer, "Invalid"); + } + break; + + case 0x24: + sprintf(buffer, "XIS 2"); + break; + + case 0x25: + sprintf(buffer, "LD 2"); + break; + + case 0x26: + sprintf(buffer, "X 2"); + break; + + case 0x27: + sprintf(buffer, "XDS 2"); + break; + + case 0x30: + sprintf(buffer, "ASC"); + break; + + case 0x31: + sprintf(buffer, "ADD"); + break; + + case 0x32: + sprintf(buffer, "RC"); + break; + + case 0x33: + bytes = 2; + + if (next_opcode >= 0x50 && next_opcode <= 0x5F) + { + sprintf(buffer, "OGI %u", next_opcode & 0xF); + } + else if (next_opcode >= 0x60 && next_opcode <= 0x6F) + { + sprintf(buffer, "LEI %u", next_opcode & 0xF); + } + else if (next_opcode >= 0x80 && next_opcode <= 0x8F) + { + sprintf(buffer, "LBI 0,%u", next_opcode & 0xF); + } + else if (next_opcode >= 0x90 && next_opcode <= 0x9F) + { + sprintf(buffer, "LBI 1,%u", next_opcode & 0xF); + } + else if (next_opcode >= 0xA0 && next_opcode <= 0xAF) + { + sprintf(buffer, "LBI 2,%u", next_opcode & 0xF); + } + else if (next_opcode >= 0xB0 && next_opcode <= 0xBF) + { + sprintf(buffer, "LBI 3,%u", next_opcode & 0xF); + } + else + { + switch (next_opcode) + { + case 0x01: + sprintf(buffer, "SKGBZ 0"); + break; + + case 0x03: + sprintf(buffer, "SKGBZ 2"); + break; + + case 0x11: + sprintf(buffer, "SKGBZ 1"); + break; + + case 0x13: + sprintf(buffer, "SKGBZ 3"); + break; + + case 0x21: + sprintf(buffer, "SKGZ"); + break; + + case 0x28: + sprintf(buffer, "ININ"); + break; + + case 0x29: + sprintf(buffer, "INIL"); + break; + + case 0x2A: + sprintf(buffer, "ING"); + break; + + case 0x2C: + sprintf(buffer, "CQMA"); + break; + + case 0x2E: + sprintf(buffer, "INL"); + break; + + case 0x2F: + sprintf(buffer, "CTMA"); + break; + + case 0x38: + sprintf(buffer, "HALT"); + break; + + case 0x39: + sprintf(buffer, "IT"); + break; + + case 0x3A: + sprintf(buffer, "OMG"); + break; + + case 0x3C: + sprintf(buffer, "CAMQ"); + break; + + case 0x3E: + sprintf(buffer, "OBD"); + break; + + case 0x3F: + sprintf(buffer, "CAMT"); + break; + + + default: + sprintf(buffer, "Invalid"); + break; + } + } + break; + + case 0x34: + sprintf(buffer, "XIS 3"); + break; + + case 0x35: + sprintf(buffer, "LD 3"); + break; + + case 0x36: + sprintf(buffer, "X 3"); + break; + + case 0x37: + sprintf(buffer, "XDS 3"); + break; + + case 0x40: + sprintf(buffer, "COMP"); + break; + + case 0x41: + sprintf(buffer, "SKT"); + break; + + case 0x42: + sprintf(buffer, "RMB 2"); + break; + + case 0x43: + sprintf(buffer, "RMB 3"); + break; + + case 0x44: + sprintf(buffer, "NOP"); + break; + + case 0x45: + sprintf(buffer, "RMB 1"); + break; + + case 0x46: + sprintf(buffer, "SMB 2"); + break; + + case 0x47: + sprintf(buffer, "SMB 1"); + break; + + case 0x48: + sprintf(buffer, "RET"); + flags = DASMFLAG_STEP_OUT; + break; + + case 0x49: + sprintf(buffer, "RETSK"); + flags = DASMFLAG_STEP_OUT; + break; + + case 0x4A: + sprintf(buffer, "ADT"); + break; + + case 0x4B: + sprintf(buffer, "SMB 3"); + break; + + case 0x4C: + sprintf(buffer, "RMB 0"); + break; + + case 0x4D: + sprintf(buffer, "SMB 0"); + break; + + case 0x4E: + sprintf(buffer, "CBA"); + break; + + case 0x4F: + sprintf(buffer, "XAS"); + break; + + case 0x50: + sprintf(buffer, "CAB"); + break; + + case 0xBF: + sprintf(buffer, "LQID"); + break; + + case 0xFF: + sprintf(buffer, "JID"); + break; + + default: + sprintf(buffer, "Invalid"); + break; + } + } + + return bytes | flags | DASMFLAG_SUPPORTED; +} diff --git a/src/devices/cpu/cosmac/cosdasm.c b/src/devices/cpu/cosmac/cosdasm.c new file mode 100644 index 00000000000..f8f41e2c4ce --- /dev/null +++ b/src/devices/cpu/cosmac/cosdasm.c @@ -0,0 +1,197 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/*************************************************************************** + + cosdasm.c + + Simple RCA COSMAC disassembler. + Written by Curt Coder + +***************************************************************************/ + +#include "emu.h" + +enum +{ + TYPE_1801, + TYPE_1802 +}; + +#define CDP1801_OPCODE(...) \ + sprintf(buffer, __VA_ARGS__) + +#define CDP1802_OPCODE(...) \ + if (variant < TYPE_1802) sprintf(buffer, "illegal"); else sprintf(buffer, __VA_ARGS__) + +static offs_t implied(const UINT8 opcode) +{ + return opcode & 0x0f; +} + +static offs_t immediate(const UINT8 **opram) +{ + return *(*opram)++; +} + +static offs_t short_branch(offs_t pc, const UINT8 **opram) +{ + return (pc & 0xff00) | immediate(opram); +} + +static offs_t long_branch(const UINT8 **opram) +{ + return (immediate(opram) << 8) | immediate(opram); +} + +static offs_t short_skip(offs_t pc) +{ + return pc + 2; +} + +static offs_t long_skip(offs_t pc) +{ + return pc + 3; +} + +static UINT32 disassemble(device_t *device, char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 variant) +{ + const UINT8 *startram = opram; + UINT32 flags = 0; + + opram++; + UINT8 opcode = *oprom++; + + switch (opcode) + { + case 0x00: CDP1801_OPCODE("IDL"); break; + case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: + case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f: + CDP1801_OPCODE("LDN R%01X", implied(opcode)); break; + case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17: + case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f: + CDP1801_OPCODE("INC R%01X", implied(opcode)); break; + case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27: + case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: case 0x2f: + CDP1801_OPCODE("DEC R%01X", implied(opcode)); break; + case 0x30: CDP1801_OPCODE("BR %04X", short_branch(pc, &opram)); break; + case 0x32: CDP1801_OPCODE("BZ %04X", short_branch(pc, &opram)); break; + case 0x33: CDP1801_OPCODE("BDF %04X", short_branch(pc, &opram)); break; + case 0x34: CDP1801_OPCODE("B1 %04X", short_branch(pc, &opram)); break; + case 0x35: CDP1801_OPCODE("B2 %04X", short_branch(pc, &opram)); break; + case 0x36: CDP1801_OPCODE("B3 %04X", short_branch(pc, &opram)); break; + case 0x37: CDP1801_OPCODE("B4 %04X", short_branch(pc, &opram)); break; + case 0x38: CDP1801_OPCODE("SKP %04X", short_skip(pc)); break; + case 0x3a: CDP1801_OPCODE("BNZ %04X", short_branch(pc, &opram)); break; + case 0x3b: CDP1801_OPCODE("BNF %04X", short_branch(pc, &opram)); break; + case 0x3c: CDP1801_OPCODE("BN1 %04X", short_branch(pc, &opram)); break; + case 0x3d: CDP1801_OPCODE("BN2 %04X", short_branch(pc, &opram)); break; + case 0x3e: CDP1801_OPCODE("BN3 %04X", short_branch(pc, &opram)); break; + case 0x3f: CDP1801_OPCODE("BN4 %04X", short_branch(pc, &opram)); break; + case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: case 0x46: case 0x47: + case 0x48: case 0x49: case 0x4a: case 0x4b: case 0x4c: case 0x4d: case 0x4e: case 0x4f: + CDP1801_OPCODE("LDA R%01X", implied(opcode)); break; + case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x55: case 0x56: case 0x57: + case 0x58: case 0x59: case 0x5a: case 0x5b: case 0x5c: case 0x5d: case 0x5e: case 0x5f: + CDP1801_OPCODE("STR R%01X", implied(opcode)); break; + case 0x61: CDP1801_OPCODE("OUT 1"); break; + case 0x62: CDP1801_OPCODE("OUT 2"); break; + case 0x63: CDP1801_OPCODE("OUT 3"); break; + case 0x64: CDP1801_OPCODE("OUT 4"); break; + case 0x65: CDP1801_OPCODE("OUT 5"); break; + case 0x66: CDP1801_OPCODE("OUT 6"); break; + case 0x67: CDP1801_OPCODE("OUT 7"); break; + case 0x69: CDP1801_OPCODE("INP 1"); break; + case 0x6a: CDP1801_OPCODE("INP 2"); break; + case 0x6b: CDP1801_OPCODE("INP 3"); break; + case 0x6c: CDP1801_OPCODE("INP 4"); break; + case 0x6d: CDP1801_OPCODE("INP 5"); break; + case 0x6e: CDP1801_OPCODE("INP 6"); break; + case 0x6f: CDP1801_OPCODE("INP 7"); break; + case 0x70: CDP1801_OPCODE("RET"); flags = DASMFLAG_STEP_OUT; break; + case 0x71: CDP1801_OPCODE("DIS"); flags = DASMFLAG_STEP_OUT; break; + case 0x78: CDP1801_OPCODE("SAV"); 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: + CDP1801_OPCODE("GLO R%01X", implied(opcode)); break; + case 0x90: case 0x91: case 0x92: case 0x93: case 0x94: case 0x95: case 0x96: case 0x97: + case 0x98: case 0x99: case 0x9a: case 0x9b: case 0x9c: case 0x9d: case 0x9e: case 0x9f: + CDP1801_OPCODE("GHI R%01X", implied(opcode)); break; + case 0xa0: case 0xa1: case 0xa2: case 0xa3: case 0xa4: case 0xa5: case 0xa6: case 0xa7: + case 0xa8: case 0xa9: case 0xaa: case 0xab: case 0xac: case 0xad: case 0xae: case 0xaf: + CDP1801_OPCODE("PLO R%01X", implied(opcode)); break; + case 0xb0: case 0xb1: case 0xb2: case 0xb3: case 0xb4: case 0xb5: case 0xb6: case 0xb7: + case 0xb8: case 0xb9: case 0xba: case 0xbb: case 0xbc: case 0xbd: case 0xbe: case 0xbf: + CDP1801_OPCODE("PHI R%01X", implied(opcode)); break; + case 0xd0: case 0xd1: case 0xd2: case 0xd3: case 0xd4: case 0xd5: case 0xd6: case 0xd7: + case 0xd8: case 0xd9: case 0xda: case 0xdb: case 0xdc: case 0xdd: case 0xde: case 0xdf: + CDP1801_OPCODE("SEP R%01X", implied(opcode)); flags = DASMFLAG_STEP_OVER; break; + case 0xe0: case 0xe1: case 0xe2: case 0xe3: case 0xe4: case 0xe5: case 0xe6: case 0xe7: + case 0xe8: case 0xe9: case 0xea: case 0xeb: case 0xec: case 0xed: case 0xee: case 0xef: + CDP1801_OPCODE("SEX R%01X", implied(opcode)); break; + case 0xf0: CDP1801_OPCODE("LDX"); break; + case 0xf1: CDP1801_OPCODE("OR"); break; + case 0xf2: CDP1801_OPCODE("AND"); break; + case 0xf3: CDP1801_OPCODE("XOR"); break; + case 0xf4: CDP1801_OPCODE("ADD"); break; + case 0xf5: CDP1801_OPCODE("SD"); break; + case 0xf6: CDP1801_OPCODE("SHR"); break; + case 0xf7: CDP1801_OPCODE("SM"); break; + case 0xf8: CDP1801_OPCODE("LDI #%02X", immediate(&opram)); break; + case 0xf9: CDP1801_OPCODE("ORI #%02X", immediate(&opram)); break; + case 0xfa: CDP1801_OPCODE("ANI #%02X", immediate(&opram)); break; + case 0xfb: CDP1801_OPCODE("XRI #%02X", immediate(&opram)); break; + case 0xfc: CDP1801_OPCODE("ADI #%02X", immediate(&opram)); break; + case 0xfd: CDP1801_OPCODE("SDI #%02X", immediate(&opram)); break; + case 0xff: CDP1801_OPCODE("SMI #%02X", immediate(&opram)); break; + // CDP1802 + case 0x31: CDP1802_OPCODE("BQ %04X", short_branch(pc, &opram)); break; + case 0x39: CDP1802_OPCODE("BNQ %04X", short_branch(pc, &opram)); break; + case 0x60: CDP1802_OPCODE("IRX"); break; + case 0x72: CDP1802_OPCODE("LDXA"); break; + case 0x73: CDP1802_OPCODE("STXD"); break; + case 0x74: CDP1802_OPCODE("ADC"); break; + case 0x75: CDP1802_OPCODE("SDB"); break; + case 0x76: CDP1802_OPCODE("SHRC"); break; + case 0x77: CDP1802_OPCODE("SMB"); break; + case 0x79: CDP1802_OPCODE("MARK"); break; + case 0x7a: CDP1802_OPCODE("REQ"); break; + case 0x7b: CDP1802_OPCODE("SEQ"); break; + case 0x7c: CDP1802_OPCODE("ADCI #%02X", immediate(&opram)); break; + case 0x7d: CDP1802_OPCODE("SDBI #%02X", immediate(&opram)); break; + case 0x7e: CDP1802_OPCODE("SHLC"); break; + case 0x7f: CDP1802_OPCODE("SMBI #%02X", immediate(&opram)); break; + case 0xc0: CDP1802_OPCODE("LBR %04X", long_branch(&opram)); break; + case 0xc1: CDP1802_OPCODE("LBQ %04X", long_branch(&opram)); break; + case 0xc2: CDP1802_OPCODE("LBZ %04X", long_branch(&opram)); break; + case 0xc3: CDP1802_OPCODE("LBDF %04X", long_branch(&opram)); break; + case 0xc4: CDP1802_OPCODE("NOP"); break; + case 0xc5: CDP1802_OPCODE("LSNQ %04X", long_skip(pc)); break; + case 0xc6: CDP1802_OPCODE("LSNZ %04X", long_skip(pc)); break; + case 0xc7: CDP1802_OPCODE("LSNF %04X", long_skip(pc)); break; + case 0xc8: CDP1802_OPCODE("LSKP %04X", long_skip(pc)); break; + case 0xc9: CDP1802_OPCODE("LBNQ %04X", long_skip(pc)); break; + case 0xca: CDP1802_OPCODE("LBNZ %04X", long_skip(pc)); break; + case 0xcb: CDP1802_OPCODE("LBNF %04X", long_skip(pc)); break; + case 0xcc: CDP1802_OPCODE("LSIE %04X", long_skip(pc)); break; + case 0xcd: CDP1802_OPCODE("LSQ %04X", long_skip(pc)); break; + case 0xce: CDP1802_OPCODE("LSZ %04X", long_skip(pc)); break; + case 0xcf: CDP1802_OPCODE("LSDF %04X", long_skip(pc)); break; + case 0xfe: CDP1802_OPCODE("SHL"); break; + // + default: CDP1801_OPCODE("illegal"); break; + } + + return (opram - startram) | flags | DASMFLAG_SUPPORTED; +} + + +CPU_DISASSEMBLE( cdp1801 ) +{ + return disassemble(device, buffer, pc, oprom, opram, TYPE_1801); +} + + +CPU_DISASSEMBLE( cdp1802 ) +{ + return disassemble(device, buffer, pc, oprom, opram, TYPE_1802); +} diff --git a/src/devices/cpu/cosmac/cosmac.c b/src/devices/cpu/cosmac/cosmac.c new file mode 100644 index 00000000000..f011e37a47a --- /dev/null +++ b/src/devices/cpu/cosmac/cosmac.c @@ -0,0 +1,1247 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + RCA COSMAC CPU emulation + +**********************************************************************/ + +#include "emu.h" +#include "debugger.h" +#include "cosmac.h" +#include "coreutil.h" + +// permit our enums to be saved +ALLOW_SAVE_TYPE(cosmac_device::cosmac_mode); +ALLOW_SAVE_TYPE(cosmac_device::cosmac_state); + + +//************************************************************************** +// CONSTANTS +//************************************************************************** + +#define CLOCKS_RESET 8 +#define CLOCKS_INIT 8 // really 9, but needs to be 8 to synchronize cdp1861 video timings +#define CLOCKS_FETCH 8 +#define CLOCKS_EXECUTE 8 +#define CLOCKS_DMA 8 +#define CLOCKS_INTERRUPT 8 + +const cosmac_state_code COSMAC_STATE_CODE[] = +{ + COSMAC_STATE_CODE_S0_FETCH, // COSMAC_STATE_0_FETCH + COSMAC_STATE_CODE_S1_EXECUTE, // COSMAC_STATE_1_RESET + COSMAC_STATE_CODE_S1_EXECUTE, // COSMAC_STATE_1_INIT + COSMAC_STATE_CODE_S1_EXECUTE, // COSMAC_STATE_1_EXECUTE + COSMAC_STATE_CODE_S2_DMA, // COSMAC_STATE_2_DMA_IN + COSMAC_STATE_CODE_S2_DMA, // COSMAC_STATE_2_DMA_OUT + COSMAC_STATE_CODE_S3_INTERRUPT // COSMAC_STATE_3_INT +}; + + + +//************************************************************************** +// MACROS +//************************************************************************** + +#define OPCODE_R(addr) read_opcode(addr) +#define RAM_R(addr) read_byte(addr) +#define RAM_W(addr, data) write_byte(addr, data) +#define IO_R(addr) read_io_byte(addr) +#define IO_W(addr, data) write_io_byte(addr, data) + +#define P m_p +#define X m_x +#define D m_d +#define B m_b +#define T m_t +#define R m_r +#define DF m_df +#define IE m_ie +#define Q m_q +#define N m_n +#define I m_i +#define EF m_ef + +#define GET_FLAGS() ((m_df << 2) | (m_ie << 1) | m_q) + +#define SET_FLAGS(v) do { \ + m_df = BIT(v, 2); \ + m_ie = BIT(v, 1); \ + m_q = BIT(v, 0); \ + } while (0); + + + +//************************************************************************** +// STATIC OPCODE TABLES +//************************************************************************** + +const cosmac_device::ophandler cdp1801_device::s_opcodetable[256] = +{ + &cdp1801_device::idl, &cdp1801_device::ldn, &cdp1801_device::ldn, &cdp1801_device::ldn, + &cdp1801_device::ldn, &cdp1801_device::ldn, &cdp1801_device::ldn, &cdp1801_device::ldn, + &cdp1801_device::ldn, &cdp1801_device::ldn, &cdp1801_device::ldn, &cdp1801_device::ldn, + &cdp1801_device::ldn, &cdp1801_device::ldn, &cdp1801_device::ldn, &cdp1801_device::ldn, + + &cdp1801_device::inc, &cdp1801_device::inc, &cdp1801_device::inc, &cdp1801_device::inc, + &cdp1801_device::inc, &cdp1801_device::inc, &cdp1801_device::inc, &cdp1801_device::inc, + &cdp1801_device::inc, &cdp1801_device::inc, &cdp1801_device::inc, &cdp1801_device::inc, + &cdp1801_device::inc, &cdp1801_device::inc, &cdp1801_device::inc, &cdp1801_device::inc, + + &cdp1801_device::dec, &cdp1801_device::dec, &cdp1801_device::dec, &cdp1801_device::dec, + &cdp1801_device::dec, &cdp1801_device::dec, &cdp1801_device::dec, &cdp1801_device::dec, + &cdp1801_device::dec, &cdp1801_device::dec, &cdp1801_device::dec, &cdp1801_device::dec, + &cdp1801_device::dec, &cdp1801_device::dec, &cdp1801_device::dec, &cdp1801_device::dec, + + &cdp1801_device::br, &cdp1801_device::und, &cdp1801_device::bz, &cdp1801_device::bdf, + &cdp1801_device::b, &cdp1801_device::b, &cdp1801_device::b, &cdp1801_device::b, + &cdp1801_device::nbr, &cdp1801_device::und, &cdp1801_device::bnz, &cdp1801_device::bnf, + &cdp1801_device::bn, &cdp1801_device::bn, &cdp1801_device::bn, &cdp1801_device::bn, + + &cdp1801_device::lda, &cdp1801_device::lda, &cdp1801_device::lda, &cdp1801_device::lda, + &cdp1801_device::lda, &cdp1801_device::lda, &cdp1801_device::lda, &cdp1801_device::lda, + &cdp1801_device::lda, &cdp1801_device::lda, &cdp1801_device::lda, &cdp1801_device::lda, + &cdp1801_device::lda, &cdp1801_device::lda, &cdp1801_device::lda, &cdp1801_device::lda, + + &cdp1801_device::str, &cdp1801_device::str, &cdp1801_device::str, &cdp1801_device::str, + &cdp1801_device::str, &cdp1801_device::str, &cdp1801_device::str, &cdp1801_device::str, + &cdp1801_device::str, &cdp1801_device::str, &cdp1801_device::str, &cdp1801_device::str, + &cdp1801_device::str, &cdp1801_device::str, &cdp1801_device::str, &cdp1801_device::str, + + &cdp1801_device::und, &cdp1801_device::out, &cdp1801_device::out, &cdp1801_device::out, + &cdp1801_device::out, &cdp1801_device::out, &cdp1801_device::out, &cdp1801_device::out, + &cdp1801_device::und, &cdp1801_device::inp, &cdp1801_device::inp, &cdp1801_device::inp, + &cdp1801_device::inp, &cdp1801_device::inp, &cdp1801_device::inp, &cdp1801_device::inp, + + &cdp1801_device::ret, &cdp1801_device::dis, &cdp1801_device::und, &cdp1801_device::und, + &cdp1801_device::und, &cdp1801_device::und, &cdp1801_device::und, &cdp1801_device::und, + &cdp1801_device::sav, &cdp1801_device::und, &cdp1801_device::und, &cdp1801_device::und, + &cdp1801_device::und, &cdp1801_device::und, &cdp1801_device::und, &cdp1801_device::und, + + &cdp1801_device::glo, &cdp1801_device::glo, &cdp1801_device::glo, &cdp1801_device::glo, + &cdp1801_device::glo, &cdp1801_device::glo, &cdp1801_device::glo, &cdp1801_device::glo, + &cdp1801_device::glo, &cdp1801_device::glo, &cdp1801_device::glo, &cdp1801_device::glo, + &cdp1801_device::glo, &cdp1801_device::glo, &cdp1801_device::glo, &cdp1801_device::glo, + + &cdp1801_device::ghi, &cdp1801_device::ghi, &cdp1801_device::ghi, &cdp1801_device::ghi, + &cdp1801_device::ghi, &cdp1801_device::ghi, &cdp1801_device::ghi, &cdp1801_device::ghi, + &cdp1801_device::ghi, &cdp1801_device::ghi, &cdp1801_device::ghi, &cdp1801_device::ghi, + &cdp1801_device::ghi, &cdp1801_device::ghi, &cdp1801_device::ghi, &cdp1801_device::ghi, + + &cdp1801_device::plo, &cdp1801_device::plo, &cdp1801_device::plo, &cdp1801_device::plo, + &cdp1801_device::plo, &cdp1801_device::plo, &cdp1801_device::plo, &cdp1801_device::plo, + &cdp1801_device::plo, &cdp1801_device::plo, &cdp1801_device::plo, &cdp1801_device::plo, + &cdp1801_device::plo, &cdp1801_device::plo, &cdp1801_device::plo, &cdp1801_device::plo, + + &cdp1801_device::phi, &cdp1801_device::phi, &cdp1801_device::phi, &cdp1801_device::phi, + &cdp1801_device::phi, &cdp1801_device::phi, &cdp1801_device::phi, &cdp1801_device::phi, + &cdp1801_device::phi, &cdp1801_device::phi, &cdp1801_device::phi, &cdp1801_device::phi, + &cdp1801_device::phi, &cdp1801_device::phi, &cdp1801_device::phi, &cdp1801_device::phi, + + &cdp1801_device::und, &cdp1801_device::und, &cdp1801_device::und, &cdp1801_device::und, + &cdp1801_device::und, &cdp1801_device::und, &cdp1801_device::und, &cdp1801_device::und, + &cdp1801_device::und, &cdp1801_device::und, &cdp1801_device::und, &cdp1801_device::und, + &cdp1801_device::und, &cdp1801_device::und, &cdp1801_device::und, &cdp1801_device::und, + + &cdp1801_device::sep, &cdp1801_device::sep, &cdp1801_device::sep, &cdp1801_device::sep, + &cdp1801_device::sep, &cdp1801_device::sep, &cdp1801_device::sep, &cdp1801_device::sep, + &cdp1801_device::sep, &cdp1801_device::sep, &cdp1801_device::sep, &cdp1801_device::sep, + &cdp1801_device::sep, &cdp1801_device::sep, &cdp1801_device::sep, &cdp1801_device::sep, + + &cdp1801_device::sex, &cdp1801_device::sex, &cdp1801_device::sex, &cdp1801_device::sex, + &cdp1801_device::sex, &cdp1801_device::sex, &cdp1801_device::sex, &cdp1801_device::sex, + &cdp1801_device::sex, &cdp1801_device::sex, &cdp1801_device::sex, &cdp1801_device::sex, + &cdp1801_device::sex, &cdp1801_device::sex, &cdp1801_device::sex, &cdp1801_device::sex, + + &cdp1801_device::ldx, &cdp1801_device::_or, &cdp1801_device::_and, &cdp1801_device::_xor, + &cdp1801_device::add, &cdp1801_device::sd, &cdp1801_device::shr, &cdp1801_device::sm, + &cdp1801_device::ldi, &cdp1801_device::ori, &cdp1801_device::ani, &cdp1801_device::xri, + &cdp1801_device::adi, &cdp1801_device::sdi, &cdp1801_device::und, &cdp1801_device::smi +}; + +cosmac_device::ophandler cdp1801_device::get_ophandler(UINT8 opcode) +{ + return s_opcodetable[opcode]; +} + +const cosmac_device::ophandler cdp1802_device::s_opcodetable[256] = +{ + &cdp1802_device::idl, &cdp1802_device::ldn, &cdp1802_device::ldn, &cdp1802_device::ldn, + &cdp1802_device::ldn, &cdp1802_device::ldn, &cdp1802_device::ldn, &cdp1802_device::ldn, + &cdp1802_device::ldn, &cdp1802_device::ldn, &cdp1802_device::ldn, &cdp1802_device::ldn, + &cdp1802_device::ldn, &cdp1802_device::ldn, &cdp1802_device::ldn, &cdp1802_device::ldn, + + &cdp1802_device::inc, &cdp1802_device::inc, &cdp1802_device::inc, &cdp1802_device::inc, + &cdp1802_device::inc, &cdp1802_device::inc, &cdp1802_device::inc, &cdp1802_device::inc, + &cdp1802_device::inc, &cdp1802_device::inc, &cdp1802_device::inc, &cdp1802_device::inc, + &cdp1802_device::inc, &cdp1802_device::inc, &cdp1802_device::inc, &cdp1802_device::inc, + + &cdp1802_device::dec, &cdp1802_device::dec, &cdp1802_device::dec, &cdp1802_device::dec, + &cdp1802_device::dec, &cdp1802_device::dec, &cdp1802_device::dec, &cdp1802_device::dec, + &cdp1802_device::dec, &cdp1802_device::dec, &cdp1802_device::dec, &cdp1802_device::dec, + &cdp1802_device::dec, &cdp1802_device::dec, &cdp1802_device::dec, &cdp1802_device::dec, + + &cdp1802_device::br, &cdp1802_device::bq, &cdp1802_device::bz, &cdp1802_device::bdf, + &cdp1802_device::b, &cdp1802_device::b, &cdp1802_device::b, &cdp1802_device::b, + &cdp1802_device::nbr, &cdp1802_device::bnq, &cdp1802_device::bnz, &cdp1802_device::bnf, + &cdp1802_device::bn, &cdp1802_device::bn, &cdp1802_device::bn, &cdp1802_device::bn, + + &cdp1802_device::lda, &cdp1802_device::lda, &cdp1802_device::lda, &cdp1802_device::lda, + &cdp1802_device::lda, &cdp1802_device::lda, &cdp1802_device::lda, &cdp1802_device::lda, + &cdp1802_device::lda, &cdp1802_device::lda, &cdp1802_device::lda, &cdp1802_device::lda, + &cdp1802_device::lda, &cdp1802_device::lda, &cdp1802_device::lda, &cdp1802_device::lda, + + &cdp1802_device::str, &cdp1802_device::str, &cdp1802_device::str, &cdp1802_device::str, + &cdp1802_device::str, &cdp1802_device::str, &cdp1802_device::str, &cdp1802_device::str, + &cdp1802_device::str, &cdp1802_device::str, &cdp1802_device::str, &cdp1802_device::str, + &cdp1802_device::str, &cdp1802_device::str, &cdp1802_device::str, &cdp1802_device::str, + + &cdp1802_device::irx, &cdp1802_device::out, &cdp1802_device::out, &cdp1802_device::out, + &cdp1802_device::out, &cdp1802_device::out, &cdp1802_device::out, &cdp1802_device::out, + &cdp1802_device::inp, &cdp1802_device::inp, &cdp1802_device::inp, &cdp1802_device::inp, + &cdp1802_device::inp, &cdp1802_device::inp, &cdp1802_device::inp, &cdp1802_device::inp, + + &cdp1802_device::ret, &cdp1802_device::dis, &cdp1802_device::ldxa, &cdp1802_device::stxd, + &cdp1802_device::adc, &cdp1802_device::sdb, &cdp1802_device::shrc, &cdp1802_device::smb, + &cdp1802_device::sav, &cdp1802_device::mark, &cdp1802_device::req, &cdp1802_device::seq, + &cdp1802_device::adci, &cdp1802_device::sdbi, &cdp1802_device::shlc, &cdp1802_device::smbi, + + &cdp1802_device::glo, &cdp1802_device::glo, &cdp1802_device::glo, &cdp1802_device::glo, + &cdp1802_device::glo, &cdp1802_device::glo, &cdp1802_device::glo, &cdp1802_device::glo, + &cdp1802_device::glo, &cdp1802_device::glo, &cdp1802_device::glo, &cdp1802_device::glo, + &cdp1802_device::glo, &cdp1802_device::glo, &cdp1802_device::glo, &cdp1802_device::glo, + + &cdp1802_device::ghi, &cdp1802_device::ghi, &cdp1802_device::ghi, &cdp1802_device::ghi, + &cdp1802_device::ghi, &cdp1802_device::ghi, &cdp1802_device::ghi, &cdp1802_device::ghi, + &cdp1802_device::ghi, &cdp1802_device::ghi, &cdp1802_device::ghi, &cdp1802_device::ghi, + &cdp1802_device::ghi, &cdp1802_device::ghi, &cdp1802_device::ghi, &cdp1802_device::ghi, + + &cdp1802_device::plo, &cdp1802_device::plo, &cdp1802_device::plo, &cdp1802_device::plo, + &cdp1802_device::plo, &cdp1802_device::plo, &cdp1802_device::plo, &cdp1802_device::plo, + &cdp1802_device::plo, &cdp1802_device::plo, &cdp1802_device::plo, &cdp1802_device::plo, + &cdp1802_device::plo, &cdp1802_device::plo, &cdp1802_device::plo, &cdp1802_device::plo, + + &cdp1802_device::phi, &cdp1802_device::phi, &cdp1802_device::phi, &cdp1802_device::phi, + &cdp1802_device::phi, &cdp1802_device::phi, &cdp1802_device::phi, &cdp1802_device::phi, + &cdp1802_device::phi, &cdp1802_device::phi, &cdp1802_device::phi, &cdp1802_device::phi, + &cdp1802_device::phi, &cdp1802_device::phi, &cdp1802_device::phi, &cdp1802_device::phi, + + &cdp1802_device::lbr, &cdp1802_device::lbq, &cdp1802_device::lbz, &cdp1802_device::lbdf, + &cdp1802_device::nop, &cdp1802_device::lsnq, &cdp1802_device::lsnz, &cdp1802_device::lsnf, + &cdp1802_device::nlbr, &cdp1802_device::lbnq, &cdp1802_device::lbnz, &cdp1802_device::lbnf, + &cdp1802_device::lsie, &cdp1802_device::lsq, &cdp1802_device::lsz, &cdp1802_device::lsdf, + + &cdp1802_device::sep, &cdp1802_device::sep, &cdp1802_device::sep, &cdp1802_device::sep, + &cdp1802_device::sep, &cdp1802_device::sep, &cdp1802_device::sep, &cdp1802_device::sep, + &cdp1802_device::sep, &cdp1802_device::sep, &cdp1802_device::sep, &cdp1802_device::sep, + &cdp1802_device::sep, &cdp1802_device::sep, &cdp1802_device::sep, &cdp1802_device::sep, + + &cdp1802_device::sex, &cdp1802_device::sex, &cdp1802_device::sex, &cdp1802_device::sex, + &cdp1802_device::sex, &cdp1802_device::sex, &cdp1802_device::sex, &cdp1802_device::sex, + &cdp1802_device::sex, &cdp1802_device::sex, &cdp1802_device::sex, &cdp1802_device::sex, + &cdp1802_device::sex, &cdp1802_device::sex, &cdp1802_device::sex, &cdp1802_device::sex, + + &cdp1802_device::ldx, &cdp1802_device::_or, &cdp1802_device::_and, &cdp1802_device::_xor, + &cdp1802_device::add, &cdp1802_device::sd, &cdp1802_device::shr, &cdp1802_device::sm, + &cdp1802_device::ldi, &cdp1802_device::ori, &cdp1802_device::ani, &cdp1802_device::xri, + &cdp1802_device::adi, &cdp1802_device::sdi, &cdp1802_device::shl, &cdp1802_device::smi +}; + +cosmac_device::ophandler cdp1802_device::get_ophandler(UINT8 opcode) +{ + return s_opcodetable[opcode]; +} + + + +//************************************************************************** +// DEVICE INTERFACE +//************************************************************************** + +// device type definition +const device_type CDP1801 = &device_creator; +const device_type CDP1802 = &device_creator; + + +//------------------------------------------------- +// cosmac_device - constructor +//------------------------------------------------- + +cosmac_device::cosmac_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : cpu_device(mconfig, type, name, tag, owner, clock, shortname, source), + m_program_config("program", ENDIANNESS_LITTLE, 8, 16), + m_io_config("io", ENDIANNESS_LITTLE, 8, 3), + m_read_wait(*this), + m_read_clear(*this), + m_read_ef1(*this), + m_read_ef2(*this), + m_read_ef3(*this), + m_read_ef4(*this), + m_write_q(*this), + m_read_dma(*this), + m_write_dma(*this), + m_write_sc(*this), + m_op(0), + m_state(COSMAC_STATE_1_RESET), + m_mode(COSMAC_MODE_RESET), + m_irq(CLEAR_LINE), + m_dmain(CLEAR_LINE), + m_dmaout(CLEAR_LINE), + m_program(NULL), + m_io(NULL), + m_direct(NULL) +{ + for (int i = 0; i < 4; i++) + m_ef[i] = CLEAR_LINE; +} + + +//------------------------------------------------- +// cdp1801_device - constructor +//------------------------------------------------- + +cdp1801_device::cdp1801_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : cosmac_device(mconfig, CDP1801, "CDP1801", tag, owner, clock, "cdp1801", __FILE__) +{ +} + + +//------------------------------------------------- +// cdp1802_device - constructor +//------------------------------------------------- + +cdp1802_device::cdp1802_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : cosmac_device(mconfig, CDP1802, "CDP1802", tag, owner, clock, "cdp1802", __FILE__) +{ +} + + +//------------------------------------------------- +// device_start - start up the device +//------------------------------------------------- + +void cosmac_device::device_start() +{ + // resolve callbacks + m_read_wait.resolve_safe(0); + m_read_clear.resolve_safe(0); + m_read_ef1.resolve(); + m_read_ef2.resolve(); + m_read_ef3.resolve(); + m_read_ef4.resolve(); + m_write_q.resolve_safe(); + m_read_dma.resolve_safe(0); + m_write_dma.resolve_safe(); + m_write_sc.resolve_safe(); + + // get our address spaces + m_program = &space(AS_PROGRAM); + m_direct = &m_program->direct(); + m_io = &space(AS_IO); + + // register our state for the debugger + state_add(STATE_GENPC, "GENPC", m_pc).callimport().callexport().noshow(); + state_add(STATE_GENFLAGS, "GENFLAGS", m_flagsio).mask(0x7).callimport().callexport().noshow().formatstr("%3s"); + + state_add(COSMAC_P, "P", m_p).mask(0xf); + state_add(COSMAC_X, "X", m_x).mask(0xf); + state_add(COSMAC_D, "D", m_d); + state_add(COSMAC_B, "B", m_b); + state_add(COSMAC_T, "T", m_t); + + state_add(COSMAC_I, "I", m_i).mask(0xf); + state_add(COSMAC_N, "N", m_n).mask(0xf); + + std::string tempstr; + for (int regnum = 0; regnum < 16; regnum++) + state_add(COSMAC_R0 + regnum, strformat(tempstr, "R%x", regnum).c_str(), m_r[regnum]); + + state_add(COSMAC_DF, "DF", m_df).mask(0x1).noshow(); + state_add(COSMAC_IE, "IE", m_ie).mask(0x1).noshow(); + state_add(COSMAC_Q, "Q", m_q).mask(0x1).noshow(); + + // register our state for saving + save_item(NAME(m_op)); + save_item(NAME(m_flagsio)); + save_item(NAME(m_state)); + save_item(NAME(m_mode)); + save_item(NAME(m_pmode)); + save_item(NAME(m_irq)); + save_item(NAME(m_dmain)); + save_item(NAME(m_dmaout)); + save_item(NAME(m_ef)); + save_item(NAME(m_d)); + save_item(NAME(m_b)); + save_item(NAME(m_r)); + save_item(NAME(m_p)); + save_item(NAME(m_x)); + save_item(NAME(m_n)); + save_item(NAME(m_i)); + save_item(NAME(m_t)); + save_item(NAME(m_df)); + save_item(NAME(m_ie)); + save_item(NAME(m_q)); + + // set our instruction counter + m_icountptr = &m_icount; +} + + +//------------------------------------------------- +// device_reset - reset the device +//------------------------------------------------- + +void cosmac_device::device_reset() +{ + m_ie = 0; + m_q = 0; + m_df = 0; + m_p = 0; + rand_memory(m_r, sizeof(m_r)); +} + + +//------------------------------------------------- +// memory_space_config - return the configuration +// of the specified address space, or NULL if +// the space doesn't exist +//------------------------------------------------- + +const address_space_config *cosmac_device::memory_space_config(address_spacenum spacenum) const +{ + switch (spacenum) + { + case AS_PROGRAM: + return &m_program_config; + + case AS_IO: + return &m_io_config; + + default: + return NULL; + } +} + + +//------------------------------------------------- +// state_import - import state into the device, +// after it has been set +//------------------------------------------------- + +void cosmac_device::state_import(const device_state_entry &entry) +{ + switch (entry.index()) + { + case STATE_GENPC: + R[P] = m_pc; + break; + + case STATE_GENFLAGS: + SET_FLAGS(m_flagsio); + break; + } +} + + +//------------------------------------------------- +// state_export - export state from the device, +// to a known location where it can be read +//------------------------------------------------- + +void cosmac_device::state_export(const device_state_entry &entry) +{ + switch (entry.index()) + { + case STATE_GENPC: + m_pc = R[P]; + break; + + case STATE_GENFLAGS: + m_flagsio = GET_FLAGS(); + break; + } +} + + +//------------------------------------------------- +// state_string_export - export state as a string +// for the debugger +//------------------------------------------------- + +void cosmac_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + switch (entry.index()) + { + case STATE_GENFLAGS: + strprintf(str, "%c%c%c", + m_df ? 'D' : '.', + m_ie ? 'I' : '.', + m_q ? 'Q' : '.'); + break; + } +} + + +//------------------------------------------------- +// disasm_min_opcode_bytes - return the length +// of the shortest instruction, in bytes +//------------------------------------------------- + +UINT32 cosmac_device::disasm_min_opcode_bytes() const +{ + return 1; +} + + +//------------------------------------------------- +// disasm_max_opcode_bytes - return the length +// of the longest instruction, in bytes +//------------------------------------------------- + +UINT32 cosmac_device::disasm_max_opcode_bytes() const +{ + return 3; +} + + +//------------------------------------------------- +// disasm_disassemble - call the disassembly +// helper function +//------------------------------------------------- + +offs_t cdp1801_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( cdp1801 ); + return CPU_DISASSEMBLE_NAME( cdp1801 )(this, buffer, pc, oprom, opram, options); +} + +offs_t cdp1802_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( cdp1802 ); + return CPU_DISASSEMBLE_NAME( cdp1802 )(this, buffer, pc, oprom, opram, options); +} + + +//************************************************************************** +// INLINE HELPERS +//************************************************************************** + +//------------------------------------------------- +// read_opcode - read an opcode at the given address +//------------------------------------------------- + +inline UINT8 cosmac_device::read_opcode(offs_t pc) +{ + return m_direct->read_byte(pc); +} + + +//------------------------------------------------- +// read_byte - read a byte at the given address +//------------------------------------------------- + +inline UINT8 cosmac_device::read_byte(offs_t address) +{ + return m_program->read_byte(address); +} + + +//------------------------------------------------- +// read_io_byte - read an I/O byte at the given +// address +//------------------------------------------------- + +inline UINT8 cosmac_device::read_io_byte(offs_t address) +{ + return m_io->read_byte(address); +} + + +//------------------------------------------------- +// write_byte - write a byte at the given address +//------------------------------------------------- + +inline void cosmac_device::write_byte(offs_t address, UINT8 data) +{ + m_program->write_byte(address, data); +} + + +//------------------------------------------------- +// write_io_byte - write an I/O byte at the given +// address +//------------------------------------------------- + +inline void cosmac_device::write_io_byte(offs_t address, UINT8 data) +{ + m_io->write_byte(address, data); +} + + + +//************************************************************************** +// CORE EXECUTION +//************************************************************************** + +//------------------------------------------------- +// get_memory_address - get current memory address +//------------------------------------------------- + +offs_t cosmac_device::get_memory_address() +{ + // this is valid for INP/OUT opcodes + return R[X]; +} + +//------------------------------------------------- +// execute_min_cycles - return minimum number of +// cycles it takes for one instruction to execute +//------------------------------------------------- + +UINT32 cosmac_device::execute_min_cycles() const +{ + return 8 * 2; +} + + +//------------------------------------------------- +// execute_max_cycles - return maximum number of +// cycles it takes for one instruction to execute +//------------------------------------------------- + +UINT32 cosmac_device::execute_max_cycles() const +{ + return 8 * 3; +} + + +//------------------------------------------------- +// execute_input_lines - return the number of +// input/interrupt lines +//------------------------------------------------- + +UINT32 cosmac_device::execute_input_lines() const +{ + return 7; +} + + +//------------------------------------------------- +// execute_set_input - +//------------------------------------------------- + +void cosmac_device::execute_set_input(int inputnum, int state) +{ + switch (inputnum) + { + case COSMAC_INPUT_LINE_INT: + m_irq = state; + break; + + case COSMAC_INPUT_LINE_DMAIN: + m_dmain = state; + break; + + case COSMAC_INPUT_LINE_DMAOUT: + m_dmaout = state; + break; + + case COSMAC_INPUT_LINE_EF1: + case COSMAC_INPUT_LINE_EF2: + case COSMAC_INPUT_LINE_EF3: + case COSMAC_INPUT_LINE_EF4: + EF[inputnum - COSMAC_INPUT_LINE_EF1] = state; + break; + } +} + + +//------------------------------------------------- +// execute_run - +//------------------------------------------------- + +void cosmac_device::execute_run() +{ + do + { + sample_wait_clear(); + + switch (m_mode) + { + case COSMAC_MODE_LOAD: + if (m_pmode == COSMAC_MODE_RESET) + { + m_pmode = COSMAC_MODE_LOAD; + + // execute initialization cycle + m_state = COSMAC_STATE_1_INIT; + run(); + + // next state is IDLE + m_state = COSMAC_STATE_1_EXECUTE; + } + else + { + // idle + m_op = 0; + I = 0; + N = 0; + run(); + } + break; + + case COSMAC_MODE_RESET: + m_state = COSMAC_STATE_1_RESET; + run(); + break; + + case COSMAC_MODE_PAUSE: + m_icount--; + break; + + case COSMAC_MODE_RUN: + switch (m_pmode) + { + case COSMAC_MODE_LOAD: + // RUN mode cannot be initiated from LOAD mode + logerror("COSMAC '%s' Tried to initiate RUN mode from LOAD mode\n", tag()); + m_mode = COSMAC_MODE_LOAD; + break; + + case COSMAC_MODE_RESET: + m_pmode = COSMAC_MODE_RUN; + m_state = COSMAC_STATE_1_INIT; + run(); + break; + + case COSMAC_MODE_PAUSE: + m_pmode = COSMAC_MODE_RUN; + m_state = COSMAC_STATE_0_FETCH; + run(); + break; + + case COSMAC_MODE_RUN: + run(); + break; + } + break; + } + } + while (m_icount > 0); +} + + +//------------------------------------------------- +// run - run the CPU state machine +//------------------------------------------------- + +inline void cosmac_device::run() +{ + output_state_code(); + + switch (m_state) + { + case COSMAC_STATE_0_FETCH: + fetch_instruction(); + break; + + case COSMAC_STATE_1_RESET: + reset(); + debug(); + break; + + case COSMAC_STATE_1_INIT: + initialize(); + debug(); + break; + + case COSMAC_STATE_1_EXECUTE: + sample_ef_lines(); + execute_instruction(); + debug(); + break; + + case COSMAC_STATE_2_DMA_IN: + dma_input(); + break; + + case COSMAC_STATE_2_DMA_OUT: + dma_output(); + break; + + case COSMAC_STATE_3_INT: + interrupt(); + debug(); + break; + } +} + + +//------------------------------------------------- +// debug - hook into debugger +//------------------------------------------------- + +inline void cosmac_device::debug() +{ + if (device_t::machine().debug_flags & DEBUG_FLAG_ENABLED) + { + debugger_instruction_hook(this, R[P]); + } +} + + +//------------------------------------------------- +// sample_wait_clear - sample wait/clear lines +//------------------------------------------------- + +inline void cosmac_device::sample_wait_clear() +{ + int wait = m_read_wait(); + int clear = m_read_clear(); + + m_pmode = m_mode; + m_mode = (cosmac_mode) ((clear << 1) | wait); +} + + +//------------------------------------------------- +// sample_ef_lines - sample EF input lines +//------------------------------------------------- + +inline void cosmac_device::sample_ef_lines() +{ + if (!m_read_ef1.isnull()) EF[0] = m_read_ef1(); + if (!m_read_ef2.isnull()) EF[1] = m_read_ef2(); + if (!m_read_ef3.isnull()) EF[2] = m_read_ef3(); + if (!m_read_ef4.isnull()) EF[3] = m_read_ef4(); +} + + +//------------------------------------------------- +// output_state_code - output state code +//------------------------------------------------- + +inline void cosmac_device::output_state_code() +{ + m_write_sc((offs_t)0, COSMAC_STATE_CODE[m_state]); +} + + +//------------------------------------------------- +// set_q_flag - set Q flag state and output it +//------------------------------------------------- + +inline void cosmac_device::set_q_flag(int state) +{ + Q = state; + + m_write_q(Q); +} + + +//------------------------------------------------- +// fetch_instruction - fetch instruction from +// the program memory +//------------------------------------------------- + +inline void cosmac_device::fetch_instruction() +{ + // instruction fetch + m_op = read_opcode(R[P]); + R[P]++; + + I = m_op >> 4; + N = m_op & 0x0f; + + m_icount -= CLOCKS_FETCH; + + m_state = COSMAC_STATE_1_EXECUTE; +} + + +//------------------------------------------------- +// reset - handle reset state +//------------------------------------------------- + +inline void cosmac_device::reset() +{ + m_op = 0; + I = 0; + N = 0; + Q = 0; + IE = 1; + + m_icount -= CLOCKS_RESET; +} + + +//------------------------------------------------- +// initialize - handle initialization state +//------------------------------------------------- + +inline void cosmac_device::initialize() +{ + X = 0; + P = 0; + R[0] = 0; + + m_icount -= CLOCKS_INIT; + + if (m_dmain) + { + m_state = COSMAC_STATE_2_DMA_IN; + } + else if (m_dmaout) + { + m_state = COSMAC_STATE_2_DMA_OUT; + } + else + { + m_state = COSMAC_STATE_0_FETCH; + } +} + + +//------------------------------------------------- +// execute_instruction - execute instruction +//------------------------------------------------- + +inline void cosmac_device::execute_instruction() +{ + // parse the instruction + (this->*this->get_ophandler(m_op))(); + + m_icount -= CLOCKS_EXECUTE; + + if (m_dmain) + { + m_state = COSMAC_STATE_2_DMA_IN; + } + else if (m_dmaout) + { + m_state = COSMAC_STATE_2_DMA_OUT; + } + else if (IE && m_irq) + { + m_state = COSMAC_STATE_3_INT; + } + else if ((I > 0) || (N > 0)) // not idling + { + m_state = COSMAC_STATE_0_FETCH; + } +} + + +//------------------------------------------------- +// dma_input - handle DMA input state +//------------------------------------------------- + +inline void cosmac_device::dma_input() +{ + RAM_W(R[0], m_read_dma(R[0])); + + R[0]++; + + m_icount -= CLOCKS_DMA; + + if (m_dmain) + { + m_state = COSMAC_STATE_2_DMA_IN; + } + else if (m_dmaout) + { + m_state = COSMAC_STATE_2_DMA_OUT; + } + else if (IE && m_irq) + { + m_state = COSMAC_STATE_3_INT; + } + else if (m_mode == COSMAC_MODE_LOAD) + { + m_state = COSMAC_STATE_1_EXECUTE; + } + else + { + m_state = COSMAC_STATE_0_FETCH; + } + + standard_irq_callback(COSMAC_INPUT_LINE_DMAIN); +} + + +//------------------------------------------------- +// dma_output - handle DMA output state +//------------------------------------------------- + +inline void cosmac_device::dma_output() +{ + m_write_dma((offs_t)R[0], RAM_R(R[0])); + + R[0]++; + + m_icount -= CLOCKS_DMA; + + if (m_dmain) + { + m_state = COSMAC_STATE_2_DMA_IN; + } + else if (m_dmaout) + { + m_state = COSMAC_STATE_2_DMA_OUT; + } + else if (IE && m_irq) + { + m_state = COSMAC_STATE_3_INT; + } + else + { + m_state = COSMAC_STATE_0_FETCH; + } + + standard_irq_callback(COSMAC_INPUT_LINE_DMAOUT); +} + + +//------------------------------------------------- +// interrupt - handle interrupt state +//------------------------------------------------- + +inline void cosmac_device::interrupt() +{ + T = (X << 4) | P; + X = 2; + P = 1; + IE = 0; + + m_icount -= CLOCKS_INTERRUPT; + + if (m_dmain) + { + m_state = COSMAC_STATE_2_DMA_IN; + } + else if (m_dmaout) + { + m_state = COSMAC_STATE_2_DMA_OUT; + } + else + { + m_state = COSMAC_STATE_0_FETCH; + } + + standard_irq_callback(COSMAC_INPUT_LINE_INT); +} + + + +//************************************************************************** +// OPCODE IMPLEMENTATIONS +//************************************************************************** + +// memory reference opcode handlers +void cosmac_device::ldn() { D = RAM_R(R[N]); } +void cosmac_device::lda() { D = RAM_R(R[N]); R[N]++; } +void cosmac_device::ldx() { D = RAM_R(R[X]); } +void cosmac_device::ldxa() { D = RAM_R(R[X]); R[X]++; } +void cosmac_device::ldi() { D = RAM_R(R[P]); R[P]++; } +void cosmac_device::str() { RAM_W(R[N], D); } +void cosmac_device::stxd() { RAM_W(R[X], D); R[X]--; } + +// register operations opcode handlers +void cosmac_device::inc() { R[N]++; } +void cosmac_device::dec() { R[N]--; } +void cosmac_device::irx() { R[X]++; } +void cosmac_device::glo() { D = R[N] & 0xff; } +void cosmac_device::plo() { R[N] = (R[N] & 0xff00) | D; } +void cosmac_device::ghi() { D = R[N] >> 8; } +void cosmac_device::phi() { R[N] = (D << 8) | (R[N] & 0xff); } + +// logic operations opcode handlers +void cosmac_device::_or() { D = RAM_R(R[X]) | D; } +void cosmac_device::ori() { D = RAM_R(R[P]) | D; R[P]++; } +void cosmac_device::_xor() { D = RAM_R(R[X]) ^ D; } +void cosmac_device::xri() { D = RAM_R(R[P]) ^ D; R[P]++; } +void cosmac_device::_and() { D = RAM_R(R[X]) & D; } +void cosmac_device::ani() { D = RAM_R(R[P]) & D; R[P]++; } +void cosmac_device::shr() { DF = BIT(D, 0); D >>= 1; } +void cosmac_device::shrc() { int b = DF; DF = BIT(D, 0); D >>= 1; D |= b << 7; } +void cosmac_device::shl() { DF = BIT(D, 7); D <<= 1; } +void cosmac_device::shlc() { int b = DF; DF = BIT(D, 7); D <<= 1; D |= b; } + +// arithmetic operations opcode handlers +void cosmac_device::add(int left, int right) +{ + int result = left + right; + + D = result & 0xff; + DF = result > 0xff; +} + +void cosmac_device::add_with_carry(int left, int right) +{ + int result = left + right + DF; + + D = result & 0xff; + DF = result > 0xff; +} + +void cosmac_device::subtract(int left, int right) +{ + int result = left + (right ^ 0xff) + 1; + + D = result & 0xff; + DF = result > 0xff; +} + +void cosmac_device::subtract_with_borrow(int left, int right) +{ + int result = left + (right ^ 0xff) + DF; + + D = result & 0xff; + DF = result > 0xff; +} + +void cosmac_device::add() { add(RAM_R(R[X]), D); } +void cosmac_device::adi() { add(RAM_R(R[P]), D); R[P]++; } +void cosmac_device::adc() { add_with_carry(RAM_R(R[X]), D); } +void cosmac_device::adci() { add_with_carry(RAM_R(R[P]), D); R[P]++; } +void cosmac_device::sd() { subtract(RAM_R(R[X]), D); } +void cosmac_device::sdi() { subtract(RAM_R(R[P]), D); R[P]++; } +void cosmac_device::sdb() { subtract_with_borrow(RAM_R(R[X]), D); } +void cosmac_device::sdbi() { subtract_with_borrow(RAM_R(R[P]), D); R[P]++; } +void cosmac_device::sm() { subtract(D, RAM_R(R[X])); } +void cosmac_device::smi() { subtract(D, RAM_R(R[P])); R[P]++; } +void cosmac_device::smb() { subtract_with_borrow(D, RAM_R(R[X])); } +void cosmac_device::smbi() { subtract_with_borrow(D, RAM_R(R[P])); R[P]++; } + +// short branch instructions opcode handlers +void cosmac_device::short_branch(int taken) +{ + if (taken) + { + R[P] = (R[P] & 0xff00) | OPCODE_R(R[P]); + } + else + { + R[P]++; + } +} + +void cosmac_device::br() { short_branch(1); } +void cosmac_device::nbr() { short_branch(0); } +void cosmac_device::bz() { short_branch(D == 0); } +void cosmac_device::bnz() { short_branch(D != 0); } +void cosmac_device::bdf() { short_branch(DF); } +void cosmac_device::bnf() { short_branch(!DF); } +void cosmac_device::bq() { short_branch(Q); } +void cosmac_device::bnq() { short_branch(!Q); } +void cosmac_device::b() { short_branch(EF[N & 0x03]); } +void cosmac_device::bn() { short_branch(!EF[N & 0x03]); } + +// long branch instructions opcode handlers +void cosmac_device::long_branch(int taken) +{ + if (taken) + { + // S1#1 + B = OPCODE_R(R[P]++); + + // S1#2 + R[P] = (B << 8) | OPCODE_R(R[P]); + } + else + { + // S1#1 + R[P]++; + + // S1#2 + R[P]++; + } + + m_icount -= CLOCKS_EXECUTE; +} + +void cosmac_device::lbr() { long_branch(1); } +void cosmac_device::nlbr() { long_skip(1); } +void cosmac_device::lbz() { long_branch(D == 0); } +void cosmac_device::lbnz() { long_branch(D != 0); } +void cosmac_device::lbdf() { long_branch(DF); } +void cosmac_device::lbnf() { long_branch(!DF); } +void cosmac_device::lbq() { long_branch(Q); } +void cosmac_device::lbnq() { long_branch(!Q); } + +// skip instructions opcode handlers +void cosmac_device::long_skip(int taken) +{ + if (taken) + { + // S1#1 + R[P]++; + + // S1#2 + R[P]++; + } + + m_icount -= CLOCKS_EXECUTE; +} + +void cosmac_device::lsz() { long_skip(D == 0); } +void cosmac_device::lsnz() { long_skip(D != 0); } +void cosmac_device::lsdf() { long_skip(DF); } +void cosmac_device::lsnf() { long_skip(!DF); } +void cosmac_device::lsq() { long_skip(Q); } +void cosmac_device::lsnq() { long_skip(!Q); } +void cosmac_device::lsie() { long_skip(IE); } + +// control instructions opcode handlers +void cosmac_device::idl() { /* idle */ } +void cosmac_device::nop() { m_icount -= CLOCKS_EXECUTE; } +void cosmac_device::und() { /* undefined opcode in CDP1801 */ m_icount -= CLOCKS_EXECUTE; } +void cosmac_device::sep() { P = N; } +void cosmac_device::sex() { X = N; } +void cosmac_device::seq() { set_q_flag(1); } +void cosmac_device::req() { set_q_flag(0); } +void cosmac_device::sav() { RAM_W(R[X], T); } + +void cosmac_device::mark() +{ + T = (X << 4) | P; + RAM_W(R[2], T); + X = P; + R[2]--; +} + +void cosmac_device::return_from_interrupt(int ie) +{ + UINT8 data = RAM_R(R[X]); + R[X]++; + P = data & 0xf; + X = data >> 4; + IE = ie; +} + +void cosmac_device::ret() { return_from_interrupt(1); } +void cosmac_device::dis() { return_from_interrupt(0); } + +// input/output byte transfer opcode handlers +void cosmac_device::out() { IO_W(N, RAM_R(R[X])); R[X]++; } + +/* + + A note about INP 0 (0x68) from Tom Pittman's "A Short Course in Programming": + + If you look carefully, you will notice that we never studied the opcode "68". + That's because it is not a defined 1802 instruction. It has the form of an INP + instruction, but 0 is not a defined input port, so if you execute it (try it!) + nothing is input. "Nothing" is the answer to a question; it is data, and something + will be put in the accumulator and memory (so now you know what the computer uses + to mean "nothing"). + + However, since the result of the "68" opcode is unpredictable, it should not be + used in your programs. In fact, "68" is the first byte of a series of additional + instructions for the 1804 and 1805 microprocessors. + + http://www.ittybittycomputers.com/IttyBitty/ShortCor.htm + +*/ +void cosmac_device::inp() { D = IO_R(N & 0x07); RAM_W(R[X], D); } diff --git a/src/devices/cpu/cosmac/cosmac.h b/src/devices/cpu/cosmac/cosmac.h new file mode 100644 index 00000000000..c80a8e9ab6c --- /dev/null +++ b/src/devices/cpu/cosmac/cosmac.h @@ -0,0 +1,486 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + RCA COSMAC CPU emulation + +********************************************************************** + _____ _____ + Vcc 1 |* \_/ | 40 Vdd + _BUS 3 2 | | 39 _BUS 4 + _BUS 2 3 | | 38 _BUS 5 + _BUS 1 4 | | 37 _BUS 6 + _BUS 0 5 | | 36 _BUS 7 + _N0 6 | | 35 Vss + _N1 7 | | 34 _EF1 + _N2 8 | | 33 _EF2 + _N3 9 | | 32 _EF3 + * 10 | CDP1801U | 31 _EF4 + * 11 | | 30 _DMA OUT + * 12 | | 29 _INTERRUPT + * 13 | | 28 _DMA IN + * 14 | | 27 _CLEAR + _CLOCK 15 | | 26 _LOAD + _TPB 16 | | 25 _SC2 + _TPA 17 | | 24 _SC1 + * 18 | | 23 _SC0 + MWR 19 | | 22 _M READ + Vss 20 |_____________| 21 * + + _____ _____ + Vcc 1 |* \_/ | 28 Vdd + _BUS 4 2 | | 27 _BUS 3 + _BUS 5 3 | | 26 _BUS 2 + _BUS 6 4 | | 25 _BUS 1 + _BUS 7 5 | | 24 _BUS 0 + _MA0 6 | | 23 * + _MA1 7 | CDP1801C | 22 _TPB + _MA2 8 | | 21 * + _MA3 9 | | 20 * + _MA4 10 | | 19 * + _MA5 11 | | 18 * + _MA6 12 | | 17 * + _MA7 13 | | 16 * + Vss 14 |_____________| 15 _CLEAR + + _____ _____ + CLOCK 1 |* \_/ | 40 Vdd + _WAIT 2 | | 39 _XTAL + _CLEAR 3 | | 38 _DMA IN + Q 4 | | 37 _DMA OUT + SC1 5 | | 36 _INTERRUPT + SC0 6 | | 35 _MWR + _MRD 7 | | 34 TPA + BUS 7 8 | | 33 TPB + BUS 6 9 | CDP1802 | 32 MA7 + BUS 5 10 | CDP1803 | 31 MA6 + BUS 4 11 | CDP1804 | 30 MA5 + BUS 3 12 | CDP1805 | 29 MA4 + BUS 2 13 | CDP1806 | 28 MA3 + BUS 1 14 | | 27 MA2 + BUS 0 15 | | 26 MA1 + * 16 | | 25 MA0 + N2 17 | | 24 _EF1 + N1 18 | | 23 _EF2 + N0 19 | | 22 _EF3 + Vss 20 |_____________| 21 _EF4 + + + Type Internal ROM Internal RAM Timer Pin 16 (*) + ------------------------------------------------------------------ + CDP1802 none none no Vcc + CDP1803 ? ? ? ? + CDP1804 2 KB 64 bytes yes ? + CDP1805 none 64 bytes yes _ME + CDP1806 none none yes Vdd + +**********************************************************************/ + +#pragma once + +#ifndef __COSMAC_H__ +#define __COSMAC_H__ + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_COSMAC_WAIT_CALLBACK(_read) \ + devcb = &cosmac_device::set_wait_rd_callback(*device, DEVCB_##_read); + +#define MCFG_COSMAC_CLEAR_CALLBACK(_read) \ + devcb = &cosmac_device::set_clear_rd_callback(*device, DEVCB_##_read); + +#define MCFG_COSMAC_EF1_CALLBACK(_read) \ + devcb = &cosmac_device::set_ef1_rd_callback(*device, DEVCB_##_read); + +#define MCFG_COSMAC_EF2_CALLBACK(_read) \ + devcb = &cosmac_device::set_ef2_rd_callback(*device, DEVCB_##_read); + +#define MCFG_COSMAC_EF3_CALLBACK(_read) \ + devcb = &cosmac_device::set_ef3_rd_callback(*device, DEVCB_##_read); + +#define MCFG_COSMAC_EF4_CALLBACK(_read) \ + devcb = &cosmac_device::set_ef4_rd_callback(*device, DEVCB_##_read); + +#define MCFG_COSMAC_Q_CALLBACK(_write) \ + devcb = &cosmac_device::set_q_wr_callback(*device, DEVCB_##_write); + +#define MCFG_COSMAC_DMAR_CALLBACK(_read) \ + devcb = &cosmac_device::set_dma_rd_callback(*device, DEVCB_##_read); + +#define MCFG_COSMAC_DMAW_CALLBACK(_write) \ + devcb = &cosmac_device::set_dma_wr_callback(*device, DEVCB_##_write); + +#define MCFG_COSMAC_SC_CALLBACK(_write) \ + devcb = &cosmac_device::set_sc_wr_callback(*device, DEVCB_##_write); + + + +//************************************************************************** +// ENUMERATIONS +//************************************************************************** + +// registers +enum +{ + COSMAC_P, + COSMAC_X, + COSMAC_D, + COSMAC_B, + COSMAC_T, + COSMAC_R0, + COSMAC_R1, + COSMAC_R2, + COSMAC_R3, + COSMAC_R4, + COSMAC_R5, + COSMAC_R6, + COSMAC_R7, + COSMAC_R8, + COSMAC_R9, + COSMAC_Ra, + COSMAC_Rb, + COSMAC_Rc, + COSMAC_Rd, + COSMAC_Re, + COSMAC_Rf, + COSMAC_DF, + COSMAC_IE, + COSMAC_Q, + COSMAC_N, + COSMAC_I, + COSMAC_SC +}; + + +// input lines +enum +{ + COSMAC_INPUT_LINE_INT = 0, + COSMAC_INPUT_LINE_DMAIN, + COSMAC_INPUT_LINE_DMAOUT, + COSMAC_INPUT_LINE_EF1, + COSMAC_INPUT_LINE_EF2, + COSMAC_INPUT_LINE_EF3, + COSMAC_INPUT_LINE_EF4 +}; + + +// state codes +enum cosmac_state_code +{ + COSMAC_STATE_CODE_S0_FETCH = 0, + COSMAC_STATE_CODE_S1_EXECUTE, + COSMAC_STATE_CODE_S2_DMA, + COSMAC_STATE_CODE_S3_INTERRUPT +}; + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> cosmac_device + +class cosmac_device : public cpu_device +{ +public: + // construction/destruction + cosmac_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + template static devcb_base &set_wait_rd_callback(device_t &device, _Object object) { return downcast(device).m_read_wait.set_callback(object); } + template static devcb_base &set_clear_rd_callback(device_t &device, _Object object) { return downcast(device).m_read_clear.set_callback(object); } + template static devcb_base &set_ef1_rd_callback(device_t &device, _Object object) { return downcast(device).m_read_ef1.set_callback(object); } + template static devcb_base &set_ef2_rd_callback(device_t &device, _Object object) { return downcast(device).m_read_ef2.set_callback(object); } + template static devcb_base &set_ef3_rd_callback(device_t &device, _Object object) { return downcast(device).m_read_ef3.set_callback(object); } + template static devcb_base &set_ef4_rd_callback(device_t &device, _Object object) { return downcast(device).m_read_ef4.set_callback(object); } + template static devcb_base &set_q_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_q.set_callback(object); } + template static devcb_base &set_dma_rd_callback(device_t &device, _Object object) { return downcast(device).m_read_dma.set_callback(object); } + template static devcb_base &set_dma_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_dma.set_callback(object); } + template static devcb_base &set_sc_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_sc.set_callback(object); } + + // public interfaces + offs_t get_memory_address(); + + DECLARE_WRITE_LINE_MEMBER( int_w ) { set_input_line(COSMAC_INPUT_LINE_INT, state); } + DECLARE_WRITE_LINE_MEMBER( dma_in_w ) { set_input_line(COSMAC_INPUT_LINE_DMAIN, state); } + DECLARE_WRITE_LINE_MEMBER( dma_out_w ) { set_input_line(COSMAC_INPUT_LINE_DMAOUT, state); } + DECLARE_WRITE_LINE_MEMBER( ef1_w ) { set_input_line(COSMAC_INPUT_LINE_EF1, state); } + DECLARE_WRITE_LINE_MEMBER( ef2_w ) { set_input_line(COSMAC_INPUT_LINE_EF2, state); } + DECLARE_WRITE_LINE_MEMBER( ef3_w ) { set_input_line(COSMAC_INPUT_LINE_EF3, state); } + DECLARE_WRITE_LINE_MEMBER( ef4_w ) { set_input_line(COSMAC_INPUT_LINE_EF4, state); } + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_execute_interface overrides + virtual UINT32 execute_min_cycles() const; + virtual UINT32 execute_max_cycles() const; + virtual UINT32 execute_input_lines() const; + virtual void execute_run(); + virtual void execute_set_input(int inputnum, int state); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const; + + // device_state_interface overrides + virtual void state_import(const device_state_entry &entry); + virtual void state_export(const device_state_entry &entry); + virtual void state_string_export(const device_state_entry &entry, std::string &str); + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const; + virtual UINT32 disasm_max_opcode_bytes() const; + + // helpers + inline UINT8 read_opcode(offs_t pc); + inline UINT8 read_byte(offs_t address); + inline UINT8 read_io_byte(offs_t address); + inline void write_byte(offs_t address, UINT8 data); + inline void write_io_byte(offs_t address, UINT8 data); + + // execution logic + inline void run(); + inline void debug(); + inline void reset(); + inline void initialize(); + inline void fetch_instruction(); + inline void fetch_instruction_debug(); + inline void execute_instruction(); + inline void dma_input(); + inline void dma_output(); + inline void interrupt(); + inline void sample_wait_clear(); + inline void sample_ef_lines(); + inline void output_state_code(); + inline void set_q_flag(int state); + + // arithmetic handlers + void add(int left, int right); + void add_with_carry(int left, int right); + void subtract(int left, int right); + void subtract_with_borrow(int left, int right); + + // condition handlers + void short_branch(int taken); + void long_branch(int taken); + void long_skip(int taken); + + // control handlers + void return_from_interrupt(int ie); + + // memory reference opcode handlers + void ldn(); + void lda(); + void ldx(); + void ldxa(); + void ldi(); + void str(); + void stxd(); + + // register operations opcode handlers + void inc(); + void dec(); + void irx(); + void glo(); + void plo(); + void ghi(); + void phi(); + + // logic operations opcode handlers + void _or(); + void ori(); + void _xor(); + void xri(); + void _and(); + void ani(); + void shr(); + void shrc(); + void shl(); + void shlc(); + + // arithmetic operations opcode handlers + void add(); + void adi(); + void adc(); + void adci(); + void sd(); + void sdi(); + void sdb(); + void sdbi(); + void sm(); + void smi(); + void smb(); + void smbi(); + + // short branch instructions opcode handlers + void br(); + void nbr(); + void bz(); + void bnz(); + void bdf(); + void bnf(); + void bq(); + void bnq(); + void b(); + void bn(); + + // long branch instructions opcode handlers + void lbr(); + void nlbr(); + void lbz(); + void lbnz(); + void lbdf(); + void lbnf(); + void lbq(); + void lbnq(); + + // skip instructions opcode handlers + void lsz(); + void lsnz(); + void lsdf(); + void lsnf(); + void lsq(); + void lsnq(); + void lsie(); + + // control instructions opcode handlers + void idl(); + void nop(); + void und(); + void sep(); + void sex(); + void seq(); + void req(); + void sav(); + void mark(); + void ret(); + void dis(); + + // input/output byte transfer opcode handlers + void out(); + void inp(); + + const address_space_config m_program_config; + const address_space_config m_io_config; + + // device callbacks + devcb_read_line m_read_wait; + devcb_read_line m_read_clear; + devcb_read_line m_read_ef1; + devcb_read_line m_read_ef2; + devcb_read_line m_read_ef3; + devcb_read_line m_read_ef4; + devcb_write_line m_write_q; + devcb_read8 m_read_dma; + devcb_write8 m_write_dma; + devcb_write8 m_write_sc; + + // control modes + enum cosmac_mode + { + COSMAC_MODE_LOAD = 0, + COSMAC_MODE_RESET, + COSMAC_MODE_PAUSE, + COSMAC_MODE_RUN + }; + + // execution states + enum cosmac_state + { + COSMAC_STATE_0_FETCH = 0, + COSMAC_STATE_1_RESET, + COSMAC_STATE_1_INIT, + COSMAC_STATE_1_EXECUTE, + COSMAC_STATE_2_DMA_IN, + COSMAC_STATE_2_DMA_OUT, + COSMAC_STATE_3_INT + }; + + // internal state + UINT16 m_pc; // fake program counter + UINT8 m_op; // current opcode + UINT8 m_flagsio; // flags storage for state saving + cosmac_state m_state; // state + cosmac_mode m_mode; // control mode + cosmac_mode m_pmode; // previous control mode + int m_irq; // interrupt request + int m_dmain; // DMA input request + int m_dmaout; // DMA output request + int m_ef[4]; // external flags + + // registers + UINT8 m_d; // data register (accumulator) + UINT8 m_b; // auxiliary holding register + UINT16 m_r[16]; // scratchpad registers + UINT8 m_p; // designates which register is Program Counter + UINT8 m_x; // designates which register is Data Pointer + UINT8 m_n; // low-order instruction digit + UINT8 m_i; // high-order instruction digit + UINT8 m_t; // temporary register + + // flags + int m_df; // data flag (ALU carry) + int m_ie; // interrupt enable + int m_q; // output flip-flop + + // internal stuff + int m_icount; + address_space * m_program; + address_space * m_io; + direct_read_data * m_direct; + + // opcode/condition tables + typedef void (cosmac_device::*ophandler)(); + virtual cosmac_device::ophandler get_ophandler(UINT8 opcode) = 0; +}; + + +// ======================> cdp1801_device + +class cdp1801_device : public cosmac_device +{ +public: + // construction/destruction + cdp1801_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // device_disasm_interface overrides + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + + virtual cosmac_device::ophandler get_ophandler(UINT8 opcode); + + static const ophandler s_opcodetable[256]; +}; + + +// ======================> cdp1802_device + +class cdp1802_device : public cosmac_device +{ +public: + // construction/destruction + cdp1802_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // device_disasm_interface overrides + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + + virtual cosmac_device::ophandler get_ophandler(UINT8 opcode); + + static const ophandler s_opcodetable[256]; +}; + + +// device type definition +extern const device_type CDP1801; +extern const device_type CDP1802; + + +#endif /* __COSMAC_H__ */ diff --git a/src/devices/cpu/cp1610/1610dasm.c b/src/devices/cpu/cp1610/1610dasm.c new file mode 100644 index 00000000000..0035e9b78a5 --- /dev/null +++ b/src/devices/cpu/cp1610/1610dasm.c @@ -0,0 +1,1490 @@ +// license:BSD-3-Clause +// copyright-holders:Frank Palazzolo +#include "emu.h" +#include "debugger.h" +#include "cp1610.h" + +CPU_DISASSEMBLE( cp1610 ) +{ + UINT16 oprom16[4]={ (oprom[0] << 8) | oprom[1], (oprom[2] << 8) | oprom[3], (oprom[4] << 8) | oprom[5], (oprom[6] << 8) | oprom[7] }; + UINT16 op = oprom16[0]; UINT16 subop; + UINT16 ea, ea1, ea2; + unsigned size = 1; +// const char *sym, *sym2; + + switch( op ) + { + /* opcode bitmask */ + case 0x00: /* 0 000 000 000 */ +// sym = set_ea_info( 0, 12, EA_UINT8, EA_ZPG_RD ); + sprintf(buffer, "HLT"); + break; + case 0x001: /* 0 000 000 001 */ + subop = oprom16[1]; + switch (subop & 0x3f8) + { + case 0x280: /* 1 010 000 xxx */ + case 0x288: /* 1 010 001 xxx */ + case 0x290: /* 1 010 010 xxx */ + case 0x298: /* 1 010 011 xxx */ + case 0x2a0: /* 1 010 100 xxx */ + case 0x2a8: /* 1 010 101 xxx */ + case 0x2b0: /* 1 010 110 xxx */ + sprintf(buffer,"MVI@ (R%01d), R%01d",(subop&0x38)>>3,subop&7); + size += 1; + break; + case 0x2b8: /* 1 010 111 xxx */ + ea1 = oprom16[2]; + ea2 = oprom16[3]; + ea = ((ea2&0xff)<<8) | (ea1&0xff); + sprintf(buffer,"MVII #%04X, R%01d",ea,subop&7); + size += 3; + break; + case 0x2c0: /* 1 011 000 xxx */ + case 0x2c8: /* 1 011 001 xxx */ + case 0x2d0: /* 1 011 010 xxx */ + case 0x2d8: /* 1 011 011 xxx */ + case 0x2e0: /* 1 011 100 xxx */ + case 0x2e8: /* 1 011 101 xxx */ + case 0x2f0: /* 1 011 110 xxx */ + sprintf(buffer,"ADD@ (R%01d), R%01d",(subop&0x38)>>3,subop&7); + size += 1; + break; + case 0x2f8: /* 1 011 111 xxx */ + ea1 = oprom16[2]; + ea2 = oprom16[3]; + ea = ((ea2&0xff)<<8) | (ea1&0xff); + sprintf(buffer,"ADDI #%04X, R%01d",ea,subop&7); + size += 3; + break; + case 0x300: /* 1 100 000 xxx */ + case 0x308: /* 1 100 001 xxx */ + case 0x310: /* 1 100 010 xxx */ + case 0x318: /* 1 100 011 xxx */ + case 0x320: /* 1 100 100 xxx */ + case 0x328: /* 1 100 101 xxx */ + case 0x330: /* 1 100 110 xxx */ + sprintf(buffer,"SUB@ (R%01d), R%01d",(subop&0x38)>>3,subop&7); + size += 1; + break; + case 0x338: /* 1 100 111 xxx */ + ea1 = oprom16[2]; + ea2 = oprom16[3]; + ea = ((ea2&0xff)<<8) | (ea1&0xff); + sprintf(buffer,"SUBI #%04X, R%01d",ea,subop&7); + size += 3; + break; + case 0x340: /* 1 101 000 xxx */ + case 0x348: /* 1 101 001 xxx */ + case 0x350: /* 1 101 010 xxx */ + case 0x358: /* 1 101 011 xxx */ + case 0x360: /* 1 101 100 xxx */ + case 0x368: /* 1 101 101 xxx */ + case 0x370: /* 1 101 110 xxx */ + sprintf(buffer,"CMP@ (R%01d), R%01d",(subop&0x38)>>3,subop&7); + size += 1; + break; + case 0x378: /* 1 101 111 xxx */ + ea1 = oprom16[2]; + ea2 = oprom16[3]; + ea = ((ea2&0xff)<<8) | (ea1&0xff); + sprintf(buffer,"CMPI #%04X, R%01d",ea,subop&7); + size += 3; + break; + case 0x380: /* 1 110 000 xxx */ + case 0x388: /* 1 110 001 xxx */ + case 0x390: /* 1 110 010 xxx */ + case 0x398: /* 1 110 011 xxx */ + case 0x3a0: /* 1 110 100 xxx */ + case 0x3a8: /* 1 110 101 xxx */ + case 0x3b0: /* 1 110 110 xxx */ + sprintf(buffer,"AND@ (R%01d), R%01d",(subop&0x38)>>3,subop&7); + size += 1; + break; + case 0x3b8: /* 1 110 111 xxx */ + ea1 = oprom16[2]; + ea2 = oprom16[3]; + ea = ((ea2&0xff)<<8) | (ea1&0xff); + sprintf(buffer,"ANDI #%04X, R%01d",ea,subop&7); + size += 3; + break; + case 0x3c0: /* 1 111 000 xxx */ + case 0x3c8: /* 1 111 001 xxx */ + case 0x3d0: /* 1 111 010 xxx */ + case 0x3d8: /* 1 111 011 xxx */ + case 0x3e0: /* 1 111 100 xxx */ + case 0x3e8: /* 1 111 101 xxx */ + case 0x3f0: /* 1 111 110 xxx */ + sprintf(buffer,"XOR@ (R%01d), R%01d",(subop&0x38)>>3,subop&7); + size += 1; + break; + case 0x3f8: /* 1 111 111 xxx */ + ea1 = oprom16[2]; + ea2 = oprom16[3]; + ea = ((ea2&0xff)<<8) | (ea1&0xff); + sprintf(buffer,"XORI #%04X, R%01d",ea,subop&7); + size += 3; + break; + default: + size += 1; + sprintf(buffer, "SDBD ????"); + } + break; + case 0x002: /* 0 000 000 010 */ + sprintf(buffer, "EIS"); + break; + case 0x003: /* 0 000 000 011 */ + sprintf(buffer, "DIS"); + break; + case 0x004: /* 0 000 000 100 */ + size += 2; + ea1 = oprom16[1]; + ea2 = oprom16[2]; + ea = ((ea1<<8)&0xfc00) + (ea2&0x3ff); + if ((ea1&0x300) == 0x300) + { + //?? set direct address + switch(ea1 & 0x03) + { + case 0: + sprintf(buffer, "J %04X",ea); + break; + case 1: + sprintf(buffer, "JE %04X",ea); + break; + case 2: + sprintf(buffer, "JD %04X",ea); + break; + case 3: + sprintf(buffer, "????"); + break; + } + } + else + { + //?? set R?, return address + switch(ea1 & 0x03) + { + case 0: + sprintf(buffer, "JSR R%01d,%04X",((ea1&0x300)>>8)+4,ea); + break; + case 1: + sprintf(buffer, "JSRE R%01d,%04X",((ea1&0x300)>>8)+4,ea); + break; + case 2: + sprintf(buffer, "JSRD R%01d,%04X",((ea1&0x300)>>8)+4,ea); + break; + case 3: + sprintf(buffer, "????"); + break; + } + } + break; + case 0x005: /* 0 000 000 101 */ + sprintf(buffer, "TCI"); + break; + case 0x006: /* 0 000 000 110 */ + sprintf(buffer, "CLRC"); + break; + case 0x007: /* 0 000 000 111 */ + sprintf(buffer, "SETC"); + break; + case 0x008: /* 0 000 001 000 */ + case 0x009: /* 0 000 001 001 */ + case 0x00a: /* 0 000 001 010 */ + case 0x00b: /* 0 000 001 011 */ + case 0x00c: /* 0 000 001 100 */ + case 0x00d: /* 0 000 001 101 */ + case 0x00e: /* 0 000 001 110 */ + case 0x00f: /* 0 000 001 111 */ + sprintf(buffer, "INCR R%01d",op&0x7); + break; + case 0x010: /* 0 000 010 000 */ + case 0x011: /* 0 000 010 001 */ + case 0x012: /* 0 000 010 010 */ + case 0x013: /* 0 000 010 011 */ + case 0x014: /* 0 000 010 100 */ + case 0x015: /* 0 000 010 101 */ + case 0x016: /* 0 000 010 110 */ + case 0x017: /* 0 000 010 111 */ + sprintf(buffer, "DECR R%01d",op&0x7); + break; + case 0x018: /* 0 000 011 000 */ + case 0x019: /* 0 000 011 001 */ + case 0x01a: /* 0 000 011 010 */ + case 0x01b: /* 0 000 011 011 */ + case 0x01c: /* 0 000 011 100 */ + case 0x01d: /* 0 000 011 101 */ + case 0x01e: /* 0 000 011 110 */ + case 0x01f: /* 0 000 011 111 */ + sprintf(buffer, "COMR R%01d",op&0x7); + break; + case 0x020: /* 0 000 100 000 */ + case 0x021: /* 0 000 100 001 */ + case 0x022: /* 0 000 100 010 */ + case 0x023: /* 0 000 100 011 */ + case 0x024: /* 0 000 100 100 */ + case 0x025: /* 0 000 100 101 */ + case 0x026: /* 0 000 100 110 */ + case 0x027: /* 0 000 100 111 */ + sprintf(buffer, "NEGR R%01d",op&0x7); + break; + case 0x028: /* 0 000 101 000 */ + case 0x029: /* 0 000 101 001 */ + case 0x02a: /* 0 000 101 010 */ + case 0x02b: /* 0 000 101 011 */ + case 0x02c: /* 0 000 101 100 */ + case 0x02d: /* 0 000 101 101 */ + case 0x02e: /* 0 000 101 110 */ + case 0x02f: /* 0 000 101 111 */ + sprintf(buffer, "ADCR R%01d",op&0x7); + break; + case 0x030: /* 0 000 110 000 */ + case 0x031: /* 0 000 110 001 */ + case 0x032: /* 0 000 110 010 */ + case 0x033: /* 0 000 110 011 */ + sprintf(buffer, "GSWD R%01d",op&0x3); + break; + case 0x034: /* 0 000 110 100 */ + case 0x035: /* 0 000 110 101 */ + sprintf(buffer, "NOP (%01d)",op&0x1); //??? + break; + case 0x036: /* 0 000 110 110 */ + case 0x037: /* 0 000 110 111 */ + sprintf(buffer, "SIN"); + break; + case 0x038: /* 0 000 111 000 */ + case 0x039: /* 0 000 111 001 */ + case 0x03a: /* 0 000 111 010 */ + case 0x03b: /* 0 000 111 011 */ + case 0x03c: /* 0 000 111 100 */ + case 0x03d: /* 0 000 111 101 */ + case 0x03e: /* 0 000 111 110 */ + case 0x03f: /* 0 000 111 111 */ + sprintf(buffer, "RSWD R%01d",op&0x7); + break; + case 0x040: /* 0 001 000 000 */ + case 0x041: /* 0 001 000 001 */ + case 0x042: /* 0 001 000 010 */ + case 0x043: /* 0 001 000 011 */ + sprintf(buffer, "SWAP R%01d,1",op&0x3); + break; + case 0x044: /* 0 001 000 100 */ + case 0x045: /* 0 001 000 101 */ + case 0x046: /* 0 001 000 110 */ + case 0x047: /* 0 001 000 111 */ + sprintf(buffer, "SWAP R%01d,2",op&0x3); + break; + case 0x048: /* 0 001 001 000 */ + case 0x049: /* 0 001 001 001 */ + case 0x04a: /* 0 001 001 010 */ + case 0x04b: /* 0 001 001 011 */ + sprintf(buffer, "SLL R%01d,1",op&0x3); + break; + case 0x04c: /* 0 001 001 100 */ + case 0x04d: /* 0 001 001 101 */ + case 0x04e: /* 0 001 001 110 */ + case 0x04f: /* 0 001 001 111 */ + sprintf(buffer, "SLL R%01d,2",op&0x3); + break; + case 0x050: /* 0 001 010 000 */ + case 0x051: /* 0 001 010 001 */ + case 0x052: /* 0 001 010 010 */ + case 0x053: /* 0 001 010 011 */ + sprintf(buffer, "RLC R%01d,1",op&0x3); + break; + case 0x054: /* 0 001 010 100 */ + case 0x055: /* 0 001 010 101 */ + case 0x056: /* 0 001 010 110 */ + case 0x057: /* 0 001 010 111 */ + sprintf(buffer, "RLC R%01d,2",op&0x3); + break; + case 0x058: /* 0 001 011 000 */ + case 0x059: /* 0 001 011 001 */ + case 0x05a: /* 0 001 011 010 */ + case 0x05b: /* 0 001 011 011 */ + sprintf(buffer, "SLLC R%01d,1",op&0x3); + break; + case 0x05c: /* 0 001 011 100 */ + case 0x05d: /* 0 001 011 101 */ + case 0x05e: /* 0 001 011 110 */ + case 0x05f: /* 0 001 011 111 */ + sprintf(buffer, "SLLC R%01d,2",op&0x3); + break; + case 0x060: /* 0 001 100 000 */ + case 0x061: /* 0 001 100 001 */ + case 0x062: /* 0 001 100 010 */ + case 0x063: /* 0 001 100 011 */ + sprintf(buffer, "SLR R%01d,1",op&0x3); + break; + case 0x064: /* 0 001 100 100 */ + case 0x065: /* 0 001 100 101 */ + case 0x066: /* 0 001 100 110 */ + case 0x067: /* 0 001 100 111 */ + sprintf(buffer, "SLR R%01d,2",op&0x3); + break; + case 0x068: /* 0 001 101 000 */ + case 0x069: /* 0 001 101 001 */ + case 0x06a: /* 0 001 101 010 */ + case 0x06b: /* 0 001 101 011 */ + sprintf(buffer, "SAR R%01d,1",op&0x3); + break; + case 0x06c: /* 0 001 101 100 */ + case 0x06d: /* 0 001 101 101 */ + case 0x06e: /* 0 001 101 110 */ + case 0x06f: /* 0 001 101 111 */ + sprintf(buffer, "SAR R%01d,2",op&0x3); + break; + case 0x070: /* 0 001 110 000 */ + case 0x071: /* 0 001 110 001 */ + case 0x072: /* 0 001 110 010 */ + case 0x073: /* 0 001 110 011 */ + sprintf(buffer, "RRC R%01d,1",op&0x3); + break; + case 0x074: /* 0 001 110 100 */ + case 0x075: /* 0 001 110 101 */ + case 0x076: /* 0 001 110 110 */ + case 0x077: /* 0 001 110 111 */ + sprintf(buffer, "RRC R%01d,2",op&0x3); + break; + case 0x078: /* 0 001 111 000 */ + case 0x079: /* 0 001 111 001 */ + case 0x07a: /* 0 001 111 010 */ + case 0x07b: /* 0 001 111 011 */ + sprintf(buffer, "SARC R%01d,1",op&0x3); + break; + case 0x07c: /* 0 001 111 100 */ + case 0x07d: /* 0 001 111 101 */ + case 0x07e: /* 0 001 111 110 */ + case 0x07f: /* 0 001 111 111 */ + sprintf(buffer, "SARC R%01d,2",op&0x3); + break; + case 0x080: /* 0 010 000 000 */ + case 0x089: /* 0 010 001 001 */ + case 0x092: /* 0 010 010 010 */ + case 0x09b: /* 0 010 011 011 */ + case 0x0a4: /* 0 010 100 100 */ + case 0x0ad: /* 0 010 101 101 */ + case 0x0b6: /* 0 010 110 110 */ + case 0x0bf: /* 0 010 111 111 */ + sprintf(buffer, "TSTR R%01d",op&0x7); + break; + case 0x087: /* 0 010 000 111 */ + case 0x08f: /* 0 010 001 111 */ + case 0x097: /* 0 010 010 111 */ + case 0x09f: /* 0 010 011 111 */ + case 0x0a7: /* 0 010 100 111 */ + case 0x0af: /* 0 010 101 111 */ + case 0x0b7: /* 0 010 110 111 */ + sprintf(buffer, "JR R%01d",(op&0x38)>>3); + break; + case 0x081: /* 0 010 000 001 */ + case 0x082: /* 0 010 000 010 */ + case 0x083: /* 0 010 000 011 */ + case 0x084: /* 0 010 000 100 */ + case 0x085: /* 0 010 000 101 */ + case 0x086: /* 0 010 000 110 */ + case 0x088: /* 0 010 001 000 */ + case 0x08a: /* 0 010 001 010 */ + case 0x08b: /* 0 010 001 011 */ + case 0x08c: /* 0 010 001 100 */ + case 0x08d: /* 0 010 001 101 */ + case 0x08e: /* 0 010 001 110 */ + case 0x090: /* 0 010 010 000 */ + case 0x091: /* 0 010 010 001 */ + case 0x093: /* 0 010 010 011 */ + case 0x094: /* 0 010 010 100 */ + case 0x095: /* 0 010 010 101 */ + case 0x096: /* 0 010 010 110 */ + case 0x098: /* 0 010 011 000 */ + case 0x099: /* 0 010 011 001 */ + case 0x09a: /* 0 010 011 010 */ + case 0x09c: /* 0 010 011 100 */ + case 0x09d: /* 0 010 011 101 */ + case 0x09e: /* 0 010 011 110 */ + case 0x0a0: /* 0 010 100 000 */ + case 0x0a1: /* 0 010 100 001 */ + case 0x0a2: /* 0 010 100 010 */ + case 0x0a3: /* 0 010 100 011 */ + case 0x0a5: /* 0 010 100 101 */ + case 0x0a6: /* 0 010 100 110 */ + case 0x0a8: /* 0 010 101 000 */ + case 0x0a9: /* 0 010 101 001 */ + case 0x0aa: /* 0 010 101 010 */ + case 0x0ab: /* 0 010 101 011 */ + case 0x0ac: /* 0 010 101 100 */ + case 0x0ae: /* 0 010 101 110 */ + case 0x0b0: /* 0 010 110 000 */ + case 0x0b1: /* 0 010 110 001 */ + case 0x0b2: /* 0 010 110 010 */ + case 0x0b3: /* 0 010 110 011 */ + case 0x0b4: /* 0 010 110 100 */ + case 0x0b5: /* 0 010 110 101 */ + case 0x0b8: /* 0 010 111 000 */ + case 0x0b9: /* 0 010 111 001 */ + case 0x0ba: /* 0 010 111 010 */ + case 0x0bb: /* 0 010 111 011 */ + case 0x0bc: /* 0 010 111 100 */ + case 0x0bd: /* 0 010 111 101 */ + case 0x0be: /* 0 010 111 110 */ + sprintf(buffer, "MOVR R%01d,R%01d",(op&0x38)>>3,op&0x7); + break; + case 0x0c0: /* 0 011 000 000 */ + case 0x0c1: /* 0 011 000 001 */ + case 0x0c2: /* 0 011 000 010 */ + case 0x0c3: /* 0 011 000 011 */ + case 0x0c4: /* 0 011 000 100 */ + case 0x0c5: /* 0 011 000 101 */ + case 0x0c6: /* 0 011 000 110 */ + case 0x0c7: /* 0 011 000 111 */ + case 0x0c8: /* 0 011 001 000 */ + case 0x0c9: /* 0 011 001 001 */ + case 0x0ca: /* 0 011 001 010 */ + case 0x0cb: /* 0 011 001 011 */ + case 0x0cc: /* 0 011 001 100 */ + case 0x0cd: /* 0 011 001 101 */ + case 0x0ce: /* 0 011 001 110 */ + case 0x0cf: /* 0 011 001 111 */ + case 0x0d0: /* 0 011 010 000 */ + case 0x0d1: /* 0 011 010 001 */ + case 0x0d2: /* 0 011 010 010 */ + case 0x0d3: /* 0 011 010 011 */ + case 0x0d4: /* 0 011 010 100 */ + case 0x0d5: /* 0 011 010 101 */ + case 0x0d6: /* 0 011 010 110 */ + case 0x0d7: /* 0 011 010 111 */ + case 0x0d8: /* 0 011 011 000 */ + case 0x0d9: /* 0 011 011 001 */ + case 0x0da: /* 0 011 011 010 */ + case 0x0db: /* 0 011 011 011 */ + case 0x0dc: /* 0 011 011 100 */ + case 0x0dd: /* 0 011 011 101 */ + case 0x0de: /* 0 011 011 110 */ + case 0x0df: /* 0 011 011 111 */ + case 0x0e0: /* 0 011 100 000 */ + case 0x0e1: /* 0 011 100 001 */ + case 0x0e2: /* 0 011 100 010 */ + case 0x0e3: /* 0 011 100 011 */ + case 0x0e4: /* 0 011 100 100 */ + case 0x0e5: /* 0 011 100 101 */ + case 0x0e6: /* 0 011 100 110 */ + case 0x0e7: /* 0 011 100 111 */ + case 0x0e8: /* 0 011 101 000 */ + case 0x0e9: /* 0 011 101 001 */ + case 0x0ea: /* 0 011 101 010 */ + case 0x0eb: /* 0 011 101 011 */ + case 0x0ec: /* 0 011 101 100 */ + case 0x0ed: /* 0 011 101 101 */ + case 0x0ee: /* 0 011 101 110 */ + case 0x0ef: /* 0 011 101 111 */ + case 0x0f0: /* 0 011 110 000 */ + case 0x0f1: /* 0 011 110 001 */ + case 0x0f2: /* 0 011 110 010 */ + case 0x0f3: /* 0 011 110 011 */ + case 0x0f4: /* 0 011 110 100 */ + case 0x0f5: /* 0 011 110 101 */ + case 0x0f6: /* 0 011 110 110 */ + case 0x0f7: /* 0 011 110 111 */ + case 0x0f8: /* 0 011 111 000 */ + case 0x0f9: /* 0 011 111 001 */ + case 0x0fa: /* 0 011 111 010 */ + case 0x0fb: /* 0 011 111 011 */ + case 0x0fc: /* 0 011 111 100 */ + case 0x0fd: /* 0 011 111 101 */ + case 0x0fe: /* 0 011 111 110 */ + case 0x0ff: /* 0 011 111 111 */ + sprintf(buffer, "ADDR R%01d,R%01d",(op&0x38)>>3,op&7); + break; + case 0x100: /* 0 100 000 000 */ + case 0x101: /* 0 100 000 001 */ + case 0x102: /* 0 100 000 010 */ + case 0x103: /* 0 100 000 011 */ + case 0x104: /* 0 100 000 100 */ + case 0x105: /* 0 100 000 101 */ + case 0x106: /* 0 100 000 110 */ + case 0x107: /* 0 100 000 111 */ + case 0x108: /* 0 100 001 000 */ + case 0x109: /* 0 100 001 001 */ + case 0x10a: /* 0 100 001 010 */ + case 0x10b: /* 0 100 001 011 */ + case 0x10c: /* 0 100 001 100 */ + case 0x10d: /* 0 100 001 101 */ + case 0x10e: /* 0 100 001 110 */ + case 0x10f: /* 0 100 001 111 */ + case 0x110: /* 0 100 010 000 */ + case 0x111: /* 0 100 010 001 */ + case 0x112: /* 0 100 010 010 */ + case 0x113: /* 0 100 010 011 */ + case 0x114: /* 0 100 010 100 */ + case 0x115: /* 0 100 010 101 */ + case 0x116: /* 0 100 010 110 */ + case 0x117: /* 0 100 010 111 */ + case 0x118: /* 0 100 011 000 */ + case 0x119: /* 0 100 011 001 */ + case 0x11a: /* 0 100 011 010 */ + case 0x11b: /* 0 100 011 011 */ + case 0x11c: /* 0 100 011 100 */ + case 0x11d: /* 0 100 011 101 */ + case 0x11e: /* 0 100 011 110 */ + case 0x11f: /* 0 100 011 111 */ + case 0x120: /* 0 100 100 000 */ + case 0x121: /* 0 100 100 001 */ + case 0x122: /* 0 100 100 010 */ + case 0x123: /* 0 100 100 011 */ + case 0x124: /* 0 100 100 100 */ + case 0x125: /* 0 100 100 101 */ + case 0x126: /* 0 100 100 110 */ + case 0x127: /* 0 100 100 111 */ + case 0x128: /* 0 100 101 000 */ + case 0x129: /* 0 100 101 001 */ + case 0x12a: /* 0 100 101 010 */ + case 0x12b: /* 0 100 101 011 */ + case 0x12c: /* 0 100 101 100 */ + case 0x12d: /* 0 100 101 101 */ + case 0x12e: /* 0 100 101 110 */ + case 0x12f: /* 0 100 101 111 */ + case 0x130: /* 0 100 110 000 */ + case 0x131: /* 0 100 110 001 */ + case 0x132: /* 0 100 110 010 */ + case 0x133: /* 0 100 110 011 */ + case 0x134: /* 0 100 110 100 */ + case 0x135: /* 0 100 110 101 */ + case 0x136: /* 0 100 110 110 */ + case 0x137: /* 0 100 110 111 */ + case 0x138: /* 0 100 111 000 */ + case 0x139: /* 0 100 111 001 */ + case 0x13a: /* 0 100 111 010 */ + case 0x13b: /* 0 100 111 011 */ + case 0x13c: /* 0 100 111 100 */ + case 0x13d: /* 0 100 111 101 */ + case 0x13e: /* 0 100 111 110 */ + case 0x13f: /* 0 100 111 111 */ + sprintf(buffer, "SUBR R%01d,R%01d",(op&0x38)>>3,op&7); + break; + case 0x140: /* 0 101 000 000 */ + case 0x141: /* 0 101 000 001 */ + case 0x142: /* 0 101 000 010 */ + case 0x143: /* 0 101 000 011 */ + case 0x144: /* 0 101 000 100 */ + case 0x145: /* 0 101 000 101 */ + case 0x146: /* 0 101 000 110 */ + case 0x147: /* 0 101 000 111 */ + case 0x148: /* 0 101 001 000 */ + case 0x149: /* 0 101 001 001 */ + case 0x14a: /* 0 101 001 010 */ + case 0x14b: /* 0 101 001 011 */ + case 0x14c: /* 0 101 001 100 */ + case 0x14d: /* 0 101 001 101 */ + case 0x14e: /* 0 101 001 110 */ + case 0x14f: /* 0 101 001 111 */ + case 0x150: /* 0 101 010 000 */ + case 0x151: /* 0 101 010 001 */ + case 0x152: /* 0 101 010 010 */ + case 0x153: /* 0 101 010 011 */ + case 0x154: /* 0 101 010 100 */ + case 0x155: /* 0 101 010 101 */ + case 0x156: /* 0 101 010 110 */ + case 0x157: /* 0 101 010 111 */ + case 0x158: /* 0 101 011 000 */ + case 0x159: /* 0 101 011 001 */ + case 0x15a: /* 0 101 011 010 */ + case 0x15b: /* 0 101 011 011 */ + case 0x15c: /* 0 101 011 100 */ + case 0x15d: /* 0 101 011 101 */ + case 0x15e: /* 0 101 011 110 */ + case 0x15f: /* 0 101 011 111 */ + case 0x160: /* 0 101 100 000 */ + case 0x161: /* 0 101 100 001 */ + case 0x162: /* 0 101 100 010 */ + case 0x163: /* 0 101 100 011 */ + case 0x164: /* 0 101 100 100 */ + case 0x165: /* 0 101 100 101 */ + case 0x166: /* 0 101 100 110 */ + case 0x167: /* 0 101 100 111 */ + case 0x168: /* 0 101 101 000 */ + case 0x169: /* 0 101 101 001 */ + case 0x16a: /* 0 101 101 010 */ + case 0x16b: /* 0 101 101 011 */ + case 0x16c: /* 0 101 101 100 */ + case 0x16d: /* 0 101 101 101 */ + case 0x16e: /* 0 101 101 110 */ + case 0x16f: /* 0 101 101 111 */ + case 0x170: /* 0 101 110 000 */ + case 0x171: /* 0 101 110 001 */ + case 0x172: /* 0 101 110 010 */ + case 0x173: /* 0 101 110 011 */ + case 0x174: /* 0 101 110 100 */ + case 0x175: /* 0 101 110 101 */ + case 0x176: /* 0 101 110 110 */ + case 0x177: /* 0 101 110 111 */ + case 0x178: /* 0 101 111 000 */ + case 0x179: /* 0 101 111 001 */ + case 0x17a: /* 0 101 111 010 */ + case 0x17b: /* 0 101 111 011 */ + case 0x17c: /* 0 101 111 100 */ + case 0x17d: /* 0 101 111 101 */ + case 0x17e: /* 0 101 111 110 */ + case 0x17f: /* 0 101 111 111 */ + sprintf(buffer, "CMPR R%01d,R%01d",(op&0x38)>>3,op&7); + break; + case 0x180: /* 0 110 000 000 */ + case 0x181: /* 0 110 000 001 */ + case 0x182: /* 0 110 000 010 */ + case 0x183: /* 0 110 000 011 */ + case 0x184: /* 0 110 000 100 */ + case 0x185: /* 0 110 000 101 */ + case 0x186: /* 0 110 000 110 */ + case 0x187: /* 0 110 000 111 */ + case 0x188: /* 0 110 001 000 */ + case 0x189: /* 0 110 001 001 */ + case 0x18a: /* 0 110 001 010 */ + case 0x18b: /* 0 110 001 011 */ + case 0x18c: /* 0 110 001 100 */ + case 0x18d: /* 0 110 001 101 */ + case 0x18e: /* 0 110 001 110 */ + case 0x18f: /* 0 110 001 111 */ + case 0x190: /* 0 110 010 000 */ + case 0x191: /* 0 110 010 001 */ + case 0x192: /* 0 110 010 010 */ + case 0x193: /* 0 110 010 011 */ + case 0x194: /* 0 110 010 100 */ + case 0x195: /* 0 110 010 101 */ + case 0x196: /* 0 110 010 110 */ + case 0x197: /* 0 110 010 111 */ + case 0x198: /* 0 110 011 000 */ + case 0x199: /* 0 110 011 001 */ + case 0x19a: /* 0 110 011 010 */ + case 0x19b: /* 0 110 011 011 */ + case 0x19c: /* 0 110 011 100 */ + case 0x19d: /* 0 110 011 101 */ + case 0x19e: /* 0 110 011 110 */ + case 0x19f: /* 0 110 011 111 */ + case 0x1a0: /* 0 110 100 000 */ + case 0x1a1: /* 0 110 100 001 */ + case 0x1a2: /* 0 110 100 010 */ + case 0x1a3: /* 0 110 100 011 */ + case 0x1a4: /* 0 110 100 100 */ + case 0x1a5: /* 0 110 100 101 */ + case 0x1a6: /* 0 110 100 110 */ + case 0x1a7: /* 0 110 100 111 */ + case 0x1a8: /* 0 110 101 000 */ + case 0x1a9: /* 0 110 101 001 */ + case 0x1aa: /* 0 110 101 010 */ + case 0x1ab: /* 0 110 101 011 */ + case 0x1ac: /* 0 110 101 100 */ + case 0x1ad: /* 0 110 101 101 */ + case 0x1ae: /* 0 110 101 110 */ + case 0x1af: /* 0 110 101 111 */ + case 0x1b0: /* 0 110 110 000 */ + case 0x1b1: /* 0 110 110 001 */ + case 0x1b2: /* 0 110 110 010 */ + case 0x1b3: /* 0 110 110 011 */ + case 0x1b4: /* 0 110 110 100 */ + case 0x1b5: /* 0 110 110 101 */ + case 0x1b6: /* 0 110 110 110 */ + case 0x1b7: /* 0 110 110 111 */ + case 0x1b8: /* 0 110 111 000 */ + case 0x1b9: /* 0 110 111 001 */ + case 0x1ba: /* 0 110 111 010 */ + case 0x1bb: /* 0 110 111 011 */ + case 0x1bc: /* 0 110 111 100 */ + case 0x1bd: /* 0 110 111 101 */ + case 0x1be: /* 0 110 111 110 */ + case 0x1bf: /* 0 110 111 111 */ + sprintf(buffer, "ANDR R%01d,R%01d",(op&0x38)>>3,op&7); + break; + case 0x1c0: /* 0 111 000 000 */ + case 0x1c9: /* 0 111 001 001 */ + case 0x1d2: /* 0 111 010 010 */ + case 0x1db: /* 0 111 011 011 */ + case 0x1e4: /* 0 111 100 100 */ + case 0x1ed: /* 0 111 101 101 */ + case 0x1f6: /* 0 111 110 110 */ + case 0x1ff: /* 0 111 111 111 */ + sprintf(buffer, "CLRR R%01d",op&7); + break; + case 0x1c1: /* 0 111 000 001 */ + case 0x1c2: /* 0 111 000 010 */ + case 0x1c3: /* 0 111 000 011 */ + case 0x1c4: /* 0 111 000 100 */ + case 0x1c5: /* 0 111 000 101 */ + case 0x1c6: /* 0 111 000 110 */ + case 0x1c7: /* 0 111 000 111 */ + case 0x1c8: /* 0 111 001 000 */ + case 0x1ca: /* 0 111 001 010 */ + case 0x1cb: /* 0 111 001 011 */ + case 0x1cc: /* 0 111 001 100 */ + case 0x1cd: /* 0 111 001 101 */ + case 0x1ce: /* 0 111 001 110 */ + case 0x1cf: /* 0 111 001 111 */ + case 0x1d0: /* 0 111 010 000 */ + case 0x1d1: /* 0 111 010 001 */ + case 0x1d3: /* 0 111 010 011 */ + case 0x1d4: /* 0 111 010 100 */ + case 0x1d5: /* 0 111 010 101 */ + case 0x1d6: /* 0 111 010 110 */ + case 0x1d7: /* 0 111 010 111 */ + case 0x1d8: /* 0 111 011 000 */ + case 0x1d9: /* 0 111 011 001 */ + case 0x1da: /* 0 111 011 010 */ + case 0x1dc: /* 0 111 011 100 */ + case 0x1dd: /* 0 111 011 101 */ + case 0x1de: /* 0 111 011 110 */ + case 0x1df: /* 0 111 011 111 */ + case 0x1e0: /* 0 111 100 000 */ + case 0x1e1: /* 0 111 100 001 */ + case 0x1e2: /* 0 111 100 010 */ + case 0x1e3: /* 0 111 100 011 */ + case 0x1e5: /* 0 111 100 101 */ + case 0x1e6: /* 0 111 100 110 */ + case 0x1e7: /* 0 111 100 111 */ + case 0x1e8: /* 0 111 101 000 */ + case 0x1e9: /* 0 111 101 001 */ + case 0x1ea: /* 0 111 101 010 */ + case 0x1eb: /* 0 111 101 011 */ + case 0x1ec: /* 0 111 101 100 */ + case 0x1ee: /* 0 111 101 110 */ + case 0x1ef: /* 0 111 101 111 */ + case 0x1f0: /* 0 111 110 000 */ + case 0x1f1: /* 0 111 110 001 */ + case 0x1f2: /* 0 111 110 010 */ + case 0x1f3: /* 0 111 110 011 */ + case 0x1f4: /* 0 111 110 100 */ + case 0x1f5: /* 0 111 110 101 */ + case 0x1f7: /* 0 111 110 111 */ + case 0x1f8: /* 0 111 111 000 */ + case 0x1f9: /* 0 111 111 001 */ + case 0x1fa: /* 0 111 111 010 */ + case 0x1fb: /* 0 111 111 011 */ + case 0x1fc: /* 0 111 111 100 */ + case 0x1fd: /* 0 111 111 101 */ + case 0x1fe: /* 0 111 111 110 */ + sprintf(buffer, "XORR R%01d,R%01d",(op&0x38)>>3,op&7); + break; + case 0x200: /* 1 000 000 000 */ + size += 1; + ea = oprom16[1]; + sprintf(buffer, "B %04X",pc+2+ea); + break; + case 0x201: /* 1 000 000 001 */ + size += 1; + ea = oprom16[1]; + sprintf(buffer, "BC %04X",pc+2+ea); + break; + case 0x202: /* 1 000 000 010 */ + size += 1; + ea = oprom16[1]; + sprintf(buffer, "BOV %04X",pc+2+ea); + break; + case 0x203: /* 1 000 000 011 */ + size += 1; + ea = oprom16[1]; + sprintf(buffer, "BPL %04X",pc+2+ea); + break; + case 0x204: /* 1 000 000 100 */ + size += 1; + ea = oprom16[1]; + sprintf(buffer, "BZE %04X",pc+2+ea); + break; + case 0x205: /* 1 000 000 101 */ + size += 1; + ea = oprom16[1]; + sprintf(buffer, "BLT %04X",pc+2+ea); + break; + case 0x206: /* 1 000 000 110 */ + size += 1; + ea = oprom16[1]; + sprintf(buffer, "BLE %04X",pc+2+ea); + break; + case 0x207: /* 1 000 000 111 */ + size += 1; + ea = oprom16[1]; + sprintf(buffer, "BUSC %04X",pc+2+ea); + break; + case 0x208: /* 1 000 001 000 */ + size += 1; + ea = oprom16[1]; + sprintf(buffer, "NOPP %04X",pc+2+ea); + break; + case 0x209: /* 1 000 001 001 */ + size += 1; + ea = oprom16[1]; + sprintf(buffer, "BNC %04X",pc+2+ea); + break; + case 0x20a: /* 1 000 001 010 */ + size += 1; + ea = oprom16[1]; + sprintf(buffer, "BNOV %04X",pc+2+ea); + break; + case 0x20b: /* 1 000 001 011 */ + size += 1; + ea = oprom16[1]; + sprintf(buffer, "BMI %04X",pc+2+ea); + break; + case 0x20c: /* 1 000 001 100 */ + size += 1; + ea = oprom16[1]; + sprintf(buffer, "BNZE %04X",pc+2+ea); + break; + case 0x20d: /* 1 000 001 101 */ + size += 1; + ea = oprom16[1]; + sprintf(buffer, "BGE %04X",pc+2+ea); + break; + case 0x20e: /* 1 000 001 110 */ + size += 1; + ea = oprom16[1]; + sprintf(buffer, "BGT %04X",pc+2+ea); + break; + case 0x20f: /* 1 000 001 111 */ + size += 1; + ea = oprom16[1]; + sprintf(buffer, "BESC %04X",pc+2+ea); + break; + case 0x210: /* 1 000 010 000 */ + case 0x211: /* 1 000 010 001 */ + case 0x212: /* 1 000 010 010 */ + case 0x213: /* 1 000 010 011 */ + case 0x214: /* 1 000 010 100 */ + case 0x215: /* 1 000 010 101 */ + case 0x216: /* 1 000 010 110 */ + case 0x217: /* 1 000 010 111 */ + case 0x218: /* 1 000 011 000 */ + case 0x219: /* 1 000 011 001 */ + case 0x21a: /* 1 000 011 010 */ + case 0x21b: /* 1 000 011 011 */ + case 0x21c: /* 1 000 011 100 */ + case 0x21d: /* 1 000 011 101 */ + case 0x21e: /* 1 000 011 110 */ + case 0x21f: /* 1 000 011 111 */ + size += 1; + ea = oprom16[1]; + sprintf(buffer, "BEXT %04X,%01X",pc+2+ea,op&0x0f); + break; + case 0x220: /* 1 000 100 000 */ + size += 1; + ea = oprom16[1]; + sprintf(buffer, "B %04X",pc+1-ea); + break; + case 0x221: /* 1 000 100 001 */ + size += 1; + ea = oprom16[1]; + sprintf(buffer, "BC %04X",pc+1-ea); + break; + case 0x222: /* 1 000 100 010 */ + size += 1; + ea = oprom16[1]; + sprintf(buffer, "BOV %04X",pc+1-ea); + break; + case 0x223: /* 1 000 100 011 */ + size += 1; + ea = oprom16[1]; + sprintf(buffer, "BPL %04X",pc+1-ea); + break; + case 0x224: /* 1 000 100 100 */ + size += 1; + ea = oprom16[1]; + sprintf(buffer, "BZE %04X",pc+1-ea); + break; + case 0x225: /* 1 000 100 101 */ + size += 1; + ea = oprom16[1]; + sprintf(buffer, "BLT %04X",pc+1-ea); + break; + case 0x226: /* 1 000 100 110 */ + size += 1; + ea = oprom16[1]; + sprintf(buffer, "BLE %04X",pc+1-ea); + break; + case 0x227: /* 1 000 100 111 */ + size += 1; + ea = oprom16[1]; + sprintf(buffer, "BUSC %04X",pc+1-ea); + break; + case 0x228: /* 1 000 101 000 */ + size += 1; + ea = oprom16[1]; + sprintf(buffer, "NOPP %04X",pc+1-ea); + break; + case 0x229: /* 1 000 101 001 */ + size += 1; + ea = oprom16[1]; + sprintf(buffer, "BNC %04X",pc+1-ea); + break; + case 0x22a: /* 1 000 101 010 */ + size += 1; + ea = oprom16[1]; + sprintf(buffer, "BNOV %04X",pc+1-ea); + break; + case 0x22b: /* 1 000 101 011 */ + size += 1; + ea = oprom16[1]; + sprintf(buffer, "BMI %04X",pc+1-ea); + break; + case 0x22c: /* 1 000 101 100 */ + size += 1; + ea = oprom16[1]; + sprintf(buffer, "BNZE %04X",pc+1-ea); + break; + case 0x22d: /* 1 000 101 101 */ + size += 1; + ea = oprom16[1]; + sprintf(buffer, "BGE %04X",pc+1-ea); + break; + case 0x22e: /* 1 000 101 110 */ + size += 1; + ea = oprom16[1]; + sprintf(buffer, "BGT %04X",pc+1-ea); + break; + case 0x22f: /* 1 000 101 111 */ + size += 1; + ea = oprom16[1]; + sprintf(buffer, "BESC %04X",pc+1-ea); + break; + case 0x230: /* 1 000 110 000 */ + case 0x231: /* 1 000 110 001 */ + case 0x232: /* 1 000 110 010 */ + case 0x233: /* 1 000 110 011 */ + case 0x234: /* 1 000 110 100 */ + case 0x235: /* 1 000 110 101 */ + case 0x236: /* 1 000 110 110 */ + case 0x237: /* 1 000 110 111 */ + case 0x238: /* 1 000 111 000 */ + case 0x239: /* 1 000 111 001 */ + case 0x23a: /* 1 000 111 010 */ + case 0x23b: /* 1 000 111 011 */ + case 0x23c: /* 1 000 111 100 */ + case 0x23d: /* 1 000 111 101 */ + case 0x23e: /* 1 000 111 110 */ + case 0x23f: /* 1 000 111 111 */ + size += 1; + ea = oprom16[1]; + sprintf(buffer, "BEXT %04X,%01X",pc+1-ea,op&0x0f); + break; + case 0x240: /* 1 001 000 000 */ + case 0x241: /* 1 001 000 001 */ + case 0x242: /* 1 001 000 010 */ + case 0x243: /* 1 001 000 011 */ + case 0x244: /* 1 001 000 100 */ + case 0x245: /* 1 001 000 101 */ + case 0x246: /* 1 001 000 110 */ + case 0x247: /* 1 001 000 111 */ + size += 1; + ea = oprom16[1]; + sprintf(buffer, "MVO R%01d,(%04X)",op&0x7,ea); + break; + case 0x248: /* 1 001 001 000 */ + case 0x249: /* 1 001 001 001 */ + case 0x24a: /* 1 001 001 010 */ + case 0x24b: /* 1 001 001 011 */ + case 0x24c: /* 1 001 001 100 */ + case 0x24d: /* 1 001 001 101 */ + case 0x24e: /* 1 001 001 110 */ + case 0x24f: /* 1 001 001 111 */ + case 0x250: /* 1 001 010 000 */ + case 0x251: /* 1 001 010 001 */ + case 0x252: /* 1 001 010 010 */ + case 0x253: /* 1 001 010 011 */ + case 0x254: /* 1 001 010 100 */ + case 0x255: /* 1 001 010 101 */ + case 0x256: /* 1 001 010 110 */ + case 0x257: /* 1 001 010 111 */ + case 0x258: /* 1 001 011 000 */ + case 0x259: /* 1 001 011 001 */ + case 0x25a: /* 1 001 011 010 */ + case 0x25b: /* 1 001 011 011 */ + case 0x25c: /* 1 001 011 100 */ + case 0x25d: /* 1 001 011 101 */ + case 0x25e: /* 1 001 011 110 */ + case 0x25f: /* 1 001 011 111 */ + case 0x260: /* 1 001 100 000 */ + case 0x261: /* 1 001 100 001 */ + case 0x262: /* 1 001 100 010 */ + case 0x263: /* 1 001 100 011 */ + case 0x264: /* 1 001 100 100 */ + case 0x265: /* 1 001 100 101 */ + case 0x266: /* 1 001 100 110 */ + case 0x267: /* 1 001 100 111 */ + case 0x268: /* 1 001 101 000 */ + case 0x269: /* 1 001 101 001 */ + case 0x26a: /* 1 001 101 010 */ + case 0x26b: /* 1 001 101 011 */ + case 0x26c: /* 1 001 101 100 */ + case 0x26d: /* 1 001 101 101 */ + case 0x26e: /* 1 001 101 110 */ + case 0x26f: /* 1 001 101 111 */ + sprintf(buffer, "MVO@ R%01d,(R%01d)",op&0x7,(op&0x38)>>3); + break; + case 0x270: /* 1 001 110 000 */ + case 0x271: /* 1 001 110 001 */ + case 0x272: /* 1 001 110 010 */ + case 0x273: /* 1 001 110 011 */ + case 0x274: /* 1 001 110 100 */ + case 0x275: /* 1 001 110 101 */ + case 0x276: /* 1 001 110 110 */ + case 0x277: /* 1 001 110 111 */ + sprintf(buffer, "PSHR R%01d",op&0x7); + break; + case 0x278: /* 1 001 111 000 */ + case 0x279: /* 1 001 111 001 */ + case 0x27a: /* 1 001 111 010 */ + case 0x27b: /* 1 001 111 011 */ + case 0x27c: /* 1 001 111 100 */ + case 0x27d: /* 1 001 111 101 */ + case 0x27e: /* 1 001 111 110 */ + case 0x27f: /* 1 001 111 111 */ + size += 1; + sprintf(buffer, "MVOI R%01d,(%04X)",op&0x7,pc+1); + break; + case 0x280: /* 1 010 000 000 */ + case 0x281: /* 1 010 000 001 */ + case 0x282: /* 1 010 000 010 */ + case 0x283: /* 1 010 000 011 */ + case 0x284: /* 1 010 000 100 */ + case 0x285: /* 1 010 000 101 */ + case 0x286: /* 1 010 000 110 */ + case 0x287: /* 1 010 000 111 */ + size += 1; + ea = oprom16[1]; + sprintf(buffer, "MVI (%04X),R%01d",ea,op&0x7); + break; + case 0x288: /* 1 010 001 000 */ + case 0x289: /* 1 010 001 001 */ + case 0x28a: /* 1 010 001 010 */ + case 0x28b: /* 1 010 001 011 */ + case 0x28c: /* 1 010 001 100 */ + case 0x28d: /* 1 010 001 101 */ + case 0x28e: /* 1 010 001 110 */ + case 0x28f: /* 1 010 001 111 */ + case 0x290: /* 1 010 010 000 */ + case 0x291: /* 1 010 010 001 */ + case 0x292: /* 1 010 010 010 */ + case 0x293: /* 1 010 010 011 */ + case 0x294: /* 1 010 010 100 */ + case 0x295: /* 1 010 010 101 */ + case 0x296: /* 1 010 010 110 */ + case 0x297: /* 1 010 010 111 */ + case 0x298: /* 1 010 011 000 */ + case 0x299: /* 1 010 011 001 */ + case 0x29a: /* 1 010 011 010 */ + case 0x29b: /* 1 010 011 011 */ + case 0x29c: /* 1 010 011 100 */ + case 0x29d: /* 1 010 011 101 */ + case 0x29e: /* 1 010 011 110 */ + case 0x29f: /* 1 010 011 111 */ + case 0x2a0: /* 1 010 100 000 */ + case 0x2a1: /* 1 010 100 001 */ + case 0x2a2: /* 1 010 100 010 */ + case 0x2a3: /* 1 010 100 011 */ + case 0x2a4: /* 1 010 100 100 */ + case 0x2a5: /* 1 010 100 101 */ + case 0x2a6: /* 1 010 100 110 */ + case 0x2a7: /* 1 010 100 111 */ + case 0x2a8: /* 1 010 101 000 */ + case 0x2a9: /* 1 010 101 001 */ + case 0x2aa: /* 1 010 101 010 */ + case 0x2ab: /* 1 010 101 011 */ + case 0x2ac: /* 1 010 101 100 */ + case 0x2ad: /* 1 010 101 101 */ + case 0x2ae: /* 1 010 101 110 */ + case 0x2af: /* 1 010 101 111 */ + sprintf(buffer, "MVI@ (R%01d),R%01d",(op&0x38)>>3,op&0x7); + break; + case 0x2b0: /* 1 010 110 000 */ + case 0x2b1: /* 1 010 110 001 */ + case 0x2b2: /* 1 010 110 010 */ + case 0x2b3: /* 1 010 110 011 */ + case 0x2b4: /* 1 010 110 100 */ + case 0x2b5: /* 1 010 110 101 */ + case 0x2b6: /* 1 010 110 110 */ + case 0x2b7: /* 1 010 110 111 */ + sprintf(buffer, "PULR R%01d",op&0x7); + break; + case 0x2b8: /* 1 010 111 000 */ + case 0x2b9: /* 1 010 111 001 */ + case 0x2ba: /* 1 010 111 010 */ + case 0x2bb: /* 1 010 111 011 */ + case 0x2bc: /* 1 010 111 100 */ + case 0x2bd: /* 1 010 111 101 */ + case 0x2be: /* 1 010 111 110 */ + case 0x2bf: /* 1 010 111 111 */ + size += 1; + ea = oprom16[1]; + sprintf(buffer, "MVII #%04X,R%01d",ea,op&0x7); + break; + case 0x2c0: /* 1 011 010 000 */ + case 0x2c1: /* 1 011 010 001 */ + case 0x2c2: /* 1 011 010 010 */ + case 0x2c3: /* 1 011 010 011 */ + case 0x2c4: /* 1 011 010 100 */ + case 0x2c5: /* 1 011 010 101 */ + case 0x2c6: /* 1 011 010 110 */ + case 0x2c7: /* 1 011 010 111 */ + size += 1; + ea = oprom16[1]; + sprintf(buffer, "ADD (%04X),R%01d",ea,op&0x7); + break; + case 0x2c8: /* 1 011 001 000 */ + case 0x2c9: /* 1 011 001 001 */ + case 0x2ca: /* 1 011 001 010 */ + case 0x2cb: /* 1 011 001 011 */ + case 0x2cc: /* 1 011 001 100 */ + case 0x2cd: /* 1 011 001 101 */ + case 0x2ce: /* 1 011 001 110 */ + case 0x2cf: /* 1 011 001 111 */ + case 0x2d0: /* 1 011 010 000 */ + case 0x2d1: /* 1 011 010 001 */ + case 0x2d2: /* 1 011 010 010 */ + case 0x2d3: /* 1 011 010 011 */ + case 0x2d4: /* 1 011 010 100 */ + case 0x2d5: /* 1 011 010 101 */ + case 0x2d6: /* 1 011 010 110 */ + case 0x2d7: /* 1 011 010 111 */ + case 0x2d8: /* 1 011 011 000 */ + case 0x2d9: /* 1 011 011 001 */ + case 0x2da: /* 1 011 011 010 */ + case 0x2db: /* 1 011 011 011 */ + case 0x2dc: /* 1 011 011 100 */ + case 0x2dd: /* 1 011 011 101 */ + case 0x2de: /* 1 011 011 110 */ + case 0x2df: /* 1 011 011 111 */ + case 0x2e0: /* 1 011 100 000 */ + case 0x2e1: /* 1 011 100 001 */ + case 0x2e2: /* 1 011 100 010 */ + case 0x2e3: /* 1 011 100 011 */ + case 0x2e4: /* 1 011 100 100 */ + case 0x2e5: /* 1 011 100 101 */ + case 0x2e6: /* 1 011 100 110 */ + case 0x2e7: /* 1 011 100 111 */ + case 0x2e8: /* 1 011 101 000 */ + case 0x2e9: /* 1 011 101 001 */ + case 0x2ea: /* 1 011 101 010 */ + case 0x2eb: /* 1 011 101 011 */ + case 0x2ec: /* 1 011 101 100 */ + case 0x2ed: /* 1 011 101 101 */ + case 0x2ee: /* 1 011 101 110 */ + case 0x2ef: /* 1 011 101 111 */ + case 0x2f0: /* 1 011 110 000 */ + case 0x2f1: /* 1 011 110 001 */ + case 0x2f2: /* 1 011 110 010 */ + case 0x2f3: /* 1 011 110 011 */ + case 0x2f4: /* 1 011 110 100 */ + case 0x2f5: /* 1 011 110 101 */ + case 0x2f6: /* 1 011 110 110 */ + case 0x2f7: /* 1 011 110 111 */ + sprintf(buffer, "ADD@ (R%01d),R%01d",(op&0x38)>>3,op&0x7); + break; + case 0x2f8: /* 1 011 111 000 */ + case 0x2f9: /* 1 011 111 001 */ + case 0x2fa: /* 1 011 111 010 */ + case 0x2fb: /* 1 011 111 011 */ + case 0x2fc: /* 1 011 111 100 */ + case 0x2fd: /* 1 011 111 101 */ + case 0x2fe: /* 1 011 111 110 */ + case 0x2ff: /* 1 011 111 111 */ + size += 1; + ea = oprom16[1]; + sprintf(buffer, "ADDI #%04X,R%01d",ea,op&0x7); + break; + case 0x300: /* 1 100 000 000 */ + case 0x301: /* 1 100 000 001 */ + case 0x302: /* 1 100 000 010 */ + case 0x303: /* 1 100 000 011 */ + case 0x304: /* 1 100 000 100 */ + case 0x305: /* 1 100 000 101 */ + case 0x306: /* 1 100 000 110 */ + case 0x307: /* 1 100 000 111 */ + size += 1; + ea = oprom16[1]; + sprintf(buffer, "SUB (%04X),R%01d",ea,op&0x7); + break; + case 0x308: /* 1 100 001 000 */ + case 0x309: /* 1 100 001 001 */ + case 0x30a: /* 1 100 001 010 */ + case 0x30b: /* 1 100 001 011 */ + case 0x30c: /* 1 100 001 100 */ + case 0x30d: /* 1 100 001 101 */ + case 0x30e: /* 1 100 001 110 */ + case 0x30f: /* 1 100 001 111 */ + case 0x310: /* 1 100 010 000 */ + case 0x311: /* 1 100 010 001 */ + case 0x312: /* 1 100 010 010 */ + case 0x313: /* 1 100 010 011 */ + case 0x314: /* 1 100 010 100 */ + case 0x315: /* 1 100 010 101 */ + case 0x316: /* 1 100 010 110 */ + case 0x317: /* 1 100 010 111 */ + case 0x318: /* 1 100 011 000 */ + case 0x319: /* 1 100 011 001 */ + case 0x31a: /* 1 100 011 010 */ + case 0x31b: /* 1 100 011 011 */ + case 0x31c: /* 1 100 011 100 */ + case 0x31d: /* 1 100 011 101 */ + case 0x31e: /* 1 100 011 110 */ + case 0x31f: /* 1 100 011 111 */ + case 0x320: /* 1 100 100 000 */ + case 0x321: /* 1 100 100 001 */ + case 0x322: /* 1 100 100 010 */ + case 0x323: /* 1 100 100 011 */ + case 0x324: /* 1 100 100 100 */ + case 0x325: /* 1 100 100 101 */ + case 0x326: /* 1 100 100 110 */ + case 0x327: /* 1 100 100 111 */ + case 0x328: /* 1 100 101 000 */ + case 0x329: /* 1 100 101 001 */ + case 0x32a: /* 1 100 101 010 */ + case 0x32b: /* 1 100 101 011 */ + case 0x32c: /* 1 100 101 100 */ + case 0x32d: /* 1 100 101 101 */ + case 0x32e: /* 1 100 101 110 */ + case 0x32f: /* 1 100 101 111 */ + case 0x330: /* 1 100 110 000 */ + case 0x331: /* 1 100 110 001 */ + case 0x332: /* 1 100 110 010 */ + case 0x333: /* 1 100 110 011 */ + case 0x334: /* 1 100 110 100 */ + case 0x335: /* 1 100 110 101 */ + case 0x336: /* 1 100 110 110 */ + case 0x337: /* 1 100 110 111 */ + sprintf(buffer, "SUB@ (R%01d),R%01d",(op&0x38)>>3,op&0x7); + break; + case 0x338: /* 1 100 111 000 */ + case 0x339: /* 1 100 111 001 */ + case 0x33a: /* 1 100 111 010 */ + case 0x33b: /* 1 100 111 011 */ + case 0x33c: /* 1 100 111 100 */ + case 0x33d: /* 1 100 111 101 */ + case 0x33e: /* 1 100 111 110 */ + case 0x33f: /* 1 100 111 111 */ + size += 1; + ea = oprom16[1]; + sprintf(buffer, "SUBI #%04X,R%01d",ea,op&0x7); + break; + case 0x340: /* 1 101 000 000 */ + case 0x341: /* 1 101 000 001 */ + case 0x342: /* 1 101 000 010 */ + case 0x343: /* 1 101 000 011 */ + case 0x344: /* 1 101 000 100 */ + case 0x345: /* 1 101 000 101 */ + case 0x346: /* 1 101 000 110 */ + case 0x347: /* 1 101 000 111 */ + size += 1; + ea = oprom16[1]; + sprintf(buffer, "CMP (%04X),R%01d",ea,op&0x7); + break; + case 0x348: /* 1 101 001 000 */ + case 0x349: /* 1 101 001 001 */ + case 0x34a: /* 1 101 001 010 */ + case 0x34b: /* 1 101 001 011 */ + case 0x34c: /* 1 101 001 100 */ + case 0x34d: /* 1 101 001 101 */ + case 0x34e: /* 1 101 001 110 */ + case 0x34f: /* 1 101 001 111 */ + case 0x350: /* 1 101 010 000 */ + case 0x351: /* 1 101 010 001 */ + case 0x352: /* 1 101 010 010 */ + case 0x353: /* 1 101 010 011 */ + case 0x354: /* 1 101 010 100 */ + case 0x355: /* 1 101 010 101 */ + case 0x356: /* 1 101 010 110 */ + case 0x357: /* 1 101 010 111 */ + case 0x358: /* 1 101 011 000 */ + case 0x359: /* 1 101 011 001 */ + case 0x35a: /* 1 101 011 010 */ + case 0x35b: /* 1 101 011 011 */ + case 0x35c: /* 1 101 011 100 */ + case 0x35d: /* 1 101 011 101 */ + case 0x35e: /* 1 101 011 110 */ + case 0x35f: /* 1 101 011 111 */ + case 0x360: /* 1 101 100 000 */ + case 0x361: /* 1 101 100 001 */ + case 0x362: /* 1 101 100 010 */ + case 0x363: /* 1 101 100 011 */ + case 0x364: /* 1 101 100 100 */ + case 0x365: /* 1 101 100 101 */ + case 0x366: /* 1 101 100 110 */ + case 0x367: /* 1 101 100 111 */ + case 0x368: /* 1 101 101 000 */ + case 0x369: /* 1 101 101 001 */ + case 0x36a: /* 1 101 101 010 */ + case 0x36b: /* 1 101 101 011 */ + case 0x36c: /* 1 101 101 100 */ + case 0x36d: /* 1 101 101 101 */ + case 0x36e: /* 1 101 101 110 */ + case 0x36f: /* 1 101 101 111 */ + case 0x370: /* 1 101 110 000 */ + case 0x371: /* 1 101 110 001 */ + case 0x372: /* 1 101 110 010 */ + case 0x373: /* 1 101 110 011 */ + case 0x374: /* 1 101 110 100 */ + case 0x375: /* 1 101 110 101 */ + case 0x376: /* 1 101 110 110 */ + case 0x377: /* 1 101 110 111 */ + sprintf(buffer, "CMP@ (R%01d),R%01d",(op&0x38)>>3,op&0x7); + break; + case 0x378: /* 1 101 111 000 */ + case 0x379: /* 1 101 111 001 */ + case 0x37a: /* 1 101 111 010 */ + case 0x37b: /* 1 101 111 011 */ + case 0x37c: /* 1 101 111 100 */ + case 0x37d: /* 1 101 111 101 */ + case 0x37e: /* 1 101 111 110 */ + case 0x37f: /* 1 101 111 111 */ + size += 1; + ea = oprom16[1]; + sprintf(buffer, "CMPI #%04X,R%01d",ea,op&0x7); + break; + case 0x380: /* 1 110 000 000 */ + case 0x381: /* 1 110 000 001 */ + case 0x382: /* 1 110 000 010 */ + case 0x383: /* 1 110 000 011 */ + case 0x384: /* 1 110 000 100 */ + case 0x385: /* 1 110 000 101 */ + case 0x386: /* 1 110 000 110 */ + case 0x387: /* 1 110 000 111 */ + size += 1; + ea = oprom16[1]; + sprintf(buffer, "AND (%04X),R%01d",ea,op&0x7); + break; + case 0x388: /* 1 110 001 000 */ + case 0x389: /* 1 110 001 001 */ + case 0x38a: /* 1 110 001 010 */ + case 0x38b: /* 1 110 001 011 */ + case 0x38c: /* 1 110 001 100 */ + case 0x38d: /* 1 110 001 101 */ + case 0x38e: /* 1 110 001 110 */ + case 0x38f: /* 1 110 001 111 */ + case 0x390: /* 1 110 010 000 */ + case 0x391: /* 1 110 010 001 */ + case 0x392: /* 1 110 010 010 */ + case 0x393: /* 1 110 010 011 */ + case 0x394: /* 1 110 010 100 */ + case 0x395: /* 1 110 010 101 */ + case 0x396: /* 1 110 010 110 */ + case 0x397: /* 1 110 010 111 */ + case 0x398: /* 1 110 011 000 */ + case 0x399: /* 1 110 011 001 */ + case 0x39a: /* 1 110 011 010 */ + case 0x39b: /* 1 110 011 011 */ + case 0x39c: /* 1 110 011 100 */ + case 0x39d: /* 1 110 011 101 */ + case 0x39e: /* 1 110 011 110 */ + case 0x39f: /* 1 110 011 111 */ + case 0x3a0: /* 1 110 100 000 */ + case 0x3a1: /* 1 110 100 001 */ + case 0x3a2: /* 1 110 100 010 */ + case 0x3a3: /* 1 110 100 011 */ + case 0x3a4: /* 1 110 100 100 */ + case 0x3a5: /* 1 110 100 101 */ + case 0x3a6: /* 1 110 100 110 */ + case 0x3a7: /* 1 110 100 111 */ + case 0x3a8: /* 1 110 101 000 */ + case 0x3a9: /* 1 110 101 001 */ + case 0x3aa: /* 1 110 101 010 */ + case 0x3ab: /* 1 110 101 011 */ + case 0x3ac: /* 1 110 101 100 */ + case 0x3ad: /* 1 110 101 101 */ + case 0x3ae: /* 1 110 101 110 */ + case 0x3af: /* 1 110 101 111 */ + case 0x3b0: /* 1 110 110 000 */ + case 0x3b1: /* 1 110 110 001 */ + case 0x3b2: /* 1 110 110 010 */ + case 0x3b3: /* 1 110 110 011 */ + case 0x3b4: /* 1 110 110 100 */ + case 0x3b5: /* 1 110 110 101 */ + case 0x3b6: /* 1 110 110 110 */ + case 0x3b7: /* 1 110 110 111 */ + sprintf(buffer, "AND@ (R%01d),R%01d",(op&0x38)>>3,op&0x7); + break; + case 0x3b8: /* 1 110 111 000 */ + case 0x3b9: /* 1 110 111 001 */ + case 0x3ba: /* 1 110 111 010 */ + case 0x3bb: /* 1 110 111 011 */ + case 0x3bc: /* 1 110 111 100 */ + case 0x3bd: /* 1 110 111 101 */ + case 0x3be: /* 1 110 111 110 */ + case 0x3bf: /* 1 110 111 111 */ + size += 1; + ea = oprom16[1]; + sprintf(buffer, "ANDI #%04X,R%01d",ea,op&0x7); + break; + case 0x3c0: /* 1 111 000 000 */ + case 0x3c1: /* 1 111 000 001 */ + case 0x3c2: /* 1 111 000 010 */ + case 0x3c3: /* 1 111 000 011 */ + case 0x3c4: /* 1 111 000 100 */ + case 0x3c5: /* 1 111 000 101 */ + case 0x3c6: /* 1 111 000 110 */ + case 0x3c7: /* 1 111 000 111 */ + size += 1; + ea = oprom16[1]; + sprintf(buffer, "XOR (%04X),R%01d",ea,op&0x7); + break; + case 0x3c8: /* 1 111 001 000 */ + case 0x3c9: /* 1 111 001 001 */ + case 0x3ca: /* 1 111 001 010 */ + case 0x3cb: /* 1 111 001 011 */ + case 0x3cc: /* 1 111 001 100 */ + case 0x3cd: /* 1 111 001 101 */ + case 0x3ce: /* 1 111 001 110 */ + case 0x3cf: /* 1 111 001 111 */ + case 0x3d0: /* 1 111 010 000 */ + case 0x3d1: /* 1 111 010 001 */ + case 0x3d2: /* 1 111 010 010 */ + case 0x3d3: /* 1 111 010 011 */ + case 0x3d4: /* 1 111 010 100 */ + case 0x3d5: /* 1 111 010 101 */ + case 0x3d6: /* 1 111 010 110 */ + case 0x3d7: /* 1 111 010 111 */ + case 0x3d8: /* 1 111 011 000 */ + case 0x3d9: /* 1 111 011 001 */ + case 0x3da: /* 1 111 011 010 */ + case 0x3db: /* 1 111 011 011 */ + case 0x3dc: /* 1 111 011 100 */ + case 0x3dd: /* 1 111 011 101 */ + case 0x3de: /* 1 111 011 110 */ + case 0x3df: /* 1 111 011 111 */ + case 0x3e0: /* 1 111 100 000 */ + case 0x3e1: /* 1 111 100 001 */ + case 0x3e2: /* 1 111 100 010 */ + case 0x3e3: /* 1 111 100 011 */ + case 0x3e4: /* 1 111 100 100 */ + case 0x3e5: /* 1 111 100 101 */ + case 0x3e6: /* 1 111 100 110 */ + case 0x3e7: /* 1 111 100 111 */ + case 0x3e8: /* 1 111 101 000 */ + case 0x3e9: /* 1 111 101 001 */ + case 0x3ea: /* 1 111 101 010 */ + case 0x3eb: /* 1 111 101 011 */ + case 0x3ec: /* 1 111 101 100 */ + case 0x3ed: /* 1 111 101 101 */ + case 0x3ee: /* 1 111 101 110 */ + case 0x3ef: /* 1 111 101 111 */ + case 0x3f0: /* 1 111 110 000 */ + case 0x3f1: /* 1 111 110 001 */ + case 0x3f2: /* 1 111 110 010 */ + case 0x3f3: /* 1 111 110 011 */ + case 0x3f4: /* 1 111 110 100 */ + case 0x3f5: /* 1 111 110 101 */ + case 0x3f6: /* 1 111 110 110 */ + case 0x3f7: /* 1 111 110 111 */ + sprintf(buffer, "XOR@ (R%01d),R%01d",(op&0x38)>>3,op&0x7); + break; + case 0x3f8: /* 1 111 111 000 */ + case 0x3f9: /* 1 111 111 001 */ + case 0x3fa: /* 1 111 111 010 */ + case 0x3fb: /* 1 111 111 011 */ + case 0x3fc: /* 1 111 111 100 */ + case 0x3fd: /* 1 111 111 101 */ + case 0x3fe: /* 1 111 111 110 */ + case 0x3ff: /* 1 111 111 111 */ + size += 1; + ea = oprom16[1]; + sprintf(buffer, "XORI #%04X,R%01d",ea,op&0x7); + break; + default: + sprintf(buffer, "????"); + } + + return size; +} diff --git a/src/devices/cpu/cp1610/cp1610.c b/src/devices/cpu/cp1610/cp1610.c new file mode 100644 index 00000000000..fd6fd5eceb7 --- /dev/null +++ b/src/devices/cpu/cp1610/cp1610.c @@ -0,0 +1,3423 @@ +// license:BSD-3-Clause +// copyright-holders:Frank Palazzolo +/***************************************************************************** + * + * cp1610.c + * Portable CP1610 emulator (General Instrument CP1610) + * + * Copyright Frank Palazzolo, all rights reserved. + * + * This work is based on Juergen Buchmueller's F8 emulation, + * and the 'General Instruments CP1610' data sheets. + * Special thanks to Joe Zbiciak for his GPL'd CP1610 emulator + * + *****************************************************************************/ + +#include "emu.h" +#include "debugger.h" +#include "cp1610.h" + + +const device_type CP1610 = &device_creator; + + +#define S 0x80 +#define Z 0x40 +#define OV 0x20 +#define C 0x10 + + +#define cp1610_readop(A) m_program->read_word((A)<<1) +#define cp1610_readmem16(A) m_program->read_word((A)<<1) +#define cp1610_writemem16(A,B) m_program->write_word((A)<<1,B) + +/* clear all flags */ +#define CLR_SZOC \ + m_flags &= ~(S|Z|C|OV) + +/* clear sign and zero flags */ +#define CLR_SZ \ + m_flags &= ~(S|Z) + +/* clear sign,zero, and carry flags */ +#define CLR_SZC \ + m_flags &= ~(S|Z|C) + +/* set sign and zero flags */ +#define SET_SZ(n) \ + if (n == 0) \ + m_flags |= Z; \ + else \ + if (n & 0x8000) \ + m_flags |= S + +/* set sign zero, and carry flags */ +#define SET_SZC(n,m) \ + if (n == 0) \ + m_flags |= Z; \ + else \ + if (n & 0x8000) \ + m_flags |= S; \ + if ((n + m) & 0x10000) \ + m_flags |= C + +/* set carry and overflow flags */ +#define SET_COV(n,m,qq) \ +{ \ + unsigned int pp = n + m; \ + if (pp & 0x10000) \ + m_flags |= C; \ + if (qq) \ + { \ + if ((n^pp)&(~(m^n))&0x8000) \ + m_flags |= OV; \ + if (m == 0x8000) \ + m_flags ^= OV; \ + } \ + else \ + { \ + if ((n^pp)&(~(m^n))&0x8000) \ + m_flags |= OV; \ + } \ +} + +/*********************************** + * illegal opcodes + ***********************************/ +void cp1610_cpu_device::cp1610_illegal() +{ + logerror("cp1610 illegal opcode at 0x%04x\n", m_r[7]); +} + +/*************************************************** + * S Z C OV 0 000 000 000 + * - - - - HLT + ***************************************************/ +void cp1610_cpu_device::cp1610_hlt() +{ + /* TBD */ + m_icount -= 4; +} + +/*************************************************** + * S Z C OV 0 000 000 010 + * - - - - EIS + ***************************************************/ +void cp1610_cpu_device::cp1610_eis() +{ + m_mask_interrupts = 1; + m_intr_enabled = 1; + m_icount -= 4; +} + +/*************************************************** + * S Z C OV 0 000 000 011 + * - - - - DIS + ***************************************************/ +void cp1610_cpu_device::cp1610_dis() +{ + m_mask_interrupts = 1; + m_intr_enabled = 0; + m_icount -= 4; +} + +/*************************************************** + * S Z C OV 0 000 000 101 + * - - - - TCI + ***************************************************/ +void cp1610_cpu_device::cp1610_tci() +{ + /* TBD */ + m_mask_interrupts = 1; + m_icount -= 4; +} + +/*************************************************** + * S Z C OV 0 000 000 110 + * - - 0 - CLRC + ***************************************************/ +void cp1610_cpu_device::cp1610_clrc() +{ + m_mask_interrupts = 1; + m_flags &= ~C; + m_icount -= 4; +} + +/*************************************************** + * S Z C OV 0 000 000 111 + * - - 1 - SETC + ***************************************************/ +void cp1610_cpu_device::cp1610_setc() +{ + m_mask_interrupts = 1; + m_flags |= C; + m_icount -= 6; +} + +/*************************************************** + * S Z C OV 0 000 001 ddd + * x x - - INCR Rd + ***************************************************/ +void cp1610_cpu_device::cp1610_incr(int n) +{ + m_r[n]++; + CLR_SZ; + SET_SZ(m_r[n]); + m_icount -= 6; +} + +/*************************************************** + * S Z C OV 0 000 010 ddd + * x x - - DECR Rd + ***************************************************/ +void cp1610_cpu_device::cp1610_decr(int n) +{ + m_r[n]--; + CLR_SZ; + SET_SZ(m_r[n]); + m_icount -= 6; +} + +/*************************************************** + * S Z C OV 0 000 011 ddd + * x x - - COMR Rd + ***************************************************/ +void cp1610_cpu_device::cp1610_comr(int n) +{ + m_r[n] ^= 0xffff; + CLR_SZ; + SET_SZ(m_r[n]); + m_icount -= 6; +} + +/*************************************************** + * S Z C OV 0 000 100 ddd + * x x x x NEGR Rd + ***************************************************/ +void cp1610_cpu_device::cp1610_negr(int n) +{ + UINT32 temp; + CLR_SZOC; + temp = (m_r[n] ^ 0xffff) + 1; + SET_COV(0,temp,1); + m_r[n] = temp&0xffff; + SET_SZ(m_r[n]); + m_icount -= 6; +} + +/*************************************************** + * S Z C OV 0 000 101 ddd + * x x x x ADCR Rd + ***************************************************/ +void cp1610_cpu_device::cp1610_adcr(int n) +{ + UINT16 offset = 0; + if (m_flags & C) + offset = 1; + CLR_SZOC; + SET_COV(m_r[n],offset,0); + m_r[n] += offset; + SET_SZ(m_r[n]); + m_icount -= 6; +} + +/*************************************************** + * S Z C OV 0 000 110 0dd + * - - - - GSWD Rd + ***************************************************/ +void cp1610_cpu_device::cp1610_gswd(int n) +{ + m_r[n] = (m_flags << 8) + m_flags; + m_icount -= 6; +} + +/*************************************************** + * S Z C OV 0 000 110 10x + * - - - - NOP + ***************************************************/ +void cp1610_cpu_device::cp1610_nop() +{ + m_icount -= 6; +} + +/*************************************************** + * S Z C OV 0 000 110 11x + * - - - - SIN + ***************************************************/ +void cp1610_cpu_device::cp1610_sin() +{ + /* TBD */ + m_icount -= 6; +} + +/*************************************************** + * S Z C OV 0 000 111 sss + * x x x x RSWD Rs + ***************************************************/ +void cp1610_cpu_device::cp1610_rswd(int n) +{ + m_flags = m_r[n]; + m_icount -= 6; +} + +/*************************************************** + * S Z C OV 0 001 000 0rr + * x x - - SWAP Rr,1 + ***************************************************/ +void cp1610_cpu_device::cp1610_swap(int r) +{ + UINT8 temp; + m_mask_interrupts = 1; + CLR_SZ; + temp = m_r[r] >> 8; + m_r[r] = (m_r[r] << 8) | temp; + SET_SZ(m_r[r]); + /* S flag is set on bit 7 not bit 15 */ + m_flags &= ~S; + if (m_r[r] & 0x80) + m_flags |= S; + m_icount -= 6; +} + +/*************************************************** + * S Z C OV 0 001 000 1rr + * x x - - SWAP Rr,2 + ***************************************************/ +void cp1610_cpu_device::cp1610_dswap(int r) +{ + /* This instruction was not officially supported by GI */ + UINT16 temp; + m_mask_interrupts = 1; + CLR_SZ; + temp = m_r[r] & 0xff; + m_r[r] = (temp << 8) | temp; + SET_SZ(m_r[r]); + /* S flag is set on bit 7 not bit 15 */ + m_flags &= ~S; + if (m_r[r] & 0x80) + m_flags |= S; + m_icount -= 8; +} + +/*************************************************** + * S Z C OV 0 001 001 0rr + * x x - - SLL Rr,1 + ***************************************************/ +void cp1610_cpu_device::cp1610_sll_1(int r) +{ + m_mask_interrupts = 1; + CLR_SZ; + m_r[r] <<= 1; + SET_SZ(m_r[r]); + m_icount -= 6; +} + +/*************************************************** + * S Z C OV 0 001 001 1rr + * x x - - SLL Rr,2 + ***************************************************/ +void cp1610_cpu_device::cp1610_sll_2(int r) +{ + m_mask_interrupts = 1; + CLR_SZ; + m_r[r] <<= 2; + SET_SZ(m_r[r]); + m_icount -= 8; +} + +/*************************************************** + * S Z C OV 0 001 010 0rr + * x x x - RLC Rr,1 + ***************************************************/ +void cp1610_cpu_device::cp1610_rlc_1(int r) +{ + UINT16 offset = 0; + m_mask_interrupts = 1; + if (m_flags & C) + offset = 1; + CLR_SZC; + if (m_r[r] & 0x8000) + m_flags |= C; + m_r[r] = (m_r[r] << 1) + offset; + SET_SZ(m_r[r]); + m_icount -= 6; +} + +/*************************************************** + * S Z C OV 0 001 010 1rr + * x x x x RLC Rr,2 + ***************************************************/ +void cp1610_cpu_device::cp1610_rlc_2(int r) +{ + UINT16 offset = 0; + m_mask_interrupts = 1; + switch(m_flags & (C | OV)) + { + case 0: + offset = 0; + break; + case OV: + offset = 1; + break; + case C: + offset = 2; + break; + case (C | OV): + offset = 3; + break; + } + + CLR_SZOC; + if (m_r[r] & 0x8000) + m_flags |= C; + if (m_r[r] & 0x4000) + m_flags |= OV; + m_r[r] <<= 2; + m_r[r] += offset; + SET_SZ(m_r[r]); + m_icount -= 8; +} + +/*************************************************** + * S Z C OV 0 001 011 0rr + * x x x - SLLC Rr,1 + ***************************************************/ +void cp1610_cpu_device::cp1610_sllc_1(int r) +{ + m_mask_interrupts = 1; + CLR_SZC; + if (m_r[r] & 0x8000) + m_flags |= C; + m_r[r] <<= 1; + SET_SZ(m_r[r]); + m_icount -= 6; +} + +/*************************************************** + * S Z C OV 0 001 011 1rr + * x x x x SLLC Rr,2 + ***************************************************/ +void cp1610_cpu_device::cp1610_sllc_2(int r) +{ + m_mask_interrupts = 1; + CLR_SZOC; + if (m_r[r] & 0x8000) + m_flags |= C; + if (m_r[r] & 0x4000) + m_flags |= OV; + m_r[r] <<= 2; + SET_SZ(m_r[r]); + m_icount -= 8; +} + +/*************************************************** + * S Z C OV 0 001 100 0rr + * x x - - SLR Rr,1 + ***************************************************/ +void cp1610_cpu_device::cp1610_slr_1(int r) +{ + m_mask_interrupts = 1; + CLR_SZ; + m_r[r] >>= 1; + SET_SZ(m_r[r]); + /* S flag is set on bit 7 not bit 15 */ + m_flags &= ~S; + if (m_r[r] & 0x80) + m_flags |= S; + m_icount -= 6; +} + +/*************************************************** + * S Z C OV 0 001 100 1rr + * x x - - SLR Rr,2 + ***************************************************/ +void cp1610_cpu_device::cp1610_slr_2(int r) +{ + m_mask_interrupts = 1; + CLR_SZ; + m_r[r] >>= 2; + SET_SZ(m_r[r]); + /* S flag is set on bit 7 not bit 15 */ + m_flags &= ~S; + if (m_r[r] & 0x80) + m_flags |= S; + m_icount -= 8; +} + +/*************************************************** + * S Z C OV 0 001 101 0rr + * x x - - SAR Rr,1 + ***************************************************/ +void cp1610_cpu_device::cp1610_sar_1(int r) +{ + m_mask_interrupts = 1; + CLR_SZ; + m_r[r] = (UINT16)(((INT16)(m_r[r])) >> 1); + SET_SZ(m_r[r]); + /* S flag is set on bit 7 not bit 15 */ + m_flags &= ~S; + if (m_r[r] & 0x80) + m_flags |= S; + m_icount -= 6; +} + +/*************************************************** + * S Z C OV 0 001 101 1rr + * x x - - SAR Rr,2 + ***************************************************/ +void cp1610_cpu_device::cp1610_sar_2(int r) +{ + m_mask_interrupts = 1; + CLR_SZ; + m_r[r] = (UINT16)(((INT16)(m_r[r])) >> 2); + SET_SZ(m_r[r]); + /* S flag is set on bit 7 not bit 15 */ + m_flags &= ~S; + if (m_r[r] & 0x80) + m_flags |= S; + m_icount -= 8; +} + +/*************************************************** + * S Z C OV 0 001 110 0rr + * x x x - RRC Rr,1 + ***************************************************/ +void cp1610_cpu_device::cp1610_rrc_1(int r) +{ + UINT16 offset = 0; + m_mask_interrupts = 1; + if (m_flags & C) + offset = 0x8000; + CLR_SZC; + if (m_r[r] & 1) + m_flags |= C; + m_r[r] >>= 1; + m_r[r] += offset; + SET_SZ(m_r[r]); + /* S flag is set on bit 7 not bit 15 */ + m_flags &= ~S; + if (m_r[r] & 0x80) + m_flags |= S; + m_icount -= 6; +} + +/*************************************************** + * S Z C OV 0 001 110 1rr + * x x x x RRC Rr,2 + ***************************************************/ +void cp1610_cpu_device::cp1610_rrc_2(int r) +{ + UINT16 offset = 0; + m_mask_interrupts = 1; + if (m_flags & C) + offset |= 0x4000; + if (m_flags & OV) + offset |= 0x8000; + CLR_SZOC; + if (m_r[r] & 1) + m_flags |= C; + if (m_r[r] & 2) + m_flags |= OV; + m_r[r] >>= 2; + m_r[r] += offset; + SET_SZ(m_r[r]); + /* S flag is set on bit 7 not bit 15 */ + m_flags &= ~S; + if (m_r[r] & 0x80) + m_flags |= S; + m_icount -= 8; +} + +/*************************************************** + * S Z C OV 0 001 111 0rr + * x x x - SARC Rr,1 + ***************************************************/ +void cp1610_cpu_device::cp1610_sarc_1(int r) +{ + m_mask_interrupts = 1; + CLR_SZC; + if (m_r[r] & 1) + m_flags |= C; + m_r[r] = (UINT16)(((INT16)m_r[r]) >> 1); + SET_SZ(m_r[r]); + /* S flag is set on bit 7 not bit 15 */ + m_flags &= ~S; + if (m_r[r] & 0x80) + m_flags |= S; + m_icount -= 6; +} + +/*************************************************** + * S Z C OV 0 001 111 1rr + * x x x x SARC Rr,2 + ***************************************************/ +void cp1610_cpu_device::cp1610_sarc_2(int r) +{ + m_mask_interrupts = 1; + CLR_SZOC; + if (m_r[r] & 1) + m_flags |= C; + if (m_r[r] & 2) + m_flags |= OV; + m_r[r] = (UINT16)(((INT16)m_r[r]) >> 2); + SET_SZ(m_r[r]); + /* S flag is set on bit 7 not bit 15 */ + m_flags &= ~S; + if (m_r[r] & 0x80) + m_flags |= S; + m_icount -= 6; +} + +/*************************************************** + * S Z C OV 0 010 sss sss + * x x - - TSTR Rs + ***************************************************/ +void cp1610_cpu_device::cp1610_tstr(int n) +{ + CLR_SZ; + SET_SZ(m_r[n]); + m_icount -= 6; + if (n > 5) + m_icount -= 1; +} + +/*************************************************** + * S Z C OV 0 010 sss ddd (sss != ddd) + * x x - - MOVR Rs,Rd + ***************************************************/ +void cp1610_cpu_device::cp1610_movr(int s, int d) +{ + CLR_SZ; + m_r[d] = m_r[s]; + SET_SZ(m_r[d]); + m_icount -= 6; + if (d > 5) + m_icount -= 1; +} + +/*************************************************** + * S Z C OV 0 011 sss ddd + * x x x x ADDR Rs, Rd + ***************************************************/ +void cp1610_cpu_device::cp1610_addr(int s, int d) +{ + CLR_SZOC; + SET_COV(m_r[s],m_r[d],0); + m_r[d] += m_r[s]; + SET_SZ(m_r[d]); + m_icount -= 6; +} + +/*************************************************** + * S Z C OV 0 100 sss ddd + * x x x x SUBR Rs, Rd + ***************************************************/ +void cp1610_cpu_device::cp1610_subr(int s, int d) +{ + CLR_SZOC; + SET_COV(m_r[d],(UINT32)((m_r[s]^0xffff)+1),1); + m_r[d] -= m_r[s]; + SET_SZ(m_r[d]); + m_icount -= 6; +} + +/*************************************************** + * S Z C OV 0 101 sss ddd + * x x x x CMPR Rs, Rd + ***************************************************/ +void cp1610_cpu_device::cp1610_cmpr(int s, int d) +{ + UINT16 temp; + CLR_SZOC; + SET_COV(m_r[d],(UINT32)((m_r[s]^0xffff)+1),1); + temp = m_r[d] - m_r[s]; + SET_SZ(temp); + m_icount -= 6; +} + +/*************************************************** + * S Z C OV 0 110 sss ddd + * x x - - ANDR Rs, Rd + ***************************************************/ +void cp1610_cpu_device::cp1610_andr(int s, int d) +{ + CLR_SZ; + m_r[d] &= m_r[s]; + SET_SZ(m_r[d]); + m_icount -= 6; +} + +/*************************************************** + * S Z C OV 0 111 sss ddd (sss != ddd) + * x x - - XORR Rs, Rd + ***************************************************/ +void cp1610_cpu_device::cp1610_xorr(int s, int d) +{ + CLR_SZ; + m_r[d] ^= m_r[s]; + SET_SZ(m_r[d]); + m_icount -= 6; +} + +/*************************************************** + * S Z C OV 0 111 ddd ddd + * x x - - CLRR Rd + ***************************************************/ +void cp1610_cpu_device::cp1610_clrr(int d) +{ + CLR_SZ; + m_r[d] = 0; + SET_SZ(m_r[d]); + m_icount -= 6; +} + +/*************************************************** + * S Z C OV 1 000 s00 000 p ppp ppp ppp ppp ppp + * - - - - B ADDR + ***************************************************/ +void cp1610_cpu_device::cp1610_b(int dir) +{ + UINT16 offset = cp1610_readop(m_r[7]); + m_r[7]++; + m_r[7] += (offset ^ dir); + m_icount -= 9; +} + +/*************************************************** + * S Z C OV 1 000 s01 000 p ppp ppp ppp ppp ppp + * - - - - NOPP + ***************************************************/ +void cp1610_cpu_device::cp1610_nopp(int dir) +{ + cp1610_readop(m_r[7]); + m_r[7]++; + m_icount -= 7; +} + +/*************************************************** + * S Z C OV 1 000 s00 001 p ppp ppp ppp ppp ppp + * - - - - BC ADDR + ***************************************************/ +void cp1610_cpu_device::cp1610_bc(int dir) +{ + UINT16 offset = cp1610_readop(m_r[7]); + m_r[7]++; + if (m_flags & C) + { + m_r[7] += (offset ^ dir); + m_icount -= 9; + } + else + { + m_icount -= 7; + } +} + +/*************************************************** + * S Z C OV 1 000 s01 001 p ppp ppp ppp ppp ppp + * - - - - BNC ADDR + ***************************************************/ +void cp1610_cpu_device::cp1610_bnc(int dir) +{ + UINT16 offset = cp1610_readop(m_r[7]); + m_r[7]++; + if (!(m_flags & C)) + { + m_r[7] += (offset ^ dir); + m_icount -= 9; + } + else + { + m_icount -= 7; + } +} + +/*************************************************** + * S Z C OV 1 000 s00 010 p ppp ppp ppp ppp ppp + * - - - - BOV ADDR + ***************************************************/ +void cp1610_cpu_device::cp1610_bov(int dir) +{ + UINT16 offset = cp1610_readop(m_r[7]); + m_r[7]++; + if (m_flags & OV) + { + m_r[7] += (offset ^ dir); + m_icount -= 9; + } + else + { + m_icount -= 7; + } +} + +/*************************************************** + * S Z C OV 1 000 s01 010 p ppp ppp ppp ppp ppp + * - - - - BNOV ADDR + ***************************************************/ +void cp1610_cpu_device::cp1610_bnov(int dir) +{ + UINT16 offset = cp1610_readop(m_r[7]); + m_r[7]++; + if (!(m_flags & OV)) + { + m_r[7] += (offset ^ dir); + m_icount -= 9; + } + else + { + m_icount -= 7; + } +} + +/*************************************************** + * S Z C OV 1 000 s00 011 p ppp ppp ppp ppp ppp + * - - - - BPL ADDR + ***************************************************/ +void cp1610_cpu_device::cp1610_bpl(int dir) +{ + UINT16 offset = cp1610_readop(m_r[7]); + m_r[7]++; + if (!(m_flags & S)) + { + m_r[7] += (offset ^ dir); + m_icount -= 9; + } + else + { + m_icount -= 7; + } +} + +/*************************************************** + * S Z C OV 1 000 s01 011 p ppp ppp ppp ppp ppp + * - - - - BMI ADDR + ***************************************************/ +void cp1610_cpu_device::cp1610_bmi(int dir) +{ + UINT16 offset = cp1610_readop(m_r[7]); + m_r[7]++; + if (m_flags & S) + { + m_r[7] += (offset ^ dir); + m_icount -= 9; + } + else + { + m_icount -= 7; + } +} + +/*************************************************** + * S Z C OV 1 000 s00 100 p ppp ppp ppp ppp ppp + * - - - - BZE ADDR + ***************************************************/ +void cp1610_cpu_device::cp1610_bze(int dir) +{ + UINT16 offset = cp1610_readop(m_r[7]); + m_r[7]++; + if (m_flags & Z) + { + m_r[7] += (offset ^ dir); + m_icount -= 9; + } + else + { + m_icount -= 7; + } +} + +/*************************************************** + * S Z C OV 1 000 s01 100 p ppp ppp ppp ppp ppp + * - - - - BNZE ADDR + ***************************************************/ +void cp1610_cpu_device::cp1610_bnze(int dir) +{ + UINT16 offset = cp1610_readop(m_r[7]); + m_r[7]++; + if (!(m_flags & Z)) + { + m_r[7] += (offset ^ dir); + m_icount -= 9; + } + else + { + m_icount -= 7; + } +} + +/*************************************************** + * S Z C OV 1 000 s00 101 p ppp ppp ppp ppp ppp + * - - - - BLT ADDR + ***************************************************/ +void cp1610_cpu_device::cp1610_blt(int dir) +{ + int condition1 = 0; + int condition2 = 0; + UINT16 offset = cp1610_readop(m_r[7]); + m_r[7]++; + if (m_flags & S) condition1 = 1; + if (m_flags & OV) condition2 = 1; + if (condition1 ^ condition2) + { + m_r[7] += (offset ^ dir); + m_icount -= 9; + } + else + { + m_icount -= 7; + } +} + +/*************************************************** + * S Z C OV 1 000 s01 101 p ppp ppp ppp ppp ppp + * - - - - BGE ADDR + ***************************************************/ +void cp1610_cpu_device::cp1610_bge(int dir) +{ + int condition1 = 0; + int condition2 = 0; + UINT16 offset = cp1610_readop(m_r[7]); + m_r[7]++; + if (m_flags & S) condition1 = 1; + if (m_flags & OV) condition2 = 1; + if (!(condition1 ^ condition2)) + { + m_r[7] += (offset ^ dir); + m_icount -= 9; + } + else + { + m_icount -= 7; + } +} + +/*************************************************** + * S Z C OV 1 000 s00 110 p ppp ppp ppp ppp ppp + * - - - - BLE ADDR + ***************************************************/ +void cp1610_cpu_device::cp1610_ble(int dir) +{ + int condition1 = 0; + int condition2 = 0; + UINT16 offset = cp1610_readop(m_r[7]); + m_r[7]++; + if (m_flags & S) condition1 = 1; + if (m_flags & OV) condition2 = 1; + if ((m_flags & Z) || (condition1 ^ condition2)) + { + m_r[7] += (offset ^ dir); + m_icount -= 9; + } + else + { + m_icount -= 7; + } +} + +/*************************************************** + * S Z C OV 1 000 s01 110 p ppp ppp ppp ppp ppp + * - - - - BGT ADDR + ***************************************************/ +void cp1610_cpu_device::cp1610_bgt(int dir) +{ + int condition1 = 0; + int condition2 = 0; + UINT16 offset = cp1610_readop(m_r[7]); + m_r[7]++; + if (m_flags & S) condition1 = 1; + if (m_flags & OV) condition2 = 1; + if (!((m_flags & Z) || (condition1 ^ condition2))) + { + m_r[7] += (offset ^ dir); + m_icount -= 9; + } + else + { + m_icount -= 7; + } +} + +/*************************************************** + * S Z C OV 1 000 s00 111 p ppp ppp ppp ppp ppp + * - - - - BUSC ADDR + ***************************************************/ +void cp1610_cpu_device::cp1610_busc(int dir) +{ + int condition1 = 0; + int condition2 = 0; + UINT16 offset = cp1610_readop(m_r[7]); + m_r[7]++; + if (m_flags & C) condition1 = 1; + if (m_flags & S) condition2 = 1; + if (condition1 ^ condition2) + { + m_r[7] += (offset ^ dir); + m_icount -= 9; + } + else + { + m_icount -= 7; + } +} + +/*************************************************** + * S Z C OV 1 000 s01 111 p ppp ppp ppp ppp ppp + * - - - - BESC ADDR + ***************************************************/ +void cp1610_cpu_device::cp1610_besc(int dir) +{ + int condition1 = 0; + int condition2 = 0; + UINT16 offset = cp1610_readop(m_r[7]); + m_r[7]++; + if (m_flags & C) condition1 = 1; + if (m_flags & S) condition2 = 1; + if (!(condition1 ^ condition2)) + { + m_r[7] += (offset ^ dir); + m_icount -= 9; + } + else + { + m_icount -= 7; + } +} + +/*************************************************** + * S Z C OV 1 000 s1e e p ppp ppp ppp ppp ppp + * - - - - BEXT ADDR, eeee + ***************************************************/ + void cp1610_cpu_device::cp1610_bext(int ext, int dir) +{ + UINT16 offset = cp1610_readop(m_r[7]); + m_r[7]++; + + if (m_read_bext(ext)) + { + m_r[7] += (offset ^ dir); + m_icount -= 9; + } + else + { + m_icount -= 7; + } +} + +/*************************************************** + * S Z C OV 1 001 000 sss a aaa aaa aaa aaa aaa + * - - - - MVO Rs, ADDR + ***************************************************/ +void cp1610_cpu_device::cp1610_mvo(int s) +{ + UINT16 addr; + m_mask_interrupts = 1; + addr = cp1610_readop(m_r[7]); + m_r[7]++; + cp1610_writemem16(addr,m_r[s]); + m_icount -= 11; +} + +/*************************************************** + * S Z C OV 1 001 mmm sss (mmm = 0xx) + * - - - - MVO@ Rs, Rm + ***************************************************/ +void cp1610_cpu_device::cp1610_mvoat(int s, int m) +{ + m_mask_interrupts = 1; + cp1610_writemem16(m_r[m],m_r[s]); + m_icount -= 9; +} + +/*************************************************** + * S Z C OV 1 001 mmm sss (m = 10x or 110) + * - - - - MVO@ Rs, Rm + ***************************************************/ +void cp1610_cpu_device::cp1610_mvoat_i(int s, int m) +{ + m_mask_interrupts = 1; + cp1610_writemem16(m_r[m],m_r[s]); + m_r[m]++; + m_icount -= 9; +} + +/*************************************************** + * S Z C OV 1 001 111 sss I III III III III III + * - - - - MVOI Rs, II + ***************************************************/ +void cp1610_cpu_device::cp1610_mvoi(int s) +{ + m_mask_interrupts = 1; + cp1610_writemem16(m_r[7],m_r[s]); + m_r[7]++; + m_icount -= 9; +} + +/*************************************************** + * S Z C OV 1 010 000 ddd a aaa aaa aaa aaa aaa + * - - - - MVI ADDR, Rd + ***************************************************/ +void cp1610_cpu_device::cp1610_mvi(int d) +{ + UINT16 addr = cp1610_readop(m_r[7]); + m_r[7]++; + m_r[d] = cp1610_readmem16(addr); + m_icount -= 10; +} + +/*************************************************** + * S Z C OV 1 010 mmm ddd (mmm = 0xx) + * - - - - MVI@ Rm, Rd + ***************************************************/ +void cp1610_cpu_device::cp1610_mviat(int m, int d) +{ + m_r[d] = cp1610_readmem16(m_r[m]); + m_icount -= 8; +} + +/*************************************************** + * S Z C OV 1 010 mmm ddd (mmm = 10x) + * - - - - MVI@ Rm, Rd + ***************************************************/ +void cp1610_cpu_device::cp1610_mviat_i(int m, int d) +{ + UINT16 temp = cp1610_readmem16(m_r[m]); + m_r[m]++; + m_r[d] = temp; + m_icount -= 8; +} + +/*************************************************** + * S Z C OV 1 010 110 ddd + * - - - - PULR Rd + ***************************************************/ +void cp1610_cpu_device::cp1610_pulr(int d) +{ + m_r[6]--; + m_r[d] = cp1610_readmem16(m_r[6]); + m_icount -= 11; +} + +/*************************************************** + * S Z C OV 1 010 111 ddd I III III III III III + * - - - - MVII II, Rd + ***************************************************/ +void cp1610_cpu_device::cp1610_mvii(int d) +{ + UINT16 temp = cp1610_readop(m_r[7]); + m_r[7]++; + m_r[d] = temp; + m_icount -= 8; +} + +/*************************************************** + * S Z C OV 1 011 000 ddd a aaa aaa aaa aaa aaa + * x x x x ADD ADDR, Rd + ***************************************************/ +void cp1610_cpu_device::cp1610_add(int d) +{ + UINT16 addr = cp1610_readop(m_r[7]); + UINT16 data = cp1610_readmem16(addr); + m_r[7]++; + CLR_SZOC; + SET_COV(m_r[d],data,0); + m_r[d] += data; + SET_SZ(m_r[d]); + m_icount -= 10; +} + +/*************************************************** + * S Z C OV 1 011 mmm ddd (mmm = 0xx) + * x x x x ADD@ Rm, Rd + ***************************************************/ +void cp1610_cpu_device::cp1610_addat(int m, int d) +{ + UINT16 data = cp1610_readmem16(m_r[m]); + CLR_SZOC; + SET_COV(m_r[d],data,0); + m_r[d] += data; + SET_SZ(m_r[d]); + m_icount -= 8; +} + +/*************************************************** + * S Z C OV 1 011 mmm ddd (mmm = 10x) + * x x x x ADD@ Rm, Rd + ***************************************************/ +void cp1610_cpu_device::cp1610_addat_i(int m, int d) +{ + UINT16 data = cp1610_readmem16(m_r[m]); + m_r[m]++; + CLR_SZOC; + SET_COV(m_r[d],data,0); + m_r[d] += data; + SET_SZ(m_r[d]); + m_icount -= 8; +} + +/*************************************************** + * S Z C OV 1 011 mmm ddd (mmm = 110) + * x x x x ADD@ Rm, Rd + ***************************************************/ +void cp1610_cpu_device::cp1610_addat_d(int m, int d) +{ + UINT16 data; + m_r[m]--; + data = cp1610_readmem16(m_r[m]); + CLR_SZOC; + SET_COV(m_r[d],data,0); + m_r[d] += data; + SET_SZ(m_r[d]); + m_icount -= 11; +} + +/*************************************************** + * S Z C OV 1 011 111 ddd I III III III III III + * x x x x ADDI II, Rd + ***************************************************/ +void cp1610_cpu_device::cp1610_addi(int d) +{ + UINT16 data; + data = cp1610_readop(m_r[7]); + m_r[7]++; + CLR_SZOC; + SET_COV(m_r[d],data,0); + m_r[d] += data; + SET_SZ(m_r[d]); + m_icount -= 8; +} + +/*************************************************** + * S Z C OV 1 100 000 ddd a aaa aaa aaa aaa aaa + * x x x x SUB ADDR, Rd + ***************************************************/ +void cp1610_cpu_device::cp1610_sub(int d) +{ + UINT16 addr = cp1610_readop(m_r[7]); + UINT32 data = cp1610_readmem16(addr); + m_r[7]++; + CLR_SZOC; + data = (data ^ 0xffff) + 1; + SET_COV(m_r[d],data,1); + data &= 0xffff; + m_r[d] += data; + SET_SZ(m_r[d]); + m_icount -= 10; +} + +/*************************************************** + * S Z C OV 1 100 mmm ddd (mmm = 0xx) + * x x x x SUB@ Rm, Rd + ***************************************************/ +void cp1610_cpu_device::cp1610_subat(int m, int d) +{ + UINT32 data = cp1610_readmem16(m_r[m]); + CLR_SZOC; + data = (data ^ 0xffff) + 1; + SET_COV(m_r[d],data,1); + data &= 0xffff; + m_r[d] += data; + SET_SZ(m_r[d]); + m_icount -= 8; +} + +/*************************************************** + * S Z C OV 1 100 mmm ddd (mmm = 10x) + * x x x x SUB@ Rm, Rd + ***************************************************/ +void cp1610_cpu_device::cp1610_subat_i(int m, int d) +{ + UINT32 data = cp1610_readmem16(m_r[m]); + m_r[m]++; + CLR_SZOC; + data = (data ^ 0xffff) + 1; + SET_COV(m_r[d],data,1); + data &= 0xffff; + m_r[d] += data; + SET_SZ(m_r[d]); + m_icount -= 8; +} + +/*************************************************** + * S Z C OV 1 100 mmm ddd (mmm = 110) + * x x x x SUB@ Rm, Rd + ***************************************************/ +void cp1610_cpu_device::cp1610_subat_d(int m, int d) +{ + UINT32 data; + m_r[m]--; + data = cp1610_readmem16(m_r[m]); + CLR_SZOC; + data = (data ^ 0xffff) + 1; + SET_COV(m_r[d],data,1); + data &= 0xffff; + m_r[d] += data; + SET_SZ(m_r[d]); + m_icount -= 11; +} + +/*************************************************** + * S Z C OV 1 100 111 ddd I III III III III III + * x x x x SUBI II, Rd + ***************************************************/ +void cp1610_cpu_device::cp1610_subi(int d) +{ + UINT32 data; + data = cp1610_readop(m_r[7]); + m_r[7]++; + data = (data ^ 0xffff) + 1; + CLR_SZOC; + SET_COV(m_r[d],data,1); + data &= 0xffff; + m_r[d] += data; + SET_SZ(m_r[d]); + m_icount -= 8; +} + +/*************************************************** + * S Z C OV 1 101 000 ddd a aaa aaa aaa aaa aaa + * x x x x CMP ADDR, Rd + ***************************************************/ +void cp1610_cpu_device::cp1610_cmp(int d) +{ + UINT16 addr = cp1610_readop(m_r[7]); + UINT32 data = cp1610_readmem16(addr); + UINT16 res; + m_r[7]++; + CLR_SZOC; + data = (data ^ 0xffff) + 1; + SET_COV(m_r[d],data,1); + data &= 0xffff; + res = m_r[d] + data; + SET_SZ(res); + m_icount -= 10; +} + +/*************************************************** + * S Z C OV 1 101 mmm ddd (mmm = 0xx) + * x x x x CMP@ Rm, Rd + ***************************************************/ +void cp1610_cpu_device::cp1610_cmpat(int m, int d) +{ + UINT32 data = cp1610_readmem16(m_r[m]); + UINT16 res; + CLR_SZOC; + data = (data ^ 0xffff) + 1; + SET_COV(m_r[d],data,1); + data &= 0xffff; + res = m_r[d] + data; + SET_SZ(res); + m_icount -= 8; +} + +/*************************************************** + * S Z C OV 1 101 mmm ddd (mmm = 10x) + * x x x x CMP@ Rm, Rd + ***************************************************/ +void cp1610_cpu_device::cp1610_cmpat_i(int m, int d) +{ + UINT32 data = cp1610_readmem16(m_r[m]); + UINT16 res; + m_r[m]++; + CLR_SZOC; + data = (data ^ 0xffff) + 1; + SET_COV(m_r[d],data,1); + data &= 0xffff; + res = m_r[d] + data; + SET_SZ(res); + m_icount -= 8; +} + +/*************************************************** + * S Z C OV 1 101 mmm ddd (mmm = 110) + * x x x x CMP@ Rm, Rd + ***************************************************/ +void cp1610_cpu_device::cp1610_cmpat_d(int m, int d) +{ + UINT32 data; + UINT16 res; + m_r[m]--; + data = cp1610_readmem16(m_r[m]); + CLR_SZOC; + data = (data ^ 0xffff) + 1; + SET_COV(m_r[d],data,1); + data &= 0xffff; + res = m_r[d] + data; + SET_SZ(res); + m_icount -= 11; +} + +/*************************************************** + * S Z C OV 1 101 111 ddd I III III III III III + * x x x x CMPI II, Rd + ***************************************************/ +void cp1610_cpu_device::cp1610_cmpi(int d) +{ + UINT32 data; + UINT16 res; + data = cp1610_readop(m_r[7]); + m_r[7]++; + data = (data ^ 0xffff) + 1; + CLR_SZOC; + SET_COV(m_r[d],data,1); + data &= 0xffff; + res = m_r[d] + data; + SET_SZ(res); + m_icount -= 8; +} + +/*************************************************** + * S Z C OV 1 110 000 ddd a aaa aaa aaa aaa aaa + * x x - - AND ADDR, Rd + ***************************************************/ +void cp1610_cpu_device::cp1610_and(int d) +{ + UINT16 addr = cp1610_readop(m_r[7]); + UINT16 data = cp1610_readmem16(addr); + m_r[7]++; + CLR_SZ; + m_r[d] &= data; + SET_SZ(m_r[d]); + m_icount -= 10; +} + +/*************************************************** + * S Z C OV 1 110 mmm ddd (mmm = 0xx) + * x x - - AND@ Rm, Rd + ***************************************************/ +void cp1610_cpu_device::cp1610_andat(int m, int d) +{ + UINT16 data = cp1610_readmem16(m_r[m]); + CLR_SZ; + m_r[d] &= data; + SET_SZ(m_r[d]); + m_icount -= 8; +} + +/*************************************************** + * S Z C OV 1 110 mmm ddd (mmm = 10x) + * x x - - AND@ Rm, Rd + ***************************************************/ +void cp1610_cpu_device::cp1610_andat_i(int m, int d) +{ + UINT16 data = cp1610_readmem16(m_r[m]); + m_r[m]++; + CLR_SZ; + m_r[d] &= data; + SET_SZ(m_r[d]); + m_icount -= 8; +} + +/*************************************************** + * S Z C OV 1 110 mmm ddd (mmm = 110) + * x x - - AND@ Rm, Rd + ***************************************************/ +void cp1610_cpu_device::cp1610_andat_d(int m, int d) +{ + UINT16 data; + m_r[m]--; + data = cp1610_readmem16(m_r[m]); + CLR_SZ; + m_r[d] &= data; + SET_SZ(m_r[d]); + m_icount -= 11; +} + +/*************************************************** + * S Z C OV 1 110 111 ddd I III III III III III + * x x - - AND II, Rd + ***************************************************/ +void cp1610_cpu_device::cp1610_andi(int d) +{ + UINT16 data; + data = cp1610_readop(m_r[7]); + m_r[7]++; + CLR_SZ; + m_r[d] &= data; + SET_SZ(m_r[d]); + m_icount -= 8; +} + +/*************************************************** + * S Z C OV 1 111 000 ddd a aaa aaa aaa aaa aaa + * x x - - XOR ADDR, Rd + ***************************************************/ +void cp1610_cpu_device::cp1610_xor(int d) +{ + UINT16 addr = cp1610_readop(m_r[7]); + UINT16 data = cp1610_readmem16(addr); + m_r[7]++; + CLR_SZ; + m_r[d] ^= data; + SET_SZ(m_r[d]); + m_icount -= 10; +} + +/*************************************************** + * S Z C OV 1 111 mmm ddd (mmm = 0xx) + * x x - - XOR@ Rm, Rd + ***************************************************/ +void cp1610_cpu_device::cp1610_xorat(int m, int d) +{ + UINT16 data = cp1610_readmem16(m_r[m]); + CLR_SZ; + m_r[d] ^= data; + SET_SZ(m_r[d]); + m_icount -= 8; +} + +/*************************************************** + * S Z C OV 1 111 mmm ddd (mmm = 10x) + * x x - - XOR@ Rm, Rd + ***************************************************/ +void cp1610_cpu_device::cp1610_xorat_i(int m, int d) +{ + UINT16 data = cp1610_readmem16(m_r[m]); + m_r[m]++; + CLR_SZ; + m_r[d] ^= data; + SET_SZ(m_r[d]); + m_icount -= 8; +} + +/*************************************************** + * S Z C OV 1 111 mmm ddd (mmm = 110) + * x x - - XOR@ Rm, Rd + ***************************************************/ +void cp1610_cpu_device::cp1610_xorat_d(int m, int d) +{ + UINT16 data; + m_r[m]--; + data = cp1610_readmem16(m_r[m]); + CLR_SZ; + m_r[d] ^= data; + SET_SZ(m_r[d]); + m_icount -= 11; +} + +/*************************************************** + * S Z C OV 1 111 111 ddd I III III III III III + * x x - - XOR II, Rd + ***************************************************/ +void cp1610_cpu_device::cp1610_xori(int d) +{ + UINT16 data; + data = cp1610_readop(m_r[7]); + m_r[7]++; + CLR_SZ; + m_r[d] ^= data; + SET_SZ(m_r[d]); + m_icount -= 8; +} + +/*************************************************** + * S Z C OV 0x001 1 010 mmm ddd (mmm = 0xx) + * - - - - SDBD, MVI@ Rm, Rd + ***************************************************/ +void cp1610_cpu_device::cp1610_sdbd_mviat(int r, int d) +{ + m_r[d] = cp1610_readmem16(m_r[r]) & 0xff; + m_r[d] |= (cp1610_readmem16(m_r[r]) << 8); + m_icount -= 14; +} + +/*************************************************** + * S Z C OV 0x001 1 010 mmm ddd (mmm = 10x) + * - - - - SDBD, MVI@ Rm, Rd + ***************************************************/ +void cp1610_cpu_device::cp1610_sdbd_mviat_i(int r, int d) +{ + UINT16 temp; + temp = cp1610_readmem16(m_r[r]) & 0xff; + m_r[r]++; + m_r[d] = temp; + temp = (cp1610_readmem16(m_r[r]) << 8); + m_r[r]++; + m_r[d] |= temp; + m_icount -= 14; +} + +/*************************************************** + * S Z C OV 0x001 1 010 mmm ddd (mmm = 101) + * - - - - SDBD, MVI@ Rm, Rd + ***************************************************/ +void cp1610_cpu_device::cp1610_sdbd_mviat_d(int r, int d) +{ + m_r[r]--; + m_r[d] = cp1610_readmem16(m_r[r]) & 0xff; + m_r[r]--; + m_r[d] |= (cp1610_readmem16(m_r[r]) << 8); + m_icount -= 17; +} + +/************************************************************************ + * S Z C OV 0x001 1 010 111 ddd x xxx xLL LLL LLL x xxx xUU UUU UUU + * - - - - SDBD, MVII I-I, Rd + ************************************************************************/ +void cp1610_cpu_device::cp1610_sdbd_mvii(int d) +{ + UINT16 addr; + addr = cp1610_readop(m_r[7]) & 0xff; + m_r[7]++; + addr |= (cp1610_readop(m_r[7]) << 8); + m_r[7]++; + m_r[d] = addr; + m_icount -= 14; +} + +/*************************************************** + * S Z C OV 0x001 1 011 mmm ddd (mmm = 0xx) + * x x x x SDBD, ADD@ Rm, Rd + ***************************************************/ +void cp1610_cpu_device::cp1610_sdbd_addat(int r, int d) +{ + UINT16 temp; + CLR_SZOC; + temp = cp1610_readmem16(m_r[r]) & 0xff; + temp |= (cp1610_readmem16(m_r[r]) << 8); + SET_COV(m_r[d],temp,0); + m_r[d] += temp; + SET_SZ(m_r[d]); + m_icount -= 14; +} + +/*************************************************** + * S Z C OV 0x001 1 011 mmm ddd (mmm = 10x) + * x x x x SDBD, ADD@ Rm, Rd + ***************************************************/ +void cp1610_cpu_device::cp1610_sdbd_addat_i(int r, int d) +{ + UINT16 temp; + CLR_SZOC; + temp = cp1610_readmem16(m_r[r]) & 0xff; + m_r[r]++; + temp |= (cp1610_readmem16(m_r[r]) << 8); + m_r[r]++; + SET_COV(m_r[d],temp,0); + m_r[d] += temp; + SET_SZ(m_r[d]); + m_icount -= 14; +} + +/*************************************************** + * S Z C OV 0x001 1 011 mmm ddd (mmm = 101) + * x x x x SDBD, ADD@ Rm, Rd + ***************************************************/ +void cp1610_cpu_device::cp1610_sdbd_addat_d(int r, int d) +{ + UINT16 temp; + CLR_SZOC; + m_r[r]--; + temp = cp1610_readmem16(m_r[r]) & 0xff; + m_r[r]--; + temp |= (cp1610_readmem16(m_r[r]) << 8); + SET_COV(m_r[d],temp,0); + m_r[d] += temp; + SET_SZ(m_r[d]); + m_icount -= 17; +} + +/************************************************************************ + * S Z C OV 0x001 1 011 111 ddd x xxx xLL LLL LLL x xxx xUU UUU UUU + * x x x x SDBD, ADDI I-I, Rd + ************************************************************************/ +void cp1610_cpu_device::cp1610_sdbd_addi(int d) +{ + UINT16 addr; + UINT16 temp; + CLR_SZOC; + addr = cp1610_readop(m_r[7]) & 0xff; + m_r[7]++; + addr |= (cp1610_readop(m_r[7]) << 8); + m_r[7]++; + temp = addr; + SET_COV(m_r[d],temp,0); + m_r[d] += temp; + SET_SZ(m_r[d]); + m_icount -= 14; +} + +/*************************************************** + * S Z C OV 0x001 1 100 mmm ddd (mmm = 0xx) + * x x x x SDBD, SUB@ Rm, Rd + ***************************************************/ +void cp1610_cpu_device::cp1610_sdbd_subat(int r, int d) +{ + UINT32 temp; + CLR_SZOC; + temp = cp1610_readmem16(m_r[r]) & 0xff; + temp |= (cp1610_readmem16(m_r[r]) << 8); + temp = (temp ^ 0xffff) + 1; + SET_COV(m_r[d],temp,1); + temp &= 0xffff; + m_r[d] += temp; + SET_SZ(m_r[d]); + m_icount -= 14; +} + +/*************************************************** + * S Z C OV 0x001 1 100 mmm ddd (mmm = 10x) + * x x x x SDBD, SUB@ Rm, Rd + ***************************************************/ +void cp1610_cpu_device::cp1610_sdbd_subat_i(int r, int d) +{ + UINT32 temp; + CLR_SZOC; + temp = cp1610_readmem16(m_r[r]) & 0xff; + m_r[r]++; + temp |= (cp1610_readmem16(m_r[r]) << 8); + m_r[r]++; + temp = (temp ^ 0xffff) + 1; + SET_COV(m_r[d],temp,1); + temp &= 0xffff; + m_r[d] += temp; + SET_SZ(m_r[d]); + m_icount -= 14; +} + +/*************************************************** + * S Z C OV 0x001 1 100 mmm ddd (mmm = 101) + * x x x x SDBD, SUB@ Rm, Rd + ***************************************************/ +void cp1610_cpu_device::cp1610_sdbd_subat_d(int r, int d) +{ + UINT32 temp; + CLR_SZOC; + m_r[r]--; + temp = cp1610_readmem16(m_r[r]) & 0xff; + m_r[r]--; + temp |= (cp1610_readmem16(m_r[r]) << 8); + temp = (temp ^ 0xffff) + 1; + SET_COV(m_r[d],temp,1); + temp &= 0xffff; + m_r[d] += temp; + SET_SZ(m_r[d]); + m_icount -= 17; +} + +/************************************************************************ + * S Z C OV 0x001 1 100 111 ddd x xxx xLL LLL LLL x xxx xUU UUU UUU + * x x x x SDBD, SUBI I-I, Rd + ************************************************************************/ +void cp1610_cpu_device::cp1610_sdbd_subi(int d) +{ + UINT16 addr; + UINT32 temp; + CLR_SZOC; + addr = cp1610_readop(m_r[7]) & 0xff; + m_r[7]++; + addr |= (cp1610_readop(m_r[7]) << 8); + m_r[7]++; + temp = addr; + temp = (temp ^ 0xffff) + 1; + SET_COV(m_r[d],temp,1); + temp &= 0xffff; + m_r[d] += temp; + SET_SZ(m_r[d]); + m_icount -= 14; +} + +/*************************************************** + * S Z C OV 0x001 1 101 mmm ddd (mmm = 0xx) + * x x x x SDBD, CMP@ Rm, Rd + ***************************************************/ +void cp1610_cpu_device::cp1610_sdbd_cmpat(int r, int d) +{ + UINT32 temp; + UINT16 temp2; + CLR_SZOC; + temp = cp1610_readmem16(m_r[r]) & 0xff; + temp |= (cp1610_readmem16(m_r[r]) << 8); + temp = (temp ^ 0xffff) + 1; + SET_COV(m_r[d],temp,1); + temp &= 0xffff; + temp2 = m_r[d] + temp; + SET_SZ(temp2); + m_icount -= 14; +} + +/*************************************************** + * S Z C OV 0x001 1 101 mmm ddd (mmm = 10x) + * x x x x SDBD, CMP@ Rm, Rd + ***************************************************/ +void cp1610_cpu_device::cp1610_sdbd_cmpat_i(int r, int d) +{ + UINT32 temp; + UINT16 temp2; + CLR_SZOC; + temp = cp1610_readmem16(m_r[r]) & 0xff; + m_r[r]++; + temp |= (cp1610_readmem16(m_r[r]) << 8); + m_r[r]++; + temp = (temp ^ 0xffff) + 1; + SET_COV(m_r[d],temp,1); + temp &= 0xffff; + temp2 = m_r[d] + temp; + SET_SZ(temp2); + m_icount -= 14; +} + +/*************************************************** + * S Z C OV 0x001 1 101 mmm ddd (mmm = 101) + * x x x x SDBD, CMP@ Rm, Rd + ***************************************************/ +void cp1610_cpu_device::cp1610_sdbd_cmpat_d(int r, int d) +{ + UINT32 temp; + UINT16 temp2; + CLR_SZOC; + m_r[r]--; + temp = cp1610_readmem16(m_r[r]) & 0xff; + m_r[r]--; + temp |= (cp1610_readmem16(m_r[r]) << 8); + temp = (temp ^ 0xffff) + 1; + SET_COV(m_r[d],temp,1); + temp &= 0xffff; + temp2 = m_r[d] + temp; + SET_SZ(temp2); + m_icount -= 17; +} + +/************************************************************************ + * S Z C OV 0x001 1 101 111 ddd x xxx xLL LLL LLL x xxx xUU UUU UUU + * x x x x SDBD, CMPI I-I, Rd + ************************************************************************/ +void cp1610_cpu_device::cp1610_sdbd_cmpi(int d) +{ + UINT16 addr; + UINT32 temp; + UINT16 temp2; + CLR_SZOC; + addr = cp1610_readop(m_r[7]) & 0xff; + m_r[7]++; + addr |= (cp1610_readop(m_r[7]) << 8); + m_r[7]++; + temp = addr; + temp = (temp ^ 0xffff) + 1; + SET_COV(m_r[d],temp,1); + temp &= 0xffff; + temp2 = m_r[d] + temp; + SET_SZ(temp2); + m_icount -= 14; +} + +/*************************************************** + * S Z C OV 0x001 1 110 mmm ddd (mmm = 0xx) + * x x - - SDBD, AND@ Rm, Rd + ***************************************************/ +void cp1610_cpu_device::cp1610_sdbd_andat(int r, int d) +{ + UINT16 temp; + CLR_SZ; + temp = cp1610_readmem16(m_r[r]) & 0xff; + temp |= (cp1610_readmem16(m_r[r]) << 8); + m_r[d] &= temp; + SET_SZ(m_r[d]); + m_icount -= 14; +} + +/*************************************************** + * S Z C OV 0x001 1 110 mmm ddd (mmm = 10x) + * x x - - SDBD, AND@ Rm, Rd + ***************************************************/ +void cp1610_cpu_device::cp1610_sdbd_andat_i(int r, int d) +{ + UINT16 temp; + CLR_SZ; + temp = cp1610_readmem16(m_r[r]) & 0xff; + m_r[r]++; + temp |= (cp1610_readmem16(m_r[r]) << 8); + m_r[r]++; + m_r[d] &= temp; + SET_SZ(m_r[d]); + m_icount -= 14; +} + +/*************************************************** + * S Z C OV 0x001 1 110 mmm ddd (mmm = 101) + * x x - - SDBD, AND@ Rm, Rd + ***************************************************/ +void cp1610_cpu_device::cp1610_sdbd_andat_d(int r, int d) +{ + UINT16 temp; + CLR_SZ; + m_r[r]--; + temp = cp1610_readmem16(m_r[r]) & 0xff; + m_r[r]--; + temp |= (cp1610_readmem16(m_r[r]) << 8); + m_r[d] &= temp; + SET_SZ(m_r[d]); + m_icount -= 17; +} + +/************************************************************************ + * S Z C OV 0x001 1 110 111 ddd x xxx xLL LLL LLL x xxx xUU UUU UUU + * x x - - SDBD, ANDI I-I, Rd + ************************************************************************/ +void cp1610_cpu_device::cp1610_sdbd_andi(int d) +{ + UINT16 addr; + CLR_SZ; + addr = cp1610_readop(m_r[7]) & 0xff; + m_r[7]++; + addr |= (cp1610_readop(m_r[7]) << 8); + m_r[7]++; + m_r[d] &= addr; + SET_SZ(m_r[d]); + m_icount -= 14; +} + +/*************************************************** + * S Z C OV 0x001 1 111 mmm ddd (mmm = 0xx) + * x x - - SDBD, XOR@ Rm, Rd + ***************************************************/ +void cp1610_cpu_device::cp1610_sdbd_xorat(int r, int d) +{ + UINT16 temp; + CLR_SZ; + temp = cp1610_readmem16(m_r[r]) & 0xff; + temp |= (cp1610_readmem16(m_r[r]) << 8); + m_r[d] ^= temp; + SET_SZ(m_r[d]); + m_icount -= 14; +} + +/*************************************************** + * S Z C OV 0x001 1 111 mmm ddd (mmm = 10x) + * x x - - SDBD, XOR@ Rm, Rd + ***************************************************/ +void cp1610_cpu_device::cp1610_sdbd_xorat_i(int r, int d) +{ + UINT16 temp; + CLR_SZ; + temp = cp1610_readmem16(m_r[r]) & 0xff; + m_r[r]++; + temp |= (cp1610_readmem16(m_r[r]) << 8); + m_r[r]++; + m_r[d] ^= temp; + SET_SZ(m_r[d]); + m_icount -= 14; +} + +/*************************************************** + * S Z C OV 0x001 1 111 mmm ddd (mmm = 101) + * x x - - SDBD, XOR@ Rm, Rd + ***************************************************/ +void cp1610_cpu_device::cp1610_sdbd_xorat_d(int r, int d) +{ + UINT16 temp; + CLR_SZ; + m_r[r]--; + temp = cp1610_readmem16(m_r[r]) & 0xff; + m_r[r]--; + temp |= (cp1610_readmem16(m_r[r]) << 8); + m_r[d] ^= temp; + SET_SZ(m_r[d]); + m_icount -= 17; +} + +/************************************************************************ + * S Z C OV 0x001 1 111 111 ddd x xxx xLL LLL LLL x xxx xUU UUU UUU + * x x - - SDBD, XORI I-I, Rd + ************************************************************************/ +void cp1610_cpu_device::cp1610_sdbd_xori(int d) +{ + UINT16 addr; + CLR_SZ; + addr = cp1610_readop(m_r[7]) & 0xff; + m_r[7]++; + addr |= (cp1610_readop(m_r[7]) << 8); + m_r[7]++; + m_r[d] ^= addr; + SET_SZ(m_r[d]); + m_icount -= 14; +} + +/*************************************************** + * S Z C OV b baa aaa a00 x xxx xxa aaa aaa aaa + * - - - - JSR R1bb, ADDR + ***************************************************/ +void cp1610_cpu_device::cp1610_jsr(int r, UINT16 addr) +{ + m_r[r] = m_r[7]; + m_r[7] = addr; +} + +/*************************************************** + * S Z C OV b baa aaa a01 x xxx xxa aaa aaa aaa + * - - - - JSRE R1bb, ADDR + ***************************************************/ +void cp1610_cpu_device::cp1610_jsre(int r, UINT16 addr) +{ + m_r[r] = m_r[7]; + m_r[7] = addr; + m_intr_enabled = 1; +} + +/*************************************************** + * S Z C OV b baa aaa a10 x xxx xxa aaa aaa aaa + * - - - - JSRD R1bb, ADDR + ***************************************************/ +void cp1610_cpu_device::cp1610_jsrd(int r, UINT16 addr) +{ + m_r[r] = m_r[7]; + m_r[7] = addr; + m_intr_enabled = 0; +} + +/*************************************************** + * S Z C OV 1 1aa aaa a00 x xxx xxa aaa aaa aaa + * - - - - J ADDR + ***************************************************/ +void cp1610_cpu_device::cp1610_j(UINT16 addr) +{ + m_r[7] = addr; +} + +/*************************************************** + * S Z C OV 1 1aa aaa a01 x xxx xxa aaa aaa aaa + * - - - - JE ADDR + ***************************************************/ +void cp1610_cpu_device::cp1610_je(UINT16 addr) +{ + m_r[7] = addr; + m_intr_enabled = 1; +} + +/*************************************************** + * S Z C OV 1 1aa aaa a10 x xxx xxa aaa aaa aaa + * - - - - JD ADDR + ***************************************************/ +void cp1610_cpu_device::cp1610_jd(UINT16 addr) +{ + m_r[7] = addr; + m_intr_enabled = 0; +} + +void cp1610_cpu_device::cp1610_do_sdbd() +{ + UINT16 sdbdtype, dest; + + /* Even though SDBD is uninterruptable, we don't need to set the mask bit, + * because we already treat the SDBD prefixed instructions as uninterruptable + */ + //m_mask_interrupts = 1; + + sdbdtype = cp1610_readop(m_r[7]); + dest = sdbdtype & 0x07; + m_r[7]++; + + switch (sdbdtype & 0x3f8) + { + case 0x240: /* Not supporting SDBD MVO@ or SDBD MVOI for now */ + case 0x248: + case 0x250: + case 0x258: + case 0x260: + case 0x268: + case 0x270: + case 0x278: /* 1 001 xxx xxx */ cp1610_illegal(); break; + + case 0x280: /* 1 010 000 xxx */ cp1610_sdbd_mviat(0,dest); break; + case 0x288: /* 1 010 001 xxx */ cp1610_sdbd_mviat(1,dest); break; + case 0x290: /* 1 010 010 xxx */ cp1610_sdbd_mviat(2,dest); break; + case 0x298: /* 1 010 011 xxx */ cp1610_sdbd_mviat(3,dest); break; + case 0x2a0: /* 1 010 100 xxx */ cp1610_sdbd_mviat_i(4,dest); break; + case 0x2a8: /* 1 010 101 xxx */ cp1610_sdbd_mviat_i(5,dest); break; + case 0x2b0: /* 1 010 110 xxx */ cp1610_sdbd_mviat_d(6,dest); break; /* ??? */ + case 0x2b8: /* 1 010 111 xxx */ cp1610_sdbd_mvii(dest); break; + + case 0x2c0: /* 1 011 000 xxx */ cp1610_sdbd_addat(0,dest); break; + case 0x2c8: /* 1 011 001 xxx */ cp1610_sdbd_addat(1,dest); break; + case 0x2d0: /* 1 011 010 xxx */ cp1610_sdbd_addat(2,dest); break; + case 0x2d8: /* 1 011 011 xxx */ cp1610_sdbd_addat(3,dest); break; + case 0x2e0: /* 1 011 100 xxx */ cp1610_sdbd_addat_i(4,dest); break; + case 0x2e8: /* 1 011 101 xxx */ cp1610_sdbd_addat_i(5,dest); break; + case 0x2f0: /* 1 011 110 xxx */ cp1610_sdbd_addat_d(6,dest); break; /* ??? */ + case 0x2f8: /* 1 011 111 xxx */ cp1610_sdbd_addi(dest); break; + + case 0x300: /* 1 100 000 xxx */ cp1610_sdbd_subat(0,dest); break; + case 0x308: /* 1 100 001 xxx */ cp1610_sdbd_subat(1,dest); break; + case 0x310: /* 1 100 010 xxx */ cp1610_sdbd_subat(2,dest); break; + case 0x318: /* 1 100 011 xxx */ cp1610_sdbd_subat(3,dest); break; + case 0x320: /* 1 100 100 xxx */ cp1610_sdbd_subat_i(4,dest); break; + case 0x328: /* 1 100 101 xxx */ cp1610_sdbd_subat_i(5,dest); break; + case 0x330: /* 1 100 110 xxx */ cp1610_sdbd_subat_d(6,dest); break; /* ??? */ + case 0x338: /* 1 100 111 xxx */ cp1610_sdbd_subi(dest); break; + + case 0x340: /* 1 101 000 xxx */ cp1610_sdbd_cmpat(0,dest); break; + case 0x348: /* 1 101 001 xxx */ cp1610_sdbd_cmpat(1,dest); break; + case 0x350: /* 1 101 010 xxx */ cp1610_sdbd_cmpat(2,dest); break; + case 0x358: /* 1 101 011 xxx */ cp1610_sdbd_cmpat(3,dest); break; + case 0x360: /* 1 101 100 xxx */ cp1610_sdbd_cmpat_i(4,dest); break; + case 0x368: /* 1 101 101 xxx */ cp1610_sdbd_cmpat_i(5,dest); break; + case 0x370: /* 1 101 110 xxx */ cp1610_sdbd_cmpat_d(6,dest); break; /* ??? */ + case 0x378: /* 1 101 111 xxx */ cp1610_sdbd_cmpi(dest); break; + + case 0x380: /* 1 110 000 xxx */ cp1610_sdbd_andat(0,dest); break; + case 0x388: /* 1 110 001 xxx */ cp1610_sdbd_andat(1,dest); break; + case 0x390: /* 1 110 010 xxx */ cp1610_sdbd_andat(2,dest); break; + case 0x398: /* 1 110 011 xxx */ cp1610_sdbd_andat(3,dest); break; + case 0x3a0: /* 1 110 100 xxx */ cp1610_sdbd_andat_i(4,dest); break; + case 0x3a8: /* 1 110 101 xxx */ cp1610_sdbd_andat_i(5,dest); break; + case 0x3b0: /* 1 110 110 xxx */ cp1610_sdbd_andat_d(6,dest); break; /* ??? */ + case 0x3b8: /* 1 110 111 xxx */ cp1610_sdbd_andi(dest); break; + + case 0x3c0: /* 1 110 000 xxx */ cp1610_sdbd_xorat(0,dest); break; + case 0x3c8: /* 1 110 001 xxx */ cp1610_sdbd_xorat(1,dest); break; + case 0x3d0: /* 1 110 010 xxx */ cp1610_sdbd_xorat(2,dest); break; + case 0x3d8: /* 1 110 011 xxx */ cp1610_sdbd_xorat(3,dest); break; + case 0x3e0: /* 1 110 100 xxx */ cp1610_sdbd_xorat_i(4,dest); break; + case 0x3e8: /* 1 110 101 xxx */ cp1610_sdbd_xorat_i(5,dest); break; + case 0x3f0: /* 1 110 110 xxx */ cp1610_sdbd_xorat_d(6,dest); break; /* ??? */ + case 0x3f8: /* 1 110 111 xxx */ cp1610_sdbd_xori(dest); break; + default: cp1610_illegal(); break; + } +} + +void cp1610_cpu_device::cp1610_do_jumps() +{ + UINT16 jumptype, arg1, arg2, addr; + + arg1 = cp1610_readop(m_r[7]); + m_r[7]++; + + arg2 = cp1610_readop(m_r[7]); + m_r[7]++; + + /*logerror("jumps: pc = 0x%04x, arg1 = 0x%04x, arg2 = 0x%04x\n",m_r[7]-1,arg1,arg2);*/ + jumptype = arg1 & 0x303; + addr = ((arg1 & 0x0fc) << 8) | (arg2 & 0x3ff); + + switch( jumptype ) + { + case 0x000: /* 0 0xx xxx x00 */ cp1610_jsr(4,addr); break; + case 0x001: /* 0 0xx xxx x01 */ cp1610_jsre(4,addr); break; + case 0x002: /* 0 0xx xxx x10 */ cp1610_jsrd(4,addr); break; + case 0x003: /* 0 0xx xxx x11 */ cp1610_illegal(); break; + + case 0x100: /* 0 1xx xxx x00 */ cp1610_jsr(5,addr); break; + case 0x101: /* 0 1xx xxx x01 */ cp1610_jsre(5,addr); break; + case 0x102: /* 0 1xx xxx x10 */ cp1610_jsrd(5,addr); break; + case 0x103: /* 0 1xx xxx x11 */ cp1610_illegal(); break; + + case 0x200: /* 1 0xx xxx x00 */ cp1610_jsr(6,addr); break; + case 0x201: /* 1 0xx xxx x01 */ cp1610_jsre(6,addr); break; + case 0x202: /* 1 0xx xxx x10 */ cp1610_jsrd(6,addr); break; + case 0x203: /* 1 0xx xxx x11 */ cp1610_illegal(); break; + + case 0x300: /* 1 1xx xxx x00 */ cp1610_j(addr); break; + case 0x301: /* 1 1xx xxx x01 */ cp1610_je(addr); break; + case 0x302: /* 1 1xx xxx x10 */ cp1610_jd(addr); break; + case 0x303: /* 1 1xx xxx x11 */ cp1610_illegal(); break; + } + + m_icount -= 12; +} + +/* Execute cycles */ +void cp1610_cpu_device::execute_run() +{ + UINT16 opcode; + + do + { + debugger_instruction_hook(this, m_r[7]); + + m_mask_interrupts = 0; + + opcode = cp1610_readop(m_r[7]); + m_r[7]++; +#if 0 + logerror("PC:0x%04x, opcode = 0x%03x, ",m_r[7]-1,opcode); + logerror("R0:0x%04x, ",m_r[0]); + logerror("R1:0x%04x, ",m_r[1]); + logerror("R2:0x%04x, ",m_r[2]); + logerror("R3:0x%04x, ",m_r[3]); + logerror("R4:0x%04x, ",m_r[4]); + logerror("R5:0x%04x, ",m_r[5]); + logerror("R6:0x%04x\n",m_r[6]); +#endif + + switch( opcode ) + { + /* opcode bitmask */ + case 0x000: /* 0 000 000 000 */ cp1610_hlt(); break; /* TBD */ + case 0x001: /* 0 000 000 001 */ cp1610_do_sdbd(); break; + case 0x002: /* 0 000 000 010 */ cp1610_eis(); break; /* TBD */ + case 0x003: /* 0 000 000 011 */ cp1610_dis(); break; /* TBD */ + case 0x004: /* 0 000 000 100 */ cp1610_do_jumps(); break; + case 0x005: /* 0 000 000 101 */ cp1610_tci(); break; /* TBD */ + case 0x006: /* 0 000 000 110 */ cp1610_clrc(); break; + case 0x007: /* 0 000 000 111 */ cp1610_setc(); break; + + case 0x008: /* 0 000 001 000 */ cp1610_incr(0); break; + case 0x009: /* 0 000 001 001 */ cp1610_incr(1); break; + case 0x00a: /* 0 000 001 010 */ cp1610_incr(2); break; + case 0x00b: /* 0 000 001 011 */ cp1610_incr(3); break; + case 0x00c: /* 0 000 001 100 */ cp1610_incr(4); break; + case 0x00d: /* 0 000 001 101 */ cp1610_incr(5); break; + case 0x00e: /* 0 000 001 110 */ cp1610_incr(6); break; + case 0x00f: /* 0 000 001 111 */ cp1610_incr(7); break; + + case 0x010: /* 0 000 010 000 */ cp1610_decr(0); break; + case 0x011: /* 0 000 010 001 */ cp1610_decr(1); break; + case 0x012: /* 0 000 010 010 */ cp1610_decr(2); break; + case 0x013: /* 0 000 010 011 */ cp1610_decr(3); break; + case 0x014: /* 0 000 010 100 */ cp1610_decr(4); break; + case 0x015: /* 0 000 010 101 */ cp1610_decr(5); break; + case 0x016: /* 0 000 010 110 */ cp1610_decr(6); break; + case 0x017: /* 0 000 010 111 */ cp1610_decr(7); break; + + case 0x018: /* 0 000 011 000 */ cp1610_comr(0); break; + case 0x019: /* 0 000 011 001 */ cp1610_comr(1); break; + case 0x01a: /* 0 000 011 010 */ cp1610_comr(2); break; + case 0x01b: /* 0 000 011 011 */ cp1610_comr(3); break; + case 0x01c: /* 0 000 011 100 */ cp1610_comr(4); break; + case 0x01d: /* 0 000 011 101 */ cp1610_comr(5); break; + case 0x01e: /* 0 000 011 110 */ cp1610_comr(6); break; + case 0x01f: /* 0 000 011 111 */ cp1610_comr(7); break; + + case 0x020: /* 0 000 100 000 */ cp1610_negr(0); break; + case 0x021: /* 0 000 100 001 */ cp1610_negr(1); break; + case 0x022: /* 0 000 100 010 */ cp1610_negr(2); break; + case 0x023: /* 0 000 100 011 */ cp1610_negr(3); break; + case 0x024: /* 0 000 100 100 */ cp1610_negr(4); break; + case 0x025: /* 0 000 100 101 */ cp1610_negr(5); break; + case 0x026: /* 0 000 100 110 */ cp1610_negr(6); break; + case 0x027: /* 0 000 100 111 */ cp1610_negr(7); break; + + case 0x028: /* 0 000 101 000 */ cp1610_adcr(0); break; + case 0x029: /* 0 000 101 001 */ cp1610_adcr(1); break; + case 0x02a: /* 0 000 101 010 */ cp1610_adcr(2); break; + case 0x02b: /* 0 000 101 011 */ cp1610_adcr(3); break; + case 0x02c: /* 0 000 101 100 */ cp1610_adcr(4); break; + case 0x02d: /* 0 000 101 101 */ cp1610_adcr(5); break; + case 0x02e: /* 0 000 101 110 */ cp1610_adcr(6); break; + case 0x02f: /* 0 000 101 111 */ cp1610_adcr(7); break; + + case 0x030: /* 0 000 110 000 */ cp1610_gswd(0); break; + case 0x031: /* 0 000 110 001 */ cp1610_gswd(1); break; + case 0x032: /* 0 000 110 010 */ cp1610_gswd(2); break; + case 0x033: /* 0 000 110 011 */ cp1610_gswd(3); break; + case 0x034: /* 0 000 110 100 */ cp1610_nop(); break; + case 0x035: /* 0 000 110 101 */ cp1610_nop(); break; + case 0x036: /* 0 000 110 110 */ cp1610_sin(); break; /* TBD */ + case 0x037: /* 0 000 110 111 */ cp1610_sin(); break; /* TBD */ + + case 0x038: /* 0 000 111 000 */ cp1610_rswd(0); break; + case 0x039: /* 0 000 111 001 */ cp1610_rswd(1); break; + case 0x03a: /* 0 000 111 010 */ cp1610_rswd(2); break; + case 0x03b: /* 0 000 111 011 */ cp1610_rswd(3); break; + case 0x03c: /* 0 000 111 100 */ cp1610_rswd(4); break; + case 0x03d: /* 0 000 111 101 */ cp1610_rswd(5); break; + case 0x03e: /* 0 000 111 110 */ cp1610_rswd(6); break; + case 0x03f: /* 0 000 111 111 */ cp1610_rswd(7); break; + + case 0x040: /* 0 001 000 000 */ cp1610_swap(0); break; + case 0x041: /* 0 001 000 001 */ cp1610_swap(1); break; + case 0x042: /* 0 001 000 010 */ cp1610_swap(2); break; + case 0x043: /* 0 001 000 011 */ cp1610_swap(3); break; + case 0x044: /* 0 001 000 100 */ cp1610_dswap(0); break; + case 0x045: /* 0 001 000 101 */ cp1610_dswap(1); break; + case 0x046: /* 0 001 000 110 */ cp1610_dswap(2); break; + case 0x047: /* 0 001 000 111 */ cp1610_dswap(3); break; + + case 0x048: /* 0 001 001 000 */ cp1610_sll_1(0); break; + case 0x049: /* 0 001 001 001 */ cp1610_sll_1(1); break; + case 0x04a: /* 0 001 001 010 */ cp1610_sll_1(2); break; + case 0x04b: /* 0 001 001 011 */ cp1610_sll_1(3); break; + case 0x04c: /* 0 001 001 100 */ cp1610_sll_2(0); break; + case 0x04d: /* 0 001 001 101 */ cp1610_sll_2(1); break; + case 0x04e: /* 0 001 001 110 */ cp1610_sll_2(2); break; + case 0x04f: /* 0 001 001 111 */ cp1610_sll_2(3); break; + + case 0x050: /* 0 001 010 000 */ cp1610_rlc_1(0); break; + case 0x051: /* 0 001 010 001 */ cp1610_rlc_1(1); break; + case 0x052: /* 0 001 010 010 */ cp1610_rlc_1(2); break; + case 0x053: /* 0 001 010 011 */ cp1610_rlc_1(3); break; + case 0x054: /* 0 001 010 100 */ cp1610_rlc_2(0); break; + case 0x055: /* 0 001 010 101 */ cp1610_rlc_2(1); break; + case 0x056: /* 0 001 010 110 */ cp1610_rlc_2(2); break; + case 0x057: /* 0 001 010 111 */ cp1610_rlc_2(3); break; + + case 0x058: /* 0 001 011 000 */ cp1610_sllc_1(0); break; + case 0x059: /* 0 001 011 001 */ cp1610_sllc_1(1); break; + case 0x05a: /* 0 001 011 010 */ cp1610_sllc_1(2); break; + case 0x05b: /* 0 001 011 011 */ cp1610_sllc_1(3); break; + case 0x05c: /* 0 001 011 100 */ cp1610_sllc_2(0); break; + case 0x05d: /* 0 001 011 101 */ cp1610_sllc_2(1); break; + case 0x05e: /* 0 001 011 110 */ cp1610_sllc_2(2); break; + case 0x05f: /* 0 001 011 111 */ cp1610_sllc_2(3); break; + + case 0x060: /* 0 001 100 000 */ cp1610_slr_1(0); break; + case 0x061: /* 0 001 100 001 */ cp1610_slr_1(1); break; + case 0x062: /* 0 001 100 010 */ cp1610_slr_1(2); break; + case 0x063: /* 0 001 100 011 */ cp1610_slr_1(3); break; + case 0x064: /* 0 001 100 100 */ cp1610_slr_2(0); break; + case 0x065: /* 0 001 100 101 */ cp1610_slr_2(1); break; + case 0x066: /* 0 001 100 110 */ cp1610_slr_2(2); break; + case 0x067: /* 0 001 100 111 */ cp1610_slr_2(3); break; + + case 0x068: /* 0 001 101 000 */ cp1610_sar_1(0); break; + case 0x069: /* 0 001 101 001 */ cp1610_sar_1(1); break; + case 0x06a: /* 0 001 101 010 */ cp1610_sar_1(2); break; + case 0x06b: /* 0 001 101 011 */ cp1610_sar_1(3); break; + case 0x06c: /* 0 001 101 100 */ cp1610_sar_2(0); break; + case 0x06d: /* 0 001 101 101 */ cp1610_sar_2(1); break; + case 0x06e: /* 0 001 101 110 */ cp1610_sar_2(2); break; + case 0x06f: /* 0 001 101 111 */ cp1610_sar_2(3); break; + + case 0x070: /* 0 001 110 000 */ cp1610_rrc_1(0); break; + case 0x071: /* 0 001 110 001 */ cp1610_rrc_1(1); break; + case 0x072: /* 0 001 110 010 */ cp1610_rrc_1(2); break; + case 0x073: /* 0 001 110 011 */ cp1610_rrc_1(3); break; + case 0x074: /* 0 001 110 100 */ cp1610_rrc_2(0); break; + case 0x075: /* 0 001 110 101 */ cp1610_rrc_2(1); break; + case 0x076: /* 0 001 110 110 */ cp1610_rrc_2(2); break; + case 0x077: /* 0 001 110 111 */ cp1610_rrc_2(3); break; + + case 0x078: /* 0 001 111 000 */ cp1610_sarc_1(0); break; + case 0x079: /* 0 001 111 001 */ cp1610_sarc_1(1); break; + case 0x07a: /* 0 001 111 010 */ cp1610_sarc_1(2); break; + case 0x07b: /* 0 001 111 011 */ cp1610_sarc_1(3); break; + case 0x07c: /* 0 001 111 100 */ cp1610_sarc_2(0); break; + case 0x07d: /* 0 001 111 101 */ cp1610_sarc_2(1); break; + case 0x07e: /* 0 001 111 110 */ cp1610_sarc_2(2); break; + case 0x07f: /* 0 001 111 111 */ cp1610_sarc_2(3); break; + + case 0x080: /* 0 010 000 000 */ cp1610_tstr(0); break; + case 0x081: /* 0 010 000 001 */ cp1610_movr(0,1); break; + case 0x082: /* 0 010 000 010 */ cp1610_movr(0,2); break; + case 0x083: /* 0 010 000 011 */ cp1610_movr(0,3); break; + case 0x084: /* 0 010 000 100 */ cp1610_movr(0,4); break; + case 0x085: /* 0 010 000 101 */ cp1610_movr(0,5); break; + case 0x086: /* 0 010 000 110 */ cp1610_movr(0,6); break; + case 0x087: /* 0 010 000 111 */ cp1610_movr(0,7); break; /* jr */ + + case 0x088: /* 0 010 001 000 */ cp1610_movr(1,0); break; + case 0x089: /* 0 010 001 001 */ cp1610_tstr(1); break; + case 0x08a: /* 0 010 001 010 */ cp1610_movr(1,2); break; + case 0x08b: /* 0 010 001 011 */ cp1610_movr(1,3); break; + case 0x08c: /* 0 010 001 100 */ cp1610_movr(1,4); break; + case 0x08d: /* 0 010 001 101 */ cp1610_movr(1,5); break; + case 0x08e: /* 0 010 001 110 */ cp1610_movr(1,6); break; + case 0x08f: /* 0 010 001 111 */ cp1610_movr(1,7); break; /* jr */ + + case 0x090: /* 0 010 010 000 */ cp1610_movr(2,0); break; + case 0x091: /* 0 010 010 001 */ cp1610_movr(2,1); break; + case 0x092: /* 0 010 010 010 */ cp1610_tstr(2); break; + case 0x093: /* 0 010 010 011 */ cp1610_movr(2,3); break; + case 0x094: /* 0 010 010 100 */ cp1610_movr(2,4); break; + case 0x095: /* 0 010 010 101 */ cp1610_movr(2,5); break; + case 0x096: /* 0 010 010 110 */ cp1610_movr(2,6); break; + case 0x097: /* 0 010 010 111 */ cp1610_movr(2,7); break; /* jr */ + + case 0x098: /* 0 010 011 000 */ cp1610_movr(3,0); break; + case 0x099: /* 0 010 011 001 */ cp1610_movr(3,1); break; + case 0x09a: /* 0 010 011 010 */ cp1610_movr(3,2); break; + case 0x09b: /* 0 010 011 011 */ cp1610_tstr(3); break; + case 0x09c: /* 0 010 011 100 */ cp1610_movr(3,4); break; + case 0x09d: /* 0 010 011 101 */ cp1610_movr(3,5); break; + case 0x09e: /* 0 010 011 110 */ cp1610_movr(3,6); break; + case 0x09f: /* 0 010 011 111 */ cp1610_movr(3,7); break; /* jr */ + + case 0x0a0: /* 0 010 100 000 */ cp1610_movr(4,0); break; + case 0x0a1: /* 0 010 100 001 */ cp1610_movr(4,1); break; + case 0x0a2: /* 0 010 100 010 */ cp1610_movr(4,2); break; + case 0x0a3: /* 0 010 100 011 */ cp1610_movr(4,3); break; + case 0x0a4: /* 0 010 100 100 */ cp1610_tstr(4); break; + case 0x0a5: /* 0 010 100 101 */ cp1610_movr(4,5); break; + case 0x0a6: /* 0 010 100 110 */ cp1610_movr(4,6); break; + case 0x0a7: /* 0 010 100 111 */ cp1610_movr(4,7); break; /* jr */ + + case 0x0a8: /* 0 010 101 000 */ cp1610_movr(5,0); break; + case 0x0a9: /* 0 010 101 001 */ cp1610_movr(5,1); break; + case 0x0aa: /* 0 010 101 010 */ cp1610_movr(5,2); break; + case 0x0ab: /* 0 010 101 011 */ cp1610_movr(5,3); break; + case 0x0ac: /* 0 010 101 100 */ cp1610_movr(5,4); break; + case 0x0ad: /* 0 010 101 101 */ cp1610_tstr(5); break; + case 0x0ae: /* 0 010 101 110 */ cp1610_movr(5,6); break; + case 0x0af: /* 0 010 101 111 */ cp1610_movr(5,7); break; /* jr */ + + case 0x0b0: /* 0 010 110 000 */ cp1610_movr(6,0); break; + case 0x0b1: /* 0 010 110 001 */ cp1610_movr(6,1); break; + case 0x0b2: /* 0 010 110 010 */ cp1610_movr(6,2); break; + case 0x0b3: /* 0 010 110 011 */ cp1610_movr(6,3); break; + case 0x0b4: /* 0 010 110 100 */ cp1610_movr(6,4); break; + case 0x0b5: /* 0 010 110 101 */ cp1610_movr(6,5); break; + case 0x0b6: /* 0 010 110 110 */ cp1610_tstr(6); break; + case 0x0b7: /* 0 010 110 111 */ cp1610_movr(6,7); break; /* jr */ + + case 0x0b8: /* 0 010 111 000 */ cp1610_movr(7,0); break; + case 0x0b9: /* 0 010 111 001 */ cp1610_movr(7,1); break; + case 0x0ba: /* 0 010 111 010 */ cp1610_movr(7,2); break; + case 0x0bb: /* 0 010 111 011 */ cp1610_movr(7,3); break; + case 0x0bc: /* 0 010 111 100 */ cp1610_movr(7,4); break; + case 0x0bd: /* 0 010 111 101 */ cp1610_movr(7,5); break; + case 0x0be: /* 0 010 111 110 */ cp1610_movr(7,6); break; + case 0x0bf: /* 0 010 111 111 */ cp1610_tstr(7); break; + + case 0x0c0: /* 0 011 000 000 */ cp1610_addr(0,0); break; + case 0x0c1: /* 0 011 000 001 */ cp1610_addr(0,1); break; + case 0x0c2: /* 0 011 000 010 */ cp1610_addr(0,2); break; + case 0x0c3: /* 0 011 000 011 */ cp1610_addr(0,3); break; + case 0x0c4: /* 0 011 000 100 */ cp1610_addr(0,4); break; + case 0x0c5: /* 0 011 000 101 */ cp1610_addr(0,5); break; + case 0x0c6: /* 0 011 000 110 */ cp1610_addr(0,6); break; + case 0x0c7: /* 0 011 000 111 */ cp1610_addr(0,7); break; + + case 0x0c8: /* 0 011 001 000 */ cp1610_addr(1,0); break; + case 0x0c9: /* 0 011 001 001 */ cp1610_addr(1,1); break; + case 0x0ca: /* 0 011 001 010 */ cp1610_addr(1,2); break; + case 0x0cb: /* 0 011 001 011 */ cp1610_addr(1,3); break; + case 0x0cc: /* 0 011 001 100 */ cp1610_addr(1,4); break; + case 0x0cd: /* 0 011 001 101 */ cp1610_addr(1,5); break; + case 0x0ce: /* 0 011 001 110 */ cp1610_addr(1,6); break; + case 0x0cf: /* 0 011 001 111 */ cp1610_addr(1,7); break; + + case 0x0d0: /* 0 011 010 000 */ cp1610_addr(2,0); break; + case 0x0d1: /* 0 011 010 001 */ cp1610_addr(2,1); break; + case 0x0d2: /* 0 011 010 010 */ cp1610_addr(2,2); break; + case 0x0d3: /* 0 011 010 011 */ cp1610_addr(2,3); break; + case 0x0d4: /* 0 011 010 100 */ cp1610_addr(2,4); break; + case 0x0d5: /* 0 011 010 101 */ cp1610_addr(2,5); break; + case 0x0d6: /* 0 011 010 110 */ cp1610_addr(2,6); break; + case 0x0d7: /* 0 011 010 111 */ cp1610_addr(2,7); break; + + case 0x0d8: /* 0 011 011 000 */ cp1610_addr(3,0); break; + case 0x0d9: /* 0 011 011 001 */ cp1610_addr(3,1); break; + case 0x0da: /* 0 011 011 010 */ cp1610_addr(3,2); break; + case 0x0db: /* 0 011 011 011 */ cp1610_addr(3,3); break; + case 0x0dc: /* 0 011 011 100 */ cp1610_addr(3,4); break; + case 0x0dd: /* 0 011 011 101 */ cp1610_addr(3,5); break; + case 0x0de: /* 0 011 011 110 */ cp1610_addr(3,6); break; + case 0x0df: /* 0 011 011 111 */ cp1610_addr(3,7); break; + + case 0x0e0: /* 0 011 100 000 */ cp1610_addr(4,0); break; + case 0x0e1: /* 0 011 100 001 */ cp1610_addr(4,1); break; + case 0x0e2: /* 0 011 100 010 */ cp1610_addr(4,2); break; + case 0x0e3: /* 0 011 100 011 */ cp1610_addr(4,3); break; + case 0x0e4: /* 0 011 100 100 */ cp1610_addr(4,4); break; + case 0x0e5: /* 0 011 100 101 */ cp1610_addr(4,5); break; + case 0x0e6: /* 0 011 100 110 */ cp1610_addr(4,6); break; + case 0x0e7: /* 0 011 100 111 */ cp1610_addr(4,7); break; + + case 0x0e8: /* 0 011 101 000 */ cp1610_addr(5,0); break; + case 0x0e9: /* 0 011 101 001 */ cp1610_addr(5,1); break; + case 0x0ea: /* 0 011 101 010 */ cp1610_addr(5,2); break; + case 0x0eb: /* 0 011 101 011 */ cp1610_addr(5,3); break; + case 0x0ec: /* 0 011 101 100 */ cp1610_addr(5,4); break; + case 0x0ed: /* 0 011 101 101 */ cp1610_addr(5,5); break; + case 0x0ee: /* 0 011 101 110 */ cp1610_addr(5,6); break; + case 0x0ef: /* 0 011 101 111 */ cp1610_addr(5,7); break; + + case 0x0f0: /* 0 011 110 000 */ cp1610_addr(6,0); break; + case 0x0f1: /* 0 011 110 001 */ cp1610_addr(6,1); break; + case 0x0f2: /* 0 011 110 010 */ cp1610_addr(6,2); break; + case 0x0f3: /* 0 011 110 011 */ cp1610_addr(6,3); break; + case 0x0f4: /* 0 011 110 100 */ cp1610_addr(6,4); break; + case 0x0f5: /* 0 011 110 101 */ cp1610_addr(6,5); break; + case 0x0f6: /* 0 011 110 110 */ cp1610_addr(6,6); break; + case 0x0f7: /* 0 011 110 111 */ cp1610_addr(6,7); break; + + case 0x0f8: /* 0 011 111 000 */ cp1610_addr(7,0); break; + case 0x0f9: /* 0 011 111 001 */ cp1610_addr(7,1); break; + case 0x0fa: /* 0 011 111 010 */ cp1610_addr(7,2); break; + case 0x0fb: /* 0 011 111 011 */ cp1610_addr(7,3); break; + case 0x0fc: /* 0 011 111 100 */ cp1610_addr(7,4); break; + case 0x0fd: /* 0 011 111 101 */ cp1610_addr(7,5); break; + case 0x0fe: /* 0 011 111 110 */ cp1610_addr(7,6); break; + case 0x0ff: /* 0 011 111 111 */ cp1610_addr(7,7); break; + + case 0x100: /* 0 100 000 000 */ cp1610_subr(0,0); break; + case 0x101: /* 0 100 000 001 */ cp1610_subr(0,1); break; + case 0x102: /* 0 100 000 010 */ cp1610_subr(0,2); break; + case 0x103: /* 0 100 000 011 */ cp1610_subr(0,3); break; + case 0x104: /* 0 100 000 100 */ cp1610_subr(0,4); break; + case 0x105: /* 0 100 000 101 */ cp1610_subr(0,5); break; + case 0x106: /* 0 100 000 110 */ cp1610_subr(0,6); break; + case 0x107: /* 0 100 000 111 */ cp1610_subr(0,7); break; + + case 0x108: /* 0 100 001 000 */ cp1610_subr(1,0); break; + case 0x109: /* 0 100 001 001 */ cp1610_subr(1,1); break; + case 0x10a: /* 0 100 001 010 */ cp1610_subr(1,2); break; + case 0x10b: /* 0 100 001 011 */ cp1610_subr(1,3); break; + case 0x10c: /* 0 100 001 100 */ cp1610_subr(1,4); break; + case 0x10d: /* 0 100 001 101 */ cp1610_subr(1,5); break; + case 0x10e: /* 0 100 001 110 */ cp1610_subr(1,6); break; + case 0x10f: /* 0 100 001 111 */ cp1610_subr(1,7); break; + + case 0x110: /* 0 100 010 000 */ cp1610_subr(2,0); break; + case 0x111: /* 0 100 010 001 */ cp1610_subr(2,1); break; + case 0x112: /* 0 100 010 010 */ cp1610_subr(2,2); break; + case 0x113: /* 0 100 010 011 */ cp1610_subr(2,3); break; + case 0x114: /* 0 100 010 100 */ cp1610_subr(2,4); break; + case 0x115: /* 0 100 010 101 */ cp1610_subr(2,5); break; + case 0x116: /* 0 100 010 110 */ cp1610_subr(2,6); break; + case 0x117: /* 0 100 010 111 */ cp1610_subr(2,7); break; + + case 0x118: /* 0 100 011 000 */ cp1610_subr(3,0); break; + case 0x119: /* 0 100 011 001 */ cp1610_subr(3,1); break; + case 0x11a: /* 0 100 011 010 */ cp1610_subr(3,2); break; + case 0x11b: /* 0 100 011 011 */ cp1610_subr(3,3); break; + case 0x11c: /* 0 100 011 100 */ cp1610_subr(3,4); break; + case 0x11d: /* 0 100 011 101 */ cp1610_subr(3,5); break; + case 0x11e: /* 0 100 011 110 */ cp1610_subr(3,6); break; + case 0x11f: /* 0 100 011 111 */ cp1610_subr(3,7); break; + + case 0x120: /* 0 100 100 000 */ cp1610_subr(4,0); break; + case 0x121: /* 0 100 100 001 */ cp1610_subr(4,1); break; + case 0x122: /* 0 100 100 010 */ cp1610_subr(4,2); break; + case 0x123: /* 0 100 100 011 */ cp1610_subr(4,3); break; + case 0x124: /* 0 100 100 100 */ cp1610_subr(4,4); break; + case 0x125: /* 0 100 100 101 */ cp1610_subr(4,5); break; + case 0x126: /* 0 100 100 110 */ cp1610_subr(4,6); break; + case 0x127: /* 0 100 100 111 */ cp1610_subr(4,7); break; + + case 0x128: /* 0 100 101 000 */ cp1610_subr(5,0); break; + case 0x129: /* 0 100 101 001 */ cp1610_subr(5,1); break; + case 0x12a: /* 0 100 101 010 */ cp1610_subr(5,2); break; + case 0x12b: /* 0 100 101 011 */ cp1610_subr(5,3); break; + case 0x12c: /* 0 100 101 100 */ cp1610_subr(5,4); break; + case 0x12d: /* 0 100 101 101 */ cp1610_subr(5,5); break; + case 0x12e: /* 0 100 101 110 */ cp1610_subr(5,6); break; + case 0x12f: /* 0 100 101 111 */ cp1610_subr(5,7); break; + + case 0x130: /* 0 100 110 000 */ cp1610_subr(6,0); break; + case 0x131: /* 0 100 110 001 */ cp1610_subr(6,1); break; + case 0x132: /* 0 100 110 010 */ cp1610_subr(6,2); break; + case 0x133: /* 0 100 110 011 */ cp1610_subr(6,3); break; + case 0x134: /* 0 100 110 100 */ cp1610_subr(6,4); break; + case 0x135: /* 0 100 110 101 */ cp1610_subr(6,5); break; + case 0x136: /* 0 100 110 110 */ cp1610_subr(6,6); break; + case 0x137: /* 0 100 110 111 */ cp1610_subr(6,7); break; + + case 0x138: /* 0 100 111 000 */ cp1610_subr(7,0); break; + case 0x139: /* 0 100 111 001 */ cp1610_subr(7,1); break; + case 0x13a: /* 0 100 111 010 */ cp1610_subr(7,2); break; + case 0x13b: /* 0 100 111 011 */ cp1610_subr(7,3); break; + case 0x13c: /* 0 100 111 100 */ cp1610_subr(7,4); break; + case 0x13d: /* 0 100 111 101 */ cp1610_subr(7,5); break; + case 0x13e: /* 0 100 111 110 */ cp1610_subr(7,6); break; + case 0x13f: /* 0 100 111 111 */ cp1610_subr(7,7); break; + + case 0x140: /* 0 101 000 000 */ cp1610_cmpr(0,0); break; + case 0x141: /* 0 101 000 001 */ cp1610_cmpr(0,1); break; + case 0x142: /* 0 101 000 010 */ cp1610_cmpr(0,2); break; + case 0x143: /* 0 101 000 011 */ cp1610_cmpr(0,3); break; + case 0x144: /* 0 101 000 100 */ cp1610_cmpr(0,4); break; + case 0x145: /* 0 101 000 101 */ cp1610_cmpr(0,5); break; + case 0x146: /* 0 101 000 110 */ cp1610_cmpr(0,6); break; + case 0x147: /* 0 101 000 111 */ cp1610_cmpr(0,7); break; + + case 0x148: /* 0 101 001 000 */ cp1610_cmpr(1,0); break; + case 0x149: /* 0 101 001 001 */ cp1610_cmpr(1,1); break; + case 0x14a: /* 0 101 001 010 */ cp1610_cmpr(1,2); break; + case 0x14b: /* 0 101 001 011 */ cp1610_cmpr(1,3); break; + case 0x14c: /* 0 101 001 100 */ cp1610_cmpr(1,4); break; + case 0x14d: /* 0 101 001 101 */ cp1610_cmpr(1,5); break; + case 0x14e: /* 0 101 001 110 */ cp1610_cmpr(1,6); break; + case 0x14f: /* 0 101 001 111 */ cp1610_cmpr(1,7); break; + + case 0x150: /* 0 101 010 000 */ cp1610_cmpr(2,0); break; + case 0x151: /* 0 101 010 001 */ cp1610_cmpr(2,1); break; + case 0x152: /* 0 101 010 010 */ cp1610_cmpr(2,2); break; + case 0x153: /* 0 101 010 011 */ cp1610_cmpr(2,3); break; + case 0x154: /* 0 101 010 100 */ cp1610_cmpr(2,4); break; + case 0x155: /* 0 101 010 101 */ cp1610_cmpr(2,5); break; + case 0x156: /* 0 101 010 110 */ cp1610_cmpr(2,6); break; + case 0x157: /* 0 101 010 111 */ cp1610_cmpr(2,7); break; + + case 0x158: /* 0 101 011 000 */ cp1610_cmpr(3,0); break; + case 0x159: /* 0 101 011 001 */ cp1610_cmpr(3,1); break; + case 0x15a: /* 0 101 011 010 */ cp1610_cmpr(3,2); break; + case 0x15b: /* 0 101 011 011 */ cp1610_cmpr(3,3); break; + case 0x15c: /* 0 101 011 100 */ cp1610_cmpr(3,4); break; + case 0x15d: /* 0 101 011 101 */ cp1610_cmpr(3,5); break; + case 0x15e: /* 0 101 011 110 */ cp1610_cmpr(3,6); break; + case 0x15f: /* 0 101 011 111 */ cp1610_cmpr(3,7); break; + + case 0x160: /* 0 101 100 000 */ cp1610_cmpr(4,0); break; + case 0x161: /* 0 101 100 001 */ cp1610_cmpr(4,1); break; + case 0x162: /* 0 101 100 010 */ cp1610_cmpr(4,2); break; + case 0x163: /* 0 101 100 011 */ cp1610_cmpr(4,3); break; + case 0x164: /* 0 101 100 100 */ cp1610_cmpr(4,4); break; + case 0x165: /* 0 101 100 101 */ cp1610_cmpr(4,5); break; + case 0x166: /* 0 101 100 110 */ cp1610_cmpr(4,6); break; + case 0x167: /* 0 101 100 111 */ cp1610_cmpr(4,7); break; + + case 0x168: /* 0 101 101 000 */ cp1610_cmpr(5,0); break; + case 0x169: /* 0 101 101 001 */ cp1610_cmpr(5,1); break; + case 0x16a: /* 0 101 101 010 */ cp1610_cmpr(5,2); break; + case 0x16b: /* 0 101 101 011 */ cp1610_cmpr(5,3); break; + case 0x16c: /* 0 101 101 100 */ cp1610_cmpr(5,4); break; + case 0x16d: /* 0 101 101 101 */ cp1610_cmpr(5,5); break; + case 0x16e: /* 0 101 101 110 */ cp1610_cmpr(5,6); break; + case 0x16f: /* 0 101 101 111 */ cp1610_cmpr(5,7); break; + + case 0x170: /* 0 101 110 000 */ cp1610_cmpr(6,0); break; + case 0x171: /* 0 101 110 001 */ cp1610_cmpr(6,1); break; + case 0x172: /* 0 101 110 010 */ cp1610_cmpr(6,2); break; + case 0x173: /* 0 101 110 011 */ cp1610_cmpr(6,3); break; + case 0x174: /* 0 101 110 100 */ cp1610_cmpr(6,4); break; + case 0x175: /* 0 101 110 101 */ cp1610_cmpr(6,5); break; + case 0x176: /* 0 101 110 110 */ cp1610_cmpr(6,6); break; + case 0x177: /* 0 101 110 111 */ cp1610_cmpr(6,7); break; + + case 0x178: /* 0 101 111 000 */ cp1610_cmpr(7,0); break; + case 0x179: /* 0 101 111 001 */ cp1610_cmpr(7,1); break; + case 0x17a: /* 0 101 111 010 */ cp1610_cmpr(7,2); break; + case 0x17b: /* 0 101 111 011 */ cp1610_cmpr(7,3); break; + case 0x17c: /* 0 101 111 100 */ cp1610_cmpr(7,4); break; + case 0x17d: /* 0 101 111 101 */ cp1610_cmpr(7,5); break; + case 0x17e: /* 0 101 111 110 */ cp1610_cmpr(7,6); break; + case 0x17f: /* 0 101 111 111 */ cp1610_cmpr(7,7); break; + + case 0x180: /* 0 110 000 000 */ cp1610_andr(0,0); break; + case 0x181: /* 0 110 000 001 */ cp1610_andr(0,1); break; + case 0x182: /* 0 110 000 010 */ cp1610_andr(0,2); break; + case 0x183: /* 0 110 000 011 */ cp1610_andr(0,3); break; + case 0x184: /* 0 110 000 100 */ cp1610_andr(0,4); break; + case 0x185: /* 0 110 000 101 */ cp1610_andr(0,5); break; + case 0x186: /* 0 110 000 110 */ cp1610_andr(0,6); break; + case 0x187: /* 0 110 000 111 */ cp1610_andr(0,7); break; + + case 0x188: /* 0 110 001 000 */ cp1610_andr(1,0); break; + case 0x189: /* 0 110 001 001 */ cp1610_andr(1,1); break; + case 0x18a: /* 0 110 001 010 */ cp1610_andr(1,2); break; + case 0x18b: /* 0 110 001 011 */ cp1610_andr(1,3); break; + case 0x18c: /* 0 110 001 100 */ cp1610_andr(1,4); break; + case 0x18d: /* 0 110 001 101 */ cp1610_andr(1,5); break; + case 0x18e: /* 0 110 001 110 */ cp1610_andr(1,6); break; + case 0x18f: /* 0 110 001 111 */ cp1610_andr(1,7); break; + + case 0x190: /* 0 110 010 000 */ cp1610_andr(2,0); break; + case 0x191: /* 0 110 010 001 */ cp1610_andr(2,1); break; + case 0x192: /* 0 110 010 010 */ cp1610_andr(2,2); break; + case 0x193: /* 0 110 010 011 */ cp1610_andr(2,3); break; + case 0x194: /* 0 110 010 100 */ cp1610_andr(2,4); break; + case 0x195: /* 0 110 010 101 */ cp1610_andr(2,5); break; + case 0x196: /* 0 110 010 110 */ cp1610_andr(2,6); break; + case 0x197: /* 0 110 010 111 */ cp1610_andr(2,7); break; + + case 0x198: /* 0 110 011 000 */ cp1610_andr(3,0); break; + case 0x199: /* 0 110 011 001 */ cp1610_andr(3,1); break; + case 0x19a: /* 0 110 011 010 */ cp1610_andr(3,2); break; + case 0x19b: /* 0 110 011 011 */ cp1610_andr(3,3); break; + case 0x19c: /* 0 110 011 100 */ cp1610_andr(3,4); break; + case 0x19d: /* 0 110 011 101 */ cp1610_andr(3,5); break; + case 0x19e: /* 0 110 011 110 */ cp1610_andr(3,6); break; + case 0x19f: /* 0 110 011 111 */ cp1610_andr(3,7); break; + + case 0x1a0: /* 0 110 100 000 */ cp1610_andr(4,0); break; + case 0x1a1: /* 0 110 100 001 */ cp1610_andr(4,1); break; + case 0x1a2: /* 0 110 100 010 */ cp1610_andr(4,2); break; + case 0x1a3: /* 0 110 100 011 */ cp1610_andr(4,3); break; + case 0x1a4: /* 0 110 100 100 */ cp1610_andr(4,4); break; + case 0x1a5: /* 0 110 100 101 */ cp1610_andr(4,5); break; + case 0x1a6: /* 0 110 100 110 */ cp1610_andr(4,6); break; + case 0x1a7: /* 0 110 100 111 */ cp1610_andr(4,7); break; + + case 0x1a8: /* 0 110 101 000 */ cp1610_andr(5,0); break; + case 0x1a9: /* 0 110 101 001 */ cp1610_andr(5,1); break; + case 0x1aa: /* 0 110 101 010 */ cp1610_andr(5,2); break; + case 0x1ab: /* 0 110 101 011 */ cp1610_andr(5,3); break; + case 0x1ac: /* 0 110 101 100 */ cp1610_andr(5,4); break; + case 0x1ad: /* 0 110 101 101 */ cp1610_andr(5,5); break; + case 0x1ae: /* 0 110 101 110 */ cp1610_andr(5,6); break; + case 0x1af: /* 0 110 101 111 */ cp1610_andr(5,7); break; + + case 0x1b0: /* 0 110 110 000 */ cp1610_andr(6,0); break; + case 0x1b1: /* 0 110 110 001 */ cp1610_andr(6,1); break; + case 0x1b2: /* 0 110 110 010 */ cp1610_andr(6,2); break; + case 0x1b3: /* 0 110 110 011 */ cp1610_andr(6,3); break; + case 0x1b4: /* 0 110 110 100 */ cp1610_andr(6,4); break; + case 0x1b5: /* 0 110 110 101 */ cp1610_andr(6,5); break; + case 0x1b6: /* 0 110 110 110 */ cp1610_andr(6,6); break; + case 0x1b7: /* 0 110 110 111 */ cp1610_andr(6,7); break; + + case 0x1b8: /* 0 110 111 000 */ cp1610_andr(7,0); break; + case 0x1b9: /* 0 110 111 001 */ cp1610_andr(7,1); break; + case 0x1ba: /* 0 110 111 010 */ cp1610_andr(7,2); break; + case 0x1bb: /* 0 110 111 011 */ cp1610_andr(7,3); break; + case 0x1bc: /* 0 110 111 100 */ cp1610_andr(7,4); break; + case 0x1bd: /* 0 110 111 101 */ cp1610_andr(7,5); break; + case 0x1be: /* 0 110 111 110 */ cp1610_andr(7,6); break; + case 0x1bf: /* 0 110 111 111 */ cp1610_andr(7,7); break; + + case 0x1c0: /* 0 111 000 000 */ cp1610_clrr(0); break; + case 0x1c1: /* 0 111 000 001 */ cp1610_xorr(0,1); break; + case 0x1c2: /* 0 111 000 010 */ cp1610_xorr(0,2); break; + case 0x1c3: /* 0 111 000 011 */ cp1610_xorr(0,3); break; + case 0x1c4: /* 0 111 000 100 */ cp1610_xorr(0,4); break; + case 0x1c5: /* 0 111 000 101 */ cp1610_xorr(0,5); break; + case 0x1c6: /* 0 111 000 110 */ cp1610_xorr(0,6); break; + case 0x1c7: /* 0 111 000 111 */ cp1610_xorr(0,7); break; + + case 0x1c8: /* 0 111 001 000 */ cp1610_xorr(1,0); break; + case 0x1c9: /* 0 111 001 001 */ cp1610_clrr(1); break; + case 0x1ca: /* 0 111 001 010 */ cp1610_xorr(1,2); break; + case 0x1cb: /* 0 111 001 011 */ cp1610_xorr(1,3); break; + case 0x1cc: /* 0 111 001 100 */ cp1610_xorr(1,4); break; + case 0x1cd: /* 0 111 001 101 */ cp1610_xorr(1,5); break; + case 0x1ce: /* 0 111 001 110 */ cp1610_xorr(1,6); break; + case 0x1cf: /* 0 111 001 111 */ cp1610_xorr(1,7); break; + + case 0x1d0: /* 0 111 010 000 */ cp1610_xorr(2,0); break; + case 0x1d1: /* 0 111 010 001 */ cp1610_xorr(2,1); break; + case 0x1d2: /* 0 111 010 010 */ cp1610_clrr(2); break; + case 0x1d3: /* 0 111 010 011 */ cp1610_xorr(2,3); break; + case 0x1d4: /* 0 111 010 100 */ cp1610_xorr(2,4); break; + case 0x1d5: /* 0 111 010 101 */ cp1610_xorr(2,5); break; + case 0x1d6: /* 0 111 010 110 */ cp1610_xorr(2,6); break; + case 0x1d7: /* 0 111 010 111 */ cp1610_xorr(2,7); break; + + case 0x1d8: /* 0 111 011 000 */ cp1610_xorr(3,0); break; + case 0x1d9: /* 0 111 011 001 */ cp1610_xorr(3,1); break; + case 0x1da: /* 0 111 011 010 */ cp1610_xorr(3,2); break; + case 0x1db: /* 0 111 011 011 */ cp1610_clrr(3); break; + case 0x1dc: /* 0 111 011 100 */ cp1610_xorr(3,4); break; + case 0x1dd: /* 0 111 011 101 */ cp1610_xorr(3,5); break; + case 0x1de: /* 0 111 011 110 */ cp1610_xorr(3,6); break; + case 0x1df: /* 0 111 011 111 */ cp1610_xorr(3,7); break; + + case 0x1e0: /* 0 111 100 000 */ cp1610_xorr(4,0); break; + case 0x1e1: /* 0 111 100 001 */ cp1610_xorr(4,1); break; + case 0x1e2: /* 0 111 100 010 */ cp1610_xorr(4,2); break; + case 0x1e3: /* 0 111 100 011 */ cp1610_xorr(4,3); break; + case 0x1e4: /* 0 111 100 100 */ cp1610_clrr(4); break; + case 0x1e5: /* 0 111 100 101 */ cp1610_xorr(4,5); break; + case 0x1e6: /* 0 111 100 110 */ cp1610_xorr(4,6); break; + case 0x1e7: /* 0 111 100 111 */ cp1610_xorr(4,7); break; + + case 0x1e8: /* 0 111 101 000 */ cp1610_xorr(5,0); break; + case 0x1e9: /* 0 111 101 001 */ cp1610_xorr(5,1); break; + case 0x1ea: /* 0 111 101 010 */ cp1610_xorr(5,2); break; + case 0x1eb: /* 0 111 101 011 */ cp1610_xorr(5,3); break; + case 0x1ec: /* 0 111 101 100 */ cp1610_xorr(5,4); break; + case 0x1ed: /* 0 111 101 101 */ cp1610_clrr(5); break; + case 0x1ee: /* 0 111 101 110 */ cp1610_xorr(5,6); break; + case 0x1ef: /* 0 111 101 111 */ cp1610_xorr(5,7); break; + + case 0x1f0: /* 0 111 110 000 */ cp1610_xorr(6,0); break; + case 0x1f1: /* 0 111 110 001 */ cp1610_xorr(6,1); break; + case 0x1f2: /* 0 111 110 010 */ cp1610_xorr(6,2); break; + case 0x1f3: /* 0 111 110 011 */ cp1610_xorr(6,3); break; + case 0x1f4: /* 0 111 110 100 */ cp1610_xorr(6,4); break; + case 0x1f5: /* 0 111 110 101 */ cp1610_xorr(6,5); break; + case 0x1f6: /* 0 111 110 110 */ cp1610_clrr(6); break; + case 0x1f7: /* 0 111 110 111 */ cp1610_xorr(6,7); break; + + case 0x1f8: /* 0 111 111 000 */ cp1610_xorr(7,0); break; + case 0x1f9: /* 0 111 111 001 */ cp1610_xorr(7,1); break; + case 0x1fa: /* 0 111 111 010 */ cp1610_xorr(7,2); break; + case 0x1fb: /* 0 111 111 011 */ cp1610_xorr(7,3); break; + case 0x1fc: /* 0 111 111 100 */ cp1610_xorr(7,4); break; + case 0x1fd: /* 0 111 111 101 */ cp1610_xorr(7,5); break; + case 0x1fe: /* 0 111 111 110 */ cp1610_xorr(7,6); break; + case 0x1ff: /* 0 110 111 111 */ cp1610_clrr(7); break; + + case 0x200: /* 1 000 000 000 */ cp1610_b(0); break; + case 0x201: /* 1 000 000 001 */ cp1610_bc(0); break; /* aka BLGE */ + case 0x202: /* 1 000 000 010 */ cp1610_bov(0); break; + case 0x203: /* 1 000 000 011 */ cp1610_bpl(0); break; + case 0x204: /* 1 000 000 100 */ cp1610_bze(0); break; /* aka BEQ */ + case 0x205: /* 1 000 000 101 */ cp1610_blt(0); break; + case 0x206: /* 1 000 000 110 */ cp1610_ble(0); break; + case 0x207: /* 1 000 000 111 */ cp1610_busc(0); break; + + case 0x208: /* 1 000 001 000 */ cp1610_nopp(0); break; + case 0x209: /* 1 000 001 001 */ cp1610_bnc(0); break; /* aka BLLT */ + case 0x20a: /* 1 000 001 010 */ cp1610_bnov(0); break; + case 0x20b: /* 1 000 001 011 */ cp1610_bmi(0); break; + case 0x20c: /* 1 000 001 100 */ cp1610_bnze(0); break; /* aka BNEQ */ + case 0x20d: /* 1 000 001 101 */ cp1610_bge(0); break; + case 0x20e: /* 1 000 001 110 */ cp1610_bgt(0); break; + case 0x20f: /* 1 000 001 111 */ cp1610_besc(0); break; + + case 0x210: /* 1 000 010 000 */ cp1610_bext(0,0); break; + case 0x211: /* 1 000 010 001 */ cp1610_bext(1,0); break; + case 0x212: /* 1 000 010 010 */ cp1610_bext(2,0); break; + case 0x213: /* 1 000 010 011 */ cp1610_bext(3,0); break; + case 0x214: /* 1 000 010 100 */ cp1610_bext(4,0); break; + case 0x215: /* 1 000 010 101 */ cp1610_bext(5,0); break; + case 0x216: /* 1 000 010 110 */ cp1610_bext(6,0); break; + case 0x217: /* 1 000 010 111 */ cp1610_bext(7,0); break; + + case 0x218: /* 1 000 011 000 */ cp1610_bext(8,0); break; + case 0x219: /* 1 000 011 001 */ cp1610_bext(9,0); break; + case 0x21a: /* 1 000 011 010 */ cp1610_bext(10,0); break; + case 0x21b: /* 1 000 011 011 */ cp1610_bext(11,0); break; + case 0x21c: /* 1 000 011 100 */ cp1610_bext(12,0); break; + case 0x21d: /* 1 000 011 101 */ cp1610_bext(13,0); break; + case 0x21e: /* 1 000 011 110 */ cp1610_bext(14,0); break; + case 0x21f: /* 1 000 011 111 */ cp1610_bext(15,0); break; + + case 0x220: /* 1 000 100 000 */ cp1610_b(0xffff); break; + case 0x221: /* 1 000 100 001 */ cp1610_bc(0xffff); break; /* aka BLGE */ + case 0x222: /* 1 000 100 010 */ cp1610_bov(0xffff); break; + case 0x223: /* 1 000 100 011 */ cp1610_bpl(0xffff); break; + case 0x224: /* 1 000 100 100 */ cp1610_bze(0xffff); break; /* aka BEQ */ + case 0x225: /* 1 000 100 101 */ cp1610_blt(0xffff); break; + case 0x226: /* 1 000 100 110 */ cp1610_ble(0xffff); break; + case 0x227: /* 1 000 100 111 */ cp1610_busc(0xffff); break; + + case 0x228: /* 1 000 101 000 */ cp1610_nopp(0xffff); break; + case 0x229: /* 1 000 101 001 */ cp1610_bnc(0xffff); break; /* aka BLLT */ + case 0x22a: /* 1 000 101 010 */ cp1610_bnov(0xffff); break; + case 0x22b: /* 1 000 101 011 */ cp1610_bmi(0xffff); break; + case 0x22c: /* 1 000 101 100 */ cp1610_bnze(0xffff); break; /* aka BNEQ */ + case 0x22d: /* 1 000 101 101 */ cp1610_bge(0xffff); break; + case 0x22e: /* 1 000 101 110 */ cp1610_bgt(0xffff); break; + case 0x22f: /* 1 000 101 111 */ cp1610_besc(0xffff); break; + + case 0x230: /* 1 000 110 000 */ cp1610_bext(0,0xffff); break; + case 0x231: /* 1 000 110 001 */ cp1610_bext(1,0xffff); break; + case 0x232: /* 1 000 110 010 */ cp1610_bext(2,0xffff); break; + case 0x233: /* 1 000 110 011 */ cp1610_bext(3,0xffff); break; + case 0x234: /* 1 000 110 100 */ cp1610_bext(4,0xffff); break; + case 0x235: /* 1 000 110 101 */ cp1610_bext(5,0xffff); break; + case 0x236: /* 1 000 110 110 */ cp1610_bext(6,0xffff); break; + case 0x237: /* 1 000 110 111 */ cp1610_bext(7,0xffff); break; + + case 0x238: /* 1 000 111 000 */ cp1610_bext(8,0xffff); break; + case 0x239: /* 1 000 111 001 */ cp1610_bext(9,0xffff); break; + case 0x23a: /* 1 000 111 010 */ cp1610_bext(10,0xffff); break; + case 0x23b: /* 1 000 111 011 */ cp1610_bext(11,0xffff); break; + case 0x23c: /* 1 000 111 100 */ cp1610_bext(12,0xffff); break; + case 0x23d: /* 1 000 111 101 */ cp1610_bext(13,0xffff); break; + case 0x23e: /* 1 000 111 110 */ cp1610_bext(14,0xffff); break; + case 0x23f: /* 1 000 111 111 */ cp1610_bext(15,0xffff); break; + + case 0x240: /* 1 001 000 000 */ cp1610_mvo(0); break; + case 0x241: /* 1 001 000 001 */ cp1610_mvo(1); break; + case 0x242: /* 1 001 000 010 */ cp1610_mvo(2); break; + case 0x243: /* 1 001 000 011 */ cp1610_mvo(3); break; + case 0x244: /* 1 001 000 100 */ cp1610_mvo(4); break; + case 0x245: /* 1 001 000 101 */ cp1610_mvo(5); break; + case 0x246: /* 1 001 000 110 */ cp1610_mvo(6); break; + case 0x247: /* 1 001 000 111 */ cp1610_mvo(7); break; + + case 0x248: /* 1 001 001 000 */ cp1610_mvoat(0,1); break; + case 0x249: /* 1 001 001 001 */ cp1610_mvoat(1,1); break; + case 0x24a: /* 1 001 001 010 */ cp1610_mvoat(2,1); break; + case 0x24b: /* 1 001 001 011 */ cp1610_mvoat(3,1); break; + case 0x24c: /* 1 001 001 100 */ cp1610_mvoat(4,1); break; + case 0x24d: /* 1 001 001 101 */ cp1610_mvoat(5,1); break; + case 0x24e: /* 1 001 001 110 */ cp1610_mvoat(6,1); break; + case 0x24f: /* 1 001 001 111 */ cp1610_mvoat(7,1); break; + + case 0x250: /* 1 001 010 000 */ cp1610_mvoat(0,2); break; + case 0x251: /* 1 001 010 001 */ cp1610_mvoat(1,2); break; + case 0x252: /* 1 001 010 010 */ cp1610_mvoat(2,2); break; + case 0x253: /* 1 001 010 011 */ cp1610_mvoat(3,2); break; + case 0x254: /* 1 001 010 100 */ cp1610_mvoat(4,2); break; + case 0x255: /* 1 001 010 101 */ cp1610_mvoat(5,2); break; + case 0x256: /* 1 001 010 110 */ cp1610_mvoat(6,2); break; + case 0x257: /* 1 001 010 111 */ cp1610_mvoat(7,2); break; + + case 0x258: /* 1 001 011 000 */ cp1610_mvoat(0,3); break; + case 0x259: /* 1 001 011 001 */ cp1610_mvoat(1,3); break; + case 0x25a: /* 1 001 011 010 */ cp1610_mvoat(2,3); break; + case 0x25b: /* 1 001 011 011 */ cp1610_mvoat(3,3); break; + case 0x25c: /* 1 001 011 100 */ cp1610_mvoat(4,3); break; + case 0x25d: /* 1 001 011 101 */ cp1610_mvoat(5,3); break; + case 0x25e: /* 1 001 011 110 */ cp1610_mvoat(6,3); break; + case 0x25f: /* 1 001 011 111 */ cp1610_mvoat(7,3); break; + + case 0x260: /* 1 001 100 000 */ cp1610_mvoat_i(0,4); break; + case 0x261: /* 1 001 100 001 */ cp1610_mvoat_i(1,4); break; + case 0x262: /* 1 001 100 010 */ cp1610_mvoat_i(2,4); break; + case 0x263: /* 1 001 100 011 */ cp1610_mvoat_i(3,4); break; + case 0x264: /* 1 001 100 100 */ cp1610_mvoat_i(4,4); break; + case 0x265: /* 1 001 100 101 */ cp1610_mvoat_i(5,4); break; + case 0x266: /* 1 001 100 110 */ cp1610_mvoat_i(6,4); break; + case 0x267: /* 1 001 100 111 */ cp1610_mvoat_i(7,4); break; + + case 0x268: /* 1 001 101 000 */ cp1610_mvoat_i(0,5); break; + case 0x269: /* 1 001 101 001 */ cp1610_mvoat_i(1,5); break; + case 0x26a: /* 1 001 101 010 */ cp1610_mvoat_i(2,5); break; + case 0x26b: /* 1 001 101 011 */ cp1610_mvoat_i(3,5); break; + case 0x26c: /* 1 001 101 100 */ cp1610_mvoat_i(4,5); break; + case 0x26d: /* 1 001 101 101 */ cp1610_mvoat_i(5,5); break; + case 0x26e: /* 1 001 101 110 */ cp1610_mvoat_i(6,5); break; + case 0x26f: /* 1 001 101 111 */ cp1610_mvoat_i(7,5); break; + + case 0x270: /* 1 001 110 000 */ cp1610_mvoat_i(0,6); break; /* pshr */ + case 0x271: /* 1 001 110 001 */ cp1610_mvoat_i(1,6); break; /* pshr */ + case 0x272: /* 1 001 110 010 */ cp1610_mvoat_i(2,6); break; /* pshr */ + case 0x273: /* 1 001 110 011 */ cp1610_mvoat_i(3,6); break; /* pshr */ + case 0x274: /* 1 001 110 100 */ cp1610_mvoat_i(4,6); break; /* pshr */ + case 0x275: /* 1 001 110 101 */ cp1610_mvoat_i(5,6); break; /* pshr */ + case 0x276: /* 1 001 110 110 */ cp1610_mvoat_i(6,6); break; /* pshr */ + case 0x277: /* 1 001 110 111 */ cp1610_mvoat_i(7,6); break; /* pshr */ + + case 0x278: /* 1 001 111 000 */ cp1610_mvoi(0); break; + case 0x279: /* 1 001 111 001 */ cp1610_mvoi(1); break; + case 0x27a: /* 1 001 111 010 */ cp1610_mvoi(2); break; + case 0x27b: /* 1 001 111 011 */ cp1610_mvoi(3); break; + case 0x27c: /* 1 001 111 100 */ cp1610_mvoi(4); break; + case 0x27d: /* 1 001 111 101 */ cp1610_mvoi(5); break; + case 0x27e: /* 1 001 111 110 */ cp1610_mvoi(6); break; + case 0x27f: /* 1 001 111 111 */ cp1610_mvoi(7); break; + + case 0x280: /* 1 010 000 000 */ cp1610_mvi(0); break; + case 0x281: /* 1 010 000 001 */ cp1610_mvi(1); break; + case 0x282: /* 1 010 000 010 */ cp1610_mvi(2); break; + case 0x283: /* 1 010 000 011 */ cp1610_mvi(3); break; + case 0x284: /* 1 010 000 100 */ cp1610_mvi(4); break; + case 0x285: /* 1 010 000 101 */ cp1610_mvi(5); break; + case 0x286: /* 1 010 000 110 */ cp1610_mvi(6); break; + case 0x287: /* 1 010 000 111 */ cp1610_mvi(7); break; + + case 0x288: /* 1 010 001 000 */ cp1610_mviat(1,0); break; + case 0x289: /* 1 010 001 001 */ cp1610_mviat(1,1); break; + case 0x28a: /* 1 010 001 010 */ cp1610_mviat(1,2); break; + case 0x28b: /* 1 010 001 011 */ cp1610_mviat(1,3); break; + case 0x28c: /* 1 010 001 100 */ cp1610_mviat(1,4); break; + case 0x28d: /* 1 010 001 101 */ cp1610_mviat(1,5); break; + case 0x28e: /* 1 010 001 110 */ cp1610_mviat(1,6); break; + case 0x28f: /* 1 010 001 111 */ cp1610_mviat(1,7); break; + + case 0x290: /* 1 010 010 000 */ cp1610_mviat(2,0); break; + case 0x291: /* 1 010 010 001 */ cp1610_mviat(2,1); break; + case 0x292: /* 1 010 010 010 */ cp1610_mviat(2,2); break; + case 0x293: /* 1 010 010 011 */ cp1610_mviat(2,3); break; + case 0x294: /* 1 010 010 100 */ cp1610_mviat(2,4); break; + case 0x295: /* 1 010 010 101 */ cp1610_mviat(2,5); break; + case 0x296: /* 1 010 010 110 */ cp1610_mviat(2,6); break; + case 0x297: /* 1 010 010 111 */ cp1610_mviat(2,7); break; + + case 0x298: /* 1 010 011 000 */ cp1610_mviat(3,0); break; + case 0x299: /* 1 010 011 001 */ cp1610_mviat(3,1); break; + case 0x29a: /* 1 010 011 010 */ cp1610_mviat(3,2); break; + case 0x29b: /* 1 010 011 011 */ cp1610_mviat(3,3); break; + case 0x29c: /* 1 010 011 100 */ cp1610_mviat(3,4); break; + case 0x29d: /* 1 010 011 101 */ cp1610_mviat(3,5); break; + case 0x29e: /* 1 010 011 110 */ cp1610_mviat(3,6); break; + case 0x29f: /* 1 010 011 111 */ cp1610_mviat(3,7); break; + + case 0x2a0: /* 1 010 100 000 */ cp1610_mviat_i(4,0); break; + case 0x2a1: /* 1 010 100 001 */ cp1610_mviat_i(4,1); break; + case 0x2a2: /* 1 010 100 010 */ cp1610_mviat_i(4,2); break; + case 0x2a3: /* 1 010 100 011 */ cp1610_mviat_i(4,3); break; + case 0x2a4: /* 1 010 100 100 */ cp1610_mviat_i(4,4); break; + case 0x2a5: /* 1 010 100 101 */ cp1610_mviat_i(4,5); break; + case 0x2a6: /* 1 010 100 110 */ cp1610_mviat_i(4,6); break; + case 0x2a7: /* 1 010 100 111 */ cp1610_mviat_i(4,7); break; + + case 0x2a8: /* 1 010 101 000 */ cp1610_mviat_i(5,0); break; + case 0x2a9: /* 1 010 101 001 */ cp1610_mviat_i(5,1); break; + case 0x2aa: /* 1 010 101 010 */ cp1610_mviat_i(5,2); break; + case 0x2ab: /* 1 010 101 011 */ cp1610_mviat_i(5,3); break; + case 0x2ac: /* 1 010 101 100 */ cp1610_mviat_i(5,4); break; + case 0x2ad: /* 1 010 101 101 */ cp1610_mviat_i(5,5); break; + case 0x2ae: /* 1 010 101 110 */ cp1610_mviat_i(5,6); break; + case 0x2af: /* 1 010 101 111 */ cp1610_mviat_i(5,7); break; + + case 0x2b0: /* 1 010 110 000 */ cp1610_pulr(0); break; + case 0x2b1: /* 1 010 110 001 */ cp1610_pulr(1); break; + case 0x2b2: /* 1 010 110 010 */ cp1610_pulr(2); break; + case 0x2b3: /* 1 010 110 011 */ cp1610_pulr(3); break; + case 0x2b4: /* 1 010 110 100 */ cp1610_pulr(4); break; + case 0x2b5: /* 1 010 110 101 */ cp1610_pulr(5); break; + case 0x2b6: /* 1 010 110 110 */ cp1610_pulr(6); break; + case 0x2b7: /* 1 010 110 111 */ cp1610_pulr(7); break; + + case 0x2b8: /* 1 010 111 000 */ cp1610_mvii(0); break; + case 0x2b9: /* 1 010 111 001 */ cp1610_mvii(1); break; + case 0x2ba: /* 1 010 111 010 */ cp1610_mvii(2); break; + case 0x2bb: /* 1 010 111 011 */ cp1610_mvii(3); break; + case 0x2bc: /* 1 010 111 100 */ cp1610_mvii(4); break; + case 0x2bd: /* 1 010 111 101 */ cp1610_mvii(5); break; + case 0x2be: /* 1 010 111 110 */ cp1610_mvii(6); break; + case 0x2bf: /* 1 010 111 111 */ cp1610_mvii(7); break; + + case 0x2c0: /* 1 011 000 000 */ cp1610_add(0); break; + case 0x2c1: /* 1 011 000 001 */ cp1610_add(1); break; + case 0x2c2: /* 1 011 000 010 */ cp1610_add(2); break; + case 0x2c3: /* 1 011 000 011 */ cp1610_add(3); break; + case 0x2c4: /* 1 011 000 100 */ cp1610_add(4); break; + case 0x2c5: /* 1 011 000 101 */ cp1610_add(5); break; + case 0x2c6: /* 1 011 000 110 */ cp1610_add(6); break; + case 0x2c7: /* 1 011 000 111 */ cp1610_add(7); break; + + case 0x2c8: /* 1 011 001 000 */ cp1610_addat(1,0); break; + case 0x2c9: /* 1 011 001 001 */ cp1610_addat(1,1); break; + case 0x2ca: /* 1 011 001 010 */ cp1610_addat(1,2); break; + case 0x2cb: /* 1 011 001 011 */ cp1610_addat(1,3); break; + case 0x2cc: /* 1 011 001 100 */ cp1610_addat(1,4); break; + case 0x2cd: /* 1 011 001 101 */ cp1610_addat(1,5); break; + case 0x2ce: /* 1 011 001 110 */ cp1610_addat(1,6); break; + case 0x2cf: /* 1 011 001 111 */ cp1610_addat(1,7); break; + + case 0x2d0: /* 1 011 010 000 */ cp1610_addat(2,0); break; + case 0x2d1: /* 1 011 010 001 */ cp1610_addat(2,1); break; + case 0x2d2: /* 1 011 010 010 */ cp1610_addat(2,2); break; + case 0x2d3: /* 1 011 010 011 */ cp1610_addat(2,3); break; + case 0x2d4: /* 1 011 010 100 */ cp1610_addat(2,4); break; + case 0x2d5: /* 1 011 010 101 */ cp1610_addat(2,5); break; + case 0x2d6: /* 1 011 010 110 */ cp1610_addat(2,6); break; + case 0x2d7: /* 1 011 010 111 */ cp1610_addat(2,7); break; + + case 0x2d8: /* 1 011 011 000 */ cp1610_addat(3,0); break; + case 0x2d9: /* 1 011 011 001 */ cp1610_addat(3,1); break; + case 0x2da: /* 1 011 011 010 */ cp1610_addat(3,2); break; + case 0x2db: /* 1 011 011 011 */ cp1610_addat(3,3); break; + case 0x2dc: /* 1 011 011 100 */ cp1610_addat(3,4); break; + case 0x2dd: /* 1 011 011 101 */ cp1610_addat(3,5); break; + case 0x2de: /* 1 011 011 110 */ cp1610_addat(3,6); break; + case 0x2df: /* 1 011 011 111 */ cp1610_addat(3,7); break; + + case 0x2e0: /* 1 011 100 000 */ cp1610_addat_i(4,0); break; + case 0x2e1: /* 1 011 100 001 */ cp1610_addat_i(4,1); break; + case 0x2e2: /* 1 011 100 010 */ cp1610_addat_i(4,2); break; + case 0x2e3: /* 1 011 100 011 */ cp1610_addat_i(4,3); break; + case 0x2e4: /* 1 011 100 100 */ cp1610_addat_i(4,4); break; + case 0x2e5: /* 1 011 100 101 */ cp1610_addat_i(4,5); break; + case 0x2e6: /* 1 011 100 110 */ cp1610_addat_i(4,6); break; + case 0x2e7: /* 1 011 100 111 */ cp1610_addat_i(4,7); break; + + case 0x2e8: /* 1 011 101 000 */ cp1610_addat_i(5,0); break; + case 0x2e9: /* 1 011 101 001 */ cp1610_addat_i(5,1); break; + case 0x2ea: /* 1 011 101 010 */ cp1610_addat_i(5,2); break; + case 0x2eb: /* 1 011 101 011 */ cp1610_addat_i(5,3); break; + case 0x2ec: /* 1 011 101 100 */ cp1610_addat_i(5,4); break; + case 0x2ed: /* 1 011 101 101 */ cp1610_addat_i(5,5); break; + case 0x2ee: /* 1 011 101 110 */ cp1610_addat_i(5,6); break; + case 0x2ef: /* 1 011 101 111 */ cp1610_addat_i(5,7); break; + + case 0x2f0: /* 1 011 110 000 */ cp1610_addat_d(6,0); break; + case 0x2f1: /* 1 011 110 001 */ cp1610_addat_d(6,1); break; + case 0x2f2: /* 1 011 110 010 */ cp1610_addat_d(6,2); break; + case 0x2f3: /* 1 011 110 011 */ cp1610_addat_d(6,3); break; + case 0x2f4: /* 1 011 110 100 */ cp1610_addat_d(6,4); break; + case 0x2f5: /* 1 011 110 101 */ cp1610_addat_d(6,5); break; + case 0x2f6: /* 1 011 110 110 */ cp1610_addat_d(6,6); break; + case 0x2f7: /* 1 011 110 111 */ cp1610_addat_d(6,7); break; + + case 0x2f8: /* 1 011 111 000 */ cp1610_addi(0); break; + case 0x2f9: /* 1 011 111 001 */ cp1610_addi(1); break; + case 0x2fa: /* 1 011 111 010 */ cp1610_addi(2); break; + case 0x2fb: /* 1 011 111 011 */ cp1610_addi(3); break; + case 0x2fc: /* 1 011 111 100 */ cp1610_addi(4); break; + case 0x2fd: /* 1 011 111 101 */ cp1610_addi(5); break; + case 0x2fe: /* 1 011 111 110 */ cp1610_addi(6); break; + case 0x2ff: /* 1 011 111 111 */ cp1610_addi(7); break; + + case 0x300: /* 1 100 000 000 */ cp1610_sub(0); break; + case 0x301: /* 1 100 000 001 */ cp1610_sub(1); break; + case 0x302: /* 1 100 000 010 */ cp1610_sub(2); break; + case 0x303: /* 1 100 000 011 */ cp1610_sub(3); break; + case 0x304: /* 1 100 000 100 */ cp1610_sub(4); break; + case 0x305: /* 1 100 000 101 */ cp1610_sub(5); break; + case 0x306: /* 1 100 000 110 */ cp1610_sub(6); break; + case 0x307: /* 1 100 000 111 */ cp1610_sub(7); break; + + case 0x308: /* 1 100 001 000 */ cp1610_subat(1,0); break; + case 0x309: /* 1 100 001 001 */ cp1610_subat(1,1); break; + case 0x30a: /* 1 100 001 010 */ cp1610_subat(1,2); break; + case 0x30b: /* 1 100 001 011 */ cp1610_subat(1,3); break; + case 0x30c: /* 1 100 001 100 */ cp1610_subat(1,4); break; + case 0x30d: /* 1 100 001 101 */ cp1610_subat(1,5); break; + case 0x30e: /* 1 100 001 110 */ cp1610_subat(1,6); break; + case 0x30f: /* 1 100 001 111 */ cp1610_subat(1,7); break; + + case 0x310: /* 1 100 010 000 */ cp1610_subat(2,0); break; + case 0x311: /* 1 100 010 001 */ cp1610_subat(2,1); break; + case 0x312: /* 1 100 010 010 */ cp1610_subat(2,2); break; + case 0x313: /* 1 100 010 011 */ cp1610_subat(2,3); break; + case 0x314: /* 1 100 010 100 */ cp1610_subat(2,4); break; + case 0x315: /* 1 100 010 101 */ cp1610_subat(2,5); break; + case 0x316: /* 1 100 010 110 */ cp1610_subat(2,6); break; + case 0x317: /* 1 100 010 111 */ cp1610_subat(2,7); break; + + case 0x318: /* 1 100 011 000 */ cp1610_subat(3,0); break; + case 0x319: /* 1 100 011 001 */ cp1610_subat(3,1); break; + case 0x31a: /* 1 100 011 010 */ cp1610_subat(3,2); break; + case 0x31b: /* 1 100 011 011 */ cp1610_subat(3,3); break; + case 0x31c: /* 1 100 011 100 */ cp1610_subat(3,4); break; + case 0x31d: /* 1 100 011 101 */ cp1610_subat(3,5); break; + case 0x31e: /* 1 100 011 110 */ cp1610_subat(3,6); break; + case 0x31f: /* 1 100 011 111 */ cp1610_subat(3,7); break; + + case 0x320: /* 1 100 100 000 */ cp1610_subat_i(4,0); break; + case 0x321: /* 1 100 100 001 */ cp1610_subat_i(4,1); break; + case 0x322: /* 1 100 100 010 */ cp1610_subat_i(4,2); break; + case 0x323: /* 1 100 100 011 */ cp1610_subat_i(4,3); break; + case 0x324: /* 1 100 100 100 */ cp1610_subat_i(4,4); break; + case 0x325: /* 1 100 100 101 */ cp1610_subat_i(4,5); break; + case 0x326: /* 1 100 100 110 */ cp1610_subat_i(4,6); break; + case 0x327: /* 1 100 100 111 */ cp1610_subat_i(4,7); break; + + case 0x328: /* 1 100 101 000 */ cp1610_subat_i(5,0); break; + case 0x329: /* 1 100 101 001 */ cp1610_subat_i(5,1); break; + case 0x32a: /* 1 100 101 010 */ cp1610_subat_i(5,2); break; + case 0x32b: /* 1 100 101 011 */ cp1610_subat_i(5,3); break; + case 0x32c: /* 1 100 101 100 */ cp1610_subat_i(5,4); break; + case 0x32d: /* 1 100 101 101 */ cp1610_subat_i(5,5); break; + case 0x32e: /* 1 100 101 110 */ cp1610_subat_i(5,6); break; + case 0x32f: /* 1 100 101 111 */ cp1610_subat_i(5,7); break; + + case 0x330: /* 1 100 110 000 */ cp1610_subat_d(6,0); break; + case 0x331: /* 1 100 110 001 */ cp1610_subat_d(6,1); break; + case 0x332: /* 1 100 110 010 */ cp1610_subat_d(6,2); break; + case 0x333: /* 1 100 110 011 */ cp1610_subat_d(6,3); break; + case 0x334: /* 1 100 110 100 */ cp1610_subat_d(6,4); break; + case 0x335: /* 1 100 110 101 */ cp1610_subat_d(6,5); break; + case 0x336: /* 1 100 110 110 */ cp1610_subat_d(6,6); break; + case 0x337: /* 1 100 110 111 */ cp1610_subat_d(6,7); break; + + case 0x338: /* 1 100 111 000 */ cp1610_subi(0); break; + case 0x339: /* 1 100 111 001 */ cp1610_subi(1); break; + case 0x33a: /* 1 100 111 010 */ cp1610_subi(2); break; + case 0x33b: /* 1 100 111 011 */ cp1610_subi(3); break; + case 0x33c: /* 1 100 111 100 */ cp1610_subi(4); break; + case 0x33d: /* 1 100 111 101 */ cp1610_subi(5); break; + case 0x33e: /* 1 100 111 110 */ cp1610_subi(6); break; + case 0x33f: /* 1 100 111 111 */ cp1610_subi(7); break; + + case 0x340: /* 1 101 000 000 */ cp1610_cmp(0); break; + case 0x341: /* 1 101 000 001 */ cp1610_cmp(1); break; + case 0x342: /* 1 101 000 010 */ cp1610_cmp(2); break; + case 0x343: /* 1 101 000 011 */ cp1610_cmp(3); break; + case 0x344: /* 1 101 000 100 */ cp1610_cmp(4); break; + case 0x345: /* 1 101 000 101 */ cp1610_cmp(5); break; + case 0x346: /* 1 101 000 110 */ cp1610_cmp(6); break; + case 0x347: /* 1 101 000 111 */ cp1610_cmp(7); break; + + case 0x348: /* 1 101 001 000 */ cp1610_cmpat(1,0); break; + case 0x349: /* 1 101 001 001 */ cp1610_cmpat(1,1); break; + case 0x34a: /* 1 101 001 010 */ cp1610_cmpat(1,2); break; + case 0x34b: /* 1 101 001 011 */ cp1610_cmpat(1,3); break; + case 0x34c: /* 1 101 001 100 */ cp1610_cmpat(1,4); break; + case 0x34d: /* 1 101 001 101 */ cp1610_cmpat(1,5); break; + case 0x34e: /* 1 101 001 110 */ cp1610_cmpat(1,6); break; + case 0x34f: /* 1 101 001 111 */ cp1610_cmpat(1,7); break; + + case 0x350: /* 1 101 010 000 */ cp1610_cmpat(2,0); break; + case 0x351: /* 1 101 010 001 */ cp1610_cmpat(2,1); break; + case 0x352: /* 1 101 010 010 */ cp1610_cmpat(2,2); break; + case 0x353: /* 1 101 010 011 */ cp1610_cmpat(2,3); break; + case 0x354: /* 1 101 010 100 */ cp1610_cmpat(2,4); break; + case 0x355: /* 1 101 010 101 */ cp1610_cmpat(2,5); break; + case 0x356: /* 1 101 010 110 */ cp1610_cmpat(2,6); break; + case 0x357: /* 1 101 010 111 */ cp1610_cmpat(2,7); break; + + case 0x358: /* 1 101 011 000 */ cp1610_cmpat(3,0); break; + case 0x359: /* 1 101 011 001 */ cp1610_cmpat(3,1); break; + case 0x35a: /* 1 101 011 010 */ cp1610_cmpat(3,2); break; + case 0x35b: /* 1 101 011 011 */ cp1610_cmpat(3,3); break; + case 0x35c: /* 1 101 011 100 */ cp1610_cmpat(3,4); break; + case 0x35d: /* 1 101 011 101 */ cp1610_cmpat(3,5); break; + case 0x35e: /* 1 101 011 110 */ cp1610_cmpat(3,6); break; + case 0x35f: /* 1 101 011 111 */ cp1610_cmpat(3,7); break; + + case 0x360: /* 1 101 100 000 */ cp1610_cmpat_i(4,0); break; + case 0x361: /* 1 101 100 001 */ cp1610_cmpat_i(4,1); break; + case 0x362: /* 1 101 100 010 */ cp1610_cmpat_i(4,2); break; + case 0x363: /* 1 101 100 011 */ cp1610_cmpat_i(4,3); break; + case 0x364: /* 1 101 100 100 */ cp1610_cmpat_i(4,4); break; + case 0x365: /* 1 101 100 101 */ cp1610_cmpat_i(4,5); break; + case 0x366: /* 1 101 100 110 */ cp1610_cmpat_i(4,6); break; + case 0x367: /* 1 101 100 111 */ cp1610_cmpat_i(4,7); break; + + case 0x368: /* 1 101 101 000 */ cp1610_cmpat_i(5,0); break; + case 0x369: /* 1 101 101 001 */ cp1610_cmpat_i(5,1); break; + case 0x36a: /* 1 101 101 010 */ cp1610_cmpat_i(5,2); break; + case 0x36b: /* 1 101 101 011 */ cp1610_cmpat_i(5,3); break; + case 0x36c: /* 1 101 101 100 */ cp1610_cmpat_i(5,4); break; + case 0x36d: /* 1 101 101 101 */ cp1610_cmpat_i(5,5); break; + case 0x36e: /* 1 101 101 110 */ cp1610_cmpat_i(5,6); break; + case 0x36f: /* 1 101 101 111 */ cp1610_cmpat_i(5,7); break; + + case 0x370: /* 1 101 110 000 */ cp1610_cmpat_d(6,0); break; + case 0x371: /* 1 101 110 001 */ cp1610_cmpat_d(6,1); break; + case 0x372: /* 1 101 110 010 */ cp1610_cmpat_d(6,2); break; + case 0x373: /* 1 101 110 011 */ cp1610_cmpat_d(6,3); break; + case 0x374: /* 1 101 110 100 */ cp1610_cmpat_d(6,4); break; + case 0x375: /* 1 101 110 101 */ cp1610_cmpat_d(6,5); break; + case 0x376: /* 1 101 110 110 */ cp1610_cmpat_d(6,6); break; + case 0x377: /* 1 101 110 111 */ cp1610_cmpat_d(6,7); break; + + case 0x378: /* 1 101 111 000 */ cp1610_cmpi(0); break; + case 0x379: /* 1 101 111 001 */ cp1610_cmpi(1); break; + case 0x37a: /* 1 101 111 010 */ cp1610_cmpi(2); break; + case 0x37b: /* 1 101 111 011 */ cp1610_cmpi(3); break; + case 0x37c: /* 1 101 111 100 */ cp1610_cmpi(4); break; + case 0x37d: /* 1 101 111 101 */ cp1610_cmpi(5); break; + case 0x37e: /* 1 101 111 110 */ cp1610_cmpi(6); break; + case 0x37f: /* 1 101 111 111 */ cp1610_cmpi(7); break; + + case 0x380: /* 1 110 000 000 */ cp1610_and(0); break; + case 0x381: /* 1 110 000 001 */ cp1610_and(1); break; + case 0x382: /* 1 110 000 010 */ cp1610_and(2); break; + case 0x383: /* 1 110 000 011 */ cp1610_and(3); break; + case 0x384: /* 1 110 000 100 */ cp1610_and(4); break; + case 0x385: /* 1 110 000 101 */ cp1610_and(5); break; + case 0x386: /* 1 110 000 110 */ cp1610_and(6); break; + case 0x387: /* 1 110 000 111 */ cp1610_and(7); break; + + case 0x388: /* 1 110 001 000 */ cp1610_andat(1,0); break; + case 0x389: /* 1 110 001 001 */ cp1610_andat(1,1); break; + case 0x38a: /* 1 110 001 010 */ cp1610_andat(1,2); break; + case 0x38b: /* 1 110 001 011 */ cp1610_andat(1,3); break; + case 0x38c: /* 1 110 001 100 */ cp1610_andat(1,4); break; + case 0x38d: /* 1 110 001 101 */ cp1610_andat(1,5); break; + case 0x38e: /* 1 110 001 110 */ cp1610_andat(1,6); break; + case 0x38f: /* 1 110 001 111 */ cp1610_andat(1,7); break; + + case 0x390: /* 1 110 010 000 */ cp1610_andat(2,0); break; + case 0x391: /* 1 110 010 001 */ cp1610_andat(2,1); break; + case 0x392: /* 1 110 010 010 */ cp1610_andat(2,2); break; + case 0x393: /* 1 110 010 011 */ cp1610_andat(2,3); break; + case 0x394: /* 1 110 010 100 */ cp1610_andat(2,4); break; + case 0x395: /* 1 110 010 101 */ cp1610_andat(2,5); break; + case 0x396: /* 1 110 010 110 */ cp1610_andat(2,6); break; + case 0x397: /* 1 110 010 111 */ cp1610_andat(2,7); break; + + case 0x398: /* 1 110 011 000 */ cp1610_andat(3,0); break; + case 0x399: /* 1 110 011 001 */ cp1610_andat(3,1); break; + case 0x39a: /* 1 110 011 010 */ cp1610_andat(3,2); break; + case 0x39b: /* 1 110 011 011 */ cp1610_andat(3,3); break; + case 0x39c: /* 1 110 011 100 */ cp1610_andat(3,4); break; + case 0x39d: /* 1 110 011 101 */ cp1610_andat(3,5); break; + case 0x39e: /* 1 110 011 110 */ cp1610_andat(3,6); break; + case 0x39f: /* 1 110 011 111 */ cp1610_andat(3,7); break; + + case 0x3a0: /* 1 110 100 000 */ cp1610_andat_i(4,0); break; + case 0x3a1: /* 1 110 100 001 */ cp1610_andat_i(4,1); break; + case 0x3a2: /* 1 110 100 010 */ cp1610_andat_i(4,2); break; + case 0x3a3: /* 1 110 100 011 */ cp1610_andat_i(4,3); break; + case 0x3a4: /* 1 110 100 100 */ cp1610_andat_i(4,4); break; + case 0x3a5: /* 1 110 100 101 */ cp1610_andat_i(4,5); break; + case 0x3a6: /* 1 110 100 110 */ cp1610_andat_i(4,6); break; + case 0x3a7: /* 1 110 100 111 */ cp1610_andat_i(4,7); break; + + case 0x3a8: /* 1 110 101 000 */ cp1610_andat_i(5,0); break; + case 0x3a9: /* 1 110 101 001 */ cp1610_andat_i(5,1); break; + case 0x3aa: /* 1 110 101 010 */ cp1610_andat_i(5,2); break; + case 0x3ab: /* 1 110 101 011 */ cp1610_andat_i(5,3); break; + case 0x3ac: /* 1 110 101 100 */ cp1610_andat_i(5,4); break; + case 0x3ad: /* 1 110 101 101 */ cp1610_andat_i(5,5); break; + case 0x3ae: /* 1 110 101 110 */ cp1610_andat_i(5,6); break; + case 0x3af: /* 1 110 101 111 */ cp1610_andat_i(5,7); break; + + case 0x3b0: /* 1 110 110 000 */ cp1610_andat_d(6,0); break; + case 0x3b1: /* 1 110 110 001 */ cp1610_andat_d(6,1); break; + case 0x3b2: /* 1 110 110 010 */ cp1610_andat_d(6,2); break; + case 0x3b3: /* 1 110 110 011 */ cp1610_andat_d(6,3); break; + case 0x3b4: /* 1 110 110 100 */ cp1610_andat_d(6,4); break; + case 0x3b5: /* 1 110 110 101 */ cp1610_andat_d(6,5); break; + case 0x3b6: /* 1 110 110 110 */ cp1610_andat_d(6,6); break; + case 0x3b7: /* 1 110 110 111 */ cp1610_andat_d(6,7); break; + + case 0x3b8: /* 1 110 111 000 */ cp1610_andi(0); break; + case 0x3b9: /* 1 110 111 001 */ cp1610_andi(1); break; + case 0x3ba: /* 1 110 111 010 */ cp1610_andi(2); break; + case 0x3bb: /* 1 110 111 011 */ cp1610_andi(3); break; + case 0x3bc: /* 1 110 111 100 */ cp1610_andi(4); break; + case 0x3bd: /* 1 110 111 101 */ cp1610_andi(5); break; + case 0x3be: /* 1 110 111 110 */ cp1610_andi(6); break; + case 0x3bf: /* 1 110 111 111 */ cp1610_andi(7); break; + + case 0x3c0: /* 1 111 000 000 */ cp1610_xor(0); break; + case 0x3c1: /* 1 111 000 001 */ cp1610_xor(1); break; + case 0x3c2: /* 1 111 000 010 */ cp1610_xor(2); break; + case 0x3c3: /* 1 111 000 011 */ cp1610_xor(3); break; + case 0x3c4: /* 1 111 000 100 */ cp1610_xor(4); break; + case 0x3c5: /* 1 111 000 101 */ cp1610_xor(5); break; + case 0x3c6: /* 1 111 000 110 */ cp1610_xor(6); break; + case 0x3c7: /* 1 111 000 111 */ cp1610_xor(7); break; + + case 0x3c8: /* 1 111 001 000 */ cp1610_xorat(1,0); break; + case 0x3c9: /* 1 111 001 001 */ cp1610_xorat(1,1); break; + case 0x3ca: /* 1 111 001 010 */ cp1610_xorat(1,2); break; + case 0x3cb: /* 1 111 001 011 */ cp1610_xorat(1,3); break; + case 0x3cc: /* 1 111 001 100 */ cp1610_xorat(1,4); break; + case 0x3cd: /* 1 111 001 101 */ cp1610_xorat(1,5); break; + case 0x3ce: /* 1 111 001 110 */ cp1610_xorat(1,6); break; + case 0x3cf: /* 1 111 001 111 */ cp1610_xorat(1,7); break; + + case 0x3d0: /* 1 111 010 000 */ cp1610_xorat(2,0); break; + case 0x3d1: /* 1 111 010 001 */ cp1610_xorat(2,1); break; + case 0x3d2: /* 1 111 010 010 */ cp1610_xorat(2,2); break; + case 0x3d3: /* 1 111 010 011 */ cp1610_xorat(2,3); break; + case 0x3d4: /* 1 111 010 100 */ cp1610_xorat(2,4); break; + case 0x3d5: /* 1 111 010 101 */ cp1610_xorat(2,5); break; + case 0x3d6: /* 1 111 010 110 */ cp1610_xorat(2,6); break; + case 0x3d7: /* 1 111 010 111 */ cp1610_xorat(2,7); break; + + case 0x3d8: /* 1 111 011 000 */ cp1610_xorat(3,0); break; + case 0x3d9: /* 1 111 011 001 */ cp1610_xorat(3,1); break; + case 0x3da: /* 1 111 011 010 */ cp1610_xorat(3,2); break; + case 0x3db: /* 1 111 011 011 */ cp1610_xorat(3,3); break; + case 0x3dc: /* 1 111 011 100 */ cp1610_xorat(3,4); break; + case 0x3dd: /* 1 111 011 101 */ cp1610_xorat(3,5); break; + case 0x3de: /* 1 111 011 110 */ cp1610_xorat(3,6); break; + case 0x3df: /* 1 111 011 111 */ cp1610_xorat(3,7); break; + + case 0x3e0: /* 1 111 100 000 */ cp1610_xorat_i(4,0); break; + case 0x3e1: /* 1 111 100 001 */ cp1610_xorat_i(4,1); break; + case 0x3e2: /* 1 111 100 010 */ cp1610_xorat_i(4,2); break; + case 0x3e3: /* 1 111 100 011 */ cp1610_xorat_i(4,3); break; + case 0x3e4: /* 1 111 100 100 */ cp1610_xorat_i(4,4); break; + case 0x3e5: /* 1 111 100 101 */ cp1610_xorat_i(4,5); break; + case 0x3e6: /* 1 111 100 110 */ cp1610_xorat_i(4,6); break; + case 0x3e7: /* 1 111 100 111 */ cp1610_xorat_i(4,7); break; + + case 0x3e8: /* 1 111 101 000 */ cp1610_xorat_i(5,0); break; + case 0x3e9: /* 1 111 101 001 */ cp1610_xorat_i(5,1); break; + case 0x3ea: /* 1 111 101 010 */ cp1610_xorat_i(5,2); break; + case 0x3eb: /* 1 111 101 011 */ cp1610_xorat_i(5,3); break; + case 0x3ec: /* 1 111 101 100 */ cp1610_xorat_i(5,4); break; + case 0x3ed: /* 1 111 101 101 */ cp1610_xorat_i(5,5); break; + case 0x3ee: /* 1 111 101 110 */ cp1610_xorat_i(5,6); break; + case 0x3ef: /* 1 111 101 111 */ cp1610_xorat_i(5,7); break; + + case 0x3f0: /* 1 111 110 000 */ cp1610_xorat_d(6,0); break; + case 0x3f1: /* 1 111 110 001 */ cp1610_xorat_d(6,1); break; + case 0x3f2: /* 1 111 110 010 */ cp1610_xorat_d(6,2); break; + case 0x3f3: /* 1 111 110 011 */ cp1610_xorat_d(6,3); break; + case 0x3f4: /* 1 111 110 100 */ cp1610_xorat_d(6,4); break; + case 0x3f5: /* 1 111 110 101 */ cp1610_xorat_d(6,5); break; + case 0x3f6: /* 1 111 110 110 */ cp1610_xorat_d(6,6); break; + case 0x3f7: /* 1 111 110 111 */ cp1610_xorat_d(6,7); break; + + case 0x3f8: /* 1 111 111 000 */ cp1610_xori(0); break; + case 0x3f9: /* 1 111 111 001 */ cp1610_xori(1); break; + case 0x3fa: /* 1 111 111 010 */ cp1610_xori(2); break; + case 0x3fb: /* 1 111 111 011 */ cp1610_xori(3); break; + case 0x3fc: /* 1 111 111 100 */ cp1610_xori(4); break; + case 0x3fd: /* 1 111 111 101 */ cp1610_xori(5); break; + case 0x3fe: /* 1 111 111 110 */ cp1610_xori(6); break; + case 0x3ff: /* 1 111 111 111 */ cp1610_xori(7); break; + } + + if (m_mask_interrupts == 0) + { + if (m_intr_pending == 1) + { + /* PSHR R7 */ + cp1610_writemem16(m_r[6],m_r[7]); + m_r[6]++; + m_icount -= 9; + m_intr_pending = 0; + m_r[7] = standard_irq_callback(CP1610_INT_INTR); + } + if ((m_intrm_pending == 1) && (m_intr_enabled)) + { + /* PSHR R7 */ + cp1610_writemem16(m_r[6],m_r[7]); + m_r[6]++; + m_icount -= 9; + m_intrm_pending = 0; + m_r[7] = standard_irq_callback(CP1610_INT_INTRM); + } + if (m_reset_pending == 1) + { + m_reset_pending = 0; + m_r[7] = standard_irq_callback(CP1610_RESET); + } + } + + } while( m_icount > 0 ); +} + + +void cp1610_cpu_device::device_start() +{ + m_read_bext.resolve_safe(0); + m_intr_enabled = 0; + m_reset_pending = 0; + m_intr_pending = 0; + m_intrm_pending = 0; + m_flags = 0; + memset(m_r, 0x00, sizeof(m_r)); + + m_program = &space(AS_PROGRAM); + + save_item(NAME(m_r)); + save_item(NAME(m_flags)); + save_item(NAME(m_intr_enabled)); + save_item(NAME(m_intr_vector)); + save_item(NAME(m_reset_state)); + save_item(NAME(m_intr_state)); + save_item(NAME(m_intrm_state)); + save_item(NAME(m_reset_pending)); + save_item(NAME(m_intr_pending)); + save_item(NAME(m_intrm_pending)); + save_item(NAME(m_mask_interrupts)); + + // Register state for debugger + state_add( CP1610_R0, "R0", m_r[0] ).formatstr("%04X"); + state_add( CP1610_R1, "R1", m_r[1] ).formatstr("%04X"); + state_add( CP1610_R2, "R2", m_r[2] ).formatstr("%04X"); + state_add( CP1610_R3, "R3", m_r[3] ).formatstr("%04X"); + state_add( CP1610_R4, "R4", m_r[4] ).formatstr("%04X"); + state_add( CP1610_R5, "R5", m_r[5] ).formatstr("%04X"); + state_add( CP1610_R6, "R6", m_r[6] ).formatstr("%04X"); + state_add( CP1610_R7, "R7", m_r[7] ).formatstr("%04X"); + state_add( STATE_GENPC, "curpc", m_r[7] ).noshow(); + state_add( STATE_GENFLAGS, "GENFLAGS", m_flags ).noshow(); + + m_icountptr = &m_icount; +} + +void cp1610_cpu_device::device_reset() +{ + /* This is how we set the reset vector */ + set_input_line(CP1610_RESET, PULSE_LINE); +} + +void cp1610_cpu_device::execute_set_input(int irqline, int state) +{ + switch(irqline) + { + case CP1610_INT_INTRM: + m_intrm_pending = (state == ASSERT_LINE); + m_intrm_state = state; + break; + case CP1610_RESET: + if (state == ASSERT_LINE) + m_reset_pending = 1; + m_reset_state = state; + break; + case CP1610_INT_INTR: + if (state == ASSERT_LINE) + m_intr_pending = 1; + m_intr_state = state; + break; + } +} + + +cp1610_cpu_device::cp1610_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : cpu_device(mconfig, CP1610, "CP1610", tag, owner, clock, "cp1610", __FILE__) + , m_program_config("program", ENDIANNESS_BIG, 16, 16, -1) + , m_read_bext(*this) +{ +} + + +void cp1610_cpu_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + switch (entry.index()) + { + case STATE_GENFLAGS: + strprintf(str, "%c%c%c%c", + m_flags & 0x80 ? 'S':'.', + m_flags & 0x40 ? 'Z':'.', + m_flags & 0x20 ? 'V':'.', + m_flags & 0x10 ? 'C':'.'); + break; + } +} + + +offs_t cp1610_cpu_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( cp1610 ); + return CPU_DISASSEMBLE_NAME(cp1610)(this, buffer, pc, oprom, opram, options); +} diff --git a/src/devices/cpu/cp1610/cp1610.h b/src/devices/cpu/cp1610/cp1610.h new file mode 100644 index 00000000000..d3d7c9a78a4 --- /dev/null +++ b/src/devices/cpu/cp1610/cp1610.h @@ -0,0 +1,216 @@ +// license:BSD-3-Clause +// copyright-holders:Frank Palazzolo +/***************************************************************************** + * + * cp1610.h + * Portable General Instruments CP1610 emulator interface + * + * Copyright Frank Palazzolo, all rights reserved. + * + *****************************************************************************/ + +#pragma once + +#ifndef __CP1610_H__ +#define __CP1610_H__ + +enum +{ + CP1610_R0=1, CP1610_R1, CP1610_R2, CP1610_R3, + CP1610_R4, CP1610_R5, CP1610_R6, CP1610_R7 +}; + +#define CP1610_INT_NONE 0 +#define CP1610_INT_INTRM 1 /* Maskable */ +#define CP1610_RESET INPUT_LINE_RESET /* Non-Maskable */ +#define CP1610_INT_INTR INPUT_LINE_NMI /* Non-Maskable */ + +#define MCFG_CP1610_BEXT_CALLBACK(_read) \ + downcast(device)->set_bext_callback(DEVCB_##_read); + + +class cp1610_cpu_device : public cpu_device +{ +public: + // construction/destruction + cp1610_cpu_device(const machine_config &mconfig, const char *_tag, device_t *_owner, UINT32 _clock); + + template void set_bext_callback(_read rd) + { + m_read_bext.set_callback(rd); + } + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_execute_interface overrides + virtual UINT32 execute_min_cycles() const { return 1; } + virtual UINT32 execute_max_cycles() const { return 7; } + virtual UINT32 execute_input_lines() const { return 2; } + virtual void execute_run(); + virtual void execute_set_input(int inputnum, int state); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const { return (spacenum == AS_PROGRAM) ? &m_program_config : NULL; } + + // device_state_interface overrides + void state_string_export(const device_state_entry &entry, std::string &str); + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const { return 2; } + virtual UINT32 disasm_max_opcode_bytes() const { return 8; } + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + +private: + address_space_config m_program_config; + + UINT16 m_r[8]; /* registers */ + UINT8 m_flags; /* flags */ + int m_intr_enabled; + UINT16 m_intr_vector; + int m_reset_state; + int m_intr_state; + int m_intrm_state; + int m_reset_pending; + int m_intr_pending; + int m_intrm_pending; + int m_mask_interrupts; + address_space *m_program; + int m_icount; + + devcb_read8 m_read_bext; + + void cp1610_illegal(); + void cp1610_hlt(); + void cp1610_eis(); + void cp1610_dis(); + void cp1610_tci(); + void cp1610_clrc(); + void cp1610_setc(); + void cp1610_incr(int n); + void cp1610_decr(int n); + void cp1610_comr(int n); + void cp1610_negr(int n); + void cp1610_adcr(int n); + void cp1610_gswd(int n); + void cp1610_nop(); + void cp1610_sin(); + void cp1610_rswd(int n); + void cp1610_swap(int r); + void cp1610_dswap(int r); + void cp1610_sll_1(int r); + void cp1610_sll_2(int r); + void cp1610_rlc_1(int r); + void cp1610_rlc_2(int r); + void cp1610_sllc_1(int r); + void cp1610_sllc_2(int r); + void cp1610_slr_1(int r); + void cp1610_slr_2(int r); + void cp1610_sar_1(int r); + void cp1610_sar_2(int r); + void cp1610_rrc_1(int r); + void cp1610_rrc_2(int r); + void cp1610_sarc_1(int r); + void cp1610_sarc_2(int r); + void cp1610_tstr(int n); + void cp1610_movr(int s, int d); + void cp1610_addr(int s, int d); + void cp1610_subr(int s, int d); + void cp1610_cmpr(int s, int d); + void cp1610_andr(int s, int d); + void cp1610_xorr(int s, int d); + void cp1610_clrr(int d); + void cp1610_b(int dir); + void cp1610_nopp(int dir); + void cp1610_bc(int dir); + void cp1610_bnc(int dir); + void cp1610_bov(int dir); + void cp1610_bnov(int dir); + void cp1610_bpl(int dir); + void cp1610_bmi(int dir); + void cp1610_bze(int dir); + void cp1610_bnze(int dir); + void cp1610_blt(int dir); + void cp1610_bge(int dir); + void cp1610_ble(int dir); + void cp1610_bgt(int dir); + void cp1610_busc(int dir); + void cp1610_besc(int dir); + void cp1610_bext(int ext, int dir); + void cp1610_mvo(int s); + void cp1610_mvoat(int s, int m); + void cp1610_mvoat_i(int s, int m); + void cp1610_mvoi(int s); + void cp1610_mvi(int d); + void cp1610_mviat(int m, int d); + void cp1610_mviat_i(int m, int d); + void cp1610_pulr(int d); + void cp1610_mvii(int d); + void cp1610_add(int d); + void cp1610_addat(int m, int d); + void cp1610_addat_i(int m, int d); + void cp1610_addat_d(int m, int d); + void cp1610_addi(int d); + void cp1610_sub(int d); + void cp1610_subat(int m, int d); + void cp1610_subat_i(int m, int d); + void cp1610_subat_d(int m, int d); + void cp1610_subi(int d); + void cp1610_cmp(int d); + void cp1610_cmpat(int m, int d); + void cp1610_cmpat_i(int m, int d); + void cp1610_cmpat_d(int m, int d); + void cp1610_cmpi(int d); + void cp1610_and(int d); + void cp1610_andat(int m, int d); + void cp1610_andat_i(int m, int d); + void cp1610_andat_d(int m, int d); + void cp1610_andi(int d); + void cp1610_xor(int d); + void cp1610_xorat(int m, int d); + void cp1610_xorat_i(int m, int d); + void cp1610_xorat_d(int m, int d); + void cp1610_xori(int d); + void cp1610_sdbd_mviat(int r, int d); + void cp1610_sdbd_mviat_i(int r, int d); + void cp1610_sdbd_mviat_d(int r, int d); + void cp1610_sdbd_mvii(int d); + void cp1610_sdbd_addat(int r, int d); + void cp1610_sdbd_addat_i(int r, int d); + void cp1610_sdbd_addat_d(int r, int d); + void cp1610_sdbd_addi(int d); + void cp1610_sdbd_subat(int r, int d); + void cp1610_sdbd_subat_i(int r, int d); + void cp1610_sdbd_subat_d(int r, int d); + void cp1610_sdbd_subi(int d); + void cp1610_sdbd_cmpat(int r, int d); + void cp1610_sdbd_cmpat_i(int r, int d); + void cp1610_sdbd_cmpat_d(int r, int d); + void cp1610_sdbd_cmpi(int d); + void cp1610_sdbd_andat(int r, int d); + void cp1610_sdbd_andat_i(int r, int d); + void cp1610_sdbd_andat_d(int r, int d); + void cp1610_sdbd_andi(int d); + void cp1610_sdbd_xorat(int r, int d); + void cp1610_sdbd_xorat_i(int r, int d); + void cp1610_sdbd_xorat_d(int r, int d); + void cp1610_sdbd_xori(int d); + void cp1610_jsr(int r, UINT16 addr); + void cp1610_jsre(int r, UINT16 addr); + void cp1610_jsrd(int r, UINT16 addr); + void cp1610_j(UINT16 addr); + void cp1610_je(UINT16 addr); + void cp1610_jd(UINT16 addr); + void cp1610_do_sdbd(); + void cp1610_do_jumps(); +}; + + +extern const device_type CP1610; + + +CPU_DISASSEMBLE( cp1610 ); + +#endif /* __CP1610_H__ */ diff --git a/src/devices/cpu/cubeqcpu/cubedasm.c b/src/devices/cpu/cubeqcpu/cubedasm.c new file mode 100644 index 00000000000..81d7d95c088 --- /dev/null +++ b/src/devices/cpu/cubeqcpu/cubedasm.c @@ -0,0 +1,306 @@ +// license:BSD-3-Clause +// copyright-holders:Philip Bennett +/*************************************************************************** + + cubedasm.c + + Implementation of the Cube Quest AM2901-based CPUs + +***************************************************************************/ + +#include "emu.h" +#include "cubeqcpu.h" + + +/*************************************************************************** + CONSTANTS +***************************************************************************/ + +/* Am2901 Instruction Fields */ +static const char *const ins[] = +{ + "ADD ", + "SUBR ", + "SUBS ", + "OR ", + "AND ", + "NOTRS", + "EXOR ", + "EXNOR", +}; + +static const char *const src[] = +{ + "A,Q", + "A,B", + "0,Q", + "0,B", + "0,A", + "D,A", + "D,Q", + "D,0", +}; + +static const char *const dst[] = +{ + "QREG ", + "NOP ", + "RAMA ", + "RAMF ", + "RAMQD", + "RAMD ", + "RAMQU", + "RAMU ", +}; + + +/*************************************************************************** + SOUND DISASSEMBLY HOOK +***************************************************************************/ + +CPU_DISASSEMBLE( cquestsnd ) +{ + static const char *const jmps[] = + { + "JUMP ", + " ", + "JMSB ", + "JNMSB", + " ", + "JZERO", + "JOVR ", + "JLOOP", + }; + + + static const char *const latches[] = + { + "PLTCH ", + "DAC ", + "ADLATCH", + " ", + }; + + UINT64 inst = BIG_ENDIANIZE_INT64(*(UINT64 *)oprom); + UINT32 inslow = inst & 0xffffffff; + UINT32 inshig = inst >> 32; + + int t = (inshig >> 24) & 0xff; + int b = (inshig >> 20) & 0xf; + int a = (inshig >> 16) & 0xf; + int ci = (inshig >> 15) & 1; + int i5_3 = (inshig >> 12) & 7; + int _ramen = (inshig >> 11) & 1; + int i2_0 = (inshig >> 8) & 7; + int rtnltch = (inshig >> 7) & 1; + int jmp = (inshig >> 4) & 7; + int inca = (inshig >> 3) & 1; + int i8_6 = (inshig >> 0) & 7; + int _ipram = (inslow >> 31) & 1; + int _ipwrt = (inslow >> 30) & 1; + int latch = (inslow >> 28) & 3; + int rtn = (inslow >> 27) & 1; + int _rin = (inslow >> 26) & 1; + + + sprintf(buffer, "%s %s %s %x,%x,%c %.2x %s %s %.2x %s %s %s %c %c %c", + ins[i5_3], + src[i2_0], + dst[i8_6], + a, + b, + ci ? 'C' : ' ', + _rin, + jmps[jmp], + rtn ? "RET" : " ", + t, + latches[latch], + rtnltch ? "RTLATCH" : " ", + _ramen ? "PROM" : "RAM ", + _ipram ? ' ' : 'R', + _ipwrt ? ' ' : 'W', + inca ? 'I' : ' '); + + return 1 | DASMFLAG_SUPPORTED; +} + + +/*************************************************************************** + ROTATE DISASSEMBLY HOOK +***************************************************************************/ + +CPU_DISASSEMBLE( cquestrot ) +{ + static const char *const jmps[] = + { + " ", + "JSEQ ", + "JC ", + "JSYNC ", + "JLDWAIT", + "JMSB ", + "JGEONE ", + "JZERO ", + + "JUMP ", + "JNSEQ ", + "JNC ", + "JNSYNC ", + "JNLDWAI", + "JNMSB ", + "JLTONE ", + "JNZERO ", + }; + + static const char *const youts[] = + { + " ", + " ", + "Y2LDA", + "Y2LDD", + "Y2DAD", + "Y2DIN", + "Y2R ", + "Y2D ", + }; + + static const char *const spfs[] = + { + " ", + " ", + "OP ", + "RET ", + "SQLTCH", + "SWRT ", + "DIV ", + "MULT ", + + "DRED ", + "DWRT ", + "??? ", + "??? ", + "??? ", + "??? ", + "??? ", + "??? " + }; + + UINT64 inst = BIG_ENDIANIZE_INT64(*(UINT64 *)oprom); + UINT32 inslow = inst & 0xffffffff; + UINT32 inshig = inst >> 32; + + int t = (inshig >> 20) & 0xfff; + int jmp = (inshig >> 16) & 0xf; + int spf = (inshig >> 12) & 0xf; +// int rsrc = (inshig >> 11) & 0x1; + int yout = (inshig >> 8) & 0x7; + int sel = (inshig >> 6) & 0x3; +// int dsrc = (inshig >> 4) & 0x3; + int b = (inshig >> 0) & 0xf; + int a = (inslow >> 28) & 0xf; + int i8_6 = (inslow >> 24) & 0x7; + int ci = (inslow >> 23) & 0x1; + int i5_3 = (inslow >> 20) & 0x7; +// int _sex = (inslow >> 19) & 0x1; + int i2_0 = (inslow >> 16) & 0x7; + + sprintf(buffer, "%s %s,%s %x,%x,%c %d %s %s %s %.2x", + ins[i5_3], + src[i2_0], + dst[i8_6], + a, + b, + ci ? 'C' : ' ', + sel, + jmps[jmp], + youts[yout], + spfs[spf], + t); + + return 1 | DASMFLAG_SUPPORTED; +} + +/*************************************************************************** + LINE DRAWER DISASSEMBLY HOOK +***************************************************************************/ + +CPU_DISASSEMBLE( cquestlin ) +{ + static const char *const jmps[] = + { + " ", + "JMSB ", + "JSEQ ", + "JGTZ ", + "JC ", + "JZ ", + "?????", + "?????", + + "JUMP ", + "JNMSB", + "JNSEQ", + "JLEZ ", + "JNC ", + "JNZ ", + "?????", + "?????", + }; + + static const char *const latches[] = + { + " ", + "SEQLTCH", + "XLTCH ", + "YLTCH ", + "BGLTCH ", + "FGLTCH ", + "CLTCH ", + "ZLTCH ", + }; + + static const char *const spfs[] = + { + " ", + "FSTOP ", + "FREG ", + "FSTART", + "PWRT ", + "MULT ", + "LSTOP ", + "BRES ", + }; + + UINT64 inst = BIG_ENDIANIZE_INT64(*(UINT64 *)oprom); + UINT32 inslow = inst & 0xffffffff; + UINT32 inshig = inst >> 32; + + int t = (inshig >> 24) & 0xff; + int jmp = (inshig >> 20) & 0xf; + int latch = (inshig >> 16) & 0x7; + int op = (inshig >> 15) & 0x1; + int spf = (inshig >> 12) & 0x7; + int b = (inshig >> 8) & 0xf; + int a = (inshig >> 4) & 0xf; + int i8_6 = (inshig >> 0) & 0x7; + int ci = (inslow >> 31) & 0x1; + int i5_3 = (inslow >> 28) & 0x7; + int _pbcs = (inslow >> 27) & 0x1; + int i2_0 = (inslow >> 24) & 0x7; + + sprintf(buffer, "%s %s,%s %x,%x %c %s %.2x %s %s %s %s", + ins[i5_3], + src[i2_0], + dst[i8_6], + a, + b, + ci ? 'C' : ' ', + jmps[jmp], + t, + latches[latch], + op ? "OP" : " ", + _pbcs ? " " : "PB", + spfs[spf]); + + return 1 | DASMFLAG_SUPPORTED; +} diff --git a/src/devices/cpu/cubeqcpu/cubeqcpu.c b/src/devices/cpu/cubeqcpu/cubeqcpu.c new file mode 100644 index 00000000000..2a1678396c2 --- /dev/null +++ b/src/devices/cpu/cubeqcpu/cubeqcpu.c @@ -0,0 +1,1542 @@ +// license:BSD-3-Clause +// copyright-holders:Philip Bennett +/*************************************************************************** + + cubeqcpu.c + + Implementation of the Cube Quest AM2901-based CPUs + Copyright Philip J Bennett + + TODO: + + * Tidy up diassembly (split into different files?) + +***************************************************************************/ + +#include "emu.h" +#include "debugger.h" +#include "cubeqcpu.h" + + +/*************************************************************************** + CONSTANTS +***************************************************************************/ + +/* Am2901 Instruction Fields */ +enum alu_src +{ + AQ = 0, + AB = 1, + ZQ = 2, + ZB = 3, + ZA = 4, + DA = 5, + DQ = 6, + DZ = 7 +}; + +enum alu_ins +{ + ADD = 0, + SUBR = 1, + SUBS = 2, + OR = 3, + AND = 4, + NOTRS = 5, + EXOR = 6, + EXNOR = 7 +}; + +enum alu_dst +{ + QREG = 0, + NOP = 1, + RAMA = 2, + RAMF = 3, + RAMQD = 4, + RAMD = 5, + RAMQU = 6, + RAMU = 7 +}; + +/*************************************************************************** + MACROS +***************************************************************************/ + +#define _BIT(x, n) ((x) & (1 << (n))) + +/*************************************************************************** + STRUCTURES & TYPEDEFS +***************************************************************************/ + + +const device_type CQUESTSND = &device_creator; +const device_type CQUESTROT = &device_creator; +const device_type CQUESTLIN = &device_creator; + + +cquestsnd_cpu_device::cquestsnd_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : cpu_device(mconfig, CQUESTSND, "Cube Quest Sound CPU", tag, owner, clock, "cquestsnd", __FILE__) + , m_program_config("program", ENDIANNESS_BIG, 64, 8, -3) + , m_dac_w(*this) + , m_sound_region_tag(NULL) +{ +} + + +offs_t cquestsnd_cpu_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( cquestsnd ); + return CPU_DISASSEMBLE_NAME(cquestsnd)(this, buffer, pc, oprom, opram, options); +} + + +cquestrot_cpu_device::cquestrot_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : cpu_device(mconfig, CQUESTROT, "Cube Quest Rotate CPU", tag, owner, clock, "cquestrot", __FILE__) + , m_program_config("program", ENDIANNESS_BIG, 64, 9, -3) + , m_linedata_w(*this) +{ +} + + +READ16_MEMBER( cquestrot_cpu_device::linedata_r ) +{ + return m_linedata; +} + + +offs_t cquestrot_cpu_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( cquestrot ); + return CPU_DISASSEMBLE_NAME(cquestrot)(this, buffer, pc, oprom, opram, options); +} + + +cquestlin_cpu_device::cquestlin_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : cpu_device(mconfig, CQUESTLIN, "Cube Quest Line CPU", tag, owner, clock, "cquestlin", __FILE__) + , m_program_config("program", ENDIANNESS_BIG, 64, 8, -3) + , m_linedata_r(*this) + , m_flags(0) + , m_curpc(0) +{ +} + + +offs_t cquestlin_cpu_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( cquestlin ); + return CPU_DISASSEMBLE_NAME(cquestlin)(this, buffer, pc, oprom, opram, options); +} + + +WRITE16_MEMBER( cquestlin_cpu_device::linedata_w ) +{ + m_sram[offset] = data; +} + + +/*************************************************************************** + MEMORY ACCESSORS FOR 68000 +***************************************************************************/ + +WRITE16_MEMBER( cquestsnd_cpu_device::sndram_w ) +{ + COMBINE_DATA(&m_sram[offset]); +} + +READ16_MEMBER( cquestsnd_cpu_device::sndram_r ) +{ + return m_sram[offset]; +} + + +WRITE16_MEMBER( cquestrot_cpu_device::rotram_w ) +{ + COMBINE_DATA(&m_dram[offset]); +} + +READ16_MEMBER( cquestrot_cpu_device::rotram_r ) +{ + return m_dram[offset]; +} + + +/*************************************************************************** + SOUND INITIALIZATION AND SHUTDOWN +***************************************************************************/ + +void cquestsnd_cpu_device::device_start() +{ + m_dac_w.resolve_safe(); + assert(m_sound_region_tag != NULL); + m_sound_data = (UINT16*)machine().root_device().memregion(m_sound_region_tag)->base(); + + m_program = &space(AS_PROGRAM); + m_direct = &m_program->direct(); + + memset(m_ram, 0, sizeof(m_ram)); + m_q = 0; + m_f = 0; + m_y = 0; + m_cflag = 0; + m_vflag = 0; + m_pc = 0; + m_platch = 0; + m_rtnlatch = 0; + m_adrcntr = 0; + m_dinlatch = 0; + m_ramwlatch = 0; + m_prev_ipram = 0; + m_prev_ipwrt = 0; + m_adrlatch = 0; + + save_item(NAME(m_ram)); + save_item(NAME(m_q)); + save_item(NAME(m_f)); + save_item(NAME(m_y)); + save_item(NAME(m_cflag)); + save_item(NAME(m_vflag)); + + save_item(NAME(m_pc)); + save_item(NAME(m_platch)); + save_item(NAME(m_rtnlatch)); + save_item(NAME(m_adrcntr)); + save_item(NAME(m_adrlatch)); + save_item(NAME(m_dinlatch)); + save_item(NAME(m_ramwlatch)); + save_item(NAME(m_prev_ipram)); + save_item(NAME(m_prev_ipwrt)); + + state_add( CQUESTSND_PC, "PC", m_pc).formatstr("%02X"); + state_add( CQUESTSND_Q, "Q", m_q).formatstr("%04X"); + state_add( CQUESTSND_RTNLATCH, "RTN", m_rtnlatch).formatstr("%02X"); + state_add( CQUESTSND_ADRCNTR, "CNT", m_adrcntr).formatstr("%02X"); + state_add( CQUESTSND_DINLATCH, "DINX", m_dinlatch).formatstr("%04X"); + state_add( CQUESTSND_RAM0, "RAM[0]", m_ram[0x0]).formatstr("%04X"); + state_add( CQUESTSND_RAM1, "RAM[1]", m_ram[0x1]).formatstr("%04X"); + state_add( CQUESTSND_RAM2, "RAM[2]", m_ram[0x2]).formatstr("%04X"); + state_add( CQUESTSND_RAM3, "RAM[3]", m_ram[0x3]).formatstr("%04X"); + state_add( CQUESTSND_RAM4, "RAM[4]", m_ram[0x4]).formatstr("%04X"); + state_add( CQUESTSND_RAM5, "RAM[5]", m_ram[0x5]).formatstr("%04X"); + state_add( CQUESTSND_RAM6, "RAM[6]", m_ram[0x6]).formatstr("%04X"); + state_add( CQUESTSND_RAM7, "RAM[7]", m_ram[0x7]).formatstr("%04X"); + state_add( CQUESTSND_RAM8, "RAM[8]", m_ram[0x8]).formatstr("%04X"); + state_add( CQUESTSND_RAM9, "RAM[9]", m_ram[0x9]).formatstr("%04X"); + state_add( CQUESTSND_RAMA, "RAM[A]", m_ram[0xa]).formatstr("%04X"); + state_add( CQUESTSND_RAMB, "RAM[B]", m_ram[0xb]).formatstr("%04X"); + state_add( CQUESTSND_RAMC, "RAM[C]", m_ram[0xc]).formatstr("%04X"); + state_add( CQUESTSND_RAMD, "RAM[D]", m_ram[0xd]).formatstr("%04X"); + state_add( CQUESTSND_RAME, "RAM[E]", m_ram[0xe]).formatstr("%04X"); + state_add( CQUESTSND_RAMF, "RAM[F]", m_ram[0xf]).formatstr("%04X"); + + state_add(STATE_GENPC, "curpc", m_pc).formatstr("%02X").noshow(); + + m_icountptr = &m_icount; +} + + +void cquestsnd_cpu_device::device_reset() +{ + m_pc = 0; +} + + +/*************************************************************************** + ROTATE INITIALIZATION AND SHUTDOWN +***************************************************************************/ + +void cquestrot_cpu_device::device_start() +{ + m_linedata_w.resolve_safe(); + + m_program = &space(AS_PROGRAM); + m_direct = &m_program->direct(); + + memset(m_ram, 0, sizeof(m_ram)); + m_q = 0; + m_f = 0; + m_y = 0; + m_cflag = 0; + m_vflag = 0; + m_pc = 0; + m_seqcnt = 0; + m_dsrclatch = 0; + m_rsrclatch = 0; + m_dynaddr = 0; + m_dyndata = 0; + m_yrlatch = 0; + m_ydlatch = 0; + m_dinlatch = 0; + m_divreg = 0; + m_linedata = 0; + m_lineaddr = 0; + m_prev_dred = 0; + m_prev_dwrt = 0; + m_wc = 0; + m_rc = 0; + m_clkcnt = 0; + + save_item(NAME(m_ram)); + save_item(NAME(m_q)); + save_item(NAME(m_f)); + save_item(NAME(m_y)); + save_item(NAME(m_cflag)); + save_item(NAME(m_vflag)); + + save_item(NAME(m_pc)); + save_item(NAME(m_seqcnt)); + save_item(NAME(m_dsrclatch)); + save_item(NAME(m_rsrclatch)); + save_item(NAME(m_dynaddr)); + save_item(NAME(m_dyndata)); + save_item(NAME(m_yrlatch)); + save_item(NAME(m_ydlatch)); + save_item(NAME(m_dinlatch)); + save_item(NAME(m_divreg)); + save_item(NAME(m_linedata)); + save_item(NAME(m_lineaddr)); + save_item(NAME(m_prev_dred)); + save_item(NAME(m_prev_dwrt)); + save_item(NAME(m_wc)); + + save_pointer(NAME(m_dram), 16384); + save_pointer(NAME(m_sram), 2048); + + state_add( CQUESTROT_PC, "PC", m_pc).formatstr("%02X"); + state_add( CQUESTROT_Q, "Q", m_q).formatstr("%04X"); + state_add( CQUESTROT_RAM0, "RAM[0]", m_ram[0x0]).formatstr("%04X"); + state_add( CQUESTROT_RAM1, "RAM[1]", m_ram[0x1]).formatstr("%04X"); + state_add( CQUESTROT_RAM2, "RAM[2]", m_ram[0x2]).formatstr("%04X"); + state_add( CQUESTROT_RAM3, "RAM[3]", m_ram[0x3]).formatstr("%04X"); + state_add( CQUESTROT_RAM4, "RAM[4]", m_ram[0x4]).formatstr("%04X"); + state_add( CQUESTROT_RAM5, "RAM[5]", m_ram[0x5]).formatstr("%04X"); + state_add( CQUESTROT_RAM6, "RAM[6]", m_ram[0x6]).formatstr("%04X"); + state_add( CQUESTROT_RAM7, "RAM[7]", m_ram[0x7]).formatstr("%04X"); + state_add( CQUESTROT_RAM8, "RAM[8]", m_ram[0x8]).formatstr("%04X"); + state_add( CQUESTROT_RAM9, "RAM[9]", m_ram[0x9]).formatstr("%04X"); + state_add( CQUESTROT_RAMA, "RAM[A]", m_ram[0xa]).formatstr("%04X"); + state_add( CQUESTROT_RAMB, "RAM[B]", m_ram[0xb]).formatstr("%04X"); + state_add( CQUESTROT_RAMC, "RAM[C]", m_ram[0xc]).formatstr("%04X"); + state_add( CQUESTROT_RAMD, "RAM[D]", m_ram[0xd]).formatstr("%04X"); + state_add( CQUESTROT_RAME, "RAM[E]", m_ram[0xe]).formatstr("%04X"); + state_add( CQUESTROT_RAMF, "RAM[F]", m_ram[0xf]).formatstr("%04X"); + state_add( CQUESTROT_SEQCNT, "SEQCNT", m_seqcnt).formatstr("%01X"); + state_add( CQUESTROT_DYNADDR, "DYNADDR", m_dynaddr).formatstr("%04X"); + state_add( CQUESTROT_DYNDATA, "DYNDATA", m_dyndata).formatstr("%04X"); + state_add( CQUESTROT_YRLATCH, "YRLATCH", m_yrlatch).formatstr("%04X"); + state_add( CQUESTROT_YDLATCH, "YDLATCH", m_ydlatch).formatstr("%04X"); + state_add( CQUESTROT_DINLATCH, "DINLATCH", m_dinlatch).formatstr("%04X"); + state_add( CQUESTROT_DSRCLATCH, "DSRCLATCH", m_dsrclatch).formatstr("%04X"); + state_add( CQUESTROT_RSRCLATCH, "RSRCLATCH", m_rsrclatch).formatstr("%04X"); + state_add( CQUESTROT_LDADDR, "LDADDR", m_lineaddr).formatstr("%04X"); + state_add( CQUESTROT_LDDATA, "LDDATA", m_linedata).formatstr("%04X"); + + state_add(STATE_GENPC, "curpc", m_pc).formatstr("%02X").noshow(); + state_add(STATE_GENFLAGS, "GENFLAGS", m_flags).formatstr("%3s").noshow(); + + m_icountptr = &m_icount; +} + + +void cquestrot_cpu_device::device_reset() +{ + m_pc = 0; + m_wc = 0; + m_prev_dred = 1; + m_prev_dwrt = 1; +} + + +void cquestrot_cpu_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + switch (entry.index()) + { + case STATE_GENFLAGS: + strprintf(str, "%c%c%c", m_cflag ? 'C' : '.', + m_vflag ? 'V' : '.', + m_f ? '.' : 'Z'); + break; + } +} + + +/*************************************************************************** + LINE DRAWER INITIALIZATION AND SHUTDOWN +***************************************************************************/ +#define FOREGROUND 0 +#define BACKGROUND 1 +#define ODD_FIELD 0 +#define EVEN_FIELD 1 + +void cquestlin_cpu_device::device_start() +{ + m_linedata_r.resolve_safe(0); + + m_program = &space(AS_PROGRAM); + m_direct = &m_program->direct(); + + memset(m_ram, 0, sizeof(m_ram)); + m_q = 0; + m_f = 0; + m_y = 0; + m_cflag = 0; + m_vflag = 0; + m_pc[0] = m_pc[1] = 0; + m_seqcnt = 0; + m_clatch = 0; + m_zlatch = 0; + m_xcnt = 0; + m_ycnt = 0; + m_sreg = 0; + m_fadlatch = 0; + m_badlatch = 0; + m_sramdlatch = 0; + m_fglatch = 0; + m_bglatch = 0; + m_gt0reg = 0; + m_fdxreg = 0; + m_field = 0; + m_clkcnt = 0; + + save_item(NAME(m_ram)); + save_item(NAME(m_q)); + save_item(NAME(m_f)); + save_item(NAME(m_y)); + save_item(NAME(m_cflag)); + save_item(NAME(m_vflag)); + + save_item(NAME(m_pc[0])); + save_item(NAME(m_pc[1])); + save_item(NAME(m_seqcnt)); + save_item(NAME(m_clatch)); + save_item(NAME(m_zlatch)); + save_item(NAME(m_xcnt)); + save_item(NAME(m_ycnt)); + save_item(NAME(m_sreg)); + save_item(NAME(m_fadlatch)); + save_item(NAME(m_badlatch)); + save_item(NAME(m_sramdlatch)); + save_item(NAME(m_fglatch)); + save_item(NAME(m_bglatch)); + save_item(NAME(m_gt0reg)); + save_item(NAME(m_fdxreg)); + save_item(NAME(m_field)); + save_item(NAME(m_clkcnt)); + + save_pointer(NAME(m_sram), 4096); + save_pointer(NAME(m_ptr_ram), 1024); + save_pointer(NAME(m_e_stack), 32768); + save_pointer(NAME(m_o_stack), 32768); + + state_add( CQUESTLIN_FGPC, "FPC", m_pc[FOREGROUND]).formatstr("%02X"); + state_add( CQUESTLIN_BGPC, "BPC", m_pc[BACKGROUND]).formatstr("%02X"); + state_add( CQUESTLIN_Q, "Q", m_q).formatstr("%04X"); + state_add( CQUESTLIN_RAM0, "RAM[0]", m_ram[0x0]).formatstr("%04X"); + state_add( CQUESTLIN_RAM1, "RAM[1]", m_ram[0x1]).formatstr("%04X"); + state_add( CQUESTLIN_RAM2, "RAM[2]", m_ram[0x2]).formatstr("%04X"); + state_add( CQUESTLIN_RAM3, "RAM[3]", m_ram[0x3]).formatstr("%04X"); + state_add( CQUESTLIN_RAM4, "RAM[4]", m_ram[0x4]).formatstr("%04X"); + state_add( CQUESTLIN_RAM5, "RAM[5]", m_ram[0x5]).formatstr("%04X"); + state_add( CQUESTLIN_RAM6, "RAM[6]", m_ram[0x6]).formatstr("%04X"); + state_add( CQUESTLIN_RAM7, "RAM[7]", m_ram[0x7]).formatstr("%04X"); + state_add( CQUESTLIN_RAM8, "RAM[8]", m_ram[0x8]).formatstr("%04X"); + state_add( CQUESTLIN_RAM9, "RAM[9]", m_ram[0x9]).formatstr("%04X"); + state_add( CQUESTLIN_RAMA, "RAM[A]", m_ram[0xa]).formatstr("%04X"); + state_add( CQUESTLIN_RAMB, "RAM[B]", m_ram[0xb]).formatstr("%04X"); + state_add( CQUESTLIN_RAMC, "RAM[C]", m_ram[0xc]).formatstr("%04X"); + state_add( CQUESTLIN_RAMD, "RAM[D]", m_ram[0xd]).formatstr("%04X"); + state_add( CQUESTLIN_RAME, "RAM[E]", m_ram[0xe]).formatstr("%04X"); + state_add( CQUESTLIN_RAMF, "RAM[F]", m_ram[0xf]).formatstr("%04X"); + + state_add( CQUESTLIN_FADLATCH, "FADDR", m_fadlatch).formatstr("%04X"); + state_add( CQUESTLIN_BADLATCH, "BADDR", m_badlatch).formatstr("%04X"); + state_add( CQUESTLIN_SREG, "SREG", m_sreg).formatstr("%04X"); + state_add( CQUESTLIN_XCNT, "XCNT", m_xcnt).formatstr("%03X"); + state_add( CQUESTLIN_YCNT, "YCNT", m_ycnt).formatstr("%03X"); + state_add( CQUESTLIN_CLATCH, "CLATCH", m_clatch).formatstr("%04X"); + state_add( CQUESTLIN_ZLATCH, "ZLATCH", m_zlatch).formatstr("%04X"); + + state_add(STATE_GENPC, "curpc", m_curpc).callimport().callexport().formatstr("%02X").noshow(); + state_add(STATE_GENFLAGS, "GENFLAGS", m_flags).formatstr("%6s").noshow(); + + m_icountptr = &m_icount; +} + + +void cquestlin_cpu_device::device_reset() +{ + m_clkcnt = 0; + m_pc[FOREGROUND] = 0; + m_pc[BACKGROUND] = 0x80; +} + + +void cquestlin_cpu_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + switch (entry.index()) + { + case STATE_GENFLAGS: + strprintf(str, "%c%c%c|%cG", m_cflag ? 'C' : '.', + m_vflag ? 'V' : '.', + m_f ? '.' : 'Z', + ( m_clkcnt & 3 ) ? 'B' : 'F'); + break; + } +} + + +/*************************************************************************** + SOUND CORE EXECUTION LOOP +***************************************************************************/ + +#define SND_PC (m_pc) +#define SND_DATA_IN (_ramen ? m_sound_data[m_platch] : m_dinlatch) + +enum snd_latch_type +{ + PLTCH = 0, + DAC = 1, + ADLATCH = 2 +}; + +int cquestsnd_cpu_device::do_sndjmp(int jmp) +{ + switch (jmp) + { + /* JUMP */ case 0: return 1; + /* MSB */ case 2: return m_f & 0x8000 ? 0 : 1; + /* !MSB */ case 3: return m_f & 0x8000 ? 1 : 0; + /* ZERO */ case 5: return m_f == 0 ? 0 : 1; + /* OVR */ case 6: return m_vflag ? 0 : 1; + /* LOOP */ case 7: return m_adrcntr & 0x80 ? 0: 1; + } + + return 0; +} + +void cquestsnd_cpu_device::execute_run() +{ + /* Core execution loop */ + do + { + /* Decode the instruction */ + UINT64 inst = m_direct->read_qword(SND_PC << 3); + UINT32 inslow = inst & 0xffffffff; + UINT32 inshig = inst >> 32; + + int t = (inshig >> 24) & 0xff; + int b = (inshig >> 20) & 0xf; + int a = (inshig >> 16) & 0xf; + int ci = (inshig >> 15) & 1; + int i5_3 = (inshig >> 12) & 7; + int _ramen = (inshig >> 11) & 1; + int i2_0 = (inshig >> 8) & 7; + int rtnltch = (inshig >> 7) & 1; + int jmp = (inshig >> 4) & 7; + int inca = (inshig >> 3) & 1; + int i8_6 = (inshig >> 0) & 7; + int _ipram = (inslow >> 31) & 1; + int _ipwrt = (inslow >> 30) & 1; + int latch = (inslow >> 28) & 3; + int rtn = (inslow >> 27) & 1; + int _rin = (inslow >> 26) & 1; + + debugger_instruction_hook(this, m_pc); + + /* Don't think this matters, but just in case */ + if (rtn) + t = m_rtnlatch; + + /* Handle the AM2901 ALU instruction */ + { + UINT16 r = 0; + UINT16 s = 0; + + UINT32 res = 0; + UINT32 cflag = 0; + UINT32 vflag = 0; + + /* Determine the ALU sources */ + switch (i2_0) + { + case AQ: r = m_ram[a]; s = m_q; break; + case AB: r = m_ram[a]; s = m_ram[b]; break; + case ZQ: r = 0; s = m_q; break; + case ZB: r = 0; s = m_ram[b]; break; + case ZA: r = 0; s = m_ram[a]; break; + case DA: r = SND_DATA_IN; s = m_ram[a]; break; + case DQ: r = SND_DATA_IN; s = m_q; break; + case DZ: r = SND_DATA_IN; s = 0; break; + } + + /* Perform the ALU operation */ + switch (i5_3) + { + case ADD: + res = r + s + ci; + cflag = (res >> 16) & 1; + vflag = (((r & 0x7fff) + (s & 0x7fff) + ci) >> 15) ^ cflag; + break; + case SUBR: + res = ~r + s + ci; + cflag = (res >> 16) & 1; + vflag = (((s & 0x7fff) + (~r & 0x7fff) + ci) >> 15) ^ cflag; + break; + case SUBS: + res = r + ~s + ci; + cflag = (res >> 16) & 1; + vflag = (((r & 0x7fff) + (~s & 0x7fff) + ci) >> 15) ^ cflag; + break; + case OR: + res = r | s; + break; + case AND: + res = r & s; + break; + case NOTRS: + res = ~r & s; + break; + case EXOR: + res = r ^ s; + break; + case EXNOR: + res = ~(r ^ s); + break; + } + + m_f = res; + m_cflag = cflag; + m_vflag = vflag; + + switch (i8_6) + { + case QREG: + m_q = m_f; + m_y = m_f; + break; + case NOP: + m_y = m_f; + break; + case RAMA: + m_y = m_ram[a]; + m_ram[b] = m_f; + break; + case RAMF: + m_ram[b] = m_f; + m_y = m_f; + break; + case RAMQD: + { + UINT16 qin; + + m_ram[b] = (_rin ? 0 : 0x8000) | (m_f >> 1); + m_q >>= 1; + m_y = m_f; + + /* When right shifting Q, we need to OR in a value */ + qin = (((m_y >> 15) ^ (m_y >> 1)) & 1) ? 0 : 0x8000; + + m_q |= qin; + break; + } + case RAMD: + m_ram[b] = (_rin ? 0 : 0x8000) | (m_f >> 1); + m_y = m_f; + break; + case RAMQU: + m_ram[b] = (m_f << 1) | (_rin ? 0 : 0x0001); + m_q <<= 1; + m_y = m_f; + break; + case RAMU: + m_ram[b] = (m_f << 1) | (_rin ? 0 : 0x0001); + m_y = m_f; + break; + } + } + + /* Now handle any SRAM accesses from the previous cycle */ + if (!m_prev_ipram) + { + UINT16 addr = m_adrlatch | (m_adrcntr & 0x7f); + + if (!m_prev_ipwrt) + m_sram[addr] = m_ramwlatch; + else + m_dinlatch = m_sram[addr]; + } + + /* Handle latches */ + if (latch == PLTCH) + { + m_platch = ((t & 3) << 9) | ((m_y >> 6) & 0x1ff); + } + else if (latch == DAC) + { + m_dac_w((m_y & 0xfff0) | ((m_adrcntr >> 3) & 0xf)); + } + else if (latch == ADLATCH) + { + /* Load the SRAM address counter - this value is instantly loaded */ + m_adrcntr = m_y & 0x7f; + + /* Also load the SRAM address latch */ + m_adrlatch = m_y & 0x780; + } + + /* Check for jump/return */ + if ( do_sndjmp(jmp) ) + m_pc = rtn ? m_rtnlatch : t; + else + m_pc++; + + /* Load the return latch? (Obviously a load and a ret in the same cycle are invalid) */ + if (rtnltch) + m_rtnlatch = t; + + /* Only increment the sound counter if not loading */ + if (inca && latch != ADLATCH) + m_adrcntr++; + + /* Latch data for a RAM write (do actual write on the next cycle) */ + if (!_ipwrt) + m_ramwlatch = m_y; + + /* Save level sensitive bits */ + m_prev_ipram = _ipram; + m_prev_ipwrt = _ipwrt; + + m_icount--; + } while (m_icount > 0); +} + + +/*************************************************************************** + ROTATE CORE EXECUTION LOOP +***************************************************************************/ + +#define ROT_PC (m_pc & 0x1ff) + +enum rot_spf +{ + SPF_UNUSED0 = 0, + SPF_UNUSED1 = 1, + SPF_OP = 2, + SPF_RET = 3, + SPF_SQLTCH = 4, + SPF_SWRT = 5, + SPF_DIV = 6, + SPF_MULT = 7, + SPF_DRED = 8, + SPF_DWRT = 9 +}; + +enum rot_yout +{ + YOUT_UNUSED0 = 0, + YOUT_UNUSED1 = 1, + YOUT_Y2LDA = 2, + YOUT_Y2LDD = 3, + YOUT_Y2DAD = 4, + YOUT_Y2DYN = 5, + YOUT_Y2R = 6, + YOUT_Y2D = 7 +}; + +/* Sync is asserted for the duration of every fourth cycle */ +/* The Dynamic RAM latch clocks in a value at the end of this cycle */ +/* So CPU waits for sync before reading from DRAM */ + +int cquestrot_cpu_device::do_rotjmp(int jmp) +{ + int ret = 0; + + switch (jmp & 7) + { + /* */ case 0: ret = 0; break; + /* SEQ */ case 1: ret = (m_seqcnt == 0xf); break; + /* CAROUT */ case 2: ret = m_cflag; break; + /* SYNC */ case 3: ret = !(m_clkcnt & 0x3); break; + /* LDWAIT */ case 4: ret = 0; break; + /* MSB */ case 5: ret = BIT(m_f, 15); break; + /* >=1 */ case 6: ret = (!_BIT(m_f, 15) && !(m_f == 0)); break; + /* ZERO */ case 7: ret = (m_f == 0); break; + } + + return !(!ret ^ BIT(jmp, 3)); +} + + +#define ROT_SRAM_ADDRESS ((m_dsrclatch & 2) ? m_yrlatch : (m_rsrclatch | 0x700)) + + +void cquestrot_cpu_device::execute_run() +{ + /* Core execution loop */ + do + { + /* Decode the instruction */ + UINT64 inst = m_direct->read_qword(ROT_PC << 3); + + UINT32 inslow = inst & 0xffffffff; + UINT32 inshig = inst >> 32; + + int t = (inshig >> 20) & 0xfff; + int jmp = (inshig >> 16) & 0xf; + int spf = (inshig >> 12) & 0xf; + int rsrc = (inshig >> 11) & 0x1; + int yout = (inshig >> 8) & 0x7; + int sel = (inshig >> 6) & 0x3; + int dsrc = (inshig >> 4) & 0x3; + int b = (inshig >> 0) & 0xf; + int a = (inslow >> 28) & 0xf; + int i8_6 = (inslow >> 24) & 0x7; + int ci = (inslow >> 23) & 0x1; + int i5_3 = (inslow >> 20) & 0x7; + int _sex = (inslow >> 19) & 0x1; + int i2_0 = (inslow >> 16) & 0x7; + + int dsrclatch; + UINT16 data_in = 0xffff; + + debugger_instruction_hook(this, ROT_PC); + + /* Handle DRAM accesses - I ought to check this... */ + if (!(m_clkcnt & 3)) + { + if (m_wc) + { + m_wc = 0; + m_dram[m_dynaddr & 0x3fff] = m_dyndata; + } + if (m_rc) + { + m_rc = 0; + m_dinlatch = m_dram[m_dynaddr & 0x3fff]; + } + } + + /* Flag pending DRAM accesses */ + if (!m_prev_dwrt) + m_wc = 1; + else if (!m_prev_dred) + m_rc = 1; + + /* What's on the D-Bus? */ + if (~m_dsrclatch & 0x10) + data_in = m_dinlatch; + else if (~m_dsrclatch & 0x20) + data_in = m_sram[ROT_SRAM_ADDRESS]; + else if (~m_dsrclatch & 0x40) + data_in = m_ydlatch; + else if (~m_dsrclatch & 0x80) + data_in = t & 0xfff; + + /* What's on the T-Bus? */ + if ((spf == SPF_RET) && (m_dsrclatch & 0x80)) + t = data_in; + else if (spf == SPF_OP) + t = (t & ~0xf) | (data_in >> 12); + + + if (~m_dsrclatch & 1) + m_sram[ROT_SRAM_ADDRESS] = data_in; + + + /* Sign extend ALU input? */ + if (!_sex) + data_in = (data_in & ~0xf000) | ((data_in & 0x800) ? 0xf000 : 0); + + /* No do the ALU operation */ + { + UINT16 r = 0; + UINT16 s = 0; + + UINT32 res = 0; + UINT32 cflag = 0; + UINT32 vflag = 0; + + /* First, determine correct I1 bit */ + if ((spf == SPF_MULT) && !_BIT(m_q, 0)) + i2_0 |= 2; + + /* Determine the ALU sources */ + switch (i2_0) + { + case 0: r = m_ram[a]; s = m_q; break; + case 1: r = m_ram[a]; s = m_ram[b]; break; + case 2: r = 0; s = m_q; break; + case 3: r = 0; s = m_ram[b]; break; + case 4: r = 0; s = m_ram[a]; break; + case 5: r = data_in; s = m_ram[a]; break; + case 6: r = data_in; s = m_q; break; + case 7: r = data_in; s = 0; break; + } + + /* Next, determine the I3 and carry bits */ + if ((spf == SPF_DIV) && m_divreg) + { + i5_3 |= 1; + ci = 1; + } + + /* Perform the ALU operation */ + switch (i5_3) + { + case ADD: + res = r + s + ci; + cflag = (res >> 16) & 1; + vflag = (((r & 0x7fff) + (s & 0x7fff) + ci) >> 15) ^ cflag; + break; + case SUBR: + res = ~r + s + ci; + cflag = (res >> 16) & 1; + vflag = (((s & 0x7fff) + (~r & 0x7fff) + ci) >> 15) ^ cflag; + break; + case SUBS: + res = r + ~s + ci; + cflag = (res >> 16) & 1; + vflag = (((r & 0x7fff) + (~s & 0x7fff) + ci) >> 15) ^ cflag; + break; + case OR: + res = r | s; + break; + case AND: + res = r & s; + break; + case NOTRS: + res = ~r & s; + break; + case EXOR: + res = r ^ s; + break; + case EXNOR: + res = ~(r ^ s); + break; + } + + m_f = res; + m_cflag = cflag; + m_vflag = vflag; + + switch (i8_6) + { + case QREG: + m_q = m_f; + m_y = m_f; + break; + case NOP: + m_y = m_f; + break; + case RAMA: + m_y = m_ram[a]; + m_ram[b] = m_f; + break; + case RAMF: + m_ram[b] = m_f; + m_y = m_f; + break; + case RAMQD: + { + UINT16 q0 = m_q & 1; + UINT16 r0 = m_f & 1; + UINT16 q15 = 0; + UINT16 r15 = 0; + + /* Determine Q15 and RAM15 */ + switch (sel) + { + case 0: q15 = r15 = 0; + break; + case 1: q15 = r15 = 0x8000; + break; + case 2: q15 = q0 << 15; + r15 = r0 << 15; + break; + case 3: q15 = r0 << 15; + r15 = (m_vflag ^ BIT(m_f, 15)) << 15; + break; + } + + m_ram[b] = r15 | (m_f >> 1); + m_q = q15 | (m_q >> 1); + m_y = m_f; + break; + } + case RAMD: + { + UINT16 r0 = m_f & 1; + UINT16 r15 = 0; + + switch (sel) + { + case 0: r15 = 0; break; + case 1: r15 = 0x8000; break; + case 2: r15 = r0 << 15; break; + case 3: + r15 = (m_vflag ^ BIT(m_f, 15)) << 15; + break; + } + + m_ram[b] = r15 | (m_f >> 1); + m_y = m_f; + break; + } + case RAMQU: + { + UINT16 q15 = BIT(m_q, 15); + UINT16 r15 = BIT(m_f, 15); + UINT16 q0 = 0; + UINT16 r0 = 0; + + switch (sel) + { + case 0: q0 = 0; r0 = 0; break; + case 1: q0 = 1; r0 = 1; break; + case 2: q0 = q15; r0 = r15; break; + case 3: + { + q0 = (spf == SPF_DIV) && !BIT(m_f, 15); + r0 = q15; + break; + } + } + + m_ram[b] = (m_f << 1) | r0; + m_q = (m_q << 1) | q0; + m_y = m_f; + break; + } + case RAMU: + { + UINT16 q15 = BIT(m_q, 15); + UINT16 r15 = BIT(m_f, 15); + UINT16 r0 = 0; + + switch (sel) + { + case 0: r0 = 0; break; + case 1: r0 = 1; break; + case 2: r0 = r15; break; + case 3: r0 = q15; break; + } + + m_ram[b] = (m_f << 1) | r0; + m_y = m_f; + break; + } + } + } + + /* Check for jump */ + if ( do_rotjmp(jmp) ) + m_pc = t; + else + m_pc = (m_pc + 1) & 0xfff; + + /* Rising edge; update the sequence counter */ + if (spf == SPF_SQLTCH) + m_seqcnt = t & 0xf; + else if ( (spf == SPF_MULT) || (spf == SPF_DIV) ) + m_seqcnt = (m_seqcnt + 1) & 0xf; + + /* Rising edge; write data source reg */ + dsrclatch = + (~(0x10 << dsrc) & 0xf0) + | (rsrc ? 0x04 : 0x02) + | !(spf == SPF_SWRT); + + /* R-latch is written on rising edge of dsrclatch bit 2 */ + if (!_BIT(m_dsrclatch, 2) && _BIT(dsrclatch, 2)) + m_rsrclatch = t & 0xff; + + m_dsrclatch = dsrclatch; + + /* Handle latching on rising edge */ + switch (yout) + { + case YOUT_Y2LDA: + { + m_lineaddr = m_y & 0xfff; + break; + } + case YOUT_Y2LDD: + { + m_linedata = ((t & 0xf) << 12) | (m_y & 0xfff); + m_linedata_w( m_lineaddr, m_linedata, 0xffff ); + break; + } + case YOUT_Y2DAD: m_dynaddr = m_y & 0x3fff; break; + case YOUT_Y2DYN: m_dyndata = m_y & 0xffff; break; + case YOUT_Y2R: m_yrlatch = m_y & 0x7ff; break; + case YOUT_Y2D: m_ydlatch = m_y; break; + } + + /* Clock in the divide register */ + m_divreg = (spf == SPF_DIV) && !_BIT(m_f, 15); + + /* DRAM accessing */ + m_prev_dred = !(spf == SPF_DRED); + m_prev_dwrt = !(spf == SPF_DWRT); + + m_clkcnt++; + m_icount--; + } while (m_icount > 0); +} + + +/*************************************************************************** + LINE DRAWER CORE EXECUTION LOOP +***************************************************************************/ + +enum line_spf +{ + LSPF_UNUSED = 0, + LSPF_FSTOP = 1, + LSPF_SREG = 2, + LSPF_FSTRT = 3, + LSPF_PWRT = 4, + LSPF_MULT = 5, + LSPF_LSTOP = 6, + LSPF_BRES = 7 +}; + +enum line_latch +{ + LLATCH_UNUSED = 0, + LLATCH_SEQLATCH = 1, + LLATCH_XLATCH = 2, + LLATCH_YLATCH = 3, + LLATCH_BADLATCH = 4, + LLATCH_FADLATCH = 5, + LLATCH_CLATCH = 6, + LLATCH_ZLATCH = 7 +}; + +enum sreg_bits +{ + SREG_E0 = 0, + SREG_DX_DY = 1, + SREG_DY = 2, + SREG_DX = 3, + SREG_LE0 = 4, + SREG_LDX_DY = 5, + SREG_LDY = 6, + SREG_LDX = 7 +}; + +int cquestlin_cpu_device::do_linjmp(int jmp) +{ + int ret = 0; + + switch (jmp & 7) + { + /* */ case 0: ret = 0; break; + /* MSB */ case 1: ret = BIT(m_f, 11); break; + /* SEQ */ case 2: ret = (m_seqcnt == 0xfff); break; + /* >0 */ case 3: ret = !(m_f == 0) && !_BIT(m_f, 11); break; + /* CAROUT */ case 4: ret = (m_cflag); break; + /* ZERO */ case 5: ret = (m_f == 0); break; + } + + return !(!ret ^ BIT(jmp, 3)); +} + + +void cquestlin_cpu_device::cubeqcpu_swap_line_banks() +{ + m_field = m_field ^ 1; +} + + +void cquestlin_cpu_device::cubeqcpu_clear_stack() +{ + memset(&m_ptr_ram[m_field * 256], 0, 256); +} + + +UINT8 cquestlin_cpu_device::cubeqcpu_get_ptr_ram_val(int i) +{ + return m_ptr_ram[((m_field^1) * 256) + i]; +} + + +UINT32* cquestlin_cpu_device::cubeqcpu_get_stack_ram() +{ + if (m_field != ODD_FIELD) + return m_o_stack; + else + return m_e_stack; +} + + +void cquestlin_cpu_device::execute_run() +{ +#define LINE_PC ((m_pc[prog] & 0x7f) | ((prog == BACKGROUND) ? 0x80 : 0)) + + UINT32 *stack_ram; + UINT8 *ptr_ram; + + /* Check the field and set the stack/pointer RAM pointers appropriately */ + if (m_field == ODD_FIELD) + { + stack_ram = m_o_stack; + ptr_ram = &m_ptr_ram[0]; + } + else + { + stack_ram = m_e_stack; + ptr_ram = &m_ptr_ram[0x100]; + } + + /* Core execution loop */ + do + { + /* Are we executing the foreground or backgroud program? */ + int prog = (m_clkcnt & 3) ? BACKGROUND : FOREGROUND; + + m_curpc = LINE_PC; + UINT64 inst = m_direct->read_qword(LINE_PC << 3); + + UINT32 inslow = inst & 0xffffffff; + UINT32 inshig = inst >> 32; + + int t = (inshig >> 24) & 0xff; + int jmp = (inshig >> 20) & 0xf; + int latch = (inshig >> 16) & 0x7; + int op = (inshig >> 15) & 0x1; + int spf = (inshig >> 12) & 0x7; + int b = (inshig >> 8) & 0xf; + int a = (inshig >> 4) & 0xf; + int i8_6 = (inshig >> 0) & 0x7; + int ci = (inslow >> 31) & 0x1; + int i5_3 = (inslow >> 28) & 0x7; + int _pbcs = (inslow >> 27) & 0x1; + int i2_0 = (inslow >> 24) & 0x7; + + UINT16 data_in = 0; + + debugger_instruction_hook(this, m_pc[prog]); + + /* Handle accesses to and from shared SRAM */ + if (prog == FOREGROUND) + { + if (!_BIT(m_fglatch, 5)) + data_in = m_sram[m_fadlatch]; + else + data_in = m_linedata_r(); + } + else + { + if (!_BIT(m_bglatch, 4)) + m_sram[m_badlatch] = m_sramdlatch; + else if (_BIT(m_bglatch, 2)) + data_in = m_sram[m_badlatch]; + else + data_in = m_linedata_r(); + } + + /* Handle a write to stack RAM (/DOWRT) */ + if ((m_clkcnt & 3) == 1) + { + if (_BIT(m_fglatch, 4) && (m_ycnt < 256)) + { + /* 20-bit words */ + UINT32 data; + UINT16 h = m_xcnt; + UINT8 v = m_ycnt & 0xff; + + /* Clamp H between 0 and 319 */ + if (h >= 320) + h = (h & 0x800) ? 0 : 319; + + /* Stack word type depends on STOP/#START bit */ + if ( _BIT(m_fglatch, 3) ) + data = (0 << 19) | (h << 8) | m_zlatch; + else + data = (1 << 19) | ((m_clatch & 0x100) << 9) | (h << 8) | (m_clatch & 0xff); + + stack_ram[(v << 7) | (ptr_ram[v] & 0x7f)] = data; + + /* Also increment the pointer RAM entry. Note that it cannot exceed 128 */ + ptr_ram[v] = (ptr_ram[v] + 1) & 0x7f; + } + } + + /* Override T3-0? */ + if (op) + t = (t & ~0xf) | (data_in >> 12); + + /* Determine the correct I1 bit */ + if ((spf == LSPF_MULT) && !_BIT(m_q, 0)) + i2_0 |= 2; + + /* Determine A0 (BRESA0) */ + if ((prog == FOREGROUND) && !_BIT(m_fglatch, 2)) + a |= m_gt0reg; + + /* Now do the ALU operation */ + { + UINT16 r = 0; + UINT16 s = 0; + + UINT16 res = 0; + UINT32 cflag = 0; + UINT32 vflag = 0; + + /* Determine the ALU sources */ + switch (i2_0) + { + case 0: r = m_ram[a]; s = m_q; break; + case 1: r = m_ram[a]; s = m_ram[b]; break; + case 2: r = 0; s = m_q; break; + case 3: r = 0; s = m_ram[b]; break; + case 4: r = 0; s = m_ram[a]; break; + case 5: r = data_in; s = m_ram[a]; break; + case 6: r = data_in; s = m_q; break; + case 7: r = data_in; s = 0; break; + } + + /* 12-bits */ + r &= 0xfff; + s &= 0xfff; + + /* Perform the 12-bit ALU operation */ + switch (i5_3) + { + case ADD: + res = r + s + ci; + cflag = (res >> 12) & 1; + vflag = (((r & 0x7ff) + (s & 0x7ff) + ci) >> 11) ^ cflag; + break; + case SUBR: + res = (r ^ 0x0FFF) + s + ci; + cflag = (res >> 12) & 1; + vflag = (((s & 0x7ff) + (~r & 0x7ff) + ci) >> 11) ^ cflag; + break; + case SUBS: + res = r + (s ^ 0x0FFF) + ci; + cflag = (res >> 12) & 1; + vflag = (((r & 0x7ff) + (~s & 0x7ff) + ci) >> 11) ^ cflag; + break; + case OR: + res = r | s; + break; + case AND: + res = r & s; + break; + case NOTRS: + res = ~r & s; + break; + case EXOR: + res = r ^ s; + break; + case EXNOR: + res = ~(r ^ s); + break; + } + + m_f = res & 0xfff; + m_cflag = cflag; + m_vflag = vflag; + + switch (i8_6) + { + case QREG: + m_q = m_f; + m_y = m_f; + break; + case NOP: + m_y = m_f; + break; + case RAMA: + m_y = m_ram[a]; + m_ram[b] = m_f; + break; + case RAMF: + m_ram[b] = m_f; + m_y = m_f; + break; + case RAMQD: + { + UINT16 r11 = (BIT(m_f, 11) ^ m_vflag) ? 0x800 : 0; + UINT16 q11 = (prog == BACKGROUND) ? 0x800 : 0; + + m_ram[b] = r11 | (m_f >> 1); + m_q = q11 | (m_q >> 1); + m_y = m_f; + break; + } + case RAMD: + { + UINT16 r11 = (BIT(m_f, 11) ^ m_vflag) ? 0x800 : 0; + + m_ram[b] = r11 | (m_f >> 1); + m_y = m_f; + break; + } + case RAMQU: + { + /* Determine shift inputs */ + UINT16 r0 = (prog == BACKGROUND); + + /* This should never happen - Q0 will be invalid */ + m_ram[b] = (m_f << 1) | r0; + m_q = (m_q << 1) | 0; + m_y = m_f; + break; + } + case RAMU: + { + UINT16 r0 = (prog == BACKGROUND); + + m_ram[b] = (m_f << 1) | r0; + m_y = m_f; + break; + } + } + } + + /* Adjust program counter */ + if ( do_linjmp(jmp) ) + m_pc[prog] = t & 0x7f; + else + m_pc[prog] = (m_pc[prog] + 1) & 0x7f; + + if (prog == BACKGROUND) + m_pc[prog] |= 0x80; + else + { + /* Handle events that happen during FG execution */ + if (latch == LLATCH_XLATCH) + m_xcnt = m_y & 0xfff; + else + { + int _xcet; + int mux_sel = (BIT(m_sreg, SREG_DX_DY) << 1) | (BIT(m_sreg, SREG_DX) ^ BIT(m_sreg, SREG_DY)); + + if (mux_sel == 0) + _xcet = !(spf == LSPF_BRES); + else if (mux_sel == 1) + _xcet = _BIT(m_fglatch, 1); + else if (mux_sel == 2) + _xcet = !(m_gt0reg && (spf == LSPF_BRES)); + else + _xcet = _BIT(m_fglatch, 0); + + if (!_xcet) + m_xcnt = (m_xcnt + (_BIT(m_sreg, SREG_DX) ? 1 : -1)) & 0xfff; + } + + if (latch == LLATCH_YLATCH) + m_ycnt = m_y & 0xfff; + else + { + int _ycet; + int mux_sel = (BIT(m_sreg, SREG_DX_DY) << 1) | (BIT(m_sreg, SREG_DX) ^ BIT(m_sreg, SREG_DY)); + + if (mux_sel == 0) + _ycet = !(m_gt0reg && (spf == LSPF_BRES)); + else if (mux_sel == 1) + _ycet = _BIT(m_fglatch, 0); + else if (mux_sel == 2) + _ycet = !(spf == LSPF_BRES); + else + _ycet = _BIT(m_fglatch, 1); + + if (!_ycet) + m_ycnt = (m_ycnt + (_BIT(m_sreg, SREG_DY) ? 1 : -1)) & 0xfff; + } + } + + if (latch == LLATCH_CLATCH) + m_clatch = m_y & 0x1ff; + else if (latch == LLATCH_ZLATCH) + m_zlatch = m_y & 0xff; + else if (latch == LLATCH_FADLATCH) + m_fadlatch = m_y & 0xfff; + else if (latch == LLATCH_BADLATCH) + m_badlatch = m_y & 0xfff; + + /* What about the SRAM dlatch? */ + if ( !_BIT(m_bglatch, 5) ) + m_sramdlatch = ((t & 0xf) << 12) | (m_y & 0x0fff); + + /* BG and FG latches */ + if (prog == FOREGROUND) + { + int mux_sel = (!(spf == LSPF_FSTOP) << 1) | !(spf == LSPF_LSTOP); + int dowrt; + int start_stop; + + /* Handle the stack write and start/stop mux */ + if (mux_sel == 0) + { + dowrt = 0; + start_stop = 0; + } + else if (mux_sel == 1) + { + dowrt = m_fdxreg ^ BIT(m_sreg, SREG_DX); + start_stop = m_fdxreg; + } + else if (mux_sel == 2) + { + dowrt = BIT(m_sreg, SREG_LDX) ^ BIT(m_sreg, SREG_DX); + start_stop = BIT(m_sreg, SREG_DX); + } + else + { + dowrt = (spf == LSPF_BRES) && (_BIT(m_sreg, SREG_DX_DY) || m_gt0reg); + start_stop = BIT(m_sreg, SREG_DY); + } + + m_fglatch = + (!(latch == LLATCH_FADLATCH) << 5) + | (dowrt << 4) + | (start_stop << 3) + | (_pbcs << 2) + | (!(spf == LSPF_BRES) << 1) + | !(m_gt0reg && (spf == LSPF_BRES)); + } + else + { + int _lpwrt = BIT(m_bglatch, 5); + + m_bglatch = + (!(spf == LSPF_PWRT) << 5) + | (_lpwrt << 4) + | ((!_lpwrt || (!(spf == LSPF_PWRT) && (latch == LLATCH_BADLATCH))) << 2); + } + + /* Clock-in another bit into the sign bit shifter? */ + if (spf == LSPF_SREG) + { + /* The sign bit is inverted */ + m_sreg = (m_sreg << 1) | !BIT(m_f, 11); + + /* Also latch the >0 reg */ + m_gt0reg = !(m_f == 0) && !_BIT(m_f, 11); + } + else if (spf == LSPF_FSTRT) + { + m_fdxreg = BIT(m_sreg, 3); + } + + /* Load or increment sequence counter? */ + if (latch == LLATCH_SEQLATCH) + { + m_seqcnt = m_y & 0xfff; + } + else if (spf == LSPF_BRES) + { + m_seqcnt = (m_seqcnt + 1) & 0xfff; + + /* Also latch the >0 reg */ + m_gt0reg = !(m_f == 0) && !_BIT(m_f, 11); + } + + m_icount--; + m_clkcnt++; + } while (m_icount > 0); +} diff --git a/src/devices/cpu/cubeqcpu/cubeqcpu.h b/src/devices/cpu/cubeqcpu/cubeqcpu.h new file mode 100644 index 00000000000..4befd97d662 --- /dev/null +++ b/src/devices/cpu/cubeqcpu/cubeqcpu.h @@ -0,0 +1,384 @@ +// license:BSD-3-Clause +// copyright-holders:Philip Bennett +/*************************************************************************** + + cubeqcpu.h + Interface file for the Cube Quest CPUs + Written by Phil Bennett + +***************************************************************************/ + +#ifndef _CUBEQCPU_H +#define _CUBEQCPU_H + + +/*************************************************************************** + COMPILE-TIME DEFINITIONS +***************************************************************************/ + + +/*************************************************************************** + GLOBAL CONSTANTS +***************************************************************************/ + + +/*************************************************************************** + REGISTER ENUMERATION +***************************************************************************/ + +enum +{ + CQUESTSND_PC = 1, + CQUESTSND_Q, + CQUESTSND_RAM0, + CQUESTSND_RAM1, + CQUESTSND_RAM2, + CQUESTSND_RAM3, + CQUESTSND_RAM4, + CQUESTSND_RAM5, + CQUESTSND_RAM6, + CQUESTSND_RAM7, + CQUESTSND_RAM8, + CQUESTSND_RAM9, + CQUESTSND_RAMA, + CQUESTSND_RAMB, + CQUESTSND_RAMC, + CQUESTSND_RAMD, + CQUESTSND_RAME, + CQUESTSND_RAMF, + CQUESTSND_RTNLATCH, + CQUESTSND_ADRCNTR, + CQUESTSND_DINLATCH +}; + +enum +{ + CQUESTROT_PC = 1, + CQUESTROT_Q, + CQUESTROT_RAM0, + CQUESTROT_RAM1, + CQUESTROT_RAM2, + CQUESTROT_RAM3, + CQUESTROT_RAM4, + CQUESTROT_RAM5, + CQUESTROT_RAM6, + CQUESTROT_RAM7, + CQUESTROT_RAM8, + CQUESTROT_RAM9, + CQUESTROT_RAMA, + CQUESTROT_RAMB, + CQUESTROT_RAMC, + CQUESTROT_RAMD, + CQUESTROT_RAME, + CQUESTROT_RAMF, + CQUESTROT_SEQCNT, + CQUESTROT_DYNADDR, + CQUESTROT_DYNDATA, + CQUESTROT_YRLATCH, + CQUESTROT_YDLATCH, + CQUESTROT_DINLATCH, + CQUESTROT_DSRCLATCH, + CQUESTROT_RSRCLATCH, + CQUESTROT_LDADDR, + CQUESTROT_LDDATA +}; + +enum +{ + CQUESTLIN_FGPC = 1, + CQUESTLIN_BGPC, + CQUESTLIN_Q, + CQUESTLIN_RAM0, + CQUESTLIN_RAM1, + CQUESTLIN_RAM2, + CQUESTLIN_RAM3, + CQUESTLIN_RAM4, + CQUESTLIN_RAM5, + CQUESTLIN_RAM6, + CQUESTLIN_RAM7, + CQUESTLIN_RAM8, + CQUESTLIN_RAM9, + CQUESTLIN_RAMA, + CQUESTLIN_RAMB, + CQUESTLIN_RAMC, + CQUESTLIN_RAMD, + CQUESTLIN_RAME, + CQUESTLIN_RAMF, + CQUESTLIN_FADLATCH, + CQUESTLIN_BADLATCH, + CQUESTLIN_SREG, + CQUESTLIN_XCNT, + CQUESTLIN_YCNT, + CQUESTLIN_CLATCH, + CQUESTLIN_ZLATCH +}; + + +/*************************************************************************** + CONFIGURATION STRUCTURE +***************************************************************************/ + + +#define MCFG_CQUESTSND_CONFIG(_dac_w, _sound_tag) \ + cquestsnd_cpu_device::set_dac_w(*device, DEVCB_##_dac_w); \ + cquestsnd_cpu_device::set_sound_region(*device, _sound_tag); + + +#define MCFG_CQUESTROT_CONFIG(_linedata_w) \ + cquestrot_cpu_device::set_linedata_w(*device, DEVCB_##_linedata_w ); + + +#define MCFG_CQUESTLIN_CONFIG(_linedata_r) \ + cquestlin_cpu_device::set_linedata_r(*device, DEVCB_##_linedata_r ); + + +/*************************************************************************** + PUBLIC FUNCTIONS +***************************************************************************/ + +class cquestsnd_cpu_device : public cpu_device +{ +public: + // construction/destruction + cquestsnd_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // static configuration helpers + template static devcb_base &set_dac_w(device_t &device, _Object object) { return downcast(device).m_dac_w.set_callback(object); } + static void set_sound_region(device_t &device, const char *tag) { downcast(device).m_sound_region_tag = tag; } + + DECLARE_WRITE16_MEMBER(sndram_w); + DECLARE_READ16_MEMBER(sndram_r); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_execute_interface overrides + virtual UINT32 execute_min_cycles() const { return 1; } + virtual UINT32 execute_max_cycles() const { return 1; } + virtual UINT32 execute_input_lines() const { return 0; } + virtual void execute_run(); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const { return (spacenum == AS_PROGRAM) ? &m_program_config : NULL; } + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const { return 8; } + virtual UINT32 disasm_max_opcode_bytes() const { return 8; } + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + +private: + address_space_config m_program_config; + + /* AM2901 internals */ + UINT16 m_ram[16]; + UINT16 m_q; + UINT16 m_f; + UINT16 m_y; + UINT32 m_cflag; + UINT32 m_vflag; + + UINT8 m_pc; /* 2 x LS161 @ 6E, 6F */ + UINT16 m_platch; + UINT8 m_rtnlatch; /* LS374 @ 5F */ + UINT8 m_adrcntr; /* 2 x LS161 */ + UINT16 m_adrlatch; + UINT16 m_dinlatch; + UINT16 m_ramwlatch; + + UINT16 m_sram[4096/2]; + + int m_prev_ipram; + int m_prev_ipwrt; + + devcb_write16 m_dac_w; + const char *m_sound_region_tag; + UINT16 *m_sound_data; + + address_space *m_program; + direct_read_data *m_direct; + int m_icount; + + int do_sndjmp(int jmp); +}; + + +class cquestrot_cpu_device : public cpu_device +{ +public: + // construction/destruction + cquestrot_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // static configuration helpers + template static devcb_base &set_linedata_w(device_t &device, _Object object) { return downcast(device).m_linedata_w.set_callback(object); } + + DECLARE_READ16_MEMBER(linedata_r); + DECLARE_WRITE16_MEMBER(rotram_w); + DECLARE_READ16_MEMBER(rotram_r); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_execute_interface overrides + virtual UINT32 execute_min_cycles() const { return 1; } + virtual UINT32 execute_max_cycles() const { return 1; } + virtual UINT32 execute_input_lines() const { return 0; } + virtual void execute_run(); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const { return (spacenum == AS_PROGRAM) ? &m_program_config : NULL; } + + // device_state_interface overrides + void state_string_export(const device_state_entry &entry, std::string &str); + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const { return 8; } + virtual UINT32 disasm_max_opcode_bytes() const { return 8; } + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + +private: + address_space_config m_program_config; + devcb_write16 m_linedata_w; + + /* AM2901 internals */ + UINT16 m_ram[16]; + UINT16 m_q; + UINT16 m_f; + UINT16 m_y; + UINT32 m_cflag; + UINT32 m_vflag; + + UINT16 m_pc; /* 12-bit, but only 9 used */ + UINT8 m_seqcnt; /* 4-bit counter */ + + UINT8 m_dsrclatch; + UINT8 m_rsrclatch; + UINT16 m_dynaddr; /* LS374 at 2D, 8D */ + UINT16 m_dyndata; /* LS374 at 10B, 9B */ + UINT16 m_yrlatch; /* LS374 at 9D, 10D */ + UINT16 m_ydlatch; /* LS374 at 9C, 10C */ + UINT16 m_dinlatch; + UINT8 m_divreg; /* LS74 at ? */ + + UINT16 m_linedata; + UINT16 m_lineaddr; + + UINT16 m_dram[16384]; /* Shared with 68000 */ + UINT16 m_sram[2048]; /* Private */ + + UINT8 m_prev_dred; + UINT8 m_prev_dwrt; + UINT8 m_wc; + UINT8 m_rc; + UINT8 m_clkcnt; + + address_space *m_program; + direct_read_data *m_direct; + int m_icount; + + // For the debugger + UINT8 m_flags; + + int do_rotjmp(int jmp); +}; + + +class cquestlin_cpu_device : public cpu_device +{ +public: + // construction/destruction + cquestlin_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // static configuration helpers + template static devcb_base &set_linedata_r(device_t &device, _Object object) { return downcast(device).m_linedata_r.set_callback(object); } + + DECLARE_WRITE16_MEMBER( linedata_w ); + void cubeqcpu_swap_line_banks(); + void cubeqcpu_clear_stack(); + UINT8 cubeqcpu_get_ptr_ram_val(int i); + UINT32* cubeqcpu_get_stack_ram(); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_execute_interface overrides + virtual UINT32 execute_min_cycles() const { return 1; } + virtual UINT32 execute_max_cycles() const { return 1; } + virtual UINT32 execute_input_lines() const { return 0; } + virtual void execute_run(); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const { return (spacenum == AS_PROGRAM) ? &m_program_config : NULL; } + + // device_state_interface overrides + void state_string_export(const device_state_entry &entry, std::string &str); + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const { return 8; } + virtual UINT32 disasm_max_opcode_bytes() const { return 8; } + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + +private: + address_space_config m_program_config; + devcb_read16 m_linedata_r; + + /* 12-bit AM2901 internals */ + UINT16 m_ram[16]; + UINT16 m_q; + UINT16 m_f; + UINT16 m_y; + UINT32 m_cflag; + UINT32 m_vflag; + + UINT8 m_pc[2]; /* Two program counters; one for FG, other for BG */ + + UINT16 m_seqcnt; /* 12-bit */ + UINT16 m_clatch; /* LS374 at 9E and 1-bit FF */ + UINT8 m_zlatch; /* LS374 at 4H */ + + UINT16 m_xcnt; + UINT16 m_ycnt; + UINT8 m_sreg; + + UINT16 m_fadlatch; + UINT16 m_badlatch; + + UINT16 m_sramdlatch; + + UINT8 m_fglatch; + UINT8 m_bglatch; + UINT8 m_gt0reg; + UINT8 m_fdxreg; + UINT32 m_field; + + UINT32 m_clkcnt; + + /* RAM */ + UINT16 m_sram[4096]; /* Shared with rotate CPU */ + UINT8 m_ptr_ram[1024]; /* Pointer RAM */ + UINT32 m_e_stack[32768]; /* Stack DRAM: 32kx20 */ + UINT32 m_o_stack[32768]; /* Stack DRAM: 32kx20 */ + + address_space *m_program; + direct_read_data *m_direct; + int m_icount; + + // For the debugger + UINT8 m_flags; + UINT16 m_curpc; + + int do_linjmp(int jmp); +}; + + +extern const device_type CQUESTSND; +extern const device_type CQUESTROT; +extern const device_type CQUESTLIN; + + +#endif /* _CUBEQCPU_H */ diff --git a/src/devices/cpu/drcbec.c b/src/devices/cpu/drcbec.c new file mode 100644 index 00000000000..d3e1538c1ba --- /dev/null +++ b/src/devices/cpu/drcbec.c @@ -0,0 +1,2278 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + drcbec.c + + Interpreted C core back-end for the universal machine language. + +***************************************************************************/ + +#include "emu.h" +#include "debugger.h" +#include "drcbec.h" + +#ifdef _MSC_VER +#include +#define isnan _isnan +#endif + +using namespace uml; + + +//************************************************************************** +// CONSTANTS +//************************************************************************** + +// define a bit to match each possible condition, starting at bit 12 +#define ZBIT (0x1000 << (COND_Z & 15)) +#define NZBIT (0x1000 << (COND_NZ & 15)) +#define SBIT (0x1000 << (COND_S & 15)) +#define NSBIT (0x1000 << (COND_NS & 15)) +#define CBIT (0x1000 << (COND_C & 15)) +#define NCBIT (0x1000 << (COND_NC & 15)) +#define VBIT (0x1000 << (COND_V & 15)) +#define NVBIT (0x1000 << (COND_NV & 15)) +#define UBIT (0x1000 << (COND_U & 15)) +#define NUBIT (0x1000 << (COND_NU & 15)) +#define ABIT (0x1000 << (COND_A & 15)) +#define BEBIT (0x1000 << (COND_BE & 15)) +#define GBIT (0x1000 << (COND_G & 15)) +#define GEBIT (0x1000 << (COND_GE & 15)) +#define LBIT (0x1000 << (COND_L & 15)) +#define LEBIT (0x1000 << (COND_LE & 15)) + + +// internal opcodes +enum +{ + OP_LOAD1 = OP_MAX, + OP_LOAD1x2, + OP_LOAD1x4, + OP_LOAD1x8, + OP_LOAD2x1, + OP_LOAD2, + OP_LOAD2x4, + OP_LOAD2x8, + OP_LOAD4x1, + OP_LOAD4x2, + OP_LOAD4, + OP_LOAD4x8, + OP_LOAD8x1, + OP_LOAD8x2, + OP_LOAD8x4, + OP_LOAD8, + OP_LOADS1, + OP_LOADS1x2, + OP_LOADS1x4, + OP_LOADS1x8, + OP_LOADS2x1, + OP_LOADS2, + OP_LOADS2x4, + OP_LOADS2x8, + OP_LOADS4x1, + OP_LOADS4x2, + OP_LOADS4, + OP_LOADS4x8, + OP_LOADS8x1, + OP_LOADS8x2, + OP_LOADS8x4, + OP_LOADS8, + OP_STORE1, + OP_STORE1x2, + OP_STORE1x4, + OP_STORE1x8, + OP_STORE2x1, + OP_STORE2, + OP_STORE2x4, + OP_STORE2x8, + OP_STORE4x1, + OP_STORE4x2, + OP_STORE4, + OP_STORE4x8, + OP_STORE8x1, + OP_STORE8x2, + OP_STORE8x4, + OP_STORE8, + OP_READ1, + OP_READ2, + OP_READ4, + OP_READ8, + OP_READM1, + OP_READM2, + OP_READM4, + OP_READM8, + OP_WRITE1, + OP_WRITE2, + OP_WRITE4, + OP_WRITE8, + OP_WRITEM1, + OP_WRITEM2, + OP_WRITEM4, + OP_WRITEM8, + OP_SEXT1, + OP_SEXT2, + OP_SEXT4, + OP_SEXT8, + OP_FTOI4T, + OP_FTOI4R, + OP_FTOI4C, + OP_FTOI4F, + OP_FTOI4, + OP_FTOI8T, + OP_FTOI8R, + OP_FTOI8C, + OP_FTOI8F, + OP_FTOI8, + OP_FFRI4, + OP_FFRI8, + OP_FFRFS, + OP_FFRFD +}; + + + +//************************************************************************** +// MACROS +//************************************************************************** + +// +// opcode format: +// +// bits 31..28 == number of words following the opcode itself (0-15) +// bits 27..12 == bitmask specify which condition code we care about +// bits 11.. 2 == opcode +// bit 1 == flags/condition summary (0 if no condition/flags, 1 otherwise) +// bit 0 == operation size (0=32-bit, 1=64-bit) +// + +// build a short opcode from the raw opcode and size +#define MAKE_OPCODE_SHORT(op, size, conditionorflags) \ + ((((size) == 8) << 0) | (((conditionorflags) != 0) << 1) | ((op) << 2)) + +// build a full opcode from the raw opcode, size, condition/flags, and immediate count +#define MAKE_OPCODE_FULL(op, size, condition, flags, pwords) \ + (MAKE_OPCODE_SHORT(op, size, (condition | flags)) | ((condition != COND_ALWAYS) ? (0x1000 << ((condition) & 15)) : 0) | ((pwords) << 28)) + +// extract various parts of the opcode +#define OPCODE_GET_SHORT(op) ((op) & 0xfff) +#define OPCODE_PASS_CONDITION(op,f) (((op) & s_condition_map[f]) != 0) +#define OPCODE_FAIL_CONDITION(op,f) (((op) & s_condition_map[f]) == 0) +#define OPCODE_GET_PWORDS(op) ((op) >> 28) + +// shorthand for accessing parameters in the instruction stream +#define PARAM0 (*inst[0].puint32) +#define PARAM1 (*inst[1].puint32) +#define PARAM2 (*inst[2].puint32) +#define PARAM3 (*inst[3].puint32) + +#define DPARAM0 (*inst[0].puint64) +#define DPARAM1 (*inst[1].puint64) +#define DPARAM2 (*inst[2].puint64) +#define DPARAM3 (*inst[3].puint64) + +#define FSPARAM0 (*inst[0].pfloat) +#define FSPARAM1 (*inst[1].pfloat) +#define FSPARAM2 (*inst[2].pfloat) +#define FSPARAM3 (*inst[3].pfloat) + +#define FDPARAM0 (*inst[0].pdouble) +#define FDPARAM1 (*inst[1].pdouble) +#define FDPARAM2 (*inst[2].pdouble) +#define FDPARAM3 (*inst[3].pdouble) + +// compute C and V flags for 32-bit add/subtract +#define FLAGS32_C_ADD(a,b) ((UINT32)~(a) < (UINT32)(b)) +#define FLAGS32_C_SUB(a,b) ((UINT32)(b) > (UINT32)(a)) +#define FLAGS32_V_SUB(r,a,b) (((((a) ^ (b)) & ((a) ^ (r))) >> 30) & FLAG_V) +#define FLAGS32_V_ADD(r,a,b) (((~((a) ^ (b)) & ((a) ^ (r))) >> 30) & FLAG_V) + +// compute N and Z flags for 32-bit operations +#define FLAGS32_NZ(v) ((((v) >> 28) & FLAG_S) | (((UINT32)(v) == 0) << 2)) +#define FLAGS32_NZCV_ADD(r,a,b) (FLAGS32_NZ(r) | FLAGS32_C_ADD(a,b) | FLAGS32_V_ADD(r,a,b)) +#define FLAGS32_NZCV_SUB(r,a,b) (FLAGS32_NZ(r) | FLAGS32_C_SUB(a,b) | FLAGS32_V_SUB(r,a,b)) + +// compute C and V flags for 64-bit add/subtract +#define FLAGS64_C_ADD(a,b) ((UINT64)~(a) < (UINT64)(b)) +#define FLAGS64_C_SUB(a,b) ((UINT64)(b) > (UINT64)(a)) +#define FLAGS64_V_SUB(r,a,b) (((((a) ^ (b)) & ((a) ^ (r))) >> 62) & FLAG_V) +#define FLAGS64_V_ADD(r,a,b) (((~((a) ^ (b)) & ((a) ^ (r))) >> 62) & FLAG_V) + +// compute N and Z flags for 64-bit operations +#define FLAGS64_NZ(v) ((((v) >> 60) & FLAG_S) | (((UINT64)(v) == 0) << 2)) +#define FLAGS64_NZCV_ADD(r,a,b) (FLAGS64_NZ(r) | FLAGS64_C_ADD(a,b) | FLAGS64_V_ADD(r,a,b)) +#define FLAGS64_NZCV_SUB(r,a,b) (FLAGS64_NZ(r) | FLAGS64_C_SUB(a,b) | FLAGS64_V_SUB(r,a,b)) + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// union to simplify accessing data via the instruction stream +union drcbec_instruction +{ + UINT32 i; + void * v; + char * c; + UINT8 * puint8; + INT8 * pint8; + UINT16 * puint16; + INT16 * pint16; + UINT32 * puint32; + INT32 * pint32; + UINT64 * puint64; + INT64 * pint64; + float * pfloat; + double * pdouble; + void (*cfunc)(void *); + drcuml_machine_state *state; + const code_handle * handle; + const drcbec_instruction *inst; + const drcbec_instruction **pinst; +}; + + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +UINT64 drcbe_c::s_immediate_zero = 0; + +const UINT32 drcbe_c::s_condition_map[] = +{ + /* ..... */ NCBIT | NVBIT | NZBIT | NSBIT | NUBIT | ABIT | GBIT | GEBIT, + /* ....C */ CBIT | NVBIT | NZBIT | NSBIT | NUBIT | BEBIT | GBIT | GEBIT, + /* ...V. */ NCBIT | VBIT | NZBIT | NSBIT | NUBIT | ABIT | LEBIT | LBIT, + /* ...VC */ CBIT | VBIT | NZBIT | NSBIT | NUBIT | BEBIT | LEBIT | LBIT, + /* ..Z.. */ NCBIT | NVBIT | ZBIT | NSBIT | NUBIT | BEBIT | LEBIT | GEBIT, + /* ..Z.C */ CBIT | NVBIT | ZBIT | NSBIT | NUBIT | BEBIT | LEBIT | GEBIT, + /* ..ZV. */ NCBIT | VBIT | ZBIT | NSBIT | NUBIT | BEBIT | LEBIT | LBIT, + /* ..ZVC */ CBIT | VBIT | ZBIT | NSBIT | NUBIT | BEBIT | LEBIT | LBIT, + /* .S... */ NCBIT | NVBIT | NZBIT | SBIT | NUBIT | ABIT | LEBIT | LBIT, + /* .S..C */ CBIT | NVBIT | NZBIT | SBIT | NUBIT | BEBIT | LEBIT | LBIT, + /* .S.V. */ NCBIT | VBIT | NZBIT | SBIT | NUBIT | ABIT | GBIT | GEBIT, + /* .S.VC */ CBIT | VBIT | NZBIT | SBIT | NUBIT | BEBIT | GBIT | GEBIT, + /* .SZ.. */ NCBIT | NVBIT | ZBIT | SBIT | NUBIT | BEBIT | LEBIT | LBIT, + /* .SZ.C */ CBIT | NVBIT | ZBIT | SBIT | NUBIT | BEBIT | LEBIT | LBIT, + /* .SZV. */ NCBIT | VBIT | ZBIT | SBIT | NUBIT | BEBIT | LEBIT | GEBIT, + /* .SZVC */ CBIT | VBIT | ZBIT | SBIT | NUBIT | BEBIT | LEBIT | GEBIT, + /* U.... */ NCBIT | NVBIT | NZBIT | NSBIT | UBIT | ABIT | GBIT | GEBIT, + /* U...C */ CBIT | NVBIT | NZBIT | NSBIT | UBIT | BEBIT | GBIT | GEBIT, + /* U..V. */ NCBIT | VBIT | NZBIT | NSBIT | UBIT | ABIT | LEBIT | LBIT, + /* U..VC */ CBIT | VBIT | NZBIT | NSBIT | UBIT | BEBIT | LEBIT | LBIT, + /* U.Z.. */ NCBIT | NVBIT | ZBIT | NSBIT | UBIT | BEBIT | LEBIT | GEBIT, + /* U.Z.C */ CBIT | NVBIT | ZBIT | NSBIT | UBIT | BEBIT | LEBIT | GEBIT, + /* U.ZV. */ NCBIT | VBIT | ZBIT | NSBIT | UBIT | BEBIT | LEBIT | LBIT, + /* U.ZVC */ CBIT | VBIT | ZBIT | NSBIT | UBIT | BEBIT | LEBIT | LBIT, + /* US... */ NCBIT | NVBIT | NZBIT | SBIT | UBIT | ABIT | LEBIT | LBIT, + /* US..C */ CBIT | NVBIT | NZBIT | SBIT | UBIT | BEBIT | LEBIT | LBIT, + /* US.V. */ NCBIT | VBIT | NZBIT | SBIT | UBIT | ABIT | GBIT | GEBIT, + /* US.VC */ CBIT | VBIT | NZBIT | SBIT | UBIT | BEBIT | GBIT | GEBIT, + /* USZ.. */ NCBIT | NVBIT | ZBIT | SBIT | UBIT | BEBIT | LEBIT | LBIT, + /* USZ.C */ CBIT | NVBIT | ZBIT | SBIT | UBIT | BEBIT | LEBIT | LBIT, + /* USZV. */ NCBIT | VBIT | ZBIT | SBIT | UBIT | BEBIT | LEBIT | GEBIT, + /* USZVC */ CBIT | VBIT | ZBIT | SBIT | UBIT | BEBIT | LEBIT | GEBIT +}; + + + +//************************************************************************** +// C BACKEND +//************************************************************************** + +//------------------------------------------------- +// drcbe_c - constructor +//------------------------------------------------- + +drcbe_c::drcbe_c(drcuml_state &drcuml, device_t &device, drc_cache &cache, UINT32 flags, int modes, int addrbits, int ignorebits) + : drcbe_interface(drcuml, cache, device), + m_hash(cache, modes, addrbits, ignorebits), + m_map(cache, 0), + m_labels(cache), + m_fixup_delegate(FUNC(drcbe_c::fixup_label), this) +{ +} + + +//------------------------------------------------- +// ~drcbe_c - destructor +//------------------------------------------------- + +drcbe_c::~drcbe_c() +{ +} + + +//------------------------------------------------- +// reset - reset back-end specific state +//------------------------------------------------- + +void drcbe_c::reset() +{ + // reset our hash tables + m_hash.reset(); + m_hash.set_default_codeptr(NULL); +} + + +//------------------------------------------------- +// drcbec_generate - generate code +//------------------------------------------------- + +void drcbe_c::generate(drcuml_block &block, const instruction *instlist, UINT32 numinst) +{ + // tell all of our utility objects that a block is beginning + m_hash.block_begin(block, instlist, numinst); + m_labels.block_begin(block); + m_map.block_begin(block); + + // begin codegen; fail if we can't + drccodeptr *cachetop = m_cache.begin_codegen(numinst * sizeof(drcbec_instruction) * 4); + if (cachetop == NULL) + block.abort(); + + // compute the base by aligning the cache top to an even multiple of drcbec_instruction + drcbec_instruction *base = (drcbec_instruction *)(((FPTR)*cachetop + sizeof(drcbec_instruction) - 1) & ~(sizeof(drcbec_instruction) - 1)); + drcbec_instruction *dst = base; + + // generate code by copying the instructions and extracting immediates + for (int inum = 0; inum < numinst; inum++) + { + const instruction &inst = instlist[inum]; + UINT8 psize[instruction::MAX_PARAMS]; + + // handle most instructions generally, but a few special cases + opcode_t opcode = inst.opcode(); + switch (opcode) + { + // when we hit a HANDLE opcode, register the current pointer for the handle + case OP_HANDLE: + inst.param(0).handle().set_codeptr((drccodeptr)dst); + break; + + // when we hit a HASH opcode, register the current pointer for the mode/PC + case OP_HASH: + m_hash.set_codeptr(inst.param(0).immediate(), inst.param(1).immediate(), (drccodeptr)dst); + break; + + // when we hit a LABEL opcode, register the current pointer for the label + case OP_LABEL: + m_labels.set_codeptr(inst.param(0).label(), (drccodeptr)dst); + break; + + // ignore COMMENT and NOP opcodes + case OP_COMMENT: + case OP_NOP: + break; + + // when we hit a MAPVAR opcode, log the change for the current PC + case OP_MAPVAR: + m_map.set_value((drccodeptr)dst, inst.param(0).mapvar(), inst.param(1).immediate()); + break; + + // JMP instructions need to resolve their labels + case OP_JMP: + (dst++)->i = MAKE_OPCODE_FULL(opcode, inst.size(), inst.condition(), inst.flags(), 1); + dst->inst = (drcbec_instruction *)m_labels.get_codeptr(inst.param(0).label(), m_fixup_delegate, dst); + dst++; + break; + + // generically handle everything else + default: + + // determine the operand size for each operand; mostly this is just the instruction size + for (int pnum = 0; pnum < inst.numparams(); pnum++) + psize[pnum] = inst.size(); + if (opcode == OP_LOAD || opcode == OP_FLOAD) + psize[2] = 4; + if (opcode == OP_STORE || opcode == OP_FSTORE) + psize[1] = 4; + if (opcode == OP_READ || opcode == OP_READM || opcode == OP_FREAD) + psize[1] = psize[2] = 4; + if (opcode == OP_WRITE || opcode == OP_WRITEM || opcode == OP_FWRITE) + psize[0] = psize[2] = 4; + if (opcode == OP_SEXT && inst.param(2).size() != SIZE_QWORD) + psize[1] = 4; + if (opcode == OP_FTOINT) + psize[0] = 1 << inst.param(2).size(); + if (opcode == OP_FFRINT || opcode == OP_FFRFLT) + psize[1] = 1 << inst.param(2).size(); + + // pre-expand opcodes that encode size/scale in them + if (opcode == OP_LOAD) + opcode = (opcode_t)(OP_LOAD1 + inst.param(3).size() * 4 + inst.param(3).scale()); + if (opcode == OP_LOADS) + opcode = (opcode_t)(OP_LOADS1 + inst.param(3).size() * 4 + inst.param(3).scale()); + if (opcode == OP_STORE) + opcode = (opcode_t)(OP_STORE1 + inst.param(3).size() * 4 + inst.param(3).scale()); + if (opcode == OP_READ) + opcode = (opcode_t)(OP_READ1 + inst.param(2).size()); + if (opcode == OP_READM) + opcode = (opcode_t)(OP_READM1 + inst.param(3).size()); + if (opcode == OP_WRITE) + opcode = (opcode_t)(OP_WRITE1 + inst.param(2).size()); + if (opcode == OP_WRITEM) + opcode = (opcode_t)(OP_WRITEM1 + inst.param(3).size()); + if (opcode == OP_SEXT) + opcode = (opcode_t)(OP_SEXT1 + inst.param(2).size()); + if (opcode == OP_FTOINT) + opcode = (opcode_t)(OP_FTOI4T + 5 * (inst.param(2).size() - 2) + inst.param(3).rounding()); + if (opcode == OP_FFRINT) + opcode = (opcode_t)(OP_FFRI4 + (inst.param(2).size() - 2)); + if (opcode == OP_FFRFLT) + opcode = (opcode_t)(OP_FFRFS + (inst.param(2).size() - 2)); + + // count how many bytes of immediates we need + int immedbytes = 0; + for (int pnum = 0; pnum < inst.numparams(); pnum++) + if (inst.param(pnum).is_mapvar() || + (inst.param(pnum).is_immediate() && inst.param(pnum).immediate() != 0) || + (inst.param(pnum).is_size_space() && inst.param(pnum).space() != 0)) + immedbytes += psize[pnum]; + + // compute how many instruction words we need for that + int immedwords = (immedbytes + sizeof(drcbec_instruction) - 1) / sizeof(drcbec_instruction); + + // first item is the opcode, size, condition flags and length + (dst++)->i = MAKE_OPCODE_FULL(opcode, inst.size(), inst.condition(), inst.flags(), inst.numparams() + immedwords); + + // immediates start after parameters + void *immed = dst + inst.numparams(); + + // output each of the parameters + for (int pnum = 0; pnum < inst.numparams(); pnum++) + output_parameter(&dst, &immed, psize[pnum], inst.param(pnum)); + + // point past the end of the immediates + dst += immedwords; + break; + } + } + + // complete codegen + *cachetop = (drccodeptr)dst; + m_cache.end_codegen(); + + // tell all of our utility objects that the block is finished + m_hash.block_end(block); + m_labels.block_end(block); + m_map.block_end(block); +} + + +//------------------------------------------------- +// hash_exists - return true if the given mode/pc +// exists in the hash table +//------------------------------------------------- + +bool drcbe_c::hash_exists(UINT32 mode, UINT32 pc) +{ + return m_hash.code_exists(mode, pc); +} + + +//------------------------------------------------- +// get_info - return information about the +// back-end implementation +//------------------------------------------------- + +void drcbe_c::get_info(drcbe_info &info) +{ + info.direct_iregs = 0; + info.direct_fregs = 0; +} + + +//------------------------------------------------- +// execute - execute a block of code registered +// at the given mode/pc +//------------------------------------------------- + +int drcbe_c::execute(code_handle &entry) +{ + // get the entry point + const drcbec_instruction *inst = (const drcbec_instruction *)entry.codeptr(); + assert_in_cache(m_cache, inst); + + // loop while we have cycles + const drcbec_instruction *callstack[32]; + const drcbec_instruction *newinst; + UINT32 temp32; + UINT64 temp64; + int shift; + UINT8 flags = 0; + UINT8 sp = 0; + while (true) + { + UINT32 opcode = (inst++)->i; + + switch (OPCODE_GET_SHORT(opcode)) + { + // ----------------------- Control Flow Operations ----------------------- + + case MAKE_OPCODE_SHORT(OP_HANDLE, 4, 0): // HANDLE handle + case MAKE_OPCODE_SHORT(OP_HASH, 4, 0): // HASH mode,pc + case MAKE_OPCODE_SHORT(OP_LABEL, 4, 0): // LABEL imm + case MAKE_OPCODE_SHORT(OP_COMMENT, 4, 0): // COMMENT string + case MAKE_OPCODE_SHORT(OP_MAPVAR, 4, 0): // MAPVAR mapvar,value + + // these opcodes should be processed at compile-time only + fatalerror("Unexpected opcode\n"); + + case MAKE_OPCODE_SHORT(OP_DEBUG, 4, 0): // DEBUG pc + debugger_instruction_hook(&m_device, PARAM0); + break; + + case MAKE_OPCODE_SHORT(OP_HASHJMP, 4, 0): // HASHJMP mode,pc,handle + sp = 0; + newinst = (const drcbec_instruction *)m_hash.get_codeptr(PARAM0, PARAM1); + if (newinst == NULL) + { + assert(sp < ARRAY_LENGTH(callstack)); + m_state.exp = PARAM1; + newinst = (const drcbec_instruction *)inst[2].handle->codeptr(); + callstack[sp++] = inst; + } + assert_in_cache(m_cache, newinst); + inst = newinst; + continue; + + case MAKE_OPCODE_SHORT(OP_EXIT, 4, 1): // EXIT src1[,c] + if (OPCODE_FAIL_CONDITION(opcode, flags)) + break; + // fall through... + + case MAKE_OPCODE_SHORT(OP_EXIT, 4, 0): + return PARAM0; + + case MAKE_OPCODE_SHORT(OP_JMP, 4, 1): // JMP imm[,c] + if (OPCODE_FAIL_CONDITION(opcode, flags)) + break; + // fall through... + + case MAKE_OPCODE_SHORT(OP_JMP, 4, 0): + newinst = inst[0].inst; + assert_in_cache(m_cache, newinst); + inst = newinst; + continue; + + case MAKE_OPCODE_SHORT(OP_CALLH, 4, 1): // CALLH handle[,c] + if (OPCODE_FAIL_CONDITION(opcode, flags)) + break; + // fall through... + + case MAKE_OPCODE_SHORT(OP_CALLH, 4, 0): + assert(sp < ARRAY_LENGTH(callstack)); + newinst = (const drcbec_instruction *)inst[0].handle->codeptr(); + assert_in_cache(m_cache, newinst); + callstack[sp++] = inst + OPCODE_GET_PWORDS(opcode); + inst = newinst; + continue; + + case MAKE_OPCODE_SHORT(OP_RET, 4, 1): // RET [c] + if (OPCODE_FAIL_CONDITION(opcode, flags)) + break; + // fall through... + + case MAKE_OPCODE_SHORT(OP_RET, 4, 0): + assert(sp > 0); + newinst = callstack[--sp]; + assert_in_cache(m_cache, newinst); + inst = newinst; + continue; + + case MAKE_OPCODE_SHORT(OP_EXH, 4, 1): // EXH handle,param[,c] + if (OPCODE_FAIL_CONDITION(opcode, flags)) + break; + // fall through... + + case MAKE_OPCODE_SHORT(OP_EXH, 4, 0): + assert(sp < ARRAY_LENGTH(callstack)); + newinst = (const drcbec_instruction *)inst[0].handle->codeptr(); + assert_in_cache(m_cache, newinst); + m_state.exp = PARAM1; + callstack[sp++] = inst; + inst = newinst; + continue; + + case MAKE_OPCODE_SHORT(OP_CALLC, 4, 1): // CALLC func,ptr[,c] + if (OPCODE_FAIL_CONDITION(opcode, flags)) + break; + // fall through... + + case MAKE_OPCODE_SHORT(OP_CALLC, 4, 0): + (*inst[0].cfunc)(inst[1].v); + break; + + case MAKE_OPCODE_SHORT(OP_RECOVER, 4, 0): // RECOVER dst,mapvar + assert(sp > 0); + PARAM0 = m_map.get_value((drccodeptr)callstack[0], MAPVAR_M0 + PARAM1); + break; + + + // ----------------------- Internal Register Operations ----------------------- + + case MAKE_OPCODE_SHORT(OP_SETFMOD, 4, 0): // SETFMOD src + m_state.fmod = PARAM0; + break; + + case MAKE_OPCODE_SHORT(OP_GETFMOD, 4, 0): // GETFMOD dst + PARAM0 = m_state.fmod; + break; + + case MAKE_OPCODE_SHORT(OP_GETEXP, 4, 0): // GETEXP dst + PARAM0 = m_state.exp; + break; + + case MAKE_OPCODE_SHORT(OP_GETFLGS, 4, 0): // GETFLGS dst[,f] + PARAM0 = flags & PARAM1; + break; + + case MAKE_OPCODE_SHORT(OP_SAVE, 4, 0): // SAVE dst + *inst[0].state = m_state; + inst[0].state->flags = flags; + break; + + case MAKE_OPCODE_SHORT(OP_RESTORE, 4, 0): // RESTORE dst + case MAKE_OPCODE_SHORT(OP_RESTORE, 4, 1): // RESTORE dst + m_state = *inst[0].state; + flags = inst[0].state->flags; + break; + + + // ----------------------- 32-Bit Integer Operations ----------------------- + + case MAKE_OPCODE_SHORT(OP_LOAD1, 4, 0): // LOAD dst,base,index,BYTE + PARAM0 = inst[1].puint8[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOAD1x2, 4, 0): // LOAD dst,base,index,BYTE_x2 + PARAM0 = *(UINT8 *)&inst[1].puint16[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOAD1x4, 4, 0): // LOAD dst,base,index,BYTE_x4 + PARAM0 = *(UINT8 *)&inst[1].puint32[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOAD1x8, 4, 0): // LOAD dst,base,index,BYTE_x8 + PARAM0 = *(UINT8 *)&inst[1].puint64[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOAD2x1, 4, 0): // LOAD dst,base,index,WORD_x1 + PARAM0 = *(UINT16 *)&inst[1].puint8[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOAD2, 4, 0): // LOAD dst,base,index,WORD + PARAM0 = inst[1].puint16[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOAD2x4, 4, 0): // LOAD dst,base,index,WORD_x4 + PARAM0 = *(UINT16 *)&inst[1].puint32[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOAD2x8, 4, 0): // LOAD dst,base,index,WORD_x8 + PARAM0 = *(UINT16 *)&inst[1].puint64[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOAD4x1, 4, 0): // LOAD dst,base,index,DWORD_x1 + PARAM0 = *(UINT32 *)&inst[1].puint8[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOAD4x2, 4, 0): // LOAD dst,base,index,DWORD_x2 + PARAM0 = *(UINT32 *)&inst[1].puint16[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOAD4, 4, 0): // LOAD dst,base,index,DWORD + PARAM0 = inst[1].puint32[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOAD4x8, 4, 0): // LOAD dst,base,index,DWORD_x8 + PARAM0 = *(UINT32 *)&inst[1].puint64[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOADS1, 4, 0): // LOADS dst,base,index,BYTE + PARAM0 = inst[1].pint8[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOADS1x2, 4, 0): // LOADS dst,base,index,BYTE_x2 + PARAM0 = *(INT8 *)&inst[1].pint16[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOADS1x4, 4, 0): // LOADS dst,base,index,BYTE_x4 + PARAM0 = *(INT8 *)&inst[1].pint32[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOADS1x8, 4, 0): // LOADS dst,base,index,BYTE_x8 + PARAM0 = *(INT8 *)&inst[1].pint64[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOADS2x1, 4, 0): // LOADS dst,base,index,WORD_x1 + PARAM0 = *(INT16 *)&inst[1].pint8[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOADS2, 4, 0): // LOADS dst,base,index,WORD + PARAM0 = inst[1].pint16[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOADS2x4, 4, 0): // LOADS dst,base,index,WORD_x4 + PARAM0 = *(INT16 *)&inst[1].pint32[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOADS2x8, 4, 0): // LOADS dst,base,index,WORD_x8 + PARAM0 = *(INT16 *)&inst[1].pint64[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOADS4x1, 4, 0): // LOADS dst,base,index,DWORD_x1 + PARAM0 = *(INT32 *)&inst[1].pint8[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOADS4x2, 4, 0): // LOADS dst,base,index,DWORD_x2 + PARAM0 = *(INT32 *)&inst[1].pint16[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOADS4, 4, 0): // LOADS dst,base,index,DWORD + PARAM0 = inst[1].pint32[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOADS4x8, 4, 0): // LOADS dst,base,index,DWORD_x8 + PARAM0 = *(INT32 *)&inst[1].pint64[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_STORE1, 4, 0): // STORE dst,base,index,BYTE + inst[0].puint8[PARAM1] = PARAM2; + break; + + case MAKE_OPCODE_SHORT(OP_STORE1x2, 4, 0): // STORE dst,base,index,BYTE_x2 + *(UINT8 *)&inst[0].puint16[PARAM1] = PARAM2; + break; + + case MAKE_OPCODE_SHORT(OP_STORE1x4, 4, 0): // STORE dst,base,index,BYTE_x4 + *(UINT8 *)&inst[0].puint32[PARAM1] = PARAM2; + break; + + case MAKE_OPCODE_SHORT(OP_STORE1x8, 4, 0): // STORE dst,base,index,BYTE_x8 + *(UINT8 *)&inst[0].puint64[PARAM1] = PARAM2; + break; + + case MAKE_OPCODE_SHORT(OP_STORE2x1, 4, 0): // STORE dst,base,index,WORD_x1 + *(UINT16 *)&inst[0].puint8[PARAM1] = PARAM2; + break; + + case MAKE_OPCODE_SHORT(OP_STORE2, 4, 0): // STORE dst,base,index,WORD + inst[0].puint16[PARAM1] = PARAM2; + break; + + case MAKE_OPCODE_SHORT(OP_STORE2x4, 4, 0): // STORE dst,base,index,WORD_x4 + *(UINT16 *)&inst[0].puint32[PARAM1] = PARAM2; + break; + + case MAKE_OPCODE_SHORT(OP_STORE2x8, 4, 0): // STORE dst,base,index,WORD_x8 + *(UINT16 *)&inst[0].puint64[PARAM1] = PARAM2; + break; + + case MAKE_OPCODE_SHORT(OP_STORE4x1, 4, 0): // STORE dst,base,index,DWORD_x1 + *(UINT32 *)&inst[0].puint8[PARAM1] = PARAM2; + break; + + case MAKE_OPCODE_SHORT(OP_STORE4x2, 4, 0): // STORE dst,base,index,DWORD_x2 + *(UINT32 *)&inst[0].puint16[PARAM1] = PARAM2; + break; + + case MAKE_OPCODE_SHORT(OP_STORE4, 4, 0): // STORE dst,base,index,DWORD + inst[0].puint32[PARAM1] = PARAM2; + break; + + case MAKE_OPCODE_SHORT(OP_STORE4x8, 4, 0): // STORE dst,base,index,DWORD_x8 + *(UINT32 *)&inst[0].puint64[PARAM1] = PARAM2; + break; + + case MAKE_OPCODE_SHORT(OP_READ1, 4, 0): // READ dst,src1,space_BYTE + PARAM0 = m_space[PARAM2]->read_byte(PARAM1); + break; + + case MAKE_OPCODE_SHORT(OP_READ2, 4, 0): // READ dst,src1,space_WORD + PARAM0 = m_space[PARAM2]->read_word(PARAM1); + break; + + case MAKE_OPCODE_SHORT(OP_READ4, 4, 0): // READ dst,src1,space_DWORD + PARAM0 = m_space[PARAM2]->read_dword(PARAM1); + break; + + case MAKE_OPCODE_SHORT(OP_READM2, 4, 0): // READM dst,src1,mask,space_WORD + PARAM0 = m_space[PARAM3]->read_word(PARAM1, PARAM2); + break; + + case MAKE_OPCODE_SHORT(OP_READM4, 4, 0): // READM dst,src1,mask,space_DWORD + PARAM0 = m_space[PARAM3]->read_dword(PARAM1, PARAM2); + break; + + case MAKE_OPCODE_SHORT(OP_WRITE1, 4, 0): // WRITE dst,src1,space_BYTE + m_space[PARAM2]->write_byte(PARAM0, PARAM1); + break; + + case MAKE_OPCODE_SHORT(OP_WRITE2, 4, 0): // WRITE dst,src1,space_WORD + m_space[PARAM2]->write_word(PARAM0, PARAM1); + break; + + case MAKE_OPCODE_SHORT(OP_WRITE4, 4, 0): // WRITE dst,src1,space_DWORD + m_space[PARAM2]->write_dword(PARAM0, PARAM1); + break; + + case MAKE_OPCODE_SHORT(OP_WRITEM2, 4, 0): // WRITEM dst,src1,mask,space_WORD + m_space[PARAM3]->write_word(PARAM0, PARAM1, PARAM2); + break; + + case MAKE_OPCODE_SHORT(OP_WRITEM4, 4, 0): // WRITEM dst,src1,mask,space_DWORD + m_space[PARAM3]->write_dword(PARAM0, PARAM1, PARAM2); + break; + + case MAKE_OPCODE_SHORT(OP_CARRY, 4, 1): // CARRY src,bitnum + flags = (flags & ~FLAG_C) | ((PARAM0 >> (PARAM1 & 31)) & FLAG_C); + break; + + case MAKE_OPCODE_SHORT(OP_MOV, 4, 1): // MOV dst,src[,c] + if (OPCODE_FAIL_CONDITION(opcode, flags)) + break; + // fall through... + + case MAKE_OPCODE_SHORT(OP_MOV, 4, 0): + PARAM0 = PARAM1; + break; + + case MAKE_OPCODE_SHORT(OP_SET, 4, 1): // SET dst,c + PARAM0 = OPCODE_FAIL_CONDITION(opcode, flags) ? 0 : 1; + break; + + case MAKE_OPCODE_SHORT(OP_SEXT1, 4, 0): // SEXT1 dst,src + PARAM0 = (INT8)PARAM1; + break; + + case MAKE_OPCODE_SHORT(OP_SEXT1, 4, 1): + temp32 = (INT8)PARAM1; + flags = FLAGS32_NZ(temp32); + PARAM0 = temp32; + break; + + case MAKE_OPCODE_SHORT(OP_SEXT2, 4, 0): // SEXT2 dst,src + PARAM0 = (INT16)PARAM1; + break; + + case MAKE_OPCODE_SHORT(OP_SEXT2, 4, 1): + temp32 = (INT16)PARAM1; + flags = FLAGS32_NZ(temp32); + PARAM0 = temp32; + break; + + case MAKE_OPCODE_SHORT(OP_ROLAND, 4, 0): // ROLAND dst,src,count,mask[,f] + shift = PARAM2 & 31; + PARAM0 = ((PARAM1 << shift) | (PARAM1 >> (32 - shift))) & PARAM3; + break; + + case MAKE_OPCODE_SHORT(OP_ROLAND, 4, 1): + shift = PARAM2 & 31; + temp32 = ((PARAM1 << shift) | (PARAM1 >> (32 - shift))) & PARAM3; + flags = FLAGS32_NZ(temp32); + PARAM0 = temp32; + break; + + case MAKE_OPCODE_SHORT(OP_ROLINS, 4, 0): // ROLINS dst,src,count,mask[,f] + shift = PARAM2 & 31; + PARAM0 = (PARAM0 & ~PARAM3) | (((PARAM1 << shift) | (PARAM1 >> (32 - shift))) & PARAM3); + break; + + case MAKE_OPCODE_SHORT(OP_ROLINS, 4, 1): + shift = PARAM2 & 31; + temp32 = (PARAM0 & ~PARAM3) | (((PARAM1 << shift) | (PARAM1 >> (32 - shift))) & PARAM3); + flags = FLAGS32_NZ(temp32); + PARAM0 = temp32; + break; + + case MAKE_OPCODE_SHORT(OP_ADD, 4, 0): // ADD dst,src1,src2[,f] + PARAM0 = PARAM1 + PARAM2; + break; + + case MAKE_OPCODE_SHORT(OP_ADD, 4, 1): + temp32 = PARAM1 + PARAM2; + flags = FLAGS32_NZCV_ADD(temp32, PARAM1, PARAM2); + PARAM0 = temp32; + break; + + case MAKE_OPCODE_SHORT(OP_ADDC, 4, 0): // ADDC dst,src1,src2[,f] + PARAM0 = PARAM1 + PARAM2 + (flags & FLAG_C); + break; + + case MAKE_OPCODE_SHORT(OP_ADDC, 4, 1): + temp32 = PARAM1 + PARAM2 + (flags & FLAG_C); + if (PARAM2 + 1 != 0) + flags = FLAGS32_NZCV_ADD(temp32, PARAM1, PARAM2 + (flags & FLAG_C)); + else + { + if ((PARAM2 == 0xffffffff) && (flags & FLAG_C)) + { + flags = FLAGS32_NZCV_ADD(temp32, PARAM1 + (flags & FLAG_C), PARAM2); + flags |= FLAG_C; + } + else + flags = FLAGS32_NZCV_ADD(temp32, PARAM1 + (flags & FLAG_C), PARAM2); + } + PARAM0 = temp32; + break; + + case MAKE_OPCODE_SHORT(OP_SUB, 4, 0): // SUB dst,src1,src2[,f] + PARAM0 = PARAM1 - PARAM2; + break; + + case MAKE_OPCODE_SHORT(OP_SUB, 4, 1): + temp32 = PARAM1 - PARAM2; + flags = FLAGS32_NZCV_SUB(temp32, PARAM1, PARAM2); + PARAM0 = temp32; + break; + + case MAKE_OPCODE_SHORT(OP_SUBB, 4, 0): // SUBB dst,src1,src2[,f] + PARAM0 = PARAM1 - PARAM2 - (flags & FLAG_C); + break; + + case MAKE_OPCODE_SHORT(OP_SUBB, 4, 1): + temp32 = PARAM1 - PARAM2 - (flags & FLAG_C); + temp64 = (UINT64)PARAM1 - (UINT64)PARAM2 - (UINT64)(flags & FLAG_C); + if (PARAM2 + 1 != 0) + flags = FLAGS32_NZCV_SUB(temp32, PARAM1, PARAM2 + (flags & FLAG_C)); + else + { + flags = FLAGS32_NZCV_SUB(temp32, PARAM1 - (flags & FLAG_C), PARAM2); + flags &= ~(FLAG_C | FLAG_V); + flags |= ((temp64>>32) & 1) ? FLAG_C : 0; + flags |= (((PARAM1) ^ (PARAM2)) & ((PARAM1) ^ (temp64)) & 0x80000000) ? FLAG_V : 0; + } + PARAM0 = temp32; + break; + + case MAKE_OPCODE_SHORT(OP_CMP, 4, 1): // CMP src1,src2[,f] + temp32 = PARAM0 - PARAM1; + flags = FLAGS32_NZCV_SUB(temp32, PARAM0, PARAM1); +// printf("CMP: %08x - %08x = flags %x\n", PARAM0, PARAM1, flags); + break; + + case MAKE_OPCODE_SHORT(OP_MULU, 4, 0): // MULU dst,edst,src1,src2[,f] + temp64 = (UINT64)(UINT32)PARAM2 * (UINT64)(UINT32)PARAM3; + PARAM1 = temp64 >> 32; + PARAM0 = (UINT32)temp64; + break; + + case MAKE_OPCODE_SHORT(OP_MULU, 4, 1): + temp64 = (UINT64)(UINT32)PARAM2 * (UINT64)(UINT32)PARAM3; + flags = FLAGS64_NZ(temp64); + PARAM1 = temp64 >> 32; + PARAM0 = (UINT32)temp64; + if (temp64 != (UINT32)temp64) + flags |= FLAG_V; + break; + + case MAKE_OPCODE_SHORT(OP_MULS, 4, 0): // MULS dst,edst,src1,src2[,f] + temp64 = (INT64)(INT32)PARAM2 * (INT64)(INT32)PARAM3; + PARAM1 = temp64 >> 32; + PARAM0 = (UINT32)temp64; + break; + + case MAKE_OPCODE_SHORT(OP_MULS, 4, 1): + temp64 = (INT64)(INT32)PARAM2 * (INT64)(INT32)PARAM3; + temp32 = (INT32)temp64; + flags = FLAGS32_NZ(temp32); + PARAM1 = temp64 >> 32; + PARAM0 = (UINT32)temp64; + if (temp64 != (INT32)temp64) + flags |= FLAG_V; + break; + + case MAKE_OPCODE_SHORT(OP_DIVU, 4, 0): // DIVU dst,edst,src1,src2[,f] + if (PARAM3 != 0) + { + temp32 = (UINT32)PARAM2 / (UINT32)PARAM3; + PARAM1 = (UINT32)PARAM2 % (UINT32)PARAM3; + PARAM0 = temp32; + } + break; + + case MAKE_OPCODE_SHORT(OP_DIVU, 4, 1): + if (PARAM3 != 0) + { + temp32 = (UINT32)PARAM2 / (UINT32)PARAM3; + PARAM1 = (UINT32)PARAM2 % (UINT32)PARAM3; + flags = FLAGS32_NZ(temp32); + PARAM0 = temp32; + } + else + flags = FLAG_V; + break; + + case MAKE_OPCODE_SHORT(OP_DIVS, 4, 0): // DIVS dst,edst,src1,src2[,f] + if (PARAM3 != 0) + { + temp32 = (INT32)PARAM2 / (INT32)PARAM3; + PARAM1 = (INT32)PARAM2 % (INT32)PARAM3; + PARAM0 = temp32; + } + break; + + case MAKE_OPCODE_SHORT(OP_DIVS, 4, 1): + if (PARAM3 != 0) + { + temp32 = (INT32)PARAM2 / (INT32)PARAM3; + PARAM1 = (INT32)PARAM2 % (INT32)PARAM3; + flags = FLAGS32_NZ(temp32); + PARAM0 = temp32; + } + else + flags = FLAG_V; + break; + + case MAKE_OPCODE_SHORT(OP_AND, 4, 0): // AND dst,src1,src2[,f] + PARAM0 = PARAM1 & PARAM2; + break; + + case MAKE_OPCODE_SHORT(OP_AND, 4, 1): + temp32 = PARAM1 & PARAM2; + flags = FLAGS32_NZ(temp32); + PARAM0 = temp32; + break; + + case MAKE_OPCODE_SHORT(OP_TEST, 4, 1): // TEST src1,src2[,f] + temp32 = PARAM0 & PARAM1; + flags = FLAGS32_NZ(temp32); + break; + + case MAKE_OPCODE_SHORT(OP_OR, 4, 0): // OR dst,src1,src2[,f] + PARAM0 = PARAM1 | PARAM2; + break; + + case MAKE_OPCODE_SHORT(OP_OR, 4, 1): + temp32 = PARAM1 | PARAM2; + flags = FLAGS32_NZ(temp32); + PARAM0 = temp32; + break; + + case MAKE_OPCODE_SHORT(OP_XOR, 4, 0): // XOR dst,src1,src2[,f] + PARAM0 = PARAM1 ^ PARAM2; + break; + + case MAKE_OPCODE_SHORT(OP_XOR, 4, 1): + temp32 = PARAM1 ^ PARAM2; + flags = FLAGS32_NZ(temp32); + PARAM0 = temp32; + break; + + case MAKE_OPCODE_SHORT(OP_LZCNT, 4, 0): // LZCNT dst,src + PARAM0 = count_leading_zeros(PARAM1); + break; + + case MAKE_OPCODE_SHORT(OP_LZCNT, 4, 1): + temp32 = count_leading_zeros(PARAM1); + flags = FLAGS32_NZ(temp32); + PARAM0 = temp32; + break; + + case MAKE_OPCODE_SHORT(OP_BSWAP, 4, 0): // BSWAP dst,src + temp32 = PARAM1; + PARAM0 = FLIPENDIAN_INT32(temp32); + break; + + case MAKE_OPCODE_SHORT(OP_BSWAP, 4, 1): + temp32 = PARAM1; + flags = FLAGS32_NZ(temp32); + PARAM0 = FLIPENDIAN_INT32(temp32); + break; + + case MAKE_OPCODE_SHORT(OP_SHL, 4, 0): // SHL dst,src,count[,f] + PARAM0 = PARAM1 << (PARAM2 & 31); + break; + + case MAKE_OPCODE_SHORT(OP_SHL, 4, 1): + shift = PARAM2 & 31; + temp32 = PARAM1 << shift; + if (shift != 0) + { + flags = FLAGS32_NZ(temp32); + flags |= ((PARAM1 << (shift - 1)) >> 31) & FLAG_C; + } + PARAM0 = temp32; + break; + + case MAKE_OPCODE_SHORT(OP_SHR, 4, 0): // SHR dst,src,count[,f] + PARAM0 = PARAM1 >> (PARAM2 & 31); + break; + + case MAKE_OPCODE_SHORT(OP_SHR, 4, 1): + shift = PARAM2 & 31; + temp32 = PARAM1 >> shift; + if (shift != 0) + { + flags = FLAGS32_NZ(temp32); + flags |= (PARAM1 >> (shift - 1)) & FLAG_C; + } + PARAM0 = temp32; + break; + + case MAKE_OPCODE_SHORT(OP_SAR, 4, 0): // SAR dst,src,count[,f] + PARAM0 = (INT32)PARAM1 >> (PARAM2 & 31); + break; + + case MAKE_OPCODE_SHORT(OP_SAR, 4, 1): + shift = PARAM2 & 31; + temp32 = (INT32)PARAM1 >> shift; + if (shift != 0) + { + flags = FLAGS32_NZ(temp32); + flags |= (PARAM1 >> (shift - 1)) & FLAG_C; + } + PARAM0 = temp32; + break; + + case MAKE_OPCODE_SHORT(OP_ROL, 4, 0): // ROL dst,src,count[,f] + shift = PARAM2 & 31; + PARAM0 = (PARAM1 << shift) | (PARAM1 >> ((32 - shift) & 31)); + break; + + case MAKE_OPCODE_SHORT(OP_ROL, 4, 1): + shift = PARAM2 & 31; + temp32 = (PARAM1 << shift) | (PARAM1 >> ((32 - shift) & 31)); + if (shift != 0) + { + flags = FLAGS32_NZ(temp32); + flags |= ((PARAM1 << (shift - 1)) >> 31) & FLAG_C; + } + PARAM0 = temp32; + break; + + case MAKE_OPCODE_SHORT(OP_ROLC, 4, 0): // ROLC dst,src,count[,f] + shift = PARAM2 & 31; + if (shift > 1) + PARAM0 = (PARAM1 << shift) | ((flags & FLAG_C) << (shift - 1)) | (PARAM1 >> (33 - shift)); + else if (shift == 1) + PARAM0 = (PARAM1 << shift) | (flags & FLAG_C); + break; + + case MAKE_OPCODE_SHORT(OP_ROLC, 4, 1): + shift = PARAM2 & 31; + if (shift > 1) + temp32 = (PARAM1 << shift) | ((flags & FLAG_C) << (shift - 1)) | (PARAM1 >> (33 - shift)); + else if (shift == 1) + temp32 = (PARAM1 << shift) | (flags & FLAG_C); + else + temp32 = PARAM1; + flags = FLAGS32_NZ(temp32); + if (shift != 0) flags |= ((PARAM1 << (shift - 1)) >> 31) & FLAG_C; + PARAM0 = temp32; + break; + + case MAKE_OPCODE_SHORT(OP_ROR, 4, 0): // ROR dst,src,count[,f] + shift = PARAM2 & 31; + PARAM0 = (PARAM1 >> shift) | (PARAM1 << ((32 - shift) & 31)); + break; + + case MAKE_OPCODE_SHORT(OP_ROR, 4, 1): + shift = PARAM2 & 31; + temp32 = (PARAM1 >> shift) | (PARAM1 << ((32 - shift) & 31)); + flags = FLAGS32_NZ(temp32); + if (shift != 0) flags |= (PARAM1 >> (shift - 1)) & FLAG_C; + PARAM0 = temp32; + break; + + case MAKE_OPCODE_SHORT(OP_RORC, 4, 0): // RORC dst,src,count[,f] + shift = PARAM2 & 31; + if (shift > 1) + PARAM0 = (PARAM1 >> shift) | (((flags & FLAG_C) << 31) >> (shift - 1)) | (PARAM1 << (33 - shift)); + else if (shift == 1) + PARAM0 = (PARAM1 >> shift) | ((flags & FLAG_C) << 31); + break; + + case MAKE_OPCODE_SHORT(OP_RORC, 4, 1): + shift = PARAM2 & 31; + if (shift > 1) + temp32 = (PARAM1 >> shift) | (((flags & FLAG_C) << 31) >> (shift - 1)) | (PARAM1 << (33 - shift)); + else if (shift == 1) + temp32 = (PARAM1 >> shift) | ((flags & FLAG_C) << 31); + else + temp32 = PARAM1; + flags = FLAGS32_NZ(temp32); + if (shift != 0) flags |= (PARAM1 >> (shift - 1)) & FLAG_C; + PARAM0 = temp32; + break; + + + // ----------------------- 64-Bit Integer Operations ----------------------- + + case MAKE_OPCODE_SHORT(OP_LOAD1, 8, 0): // DLOAD dst,base,index,BYTE + DPARAM0 = inst[1].puint8[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOAD1x2, 8, 0): // DLOAD dst,base,index,BYTE_x2 + DPARAM0 = *(UINT8 *)&inst[1].puint16[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOAD1x4, 8, 0): // DLOAD dst,base,index,BYTE_x4 + DPARAM0 = *(UINT8 *)&inst[1].puint32[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOAD1x8, 8, 0): // DLOAD dst,base,index,BYTE_x8 + DPARAM0 = *(UINT8 *)&inst[1].puint64[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOAD2x1, 8, 0): // DLOAD dst,base,index,WORD_x1 + DPARAM0 = *(UINT16 *)&inst[1].puint8[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOAD2, 8, 0): // DLOAD dst,base,index,WORD + DPARAM0 = inst[1].puint16[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOAD2x4, 8, 0): // DLOAD dst,base,index,WORD_x4 + DPARAM0 = *(UINT16 *)&inst[1].puint32[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOAD2x8, 8, 0): // DLOAD dst,base,index,WORD_x8 + DPARAM0 = *(UINT16 *)&inst[1].puint64[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOAD4x1, 8, 0): // DLOAD dst,base,index,DWORD_x1 + DPARAM0 = *(UINT32 *)&inst[1].puint8[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOAD4x2, 8, 0): // DLOAD dst,base,index,DWORD_x2 + DPARAM0 = *(UINT32 *)&inst[1].puint16[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOAD4, 8, 0): // DLOAD dst,base,index,DWORD + DPARAM0 = inst[1].puint32[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOAD4x8, 8, 0): // DLOAD dst,base,index,DWORD_x8 + DPARAM0 = *(UINT32 *)&inst[1].puint64[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOAD8x1, 8, 0): // DLOAD dst,base,index,QWORD_x1 + DPARAM0 = *(UINT64 *)&inst[1].puint8[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOAD8x2, 8, 0): // DLOAD dst,base,index,QWORD_x2 + DPARAM0 = *(UINT64 *)&inst[1].puint16[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOAD8x4, 8, 0): // DLOAD dst,base,index,QWORD_x4 + DPARAM0 = *(UINT64 *)&inst[1].puint32[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOAD8, 8, 0): // DLOAD dst,base,index,QWORD + DPARAM0 = inst[1].puint64[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOADS1, 8, 0): // DLOADS dst,base,index,BYTE + DPARAM0 = inst[1].pint8[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOADS1x2, 8, 0): // DLOADS dst,base,index,BYTE_x2 + DPARAM0 = *(INT8 *)&inst[1].pint16[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOADS1x4, 8, 0): // DLOADS dst,base,index,BYTE_x4 + DPARAM0 = *(INT8 *)&inst[1].pint32[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOADS1x8, 8, 0): // DLOADS dst,base,index,BYTE_x8 + DPARAM0 = *(INT8 *)&inst[1].pint64[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOADS2x1, 8, 0): // DLOADS dst,base,index,WORD_x1 + DPARAM0 = *(INT16 *)&inst[1].pint8[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOADS2, 8, 0): // DLOADS dst,base,index,WORD + DPARAM0 = inst[1].pint16[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOADS2x4, 8, 0): // DLOADS dst,base,index,WORD_x4 + DPARAM0 = *(INT16 *)&inst[1].pint32[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOADS2x8, 8, 0): // DLOADS dst,base,index,WORD_x8 + DPARAM0 = *(INT16 *)&inst[1].pint64[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOADS4x1, 8, 0): // DLOADS dst,base,index,DWORD_x1 + DPARAM0 = *(INT32 *)&inst[1].pint8[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOADS4x2, 8, 0): // DLOADS dst,base,index,DWORD_x2 + DPARAM0 = *(INT32 *)&inst[1].pint16[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOADS4, 8, 0): // DLOADS dst,base,index,DWORD + DPARAM0 = inst[1].pint32[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOADS4x8, 8, 0): // DLOADS dst,base,index,DWORD_x8 + DPARAM0 = *(INT32 *)&inst[1].pint64[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOADS8x1, 8, 0): // DLOADS dst,base,index,QWORD_x1 + DPARAM0 = *(INT64 *)&inst[1].pint8[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOADS8x2, 8, 0): // DLOADS dst,base,index,QWORD_x2 + DPARAM0 = *(INT64 *)&inst[1].pint16[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOADS8x4, 8, 0): // DLOADS dst,base,index,QWORD_x4 + DPARAM0 = *(INT64 *)&inst[1].pint32[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_LOADS8, 8, 0): // DLOADS dst,base,index,QWORD + DPARAM0 = inst[1].pint64[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_STORE1, 8, 0): // DSTORE dst,base,index,BYTE + inst[0].puint8[PARAM1] = DPARAM2; + break; + + case MAKE_OPCODE_SHORT(OP_STORE1x2, 8, 0): // DSTORE dst,base,index,BYTE_x2 + *(UINT8 *)&inst[0].puint16[PARAM1] = DPARAM2; + break; + + case MAKE_OPCODE_SHORT(OP_STORE1x4, 8, 0): // DSTORE dst,base,index,BYTE_x4 + *(UINT8 *)&inst[0].puint32[PARAM1] = DPARAM2; + break; + + case MAKE_OPCODE_SHORT(OP_STORE1x8, 8, 0): // DSTORE dst,base,index,BYTE_x8 + *(UINT8 *)&inst[0].puint64[PARAM1] = DPARAM2; + break; + + case MAKE_OPCODE_SHORT(OP_STORE2x1, 8, 0): // DSTORE dst,base,index,WORD_x1 + *(UINT16 *)&inst[0].puint8[PARAM1] = DPARAM2; + break; + + case MAKE_OPCODE_SHORT(OP_STORE2, 8, 0): // DSTORE dst,base,index,WORD + inst[0].puint16[PARAM1] = DPARAM2; + break; + + case MAKE_OPCODE_SHORT(OP_STORE2x4, 8, 0): // DSTORE dst,base,index,WORD_x4 + *(UINT16 *)&inst[0].puint32[PARAM1] = DPARAM2; + break; + + case MAKE_OPCODE_SHORT(OP_STORE2x8, 8, 0): // DSTORE dst,base,index,WORD_x8 + *(UINT16 *)&inst[0].puint64[PARAM1] = DPARAM2; + break; + + case MAKE_OPCODE_SHORT(OP_STORE4x1, 8, 0): // DSTORE dst,base,index,DWORD_x1 + *(UINT32 *)&inst[0].puint8[PARAM1] = DPARAM2; + break; + + case MAKE_OPCODE_SHORT(OP_STORE4x2, 8, 0): // DSTORE dst,base,index,DWORD_x2 + *(UINT32 *)&inst[0].puint16[PARAM1] = DPARAM2; + break; + + case MAKE_OPCODE_SHORT(OP_STORE4, 8, 0): // DSTORE dst,base,index,DWORD + inst[0].puint32[PARAM1] = DPARAM2; + break; + + case MAKE_OPCODE_SHORT(OP_STORE4x8, 8, 0): // DSTORE dst,base,index,DWORD_x8 + *(UINT32 *)&inst[0].puint64[PARAM1] = DPARAM2; + break; + + case MAKE_OPCODE_SHORT(OP_STORE8x1, 8, 0): // DSTORE dst,base,index,QWORD_x1 + *(UINT64 *)&inst[0].puint8[PARAM1] = DPARAM2; + break; + + case MAKE_OPCODE_SHORT(OP_STORE8x2, 8, 0): // DSTORE dst,base,index,QWORD_x2 + *(UINT64 *)&inst[0].puint16[PARAM1] = DPARAM2; + break; + + case MAKE_OPCODE_SHORT(OP_STORE8x4, 8, 0): // DSTORE dst,base,index,QWORD_x4 + *(UINT64 *)&inst[0].puint32[PARAM1] = DPARAM2; + break; + + case MAKE_OPCODE_SHORT(OP_STORE8, 8, 0): // DSTORE dst,base,index,QWORD + inst[0].puint64[PARAM1] = DPARAM2; + break; + + case MAKE_OPCODE_SHORT(OP_READ1, 8, 0): // DREAD dst,src1,space_BYTE + DPARAM0 = m_space[PARAM2]->read_byte(PARAM1); + break; + + case MAKE_OPCODE_SHORT(OP_READ2, 8, 0): // DREAD dst,src1,space_WORD + DPARAM0 = m_space[PARAM2]->read_word(PARAM1); + break; + + case MAKE_OPCODE_SHORT(OP_READ4, 8, 0): // DREAD dst,src1,space_DWORD + DPARAM0 = m_space[PARAM2]->read_dword(PARAM1); + break; + + case MAKE_OPCODE_SHORT(OP_READ8, 8, 0): // DREAD dst,src1,space_QOWRD + DPARAM0 = m_space[PARAM2]->read_qword(PARAM1); + break; + + case MAKE_OPCODE_SHORT(OP_READM2, 8, 0): // DREADM dst,src1,mask,space_WORD + DPARAM0 = m_space[PARAM3]->read_word(PARAM1, PARAM2); + break; + + case MAKE_OPCODE_SHORT(OP_READM4, 8, 0): // DREADM dst,src1,mask,space_DWORD + DPARAM0 = m_space[PARAM3]->read_dword(PARAM1, PARAM2); + break; + + case MAKE_OPCODE_SHORT(OP_READM8, 8, 0): // DREADM dst,src1,mask,space_QWORD + DPARAM0 = m_space[PARAM3]->read_qword(PARAM1, PARAM2); + break; + + case MAKE_OPCODE_SHORT(OP_WRITE1, 8, 0): // DWRITE dst,src1,space_BYTE + m_space[PARAM2]->write_byte(PARAM0, PARAM1); + break; + + case MAKE_OPCODE_SHORT(OP_WRITE2, 8, 0): // DWRITE dst,src1,space_WORD + m_space[PARAM2]->write_word(PARAM0, PARAM1); + break; + + case MAKE_OPCODE_SHORT(OP_WRITE4, 8, 0): // DWRITE dst,src1,space_DWORD + m_space[PARAM2]->write_dword(PARAM0, PARAM1); + break; + + case MAKE_OPCODE_SHORT(OP_WRITE8, 8, 0): // DWRITE dst,src1,space_QWORD + m_space[PARAM2]->write_qword(PARAM0, DPARAM1); + break; + + case MAKE_OPCODE_SHORT(OP_WRITEM2, 8, 0): // DWRITEM dst,src1,mask,space_WORD + m_space[PARAM3]->write_word(PARAM0, DPARAM1, DPARAM2); + break; + + case MAKE_OPCODE_SHORT(OP_WRITEM4, 8, 0): // DWRITEM dst,src1,mask,space_DWORD + m_space[PARAM3]->write_dword(PARAM0, DPARAM1, DPARAM2); + break; + + case MAKE_OPCODE_SHORT(OP_WRITEM8, 8, 0): // DWRITEM dst,src1,mask,space_QWORD + m_space[PARAM3]->write_qword(PARAM0, DPARAM1, DPARAM2); + break; + + case MAKE_OPCODE_SHORT(OP_CARRY, 8, 0): // DCARRY src,bitnum + flags = (flags & ~FLAG_C) | ((DPARAM0 >> (DPARAM1 & 63)) & FLAG_C); + break; + + case MAKE_OPCODE_SHORT(OP_MOV, 8, 1): // DMOV dst,src[,c] + if (OPCODE_FAIL_CONDITION(opcode, flags)) + break; + // fall through... + + case MAKE_OPCODE_SHORT(OP_MOV, 8, 0): + DPARAM0 = DPARAM1; + break; + + case MAKE_OPCODE_SHORT(OP_SET, 8, 1): // DSET dst,c + DPARAM0 = OPCODE_FAIL_CONDITION(opcode, flags) ? 0 : 1; + break; + + case MAKE_OPCODE_SHORT(OP_SEXT1, 8, 0): // DSEXT dst,src,BYTE + DPARAM0 = (INT8)PARAM1; + break; + + case MAKE_OPCODE_SHORT(OP_SEXT1, 8, 1): + temp64 = (INT8)PARAM1; + flags = FLAGS64_NZ(temp64); + DPARAM0 = temp64; + break; + + case MAKE_OPCODE_SHORT(OP_SEXT2, 8, 0): // DSEXT dst,src,WORD + DPARAM0 = (INT16)PARAM1; + break; + + case MAKE_OPCODE_SHORT(OP_SEXT2, 8, 1): + temp64 = (INT16)PARAM1; + flags = FLAGS64_NZ(temp64); + DPARAM0 = temp64; + break; + + case MAKE_OPCODE_SHORT(OP_SEXT4, 8, 0): // DSEXT dst,src,DWORD + DPARAM0 = (INT32)PARAM1; + break; + + case MAKE_OPCODE_SHORT(OP_SEXT4, 8, 1): + temp64 = (INT32)PARAM1; + flags = FLAGS64_NZ(temp64); + DPARAM0 = temp64; + break; + + case MAKE_OPCODE_SHORT(OP_ROLAND, 8, 0): // DROLAND dst,src,count,mask[,f] + shift = DPARAM2 & 63; + DPARAM0 = ((DPARAM1 << shift) | (DPARAM1 >> (64 - shift))) & DPARAM3; + break; + + case MAKE_OPCODE_SHORT(OP_ROLAND, 8, 1): + shift = DPARAM2 & 63; + temp64 = ((DPARAM1 << shift) | (DPARAM1 >> (64 - shift))) & DPARAM3; + flags = FLAGS64_NZ(temp64); + DPARAM0 = temp64; + break; + + case MAKE_OPCODE_SHORT(OP_ROLINS, 8, 0): // DROLINS dst,src,count,mask[,f] + shift = DPARAM2 & 63; + DPARAM0 = (DPARAM0 & ~DPARAM3) | (((DPARAM1 << shift) | (DPARAM1 >> (64 - shift))) & DPARAM3); + break; + + case MAKE_OPCODE_SHORT(OP_ROLINS, 8, 1): + shift = DPARAM2 & 63; + temp64 = (DPARAM0 & ~DPARAM3) | (((DPARAM1 << shift) | (DPARAM1 >> (64 - shift))) & DPARAM3); + flags = FLAGS64_NZ(temp64); + DPARAM0 = temp64; + break; + + case MAKE_OPCODE_SHORT(OP_ADD, 8, 0): // DADD dst,src1,src2[,f] + DPARAM0 = DPARAM1 + DPARAM2; + break; + + case MAKE_OPCODE_SHORT(OP_ADD, 8, 1): + temp64 = DPARAM1 + DPARAM2; + flags = FLAGS64_NZCV_ADD(temp64, DPARAM1, DPARAM2); + DPARAM0 = temp64; + break; + + case MAKE_OPCODE_SHORT(OP_ADDC, 8, 0): // DADDC dst,src1,src2[,f] + DPARAM0 = DPARAM1 + DPARAM2 + (flags & FLAG_C); + break; + + case MAKE_OPCODE_SHORT(OP_ADDC, 8, 1): + temp64 = DPARAM1 + DPARAM2 + (flags & FLAG_C); + if (DPARAM2 + 1 != 0) + flags = FLAGS64_NZCV_ADD(temp64, DPARAM1, DPARAM2 + (flags & FLAG_C)); + else + flags = FLAGS64_NZCV_ADD(temp64, DPARAM1 + (flags & FLAG_C), DPARAM2); + DPARAM0 = temp64; + break; + + case MAKE_OPCODE_SHORT(OP_SUB, 8, 0): // DSUB dst,src1,src2[,f] + DPARAM0 = DPARAM1 - DPARAM2; + break; + + case MAKE_OPCODE_SHORT(OP_SUB, 8, 1): + temp64 = DPARAM1 - DPARAM2; + flags = FLAGS64_NZCV_SUB(temp64, DPARAM1, DPARAM2); + DPARAM0 = temp64; + break; + + case MAKE_OPCODE_SHORT(OP_SUBB, 8, 0): // DSUBB dst,src1,src2[,f] + DPARAM0 = DPARAM1 - DPARAM2 - (flags & FLAG_C); + break; + + case MAKE_OPCODE_SHORT(OP_SUBB, 8, 1): + temp64 = DPARAM1 - DPARAM2 - (flags & FLAG_C); + if (DPARAM2 + 1 != 0) + flags = FLAGS64_NZCV_SUB(temp64, DPARAM1, DPARAM2 + (flags & FLAG_C)); + else + flags = FLAGS64_NZCV_SUB(temp64, DPARAM1 - (flags & FLAG_C), DPARAM2); + DPARAM0 = temp64; + break; + + case MAKE_OPCODE_SHORT(OP_CMP, 8, 1): // DCMP src1,src2[,f] + temp64 = DPARAM0 - DPARAM1; + flags = FLAGS64_NZCV_SUB(temp64, DPARAM0, DPARAM1); + break; + + case MAKE_OPCODE_SHORT(OP_MULU, 8, 0): // DMULU dst,edst,src1,src2[,f] + dmulu(*inst[0].puint64, *inst[1].puint64, DPARAM2, DPARAM3, FALSE); + break; + + case MAKE_OPCODE_SHORT(OP_MULU, 8, 1): + flags = dmulu(*inst[0].puint64, *inst[1].puint64, DPARAM2, DPARAM3, TRUE); + break; + + case MAKE_OPCODE_SHORT(OP_MULS, 8, 0): // DMULS dst,edst,src1,src2[,f] + dmuls(*inst[0].puint64, *inst[1].puint64, DPARAM2, DPARAM3, FALSE); + break; + + case MAKE_OPCODE_SHORT(OP_MULS, 8, 1): + flags = dmuls(*inst[0].puint64, *inst[1].puint64, DPARAM2, DPARAM3, TRUE); + break; + + case MAKE_OPCODE_SHORT(OP_DIVU, 8, 0): // DDIVU dst,edst,src1,src2[,f] + if (DPARAM3 != 0) + { + temp64 = (UINT64)DPARAM2 / (UINT64)DPARAM3; + DPARAM1 = (UINT64)DPARAM2 % (UINT64)DPARAM3; + DPARAM0 = temp64; + } + break; + + case MAKE_OPCODE_SHORT(OP_DIVU, 8, 1): + if (DPARAM3 != 0) + { + temp64 = (UINT64)DPARAM2 / (UINT64)DPARAM3; + DPARAM1 = (UINT64)DPARAM2 % (UINT64)DPARAM3; + flags = FLAGS64_NZ(temp64); + DPARAM0 = temp64; + } + else + flags = FLAG_V; + break; + + case MAKE_OPCODE_SHORT(OP_DIVS, 8, 0): // DDIVS dst,edst,src1,src2[,f] + if (DPARAM3 != 0) + { + temp64 = (INT64)DPARAM2 / (INT64)DPARAM3; + DPARAM1 = (INT64)DPARAM2 % (INT64)DPARAM3; + DPARAM0 = temp64; + } + break; + + case MAKE_OPCODE_SHORT(OP_DIVS, 8, 1): + if (DPARAM3 != 0) + { + temp64 = (INT64)DPARAM2 / (INT64)DPARAM3; + DPARAM1 = (INT64)DPARAM2 % (INT64)DPARAM3; + flags = FLAGS64_NZ(temp64); + DPARAM0 = temp64; + } + else + flags = FLAG_V; + break; + + case MAKE_OPCODE_SHORT(OP_AND, 8, 0): // DAND dst,src1,src2[,f] + DPARAM0 = DPARAM1 & DPARAM2; + break; + + case MAKE_OPCODE_SHORT(OP_AND, 8, 1): + temp64 = DPARAM1 & DPARAM2; + flags = FLAGS64_NZ(temp64); + DPARAM0 = temp64; + break; + + case MAKE_OPCODE_SHORT(OP_TEST, 8, 1): // DTEST src1,src2[,f] + temp64 = DPARAM1 & DPARAM2; + flags = FLAGS64_NZ(temp64); + break; + + case MAKE_OPCODE_SHORT(OP_OR, 8, 0): // DOR dst,src1,src2[,f] + DPARAM0 = DPARAM1 | DPARAM2; + break; + + case MAKE_OPCODE_SHORT(OP_OR, 8, 1): + temp64 = DPARAM1 | DPARAM2; + flags = FLAGS64_NZ(temp64); + DPARAM0 = temp64; + break; + + case MAKE_OPCODE_SHORT(OP_XOR, 8, 0): // DXOR dst,src1,src2[,f] + DPARAM0 = DPARAM1 ^ DPARAM2; + break; + + case MAKE_OPCODE_SHORT(OP_XOR, 8, 1): + temp64 = DPARAM1 ^ DPARAM2; + flags = FLAGS64_NZ(temp64); + DPARAM0 = temp64; + break; + + case MAKE_OPCODE_SHORT(OP_LZCNT, 8, 0): // DLZCNT dst,src + if ((UINT32)(DPARAM1 >> 32) != 0) + DPARAM0 = count_leading_zeros(DPARAM1 >> 32); + else + DPARAM0 = 32 + count_leading_zeros(DPARAM1); + break; + + case MAKE_OPCODE_SHORT(OP_LZCNT, 8, 1): + if ((UINT32)(DPARAM1 >> 32) != 0) + temp64 = count_leading_zeros(DPARAM1 >> 32); + else + temp64 = 32 + count_leading_zeros(DPARAM1); + flags = FLAGS64_NZ(temp64); + DPARAM0 = temp64; + break; + + case MAKE_OPCODE_SHORT(OP_BSWAP, 8, 0): // DBSWAP dst,src + temp64 = DPARAM1; + DPARAM0 = FLIPENDIAN_INT64(temp64); + break; + + case MAKE_OPCODE_SHORT(OP_BSWAP, 8, 1): + temp64 = DPARAM1; + flags = FLAGS64_NZ(temp64); + DPARAM0 = FLIPENDIAN_INT64(temp64); + break; + + case MAKE_OPCODE_SHORT(OP_SHL, 8, 0): // DSHL dst,src,count[,f] + DPARAM0 = DPARAM1 << (DPARAM2 & 63); + break; + + case MAKE_OPCODE_SHORT(OP_SHL, 8, 1): + shift = DPARAM2 & 63; + temp64 = DPARAM1 << shift; + flags = FLAGS64_NZ(temp64); + if (shift != 0) flags |= ((DPARAM1 << (shift - 1)) >> 63) & FLAG_C; + DPARAM0 = temp64; + break; + + case MAKE_OPCODE_SHORT(OP_SHR, 8, 0): // DSHR dst,src,count[,f] + DPARAM0 = DPARAM1 >> (DPARAM2 & 63); + break; + + case MAKE_OPCODE_SHORT(OP_SHR, 8, 1): + shift = DPARAM2 & 63; + temp64 = DPARAM1 >> shift; + flags = FLAGS64_NZ(temp64); + if (shift != 0) flags |= (DPARAM1 >> (shift - 1)) & FLAG_C; + DPARAM0 = temp64; + break; + + case MAKE_OPCODE_SHORT(OP_SAR, 8, 0): // DSAR dst,src,count[,f] + DPARAM0 = (INT64)DPARAM1 >> (DPARAM2 & 63); + break; + + case MAKE_OPCODE_SHORT(OP_SAR, 8, 1): + shift = DPARAM2 & 63; + temp64 = (INT32)DPARAM1 >> shift; + flags = FLAGS64_NZ(temp64); + if (shift != 0) flags |= (DPARAM1 >> (shift - 1)) & FLAG_C; + DPARAM0 = temp64; + break; + + case MAKE_OPCODE_SHORT(OP_ROL, 8, 0): // DROL dst,src,count[,f] + shift = DPARAM2 & 31; + DPARAM0 = (DPARAM1 << shift) | (DPARAM1 >> ((64 - shift) & 63)); + break; + + case MAKE_OPCODE_SHORT(OP_ROL, 8, 1): + shift = DPARAM2 & 63; + temp64 = (DPARAM1 << shift) | (DPARAM1 >> ((64 - shift) & 63)); + flags = FLAGS64_NZ(temp64); + if (shift != 0) flags |= ((DPARAM1 << (shift - 1)) >> 63) & FLAG_C; + DPARAM0 = temp64; + break; + + case MAKE_OPCODE_SHORT(OP_ROLC, 8, 0): // DROLC dst,src,count[,f] + shift = DPARAM2 & 63; + if (shift > 1) + DPARAM0 = (DPARAM1 << shift) | ((flags & FLAG_C) << (shift - 1)) | (DPARAM1 >> (65 - shift)); + else if (shift == 1) + DPARAM0 = (DPARAM1 << shift) | (flags & FLAG_C); + break; + + case MAKE_OPCODE_SHORT(OP_ROLC, 8, 1): + shift = DPARAM2 & 63; + if (shift > 1) + temp64 = (DPARAM1 << shift) | ((flags & FLAG_C) << (shift - 1)) | (DPARAM1 >> (65 - shift)); + else if (shift == 1) + temp64 = (DPARAM1 << shift) | (flags & FLAG_C); + else + temp64 = DPARAM1; + flags = FLAGS64_NZ(temp64); + if (shift != 0) flags |= ((DPARAM1 << (shift - 1)) >> 63) & FLAG_C; + DPARAM0 = temp64; + break; + + case MAKE_OPCODE_SHORT(OP_ROR, 8, 0): // DROR dst,src,count[,f] + shift = DPARAM2 & 63; + DPARAM0 = (DPARAM1 >> shift) | (DPARAM1 << ((64 - shift) & 63)); + break; + + case MAKE_OPCODE_SHORT(OP_ROR, 8, 1): + shift = DPARAM2 & 63; + temp64 = (DPARAM1 >> shift) | (DPARAM1 << ((64 - shift) & 63)); + flags = FLAGS64_NZ(temp64); + if (shift != 0) flags |= (DPARAM1 >> (shift - 1)) & FLAG_C; + DPARAM0 = temp64; + break; + + case MAKE_OPCODE_SHORT(OP_RORC, 8, 0): // DRORC dst,src,count[,f] + shift = DPARAM2 & 63; + if (shift > 1) + DPARAM0 = (DPARAM1 >> shift) | ((((UINT64)flags & FLAG_C) << 63) >> (shift - 1)) | (DPARAM1 << (65 - shift)); + else if (shift == 1) + DPARAM0 = (DPARAM1 >> shift) | (((UINT64)flags & FLAG_C) << 63); + break; + + case MAKE_OPCODE_SHORT(OP_RORC, 8, 1): + shift = DPARAM2 & 63; + if (shift > 1) + temp64 = (DPARAM1 >> shift) | ((((UINT64)flags & FLAG_C) << 63) >> (shift - 1)) | (DPARAM1 << (65 - shift)); + else if (shift == 1) + temp64 = (DPARAM1 >> shift) | (((UINT64)flags & FLAG_C) << 63); + else + temp64 = DPARAM1; + flags = FLAGS64_NZ(temp64); + if (shift != 0) flags |= (DPARAM1 >> (shift - 1)) & FLAG_C; + DPARAM0 = temp64; + break; + + + // ----------------------- 32-Bit Floating Point Operations ----------------------- + + case MAKE_OPCODE_SHORT(OP_FLOAD, 4, 0): // FSLOAD dst,base,index + FSPARAM0 = inst[1].pfloat[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_FSTORE, 4, 0): // FSSTORE dst,base,index + inst[0].pfloat[PARAM1] = FSPARAM2; + break; + + case MAKE_OPCODE_SHORT(OP_FREAD, 4, 0): // FSREAD dst,src1,space + PARAM0 = m_space[PARAM2]->read_dword(PARAM1); + break; + + case MAKE_OPCODE_SHORT(OP_FWRITE, 4, 0): // FSWRITE dst,src1,space + m_space[PARAM2]->write_dword(PARAM0, PARAM1); + break; + + case MAKE_OPCODE_SHORT(OP_FMOV, 4, 1): // FSMOV dst,src[,c] + if (OPCODE_FAIL_CONDITION(opcode, flags)) + break; + // fall through... + + case MAKE_OPCODE_SHORT(OP_FMOV, 4, 0): + FSPARAM0 = FSPARAM1; + break; + + case MAKE_OPCODE_SHORT(OP_FTOI4T, 4, 0): // FSTOI4T dst,src1 + if (FSPARAM1 >= 0) + *inst[0].pint32 = floor(FSPARAM1); + else + *inst[0].pint32 = ceil(FSPARAM1); + break; + + case MAKE_OPCODE_SHORT(OP_FTOI4R, 4, 0): // FSTOI4R dst,src1 + if (FSPARAM1 >= 0) + *inst[0].pint32 = floor(FSPARAM1 + 0.5f); + else + *inst[0].pint32 = ceil(FSPARAM1 - 0.5f); + break; + + case MAKE_OPCODE_SHORT(OP_FTOI4F, 4, 0): // FSTOI4F dst,src1 + *inst[0].pint32 = floor(FSPARAM1); + break; + + case MAKE_OPCODE_SHORT(OP_FTOI4C, 4, 0): // FSTOI4C dst,src1 + *inst[0].pint32 = ceil(FSPARAM1); + break; + + case MAKE_OPCODE_SHORT(OP_FTOI4, 4, 0): // FSTOI4 dst,src1 + *inst[0].pint32 = FSPARAM1; + break; + + case MAKE_OPCODE_SHORT(OP_FTOI8T, 4, 0): // FSTOI8T dst,src1 + if (FSPARAM1 >= 0) + *inst[0].pint64 = floor(FSPARAM1); + else + *inst[0].pint64 = ceil(FSPARAM1); + break; + + case MAKE_OPCODE_SHORT(OP_FTOI8R, 4, 0): // FSTOI8R dst,src1 + if (FSPARAM1 >= 0) + *inst[0].pint64 = floor(FSPARAM1 + 0.5f); + else + *inst[0].pint64 = ceil(FSPARAM1 - 0.5f); + break; + + case MAKE_OPCODE_SHORT(OP_FTOI8F, 4, 0): // FSTOI8F dst,src1 + *inst[0].pint64 = floor(FSPARAM1); + break; + + case MAKE_OPCODE_SHORT(OP_FTOI8C, 4, 0): // FSTOI8C dst,src1 + *inst[0].pint64 = ceil(FSPARAM1); + break; + + case MAKE_OPCODE_SHORT(OP_FTOI8, 4, 0): // FSTOI8 dst,src1 + *inst[0].pint64 = FSPARAM1; + break; + + case MAKE_OPCODE_SHORT(OP_FFRI4, 4, 0): // FSFRI4 dst,src1 + FSPARAM0 = *inst[1].pint32; + break; + + case MAKE_OPCODE_SHORT(OP_FFRI8, 4, 0): // FSFRI8 dst,src1 + FSPARAM0 = *inst[1].pint64; + break; + + case MAKE_OPCODE_SHORT(OP_FFRFD, 4, 0): // FSFRFD dst,src1 + FSPARAM0 = FDPARAM1; + break; + + case MAKE_OPCODE_SHORT(OP_FADD, 4, 0): // FSADD dst,src1,src2 + FSPARAM0 = FSPARAM1 + FSPARAM2; + break; + + case MAKE_OPCODE_SHORT(OP_FSUB, 4, 0): // FSSUB dst,src1,src2 + FSPARAM0 = FSPARAM1 - FSPARAM2; + break; + + case MAKE_OPCODE_SHORT(OP_FCMP, 4, 1): // FSCMP src1,src2 + if (isnan(FSPARAM0) || isnan(FSPARAM1)) + flags = FLAG_U; + else + flags = (FSPARAM0 < FSPARAM1) | ((FSPARAM0 == FSPARAM1) << 2); + break; + + case MAKE_OPCODE_SHORT(OP_FMUL, 4, 0): // FSMUL dst,src1,src2 + FSPARAM0 = FSPARAM1 * FSPARAM2; + break; + + case MAKE_OPCODE_SHORT(OP_FDIV, 4, 0): // FSDIV dst,src1,src2 + FSPARAM0 = FSPARAM1 / FSPARAM2; + break; + + case MAKE_OPCODE_SHORT(OP_FNEG, 4, 0): // FSNEG dst,src1 + FSPARAM0 = -FSPARAM1; + break; + + case MAKE_OPCODE_SHORT(OP_FABS, 4, 0): // FSABS dst,src1 + FSPARAM0 = fabs(FSPARAM1); + break; + + case MAKE_OPCODE_SHORT(OP_FSQRT, 4, 0): // FSSQRT dst,src1 + FSPARAM0 = sqrt(FSPARAM1); + break; + + case MAKE_OPCODE_SHORT(OP_FRECIP, 4, 0): // FSRECIP dst,src1 + FSPARAM0 = 1.0f / FSPARAM1; + break; + + case MAKE_OPCODE_SHORT(OP_FRSQRT, 4, 0): // FSRSQRT dst,src1 + FSPARAM0 = 1.0f / sqrtf(FSPARAM1); + break; + + + // ----------------------- 64-Bit Floating Point Operations ----------------------- + + case MAKE_OPCODE_SHORT(OP_FLOAD, 8, 0): // FDLOAD dst,base,index + FDPARAM0 = inst[1].pdouble[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(OP_FSTORE, 8, 0): // FDSTORE dst,base,index + inst[0].pdouble[PARAM1] = FDPARAM2; + break; + + case MAKE_OPCODE_SHORT(OP_FREAD, 8, 0): // FDREAD dst,src1,space + DPARAM0 = m_space[PARAM2]->read_qword(PARAM1); + break; + + case MAKE_OPCODE_SHORT(OP_FWRITE, 8, 0): // FDWRITE dst,src1,space + m_space[PARAM2]->write_qword(PARAM0, DPARAM1); + break; + + case MAKE_OPCODE_SHORT(OP_FMOV, 8, 1): // FDMOV dst,src[,c] + if (OPCODE_FAIL_CONDITION(opcode, flags)) + break; + // fall through... + + case MAKE_OPCODE_SHORT(OP_FMOV, 8, 0): + FDPARAM0 = FDPARAM1; + break; + + case MAKE_OPCODE_SHORT(OP_FTOI4T, 8, 0): // FDTOI4T dst,src1 + if (FDPARAM1 >= 0) + *inst[0].pint32 = floor(FDPARAM1); + else + *inst[0].pint32 = ceil(FDPARAM1); + break; + + case MAKE_OPCODE_SHORT(OP_FTOI4R, 8, 0): // FDTOI4R dst,src1 + if (FDPARAM1 >= 0) + *inst[0].pint32 = floor(FDPARAM1 + 0.5); + else + *inst[0].pint32 = ceil(FDPARAM1 - 0.5); + break; + + case MAKE_OPCODE_SHORT(OP_FTOI4F, 8, 0): // FDTOI4F dst,src1 + *inst[0].pint32 = floor(FDPARAM1); + break; + + case MAKE_OPCODE_SHORT(OP_FTOI4C, 8, 0): // FDTOI4C dst,src1 + *inst[0].pint32 = ceil(FDPARAM1); + break; + + case MAKE_OPCODE_SHORT(OP_FTOI4, 8, 0): // FDTOI4 dst,src1 + *inst[0].pint32 = FDPARAM1; + break; + + case MAKE_OPCODE_SHORT(OP_FTOI8T, 8, 0): // FDTOI8T dst,src1 + if (FDPARAM1 >= 0) + *inst[0].pint64 = floor(FDPARAM1); + else + *inst[0].pint64 = ceil(FDPARAM1); + break; + + case MAKE_OPCODE_SHORT(OP_FTOI8R, 8, 0): // FDTOI8R dst,src1 + if (FDPARAM1 >= 0) + *inst[0].pint64 = floor(FDPARAM1 + 0.5); + else + *inst[0].pint64 = ceil(FDPARAM1 - 0.5); + break; + + case MAKE_OPCODE_SHORT(OP_FTOI8F, 8, 0): // FDTOI8F dst,src1 + *inst[0].pint64 = floor(FDPARAM1); + break; + + case MAKE_OPCODE_SHORT(OP_FTOI8C, 8, 0): // FDTOI8C dst,src1 + *inst[0].pint64 = ceil(FDPARAM1); + break; + + case MAKE_OPCODE_SHORT(OP_FTOI8, 8, 0): // FDTOI8 dst,src1 + *inst[0].pint64 = FDPARAM1; + break; + + case MAKE_OPCODE_SHORT(OP_FFRI4, 8, 0): // FDFRI4 dst,src1 + FDPARAM0 = *inst[1].pint32; + break; + + case MAKE_OPCODE_SHORT(OP_FFRI8, 8, 0): // FDFRI8 dst,src1 + FDPARAM0 = *inst[1].pint64; + break; + + case MAKE_OPCODE_SHORT(OP_FFRFS, 8, 0): // FDFRFS dst,src1 + FDPARAM0 = FSPARAM1; + break; + + case MAKE_OPCODE_SHORT(OP_FRNDS, 8, 0): // FDRNDS dst,src1 + FDPARAM0 = (float)FDPARAM1; + break; + + case MAKE_OPCODE_SHORT(OP_FADD, 8, 0): // FDADD dst,src1,src2 + FDPARAM0 = FDPARAM1 + FDPARAM2; + break; + + case MAKE_OPCODE_SHORT(OP_FSUB, 8, 0): // FDSUB dst,src1,src2 + FDPARAM0 = FDPARAM1 - FDPARAM2; + break; + + case MAKE_OPCODE_SHORT(OP_FCMP, 8, 1): // FDCMP src1,src2 + if (isnan(FDPARAM0) || isnan(FDPARAM1)) + flags = FLAG_U; + else + flags = (FDPARAM0 < FDPARAM1) | ((FDPARAM0 == FDPARAM1) << 2); + break; + + case MAKE_OPCODE_SHORT(OP_FMUL, 8, 0): // FDMUL dst,src1,src2 + FDPARAM0 = FDPARAM1 * FDPARAM2; + break; + + case MAKE_OPCODE_SHORT(OP_FDIV, 8, 0): // FDDIV dst,src1,src2 + FDPARAM0 = FDPARAM1 / FDPARAM2; + break; + + case MAKE_OPCODE_SHORT(OP_FNEG, 8, 0): // FDNEG dst,src1 + FDPARAM0 = -FDPARAM1; + break; + + case MAKE_OPCODE_SHORT(OP_FABS, 8, 0): // FDABS dst,src1 + FDPARAM0 = fabs(FDPARAM1); + break; + + case MAKE_OPCODE_SHORT(OP_FSQRT, 8, 0): // FDSQRT dst,src1 + FDPARAM0 = sqrt(FDPARAM1); + break; + + case MAKE_OPCODE_SHORT(OP_FRECIP, 8, 0): // FDRECIP dst,src1 + FDPARAM0 = 1.0 / FDPARAM1; + break; + + case MAKE_OPCODE_SHORT(OP_FRSQRT, 8, 0): // FDRSQRT dst,src1 + FDPARAM0 = 1.0 / sqrt(FDPARAM1); + break; + + default: + fatalerror("Unexpected opcode!\n"); + } + + // advance past the parameters and immediates + inst += OPCODE_GET_PWORDS(opcode); + } + + // never executed + //return 0; +} + + +//------------------------------------------------- +// output_parameter - output a parameter +//------------------------------------------------- + +void drcbe_c::output_parameter(drcbec_instruction **dstptr, void **immedptr, int size, const parameter ¶m) +{ + drcbec_instruction *dst = *dstptr; + void *immed = *immedptr; + parameter temp_param; + + switch (param.type()) + { + // immediates store a pointer to the immediate data, which is stored at the end of the instruction + case parameter::PTYPE_IMMEDIATE: + if (param.immediate() == 0) + (dst++)->v = &s_immediate_zero; + else + { + (dst++)->v = immed; + if (size == 4) + *(UINT32 *)immed = (UINT32)param.immediate(); + else + *(UINT64 *)immed = (UINT64)param.immediate(); + immed = (UINT8 *)immed + size; + } + break; + + // int registers point to the appropriate part of the integer register state + case parameter::PTYPE_INT_REGISTER: + if (size == 4) + (dst++)->puint32 = &m_state.r[param.ireg() - REG_I0].w.l; + else + (dst++)->puint64 = &m_state.r[param.ireg() - REG_I0].d; + break; + + // float registers point to the appropriate part of the floating point register state + case parameter::PTYPE_FLOAT_REGISTER: + if (size == 4) + (dst++)->pfloat = &m_state.f[param.freg() - REG_F0].s.l; + else + (dst++)->pdouble = &m_state.f[param.freg() - REG_F0].d; + break; + + // convert mapvars to immediates + case parameter::PTYPE_MAPVAR: + temp_param = m_map.get_last_value(param.mapvar()); + return output_parameter(dstptr, immedptr, size, temp_param); + + // memory just points to the memory + case parameter::PTYPE_MEMORY: + (dst++)->v = param.memory(); + break; + + // ignore these parameters: they are directly encoded in the opcode + case parameter::PTYPE_SIZE: + case parameter::PTYPE_SIZE_SCALE: + case parameter::PTYPE_ROUNDING: + case parameter::PTYPE_STRING: + return output_parameter(dstptr, immedptr, size, 0); + + // space/size parameters; sizes are built into our opcodes, but space needs to be encoded + case parameter::PTYPE_SIZE_SPACE: + return output_parameter(dstptr, immedptr, size, param.space()); + + // code handle just points to the handle + case parameter::PTYPE_CODE_HANDLE: + (dst++)->handle = ¶m.handle(); + break; + + // code label just contains the label value + case parameter::PTYPE_CODE_LABEL: + return output_parameter(dstptr, immedptr, size, UINT32(param.label())); + + // c_function just points to the C function + case parameter::PTYPE_C_FUNCTION: + (dst++)->cfunc = param.cfunc(); + break; + + default: + fatalerror("Unexpected param->type\n"); + } + + *dstptr = dst; + *immedptr = immed; +} + + +//------------------------------------------------- +// fixup_label - callback to fixup forward- +// referenced labels +//------------------------------------------------- + +void drcbe_c::fixup_label(void *parameter, drccodeptr labelcodeptr) +{ + drcbec_instruction *dst = (drcbec_instruction *)parameter; + dst->inst = (drcbec_instruction *)labelcodeptr; +} + + +//------------------------------------------------- +// dmulu - perform a double-wide unsigned multiply +//------------------------------------------------- + +int drcbe_c::dmulu(UINT64 &dstlo, UINT64 &dsthi, UINT64 src1, UINT64 src2, int flags) +{ + // shortcut if we don't care about the high bits or the flags + if (&dstlo == &dsthi && flags == 0) + { + dstlo = src1 * src2; + return 0; + } + + // fetch source values + UINT64 a = src1; + UINT64 b = src2; + if (a == 0 || b == 0) + { + dsthi = dstlo = 0; + return FLAG_Z; + } + + // compute high and low parts first + UINT64 lo = (UINT64)(UINT32)(a >> 0) * (UINT64)(UINT32)(b >> 0); + UINT64 hi = (UINT64)(UINT32)(a >> 32) * (UINT64)(UINT32)(b >> 32); + + // compute middle parts + UINT64 prevlo = lo; + UINT64 temp = (UINT64)(UINT32)(a >> 32) * (UINT64)(UINT32)(b >> 0); + lo += temp << 32; + hi += (temp >> 32) + (lo < prevlo); + + prevlo = lo; + temp = (UINT64)(UINT32)(a >> 0) * (UINT64)(UINT32)(b >> 32); + lo += temp << 32; + hi += (temp >> 32) + (lo < prevlo); + + // store the results + dsthi = hi; + dstlo = lo; + return ((hi >> 60) & FLAG_S) | ((dsthi != 0) << 1); +} + + +//------------------------------------------------- +// dmuls - perform a double-wide signed multiply +//------------------------------------------------- + +int drcbe_c::dmuls(UINT64 &dstlo, UINT64 &dsthi, INT64 src1, INT64 src2, int flags) +{ + // shortcut if we don't care about the high bits or the flags + if (&dstlo == &dsthi && flags == 0) + { + dstlo = src1 * src2; + return 0; + } + + // fetch absolute source values + UINT64 a = src1; if ((INT64)a < 0) a = -a; + UINT64 b = src2; if ((INT64)b < 0) b = -b; + if (a == 0 || b == 0) + { + dsthi = dstlo = 0; + return FLAG_Z; + } + + // compute high and low parts first + UINT64 lo = (UINT64)(UINT32)(a >> 0) * (UINT64)(UINT32)(b >> 0); + UINT64 hi = (UINT64)(UINT32)(a >> 32) * (UINT64)(UINT32)(b >> 32); + + // compute middle parts + UINT64 prevlo = lo; + UINT64 temp = (UINT64)(UINT32)(a >> 32) * (UINT64)(UINT32)(b >> 0); + lo += temp << 32; + hi += (temp >> 32) + (lo < prevlo); + + prevlo = lo; + temp = (UINT64)(UINT32)(a >> 0) * (UINT64)(UINT32)(b >> 32); + lo += temp << 32; + hi += (temp >> 32) + (lo < prevlo); + + // adjust for signage + if ((INT64)(src1 ^ src2) < 0) + { + hi = ~hi + (lo == 0); + lo = ~lo + 1; + } + + // store the results + dsthi = hi; + dstlo = lo; + return ((hi >> 60) & FLAG_S) | ((dsthi != ((INT64)lo >> 63)) << 1); +} diff --git a/src/devices/cpu/drcbec.h b/src/devices/cpu/drcbec.h new file mode 100644 index 00000000000..720d70f9a87 --- /dev/null +++ b/src/devices/cpu/drcbec.h @@ -0,0 +1,59 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + drcbec.h + + Interpreted C core back-end for the universal machine language. + +***************************************************************************/ + +#pragma once + +#ifndef __DRCBEC_H__ +#define __DRCBEC_H__ + +#include "drcuml.h" +#include "drcbeut.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +union drcbec_instruction; + +class drcbe_c : public drcbe_interface +{ +public: + // construction/destruction + drcbe_c(drcuml_state &drcuml, device_t &device, drc_cache &cache, UINT32 flags, int modes, int addrbits, int ignorebits); + virtual ~drcbe_c(); + + // required overrides + virtual void reset(); + virtual int execute(uml::code_handle &entry); + virtual void generate(drcuml_block &block, const uml::instruction *instlist, UINT32 numinst); + virtual bool hash_exists(UINT32 mode, UINT32 pc); + virtual void get_info(drcbe_info &info); + +private: + // helpers + void output_parameter(drcbec_instruction **dstptr, void **immedptr, int size, const uml::parameter ¶m); + void fixup_label(void *parameter, drccodeptr labelcodeptr); + int dmulu(UINT64 &dstlo, UINT64 &dsthi, UINT64 src1, UINT64 src2, int flags); + int dmuls(UINT64 &dstlo, UINT64 &dsthi, INT64 src1, INT64 src2, int flags); + + // internal state + drc_hash_table m_hash; // hash table state + drc_map_variables m_map; // code map + drc_label_list m_labels; // label list + drc_label_fixup_delegate m_fixup_delegate; // precomputed delegate + + static const UINT32 s_condition_map[32]; + static UINT64 s_immediate_zero; +}; + + +#endif /* __DRCBEC_H__ */ diff --git a/src/devices/cpu/drcbeut.c b/src/devices/cpu/drcbeut.c new file mode 100644 index 00000000000..4df863c8fb5 --- /dev/null +++ b/src/devices/cpu/drcbeut.c @@ -0,0 +1,577 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + drcbeut.c + + Utility functions for dynamic recompiling backends. + +***************************************************************************/ + +#include "emu.h" +#include "drcbeut.h" + +using namespace uml; + + +//************************************************************************** +// DEBUGGING +//************************************************************************** + +#define LOG_RECOVER (0) + + + +//************************************************************************** +// DRC HASH TABLE +//************************************************************************** + +//------------------------------------------------- +// drc_hash_table - constructor +//------------------------------------------------- + +drc_hash_table::drc_hash_table(drc_cache &cache, UINT32 modes, UINT8 addrbits, UINT8 ignorebits) + : m_cache(cache), + m_modes(modes), + m_nocodeptr(NULL), + m_l1bits((addrbits - ignorebits) / 2), + m_l2bits((addrbits - ignorebits) - m_l1bits), + m_l1shift(ignorebits + m_l2bits), + m_l2shift(ignorebits), + m_l1mask((1 << m_l1bits) - 1), + m_l2mask((1 << m_l2bits) - 1), + m_base(reinterpret_cast(cache.alloc(modes * sizeof(**m_base)))), + m_emptyl1(NULL), + m_emptyl2(NULL) +{ + reset(); +} + + +//------------------------------------------------- +// reset - flush existing hash tables and create +// new ones +//------------------------------------------------- + +bool drc_hash_table::reset() +{ + // allocate an empty l2 hash table + m_emptyl2 = (drccodeptr *)m_cache.alloc_temporary(sizeof(drccodeptr) << m_l2bits); + if (m_emptyl2 == NULL) + return false; + + // populate it with pointers to the recompile_exit code + for (int entry = 0; entry < (1 << m_l2bits); entry++) + m_emptyl2[entry] = m_nocodeptr; + + // allocate an empty l1 hash table + m_emptyl1 = (drccodeptr **)m_cache.alloc_temporary(sizeof(drccodeptr *) << m_l1bits); + if (m_emptyl1 == NULL) + return false; + + // populate it with pointers to the empty l2 table + for (int entry = 0; entry < (1 << m_l1bits); entry++) + m_emptyl1[entry] = m_emptyl2; + + // reset the hash tables + for (int modenum = 0; modenum < m_modes; modenum++) + m_base[modenum] = m_emptyl1; + + return true; +} + + +//------------------------------------------------- +// block_begin - note the beginning of a block +//------------------------------------------------- + +void drc_hash_table::block_begin(drcuml_block &block, const uml::instruction *instlist, UINT32 numinst) +{ + // before generating code, pre-allocate any hash entries; we do this by setting dummy hash values + for (int inum = 0; inum < numinst; inum++) + { + const uml::instruction &inst = instlist[inum]; + + // if the opcode is a hash, verify that it makes sense and then set a NULL entry + if (inst.opcode() == OP_HASH) + { + assert(inst.numparams() == 2); + + // if we fail to allocate, we must abort the block + if (!set_codeptr(inst.param(0).immediate(), inst.param(1).immediate(), NULL)) + block.abort(); + } + + // if the opcode is a hashjmp to a fixed location, make sure we preallocate the tables + if (inst.opcode() == OP_HASHJMP && inst.param(0).is_immediate() && inst.param(1).is_immediate()) + { + // if we fail to allocate, we must abort the block + drccodeptr code = get_codeptr(inst.param(0).immediate(), inst.param(1).immediate()); + if (!set_codeptr(inst.param(0).immediate(), inst.param(1).immediate(), code)) + block.abort(); + } + } +} + + +//------------------------------------------------- +// block_end - note the end of a block +//------------------------------------------------- + +void drc_hash_table::block_end(drcuml_block &block) +{ + // nothing to do here, yet +} + + +//------------------------------------------------- +// set_default_codeptr - change the default +// codeptr +//------------------------------------------------- + +void drc_hash_table::set_default_codeptr(drccodeptr nocodeptr) +{ + // nothing to do if the same + drccodeptr old = m_nocodeptr; + if (old == nocodeptr) + return; + m_nocodeptr = nocodeptr; + + // update the empty L2 table first + for (int l2entry = 0; l2entry < (1 << m_l2bits); l2entry++) + m_emptyl2[l2entry] = nocodeptr; + + // now scan all existing hashtables for entries + for (int modenum = 0; modenum < m_modes; modenum++) + if (m_base[modenum] != m_emptyl1) + for (int l1entry = 0; l1entry < (1 << m_l1bits); l1entry++) + if (m_base[modenum][l1entry] != m_emptyl2) + for (int l2entry = 0; l2entry < (1 << m_l2bits); l2entry++) + if (m_base[modenum][l1entry][l2entry] == old) + m_base[modenum][l1entry][l2entry] = nocodeptr; +} + + +//------------------------------------------------- +// set_codeptr - set the codeptr for the given +// mode/pc +//------------------------------------------------- + +bool drc_hash_table::set_codeptr(UINT32 mode, UINT32 pc, drccodeptr code) +{ + // copy-on-write for the l1 hash table + assert(mode < m_modes); + if (m_base[mode] == m_emptyl1) + { + drccodeptr **newtable = (drccodeptr **)m_cache.alloc_temporary(sizeof(drccodeptr *) << m_l1bits); + if (newtable == NULL) + return false; + memcpy(newtable, m_emptyl1, sizeof(drccodeptr *) << m_l1bits); + m_base[mode] = newtable; + } + + // copy-on-write for the l2 hash table + UINT32 l1 = (pc >> m_l1shift) & m_l1mask; + if (m_base[mode][l1] == m_emptyl2) + { + drccodeptr *newtable = (drccodeptr *)m_cache.alloc_temporary(sizeof(drccodeptr) << m_l2bits); + if (newtable == NULL) + return false; + memcpy(newtable, m_emptyl2, sizeof(drccodeptr) << m_l2bits); + m_base[mode][l1] = newtable; + } + + // set the new entry + UINT32 l2 = (pc >> m_l2shift) & m_l2mask; + m_base[mode][l1][l2] = code; + return true; +} + + + +//************************************************************************** +// DRC MAP VARIABLES +//************************************************************************** + +//------------------------------------------------- +// drc_map_variables - constructor +//------------------------------------------------- + +drc_map_variables::drc_map_variables(drc_cache &cache, UINT64 uniquevalue) + : m_cache(cache), + m_uniquevalue(uniquevalue) +{ + memset(m_mapvalue, 0, sizeof(m_mapvalue)); +} + + +//------------------------------------------------- +// ~drc_map_variables - destructor +//------------------------------------------------- + +drc_map_variables::~drc_map_variables() +{ + // must detach all items from the entry list so that the list object + // doesn't try to free them on exit + m_entry_list.detach_all(); +} + + +//------------------------------------------------- +// block_begin - note the beginning of a block +//------------------------------------------------- + +void drc_map_variables::block_begin(drcuml_block &block) +{ + // release any remaining live entries + map_entry *entry; + while ((entry = m_entry_list.detach_head()) != NULL) + m_cache.dealloc(entry, sizeof(*entry)); + + // reset the variable values + memset(m_mapvalue, 0, sizeof(m_mapvalue)); +} + + +//------------------------------------------------- +// block_end - note the end of a block +//------------------------------------------------- + +void drc_map_variables::block_end(drcuml_block &block) +{ + // only process if we have data + if (m_entry_list.first() == NULL) + return; + + // begin "code generation" aligned to an 8-byte boundary + drccodeptr *top = m_cache.begin_codegen(sizeof(UINT64) + sizeof(UINT32) + 2 * sizeof(UINT32) * m_entry_list.count()); + if (top == NULL) + block.abort(); + UINT32 *dest = (UINT32 *)(((FPTR)*top + 7) & ~7); + + // store the cookie first + *(UINT64 *)dest = m_uniquevalue; + dest += 2; + + // get the pointer to the first item and store an initial backwards offset + drccodeptr lastptr = m_entry_list.first()->m_codeptr; + *dest = (drccodeptr)dest - lastptr; + dest++; + + // now iterate over entries and store them + UINT32 curvalue[MAPVAR_COUNT] = { 0 }; + bool changed[MAPVAR_COUNT] = { false }; + for (map_entry *entry = m_entry_list.first(); entry != NULL; entry = entry->next()) + { + // update the current value of the variable and detect changes + if (curvalue[entry->m_mapvar] != entry->m_newval) + { + curvalue[entry->m_mapvar] = entry->m_newval; + changed[entry->m_mapvar] = true; + } + + // if the next code pointer is different, or if we're at the end, flush changes + if (entry->next() == NULL || entry->next()->m_codeptr != entry->m_codeptr) + { + // build a mask of changed variables + int numchanged = 0; + UINT32 varmask = 0; + for (int varnum = 0; varnum < ARRAY_LENGTH(changed); varnum++) + if (changed[varnum]) + { + changed[varnum] = false; + varmask |= 1 << varnum; + numchanged++; + } + + // if nothing really changed, skip it + if (numchanged == 0) + continue; + + // first word is a code delta plus mask of changed variables + UINT32 codedelta = entry->m_codeptr - lastptr; + while (codedelta > 0xffff) + { + *dest++ = 0xffff << 16; + codedelta -= 0xffff; + } + *dest++ = (codedelta << 16) | (varmask << 4) | numchanged; + + // now output updated variable values + for (int varnum = 0; varnum < ARRAY_LENGTH(changed); varnum++) + if ((varmask >> varnum) & 1) + *dest++ = curvalue[varnum]; + + // remember our lastptr + lastptr = entry->m_codeptr; + } + } + + // add a terminator + *dest++ = 0; + + // complete codegen + *top = (drccodeptr)dest; + m_cache.end_codegen(); +} + + +//------------------------------------------------- +// set_value - set a map value for the given +// code pointer +//------------------------------------------------- + +void drc_map_variables::set_value(drccodeptr codebase, UINT32 mapvar, UINT32 newvalue) +{ + assert(mapvar >= MAPVAR_M0 && mapvar < MAPVAR_END); + + // if this value isn't different, skip it + if (m_mapvalue[mapvar - MAPVAR_M0] == newvalue) + return; + + // allocate a new entry and fill it in + map_entry *entry = (map_entry *)m_cache.alloc(sizeof(*entry)); + entry->m_next = NULL; + entry->m_codeptr = codebase; + entry->m_mapvar = mapvar - MAPVAR_M0; + entry->m_newval = newvalue; + + // hook us into the end of the list + m_entry_list.append(*entry); + + // update our state in the table as well + m_mapvalue[mapvar - MAPVAR_M0] = newvalue; +} + + +//------------------------------------------------- +// get_value - return a map value for the given +// code pointer +//------------------------------------------------- + +UINT32 drc_map_variables::get_value(drccodeptr codebase, UINT32 mapvar) const +{ + assert(mapvar >= MAPVAR_M0 && mapvar < MAPVAR_END); + mapvar -= MAPVAR_M0; + + // get an aligned pointer to start scanning + UINT64 *curscan = (UINT64 *)(((FPTR)codebase | 7) + 1); + UINT64 *endscan = (UINT64 *)m_cache.top(); + + // look for the signature + while (curscan < endscan && *curscan++ != m_uniquevalue) ; + if (curscan >= endscan) + return 0; + + // switch to 32-bit pointers for processing the rest + UINT32 *data = (UINT32 *)curscan; + + // first get the 32-bit starting offset to the code + drccodeptr curcode = (drccodeptr)data - *data; + data++; + + // now loop until we advance past our target + UINT32 varmask = 0x10 << mapvar; + UINT32 result = 0; + while (true) + { + // a 0 is a terminator + UINT32 controlword = *data++; + if (controlword == 0) + break; + + // update the codeptr; if this puts us past the end, we're done + curcode += (controlword >> 16) & 0xffff; + if (curcode > codebase) + break; + + // if our mapvar has changed, process this word + if ((controlword & varmask) != 0) + { + // count how many words precede the one we care about + int dataoffs = 0; + for (UINT32 skipmask = (controlword & (varmask - 1)) >> 4; skipmask != 0; skipmask = skipmask & (skipmask - 1)) + dataoffs++; + + // fetch the one we want + result = data[dataoffs]; + } + + // low 4 bits contain the total number of words of data + data += controlword & 0x0f; + } + if (LOG_RECOVER) + printf("recover %d @ %p = %08X\n", mapvar, codebase, result); + return result; +} + +UINT32 drc_map_variables::static_get_value(drc_map_variables &map, drccodeptr codebase, UINT32 mapvar) +{ + return map.get_value(codebase, mapvar); +} + + + +//------------------------------------------------- +// get_last_value - return the most recently set +// map value +//------------------------------------------------- + +UINT32 drc_map_variables::get_last_value(UINT32 mapvar) +{ + assert(mapvar >= MAPVAR_M0 && mapvar < MAPVAR_END); + return m_mapvalue[mapvar - MAPVAR_M0]; +} + + + +//************************************************************************** +// DRC LABEL LIST +//************************************************************************** + +//------------------------------------------------- +// drc_label_list - constructor +//------------------------------------------------- + +drc_label_list::drc_label_list(drc_cache &cache) + : m_cache(cache), + m_oob_callback_delegate(FUNC(drc_label_list::oob_callback), this) +{ +} + + +//------------------------------------------------- +// ~drc_label_list - destructor +//------------------------------------------------- + +drc_label_list::~drc_label_list() +{ + // must detach all items from the entry list so that the list object + // doesn't try to free them on exit + m_list.detach_all(); +} + + +//------------------------------------------------- +// block_begin - note the beginning of a block +//------------------------------------------------- + +void drc_label_list::block_begin(drcuml_block &block) +{ + // make sure the label list is clear, but don't fatalerror + reset(false); +} + + +//------------------------------------------------- +// block_end - note the end of a block +//------------------------------------------------- + +void drc_label_list::block_end(drcuml_block &block) +{ + // can't free until the cache is clean of our OOB requests + assert(!m_cache.generating_code()); + + // free all of the pending fixup requests + label_fixup *fixup; + while ((fixup = m_fixup_list.detach_head()) != NULL) + m_cache.dealloc(fixup, sizeof(*fixup)); + + // make sure the label list is clear, and fatalerror if we missed anything + reset(true); +} + + +//------------------------------------------------- +// get_codeptr - find or allocate a new label; +// returns NULL and requests an OOB callback if +// undefined +//------------------------------------------------- + +drccodeptr drc_label_list::get_codeptr(uml::code_label label, drc_label_fixup_delegate callback, void *param) +{ + label_entry *curlabel = find_or_allocate(label); + + // if no code pointer, request an OOB callback + if (curlabel->m_codeptr == NULL && !callback.isnull()) + { + label_fixup *fixup = reinterpret_cast(m_cache.alloc(sizeof(*fixup))); + fixup->m_callback = callback; + fixup->m_label = curlabel; + m_fixup_list.append(*fixup); + m_cache.request_oob_codegen(m_oob_callback_delegate, fixup, param); + } + + return curlabel->m_codeptr; +} + + +//------------------------------------------------- +// set_codeptr - set the pointer to a new label +//------------------------------------------------- + +void drc_label_list::set_codeptr(uml::code_label label, drccodeptr codeptr) +{ + // set the code pointer + label_entry *curlabel = find_or_allocate(label); + assert(curlabel->m_codeptr == NULL); + curlabel->m_codeptr = codeptr; +} + + +//------------------------------------------------- +// reset - reset a label list (add all entries to +// the free list) +//------------------------------------------------- + +void drc_label_list::reset(bool fatal_on_leftovers) +{ + // loop until out of labels + label_entry *curlabel; + while ((curlabel = m_list.detach_head()) != NULL) + { + // fatal if we were a leftover + if (fatal_on_leftovers && curlabel->m_codeptr == NULL) + fatalerror("Label %08X never defined!\n", curlabel->m_label.label()); + + // free the label + m_cache.dealloc(curlabel, sizeof(*curlabel)); + } +} + + +//------------------------------------------------- +// find_or_allocate - look up a label and +// allocate a new one if not found +//------------------------------------------------- + +drc_label_list::label_entry *drc_label_list::find_or_allocate(uml::code_label label) +{ + // find the label, or else allocate a new one + label_entry *curlabel; + for (curlabel = m_list.first(); curlabel != NULL; curlabel = curlabel->next()) + if (curlabel->m_label == label) + break; + + // if none found, allocate + if (curlabel == NULL) + { + curlabel = (label_entry *)m_cache.alloc(sizeof(*curlabel)); + curlabel->m_label = label; + curlabel->m_codeptr = NULL; + m_list.append(*curlabel); + } + return curlabel; +} + + +//------------------------------------------------- +// oob_callback - out-of-band codegen callback +// for labels +//------------------------------------------------- + +void drc_label_list::oob_callback(drccodeptr *codeptr, void *param1, void *param2) +{ + label_fixup *fixup = reinterpret_cast(param1); + fixup->m_callback(param2, fixup->m_label->m_codeptr); +} diff --git a/src/devices/cpu/drcbeut.h b/src/devices/cpu/drcbeut.h new file mode 100644 index 00000000000..8987edb49c2 --- /dev/null +++ b/src/devices/cpu/drcbeut.h @@ -0,0 +1,166 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + drcbeut.h + + Utility functions for dynamic recompiling backends. + +***************************************************************************/ + +#pragma once + +#ifndef __DRCBEUT_H__ +#define __DRCBEUT_H__ + +#include "drcuml.h" + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> drc_hash_table + +// common hash table management +class drc_hash_table +{ +public: + // construction/destruction + drc_hash_table(drc_cache &cache, UINT32 modes, UINT8 addrbits, UINT8 ignorebits); + + // getters + drccodeptr ***base() const { return m_base; } + UINT8 l1bits() const { return m_l1bits; } + UINT8 l2bits() const { return m_l2bits; } + UINT8 l1shift() const { return m_l1shift; } + UINT8 l2shift() const { return m_l2shift; } + offs_t l1mask() const { return m_l1mask; } + offs_t l2mask() const { return m_l2mask; } + bool is_mode_populated(UINT32 mode) const { return m_base[mode] != m_emptyl1; } + + // set up and configuration + bool reset(); + void set_default_codeptr(drccodeptr code); + + // block begin/end + void block_begin(drcuml_block &block, const uml::instruction *instlist, UINT32 numinst); + void block_end(drcuml_block &block); + + // code pointer access + bool set_codeptr(UINT32 mode, UINT32 pc, drccodeptr code); + drccodeptr get_codeptr(UINT32 mode, UINT32 pc) { assert(mode < m_modes); return m_base[mode][(pc >> m_l1shift) & m_l1mask][(pc >> m_l2shift) & m_l2mask]; } + bool code_exists(UINT32 mode, UINT32 pc) { return get_codeptr(mode, pc) != m_nocodeptr; } + +private: + // internal state + drc_cache & m_cache; // cache where allocations come from + UINT32 m_modes; // number of modes supported + + drccodeptr m_nocodeptr; // pointer to code which will handle missing entries + + UINT8 m_l1bits; // bits worth of entries in l1 hash tables + UINT8 m_l2bits; // bits worth of entries in l2 hash tables + UINT8 m_l1shift; // shift to apply to the PC to get the l1 hash entry + UINT8 m_l2shift; // shift to apply to the PC to get the l2 hash entry + offs_t m_l1mask; // mask to apply after shifting + offs_t m_l2mask; // mask to apply after shifting + + drccodeptr *** m_base; // pointer to the l1 table for each mode + drccodeptr ** m_emptyl1; // pointer to empty l1 hash table + drccodeptr * m_emptyl2; // pointer to empty l2 hash table +}; + + +// ======================> drc_map_variables + +// common map variable management +class drc_map_variables +{ +public: + // construction/destruction + drc_map_variables(drc_cache &cache, UINT64 uniquevalue); + ~drc_map_variables(); + + // block begin/end + void block_begin(drcuml_block &block); + void block_end(drcuml_block &block); + + // get/set values + void set_value(drccodeptr codebase, UINT32 mapvar, UINT32 newvalue); + UINT32 get_value(drccodeptr codebase, UINT32 mapvar) const; + UINT32 get_last_value(UINT32 mapvar); + + // static accessors to be called directly by generated code + static UINT32 static_get_value(drc_map_variables &map, drccodeptr codebase, UINT32 mapvar); + +private: + // internal state + drc_cache & m_cache; // pointer to the cache + UINT64 m_uniquevalue; // unique value used to find the table + UINT32 m_mapvalue[uml::MAPVAR_END - uml::MAPVAR_M0]; // array of current values + + // list of entries + struct map_entry + { + map_entry *next() const { return m_next; } + map_entry * m_next; // pointer to next map entry + drccodeptr m_codeptr; // pointer to the relevant code + UINT32 m_mapvar; // map variable id + UINT32 m_newval; // value of the variable starting at codeptr + }; + simple_list m_entry_list; // list of entries +}; + + +// ======================> drc_label_list + +typedef delegate drc_label_fixup_delegate; + +// structure holding a live list of labels +class drc_label_list +{ +public: + // construction/destruction + drc_label_list(drc_cache &cache); + ~drc_label_list(); + + // block begin/end + void block_begin(drcuml_block &block); + void block_end(drcuml_block &block); + + // get/set values + drccodeptr get_codeptr(uml::code_label label, drc_label_fixup_delegate fixup, void *param); + void set_codeptr(uml::code_label label, drccodeptr codeptr); + +private: + struct label_entry + { + label_entry *next() const { return m_next; } + label_entry * m_next; // pointer to next label + uml::code_label m_label; // the label specified + drccodeptr m_codeptr; // pointer to the relevant code + }; + + struct label_fixup + { + label_fixup *next() const { return m_next; } + label_fixup * m_next; // pointer to the next oob + label_entry * m_label; // the label in question + drc_label_fixup_delegate m_callback; // callback + }; + + // internal helpers + void reset(bool fatal_on_leftovers); + label_entry *find_or_allocate(uml::code_label label); + void oob_callback(drccodeptr *codeptr, void *param1, void *param2); + + // internal state + drc_cache & m_cache; // pointer to the cache + simple_list m_list; // head of the live list + simple_list m_fixup_list; // list of pending oob fixups + drc_oob_delegate m_oob_callback_delegate; // pre-computed delegate +}; + + +#endif /* __DRCBEUT_H__ */ diff --git a/src/devices/cpu/drcbex64.c b/src/devices/cpu/drcbex64.c new file mode 100644 index 00000000000..64f2dd89bf0 --- /dev/null +++ b/src/devices/cpu/drcbex64.c @@ -0,0 +1,6711 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + drcbex64.c + + 64-bit x64 back-end for the universal machine language. + +**************************************************************************** + + Future improvements/changes: + + * Add support for FP registers + + * Optimize to avoid unnecessary reloads + + * Identify common pairs and optimize output + + * Convert SUB a,0,b to NEG + + * Optimize, e.g., and [r5],i0,$FF to use rbx as temporary register + (avoid initial move) if i0 is not needed going forward + +**************************************************************************** + + ------------------------- + ABI/conventions (Windows) + ------------------------- + + Registers: + RAX - volatile, function return value + RBX - non-volatile + RCX - volatile, integer function parameter 1 + RDX - volatile, integer function parameter 2 + RSI - non-volatile + RDI - non-volatile + RBP - non-volatile + R8 - volatile, integer function parameter 3 + R9 - volatile, integer function parameter 4 + R10 - volatile + R11 - volatile, scratch immediate storage + R12 - non-volatile + R13 - non-volatile + R14 - non-volatile + R15 - non-volatile + + XMM0 - volatile, FP function parameter 1 + XMM1 - volatile, FP function parameter 2 + XMM2 - volatile, FP function parameter 3 + XMM3 - volatile, FP function parameter 4 + XMM4 - volatile + XMM5 - volatile + XMM6 - non-volatile + XMM7 - non-volatile + XMM8 - non-volatile + XMM9 - non-volatile + XMM10 - non-volatile + XMM11 - non-volatile + XMM12 - non-volatile + XMM13 - non-volatile + XMM14 - non-volatile + XMM15 - non-volatile + + + ----------------------------- + ABI/conventions (Linux/MacOS) + ----------------------------- + + Registers: + RAX - volatile, function return value + RBX - non-volatile + RCX - volatile, integer function parameter 4 + RDX - volatile, integer function parameter 3 + RSI - volatile, integer function parameter 2 + RDI - volatile, integer function parameter 1 + RBP - non-volatile + R8 - volatile, integer function parameter 5 + R9 - volatile, integer function parameter 6 + R10 - volatile + R11 - volatile, scratch immediate storage + R12 - non-volatile + R13 - non-volatile + R14 - non-volatile + R15 - non-volatile + + XMM0 - volatile, FP function parameter 1 + XMM1 - volatile, FP function parameter 2 + XMM2 - volatile, FP function parameter 3 + XMM3 - volatile, FP function parameter 4 + XMM4 - volatile + XMM5 - volatile + XMM6 - volatile + XMM7 - volatile + XMM8 - volatile + XMM9 - volatile + XMM10 - volatile + XMM11 - volatile + XMM12 - volatile + XMM13 - volatile + XMM14 - volatile + XMM15 - volatile + + + --------------- + Execution model + --------------- + + Registers (Windows): + RAX - scratch register + RBX - maps to I0 + RCX - scratch register + RDX - scratch register + RSI - maps to I1 + RDI - maps to I2 + RBP - pointer to code cache + R8 - scratch register + R9 - scratch register + R10 - scratch register + R11 - scratch register + R12 - maps to I3 + R13 - maps to I4 + R14 - maps to I5 + R15 - maps to I6 + + Registers (Linux/MacOS): + RAX - scratch register + RBX - maps to I0 + RCX - scratch register + RDX - scratch register + RSI - unused + RDI - unused + RBP - pointer to code cache + R8 - scratch register + R9 - scratch register + R10 - scratch register + R11 - scratch register + R12 - maps to I1 + R13 - maps to I2 + R14 - maps to I3 + R15 - maps to I4 + + Entry point: + Assumes 1 parameter passed, which is the codeptr of the code + to execute once the environment is set up. + + Exit point: + Assumes exit value is in RAX. + + Entry stack: + [rsp] - return + + Runtime stack: + [rsp] - r9 home + [rsp+8] - r8 home + [rsp+16] - rdx home + [rsp+24] - rcx home + [rsp+40] - saved r15 + [rsp+48] - saved r14 + [rsp+56] - saved r13 + [rsp+64] - saved r12 + [rsp+72] - saved ebp + [rsp+80] - saved edi + [rsp+88] - saved esi + [rsp+96] - saved ebx + [rsp+104] - ret + +***************************************************************************/ + +#include +#include "emu.h" +#include "debugger.h" +#include "drcuml.h" +#include "drcbex64.h" + +using namespace uml; +using namespace x64emit; + + + +//************************************************************************** +// DEBUGGING +//************************************************************************** + +#define LOG_HASHJMPS (0) + +#define USE_RCPSS_FOR_SINGLES (0) +#define USE_RSQRTSS_FOR_SINGLES (0) +#define USE_RCPSS_FOR_DOUBLES (0) +#define USE_RSQRTSS_FOR_DOUBLES (0) + + + +//************************************************************************** +// CONSTANTS +//************************************************************************** + +const UINT32 PTYPE_M = 1 << parameter::PTYPE_MEMORY; +const UINT32 PTYPE_I = 1 << parameter::PTYPE_IMMEDIATE; +const UINT32 PTYPE_R = 1 << parameter::PTYPE_INT_REGISTER; +const UINT32 PTYPE_F = 1 << parameter::PTYPE_FLOAT_REGISTER; +//const UINT32 PTYPE_MI = PTYPE_M | PTYPE_I; +//const UINT32 PTYPE_RI = PTYPE_R | PTYPE_I; +const UINT32 PTYPE_MR = PTYPE_M | PTYPE_R; +const UINT32 PTYPE_MRI = PTYPE_M | PTYPE_R | PTYPE_I; +const UINT32 PTYPE_MF = PTYPE_M | PTYPE_F; + +#ifdef X64_WINDOWS_ABI + +const int REG_PARAM1 = REG_RCX; +const int REG_PARAM2 = REG_RDX; +const int REG_PARAM3 = REG_R8; +const int REG_PARAM4 = REG_R9; + +#else + +const int REG_PARAM1 = REG_RDI; +const int REG_PARAM2 = REG_RSI; +const int REG_PARAM3 = REG_RDX; +const int REG_PARAM4 = REG_RCX; + +#endif + + + +//************************************************************************** +// MACROS +//************************************************************************** + +#define X86_CONDITION(condition) (condition_map[condition - uml::COND_Z]) +#define X86_NOT_CONDITION(condition) (condition_map[condition - uml::COND_Z] ^ 1) + +inline x86_memref drcbe_x64::MABS(const void *ptr) +{ + return MBD(REG_BP, offset_from_rbp(ptr)); +} + +#define assert_no_condition(inst) assert((inst).condition() == uml::COND_ALWAYS) +#define assert_any_condition(inst) assert((inst).condition() == uml::COND_ALWAYS || ((inst).condition() >= uml::COND_Z && (inst).condition() < uml::COND_MAX)) +#define assert_no_flags(inst) assert((inst).flags() == 0) +#define assert_flags(inst, valid) assert(((inst).flags() & ~(valid)) == 0) + + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +drcbe_x64::opcode_generate_func drcbe_x64::s_opcode_table[OP_MAX]; + +// size-to-mask table +//static const UINT64 size_to_mask[] = { 0, 0xff, 0xffff, 0, 0xffffffff, 0, 0, 0, U64(0xffffffffffffffff) }; + +// register mapping tables +static const UINT8 int_register_map[REG_I_COUNT] = +{ +#ifdef X64_WINDOWS_ABI + REG_RBX, REG_RSI, REG_RDI, REG_R12, REG_R13, REG_R14, REG_R15 +#else + REG_RBX, REG_R12, REG_R13, REG_R14, REG_R15 +#endif +}; + +static UINT8 float_register_map[REG_F_COUNT] = +{ + 0 +}; + +// condition mapping table +static const UINT8 condition_map[uml::COND_MAX - uml::COND_Z] = +{ + x64emit::COND_Z, // COND_Z = 0x80, requires Z + x64emit::COND_NZ, // COND_NZ, requires Z + x64emit::COND_S, // COND_S, requires S + x64emit::COND_NS, // COND_NS, requires S + x64emit::COND_C, // COND_C, requires C + x64emit::COND_NC, // COND_NC, requires C + x64emit::COND_O, // COND_V, requires V + x64emit::COND_NO, // COND_NV, requires V + x64emit::COND_P, // COND_U, requires U + x64emit::COND_NP, // COND_NU, requires U + x64emit::COND_A, // COND_A, requires CZ + x64emit::COND_BE, // COND_BE, requires CZ + x64emit::COND_G, // COND_G, requires SVZ + x64emit::COND_LE, // COND_LE, requires SVZ + x64emit::COND_L, // COND_L, requires SV + x64emit::COND_GE, // COND_GE, requires SV +}; + +#if 0 +// rounding mode mapping table +static const UINT8 fprnd_map[4] = +{ + FPRND_CHOP, // ROUND_TRUNC, truncate + FPRND_NEAR, // ROUND_ROUND, round + FPRND_UP, // ROUND_CEIL, round up + FPRND_DOWN // ROUND_FLOOR round down +}; +#endif + + + +//************************************************************************** +// TABLES +//************************************************************************** + +const drcbe_x64::opcode_table_entry drcbe_x64::s_opcode_table_source[] = +{ + // Compile-time opcodes + { uml::OP_HANDLE, &drcbe_x64::op_handle }, // HANDLE handle + { uml::OP_HASH, &drcbe_x64::op_hash }, // HASH mode,pc + { uml::OP_LABEL, &drcbe_x64::op_label }, // LABEL imm + { uml::OP_COMMENT, &drcbe_x64::op_comment }, // COMMENT string + { uml::OP_MAPVAR, &drcbe_x64::op_mapvar }, // MAPVAR mapvar,value + + // Control Flow Operations + { uml::OP_NOP, &drcbe_x64::op_nop }, // NOP + { uml::OP_DEBUG, &drcbe_x64::op_debug }, // DEBUG pc + { uml::OP_EXIT, &drcbe_x64::op_exit }, // EXIT src1[,c] + { uml::OP_HASHJMP, &drcbe_x64::op_hashjmp }, // HASHJMP mode,pc,handle + { uml::OP_JMP, &drcbe_x64::op_jmp }, // JMP imm[,c] + { uml::OP_EXH, &drcbe_x64::op_exh }, // EXH handle,param[,c] + { uml::OP_CALLH, &drcbe_x64::op_callh }, // CALLH handle[,c] + { uml::OP_RET, &drcbe_x64::op_ret }, // RET [c] + { uml::OP_CALLC, &drcbe_x64::op_callc }, // CALLC func,ptr[,c] + { uml::OP_RECOVER, &drcbe_x64::op_recover }, // RECOVER dst,mapvar + + // Internal Register Operations + { uml::OP_SETFMOD, &drcbe_x64::op_setfmod }, // SETFMOD src + { uml::OP_GETFMOD, &drcbe_x64::op_getfmod }, // GETFMOD dst + { uml::OP_GETEXP, &drcbe_x64::op_getexp }, // GETEXP dst + { uml::OP_GETFLGS, &drcbe_x64::op_getflgs }, // GETFLGS dst[,f] + { uml::OP_SAVE, &drcbe_x64::op_save }, // SAVE dst + { uml::OP_RESTORE, &drcbe_x64::op_restore }, // RESTORE dst + + // Integer Operations + { uml::OP_LOAD, &drcbe_x64::op_load }, // LOAD dst,base,index,size + { uml::OP_LOADS, &drcbe_x64::op_loads }, // LOADS dst,base,index,size + { uml::OP_STORE, &drcbe_x64::op_store }, // STORE base,index,src,size + { uml::OP_READ, &drcbe_x64::op_read }, // READ dst,src1,spacesize + { uml::OP_READM, &drcbe_x64::op_readm }, // READM dst,src1,mask,spacesize + { uml::OP_WRITE, &drcbe_x64::op_write }, // WRITE dst,src1,spacesize + { uml::OP_WRITEM, &drcbe_x64::op_writem }, // WRITEM dst,src1,spacesize + { uml::OP_CARRY, &drcbe_x64::op_carry }, // CARRY src,bitnum + { uml::OP_SET, &drcbe_x64::op_set }, // SET dst,c + { uml::OP_MOV, &drcbe_x64::op_mov }, // MOV dst,src[,c] + { uml::OP_SEXT, &drcbe_x64::op_sext }, // SEXT dst,src + { uml::OP_ROLAND, &drcbe_x64::op_roland }, // ROLAND dst,src1,src2,src3 + { uml::OP_ROLINS, &drcbe_x64::op_rolins }, // ROLINS dst,src1,src2,src3 + { uml::OP_ADD, &drcbe_x64::op_add }, // ADD dst,src1,src2[,f] + { uml::OP_ADDC, &drcbe_x64::op_addc }, // ADDC dst,src1,src2[,f] + { uml::OP_SUB, &drcbe_x64::op_sub }, // SUB dst,src1,src2[,f] + { uml::OP_SUBB, &drcbe_x64::op_subc }, // SUBB dst,src1,src2[,f] + { uml::OP_CMP, &drcbe_x64::op_cmp }, // CMP src1,src2[,f] + { uml::OP_MULU, &drcbe_x64::op_mulu }, // MULU dst,edst,src1,src2[,f] + { uml::OP_MULS, &drcbe_x64::op_muls }, // MULS dst,edst,src1,src2[,f] + { uml::OP_DIVU, &drcbe_x64::op_divu }, // DIVU dst,edst,src1,src2[,f] + { uml::OP_DIVS, &drcbe_x64::op_divs }, // DIVS dst,edst,src1,src2[,f] + { uml::OP_AND, &drcbe_x64::op_and }, // AND dst,src1,src2[,f] + { uml::OP_TEST, &drcbe_x64::op_test }, // TEST src1,src2[,f] + { uml::OP_OR, &drcbe_x64::op_or }, // OR dst,src1,src2[,f] + { uml::OP_XOR, &drcbe_x64::op_xor }, // XOR dst,src1,src2[,f] + { uml::OP_LZCNT, &drcbe_x64::op_lzcnt }, // LZCNT dst,src[,f] + { uml::OP_BSWAP, &drcbe_x64::op_bswap }, // BSWAP dst,src + { uml::OP_SHL, &drcbe_x64::op_shl }, // SHL dst,src,count[,f] + { uml::OP_SHR, &drcbe_x64::op_shr }, // SHR dst,src,count[,f] + { uml::OP_SAR, &drcbe_x64::op_sar }, // SAR dst,src,count[,f] + { uml::OP_ROL, &drcbe_x64::op_rol }, // ROL dst,src,count[,f] + { uml::OP_ROLC, &drcbe_x64::op_rolc }, // ROLC dst,src,count[,f] + { uml::OP_ROR, &drcbe_x64::op_ror }, // ROR dst,src,count[,f] + { uml::OP_RORC, &drcbe_x64::op_rorc }, // RORC dst,src,count[,f] + + // Floating Point Operations + { uml::OP_FLOAD, &drcbe_x64::op_fload }, // FLOAD dst,base,index + { uml::OP_FSTORE, &drcbe_x64::op_fstore }, // FSTORE base,index,src + { uml::OP_FREAD, &drcbe_x64::op_fread }, // FREAD dst,space,src1 + { uml::OP_FWRITE, &drcbe_x64::op_fwrite }, // FWRITE space,dst,src1 + { uml::OP_FMOV, &drcbe_x64::op_fmov }, // FMOV dst,src1[,c] + { uml::OP_FTOINT, &drcbe_x64::op_ftoint }, // FTOINT dst,src1,size,round + { uml::OP_FFRINT, &drcbe_x64::op_ffrint }, // FFRINT dst,src1,size + { uml::OP_FFRFLT, &drcbe_x64::op_ffrflt }, // FFRFLT dst,src1,size + { uml::OP_FRNDS, &drcbe_x64::op_frnds }, // FRNDS dst,src1 + { uml::OP_FADD, &drcbe_x64::op_fadd }, // FADD dst,src1,src2 + { uml::OP_FSUB, &drcbe_x64::op_fsub }, // FSUB dst,src1,src2 + { uml::OP_FCMP, &drcbe_x64::op_fcmp }, // FCMP src1,src2 + { uml::OP_FMUL, &drcbe_x64::op_fmul }, // FMUL dst,src1,src2 + { uml::OP_FDIV, &drcbe_x64::op_fdiv }, // FDIV dst,src1,src2 + { uml::OP_FNEG, &drcbe_x64::op_fneg }, // FNEG dst,src1 + { uml::OP_FABS, &drcbe_x64::op_fabs }, // FABS dst,src1 + { uml::OP_FSQRT, &drcbe_x64::op_fsqrt }, // FSQRT dst,src1 + { uml::OP_FRECIP, &drcbe_x64::op_frecip }, // FRECIP dst,src1 + { uml::OP_FRSQRT, &drcbe_x64::op_frsqrt } // FRSQRT dst,src1 +}; + + + +//************************************************************************** +// INLINE FUNCTIONS +//************************************************************************** + +//------------------------------------------------- +// param_normalize - convert a full parameter +// into a reduced set +//------------------------------------------------- + +drcbe_x64::be_parameter::be_parameter(drcbe_x64 &drcbe, const parameter ¶m, UINT32 allowed) +{ + int regnum; + + switch (param.type()) + { + // immediates pass through + case parameter::PTYPE_IMMEDIATE: + assert(allowed & PTYPE_I); + *this = param.immediate(); + break; + + // memory passes through + case parameter::PTYPE_MEMORY: + assert(allowed & PTYPE_M); + *this = make_memory(param.memory()); + break; + + // if a register maps to a register, keep it as a register; otherwise map it to memory + case parameter::PTYPE_INT_REGISTER: + assert(allowed & PTYPE_R); + assert(allowed & PTYPE_M); + regnum = int_register_map[param.ireg() - REG_I0]; + if (regnum != 0) + *this = make_ireg(regnum); + else + *this = make_memory(&drcbe.m_state.r[param.ireg() - REG_I0]); + break; + + // if a register maps to a register, keep it as a register; otherwise map it to memory + case parameter::PTYPE_FLOAT_REGISTER: + assert(allowed & PTYPE_F); + assert(allowed & PTYPE_M); + regnum = float_register_map[param.freg() - REG_F0]; + if (regnum != 0) + *this = make_freg(regnum); + else + *this = make_memory(&drcbe.m_state.f[param.freg() - REG_F0]); + break; + + // everything else is unexpected + default: + fatalerror("Unexpected parameter type\n"); + } +} + + +//------------------------------------------------- +// select_register - select a register to use, +// avoiding conflicts with the optional +// checkparam +//------------------------------------------------- + +inline int drcbe_x64::be_parameter::select_register(int defreg) const +{ + if (m_type == PTYPE_INT_REGISTER || m_type == PTYPE_FLOAT_REGISTER || m_type == PTYPE_VECTOR_REGISTER) + return m_value; + return defreg; +} + +inline int drcbe_x64::be_parameter::select_register(int defreg, const be_parameter &checkparam) const +{ + if (*this == checkparam) + return defreg; + return select_register(defreg); +} + +inline int drcbe_x64::be_parameter::select_register(int defreg, const be_parameter &checkparam, const be_parameter &checkparam2) const +{ + if (*this == checkparam || *this == checkparam2) + return defreg; + return select_register(defreg); +} + + +//------------------------------------------------- +// select_register - select a register to use, +// avoiding conflicts with the optional +// checkparam +//------------------------------------------------- + +inline void drcbe_x64::normalize_commutative(be_parameter &inner, be_parameter &outer) +{ + // if the inner parameter is a memory operand, push it to the outer + if (inner.is_memory()) + { + be_parameter temp = inner; + inner = outer; + outer = temp; + } + + // if the inner parameter is an immediate, push it to the outer + if (inner.is_immediate()) + { + be_parameter temp = inner; + inner = outer; + outer = temp; + } +} + + +//------------------------------------------------- +// offset_from_rbp - return the verified offset +// from rbp +//------------------------------------------------- + +inline INT32 drcbe_x64::offset_from_rbp(const void *ptr) +{ + INT64 delta = reinterpret_cast(const_cast(ptr)) - m_rbpvalue; + assert_always((INT32)delta == delta, "offset_from_rbp: delta out of range"); + return (INT32)delta; +} + + +//------------------------------------------------- +// get_base_register_and_offset - determine right +// base register and offset to access the given +// target address +//------------------------------------------------- + +inline int drcbe_x64::get_base_register_and_offset(x86code *&dst, void *target, UINT8 reg, INT32 &offset) +{ + INT64 delta = (UINT8 *)target - m_rbpvalue; + if (short_immediate(delta)) + { + offset = delta; + return REG_RBP; + } + else + { + offset = 0; + emit_mov_r64_imm(dst, reg, (FPTR)target); // mov reg,target + return reg; + } +} + + +//------------------------------------------------- +// emit_smart_call_r64 - generate a call either +// directly or via a call through pointer +//------------------------------------------------- + +inline void drcbe_x64::emit_smart_call_r64(x86code *&dst, x86code *target, UINT8 reg) +{ + INT64 delta = target - (dst + 5); + if (short_immediate(delta)) + emit_call(dst, target); // call target + else + { + emit_mov_r64_imm(dst, reg, (FPTR)target); // mov reg,target + emit_call_r64(dst, reg); // call reg + } +} + + +//------------------------------------------------- +// emit_smart_call_m64 - generate a call either +// directly or via a call through pointer +//------------------------------------------------- + +inline void drcbe_x64::emit_smart_call_m64(x86code *&dst, x86code **target) +{ + INT64 delta = *target - (dst + 5); + if (short_immediate(delta)) + emit_call(dst, *target); // call *target + else + emit_call_m64(dst, MABS(target)); // call [target] +} + + + +//************************************************************************** +// BACKEND CALLBACKS +//************************************************************************** + +//------------------------------------------------- +// drcbe_x64 - constructor +//------------------------------------------------- + +drcbe_x64::drcbe_x64(drcuml_state &drcuml, device_t &device, drc_cache &cache, UINT32 flags, int modes, int addrbits, int ignorebits) + : drcbe_interface(drcuml, cache, device), + m_hash(cache, modes, addrbits, ignorebits), + m_map(cache, 0), + m_labels(cache), + m_log(NULL), + m_sse41(false), + m_absmask32((UINT32 *)cache.alloc_near(16*2 + 15)), + m_absmask64(NULL), + m_rbpvalue(cache.near() + 0x80), + m_entry(NULL), + m_exit(NULL), + m_nocode(NULL), + m_fixup_label(FUNC(drcbe_x64::fixup_label), this), + m_fixup_exception(FUNC(drcbe_x64::fixup_exception), this), + m_near(*(near_state *)cache.alloc_near(sizeof(m_near))) +{ + // build up necessary arrays + static const UINT32 sse_control[4] = + { + 0xffc0, // ROUND_TRUNC + 0x9fc0, // ROUND_ROUND + 0xdfc0, // ROUND_CEIL + 0xbfc0 // ROUND_FLOOR + }; + memcpy(m_near.ssecontrol, sse_control, sizeof(m_near.ssecontrol)); + m_near.single1 = 1.0f; + m_near.double1 = 1.0; + + // create absolute value masks that are aligned to SSE boundaries + m_absmask32 = (UINT32 *)(((FPTR)m_absmask32 + 15) & ~15); + m_absmask32[0] = m_absmask32[1] = m_absmask32[2] = m_absmask32[3] = 0x7fffffff; + m_absmask64 = (UINT64 *)&m_absmask32[4]; + m_absmask64[0] = m_absmask64[1] = U64(0x7fffffffffffffff); + + // get pointers to C functions we need to call + m_near.debug_cpu_instruction_hook = (x86code *)debugger_instruction_hook; + if (LOG_HASHJMPS) + { + m_near.debug_log_hashjmp = (x86code *)debug_log_hashjmp; + m_near.debug_log_hashjmp_fail = (x86code *)debug_log_hashjmp_fail; + } + m_near.drcmap_get_value = (x86code *)&drc_map_variables::static_get_value; + + // build the flags map + for (int entry = 0; entry < ARRAY_LENGTH(m_near.flagsmap); entry++) + { + UINT8 flags = 0; + if (entry & 0x001) flags |= FLAG_C; + if (entry & 0x004) flags |= FLAG_U; + if (entry & 0x040) flags |= FLAG_Z; + if (entry & 0x080) flags |= FLAG_S; + if (entry & 0x800) flags |= FLAG_V; + m_near.flagsmap[entry] = flags; + } + for (int entry = 0; entry < ARRAY_LENGTH(m_near.flagsunmap); entry++) + { + UINT64 flags = 0; + if (entry & FLAG_C) flags |= 0x001; + if (entry & FLAG_U) flags |= 0x004; + if (entry & FLAG_Z) flags |= 0x040; + if (entry & FLAG_S) flags |= 0x080; + if (entry & FLAG_V) flags |= 0x800; + m_near.flagsunmap[entry] = flags; + } + + // build the opcode table (static but it doesn't hurt to regenerate it) + for (int opnum = 0; opnum < ARRAY_LENGTH(s_opcode_table_source); opnum++) + s_opcode_table[s_opcode_table_source[opnum].opcode] = s_opcode_table_source[opnum].func; + + // create the log + if (device.machine().options().drc_log_native()) + { + std::string filename = std::string("drcbex64_").append(device.shortname()).append(".asm"); + m_log = x86log_create_context(filename.c_str()); + } +} + + +//------------------------------------------------- +// ~drcbe_x64 - destructor +//------------------------------------------------- + +drcbe_x64::~drcbe_x64() +{ + // free the log context + if (m_log != NULL) + x86log_free_context(m_log); +} + + +//------------------------------------------------- +// reset - reset back-end specific state +//------------------------------------------------- + +void drcbe_x64::reset() +{ + // output a note to the log + if (m_log != NULL) + x86log_printf(m_log, "\n\n===========\nCACHE RESET\n===========\n\n"); + + // generate a little bit of glue code to set up the environment + drccodeptr *cachetop = m_cache.begin_codegen(500); + if (cachetop == NULL) + fatalerror("Out of cache space after a reset!\n"); + + x86code *dst = (x86code *)*cachetop; + + // generate a simple CPUID stub + UINT32 (*cpuid_ecx_stub)(void) = (UINT32 (*)(void))dst; + emit_push_r64(dst, REG_RBX); // push rbx + emit_mov_r32_imm(dst, REG_EAX, 1); // mov eax,1 + emit_cpuid(dst); // cpuid + emit_mov_r32_r32(dst, REG_EAX, REG_ECX); // mov eax,ecx + emit_pop_r64(dst, REG_RBX); // pop rbx + emit_ret(dst); // ret + + // call it to determine if we have SSE4.1 support + m_sse41 = (((*cpuid_ecx_stub)() & 0x80000) != 0); + + // generate an entry point + m_entry = (x86_entry_point_func)dst; + emit_push_r64(dst, REG_RBX); // push rbx + emit_push_r64(dst, REG_RSI); // push rsi + emit_push_r64(dst, REG_RDI); // push rdi + emit_push_r64(dst, REG_RBP); // push rbp + emit_push_r64(dst, REG_R12); // push r12 + emit_push_r64(dst, REG_R13); // push r13 + emit_push_r64(dst, REG_R14); // push r14 + emit_push_r64(dst, REG_R15); // push r15 + emit_mov_r64_r64(dst, REG_RBP, REG_PARAM1); // mov rbp,param1 + emit_sub_r64_imm(dst, REG_RSP, 32); // sub rsp,32 + emit_mov_m64_r64(dst, MABS(&m_near.hashstacksave), REG_RSP); // mov [hashstacksave],rsp + emit_sub_r64_imm(dst, REG_RSP, 8); // sub rsp,8 + emit_mov_m64_r64(dst, MABS(&m_near.stacksave), REG_RSP); // mov [stacksave],rsp + emit_stmxcsr_m32(dst, MABS(&m_near.ssemode)); // stmxcsr [ssemode] + emit_jmp_r64(dst, REG_PARAM2); // jmp param2 + if (m_log != NULL) + x86log_disasm_code_range(m_log, "entry_point", (x86code *)m_entry, dst); + + // generate an exit point + m_exit = dst; + emit_ldmxcsr_m32(dst, MABS(&m_near.ssemode)); // ldmxcsr [ssemode] + emit_mov_r64_m64(dst, REG_RSP, MABS(&m_near.hashstacksave)); // mov rsp,[hashstacksave] + emit_add_r64_imm(dst, REG_RSP, 32); // add rsp,32 + emit_pop_r64(dst, REG_R15); // pop r15 + emit_pop_r64(dst, REG_R14); // pop r14 + emit_pop_r64(dst, REG_R13); // pop r13 + emit_pop_r64(dst, REG_R12); // pop r12 + emit_pop_r64(dst, REG_RBP); // pop rbp + emit_pop_r64(dst, REG_RDI); // pop rdi + emit_pop_r64(dst, REG_RSI); // pop rsi + emit_pop_r64(dst, REG_RBX); // pop rbx + emit_ret(dst); // ret + if (m_log != NULL) + x86log_disasm_code_range(m_log, "exit_point", m_exit, dst); + + // generate a no code point + m_nocode = dst; + emit_ret(dst); // ret + if (m_log != NULL) + x86log_disasm_code_range(m_log, "nocode", m_nocode, dst); + + // finish up codegen + *cachetop = (drccodeptr)dst; + m_cache.end_codegen(); + + // reset our hash tables + m_hash.reset(); + m_hash.set_default_codeptr(m_nocode); +} + + +//------------------------------------------------- +// execute - execute a block of code referenced +// by the given handle +//------------------------------------------------- + +int drcbe_x64::execute(code_handle &entry) +{ + // call our entry point which will jump to the destination + return (*m_entry)(m_rbpvalue, (x86code *)entry.codeptr()); +} + + +//------------------------------------------------- +// drcbex64_generate - generate code +//------------------------------------------------- + +void drcbe_x64::generate(drcuml_block &block, const instruction *instlist, UINT32 numinst) +{ + // tell all of our utility objects that a block is beginning + m_hash.block_begin(block, instlist, numinst); + m_labels.block_begin(block); + m_map.block_begin(block); + + // begin codegen; fail if we can't + drccodeptr *cachetop = m_cache.begin_codegen(numinst * 8 * 4); + if (cachetop == NULL) + block.abort(); + + // compute the base by aligning the cache top to a cache line (assumed to be 64 bytes) + x86code *base = (x86code *)(((FPTR)*cachetop + 63) & ~63); + x86code *dst = base; + + // generate code + std::string tempstring; + const char *blockname = NULL; + for (int inum = 0; inum < numinst; inum++) + { + const instruction &inst = instlist[inum]; + assert(inst.opcode() < ARRAY_LENGTH(s_opcode_table)); + + // add a comment + if (m_log != NULL) + { + std::string dasm; + inst.disasm(dasm, &m_drcuml); + x86log_add_comment(m_log, dst, "%s", dasm.c_str()); + } + + // extract a blockname + if (blockname == NULL) + { + if (inst.opcode() == OP_HANDLE) + blockname = inst.param(0).handle().string(); + else if (inst.opcode() == OP_HASH) + blockname = strformat(tempstring, "Code: mode=%d PC=%08X", (UINT32)inst.param(0).immediate(), (offs_t)inst.param(1).immediate()).c_str(); + } + + // generate code + (this->*s_opcode_table[inst.opcode()])(dst, inst); + } + + // complete codegen + *cachetop = (drccodeptr)dst; + m_cache.end_codegen(); + + // log it + if (m_log != NULL) + x86log_disasm_code_range(m_log, (blockname == NULL) ? "Unknown block" : blockname, base, m_cache.top()); + + // tell all of our utility objects that the block is finished + m_hash.block_end(block); + m_labels.block_end(block); + m_map.block_end(block); +} + + +//------------------------------------------------- +// hash_exists - return true if the given mode/pc +// exists in the hash table +//------------------------------------------------- + +bool drcbe_x64::hash_exists(UINT32 mode, UINT32 pc) +{ + return m_hash.code_exists(mode, pc); +} + + +//------------------------------------------------- +// get_info - return information about the +// back-end implementation +//------------------------------------------------- + +void drcbe_x64::get_info(drcbe_info &info) +{ + for (info.direct_iregs = 0; info.direct_iregs < REG_I_COUNT; info.direct_iregs++) + if (int_register_map[info.direct_iregs] == 0) + break; + for (info.direct_fregs = 0; info.direct_fregs < REG_F_COUNT; info.direct_fregs++) + if (float_register_map[info.direct_fregs] == 0) + break; +} + + + +/*************************************************************************** + EMITTERS FOR 32-BIT OPERATIONS WITH PARAMETERS +***************************************************************************/ + +//------------------------------------------------- +// emit_mov_r32_p32 - move a 32-bit parameter +// into a register +//------------------------------------------------- + +void drcbe_x64::emit_mov_r32_p32(x86code *&dst, UINT8 reg, const be_parameter ¶m) +{ + if (param.is_immediate()) + { + if (param.immediate() == 0) + emit_xor_r32_r32(dst, reg, reg); // xor reg,reg + else + emit_mov_r32_imm(dst, reg, param.immediate()); // mov reg,param + } + else if (param.is_memory()) + emit_mov_r32_m32(dst, reg, MABS(param.memory())); // mov reg,[param] + else if (param.is_int_register()) + { + if (reg != param.ireg()) + emit_mov_r32_r32(dst, reg, param.ireg()); // mov reg,param + } +} + + +//------------------------------------------------- +// emit_movsx_r64_p32 - move a 32-bit parameter +// sign-extended into a register +//------------------------------------------------- + +void drcbe_x64::emit_movsx_r64_p32(x86code *&dst, UINT8 reg, const be_parameter ¶m) +{ + if (param.is_immediate()) + { + if (param.immediate() == 0) + emit_xor_r32_r32(dst, reg, reg); // xor reg,reg + else if ((INT32)param.immediate() >= 0) + emit_mov_r32_imm(dst, reg, param.immediate()); // mov reg,param + else + emit_mov_r64_imm(dst, reg, (INT32)param.immediate()); // mov reg,param + } + else if (param.is_memory()) + emit_movsxd_r64_m32(dst, reg, MABS(param.memory())); // movsxd reg,[param] + else if (param.is_int_register()) + emit_movsxd_r64_r32(dst, reg, param.ireg()); // movsdx reg,param +} + + +//------------------------------------------------- +// emit_mov_r32_p32_keepflags - move a 32-bit +// parameter into a register without affecting +// any flags +//------------------------------------------------- + +void drcbe_x64::emit_mov_r32_p32_keepflags(x86code *&dst, UINT8 reg, const be_parameter ¶m) +{ + if (param.is_immediate()) + emit_mov_r32_imm(dst, reg, param.immediate()); // mov reg,param + else if (param.is_memory()) + emit_mov_r32_m32(dst, reg, MABS(param.memory())); // mov reg,[param] + else if (param.is_int_register()) + { + if (reg != param.ireg()) + emit_mov_r32_r32(dst, reg, param.ireg()); // mov reg,param + } +} + + +//------------------------------------------------- +// emit_mov_m32_p32 - move a 32-bit parameter +// into a memory location +//------------------------------------------------- + +void drcbe_x64::emit_mov_m32_p32(x86code *&dst, x86_memref memref, const be_parameter ¶m) +{ + if (param.is_immediate()) + emit_mov_m32_imm(dst, memref, param.immediate()); // mov [mem],param + else if (param.is_memory()) + { + emit_mov_r32_m32(dst, REG_EAX, MABS(param.memory())); // mov eax,[param] + emit_mov_m32_r32(dst, memref, REG_EAX); // mov [mem],eax + } + else if (param.is_int_register()) + emit_mov_m32_r32(dst, memref, param.ireg()); // mov [mem],param +} + + +//------------------------------------------------- +// emit_mov_p32_r32 - move a register into a +// 32-bit parameter +//------------------------------------------------- + +void drcbe_x64::emit_mov_p32_r32(x86code *&dst, const be_parameter ¶m, UINT8 reg) +{ + assert(!param.is_immediate()); + if (param.is_memory()) + emit_mov_m32_r32(dst, MABS(param.memory()), reg); // mov [param],reg + else if (param.is_int_register()) + { + if (reg != param.ireg()) + emit_mov_r32_r32(dst, param.ireg(), reg); // mov param,reg + } +} + + +//------------------------------------------------- +// emit_add_r32_p32 - add operation to a 32-bit +// register from a 32-bit parameter +//------------------------------------------------- + +void drcbe_x64::emit_add_r32_p32(x86code *&dst, UINT8 reg, const be_parameter ¶m, const instruction &inst) +{ + if (param.is_immediate()) + { + if (inst.flags() != 0 || param.immediate() != 0) + emit_add_r32_imm(dst, reg, param.immediate()); // add reg,param + } + else if (param.is_memory()) + emit_add_r32_m32(dst, reg, MABS(param.memory())); // add reg,[param] + else if (param.is_int_register()) + emit_add_r32_r32(dst, reg, param.ireg()); // add reg,param +} + + +//------------------------------------------------- +// emit_add_m32_p32 - add operation to a 32-bit +// memory location from a 32-bit parameter +//------------------------------------------------- + +void drcbe_x64::emit_add_m32_p32(x86code *&dst, x86_memref memref, const be_parameter ¶m, const instruction &inst) +{ + if (param.is_immediate()) + { + if (inst.flags() != 0 || param.immediate() != 0) + emit_add_m32_imm(dst, memref, param.immediate()); // add [dest],param + } + else + { + int reg = param.select_register(REG_EAX); + emit_mov_r32_p32(dst, reg, param); // mov reg,param + emit_add_m32_r32(dst, memref, reg); // add [dest],reg + } +} + + +//------------------------------------------------- +// emit_adc_r32_p32 - adc operation to a 32-bit +// register from a 32-bit parameter +//------------------------------------------------- + +void drcbe_x64::emit_adc_r32_p32(x86code *&dst, UINT8 reg, const be_parameter ¶m, const instruction &inst) +{ + if (param.is_immediate()) + emit_adc_r32_imm(dst, reg, param.immediate()); // adc reg,param + else if (param.is_memory()) + emit_adc_r32_m32(dst, reg, MABS(param.memory())); // adc reg,[param] + else if (param.is_int_register()) + emit_adc_r32_r32(dst, reg, param.ireg()); // adc reg,param +} + + +//------------------------------------------------- +// emit_adc_m32_p32 - adc operation to a 32-bit +// memory location from a 32-bit parameter +//------------------------------------------------- + +void drcbe_x64::emit_adc_m32_p32(x86code *&dst, x86_memref memref, const be_parameter ¶m, const instruction &inst) +{ + if (param.is_immediate()) + emit_adc_m32_imm(dst, memref, param.immediate()); // adc [dest],param + else + { + int reg = param.select_register(REG_EAX); + emit_mov_r32_p32_keepflags(dst, reg, param); // mov reg,param + emit_adc_m32_r32(dst, memref, reg); // adc [dest],reg + } +} + + +//------------------------------------------------- +// emit_sub_r32_p32 - sub operation to a 32-bit +// register from a 32-bit parameter +//------------------------------------------------- + +void drcbe_x64::emit_sub_r32_p32(x86code *&dst, UINT8 reg, const be_parameter ¶m, const instruction &inst) +{ + if (param.is_immediate()) + { + if (inst.flags() != 0 || param.immediate() != 0) + emit_sub_r32_imm(dst, reg, param.immediate()); // sub reg,param + } + else if (param.is_memory()) + emit_sub_r32_m32(dst, reg, MABS(param.memory())); // sub reg,[param] + else if (param.is_int_register()) + emit_sub_r32_r32(dst, reg, param.ireg()); // sub reg,param +} + + +//------------------------------------------------- +// emit_sub_m32_p32 - sub operation to a 32-bit +// memory location from a 32-bit parameter +//------------------------------------------------- + +void drcbe_x64::emit_sub_m32_p32(x86code *&dst, x86_memref memref, const be_parameter ¶m, const instruction &inst) +{ + if (param.is_immediate()) + { + if (inst.flags() != 0 || param.immediate() != 0) + emit_sub_m32_imm(dst, memref, param.immediate()); // sub [dest],param + } + else + { + int reg = param.select_register(REG_EAX); + emit_mov_r32_p32(dst, reg, param); // mov reg,param + emit_sub_m32_r32(dst, memref, reg); // sub [dest],reg + } +} + + +//------------------------------------------------- +// emit_sbb_r32_p32 - sbb operation to a 32-bit +// register from a 32-bit parameter +//------------------------------------------------- + +void drcbe_x64::emit_sbb_r32_p32(x86code *&dst, UINT8 reg, const be_parameter ¶m, const instruction &inst) +{ + if (param.is_immediate()) + emit_sbb_r32_imm(dst, reg, param.immediate()); // sbb reg,param + else if (param.is_memory()) + emit_sbb_r32_m32(dst, reg, MABS(param.memory())); // sbb reg,[param] + else if (param.is_int_register()) + emit_sbb_r32_r32(dst, reg, param.ireg()); // sbb reg,param +} + + +//------------------------------------------------- +// emit_sbb_m32_p32 - sbb operation to a 32-bit +// memory location from a 32-bit parameter +//------------------------------------------------- + +void drcbe_x64::emit_sbb_m32_p32(x86code *&dst, x86_memref memref, const be_parameter ¶m, const instruction &inst) +{ + if (param.is_immediate()) + emit_sbb_m32_imm(dst, memref, param.immediate()); // sbb [dest],param + else + { + int reg = param.select_register(REG_EAX); + emit_mov_r32_p32_keepflags(dst, reg, param); // mov reg,param + emit_sbb_m32_r32(dst, memref, reg); // sbb [dest],reg + } +} + + +//------------------------------------------------- +// emit_cmp_r32_p32 - cmp operation to a 32-bit +// register from a 32-bit parameter +//------------------------------------------------- + +void drcbe_x64::emit_cmp_r32_p32(x86code *&dst, UINT8 reg, const be_parameter ¶m, const instruction &inst) +{ + if (param.is_immediate()) + emit_cmp_r32_imm(dst, reg, param.immediate()); // cmp reg,param + else if (param.is_memory()) + emit_cmp_r32_m32(dst, reg, MABS(param.memory())); // cmp reg,[param] + else if (param.is_int_register()) + emit_cmp_r32_r32(dst, reg, param.ireg()); // cmp reg,param +} + + +//------------------------------------------------- +// emit_cmp_m32_p32 - cmp operation to a 32-bit +// memory location from a 32-bit parameter +//------------------------------------------------- + +void drcbe_x64::emit_cmp_m32_p32(x86code *&dst, x86_memref memref, const be_parameter ¶m, const instruction &inst) +{ + if (param.is_immediate()) + emit_cmp_m32_imm(dst, memref, param.immediate()); // cmp [dest],param + else + { + int reg = param.select_register(REG_EAX); + emit_mov_r32_p32(dst, reg, param); // mov reg,param + emit_cmp_m32_r32(dst, memref, reg); // cmp [dest],reg + } +} + + +//------------------------------------------------- +// emit_and_r32_p32 - and operation to a 32-bit +// register from a 32-bit parameter +//------------------------------------------------- + +void drcbe_x64::emit_and_r32_p32(x86code *&dst, UINT8 reg, const be_parameter ¶m, const instruction &inst) +{ + if (param.is_immediate()) + { + if (inst.flags() == 0 && (UINT32)param.immediate() == 0xffffffff) + ;// skip + else if (inst.flags() == 0 && (UINT32)param.immediate() == 0) + emit_xor_r32_r32(dst, reg, reg); // xor reg,reg + else + emit_and_r32_imm(dst, reg, param.immediate()); // and reg,param + } + else if (param.is_memory()) + emit_and_r32_m32(dst, reg, MABS(param.memory())); // and reg,[param] + else if (param.is_int_register()) + emit_and_r32_r32(dst, reg, param.ireg()); // and reg,param +} + + +//------------------------------------------------- +// emit_and_m32_p32 - and operation to a 32-bit +// memory location from a 32-bit parameter +//------------------------------------------------- + +void drcbe_x64::emit_and_m32_p32(x86code *&dst, x86_memref memref, const be_parameter ¶m, const instruction &inst) +{ + if (param.is_immediate()) + { + if (inst.flags() == 0 && (UINT32)param.immediate() == 0xffffffff) + ;// skip + else if (inst.flags() == 0 && (UINT32)param.immediate() == 0) + emit_mov_m32_imm(dst, memref, 0); // mov [dest],0 + else + emit_and_m32_imm(dst, memref, param.immediate()); // and [dest],param + } + else + { + int reg = param.select_register(REG_EAX); + emit_mov_r32_p32(dst, reg, param); // mov reg,param + emit_and_m32_r32(dst, memref, reg); // and [dest],reg + } +} + + +//------------------------------------------------- +// emit_test_r32_p32 - test operation to a 32-bit +// register from a 32-bit parameter +//------------------------------------------------- + +void drcbe_x64::emit_test_r32_p32(x86code *&dst, UINT8 reg, const be_parameter ¶m, const instruction &inst) +{ + if (param.is_immediate()) + emit_test_r32_imm(dst, reg, param.immediate()); // test reg,param + else if (param.is_memory()) + emit_test_m32_r32(dst, MABS(param.memory()), reg); // test [param],reg + else if (param.is_int_register()) + emit_test_r32_r32(dst, reg, param.ireg()); // test reg,param +} + + +//------------------------------------------------- +// emit_test_m32_p32 - test operation to a 32-bit +// memory location from a 32-bit parameter +//------------------------------------------------- + +void drcbe_x64::emit_test_m32_p32(x86code *&dst, x86_memref memref, const be_parameter ¶m, const instruction &inst) +{ + if (param.is_immediate()) + emit_test_m32_imm(dst, memref, param.immediate()); // test [dest],param + else if (param.is_memory()) + { + emit_mov_r32_p32(dst, REG_EAX, param); // mov reg,param + emit_test_m32_r32(dst, memref, REG_EAX); // test [dest],reg + } + else if (param.is_int_register()) + emit_test_m32_r32(dst, memref, param.ireg()); // test [dest],param +} + + +//------------------------------------------------- +// emit_or_r32_p32 - or operation to a 32-bit +// register from a 32-bit parameter +//------------------------------------------------- + +void drcbe_x64::emit_or_r32_p32(x86code *&dst, UINT8 reg, const be_parameter ¶m, const instruction &inst) +{ + if (param.is_immediate()) + { + if (inst.flags() == 0 && (UINT32)param.immediate() == 0) + ;// skip + else if (inst.flags() == 0 && (UINT32)param.immediate() == 0xffffffff) + emit_mov_r32_imm(dst, reg, 0xffffffff); // mov reg,-1 + else + emit_or_r32_imm(dst, reg, param.immediate()); // or reg,param + } + else if (param.is_memory()) + emit_or_r32_m32(dst, reg, MABS(param.memory())); // or reg,[param] + else if (param.is_int_register()) + emit_or_r32_r32(dst, reg, param.ireg()); // or reg,param +} + + +//------------------------------------------------- +// emit_or_m32_p32 - or operation to a 32-bit +// memory location from a 32-bit parameter +//------------------------------------------------- + +void drcbe_x64::emit_or_m32_p32(x86code *&dst, x86_memref memref, const be_parameter ¶m, const instruction &inst) +{ + if (param.is_immediate()) + { + if (inst.flags() == 0 && (UINT32)param.immediate() == 0) + ;// skip + else if (inst.flags() == 0 && (UINT32)param.immediate() == 0xffffffff) + emit_mov_m32_imm(dst, memref, 0xffffffff); // mov [dest],-1 + else + emit_or_m32_imm(dst, memref, param.immediate()); // or [dest],param + } + else + { + int reg = param.select_register(REG_EAX); + emit_mov_r32_p32(dst, reg, param); // mov reg,param + emit_or_m32_r32(dst, memref, reg); // or [dest],reg + } +} + + +//------------------------------------------------- +// emit_xor_r32_p32 - xor operation to a 32-bit +// register from a 32-bit parameter +//------------------------------------------------- + +void drcbe_x64::emit_xor_r32_p32(x86code *&dst, UINT8 reg, const be_parameter ¶m, const instruction &inst) +{ + if (param.is_immediate()) + { + if (inst.flags() == 0 && (UINT32)param.immediate() == 0) + ;// skip + else if (inst.flags() == 0 && (UINT32)param.immediate() == 0xffffffff) + emit_not_r32(dst, reg); // not reg + else + emit_xor_r32_imm(dst, reg, param.immediate()); // xor reg,param + } + else if (param.is_memory()) + emit_xor_r32_m32(dst, reg, MABS(param.memory())); // xor reg,[param] + else if (param.is_int_register()) + emit_xor_r32_r32(dst, reg, param.ireg()); // xor reg,param +} + + +//------------------------------------------------- +// emit_xor_m32_p32 - xor operation to a 32-bit +// memory location from a 32-bit parameter +//------------------------------------------------- + +void drcbe_x64::emit_xor_m32_p32(x86code *&dst, x86_memref memref, const be_parameter ¶m, const instruction &inst) +{ + if (param.is_immediate()) + { + if (inst.flags() == 0 && (UINT32)param.immediate() == 0) + ;// skip + else if (inst.flags() == 0 && (UINT32)param.immediate() == 0xffffffff) + emit_not_m32(dst, memref); // not [dest] + else + emit_xor_m32_imm(dst, memref, param.immediate()); // xor [dest],param + } + else + { + int reg = param.select_register(REG_EAX); + emit_mov_r32_p32(dst, reg, param); // mov reg,param + emit_xor_m32_r32(dst, memref, reg); // xor [dest],reg + } +} + + +//------------------------------------------------- +// emit_shl_r32_p32 - shl operation to a 32-bit +// register from a 32-bit parameter +//------------------------------------------------- + +void drcbe_x64::emit_shl_r32_p32(x86code *&dst, UINT8 reg, const be_parameter ¶m, const instruction &inst) +{ + if (param.is_immediate()) + { + if (inst.flags() == 0 && (UINT32)param.immediate() == 0) + ;// skip + else + emit_shl_r32_imm(dst, reg, param.immediate()); // shl reg,param + } + else + { + emit_mov_r32_p32(dst, REG_ECX, param); // mov ecx,param + emit_shl_r32_cl(dst, reg); // shl reg,cl + } +} + + +//------------------------------------------------- +// emit_shl_m32_p32 - shl operation to a 32-bit +// memory location from a 32-bit parameter +//------------------------------------------------- + +void drcbe_x64::emit_shl_m32_p32(x86code *&dst, x86_memref memref, const be_parameter ¶m, const instruction &inst) +{ + if (param.is_immediate()) + { + if (inst.flags() == 0 && (UINT32)param.immediate() == 0) + ;// skip + else + emit_shl_m32_imm(dst, memref, param.immediate()); // shl [dest],param + } + else + { + emit_mov_r32_p32(dst, REG_ECX, param); // mov ecx,param + emit_shl_m32_cl(dst, memref); // shl [dest],cl + } +} + + +//------------------------------------------------- +// emit_shr_r32_p32 - shr operation to a 32-bit +// register from a 32-bit parameter +//------------------------------------------------- + +void drcbe_x64::emit_shr_r32_p32(x86code *&dst, UINT8 reg, const be_parameter ¶m, const instruction &inst) +{ + if (param.is_immediate()) + { + if (inst.flags() == 0 && (UINT32)param.immediate() == 0) + ;// skip + else + emit_shr_r32_imm(dst, reg, param.immediate()); // shr reg,param + } + else + { + emit_mov_r32_p32(dst, REG_ECX, param); // mov ecx,param + emit_shr_r32_cl(dst, reg); // shr reg,cl + } +} + + +//------------------------------------------------- +// emit_shr_m32_p32 - shr operation to a 32-bit +// memory location from a 32-bit parameter +//------------------------------------------------- + +void drcbe_x64::emit_shr_m32_p32(x86code *&dst, x86_memref memref, const be_parameter ¶m, const instruction &inst) +{ + if (param.is_immediate()) + { + if (inst.flags() == 0 && (UINT32)param.immediate() == 0) + ;// skip + else + emit_shr_m32_imm(dst, memref, param.immediate()); // shr [dest],param + } + else + { + emit_mov_r32_p32(dst, REG_ECX, param); // mov ecx,param + emit_shr_m32_cl(dst, memref); // shr [dest],cl + } +} + + +//------------------------------------------------- +// emit_sar_r32_p32 - sar operation to a 32-bit +// register from a 32-bit parameter +//------------------------------------------------- + +void drcbe_x64::emit_sar_r32_p32(x86code *&dst, UINT8 reg, const be_parameter ¶m, const instruction &inst) +{ + if (param.is_immediate()) + { + if (inst.flags() == 0 && (UINT32)param.immediate() == 0) + ;// skip + else + emit_sar_r32_imm(dst, reg, param.immediate()); // sar reg,param + } + else + { + emit_mov_r32_p32(dst, REG_ECX, param); // mov ecx,param + emit_sar_r32_cl(dst, reg); // sar reg,cl + } +} + + +//------------------------------------------------- +// emit_sar_m32_p32 - sar operation to a 32-bit +// memory location from a 32-bit parameter +//------------------------------------------------- + +void drcbe_x64::emit_sar_m32_p32(x86code *&dst, x86_memref memref, const be_parameter ¶m, const instruction &inst) +{ + if (param.is_immediate()) + { + if (inst.flags() == 0 && (UINT32)param.immediate() == 0) + ;// skip + else + emit_sar_m32_imm(dst, memref, param.immediate()); // sar [dest],param + } + else + { + emit_mov_r32_p32(dst, REG_ECX, param); // mov ecx,param + emit_sar_m32_cl(dst, memref); // sar [dest],cl + } +} + + +//------------------------------------------------- +// emit_rol_r32_p32 - rol operation to a 32-bit +// register from a 32-bit parameter +//------------------------------------------------- + +void drcbe_x64::emit_rol_r32_p32(x86code *&dst, UINT8 reg, const be_parameter ¶m, const instruction &inst) +{ + if (param.is_immediate()) + { + if (inst.flags() == 0 && (UINT32)param.immediate() == 0) + ;// skip + else + emit_rol_r32_imm(dst, reg, param.immediate()); // rol reg,param + } + else + { + emit_mov_r32_p32(dst, REG_ECX, param); // mov ecx,param + emit_rol_r32_cl(dst, reg); // rol reg,cl + } +} + + +//------------------------------------------------- +// emit_rol_m32_p32 - rol operation to a 32-bit +// memory location from a 32-bit parameter +//------------------------------------------------- + +void drcbe_x64::emit_rol_m32_p32(x86code *&dst, x86_memref memref, const be_parameter ¶m, const instruction &inst) +{ + if (param.is_immediate()) + { + if (inst.flags() == 0 && (UINT32)param.immediate() == 0) + ;// skip + else + emit_rol_m32_imm(dst, memref, param.immediate()); // rol [dest],param + } + else + { + emit_mov_r32_p32(dst, REG_ECX, param); // mov ecx,param + emit_rol_m32_cl(dst, memref); // rol [dest],cl + } +} + + +//------------------------------------------------- +// emit_ror_r32_p32 - ror operation to a 32-bit +// register from a 32-bit parameter +//------------------------------------------------- + +void drcbe_x64::emit_ror_r32_p32(x86code *&dst, UINT8 reg, const be_parameter ¶m, const instruction &inst) +{ + if (param.is_immediate()) + { + if (inst.flags() == 0 && (UINT32)param.immediate() == 0) + ;// skip + else + emit_ror_r32_imm(dst, reg, param.immediate()); // ror reg,param + } + else + { + emit_mov_r32_p32(dst, REG_ECX, param); // mov ecx,param + emit_ror_r32_cl(dst, reg); // ror reg,cl + } +} + + +//------------------------------------------------- +// emit_ror_m32_p32 - ror operation to a 32-bit +// memory location from a 32-bit parameter +//------------------------------------------------- + +void drcbe_x64::emit_ror_m32_p32(x86code *&dst, x86_memref memref, const be_parameter ¶m, const instruction &inst) +{ + if (param.is_immediate()) + { + if (inst.flags() == 0 && (UINT32)param.immediate() == 0) + ;// skip + else + emit_ror_m32_imm(dst, memref, param.immediate()); // ror [dest],param + } + else + { + emit_mov_r32_p32(dst, REG_ECX, param); // mov ecx,param + emit_ror_m32_cl(dst, memref); // ror [dest],cl + } +} + + +//------------------------------------------------- +// emit_rcl_r32_p32 - rcl operation to a 32-bit +// register from a 32-bit parameter +//------------------------------------------------- + +void drcbe_x64::emit_rcl_r32_p32(x86code *&dst, UINT8 reg, const be_parameter ¶m, const instruction &inst) +{ + if (param.is_immediate()) + { + if (inst.flags() == 0 && (UINT32)param.immediate() == 0) + ;// skip + else + emit_rcl_r32_imm(dst, reg, param.immediate()); // rcl reg,param + } + else + { + emit_mov_r32_p32_keepflags(dst, REG_ECX, param); // mov ecx,param + emit_rcl_r32_cl(dst, reg); // rcl reg,cl + } +} + + +//------------------------------------------------- +// emit_rcl_m32_p32 - rcl operation to a 32-bit +// memory location from a 32-bit parameter +//------------------------------------------------- + +void drcbe_x64::emit_rcl_m32_p32(x86code *&dst, x86_memref memref, const be_parameter ¶m, const instruction &inst) +{ + if (param.is_immediate()) + { + if (inst.flags() == 0 && (UINT32)param.immediate() == 0) + ;// skip + else + emit_rcl_m32_imm(dst, memref, param.immediate()); // rcl [dest],param + } + else + { + emit_mov_r32_p32_keepflags(dst, REG_ECX, param); // mov ecx,param + emit_rcl_m32_cl(dst, memref); // rcl [dest],cl + } +} + + +//------------------------------------------------- +// emit_rcr_r32_p32 - rcr operation to a 32-bit +// register from a 32-bit parameter +//------------------------------------------------- + +void drcbe_x64::emit_rcr_r32_p32(x86code *&dst, UINT8 reg, const be_parameter ¶m, const instruction &inst) +{ + if (param.is_immediate()) + { + if (inst.flags() == 0 && (UINT32)param.immediate() == 0) + ;// skip + else + emit_rcr_r32_imm(dst, reg, param.immediate()); // rcr reg,param + } + else + { + emit_mov_r32_p32_keepflags(dst, REG_ECX, param); // mov ecx,param + emit_rcr_r32_cl(dst, reg); // rcr reg,cl + } +} + + +//------------------------------------------------- +// emit_rcr_m32_p32 - rcr operation to a 32-bit +// memory location from a 32-bit parameter +//------------------------------------------------- + +void drcbe_x64::emit_rcr_m32_p32(x86code *&dst, x86_memref memref, const be_parameter ¶m, const instruction &inst) +{ + if (param.is_immediate()) + { + if (inst.flags() == 0 && (UINT32)param.immediate() == 0) + ;// skip + else + emit_rcr_m32_imm(dst, memref, param.immediate()); // rcr [dest],param + } + else + { + emit_mov_r32_p32_keepflags(dst, REG_ECX, param); // mov ecx,param + emit_rcr_m32_cl(dst, memref); // rcr [dest],cl + } +} + + + +/*************************************************************************** + EMITTERS FOR 64-BIT OPERATIONS WITH PARAMETERS +***************************************************************************/ + +//------------------------------------------------- +// emit_mov_r64_p64 - move a 64-bit parameter +// into a register +//------------------------------------------------- + +void drcbe_x64::emit_mov_r64_p64(x86code *&dst, UINT8 reg, const be_parameter ¶m) +{ + if (param.is_immediate()) + { + if (param.immediate() == 0) + emit_xor_r32_r32(dst, reg, reg); // xor reg,reg + else + emit_mov_r64_imm(dst, reg, param.immediate()); // mov reg,param + } + else if (param.is_memory()) + emit_mov_r64_m64(dst, reg, MABS(param.memory())); // mov reg,[param] + else if (param.is_int_register()) + { + if (reg != param.ireg()) + emit_mov_r64_r64(dst, reg, param.ireg()); // mov reg,param + } +} + + +//------------------------------------------------- +// emit_mov_r64_p64_keepflags - move a 64-bit +// parameter into a register without affecting +// any flags +//------------------------------------------------- + +void drcbe_x64::emit_mov_r64_p64_keepflags(x86code *&dst, UINT8 reg, const be_parameter ¶m) +{ + if (param.is_immediate()) + emit_mov_r64_imm(dst, reg, param.immediate()); // mov reg,param + else if (param.is_memory()) + emit_mov_r64_m64(dst, reg, MABS(param.memory())); // mov reg,[param] + else if (param.is_int_register()) + { + if (reg != param.ireg()) + emit_mov_r64_r64(dst, reg, param.ireg()); // mov reg,param + } +} + + +//------------------------------------------------- +// emit_mov_p64_r64 - move a registers into a +// 64-bit parameter +//------------------------------------------------- + +void drcbe_x64::emit_mov_p64_r64(x86code *&dst, const be_parameter ¶m, UINT8 reg) +{ + assert(!param.is_immediate()); + if (param.is_memory()) + emit_mov_m64_r64(dst, MABS(param.memory()), reg); // mov [param],reg + else if (param.is_int_register()) + { + if (reg != param.ireg()) + emit_mov_r64_r64(dst, param.ireg(), reg); // mov param,reg + } +} + + +//------------------------------------------------- +// emit_add_r64_p64 - add operation to a 64-bit +// register from a 64-bit parameter +//------------------------------------------------- + +void drcbe_x64::emit_add_r64_p64(x86code *&dst, UINT8 reg, const be_parameter ¶m, const instruction &inst) +{ + if (param.is_immediate()) + { + if (inst.flags() != 0 || param.immediate() != 0) + { + if (short_immediate(param.immediate())) + emit_add_r64_imm(dst, reg, param.immediate()); // add reg,param + else + { + emit_mov_r64_imm(dst, REG_R11, param.immediate()); // mov r11,param + emit_add_r64_r64(dst, reg, REG_R11); // add reg,r11 + } + } + } + else if (param.is_memory()) + emit_add_r64_m64(dst, reg, MABS(param.memory())); // add reg,[param] + else if (param.is_int_register()) + emit_add_r64_r64(dst, reg, param.ireg()); // add reg,param +} + + +//------------------------------------------------- +// emit_add_m64_p64 - add operation to a 64-bit +// memory location from a 64-bit parameter +//------------------------------------------------- + +void drcbe_x64::emit_add_m64_p64(x86code *&dst, x86_memref memref, const be_parameter ¶m, const instruction &inst) +{ + if (param.is_immediate()) + { + if (inst.flags() != 0 || param.immediate() != 0) + { + if (short_immediate(param.immediate())) + emit_add_m64_imm(dst, memref, param.immediate()); // add [mem],param + else + { + emit_mov_r64_imm(dst, REG_R11, param.immediate()); // mov r11,param + emit_add_m64_r64(dst, memref, REG_R11); // add [mem],r11 + } + } + } + else + { + int reg = param.select_register(REG_EAX); + emit_mov_r64_p64(dst, reg, param); // mov reg,param + emit_add_m64_r64(dst, memref, reg); // add [dest],reg + } +} + + +//------------------------------------------------- +// emit_adc_r64_p64 - adc operation to a 64-bit +// register from a 64-bit parameter +//------------------------------------------------- + +void drcbe_x64::emit_adc_r64_p64(x86code *&dst, UINT8 reg, const be_parameter ¶m, const instruction &inst) +{ + if (param.is_immediate()) + { + if (short_immediate(param.immediate())) + emit_adc_r64_imm(dst, reg, param.immediate()); // adc reg,param + else + { + emit_mov_r64_imm(dst, REG_R11, param.immediate()); // mov r11,param + emit_adc_r64_r64(dst, reg, REG_R11); // adc reg,r11 + } + } + else if (param.is_memory()) + emit_adc_r64_m64(dst, reg, MABS(param.memory())); // adc reg,[param] + else if (param.is_int_register()) + emit_adc_r64_r64(dst, reg, param.ireg()); // adc reg,param +} + + +//------------------------------------------------- +// emit_adc_m64_p64 - adc operation to a 64-bit +// memory locaiton from a 64-bit parameter +//------------------------------------------------- + +void drcbe_x64::emit_adc_m64_p64(x86code *&dst, x86_memref memref, const be_parameter ¶m, const instruction &inst) +{ + if (param.is_immediate() && short_immediate(param.immediate())) + emit_adc_m64_imm(dst, memref, param.immediate()); // adc [mem],param + else + { + int reg = param.select_register(REG_EAX); + emit_mov_r64_p64_keepflags(dst, reg, param); // mov reg,param + emit_adc_m64_r64(dst, memref, reg); // adc [dest],reg + } +} + + +//------------------------------------------------- +// emit_sub_r64_p64 - sub operation to a 64-bit +// register from a 64-bit parameter +//------------------------------------------------- + +void drcbe_x64::emit_sub_r64_p64(x86code *&dst, UINT8 reg, const be_parameter ¶m, const instruction &inst) +{ + if (param.is_immediate()) + { + if (inst.flags() != 0 || param.immediate() != 0) + { + if (short_immediate(param.immediate())) + emit_sub_r64_imm(dst, reg, param.immediate()); // sub reg,param + else + { + emit_mov_r64_imm(dst, REG_R11, param.immediate()); // mov r11,param + emit_sub_r64_r64(dst, reg, REG_R11); // sub reg,r11 + } + } + } + else if (param.is_memory()) + emit_sub_r64_m64(dst, reg, MABS(param.memory())); // sub reg,[param] + else if (param.is_int_register()) + emit_sub_r64_r64(dst, reg, param.ireg()); // sub reg,param +} + + +//------------------------------------------------- +// emit_sub_m64_p64 - sub operation to a 64-bit +// memory location from a 64-bit parameter +//------------------------------------------------- + +void drcbe_x64::emit_sub_m64_p64(x86code *&dst, x86_memref memref, const be_parameter ¶m, const instruction &inst) +{ + if (param.is_immediate()) + { + if (inst.flags() != 0 || param.immediate() != 0) + { + if (short_immediate(param.immediate())) + emit_sub_m64_imm(dst, memref, param.immediate()); // sub [mem],param + else + { + emit_mov_r64_imm(dst, REG_R11, param.immediate()); // mov r11,param + emit_sub_m64_r64(dst, memref, REG_R11); // sub [mem],r11 + } + } + } + else + { + int reg = param.select_register(REG_EAX); + emit_mov_r64_p64(dst, reg, param); // mov reg,param + emit_sub_m64_r64(dst, memref, reg); // sub [dest],reg + } +} + + +//------------------------------------------------- +// emit_sbb_r64_p64 - sbb operation to a 64-bit +// register from a 64-bit parameter +//------------------------------------------------- + +void drcbe_x64::emit_sbb_r64_p64(x86code *&dst, UINT8 reg, const be_parameter ¶m, const instruction &inst) +{ + if (param.is_immediate()) + { + if (short_immediate(param.immediate())) + emit_sbb_r64_imm(dst, reg, param.immediate()); // sbb reg,param + else + { + emit_mov_r64_imm(dst, REG_R11, param.immediate()); // mov r11,param + emit_sbb_r64_r64(dst, reg, REG_R11); // sbb reg,r11 + } + } + else if (param.is_memory()) + emit_sbb_r64_m64(dst, reg, MABS(param.memory())); // sbb reg,[param] + else if (param.is_int_register()) + emit_sbb_r64_r64(dst, reg, param.ireg()); // sbb reg,param +} + + +//------------------------------------------------- +// emit_sbb_m64_p64 - sbb operation to a 64-bit +// memory location from a 64-bit parameter +//------------------------------------------------- + +void drcbe_x64::emit_sbb_m64_p64(x86code *&dst, x86_memref memref, const be_parameter ¶m, const instruction &inst) +{ + if (param.is_immediate() && short_immediate(param.immediate())) + emit_sbb_m64_imm(dst, memref, param.immediate()); // sbb [mem],param + else + { + int reg = param.select_register(REG_EAX); + emit_mov_r64_p64_keepflags(dst, reg, param); // mov reg,param + emit_sbb_m64_r64(dst, memref, reg); // sbb [dest],reg + } +} + + +//------------------------------------------------- +// emit_cmp_r64_p64 - cmp operation to a 64-bit +// register from a 64-bit parameter +//------------------------------------------------- + +void drcbe_x64::emit_cmp_r64_p64(x86code *&dst, UINT8 reg, const be_parameter ¶m, const instruction &inst) +{ + if (param.is_immediate()) + { + if (short_immediate(param.immediate())) + emit_cmp_r64_imm(dst, reg, param.immediate()); // cmp reg,param + else + { + emit_mov_r64_imm(dst, REG_R11, param.immediate()); // mov r11,param + emit_cmp_r64_r64(dst, reg, REG_R11); // cmp reg,r11 + } + } + else if (param.is_memory()) + emit_cmp_r64_m64(dst, reg, MABS(param.memory())); // cmp reg,[param] + else if (param.is_int_register()) + emit_cmp_r64_r64(dst, reg, param.ireg()); // cmp reg,param +} + + +//------------------------------------------------- +// emit_cmp_m64_p64 - cmp operation to a 64-bit +// memory location from a 64-bit parameter +//------------------------------------------------- + +void drcbe_x64::emit_cmp_m64_p64(x86code *&dst, x86_memref memref, const be_parameter ¶m, const instruction &inst) +{ + if (param.is_immediate() && short_immediate(param.immediate())) + emit_cmp_m64_imm(dst, memref, param.immediate()); // cmp [dest],param + else + { + int reg = param.select_register(REG_EAX); + emit_mov_r64_p64(dst, reg, param); // mov reg,param + emit_cmp_m64_r64(dst, memref, reg); // cmp [dest],reg + } +} + + +//------------------------------------------------- +// emit_and_r64_p64 - and operation to a 64-bit +// register from a 64-bit parameter +//------------------------------------------------- + +void drcbe_x64::emit_and_r64_p64(x86code *&dst, UINT8 reg, const be_parameter ¶m, const instruction &inst) +{ + if (param.is_immediate()) + { + if (inst.flags() != 0 || param.immediate() != U64(0xffffffffffffffff)) + { + if (short_immediate(param.immediate())) + emit_and_r64_imm(dst, reg, param.immediate()); // and reg,param + else + { + emit_mov_r64_imm(dst, REG_R11, param.immediate()); // mov r11,param + emit_and_r64_r64(dst, reg, REG_R11); // and reg,r11 + } + } + } + else if (param.is_memory()) + emit_and_r64_m64(dst, reg, MABS(param.memory())); // and reg,[param] + else if (param.is_int_register()) + emit_and_r64_r64(dst, reg, param.ireg()); // and reg,param +} + + +//------------------------------------------------- +// emit_and_m64_p64 - and operation to a 64-bit +// memory location from a 64-bit parameter +//------------------------------------------------- + +void drcbe_x64::emit_and_m64_p64(x86code *&dst, x86_memref memref, const be_parameter ¶m, const instruction &inst) +{ + if (param.is_immediate()) + { + if (inst.flags() != 0 || param.immediate() != U64(0xffffffffffffffff)) + { + if (short_immediate(param.immediate())) + emit_and_m64_imm(dst, memref, param.immediate()); // and [mem],param + else + { + emit_mov_r64_imm(dst, REG_R11, param.immediate()); // mov r11,param + emit_and_m64_r64(dst, memref, REG_R11); // and [mem],r11 + } + } + } + else + { + int reg = param.select_register(REG_EAX); + emit_mov_r64_p64(dst, reg, param); // mov reg,param + emit_and_m64_r64(dst, memref, reg); // and [dest],reg + } +} + + +//------------------------------------------------- +// emit_test_r64_p64 - test operation to a 64-bit +// register from a 64-bit parameter +//------------------------------------------------- + +void drcbe_x64::emit_test_r64_p64(x86code *&dst, UINT8 reg, const be_parameter ¶m, const instruction &inst) +{ + if (param.is_immediate()) + { + if (short_immediate(param.immediate())) + emit_test_r64_imm(dst, reg, param.immediate()); // test reg,param + else + { + emit_mov_r64_imm(dst, REG_R11, param.immediate()); // mov r11,param + emit_test_r64_r64(dst, reg, REG_R11); // test reg,r11 + } + } + else if (param.is_memory()) + emit_test_m64_r64(dst, MABS(param.memory()), reg); // test [param],reg + else if (param.is_int_register()) + emit_test_r64_r64(dst, reg, param.ireg()); // test reg,param +} + + +//------------------------------------------------- +// emit_test_m64_p64 - test operation to a 64-bit +// memory location from a 64-bit parameter +//------------------------------------------------- + +void drcbe_x64::emit_test_m64_p64(x86code *&dst, x86_memref memref, const be_parameter ¶m, const instruction &inst) +{ + if (param.is_immediate() && short_immediate(param.immediate())) + emit_test_m64_imm(dst, memref, param.immediate()); // test [dest],param + else if (param.is_memory()) + { + emit_mov_r64_p64(dst, REG_EAX, param); // mov reg,param + emit_test_m64_r64(dst, memref, REG_EAX); // test [dest],reg + } + else if (param.is_int_register()) + emit_test_m64_r64(dst, memref, param.ireg()); // test [dest],param +} + + +//------------------------------------------------- +// emit_or_r64_p64 - or operation to a 64-bit +// register from a 64-bit parameter +//------------------------------------------------- + +void drcbe_x64::emit_or_r64_p64(x86code *&dst, UINT8 reg, const be_parameter ¶m, const instruction &inst) +{ + if (param.is_immediate()) + { + if (inst.flags() != 0 || param.immediate() != 0) + { + if (short_immediate(param.immediate())) + emit_or_r64_imm(dst, reg, param.immediate()); // or reg,param + else + { + emit_mov_r64_imm(dst, REG_R11, param.immediate()); // mov r11,param + emit_or_r64_r64(dst, reg, REG_R11); // or reg,r11 + } + } + } + else if (param.is_memory()) + emit_or_r64_m64(dst, reg, MABS(param.memory())); // or reg,[param] + else if (param.is_int_register()) + emit_or_r64_r64(dst, reg, param.ireg()); // or reg,param +} + + +//------------------------------------------------- +// emit_or_m64_p64 - or operation to a 64-bit +// memory location from a 64-bit parameter +//------------------------------------------------- + +void drcbe_x64::emit_or_m64_p64(x86code *&dst, x86_memref memref, const be_parameter ¶m, const instruction &inst) +{ + if (param.is_immediate()) + { + if (inst.flags() != 0 || param.immediate() != 0) + { + if (short_immediate(param.immediate())) + emit_or_m64_imm(dst, memref, param.immediate()); // or [mem],param + else + { + emit_mov_r64_imm(dst, REG_R11, param.immediate()); // mov r11,param + emit_or_m64_r64(dst, memref, REG_R11); // or [mem],r11 + } + } + } + else + { + int reg = param.select_register(REG_EAX); + emit_mov_r64_p64(dst, reg, param); // mov reg,param + emit_or_m64_r64(dst, memref, reg); // or [dest],reg + } +} + + +//------------------------------------------------- +// emit_xor_r64_p64 - xor operation to a 64-bit +// register from a 64-bit parameter +//------------------------------------------------- + +void drcbe_x64::emit_xor_r64_p64(x86code *&dst, UINT8 reg, const be_parameter ¶m, const instruction &inst) +{ + if (param.is_immediate()) + { + if (inst.flags() != 0 || param.immediate() != 0) + { + if (param.immediate() == U64(0xffffffffffffffff)) + emit_not_r64(dst, reg); // not reg + else if (short_immediate(param.immediate())) + emit_xor_r64_imm(dst, reg, param.immediate()); // xor reg,param + else + { + emit_mov_r64_imm(dst, REG_R11, param.immediate()); // mov r11,param + emit_xor_r64_r64(dst, reg, REG_R11); // xor reg,r11 + } + } + } + else if (param.is_memory()) + emit_xor_r64_m64(dst, reg, MABS(param.memory())); // xor reg,[param] + else if (param.is_int_register()) + emit_xor_r64_r64(dst, reg, param.ireg()); // xor reg,param +} + + +//------------------------------------------------- +// emit_xor_m64_p64 - xor operation to a 64-bit +// memory location from a 64-bit parameter +//------------------------------------------------- + +void drcbe_x64::emit_xor_m64_p64(x86code *&dst, x86_memref memref, const be_parameter ¶m, const instruction &inst) +{ + if (param.is_immediate()) + { + if (inst.flags() != 0 || param.immediate() != 0) + { + if (param.immediate() == U64(0xffffffffffffffff)) + emit_not_m64(dst, memref); // not [mem] + else if (short_immediate(param.immediate())) + emit_xor_m64_imm(dst, memref, param.immediate()); // xor [mem],param + else + { + emit_mov_r64_imm(dst, REG_R11, param.immediate()); // mov r11,param + emit_xor_m64_r64(dst, memref, REG_R11); // xor [mem],r11 + } + } + } + else + { + int reg = param.select_register(REG_EAX); + emit_mov_r64_p64(dst, reg, param); // mov reg,param + emit_xor_m64_r64(dst, memref, reg); // xor [dest],reg + } +} + + +//------------------------------------------------- +// emit_shl_r64_p64 - shl operation to a 64-bit +// register from a 64-bit parameter +//------------------------------------------------- + +void drcbe_x64::emit_shl_r64_p64(x86code *&dst, UINT8 reg, const be_parameter ¶m, const instruction &inst) +{ + if (param.is_immediate()) + { + if (inst.flags() == 0 && (UINT32)param.immediate() == 0) + ;// skip + else + emit_shl_r64_imm(dst, reg, param.immediate()); // shl reg,param + } + else + { + emit_mov_r64_p64(dst, REG_RCX, param); // mov rcx,param + emit_shl_r64_cl(dst, reg); // shl reg,cl + } +} + + +//------------------------------------------------- +// emit_shl_m64_p64 - shl operation to a 64-bit +// memory location from a 64-bit parameter +//------------------------------------------------- + +void drcbe_x64::emit_shl_m64_p64(x86code *&dst, x86_memref memref, const be_parameter ¶m, const instruction &inst) +{ + if (param.is_immediate()) + { + if (inst.flags() == 0 && (UINT64)param.immediate() == 0) + ;// skip + else + emit_shl_m64_imm(dst, memref, param.immediate()); // shl [dest],param + } + else + { + emit_mov_r64_p64(dst, REG_RCX, param); // mov rcx,param + emit_shl_m64_cl(dst, memref); // shl [dest],cl + } +} + + +//------------------------------------------------- +// emit_shr_r64_p64 - shr operation to a 64-bit +// register from a 64-bit parameter +//------------------------------------------------- + +void drcbe_x64::emit_shr_r64_p64(x86code *&dst, UINT8 reg, const be_parameter ¶m, const instruction &inst) +{ + if (param.is_immediate()) + { + if (inst.flags() == 0 && (UINT32)param.immediate() == 0) + ;// skip + else + emit_shr_r64_imm(dst, reg, param.immediate()); // shr reg,param + } + else + { + emit_mov_r64_p64(dst, REG_RCX, param); // mov rcx,param + emit_shr_r64_cl(dst, reg); // shr reg,cl + } +} + + +//------------------------------------------------- +// emit_shr_m64_p64 - shr operation to a 64-bit +// memory location from a 64-bit parameter +//------------------------------------------------- + +void drcbe_x64::emit_shr_m64_p64(x86code *&dst, x86_memref memref, const be_parameter ¶m, const instruction &inst) +{ + if (param.is_immediate()) + { + if (inst.flags() == 0 && (UINT64)param.immediate() == 0) + ;// skip + else + emit_shr_m64_imm(dst, memref, param.immediate()); // shr [dest],param + } + else + { + emit_mov_r64_p64(dst, REG_RCX, param); // mov rcx,param + emit_shr_m64_cl(dst, memref); // shr [dest],cl + } +} + + +//------------------------------------------------- +// emit_sar_r64_p64 - sar operation to a 64-bit +// register from a 64-bit parameter +//------------------------------------------------- + +void drcbe_x64::emit_sar_r64_p64(x86code *&dst, UINT8 reg, const be_parameter ¶m, const instruction &inst) +{ + if (param.is_immediate()) + { + if (inst.flags() == 0 && (UINT32)param.immediate() == 0) + ;// skip + else + emit_sar_r64_imm(dst, reg, param.immediate()); // sar reg,param + } + else + { + emit_mov_r64_p64(dst, REG_RCX, param); // mov rcx,param + emit_sar_r64_cl(dst, reg); // sar reg,cl + } +} + + +//------------------------------------------------- +// emit_sar_m64_p64 - sar operation to a 64-bit +// memory location from a 64-bit parameter +//------------------------------------------------- + +void drcbe_x64::emit_sar_m64_p64(x86code *&dst, x86_memref memref, const be_parameter ¶m, const instruction &inst) +{ + if (param.is_immediate()) + { + if (inst.flags() == 0 && (UINT64)param.immediate() == 0) + ;// skip + else + emit_sar_m64_imm(dst, memref, param.immediate()); // sar [dest],param + } + else + { + emit_mov_r64_p64(dst, REG_RCX, param); // mov rcx,param + emit_sar_m64_cl(dst, memref); // sar [dest],cl + } +} + + +//------------------------------------------------- +// emit_rol_r64_p64 - rol operation to a 64-bit +// register from a 64-bit parameter +//------------------------------------------------- + +void drcbe_x64::emit_rol_r64_p64(x86code *&dst, UINT8 reg, const be_parameter ¶m, const instruction &inst) +{ + if (param.is_immediate()) + { + if (inst.flags() == 0 && (UINT32)param.immediate() == 0) + ;// skip + else + emit_rol_r64_imm(dst, reg, param.immediate()); // rol reg,param + } + else + { + emit_mov_r64_p64(dst, REG_RCX, param); // mov rcx,param + emit_rol_r64_cl(dst, reg); // rol reg,cl + } +} + + +//------------------------------------------------- +// emit_rol_m64_p64 - rol operation to a 64-bit +// memory location from a 64-bit parameter +//------------------------------------------------- + +void drcbe_x64::emit_rol_m64_p64(x86code *&dst, x86_memref memref, const be_parameter ¶m, const instruction &inst) +{ + if (param.is_immediate()) + { + if (inst.flags() == 0 && (UINT64)param.immediate() == 0) + ;// skip + else + emit_rol_m64_imm(dst, memref, param.immediate()); // rol [dest],param + } + else + { + emit_mov_r64_p64(dst, REG_RCX, param); // mov rcx,param + emit_rol_m64_cl(dst, memref); // rol [dest],cl + } +} + + +//------------------------------------------------- +// emit_ror_r64_p64 - ror operation to a 64-bit +// register from a 64-bit parameter +//------------------------------------------------- + +void drcbe_x64::emit_ror_r64_p64(x86code *&dst, UINT8 reg, const be_parameter ¶m, const instruction &inst) +{ + if (param.is_immediate()) + { + if (inst.flags() == 0 && (UINT32)param.immediate() == 0) + ;// skip + else + emit_ror_r64_imm(dst, reg, param.immediate()); // ror reg,param + } + else + { + emit_mov_r64_p64(dst, REG_RCX, param); // mov rcx,param + emit_ror_r64_cl(dst, reg); // ror reg,cl + } +} + + +//------------------------------------------------- +// emit_ror_m64_p64 - ror operation to a 64-bit +// memory location from a 64-bit parameter +//------------------------------------------------- + +void drcbe_x64::emit_ror_m64_p64(x86code *&dst, x86_memref memref, const be_parameter ¶m, const instruction &inst) +{ + if (param.is_immediate()) + { + if (inst.flags() == 0 && (UINT64)param.immediate() == 0) + ;// skip + else + emit_ror_m64_imm(dst, memref, param.immediate()); // ror [dest],param + } + else + { + emit_mov_r64_p64(dst, REG_RCX, param); // mov rcx,param + emit_ror_m64_cl(dst, memref); // ror [dest],cl + } +} + + +//------------------------------------------------- +// emit_rcl_r64_p64 - rcl operation to a 64-bit +// register from a 64-bit parameter +//------------------------------------------------- + +void drcbe_x64::emit_rcl_r64_p64(x86code *&dst, UINT8 reg, const be_parameter ¶m, const instruction &inst) +{ + if (param.is_immediate()) + { + if (inst.flags() == 0 && (UINT32)param.immediate() == 0) + ;// skip + else + emit_rcl_r64_imm(dst, reg, param.immediate()); // rcl reg,param + } + else + { + emit_mov_r64_p64_keepflags(dst, REG_RCX, param); // mov rcx,param + emit_rcl_r64_cl(dst, reg); // rcl reg,cl + } +} + + +//------------------------------------------------- +// emit_rcl_m64_p64 - rcl operation to a 64-bit +// memory location from a 64-bit parameter +//------------------------------------------------- + +void drcbe_x64::emit_rcl_m64_p64(x86code *&dst, x86_memref memref, const be_parameter ¶m, const instruction &inst) +{ + if (param.is_immediate()) + { + if (inst.flags() == 0 && (UINT64)param.immediate() == 0) + ;// skip + else + emit_rcl_m64_imm(dst, memref, param.immediate()); // rcl [dest],param + } + else + { + emit_mov_r64_p64_keepflags(dst, REG_RCX, param); // mov rcx,param + emit_rcl_m64_cl(dst, memref); // rcl [dest],cl + } +} + + +//------------------------------------------------- +// emit_rcr_r64_p64 - rcr operation to a 64-bit +// register from a 64-bit parameter +//------------------------------------------------- + +void drcbe_x64::emit_rcr_r64_p64(x86code *&dst, UINT8 reg, const be_parameter ¶m, const instruction &inst) +{ + if (param.is_immediate()) + { + if (inst.flags() == 0 && (UINT32)param.immediate() == 0) + ;// skip + else + emit_rcr_r64_imm(dst, reg, param.immediate()); // rcr reg,param + } + else + { + emit_mov_r64_p64_keepflags(dst, REG_RCX, param); // mov rcx,param + emit_rcr_r64_cl(dst, reg); // rcr reg,cl + } +} + + +//------------------------------------------------- +// emit_rcr_m64_p64 - rcr operation to a 64-bit +// memory location from a 64-bit parameter +//------------------------------------------------- + +void drcbe_x64::emit_rcr_m64_p64(x86code *&dst, x86_memref memref, const be_parameter ¶m, const instruction &inst) +{ + if (param.is_immediate()) + { + if (inst.flags() == 0 && (UINT64)param.immediate() == 0) + ;// skip + else + emit_rcr_m64_imm(dst, memref, param.immediate()); // rcr [dest],param + } + else + { + emit_mov_r64_p64_keepflags(dst, REG_RCX, param); // mov rcx,param + emit_rcr_m64_cl(dst, memref); // rcr [dest],cl + } +} + + + +/*************************************************************************** + EMITTERS FOR FLOATING POINT OPERATIONS WITH PARAMETERS +***************************************************************************/ + +//------------------------------------------------- +// emit_movss_r128_p32 - move a 32-bit parameter +// into a register +//------------------------------------------------- + +void drcbe_x64::emit_movss_r128_p32(x86code *&dst, UINT8 reg, const be_parameter ¶m) +{ + assert(!param.is_immediate()); + if (param.is_memory()) + emit_movss_r128_m32(dst, reg, MABS(param.memory())); // movss reg,[param] + else if (param.is_float_register()) + { + if (reg != param.freg()) + emit_movss_r128_r128(dst, reg, param.freg()); // movss reg,param + } +} + + +//------------------------------------------------- +// emit_movss_p32_r128 - move a register into a +// 32-bit parameter +//------------------------------------------------- + +void drcbe_x64::emit_movss_p32_r128(x86code *&dst, const be_parameter ¶m, UINT8 reg) +{ + assert(!param.is_immediate()); + if (param.is_memory()) + emit_movss_m32_r128(dst, MABS(param.memory()), reg); // movss [param],reg + else if (param.is_float_register()) + { + if (reg != param.freg()) + emit_movss_r128_r128(dst, param.freg(), reg); // movss param,reg + } +} + + +//------------------------------------------------- +// emit_movsd_r128_p64 - move a 64-bit parameter +// into a register +//------------------------------------------------- + +void drcbe_x64::emit_movsd_r128_p64(x86code *&dst, UINT8 reg, const be_parameter ¶m) +{ + assert(!param.is_immediate()); + if (param.is_memory()) + emit_movsd_r128_m64(dst, reg, MABS(param.memory())); // movsd reg,[param] + else if (param.is_float_register()) + { + if (reg != param.freg()) + emit_movsd_r128_r128(dst, reg, param.freg()); // movsd reg,param + } +} + + +//------------------------------------------------- +// emit_movsd_p64_r128 - move a register into a +// 64-bit parameter +//------------------------------------------------- + +void drcbe_x64::emit_movsd_p64_r128(x86code *&dst, const be_parameter ¶m, UINT8 reg) +{ + assert(!param.is_immediate()); + if (param.is_memory()) + emit_movsd_m64_r128(dst, MABS(param.memory()), reg); // movsd [param],reg + else if (param.is_float_register()) + { + if (reg != param.freg()) + emit_movsd_r128_r128(dst, param.freg(), reg); // movsd param,reg + } +} + + + +/*************************************************************************** + OUT-OF-BAND CODE FIXUP CALLBACKS +***************************************************************************/ + +//------------------------------------------------- +// fixup_label - callback to fixup forward- +// referenced labels +//------------------------------------------------- + +void drcbe_x64::fixup_label(void *parameter, drccodeptr labelcodeptr) +{ + drccodeptr src = (drccodeptr)parameter; + + // find the end of the instruction + if (src[0] == 0xe3) + { + src += 1 + 1; + src[-1] = labelcodeptr - src; + } + else if (src[0] == 0xe9) + { + src += 1 + 4; + ((UINT32 *)src)[-1] = labelcodeptr - src; + } + else if (src[0] == 0x0f && (src[1] & 0xf0) == 0x80) + { + src += 2 + 4; + ((UINT32 *)src)[-1] = labelcodeptr - src; + } + else + fatalerror("fixup_label called with invalid jmp source!\n"); +} + + +//------------------------------------------------- +// fixup_exception - callback to perform cleanup +// and jump to an exception handler +//------------------------------------------------- + +void drcbe_x64::fixup_exception(drccodeptr *codeptr, void *param1, void *param2) +{ + drccodeptr src = (drccodeptr)param1; + const instruction &inst = *(const instruction *)param2; + + // normalize parameters + const parameter &handp = inst.param(0); + assert(handp.is_code_handle()); + be_parameter exp(*this, inst.param(1), PTYPE_MRI); + + // look up the handle target + drccodeptr *targetptr = handp.handle().codeptr_addr(); + + // first fixup the jump to get us here + drccodeptr dst = *codeptr; + ((UINT32 *)src)[-1] = dst - src; + + // then store the exception parameter + emit_mov_m32_p32(dst, MABS(&m_state.exp), exp); // mov [exp],exp + + // push the original return address on the stack + emit_lea_r64_m64(dst, REG_RAX, MABS(src)); // lea rax,[return] + emit_push_r64(dst, REG_RAX); // push rax + if (*targetptr != NULL) + emit_jmp(dst, *targetptr); // jmp *targetptr + else + emit_jmp_m64(dst, MABS(targetptr)); // jmp [targetptr] + + *codeptr = dst; +} + + + +//************************************************************************** +// DEBUG HELPERS +//************************************************************************** + +//------------------------------------------------- +// debug_log_hashjmp - callback to handle +// logging of hashjmps +//------------------------------------------------- + +void drcbe_x64::debug_log_hashjmp(offs_t pc, int mode) +{ + printf("mode=%d PC=%08X\n", mode, pc); +} + + +//------------------------------------------------- +// debug_log_hashjmp - callback to handle +// logging of hashjmps +//------------------------------------------------- + +void drcbe_x64::debug_log_hashjmp_fail() +{ + printf(" (FAIL)\n"); +} + + + +/*************************************************************************** + COMPILE-TIME OPCODES +***************************************************************************/ + +//------------------------------------------------- +// op_handle - process a HANDLE opcode +//------------------------------------------------- + +void drcbe_x64::op_handle(x86code *&dst, const instruction &inst) +{ + assert_no_condition(inst); + assert_no_flags(inst); + assert(inst.numparams() == 1); + assert(inst.param(0).is_code_handle()); + + // emit a jump around the stack adjust in case code falls through here + emit_link skip; + emit_jmp_short_link(dst, skip); // jmp skip + + // register the current pointer for the handle + inst.param(0).handle().set_codeptr(dst); + + // by default, the handle points to prolog code that moves the stack pointer + emit_lea_r64_m64(dst, REG_RSP, MBD(REG_RSP, -40)); // lea rsp,[rsp-40] + resolve_link(dst, skip); // skip: +} + + +//------------------------------------------------- +// op_hash - process a HASH opcode +//------------------------------------------------- + +void drcbe_x64::op_hash(x86code *&dst, const instruction &inst) +{ + assert_no_condition(inst); + assert_no_flags(inst); + assert(inst.numparams() == 2); + assert(inst.param(0).is_immediate()); + assert(inst.param(1).is_immediate()); + + // register the current pointer for the mode/PC + m_hash.set_codeptr(inst.param(0).immediate(), inst.param(1).immediate(), dst); +} + + +//------------------------------------------------- +// op_label - process a LABEL opcode +//------------------------------------------------- + +void drcbe_x64::op_label(x86code *&dst, const instruction &inst) +{ + assert_no_condition(inst); + assert_no_flags(inst); + assert(inst.numparams() == 1); + assert(inst.param(0).is_code_label()); + + // register the current pointer for the label + m_labels.set_codeptr(inst.param(0).label(), dst); +} + + +//------------------------------------------------- +// op_comment - process a COMMENT opcode +//------------------------------------------------- + +void drcbe_x64::op_comment(x86code *&dst, const instruction &inst) +{ + assert_no_condition(inst); + assert_no_flags(inst); + assert(inst.numparams() == 1); + assert(inst.param(0).is_string()); + + // do nothing +} + + +//------------------------------------------------- +// op_mapvar - process a MAPVAR opcode +//------------------------------------------------- + +void drcbe_x64::op_mapvar(x86code *&dst, const instruction &inst) +{ + assert_no_condition(inst); + assert_no_flags(inst); + assert(inst.numparams() == 2); + assert(inst.param(0).is_mapvar()); + assert(inst.param(1).is_immediate()); + + // set the value of the specified mapvar + m_map.set_value(dst, inst.param(0).mapvar(), inst.param(1).immediate()); +} + + + +/*************************************************************************** + CONTROL FLOW OPCODES +***************************************************************************/ + +//------------------------------------------------- +// op_nop - process a NOP opcode +//------------------------------------------------- + +void drcbe_x64::op_nop(x86code *&dst, const instruction &inst) +{ + // nothing +} + + +//------------------------------------------------- +// op_debug - process a DEBUG opcode +//------------------------------------------------- + +void drcbe_x64::op_debug(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4); + assert_no_condition(inst); + assert_no_flags(inst); + + if ((m_device.machine().debug_flags & DEBUG_FLAG_ENABLED) != 0) + { + // normalize parameters + be_parameter pcp(*this, inst.param(0), PTYPE_MRI); + + // test and branch + emit_mov_r64_imm(dst, REG_RAX, (FPTR)&m_device.machine().debug_flags); // mov rax,&debug_flags + emit_test_m32_imm(dst, MBD(REG_RAX, 0), DEBUG_FLAG_CALL_HOOK); // test [debug_flags],DEBUG_FLAG_CALL_HOOK + emit_link skip = { 0 }; + emit_jcc_short_link(dst, x64emit::COND_Z, skip); // jz skip + + // push the parameter + emit_mov_r64_imm(dst, REG_PARAM1, (FPTR)&m_device); // mov param1,device + emit_mov_r32_p32(dst, REG_PARAM2, pcp); // mov param2,pcp + emit_smart_call_m64(dst, &m_near.debug_cpu_instruction_hook); // call debug_cpu_instruction_hook + + resolve_link(dst, skip); // skip: + } +} + + +//------------------------------------------------- +// op_exit - process an EXIT opcode +//------------------------------------------------- + +void drcbe_x64::op_exit(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4); + assert_any_condition(inst); + assert_no_flags(inst); + + // normalize parameters + be_parameter retp(*this, inst.param(0), PTYPE_MRI); + + // load the parameter into EAX + emit_mov_r32_p32(dst, REG_EAX, retp); // mov eax,retp + if (inst.condition() == uml::COND_ALWAYS) + emit_jmp(dst, m_exit); // jmp exit + else + emit_jcc(dst, X86_CONDITION(inst.condition()), m_exit); // jcc exit +} + + +//------------------------------------------------- +// op_hashjmp - process a HASHJMP opcode +//------------------------------------------------- + +void drcbe_x64::op_hashjmp(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4); + assert_no_condition(inst); + assert_no_flags(inst); + + // normalize parameters + be_parameter modep(*this, inst.param(0), PTYPE_MRI); + be_parameter pcp(*this, inst.param(1), PTYPE_MRI); + const parameter &exp = inst.param(2); + assert(exp.is_code_handle()); + + if (LOG_HASHJMPS) + { + emit_mov_r32_p32(dst, REG_PARAM1, pcp); + emit_mov_r32_p32(dst, REG_PARAM2, modep); + emit_smart_call_m64(dst, &m_near.debug_log_hashjmp); + } + + // load the stack base one word early so we end up at the right spot after our call below + emit_mov_r64_m64(dst, REG_RSP, MABS(&m_near.hashstacksave)); // mov rsp,[hashstacksave] + + // fixed mode cases + if (modep.is_immediate() && m_hash.is_mode_populated(modep.immediate())) + { + // a straight immediate jump is direct, though we need the PC in EAX in case of failure + if (pcp.is_immediate()) + { + UINT32 l1val = (pcp.immediate() >> m_hash.l1shift()) & m_hash.l1mask(); + UINT32 l2val = (pcp.immediate() >> m_hash.l2shift()) & m_hash.l2mask(); + emit_call_m64(dst, MABS(&m_hash.base()[modep.immediate()][l1val][l2val])); + // call hash[modep][l1val][l2val] + } + + // a fixed mode but variable PC + else + { + emit_mov_r32_p32(dst, REG_EAX, pcp); // mov eax,pcp + emit_mov_r32_r32(dst, REG_EDX, REG_EAX); // mov edx,eax + emit_shr_r32_imm(dst, REG_EDX, m_hash.l1shift()); // shr edx,l1shift + emit_and_r32_imm(dst, REG_EAX, m_hash.l2mask() << m_hash.l2shift()); // and eax,l2mask << l2shift + emit_mov_r64_m64(dst, REG_RDX, MBISD(REG_RBP, REG_RDX, 8, offset_from_rbp(&m_hash.base()[modep.immediate()][0]))); + // mov rdx,hash[modep+edx*8] + emit_call_m64(dst, MBISD(REG_RDX, REG_RAX, 8 >> m_hash.l2shift(), 0)); // call [rdx+rax*shift] + } + } + else + { + // variable mode + int modereg = modep.select_register(REG_ECX); + emit_mov_r32_p32(dst, modereg, modep); // mov modereg,modep + emit_mov_r64_m64(dst, REG_RCX, MBISD(REG_RBP, modereg, 8, offset_from_rbp(m_hash.base()))); + // mov rcx,hash[modereg*8] + + // fixed PC + if (pcp.is_immediate()) + { + UINT32 l1val = (pcp.immediate() >> m_hash.l1shift()) & m_hash.l1mask(); + UINT32 l2val = (pcp.immediate() >> m_hash.l2shift()) & m_hash.l2mask(); + emit_mov_r64_m64(dst, REG_RDX, MBD(REG_RCX, l1val*8)); // mov rdx,[rcx+l1val*8] + emit_call_m64(dst, MBD(REG_RDX, l2val*8)); // call [l2val*8] + } + + // variable PC + else + { + emit_mov_r32_p32(dst, REG_EAX, pcp); // mov eax,pcp + emit_mov_r32_r32(dst, REG_EDX, REG_EAX); // mov edx,eax + emit_shr_r32_imm(dst, REG_EDX, m_hash.l1shift()); // shr edx,l1shift + emit_mov_r64_m64(dst, REG_RDX, MBISD(REG_RCX, REG_RDX, 8, 0)); // mov rdx,[rcx+rdx*8] + emit_and_r32_imm(dst, REG_EAX, m_hash.l2mask() << m_hash.l2shift()); // and eax,l2mask << l2shift + emit_call_m64(dst, MBISD(REG_RDX, REG_RAX, 8 >> m_hash.l2shift(), 0)); // call [rdx+rax*shift] + } + } + + // in all cases, if there is no code, we return here to generate the exception + if (LOG_HASHJMPS) + emit_smart_call_m64(dst, &m_near.debug_log_hashjmp_fail); + + emit_mov_m32_p32(dst, MABS(&m_state.exp), pcp); // mov [exp],param + emit_sub_r64_imm(dst, REG_RSP, 8); // sub rsp,8 + emit_call_m64(dst, MABS(exp.handle().codeptr_addr())); // call [exp] +} + + +//------------------------------------------------- +// op_jmp - process a JMP opcode +//------------------------------------------------- + +void drcbe_x64::op_jmp(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4); + assert_any_condition(inst); + assert_no_flags(inst); + + // normalize parameters + const parameter &labelp = inst.param(0); + assert(labelp.is_code_label()); + + // look up the jump target and jump there + x86code *jmptarget = (x86code *)m_labels.get_codeptr(labelp.label(), m_fixup_label, dst); + if (jmptarget == NULL) + jmptarget = dst + 0x7ffffff0; + if (inst.condition() == uml::COND_ALWAYS) + emit_jmp(dst, jmptarget); // jmp target + else + emit_jcc(dst, X86_CONDITION(inst.condition()), jmptarget); // jcc target + +} + + +//------------------------------------------------- +// op_exh - process an EXH opcode +//------------------------------------------------- + +void drcbe_x64::op_exh(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4); + assert_any_condition(inst); + assert_no_flags(inst); + + // normalize parameters + const parameter &handp = inst.param(0); + assert(handp.is_code_handle()); + be_parameter exp(*this, inst.param(1), PTYPE_MRI); + + // look up the handle target + drccodeptr *targetptr = handp.handle().codeptr_addr(); + + // perform the exception processing inline if unconditional + if (inst.condition() == uml::COND_ALWAYS) + { + emit_mov_m32_p32(dst, MABS(&m_state.exp), exp); // mov [exp],exp + if (*targetptr != NULL) + emit_call(dst, *targetptr); // call *targetptr + else + emit_call_m64(dst, MABS(targetptr)); // call [targetptr] + } + + // otherwise, jump to an out-of-band handler + else + { + emit_jcc(dst, X86_CONDITION(inst.condition()), dst + 0x7ffffff0); // jcc exception + m_cache.request_oob_codegen(m_fixup_exception, dst, &const_cast(inst)); + } +} + + +//------------------------------------------------- +// op_callh - process a CALLH opcode +//------------------------------------------------- + +void drcbe_x64::op_callh(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4); + assert_any_condition(inst); + assert_no_flags(inst); + + // normalize parameters + const parameter &handp = inst.param(0); + assert(handp.is_code_handle()); + + // look up the handle target + drccodeptr *targetptr = handp.handle().codeptr_addr(); + + // skip if conditional + emit_link skip = { 0 }; + if (inst.condition() != uml::COND_ALWAYS) + emit_jcc_short_link(dst, X86_NOT_CONDITION(inst.condition()), skip); // jcc skip + + // jump through the handle; directly if a normal jump + if (*targetptr != NULL) + emit_call(dst, *targetptr); // call *targetptr + else + emit_call_m64(dst, MABS(targetptr)); // call [targetptr] + + // resolve the conditional link + if (inst.condition() != uml::COND_ALWAYS) + resolve_link(dst, skip); // skip: +} + + +//------------------------------------------------- +// op_ret - process a RET opcode +//------------------------------------------------- + +void drcbe_x64::op_ret(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4); + assert_any_condition(inst); + assert_no_flags(inst); + assert(inst.numparams() == 0); + + // skip if conditional + emit_link skip = { 0 }; + if (inst.condition() != uml::COND_ALWAYS) + emit_jcc_short_link(dst, X86_NOT_CONDITION(inst.condition()), skip); // jcc skip + + // return + emit_lea_r64_m64(dst, REG_RSP, MBD(REG_RSP, 40)); // lea rsp,[rsp+40] + emit_ret(dst); // ret + + // resolve the conditional link + if (inst.condition() != uml::COND_ALWAYS) + resolve_link(dst, skip); // skip: +} + + +//------------------------------------------------- +// op_callc - process a CALLC opcode +//------------------------------------------------- + +void drcbe_x64::op_callc(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4); + assert_any_condition(inst); + assert_no_flags(inst); + + // normalize parameters + const parameter &funcp = inst.param(0); + assert(funcp.is_c_function()); + be_parameter paramp(*this, inst.param(1), PTYPE_M); + + // skip if conditional + emit_link skip = { 0 }; + if (inst.condition() != uml::COND_ALWAYS) + emit_jcc_short_link(dst, X86_NOT_CONDITION(inst.condition()), skip); // jcc skip + + // perform the call + emit_mov_r64_imm(dst, REG_PARAM1, (FPTR)paramp.memory()); // mov param1,paramp + emit_smart_call_r64(dst, (x86code *)(FPTR)funcp.cfunc(), REG_RAX); // call funcp + + // resolve the conditional link + if (inst.condition() != uml::COND_ALWAYS) + resolve_link(dst, skip); // skip: +} + + +//------------------------------------------------- +// op_recover - process a RECOVER opcode +//------------------------------------------------- + +void drcbe_x64::op_recover(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4); + assert_no_condition(inst); + assert_no_flags(inst); + + // normalize parameters + be_parameter dstp(*this, inst.param(0), PTYPE_MR); + + // call the recovery code + emit_mov_r64_m64(dst, REG_RAX, MABS(&m_near.stacksave)); // mov rax,stacksave + emit_mov_r64_m64(dst, REG_RAX, MBD(REG_RAX, -8)); // mov rax,[rax-4] + emit_mov_r64_imm(dst, REG_PARAM1, (FPTR)&m_map); // mov param1,m_map + emit_lea_r64_m64(dst, REG_PARAM2, MBD(REG_RAX, -1)); // lea param2,[rax-1] + emit_mov_r64_imm(dst, REG_PARAM3, inst.param(1).mapvar()); // mov param3,param[1].value + emit_smart_call_m64(dst, &m_near.drcmap_get_value); // call drcmap_get_value + emit_mov_p32_r32(dst, dstp, REG_EAX); // mov dstp,eax + +} + + + +/*************************************************************************** + INTERNAL REGISTER OPCODES +***************************************************************************/ + +//------------------------------------------------- +// op_setfmod - process a SETFMOD opcode +//------------------------------------------------- + +void drcbe_x64::op_setfmod(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4); + assert_no_condition(inst); + assert_no_flags(inst); + + // normalize parameters + be_parameter srcp(*this, inst.param(0), PTYPE_MRI); + + // immediate case + if (srcp.is_immediate()) + { + int value = srcp.immediate() & 3; + emit_mov_m8_imm(dst, MABS(&m_state.fmod), value); // mov [fmod],srcp + emit_ldmxcsr_m32(dst, MABS(&m_near.ssecontrol[value])); // ldmxcsr fp_control[srcp] + } + + // register/memory case + else + { + emit_mov_r32_p32(dst, REG_EAX, srcp); // mov eax,srcp + emit_and_r32_imm(dst, REG_EAX, 3); // and eax,3 + emit_mov_m8_r8(dst, MABS(&m_state.fmod), REG_AL); // mov [fmod],al + emit_ldmxcsr_m32(dst, MBISD(REG_RBP, REG_RAX, 4, offset_from_rbp(&m_near.ssecontrol[0]))); + // ldmxcsr fp_control[eax] + } +} + + +//------------------------------------------------- +// op_getfmod - process a GETFMOD opcode +//------------------------------------------------- + +void drcbe_x64::op_getfmod(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4); + assert_no_condition(inst); + assert_no_flags(inst); + + // normalize parameters + be_parameter dstp(*this, inst.param(0), PTYPE_MR); + + // fetch the current mode and store to the destination + if (dstp.is_int_register()) + emit_movzx_r32_m8(dst, dstp.ireg(), MABS(&m_state.fmod)); // movzx reg,[fmod] + else + { + emit_movzx_r32_m8(dst, REG_EAX, MABS(&m_state.fmod)); // movzx eax,[fmod] + emit_mov_m32_r32(dst, MABS(dstp.memory()), REG_EAX); // mov [dstp],eax + } +} + + +//------------------------------------------------- +// op_getexp - process a GETEXP opcode +//------------------------------------------------- + +void drcbe_x64::op_getexp(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4); + assert_no_condition(inst); + assert_no_flags(inst); + + // normalize parameters + be_parameter dstp(*this, inst.param(0), PTYPE_MR); + + // fetch the exception parameter and store to the destination + if (dstp.is_int_register()) + emit_mov_r32_m32(dst, dstp.ireg(), MABS(&m_state.exp)); // mov reg,[exp] + else + { + emit_mov_r32_m32(dst, REG_EAX, MABS(&m_state.exp)); // mov eax,[exp] + emit_mov_m32_r32(dst, MABS(dstp.memory()), REG_EAX); // mov [dstp],eax + } +} + + +//------------------------------------------------- +// op_getflgs - process a GETFLGS opcode +//------------------------------------------------- + +void drcbe_x64::op_getflgs(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4); + assert_no_condition(inst); + assert_no_flags(inst); + + // normalize parameters + be_parameter dstp(*this, inst.param(0), PTYPE_MR); + be_parameter maskp(*this, inst.param(1), PTYPE_I); + + // pick a target register for the general case + int dstreg = dstp.select_register(REG_EAX); + + // compute mask for flags + UINT32 flagmask = 0; + if (maskp.immediate() & FLAG_C) flagmask |= 0x001; + if (maskp.immediate() & FLAG_V) flagmask |= 0x800; + if (maskp.immediate() & FLAG_Z) flagmask |= 0x040; + if (maskp.immediate() & FLAG_S) flagmask |= 0x080; + if (maskp.immediate() & FLAG_U) flagmask |= 0x004; + + switch (maskp.immediate()) + { + // single flags only + case FLAG_C: + emit_setcc_r8(dst, x64emit::COND_C, REG_AL); // setc al + emit_movzx_r32_r8(dst, dstreg, REG_AL); // movzx dstreg,al + break; + + case FLAG_V: + emit_setcc_r8(dst, x64emit::COND_O, REG_AL); // seto al + emit_movzx_r32_r8(dst, dstreg, REG_AL); // movzx dstreg,al + emit_shl_r32_imm(dst, dstreg, 1); // shl dstreg,1 + break; + + case FLAG_Z: + emit_setcc_r8(dst, x64emit::COND_Z, REG_AL); // setz al + emit_movzx_r32_r8(dst, dstreg, REG_AL); // movzx dstreg,al + emit_shl_r32_imm(dst, dstreg, 2); // shl dstreg,2 + break; + + case FLAG_S: + emit_setcc_r8(dst, x64emit::COND_S, REG_AL); // sets al + emit_movzx_r32_r8(dst, dstreg, REG_AL); // movzx dstreg,al + emit_shl_r32_imm(dst, dstreg, 3); // shl dstreg,3 + break; + + case FLAG_U: + emit_setcc_r8(dst, x64emit::COND_P, REG_AL); // setp al + emit_movzx_r32_r8(dst, dstreg, REG_AL); // movzx dstreg,al + emit_shl_r32_imm(dst, dstreg, 4); // shl dstreg,4 + break; + + // carry plus another flag + case FLAG_C | FLAG_V: + emit_setcc_r8(dst, x64emit::COND_C, REG_AL); // setc al + emit_setcc_r8(dst, x64emit::COND_O, REG_CL); // seto cl + emit_movzx_r32_r8(dst, REG_EAX, REG_AL); // movzx eax,al + emit_movzx_r32_r8(dst, REG_ECX, REG_CL); // movzx ecx,cl + emit_lea_r32_m32(dst, dstreg, MBISD(REG_EAX, REG_ECX, 2, 0)); // lea dstreg,[eax+ecx*2] + break; + + case FLAG_C | FLAG_Z: + emit_setcc_r8(dst, x64emit::COND_C, REG_AL); // setc al + emit_setcc_r8(dst, x64emit::COND_Z, REG_CL); // setz cl + emit_movzx_r32_r8(dst, REG_EAX, REG_AL); // movzx eax,al + emit_movzx_r32_r8(dst, REG_ECX, REG_CL); // movzx ecx,cl + emit_lea_r32_m32(dst, dstreg, MBISD(REG_EAX, REG_ECX, 4, 0)); // lea dstreg,[eax+ecx*4] + break; + + case FLAG_C | FLAG_S: + emit_setcc_r8(dst, x64emit::COND_C, REG_AL); // setc al + emit_setcc_r8(dst, x64emit::COND_S, REG_CL); // sets cl + emit_movzx_r32_r8(dst, REG_EAX, REG_AL); // movzx eax,al + emit_movzx_r32_r8(dst, REG_ECX, REG_CL); // movzx ecx,cl + emit_lea_r32_m32(dst, dstreg, MBISD(REG_EAX, REG_ECX, 8, 0)); // lea dstreg,[eax+ecx*8] + break; + + // overflow plus another flag + case FLAG_V | FLAG_Z: + emit_setcc_r8(dst, x64emit::COND_O, REG_AL); // seto al + emit_setcc_r8(dst, x64emit::COND_Z, REG_CL); // setz cl + emit_movzx_r32_r8(dst, REG_EAX, REG_AL); // movzx eax,al + emit_movzx_r32_r8(dst, REG_ECX, REG_CL); // movzx ecx,cl + emit_lea_r32_m32(dst, dstreg, MBISD(REG_EAX, REG_ECX, 2, 0)); // lea dstreg,[eax+ecx*2] + emit_shl_r32_imm(dst, dstreg, 1); // shl dstreg,1 + break; + + case FLAG_V | FLAG_S: + emit_setcc_r8(dst, x64emit::COND_O, REG_AL); // seto al + emit_setcc_r8(dst, x64emit::COND_S, REG_CL); // sets cl + emit_movzx_r32_r8(dst, REG_EAX, REG_AL); // movzx eax,al + emit_movzx_r32_r8(dst, REG_ECX, REG_CL); // movzx ecx,al + emit_lea_r32_m32(dst, dstreg, MBISD(REG_EAX, REG_ECX, 4, 0)); // lea dstreg,[eax+ecx*4] + emit_shl_r32_imm(dst, dstreg, 1); // shl dstreg,1 + break; + + // zero plus another flag + case FLAG_Z | FLAG_S: + emit_setcc_r8(dst, x64emit::COND_Z, REG_AL); // setz al + emit_setcc_r8(dst, x64emit::COND_S, REG_CL); // sets cl + emit_movzx_r32_r8(dst, REG_EAX, REG_AL); // movzx eax,al + emit_movzx_r32_r8(dst, REG_ECX, REG_CL); // movzx ecx,al + emit_lea_r32_m32(dst, dstreg, MBISD(REG_EAX, REG_ECX, 2, 0)); // lea dstreg,[eax+ecx*2] + emit_shl_r32_imm(dst, dstreg, 2); // shl dstreg,2 + break; + + // default cases + default: + emit_pushf(dst); // pushf + emit_pop_r64(dst, REG_EAX); // pop eax + emit_and_r32_imm(dst, REG_EAX, flagmask); // and eax,flagmask + emit_movzx_r32_m8(dst, dstreg, MBISD(REG_RBP, REG_RAX, 1, offset_from_rbp(&m_near.flagsmap[0]))); + // movzx dstreg,[flags_map] + break; + } + + // 32-bit form + if (inst.size() == 4) + emit_mov_p32_r32(dst, dstp, dstreg); // mov dstp,dstreg + + // 64-bit form + else if (inst.size() == 8) + emit_mov_p64_r64(dst, dstp, dstreg); // mov dstp,dstreg +} + + +//------------------------------------------------- +// op_save - process a SAVE opcode +//------------------------------------------------- + +void drcbe_x64::op_save(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4); + assert_no_condition(inst); + assert_no_flags(inst); + + // normalize parameters + be_parameter dstp(*this, inst.param(0), PTYPE_M); + + // copy live state to the destination + emit_mov_r64_imm(dst, REG_RCX, (FPTR)dstp.memory()); // mov rcx,dstp + + // copy flags + emit_pushf(dst); // pushf + emit_pop_r64(dst, REG_RAX); // pop rax + emit_and_r32_imm(dst, REG_EAX, 0x8c5); // and eax,0x8c5 + emit_mov_r8_m8(dst, REG_AL, MBISD(REG_RBP, REG_RAX, 1, offset_from_rbp(&m_near.flagsmap[0]))); + // mov al,[flags_map] + emit_mov_m8_r8(dst, MBD(REG_RCX, offsetof(drcuml_machine_state, flags)), REG_AL); // mov state->flags,al + + // copy fmod and exp + emit_mov_r8_m8(dst, REG_AL, MABS(&m_state.fmod)); // mov al,[fmod] + emit_mov_m8_r8(dst, MBD(REG_RCX, offsetof(drcuml_machine_state, fmod)), REG_AL); // mov state->fmod,al + emit_mov_r32_m32(dst, REG_EAX, MABS(&m_state.exp)); // mov eax,[exp] + emit_mov_m32_r32(dst, MBD(REG_RCX, offsetof(drcuml_machine_state, exp)), REG_EAX); // mov state->exp,eax + + // copy integer registers + int regoffs = offsetof(drcuml_machine_state, r); + for (int regnum = 0; regnum < ARRAY_LENGTH(m_state.r); regnum++) + { + if (int_register_map[regnum] != 0) + emit_mov_m64_r64(dst, MBD(REG_RCX, regoffs + 8 * regnum), int_register_map[regnum]); + else + { + emit_mov_r64_m64(dst, REG_RAX, MABS(&m_state.r[regnum].d)); + emit_mov_m64_r64(dst, MBD(REG_RCX, regoffs + 8 * regnum), REG_RAX); + } + } + + // copy FP registers + regoffs = offsetof(drcuml_machine_state, f); + for (int regnum = 0; regnum < ARRAY_LENGTH(m_state.f); regnum++) + { + if (float_register_map[regnum] != 0) + emit_movsd_m64_r128(dst, MBD(REG_RCX, regoffs + 8 * regnum), float_register_map[regnum]); + else + { + emit_mov_r64_m64(dst, REG_RAX, MABS(&m_state.f[regnum].d)); + emit_mov_m64_r64(dst, MBD(REG_RCX, regoffs + 8 * regnum), REG_RAX); + } + } +} + + +//------------------------------------------------- +// op_restore - process a RESTORE opcode +//------------------------------------------------- + +void drcbe_x64::op_restore(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4); + assert_no_condition(inst); + + // normalize parameters + be_parameter srcp(*this, inst.param(0), PTYPE_M); + + // copy live state from the destination + emit_mov_r64_imm(dst, REG_ECX, (FPTR)srcp.memory()); // mov rcx,dstp + + // copy integer registers + int regoffs = offsetof(drcuml_machine_state, r); + for (int regnum = 0; regnum < ARRAY_LENGTH(m_state.r); regnum++) + { + if (int_register_map[regnum] != 0) + emit_mov_r64_m64(dst, int_register_map[regnum], MBD(REG_RCX, regoffs + 8 * regnum)); + else + { + emit_mov_r64_m64(dst, REG_RAX, MBD(REG_RCX, regoffs + 8 * regnum)); + emit_mov_m64_r64(dst, MABS(&m_state.r[regnum].d), REG_RAX); + } + } + + // copy FP registers + regoffs = offsetof(drcuml_machine_state, f); + for (int regnum = 0; regnum < ARRAY_LENGTH(m_state.f); regnum++) + { + if (float_register_map[regnum] != 0) + emit_movsd_r128_m64(dst, float_register_map[regnum], MBD(REG_RCX, regoffs + 8 * regnum)); + else + { + emit_mov_r64_m64(dst, REG_RAX, MBD(REG_RCX, regoffs + 8 * regnum)); + emit_mov_m64_r64(dst, MABS(&m_state.f[regnum].d), REG_RAX); + } + } + + // copy fmod and exp + emit_movzx_r32_m8(dst, REG_EAX, MBD(REG_RCX, offsetof(drcuml_machine_state, fmod)));// movzx eax,state->fmod + emit_and_r32_imm(dst, REG_EAX, 3); // and eax,3 + emit_mov_m8_r8(dst, MABS(&m_state.fmod), REG_AL); // mov [fmod],al + emit_ldmxcsr_m32(dst, MBISD(REG_RBP, REG_RAX, 4, offset_from_rbp(&m_near.ssecontrol[0]))); + emit_mov_r32_m32(dst, REG_EAX, MBD(REG_RCX, offsetof(drcuml_machine_state, exp))); // mov eax,state->exp + emit_mov_m32_r32(dst, MABS(&m_state.exp), REG_EAX); // mov [exp],eax + + // copy flags + emit_movzx_r32_m8(dst, REG_EAX, MBD(REG_RCX, offsetof(drcuml_machine_state, flags)));// movzx eax,state->flags + emit_push_m64(dst, MBISD(REG_RBP, REG_RAX, 8, offset_from_rbp(&m_near.flagsunmap[0]))); + // push flags_unmap[eax*8] + emit_popf(dst); // popf +} + + + +/*************************************************************************** + INTEGER OPERATIONS +***************************************************************************/ + +//------------------------------------------------- +// op_load - process a LOAD opcode +//------------------------------------------------- + +void drcbe_x64::op_load(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_no_condition(inst); + assert_no_flags(inst); + + // normalize parameters + be_parameter dstp(*this, inst.param(0), PTYPE_MR); + be_parameter basep(*this, inst.param(1), PTYPE_M); + be_parameter indp(*this, inst.param(2), PTYPE_MRI); + const parameter &scalesizep = inst.param(3); + assert(scalesizep.is_size_scale()); + int scale = 1 << scalesizep.scale(); + int size = scalesizep.size(); + + // determine the pointer base + INT32 baseoffs; + int basereg = get_base_register_and_offset(dst, basep.memory(), REG_RDX, baseoffs); + + // pick a target register for the general case + int dstreg = dstp.select_register(REG_EAX); + + // immediate index + if (indp.is_immediate()) + { + if (size == SIZE_BYTE) + emit_movzx_r32_m8(dst, dstreg, MBD(basereg, baseoffs + scale*indp.immediate()));// movzx dstreg,[basep + scale*indp] + else if (size == SIZE_WORD) + emit_movzx_r32_m16(dst, dstreg, MBD(basereg, baseoffs + scale*indp.immediate()));// movzx dstreg,[basep + scale*indp] + else if (size == SIZE_DWORD) + emit_mov_r32_m32(dst, dstreg, MBD(basereg, baseoffs + scale*indp.immediate())); // mov dstreg,[basep + scale*indp] + else if (size == SIZE_QWORD) + emit_mov_r64_m64(dst, dstreg, MBD(basereg, baseoffs + scale*indp.immediate())); // mov dstreg,[basep + scale*indp] + } + + // other index + else + { + int indreg = indp.select_register(REG_ECX); + emit_movsx_r64_p32(dst, indreg, indp); + if (size == SIZE_BYTE) + emit_movzx_r32_m8(dst, dstreg, MBISD(basereg, indreg, scale, baseoffs)); // movzx dstreg,[basep + scale*indp] + else if (size == SIZE_WORD) + emit_movzx_r32_m16(dst, dstreg, MBISD(basereg, indreg, scale, baseoffs)); // movzx dstreg,[basep + scale*indp] + else if (size == SIZE_DWORD) + emit_mov_r32_m32(dst, dstreg, MBISD(basereg, indreg, scale, baseoffs)); // mov dstreg,[basep + scale*indp] + else if (size == SIZE_QWORD) + emit_mov_r64_m64(dst, dstreg, MBISD(basereg, indreg, scale, baseoffs)); // mov dstreg,[basep + scale*indp] + } + + // store result + if (inst.size() == 4) + emit_mov_p32_r32(dst, dstp, dstreg); // mov dstp,dstreg + else + emit_mov_p64_r64(dst, dstp, dstreg); // mov dstp,dstreg + +} + + +//------------------------------------------------- +// op_loads - process a LOADS opcode +//------------------------------------------------- + +void drcbe_x64::op_loads(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_no_condition(inst); + assert_no_flags(inst); + + // normalize parameters + be_parameter dstp(*this, inst.param(0), PTYPE_MR); + be_parameter basep(*this, inst.param(1), PTYPE_M); + be_parameter indp(*this, inst.param(2), PTYPE_MRI); + const parameter &scalesizep = inst.param(3); + assert(scalesizep.is_size_scale()); + int scale = 1 << scalesizep.scale(); + int size = scalesizep.size(); + + // determine the pointer base + INT32 baseoffs; + int basereg = get_base_register_and_offset(dst, basep.memory(), REG_RDX, baseoffs); + + // pick a target register for the general case + int dstreg = dstp.select_register(REG_EAX); + + // immediate index + if (indp.is_immediate()) + { + if (inst.size() == 4) + { + if (size == SIZE_BYTE) + emit_movsx_r32_m8(dst, dstreg, MBD(basereg, baseoffs + scale*indp.immediate()));// movsx dstreg,[basep + scale*indp] + else if (size == SIZE_WORD) + emit_movsx_r32_m16(dst, dstreg, MBD(basereg, baseoffs + scale*indp.immediate()));// movsx dstreg,[basep + scale*indp] + else if (size == SIZE_DWORD) + emit_mov_r32_m32(dst, dstreg, MBD(basereg, baseoffs + scale*indp.immediate())); // mov dstreg,[basep + scale*indp] + } + else if (inst.size() == 8) + { + if (size == SIZE_BYTE) + emit_movsx_r64_m8(dst, dstreg, MBD(basereg, baseoffs + scale*indp.immediate()));// movzx dstreg,[basep + scale*indp] + else if (size == SIZE_WORD) + emit_movsx_r64_m16(dst, dstreg, MBD(basereg, baseoffs + scale*indp.immediate()));// movzx dstreg,[basep + scale*indp] + else if (size == SIZE_DWORD) + emit_movsxd_r64_m32(dst, dstreg, MBD(basereg, baseoffs + scale*indp.immediate()));// movsxd dstreg,[basep + scale*indp] + else if (size == SIZE_QWORD) + emit_mov_r64_m64(dst, dstreg, MBD(basereg, baseoffs + scale*indp.immediate())); // mov dstreg,[basep + scale*indp] + } + } + + // other index + else + { + int indreg = indp.select_register(REG_ECX); + emit_movsx_r64_p32(dst, indreg, indp); + if (inst.size() == 4) + { + if (size == SIZE_BYTE) + emit_movsx_r32_m8(dst, dstreg, MBISD(basereg, indreg, scale, baseoffs));// movsx dstreg,[basep + scale*indp] + else if (size == SIZE_WORD) + emit_movsx_r32_m16(dst, dstreg, MBISD(basereg, indreg, scale, baseoffs));// movsx dstreg,[basep + scale*indp] + else if (size == SIZE_DWORD) + emit_mov_r32_m32(dst, dstreg, MBISD(basereg, indreg, scale, baseoffs)); // mov dstreg,[basep + scale*indp] + } + else if (inst.size() == 8) + { + if (size == SIZE_BYTE) + emit_movsx_r64_m8(dst, dstreg, MBISD(basereg, indreg, scale, baseoffs));// movsx dstreg,[basep + scale*indp] + else if (size == SIZE_WORD) + emit_movsx_r64_m16(dst, dstreg, MBISD(basereg, indreg, scale, baseoffs));// movsx dstreg,[basep + scale*indp] + else if (size == SIZE_DWORD) + emit_movsxd_r64_m32(dst, dstreg, MBISD(basereg, indreg, scale, baseoffs));// movsxd dstreg,[basep + scale*indp] + else if (size == SIZE_QWORD) + emit_mov_r64_m64(dst, dstreg, MBISD(basereg, indreg, scale, baseoffs)); // mov dstreg,[basep + scale*indp] + } + } + + // store result + if (inst.size() == 4) + emit_mov_p32_r32(dst, dstp, dstreg); // mov dstp,dstreg + else + emit_mov_p64_r64(dst, dstp, dstreg); // mov dstp,dstreg + +} + + +//------------------------------------------------- +// op_store - process a STORE opcode +//------------------------------------------------- + +void drcbe_x64::op_store(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_no_condition(inst); + assert_no_flags(inst); + + // normalize parameters + be_parameter basep(*this, inst.param(0), PTYPE_M); + be_parameter indp(*this, inst.param(1), PTYPE_MRI); + be_parameter srcp(*this, inst.param(2), PTYPE_MRI); + const parameter &scalesizep = inst.param(3); + int scale = 1 << (scalesizep.scale()); + int size = scalesizep.size(); + + // determine the pointer base + INT32 baseoffs; + int basereg = get_base_register_and_offset(dst, basep.memory(), REG_RDX, baseoffs); + + // pick a source register for the general case + int srcreg = srcp.select_register(REG_EAX); + + // degenerate case: constant index + if (indp.is_immediate()) + { + // immediate source + if (srcp.is_immediate()) + { + if (size == SIZE_BYTE) + emit_mov_m8_imm(dst, MBD(basereg, baseoffs + scale*indp.immediate()), srcp.immediate());// mov [basep + scale*indp],srcp + else if (size == SIZE_WORD) + emit_mov_m16_imm(dst, MBD(basereg, baseoffs + scale*indp.immediate()), srcp.immediate());// mov [basep + scale*indp],srcp + else if (size == SIZE_DWORD) + emit_mov_m32_imm(dst, MBD(basereg, baseoffs + scale*indp.immediate()), srcp.immediate());// mov [basep + scale*indp],srcp + else if (size == SIZE_QWORD) + { + if (short_immediate(srcp.immediate())) + emit_mov_m64_imm(dst, MBD(basereg, baseoffs + scale*indp.immediate()), srcp.immediate());// mov [basep + scale*indp],srcp + else + { + emit_mov_m32_imm(dst, MBD(basereg, baseoffs + scale*indp.immediate()), srcp.immediate());// mov [basep + scale*indp],srcp + emit_mov_m32_imm(dst, MBD(basereg, baseoffs + scale*indp.immediate() + 4), srcp.immediate() >> 32); + // mov [basep + scale*indp + 4],srcp >> 32 + } + } + } + + // variable source + else + { + if (size != SIZE_QWORD) + emit_mov_r32_p32(dst, srcreg, srcp); // mov srcreg,srcp + else + emit_mov_r64_p64(dst, srcreg, srcp); // mov srcreg,srcp + if (size == SIZE_BYTE) + emit_mov_m8_r8(dst, MBD(basereg, baseoffs + scale*indp.immediate()), srcreg); // mov [basep + scale*indp],srcreg + else if (size == SIZE_WORD) + emit_mov_m16_r16(dst, MBD(basereg, baseoffs + scale*indp.immediate()), srcreg); // mov [basep + scale*indp],srcreg + else if (size == SIZE_DWORD) + emit_mov_m32_r32(dst, MBD(basereg, baseoffs + scale*indp.immediate()), srcreg); // mov [basep + scale*indp],srcreg + else if (size == SIZE_QWORD) + emit_mov_m64_r64(dst, MBD(basereg, baseoffs + scale*indp.immediate()), srcreg); // mov [basep + scale*indp],srcreg + } + } + + // normal case: variable index + else + { + int indreg = indp.select_register(REG_ECX); + emit_movsx_r64_p32(dst, indreg, indp); // mov indreg,indp + + // immediate source + if (srcp.is_immediate()) + { + if (size == SIZE_BYTE) + emit_mov_m8_imm(dst, MBISD(basereg, indreg, scale, baseoffs), srcp.immediate());// mov [basep + scale*ecx],srcp + else if (size == SIZE_WORD) + emit_mov_m16_imm(dst, MBISD(basereg, indreg, scale, baseoffs), srcp.immediate());// mov [basep + scale*ecx],srcp + else if (size == SIZE_DWORD) + emit_mov_m32_imm(dst, MBISD(basereg, indreg, scale, baseoffs), srcp.immediate());// mov [basep + scale*ecx],srcp + else if (size == SIZE_QWORD) + { + if (short_immediate(srcp.immediate())) + emit_mov_m64_imm(dst, MBISD(basereg, indreg, scale, baseoffs), srcp.immediate());// mov [basep + scale*indp],srcp + else + { + emit_mov_m32_imm(dst, MBISD(basereg, indreg, scale, baseoffs), srcp.immediate());// mov [basep + scale*ecx],srcp + emit_mov_m32_imm(dst, MBISD(basereg, indreg, scale, baseoffs + 4), srcp.immediate() >> 32); + // mov [basep + scale*ecx + 4],srcp >> 32 + } + } + } + + // variable source + else + { + if (size != SIZE_QWORD) + emit_mov_r32_p32(dst, srcreg, srcp); // mov srcreg,srcp + else + emit_mov_r64_p64(dst, srcreg, srcp); // mov edx:srcreg,srcp + if (size == SIZE_BYTE) + emit_mov_m8_r8(dst, MBISD(basereg, indreg, scale, baseoffs), srcreg); // mov [basep + scale*ecx],srcreg + else if (size == SIZE_WORD) + emit_mov_m16_r16(dst, MBISD(basereg, indreg, scale, baseoffs), srcreg); // mov [basep + scale*ecx],srcreg + else if (size == SIZE_DWORD) + emit_mov_m32_r32(dst, MBISD(basereg, indreg, scale, baseoffs), srcreg); // mov [basep + scale*ecx],srcreg + else if (size == SIZE_QWORD) + emit_mov_m64_r64(dst, MBISD(basereg, indreg, scale, baseoffs), srcreg); // mov [basep + scale*ecx],srcreg + } + } +} + + +//------------------------------------------------- +// op_read - process a READ opcode +//------------------------------------------------- + +void drcbe_x64::op_read(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_no_condition(inst); + assert_no_flags(inst); + + // normalize parameters + be_parameter dstp(*this, inst.param(0), PTYPE_MR); + be_parameter addrp(*this, inst.param(1), PTYPE_MRI); + const parameter &spacesizep = inst.param(2); + assert(spacesizep.is_size_space()); + + // pick a target register for the general case + int dstreg = dstp.select_register(REG_EAX); + + // set up a call to the read byte handler + emit_mov_r64_imm(dst, REG_PARAM1, (FPTR)(m_space[spacesizep.space()])); // mov param1,space + emit_mov_r32_p32(dst, REG_PARAM2, addrp); // mov param2,addrp + if (spacesizep.size() == SIZE_BYTE) + { + emit_smart_call_m64(dst, (x86code **)&m_accessors[spacesizep.space()].read_byte); + // call read_byte + emit_movzx_r32_r8(dst, dstreg, REG_AL); // movzx dstreg,al + } + else if (spacesizep.size() == SIZE_WORD) + { + emit_smart_call_m64(dst, (x86code **)&m_accessors[spacesizep.space()].read_word); + // call read_word + emit_movzx_r32_r16(dst, dstreg, REG_AX); // movzx dstreg,ax + } + else if (spacesizep.size() == SIZE_DWORD) + { + emit_smart_call_m64(dst, (x86code **)&m_accessors[spacesizep.space()].read_dword); + // call read_dword + if (dstreg != REG_EAX || inst.size() == 8) + emit_mov_r32_r32(dst, dstreg, REG_EAX); // mov dstreg,eax + } + else if (spacesizep.size() == SIZE_QWORD) + { + emit_smart_call_m64(dst, (x86code **)&m_accessors[spacesizep.space()].read_qword); + // call read_qword + if (dstreg != REG_RAX) + emit_mov_r64_r64(dst, dstreg, REG_RAX); // mov dstreg,rax + } + + // store result + if (inst.size() == 4) + emit_mov_p32_r32(dst, dstp, dstreg); // mov dstp,dstreg + else + emit_mov_p64_r64(dst, dstp, dstreg); // mov dstp,dstreg +} + + +//------------------------------------------------- +// op_readm - process a READM opcode +//------------------------------------------------- + +void drcbe_x64::op_readm(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_no_condition(inst); + assert_no_flags(inst); + + // normalize parameters + be_parameter dstp(*this, inst.param(0), PTYPE_MR); + be_parameter addrp(*this, inst.param(1), PTYPE_MRI); + be_parameter maskp(*this, inst.param(2), PTYPE_MRI); + const parameter &spacesizep = inst.param(3); + assert(spacesizep.is_size_space()); + + // pick a target register for the general case + int dstreg = dstp.select_register(REG_EAX); + + // set up a call to the read byte handler + emit_mov_r64_imm(dst, REG_PARAM1, (FPTR)(m_space[spacesizep.space()])); // mov param1,space + emit_mov_r32_p32(dst, REG_PARAM2, addrp); // mov param2,addrp + if (spacesizep.size() != SIZE_QWORD) + emit_mov_r32_p32(dst, REG_PARAM3, maskp); // mov param3,maskp + else + emit_mov_r64_p64(dst, REG_PARAM3, maskp); // mov param3,maskp + if (spacesizep.size() == SIZE_WORD) + { + emit_smart_call_m64(dst, (x86code **)&m_accessors[spacesizep.space()].read_word_masked); + // call read_word_masked + emit_movzx_r32_r16(dst, dstreg, REG_AX); // movzx dstreg,ax + } + else if (spacesizep.size() == SIZE_DWORD) + { + emit_smart_call_m64(dst, (x86code **)&m_accessors[spacesizep.space()].read_dword_masked); + // call read_dword_masked + if (dstreg != REG_EAX || inst.size() == 8) + emit_mov_r32_r32(dst, dstreg, REG_EAX); // mov dstreg,eax + } + else if (spacesizep.size() == SIZE_QWORD) + { + emit_smart_call_m64(dst, (x86code **)&m_accessors[spacesizep.space()].read_qword_masked); + // call read_qword_masked + if (dstreg != REG_RAX) + emit_mov_r64_r64(dst, dstreg, REG_RAX); // mov dstreg,rax + } + + // store result + if (inst.size() == 4) + emit_mov_p32_r32(dst, dstp, dstreg); // mov dstp,dstreg + else + emit_mov_p64_r64(dst, dstp, dstreg); // mov dstp,dstreg +} + + +//------------------------------------------------- +// op_write - process a WRITE opcode +//------------------------------------------------- + +void drcbe_x64::op_write(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_no_condition(inst); + assert_no_flags(inst); + + // normalize parameters + be_parameter addrp(*this, inst.param(0), PTYPE_MRI); + be_parameter srcp(*this, inst.param(1), PTYPE_MRI); + const parameter &spacesizep = inst.param(2); + assert(spacesizep.is_size_space()); + + // set up a call to the write byte handler + emit_mov_r64_imm(dst, REG_PARAM1, (FPTR)(m_space[spacesizep.space()])); // mov param1,space + emit_mov_r32_p32(dst, REG_PARAM2, addrp); // mov param2,addrp + if (spacesizep.size() != SIZE_QWORD) + emit_mov_r32_p32(dst, REG_PARAM3, srcp); // mov param3,srcp + else + emit_mov_r64_p64(dst, REG_PARAM3, srcp); // mov param3,srcp + if (spacesizep.size() == SIZE_BYTE) + emit_smart_call_m64(dst, (x86code **)&m_accessors[spacesizep.space()].write_byte); + // call write_byte + else if (spacesizep.size() == SIZE_WORD) + emit_smart_call_m64(dst, (x86code **)&m_accessors[spacesizep.space()].write_word); + // call write_word + else if (spacesizep.size() == SIZE_DWORD) + emit_smart_call_m64(dst, (x86code **)&m_accessors[spacesizep.space()].write_dword); + // call write_dword + else if (spacesizep.size() == SIZE_QWORD) + emit_smart_call_m64(dst, (x86code **)&m_accessors[spacesizep.space()].write_qword); + // call write_qword +} + + +//------------------------------------------------- +// op_writem - process a WRITEM opcode +//------------------------------------------------- + +void drcbe_x64::op_writem(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_no_condition(inst); + assert_no_flags(inst); + + // normalize parameters + be_parameter addrp(*this, inst.param(0), PTYPE_MRI); + be_parameter srcp(*this, inst.param(1), PTYPE_MRI); + be_parameter maskp(*this, inst.param(2), PTYPE_MRI); + const parameter &spacesizep = inst.param(3); + assert(spacesizep.is_size_space()); + + // set up a call to the write byte handler + emit_mov_r64_imm(dst, REG_PARAM1, (FPTR)(m_space[spacesizep.space()])); // mov param1,space + emit_mov_r32_p32(dst, REG_PARAM2, addrp); // mov param2,addrp + if (spacesizep.size() != SIZE_QWORD) + { + emit_mov_r32_p32(dst, REG_PARAM3, srcp); // mov param3,srcp + emit_mov_r32_p32(dst, REG_PARAM4, maskp); // mov param4,maskp + } + else + { + emit_mov_r64_p64(dst, REG_PARAM3, srcp); // mov param3,srcp + emit_mov_r64_p64(dst, REG_PARAM4, maskp); // mov param4,maskp + } + if (spacesizep.size() == SIZE_WORD) + emit_smart_call_m64(dst, (x86code **)&m_accessors[spacesizep.space()].write_word_masked); + // call write_word_masked + else if (spacesizep.size() == SIZE_DWORD) + emit_smart_call_m64(dst, (x86code **)&m_accessors[spacesizep.space()].write_dword_masked); + // call write_dword_masked + else if (spacesizep.size() == SIZE_QWORD) + emit_smart_call_m64(dst, (x86code **)&m_accessors[spacesizep.space()].write_qword_masked); + // call write_qword_masked +} + + +//------------------------------------------------- +// op_carry - process a CARRY opcode +//------------------------------------------------- + +void drcbe_x64::op_carry(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_no_condition(inst); + assert_flags(inst, FLAG_C); + + // normalize parameters + be_parameter srcp(*this, inst.param(0), PTYPE_MRI); + be_parameter bitp(*this, inst.param(1), PTYPE_MRI); + + // degenerate case: source is immediate + if (srcp.is_immediate() && bitp.is_immediate()) + { + if (srcp.immediate() & ((UINT64)1 << bitp.immediate())) + emit_stc(dst); + else + emit_clc(dst); + } + + // load non-immediate bit numbers into a register + if (!bitp.is_immediate()) + { + emit_mov_r32_p32(dst, REG_ECX, bitp); + emit_and_r32_imm(dst, REG_ECX, inst.size() * 8 - 1); + } + + // 32-bit form + if (inst.size() == 4) + { + if (bitp.is_immediate()) + { + if (srcp.is_memory()) + emit_bt_m32_imm(dst, MABS(srcp.memory()), bitp.immediate()); // bt [srcp],bitp + else if (srcp.is_int_register()) + emit_bt_r32_imm(dst, srcp.ireg(), bitp.immediate()); // bt srcp,bitp + } + else + { + if (srcp.is_memory()) + emit_bt_m32_r32(dst, MABS(srcp.memory()), REG_ECX); // bt [srcp],ecx + else if (srcp.is_int_register()) + emit_bt_r32_r32(dst, srcp.ireg(), REG_ECX); // bt srcp,ecx + } + } + + // 64-bit form + else + { + if (bitp.is_immediate()) + { + if (srcp.is_memory()) + emit_bt_m64_imm(dst, MABS(srcp.memory()), bitp.immediate()); // bt [srcp],bitp + else if (srcp.is_int_register()) + emit_bt_r64_imm(dst, srcp.ireg(), bitp.immediate()); // bt srcp,bitp + } + else + { + if (srcp.is_memory()) + emit_bt_m64_r64(dst, MABS(srcp.memory()), REG_ECX); // bt [srcp],ecx + else if (srcp.is_int_register()) + emit_bt_r64_r64(dst, srcp.ireg(), REG_ECX); // bt srcp,ecx + } + } +} + + +//------------------------------------------------- +// op_set - process a SET opcode +//------------------------------------------------- + +void drcbe_x64::op_set(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_any_condition(inst); + assert_no_flags(inst); + + // normalize parameters + be_parameter dstp(*this, inst.param(0), PTYPE_MR); + + // pick a target register for the general case + int dstreg = dstp.select_register(REG_EAX); + + // set to AL + emit_setcc_r8(dst, X86_CONDITION(inst.condition()), REG_AL); // setcc al + emit_movzx_r32_r8(dst, dstreg, REG_AL); // movzx dstreg,al + + // 32-bit form + if (inst.size() == 4) + emit_mov_p32_r32(dst, dstp, dstreg); // mov dstp,dstreg + + // 64-bit form + else if (inst.size() == 8) + emit_mov_p64_r64(dst, dstp, dstreg); // mov dstp,dstreg + +} + + +//------------------------------------------------- +// op_mov - process a MOV opcode +//------------------------------------------------- + +void drcbe_x64::op_mov(x86code *&dst, const instruction &inst) +{ + x86code *savedst = dst; + + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_any_condition(inst); + assert_no_flags(inst); + + // normalize parameters + be_parameter dstp(*this, inst.param(0), PTYPE_MR); + be_parameter srcp(*this, inst.param(1), PTYPE_MRI); + + // pick a target register for the general case + int dstreg = dstp.select_register(REG_EAX); + + // always start with a jmp + emit_link skip = { 0 }; + if (inst.condition() != uml::COND_ALWAYS) + emit_jcc_short_link(dst, X86_NOT_CONDITION(inst.condition()), skip); // jcc skip + + // 32-bit form + if (inst.size() == 4) + { + // register to memory + if (dstp.is_memory() && srcp.is_int_register()) + emit_mov_m32_r32(dst, MABS(dstp.memory()), srcp.ireg()); // mov [dstp],srcp + + // immediate to memory + else if (dstp.is_memory() && srcp.is_immediate()) + emit_mov_m32_imm(dst, MABS(dstp.memory()), srcp.immediate()); // mov [dstp],srcp + + // conditional memory to register + else if (inst.condition() != 0 && dstp.is_int_register() && srcp.is_memory()) + { + dst = savedst; + skip.target = NULL; + emit_cmovcc_r32_m32(dst, X86_CONDITION(inst.condition()), dstp.ireg(), MABS(srcp.memory())); + // cmovcc dstp,[srcp] + } + + // conditional register to register + else if (inst.condition() != 0 && dstp.is_int_register() && srcp.is_int_register()) + { + dst = savedst; + skip.target = NULL; + emit_cmovcc_r32_r32(dst, X86_CONDITION(inst.condition()), dstp.ireg(), srcp.ireg()); + // cmovcc dstp,srcp + } + + // general case + else + { + emit_mov_r32_p32_keepflags(dst, dstreg, srcp); // mov dstreg,srcp + emit_mov_p32_r32(dst, dstp, dstreg); // mov dstp,dstreg + } + } + + // 64-bit form + else if (inst.size() == 8) + { + // register to memory + if (dstp.is_memory() && srcp.is_int_register()) + emit_mov_m64_r64(dst, MABS(dstp.memory()), srcp.ireg()); // mov [dstp],srcp + + // immediate to memory + else if (dstp.is_memory() && srcp.is_immediate() && short_immediate(srcp.immediate())) + emit_mov_m64_imm(dst, MABS(dstp.memory()), srcp.immediate()); // mov [dstp],srcp + + // conditional memory to register + else if (inst.condition() != 0 && dstp.is_int_register() && srcp.is_memory()) + { + dst = savedst; + skip.target = NULL; + emit_cmovcc_r64_m64(dst, X86_CONDITION(inst.condition()), dstp.ireg(), MABS(srcp.memory())); + // cmovcc dstp,[srcp] + } + + // conditional register to register + else if (inst.condition() != 0 && dstp.is_int_register() && srcp.is_int_register()) + { + dst = savedst; + skip.target = NULL; + emit_cmovcc_r64_r64(dst, X86_CONDITION(inst.condition()), dstp.ireg(), srcp.ireg()); + // cmovcc dstp,srcp + } + + // general case + else + { + emit_mov_r64_p64_keepflags(dst, dstreg, srcp); // mov dstreg,srcp + emit_mov_p64_r64(dst, dstp, dstreg); // mov dstp,dstreg + } + } + + // resolve the jump + if (skip.target != NULL) + resolve_link(dst, skip); +} + + +//------------------------------------------------- +// op_sext - process a SEXT opcode +//------------------------------------------------- + +void drcbe_x64::op_sext(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_no_condition(inst); + assert_flags(inst, FLAG_S | FLAG_Z); + + // normalize parameters + be_parameter dstp(*this, inst.param(0), PTYPE_MR); + be_parameter srcp(*this, inst.param(1), PTYPE_MRI); + const parameter &sizep = inst.param(2); + assert(sizep.is_size()); + + // pick a target register for the general case + int dstreg = dstp.select_register(REG_EAX); + + // 32-bit form + if (inst.size() == 4) + { + // general case + if (srcp.is_memory()) + { + if (sizep.size() == SIZE_BYTE) + emit_movsx_r32_m8(dst, dstreg, MABS(srcp.memory())); // movsx dstreg,[srcp] + else if (sizep.size() == SIZE_WORD) + emit_movsx_r32_m16(dst, dstreg, MABS(srcp.memory())); // movsx dstreg,[srcp] + else if (sizep.size() == SIZE_DWORD) + emit_mov_r32_m32(dst, dstreg, MABS(srcp.memory())); // mov dstreg,[srcp] + } + else if (srcp.is_int_register()) + { + if (sizep.size() == SIZE_BYTE) + emit_movsx_r32_r8(dst, dstreg, srcp.ireg()); // movsx dstreg,srcp + else if (sizep.size() == SIZE_WORD) + emit_movsx_r32_r16(dst, dstreg, srcp.ireg()); // movsx dstreg,srcp + else if (sizep.size() == SIZE_DWORD) + emit_mov_r32_r32(dst, dstreg, srcp.ireg()); // mov dstreg,srcp + } + emit_mov_p32_r32(dst, dstp, dstreg); // mov dstp,dstreg + if (inst.flags() != 0) + emit_test_r32_r32(dst, dstreg, dstreg); // test dstreg,dstreg + } + + // 64-bit form + else if (inst.size() == 8) + { + // general case + if (srcp.is_memory()) + { + if (sizep.size() == SIZE_BYTE) + emit_movsx_r64_m8(dst, dstreg, MABS(srcp.memory())); // movsx dstreg,[srcp] + else if (sizep.size() == SIZE_WORD) + emit_movsx_r64_m16(dst, dstreg, MABS(srcp.memory())); // movsx dstreg,[srcp] + else if (sizep.size() == SIZE_DWORD) + emit_movsxd_r64_m32(dst, dstreg, MABS(srcp.memory())); // movsxd dstreg,[srcp] + else if (sizep.size() == SIZE_QWORD) + emit_mov_r64_m64(dst, dstreg, MABS(srcp.memory())); // mov dstreg,[srcp] + } + else if (srcp.is_int_register()) + { + if (sizep.size() == SIZE_BYTE) + emit_movsx_r64_r8(dst, dstreg, srcp.ireg()); // movsx dstreg,srcp + else if (sizep.size() == SIZE_WORD) + emit_movsx_r64_r16(dst, dstreg, srcp.ireg()); // movsx dstreg,srcp + else if (sizep.size() == SIZE_DWORD) + emit_movsxd_r64_r32(dst, dstreg, srcp.ireg()); // movsxd dstreg,srcp + else if (sizep.size() == SIZE_QWORD) + emit_mov_r64_r64(dst, dstreg, srcp.ireg()); // mov dstreg,srcp + } + emit_mov_p64_r64(dst, dstp, dstreg); // mov dstp,dstreg + if (inst.flags() != 0) + emit_test_r64_r64(dst, dstreg, dstreg); // test dstreg,dstreg + } +} + + +//------------------------------------------------- +// op_roland - process an ROLAND opcode +//------------------------------------------------- + +void drcbe_x64::op_roland(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_no_condition(inst); + assert_flags(inst, FLAG_S | FLAG_Z); + + // normalize parameters + be_parameter dstp(*this, inst.param(0), PTYPE_MR); + be_parameter srcp(*this, inst.param(1), PTYPE_MRI); + be_parameter shiftp(*this, inst.param(2), PTYPE_MRI); + be_parameter maskp(*this, inst.param(3), PTYPE_MRI); + + // pick a target register for the general case + int dstreg = dstp.select_register(REG_EAX, shiftp, maskp); + + // 32-bit form + if (inst.size() == 4) + { + emit_mov_r32_p32(dst, dstreg, srcp); // mov dstreg,srcp + emit_rol_r32_p32(dst, dstreg, shiftp, inst); // rol dstreg,shiftp + emit_and_r32_p32(dst, dstreg, maskp, inst); // and dstreg,maskp + emit_mov_p32_r32(dst, dstp, dstreg); // mov dstp,dstreg + } + + // 64-bit form + else if (inst.size() == 8) + { + emit_mov_r64_p64(dst, dstreg, srcp); // mov dstreg,srcp + emit_rol_r64_p64(dst, dstreg, shiftp, inst); // rol dstreg,shiftp + emit_and_r64_p64(dst, dstreg, maskp, inst); // and dstreg,maskp + emit_mov_p64_r64(dst, dstp, dstreg); // mov dstp,dstreg + } +} + + +//------------------------------------------------- +// op_rolins - process an ROLINS opcode +//------------------------------------------------- + +void drcbe_x64::op_rolins(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_no_condition(inst); + assert_flags(inst, FLAG_S | FLAG_Z); + + // normalize parameters + be_parameter dstp(*this, inst.param(0), PTYPE_MR); + be_parameter srcp(*this, inst.param(1), PTYPE_MRI); + be_parameter shiftp(*this, inst.param(2), PTYPE_MRI); + be_parameter maskp(*this, inst.param(3), PTYPE_MRI); + + // pick a target register for the general case + int dstreg = dstp.select_register(REG_ECX, shiftp, maskp); + + // 32-bit form + if (inst.size() == 4) + { + emit_mov_r32_p32(dst, REG_EAX, srcp); // mov eax,srcp + emit_rol_r32_p32(dst, REG_EAX, shiftp, inst); // rol eax,shiftp + emit_mov_r32_p32(dst, dstreg, dstp); // mov dstreg,dstp + if (maskp.is_immediate()) + { + emit_and_r32_imm(dst, REG_EAX, maskp.immediate()); // and eax,maskp + emit_and_r32_imm(dst, dstreg, ~maskp.immediate()); // and dstreg,~maskp + } + else + { + emit_mov_r32_p32(dst, REG_EDX, maskp); // mov edx,maskp + emit_and_r32_r32(dst, REG_EAX, REG_EDX); // and eax,edx + emit_not_r32(dst, REG_EDX); // not edx + emit_and_r32_r32(dst, dstreg, REG_EDX); // and dstreg,edx + } + emit_or_r32_r32(dst, dstreg, REG_EAX); // or dstreg,eax + emit_mov_p32_r32(dst, dstp, dstreg); // mov dstp,dstreg + } + + // 64-bit form + else if (inst.size() == 8) + { + emit_mov_r64_p64(dst, REG_RAX, srcp); // mov rax,srcp + emit_mov_r64_p64(dst, REG_RDX, maskp); // mov rdx,maskp + emit_rol_r64_p64(dst, REG_RAX, shiftp, inst); // rol rax,shiftp + emit_mov_r64_p64(dst, dstreg, dstp); // mov dstreg,dstp + emit_and_r64_r64(dst, REG_RAX, REG_RDX); // and eax,rdx + emit_not_r64(dst, REG_RDX); // not rdx + emit_and_r64_r64(dst, dstreg, REG_RDX); // and dstreg,rdx + emit_or_r64_r64(dst, dstreg, REG_RAX); // or dstreg,rax + emit_mov_p64_r64(dst, dstp, dstreg); // mov dstp,dstreg + } +} + + +//------------------------------------------------- +// op_add - process a ADD opcode +//------------------------------------------------- + +void drcbe_x64::op_add(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_no_condition(inst); + assert_flags(inst, FLAG_C | FLAG_V | FLAG_Z | FLAG_S); + + // normalize parameters + be_parameter dstp(*this, inst.param(0), PTYPE_MR); + be_parameter src1p(*this, inst.param(1), PTYPE_MRI); + be_parameter src2p(*this, inst.param(2), PTYPE_MRI); + normalize_commutative(src1p, src2p); + + // pick a target register for the general case + int dstreg = dstp.select_register(REG_EAX, src2p); + + // 32-bit form + if (inst.size() == 4) + { + // dstp == src1p in memory + if (dstp.is_memory() && dstp == src1p) + emit_add_m32_p32(dst, MABS(dstp.memory()), src2p, inst); // add [dstp],src2p + + // reg = reg + imm + else if (dstp.is_int_register() && src1p.is_int_register() && src2p.is_immediate() && inst.flags() == 0) + emit_lea_r32_m32(dst, dstp.ireg(), MBD(src1p.ireg(), src2p.immediate())); // lea dstp,[src1p+src2p] + + // reg = reg + reg + else if (dstp.is_int_register() && src1p.is_int_register() && src2p.is_int_register() && inst.flags() == 0) + emit_lea_r32_m32(dst, dstp.ireg(), MBISD(src1p.ireg(), src2p.ireg(), 1, 0));// lea dstp,[src1p+src2p] + + // general case + else + { + emit_mov_r32_p32(dst, dstreg, src1p); // mov dstreg,src1p + emit_add_r32_p32(dst, dstreg, src2p, inst); // add dstreg,src2p + emit_mov_p32_r32(dst, dstp, dstreg); // mov dstp,dstreg + } + } + + // 64-bit form + else if (inst.size() == 8) + { + // dstp == src1p in memory + if (dstp.is_memory() && dstp == src1p) + emit_add_m64_p64(dst, MABS(dstp.memory()), src2p, inst); // add [dstp],src2p + + // reg = reg + imm + else if (dstp.is_int_register() && src1p.is_int_register() && src2p.is_immediate() && short_immediate(src2p.immediate()) && inst.flags() == 0) + emit_lea_r64_m64(dst, dstp.ireg(), MBD(src1p.ireg(), src2p.immediate())); // lea dstp,[src1p+src2p] + + // reg = reg + reg + else if (dstp.is_int_register() && src1p.is_int_register() && src2p.is_int_register() && inst.flags() == 0) + emit_lea_r64_m64(dst, dstp.ireg(), MBISD(src1p.ireg(), src2p.ireg(), 1, 0));// lea dstp,[src1p+src2p] + + // general case + else + { + emit_mov_r64_p64(dst, dstreg, src1p); // mov dstreg,src1p + emit_add_r64_p64(dst, dstreg, src2p, inst); // add dstreg,src2p + emit_mov_p64_r64(dst, dstp, dstreg); // mov dstp,dstreg + } + } +} + + +//------------------------------------------------- +// op_addc - process a ADDC opcode +//------------------------------------------------- + +void drcbe_x64::op_addc(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_no_condition(inst); + assert_flags(inst, FLAG_C | FLAG_V | FLAG_Z | FLAG_S); + + // normalize parameters + be_parameter dstp(*this, inst.param(0), PTYPE_MR); + be_parameter src1p(*this, inst.param(1), PTYPE_MRI); + be_parameter src2p(*this, inst.param(2), PTYPE_MRI); + normalize_commutative(src1p, src2p); + + // pick a target register for the general case + int dstreg = dstp.select_register(REG_EAX, src2p); + + // 32-bit form + if (inst.size() == 4) + { + // dstp == src1p in memory + if (dstp.is_memory() && dstp == src1p) + emit_adc_m32_p32(dst, MABS(dstp.memory()), src2p, inst); // adc [dstp],src2p + + // general case + else + { + emit_mov_r32_p32_keepflags(dst, dstreg, src1p); // mov dstreg,src1p + emit_adc_r32_p32(dst, dstreg, src2p, inst); // adc dstreg,src2p + emit_mov_p32_r32(dst, dstp, dstreg); // mov dstp,dstreg + } + } + + // 64-bit form + else if (inst.size() == 8) + { + // dstp == src1p in memory + if (dstp.is_memory() && dstp == src1p) + emit_adc_m64_p64(dst, MABS(dstp.memory()), src2p, inst); // adc [dstp],src2p + + // general case + else + { + emit_mov_r64_p64_keepflags(dst, dstreg, src1p); // mov dstreg,src1p + emit_adc_r64_p64(dst, dstreg, src2p, inst); // adc dstreg,src2p + emit_mov_p64_r64(dst, dstp, dstreg); // mov dstp,dstreg + } + } +} + + +//------------------------------------------------- +// op_sub - process a SUB opcode +//------------------------------------------------- + +void drcbe_x64::op_sub(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_no_condition(inst); + assert_flags(inst, FLAG_C | FLAG_V | FLAG_Z | FLAG_S); + + // normalize parameters + be_parameter dstp(*this, inst.param(0), PTYPE_MR); + be_parameter src1p(*this, inst.param(1), PTYPE_MRI); + be_parameter src2p(*this, inst.param(2), PTYPE_MRI); + + // pick a target register for the general case + int dstreg = dstp.select_register(REG_EAX, src2p); + + // 32-bit form + if (inst.size() == 4) + { + // dstp == src1p in memory + if (dstp.is_memory() && dstp == src1p) + emit_sub_m32_p32(dst, MABS(dstp.memory()), src2p, inst); // sub [dstp],src2p + + // reg = reg - imm + else if (dstp.is_int_register() && src1p.is_int_register() && src2p.is_immediate() && inst.flags() == 0) + emit_lea_r32_m32(dst, dstp.ireg(), MBD(src1p.ireg(), -src2p.immediate())); // lea dstp,[src1p-src2p] + + // general case + else + { + emit_mov_r32_p32(dst, dstreg, src1p); // mov dstreg,src1p + emit_sub_r32_p32(dst, dstreg, src2p, inst); // sub dstreg,src2p + emit_mov_p32_r32(dst, dstp, dstreg); // mov dstp,dstreg + } + } + + // 64-bit form + else if (inst.size() == 8) + { + // dstp == src1p in memory + if (dstp.is_memory() && dstp == src1p) + emit_sub_m64_p64(dst, MABS(dstp.memory()), src2p, inst); // sub [dstp],src2p + + // reg = reg - imm + else if (dstp.is_int_register() && src1p.is_int_register() && src2p.is_immediate() && short_immediate(src2p.immediate()) && inst.flags() == 0) + emit_lea_r64_m64(dst, dstp.ireg(), MBD(src1p.ireg(), -src2p.immediate())); // lea dstp,[src1p-src2p] + + // general case + else + { + emit_mov_r64_p64(dst, dstreg, src1p); // mov dstreg,src1p + emit_sub_r64_p64(dst, dstreg, src2p, inst); // sub dstreg,src2p + emit_mov_p64_r64(dst, dstp, dstreg); // mov dstp,dstreg + } + } +} + + +//------------------------------------------------- +// op_subc - process a SUBC opcode +//------------------------------------------------- + +void drcbe_x64::op_subc(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_no_condition(inst); + assert_flags(inst, FLAG_C | FLAG_V | FLAG_Z | FLAG_S); + + // normalize parameters + be_parameter dstp(*this, inst.param(0), PTYPE_MR); + be_parameter src1p(*this, inst.param(1), PTYPE_MRI); + be_parameter src2p(*this, inst.param(2), PTYPE_MRI); + + // pick a target register for the general case + int dstreg = dstp.select_register(REG_EAX, src2p); + + // 32-bit form + if (inst.size() == 4) + { + // dstp == src1p in memory + if (dstp.is_memory() && dstp == src1p) + emit_sbb_m32_p32(dst, MABS(dstp.memory()), src2p, inst); // sbb [dstp],src2p + + // general case + else + { + emit_mov_r32_p32_keepflags(dst, dstreg, src1p); // mov dstreg,src1p + emit_sbb_r32_p32(dst, dstreg, src2p, inst); // sbb dstreg,src2p + emit_mov_p32_r32(dst, dstp, dstreg); // mov dstp,dstreg + } + } + + // 64-bit form + else if (inst.size() == 8) + { + // dstp == src1p in memory + if (dstp.is_memory() && dstp == src1p) + emit_sbb_m64_p64(dst, MABS(dstp.memory()), src2p, inst); // sbb [dstp],src2p + + // general case + else + { + emit_mov_r64_p64_keepflags(dst, dstreg, src1p); // mov dstreg,src1p + emit_sbb_r64_p64(dst, dstreg, src2p, inst); // sbb dstreg,src2p + emit_mov_p64_r64(dst, dstp, dstreg); // mov dstp,dstreg + } + } +} + + +//------------------------------------------------- +// op_cmp - process a CMP opcode +//------------------------------------------------- + +void drcbe_x64::op_cmp(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_no_condition(inst); + assert_flags(inst, FLAG_C | FLAG_V | FLAG_Z | FLAG_S); + + // normalize parameters + be_parameter src1p(*this, inst.param(0), PTYPE_MRI); + be_parameter src2p(*this, inst.param(1), PTYPE_MRI); + + // pick a target register for the general case + int src1reg = src1p.select_register(REG_EAX); + + // 32-bit form + if (inst.size() == 4) + { + // memory versus anything + if (src1p.is_memory()) + emit_cmp_m32_p32(dst, MABS(src1p.memory()), src2p, inst); // cmp [dstp],src2p + + // general case + else + { + if (src1p.is_immediate()) + emit_mov_r32_imm(dst, src1reg, src1p.immediate()); // mov src1reg,imm + emit_cmp_r32_p32(dst, src1reg, src2p, inst); // cmp src1reg,src2p + } + } + + // 64-bit form + else + { + // memory versus anything + if (src1p.is_memory()) + emit_cmp_m64_p64(dst, MABS(src1p.memory()), src2p, inst); // cmp [dstp],src2p + + // general case + else + { + if (src1p.is_immediate()) + emit_mov_r64_imm(dst, src1reg, src1p.immediate()); // mov src1reg,imm + emit_cmp_r64_p64(dst, src1reg, src2p, inst); // cmp src1reg,src2p + } + } +} + + +//------------------------------------------------- +// op_mulu - process a MULU opcode +//------------------------------------------------- + +void drcbe_x64::op_mulu(x86code *&dst, const instruction &inst) +{ + UINT8 zsflags = inst.flags() & (FLAG_Z | FLAG_S); + UINT8 vflag = inst.flags() & FLAG_V; + + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_no_condition(inst); + assert_flags(inst, FLAG_V | FLAG_Z | FLAG_S); + + // normalize parameters + be_parameter dstp(*this, inst.param(0), PTYPE_MR); + be_parameter edstp(*this, inst.param(1), PTYPE_MR); + be_parameter src1p(*this, inst.param(2), PTYPE_MRI); + be_parameter src2p(*this, inst.param(3), PTYPE_MRI); + normalize_commutative(src1p, src2p); + bool compute_hi = (dstp != edstp); + + // 32-bit form + if (inst.size() == 4) + { + // general case + emit_mov_r32_p32(dst, REG_EAX, src1p); // mov eax,src1p + if (src2p.is_memory()) + emit_mul_m32(dst, MABS(src2p.memory())); // mul [src2p] + else if (src2p.is_int_register()) + emit_mul_r32(dst, src2p.ireg()); // mul src2p + else if (src2p.is_immediate()) + { + emit_mov_r32_imm(dst, REG_EDX, src2p.immediate()); // mov edx,src2p + emit_mul_r32(dst, REG_EDX); // mul edx + } + emit_mov_p32_r32(dst, dstp, REG_EAX); // mov dstp,eax + if (compute_hi) + emit_mov_p32_r32(dst, edstp, REG_EDX); // mov edstp,edx + + // compute flags + if (inst.flags() != 0) + { + if (zsflags != 0) + { + if (vflag) + emit_pushf(dst); // pushf + if (compute_hi) + { + if (zsflags == FLAG_Z) + emit_or_r32_r32(dst, REG_EDX, REG_EAX); // or edx,eax + else if (zsflags == FLAG_S) + emit_test_r32_r32(dst, REG_EDX, REG_EDX); // test edx,edx + else + { + emit_movzx_r32_r16(dst, REG_ECX, REG_AX); // movzx ecx,ax + emit_shr_r32_imm(dst, REG_EAX, 16); // shr eax,16 + emit_or_r32_r32(dst, REG_EDX, REG_ECX); // or edx,ecx + emit_or_r32_r32(dst, REG_EDX, REG_EAX); // or edx,eax + } + } + else + emit_test_r32_r32(dst, REG_EAX, REG_EAX); // test eax,eax + + // we rely on the fact that OF is cleared by all logical operations above + if (vflag) + { + emit_pushf(dst); // pushf + emit_pop_r64(dst, REG_RAX); // pop rax + emit_and_m64_imm(dst, MBD(REG_RSP, 0), ~0x84); // and [rsp],~0x84 + emit_or_m64_r64(dst, MBD(REG_RSP, 0), REG_RAX); // or [rsp],rax + emit_popf(dst); // popf + } + } + } + } + + // 64-bit form + else if (inst.size() == 8) + { + // general case + emit_mov_r64_p64(dst, REG_RAX, src1p); // mov rax,src1p + if (src2p.is_memory()) + emit_mul_m64(dst, MABS(src2p.memory())); // mul [src2p] + else if (src2p.is_int_register()) + emit_mul_r64(dst, src2p.ireg()); // mul src2p + else if (src2p.is_immediate()) + { + emit_mov_r64_imm(dst, REG_RDX, src2p.immediate()); // mov rdx,src2p + emit_mul_r64(dst, REG_RDX); // mul rdx + } + emit_mov_p64_r64(dst, dstp, REG_RAX); // mov dstp,rax + if (compute_hi) + emit_mov_p64_r64(dst, edstp, REG_RDX); // mov edstp,rdx + + // compute flags + if (inst.flags() != 0) + { + if (zsflags != 0) + { + if (vflag) + emit_pushf(dst); // pushf + if (compute_hi) + { + if (zsflags == FLAG_Z) + emit_or_r64_r64(dst, REG_RDX, REG_RAX); // or rdx,rax + else if (zsflags == FLAG_S) + emit_test_r64_r64(dst, REG_RDX, REG_RDX); // test rdx,rdx + else + { + emit_mov_r32_r32(dst, REG_ECX, REG_EAX); // mov ecx,eax + emit_shr_r64_imm(dst, REG_RAX, 32); // shr rax,32 + emit_or_r64_r64(dst, REG_RDX, REG_RCX); // or rdx,rcx + emit_or_r64_r64(dst, REG_RDX, REG_RAX); // or rdx,rax + } + } + else + emit_test_r64_r64(dst, REG_RAX, REG_RAX); // test rax,rax + + // we rely on the fact that OF is cleared by all logical operations above + if (vflag) + { + emit_pushf(dst); // pushf + emit_pop_r64(dst, REG_RAX); // pop rax + emit_and_m64_imm(dst, MBD(REG_RSP, 0), ~0x84); // and [rsp],~0x84 + emit_or_m64_r64(dst, MBD(REG_RSP, 0), REG_RAX); // or [rsp],rax + emit_popf(dst); // popf + } + } + } + } +} + + +//------------------------------------------------- +// op_muls - process a MULS opcode +//------------------------------------------------- + +void drcbe_x64::op_muls(x86code *&dst, const instruction &inst) +{ + UINT8 zsflags = inst.flags() & (FLAG_Z | FLAG_S); + UINT8 vflag = inst.flags() & FLAG_V; + + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_no_condition(inst); + assert_flags(inst, FLAG_V | FLAG_Z | FLAG_S); + + // normalize parameters + be_parameter dstp(*this, inst.param(0), PTYPE_MR); + be_parameter edstp(*this, inst.param(1), PTYPE_MR); + be_parameter src1p(*this, inst.param(2), PTYPE_MRI); + be_parameter src2p(*this, inst.param(3), PTYPE_MRI); + normalize_commutative(src1p, src2p); + bool compute_hi = (dstp != edstp); + + // 32-bit form + if (inst.size() == 4) + { + // 32-bit destination with memory/immediate or register/immediate + if (!compute_hi && !src1p.is_immediate() && src2p.is_immediate()) + { + if (src1p.is_memory()) + emit_imul_r32_m32_imm(dst, REG_EAX, MABS(src1p.memory()), src2p.immediate()); // imul eax,[src1p],src2p + else if (src1p.is_int_register()) + emit_imul_r32_r32_imm(dst, REG_EAX, src1p.ireg(), src2p.immediate()); // imul eax,src1p,src2p + emit_mov_p32_r32(dst, dstp, REG_EAX); // mov dstp,eax + } + + // 32-bit destination, general case + else if (!compute_hi) + { + emit_mov_r32_p32(dst, REG_EAX, src1p); // mov eax,src1p + if (src2p.is_memory()) + emit_imul_r32_m32(dst, REG_EAX, MABS(src2p.memory())); // imul eax,[src2p] + else if (src2p.is_int_register()) + emit_imul_r32_r32(dst, REG_EAX, src2p.ireg()); // imul eax,src2p + emit_mov_p32_r32(dst, dstp, REG_EAX); // mov dstp,eax + } + + // 64-bit destination, general case + else + { + emit_mov_r32_p32(dst, REG_EAX, src1p); // mov eax,src1p + if (src2p.is_memory()) + emit_imul_m32(dst, MABS(src2p.memory())); // imul [src2p] + else if (src2p.is_int_register()) + emit_imul_r32(dst, src2p.ireg()); // imul src2p + else if (src2p.is_immediate()) + { + emit_mov_r32_imm(dst, REG_EDX, src2p.immediate()); // mov edx,src2p + emit_imul_r32(dst, REG_EDX); // imul edx + } + emit_mov_p32_r32(dst, dstp, REG_EAX); // mov dstp,eax + emit_mov_p32_r32(dst, edstp, REG_EDX); // mov edstp,edx + } + + // compute flags + if (inst.flags() != 0) + { + if (zsflags != 0) + { + if (vflag) + emit_pushf(dst); // pushf + if (compute_hi) + { + if (zsflags == FLAG_Z) + emit_or_r32_r32(dst, REG_EDX, REG_EAX); // or edx,eax + else if (zsflags == FLAG_S) + emit_test_r32_r32(dst, REG_EDX, REG_EDX); // test edx,edx + else + { + emit_movzx_r32_r16(dst, REG_ECX, REG_AX); // movzx ecx,ax + emit_shr_r32_imm(dst, REG_EAX, 16); // shr eax,16 + emit_or_r32_r32(dst, REG_EDX, REG_ECX); // or edx,ecx + emit_or_r32_r32(dst, REG_EDX, REG_EAX); // or edx,eax + } + } + else + emit_test_r32_r32(dst, REG_EAX, REG_EAX); // test eax,eax + + // we rely on the fact that OF is cleared by all logical operations above + if (vflag) + { + emit_pushf(dst); // pushf + emit_pop_r64(dst, REG_RAX); // pop rax + emit_and_m64_imm(dst, MBD(REG_RSP, 0), ~0x84); // and [rsp],~0x84 + emit_or_m64_r64(dst, MBD(REG_RSP, 0), REG_RAX); // or [rsp],rax + emit_popf(dst); // popf + } + } + } + } + + // 64-bit form + else if (inst.size() == 8) + { + // 64-bit destination with memory/immediate or register/immediate + if (!compute_hi && !src1p.is_immediate() && src2p.is_immediate() && short_immediate(src2p.immediate())) + { + if (src1p.is_memory()) + emit_imul_r64_m64_imm(dst, REG_RAX, MABS(src1p.memory()), src2p.immediate());// imul rax,[src1p],src2p + else if (src1p.is_int_register()) + emit_imul_r64_r64_imm(dst, REG_RAX, src1p.ireg(), src2p.immediate()); // imul rax,src1p,src2p + emit_mov_p64_r64(dst, dstp, REG_RAX); // mov dstp,rax + } + + // 64-bit destination, general case + else if (!compute_hi) + { + emit_mov_r64_p64(dst, REG_RAX, src1p); // mov rax,src1p + if (src2p.is_memory()) + emit_imul_r64_m64(dst, REG_RAX, MABS(src2p.memory())); // imul rax,[src2p] + else if (src2p.is_int_register()) + emit_imul_r64_r64(dst, REG_RAX, src2p.ireg()); // imul rax,src2p + emit_mov_p64_r64(dst, dstp, REG_RAX); // mov dstp,rax + } + + // 128-bit destination, general case + else + { + emit_mov_r64_p64(dst, REG_RAX, src1p); // mov rax,src1p + if (src2p.is_memory()) + emit_imul_m64(dst, MABS(src2p.memory())); // imul [src2p] + else if (src2p.is_int_register()) + emit_imul_r64(dst, src2p.ireg()); // imul src2p + else if (src2p.is_immediate()) + { + emit_mov_r64_imm(dst, REG_RDX, src2p.immediate()); // mov rdx,src2p + emit_imul_r64(dst, REG_RDX); // imul rdx + } + emit_mov_p64_r64(dst, dstp, REG_RAX); // mov dstp,rax + emit_mov_p64_r64(dst, edstp, REG_RDX); // mov edstp,rdx + } + + // compute flags + if (inst.flags() != 0) + { + if (zsflags != 0) + { + if (vflag) + emit_pushf(dst); // pushf + if (compute_hi) + { + if (zsflags == FLAG_Z) + emit_or_r64_r64(dst, REG_RDX, REG_RAX); // or rdx,rax + else if (zsflags == FLAG_S) + emit_test_r64_r64(dst, REG_RDX, REG_RDX); // test rdx,rdx + else + { + emit_mov_r32_r32(dst, REG_ECX, REG_EAX); // mov ecx,eax + emit_shr_r64_imm(dst, REG_RAX, 32); // shr rax,32 + emit_or_r64_r64(dst, REG_RDX, REG_RCX); // or rdx,rcx + emit_or_r64_r64(dst, REG_RDX, REG_RAX); // or rdx,rax + } + } + else + emit_test_r64_r64(dst, REG_RAX, REG_RAX); // test rax,rax + + // we rely on the fact that OF is cleared by all logical operations above + if (vflag) + { + emit_pushf(dst); // pushf + emit_pop_r64(dst, REG_RAX); // pop rax + emit_and_m64_imm(dst, MBD(REG_RSP, 0), ~0x84); // and [rsp],~0x84 + emit_or_m64_r64(dst, MBD(REG_RSP, 0), REG_RAX); // or [rsp],rax + emit_popf(dst); // popf + } + } + } + } +} + + +//------------------------------------------------- +// op_divu - process a DIVU opcode +//------------------------------------------------- + +void drcbe_x64::op_divu(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_no_condition(inst); + assert_flags(inst, FLAG_V | FLAG_Z | FLAG_S); + + // normalize parameters + be_parameter dstp(*this, inst.param(0), PTYPE_MR); + be_parameter edstp(*this, inst.param(1), PTYPE_MR); + be_parameter src1p(*this, inst.param(2), PTYPE_MRI); + be_parameter src2p(*this, inst.param(3), PTYPE_MRI); + bool compute_rem = (dstp != edstp); + + // 32-bit form + if (inst.size() == 4) + { + // general case + emit_mov_r32_p32(dst, REG_ECX, src2p); // mov ecx,src2p + if (inst.flags() != 0) + { + emit_mov_r32_imm(dst, REG_EAX, 0xa0000000); // mov eax,0xa0000000 + emit_add_r32_r32(dst, REG_EAX, REG_EAX); // add eax,eax + } + emit_link skip; + emit_jecxz_link(dst, skip); // jecxz skip + emit_mov_r32_p32(dst, REG_EAX, src1p); // mov eax,src1p + emit_xor_r32_r32(dst, REG_EDX, REG_EDX); // xor edx,edx + emit_div_r32(dst, REG_ECX); // div ecx + emit_mov_p32_r32(dst, dstp, REG_EAX); // mov dstp,eax + if (compute_rem) + emit_mov_p32_r32(dst, edstp, REG_EDX); // mov edstp,edx + if (inst.flags() != 0) + emit_test_r32_r32(dst, REG_EAX, REG_EAX); // test eax,eax + resolve_link(dst, skip); // skip: + } + + // 64-bit form + else if (inst.size() == 8) + { + // general case + emit_mov_r64_p64(dst, REG_RCX, src2p); // mov rcx,src2p + if (inst.flags() != 0) + { + emit_mov_r32_imm(dst, REG_EAX, 0xa0000000); // mov eax,0xa0000000 + emit_add_r32_r32(dst, REG_EAX, REG_EAX); // add eax,eax + } + emit_link skip; + emit_jrcxz_link(dst, skip); // jrcxz skip + emit_mov_r64_p64(dst, REG_RAX, src1p); // mov rax,src1p + emit_xor_r32_r32(dst, REG_EDX, REG_EDX); // xor edx,edx + emit_div_r64(dst, REG_RCX); // div rcx + emit_mov_p64_r64(dst, dstp, REG_RAX); // mov dstp,rax + if (compute_rem) + emit_mov_p64_r64(dst, edstp, REG_RDX); // mov edstp,rdx + if (inst.flags() != 0) + emit_test_r64_r64(dst, REG_RAX, REG_RAX); // test eax,eax + resolve_link(dst, skip); // skip: + } +} + + +//------------------------------------------------- +// op_divs - process a DIVS opcode +//------------------------------------------------- + +void drcbe_x64::op_divs(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_no_condition(inst); + assert_flags(inst, FLAG_V | FLAG_Z | FLAG_S); + + // normalize parameters + be_parameter dstp(*this, inst.param(0), PTYPE_MR); + be_parameter edstp(*this, inst.param(1), PTYPE_MR); + be_parameter src1p(*this, inst.param(2), PTYPE_MRI); + be_parameter src2p(*this, inst.param(3), PTYPE_MRI); + bool compute_rem = (dstp != edstp); + + // 32-bit form + if (inst.size() == 4) + { + // general case + emit_mov_r32_p32(dst, REG_ECX, src2p); // mov ecx,src2p + if (inst.flags() != 0) + { + emit_mov_r32_imm(dst, REG_EAX, 0xa0000000); // mov eax,0xa0000000 + emit_add_r32_r32(dst, REG_EAX, REG_EAX); // add eax,eax + } + emit_link skip; + emit_jecxz_link(dst, skip); // jecxz skip + emit_mov_r32_p32(dst, REG_EAX, src1p); // mov eax,src1p + emit_cdq(dst); // cdq + emit_idiv_r32(dst, REG_ECX); // idiv ecx + emit_mov_p32_r32(dst, dstp, REG_EAX); // mov dstp,eax + if (compute_rem) + emit_mov_p32_r32(dst, edstp, REG_EDX); // mov edstp,edx + if (inst.flags() != 0) + emit_test_r32_r32(dst, REG_EAX, REG_EAX); // test eax,eax + resolve_link(dst, skip); // skip: + } + + // 64-bit form + else if (inst.size() == 8) + { + // general case + emit_mov_r64_p64(dst, REG_RCX, src2p); // mov rcx,src2p + if (inst.flags() != 0) + { + emit_mov_r32_imm(dst, REG_EAX, 0xa0000000); // mov eax,0xa0000000 + emit_add_r32_r32(dst, REG_EAX, REG_EAX); // add eax,eax + } + emit_link skip; + emit_jrcxz_link(dst, skip); // jrcxz skip + emit_mov_r64_p64(dst, REG_RAX, src1p); // mov rax,src1p + emit_cqo(dst); // cqo + emit_idiv_r64(dst, REG_RCX); // idiv rcx + emit_mov_p64_r64(dst, dstp, REG_RAX); // mov dstp,rax + if (compute_rem) + emit_mov_p64_r64(dst, edstp, REG_RDX); // mov edstp,rdx + if (inst.flags() != 0) + emit_test_r64_r64(dst, REG_RAX, REG_RAX); // test eax,eax + resolve_link(dst, skip); // skip: + } +} + + +//------------------------------------------------- +// op_and - process a AND opcode +//------------------------------------------------- + +void drcbe_x64::op_and(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_no_condition(inst); + assert_flags(inst, FLAG_Z | FLAG_S); + + // normalize parameters + be_parameter dstp(*this, inst.param(0), PTYPE_MR); + be_parameter src1p(*this, inst.param(1), PTYPE_MRI); + be_parameter src2p(*this, inst.param(2), PTYPE_MRI); + normalize_commutative(src1p, src2p); + + // pick a target register for the general case + int dstreg = dstp.select_register(REG_EAX, src2p); + + // 32-bit form + if (inst.size() == 4) + { + // dstp == src1p in memory + if (dstp.is_memory() && dstp == src1p) + emit_and_m32_p32(dst, MABS(dstp.memory()), src2p, inst); // and [dstp],src2p + + // AND with immediate 0xff + else if (src2p.is_immediate_value(0xff) && inst.flags() == 0) + { + if (src1p.is_int_register()) + emit_movzx_r32_r8(dst, dstreg, src1p.ireg()); // movzx dstreg,src1p + else if (src1p.is_memory()) + emit_movzx_r32_m8(dst, dstreg, MABS(src1p.memory())); // movzx dstreg,[src1p] + emit_mov_p32_r32(dst, dstp, dstreg); // mov dstp,dstreg + } + + // AND with immediate 0xffff + else if (src2p.is_immediate_value(0xffff) && inst.flags() == 0) + { + if (src1p.is_int_register()) + emit_movzx_r32_r16(dst, dstreg, src1p.ireg()); // movzx dstreg,src1p + else if (src1p.is_memory()) + emit_movzx_r32_m16(dst, dstreg, MABS(src1p.memory())); // movzx dstreg,[src1p] + emit_mov_p32_r32(dst, dstp, dstreg); // mov dstp,dstreg + } + + // general case + else + { + emit_mov_r32_p32(dst, dstreg, src1p); // mov dstreg,src1p + emit_and_r32_p32(dst, dstreg, src2p, inst); // and dstreg,src2p + emit_mov_p32_r32(dst, dstp, dstreg); // mov dstp,dstreg + } + } + + // 64-bit form + else if (inst.size() == 8) + { + // dstp == src1p in memory + if (dstp.is_memory() && dstp == src1p) + emit_and_m64_p64(dst, MABS(dstp.memory()), src2p, inst); // and [dstp],src2p + + // AND with immediate 0xff + else if (src2p.is_immediate_value(0xff) && inst.flags() == 0) + { + if (src1p.is_int_register()) + emit_movzx_r32_r8(dst, dstreg, src1p.ireg()); // movzx dstreg,src1p + else if (src1p.is_memory()) + emit_movzx_r32_m8(dst, dstreg, MABS(src1p.memory())); // movzx dstreg,[src1p] + emit_mov_p64_r64(dst, dstp, dstreg); // mov dstp,dstreg + } + + // AND with immediate 0xffff + else if (src2p.is_immediate_value(0xffff) && inst.flags() == 0) + { + if (src1p.is_int_register()) + emit_movzx_r32_r16(dst, dstreg, src1p.ireg()); // movzx dstreg,src1p + else if (src1p.is_memory()) + emit_movzx_r32_m16(dst, dstreg, MABS(src1p.memory())); // movzx dstreg,[src1p] + emit_mov_p64_r64(dst, dstp, dstreg); // mov dstp,dstreg + } + + // AND with immediate 0xffffffff + else if (src2p.is_immediate_value(0xffffffff) && inst.flags() == 0) + { + if (dstp.is_int_register() && src1p == dstp) + emit_mov_r32_r32(dst, dstreg, dstreg); // mov dstreg,dstreg + else + { + emit_mov_r32_p32(dst, dstreg, src1p); // mov dstreg,src1p + emit_mov_p64_r64(dst, dstp, dstreg); // mov dstp,dstreg + } + } + + // general case + else + { + emit_mov_r64_p64(dst, dstreg, src1p); // mov dstreg,src1p + emit_and_r64_p64(dst, dstreg, src2p, inst); // and dstreg,src2p + emit_mov_p64_r64(dst, dstp, dstreg); // mov dstp,dstreg + } + } +} + + +//------------------------------------------------- +// op_test - process a TEST opcode +//------------------------------------------------- + +void drcbe_x64::op_test(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_no_condition(inst); + assert_flags(inst, FLAG_Z | FLAG_S); + + // normalize parameters + be_parameter src1p(*this, inst.param(0), PTYPE_MRI); + be_parameter src2p(*this, inst.param(1), PTYPE_MRI); + normalize_commutative(src1p, src2p); + + // pick a target register for the general case + int src1reg = src1p.select_register(REG_EAX); + + // 32-bit form + if (inst.size() == 4) + { + // src1p in memory + if (src1p.is_memory()) + emit_test_m32_p32(dst, MABS(src1p.memory()), src2p, inst); // test [src1p],src2p + + // general case + else + { + emit_mov_r32_p32(dst, src1reg, src1p); // mov src1reg,src1p + emit_test_r32_p32(dst, src1reg, src2p, inst); // test src1reg,src2p + } + } + + // 64-bit form + else if (inst.size() == 8) + { + // src1p in memory + if (src1p.is_memory()) + emit_test_m64_p64(dst, MABS(src1p.memory()), src2p, inst); // test [src1p],src2p + + // general case + else + { + emit_mov_r64_p64(dst, src1reg, src1p); // mov src1reg,src1p + emit_test_r64_p64(dst, src1reg, src2p, inst); // test src1reg,src2p + } + } +} + + +//------------------------------------------------- +// op_or - process a OR opcode +//------------------------------------------------- + +void drcbe_x64::op_or(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_no_condition(inst); + assert_flags(inst, FLAG_Z | FLAG_S); + + // normalize parameters + be_parameter dstp(*this, inst.param(0), PTYPE_MR); + be_parameter src1p(*this, inst.param(1), PTYPE_MRI); + be_parameter src2p(*this, inst.param(2), PTYPE_MRI); + normalize_commutative(src1p, src2p); + + // pick a target register for the general case + int dstreg = dstp.select_register(REG_EAX, src2p); + + // 32-bit form + if (inst.size() == 4) + { + // dstp == src1p in memory + if (dstp.is_memory() && dstp == src1p) + emit_or_m32_p32(dst, MABS(dstp.memory()), src2p, inst); // or [dstp],src2p + + // general case + else + { + emit_mov_r32_p32(dst, dstreg, src1p); // mov dstreg,src1p + emit_or_r32_p32(dst, dstreg, src2p, inst); // or dstreg,src2p + emit_mov_p32_r32(dst, dstp, dstreg); // mov dstp,dstreg + } + } + + // 64-bit form + else if (inst.size() == 8) + { + // dstp == src1p in memory + if (dstp.is_memory() && dstp == src1p) + emit_or_m64_p64(dst, MABS(dstp.memory()), src2p, inst); // or [dstp],src2p + + // general case + else + { + emit_mov_r64_p64(dst, dstreg, src1p); // mov dstreg,src1p + emit_or_r64_p64(dst, dstreg, src2p, inst); // or dstreg,src2p + emit_mov_p64_r64(dst, dstp, dstreg); // mov dstp,dstreg + } + } +} + + +//------------------------------------------------- +// op_xor - process a XOR opcode +//------------------------------------------------- + +void drcbe_x64::op_xor(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_no_condition(inst); + assert_flags(inst, FLAG_Z | FLAG_S); + + // normalize parameters + be_parameter dstp(*this, inst.param(0), PTYPE_MR); + be_parameter src1p(*this, inst.param(1), PTYPE_MRI); + be_parameter src2p(*this, inst.param(2), PTYPE_MRI); + normalize_commutative(src1p, src2p); + + // pick a target register for the general case + int dstreg = dstp.select_register(REG_EAX, src2p); + + // 32-bit form + if (inst.size() == 4) + { + // dstp == src1p in memory + if (dstp.is_memory() && dstp == src1p) + emit_xor_m32_p32(dst, MABS(dstp.memory()), src2p, inst); // xor [dstp],src2p + + // general case + else + { + emit_mov_r32_p32(dst, dstreg, src1p); // mov dstreg,src1p + emit_xor_r32_p32(dst, dstreg, src2p, inst); // xor dstreg,src2p + emit_mov_p32_r32(dst, dstp, dstreg); // mov dstp,dstreg + } + } + + // 64-bit form + else if (inst.size() == 8) + { + // dstp == src1p in memory + if (dstp.is_memory() && dstp == src1p) + emit_xor_m64_p64(dst, MABS(dstp.memory()), src2p, inst); // xor [dstp],src2p + + // general case + else + { + emit_mov_r64_p64(dst, dstreg, src1p); // mov dstreg,src1p + emit_xor_r64_p64(dst, dstreg, src2p, inst); // xor dstreg,src2p + emit_mov_p64_r64(dst, dstp, dstreg); // mov dstp,dstreg + } + } +} + + +//------------------------------------------------- +// op_lzcnt - process a LZCNT opcode +//------------------------------------------------- + +void drcbe_x64::op_lzcnt(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_no_condition(inst); + assert_flags(inst, FLAG_Z | FLAG_S); + + // normalize parameters + be_parameter dstp(*this, inst.param(0), PTYPE_MR); + be_parameter srcp(*this, inst.param(1), PTYPE_MRI); + + // pick a target register for the general case + int dstreg = dstp.select_register(REG_EAX); + + // 32-bit form + if (inst.size() == 4) + { + emit_mov_r32_p32(dst, dstreg, srcp); // mov dstreg,src1p + emit_mov_r32_imm(dst, REG_ECX, 32 ^ 31); // mov ecx,32 ^ 31 + emit_bsr_r32_r32(dst, dstreg, dstreg); // bsr dstreg,dstreg + emit_cmovcc_r32_r32(dst, x64emit::COND_Z, dstreg, REG_ECX); // cmovz dstreg,ecx + emit_xor_r32_imm(dst, dstreg, 31); // xor dstreg,31 + emit_mov_p32_r32(dst, dstp, dstreg); // mov dstp,dstreg + } + + // 64-bit form + else if (inst.size() == 8) + { + emit_mov_r64_p64(dst, dstreg, srcp); // mov dstreg,src1p + emit_mov_r64_imm(dst, REG_RCX, 64 ^ 63); // mov rcx,64 ^ 63 + emit_bsr_r64_r64(dst, dstreg, dstreg); // bsr dstreg,dstreg + emit_cmovcc_r64_r64(dst, x64emit::COND_Z, dstreg, REG_RCX); // cmovz dstreg,rcx + emit_xor_r32_imm(dst, dstreg, 63); // xor dstreg,63 + emit_mov_p64_r64(dst, dstp, dstreg); // mov dstp,dstreg + } +} + + +//------------------------------------------------- +// op_bswap - process a BSWAP opcode +//------------------------------------------------- + +void drcbe_x64::op_bswap(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_no_condition(inst); + assert_flags(inst, FLAG_Z | FLAG_S); + + // normalize parameters + be_parameter dstp(*this, inst.param(0), PTYPE_MR); + be_parameter srcp(*this, inst.param(1), PTYPE_MRI); + + // pick a target register for the general case + int dstreg = dstp.select_register(REG_RAX); + + // 32-bit form + if (inst.size() == 4) + { + emit_mov_r32_p32(dst, dstreg, srcp); // mov dstreg,src1p + emit_bswap_r32(dst, dstreg); // bswap dstreg + if (inst.flags() != 0) + emit_test_r32_r32(dst, dstreg, dstreg); // test dstreg,dstreg + emit_mov_p32_r32(dst, dstp, dstreg); // mov dstp,dstreg + } + + // 64-bit form + else if (inst.size() == 8) + { + emit_mov_r64_p64(dst, dstreg, srcp); // mov dstreg,src1p + emit_bswap_r64(dst, dstreg); // bswap dstreg + if (inst.flags() != 0) + emit_test_r64_r64(dst, dstreg, dstreg); // test dstreg,dstreg + emit_mov_p64_r64(dst, dstp, dstreg); // mov dstp,dstreg + } +} + + +//------------------------------------------------- +// op_shl - process a SHL opcode +//------------------------------------------------- + +void drcbe_x64::op_shl(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_no_condition(inst); + assert_flags(inst, FLAG_C | FLAG_Z | FLAG_S); + + // normalize parameters + be_parameter dstp(*this, inst.param(0), PTYPE_MR); + be_parameter src1p(*this, inst.param(1), PTYPE_MRI); + be_parameter src2p(*this, inst.param(2), PTYPE_MRI); + + // pick a target register for the general case + int dstreg = dstp.select_register(REG_EAX, src2p); + + // 32-bit form + if (inst.size() == 4) + { + // dstp == src1p in memory + if (dstp.is_memory() && dstp == src1p) + emit_shl_m32_p32(dst, MABS(dstp.memory()), src2p, inst); // shl [dstp],src2p + + // general case + else + { + emit_mov_r32_p32(dst, dstreg, src1p); // mov dstreg,src1p + emit_shl_r32_p32(dst, dstreg, src2p, inst); // shl dstreg,src2p + emit_mov_p32_r32(dst, dstp, dstreg); // mov dstp,dstreg + } + } + + // 64-bit form + else if (inst.size() == 8) + { + // dstp == src1p in memory + if (dstp.is_memory() && dstp == src1p) + emit_shl_m64_p64(dst, MABS(dstp.memory()), src2p, inst); // shl [dstp],src2p + + // general case + else + { + emit_mov_r64_p64(dst, dstreg, src1p); // mov dstreg,src1p + emit_shl_r64_p64(dst, dstreg, src2p, inst); // shl dstreg,src2p + emit_mov_p64_r64(dst, dstp, dstreg); // mov dstp,dstreg + } + } +} + + +//------------------------------------------------- +// op_shr - process a SHR opcode +//------------------------------------------------- + +void drcbe_x64::op_shr(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_no_condition(inst); + assert_flags(inst, FLAG_C | FLAG_Z | FLAG_S); + + // normalize parameters + be_parameter dstp(*this, inst.param(0), PTYPE_MR); + be_parameter src1p(*this, inst.param(1), PTYPE_MRI); + be_parameter src2p(*this, inst.param(2), PTYPE_MRI); + + // pick a target register for the general case + int dstreg = dstp.select_register(REG_EAX, src2p); + + // 32-bit form + if (inst.size() == 4) + { + // dstp == src1p in memory + if (dstp.is_memory() && dstp == src1p) + emit_shr_m32_p32(dst, MABS(dstp.memory()), src2p, inst); // shr [dstp],src2p + + // general case + else + { + emit_mov_r32_p32(dst, dstreg, src1p); // mov dstreg,src1p + emit_shr_r32_p32(dst, dstreg, src2p, inst); // shr dstreg,src2p + emit_mov_p32_r32(dst, dstp, dstreg); // mov dstp,dstreg + } + } + + // 64-bit form + else if (inst.size() == 8) + { + // dstp == src1p in memory + if (dstp.is_memory() && dstp == src1p) + emit_shr_m64_p64(dst, MABS(dstp.memory()), src2p, inst); // shr [dstp],src2p + + // general case + else + { + emit_mov_r64_p64(dst, dstreg, src1p); // mov dstreg,src1p + emit_shr_r64_p64(dst, dstreg, src2p, inst); // shr dstreg,src2p + emit_mov_p64_r64(dst, dstp, dstreg); // mov dstp,dstreg + } + } +} + + +//------------------------------------------------- +// op_sar - process a SAR opcode +//------------------------------------------------- + +void drcbe_x64::op_sar(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_no_condition(inst); + assert_flags(inst, FLAG_C | FLAG_Z | FLAG_S); + + // normalize parameters + be_parameter dstp(*this, inst.param(0), PTYPE_MR); + be_parameter src1p(*this, inst.param(1), PTYPE_MRI); + be_parameter src2p(*this, inst.param(2), PTYPE_MRI); + + // pick a target register for the general case + int dstreg = dstp.select_register(REG_EAX, src2p); + + // 32-bit form + if (inst.size() == 4) + { + // dstp == src1p in memory + if (dstp.is_memory() && dstp == src1p) + emit_sar_m32_p32(dst, MABS(dstp.memory()), src2p, inst); // sar [dstp],src2p + + // general case + else + { + emit_mov_r32_p32(dst, dstreg, src1p); // mov dstreg,src1p + emit_sar_r32_p32(dst, dstreg, src2p, inst); // sar dstreg,src2p + emit_mov_p32_r32(dst, dstp, dstreg); // mov dstp,dstreg + } + } + + // 64-bit form + else if (inst.size() == 8) + { + // dstp == src1p in memory + if (dstp.is_memory() && dstp == src1p) + emit_sar_m64_p64(dst, MABS(dstp.memory()), src2p, inst); // sar [dstp],src2p + + // general case + else + { + emit_mov_r64_p64(dst, dstreg, src1p); // mov dstreg,src1p + emit_sar_r64_p64(dst, dstreg, src2p, inst); // sar dstreg,src2p + emit_mov_p64_r64(dst, dstp, dstreg); // mov dstp,dstreg + } + } +} + + +//------------------------------------------------- +// op_rol - process a rol opcode +//------------------------------------------------- + +void drcbe_x64::op_rol(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_no_condition(inst); + assert_flags(inst, FLAG_C | FLAG_Z | FLAG_S); + + // normalize parameters + be_parameter dstp(*this, inst.param(0), PTYPE_MR); + be_parameter src1p(*this, inst.param(1), PTYPE_MRI); + be_parameter src2p(*this, inst.param(2), PTYPE_MRI); + + // pick a target register for the general case + int dstreg = dstp.select_register(REG_EAX, src2p); + + // 32-bit form + if (inst.size() == 4) + { + // dstp == src1p in memory + if (dstp.is_memory() && dstp == src1p) + emit_rol_m32_p32(dst, MABS(dstp.memory()), src2p, inst); // rol [dstp],src2p + + // general case + else + { + emit_mov_r32_p32(dst, dstreg, src1p); // mov dstreg,src1p + emit_rol_r32_p32(dst, dstreg, src2p, inst); // rol dstreg,src2p + emit_mov_p32_r32(dst, dstp, dstreg); // mov dstp,dstreg + } + } + + // 64-bit form + else if (inst.size() == 8) + { + // dstp == src1p in memory + if (dstp.is_memory() && dstp == src1p) + emit_rol_m64_p64(dst, MABS(dstp.memory()), src2p, inst); // rol [dstp],src2p + + // general case + else + { + emit_mov_r64_p64(dst, dstreg, src1p); // mov dstreg,src1p + emit_rol_r64_p64(dst, dstreg, src2p, inst); // rol dstreg,src2p + emit_mov_p64_r64(dst, dstp, dstreg); // mov dstp,dstreg + } + } +} + + +//------------------------------------------------- +// op_ror - process a ROR opcode +//------------------------------------------------- + +void drcbe_x64::op_ror(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_no_condition(inst); + assert_flags(inst, FLAG_C | FLAG_Z | FLAG_S); + + // normalize parameters + be_parameter dstp(*this, inst.param(0), PTYPE_MR); + be_parameter src1p(*this, inst.param(1), PTYPE_MRI); + be_parameter src2p(*this, inst.param(2), PTYPE_MRI); + + // pick a target register for the general case + int dstreg = dstp.select_register(REG_EAX, src2p); + + // 32-bit form + if (inst.size() == 4) + { + // dstp == src1p in memory + if (dstp.is_memory() && dstp == src1p) + emit_ror_m32_p32(dst, MABS(dstp.memory()), src2p, inst); // ror [dstp],src2p + + // general case + else + { + emit_mov_r32_p32(dst, dstreg, src1p); // mov dstreg,src1p + emit_ror_r32_p32(dst, dstreg, src2p, inst); // ror dstreg,src2p + emit_mov_p32_r32(dst, dstp, dstreg); // mov dstp,dstreg + } + } + + // 64-bit form + else if (inst.size() == 8) + { + // dstp == src1p in memory + if (dstp.is_memory() && dstp == src1p) + emit_ror_m64_p64(dst, MABS(dstp.memory()), src2p, inst); // ror [dstp],src2p + + // general case + else + { + emit_mov_r64_p64(dst, dstreg, src1p); // mov dstreg,src1p + emit_ror_r64_p64(dst, dstreg, src2p, inst); // ror dstreg,src2p + emit_mov_p64_r64(dst, dstp, dstreg); // mov dstp,dstreg + } + } +} + + +//------------------------------------------------- +// op_rolc - process a ROLC opcode +//------------------------------------------------- + +void drcbe_x64::op_rolc(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_no_condition(inst); + assert_flags(inst, FLAG_C | FLAG_Z | FLAG_S); + + // normalize parameters + be_parameter dstp(*this, inst.param(0), PTYPE_MR); + be_parameter src1p(*this, inst.param(1), PTYPE_MRI); + be_parameter src2p(*this, inst.param(2), PTYPE_MRI); + + // pick a target register for the general case + int dstreg = dstp.select_register(REG_EAX, src2p); + + // 32-bit form + if (inst.size() == 4) + { + // dstp == src1p in memory + if (dstp.is_memory() && dstp == src1p) + emit_rcl_m32_p32(dst, MABS(dstp.memory()), src2p, inst); // rcl [dstp],src2p + + // general case + else + { + emit_mov_r32_p32_keepflags(dst, dstreg, src1p); // mov dstreg,src1p + emit_rcl_r32_p32(dst, dstreg, src2p, inst); // rcl dstreg,src2p + emit_mov_p32_r32(dst, dstp, dstreg); // mov dstp,dstreg + } + } + + // 64-bit form + else if (inst.size() == 8) + { + // dstp == src1p in memory + if (dstp.is_memory() && dstp == src1p) + emit_rcl_m64_p64(dst, MABS(dstp.memory()), src2p, inst); // rcl [dstp],src2p + + // general case + else + { + emit_mov_r64_p64_keepflags(dst, dstreg, src1p); // mov dstreg,src1p + emit_rcl_r64_p64(dst, dstreg, src2p, inst); // rcl dstreg,src2p + emit_mov_p64_r64(dst, dstp, dstreg); // mov dstp,dstreg + } + } +} + + +//------------------------------------------------- +// op_rorc - process a RORC opcode +//------------------------------------------------- + +void drcbe_x64::op_rorc(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_no_condition(inst); + assert_flags(inst, FLAG_C | FLAG_Z | FLAG_S); + + // normalize parameters + be_parameter dstp(*this, inst.param(0), PTYPE_MR); + be_parameter src1p(*this, inst.param(1), PTYPE_MRI); + be_parameter src2p(*this, inst.param(2), PTYPE_MRI); + + // pick a target register for the general case + int dstreg = dstp.select_register(REG_EAX, src2p); + + // 32-bit form + if (inst.size() == 4) + { + // dstp == src1p in memory + if (dstp.is_memory() && dstp == src1p) + emit_rcr_m32_p32(dst, MABS(dstp.memory()), src2p, inst); // rcr [dstp],src2p + + // general case + else + { + emit_mov_r32_p32_keepflags(dst, dstreg, src1p); // mov dstreg,src1p + emit_rcr_r32_p32(dst, dstreg, src2p, inst); // rcr dstreg,src2p + emit_mov_p32_r32(dst, dstp, dstreg); // mov dstp,dstreg + } + } + + // 64-bit form + else if (inst.size() == 8) + { + // dstp == src1p in memory + if (dstp.is_memory() && dstp == src1p) + emit_rcr_m64_p64(dst, MABS(dstp.memory()), src2p, inst); // rcr [dstp],src2p + + // general case + else + { + emit_mov_r64_p64_keepflags(dst, dstreg, src1p); // mov dstreg,src1p + emit_rcr_r64_p64(dst, dstreg, src2p, inst); // rcr dstreg,src2p + emit_mov_p64_r64(dst, dstp, dstreg); // mov dstp,dstreg + } + } +} + + + +/*************************************************************************** + FLOATING POINT OPERATIONS +***************************************************************************/ + +//------------------------------------------------- +// op_fload - process a FLOAD opcode +//------------------------------------------------- + +void drcbe_x64::op_fload(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_no_condition(inst); + assert_no_flags(inst); + + // normalize parameters + be_parameter dstp(*this, inst.param(0), PTYPE_MF); + be_parameter basep(*this, inst.param(1), PTYPE_M); + be_parameter indp(*this, inst.param(2), PTYPE_MRI); + + // pick a target register for the general case + int dstreg = dstp.select_register(REG_XMM0); + + // determine the pointer base + INT32 baseoffs; + int basereg = get_base_register_and_offset(dst, basep.memory(), REG_RDX, baseoffs); + + // 32-bit form + if (inst.size() == 4) + { + if (indp.is_immediate()) + emit_movss_r128_m32(dst, dstreg, MBD(basereg, baseoffs + 4*indp.immediate())); // movss dstreg,[basep + 4*indp] + else + { + int indreg = indp.select_register(REG_ECX); + emit_mov_r32_p32(dst, indreg, indp); // mov indreg,indp + emit_movss_r128_m32(dst, dstreg, MBISD(basereg, indreg, 4, baseoffs)); // movss dstreg,[basep + 4*indp] + } + emit_movss_p32_r128(dst, dstp, dstreg); // movss dstp,dstreg + } + + // 64-bit form + else if (inst.size() == 8) + { + if (indp.is_immediate()) + emit_movsd_r128_m64(dst, dstreg, MBD(basereg, baseoffs + 8*indp.immediate())); // movsd dstreg,[basep + 8*indp] + else + { + int indreg = indp.select_register(REG_ECX); + emit_mov_r32_p32(dst, indreg, indp); // mov indreg,indp + emit_movsd_r128_m64(dst, dstreg, MBISD(basereg, indreg, 8, baseoffs)); // movsd dstreg,[basep + 8*indp] + } + emit_movsd_p64_r128(dst, dstp, dstreg); // movsd dstp,dstreg + } +} + + +//------------------------------------------------- +// op_fstore - process a FSTORE opcode +//------------------------------------------------- + +void drcbe_x64::op_fstore(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_no_condition(inst); + assert_no_flags(inst); + + // normalize parameters + be_parameter basep(*this, inst.param(0), PTYPE_M); + be_parameter indp(*this, inst.param(1), PTYPE_MRI); + be_parameter srcp(*this, inst.param(2), PTYPE_MF); + + // pick a target register for the general case + int srcreg = srcp.select_register(REG_XMM0); + + // determine the pointer base + INT32 baseoffs; + int basereg = get_base_register_and_offset(dst, basep.memory(), REG_RDX, baseoffs); + + // 32-bit form + if (inst.size() == 4) + { + emit_movss_r128_p32(dst, srcreg, srcp); // movss srcreg,srcp + if (indp.is_immediate()) + emit_movss_m32_r128(dst, MBD(basereg, baseoffs + 4*indp.immediate()), srcreg); // movss [basep + 4*indp],srcreg + else + { + int indreg = indp.select_register(REG_ECX); + emit_mov_r32_p32(dst, indreg, indp); // mov indreg,indp + emit_movss_m32_r128(dst, MBISD(basereg, indreg, 4, baseoffs), srcreg); // movss [basep + 4*indp],srcreg + } + } + + // 64-bit form + else if (inst.size() == 8) + { + emit_movsd_r128_p64(dst, srcreg, srcp); // movsd srcreg,srcp + if (indp.is_immediate()) + emit_movsd_m64_r128(dst, MBD(basereg, baseoffs + 8*indp.immediate()), srcreg); // movsd [basep + 8*indp],srcreg + else + { + int indreg = indp.select_register(REG_ECX); + emit_mov_r32_p32(dst, indreg, indp); // mov indreg,indp + emit_movsd_m64_r128(dst, MBISD(basereg, indreg, 8, baseoffs), srcreg); // movsd [basep + 8*indp],srcreg + } + } +} + + +//------------------------------------------------- +// op_fread - process a FREAD opcode +//------------------------------------------------- + +void drcbe_x64::op_fread(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_no_condition(inst); + assert_no_flags(inst); + + // normalize parameters + be_parameter dstp(*this, inst.param(0), PTYPE_MF); + be_parameter addrp(*this, inst.param(1), PTYPE_MRI); + const parameter &spacep = inst.param(2); + assert(spacep.is_size_space()); + assert((1 << spacep.size()) == inst.size()); + + // set up a call to the read dword/qword handler + emit_mov_r64_imm(dst, REG_PARAM1, (FPTR)(m_space[spacep.space()])); // mov param1,space + emit_mov_r32_p32(dst, REG_PARAM2, addrp); // mov param2,addrp + if (inst.size() == 4) + emit_smart_call_m64(dst, (x86code **)&m_accessors[spacep.space()].read_dword); // call read_dword + else if (inst.size() == 8) + emit_smart_call_m64(dst, (x86code **)&m_accessors[spacep.space()].read_qword); // call read_qword + + // store result + if (inst.size() == 4) + { + if (dstp.is_memory()) + emit_mov_m32_r32(dst, MABS(dstp.memory()), REG_EAX); // mov [dstp],eax + else if (dstp.is_float_register()) + emit_movd_r128_r32(dst, dstp.freg(), REG_EAX); // movd dstp,eax + } + else if (inst.size() == 8) + { + if (dstp.is_memory()) + emit_mov_m64_r64(dst, MABS(dstp.memory()), REG_RAX); // mov [dstp],rax + else if (dstp.is_float_register()) + emit_movq_r128_r64(dst, dstp.freg(), REG_RAX); // movq dstp,rax + } +} + + +//------------------------------------------------- +// op_fwrite - process a FWRITE opcode +//------------------------------------------------- + +void drcbe_x64::op_fwrite(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_no_condition(inst); + assert_no_flags(inst); + + // normalize parameters + be_parameter addrp(*this, inst.param(0), PTYPE_MRI); + be_parameter srcp(*this, inst.param(1), PTYPE_MF); + const parameter &spacep = inst.param(2); + assert(spacep.is_size_space()); + assert((1 << spacep.size()) == inst.size()); + + // general case + emit_mov_r64_imm(dst, REG_PARAM1, (FPTR)(m_space[spacep.space()])); // mov param1,space + emit_mov_r32_p32(dst, REG_PARAM2, addrp); // mov param21,addrp + + // 32-bit form + if (inst.size() == 4) + { + if (srcp.is_memory()) + emit_mov_r32_m32(dst, REG_PARAM3, MABS(srcp.memory())); // mov param3,[srcp] + else if (srcp.is_float_register()) + emit_movd_r32_r128(dst, REG_PARAM3, srcp.freg()); // movd param3,srcp + emit_smart_call_m64(dst, (x86code **)&m_accessors[spacep.space()].write_dword); // call write_dword + } + + // 64-bit form + else if (inst.size() == 8) + { + if (srcp.is_memory()) + emit_mov_r64_m64(dst, REG_PARAM3, MABS(srcp.memory())); // mov param3,[srcp] + else if (srcp.is_float_register()) + emit_movq_r64_r128(dst, REG_PARAM3, srcp.freg()); // movq param3,srcp + emit_smart_call_m64(dst, (x86code **)&m_accessors[spacep.space()].write_qword); // call write_qword + } +} + + +//------------------------------------------------- +// op_fmov - process a FMOV opcode +//------------------------------------------------- + +void drcbe_x64::op_fmov(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_any_condition(inst); + assert_no_flags(inst); + + // normalize parameters + be_parameter dstp(*this, inst.param(0), PTYPE_MF); + be_parameter srcp(*this, inst.param(1), PTYPE_MF); + + // pick a target register for the general case + int dstreg = dstp.select_register(REG_XMM0); + + // always start with a jmp + emit_link skip = { 0 }; + if (inst.condition() != uml::COND_ALWAYS) + emit_jcc_short_link(dst, X86_NOT_CONDITION(inst.condition()), skip); // jcc skip + + // 32-bit form + if (inst.size() == 4) + { + emit_movss_r128_p32(dst, dstreg, srcp); // movss dstreg,srcp + emit_movss_p32_r128(dst, dstp, dstreg); // movss dstp,dstreg + } + + // 64-bit form + else if (inst.size() == 8) + { + emit_movsd_r128_p64(dst, dstreg, srcp); // movsd dstreg,srcp + emit_movsd_p64_r128(dst, dstp, dstreg); // movsd dstp,dstreg + } + + // resolve the jump + if (inst.condition() != uml::COND_ALWAYS) + resolve_link(dst, skip); // skip: +} + + +//------------------------------------------------- +// op_ftoint - process a FTOINT opcode +//------------------------------------------------- + +void drcbe_x64::op_ftoint(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_no_condition(inst); + assert_no_flags(inst); + + // normalize parameters + be_parameter dstp(*this, inst.param(0), PTYPE_MR); + be_parameter srcp(*this, inst.param(1), PTYPE_MF); + const parameter &sizep = inst.param(2); + assert(sizep.is_size()); + const parameter &roundp = inst.param(3); + assert(roundp.is_rounding()); + + // pick a target register for the general case + int dstreg = dstp.select_register(REG_EAX); + + // set rounding mode if necessary + if (roundp.rounding() != ROUND_DEFAULT && roundp.rounding() != ROUND_TRUNC) + { + emit_stmxcsr_m32(dst, MABS(&m_near.ssemodesave)); // stmxcsr [ssemodesave] + emit_ldmxcsr_m32(dst, MABS(&m_near.ssecontrol[roundp.rounding()])); // ldmxcsr fpcontrol[mode] + } + + // 32-bit form + if (inst.size() == 4) + { + // 32-bit integer source + if (sizep.size() == SIZE_DWORD) + { + if (srcp.is_memory()) + { + if (roundp.rounding() != ROUND_TRUNC) + emit_cvtss2si_r32_m32(dst, dstreg, MABS(srcp.memory())); // cvtss2si dstreg,[srcp] + else + emit_cvttss2si_r32_m32(dst, dstreg, MABS(srcp.memory())); // cvttss2si dstreg,[srcp] + } + else if (srcp.is_float_register()) + { + if (roundp.rounding() != ROUND_TRUNC) + emit_cvtss2si_r32_r128(dst, dstreg, srcp.freg()); // cvtss2si dstreg,srcp + else + emit_cvttss2si_r32_r128(dst, dstreg, srcp.freg()); // cvttss2si dstreg,srcp + } + } + + // 64-bit integer source + else if (sizep.size() == SIZE_QWORD) + { + if (srcp.is_memory()) + { + if (roundp.rounding() != ROUND_TRUNC) + emit_cvtss2si_r64_m32(dst, dstreg, MABS(srcp.memory())); // cvtss2si dstreg,[srcp] + else + emit_cvttss2si_r64_m32(dst, dstreg, MABS(srcp.memory())); // cvttss2si dstreg,[srcp] + } + else if (srcp.is_float_register()) + { + if (roundp.rounding() != ROUND_TRUNC) + emit_cvtss2si_r64_r128(dst, dstreg, srcp.freg()); // cvtss2si dstreg,srcp + else + emit_cvttss2si_r64_r128(dst, dstreg, srcp.freg()); // cvttss2si dstreg,srcp + } + } + } + + // 64-bit form + else if (inst.size() == 8) + { + // 32-bit integer source + if (sizep.size() == SIZE_DWORD) + { + if (srcp.is_memory()) + { + if (roundp.rounding() != ROUND_TRUNC) + emit_cvtsd2si_r32_m64(dst, dstreg, MABS(srcp.memory())); // cvtsd2si dstreg,[srcp] + else + emit_cvttsd2si_r32_m64(dst, dstreg, MABS(srcp.memory())); // cvttsd2si dstreg,[srcp] + } + else if (srcp.is_float_register()) + { + if (roundp.rounding() != ROUND_TRUNC) + emit_cvtsd2si_r32_r128(dst, dstreg, srcp.freg()); // cvtsd2si dstreg,srcp + else + emit_cvttsd2si_r32_r128(dst, dstreg, srcp.freg()); // cvttsd2si dstreg,srcp + } + } + + // 64-bit integer source + else if (sizep.size() == SIZE_QWORD) + { + if (srcp.is_memory()) + { + if (roundp.rounding() != ROUND_TRUNC) + emit_cvtsd2si_r64_m64(dst, dstreg, MABS(srcp.memory())); // cvtsd2si dstreg,[srcp] + else + emit_cvttsd2si_r64_m64(dst, dstreg, MABS(srcp.memory())); // cvttsd2si dstreg,[srcp] + } + else if (srcp.is_float_register()) + { + if (roundp.rounding() != ROUND_TRUNC) + emit_cvtsd2si_r64_r128(dst, dstreg, srcp.freg()); // cvtsd2si dstreg,srcp + else + emit_cvttsd2si_r64_r128(dst, dstreg, srcp.freg()); // cvttsd2si dstreg,srcp + } + } + } + + // general case + if (sizep.size() == SIZE_DWORD) + emit_mov_p32_r32(dst, dstp, dstreg); // mov dstp,dstreg + else + emit_mov_p64_r64(dst, dstp, dstreg); // mov dstp,dstreg + + // restore rounding mode + if (roundp.rounding() != ROUND_DEFAULT && roundp.rounding() != ROUND_TRUNC) + emit_ldmxcsr_m32(dst, MABS(&m_near.ssemodesave)); // ldmxcsr [ssemodesave] +} + + +//------------------------------------------------- +// op_ffrint - process a FFRINT opcode +//------------------------------------------------- + +void drcbe_x64::op_ffrint(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_no_condition(inst); + assert_no_flags(inst); + + // normalize parameters + be_parameter dstp(*this, inst.param(0), PTYPE_MF); + be_parameter srcp(*this, inst.param(1), PTYPE_MRI); + const parameter &sizep = inst.param(2); + assert(sizep.is_size()); + + // pick a target register for the general case + int dstreg = dstp.select_register(REG_XMM0); + + // 32-bit form + if (inst.size() == 4) + { + // 32-bit integer source + if (sizep.size() == SIZE_DWORD) + { + if (srcp.is_memory()) + emit_cvtsi2ss_r128_m32(dst, dstreg, MABS(srcp.memory())); // cvtsi2ss dstreg,[srcp] + else + { + int srcreg = srcp.select_register(REG_EAX); + emit_mov_r32_p32(dst, srcreg, srcp); // mov srcreg,srcp + emit_cvtsi2ss_r128_r32(dst, dstreg, srcreg); // cvtsi2ss dstreg,srcreg + } + } + + // 64-bit integer source + else + { + if (srcp.is_memory()) + emit_cvtsi2ss_r128_m64(dst, dstreg, MABS(srcp.memory())); // cvtsi2ss dstreg,[srcp] + else + { + int srcreg = srcp.select_register(REG_RAX); + emit_mov_r64_p64(dst, srcreg, srcp); // mov srcreg,srcp + emit_cvtsi2ss_r128_r64(dst, dstreg, srcreg); // cvtsi2ss dstreg,srcreg + } + } + emit_movss_p32_r128(dst, dstp, dstreg); // movss dstp,dstreg + } + + // 64-bit form + else if (inst.size() == 8) + { + // 32-bit integer source + if (sizep.size() == SIZE_DWORD) + { + if (srcp.is_memory()) + emit_cvtsi2sd_r128_m32(dst, dstreg, MABS(srcp.memory())); // cvtsi2sd dstreg,[srcp] + else + { + int srcreg = srcp.select_register(REG_EAX); + emit_mov_r32_p32(dst, srcreg, srcp); // mov srcreg,srcp + emit_cvtsi2sd_r128_r32(dst, dstreg, srcreg); // cvtsi2sd dstreg,srcreg + } + } + + // 64-bit integer source + else + { + if (srcp.is_memory()) + emit_cvtsi2sd_r128_m64(dst, dstreg, MABS(srcp.memory())); // cvtsi2sd dstreg,[srcp] + else + { + int srcreg = srcp.select_register(REG_EAX); + emit_mov_r64_p64(dst, srcreg, srcp); // mov srcreg,srcp + emit_cvtsi2sd_r128_r64(dst, dstreg, srcreg); // cvtsi2sd dstreg,srcreg + } + } + emit_movsd_p64_r128(dst, dstp, dstreg); // movsd dstp,dstreg + } +} + + +//------------------------------------------------- +// op_ffrflt - process a FFRFLT opcode +//------------------------------------------------- + +void drcbe_x64::op_ffrflt(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_no_condition(inst); + assert_no_flags(inst); + + // normalize parameters + be_parameter dstp(*this, inst.param(0), PTYPE_MF); + be_parameter srcp(*this, inst.param(1), PTYPE_MF); + const parameter &sizep = inst.param(2); + assert(sizep.is_size()); + + // pick a target register for the general case + int dstreg = dstp.select_register(REG_XMM0); + + // single-to-double + if (inst.size() == 8 && sizep.size() == SIZE_DWORD) + { + if (srcp.is_memory()) + emit_cvtss2sd_r128_m32(dst, dstreg, MABS(srcp.memory())); // cvtss2sd dstreg,[srcp] + else if (srcp.is_float_register()) + emit_cvtss2sd_r128_r128(dst, dstreg, srcp.freg()); // cvtss2sd dstreg,srcp + emit_movsd_p64_r128(dst, dstp, dstreg); // movsd dstp,dstreg + } + + // double-to-single + else if (inst.size() == 4 && sizep.size() == SIZE_QWORD) + { + if (srcp.is_memory()) + emit_cvtsd2ss_r128_m64(dst, dstreg, MABS(srcp.memory())); // cvtsd2ss dstreg,[srcp] + else if (srcp.is_float_register()) + emit_cvtsd2ss_r128_r128(dst, dstreg, srcp.freg()); // cvtsd2ss dstreg,srcp + emit_movss_p32_r128(dst, dstp, dstreg); // movss dstp,dstreg + } +} + + +//------------------------------------------------- +// op_frnds - process a FRNDS opcode +//------------------------------------------------- + +void drcbe_x64::op_frnds(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 8); + assert_no_condition(inst); + assert_no_flags(inst); + + // normalize parameters + be_parameter dstp(*this, inst.param(0), PTYPE_MF); + be_parameter srcp(*this, inst.param(1), PTYPE_MF); + + // pick a target register for the general case + int dstreg = dstp.select_register(REG_XMM0); + + // 64-bit form + if (srcp.is_memory()) + emit_cvtsd2ss_r128_m64(dst, dstreg, MABS(srcp.memory())); // cvtsd2ss dstreg,[srcp] + else if (srcp.is_float_register()) + emit_cvtsd2ss_r128_r128(dst, dstreg, srcp.freg()); // cvtsd2ss dstreg,srcp + emit_cvtss2sd_r128_r128(dst, dstreg, dstreg); // cvtss2sd dstreg,dstreg + emit_movsd_p64_r128(dst, dstp, dstreg); // movsd dstp,dstreg +} + + +//------------------------------------------------- +// op_fadd - process a FADD opcode +//------------------------------------------------- + +void drcbe_x64::op_fadd(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_no_condition(inst); + assert_no_flags(inst); + + // normalize parameters + be_parameter dstp(*this, inst.param(0), PTYPE_MF); + be_parameter src1p(*this, inst.param(1), PTYPE_MF); + be_parameter src2p(*this, inst.param(2), PTYPE_MF); + normalize_commutative(src1p, src2p); + + // pick a target register for the general case + int dstreg = dstp.select_register(REG_XMM0, src2p); + + // 32-bit form + if (inst.size() == 4) + { + emit_movss_r128_p32(dst, dstreg, src1p); // movss dstreg,src1p + if (src2p.is_memory()) + emit_addss_r128_m32(dst, dstreg, MABS(src2p.memory())); // addss dstreg,[src2p] + else if (src2p.is_float_register()) + emit_addss_r128_r128(dst, dstreg, src2p.freg()); // addss dstreg,src2p + emit_movss_p32_r128(dst, dstp, dstreg); // movss dstp,dstreg + } + + // 64-bit form + else if (inst.size() == 8) + { + emit_movsd_r128_p64(dst, dstreg, src1p); // movsd dstreg,src1p + if (src2p.is_memory()) + emit_addsd_r128_m64(dst, dstreg, MABS(src2p.memory())); // addsd dstreg,[src2p] + else if (src2p.is_float_register()) + emit_addsd_r128_r128(dst, dstreg, src2p.freg()); // addsd dstreg,src2p + emit_movsd_p64_r128(dst, dstp, dstreg); // movsd dstp,dstreg + } +} + + +//------------------------------------------------- +// op_fsub - process a FSUB opcode +//------------------------------------------------- + +void drcbe_x64::op_fsub(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_no_condition(inst); + assert_no_flags(inst); + + // normalize parameters + be_parameter dstp(*this, inst.param(0), PTYPE_MF); + be_parameter src1p(*this, inst.param(1), PTYPE_MF); + be_parameter src2p(*this, inst.param(2), PTYPE_MF); + + // pick a target register for the general case + int dstreg = dstp.select_register(REG_XMM0, src2p); + + // 32-bit form + if (inst.size() == 4) + { + emit_movss_r128_p32(dst, dstreg, src1p); // movss dstreg,src1p + if (src2p.is_memory()) + emit_subss_r128_m32(dst, dstreg, MABS(src2p.memory())); // subss dstreg,[src2p] + else if (src2p.is_float_register()) + emit_subss_r128_r128(dst, dstreg, src2p.freg()); // subss dstreg,src2p + emit_movss_p32_r128(dst, dstp, dstreg); // movss dstp,dstreg + } + + // 64-bit form + else if (inst.size() == 8) + { + emit_movsd_r128_p64(dst, dstreg, src1p); // movsd dstreg,src1p + if (src2p.is_memory()) + emit_subsd_r128_m64(dst, dstreg, MABS(src2p.memory())); // subsd dstreg,[src2p] + else if (src2p.is_float_register()) + emit_subsd_r128_r128(dst, dstreg, src2p.freg()); // subsd dstreg,src2p + emit_movsd_p64_r128(dst, dstp, dstreg); // movsd dstp,dstreg + } +} + + +//------------------------------------------------- +// op_fcmp - process a FCMP opcode +//------------------------------------------------- + +void drcbe_x64::op_fcmp(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_no_condition(inst); + assert_flags(inst, FLAG_C | FLAG_Z | FLAG_U); + + // normalize parameters + be_parameter src1p(*this, inst.param(0), PTYPE_MF); + be_parameter src2p(*this, inst.param(1), PTYPE_MF); + + // pick a target register for the general case + int src1reg = src1p.select_register(REG_XMM0); + + // 32-bit form + if (inst.size() == 4) + { + emit_movss_r128_p32(dst, src1reg, src1p); // movss src1reg,src1p + if (src2p.is_memory()) + emit_comiss_r128_m32(dst, src1reg, MABS(src2p.memory())); // comiss src1reg,[src2p] + else if (src2p.is_float_register()) + emit_comiss_r128_r128(dst, src1reg, src2p.freg()); // comiss src1reg,src2p + } + + // 64-bit form + else if (inst.size() == 8) + { + emit_movsd_r128_p64(dst, src1reg, src1p); // movsd src1reg,src1p + if (src2p.is_memory()) + emit_comisd_r128_m64(dst, src1reg, MABS(src2p.memory())); // comisd src1reg,[src2p] + else if (src2p.is_float_register()) + emit_comisd_r128_r128(dst, src1reg, src2p.freg()); // comisd src1reg,src2p + } +} + + +//------------------------------------------------- +// op_fmul - process a FMUL opcode +//------------------------------------------------- + +void drcbe_x64::op_fmul(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_no_condition(inst); + assert_no_flags(inst); + + // normalize parameters + be_parameter dstp(*this, inst.param(0), PTYPE_MF); + be_parameter src1p(*this, inst.param(1), PTYPE_MF); + be_parameter src2p(*this, inst.param(2), PTYPE_MF); + normalize_commutative(src1p, src2p); + + // pick a target register for the general case + int dstreg = dstp.select_register(REG_XMM0, src2p); + + // 32-bit form + if (inst.size() == 4) + { + emit_movss_r128_p32(dst, dstreg, src1p); // movss dstreg,src1p + if (src2p.is_memory()) + emit_mulss_r128_m32(dst, dstreg, MABS(src2p.memory())); // mulss dstreg,[src2p] + else if (src2p.is_float_register()) + emit_mulss_r128_r128(dst, dstreg, src2p.freg()); // mulss dstreg,src2p + emit_movss_p32_r128(dst, dstp, dstreg); // movss dstp,dstreg + } + + // 64-bit form + else if (inst.size() == 8) + { + emit_movsd_r128_p64(dst, dstreg, src1p); // movsd dstreg,src1p + if (src2p.is_memory()) + emit_mulsd_r128_m64(dst, dstreg, MABS(src2p.memory())); // mulsd dstreg,[src2p] + else if (src2p.is_float_register()) + emit_mulsd_r128_r128(dst, dstreg, src2p.freg()); // mulsd dstreg,src2p + emit_movsd_p64_r128(dst, dstp, dstreg); // movsd dstp,dstreg + } +} + + +//------------------------------------------------- +// op_fdiv - process a FDIV opcode +//------------------------------------------------- + +void drcbe_x64::op_fdiv(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_no_condition(inst); + assert_no_flags(inst); + + // normalize parameters + be_parameter dstp(*this, inst.param(0), PTYPE_MF); + be_parameter src1p(*this, inst.param(1), PTYPE_MF); + be_parameter src2p(*this, inst.param(2), PTYPE_MF); + + // pick a target register for the general case + int dstreg = dstp.select_register(REG_XMM0, src2p); + + // 32-bit form + if (inst.size() == 4) + { + emit_movss_r128_p32(dst, dstreg, src1p); // movss dstreg,src1p + if (src2p.is_memory()) + emit_divss_r128_m32(dst, dstreg, MABS(src2p.memory())); // divss dstreg,[src2p] + else if (src2p.is_float_register()) + emit_divss_r128_r128(dst, dstreg, src2p.freg()); // divss dstreg,src2p + emit_movss_p32_r128(dst, dstp, dstreg); // movss dstp,dstreg + } + + // 64-bit form + else if (inst.size() == 8) + { + emit_movsd_r128_p64(dst, dstreg, src1p); // movsd dstreg,src1p + if (src2p.is_memory()) + emit_divsd_r128_m64(dst, dstreg, MABS(src2p.memory())); // divsd dstreg,[src2p] + else if (src2p.is_float_register()) + emit_divsd_r128_r128(dst, dstreg, src2p.freg()); // divsd dstreg,src2p + emit_movsd_p64_r128(dst, dstp, dstreg); // movsd dstp,dstreg + } +} + + +//------------------------------------------------- +// op_fneg - process a FNEG opcode +//------------------------------------------------- + +void drcbe_x64::op_fneg(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_no_condition(inst); + assert_no_flags(inst); + + // normalize parameters + be_parameter dstp(*this, inst.param(0), PTYPE_MF); + be_parameter srcp(*this, inst.param(1), PTYPE_MF); + + // pick a target register for the general case + int dstreg = dstp.select_register(REG_XMM0, srcp); + + // 32-bit form + if (inst.size() == 4) + { + emit_xorps_r128_r128(dst, dstreg, dstreg); // xorps dstreg,dstreg + if (srcp.is_memory()) + emit_subss_r128_m32(dst, dstreg, MABS(srcp.memory())); // subss dstreg,[srcp] + else if (srcp.is_float_register()) + emit_subss_r128_r128(dst, dstreg, srcp.freg()); // subss dstreg,srcp + emit_movss_p32_r128(dst, dstp, dstreg); // movss dstp,dstreg + } + + // 64-bit form + else if (inst.size() == 8) + { + emit_xorpd_r128_r128(dst, dstreg, dstreg); // xorpd dstreg,dstreg + if (srcp.is_memory()) + emit_subsd_r128_m64(dst, dstreg, MABS(srcp.memory())); // subsd dstreg,[srcp] + else if (srcp.is_float_register()) + emit_subsd_r128_r128(dst, dstreg, srcp.freg()); // subsd dstreg,srcp + emit_movsd_p64_r128(dst, dstp, dstreg); // movsd dstp,dstreg + } +} + + +//------------------------------------------------- +// op_fabs - process a FABS opcode +//------------------------------------------------- + +void drcbe_x64::op_fabs(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_no_condition(inst); + assert_no_flags(inst); + + // normalize parameters + be_parameter dstp(*this, inst.param(0), PTYPE_MF); + be_parameter srcp(*this, inst.param(1), PTYPE_MF); + + // pick a target register for the general case + int dstreg = dstp.select_register(REG_XMM0, srcp); + + // 32-bit form + if (inst.size() == 4) + { + emit_movss_r128_p32(dst, dstreg, srcp); // movss dstreg,srcp + emit_andps_r128_m128(dst, dstreg, MABS(m_absmask32)); // andps dstreg,[absmask32] + emit_movss_p32_r128(dst, dstp, dstreg); // movss dstp,dstreg + } + + // 64-bit form + else if (inst.size() == 8) + { + emit_movsd_r128_p64(dst, dstreg, srcp); // movsd dstreg,srcp + emit_andpd_r128_m128(dst, dstreg, MABS(m_absmask64)); // andpd dstreg,[absmask64] + emit_movsd_p64_r128(dst, dstp, dstreg); // movsd dstp,dstreg + } +} + + +//------------------------------------------------- +// op_fsqrt - process a FSQRT opcode +//------------------------------------------------- + +void drcbe_x64::op_fsqrt(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_no_condition(inst); + assert_no_flags(inst); + + // normalize parameters + be_parameter dstp(*this, inst.param(0), PTYPE_MF); + be_parameter srcp(*this, inst.param(1), PTYPE_MF); + + // pick a target register for the general case + int dstreg = dstp.select_register(REG_XMM0); + + // 32-bit form + if (inst.size() == 4) + { + if (srcp.is_memory()) + emit_sqrtss_r128_m32(dst, dstreg, MABS(srcp.memory())); // sqrtss dstreg,[srcp] + else if (srcp.is_float_register()) + emit_sqrtss_r128_r128(dst, dstreg, srcp.freg()); // sqrtss dstreg,srcp + emit_movss_p32_r128(dst, dstp, dstreg); // movss dstp,dstreg + } + + // 64-bit form + else if (inst.size() == 8) + { + if (srcp.is_memory()) + emit_sqrtsd_r128_m64(dst, dstreg, MABS(srcp.memory())); // sqrtsd dstreg,[srcp] + else if (srcp.is_float_register()) + emit_sqrtsd_r128_r128(dst, dstreg, srcp.freg()); // sqrtsd dstreg,srcp + emit_movsd_p64_r128(dst, dstp, dstreg); // movsd dstp,dstreg + } +} + + +//------------------------------------------------- +// op_frecip - process a FRECIP opcode +//------------------------------------------------- + +void drcbe_x64::op_frecip(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_no_condition(inst); + assert_no_flags(inst); + + // normalize parameters + be_parameter dstp(*this, inst.param(0), PTYPE_MF); + be_parameter srcp(*this, inst.param(1), PTYPE_MF); + + // pick a target register for the general case + int dstreg = dstp.select_register(REG_XMM0); + + // 32-bit form + if (inst.size() == 4) + { + if (USE_RCPSS_FOR_SINGLES) + { + if (srcp.is_memory()) + emit_rcpss_r128_m32(dst, dstreg, MABS(srcp.memory())); // rcpss dstreg,[srcp] + else if (srcp.is_float_register()) + emit_rcpss_r128_r128(dst, dstreg, srcp.freg()); // rcpss dstreg,srcp + emit_movss_p32_r128(dst, dstp, dstreg); // movss dstp,dstreg + } + else + { + emit_movss_r128_m32(dst, REG_XMM1, MABS(&m_near.single1)); // movss xmm1,1.0 + if (srcp.is_memory()) + emit_divss_r128_m32(dst, REG_XMM1, MABS(srcp.memory())); // divss xmm1,[srcp] + else if (srcp.is_float_register()) + emit_divss_r128_r128(dst, REG_XMM1, srcp.freg()); // divss xmm1,srcp + emit_movss_p32_r128(dst, dstp, REG_XMM1); // movss dstp,xmm1 + } + } + + // 64-bit form + else if (inst.size() == 8) + { + if (USE_RCPSS_FOR_DOUBLES) + { + if (srcp.is_memory()) + emit_cvtsd2ss_r128_m64(dst, dstreg, MABS(srcp.memory())); // cvtsd2ss dstreg,[srcp] + else if (srcp.is_float_register()) + emit_cvtsd2ss_r128_r128(dst, dstreg, srcp.freg()); // cvtsd2ss dstreg,srcp + emit_rcpss_r128_r128(dst, dstreg, dstreg); // rcpss dstreg,dstreg + emit_cvtss2sd_r128_r128(dst, dstreg, dstreg); // cvtss2sd dstreg,dstreg + emit_movsd_p64_r128(dst, dstp, REG_XMM1); // movsd dstp,dstreg + } + else + { + emit_movsd_r128_m64(dst, REG_XMM1, MABS(&m_near.double1)); // movsd xmm1,1.0 + if (srcp.is_memory()) + emit_divsd_r128_m64(dst, REG_XMM1, MABS(srcp.memory())); // divsd xmm1,[srcp] + else if (srcp.is_float_register()) + emit_divsd_r128_r128(dst, REG_XMM1, srcp.freg()); // divsd xmm1,srcp + emit_movsd_p64_r128(dst, dstp, REG_XMM1); // movsd dstp,xmm1 + } + } +} + + +//------------------------------------------------- +// op_frsqrt - process a FRSQRT opcode +//------------------------------------------------- + +void drcbe_x64::op_frsqrt(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_no_condition(inst); + assert_no_flags(inst); + + // normalize parameters + be_parameter dstp(*this, inst.param(0), PTYPE_MF); + be_parameter srcp(*this, inst.param(1), PTYPE_MF); + + // pick a target register for the general case + int dstreg = dstp.select_register(REG_XMM0); + + // 32-bit form + if (inst.size() == 4) + { + if (USE_RSQRTSS_FOR_SINGLES) + { + if (srcp.is_memory()) + emit_rsqrtss_r128_m32(dst, dstreg, MABS(srcp.memory())); // rsqrtss dstreg,[srcp] + else if (srcp.is_float_register()) + emit_rsqrtss_r128_r128(dst, dstreg, srcp.freg()); // rsqrtss dstreg,srcp + } + else + { + if (srcp.is_memory()) + emit_sqrtss_r128_m32(dst, REG_XMM1, MABS(srcp.memory())); // sqrtss xmm1,[srcp] + else if (srcp.is_float_register()) + emit_sqrtss_r128_r128(dst, REG_XMM1, srcp.freg()); // sqrtss xmm1,srcp + emit_movss_r128_m32(dst, dstreg, MABS(&m_near.single1)); // movss dstreg,1.0 + emit_divss_r128_r128(dst, dstreg, REG_XMM1); // divss dstreg,xmm1 + } + emit_movss_p32_r128(dst, dstp, dstreg); // movss dstp,dstreg + } + + // 64-bit form + else if (inst.size() == 8) + { + if (USE_RSQRTSS_FOR_DOUBLES) + { + if (srcp.is_memory()) + emit_cvtsd2ss_r128_m64(dst, dstreg, MABS(srcp.memory())); // cvtsd2ss dstreg,[srcp] + else if (srcp.is_float_register()) + emit_cvtsd2ss_r128_r128(dst, dstreg, srcp.freg()); // cvtsd2ss dstreg,srcp + emit_rsqrtss_r128_r128(dst, dstreg, dstreg); // rsqrtss dstreg,dstreg + emit_cvtss2sd_r128_r128(dst, dstreg, dstreg); // cvtss2sd dstreg,dstreg + } + else + { + if (srcp.is_memory()) + emit_sqrtsd_r128_m64(dst, REG_XMM1, MABS(srcp.memory())); // sqrtsd xmm1,[srcp] + else if (srcp.is_float_register()) + emit_sqrtsd_r128_r128(dst, REG_XMM1, srcp.freg()); // sqrtsd xmm1,srcp + emit_movsd_r128_m64(dst, dstreg, MABS(&m_near.double1)); // movsd dstreg,1.0 + emit_divsd_r128_r128(dst, dstreg, REG_XMM1); // divsd dstreg,xmm1 + } + emit_movsd_p64_r128(dst, dstp, dstreg); // movsd dstp,dstreg + } +} diff --git a/src/devices/cpu/drcbex64.h b/src/devices/cpu/drcbex64.h new file mode 100644 index 00000000000..6b6cf729b64 --- /dev/null +++ b/src/devices/cpu/drcbex64.h @@ -0,0 +1,345 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + drcbex64.h + + 64-bit x64 back-end for the universal machine language. + +***************************************************************************/ + +#pragma once + +#ifndef __DRCBEX64_H__ +#define __DRCBEX64_H__ + +#include "drcuml.h" +#include "drcbeut.h" +#include "x86log.h" + +#define X86EMIT_SIZE 64 +#include "x86emit.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class drcbe_x64 : public drcbe_interface +{ + typedef UINT32 (*x86_entry_point_func)(UINT8 *rbpvalue, x86code *entry); + +public: + // construction/destruction + drcbe_x64(drcuml_state &drcuml, device_t &device, drc_cache &cache, UINT32 flags, int modes, int addrbits, int ignorebits); + virtual ~drcbe_x64(); + + // required overrides + virtual void reset(); + virtual int execute(uml::code_handle &entry); + virtual void generate(drcuml_block &block, const uml::instruction *instlist, UINT32 numinst); + virtual bool hash_exists(UINT32 mode, UINT32 pc); + virtual void get_info(drcbe_info &info); + virtual bool logging() const { return m_log != NULL; } + +private: + // a be_parameter is similar to a uml::parameter but maps to native registers/memory + class be_parameter + { + public: + // parameter types + enum be_parameter_type + { + PTYPE_NONE = 0, // invalid + PTYPE_IMMEDIATE, // immediate; value = sign-extended to 64 bits + PTYPE_INT_REGISTER, // integer register; value = 0-REG_MAX + PTYPE_FLOAT_REGISTER, // floating point register; value = 0-REG_MAX + PTYPE_VECTOR_REGISTER, // vector register; value = 0-REG_MAX + PTYPE_MEMORY, // memory; value = pointer to memory + PTYPE_MAX + }; + + // represents the value of a parameter + typedef UINT64 be_parameter_value; + + // construction + be_parameter() : m_type(PTYPE_NONE), m_value(0) { } + be_parameter(const be_parameter ¶m) : m_type(param.m_type), m_value(param.m_value) { } + be_parameter(UINT64 val) : m_type(PTYPE_IMMEDIATE), m_value(val) { } + be_parameter(drcbe_x64 &drcbe, const uml::parameter ¶m, UINT32 allowed); + + // creators for types that don't safely default + static inline be_parameter make_ireg(int regnum) { assert(regnum >= 0 && regnum < x64emit::REG_MAX); return be_parameter(PTYPE_INT_REGISTER, regnum); } + static inline be_parameter make_freg(int regnum) { assert(regnum >= 0 && regnum < x64emit::REG_MAX); return be_parameter(PTYPE_FLOAT_REGISTER, regnum); } + static inline be_parameter make_vreg(int regnum) { assert(regnum >= 0 && regnum < x64emit::REG_MAX); return be_parameter(PTYPE_VECTOR_REGISTER, regnum); } + static inline be_parameter make_memory(void *base) { return be_parameter(PTYPE_MEMORY, reinterpret_cast(base)); } + static inline be_parameter make_memory(const void *base) { return be_parameter(PTYPE_MEMORY, reinterpret_cast(const_cast(base))); } + + // operators + bool operator==(const be_parameter &rhs) const { return (m_type == rhs.m_type && m_value == rhs.m_value); } + bool operator!=(const be_parameter &rhs) const { return (m_type != rhs.m_type || m_value != rhs.m_value); } + + // getters + be_parameter_type type() const { return m_type; } + UINT64 immediate() const { assert(m_type == PTYPE_IMMEDIATE); return m_value; } + int ireg() const { assert(m_type == PTYPE_INT_REGISTER); assert(m_value < x64emit::REG_MAX); return m_value; } + int freg() const { assert(m_type == PTYPE_FLOAT_REGISTER); assert(m_value < x64emit::REG_MAX); return m_value; } + int vreg() const { assert(m_type == PTYPE_VECTOR_REGISTER); assert(m_value < x64emit::REG_MAX); return m_value; } + void *memory() const { assert(m_type == PTYPE_MEMORY); return reinterpret_cast(m_value); } + + // type queries + bool is_immediate() const { return (m_type == PTYPE_IMMEDIATE); } + bool is_int_register() const { return (m_type == PTYPE_INT_REGISTER); } + bool is_float_register() const { return (m_type == PTYPE_FLOAT_REGISTER); } + bool is_vector_register() const { return (m_type == PTYPE_VECTOR_REGISTER); } + bool is_memory() const { return (m_type == PTYPE_MEMORY); } + + // other queries + bool is_immediate_value(UINT64 value) const { return (m_type == PTYPE_IMMEDIATE && m_value == value); } + + // helpers + int select_register(int defreg) const; + int select_register(int defreg, const be_parameter &checkparam) const; + int select_register(int defreg, const be_parameter &checkparam, const be_parameter &checkparam2) const; + + private: + // private constructor + be_parameter(be_parameter_type type, be_parameter_value value) : m_type(type), m_value(value) { } + + // internals + be_parameter_type m_type; // parameter type + be_parameter_value m_value; // parameter value + }; + + // helpers + x86_memref MABS(const void *ptr); + bool short_immediate(INT64 immediate) const { return (INT32)immediate == immediate; } + void normalize_commutative(be_parameter &inner, be_parameter &outer); + INT32 offset_from_rbp(const void *ptr); + int get_base_register_and_offset(x86code *&dst, void *target, UINT8 reg, INT32 &offset); + void emit_smart_call_r64(x86code *&dst, x86code *target, UINT8 reg); + void emit_smart_call_m64(x86code *&dst, x86code **target); + + void fixup_label(void *parameter, drccodeptr labelcodeptr); + void fixup_exception(drccodeptr *codeptr, void *param1, void *param2); + + static void debug_log_hashjmp(offs_t pc, int mode); + static void debug_log_hashjmp_fail(); + + // code generators + void op_handle(x86code *&dst, const uml::instruction &inst); + void op_hash(x86code *&dst, const uml::instruction &inst); + void op_label(x86code *&dst, const uml::instruction &inst); + void op_comment(x86code *&dst, const uml::instruction &inst); + void op_mapvar(x86code *&dst, const uml::instruction &inst); + + void op_nop(x86code *&dst, const uml::instruction &inst); + void op_debug(x86code *&dst, const uml::instruction &inst); + void op_exit(x86code *&dst, const uml::instruction &inst); + void op_hashjmp(x86code *&dst, const uml::instruction &inst); + void op_jmp(x86code *&dst, const uml::instruction &inst); + void op_exh(x86code *&dst, const uml::instruction &inst); + void op_callh(x86code *&dst, const uml::instruction &inst); + void op_ret(x86code *&dst, const uml::instruction &inst); + void op_callc(x86code *&dst, const uml::instruction &inst); + void op_recover(x86code *&dst, const uml::instruction &inst); + + void op_setfmod(x86code *&dst, const uml::instruction &inst); + void op_getfmod(x86code *&dst, const uml::instruction &inst); + void op_getexp(x86code *&dst, const uml::instruction &inst); + void op_getflgs(x86code *&dst, const uml::instruction &inst); + void op_save(x86code *&dst, const uml::instruction &inst); + void op_restore(x86code *&dst, const uml::instruction &inst); + + void op_load(x86code *&dst, const uml::instruction &inst); + void op_loads(x86code *&dst, const uml::instruction &inst); + void op_store(x86code *&dst, const uml::instruction &inst); + void op_read(x86code *&dst, const uml::instruction &inst); + void op_readm(x86code *&dst, const uml::instruction &inst); + void op_write(x86code *&dst, const uml::instruction &inst); + void op_writem(x86code *&dst, const uml::instruction &inst); + void op_carry(x86code *&dst, const uml::instruction &inst); + void op_set(x86code *&dst, const uml::instruction &inst); + void op_mov(x86code *&dst, const uml::instruction &inst); + void op_sext(x86code *&dst, const uml::instruction &inst); + void op_roland(x86code *&dst, const uml::instruction &inst); + void op_rolins(x86code *&dst, const uml::instruction &inst); + void op_add(x86code *&dst, const uml::instruction &inst); + void op_addc(x86code *&dst, const uml::instruction &inst); + void op_sub(x86code *&dst, const uml::instruction &inst); + void op_subc(x86code *&dst, const uml::instruction &inst); + void op_cmp(x86code *&dst, const uml::instruction &inst); + void op_mulu(x86code *&dst, const uml::instruction &inst); + void op_muls(x86code *&dst, const uml::instruction &inst); + void op_divu(x86code *&dst, const uml::instruction &inst); + void op_divs(x86code *&dst, const uml::instruction &inst); + void op_and(x86code *&dst, const uml::instruction &inst); + void op_test(x86code *&dst, const uml::instruction &inst); + void op_or(x86code *&dst, const uml::instruction &inst); + void op_xor(x86code *&dst, const uml::instruction &inst); + void op_lzcnt(x86code *&dst, const uml::instruction &inst); + void op_bswap(x86code *&dst, const uml::instruction &inst); + void op_shl(x86code *&dst, const uml::instruction &inst); + void op_shr(x86code *&dst, const uml::instruction &inst); + void op_sar(x86code *&dst, const uml::instruction &inst); + void op_ror(x86code *&dst, const uml::instruction &inst); + void op_rol(x86code *&dst, const uml::instruction &inst); + void op_rorc(x86code *&dst, const uml::instruction &inst); + void op_rolc(x86code *&dst, const uml::instruction &inst); + + void op_fload(x86code *&dst, const uml::instruction &inst); + void op_fstore(x86code *&dst, const uml::instruction &inst); + void op_fread(x86code *&dst, const uml::instruction &inst); + void op_fwrite(x86code *&dst, const uml::instruction &inst); + void op_fmov(x86code *&dst, const uml::instruction &inst); + void op_ftoint(x86code *&dst, const uml::instruction &inst); + void op_ffrint(x86code *&dst, const uml::instruction &inst); + void op_ffrflt(x86code *&dst, const uml::instruction &inst); + void op_frnds(x86code *&dst, const uml::instruction &inst); + void op_fadd(x86code *&dst, const uml::instruction &inst); + void op_fsub(x86code *&dst, const uml::instruction &inst); + void op_fcmp(x86code *&dst, const uml::instruction &inst); + void op_fmul(x86code *&dst, const uml::instruction &inst); + void op_fdiv(x86code *&dst, const uml::instruction &inst); + void op_fneg(x86code *&dst, const uml::instruction &inst); + void op_fabs(x86code *&dst, const uml::instruction &inst); + void op_fsqrt(x86code *&dst, const uml::instruction &inst); + void op_frecip(x86code *&dst, const uml::instruction &inst); + void op_frsqrt(x86code *&dst, const uml::instruction &inst); + + // 32-bit code emission helpers + void emit_mov_r32_p32(x86code *&dst, UINT8 reg, const be_parameter ¶m); + void emit_movsx_r64_p32(x86code *&dst, UINT8 reg, const be_parameter ¶m); + void emit_mov_r32_p32_keepflags(x86code *&dst, UINT8 reg, const be_parameter ¶m); + void emit_mov_m32_p32(x86code *&dst, x86_memref memref, const be_parameter ¶m); + void emit_mov_p32_r32(x86code *&dst, const be_parameter ¶m, UINT8 reg); + void emit_add_r32_p32(x86code *&dst, UINT8 reg, const be_parameter ¶m, const uml::instruction &inst); + void emit_add_m32_p32(x86code *&dst, x86_memref memref, const be_parameter ¶m, const uml::instruction &inst); + void emit_adc_r32_p32(x86code *&dst, UINT8 reg, const be_parameter ¶m, const uml::instruction &inst); + void emit_adc_m32_p32(x86code *&dst, x86_memref memref, const be_parameter ¶m, const uml::instruction &inst); + void emit_sub_r32_p32(x86code *&dst, UINT8 reg, const be_parameter ¶m, const uml::instruction &inst); + void emit_sub_m32_p32(x86code *&dst, x86_memref memref, const be_parameter ¶m, const uml::instruction &inst); + void emit_sbb_r32_p32(x86code *&dst, UINT8 reg, const be_parameter ¶m, const uml::instruction &inst); + void emit_sbb_m32_p32(x86code *&dst, x86_memref memref, const be_parameter ¶m, const uml::instruction &inst); + void emit_cmp_r32_p32(x86code *&dst, UINT8 reg, const be_parameter ¶m, const uml::instruction &inst); + void emit_cmp_m32_p32(x86code *&dst, x86_memref memref, const be_parameter ¶m, const uml::instruction &inst); + void emit_and_r32_p32(x86code *&dst, UINT8 reg, const be_parameter ¶m, const uml::instruction &inst); + void emit_and_m32_p32(x86code *&dst, x86_memref memref, const be_parameter ¶m, const uml::instruction &inst); + void emit_test_r32_p32(x86code *&dst, UINT8 reg, const be_parameter ¶m, const uml::instruction &inst); + void emit_test_m32_p32(x86code *&dst, x86_memref memref, const be_parameter ¶m, const uml::instruction &inst); + void emit_or_r32_p32(x86code *&dst, UINT8 reg, const be_parameter ¶m, const uml::instruction &inst); + void emit_or_m32_p32(x86code *&dst, x86_memref memref, const be_parameter ¶m, const uml::instruction &inst); + void emit_xor_r32_p32(x86code *&dst, UINT8 reg, const be_parameter ¶m, const uml::instruction &inst); + void emit_xor_m32_p32(x86code *&dst, x86_memref memref, const be_parameter ¶m, const uml::instruction &inst); + void emit_shl_r32_p32(x86code *&dst, UINT8 reg, const be_parameter ¶m, const uml::instruction &inst); + void emit_shl_m32_p32(x86code *&dst, x86_memref memref, const be_parameter ¶m, const uml::instruction &inst); + void emit_shr_r32_p32(x86code *&dst, UINT8 reg, const be_parameter ¶m, const uml::instruction &inst); + void emit_shr_m32_p32(x86code *&dst, x86_memref memref, const be_parameter ¶m, const uml::instruction &inst); + void emit_sar_r32_p32(x86code *&dst, UINT8 reg, const be_parameter ¶m, const uml::instruction &inst); + void emit_sar_m32_p32(x86code *&dst, x86_memref memref, const be_parameter ¶m, const uml::instruction &inst); + void emit_rol_r32_p32(x86code *&dst, UINT8 reg, const be_parameter ¶m, const uml::instruction &inst); + void emit_rol_m32_p32(x86code *&dst, x86_memref memref, const be_parameter ¶m, const uml::instruction &inst); + void emit_ror_r32_p32(x86code *&dst, UINT8 reg, const be_parameter ¶m, const uml::instruction &inst); + void emit_ror_m32_p32(x86code *&dst, x86_memref memref, const be_parameter ¶m, const uml::instruction &inst); + void emit_rcl_r32_p32(x86code *&dst, UINT8 reg, const be_parameter ¶m, const uml::instruction &inst); + void emit_rcl_m32_p32(x86code *&dst, x86_memref memref, const be_parameter ¶m, const uml::instruction &inst); + void emit_rcr_r32_p32(x86code *&dst, UINT8 reg, const be_parameter ¶m, const uml::instruction &inst); + void emit_rcr_m32_p32(x86code *&dst, x86_memref memref, const be_parameter ¶m, const uml::instruction &inst); + + // 64-bit code emission helpers + void emit_mov_r64_p64(x86code *&dst, UINT8 reg, const be_parameter ¶m); + void emit_mov_r64_p64_keepflags(x86code *&dst, UINT8 reg, const be_parameter ¶m); + void emit_mov_p64_r64(x86code *&dst, const be_parameter ¶m, UINT8 reg); + void emit_add_r64_p64(x86code *&dst, UINT8 reg, const be_parameter ¶m, const uml::instruction &inst); + void emit_add_m64_p64(x86code *&dst, x86_memref memref, const be_parameter ¶m, const uml::instruction &inst); + void emit_adc_r64_p64(x86code *&dst, UINT8 reg, const be_parameter ¶m, const uml::instruction &inst); + void emit_adc_m64_p64(x86code *&dst, x86_memref memref, const be_parameter ¶m, const uml::instruction &inst); + void emit_sub_r64_p64(x86code *&dst, UINT8 reg, const be_parameter ¶m, const uml::instruction &inst); + void emit_sub_m64_p64(x86code *&dst, x86_memref memref, const be_parameter ¶m, const uml::instruction &inst); + void emit_sbb_r64_p64(x86code *&dst, UINT8 reg, const be_parameter ¶m, const uml::instruction &inst); + void emit_sbb_m64_p64(x86code *&dst, x86_memref memref, const be_parameter ¶m, const uml::instruction &inst); + void emit_cmp_r64_p64(x86code *&dst, UINT8 reg, const be_parameter ¶m, const uml::instruction &inst); + void emit_cmp_m64_p64(x86code *&dst, x86_memref memref, const be_parameter ¶m, const uml::instruction &inst); + void emit_and_r64_p64(x86code *&dst, UINT8 reg, const be_parameter ¶m, const uml::instruction &inst); + void emit_and_m64_p64(x86code *&dst, x86_memref memref, const be_parameter ¶m, const uml::instruction &inst); + void emit_test_r64_p64(x86code *&dst, UINT8 reg, const be_parameter ¶m, const uml::instruction &inst); + void emit_test_m64_p64(x86code *&dst, x86_memref memref, const be_parameter ¶m, const uml::instruction &inst); + void emit_or_r64_p64(x86code *&dst, UINT8 reg, const be_parameter ¶m, const uml::instruction &inst); + void emit_or_m64_p64(x86code *&dst, x86_memref memref, const be_parameter ¶m, const uml::instruction &inst); + void emit_xor_r64_p64(x86code *&dst, UINT8 reg, const be_parameter ¶m, const uml::instruction &inst); + void emit_xor_m64_p64(x86code *&dst, x86_memref memref, const be_parameter ¶m, const uml::instruction &inst); + void emit_shl_r64_p64(x86code *&dst, UINT8 reg, const be_parameter ¶m, const uml::instruction &inst); + void emit_shl_m64_p64(x86code *&dst, x86_memref memref, const be_parameter ¶m, const uml::instruction &inst); + void emit_shr_r64_p64(x86code *&dst, UINT8 reg, const be_parameter ¶m, const uml::instruction &inst); + void emit_shr_m64_p64(x86code *&dst, x86_memref memref, const be_parameter ¶m, const uml::instruction &inst); + void emit_sar_r64_p64(x86code *&dst, UINT8 reg, const be_parameter ¶m, const uml::instruction &inst); + void emit_sar_m64_p64(x86code *&dst, x86_memref memref, const be_parameter ¶m, const uml::instruction &inst); + void emit_rol_r64_p64(x86code *&dst, UINT8 reg, const be_parameter ¶m, const uml::instruction &inst); + void emit_rol_m64_p64(x86code *&dst, x86_memref memref, const be_parameter ¶m, const uml::instruction &inst); + void emit_ror_r64_p64(x86code *&dst, UINT8 reg, const be_parameter ¶m, const uml::instruction &inst); + void emit_ror_m64_p64(x86code *&dst, x86_memref memref, const be_parameter ¶m, const uml::instruction &inst); + void emit_rcl_r64_p64(x86code *&dst, UINT8 reg, const be_parameter ¶m, const uml::instruction &inst); + void emit_rcl_m64_p64(x86code *&dst, x86_memref memref, const be_parameter ¶m, const uml::instruction &inst); + void emit_rcr_r64_p64(x86code *&dst, UINT8 reg, const be_parameter ¶m, const uml::instruction &inst); + void emit_rcr_m64_p64(x86code *&dst, x86_memref memref, const be_parameter ¶m, const uml::instruction &inst); + + // floating-point code emission helpers + void emit_movss_r128_p32(x86code *&dst, UINT8 reg, const be_parameter ¶m); + void emit_movss_p32_r128(x86code *&dst, const be_parameter ¶m, UINT8 reg); + void emit_movsd_r128_p64(x86code *&dst, UINT8 reg, const be_parameter ¶m); + void emit_movsd_p64_r128(x86code *&dst, const be_parameter ¶m, UINT8 reg); + + // internal state + drc_hash_table m_hash; // hash table state + drc_map_variables m_map; // code map + drc_label_list m_labels; // label list + x86log_context * m_log; // logging + bool m_sse41; // do we have SSE4.1 support? + + UINT32 * m_absmask32; // absolute value mask (32-bit) + UINT64 * m_absmask64; // absolute value mask (32-bit) + UINT8 * m_rbpvalue; // value of RBP + + x86_entry_point_func m_entry; // entry point + x86code * m_exit; // exit point + x86code * m_nocode; // nocode handler + + drc_label_fixup_delegate m_fixup_label; // precomputed delegate for fixups + drc_oob_delegate m_fixup_exception; // precomputed delegate for exception fixups + + // state to live in the near cache + struct near_state + { + x86code * debug_cpu_instruction_hook;// debugger callback + x86code * debug_log_hashjmp; // hashjmp debugging + x86code * debug_log_hashjmp_fail; // hashjmp debugging + x86code * drcmap_get_value; // map lookup helper + + UINT32 ssemode; // saved SSE mode + UINT32 ssemodesave; // temporary location for saving + UINT32 ssecontrol[4]; // copy of the sse_control array + float single1; // 1.0 is single-precision + double double1; // 1.0 in double-precision + + void * stacksave; // saved stack pointer + void * hashstacksave; // saved stack pointer for hashjmp + + UINT8 flagsmap[0x1000]; // flags map + UINT64 flagsunmap[0x20]; // flags unmapper + }; + near_state & m_near; + + // globals + typedef void (drcbe_x64::*opcode_generate_func)(x86code *&dst, const uml::instruction &inst); + struct opcode_table_entry + { + uml::opcode_t opcode; // opcode in question + opcode_generate_func func; // function pointer to the work + }; + static const opcode_table_entry s_opcode_table_source[]; + static opcode_generate_func s_opcode_table[uml::OP_MAX]; +}; + + +#endif /* __DRCBEC_H__ */ diff --git a/src/devices/cpu/drcbex86.c b/src/devices/cpu/drcbex86.c new file mode 100644 index 00000000000..b52ece2b0cc --- /dev/null +++ b/src/devices/cpu/drcbex86.c @@ -0,0 +1,6589 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + drcbex86.c + + 32-bit x86 back-end for the universal machine language. + +**************************************************************************** + + Future improvements/changes: + + * Optimize to avoid unnecessary reloads + - especially EDX for 64-bit operations + - also FCMP/FLAGS has unnecessary PUSHF/POP EAX + + * Identify common pairs and optimize output + + * Convert SUB a,0,b to NEG + + * Optimize, e.g., and [r5],i0,$FF to use ebx as temporary register + (avoid initial move) if i0 is not needed going forward + +**************************************************************************** + + --------------- + ABI/conventions + --------------- + + Registers: + EAX - volatile, function return value + EBX - non-volatile + ECX - volatile + EDX - volatile, function return value (upper 32 bits) + ESI - non-volatile + EDI - non-volatile + EBP - non-volatile + + FP stack - volatile + + + --------------- + Execution model + --------------- + + Registers: + EAX - scratch register + EBX - maps to I0 (low 32 bits) + ECX - scratch register + EDX - scratch register + ESI - maps to I1 (low 32 bits) + EDI - maps to I2 (low 32 bits) + EBP - maps to I3 (low 32 bits) + + FP stack - scratch registers + + Entry point: + Assumes 1 parameter passed, which is the codeptr of the code + to execute once the environment is set up. + + Exit point: + Assumes exit value is in EAX. + + Entry stack: + [esp] - return + [esp+4] - input parameter (entry handle) + + Runtime stack: + [esp] - param 0 + [esp+4] - param 1 + [esp+8] - param 2 + [esp+12] - param 3 + [esp+16] - param 4 + [esp+20] - alignment + [esp+24] - alignment + [esp+28] - saved ebp + [esp+32] - saved edi + [esp+36] - saved esi + [esp+40] - saved ebx + [esp+44] - ret + [esp+48] - input parameter (entry handle) + +**************************************************************************/ + +#include +#include "emu.h" +#include "debugger.h" +#include "drcuml.h" +#include "drcbex86.h" + +using namespace uml; +using namespace x86emit; + + +//************************************************************************** +// DEBUGGING +//************************************************************************** + +#define LOG_HASHJMPS (0) + + + +//************************************************************************** +// CONSTANTS +//************************************************************************** + +const UINT32 PTYPE_M = 1 << parameter::PTYPE_MEMORY; +const UINT32 PTYPE_I = 1 << parameter::PTYPE_IMMEDIATE; +const UINT32 PTYPE_R = 1 << parameter::PTYPE_INT_REGISTER; +const UINT32 PTYPE_F = 1 << parameter::PTYPE_FLOAT_REGISTER; +//const UINT32 PTYPE_MI = PTYPE_M | PTYPE_I; +//const UINT32 PTYPE_RI = PTYPE_R | PTYPE_I; +const UINT32 PTYPE_MR = PTYPE_M | PTYPE_R; +const UINT32 PTYPE_MRI = PTYPE_M | PTYPE_R | PTYPE_I; +const UINT32 PTYPE_MF = PTYPE_M | PTYPE_F; + + + +//************************************************************************** +// MACROS +//************************************************************************** + +#define X86_CONDITION(condition) (condition_map[condition - uml::COND_Z]) +#define X86_NOT_CONDITION(condition) (condition_map[condition - uml::COND_Z] ^ 1) + +#define assert_no_condition(inst) assert((inst).condition() == uml::COND_ALWAYS) +#define assert_any_condition(inst) assert((inst).condition() == uml::COND_ALWAYS || ((inst).condition() >= uml::COND_Z && (inst).condition() < uml::COND_MAX)) +#define assert_no_flags(inst) assert((inst).flags() == 0) +#define assert_flags(inst, valid) assert(((inst).flags() & ~(valid)) == 0) + + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +drcbe_x86::opcode_generate_func drcbe_x86::s_opcode_table[OP_MAX]; + +// size-to-mask table +//static const UINT64 size_to_mask[] = { 0, 0xff, 0xffff, 0, 0xffffffff, 0, 0, 0, U64(0xffffffffffffffff) }; + +// register mapping tables +static const UINT8 int_register_map[REG_I_COUNT] = +{ + REG_EBX, REG_ESI, REG_EDI, REG_EBP +}; + +// flags mapping tables +static UINT8 flags_map[0x1000]; +static UINT32 flags_unmap[0x20]; + +// condition mapping table +static const UINT8 condition_map[uml::COND_MAX - uml::COND_Z] = +{ + x86emit::COND_Z, // COND_Z = 0x80, requires Z + x86emit::COND_NZ, // COND_NZ, requires Z + x86emit::COND_S, // COND_S, requires S + x86emit::COND_NS, // COND_NS, requires S + x86emit::COND_C, // COND_C, requires C + x86emit::COND_NC, // COND_NC, requires C + x86emit::COND_O, // COND_V, requires V + x86emit::COND_NO, // COND_NV, requires V + x86emit::COND_P, // COND_U, requires U + x86emit::COND_NP, // COND_NU, requires U + x86emit::COND_A, // COND_A, requires CZ + x86emit::COND_BE, // COND_BE, requires CZ + x86emit::COND_G, // COND_G, requires SVZ + x86emit::COND_LE, // COND_LE, requires SVZ + x86emit::COND_L, // COND_L, requires SV + x86emit::COND_GE, // COND_GE, requires SV +}; + +// FPU control register mapping +static const UINT16 fp_control[4] = +{ + 0x0e3f, // ROUND_TRUNC + 0x023f, // ROUND_ROUND + 0x0a3f, // ROUND_CEIL + 0x063f // ROUND_FLOOR +}; + + + +//************************************************************************** +// TABLES +//************************************************************************** + +const drcbe_x86::opcode_table_entry drcbe_x86::s_opcode_table_source[] = +{ + // Compile-time opcodes + { uml::OP_HANDLE, &drcbe_x86::op_handle }, // HANDLE handle + { uml::OP_HASH, &drcbe_x86::op_hash }, // HASH mode,pc + { uml::OP_LABEL, &drcbe_x86::op_label }, // LABEL imm + { uml::OP_COMMENT, &drcbe_x86::op_comment }, // COMMENT string + { uml::OP_MAPVAR, &drcbe_x86::op_mapvar }, // MAPVAR mapvar,value + + // Control Flow Operations + { uml::OP_NOP, &drcbe_x86::op_nop }, // NOP + { uml::OP_DEBUG, &drcbe_x86::op_debug }, // DEBUG pc + { uml::OP_EXIT, &drcbe_x86::op_exit }, // EXIT src1[,c] + { uml::OP_HASHJMP, &drcbe_x86::op_hashjmp }, // HASHJMP mode,pc,handle + { uml::OP_JMP, &drcbe_x86::op_jmp }, // JMP imm[,c] + { uml::OP_EXH, &drcbe_x86::op_exh }, // EXH handle,param[,c] + { uml::OP_CALLH, &drcbe_x86::op_callh }, // CALLH handle[,c] + { uml::OP_RET, &drcbe_x86::op_ret }, // RET [c] + { uml::OP_CALLC, &drcbe_x86::op_callc }, // CALLC func,ptr[,c] + { uml::OP_RECOVER, &drcbe_x86::op_recover }, // RECOVER dst,mapvar + + // Internal Register Operations + { uml::OP_SETFMOD, &drcbe_x86::op_setfmod }, // SETFMOD src + { uml::OP_GETFMOD, &drcbe_x86::op_getfmod }, // GETFMOD dst + { uml::OP_GETEXP, &drcbe_x86::op_getexp }, // GETEXP dst + { uml::OP_GETFLGS, &drcbe_x86::op_getflgs }, // GETFLGS dst[,f] + { uml::OP_SAVE, &drcbe_x86::op_save }, // SAVE dst + { uml::OP_RESTORE, &drcbe_x86::op_restore }, // RESTORE dst + + // Integer Operations + { uml::OP_LOAD, &drcbe_x86::op_load }, // LOAD dst,base,index,size + { uml::OP_LOADS, &drcbe_x86::op_loads }, // LOADS dst,base,index,size + { uml::OP_STORE, &drcbe_x86::op_store }, // STORE base,index,src,size + { uml::OP_READ, &drcbe_x86::op_read }, // READ dst,src1,spacesize + { uml::OP_READM, &drcbe_x86::op_readm }, // READM dst,src1,mask,spacesize + { uml::OP_WRITE, &drcbe_x86::op_write }, // WRITE dst,src1,spacesize + { uml::OP_WRITEM, &drcbe_x86::op_writem }, // WRITEM dst,src1,spacesize + { uml::OP_CARRY, &drcbe_x86::op_carry }, // CARRY src,bitnum + { uml::OP_SET, &drcbe_x86::op_set }, // SET dst,c + { uml::OP_MOV, &drcbe_x86::op_mov }, // MOV dst,src[,c] + { uml::OP_SEXT, &drcbe_x86::op_sext }, // SEXT dst,src + { uml::OP_ROLAND, &drcbe_x86::op_roland }, // ROLAND dst,src1,src2,src3 + { uml::OP_ROLINS, &drcbe_x86::op_rolins }, // ROLINS dst,src1,src2,src3 + { uml::OP_ADD, &drcbe_x86::op_add }, // ADD dst,src1,src2[,f] + { uml::OP_ADDC, &drcbe_x86::op_addc }, // ADDC dst,src1,src2[,f] + { uml::OP_SUB, &drcbe_x86::op_sub }, // SUB dst,src1,src2[,f] + { uml::OP_SUBB, &drcbe_x86::op_subc }, // SUBB dst,src1,src2[,f] + { uml::OP_CMP, &drcbe_x86::op_cmp }, // CMP src1,src2[,f] + { uml::OP_MULU, &drcbe_x86::op_mulu }, // MULU dst,edst,src1,src2[,f] + { uml::OP_MULS, &drcbe_x86::op_muls }, // MULS dst,edst,src1,src2[,f] + { uml::OP_DIVU, &drcbe_x86::op_divu }, // DIVU dst,edst,src1,src2[,f] + { uml::OP_DIVS, &drcbe_x86::op_divs }, // DIVS dst,edst,src1,src2[,f] + { uml::OP_AND, &drcbe_x86::op_and }, // AND dst,src1,src2[,f] + { uml::OP_TEST, &drcbe_x86::op_test }, // TEST src1,src2[,f] + { uml::OP_OR, &drcbe_x86::op_or }, // OR dst,src1,src2[,f] + { uml::OP_XOR, &drcbe_x86::op_xor }, // XOR dst,src1,src2[,f] + { uml::OP_LZCNT, &drcbe_x86::op_lzcnt }, // LZCNT dst,src[,f] + { uml::OP_BSWAP, &drcbe_x86::op_bswap }, // BSWAP dst,src + { uml::OP_SHL, &drcbe_x86::op_shl }, // SHL dst,src,count[,f] + { uml::OP_SHR, &drcbe_x86::op_shr }, // SHR dst,src,count[,f] + { uml::OP_SAR, &drcbe_x86::op_sar }, // SAR dst,src,count[,f] + { uml::OP_ROL, &drcbe_x86::op_rol }, // ROL dst,src,count[,f] + { uml::OP_ROLC, &drcbe_x86::op_rolc }, // ROLC dst,src,count[,f] + { uml::OP_ROR, &drcbe_x86::op_ror }, // ROR dst,src,count[,f] + { uml::OP_RORC, &drcbe_x86::op_rorc }, // RORC dst,src,count[,f] + + // Floating Point Operations + { uml::OP_FLOAD, &drcbe_x86::op_fload }, // FLOAD dst,base,index + { uml::OP_FSTORE, &drcbe_x86::op_fstore }, // FSTORE base,index,src + { uml::OP_FREAD, &drcbe_x86::op_fread }, // FREAD dst,space,src1 + { uml::OP_FWRITE, &drcbe_x86::op_fwrite }, // FWRITE space,dst,src1 + { uml::OP_FMOV, &drcbe_x86::op_fmov }, // FMOV dst,src1[,c] + { uml::OP_FTOINT, &drcbe_x86::op_ftoint }, // FTOINT dst,src1,size,round + { uml::OP_FFRINT, &drcbe_x86::op_ffrint }, // FFRINT dst,src1,size + { uml::OP_FFRFLT, &drcbe_x86::op_ffrflt }, // FFRFLT dst,src1,size + { uml::OP_FRNDS, &drcbe_x86::op_frnds }, // FRNDS dst,src1 + { uml::OP_FADD, &drcbe_x86::op_fadd }, // FADD dst,src1,src2 + { uml::OP_FSUB, &drcbe_x86::op_fsub }, // FSUB dst,src1,src2 + { uml::OP_FCMP, &drcbe_x86::op_fcmp }, // FCMP src1,src2 + { uml::OP_FMUL, &drcbe_x86::op_fmul }, // FMUL dst,src1,src2 + { uml::OP_FDIV, &drcbe_x86::op_fdiv }, // FDIV dst,src1,src2 + { uml::OP_FNEG, &drcbe_x86::op_fneg }, // FNEG dst,src1 + { uml::OP_FABS, &drcbe_x86::op_fabs }, // FABS dst,src1 + { uml::OP_FSQRT, &drcbe_x86::op_fsqrt }, // FSQRT dst,src1 + { uml::OP_FRECIP, &drcbe_x86::op_frecip }, // FRECIP dst,src1 + { uml::OP_FRSQRT, &drcbe_x86::op_frsqrt } // FRSQRT dst,src1 +}; + + + +//************************************************************************** +// INLINE FUNCTIONS +//************************************************************************** + +//------------------------------------------------- +// param_normalize - convert a full parameter +// into a reduced set +//------------------------------------------------- + +drcbe_x86::be_parameter::be_parameter(drcbe_x86 &drcbe, const parameter ¶m, UINT32 allowed) +{ + int regnum; + + switch (param.type()) + { + // immediates pass through + case parameter::PTYPE_IMMEDIATE: + assert(allowed & PTYPE_I); + *this = param.immediate(); + break; + + // memory passes through + case parameter::PTYPE_MEMORY: + assert(allowed & PTYPE_M); + *this = make_memory(param.memory()); + break; + + // if a register maps to a register, keep it as a register; otherwise map it to memory + case parameter::PTYPE_INT_REGISTER: + assert(allowed & PTYPE_R); + assert(allowed & PTYPE_M); + regnum = int_register_map[param.ireg() - REG_I0]; + if (regnum != 0) + *this = make_ireg(regnum); + else + *this = make_memory(&drcbe.m_state.r[param.ireg() - REG_I0]); + break; + + // if a register maps to a register, keep it as a register; otherwise map it to memory + case parameter::PTYPE_FLOAT_REGISTER: + assert(allowed & PTYPE_F); + assert(allowed & PTYPE_M); + *this = make_memory(&drcbe.m_state.f[param.freg() - REG_F0]); + break; + + // everything else is unexpected + default: + fatalerror("Unexpected parameter type\n"); + } +} + + +//------------------------------------------------- +// select_register - select a register to use, +// avoiding conflicts with the optional +// checkparam +//------------------------------------------------- + +inline int drcbe_x86::be_parameter::select_register(int defreg) const +{ + if (m_type == PTYPE_INT_REGISTER || m_type == PTYPE_FLOAT_REGISTER || m_type == PTYPE_VECTOR_REGISTER) + return m_value; + return defreg; +} + +inline int drcbe_x86::be_parameter::select_register(int defreg, const be_parameter &checkparam) const +{ + if (*this == checkparam) + return defreg; + return select_register(defreg); +} + +inline int drcbe_x86::be_parameter::select_register(int defreg, const be_parameter &checkparam, const be_parameter &checkparam2) const +{ + if (*this == checkparam || *this == checkparam2) + return defreg; + return select_register(defreg); +} + + +//------------------------------------------------- +// select_register - select a register to use, +// avoiding conflicts with the optional +// checkparam +//------------------------------------------------- + +inline void drcbe_x86::normalize_commutative(be_parameter &inner, be_parameter &outer) +{ + // if the inner parameter is a memory operand, push it to the outer + if (inner.is_memory()) + { + be_parameter temp = inner; + inner = outer; + outer = temp; + } + + // if the inner parameter is an immediate, push it to the outer + if (inner.is_immediate()) + { + be_parameter temp = inner; + inner = outer; + outer = temp; + } +} + + +//------------------------------------------------- +// emit_combine_z_flags - combine the Z flag from +// two 32-bit operations +//------------------------------------------------- + +inline void drcbe_x86::emit_combine_z_flags(x86code *&dst) +{ + // this assumes that the flags from the low 32-bit op are on the stack + // and the flags from the high 32-bit op are live + emit_pushf(dst); // pushf + emit_mov_r32_m32(dst, REG_ECX, MBD(REG_ESP, 4)); // mov ecx,[esp+4] + emit_or_r32_imm(dst, REG_ECX, ~0x40); // or ecx,~0x40 + emit_and_m32_r32(dst, MBD(REG_ESP, 0), REG_ECX); // and [esp],ecx + emit_popf(dst); // popf + emit_lea_r32_m32(dst, REG_ESP, MBD(REG_ESP, 4)); // lea esp,[esp+4] +} + + +//------------------------------------------------- +// emit_combine_z_shl_flags - combine the Z +// flags from two 32-bit shift left operations +//------------------------------------------------- + +inline void drcbe_x86::emit_combine_z_shl_flags(x86code *&dst) +{ + // this assumes that the flags from the high 32-bit op are on the stack + // and the flags from the low 32-bit op are live + emit_pushf(dst); // pushf + emit_pop_r32(dst, REG_ECX); // pop ecx + emit_or_r32_imm(dst, REG_ECX, ~0x40); // or ecx,~0x40 + emit_and_m32_r32(dst, MBD(REG_ESP, 0), REG_ECX); // and [esp],ecx + emit_popf(dst); // popf +} + + +//------------------------------------------------- +// reset_last_upper_lower_reg - reset the last +// upper/lower register state +//------------------------------------------------- + +inline void drcbe_x86::reset_last_upper_lower_reg() +{ + m_last_lower_reg = REG_NONE; + m_last_upper_reg = REG_NONE; +} + + +//------------------------------------------------- +// set_last_lower_reg - note that we have just +// loaded a lower register +//------------------------------------------------- + +inline void drcbe_x86::set_last_lower_reg(x86code *&dst, const be_parameter ¶m, UINT8 reglo) +{ + if (param.is_memory()) + { + m_last_lower_reg = reglo; + m_last_lower_addr = (UINT32 *)((FPTR)param.memory()); + m_last_lower_pc = dst; + } +} + + +//------------------------------------------------- +// set_last_upper_reg - note that we have just +// loaded an upper register +//------------------------------------------------- + +inline void drcbe_x86::set_last_upper_reg(x86code *&dst, const be_parameter ¶m, UINT8 reghi) +{ + m_last_upper_reg = reghi; + m_last_upper_addr = (param.is_int_register()) ? m_reghi[param.ireg()] : (UINT32 *)((FPTR)param.memory(4)); + m_last_upper_pc = dst; +} + + +//------------------------------------------------- +// can_skip_lower_load - return true if we can +// skip re-loading a lower half of a register +//------------------------------------------------- + +inline bool drcbe_x86::can_skip_lower_load(x86code *&dst, UINT32 *memref, UINT8 reglo) +{ + return (dst == m_last_lower_pc && memref == m_last_lower_addr && reglo == m_last_lower_reg); +} + + +//------------------------------------------------- +// can_skip_upper_load - return true if we can +// skip re-loading an upper half of a register +//------------------------------------------------- + +inline bool drcbe_x86::can_skip_upper_load(x86code *&dst, UINT32 *memref, UINT8 reghi) +{ + return (dst == m_last_upper_pc && memref == m_last_upper_addr && reghi == m_last_upper_reg); +} + + +//------------------------------------------------- +// track_resolve_link - wrapper for resolve_link +// that resets all register tracking info +//------------------------------------------------- + +inline void drcbe_x86::track_resolve_link(x86code *&destptr, const emit_link &linkinfo) +{ + reset_last_upper_lower_reg(); + resolve_link(destptr, linkinfo); +} + +#define resolve_link INVALID + + + +//************************************************************************** +// BACKEND CALLBACKS +//************************************************************************** + +//------------------------------------------------- +// drcbe_x86 - constructor +//------------------------------------------------- + +drcbe_x86::drcbe_x86(drcuml_state &drcuml, device_t &device, drc_cache &cache, UINT32 flags, int modes, int addrbits, int ignorebits) + : drcbe_interface(drcuml, cache, device), + m_hash(cache, modes, addrbits, ignorebits), + m_map(cache, 0), + m_labels(cache), + m_log(NULL), + m_logged_common(false), + m_sse3(false), + m_entry(NULL), + m_exit(NULL), + m_nocode(NULL), + m_save(NULL), + m_restore(NULL), + m_last_lower_reg(REG_NONE), + m_last_lower_pc(NULL), + m_last_lower_addr(NULL), + m_last_upper_reg(REG_NONE), + m_last_upper_pc(NULL), + m_last_upper_addr(NULL), + m_fptemp(0), + m_fpumode(0), + m_fmodesave(0), + m_stacksave(0), + m_hashstacksave(0), + m_reslo(0), + m_reshi(0), + m_fixup_label(FUNC(drcbe_x86::fixup_label), this), + m_fixup_exception(FUNC(drcbe_x86::fixup_exception), this) +{ + // compute hi pointers for each register + for (int regnum = 0; regnum < ARRAY_LENGTH(int_register_map); regnum++) + if (int_register_map[regnum] != 0) + { + m_reglo[int_register_map[regnum]] = &m_state.r[regnum].w.l; + m_reghi[int_register_map[regnum]] = &m_state.r[regnum].w.h; + } + + // build the flags map (static but it doesn't hurt to regenerate it) + for (int entry = 0; entry < ARRAY_LENGTH(flags_map); entry++) + { + UINT8 flags = 0; + if (entry & 0x001) flags |= FLAG_C; + if (entry & 0x004) flags |= FLAG_U; + if (entry & 0x040) flags |= FLAG_Z; + if (entry & 0x080) flags |= FLAG_S; + if (entry & 0x800) flags |= FLAG_V; + flags_map[entry] = flags; + } + for (int entry = 0; entry < ARRAY_LENGTH(flags_unmap); entry++) + { + UINT32 flags = 0; + if (entry & FLAG_C) flags |= 0x001; + if (entry & FLAG_U) flags |= 0x004; + if (entry & FLAG_Z) flags |= 0x040; + if (entry & FLAG_S) flags |= 0x080; + if (entry & FLAG_V) flags |= 0x800; + flags_unmap[entry] = flags; + } + + // build the opcode table (static but it doesn't hurt to regenerate it) + for (int opnum = 0; opnum < ARRAY_LENGTH(s_opcode_table_source); opnum++) + s_opcode_table[s_opcode_table_source[opnum].opcode] = s_opcode_table_source[opnum].func; + + // create the log + if (device.machine().options().drc_log_native()) + { + std::string filename = std::string("drcbex86_").append(device.shortname()).append(".asm"); + m_log = x86log_create_context(filename.c_str()); + } +} + + +//------------------------------------------------- +// ~drcbe_x86 - destructor +//------------------------------------------------- + +drcbe_x86::~drcbe_x86() +{ + // free the log context + if (m_log != NULL) + x86log_free_context(m_log); +} + + +//------------------------------------------------- +// reset - reset back-end specific state +//------------------------------------------------- + +void drcbe_x86::reset() +{ + // output a note to the log + if (m_log != NULL) + x86log_printf(m_log, "\n\n===========\nCACHE RESET\n===========\n\n"); + + // generate a little bit of glue code to set up the environment + drccodeptr *cachetop = m_cache.begin_codegen(500); + if (cachetop == NULL) + fatalerror("Out of cache space after a reset!\n"); + + x86code *dst = (x86code *)*cachetop; + + // generate a simple CPUID stub + UINT32 (*cpuid_ecx_stub)(void) = (UINT32 (*)(void))dst; + emit_push_r32(dst, REG_EBX); // push ebx + emit_mov_r32_imm(dst, REG_EAX, 1); // mov eax,1 + emit_cpuid(dst); // cpuid + emit_mov_r32_r32(dst, REG_EAX, REG_ECX); // mov eax,ecx + emit_pop_r32(dst, REG_EBX); // pop ebx + emit_ret(dst); // ret + + // call it to determine if we have SSE3 support + m_sse3 = (((*cpuid_ecx_stub)() & 1) != 0); + + // generate an entry point + m_entry = (x86_entry_point_func)dst; + emit_mov_r32_m32(dst, REG_EAX, MBD(REG_ESP, 4)); // mov eax,[esp+4] + emit_push_r32(dst, REG_EBX); // push ebx + emit_push_r32(dst, REG_ESI); // push esi + emit_push_r32(dst, REG_EDI); // push edi + emit_push_r32(dst, REG_EBP); // push ebp + emit_sub_r32_imm(dst, REG_ESP, 24); // sub esp,24 + emit_mov_m32_r32(dst, MABS(&m_hashstacksave), REG_ESP); // mov [hashstacksave],esp + emit_sub_r32_imm(dst, REG_ESP, 4); // sub esp,4 + emit_mov_m32_r32(dst, MABS(&m_stacksave), REG_ESP); // mov [stacksave],esp + emit_fstcw_m16(dst, MABS(&m_fpumode)); // fstcw [fpumode] + emit_jmp_r32(dst, REG_EAX); // jmp eax + if (m_log != NULL && !m_logged_common) + x86log_disasm_code_range(m_log, "entry_point", (x86code *)m_entry, dst); + + // generate an exit point + m_exit = dst; + emit_fldcw_m16(dst, MABS(&m_fpumode)); // fldcw [fpumode] + emit_mov_r32_m32(dst, REG_ESP, MABS(&m_hashstacksave)); // mov esp,[hashstacksave] + emit_add_r32_imm(dst, REG_ESP, 24); // add esp,24 + emit_pop_r32(dst, REG_EBP); // pop ebp + emit_pop_r32(dst, REG_EDI); // pop edi + emit_pop_r32(dst, REG_ESI); // pop esi + emit_pop_r32(dst, REG_EBX); // pop ebx + emit_ret(dst); // ret + if (m_log != NULL && !m_logged_common) + x86log_disasm_code_range(m_log, "exit_point", m_exit, dst); + + // generate a no code point + m_nocode = dst; + emit_ret(dst); // ret + if (m_log != NULL && !m_logged_common) + x86log_disasm_code_range(m_log, "nocode", m_nocode, dst); + + // generate a save subroutine + m_save = dst; + emit_pushf(dst); // pushf + emit_pop_r32(dst, REG_EAX); // pop eax + emit_and_r32_imm(dst, REG_EAX, 0x8c5); // and eax,0x8c5 + emit_mov_r8_m8(dst, REG_AL, MABSI(flags_map, REG_EAX)); // mov al,[flags_map] + emit_mov_m8_r8(dst, MBD(REG_ECX, offsetof(drcuml_machine_state, flags)), REG_AL); // mov state->flags,al + emit_mov_r8_m8(dst, REG_AL, MABS(&m_state.fmod)); // mov al,[fmod] + emit_mov_m8_r8(dst, MBD(REG_ECX, offsetof(drcuml_machine_state, fmod)), REG_AL); // mov state->fmod,al + emit_mov_r32_m32(dst, REG_EAX, MABS(&m_state.exp)); // mov eax,[exp] + emit_mov_m32_r32(dst, MBD(REG_ECX, offsetof(drcuml_machine_state, exp)), REG_EAX); // mov state->exp,eax + for (int regnum = 0; regnum < ARRAY_LENGTH(m_state.r); regnum++) + { + FPTR regoffsl = (FPTR)&((drcuml_machine_state *)NULL)->r[regnum].w.l; + FPTR regoffsh = (FPTR)&((drcuml_machine_state *)NULL)->r[regnum].w.h; + if (int_register_map[regnum] != 0) + emit_mov_m32_r32(dst, MBD(REG_ECX, regoffsl), int_register_map[regnum]); + else + { + emit_mov_r32_m32(dst, REG_EAX, MABS(&m_state.r[regnum].w.l)); + emit_mov_m32_r32(dst, MBD(REG_ECX, regoffsl), REG_EAX); + } + emit_mov_r32_m32(dst, REG_EAX, MABS(&m_state.r[regnum].w.h)); + emit_mov_m32_r32(dst, MBD(REG_ECX, regoffsh), REG_EAX); + } + for (int regnum = 0; regnum < ARRAY_LENGTH(m_state.f); regnum++) + { + FPTR regoffsl = (FPTR)&((drcuml_machine_state *)NULL)->f[regnum].s.l; + FPTR regoffsh = (FPTR)&((drcuml_machine_state *)NULL)->f[regnum].s.h; + emit_mov_r32_m32(dst, REG_EAX, MABS(&m_state.f[regnum].s.l)); + emit_mov_m32_r32(dst, MBD(REG_ECX, regoffsl), REG_EAX); + emit_mov_r32_m32(dst, REG_EAX, MABS(&m_state.f[regnum].s.h)); + emit_mov_m32_r32(dst, MBD(REG_ECX, regoffsh), REG_EAX); + } + emit_ret(dst); // ret + if (m_log != NULL && !m_logged_common) + x86log_disasm_code_range(m_log, "save", m_save, dst); + + // generate a restore subroutine + m_restore = dst; + for (int regnum = 0; regnum < ARRAY_LENGTH(m_state.r); regnum++) + { + FPTR regoffsl = (FPTR)&((drcuml_machine_state *)NULL)->r[regnum].w.l; + FPTR regoffsh = (FPTR)&((drcuml_machine_state *)NULL)->r[regnum].w.h; + if (int_register_map[regnum] != 0) + emit_mov_r32_m32(dst, int_register_map[regnum], MBD(REG_ECX, regoffsl)); + else + { + emit_mov_r32_m32(dst, REG_EAX, MBD(REG_ECX, regoffsl)); + emit_mov_m32_r32(dst, MABS(&m_state.r[regnum].w.l), REG_EAX); + } + emit_mov_r32_m32(dst, REG_EAX, MBD(REG_ECX, regoffsh)); + emit_mov_m32_r32(dst, MABS(&m_state.r[regnum].w.h), REG_EAX); + } + for (int regnum = 0; regnum < ARRAY_LENGTH(m_state.f); regnum++) + { + FPTR regoffsl = (FPTR)&((drcuml_machine_state *)NULL)->f[regnum].s.l; + FPTR regoffsh = (FPTR)&((drcuml_machine_state *)NULL)->f[regnum].s.h; + emit_mov_r32_m32(dst, REG_EAX, MBD(REG_ECX, regoffsl)); + emit_mov_m32_r32(dst, MABS(&m_state.f[regnum].s.l), REG_EAX); + emit_mov_r32_m32(dst, REG_EAX, MBD(REG_ECX, regoffsh)); + emit_mov_m32_r32(dst, MABS(&m_state.f[regnum].s.h), REG_EAX); + } + emit_movzx_r32_m8(dst, REG_EAX, MBD(REG_ECX, offsetof(drcuml_machine_state, fmod)));// movzx eax,state->fmod + emit_and_r32_imm(dst, REG_EAX, 3); // and eax,3 + emit_mov_m8_r8(dst, MABS(&m_state.fmod), REG_AL); // mov [fmod],al + emit_fldcw_m16(dst, MABSI(&fp_control[0], REG_EAX, 2)); // fldcw fp_control[eax] + emit_mov_r32_m32(dst, REG_EAX, MBD(REG_ECX, offsetof(drcuml_machine_state, exp))); // mov eax,state->exp + emit_mov_m32_r32(dst, MABS(&m_state.exp), REG_EAX); // mov [exp],eax + emit_movzx_r32_m8(dst, REG_EAX, MBD(REG_ECX, offsetof(drcuml_machine_state, flags)));// movzx eax,state->flags + emit_push_m32(dst, MABSI(flags_unmap, REG_EAX, 4)); // push flags_unmap[eax*4] + emit_popf(dst); // popf + emit_ret(dst); // ret + if (m_log != NULL && !m_logged_common) + x86log_disasm_code_range(m_log, "restore", m_restore, dst); + + // finish up codegen + *cachetop = dst; + m_cache.end_codegen(); + m_logged_common = true; + + // reset our hash tables + m_hash.reset(); + m_hash.set_default_codeptr(m_nocode); +} + + +//------------------------------------------------- +// drcbex86_execute - execute a block of code +// referenced by the given handle +//------------------------------------------------- + +int drcbe_x86::execute(code_handle &entry) +{ + // call our entry point which will jump to the destination + return (*m_entry)((x86code *)entry.codeptr()); +} + + +//------------------------------------------------- +// drcbex86_generate - generate code +//------------------------------------------------- + +void drcbe_x86::generate(drcuml_block &block, const instruction *instlist, UINT32 numinst) +{ + // tell all of our utility objects that a block is beginning + m_hash.block_begin(block, instlist, numinst); + m_labels.block_begin(block); + m_map.block_begin(block); + + // begin codegen; fail if we can't + drccodeptr *cachetop = m_cache.begin_codegen(numinst * 8 * 4); + if (cachetop == NULL) + block.abort(); + + // compute the base by aligning the cache top to a cache line (assumed to be 64 bytes) + x86code *base = (x86code *)(((FPTR)*cachetop + 63) & ~63); + x86code *dst = base; + + // generate code + std::string tempstring; + const char *blockname = NULL; + for (int inum = 0; inum < numinst; inum++) + { + const instruction &inst = instlist[inum]; + assert(inst.opcode() < ARRAY_LENGTH(s_opcode_table)); + + // add a comment + if (m_log != NULL) + { + std::string dasm; + inst.disasm(dasm, &m_drcuml); + x86log_add_comment(m_log, dst, "%s", dasm.c_str()); + } + + // extract a blockname + if (blockname == NULL) + { + if (inst.opcode() == OP_HANDLE) + blockname = inst.param(0).handle().string(); + else if (inst.opcode() == OP_HASH) + blockname = strformat(tempstring, "Code: mode=%d PC=%08X", (UINT32)inst.param(0).immediate(), (offs_t)inst.param(1).immediate()).c_str(); + } + + // generate code + (this->*s_opcode_table[inst.opcode()])(dst, inst); + } + + // complete codegen + *cachetop = (drccodeptr)dst; + m_cache.end_codegen(); + + // log it + if (m_log != NULL) + x86log_disasm_code_range(m_log, (blockname == NULL) ? "Unknown block" : blockname, base, m_cache.top()); + + // tell all of our utility objects that the block is finished + m_hash.block_end(block); + m_labels.block_end(block); + m_map.block_end(block); +} + + +//------------------------------------------------- +// drcbex86_hash_exists - return true if the +// given mode/pc exists in the hash table +//------------------------------------------------- + +bool drcbe_x86::hash_exists(UINT32 mode, UINT32 pc) +{ + return m_hash.code_exists(mode, pc); +} + + +//------------------------------------------------- +// drcbex86_get_info - return information about +// the back-end implementation +//------------------------------------------------- + +void drcbe_x86::get_info(drcbe_info &info) +{ + for (info.direct_iregs = 0; info.direct_iregs < REG_I_COUNT; info.direct_iregs++) + if (int_register_map[info.direct_iregs] == 0) + break; + info.direct_fregs = 0; +} + + + +//************************************************************************** +// EMITTERS FOR 32-BIT OPERATIONS WITH PARAMETERS +//************************************************************************** + +//------------------------------------------------- +// emit_mov_r32_p32 - move a 32-bit parameter +// into a register +//------------------------------------------------- + +void drcbe_x86::emit_mov_r32_p32(x86code *&dst, UINT8 reg, const be_parameter ¶m) +{ + if (param.is_immediate()) + { + if (param.immediate() == 0) + emit_xor_r32_r32(dst, reg, reg); // xor reg,reg + else + emit_mov_r32_imm(dst, reg, param.immediate()); // mov reg,param + } + else if (param.is_memory()) + emit_mov_r32_m32(dst, reg, MABS(param.memory())); // mov reg,[param] + else if (param.is_int_register()) + { + if (reg != param.ireg()) + emit_mov_r32_r32(dst, reg, param.ireg()); // mov reg,param + } +} + + +//------------------------------------------------- +// emit_mov_r32_p32_keepflags - move a 32-bit +// parameter into a register without affecting +// any flags +//------------------------------------------------- + +void drcbe_x86::emit_mov_r32_p32_keepflags(x86code *&dst, UINT8 reg, const be_parameter ¶m) +{ + if (param.is_immediate()) + emit_mov_r32_imm(dst, reg, param.immediate()); // mov reg,param + else if (param.is_memory()) + { + if (!can_skip_lower_load(dst, (UINT32 *)((FPTR)param.memory()), reg)) + emit_mov_r32_m32(dst, reg, MABS(param.memory())); // mov reg,[param] + } + else if (param.is_int_register()) + { + if (reg != param.ireg()) + emit_mov_r32_r32(dst, reg, param.ireg()); // mov reg,param + } +} + + +//------------------------------------------------- +// emit_mov_m32_p32 - move a 32-bit parameter +// into a memory location +//------------------------------------------------- + +void drcbe_x86::emit_mov_m32_p32(x86code *&dst, x86_memref memref, const be_parameter ¶m) +{ + if (param.is_immediate()) + emit_mov_m32_imm(dst, memref, param.immediate()); // mov [mem],param + else if (param.is_memory()) + { + if (!can_skip_lower_load(dst, (UINT32 *)((FPTR)param.memory()), REG_EAX)) + emit_mov_r32_m32(dst, REG_EAX, MABS(param.memory())); // mov eax,[param] + emit_mov_m32_r32(dst, memref, REG_EAX); // mov [mem],eax + } + else if (param.is_int_register()) + emit_mov_m32_r32(dst, memref, param.ireg()); // mov [mem],param +} + + +//------------------------------------------------- +// emit_mov_p32_r32 - move a register into a +// 32-bit parameter +//------------------------------------------------- + +void drcbe_x86::emit_mov_p32_r32(x86code *&dst, const be_parameter ¶m, UINT8 reg) +{ + assert(!param.is_immediate()); + if (param.is_memory()) + { + emit_mov_m32_r32(dst, MABS(param.memory()), reg); // mov [param],reg + set_last_lower_reg(dst, param, reg); + } + else if (param.is_int_register()) + { + if (reg != param.ireg()) + emit_mov_r32_r32(dst, param.ireg(), reg); // mov param,reg + } +} + + +//------------------------------------------------- +// emit_add_r32_p32 - add operation to a 32-bit +// register from a 32-bit parameter +//------------------------------------------------- + +void drcbe_x86::emit_add_r32_p32(x86code *&dst, UINT8 reg, const be_parameter ¶m, const instruction &inst) +{ + if (param.is_immediate()) + { + if (inst.flags() != 0 || param.immediate() != 0) + emit_add_r32_imm(dst, reg, param.immediate()); // add reg,param + } + else if (param.is_memory()) + emit_add_r32_m32(dst, reg, MABS(param.memory())); // add reg,[param] + else if (param.is_int_register()) + emit_add_r32_r32(dst, reg, param.ireg()); // add reg,param +} + + +//------------------------------------------------- +// emit_add_m32_p32 - add operation to a 32-bit +// memory location from a 32-bit parameter +//------------------------------------------------- + +void drcbe_x86::emit_add_m32_p32(x86code *&dst, x86_memref memref, const be_parameter ¶m, const instruction &inst) +{ + if (param.is_immediate()) + { + if (inst.flags() != 0 || param.immediate() != 0) + emit_add_m32_imm(dst, memref, param.immediate()); // add [dest],param + } + else + { + int reg = param.select_register(REG_EAX); + emit_mov_r32_p32(dst, reg, param); // mov reg,param + emit_add_m32_r32(dst, memref, reg); // add [dest],reg + } +} + + +//------------------------------------------------- +// emit_adc_r32_p32 - adc operation to a 32-bit +// register from a 32-bit parameter +//------------------------------------------------- + +void drcbe_x86::emit_adc_r32_p32(x86code *&dst, UINT8 reg, const be_parameter ¶m, const instruction &inst) +{ + if (param.is_immediate()) + emit_adc_r32_imm(dst, reg, param.immediate()); // adc reg,param + else if (param.is_memory()) + emit_adc_r32_m32(dst, reg, MABS(param.memory())); // adc reg,[param] + else if (param.is_int_register()) + emit_adc_r32_r32(dst, reg, param.ireg()); // adc reg,param +} + + +//------------------------------------------------- +// emit_adc_m32_p32 - adc operation to a 32-bit +// memory location from a 32-bit parameter +//------------------------------------------------- + +void drcbe_x86::emit_adc_m32_p32(x86code *&dst, x86_memref memref, const be_parameter ¶m, const instruction &inst) +{ + if (param.is_immediate()) + emit_adc_m32_imm(dst, memref, param.immediate()); // adc [dest],param + else + { + int reg = param.select_register(REG_EAX); + emit_mov_r32_p32_keepflags(dst, reg, param); // mov reg,param + emit_adc_m32_r32(dst, memref, reg); // adc [dest],reg + } +} + + +//------------------------------------------------- +// emit_sub_r32_p32 - sub operation to a 32-bit +// register from a 32-bit parameter +//------------------------------------------------- + +void drcbe_x86::emit_sub_r32_p32(x86code *&dst, UINT8 reg, const be_parameter ¶m, const instruction &inst) +{ + if (param.is_immediate()) + { + if (inst.flags() != 0 || param.immediate() != 0) + emit_sub_r32_imm(dst, reg, param.immediate()); // sub reg,param + } + else if (param.is_memory()) + emit_sub_r32_m32(dst, reg, MABS(param.memory())); // sub reg,[param] + else if (param.is_int_register()) + emit_sub_r32_r32(dst, reg, param.ireg()); // sub reg,param +} + + +//------------------------------------------------- +// emit_sub_m32_p32 - sub operation to a 32-bit +// memory location from a 32-bit parameter +//------------------------------------------------- + +void drcbe_x86::emit_sub_m32_p32(x86code *&dst, x86_memref memref, const be_parameter ¶m, const instruction &inst) +{ + if (param.is_immediate()) + { + if (inst.flags() != 0 || param.immediate() != 0) + emit_sub_m32_imm(dst, memref, param.immediate()); // sub [dest],param + } + else + { + int reg = param.select_register(REG_EAX); + emit_mov_r32_p32(dst, reg, param); // mov reg,param + emit_sub_m32_r32(dst, memref, reg); // sub [dest],reg + } +} + + +//------------------------------------------------- +// emit_sbb_r32_p32 - sbb operation to a 32-bit +// register from a 32-bit parameter +//------------------------------------------------- + +void drcbe_x86::emit_sbb_r32_p32(x86code *&dst, UINT8 reg, const be_parameter ¶m, const instruction &inst) +{ + if (param.is_immediate()) + emit_sbb_r32_imm(dst, reg, param.immediate()); // sbb reg,param + else if (param.is_memory()) + emit_sbb_r32_m32(dst, reg, MABS(param.memory())); // sbb reg,[param] + else if (param.is_int_register()) + emit_sbb_r32_r32(dst, reg, param.ireg()); // sbb reg,param +} + + +//------------------------------------------------- +// emit_sbb_m32_p32 - sbb operation to a 32-bit +// memory location from a 32-bit parameter +//------------------------------------------------- + +void drcbe_x86::emit_sbb_m32_p32(x86code *&dst, x86_memref memref, const be_parameter ¶m, const instruction &inst) +{ + if (param.is_immediate()) + emit_sbb_m32_imm(dst, memref, param.immediate()); // sbb [dest],param + else + { + int reg = param.select_register(REG_EAX); + emit_mov_r32_p32_keepflags(dst, reg, param); // mov reg,param + emit_sbb_m32_r32(dst, memref, reg); // sbb [dest],reg + } +} + + +//------------------------------------------------- +// emit_cmp_r32_p32 - cmp operation to a 32-bit +// register from a 32-bit parameter +//------------------------------------------------- + +void drcbe_x86::emit_cmp_r32_p32(x86code *&dst, UINT8 reg, const be_parameter ¶m, const instruction &inst) +{ + if (param.is_immediate()) + emit_cmp_r32_imm(dst, reg, param.immediate()); // cmp reg,param + else if (param.is_memory()) + emit_cmp_r32_m32(dst, reg, MABS(param.memory())); // cmp reg,[param] + else if (param.is_int_register()) + emit_cmp_r32_r32(dst, reg, param.ireg()); // cmp reg,param +} + + +//------------------------------------------------- +// emit_cmp_m32_p32 - cmp operation to a 32-bit +// memory location from a 32-bit parameter +//------------------------------------------------- + +void drcbe_x86::emit_cmp_m32_p32(x86code *&dst, x86_memref memref, const be_parameter ¶m, const instruction &inst) +{ + if (param.is_immediate()) + emit_cmp_m32_imm(dst, memref, param.immediate()); // cmp [dest],param + else + { + int reg = param.select_register(REG_EAX); + emit_mov_r32_p32(dst, reg, param); // mov reg,param + emit_cmp_m32_r32(dst, memref, reg); // cmp [dest],reg + } +} + + +//------------------------------------------------- +// emit_and_r32_p32 - and operation to a 32-bit +// register from a 32-bit parameter +//------------------------------------------------- + +void drcbe_x86::emit_and_r32_p32(x86code *&dst, UINT8 reg, const be_parameter ¶m, const instruction &inst) +{ + if (param.is_immediate()) + { + if (inst.flags() == 0 && (UINT32)param.immediate() == 0xffffffff) + ;// skip + else if (inst.flags() == 0 && (UINT32)param.immediate() == 0) + emit_xor_r32_r32(dst, reg, reg); // xor reg,reg + else + emit_and_r32_imm(dst, reg, param.immediate()); // and reg,param + } + else if (param.is_memory()) + emit_and_r32_m32(dst, reg, MABS(param.memory())); // and reg,[param] + else if (param.is_int_register()) + emit_and_r32_r32(dst, reg, param.ireg()); // and reg,param +} + + +//------------------------------------------------- +// emit_and_m32_p32 - and operation to a 32-bit +// memory location from a 32-bit parameter +//------------------------------------------------- + +void drcbe_x86::emit_and_m32_p32(x86code *&dst, x86_memref memref, const be_parameter ¶m, const instruction &inst) +{ + if (param.is_immediate()) + { + if (inst.flags() == 0 && (UINT32)param.immediate() == 0xffffffff) + ;// skip + else if (inst.flags() == 0 && (UINT32)param.immediate() == 0) + emit_mov_m32_imm(dst, memref, 0); // mov [dest],0 + else + emit_and_m32_imm(dst, memref, param.immediate()); // and [dest],param + } + else + { + int reg = param.select_register(REG_EAX); + emit_mov_r32_p32(dst, reg, param); // mov reg,param + emit_and_m32_r32(dst, memref, reg); // and [dest],reg + } +} + + +//------------------------------------------------- +// emit_test_r32_p32 - test operation to a 32-bit +// register from a 32-bit parameter +//------------------------------------------------- + +void drcbe_x86::emit_test_r32_p32(x86code *&dst, UINT8 reg, const be_parameter ¶m, const instruction &inst) +{ + if (param.is_immediate()) + emit_test_r32_imm(dst, reg, param.immediate()); // test reg,param + else if (param.is_memory()) + emit_test_m32_r32(dst, MABS(param.memory()), reg); // test [param],reg + else if (param.is_int_register()) + emit_test_r32_r32(dst, reg, param.ireg()); // test reg,param +} + + +//------------------------------------------------- +// emit_test_m32_p32 - test operation to a 32-bit +// memory location from a 32-bit parameter +//------------------------------------------------- + +void drcbe_x86::emit_test_m32_p32(x86code *&dst, x86_memref memref, const be_parameter ¶m, const instruction &inst) +{ + if (param.is_immediate()) + emit_test_m32_imm(dst, memref, param.immediate()); // test [dest],param + else if (param.is_memory()) + { + emit_mov_r32_p32(dst, REG_EAX, param); // mov reg,param + emit_test_m32_r32(dst, memref, REG_EAX); // test [dest],reg + } + else if (param.is_int_register()) + emit_test_m32_r32(dst, memref, param.ireg()); // test [dest],param +} + + +//------------------------------------------------- +// emit_or_r32_p32 - or operation to a 32-bit +// register from a 32-bit parameter +//------------------------------------------------- + +void drcbe_x86::emit_or_r32_p32(x86code *&dst, UINT8 reg, const be_parameter ¶m, const instruction &inst) +{ + if (param.is_immediate()) + { + if (inst.flags() == 0 && (UINT32)param.immediate() == 0) + ;// skip + else if (inst.flags() == 0 && (UINT32)param.immediate() == 0xffffffff) + emit_mov_r32_imm(dst, reg, ~0); // mov reg,-1 + else + emit_or_r32_imm(dst, reg, param.immediate()); // or reg,param + } + else if (param.is_memory()) + emit_or_r32_m32(dst, reg, MABS(param.memory())); // or reg,[param] + else if (param.is_int_register()) + emit_or_r32_r32(dst, reg, param.ireg()); // or reg,param +} + + +//------------------------------------------------- +// emit_or_m32_p32 - or operation to a 32-bit +// memory location from a 32-bit parameter +//------------------------------------------------- + +void drcbe_x86::emit_or_m32_p32(x86code *&dst, x86_memref memref, const be_parameter ¶m, const instruction &inst) +{ + if (param.is_immediate()) + { + if (inst.flags() == 0 && (UINT32)param.immediate() == 0) + ;// skip + else if (inst.flags() == 0 && (UINT32)param.immediate() == 0xffffffff) + emit_mov_m32_imm(dst, memref, ~0); // mov [dest],-1 + else + emit_or_m32_imm(dst, memref, param.immediate()); // or [dest],param + } + else + { + int reg = param.select_register(REG_EAX); + emit_mov_r32_p32(dst, reg, param); // mov reg,param + emit_or_m32_r32(dst, memref, reg); // or [dest],reg + } +} + + +//------------------------------------------------- +// emit_xor_r32_p32 - xor operation to a 32-bit +// register from a 32-bit parameter +//------------------------------------------------- + +void drcbe_x86::emit_xor_r32_p32(x86code *&dst, UINT8 reg, const be_parameter ¶m, const instruction &inst) +{ + if (param.is_immediate()) + { + if (inst.flags() == 0 && (UINT32)param.immediate() == 0) + ;// skip + else if (inst.flags() == 0 && (UINT32)param.immediate() == 0xffffffff) + emit_not_r32(dst, reg); // not reg + else + emit_xor_r32_imm(dst, reg, param.immediate()); // xor reg,param + } + else if (param.is_memory()) + emit_xor_r32_m32(dst, reg, MABS(param.memory())); // xor reg,[param] + else if (param.is_int_register()) + emit_xor_r32_r32(dst, reg, param.ireg()); // xor reg,param +} + + +//------------------------------------------------- +// emit_xor_m32_p32 - xor operation to a 32-bit +// memory location from a 32-bit parameter +//------------------------------------------------- + +void drcbe_x86::emit_xor_m32_p32(x86code *&dst, x86_memref memref, const be_parameter ¶m, const instruction &inst) +{ + if (param.is_immediate()) + { + if (inst.flags() == 0 && (UINT32)param.immediate() == 0) + ;// skip + else if (inst.flags() == 0 && (UINT32)param.immediate() == 0xffffffff) + emit_not_m32(dst, memref); // not [dest] + else + emit_xor_m32_imm(dst, memref, param.immediate()); // xor [dest],param + } + else + { + int reg = param.select_register(REG_EAX); + emit_mov_r32_p32(dst, reg, param); // mov reg,param + emit_xor_m32_r32(dst, memref, reg); // xor [dest],reg + } +} + + +//------------------------------------------------- +// emit_shl_r32_p32 - shl operation to a 32-bit +// register from a 32-bit parameter +//------------------------------------------------- + +void drcbe_x86::emit_shl_r32_p32(x86code *&dst, UINT8 reg, const be_parameter ¶m, const instruction &inst) +{ + if (param.is_immediate()) + { + if (inst.flags() == 0 && (UINT32)param.immediate() == 0) + ;// skip + else + emit_shl_r32_imm(dst, reg, param.immediate()); // shl reg,param + } + else + { + emit_mov_r32_p32(dst, REG_ECX, param); // mov ecx,param + emit_shl_r32_cl(dst, reg); // shl reg,cl + } +} + + +//------------------------------------------------- +// emit_shl_m32_p32 - shl operation to a 32-bit +// memory location from a 32-bit parameter +//------------------------------------------------- + +void drcbe_x86::emit_shl_m32_p32(x86code *&dst, x86_memref memref, const be_parameter ¶m, const instruction &inst) +{ + if (param.is_immediate()) + { + if (inst.flags() == 0 && (UINT32)param.immediate() == 0) + ;// skip + else + emit_shl_m32_imm(dst, memref, param.immediate()); // shl [dest],param + } + else + { + emit_mov_r32_p32(dst, REG_ECX, param); // mov ecx,param + emit_shl_m32_cl(dst, memref); // shl [dest],cl + } +} + + +//------------------------------------------------- +// emit_shr_r32_p32 - shr operation to a 32-bit +// register from a 32-bit parameter +//------------------------------------------------- + +void drcbe_x86::emit_shr_r32_p32(x86code *&dst, UINT8 reg, const be_parameter ¶m, const instruction &inst) +{ + if (param.is_immediate()) + { + if (inst.flags() == 0 && (UINT32)param.immediate() == 0) + ;// skip + else + emit_shr_r32_imm(dst, reg, param.immediate()); // shr reg,param + } + else + { + emit_mov_r32_p32(dst, REG_ECX, param); // mov ecx,param + emit_shr_r32_cl(dst, reg); // shr reg,cl + } +} + + +//------------------------------------------------- +// emit_shr_m32_p32 - shr operation to a 32-bit +// memory location from a 32-bit parameter +//------------------------------------------------- + +void drcbe_x86::emit_shr_m32_p32(x86code *&dst, x86_memref memref, const be_parameter ¶m, const instruction &inst) +{ + if (param.is_immediate()) + { + if (inst.flags() == 0 && (UINT32)param.immediate() == 0) + ;// skip + else + emit_shr_m32_imm(dst, memref, param.immediate()); // shr [dest],param + } + else + { + emit_mov_r32_p32(dst, REG_ECX, param); // mov ecx,param + emit_shr_m32_cl(dst, memref); // shr [dest],cl + } +} + + +//------------------------------------------------- +// emit_sar_r32_p32 - sar operation to a 32-bit +// register from a 32-bit parameter +//------------------------------------------------- + +void drcbe_x86::emit_sar_r32_p32(x86code *&dst, UINT8 reg, const be_parameter ¶m, const instruction &inst) +{ + if (param.is_immediate()) + { + if (inst.flags() == 0 && (UINT32)param.immediate() == 0) + ;// skip + else + emit_sar_r32_imm(dst, reg, param.immediate()); // sar reg,param + } + else + { + emit_mov_r32_p32(dst, REG_ECX, param); // mov ecx,param + emit_sar_r32_cl(dst, reg); // sar reg,cl + } +} + + +//------------------------------------------------- +// emit_sar_m32_p32 - sar operation to a 32-bit +// memory location from a 32-bit parameter +//------------------------------------------------- + +void drcbe_x86::emit_sar_m32_p32(x86code *&dst, x86_memref memref, const be_parameter ¶m, const instruction &inst) +{ + if (param.is_immediate()) + { + if (inst.flags() == 0 && (UINT32)param.immediate() == 0) + ;// skip + else + emit_sar_m32_imm(dst, memref, param.immediate()); // sar [dest],param + } + else + { + emit_mov_r32_p32(dst, REG_ECX, param); // mov ecx,param + emit_sar_m32_cl(dst, memref); // sar [dest],cl + } +} + + +//------------------------------------------------- +// emit_rol_r32_p32 - rol operation to a 32-bit +// register from a 32-bit parameter +//------------------------------------------------- + +void drcbe_x86::emit_rol_r32_p32(x86code *&dst, UINT8 reg, const be_parameter ¶m, const instruction &inst) +{ + if (param.is_immediate()) + { + if (inst.flags() == 0 && (UINT32)param.immediate() == 0) + ;// skip + else + emit_rol_r32_imm(dst, reg, param.immediate()); // rol reg,param + } + else + { + emit_mov_r32_p32(dst, REG_ECX, param); // mov ecx,param + emit_rol_r32_cl(dst, reg); // rol reg,cl + } +} + + +//------------------------------------------------- +// emit_rol_m32_p32 - rol operation to a 32-bit +// memory location from a 32-bit parameter +//------------------------------------------------- + +void drcbe_x86::emit_rol_m32_p32(x86code *&dst, x86_memref memref, const be_parameter ¶m, const instruction &inst) +{ + if (param.is_immediate()) + { + if (inst.flags() == 0 && (UINT32)param.immediate() == 0) + ;// skip + else + emit_rol_m32_imm(dst, memref, param.immediate()); // rol [dest],param + } + else + { + emit_mov_r32_p32(dst, REG_ECX, param); // mov ecx,param + emit_rol_m32_cl(dst, memref); // rol [dest],cl + } +} + + +//------------------------------------------------- +// emit_ror_r32_p32 - ror operation to a 32-bit +// register from a 32-bit parameter +//------------------------------------------------- + +void drcbe_x86::emit_ror_r32_p32(x86code *&dst, UINT8 reg, const be_parameter ¶m, const instruction &inst) +{ + if (param.is_immediate()) + { + if (inst.flags() == 0 && (UINT32)param.immediate() == 0) + ;// skip + else + emit_ror_r32_imm(dst, reg, param.immediate()); // ror reg,param + } + else + { + emit_mov_r32_p32(dst, REG_ECX, param); // mov ecx,param + emit_ror_r32_cl(dst, reg); // ror reg,cl + } +} + + +//------------------------------------------------- +// emit_ror_m32_p32 - ror operation to a 32-bit +// memory location from a 32-bit parameter +//------------------------------------------------- + +void drcbe_x86::emit_ror_m32_p32(x86code *&dst, x86_memref memref, const be_parameter ¶m, const instruction &inst) +{ + if (param.is_immediate()) + { + if (inst.flags() == 0 && (UINT32)param.immediate() == 0) + ;// skip + else + emit_ror_m32_imm(dst, memref, param.immediate()); // ror [dest],param + } + else + { + emit_mov_r32_p32(dst, REG_ECX, param); // mov ecx,param + emit_ror_m32_cl(dst, memref); // ror [dest],cl + } +} + + +//------------------------------------------------- +// emit_rcl_r32_p32 - rcl operation to a 32-bit +// register from a 32-bit parameter +//------------------------------------------------- + +void drcbe_x86::emit_rcl_r32_p32(x86code *&dst, UINT8 reg, const be_parameter ¶m, const instruction &inst) +{ + if (param.is_immediate()) + { + if (inst.flags() == 0 && (UINT32)param.immediate() == 0) + ;// skip + else + emit_rcl_r32_imm(dst, reg, param.immediate()); // rcl reg,param + } + else + { + emit_mov_r32_p32_keepflags(dst, REG_ECX, param); // mov ecx,param + emit_rcl_r32_cl(dst, reg); // rcl reg,cl + } +} + + +//------------------------------------------------- +// emit_rcl_m32_p32 - rcl operation to a 32-bit +// memory location from a 32-bit parameter +//------------------------------------------------- + +void drcbe_x86::emit_rcl_m32_p32(x86code *&dst, x86_memref memref, const be_parameter ¶m, const instruction &inst) +{ + if (param.is_immediate()) + { + if (inst.flags() == 0 && (UINT32)param.immediate() == 0) + ;// skip + else + emit_rcl_m32_imm(dst, memref, param.immediate()); // rcl [dest],param + } + else + { + emit_mov_r32_p32_keepflags(dst, REG_ECX, param); // mov ecx,param + emit_rcl_m32_cl(dst, memref); // rcl [dest],cl + } +} + + +//------------------------------------------------- +// emit_rcr_r32_p32 - rcr operation to a 32-bit +// register from a 32-bit parameter +//------------------------------------------------- + +void drcbe_x86::emit_rcr_r32_p32(x86code *&dst, UINT8 reg, const be_parameter ¶m, const instruction &inst) +{ + if (param.is_immediate()) + { + if (inst.flags() == 0 && (UINT32)param.immediate() == 0) + ;// skip + else + emit_rcr_r32_imm(dst, reg, param.immediate()); // rcr reg,param + } + else + { + emit_mov_r32_p32_keepflags(dst, REG_ECX, param); // mov ecx,param + emit_rcr_r32_cl(dst, reg); // rcr reg,cl + } +} + + +//------------------------------------------------- +// emit_rcr_m32_p32 - rcr operation to a 32-bit +// memory location from a 32-bit parameter +//------------------------------------------------- + +void drcbe_x86::emit_rcr_m32_p32(x86code *&dst, x86_memref memref, const be_parameter ¶m, const instruction &inst) +{ + if (param.is_immediate()) + { + if (inst.flags() == 0 && (UINT32)param.immediate() == 0) + ;// skip + else + emit_rcr_m32_imm(dst, memref, param.immediate()); // rcr [dest],param + } + else + { + emit_mov_r32_p32_keepflags(dst, REG_ECX, param); // mov ecx,param + emit_rcr_m32_cl(dst, memref); // rcr [dest],cl + } +} + + + +//************************************************************************** +// EMITTERS FOR 64-BIT OPERATIONS WITH PARAMETERS +//************************************************************************** + +//------------------------------------------------- +// emit_mov_r64_p64 - move a 64-bit parameter +// into a pair of registers +//------------------------------------------------- + +void drcbe_x86::emit_mov_r64_p64(x86code *&dst, UINT8 reglo, UINT8 reghi, const be_parameter ¶m) +{ + if (param.is_immediate()) + { + if (reglo == REG_NONE) + ; + else if ((UINT32)param.immediate() == 0) + emit_xor_r32_r32(dst, reglo, reglo); // xor reglo,reglo + else + emit_mov_r32_imm(dst, reglo, param.immediate()); // mov reglo,param + if (reghi == REG_NONE) + ; + else if ((UINT32)(param.immediate() >> 32) == 0) + emit_xor_r32_r32(dst, reghi, reghi); // xor reghi,reghi + else + emit_mov_r32_imm(dst, reghi, param.immediate() >> 32); // mov reghi,param >> 32 + } + else if (param.is_memory()) + { + int skip_lower = can_skip_lower_load(dst, (UINT32 *)((FPTR)param.memory()), reglo); + int skip_upper = can_skip_upper_load(dst, (UINT32 *)((FPTR)param.memory(4)), reghi); + if (reglo != REG_NONE && !skip_lower) + emit_mov_r32_m32(dst, reglo, MABS(param.memory())); // mov reglo,[param] + if (reghi != REG_NONE && !skip_upper) + emit_mov_r32_m32(dst, reghi, MABS(param.memory(4))); // mov reghi,[param+4] + } + else if (param.is_int_register()) + { + int skip_upper = can_skip_upper_load(dst, m_reghi[param.ireg()], reghi); + if (reglo != REG_NONE && reglo != param.ireg()) + emit_mov_r32_r32(dst, reglo, param.ireg()); // mov reglo,param + if (reghi != REG_NONE && !skip_upper) + emit_mov_r32_m32(dst, reghi, MABS(m_reghi[param.ireg()])); // mov reghi,reghi[param] + } +} + + +//------------------------------------------------- +// emit_mov_r64_p64_keepflags - move a 64-bit +// parameter into a pair of registers without +// affecting any flags +//------------------------------------------------- + +void drcbe_x86::emit_mov_r64_p64_keepflags(x86code *&dst, UINT8 reglo, UINT8 reghi, const be_parameter ¶m) +{ + if (param.is_immediate()) + { + if (reglo != REG_NONE) + emit_mov_r32_imm(dst, reglo, param.immediate()); // mov reglo,param + if (reghi != REG_NONE) + emit_mov_r32_imm(dst, reghi, param.immediate() >> 32); // mov reghi,param >> 32 + } + else if (param.is_memory()) + { + int skip_lower = can_skip_lower_load(dst, (UINT32 *)((FPTR)param.memory()), reglo); + int skip_upper = can_skip_upper_load(dst, (UINT32 *)((FPTR)param.memory(4)), reghi); + if (reglo != REG_NONE && !skip_lower) + emit_mov_r32_m32(dst, reglo, MABS(param.memory())); // mov reglo,[param] + if (reghi != REG_NONE && !skip_upper) + emit_mov_r32_m32(dst, reghi, MABS(param.memory(4))); // mov reghi,[param+4] + } + else if (param.is_int_register()) + { + int skip_upper = can_skip_upper_load(dst, m_reghi[param.ireg()], reghi); + if (reglo != REG_NONE && reglo != param.ireg()) + emit_mov_r32_r32(dst, reglo, param.ireg()); // mov reglo,param + if (reghi != REG_NONE && !skip_upper) + emit_mov_r32_m32(dst, reghi, MABS(m_reghi[param.ireg()])); // mov reghi,reghi[param] + } +} + + +//------------------------------------------------- +// emit_mov_m64_p64 - move a 64-bit parameter +// into a memory location +//------------------------------------------------- + +void drcbe_x86::emit_mov_m64_p64(x86code *&dst, x86_memref memref, const be_parameter ¶m) +{ + if (param.is_immediate()) + { + emit_mov_m32_imm(dst, memref + 0, param.immediate()); // mov [mem],param + emit_mov_m32_imm(dst, memref + 4, param.immediate() >> 32); // mov [mem],param >> 32 + } + else if (param.is_memory()) + { + int skip_lower = can_skip_lower_load(dst, (UINT32 *)((FPTR)param.memory()), REG_EAX); + if (!skip_lower) + emit_mov_r32_m32(dst, REG_EAX, MABS(param.memory())); // mov eax,[param] + emit_mov_m32_r32(dst, memref + 0, REG_EAX); // mov [mem],eax + emit_mov_r32_m32(dst, REG_EAX, MABS(param.memory(4))); // mov eax,[param+4] + emit_mov_m32_r32(dst, memref + 4, REG_EAX); // mov [mem+4],eax + } + else if (param.is_int_register()) + { + emit_mov_m32_r32(dst, memref + 0, param.ireg()); // mov [mem],param + emit_mov_r32_m32(dst, REG_EAX, MABS(m_reghi[param.ireg()])); // mov eax,[param.hi] + emit_mov_m32_r32(dst, memref + 4, REG_EAX); // mov [mem+4],eax + } +} + + +//------------------------------------------------- +// emit_mov_p64_r64 - move a pair of registers +// into a 64-bit parameter +//------------------------------------------------- + +void drcbe_x86::emit_mov_p64_r64(x86code *&dst, const be_parameter ¶m, UINT8 reglo, UINT8 reghi) +{ + assert(!param.is_immediate()); + if (param.is_memory()) + { + emit_mov_m32_r32(dst, MABS(param.memory()), reglo); // mov [param],reglo + emit_mov_m32_r32(dst, MABS(param.memory(4)), reghi); // mov [param+4],reghi + } + else if (param.is_int_register()) + { + if (reglo != param.ireg()) + emit_mov_r32_r32(dst, param.ireg(), reglo); // mov param,reglo + emit_mov_m32_r32(dst, MABS(m_reghi[param.ireg()]), reghi); // mov reghi[param],reghi + } + set_last_lower_reg(dst, param, reglo); + set_last_upper_reg(dst, param, reghi); +} + + +//------------------------------------------------- +// emit_add_r64_p64 - add operation to a 64-bit +// pair of registers from a 64-bit parameter +//------------------------------------------------- + +void drcbe_x86::emit_add_r64_p64(x86code *&dst, UINT8 reglo, UINT8 reghi, const be_parameter ¶m, const instruction &inst) +{ + int saveflags = ((inst.flags() & FLAG_Z) != 0); + if (param.is_memory()) + { + emit_add_r32_m32(dst, reglo, MABS(param.memory())); // add reglo,[param] + if (saveflags) emit_pushf(dst); // pushf + emit_adc_r32_m32(dst, reghi, MABS(param.memory(4))); // adc reghi,[param] + } + else if (param.is_immediate()) + { + emit_add_r32_imm(dst, reglo, param.immediate()); // add reglo,param + if (saveflags) emit_pushf(dst); // pushf + emit_adc_r32_imm(dst, reghi, param.immediate() >> 32); // adc reghi,param >> 32 + } + else if (param.is_int_register()) + { + emit_add_r32_r32(dst, reglo, param.ireg()); // add reglo,param + if (saveflags) emit_pushf(dst); // pushf + emit_adc_r32_m32(dst, reghi, MABS(m_reghi[param.ireg()])); // adc reghi,reghi[param] + } + if (saveflags) + emit_combine_z_flags(dst); +} + + +//------------------------------------------------- +// emit_add_m64_p64 - add operation to a 64-bit +// memory location from a 64-bit parameter +//------------------------------------------------- + +void drcbe_x86::emit_add_m64_p64(x86code *&dst, x86_memref memref, const be_parameter ¶m, const instruction &inst) +{ + int saveflags = ((inst.flags() & FLAG_Z) != 0); + if (param.is_immediate()) + { + emit_add_m32_imm(dst, memref, param.immediate()); // add [dest],param + if (saveflags) emit_pushf(dst); // pushf + emit_adc_m32_imm(dst, memref + 4, param.immediate() >> 32); // adc [dest+4],param >> 32 + } + else + { + int reglo = (param.is_int_register()) ? param.ireg() : REG_EAX; + emit_mov_r64_p64(dst, reglo, REG_EDX, param); // mov edx:reglo,param + emit_add_m32_r32(dst, memref, reglo); // add [dest],reglo + if (saveflags) emit_pushf(dst); // pushf + emit_adc_m32_r32(dst, memref + 4, REG_EDX); // adc [dest+4],edx + } + if (saveflags) + emit_combine_z_flags(dst); +} + + +//------------------------------------------------- +// emit_adc_r64_p64 - adc operation to a 64-bit +// pair of registers from a 64-bit parameter +//------------------------------------------------- + +void drcbe_x86::emit_adc_r64_p64(x86code *&dst, UINT8 reglo, UINT8 reghi, const be_parameter ¶m, const instruction &inst) +{ + int saveflags = ((inst.flags() & FLAG_Z) != 0); + if (param.is_memory()) + { + emit_adc_r32_m32(dst, reglo, MABS(param.memory())); // adc reglo,[param] + if (saveflags) emit_pushf(dst); // pushf + emit_adc_r32_m32(dst, reghi, MABS(param.memory(4))); // adc reghi,[param] + } + else if (param.is_immediate()) + { + emit_adc_r32_imm(dst, reglo, param.immediate()); // adc reglo,param + if (saveflags) emit_pushf(dst); // pushf + emit_adc_r32_imm(dst, reghi, param.immediate() >> 32); // adc reghi,param >> 32 + } + else if (param.is_int_register()) + { + emit_adc_r32_r32(dst, reglo, param.ireg()); // adc reglo,param + if (saveflags) emit_pushf(dst); // pushf + emit_adc_r32_m32(dst, reghi, MABS(m_reghi[param.ireg()])); // adc reghi,reghi[param] + } + if (saveflags) + emit_combine_z_flags(dst); +} + + +//------------------------------------------------- +// emit_adc_m64_p64 - adc operation to a 64-bit +// memory location from a 64-bit parameter +//------------------------------------------------- + +void drcbe_x86::emit_adc_m64_p64(x86code *&dst, x86_memref memref, const be_parameter ¶m, const instruction &inst) +{ + int saveflags = ((inst.flags() & FLAG_Z) != 0); + if (param.is_immediate()) + { + emit_adc_m32_imm(dst, memref, param.immediate()); // adc [dest],param + if (saveflags) emit_pushf(dst); // pushf + emit_adc_m32_imm(dst, memref + 4, param.immediate() >> 32); // adc [dest+4],param >> 32 + } + else + { + int reglo = (param.is_int_register()) ? param.ireg() : REG_EAX; + emit_mov_r64_p64_keepflags(dst, reglo, REG_EDX, param); // mov edx:reglo,param + emit_adc_m32_r32(dst, memref, reglo); // adc [dest],reglo + if (saveflags) emit_pushf(dst); // pushf + emit_adc_m32_r32(dst, memref + 4, REG_EDX); // adc [dest+4],edx + } + if (saveflags) + emit_combine_z_flags(dst); +} + + +//------------------------------------------------- +// emit_sub_r64_p64 - sub operation to a 64-bit +// pair of registers from a 64-bit parameter +//------------------------------------------------- + +void drcbe_x86::emit_sub_r64_p64(x86code *&dst, UINT8 reglo, UINT8 reghi, const be_parameter ¶m, const instruction &inst) +{ + int saveflags = ((inst.flags() & FLAG_Z) != 0); + if (param.is_memory()) + { + emit_sub_r32_m32(dst, reglo, MABS(param.memory())); // sub reglo,[param] + if (saveflags) emit_pushf(dst); // pushf + emit_sbb_r32_m32(dst, reghi, MABS(param.memory(4))); // sbb reghi,[param] + } + else if (param.is_immediate()) + { + emit_sub_r32_imm(dst, reglo, param.immediate()); // sub reglo,param + if (saveflags) emit_pushf(dst); // pushf + emit_sbb_r32_imm(dst, reghi, param.immediate() >> 32); // sbb reghi,param >> 32 + } + else if (param.is_int_register()) + { + emit_sub_r32_r32(dst, reglo, param.ireg()); // sub reglo,param + if (saveflags) emit_pushf(dst); // pushf + emit_sbb_r32_m32(dst, reghi, MABS(m_reghi[param.ireg()])); // sbb reghi,reghi[param] + } + if (saveflags) + emit_combine_z_flags(dst); +} + + +//------------------------------------------------- +// emit_sub_m64_p64 - sub operation to a 64-bit +// memory location from a 64-bit parameter +//------------------------------------------------- + +void drcbe_x86::emit_sub_m64_p64(x86code *&dst, x86_memref memref, const be_parameter ¶m, const instruction &inst) +{ + int saveflags = ((inst.flags() & FLAG_Z) != 0); + if (param.is_immediate()) + { + emit_sub_m32_imm(dst, memref, param.immediate()); // sub [dest],param + if (saveflags) emit_pushf(dst); // pushf + emit_sbb_m32_imm(dst, memref + 4, param.immediate() >> 32); // sbb [dest+4],param >> 32 + } + else + { + int reglo = (param.is_int_register()) ? param.ireg() : REG_EAX; + emit_mov_r64_p64(dst, reglo, REG_EDX, param); // mov edx:reglo,param + emit_sub_m32_r32(dst, memref, reglo); // sub [dest],reglo + if (saveflags) emit_pushf(dst); // pushf + emit_sbb_m32_r32(dst, memref + 4, REG_EDX); // sbb [dest+4],edx + } + if (saveflags) + emit_combine_z_flags(dst); +} + + +//------------------------------------------------- +// emit_sbb_r64_p64 - sbb operation to a 64-bit +// pair of registers from a 64-bit parameter +//------------------------------------------------- + +void drcbe_x86::emit_sbb_r64_p64(x86code *&dst, UINT8 reglo, UINT8 reghi, const be_parameter ¶m, const instruction &inst) +{ + int saveflags = ((inst.flags() & FLAG_Z) != 0); + if (param.is_memory()) + { + emit_sbb_r32_m32(dst, reglo, MABS(param.memory())); // sbb reglo,[param] + if (saveflags) emit_pushf(dst); // pushf + emit_sbb_r32_m32(dst, reghi, MABS(param.memory(4))); // sbb reghi,[param] + } + else if (param.is_immediate()) + { + emit_sbb_r32_imm(dst, reglo, param.immediate()); // sbb reglo,param + if (saveflags) emit_pushf(dst); // pushf + emit_sbb_r32_imm(dst, reghi, param.immediate() >> 32); // sbb reghi,param >> 32 + } + else if (param.is_int_register()) + { + emit_sbb_r32_r32(dst, reglo, param.ireg()); // sbb reglo,param + if (saveflags) emit_pushf(dst); // pushf + emit_sbb_r32_m32(dst, reghi, MABS(m_reghi[param.ireg()])); // sbb reghi,reghi[param] + } + if (saveflags) + emit_combine_z_flags(dst); +} + + +//------------------------------------------------- +// emit_sbb_m64_p64 - sbb operation to a 64-bit +// memory location from a 64-bit parameter +//------------------------------------------------- + +void drcbe_x86::emit_sbb_m64_p64(x86code *&dst, x86_memref memref, const be_parameter ¶m, const instruction &inst) +{ + int saveflags = ((inst.flags() & FLAG_Z) != 0); + if (param.is_immediate()) + { + emit_sbb_m32_imm(dst, memref, param.immediate()); // sbb [dest],param + if (saveflags) emit_pushf(dst); // pushf + emit_sbb_m32_imm(dst, memref + 4, param.immediate() >> 32); // sbb [dest+4],param >> 32 + } + else + { + int reglo = (param.is_int_register()) ? param.ireg() : REG_EAX; + emit_mov_r64_p64_keepflags(dst, reglo, REG_EDX, param); // mov edx:reglo,param + emit_sbb_m32_r32(dst, memref, reglo); // sbb [dest],reglo + if (saveflags) emit_pushf(dst); // pushf + emit_sbb_m32_r32(dst, memref + 4, REG_EDX); // sbb [dest+4],edx + } + if (saveflags) + emit_combine_z_flags(dst); +} + + +//------------------------------------------------- +// emit_cmp_r64_p64 - sub operation to a 64-bit +// pair of registers from a 64-bit parameter +//------------------------------------------------- + +void drcbe_x86::emit_cmp_r64_p64(x86code *&dst, UINT8 reglo, UINT8 reghi, const be_parameter ¶m, const instruction &inst) +{ + int saveflags = (inst.flags() != FLAG_Z && (inst.flags() & FLAG_Z) != 0); + if (param.is_memory()) + { + emit_sub_r32_m32(dst, reglo, MABS(param.memory())); // sub reglo,[param] + if (saveflags) emit_pushf(dst); // pushf + emit_sbb_r32_m32(dst, reghi, MABS(param.memory(4))); // sbb reghi,[param] + } + else if (param.is_immediate()) + { + emit_sub_r32_imm(dst, reglo, param.immediate()); // sub reglo,param + if (saveflags) emit_pushf(dst); // pushf + emit_sbb_r32_imm(dst, reghi, param.immediate() >> 32); // sbb reghi,param >> 32 + } + else if (param.is_int_register()) + { + emit_sub_r32_r32(dst, reglo, param.ireg()); // sub reglo,param + if (saveflags) emit_pushf(dst); // pushf + emit_sbb_r32_m32(dst, reghi, MABS(m_reghi[param.ireg()])); // sbb reghi,reghi[param] + } + if (inst.flags() == FLAG_Z) + emit_or_r32_r32(dst, reghi, reglo); // or reghi,reglo + else if (saveflags) + emit_combine_z_flags(dst); +} + + +//------------------------------------------------- +// emit_and_r64_p64 - and operation to a 64-bit +// pair of registers from a 64-bit parameter +//------------------------------------------------- + +void drcbe_x86::emit_and_r64_p64(x86code *&dst, UINT8 reglo, UINT8 reghi, const be_parameter ¶m, const instruction &inst) +{ + int saveflags = ((inst.flags() & FLAG_Z) != 0); + if (param.is_memory()) + { + emit_and_r32_m32(dst, reglo, MABS(param.memory())); // and reglo,[param] + if (saveflags) emit_pushf(dst); // pushf + emit_and_r32_m32(dst, reghi, MABS(param.memory(4))); // and reghi,[param] + } + else if (param.is_immediate()) + { + if (inst.flags() == 0 && (UINT32)param.immediate() == 0xffffffff) + ;// skip + else if (inst.flags() == 0 && (UINT32)param.immediate() == 0) + emit_xor_r32_r32(dst, reglo, reglo); // xor reglo,reglo + else + emit_and_r32_imm(dst, reglo, param.immediate()); // and reglo,param + if (saveflags) emit_pushf(dst); // pushf + if (inst.flags() == 0 && (UINT32)(param.immediate() >> 32) == 0xffffffff) + ;// skip + else if (inst.flags() == 0 && (UINT32)(param.immediate() >> 32) == 0) + emit_xor_r32_r32(dst, reghi, reghi); // xor reghi,reghi + else + emit_and_r32_imm(dst, reghi, param.immediate() >> 32); // and reghi,param >> 32 + } + else if (param.is_int_register()) + { + emit_and_r32_r32(dst, reglo, param.ireg()); // and reglo,param + if (saveflags) emit_pushf(dst); // pushf + emit_and_r32_m32(dst, reghi, MABS(m_reghi[param.ireg()])); // and reghi,reghi[param] + } + if (saveflags) + emit_combine_z_flags(dst); +} + + +//------------------------------------------------- +// emit_and_m64_p64 - and operation to a 64-bit +// memory location from a 64-bit parameter +//------------------------------------------------- + +void drcbe_x86::emit_and_m64_p64(x86code *&dst, x86_memref memref, const be_parameter ¶m, const instruction &inst) +{ + int saveflags = ((inst.flags() & FLAG_Z) != 0); + if (param.is_immediate()) + { + if (inst.flags() == 0 && (UINT32)param.immediate() == 0xffffffff) + ;// skip + else if (inst.flags() == 0 && (UINT32)param.immediate() == 0) + emit_mov_m32_imm(dst, memref, 0); // mov [dest],0 + else + emit_and_m32_imm(dst, memref, param.immediate()); // and [dest],param + if (saveflags) emit_pushf(dst); // pushf + if (inst.flags() == 0 && (UINT32)(param.immediate() >> 32) == 0xffffffff) + ;// skip + else if (inst.flags() == 0 && (UINT32)(param.immediate() >> 32) == 0) + emit_mov_m32_imm(dst, memref + 4, 0); // mov [dest+4],0 + else + emit_and_m32_imm(dst, memref + 4, param.immediate() >> 32); // and [dest+4],param >> 32 + } + else + { + int reglo = (param.is_int_register()) ? param.ireg() : REG_EAX; + emit_mov_r64_p64(dst, reglo, REG_EDX, param); // mov edx:reglo,param + emit_and_m32_r32(dst, memref, reglo); // and [dest],reglo + if (saveflags) emit_pushf(dst); // pushf + emit_and_m32_r32(dst, memref + 4, REG_EDX); // and [dest+4],edx + } + if (saveflags) + emit_combine_z_flags(dst); +} + + +//------------------------------------------------- +// emit_test_r64_p64 - test operation to a 64-bit +// pair of registers from a 64-bit parameter +//------------------------------------------------- + +void drcbe_x86::emit_test_r64_p64(x86code *&dst, UINT8 reglo, UINT8 reghi, const be_parameter ¶m, const instruction &inst) +{ + int saveflags = ((inst.flags() & FLAG_Z) != 0); + if (param.is_memory()) + { + emit_test_m32_r32(dst, MABS(param.memory()), reglo); // test [param],reglo + if (saveflags) emit_pushf(dst); // pushf + emit_test_m32_r32(dst, MABS(param.memory(4)), reghi); // test [param],reghi + } + else if (param.is_immediate()) + { + emit_test_r32_imm(dst, reglo, param.immediate()); // test reglo,param + if (saveflags) emit_pushf(dst); // pushf + emit_test_r32_imm(dst, reghi, param.immediate() >> 32); // test reghi,param >> 32 + } + else if (param.is_int_register()) + { + emit_test_r32_r32(dst, reglo, param.ireg()); // test reglo,param + if (saveflags) emit_pushf(dst); // pushf + emit_test_m32_r32(dst, MABS(m_reghi[param.ireg()]), reghi); // test reghi[param],reghi + } + if (saveflags) + emit_combine_z_flags(dst); +} + + +//------------------------------------------------- +// emit_test_m64_p64 - test operation to a 64-bit +// memory location from a 64-bit parameter +//------------------------------------------------- + +void drcbe_x86::emit_test_m64_p64(x86code *&dst, x86_memref memref, const be_parameter ¶m, const instruction &inst) +{ + int saveflags = ((inst.flags() & FLAG_Z) != 0); + if (param.is_immediate()) + { + emit_test_m32_imm(dst, memref, param.immediate()); // test [dest],param + if (saveflags) emit_pushf(dst); // pushf + emit_test_m32_imm(dst, memref + 4, param.immediate() >> 32); // test [dest+4],param >> 32 + } + else + { + int reglo = (param.is_int_register()) ? param.ireg() : REG_EAX; + emit_mov_r64_p64(dst, reglo, REG_EDX, param); // mov edx:reglo,param + emit_test_m32_r32(dst, memref, reglo); // test [dest],reglo + if (saveflags) emit_pushf(dst); // pushf + emit_test_m32_r32(dst, memref + 4, REG_EDX); // test [dest+4],edx + } + if (saveflags) + emit_combine_z_flags(dst); +} + + +//------------------------------------------------- +// emit_or_r64_p64 - or operation to a 64-bit +// pair of registers from a 64-bit parameter +//------------------------------------------------- + +void drcbe_x86::emit_or_r64_p64(x86code *&dst, UINT8 reglo, UINT8 reghi, const be_parameter ¶m, const instruction &inst) +{ + int saveflags = ((inst.flags() & FLAG_Z) != 0); + if (param.is_memory()) + { + emit_or_r32_m32(dst, reglo, MABS(param.memory())); // or reglo,[param] + if (saveflags) emit_pushf(dst); // pushf + emit_or_r32_m32(dst, reghi, MABS(param.memory(4))); // or reghi,[param] + } + else if (param.is_immediate()) + { + if (inst.flags() == 0 && (UINT32)param.immediate() == 0) + ;// skip + else if (inst.flags() == 0 && (UINT32)param.immediate() == 0xffffffff) + emit_mov_r32_imm(dst, reglo, ~0); // mov reglo,-1 + else + emit_or_r32_imm(dst, reglo, param.immediate()); // or reglo,param + if (saveflags) emit_pushf(dst); // pushf + if (inst.flags() == 0 && (UINT32)(param.immediate() >> 32) == 0) + ;// skip + else if (inst.flags() == 0 && (UINT32)(param.immediate() >> 32) == 0xffffffff) + emit_mov_r32_imm(dst, reghi, ~0); // mov reghi,-1 + else + emit_or_r32_imm(dst, reghi, param.immediate() >> 32); // or reghi,param >> 32 + } + else if (param.is_int_register()) + { + emit_or_r32_r32(dst, reglo, param.ireg()); // or reglo,param + if (saveflags) emit_pushf(dst); // pushf + emit_or_r32_m32(dst, reghi, MABS(m_reghi[param.ireg()])); // or reghi,reghi[param] + } + if (saveflags) + emit_combine_z_flags(dst); +} + + +//------------------------------------------------- +// emit_or_m64_p64 - or operation to a 64-bit +// memory location from a 64-bit parameter +//------------------------------------------------- + +void drcbe_x86::emit_or_m64_p64(x86code *&dst, x86_memref memref, const be_parameter ¶m, const instruction &inst) +{ + int saveflags = ((inst.flags() & FLAG_Z) != 0); + if (param.is_immediate()) + { + if (inst.flags() == 0 && (UINT32)param.immediate() == 0) + ;// skip + else if (inst.flags() == 0 && (UINT32)param.immediate() == 0xffffffff) + emit_mov_m32_imm(dst, memref, ~0); // mov [dest],-1 + else + emit_or_m32_imm(dst, memref, param.immediate()); // or [dest],param + if (saveflags) emit_pushf(dst); // pushf + if (inst.flags() == 0 && (UINT32)(param.immediate() >> 32) == 0) + ;// skip + else if (inst.flags() == 0 && (UINT32)(param.immediate() >> 32) == 0xffffffff) + emit_mov_m32_imm(dst, memref + 4, ~0); // mov [dest+4],-1 + else + emit_or_m32_imm(dst, memref + 4, param.immediate() >> 32); // or [dest+4],param >> 32 + } + else + { + int reglo = (param.is_int_register()) ? param.ireg() : REG_EAX; + emit_mov_r64_p64(dst, reglo, REG_EDX, param); // mov edx:reglo,param + emit_or_m32_r32(dst, memref, reglo); // or [dest],reglo + if (saveflags) emit_pushf(dst); // pushf + emit_or_m32_r32(dst, memref + 4, REG_EDX); // or [dest+4],edx + } + if (saveflags) + emit_combine_z_flags(dst); +} + + +//------------------------------------------------- +// emit_xor_r64_p64 - xor operation to a 64-bit +// pair of registers from a 64-bit parameter +//------------------------------------------------- + +void drcbe_x86::emit_xor_r64_p64(x86code *&dst, UINT8 reglo, UINT8 reghi, const be_parameter ¶m, const instruction &inst) +{ + int saveflags = ((inst.flags() & FLAG_Z) != 0); + if (param.is_memory()) + { + emit_xor_r32_m32(dst, reglo, MABS(param.memory())); // xor reglo,[param] + if (saveflags) emit_pushf(dst); // pushf + emit_xor_r32_m32(dst, reghi, MABS(param.memory(4))); // xor reghi,[param] + } + else if (param.is_immediate()) + { + if (inst.flags() == 0 && (UINT32)param.immediate() == 0) + ;// skip + else if (inst.flags() == 0 && (UINT32)param.immediate() == 0xffffffff) + emit_not_r32(dst, reglo); // not reglo + else + emit_xor_r32_imm(dst, reglo, param.immediate()); // xor reglo,param + if (saveflags) emit_pushf(dst); // pushf + if (inst.flags() == 0 && (UINT32)(param.immediate() >> 32) == 0) + ;// skip + else if (inst.flags() == 0 && (UINT32)(param.immediate() >> 32) == 0xffffffff) + emit_not_r32(dst, reghi); // not reghi + else + emit_xor_r32_imm(dst, reghi, param.immediate() >> 32); // xor reghi,param >> 32 + } + else if (param.is_int_register()) + { + emit_xor_r32_r32(dst, reglo, param.ireg()); // xor reglo,param + if (saveflags) emit_pushf(dst); // pushf + emit_xor_r32_m32(dst, reghi, MABS(m_reghi[param.ireg()])); // xor reghi,reghi[param] + } + if (saveflags) + emit_combine_z_flags(dst); +} + + +//------------------------------------------------- +// emit_xor_m64_p64 - xor operation to a 64-bit +// memory location from a 64-bit parameter +//------------------------------------------------- + +void drcbe_x86::emit_xor_m64_p64(x86code *&dst, x86_memref memref, const be_parameter ¶m, const instruction &inst) +{ + int saveflags = ((inst.flags() & FLAG_Z) != 0); + if (param.is_immediate()) + { + if (inst.flags() == 0 && (UINT32)param.immediate() == 0) + ;// skip + else if (inst.flags() == 0 && (UINT32)param.immediate() == 0xffffffff) + emit_not_m32(dst, memref); // not [dest] + else + emit_xor_m32_imm(dst, memref, param.immediate()); // xor [dest],param + if (saveflags) emit_pushf(dst); // pushf + if (inst.flags() == 0 && (UINT32)(param.immediate() >> 32) == 0) + ;// skip + else if (inst.flags() == 0 && (UINT32)(param.immediate() >> 32) == 0xffffffff) + emit_not_m32(dst, memref + 4); // not [dest+4] + else + emit_xor_m32_imm(dst, memref + 4, param.immediate() >> 32); // xor [dest+4],param >> 32 + } + else + { + int reglo = (param.is_int_register()) ? param.ireg() : REG_EAX; + emit_mov_r64_p64(dst, reglo, REG_EDX, param); // mov edx:reglo,param + emit_xor_m32_r32(dst, memref, reglo); // xor [dest],reglo + if (saveflags) emit_pushf(dst); // pushf + emit_xor_m32_r32(dst, memref + 4, REG_EDX); // xor [dest+4],edx + } + if (saveflags) + emit_combine_z_flags(dst); +} + + +//------------------------------------------------- +// emit_shl_r64_p64 - shl operation to a 64-bit +// pair of registers from a 64-bit parameter +//------------------------------------------------- + +void drcbe_x86::emit_shl_r64_p64(x86code *&dst, UINT8 reglo, UINT8 reghi, const be_parameter ¶m, const instruction &inst) +{ + int saveflags = (inst.flags() != 0); + if (param.is_immediate()) + { + int count = param.immediate() & 63; + if (inst.flags() == 0 && count == 0) + ;// skip + else + { + while (count >= 32) + { + if (inst.flags() != 0) + { + emit_shld_r32_r32_imm(dst, reghi, reglo, 31); // shld reghi,reglo,31 + emit_shl_r32_imm(dst, reglo, 31); // shl reglo,31 + count -= 31; + } + else + { + emit_mov_r32_r32(dst, reghi, reglo); // mov reghi,reglo + emit_xor_r32_r32(dst, reglo, reglo); // xor reglo,reglo + count -= 32; + } + } + if (inst.flags() != 0 || count > 0) + { + emit_shld_r32_r32_imm(dst, reghi, reglo, count); // shld reghi,reglo,count + if (saveflags) emit_pushf(dst); // pushf + emit_shl_r32_imm(dst, reglo, count); // shl reglo,count + } + } + } + else + { + emit_link skip1, skip2; + emit_mov_r32_p32(dst, REG_ECX, param); // mov ecx,param + emit_test_r32_imm(dst, REG_ECX, 0x20); // test ecx,0x20 + emit_jcc_short_link(dst, x86emit::COND_Z, skip1); // jz skip1 + if (inst.flags() != 0) + { + emit_sub_r32_imm(dst, REG_ECX, 31); // sub ecx,31 + emit_shld_r32_r32_imm(dst, reghi, reglo, 31); // shld reghi,reglo,31 + emit_shl_r32_imm(dst, reglo, 31); // shl reglo,31 + emit_test_r32_imm(dst, REG_ECX, 0x20); // test ecx,0x20 + emit_jcc_short_link(dst, x86emit::COND_Z, skip2); // jz skip2 + emit_sub_r32_imm(dst, REG_ECX, 31); // sub ecx,31 + emit_shld_r32_r32_imm(dst, reghi, reglo, 31); // shld reghi,reglo,31 + emit_shl_r32_imm(dst, reglo, 31); // shl reglo,31 + track_resolve_link(dst, skip2); // skip2: + } + else + { + emit_mov_r32_r32(dst, reghi, reglo); // mov reghi,reglo + emit_xor_r32_r32(dst, reglo, reglo); // xor reglo,reglo + } + track_resolve_link(dst, skip1); // skip1: + emit_shld_r32_r32_cl(dst, reghi, reglo); // shld reghi,reglo,cl + if (saveflags) emit_pushf(dst); // pushf + emit_shl_r32_cl(dst, reglo); // shl reglo,cl + } + if (saveflags) + emit_combine_z_shl_flags(dst); +} + + +//------------------------------------------------- +// emit_shr_r64_p64 - shr operation to a 64-bit +// pair of registers from a 64-bit parameter +//------------------------------------------------- + +void drcbe_x86::emit_shr_r64_p64(x86code *&dst, UINT8 reglo, UINT8 reghi, const be_parameter ¶m, const instruction &inst) +{ + int saveflags = ((inst.flags() & FLAG_Z) != 0); + if (param.is_immediate()) + { + int count = param.immediate() & 63; + if (inst.flags() == 0 && count == 0) + ;// skip + else + { + while (count >= 32) + { + if (inst.flags() != 0) + { + emit_shrd_r32_r32_imm(dst, reglo, reghi, 31); // shrd reglo,reghi,31 + emit_shr_r32_imm(dst, reghi, 31); // shr reghi,31 + count -= 31; + } + else + { + emit_mov_r32_r32(dst, reglo, reghi); // mov reglo,reghi + emit_xor_r32_r32(dst, reghi, reghi); // xor reghi,reghi + count -= 32; + } + } + if (inst.flags() != 0 || count > 0) + { + emit_shrd_r32_r32_imm(dst, reglo, reghi, count); // shrd reglo,reghi,count + if (saveflags) emit_pushf(dst); // pushf + emit_shr_r32_imm(dst, reghi, count); // shr reghi,count + } + } + } + else + { + emit_link skip1, skip2; + emit_mov_r32_p32(dst, REG_ECX, param); // mov ecx,param + emit_test_r32_imm(dst, REG_ECX, 0x20); // test ecx,0x20 + emit_jcc_short_link(dst, x86emit::COND_Z, skip1); // jz skip1 + if (inst.flags() != 0) + { + emit_sub_r32_imm(dst, REG_ECX, 31); // sub ecx,31 + emit_shrd_r32_r32_imm(dst, reglo, reghi, 31); // shrd reglo,reghi,31 + emit_shr_r32_imm(dst, reghi, 31); // shr reghi,31 + emit_test_r32_imm(dst, REG_ECX, 0x20); // test ecx,0x20 + emit_jcc_short_link(dst, x86emit::COND_Z, skip2); // jz skip2 + emit_sub_r32_imm(dst, REG_ECX, 31); // sub ecx,31 + emit_shrd_r32_r32_imm(dst, reglo, reghi, 31); // shrd reglo,reghi,31 + emit_shr_r32_imm(dst, reghi, 31); // shr reghi,31 + track_resolve_link(dst, skip2); // skip2: + } + else + { + emit_mov_r32_r32(dst, reglo, reghi); // mov reglo,reghi + emit_xor_r32_r32(dst, reghi, reghi); // xor reghi,reghi + } + track_resolve_link(dst, skip1); // skip1: + emit_shrd_r32_r32_cl(dst, reglo, reghi); // shrd reglo,reghi,cl + if (saveflags) emit_pushf(dst); // pushf + emit_shr_r32_cl(dst, reghi); // shr reghi,cl + } + if (saveflags) + emit_combine_z_flags(dst); +} + + +//------------------------------------------------- +// emit_sar_r64_p64 - sar operation to a 64-bit +// pair of registers from a 64-bit parameter +//------------------------------------------------- + +void drcbe_x86::emit_sar_r64_p64(x86code *&dst, UINT8 reglo, UINT8 reghi, const be_parameter ¶m, const instruction &inst) +{ + int saveflags = ((inst.flags() & FLAG_Z) != 0); + if (param.is_immediate()) + { + int count = param.immediate() & 63; + if (inst.flags() == 0 && count == 0) + ;// skip + else + { + while (count >= 32) + { + if (inst.flags() != 0) + { + emit_shrd_r32_r32_imm(dst, reglo, reghi, 31); // shrd reglo,reghi,31 + emit_sar_r32_imm(dst, reghi, 31); // sar reghi,31 + count -= 31; + } + else + { + emit_mov_r32_r32(dst, reglo, reghi); // mov reglo,reghi + emit_sar_r32_imm(dst, reghi, 31); // sar reghi,31 + count -= 32; + } + } + if (inst.flags() != 0 || count > 0) + { + emit_shrd_r32_r32_imm(dst, reglo, reghi, count); // shrd reglo,reghi,count + if (saveflags) emit_pushf(dst); // pushf + emit_sar_r32_imm(dst, reghi, count); // sar reghi,count + } + } + } + else + { + emit_link skip1, skip2; + emit_mov_r32_p32(dst, REG_ECX, param); // mov ecx,param + emit_test_r32_imm(dst, REG_ECX, 0x20); // test ecx,0x20 + emit_jcc_short_link(dst, x86emit::COND_Z, skip1); // jz skip1 + if (inst.flags() != 0) + { + emit_sub_r32_imm(dst, REG_ECX, 31); // sub ecx,31 + emit_shrd_r32_r32_imm(dst, reglo, reghi, 31); // shrd reglo,reghi,31 + emit_sar_r32_imm(dst, reghi, 31); // sar reghi,31 + emit_test_r32_imm(dst, REG_ECX, 0x20); // test ecx,0x20 + emit_jcc_short_link(dst, x86emit::COND_Z, skip2); // jz skip + emit_sub_r32_imm(dst, REG_ECX, 31); // sub ecx,31 + emit_shrd_r32_r32_imm(dst, reglo, reghi, 31); // shrd reglo,reghi,31 + emit_sar_r32_imm(dst, reghi, 31); // sar reghi,31 + track_resolve_link(dst, skip2); // skip2: + } + else + { + emit_mov_r32_r32(dst, reglo, reghi); // mov reglo,reghi + emit_sar_r32_imm(dst, reghi, 31); // sar reghi,31 + } + track_resolve_link(dst, skip1); // skip1: + emit_shrd_r32_r32_cl(dst, reglo, reghi); // shrd reglo,reghi,cl + if (saveflags) emit_pushf(dst); // pushf + emit_sar_r32_cl(dst, reghi); // sar reghi,cl + } + if (saveflags) + emit_combine_z_flags(dst); +} + + +//------------------------------------------------- +// emit_rol_r64_p64 - rol operation to a 64-bit +// pair of registers from a 64-bit parameter +//------------------------------------------------- + +void drcbe_x86::emit_rol_r64_p64(x86code *&dst, UINT8 reglo, UINT8 reghi, const be_parameter ¶m, const instruction &inst) +{ + int saveflags = ((inst.flags() & FLAG_Z) != 0); + if (param.is_immediate()) + { + int count = param.immediate() & 63; + if (inst.flags() == 0 && count == 0) + ;// skip + else + { + while (count >= 32) + { + if (inst.flags() != 0) + { + emit_mov_r32_r32(dst, REG_ECX, reglo); // mov ecx,reglo + emit_shld_r32_r32_imm(dst, reglo, reghi, 31); // shld reglo,reghi,31 + emit_shld_r32_r32_imm(dst, reghi, REG_ECX, 31); // shld reghi,ecx,31 + count -= 31; + } + else + { + emit_xchg_r32_r32(dst, reghi, reglo); // xchg reghi,reglo + count -= 32; + } + } + if (inst.flags() != 0 || count > 0) + { + emit_mov_r32_r32(dst, REG_ECX, reglo); // mov ecx,reglo + emit_shld_r32_r32_imm(dst, reglo, reghi, count); // shld reglo,reghi,count + if (saveflags) emit_pushf(dst); // pushf + emit_shld_r32_r32_imm(dst, reghi, REG_ECX, count); // shld reghi,ecx,count + } + } + } + else + { + emit_link skip1, skip2; + int tempreg = REG_EBX; + emit_mov_m32_r32(dst, MBD(REG_ESP, -8), tempreg); // mov [esp-8],ebx + emit_mov_r32_p32(dst, REG_ECX, param); // mov ecx,param + emit_test_r32_imm(dst, REG_ECX, 0x20); // test ecx,0x20 + emit_jcc_short_link(dst, x86emit::COND_Z, skip1); // jz skip1 + if (inst.flags() != 0) + { + emit_sub_r32_imm(dst, REG_ECX, 31); // sub ecx,31 + emit_mov_r32_r32(dst, tempreg, reglo); // mov ebx,reglo + emit_shld_r32_r32_imm(dst, reglo, reghi, 31); // shld reglo,reghi,31 + emit_shld_r32_r32_imm(dst, reghi, tempreg, 31); // shld reghi,ebx,31 + emit_test_r32_imm(dst, REG_ECX, 0x20); // test ecx,0x20 + emit_jcc_short_link(dst, x86emit::COND_Z, skip2); // jz skip2 + emit_sub_r32_imm(dst, REG_ECX, 31); // sub ecx,31 + emit_mov_r32_r32(dst, tempreg, reglo); // mov ebx,reglo + emit_shld_r32_r32_imm(dst, reglo, reghi, 31); // shld reglo,reghi,31 + emit_shld_r32_r32_imm(dst, reghi, tempreg, 31); // shld reghi,ebx,31 + track_resolve_link(dst, skip2); // skip2: + } + else + emit_xchg_r32_r32(dst, reghi, reglo); // xchg reghi,reglo + track_resolve_link(dst, skip1); // skip1: + emit_mov_r32_r32(dst, tempreg, reglo); // mov ebx,reglo + emit_shld_r32_r32_cl(dst, reglo, reghi); // shld reglo,reghi,cl + if (saveflags) emit_pushf(dst); // pushf + emit_shld_r32_r32_cl(dst, reghi, tempreg); // shld reghi,ebx,cl + emit_mov_r32_m32(dst, tempreg, MBD(REG_ESP, saveflags ? -4 : -8)); // mov ebx,[esp-8] + } + if (saveflags) + emit_combine_z_flags(dst); +} + + +//------------------------------------------------- +// emit_ror_r64_p64 - ror operation to a 64-bit +// pair of registers from a 64-bit parameter +//------------------------------------------------- + +void drcbe_x86::emit_ror_r64_p64(x86code *&dst, UINT8 reglo, UINT8 reghi, const be_parameter ¶m, const instruction &inst) +{ + int saveflags = ((inst.flags() & FLAG_Z) != 0); + if (param.is_immediate()) + { + int count = param.immediate() & 63; + if (inst.flags() == 0 && count == 0) + ;// skip + else + { + while (count >= 32) + { + if (inst.flags() != 0) + { + emit_mov_r32_r32(dst, REG_ECX, reglo); // mov ecx,reglo + emit_shrd_r32_r32_imm(dst, reglo, reghi, 31); // shrd reglo,reghi,31 + emit_shrd_r32_r32_imm(dst, reghi, REG_ECX, 31); // shrd reghi,ecx,31 + count -= 31; + } + else + { + emit_xchg_r32_r32(dst, reghi, reglo); // xchg reghi,reglo + count -= 32; + } + } + if (inst.flags() != 0 || count > 0) + { + emit_mov_r32_r32(dst, REG_ECX, reglo); // mov ecx,reglo + emit_shrd_r32_r32_imm(dst, reglo, reghi, count); // shrd reglo,reghi,count + if (saveflags) emit_pushf(dst); // pushf + emit_shrd_r32_r32_imm(dst, reghi, REG_ECX, count); // shrd reghi,ecx,count + } + } + } + else + { + emit_link skip1, skip2; + int tempreg = REG_EBX; + emit_mov_m32_r32(dst, MBD(REG_ESP, -8), tempreg); // mov [esp-8],ebx + emit_mov_r32_p32(dst, REG_ECX, param); // mov ecx,param + emit_test_r32_imm(dst, REG_ECX, 0x20); // test ecx,0x20 + emit_jcc_short_link(dst, x86emit::COND_Z, skip1); // jz skip1 + if (inst.flags() != 0) + { + emit_sub_r32_imm(dst, REG_ECX, 31); // sub ecx,31 + emit_mov_r32_r32(dst, tempreg, reglo); // mov ebx,reglo + emit_shrd_r32_r32_imm(dst, reglo, reghi, 31); // shrd reglo,reghi,31 + emit_shrd_r32_r32_imm(dst, reghi, tempreg, 31); // shrd reghi,ebx,31 + emit_test_r32_imm(dst, REG_ECX, 0x20); // test ecx,0x20 + emit_jcc_short_link(dst, x86emit::COND_Z, skip2); // jz skip2 + emit_sub_r32_imm(dst, REG_ECX, 31); // sub ecx,31 + emit_mov_r32_r32(dst, tempreg, reglo); // mov ebx,reglo + emit_shrd_r32_r32_imm(dst, reglo, reghi, 31); // shrd reglo,reghi,31 + emit_shrd_r32_r32_imm(dst, reghi, tempreg, 31); // shrd reghi,ebx,31 + track_resolve_link(dst, skip2); // skip2: + } + else + emit_xchg_r32_r32(dst, reghi, reglo); // xchg reghi,reglo + track_resolve_link(dst, skip1); // skip1: + emit_mov_r32_r32(dst, tempreg, reglo); // mov ebx,reglo + emit_shrd_r32_r32_cl(dst, reglo, reghi); // shrd reglo,reghi,cl + if (saveflags) emit_pushf(dst); // pushf + emit_shrd_r32_r32_cl(dst, reghi, tempreg); // shrd reghi,ebx,cl + emit_mov_r32_m32(dst, tempreg, MBD(REG_ESP, saveflags ? -4 : -8)); // mov ebx,[esp-8] + } + if (saveflags) + emit_combine_z_flags(dst); +} + + +//------------------------------------------------- +// emit_rcl_r64_p64 - rcl operation to a 64-bit +// pair of registers from a 64-bit parameter +//------------------------------------------------- + +void drcbe_x86::emit_rcl_r64_p64(x86code *&dst, UINT8 reglo, UINT8 reghi, const be_parameter ¶m, const instruction &inst) +{ + int saveflags = ((inst.flags() & FLAG_Z) != 0); + emit_link skipall, skiploop; + x86code *loop; + + emit_mov_r32_p32_keepflags(dst, REG_ECX, param); // mov ecx,param + if (!saveflags) + { + loop = dst; // loop: + emit_jecxz_link(dst, skipall); // jecxz skipall + emit_lea_r32_m32(dst, REG_ECX, MBD(REG_ECX, -1)); // lea ecx,[ecx-1] + emit_rcl_r32_imm(dst, reglo, 1); // rcl reglo,1 + emit_rcl_r32_imm(dst, reghi, 1); // rcl reghi,1 + emit_jmp(dst, loop); // jmp loop + track_resolve_link(dst, skipall); // skipall: + } + else + { + emit_jecxz_link(dst, skipall); // jecxz skipall + emit_lea_r32_m32(dst, REG_ECX, MBD(REG_ECX, -1)); // lea ecx,[ecx-1] + loop = dst; // loop: + emit_jecxz_link(dst, skiploop); // jecxz skiploop + emit_lea_r32_m32(dst, REG_ECX, MBD(REG_ECX, -1)); // lea ecx,[ecx-1] + emit_rcl_r32_imm(dst, reglo, 1); // rcl reglo,1 + emit_rcl_r32_imm(dst, reghi, 1); // rcl reghi,1 + emit_jmp(dst, loop); // jmp loop + track_resolve_link(dst, skiploop); // skiploop: + emit_rcl_r32_imm(dst, reglo, 1); // rcl reglo,1 + emit_pushf(dst); // pushf + emit_rcl_r32_imm(dst, reghi, 1); // rcl reghi,1 + track_resolve_link(dst, skipall); // skipall: + emit_combine_z_flags(dst); + } +} + + +//------------------------------------------------- +// emit_rcr_r64_p64 - rcr operation to a 64-bit +// pair of registers from a 64-bit parameter +//------------------------------------------------- + +void drcbe_x86::emit_rcr_r64_p64(x86code *&dst, UINT8 reglo, UINT8 reghi, const be_parameter ¶m, const instruction &inst) +{ + int saveflags = (inst.flags() != 0); + emit_link skipall, skiploop; + x86code *loop; + + emit_mov_r32_p32_keepflags(dst, REG_ECX, param); // mov ecx,param + if (!saveflags) + { + loop = dst; // loop: + emit_jecxz_link(dst, skipall); // jecxz skipall + emit_lea_r32_m32(dst, REG_ECX, MBD(REG_ECX, -1)); // lea ecx,[ecx-1] + emit_rcr_r32_imm(dst, reghi, 1); // rcr reghi,1 + emit_rcr_r32_imm(dst, reglo, 1); // rcr reglo,1 + emit_jmp(dst, loop); // jmp loop + track_resolve_link(dst, skipall); // skipall: + } + else + { + emit_jecxz_link(dst, skipall); // jecxz skipall + emit_lea_r32_m32(dst, REG_ECX, MBD(REG_ECX, -1)); // lea ecx,[ecx-1] + loop = dst; // loop: + emit_jecxz_link(dst, skiploop); // jecxz skiploop + emit_lea_r32_m32(dst, REG_ECX, MBD(REG_ECX, -1)); // lea ecx,[ecx-1] + emit_rcr_r32_imm(dst, reghi, 1); // rcr reghi,1 + emit_rcr_r32_imm(dst, reglo, 1); // rcr reglo,1 + emit_jmp(dst, loop); // jmp loop + track_resolve_link(dst, skiploop); // skiploop: + emit_rcr_r32_imm(dst, reghi, 1); // rcr reghi,1 + emit_pushf(dst); // pushf + emit_rcr_r32_imm(dst, reglo, 1); // rcr reglo,1 + track_resolve_link(dst, skipall); // skipall: + emit_combine_z_shl_flags(dst); + } +} + + + +//************************************************************************** +// EMITTERS FOR FLOATING POINT +//************************************************************************** + +//------------------------------------------------- +// emit_fld_p - load a floating point parameter +// onto the stack +//------------------------------------------------- + +void drcbe_x86::emit_fld_p(x86code *&dst, int size, const be_parameter ¶m) +{ + assert(param.is_memory()); + assert(size == 4 || size == 8); + if (size == 4) + emit_fld_m32(dst, MABS(param.memory())); + else if (size == 8) + emit_fld_m64(dst, MABS(param.memory())); +} + + +//------------------------------------------------- +// emit_fstp_p - store a floating point parameter +// from the stack and pop it +//------------------------------------------------- + +void drcbe_x86::emit_fstp_p(x86code *&dst, int size, const be_parameter ¶m) +{ + assert(param.is_memory()); + assert(size == 4 || size == 8); + if (size == 4) + emit_fstp_m32(dst, MABS(param.memory())); + else if (size == 8) + emit_fstp_m64(dst, MABS(param.memory())); +} + + + +//************************************************************************** +// OUT-OF-BAND CODE FIXUP CALLBACKS +//************************************************************************** + +//------------------------------------------------- +// fixup_label - callback to fixup forward- +// referenced labels +//------------------------------------------------- + +void drcbe_x86::fixup_label(void *parameter, drccodeptr labelcodeptr) +{ + drccodeptr src = (drccodeptr)parameter; + + // find the end of the instruction + if (src[0] == 0xe3) + { + src += 1 + 1; + src[-1] = labelcodeptr - src; + } + else if (src[0] == 0xe9) + { + src += 1 + 4; + ((UINT32 *)src)[-1] = labelcodeptr - src; + } + else if (src[0] == 0x0f && (src[1] & 0xf0) == 0x80) + { + src += 2 + 4; + ((UINT32 *)src)[-1] = labelcodeptr - src; + } + else + fatalerror("fixup_label called with invalid jmp source!\n"); +} + + +//------------------------------------------------- +// fixup_exception - callback to perform cleanup +// and jump to an exception handler +//------------------------------------------------- + +void drcbe_x86::fixup_exception(drccodeptr *codeptr, void *param1, void *param2) +{ + drccodeptr src = (drccodeptr)param1; + const instruction &inst = *(const instruction *)param2; + + // normalize parameters + const parameter &handp = inst.param(0); + assert(handp.is_code_handle()); + be_parameter exp(*this, inst.param(1), PTYPE_MRI); + + // look up the handle target + drccodeptr *targetptr = handp.handle().codeptr_addr(); + + // first fixup the jump to get us here + drccodeptr dst = *codeptr; + ((UINT32 *)src)[-1] = dst - src; + + // then store the exception parameter + emit_mov_m32_p32(dst, MABS(&m_state.exp), exp); // mov [exp],exp + + // push the original return address on the stack + emit_push_imm(dst, (FPTR)src); // push + if (*targetptr != NULL) + emit_jmp(dst, *targetptr); // jmp *targetptr + else + emit_jmp_m32(dst, MABS(targetptr)); // jmp [targetptr] + + *codeptr = dst; +} + + + +//************************************************************************** +// DEBUG HELPERS +//************************************************************************** + +//------------------------------------------------- +// debug_log_hashjmp - callback to handle +// logging of hashjmps +//------------------------------------------------- + +void drcbe_x86::debug_log_hashjmp(int mode, offs_t pc) +{ + printf("mode=%d PC=%08X\n", mode, pc); +} + + + +//************************************************************************** +// COMPILE-TIME OPCODES +//************************************************************************** + +//------------------------------------------------- +// op_handle - process a HANDLE opcode +//------------------------------------------------- + +void drcbe_x86::op_handle(x86code *&dst, const instruction &inst) +{ + assert_no_condition(inst); + assert_no_flags(inst); + assert(inst.numparams() == 1); + assert(inst.param(0).is_code_handle()); + + reset_last_upper_lower_reg(); + + // emit a jump around the stack adjust in case code falls through here + emit_link skip; + emit_jmp_short_link(dst, skip); // jmp skip + + // register the current pointer for the handle + inst.param(0).handle().set_codeptr(dst); + + // by default, the handle points to prolog code that moves the stack pointer + emit_lea_r32_m32(dst, REG_ESP, MBD(REG_ESP, -28)); // lea rsp,[rsp-28] + track_resolve_link(dst, skip); // skip: +} + + +//------------------------------------------------- +// op_hash - process a HASH opcode +//------------------------------------------------- + +void drcbe_x86::op_hash(x86code *&dst, const instruction &inst) +{ + assert_no_condition(inst); + assert_no_flags(inst); + assert(inst.numparams() == 2); + assert(inst.param(0).is_immediate()); + assert(inst.param(1).is_immediate()); + + // register the current pointer for the mode/PC + m_hash.set_codeptr(inst.param(0).immediate(), inst.param(1).immediate(), dst); + reset_last_upper_lower_reg(); +} + + +//------------------------------------------------- +// op_label - process a LABEL opcode +//------------------------------------------------- + +void drcbe_x86::op_label(x86code *&dst, const instruction &inst) +{ + assert_no_condition(inst); + assert_no_flags(inst); + assert(inst.numparams() == 1); + assert(inst.param(0).is_code_label()); + + // register the current pointer for the label + m_labels.set_codeptr(inst.param(0).label(), dst); + reset_last_upper_lower_reg(); +} + + +//------------------------------------------------- +// op_comment - process a COMMENT opcode +//------------------------------------------------- + +void drcbe_x86::op_comment(x86code *&dst, const instruction &inst) +{ + assert_no_condition(inst); + assert_no_flags(inst); + assert(inst.numparams() == 1); + assert(inst.param(0).is_string()); + + // do nothing +} + + +//------------------------------------------------- +// op_mapvar - process a MAPVAR opcode +//------------------------------------------------- + +void drcbe_x86::op_mapvar(x86code *&dst, const instruction &inst) +{ + assert_no_condition(inst); + assert_no_flags(inst); + assert(inst.numparams() == 2); + assert(inst.param(0).is_mapvar()); + assert(inst.param(1).is_immediate()); + + // set the value of the specified mapvar + m_map.set_value(dst, inst.param(0).mapvar(), inst.param(1).immediate()); +} + + + +//************************************************************************** +// CONTROL FLOW OPCODES +//************************************************************************** + +//------------------------------------------------- +// op_nop - process a NOP opcode +//------------------------------------------------- + +void drcbe_x86::op_nop(x86code *&dst, const instruction &inst) +{ + // nothing +} + + +//------------------------------------------------- +// op_debug - process a DEBUG opcode +//------------------------------------------------- + +void drcbe_x86::op_debug(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4); + assert_no_condition(inst); + assert_no_flags(inst); + + if ((m_device.machine().debug_flags & DEBUG_FLAG_ENABLED) != 0) + { + // normalize parameters + be_parameter pcp(*this, inst.param(0), PTYPE_MRI); + + // test and branch + emit_test_m32_imm(dst, MABS(&m_device.machine().debug_flags), DEBUG_FLAG_CALL_HOOK); // test [debug_flags],DEBUG_FLAG_CALL_HOOK + emit_link skip = { 0 }; + emit_jcc_short_link(dst, x86emit::COND_Z, skip); // jz skip + + // push the parameter + emit_mov_m32_p32(dst, MBD(REG_ESP, 4), pcp); // mov [esp+4],pcp + emit_mov_m32_imm(dst, MBD(REG_ESP, 0), (FPTR)&m_device); // mov [esp],device + emit_call(dst, (x86code *)debugger_instruction_hook); // call debug_cpu_instruction_hook + + track_resolve_link(dst, skip); // skip: + } +} + + +//------------------------------------------------- +// op_exit - process an EXIT opcode +//------------------------------------------------- + +void drcbe_x86::op_exit(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4); + assert_any_condition(inst); + assert_no_flags(inst); + + // normalize parameters + be_parameter retp(*this, inst.param(0), PTYPE_MRI); + + // load the parameter into EAX + emit_mov_r32_p32(dst, REG_EAX, retp); // mov eax,retp + if (inst.condition() == uml::COND_ALWAYS) + emit_jmp(dst, m_exit); // jmp exit + else + emit_jcc(dst, X86_CONDITION(inst.condition()), m_exit); // jcc exit +} + + +//------------------------------------------------- +// op_hashjmp - process a HASHJMP opcode +//------------------------------------------------- + +void drcbe_x86::op_hashjmp(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4); + assert_no_condition(inst); + assert_no_flags(inst); + + // normalize parameters + be_parameter modep(*this, inst.param(0), PTYPE_MRI); + be_parameter pcp(*this, inst.param(1), PTYPE_MRI); + const parameter &exp = inst.param(2); + assert(exp.is_code_handle()); + + if (LOG_HASHJMPS) + { + emit_mov_m32_p32(dst, MBD(REG_ESP, 4), pcp); + emit_mov_m32_p32(dst, MBD(REG_ESP, 0), modep); + emit_call(dst, (x86code *)debug_log_hashjmp); + } + + // load the stack base one word early so we end up at the right spot after our call below + emit_mov_r32_m32(dst, REG_ESP, MABS(&m_hashstacksave)); // mov esp,[hashstacksave] + + // fixed mode cases + if (modep.is_immediate() && m_hash.is_mode_populated(modep.immediate())) + { + // a straight immediate jump is direct, though we need the PC in EAX in case of failure + if (pcp.is_immediate()) + { + UINT32 l1val = (pcp.immediate() >> m_hash.l1shift()) & m_hash.l1mask(); + UINT32 l2val = (pcp.immediate() >> m_hash.l2shift()) & m_hash.l2mask(); + emit_call_m32(dst, MABS(&m_hash.base()[modep.immediate()][l1val][l2val])); // call hash[modep][l1val][l2val] + } + + // a fixed mode but variable PC + else + { + emit_mov_r32_p32(dst, REG_EAX, pcp); // mov eax,pcp + emit_mov_r32_r32(dst, REG_EDX, REG_EAX); // mov edx,eax + emit_shr_r32_imm(dst, REG_EDX, m_hash.l1shift()); // shr edx,l1shift + emit_and_r32_imm(dst, REG_EAX, m_hash.l2mask() << m_hash.l2shift());// and eax,l2mask << l2shift + emit_mov_r32_m32(dst, REG_EDX, MABSI(&m_hash.base()[modep.immediate()][0], REG_EDX, 4)); + // mov edx,hash[modep+edx*4] + emit_call_m32(dst, MBISD(REG_EDX, REG_EAX, 4 >> m_hash.l2shift(), 0));// call [edx+eax*shift] + } + } + else + { + // variable mode + int modereg = modep.select_register(REG_ECX); + emit_mov_r32_p32(dst, modereg, modep); // mov modereg,modep + emit_mov_r32_m32(dst, REG_ECX, MABSI(m_hash.base(), modereg, 4)); // mov ecx,hash[modereg*4] + + // fixed PC + if (pcp.is_immediate()) + { + UINT32 l1val = (pcp.immediate() >> m_hash.l1shift()) & m_hash.l1mask(); + UINT32 l2val = (pcp.immediate() >> m_hash.l2shift()) & m_hash.l2mask(); + emit_mov_r32_m32(dst, REG_EDX, MBD(REG_ECX, l1val*4)); // mov edx,[ecx+l1val*4] + emit_call_m32(dst, MBD(REG_EDX, l2val*4)); // call [l2val*4] + } + + // variable PC + else + { + emit_mov_r32_p32(dst, REG_EAX, pcp); // mov eax,pcp + emit_mov_r32_r32(dst, REG_EDX, REG_EAX); // mov edx,eax + emit_shr_r32_imm(dst, REG_EDX, m_hash.l1shift()); // shr edx,l1shift + emit_mov_r32_m32(dst, REG_EDX, MBISD(REG_ECX, REG_EDX, 4, 0)); // mov edx,[ecx+edx*4] + emit_and_r32_imm(dst, REG_EAX, m_hash.l2mask() << m_hash.l2shift());// and eax,l2mask << l2shift + emit_call_m32(dst, MBISD(REG_EDX, REG_EAX, 4 >> m_hash.l2shift(), 0));// call [edx+eax*shift] + } + } + + // in all cases, if there is no code, we return here to generate the exception + emit_mov_m32_p32(dst, MABS(&m_state.exp), pcp); // mov [exp],param + emit_sub_r32_imm(dst, REG_ESP, 4); // sub esp,4 + emit_call_m32(dst, MABS(exp.handle().codeptr_addr())); // call [exp] +} + + +//------------------------------------------------- +// op_jmp - process a JMP opcode +//------------------------------------------------- + +void drcbe_x86::op_jmp(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4); + assert_any_condition(inst); + assert_no_flags(inst); + + // normalize parameters + const parameter &labelp = inst.param(0); + assert(labelp.is_code_label()); + + // look up the jump target and jump there + x86code *jmptarget = (x86code *)m_labels.get_codeptr(labelp.label(), m_fixup_label, dst); + if (inst.condition() == uml::COND_ALWAYS) + emit_jmp(dst, jmptarget); // jmp target + else + emit_jcc(dst, X86_CONDITION(inst.condition()), jmptarget); // jcc target +} + + +//------------------------------------------------- +// op_exh - process an EXH opcode +//------------------------------------------------- + +void drcbe_x86::op_exh(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4); + assert_any_condition(inst); + assert_no_flags(inst); + + // normalize parameters + const parameter &handp = inst.param(0); + assert(handp.is_code_handle()); + be_parameter exp(*this, inst.param(1), PTYPE_MRI); + + // look up the handle target + drccodeptr *targetptr = handp.handle().codeptr_addr(); + + // perform the exception processing inline if unconditional + if (inst.condition() == uml::COND_ALWAYS) + { + emit_mov_m32_p32(dst, MABS(&m_state.exp), exp); // mov [exp],exp + if (*targetptr != NULL) + emit_call(dst, *targetptr); // call *targetptr + else + emit_call_m32(dst, MABS(targetptr)); // call [targetptr] + } + + // otherwise, jump to an out-of-band handler + else + { + emit_jcc(dst, X86_CONDITION(inst.condition()), 0); // jcc exception + m_cache.request_oob_codegen(m_fixup_exception, dst, &const_cast(inst)); + } +} + + +//------------------------------------------------- +// op_callh - process a CALLH opcode +//------------------------------------------------- + +void drcbe_x86::op_callh(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4); + assert_any_condition(inst); + assert_no_flags(inst); + + // normalize parameters + const parameter &handp = inst.param(0); + assert(handp.is_code_handle()); + + // look up the handle target + drccodeptr *targetptr = handp.handle().codeptr_addr(); + + // skip if conditional + emit_link skip = { 0 }; + if (inst.condition() != uml::COND_ALWAYS) + emit_jcc_short_link(dst, X86_NOT_CONDITION(inst.condition()), skip); // jcc skip + + // jump through the handle; directly if a normal jump + if (*targetptr != NULL) + emit_call(dst, *targetptr); // call *targetptr + else + emit_call_m32(dst, MABS(targetptr)); // call [targetptr] + + // resolve the conditional link + if (inst.condition() != uml::COND_ALWAYS) + track_resolve_link(dst, skip); // skip: +} + + +//------------------------------------------------- +// op_ret - process a RET opcode +//------------------------------------------------- + +void drcbe_x86::op_ret(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4); + assert_any_condition(inst); + assert_no_flags(inst); + assert(inst.numparams() == 0); + + // skip if conditional + emit_link skip = { 0 }; + if (inst.condition() != uml::COND_ALWAYS) + emit_jcc_short_link(dst, X86_NOT_CONDITION(inst.condition()), skip); // jcc skip + + // return + emit_lea_r32_m32(dst, REG_ESP, MBD(REG_ESP, 28)); // lea rsp,[rsp+28] + emit_ret(dst); // ret + + // resolve the conditional link + if (inst.condition() != uml::COND_ALWAYS) + track_resolve_link(dst, skip); // skip: +} + + +//------------------------------------------------- +// op_callc - process a CALLC opcode +//------------------------------------------------- + +void drcbe_x86::op_callc(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4); + assert_any_condition(inst); + assert_no_flags(inst); + + // normalize parameters + const parameter &funcp = inst.param(0); + assert(funcp.is_c_function()); + be_parameter paramp(*this, inst.param(1), PTYPE_M); + + // skip if conditional + emit_link skip = { 0 }; + if (inst.condition() != uml::COND_ALWAYS) + emit_jcc_short_link(dst, X86_NOT_CONDITION(inst.condition()), skip); // jcc skip + + // perform the call + emit_mov_m32_imm(dst, MBD(REG_ESP, 0), (FPTR)paramp.memory()); // mov [esp],paramp + emit_call(dst, (x86code *)(FPTR)funcp.cfunc()); // call funcp + + // resolve the conditional link + if (inst.condition() != uml::COND_ALWAYS) + track_resolve_link(dst, skip); // skip: +} + + +//------------------------------------------------- +// op_recover - process a RECOVER opcode +//------------------------------------------------- + +void drcbe_x86::op_recover(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4); + assert_no_condition(inst); + assert_no_flags(inst); + + // normalize parameters + be_parameter dstp(*this, inst.param(0), PTYPE_MR); + + // call the recovery code + emit_mov_r32_m32(dst, REG_EAX, MABS(&m_stacksave)); // mov eax,stacksave + emit_mov_r32_m32(dst, REG_EAX, MBD(REG_EAX, -4)); // mov eax,[eax-4] + emit_sub_r32_imm(dst, REG_EAX, 1); // sub eax,1 + emit_mov_m32_imm(dst, MBD(REG_ESP, 8), inst.param(1).mapvar()); // mov [esp+8],param1 + emit_mov_m32_r32(dst, MBD(REG_ESP, 4), REG_EAX); // mov [esp+4],eax + emit_mov_m32_imm(dst, MBD(REG_ESP, 0), (FPTR)&m_map); // mov [esp],m_map + emit_call(dst, (x86code *)&drc_map_variables::static_get_value); // call drcmap_get_value + emit_mov_p32_r32(dst, dstp, REG_EAX); // mov dstp,eax +} + + + +//************************************************************************** +// INTERNAL REGISTER OPCODES +//************************************************************************** + +//------------------------------------------------- +// op_setfmod - process a SETFMOD opcode +//------------------------------------------------- + +void drcbe_x86::op_setfmod(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4); + assert_no_condition(inst); + assert_no_flags(inst); + + // normalize parameters + be_parameter srcp(*this, inst.param(0), PTYPE_MRI); + + // immediate case + if (srcp.is_immediate()) + { + int value = srcp.immediate() & 3; + emit_mov_m8_imm(dst, MABS(&m_state.fmod), value); // mov [fmod],srcp + emit_fldcw_m16(dst, MABS(&fp_control[value])); // fldcw fp_control[srcp] + } + + // register/memory case + else + { + emit_mov_r32_p32(dst, REG_EAX, srcp); // mov eax,srcp + emit_and_r32_imm(dst, REG_EAX, 3); // and eax,3 + emit_mov_m8_r8(dst, MABS(&m_state.fmod), REG_AL); // mov [fmod],al + emit_fldcw_m16(dst, MABSI(&fp_control[0], REG_EAX, 2)); // fldcw fp_control[eax] + } +} + + +//------------------------------------------------- +// op_getfmod - process a GETFMOD opcode +//------------------------------------------------- + +void drcbe_x86::op_getfmod(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4); + assert_no_condition(inst); + assert_no_flags(inst); + + // normalize parameters + be_parameter dstp(*this, inst.param(0), PTYPE_MR); + + // fetch the current mode and store to the destination + if (dstp.is_int_register()) + emit_movzx_r32_m8(dst, dstp.ireg(), MABS(&m_state.fmod)); // movzx reg,[fmod] + else + { + emit_movzx_r32_m8(dst, REG_EAX, MABS(&m_state.fmod)); // movzx eax,[fmod] + emit_mov_m32_r32(dst, MABS(dstp.memory()), REG_EAX); // mov [dstp],eax + } +} + + +//------------------------------------------------- +// op_getexp - process a GETEXP opcode +//------------------------------------------------- + +void drcbe_x86::op_getexp(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4); + assert_no_condition(inst); + assert_no_flags(inst); + + // normalize parameters + be_parameter dstp(*this, inst.param(0), PTYPE_MR); + + // fetch the exception parameter and store to the destination + if (dstp.is_int_register()) + emit_mov_r32_m32(dst, dstp.ireg(), MABS(&m_state.exp)); // mov reg,[exp] + else + { + emit_mov_r32_m32(dst, REG_EAX, MABS(&m_state.exp)); // mov eax,[exp] + emit_mov_m32_r32(dst, MABS(dstp.memory()), REG_EAX); // mov [dstp],eax + } +} + + +//------------------------------------------------- +// op_getflgs - process a GETFLGS opcode +//------------------------------------------------- + +void drcbe_x86::op_getflgs(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4); + assert_no_condition(inst); + assert_no_flags(inst); + + // normalize parameters + be_parameter dstp(*this, inst.param(0), PTYPE_MR); + be_parameter maskp(*this, inst.param(1), PTYPE_I); + + // pick a target register for the general case + int dstreg = dstp.select_register(REG_EAX); + + // compute mask for flags + UINT32 flagmask = 0; + if (maskp.immediate() & FLAG_C) flagmask |= 0x001; + if (maskp.immediate() & FLAG_V) flagmask |= 0x800; + if (maskp.immediate() & FLAG_Z) flagmask |= 0x040; + if (maskp.immediate() & FLAG_S) flagmask |= 0x080; + if (maskp.immediate() & FLAG_U) flagmask |= 0x004; + + switch (maskp.immediate()) + { + // single flags only + case FLAG_C: + emit_setcc_r8(dst, x86emit::COND_C, REG_AL); // setc al + emit_movzx_r32_r8(dst, dstreg, REG_AL); // movzx dstreg,al + break; + + case FLAG_V: + emit_setcc_r8(dst, x86emit::COND_O, REG_AL); // seto al + emit_movzx_r32_r8(dst, dstreg, REG_AL); // movzx dstreg,al + emit_shl_r32_imm(dst, dstreg, 1); // shl dstreg,1 + break; + + case FLAG_Z: + emit_setcc_r8(dst, x86emit::COND_Z, REG_AL); // setz al + emit_movzx_r32_r8(dst, dstreg, REG_AL); // movzx dstreg,al + emit_shl_r32_imm(dst, dstreg, 2); // shl dstreg,2 + break; + + case FLAG_S: + emit_setcc_r8(dst, x86emit::COND_S, REG_AL); // sets al + emit_movzx_r32_r8(dst, dstreg, REG_AL); // movzx dstreg,al + emit_shl_r32_imm(dst, dstreg, 3); // shl dstreg,3 + break; + + case FLAG_U: + emit_setcc_r8(dst, x86emit::COND_P, REG_AL); // setp al + emit_movzx_r32_r8(dst, dstreg, REG_AL); // movzx dstreg,al + emit_shl_r32_imm(dst, dstreg, 4); // shl dstreg,4 + break; + + // carry plus another flag + case FLAG_C | FLAG_V: + emit_setcc_r8(dst, x86emit::COND_C, REG_AL); // setc al + emit_setcc_r8(dst, x86emit::COND_O, REG_CL); // seto cl + emit_movzx_r32_r8(dst, REG_EAX, REG_AL); // movzx eax,al + emit_movzx_r32_r8(dst, REG_ECX, REG_CL); // movzx ecx,al + emit_lea_r32_m32(dst, dstreg, MBISD(REG_EAX, REG_ECX, 2, 0)); // lea dstreg,[eax+ecx*2] + break; + + case FLAG_C | FLAG_Z: + emit_setcc_r8(dst, x86emit::COND_C, REG_AL); // setc al + emit_setcc_r8(dst, x86emit::COND_Z, REG_CL); // setz cl + emit_movzx_r32_r8(dst, REG_EAX, REG_AL); // movzx eax,al + emit_movzx_r32_r8(dst, REG_ECX, REG_CL); // movzx ecx,al + emit_lea_r32_m32(dst, dstreg, MBISD(REG_EAX, REG_ECX, 4, 0)); // lea dstreg,[eax+ecx*4] + break; + + case FLAG_C | FLAG_S: + emit_setcc_r8(dst, x86emit::COND_C, REG_AL); // setc al + emit_setcc_r8(dst, x86emit::COND_S, REG_CL); // sets cl + emit_movzx_r32_r8(dst, REG_EAX, REG_AL); // movzx eax,al + emit_movzx_r32_r8(dst, REG_ECX, REG_CL); // movzx ecx,al + emit_lea_r32_m32(dst, dstreg, MBISD(REG_EAX, REG_ECX, 8, 0)); // lea dstreg,[eax+ecx*8] + break; + + // overflow plus another flag + case FLAG_V | FLAG_Z: + emit_setcc_r8(dst, x86emit::COND_O, REG_AL); // seto al + emit_setcc_r8(dst, x86emit::COND_Z, REG_CL); // setz cl + emit_movzx_r32_r8(dst, REG_EAX, REG_AL); // movzx eax,al + emit_movzx_r32_r8(dst, REG_ECX, REG_CL); // movzx ecx,al + emit_lea_r32_m32(dst, dstreg, MBISD(REG_EAX, REG_ECX, 2, 0)); // lea dstreg,[eax+ecx*2] + emit_shl_r32_imm(dst, dstreg, 1); // shl dstreg,1 + break; + + case FLAG_V | FLAG_S: + emit_setcc_r8(dst, x86emit::COND_O, REG_AL); // seto al + emit_setcc_r8(dst, x86emit::COND_S, REG_CL); // sets cl + emit_movzx_r32_r8(dst, REG_EAX, REG_AL); // movzx eax,al + emit_movzx_r32_r8(dst, REG_ECX, REG_CL); // movzx ecx,al + emit_lea_r32_m32(dst, dstreg, MBISD(REG_EAX, REG_ECX, 4, 0)); // lea dstreg,[eax+ecx*4] + emit_shl_r32_imm(dst, dstreg, 1); // shl dstreg,1 + break; + + // zero plus another flag + case FLAG_Z | FLAG_S: + emit_setcc_r8(dst, x86emit::COND_Z, REG_AL); // setz al + emit_setcc_r8(dst, x86emit::COND_S, REG_CL); // sets cl + emit_movzx_r32_r8(dst, REG_EAX, REG_AL); // movzx eax,al + emit_movzx_r32_r8(dst, REG_ECX, REG_CL); // movzx ecx,al + emit_lea_r32_m32(dst, dstreg, MBISD(REG_EAX, REG_ECX, 2, 0)); // lea dstreg,[eax+ecx*2] + emit_shl_r32_imm(dst, dstreg, 2); // shl dstreg,2 + break; + + // default cases + default: + emit_pushf(dst); // pushf + emit_pop_r32(dst, REG_EAX); // pop eax + emit_and_r32_imm(dst, REG_EAX, flagmask); // and eax,flagmask + emit_movzx_r32_m8(dst, dstreg, MABSI(flags_map, REG_EAX)); // movzx dstreg,[flags_map] + break; + } + + // store low 32 bits + emit_mov_p32_r32(dst, dstp, dstreg); // mov dstp,dstreg + + // 64-bit form stores upper 32 bits + if (inst.size() == 8) + { + // general case + if (dstp.is_memory()) + emit_mov_m32_imm(dst, MABS(dstp.memory(4)), 0); // mov [dstp+4],0 + else if (dstp.is_int_register()) + emit_mov_m32_imm(dst, MABS(m_reghi[dstp.ireg()]), 0); // mov [reghi],0 + } +} + + +//------------------------------------------------- +// op_save - process a SAVE opcode +//------------------------------------------------- + +void drcbe_x86::op_save(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4); + assert_no_condition(inst); + assert_no_flags(inst); + + // normalize parameters + be_parameter dstp(*this, inst.param(0), PTYPE_M); + + // copy live state to the destination + emit_mov_r32_imm(dst, REG_ECX, (FPTR)dstp.memory()); // mov ecx,dstp + emit_call(dst, m_save); // call save +} + + +//------------------------------------------------- +// op_restore - process a RESTORE opcode +//------------------------------------------------- + +void drcbe_x86::op_restore(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4); + assert_no_condition(inst); + + // normalize parameters + be_parameter srcp(*this, inst.param(0), PTYPE_M); + + // copy live state from the destination + emit_mov_r32_imm(dst, REG_ECX, (FPTR)srcp.memory()); // mov ecx,dstp + emit_call(dst, m_restore); // call restore +} + + + +//************************************************************************** +// INTEGER OPERATIONS +//************************************************************************** + +//------------------------------------------------- +// op_load - process a LOAD opcode +//------------------------------------------------- + +void drcbe_x86::op_load(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_no_condition(inst); + assert_no_flags(inst); + + // normalize parameters + be_parameter dstp(*this, inst.param(0), PTYPE_MR); + be_parameter basep(*this, inst.param(1), PTYPE_M); + be_parameter indp(*this, inst.param(2), PTYPE_MRI); + const parameter &scalesizep = inst.param(3); + assert(scalesizep.is_size_scale()); + int scale = 1 << scalesizep.scale(); + int size = scalesizep.size(); + + // pick a target register for the general case + int dstreg = dstp.select_register(REG_EAX); + + // immediate index + if (indp.is_immediate()) + { + if (size == SIZE_BYTE) + emit_movzx_r32_m8(dst, dstreg, MABS(basep.memory(scale*indp.immediate()))); // movzx dstreg,[basep + scale*indp] + else if (size == SIZE_WORD) + emit_movzx_r32_m16(dst, dstreg, MABS(basep.memory(scale*indp.immediate()))); // movzx dstreg,[basep + scale*indp] + else if (size == SIZE_DWORD) + emit_mov_r32_m32(dst, dstreg, MABS(basep.memory(scale*indp.immediate()))); // mov dstreg,[basep + scale*indp] + else if (size == SIZE_QWORD) + { + emit_mov_r32_m32(dst, REG_EDX, MABS(basep.memory(scale*indp.immediate() + 4))); // mov edx,[basep + scale*indp + 4] + emit_mov_r32_m32(dst, dstreg, MABS(basep.memory(scale*indp.immediate()))); // mov dstreg,[basep + scale*indp] + } + } + + // other index + else + { + int indreg = indp.select_register(REG_ECX); + emit_mov_r32_p32(dst, indreg, indp); + if (size == SIZE_BYTE) + emit_movzx_r32_m8(dst, dstreg, MABSI(basep.memory(), indreg, scale)); // movzx dstreg,[basep + scale*indp] + else if (size == SIZE_WORD) + emit_movzx_r32_m16(dst, dstreg, MABSI(basep.memory(), indreg, scale)); // movzx dstreg,[basep + scale*indp] + else if (size == SIZE_DWORD) + emit_mov_r32_m32(dst, dstreg, MABSI(basep.memory(), indreg, scale)); // mov dstreg,[basep + scale*indp] + else if (size == SIZE_QWORD) + { + emit_mov_r32_m32(dst, REG_EDX, MABSI(basep.memory(4), indreg, scale)); // mov edx,[basep + scale*indp + 4] + emit_mov_r32_m32(dst, dstreg, MABSI(basep.memory(), indreg, scale)); // mov dstreg,[basep + scale*indp] + } + } + + // store low 32 bits + emit_mov_p32_r32(dst, dstp, dstreg); // mov dstp,dstreg + + // 64-bit form stores upper 32 bits + if (inst.size() == 8) + { + // 1, 2, or 4-byte case + if (size != SIZE_QWORD) + { + if (dstp.is_memory()) + emit_mov_m32_imm(dst, MABS(dstp.memory(4)), 0); // mov [dstp+4],0 + else if (dstp.is_int_register()) + emit_mov_m32_imm(dst, MABS(m_reghi[dstp.ireg()]), 0); // mov [reghi],0 + } + + // 8-byte case + else + { + if (dstp.is_memory()) + emit_mov_m32_r32(dst, MABS(dstp.memory(4)), REG_EDX); // mov [dstp+4],edx + else if (dstp.is_int_register()) + emit_mov_m32_r32(dst, MABS(m_reghi[dstp.ireg()]), REG_EDX); // mov [reghi],edx + set_last_upper_reg(dst, dstp, REG_EDX); + } + } + set_last_lower_reg(dst, dstp, dstreg); +} + + +//------------------------------------------------- +// op_loads - process a LOADS opcode +//------------------------------------------------- + +void drcbe_x86::op_loads(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_no_condition(inst); + assert_no_flags(inst); + + // normalize parameters + be_parameter dstp(*this, inst.param(0), PTYPE_MR); + be_parameter basep(*this, inst.param(1), PTYPE_M); + be_parameter indp(*this, inst.param(2), PTYPE_MRI); + const parameter &scalesizep = inst.param(3); + assert(scalesizep.is_size_scale()); + int scale = 1 << scalesizep.scale(); + int size = scalesizep.size(); + + // pick a target register for the general case + int dstreg = dstp.select_register(REG_EAX); + + // immediate index + if (indp.is_immediate()) + { + if (size == SIZE_BYTE) + emit_movsx_r32_m8(dst, dstreg, MABS(basep.memory(scale*indp.immediate()))); // movsx dstreg,[basep + scale*indp] + else if (size == SIZE_WORD) + emit_movsx_r32_m16(dst, dstreg, MABS(basep.memory(scale*indp.immediate()))); // movsx dstreg,[basep + scale*indp] + else if (size == SIZE_DWORD) + emit_mov_r32_m32(dst, dstreg, MABS(basep.memory(scale*indp.immediate()))); // mov dstreg,[basep + scale*indp] + else if (size == SIZE_QWORD) + { + emit_mov_r32_m32(dst, REG_EDX, MABS(basep.memory(scale*indp.immediate() + 4))); // mov edx,[basep + scale*indp + 4] + emit_mov_r32_m32(dst, dstreg, MABS(basep.memory(scale*indp.immediate()))); // mov dstreg,[basep + scale*indp] + } + } + + // other index + else + { + int indreg = indp.select_register(REG_ECX); + emit_mov_r32_p32(dst, indreg, indp); + if (size == SIZE_BYTE) + emit_movsx_r32_m8(dst, dstreg, MABSI(basep.memory(), indreg, scale)); // movsx dstreg,[basep + scale*indp] + else if (size == SIZE_WORD) + emit_movsx_r32_m16(dst, dstreg, MABSI(basep.memory(), indreg, scale)); // movsx dstreg,[basep + scale*indp] + else if (size == SIZE_DWORD) + emit_mov_r32_m32(dst, dstreg, MABSI(basep.memory(), indreg, scale)); // mov dstreg,[basep + scale*indp] + else if (size == SIZE_QWORD) + { + emit_mov_r32_m32(dst, REG_EDX, MABSI(basep.memory(4), indreg, scale)); // mov edx,[basep + scale*indp + 4] + emit_mov_r32_m32(dst, dstreg, MABSI(basep.memory(), indreg, scale)); // mov dstreg,[basep + scale*indp] + } + } + + // store low 32 bits + emit_mov_p32_r32(dst, dstp, dstreg); // mov dstp,dstreg + + // 64-bit form stores upper 32 bits + if (inst.size() == 8) + { + emit_cdq(dst); // cdq + if (dstp.is_memory()) + emit_mov_m32_r32(dst, MABS(dstp.memory(4)), REG_EDX); // mov [dstp+4],edx + else if (dstp.is_int_register()) + emit_mov_m32_r32(dst, MABS(m_reghi[dstp.ireg()]), REG_EDX); // mov [reghi],edx + set_last_upper_reg(dst, dstp, REG_EDX); + } + set_last_lower_reg(dst, dstp, dstreg); +} + + +//------------------------------------------------- +// op_store - process a STORE opcode +//------------------------------------------------- + +void drcbe_x86::op_store(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_no_condition(inst); + assert_no_flags(inst); + + // normalize parameters + be_parameter basep(*this, inst.param(0), PTYPE_M); + be_parameter indp(*this, inst.param(1), PTYPE_MRI); + be_parameter srcp(*this, inst.param(2), PTYPE_MRI); + const parameter &scalesizep = inst.param(3); + int scale = 1 << (scalesizep.scale()); + int size = scalesizep.size(); + + // pick a source register for the general case + int srcreg = srcp.select_register(REG_EAX); + if (size == SIZE_BYTE && (srcreg & 4)) + srcreg = REG_EAX; + + // degenerate case: constant index + if (indp.is_immediate()) + { + // immediate source + if (srcp.is_immediate()) + { + if (size == SIZE_BYTE) + emit_mov_m8_imm(dst, MABS(basep.memory(scale*indp.immediate())), srcp.immediate()); // mov [basep + scale*indp],srcp + else if (size == SIZE_WORD) + emit_mov_m16_imm(dst, MABS(basep.memory(scale*indp.immediate())), srcp.immediate()); // mov [basep + scale*indp],srcp + else if (size == SIZE_DWORD) + emit_mov_m32_imm(dst, MABS(basep.memory(scale*indp.immediate())), srcp.immediate()); // mov [basep + scale*indp],srcp + else if (size == SIZE_QWORD) + { + emit_mov_m32_imm(dst, MABS(basep.memory(scale*indp.immediate())), srcp.immediate()); // mov [basep + scale*indp],srcp + emit_mov_m32_imm(dst, MABS(basep.memory(scale*indp.immediate() + 4)), srcp.immediate() >> 32); + // mov [basep + scale*indp + 4],srcp >> 32 + } + } + + // variable source + else + { + if (size != SIZE_QWORD) + emit_mov_r32_p32(dst, srcreg, srcp); // mov srcreg,srcp + else + emit_mov_r64_p64(dst, srcreg, REG_EDX, srcp); // mov edx:srcreg,srcp + if (size == SIZE_BYTE) + emit_mov_m8_r8(dst, MABS(basep.memory(scale*indp.immediate())), srcreg); // mov [basep + scale*indp],srcreg + else if (size == SIZE_WORD) + emit_mov_m16_r16(dst, MABS(basep.memory(scale*indp.immediate())), srcreg); // mov [basep + scale*indp],srcreg + else if (size == SIZE_DWORD) + emit_mov_m32_r32(dst, MABS(basep.memory(scale*indp.immediate())), srcreg); // mov [basep + scale*indp],srcreg + else if (size == SIZE_QWORD) + { + emit_mov_m32_r32(dst, MABS(basep.memory(scale*indp.immediate())), srcreg); // mov [basep + scale*indp],srcreg + emit_mov_m32_r32(dst, MABS(basep.memory(scale*indp.immediate() + 4)), REG_EDX); // mov [basep + scale*indp + 4],edx + } + } + } + + // normal case: variable index + else + { + int indreg = indp.select_register(REG_ECX); + emit_mov_r32_p32(dst, indreg, indp); // mov indreg,indp + + // immediate source + if (srcp.is_immediate()) + { + if (size == SIZE_BYTE) + emit_mov_m8_imm(dst, MABSI(basep.memory(), indreg, scale), srcp.immediate()); // mov [basep + 1*ecx],srcp + else if (size == SIZE_WORD) + emit_mov_m16_imm(dst, MABSI(basep.memory(), indreg, scale), srcp.immediate()); // mov [basep + 2*ecx],srcp + else if (size == SIZE_DWORD) + emit_mov_m32_imm(dst, MABSI(basep.memory(), indreg, scale), srcp.immediate()); // mov [basep + 4*ecx],srcp + else if (size == SIZE_QWORD) + { + emit_mov_m32_imm(dst, MABSI(basep.memory(), indreg, scale), srcp.immediate()); // mov [basep + 8*ecx],srcp + emit_mov_m32_imm(dst, MABSI(basep.memory(4), indreg, scale), srcp.immediate() >> 32); + // mov [basep + 8*ecx + 4],srcp >> 32 + } + } + + // variable source + else + { + if (size != SIZE_QWORD) + emit_mov_r32_p32(dst, srcreg, srcp); // mov srcreg,srcp + else + emit_mov_r64_p64(dst, srcreg, REG_EDX, srcp); // mov edx:srcreg,srcp + if (size == SIZE_BYTE) + emit_mov_m8_r8(dst, MABSI(basep.memory(), indreg, scale), srcreg); // mov [basep + 1*ecx],srcreg + else if (size == SIZE_WORD) + emit_mov_m16_r16(dst, MABSI(basep.memory(), indreg, scale), srcreg); // mov [basep + 2*ecx],srcreg + else if (size == SIZE_DWORD) + emit_mov_m32_r32(dst, MABSI(basep.memory(), indreg, scale), srcreg); // mov [basep + 4*ecx],srcreg + else if (size == SIZE_QWORD) + { + emit_mov_m32_r32(dst, MABSI(basep.memory(), indreg, scale), srcreg); // mov [basep + 8*ecx],srcreg + emit_mov_m32_r32(dst, MABSI(basep.memory(4), indreg, scale), REG_EDX); // mov [basep + 8*ecx],edx + } + } + } +} + + +//------------------------------------------------- +// op_read - process a READ opcode +//------------------------------------------------- + +void drcbe_x86::op_read(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_no_condition(inst); + assert_no_flags(inst); + + // normalize parameters + be_parameter dstp(*this, inst.param(0), PTYPE_MR); + be_parameter addrp(*this, inst.param(1), PTYPE_MRI); + const parameter &spacesizep = inst.param(2); + assert(spacesizep.is_size_space()); + + // pick a target register for the general case + int dstreg = dstp.select_register(REG_EAX); + + // set up a call to the read byte handler + emit_mov_m32_p32(dst, MBD(REG_ESP, 4), addrp); // mov [esp+4],addrp + emit_mov_m32_imm(dst, MBD(REG_ESP, 0), (FPTR)m_space[spacesizep.space()]); // mov [esp],space + if (spacesizep.size() == SIZE_BYTE) + { + emit_call(dst, (x86code *)m_accessors[spacesizep.space()].read_byte); + // call read_byte + emit_movzx_r32_r8(dst, dstreg, REG_AL); // movzx dstreg,al + } + else if (spacesizep.size() == SIZE_WORD) + { + emit_call(dst, (x86code *)m_accessors[spacesizep.space()].read_word); + // call read_word + emit_movzx_r32_r16(dst, dstreg, REG_AX); // movzx dstreg,ax + } + else if (spacesizep.size() == SIZE_DWORD) + { + emit_call(dst, (x86code *)m_accessors[spacesizep.space()].read_dword); + // call read_dword + emit_mov_r32_r32(dst, dstreg, REG_EAX); // mov dstreg,eax + } + else if (spacesizep.size() == SIZE_QWORD) + { + emit_call(dst, (x86code *)m_accessors[spacesizep.space()].read_qword); + // call read_qword + emit_mov_r32_r32(dst, dstreg, REG_EAX); // mov dstreg,eax + } + + // store low 32 bits + emit_mov_p32_r32(dst, dstp, dstreg); // mov dstp,dstreg + + // 64-bit form stores upper 32 bits + if (inst.size() == 8) + { + // 1, 2, or 4-byte case + if (spacesizep.size() != SIZE_QWORD) + { + if (dstp.is_memory()) + emit_mov_m32_imm(dst, MABS(dstp.memory(4)), 0); // mov [dstp+4],0 + else if (dstp.is_int_register()) + emit_mov_m32_imm(dst, MABS(m_reghi[dstp.ireg()]), 0); // mov [reghi],0 + } + + // 8-byte case + else + { + if (dstp.is_memory()) + emit_mov_m32_r32(dst, MABS(dstp.memory(4)), REG_EDX); // mov [dstp+4],edx + else if (dstp.is_int_register()) + emit_mov_m32_r32(dst, MABS(m_reghi[dstp.ireg()]), REG_EDX); // mov [reghi],edx + } + } +} + + +//------------------------------------------------- +// op_readm - process a READM opcode +//------------------------------------------------- + +void drcbe_x86::op_readm(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_no_condition(inst); + assert_no_flags(inst); + + // normalize parameters + be_parameter dstp(*this, inst.param(0), PTYPE_MR); + be_parameter addrp(*this, inst.param(1), PTYPE_MRI); + be_parameter maskp(*this, inst.param(2), PTYPE_MRI); + const parameter &spacesizep = inst.param(3); + assert(spacesizep.is_size_space()); + + // pick a target register for the general case + int dstreg = dstp.select_register(REG_EAX); + + // set up a call to the read byte handler + if (spacesizep.size() != SIZE_QWORD) + emit_mov_m32_p32(dst, MBD(REG_ESP, 8), maskp); // mov [esp+8],maskp + else + emit_mov_m64_p64(dst, MBD(REG_ESP, 8), maskp); // mov [esp+8],maskp + emit_mov_m32_p32(dst, MBD(REG_ESP, 4), addrp); // mov [esp+4],addrp + emit_mov_m32_imm(dst, MBD(REG_ESP, 0), (FPTR)m_space[spacesizep.space()]); // mov [esp],space + if (spacesizep.size() == SIZE_WORD) + { + emit_call(dst, (x86code *)m_accessors[spacesizep.space()].read_word_masked); + // call read_word_masked + emit_movzx_r32_r16(dst, dstreg, REG_AX); // movzx dstreg,ax + } + else if (spacesizep.size() == SIZE_DWORD) + { + emit_call(dst, (x86code *)m_accessors[spacesizep.space()].read_dword_masked); + // call read_dword_masked + emit_mov_r32_r32(dst, dstreg, REG_EAX); // mov dstreg,eax + } + else if (spacesizep.size() == SIZE_QWORD) + { + emit_call(dst, (x86code *)m_accessors[spacesizep.space()].read_qword_masked); + // call read_qword_masked + emit_mov_r32_r32(dst, dstreg, REG_EAX); // mov dstreg,eax + } + + // store low 32 bits + emit_mov_p32_r32(dst, dstp, dstreg); // mov dstp,dstreg + + // 64-bit form stores upper 32 bits + if (inst.size() == 8) + { + // 1, 2, or 4-byte case + if (spacesizep.size() != SIZE_QWORD) + { + if (dstp.is_memory()) + emit_mov_m32_imm(dst, MABS(dstp.memory(4)), 0); // mov [dstp+4],0 + else if (dstp.is_int_register()) + emit_mov_m32_imm(dst, MABS(m_reghi[dstp.ireg()]), 0); // mov [reghi],0 + } + + // 8-byte case + else + { + if (dstp.is_memory()) + emit_mov_m32_r32(dst, MABS(dstp.memory(4)), REG_EDX); // mov [dstp+4],edx + else if (dstp.is_int_register()) + emit_mov_m32_r32(dst, MABS(m_reghi[dstp.ireg()]), REG_EDX); // mov [reghi],edx + } + } +} + + +//------------------------------------------------- +// op_write - process a WRITE opcode +//------------------------------------------------- + +void drcbe_x86::op_write(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_no_condition(inst); + assert_no_flags(inst); + + // normalize parameters + be_parameter addrp(*this, inst.param(0), PTYPE_MRI); + be_parameter srcp(*this, inst.param(1), PTYPE_MRI); + const parameter &spacesizep = inst.param(2); + assert(spacesizep.is_size_space()); + + // set up a call to the write byte handler + if (spacesizep.size() != SIZE_QWORD) + emit_mov_m32_p32(dst, MBD(REG_ESP, 8), srcp); // mov [esp+8],srcp + else + emit_mov_m64_p64(dst, MBD(REG_ESP, 8), srcp); // mov [esp+8],srcp + emit_mov_m32_p32(dst, MBD(REG_ESP, 4), addrp); // mov [esp+4],addrp + emit_mov_m32_imm(dst, MBD(REG_ESP, 0), (FPTR)m_space[spacesizep.space()]); // mov [esp],space + if (spacesizep.size() == SIZE_BYTE) + emit_call(dst, (x86code *)m_accessors[spacesizep.space()].write_byte); + // call write_byte + else if (spacesizep.size() == SIZE_WORD) + emit_call(dst, (x86code *)m_accessors[spacesizep.space()].write_word); + // call write_word + else if (spacesizep.size() == SIZE_DWORD) + emit_call(dst, (x86code *)m_accessors[spacesizep.space()].write_dword); + // call write_dword + else if (spacesizep.size() == SIZE_QWORD) + emit_call(dst, (x86code *)m_accessors[spacesizep.space()].write_qword); + // call write_qword +} + + +//------------------------------------------------- +// op_writem - process a WRITEM opcode +//------------------------------------------------- + +void drcbe_x86::op_writem(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_no_condition(inst); + assert_no_flags(inst); + + // normalize parameters + be_parameter addrp(*this, inst.param(0), PTYPE_MRI); + be_parameter srcp(*this, inst.param(1), PTYPE_MRI); + be_parameter maskp(*this, inst.param(2), PTYPE_MRI); + const parameter &spacesizep = inst.param(3); + assert(spacesizep.is_size_space()); + + // set up a call to the write byte handler + if (spacesizep.size() != SIZE_QWORD) + { + emit_mov_m32_p32(dst, MBD(REG_ESP, 12), maskp); // mov [esp+12],maskp + emit_mov_m32_p32(dst, MBD(REG_ESP, 8), srcp); // mov [esp+8],srcp + } + else + { + emit_mov_m64_p64(dst, MBD(REG_ESP, 16), maskp); // mov [esp+16],maskp + emit_mov_m64_p64(dst, MBD(REG_ESP, 8), srcp); // mov [esp+8],srcp + } + emit_mov_m32_p32(dst, MBD(REG_ESP, 4), addrp); // mov [esp+4],addrp + emit_mov_m32_imm(dst, MBD(REG_ESP, 0), (FPTR)m_space[spacesizep.space()]); // mov [esp],space + if (spacesizep.size() == SIZE_WORD) + emit_call(dst, (x86code *)m_accessors[spacesizep.space()].write_word_masked); + // call write_word_masked + else if (spacesizep.size() == SIZE_DWORD) + emit_call(dst, (x86code *)m_accessors[spacesizep.space()].write_dword_masked); + // call write_dword_masked + else if (spacesizep.size() == SIZE_QWORD) + emit_call(dst, (x86code *)m_accessors[spacesizep.space()].write_qword_masked); + // call write_qword_masked +} + + +//------------------------------------------------- +// op_carry - process a CARRY opcode +//------------------------------------------------- + +void drcbe_x86::op_carry(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_no_condition(inst); + assert_flags(inst, FLAG_C); + + // normalize parameters + be_parameter srcp(*this, inst.param(0), PTYPE_MRI); + be_parameter bitp(*this, inst.param(1), PTYPE_MRI); + + // degenerate case: source is immediate + if (srcp.is_immediate() && bitp.is_immediate()) + { + if (srcp.immediate() & ((UINT64)1 << bitp.immediate())) + emit_stc(dst); + else + emit_clc(dst); + } + + // load non-immediate bit numbers into a register + if (!bitp.is_immediate()) + { + emit_mov_r32_p32(dst, REG_ECX, bitp); + emit_and_r32_imm(dst, REG_ECX, inst.size() * 8 - 1); + } + + // 32-bit form + if (inst.size() == 4) + { + if (bitp.is_immediate()) + { + if (srcp.is_memory()) + emit_bt_m32_imm(dst, MABS(srcp.memory()), bitp.immediate()); // bt [srcp],bitp + else if (srcp.is_int_register()) + emit_bt_r32_imm(dst, srcp.ireg(), bitp.immediate()); // bt srcp,bitp + } + else + { + if (srcp.is_memory()) + emit_bt_m32_r32(dst, MABS(srcp.memory()), REG_ECX); // bt [srcp],ecx + else if (srcp.is_int_register()) + emit_bt_r32_r32(dst, srcp.ireg(), REG_ECX); // bt [srcp],ecx + } + } + + // 64-bit form + else + { + if (bitp.is_immediate()) + { + if (srcp.is_memory()) + emit_bt_m32_imm(dst, MABS(srcp.memory()), bitp.immediate()); // bt [srcp],bitp + else if (srcp.is_int_register() && bitp.immediate() < 32) + emit_bt_r32_imm(dst, srcp.ireg(), bitp.immediate()); // bt srcp,bitp + else if (srcp.is_int_register() && bitp.immediate() >= 32) + emit_bt_m32_imm(dst, MABS(m_reghi[srcp.ireg()]), bitp.immediate() - 32); // bt [srcp.hi],bitp + } + else + { + if (srcp.is_memory()) + emit_bt_m32_r32(dst, MABS(srcp.memory()), REG_ECX); // bt [srcp],ecx + else if (srcp.is_int_register()) + { + emit_mov_m32_r32(dst, MABS(m_reglo[srcp.ireg()]), srcp.ireg()); // mov [srcp.lo],srcp + emit_bt_m32_r32(dst, MABS(m_reglo[srcp.ireg()]), REG_ECX); // bt [srcp],ecx + } + } + } +} + + +//------------------------------------------------- +// op_set - process a SET opcode +//------------------------------------------------- + +void drcbe_x86::op_set(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_any_condition(inst); + assert_no_flags(inst); + + // normalize parameters + be_parameter dstp(*this, inst.param(0), PTYPE_MR); + + // pick a target register for the general case + int dstreg = dstp.select_register(REG_EAX); + + // set to AL + emit_setcc_r8(dst, X86_CONDITION(inst.condition()), REG_AL); // setcc al + emit_movzx_r32_r8(dst, dstreg, REG_AL); // movzx dstreg,al + + // store low 32 bits + emit_mov_p32_r32(dst, dstp, dstreg); // mov dstp,dstreg + + // 64-bit form stores upper 32 bits + if (inst.size() == 8) + { + // general case + if (dstp.is_memory()) + emit_mov_m32_imm(dst, MABS(dstp.memory(4)), 0); // mov [dstp+4],0 + else if (dstp.is_int_register()) + emit_mov_m32_imm(dst, MABS(m_reghi[dstp.ireg()]), 0); // mov [reghi],0 + } +} + + +//------------------------------------------------- +// op_mov - process a MOV opcode +//------------------------------------------------- + +void drcbe_x86::op_mov(x86code *&dst, const instruction &inst) +{ + x86code *savedst = dst; + + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_any_condition(inst); + assert_no_flags(inst); + + // normalize parameters + be_parameter dstp(*this, inst.param(0), PTYPE_MR); + be_parameter srcp(*this, inst.param(1), PTYPE_MRI); + + // pick a target register for the general case + int dstreg = dstp.select_register(REG_EAX); + + // always start with a jmp + emit_link skip = { 0 }; + if (inst.condition() != uml::COND_ALWAYS) + emit_jcc_short_link(dst, X86_NOT_CONDITION(inst.condition()), skip); // jcc skip + + // 32-bit form + if (inst.size() == 4) + { + // register to memory + if (dstp.is_memory() && srcp.is_int_register()) + emit_mov_m32_r32(dst, MABS(dstp.memory()), srcp.ireg()); // mov [dstp],srcp + + // immediate to memory + else if (dstp.is_memory() && srcp.is_immediate()) + emit_mov_m32_imm(dst, MABS(dstp.memory()), srcp.immediate()); // mov [dstp],srcp + + // conditional memory to register + else if (inst.condition() != uml::COND_ALWAYS && dstp.is_int_register() && srcp.is_memory()) + { + dst = savedst; + skip.target = NULL; + emit_cmovcc_r32_m32(dst, X86_CONDITION(inst.condition()), dstp.ireg(), MABS(srcp.memory())); + // cmovcc dstp,[srcp] + } + + // conditional register to register + else if (inst.condition() != uml::COND_ALWAYS && dstp.is_int_register() && srcp.is_int_register()) + { + dst = savedst; + skip.target = NULL; + emit_cmovcc_r32_r32(dst, X86_CONDITION(inst.condition()), dstp.ireg(), srcp.ireg()); + // cmovcc dstp,srcp + } + + // general case + else + { + emit_mov_r32_p32_keepflags(dst, dstreg, srcp); // mov dstreg,srcp + emit_mov_p32_r32(dst, dstp, dstreg); // mov dstp,dstreg + } + } + + // 64-bit form + else if (inst.size() == 8) + { + // register to memory + if (dstp.is_memory() && srcp.is_int_register()) + { + emit_mov_r32_m32(dst, REG_EAX, MABS(m_reghi[srcp.ireg()])); // mov eax,reghi[srcp] + emit_mov_m32_r32(dst, MABS(dstp.memory()), srcp.ireg()); // mov [dstp],srcp + emit_mov_m32_r32(dst, MABS(dstp.memory(4)), REG_EAX); // mov [dstp+4],eax + } + + // immediate to memory + else if (dstp.is_memory() && srcp.is_immediate()) + { + emit_mov_m32_imm(dst, MABS(dstp.memory()), srcp.immediate()); // mov [dstp],srcp + emit_mov_m32_imm(dst, MABS(dstp.memory(4)), srcp.immediate() >> 32); // mov [dstp+4],srcp >> 32 + } + + // general case + else + { + emit_mov_r64_p64(dst, dstreg, REG_EDX, srcp); // mov edx:dstreg,srcp + emit_mov_p64_r64(dst, dstp, dstreg, REG_EDX); // mov dstp,edx:dstreg + } + } + + // resolve the jump + if (skip.target != NULL) + track_resolve_link(dst, skip); +} + + +//------------------------------------------------- +// op_sext - process a SEXT opcode +//------------------------------------------------- + +void drcbe_x86::op_sext(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_no_condition(inst); + assert_flags(inst, FLAG_S | FLAG_Z); + + // normalize parameters + be_parameter dstp(*this, inst.param(0), PTYPE_MR); + be_parameter srcp(*this, inst.param(1), PTYPE_MRI); + const parameter &sizep = inst.param(2); + assert(sizep.is_size()); + + // pick a target register for the general case + int dstreg = (inst.size() == 8) ? REG_EAX : dstp.select_register(REG_EAX); + + // convert 8-bit source registers to EAX + if (sizep.size() == SIZE_BYTE && srcp.is_int_register() && (srcp.ireg() & 4)) + { + emit_mov_r32_r32(dst, REG_EAX, srcp.ireg()); // mov eax,srcp + srcp = be_parameter::make_ireg(REG_EAX); + } + + // general case + if (srcp.is_memory()) + { + if (sizep.size() == SIZE_BYTE) + emit_movsx_r32_m8(dst, dstreg, MABS(srcp.memory())); // movsx dstreg,[srcp] + else if (sizep.size() == SIZE_WORD) + emit_movsx_r32_m16(dst, dstreg, MABS(srcp.memory())); // movsx dstreg,[srcp] + else if (sizep.size() == SIZE_DWORD) + emit_mov_r32_m32(dst, dstreg, MABS(srcp.memory())); // mov dstreg,[srcp] + } + else if (srcp.is_int_register()) + { + if (sizep.size() == SIZE_BYTE) + emit_movsx_r32_r8(dst, dstreg, srcp.ireg()); // movsx dstreg,srcp + else if (sizep.size() == SIZE_WORD) + emit_movsx_r32_r16(dst, dstreg, srcp.ireg()); // movsx dstreg,srcp + else if (sizep.size() == SIZE_DWORD && dstreg != srcp.ireg()) + emit_mov_r32_r32(dst, dstreg, srcp.ireg()); // mov dstreg,srcp + } + if (inst.flags() != 0) + emit_test_r32_r32(dst, dstreg, dstreg); // test dstreg,dstreg + + // 32-bit form: store the low 32 bits + if (inst.size() == 4) + emit_mov_p32_r32(dst, dstp, dstreg); // mov dstp,dstreg + + // 64-bit form: sign extend to 64 bits and store edx:eax + else if (inst.size() == 8) + { + emit_cdq(dst); // cdq + emit_mov_p64_r64(dst, dstp, REG_EAX, REG_EDX); // mov dstp,edx:eax + } +} + + +//------------------------------------------------- +// op_roland - process an ROLAND opcode +//------------------------------------------------- + +void drcbe_x86::op_roland(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_no_condition(inst); + assert_flags(inst, FLAG_S | FLAG_Z); + + // normalize parameters + be_parameter dstp(*this, inst.param(0), PTYPE_MR); + be_parameter srcp(*this, inst.param(1), PTYPE_MRI); + be_parameter shiftp(*this, inst.param(2), PTYPE_MRI); + be_parameter maskp(*this, inst.param(3), PTYPE_MRI); + + // pick a target register for the general case + int dstreg = dstp.select_register(REG_EAX, shiftp, maskp); + + // 32-bit form + if (inst.size() == 4) + { + emit_mov_r32_p32(dst, dstreg, srcp); // mov dstreg,srcp + emit_rol_r32_p32(dst, dstreg, shiftp, inst); // rol dstreg,shiftp + emit_and_r32_p32(dst, dstreg, maskp, inst); // and dstreg,maskp + emit_mov_p32_r32(dst, dstp, dstreg); // mov dstp,dstreg + } + + // 64-bit form + else if (inst.size() == 8) + { + emit_mov_r64_p64(dst, dstreg, REG_EDX, srcp); // mov edx:dstreg,srcp + emit_rol_r64_p64(dst, dstreg, REG_EDX, shiftp, inst); // rol edx:dstreg,shiftp + emit_and_r64_p64(dst, dstreg, REG_EDX, maskp, inst); // and edx:dstreg,maskp + emit_mov_p64_r64(dst, dstp, dstreg, REG_EDX); // mov dstp,edx:dstreg + } +} + + +//------------------------------------------------- +// op_rolins - process an ROLINS opcode +//------------------------------------------------- + +void drcbe_x86::op_rolins(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_no_condition(inst); + assert_flags(inst, FLAG_S | FLAG_Z); + + // normalize parameters + be_parameter dstp(*this, inst.param(0), PTYPE_MR); + be_parameter srcp(*this, inst.param(1), PTYPE_MRI); + be_parameter shiftp(*this, inst.param(2), PTYPE_MRI); + be_parameter maskp(*this, inst.param(3), PTYPE_MRI); + + // pick a target register for the general case + int dstreg = dstp.select_register(REG_ECX, shiftp, maskp); + + // 32-bit form + if (inst.size() == 4) + { + emit_mov_r32_p32(dst, REG_EAX, srcp); // mov eax,srcp + emit_rol_r32_p32(dst, REG_EAX, shiftp, inst); // rol eax,shiftp + emit_mov_r32_p32(dst, dstreg, dstp); // mov dstreg,dstp + if (maskp.is_immediate()) + { + emit_and_r32_imm(dst, REG_EAX, maskp.immediate()); // and eax,maskp + emit_and_r32_imm(dst, dstreg, ~maskp.immediate()); // and dstreg,~maskp + } + else + { + emit_mov_r32_p32(dst, REG_EDX, maskp); // mov edx,maskp + emit_and_r32_r32(dst, REG_EAX, REG_EDX); // and eax,edx + emit_not_r32(dst, REG_EDX); // not edx + emit_and_r32_r32(dst, dstreg, REG_EDX); // and dstreg,edx + } + emit_or_r32_r32(dst, dstreg, REG_EAX); // or dstreg,eax + emit_mov_p32_r32(dst, dstp, dstreg); // mov dstp,dstreg + } + + // 64-bit form + else if (inst.size() == 8) + { + emit_mov_r64_p64(dst, REG_EAX, REG_EDX, srcp); // mov edx:eax,srcp + emit_rol_r64_p64(dst, REG_EAX, REG_EDX, shiftp, inst); // rol edx:eax,shiftp + if (maskp.is_immediate()) + { + emit_and_r32_imm(dst, REG_EAX, maskp.immediate()); // and eax,maskp + emit_and_r32_imm(dst, REG_EDX, maskp.immediate() >> 32); // and edx,maskp >> 32 + if (dstp.is_int_register()) + { + emit_and_r32_imm(dst, dstp.ireg(), ~maskp.immediate()); // and dstp.lo,~maskp + emit_and_m32_imm(dst, MABS(m_reghi[dstp.ireg()]), ~maskp.immediate() >> 32);// and dstp.hi,~maskp >> 32 + emit_or_r32_r32(dst, dstp.ireg(), REG_EAX); // or dstp.lo,eax + emit_or_m32_r32(dst, MABS(m_reghi[dstp.ireg()]), REG_EDX); // or dstp.hi,edx + } + else + { + emit_and_m32_imm(dst, MABS(dstp.memory()), ~maskp.immediate()); // and dstp.lo,~maskp + emit_and_m32_imm(dst, MABS(dstp.memory(4)), ~maskp.immediate() >> 32); // and dstp.hi,~maskp >> 32 + emit_or_m32_r32(dst, MABS(dstp.memory()), REG_EAX); // or dstp.lo,eax + emit_or_m32_r32(dst, MABS(dstp.memory(4)), REG_EDX); // or dstp.hi,edx + } + } + else + { + int tempreg = REG_EBX; + emit_mov_m32_r32(dst, MBD(REG_ESP, -8), tempreg); // mov [esp-8],ebx + emit_mov_r64_p64(dst, tempreg, REG_ECX, maskp); // mov ecx:ebx,maskp + emit_and_r32_r32(dst, REG_EAX, tempreg); // and eax,ebx + emit_and_r32_r32(dst, REG_EDX, REG_ECX); // and edx,ecx + emit_not_r32(dst, tempreg); // not ebx + emit_not_r32(dst, REG_ECX); // not ecx + if (dstp.is_int_register()) + { + emit_and_r32_r32(dst, dstp.ireg(), tempreg); // and dstp.lo,ebx + emit_and_m32_r32(dst, MABS(m_reghi[dstp.ireg()]), REG_ECX); // and dstp.hi,ecx + emit_or_r32_r32(dst, dstp.ireg(), REG_EAX); // or dstp.lo,eax + emit_or_m32_r32(dst, MABS(m_reghi[dstp.ireg()]), REG_EDX); // or dstp.hi,edx + } + else + { + emit_and_m32_r32(dst, MABS(dstp.memory()), tempreg); // and dstp.lo,ebx + emit_and_m32_r32(dst, MABS(dstp.memory(4)), REG_ECX); // and dstp.hi,ecx + emit_or_m32_r32(dst, MABS(dstp.memory()), REG_EAX); // or dstp.lo,eax + emit_or_m32_r32(dst, MABS(dstp.memory(4)), REG_EDX); // or dstp.hi,edx + } + emit_mov_r32_m32(dst, tempreg, MBD(REG_ESP, -8)); // mov ebx,[esp-8] + } + if (inst.flags() == FLAG_Z) + emit_or_r32_r32(dst, REG_EAX, REG_EDX); // or eax,edx + else if (inst.flags() == FLAG_S) + ;// do nothing -- final OR will have the right result + else if (inst.flags() == (FLAG_Z | FLAG_S)) + { + emit_movzx_r32_r16(dst, REG_ECX, REG_AX); // movzx ecx,ax + emit_shr_r32_imm(dst, REG_EAX, 16); // shr eax,16 + emit_or_r32_r32(dst, REG_EDX, REG_ECX); // or edx,ecx + emit_or_r32_r32(dst, REG_EDX, REG_EAX); // or edx,eax + } + } +} + + +//------------------------------------------------- +// op_add - process a ADD opcode +//------------------------------------------------- + +void drcbe_x86::op_add(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_no_condition(inst); + assert_flags(inst, FLAG_C | FLAG_V | FLAG_Z | FLAG_S); + + // normalize parameters + be_parameter dstp(*this, inst.param(0), PTYPE_MR); + be_parameter src1p(*this, inst.param(1), PTYPE_MRI); + be_parameter src2p(*this, inst.param(2), PTYPE_MRI); + normalize_commutative(src1p, src2p); + + // pick a target register for the general case + int dstreg = dstp.select_register(REG_EAX, src2p); + + // 32-bit form + if (inst.size() == 4) + { + // dstp == src1p in memory + if (dstp.is_memory() && dstp == src1p) + emit_add_m32_p32(dst, MABS(dstp.memory()), src2p, inst); // add [dstp],src2p + + // reg = reg + imm + else if (dstp.is_int_register() && src1p.is_int_register() && src2p.is_immediate() && inst.flags() == 0) + emit_lea_r32_m32(dst, dstp.ireg(), MBD(src1p.ireg(), src2p.immediate())); // lea dstp,[src1p+src2p] + + // reg = reg + reg + else if (dstp.is_int_register() && src1p.is_int_register() && src2p.is_int_register() && inst.flags() == 0) + emit_lea_r32_m32(dst, dstp.ireg(), MBISD(src1p.ireg(), src2p.ireg(), 1, 0)); // lea dstp,[src1p+src2p] + + // general case + else + { + emit_mov_r32_p32(dst, dstreg, src1p); // mov dstreg,src1p + emit_add_r32_p32(dst, dstreg, src2p, inst); // add dstreg,src2p + emit_mov_p32_r32(dst, dstp, dstreg); // mov dstp,dstreg + } + } + + // 64-bit form + else if (inst.size() == 8) + { + // dstp == src1p in memory + if (dstp.is_memory() && dstp == src1p) + emit_add_m64_p64(dst, MABS(dstp.memory()), src2p, inst); // add [dstp],src2p + + // general case + else + { + emit_mov_r64_p64(dst, dstreg, REG_EDX, src1p); // mov dstreg:dstp,[src1p] + emit_add_r64_p64(dst, dstreg, REG_EDX, src2p, inst); // add dstreg:dstp,src2p + emit_mov_p64_r64(dst, dstp, dstreg, REG_EDX); // mov dstp,dstreg:eax + } + } +} + + +//------------------------------------------------- +// op_addc - process a ADDC opcode +//------------------------------------------------- + +void drcbe_x86::op_addc(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_no_condition(inst); + assert_flags(inst, FLAG_C | FLAG_V | FLAG_Z | FLAG_S); + + // normalize parameters + be_parameter dstp(*this, inst.param(0), PTYPE_MR); + be_parameter src1p(*this, inst.param(1), PTYPE_MRI); + be_parameter src2p(*this, inst.param(2), PTYPE_MRI); + normalize_commutative(src1p, src2p); + + // pick a target register for the general case + int dstreg = dstp.select_register(REG_EAX, src2p); + + // 32-bit form + if (inst.size() == 4) + { + // dstp == src1p in memory + if (dstp.is_memory() && dstp == src1p) + emit_adc_m32_p32(dst, MABS(dstp.memory()), src2p, inst); // adc [dstp],src2p + + // general case + else + { + emit_mov_r32_p32_keepflags(dst, dstreg, src1p); // mov dstreg,src1p + emit_adc_r32_p32(dst, dstreg, src2p, inst); // adc dstreg,src2p + emit_mov_p32_r32(dst, dstp, dstreg); // mov dstp,dstreg + } + } + + // 64-bit form + else if (inst.size() == 8) + { + // dstp == src1p in memory + if (dstp.is_memory() && dstp == src1p) + emit_adc_m64_p64(dst, MABS(dstp.memory()), src2p, inst); // adc [dstp],src2p + + // general case + else + { + emit_mov_r64_p64_keepflags(dst, dstreg, REG_EDX, src1p); // mov dstreg:dstp,[src1p] + emit_adc_r64_p64(dst, dstreg, REG_EDX, src2p, inst); // adc dstreg:dstp,src2p + emit_mov_p64_r64(dst, dstp, dstreg, REG_EDX); // mov dstp,dstreg:eax + } + } +} + + +//------------------------------------------------- +// op_sub - process a SUB opcode +//------------------------------------------------- + +void drcbe_x86::op_sub(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_no_condition(inst); + assert_flags(inst, FLAG_C | FLAG_V | FLAG_Z | FLAG_S); + + // normalize parameters + be_parameter dstp(*this, inst.param(0), PTYPE_MR); + be_parameter src1p(*this, inst.param(1), PTYPE_MRI); + be_parameter src2p(*this, inst.param(2), PTYPE_MRI); + + // pick a target register for the general case + int dstreg = dstp.select_register(REG_EAX, src2p); + + // 32-bit form + if (inst.size() == 4) + { + // dstp == src1p in memory + if (dstp.is_memory() && dstp == src1p) + emit_sub_m32_p32(dst, MABS(dstp.memory()), src2p, inst); // sub [dstp],src2p + + // reg = reg - imm + else if (dstp.is_int_register() && src1p.is_int_register() && src2p.is_immediate() && inst.flags() == 0) + emit_lea_r32_m32(dst, dstp.ireg(), MBD(src1p.ireg(), -src2p.immediate())); // lea dstp,[src1p-src2p] + + // general case + else + { + emit_mov_r32_p32(dst, dstreg, src1p); // mov dstreg,src1p + emit_sub_r32_p32(dst, dstreg, src2p, inst); // sub dstreg,src2p + emit_mov_p32_r32(dst, dstp, dstreg); // mov dstp,dstreg + } + } + + // 64-bit form + else if (inst.size() == 8) + { + // dstp == src1p in memory + if (dstp.is_memory() && dstp == src1p) + emit_sub_m64_p64(dst, MABS(dstp.memory()), src2p, inst); // sub [dstp],src2p + + // general case + else + { + emit_mov_r64_p64(dst, dstreg, REG_EDX, src1p); // mov dstreg:dstp,[src1p] + emit_sub_r64_p64(dst, dstreg, REG_EDX, src2p, inst); // sub dstreg:dstp,src2p + emit_mov_p64_r64(dst, dstp, dstreg, REG_EDX); // mov dstp,dstreg:eax + } + } +} + + +//------------------------------------------------- +// op_subc - process a SUBC opcode +//------------------------------------------------- + +void drcbe_x86::op_subc(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_no_condition(inst); + assert_flags(inst, FLAG_C | FLAG_V | FLAG_Z | FLAG_S); + + // normalize parameters + be_parameter dstp(*this, inst.param(0), PTYPE_MR); + be_parameter src1p(*this, inst.param(1), PTYPE_MRI); + be_parameter src2p(*this, inst.param(2), PTYPE_MRI); + + // pick a target register for the general case + int dstreg = dstp.select_register(REG_EAX, src2p); + + // 32-bit form + if (inst.size() == 4) + { + // dstp == src1p in memory + if (dstp.is_memory() && dstp == src1p) + emit_sbb_m32_p32(dst, MABS(dstp.memory()), src2p, inst); // sbb [dstp],src2p + + // general case + else + { + emit_mov_r32_p32_keepflags(dst, dstreg, src1p); // mov dstreg,src1p + emit_sbb_r32_p32(dst, dstreg, src2p, inst); // sbb dstreg,src2p + emit_mov_p32_r32(dst, dstp, dstreg); // mov dstp,dstreg + } + } + + // 64-bit form + else if (inst.size() == 8) + { + // dstp == src1p in memory + if (dstp.is_memory() && dstp == src1p) + emit_sbb_m64_p64(dst, MABS(dstp.memory()), src2p, inst); // sbb [dstp],src2p + + // general case + else + { + emit_mov_r64_p64_keepflags(dst, dstreg, REG_EDX, src1p); // mov dstreg:dstp,[src1p] + emit_sbb_r64_p64(dst, dstreg, REG_EDX, src2p, inst); // sbb dstreg:dstp,src2p + emit_mov_p64_r64(dst, dstp, dstreg, REG_EDX); // mov dstp,dstreg:eax + } + } +} + + +//------------------------------------------------- +// op_cmp - process a CMP opcode +//------------------------------------------------- + +void drcbe_x86::op_cmp(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_no_condition(inst); + assert_flags(inst, FLAG_C | FLAG_V | FLAG_Z | FLAG_S); + + // normalize parameters + be_parameter src1p(*this, inst.param(0), PTYPE_MRI); + be_parameter src2p(*this, inst.param(1), PTYPE_MRI); + + // pick a target register for the general case + int src1reg = src1p.select_register(REG_EAX); + + // 32-bit form + if (inst.size() == 4) + { + // memory versus anything + if (src1p.is_memory()) + emit_cmp_m32_p32(dst, MABS(src1p.memory()), src2p, inst); // cmp [dstp],src2p + + // general case + else + { + if (src1p.is_immediate()) + emit_mov_r32_imm(dst, src1reg, src1p.immediate()); // mov src1reg,imm + emit_cmp_r32_p32(dst, src1reg, src2p, inst); // cmp src1reg,src2p + } + } + + // 64-bit form + else + { + // general case + emit_mov_r64_p64(dst, REG_EAX, REG_EDX, src1p); // mov eax:dstp,[src1p] + emit_cmp_r64_p64(dst, REG_EAX, REG_EDX, src2p, inst); // cmp eax:dstp,src2p + } +} + + +//------------------------------------------------- +// op_mulu - process a MULU opcode +//------------------------------------------------- + +void drcbe_x86::op_mulu(x86code *&dst, const instruction &inst) +{ + UINT8 zsflags = inst.flags() & (FLAG_Z | FLAG_S); + UINT8 vflag = inst.flags() & FLAG_V; + + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_no_condition(inst); + assert_flags(inst, FLAG_V | FLAG_Z | FLAG_S); + + // normalize parameters + be_parameter dstp(*this, inst.param(0), PTYPE_MR); + be_parameter edstp(*this, inst.param(1), PTYPE_MR); + be_parameter src1p(*this, inst.param(2), PTYPE_MRI); + be_parameter src2p(*this, inst.param(3), PTYPE_MRI); + normalize_commutative(src1p, src2p); + bool compute_hi = (dstp != edstp); + + // 32-bit form + if (inst.size() == 4) + { + // general case + emit_mov_r32_p32(dst, REG_EAX, src1p); // mov eax,src1p + if (src2p.is_memory()) + emit_mul_m32(dst, MABS(src2p.memory())); // mul [src2p] + else if (src2p.is_int_register()) + emit_mul_r32(dst, src2p.ireg()); // mul src2p + else if (src2p.is_immediate()) + { + emit_mov_r32_imm(dst, REG_EDX, src2p.immediate()); // mov edx,src2p + emit_mul_r32(dst, REG_EDX); // mul edx + } + emit_mov_p32_r32(dst, dstp, REG_EAX); // mov dstp,eax + if (compute_hi) + emit_mov_p32_r32(dst, edstp, REG_EDX); // mov edstp,edx + + // compute flags + if (inst.flags() != 0) + { + if (zsflags != 0) + { + if (vflag) + emit_pushf(dst); // pushf + if (compute_hi) + { + if (zsflags == FLAG_Z) + emit_or_r32_r32(dst, REG_EDX, REG_EAX); // or edx,eax + else if (zsflags == FLAG_S) + emit_test_r32_r32(dst, REG_EDX, REG_EDX); // test edx,edx + else + { + emit_movzx_r32_r16(dst, REG_ECX, REG_AX); // movzx ecx,ax + emit_shr_r32_imm(dst, REG_EAX, 16); // shr eax,16 + emit_or_r32_r32(dst, REG_EDX, REG_ECX); // or edx,ecx + emit_or_r32_r32(dst, REG_EDX, REG_EAX); // or edx,eax + } + } + else + emit_test_r32_r32(dst, REG_EAX, REG_EAX); // test eax,eax + + // we rely on the fact that OF is cleared by all logical operations above + if (vflag) + { + emit_pushf(dst); // pushf + emit_pop_r32(dst, REG_EAX); // pop eax + emit_and_m32_imm(dst, MBD(REG_ESP, 0), ~0x84); // and [esp],~0x84 + emit_or_m32_r32(dst, MBD(REG_ESP, 0), REG_EAX); // or [esp],eax + emit_popf(dst); // popf + } + } + } + } + + // 64-bit form + else if (inst.size() == 8) + { + // general case + emit_mov_m32_imm(dst, MBD(REG_ESP, 24), inst.flags()); // mov [esp+24],flags + emit_mov_m64_p64(dst, MBD(REG_ESP, 16), src2p); // mov [esp+16],src2p + emit_mov_m64_p64(dst, MBD(REG_ESP, 8), src1p); // mov [esp+8],src1p + if (!compute_hi) + emit_mov_m32_imm(dst, MBD(REG_ESP, 4), (FPTR)&m_reslo); // mov [esp+4],&reslo + else + emit_mov_m32_imm(dst, MBD(REG_ESP, 4), (FPTR)&m_reshi); // mov [esp+4],&reshi + emit_mov_m32_imm(dst, MBD(REG_ESP, 0), (FPTR)&m_reslo); // mov [esp],&reslo + emit_call(dst, (x86code *)dmulu); // call dmulu + if (inst.flags() != 0) + emit_push_m32(dst, MABSI(flags_unmap, REG_EAX, 4)); // push flags_unmap[eax*4] + emit_mov_r32_m32(dst, REG_EAX, MABS((UINT32 *)&m_reslo + 0)); // mov eax,reslo.lo + emit_mov_r32_m32(dst, REG_EDX, MABS((UINT32 *)&m_reslo + 1)); // mov edx,reslo.hi + emit_mov_p64_r64(dst, dstp, REG_EAX, REG_EDX); // mov dstp,edx:eax + if (compute_hi) + { + emit_mov_r32_m32(dst, REG_EAX, MABS((UINT32 *)&m_reshi + 0)); // mov eax,reshi.lo + emit_mov_r32_m32(dst, REG_ECX, MABS((UINT32 *)&m_reshi + 1)); // mov ecx,reshi.hi + emit_mov_p64_r64(dst, edstp, REG_EAX, REG_ECX); // mov edstp,ecx:eax + } + if (inst.flags() != 0) + emit_popf(dst); // popf + } +} + + +//------------------------------------------------- +// op_muls - process a MULS opcode +//------------------------------------------------- + +void drcbe_x86::op_muls(x86code *&dst, const instruction &inst) +{ + UINT8 zsflags = inst.flags() & (FLAG_Z | FLAG_S); + UINT8 vflag = inst.flags() & FLAG_V; + + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_no_condition(inst); + assert_flags(inst, FLAG_V | FLAG_Z | FLAG_S); + + // normalize parameters + be_parameter dstp(*this, inst.param(0), PTYPE_MR); + be_parameter edstp(*this, inst.param(1), PTYPE_MR); + be_parameter src1p(*this, inst.param(2), PTYPE_MRI); + be_parameter src2p(*this, inst.param(3), PTYPE_MRI); + normalize_commutative(src1p, src2p); + bool compute_hi = (dstp != edstp); + + // 32-bit form + if (inst.size() == 4) + { + // 32-bit destination with memory/immediate or register/immediate + if (!compute_hi && !src1p.is_immediate() && src2p.is_immediate()) + { + if (src1p.is_memory()) + emit_imul_r32_m32_imm(dst, REG_EAX, MABS(src1p.memory()), src2p.immediate()); // imul eax,[src1p],src2p + else if (src1p.is_int_register()) + emit_imul_r32_r32_imm(dst, REG_EAX, src1p.ireg(), src2p.immediate()); // imul eax,src1p,src2p + emit_mov_p32_r32(dst, dstp, REG_EAX); // mov dstp,eax + } + + // 32-bit destination, general case + else if (!compute_hi) + { + emit_mov_r32_p32(dst, REG_EAX, src1p); // mov eax,src1p + if (src2p.is_memory()) + emit_imul_r32_m32(dst, REG_EAX, MABS(src2p.memory())); // imul eax,[src2p] + else if (src2p.is_int_register()) + emit_imul_r32_r32(dst, REG_EAX, src2p.ireg()); // imul eax,src2p + emit_mov_p32_r32(dst, dstp, REG_EAX); // mov dstp,eax + } + + // 64-bit destination, general case + else + { + emit_mov_r32_p32(dst, REG_EAX, src1p); // mov eax,src1p + if (src2p.is_memory()) + emit_imul_m32(dst, MABS(src2p.memory())); // imul [src2p] + else if (src2p.is_int_register()) + emit_imul_r32(dst, src2p.ireg()); // imul src2p + else if (src2p.is_immediate()) + { + emit_mov_r32_imm(dst, REG_EDX, src2p.immediate()); // mov edx,src2p + emit_imul_r32(dst, REG_EDX); // imul edx + } + emit_mov_p32_r32(dst, dstp, REG_EAX); // mov dstp,eax + emit_mov_p32_r32(dst, edstp, REG_EDX); // mov edstp,edx + } + + // compute flags + if (inst.flags() != 0) + { + if (zsflags != 0) + { + if (vflag) + emit_pushf(dst); // pushf + if (compute_hi) + { + if (inst.flags() == FLAG_Z) + emit_or_r32_r32(dst, REG_EDX, REG_EAX); // or edx,eax + else if (inst.flags() == FLAG_S) + emit_test_r32_r32(dst, REG_EDX, REG_EDX); // test edx,edx + else + { + emit_movzx_r32_r16(dst, REG_ECX, REG_AX); // movzx ecx,ax + emit_shr_r32_imm(dst, REG_EAX, 16); // shr eax,16 + emit_or_r32_r32(dst, REG_EDX, REG_ECX); // or edx,ecx + emit_or_r32_r32(dst, REG_EDX, REG_EAX); // or edx,eax + } + } + else + emit_test_r32_r32(dst, REG_EAX, REG_EAX); // test eax,eax + + // we rely on the fact that OF is cleared by all logical operations above + if (vflag) + { + emit_pushf(dst); // pushf + emit_pop_r32(dst, REG_EAX); // pop eax + emit_and_m32_imm(dst, MBD(REG_ESP, 0), ~0x84); // and [esp],~0x84 + emit_or_m32_r32(dst, MBD(REG_ESP, 0), REG_EAX); // or [esp],eax + emit_popf(dst); // popf + } + } + } + } + + // 64-bit form + else if (inst.size() == 8) + { + // general case + emit_mov_m32_imm(dst, MBD(REG_ESP, 24), inst.flags()); // mov [esp+24],flags + emit_mov_m64_p64(dst, MBD(REG_ESP, 16), src2p); // mov [esp+16],src2p + emit_mov_m64_p64(dst, MBD(REG_ESP, 8), src1p); // mov [esp+8],src1p + if (!compute_hi) + emit_mov_m32_imm(dst, MBD(REG_ESP, 4), (FPTR)&m_reslo); // mov [esp+4],&reslo + else + emit_mov_m32_imm(dst, MBD(REG_ESP, 4), (FPTR)&m_reshi); // push [esp+4],&reshi + emit_mov_m32_imm(dst, MBD(REG_ESP, 0), (FPTR)&m_reslo); // mov [esp],&reslo + emit_call(dst, (x86code *)dmuls); // call dmuls + if (inst.flags() != 0) + emit_push_m32(dst, MABSI(flags_unmap, REG_EAX, 4)); // push flags_unmap[eax*4] + emit_mov_r32_m32(dst, REG_EAX, MABS((UINT32 *)&m_reslo + 0)); // mov eax,reslo.lo + emit_mov_r32_m32(dst, REG_EDX, MABS((UINT32 *)&m_reslo + 1)); // mov edx,reslo.hi + emit_mov_p64_r64(dst, dstp, REG_EAX, REG_EDX); // mov dstp,edx:eax + if (compute_hi) + { + emit_mov_r32_m32(dst, REG_EAX, MABS((UINT32 *)&m_reshi + 0)); // mov eax,reshi.lo + emit_mov_r32_m32(dst, REG_EDX, MABS((UINT32 *)&m_reshi + 1)); // mov edx,reshi.hi + emit_mov_p64_r64(dst, edstp, REG_EAX, REG_EDX); // mov edstp,edx:eax + } + if (inst.flags() != 0) + emit_popf(dst); // popf + } +} + + +//------------------------------------------------- +// op_divu - process a DIVU opcode +//------------------------------------------------- + +void drcbe_x86::op_divu(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_no_condition(inst); + assert_flags(inst, FLAG_V | FLAG_Z | FLAG_S); + + // normalize parameters + be_parameter dstp(*this, inst.param(0), PTYPE_MR); + be_parameter edstp(*this, inst.param(1), PTYPE_MR); + be_parameter src1p(*this, inst.param(2), PTYPE_MRI); + be_parameter src2p(*this, inst.param(3), PTYPE_MRI); + bool compute_rem = (dstp != edstp); + + // 32-bit form + if (inst.size() == 4) + { + // general case + emit_mov_r32_p32(dst, REG_ECX, src2p); // mov ecx,src2p + if (inst.flags() != 0) + { + emit_mov_r32_imm(dst, REG_EAX, 0xa0000000); // mov eax,0xa0000000 + emit_add_r32_r32(dst, REG_EAX, REG_EAX); // add eax,eax + } + emit_link skip; + emit_jecxz_link(dst, skip); // jecxz skip + emit_mov_r32_p32(dst, REG_EAX, src1p); // mov eax,src1p + emit_xor_r32_r32(dst, REG_EDX, REG_EDX); // xor edx,edx + emit_div_r32(dst, REG_ECX); // div ecx + emit_mov_p32_r32(dst, dstp, REG_EAX); // mov dstp,eax + if (compute_rem) + emit_mov_p32_r32(dst, edstp, REG_EDX); // mov edstp,edx + if (inst.flags() != 0) + emit_test_r32_r32(dst, REG_EAX, REG_EAX); // test eax,eax + track_resolve_link(dst, skip); // skip: + } + + // 64-bit form + else if (inst.size() == 8) + { + // general case + emit_mov_m64_p64(dst, MBD(REG_ESP, 16), src2p); // mov [esp+16],src2p + emit_mov_m64_p64(dst, MBD(REG_ESP, 8), src1p); // mov [esp+8],src1p + if (!compute_rem) + emit_mov_m32_imm(dst, MBD(REG_ESP, 4), (FPTR)&m_reslo); // mov [esp+4],&reslo + else + emit_mov_m32_imm(dst, MBD(REG_ESP, 4), (FPTR)&m_reshi); // push [esp+4],&reshi + emit_mov_m32_imm(dst, MBD(REG_ESP, 0), (FPTR)&m_reslo); // mov [esp],&reslo + emit_call(dst, (x86code *)ddivu); // call ddivu + if (inst.flags() != 0) + emit_push_m32(dst, MABSI(flags_unmap, REG_EAX, 4)); // push flags_unmap[eax*4] + emit_mov_r32_m32(dst, REG_EAX, MABS((UINT32 *)&m_reslo + 0)); // mov eax,reslo.lo + emit_mov_r32_m32(dst, REG_EDX, MABS((UINT32 *)&m_reslo + 1)); // mov edx,reslo.hi + emit_mov_p64_r64(dst, dstp, REG_EAX, REG_EDX); // mov dstp,edx:eax + if (compute_rem) + { + emit_mov_r32_m32(dst, REG_EAX, MABS((UINT32 *)&m_reshi + 0)); // mov eax,reshi.lo + emit_mov_r32_m32(dst, REG_EDX, MABS((UINT32 *)&m_reshi + 1)); // mov edx,reshi.hi + emit_mov_p64_r64(dst, edstp, REG_EAX, REG_EDX); // mov edstp,edx:eax + } + if (inst.flags() != 0) + emit_popf(dst); // popf + } +} + + +//------------------------------------------------- +// op_divs - process a DIVS opcode +//------------------------------------------------- + +void drcbe_x86::op_divs(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_no_condition(inst); + assert_flags(inst, FLAG_V | FLAG_Z | FLAG_S); + + // normalize parameters + be_parameter dstp(*this, inst.param(0), PTYPE_MR); + be_parameter edstp(*this, inst.param(1), PTYPE_MR); + be_parameter src1p(*this, inst.param(2), PTYPE_MRI); + be_parameter src2p(*this, inst.param(3), PTYPE_MRI); + bool compute_rem = (dstp != edstp); + + // 32-bit form + if (inst.size() == 4) + { + // general case + emit_mov_r32_p32(dst, REG_ECX, src2p); // mov ecx,src2p + if (inst.flags() != 0) + { + emit_mov_r32_imm(dst, REG_EAX, 0xa0000000); // mov eax,0xa0000000 + emit_add_r32_r32(dst, REG_EAX, REG_EAX); // add eax,eax + } + emit_link skip; + emit_jecxz_link(dst, skip); // jecxz skip + emit_mov_r32_p32(dst, REG_EAX, src1p); // mov eax,src1p + emit_cdq(dst); // cdq + emit_idiv_r32(dst, REG_ECX); // idiv ecx + emit_mov_p32_r32(dst, dstp, REG_EAX); // mov dstp,eax + if (compute_rem) + emit_mov_p32_r32(dst, edstp, REG_EDX); // mov edstp,edx + if (inst.flags() != 0) + emit_test_r32_r32(dst, REG_EAX, REG_EAX); // test eax,eax + track_resolve_link(dst, skip); // skip: + } + + // 64-bit form + else if (inst.size() == 8) + { + // general case + emit_mov_m64_p64(dst, MBD(REG_ESP, 16), src2p); // mov [esp+16],src2p + emit_mov_m64_p64(dst, MBD(REG_ESP, 8), src1p); // mov [esp+8],src1p + if (!compute_rem) + emit_mov_m32_imm(dst, MBD(REG_ESP, 4), (FPTR)&m_reslo); // mov [esp+4],&reslo + else + emit_mov_m32_imm(dst, MBD(REG_ESP, 4), (FPTR)&m_reshi); // push [esp+4],&reshi + emit_mov_m32_imm(dst, MBD(REG_ESP, 0), (FPTR)&m_reslo); // mov [esp],&reslo + emit_call(dst, (x86code *)ddivs); // call ddivs + if (inst.flags() != 0) + emit_push_m32(dst, MABSI(flags_unmap, REG_EAX, 4)); // push flags_unmap[eax*4] + emit_mov_r32_m32(dst, REG_EAX, MABS((UINT32 *)&m_reslo + 0)); // mov eax,reslo.lo + emit_mov_r32_m32(dst, REG_EDX, MABS((UINT32 *)&m_reslo + 1)); // mov edx,reslo.hi + emit_mov_p64_r64(dst, dstp, REG_EAX, REG_EDX); // mov dstp,edx:eax + if (compute_rem) + { + emit_mov_r32_m32(dst, REG_EAX, MABS((UINT32 *)&m_reshi + 0)); // mov eax,reshi.lo + emit_mov_r32_m32(dst, REG_EDX, MABS((UINT32 *)&m_reshi + 1)); // mov edx,reshi.hi + emit_mov_p64_r64(dst, edstp, REG_EAX, REG_EDX); // mov edstp,edx:eax + } + if (inst.flags() != 0) + emit_popf(dst); // popf + } +} + + +//------------------------------------------------- +// op_and - process a AND opcode +//------------------------------------------------- + +void drcbe_x86::op_and(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_no_condition(inst); + assert_flags(inst, FLAG_Z | FLAG_S); + + // normalize parameters + be_parameter dstp(*this, inst.param(0), PTYPE_MR); + be_parameter src1p(*this, inst.param(1), PTYPE_MRI); + be_parameter src2p(*this, inst.param(2), PTYPE_MRI); + normalize_commutative(src1p, src2p); + + // pick a target register for the general case + int dstreg = dstp.select_register(REG_EAX, src2p); + + // 32-bit form + if (inst.size() == 4) + { + // dstp == src1p in memory + if (dstp.is_memory() && dstp == src1p) + emit_and_m32_p32(dst, MABS(dstp.memory()), src2p, inst); // and [dstp],src2p + + // AND with immediate 0xff + else if (src2p.is_immediate_value(0xff) && inst.flags() == 0) + { + if (src1p.is_int_register()) + emit_movzx_r32_r8(dst, dstreg, src1p.ireg()); // movzx dstreg,src1p + else if (src1p.is_memory()) + emit_movzx_r32_m8(dst, dstreg, MABS(src1p.memory())); // movzx dstreg,[src1p] + emit_mov_p32_r32(dst, dstp, dstreg); // mov dstp,dstreg + } + + // AND with immediate 0xffff + else if (src2p.is_immediate_value(0xffff) && inst.flags() == 0) + { + if (src1p.is_int_register()) + emit_movzx_r32_r16(dst, dstreg, src1p.ireg()); // movzx dstreg,src1p + else if (src1p.is_memory()) + emit_movzx_r32_m16(dst, dstreg, MABS(src1p.memory())); // movzx dstreg,[src1p] + emit_mov_p32_r32(dst, dstp, dstreg); // mov dstp,dstreg + } + + // general case + else + { + emit_mov_r32_p32(dst, dstreg, src1p); // mov dstreg,src1p + emit_and_r32_p32(dst, dstreg, src2p, inst); // and dstreg,src2p + emit_mov_p32_r32(dst, dstp, dstreg); // mov dstp,dstreg + } + } + + // 64-bit form + else if (inst.size() == 8) + { + // dstp == src1p in memory + if (dstp.is_memory() && dstp == src1p) + emit_and_m64_p64(dst, MABS(dstp.memory()), src2p, inst); // and [dstp],src2p + + // AND with immediate 0xff + else if (src2p.is_immediate_value(0xff) && inst.flags() == 0) + { + if (src1p.is_int_register()) + emit_movzx_r32_r8(dst, dstreg, src1p.ireg()); // movzx dstreg,src1p + else if (src1p.is_memory()) + emit_movzx_r32_m8(dst, dstreg, MABS(src1p.memory())); // movzx dstreg,[src1p] + emit_mov_p32_r32(dst, dstp, dstreg); // mov dstp,dstreg + if (dstp.is_int_register()) + emit_mov_m32_imm(dst, MABS(m_reghi[dstp.ireg()]), 0); // mov dsthi,0 + else if (dstp.is_memory()) + emit_mov_m32_imm(dst, MABS(dstp.memory(4)), 0); // mov dsthi,0 + } + + // AND with immediate 0xffff + else if (src2p.is_immediate_value(0xffff) && inst.flags() == 0) + { + if (src1p.is_int_register()) + emit_movzx_r32_r16(dst, dstreg, src1p.ireg()); // movzx dstreg,src1p + else if (src1p.is_memory()) + emit_movzx_r32_m16(dst, dstreg, MABS(src1p.memory())); // movzx dstreg,[src1p] + emit_mov_p32_r32(dst, dstp, dstreg); // mov dstp,dstreg + if (dstp.is_int_register()) + emit_mov_m32_imm(dst, MABS(m_reghi[dstp.ireg()]), 0); // mov dsthi,0 + else if (dstp.is_memory()) + emit_mov_m32_imm(dst, MABS(dstp.memory(4)), 0); // mov dsthi,0 + } + + // AND with immediate 0xffffffff + else if (src2p.is_immediate_value(0xffffffff) && inst.flags() == 0) + { + emit_mov_r32_p32(dst, dstreg, src1p); // mov dstreg,src1p + emit_mov_p32_r32(dst, dstp, dstreg); // mov dstp,dstreg + if (dstp.is_int_register()) + emit_mov_m32_imm(dst, MABS(m_reghi[dstp.ireg()]), 0); // mov dsthi,0 + else if (dstp.is_memory()) + emit_mov_m32_imm(dst, MABS(dstp.memory(4)), 0); // mov dsthi,0 + } + + // AND with immediate 0xffffffff00000000 + else if (src2p.is_immediate_value(U64(0xffffffff00000000)) && inst.flags() == 0) + { + if (src1p != dstp) + { + emit_mov_r64_p64(dst, REG_NONE, REG_EDX, src1p); // mov dstreg,src1p + emit_mov_p64_r64(dst, dstp, REG_NONE, REG_EDX); // mov dstp,dstreg + } + if (dstp.is_int_register()) + emit_xor_r32_r32(dst, dstp.ireg(), dstp.ireg()); // xor dstlo,dstlo + else if (dstp.is_memory()) + emit_mov_m32_imm(dst, MABS(dstp.memory()), 0); // mov dstlo,0 + } + + // AND with immediate <= 0xffffffff + else if (src2p.is_immediate() && src2p.immediate() <= 0xffffffff && inst.flags() == 0) + { + emit_mov_r32_p32(dst, dstreg, src1p); // mov dstreg,src1p + emit_and_r32_p32(dst, dstreg, src2p, inst); // and dstreg,src2p + emit_mov_p32_r32(dst, dstp, dstreg); // mov dstp,dstreg + if (dstp.is_int_register()) + emit_mov_m32_imm(dst, MABS(m_reghi[dstp.ireg()]), 0); // mov dsthi,0 + else if (dstp.is_memory()) + emit_mov_m32_imm(dst, MABS(dstp.memory(4)), 0); // mov dsthi,0 + } + + // general case + else + { + emit_mov_r64_p64(dst, dstreg, REG_EDX, src1p); // mov dstreg:dstp,[src1p] + emit_and_r64_p64(dst, dstreg, REG_EDX, src2p, inst); // and dstreg:dstp,src2p + emit_mov_p64_r64(dst, dstp, dstreg, REG_EDX); // mov dstp,dstreg:eax + } + } +} + + +//------------------------------------------------- +// op_test - process a TEST opcode +//------------------------------------------------- + +void drcbe_x86::op_test(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_no_condition(inst); + assert_flags(inst, FLAG_Z | FLAG_S); + + // normalize parameters + be_parameter src1p(*this, inst.param(0), PTYPE_MRI); + be_parameter src2p(*this, inst.param(1), PTYPE_MRI); + normalize_commutative(src1p, src2p); + + // pick a target register for the general case + int src1reg = src1p.select_register(REG_EAX); + + // 32-bit form + if (inst.size() == 4) + { + // src1p in memory + if (src1p.is_memory()) + emit_test_m32_p32(dst, MABS(src1p.memory()), src2p, inst); // test [src1p],src2p + + // general case + else + { + emit_mov_r32_p32(dst, src1reg, src1p); // mov src1reg,src1p + emit_test_r32_p32(dst, src1reg, src2p, inst); // test src1reg,src2p + } + } + + // 64-bit form + else if (inst.size() == 8) + { + // src1p in memory + if (src1p.is_memory()) + emit_test_m64_p64(dst, MABS(src1p.memory()), src2p, inst); // test [dstp],src2p + + // general case + else + { + emit_mov_r64_p64(dst, src1reg, REG_EDX, src1p); // mov src1reg:dstp,[src1p] + emit_test_r64_p64(dst, src1reg, REG_EDX, src2p, inst); // test src1reg:dstp,src2p + } + } +} + + +//------------------------------------------------- +// op_or - process a OR opcode +//------------------------------------------------- + +void drcbe_x86::op_or(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_no_condition(inst); + assert_flags(inst, FLAG_Z | FLAG_S); + + // normalize parameters + be_parameter dstp(*this, inst.param(0), PTYPE_MR); + be_parameter src1p(*this, inst.param(1), PTYPE_MRI); + be_parameter src2p(*this, inst.param(2), PTYPE_MRI); + normalize_commutative(src1p, src2p); + + // pick a target register for the general case + int dstreg = dstp.select_register(REG_EAX, src2p); + + // 32-bit form + if (inst.size() == 4) + { + // dstp == src1p in memory + if (dstp.is_memory() && dstp == src1p) + emit_or_m32_p32(dst, MABS(dstp.memory()), src2p, inst); // or [dstp],src2p + + // general case + else + { + emit_mov_r32_p32(dst, dstreg, src1p); // mov dstreg,src1p + emit_or_r32_p32(dst, dstreg, src2p, inst); // or dstreg,src2p + emit_mov_p32_r32(dst, dstp, dstreg); // mov dstp,dstreg + } + } + + // 64-bit form + else if (inst.size() == 8) + { + // dstp == src1p in memory + if (dstp.is_memory() && dstp == src1p) + emit_or_m64_p64(dst, MABS(dstp.memory()), src2p, inst); // or [dstp],src2p + + // general case + else + { + emit_mov_r64_p64(dst, dstreg, REG_EDX, src1p); // mov dstreg:dstp,[src1p] + emit_or_r64_p64(dst, dstreg, REG_EDX, src2p, inst); // or dstreg:dstp,src2p + emit_mov_p64_r64(dst, dstp, dstreg, REG_EDX); // mov dstp,dstreg:eax + } + } +} + + +//------------------------------------------------- +// op_xor - process a XOR opcode +//------------------------------------------------- + +void drcbe_x86::op_xor(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_no_condition(inst); + assert_flags(inst, FLAG_Z | FLAG_S); + + // normalize parameters + be_parameter dstp(*this, inst.param(0), PTYPE_MR); + be_parameter src1p(*this, inst.param(1), PTYPE_MRI); + be_parameter src2p(*this, inst.param(2), PTYPE_MRI); + normalize_commutative(src1p, src2p); + + // pick a target register for the general case + int dstreg = dstp.select_register(REG_EAX, src2p); + + // 32-bit form + if (inst.size() == 4) + { + // dstp == src1p in memory + if (dstp.is_memory() && dstp == src1p) + emit_xor_m32_p32(dst, MABS(dstp.memory()), src2p, inst); // xor [dstp],src2p + + // general case + else + { + emit_mov_r32_p32(dst, dstreg, src1p); // mov dstreg,src1p + emit_xor_r32_p32(dst, dstreg, src2p, inst); // xor dstreg,src2p + emit_mov_p32_r32(dst, dstp, dstreg); // mov dstp,dstreg + } + } + + // 64-bit form + else if (inst.size() == 8) + { + // dstp == src1p in memory + if (dstp.is_memory() && dstp == src1p) + emit_xor_m64_p64(dst, MABS(dstp.memory()), src2p, inst); // xor [dstp],src2p + + // general case + else + { + emit_mov_r64_p64(dst, dstreg, REG_EDX, src1p); // mov dstreg:dstp,[src1p] + emit_xor_r64_p64(dst, dstreg, REG_EDX, src2p, inst); // xor dstreg:dstp,src2p + emit_mov_p64_r64(dst, dstp, dstreg, REG_EDX); // mov dstp,dstreg:eax + } + } +} + + +//------------------------------------------------- +// op_lzcnt - process a LZCNT opcode +//------------------------------------------------- + +void drcbe_x86::op_lzcnt(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_no_condition(inst); + assert_flags(inst, FLAG_Z | FLAG_S); + + // normalize parameters + be_parameter dstp(*this, inst.param(0), PTYPE_MR); + be_parameter srcp(*this, inst.param(1), PTYPE_MRI); + + // pick a target register for the general case + int dstreg = dstp.select_register(REG_EAX); + + // 32-bit form + if (inst.size() == 4) + { + emit_mov_r32_p32(dst, dstreg, srcp); // mov dstreg,src1p + emit_mov_r32_imm(dst, REG_ECX, 32 ^ 31); // mov ecx,32 ^ 31 + emit_bsr_r32_r32(dst, dstreg, dstreg); // bsr dstreg,dstreg + emit_cmovcc_r32_r32(dst, x86emit::COND_Z, dstreg, REG_ECX); // cmovz dstreg,ecx + emit_xor_r32_imm(dst, dstreg, 31); // xor dstreg,31 + emit_mov_p32_r32(dst, dstp, dstreg); // mov dstp,dstreg + } + + // 64-bit form + else if (inst.size() == 8) + { + emit_mov_r64_p64(dst, REG_EDX, dstreg, srcp); // mov dstreg:edx,srcp + emit_bsr_r32_r32(dst, dstreg, dstreg); // bsr dstreg,dstreg + emit_link skip; + emit_jcc_short_link(dst, x86emit::COND_NZ, skip); // jnz skip + emit_mov_r32_imm(dst, REG_ECX, 32 ^ 31); // mov ecx,32 ^ 31 + emit_bsr_r32_r32(dst, dstreg, REG_EDX); // bsr dstreg,edx + emit_cmovcc_r32_r32(dst, x86emit::COND_Z, dstreg, REG_ECX); // cmovz dstreg,ecx + emit_add_r32_imm(dst, REG_ECX, 32); // add ecx,32 + track_resolve_link(dst, skip); // skip: + emit_xor_r32_r32(dst, REG_EDX, REG_EDX); // xor edx,edx + emit_xor_r32_imm(dst, dstreg, 31); // xor dstreg,31 + emit_mov_p64_r64(dst, dstp, dstreg, REG_EDX); // mov dstp,edx:dstreg + } +} + + +//------------------------------------------------- +// op_bswap - process a BSWAP opcode +//------------------------------------------------- + +void drcbe_x86::op_bswap(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_no_condition(inst); + assert_flags(inst, FLAG_Z | FLAG_S); + + // normalize parameters + be_parameter dstp(*this, inst.param(0), PTYPE_MR); + be_parameter srcp(*this, inst.param(1), PTYPE_MRI); + + // pick a target register for the general case + int dstreg = dstp.select_register(REG_EAX); + + // 32-bit form + if (inst.size() == 4) + { + emit_mov_r32_p32(dst, dstreg, srcp); // mov dstreg,src1p + emit_bswap_r32(dst, dstreg); // bswap dstreg + if (inst.flags() != 0) + emit_test_r32_r32(dst, dstreg, dstreg); // test dstreg,dstreg + emit_mov_p32_r32(dst, dstp, dstreg); // mov dstp,dstreg + } + + // 64-bit form + else if (inst.size() == 8) + { + emit_mov_r64_p64(dst, REG_EDX, dstreg, srcp); // mov dstreg:edx,srcp + emit_bswap_r32(dst, dstreg); // bswap dstreg + emit_bswap_r32(dst, REG_EDX); // bswap edx + emit_mov_p64_r64(dst, dstp, dstreg, REG_EDX); // mov dstp,edx:dstreg + if (inst.flags() == FLAG_Z) + emit_or_r32_r32(dst, REG_EDX, dstreg); // or edx,eax + else if (inst.flags() == FLAG_S) + emit_test_r32_r32(dst, REG_EDX, REG_EDX); // test edx,edx + else + { + emit_movzx_r32_r16(dst, REG_ECX, dstreg); // movzx ecx,dstreg + emit_or_r32_r32(dst, REG_EDX, REG_ECX); // or edx,ecx + emit_mov_r32_r32(dst, REG_ECX, dstreg); // mov ecx,dstreg + emit_shr_r32_imm(dst, REG_ECX, 16); // shr ecx,16 + emit_or_r32_r32(dst, REG_EDX, REG_ECX); // or edx,ecx + } + } +} + + +//------------------------------------------------- +// op_shl - process a SHL opcode +//------------------------------------------------- + +void drcbe_x86::op_shl(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_no_condition(inst); + assert_flags(inst, FLAG_C | FLAG_Z | FLAG_S); + + // normalize parameters + be_parameter dstp(*this, inst.param(0), PTYPE_MR); + be_parameter src1p(*this, inst.param(1), PTYPE_MRI); + be_parameter src2p(*this, inst.param(2), PTYPE_MRI); + + // pick a target register for the general case + int dstreg = dstp.select_register(REG_EAX, src2p); + + // 32-bit form + if (inst.size() == 4) + { + // dstp == src1p in memory + if (dstp.is_memory() && dstp == src1p) + emit_shl_m32_p32(dst, MABS(dstp.memory()), src2p, inst); // shl [dstp],src2p + + // general case + else + { + emit_mov_r32_p32(dst, dstreg, src1p); // mov dstreg,src1p + emit_shl_r32_p32(dst, dstreg, src2p, inst); // shl dstreg,src2p + emit_mov_p32_r32(dst, dstp, dstreg); // mov dstp,dstreg + } + } + + // 64-bit form + else if (inst.size() == 8) + { + // general case + emit_mov_r64_p64(dst, dstreg, REG_EDX, src1p); // mov dstreg:dstp,[src1p] + emit_shl_r64_p64(dst, dstreg, REG_EDX, src2p, inst); // shl dstreg:dstp,src2p + emit_mov_p64_r64(dst, dstp, dstreg, REG_EDX); // mov dstp,dstreg:eax + } +} + + +//------------------------------------------------- +// op_shr - process a SHR opcode +//------------------------------------------------- + +void drcbe_x86::op_shr(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_no_condition(inst); + assert_flags(inst, FLAG_C | FLAG_Z | FLAG_S); + + // normalize parameters + be_parameter dstp(*this, inst.param(0), PTYPE_MR); + be_parameter src1p(*this, inst.param(1), PTYPE_MRI); + be_parameter src2p(*this, inst.param(2), PTYPE_MRI); + + // pick a target register for the general case + int dstreg = dstp.select_register(REG_EAX, src2p); + + // 32-bit form + if (inst.size() == 4) + { + // dstp == src1p in memory + if (dstp.is_memory() && dstp == src1p) + emit_shr_m32_p32(dst, MABS(dstp.memory()), src2p, inst); // shr [dstp],src2p + + // general case + else + { + emit_mov_r32_p32(dst, dstreg, src1p); // mov dstreg,src1p + emit_shr_r32_p32(dst, dstreg, src2p, inst); // shr dstreg,src2p + emit_mov_p32_r32(dst, dstp, dstreg); // mov dstp,dstreg + } + } + + // 64-bit form + else if (inst.size() == 8) + { + // general case + emit_mov_r64_p64(dst, dstreg, REG_EDX, src1p); // mov dstreg:dstp,[src1p] + emit_shr_r64_p64(dst, dstreg, REG_EDX, src2p, inst); // shr dstreg:dstp,src2p + emit_mov_p64_r64(dst, dstp, dstreg, REG_EDX); // mov dstp,dstreg:eax + } +} + + +//------------------------------------------------- +// op_sar - process a SAR opcode +//------------------------------------------------- + +void drcbe_x86::op_sar(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_no_condition(inst); + assert_flags(inst, FLAG_C | FLAG_Z | FLAG_S); + + // normalize parameters + be_parameter dstp(*this, inst.param(0), PTYPE_MR); + be_parameter src1p(*this, inst.param(1), PTYPE_MRI); + be_parameter src2p(*this, inst.param(2), PTYPE_MRI); + + // pick a target register for the general case + int dstreg = dstp.select_register(REG_EAX, src2p); + + // 32-bit form + if (inst.size() == 4) + { + // dstp == src1p in memory + if (dstp.is_memory() && dstp == src1p) + emit_sar_m32_p32(dst, MABS(dstp.memory()), src2p, inst); // sar [dstp],src2p + + // general case + else + { + emit_mov_r32_p32(dst, dstreg, src1p); // mov dstreg,src1p + emit_sar_r32_p32(dst, dstreg, src2p, inst); // sar dstreg,src2p + emit_mov_p32_r32(dst, dstp, dstreg); // mov dstp,dstreg + } + } + + // 64-bit form + else if (inst.size() == 8) + { + // general case + emit_mov_r64_p64(dst, dstreg, REG_EDX, src1p); // mov dstreg:dstp,[src1p] + emit_sar_r64_p64(dst, dstreg, REG_EDX, src2p, inst); // sar dstreg:dstp,src2p + emit_mov_p64_r64(dst, dstp, dstreg, REG_EDX); // mov dstp,dstreg:eax + } +} + + +//------------------------------------------------- +// op_rol - process a rol opcode +//------------------------------------------------- + +void drcbe_x86::op_rol(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_no_condition(inst); + assert_flags(inst, FLAG_C | FLAG_Z | FLAG_S); + + // normalize parameters + be_parameter dstp(*this, inst.param(0), PTYPE_MR); + be_parameter src1p(*this, inst.param(1), PTYPE_MRI); + be_parameter src2p(*this, inst.param(2), PTYPE_MRI); + + // pick a target register for the general case + int dstreg = dstp.select_register(REG_EAX, src2p); + + // 32-bit form + if (inst.size() == 4) + { + // dstp == src1p in memory + if (dstp.is_memory() && dstp == src1p) + emit_rol_m32_p32(dst, MABS(dstp.memory()), src2p, inst); // rol [dstp],src2p + + // general case + else + { + emit_mov_r32_p32(dst, dstreg, src1p); // mov dstreg,src1p + emit_rol_r32_p32(dst, dstreg, src2p, inst); // rol dstreg,src2p + emit_mov_p32_r32(dst, dstp, dstreg); // mov dstp,dstreg + } + } + + // 64-bit form + else if (inst.size() == 8) + { + // general case + emit_mov_r64_p64(dst, dstreg, REG_EDX, src1p); // mov dstreg:dstp,[src1p] + emit_rol_r64_p64(dst, dstreg, REG_EDX, src2p, inst); // rol dstreg:dstp,src2p + emit_mov_p64_r64(dst, dstp, dstreg, REG_EDX); // mov dstp,dstreg:eax + } +} + + +//------------------------------------------------- +// op_ror - process a ROR opcode +//------------------------------------------------- + +void drcbe_x86::op_ror(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_no_condition(inst); + assert_flags(inst, FLAG_C | FLAG_Z | FLAG_S); + + // normalize parameters + be_parameter dstp(*this, inst.param(0), PTYPE_MR); + be_parameter src1p(*this, inst.param(1), PTYPE_MRI); + be_parameter src2p(*this, inst.param(2), PTYPE_MRI); + + // pick a target register for the general case + int dstreg = dstp.select_register(REG_EAX, src2p); + + // 32-bit form + if (inst.size() == 4) + { + // dstp == src1p in memory + if (dstp.is_memory() && dstp == src1p) + emit_ror_m32_p32(dst, MABS(dstp.memory()), src2p, inst); // ror [dstp],src2p + + // general case + else + { + emit_mov_r32_p32(dst, dstreg, src1p); // mov dstreg,src1p + emit_ror_r32_p32(dst, dstreg, src2p, inst); // ror dstreg,src2p + emit_mov_p32_r32(dst, dstp, dstreg); // mov dstp,dstreg + } + } + + // 64-bit form + else if (inst.size() == 8) + { + // general case + emit_mov_r64_p64(dst, dstreg, REG_EDX, src1p); // mov dstreg:dstp,[src1p] + emit_ror_r64_p64(dst, dstreg, REG_EDX, src2p, inst); // ror dstreg:dstp,src2p + emit_mov_p64_r64(dst, dstp, dstreg, REG_EDX); // mov dstp,dstreg:eax + } +} + + +//------------------------------------------------- +// op_rolc - process a ROLC opcode +//------------------------------------------------- + +void drcbe_x86::op_rolc(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_no_condition(inst); + assert_flags(inst, FLAG_C | FLAG_Z | FLAG_S); + + // normalize parameters + be_parameter dstp(*this, inst.param(0), PTYPE_MR); + be_parameter src1p(*this, inst.param(1), PTYPE_MRI); + be_parameter src2p(*this, inst.param(2), PTYPE_MRI); + + // pick a target register for the general case + int dstreg = dstp.select_register(REG_EAX, src2p); + + // 32-bit form + if (inst.size() == 4) + { + // dstp == src1p in memory + if (dstp.is_memory() && dstp == src1p) + emit_rcl_m32_p32(dst, MABS(dstp.memory()), src2p, inst); // rcl [dstp],src2p + + // general case + else + { + emit_mov_r32_p32_keepflags(dst, dstreg, src1p); // mov dstreg,src1p + emit_rcl_r32_p32(dst, dstreg, src2p, inst); // rcl dstreg,src2p + emit_mov_p32_r32(dst, dstp, dstreg); // mov dstp,dstreg + } + } + + // 64-bit form + else if (inst.size() == 8) + { + // general case + emit_mov_r64_p64_keepflags(dst, dstreg, REG_EDX, src1p); // mov dstreg:dstp,[src1p] + emit_rcl_r64_p64(dst, dstreg, REG_EDX, src2p, inst); // rcl dstreg:dstp,src2p + emit_mov_p64_r64(dst, dstp, dstreg, REG_EDX); // mov dstp,dstreg:eax + } +} + + +//------------------------------------------------- +// op_rorc - process a RORC opcode +//------------------------------------------------- + +void drcbe_x86::op_rorc(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_no_condition(inst); + assert_flags(inst, FLAG_C | FLAG_Z | FLAG_S); + + // normalize parameters + be_parameter dstp(*this, inst.param(0), PTYPE_MR); + be_parameter src1p(*this, inst.param(1), PTYPE_MRI); + be_parameter src2p(*this, inst.param(2), PTYPE_MRI); + + // pick a target register for the general case + int dstreg = dstp.select_register(REG_EAX, src2p); + + // 32-bit form + if (inst.size() == 4) + { + // dstp == src1p in memory + if (dstp.is_memory() && dstp == src1p) + emit_rcr_m32_p32(dst, MABS(dstp.memory()), src2p, inst); // rcr [dstp],src2p + + // general case + else + { + emit_mov_r32_p32_keepflags(dst, dstreg, src1p); // mov dstreg,src1p + emit_rcr_r32_p32(dst, dstreg, src2p, inst); // rcr dstreg,src2p + emit_mov_p32_r32(dst, dstp, dstreg); // mov dstp,dstreg + } + } + + // 64-bit form + else if (inst.size() == 8) + { + // general case + emit_mov_r64_p64_keepflags(dst, dstreg, REG_EDX, src1p); // mov dstreg:dstp,[src1p] + emit_rcr_r64_p64(dst, dstreg, REG_EDX, src2p, inst); // rcr dstreg:dstp,src2p + emit_mov_p64_r64(dst, dstp, dstreg, REG_EDX); // mov dstp,dstreg:eax + } +} + + + +//************************************************************************** +// FLOATING POINT OPERATIONS +//************************************************************************** + +//------------------------------------------------- +// op_fload - process a FLOAD opcode +//------------------------------------------------- + +void drcbe_x86::op_fload(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_no_condition(inst); + assert_no_flags(inst); + + // normalize parameters + be_parameter dstp(*this, inst.param(0), PTYPE_MF); + be_parameter basep(*this, inst.param(1), PTYPE_M); + be_parameter indp(*this, inst.param(2), PTYPE_MRI); + + // immediate index + if (indp.is_immediate()) + { + emit_mov_r32_m32(dst, REG_EAX, MABS(basep.memory(4*indp.immediate()))); // mov eax,[basep + 4*indp] + if (inst.size() == 8) + emit_mov_r32_m32(dst, REG_EDX, MABS(basep.memory(4 + 4*indp.immediate()))); // mov edx,[basep + 4*indp + 4] + } + + // other index + else + { + int indreg = indp.select_register(REG_ECX); + emit_mov_r32_p32(dst, indreg, indp); + emit_mov_r32_m32(dst, REG_EAX, MABSI(basep.memory(), indreg, 4)); // mov eax,[basep + 4*indp] + if (inst.size() == 8) + emit_mov_r32_m32(dst, REG_EDX, MABSI(basep.memory(4), indreg, 4)); // mov edx,[basep + 4*indp + 4] + } + + // general case + emit_mov_m32_r32(dst, MABS(dstp.memory()), REG_EAX); // mov [dstp],eax + if (inst.size() == 8) + emit_mov_m32_r32(dst, MABS(dstp.memory(4)), REG_EDX); // mov [dstp + 4],edx +} + + +//------------------------------------------------- +// op_fstore - process a FSTORE opcode +//------------------------------------------------- + +void drcbe_x86::op_fstore(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_no_condition(inst); + assert_no_flags(inst); + + // normalize parameters + be_parameter basep(*this, inst.param(0), PTYPE_M); + be_parameter indp(*this, inst.param(1), PTYPE_MRI); + be_parameter srcp(*this, inst.param(2), PTYPE_MF); + + // general case + emit_mov_r32_m32(dst, REG_EAX, MABS(srcp.memory())); // mov eax,[srcp] + if (inst.size() == 8) + emit_mov_r32_m32(dst, REG_EDX, MABS(srcp.memory(4))); // mov edx,[srcp + 4] + + // immediate index + if (indp.is_immediate()) + { + emit_mov_m32_r32(dst, MABS(basep.memory(4*indp.immediate())), REG_EAX); // mov [basep + 4*indp],eax + if (inst.size() == 8) + emit_mov_m32_r32(dst, MABS(basep.memory(4 + 4*indp.immediate())), REG_EDX); // mov [basep + 4*indp + 4],edx + } + + // other index + else + { + int indreg = indp.select_register(REG_ECX); + emit_mov_r32_p32(dst, indreg, indp); + emit_mov_m32_r32(dst, MABSI(basep.memory(), indreg, 4), REG_EAX); // mov [basep + 4*indp],eax + if (inst.size() == 8) + emit_mov_m32_r32(dst, MABSI(basep.memory(4), indreg, 4), REG_EDX); // mov [basep + 4*indp + 4],edx + } +} + + +//------------------------------------------------- +// op_fread - process a FREAD opcode +//------------------------------------------------- + +void drcbe_x86::op_fread(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_no_condition(inst); + assert_no_flags(inst); + + // normalize parameters + be_parameter dstp(*this, inst.param(0), PTYPE_MF); + be_parameter addrp(*this, inst.param(1), PTYPE_MRI); + const parameter &spacep = inst.param(2); + assert(spacep.is_size_space()); + assert((1 << spacep.size()) == inst.size()); + + // set up a call to the read dword/qword handler + emit_mov_m32_p32(dst, MBD(REG_ESP, 4), addrp); // mov [esp+4],addrp + emit_mov_m32_imm(dst, MBD(REG_ESP, 0), (FPTR)m_space[spacep.space()]); // mov [esp],space + if (inst.size() == 4) + emit_call(dst, (x86code *)m_accessors[spacep.space()].read_dword); // call read_dword + else if (inst.size() == 8) + emit_call(dst, (x86code *)m_accessors[spacep.space()].read_qword); // call read_qword + + // store result + if (inst.size() == 4) + emit_mov_p32_r32(dst, dstp, REG_EAX); // mov dstp,eax + else if (inst.size() == 8) + emit_mov_p64_r64(dst, dstp, REG_EAX, REG_EDX); // mov dstp,edx:eax +} + + +//------------------------------------------------- +// op_fwrite - process a FWRITE opcode +//------------------------------------------------- + +void drcbe_x86::op_fwrite(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_no_condition(inst); + assert_no_flags(inst); + + // normalize parameters + be_parameter addrp(*this, inst.param(0), PTYPE_MRI); + be_parameter srcp(*this, inst.param(1), PTYPE_MF); + const parameter &spacep = inst.param(2); + assert(spacep.is_size_space()); + assert((1 << spacep.size()) == inst.size()); + + // set up a call to the write dword/qword handler + if (inst.size() == 4) + emit_mov_m32_p32(dst, MBD(REG_ESP, 8), srcp); // mov [esp+8],srcp + else if (inst.size() == 8) + emit_mov_m64_p64(dst, MBD(REG_ESP, 8), srcp); // mov [esp+8],srcp + emit_mov_m32_p32(dst, MBD(REG_ESP, 4), addrp); // mov [esp+4],addrp + emit_mov_m32_imm(dst, MBD(REG_ESP, 0), (FPTR)m_space[spacep.space()]); // mov [esp],space + if (inst.size() == 4) + emit_call(dst, (x86code *)m_accessors[spacep.space()].write_dword); // call write_dword + else if (inst.size() == 8) + emit_call(dst, (x86code *)m_accessors[spacep.space()].write_qword); // call write_qword +} + + +//------------------------------------------------- +// op_fmov - process a FMOV opcode +//------------------------------------------------- + +void drcbe_x86::op_fmov(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_any_condition(inst); + assert_no_flags(inst); + + // normalize parameters + be_parameter dstp(*this, inst.param(0), PTYPE_MF); + be_parameter srcp(*this, inst.param(1), PTYPE_MF); + + // always start with a jmp + emit_link skip = { 0 }; + if (inst.condition() != uml::COND_ALWAYS) + emit_jcc_short_link(dst, X86_NOT_CONDITION(inst.condition()), skip); // jcc skip + + // general case + emit_mov_r32_m32(dst, REG_EAX, MABS(srcp.memory())); // mov eax,[srcp] + if (inst.size() == 8) + emit_mov_r32_m32(dst, REG_EDX, MABS(srcp.memory(4))); // mov edx,[srcp + 4] + emit_mov_m32_r32(dst, MABS(dstp.memory()), REG_EAX); // mov [dstp],eax + if (inst.size() == 8) + emit_mov_m32_r32(dst, MABS(dstp.memory(4)), REG_EDX); // mov [dstp + 4],edx + + // resolve the jump + if (skip.target != NULL) + track_resolve_link(dst, skip); // skip: +} + + +//------------------------------------------------- +// op_ftoint - process a FTOINT opcode +//------------------------------------------------- + +void drcbe_x86::op_ftoint(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_no_condition(inst); + assert_no_flags(inst); + + // normalize parameters + be_parameter dstp(*this, inst.param(0), PTYPE_MR); + be_parameter srcp(*this, inst.param(1), PTYPE_MF); + const parameter &sizep = inst.param(2); + assert(sizep.is_size()); + const parameter &roundp = inst.param(3); + assert(roundp.is_rounding()); + + // set rounding mode if necessary + if (roundp.rounding() != ROUND_DEFAULT && (!m_sse3 || roundp.rounding() != ROUND_TRUNC)) + { + emit_fstcw_m16(dst, MABS(&m_fmodesave)); // fstcw [fmodesave] + emit_fldcw_m16(dst, MABS(&fp_control[roundp.rounding()])); // fldcw fpcontrol[roundp] + } + + // general case + emit_fld_p(dst, inst.size(), srcp); // fld srcp + + // 4-byte integer case + if (sizep.size() == SIZE_DWORD) + { + if (dstp.is_memory()) + { + if (!m_sse3 || roundp.rounding() != ROUND_TRUNC) + emit_fistp_m32(dst, MABS(dstp.memory())); // fistp [dstp] + else + emit_fisttp_m32(dst, MABS(dstp.memory())); // fisttp [dstp] + } + else if (dstp.is_int_register()) + { + if (!m_sse3 || roundp.rounding() != ROUND_TRUNC) + emit_fistp_m32(dst, MABS(m_reglo[dstp.ireg()])); // fistp reglo[dstp] + else + emit_fisttp_m32(dst, MABS(m_reglo[dstp.ireg()])); // fisttp reglo[dstp] + emit_mov_r32_m32(dst, dstp.ireg(), MABS(m_reglo[dstp.ireg()])); // mov dstp,reglo[dstp] + } + } + + // 8-byte integer case + else if (sizep.size() == SIZE_QWORD) + { + if (dstp.is_memory()) + { + if (!m_sse3 || roundp.rounding() != ROUND_TRUNC) + emit_fistp_m64(dst, MABS(dstp.memory())); // fistp [dstp] + else + emit_fisttp_m64(dst, MABS(dstp.memory())); // fisttp [dstp] + } + else if (dstp.is_int_register()) + { + if (!m_sse3 || roundp.rounding() != ROUND_TRUNC) + emit_fistp_m64(dst, MABS(m_reglo[dstp.ireg()])); // fistp reglo[dstp] + else + emit_fisttp_m64(dst, MABS(m_reglo[dstp.ireg()])); // fisttp reglo[dstp] + emit_mov_r32_m32(dst, dstp.ireg(), MABS(m_reglo[dstp.ireg()])); // mov dstp,reglo[dstp] + } + } + + // restore control word and proceed + if (roundp.rounding() != ROUND_DEFAULT && (!m_sse3 || roundp.rounding() != ROUND_TRUNC)) + emit_fldcw_m16(dst, MABS(&m_fmodesave)); // fldcw [fmodesave] +} + + +//------------------------------------------------- +// op_ffrint - process a FFRINT opcode +//------------------------------------------------- + +void drcbe_x86::op_ffrint(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_no_condition(inst); + assert_no_flags(inst); + + // normalize parameters + be_parameter dstp(*this, inst.param(0), PTYPE_MF); + be_parameter srcp(*this, inst.param(1), PTYPE_MRI); + const parameter &sizep = inst.param(2); + assert(sizep.is_size()); + + // 4-byte integer case + if (sizep.size() == SIZE_DWORD) + { + if (srcp.is_immediate()) + { + emit_mov_m32_imm(dst, MABS(&m_fptemp), srcp.immediate()); // mov [fptemp],srcp + emit_fild_m32(dst, MABS(&m_fptemp)); // fild [fptemp] + } + else if (srcp.is_memory()) + emit_fild_m32(dst, MABS(srcp.memory())); // fild [srcp] + else if (srcp.is_int_register()) + { + emit_mov_m32_r32(dst, MABS(m_reglo[srcp.ireg()]), srcp.ireg()); // mov reglo[srcp],srcp + emit_fild_m32(dst, MABS(m_reglo[srcp.ireg()])); // fild reglo[srcp] + } + } + + // 8-bit integer case + else if (sizep.size() == SIZE_QWORD) + { + if (srcp.is_immediate()) + { + emit_mov_m32_imm(dst, MABS(&m_fptemp), srcp.immediate()); // mov [fptemp],srcp + emit_mov_m32_imm(dst, MABS((UINT8 *)&m_fptemp + 4), srcp.immediate()); // mov [fptemp+4],srcp + emit_fild_m64(dst, MABS(&m_fptemp)); // fild [fptemp] + } + else if (srcp.is_memory()) + emit_fild_m64(dst, MABS(srcp.memory())); // fild [srcp] + else if (srcp.is_int_register()) + { + emit_mov_m32_r32(dst, MABS(m_reglo[srcp.ireg()]), srcp.ireg()); // mov reglo[srcp],srcp + emit_fild_m64(dst, MABS(m_reglo[srcp.ireg()])); // fild reglo[srcp] + } + } + + // store the result and be done + emit_fstp_p(dst, inst.size(), dstp); // fstp [dstp] +} + + +//------------------------------------------------- +// op_ffrflt - process a FFRFLT opcode +//------------------------------------------------- + +void drcbe_x86::op_ffrflt(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_no_condition(inst); + assert_no_flags(inst); + + // normalize parameters + be_parameter dstp(*this, inst.param(0), PTYPE_MF); + be_parameter srcp(*this, inst.param(1), PTYPE_MF); + const parameter &sizep = inst.param(2); + assert(sizep.is_size()); + + // general case + if (sizep.size() == SIZE_DWORD) + emit_fld_m32(dst, MABS(srcp.memory())); // fld [srcp] + else if (sizep.size() == SIZE_QWORD) + emit_fld_m64(dst, MABS(srcp.memory())); // fld [srcp] + emit_fstp_p(dst, inst.size(), dstp); // fstp dstp +} + + +//------------------------------------------------- +// op_frnds - process a FRNDS opcode +//------------------------------------------------- + +void drcbe_x86::op_frnds(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 8); + assert_no_condition(inst); + assert_no_flags(inst); + + // normalize parameters + be_parameter dstp(*this, inst.param(0), PTYPE_MF); + be_parameter srcp(*this, inst.param(1), PTYPE_MF); + + // general case + emit_fld_p(dst, inst.size(), srcp); // fld srcp + emit_fstp_m32(dst, MABS(&m_fptemp)); // fstp [fptemp] + emit_fld_m32(dst, MABS(&m_fptemp)); // fld [fptemp] + emit_fstp_p(dst, inst.size(), dstp); // fstp [dstp] +} + + +//------------------------------------------------- +// op_fadd - process a FADD opcode +//------------------------------------------------- + +void drcbe_x86::op_fadd(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_no_condition(inst); + assert_no_flags(inst); + + // normalize parameters + be_parameter dstp(*this, inst.param(0), PTYPE_MF); + be_parameter src1p(*this, inst.param(1), PTYPE_MF); + be_parameter src2p(*this, inst.param(2), PTYPE_MF); + normalize_commutative(src1p, src2p); + + // general case + emit_fld_p(dst, inst.size(), src1p); // fld src1p + emit_fld_p(dst, inst.size(), src2p); // fld src2p + emit_faddp(dst); // faddp + emit_fstp_p(dst, inst.size(), dstp); // fstp dstp +} + + +//------------------------------------------------- +// op_fsub - process a FSUB opcode +//------------------------------------------------- + +void drcbe_x86::op_fsub(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_no_condition(inst); + assert_no_flags(inst); + + // normalize parameters + be_parameter dstp(*this, inst.param(0), PTYPE_MF); + be_parameter src1p(*this, inst.param(1), PTYPE_MF); + be_parameter src2p(*this, inst.param(2), PTYPE_MF); + + // general case + emit_fld_p(dst, inst.size(), src1p); // fld src1p + emit_fld_p(dst, inst.size(), src2p); // fld src2p + emit_fsubp(dst); // fsubp + emit_fstp_p(dst, inst.size(), dstp); // fstp dstp +} + + +//------------------------------------------------- +// op_fcmp - process a FCMP opcode +//------------------------------------------------- + +void drcbe_x86::op_fcmp(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_no_condition(inst); + assert_flags(inst, FLAG_C | FLAG_Z | FLAG_U); + + // normalize parameters + be_parameter src1p(*this, inst.param(0), PTYPE_MF); + be_parameter src2p(*this, inst.param(1), PTYPE_MF); + + // general case + emit_fld_p(dst, inst.size(), src2p); // fld src2p + emit_fld_p(dst, inst.size(), src1p); // fld src1p + emit_fcompp(dst); // fcompp + emit_fstsw_ax(dst); // fnstsw ax + emit_sahf(dst); // sahf +} + + +//------------------------------------------------- +// op_fmul - process a FMUL opcode +//------------------------------------------------- + +void drcbe_x86::op_fmul(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_no_condition(inst); + assert_no_flags(inst); + + // normalize parameters + be_parameter dstp(*this, inst.param(0), PTYPE_MF); + be_parameter src1p(*this, inst.param(1), PTYPE_MF); + be_parameter src2p(*this, inst.param(2), PTYPE_MF); + normalize_commutative(src1p, src2p); + + // general case + emit_fld_p(dst, inst.size(), src1p); // fld src1p + emit_fld_p(dst, inst.size(), src2p); // fld src2p + emit_fmulp(dst); // fmulp + emit_fstp_p(dst, inst.size(), dstp); // fstp dstp +} + + +//------------------------------------------------- +// op_fdiv - process a FDIV opcode +//------------------------------------------------- + +void drcbe_x86::op_fdiv(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_no_condition(inst); + assert_no_flags(inst); + + // normalize parameters + be_parameter dstp(*this, inst.param(0), PTYPE_MF); + be_parameter src1p(*this, inst.param(1), PTYPE_MF); + be_parameter src2p(*this, inst.param(2), PTYPE_MF); + + // general case + emit_fld_p(dst, inst.size(), src1p); // fld src1p + emit_fld_p(dst, inst.size(), src2p); // fld src2p + emit_fdivp(dst); // fdivp + emit_fstp_p(dst, inst.size(), dstp); // fstp dstp +} + + +//------------------------------------------------- +// op_fneg - process a FNEG opcode +//------------------------------------------------- + +void drcbe_x86::op_fneg(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_no_condition(inst); + assert_no_flags(inst); + + // normalize parameters + be_parameter dstp(*this, inst.param(0), PTYPE_MF); + be_parameter srcp(*this, inst.param(1), PTYPE_MF); + + // general case + emit_fld_p(dst, inst.size(), srcp); // fld srcp + emit_fchs(dst); // fchs + emit_fstp_p(dst, inst.size(), dstp); // fstp dstp +} + + +//------------------------------------------------- +// op_fabs - process a FABS opcode +//------------------------------------------------- + +void drcbe_x86::op_fabs(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_no_condition(inst); + assert_no_flags(inst); + + // normalize parameters + be_parameter dstp(*this, inst.param(0), PTYPE_MF); + be_parameter srcp(*this, inst.param(1), PTYPE_MF); + + // general case + emit_fld_p(dst, inst.size(), srcp); // fld srcp + emit_fabs(dst); // fabs + emit_fstp_p(dst, inst.size(), dstp); // fstp dstp +} + + +//------------------------------------------------- +// op_fsqrt - process a FSQRT opcode +//------------------------------------------------- + +void drcbe_x86::op_fsqrt(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_no_condition(inst); + assert_no_flags(inst); + + // normalize parameters + be_parameter dstp(*this, inst.param(0), PTYPE_MF); + be_parameter srcp(*this, inst.param(1), PTYPE_MF); + + // general case + emit_fld_p(dst, inst.size(), srcp); // fld srcp + emit_fsqrt(dst); // fsqrt + emit_fstp_p(dst, inst.size(), dstp); // fstp dstp +} + + +//------------------------------------------------- +// op_frecip - process a FRECIP opcode +//------------------------------------------------- + +void drcbe_x86::op_frecip(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_no_condition(inst); + assert_no_flags(inst); + + // normalize parameters + be_parameter dstp(*this, inst.param(0), PTYPE_MF); + be_parameter srcp(*this, inst.param(1), PTYPE_MF); + + // general case + emit_fld1(dst); // fld1 + emit_fld_p(dst, inst.size(), srcp); // fld srcp + emit_fdivp(dst); // fdivp + emit_fstp_p(dst, inst.size(), dstp); // fstp dstp +} + + +//------------------------------------------------- +// op_frsqrt - process a FRSQRT opcode +//------------------------------------------------- + +void drcbe_x86::op_frsqrt(x86code *&dst, const instruction &inst) +{ + // validate instruction + assert(inst.size() == 4 || inst.size() == 8); + assert_no_condition(inst); + assert_no_flags(inst); + + // normalize parameters + be_parameter dstp(*this, inst.param(0), PTYPE_MF); + be_parameter srcp(*this, inst.param(1), PTYPE_MF); + + // general case + emit_fld1(dst); // fld1 + emit_fld_p(dst, inst.size(), srcp); // fld srcp + emit_fsqrt(dst); // fsqrt + emit_fdivp(dst); // fdivp + emit_fstp_p(dst, inst.size(), dstp); // fstp dstp +} + + + +//************************************************************************** +// MISCELLAENOUS FUNCTIONS +//************************************************************************** + +//------------------------------------------------- +// dmulu - perform a double-wide unsigned multiply +//------------------------------------------------- + +int drcbe_x86::dmulu(UINT64 &dstlo, UINT64 &dsthi, UINT64 src1, UINT64 src2, int flags) +{ + // shortcut if we don't care about the high bits or the flags + if (&dstlo == &dsthi && flags == 0) + { + dstlo = src1 * src2; + return 0; + } + + // fetch source values + UINT64 a = src1; + UINT64 b = src2; + if (a == 0 || b == 0) + { + dsthi = dstlo = 0; + return FLAG_Z; + } + + // compute high and low parts first + UINT64 lo = (UINT64)(UINT32)(a >> 0) * (UINT64)(UINT32)(b >> 0); + UINT64 hi = (UINT64)(UINT32)(a >> 32) * (UINT64)(UINT32)(b >> 32); + + // compute middle parts + UINT64 prevlo = lo; + UINT64 temp = (UINT64)(UINT32)(a >> 32) * (UINT64)(UINT32)(b >> 0); + lo += temp << 32; + hi += (temp >> 32) + (lo < prevlo); + + prevlo = lo; + temp = (UINT64)(UINT32)(a >> 0) * (UINT64)(UINT32)(b >> 32); + lo += temp << 32; + hi += (temp >> 32) + (lo < prevlo); + + // store the results + dsthi = hi; + dstlo = lo; + return ((hi >> 60) & FLAG_S) | ((dsthi != 0) << 1); +} + + +//------------------------------------------------- +// dmuls - perform a double-wide signed multiply +//------------------------------------------------- + +int drcbe_x86::dmuls(UINT64 &dstlo, UINT64 &dsthi, INT64 src1, INT64 src2, int flags) +{ + UINT64 lo, hi, prevlo; + UINT64 a, b, temp; + + // shortcut if we don't care about the high bits or the flags + if (&dstlo == &dsthi && flags == 0) + { + dstlo = src1 * src2; + return 0; + } + + // fetch absolute source values + a = src1; if ((INT64)a < 0) a = -a; + b = src2; if ((INT64)b < 0) b = -b; + if (a == 0 || b == 0) + { + dsthi = dstlo = 0; + return FLAG_Z; + } + + // compute high and low parts first + lo = (UINT64)(UINT32)(a >> 0) * (UINT64)(UINT32)(b >> 0); + hi = (UINT64)(UINT32)(a >> 32) * (UINT64)(UINT32)(b >> 32); + + // compute middle parts + prevlo = lo; + temp = (UINT64)(UINT32)(a >> 32) * (UINT64)(UINT32)(b >> 0); + lo += temp << 32; + hi += (temp >> 32) + (lo < prevlo); + + prevlo = lo; + temp = (UINT64)(UINT32)(a >> 0) * (UINT64)(UINT32)(b >> 32); + lo += temp << 32; + hi += (temp >> 32) + (lo < prevlo); + + // adjust for signage + if ((INT64)(src1 ^ src2) < 0) + { + hi = ~hi + (lo == 0); + lo = ~lo + 1; + } + + // store the results + dsthi = hi; + dstlo = lo; + return ((hi >> 60) & FLAG_S) | ((dsthi != ((INT64)lo >> 63)) << 1); +} + + +//------------------------------------------------- +// ddivu - perform a double-wide unsigned divide +//------------------------------------------------- + +int drcbe_x86::ddivu(UINT64 &dstlo, UINT64 &dsthi, UINT64 src1, UINT64 src2) +{ + // do nothing if src2 == 0 + if (src2 == 0) + return FLAG_V; + + // shortcut if no remainder + dstlo = src1 / src2; + if (dstlo != dsthi) + dsthi = src1 % src2; + return ((dstlo == 0) << 2) | ((dstlo >> 60) & FLAG_S); +} + + +//------------------------------------------------- +// ddivs - perform a double-wide signed divide +//------------------------------------------------- + +int drcbe_x86::ddivs(UINT64 &dstlo, UINT64 &dsthi, INT64 src1, INT64 src2) +{ + // do nothing if src2 == 0 + if (src2 == 0) + return FLAG_V; + + // shortcut if no remainder + dstlo = src1 / src2; + if (dstlo != dsthi) + dsthi = src1 % src2; + return ((dstlo == 0) << 2) | ((dstlo >> 60) & FLAG_S); +} diff --git a/src/devices/cpu/drcbex86.h b/src/devices/cpu/drcbex86.h new file mode 100644 index 00000000000..3c3af63d0d0 --- /dev/null +++ b/src/devices/cpu/drcbex86.h @@ -0,0 +1,346 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + drcbex86.h + + 32-bit x86 back-end for the universal machine language. + +***************************************************************************/ + +#pragma once + +#ifndef __DRCBEX86_H__ +#define __DRCBEX86_H__ + +#include "drcuml.h" +#include "drcbeut.h" +#include "x86log.h" + +#define X86EMIT_SIZE 32 +#include "x86emit.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class drcbe_x86 : public drcbe_interface +{ + typedef UINT32 (*x86_entry_point_func)(x86code *entry); + +public: + // construction/destruction + drcbe_x86(drcuml_state &drcuml, device_t &device, drc_cache &cache, UINT32 flags, int modes, int addrbits, int ignorebits); + virtual ~drcbe_x86(); + + // required overrides + virtual void reset(); + virtual int execute(uml::code_handle &entry); + virtual void generate(drcuml_block &block, const uml::instruction *instlist, UINT32 numinst); + virtual bool hash_exists(UINT32 mode, UINT32 pc); + virtual void get_info(drcbe_info &info); + virtual bool logging() const { return m_log != NULL; } + +private: + // a be_parameter is similar to a uml::parameter but maps to native registers/memory + class be_parameter + { + public: + // parameter types + enum be_parameter_type + { + PTYPE_NONE = 0, // invalid + PTYPE_IMMEDIATE, // immediate; value = sign-extended to 64 bits + PTYPE_INT_REGISTER, // integer register; value = 0-REG_MAX + PTYPE_FLOAT_REGISTER, // floating point register; value = 0-REG_MAX + PTYPE_VECTOR_REGISTER, // vector register; value = 0-REG_MAX + PTYPE_MEMORY, // memory; value = pointer to memory + PTYPE_MAX + }; + + // represents the value of a parameter + typedef UINT64 be_parameter_value; + + // construction + be_parameter() : m_type(PTYPE_NONE), m_value(0) { } + be_parameter(const be_parameter ¶m) : m_type(param.m_type), m_value(param.m_value) { } + be_parameter(UINT64 val) : m_type(PTYPE_IMMEDIATE), m_value(val) { } + be_parameter(drcbe_x86 &drcbe, const uml::parameter ¶m, UINT32 allowed); + + // creators for types that don't safely default + static inline be_parameter make_ireg(int regnum) { assert(regnum >= 0 && regnum < x86emit::REG_MAX); return be_parameter(PTYPE_INT_REGISTER, regnum); } + static inline be_parameter make_freg(int regnum) { assert(regnum >= 0 && regnum < x86emit::REG_MAX); return be_parameter(PTYPE_FLOAT_REGISTER, regnum); } + static inline be_parameter make_vreg(int regnum) { assert(regnum >= 0 && regnum < x86emit::REG_MAX); return be_parameter(PTYPE_VECTOR_REGISTER, regnum); } + static inline be_parameter make_memory(void *base) { return be_parameter(PTYPE_MEMORY, reinterpret_cast(base)); } + static inline be_parameter make_memory(const void *base) { return be_parameter(PTYPE_MEMORY, reinterpret_cast(const_cast(base))); } + + // operators + bool operator==(const be_parameter &rhs) const { return (m_type == rhs.m_type && m_value == rhs.m_value); } + bool operator!=(const be_parameter &rhs) const { return (m_type != rhs.m_type || m_value != rhs.m_value); } + + // getters + be_parameter_type type() const { return m_type; } + UINT64 immediate() const { assert(m_type == PTYPE_IMMEDIATE); return m_value; } + int ireg() const { assert(m_type == PTYPE_INT_REGISTER); assert(m_value < x86emit::REG_MAX); return m_value; } + int freg() const { assert(m_type == PTYPE_FLOAT_REGISTER); assert(m_value < x86emit::REG_MAX); return m_value; } + int vreg() const { assert(m_type == PTYPE_VECTOR_REGISTER); assert(m_value < x86emit::REG_MAX); return m_value; } + void *memory(UINT32 offset = 0) const { assert(m_type == PTYPE_MEMORY); return reinterpret_cast(m_value + offset); } + + // type queries + bool is_immediate() const { return (m_type == PTYPE_IMMEDIATE); } + bool is_int_register() const { return (m_type == PTYPE_INT_REGISTER); } + bool is_float_register() const { return (m_type == PTYPE_FLOAT_REGISTER); } + bool is_vector_register() const { return (m_type == PTYPE_VECTOR_REGISTER); } + bool is_memory() const { return (m_type == PTYPE_MEMORY); } + + // other queries + bool is_immediate_value(UINT64 value) const { return (m_type == PTYPE_IMMEDIATE && m_value == value); } + + // helpers + int select_register(int defreg) const; + int select_register(int defreg, const be_parameter &checkparam) const; + int select_register(int defreg, const be_parameter &checkparam, const be_parameter &checkparam2) const; + + private: + // private constructor + be_parameter(be_parameter_type type, be_parameter_value value) : m_type(type), m_value(value) { } + + // internals + be_parameter_type m_type; // parameter type + be_parameter_value m_value; // parameter value + }; + + // helpers + void normalize_commutative(be_parameter &inner, be_parameter &outer); + void emit_combine_z_flags(x86code *&dst); + void emit_combine_z_shl_flags(x86code *&dst); + void reset_last_upper_lower_reg(); + void set_last_lower_reg(x86code *&dst, const be_parameter ¶m, UINT8 reglo); + void set_last_upper_reg(x86code *&dst, const be_parameter ¶m, UINT8 reghi); + bool can_skip_lower_load(x86code *&dst, UINT32 *memref, UINT8 reglo); + bool can_skip_upper_load(x86code *&dst, UINT32 *memref, UINT8 reghi); + void track_resolve_link(x86code *&destptr, const emit_link &linkinfo); + + void fixup_label(void *parameter, drccodeptr labelcodeptr); + void fixup_exception(drccodeptr *codeptr, void *param1, void *param2); + + static void debug_log_hashjmp(int mode, offs_t pc); + static void debug_log_hashjmp_fail(); + + // code generators + void op_handle(x86code *&dst, const uml::instruction &inst); + void op_hash(x86code *&dst, const uml::instruction &inst); + void op_label(x86code *&dst, const uml::instruction &inst); + void op_comment(x86code *&dst, const uml::instruction &inst); + void op_mapvar(x86code *&dst, const uml::instruction &inst); + + void op_nop(x86code *&dst, const uml::instruction &inst); + void op_debug(x86code *&dst, const uml::instruction &inst); + void op_exit(x86code *&dst, const uml::instruction &inst); + void op_hashjmp(x86code *&dst, const uml::instruction &inst); + void op_jmp(x86code *&dst, const uml::instruction &inst); + void op_exh(x86code *&dst, const uml::instruction &inst); + void op_callh(x86code *&dst, const uml::instruction &inst); + void op_ret(x86code *&dst, const uml::instruction &inst); + void op_callc(x86code *&dst, const uml::instruction &inst); + void op_recover(x86code *&dst, const uml::instruction &inst); + + void op_setfmod(x86code *&dst, const uml::instruction &inst); + void op_getfmod(x86code *&dst, const uml::instruction &inst); + void op_getexp(x86code *&dst, const uml::instruction &inst); + void op_getflgs(x86code *&dst, const uml::instruction &inst); + void op_save(x86code *&dst, const uml::instruction &inst); + void op_restore(x86code *&dst, const uml::instruction &inst); + + void op_load(x86code *&dst, const uml::instruction &inst); + void op_loads(x86code *&dst, const uml::instruction &inst); + void op_store(x86code *&dst, const uml::instruction &inst); + void op_read(x86code *&dst, const uml::instruction &inst); + void op_readm(x86code *&dst, const uml::instruction &inst); + void op_write(x86code *&dst, const uml::instruction &inst); + void op_writem(x86code *&dst, const uml::instruction &inst); + void op_carry(x86code *&dst, const uml::instruction &inst); + void op_set(x86code *&dst, const uml::instruction &inst); + void op_mov(x86code *&dst, const uml::instruction &inst); + void op_sext(x86code *&dst, const uml::instruction &inst); + void op_roland(x86code *&dst, const uml::instruction &inst); + void op_rolins(x86code *&dst, const uml::instruction &inst); + void op_add(x86code *&dst, const uml::instruction &inst); + void op_addc(x86code *&dst, const uml::instruction &inst); + void op_sub(x86code *&dst, const uml::instruction &inst); + void op_subc(x86code *&dst, const uml::instruction &inst); + void op_cmp(x86code *&dst, const uml::instruction &inst); + void op_mulu(x86code *&dst, const uml::instruction &inst); + void op_muls(x86code *&dst, const uml::instruction &inst); + void op_divu(x86code *&dst, const uml::instruction &inst); + void op_divs(x86code *&dst, const uml::instruction &inst); + void op_and(x86code *&dst, const uml::instruction &inst); + void op_test(x86code *&dst, const uml::instruction &inst); + void op_or(x86code *&dst, const uml::instruction &inst); + void op_xor(x86code *&dst, const uml::instruction &inst); + void op_lzcnt(x86code *&dst, const uml::instruction &inst); + void op_bswap(x86code *&dst, const uml::instruction &inst); + void op_shl(x86code *&dst, const uml::instruction &inst); + void op_shr(x86code *&dst, const uml::instruction &inst); + void op_sar(x86code *&dst, const uml::instruction &inst); + void op_ror(x86code *&dst, const uml::instruction &inst); + void op_rol(x86code *&dst, const uml::instruction &inst); + void op_rorc(x86code *&dst, const uml::instruction &inst); + void op_rolc(x86code *&dst, const uml::instruction &inst); + + void op_fload(x86code *&dst, const uml::instruction &inst); + void op_fstore(x86code *&dst, const uml::instruction &inst); + void op_fread(x86code *&dst, const uml::instruction &inst); + void op_fwrite(x86code *&dst, const uml::instruction &inst); + void op_fmov(x86code *&dst, const uml::instruction &inst); + void op_ftoint(x86code *&dst, const uml::instruction &inst); + void op_ffrint(x86code *&dst, const uml::instruction &inst); + void op_ffrflt(x86code *&dst, const uml::instruction &inst); + void op_frnds(x86code *&dst, const uml::instruction &inst); + void op_fadd(x86code *&dst, const uml::instruction &inst); + void op_fsub(x86code *&dst, const uml::instruction &inst); + void op_fcmp(x86code *&dst, const uml::instruction &inst); + void op_fmul(x86code *&dst, const uml::instruction &inst); + void op_fdiv(x86code *&dst, const uml::instruction &inst); + void op_fneg(x86code *&dst, const uml::instruction &inst); + void op_fabs(x86code *&dst, const uml::instruction &inst); + void op_fsqrt(x86code *&dst, const uml::instruction &inst); + void op_frecip(x86code *&dst, const uml::instruction &inst); + void op_frsqrt(x86code *&dst, const uml::instruction &inst); + + // 32-bit code emission helpers + void emit_mov_r32_p32(x86code *&dst, UINT8 reg, const be_parameter ¶m); + void emit_mov_r32_p32_keepflags(x86code *&dst, UINT8 reg, const be_parameter ¶m); + void emit_mov_m32_p32(x86code *&dst, x86_memref memref, const be_parameter ¶m); + void emit_mov_p32_r32(x86code *&dst, const be_parameter ¶m, UINT8 reg); + void emit_add_r32_p32(x86code *&dst, UINT8 reg, const be_parameter ¶m, const uml::instruction &inst); + void emit_add_m32_p32(x86code *&dst, x86_memref memref, const be_parameter ¶m, const uml::instruction &inst); + void emit_adc_r32_p32(x86code *&dst, UINT8 reg, const be_parameter ¶m, const uml::instruction &inst); + void emit_adc_m32_p32(x86code *&dst, x86_memref memref, const be_parameter ¶m, const uml::instruction &inst); + void emit_sub_r32_p32(x86code *&dst, UINT8 reg, const be_parameter ¶m, const uml::instruction &inst); + void emit_sub_m32_p32(x86code *&dst, x86_memref memref, const be_parameter ¶m, const uml::instruction &inst); + void emit_sbb_r32_p32(x86code *&dst, UINT8 reg, const be_parameter ¶m, const uml::instruction &inst); + void emit_sbb_m32_p32(x86code *&dst, x86_memref memref, const be_parameter ¶m, const uml::instruction &inst); + void emit_cmp_r32_p32(x86code *&dst, UINT8 reg, const be_parameter ¶m, const uml::instruction &inst); + void emit_cmp_m32_p32(x86code *&dst, x86_memref memref, const be_parameter ¶m, const uml::instruction &inst); + void emit_and_r32_p32(x86code *&dst, UINT8 reg, const be_parameter ¶m, const uml::instruction &inst); + void emit_and_m32_p32(x86code *&dst, x86_memref memref, const be_parameter ¶m, const uml::instruction &inst); + void emit_test_r32_p32(x86code *&dst, UINT8 reg, const be_parameter ¶m, const uml::instruction &inst); + void emit_test_m32_p32(x86code *&dst, x86_memref memref, const be_parameter ¶m, const uml::instruction &inst); + void emit_or_r32_p32(x86code *&dst, UINT8 reg, const be_parameter ¶m, const uml::instruction &inst); + void emit_or_m32_p32(x86code *&dst, x86_memref memref, const be_parameter ¶m, const uml::instruction &inst); + void emit_xor_r32_p32(x86code *&dst, UINT8 reg, const be_parameter ¶m, const uml::instruction &inst); + void emit_xor_m32_p32(x86code *&dst, x86_memref memref, const be_parameter ¶m, const uml::instruction &inst); + void emit_shl_r32_p32(x86code *&dst, UINT8 reg, const be_parameter ¶m, const uml::instruction &inst); + void emit_shl_m32_p32(x86code *&dst, x86_memref memref, const be_parameter ¶m, const uml::instruction &inst); + void emit_shr_r32_p32(x86code *&dst, UINT8 reg, const be_parameter ¶m, const uml::instruction &inst); + void emit_shr_m32_p32(x86code *&dst, x86_memref memref, const be_parameter ¶m, const uml::instruction &inst); + void emit_sar_r32_p32(x86code *&dst, UINT8 reg, const be_parameter ¶m, const uml::instruction &inst); + void emit_sar_m32_p32(x86code *&dst, x86_memref memref, const be_parameter ¶m, const uml::instruction &inst); + void emit_rol_r32_p32(x86code *&dst, UINT8 reg, const be_parameter ¶m, const uml::instruction &inst); + void emit_rol_m32_p32(x86code *&dst, x86_memref memref, const be_parameter ¶m, const uml::instruction &inst); + void emit_ror_r32_p32(x86code *&dst, UINT8 reg, const be_parameter ¶m, const uml::instruction &inst); + void emit_ror_m32_p32(x86code *&dst, x86_memref memref, const be_parameter ¶m, const uml::instruction &inst); + void emit_rcl_r32_p32(x86code *&dst, UINT8 reg, const be_parameter ¶m, const uml::instruction &inst); + void emit_rcl_m32_p32(x86code *&dst, x86_memref memref, const be_parameter ¶m, const uml::instruction &inst); + void emit_rcr_r32_p32(x86code *&dst, UINT8 reg, const be_parameter ¶m, const uml::instruction &inst); + void emit_rcr_m32_p32(x86code *&dst, x86_memref memref, const be_parameter ¶m, const uml::instruction &inst); + + // 64-bit code emission helpers + void emit_mov_r64_p64(x86code *&dst, UINT8 reglo, UINT8 reghi, const be_parameter ¶m); + void emit_mov_r64_p64_keepflags(x86code *&dst, UINT8 reglo, UINT8 reghi, const be_parameter ¶m); + void emit_mov_m64_p64(x86code *&dst, x86_memref memref, const be_parameter ¶m); + void emit_mov_p64_r64(x86code *&dst, const be_parameter ¶m, UINT8 reglo, UINT8 reghi); + void emit_add_r64_p64(x86code *&dst, UINT8 reglo, UINT8 reghi, const be_parameter ¶m, const uml::instruction &inst); + void emit_add_m64_p64(x86code *&dst, x86_memref memref, const be_parameter ¶m, const uml::instruction &inst); + void emit_adc_r64_p64(x86code *&dst, UINT8 reglo, UINT8 reghi, const be_parameter ¶m, const uml::instruction &inst); + void emit_adc_m64_p64(x86code *&dst, x86_memref memref, const be_parameter ¶m, const uml::instruction &inst); + void emit_sub_r64_p64(x86code *&dst, UINT8 reglo, UINT8 reghi, const be_parameter ¶m, const uml::instruction &inst); + void emit_sub_m64_p64(x86code *&dst, x86_memref memref, const be_parameter ¶m, const uml::instruction &inst); + void emit_sbb_r64_p64(x86code *&dst, UINT8 reglo, UINT8 reghi, const be_parameter ¶m, const uml::instruction &inst); + void emit_sbb_m64_p64(x86code *&dst, x86_memref memref, const be_parameter ¶m, const uml::instruction &inst); + void emit_cmp_r64_p64(x86code *&dst, UINT8 reglo, UINT8 reghi, const be_parameter ¶m, const uml::instruction &inst); + void emit_cmp_m64_p64(x86code *&dst, x86_memref memref, const be_parameter ¶m, const uml::instruction &inst); + void emit_and_r64_p64(x86code *&dst, UINT8 reglo, UINT8 reghi, const be_parameter ¶m, const uml::instruction &inst); + void emit_and_m64_p64(x86code *&dst, x86_memref memref, const be_parameter ¶m, const uml::instruction &inst); + void emit_test_r64_p64(x86code *&dst, UINT8 reglo, UINT8 reghi, const be_parameter ¶m, const uml::instruction &inst); + void emit_test_m64_p64(x86code *&dst, x86_memref memref, const be_parameter ¶m, const uml::instruction &inst); + void emit_or_r64_p64(x86code *&dst, UINT8 reglo, UINT8 reghi, const be_parameter ¶m, const uml::instruction &inst); + void emit_or_m64_p64(x86code *&dst, x86_memref memref, const be_parameter ¶m, const uml::instruction &inst); + void emit_xor_r64_p64(x86code *&dst, UINT8 reglo, UINT8 reghi, const be_parameter ¶m, const uml::instruction &inst); + void emit_xor_m64_p64(x86code *&dst, x86_memref memref, const be_parameter ¶m, const uml::instruction &inst); + void emit_shl_r64_p64(x86code *&dst, UINT8 reglo, UINT8 reghi, const be_parameter ¶m, const uml::instruction &inst); + void emit_shl_m64_p64(x86code *&dst, x86_memref memref, const be_parameter ¶m, const uml::instruction &inst); + void emit_shr_r64_p64(x86code *&dst, UINT8 reglo, UINT8 reghi, const be_parameter ¶m, const uml::instruction &inst); + void emit_shr_m64_p64(x86code *&dst, x86_memref memref, const be_parameter ¶m, const uml::instruction &inst); + void emit_sar_r64_p64(x86code *&dst, UINT8 reglo, UINT8 reghi, const be_parameter ¶m, const uml::instruction &inst); + void emit_sar_m64_p64(x86code *&dst, x86_memref memref, const be_parameter ¶m, const uml::instruction &inst); + void emit_rol_r64_p64(x86code *&dst, UINT8 reglo, UINT8 reghi, const be_parameter ¶m, const uml::instruction &inst); + void emit_rol_m64_p64(x86code *&dst, x86_memref memref, const be_parameter ¶m, const uml::instruction &inst); + void emit_ror_r64_p64(x86code *&dst, UINT8 reglo, UINT8 reghi, const be_parameter ¶m, const uml::instruction &inst); + void emit_ror_m64_p64(x86code *&dst, x86_memref memref, const be_parameter ¶m, const uml::instruction &inst); + void emit_rcl_r64_p64(x86code *&dst, UINT8 reglo, UINT8 reghi, const be_parameter ¶m, const uml::instruction &inst); + void emit_rcl_m64_p64(x86code *&dst, x86_memref memref, const be_parameter ¶m, const uml::instruction &inst); + void emit_rcr_r64_p64(x86code *&dst, UINT8 reglo, UINT8 reghi, const be_parameter ¶m, const uml::instruction &inst); + void emit_rcr_m64_p64(x86code *&dst, x86_memref memref, const be_parameter ¶m, const uml::instruction &inst); + + // floating-point code emission helpers + void emit_fld_p(x86code *&dst, int size, const be_parameter ¶m); + void emit_fstp_p(x86code *&dst, int size, const be_parameter ¶m); + + // callback helpers + static int dmulu(UINT64 &dstlo, UINT64 &dsthi, UINT64 src1, UINT64 src2, int flags); + static int dmuls(UINT64 &dstlo, UINT64 &dsthi, INT64 src1, INT64 src2, int flags); + static int ddivu(UINT64 &dstlo, UINT64 &dsthi, UINT64 src1, UINT64 src2); + static int ddivs(UINT64 &dstlo, UINT64 &dsthi, INT64 src1, INT64 src2); + + // internal state + drc_hash_table m_hash; // hash table state + drc_map_variables m_map; // code map + drc_label_list m_labels; // label list + x86log_context * m_log; // logging + bool m_logged_common; // logged common code already? + bool m_sse3; // do we have SSE3 support? + + x86_entry_point_func m_entry; // entry point + x86code * m_exit; // exit point + x86code * m_nocode; // nocode handler + x86code * m_save; // save handler + x86code * m_restore; // restore handler + + UINT32 * m_reglo[x86emit::REG_MAX];// pointer to low part of data for each register + UINT32 * m_reghi[x86emit::REG_MAX];// pointer to high part of data for each register + UINT8 m_last_lower_reg; // last register we stored a lower from + x86code * m_last_lower_pc; // PC after instruction where we last stored a lower register + UINT32 * m_last_lower_addr; // address where we last stored an lower register + UINT8 m_last_upper_reg; // last register we stored an upper from + x86code * m_last_upper_pc; // PC after instruction where we last stored an upper register + UINT32 * m_last_upper_addr; // address where we last stored an upper register + double m_fptemp; // temporary storage for floating point + + UINT16 m_fpumode; // saved FPU mode + UINT16 m_fmodesave; // temporary location for saving + + void * m_stacksave; // saved stack pointer + void * m_hashstacksave; // saved stack pointer for hashjmp + UINT64 m_reslo; // extended low result + UINT64 m_reshi; // extended high result + + drc_label_fixup_delegate m_fixup_label; // precomputed delegate for fixups + drc_oob_delegate m_fixup_exception; // precomputed delegate for exception fixups + + // globals + typedef void (drcbe_x86::*opcode_generate_func)(x86code *&dst, const uml::instruction &inst); + struct opcode_table_entry + { + uml::opcode_t opcode; // opcode in question + opcode_generate_func func; // function pointer to the work + }; + static const opcode_table_entry s_opcode_table_source[]; + static opcode_generate_func s_opcode_table[uml::OP_MAX]; +}; + + +#endif /* __DRCBEC_H__ */ diff --git a/src/devices/cpu/drccache.c b/src/devices/cpu/drccache.c new file mode 100644 index 00000000000..74a0116aa97 --- /dev/null +++ b/src/devices/cpu/drccache.c @@ -0,0 +1,252 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + drccache.c + + Universal dynamic recompiler cache management. + +***************************************************************************/ + +#include "emu.h" +#include "drccache.h" + + + +//************************************************************************** +// MACROS +//************************************************************************** + +// ensure that all memory allocated is aligned to an 8-byte boundary +#define ALIGN_PTR_UP(p) ((void *)(((FPTR)(p) + (CACHE_ALIGNMENT - 1)) & ~(CACHE_ALIGNMENT - 1))) +#define ALIGN_PTR_DOWN(p) ((void *)((FPTR)(p) & ~(CACHE_ALIGNMENT - 1))) + + + +//************************************************************************** +// DRC CACHE +//************************************************************************** + +//------------------------------------------------- +// drc_cache - constructor +//------------------------------------------------- + +drc_cache::drc_cache(size_t bytes) + : m_near((drccodeptr)osd_alloc_executable(bytes)), + m_neartop(m_near), + m_base(m_near + NEAR_CACHE_SIZE), + m_top(m_base), + m_end(m_near + bytes), + m_codegen(0), + m_size(bytes) +{ + memset(m_free, 0, sizeof(m_free)); + memset(m_nearfree, 0, sizeof(m_nearfree)); +} + + +//------------------------------------------------- +// ~drc_cache - destructor +//------------------------------------------------- + +drc_cache::~drc_cache() +{ + // release the memory + osd_free_executable(m_near, m_size); +} + + + +//------------------------------------------------- +// flush - flush the cache contents +//------------------------------------------------- + +void drc_cache::flush() +{ + // can't flush in the middle of codegen + assert(m_codegen == NULL); + + // just reset the top back to the base and re-seed + m_top = m_base; +} + + +//------------------------------------------------- +// alloc - allocate permanent memory from the +// cache +//------------------------------------------------- + +void *drc_cache::alloc(size_t bytes) +{ + assert(bytes > 0); + + // pick first from the free list + if (bytes < MAX_PERMANENT_ALLOC) + { + free_link **linkptr = &m_free[(bytes + CACHE_ALIGNMENT - 1) / CACHE_ALIGNMENT]; + free_link *link = *linkptr; + if (link != NULL) + { + *linkptr = link->m_next; + return link; + } + } + + // if no space, we just fail + drccodeptr ptr = (drccodeptr)ALIGN_PTR_DOWN(m_end - bytes); + if (m_top > ptr) + return NULL; + + // otherwise update the end of the cache + m_end = ptr; + return ptr; +} + + +//------------------------------------------------- +// alloc_near - allocate permanent memory from +// the near part of the cache +//------------------------------------------------- + +void *drc_cache::alloc_near(size_t bytes) +{ + assert(bytes > 0); + + // pick first from the free list + if (bytes < MAX_PERMANENT_ALLOC) + { + free_link **linkptr = &m_nearfree[(bytes + CACHE_ALIGNMENT - 1) / CACHE_ALIGNMENT]; + free_link *link = *linkptr; + if (link != NULL) + { + *linkptr = link->m_next; + return link; + } + } + + // if no space, we just fail + drccodeptr ptr = (drccodeptr)ALIGN_PTR_UP(m_neartop); + if (ptr + bytes > m_base) + return NULL; + + // otherwise update the top of the near part of the cache + m_neartop = ptr + bytes; + return ptr; +} + + +//------------------------------------------------- +// alloc_temporary - allocate temporary memory +// from the cache +//------------------------------------------------- + +void *drc_cache::alloc_temporary(size_t bytes) +{ + // can't allocate in the middle of codegen + assert(m_codegen == NULL); + + // if no space, we just fail + drccodeptr ptr = m_top; + if (ptr + bytes >= m_end) + return NULL; + + // otherwise, update the cache top + m_top = (drccodeptr)ALIGN_PTR_UP(ptr + bytes); + return ptr; +} + + +//------------------------------------------------- +// free - release permanent memory allocated from +// the cache +//------------------------------------------------- + +void drc_cache::dealloc(void *memory, size_t bytes) +{ + assert(bytes < MAX_PERMANENT_ALLOC); + assert(((drccodeptr)memory >= m_near && (drccodeptr)memory < m_base) || ((drccodeptr)memory >= m_end && (drccodeptr)memory < m_near + m_size)); + + // determine which free list to add to + free_link **linkptr; + if ((drccodeptr)memory < m_base) + linkptr = &m_nearfree[(bytes + CACHE_ALIGNMENT - 1) / CACHE_ALIGNMENT]; + else + linkptr = &m_free[(bytes + CACHE_ALIGNMENT - 1) / CACHE_ALIGNMENT]; + + // link is into the free list for our size + free_link *link = (free_link *)memory; + link->m_next = *linkptr; + *linkptr = link; +} + + +//------------------------------------------------- +// begin_codegen - begin code generation +//------------------------------------------------- + +drccodeptr *drc_cache::begin_codegen(UINT32 reserve_bytes) +{ + // can't restart in the middle of codegen + assert(m_codegen == NULL); + assert(m_ooblist.first() == NULL); + + // if still no space, we just fail + drccodeptr ptr = m_top; + if (ptr + reserve_bytes >= m_end) + return NULL; + + // otherwise, return a pointer to the cache top + m_codegen = m_top; + return &m_top; +} + + +//------------------------------------------------- +// end_codegen - complete code generation +//------------------------------------------------- + +drccodeptr drc_cache::end_codegen() +{ + drccodeptr result = m_codegen; + + // run the OOB handlers + oob_handler *oob; + while ((oob = m_ooblist.detach_head()) != NULL) + { + // call the callback + oob->m_callback(&m_top, oob->m_param1, oob->m_param2); + assert(m_top - m_codegen < CODEGEN_MAX_BYTES); + + // release our memory + dealloc(oob, sizeof(*oob)); + } + + // update the cache top + m_top = (drccodeptr)ALIGN_PTR_UP(m_top); + m_codegen = NULL; + + return result; +} + + +//------------------------------------------------- +// request_oob_codegen - request callback for +// out-of-band codegen +//------------------------------------------------- + +void drc_cache::request_oob_codegen(drc_oob_delegate callback, void *param1, void *param2) +{ + assert(m_codegen != NULL); + + // pull an item from the free list + oob_handler *oob = (oob_handler *)alloc(sizeof(*oob)); + assert(oob != NULL); + + // fill it in + oob->m_callback = callback; + oob->m_param1 = param1; + oob->m_param2 = param2; + + // add to the tail + m_ooblist.append(*oob); +} diff --git a/src/devices/cpu/drccache.h b/src/devices/cpu/drccache.h new file mode 100644 index 00000000000..cf5a41e41dd --- /dev/null +++ b/src/devices/cpu/drccache.h @@ -0,0 +1,114 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + drccache.h + + Universal dynamic recompiler cache management. + +***************************************************************************/ + +#pragma once + +#ifndef __DRCCACHE_H__ +#define __DRCCACHE_H__ + + + +//************************************************************************** +// MACROS +//************************************************************************** + +// ensure that a given pointer is within the cache boundaries +#define assert_in_cache(c,p) assert((c).contains_pointer(p)) +#define assert_in_near_cache(c,p) assert((c).contains_near_pointer(p)) + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// generic code pointer +typedef UINT8 *drccodeptr; + + +// helper template for oob codegen +typedef delegate drc_oob_delegate; + + +// drc_cache +class drc_cache +{ +public: + // construction/destruction + drc_cache(size_t bytes); + ~drc_cache(); + + // getters + drccodeptr near() const { return m_near; } + drccodeptr base() const { return m_base; } + drccodeptr top() const { return m_top; } + + // pointer checking + bool contains_pointer(const void *ptr) const { return ((const drccodeptr)ptr >= m_near && (const drccodeptr)ptr < m_near + m_size); } + bool contains_near_pointer(const void *ptr) const { return ((const drccodeptr)ptr >= m_near && (const drccodeptr)ptr < m_neartop); } + bool generating_code() const { return (m_codegen != NULL); } + + // memory management + void flush(); + void *alloc(size_t bytes); + void *alloc_near(size_t bytes); + void *alloc_temporary(size_t bytes); + void dealloc(void *memory, size_t bytes); + + // codegen helpers + drccodeptr *begin_codegen(UINT32 reserve_bytes); + drccodeptr end_codegen(); + void request_oob_codegen(drc_oob_delegate callback, void *param1 = NULL, void *param2 = NULL); + +private: + // largest block of code that can be generated at once + static const size_t CODEGEN_MAX_BYTES = 65536; + + // minimum alignment, in bytes (must be power of 2) + static const size_t CACHE_ALIGNMENT = 8; + + // largest permanent allocation we allow + static const size_t MAX_PERMANENT_ALLOC = 1024; + + // size of "near" area at the base of the cache + static const size_t NEAR_CACHE_SIZE = 65536; + + // core parameters + drccodeptr m_near; // pointer to the near part of the cache + drccodeptr m_neartop; // top of the near part of the cache + drccodeptr m_base; // base pointer to the compiler cache + drccodeptr m_top; // current top of cache + drccodeptr m_end; // end of cache memory + drccodeptr m_codegen; // start of generated code + size_t m_size; // size of the cache in bytes + + // oob management + struct oob_handler + { + oob_handler *next() const { return m_next; } + + oob_handler * m_next; // next handler + drc_oob_delegate m_callback; // callback function + void * m_param1; // 1st pointer parameter + void * m_param2; // 2nd pointer parameter + }; + simple_list m_ooblist; // list of oob handlers + + // free lists + struct free_link + { + free_link * m_next; // pointer to the next guy + }; + free_link * m_free[MAX_PERMANENT_ALLOC / CACHE_ALIGNMENT]; + free_link * m_nearfree[MAX_PERMANENT_ALLOC / CACHE_ALIGNMENT]; +}; + + +#endif /* __DRCCACHE_H__ */ diff --git a/src/devices/cpu/drcfe.c b/src/devices/cpu/drcfe.c new file mode 100644 index 00000000000..f3746b22dc0 --- /dev/null +++ b/src/devices/cpu/drcfe.c @@ -0,0 +1,378 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + drcfe.c + + Generic dynamic recompiler frontend structures and utilities. + +**************************************************************************** + + Future improvements/changes: + + * more aggressive handling of needed registers for conditional + intrablock branches + +***************************************************************************/ + +#include "emu.h" +#include "drcfe.h" + + +//************************************************************************** +// CONSTANTS +//************************************************************************** + +const UINT32 MAX_STACK_DEPTH = 100; + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// an entry that maps branches for our code walking +struct pc_stack_entry +{ + offs_t targetpc; + offs_t srcpc; +}; + + + +//************************************************************************** +// DRC FRONTEND +//************************************************************************** + +//------------------------------------------------- +// drc_frontend - constructor +//------------------------------------------------- + +drc_frontend::drc_frontend(device_t &cpu, UINT32 window_start, UINT32 window_end, UINT32 max_sequence) + : m_window_start(window_start), + m_window_end(window_end), + m_max_sequence(max_sequence), + m_cpudevice(downcast(cpu)), + m_program(m_cpudevice.space(AS_PROGRAM)), + m_pageshift(m_cpudevice.space_config(AS_PROGRAM)->m_page_shift), + m_desc_array(window_end + window_start + 2, 0) +{ +} + + +//------------------------------------------------- +// ~drc_frontend - destructor +//------------------------------------------------- + +drc_frontend::~drc_frontend() +{ + // release any descriptions we've accumulated + release_descriptions(); +} + + +//------------------------------------------------- +// describe_code - describe a sequence of code +// that falls within the configured window +// relative to the specified startpc +//------------------------------------------------- + +const opcode_desc *drc_frontend::describe_code(offs_t startpc) +{ + // release any descriptions we've accumulated + release_descriptions(); + + // add the initial PC to the stack + pc_stack_entry pcstack[MAX_STACK_DEPTH]; + pc_stack_entry *pcstackptr = &pcstack[0]; + pcstackptr->srcpc = 0; + pcstackptr->targetpc = startpc; + pcstackptr++; + + // loop while we still have a stack + offs_t minpc = startpc - MIN(m_window_start, startpc); + offs_t maxpc = startpc + MIN(m_window_end, 0xffffffff - startpc); + while (pcstackptr != &pcstack[0]) + { + // if we've already hit this PC, just mark it a branch target and continue + pc_stack_entry *curstack = --pcstackptr; + opcode_desc *curdesc = m_desc_array[curstack->targetpc - minpc]; + if (curdesc != NULL) + { + curdesc->flags |= OPFLAG_IS_BRANCH_TARGET; + + // if the branch crosses a page boundary, mark the target as needing to revalidate + if (m_pageshift != 0 && ((curstack->srcpc ^ curdesc->pc) >> m_pageshift) != 0) + curdesc->flags |= OPFLAG_VALIDATE_TLB | OPFLAG_CAN_CAUSE_EXCEPTION; + + // continue processing + continue; + } + + // loop until we exit the block + for (offs_t curpc = curstack->targetpc; curpc >= minpc && curpc < maxpc && m_desc_array[curpc - minpc] == NULL; curpc += m_desc_array[curpc - minpc]->length) + { + // allocate a new description and describe this instruction + m_desc_array[curpc - minpc] = curdesc = describe_one(curpc, curdesc); + + // first instruction in a sequence is always a branch target + if (curpc == curstack->targetpc) + curdesc->flags |= OPFLAG_IS_BRANCH_TARGET; + + // stop if we hit a page fault + if (curdesc->flags & OPFLAG_COMPILER_PAGE_FAULT) + break; + + // if we are the first instruction in the whole window, we must validate the TLB + if (curpc == startpc && m_pageshift != 0) + curdesc->flags |= OPFLAG_VALIDATE_TLB | OPFLAG_CAN_CAUSE_EXCEPTION; + + // if we are a branch within the block range, add the branch target to our stack + if ((curdesc->flags & OPFLAG_IS_BRANCH) && curdesc->targetpc >= minpc && curdesc->targetpc < maxpc && pcstackptr < &pcstack[MAX_STACK_DEPTH]) + { + curdesc->flags |= OPFLAG_INTRABLOCK_BRANCH; + pcstackptr->srcpc = curdesc->pc; + pcstackptr->targetpc = curdesc->targetpc; + pcstackptr++; + } + + // if we're done, we're done + if (curdesc->flags & OPFLAG_END_SEQUENCE) + break; + } + } + + // now build the list of descriptions in order + // first from startpc -> maxpc, then from minpc -> startpc + build_sequence(startpc - minpc, maxpc - minpc, OPFLAG_REDISPATCH); + build_sequence(minpc - minpc, startpc - minpc, OPFLAG_RETURN_TO_START); + return m_desc_live_list.first(); +} + + +//------------------------------------------------- +// describe_one - describe a single instruction, +// recursively describing opcodes in delay +// slots of branches as well +//------------------------------------------------- + +opcode_desc *drc_frontend::describe_one(offs_t curpc, const opcode_desc *prevdesc) +{ + // initialize the description + opcode_desc *desc = m_desc_allocator.alloc(); + desc->m_next = NULL; + desc->branch = NULL; + desc->delay.reset(); + desc->pc = curpc; + desc->physpc = curpc; + desc->targetpc = BRANCH_TARGET_DYNAMIC; + memset(&desc->opptr, 0x00, sizeof(desc->opptr)); + desc->length = 0; + desc->delayslots = 0; + desc->skipslots = 0; + desc->flags = 0; + desc->cycles = 0; + memset(desc->regin, 0x00, sizeof(desc->regin)); + memset(desc->regout, 0x00, sizeof(desc->regout)); + memset(desc->regreq, 0x00, sizeof(desc->regreq)); + + // call the callback to describe an instruction + if (!describe(*desc, prevdesc)) + { + desc->flags |= OPFLAG_WILL_CAUSE_EXCEPTION | OPFLAG_INVALID_OPCODE; + return desc; + } + + // validate the TLB if we are exactly at the start of a page, or if we cross a page boundary + if (m_pageshift != 0 && (((curpc - 1) ^ (curpc + desc->length - 1)) >> m_pageshift) != 0) + desc->flags |= OPFLAG_VALIDATE_TLB | OPFLAG_CAN_CAUSE_EXCEPTION; + + // validate stuff + assert(desc->length > 0 || (desc->flags & OPFLAG_VIRTUAL_NOOP) != 0); + + // if we are a branch with delay slots, recursively walk those + if (desc->flags & OPFLAG_IS_BRANCH) + { + // iterate over slots and describe them + offs_t delaypc = curpc + desc->length; + opcode_desc *prev = desc; + for (UINT8 slotnum = 0; slotnum < desc->delayslots; slotnum++) + { + // recursively describe the next instruction + opcode_desc *delaydesc = describe_one(delaypc, prev); + if (delaydesc == NULL) + break; + desc->delay.append(*delaydesc); + prev = desc; + + // set the delay slot flag and a pointer back to the original branch + delaydesc->flags |= OPFLAG_IN_DELAY_SLOT; + delaydesc->branch = desc; + + // stop if we hit a page fault + if (delaydesc->flags & OPFLAG_COMPILER_PAGE_FAULT) + break; + + // otherwise, advance + delaypc += delaydesc->length; + } + } + return desc; +} + + +//------------------------------------------------- +// build_sequence - build an ordered sequence +// of instructions +//------------------------------------------------- + +void drc_frontend::build_sequence(int start, int end, UINT32 endflag) +{ + // iterate in order from start to end, picking up all non-NULL instructions + int consecutive = 0; + int seqstart = -1; + int skipsleft = 0; + for (int descnum = start; descnum < end; descnum++) + if (m_desc_array[descnum] != NULL) + { + // determine the next instruction, taking skips into account + opcode_desc *curdesc = m_desc_array[descnum]; + int nextdescnum = descnum + curdesc->length; + opcode_desc *nextdesc = (nextdescnum < end) ? m_desc_array[nextdescnum] : NULL; + for (UINT8 skipnum = 0; skipnum < curdesc->skipslots && nextdesc != NULL; skipnum++) + { + nextdescnum = nextdescnum + nextdesc->length; + nextdesc = (nextdescnum < end) ? m_desc_array[nextdescnum] : NULL; + } + + // start a new sequence if we aren't already in the middle of one + if (seqstart == -1 && skipsleft == 0) + { + // tag all start-of-sequence instructions as needing TLB verification + curdesc->flags |= OPFLAG_VALIDATE_TLB | OPFLAG_CAN_CAUSE_EXCEPTION; + seqstart = descnum; + } + + // if we are the last instruction, indicate end-of-sequence and redispatch + if (nextdesc == NULL) + { + curdesc->flags |= OPFLAG_END_SEQUENCE; + if (endflag != OPFLAG_RETURN_TO_START || nextdescnum == end) + curdesc->flags |= endflag; + } + + // otherwise, do some analysis based on the next instruction + else + { + // if there are instructions between us and the next instruction, we must end our sequence here + int scandescnum; + opcode_desc *scandesc = NULL; + for (scandescnum = descnum + 1; scandescnum < end; scandescnum++) + { + scandesc = m_desc_array[scandescnum]; + if (scandesc != NULL || scandesc == nextdesc) + break; + } + if (scandesc != nextdesc) + curdesc->flags |= OPFLAG_END_SEQUENCE; + + // if the next instruction is a branch target, mark this instruction as end of sequence + if (nextdesc->flags & OPFLAG_IS_BRANCH_TARGET) + curdesc->flags |= OPFLAG_END_SEQUENCE; + } + + // if we exceed the maximum consecutive count, cut off the sequence + if (++consecutive >= m_max_sequence) + curdesc->flags |= OPFLAG_END_SEQUENCE; + if (curdesc->flags & OPFLAG_END_SEQUENCE) + consecutive = 0; + + // if this is the end of a sequence, work backwards + if (curdesc->flags & OPFLAG_END_SEQUENCE) + { + // figure out which registers we *must* generate, assuming at the end all must be + UINT32 reqmask[4] = { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }; + if (seqstart != -1) + for (int backdesc = descnum; backdesc != seqstart - 1; backdesc--) + if (m_desc_array[backdesc] != NULL) + accumulate_required_backwards(*m_desc_array[backdesc], reqmask); + + // reset the register states + seqstart = -1; + } + + // if we have instructions remaining to be skipped, and this instruction is a branch target + // belay the skip order + if (skipsleft > 0 && (curdesc->flags & OPFLAG_IS_BRANCH_TARGET)) + skipsleft = 0; + + // if we're not getting skipped, add us to the end of the list and clear our array slot + if (skipsleft == 0) + m_desc_live_list.append(*curdesc); + else + m_desc_allocator.reclaim(*curdesc); + + // if the current instruction starts skipping, reset our skip count + // otherwise, just decrement + if (curdesc->skipslots > 0) + skipsleft = curdesc->skipslots; + else if (skipsleft > 0) + skipsleft--; + } + + // zap the array + memset(&m_desc_array[start], 0, (end - start) * sizeof(m_desc_array[0])); +} + + +//------------------------------------------------- +// accumulate_required_backwards - recursively +// accumulate live register liveness information +// walking in a backwards direction +//------------------------------------------------- + +void drc_frontend::accumulate_required_backwards(opcode_desc &desc, UINT32 *reqmask) +{ + // recursively handle delay slots + if (desc.delay.first() != NULL) + accumulate_required_backwards(*desc.delay.first(), reqmask); + + // if this is a branch, we have to reset our requests + if (desc.flags & OPFLAG_IS_BRANCH) + reqmask[0] = reqmask[1] = reqmask[2] = reqmask[3] = 0xffffffff; + + // determine the required registers + desc.regreq[0] = desc.regout[0] & reqmask[0]; + desc.regreq[1] = desc.regout[1] & reqmask[1]; + desc.regreq[2] = desc.regout[2] & reqmask[2]; + desc.regreq[3] = desc.regout[3] & reqmask[3]; + + // any registers modified by this instruction aren't required upstream until referenced + reqmask[0] &= ~desc.regout[0]; + reqmask[1] &= ~desc.regout[1]; + reqmask[2] &= ~desc.regout[2]; + reqmask[3] &= ~desc.regout[3]; + + // any registers required by this instruction now get marked required + reqmask[0] |= desc.regin[0]; + reqmask[1] |= desc.regin[1]; + reqmask[2] |= desc.regin[2]; + reqmask[3] |= desc.regin[3]; +} + + +//------------------------------------------------- +// release_descriptions - release any +// descriptions we've allocated back to the +// free list +//------------------------------------------------ + +void drc_frontend::release_descriptions() +{ + // release all delay slots first + for (opcode_desc *curdesc = m_desc_live_list.first(); curdesc != NULL; curdesc = curdesc->next()) + m_desc_allocator.reclaim_all(curdesc->delay); + + // reclaim all the descriptors + m_desc_allocator.reclaim_all(m_desc_live_list); +} diff --git a/src/devices/cpu/drcfe.h b/src/devices/cpu/drcfe.h new file mode 100644 index 00000000000..67c67067221 --- /dev/null +++ b/src/devices/cpu/drcfe.h @@ -0,0 +1,164 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + drcfe.h + + Generic dynamic recompiler frontend structures and utilities. + +**************************************************************************** + + Concepts: + + Dynamic recompiling cores are generally broken into a platform-neutral + "frontend", which performs some level of analysis on the code, and a + platform-specific "backend", which generates the recompiled machine + code. + + The frontend's job is generally to walk through the instruction stream, + identifying basic blocks, or "sequences" of code that can be compiled + and optimized as a unit. This scanning involves recursively walking + the instruction stream, following branches, etc., within a specific + "code window", relative to the current PC. + + As the frontend walks through the code, it generates a list of opcode + "descriptions", one per visited opcode, providing information about + code flow, exception handling, and other characteristics. Once the + walkthrough is finished, these descriptions are assembled together into + a linked list and returned for further processing by the backend. + +***************************************************************************/ + +#pragma once + +#ifndef __DRCFE_H__ +#define __DRCFE_H__ + + +//************************************************************************** +// CONSTANTS +//************************************************************************** + +// this defines a branch targetpc that is dynamic at runtime +const offs_t BRANCH_TARGET_DYNAMIC = ~0; + + +// opcode branch flags +const UINT32 OPFLAG_IS_UNCONDITIONAL_BRANCH = 0x00000001; // instruction is unconditional branch +const UINT32 OPFLAG_IS_CONDITIONAL_BRANCH = 0x00000002; // instruction is conditional branch +const UINT32 OPFLAG_IS_BRANCH = (OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_IS_CONDITIONAL_BRANCH); +const UINT32 OPFLAG_IS_BRANCH_TARGET = 0x00000004; // instruction is the target of a branch +const UINT32 OPFLAG_IN_DELAY_SLOT = 0x00000008; // instruction is in the delay slot of a branch +const UINT32 OPFLAG_INTRABLOCK_BRANCH = 0x00000010; // instruction branches within the block + +// opcode exception flags +const UINT32 OPFLAG_CAN_TRIGGER_SW_INT = 0x00000020; // instruction can trigger a software interrupt +const UINT32 OPFLAG_CAN_EXPOSE_EXTERNAL_INT = 0x00000040; // instruction can expose an external interrupt +const UINT32 OPFLAG_CAN_CAUSE_EXCEPTION = 0x00000080; // instruction may generate exception +const UINT32 OPFLAG_WILL_CAUSE_EXCEPTION = 0x00000100; // instruction will generate exception +const UINT32 OPFLAG_PRIVILEGED = 0x00000200; // instruction is privileged + +// opcode virtual->physical translation flags +const UINT32 OPFLAG_VALIDATE_TLB = 0x00000400; // instruction must validate TLB before execution +const UINT32 OPFLAG_MODIFIES_TRANSLATION = 0x00000800; // instruction modifies the TLB +const UINT32 OPFLAG_COMPILER_PAGE_FAULT = 0x00001000; // compiler hit a page fault when parsing +const UINT32 OPFLAG_COMPILER_UNMAPPED = 0x00002000; // compiler hit unmapped memory when parsing + +// opcode flags +const UINT32 OPFLAG_INVALID_OPCODE = 0x00004000; // instruction is invalid +const UINT32 OPFLAG_VIRTUAL_NOOP = 0x00008000; // instruction is a virtual no-op + +// opcode sequence flow flags +const UINT32 OPFLAG_REDISPATCH = 0x00010000; // instruction must redispatch after completion +const UINT32 OPFLAG_RETURN_TO_START = 0x00020000; // instruction must jump back to the beginning after completion +const UINT32 OPFLAG_END_SEQUENCE = 0x00040000; // this is the last instruction in a sequence +const UINT32 OPFLAG_CAN_CHANGE_MODES = 0x00080000; // instruction can change modes + +// execution semantics +const UINT32 OPFLAG_READS_MEMORY = 0x00100000; // instruction reads memory +const UINT32 OPFLAG_WRITES_MEMORY = 0x00200000; // instruction writes memory + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// description of a given opcode +struct opcode_desc +{ + opcode_desc *next() const { return m_next; } + + // links to other descriptions + opcode_desc * m_next; // pointer to next description + opcode_desc * branch; // pointer back to branch description for delay slots + simple_list delay; // pointer to delay slot description + + // information about the current PC + offs_t pc; // PC of this opcode + offs_t physpc; // physical PC of this opcode + offs_t targetpc; // target PC if we are a branch, or BRANCH_TARGET_DYNAMIC + + // copy of up to 16 bytes of opcode + union + { + UINT8 b[16]; + UINT16 w[8]; + UINT32 l[4]; + UINT64 q[2]; + } opptr; // pointer to opcode memory + + // information about this instruction's execution + UINT8 length; // length in bytes of this opcode + UINT8 delayslots; // number of delay slots (for branches) + UINT8 skipslots; // number of skip slots (for branches) + UINT32 flags; // OPFLAG_* opcode flags + UINT32 cycles; // number of cycles needed to execute + + // register usage information + UINT32 regin[4]; // input registers + UINT32 regout[4]; // output registers + UINT32 regreq[4]; // required output registers +}; + + +// DRC frontend state +class drc_frontend +{ +public: + // construction/destruction + drc_frontend(device_t &cpu, UINT32 window_start, UINT32 window_end, UINT32 max_sequence); + virtual ~drc_frontend(); + + // describe a block + const opcode_desc *describe_code(offs_t startpc); + +protected: + // required overrides + virtual bool describe(opcode_desc &desc, const opcode_desc *prev) = 0; + +private: + // internal helpers + opcode_desc *describe_one(offs_t curpc, const opcode_desc *prevdesc); + void build_sequence(int start, int end, UINT32 endflag); + void accumulate_required_backwards(opcode_desc &desc, UINT32 *reqmask); + void release_descriptions(); + + // configuration parameters + UINT32 m_window_start; // code window start offset = startpc - window_start + UINT32 m_window_end; // code window end offset = startpc + window_end + UINT32 m_max_sequence; // maximum instructions to include in a sequence + + // CPU parameters + cpu_device & m_cpudevice; // CPU device object + address_space & m_program; // program address space for this CPU + offs_t m_pageshift; // shift to convert address to a page index + + // opcode descriptor arrays + simple_list m_desc_live_list; // list of live descriptions + fixed_allocator m_desc_allocator; // fixed allocator for descriptions + std::vector m_desc_array; // array of descriptions in PC order +}; + + +#endif /* __DRCFE_H__ */ diff --git a/src/devices/cpu/drcuml.c b/src/devices/cpu/drcuml.c new file mode 100644 index 00000000000..b7e3c3e0045 --- /dev/null +++ b/src/devices/cpu/drcuml.c @@ -0,0 +1,1142 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + drcuml.c + + Universal machine language for dynamic recompiling CPU cores. + +**************************************************************************** + + Future improvements/changes: + + * UML optimizer: + - constant folding + + * Write a back-end validator: + - checks all combinations of memory/register/immediate on all params + - checks behavior of all opcodes + + * Extend registers to 16? Depends on if PPC can use them + + * Support for FPU exceptions + + * New instructions? + - FCOPYI, ICOPYF + copy raw between float and integer registers + + - VALID opcode_desc,handle,param + checksum/compare code referenced by opcode_desc; if not + matching, generate exception with handle,param + + - RECALL handle + change code at caller to call handle in the future + +***************************************************************************/ + +#include "emu.h" +#include "drcuml.h" +#include "drcbec.h" +#include "drcbex86.h" +#include "drcbex64.h" + +using namespace uml; + + + +//************************************************************************** +// DEBUGGING +//************************************************************************** + +#define VALIDATE_BACKEND (0) +#define LOG_SIMPLIFICATIONS (0) + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// structure describing back-end validation test +struct bevalidate_test +{ + opcode_t opcode; + UINT8 size; + UINT8 iflags; + UINT8 flags; + UINT64 param[4]; +}; + + + +//************************************************************************** +// DRC BACKEND INTERFACE +//************************************************************************** + +//------------------------------------------------- +// drcbe_interface - constructor +//------------------------------------------------- + +drcbe_interface::drcbe_interface(drcuml_state &drcuml, drc_cache &cache, device_t &device) + : m_drcuml(drcuml), + m_cache(cache), + m_device(device), + m_state(*(drcuml_machine_state *)cache.alloc_near(sizeof(m_state))), + m_accessors((data_accessors *)cache.alloc_near(sizeof(*m_accessors) * ADDRESS_SPACES)) +{ + // reset the machine state + memset(m_accessors, 0, sizeof(*m_accessors) * ADDRESS_SPACES); + memset(&m_state, 0, sizeof(m_state)); + + // find the spaces and fetch memory accessors + device_memory_interface *memory; + if (device.interface(memory)) + for (address_spacenum spacenum = AS_0; spacenum < ARRAY_LENGTH(m_space); spacenum++) + if (memory->has_space(spacenum)) + { + m_space[spacenum] = &memory->space(spacenum); + m_space[spacenum]->accessors(m_accessors[spacenum]); + } +} + + +//------------------------------------------------- +// ~drcbe_interface - destructor +//------------------------------------------------- + +drcbe_interface::~drcbe_interface() +{ +} + + + +//************************************************************************** +// DRCUML STATE +//************************************************************************** + +//------------------------------------------------- +// drcuml_state - constructor +//------------------------------------------------- + +drcuml_state::drcuml_state(device_t &device, drc_cache &cache, UINT32 flags, int modes, int addrbits, int ignorebits) + : m_device(device), + m_cache(cache), + m_beintf(device.machine().options().drc_use_c() ? + *static_cast(auto_alloc(device.machine(), drcbe_c(*this, device, cache, flags, modes, addrbits, ignorebits))) : + *static_cast(auto_alloc(device.machine(), drcbe_native(*this, device, cache, flags, modes, addrbits, ignorebits)))), + m_umllog(NULL) +{ + // if we're to log, create the logfile + if (device.machine().options().drc_log_uml()) + { + std::string filename = std::string("drcuml_").append(m_device.shortname()).append(".asm"); + m_umllog = fopen(filename.c_str(), "w"); + } +} + + +//------------------------------------------------- +// ~drcuml_state - destructor +//------------------------------------------------- + +drcuml_state::~drcuml_state() +{ + // free the back-end + auto_free(m_device.machine(), &m_beintf); + + // close any files + if (m_umllog != NULL) + fclose(m_umllog); +} + + +//------------------------------------------------- +// reset - reset the state completely, flushing +// the cache and all information +//------------------------------------------------- + +void drcuml_state::reset() +{ + // if we error here, we are screwed + try + { + // flush the cache + m_cache.flush(); + + // reset all handle code pointers + for (code_handle *handle = m_handlelist.first(); handle != NULL; handle = handle->next()) + *handle->m_code = NULL; + + // call the backend to reset + m_beintf.reset(); + + // do a one-time validation if requested +/* if (VALIDATE_BACKEND) + { + static bool validated = false; + if (!validated) + { + validated = true; + validate_backend(this); + } + }*/ + } + catch (drcuml_block::abort_compilation &) + { + fatalerror("Out of cache space in drcuml_state::reset\n"); + } +} + + +//------------------------------------------------- +// begin_block - begin a new code block +//------------------------------------------------- + +drcuml_block *drcuml_state::begin_block(UINT32 maxinst) +{ + // find an inactive block that matches our qualifications + drcuml_block *bestblock = NULL; + for (drcuml_block *block = m_blocklist.first(); block != NULL; block = block->next()) + if (!block->inuse() && block->maxinst() >= maxinst && (bestblock == NULL || block->maxinst() < bestblock->maxinst())) + bestblock = block; + + // if we failed to find one, allocate a new one + if (bestblock == NULL) + bestblock = &m_blocklist.append(*global_alloc(drcuml_block(*this, maxinst * 3/2))); + + // start the block + bestblock->begin(); + return bestblock; +} + + +//------------------------------------------------- +// handle_alloc - allocate a new handle +//------------------------------------------------- + +code_handle *drcuml_state::handle_alloc(const char *name) +{ + // allocate the handle, add it to our list, and return it + return &m_handlelist.append(*global_alloc(code_handle(*this, name))); +} + + +//------------------------------------------------- +// symbol_add - add a symbol to the internal +// symbol table +//------------------------------------------------- + +void drcuml_state::symbol_add(void *base, UINT32 length, const char *name) +{ + m_symlist.append(*global_alloc(symbol(base, length, name))); +} + + +//------------------------------------------------- +// symbol_find - look up a symbol from the +// internal symbol table or return NULL if not +// found +//------------------------------------------------- + +const char *drcuml_state::symbol_find(void *base, UINT32 *offset) +{ + drccodeptr search = drccodeptr(base); + + // simple linear search + for (symbol *cursym = m_symlist.first(); cursym != NULL; cursym = cursym->next()) + if (search >= cursym->m_base && search < cursym->m_base + cursym->m_length) + { + // if no offset pointer, only match perfectly + if (offset == NULL && search != cursym->m_base) + continue; + + // return the offset and name + if (offset != NULL) + *offset = search - cursym->m_base; + return cursym->m_name.c_str(); + } + + // not found; return NULL + return NULL; +} + + +//------------------------------------------------- +// log_printf - directly printf to the UML log +// if generated +//------------------------------------------------- + +void drcuml_state::log_printf(const char *format, ...) +{ + // if we have a file, print to it + if (m_umllog != NULL) + { + va_list va; + + // do the printf + va_start(va, format); + vfprintf(m_umllog, format, va); + va_end(va); + fflush(m_umllog); + } +} + + + +//************************************************************************** +// DRCUML BLOCK +//************************************************************************** + +//------------------------------------------------- +// drcuml_block - constructor +//------------------------------------------------- + +drcuml_block::drcuml_block(drcuml_state &drcuml, UINT32 maxinst) + : m_drcuml(drcuml), + m_next(NULL), + m_nextinst(0), + m_maxinst(maxinst * 3/2), + m_inst(m_maxinst), + m_inuse(false) +{ +} + + +//------------------------------------------------- +// ~drcuml_block - destructor +//------------------------------------------------- + +drcuml_block::~drcuml_block() +{ +} + + +//------------------------------------------------- +// begin - begin code generation +//------------------------------------------------- + +void drcuml_block::begin() +{ + // set up the block information and return it + m_inuse = true; + m_nextinst = 0; +} + + +//------------------------------------------------- +// end - complete a code block and commit it to +// the cache via the back-end +//------------------------------------------------- + +void drcuml_block::end() +{ + assert(m_inuse); + + // optimize the resulting code first + optimize(); + + // if we have a logfile, generate a disassembly of the block + if (m_drcuml.logging()) + disassemble(); + + // generate the code via the back-end + m_drcuml.generate(*this, &m_inst[0], m_nextinst); + + // block is no longer in use + m_inuse = false; +} + + +//------------------------------------------------- +// abort - abort a code block in progress +//------------------------------------------------- + +void drcuml_block::abort() +{ + assert(m_inuse); + + // block is no longer in use + m_inuse = false; + + // unwind + throw abort_compilation(); +} + + +//------------------------------------------------- +// append - append an opcode to the block +//------------------------------------------------- + +uml::instruction &drcuml_block::append() +{ + // get a pointer to the next instruction + instruction &curinst = m_inst[m_nextinst++]; + if (m_nextinst > m_maxinst) + fatalerror("Overran maxinst in drcuml_block_append\n"); + + return curinst; +} + + +//------------------------------------------------- +// comment - attach a comment to the current +// output location in the specified block +//------------------------------------------------- + +void drcuml_block::append_comment(const char *format, ...) +{ + // do the printf + std::string temp; + va_list va; + va_start(va, format); + strvprintf(temp,format, va); + va_end(va); + + // allocate space in the cache to hold the comment + char *comment = (char *)m_drcuml.cache().alloc_temporary(temp.length() + 1); + if (comment == NULL) + return; + strcpy(comment, temp.c_str()); + + // add an instruction with a pointer + append().comment(comment); +} + + +//------------------------------------------------- +// optimize - apply various optimizations to a +// block of code +//------------------------------------------------- + +void drcuml_block::optimize() +{ + UINT32 mapvar[MAPVAR_COUNT] = { 0 }; + + // iterate over instructions + for (int instnum = 0; instnum < m_nextinst; instnum++) + { + instruction &inst = m_inst[instnum]; + + // first compute what flags we need + UINT8 accumflags = 0; + UINT8 remainingflags = inst.output_flags(); + + // scan ahead until we run out of possible remaining flags + for (int scannum = instnum + 1; remainingflags != 0 && scannum < m_nextinst; scannum++) + { + // any input flags are required + const instruction &scan = m_inst[scannum]; + accumflags |= scan.input_flags(); + + // if the scanahead instruction is unconditional, assume his flags are modified + if (scan.condition() == COND_ALWAYS) + remainingflags &= ~scan.modified_flags(); + } + inst.set_flags(accumflags); + + // track mapvars + if (inst.opcode() == OP_MAPVAR) + mapvar[inst.param(0).mapvar() - MAPVAR_M0] = inst.param(1).immediate(); + + // convert all mapvar parameters to immediates + else if (inst.opcode() != OP_RECOVER) + for (int pnum = 0; pnum < inst.numparams(); pnum++) + if (inst.param(pnum).is_mapvar()) + inst.set_mapvar(pnum, mapvar[inst.param(pnum).mapvar() - MAPVAR_M0]); + + // now that flags are correct, simplify the instruction + inst.simplify(); + } +} + + +//------------------------------------------------- +// disassemble - disassemble a block of +// instructions to the log +//------------------------------------------------- + +void drcuml_block::disassemble() +{ + std::string comment; + std::string dasm; + + // iterate over instructions and output + int firstcomment = -1; + for (int instnum = 0; instnum < m_nextinst; instnum++) + { + const instruction &inst = m_inst[instnum]; + bool flushcomments = false; + + // remember comments and mapvars for later + if (inst.opcode() == OP_COMMENT || inst.opcode() == OP_MAPVAR) + { + if (firstcomment == -1) + firstcomment = instnum; + } + + // print labels, handles, and hashes left justified + else if (inst.opcode() == OP_LABEL) + m_drcuml.log_printf("$%X:\n", UINT32(inst.param(0).label())); + else if (inst.opcode() == OP_HANDLE) + m_drcuml.log_printf("%s:\n", inst.param(0).handle().string()); + else if (inst.opcode() == OP_HASH) + m_drcuml.log_printf("(%X,%X):\n", UINT32(inst.param(0).immediate()), UINT32(inst.param(1).immediate())); + + // indent everything else with a tab + else + { + m_inst[instnum].disasm(dasm, &m_drcuml); + + // include the first accumulated comment with this line + if (firstcomment != -1) + { + m_drcuml.log_printf("\t%-50.50s; %s\n", dasm.c_str(), get_comment_text(m_inst[firstcomment], comment)); + firstcomment++; + flushcomments = TRUE; + } + else + m_drcuml.log_printf("\t%s\n", dasm.c_str()); + } + + // flush any comments pending + if (firstcomment != -1 && (flushcomments || instnum == m_nextinst - 1)) + { + while (firstcomment <= instnum) + { + const char *text = get_comment_text(m_inst[firstcomment++], comment); + if (text != NULL) + m_drcuml.log_printf("\t%50s; %s\n", "", text); + } + firstcomment = -1; + } + } + m_drcuml.log_printf("\n\n"); + m_drcuml.log_flush(); +} + + +//------------------------------------------------- +// get_comment_text - determine the text +// associated with a comment or mapvar +//------------------------------------------------- + +const char *drcuml_block::get_comment_text(const instruction &inst, std::string &comment) +{ + // comments return their strings + if (inst.opcode() == OP_COMMENT) + return comment.assign(inst.param(0).string()).c_str(); + + // mapvars comment about their values + else if (inst.opcode() == OP_MAPVAR) { + strprintf(comment,"m%d = $%X", (int)inst.param(0).mapvar() - MAPVAR_M0, (UINT32)inst.param(1).immediate()); + return comment.c_str(); + } + + // everything else is NULL + return NULL; +} + + + +#if 0 + +/*************************************************************************** + BACK-END VALIDATION +***************************************************************************/ + +//------------------------------------------------- +// effective_test_psize - return the effective +// parameter size based on the size and fixed +// array of parameter values +//------------------------------------------------- + +inline UINT8 effective_test_psize(const opcode_info &opinfo, int pnum, int instsize, const UINT64 *params) +{ + switch (opinfo.param[pnum].size) + { + case PSIZE_4: return 4; + case PSIZE_8: return 8; + case PSIZE_OP: return instsize; + case PSIZE_P1: return 1 << (params[0] & 3); + case PSIZE_P2: return 1 << (params[1] & 3); + case PSIZE_P3: return 1 << (params[2] & 3); + case PSIZE_P4: return 1 << (params[3] & 3); + } + return instsize; +} + +#define TEST_ENTRY_2(op, size, p1, p2, flags) { OP_##op, size, 0, flags, { U64(p1), U64(p2) } }, +#define TEST_ENTRY_2F(op, size, p1, p2, iflags, flags) { OP_##op, size, iflags, flags, { U64(p1), U64(p2) } }, +#define TEST_ENTRY_3(op, size, p1, p2, p3, flags) { OP_##op, size, 0, flags, { U64(p1), U64(p2), U64(p3) } }, +#define TEST_ENTRY_3F(op, size, p1, p2, p3, iflags, flags) { OP_##op, size, iflags, flags, { U64(p1), U64(p2), U64(p3) } }, +#define TEST_ENTRY_4(op, size, p1, p2, p3, p4, flags) { OP_##op, size, 0, flags, { U64(p1), U64(p2), U64(p3), U64(p4) } }, +#define TEST_ENTRY_4F(op, size, p1, p2, p3, p4, iflags, flags) { OP_##op, size, iflags, flags, { U64(p1), U64(p2), U64(p3), U64(p4) } }, + +static const bevalidate_test bevalidate_test_list[] = +{ + TEST_ENTRY_3(ADD, 4, 0x7fffffff, 0x12345678, 0x6dcba987, 0) + TEST_ENTRY_3(ADD, 4, 0x80000000, 0x12345678, 0x6dcba988, FLAG_V | FLAG_S) + TEST_ENTRY_3(ADD, 4, 0xffffffff, 0x92345678, 0x6dcba987, FLAG_S) + TEST_ENTRY_3(ADD, 4, 0x00000000, 0x92345678, 0x6dcba988, FLAG_C | FLAG_Z) + + TEST_ENTRY_3(ADD, 8, 0x7fffffffffffffff, 0x0123456789abcdef, 0x7edcba9876543210, 0) + TEST_ENTRY_3(ADD, 8, 0x8000000000000000, 0x0123456789abcdef, 0x7edcba9876543211, FLAG_V | FLAG_S) + TEST_ENTRY_3(ADD, 8, 0xffffffffffffffff, 0x8123456789abcdef, 0x7edcba9876543210, FLAG_S) + TEST_ENTRY_3(ADD, 8, 0x0000000000000000, 0x8123456789abcdef, 0x7edcba9876543211, FLAG_C | FLAG_Z) + + TEST_ENTRY_3F(ADDC, 4, 0x7fffffff, 0x12345678, 0x6dcba987, 0, 0) + TEST_ENTRY_3F(ADDC, 4, 0x7fffffff, 0x12345678, 0x6dcba986, FLAG_C, 0) + TEST_ENTRY_3F(ADDC, 4, 0x80000000, 0x12345678, 0x6dcba988, 0, FLAG_V | FLAG_S) + TEST_ENTRY_3F(ADDC, 4, 0x80000000, 0x12345678, 0x6dcba987, FLAG_C, FLAG_V | FLAG_S) + TEST_ENTRY_3F(ADDC, 4, 0xffffffff, 0x92345678, 0x6dcba987, 0, FLAG_S) + TEST_ENTRY_3F(ADDC, 4, 0xffffffff, 0x92345678, 0x6dcba986, FLAG_C, FLAG_S) + TEST_ENTRY_3F(ADDC, 4, 0x00000000, 0x92345678, 0x6dcba988, 0, FLAG_C | FLAG_Z) + TEST_ENTRY_3F(ADDC, 4, 0x00000000, 0x92345678, 0x6dcba987, FLAG_C, FLAG_C | FLAG_Z) + TEST_ENTRY_3F(ADDC, 4, 0x12345678, 0x12345678, 0xffffffff, FLAG_C, FLAG_C) + + TEST_ENTRY_3F(ADDC, 8, 0x7fffffffffffffff, 0x0123456789abcdef, 0x7edcba9876543210, 0, 0) + TEST_ENTRY_3F(ADDC, 8, 0x7fffffffffffffff, 0x0123456789abcdef, 0x7edcba987654320f, FLAG_C, 0) + TEST_ENTRY_3F(ADDC, 8, 0x8000000000000000, 0x0123456789abcdef, 0x7edcba9876543211, 0, FLAG_V | FLAG_S) + TEST_ENTRY_3F(ADDC, 8, 0x8000000000000000, 0x0123456789abcdef, 0x7edcba9876543210, FLAG_C, FLAG_V | FLAG_S) + TEST_ENTRY_3F(ADDC, 8, 0xffffffffffffffff, 0x8123456789abcdef, 0x7edcba9876543210, 0, FLAG_S) + TEST_ENTRY_3F(ADDC, 8, 0xffffffffffffffff, 0x8123456789abcdef, 0x7edcba987654320f, FLAG_C, FLAG_S) + TEST_ENTRY_3F(ADDC, 8, 0x0000000000000000, 0x8123456789abcdef, 0x7edcba9876543211, 0, FLAG_C | FLAG_Z) + TEST_ENTRY_3F(ADDC, 8, 0x0000000000000000, 0x8123456789abcdef, 0x7edcba9876543210, FLAG_C, FLAG_C | FLAG_Z) + TEST_ENTRY_3F(ADDC, 8, 0x123456789abcdef0, 0x123456789abcdef0, 0xffffffffffffffff, FLAG_C, FLAG_C) + + TEST_ENTRY_3(SUB, 4, 0x12345678, 0x7fffffff, 0x6dcba987, 0) + TEST_ENTRY_3(SUB, 4, 0x12345678, 0x80000000, 0x6dcba988, FLAG_V) + TEST_ENTRY_3(SUB, 4, 0x92345678, 0xffffffff, 0x6dcba987, FLAG_S) + TEST_ENTRY_3(SUB, 4, 0x92345678, 0x00000000, 0x6dcba988, FLAG_C | FLAG_S) + TEST_ENTRY_3(SUB, 4, 0x00000000, 0x12345678, 0x12345678, FLAG_Z) + + TEST_ENTRY_3(SUB, 8, 0x0123456789abcdef, 0x7fffffffffffffff, 0x7edcba9876543210, 0) + TEST_ENTRY_3(SUB, 8, 0x0123456789abcdef, 0x8000000000000000, 0x7edcba9876543211, FLAG_V) + TEST_ENTRY_3(SUB, 8, 0x8123456789abcdef, 0xffffffffffffffff, 0x7edcba9876543210, FLAG_S) + TEST_ENTRY_3(SUB, 8, 0x8123456789abcdef, 0x0000000000000000, 0x7edcba9876543211, FLAG_C | FLAG_S) + TEST_ENTRY_3(SUB, 8, 0x0000000000000000, 0x0123456789abcdef, 0x0123456789abcdef, FLAG_Z) + + TEST_ENTRY_3F(SUBB, 4, 0x12345678, 0x7fffffff, 0x6dcba987, 0, 0) + TEST_ENTRY_3F(SUBB, 4, 0x12345678, 0x7fffffff, 0x6dcba986, FLAG_C, 0) + TEST_ENTRY_3F(SUBB, 4, 0x12345678, 0x80000000, 0x6dcba988, 0, FLAG_V) + TEST_ENTRY_3F(SUBB, 4, 0x12345678, 0x80000000, 0x6dcba987, FLAG_C, FLAG_V) + TEST_ENTRY_3F(SUBB, 4, 0x92345678, 0xffffffff, 0x6dcba987, 0, FLAG_S) + TEST_ENTRY_3F(SUBB, 4, 0x92345678, 0xffffffff, 0x6dcba986, FLAG_C, FLAG_S) + TEST_ENTRY_3F(SUBB, 4, 0x92345678, 0x00000000, 0x6dcba988, 0, FLAG_C | FLAG_S) + TEST_ENTRY_3F(SUBB, 4, 0x92345678, 0x00000000, 0x6dcba987, FLAG_C, FLAG_C | FLAG_S) + TEST_ENTRY_3F(SUBB, 4, 0x12345678, 0x12345678, 0xffffffff, FLAG_C, FLAG_C) + TEST_ENTRY_3F(SUBB, 4, 0x00000000, 0x12345678, 0x12345677, FLAG_C, FLAG_Z) + + TEST_ENTRY_3F(SUBB, 8, 0x0123456789abcdef, 0x7fffffffffffffff, 0x7edcba9876543210, 0, 0) + TEST_ENTRY_3F(SUBB, 8, 0x0123456789abcdef, 0x7fffffffffffffff, 0x7edcba987654320f, FLAG_C, 0) + TEST_ENTRY_3F(SUBB, 8, 0x0123456789abcdef, 0x8000000000000000, 0x7edcba9876543211, 0, FLAG_V) + TEST_ENTRY_3F(SUBB, 8, 0x0123456789abcdef, 0x8000000000000000, 0x7edcba9876543210, FLAG_C, FLAG_V) + TEST_ENTRY_3F(SUBB, 8, 0x8123456789abcdef, 0xffffffffffffffff, 0x7edcba9876543210, 0, FLAG_S) + TEST_ENTRY_3F(SUBB, 8, 0x8123456789abcdef, 0xffffffffffffffff, 0x7edcba987654320f, FLAG_C, FLAG_S) + TEST_ENTRY_3F(SUBB, 8, 0x8123456789abcdef, 0x0000000000000000, 0x7edcba9876543211, 0, FLAG_C | FLAG_S) + TEST_ENTRY_3F(SUBB, 8, 0x8123456789abcdef, 0x0000000000000000, 0x7edcba9876543210, FLAG_C, FLAG_C | FLAG_S) + TEST_ENTRY_3F(SUBB, 8, 0x123456789abcdef0, 0x123456789abcdef0, 0xffffffffffffffff, FLAG_C, FLAG_C) + TEST_ENTRY_3F(SUBB, 8, 0x0000000000000000, 0x123456789abcdef0, 0x123456789abcdeef, FLAG_C, FLAG_Z) + + TEST_ENTRY_2(CMP, 4, 0x7fffffff, 0x6dcba987, 0) + TEST_ENTRY_2(CMP, 4, 0x80000000, 0x6dcba988, FLAG_V) + TEST_ENTRY_2(CMP, 4, 0xffffffff, 0x6dcba987, FLAG_S) + TEST_ENTRY_2(CMP, 4, 0x00000000, 0x6dcba988, FLAG_C | FLAG_S) + TEST_ENTRY_2(CMP, 4, 0x12345678, 0x12345678, FLAG_Z) + + TEST_ENTRY_2(CMP, 8, 0x7fffffffffffffff, 0x7edcba9876543210, 0) + TEST_ENTRY_2(CMP, 8, 0x8000000000000000, 0x7edcba9876543211, FLAG_V) + TEST_ENTRY_2(CMP, 8, 0xffffffffffffffff, 0x7edcba9876543210, FLAG_S) + TEST_ENTRY_2(CMP, 8, 0x0000000000000000, 0x7edcba9876543211, FLAG_C | FLAG_S) + TEST_ENTRY_2(CMP, 8, 0x0123456789abcdef, 0x0123456789abcdef, FLAG_Z) + + TEST_ENTRY_4(MULU, 4, 0x77777777, 0x00000000, 0x11111111, 0x00000007, 0) + TEST_ENTRY_4(MULU, 4, 0xffffffff, 0x00000000, 0x11111111, 0x0000000f, 0) + TEST_ENTRY_4(MULU, 4, 0x00000000, 0x00000000, 0x11111111, 0x00000000, FLAG_Z) + TEST_ENTRY_4(MULU, 4, 0xea61d951, 0x37c048d0, 0x77777777, 0x77777777, FLAG_V) + TEST_ENTRY_4(MULU, 4, 0x32323233, 0xcdcdcdcc, 0xcdcdcdcd, 0xffffffff, FLAG_V | FLAG_S) + + TEST_ENTRY_4(MULU, 8, 0x7777777777777777, 0x0000000000000000, 0x1111111111111111, 0x0000000000000007, 0) + TEST_ENTRY_4(MULU, 8, 0xffffffffffffffff, 0x0000000000000000, 0x1111111111111111, 0x000000000000000f, 0) + TEST_ENTRY_4(MULU, 8, 0x0000000000000000, 0x0000000000000000, 0x1111111111111111, 0x0000000000000000, FLAG_Z) + TEST_ENTRY_4(MULU, 8, 0x0c83fb72ea61d951, 0x37c048d159e26af3, 0x7777777777777777, 0x7777777777777777, FLAG_V) + TEST_ENTRY_4(MULU, 8, 0x3232323232323233, 0xcdcdcdcdcdcdcdcc, 0xcdcdcdcdcdcdcdcd, 0xffffffffffffffff, FLAG_V | FLAG_S) + + TEST_ENTRY_4(MULS, 4, 0x77777777, 0x00000000, 0x11111111, 0x00000007, 0) + TEST_ENTRY_4(MULS, 4, 0xffffffff, 0x00000000, 0x11111111, 0x0000000f, FLAG_V) + TEST_ENTRY_4(MULS, 4, 0x00000000, 0x00000000, 0x11111111, 0x00000000, FLAG_Z) + TEST_ENTRY_4(MULS, 4, 0x9e26af38, 0xc83fb72e, 0x77777777, 0x88888888, FLAG_V | FLAG_S) + TEST_ENTRY_4(MULS, 4, 0x32323233, 0x00000000, 0xcdcdcdcd, 0xffffffff, 0) + + TEST_ENTRY_4(MULS, 8, 0x7777777777777777, 0x0000000000000000, 0x1111111111111111, 0x0000000000000007, 0) + TEST_ENTRY_4(MULS, 8, 0xffffffffffffffff, 0x0000000000000000, 0x1111111111111111, 0x000000000000000f, FLAG_V) + TEST_ENTRY_4(MULS, 8, 0x0000000000000000, 0x0000000000000000, 0x1111111111111111, 0x0000000000000000, FLAG_Z) + TEST_ENTRY_4(MULS, 8, 0x7c048d159e26af38, 0xc83fb72ea61d950c, 0x7777777777777777, 0x8888888888888888, FLAG_V | FLAG_S) + TEST_ENTRY_4(MULS, 8, 0x3232323232323233, 0x0000000000000000, 0xcdcdcdcdcdcdcdcd, 0xffffffffffffffff, 0) + + TEST_ENTRY_4(DIVU, 4, 0x02702702, 0x00000003, 0x11111111, 0x00000007, 0) + TEST_ENTRY_4(DIVU, 4, 0x00000000, 0x11111111, 0x11111111, 0x11111112, FLAG_Z) + TEST_ENTRY_4(DIVU, 4, 0x7fffffff, 0x00000000, 0xfffffffe, 0x00000002, 0) + TEST_ENTRY_4(DIVU, 4, 0xfffffffe, 0x00000000, 0xfffffffe, 0x00000001, FLAG_S) + TEST_ENTRY_4(DIVU, 4, UNDEFINED, UNDEFINED, 0xffffffff, 0x00000000, FLAG_V) + + TEST_ENTRY_4(DIVU, 8, 0x0270270270270270, 0x0000000000000001, 0x1111111111111111, 0x0000000000000007, 0) + TEST_ENTRY_4(DIVU, 8, 0x0000000000000000, 0x1111111111111111, 0x1111111111111111, 0x1111111111111112, FLAG_Z) + TEST_ENTRY_4(DIVU, 8, 0x7fffffffffffffff, 0x0000000000000000, 0xfffffffffffffffe, 0x0000000000000002, 0) + TEST_ENTRY_4(DIVU, 8, 0xfffffffffffffffe, 0x0000000000000000, 0xfffffffffffffffe, 0x0000000000000001, FLAG_S) + TEST_ENTRY_4(DIVU, 8, UNDEFINED, UNDEFINED, 0xffffffffffffffff, 0x0000000000000000, FLAG_V) + + TEST_ENTRY_4(DIVS, 4, 0x02702702, 0x00000003, 0x11111111, 0x00000007, 0) + TEST_ENTRY_4(DIVS, 4, 0x00000000, 0x11111111, 0x11111111, 0x11111112, FLAG_Z) + TEST_ENTRY_4(DIVS, 4, 0xffffffff, 0x00000000, 0xfffffffe, 0x00000002, FLAG_S) + TEST_ENTRY_4(DIVS, 4, UNDEFINED, UNDEFINED, 0xffffffff, 0x00000000, FLAG_V) + + TEST_ENTRY_4(DIVS, 8, 0x0270270270270270, 0x0000000000000001, 0x1111111111111111, 0x0000000000000007, 0) + TEST_ENTRY_4(DIVS, 8, 0x0000000000000000, 0x1111111111111111, 0x1111111111111111, 0x1111111111111112, FLAG_Z) + TEST_ENTRY_4(DIVS, 8, 0xffffffffffffffff, 0x0000000000000000, 0xfffffffffffffffe, 0x0000000000000002, FLAG_S) + TEST_ENTRY_4(DIVS, 8, UNDEFINED, UNDEFINED, 0xffffffffffffffff, 0x0000000000000000, FLAG_V) +}; + + +/*------------------------------------------------- + validate_backend - execute a number of + generic tests on the backend code generator +-------------------------------------------------*/ + +static void validate_backend(drcuml_state *drcuml) +{ + code_handle *handles[3]; + int tnum; + + // allocate handles for the code + handles[0] = drcuml->handle_alloc("test_entry"); + handles[1] = drcuml->handle_alloc("code_start"); + handles[2] = drcuml->handle_alloc("code_end"); + + // iterate over test entries + printf("Backend validation....\n"); + for (tnum = 31; tnum < ARRAY_LENGTH(bevalidate_test_list); tnum++) + { + const bevalidate_test *test = &bevalidate_test_list[tnum]; + parameter param[ARRAY_LENGTH(test->param)]; + char mnemonic[20], *dst; + const char *src; + + // progress + dst = mnemonic; + for (src = opcode_info_table[test->opcode()]->mnemonic; *src != 0; src++) + { + if (*src == '!') + { + if (test->size == 8) + *dst++ = 'd'; + } + else if (*src == '#') + *dst++ = (test->size == 8) ? 'd' : 's'; + else + *dst++ = *src; + } + *dst = 0; + printf("Executing test %d/%d (%s)", tnum + 1, (int)ARRAY_LENGTH(bevalidate_test_list), mnemonic); + + // reset parameter list and iterate + memset(param, 0, sizeof(param)); + bevalidate_iterate_over_params(drcuml, handles, test, param, 0); + printf("\n"); + } + fatalerror("All tests passed!\n"); +} + + +/*------------------------------------------------- + bevalidate_iterate_over_params - iterate over + all supported types and values of a parameter + and recursively hand off to the next parameter, + or else move on to iterate over the flags +-------------------------------------------------*/ + +static void bevalidate_iterate_over_params(drcuml_state *drcuml, code_handle **handles, const bevalidate_test *test, parameter *paramlist, int pnum) +{ + const opcode_info *opinfo = opcode_info_table[test->opcode()]; + drcuml_ptype ptype; + + // if no parameters, execute now + if (pnum >= ARRAY_LENGTH(opinfo->param) || opinfo->param[pnum].typemask == PTYPES_NONE) + { + bevalidate_iterate_over_flags(drcuml, handles, test, paramlist); + return; + } + + // iterate over valid parameter types + for (ptype = parameter::PTYPE_IMMEDIATE; ptype < parameter::PTYPE_MAX; ptype++) + if (opinfo->param[pnum].typemask & (1 << ptype)) + { + int pindex, pcount; + + // mapvars can only do 32-bit tests + if (ptype == parameter::PTYPE_MAPVAR && effective_test_psize(opinfo, pnum, test->size, test->param) == 8) + continue; + + // for some parameter types, we wish to iterate over all possibilities + switch (ptype) + { + case parameter::PTYPE_INT_REGISTER: pcount = REG_I_END - REG_I0; break; + case parameter::PTYPE_FLOAT_REGISTER: pcount = REG_F_END - REG_F0; break; + default: pcount = 1; break; + } + + // iterate over possibilities + for (pindex = 0; pindex < pcount; pindex++) + { + int skip = FALSE; + int pscannum; + + // for param 0, print a dot + if (pnum == 0) + printf("."); + + // can't duplicate multiple source parameters unless they are immediates + if (ptype != parameter::PTYPE_IMMEDIATE && (opinfo->param[pnum].output & PIO_IN)) + + // loop over all parameters we've done before; if the parameter is a source and matches us, skip this case + for (pscannum = 0; pscannum < pnum; pscannum++) + if ((opinfo->param[pscannum].output & PIO_IN) && ptype == paramlist[pscannum].type && pindex == paramlist[pscannum].value) + skip = TRUE; + + // can't duplicate multiple dest parameters + if (opinfo->param[pnum].output & PIO_OUT) + + // loop over all parameters we've done before; if the parameter is a source and matches us, skip this case + for (pscannum = 0; pscannum < pnum; pscannum++) + if ((opinfo->param[pscannum].output & PIO_OUT) && ptype == paramlist[pscannum].type && pindex == paramlist[pscannum].value) + skip = TRUE; + + // iterate over the next parameter in line + if (!skip) + { + paramlist[pnum].type = ptype; + paramlist[pnum].value = pindex; + bevalidate_iterate_over_params(drcuml, handles, test, paramlist, pnum + 1); + } + } + } +} + + +/*------------------------------------------------- + bevalidate_iterate_over_flags - iterate over + all supported flag masks +-------------------------------------------------*/ + +static void bevalidate_iterate_over_flags(drcuml_state *drcuml, code_handle **handles, const bevalidate_test *test, parameter *paramlist) +{ + const opcode_info *opinfo = opcode_info_table[test->opcode()]; + UINT8 flagmask = opinfo->outflags; + UINT8 curmask; + + // iterate over all possible flag combinations + for (curmask = 0; curmask <= flagmask; curmask++) + if ((curmask & flagmask) == curmask) + bevalidate_execute(drcuml, handles, test, paramlist, curmask); +} + + +/*------------------------------------------------- + bevalidate_execute - execute a single instance + of a test, generating code and verifying the + results +-------------------------------------------------*/ + +static void bevalidate_execute(drcuml_state *drcuml, code_handle **handles, const bevalidate_test *test, const parameter *paramlist, UINT8 flagmask) +{ + parameter params[ARRAY_LENGTH(test->param)]; + drcuml_machine_state istate, fstate; + instruction testinst; + drcuml_block *block; + UINT64 *parammem; + int numparams; + + // allocate memory for parameters + parammem = (UINT64 *)drcuml->cache->alloc_near(sizeof(UINT64) * (ARRAY_LENGTH(test->param) + 1)); + + // flush the cache + drcuml->reset(); + + // start a new block + block = drcuml->block_begin(30); + UML_HANDLE(block, handles[0]); + + // set up a random initial state + bevalidate_initialize_random_state(drcuml, block, &istate); + + // then populate the state with the parameters + numparams = bevalidate_populate_state(block, &istate, test, paramlist, params, parammem); + + // generate the code + UML_RESTORE(block, &istate); + UML_HANDLE(block, handles[1]); + switch (numparams) + { + case 0: + block->append(test->opcode(), test->size); + break; + + case 1: + block->append(test->opcode(), test->size, params[0]); + break; + + case 2: + block->append(test->opcode(), test->size, params[0], params[1]); + break; + + case 3: + block->append(test->opcode(), test->size, params[0], params[1], params[2]); + break; + + case 4: + block->append(test->opcode(), test->size, params[0], params[1], params[2], params[3]); + break; + } + testinst = block->inst[block->nextinst - 1]; + UML_HANDLE(block, handles[2]); + UML_GETFLGS(block, MEM(¶mmem[ARRAY_LENGTH(test->param)]), flagmask); + UML_SAVE(block, &fstate); + UML_EXIT(block, IMM(0)); + + // end the block + block->end(); + + // execute + drcuml->execute(*handles[0]); + + // verify the results + bevalidate_verify_state(drcuml, &istate, &fstate, test, *(UINT32 *)¶mmem[ARRAY_LENGTH(test->param)], params, &testinst, handles[1]->code, handles[2]->code, flagmask); + + // free memory + drcuml->cache->dealloc(parammem, sizeof(UINT64) * (ARRAY_LENGTH(test->param) + 1)); +} + + +/*------------------------------------------------- + bevalidate_initialize_random_state - + initialize the machine state to randomness +-------------------------------------------------*/ + +static void bevalidate_initialize_random_state(drcuml_state *drcuml, drcuml_block *block, drcuml_machine_state *state) +{ + running_machine &machine = drcuml->device->machine(); + int regnum; + + // initialize core state to random values + state->fmod = machine.rand() & 0x03; + state->flags = machine.rand() & 0x1f; + state->exp = machine.rand(); + + // initialize integer registers to random values + for (regnum = 0; regnum < ARRAY_LENGTH(state->r); regnum++) + { + state->r[regnum].w.h = machine.rand(); + state->r[regnum].w.l = machine.rand(); + } + + // initialize float registers to random values + for (regnum = 0; regnum < ARRAY_LENGTH(state->f); regnum++) + { + *(UINT32 *)&state->f[regnum].s.h = machine.rand(); + *(UINT32 *)&state->f[regnum].s.l = machine.rand(); + } + + // initialize map variables to random values + for (regnum = 0; regnum < MAPVAR_COUNT; regnum++) + UML_MAPVAR(block, MVAR(regnum), machine.rand()); +} + + +/*------------------------------------------------- + bevalidate_populate_state - populate the + machine state with the proper values prior + to executing a test +-------------------------------------------------*/ + +static int bevalidate_populate_state(drcuml_block *block, drcuml_machine_state *state, const bevalidate_test *test, const parameter *paramlist, parameter *params, UINT64 *parammem) +{ + const opcode_info *opinfo = opcode_info_table[test->opcode()]; + int numparams = ARRAY_LENGTH(test->param); + int pnum; + + // copy flags as-is + state->flags = test->iflags; + + // iterate over parameters + for (pnum = 0; pnum < ARRAY_LENGTH(test->param); pnum++) + { + int psize = effective_test_psize(opinfo, pnum, test->size, test->param); + parameter *curparam = ¶ms[pnum]; + + // start with a copy of the parameter from the list + *curparam = paramlist[pnum]; + + // switch off the type + switch (curparam->type) + { + // immediate parameters: take the value from the test entry + case parameter::PTYPE_IMMEDIATE: + curparam->value = test->param[pnum]; + break; + + // register parameters: set the register value in the state and set the parameter value to the register index + case parameter::PTYPE_INT_REGISTER: + state->r[curparam->value].d = test->param[pnum]; + curparam->value += REG_I0; + break; + + // register parameters: set the register value in the state and set the parameter value to the register index + case parameter::PTYPE_FLOAT_REGISTER: + state->f[curparam->value].d = test->param[pnum]; + curparam->value += REG_F0; + break; + + // memory parameters: set the memory value in the parameter space and set the parameter value to point to it + case parameter::PTYPE_MEMORY: + curparam->value = (FPTR)¶mmem[pnum]; + if (psize == 4) + *(UINT32 *)(FPTR)curparam->value = test->param[pnum]; + else + *(UINT64 *)(FPTR)curparam->value = test->param[pnum]; + break; + + // map variables: issue a MAPVAR instruction to set the value and set the parameter value to the mapvar index + case parameter::PTYPE_MAPVAR: + UML_MAPVAR(block, MVAR(curparam->value), test->param[pnum]); + curparam->value += MAPVAR_M0; + break; + + // use anything else to count the number of parameters + default: + numparams = MIN(numparams, pnum); + break; + } + } + + // return the total number of parameters + return numparams; +} + + +/*------------------------------------------------- + bevalidate_verify_state - verify the final + state after executing a test, and report any + discrepancies +-------------------------------------------------*/ + +static int bevalidate_verify_state(drcuml_state *drcuml, const drcuml_machine_state *istate, drcuml_machine_state *state, const bevalidate_test *test, UINT32 flags, const parameter *params, const instruction *testinst, drccodeptr codestart, drccodeptr codeend, UINT8 flagmask) +{ + const opcode_info *opinfo = opcode_info_table[test->opcode()]; + UINT8 ireg[REG_I_END - REG_I0] = { 0 }; + UINT8 freg[REG_F_END - REG_F0] = { 0 }; + char errorbuf[1024]; + char *errend = errorbuf; + int pnum, regnum; + + *errend = 0; + + // check flags + if (flags != (test->flags & flagmask)) + { + errend += sprintf(errend, " Flags ... result:%c%c%c%c%c expected:%c%c%c%c%c\n", + (flagmask & FLAG_U) ? ((flags & FLAG_U) ? 'U' : '.') : '-', + (flagmask & FLAG_S) ? ((flags & FLAG_S) ? 'S' : '.') : '-', + (flagmask & FLAG_Z) ? ((flags & FLAG_Z) ? 'Z' : '.') : '-', + (flagmask & FLAG_V) ? ((flags & FLAG_V) ? 'V' : '.') : '-', + (flagmask & FLAG_C) ? ((flags & FLAG_C) ? 'C' : '.') : '-', + (flagmask & FLAG_U) ? ((test->flags & FLAG_U) ? 'U' : '.') : '-', + (flagmask & FLAG_S) ? ((test->flags & FLAG_S) ? 'S' : '.') : '-', + (flagmask & FLAG_Z) ? ((test->flags & FLAG_Z) ? 'Z' : '.') : '-', + (flagmask & FLAG_V) ? ((test->flags & FLAG_V) ? 'V' : '.') : '-', + (flagmask & FLAG_C) ? ((test->flags & FLAG_C) ? 'C' : '.') : '-'); + } + + // check destination parameters + for (pnum = 0; pnum < ARRAY_LENGTH(test->param); pnum++) + if (opinfo->param[pnum].output & PIO_OUT) + { + int psize = effective_test_psize(opinfo, pnum, test->size, test->param); + UINT64 mask = U64(0xffffffffffffffff) >> (64 - 8 * psize); + UINT64 result = 0; + + // fetch the result from the parameters + switch (params[pnum].type) + { + // integer registers fetch from the state + case parameter::PTYPE_INT_REGISTER: + ireg[params[pnum].value - REG_I0] = 1; + result = state->r[params[pnum].value - REG_I0].d; + break; + + // float registers fetch from the state + case parameter::PTYPE_FLOAT_REGISTER: + freg[params[pnum].value - REG_I0] = 1; + result = state->f[params[pnum].value - REG_F0].d; + break; + + // memory registers fetch from the memory address + case parameter::PTYPE_MEMORY: + if (psize == 4) + result = *(UINT32 *)(FPTR)params[pnum].value; + else + result = *(UINT64 *)(FPTR)params[pnum].value; + break; + + default: + break; + } + + // check against the mask + if (test->param[pnum] != UNDEFINED_U64 && (result & mask) != (test->param[pnum] & mask)) + { + if ((UINT32)mask == mask) + errend += sprintf(errend, " Parameter %d ... result:%08X expected:%08X\n", pnum, + (UINT32)(result & mask), (UINT32)(test->param[pnum] & mask)); + else + errend += sprintf(errend, " Parameter %d ... result:%08X%08X expected:%08X%08X\n", pnum, + (UINT32)((result & mask) >> 32), (UINT32)(result & mask), + (UINT32)((test->param[pnum] & mask) >> 32), (UINT32)(test->param[pnum] & mask)); + } + } + + // check source integer parameters for unexpected alterations + for (regnum = 0; regnum < ARRAY_LENGTH(state->r); regnum++) + if (ireg[regnum] == 0 && istate->r[regnum].d != state->r[regnum].d) + errend += sprintf(errend, " Register i%d ... result:%08X%08X originally:%08X%08X\n", regnum, + (UINT32)(state->r[regnum].d >> 32), (UINT32)state->r[regnum].d, + (UINT32)(istate->r[regnum].d >> 32), (UINT32)istate->r[regnum].d); + + // check source float parameters for unexpected alterations + for (regnum = 0; regnum < ARRAY_LENGTH(state->f); regnum++) + if (freg[regnum] == 0 && *(UINT64 *)&istate->f[regnum].d != *(UINT64 *)&state->f[regnum].d) + errend += sprintf(errend, " Register f%d ... result:%08X%08X originally:%08X%08X\n", regnum, + (UINT32)(*(UINT64 *)&state->f[regnum].d >> 32), (UINT32)*(UINT64 *)&state->f[regnum].d, + (UINT32)(*(UINT64 *)&istate->f[regnum].d >> 32), (UINT32)*(UINT64 *)&istate->f[regnum].d); + + // output the error if we have one + if (errend != errorbuf) + { + char disasm[256]; + + // disassemble the test instruction + testinst->disasm(disasm, drcuml); + + // output a description of what went wrong + printf("\n"); + printf("----------------------------------------------\n"); + printf("Backend validation error:\n"); + printf(" %s\n", disasm); + printf("\n"); + printf("Errors:\n"); + printf("%s\n", errorbuf); + fatalerror("Error during validation\n"); + } + return errend != errorbuf; +} + +#endif diff --git a/src/devices/cpu/drcuml.h b/src/devices/cpu/drcuml.h new file mode 100644 index 00000000000..10652a224cc --- /dev/null +++ b/src/devices/cpu/drcuml.h @@ -0,0 +1,238 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + drcuml.h + + Universal machine language for dynamic recompiling CPU cores. + +***************************************************************************/ + +#pragma once + +#ifndef __DRCUML_H__ +#define __DRCUML_H__ + +#include "drccache.h" +#include "uml.h" + + +//************************************************************************** +// CONSTANTS +//************************************************************************** + +// these options are passed into drcuml_alloc() and control global behaviors + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// determine the type of the native DRC, falling back to C +#ifndef NATIVE_DRC +class drcbe_c; +typedef drcbe_c drcbe_native; +#else +class NATIVE_DRC; +typedef NATIVE_DRC drcbe_native; +#endif + + +// opaque structure describing UML generation state +class drcuml_state; + + +// an integer register, with low/high parts +union drcuml_ireg +{ +#ifdef LSB_FIRST + struct { UINT32 l,h; } w; // 32-bit low, high parts of the register +#else + struct { UINT32 h,l; } w; // 32-bit low, high parts of the register +#endif + UINT64 d; // 64-bit full register +}; + + +// a floating-point register, with low/high parts +union drcuml_freg +{ +#ifdef LSB_FIRST + struct { float l,h; } s; // 32-bit low, high parts of the register +#else + struct { float h,l; } s; // 32-bit low, high parts of the register +#endif + double d; // 64-bit full register +}; + + +// the collected machine state of a system +struct drcuml_machine_state +{ + drcuml_ireg r[uml::REG_I_COUNT]; // integer registers + drcuml_freg f[uml::REG_F_COUNT]; // floating-point registers + UINT32 exp; // exception parameter register + UINT8 fmod; // fmod (floating-point mode) register + UINT8 flags; // flags state +}; + + +// hints and information about the back-end +struct drcbe_info +{ + UINT8 direct_iregs; // number of direct-mapped integer registers + UINT8 direct_fregs; // number of direct-mapped floating point registers +}; + + +// a drcuml_block describes a basic block of instructions +class drcuml_block +{ + friend class simple_list; + +public: + // construction/destruction + drcuml_block(drcuml_state &drcuml, UINT32 maxinst); + ~drcuml_block(); + + // getters + drcuml_block *next() const { return m_next; } + bool inuse() const { return m_inuse; } + UINT32 maxinst() const { return m_maxinst; } + + // code generation + void begin(); + void end(); + void abort(); + + // instruction appending + uml::instruction &append(); + void append_comment(const char *format, ...) ATTR_PRINTF(2,3); + + // this class is thrown if abort() is called + class abort_compilation : public emu_exception + { + friend class drcuml_block; + abort_compilation() { } + }; + +private: + // internal helpers + void optimize(); + void disassemble(); + const char *get_comment_text(const uml::instruction &inst, std::string &comment); + + // internal state + drcuml_state & m_drcuml; // pointer back to the owning UML + drcuml_block * m_next; // pointer to next block + UINT32 m_nextinst; // next instruction to fill in the cache + UINT32 m_maxinst; // maximum number of instructions + std::vector m_inst; // pointer to the instruction list + bool m_inuse; // this block is in use +}; + + +// interface structure for a back-end +class drcbe_interface +{ +public: + // construction/destruction + drcbe_interface(drcuml_state &drcuml, drc_cache &cache, device_t &device); + virtual ~drcbe_interface(); + + // required overrides + virtual void reset() = 0; + virtual int execute(uml::code_handle &entry) = 0; + virtual void generate(drcuml_block &block, const uml::instruction *instlist, UINT32 numinst) = 0; + virtual bool hash_exists(UINT32 mode, UINT32 pc) = 0; + virtual void get_info(drcbe_info &info) = 0; + virtual bool logging() const { return false; } + +protected: + // internal state + drcuml_state & m_drcuml; // pointer back to our owner + drc_cache & m_cache; // pointer to the cache + device_t & m_device; // CPU device we are associated with + address_space * m_space[ADDRESS_SPACES];// pointers to CPU's address space + drcuml_machine_state & m_state; // state of the machine (in near cache) + data_accessors * m_accessors; // memory accessors (in near cache) +}; + + +// structure describing UML generation state +class drcuml_state +{ +public: + // construction/destruction + drcuml_state(device_t &device, drc_cache &cache, UINT32 flags, int modes, int addrbits, int ignorebits); + ~drcuml_state(); + + // getters + device_t &device() const { return m_device; } + drc_cache &cache() const { return m_cache; } + + // reset the state + void reset(); + int execute(uml::code_handle &entry) { return m_beintf.execute(entry); } + + // code generation + drcuml_block *begin_block(UINT32 maxinst); + + // back-end interface + void get_backend_info(drcbe_info &info) { m_beintf.get_info(info); } + bool hash_exists(UINT32 mode, UINT32 pc) { return m_beintf.hash_exists(mode, pc); } + void generate(drcuml_block &block, uml::instruction *instructions, UINT32 count) { m_beintf.generate(block, instructions, count); } + + // handle management + uml::code_handle *handle_alloc(const char *name); + + // symbol management + void symbol_add(void *base, UINT32 length, const char *name); + const char *symbol_find(void *base, UINT32 *offset = NULL); + + // logging + bool logging() const { return (m_umllog != NULL); } + void log_printf(const char *format, ...) ATTR_PRINTF(2,3); + void log_flush() { if (logging()) fflush(m_umllog); } + bool logging_native() const { return m_beintf.logging(); } + +private: + // symbol class + class symbol + { + friend class drcuml_state; + friend class simple_list; + + // construction/destruction + symbol(void *base, UINT32 length, const char *name) + : m_next(NULL), + m_base(drccodeptr(base)), + m_length(length), + m_name(name) { } + + public: + // getters + symbol *next() const { return m_next; } + + private: + // internal state + symbol * m_next; // link to the next symbol + drccodeptr m_base; // base of the symbol + UINT32 m_length; // length of the region covered + std::string m_name; // name of the symbol + }; + + // internal state + device_t & m_device; // CPU device we are associated with + drc_cache & m_cache; // pointer to the codegen cache + drcbe_interface & m_beintf; // backend interface pointer + FILE * m_umllog; // handle to the UML logfile + simple_list m_blocklist; // list of active blocks + simple_list m_handlelist; // list of active handles + simple_list m_symlist; // list of symbols +}; + + + +#endif /* __DRCUML_H__ */ diff --git a/src/devices/cpu/drcumlsh.h b/src/devices/cpu/drcumlsh.h new file mode 100644 index 00000000000..d14c1321d9e --- /dev/null +++ b/src/devices/cpu/drcumlsh.h @@ -0,0 +1,184 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + drcumlsh.h + + Shorthand definitions for the universal machine language. + +***************************************************************************/ + +#pragma once + +#ifndef __DRCUMLSH_H__ +#define __DRCUMLSH_H__ + +#include "drcuml.h" + + + +/*************************************************************************** + INLINE FUNCTIONS +***************************************************************************/ + +/* ----- Compile-time Opcodes ----- */ +#define UML_HANDLE(block, _handle) do { block->append().handle(_handle); } while (0) +#define UML_HASH(block, mode, pc) do { block->append().hash(mode, pc); } while (0) +#define UML_LABEL(block, _label) do { block->append().label(_label); } while (0) +#define UML_MAPVAR(block, _mapvar, _value) do { block->append().mapvar(_mapvar, _value); } while (0) + + +/* ----- Control Flow Operations ----- */ +#define UML_NOP(block) do { block->append().nop(); } while (0) +#define UML_DEBUG(block, pc) do { block->append().debug(pc); } while (0) +#define UML_EXIT(block, param) do { block->append().exit(param); } while (0) +#define UML_EXITc(block, cond, param) do { block->append().exit(param, cond); } while (0) +#define UML_HASHJMP(block, mode, pc, handle) do { block->append().hashjmp(mode, pc, handle); } while (0) +#define UML_JMP(block, label) do { block->append().jmp(label); } while (0) +#define UML_JMPc(block, cond, label) do { block->append().jmp(cond, label); } while (0) +#define UML_JMPH(block, handle) do { block->append().jmph(handle); } while (0) +#define UML_JMPHc(block, cond, handle) do { block->append().jmph(cond, handle); } while (0) +#define UML_EXH(block, handle, param) do { block->append().exh(handle, param); } while (0) +#define UML_EXHc(block, cond, handle, param) do { block->append().exh(cond, handle, param); } while (0) +#define UML_CALLH(block, handle) do { block->append().callh(handle); } while (0) +#define UML_CALLHc(block, cond, handle) do { block->append().callh(cond, handle); } while (0) +#define UML_RET(block) do { block->append().ret(); } while (0) +#define UML_RETc(block, cond) do { block->append().ret(cond); } while (0) +#define UML_CALLC(block, func, ptr) do { block->append().callc(func, ptr); } while (0) +#define UML_CALLCc(block, cond, func, ptr) do { block->append().callc(cond, func, ptr); } while (0) +#define UML_RECOVER(block, dst, mapvar) do { block->append().recover(dst, mapvar); } while (0) + + +/* ----- Internal Register Operations ----- */ +#define UML_SETFMOD(block, mode) do { block->append().setfmod(mode); } while (0) +#define UML_GETFMOD(block, dst) do { block->append().getfmod(dst); } while (0) +#define UML_GETEXP(block, dst) do { block->append().getexp(dst); } while (0) +#define UML_GETFLGS(block, dst, flags) do { block->append().getflgs(dst, flags); } while (0) +#define UML_SAVE(block, dst) do { block->append().save(dst); } while (0) +#define UML_RESTORE(block, src) do { block->append().restore(src); } while (0) + + +/* ----- 32-Bit Integer Operations ----- */ +#define UML_LOAD(block, dst, base, index, size, scale) do { block->append().load(dst, base, index, size, scale); } while (0) +#define UML_LOADS(block, dst, base, index, size, scale) do { block->append().loads(dst, base, index, size, scale); } while (0) +#define UML_STORE(block, base, index, src1, size, scale) do { block->append().store(base, index, src1, size, scale); } while (0) +#define UML_READ(block, dst, src1, size, space) do { block->append().read(dst, src1, size, space); } while (0) +#define UML_READM(block, dst, src1, mask, size, space) do { block->append().readm(dst, src1, mask, size, space); } while (0) +#define UML_WRITE(block, dst, src1, size, space) do { block->append().write(dst, src1, size, space); } while (0) +#define UML_WRITEM(block, dst, src1, mask, size, space) do { block->append().writem(dst, src1, mask, size, space); } while (0) +#define UML_CARRY(block, src, bitnum) do { block->append().carry(src, bitnum); } while (0) +#define UML_SETc(block, cond, dst) do { block->append().set(cond, dst); } while (0) +#define UML_MOV(block, dst, src1) do { block->append().mov(dst, src1); } while (0) +#define UML_MOVc(block, cond, dst, src1) do { block->append().mov(cond, dst, src1); } while (0) +#define UML_SEXT(block, dst, src1, size) do { block->append().sext(dst, src1, size); } while (0) +#define UML_ROLAND(block, dst, src, shift, mask) do { block->append().roland(dst, src, shift, mask); } while (0) +#define UML_ROLINS(block, dst, src, shift, mask) do { block->append().rolins(dst, src, shift, mask); } while (0) +#define UML_ADD(block, dst, src1, src2) do { block->append().add(dst, src1, src2); } while (0) +#define UML_ADDC(block, dst, src1, src2) do { block->append().addc(dst, src1, src2); } while (0) +#define UML_SUB(block, dst, src1, src2) do { block->append().sub(dst, src1, src2); } while (0) +#define UML_SUBB(block, dst, src1, src2) do { block->append().subb(dst, src1, src2); } while (0) +#define UML_CMP(block, src1, src2) do { block->append().cmp(src1, src2); } while (0) +#define UML_MULU(block, dst, edst, src1, src2) do { block->append().mulu(dst, edst, src1, src2); } while (0) +#define UML_MULS(block, dst, edst, src1, src2) do { block->append().muls(dst, edst, src1, src2); } while (0) +#define UML_DIVU(block, dst, edst, src1, src2) do { block->append().divu(dst, edst, src1, src2); } while (0) +#define UML_DIVS(block, dst, edst, src1, src2) do { block->append().divs(dst, edst, src1, src2); } while (0) +#define UML_AND(block, dst, src1, src2) do { block->append()._and(dst, src1, src2); } while (0) +#define UML_TEST(block, src1, src2) do { block->append().test(src1, src2); } while (0) +#define UML_OR(block, dst, src1, src2) do { block->append()._or(dst, src1, src2); } while (0) +#define UML_XOR(block, dst, src1, src2) do { block->append()._xor(dst, src1, src2); } while (0) +#define UML_LZCNT(block, dst, src) do { block->append().lzcnt(dst, src); } while (0) +#define UML_BSWAP(block, dst, src) do { block->append().bswap(dst, src); } while (0) +#define UML_SHL(block, dst, src, count) do { block->append().shl(dst, src, count); } while (0) +#define UML_SHR(block, dst, src, count) do { block->append().shr(dst, src, count); } while (0) +#define UML_SAR(block, dst, src, count) do { block->append().sar(dst, src, count); } while (0) +#define UML_ROL(block, dst, src, count) do { block->append().rol(dst, src, count); } while (0) +#define UML_ROLC(block, dst, src, count) do { block->append().rolc(dst, src, count); } while (0) +#define UML_ROR(block, dst, src, count) do { block->append().ror(dst, src, count); } while (0) +#define UML_RORC(block, dst, src, count) do { block->append().rorc(dst, src, count); } while (0) + + +/* ----- 64-Bit Integer Operations ----- */ +#define UML_DLOAD(block, dst, base, index, size, scale) do { block->append().dload(dst, base, index, size, scale); } while (0) +#define UML_DLOADS(block, dst, base, index, size, scale) do { block->append().dloads(dst, base, index, size, scale); } while (0) +#define UML_DSTORE(block, base, index, src1, size, scale) do { block->append().dstore(base, index, src1, size, scale); } while (0) +#define UML_DREAD(block, dst, src1, size, space) do { block->append().dread(dst, src1, size, space); } while (0) +#define UML_DREADM(block, dst, src1, mask, size, space) do { block->append().dreadm(dst, src1, mask, size, space); } while (0) +#define UML_DWRITE(block, dst, src1, size, space) do { block->append().dwrite(dst, src1, size, space); } while (0) +#define UML_DWRITEM(block, dst, src1, mask, size, space) do { block->append().dwritem(dst, src1, mask, size, space); } while (0) +#define UML_DCARRY(block, src, bitnum) do { block->append().dcarry(src, bitnum); } while (0) +#define UML_DSETc(block, cond, dst) do { block->append().dset(cond, dst); } while (0) +#define UML_DMOV(block, dst, src1) do { block->append().dmov(dst, src1); } while (0) +#define UML_DMOVc(block, cond, dst, src1) do { block->append().dmov(cond, dst, src1); } while (0) +#define UML_DSEXT(block, dst, src1, size) do { block->append().dsext(dst, src1, size); } while (0) +#define UML_DROLAND(block, dst, src, shift, mask) do { block->append().droland(dst, src, shift, mask); } while (0) +#define UML_DROLINS(block, dst, src, shift, mask) do { block->append().drolins(dst, src, shift, mask); } while (0) +#define UML_DADD(block, dst, src1, src2) do { block->append().dadd(dst, src1, src2); } while (0) +#define UML_DADDC(block, dst, src1, src2) do { block->append().daddc(dst, src1, src2); } while (0) +#define UML_DSUB(block, dst, src1, src2) do { block->append().dsub(dst, src1, src2); } while (0) +#define UML_DSUBB(block, dst, src1, src2) do { block->append().dsubb(dst, src1, src2); } while (0) +#define UML_DCMP(block, src1, src2) do { block->append().dcmp(src1, src2); } while (0) +#define UML_DMULU(block, dst, edst, src1, src2) do { block->append().dmulu(dst, edst, src1, src2); } while (0) +#define UML_DMULS(block, dst, edst, src1, src2) do { block->append().dmuls(dst, edst, src1, src2); } while (0) +#define UML_DDIVU(block, dst, edst, src1, src2) do { block->append().ddivu(dst, edst, src1, src2); } while (0) +#define UML_DDIVS(block, dst, edst, src1, src2) do { block->append().ddivs(dst, edst, src1, src2); } while (0) +#define UML_DAND(block, dst, src1, src2) do { block->append().dand(dst, src1, src2); } while (0) +#define UML_DTEST(block, src1, src2) do { block->append().dtest(src1, src2); } while (0) +#define UML_DOR(block, dst, src1, src2) do { block->append().dor(dst, src1, src2); } while (0) +#define UML_DXOR(block, dst, src1, src2) do { block->append().dxor(dst, src1, src2); } while (0) +#define UML_DLZCNT(block, dst, src) do { block->append().dlzcnt(dst, src); } while (0) +#define UML_DBSWAP(block, dst, src) do { block->append().dbswap(dst, src); } while (0) +#define UML_DSHL(block, dst, src, count) do { block->append().dshl(dst, src, count); } while (0) +#define UML_DSHR(block, dst, src, count) do { block->append().dshr(dst, src, count); } while (0) +#define UML_DSAR(block, dst, src, count) do { block->append().dsar(dst, src, count); } while (0) +#define UML_DROL(block, dst, src, count) do { block->append().drol(dst, src, count); } while (0) +#define UML_DROLC(block, dst, src, count) do { block->append().drolc(dst, src, count); } while (0) +#define UML_DROR(block, dst, src, count) do { block->append().dror(dst, src, count); } while (0) +#define UML_DRORC(block, dst, src, count) do { block->append().drorc(dst, src, count); } while (0) + + +/* ----- 32-bit Floating Point Arithmetic Operations ----- */ +#define UML_FSLOAD(block, dst, base, index) do { block->append().fsload(dst, base, index); } while (0) +#define UML_FSSTORE(block, base, index, src1) do { block->append().fsstore(base, index, src1); } while (0) +#define UML_FSREAD(block, dst, src1, space) do { block->append().fsread(dst, src1, AS_##space); } while (0) +#define UML_FSWRITE(block, dst, src1, space) do { block->append().fswrite(dst, src1, AS_##space); } while (0) +#define UML_FSMOV(block, dst, src1) do { block->append().fsmov(dst, src1); } while (0) +#define UML_FSMOVc(block, cond, dst, src1) do { block->append().fsmov(cond, dst, src1); } while (0) +#define UML_FSTOINT(block, dst, src1, size, round) do { block->append().fstoint(dst, src1, size, round); } while (0) +#define UML_FSFRINT(block, dst, src1, size) do { block->append().fsfrint(dst, src1, size); } while (0) +#define UML_FSFRFLT(block, dst, src1, size) do { block->append().fsfrflt(dst, src1, size); } while (0) +#define UML_FSADD(block, dst, src1, src2) do { block->append().fsadd(dst, src1, src2); } while (0) +#define UML_FSSUB(block, dst, src1, src2) do { block->append().fssub(dst, src1, src2); } while (0) +#define UML_FSCMP(block, src1, src2) do { block->append().fscmp(src1, src2); } while (0) +#define UML_FSMUL(block, dst, src1, src2) do { block->append().fsmul(dst, src1, src2); } while (0) +#define UML_FSDIV(block, dst, src1, src2) do { block->append().fsdiv(dst, src1, src2); } while (0) +#define UML_FSNEG(block, dst, src1) do { block->append().fsneg(dst, src1); } while (0) +#define UML_FSABS(block, dst, src1) do { block->append().fsabs(dst, src1); } while (0) +#define UML_FSSQRT(block, dst, src1) do { block->append().fssqrt(dst, src1); } while (0) +#define UML_FSRECIP(block, dst, src1) do { block->append().fsrecip(dst, src1); } while (0) +#define UML_FSRSQRT(block, dst, src1) do { block->append().fsrsqrt(dst, src1); } while (0) + + +/* ----- 64-bit Floating Point Arithmetic Operations ----- */ +#define UML_FDLOAD(block, dst, base, index) do { block->append().fdload(dst, base, index); } while (0) +#define UML_FDSTORE(block, base, index, src1) do { block->append().fdstore(base, index, src1); } while (0) +#define UML_FDREAD(block, dst, src1, space) do { block->append().fdread(dst, src1, AS_##space); } while (0) +#define UML_FDWRITE(block, dst, src1, space) do { block->append().fdwrite(dst, src1, AS_##space); } while (0) +#define UML_FDMOV(block, dst, src1) do { block->append().fdmov(dst, src1); } while (0) +#define UML_FDMOVc(block, cond, dst, src1) do { block->append().fdmov(cond, dst, src1); } while (0) +#define UML_FDTOINT(block, dst, src1, size, round) do { block->append().fdtoint(dst, src1, size, round); } while (0) +#define UML_FDFRINT(block, dst, src1, size) do { block->append().fdfrint(dst, src1, size); } while (0) +#define UML_FDFRFLT(block, dst, src1, size) do { block->append().fdfrflt(dst, src1, size); } while (0) +#define UML_FDRNDS(block, dst, src1) do { block->append().fdrnds(dst, src1); } while (0) +#define UML_FDADD(block, dst, src1, src2) do { block->append().fdadd(dst, src1, src2); } while (0) +#define UML_FDSUB(block, dst, src1, src2) do { block->append().fdsub(dst, src1, src2); } while (0) +#define UML_FDCMP(block, src1, src2) do { block->append().fdcmp(src1, src2); } while (0) +#define UML_FDMUL(block, dst, src1, src2) do { block->append().fdmul(dst, src1, src2); } while (0) +#define UML_FDDIV(block, dst, src1, src2) do { block->append().fddiv(dst, src1, src2); } while (0) +#define UML_FDNEG(block, dst, src1) do { block->append().fdneg(dst, src1); } while (0) +#define UML_FDABS(block, dst, src1) do { block->append().fdabs(dst, src1); } while (0) +#define UML_FDSQRT(block, dst, src1) do { block->append().fdsqrt(dst, src1); } while (0) +#define UML_FDRECIP(block, dst, src1) do { block->append().fdrecip(dst, src1); } while (0) +#define UML_FDRSQRT(block, dst, src1) do { block->append().fdrsqrt(dst, src1); } while (0) + + +#endif /* __DRCUMLSH_H__ */ diff --git a/src/devices/cpu/dsp16/dsp16.c b/src/devices/cpu/dsp16/dsp16.c new file mode 100644 index 00000000000..9f1de0c79f6 --- /dev/null +++ b/src/devices/cpu/dsp16/dsp16.c @@ -0,0 +1,453 @@ +// license:BSD-3-Clause +// copyright-holders:Andrew Gardner +/*************************************************************************** + + dsp16.h + + WE|AT&T DSP16 series emulator. + +***************************************************************************/ + +#include "emu.h" +#include "debugger.h" +#include "dsp16.h" + +// +// TODO: +// * Store the cache in 15 unique memory locations as it is on-chip. +// * Modify cycle counts when running from within the cache +// * A write to PI resets the pseudoramdom sequence generator) (page 2-4) +// * Handle virtual shift addressing using RB & RE (when RE is enabled) (page 2-6) +// * The ALU sign-extends 32-bit operands from y or p to 36 bits and produces a 36-bit output +// * Interrupt lines (page 2-15) +// + +//************************************************************************** +// DEVICE INTERFACE +//************************************************************************** + +// device type definition +const device_type DSP16 = &device_creator; + + +//------------------------------------------------- +// dsp16_device - constructor +//------------------------------------------------- + +dsp16_device::dsp16_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : cpu_device(mconfig, DSP16, "DSP16", tag, owner, clock, "dsp16", __FILE__), + m_program_config("program", ENDIANNESS_LITTLE, 16, 16, -1), + m_data_config("data", ENDIANNESS_LITTLE, 16, 16, -1), + m_i(0), + m_pc(0), + m_pt(0), + m_pr(0), + m_pi(0), + m_j(0), + m_k(0), + m_rb(0), + m_re(0), + m_r0(0), + m_r1(0), + m_r2(0), + m_r3(0), + m_x(0), + m_y(0), + m_p(0), + m_a0(0), + m_a1(0), + m_auc(0), + m_psw(0), + m_c0(0), + m_c1(0), + m_c2(0), + m_sioc(0), + m_srta(0), + m_sdx(0), + m_pioc(0), + m_pdx0(0), + m_pdx1(0), + m_ppc(0), + m_cacheStart(CACHE_INVALID), + m_cacheEnd(CACHE_INVALID), + m_cacheRedoNextPC(CACHE_INVALID), + m_cacheIterations(0), + m_program(NULL), + m_data(NULL), + m_direct(NULL), + m_icount(0) +{ + // Allocate & setup +} + + + +//------------------------------------------------- +// device_start - start up the device +//------------------------------------------------- + +void dsp16_device::device_start() +{ + // register state with the debugger + state_add(STATE_GENPC, "GENPC", m_pc).noshow(); + //state_add(STATE_GENPCBASE, "GENPCBASE", m_ppc).noshow(); + state_add(STATE_GENFLAGS, "GENFLAGS", m_psw).callimport().callexport().formatstr("%10s").noshow(); + state_add(DSP16_PC, "PC", m_pc); + state_add(DSP16_I, "I", m_i); + state_add(DSP16_PT, "PT", m_pt); + state_add(DSP16_PR, "PR", m_pr); + state_add(DSP16_PI, "PI", m_pi); + state_add(DSP16_J, "J", m_j); + state_add(DSP16_K, "K", m_k); + state_add(DSP16_RB, "RB", m_rb); + state_add(DSP16_RE, "RE", m_re); + state_add(DSP16_R0, "R0", m_r0); + state_add(DSP16_R1, "R1", m_r1); + state_add(DSP16_R2, "R2", m_r2); + state_add(DSP16_R3, "R3", m_r3); + state_add(DSP16_X, "X", m_x); + state_add(DSP16_Y, "Y", m_y); + state_add(DSP16_P, "P", m_p); + state_add(DSP16_A0, "A0", m_a0).mask(U64(0xfffffffff)); + state_add(DSP16_A1, "A1", m_a1).mask(U64(0xfffffffff)); + state_add(DSP16_AUC, "AUC", m_auc).formatstr("%8s"); + state_add(DSP16_PSW, "PSW", m_psw).formatstr("%16s"); + state_add(DSP16_C0, "C0", m_c0); + state_add(DSP16_C1, "C1", m_c1); + state_add(DSP16_C2, "C2", m_c2); + state_add(DSP16_SIOC, "SIOC", m_sioc).formatstr("%10s"); + state_add(DSP16_SRTA, "SRTA", m_srta); + state_add(DSP16_SDX, "SDX", m_sdx); + state_add(DSP16_PIOC, "PIOC", m_pioc).formatstr("%16s"); + state_add(DSP16_PDX0, "PDX0", m_pdx0); + state_add(DSP16_PDX1, "PDX1", m_pdx1); + + // register our state for saving + save_item(NAME(m_i)); + save_item(NAME(m_pc)); + save_item(NAME(m_pt)); + save_item(NAME(m_pr)); + save_item(NAME(m_pi)); + save_item(NAME(m_j)); + save_item(NAME(m_k)); + save_item(NAME(m_rb)); + save_item(NAME(m_re)); + save_item(NAME(m_r0)); + save_item(NAME(m_r1)); + save_item(NAME(m_r2)); + save_item(NAME(m_r3)); + save_item(NAME(m_x)); + save_item(NAME(m_y)); + save_item(NAME(m_p)); + save_item(NAME(m_a0)); + save_item(NAME(m_a1)); + save_item(NAME(m_auc)); + save_item(NAME(m_psw)); + save_item(NAME(m_c0)); + save_item(NAME(m_c1)); + save_item(NAME(m_c2)); + save_item(NAME(m_sioc)); + save_item(NAME(m_srta)); + save_item(NAME(m_sdx)); + save_item(NAME(m_pioc)); + save_item(NAME(m_pdx0)); + save_item(NAME(m_pdx1)); + save_item(NAME(m_ppc)); + save_item(NAME(m_cacheStart)); + save_item(NAME(m_cacheEnd)); + save_item(NAME(m_cacheRedoNextPC)); + save_item(NAME(m_cacheIterations)); + + // get our address spaces + m_program = &space(AS_PROGRAM); + m_data = &space(AS_DATA); + m_direct = &m_program->direct(); + + // set our instruction counter + m_icountptr = &m_icount; +} + + +//------------------------------------------------- +// device_reset - reset the device +//------------------------------------------------- + +void dsp16_device::device_reset() +{ + // Page 7-5 + m_pc = 0x0000; + m_pi = 0x0000; + m_sioc = 0x0000; // (page 5-4) + + // SRTA is unaltered by reset + m_pioc = 0x0008; + m_rb = 0x0000; + m_re = 0x0000; + + // AUC is not affected by reset + m_ppc = m_pc; + + // Hacky cache emulation. + m_cacheStart = CACHE_INVALID; + m_cacheEnd = CACHE_INVALID; + m_cacheRedoNextPC = CACHE_INVALID; + m_cacheIterations = 0; +} + + +//------------------------------------------------- +// memory_space_config - return the configuration +// of the specified address space, or NULL if +// the space doesn't exist +//------------------------------------------------- + +const address_space_config *dsp16_device::memory_space_config(address_spacenum spacenum) const +{ + return (spacenum == AS_PROGRAM) ? &m_program_config : + (spacenum == AS_DATA) ? &m_data_config : + NULL; +} + + +//------------------------------------------------- +// state_string_export - export state as a string +// for the debugger +//------------------------------------------------- + +void dsp16_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + switch (entry.index()) + { + case STATE_GENFLAGS: + strprintf(str, "(below)"); + break; + + case DSP16_AUC: + { + std::string alignString; + const UINT8 align = m_auc & 0x03; + switch (align) + { + case 0x00: strprintf(alignString,"xy"); break; + case 0x01: strprintf(alignString,"/4"); break; + case 0x02: strprintf(alignString,"x4"); break; + case 0x03: strprintf(alignString,",,"); break; + } + strprintf(str, "%c%c%c%c%c%s", + m_auc & 0x40 ? 'Y':'.', + m_auc & 0x20 ? '1':'.', + m_auc & 0x10 ? '0':'.', + m_auc & 0x08 ? '1':'.', + m_auc & 0x04 ? '0':'.', + alignString.c_str()); + break; + } + + case DSP16_PSW: + strprintf(str, "%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c", + m_psw & 0x8000 ? 'M':'.', + m_psw & 0x4000 ? 'E':'.', + m_psw & 0x2000 ? 'L':'.', + m_psw & 0x1000 ? 'V':'.', + m_psw & 0x0800 ? ',':',', + m_psw & 0x0400 ? ',':',', + m_psw & 0x0200 ? 'O':'.', + m_psw & 0x0100 ? '1':'.', + m_psw & 0x0080 ? '1':'.', + m_psw & 0x0040 ? '1':'.', + m_psw & 0x0020 ? '1':'.', + m_psw & 0x0010 ? 'O':'.', + m_psw & 0x0008 ? '1':'.', + m_psw & 0x0004 ? '1':'.', + m_psw & 0x0002 ? '1':'.', + m_psw & 0x0001 ? '1':'.'); + break; + + case DSP16_PIOC: + { + std::string strobeString; + const UINT8 strobe = (m_pioc & 0x6000) >> 13; + switch (strobe) + { + case 0x00: strprintf(strobeString, "1T"); break; + case 0x01: strprintf(strobeString, "2T"); break; + case 0x02: strprintf(strobeString, "3T"); break; + case 0x03: strprintf(strobeString, "4T"); break; + } + strprintf(str, "%c%s%c%c%c%c%c%c%c%c%c%c%c%c%c", + m_pioc & 0x8000 ? 'I':'.', + strobeString.c_str(), + m_pioc & 0x1000 ? 'O':'I', + m_pioc & 0x0800 ? 'O':'I', + m_pioc & 0x0400 ? 'S':'.', + m_pioc & 0x0200 ? 'I':'.', + m_pioc & 0x0100 ? 'O':'.', + m_pioc & 0x0080 ? 'P':'.', + m_pioc & 0x0040 ? 'P':'.', + m_pioc & 0x0020 ? 'I':'.', + m_pioc & 0x0010 ? 'I':'.', + m_pioc & 0x0008 ? 'O':'.', + m_pioc & 0x0004 ? 'P':'.', + m_pioc & 0x0002 ? 'P':'.', + m_pioc & 0x0001 ? 'I':'.'); + break; + } + + // Placeholder for a better view later (TODO) + case DSP16_SIOC: + { + std::string clkString; + const UINT8 clk = (m_sioc & 0x0180) >> 7; + switch (clk) + { + case 0x00: strprintf(clkString, "/4"); break; + case 0x01: strprintf(clkString, "12"); break; + case 0x02: strprintf(clkString, "16"); break; + case 0x03: strprintf(clkString, "20"); break; + } + strprintf(str, "%c%s%c%c%c%c%c%c%c", + m_sioc & 0x0200 ? 'I':'O', + clkString.c_str(), + m_sioc & 0x0040 ? 'L':'M', + m_sioc & 0x0020 ? 'I':'O', + m_sioc & 0x0010 ? 'I':'O', + m_sioc & 0x0008 ? 'I':'O', + m_sioc & 0x0004 ? 'I':'O', + m_sioc & 0x0002 ? '2':'1', + m_sioc & 0x0001 ? '2':'1'); + break; + } + } +} + + +//------------------------------------------------- +// disasm_min_opcode_bytes - return the length +// of the shortest instruction, in bytes +//------------------------------------------------- + +UINT32 dsp16_device::disasm_min_opcode_bytes() const +{ + return 2; +} + + +//------------------------------------------------- +// disasm_max_opcode_bytes - return the length +// of the longest instruction, in bytes +//------------------------------------------------- + +UINT32 dsp16_device::disasm_max_opcode_bytes() const +{ + return 4; +} + + +//------------------------------------------------- +// disasm_disassemble - call the disassembly +// helper function +//------------------------------------------------- + +offs_t dsp16_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( dsp16a ); + return CPU_DISASSEMBLE_NAME(dsp16a)(this, buffer, pc, oprom, opram, options); +} + + + +/*************************************************************************** + MEMORY ACCESSORS +***************************************************************************/ + +inline UINT32 dsp16_device::data_read(const UINT16& addr) +{ + return m_data->read_word(addr << 1); +} + +inline void dsp16_device::data_write(const UINT16& addr, const UINT16& data) +{ + m_data->write_word(addr << 1, data & 0xffff); +} + +inline UINT32 dsp16_device::opcode_read(const UINT8 pcOffset) +{ + const UINT16 readPC = m_pc + pcOffset; + return m_direct->read_dword(readPC << 1); +} + + +/*************************************************************************** + CORE EXECUTION LOOP +***************************************************************************/ + +//------------------------------------------------- +// execute_min_cycles - return minimum number of +// cycles it takes for one instruction to execute +//------------------------------------------------- + +UINT32 dsp16_device::execute_min_cycles() const +{ + return 1; +} + + +//------------------------------------------------- +// execute_max_cycles - return maximum number of +// cycles it takes for one instruction to execute +//------------------------------------------------- + +UINT32 dsp16_device::execute_max_cycles() const +{ + return 1; +} + + +//------------------------------------------------- +// execute_input_lines - return the number of +// input/interrupt lines +//------------------------------------------------- + +UINT32 dsp16_device::execute_input_lines() const +{ + return 1; +} + + +void dsp16_device::execute_set_input(int inputnum, int state) +{ + // Only has one external IRQ line +} + + +void dsp16_device::execute_run() +{ + // HACK TO MAKE CPU DO NOTHING. + // REMOVE IF DEVELOPING CPU CORE. + m_icount = 0; + return; + + do + { + // debugging + m_ppc = m_pc; // copy PC to previous PC + debugger_instruction_hook(this, m_pc); + + // instruction fetch & execute + UINT8 cycles; + UINT8 pcAdvance; + const UINT16 op = opcode_read(); + execute_one(op, cycles, pcAdvance); + + // step + m_pc += pcAdvance; + m_icount -= cycles; + + // The 16 bit PI "shadow" register gets set to PC on each instruction except + // when an interrupt service routine is active (TODO: Interrupt check) (page 2-4) + m_pi = m_pc; + + } while (m_icount > 0); +} + +#include "dsp16ops.inc" diff --git a/src/devices/cpu/dsp16/dsp16.h b/src/devices/cpu/dsp16/dsp16.h new file mode 100644 index 00000000000..195cdcb5943 --- /dev/null +++ b/src/devices/cpu/dsp16/dsp16.h @@ -0,0 +1,191 @@ +// license:BSD-3-Clause +// copyright-holders:Andrew Gardner +/*************************************************************************** + + dsp16.h + + WE|AT&T DSP16 series emulator. + +***************************************************************************/ + +#pragma once + +#ifndef __DSP16_H__ +#define __DSP16_H__ + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> dsp16_device + +class dsp16_device : public cpu_device +{ +public: + // construction/destruction + dsp16_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // public interfaces + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_execute_interface overrides + virtual UINT64 execute_clocks_to_cycles(UINT64 clocks) const { return (clocks + 2 - 1) / 2; } // internal /2 divider + virtual UINT64 execute_cycles_to_clocks(UINT64 cycles) const { return (cycles * 2); } // internal /2 divider + virtual UINT32 execute_min_cycles() const; + virtual UINT32 execute_max_cycles() const; + virtual UINT32 execute_input_lines() const; + virtual void execute_run(); + virtual void execute_set_input(int inputnum, int state); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const; + + // device_state_interface overrides + virtual void state_string_export(const device_state_entry &entry, std::string &str); + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const; + virtual UINT32 disasm_max_opcode_bytes() const; + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + + // address spaces + const address_space_config m_program_config; + const address_space_config m_data_config; + + // CPU registers + // ROM Address Arithmetic Unit (XAAU) (page 2-4) + UINT16 m_i; // 12 bits + UINT16 m_pc; + UINT16 m_pt; + UINT16 m_pr; + UINT16 m_pi; + + // RAM Address Arithmetic Unit (YAAU) (page 2-6) + UINT16 m_j; // Signed + UINT16 m_k; // Signed + UINT16 m_rb; + UINT16 m_re; + UINT16 m_r0; + UINT16 m_r1; + UINT16 m_r2; + UINT16 m_r3; + + // Data Arithmetic Unit (DAU) (page 2-6) + UINT16 m_x; + UINT32 m_y; + UINT32 m_p; + UINT64 m_a0; // 36 bits + UINT64 m_a1; // 36 bits + UINT8 m_auc; // 6 bits + UINT16 m_psw; + UINT8 m_c0; + UINT8 m_c1; + UINT8 m_c2; + + // Serial and parallel interfaces (TODO: More here (page 2-13)) + UINT16 m_sioc; + UINT16 m_srta; + UINT16 m_sdx; + UINT16 m_pioc; + UINT16 m_pdx0; // pdx0 & pdx1 refer to the same physical register (page 6-1) + UINT16 m_pdx1; // but we keep them separate for logic's sake. + + // internal stuff + UINT16 m_ppc; + + // This CPU core handles the cache as more of a loop than 15 separate memory elements. + // It's a bit of a hack, but it's easier this way (for now). + UINT16 m_cacheStart; + UINT16 m_cacheEnd; + UINT16 m_cacheRedoNextPC; + UINT16 m_cacheIterations; + static const UINT16 CACHE_INVALID = 0xffff; + + // memory access + inline UINT32 data_read(const UINT16& addr); + inline void data_write(const UINT16& addr, const UINT16& data); + inline UINT32 opcode_read(const UINT8 pcOffset=0); + + // address spaces + address_space* m_program; + address_space* m_data; + direct_read_data* m_direct; + + // other internal states + int m_icount; + + // operations + void execute_one(const UINT16& op, UINT8& cycles, UINT8& pcAdvance); + + // table decoders + void* registerFromRImmediateField(const UINT8& R); + void* registerFromRTable(const UINT8& R); + UINT16* registerFromYFieldUpper(const UINT8& Y); + + // execution + void executeF1Field(const UINT8& F1, const UINT8& D, const UINT8& S); + void executeYFieldPost(const UINT8& Y); + void executeZFieldPartOne(const UINT8& Z, UINT16* rN); + void executeZFieldPartTwo(const UINT8& Z, UINT16* rN); + + // helpers + void* addressYL(); + void writeRegister(void* reg, const UINT16& value); + bool conditionTest(const UINT8& CON); + + // flags + bool lmi(); + bool leq(); + bool llv(); + bool lmv(); +}; + + +// device type definition +extern const device_type DSP16; + + +/*************************************************************************** + REGISTER ENUMERATION +***************************************************************************/ + +enum +{ + DSP16_I, // ROM Address Arithmetic Unit (XAAU) + DSP16_PC, + DSP16_PT, + DSP16_PR, + DSP16_PI, + DSP16_J, // RAM Address Arithmetic Unit (YAAU) + DSP16_K, + DSP16_RB, + DSP16_RE, + DSP16_R0, + DSP16_R1, + DSP16_R2, + DSP16_R3, + DSP16_X, // Data Arithmetic Unit (DAU) + DSP16_Y, + DSP16_P, + DSP16_A0, + DSP16_A1, + DSP16_AUC, + DSP16_PSW, + DSP16_C0, + DSP16_C1, + DSP16_C2, + DSP16_SIOC, + DSP16_SRTA, + DSP16_SDX, + DSP16_PIOC, + DSP16_PDX0, + DSP16_PDX1 +}; + + +#endif /* __DSP16_H__ */ diff --git a/src/devices/cpu/dsp16/dsp16dis.c b/src/devices/cpu/dsp16/dsp16dis.c new file mode 100644 index 00000000000..2e144df03af --- /dev/null +++ b/src/devices/cpu/dsp16/dsp16dis.c @@ -0,0 +1,583 @@ +// license:BSD-3-Clause +// copyright-holders:Andrew Gardner +#include "emu.h" +#include "dsp16.h" + +std::string disasmF1Field(const UINT8& F1, const UINT8& D, const UINT8& S) +{ + std::string ret = ""; + switch (F1) + { + case 0x00: strprintf(ret, "a%d = p, p = x*y", D); break; + case 0x01: strprintf(ret, "a%d = a%d + p, p = x*y", D, S); break; + case 0x02: strprintf(ret, "p = x*y"); break; + case 0x03: strprintf(ret, "a%d = a%d - p, p = x*y", D, S); break; + case 0x04: strprintf(ret, "a%d = p", D); break; + case 0x05: strprintf(ret, "a%d = a%d + p", D, S); break; + case 0x06: strprintf(ret, "NOP"); break; + case 0x07: strprintf(ret, "a%d = a%d - p", D, S); break; + case 0x08: strprintf(ret, "a%d = a%d | y", D, S); break; + case 0x09: strprintf(ret, "a%d = a%d ^ y", D, S); break; + case 0x0a: strprintf(ret, "a%d & y", S); break; + case 0x0b: strprintf(ret, "a%d - y", S); break; + case 0x0c: strprintf(ret, "a%d = y", D); break; + case 0x0d: strprintf(ret, "a%d = a%d + y", D, S); break; + case 0x0e: strprintf(ret, "a%d = a%d & y", D, S); break; + case 0x0f: strprintf(ret, "a%d = a%d - y", D, S); break; + + default: return "UNKNOWN"; + } + return ret; +} + +std::string disasmYField(const UINT8& Y) +{ + switch (Y) + { + case 0x00: return "*r0"; + case 0x01: return "*r0++"; + case 0x02: return "*r0--"; + case 0x03: return "*r0++j"; + + case 0x04: return "*r1"; + case 0x05: return "*r1++"; + case 0x06: return "*r1--"; + case 0x07: return "*r1++j"; + + case 0x08: return "*r2"; + case 0x09: return "*r2++"; + case 0x0a: return "*r2--"; + case 0x0b: return "*r2++j"; + + case 0x0c: return "*r3"; + case 0x0d: return "*r3++"; + case 0x0e: return "*r3--"; + case 0x0f: return "*r3++j"; + + default: return "UNKNOWN"; + } + // never executed + //return ""; +} + +std::string disasmZField(const UINT8& Z) +{ + switch (Z) + { + case 0x00: return "*r0zp"; + case 0x01: return "*r0pz"; + case 0x02: return "*r0m2"; + case 0x03: return "*r0jk"; + + case 0x04: return "*r1zp"; + case 0x05: return "*r1pz"; + case 0x06: return "*r1m2"; + case 0x07: return "*r1jk"; + + case 0x08: return "*r2zp"; + case 0x09: return "*r2pz"; + case 0x0a: return "*r2m2"; + case 0x0b: return "*r2jk"; + + case 0x0c: return "*r3zp"; + case 0x0d: return "*r3pz"; + case 0x0e: return "*r3m2"; + case 0x0f: return "*r3jk"; + + default: return "UNKNOWN"; + } + // never executed + //return ""; +} + +std::string disasmF2Field(const UINT8& F2, const UINT8& D, const UINT8& S) +{ + std::string ret = ""; + switch (F2) + { + case 0x00: strprintf(ret, "a%d = a%d >> 1", D, S); break; + case 0x01: strprintf(ret, "a%d = a%d << 1", D, S); break; + case 0x02: strprintf(ret, "a%d = a%d >> 4", D, S); break; + case 0x03: strprintf(ret, "a%d = a%d << 4", D, S); break; + case 0x04: strprintf(ret, "a%d = a%d >> 8", D, S); break; + case 0x05: strprintf(ret, "a%d = a%d << 8", D, S); break; + case 0x06: strprintf(ret, "a%d = a%d >> 16", D, S); break; + case 0x07: strprintf(ret, "a%d = a%d << 16", D, S); break; + + case 0x08: strprintf(ret, "a%d = p", D); break; + case 0x09: strprintf(ret, "a%dh = a%dh + 1", D, S); break; + case 0x0a: strprintf(ret, "RESERVED"); break; + case 0x0b: strprintf(ret, "a%d = rnd(a%d)", D, S); break; + case 0x0c: strprintf(ret, "a%d = y", D); break; + case 0x0d: strprintf(ret, "a%d = a%d + 1", D, S); break; + case 0x0e: strprintf(ret, "a%d = a%d", D, S); break; + case 0x0f: strprintf(ret, "a%d = -a%d", D, S); break; + + default: return "UNKNOWN"; + } + return ret; +} + +std::string disasmCONField(const UINT8& CON) +{ + switch (CON) + { + case 0x00: return "mi"; + case 0x01: return "pl"; + case 0x02: return "eq"; + case 0x03: return "ne"; + case 0x04: return "lvs"; + case 0x05: return "lvc"; + case 0x06: return "mvs"; + case 0x07: return "mvc"; + case 0x08: return "heads"; + case 0x09: return "tails"; + case 0x0a: return "c0ge"; + case 0x0b: return "c0lt"; + case 0x0c: return "c1ge"; + case 0x0d: return "c1lt"; + case 0x0e: return "true"; + case 0x0f: return "false"; + case 0x10: return "gt"; + case 0x11: return "le"; + + default: return "RESERVED"; + } + // never executed + //return ""; +} + +std::string disasmBField(const UINT8& B) +{ + switch (B) + { + case 0x00: return "return"; + case 0x01: return "ireturn"; + case 0x02: return "goto pt"; + case 0x03: return "call pt"; + case 0x04: + case 0x05: + case 0x06: + case 0x07: return "RESERVED"; + + default: return "UNKNOWN"; + } + // never executed + //return ""; +} + +std::string disasmRImmediateField(const UINT8& R) +{ + switch (R) + { + case 0x00: return "j"; + case 0x01: return "k"; + case 0x02: return "rb"; + case 0x03: return "re"; + case 0x04: return "r0"; + case 0x05: return "r1"; + case 0x06: return "r2"; + case 0x07: return "r3"; + + default: return "UNKNOWN"; + } + // never executed + //return ""; +} + +std::string disasmRField(const UINT8& R) +{ + switch (R) + { + case 0x00: return "r0"; + case 0x01: return "r1"; + case 0x02: return "r2"; + case 0x03: return "r3"; + case 0x04: return "j"; + case 0x05: return "k"; + case 0x06: return "rb"; + case 0x07: return "re"; + case 0x08: return "pt"; + case 0x09: return "pr"; + case 0x0a: return "pi"; + case 0x0b: return "i"; + + case 0x10: return "x"; + case 0x11: return "y"; + case 0x12: return "yl"; + case 0x13: return "auc"; + case 0x14: return "psw"; + case 0x15: return "c0"; + case 0x16: return "c1"; + case 0x17: return "c2"; + case 0x18: return "sioc"; + case 0x19: return "srta"; + case 0x1a: return "sdx"; + case 0x1b: return "tdms"; + case 0x1c: return "pioc"; + case 0x1d: return "pdx0"; + case 0x1e: return "pdx1"; + + default: return "RESERVED"; + } + // never executed + //return ""; +} + +std::string disasmIField(const UINT8& I) +{ + switch (I) + { + case 0x00: return "r0/j"; + case 0x01: return "r1/k"; + case 0x02: return "r2/rb"; + case 0x03: return "r3/re"; + + default: return "UNKNOWN"; + } + // never executed + //return ""; +} + +bool disasmSIField(const UINT8& SI) +{ + switch (SI) + { + case 0x00: return 0; // Not a software interrupt + case 0x01: return 1; // Software Interrupt + } + return false; +} + + +CPU_DISASSEMBLE( dsp16a ) +{ + UINT8 opSize = 1; + UINT32 dasmflags = 0; + UINT16 op = oprom[0] | (oprom[1] << 8); + UINT16 op2 = oprom[2] | (oprom[3] << 8); + + // TODO: Test for previous "if CON" instruction and tab the next instruction in? + + const UINT8 opcode = (op >> 11) & 0x1f; + switch(opcode) + { + // Format 1: Multiply/ALU Read/Write Group + case 0x06: + { + // F1, Y + const UINT8 Y = (op & 0x000f); + const UINT8 S = (op & 0x0200) >> 9; + const UINT8 D = (op & 0x0400) >> 10; + const UINT8 F1 = (op & 0x01e0) >> 5; + std::string yString = disasmYField(Y); + std::string fString = disasmF1Field(F1, D, S); + sprintf(buffer, "%s, %s", fString.c_str(), yString.c_str()); + break; + } + case 0x04: case 0x1c: + { + // F1 Y=a0[1] | F1 Y=a1[1] + const UINT8 Y = (op & 0x000f); + const UINT8 X = (op & 0x0010) >> 4; + const UINT8 S = (op & 0x0200) >> 9; + const UINT8 D = (op & 0x0400) >> 10; + const UINT8 F1 = (op & 0x01e0) >> 5; + std::string yString = disasmYField(Y); + std::string fString = disasmF1Field(F1, D, S); + std::string aString = (opcode == 0x1c) ? "a0" : "a1"; + std::string xString = (X) ? "" : "l"; + sprintf(buffer, "%s = %s%s, %s", yString.c_str(), aString.c_str(), xString.c_str(), fString.c_str()); + break; + } + case 0x16: + { + // F1, x = Y + const UINT8 Y = (op & 0x000f); + const UINT8 S = (op & 0x0200) >> 9; + const UINT8 D = (op & 0x0400) >> 10; + const UINT8 F1 = (op & 0x01e0) >> 5; + std::string yString = disasmYField(Y); + std::string fString = disasmF1Field(F1, D, S); + sprintf(buffer, "%s, x = %s", fString.c_str(), yString.c_str()); + break; + } + case 0x17: + { + // F1, y[l] = Y + const UINT8 Y = (op & 0x000f); + const UINT8 X = (op & 0x0010) >> 4; + const UINT8 S = (op & 0x0200) >> 9; + const UINT8 D = (op & 0x0400) >> 10; + const UINT8 F1 = (op & 0x01e0) >> 5; + std::string yString = disasmYField(Y); + std::string fString = disasmF1Field(F1, D, S); + std::string xString = (X ? "y" : "y1"); + sprintf(buffer, "%s, %s = %s", fString.c_str(), xString.c_str(), yString.c_str()); + break; + } + case 0x1f: + { + // F1, y = Y, x = *pt++[i] + const UINT8 Y = (op & 0x000f); + const UINT8 X = (op & 0x0010) >> 4; + const UINT8 S = (op & 0x0200) >> 9; + const UINT8 D = (op & 0x0400) >> 10; + const UINT8 F1 = (op & 0x01e0) >> 5; + std::string yString = disasmYField(Y); + std::string fString = disasmF1Field(F1, D, S); + std::string xString = (X ? "*pt++i" : "*pt++"); + sprintf(buffer, "%s, y = %s, x = %s", fString.c_str(), yString.c_str(), xString.c_str()); + break; + } + case 0x19: case 0x1b: + { + // F1, y = a0|1, x = *pt++[i] + const UINT8 Y = (op & 0x000f); + const UINT8 X = (op & 0x0010) >> 4; + const UINT8 S = (op & 0x0200) >> 9; + const UINT8 D = (op & 0x0400) >> 10; + const UINT8 F1 = (op & 0x01e0) >> 5; + std::string fString = disasmF1Field(F1, D, S); + std::string xString = (X ? "*pt++i" : "*pt++"); + std::string aString = (opcode == 0x19) ? "a0" : "a1"; + sprintf(buffer, "%s, y = %s, x = %s", fString.c_str(), aString.c_str(), xString.c_str()); + if (Y != 0x00) sprintf(buffer, "UNKNOWN"); + break; + } + case 0x14: + { + // F1, Y = y[1] + const UINT8 Y = (op & 0x000f); + const UINT8 X = (op & 0x0010) >> 4; + const UINT8 S = (op & 0x0200) >> 9; + const UINT8 D = (op & 0x0400) >> 10; + const UINT8 F1 = (op & 0x01e0) >> 5; + std::string yString = disasmYField(Y); + std::string xString = (X ? "y" : "y1"); + std::string fString = disasmF1Field(F1, D, S); + sprintf(buffer, "%s, %s = %s", fString.c_str(), yString.c_str(), xString.c_str()); + break; + } + + // Format 1a: Multiply/ALU Read/Write Group (major typo in docs on p3-51) + case 0x07: + { + // F1, At[1] = Y + const UINT8 Y = (op & 0x000f); + const UINT8 S = (op & 0x0200) >> 9; + const UINT8 aT = (op & 0x0400) >> 10; + const UINT8 F1 = (op & 0x01e0) >> 5; + std::string yString = disasmYField(Y); + std::string atString = (aT ? "a0" : "a1"); + std::string fString = disasmF1Field(F1, aT, S); + sprintf(buffer, "%s, %s = %s", fString.c_str(), atString.c_str(), yString.c_str()); + break; + } + + // Format 2: Multiply/ALU Read/Write Group + case 0x15: + { + // F1, Z : y[1] + const UINT8 Z = (op & 0x000f); + const UINT8 X = (op & 0x0010) >> 4; + const UINT8 S = (op & 0x0200) >> 9; + const UINT8 D = (op & 0x0400) >> 10; + const UINT8 F1 = (op & 0x01e0) >> 5; + std::string zString = disasmZField(Z); + std::string xString = (X ? "y" : "y1"); + std::string fString = disasmF1Field(F1, D, S); + sprintf(buffer, "%s, %s <=> %s", fString.c_str(), xString.c_str(), zString.c_str()); + break; + } + case 0x1d: + { + // F1, Z : y, x=*pt++[i] + const UINT8 Z = (op & 0x000f); + const UINT8 X = (op & 0x0010) >> 4; + const UINT8 S = (op & 0x0200) >> 9; + const UINT8 D = (op & 0x0400) >> 10; + const UINT8 F1 = (op & 0x01e0) >> 5; + std::string zString = disasmZField(Z); + std::string xString = (X ? "*pt++i" : "*pt++"); + std::string fString = disasmF1Field(F1, D, S); + sprintf(buffer, "%s, %s <=> y, x = %s", fString.c_str(), zString.c_str(), xString.c_str()); + break; + } + + // Format 2a: Multiply/ALU Read/Write Group + case 0x05: + { + // F1, Z : aT[1] + const UINT8 Z = (op & 0x000f); + const UINT8 X = (op & 0x0010) >> 4; + const UINT8 S = (op & 0x0200) >> 9; + const UINT8 aT = (op & 0x0400) >> 10; + const UINT8 F1 = (op & 0x01e0) >> 5; + std::string zString = disasmZField(Z); + std::string atString = (aT ? "a0" : "a1"); + atString += X ? "" : "1"; // TODO: Figure out unclear wording. + std::string fString = disasmF1Field(F1, aT, S); + sprintf(buffer, "%s, %s <=> %s", fString.c_str(), zString.c_str(), atString.c_str()); + break; + } + + // Format 3: Special Functions + case 0x12: + case 0x13: + { + // if|ifc CON F2 + const UINT8 CON = (op & 0x001f); + const UINT8 S = (op & 0x0200) >> 9; + const UINT8 D = (op & 0x0400) >> 10; + const UINT8 F2 = (op & 0x01e0) >> 5; + std::string fString = disasmF2Field(F2, D, S); + std::string conString = disasmCONField(CON); + if (op & 0x0800) sprintf(buffer, "if %s : %s", conString.c_str(), fString.c_str()); + else sprintf(buffer, "ifc %s : %s", conString.c_str(), fString.c_str()); + break; + } + + // Format 4: Branch Direct Group + case 0x00: case 0x01: + { + // goto JA + const UINT16 JA = (op & 0x0fff) | (pc & 0xf000); + sprintf(buffer, "goto 0x%04x", JA); + break; + } + case 0x10: case 0x11: + { + // call JA + const UINT16 JA = (op & 0x0fff) | (pc & 0xf000); + sprintf(buffer, "call 0x%04x", JA); + break; + } + + // Format 5: Branch Indirect Group + case 0x18: + { + // goto B + const UINT8 B = (op & 0x0700) >> 8; + std::string bString = disasmBField(B); + sprintf(buffer, "%s", bString.c_str()); + break; + } + + // Format 6: Contitional Branch Qualifier/Software Interrupt (icall) + case 0x1a: + { + // if CON [goto/call/return] + const UINT8 CON = (op & 0x001f); + std::string conString = disasmCONField(CON); + sprintf(buffer, "if %s:", conString.c_str()); + // TODO: Test for invalid ops + // icall + if (op == 0xd40e) sprintf(buffer, "icall"); + break; + } + + // Format 7: Data Move Group + case 0x09: case 0x0b: + { + // R = aS + const UINT8 R = (op & 0x03f0) >> 4; + const UINT8 S = (op & 0x1000) >> 12; + std::string rString = disasmRField(R); + sprintf(buffer, "%s = %s", rString.c_str(), (S ? "a1" : "a0")); + break; + } + case 0x08: + { + // aT = R + const UINT8 R = (op & 0x03f0) >> 4; + const UINT8 aT = (op & 0x0400) >> 10; + std::string rString = disasmRField(R); + sprintf(buffer, "%s = %s", (aT ? "a0" : "a1"), rString.c_str()); + break; + } + case 0x0f: + { + // R = Y + const UINT8 Y = (op & 0x000f); + const UINT8 R = (op & 0x03f0) >> 4; + std::string yString = disasmYField(Y); + std::string rString = disasmRField(R); + sprintf(buffer, "%s = %s", rString.c_str(), yString.c_str()); + // TODO: Special case the R == [y, y1, or x] case + break; + } + case 0x0c: + { + // Y = R + const UINT8 Y = (op & 0x000f); + const UINT8 R = (op & 0x03f0) >> 4; + std::string yString = disasmYField(Y); + std::string rString = disasmRField(R); + // TODO: page 3-31 "special function encoding" + sprintf(buffer, "%s = %s", yString.c_str(), rString.c_str()); + break; + } + case 0x0d: + { + // Z : R + const UINT8 Z = (op & 0x000f); + const UINT8 R = (op & 0x03f0) >> 4; + std::string zString = disasmZField(Z); + std::string rString = disasmRField(R); + sprintf(buffer, "%s <=> %s", zString.c_str(), rString.c_str()); + break; + } + + // Format 8: Data Move (immediate operand - 2 words) + case 0x0a: + { + // R = N + const UINT8 R = (op & 0x03f0) >> 4; + std::string rString = disasmRField(R); + sprintf(buffer, "%s = 0x%04x", rString.c_str(), op2); + opSize = 2; + break; + } + + // Format 9: Short Immediate Group + case 0x02: case 0x03: + { + // R = M + const UINT16 M = (op & 0x01ff); + const UINT8 R = (op & 0x0e00) >> 9; + std::string rString = disasmRImmediateField(R); + sprintf(buffer, "%s = 0x%04x", rString.c_str(), M); + break; + } + + // Format 10: do - redo + case 0x0e: + { + // do|redo K + const UINT8 K = (op & 0x007f); + const UINT8 NI = (op & 0x0780) >> 7; + sprintf(buffer, "do (next %d inst) %d times", NI, K); + // TODO: Limits on K & NI + if (NI == 0x00) + sprintf(buffer, "redo %d", K); + break; + } + + // RESERVED + case 0x1e: + { + sprintf(buffer, "RESERVED"); + break; + } + + // UNKNOWN + default: + { + sprintf(buffer, "UNKNOWN"); + break; + } + } + + return opSize | dasmflags | DASMFLAG_SUPPORTED; +} diff --git a/src/devices/cpu/dsp16/dsp16ops.inc b/src/devices/cpu/dsp16/dsp16ops.inc new file mode 100644 index 00000000000..d63fe9d3f99 --- /dev/null +++ b/src/devices/cpu/dsp16/dsp16ops.inc @@ -0,0 +1,937 @@ +// license:BSD-3-Clause +// copyright-holders:Andrew Gardner +#include "dsp16.h" + +#define DSP_LINE(__DSP_DOCLINE__) printf("0x%04x - %d (%s)\n", m_pc, __LINE__, __DSP_DOCLINE__); + +// TODO: +// * AUC has a CLR field for writing to A0 & A1 + sign extension + psw + zero lower bits +// implement as a clean function (page 2-7) +// * Implement saturation overflow (SAT on AUC) (page 2-8) +// * Implement p alignment (ALIGN on AUC) (page 2-9) +// * When a register is used as a memory pointer. its value is compared with re. If its value is +// equal to the contents of re and the postincrement is +1, then the value in rb is copied into +// the register after the memory access is complete. See Section 4.2.3. +// * CPU flags go to the PSW & conditionTest() works on that (Page 3-4) +// * Some instructions are not interruptible. +// + + +// NOTES: +// When y is used in an assembly-language instruction, the DSPI6/DSPI6A device will read +// or write the high half (bits 16-31) of the y register (page 2-7) + +// The YL register is the lower half of the 32 bit Y register +void* dsp16_device::addressYL() +{ + return (void*)(((UINT8*)&m_y) + 2); +} + + +// Flag getters +bool dsp16_device::lmi() +{ + return m_psw & 0x8000; +} + +bool dsp16_device::leq() +{ + return m_psw & 0x4000; +} + +bool dsp16_device::llv() +{ + return m_psw & 0x2000; +} + +bool dsp16_device::lmv() +{ + return m_psw & 0x1000; +} + + +void dsp16_device::writeRegister(void* reg, const UINT16 &value) +{ + // Make sure you're not attempting to write somewhere this function doesn't support. + if (reg == &m_p || reg == &m_a0 || reg == &m_a1) + { + logerror("dsp16::writeRegister called on invalid register at PC 0x%04x.\n", m_pc); + return; + } + + if (reg == &m_auc || reg == &m_c0 || reg == &m_c1 || reg == &m_c2) + { + // 8 bit registers + *(UINT8*)reg = value & 0x00ff; + } + else if (reg == &m_psw) + { + // Writes to the a0 & a1 guard bits too + m_a0 &= U64(0x0ffffffff); + m_a0 |= U64(m_psw & 0x000f) << 32; + m_a1 &= U64(0x0ffffffff); + m_a1 |= U64(m_psw & 0x01e0) << 27; + m_psw = value; + } + else if (reg == &m_i) + { + // 12 bit register + m_i = value & 0x0fff; + } + else if (reg == &m_y) + { + // Y register + // TODO - Automatic clearing of yl may be selected (according to the CLR field of the auc register) (page 2-7) + m_y = (value << 16) | (m_y & 0x0000ffff); + } + else if (reg == addressYL()) + { + // Yl register (Writes to yl do not change the data in the high half of y) + m_y = value | (m_y & 0xffff0000); + } + else + { + // Everything else + *(UINT16*)reg = value; + } +} + + +bool dsp16_device::conditionTest(const UINT8& CON) +{ + switch (CON) + { + case 0x00: return lmi(); // mi (negative result) + case 0x01: return !lmi(); // pl (positive result) + case 0x02: return leq(); // eq (result == 0) + case 0x03: return !leq(); // ne (result != 0) + case 0x04: return llv(); // lvs (logical overflow set) + case 0x05: return !llv(); // lvc (logical overflow clear) + case 0x06: return lmv(); // mvs (math. overflow set) + case 0x07: return !lmv(); // mvc (math. overflow clear) + case 0x08: printf("UNIMPLEMENTED condition check @ PC 0x%04x\n", m_pc); return false; // heads (random bit set) + case 0x09: printf("UNIMPLEMENTED condition check @ PC 0x%04x\n", m_pc); return false; // tails (random bit clear) + case 0x0a: printf("UNIMPLEMENTED condition check @ PC 0x%04x\n", m_pc); return false; // c0ge (counter0 >= 0)* + case 0x0b: printf("UNIMPLEMENTED condition check @ PC 0x%04x\n", m_pc); return false; // c0lt (counter0 < 0)* + case 0x0c: printf("UNIMPLEMENTED condition check @ PC 0x%04x\n", m_pc); return false; // c1ge (counter1 >= 0)* + case 0x0d: printf("UNIMPLEMENTED condition check @ PC 0x%04x\n", m_pc); return false; // c1lt (counter1 < 0)* + case 0x0e: return true; // true (always) + case 0x0f: return false; // false (never) + case 0x10: return (!lmi() && !leq()); // gt (result > 0) + case 0x11: return (lmi() || leq()); // le (result <= 0) + default: logerror("Unrecognized condition at PC=0x%04x\n", m_pc); break; + } + + // Testing each of these conditions (*) increments the respective counter being tested (page 3-5) + + return false; +} + + +void* dsp16_device::registerFromRImmediateField(const UINT8& R) +{ + switch (R) + { + case 0x00: return (void*)&m_j; + case 0x01: return (void*)&m_k; + case 0x02: return (void*)&m_rb; + case 0x03: return (void*)&m_re; + case 0x04: return (void*)&m_r0; + case 0x05: return (void*)&m_r1; + case 0x06: return (void*)&m_r2; + case 0x07: return (void*)&m_r3; + + default: return NULL; + } + return NULL; +} + + +void* dsp16_device::registerFromRTable(const UINT8 &R) +{ + switch (R) + { + case 0x00: return (void*)&m_r0; + case 0x01: return (void*)&m_r1; + case 0x02: return (void*)&m_r2; + case 0x03: return (void*)&m_r3; + case 0x04: return (void*)&m_j; + case 0x05: return (void*)&m_k; + case 0x06: return (void*)&m_rb; + case 0x07: return (void*)&m_re; + case 0x08: return (void*)&m_pt; + case 0x09: return (void*)&m_pr; + case 0x0a: return (void*)&m_pi; + case 0x0b: return (void*)&m_i; + + case 0x10: return (void*)&m_x; + case 0x11: return (void*)&m_y; + case 0x12: return (void*)addressYL(); + case 0x13: return (void*)&m_auc; // zero extended + case 0x14: return (void*)&m_psw; + case 0x15: return (void*)&m_c0; // sign extended + case 0x16: return (void*)&m_c1; // sign extended + case 0x17: return (void*)&m_c2; // sign extended + case 0x18: return (void*)&m_sioc; + case 0x19: return (void*)&m_srta; + case 0x1a: return (void*)&m_sdx; + case 0x1b: logerror("dsp16::registerFromRTable tdms requested 0x%04x.\n", m_pc); break; + case 0x1c: return (void*)&m_pioc; + case 0x1d: return (void*)&m_pdx0; + case 0x1e: return (void*)&m_pdx1; + + default: return NULL; + } + return NULL; +} + + +void dsp16_device::executeF1Field(const UINT8& F1, const UINT8& D, const UINT8& S) +{ + // TODO: I'm pretty sure we need to feed X into these as well - Double check + + // Note these instructions read right-to-left, so act accordingly (page 3-6) + // y & p are sign extended (page 3-9) + // implementation details (page 3-9) + + // Where is are the results going? + UINT64* destinationReg = NULL; + switch (D) + { + case 0x00: destinationReg = &m_a0; break; + case 0x01: destinationReg = &m_a1; break; + default: break; + } + + // Which source is being used? + UINT64* sourceReg = NULL; + switch (S) + { + case 0x00: sourceReg = &m_a0; break; + case 0x01: sourceReg = &m_a1; break; + default: break; + } + + + // We must compute into an intermediate variable to compute flags on + UINT64 result = 0; + bool justATest = false; + + switch (F1) + { + case 0x00: + { + // Ad = p p = x*y + printf("UNIMPLEMENTED F1 operation @ PC 0x%04x (%d)\n", m_pc, __LINE__); + break; + } + case 0x01: + { + // Ad = aS+p p = x*y + printf("UNIMPLEMENTED F1 operation @ PC 0x%04x (%d)\n", m_pc, __LINE__); + break; + } + case 0x02: + { + // p = x*y + // TODO: What happens to the flags in this operation? + const INT16 y = (m_y & 0xffff0000) >> 16; + m_p = (INT32)((INT16)m_x * y); + justATest = true; + break; + } + case 0x03: + { + // Ad = aS-p p = x*y + printf("UNIMPLEMENTED F1 operation @ PC 0x%04x (%d)\n", m_pc, __LINE__); + break; + } + case 0x04: + { + // Ad = p + printf("UNIMPLEMENTED F1 operation @ PC 0x%04x (%d)\n", m_pc, __LINE__); + break; + } + case 0x05: + { + // Ad = aS+p + printf("UNIMPLEMENTED F1 operation @ PC 0x%04x (%d)\n", m_pc, __LINE__); + break; + } + case 0x06: + { + // nop + justATest = true; + break; + } + case 0x07: + { + // Ad = aS-p + printf("UNIMPLEMENTED F1 operation @ PC 0x%04x (%d)\n", m_pc, __LINE__); + break; + } + case 0x08: + { + // Ad = aS|y + printf("UNIMPLEMENTED F1 operation @ PC 0x%04x (%d)\n", m_pc, __LINE__); + break; + } + case 0x09: + { + // Ad = aS^y + printf("UNIMPLEMENTED F1 operation @ PC 0x%04x (%d)\n", m_pc, __LINE__); + break; + } + case 0x0a: + { + // aS&y + printf("UNIMPLEMENTED F1 operation @ PC 0x%04x (%d)\n", m_pc, __LINE__); + justATest = true; + break; + } + case 0x0b: + { + // aS-y + INT64 aS = *sourceReg; + if (aS & U64(0x800000000)) + aS |= U64(0xfffffff000000000); + + INT64 y = (m_y & 0xffff0000) >> 16; + if (y & 0x8000) + y |= U64(0xffffffffffff0000); + + result = aS-y; + justATest = true; + break; + } + case 0x0c: + { + // Ad = y + printf("UNIMPLEMENTED F1 operation @ PC 0x%04x (%d)\n", m_pc, __LINE__); + break; + } + case 0x0d: + { + // Ad = aS+y + INT64 aS = *sourceReg; + if (aS & U64(0x800000000)) + aS |= U64(0xfffffff000000000); + + INT64 y = (m_y & 0xffff0000) >> 16; + if (y & 0x8000) + y |= U64(0xffffffffffff0000); + + result = aS+y; + break; + } + case 0x0e: + { + // Ad = aS&y + printf("UNIMPLEMENTED F1 operation @ PC 0x%04x (%d)\n", m_pc, __LINE__); + break; + } + case 0x0f: + { + // Ad = aS-y + INT64 aS = *sourceReg; + if (aS & U64(0x800000000)) + aS |= U64(0xfffffff000000000); + + INT64 y = (m_y & 0xffff0000) >> 16; + if (y & 0x8000) + y |= U64(0xffffffffffff0000); + + result = aS-y; + break; + } + } + + // CPU Flags (page 3-4) + // LMI (logical minus) + if (result & U64(0x800000000)) + m_psw |= 0x8000; + else + m_psw &= (~0x8000); + + // LEQ (logical equal) + if (result == U64(0x000000000)) + m_psw |= 0x4000; + else + m_psw &= (~0x4000); + + // LLV (logical overflow) + // TODO + + // LMV (mathematical overflow) + if ((result & U64(0xf00000000)) != U64(0xf00000000) && + (result & U64(0xf00000000)) != U64(0x000000000)) + m_psw |= 0x1000; + else + m_psw &= (~0x1000); + + // If it was a real operation, make sure the data goes where it should + if (!justATest) + *destinationReg = (UINT64)result & U64(0x0000000fffffffff); +} + + +UINT16* dsp16_device::registerFromYFieldUpper(const UINT8& Y) +{ + UINT16* destinationReg = NULL; + const UINT8 N = (Y & 0x0c) >> 2; + switch (N) + { + case 0x00: destinationReg = &m_r0; break; + case 0x01: destinationReg = &m_r1; break; + case 0x02: destinationReg = &m_r2; break; + case 0x03: destinationReg = &m_r3; break; + default: break; + } + return destinationReg; +} + + +void dsp16_device::executeYFieldPost(const UINT8& Y) +{ + UINT16* opReg = registerFromYFieldUpper(Y); + + const UINT8 lower = Y & 0x03; + switch (lower) + { + case 0x00: /* nop */ break; + case 0x01: (*opReg)++; break; + case 0x02: (*opReg)--; break; + case 0x03: (*opReg) += m_j; break; // TODO: J is signed + } +} + + +void dsp16_device::executeZFieldPartOne(const UINT8& Z, UINT16* rN) +{ + const UINT8 lower = Z & 0x03; + switch (lower) + { + case 0x00: /* nop */ break; + case 0x01: (*rN)++; break; + case 0x02: (*rN)--; break; + case 0x03: (*rN) += m_j; break; // TODO: J is signed + } +} + + +void dsp16_device::executeZFieldPartTwo(const UINT8& Z, UINT16* rN) +{ + const UINT8 lower = Z & 0x03; + switch (lower) + { + case 0x00: (*rN)++; break; + case 0x01: /* nop */ break; + case 0x02: (*rN) += 2; break; + case 0x03: (*rN) += m_k; break; // TODO: K is signed + } +} + + +void dsp16_device::execute_one(const UINT16& op, UINT8& cycles, UINT8& pcAdvance) +{ + cycles = 1; + pcAdvance = 0; + +// NOTE: pages 3-5 through 3-19 are good english descriptions of what's up + + const UINT8 opcode = (op >> 11) & 0x1f; + switch(opcode) + { + // Format 1: Multiply/ALU Read/Write Group + case 0x06: + { + DSP_LINE("3-38") + // F1, Y : (page 3-38) + const UINT8 Y = (op & 0x000f); + const UINT8 S = (op & 0x0200) >> 9; + const UINT8 D = (op & 0x0400) >> 10; + const UINT8 F1 = (op & 0x01e0) >> 5; + executeF1Field(F1, D, S); + executeYFieldPost(Y); + cycles = 1; + pcAdvance = 1; + break; + } + case 0x04: case 0x1c: + { + DSP_LINE("3-40") + // F1 Y=a0[1] | F1 Y=a1[1] : (page 3-40) + const UINT8 Y = (op & 0x000f); + //const UINT8 X = (op & 0x0010) >> 4; + const UINT8 S = (op & 0x0200) >> 9; + const UINT8 D = (op & 0x0400) >> 10; + const UINT8 F1 = (op & 0x01e0) >> 5; + UINT16* destinationReg = registerFromYFieldUpper(Y); + // (page 3-18) + UINT16 aRegValue = 0x0000; + if (op & 0xc000) + { + aRegValue = (m_a0 & U64(0x0ffff0000)) >> 16; + } + else + { + aRegValue = (m_a1 & U64(0x0ffff0000)) >> 16; + } + data_write(*destinationReg, aRegValue); + executeYFieldPost(Y); + executeF1Field(F1, D, S); + cycles = 2; + pcAdvance = 1; + break; + } + case 0x16: + { + DSP_LINE("3-42") + // F1, x = Y : (page 3-42) + const UINT8 Y = (op & 0x000f); + const UINT8 S = (op & 0x0200) >> 9; + const UINT8 D = (op & 0x0400) >> 10; + const UINT8 F1 = (op & 0x01e0) >> 5; + executeF1Field(F1, D, S); + UINT16* sourceReg = registerFromYFieldUpper(Y); + writeRegister(&m_x, data_read(*sourceReg)); + executeYFieldPost(Y); + cycles = 1; + pcAdvance = 1; + break; + } + case 0x17: + { + DSP_LINE("3-44") + // F1, y[l] = Y : (page 3-44) + const UINT8 Y = (op & 0x000f); + const UINT8 X = (op & 0x0010) >> 4; + const UINT8 S = (op & 0x0200) >> 9; + const UINT8 D = (op & 0x0400) >> 10; + const UINT8 F1 = (op & 0x01e0) >> 5; + executeF1Field(F1, D, S); + UINT16* sourceReg = registerFromYFieldUpper(Y); + UINT16 sourceValue = data_read(*sourceReg); + switch (X) + { + case 0x00: writeRegister(addressYL(), sourceValue); break; + case 0x01: writeRegister(&m_y, sourceValue); break; + default: break; + } + executeYFieldPost(Y); + cycles = 1; + pcAdvance = 1; + break; + } + case 0x1f: + { + DSP_LINE("3-46") + // F1, y = Y, x = *pt++[i] : (page 3-46) + const UINT8 Y = (op & 0x000f); + const UINT8 X = (op & 0x0010) >> 4; + const UINT8 S = (op & 0x0200) >> 9; + const UINT8 D = (op & 0x0400) >> 10; + const UINT8 F1 = (op & 0x01e0) >> 5; + executeF1Field(F1, D, S); + UINT16* sourceRegR = registerFromYFieldUpper(Y); + writeRegister(&m_y, data_read(*sourceRegR)); + executeYFieldPost(Y); + writeRegister(&m_x, data_read(m_pt)); + switch (X) + { + case 0x00: m_pt++; break; + case 0x01: m_pt += m_i; break; + } + cycles = 2; // TODO: 1 if cached + pcAdvance = 1; + break; + } + case 0x19: case 0x1b: + { + DSP_LINE("3-48") + // F1, y = a0|1, x = *pt++[i] : (page 3-48) + const UINT8 Y = (op & 0x000f); + const UINT8 X = (op & 0x0010) >> 4; + const UINT8 S = (op & 0x0200) >> 9; + const UINT8 D = (op & 0x0400) >> 10; + const UINT8 F1 = (op & 0x01e0) >> 5; + bool useA1 = (opcode == 0x1b); + if (Y != 0x00) printf("Unknown opcode @ PC=0x%04x", m_pc); + m_y = (useA1) ? (m_a1 & 0xffffffff) : (m_a0 & 0xffffffff); // TODO: What happens to Ax when it goes 32 bit (pc=3f & pc=47)? + executeF1Field(F1, D, S); + writeRegister(&m_x, data_read(m_pt)); // TODO: EXM Pin & internal/external ROM? Research. + switch (X) + { + case 0x00: m_pt++; break; + case 0x01: m_pt += m_i; break; + } + cycles = 2; // TODO: 1 if cached + pcAdvance = 1; + break; + } + case 0x14: + { + DSP_LINE("3-53") + // F1, Y = y[l] : (page 3-53) + const UINT8 Y = (op & 0x000f); + const UINT8 X = (op & 0x0010) >> 4; + const UINT8 S = (op & 0x0200) >> 9; + const UINT8 D = (op & 0x0400) >> 10; + const UINT8 F1 = (op & 0x01e0) >> 5; + executeF1Field(F1, D, S); + UINT16* destinationReg = registerFromYFieldUpper(Y); + UINT16 yRegValue = 0x0000; + switch (X) + { + case 0x00: yRegValue = (m_y & 0x0000ffff); break; + case 0x01: yRegValue = (m_y & 0xffff0000) >> 16; break; + default: break; + } + data_write(*destinationReg, yRegValue); + executeYFieldPost(Y); + cycles = 2; + pcAdvance = 1; + break; + } + + // Format 1a: Multiply/ALU Read/Write Group (TODO: Figure out major typo in docs on p3-51) + case 0x07: + { + DSP_LINE("3-50") + // F1, At[1] = Y : (page 3-50) + // TODO: What does the X field do here, exactly? + const UINT8 Y = (op & 0x000f); + const UINT8 S = (op & 0x0200) >> 9; + const UINT8 aT = (op & 0x0400) >> 10; + const UINT8 F1 = (op & 0x01e0) >> 5; + executeF1Field(F1, !aT, S); + UINT64* destinationReg = NULL; + switch(aT) + { + case 0: destinationReg = &m_a1; break; + case 1: destinationReg = &m_a0; break; + default: break; + } + UINT16 sourceAddress = *(registerFromYFieldUpper(Y)); + INT64 sourceValueSigned = (INT16)data_read(sourceAddress); + *destinationReg = sourceValueSigned & U64(0xffffffffff); + executeYFieldPost(Y); + cycles = 1; + pcAdvance = 1; + break; + } + + // Format 2: Multiply/ALU Read/Write Group + case 0x15: + { + DSP_LINE("3-54") + // F1, Z : y[l] : (page 3-54) + const UINT8 Z = (op & 0x000f); + const UINT8 X = (op & 0x0010) >> 4; + const UINT8 S = (op & 0x0200) >> 9; + const UINT8 D = (op & 0x0400) >> 10; + const UINT8 F1 = (op & 0x01e0) >> 5; + executeF1Field(F1, D, S); + UINT16 temp = 0x0000; + UINT16* rN = registerFromYFieldUpper(Z); + switch (X) + { + case 0x00: + temp = m_y & 0x0000ffff; + m_y &= 0xffff0000; + m_y |= data_read(*rN); + executeZFieldPartOne(Z, rN); + data_write(*rN, temp); + executeZFieldPartTwo(Z, rN); + break; + case 0x01: + temp = (m_y & 0xffff0000) >> 16; + m_y &= 0x0000ffff; + m_y |= (data_read(*rN) << 16); + executeZFieldPartOne(Z, rN); + data_write(*rN, temp); + executeZFieldPartTwo(Z, rN); + break; + } + cycles = 2; + pcAdvance = 1; + break; + } + case 0x1d: + { + DSP_LINE("?") + // F1, Z : y, x=*pt++[i] + //const UINT8 Z = (op & 0x000f); + //const UINT8 X = (op & 0x0010) >> 4; + //const UINT8 S = (op & 0x0200) >> 9; + //const UINT8 D = (op & 0x0400) >> 10; + //const UINT8 F1 = (op & 0x01e0) >> 5; + break; + } + + // Format 2a: Multiply/ALU Read/Write Group + case 0x05: + { + DSP_LINE("?") + // F1, Z : aT[1] + //const UINT8 Z = (op & 0x000f); + //const UINT8 X = (op & 0x0010) >> 4; + //const UINT8 S = (op & 0x0200) >> 9; + //const UINT8 aT = (op & 0x0400) >> 10; + //const UINT8 F1 = (op & 0x01e0) >> 5; + break; + } + + // Format 3: Special Functions + case 0x12: + case 0x13: + { + DSP_LINE("3-36") + // if|ifc CON F2 (page 3-36) + const UINT8 CON = (op & 0x001f); + //const UINT8 S = (op & 0x0200) >> 9; + //const UINT8 D = (op & 0x0400) >> 10; + //const UINT8 F2 = (op & 0x01e0) >> 5; + bool conditionFulfilled = conditionTest(CON); + if (conditionFulfilled) + { + printf("Fulfilled condition not yet implemented @ PC=0x%04x\n", m_pc); + } + cycles = 1; + pcAdvance = 1; + break; + } + + // Format 4: Branch Direct Group + case 0x00: case 0x01: + { + DSP_LINE("3-20") + // goto JA : (page 3-20) (DONE) + const UINT16 JA = (op & 0x0fff) | (m_pc & 0xf000); + m_pc = JA; + cycles = 2; + pcAdvance = 0; + break; + } + + case 0x10: case 0x11: + { + DSP_LINE("3-23") + // call JA : (page 3-23) + const UINT16 JA = (op & 0x0fff) | (m_pc & 0xf000); + m_pr = m_pc + 1; + m_pc = JA; + cycles = 2; + pcAdvance = 0; + break; + } + + // Format 5: Branch Indirect Group + case 0x18: + { + DSP_LINE("3-21") + // goto B : (page 3-21) + const UINT8 B = (op & 0x0700) >> 8; + switch (B) + { + case 0x00: m_pc = m_pr; break; + case 0x01: printf("UNIMPLEMENTED branch instruction @ PC 0x%04x\n", m_pc); break; + case 0x02: printf("UNIMPLEMENTED branch instruction @ PC 0x%04x\n", m_pc); break; + case 0x03: printf("UNIMPLEMENTED branch instruction @ PC 0x%04x\n", m_pc); break; + default: logerror("DSP16: Invalid branch indirect instruction executed at PC=0x%04x\n.", m_pc); break; + } + cycles = 2; + pcAdvance = 0; + break; + } + + // Format 6: Contitional Branch Qualifier/Software Interrupt (icall) + case 0x1a: + { + DSP_LINE("3-22") + // if CON [goto/call/return] : (page 3-22) + const UINT8 CON = (op & 0x001f); + bool conditionFulfilled = conditionTest(CON); + cycles = 3; // TODO: This may need to interact with the next opcode to make sure it doesn't exceed 3? + pcAdvance = 1; + if (!conditionFulfilled) + { + pcAdvance = 2; + } + break; + } + + // Format 7: Data Move Group + case 0x09: case 0x0b: + { + DSP_LINE("3-29") + // R = aS : (page 3-29) + // TODO: Fix register pdxX (pc=338) + const UINT8 R = (op & 0x03f0) >> 4; + const UINT8 S = (op & 0x1000) >> 12; + void* destinationReg = registerFromRTable(R); + UINT64* sourceReg = (S) ? &m_a1 : &m_a0; + UINT16 sourceValue = (*sourceReg & U64(0x0ffff0000)) >> 16; + writeRegister(destinationReg, sourceValue); + cycles = 2; + pcAdvance = 1; + break; + } + case 0x08: + { + DSP_LINE("3-30") + // aT = R : (page 3-30) + const UINT8 R = (op & 0x03f0) >> 4; + const UINT8 aT = (op & 0x0400) >> 10; + UINT64* destinationReg = NULL; + switch(aT) + { + case 0: destinationReg = &m_a1; break; + case 1: destinationReg = &m_a0; break; + default: break; + } + void* sourceReg = registerFromRTable(R); + *destinationReg &= U64(0x00000ffff); + *destinationReg |= (*(UINT16*)sourceReg) << 16; // TODO: Fix for all registers + if (*(UINT16*)sourceReg & 0x8000) + *destinationReg |= U64(0xf00000000); + // TODO: Special function encoding + cycles = 2; + pcAdvance = 1; + break; + } + case 0x0f: + { + DSP_LINE("3-32") + // R = Y : (page 3-32) + const UINT8 Y = (op & 0x000f); + const UINT8 R = (op & 0x03f0) >> 4; + UINT16* sourceReg = registerFromYFieldUpper(Y); + void* destinationReg = registerFromRTable(R); + writeRegister(destinationReg, data_read(*sourceReg)); + executeYFieldPost(Y); + cycles = 2; + pcAdvance = 1; + break; + } + case 0x0c: + { + DSP_LINE("3-33") + // Y = R : (page 3-33) + // TODO: Zero & Sign extend i, c0, c1, c2, and auc + const UINT8 Y = (op & 0x000f); + const UINT8 R = (op & 0x03f0) >> 4; + UINT16* destinationReg = registerFromYFieldUpper(Y); + UINT16* sourceReg = (UINT16*)registerFromRTable(R); // TODO: This won't work for certain registers! + data_write(*destinationReg, *sourceReg); // Fix in data_write() maybe? + executeYFieldPost(Y); + cycles = 2; + pcAdvance = 1; + break; + } + case 0x0d: + { + DSP_LINE("?") + // Z : R + //const UINT8 Z = (op & 0x000f); + //const UINT8 R = (op & 0x03f0) >> 4; + break; + } + + // Format 8: Data Move (immediate operand - 2 words) + case 0x0a: + { + DSP_LINE("3-28") + // R = N : (page 3-28) (DONE) + // NOTE: The docs speak of register sources & sign extension, but this is a register + // destination, so, typo? If so, what does one do with the overflow bits? + const UINT8 R = (op & 0x03f0) >> 4; + const UINT16 iVal = opcode_read(1); + void* destinationReg = registerFromRTable(R); + writeRegister(destinationReg, iVal); + cycles = 2; + pcAdvance = 2; + break; + } + + // Format 9: Short Immediate Group + case 0x02: case 0x03: + { + DSP_LINE("3-27") + // R = M : (page 3-27) + // TODO: Figure out notes about the DSP16A vs the DSP16. 9 bit is very DSP16... + const UINT16 M = (op & 0x01ff); + const UINT8 R = (op & 0x0e00) >> 9; + void* destinationReg = registerFromRImmediateField(R); + // Sign extend if the destination is j or k + UINT16 mValue = M; + if (destinationReg == &m_j || destinationReg == &m_k) + { + if (mValue & 0x0100) mValue |= 0xfe00; + } + writeRegister(destinationReg, mValue); + cycles = 1; + pcAdvance = 1; + break; + } + + // Format 10: do - redo + case 0x0e: + { + DSP_LINE("3-25/3-26") + // do|redo K : (pages 3-25 & 3-26) + // TODO: The timings are intricate to say the least... + const UINT8 K = (op & 0x007f); + const UINT8 NI = (op & 0x0780) >> 7; + if (NI != 0) + { + // Do + m_cacheStart = m_pc + 1; + m_cacheEnd = m_pc + 1 + NI; + m_cacheIterations = K-1; // -1 because we check the counter @ the end + cycles = 1; + pcAdvance = 1; + } + else + { + // Redo + m_cacheIterations = K-1; // -1 because we check the counter @ the end + m_cacheRedoNextPC = m_pc + 1; + m_pc = m_cacheStart; + cycles = 2; + pcAdvance = 0; + } + break; + } + + // RESERVED + case 0x1e: + { + DSP_LINE("XXX") + break; + } + + // UNKNOWN + default: + { + DSP_LINE("XXX") + break; + } + } + + // Handle end-of-cache conditions for do|redos + if (m_cacheIterations == 0 && m_cacheRedoNextPC != CACHE_INVALID) + { + // You've reached the end of a cache loop after a redo opcode. + m_pc = m_cacheRedoNextPC; + m_cacheRedoNextPC = CACHE_INVALID; + pcAdvance = 0; + } + if (m_cacheIterations > 0 && (m_pc+pcAdvance == m_cacheEnd)) + { + // A regular iteration on a cached loop. + m_cacheIterations--; + m_pc = m_cacheStart; + pcAdvance = 0; + } +} diff --git a/src/devices/cpu/dsp32/dsp32.c b/src/devices/cpu/dsp32/dsp32.c new file mode 100644 index 00000000000..21de1f18a74 --- /dev/null +++ b/src/devices/cpu/dsp32/dsp32.c @@ -0,0 +1,874 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + dsp32.c + Core implementation for the portable DSP32 emulator. + +**************************************************************************** + + Important note: + + At this time, the emulator is rather incomplete. However, it is + sufficiently complete to run both Race Drivin' and Hard Drivin's + Airborne, which is all I was after. + + Things that still need to be implemented: + + * interrupts + * carry-reverse add operations + * do loops + * ieee/dsp conversions + * input/output conversion + * serial I/O + + In addition, there are several optimizations enabled which make + assumptions about the code which may not be valid for other + applications. Check dsp32ops.inc for details. + +***************************************************************************/ + +#include "emu.h" +#include "debugger.h" +#include "dsp32.h" + + +//************************************************************************** +// DEBUGGING +//************************************************************************** + +#define DETECT_MISALIGNED_MEMORY 0 + + + +//************************************************************************** +// CONSTANTS +//************************************************************************** + +// internal register numbering for PIO registers +#define PIO_PAR 0 +#define PIO_PDR 1 +#define PIO_EMR 2 +#define PIO_ESR 3 +#define PIO_PCR 4 +#define PIO_PIR 5 +#define PIO_PARE 6 +#define PIO_PDR2 7 +#define PIO_RESERVED 8 + +#define UPPER (0x00ff << 8) +#define LOWER (0xff00 << 8) + +// bits in the PCR register +#define PCR_RESET 0x001 +#define PCR_REGMAP 0x002 +#define PCR_ENI 0x004 +#define PCR_DMA 0x008 +#define PCR_AUTO 0x010 +#define PCR_PDFs 0x020 +#define PCR_PIFs 0x040 +#define PCR_RES 0x080 +#define PCR_DMA32 0x100 +#define PCR_PIO16 0x200 +#define PCR_FLG 0x400 + +// internal flag bits +#define UFLAGBIT 1 +#define VFLAGBIT 2 + + + +//************************************************************************** +// MACROS +//************************************************************************** + +// register mapping +#define R0 m_r[0] +#define R1 m_r[1] +#define R2 m_r[2] +#define R3 m_r[3] +#define R4 m_r[4] +#define R5 m_r[5] +#define R6 m_r[6] +#define R7 m_r[7] +#define R8 m_r[8] +#define R9 m_r[9] +#define R10 m_r[10] +#define R11 m_r[11] +#define R12 m_r[12] +#define R13 m_r[13] +#define R14 m_r[14] +#define PC m_r[15] +#define R0_ALT m_r[16] +#define R15 m_r[17] +#define R16 m_r[18] +#define R17 m_r[19] +#define R18 m_r[20] +#define R19 m_r[21] +#define RMM m_r[22] +#define RPP m_r[23] +#define R20 m_r[24] +#define R21 m_r[25] +#define DAUC m_r[26] +#define IOC m_r[27] +#define R22 m_r[29] +#define PCSH m_r[30] + +#define A0 m_a[0] +#define A1 m_a[1] +#define A2 m_a[2] +#define A3 m_a[3] +#define A_0 m_a[4] +#define A_1 m_a[5] + +#define zFLAG ((m_nzcflags & 0xffffff) == 0) +#define nFLAG ((m_nzcflags & 0x800000) != 0) +#define cFLAG ((m_nzcflags & 0x1000000) != 0) +#define vFLAG ((m_vflags & 0x800000) != 0) +#define ZFLAG (m_NZflags == 0) +#define NFLAG (m_NZflags < 0) +#define UFLAG (m_VUflags & UFLAGBIT) +#define VFLAG (m_VUflags & VFLAGBIT) + + + +//************************************************************************** +// DEVICE INTERFACE +//************************************************************************** + +const device_type DSP32C = &device_creator; + +//------------------------------------------------- +// dsp32c_device - constructor +//------------------------------------------------- + +dsp32c_device::dsp32c_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : cpu_device(mconfig, DSP32C, "DSP32C", tag, owner, clock, "dsp32c", __FILE__), + m_program_config("program", ENDIANNESS_LITTLE, 32, 24), + m_pin(0), + m_pout(0), + m_ivtp(0), + m_nzcflags(0), + m_vflags(0), + m_NZflags(0), + m_VUflags(0), + m_abuf_index(0), + m_mbuf_index(0), + m_par(0), + m_pare(0), + m_pdr(0), + m_pdr2(0), + m_pir(0), + m_pcr(0), + m_emr(0), + m_esr(0), + m_pcw(0), + m_piop(0), + m_ibuf(0), + m_isr(0), + m_obuf(0), + m_osr(0), + m_iotemp(0), + m_lastp(0), + m_icount(0), + m_lastpins(0), + m_ppc(0), + m_program(NULL), + m_direct(NULL), + m_output_pins_changed(*this) +{ + // set our instruction counter + m_icountptr = &m_icount; +} + +//------------------------------------------------- +// device_start - start up the device +//------------------------------------------------- + +void dsp32c_device::device_start() +{ + m_output_pins_changed.resolve_safe(); + + // get our address spaces + m_program = &space(AS_PROGRAM); + m_direct = &m_program->direct(); + + // register our state for the debugger + std::string tempstr; + state_add(STATE_GENPC, "GENPC", m_r[15]).noshow(); + state_add(STATE_GENPCBASE, "GENPCBASE", m_ppc).noshow(); + state_add(STATE_GENSP, "GENSP", m_r[21]).noshow(); + state_add(STATE_GENFLAGS, "GENFLAGS", m_iotemp).callimport().callexport().formatstr("%6s").noshow(); + state_add(DSP32_PC, "PC", m_r[15]).mask(0xffffff); + for (int regnum = 0; regnum <= 14; regnum++) + state_add(DSP32_R0 + regnum, strformat(tempstr, "R%d", regnum).c_str(), m_r[regnum]).mask(0xffffff); + state_add(DSP32_R15, "R15", m_r[17]).mask(0xffffff); + state_add(DSP32_R16, "R16", m_r[18]).mask(0xffffff); + state_add(DSP32_R17, "R17", m_r[19]).mask(0xffffff); + state_add(DSP32_R18, "R18", m_r[20]).mask(0xffffff); + state_add(DSP32_R19, "R19", m_r[21]).mask(0xffffff); + state_add(DSP32_R20, "R20", m_r[24]).mask(0xffffff); + state_add(DSP32_R21, "R21", m_r[25]).mask(0xffffff); + state_add(DSP32_R22, "R22", m_r[29]).mask(0xffffff); + state_add(DSP32_PIN, "PIN", m_pin).mask(0xffffff); + state_add(DSP32_POUT, "POUT", m_pout).mask(0xffffff); + state_add(DSP32_IVTP, "IVTP", m_ivtp).mask(0xffffff); + state_add(DSP32_A0, "A0", m_a[0]).formatstr("%8s"); + state_add(DSP32_A1, "A1", m_a[1]).formatstr("%8s"); + state_add(DSP32_A2, "A2", m_a[2]).formatstr("%8s"); + state_add(DSP32_A3, "A3", m_a[3]).formatstr("%8s"); + state_add(DSP32_DAUC, "DAUC", m_r[26]).mask(0xff); + state_add(DSP32_PAR, "PAR", m_par); + state_add(DSP32_PDR, "PDR", m_pdr); + state_add(DSP32_PIR, "PIR", m_pir); + state_add(DSP32_PCR, "PCR", m_iotemp).mask(0x3ff).callimport(); + state_add(DSP32_EMR, "EMR", m_emr); + state_add(DSP32_ESR, "ESR", m_esr); + state_add(DSP32_PCW, "PCW", m_pcw); + state_add(DSP32_PIOP, "PIOP", m_piop); + state_add(DSP32_IBUF, "IBUF", m_ibuf); + state_add(DSP32_ISR, "ISR", m_isr); + state_add(DSP32_OBUF, "OBUF", m_obuf); + state_add(DSP32_OSR, "OSR" , m_osr); + state_add(DSP32_IOC, "IOC", m_r[27]).mask(0xfffff); + + // register our state for saving + save_item(NAME(m_r)); + save_item(NAME(m_pin)); + save_item(NAME(m_pout)); + save_item(NAME(m_ivtp)); + save_item(NAME(m_nzcflags)); + save_item(NAME(m_vflags)); + save_item(NAME(m_a)); + save_item(NAME(m_NZflags)); + save_item(NAME(m_VUflags)); + save_item(NAME(m_abuf)); + save_item(NAME(m_abufreg)); + save_item(NAME(m_abufVUflags)); + save_item(NAME(m_abufNZflags)); + save_item(NAME(m_abufcycle)); + save_item(NAME(m_abuf_index)); + save_item(NAME(m_mbufaddr)); + save_item(NAME(m_mbufdata)); + save_item(NAME(m_par)); + save_item(NAME(m_pare)); + save_item(NAME(m_pdr)); + save_item(NAME(m_pdr2)); + save_item(NAME(m_pir)); + save_item(NAME(m_pcr)); + save_item(NAME(m_emr)); + save_item(NAME(m_esr)); + save_item(NAME(m_pcw)); + save_item(NAME(m_piop)); + save_item(NAME(m_ibuf)); + save_item(NAME(m_isr)); + save_item(NAME(m_obuf)); + save_item(NAME(m_osr)); + save_item(NAME(m_lastpins)); + save_item(NAME(m_ppc)); +} + + +//------------------------------------------------- +// device_reset - reset the device +//------------------------------------------------- + +void dsp32c_device::device_reset() +{ + // reset goes to 0 + PC = 0; + + // clear some registers + m_pcw &= 0x03ff; + m_pcr = PCR_RESET; + m_esr = 0; + m_emr = 0xffff; + + // clear the output pins + m_output_pins_changed(0); + + // initialize fixed registers + R0 = R0_ALT = 0; + RMM = -1; + RPP = 1; + A_0 = 0.0; + A_1 = 1.0; + + // init internal stuff + m_abufcycle[0] = m_abufcycle[1] = m_abufcycle[2] = m_abufcycle[3] = 12345678; + m_mbufaddr[0] = m_mbufaddr[1] = m_mbufaddr[2] = m_mbufaddr[3] = 1; +} + + +//------------------------------------------------- +// memory_space_config - return the configuration +// of the specified address space, or NULL if +// the space doesn't exist +//------------------------------------------------- + +const address_space_config *dsp32c_device::memory_space_config(address_spacenum spacenum) const +{ + return (spacenum == AS_PROGRAM) ? &m_program_config : NULL; +} + + +//------------------------------------------------- +// state_import - import state into the device, +// after it has been set +//------------------------------------------------- + +void dsp32c_device::state_import(const device_state_entry &entry) +{ + switch (entry.index()) + { + case STATE_GENFLAGS: + break; + + case DSP32_PCR: + update_pcr(m_iotemp); + break; + + default: + fatalerror("dsp32c_device::state_import called for unexpected value\n"); + } +} + + +//------------------------------------------------- +// state_export - export state out of the device +//------------------------------------------------- + +void dsp32c_device::state_export(const device_state_entry &entry) +{ + switch (entry.index()) + { + case STATE_GENFLAGS: + // no actual flags register, so just make something up + m_iotemp = ((zFLAG != 0) << 0) | + ((nFLAG != 0) << 1) | + ((cFLAG != 0) << 2) | + ((vFLAG != 0) << 3) | + ((ZFLAG != 0) << 4) | + ((NFLAG != 0) << 5) | + ((UFLAG != 0) << 6) | + ((VFLAG != 0) << 7); + break; + + case DSP32_PCR: + m_iotemp = m_pcr; + break; + + default: + fatalerror("dsp32c_device::state_export called for unexpected value\n"); + } +} + + +//------------------------------------------------- +// state_string_export - export state as a string +// for the debugger +//------------------------------------------------- + +void dsp32c_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + switch (entry.index()) + { + case STATE_GENFLAGS: + strprintf(str, "%c%c%c%c%c%c%c%c", + NFLAG ? 'N':'.', + ZFLAG ? 'Z':'.', + UFLAG ? 'U':'.', + VFLAG ? 'V':'.', + nFLAG ? 'n':'.', + zFLAG ? 'z':'.', + cFLAG ? 'c':'.', + vFLAG ? 'v':'.'); + break; + + case DSP32_A0: + case DSP32_A1: + case DSP32_A2: + case DSP32_A3: + strprintf(str, "%8g", *(double *)entry.dataptr()); + break; + } +} + + +//------------------------------------------------- +// disasm_min_opcode_bytes - return the length +// of the shortest instruction, in bytes +//------------------------------------------------- + +UINT32 dsp32c_device::disasm_min_opcode_bytes() const +{ + return 4; +} + + +//------------------------------------------------- +// disasm_max_opcode_bytes - return the length +// of the longest instruction, in bytes +//------------------------------------------------- + +UINT32 dsp32c_device::disasm_max_opcode_bytes() const +{ + return 4; +} + + +//------------------------------------------------- +// disasm_disassemble - call the disassembly +// helper function +//------------------------------------------------- + +offs_t dsp32c_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( dsp32c ); + return CPU_DISASSEMBLE_NAME(dsp32c)(this, buffer, pc, oprom, opram, options); +} + + + + +//************************************************************************** +// MEMORY ACCESSORS +//************************************************************************** + +inline UINT32 dsp32c_device::ROPCODE(offs_t pc) +{ + return m_direct->read_dword(pc); +} + +inline UINT8 dsp32c_device::RBYTE(offs_t addr) +{ + return m_program->read_byte(addr); +} + +inline void dsp32c_device::WBYTE(offs_t addr, UINT8 data) +{ + m_program->write_byte(addr, data); +} + +inline UINT16 dsp32c_device::RWORD(offs_t addr) +{ +#if DETECT_MISALIGNED_MEMORY + if (addr & 1) fprintf(stderr, "Unaligned word read @ %06X, PC=%06X\n", addr, PC); +#endif + return m_program->read_word(addr); +} + +inline UINT32 dsp32c_device::RLONG(offs_t addr) +{ +#if DETECT_MISALIGNED_MEMORY + if (addr & 3) fprintf(stderr, "Unaligned long read @ %06X, PC=%06X\n", addr, PC); +#endif + return m_program->read_dword(addr); +} + +inline void dsp32c_device::WWORD(offs_t addr, UINT16 data) +{ +#if DETECT_MISALIGNED_MEMORY + if (addr & 1) fprintf(stderr, "Unaligned word write @ %06X, PC=%06X\n", addr, PC); +#endif + m_program->write_word(addr, data); +} + +inline void dsp32c_device::WLONG(offs_t addr, UINT32 data) +{ +#if DETECT_MISALIGNED_MEMORY + if (addr & 3) fprintf(stderr, "Unaligned long write @ %06X, PC=%06X\n", addr, PC); +#endif + m_program->write_dword(addr, data); +} + + + +//************************************************************************** +// IRQ HANDLING +//************************************************************************** + +void dsp32c_device::check_irqs() +{ + // finish me! +} + + +void dsp32c_device::set_irq_line(int irqline, int state) +{ + // finish me! +} + + + +//************************************************************************** +// REGISTER HANDLING +//************************************************************************** + +void dsp32c_device::update_pcr(UINT16 newval) +{ + UINT16 oldval = m_pcr; + m_pcr = newval; + + // reset the chip if we get a reset + if ((oldval & PCR_RESET) == 0 && (newval & PCR_RESET) != 0) + reset(); +} + + + +//************************************************************************** +// OUTPUT HANDLING +//************************************************************************** + +void dsp32c_device::update_pins(void) +{ + if (m_pcr & PCR_ENI) + { + UINT16 newoutput = 0; + + if (m_pcr & PCR_PIFs) + newoutput |= DSP32_OUTPUT_PIF; + + if (m_pcr & PCR_PDFs) + newoutput |= DSP32_OUTPUT_PDF; + + if (newoutput != m_lastpins) + { + m_lastpins = newoutput; + m_output_pins_changed(newoutput); + } + } +} + + + +//************************************************************************** +// CORE INCLUDE +//************************************************************************** + +#include "dsp32ops.inc" + + + +//************************************************************************** +// CORE EXECUTION LOOP +//************************************************************************** + +//------------------------------------------------- +// execute_min_cycles - return minimum number of +// cycles it takes for one instruction to execute +//------------------------------------------------- + +UINT32 dsp32c_device::execute_min_cycles() const +{ + return 4; +} + + +//------------------------------------------------- +// execute_max_cycles - return maximum number of +// cycles it takes for one instruction to execute +//------------------------------------------------- + +UINT32 dsp32c_device::execute_max_cycles() const +{ + return 4; +} + + +//------------------------------------------------- +// execute_input_lines - return the number of +// input/interrupt lines +//------------------------------------------------- + +UINT32 dsp32c_device::execute_input_lines() const +{ + return 2; +} + + +void dsp32c_device::execute_set_input(int inputnum, int state) +{ +} + + +void dsp32c_device::execute_run() +{ + // skip if halted + if ((m_pcr & PCR_RESET) == 0) + { + m_icount = 0; + return; + } + + // update buffered accumulator values + m_abufcycle[0] += m_icount; + m_abufcycle[1] += m_icount; + m_abufcycle[2] += m_icount; + m_abufcycle[3] += m_icount; + + // handle interrupts + check_irqs(); + + while (m_icount > 0) + execute_one(); + + // normalize buffered accumulator values + m_abufcycle[0] -= m_icount; + m_abufcycle[1] -= m_icount; + m_abufcycle[2] -= m_icount; + m_abufcycle[3] -= m_icount; +} + + + +//************************************************************************** +// PARALLEL INTERFACE WRITES +//************************************************************************** + +const UINT32 dsp32c_device::s_regmap[4][16] = +{ + { // DSP32 compatible mode + PIO_PAR|LOWER, PIO_PAR|UPPER, PIO_PDR|LOWER, PIO_PDR|UPPER, + PIO_EMR|LOWER, PIO_EMR|UPPER, PIO_ESR|LOWER, PIO_PCR|LOWER, + PIO_PIR|UPPER, PIO_PIR|UPPER, PIO_PIR|UPPER, PIO_PIR|UPPER, + PIO_PIR|UPPER, PIO_PIR|UPPER, PIO_PIR|UPPER, PIO_PIR|UPPER + }, + { // DSP32C 8-bit mode + PIO_PAR|LOWER, PIO_PAR|UPPER, PIO_PDR|LOWER, PIO_PDR|UPPER, + PIO_EMR|LOWER, PIO_EMR|UPPER, PIO_ESR|LOWER, PIO_PCR|LOWER, + PIO_PIR|LOWER, PIO_PIR|UPPER, PIO_PCR|UPPER, PIO_PARE|LOWER, + PIO_PDR2|LOWER,PIO_PDR2|UPPER,PIO_RESERVED, PIO_RESERVED + }, + { // DSP32C illegal mode + PIO_RESERVED, PIO_RESERVED, PIO_RESERVED, PIO_RESERVED, + PIO_RESERVED, PIO_RESERVED, PIO_RESERVED, PIO_RESERVED, + PIO_RESERVED, PIO_RESERVED, PIO_RESERVED, PIO_RESERVED, + PIO_RESERVED, PIO_RESERVED, PIO_RESERVED, PIO_RESERVED + }, + { // DSP32C 16-bit mode + PIO_PAR, PIO_RESERVED, PIO_PDR, PIO_RESERVED, + PIO_EMR, PIO_RESERVED, PIO_ESR|LOWER, PIO_PCR, + PIO_PIR, PIO_RESERVED, PIO_RESERVED, PIO_PARE|LOWER, + PIO_PDR2, PIO_RESERVED, PIO_RESERVED, PIO_RESERVED + } +}; + + + +//************************************************************************** +// PARALLEL INTERFACE WRITES +//************************************************************************** + +void dsp32c_device::dma_increment() +{ + if (m_pcr & PCR_AUTO) + { + int amount = (m_pcr & PCR_DMA32) ? 4 : 2; + m_par += amount; + if (m_par < amount) + m_pare++; + } +} + + +void dsp32c_device::dma_load() +{ + // only process if DMA is enabled + if (m_pcr & PCR_DMA) + { + UINT32 addr = m_par | (m_pare << 16); + + // 16-bit case + if (!(m_pcr & PCR_DMA32)) + m_pdr = RWORD(addr & 0xfffffe); + + // 32-bit case + else + { + UINT32 temp = RLONG(addr & 0xfffffc); + m_pdr = temp >> 16; + m_pdr2 = temp & 0xffff; + } + + // set the PDF flag to indicate we have data ready + update_pcr(m_pcr | PCR_PDFs); + } +} + + +void dsp32c_device::dma_store() +{ + // only process if DMA is enabled + if (m_pcr & PCR_DMA) + { + UINT32 addr = m_par | (m_pare << 16); + + // 16-bit case + if (!(m_pcr & PCR_DMA32)) + WWORD(addr & 0xfffffe, m_pdr); + + // 32-bit case + else + WLONG(addr & 0xfffffc, (m_pdr << 16) | m_pdr2); + + // clear the PDF flag to indicate we have taken the data + update_pcr(m_pcr & ~PCR_PDFs); + } +} + + +void dsp32c_device::pio_w(int reg, int data) +{ + UINT16 mask; + UINT8 mode; + + // look up register and mask + mode = ((m_pcr >> 8) & 2) | ((m_pcr >> 1) & 1); + reg = s_regmap[mode][reg]; + mask = reg >> 8; + if (mask == 0x00ff) data <<= 8; + data &= ~mask; + reg &= 0xff; + + // switch off the register + switch (reg) + { + case PIO_PAR: + m_par = (m_par & mask) | data; + + // trigger a load on the upper half + if (!(mask & 0xff00)) + dma_load(); + break; + + case PIO_PARE: + m_pare = (m_pare & mask) | data; + break; + + case PIO_PDR: + m_pdr = (m_pdr & mask) | data; + + // trigger a write and PDF setting on the upper half + if (!(mask & 0xff00)) + { + dma_store(); + dma_increment(); + update_pins(); + } + break; + + case PIO_PDR2: + m_pdr2 = (m_pdr2 & mask) | data; + break; + + case PIO_EMR: + m_emr = (m_emr & mask) | data; + break; + + case PIO_ESR: + m_esr = (m_esr & mask) | data; + break; + + case PIO_PCR: + mask |= 0x0060; + data &= ~mask; + update_pcr((m_pcr & mask) | data); + break; + + case PIO_PIR: + m_pir = (m_pir & mask) | data; + + // set PIF on upper half + if (!(mask & 0xff00)) + { + update_pcr(m_pcr | PCR_PIFs); + update_pins(); + } + break; + + // error case + default: + logerror("dsp32_pio_w called on invalid register %d\n", reg); + break; + } +} + + + +//************************************************************************** +// PARALLEL INTERFACE READS +//************************************************************************** + +int dsp32c_device::pio_r(int reg) +{ + UINT16 mask, result = 0xffff; + UINT8 mode, shift = 0; + + // look up register and mask + mode = ((m_pcr >> 8) & 2) | ((m_pcr >> 1) & 1); + reg = s_regmap[mode][reg]; + mask = reg >> 8; + if (mask == 0x00ff) mask = 0xff00, shift = 8; + reg &= 0xff; + + // switch off the register + switch (reg) + { + case PIO_PAR: + result = m_par | 1; + break; + + case PIO_PARE: + result = m_pare; + break; + + case PIO_PDR: + result = m_pdr; + + // trigger an increment on the lower half + if (shift != 8) + dma_increment(); + + // trigger a fetch on the upper half + if (!(mask & 0xff00)) + { + dma_load(); + update_pins(); + } + break; + + case PIO_PDR2: + result = m_pdr2; + break; + + case PIO_EMR: + result = m_emr; + break; + + case PIO_ESR: + result = m_esr; + break; + + case PIO_PCR: + result = m_pcr; + break; + + case PIO_PIR: + if (!(mask & 0xff00)) + { + update_pcr(m_pcr & ~PCR_PIFs); // clear PIFs + update_pins(); + } + result = m_pir; + break; + + // error case + default: + logerror("dsp32_pio_w called on invalid register %d\n", reg); + break; + } + + return (result >> shift) & ~mask; +} diff --git a/src/devices/cpu/dsp32/dsp32.h b/src/devices/cpu/dsp32/dsp32.h new file mode 100644 index 00000000000..1ef1642f6c2 --- /dev/null +++ b/src/devices/cpu/dsp32/dsp32.h @@ -0,0 +1,439 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + dsp32.h + Interface file for the portable DSP32 emulator. + +***************************************************************************/ + +#pragma once + +#ifndef __DSP32_H__ +#define __DSP32_H__ + + +//************************************************************************** +// CONSTANTS +//************************************************************************** + +// IRQ sources +const int DSP32_IRQ0 = 0; // IRQ0 +const int DSP32_IRQ1 = 1; // IRQ1 + +// pin signal bits +const int DSP32_OUTPUT_PIF = 0x01; +const int DSP32_OUTPUT_PDF = 0x02; + +// register enumeration +enum +{ + // CAU + DSP32_PC=1, + DSP32_R0, + DSP32_R1, + DSP32_R2, + DSP32_R3, + DSP32_R4, + DSP32_R5, + DSP32_R6, + DSP32_R7, + DSP32_R8, + DSP32_R9, + DSP32_R10, + DSP32_R11, + DSP32_R12, + DSP32_R13, + DSP32_R14, + DSP32_R15, + DSP32_R16, + DSP32_R17, + DSP32_R18, + DSP32_R19, + DSP32_R20, + DSP32_R21, + DSP32_R22, + DSP32_PIN, + DSP32_POUT, + DSP32_IVTP, + + // DAU + DSP32_A0, + DSP32_A1, + DSP32_A2, + DSP32_A3, + DSP32_DAUC, + + // PIO + DSP32_PAR, + DSP32_PDR, + DSP32_PIR, + DSP32_PCR, + DSP32_EMR, + DSP32_ESR, + DSP32_PCW, + DSP32_PIOP, + + // SIO + DSP32_IBUF, + DSP32_ISR, + DSP32_OBUF, + DSP32_OSR, + DSP32_IOC +}; + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +#define MCFG_DSP32C_OUTPUT_CALLBACK(_write) \ + devcb = &dsp32c_device::set_output_pins_callback(*device, DEVCB_##_write); + +// ======================> dsp32c_device + +class dsp32c_device : public cpu_device +{ +public: + // construction/destruction + dsp32c_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + template static devcb_base &set_output_pins_callback(device_t &device, _Object object) { return downcast(device).m_output_pins_changed.set_callback(object); } + + + // public interfaces + void pio_w(int reg, int data); + int pio_r(int reg); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_execute_interface overrides + virtual UINT32 execute_min_cycles() const; + virtual UINT32 execute_max_cycles() const; + virtual UINT32 execute_input_lines() const; + virtual void execute_run(); + virtual void execute_set_input(int inputnum, int state); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const; + + // device_state_interface overrides + virtual void state_import(const device_state_entry &entry); + virtual void state_export(const device_state_entry &entry); + virtual void state_string_export(const device_state_entry &entry, std::string &str); + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const; + virtual UINT32 disasm_max_opcode_bytes() const; + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + + // memory accessors + UINT32 ROPCODE(offs_t pc); + UINT8 RBYTE(offs_t addr); + void WBYTE(offs_t addr, UINT8 data); + UINT16 RWORD(offs_t addr); + UINT32 RLONG(offs_t addr); + void WWORD(offs_t addr, UINT16 data); + void WLONG(offs_t addr, UINT32 data); + + // interrupts + void check_irqs(); + void set_irq_line(int irqline, int state); + + void update_pcr(UINT16 newval); + void update_pins(void); + void illegal(UINT32 op); + void unimplemented(UINT32 op); + void execute_one(); + + // CAU helpers + UINT32 cau_read_pi_special(UINT8 i); + void cau_write_pi_special(UINT8 i, UINT32 val); + UINT8 cau_read_pi_1byte(int pi); + UINT16 cau_read_pi_2byte(int pi); + UINT32 cau_read_pi_4byte(int pi); + void cau_write_pi_1byte(int pi, UINT8 val); + void cau_write_pi_2byte(int pi, UINT16 val); + void cau_write_pi_4byte(int pi, UINT32 val); + + // DAU helpers + double dau_get_amult(int aidx); + double dau_get_anzflags(); + UINT8 dau_get_avuflags(); + void remember_last_dau(int aidx); + void dau_set_val_noflags(int aidx, double res); + void dau_set_val_flags(int aidx, double res); + double dsp_to_double(UINT32 val); + UINT32 double_to_dsp(double val); + double dau_read_pi_special(int i); + void dau_write_pi_special(int i, double val); + double dau_read_pi_double_1st(int pi, int multiplier); + double dau_read_pi_double_2nd(int pi, int multiplier, double xval); + UINT32 dau_read_pi_4bytes(int pi); + UINT16 dau_read_pi_2bytes(int pi); + void dau_write_pi_double(int pi, double val); + void dau_write_pi_4bytes(int pi, UINT32 val); + void dau_write_pi_2bytes(int pi, UINT16 val); + + // common condition routine + int condition(int cond); + + // CAU branch instruction implementation + void nop(UINT32 op); + void goto_t(UINT32 op); + void goto_pl(UINT32 op); + void goto_mi(UINT32 op); + void goto_ne(UINT32 op); + void goto_eq(UINT32 op); + void goto_vc(UINT32 op); + void goto_vs(UINT32 op); + void goto_cc(UINT32 op); + void goto_cs(UINT32 op); + void goto_ge(UINT32 op); + void goto_lt(UINT32 op); + void goto_gt(UINT32 op); + void goto_le(UINT32 op); + void goto_hi(UINT32 op); + void goto_ls(UINT32 op); + void goto_auc(UINT32 op); + void goto_aus(UINT32 op); + void goto_age(UINT32 op); + void goto_alt(UINT32 op); + void goto_ane(UINT32 op); + void goto_aeq(UINT32 op); + void goto_avc(UINT32 op); + void goto_avs(UINT32 op); + void goto_agt(UINT32 op); + void goto_ale(UINT32 op); + void goto_ibe(UINT32 op); + void goto_ibf(UINT32 op); + void goto_obf(UINT32 op); + void goto_obe(UINT32 op); + void goto_pde(UINT32 op); + void goto_pdf(UINT32 op); + void goto_pie(UINT32 op); + void goto_pif(UINT32 op); + void goto_syc(UINT32 op); + void goto_sys(UINT32 op); + void goto_fbc(UINT32 op); + void goto_fbs(UINT32 op); + void goto_irq1lo(UINT32 op); + void goto_irq1hi(UINT32 op); + void goto_irq2lo(UINT32 op); + void goto_irq2hi(UINT32 op); + void dec_goto(UINT32 op); + void call(UINT32 op); + void goto24(UINT32 op); + void call24(UINT32 op); + void do_i(UINT32 op); + void do_r(UINT32 op); + + // CAU 16-bit arithmetic implementation + void add_si(UINT32 op); + void add_ss(UINT32 op); + void mul2_s(UINT32 op); + void subr_ss(UINT32 op); + void addr_ss(UINT32 op); + void sub_ss(UINT32 op); + void neg_s(UINT32 op); + void andc_ss(UINT32 op); + void cmp_ss(UINT32 op); + void xor_ss(UINT32 op); + void rcr_s(UINT32 op); + void or_ss(UINT32 op); + void rcl_s(UINT32 op); + void shr_s(UINT32 op); + void div2_s(UINT32 op); + void and_ss(UINT32 op); + void test_ss(UINT32 op); + void add_di(UINT32 op); + void subr_di(UINT32 op); + void addr_di(UINT32 op); + void sub_di(UINT32 op); + void andc_di(UINT32 op); + void cmp_di(UINT32 op); + void xor_di(UINT32 op); + void or_di(UINT32 op); + void and_di(UINT32 op); + void test_di(UINT32 op); + + // CAU 24-bit arithmetic implementation + void adde_si(UINT32 op); + void adde_ss(UINT32 op); + void mul2e_s(UINT32 op); + void subre_ss(UINT32 op); + void addre_ss(UINT32 op); + void sube_ss(UINT32 op); + void nege_s(UINT32 op); + void andce_ss(UINT32 op); + void cmpe_ss(UINT32 op); + void xore_ss(UINT32 op); + void rcre_s(UINT32 op); + void ore_ss(UINT32 op); + void rcle_s(UINT32 op); + void shre_s(UINT32 op); + void div2e_s(UINT32 op); + void ande_ss(UINT32 op); + void teste_ss(UINT32 op); + void adde_di(UINT32 op); + void subre_di(UINT32 op); + void addre_di(UINT32 op); + void sube_di(UINT32 op); + void andce_di(UINT32 op); + void cmpe_di(UINT32 op); + void xore_di(UINT32 op); + void ore_di(UINT32 op); + void ande_di(UINT32 op); + void teste_di(UINT32 op); + + // CAU load/store implementation + void load_hi(UINT32 op); + void load_li(UINT32 op); + void load_i(UINT32 op); + void load_ei(UINT32 op); + void store_hi(UINT32 op); + void store_li(UINT32 op); + void store_i(UINT32 op); + void store_ei(UINT32 op); + void load_hr(UINT32 op); + void load_lr(UINT32 op); + void load_r(UINT32 op); + void load_er(UINT32 op); + void store_hr(UINT32 op); + void store_lr(UINT32 op); + void store_r(UINT32 op); + void store_er(UINT32 op); + void load24(UINT32 op); + + // DAU form 1 implementation + void d1_aMpp(UINT32 op); + void d1_aMpm(UINT32 op); + void d1_aMmp(UINT32 op); + void d1_aMmm(UINT32 op); + void d1_0px(UINT32 op); + void d1_0mx(UINT32 op); + void d1_1pp(UINT32 op); + void d1_1pm(UINT32 op); + void d1_1mp(UINT32 op); + void d1_1mm(UINT32 op); + void d1_aMppr(UINT32 op); + void d1_aMpmr(UINT32 op); + void d1_aMmpr(UINT32 op); + void d1_aMmmr(UINT32 op); + + // DAU form 2 implementation + void d2_aMpp(UINT32 op); + void d2_aMpm(UINT32 op); + void d2_aMmp(UINT32 op); + void d2_aMmm(UINT32 op); + void d2_aMppr(UINT32 op); + void d2_aMpmr(UINT32 op); + void d2_aMmpr(UINT32 op); + void d2_aMmmr(UINT32 op); + + // DAU form 3 implementation + void d3_aMpp(UINT32 op); + void d3_aMpm(UINT32 op); + void d3_aMmp(UINT32 op); + void d3_aMmm(UINT32 op); + void d3_aMppr(UINT32 op); + void d3_aMpmr(UINT32 op); + void d3_aMmpr(UINT32 op); + void d3_aMmmr(UINT32 op); + + // DAU form 4 implementation + void d4_pp(UINT32 op); + void d4_pm(UINT32 op); + void d4_mp(UINT32 op); + void d4_mm(UINT32 op); + void d4_ppr(UINT32 op); + void d4_pmr(UINT32 op); + void d4_mpr(UINT32 op); + void d4_mmr(UINT32 op); + + // DAU form 5 implementation + void d5_ic(UINT32 op); + void d5_oc(UINT32 op); + void d5_float(UINT32 op); + void d5_int(UINT32 op); + void d5_round(UINT32 op); + void d5_ifalt(UINT32 op); + void d5_ifaeq(UINT32 op); + void d5_ifagt(UINT32 op); + void d5_float24(UINT32 op); + void d5_int24(UINT32 op); + void d5_ieee(UINT32 op); + void d5_dsp(UINT32 op); + void d5_seed(UINT32 op); + + // dma helpers + void dma_increment(); + void dma_load(); + void dma_store(); + + // configuration + const address_space_config m_program_config; + + // internal state + UINT32 m_r[32]; + UINT32 m_pin, m_pout; + UINT32 m_ivtp; + UINT32 m_nzcflags; + UINT32 m_vflags; + + double m_a[6]; + double m_NZflags; + UINT8 m_VUflags; + + double m_abuf[4]; + UINT8 m_abufreg[4]; + UINT8 m_abufVUflags[4]; + UINT8 m_abufNZflags[4]; + int m_abufcycle[4]; + int m_abuf_index; + + INT32 m_mbufaddr[4]; + UINT32 m_mbufdata[4]; + int m_mbuf_index; + + UINT16 m_par; + UINT8 m_pare; + UINT16 m_pdr; + UINT16 m_pdr2; + UINT16 m_pir; + UINT16 m_pcr; + UINT16 m_emr; + UINT8 m_esr; + UINT16 m_pcw; + UINT8 m_piop; + + UINT32 m_ibuf; + UINT32 m_isr; + UINT32 m_obuf; + UINT32 m_osr; + + UINT32 m_iotemp; + + // internal stuff + int m_lastp; + int m_icount; + UINT8 m_lastpins; + UINT32 m_ppc; + address_space * m_program; + direct_read_data *m_direct; + + devcb_write32 m_output_pins_changed; + // tables + static void (dsp32c_device::*const s_dsp32ops[])(UINT32 op); + static const UINT32 s_regmap[4][16]; +}; + + +extern const device_type DSP32C; + + + +#endif /* __DSP32_H__ */ diff --git a/src/devices/cpu/dsp32/dsp32dis.c b/src/devices/cpu/dsp32/dsp32dis.c new file mode 100644 index 00000000000..25f43e30761 --- /dev/null +++ b/src/devices/cpu/dsp32/dsp32dis.c @@ -0,0 +1,704 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + dsp32dis.c + Disassembler for the portable AT&T/Lucent DSP32C emulator. + Written by Aaron Giles + +***************************************************************************/ + +#include "emu.h" +#include "dsp32.h" + + +/*************************************************************************** + MEMORY ACCESSORS +***************************************************************************/ + +#define ABS(x) (((x) >= 0) ? (x) : -(x)) + + +/*************************************************************************** + CODE CODE +***************************************************************************/ + +static const char *const sizesuffix[] = { "", "e" }; +static const char *const unarysign[] = { "", "-" }; +static const char *const sign[] = { "+", "-" }; +static const char *const aMvals[] = { "a0", "a1", "a2", "a3", "0.0", "1.0", "Format 4", "Reserved" }; +static const char *const memsuffix[] = { "h", "l", "", "e" }; +static const char *const functable[] = +{ + "ic", "oc", "float", "int", "round", "ifalt", "ifaeq", "ifagt", + "reserved8", "reserved9", "float24", "int24", "ieee", "dsp", "seed", "reservedf" +}; +static const char *const condtable[] = +{ + "false", "true", + "pl", "mi", + "ne", "eq", + "vc", "vs", + "cc", "cs", + "ge", "lt", + "gt", "le", + "hi", "ls", + "auc", "aus", + "age", "alt", + "ane", "aeq", + "avc", "avs", + "agt", "ale", + "!resd", "resd", + "!rese", "rese", + "!resf", "resf", + "ibe", "ibf", + "obf", "obe", + "pde", "pdf", + "pie", "pif", + "syc", "sys", + "fbc", "fbs", + "ireq1_lo", "ireq1_hi", + "ireq2_lo", "ireq2_hi", + "!?18", "?18", + "!?19", "?19", + "!?1a", "?1a", + "!?1b", "?1b", + "!?1c", "?1c", + "!?1d", "?1d", + "!?1e", "?1e", + "!?1f", "?1f" +}; +static const char *const regname[] = +{ + "0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", + "r8", "r9", "r10", "r11", "r12", "r13", "r14", "pc", + "0", "r15", "r16", "r17", "r18", "r19", "-1", "1", + "r20", "r21", "dauc", "ioc", "res1c", "r22", "pcsh", "res1f" +}; +static const char *const regnamee[] = +{ + "0", "r1e", "r2e", "r3e", "r4e", "r5e", "r6e", "r7e", + "r8e", "r9e", "r10e", "r11e", "r12e", "r13e", "r14e", "pce", + "0", "r15e", "r16e", "r17e", "r18e", "r19e", "--", "++", + "r20e", "r21e", "dauce", "ioce", "res1ce", "r22e", "pcshe", "res1fe" +}; + +static char tempbuf[10][40]; + +INLINE char *signed_16bit_unary(INT16 val) +{ + static char temp[10]; + if (val < 0) + sprintf(temp, "-$%x", -val); + else + sprintf(temp, "$%x", val); + return temp; +} + +INLINE char *signed_16bit_sep(INT16 val) +{ + static char temp[10]; + if (val < 0) + sprintf(temp, " - $%x", -val); + else + sprintf(temp, " + $%x", val); + return temp; +} + +INLINE char *signed_16bit_sep_nospace(INT16 val) +{ + static char temp[10]; + if (val < 0) + sprintf(temp, "-$%x", -val); + else + sprintf(temp, "+$%x", val); + return temp; +} + +INLINE char *unsigned_16bit_size(INT16 val, UINT8 size) +{ + static char temp[10]; + if (size) + sprintf(temp, "$%06x", (INT32)val & 0xffffff); + else + sprintf(temp, "$%04x", val & 0xffff); + return temp; +} + +static UINT8 lastp; +static const char *dasm_XYZ(UINT8 bits, char *buffer) +{ + UINT8 p = bits >> 3; + UINT8 i = bits & 7; + + if (p) + { + if (p == 15) p = lastp; /* P=15 means Z inherits from Y, Y inherits from X */ + lastp = p; + switch (i) + { + case 0: sprintf(buffer, "*r%d", p); break; + case 1: + case 2: + case 3: + case 4: + case 5: sprintf(buffer, "*r%d++r%d", p, i + 14); break; + case 6: sprintf(buffer, "*r%d--", p); break; + case 7: sprintf(buffer, "*r%d++", p); break; + } + } + else + { + switch (i) + { + case 0: + case 1: + case 2: + case 3: sprintf(buffer, "a%d", i); break; + case 4: sprintf(buffer, "ibuf"); break; + case 5: sprintf(buffer, "obuf"); break; + case 6: sprintf(buffer, "pdr"); break; + case 7: buffer[0] = 0; break; + } + } + return buffer; +} + + +static const char *dasm_PI(UINT16 bits, char *buffer) +{ + UINT8 p = bits >> 5; + UINT8 i = bits & 0x1f; + + if (p) + { + switch (i) + { + case 0: + case 16: sprintf(buffer, "*%s", regname[p]); break; + case 22: sprintf(buffer, "*%s--", regname[p]); break; + case 23: sprintf(buffer, "*%s++", regname[p]); break; + default: sprintf(buffer, "*%s++%s", regname[p], regname[i]); break; + } + } + else + { + switch (i) + { + case 4: sprintf(buffer, "ibuf"); break; + case 5: sprintf(buffer, "obuf"); break; + case 6: sprintf(buffer, "pdr"); break; + case 14: sprintf(buffer, "piop"); break; + case 20: sprintf(buffer, "pdr2"); break; + case 22: sprintf(buffer, "pir"); break; + case 30: sprintf(buffer, "pcw"); break; + default: sprintf(buffer, "????"); break; + } + } + return buffer; +} + + +static unsigned dasm_dsp32(char *buffer, unsigned pc, UINT32 op) +{ + UINT32 flags = 0; + + switch (op >> 25) + { + /* DA format 1 */ + case 0x10: case 0x11: case 0x12: case 0x13: + case 0x14: case 0x15: case 0x16: case 0x17: + case 0x18: case 0x19: case 0x1a: case 0x1b: + { + const char *X = dasm_XYZ((op >> 14) & 0x7f, tempbuf[0]); + const char *Y = dasm_XYZ((op >> 7) & 0x7f, tempbuf[1]); + const char *Z = dasm_XYZ((op >> 0) & 0x7f, tempbuf[2]); + const char *aM = aMvals[(op >> 26) & 7]; + UINT8 aN = (op >> 21) & 3; + if ((op & 0x7f) == 7) + { + if (aM[0] == '0') + sprintf(buffer, "a%d = %s%s", aN, unarysign[(op >> 24) & 1], Y); + else if (aM[0] == '1') + sprintf(buffer, "a%d = %s%s %s %s", aN, unarysign[(op >> 24) & 1], Y, sign[(op >> 23) & 1], X); + else + sprintf(buffer, "a%d = %s%s %s %s * %s", aN, unarysign[(op >> 24) & 1], Y, sign[(op >> 23) & 1], aM, X); + } + else + { + if (aM[0] == '0') + sprintf(buffer, "%s = a%d = %s%s", Z, aN, unarysign[(op >> 24) & 1], Y); + else if (aM[0] == '1') + sprintf(buffer, "%s = a%d = %s%s %s %s", Z, aN, unarysign[(op >> 24) & 1], Y, sign[(op >> 23) & 1], X); + else + sprintf(buffer, "%s = a%d = %s%s %s %s * %s", Z, aN, unarysign[(op >> 24) & 1], Y, sign[(op >> 23) & 1], aM, X); + } + break; + } + + /* DA format 2 */ + case 0x20: case 0x21: case 0x22: case 0x23: + case 0x24: case 0x25: case 0x26: case 0x27: + case 0x28: case 0x29: case 0x2a: case 0x2b: + { + const char *X = dasm_XYZ((op >> 14) & 0x7f, tempbuf[0]); + const char *Y = dasm_XYZ((op >> 7) & 0x7f, tempbuf[1]); + const char *Z = dasm_XYZ((op >> 0) & 0x7f, tempbuf[2]); + const char *aM = aMvals[(op >> 26) & 7]; + UINT8 aN = (op >> 21) & 3; + + if ((op & 0x7f) == 7) + { + if (aM[0] == '0') + sprintf(buffer, "a%d = %s%s * %s", aN, unarysign[(op >> 23) & 1], Y, X); + else + sprintf(buffer, "a%d = %s%s %s %s * %s", aN, unarysign[(op >> 24) & 1], aM, sign[(op >> 23) & 1], Y, X); + } + else + { + if (aM[0] == '0') + sprintf(buffer, "a%d = %s(%s=%s) * %s", aN, unarysign[(op >> 23) & 1], Z, Y, X); + else + sprintf(buffer, "a%d = %s%s %s (%s=%s) * %s", aN, unarysign[(op >> 24) & 1], aM, sign[(op >> 23) & 1], Z, Y, X); + } + break; + } + + /* DA format 3 */ + case 0x30: case 0x31: case 0x32: case 0x33: + case 0x34: case 0x35: case 0x36: case 0x37: + case 0x38: case 0x39: case 0x3a: case 0x3b: + { + const char *X = dasm_XYZ((op >> 14) & 0x7f, tempbuf[0]); + const char *Y = dasm_XYZ((op >> 7) & 0x7f, tempbuf[1]); + const char *Z = dasm_XYZ((op >> 0) & 0x7f, tempbuf[2]); + const char *aM = aMvals[(op >> 26) & 7]; + UINT8 aN = (op >> 21) & 3; + + if ((op & 0x7f) == 7) + { + if (aM[0] == '0') + sprintf(buffer, "a%d = %s%s * %s", aN, unarysign[(op >> 23) & 1], Y, X); + else + sprintf(buffer, "a%d = %s%s %s %s * %s", aN, unarysign[(op >> 24) & 1], aM, sign[(op >> 23) & 1], Y, X); + } + else + { + if (aM[0] == '0') + sprintf(buffer, "%s = a%d = %s%s * %s", Z, aN, unarysign[(op >> 23) & 1], Y, X); + else + sprintf(buffer, "%s = a%d = %s%s %s %s * %s", Z, aN, unarysign[(op >> 24) & 1], aM, sign[(op >> 23) & 1], Y, X); + } + break; + } + + /* DA format 4 */ + case 0x1c: case 0x1d: + { + const char *X = dasm_XYZ((op >> 14) & 0x7f, tempbuf[0]); + const char *Y = dasm_XYZ((op >> 7) & 0x7f, tempbuf[1]); + const char *Z = dasm_XYZ((op >> 0) & 0x7f, tempbuf[2]); + UINT8 aN = (op >> 21) & 3; + + if ((op & 0x7f) == 7) + sprintf(buffer, "a%d = %s%s %s %s", aN, unarysign[(op >> 24) & 1], Y, sign[(op >> 23) & 1], X); + else + sprintf(buffer, "a%d = %s(%s=%s) %s %s", aN, unarysign[(op >> 24) & 1], Z, Y, sign[(op >> 23) & 1], X); + break; + } + + /* DA format 5 */ + case 0x3c: case 0x3d: case 0x3e: case 0x3f: + if ((op & 0x7f) == 7) + sprintf(buffer, "a%d = %s(%s)", + (op >> 21) & 3, // aN + functable[(op >> 23) & 15], // G + dasm_XYZ((op >> 7) & 0x7f, tempbuf[0])); // Y + else + sprintf(buffer, "%s = a%d = %s(%s)", + dasm_XYZ((op >> 0) & 0x7f, tempbuf[2]), // Z + (op >> 21) & 3, // aN + functable[(op >> 23) & 15], // G + dasm_XYZ((op >> 7) & 0x7f, tempbuf[0])); // Y + break; + + /* CA formats 0/1 */ + case 0x00: case 0x01: case 0x02: case 0x03: + { + const char *rH = regname[(op >> 16) & 0x1f]; + UINT8 C = (op >> 21) & 0x3f; + INT16 N = (INT16)op; + + if (op == 0) + sprintf(buffer, "nop"); + else if (C == 1 && N == 0 && ((op >> 16) & 0x1f) == 0x1e) + sprintf(buffer, "ireturn"); + else if (C == 1) + { + if (((op >> 16) & 0x1f) == 15) + sprintf(buffer, "goto %s%s [%x]", rH, signed_16bit_sep_nospace(N), (pc + 8 + N) & 0xffffff); + else if (N && rH[0] != '0') + sprintf(buffer, "goto %s%s", rH, signed_16bit_sep_nospace(N)); + else if (N) + sprintf(buffer, "goto $%x", ((INT32)N & 0xffffff)); + else + { + if (((op >> 16) & 0x1f) == 20) + flags = DASMFLAG_STEP_OUT; + sprintf(buffer, "goto %s", rH); + } + } + else + { + if (((op >> 16) & 0x1f) == 15) + sprintf(buffer, "if (%s) goto %s%s [%x]", condtable[C], rH, signed_16bit_sep_nospace(N), (pc + 8 + N) & 0xffffff); + else if (N && rH[0] != '0') + sprintf(buffer, "if (%s) goto %s%s", condtable[C], rH, signed_16bit_sep_nospace(N)); + else if (N) + sprintf(buffer, "if (%s) goto $%x", condtable[C], ((INT32)N & 0xffffff)); + else + { + if (((op >> 16) & 0x1f) == 20) + flags = DASMFLAG_STEP_OUT; + sprintf(buffer, "if (%s) goto %s", condtable[C], rH); + } + } + break; + } + + /* CA format 3a */ + case 0x06: case 0x07: + { + const char *rH = regname[(op >> 16) & 0x1f]; + const char *rM = regname[(op >> 21) & 0x1f]; + INT16 N = (INT16)op; + + if (((op >> 16) & 0x1f) == 15) + { + sprintf(buffer, "if (%s-- >= 0) goto %s%s [%x]", rM, rH, signed_16bit_sep_nospace(N), (pc + 8 + N) & 0xffffff); + if (((pc + 8 + N) & 0xffffff) < pc) + flags = DASMFLAG_STEP_OVER; + } + else if (N && rH[0] != '0') + sprintf(buffer, "if (%s-- >= 0) goto %s%s", rM, rH, signed_16bit_sep_nospace(N)); + else if (N) + { + sprintf(buffer, "if (%s-- >= 0) goto $%x", rM, ((INT32)N & 0xffffff)); + if (((INT32)N & 0xffffff) < pc) + flags = DASMFLAG_STEP_OVER; + } + else + { + sprintf(buffer, "if (%s-- >= 0) goto %s", rM, rH); + if (((op >> 16) & 0x1f) == 20) + flags = DASMFLAG_STEP_OUT; + } + break; + } + + /* CA format 3b/3c */ + case 0x46: + if (((op >> 21) & 0x1f) == 0) + sprintf(buffer, "do %d,%d", (op >> 16) & 0x1f, op & 0x7ff); + else if (((op >> 21) & 0x1f) == 1) + sprintf(buffer, "do %d,%s", (op >> 16) & 0x1f, regname[op & 0x1f]); + break; + + /* CA format 4 */ + case 0x08: case 0x09: + { + const char *rH = regname[(op >> 16) & 0x1f]; + const char *rM = regname[(op >> 21) & 0x1f]; + INT16 N = (INT16)op; + + if (((op >> 16) & 0x1f) == 15) + sprintf(buffer, "call %s%s (%s) [%x]", rH, signed_16bit_sep_nospace(N), rM, (pc + 8 + N) & 0xffffff); + else if (N && rH[0] != '0') + sprintf(buffer, "call %s%s (%s)", rH, signed_16bit_sep_nospace(N), rM); + else if (N) + sprintf(buffer, "call $%x (%s)", ((INT32)N & 0xffffff), rM); + else + sprintf(buffer, "call %s (%s)", rH, rM); + flags = DASMFLAG_STEP_OVER | DASMFLAG_STEP_OVER_EXTRA(1); + break; + } + + /* CA format 5a/5b */ + case 0x0a: case 0x0b: + case 0x4a: case 0x4b: + { + const char *rD = regname[(op >> 21) & 0x1f]; + const char *rH = regname[(op >> 16) & 0x1f]; + const char *s = sizesuffix[(op >> 31) & 1]; + INT16 N = (INT16)op; + if (N == 0) + sprintf(buffer, "%s%s = %s%s", rD, s, rH, s); + else if (rH[0] == '0') + sprintf(buffer, "%s%s = %s", rD, s, signed_16bit_unary(N)); + else + sprintf(buffer, "%s%s = %s%s%s", rD, s, rH, s, signed_16bit_sep((INT16)op)); + break; + } + + /* CA format 6a/6b */ + case 0x0c: case 0x4c: + { + const char *rD = regname[(op >> 16) & 0x1f]; + const char *rS1 = regname[(op >> 5) & 0x1f]; + const char *rS2 = regname[(op >> 0) & 0x1f]; + const char *s = sizesuffix[(op >> 31) & 1]; + UINT8 threeop = (op >> 11) & 1; + char condbuf[40] = { 0 }; + + if ((op >> 10) & 1) + sprintf(condbuf, "if (%s) ", condtable[(op >> 12) & 15]); + + switch ((op >> 21) & 15) + { + /* add */ + case 0: + if (threeop) + { + if (rS1[0] == '0' && rS2[0] == '0') + sprintf(buffer, "%s%s%s = 0", condbuf, rD, s); + else if (rS1[0] == '0') + sprintf(buffer, "%s%s%s = %s%s", condbuf, rD, s, rS2, s); + else if (rS2[0] == '0') + sprintf(buffer, "%s%s%s = %s%s", condbuf, rD, s, rS1, s); + else + sprintf(buffer, "%s%s%s = %s%s + %s%s", condbuf, rD, s, rS2, s, rS1, s); + } + else + { + if (rS1[0] == '0') + sprintf(buffer, "%s%s%s = %s%s", condbuf, rD, s, rD, s); + else + sprintf(buffer, "%s%s%s = %s%s + %s%s", condbuf, rD, s, rD, s, rS1, s); + } + break; + + case 1: + sprintf(buffer, "%s%s%s = %s%s * 2", condbuf, rD, s, rS1, s); + break; + + case 2: + if (threeop) + sprintf(buffer, "%s%s%s = %s%s - %s%s", condbuf, rD, s, rS1, s, rS2, s); + else + sprintf(buffer, "%s%s%s = %s%s - %s%s", condbuf, rD, s, rS1, s, rD, s); + break; + + case 3: + if (threeop) + sprintf(buffer, "%s%s%s = %s%s # %s%s", condbuf, rD, s, rS2, s, rS1, s); + else + sprintf(buffer, "%s%s%s = %s%s # %s%s", condbuf, rD, s, rD, s, rS1, s); + break; + + case 4: + if (threeop) + sprintf(buffer, "%s%s%s = %s%s - %s%s", condbuf, rD, s, rS2, s, rS1, s); + else + sprintf(buffer, "%s%s%s = %s%s - %s%s", condbuf, rD, s, rD, s, rS1, s); + break; + + case 5: + sprintf(buffer, "%s%s%s = -%s%s", condbuf, rD, s, rS1, s); + break; + + case 6: + if (threeop) + sprintf(buffer, "%s%s%s = %s%s &~ %s%s", condbuf, rD, s, rS2, s, rS1, s); + else + sprintf(buffer, "%s%s%s = %s%s &~ %s%s", condbuf, rD, s, rD, s, rS1, s); + break; + + case 7: +// if (threeop) +// sprintf(buffer, "%s%s%s - %s%s", condbuf, rS2, s, rS1, s); +// else + sprintf(buffer, "%s%s%s - %s%s", condbuf, rD, s, rS1, s); + break; + + case 8: + if (threeop) + sprintf(buffer, "%s%s%s = %s%s ^ %s%s", condbuf, rD, s, rS2, s, rS1, s); + else + sprintf(buffer, "%s%s%s = %s%s ^ %s%s", condbuf, rD, s, rD, s, rS1, s); + break; + + case 9: + sprintf(buffer, "%s%s%s = %s%s >>> 1", condbuf, rD, s, rS1, s); + break; + + case 10: + if (threeop) + sprintf(buffer, "%s%s%s = %s%s | %s%s", condbuf, rD, s, rS2, s, rS1, s); + else + sprintf(buffer, "%s%s%s = %s%s | %s%s", condbuf, rD, s, rD, s, rS1, s); + break; + + case 11: + sprintf(buffer, "%s%s%s = %s%s <<< 1", condbuf, rD, s, rS1, s); + break; + + case 12: + sprintf(buffer, "%s%s%s = %s%s >> 1", condbuf, rD, s, rS1, s); + break; + + case 13: + sprintf(buffer, "%s%s%s = %s%s / 2", condbuf, rD, s, rS1, s); + break; + + case 14: + if (threeop) + sprintf(buffer, "%s%s%s = %s%s & %s%s", condbuf, rD, s, rS2, s, rS1, s); + else + sprintf(buffer, "%s%s%s = %s%s & %s%s", condbuf, rD, s, rD, s, rS1, s); + break; + + case 15: +// if (threeop) +// sprintf(buffer, "%s%s%s & %s%s", condbuf, rS1, s, rS2, s); +// else + sprintf(buffer, "%s%s%s & %s%s", condbuf, rD, s, rS1, s); + break; + } + break; + } + + /* CA format 6c/6d */ + case 0x0d: case 0x4d: + { + const char *rD = regname[(op >> 16) & 0x1f]; + const char *s = sizesuffix[(op >> 31) & 1]; + INT16 N = (INT16)op; + + switch ((op >> 21) & 15) + { + case 0: + case 1: + case 5: + case 9: + case 11: + case 12: + case 13: + sprintf(buffer, "Unexpected: %08X", op); + break; + + case 2: + sprintf(buffer, "%s%s = %s - %s%s", rD, s, signed_16bit_unary(N), rD, s); + break; + + case 3: + sprintf(buffer, "%s%s = %s%s # %s", rD, s, rD, s, signed_16bit_unary(N)); + break; + + case 4: + sprintf(buffer, "%s%s = %s%s - %s", rD, s, rD, s, signed_16bit_unary(N)); + break; + + case 6: + sprintf(buffer, "%s%s = %s%s &~ %s", rD, s, rD, s, unsigned_16bit_size(N, (op >> 31) & 1)); + break; + + case 7: + sprintf(buffer, "%s%s - %s", rD, s, signed_16bit_unary(N)); + break; + + case 8: + sprintf(buffer, "%s%s = %s%s ^ %s", rD, s, rD, s, unsigned_16bit_size(N, (op >> 31) & 1)); + break; + + case 10: + sprintf(buffer, "%s%s = %s%s | %s", rD, s, rD, s, unsigned_16bit_size(N, (op >> 31) & 1)); + break; + + case 14: + sprintf(buffer, "%s%s = %s%s & %s", rD, s, rD, s, unsigned_16bit_size(N, (op >> 31) & 1)); + break; + + case 15: + sprintf(buffer, "%s%s & %s", rD, s, unsigned_16bit_size(N, (op >> 31) & 1)); + break; + } + break; + } + + /* CA format 7a */ + case 0x0e: + if ((op >> 24) & 1) + sprintf(buffer, "*%08X = %s%s", (INT16)op, regname[(op >> 16) & 0x1f], memsuffix[(op >> 22) & 3]); + else + sprintf(buffer, "%s%s = *%08X", regname[(op >> 16) & 0x1f], memsuffix[(op >> 22) & 3], (INT16)op); + break; + + /* CA format 7b */ + case 0x0f: + if ((op >> 24) & 1) + sprintf(buffer, "%s = %s%s", dasm_PI(op & 0x3ff, tempbuf[0]), regname[(op >> 16) & 0x1f], memsuffix[(op >> 22) & 3]); + else + sprintf(buffer, "%s%s = %s", regname[(op >> 16) & 0x1f], memsuffix[(op >> 22) & 3], dasm_PI(op & 0x3ff, tempbuf[0])); + break; + + /* CA format 8a */ + case 0x50: case 0x51: case 0x52: case 0x53: + case 0x54: case 0x55: case 0x56: case 0x57: + case 0x58: case 0x59: case 0x5a: case 0x5b: + case 0x5c: case 0x5d: case 0x5e: case 0x5f: + { + INT32 N = (op & 0xffff) | ((INT32)((op & 0x1fe00000) << 3) >> 8); + const char *rH = regname[(op >> 16) & 0x1f]; + + if (((op >> 16) & 0x1f) == 15) + sprintf(buffer, "goto %s%s [%x]", rH, signed_16bit_sep_nospace(N), (pc + 8 + N) & 0xffffff); + else if (N && rH[0] != '0') + sprintf(buffer, "goto %s%s", rH, signed_16bit_sep_nospace(N)); + else if (N) + sprintf(buffer, "goto $%x", ((INT32)N & 0xffffff)); + else + { + if (((op >> 16) & 0x1f) == 20) + flags = DASMFLAG_STEP_OUT; + sprintf(buffer, "goto %s", rH); + } + break; + } + + /* CA format 8b */ + case 0x60: case 0x61: case 0x62: case 0x63: + case 0x64: case 0x65: case 0x66: case 0x67: + case 0x68: case 0x69: case 0x6a: case 0x6b: + case 0x6c: case 0x6d: case 0x6e: case 0x6f: + { + INT32 immed = (op & 0xffff) | ((INT32)((op & 0x1fe00000) << 3) >> 8); + sprintf(buffer, "%s = $%x", regnamee[(op >> 16) & 0x1f], immed & 0xffffff); + break; + } + + /* CA format 8c */ + case 0x70: case 0x71: case 0x72: case 0x73: + case 0x74: case 0x75: case 0x76: case 0x77: + case 0x78: case 0x79: case 0x7a: case 0x7b: + case 0x7c: case 0x7d: case 0x7e: case 0x7f: + { + INT32 N = (op & 0xffff) | ((INT32)((op & 0x1fe00000) << 3) >> 8); + const char *rM = regname[(op >> 16) & 0x1f]; + sprintf(buffer, "call $%x (%s)", N & 0xffffff, rM); + flags = DASMFLAG_STEP_OVER | DASMFLAG_STEP_OVER_EXTRA(1); + break; + } + } + + return 4 | flags | DASMFLAG_SUPPORTED; +} + + +/*************************************************************************** + DISASSEMBLY HOOK +***************************************************************************/ + +CPU_DISASSEMBLE( dsp32c ) +{ + return dasm_dsp32(buffer, pc, oprom[0] | (oprom[1] << 8) | (oprom[2] << 16) | (oprom[3] << 24)); +} diff --git a/src/devices/cpu/dsp32/dsp32ops.inc b/src/devices/cpu/dsp32/dsp32ops.inc new file mode 100644 index 00000000000..09844f6ee4f --- /dev/null +++ b/src/devices/cpu/dsp32/dsp32ops.inc @@ -0,0 +1,2846 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + dsp32ops.inc + Core implementation for the portable DSP32 emulator. + +****************************************************************************/ + + + +//************************************************************************** +// COMPILE-TIME OPTIONS +//************************************************************************** + +// these defined latencies are a pain to implement, but are necessary +#define EMULATE_MEMORY_LATENCY (1) +#define EMULATE_MULTIPLIER_LATENCY (1) +#define EMULATE_AFLAGS_LATENCY (1) + +// these optimizations should have some effect, but they don't really, so +// leave them off +#define IGNORE_DAU_UV_FLAGS (0) +#define ASSUME_WRITEABLE (0) +#define ASSUME_UNCONDITIONAL_CAU (0) + + + +//************************************************************************** +// MACROS +//************************************************************************** + +#define SET_V_16(a,b,r) m_vflags = (((a) ^ (b) ^ (r) ^ ((r) >> 1)) << 8) +#define SET_NZC_16(r) m_nzcflags = ((r) << 8) +#define SET_NZCV_16(a,b,r) SET_NZC_16(r); SET_V_16(a,b,r) +#define SET_NZ00_16(r) m_nzcflags = (((r) << 8) & 0xffffff); m_vflags = 0 + +#define SET_V_24(a,b,r) m_vflags = ((a) ^ (b) ^ (r) ^ ((r) >> 1)) +#define SET_NZC_24(r) m_nzcflags = (r) +#define SET_NZCV_24(a,b,r) SET_NZC_24(r); SET_V_24(a,b,r) +#define SET_NZ00_24(r) m_nzcflags = ((r) & 0xffffff); m_vflags = 0 + +#define TRUNCATE24(a) ((a) & 0xffffff) +#define EXTEND16_TO_24(a) TRUNCATE24((INT32)(INT16)(a)) +#define REG16(a) ((UINT16)m_r[a]) +#define REG24(a) (m_r[a]) + +#define WRITEABLE_REGS (0x6f3efffe) +#if ASSUME_WRITEABLE +#define IS_WRITEABLE(r) (1) +#else +#define IS_WRITEABLE(r) (WRITEABLE_REGS & (1 << (r))) +#endif + +#if ASSUME_UNCONDITIONAL_CAU +#define CONDITION_IS_TRUE() (1) +#else +#define CONDITION_IS_TRUE() (!(op & 0x400) || (condition((op >> 12) & 15))) +#endif + +#if EMULATE_MEMORY_LATENCY +#define WWORD_DEFERRED(a,v) do { int bufidx = m_mbuf_index & 3; m_mbufaddr[bufidx] = -(a); m_mbufdata[bufidx] = (v); } while (0) +#define WLONG_DEFERRED(a,v) do { int bufidx = m_mbuf_index & 3; m_mbufaddr[bufidx] = (a); m_mbufdata[bufidx] = (v); } while (0) +#define PROCESS_DEFERRED_MEMORY() \ + if (m_mbufaddr[++m_mbuf_index & 3] != 1) \ + { \ + int bufidx = m_mbuf_index & 3; \ + if (m_mbufaddr[bufidx] >= 0) \ + WLONG(m_mbufaddr[bufidx], m_mbufdata[bufidx]); \ + else \ + WWORD(-m_mbufaddr[bufidx], m_mbufdata[bufidx]); \ + m_mbufaddr[bufidx] = 1; \ + } +#else +#define WWORD_DEFERRED(a,v) WWORD(a,v) +#define WLONG_DEFERRED(a,v) WLONG(a,v) +#define PROCESS_DEFERRED_MEMORY() +#endif + +#if EMULATE_MULTIPLIER_LATENCY +#define DEFERRED_MULTIPLIER(x) dau_get_amult(x) +#else +#define DEFERRED_MULTIPLIER(x) m_a[x] +#endif + +#if EMULATE_AFLAGS_LATENCY +#define DEFERRED_NZFLAGS() dau_get_anzflags() +#define DEFERRED_VUFLAGS() dau_get_avuflags() +#else +#define DEFERRED_NZFLAGS() m_NZflags +#define DEFERRED_VUFLAGS() m_VUflags +#endif + + + +//************************************************************************** +// TYPEDEFS +//************************************************************************** + +union int_double +{ + double d; + UINT32 i[2]; +}; + + + +//************************************************************************** +// IMPLEMENTATION +//************************************************************************** + +void dsp32c_device::illegal(UINT32 op) +{ +} + + +void dsp32c_device::unimplemented(UINT32 op) +{ + fatalerror("Unimplemented op @ %06X: %08X (dis=%02X, tbl=%03X)\n", PC - 4, op, op >> 25, op >> 21); +} + + +inline void dsp32c_device::execute_one() +{ + UINT32 op; + + PROCESS_DEFERRED_MEMORY(); + debugger_instruction_hook(this, PC); + op = ROPCODE(PC); + m_icount -= 4; // 4 clocks per cycle + PC += 4; + if (op) + (this->*s_dsp32ops[op >> 21])(op); +} + + + +//************************************************************************** +// CAU HELPERS +//************************************************************************** + +UINT32 dsp32c_device::cau_read_pi_special(UINT8 i) +{ + switch (i) + { + case 4: return m_ibuf; + case 5: return m_obuf; + case 6: update_pcr(m_pcr & ~PCR_PDFs); update_pins(); return m_pdr; + case 14: return m_piop; + case 20: return m_pdr2; + case 22: update_pcr(m_pcr & ~PCR_PIFs); update_pins(); return m_pir; + case 30: return m_pcw; + default: fprintf(stderr, "Unimplemented CAU PI read = %X\n", i); + } + return 0; +} + + +void dsp32c_device::cau_write_pi_special(UINT8 i, UINT32 val) +{ + switch (i) + { + case 4: m_ibuf = val; break; + case 5: m_obuf = val; break; + case 6: m_pdr = val; update_pcr(m_pcr | PCR_PDFs); update_pins(); break; + case 14: m_piop = val; break; + case 20: m_pdr2 = val; break; + case 22: m_pir = val; update_pcr(m_pcr | PCR_PIFs); update_pins(); break; + case 30: m_pcw = val; break; + default: fprintf(stderr, "Unimplemented CAU PI write = %X\n", i); + } +} + + +inline UINT8 dsp32c_device::cau_read_pi_1byte(int pi) +{ + int p = (pi >> 5) & 0x1f; + int i = (pi >> 0) & 0x1f; + if (p) + { + UINT32 result = RBYTE(m_r[p]); + m_r[p] = TRUNCATE24(m_r[p] + m_r[i]); + return result; + } + else + return cau_read_pi_special(i); +} + + +inline UINT16 dsp32c_device::cau_read_pi_2byte(int pi) +{ + int p = (pi >> 5) & 0x1f; + int i = (pi >> 0) & 0x1f; + if (p) + { + UINT32 result = RWORD(m_r[p]); + if (i < 22 || i > 23) + m_r[p] = TRUNCATE24(m_r[p] + m_r[i]); + else + m_r[p] = TRUNCATE24(m_r[p] + m_r[i] * 2); + return result; + } + else + return cau_read_pi_special(i); +} + + +inline UINT32 dsp32c_device::cau_read_pi_4byte(int pi) +{ + int p = (pi >> 5) & 0x1f; + int i = (pi >> 0) & 0x1f; + if (p) + { + UINT32 result = RLONG(m_r[p]); + if (i < 22 || i > 23) + m_r[p] = TRUNCATE24(m_r[p] + m_r[i]); + else + m_r[p] = TRUNCATE24(m_r[p] + m_r[i] * 4); + return result; + } + else + return cau_read_pi_special(i); +} + + +inline void dsp32c_device::cau_write_pi_1byte(int pi, UINT8 val) +{ + int p = (pi >> 5) & 0x1f; + int i = (pi >> 0) & 0x1f; + if (p) + { + WBYTE(m_r[p], val); + m_r[p] = TRUNCATE24(m_r[p] + m_r[i]); + } + else + cau_write_pi_special(i, val); +} + + +inline void dsp32c_device::cau_write_pi_2byte(int pi, UINT16 val) +{ + int p = (pi >> 5) & 0x1f; + int i = (pi >> 0) & 0x1f; + if (p) + { + WWORD(m_r[p], val); + if (i < 22 || i > 23) + m_r[p] = TRUNCATE24(m_r[p] + m_r[i]); + else + m_r[p] = TRUNCATE24(m_r[p] + m_r[i] * 2); + } + else + cau_write_pi_special(i, val); +} + + +inline void dsp32c_device::cau_write_pi_4byte(int pi, UINT32 val) +{ + int p = (pi >> 5) & 0x1f; + int i = (pi >> 0) & 0x1f; + if (p) + { + WLONG(m_r[p], (INT32)(val << 8) >> 8); + if (i < 22 || i > 23) + m_r[p] = TRUNCATE24(m_r[p] + m_r[i]); + else + m_r[p] = TRUNCATE24(m_r[p] + m_r[i] * 4); + } + else + cau_write_pi_special(i, val); +} + + + +//************************************************************************** +// DAU HELPERS +//************************************************************************** + +inline double dsp32c_device::dau_get_amult(int aidx) +{ + int bufidx = (m_abuf_index - 1) & 3; + double val = m_a[aidx]; + while (m_icount >= m_abufcycle[bufidx] - 2 * 4) + { + if (m_abufreg[bufidx] == aidx) + val = m_abuf[bufidx]; + bufidx = (bufidx - 1) & 3; + } + return val; +} + + +inline double dsp32c_device::dau_get_anzflags() +{ + int bufidx = (m_abuf_index - 1) & 3; + double nzflags = m_NZflags; + while (m_icount >= m_abufcycle[bufidx] - 3 * 4) + { + nzflags = m_abufNZflags[bufidx]; + bufidx = (bufidx - 1) & 3; + } + return nzflags; +} + + +inline UINT8 dsp32c_device::dau_get_avuflags() +{ +#if (!IGNORE_DAU_UV_FLAGS) + int bufidx = (m_abuf_index - 1) & 3; + UINT8 vuflags = m_VUflags; + while (m_icount >= m_abufcycle[bufidx] - 3 * 4) + { + vuflags = m_abufVUflags[bufidx]; + bufidx = (bufidx - 1) & 3; + } + return vuflags; +#else + return 0; +#endif +} + + +inline void dsp32c_device::remember_last_dau(int aidx) +{ +#if (EMULATE_MULTIPLIER_LATENCY || EMULATE_AFLAGS_LATENCY) + int bufidx = m_abuf_index++ & 3; + m_abuf[bufidx] = m_a[aidx]; + m_abufreg[bufidx] = aidx; + m_abufNZflags[bufidx] = m_NZflags; +#if (!IGNORE_DAU_UV_FLAGS) + m_abufVUflags[bufidx] = m_VUflags; +#endif + m_abufcycle[bufidx] = m_icount; +#endif +} + + +inline void dsp32c_device::dau_set_val_noflags(int aidx, double res) +{ + remember_last_dau(aidx); + m_a[aidx] = res; +} + + +inline void dsp32c_device::dau_set_val_flags(int aidx, double res) +{ + remember_last_dau(aidx); +#if (!IGNORE_DAU_UV_FLAGS) +{ + double absres = (res < 0) ? -res : res; + m_VUflags = 0; + if (absres < 5.87747e-39) + { + if (absres != 0) + m_VUflags = UFLAGBIT; + res = 0.0; + } + else if (absres > 3.40282e38) + { + m_VUflags = VFLAGBIT; +// debugger_break(Machine); +// fprintf(stderr, "Result = %g\n", absres); + res = (res < 0) ? -3.40282e38 : 3.40282e38; + } +} +#endif + m_NZflags = res; + m_a[aidx] = res; +} + + +inline double dsp32c_device::dsp_to_double(UINT32 val) +{ + int_double id; + + if (val == 0) + return 0; + else if ((INT32)val > 0) + { + int exponent = ((val & 0xff) - 128 + 1023) << 20; + id.i[BYTE_XOR_BE(0)] = exponent + (val >> 11); + id.i[BYTE_XOR_BE(1)] = (val << 21) & 0xe0000000; + } + else + { + int exponent = ((val & 0xff) - 128 + 1023) << 20; + val = -(val & 0xffffff00); + id.i[BYTE_XOR_BE(0)] = 0x80000000 + exponent + ((val >> 11) & 0x001fffff); + id.i[BYTE_XOR_BE(1)] = (val << 21) & 0xe0000000; + } + return id.d; +} + + +inline UINT32 dsp32c_device::double_to_dsp(double val) +{ + int mantissa, exponent; + int_double id; + id.d = val; + mantissa = ((id.i[BYTE_XOR_BE(0)] & 0x000fffff) << 11) | ((id.i[BYTE_XOR_BE(1)] & 0xe0000000) >> 21); + exponent = ((id.i[BYTE_XOR_BE(0)] & 0x7ff00000) >> 20) - 1023 + 128; + if (exponent < 0) + return 0x00000000; + else if (exponent > 255) + { +// debugger_break(Machine); +// fprintf(stderr, "Exponent = %d\n", exponent); + return ((INT32)id.i[BYTE_XOR_BE(0)] >= 0) ? 0x7fffffff : 0x800000ff; + } + else if ((INT32)id.i[BYTE_XOR_BE(0)] >= 0) + return exponent | mantissa; + else + { + mantissa = -mantissa; + if (mantissa == 0) { mantissa = 0x80000000; exponent--; } + return 0x80000000 | exponent | (mantissa & 0xffffff00); + } +} + + +double dsp32c_device::dau_read_pi_special(int i) +{ + fatalerror("Unimplemented dau_read_pi_special(%d)\n", i); + return 0; +} + + +void dsp32c_device::dau_write_pi_special(int i, double val) +{ + fatalerror("Unimplemented dau_write_pi_special(%d)\n", i); +} + + +inline double dsp32c_device::dau_read_pi_double_1st(int pi, int multiplier) +{ + int p = (pi >> 3) & 15; + int i = (pi >> 0) & 7; + + m_lastp = p; + if (p) + { + UINT32 result = RLONG(m_r[p]); + if (i < 6) + m_r[p] = TRUNCATE24(m_r[p] + m_r[i+16]); + else + m_r[p] = TRUNCATE24(m_r[p] + m_r[i+16] * 4); + return dsp_to_double(result); + } + else if (i < 4) + return multiplier ? DEFERRED_MULTIPLIER(i) : m_a[i]; + else + return dau_read_pi_special(i); +} + + +inline double dsp32c_device::dau_read_pi_double_2nd(int pi, int multiplier, double xval) +{ + int p = (pi >> 3) & 15; + int i = (pi >> 0) & 7; + + if (p == 15) p = m_lastp; // P=15 means Z inherits from Y, Y inherits from X + m_lastp = p; + if (p) + { + UINT32 result; + result = RLONG(m_r[p]); + if (i < 6) + m_r[p] = TRUNCATE24(m_r[p] + m_r[i+16]); + else + m_r[p] = TRUNCATE24(m_r[p] + m_r[i+16] * 4); + return dsp_to_double(result); + } + else if (i < 4) + return multiplier ? DEFERRED_MULTIPLIER(i) : m_a[i]; + else + return dau_read_pi_special(i); +} + + +inline UINT32 dsp32c_device::dau_read_pi_4bytes(int pi) +{ + int p = (pi >> 3) & 15; + int i = (pi >> 0) & 7; + + m_lastp = p; + if (p) + { + UINT32 result = RLONG(m_r[p]); + if (i < 6) + m_r[p] = TRUNCATE24(m_r[p] + m_r[i+16]); + else + m_r[p] = TRUNCATE24(m_r[p] + m_r[i+16] * 4); + return result; + } + else if (i < 4) + return double_to_dsp(m_a[i]); + else + return dau_read_pi_special(i); +} + + +inline UINT16 dsp32c_device::dau_read_pi_2bytes(int pi) +{ + int p = (pi >> 3) & 15; + int i = (pi >> 0) & 7; + + m_lastp = p; + if (p) + { + UINT32 result = RWORD(m_r[p]); + if (i < 6) + m_r[p] = TRUNCATE24(m_r[p] + m_r[i+16]); + else + m_r[p] = TRUNCATE24(m_r[p] + m_r[i+16] * 2); + return result; + } + else if (i < 4) + return double_to_dsp(m_a[i]); + else + return dau_read_pi_special(i); +} + + +inline void dsp32c_device::dau_write_pi_double(int pi, double val) +{ + int p = (pi >> 3) & 15; + int i = (pi >> 0) & 7; + + if (p == 15) p = m_lastp; // P=15 means Z inherits from Y, Y inherits from X + if (p) + { + WLONG_DEFERRED(m_r[p], double_to_dsp(val)); + if (i < 6) + m_r[p] = TRUNCATE24(m_r[p] + m_r[i+16]); + else + m_r[p] = TRUNCATE24(m_r[p] + m_r[i+16] * 4); + } + else if (i < 4) + dau_set_val_noflags(i, val); + else + dau_write_pi_special(i, val); +} + + +inline void dsp32c_device::dau_write_pi_4bytes(int pi, UINT32 val) +{ + int p = (pi >> 3) & 15; + int i = (pi >> 0) & 7; + + if (p == 15) p = m_lastp; // P=15 means Z inherits from Y, Y inherits from X + if (p) + { + m_lastp = p; + WLONG_DEFERRED(m_r[p], val); + if (i < 6) + m_r[p] = TRUNCATE24(m_r[p] + m_r[i+16]); + else + m_r[p] = TRUNCATE24(m_r[p] + m_r[i+16] * 4); + } + else if (i < 4) + dau_set_val_noflags(i, dsp_to_double(val)); + else + dau_write_pi_special(i, val); +} + + +inline void dsp32c_device::dau_write_pi_2bytes(int pi, UINT16 val) +{ + int p = (pi >> 3) & 15; + int i = (pi >> 0) & 7; + + if (p == 15) p = m_lastp; // P=15 means Z inherits from Y, Y inherits from X + if (p) + { + m_lastp = p; + WWORD_DEFERRED(m_r[p], val); + if (i < 6) + m_r[p] = TRUNCATE24(m_r[p] + m_r[i+16]); + else + m_r[p] = TRUNCATE24(m_r[p] + m_r[i+16] * 2); + } + else if (i < 4) + dau_set_val_noflags(i, dsp_to_double(val << 16)); + else + dau_write_pi_special(i, val); +} + + + +//************************************************************************** +// COMMON CONDITION ROUTINE +//************************************************************************** + +#if (!ASSUME_UNCONDITIONAL_CAU) +int dsp32c_device::condition(int cond) +{ + switch (cond) + { + case 0: + return 0; + case 1: + return 1; + case 2: + return !nFLAG; + case 3: + return nFLAG; + case 4: + return !zFLAG; + case 5: + return zFLAG; + case 6: + return !vFLAG; + case 7: + return vFLAG; + case 8: + return !cFLAG; + case 9: + return cFLAG; + case 10: + return !(nFLAG ^ cFLAG); + case 11: + return (nFLAG ^ cFLAG); + case 12: + return !(zFLAG | (nFLAG ^ vFLAG)); + case 13: + return (zFLAG | (nFLAG ^ vFLAG)); + case 14: + return !(cFLAG | zFLAG); + case 15: + return (cFLAG | zFLAG); + + case 16: + return !(DEFERRED_VUFLAGS() & UFLAGBIT); + case 17: + return (DEFERRED_VUFLAGS() & UFLAGBIT); + case 18: + return !(DEFERRED_NZFLAGS() < 0); + case 19: + return (DEFERRED_NZFLAGS() < 0); + case 20: + return !(DEFERRED_NZFLAGS() == 0); + case 21: + return (DEFERRED_NZFLAGS() == 0); + case 22: + return !(DEFERRED_VUFLAGS() & VFLAGBIT); + case 23: + return (DEFERRED_VUFLAGS() & VFLAGBIT); + case 24: + return !(DEFERRED_NZFLAGS() <= 0); + case 25: + return (DEFERRED_NZFLAGS() <= 0); + + case 32: // !ibf + case 33: // ibf + case 34: // !obe + case 35: // obe + case 36: // !pdf + case 37: // pdf + case 38: // !pif + case 39: // pif + case 40: // !sy + case 41: // sy + case 42: // !fb + case 43: // fb + case 44: // !ireq1 + case 45: // ireq1 + case 46: // !ireq2 + case 47: // ireq2 + default: + fatalerror("Unimplemented condition: %X\n", cond); + } +} +#endif + + + +//************************************************************************** +// CAU BRANCH INSTRUCTION IMPLEMENTATION +//************************************************************************** + +void dsp32c_device::nop(UINT32 op) +{ + if (op == 0) + return; + execute_one(); + PC = TRUNCATE24(REG24((op >> 16) & 0x1f) + (INT16)op); +} + + +void dsp32c_device::goto_t(UINT32 op) +{ + execute_one(); + PC = TRUNCATE24(REG24((op >> 16) & 0x1f) + (INT16)op); +} + + +void dsp32c_device::goto_pl(UINT32 op) +{ + if (!nFLAG) + { + execute_one(); + PC = TRUNCATE24(REG24((op >> 16) & 0x1f) + (INT16)op); + } +} + + +void dsp32c_device::goto_mi(UINT32 op) +{ + if (nFLAG) + { + execute_one(); + PC = TRUNCATE24(REG24((op >> 16) & 0x1f) + (INT16)op); + } +} + + +void dsp32c_device::goto_ne(UINT32 op) +{ + if (!zFLAG) + { + execute_one(); + PC = TRUNCATE24(REG24((op >> 16) & 0x1f) + (INT16)op); + } +} + + +void dsp32c_device::goto_eq(UINT32 op) +{ + if (zFLAG) + { + execute_one(); + PC = TRUNCATE24(REG24((op >> 16) & 0x1f) + (INT16)op); + } +} + + +void dsp32c_device::goto_vc(UINT32 op) +{ + if (!vFLAG) + { + execute_one(); + PC = TRUNCATE24(REG24((op >> 16) & 0x1f) + (INT16)op); + } +} + + +void dsp32c_device::goto_vs(UINT32 op) +{ + if (vFLAG) + { + execute_one(); + PC = TRUNCATE24(REG24((op >> 16) & 0x1f) + (INT16)op); + } +} + + +void dsp32c_device::goto_cc(UINT32 op) +{ + if (!cFLAG) + { + execute_one(); + PC = TRUNCATE24(REG24((op >> 16) & 0x1f) + (INT16)op); + } +} + + +void dsp32c_device::goto_cs(UINT32 op) +{ + if (cFLAG) + { + execute_one(); + PC = TRUNCATE24(REG24((op >> 16) & 0x1f) + (INT16)op); + } +} + + +void dsp32c_device::goto_ge(UINT32 op) +{ + if (!(nFLAG ^ vFLAG)) + { + execute_one(); + PC = TRUNCATE24(REG24((op >> 16) & 0x1f) + (INT16)op); + } +} + + +void dsp32c_device::goto_lt(UINT32 op) +{ + if (nFLAG ^ vFLAG) + { + execute_one(); + PC = TRUNCATE24(REG24((op >> 16) & 0x1f) + (INT16)op); + } +} + + +void dsp32c_device::goto_gt(UINT32 op) +{ + if (!(zFLAG | (nFLAG ^ vFLAG))) + { + execute_one(); + PC = TRUNCATE24(REG24((op >> 16) & 0x1f) + (INT16)op); + } +} + + +void dsp32c_device::goto_le(UINT32 op) +{ + if (zFLAG | (nFLAG ^ vFLAG)) + { + execute_one(); + PC = TRUNCATE24(REG24((op >> 16) & 0x1f) + (INT16)op); + } +} + + +void dsp32c_device::goto_hi(UINT32 op) +{ + if (!cFLAG && !zFLAG) + { + execute_one(); + PC = TRUNCATE24(REG24((op >> 16) & 0x1f) + (INT16)op); + } +} + + +void dsp32c_device::goto_ls(UINT32 op) +{ + if (cFLAG || zFLAG) + { + execute_one(); + PC = TRUNCATE24(REG24((op >> 16) & 0x1f) + (INT16)op); + } +} + + +void dsp32c_device::goto_auc(UINT32 op) +{ + if (!(DEFERRED_VUFLAGS() & UFLAGBIT)) + { + execute_one(); + PC = TRUNCATE24(REG24((op >> 16) & 0x1f) + (INT16)op); + } +} + + +void dsp32c_device::goto_aus(UINT32 op) +{ + if (DEFERRED_VUFLAGS() & UFLAGBIT) + { + execute_one(); + PC = TRUNCATE24(REG24((op >> 16) & 0x1f) + (INT16)op); + } +} + + +void dsp32c_device::goto_age(UINT32 op) +{ + if (DEFERRED_NZFLAGS() >= 0) + { + execute_one(); + PC = TRUNCATE24(REG24((op >> 16) & 0x1f) + (INT16)op); + } +} + + +void dsp32c_device::goto_alt(UINT32 op) +{ + if (DEFERRED_NZFLAGS() < 0) + { + execute_one(); + PC = TRUNCATE24(REG24((op >> 16) & 0x1f) + (INT16)op); + } +} + + +void dsp32c_device::goto_ane(UINT32 op) +{ + if (DEFERRED_NZFLAGS() != 0) + { + execute_one(); + PC = TRUNCATE24(REG24((op >> 16) & 0x1f) + (INT16)op); + } +} + + +void dsp32c_device::goto_aeq(UINT32 op) +{ + if (DEFERRED_NZFLAGS() == 0) + { + execute_one(); + PC = TRUNCATE24(REG24((op >> 16) & 0x1f) + (INT16)op); + } +} + + +void dsp32c_device::goto_avc(UINT32 op) +{ + if (!(DEFERRED_VUFLAGS() & VFLAGBIT)) + { + execute_one(); + PC = TRUNCATE24(REG24((op >> 16) & 0x1f) + (INT16)op); + } +} + + +void dsp32c_device::goto_avs(UINT32 op) +{ + if (DEFERRED_VUFLAGS() & VFLAGBIT) + { + execute_one(); + PC = TRUNCATE24(REG24((op >> 16) & 0x1f) + (INT16)op); + } +} + + +void dsp32c_device::goto_agt(UINT32 op) +{ + if (DEFERRED_NZFLAGS() > 0) + { + execute_one(); + PC = TRUNCATE24(REG24((op >> 16) & 0x1f) + (INT16)op); + } +} + + +void dsp32c_device::goto_ale(UINT32 op) +{ + if (DEFERRED_NZFLAGS() <= 0) + { + execute_one(); + PC = TRUNCATE24(REG24((op >> 16) & 0x1f) + (INT16)op); + } +} + + +void dsp32c_device::goto_ibe(UINT32 op) +{ + unimplemented(op); +} + + +void dsp32c_device::goto_ibf(UINT32 op) +{ + unimplemented(op); +} + + +void dsp32c_device::goto_obf(UINT32 op) +{ + unimplemented(op); +} + + +void dsp32c_device::goto_obe(UINT32 op) +{ + unimplemented(op); +} + + +void dsp32c_device::goto_pde(UINT32 op) +{ + if (!(m_pcr & PCR_PDFs)) + { + execute_one(); + PC = TRUNCATE24(REG24((op >> 16) & 0x1f) + (INT16)op); + } +} + + +void dsp32c_device::goto_pdf(UINT32 op) +{ + if (m_pcr & PCR_PDFs) + { + execute_one(); + PC = TRUNCATE24(REG24((op >> 16) & 0x1f) + (INT16)op); + } +} + + +void dsp32c_device::goto_pie(UINT32 op) +{ + if (!(m_pcr & PCR_PIFs)) + { + execute_one(); + PC = TRUNCATE24(REG24((op >> 16) & 0x1f) + (INT16)op); + } +} + + +void dsp32c_device::goto_pif(UINT32 op) +{ + if (m_pcr & PCR_PIFs) + { + execute_one(); + PC = TRUNCATE24(REG24((op >> 16) & 0x1f) + (INT16)op); + } +} + + +void dsp32c_device::goto_syc(UINT32 op) +{ + unimplemented(op); +} + + +void dsp32c_device::goto_sys(UINT32 op) +{ + unimplemented(op); +} + + +void dsp32c_device::goto_fbc(UINT32 op) +{ + unimplemented(op); +} + + +void dsp32c_device::goto_fbs(UINT32 op) +{ + unimplemented(op); +} + + +void dsp32c_device::goto_irq1lo(UINT32 op) +{ + unimplemented(op); +} + + +void dsp32c_device::goto_irq1hi(UINT32 op) +{ + unimplemented(op); +} + + +void dsp32c_device::goto_irq2lo(UINT32 op) +{ + unimplemented(op); +} + + +void dsp32c_device::goto_irq2hi(UINT32 op) +{ + unimplemented(op); +} + + +void dsp32c_device::dec_goto(UINT32 op) +{ + int hr = (op >> 21) & 0x1f; + int old = (INT16)m_r[hr]; + m_r[hr] = EXTEND16_TO_24(m_r[hr] - 1); + if (old >= 0) + { + execute_one(); + PC = TRUNCATE24(REG24((op >> 16) & 0x1f) + (INT16)op); + } +} + + +void dsp32c_device::call(UINT32 op) +{ + int mr = (op >> 21) & 0x1f; + if (IS_WRITEABLE(mr)) + m_r[mr] = PC + 4; + execute_one(); + PC = TRUNCATE24(REG24((op >> 16) & 0x1f) + (INT16)op); +} + + +void dsp32c_device::goto24(UINT32 op) +{ + execute_one(); + PC = TRUNCATE24(REG24((op >> 16) & 0x1f) + (op & 0xffff) + ((op >> 5) & 0xff0000)); +} + + +void dsp32c_device::call24(UINT32 op) +{ + int mr = (op >> 16) & 0x1f; + if (IS_WRITEABLE(mr)) + m_r[mr] = PC + 4; + execute_one(); + PC = (op & 0xffff) + ((op >> 5) & 0xff0000); +} + + +void dsp32c_device::do_i(UINT32 op) +{ + unimplemented(op); +} + + +void dsp32c_device::do_r(UINT32 op) +{ + unimplemented(op); +} + + + +//************************************************************************** +// CAU 16-BIT ARITHMETIC IMPLEMENTATION +//************************************************************************** + +void dsp32c_device::add_si(UINT32 op) +{ + int dr = (op >> 21) & 0x1f; + int hrval = REG16((op >> 16) & 0x1f); + int res = hrval + (UINT16)op; + if (IS_WRITEABLE(dr)) + m_r[dr] = EXTEND16_TO_24(res); + SET_NZCV_16(hrval, op, res); +} + + +void dsp32c_device::add_ss(UINT32 op) +{ + if (CONDITION_IS_TRUE()) + { + int dr = (op >> 16) & 0x1f; + int s1rval = REG16((op >> 5) & 0x1f); + int s2rval = (op & 0x800) ? REG16((op >> 0) & 0x1f) : REG16(dr); + int res = s2rval + s1rval; + if (IS_WRITEABLE(dr)) + m_r[dr] = EXTEND16_TO_24(res); + SET_NZCV_16(s1rval, s2rval, res); + } +} + + +void dsp32c_device::mul2_s(UINT32 op) +{ + if (CONDITION_IS_TRUE()) + { + int dr = (op >> 16) & 0x1f; + int s1rval = REG16((op >> 5) & 0x1f); + int res = s1rval * 2; + if (IS_WRITEABLE(dr)) + m_r[dr] = EXTEND16_TO_24(res); + SET_NZCV_16(s1rval, 0, res); + } +} + + +void dsp32c_device::subr_ss(UINT32 op) +{ + if (CONDITION_IS_TRUE()) + { + int dr = (op >> 16) & 0x1f; + int s1rval = REG16((op >> 5) & 0x1f); + int s2rval = (op & 0x800) ? REG16((op >> 0) & 0x1f) : REG16(dr); + int res = s1rval - s2rval; + if (IS_WRITEABLE(dr)) + m_r[dr] = EXTEND16_TO_24(res); + SET_NZCV_16(s1rval, s2rval, res); + } +} + + +void dsp32c_device::addr_ss(UINT32 op) +{ + unimplemented(op); +} + + +void dsp32c_device::sub_ss(UINT32 op) +{ + if (CONDITION_IS_TRUE()) + { + int dr = (op >> 16) & 0x1f; + int s1rval = REG16((op >> 5) & 0x1f); + int s2rval = (op & 0x800) ? REG16((op >> 0) & 0x1f) : REG16(dr); + int res = s2rval - s1rval; + if (IS_WRITEABLE(dr)) + m_r[dr] = EXTEND16_TO_24(res); + SET_NZCV_16(s1rval, s2rval, res); + } +} + + +void dsp32c_device::neg_s(UINT32 op) +{ + if (CONDITION_IS_TRUE()) + { + int dr = (op >> 16) & 0x1f; + int s1rval = REG16((op >> 5) & 0x1f); + int res = -s1rval; + if (IS_WRITEABLE(dr)) + m_r[dr] = EXTEND16_TO_24(res); + SET_NZCV_16(s1rval, 0, res); + } +} + + +void dsp32c_device::andc_ss(UINT32 op) +{ + if (CONDITION_IS_TRUE()) + { + int dr = (op >> 16) & 0x1f; + int s1rval = REG16((op >> 5) & 0x1f); + int s2rval = (op & 0x800) ? REG16((op >> 0) & 0x1f) : REG16(dr); + int res = s2rval & ~s1rval; + if (IS_WRITEABLE(dr)) + m_r[dr] = EXTEND16_TO_24(res); + SET_NZ00_16(res); + } +} + + +void dsp32c_device::cmp_ss(UINT32 op) +{ + if (CONDITION_IS_TRUE()) + { + int drval = REG16((op >> 16) & 0x1f); + int s1rval = REG16((op >> 5) & 0x1f); + int res = drval - s1rval; + SET_NZCV_16(drval, s1rval, res); + } +} + + +void dsp32c_device::xor_ss(UINT32 op) +{ + if (CONDITION_IS_TRUE()) + { + int dr = (op >> 16) & 0x1f; + int s1rval = REG16((op >> 5) & 0x1f); + int s2rval = (op & 0x800) ? REG16((op >> 0) & 0x1f) : REG16(dr); + int res = s2rval ^ s1rval; + if (IS_WRITEABLE(dr)) + m_r[dr] = EXTEND16_TO_24(res); + SET_NZ00_16(res); + } +} + + +void dsp32c_device::rcr_s(UINT32 op) +{ + if (CONDITION_IS_TRUE()) + { + int dr = (op >> 16) & 0x1f; + int s1rval = REG16((op >> 5) & 0x1f); + int res = ((m_nzcflags >> 9) & 0x8000) | (s1rval >> 1); + if (IS_WRITEABLE(dr)) + m_r[dr] = EXTEND16_TO_24(res); + m_nzcflags = ((res & 0xffff) << 8) | ((s1rval & 1) << 24); + m_vflags = 0; + } +} + + +void dsp32c_device::or_ss(UINT32 op) +{ + if (CONDITION_IS_TRUE()) + { + int dr = (op >> 16) & 0x1f; + int s1rval = REG16((op >> 5) & 0x1f); + int s2rval = (op & 0x800) ? REG16((op >> 0) & 0x1f) : REG16(dr); + int res = s2rval | s1rval; + if (IS_WRITEABLE(dr)) + m_r[dr] = EXTEND16_TO_24(res); + SET_NZ00_16(res); + } +} + + +void dsp32c_device::rcl_s(UINT32 op) +{ + if (CONDITION_IS_TRUE()) + { + int dr = (op >> 16) & 0x1f; + int s1rval = REG16((op >> 5) & 0x1f); + int res = ((m_nzcflags >> 24) & 0x0001) | (s1rval << 1); + if (IS_WRITEABLE(dr)) + m_r[dr] = EXTEND16_TO_24(res); + m_nzcflags = ((res & 0xffff) << 8) | ((s1rval & 0x8000) << 9); + m_vflags = 0; + } +} + + +void dsp32c_device::shr_s(UINT32 op) +{ + if (CONDITION_IS_TRUE()) + { + int dr = (op >> 16) & 0x1f; + int s1rval = REG16((op >> 5) & 0x1f); + int res = s1rval >> 1; + if (IS_WRITEABLE(dr)) + m_r[dr] = EXTEND16_TO_24(res); + m_nzcflags = ((res & 0xffff) << 8) | ((s1rval & 1) << 24); + m_vflags = 0; + } +} + + +void dsp32c_device::div2_s(UINT32 op) +{ + if (CONDITION_IS_TRUE()) + { + int dr = (op >> 16) & 0x1f; + int s1rval = REG16((op >> 5) & 0x1f); + int res = (s1rval & 0x8000) | (s1rval >> 1); + if (IS_WRITEABLE(dr)) + m_r[dr] = EXTEND16_TO_24(res); + m_nzcflags = ((res & 0xffff) << 8) | ((s1rval & 1) << 24); + m_vflags = 0; + } +} + + +void dsp32c_device::and_ss(UINT32 op) +{ + if (CONDITION_IS_TRUE()) + { + int dr = (op >> 16) & 0x1f; + int s1rval = REG16((op >> 5) & 0x1f); + int s2rval = (op & 0x800) ? REG16((op >> 0) & 0x1f) : REG16(dr); + int res = s2rval & s1rval; + if (IS_WRITEABLE(dr)) + m_r[dr] = EXTEND16_TO_24(res); + SET_NZ00_16(res); + } +} + + +void dsp32c_device::test_ss(UINT32 op) +{ + if (CONDITION_IS_TRUE()) + { + int drval = REG16((op >> 16) & 0x1f); + int s1rval = REG16((op >> 5) & 0x1f); + int res = drval & s1rval; + SET_NZ00_16(res); + } +} + + +void dsp32c_device::add_di(UINT32 op) +{ + int dr = (op >> 16) & 0x1f; + int drval = REG16(dr); + int res = drval + (UINT16)op; + if (IS_WRITEABLE(dr)) + m_r[dr] = EXTEND16_TO_24(res); + SET_NZCV_16(drval, op, res); +} + + +void dsp32c_device::subr_di(UINT32 op) +{ + int dr = (op >> 16) & 0x1f; + int drval = REG16(dr); + int res = (UINT16)op - drval; + if (IS_WRITEABLE(dr)) + m_r[dr] = EXTEND16_TO_24(res); + SET_NZCV_16(drval, op, res); +} + + +void dsp32c_device::addr_di(UINT32 op) +{ + unimplemented(op); +} + + +void dsp32c_device::sub_di(UINT32 op) +{ + int dr = (op >> 16) & 0x1f; + int drval = REG16(dr); + int res = drval - (UINT16)op; + if (IS_WRITEABLE(dr)) + m_r[dr] = EXTEND16_TO_24(res); + SET_NZCV_16(drval, op, res); +} + + +void dsp32c_device::andc_di(UINT32 op) +{ + int dr = (op >> 16) & 0x1f; + int drval = REG16(dr); + int res = drval & ~(UINT16)op; + if (IS_WRITEABLE(dr)) + m_r[dr] = EXTEND16_TO_24(res); + SET_NZ00_16(res); +} + + +void dsp32c_device::cmp_di(UINT32 op) +{ + int drval = REG16((op >> 16) & 0x1f); + int res = drval - (UINT16)op; + SET_NZCV_16(drval, op, res); +} + + +void dsp32c_device::xor_di(UINT32 op) +{ + int dr = (op >> 16) & 0x1f; + int drval = REG16(dr); + int res = drval ^ (UINT16)op; + if (IS_WRITEABLE(dr)) + m_r[dr] = EXTEND16_TO_24(res); + SET_NZ00_16(res); +} + + +void dsp32c_device::or_di(UINT32 op) +{ + int dr = (op >> 16) & 0x1f; + int drval = REG16(dr); + int res = drval | (UINT16)op; + if (IS_WRITEABLE(dr)) + m_r[dr] = EXTEND16_TO_24(res); + SET_NZ00_16(res); +} + + +void dsp32c_device::and_di(UINT32 op) +{ + int dr = (op >> 16) & 0x1f; + int drval = REG16(dr); + int res = drval & (UINT16)op; + if (IS_WRITEABLE(dr)) + m_r[dr] = EXTEND16_TO_24(res); + SET_NZ00_16(res); +} + + +void dsp32c_device::test_di(UINT32 op) +{ + int drval = REG16((op >> 16) & 0x1f); + int res = drval & (UINT16)op; + SET_NZ00_16(res); +} + + + +//************************************************************************** +// CAU 24-BIT ARITHMETIC IMPLEMENTATION +//************************************************************************** + +void dsp32c_device::adde_si(UINT32 op) +{ + int dr = (op >> 21) & 0x1f; + int hrval = REG24((op >> 16) & 0x1f); + int res = hrval + EXTEND16_TO_24(op); + if (IS_WRITEABLE(dr)) + m_r[dr] = TRUNCATE24(res); + SET_NZCV_24(hrval, op << 8, res); +} + + +void dsp32c_device::adde_ss(UINT32 op) +{ + if (CONDITION_IS_TRUE()) + { + int dr = (op >> 16) & 0x1f; + int s1rval = REG24((op >> 5) & 0x1f); + int s2rval = (op & 0x800) ? REG24((op >> 0) & 0x1f) : REG24(dr); + int res = s2rval + s1rval; + if (IS_WRITEABLE(dr)) + m_r[dr] = TRUNCATE24(res); + SET_NZCV_24(s1rval, s2rval, res); + } +} + + +void dsp32c_device::mul2e_s(UINT32 op) +{ + if (CONDITION_IS_TRUE()) + { + int dr = (op >> 16) & 0x1f; + int s1rval = REG24((op >> 5) & 0x1f); + int res = s1rval * 2; + if (IS_WRITEABLE(dr)) + m_r[dr] = TRUNCATE24(res); + SET_NZCV_24(s1rval, 0, res); + } +} + + +void dsp32c_device::subre_ss(UINT32 op) +{ + if (CONDITION_IS_TRUE()) + { + int dr = (op >> 16) & 0x1f; + int s1rval = REG24((op >> 5) & 0x1f); + int s2rval = (op & 0x800) ? REG24((op >> 0) & 0x1f) : REG24(dr); + int res = s1rval - s2rval; + if (IS_WRITEABLE(dr)) + m_r[dr] = TRUNCATE24(res); + SET_NZCV_24(s1rval, s2rval, res); + } +} + + +void dsp32c_device::addre_ss(UINT32 op) +{ + unimplemented(op); +} + + +void dsp32c_device::sube_ss(UINT32 op) +{ + if (CONDITION_IS_TRUE()) + { + int dr = (op >> 16) & 0x1f; + int s1rval = REG24((op >> 5) & 0x1f); + int s2rval = (op & 0x800) ? REG24((op >> 0) & 0x1f) : REG24(dr); + int res = s2rval - s1rval; + if (IS_WRITEABLE(dr)) + m_r[dr] = TRUNCATE24(res); + SET_NZCV_24(s1rval, s2rval, res); + } +} + + +void dsp32c_device::nege_s(UINT32 op) +{ + if (CONDITION_IS_TRUE()) + { + int dr = (op >> 16) & 0x1f; + int s1rval = REG24((op >> 5) & 0x1f); + int res = -s1rval; + if (IS_WRITEABLE(dr)) + m_r[dr] = TRUNCATE24(res); + SET_NZCV_24(s1rval, 0, res); + } +} + + +void dsp32c_device::andce_ss(UINT32 op) +{ + if (CONDITION_IS_TRUE()) + { + int dr = (op >> 16) & 0x1f; + int s1rval = REG24((op >> 5) & 0x1f); + int s2rval = (op & 0x800) ? REG24((op >> 0) & 0x1f) : REG24(dr); + int res = s2rval & ~s1rval; + if (IS_WRITEABLE(dr)) + m_r[dr] = res; + SET_NZ00_24(res); + } +} + + +void dsp32c_device::cmpe_ss(UINT32 op) +{ + if (CONDITION_IS_TRUE()) + { + int drval = REG24((op >> 16) & 0x1f); + int s1rval = REG24((op >> 5) & 0x1f); + int res = drval - s1rval; + SET_NZCV_24(drval, s1rval, res); + } +} + + +void dsp32c_device::xore_ss(UINT32 op) +{ + if (CONDITION_IS_TRUE()) + { + int dr = (op >> 16) & 0x1f; + int s1rval = REG24((op >> 5) & 0x1f); + int s2rval = (op & 0x800) ? REG24((op >> 0) & 0x1f) : REG24(dr); + int res = s2rval ^ s1rval; + if (IS_WRITEABLE(dr)) + m_r[dr] = res; + SET_NZ00_24(res); + } +} + + +void dsp32c_device::rcre_s(UINT32 op) +{ + if (CONDITION_IS_TRUE()) + { + int dr = (op >> 16) & 0x1f; + int s1rval = REG24((op >> 5) & 0x1f); + int res = ((m_nzcflags >> 1) & 0x800000) | (s1rval >> 1); + if (IS_WRITEABLE(dr)) + m_r[dr] = TRUNCATE24(res); + m_nzcflags = res | ((s1rval & 1) << 24); + m_vflags = 0; + } +} + + +void dsp32c_device::ore_ss(UINT32 op) +{ + if (CONDITION_IS_TRUE()) + { + int dr = (op >> 16) & 0x1f; + int s1rval = REG24((op >> 5) & 0x1f); + int s2rval = (op & 0x800) ? REG24((op >> 0) & 0x1f) : REG24(dr); + int res = s2rval | s1rval; + if (IS_WRITEABLE(dr)) + m_r[dr] = res; + SET_NZ00_24(res); + } +} + + +void dsp32c_device::rcle_s(UINT32 op) +{ + if (CONDITION_IS_TRUE()) + { + int dr = (op >> 16) & 0x1f; + int s1rval = REG24((op >> 5) & 0x1f); + int res = ((m_nzcflags >> 24) & 0x000001) | (s1rval << 1); + if (IS_WRITEABLE(dr)) + m_r[dr] = TRUNCATE24(res); + m_nzcflags = res | ((s1rval & 0x800000) << 1); + m_vflags = 0; + } +} + + +void dsp32c_device::shre_s(UINT32 op) +{ + if (CONDITION_IS_TRUE()) + { + int dr = (op >> 16) & 0x1f; + int s1rval = REG24((op >> 5) & 0x1f); + int res = s1rval >> 1; + if (IS_WRITEABLE(dr)) + m_r[dr] = res; + m_nzcflags = res | ((s1rval & 1) << 24); + m_vflags = 0; + } +} + + +void dsp32c_device::div2e_s(UINT32 op) +{ + if (CONDITION_IS_TRUE()) + { + int dr = (op >> 16) & 0x1f; + int s1rval = REG24((op >> 5) & 0x1f); + int res = (s1rval & 0x800000) | (s1rval >> 1); + if (IS_WRITEABLE(dr)) + m_r[dr] = TRUNCATE24(res); + m_nzcflags = res | ((s1rval & 1) << 24); + m_vflags = 0; + } +} + + +void dsp32c_device::ande_ss(UINT32 op) +{ + if (CONDITION_IS_TRUE()) + { + int dr = (op >> 16) & 0x1f; + int s1rval = REG24((op >> 5) & 0x1f); + int s2rval = (op & 0x800) ? REG24((op >> 0) & 0x1f) : REG24(dr); + int res = s2rval & s1rval; + if (IS_WRITEABLE(dr)) + m_r[dr] = res; + SET_NZ00_24(res); + } +} + + +void dsp32c_device::teste_ss(UINT32 op) +{ + if (CONDITION_IS_TRUE()) + { + int drval = REG24((op >> 16) & 0x1f); + int s1rval = REG24((op >> 5) & 0x1f); + int res = drval & s1rval; + SET_NZ00_24(res); + } +} + + +void dsp32c_device::adde_di(UINT32 op) +{ + int dr = (op >> 16) & 0x1f; + int drval = REG24(dr); + int res = drval + EXTEND16_TO_24(op); + if (IS_WRITEABLE(dr)) + m_r[dr] = TRUNCATE24(res); + SET_NZCV_24(drval, op << 8, res); +} + + +void dsp32c_device::subre_di(UINT32 op) +{ + int dr = (op >> 16) & 0x1f; + int drval = REG24(dr); + int res = EXTEND16_TO_24(op) - drval; + if (IS_WRITEABLE(dr)) + m_r[dr] = TRUNCATE24(res); + SET_NZCV_24(drval, op << 8, res); +} + + +void dsp32c_device::addre_di(UINT32 op) +{ + unimplemented(op); +} + + +void dsp32c_device::sube_di(UINT32 op) +{ + int dr = (op >> 16) & 0x1f; + int drval = REG24(dr); + int res = drval - EXTEND16_TO_24(op); + if (IS_WRITEABLE(dr)) + m_r[dr] = TRUNCATE24(res); + SET_NZCV_24(drval, op << 8, res); +} + + +void dsp32c_device::andce_di(UINT32 op) +{ + int dr = (op >> 16) & 0x1f; + int drval = REG24(dr); + int res = drval & ~EXTEND16_TO_24(op); + if (IS_WRITEABLE(dr)) + m_r[dr] = res; + SET_NZ00_24(res); +} + + +void dsp32c_device::cmpe_di(UINT32 op) +{ + int drval = REG24((op >> 16) & 0x1f); + int res = drval - EXTEND16_TO_24(op); + SET_NZCV_24(drval, op << 8, res); +} + + +void dsp32c_device::xore_di(UINT32 op) +{ + int dr = (op >> 16) & 0x1f; + int drval = REG24(dr); + int res = drval ^ EXTEND16_TO_24(op); + if (IS_WRITEABLE(dr)) + m_r[dr] = res; + SET_NZ00_24(res); +} + + +void dsp32c_device::ore_di(UINT32 op) +{ + int dr = (op >> 16) & 0x1f; + int drval = REG24(dr); + int res = drval | EXTEND16_TO_24(op); + if (IS_WRITEABLE(dr)) + m_r[dr] = res; + SET_NZ00_24(res); +} + + +void dsp32c_device::ande_di(UINT32 op) +{ + int dr = (op >> 16) & 0x1f; + int drval = REG24(dr); + int res = drval & EXTEND16_TO_24(op); + if (IS_WRITEABLE(dr)) + m_r[dr] = res; + SET_NZ00_24(res); +} + + +void dsp32c_device::teste_di(UINT32 op) +{ + int drval = REG24((op >> 16) & 0x1f); + int res = drval & EXTEND16_TO_24(op); + SET_NZ00_24(res); +} + + + +//************************************************************************** +// CAU LOAD/STORE IMPLEMENTATION +//************************************************************************** + +void dsp32c_device::load_hi(UINT32 op) +{ + int dr = (op >> 16) & 0x1f; + UINT32 res = RBYTE(EXTEND16_TO_24(op)); + if (IS_WRITEABLE(dr)) + m_r[dr] = EXTEND16_TO_24(res); + m_nzcflags = res << 8; + m_vflags = 0; +} + + +void dsp32c_device::load_li(UINT32 op) +{ + int dr = (op >> 16) & 0x1f; + UINT32 res = RBYTE(EXTEND16_TO_24(op)); + if (IS_WRITEABLE(dr)) + m_r[dr] = res; + m_nzcflags = res << 8; + m_vflags = 0; +} + + +void dsp32c_device::load_i(UINT32 op) +{ + UINT32 res = RWORD(EXTEND16_TO_24(op)); + int dr = (op >> 16) & 0x1f; + if (IS_WRITEABLE(dr)) + m_r[dr] = EXTEND16_TO_24(res); + m_nzcflags = res << 8; + m_vflags = 0; +} + + +void dsp32c_device::load_ei(UINT32 op) +{ + UINT32 res = TRUNCATE24(RLONG(EXTEND16_TO_24(op))); + int dr = (op >> 16) & 0x1f; + if (IS_WRITEABLE(dr)) + m_r[dr] = res; + m_nzcflags = res; + m_vflags = 0; +} + + +void dsp32c_device::store_hi(UINT32 op) +{ + WBYTE(EXTEND16_TO_24(op), m_r[(op >> 16) & 0x1f] >> 8); +} + + +void dsp32c_device::store_li(UINT32 op) +{ + WBYTE(EXTEND16_TO_24(op), m_r[(op >> 16) & 0x1f]); +} + + +void dsp32c_device::store_i(UINT32 op) +{ + WWORD(EXTEND16_TO_24(op), REG16((op >> 16) & 0x1f)); +} + + +void dsp32c_device::store_ei(UINT32 op) +{ + WLONG(EXTEND16_TO_24(op), (INT32)(REG24((op >> 16) & 0x1f) << 8) >> 8); +} + + +void dsp32c_device::load_hr(UINT32 op) +{ + if (!(op & 0x400)) + { + int dr = (op >> 16) & 0x1f; + UINT32 res = cau_read_pi_1byte(op) << 8; + if (IS_WRITEABLE(dr)) + m_r[dr] = EXTEND16_TO_24(res); + m_nzcflags = res << 8; + m_vflags = 0; + } + else + unimplemented(op); +} + + +void dsp32c_device::load_lr(UINT32 op) +{ + if (!(op & 0x400)) + { + int dr = (op >> 16) & 0x1f; + UINT32 res = cau_read_pi_1byte(op); + if (IS_WRITEABLE(dr)) + m_r[dr] = res; + m_nzcflags = res << 8; + m_vflags = 0; + } + else + unimplemented(op); +} + + +void dsp32c_device::load_r(UINT32 op) +{ + if (!(op & 0x400)) + { + UINT32 res = cau_read_pi_2byte(op); + int dr = (op >> 16) & 0x1f; + if (IS_WRITEABLE(dr)) + m_r[dr] = EXTEND16_TO_24(res); + m_nzcflags = res << 8; + m_vflags = 0; + } + else + unimplemented(op); +} + + +void dsp32c_device::load_er(UINT32 op) +{ + if (!(op & 0x400)) + { + UINT32 res = TRUNCATE24(cau_read_pi_4byte(op)); + int dr = (op >> 16) & 0x1f; + if (IS_WRITEABLE(dr)) + m_r[dr] = res; + m_nzcflags = res; + m_vflags = 0; + } + else + unimplemented(op); +} + + +void dsp32c_device::store_hr(UINT32 op) +{ + if (!(op & 0x400)) + cau_write_pi_1byte(op, m_r[(op >> 16) & 0x1f] >> 8); + else + unimplemented(op); +} + + +void dsp32c_device::store_lr(UINT32 op) +{ + if (!(op & 0x400)) + cau_write_pi_1byte(op, m_r[(op >> 16) & 0x1f]); + else + unimplemented(op); +} + + +void dsp32c_device::store_r(UINT32 op) +{ + if (!(op & 0x400)) + cau_write_pi_2byte(op, REG16((op >> 16) & 0x1f)); + else + unimplemented(op); +} + + +void dsp32c_device::store_er(UINT32 op) +{ + if (!(op & 0x400)) + cau_write_pi_4byte(op, REG24((op >> 16) & 0x1f)); + else + unimplemented(op); +} + + +void dsp32c_device::load24(UINT32 op) +{ + int dr = (op >> 16) & 0x1f; + UINT32 res = (op & 0xffff) + ((op >> 5) & 0xff0000); + if (IS_WRITEABLE(dr)) + m_r[dr] = res; +} + + + +//************************************************************************** +// DAU FORM 1 IMPLEMENTATION +//************************************************************************** + +void dsp32c_device::d1_aMpp(UINT32 op) +{ + double xval = dau_read_pi_double_1st(op >> 14, 1); + double yval = dau_read_pi_double_2nd(op >> 7, 0, xval); + double res = yval + DEFERRED_MULTIPLIER((op >> 26) & 7) * xval; + int zpi = (op >> 0) & 0x7f; + if (zpi != 7) + dau_write_pi_double(zpi, res); + dau_set_val_flags((op >> 21) & 3, res); +} + + +void dsp32c_device::d1_aMpm(UINT32 op) +{ + double xval = dau_read_pi_double_1st(op >> 14, 1); + double yval = dau_read_pi_double_2nd(op >> 7, 0, xval); + double res = yval - DEFERRED_MULTIPLIER((op >> 26) & 7) * xval; + int zpi = (op >> 0) & 0x7f; + if (zpi != 7) + dau_write_pi_double(zpi, res); + dau_set_val_flags((op >> 21) & 3, res); +} + + +void dsp32c_device::d1_aMmp(UINT32 op) +{ + double xval = dau_read_pi_double_1st(op >> 14, 1); + double yval = dau_read_pi_double_2nd(op >> 7, 0, xval); + double res = -yval + DEFERRED_MULTIPLIER((op >> 26) & 7) * xval; + int zpi = (op >> 0) & 0x7f; + if (zpi != 7) + dau_write_pi_double(zpi, res); + dau_set_val_flags((op >> 21) & 3, res); +} + + +void dsp32c_device::d1_aMmm(UINT32 op) +{ + double xval = dau_read_pi_double_1st(op >> 14, 1); + double yval = dau_read_pi_double_2nd(op >> 7, 0, xval); + double res = -yval - DEFERRED_MULTIPLIER((op >> 26) & 7) * xval; + int zpi = (op >> 0) & 0x7f; + if (zpi != 7) + dau_write_pi_double(zpi, res); + dau_set_val_flags((op >> 21) & 3, res); +} + + +void dsp32c_device::d1_0px(UINT32 op) +{ + double xval = dau_read_pi_double_1st(op >> 14, 1); + double yval = dau_read_pi_double_2nd(op >> 7, 0, xval); + double res = yval; + int zpi = (op >> 0) & 0x7f; + if (zpi != 7) + dau_write_pi_double(zpi, res); + dau_set_val_flags((op >> 21) & 3, res); + (void)xval; +} + + +void dsp32c_device::d1_0mx(UINT32 op) +{ + double xval = dau_read_pi_double_1st(op >> 14, 1); + double yval = dau_read_pi_double_2nd(op >> 7, 0, xval); + double res = -yval; + int zpi = (op >> 0) & 0x7f; + if (zpi != 7) + dau_write_pi_double(zpi, res); + dau_set_val_flags((op >> 21) & 3, res); + (void)xval; +} + + +void dsp32c_device::d1_1pp(UINT32 op) +{ + double xval = dau_read_pi_double_1st(op >> 14, 1); + double yval = dau_read_pi_double_2nd(op >> 7, 0, xval); + double res = yval + xval; + int zpi = (op >> 0) & 0x7f; + if (zpi != 7) + dau_write_pi_double(zpi, res); + dau_set_val_flags((op >> 21) & 3, res); +} + + +void dsp32c_device::d1_1pm(UINT32 op) +{ + double xval = dau_read_pi_double_1st(op >> 14, 1); + double yval = dau_read_pi_double_2nd(op >> 7, 0, xval); + double res = yval - xval; + int zpi = (op >> 0) & 0x7f; + if (zpi != 7) + dau_write_pi_double(zpi, res); + dau_set_val_flags((op >> 21) & 3, res); +} + + +void dsp32c_device::d1_1mp(UINT32 op) +{ + double xval = dau_read_pi_double_1st(op >> 14, 1); + double yval = dau_read_pi_double_2nd(op >> 7, 0, xval); + double res = -yval + xval; + int zpi = (op >> 0) & 0x7f; + if (zpi != 7) + dau_write_pi_double(zpi, res); + dau_set_val_flags((op >> 21) & 3, res); +} + + +void dsp32c_device::d1_1mm(UINT32 op) +{ + double xval = dau_read_pi_double_1st(op >> 14, 1); + double yval = dau_read_pi_double_2nd(op >> 7, 0, xval); + double res = -yval - xval; + int zpi = (op >> 0) & 0x7f; + if (zpi != 7) + dau_write_pi_double(zpi, res); + dau_set_val_flags((op >> 21) & 3, res); +} + + +void dsp32c_device::d1_aMppr(UINT32 op) +{ + unimplemented(op); +} + + +void dsp32c_device::d1_aMpmr(UINT32 op) +{ + unimplemented(op); +} + + +void dsp32c_device::d1_aMmpr(UINT32 op) +{ + unimplemented(op); +} + + +void dsp32c_device::d1_aMmmr(UINT32 op) +{ + unimplemented(op); +} + + + +//************************************************************************** +// DAU FORM 2 IMPLEMENTATION +//************************************************************************** + +void dsp32c_device::d2_aMpp(UINT32 op) +{ + double xval = dau_read_pi_double_1st(op >> 14, 1); + double yval = dau_read_pi_double_2nd(op >> 7, 1, xval); + double res = m_a[(op >> 26) & 7] + yval * xval; + int zpi = (op >> 0) & 0x7f; + if (zpi != 7) + dau_write_pi_double(zpi, yval); + dau_set_val_flags((op >> 21) & 3, res); +} + + +void dsp32c_device::d2_aMpm(UINT32 op) +{ + double xval = dau_read_pi_double_1st(op >> 14, 1); + double yval = dau_read_pi_double_2nd(op >> 7, 1, xval); + double res = m_a[(op >> 26) & 7] - yval * xval; + int zpi = (op >> 0) & 0x7f; + if (zpi != 7) + dau_write_pi_double(zpi, yval); + dau_set_val_flags((op >> 21) & 3, res); +} + + +void dsp32c_device::d2_aMmp(UINT32 op) +{ + double xval = dau_read_pi_double_1st(op >> 14, 1); + double yval = dau_read_pi_double_2nd(op >> 7, 1, xval); + double res = -m_a[(op >> 26) & 7] + yval * xval; + int zpi = (op >> 0) & 0x7f; + if (zpi != 7) + dau_write_pi_double(zpi, yval); + dau_set_val_flags((op >> 21) & 3, res); +} + + +void dsp32c_device::d2_aMmm(UINT32 op) +{ + double xval = dau_read_pi_double_1st(op >> 14, 1); + double yval = dau_read_pi_double_2nd(op >> 7, 1, xval); + double res = -m_a[(op >> 26) & 7] - yval * xval; + int zpi = (op >> 0) & 0x7f; + if (zpi != 7) + dau_write_pi_double(zpi, yval); + dau_set_val_flags((op >> 21) & 3, res); +} + + +void dsp32c_device::d2_aMppr(UINT32 op) +{ + unimplemented(op); +} + + +void dsp32c_device::d2_aMpmr(UINT32 op) +{ + unimplemented(op); +} + + +void dsp32c_device::d2_aMmpr(UINT32 op) +{ + unimplemented(op); +} + + +void dsp32c_device::d2_aMmmr(UINT32 op) +{ + unimplemented(op); +} + + + +//************************************************************************** +// DAU FORM 3 IMPLEMENTATION +//************************************************************************** + +void dsp32c_device::d3_aMpp(UINT32 op) +{ + double xval = dau_read_pi_double_1st(op >> 14, 1); + double yval = dau_read_pi_double_2nd(op >> 7, 1, xval); + double res = m_a[(op >> 26) & 7] + yval * xval; + int zpi = (op >> 0) & 0x7f; + if (zpi != 7) + dau_write_pi_double(zpi, res); + dau_set_val_flags((op >> 21) & 3, res); +} + + +void dsp32c_device::d3_aMpm(UINT32 op) +{ + double xval = dau_read_pi_double_1st(op >> 14, 1); + double yval = dau_read_pi_double_2nd(op >> 7, 1, xval); + double res = m_a[(op >> 26) & 7] - yval * xval; + int zpi = (op >> 0) & 0x7f; + if (zpi != 7) + dau_write_pi_double(zpi, res); + dau_set_val_flags((op >> 21) & 3, res); +} + + +void dsp32c_device::d3_aMmp(UINT32 op) +{ + double xval = dau_read_pi_double_1st(op >> 14, 1); + double yval = dau_read_pi_double_2nd(op >> 7, 1, xval); + double res = -m_a[(op >> 26) & 7] + yval * xval; + int zpi = (op >> 0) & 0x7f; + if (zpi != 7) + dau_write_pi_double(zpi, res); + dau_set_val_flags((op >> 21) & 3, res); +} + + +void dsp32c_device::d3_aMmm(UINT32 op) +{ + double xval = dau_read_pi_double_1st(op >> 14, 1); + double yval = dau_read_pi_double_2nd(op >> 7, 1, xval); + double res = -m_a[(op >> 26) & 7] - yval * xval; + int zpi = (op >> 0) & 0x7f; + if (zpi != 7) + dau_write_pi_double(zpi, res); + dau_set_val_flags((op >> 21) & 3, res); +} + + +void dsp32c_device::d3_aMppr(UINT32 op) +{ + unimplemented(op); +} + + +void dsp32c_device::d3_aMpmr(UINT32 op) +{ + unimplemented(op); +} + + +void dsp32c_device::d3_aMmpr(UINT32 op) +{ + unimplemented(op); +} + + +void dsp32c_device::d3_aMmmr(UINT32 op) +{ + unimplemented(op); +} + + + +//************************************************************************** +// DAU FORM 4 IMPLEMENTATION +//************************************************************************** + +void dsp32c_device::d4_pp(UINT32 op) +{ + double xval = dau_read_pi_double_1st(op >> 14, 1); + double yval = dau_read_pi_double_2nd(op >> 7, 0, xval); + double res = yval + xval; + int zpi = (op >> 0) & 0x7f; + if (zpi != 7) + dau_write_pi_double(zpi, yval); + dau_set_val_flags((op >> 21) & 3, res); +} + + +void dsp32c_device::d4_pm(UINT32 op) +{ + double xval = dau_read_pi_double_1st(op >> 14, 1); + double yval = dau_read_pi_double_2nd(op >> 7, 0, xval); + double res = yval - xval; + int zpi = (op >> 0) & 0x7f; + if (zpi != 7) + dau_write_pi_double(zpi, yval); + dau_set_val_flags((op >> 21) & 3, res); +} + + +void dsp32c_device::d4_mp(UINT32 op) +{ + double xval = dau_read_pi_double_1st(op >> 14, 1); + double yval = dau_read_pi_double_2nd(op >> 7, 0, xval); + double res = -yval + xval; + int zpi = (op >> 0) & 0x7f; + if (zpi != 7) + dau_write_pi_double(zpi, yval); + dau_set_val_flags((op >> 21) & 3, res); +} + + +void dsp32c_device::d4_mm(UINT32 op) +{ + double xval = dau_read_pi_double_1st(op >> 14, 1); + double yval = dau_read_pi_double_2nd(op >> 7, 0, xval); + double res = -yval - xval; + int zpi = (op >> 0) & 0x7f; + if (zpi != 7) + dau_write_pi_double(zpi, yval); + dau_set_val_flags((op >> 21) & 3, res); +} + + +void dsp32c_device::d4_ppr(UINT32 op) +{ + unimplemented(op); +} + + +void dsp32c_device::d4_pmr(UINT32 op) +{ + unimplemented(op); +} + + +void dsp32c_device::d4_mpr(UINT32 op) +{ + unimplemented(op); +} + + +void dsp32c_device::d4_mmr(UINT32 op) +{ + unimplemented(op); +} + + + +//************************************************************************** +// DAU FORM 5 IMPLEMENTATION +//************************************************************************** + +void dsp32c_device::d5_ic(UINT32 op) +{ + unimplemented(op); +} + + +void dsp32c_device::d5_oc(UINT32 op) +{ + unimplemented(op); +} + + +void dsp32c_device::d5_float(UINT32 op) +{ + double res = (double)(INT16)dau_read_pi_2bytes(op >> 7); + int zpi = (op >> 0) & 0x7f; + if (zpi != 7) + dau_write_pi_double(zpi, res); + dau_set_val_flags((op >> 21) & 3, res); +} + + +void dsp32c_device::d5_int(UINT32 op) +{ + double val = dau_read_pi_double_1st(op >> 7, 0); + int zpi = (op >> 0) & 0x7f; + INT16 res; + if (!(DAUC & 0x10)) val = floor(val + 0.5); + else val = ceil(val - 0.5); + res = (INT16)val; + if (zpi != 7) + dau_write_pi_2bytes(zpi, res); + dau_set_val_noflags((op >> 21) & 3, dsp_to_double(res << 16)); +} + + +void dsp32c_device::d5_round(UINT32 op) +{ + double res = (double)(float)dau_read_pi_double_1st(op >> 7, 0); + int zpi = (op >> 0) & 0x7f; + if (zpi != 7) + dau_write_pi_double(zpi, res); + dau_set_val_flags((op >> 21) & 3, res); +} + + +void dsp32c_device::d5_ifalt(UINT32 op) +{ + int ar = (op >> 21) & 3; + double res = m_a[ar]; + int zpi = (op >> 0) & 0x7f; + if (NFLAG) + res = dau_read_pi_double_1st(op >> 7, 0); + if (zpi != 7) + dau_write_pi_double(zpi, res); + dau_set_val_noflags(ar, res); +} + + +void dsp32c_device::d5_ifaeq(UINT32 op) +{ + int ar = (op >> 21) & 3; + double res = m_a[ar]; + int zpi = (op >> 0) & 0x7f; + if (ZFLAG) + res = dau_read_pi_double_1st(op >> 7, 0); + if (zpi != 7) + dau_write_pi_double(zpi, res); + dau_set_val_noflags(ar, res); +} + + +void dsp32c_device::d5_ifagt(UINT32 op) +{ + int ar = (op >> 21) & 3; + double res = m_a[ar]; + int zpi = (op >> 0) & 0x7f; + if (!NFLAG && !ZFLAG) + res = dau_read_pi_double_1st(op >> 7, 0); + if (zpi != 7) + dau_write_pi_double(zpi, res); + dau_set_val_noflags(ar, res); +} + + +void dsp32c_device::d5_float24(UINT32 op) +{ + double res = (double)((INT32)(dau_read_pi_4bytes(op >> 7) << 8) >> 8); + int zpi = (op >> 0) & 0x7f; + if (zpi != 7) + dau_write_pi_double(zpi, res); + dau_set_val_flags((op >> 21) & 3, res); +} + + +void dsp32c_device::d5_int24(UINT32 op) +{ + double val = dau_read_pi_double_1st(op >> 7, 0); + int zpi = (op >> 0) & 0x7f; + INT32 res; + if (!(DAUC & 0x10)) val = floor(val + 0.5); + else val = ceil(val - 0.5); + res = (INT32)val; + if (res > 0x7fffff) res = 0x7fffff; + else if (res < -0x800000) res = -0x800000; + if (zpi != 7) + dau_write_pi_4bytes(zpi, (INT32)(res << 8) >> 8); + dau_set_val_noflags((op >> 21) & 3, dsp_to_double(res << 8)); +} + + +void dsp32c_device::d5_ieee(UINT32 op) +{ + unimplemented(op); +} + + +void dsp32c_device::d5_dsp(UINT32 op) +{ + unimplemented(op); +} + + +void dsp32c_device::d5_seed(UINT32 op) +{ + UINT32 val = dau_read_pi_4bytes(op >> 7); + INT32 res = val ^ 0x7fffffff; + int zpi = (op >> 0) & 0x7f; + if (zpi != 7) + dau_write_pi_4bytes(zpi, res); + dau_set_val_flags((op >> 21) & 3, dsp_to_double((INT32)res)); +} + + + +//************************************************************************** +// FUNCTION TABLE +//************************************************************************** + +void (dsp32c_device::*const dsp32c_device::s_dsp32ops[])(UINT32 op) = +{ + &dsp32c_device::nop, &dsp32c_device::goto_t, &dsp32c_device::goto_pl, &dsp32c_device::goto_mi, &dsp32c_device::goto_ne, &dsp32c_device::goto_eq, &dsp32c_device::goto_vc, &dsp32c_device::goto_vs, // 00 + &dsp32c_device::goto_cc, &dsp32c_device::goto_cs, &dsp32c_device::goto_ge, &dsp32c_device::goto_lt, &dsp32c_device::goto_gt, &dsp32c_device::goto_le, &dsp32c_device::goto_hi, &dsp32c_device::goto_ls, + &dsp32c_device::goto_auc, &dsp32c_device::goto_aus, &dsp32c_device::goto_age, &dsp32c_device::goto_alt, &dsp32c_device::goto_ane, &dsp32c_device::goto_aeq, &dsp32c_device::goto_avc, &dsp32c_device::goto_avs, // 01 + &dsp32c_device::goto_agt, &dsp32c_device::goto_ale, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, + &dsp32c_device::goto_ibe, &dsp32c_device::goto_ibf, &dsp32c_device::goto_obf, &dsp32c_device::goto_obe, &dsp32c_device::goto_pde, &dsp32c_device::goto_pdf, &dsp32c_device::goto_pie, &dsp32c_device::goto_pif, // 02 + &dsp32c_device::goto_syc, &dsp32c_device::goto_sys, &dsp32c_device::goto_fbc, &dsp32c_device::goto_fbs, &dsp32c_device::goto_irq1lo,&dsp32c_device::goto_irq1hi,&dsp32c_device::goto_irq2lo,&dsp32c_device::goto_irq2hi, + &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, // 03 + &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, + + &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, // 04 + &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, + &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, // 05 + &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, + &dsp32c_device::dec_goto, &dsp32c_device::dec_goto, &dsp32c_device::dec_goto, &dsp32c_device::dec_goto, &dsp32c_device::dec_goto, &dsp32c_device::dec_goto, &dsp32c_device::dec_goto, &dsp32c_device::dec_goto, // 06 + &dsp32c_device::dec_goto, &dsp32c_device::dec_goto, &dsp32c_device::dec_goto, &dsp32c_device::dec_goto, &dsp32c_device::dec_goto, &dsp32c_device::dec_goto, &dsp32c_device::dec_goto, &dsp32c_device::dec_goto, + &dsp32c_device::dec_goto, &dsp32c_device::dec_goto, &dsp32c_device::dec_goto, &dsp32c_device::dec_goto, &dsp32c_device::dec_goto, &dsp32c_device::dec_goto, &dsp32c_device::dec_goto, &dsp32c_device::dec_goto, // 07 + &dsp32c_device::dec_goto, &dsp32c_device::dec_goto, &dsp32c_device::dec_goto, &dsp32c_device::dec_goto, &dsp32c_device::dec_goto, &dsp32c_device::dec_goto, &dsp32c_device::dec_goto, &dsp32c_device::dec_goto, + + &dsp32c_device::call, &dsp32c_device::call, &dsp32c_device::call, &dsp32c_device::call, &dsp32c_device::call, &dsp32c_device::call, &dsp32c_device::call, &dsp32c_device::call, // 08 + &dsp32c_device::call, &dsp32c_device::call, &dsp32c_device::call, &dsp32c_device::call, &dsp32c_device::call, &dsp32c_device::call, &dsp32c_device::call, &dsp32c_device::call, + &dsp32c_device::call, &dsp32c_device::call, &dsp32c_device::call, &dsp32c_device::call, &dsp32c_device::call, &dsp32c_device::call, &dsp32c_device::call, &dsp32c_device::call, // 09 + &dsp32c_device::call, &dsp32c_device::call, &dsp32c_device::call, &dsp32c_device::call, &dsp32c_device::call, &dsp32c_device::call, &dsp32c_device::call, &dsp32c_device::call, + &dsp32c_device::add_si, &dsp32c_device::add_si, &dsp32c_device::add_si, &dsp32c_device::add_si, &dsp32c_device::add_si, &dsp32c_device::add_si, &dsp32c_device::add_si, &dsp32c_device::add_si, // 0a + &dsp32c_device::add_si, &dsp32c_device::add_si, &dsp32c_device::add_si, &dsp32c_device::add_si, &dsp32c_device::add_si, &dsp32c_device::add_si, &dsp32c_device::add_si, &dsp32c_device::add_si, + &dsp32c_device::add_si, &dsp32c_device::add_si, &dsp32c_device::add_si, &dsp32c_device::add_si, &dsp32c_device::add_si, &dsp32c_device::add_si, &dsp32c_device::add_si, &dsp32c_device::add_si, // 0b + &dsp32c_device::add_si, &dsp32c_device::add_si, &dsp32c_device::add_si, &dsp32c_device::add_si, &dsp32c_device::add_si, &dsp32c_device::add_si, &dsp32c_device::add_si, &dsp32c_device::add_si, + + &dsp32c_device::add_ss, &dsp32c_device::mul2_s, &dsp32c_device::subr_ss, &dsp32c_device::addr_ss, &dsp32c_device::sub_ss, &dsp32c_device::neg_s, &dsp32c_device::andc_ss, &dsp32c_device::cmp_ss, // 0c + &dsp32c_device::xor_ss, &dsp32c_device::rcr_s, &dsp32c_device::or_ss, &dsp32c_device::rcl_s, &dsp32c_device::shr_s, &dsp32c_device::div2_s, &dsp32c_device::and_ss, &dsp32c_device::test_ss, + &dsp32c_device::add_di, &dsp32c_device::illegal, &dsp32c_device::subr_di, &dsp32c_device::addr_di, &dsp32c_device::sub_di, &dsp32c_device::illegal, &dsp32c_device::andc_di, &dsp32c_device::cmp_di, // 0d + &dsp32c_device::xor_di, &dsp32c_device::illegal, &dsp32c_device::or_di, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::and_di, &dsp32c_device::test_di, + &dsp32c_device::load_hi, &dsp32c_device::load_hi, &dsp32c_device::load_li, &dsp32c_device::load_li, &dsp32c_device::load_i, &dsp32c_device::load_i, &dsp32c_device::load_ei, &dsp32c_device::load_ei, // 0e + &dsp32c_device::store_hi, &dsp32c_device::store_hi, &dsp32c_device::store_li, &dsp32c_device::store_li, &dsp32c_device::store_i, &dsp32c_device::store_i, &dsp32c_device::store_ei, &dsp32c_device::store_ei, + &dsp32c_device::load_hr, &dsp32c_device::load_hr, &dsp32c_device::load_lr, &dsp32c_device::load_lr, &dsp32c_device::load_r, &dsp32c_device::load_r, &dsp32c_device::load_er, &dsp32c_device::load_er, // 0f + &dsp32c_device::store_hr, &dsp32c_device::store_hr, &dsp32c_device::store_lr, &dsp32c_device::store_lr, &dsp32c_device::store_r, &dsp32c_device::store_r, &dsp32c_device::store_er, &dsp32c_device::store_er, + + &dsp32c_device::d1_aMpp, &dsp32c_device::d1_aMpp, &dsp32c_device::d1_aMpp, &dsp32c_device::d1_aMpp, &dsp32c_device::d1_aMpm, &dsp32c_device::d1_aMpm, &dsp32c_device::d1_aMpm, &dsp32c_device::d1_aMpm, // 10 + &dsp32c_device::d1_aMmp, &dsp32c_device::d1_aMmp, &dsp32c_device::d1_aMmp, &dsp32c_device::d1_aMmp, &dsp32c_device::d1_aMmm, &dsp32c_device::d1_aMmm, &dsp32c_device::d1_aMmm, &dsp32c_device::d1_aMmm, + &dsp32c_device::d1_aMppr, &dsp32c_device::d1_aMppr, &dsp32c_device::d1_aMppr, &dsp32c_device::d1_aMppr, &dsp32c_device::d1_aMpmr, &dsp32c_device::d1_aMpmr, &dsp32c_device::d1_aMpmr, &dsp32c_device::d1_aMpmr, // 11 + &dsp32c_device::d1_aMmpr, &dsp32c_device::d1_aMmpr, &dsp32c_device::d1_aMmpr, &dsp32c_device::d1_aMmpr, &dsp32c_device::d1_aMmmr, &dsp32c_device::d1_aMmmr, &dsp32c_device::d1_aMmmr, &dsp32c_device::d1_aMmmr, + &dsp32c_device::d1_aMpp, &dsp32c_device::d1_aMpp, &dsp32c_device::d1_aMpp, &dsp32c_device::d1_aMpp, &dsp32c_device::d1_aMpm, &dsp32c_device::d1_aMpm, &dsp32c_device::d1_aMpm, &dsp32c_device::d1_aMpm, // 12 + &dsp32c_device::d1_aMmp, &dsp32c_device::d1_aMmp, &dsp32c_device::d1_aMmp, &dsp32c_device::d1_aMmp, &dsp32c_device::d1_aMmm, &dsp32c_device::d1_aMmm, &dsp32c_device::d1_aMmm, &dsp32c_device::d1_aMmm, + &dsp32c_device::d1_aMppr, &dsp32c_device::d1_aMppr, &dsp32c_device::d1_aMppr, &dsp32c_device::d1_aMppr, &dsp32c_device::d1_aMpmr, &dsp32c_device::d1_aMpmr, &dsp32c_device::d1_aMpmr, &dsp32c_device::d1_aMpmr, // 13 + &dsp32c_device::d1_aMmpr, &dsp32c_device::d1_aMmpr, &dsp32c_device::d1_aMmpr, &dsp32c_device::d1_aMmpr, &dsp32c_device::d1_aMmmr, &dsp32c_device::d1_aMmmr, &dsp32c_device::d1_aMmmr, &dsp32c_device::d1_aMmmr, + + &dsp32c_device::d1_aMpp, &dsp32c_device::d1_aMpp, &dsp32c_device::d1_aMpp, &dsp32c_device::d1_aMpp, &dsp32c_device::d1_aMpm, &dsp32c_device::d1_aMpm, &dsp32c_device::d1_aMpm, &dsp32c_device::d1_aMpm, // 14 + &dsp32c_device::d1_aMmp, &dsp32c_device::d1_aMmp, &dsp32c_device::d1_aMmp, &dsp32c_device::d1_aMmp, &dsp32c_device::d1_aMmm, &dsp32c_device::d1_aMmm, &dsp32c_device::d1_aMmm, &dsp32c_device::d1_aMmm, + &dsp32c_device::d1_aMppr, &dsp32c_device::d1_aMppr, &dsp32c_device::d1_aMppr, &dsp32c_device::d1_aMppr, &dsp32c_device::d1_aMpmr, &dsp32c_device::d1_aMpmr, &dsp32c_device::d1_aMpmr, &dsp32c_device::d1_aMpmr, // 15 + &dsp32c_device::d1_aMmpr, &dsp32c_device::d1_aMmpr, &dsp32c_device::d1_aMmpr, &dsp32c_device::d1_aMmpr, &dsp32c_device::d1_aMmmr, &dsp32c_device::d1_aMmmr, &dsp32c_device::d1_aMmmr, &dsp32c_device::d1_aMmmr, + &dsp32c_device::d1_aMpp, &dsp32c_device::d1_aMpp, &dsp32c_device::d1_aMpp, &dsp32c_device::d1_aMpp, &dsp32c_device::d1_aMpm, &dsp32c_device::d1_aMpm, &dsp32c_device::d1_aMpm, &dsp32c_device::d1_aMpm, // 16 + &dsp32c_device::d1_aMmp, &dsp32c_device::d1_aMmp, &dsp32c_device::d1_aMmp, &dsp32c_device::d1_aMmp, &dsp32c_device::d1_aMmm, &dsp32c_device::d1_aMmm, &dsp32c_device::d1_aMmm, &dsp32c_device::d1_aMmm, + &dsp32c_device::d1_aMppr, &dsp32c_device::d1_aMppr, &dsp32c_device::d1_aMppr, &dsp32c_device::d1_aMppr, &dsp32c_device::d1_aMpmr, &dsp32c_device::d1_aMpmr, &dsp32c_device::d1_aMpmr, &dsp32c_device::d1_aMpmr, // 17 + &dsp32c_device::d1_aMmpr, &dsp32c_device::d1_aMmpr, &dsp32c_device::d1_aMmpr, &dsp32c_device::d1_aMmpr, &dsp32c_device::d1_aMmmr, &dsp32c_device::d1_aMmmr, &dsp32c_device::d1_aMmmr, &dsp32c_device::d1_aMmmr, + + &dsp32c_device::d1_0px, &dsp32c_device::d1_0px, &dsp32c_device::d1_0px, &dsp32c_device::d1_0px, &dsp32c_device::d1_0px, &dsp32c_device::d1_0px, &dsp32c_device::d1_0px, &dsp32c_device::d1_0px, // 18 + &dsp32c_device::d1_0mx, &dsp32c_device::d1_0mx, &dsp32c_device::d1_0mx, &dsp32c_device::d1_0mx, &dsp32c_device::d1_0mx, &dsp32c_device::d1_0mx, &dsp32c_device::d1_0mx, &dsp32c_device::d1_0mx, + &dsp32c_device::d1_aMppr, &dsp32c_device::d1_aMppr, &dsp32c_device::d1_aMppr, &dsp32c_device::d1_aMppr, &dsp32c_device::d1_aMpmr, &dsp32c_device::d1_aMpmr, &dsp32c_device::d1_aMpmr, &dsp32c_device::d1_aMpmr, // 19 + &dsp32c_device::d1_aMmpr, &dsp32c_device::d1_aMmpr, &dsp32c_device::d1_aMmpr, &dsp32c_device::d1_aMmpr, &dsp32c_device::d1_aMmmr, &dsp32c_device::d1_aMmmr, &dsp32c_device::d1_aMmmr, &dsp32c_device::d1_aMmmr, + &dsp32c_device::d1_1pp, &dsp32c_device::d1_1pp, &dsp32c_device::d1_1pp, &dsp32c_device::d1_1pp, &dsp32c_device::d1_1pm, &dsp32c_device::d1_1pm, &dsp32c_device::d1_1pm, &dsp32c_device::d1_1pm, // 1a + &dsp32c_device::d1_1mp, &dsp32c_device::d1_1mp, &dsp32c_device::d1_1mp, &dsp32c_device::d1_1mp, &dsp32c_device::d1_1mm, &dsp32c_device::d1_1mm, &dsp32c_device::d1_1mm, &dsp32c_device::d1_1mm, + &dsp32c_device::d1_aMppr, &dsp32c_device::d1_aMppr, &dsp32c_device::d1_aMppr, &dsp32c_device::d1_aMppr, &dsp32c_device::d1_aMpmr, &dsp32c_device::d1_aMpmr, &dsp32c_device::d1_aMpmr, &dsp32c_device::d1_aMpmr, // 1b + &dsp32c_device::d1_aMmpr, &dsp32c_device::d1_aMmpr, &dsp32c_device::d1_aMmpr, &dsp32c_device::d1_aMmpr, &dsp32c_device::d1_aMmmr, &dsp32c_device::d1_aMmmr, &dsp32c_device::d1_aMmmr, &dsp32c_device::d1_aMmmr, + + &dsp32c_device::d4_pp, &dsp32c_device::d4_pp, &dsp32c_device::d4_pp, &dsp32c_device::d4_pp, &dsp32c_device::d4_pm, &dsp32c_device::d4_pm, &dsp32c_device::d4_pm, &dsp32c_device::d4_pm, // 1c + &dsp32c_device::d4_mp, &dsp32c_device::d4_mp, &dsp32c_device::d4_mp, &dsp32c_device::d4_mp, &dsp32c_device::d4_mm, &dsp32c_device::d4_mm, &dsp32c_device::d4_mm, &dsp32c_device::d4_mm, + &dsp32c_device::d4_ppr, &dsp32c_device::d4_ppr, &dsp32c_device::d4_ppr, &dsp32c_device::d4_ppr, &dsp32c_device::d4_pmr, &dsp32c_device::d4_pmr, &dsp32c_device::d4_pmr, &dsp32c_device::d4_pmr, // 1d + &dsp32c_device::d4_mpr, &dsp32c_device::d4_mpr, &dsp32c_device::d4_mpr, &dsp32c_device::d4_mpr, &dsp32c_device::d4_mmr, &dsp32c_device::d4_mmr, &dsp32c_device::d4_mmr, &dsp32c_device::d4_mmr, + &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, // 1e + &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, + &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, // 1f + &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, + + &dsp32c_device::d2_aMpp, &dsp32c_device::d2_aMpp, &dsp32c_device::d2_aMpp, &dsp32c_device::d2_aMpp, &dsp32c_device::d2_aMpm, &dsp32c_device::d2_aMpm, &dsp32c_device::d2_aMpm, &dsp32c_device::d2_aMpm, // 20 + &dsp32c_device::d2_aMmp, &dsp32c_device::d2_aMmp, &dsp32c_device::d2_aMmp, &dsp32c_device::d2_aMmp, &dsp32c_device::d2_aMmm, &dsp32c_device::d2_aMmm, &dsp32c_device::d2_aMmm, &dsp32c_device::d2_aMmm, + &dsp32c_device::d2_aMppr, &dsp32c_device::d2_aMppr, &dsp32c_device::d2_aMppr, &dsp32c_device::d2_aMppr, &dsp32c_device::d2_aMpmr, &dsp32c_device::d2_aMpmr, &dsp32c_device::d2_aMpmr, &dsp32c_device::d2_aMpmr, // 21 + &dsp32c_device::d2_aMmpr, &dsp32c_device::d2_aMmpr, &dsp32c_device::d2_aMmpr, &dsp32c_device::d2_aMmpr, &dsp32c_device::d2_aMmmr, &dsp32c_device::d2_aMmmr, &dsp32c_device::d2_aMmmr, &dsp32c_device::d2_aMmmr, + &dsp32c_device::d2_aMpp, &dsp32c_device::d2_aMpp, &dsp32c_device::d2_aMpp, &dsp32c_device::d2_aMpp, &dsp32c_device::d2_aMpm, &dsp32c_device::d2_aMpm, &dsp32c_device::d2_aMpm, &dsp32c_device::d2_aMpm, // 22 + &dsp32c_device::d2_aMmp, &dsp32c_device::d2_aMmp, &dsp32c_device::d2_aMmp, &dsp32c_device::d2_aMmp, &dsp32c_device::d2_aMmm, &dsp32c_device::d2_aMmm, &dsp32c_device::d2_aMmm, &dsp32c_device::d2_aMmm, + &dsp32c_device::d2_aMppr, &dsp32c_device::d2_aMppr, &dsp32c_device::d2_aMppr, &dsp32c_device::d2_aMppr, &dsp32c_device::d2_aMpmr, &dsp32c_device::d2_aMpmr, &dsp32c_device::d2_aMpmr, &dsp32c_device::d2_aMpmr, // 23 + &dsp32c_device::d2_aMmpr, &dsp32c_device::d2_aMmpr, &dsp32c_device::d2_aMmpr, &dsp32c_device::d2_aMmpr, &dsp32c_device::d2_aMmmr, &dsp32c_device::d2_aMmmr, &dsp32c_device::d2_aMmmr, &dsp32c_device::d2_aMmmr, + + &dsp32c_device::d2_aMpp, &dsp32c_device::d2_aMpp, &dsp32c_device::d2_aMpp, &dsp32c_device::d2_aMpp, &dsp32c_device::d2_aMpm, &dsp32c_device::d2_aMpm, &dsp32c_device::d2_aMpm, &dsp32c_device::d2_aMpm, // 24 + &dsp32c_device::d2_aMmp, &dsp32c_device::d2_aMmp, &dsp32c_device::d2_aMmp, &dsp32c_device::d2_aMmp, &dsp32c_device::d2_aMmm, &dsp32c_device::d2_aMmm, &dsp32c_device::d2_aMmm, &dsp32c_device::d2_aMmm, + &dsp32c_device::d2_aMppr, &dsp32c_device::d2_aMppr, &dsp32c_device::d2_aMppr, &dsp32c_device::d2_aMppr, &dsp32c_device::d2_aMpmr, &dsp32c_device::d2_aMpmr, &dsp32c_device::d2_aMpmr, &dsp32c_device::d2_aMpmr, // 25 + &dsp32c_device::d2_aMmpr, &dsp32c_device::d2_aMmpr, &dsp32c_device::d2_aMmpr, &dsp32c_device::d2_aMmpr, &dsp32c_device::d2_aMmmr, &dsp32c_device::d2_aMmmr, &dsp32c_device::d2_aMmmr, &dsp32c_device::d2_aMmmr, + &dsp32c_device::d2_aMpp, &dsp32c_device::d2_aMpp, &dsp32c_device::d2_aMpp, &dsp32c_device::d2_aMpp, &dsp32c_device::d2_aMpm, &dsp32c_device::d2_aMpm, &dsp32c_device::d2_aMpm, &dsp32c_device::d2_aMpm, // 26 + &dsp32c_device::d2_aMmp, &dsp32c_device::d2_aMmp, &dsp32c_device::d2_aMmp, &dsp32c_device::d2_aMmp, &dsp32c_device::d2_aMmm, &dsp32c_device::d2_aMmm, &dsp32c_device::d2_aMmm, &dsp32c_device::d2_aMmm, + &dsp32c_device::d2_aMppr, &dsp32c_device::d2_aMppr, &dsp32c_device::d2_aMppr, &dsp32c_device::d2_aMppr, &dsp32c_device::d2_aMpmr, &dsp32c_device::d2_aMpmr, &dsp32c_device::d2_aMpmr, &dsp32c_device::d2_aMpmr, // 27 + &dsp32c_device::d2_aMmpr, &dsp32c_device::d2_aMmpr, &dsp32c_device::d2_aMmpr, &dsp32c_device::d2_aMmpr, &dsp32c_device::d2_aMmmr, &dsp32c_device::d2_aMmmr, &dsp32c_device::d2_aMmmr, &dsp32c_device::d2_aMmmr, + + &dsp32c_device::d2_aMpp, &dsp32c_device::d2_aMpp, &dsp32c_device::d2_aMpp, &dsp32c_device::d2_aMpp, &dsp32c_device::d2_aMpm, &dsp32c_device::d2_aMpm, &dsp32c_device::d2_aMpm, &dsp32c_device::d2_aMpm, // 28 + &dsp32c_device::d2_aMmp, &dsp32c_device::d2_aMmp, &dsp32c_device::d2_aMmp, &dsp32c_device::d2_aMmp, &dsp32c_device::d2_aMmm, &dsp32c_device::d2_aMmm, &dsp32c_device::d2_aMmm, &dsp32c_device::d2_aMmm, + &dsp32c_device::d2_aMppr, &dsp32c_device::d2_aMppr, &dsp32c_device::d2_aMppr, &dsp32c_device::d2_aMppr, &dsp32c_device::d2_aMpmr, &dsp32c_device::d2_aMpmr, &dsp32c_device::d2_aMpmr, &dsp32c_device::d2_aMpmr, // 29 + &dsp32c_device::d2_aMmpr, &dsp32c_device::d2_aMmpr, &dsp32c_device::d2_aMmpr, &dsp32c_device::d2_aMmpr, &dsp32c_device::d2_aMmmr, &dsp32c_device::d2_aMmmr, &dsp32c_device::d2_aMmmr, &dsp32c_device::d2_aMmmr, + &dsp32c_device::d2_aMpp, &dsp32c_device::d2_aMpp, &dsp32c_device::d2_aMpp, &dsp32c_device::d2_aMpp, &dsp32c_device::d2_aMpm, &dsp32c_device::d2_aMpm, &dsp32c_device::d2_aMpm, &dsp32c_device::d2_aMpm, // 2a + &dsp32c_device::d2_aMmp, &dsp32c_device::d2_aMmp, &dsp32c_device::d2_aMmp, &dsp32c_device::d2_aMmp, &dsp32c_device::d2_aMmm, &dsp32c_device::d2_aMmm, &dsp32c_device::d2_aMmm, &dsp32c_device::d2_aMmm, + &dsp32c_device::d2_aMppr, &dsp32c_device::d2_aMppr, &dsp32c_device::d2_aMppr, &dsp32c_device::d2_aMppr, &dsp32c_device::d2_aMpmr, &dsp32c_device::d2_aMpmr, &dsp32c_device::d2_aMpmr, &dsp32c_device::d2_aMpmr, // 2b + &dsp32c_device::d2_aMmpr, &dsp32c_device::d2_aMmpr, &dsp32c_device::d2_aMmpr, &dsp32c_device::d2_aMmpr, &dsp32c_device::d2_aMmmr, &dsp32c_device::d2_aMmmr, &dsp32c_device::d2_aMmmr, &dsp32c_device::d2_aMmmr, + + &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, // 2c + &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, + &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, // 2d + &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, + &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, // 2e + &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, + &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, // 2f + &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, + + &dsp32c_device::d3_aMpp, &dsp32c_device::d3_aMpp, &dsp32c_device::d3_aMpp, &dsp32c_device::d3_aMpp, &dsp32c_device::d3_aMpm, &dsp32c_device::d3_aMpm, &dsp32c_device::d3_aMpm, &dsp32c_device::d3_aMpm, // 30 + &dsp32c_device::d3_aMmp, &dsp32c_device::d3_aMmp, &dsp32c_device::d3_aMmp, &dsp32c_device::d3_aMmp, &dsp32c_device::d3_aMmm, &dsp32c_device::d3_aMmm, &dsp32c_device::d3_aMmm, &dsp32c_device::d3_aMmm, + &dsp32c_device::d3_aMppr, &dsp32c_device::d3_aMppr, &dsp32c_device::d3_aMppr, &dsp32c_device::d3_aMppr, &dsp32c_device::d3_aMpmr, &dsp32c_device::d3_aMpmr, &dsp32c_device::d3_aMpmr, &dsp32c_device::d3_aMpmr, // 31 + &dsp32c_device::d3_aMmpr, &dsp32c_device::d3_aMmpr, &dsp32c_device::d3_aMmpr, &dsp32c_device::d3_aMmpr, &dsp32c_device::d3_aMmmr, &dsp32c_device::d3_aMmmr, &dsp32c_device::d3_aMmmr, &dsp32c_device::d3_aMmmr, + &dsp32c_device::d3_aMpp, &dsp32c_device::d3_aMpp, &dsp32c_device::d3_aMpp, &dsp32c_device::d3_aMpp, &dsp32c_device::d3_aMpm, &dsp32c_device::d3_aMpm, &dsp32c_device::d3_aMpm, &dsp32c_device::d3_aMpm, // 32 + &dsp32c_device::d3_aMmp, &dsp32c_device::d3_aMmp, &dsp32c_device::d3_aMmp, &dsp32c_device::d3_aMmp, &dsp32c_device::d3_aMmm, &dsp32c_device::d3_aMmm, &dsp32c_device::d3_aMmm, &dsp32c_device::d3_aMmm, + &dsp32c_device::d3_aMppr, &dsp32c_device::d3_aMppr, &dsp32c_device::d3_aMppr, &dsp32c_device::d3_aMppr, &dsp32c_device::d3_aMpmr, &dsp32c_device::d3_aMpmr, &dsp32c_device::d3_aMpmr, &dsp32c_device::d3_aMpmr, // 33 + &dsp32c_device::d3_aMmpr, &dsp32c_device::d3_aMmpr, &dsp32c_device::d3_aMmpr, &dsp32c_device::d3_aMmpr, &dsp32c_device::d3_aMmmr, &dsp32c_device::d3_aMmmr, &dsp32c_device::d3_aMmmr, &dsp32c_device::d3_aMmmr, + + &dsp32c_device::d3_aMpp, &dsp32c_device::d3_aMpp, &dsp32c_device::d3_aMpp, &dsp32c_device::d3_aMpp, &dsp32c_device::d3_aMpm, &dsp32c_device::d3_aMpm, &dsp32c_device::d3_aMpm, &dsp32c_device::d3_aMpm, // 34 + &dsp32c_device::d3_aMmp, &dsp32c_device::d3_aMmp, &dsp32c_device::d3_aMmp, &dsp32c_device::d3_aMmp, &dsp32c_device::d3_aMmm, &dsp32c_device::d3_aMmm, &dsp32c_device::d3_aMmm, &dsp32c_device::d3_aMmm, + &dsp32c_device::d3_aMppr, &dsp32c_device::d3_aMppr, &dsp32c_device::d3_aMppr, &dsp32c_device::d3_aMppr, &dsp32c_device::d3_aMpmr, &dsp32c_device::d3_aMpmr, &dsp32c_device::d3_aMpmr, &dsp32c_device::d3_aMpmr, // 35 + &dsp32c_device::d3_aMmpr, &dsp32c_device::d3_aMmpr, &dsp32c_device::d3_aMmpr, &dsp32c_device::d3_aMmpr, &dsp32c_device::d3_aMmmr, &dsp32c_device::d3_aMmmr, &dsp32c_device::d3_aMmmr, &dsp32c_device::d3_aMmmr, + &dsp32c_device::d3_aMpp, &dsp32c_device::d3_aMpp, &dsp32c_device::d3_aMpp, &dsp32c_device::d3_aMpp, &dsp32c_device::d3_aMpm, &dsp32c_device::d3_aMpm, &dsp32c_device::d3_aMpm, &dsp32c_device::d3_aMpm, // 36 + &dsp32c_device::d3_aMmp, &dsp32c_device::d3_aMmp, &dsp32c_device::d3_aMmp, &dsp32c_device::d3_aMmp, &dsp32c_device::d3_aMmm, &dsp32c_device::d3_aMmm, &dsp32c_device::d3_aMmm, &dsp32c_device::d3_aMmm, + &dsp32c_device::d3_aMppr, &dsp32c_device::d3_aMppr, &dsp32c_device::d3_aMppr, &dsp32c_device::d3_aMppr, &dsp32c_device::d3_aMpmr, &dsp32c_device::d3_aMpmr, &dsp32c_device::d3_aMpmr, &dsp32c_device::d3_aMpmr, // 37 + &dsp32c_device::d3_aMmpr, &dsp32c_device::d3_aMmpr, &dsp32c_device::d3_aMmpr, &dsp32c_device::d3_aMmpr, &dsp32c_device::d3_aMmmr, &dsp32c_device::d3_aMmmr, &dsp32c_device::d3_aMmmr, &dsp32c_device::d3_aMmmr, + + &dsp32c_device::d3_aMpp, &dsp32c_device::d3_aMpp, &dsp32c_device::d3_aMpp, &dsp32c_device::d3_aMpp, &dsp32c_device::d3_aMpm, &dsp32c_device::d3_aMpm, &dsp32c_device::d3_aMpm, &dsp32c_device::d3_aMpm, // 38 + &dsp32c_device::d3_aMmp, &dsp32c_device::d3_aMmp, &dsp32c_device::d3_aMmp, &dsp32c_device::d3_aMmp, &dsp32c_device::d3_aMmm, &dsp32c_device::d3_aMmm, &dsp32c_device::d3_aMmm, &dsp32c_device::d3_aMmm, + &dsp32c_device::d3_aMppr, &dsp32c_device::d3_aMppr, &dsp32c_device::d3_aMppr, &dsp32c_device::d3_aMppr, &dsp32c_device::d3_aMpmr, &dsp32c_device::d3_aMpmr, &dsp32c_device::d3_aMpmr, &dsp32c_device::d3_aMpmr, // 39 + &dsp32c_device::d3_aMmpr, &dsp32c_device::d3_aMmpr, &dsp32c_device::d3_aMmpr, &dsp32c_device::d3_aMmpr, &dsp32c_device::d3_aMmmr, &dsp32c_device::d3_aMmmr, &dsp32c_device::d3_aMmmr, &dsp32c_device::d3_aMmmr, + &dsp32c_device::d3_aMpp, &dsp32c_device::d3_aMpp, &dsp32c_device::d3_aMpp, &dsp32c_device::d3_aMpp, &dsp32c_device::d3_aMpm, &dsp32c_device::d3_aMpm, &dsp32c_device::d3_aMpm, &dsp32c_device::d3_aMpm, // 3a + &dsp32c_device::d3_aMmp, &dsp32c_device::d3_aMmp, &dsp32c_device::d3_aMmp, &dsp32c_device::d3_aMmp, &dsp32c_device::d3_aMmm, &dsp32c_device::d3_aMmm, &dsp32c_device::d3_aMmm, &dsp32c_device::d3_aMmm, + &dsp32c_device::d3_aMppr, &dsp32c_device::d3_aMppr, &dsp32c_device::d3_aMppr, &dsp32c_device::d3_aMppr, &dsp32c_device::d3_aMpmr, &dsp32c_device::d3_aMpmr, &dsp32c_device::d3_aMpmr, &dsp32c_device::d3_aMpmr, // 3b + &dsp32c_device::d3_aMmpr, &dsp32c_device::d3_aMmpr, &dsp32c_device::d3_aMmpr, &dsp32c_device::d3_aMmpr, &dsp32c_device::d3_aMmmr, &dsp32c_device::d3_aMmmr, &dsp32c_device::d3_aMmmr, &dsp32c_device::d3_aMmmr, + + &dsp32c_device::d5_ic, &dsp32c_device::d5_ic, &dsp32c_device::d5_ic, &dsp32c_device::d5_ic, &dsp32c_device::d5_oc, &dsp32c_device::d5_oc, &dsp32c_device::d5_oc, &dsp32c_device::d5_oc, // 3c + &dsp32c_device::d5_float, &dsp32c_device::d5_float, &dsp32c_device::d5_float, &dsp32c_device::d5_float, &dsp32c_device::d5_int, &dsp32c_device::d5_int, &dsp32c_device::d5_int, &dsp32c_device::d5_int, + &dsp32c_device::d5_round, &dsp32c_device::d5_round, &dsp32c_device::d5_round, &dsp32c_device::d5_round, &dsp32c_device::d5_ifalt, &dsp32c_device::d5_ifalt, &dsp32c_device::d5_ifalt, &dsp32c_device::d5_ifalt, // 3d + &dsp32c_device::d5_ifaeq, &dsp32c_device::d5_ifaeq, &dsp32c_device::d5_ifaeq, &dsp32c_device::d5_ifaeq, &dsp32c_device::d5_ifagt, &dsp32c_device::d5_ifagt, &dsp32c_device::d5_ifagt, &dsp32c_device::d5_ifagt, + &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, // 3e + &dsp32c_device::d5_float24, &dsp32c_device::d5_float24, &dsp32c_device::d5_float24, &dsp32c_device::d5_float24, &dsp32c_device::d5_int24, &dsp32c_device::d5_int24, &dsp32c_device::d5_int24, &dsp32c_device::d5_int24, + &dsp32c_device::d5_ieee, &dsp32c_device::d5_ieee, &dsp32c_device::d5_ieee, &dsp32c_device::d5_ieee, &dsp32c_device::d5_dsp, &dsp32c_device::d5_dsp, &dsp32c_device::d5_dsp, &dsp32c_device::d5_dsp, // 3f + &dsp32c_device::d5_seed, &dsp32c_device::d5_seed, &dsp32c_device::d5_seed, &dsp32c_device::d5_seed, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, + + &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, // 40 + &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, + &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, // 41 + &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, + &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, // 42 + &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, + &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, // 43 + &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, + + &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, // 44 + &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, + &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, // 45 + &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, + &dsp32c_device::do_i, &dsp32c_device::do_r, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, // 46 + &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, + &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, // 47 + &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, + + &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, // 48 + &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, + &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, // 49 + &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, + &dsp32c_device::adde_si, &dsp32c_device::adde_si, &dsp32c_device::adde_si, &dsp32c_device::adde_si, &dsp32c_device::adde_si, &dsp32c_device::adde_si, &dsp32c_device::adde_si, &dsp32c_device::adde_si, // 4a + &dsp32c_device::adde_si, &dsp32c_device::adde_si, &dsp32c_device::adde_si, &dsp32c_device::adde_si, &dsp32c_device::adde_si, &dsp32c_device::adde_si, &dsp32c_device::adde_si, &dsp32c_device::adde_si, + &dsp32c_device::adde_si, &dsp32c_device::adde_si, &dsp32c_device::adde_si, &dsp32c_device::adde_si, &dsp32c_device::adde_si, &dsp32c_device::adde_si, &dsp32c_device::adde_si, &dsp32c_device::adde_si, // 4b + &dsp32c_device::adde_si, &dsp32c_device::adde_si, &dsp32c_device::adde_si, &dsp32c_device::adde_si, &dsp32c_device::adde_si, &dsp32c_device::adde_si, &dsp32c_device::adde_si, &dsp32c_device::adde_si, + + &dsp32c_device::adde_ss, &dsp32c_device::mul2e_s, &dsp32c_device::subre_ss, &dsp32c_device::addre_ss, &dsp32c_device::sube_ss, &dsp32c_device::nege_s, &dsp32c_device::andce_ss, &dsp32c_device::cmpe_ss, // 4c + &dsp32c_device::xore_ss, &dsp32c_device::rcre_s, &dsp32c_device::ore_ss, &dsp32c_device::rcle_s, &dsp32c_device::shre_s, &dsp32c_device::div2e_s, &dsp32c_device::ande_ss, &dsp32c_device::teste_ss, + &dsp32c_device::adde_di, &dsp32c_device::illegal, &dsp32c_device::subre_di, &dsp32c_device::addre_di, &dsp32c_device::sube_di, &dsp32c_device::illegal, &dsp32c_device::andce_di, &dsp32c_device::cmpe_di, // 4d + &dsp32c_device::xore_di, &dsp32c_device::illegal, &dsp32c_device::ore_di, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::ande_di, &dsp32c_device::teste_di, + &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, // 4e + &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, + &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, // 4f + &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, &dsp32c_device::illegal, + + &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, // 50 + &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, + &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, // 51 + &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, + &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, // 52 + &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, + &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, // 53 + &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, + + &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, // 54 + &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, + &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, // 55 + &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, + &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, // 56 + &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, + &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, // 57 + &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, + + &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, // 58 + &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, + &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, // 59 + &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, + &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, // 5a + &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, + &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, // 5b + &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, + + &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, // 5c + &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, + &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, // 5d + &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, + &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, // 5e + &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, + &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, // 5f + &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, &dsp32c_device::goto24, + + &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, // 60 + &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, + &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, // 61 + &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, + &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, // 62 + &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, + &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, // 63 + &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, + + &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, // 64 + &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, + &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, // 65 + &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, + &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, // 66 + &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, + &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, // 67 + &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, + + &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, // 68 + &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, + &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, // 69 + &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, + &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, // 6a + &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, + &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, // 6b + &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, + + &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, // 6c + &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, + &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, // 6d + &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, + &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, // 6e + &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, + &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, // 6f + &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, &dsp32c_device::load24, + + &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, // 70 + &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, + &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, // 71 + &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, + &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, // 72 + &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, + &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, // 73 + &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, + + &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, // 74 + &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, + &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, // 75 + &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, + &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, // 76 + &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, + &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, // 77 + &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, + + &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, // 78 + &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, + &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, // 79 + &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, + &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, // 7a + &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, + &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, // 7b + &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, + + &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, // 7c + &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, + &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, // 7d + &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, + &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, // 7e + &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, + &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, // 7f + &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24, &dsp32c_device::call24 +}; + + +/* + + Most common OPs in Race Drivin': + +301681217 - op 0 - nop +164890391 - op 4A1 - adde_si +99210113 - op 661 - load24 +86010010 - op F7 - load_er +61148739 - op 4D4 - sube_di +52693763 - op 180 - d1_0px +41525754 - op FF - store_er +35033321 - op 380 - d3_aMpp +31621151 - op 4C0 - adde_ss +28076244 - op 660 - load24 +19190505 - op 4C1 - mul2e_s +13270852 - op F5 - load_r +12535169 - op 1A4 - d1_1pm +12265141 - op 4C4 - sube_ss +10748211 - op 4CD - div2e_s +10493660 - op FD - store_r + 9721263 - op 189 + 9415685 - op 3C8 + 9294148 - op 3D5 + 8887846 - op 1A1 + 8788648 - op 381 + 8185239 - op 300 + 7241256 - op 383 + 6877349 - op 4A3 + 6832295 - op 181 + 6601270 - op 3E8 + 6562483 - op 4A4 + 6553514 - op 3C9 + 6270430 - op 280 + 6041485 - op 1A0 + 5299529 - op 304 + 5110926 - op 382 + 4922253 - op 363 + 4603670 - op 4D7 + 4164327 - op 4AE + 3980085 - op 3EC + 3599198 - op 3CC + 3543878 - op 3D0 + 3489158 - op 4 + 3463235 - op 321 + 3335995 - op 3F9 + 3001546 - op 4CE + 2882940 - op 129 + 2882940 - op 1A5 + 2882940 - op 342 + 2841981 - op 360 + 2663417 - op FB + 2059640 - op 3ED + 1867166 - op 1A8 + 1830789 - op 305 + 1753312 - op 301 + 1726866 - op 5 + 1594991 - op 12 + 1571286 - op 19 + 1507644 - op A2 + 1418846 - op 3CD + 1273134 - op F3 + 1177914 - op 4C7 + 1175720 - op 188 + 1091848 - op 3E9 + 1088206 - op 6FF + 1088204 - op 4CA + 1012639 - op 101 + 939617 - op 4C5 + +*/ diff --git a/src/devices/cpu/dsp56k/dsp56def.h b/src/devices/cpu/dsp56k/dsp56def.h new file mode 100644 index 00000000000..14fe208dbb8 --- /dev/null +++ b/src/devices/cpu/dsp56k/dsp56def.h @@ -0,0 +1,56 @@ +// license:BSD-3-Clause +// copyright-holders:Andrew Gardner +/////////////////////////////////////////// +// All the macros that are fit to print. // +/////////////////////////////////////////// + +#ifndef __DSP56_DEF_H__ +#define __DSP56_DEF_H__ + +#include "dsp56k.h" + +namespace DSP56K +{ +/*************************************************************************** + ALU +***************************************************************************/ +#define X cpustate->ALU.x.d +#define X1 cpustate->ALU.x.w.h +#define X0 cpustate->ALU.x.w.l +#define Y cpustate->ALU.y.d +#define Y1 cpustate->ALU.y.w.h +#define Y0 cpustate->ALU.y.w.l + +#define A cpustate->ALU.a.q +#define A2 cpustate->ALU.a.b.h4 +#define A1 cpustate->ALU.a.w.h +#define A0 cpustate->ALU.a.w.l +#define B cpustate->ALU.b.q +#define B2 cpustate->ALU.b.b.h4 +#define B1 cpustate->ALU.b.w.h +#define B0 cpustate->ALU.b.w.l + + +/*************************************************************************** + AGU +***************************************************************************/ +#define R0 cpustate->AGU.r0 +#define R1 cpustate->AGU.r1 +#define R2 cpustate->AGU.r2 +#define R3 cpustate->AGU.r3 + +#define N0 cpustate->AGU.n0 +#define N1 cpustate->AGU.n1 +#define N2 cpustate->AGU.n2 +#define N3 cpustate->AGU.n3 + +#define M0 cpustate->AGU.m0 +#define M1 cpustate->AGU.m1 +#define M2 cpustate->AGU.m2 +#define M3 cpustate->AGU.m3 + +#define TEMP cpustate->AGU.temp + +} // namespace DSP56K + +#endif diff --git a/src/devices/cpu/dsp56k/dsp56dsm.c b/src/devices/cpu/dsp56k/dsp56dsm.c new file mode 100644 index 00000000000..283f712ecda --- /dev/null +++ b/src/devices/cpu/dsp56k/dsp56dsm.c @@ -0,0 +1,30 @@ +// license:BSD-3-Clause +// copyright-holders:Andrew Gardner +/*************************************************************************** + + dsp56dsm.c + Disassembler for the portable Motorola/Freescale dsp56k emulator. + Written by Andrew Gardner + +***************************************************************************/ + +#include "opcode.h" + +#include "emu.h" +#include "dsp56k.h" + +/*****************************/ +/* Main disassembly function */ +/*****************************/ +CPU_DISASSEMBLE( dsp56k ) +{ + const UINT16 w0 = oprom[0] | (oprom[1] << 8); + const UINT16 w1 = oprom[2] | (oprom[3] << 8); + + // Decode and disassemble. + DSP56K::Opcode op(w0, w1); + sprintf(buffer, "%s", op.disassemble().c_str()); + + const unsigned size = op.size(); + return (size | DASMFLAG_SUPPORTED); +} diff --git a/src/devices/cpu/dsp56k/dsp56k.c b/src/devices/cpu/dsp56k/dsp56k.c new file mode 100644 index 00000000000..9e151019c7e --- /dev/null +++ b/src/devices/cpu/dsp56k/dsp56k.c @@ -0,0 +1,499 @@ +// license:BSD-3-Clause +// copyright-holders:Andrew Gardner +/*************************************************************************** + + dsp56k.c + Core implementation for the portable DSP56k emulator. + Written by Andrew Gardner + +**************************************************************************** + + Note: + This CPU emulator is very much a work-in-progress. + + DONE: + 1: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, + 11, , , , , , ,18, , , + + TODO: + X 1-6 Explore CORE naming scheme. + - 1-9 paragraph 1 : memory access timings + - 1-9 Data ALU arithmetic operations generally use fractional two's complement arithmetic + (Unsigned numbers are only supported by the multiply and multiply-accumulate instruction) + - 1-9 For fractional arithmetic, the 31-bit product is added to the 40-bit contents of A or B. No pipeline! + - 1-10 Two types of rounding: convergent rounding and two's complement rounding. See status register bit R. + - 1-10 Logic unit is 16-bits wide and works on MSP portion of accum register + - 1-10 The AGU can implement three types of arithmetic: linear, modulo, and reverse carry. + - 1-12 "Two external interrupt pins!!!" + - 1-12 Take care of all interrupt priority (IPR) stuff! + - 1-19 Memory WAIT states + - 1-20 The timer's interesting! + - 1-21 Vectored exception requests on the Host Interface! +***************************************************************************/ + +#include "opcode.h" + +#include "emu.h" +#include "debugger.h" +#include "dsp56k.h" + +#include "dsp56def.h" + +using namespace DSP56K; + +/*************************************************************************** + COMPONENT FUNCTIONALITY +***************************************************************************/ +/* 1-9 ALU */ +// #include "dsp56alu.h" + +/* 1-10 Address Generation Unit (AGU) */ +// #include "dsp56agu.h" + +/* 1-11 Program Control Unit (PCU) */ +#include "dsp56pcu.h" + +/* 5-1 Host Interface (HI) */ +//#include "dsp56hi.h" + +/* 4-8 Memory handlers for on-chip peripheral memory. */ +#include "dsp56mem.h" + + +enum +{ + // PCU + DSP56K_PC=1, + DSP56K_SR, + DSP56K_LC, + DSP56K_LA, + DSP56K_SP, + DSP56K_OMR, + + // ALU + DSP56K_X, DSP56K_Y, + DSP56K_A, DSP56K_B, + + // AGU + DSP56K_R0,DSP56K_R1,DSP56K_R2,DSP56K_R3, + DSP56K_N0,DSP56K_N1,DSP56K_N2,DSP56K_N3, + DSP56K_M0,DSP56K_M1,DSP56K_M2,DSP56K_M3, + DSP56K_TEMP, + DSP56K_STATUS, + + // CPU STACK + DSP56K_ST0, + DSP56K_ST1, + DSP56K_ST2, + DSP56K_ST3, + DSP56K_ST4, + DSP56K_ST5, + DSP56K_ST6, + DSP56K_ST7, + DSP56K_ST8, + DSP56K_ST9, + DSP56K_ST10, + DSP56K_ST11, + DSP56K_ST12, + DSP56K_ST13, + DSP56K_ST14, + DSP56K_ST15 +}; + + +const device_type DSP56156 = &device_creator; + + +/**************************************************************************** + * Internal Memory Maps + ****************************************************************************/ +static ADDRESS_MAP_START( dsp56156_program_map, AS_PROGRAM, 16, dsp56k_device ) + AM_RANGE(0x0000,0x07ff) AM_RAM AM_SHARE("dsk56k_program_ram") /* 1-5 */ +// AM_RANGE(0x2f00,0x2fff) AM_ROM /* 1-5 PROM reserved memory. Is this the right spot for it? */ +ADDRESS_MAP_END + +static ADDRESS_MAP_START( dsp56156_x_data_map, AS_DATA, 16, dsp56k_device ) + AM_RANGE(0x0000,0x07ff) AM_RAM /* 1-5 */ + AM_RANGE(0xffc0,0xffff) AM_READWRITE(peripheral_register_r, peripheral_register_w) /* 1-5 On-chip peripheral registers memory mapped in data space */ +ADDRESS_MAP_END + + +dsp56k_device::dsp56k_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : cpu_device(mconfig, DSP56156, "DSP56156", tag, owner, clock, "dsp56156", __FILE__) + , m_program_config("program", ENDIANNESS_LITTLE, 16, 16, -1, ADDRESS_MAP_NAME(dsp56156_program_map)) + , m_data_config("data", ENDIANNESS_LITTLE, 16, 16, -1, ADDRESS_MAP_NAME(dsp56156_x_data_map)) + , m_program_ram(*this, "dsk56k_program_ram") +{ +} + +/*************************************************************************** + MEMORY ACCESSORS +***************************************************************************/ +#define ROPCODE(pc) cpustate->direct->read_word(pc) + + +/*************************************************************************** + IRQ HANDLING +***************************************************************************/ +void dsp56k_device::execute_set_input(int irqline, int state) +{ + //logerror("DSP56k set irq line %d %d\n", irqline, state); + + switch(irqline) + { + case DSP56K_IRQ_MODA: + // TODO: 1-12 Get this triggering right + if (irqa_trigger(&m_dsp56k_core)) + logerror("DSP56k IRQA is set to fire on the \"Negative Edge\".\n"); + + if (state != CLEAR_LINE) + m_dsp56k_core.modA_state = TRUE; + else + m_dsp56k_core.modA_state = FALSE; + + if (m_dsp56k_core.reset_state != TRUE) + dsp56k_add_pending_interrupt(&m_dsp56k_core, "IRQA"); + break; + + case DSP56K_IRQ_MODB: + // TODO: 1-12 Get this triggering right + if (irqb_trigger(&m_dsp56k_core)) + logerror("DSP56k IRQB is set to fire on the \"Negative Edge\".\n"); + + if (state != CLEAR_LINE) + m_dsp56k_core.modB_state = TRUE; + else + m_dsp56k_core.modB_state = FALSE; + + if (m_dsp56k_core.reset_state != TRUE) + dsp56k_add_pending_interrupt(&m_dsp56k_core, "IRQB"); + break; + + case DSP56K_IRQ_MODC: + if (state != CLEAR_LINE) + m_dsp56k_core.modC_state = TRUE; + else + m_dsp56k_core.modC_state = FALSE; + + // TODO : Set bus mode or whatever + break; + + case DSP56K_IRQ_RESET: + if (state != CLEAR_LINE) + m_dsp56k_core.reset_state = TRUE; + else + { + /* If it changes state from asserted to cleared. Call the reset function. */ + if (m_dsp56k_core.reset_state == TRUE) + device_reset(); + + m_dsp56k_core.reset_state = FALSE; + } + + // dsp56k_add_pending_interrupt("Hardware RESET"); + break; + + default: + logerror("DSP56k setting some weird irq line : %d", irqline); + break; + } + + /* If the reset line isn't asserted, service interrupts */ + // TODO: Is it right to immediately service interrupts? + //if (cpustate->reset_state != TRUE) + // pcu_service_interrupts(); +} + + +/*************************************************************************** + INITIALIZATION AND SHUTDOWN +***************************************************************************/ +void dsp56k_device::agu_init() +{ + /* save states - dsp56k_agu members */ + save_item(NAME(m_dsp56k_core.AGU.r0)); + save_item(NAME(m_dsp56k_core.AGU.r1)); + save_item(NAME(m_dsp56k_core.AGU.r2)); + save_item(NAME(m_dsp56k_core.AGU.r3)); + save_item(NAME(m_dsp56k_core.AGU.n0)); + save_item(NAME(m_dsp56k_core.AGU.n1)); + save_item(NAME(m_dsp56k_core.AGU.n2)); + save_item(NAME(m_dsp56k_core.AGU.n3)); + save_item(NAME(m_dsp56k_core.AGU.m0)); + save_item(NAME(m_dsp56k_core.AGU.m1)); + save_item(NAME(m_dsp56k_core.AGU.m2)); + save_item(NAME(m_dsp56k_core.AGU.m3)); + save_item(NAME(m_dsp56k_core.AGU.temp)); +} + +void dsp56k_device::alu_init() +{ + /* save states - dsp56k_alu members */ + save_item(NAME(m_dsp56k_core.ALU.x)); + save_item(NAME(m_dsp56k_core.ALU.y)); + save_item(NAME(m_dsp56k_core.ALU.a)); + save_item(NAME(m_dsp56k_core.ALU.b)); +} + +void dsp56k_device::device_start() +{ + memset(&m_dsp56k_core, 0, sizeof(m_dsp56k_core)); + + m_dsp56k_core.device = this; + m_dsp56k_core.program_ram = m_program_ram; + + /* Call specific module inits */ + pcu_init(&m_dsp56k_core, this); + agu_init(); + alu_init(); + + /* HACK - You're not in bootstrap mode upon bootup */ + m_dsp56k_core.bootstrap_mode = BOOTSTRAP_OFF; + + /* Clear the irq states */ + m_dsp56k_core.modA_state = FALSE; + m_dsp56k_core.modB_state = FALSE; + m_dsp56k_core.modC_state = FALSE; + m_dsp56k_core.reset_state = FALSE; + + /* save states - dsp56k_core members */ + save_item(NAME(m_dsp56k_core.modA_state)); + save_item(NAME(m_dsp56k_core.modB_state)); + save_item(NAME(m_dsp56k_core.modC_state)); + save_item(NAME(m_dsp56k_core.reset_state)); + save_item(NAME(m_dsp56k_core.bootstrap_mode)); + save_item(NAME(m_dsp56k_core.repFlag)); + save_item(NAME(m_dsp56k_core.repAddr)); + save_item(NAME(m_dsp56k_core.ppc)); + save_item(NAME(m_dsp56k_core.op)); + save_item(NAME(m_dsp56k_core.interrupt_cycles)); + + /* save states - dsp56k_host_interface members */ + save_item(NAME(m_dsp56k_core.HI.icr)); + save_item(NAME(m_dsp56k_core.HI.cvr)); + save_item(NAME(m_dsp56k_core.HI.isr)); + save_item(NAME(m_dsp56k_core.HI.ivr)); + save_item(NAME(m_dsp56k_core.HI.trxh)); + save_item(NAME(m_dsp56k_core.HI.trxl)); + save_item(NAME(m_dsp56k_core.HI.bootstrap_offset)); + + save_item(NAME(m_dsp56k_core.peripheral_ram)); + + m_dsp56k_core.program = &space(AS_PROGRAM); + m_dsp56k_core.direct = &m_dsp56k_core.program->direct(); + m_dsp56k_core.data = &space(AS_DATA); + + state_add(DSP56K_PC, "PC", m_dsp56k_core.PCU.pc).formatstr("%04X"); + state_add(DSP56K_SR, "SR", m_dsp56k_core.PCU.sr).formatstr("%04X"); + state_add(DSP56K_LC, "LC", m_dsp56k_core.PCU.lc).formatstr("%04X"); + state_add(DSP56K_LA, "LA", m_dsp56k_core.PCU.la).formatstr("%04X"); + state_add(DSP56K_SP, "SP", m_dsp56k_core.PCU.sp).formatstr("%02X"); + state_add(DSP56K_OMR, "OMR", m_dsp56k_core.PCU.omr).formatstr("%02X"); + + state_add(DSP56K_X, "X", m_dsp56k_core.ALU.x.d).mask(0xffffffff).formatstr("%9s"); + state_add(DSP56K_Y, "Y", m_dsp56k_core.ALU.y.d).mask(0xffffffff).formatstr("%9s"); + + state_add(DSP56K_A, "A", m_dsp56k_core.ALU.a.q).mask((UINT64)U64(0xffffffffffffffff)).formatstr("%12s"); /* could benefit from a better mask? */ + state_add(DSP56K_B, "B", m_dsp56k_core.ALU.b.q).mask((UINT64)U64(0xffffffffffffffff)).formatstr("%12s"); /* could benefit from a better mask? */ + + state_add(DSP56K_R0, "R0", m_dsp56k_core.AGU.r0).formatstr("%04X"); + state_add(DSP56K_R1, "R1", m_dsp56k_core.AGU.r1).formatstr("%04X"); + state_add(DSP56K_R2, "R2", m_dsp56k_core.AGU.r2).formatstr("%04X"); + state_add(DSP56K_R3, "R3", m_dsp56k_core.AGU.r3).formatstr("%04X"); + + state_add(DSP56K_N0, "N0", m_dsp56k_core.AGU.n0).formatstr("%04X"); + state_add(DSP56K_N1, "N1", m_dsp56k_core.AGU.n1).formatstr("%04X"); + state_add(DSP56K_N2, "N2", m_dsp56k_core.AGU.n2).formatstr("%04X"); + state_add(DSP56K_N3, "N3", m_dsp56k_core.AGU.n3).formatstr("%04X"); + + state_add(DSP56K_M0, "M0", m_dsp56k_core.AGU.m0).formatstr("%04X"); + state_add(DSP56K_M1, "M1", m_dsp56k_core.AGU.m1).formatstr("%04X"); + state_add(DSP56K_M2, "M2", m_dsp56k_core.AGU.m2).formatstr("%04X"); + state_add(DSP56K_M3, "M3", m_dsp56k_core.AGU.m3).formatstr("%04X"); + + state_add(DSP56K_TEMP, "TMP", m_dsp56k_core.AGU.temp).formatstr("%04X").noshow(); + //state_add(DSP56K_STATUS, "STS", STATUS).formatstr("%02X"); + + state_add(DSP56K_ST0, "ST0", m_dsp56k_core.PCU.ss[0].d).formatstr("%08X"); + state_add(DSP56K_ST1, "ST1", m_dsp56k_core.PCU.ss[1].d).formatstr("%08X"); + state_add(DSP56K_ST2, "ST2", m_dsp56k_core.PCU.ss[2].d).formatstr("%08X"); + state_add(DSP56K_ST3, "ST3", m_dsp56k_core.PCU.ss[3].d).formatstr("%08X"); + state_add(DSP56K_ST4, "ST4", m_dsp56k_core.PCU.ss[4].d).formatstr("%08X"); + state_add(DSP56K_ST5, "ST5", m_dsp56k_core.PCU.ss[5].d).formatstr("%08X"); + state_add(DSP56K_ST6, "ST6", m_dsp56k_core.PCU.ss[6].d).formatstr("%08X"); + state_add(DSP56K_ST7, "ST7", m_dsp56k_core.PCU.ss[7].d).formatstr("%08X"); + state_add(DSP56K_ST8, "ST8", m_dsp56k_core.PCU.ss[8].d).formatstr("%08X"); + state_add(DSP56K_ST9, "ST9", m_dsp56k_core.PCU.ss[9].d).formatstr("%08X"); + state_add(DSP56K_ST10, "ST10", m_dsp56k_core.PCU.ss[10].d).formatstr("%08X"); + state_add(DSP56K_ST11, "ST11", m_dsp56k_core.PCU.ss[11].d).formatstr("%08X"); + state_add(DSP56K_ST12, "ST12", m_dsp56k_core.PCU.ss[12].d).formatstr("%08X"); + state_add(DSP56K_ST13, "ST13", m_dsp56k_core.PCU.ss[13].d).formatstr("%08X"); + state_add(DSP56K_ST14, "ST14", m_dsp56k_core.PCU.ss[14].d).formatstr("%08X"); + state_add(DSP56K_ST15, "ST15", m_dsp56k_core.PCU.ss[15].d).formatstr("%08X"); + + state_add(STATE_GENPC, "GENPC", m_dsp56k_core.PCU.pc).noshow(); + state_add(STATE_GENSP, "GENSP", m_dsp56k_core.PCU.sp).noshow(); + state_add(STATE_GENPCBASE, "GENPCBASE", m_dsp56k_core.ppc).noshow(); + state_add(STATE_GENFLAGS, "GENFLAGS", m_dsp56k_core.PCU.sr).formatstr("%14s").noshow(); + + m_icountptr = &m_dsp56k_core.icount; +} + + +void dsp56k_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + dsp56k_core *cpustate = &m_dsp56k_core; + + switch (entry.index()) + { + case STATE_GENFLAGS: + strprintf(str, "%s%s %s%s%s%s%s%s%s%s %s%s", + /* Status Register */ + LF_bit(cpustate) ? "L" : ".", + FV_bit(cpustate) ? "F" : ".", + + S_bit(cpustate) ? "S" : ".", + L_bit(cpustate) ? "L" : ".", + E_bit(cpustate) ? "E" : ".", + U_bit(cpustate) ? "U" : ".", + N_bit(cpustate) ? "N" : ".", + Z_bit(cpustate) ? "Z" : ".", + V_bit(cpustate) ? "V" : ".", + C_bit(cpustate) ? "C" : ".", + + /* Stack Pointer */ + UF_bit(cpustate) ? "U" : ".", + SE_bit(cpustate) ? "S" : "."); + break; + + case DSP56K_X: + strprintf(str, "%04x %04x", X1, X0); + break; + + case DSP56K_Y: + strprintf(str, "%04x %04x", Y1, Y0); + break; + + case DSP56K_A: + strprintf(str, "%02x %04x %04x", A2, A1, A0); + break; + + case DSP56K_B: + strprintf(str, "%02x %04x %04x", B2, B1, B0); + break; + } +} + +/*************************************************************************** + RESET BEHAVIOR +***************************************************************************/ +static void agu_reset(dsp56k_core* cpustate) +{ + /* FM.4-3 */ + R0 = 0x0000; + R1 = 0x0000; + R2 = 0x0000; + R3 = 0x0000; + + N0 = 0x0000; + N1 = 0x0000; + N2 = 0x0000; + N3 = 0x0000; + + M0 = 0xffff; + M1 = 0xffff; + M2 = 0xffff; + M3 = 0xffff; + + TEMP = 0x0000; +} + +static void alu_reset(dsp56k_core* cpustate) +{ + X = 0x00000000; + Y = 0x00000000; + A = 0x0000000000; + B = 0x0000000000; +} + +void dsp56k_device::device_reset() +{ + logerror("Dsp56k reset\n"); + + m_dsp56k_core.interrupt_cycles = 0; + m_dsp56k_core.ppc = 0x0000; + + m_dsp56k_core.repFlag = 0; + m_dsp56k_core.repAddr = 0x0000; + + pcu_reset(&m_dsp56k_core); + mem_reset(&m_dsp56k_core); + agu_reset(&m_dsp56k_core); + alu_reset(&m_dsp56k_core); + + /* HACK - Put a jump to 0x0000 at 0x0000 - this keeps the CPU locked to the instruction at address 0x0000 */ + m_dsp56k_core.program->write_word(0x0000, 0x0124); +} + + + +/*************************************************************************** + CORE INCLUDE +***************************************************************************/ +#include "dsp56ops.inc" + + +/*************************************************************************** + CORE EXECUTION LOOP +***************************************************************************/ +// Execute a single opcode and return how many cycles it took. +static size_t execute_one_new(dsp56k_core* cpustate) +{ + // For MAME + cpustate->op = ROPCODE(ADDRESS(PC)); + debugger_instruction_hook(cpustate->device, PC); + + UINT16 w0 = ROPCODE(ADDRESS(PC)); + UINT16 w1 = ROPCODE(ADDRESS(PC) + ADDRESS(1)); + + Opcode op(w0, w1); + op.evaluate(cpustate); + PC += op.evalSize(); // Special size function needed to handle jmps, etc. + + // TODO: Currently all operations take up 4 cycles (inst->cycles()). + return 4; +} + +void dsp56k_device::execute_run() +{ + /* If reset line is asserted, do nothing */ + if (m_dsp56k_core.reset_state) + { + m_dsp56k_core.icount = 0; + return; + } + + /* HACK - if you're in bootstrap mode, simply pretend you ate up all your cycles waiting for data. */ + if (m_dsp56k_core.bootstrap_mode != BOOTSTRAP_OFF) + { + m_dsp56k_core.icount = 0; + return; + } + + //m_dsp56k_core.icount -= m_dsp56k_core.interrupt_cycles; + //m_dsp56k_core.interrupt_cycles = 0; + + while(m_dsp56k_core.icount > 0) + { + execute_one(&m_dsp56k_core); + if (0) m_dsp56k_core.icount -= execute_one_new(&m_dsp56k_core); + pcu_service_interrupts(&m_dsp56k_core); // TODO: Is it incorrect to service after each instruction? + } +} + + +offs_t dsp56k_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( dsp56k ); + return CPU_DISASSEMBLE_NAME(dsp56k)(this, buffer, pc, oprom, opram, options); +} diff --git a/src/devices/cpu/dsp56k/dsp56k.h b/src/devices/cpu/dsp56k/dsp56k.h new file mode 100644 index 00000000000..fc461dbcb16 --- /dev/null +++ b/src/devices/cpu/dsp56k/dsp56k.h @@ -0,0 +1,259 @@ +// license:BSD-3-Clause +// copyright-holders:Andrew Gardner +/*************************************************************************** + + dsp56k.h + Interface file for the portable Motorola/Freescale DSP56k emulator. + Written by Andrew Gardner + +***************************************************************************/ + + +#pragma once + +#ifndef __DSP56K_H__ +#define __DSP56K_H__ + +#include "emu.h" + + +// IRQ Lines +// MODA and MODB are also known as IRQA and IRQB +#define DSP56K_IRQ_MODA 0 +#define DSP56K_IRQ_MODB 1 +#define DSP56K_IRQ_MODC 2 +#define DSP56K_IRQ_RESET 3 /* Is this needed? */ + + +/*************************************************************************** + STRUCTURES & TYPEDEFS +***************************************************************************/ +// 5-4 Host Interface +struct dsp56k_host_interface +{ + // **** Dsp56k side **** // + // Host Control Register + UINT16* hcr; + + // Host Status Register + UINT16* hsr; + + // Host Transmit/Receive Data + UINT16* htrx; + + // **** Host CPU side **** // + // Interrupt Control Register + UINT8 icr; + + // Command Vector Register + UINT8 cvr; + + // Interrupt Status Register + UINT8 isr; + + // Interrupt Vector Register + UINT8 ivr; + + // Transmit / Receive Registers + UINT8 trxh; + UINT8 trxl; + + // HACK - Host interface bootstrap write offset + UINT16 bootstrap_offset; + +}; + +// 1-9 ALU +struct dsp56k_data_alu +{ + // Four 16-bit input registers (can be accessed as 2 32-bit registers) + PAIR x; + PAIR y; + + // Two 32-bit accumulator registers + 8-bit accumulator extension registers + PAIR64 a; + PAIR64 b; + + // An accumulation shifter + // One data bus shifter/limiter + // A parallel, single cycle, non-pipelined Multiply-Accumulator (MAC) unit + // Basics +}; + +// 1-10 Address Generation Unit (AGU) +struct dsp56k_agu +{ + // Four address registers + UINT16 r0; + UINT16 r1; + UINT16 r2; + UINT16 r3; + + // Four offset registers + UINT16 n0; + UINT16 n1; + UINT16 n2; + UINT16 n3; + + // Four modifier registers + UINT16 m0; + UINT16 m1; + UINT16 m2; + UINT16 m3; + + // Used in loop processing + UINT16 temp; + + // FM.4-5 - hmmm? + // UINT8 status; + + // Basics +}; + +// 1-11 Program Control Unit (PCU) +struct dsp56k_pcu +{ + // Program Counter + UINT16 pc; + + // Loop Address + UINT16 la; + + // Loop Counter + UINT16 lc; + + // Status Register + UINT16 sr; + + // Operating Mode Register + UINT16 omr; + + // Stack Pointer + UINT16 sp; + + // Stack (TODO: 15-level?) + PAIR ss[16]; + + // Controls IRQ processing + void (*service_interrupts)(void); + + // A list of pending interrupts (indices into dsp56k_interrupt_sources array) + INT8 pending_interrupts[32]; + + // Basics + + // Other PCU internals + UINT16 reset_vector; + +}; + +// 1-8 The dsp56156 CORE +struct dsp56k_core +{ + // PROGRAM CONTROLLER + dsp56k_pcu PCU; + + // ADR ALU (AGU) + dsp56k_agu AGU; + + // CLOCK GEN + //static emu_timer *dsp56k_timer; // 1-5, 1-8 - Clock gen + + // DATA ALU + dsp56k_data_alu ALU; + + // OnCE + + // IBS and BITFIELD UNIT + + // Host Interface + dsp56k_host_interface HI; + + // IRQ line states + UINT8 modA_state; + UINT8 modB_state; + UINT8 modC_state; + UINT8 reset_state; + + // HACK - Bootstrap mode state variable. + UINT8 bootstrap_mode; + + UINT8 repFlag; // Knowing if we're in a 'repeat' state (dunno how the processor does this) + UINT32 repAddr; // The address of the instruction to repeat... + + + /* MAME internal stuff */ + int icount; + + UINT32 ppc; + UINT32 op; + int interrupt_cycles; + void (*output_pins_changed)(UINT32 pins); + cpu_device *device; + address_space *program; + direct_read_data *direct; + address_space *data; + + UINT16 peripheral_ram[0x40]; + UINT16 *program_ram; +}; + + +class dsp56k_device : public cpu_device +{ +public: + dsp56k_device(const machine_config &mconfig, const char *_tag, device_t *_owner, UINT32 _clock); + + DECLARE_READ16_MEMBER( program_r ); + DECLARE_WRITE16_MEMBER( program_w ); + DECLARE_READ16_MEMBER( peripheral_register_r ); + DECLARE_WRITE16_MEMBER( peripheral_register_w ); + + void host_interface_write(UINT8 offset, UINT8 data); + UINT8 host_interface_read(UINT8 offset); + + UINT16 get_peripheral_memory(UINT16 addr); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_execute_interface overrides + virtual UINT64 execute_clocks_to_cycles(UINT64 clocks) const { return (clocks + 2 - 1) / 2; } + virtual UINT64 execute_cycles_to_clocks(UINT64 cycles) const { return (cycles * 2); } + virtual UINT32 execute_min_cycles() const { return 1; } + virtual UINT32 execute_max_cycles() const { return 8; } + virtual UINT32 execute_input_lines() const { return 4; } + virtual UINT32 execute_default_irq_vector() const { return 0; } + virtual void execute_run(); + virtual void execute_set_input(int inputnum, int state); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const { return (spacenum == AS_PROGRAM) ? &m_program_config : ((spacenum == AS_DATA) ? &m_data_config : NULL ); } + + // device_state_interface overrides + void state_string_export(const device_state_entry &entry, std::string &str); + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const { return 2; } + virtual UINT32 disasm_max_opcode_bytes() const { return 4; } + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + +private: + address_space_config m_program_config; + address_space_config m_data_config; + required_shared_ptr m_program_ram; + + dsp56k_core m_dsp56k_core; + + void agu_init(); + void alu_init(); + +}; + + +extern const device_type DSP56156; + + +#endif /* __DSP56K_H__ */ diff --git a/src/devices/cpu/dsp56k/dsp56mem.c b/src/devices/cpu/dsp56k/dsp56mem.c new file mode 100644 index 00000000000..6ec2251df64 --- /dev/null +++ b/src/devices/cpu/dsp56k/dsp56mem.c @@ -0,0 +1,948 @@ +// license:BSD-3-Clause +// copyright-holders:Andrew Gardner +// This file contains functions which handle the On-Chip peripheral Memory Map +// as well as the Host Interface and the SSI0/SSI1 Serial Interfaces. + +#include "dsp56mem.h" +#include "dsp56pcu.h" + +namespace DSP56K +{ +/* IPR Accessor Implementations */ +void IPR_set(dsp56k_core* cpustate, UINT16 value) +{ + /* TODO: Is there anything else? */ + IPR = value; +} + +INT8 irqa_ipl(dsp56k_core* cpustate) { return ((IPR & 0x0003) >> 0) - 1; } +UINT8 irqa_trigger(dsp56k_core* cpustate){ return (IPR & 0x0004) >> 2; } +INT8 irqb_ipl(dsp56k_core* cpustate) { return ((IPR & 0x0018) >> 3) - 1; } +UINT8 irqb_trigger(dsp56k_core* cpustate){ return (IPR & 0x0002) >> 5; } +INT8 codec_ipl(dsp56k_core* cpustate) { return ((IPR & 0x00c0) >> 6) - 1; } +INT8 host_ipl(dsp56k_core* cpustate) { return ((IPR & 0x0300) >> 8) - 1; } +INT8 ssi0_ipl(dsp56k_core* cpustate) { return ((IPR & 0x0c00) >> 10) - 1; } +INT8 ssi1_ipl(dsp56k_core* cpustate) { return ((IPR & 0x3000) >> 12) - 1; } +INT8 tm_ipl(dsp56k_core* cpustate) { return ((IPR & 0xc000) >> 14) - 1; } + +void mem_reset(dsp56k_core* cpustate) +{ + // Reset the HI registers + dsp56k_host_interface_reset(cpustate); + + // Reset the IO registers + dsp56k_io_reset(cpustate); +} + + +/*************************************************************************** + HOST INTERFACE +***************************************************************************/ +/***************/ +/* DSP56k SIDE */ +/***************/ +/************************************/ +/* Host Control Register (HCR) Bits */ +/************************************/ +void HCR_set(dsp56k_core* cpustate, UINT16 value) +{ + HF3_bit_set (cpustate, (value & 0x0010) >> 4); + HF2_bit_set (cpustate, (value & 0x0008) >> 3); + HCIE_bit_set(cpustate, (value & 0x0004) >> 2); + HTIE_bit_set(cpustate, (value & 0x0002) >> 1); + HRIE_bit_set(cpustate, (value & 0x0001) >> 0); +} +//UINT16 HF3_bit(dsp56k_core* cpustate) { return ((HCR & 0x0010) != 0); } +//UINT16 HF2_bit(dsp56k_core* cpustate) { return ((HCR & 0x0008) != 0); } +UINT16 HCIE_bit(dsp56k_core* cpustate) { return ((HCR & 0x0004) != 0); } +UINT16 HTIE_bit(dsp56k_core* cpustate) { return ((HCR & 0x0002) != 0); } +UINT16 HRIE_bit(dsp56k_core* cpustate) { return ((HCR & 0x0001) != 0); } + +void HF3_bit_set(dsp56k_core* cpustate, UINT16 value) +{ + value = value & 0x01; + HCR &= ~(0x0010); + HCR |= (value << 4); + + HF3_bit_host_set(cpustate, value); +} +void HF2_bit_set(dsp56k_core* cpustate, UINT16 value) +{ + value = value & 0x01; + HCR &= ~(0x0008); + HCR |= (value << 3); + + HF2_bit_host_set(cpustate, value); +} +void HCIE_bit_set(dsp56k_core* cpustate, UINT16 value) +{ + value = value & 0x01; + HCR &= ~(0x0004); + HCR |= (value << 2); +} +void HTIE_bit_set(dsp56k_core* cpustate, UINT16 value) +{ + value = value & 0x01; + HCR &= ~(0x0002); + HCR |= (value << 1); +} +void HRIE_bit_set(dsp56k_core* cpustate, UINT16 value) +{ + value = value & 0x01; + HCR &= ~(0x0001); + HCR |= (value << 0); +} + +/***********************************/ +/* Host Status Register (HSR) Bits */ +/***********************************/ +//UINT16 DMA_bit(dsp56k_core* cpustate) { return ((HSR & 0x0080) != 0); } +//UINT16 HF1_bit(dsp56k_core* cpustate) { return ((HSR & 0x0010) != 0); } +//UINT16 HF0_bit(dsp56k_core* cpustate) { return ((HSR & 0x0008) != 0); } +//UINT16 HCP_bit(dsp56k_core* cpustate) { return ((HSR & 0x0004) != 0); } +UINT16 HTDE_bit(dsp56k_core* cpustate) { return ((HSR & 0x0002) != 0); } +UINT16 HRDF_bit(dsp56k_core* cpustate) { return ((HSR & 0x0001) != 0); } + +void DMA_bit_set(dsp56k_core* cpustate, UINT16 value) +{ + value = value & 0x01; + HSR &= ~(0x0080); + HSR |= (value << 7); + // TODO: 5-12 When the DMA bit is set, the DMA mode is enabled by the Host Mode bits HM0 & HM1 +} +void HF1_bit_set(dsp56k_core* cpustate, UINT16 value) +{ + value = value & 0x01; + HSR &= ~(0x0010); + HSR |= (value << 4); +} +void HF0_bit_set(dsp56k_core* cpustate, UINT16 value) +{ + value = value & 0x01; + HSR &= ~(0x0008); + HSR |= (value << 3); +} +void HCP_bit_set(dsp56k_core* cpustate, UINT16 value) +{ + value = value & 0x01; + HSR &= ~(0x0004); + HSR |= (value << 2); + + if (value && HCIE_bit(cpustate)) + dsp56k_add_pending_interrupt(cpustate, "Host Command"); +} +void HTDE_bit_set(dsp56k_core* cpustate, UINT16 value) +{ + value = value & 0x01; + HSR &= ~(0x0002); + HSR |= (value << 1); + + // 5-10 If HTIE bit is set, whip out a Host Transmit Data interrupt + if (value && HTIE_bit(cpustate)) + dsp56k_add_pending_interrupt(cpustate, "Host Transmit Data"); + + // 5-5 If both me and RXDF are cleared, transmit data to the host + if (!value && !RXDF_bit(cpustate)) + dsp56k_host_interface_HTX_to_host(cpustate); +} +void HRDF_bit_set(dsp56k_core* cpustate, UINT16 value) +{ + value = value & 0x01; + HSR &= ~(0x0001); + HSR |= (value << 0); + + // 5-10 If HRIE is set, whip out a Host Receive Data interrupt + if (value && HRIE_bit(cpustate)) + dsp56k_add_pending_interrupt(cpustate, "Host Receive Data"); + + // 5-5 If both me and TXDE are cleared, transmit data to the dsp56k + if (!value && !TXDE_bit(cpustate)) + dsp56k_host_interface_host_to_HTX(cpustate); +} + + + +/*************/ +/* HOST SIDE */ +/*************/ +/*****************************************/ +/* Interrupt Control Register (ICR) Bits */ +/*****************************************/ +void ICR_set(dsp56k_core* cpustate, UINT8 value) +{ + HF1_bit_host_set(cpustate, (value & 0x10) >> 4); + HF0_bit_host_set(cpustate, (value & 0x08) >> 3); + TREQ_bit_set(cpustate, (value & 0x02) >> 1); + RREQ_bit_set(cpustate, (value & 0x01) >> 0); +} + +//UINT8 INIT_bit(dsp56k_core* cpustate); #define x_initBIT ((dsp56k.HI.ICR & 0x0080) != 0) +//UINT8 HM1_bit(dsp56k_core* cpustate); #define x_hm1BIT ((dsp56k.HI.ICR & 0x0040) != 0) +//UINT8 HM0_bit(dsp56k_core* cpustate); #define x_hm0BIT ((dsp56k.HI.ICR & 0x0020) != 0) +//UINT8 HF1_bit_host(dsp56k_core* cpustate); #define x_hf1BIT ((dsp56k.HI.ICR & 0x0010) != 0) +//UINT8 HF0_bit_host(dsp56k_core* cpustate); #define x_hf0BIT ((dsp56k.HI.ICR & 0x0008) != 0) +//UINT8 TREQ_bit(dsp56k_core* cpustate); #define x_treqBIT ((dsp56k.HI.ICR & 0x0002) != 0) +//UINT8 RREQ_bit(dsp56k_core* cpustate); #define x_rreqBIT ((dsp56k.HI.ICR & 0x0001) != 0) + +//void INIT_bit_set(dsp56k_core* cpustate, UINT8 value); #define CLEAR_x_initBIT() (dsp56k.HI.ICR &= (~0x0080)) +//void HM1_bit_set(dsp56k_core* cpustate, UINT8 value); #define CLEAR_x_hm1BIT() (dsp56k.HI.ICR &= (~0x0040)) +//void HM0_bit_set(dsp56k_core* cpustate, UINT8 value); #define CLEAR_x_hm0BIT() (dsp56k.HI.ICR &= (~0x0020)) +void HF1_bit_host_set(dsp56k_core* cpustate, UINT8 value) +{ + value = value & 0x01; + ICR &= ~(0x10); + ICR |= (value << 4); + + HF1_bit_set(cpustate, value); // 5-14 +} +void HF0_bit_host_set(dsp56k_core* cpustate, UINT8 value) +{ + value = value & 0x01; + ICR &= ~(0x08); + ICR |= (value << 3); + + HF0_bit_set(cpustate, value); // 5-13 +} +void TREQ_bit_set(dsp56k_core* cpustate, UINT8 value) +{ + value = value & 0x01; + ICR &= ~(0x02); + ICR |= (value << 1); +} +void RREQ_bit_set(dsp56k_core* cpustate, UINT8 value) +{ + value = value & 0x01; + ICR &= ~(0x01); + ICR |= (value << 0); + + // 5-12 + if (value) + { + // TODO : HREQ_assert(); + } +} + + + +/**************************************/ +/* Command Vector Register (CVR) Bits */ +/**************************************/ +UINT8 HV_bits(dsp56k_core* cpustate) { return (CVR & 0x1f); } + +void CVR_set(dsp56k_core* cpustate, UINT8 value) +{ + /* A single, unified place to run all callbacks for each of the bits */ + HC_bit_set(cpustate, (value & 0x80) >> 7); + HV_bits_set(cpustate, (value & 0x1f)); +} + +void HC_bit_set(dsp56k_core* cpustate, UINT8 value) +{ + value = value & 0x01; + CVR &= ~(0x80); + CVR |= (value << 7); + + HCP_bit_set(cpustate, value); // 5-9 & 5-11 +} +void HV_bits_set(dsp56k_core* cpustate, UINT8 value) +{ + value = value & 0x1f; + CVR &= ~(0x1f); + CVR |= (value << 0); +} + + +/****************************************/ +/* Interrupt Status Register (ISR) Bits */ +/****************************************/ +UINT8 TXDE_bit(dsp56k_core* cpustate) { return ((ISR & 0x0002) != 0); } +UINT8 RXDF_bit(dsp56k_core* cpustate) { return ((ISR & 0x0001) != 0); } + +void HF3_bit_host_set(dsp56k_core* cpustate, UINT8 value) +{ + value = value & 0x01; + ISR &= ~(0x0010); + ISR |= (value << 4); +} +void HF2_bit_host_set(dsp56k_core* cpustate, UINT8 value) +{ + value = value & 0x01; + ISR &= ~(0x0008); + ISR |= (value << 3); +} + +void TXDE_bit_set(dsp56k_core* cpustate, UINT8 value) +{ + value = value & 0x01; + ISR &= ~(0x0002); + ISR |= (value << 1); + + // If both me and the HRDF are cleared, transmit data to the dsp56k + if (!value && !HRDF_bit(cpustate)) + dsp56k_host_interface_host_to_HTX(cpustate); +} + +void RXDF_bit_set(dsp56k_core* cpustate, UINT8 value) +{ + value = value & 0x01; + ISR &= ~(0x0001); + ISR |= (value << 0); + + // If both me and HTDE are cleared, transmit data to the host + if (!value && !HTDE_bit(cpustate)) + dsp56k_host_interface_HTX_to_host(cpustate); +} + + +// TODO: 5-11 What is the host processor Initialize function? + +void dsp56k_host_interface_reset(dsp56k_core* cpustate) +{ + // Hook up the CPU-side pointers properly. + cpustate->HI.hcr = &cpustate->peripheral_ram[A2O(0xffc4)]; + cpustate->HI.hsr = &cpustate->peripheral_ram[A2O(0xffe4)]; + cpustate->HI.htrx = &cpustate->peripheral_ram[A2O(0xffe5)]; + + // The Bootstrap hack is initialized to write to address 0x0000 + cpustate->HI.bootstrap_offset = 0x0000; + + /* HCR */ + HCR_set(cpustate, 0x0000); // 5-10 + + /* HSR */ + HRDF_bit_set(cpustate, 0); // 5-11 + HTDE_bit_set(cpustate, 1); // 5-11 + HCP_bit_set(cpustate, 0); // 5-11 + HF0_bit_set(cpustate, 0); // 5-12 + HF1_bit_set(cpustate, 0); // 5-12 + DMA_bit_set(cpustate, 0); // 5-12 + + /* CVR*/ + HV_bits_set(cpustate, 0x16); // 5-7 + HC_bit_set(cpustate, 0); // 5-9 + + /* TODO: ISR (at least) */ +} + +void dsp56k_host_interface_HTX_to_host(dsp56k_core* cpustate) +{ + RXH = ((HTX & 0xff00) >> 8); + RXL = ((HTX & 0x00ff)); + RXDF_bit_set(cpustate, 1); + HTDE_bit_set(cpustate, 1); +} + +void dsp56k_host_interface_host_to_HTX(dsp56k_core* cpustate) +{ + HRX &= 0x00ff; + HRX |= (TXH << 8); + HRX &= 0xff00; + HRX |= TXL; + TXDE_bit_set(cpustate, 1); + HRDF_bit_set(cpustate, 1); +} + + +/*************************************************************************** + I/O INTERFACE +***************************************************************************/ +/* BCR */ +void BCR_set(dsp56k_core* cpustate, UINT16 value) +{ + RH_bit_set(cpustate, (value & 0x8000) >> 15); + BS_bit_set(cpustate, (value & 0x4000) >> 14); + external_x_wait_states_set(cpustate, (value & 0x03e0) >> 5); + external_p_wait_states_set(cpustate, (value & 0x001f) >> 0); +} + +//UINT16 RH_bit(dsp56k_core* cpustate); +//UINT16 BS_bit(dsp56k_core* cpustate); +//UINT16 external_x_wait_states(dsp56k_core* cpustate); +//UINT16 external_p_wait_states(dsp56k_core* cpustate); + +void RH_bit_set(dsp56k_core* cpustate, UINT16 value) +{ + value = value & 0x0001; + BCR &= ~(0x8000); + BCR |= (value << 15); + + // TODO: 4-6 Assert BR pin? +} +void BS_bit_set(dsp56k_core* cpustate, UINT16 value) +{ + value = value & 0x0001; + BCR &= ~(0x4000); + BCR |= (value << 14); + + // TODO: 4-6 Respond to BR pin? +} +void external_x_wait_states_set(dsp56k_core* cpustate, UINT16 value) +{ + value = value & 0x001f; + BCR &= ~(0x03e0); + BCR |= (value << 5); +} +void external_p_wait_states_set(dsp56k_core* cpustate, UINT16 value) +{ + value = value & 0x001f; + BCR &= ~(0x001f); + BCR |= (value << 0); +} + + +/* Port B Control Register PBC */ +void PBC_set(dsp56k_core* cpustate, UINT16 value) +{ + if (value & 0xfffe) + logerror("Dsp56k : Attempting to set reserved bits in the PBC. Ignoring.\n"); + + value = value & 0x0001; + PBC &= ~(0x0001); + PBC |= (value << 0); +} + +#ifdef UNUSED_FUNCTION +int host_interface_active(dsp56k_core* cpustate) +{ + /* The host interface is active if the 0th bit in the PBC is set */ + return PBC & 0x0001; +} +#endif + +/* Port B Data Direction Register (PBDDR) */ +void PBDDR_set(dsp56k_core* cpustate, UINT16 value) +{ + if (value & 0x8000) + logerror("Dsp56k : Attempting to set reserved bits in the PBDDR. Ignoring.\n"); + + value = value & 0x7fff; + PBDDR &= ~(0x7fff); + PBDDR |= (value << 0); + + /* TODO: Implement dsp56k io restrictions, etc. */ +} + +/* Port B Data Register (PBD) */ +void PBD_set(dsp56k_core* cpustate, UINT16 value) +{ + if (value & 0x8000) + logerror("Dsp56k : Attempting to set reserved bits in the PBD. Ignoring.\n"); + + value = value & 0x7fff; + PBD &= ~(0x7fff); + PBD |= (value << 0); + + /* TODO: Implement dsp56k io restrictions, etc. */ +} + +/* Port C Control Register (PCC) */ +void PCC_set(dsp56k_core* cpustate, UINT16 value) +{ + if (value & 0xf000) + logerror("Dsp56k : Attempting to set reserved bits in the PCC. Ignoring.\n"); + + value = value & 0x0fff; + PCC &= ~(0x0fff); + PCC |= (value << 0); + + /* TODO: Implement dsp56k timer and control glue */ +} + +/* Port C Data Direction Register (PCDDR) */ +void PCDDR_set(dsp56k_core* cpustate, UINT16 value) +{ + if (value & 0xf000) + logerror("Dsp56k : Attempting to set reserved bits in the PCDDR. Ignoring.\n"); + + value = value & 0x0fff; + PCDDR &= ~(0x0fff); + PCDDR |= (value << 0); + + /* TODO: Implement dsp56k io restrictions, etc. */ +} + +/* Port C Data Register (PCD) */ +void PCD_set(dsp56k_core* cpustate, UINT16 value) +{ + if (value & 0xf000) + logerror("Dsp56k : Attempting to set reserved bits in the PCD. Ignoring.\n"); + + /* TODO: Temporary */ + logerror("Dsp56k : Setting general output port C data to 0x%04x\n", value); + + value = value & 0x0fff; + PCD &= ~(0x0fff); + PCD |= (value << 0); +} + +void dsp56k_io_reset(dsp56k_core* cpustate) +{ + /* The BCR = 0x43ff */ + RH_bit_set(cpustate, 0); + BS_bit_set(cpustate, 1); + external_x_wait_states_set(cpustate, 0x1f); + external_p_wait_states_set(cpustate, 0x1f); +} + + +} // namespace DSP56K + + +/* Work */ +READ16_MEMBER( dsp56k_device::peripheral_register_r ) +{ + dsp56k_core* cpustate = &m_dsp56k_core; + // (printf) logerror("Peripheral read 0x%04x\n", O2A(offset)); + + switch (O2A(offset)) + { + // Port B Control Register (PBC) + case 0xffc0: break; + + // Port C Control Register (PCC) + case 0xffc1: break; + + // Port B Data Direction Register (PBDDR) + case 0xffc2: break; + + // Port C Data Direction Register (PCDDR) + case 0xffc3: break; + + // HCR: Host Control Register + case 0xffc4: break; + + // COCR + case 0xffc8: break; + + // reserved for test + case 0xffc9: break; + + // CRA-SSI0 Control Register A + case 0xffd0: break; + + // CRB-SSI0 Control Register B + case 0xffd1: break; + + // CRA-SSI1 Control Register A + case 0xffd8: break; + + // CRB-SSI1 Control Register B + case 0xffd9: break; + + // PLCR + case 0xffdc: break; + + // reserved for future use + case 0xffdd: break; + + // BCR: Bus Control Register + case 0xffde: break; + + // IPR: Interrupt Priority Register + case 0xffdf: break; + + // Port B Data Register (PBD) + case 0xffe2: break; + + // Port C Data Register (PCD) + case 0xffe3: break; + + // HSR: Host Status Register + case 0xffe4: break; + + // HTX/HRX: Host TX/RX Register + case 0xffe5: + // 5-5 + if (!DSP56K::HRDF_bit(cpustate)) + return 0xbeef; + else + { + UINT16 value = HRX; // TODO: Maybe not exactly right? Just being safe. + DSP56K::HRDF_bit_set(cpustate, 0); + return value; + } + // COSR + case 0xffe8: break; + + // CRX/CTX + case 0xffe9: break; + + // Timer Control Register (TCR) + case 0xffec: break; + + // Timer Count Register (TCTR) + case 0xffed: break; + + // Timer Compare Register (TCPR) + case 0xffee: break; + + // Timer Preload Register (TPR) + case 0xffef: break; + + // SR/TSR SSI0 Status Register + case 0xfff0: break; + + // TX/RX SSI0 Tx/RX Registers + case 0xfff1: break; + + // RSMA0 SSI0 Register + case 0xfff2: break; + + // RSMB0 SSI0 Register + case 0xfff3: break; + + // TSMA0 SSI0 Register + case 0xfff4: break; + + // TSMB0 SSI0 Register + case 0xfff5: break; + + // SR/TSR SSI1 Status Register + case 0xfff8: break; + + // TX/RX SSI1 TX/RX Registers + case 0xfff9: break; + + // RSMA1 SSI1 Register + case 0xfffa: break; + + // RSMB1 SSI1 Register + case 0xfffb: break; + + // TSMA1 SSI1 Register + case 0xfffc: break; + + // TSMB1 SSI1 Register + case 0xfffd: break; + + // Reserved for on-chip emulation + case 0xffff: break; + } + + // Its primary behavior is RAM + return cpustate->peripheral_ram[offset]; +} + +WRITE16_MEMBER( dsp56k_device::peripheral_register_w ) +{ + dsp56k_core* cpustate = &m_dsp56k_core; + + // Its primary behavior is RAM + // COMBINE_DATA(&cpustate->peripheral_ram[offset]); + + // (printf) logerror("Peripheral write 0x%04x = %04x\n", O2A(offset), data); + + // 4-8 + switch (O2A(offset)) + { + // Port B Control Register (PBC) + case 0xffc0: + DSP56K::PBC_set(cpustate, data); + break; + + // Port C Control Register (PCC) + case 0xffc1: + DSP56K::PCC_set(cpustate, data); + break; + + // Port B Data Direction Register (PBDDR) + case 0xffc2: + DSP56K::PBDDR_set(cpustate, data); + break; + + // Port C Data Direction Register (PCDDR) + case 0xffc3: + DSP56K::PCDDR_set(cpustate, data); + break; + + // HCR: Host Control Register + case 0xffc4: + DSP56K::HCR_set(cpustate, data); + break; + + // COCR + case 0xffc8: break; + + // reserved for test + case 0xffc9: + logerror("DSP56k : Warning write to 0xffc9 reserved for test.\n"); + break; + + // CRA-SSI0 Control Register A + case 0xffd0: break; + + // CRB-SSI0 Control Register B + case 0xffd1: break; + + // CRA-SSI1 Control Register A + case 0xffd8: break; + + // CRB-SSI1 Control Register B + case 0xffd9: break; + + // PLCR + case 0xffdc: break; + + // reserved for future use + case 0xffdd: + logerror("DSP56k : Warning write to 0xffdd reserved for future use.\n"); + break; + + // BCR: Bus Control Register + case 0xffde: + DSP56K::BCR_set(cpustate, data); + break; + + // IPR: Interrupt Priority Register + case 0xffdf: + DSP56K::IPR_set(cpustate, data); + break; + + // Port B Data Register (PBD) + case 0xffe2: + DSP56K::PBD_set(cpustate, data); + break; + + // Port C Data Register (PCD) + case 0xffe3: + DSP56K::PCD_set(cpustate, data); + break; + + // HSR: Host Status Register + case 0xffe4: break; + + // HTX/HRX: Host TX/RX Register + case 0xffe5: + HTX = data; + DSP56K::HTDE_bit_set(cpustate, 0); // 5-5 + break; + + // COSR + case 0xffe8: break; + + // CRX/CTX + case 0xffe9: break; + + // Timer Control Register (TCR) + case 0xffec: break; + + // Timer Count Register (TCTR) + case 0xffed: break; + + // Timer Compare Register (TCPR) + case 0xffee: break; + + // Timer Preload Register (TPR) + case 0xffef: break; + + // SR/TSR SSI0 Status Register + case 0xfff0: break; + + // TX/RX SSI0 Tx/RX Registers + case 0xfff1: break; + + // RSMA0 SSI0 Register + case 0xfff2: break; + + // RSMB0 SSI0 Register + case 0xfff3: break; + + // TSMA0 SSI0 Register + case 0xfff4: break; + + // TSMB0 SSI0 Register + case 0xfff5: break; + + // SR/TSR SSI1 Status Register + case 0xfff8: break; + + // TX/RX SSI1 TX/RX Registers + case 0xfff9: break; + + // RSMA1 SSI1 Register + case 0xfffa: break; + + // RSMB1 SSI1 Register + case 0xfffb: break; + + // TSMA1 SSI1 Register + case 0xfffc: break; + + // TSMB1 SSI1 Register + case 0xfffd: break; + + // Reserved for on-chip emulation + case 0xffff: + logerror("DSP56k : Warning write to 0xffff reserved for on-chip emulation.\n"); + break; + } +} + +/* These two functions are exposed to the outside world */ +/* They represent the host side of the dsp56k's host interface */ +void dsp56k_device::host_interface_write(UINT8 offset, UINT8 data) +{ + dsp56k_core* cpustate = &m_dsp56k_core; + + /* Not exactly correct since the bootstrap hack doesn't need this to be true */ + /* + if (!host_interface_active()) + logerror("Dsp56k : Host interface write called without HI being set active by the PBC.\n"); + */ + + switch (offset) + { + // Interrupt Control Register (ICR) + case 0x00: + // HACK + if (cpustate->bootstrap_mode == BOOTSTRAP_HI) + { + // A-4 If they set HF0 while in bootstrap mode, it stops the bootstrap short. + if (data & 0x08) + { + cpustate->bootstrap_mode = BOOTSTRAP_OFF; + PC = 0x0000; + // TODO: Do we set HF0 then, or let it slide? + // TODO: Do I allow it to do an ICR_set(), or intercept it and throw everything away? + break; + } + } + DSP56K::ICR_set(cpustate, data); + break; + + // Command Vector Register (CVR) + case 0x01: + DSP56K::CVR_set(cpustate, data); + break; + + // Interrupt status register (ISR) - Read only! + case 0x02: + logerror("DSP56k : Interrupt status register is read only.\n"); + break; + + // Interrupt vector register (IVR) + case 0x03: break; + + // Not used + case 0x04: + logerror("DSP56k : Address 0x4 on the host side of the host interface is not used.\n"); + break; + + // Reserved + case 0x05: + logerror("DSP56k : Address 0x5 on the host side of the host interface is reserved.\n"); + break; + + // Transmit byte register - high byte (TXH) + case 0x06: + // HACK + if (cpustate->bootstrap_mode == BOOTSTRAP_HI) + { + cpustate->program_ram[cpustate->HI.bootstrap_offset] &= 0x00ff; + cpustate->program_ram[cpustate->HI.bootstrap_offset] |= (data << 8); + break; /* Probably the right thing to do, given this is a hack */ + } + + if (DSP56K::TXDE_bit(cpustate)) // 5-5 + { + TXH = data; + } + break; + + // Transmit byte register - low byte (TXL) + case 0x07: + // HACK + if (cpustate->bootstrap_mode == BOOTSTRAP_HI) + { + cpustate->program_ram[cpustate->HI.bootstrap_offset] &= 0xff00; + cpustate->program_ram[cpustate->HI.bootstrap_offset] |= data; + cpustate->HI.bootstrap_offset++; + + if (cpustate->HI.bootstrap_offset == 0x800) + { + cpustate->bootstrap_mode = BOOTSTRAP_OFF; + } + break; /* Probably the right thing to do, given this is a hack */ + } + + if (DSP56K::TXDE_bit(cpustate)) // 5-5 + { + TXL = data; + DSP56K::TXDE_bit_set(cpustate, 0); + } + break; + + default: logerror("DSP56k : dsp56k_host_interface_write called with invalid address 0x%02x.\n", offset); + } +} + +UINT8 dsp56k_device::host_interface_read(UINT8 offset) +{ + dsp56k_core* cpustate = &m_dsp56k_core; + + /* Not exactly correct since the bootstrap hack doesn't need this to be true */ + /* + if (!host_interface_active()) + logerror("Dsp56k : Host interface write called without HI being set active by the PBC.\n"); + */ + + switch (offset) + { + // Interrupt Control Register (ICR) + case 0x00: + return ICR; + + // Command Vector Register (CVR) + case 0x01: + return CVR; + + // Interrupt status register (ISR) + case 0x02: + return ISR; + + // Interrupt vector register (IVR) + case 0x03: + return IVR; + + // Read zeroes + case 0x04: + return 0x00; + + // Reserved + case 0x05: + logerror("DSP56k : Address 0x5 on the host side of the host interface is reserved.\n"); + break; + + // Receive byte register - high byte (RXH) + case 0x06: + // 5-5 + if (!DSP56K::RXDF_bit(cpustate)) + return 0xbf; + else + return RXH; + + // Receive byte register - low byte (RXL) + case 0x07: + // 5-5 + if (!DSP56K::RXDF_bit(cpustate)) + return 0xbf; + else + { + UINT8 value = RXL; // TODO: Maybe not exactly right? I'm just being safe. + DSP56K::RXDF_bit_set(cpustate, 0); + return value; + } + + default: logerror("DSP56k : dsp56k_host_interface_read called with invalid address 0x%02x.\n", offset); + } + + /* Shouldn't get here */ + return 0xff; +} + +/* MISC*/ +UINT16 dsp56k_device::get_peripheral_memory(UINT16 addr) +{ + dsp56k_core* cpustate = &m_dsp56k_core; + return cpustate->peripheral_ram[A2O(addr)]; +} diff --git a/src/devices/cpu/dsp56k/dsp56mem.h b/src/devices/cpu/dsp56k/dsp56mem.h new file mode 100644 index 00000000000..93ab74ede42 --- /dev/null +++ b/src/devices/cpu/dsp56k/dsp56mem.h @@ -0,0 +1,241 @@ +// license:BSD-3-Clause +// copyright-holders:Andrew Gardner +#ifndef __DSP56_MEM_H__ +#define __DSP56_MEM_H__ + +#include "dsp56k.h" + +namespace DSP56K +{ +/*************************************************************************** + MEMORY +***************************************************************************/ +void mem_reset(dsp56k_core* cpustate); + +// Adjusts the documented address to match the offset in peripheral RAM +#define A2O(a) (a-0xffc0) + +// Adjusts the offset in peripheral RAM to match the documented address +#define O2A(a) (a+0xffc0) + +// The memory 'registers' +#define PBC (cpustate->peripheral_ram[A2O(0xffc0)]) +#define PCC (cpustate->peripheral_ram[A2O(0xffc1)]) +#define PBDDR (cpustate->peripheral_ram[A2O(0xffc2)]) +#define PCDDR (cpustate->peripheral_ram[A2O(0xffc3)]) +#define HCR (cpustate->peripheral_ram[A2O(0xffc4)]) +#define COCR (cpustate->peripheral_ram[A2O(0xffc8)]) +#define CRASSI0 (cpustate->peripheral_ram[A2O(0xffd0)]) +#define CRBSSI0 (cpustate->peripheral_ram[A2O(0xffd1)]) +#define CRASSI1 (cpustate->peripheral_ram[A2O(0xffd8)]) +#define CRBSSI1 (cpustate->peripheral_ram[A2O(0xffd9)]) +#define PLCR (cpustate->peripheral_ram[A2O(0xffdc)]) +#define BCR (cpustate->peripheral_ram[A2O(0xffde)]) +#define IPR (cpustate->peripheral_ram[A2O(0xffdf)]) +#define PBD (cpustate->peripheral_ram[A2O(0xffe2)]) +#define PCD (cpustate->peripheral_ram[A2O(0xffe3)]) +#define HSR (cpustate->peripheral_ram[A2O(0xffe4)]) +#define HTXHRX (cpustate->peripheral_ram[A2O(0xffe5)]) +#define COSR (cpustate->peripheral_ram[A2O(0xffe8)]) +#define CRXCTX (cpustate->peripheral_ram[A2O(0xffe9)]) +#define TCR (cpustate->peripheral_ram[A2O(0xffec)]) +#define TCTR (cpustate->peripheral_ram[A2O(0xffed)]) +#define TCPR (cpustate->peripheral_ram[A2O(0xffee)]) +#define TPR (cpustate->peripheral_ram[A2O(0xffef)]) +#define TSRSSI0 (cpustate->peripheral_ram[A2O(0xfff0)]) +#define TRXSSI0 (cpustate->peripheral_ram[A2O(0xfff1)]) +#define RSMA0 (cpustate->peripheral_ram[A2O(0xfff2)]) +#define RSMB0 (cpustate->peripheral_ram[A2O(0xfff3)]) +#define TSMA0 (cpustate->peripheral_ram[A2O(0xfff4)]) +#define TSMB0 (cpustate->peripheral_ram[A2O(0xfff5)]) +#define TSRSSI1 (cpustate->peripheral_ram[A2O(0xfff8)]) +#define TRXSSI1 (cpustate->peripheral_ram[A2O(0xfff9)]) +#define RSMA1 (cpustate->peripheral_ram[A2O(0xfffa)]) +#define RSMB1 (cpustate->peripheral_ram[A2O(0xfffb)]) +#define TSMA1 (cpustate->peripheral_ram[A2O(0xfffc)]) +#define TSMB1 (cpustate->peripheral_ram[A2O(0xfffd)]) + +/* Interrupt priority register (IPR) bits */ +void IPR_set(dsp56k_core* cpustate, UINT16 value); + +/* A return value of -1 means disabled */ +INT8 irqa_ipl(dsp56k_core* cpustate); +INT8 irqb_ipl(dsp56k_core* cpustate); +UINT8 irqa_trigger(dsp56k_core* cpustate); +UINT8 irqb_trigger(dsp56k_core* cpustate); + +INT8 codec_ipl(dsp56k_core* cpustate); +INT8 host_ipl(dsp56k_core* cpustate); +INT8 ssi0_ipl(dsp56k_core* cpustate); +INT8 ssi1_ipl(dsp56k_core* cpustate); +INT8 tm_ipl(dsp56k_core* cpustate); + + +/*************************************************************************** + HOST INTERFACE +***************************************************************************/ +void dsp56k_host_interface_reset(dsp56k_core* cpustate); +#define HTX (HTXHRX) +#define HRX (HTXHRX) + +#define ICR (cpustate->HI.icr) +#define CVR (cpustate->HI.cvr) +#define ISR (cpustate->HI.isr) +#define IVR (cpustate->HI.ivr) +#define TXH (cpustate->HI.trxh) +#define TXL (cpustate->HI.trxl) +#define RXH (cpustate->HI.trxh) +#define RXL (cpustate->HI.trxl) + +/***************/ +/* DSP56k SIDE */ +/***************/ +/* Host Control Register (HCR) Bits */ +void HCR_set(dsp56k_core* cpustate, UINT16 value); + +//UINT16 HF3_bit(dsp56k_core* cpustate); #define hf3BIT ((HCR & 0x0010) != 0) +//UINT16 HF2_bit(dsp56k_core* cpustate); #define hf2BIT ((HCR & 0x0008) != 0) +UINT16 HCIE_bit(dsp56k_core* cpustate); +UINT16 HTIE_bit(dsp56k_core* cpustate); +UINT16 HRIE_bit(dsp56k_core* cpustate); + +void HF3_bit_set(dsp56k_core* cpustate, UINT16 value); +void HF2_bit_set(dsp56k_core* cpustate, UINT16 value); +void HCIE_bit_set(dsp56k_core* cpustate, UINT16 value); +void HTIE_bit_set(dsp56k_core* cpustate, UINT16 value); +void HRIE_bit_set(dsp56k_core* cpustate, UINT16 value); + +/* Host Status Register (HSR) Bits */ +//void HSR_set(dsp56k_core* cpustate, UINT16 value); + +//UINT16 DMA_bit(dsp56k_core* cpustate); #define dmaBIT ((HSR & 0x0080) != 0) +//UINT16 HF1_bit(dsp56k_core* cpustate); #define hf1BIT ((HSR & 0x0010) != 0) +//UINT16 HF0_bit(dsp56k_core* cpustate); #define hf0BIT ((HSR & 0x0008) != 0) +//UINT16 HCP_bit(dsp56k_core* cpustate); #define hcpBIT ((HSR & 0x0004) != 0) +UINT16 HTDE_bit(dsp56k_core* cpustate); +UINT16 HRDF_bit(dsp56k_core* cpustate); + +void DMA_bit_set(dsp56k_core* cpustate, UINT16 value); +void HF1_bit_set(dsp56k_core* cpustate, UINT16 value); +void HF0_bit_set(dsp56k_core* cpustate, UINT16 value); +void HCP_bit_set(dsp56k_core* cpustate, UINT16 value); +void HTDE_bit_set(dsp56k_core* cpustate, UINT16 value); +void HRDF_bit_set(dsp56k_core* cpustate, UINT16 value); + +/*************/ +/* HOST SIDE */ +/*************/ +/* Interrupt Control Register (ICR) Bits */ +void ICR_set(dsp56k_core* cpustate, UINT8 value); + +//UINT8 INIT_bit(dsp56k_core* cpustate); #define x_initBIT ((dsp56k.HI.ICR & 0x0080) != 0) +//UINT8 HM1_bit(dsp56k_core* cpustate); #define x_hm1BIT ((dsp56k.HI.ICR & 0x0040) != 0) +//UINT8 HM0_bit(dsp56k_core* cpustate); #define x_hm0BIT ((dsp56k.HI.ICR & 0x0020) != 0) +//UINT8 HF1_bit_host(dsp56k_core* cpustate); #define x_hf1BIT ((dsp56k.HI.ICR & 0x0010) != 0) +//UINT8 HF0_bit_host(dsp56k_core* cpustate); #define x_hf0BIT ((dsp56k.HI.ICR & 0x0008) != 0) +//UINT8 TREQ_bit(dsp56k_core* cpustate); #define x_treqBIT ((dsp56k.HI.ICR & 0x0002) != 0) +//UINT8 RREQ_bit(dsp56k_core* cpustate); #define x_rreqBIT ((dsp56k.HI.ICR & 0x0001) != 0) + +//void INIT_bit_set(dsp56k_core* cpustate, UINT8 value); #define CLEAR_x_initBIT() (dsp56k.HI.ICR &= (~0x0080)) +//void HM1_bit_set(dsp56k_core* cpustate, UINT8 value); #define CLEAR_x_hm1BIT() (dsp56k.HI.ICR &= (~0x0040)) +//void HM0_bit_set(dsp56k_core* cpustate, UINT8 value); #define CLEAR_x_hm0BIT() (dsp56k.HI.ICR &= (~0x0020)) +void HF1_bit_host_set(dsp56k_core* cpustate, UINT8 value); +void HF0_bit_host_set(dsp56k_core* cpustate, UINT8 value); +void TREQ_bit_set(dsp56k_core* cpustate, UINT8 value); +void RREQ_bit_set(dsp56k_core* cpustate, UINT8 value); + +/* Command Vector Register (CVR) Bits */ +void CVR_set(dsp56k_core* cpustate, UINT8 value); + +//UINT8 HC_bit(); +UINT8 HV_bits(dsp56k_core* cpustate); + +void HC_bit_set(dsp56k_core* cpustate, UINT8 value); +void HV_bits_set(dsp56k_core* cpustate, UINT8 value); + +/* Interrupt Status Register (ISR) Bits */ +// void ISR_set(dsp56k_core* cpustate, UINT8 value); + +//UINT8 HREQ_bit(dsp56k_core* cpustate); #define x_hreqBIT ((dsp56k.HI.ISR & 0x0080) != 0) +//UINT8 DMA_bit(dsp56k_core* cpustate); #define x_dmaBIT ((dsp56k.HI.ISR & 0x0040) != 0) +//UINT8 HF3_bit_host(dsp56k_core* cpustate); #define x_hf3BIT ((dsp56k.HI.ISR & 0x0010) != 0) +//UINT8 HF2_bit_host(dsp56k_core* cpustate); #define x_hf2BIT ((dsp56k.HI.ISR & 0x0008) != 0) +//UINT8 TRDY_bit(dsp56k_core* cpustate); #define x_trdyBIT ((dsp56k.HI.ISR & 0x0004) != 0) +UINT8 TXDE_bit(dsp56k_core* cpustate); +UINT8 RXDF_bit(dsp56k_core* cpustate); + +//void HREQ_bit_set(dsp56k_core* cpustate, UINT8 value); #define CLEAR_x_hreqBIT() (dsp56k.HI.ISR &= (~0x0080)) +//void DMA_bit_set(dsp56k_core* cpustate, UINT8 value); #define CLEAR_x_dmaBIT() (dsp56k.HI.ISR &= (~0x0040)) +void HF3_bit_host_set(dsp56k_core* cpustate, UINT8 value); +void HF2_bit_host_set(dsp56k_core* cpustate, UINT8 value); +//void TRDY_bit_set(dsp56k_core* cpustate, UINT8 value); #define CLEAR_x_trdyBIT() (dsp56k.HI.ISR &= (~0x0004)) +void TXDE_bit_set(dsp56k_core* cpustate, UINT8 value); +void RXDF_bit_set(dsp56k_core* cpustate, UINT8 value); + +/* Interrupt Vector Register (IVR) Bits */ +//void IVR_set(dsp56k_core* cpustate, UINT8 value); + +//UINT8 IV7_bit(dsp56k_core* cpustate); +//UINT8 IV6_bit(dsp56k_core* cpustate); +//UINT8 IV5_bit(dsp56k_core* cpustate); +//UINT8 IV4_bit(dsp56k_core* cpustate); +//UINT8 IV3_bit(dsp56k_core* cpustate); +//UINT8 IV2_bit(dsp56k_core* cpustate); +//UINT8 IV1_bit(dsp56k_core* cpustate); +//UINT8 IV0_bit(dsp56k_core* cpustate); + +//void IV7_bit_set(dsp56k_core* cpustate, UINT8 value); +//void IV6_bit_set(dsp56k_core* cpustate, UINT8 value); +//void IV5_bit_set(dsp56k_core* cpustate, UINT8 value); +//void IV4_bit_set(dsp56k_core* cpustate, UINT8 value); +//void IV3_bit_set(dsp56k_core* cpustate, UINT8 value); +//void IV2_bit_set(dsp56k_core* cpustate, UINT8 value); +//void IV1_bit_set(dsp56k_core* cpustate, UINT8 value); +//void IV0_bit_set(dsp56k_core* cpustate, UINT8 value); + + +/* PROTOTYPES */ +void dsp56k_host_interface_HTX_to_host(dsp56k_core* cpustate); +void dsp56k_host_interface_host_to_HTX(dsp56k_core* cpustate); + + +/*************************************************************************** + I/O INTERFACE +***************************************************************************/ +void dsp56k_io_reset(dsp56k_core* cpustate); + +/* Port A Bus Control Register (BCR) */ +void BCR_set(dsp56k_core* cpustate, UINT16 value); + +//UINT16 RH_bit(dsp56k_core* cpustate); +//UINT16 BS_bit(dsp56k_core* cpustate); +//UINT16 external_x_wait_states(dsp56k_core* cpustate); +//UINT16 external_p_wait_states(dsp56k_core* cpustate); + +void RH_bit_set(dsp56k_core* cpustate, UINT16 value); +void BS_bit_set(dsp56k_core* cpustate, UINT16 value); +void external_x_wait_states_set(dsp56k_core* cpustate, UINT16 value); +void external_p_wait_states_set(dsp56k_core* cpustate, UINT16 value); + +/* Port B Control Register (PBC) */ +void PBC_set(dsp56k_core* cpustate, UINT16 value); +//int host_interface_active(dsp56k_core* cpustate); + +/* Port B Data Direction Register (PBDDR) */ +void PBDDR_set(dsp56k_core* cpustate, UINT16 value); + +/* Port B Data Register (PBD) */ +void PBD_set(dsp56k_core* cpustate, UINT16 value); + +/* Port C Control Register (PCC) */ +void PCC_set(dsp56k_core* cpustate, UINT16 value); + +/* Port C Data Direction Register (PCDDR) */ +void PCDDR_set(dsp56k_core* cpustate, UINT16 value); + +/* Port C Dtaa Register (PCD) */ +void PCD_set(dsp56k_core* cpustate, UINT16 value); + +} // namespace DSP56K + +#endif diff --git a/src/devices/cpu/dsp56k/dsp56ops.inc b/src/devices/cpu/dsp56k/dsp56ops.inc new file mode 100644 index 00000000000..f00d1cc84b4 --- /dev/null +++ b/src/devices/cpu/dsp56k/dsp56ops.inc @@ -0,0 +1,4922 @@ +// license:BSD-3-Clause +// copyright-holders:Andrew Gardner +/*************************************************************************** + + dsp56ops.inc + Core implementation for the portable Motorola/Freescale DSP56k emulator. + Written by Andrew Gardner + +***************************************************************************/ + +/* NOTES For register setting: + FM.3-4 : When A2 or B2 is read, the register contents occupy the low-order portion + (bits 7-0) of the word; the high-order portion (bits 16-8) is sign-extended. When A2 or B2 + is written, the register receives the low-order portion of the word; the high-order portion is not used + : ...much more! + : ...shifter/limiter/overflow notes too. + +*/ + +/* +TODO: + - 0x01ee: should this move sign extend? otherwise the test-against-minus means nothing. + - Restore only the proper bits upon loop termination! + - BFCLR has some errata in the docs that may need to be applied. +*/ + +/************************/ +/* Datatypes and macros */ +/************************/ +enum addSubOpType { OP_ADD, + OP_SUB, + OP_OTHER }; + +enum dataType { DT_BYTE, + DT_WORD, + DT_DOUBLE_WORD, + DT_LONG_WORD }; + +struct typed_pointer +{ + void* addr; + char data_type; +}; + +//#define ADDRESS(X) (X<<1) +#define BITS(CUR,MASK) (Dsp56kOpMask(CUR,MASK)) + +/*********************/ +/* Opcode prototypes */ +/*********************/ +static size_t dsp56k_op_addsub_2 (dsp56k_core* cpustate, const UINT16 op_byte, typed_pointer* d_register, UINT8* cycles); +static size_t dsp56k_op_mac_1 (dsp56k_core* cpustate, const UINT16 op_byte, typed_pointer* d_register, UINT8* cycles); +static size_t dsp56k_op_macr_1 (dsp56k_core* cpustate, const UINT16 op_byte, typed_pointer* d_register, UINT8* cycles); +static size_t dsp56k_op_move_1 (dsp56k_core* cpustate, const UINT16 op_byte, typed_pointer* d_register, UINT8* cycles); +static size_t dsp56k_op_mpy_1 (dsp56k_core* cpustate, const UINT16 op_byte, typed_pointer* d_register, UINT8* cycles); +static size_t dsp56k_op_mpyr_1 (dsp56k_core* cpustate, const UINT16 op_byte, typed_pointer* d_register, UINT8* cycles); +static size_t dsp56k_op_tfr_2 (dsp56k_core* cpustate, const UINT16 op_byte, typed_pointer* d_register, UINT8* cycles); +static size_t dsp56k_op_mpy_2 (dsp56k_core* cpustate, const UINT16 op_byte, UINT8* cycles); +static size_t dsp56k_op_mac_2 (dsp56k_core* cpustate, const UINT16 op_byte, UINT8* cycles); +static size_t dsp56k_op_clr (dsp56k_core* cpustate, const UINT16 op_byte, typed_pointer* d_register, UINT64* p_accum, UINT8* cycles); +static size_t dsp56k_op_add (dsp56k_core* cpustate, const UINT16 op_byte, typed_pointer* d_register, UINT64* p_accum, UINT8* cycles); +static size_t dsp56k_op_move (dsp56k_core* cpustate, const UINT16 op_byte, typed_pointer* d_register, UINT64* p_accum, UINT8* cycles); +static size_t dsp56k_op_tfr (dsp56k_core* cpustate, const UINT16 op_byte, typed_pointer* d_register, UINT64* p_accum, UINT8* cycles); +static size_t dsp56k_op_rnd (dsp56k_core* cpustate, const UINT16 op_byte, typed_pointer* d_register, UINT64* p_accum, UINT8* cycles); +static size_t dsp56k_op_tst (dsp56k_core* cpustate, const UINT16 op_byte, typed_pointer* d_register, UINT64* p_accum, UINT8* cycles); +static size_t dsp56k_op_inc (dsp56k_core* cpustate, const UINT16 op_byte, typed_pointer* d_register, UINT64* p_accum, UINT8* cycles); +static size_t dsp56k_op_inc24 (dsp56k_core* cpustate, const UINT16 op_byte, typed_pointer* d_register, UINT64* p_accum, UINT8* cycles); +static size_t dsp56k_op_or (dsp56k_core* cpustate, const UINT16 op_byte, typed_pointer* d_register, UINT64* p_accum, UINT8* cycles); +static size_t dsp56k_op_asr (dsp56k_core* cpustate, const UINT16 op_byte, typed_pointer* d_register, UINT64* p_accum, UINT8* cycles); +static size_t dsp56k_op_asl (dsp56k_core* cpustate, const UINT16 op_byte, typed_pointer* d_register, UINT64* p_accum, UINT8* cycles); +static size_t dsp56k_op_lsr (dsp56k_core* cpustate, const UINT16 op_byte, typed_pointer* d_register, UINT64* p_accum, UINT8* cycles); +static size_t dsp56k_op_lsl (dsp56k_core* cpustate, const UINT16 op_byte, typed_pointer* d_register, UINT64* p_accum, UINT8* cycles); +static size_t dsp56k_op_eor (dsp56k_core* cpustate, const UINT16 op_byte, typed_pointer* d_register, UINT64* p_accum, UINT8* cycles); +static size_t dsp56k_op_subl (dsp56k_core* cpustate, const UINT16 op_byte, typed_pointer* d_register, UINT64* p_accum, UINT8* cycles); +static size_t dsp56k_op_sub (dsp56k_core* cpustate, const UINT16 op_byte, typed_pointer* d_register, UINT64* p_accum, UINT8* cycles); +static size_t dsp56k_op_clr24 (dsp56k_core* cpustate, const UINT16 op_byte, typed_pointer* d_register, UINT64* p_accum, UINT8* cycles); +static size_t dsp56k_op_sbc (dsp56k_core* cpustate, const UINT16 op_byte, typed_pointer* d_register, UINT64* p_accum, UINT8* cycles); +static size_t dsp56k_op_cmp (dsp56k_core* cpustate, const UINT16 op_byte, typed_pointer* d_register, UINT64* p_accum, UINT8* cycles); +static size_t dsp56k_op_neg (dsp56k_core* cpustate, const UINT16 op_byte, typed_pointer* d_register, UINT64* p_accum, UINT8* cycles); +static size_t dsp56k_op_not (dsp56k_core* cpustate, const UINT16 op_byte, typed_pointer* d_register, UINT64* p_accum, UINT8* cycles); +static size_t dsp56k_op_dec (dsp56k_core* cpustate, const UINT16 op_byte, typed_pointer* d_register, UINT64* p_accum, UINT8* cycles); +static size_t dsp56k_op_dec24 (dsp56k_core* cpustate, const UINT16 op_byte, typed_pointer* d_register, UINT64* p_accum, UINT8* cycles); +static size_t dsp56k_op_and (dsp56k_core* cpustate, const UINT16 op_byte, typed_pointer* d_register, UINT64* p_accum, UINT8* cycles); +static size_t dsp56k_op_abs (dsp56k_core* cpustate, const UINT16 op_byte, typed_pointer* d_register, UINT64* p_accum, UINT8* cycles); +static size_t dsp56k_op_ror (dsp56k_core* cpustate, const UINT16 op_byte, typed_pointer* d_register, UINT64* p_accum, UINT8* cycles); +static size_t dsp56k_op_rol (dsp56k_core* cpustate, const UINT16 op_byte, typed_pointer* d_register, UINT64* p_accum, UINT8* cycles); +static size_t dsp56k_op_cmpm (dsp56k_core* cpustate, const UINT16 op_byte, typed_pointer* d_register, UINT64* p_accum, UINT8* cycles); +static size_t dsp56k_op_mpy (dsp56k_core* cpustate, const UINT16 op_byte, typed_pointer* d_register, UINT64* p_accum, UINT8* cycles); +static size_t dsp56k_op_mpyr (dsp56k_core* cpustate, const UINT16 op_byte, typed_pointer* d_register, UINT64* p_accum, UINT8* cycles); +static size_t dsp56k_op_mac (dsp56k_core* cpustate, const UINT16 op_byte, typed_pointer* d_register, UINT64* p_accum, UINT8* cycles); +static size_t dsp56k_op_macr (dsp56k_core* cpustate, const UINT16 op_byte, typed_pointer* d_register, UINT64* p_accum, UINT8* cycles); +static size_t dsp56k_op_adc (dsp56k_core* cpustate, const UINT16 op, UINT8* cycles); +static size_t dsp56k_op_andi (dsp56k_core* cpustate, const UINT16 op, UINT8* cycles); +static size_t dsp56k_op_asl4 (dsp56k_core* cpustate, const UINT16 op, UINT8* cycles); +static size_t dsp56k_op_asr4 (dsp56k_core* cpustate, const UINT16 op, UINT8* cycles); +static size_t dsp56k_op_asr16 (dsp56k_core* cpustate, const UINT16 op, UINT8* cycles); +static size_t dsp56k_op_bfop (dsp56k_core* cpustate, const UINT16 op, const UINT16 op2, UINT8* cycles); +static size_t dsp56k_op_bfop_1 (dsp56k_core* cpustate, const UINT16 op, const UINT16 op2, UINT8* cycles); +static size_t dsp56k_op_bfop_2 (dsp56k_core* cpustate, const UINT16 op, const UINT16 op2, UINT8* cycles); +static size_t dsp56k_op_bcc (dsp56k_core* cpustate, const UINT16 op, const UINT16 op2, UINT8* cycles); +static size_t dsp56k_op_bcc_1 (dsp56k_core* cpustate, const UINT16 op, UINT8* cycles); +static size_t dsp56k_op_bcc_2 (dsp56k_core* cpustate, const UINT16 op, UINT8* cycles); +static size_t dsp56k_op_bra (dsp56k_core* cpustate, const UINT16 op, const UINT16 op2, UINT8* cycles); +static size_t dsp56k_op_bra_1 (dsp56k_core* cpustate, const UINT16 op, UINT8* cycles); +static size_t dsp56k_op_bra_2 (dsp56k_core* cpustate, const UINT16 op, UINT8* cycles); +static size_t dsp56k_op_brkcc (dsp56k_core* cpustate, const UINT16 op, UINT8* cycles); +static size_t dsp56k_op_bscc (dsp56k_core* cpustate, const UINT16 op, const UINT16 op2, UINT8* cycles); +static size_t dsp56k_op_bscc_1 (dsp56k_core* cpustate, const UINT16 op, UINT8* cycles); +static size_t dsp56k_op_bsr (dsp56k_core* cpustate, const UINT16 op, const UINT16 op2, UINT8* cycles); +static size_t dsp56k_op_bsr_1 (dsp56k_core* cpustate, const UINT16 op, UINT8* cycles); +static size_t dsp56k_op_chkaau (dsp56k_core* cpustate, const UINT16 op, UINT8* cycles); +static size_t dsp56k_op_debug (dsp56k_core* cpustate, const UINT16 op, UINT8* cycles); +static size_t dsp56k_op_debugcc (dsp56k_core* cpustate, const UINT16 op, UINT8* cycles); +static size_t dsp56k_op_div (dsp56k_core* cpustate, const UINT16 op, UINT8* cycles); +static size_t dsp56k_op_dmac (dsp56k_core* cpustate, const UINT16 op, UINT8* cycles); +static size_t dsp56k_op_do (dsp56k_core* cpustate, const UINT16 op, const UINT16 op2, UINT8* cycles); +static size_t dsp56k_op_do_1 (dsp56k_core* cpustate, const UINT16 op, const UINT16 op2, UINT8* cycles); +static size_t dsp56k_op_do_2 (dsp56k_core* cpustate, const UINT16 op, const UINT16 op2, UINT8* cycles); +static size_t dsp56k_op_doforever(dsp56k_core* cpustate, const UINT16 op, const UINT16 op2, UINT8* cycles); +static size_t dsp56k_op_enddo (dsp56k_core* cpustate, const UINT16 op, UINT8* cycles); +static size_t dsp56k_op_ext (dsp56k_core* cpustate, const UINT16 op, UINT8* cycles); +static size_t dsp56k_op_illegal (dsp56k_core* cpustate, const UINT16 op, UINT8* cycles); +static size_t dsp56k_op_imac (dsp56k_core* cpustate, const UINT16 op, UINT8* cycles); +static size_t dsp56k_op_impy (dsp56k_core* cpustate, const UINT16 op, UINT8* cycles); +static size_t dsp56k_op_jcc (dsp56k_core* cpustate, const UINT16 op, const UINT16 op2, UINT8* cycles); +static size_t dsp56k_op_jcc_1 (dsp56k_core* cpustate, const UINT16 op, UINT8* cycles); +static size_t dsp56k_op_jmp (dsp56k_core* cpustate, const UINT16 op, const UINT16 op2, UINT8* cycles); +static size_t dsp56k_op_jmp_1 (dsp56k_core* cpustate, const UINT16 op, UINT8* cycles); +static size_t dsp56k_op_jscc (dsp56k_core* cpustate, const UINT16 op, const UINT16 op2, UINT8* cycles); +static size_t dsp56k_op_jscc_1 (dsp56k_core* cpustate, const UINT16 op, UINT8* cycles); +static size_t dsp56k_op_jsr (dsp56k_core* cpustate, const UINT16 op, const UINT16 op2, UINT8* cycles); +static size_t dsp56k_op_jsr_1 (dsp56k_core* cpustate, const UINT16 op, UINT8* cycles); +static size_t dsp56k_op_jsr_2 (dsp56k_core* cpustate, const UINT16 op, UINT8* cycles); +static size_t dsp56k_op_lea (dsp56k_core* cpustate, const UINT16 op, UINT8* cycles); +static size_t dsp56k_op_lea_1 (dsp56k_core* cpustate, const UINT16 op, UINT8* cycles); +static size_t dsp56k_op_macsuuu (dsp56k_core* cpustate, const UINT16 op, UINT8* cycles); +static size_t dsp56k_op_move_2 (dsp56k_core* cpustate, const UINT16 op, const UINT16 op2, UINT8* cycles); +static size_t dsp56k_op_movec (dsp56k_core* cpustate, const UINT16 op, UINT8* cycles); +static size_t dsp56k_op_movec_1 (dsp56k_core* cpustate, const UINT16 op, UINT8* cycles); +static size_t dsp56k_op_movec_2 (dsp56k_core* cpustate, const UINT16 op, UINT8* cycles); +static size_t dsp56k_op_movec_3 (dsp56k_core* cpustate, const UINT16 op, const UINT16 op2, UINT8* cycles); +static size_t dsp56k_op_movec_4 (dsp56k_core* cpustate, const UINT16 op, UINT8* cycles); +static size_t dsp56k_op_movec_5 (dsp56k_core* cpustate, const UINT16 op, const UINT16 op2, UINT8* cycles); +static size_t dsp56k_op_movei (dsp56k_core* cpustate, const UINT16 op, UINT8* cycles); +static size_t dsp56k_op_movem (dsp56k_core* cpustate, const UINT16 op, UINT8* cycles); +static size_t dsp56k_op_movem_1 (dsp56k_core* cpustate, const UINT16 op, UINT8* cycles); +static size_t dsp56k_op_movem_2 (dsp56k_core* cpustate, const UINT16 op, const UINT16 op2, UINT8* cycles); +static size_t dsp56k_op_movep (dsp56k_core* cpustate, const UINT16 op, UINT8* cycles); +static size_t dsp56k_op_movep_1 (dsp56k_core* cpustate, const UINT16 op, UINT8* cycles); +static size_t dsp56k_op_moves (dsp56k_core* cpustate, const UINT16 op, UINT8* cycles); +static size_t dsp56k_op_mpysuuu (dsp56k_core* cpustate, const UINT16 op, UINT8* cycles); +static size_t dsp56k_op_negc (dsp56k_core* cpustate, const UINT16 op, UINT8* cycles); +static size_t dsp56k_op_nop (dsp56k_core* cpustate, const UINT16 op, UINT8* cycles); +static size_t dsp56k_op_norm (dsp56k_core* cpustate, const UINT16 op, UINT8* cycles); +static size_t dsp56k_op_ori (dsp56k_core* cpustate, const UINT16 op, UINT8* cycles); +static size_t dsp56k_op_rep (dsp56k_core* cpustate, const UINT16 op, UINT8* cycles); +static size_t dsp56k_op_rep_1 (dsp56k_core* cpustate, const UINT16 op, UINT8* cycles); +static size_t dsp56k_op_rep_2 (dsp56k_core* cpustate, const UINT16 op, UINT8* cycles); +static size_t dsp56k_op_repcc (dsp56k_core* cpustate, const UINT16 op, UINT8* cycles); +static size_t dsp56k_op_reset (dsp56k_core* cpustate, const UINT16 op, UINT8* cycles); +static size_t dsp56k_op_rti (dsp56k_core* cpustate, const UINT16 op, UINT8* cycles); +static size_t dsp56k_op_rts (dsp56k_core* cpustate, const UINT16 op, UINT8* cycles); +static size_t dsp56k_op_stop (dsp56k_core* cpustate, const UINT16 op, UINT8* cycles); +static size_t dsp56k_op_swap (dsp56k_core* cpustate, const UINT16 op, UINT8* cycles); +static size_t dsp56k_op_swi (dsp56k_core* cpustate, const UINT16 op, UINT8* cycles); +static size_t dsp56k_op_tcc (dsp56k_core* cpustate, const UINT16 op, UINT8* cycles); +static size_t dsp56k_op_tfr2 (dsp56k_core* cpustate, const UINT16 op, UINT8* cycles); +static size_t dsp56k_op_tfr3 (dsp56k_core* cpustate, const UINT16 op, UINT8* cycles); +static size_t dsp56k_op_tst2 (dsp56k_core* cpustate, const UINT16 op, UINT8* cycles); +static size_t dsp56k_op_wait (dsp56k_core* cpustate, const UINT16 op, UINT8* cycles); +static size_t dsp56k_op_zero (dsp56k_core* cpustate, const UINT16 op, UINT8* cycles); + + +static void execute_register_to_register_data_move(dsp56k_core* cpustate, const UINT16 op, typed_pointer* d_register, UINT64* prev_accum_value); +static void execute_address_register_update(dsp56k_core* cpustate, const UINT16 op, typed_pointer* d_register, UINT64* prev_accum_value); +static void execute_x_memory_data_move (dsp56k_core* cpustate, const UINT16 op, typed_pointer* d_register, UINT64* prev_accum_value); +static void execute_x_memory_data_move2(dsp56k_core* cpustate, const UINT16 op, typed_pointer* d_register); +static void execute_dual_x_memory_data_read(dsp56k_core* cpustate, const UINT16 op, typed_pointer* d_register); +static void execute_x_memory_data_move_with_short_displacement(dsp56k_core* cpustate, const UINT16 op, const UINT16 op2); + +static UINT16 decode_BBB_bitmask(dsp56k_core* cpustate, UINT16 BBB, UINT16 *iVal); +static int decode_cccc_table(dsp56k_core* cpustate, UINT16 cccc); +static void decode_DDDDD_table(dsp56k_core* cpustate, UINT16 DDDDD, typed_pointer* ret); +static void decode_DD_table(dsp56k_core* cpustate, UINT16 DD, typed_pointer* ret); +static void decode_DDF_table(dsp56k_core* cpustate, UINT16 DD, UINT16 F, typed_pointer* src_ret, typed_pointer* dst_ret); +static void decode_F_table(dsp56k_core* cpustate, UINT16 F, typed_pointer* ret); +static void decode_h0hF_table(dsp56k_core* cpustate, UINT16 h0h, UINT16 F, typed_pointer* src_ret, typed_pointer* dst_ret); +static void decode_HH_table(dsp56k_core* cpustate, UINT16 HH, typed_pointer* ret); +static void decode_HHH_table(dsp56k_core* cpustate, UINT16 HHH, typed_pointer* ret); +static void decode_IIII_table(dsp56k_core* cpustate, UINT16 IIII, typed_pointer* src_ret, typed_pointer* dst_ret, void* working); +static void decode_JJJF_table(dsp56k_core* cpustate, UINT16 JJJ, UINT16 F, typed_pointer* src_ret, typed_pointer* dst_ret); +static void decode_JJF_table(dsp56k_core* cpustate, UINT16 JJ, UINT16 F, typed_pointer* src_ret, typed_pointer* dst_ret); +static void decode_JF_table(dsp56k_core* cpustate, UINT16 JJ, UINT16 F, typed_pointer* src_ret, typed_pointer* dst_ret); +static void decode_KKK_table(dsp56k_core* cpustate, UINT16 KKK, typed_pointer* dst_ret1, typed_pointer* dst_ret2, void* working); +static void decode_QQF_table(dsp56k_core* cpustate, UINT16 QQ, UINT16 F, void **S1, void **S2, void **D); +static void decode_QQF_special_table(dsp56k_core* cpustate, UINT16 QQ, UINT16 F, void **S1, void **S2, void **D); +static void decode_QQQF_table(dsp56k_core* cpustate, UINT16 QQQ, UINT16 F, void **S1, void **S2, void **D); +static void decode_RR_table(dsp56k_core* cpustate, UINT16 RR, typed_pointer* ret); +static void decode_TT_table(dsp56k_core* cpustate, UINT16 TT, typed_pointer* ret); +static void decode_uuuuF_table(dsp56k_core* cpustate, UINT16 uuuu, UINT16 F, UINT8 add_sub_other, typed_pointer* src_ret, typed_pointer* dst_ret); +static void decode_Z_table(dsp56k_core* cpustate, UINT16 Z, typed_pointer* ret); + +static void execute_m_table(dsp56k_core* cpustate, int x, UINT16 m); +static void execute_mm_table(dsp56k_core* cpustate, UINT16 rnum, UINT16 mm); +static void execute_MM_table(dsp56k_core* cpustate, UINT16 rnum, UINT16 MM); +static UINT16 execute_q_table(dsp56k_core* cpustate, int RR, UINT16 q); +static void execute_z_table(dsp56k_core* cpustate, int RR, UINT16 z); + +static UINT16 assemble_address_from_Pppppp_table(dsp56k_core* cpustate, UINT16 P, UINT16 ppppp); +static UINT16 assemble_address_from_IO_short_address(dsp56k_core* cpustate, UINT16 pp); +static UINT16 assemble_address_from_6bit_signed_relative_short_address(dsp56k_core* cpustate, UINT16 srs); + +static void dsp56k_process_loop(dsp56k_core* cpustate); +static void dsp56k_process_rep(dsp56k_core* cpustate, size_t repSize); + + + +/********************/ +/* Helper Functions */ +/********************/ +static UINT16 Dsp56kOpMask(UINT16 op, UINT16 mask); + +/* These arguments are written source->destination to fall in line with the processor's paradigm. */ +static void SetDestinationValue(typed_pointer source, typed_pointer dest); + +static void SetDataMemoryValue(dsp56k_core* cpustate, typed_pointer source, UINT32 destinationAddr); +static void SetProgramMemoryValue(dsp56k_core* cpustate, typed_pointer source, UINT32 destinationAddr); + + + +/*************************************************************************** + IMPLEMENTATION +***************************************************************************/ + +static void execute_one(dsp56k_core* cpustate) +{ + UINT16 op; + UINT16 op2; + size_t size = 0x1337; + UINT8 cycle_count = 0; + + /* For MAME */ + cpustate->op = ROPCODE(ADDRESS(PC)); + debugger_instruction_hook(cpustate->device, PC); + + /* The words we're going to be working with */ + op = ROPCODE(ADDRESS(PC)); + op2 = ROPCODE(ADDRESS(PC) + ADDRESS(1)); + + + /* DECODE */ + /* Dual X Memory Data Read : 011m mKKK .rr. .... : A-142*/ + if ((op & 0xe000) == 0x6000) + { + typed_pointer d_register = {NULL, DT_BYTE}; + + /* Quote: (MOVE, MAC(R), MPY(R), ADD, SUB, TFR) */ + UINT16 op_byte = op & 0x00ff; + + /* ADD : 011m mKKK 0rru Fuuu : A-22 */ + /* SUB : 011m mKKK 0rru Fuuu : A-202 */ + /* Note: 0x0094 check allows command to drop through to MOVE and TFR */ + if (((op & 0xe080) == 0x6000) && ((op & 0x0094) != 0x0010)) + { + size = dsp56k_op_addsub_2(cpustate, op_byte, &d_register, &cycle_count); + } + /* MAC : 011m mKKK 1xx0 F1QQ : A-122 */ + else if ((op & 0xe094) == 0x6084) + { + size = dsp56k_op_mac_1(cpustate, op_byte, &d_register, &cycle_count); + } + /* MACR: 011m mKKK 1--1 F1QQ : A-124 */ + else if ((op & 0xe094) == 0x6094) + { + size = dsp56k_op_macr_1(cpustate, op_byte, &d_register, &cycle_count); + } + /* TFR : 011m mKKK 0rr1 F0DD : A-212 */ + else if ((op & 0xe094) == 0x6010) + { + size = dsp56k_op_tfr_2(cpustate, op_byte, &d_register, &cycle_count); + } + /* MOVE : 011m mKKK 0rr1 0000 : A-128 */ + else if ((op & 0xe09f) == 0x6010) + { + /* Note: The opcode encoding : 011x xxxx 0xx1 0000 (move + double memory read) + is .identical. to (tfr X0,A + two parallel reads). This sparks the notion + that these 'move' opcodes don't actually exist and are just there as + documentation. Real-world examples would need to be examined to come + to a satisfactory conclusion, but as it stands, tfr will override this + move operation. */ + size = dsp56k_op_move_1(cpustate, op_byte, &d_register, &cycle_count); + } + /* MPY : 011m mKKK 1xx0 F0QQ : A-160 */ + else if ((op & 0xe094) == 0x6080) + { + size = dsp56k_op_mpy_1(cpustate, op_byte, &d_register, &cycle_count); + } + /* MPYR : 011m mKKK 1--1 F0QQ : A-162 */ + else if ((op & 0xe094) == 0x6090) + { + size = dsp56k_op_mpyr_1(cpustate, op_byte, &d_register, &cycle_count); + } + + /* Now evaluate the parallel data move */ + execute_dual_x_memory_data_read(cpustate, op, &d_register); + } + /* X Memory Data Write and Register Data Move : 0001 011k RRDD .... : A-140 */ + else if ((op & 0xfe00) == 0x1600) + { + /* Quote: (MPY or MAC) */ + UINT16 op_byte = op & 0x00ff; + + /* MPY : 0001 0110 RRDD FQQQ : A-160 */ + if ((op & 0xff00) == 0x1600) + { + size = dsp56k_op_mpy_2(cpustate, op_byte, &cycle_count); + } + /* MAC : 0001 0111 RRDD FQQQ : A-122 */ + else if ((op & 0xff00) == 0x1700) + { + size = dsp56k_op_mac_2(cpustate, op_byte, &cycle_count); + } + + /* Now evaluate the parallel data move */ + /* TODO // decode_x_memory_data_write_and_register_data_move(op, parallel_move_str, parallel_move_str2); */ + logerror("DSP56k: Unemulated Dual X Memory Data And Register Data Move @ 0x%x\n", PC); + } + + /* Handle Other parallel types */ + else + { + /***************************************/ + /* 32 General parallel move operations */ + /***************************************/ + + enum pType { kNoParallelDataMove, + kRegisterToRegister, + kAddressRegister, + kXMemoryDataMove, + kXMemoryDataMove2, + kXMemoryDataMoveWithDisp }; + + int parallelType = -1; + UINT16 op_byte = 0x0000; + typed_pointer d_register = {NULL, DT_BYTE}; + UINT64 prev_accum_value = U64(0x0000000000000000); + + /* Note: it's important that NPDM comes before RtRDM here */ + /* No Parallel Data Move : 0100 1010 .... .... : A-131 */ + if ((op & 0xff00) == 0x4a00) + { + op_byte = op & 0x00ff; + parallelType = kNoParallelDataMove; + } + /* Register to Register Data Move : 0100 IIII .... .... : A-133 */ + else if ((op & 0xf000) == 0x4000) + { + op_byte = op & 0x00ff; + parallelType = kRegisterToRegister; + } + /* Address Register Update : 0011 0zRR .... .... : A-135 */ + else if ((op & 0xf800) == 0x3000) + { + op_byte = op & 0x00ff; + parallelType = kAddressRegister; + } + /* X Memory Data Move : 1mRR HHHW .... .... : A-137 */ + else if ((op & 0x8000) == 0x8000) + { + op_byte = op & 0x00ff; + parallelType = kXMemoryDataMove; + } + /* X Memory Data Move : 0101 HHHW .... .... : A-137 */ + else if ((op & 0xf000) == 0x5000) + { + op_byte = op & 0x00ff; + parallelType = kXMemoryDataMove2; + } + /* X Memory Data Move with short displacement : 0000 0101 BBBB BBBB ---- HHHW .... .... : A-139 */ + else if ((op & 0xff00) == 0x0500) + { + /* Now check it against all the other potential collisions */ + /* This is necessary because "don't care bits" get in the way. */ + /* + MOVE(M) : 0000 0101 BBBB BBBB 0000 001W --0- -HHH : A-152 + MOVE(C) : 0000 0101 BBBB BBBB 0011 1WDD DDD0 ---- : A-144 + MOVE : 0000 0101 BBBB BBBB ---- HHHW 0001 0001 : A-128 + */ + if (((op2 & 0xfe20) != 0x0200) && + ((op2 & 0xf810) != 0x3800) && + ((op2 & 0x00ff) != 0x0011)) + { + op_byte = op2 & 0x00ff; + parallelType = kXMemoryDataMoveWithDisp; + } + } + + + if (parallelType != -1) + { + /* Note: There is much overlap between opcodes down here */ + /* To this end, certain ops must come before others in the list */ + + /* CLR : .... .... 0000 F001 : A-60 */ + if ((op_byte & 0x00f7) == 0x0001) + { + size = dsp56k_op_clr(cpustate, op_byte, &d_register, &prev_accum_value, &cycle_count); + } + /* ADD : .... .... 0000 FJJJ : A-22 */ + else if ((op_byte & 0x00f0) == 0x0000) + { + size = dsp56k_op_add(cpustate, op_byte, &d_register, &prev_accum_value, &cycle_count); + } + + + /* MOVE : .... .... 0001 0001 : A-128 */ + else if ((op_byte & 0x00ff) == 0x0011) + { + size = dsp56k_op_move(cpustate, op_byte, &d_register, &prev_accum_value, &cycle_count); + } + /* TFR : .... .... 0001 FJJJ : A-212 */ + else if ((op_byte & 0x00f0) == 0x0010) + { + size = dsp56k_op_tfr(cpustate, op_byte, &d_register, &prev_accum_value, &cycle_count); + } + + + /* RND : .... .... 0010 F000 : A-188 */ + else if ((op_byte & 0x00f7) == 0x0020) + { + size = dsp56k_op_rnd(cpustate, op_byte, &d_register, &prev_accum_value, &cycle_count); + } + /* TST : .... .... 0010 F001 : A-218 */ + else if ((op_byte & 0x00f7) == 0x0021) + { + size = dsp56k_op_tst(cpustate, op_byte, &d_register, &prev_accum_value, &cycle_count); + } + /* INC : .... .... 0010 F010 : A-104 */ + else if ((op_byte & 0x00f7) == 0x0022) + { + size = dsp56k_op_inc(cpustate, op_byte, &d_register, &prev_accum_value, &cycle_count); + } + /* INC24 : .... .... 0010 F011 : A-106 */ + else if ((op_byte & 0x00f7) == 0x0023) + { + size = dsp56k_op_inc24(cpustate, op_byte, &d_register, &prev_accum_value, &cycle_count); + } + /* OR : .... .... 0010 F1JJ : A-176 */ + else if ((op_byte & 0x00f4) == 0x0024) + { + size = dsp56k_op_or(cpustate, op_byte, &d_register, &prev_accum_value, &cycle_count); + } + + + /* ASR : .... .... 0011 F000 : A-32 */ + else if ((op_byte & 0x00f7) == 0x0030) + { + size = dsp56k_op_asr(cpustate, op_byte, &d_register, &prev_accum_value, &cycle_count); + } + /* ASL : .... .... 0011 F001 : A-28 */ + else if ((op_byte & 0x00f7) == 0x0031) + { + size = dsp56k_op_asl(cpustate, op_byte, &d_register, &prev_accum_value, &cycle_count); + } + /* LSR : .... .... 0011 F010 : A-120 */ + else if ((op_byte & 0x00f7) == 0x0032) + { + size = dsp56k_op_lsr(cpustate, op_byte, &d_register, &prev_accum_value, &cycle_count); + } + /* LSL : .... .... 0011 F011 : A-118 */ + else if ((op_byte & 0x00f7) == 0x0033) + { + size = dsp56k_op_lsl(cpustate, op_byte, &d_register, &prev_accum_value, &cycle_count); + } + /* EOR : .... .... 0011 F1JJ : A-94 */ + else if ((op_byte & 0x00f4) == 0x0034) + { + size = dsp56k_op_eor(cpustate, op_byte, &d_register, &prev_accum_value, &cycle_count); + } + + + /* SUBL : .... .... 0100 F001 : A-204 */ + else if ((op_byte & 0x00f7) == 0x0041) + { + size = dsp56k_op_subl(cpustate, op_byte, &d_register, &prev_accum_value, &cycle_count); + } + /* SUB : .... .... 0100 FJJJ : A-202 */ + else if ((op_byte & 0x00f0) == 0x0040) + { + size = dsp56k_op_sub(cpustate, op_byte, &d_register, &prev_accum_value, &cycle_count); + } + + + /* CLR24 : .... .... 0101 F001 : A-62 */ + else if ((op_byte & 0x00f7) == 0x0051) + { + size = dsp56k_op_clr24(cpustate, op_byte, &d_register, &prev_accum_value, &cycle_count); + } + /* SBC : .... .... 0101 F01J : A-198 */ + else if ((op_byte & 0x00f6) == 0x0052) + { + size = dsp56k_op_sbc(cpustate, op_byte, &d_register, &prev_accum_value, &cycle_count); + } + /* CMP : .... .... 0101 FJJJ : A-64 */ + else if ((op_byte & 0x00f0) == 0x0050) + { + size = dsp56k_op_cmp(cpustate, op_byte, &d_register, &prev_accum_value, &cycle_count); + } + + + /* NEG : .... .... 0110 F000 : A-166 */ + else if ((op_byte & 0x00f7) == 0x0060) + { + size = dsp56k_op_neg(cpustate, op_byte, &d_register, &prev_accum_value, &cycle_count); + } + /* NOT : .... .... 0110 F001 : A-174 */ + else if ((op_byte & 0x00f7) == 0x0061) + { + size = dsp56k_op_not(cpustate, op_byte, &d_register, &prev_accum_value, &cycle_count); + } + /* DEC : .... .... 0110 F010 : A-72 */ + else if ((op_byte & 0x00f7) == 0x0062) + { + size = dsp56k_op_dec(cpustate, op_byte, &d_register, &prev_accum_value, &cycle_count); + } + /* DEC24 : .... .... 0110 F011 : A-74 */ + else if ((op_byte & 0x00f7) == 0x0063) + { + size = dsp56k_op_dec24(cpustate, op_byte, &d_register, &prev_accum_value, &cycle_count); + } + /* AND : .... .... 0110 F1JJ : A-24 */ + else if ((op_byte & 0x00f4) == 0x0064) + { + size = dsp56k_op_and(cpustate, op_byte, &d_register, &prev_accum_value, &cycle_count); + } + + + /* ABS : .... .... 0111 F001 : A-18 */ + if ((op_byte & 0x00f7) == 0x0071) + { + size = dsp56k_op_abs(cpustate, op_byte, &d_register, &prev_accum_value, &cycle_count); + } + /* ROR : .... .... 0111 F010 : A-192 */ + else if ((op_byte & 0x00f7) == 0x0072) + { + size = dsp56k_op_ror(cpustate, op_byte, &d_register, &prev_accum_value, &cycle_count); + } + /* ROL : .... .... 0111 F011 : A-190 */ + else if ((op_byte & 0x00f7) == 0x0073) + { + size = dsp56k_op_rol(cpustate, op_byte, &d_register, &prev_accum_value, &cycle_count); + } + /* CMPM : .... .... 0111 FJJJ : A-66 */ + else if ((op_byte & 0x00f0) == 0x0070) + { + size = dsp56k_op_cmpm(cpustate, op_byte, &d_register, &prev_accum_value, &cycle_count); + } + + + /* MPY : .... .... 1k00 FQQQ : A-160 -- CONFIRMED TYPO IN DOCS (HHHH vs HHHW) */ + else if ((op_byte & 0x00b0) == 0x0080) + { + size = dsp56k_op_mpy(cpustate, op_byte, &d_register, &prev_accum_value, &cycle_count); + } + /* MPYR : .... .... 1k01 FQQQ : A-162 */ + else if ((op_byte & 0x00b0) == 0x0090) + { + size = dsp56k_op_mpyr(cpustate, op_byte, &d_register, &prev_accum_value, &cycle_count); + } + /* MAC : .... .... 1k10 FQQQ : A-122 */ + else if ((op_byte & 0x00b0) == 0x00a0) + { + size = dsp56k_op_mac(cpustate, op_byte, &d_register, &prev_accum_value, &cycle_count); + } + /* MACR : .... .... 1k11 FQQQ : A-124 -- DRAMA - rr vs xx (805) */ + else if ((op_byte & 0x00b0) == 0x00b0) + { + size = dsp56k_op_macr(cpustate, op_byte, &d_register, &prev_accum_value, &cycle_count); + } + + + /* Now evaluate the parallel data move */ + switch (parallelType) + { + case kNoParallelDataMove: + /* DO NOTHING */ + break; + case kRegisterToRegister: + execute_register_to_register_data_move(cpustate, op, &d_register, &prev_accum_value); + break; + case kAddressRegister: + execute_address_register_update(cpustate, op, &d_register, &prev_accum_value); + break; + case kXMemoryDataMove: + execute_x_memory_data_move(cpustate, op, &d_register, &prev_accum_value); + break; + case kXMemoryDataMove2: + execute_x_memory_data_move2(cpustate, op, &d_register); + break; + case kXMemoryDataMoveWithDisp: + execute_x_memory_data_move_with_short_displacement(cpustate, op, op2); + size = 2; + break; + } + } + } + + /* Drop out if you've already completed your work. */ + if (size != 0x1337) + { + PC += (UINT16)size; + + dsp56k_process_loop(cpustate); + dsp56k_process_rep(cpustate, size); + + cpustate->icount -= 4; /* Temporarily hard-coded at 4 clocks per opcode */ /* cycle_count */ + return; + } + + + /******************************/ + /* Remaining non-parallel ops */ + /******************************/ + + /* ADC : 0001 0101 0000 F01J : A-20 */ + if ((op & 0xfff6) == 0x1502) + { + size = dsp56k_op_adc(cpustate, op, &cycle_count); + } + /* ANDI : 0001 1EE0 iiii iiii : A-26 */ + /* (MoveP sneaks in here if you don't check 0x0600) */ + else if (((op & 0xf900) == 0x1800) & ((op & 0x0600) != 0x0000)) + { + size = dsp56k_op_andi(cpustate, op, &cycle_count); + } + /* ASL4 : 0001 0101 0011 F001 : A-30 */ + else if ((op & 0xfff7) == 0x1531) + { + size = dsp56k_op_asl4(cpustate, op, &cycle_count); + } + /* ASR4 : 0001 0101 0011 F000 : A-34 */ + else if ((op & 0xfff7) == 0x1530) + { + size = dsp56k_op_asr4(cpustate, op, &cycle_count); + } + /* ASR16 : 0001 0101 0111 F000 : A-36 */ + else if ((op & 0xfff7) == 0x1570) + { + size = dsp56k_op_asr16(cpustate, op, &cycle_count); + } + /* BFCHG : 0001 0100 11Pp pppp BBB1 0010 iiii iiii : A-38 */ + else if (((op & 0xffc0) == 0x14c0) && ((op2 & 0x1f00) == 0x1200)) + { + size = dsp56k_op_bfop(cpustate, op, op2, &cycle_count); + } + /* BFCHG : 0001 0100 101- --RR BBB1 0010 iiii iiii : A-38 */ + else if (((op & 0xffe0) == 0x14a0) && ((op2 & 0x1f00) == 0x1200)) + { + size = dsp56k_op_bfop_1(cpustate, op, op2, &cycle_count); + } + /* BFCHG : 0001 0100 100D DDDD BBB1 0010 iiii iiii : A-38 */ + else if (((op & 0xffe0) == 0x1480) && ((op2 & 0x1f00) == 0x1200)) + { + size = dsp56k_op_bfop_2(cpustate, op, op2, &cycle_count); + } + /* BFCLR : 0001 0100 11Pp pppp BBB0 0100 iiii iiii : A-40 */ + else if (((op & 0xffc0) == 0x14c0) && ((op2 & 0x1f00) == 0x0400)) + { + size = dsp56k_op_bfop(cpustate, op, op2, &cycle_count); + } + /* BFCLR : 0001 0100 101- --RR BBB0 0100 iiii iiii : A-40 */ + else if (((op & 0xffe0) == 0x14a0) && ((op2 & 0x1f00) == 0x0400)) + { + size = dsp56k_op_bfop_1(cpustate, op, op2, &cycle_count); + } + /* BFCLR : 0001 0100 100D DDDD BBB0 0100 iiii iiii : A-40 */ + else if (((op & 0xffe0) == 0x1480) && ((op2 & 0x1f00) == 0x0400)) + { + size = dsp56k_op_bfop_2(cpustate, op, op2, &cycle_count); + } + /* BFSET : 0001 0100 11Pp pppp BBB1 1000 iiii iiii : A-42 */ + else if (((op & 0xffc0) == 0x14c0) && ((op2 & 0x1f00) == 0x1800)) + { + size = dsp56k_op_bfop(cpustate, op, op2, &cycle_count); + } + /* BFSET : 0001 0100 101- --RR BBB1 1000 iiii iiii : A-42 */ + else if (((op & 0xffe0) == 0x14a0) && ((op2 & 0x1f00) == 0x1800)) + { + size = dsp56k_op_bfop_1(cpustate, op, op2, &cycle_count); + } + /* BFSET : 0001 0100 100D DDDD BBB1 1000 iiii iiii : A-42 */ + else if (((op & 0xffe0) == 0x1480) && ((op2 & 0x1f00) == 0x1800)) + { + size = dsp56k_op_bfop_2(cpustate, op, op2, &cycle_count); + } + /* BFTSTH : 0001 0100 01Pp pppp BBB1 0000 iiii iiii : A-44 */ + else if (((op & 0xffc0) == 0x1440) && ((op2 & 0x1f00) == 0x1000)) + { + size = dsp56k_op_bfop(cpustate, op, op2, &cycle_count); + } + /* BFTSTH : 0001 0100 001- --RR BBB1 0000 iiii iiii : A-44 */ + else if (((op & 0xffe0) == 0x1420) && ((op2 & 0x1f00) == 0x1000)) + { + size = dsp56k_op_bfop_1(cpustate, op, op2, &cycle_count); + } + /* BFTSTH : 0001 0100 000D DDDD BBB1 0000 iiii iiii : A-44 */ + else if (((op & 0xffe0) == 0x1400) && ((op2 & 0x1f00) == 0x1000)) + { + size = dsp56k_op_bfop_2(cpustate, op, op2, &cycle_count); + } + /* BFTSTL : 0001 0100 01Pp pppp BBB0 0000 iiii iiii : A-46 */ + else if (((op & 0xffc0) == 0x1440) && ((op2 & 0x1f00) == 0x0000)) + { + size = dsp56k_op_bfop(cpustate, op, op2, &cycle_count); + } + /* BFTSTL : 0001 0100 001- --RR BBB0 0000 iiii iiii : A-46 */ + else if (((op & 0xffe0) == 0x1420) && ((op2 & 0x1f00) == 0x0000)) + { + size = dsp56k_op_bfop_1(cpustate, op, op2, &cycle_count); + } + /* BFTSTL : 0001 0100 000D DDDD BBB0 0000 iiii iiii : A-46 */ + else if (((op & 0xffe0) == 0x1400) && ((op2 & 0x1f00) == 0x0000)) + { + size = dsp56k_op_bfop_2(cpustate, op, op2, &cycle_count); + } + /* Bcc : 0000 0111 --11 cccc xxxx xxxx xxxx xxxx : A-48 */ + else if (((op & 0xff30) == 0x0730) && ((op2 & 0x0000) == 0x0000)) + { + size = dsp56k_op_bcc(cpustate, op, op2, &cycle_count); + } + /* Bcc : 0010 11cc ccee eeee : A-48 */ + else if ((op & 0xfc00) == 0x2c00) + { + size = dsp56k_op_bcc_1(cpustate, op, &cycle_count); + } + /* Bcc : 0000 0111 RR10 cccc : A-48 */ + else if ((op & 0xff30) == 0x0720) + { + size = dsp56k_op_bcc_2(cpustate, op, &cycle_count); + } + /* BRA : 0000 0001 0011 11-- xxxx xxxx xxxx xxxx : A-50 */ + else if (((op & 0xfffc) == 0x013c) && ((op2 & 0x0000) == 0x0000)) + { + size = dsp56k_op_bra(cpustate, op, op2, &cycle_count); + } + /* BRA : 0000 1011 aaaa aaaa : A-50 */ + else if ((op & 0xff00) == 0x0b00) + { + size = dsp56k_op_bra_1(cpustate, op, &cycle_count); + } + /* BRA : 0000 0001 0010 11RR : A-50 */ + else if ((op & 0xfffc) == 0x012c) + { + size = dsp56k_op_bra_2(cpustate, op, &cycle_count); + } + /* BRKc : 0000 0001 0001 cccc : A-52 */ + else if ((op & 0xfff0) == 0x0110) + { + size = dsp56k_op_brkcc(cpustate, op, &cycle_count); + } + /* BScc : 0000 0111 --01 cccc xxxx xxxx xxxx xxxx : A-54 */ + else if (((op & 0xff30) == 0x0710) && ((op2 & 0x0000) == 0x0000)) + { + size = dsp56k_op_bscc(cpustate, op, op2, &cycle_count); + } + /* BScc : 0000 0111 RR00 cccc : A-54 */ + else if ((op & 0xff30) == 0x0700) + { + size = dsp56k_op_bscc_1(cpustate, op, &cycle_count); + } + /* BSR : 0000 0001 0011 10-- xxxx xxxx xxxx xxxx : A-56 */ + else if (((op & 0xfffc) == 0x0138) && ((op2 & 0x0000) == 0x0000)) + { + size = dsp56k_op_bsr(cpustate, op, op2, &cycle_count); + } + /* BSR : 0000 0001 0010 10RR : A-56 */ + else if ((op & 0xfffc) == 0x0128) + { + size = dsp56k_op_bsr_1(cpustate, op, &cycle_count); + } + /* CHKAAU : 0000 0000 0000 0100 : A-58 */ + else if ((op & 0xffff) == 0x0004) + { + size = dsp56k_op_chkaau(cpustate, op, &cycle_count); + } + /* DEBUG : 0000 0000 0000 0001 : A-68 */ + else if ((op & 0xffff) == 0x0001) + { + size = dsp56k_op_debug(cpustate, op, &cycle_count); + } + /* DEBUGcc : 0000 0000 0101 cccc : A-70 */ + else if ((op & 0xfff0) == 0x0050) + { + size = dsp56k_op_debugcc(cpustate, op, &cycle_count); + } + /* DIV : 0001 0101 0--0 F1DD : A-76 */ + else if ((op & 0xff94) == 0x1504) + { + size = dsp56k_op_div(cpustate, op, &cycle_count); + } + /* DMAC : 0001 0101 10s1 FsQQ : A-80 */ + else if ((op & 0xffd0) == 0x1590) + { + size = dsp56k_op_dmac(cpustate, op, &cycle_count); + } + /* DO : 0000 0000 110- --RR xxxx xxxx xxxx xxxx : A-82 */ + else if (((op & 0xffe0) == 0x00c0) && ((op2 & 0x0000) == 0x0000)) + { + size = dsp56k_op_do(cpustate, op, op2, &cycle_count); + } + /* DO : 0000 1110 iiii iiii xxxx xxxx xxxx xxxx : A-82 */ + else if (((op & 0xff00) == 0x0e00) && ((op2 & 0x0000) == 0x0000)) + { + size = dsp56k_op_do_1(cpustate, op, op2, &cycle_count); + } + /* DO : 0000 0100 000D DDDD xxxx xxxx xxxx xxxx : A-82 */ + else if (((op & 0xffe0) == 0x0400) && ((op2 & 0x0000) == 0x0000)) + { + size = dsp56k_op_do_2(cpustate, op, op2, &cycle_count); + } + /* DO FOREVER : 0000 0000 0000 0010 xxxx xxxx xxxx xxxx : A-88 */ + else if (((op & 0xffff) == 0x0002) && ((op2 & 0x0000) == 0x0000)) + { + size = dsp56k_op_doforever(cpustate, op, op2, &cycle_count); + } + /* ENDDO : 0000 0000 0000 1001 : A-92 */ + else if ((op & 0xffff) == 0x0009) + { + size = dsp56k_op_enddo(cpustate, op, &cycle_count); + } + /* EXT : 0001 0101 0101 F010 : A-96 */ + else if ((op & 0xfff7) == 0x1552) + { + size = dsp56k_op_ext(cpustate, op, &cycle_count); + } + /* ILLEGAL : 0000 0000 0000 1111 : A-98 */ + else if ((op & 0xffff) == 0x000f) + { + size = dsp56k_op_illegal(cpustate, op, &cycle_count); + } + /* IMAC : 0001 0101 1010 FQQQ : A-100 */ + else if ((op & 0xfff0) == 0x15a0) + { + size = dsp56k_op_imac(cpustate, op, &cycle_count); + } + /* IMPY : 0001 0101 1000 FQQQ : A-102 */ + else if ((op & 0xfff0) == 0x1580) + { + size = dsp56k_op_impy(cpustate, op, &cycle_count); + } + /* Jcc : 0000 0110 --11 cccc xxxx xxxx xxxx xxxx : A-108 */ + else if (((op & 0xff30) == 0x0630) && ((op2 & 0x0000) == 0x0000)) + { + size = dsp56k_op_jcc(cpustate, op, op2, &cycle_count); + } + /* Jcc : 0000 0110 RR10 cccc : A-108 */ + else if ((op & 0xff30) == 0x0620 ) + { + size = dsp56k_op_jcc_1(cpustate, op, &cycle_count); + } + /* JMP : 0000 0001 0011 01-- xxxx xxxx xxxx xxxx : A-110 */ + else if (((op & 0xfffc) == 0x0134) && ((op2 & 0x0000) == 0x0000)) + { + size = dsp56k_op_jmp(cpustate, op, op2, &cycle_count); + } + /* JMP : 0000 0001 0010 01RR : A-110 */ + else if ((op & 0xfffc) == 0x0124) + { + size = dsp56k_op_jmp_1(cpustate, op, &cycle_count); + } + /* JScc : 0000 0110 --01 cccc xxxx xxxx xxxx xxxx : A-112 */ + else if (((op & 0xff30) == 0x0610) && ((op2 & 0x0000) == 0x0000)) + { + size = dsp56k_op_jscc(cpustate, op, op2, &cycle_count); + } + /* JScc : 0000 0110 RR00 cccc : A-112 */ + else if ((op & 0xff30) == 0x0600) + { + size = dsp56k_op_jscc_1(cpustate, op, &cycle_count); + } + /* JSR : 0000 0001 0011 00-- xxxx xxxx xxxx xxxx : A-114 */ + else if (((op & 0xfffc) == 0x0130) && ((op2 & 0x0000) == 0x0000)) + { + size = dsp56k_op_jsr(cpustate, op, op2, &cycle_count); + } + /* JSR : 0000 1010 AAAA AAAA : A-114 */ + else if ((op & 0xff00) == 0x0a00) + { + size = dsp56k_op_jsr_1(cpustate, op, &cycle_count); + } + /* JSR : 0000 0001 0010 00RR : A-114 */ + else if ((op & 0xfffc) == 0x0120) + { + size = dsp56k_op_jsr_2(cpustate, op, &cycle_count); + } + /* LEA : 0000 0001 11TT MMRR : A-116 */ + else if ((op & 0xffc0) == 0x01c0) + { + size = dsp56k_op_lea(cpustate, op, &cycle_count); + } + /* LEA : 0000 0001 10NN MMRR : A-116 */ + else if ((op & 0xffc0) == 0x0180) + { + size = dsp56k_op_lea_1(cpustate, op, &cycle_count); + } + /* MAC(su,uu) : 0001 0101 1110 FsQQ : A-126 */ + else if ((op & 0xfff0) == 0x15e0) + { + size = dsp56k_op_macsuuu(cpustate, op, &cycle_count); + } + /* MOVE : 0000 0101 BBBB BBBB ---- HHHW 0001 0001 : A-128 */ + else if (((op & 0xff00) == 0x0500) && ((op2 & 0x00ff) == 0x0011)) + { + size = dsp56k_op_move_2(cpustate, op, op2, &cycle_count); + } + /* MOVE(C) : 0011 1WDD DDD0 MMRR : A-144 */ + else if ((op & 0xf810) == 0x3800) + { + size = dsp56k_op_movec(cpustate, op, &cycle_count); + } + /* MOVE(C) : 0011 1WDD DDD1 q0RR : A-144 */ + else if ((op & 0xf814) == 0x3810) + { + size = dsp56k_op_movec_1(cpustate, op, &cycle_count); + } + /* MOVE(C) : 0011 1WDD DDD1 Z11- : A-144 */ + else if ((op & 0xf816) == 0x3816) + { + size = dsp56k_op_movec_2(cpustate, op, &cycle_count); + } + /* MOVE(C) : 0011 1WDD DDD1 t10- xxxx xxxx xxxx xxxx : A-144 */ + else if (((op & 0xf816) == 0x3814) && ((op2 & 0x0000) == 0x0000)) + { + size = dsp56k_op_movec_3(cpustate, op, op2, &cycle_count); + } + /* MOVE(C) : 0010 10dd dddD DDDD : A-144 */ + else if ((op & 0xfc00) == 0x2800) + { + size = dsp56k_op_movec_4(cpustate, op, &cycle_count); + } + /* MOVE(C) : 0000 0101 BBBB BBBB 0011 1WDD DDD0 ---- : A-144 */ + else if (((op & 0xff00) == 0x0500) && ((op2 & 0xf810) == 0x3800)) + { + size = dsp56k_op_movec_5(cpustate, op, op2, &cycle_count); + } + /* MOVE(I) : 0010 00DD BBBB BBBB : A-150 */ + else if ((op & 0xfc00) == 0x2000) + { + size = dsp56k_op_movei(cpustate, op, &cycle_count); + } + /* MOVE(M) : 0000 001W RR0M MHHH : A-152 */ + else if ((op & 0xfe20) == 0x0200) + { + size = dsp56k_op_movem(cpustate, op, &cycle_count); + } + /* MOVE(M) : 0000 001W RR11 mmRR : A-152 */ + else if ((op & 0xfe30) == 0x0230) + { + size = dsp56k_op_movem_1(cpustate, op, &cycle_count); + } + /* MOVE(M) : 0000 0101 BBBB BBBB 0000 001W --0- -HHH : A-152 */ + else if (((op & 0xff00) == 0x0500) && ((op2 & 0xfe20) == 0x0200)) + { + size = dsp56k_op_movem_2(cpustate, op, op2, &cycle_count); + } + /* MOVE(P) : 0001 100W HH1p pppp : A-156 */ + else if ((op & 0xfe20) == 0x1820) + { + size = dsp56k_op_movep(cpustate, op, &cycle_count); + } + /* MOVE(P) : 0000 110W RRmp pppp : A-156 */ + else if ((op & 0xfe00) == 0x0c00) + { + size = dsp56k_op_movep_1(cpustate, op, &cycle_count); + } + /* MOVE(S) : 0001 100W HH0a aaaa : A-158 */ + else if ((op & 0xfe20) == 0x1800) + { + size = dsp56k_op_moves(cpustate, op, &cycle_count); + } + /* MPY(su,uu) : 0001 0101 1100 FsQQ : A-164 */ + else if ((op & 0xfff0) == 0x15c0) + { + size = dsp56k_op_mpysuuu(cpustate, op, &cycle_count); + } + /* NEGC : 0001 0101 0110 F000 : A-168 */ + else if ((op & 0xfff7) == 0x1560) + { + size = dsp56k_op_negc(cpustate, op, &cycle_count); + } + /* NOP : 0000 0000 0000 0000 : A-170 */ + else if ((op & 0xffff) == 0x0000) + { + size = dsp56k_op_nop(cpustate, op, &cycle_count); + } + /* NORM : 0001 0101 0010 F0RR : A-172 */ + else if ((op & 0xfff4) == 0x1520) + { + size = dsp56k_op_norm(cpustate, op, &cycle_count); + } + /* ORI : 0001 1EE1 iiii iiii : A-178 */ + else if ((op & 0xf900) == 0x1900) + { + size = dsp56k_op_ori(cpustate, op, &cycle_count); + } + /* REP : 0000 0000 111- --RR : A-180 */ + else if ((op & 0xffe0) == 0x00e0) + { + size = dsp56k_op_rep(cpustate, op, &cycle_count); + } + /* REP : 0000 1111 iiii iiii : A-180 */ + else if ((op & 0xff00) == 0x0f00) + { + size = dsp56k_op_rep_1(cpustate, op, &cycle_count); + } + /* REP : 0000 0100 001D DDDD : A-180 */ + else if ((op & 0xffe0) == 0x0420) + { + size = dsp56k_op_rep_2(cpustate, op, &cycle_count); + } + /* REPcc : 0000 0001 0101 cccc : A-184 */ + else if ((op & 0xfff0) == 0x0150) + { + size = dsp56k_op_repcc(cpustate, op, &cycle_count); + } + /* RESET : 0000 0000 0000 1000 : A-186 */ + else if ((op & 0xffff) == 0x0008) + { + size = dsp56k_op_reset(cpustate, op, &cycle_count); + } + /* RTI : 0000 0000 0000 0111 : A-194 */ + else if ((op & 0xffff) == 0x0007) + { + size = dsp56k_op_rti(cpustate, op, &cycle_count); + } + /* RTS : 0000 0000 0000 0110 : A-196 */ + else if ((op & 0xffff) == 0x0006) + { + size = dsp56k_op_rts(cpustate, op, &cycle_count); + } + /* STOP : 0000 0000 0000 1010 : A-200 */ + else if ((op & 0xffff) == 0x000a) + { + size = dsp56k_op_stop(cpustate, op, &cycle_count); + } + /* SWAP : 0001 0101 0111 F001 : A-206 */ + else if ((op & 0xfff7) == 0x1571) + { + size = dsp56k_op_swap(cpustate, op, &cycle_count); + } + /* SWI : 0000 0000 0000 0101 : A-208 */ + else if ((op & 0xffff) == 0x0005) + { + size = dsp56k_op_swi(cpustate, op, &cycle_count); + } + /* Tcc : 0001 00cc ccTT Fh0h : A-210 */ + else if ((op & 0xfc02) == 0x1000) + { + size = dsp56k_op_tcc(cpustate, op, &cycle_count); + } + /* TFR(2) : 0001 0101 0000 F00J : A-214 */ + else if ((op & 0xfff6) == 0x1500) + { + size = dsp56k_op_tfr2(cpustate, op, &cycle_count); + } + /* TFR(3) : 0010 01mW RRDD FHHH : A-216 */ + else if ((op & 0xfc00) == 0x2400) + { + size = dsp56k_op_tfr3(cpustate, op, &cycle_count); + } + /* TST(2) : 0001 0101 0001 -1DD : A-220 */ + else if ((op & 0xfff4) == 0x1514) + { + size = dsp56k_op_tst2(cpustate, op, &cycle_count); + } + /* WAIT : 0000 0000 0000 1011 : A-222 */ + else if ((op & 0xffff) == 0x000b) + { + size = dsp56k_op_wait(cpustate, op, &cycle_count); + } + /* ZERO : 0001 0101 0101 F000 : A-224 */ + else if ((op & 0xfff7) == 0x1550) + { + size = dsp56k_op_zero(cpustate, op, &cycle_count); + } + + + /* Not recognized? Nudge debugger onto the next word */ + if (size == 0x1337) + { + logerror("DSP56k: Unimplemented opcode at 0x%04x : %04x\n", PC, op); + size = 1 ; /* Just to get the debugger past the bad opcode */ + } + + /* Must have been a good opcode */ + PC += (UINT16)size; + + dsp56k_process_loop(cpustate); + dsp56k_process_rep(cpustate, size); + + cpustate->icount -= 4; /* Temporarily hard-coded at 4 clocks per opcode */ /* cycle_count */ +} + + + + +/*************************************************************************** + Opcode implementations +***************************************************************************/ + +/*******************************/ +/* 32 Parallel move operations */ +/*******************************/ + +/* ADD : 011m mKKK 0rru Fuuu : A-22 */ +/* SUB : 011m mKKK 0rru Fuuu : A-202 */ +static size_t dsp56k_op_addsub_2(dsp56k_core* cpustate, const UINT16 op_byte, typed_pointer* d_register, UINT8* cycles) +{ + UINT64 useVal = 0; + UINT8 op_type = OP_OTHER; + typed_pointer S = {NULL, DT_BYTE}; + typed_pointer D = {NULL, DT_BYTE}; + + decode_uuuuF_table(cpustate, BITS(op_byte,0x0017), BITS(op_byte,0x0008), op_type, &S, &D); + + /* If you gave an invalid operation type, presume it's a nop and move on with the parallel move */ + if (op_type == OP_OTHER) + { + d_register->addr = NULL; + d_register->data_type = DT_BYTE; + cycles += 2; + return 1; + } + + /* It's a real operation. Get on with it. */ + switch(S.data_type) + { + case DT_WORD: useVal = (UINT64)*((UINT16*)S.addr) << 16; break; + case DT_DOUBLE_WORD: useVal = (UINT64)*((UINT32*)S.addr); break; + case DT_LONG_WORD: useVal = (UINT64)*((UINT64*)S.addr); break; + } + + /* Sign-extend word for proper add/sub op */ + if ((S.data_type == DT_WORD) && useVal & U64(0x0000000080000000)) + useVal |= U64(0x000000ff00000000); + + /* Operate*/ + if (op_type == OP_ADD) + *((UINT64*)D.addr) += useVal; + else if (op_type == OP_SUB) + *((UINT64*)D.addr) -= useVal; + + d_register->addr = D.addr; + d_register->data_type = D.data_type; + + /* S L E U N Z V C */ + /* * * * * * * * * */ + /* TODO S, L, E, U, V, C */ + if (*((UINT64*)D.addr) & U64(0x0000008000000000)) DSP56K_N_SET(); else DSP56K_N_CLEAR(); + if (*((UINT64*)D.addr) == 0) DSP56K_Z_SET(); else DSP56K_Z_CLEAR(); + + cycles += 2; /* TODO: + mv oscillator cycles */ + return 1; +} + +/* MAC : 011m mKKK 1xx0 F1QQ : A-122 */ +static size_t dsp56k_op_mac_1(dsp56k_core* cpustate, const UINT16 op_byte, typed_pointer* d_register, UINT8* cycles) +{ + INT64 opD = 0; + INT64 result = 0; + + INT32 s1 = 0; + INT32 s2 = 0; + + void* D = NULL; + void* S1 = NULL; + void* S2 = NULL; + + decode_QQF_table(cpustate, BITS(op_byte,0x0003), BITS(op_byte,0x0008), &S1, &S2, &D); + + /* Cast both values as being signed */ + s1 = *((INT16*)S1); + s2 = *((INT16*)S2); + + /* Fixed-point 2's complement multiplication requires a shift */ + result = (s1 * s2) << 1; + + /* Sign extend D into a temp variable */ + opD = (*((UINT64*)D)); + if (opD & U64(0x0000008000000000)) + opD |= U64(0xffffff0000000000); + else + opD &= U64(0x000000ffffffffff); + + /* Accumulate */ + opD += result; + + /* And out the bits that don't live in the register */ + opD &= U64(0x000000ffffffffff); + + (*((UINT64*)D)) = (UINT64)opD; + + /* For the parallel move */ + d_register->addr = D; + d_register->data_type = DT_LONG_WORD; + + /* S L E U N Z V C */ + /* * * * * * * * - */ + /* TODO: S, L, E, V */ + if ( *((UINT64*)D) & U64(0x0000008000000000)) DSP56K_N_SET(); else DSP56K_N_CLEAR(); + if ((*((UINT64*)D) & U64(0x000000ffffffffff)) == 0) DSP56K_Z_SET(); else DSP56K_Z_CLEAR(); + + cycles += 2; /* TODO: +mv oscillator cycles */ + return 1; +} + +/* MACR: 011m mKKK 1--1 F1QQ : A-124 */ +static size_t dsp56k_op_macr_1(dsp56k_core* cpustate, const UINT16 op_byte, typed_pointer* d_register, UINT8* cycles) +{ + /* S L E U N Z V C */ + /* * * * * * * * - */ + return 0; +} + +/* MOVE : 011m mKKK 0rr1 0000 : A-128 */ +static size_t dsp56k_op_move_1(dsp56k_core* cpustate, const UINT16 op_byte, typed_pointer* d_register, UINT8* cycles) +{ + /* S L E U N Z V C */ + /* * * - - - - - - */ + return 0; +} + +/* MPY : 011m mKKK 1xx0 F0QQ : A-160 */ +static size_t dsp56k_op_mpy_1(dsp56k_core* cpustate, const UINT16 op_byte, typed_pointer* d_register, UINT8* cycles) +{ + INT64 result = 0; + + INT32 s1 = 0; + INT32 s2 = 0; + + void* D = NULL; + void* S1 = NULL; + void* S2 = NULL; + + decode_QQF_table(cpustate, BITS(op_byte,0x0003), BITS(op_byte,0x0008), &S1, &S2, &D); + + /* Cast both values as being signed */ + s1 = *((INT16*)S1); + s2 = *((INT16*)S2); + + /* Fixed-point 2's complement multiplication requires a shift */ + result = (s1 * s2) << 1; + + /* And out the bits that don't live in the register */ + (*((UINT64*)D)) = result & U64(0x000000ffffffffff); + + /* For the parallel move */ + d_register->addr = D; + d_register->data_type = DT_LONG_WORD; + + /* S L E U N Z V C */ + /* * * * * * * * - */ + /* TODO: S, L, E, V */ + if ( *((UINT64*)D) & U64(0x0000008000000000)) DSP56K_N_SET(); else DSP56K_N_CLEAR(); + if ((*((UINT64*)D) & U64(0x000000ffffffffff)) == 0) DSP56K_Z_SET(); else DSP56K_Z_CLEAR(); + + cycles += 2; /* TODO: +mv oscillator cycles */ + return 1; +} + +/* MPYR : 011m mKKK 1--1 F0QQ : A-162 */ +static size_t dsp56k_op_mpyr_1(dsp56k_core* cpustate, const UINT16 op_byte, typed_pointer* d_register, UINT8* cycles) +{ + /* S L E U N Z V C */ + /* * * * * * * * - */ + return 0; +} + +/* TFR : 011m mKKK 0rr1 F0DD : A-212 */ +static size_t dsp56k_op_tfr_2(dsp56k_core* cpustate, const UINT16 op_byte, typed_pointer* d_register, UINT8* cycles) +{ + /* S L E U N Z V C */ + /* - - - - - - - - */ + return 0; +} + +/* MPY : 0001 0110 RRDD FQQQ : A-160 */ +static size_t dsp56k_op_mpy_2(dsp56k_core* cpustate, const UINT16 op_byte, UINT8* cycles) +{ + /* S L E U N Z V C */ + /* * * * * * * * - */ + return 0; +} + +/* MAC : 0001 0111 RRDD FQQQ : A-122 */ +static size_t dsp56k_op_mac_2(dsp56k_core* cpustate, const UINT16 op_byte, UINT8* cycles) +{ + /* S L E U N Z V C */ + /* * * * * * * * - */ + return 0; +} + +/* CLR : .... .... 0000 F001 : A-60 */ +static size_t dsp56k_op_clr(dsp56k_core* cpustate, const UINT16 op_byte, typed_pointer* d_register, UINT64* p_accum, UINT8* cycles) +{ + typed_pointer D = {NULL, DT_LONG_WORD}; + typed_pointer clear = {NULL, DT_LONG_WORD}; + UINT64 clear_val = U64(0x0000000000000000); + + decode_F_table(cpustate, BITS(op_byte,0x0008), &D); + + *p_accum = *((UINT64*)D.addr); + + clear.addr = &clear_val; + clear.data_type = DT_LONG_WORD; + SetDestinationValue(clear, D); + + d_register->addr = D.addr; + d_register->data_type = D.data_type; + + /* S L E U N Z V C */ + /* * * * * * * 0 - */ + /* TODO - S, L */ + DSP56K_E_CLEAR(); + DSP56K_U_SET(); + DSP56K_N_CLEAR(); + DSP56K_Z_SET(); + DSP56K_V_CLEAR(); + + cycles += 2; /* TODO: + mv oscillator clock cycles */ + return 1; +} + +/* ADD : .... .... 0000 FJJJ : A-22 */ +static size_t dsp56k_op_add(dsp56k_core* cpustate, const UINT16 op_byte, typed_pointer* d_register, UINT64* p_accum, UINT8* cycles) +{ + UINT64 addVal = 0; + + typed_pointer S = {NULL, DT_BYTE}; + typed_pointer D = {NULL, DT_BYTE}; + decode_JJJF_table(cpustate, BITS(op_byte,0x0007),BITS(op_byte,0x0008), &S, &D); + + *p_accum = *((UINT64*)D.addr); + + switch(S.data_type) + { + case DT_WORD: addVal = (UINT64)*((UINT16*)S.addr) << 16; break; + case DT_DOUBLE_WORD: addVal = (UINT64)*((UINT32*)S.addr); break; + case DT_LONG_WORD: addVal = (UINT64)*((UINT64*)S.addr); break; + } + + /* Sign-extend word for proper add/sub op */ + if ((S.data_type == DT_WORD) && addVal & U64(0x0000000080000000)) + addVal |= U64(0x000000ff00000000); + + /* Operate*/ + *((UINT64*)D.addr) += addVal; + + d_register->addr = D.addr; + d_register->data_type = D.data_type; + + /* S L E U N Z V C */ + /* * * * * * * * * */ + /* TODO S, L, E, U, V, C */ + if (*((UINT64*)D.addr) & U64(0x0000008000000000)) DSP56K_N_SET(); else DSP56K_N_CLEAR(); + if (*((UINT64*)D.addr) == 0) DSP56K_Z_SET(); else DSP56K_Z_CLEAR(); + + cycles += 2; /* TODO: + mv oscillator cycles */ + return 1; +} + +/* MOVE : .... .... 0001 0001 : A-128 */ +static size_t dsp56k_op_move(dsp56k_core* cpustate, const UINT16 op_byte, typed_pointer* d_register, UINT64* p_accum, UINT8* cycles) +{ + /* Equivalent to a nop with a parallel move */ + /* These can't be used later. Hopefully compilers would pick this up. */ + *p_accum = 0; + d_register->addr = NULL; + d_register->data_type = DT_BYTE; + + /* S L E U N Z V C */ + /* * * - - - - - - */ + /* TODO: S, L */ + cycles += 2; /* TODO: + mv oscillator cycles */ + return 1; +} + +/* TFR : .... .... 0001 FJJJ : A-212 */ +static size_t dsp56k_op_tfr(dsp56k_core* cpustate, const UINT16 op_byte, typed_pointer* d_register, UINT64* p_accum, UINT8* cycles) +{ + typed_pointer S = {NULL, DT_BYTE}; + typed_pointer D = {NULL, DT_BYTE}; + + decode_JJJF_table(cpustate, BITS(op_byte,0x0007),BITS(op_byte,0x0008), &S, &D); + + *p_accum = *((UINT64*)D.addr); + + SetDestinationValue(S, D); + + d_register->addr = D.addr; + d_register->data_type = D.data_type; + + /* S L E U N Z V C */ + /* * * - - - - - - */ + /* TODO: S, L */ + cycles += 2; /* TODO: + mv oscillator cycles */ + return 1; +} + +/* RND : .... .... 0010 F000 : A-188 */ +static size_t dsp56k_op_rnd(dsp56k_core* cpustate, const UINT16 op_byte, typed_pointer* d_register, UINT64* p_accum, UINT8* cycles) +{ + typed_pointer D = {NULL, DT_BYTE}; + + decode_F_table(cpustate, BITS(op_byte,0x0008), &D); + + *p_accum = *((UINT64*)D.addr); + + /* WARNING : ROUNDING NOT FULLY IMPLEMENTED YET! */ + if ((*((UINT64*)D.addr) & U64(0x000000000000ffff)) >= 0x8000) + *((UINT64*)D.addr) += U64(0x0000000000010000); + + *((UINT64*)D.addr) = *((UINT64*)D.addr) & U64(0x000000ffffff0000); + + d_register->addr = D.addr; + d_register->data_type = D.data_type; + + /* S L E U N Z V C */ + /* * * * * * * * - */ + /* TODO: S, L, E, U, V */ + if ((*((UINT64*)D.addr)) & U64(0x0000008000000000)) DSP56K_N_SET(); else DSP56K_N_CLEAR(); + if ((*((UINT64*)D.addr)) == 0) DSP56K_Z_SET(); else DSP56K_Z_CLEAR(); + + cycles += 2; /* TODO: + mv oscillator clock cycles */ + return 1; +} + +/* TST : .... .... 0010 F001 : A-218 */ +static size_t dsp56k_op_tst(dsp56k_core* cpustate, const UINT16 op_byte, typed_pointer* d_register, UINT64* p_accum, UINT8* cycles) +{ + typed_pointer D = {NULL, DT_LONG_WORD}; + + decode_F_table(cpustate, BITS(op_byte,0x0008), &D); + + *p_accum = *((UINT64*)D.addr); + + d_register->addr = D.addr; + d_register->data_type = D.data_type; + + /* S L E U N Z V C */ + /* 0 * * * * * 0 0 */ + /* TODO: S, L, E, U */ + if ((*((UINT64*)D.addr)) & U64(0x0000008000000000)) DSP56K_N_SET(); else DSP56K_N_CLEAR(); + if ((*((UINT64*)D.addr)) == 0) DSP56K_Z_SET(); else DSP56K_Z_CLEAR(); + DSP56K_V_CLEAR(); + DSP56K_C_CLEAR(); + + cycles += 2; /* TODO: + mv oscillator clock cycles */ + return 1; +} + +/* INC : .... .... 0010 F010 : A-104 */ +static size_t dsp56k_op_inc(dsp56k_core* cpustate, const UINT16 op_byte, typed_pointer* d_register, UINT64* p_accum, UINT8* cycles) +{ + typed_pointer D = {NULL, DT_BYTE}; + decode_F_table(cpustate, BITS(op_byte,0x0008), &D); + + /* Save some data for the parallel move */ + *p_accum = *((UINT64*)D.addr); + + /* Make sure the destination is a real 40-bit value */ + *((UINT64*)D.addr) &= U64(0x000000ffffffffff); + + /* Increment */ + *((UINT64*)D.addr) = *((UINT64*)D.addr) + 1; + + d_register->addr = D.addr; + d_register->data_type = D.data_type; + + /* S L E U N Z V C */ + /* * * * * * * * * */ + /* TODO: S, L, E, U */ + if ( *((UINT64*)D.addr) & U64(0x0000008000000000)) DSP56K_N_SET(); else DSP56K_N_CLEAR(); + if ((*((UINT64*)D.addr) & U64(0x000000ffffff0000)) == 0) DSP56K_Z_SET(); else DSP56K_Z_CLEAR(); + if ((*((UINT64*)D.addr) & U64(0xffffff0000000000)) != 0) DSP56K_V_SET(); else DSP56K_V_CLEAR(); + if ((*((UINT64*)D.addr) & U64(0xffffff0000000000)) != 0) DSP56K_C_SET(); else DSP56K_C_CLEAR(); + + cycles += 2; /* TODO: +mv oscillator cycles */ + return 1; +} + +/* INC24 : .... .... 0010 F011 : A-106 */ +static size_t dsp56k_op_inc24(dsp56k_core* cpustate, const UINT16 op_byte, typed_pointer* d_register, UINT64* p_accum, UINT8* cycles) +{ + UINT32 workBits24; + + typed_pointer D = {NULL, DT_BYTE}; + decode_F_table(cpustate, BITS(op_byte,0x0008), &D); + + /* Save some data for the parallel move */ + *p_accum = *((UINT64*)D.addr); + + /* TODO: I wonder if workBits24 should be signed? */ + workBits24 = ((*((UINT64*)D.addr)) & U64(0x000000ffffff0000)) >> 16; + workBits24++; + //workBits24 &= 0x00ffffff; /* Solves -x issues - TODO: huh? */ + + /* Set the D bits with the dec result */ + *((UINT64*)D.addr) &= U64(0x000000000000ffff); + *((UINT64*)D.addr) |= (((UINT64)(workBits24)) << 16); + + d_register->addr = D.addr; + d_register->data_type = D.data_type; + + /* S L E U N Z V C */ + /* * * * * * ? * * */ + /* TODO: S, L, E, U */ + if ( *((UINT64*)D.addr) & U64(0x0000008000000000)) DSP56K_N_SET(); else DSP56K_N_CLEAR(); + if ((*((UINT64*)D.addr) & U64(0x000000ffffff0000)) == 0) DSP56K_Z_SET(); else DSP56K_Z_CLEAR(); + if ((workBits24 & 0xff000000) != 0) DSP56K_V_SET(); else DSP56K_V_CLEAR(); + if ((workBits24 & 0xff000000) != 0) DSP56K_C_SET(); else DSP56K_C_CLEAR(); + + cycles += 2; /* TODO: + mv oscillator clock cycles */ + return 1; +} + +/* OR : .... .... 0010 F1JJ : A-176 */ +static size_t dsp56k_op_or(dsp56k_core* cpustate, const UINT16 op_byte, typed_pointer* d_register, UINT64* p_accum, UINT8* cycles) +{ + typed_pointer S = {NULL, DT_BYTE}; + typed_pointer D = {NULL, DT_BYTE}; + + decode_JJF_table(cpustate, BITS(op_byte,0x0003), BITS(op_byte,0x0008), &S, &D); + + /* Save some data for the parallel move */ + *p_accum = *((UINT64*)D.addr); + + /* OR a word of S with A1|B1 */ + ((PAIR64*)D.addr)->w.h = *((UINT16*)S.addr) | ((PAIR64*)D.addr)->w.h; + + d_register->addr = D.addr; + d_register->data_type = D.data_type; + + /* S L E U N Z V C */ + /* * * - - ? ? 0 - */ + /* TODO: S, L */ + if ( *((UINT64*)D.addr) & U64(0x0000000080000000)) DSP56K_N_SET(); else DSP56K_N_CLEAR(); + if ((*((UINT64*)D.addr) & U64(0x00000000ffff0000)) == 0) DSP56K_Z_SET(); else DSP56K_Z_CLEAR(); + DSP56K_V_CLEAR(); + + cycles += 2; /* TODO: + mv oscillator cycles */ + return 1; +} + +/* ASR : .... .... 0011 F000 : A-32 */ +static size_t dsp56k_op_asr(dsp56k_core* cpustate, const UINT16 op_byte, typed_pointer* d_register, UINT64* p_accum, UINT8* cycles) +{ + typed_pointer D = {NULL, DT_BYTE}; + decode_F_table(cpustate, BITS(op_byte,0x0008), &D); + + *p_accum = *((UINT64*)D.addr); + + *((UINT64*)D.addr) = (*((UINT64*)D.addr)) >> 1; + + /* Make sure the MSB is maintained */ + if (*p_accum & U64(0x0000008000000000)) + *((UINT64*)D.addr) |= U64(0x0000008000000000); + else + *((UINT64*)D.addr) &= (~U64(0x0000008000000000)); + + /* For the parallel move */ + d_register->addr = D.addr; + d_register->data_type = D.data_type; + + /* S L E U N Z V C */ + /* * * * * * * 0 ? */ + /* TODO: S, L, E, U */ + if (*((UINT64*)D.addr) & U64(0x0000008000000000)) DSP56K_N_SET(); else DSP56K_N_CLEAR(); + if (*((UINT64*)D.addr) == 0) DSP56K_Z_SET(); else DSP56K_Z_CLEAR(); + DSP56K_V_CLEAR(); + if (*p_accum & U64(0x0000000000000001)) DSP56K_C_SET(); else DSP56K_C_CLEAR(); + + cycles += 2; /* TODO: + mv oscillator cycles */ + return 1; +} + +/* ASL : .... .... 0011 F001 : A-28 */ +static size_t dsp56k_op_asl(dsp56k_core* cpustate, const UINT16 op_byte, typed_pointer* d_register, UINT64* p_accum, UINT8* cycles) +{ + /* S L E U N Z V C */ + /* * * * * * * ? ? */ + /* V - Set if an arithmetic overflow occurs in the 40 bit result. Also set if the most significant + bit of the destination operand is changed as a result of the left shift. Cleared otherwise. */ + /* C - Set if bit 39 of source operand is set. Cleared otherwise. */ + return 0; +} + +/* LSR : .... .... 0011 F010 : A-120 */ +static size_t dsp56k_op_lsr(dsp56k_core* cpustate, const UINT16 op_byte, typed_pointer* d_register, UINT64* p_accum, UINT8* cycles) +{ + typed_pointer D = {NULL, DT_BYTE}; + decode_F_table(cpustate, BITS(op_byte,0x0008), &D); + + *p_accum = *((UINT64*)D.addr); + + ((PAIR64*)D.addr)->w.h = (((PAIR64*)D.addr)->w.h) >> 1; + + /* Make sure bit 31 gets a 0 */ + ((PAIR64*)D.addr)->w.h &= (~0x8000); + + /* For the parallel move */ + d_register->addr = D.addr; + d_register->data_type = D.data_type; + + /* S L E U N Z V C */ + /* * * - - ? ? 0 ? */ + /* TODO: S, L */ + DSP56K_N_CLEAR(); + if (((PAIR64*)D.addr)->w.h == 0) DSP56K_Z_SET(); else DSP56K_Z_CLEAR(); + DSP56K_V_CLEAR(); + if (*p_accum & U64(0x0000000000010000)) DSP56K_C_SET(); else DSP56K_C_CLEAR(); + + cycles += 2; /* TODO: + mv oscillator cycles */ + return 1; +} + +/* LSL : .... .... 0011 F011 : A-118 */ +static size_t dsp56k_op_lsl(dsp56k_core* cpustate, const UINT16 op_byte, typed_pointer* d_register, UINT64* p_accum, UINT8* cycles) +{ + /* S L E U N Z V C */ + /* * * - - ? ? 0 ? */ + /* N - Set if bit 31 of the result is set. Cleared otherwise. */ + /* Z - Set if bits 16-31 of the result are zero. Cleared otherwise. */ + /* C - Set if bit 31 of the source operand is set. Cleared otherwise. */ + return 0; +} + +/* EOR : .... .... 0011 F1JJ : A-94 */ +static size_t dsp56k_op_eor(dsp56k_core* cpustate, const UINT16 op_byte, typed_pointer* d_register, UINT64* p_accum, UINT8* cycles) +{ + /* S L E U N Z V C */ + /* * * - - ? ? 0 - */ + /* N - Set if bit 31 of the result is set. Cleared otherwise. */ + /* Z - Set if bits 16-31 of the result are zero. Cleared otherwise. */ + return 0; +} + +/* SUBL : .... .... 0100 F001 : A-204 */ +static size_t dsp56k_op_subl(dsp56k_core* cpustate, const UINT16 op_byte, typed_pointer* d_register, UINT64* p_accum, UINT8* cycles) +{ + /* S L E U N Z V C */ + /* * * * * * * ? * */ + /* V - Set if an arithmetic overflow occurs in the 40 bit result. Also set if the most significant + bit of the destination operand is changed as a result of the left shift. Cleared otherwise. */ + return 0; +} + +/* SUB : .... .... 0100 FJJJ : A-202 */ +static size_t dsp56k_op_sub(dsp56k_core* cpustate, const UINT16 op_byte, typed_pointer* d_register, UINT64* p_accum, UINT8* cycles) +{ + UINT64 useVal = 0; + typed_pointer S = {NULL, DT_BYTE}; + typed_pointer D = {NULL, DT_BYTE}; + + decode_JJJF_table(cpustate, BITS(op_byte,0x0007), BITS(op_byte,0x0008), &S, &D); + + /* Get on with it. */ + switch(S.data_type) + { + case DT_WORD: useVal = (UINT64)*((UINT16*)S.addr) << 16; break; + case DT_DOUBLE_WORD: useVal = (UINT64)*((UINT32*)S.addr); break; + case DT_LONG_WORD: useVal = (UINT64)*((UINT64*)S.addr); break; + } + + /* Sign-extend word for proper sub op */ + if ((S.data_type == DT_WORD) && useVal & U64(0x0000000080000000)) + useVal |= U64(0x000000ff00000000); + + /* Make sure they're both real 40-bit values */ + useVal &= U64(0x000000ffffffffff); + *((UINT64*)D.addr) &= U64(0x000000ffffffffff); + + /* Operate*/ + *((UINT64*)D.addr) -= useVal; + + d_register->addr = D.addr; + d_register->data_type = D.data_type; + + /* S L E U N Z V C */ + /* * * * * * * * * */ + /* TODO S, L, E, U */ + if ( *((UINT64*)D.addr) & U64(0x0000008000000000)) DSP56K_N_SET(); else DSP56K_N_CLEAR(); + if ( *((UINT64*)D.addr) == 0) DSP56K_Z_SET(); else DSP56K_Z_CLEAR(); + if ((*((UINT64*)D.addr) & U64(0xffffff0000000000)) != 0) DSP56K_V_SET(); else DSP56K_V_CLEAR(); + if ((*((UINT64*)D.addr) & U64(0xffffff0000000000)) != 0) DSP56K_C_SET(); else DSP56K_C_CLEAR(); + + cycles += 2; /* TODO: + mv oscillator cycles */ + return 1; +} + +/* CLR24 : .... .... 0101 F001 : A-62 */ +static size_t dsp56k_op_clr24(dsp56k_core* cpustate, const UINT16 op_byte, typed_pointer* d_register, UINT64* p_accum, UINT8* cycles) +{ + /* S L E U N Z V C */ + /* * * * * * ? 0 - */ + /* Z - Set if the 24 most significant bits of the destination result are all zeroes. */ + return 0; +} + +/* SBC : .... .... 0101 F01J : A-198 */ +static size_t dsp56k_op_sbc(dsp56k_core* cpustate, const UINT16 op_byte, typed_pointer* d_register, UINT64* p_accum, UINT8* cycles) +{ + /* S L E U N Z V C */ + /* * * * * * * * * */ + return 0; +} + +/* CMP : .... .... 0101 FJJJ : A-64 */ +static size_t dsp56k_op_cmp(dsp56k_core* cpustate, const UINT16 op_byte, typed_pointer* d_register, UINT64* p_accum, UINT8* cycles) +{ + UINT64 cmpVal = 0; + UINT64 result = 0; + + typed_pointer S = {NULL, DT_BYTE}; + typed_pointer D = {NULL, DT_BYTE}; + + decode_JJJF_table(cpustate, BITS(op_byte,0x0007),BITS(op_byte,0x0008), &S, &D); + + *p_accum = *((UINT64*)D.addr); + + switch(S.data_type) + { + case DT_WORD: cmpVal = (UINT64)*((UINT16*)S.addr) << 16; break; + case DT_DOUBLE_WORD: cmpVal = (UINT64)*((UINT32*)S.addr); break; + case DT_LONG_WORD: cmpVal = (UINT64)*((UINT64*)S.addr); break; + } + + /* Sign-extend word for proper subtraction op */ + if ((S.data_type == DT_WORD) && cmpVal & U64(0x0000000080000000)) + cmpVal |= U64(0x000000ff00000000); + + /* Make sure they're both real 40-bit values */ + cmpVal &= U64(0x000000ffffffffff); + *((UINT64*)D.addr) &= U64(0x000000ffffffffff); + + /* Operate */ + result = *((UINT64*)D.addr) - cmpVal; + + d_register->addr = D.addr; + d_register->data_type = D.data_type; + + /* S L E U N Z V C */ + /* * * * * * * * * */ + /* TODO: S, L, E, U */ + if ( result & U64(0x0000008000000000)) DSP56K_N_SET(); else DSP56K_N_CLEAR(); + if ( result == 0) DSP56K_Z_SET(); else DSP56K_Z_CLEAR(); + if ((result & U64(0xffffff0000000000)) != 0) DSP56K_V_SET(); else DSP56K_V_CLEAR(); + if ((result & U64(0xffffff0000000000)) != 0) DSP56K_C_SET(); else DSP56K_C_CLEAR(); + + + cycles += 2; /* TODO: + mv oscillator clock cycles */ + return 1; +} + +/* NEG : .... .... 0110 F000 : A-166 */ +static size_t dsp56k_op_neg(dsp56k_core* cpustate, const UINT16 op_byte, typed_pointer* d_register, UINT64* p_accum, UINT8* cycles) +{ + /* S L E U N Z V C */ + /* * * * * * * * * */ + return 0; +} + +/* NOT : .... .... 0110 F001 : A-174 */ +static size_t dsp56k_op_not(dsp56k_core* cpustate, const UINT16 op_byte, typed_pointer* d_register, UINT64* p_accum, UINT8* cycles) +{ + typed_pointer D = {NULL, DT_BYTE}; + decode_F_table(cpustate, BITS(op_byte,0x0008), &D); + + *p_accum = *((UINT64*)D.addr); + + /* Invert bits [16:31] of D */ + ((PAIR64*)D.addr)->w.h = ~(((PAIR64*)D.addr)->w.h); + + d_register->addr = D.addr; + d_register->data_type = D.data_type; + + /* S L E U N Z V C */ + /* * * - - ? ? 0 - */ + /* TODO: S?, L */ + if ( *((UINT64*)D.addr) & U64(0x0000000080000000)) DSP56K_N_SET(); else DSP56K_N_CLEAR(); + if ((*((UINT64*)D.addr) & U64(0x00000000ffff0000)) == 0) DSP56K_Z_SET(); else DSP56K_Z_CLEAR(); + DSP56K_V_CLEAR(); + + cycles += 2; /* TODO: + mv oscillator cycles */ + return 1; +} + +/* DEC : .... .... 0110 F010 : A-72 */ +static size_t dsp56k_op_dec(dsp56k_core* cpustate, const UINT16 op_byte, typed_pointer* d_register, UINT64* p_accum, UINT8* cycles) +{ + /* S L E U N Z V C */ + /* * * * * * * * * */ + return 0; +} + +/* DEC24 : .... .... 0110 F011 : A-74 */ +static size_t dsp56k_op_dec24(dsp56k_core* cpustate, const UINT16 op_byte, typed_pointer* d_register, UINT64* p_accum, UINT8* cycles) +{ + UINT32 workBits24; + + typed_pointer D = {NULL, DT_BYTE}; + decode_F_table(cpustate, BITS(op_byte,0x0008), &D); + + /* Save some data for the parallel move */ + *p_accum = *((UINT64*)D.addr); + + /* TODO: I wonder if workBits24 should be signed? */ + workBits24 = ((*((UINT64*)D.addr)) & U64(0x000000ffffff0000)) >> 16; + workBits24--; + workBits24 &= 0x00ffffff; /* Solves -x issues */ + + /* Set the D bits with the dec result */ + *((UINT64*)D.addr) &= U64(0x000000000000ffff); + *((UINT64*)D.addr) |= (((UINT64)(workBits24)) << 16); + + d_register->addr = D.addr; + d_register->data_type = D.data_type; + + /* S L E U N Z V C */ + /* * * * * * ? * * */ + /* TODO: S, L, E, U, V, C */ + if ( *((UINT64*)D.addr) & U64(0x0000008000000000)) DSP56K_N_SET(); else DSP56K_N_CLEAR(); + if ((*((UINT64*)D.addr) & U64(0x000000ffffff0000)) == 0) DSP56K_Z_SET(); else DSP56K_Z_CLEAR(); + + cycles += 2; /* TODO: + mv oscillator clock cycles */ + return 1; +} + +/* AND : .... .... 0110 F1JJ : A-24 */ +static size_t dsp56k_op_and(dsp56k_core* cpustate, const UINT16 op_byte, typed_pointer* d_register, UINT64* p_accum, UINT8* cycles) +{ + typed_pointer S = {NULL, DT_BYTE}; + typed_pointer D = {NULL, DT_BYTE}; + + decode_JJF_table(cpustate, BITS(op_byte,0x0003), BITS(op_byte,0x0008), &S, &D); + + /* Save some data for the parallel move */ + *p_accum = *((UINT64*)D.addr); + + /* AND a word of S with A1|B1 */ + ((PAIR64*)D.addr)->w.h = *((UINT16*)S.addr) & ((PAIR64*)D.addr)->w.h; + + d_register->addr = D.addr; + d_register->data_type = D.data_type; + + /* S L E U N Z V C */ + /* * * - - ? ? 0 - */ + /* TODO: S, L */ + if ( *((UINT64*)D.addr) & U64(0x0000000080000000)) DSP56K_N_SET(); else DSP56K_N_CLEAR(); + if ((*((UINT64*)D.addr) & U64(0x00000000ffff0000)) == 0) DSP56K_Z_SET(); else DSP56K_Z_CLEAR(); + DSP56K_V_CLEAR(); + + cycles += 2; /* TODO: + mv oscillator cycles */ + return 1; +} + +/* ABS : .... .... 0111 F001 : A-18 */ +static size_t dsp56k_op_abs(dsp56k_core* cpustate, const UINT16 op_byte, typed_pointer* d_register, UINT64* p_accum, UINT8* cycles) +{ + INT64 opD = 0; + typed_pointer D = {NULL, DT_LONG_WORD}; + + decode_F_table(cpustate, BITS(op_byte,0x0008), &D); + + *p_accum = *((UINT64*)D.addr); + + /* Sign extend D into a temp variable */ + opD = *p_accum; + if (opD & U64(0x0000008000000000)) + opD |= U64(0xffffff0000000000); + else + opD &= U64(0x000000ffffffffff); + + /* Take the absolute value and clean up */ + opD = (opD < 0) ? -opD : opD; + opD &= U64(0x000000ffffffffff); + + /* Reassign */ + *((UINT64*)D.addr) = opD; + + /* Special overflow case */ + if ((*p_accum) == U64(0x0000008000000000)) + *((UINT64*)D.addr) = U64(0x0000007fffffffff); + + /* S L E U N Z V C */ + /* * * * * * * * - */ + /* TODO: S, L, E, U */ + if ( *((UINT64*)D.addr) & U64(0x0000008000000000)) DSP56K_N_SET(); else DSP56K_N_CLEAR(); + if ((*((UINT64*)D.addr) & U64(0x000000ffffffffff)) == 0) DSP56K_Z_SET(); else DSP56K_Z_CLEAR(); + if ((*p_accum) == U64(0x0000008000000000)) DSP56K_V_SET(); else DSP56K_V_CLEAR(); + + cycles += 2; /* TODO: + mv oscillator clock cycles */ + return 1; +} + +/* ROR : .... .... 0111 F010 : A-192 */ +static size_t dsp56k_op_ror(dsp56k_core* cpustate, const UINT16 op_byte, typed_pointer* d_register, UINT64* p_accum, UINT8* cycles) +{ + /* S L E U N Z V C */ + /* * * - - ? ? 0 ? */ + /* N - Set if bit 31 of the result is set. Cleared otherwise. */ + /* Z - Set if bits 16-31 of the result are zero. Cleared otherwise. */ + /* C - Set if bit 16 of the source operand is set. Cleared otherwise. */ + return 0; +} + +/* ROL : .... .... 0111 F011 : A-190 */ +static size_t dsp56k_op_rol(dsp56k_core* cpustate, const UINT16 op_byte, typed_pointer* d_register, UINT64* p_accum, UINT8* cycles) +{ + /* S L E U N Z V C */ + /* * * - - ? ? 0 ? */ + /* N - Set if bit 31 of the result is set. Cleared otherwise. */ + /* Z - Set if bits 16-31 of the result are zero. Cleared otherwise. */ + /* C - Set if bit 31 of the source operand is set. Cleared otherwise. */ + return 0; +} + +/* CMPM : .... .... 0111 FJJJ : A-66 */ +static size_t dsp56k_op_cmpm(dsp56k_core* cpustate, const UINT16 op_byte, typed_pointer* d_register, UINT64* p_accum, UINT8* cycles) +{ + INT64 absS; + INT64 absD; + INT64 absResult; + + typed_pointer S = {NULL, DT_BYTE}; + typed_pointer D = {NULL, DT_BYTE}; + + decode_JJJF_table(cpustate, BITS(op_byte,0x0007),BITS(op_byte,0x0008), &S, &D); + + *p_accum = *((UINT64*)D.addr); + + /* Sign extend and get absolute value of the source */ + if (S.addr == &A || S.addr == &B) + { + absS = *((UINT64*)S.addr); + if (absS & U64(0x0000008000000000)) + absS |= U64(0xffffff8000000000); + } + else + { + absS = (*((UINT16*)S.addr)) << 16; + if (absS & U64(0x0000000080000000)) + absS |= U64(0xffffffff80000000); + } + absS = (absS < 0) ? -absS : absS; + + /* Sign extend and get absolute value of the destination */ + if (D.addr == &A || D.addr == &B) + { + absD = *((UINT64*)D.addr); + if (absD & U64(0x0000008000000000)) + absD |= U64(0xffffff8000000000); + } + else + { + absD = (*((UINT16*)D.addr)) << 16; + if (absS & U64(0x0000000080000000)) + absS |= U64(0xffffffff80000000); + } + absD = (absD < 0) ? -absD : absD; + + /* Compare */ + absResult = absD - absS; + + d_register->addr = D.addr; + d_register->data_type = D.data_type; + + /* S L E U N Z V C */ + /* * * * * * * * * */ + /* TODO: S, L, E, U */ + if ( (absResult) & U64(0x0000008000000000)) DSP56K_N_SET(); else DSP56K_N_CLEAR(); + if (((absResult) & U64(0x000000ffffffffff)) == 0) DSP56K_Z_SET(); else DSP56K_Z_CLEAR(); + if ( (absResult & U64(0xffffff0000000000)) != 0) DSP56K_V_SET(); else DSP56K_V_CLEAR(); + if ( (absResult & U64(0xffffff0000000000)) != 0) DSP56K_C_SET(); else DSP56K_C_CLEAR(); + + cycles += 2; /* TODO: +mv oscillator cycles */ + return 1; +} + +/* MPY : .... .... 1k00 FQQQ : A-160 -- CONFIRMED TYPO IN DOCS (HHHH vs HHHW) */ +static size_t dsp56k_op_mpy(dsp56k_core* cpustate, const UINT16 op_byte, typed_pointer* d_register, UINT64* p_accum, UINT8* cycles) +{ + UINT16 k = 0; + INT64 result = 0; + + INT32 s1 = 0; + INT32 s2 = 0; + + void* D = NULL; + void* S1 = NULL; + void* S2 = NULL; + + decode_QQQF_table(cpustate, BITS(op_byte,0x0007), BITS(op_byte,0x0008), &S1, &S2, &D); + + k = BITS(op_byte,0x0040); + + /* Cast both values as being signed */ + s1 = *((INT16*)S1); + s2 = *((INT16*)S2); + + /* Fixed-point 2's complement multiplication requires a shift */ + result = (s1 * s2) << 1; + + /* Negate the product if necessary */ + if (k) + result *= -1; + + (*((UINT64*)D)) = result & U64(0x000000ffffffffff); + + /* S L E U N Z V C */ + /* * * * * * * * - */ + /* TODO: S, L, E, V */ + if ( *((UINT64*)D) & U64(0x0000008000000000)) DSP56K_N_SET(); else DSP56K_N_CLEAR(); + if ((*((UINT64*)D) & U64(0x000000ffffffffff)) == 0) DSP56K_Z_SET(); else DSP56K_Z_CLEAR(); + + cycles += 2; /* TODO: +mv oscillator cycles */ + return 1; +} + +/* MPYR : .... .... 1k01 FQQQ : A-162 */ +static size_t dsp56k_op_mpyr(dsp56k_core* cpustate, const UINT16 op_byte, typed_pointer* d_register, UINT64* p_accum, UINT8* cycles) +{ + /* S L E U N Z V C */ + /* * * * * * * * - */ + return 0; +} + +/* MAC : .... .... 1k10 FQQQ : A-122 */ +static size_t dsp56k_op_mac(dsp56k_core* cpustate, const UINT16 op_byte, typed_pointer* d_register, UINT64* p_accum, UINT8* cycles) +{ + UINT16 k = 0; + INT64 opD = 0; + INT64 result = 0; + + INT32 s1 = 0; + INT32 s2 = 0; + + void* D = NULL; + void* S1 = NULL; + void* S2 = NULL; + + decode_QQQF_table(cpustate, BITS(op_byte,0x0007), BITS(op_byte,0x0008), &S1, &S2, &D); + + k = BITS(op_byte,0x0040); + + /* Cast both values as being signed */ + s1 = *((INT16*)S1); + s2 = *((INT16*)S2); + + /* Fixed-point 2's complement multiplication requires a shift */ + result = (s1 * s2) << 1; + + /* Sign extend D into a temp variable */ + opD = (*((UINT64*)D)); + if (opD & U64(0x0000008000000000)) + opD |= U64(0xffffff0000000000); + else + opD &= U64(0x000000ffffffffff); + + /* Negate if necessary */ + if (k) + result *= -1; + + /* Accumulate */ + opD += result; + + /* And out the bits that don't live in the register */ + opD &= U64(0x000000ffffffffff); + + (*((UINT64*)D)) = (UINT64)opD; + + /* For the parallel move */ + d_register->addr = D; + d_register->data_type = DT_LONG_WORD; + + /* S L E U N Z V C */ + /* * * * * * * * - */ + /* TODO: S, L, E, V */ + if ( *((UINT64*)D) & U64(0x0000008000000000)) DSP56K_N_SET(); else DSP56K_N_CLEAR(); + if ((*((UINT64*)D) & U64(0x000000ffffffffff)) == 0) DSP56K_Z_SET(); else DSP56K_Z_CLEAR(); + + cycles += 2; /* TODO: +mv oscillator cycles */ + return 1; +} + +/* MACR : .... .... 1k11 FQQQ : A-124 -- DRAMA - rr vs xx (805) */ +static size_t dsp56k_op_macr(dsp56k_core* cpustate, const UINT16 op_byte, typed_pointer* d_register, UINT64* p_accum, UINT8* cycles) +{ + UINT16 k = 0; + INT64 opD = 0; + INT64 result = 0; + + INT32 s1 = 0; + INT32 s2 = 0; + + void* D = NULL; + void* S1 = NULL; + void* S2 = NULL; + + decode_QQQF_table(cpustate, BITS(op_byte,0x0007), BITS(op_byte,0x0008), &S1, &S2, &D); + + k = BITS(op_byte,0x0040); + + /* Cast both values as being signed */ + s1 = *((INT16*)S1); + s2 = *((INT16*)S2); + + /* Fixed-point 2's complement multiplication requires a shift */ + result = (s1 * s2) << 1; + + /* Sign extend D into a temp variable */ + opD = (*((UINT64*)D)); + if (opD & U64(0x0000008000000000)) + opD |= U64(0xffffff0000000000); + else + opD &= U64(0x000000ffffffffff); + + /* Negate if necessary */ + if (k) + result *= -1; + + /* Accumulate */ + opD += result; + + /* Round the result */ + /* WARNING : ROUNDING NOT FULLY IMPLEMENTED YET! */ + if ((opD & U64(0x000000000000ffff)) >= 0x8000) + opD += U64(0x0000000000010000); + + opD &= U64(0x000000ffffff0000); + + /* And out the bits that don't live in the register */ + opD &= U64(0x000000ffffffffff); + + /* Store the result */ + (*((UINT64*)D)) = (UINT64)opD; + + /* For the parallel move */ + d_register->addr = D; + d_register->data_type = DT_LONG_WORD; + + /* S L E U N Z V C */ + /* * * * * * * * - */ + /* TODO: S, L, E, V */ + if ( *((UINT64*)D) & U64(0x0000008000000000)) DSP56K_N_SET(); else DSP56K_N_CLEAR(); + if ((*((UINT64*)D) & U64(0x000000ffffffffff)) == 0) DSP56K_Z_SET(); else DSP56K_Z_CLEAR(); + + cycles += 2; /* TODO: +mv oscillator cycles */ + return 1; +} + + +/******************************/ +/* Remaining non-parallel ops */ +/******************************/ + +/* ADC : 0001 0101 0000 F01J : A-20 */ +static size_t dsp56k_op_adc(dsp56k_core* cpustate, const UINT16 op, UINT8* cycles) +{ + /* S L E U N Z V C */ + /* - * * * * * * * */ + return 0; +} + +/* ANDI : 0001 1EE0 iiii iiii : A-26 */ +static size_t dsp56k_op_andi(dsp56k_core* cpustate, const UINT16 op, UINT8* cycles) +{ + UINT16 immediate = BITS(op,0x00ff); + + /* There is not currently a good way to refer to CCR or MR. Explicitly decode here. */ + switch(BITS(op,0x0600)) + { + case 0x01: /* MR */ + SR &= ((immediate << 8) | 0x00ff); + break; + + case 0x02: /* CCR */ + SR &= (immediate | 0xff00); + break; + + case 0x03: /* OMR */ + OMR &= (UINT8)(immediate); + break; + + default: + fatalerror("DSP56k - BAD EE value in andi operation\n") ; + } + + /* S L E U N Z V C */ + /* - ? ? ? ? ? ? ? */ + /* All ? bits - Cleared if the corresponding bit in the immediate data is cleared and if the operand + is the CCR. Not affected otherwise. */ + cycles += 2; + return 1; +} + +/* ASL4 : 0001 0101 0011 F001 : A-30 */ +static size_t dsp56k_op_asl4(dsp56k_core* cpustate, const UINT16 op, UINT8* cycles) +{ + UINT64 p_accum = 0; + typed_pointer D = {NULL, DT_BYTE}; + decode_F_table(cpustate, BITS(op,0x0008), &D); + + p_accum = *((UINT64*)D.addr); + + *((UINT64*)D.addr) = (*((UINT64*)D.addr)) << 4; + *((UINT64*)D.addr) = (*((UINT64*)D.addr)) & U64(0x000000ffffffffff); + + /* S L E U N Z V C */ + /* - ? * * * * ? ? */ + /* TODO: L, E, U */ + /* V - Set if an arithmetic overflow occurs in the 40 bit result. Also set if bit 35 through 39 are + not the same. */ + /* C - Set if bit 36 of source operand is set. Cleared otherwise. */ + if (*((UINT64*)D.addr) & U64(0x0000008000000000)) DSP56K_N_SET(); else DSP56K_N_CLEAR(); + if (*((UINT64*)D.addr) == 0) DSP56K_Z_SET(); else DSP56K_Z_CLEAR(); + if ( (*((UINT64*)D.addr) & U64(0x000000ff00000000)) != (p_accum & U64(0x000000ff00000000)) ) DSP56K_V_SET(); else DSP56K_V_CLEAR(); + if (p_accum & U64(0x0000001000000000)) DSP56K_C_SET(); else DSP56K_C_CLEAR(); + + cycles += 2; + return 1; +} + +/* ASR4 : 0001 0101 0011 F000 : A-34 */ +static size_t dsp56k_op_asr4(dsp56k_core* cpustate, const UINT16 op, UINT8* cycles) +{ + UINT64 p_accum = 0; + typed_pointer D = {NULL, DT_BYTE}; + decode_F_table(cpustate, BITS(op,0x0008), &D); + + p_accum = *((UINT64*)D.addr); + + *((UINT64*)D.addr) = (*((UINT64*)D.addr)) >> 4; + *((UINT64*)D.addr) = (*((UINT64*)D.addr)) & U64(0x000000ffffffffff); + + /* The top 4 bits become the old bit 39 */ + if (p_accum & U64(0x0000008000000000)) + *((UINT64*)D.addr) |= U64(0x000000f000000000); + else + *((UINT64*)D.addr) &= (~U64(0x000000f000000000)); + + /* S L E U N Z V C */ + /* - * * * * * 0 ? */ + /* TODO: E, U */ + /* C - Set if bit 3 of source operand is set. Cleared otherwise. */ + if (*((UINT64*)D.addr) & U64(0x0000008000000000)) DSP56K_N_SET(); else DSP56K_N_CLEAR(); + if (*((UINT64*)D.addr) == 0) DSP56K_Z_SET(); else DSP56K_Z_CLEAR(); + DSP56K_V_CLEAR(); + if (p_accum & U64(0x0000000000000008)) DSP56K_C_SET(); else DSP56K_C_CLEAR(); + + cycles += 2; + return 1; +} + +/* ASR16 : 0001 0101 0111 F000 : A-36 */ +static size_t dsp56k_op_asr16(dsp56k_core* cpustate, const UINT16 op, UINT8* cycles) +{ + UINT64 backupVal; + typed_pointer D = {NULL, DT_BYTE}; + + decode_F_table(cpustate, BITS(op,0x0008), &D); + + backupVal = *((UINT64*)D.addr); + + *((UINT64*)D.addr) = *((UINT64*)D.addr) >> 16; + + if(backupVal & U64(0x0000008000000000)) + *((UINT64*)D.addr) |= U64(0x000000ffff000000); + else + *((UINT64*)D.addr) &= U64(0x0000000000ffffff); + + /* S L E U N Z V C */ + /* - * * * * * 0 ? */ + /* TODO: E, U */ + if (*((UINT64*)D.addr) & U64(0x0000008000000000)) DSP56K_N_SET(); else DSP56K_N_CLEAR(); + if (*((UINT64*)D.addr) == 0) DSP56K_Z_SET(); else DSP56K_Z_CLEAR(); + DSP56K_V_CLEAR(); + if (backupVal & U64(0x0000000000008000)) DSP56K_C_SET(); else DSP56K_C_CLEAR(); + + cycles += 2; + return 1; +} + +/* BFCHG : 0001 0100 11Pp pppp BBB1 0010 iiii iiii : A-38 */ +/* BFCLR : 0001 0100 11Pp pppp BBB0 0100 iiii iiii : A-40 */ +/* BFSET : 0001 0100 11Pp pppp BBB1 1000 iiii iiii : A-42 */ +/* BFTSTH : 0001 0100 01Pp pppp BBB1 0000 iiii iiii : A-44 */ +/* BFTSTL : 0001 0100 01Pp pppp BBB0 0000 iiii iiii : A-46 */ +static size_t dsp56k_op_bfop(dsp56k_core* cpustate, const UINT16 op, const UINT16 op2, UINT8* cycles) +{ + UINT16 workAddr = 0x0000; + UINT16 workingWord = 0x0000; + UINT16 previousValue = 0x0000; + typed_pointer tempTP = { NULL, DT_BYTE }; + + UINT16 iVal = op2 & 0x00ff; + decode_BBB_bitmask(cpustate, BITS(op2,0xe000), &iVal); + + workAddr = assemble_address_from_Pppppp_table(cpustate, BITS(op,0x0020), BITS(op,0x001f)); + previousValue = cpustate->data->read_word(ADDRESS(workAddr)); + workingWord = previousValue; + + switch(BITS(op2, 0x1f00)) + { + case 0x12: /* BFCHG */ + workingWord ^= iVal; + break; + case 0x04: /* BFCLR */ + workingWord = workingWord & (~iVal); + break; + case 0x18: /* BFSET */ + workingWord = workingWord | iVal; + break; + case 0x10: /* BFTSTH */ + /* Just the test below */ + break; + case 0x00: /* BFTSTL */ + /* Just the test below */ + break; + } + + tempTP.addr = &workingWord; + tempTP.data_type = DT_WORD; + SetDataMemoryValue(cpustate, tempTP, ADDRESS(workAddr)); + + /* S L E U N Z V C */ + /* - * - - - - - ? */ + /* TODO: L */ + switch(BITS(op2, 0x1f00)) + { + case 0x12: /* BFCHG */ + if ((iVal & previousValue) == iVal) DSP56K_C_SET(); else DSP56K_C_CLEAR(); break; + case 0x04: /* BFCLR */ + if ((iVal & previousValue) == iVal) DSP56K_C_SET(); else DSP56K_C_CLEAR(); break; + case 0x18: /* BFSET */ + if ((iVal & previousValue) == iVal) DSP56K_C_SET(); else DSP56K_C_CLEAR(); break; + case 0x10: /* BFTSTH */ + if ((iVal & previousValue) == iVal) DSP56K_C_SET(); else DSP56K_C_CLEAR(); break; + case 0x00: /* BFTSTL */ + if ((iVal & previousValue) == 0x0000) DSP56K_C_SET(); else DSP56K_C_CLEAR(); break; + } + + cycles += 4; /* TODO: + mvb oscillator clock cycles */ + return 2; +} + +/* BFCHG : 0001 0100 101- --RR BBB1 0010 iiii iiii : A-38 */ +/* BFCLR : 0001 0100 101- --RR BBB0 0100 iiii iiii : A-40 */ +/* BFSET : 0001 0100 101- --RR BBB1 1000 iiii iiii : A-42 */ +/* BFTSTH : 0001 0100 001- --RR BBB1 0000 iiii iiii : A-44 */ +/* BFTSTL : 0001 0100 001- --RR BBB0 0000 iiii iiii : A-46 */ +static size_t dsp56k_op_bfop_1(dsp56k_core* cpustate, const UINT16 op, const UINT16 op2, UINT8* cycles) +{ + UINT16 workAddr = 0x0000; + UINT16 workingWord = 0x0000; + UINT16 previousValue = 0x0000; + typed_pointer R = { NULL, DT_BYTE }; + typed_pointer tempTP = { NULL, DT_BYTE }; + + UINT16 iVal = op2 & 0x00ff; + decode_BBB_bitmask(cpustate, BITS(op2,0xe000), &iVal); + + decode_RR_table(cpustate, BITS(op,0x0003), &R); + + workAddr = *((UINT16*)R.addr); + previousValue = cpustate->data->read_word(ADDRESS(workAddr)); + workingWord = previousValue; + + switch(BITS(op2, 0x1f00)) + { + case 0x12: /* BFCHG */ + workingWord ^= iVal; + break; + case 0x04: /* BFCLR */ + workingWord = workingWord & (~iVal); + break; + case 0x18: /* BFSET */ + workingWord = workingWord | iVal; + break; + case 0x10: /* BFTSTH */ + /* Just the test below */ + break; + case 0x00: /* BFTSTL */ + /* Just the test below */ + break; + } + + tempTP.addr = &workingWord; + tempTP.data_type = DT_WORD; + SetDataMemoryValue(cpustate, tempTP, ADDRESS(workAddr)); + + /* S L E U N Z V C */ + /* - * - - - - - ? */ + /* TODO: L */ + switch(BITS(op2, 0x1f00)) + { + case 0x12: /* BFCHG */ + if ((iVal & previousValue) == iVal) DSP56K_C_SET(); else DSP56K_C_CLEAR(); break; + case 0x04: /* BFCLR */ + if ((iVal & previousValue) == iVal) DSP56K_C_SET(); else DSP56K_C_CLEAR(); break; + case 0x18: /* BFSET */ + if ((iVal & previousValue) == iVal) DSP56K_C_SET(); else DSP56K_C_CLEAR(); break; + case 0x10: /* BFTSTH */ + if ((iVal & previousValue) == iVal) DSP56K_C_SET(); else DSP56K_C_CLEAR(); break; + case 0x00: /* BFTSTL */ + if ((iVal & previousValue) == 0x0000) DSP56K_C_SET(); else DSP56K_C_CLEAR(); break; + } + + cycles += 4; /* TODO: + mvb oscillator clock cycles */ + return 2; +} + +/* BFCHG : 0001 0100 100D DDDD BBB1 0010 iiii iiii : A-38 */ +/* BFCLR : 0001 0100 100D DDDD BBB0 0100 iiii iiii : A-40 */ +/* BFSET : 0001 0100 100D DDDD BBB1 1000 iiii iiii : A-42 */ +/* BFTSTH : 0001 0100 000D DDDD BBB1 0000 iiii iiii : A-44 */ +/* BFTSTL : 0001 0100 000D DDDD BBB0 0000 iiii iiii : A-46 */ +static size_t dsp56k_op_bfop_2(dsp56k_core* cpustate, const UINT16 op, const UINT16 op2, UINT8* cycles) +{ + UINT16 workingWord = 0x0000; + UINT16 previousValue = 0x0000; + + UINT16 iVal = op2 & 0x00ff; + typed_pointer S = { NULL, DT_BYTE }; + + decode_BBB_bitmask(cpustate, BITS(op2,0xe000), &iVal); + decode_DDDDD_table(cpustate, BITS(op,0x001f), &S); + + /* A & B are special */ + if (S.data_type == DT_LONG_WORD) + previousValue = ((PAIR64*)S.addr)->w.h; + else + previousValue = *((UINT16*)S.addr); + + workingWord = previousValue; + + switch(BITS(op2, 0x1f00)) + { + case 0x12: /* BFCHG */ + workingWord ^= iVal; + break; + case 0x04: /* BFCLR */ + workingWord = workingWord & (~iVal); + break; + case 0x18: /* BFSET */ + workingWord = workingWord | iVal; + break; + case 0x10: /* BFTSTH */ + /* Just the test below */ + break; + case 0x00: /* BFTSTL */ + /* Just the test below */ + break; + } + + /* Put the data back where it belongs (A & B are special) */ + if (S.data_type == DT_LONG_WORD) + ((PAIR64*)S.addr)->w.h = workingWord; + else + *((UINT16*)S.addr) = workingWord; + + /* S L E U N Z V C */ + /* - * - - - - - ? */ + /* TODO: L */ + switch(BITS(op2, 0x1f00)) + { + case 0x12: /* BFCHG */ + if ((iVal & previousValue) == iVal) DSP56K_C_SET(); else DSP56K_C_CLEAR(); break; + case 0x04: /* BFCLR */ + if ((iVal & previousValue) == iVal) DSP56K_C_SET(); else DSP56K_C_CLEAR(); break; + case 0x18: /* BFSET */ + if ((iVal & previousValue) == iVal) DSP56K_C_SET(); else DSP56K_C_CLEAR(); break; + case 0x10: /* BFTSTH */ + if ((iVal & previousValue) == iVal) DSP56K_C_SET(); else DSP56K_C_CLEAR(); break; + case 0x00: /* BFTSTL */ + if ((iVal & previousValue) == 0x0000) DSP56K_C_SET(); else DSP56K_C_CLEAR(); break; + } + + cycles += 4; /* TODO: + mvb oscillator clock cycles */ + return 2; +} + +/* Bcc : 0000 0111 --11 cccc xxxx xxxx xxxx xxxx : A-48 */ +static size_t dsp56k_op_bcc(dsp56k_core* cpustate, const UINT16 op, const UINT16 op2, UINT8* cycles) +{ + int shouldBranch = decode_cccc_table(cpustate, BITS(op,0x000f)); + + if (shouldBranch) + { + INT16 offset = (INT16)op2; + + PC += 2; + + cpustate->ppc = PC; + PC += offset; + + cycles += 4; + return 0; + } + else + { + cycles += 4; + return 2; + } + + /* S L E U N Z V C */ + /* - - - - - - - - */ + return 0; +} + +/* Bcc : 0010 11cc ccee eeee : A-48 */ +static size_t dsp56k_op_bcc_1(dsp56k_core* cpustate, const UINT16 op, UINT8* cycles) +{ + int shouldBranch = decode_cccc_table(cpustate, BITS(op,0x03c0)); + + if (shouldBranch) + { + INT16 offset = (INT16)assemble_address_from_6bit_signed_relative_short_address(cpustate, BITS(op,0x003f)); + + PC += 1; + + cpustate->ppc = PC; + PC += offset; + + cycles += 4; + return 0; + } + else + { + cycles += 4; + return 1; + } + + /* S L E U N Z V C */ + /* - - - - - - - - */ + return 0; +} + +/* Bcc : 0000 0111 RR10 cccc : A-48 */ +static size_t dsp56k_op_bcc_2(dsp56k_core* cpustate, const UINT16 op, UINT8* cycles) +{ + /* S L E U N Z V C */ + /* - - - - - - - - */ + return 0; +} + +/* BRA : 0000 0001 0011 11-- xxxx xxxx xxxx xxxx : A-50 */ +static size_t dsp56k_op_bra(dsp56k_core* cpustate, const UINT16 op, const UINT16 op2, UINT8* cycles) +{ + /* S L E U N Z V C */ + /* - - - - - - - - */ + return 0; +} + +/* BRA : 0000 1011 aaaa aaaa : A-50 */ +static size_t dsp56k_op_bra_1(dsp56k_core* cpustate, const UINT16 op, UINT8* cycles) +{ + /* 8 bit immediate, relative offset */ + INT8 branchOffset = (INT8)BITS(op,0x00ff); + + /* "The PC Contains the address of the next instruction" */ + PC += 1; + + /* Jump */ + cpustate->ppc = PC; + PC += branchOffset; + + /* S L E U N Z V C */ + /* - - - - - - - - */ + cycles += 4; /* TODO: + jx oscillator clock cycles */ + return 0; +} + +/* BRA : 0000 0001 0010 11RR : A-50 */ +static size_t dsp56k_op_bra_2(dsp56k_core* cpustate, const UINT16 op, UINT8* cycles) +{ + /* S L E U N Z V C */ + /* - - - - - - - - */ + return 0; +} + +/* BRKcc : 0000 0001 0001 cccc : A-52 */ +static size_t dsp56k_op_brkcc(dsp56k_core* cpustate, const UINT16 op, UINT8* cycles) +{ + int shouldBreak = decode_cccc_table(cpustate, BITS(op,0x000f)); + + if (shouldBreak) + { + /* TODO: I think this PC = LA thing is off-by-1, but it's working this way because its consistently so */ + cpustate->ppc = PC; + PC = LA; + + SR = SSL; /* TODO: A-83. I believe only the Loop Flag and Forever Flag come back here. */ + SP--; + + LA = SSH; + LC = SSL; + SP--; + + cycles += 8; + return 0; + } + else + { + cycles += 2; + return 1; + } + + /* S L E U N Z V C */ + /* - - - - - - - - */ + return 0; +} + +/* BScc : 0000 0111 --01 cccc xxxx xxxx xxxx xxxx : A-54 */ +static size_t dsp56k_op_bscc(dsp56k_core* cpustate, const UINT16 op, const UINT16 op2, UINT8* cycles) +{ + int shouldBranch = decode_cccc_table(cpustate, BITS(op,0x000f)); + + if (shouldBranch) + { + /* The PC Contains the address of the next instruction */ + PC += 2; + + /* Push */ + SP++; + SSH = PC; + SSL = SR; + + /* Change */ + cpustate->ppc = PC; + PC = PC + (INT16)op2; + + /* S L E U N Z V C */ + /* - - - - - - - - */ + cycles += 4; /* TODO: + jx oscillator clock cycles */ + return 0; + } + + /* S L E U N Z V C */ + /* - - - - - - - - */ + cycles += 4; /* TODO: + jx oscillator clock cycles */ + return 2; +} + +/* BScc : 0000 0111 RR00 cccc : A-54 */ +static size_t dsp56k_op_bscc_1(dsp56k_core* cpustate, const UINT16 op, UINT8* cycles) +{ + /* S L E U N Z V C */ + /* - - - - - - - - */ + return 0; +} + +/* BSR : 0000 0001 0011 10-- xxxx xxxx xxxx xxxx : A-56 */ +static size_t dsp56k_op_bsr(dsp56k_core* cpustate, const UINT16 op, const UINT16 op2, UINT8* cycles) +{ + /* The PC Contains the address of the next instruction */ + PC += 2; + + /* Push */ + SP++; + SSH = PC; + SSL = SR; + + /* Change */ + cpustate->ppc = PC; + PC = PC + (INT16)op2; + + /* S L E U N Z V C */ + /* - - - - - - - - */ + cycles += 4; /* TODO: + jx oscillator clock cycles */ + return 0; +} + +/* BSR : 0000 0001 0010 10RR : A-56 */ +static size_t dsp56k_op_bsr_1(dsp56k_core* cpustate, const UINT16 op, UINT8* cycles) +{ + /* S L E U N Z V C */ + /* - - - - - - - - */ + return 0; +} + +/* CHKAAU : 0000 0000 0000 0100 : A-58 */ +static size_t dsp56k_op_chkaau(dsp56k_core* cpustate, const UINT16 op, UINT8* cycles) +{ + /* S L E U N Z V C */ + /* - - - - ? ? ? - */ + /* V - Set if the result of the last address ALU update performed a modulo wrap. Cleared if + result of the last address ALU did not perform a modulo wrap.*/ + /* Z - Set if the result of the last address ALU update is 0. Cleared if the result of the last + address ALU is positive. */ + /* N - Set if the result of the last address ALU update is negative. Cleared if the result of the + last address ALU is positive. */ + return 0; +} + +/* DEBUG : 0000 0000 0000 0001 : A-68 */ +static size_t dsp56k_op_debug(dsp56k_core* cpustate, const UINT16 op, UINT8* cycles) +{ + /* S L E U N Z V C */ + /* - - - - - - - - */ + return 0; +} + +/* DEBUGcc : 0000 0000 0101 cccc : A-70 */ +static size_t dsp56k_op_debugcc(dsp56k_core* cpustate, const UINT16 op, UINT8* cycles) +{ + /* S L E U N Z V C */ + /* - - - - - - - - */ + return 0; +} + +/* DIV : 0001 0101 0--0 F1DD : A-76 */ +/* WARNING : DOCS SAY THERE IS A PARALLEL MOVE HERE !!! */ +static size_t dsp56k_op_div(dsp56k_core* cpustate, const UINT16 op, UINT8* cycles) +{ + /* WARNING : THIS DOES NOT WORK. IT DOESN'T EVEN TRY !!! */ + typed_pointer S = {NULL, DT_BYTE}; + typed_pointer D = {NULL, DT_BYTE}; + + decode_DDF_table(cpustate, BITS(op,0x0003), BITS(op,0x0008), &S, &D); + + /* S L E U N Z V C */ + /* - * - - - - ? ? */ + /* V - Set if an arithmetic overflow occurs in the 40 bit result. Also set if the most significantst + bit of the destination operand is changed as a result of the left shift. Cleared otherwise. */ + /* C - Set if bit 39 of the result is cleared. Cleared otherwise. */ + cycles += 2; + return 1; +} + +/* DMAC : 0001 0101 10s1 FsQQ : A-80 */ +static size_t dsp56k_op_dmac(dsp56k_core* cpustate, const UINT16 op, UINT8* cycles) +{ + UINT8 ss = 0; + INT64 result = 0; + + void* D = NULL; + void* S1 = NULL; + void* S2 = NULL; + + decode_QQF_special_table(cpustate, BITS(op,0x0003), BITS(op,0x0008), &S1, &S2, &D); + + ss = BITS(op,0x0024); + + /* Fixed-point 2's complement multiplication requires a shift */ + if (ss == 0x00 || ss == 0x01) + { + /* Signed * Signed */ + INT32 s1 = ((INT32)(*((UINT16*)S1))); + INT32 s2 = ((INT32)(*((UINT16*)S2))); + result = ( s1 * s2 ) << 1; + } + else if (ss == 0x2) + { + /* Signed * Unsigned */ + /* WARNING : THERE IS A HUGE CHANCE THIS DOESN'T WORK RIGHT */ + INT32 s1 = ((INT32)(*((UINT16*)S1))); + INT32 s2 = (UINT32)(*((UINT16*)S2)); + result = ( s1 * s2 ) << 1; + } + else if (ss == 0x3) + { + /* Unsigned * Unsigned */ + UINT32 s1 = (UINT32)(*((UINT16*)S1)); + UINT32 s2 = (UINT32)(*((UINT16*)S2)); + result = ( s1 * s2 ) << 1; + } + + /* Shift right, then accumulate */ + (*((UINT64*)D)) = (*((UINT64*)D)) >> 16; + (*((UINT64*)D)) += result; + + /* S L E U N Z V C */ + /* - * * * * * * - */ + /* TODO: L, E, U, V */ + if ( *((UINT64*)D) & U64(0x0000008000000000)) DSP56K_N_SET(); else DSP56K_N_CLEAR(); + if ((*((UINT64*)D) & U64(0x000000ffffffffff)) == 0) DSP56K_Z_SET(); else DSP56K_Z_CLEAR(); + + cycles += 2; + return 1; +} + +/* DO : 0000 0000 110- --RR xxxx xxxx xxxx xxxx : A-82 */ +static size_t dsp56k_op_do(dsp56k_core* cpustate, const UINT16 op, const UINT16 op2, UINT8* cycles) +{ + /* S L E U N Z V C */ + /* - * - - - - - - */ + return 0; +} + +/* DO : 0000 1110 iiii iiii xxxx xxxx xxxx xxxx : A-82 */ +static size_t dsp56k_op_do_1(dsp56k_core* cpustate, const UINT16 op, const UINT16 op2, UINT8* cycles) +{ + UINT8 retSize = 0; + UINT8 iValue = BITS(op,0x00ff); + + /* Don't execute if the loop counter == 0 */ + if (iValue != 0x00) + { + /* First instruction cycle */ + SP++; /* TODO: Should i really inc here first? */ + SSH = LA; + SSL = LC; + LC = (UINT16)iValue; + + + /* Second instruction cycle */ + SP++; /* TODO: See above */ + SSH = PC + 2; /* Keep these stack entries in 'word-based-index' space */ + SSL = SR; + LA = PC + 2 + op2; /* TODO: The docs subtract 1 from here? */ + + + /* Third instruction cycle */ + LF_bit_set(cpustate, 1); + + /* Undocumented, but it must be true to nest Dos in DoForevers */ + FV_bit_set(cpustate, 0); + + + /* S L E U N Z V C */ + /* - * - - - - - - */ + /* TODO : L */ + + cycles += 6; /* TODO: + mv oscillator cycles */ + retSize = 2; + } + else + { + /* Skip over the contents of the loop */ + cpustate->ppc = PC; + PC = PC + 2 + op2; + + cycles += 10; /* TODO: + mv oscillator cycles */ + retSize = 0; + } + + return retSize; +} + +/* DO : 0000 0100 000D DDDD xxxx xxxx xxxx xxxx : A-82 */ +static size_t dsp56k_op_do_2(dsp56k_core* cpustate, const UINT16 op, const UINT16 op2, UINT8* cycles) +{ + UINT8 retSize = 0; + UINT16 lValue = 0x0000; + typed_pointer S = {NULL, DT_BYTE}; + decode_DDDDD_table(cpustate, BITS(op,0x001f), &S); + + /* TODO: Does not properly shift-limit sources A&B - Fix per the docs. */ + /* TODO: There are other cases besides A&B this code won't work. */ + if (S.addr == &A) lValue = *((UINT16*)(&A1)); + else if (S.addr == &B) lValue = *((UINT16*)(&B1)); + else lValue = *((UINT16*)S.addr); + + /* HACK */ + if (lValue >= 0xfff0) + { + logerror("Dsp56k : DO_2 operation changed %04x to 0000.\n", lValue); + lValue = 0x0000; + } + + /* TODO: Fix for special cased SP S */ + if (S.addr == &SP) + logerror("DSP56k: do with SP as the source not properly implemented yet.\n"); + + /* TODO: Fix for special cased SSSL S */ + if (S.addr == &SSL) + logerror("DSP56k: do with SP as the source not properly implemented yet.\n"); + + /* Don't execute if the loop counter == 0 */ + if (lValue != 0x00) + { + /* First instruction cycle */ + SP++; /* TODO: Should i really inc here first? */ + SSH = LA; + SSL = LC; + LC = (UINT16)lValue; + + + /* Second instruction cycle */ + SP++; /* TODO: See above */ + SSH = PC + 2; /* Keep these stack entries in 'word-based-index' space */ + SSL = SR; + LA = PC + 2 + op2; /* TODO: The docs subtract 1 from here? */ + + + /* Third instruction cycle */ + LF_bit_set(cpustate, 1); + + + /* S L E U N Z V C */ + /* - * - - - - - - */ + /* TODO : L */ + + cycles += 6; /* TODO: + mv oscillator cycles */ + retSize = 2; + } + else + { + /* Skip over the contents of the loop */ + cpustate->ppc = PC; + PC = PC + 2 + op2; + + cycles += 10; /* TODO: + mv oscillator cycles */ + retSize = 0; + } + + return retSize; +} + +/* DO FOREVER : 0000 0000 0000 0010 xxxx xxxx xxxx xxxx : A-88 */ +static size_t dsp56k_op_doforever(dsp56k_core* cpustate, const UINT16 op, const UINT16 op2, UINT8* cycles) +{ + /* First instruction cycle */ + SP++; + SSH = LA; + SSL = LC; + + /* Second instruction cycle */ + SP++; + SSH = PC + 2; + SSL = SR; + LA = PC + 2 + op2; + + /* Third instruction cycle */ + LF_bit_set(cpustate, 1); + FV_bit_set(cpustate, 1); + + /* S L E U N Z V C */ + /* - - - - - - - - */ + cycles += 6; + return 2; +} + +/* ENDDO : 0000 0000 0000 1001 : A-92 */ +static size_t dsp56k_op_enddo(dsp56k_core* cpustate, const UINT16 op, UINT8* cycles) +{ + /* S L E U N Z V C */ + /* - - - - - - - - */ + return 0; +} + +/* EXT : 0001 0101 0101 F010 : A-96 */ +static size_t dsp56k_op_ext(dsp56k_core* cpustate, const UINT16 op, UINT8* cycles) +{ + /* S L E U N Z V C */ + /* - * * * * * * - */ + return 0; +} + +/* ILLEGAL : 0000 0000 0000 1111 : A-98 */ +static size_t dsp56k_op_illegal(dsp56k_core* cpustate, const UINT16 op, UINT8* cycles) +{ + /* S L E U N Z V C */ + /* - - - - - - - - */ + return 0; +} + +/* IMAC : 0001 0101 1010 FQQQ : A-100 */ +static size_t dsp56k_op_imac(dsp56k_core* cpustate, const UINT16 op, UINT8* cycles) +{ + INT64 opD = 0; + INT64 result = 0; + + INT32 s1 = 0; + INT32 s2 = 0; + + void* D = NULL; + void* S1 = NULL; + void* S2 = NULL; + + decode_QQQF_table(cpustate, BITS(op,0x0007), BITS(op,0x0008), &S1, &S2, &D); + + /* Cast both values as being signed */ + s1 = *((INT16*)S1); + s2 = *((INT16*)S2); + + /* Integral multiply doesn't require the shift */ + result = (s1 * s2); + + /* Shift result 16 bits to the left before adding to destination */ + result = (result << 16) & 0xffff0000; + + /* Sign extend D into a temp variable */ + opD = (*((UINT64*)D)); + if (opD & U64(0x0000008000000000)) + opD |= U64(0xffffff0000000000); + else + opD &= U64(0x000000ffffffffff); + + /* Accumulate */ + opD += result; + + /* And out the bits that don't live in the register */ + opD &= U64(0x000000ffffffffff); + + (*((UINT64*)D)) = (UINT64)opD; + + /* S L E U N Z V C */ + /* - * ? ? * ? ? - */ + /* TODO: L */ + /* U,E - Will not be set correctly by this instruction*/ + if ( *((UINT64*)D) & U64(0x0000008000000000)) DSP56K_N_SET(); else DSP56K_N_CLEAR(); + if ((*((UINT64*)D) & U64(0x000000ffffff0000)) == 0) DSP56K_Z_SET(); else DSP56K_Z_CLEAR(); + DSP56K_V_CLEAR(); + + cycles += 2; + return 1; +} + +/* IMPY : 0001 0101 1000 FQQQ : A-102 */ +static size_t dsp56k_op_impy(dsp56k_core* cpustate, const UINT16 op, UINT8* cycles) +{ + /* S L E U N Z V C */ + /* - * ? ? * ? ? - */ + /* Z - Set if the 24 most significant bits of the destination result are all zeroes. */ + /* U,E - Will not be set correctly by this instruction*/ + /* V - Set to zero regardless of the overflow */ + return 0; +} + +/* Jcc : 0000 0110 --11 cccc xxxx xxxx xxxx xxxx : A-108 */ +static size_t dsp56k_op_jcc(dsp56k_core* cpustate, const UINT16 op, const UINT16 op2, UINT8* cycles) +{ + /* S L E U N Z V C */ + /* - - - - - - - - */ + return 0; +} + +/* Jcc : 0000 0110 RR10 cccc : A-108 */ +static size_t dsp56k_op_jcc_1(dsp56k_core* cpustate, const UINT16 op, UINT8* cycles) +{ + /* S L E U N Z V C */ + /* - - - - - - - - */ + return 0; +} + +/* JMP : 0000 0001 0011 01-- xxxx xxxx xxxx xxxx : A-110 */ +static size_t dsp56k_op_jmp(dsp56k_core* cpustate, const UINT16 op, const UINT16 op2, UINT8* cycles) +{ + cpustate->ppc = PC; + PC = op2; + + /* S L E U N Z V C */ + /* - - - - - - - - */ + + cycles += 4; /* TODO: + jx */ + return 0; +} + +/* JMP : 0000 0001 0010 01RR : A-110 */ +static size_t dsp56k_op_jmp_1(dsp56k_core* cpustate, const UINT16 op, UINT8* cycles) +{ + typed_pointer R = { NULL, DT_BYTE }; + decode_RR_table(cpustate, BITS(op,0x0003), &R); + + cpustate->ppc = PC; + PC = *((UINT16*)R.addr); + + /* S L E U N Z V C */ + /* - - - - - - - - */ + + cycles += 4; /* TODO: + jx */ + return 0; +} + +/* JScc : 0000 0110 --01 cccc xxxx xxxx xxxx xxxx : A-112 */ +static size_t dsp56k_op_jscc(dsp56k_core* cpustate, const UINT16 op, const UINT16 op2, UINT8* cycles) +{ + int shouldJump = decode_cccc_table(cpustate, BITS(op,0x000f)); + + if(shouldJump) + { + /* TODO: It says "signed" absolute offset. Weird. */ + UINT16 branchOffset = op2; + + /* TODO: Verify, since it's not in the docs, but it must be true */ + PC += 2; + + SP++; + SSH = PC; + SSL = SR; + + cpustate->ppc = PC; + PC = branchOffset; + + cycles += 4; /* TODO: +jx oscillator clock cycles */ + return 0; + } + else + { + cycles += 4; /* TODO: +jx oscillator clock cycles */ + return 2; + } + + /* S L E U N Z V C */ + /* - - - - - - - - */ + return 0; +} + +/* JScc : 0000 0110 RR00 cccc : A-112 */ +static size_t dsp56k_op_jscc_1(dsp56k_core* cpustate, const UINT16 op, UINT8* cycles) +{ + /* S L E U N Z V C */ + /* - - - - - - - - */ + return 0; +} + +/* JSR : 0000 0001 0011 00-- xxxx xxxx xxxx xxxx : A-114 */ +static size_t dsp56k_op_jsr(dsp56k_core* cpustate, const UINT16 op, const UINT16 op2, UINT8* cycles) +{ + /* TODO: It says "signed" absolute offset. Weird. */ + UINT16 branchOffset = op2; + + /* TODO: Verify, since it's not in the docs, but it must be true */ + PC += 2; + + /* TODO: This is a hacky implementation of Long vs Fast Interrupts. Do it right someday! */ + if (PC < ADDRESS(0x40)) + { + /* Long interrupt gets the previous PC, not the current one */ + SP++; + SSH = cpustate->ppc; + SSL = SR; + + cpustate->ppc = cpustate->ppc; + PC = branchOffset; + } + else + { + /* Normal operation */ + SP++; + SSH = PC; + SSL = SR; + + cpustate->ppc = PC; + PC = branchOffset; + } + + /* S L E U N Z V C */ + /* - - - - - - - - */ + cycles += 4; /* TODO: + jx oscillator cycles */ + return 0; +} + +/* JSR : 0000 1010 AAAA AAAA : A-114 */ +static size_t dsp56k_op_jsr_1(dsp56k_core* cpustate, const UINT16 op, UINT8* cycles) +{ + /* S L E U N Z V C */ + /* - - - - - - - - */ + return 0; +} + +/* JSR : 0000 0001 0010 00RR : A-114 */ +static size_t dsp56k_op_jsr_2(dsp56k_core* cpustate, const UINT16 op, UINT8* cycles) +{ + /* S L E U N Z V C */ + /* - - - - - - - - */ + return 0; +} + +/* LEA : 0000 0001 11TT MMRR : A-116 */ +static size_t dsp56k_op_lea(dsp56k_core* cpustate, const UINT16 op, UINT8* cycles) +{ + UINT16 ea = 0; + UINT16 *rX = NULL; + UINT16 *nX = NULL; + typed_pointer D = {NULL, DT_BYTE}; + decode_TT_table(cpustate, BITS(op,0x0030), &D); + + /* TODO: change the execute_mm_functions to return values. Maybe */ + /* Because this calculation isn't applied, do everything locally */ + /* RR table */ + switch(BITS(op,0x0003)) + { + case 0x0: rX = &R0; nX = &N0; break; + case 0x1: rX = &R1; nX = &N1; break; + case 0x2: rX = &R2; nX = &N2; break; + case 0x3: rX = &R3; nX = &N3; break; + } + + /* MM table */ + switch(BITS(op,0x000c)) + { + case 0x0: ea = *rX; break; + case 0x1: ea = *rX + 1; break; + case 0x2: ea = *rX - 1; break; + case 0x3: ea = *rX + *nX; break; + } + + *((UINT16*)D.addr) = ea; + + /* S L E U N Z V C */ + /* - - - - - - - - */ + return 1; +} + +/* LEA : 0000 0001 10NN MMRR : A-116 */ +static size_t dsp56k_op_lea_1(dsp56k_core* cpustate, const UINT16 op, UINT8* cycles) +{ + /* S L E U N Z V C */ + /* - - - - - - - - */ + return 0; +} + +/* MAC(su,uu) : 0001 0101 1110 FsQQ : A-126 */ +static size_t dsp56k_op_macsuuu(dsp56k_core* cpustate, const UINT16 op, UINT8* cycles) +{ + UINT8 s = 0; + INT64 result = 0; + + void* D = NULL; + void* S1 = NULL; + void* S2 = NULL; + + decode_QQF_special_table(cpustate, BITS(op,0x0003), BITS(op,0x0008), &S1, &S2, &D); + + s = BITS(op,0x0004); + + /* Fixed-point 2's complement multiplication requires a shift */ + if (s) + { + /* Unsigned * Unsigned */ + UINT32 s1 = (UINT32)(*((UINT16*)S1)); + UINT32 s2 = (UINT32)(*((UINT16*)S2)); + result = ( s1 * s2 ) << 1; + } + else + { + /* Signed * Unsigned */ + /* WARNING : THERE IS A HUGE CHANCE THIS DOESN'T WORK RIGHT */ + INT32 s1 = ((INT32)(*((UINT16*)S1))); + INT32 s2 = (UINT32)(*((UINT16*)S2)); + result = ( s1 * s2 ) << 1; + } + + (*((UINT64*)D)) += result; + + /* And out the bits that don't live in the register */ + (*((UINT64*)D)) &= U64(0x000000ffffffffff); + + /* S L E U N Z V C */ + /* - * * * * * * - */ + /* TODO: L, E, U, V */ + if ( *((UINT64*)D) & U64(0x0000008000000000)) DSP56K_N_SET(); else DSP56K_N_CLEAR(); + if ((*((UINT64*)D) & U64(0x000000ffffffffff)) == 0) DSP56K_Z_SET(); else DSP56K_Z_CLEAR(); + + cycles += 2; + return 1; +} + +/* MOVE : 0000 0101 BBBB BBBB ---- HHHW 0001 0001 : A-128 */ +static size_t dsp56k_op_move_2(dsp56k_core* cpustate, const UINT16 op, const UINT16 op2, UINT8* cycles) +{ + /* S L E U N Z V C */ + /* * * - - - - - - */ + return 0; +} + +/* MOVE(C) : 0011 1WDD DDD0 MMRR : A-144 */ +static size_t dsp56k_op_movec(dsp56k_core* cpustate, const UINT16 op, UINT8* cycles) +{ + UINT8 W; + typed_pointer R = { NULL, DT_BYTE }; + typed_pointer SD = { NULL, DT_BYTE }; + + W = BITS(op,0x0400); + decode_DDDDD_table(cpustate, BITS(op,0x03e0), &SD); + decode_RR_table(cpustate, BITS(op,0x0003), &R); + + if (W) + { + /* Write D */ + UINT16 value = cpustate->data->read_word(ADDRESS(*((UINT16*)R.addr))) ; + typed_pointer temp_src = { &value, DT_WORD }; + SetDestinationValue(temp_src, SD); + } + else + { + /* Read S */ + UINT16 dataMemOffset = *((UINT16*)R.addr); + SetDataMemoryValue(cpustate, SD, ADDRESS(dataMemOffset)); + } + + execute_MM_table(cpustate, BITS(op,0x0003), BITS(op,0x000c)); + + /* S L E U N Z V C */ + /* * ? ? ? ? ? ? ? */ + /* All ? bits - If SR is specified as a destination operand, set according to the corresponding + bit of the source operand. If SR is not specified as a destination operand, L is set if data + limiting occurred. All ? bits are not affected otherwise.*/ + if (W && (SD.addr != &SR)) + { + /* If you're writing to something other than the SR */ + /* TODO */ + } + + cycles += 2; /* TODO: + mvc */ + return 1; +} + +/* MOVE(C) : 0011 1WDD DDD1 q0RR : A-144 */ +static size_t dsp56k_op_movec_1(dsp56k_core* cpustate, const UINT16 op, UINT8* cycles) +{ + UINT8 W; + UINT16 memOffset; + typed_pointer SD = {NULL, DT_BYTE}; + + W = BITS(op,0x0400); + decode_DDDDD_table(cpustate, BITS(op,0x03e0), &SD); + memOffset = execute_q_table(cpustate, BITS(op,0x0003), BITS(op,0x0008)); + + if (W) + { + /* Write D */ + UINT16 tempData = cpustate->data->read_word(ADDRESS(memOffset)); + typed_pointer temp_src = { (void*)&tempData, DT_WORD }; + SetDestinationValue(temp_src, SD); + } + else + { + /* Read S */ + UINT16 tempData = *((UINT16*)SD.addr); + typed_pointer temp_src = { (void*)&tempData, DT_WORD }; + SetDataMemoryValue(cpustate, temp_src, ADDRESS(memOffset)); + } + + /* S L E U N Z V C */ + /* * ? ? ? ? ? ? ? */ + /* All ? bits - If SR is specified as a destination operand, set according to the corresponding + bit of the source operand. If SR is not specified as a destination operand, L is set if data + limiting occurred. All ? bits are not affected otherwise.*/ + if (W && (SD.addr != &SR)) + { + /* If you're writing to something other than the SR */ + /* TODO */ + } + + cycles += 2; /* + mvc oscillator clock cycles */ + return 1; +} + +/* MOVE(C) : 0011 1WDD DDD1 Z11- : A-144 */ +static size_t dsp56k_op_movec_2(dsp56k_core* cpustate, const UINT16 op, UINT8* cycles) +{ + UINT8 W; + UINT16 memOffset; + typed_pointer SD = {NULL, DT_BYTE}; + typed_pointer XMemOffset = {NULL, DT_BYTE}; + + W = BITS(op,0x0400); + decode_Z_table(cpustate, BITS(op,0x0008), &XMemOffset); + decode_DDDDD_table(cpustate, BITS(op,0x03e0), &SD); + + memOffset = *((UINT16*)XMemOffset.addr); + + if (W) + { + /* Write D */ + UINT16 tempData = cpustate->data->read_word(ADDRESS(memOffset)); + typed_pointer temp_src = { (void*)&tempData, DT_WORD }; + SetDestinationValue(temp_src, SD); + } + else + { + /* Read S */ + UINT16 tempData = *((UINT16*)SD.addr); + typed_pointer temp_src = { (void*)&tempData, DT_WORD }; + SetDataMemoryValue(cpustate, temp_src, ADDRESS(memOffset)); + } + + + /* S L E U N Z V C */ + /* * ? ? ? ? ? ? ? */ + /* All ? bits - If SR is specified as a destination operand, set according to the corresponding + bit of the source operand. If SR is not specified as a destination operand, L is set if data + limiting occurred. All ? bits are not affected otherwise.*/ + if (W && (SD.addr != &SR)) + { + /* If you're writing to something other than the SR */ + /* TODO */ + } + + cycles += 2; /* + mvc oscillator clock cycles */ + return 1; +} + +/* MOVE(C) : 0011 1WDD DDD1 t10- xxxx xxxx xxxx xxxx : A-144 */ +static size_t dsp56k_op_movec_3(dsp56k_core* cpustate, const UINT16 op, const UINT16 op2, UINT8* cycles) +{ + UINT8 W; + UINT8 t; + typed_pointer SD = { NULL, DT_BYTE }; + + W = BITS(op,0x0400); + t = BITS(op,0x0008); + decode_DDDDD_table(cpustate, BITS(op,0x03e0), &SD); + + if (W) + { + /* Write D */ + if (t) + { + /* 16-bit long data */ + typed_pointer temp_src = { (void*)&op2, DT_WORD }; + SetDestinationValue(temp_src, SD); + } + else + { + /* 16-bit long address */ + UINT16 tempD = cpustate->data->read_word(ADDRESS(op2)); + typed_pointer tempTP = {&tempD, DT_WORD}; + SetDestinationValue(tempTP, SD); + } + } + else + { + /* Read S */ + if (t) + { + /* 16-bit long data */ + logerror("DSP56k: Movec - I don't think this exists?"); + } + else + { + /* 16-bit long address */ + SetDataMemoryValue(cpustate, SD, ADDRESS(op2)); + } + } + + /* S L E U N Z V C */ + /* * ? ? ? ? ? ? ? */ + /* All ? bits - If SR is specified as a destination operand, set according to the corresponding + bit of the source operand. If SR is not specified as a destination operand, L is set if data + limiting occurred. All ? bits are not affected otherwise.*/ + if (W && (SD.addr != &SR)) + { + /* If you're writing to something other than the SR */ + /* TODO */ + } + + cycles += 2; /* TODO: + mvc */ + return 2; +} + +/* MOVE(C) : 0010 10dd dddD DDDD : A-144 */ +static size_t dsp56k_op_movec_4(dsp56k_core* cpustate, const UINT16 op, UINT8* cycles) +{ + typed_pointer S = {NULL, DT_BYTE}; + typed_pointer D = {NULL, DT_BYTE}; + + decode_DDDDD_table(cpustate, BITS(op,0x03e0), &S); + decode_DDDDD_table(cpustate, BITS(op,0x001f), &D); + + SetDestinationValue(S, D); + + /* S L E U N Z V C */ + /* * ? ? ? ? ? ? ? */ + /* All ? bits - If SR is specified as a destination operand, set according to the corresponding + bit of the source operand. If SR is not specified as a destination operand, L is set if data + limiting occurred. All ? bits are not affected otherwise.*/ + if (D.addr != &SR) + { + /* If you're writing to something other than the SR */ + /* TODO */ + } + + cycles += 2; + return 1; +} + +/* MOVE(C) : 0000 0101 BBBB BBBB 0011 1WDD DDD0 ---- : A-144 */ +static size_t dsp56k_op_movec_5(dsp56k_core* cpustate, const UINT16 op, const UINT16 op2, UINT8* cycles) +{ + INT8 xx; + UINT8 W; + UINT16 memOffset; + typed_pointer SD = { NULL, DT_BYTE }; + + xx = (INT8)(op & 0x00ff); + W = BITS(op2,0x0400); + decode_DDDDD_table(cpustate, BITS(op2,0x03e0), &SD); + + memOffset = R2 + (INT16)xx; + + if (W) + { + /* Write D */ + UINT16 tempData = cpustate->data->read_word(ADDRESS(memOffset)); + typed_pointer temp_src = { (void*)&tempData, DT_WORD }; + SetDestinationValue(temp_src, SD); + } + else + { + /* Read S */ + UINT16 tempData = *((UINT16*)SD.addr); + typed_pointer temp_src = { (void*)&tempData, DT_WORD }; + SetDataMemoryValue(cpustate, temp_src, ADDRESS(memOffset)); + } + + /* S L E U N Z V C */ + /* * ? ? ? ? ? ? ? */ + /* All ? bits - If SR is specified as a destination operand, set according to the corresponding + bit of the source operand. If SR is not specified as a destination operand, L is set if data + limiting occurred. All ? bits are not affected otherwise.*/ + if (W && (SD.addr != &SR)) + { + /* If you're writing to something other than the SR */ + /* TODO */ + } + + cycles += 2; /* TODO: + mvc oscillator clock cycles */ + return 2; +} + +/* MOVE(I) : 0010 00DD BBBB BBBB : A-150 */ +static size_t dsp56k_op_movei(dsp56k_core* cpustate, const UINT16 op, UINT8* cycles) +{ + typed_pointer D = {NULL, DT_BYTE}; + typed_pointer immTP = {NULL, DT_BYTE}; + + /* Typecasting to INT16 sign-extends the BBBBBBBB operand */ + UINT16 immediateSignExtended = (INT16)(op & 0x00ff); + immTP.addr = &immediateSignExtended; + immTP.data_type = DT_WORD; + + decode_DD_table(cpustate, BITS(op,0x0300), &D); + + SetDestinationValue(immTP, D); + + /* S L E U N Z V C */ + /* - - - - - - - - */ + cycles += 2; + return 1; +} + +/* MOVE(M) : 0000 001W RR0M MHHH : A-152 */ +static size_t dsp56k_op_movem(dsp56k_core* cpustate, const UINT16 op, UINT8* cycles) +{ + UINT8 W; + typed_pointer R = { NULL, DT_BYTE }; + typed_pointer SD = { NULL, DT_BYTE }; + + W = BITS(op,0x0100); + decode_RR_table(cpustate, BITS(op,0x00c0), &R); + decode_HHH_table(cpustate, BITS(op,0x0007), &SD); + + if (W) + { + /* Read from Program Memory */ + typed_pointer data; + UINT16 ldata = cpustate->program->read_word(ADDRESS(*((UINT16*)R.addr))); + + data.addr = &ldata; + data.data_type = DT_WORD; + SetDestinationValue(data, SD) ; + } + else + { + /* Write to Program Memory */ + SetProgramMemoryValue(cpustate, SD, ADDRESS(*((UINT16*)R.addr))) ; + } + + execute_MM_table(cpustate, BITS(op,0x00c0), BITS(op,0x0018)); + + /* S L E U N Z V C */ + /* * * - - - - - - */ + /* TODO: S, L */ + cycles += 2; /* TODO: + mvm oscillator clock cycles */ + return 1; +} + +/* MOVE(M) : 0000 001W RR11 mmRR : A-152 */ +static size_t dsp56k_op_movem_1(dsp56k_core* cpustate, const UINT16 op, UINT8* cycles) +{ + /* S L E U N Z V C */ + /* * * - - - - - - */ + return 0; +} + +/* MOVE(M) : 0000 0101 BBBB BBBB 0000 001W --0- -HHH : A-152 */ +static size_t dsp56k_op_movem_2(dsp56k_core* cpustate, const UINT16 op, const UINT16 op2, UINT8* cycles) +{ + /* S L E U N Z V C */ + /* * * - - - - - - */ + return 0; +} + +/* MOVE(P) : 0001 100W HH1p pppp : A-156 */ +static size_t dsp56k_op_movep(dsp56k_core* cpustate, const UINT16 op, UINT8* cycles) +{ + UINT16 W; + UINT16 pp; + typed_pointer SD = {NULL, DT_BYTE}; + + decode_HH_table(cpustate, BITS(op,0x00c0), &SD); + /* TODO: Special cases for A & B */ + + pp = op & 0x001f; + pp = assemble_address_from_IO_short_address(cpustate, pp); + + W = BITS(op,0x0100); + + if (W) + { + UINT16 data = cpustate->data->read_word(ADDRESS(pp)); + + typed_pointer tempTP; + tempTP.addr = &data; + tempTP.data_type = DT_WORD; + + SetDestinationValue(tempTP, SD); + } + else + { + SetDataMemoryValue(cpustate, SD, ADDRESS(pp)); + } + + /* S L E U N Z V C */ + /* * * - - - - - - */ + /* TODO: S, L */ + + cycles += 4; /* TODO: + mvp oscillator cycles */ + return 1; +} + +/* MOVE(P) : 0000 110W RRmp pppp : A-156 */ +static size_t dsp56k_op_movep_1(dsp56k_core* cpustate, const UINT16 op, UINT8* cycles) +{ + /* X: and X: */ + UINT16 W; + UINT16 pp; + + typed_pointer SD = {NULL, DT_BYTE}; + decode_RR_table(cpustate, BITS(op,0x00c0), &SD); + + pp = op & 0x001f; + pp = assemble_address_from_IO_short_address(cpustate, pp); + + W = BITS(op,0x0100); + + /* A little different than most W if's - opposite read and write */ + if (W) + { + UINT16 data = cpustate->data->read_word(ADDRESS(*((UINT16*)SD.addr))); + + typed_pointer tempTP; + tempTP.addr = &data; + tempTP.data_type = DT_WORD; + + SetDataMemoryValue(cpustate, tempTP, ADDRESS(pp)); + } + else + { + /* TODO */ + fatalerror("dsp56k : move(p) NOTHING HERE (yet)\n") ; + } + + /* Postincrement */ + execute_m_table(cpustate, BITS(op,0x00c0), BITS(op,0x0020)); + + /* S L E U N Z V C */ + /* * * - - - - - - */ + /* TODO: S, L */ + cycles += 4; /* TODO: + mvp oscillator cycles */ + return 1; +} + +/* MOVE(S) : 0001 100W HH0a aaaa : A-158 */ +static size_t dsp56k_op_moves(dsp56k_core* cpustate, const UINT16 op, UINT8* cycles) +{ + /* S L E U N Z V C */ + /* * * - - - - - - */ + return 0; +} + +/* MPY(su,uu) : 0001 0101 1100 FsQQ : A-164 */ +static size_t dsp56k_op_mpysuuu(dsp56k_core* cpustate, const UINT16 op, UINT8* cycles) +{ + UINT8 s = 0; + INT64 result = 0; + + void* D = NULL; + void* S1 = NULL; + void* S2 = NULL; + + decode_QQF_special_table(cpustate, BITS(op,0x0003), BITS(op,0x0008), &S1, &S2, &D); + + s = BITS(op,0x0004); + + /* Fixed-point 2's complement multiplication requires a shift */ + if (s) + { + /* Unsigned * Unsigned */ + UINT32 s1 = (UINT32)(*((UINT16*)S1)); + UINT32 s2 = (UINT32)(*((UINT16*)S2)); + result = ( s1 * s2 ) << 1; + } + else + { + /* Signed * Unsigned */ + /* WARNING : THERE IS A HUGE CHANCE THIS DOESN'T WORK RIGHT */ + INT32 s1 = ((INT32)(*((UINT16*)S1))); + INT32 s2 = (UINT32)(*((UINT16*)S2)); + result = ( s1 * s2 ) << 1; + } + + (*((UINT64*)D)) = result; + + /* And out the bits that don't live in the register */ + (*((UINT64*)D)) &= U64(0x000000ffffffffff); + + /* S L E U N Z V C */ + /* - * * * * * * - */ + /* TODO: L, E, U, V */ + if ( *((UINT64*)D) & U64(0x0000008000000000)) DSP56K_N_SET(); else DSP56K_N_CLEAR(); + if ((*((UINT64*)D) & U64(0x000000ffffffffff)) == 0) DSP56K_Z_SET(); else DSP56K_Z_CLEAR(); + + cycles += 2; + return 1; +} + +/* NEGC : 0001 0101 0110 F000 : A-168 */ +static size_t dsp56k_op_negc(dsp56k_core* cpustate, const UINT16 op, UINT8* cycles) +{ + /* S L E U N Z V C */ + /* - * * * * * * * */ + return 0; +} + +/* NOP : 0000 0000 0000 0000 : A-170 */ +static size_t dsp56k_op_nop(dsp56k_core* cpustate, const UINT16 op, UINT8* cycles) +{ + /* S L E U N Z V C */ + /* - - - - - - - - */ + return 1; +} + +/* NORM : 0001 0101 0010 F0RR : A-172 */ +static size_t dsp56k_op_norm(dsp56k_core* cpustate, const UINT16 op, UINT8* cycles) +{ + /* S L E U N Z V C */ + /* - * * * * * ? - */ + /* V - Set if an arithmetic overflow occurs in the 40 bit result. Also set if the most significantst + bit of the destination operand is changed as a result of the left shift. Cleared otherwise. */ + return 0; +} + +/* ORI : 0001 1EE1 iiii iiii : A-178 */ +static size_t dsp56k_op_ori(dsp56k_core* cpustate, const UINT16 op, UINT8* cycles) +{ + /* S L E U N Z V C */ + /* - ? ? ? ? ? ? ? */ + /* All ? bits - Set if the corresponding bit in the immediate data is set and if the operand is the + CCR. Not affected otherwise. */ + return 0; +} + +/* REP : 0000 0000 111- --RR : A-180 */ +static size_t dsp56k_op_rep(dsp56k_core* cpustate, const UINT16 op, UINT8* cycles) +{ + /* S L E U N Z V C */ + /* - * - - - - - - */ + return 0; +} + +/* REP : 0000 1111 iiii iiii : A-180 */ +static size_t dsp56k_op_rep_1(dsp56k_core* cpustate, const UINT16 op, UINT8* cycles) +{ + /* TODO: This is non-interruptable, probably have to turn off interrupts here */ + UINT16 iVal = op & 0x00ff; + + if (iVal != 0) + { + TEMP = LC; + LC = iVal; + + cpustate->repFlag = 1; + cpustate->repAddr = PC + ADDRESS(1); + + cycles += 4; /* TODO: + mv oscillator clock cycles */ + } + else + { + cycles += 6; /* TODO: + mv oscillator clock cycles */ + } + + + /* S L E U N Z V C */ + /* - * - - - - - - */ + /* TODO: L */ + return 1; +} + +/* REP : 0000 0100 001D DDDD : A-180 */ +static size_t dsp56k_op_rep_2(dsp56k_core* cpustate, const UINT16 op, UINT8* cycles) +{ + /* TODO: This is non-interruptable, probably have to turn off interrupts here */ + UINT16 repValue; + typed_pointer D = {NULL, DT_BYTE}; + decode_DDDDD_table(cpustate, BITS(op,0x001f), &D); + + /* TODO: handle special A&B source cases */ + if (D.addr == &A || D.addr == &B) + logerror("DSP56k ERROR : Rep with A or B instruction not implemented yet!\n"); + + repValue = *((UINT16*)D.addr); + + if (repValue != 0) + { + TEMP = LC; + LC = repValue; + + cpustate->repFlag = 1; + cpustate->repAddr = PC + ADDRESS(1); + + cycles += 4; /* TODO: + mv oscillator clock cycles */ + } + else + { + cycles += 6; /* TODO: + mv oscillator clock cycles */ + } + + /* S L E U N Z V C */ + /* - * - - - - - - */ + /* TODO: L */ + return 1; +} + +/* REPcc : 0000 0001 0101 cccc : A-184 */ +static size_t dsp56k_op_repcc(dsp56k_core* cpustate, const UINT16 op, UINT8* cycles) +{ + /* S L E U N Z V C */ + /* - - - - - - - - */ + return 0; +} + +/* RESET : 0000 0000 0000 1000 : A-186 */ +static size_t dsp56k_op_reset(dsp56k_core* cpustate, const UINT16 op, UINT8* cycles) +{ + /* S L E U N Z V C */ + /* - - - - - - - - */ + return 0; +} + +/* RTI : 0000 0000 0000 0111 : A-194 */ +static size_t dsp56k_op_rti(dsp56k_core* cpustate, const UINT16 op, UINT8* cycles) +{ + /* WARNING : THERE SHOULD BE A MORE GENERAL HANDLING OF STACK ERRORS. */ + if (SP == 0) + { + dsp56k_add_pending_interrupt(cpustate, "Stack Error"); + return 0; + } + + cpustate->ppc = PC; + PC = SSH; + + SR = SSL; + SP = SP - 1; + + /* S L E U N Z V C */ + /* ? ? ? ? ? ? ? ? */ + /* All ? bits - Set according to value pulled from the stack. */ + cycles += 4; /* TODO: + rx oscillator clock cycles */ + return 0; +} + +/* RTS : 0000 0000 0000 0110 : A-196 */ +static size_t dsp56k_op_rts(dsp56k_core* cpustate, const UINT16 op, UINT8* cycles) +{ + /* Pop */ + cpustate->ppc = PC; + PC = SSH; + + /* SR = SSL; The status register is not affected. */ + + SP--; + + /* S L E U N Z V C */ + /* - - - - - - - - */ + cycles += 4; /* TODO: + rx oscillator clock cycles */ + return 0; +} + +/* STOP : 0000 0000 0000 1010 : A-200 */ +static size_t dsp56k_op_stop(dsp56k_core* cpustate, const UINT16 op, UINT8* cycles) +{ + /* S L E U N Z V C */ + /* - - - - - - - - */ + return 0; +} + +/* SWAP : 0001 0101 0111 F001 : A-206 */ +static size_t dsp56k_op_swap(dsp56k_core* cpustate, const UINT16 op, UINT8* cycles) +{ + /* S L E U N Z V C */ + /* - - - - - - - - */ + return 0; +} + +/* SWI : 0000 0000 0000 0101 : A-208 */ +static size_t dsp56k_op_swi(dsp56k_core* cpustate, const UINT16 op, UINT8* cycles) +{ + /* S L E U N Z V C */ + /* - - - - - - - - */ + return 0; +} + +/* Tcc : 0001 00cc ccTT Fh0h : A-210 */ +static size_t dsp56k_op_tcc(dsp56k_core* cpustate, const UINT16 op, UINT8* cycles) +{ + int shouldTransfer = decode_cccc_table(cpustate, BITS(op,0x03c0)); + + if (shouldTransfer) + { + typed_pointer S = {NULL, DT_BYTE}; + typed_pointer D = {NULL, DT_BYTE}; + typed_pointer S2 = {&R0, DT_WORD}; + typed_pointer D2 = {NULL, DT_BYTE}; + + decode_h0hF_table(cpustate, BITS(op,0x0007),BITS(op,0x0008), &S, &D); + SetDestinationValue(S, D); + + /* TODO: What's up with that A,A* thing in the docs? Can you only ignore the R0->RX transfer if you do an A,A? */ + decode_RR_table(cpustate, BITS(op,0x0030), &D2); /* TT is the same as RR */ + SetDestinationValue(S2, D2); + } + + /* S L E U N Z V C */ + /* - - - - - - - - */ + cycles += 2; + return 1; +} + +/* TFR(2) : 0001 0101 0000 F00J : A-214 */ +static size_t dsp56k_op_tfr2(dsp56k_core* cpustate, const UINT16 op, UINT8* cycles) +{ + typed_pointer S = {NULL, DT_BYTE}; + typed_pointer D = {NULL, DT_BYTE}; + + decode_JF_table(cpustate, BITS(op,0x0001), BITS(op,0x0008), &S, &D); + + SetDestinationValue(S, D); + + /* S L E U N Z V C */ + /* - * - - - - - - */ + /* TODO: L */ + cycles += 2; + return 1; +} + +/* TFR(3) : 0010 01mW RRDD FHHH : A-216 */ +static size_t dsp56k_op_tfr3(dsp56k_core* cpustate, const UINT16 op, UINT8* cycles) +{ + /* S L E U N Z V C */ + /* * * - - - - - - */ + return 0; +} + +/* TST(2) : 0001 0101 0001 -1DD : A-220 */ +static size_t dsp56k_op_tst2(dsp56k_core* cpustate, const UINT16 op, UINT8* cycles) +{ + typed_pointer D = {NULL, DT_BYTE}; + decode_DD_table(cpustate, BITS(op,0x0003), &D); + + /* S L E U N Z V C */ + /* - * * * * * 0 0 */ + /* (L,E,U should be set to 0) */ + DSP56K_L_CLEAR(); + DSP56K_E_CLEAR(); + /* U_CLEAR(); */ /* TODO: Conflicting opinions? "Set if unnormalized." Documentation is weird (A&B?) */ + if ((*((UINT16*)D.addr)) & 0x8000) DSP56K_N_SET(); else DSP56K_N_CLEAR(); + if ((*((UINT16*)D.addr)) == 0x0000) DSP56K_Z_SET(); else DSP56K_Z_CLEAR(); + /* DSP56K_V_CLEAR(); */ /* Unaffected */ + DSP56K_C_CLEAR(); + + cycles += 2; + return 1; +} + +/* WAIT : 0000 0000 0000 1011 : A-222 */ +static size_t dsp56k_op_wait(dsp56k_core* cpustate, const UINT16 op, UINT8* cycles) +{ + /* S L E U N Z V C */ + /* - - - - - - - - */ + return 0; +} + +/* ZERO : 0001 0101 0101 F000 : A-224 */ +static size_t dsp56k_op_zero(dsp56k_core* cpustate, const UINT16 op, UINT8* cycles) +{ + /* S L E U N Z V C */ + /* - * * * * * * - */ + return 0; +} + + + +/*************************************************************************** + Table decoding +***************************************************************************/ +static UINT16 decode_BBB_bitmask(dsp56k_core* cpustate, UINT16 BBB, UINT16 *iVal) +{ + UINT16 retVal = 0x0000; + + switch(BBB) + { + case 0x4: retVal = 0xff00; *iVal <<= 8; break; + case 0x2: retVal = 0x0ff0; *iVal <<= 4; break; + case 0x1: retVal = 0x00ff; *iVal <<= 0; break; + } + + return retVal; +} + +static int decode_cccc_table(dsp56k_core* cpustate, UINT16 cccc) +{ + int retVal = 0; + + /* Not fully tested */ + switch (cccc) + { + /* Arranged according to mnemonic table - not decoding table */ + case 0x0: if( C() == 0) retVal = 1; break; /* cc(hs) */ + case 0x8: if( C() == 1) retVal = 1; break; /* cs(lo) */ + case 0x5: if( E() == 0) retVal = 1; break; /* ec */ + case 0xa: if( Z() == 1) retVal = 1; break; /* eq */ + case 0xd: if( E() == 1) retVal = 1; break; /* es */ + case 0x1: if((N() ^ V()) == 0) retVal = 1; break; /* ge */ + case 0x7: if((Z() | (N() ^ V())) == 0) retVal = 1; break; /* gt */ + case 0x6: if( L() == 0) retVal = 1; break; /* lc */ + case 0xf: if((Z() | (N() ^ V())) == 1) retVal = 1; break; /* le */ + case 0xe: if( L() == 1) retVal = 1; break; /* ls */ + case 0x9: if((N() ^ V()) == 1) retVal = 1; break; /* lt */ + case 0xb: if( N() == 1) retVal = 1; break; /* mi */ + case 0x2: if( Z() == 0) retVal = 1; break; /* ne */ + case 0xc: if((Z() | ((!U()) & (!E()))) == 1) retVal = 1; break; /* nr */ + case 0x3: if( N() == 0) retVal = 1; break; /* pl */ + case 0x4: if((Z() | ((!U()) & (!E()))) == 0) retVal = 1; break; /* nn */ + } + + return retVal; +} + +static void decode_DDDDD_table(dsp56k_core* cpustate, UINT16 DDDDD, typed_pointer* ret) +{ + switch(DDDDD) + { + case 0x00: ret->addr = &X0; ret->data_type = DT_WORD; break; + case 0x01: ret->addr = &Y0; ret->data_type = DT_WORD; break; + case 0x02: ret->addr = &X1; ret->data_type = DT_WORD; break; + case 0x03: ret->addr = &Y1; ret->data_type = DT_WORD; break; + case 0x04: ret->addr = &A ; ret->data_type = DT_LONG_WORD; break; + case 0x05: ret->addr = &B ; ret->data_type = DT_LONG_WORD; break; + case 0x06: ret->addr = &A0; ret->data_type = DT_WORD; break; + case 0x07: ret->addr = &B0; ret->data_type = DT_WORD; break; + case 0x08: ret->addr = &LC; ret->data_type = DT_WORD; break; + case 0x09: ret->addr = &SR; ret->data_type = DT_WORD; break; + case 0x0a: ret->addr = &OMR; ret->data_type = DT_BYTE; break; + case 0x0b: ret->addr = &SP; ret->data_type = DT_BYTE; break; + case 0x0c: ret->addr = &A1; ret->data_type = DT_WORD; break; + case 0x0d: ret->addr = &B1; ret->data_type = DT_WORD; break; + case 0x0e: ret->addr = &A2; ret->data_type = DT_BYTE; break; + case 0x0f: ret->addr = &B2; ret->data_type = DT_BYTE; break; + + case 0x10: ret->addr = &R0; ret->data_type = DT_WORD; break; + case 0x11: ret->addr = &R1; ret->data_type = DT_WORD; break; + case 0x12: ret->addr = &R2; ret->data_type = DT_WORD; break; + case 0x13: ret->addr = &R3; ret->data_type = DT_WORD; break; + case 0x14: ret->addr = &M0; ret->data_type = DT_WORD; break; + case 0x15: ret->addr = &M1; ret->data_type = DT_WORD; break; + case 0x16: ret->addr = &M2; ret->data_type = DT_WORD; break; + case 0x17: ret->addr = &M3; ret->data_type = DT_WORD; break; + case 0x18: ret->addr = &SSH; ret->data_type = DT_WORD; break; + case 0x19: ret->addr = &SSL; ret->data_type = DT_WORD; break; + case 0x1a: ret->addr = &LA; ret->data_type = DT_WORD; break; + /*no 0x1b */ + case 0x1c: ret->addr = &N0; ret->data_type = DT_WORD; break; + case 0x1d: ret->addr = &N1; ret->data_type = DT_WORD; break; + case 0x1e: ret->addr = &N2; ret->data_type = DT_WORD; break; + case 0x1f: ret->addr = &N3; ret->data_type = DT_WORD; break; + } +} + +static void decode_DD_table(dsp56k_core* cpustate, UINT16 DD, typed_pointer* ret) +{ + switch(DD) + { + case 0x00: ret->addr = &X0; ret->data_type = DT_WORD; break; + case 0x01: ret->addr = &Y0; ret->data_type = DT_WORD; break; + case 0x02: ret->addr = &X1; ret->data_type = DT_WORD; break; + case 0x03: ret->addr = &Y1; ret->data_type = DT_WORD; break; + } +} + +static void decode_DDF_table(dsp56k_core* cpustate, UINT16 DD, UINT16 F, typed_pointer* src_ret, typed_pointer* dst_ret) +{ + UINT16 switchVal = (DD << 1) | F; + + switch (switchVal) + { + case 0x0: src_ret->addr = &X0; src_ret->data_type = DT_WORD; dst_ret->addr = &A; dst_ret->data_type = DT_LONG_WORD; break; + case 0x1: src_ret->addr = &X0; src_ret->data_type = DT_WORD; dst_ret->addr = &B; dst_ret->data_type = DT_LONG_WORD; break; + case 0x2: src_ret->addr = &Y0; src_ret->data_type = DT_WORD; dst_ret->addr = &A; dst_ret->data_type = DT_LONG_WORD; break; + case 0x3: src_ret->addr = &Y0; src_ret->data_type = DT_WORD; dst_ret->addr = &B; dst_ret->data_type = DT_LONG_WORD; break; + case 0x4: src_ret->addr = &X1; src_ret->data_type = DT_WORD; dst_ret->addr = &A; dst_ret->data_type = DT_LONG_WORD; break; + case 0x5: src_ret->addr = &X1; src_ret->data_type = DT_WORD; dst_ret->addr = &B; dst_ret->data_type = DT_LONG_WORD; break; + case 0x6: src_ret->addr = &Y1; src_ret->data_type = DT_WORD; dst_ret->addr = &A; dst_ret->data_type = DT_LONG_WORD; break; + case 0x7: src_ret->addr = &Y1; src_ret->data_type = DT_WORD; dst_ret->addr = &B; dst_ret->data_type = DT_LONG_WORD; break; + } +} + +static void decode_F_table(dsp56k_core* cpustate, UINT16 F, typed_pointer* ret) +{ + switch(F) + { + case 0x0: ret->addr = &A; ret->data_type = DT_LONG_WORD; break; + case 0x1: ret->addr = &B; ret->data_type = DT_LONG_WORD; break; + } +} + +static void decode_h0hF_table(dsp56k_core* cpustate, UINT16 h0h, UINT16 F, typed_pointer* src_ret, typed_pointer* dst_ret) +{ + UINT16 switchVal = (h0h << 1) | F ; + + switch (switchVal) + { + case 0x8: src_ret->addr = &X0; src_ret->data_type = DT_WORD; dst_ret->addr = &A; dst_ret->data_type = DT_LONG_WORD; break; + case 0x9: src_ret->addr = &X0; src_ret->data_type = DT_WORD; dst_ret->addr = &B; dst_ret->data_type = DT_LONG_WORD; break; + case 0xa: src_ret->addr = &Y0; src_ret->data_type = DT_WORD; dst_ret->addr = &A; dst_ret->data_type = DT_LONG_WORD; break; + case 0xb: src_ret->addr = &Y0; src_ret->data_type = DT_WORD; dst_ret->addr = &B; dst_ret->data_type = DT_LONG_WORD; break; + case 0x2: src_ret->addr = &A; src_ret->data_type = DT_LONG_WORD; dst_ret->addr = &A; dst_ret->data_type = DT_LONG_WORD; break; + case 0x1: src_ret->addr = &A; src_ret->data_type = DT_LONG_WORD; dst_ret->addr = &B; dst_ret->data_type = DT_LONG_WORD; break; + case 0x0: src_ret->addr = &B; src_ret->data_type = DT_LONG_WORD; dst_ret->addr = &A; dst_ret->data_type = DT_LONG_WORD; break; + case 0x3: src_ret->addr = &B; src_ret->data_type = DT_LONG_WORD; dst_ret->addr = &B; dst_ret->data_type = DT_LONG_WORD; break; + } +} + +static void decode_HH_table(dsp56k_core* cpustate, UINT16 HH, typed_pointer* ret) +{ + switch(HH) + { + case 0x0: ret->addr = &X0; ret->data_type = DT_WORD; break; + case 0x1: ret->addr = &Y0; ret->data_type = DT_WORD; break; + case 0x2: ret->addr = &A; ret->data_type = DT_LONG_WORD; break; + case 0x3: ret->addr = &B; ret->data_type = DT_LONG_WORD; break; + } +} + +static void decode_HHH_table(dsp56k_core* cpustate, UINT16 HHH, typed_pointer* ret) +{ + switch(HHH) + { + case 0x0: ret->addr = &X0; ret->data_type = DT_WORD; break; + case 0x1: ret->addr = &Y0; ret->data_type = DT_WORD; break; + case 0x2: ret->addr = &X1; ret->data_type = DT_WORD; break; + case 0x3: ret->addr = &Y1; ret->data_type = DT_WORD; break; + case 0x4: ret->addr = &A; ret->data_type = DT_LONG_WORD; break; + case 0x5: ret->addr = &B; ret->data_type = DT_LONG_WORD; break; + case 0x6: ret->addr = &A0; ret->data_type = DT_WORD; break; + case 0x7: ret->addr = &B0; ret->data_type = DT_WORD; break; + } +} + +static void decode_IIII_table(dsp56k_core* cpustate, UINT16 IIII, typed_pointer* src_ret, typed_pointer* dst_ret, void *working) +{ + void *opposite = 0x00 ; + + if (working == &A) opposite = &B ; + else opposite = &A ; + + switch(IIII) + { + case 0x0: src_ret->addr = &X0; src_ret->data_type = DT_WORD; dst_ret->addr = opposite; dst_ret->data_type = DT_LONG_WORD; break; + case 0x1: src_ret->addr = &Y0; src_ret->data_type = DT_WORD; dst_ret->addr = opposite; dst_ret->data_type = DT_LONG_WORD; break; + case 0x2: src_ret->addr = &X1; src_ret->data_type = DT_WORD; dst_ret->addr = opposite; dst_ret->data_type = DT_LONG_WORD; break; + case 0x3: src_ret->addr = &Y1; src_ret->data_type = DT_WORD; dst_ret->addr = opposite; dst_ret->data_type = DT_LONG_WORD; break; + case 0x4: src_ret->addr = &A; src_ret->data_type = DT_LONG_WORD; dst_ret->addr = &X0; dst_ret->data_type = DT_WORD; break; + case 0x5: src_ret->addr = &B; src_ret->data_type = DT_LONG_WORD; dst_ret->addr = &Y0; dst_ret->data_type = DT_WORD; break; + case 0x6: src_ret->addr = &A0; src_ret->data_type = DT_WORD; dst_ret->addr = &X0; dst_ret->data_type = DT_WORD; break; + case 0x7: src_ret->addr = &B0; src_ret->data_type = DT_WORD; dst_ret->addr = &Y0; dst_ret->data_type = DT_WORD; break; + case 0x8: src_ret->addr = working; src_ret->data_type = DT_LONG_WORD; dst_ret->addr = opposite; dst_ret->data_type = DT_LONG_WORD; break; + case 0x9: src_ret->addr = working; src_ret->data_type = DT_LONG_WORD; dst_ret->addr = opposite; dst_ret->data_type = DT_LONG_WORD; break; + case 0xc: src_ret->addr = &A; src_ret->data_type = DT_LONG_WORD; dst_ret->addr = &X1; dst_ret->data_type = DT_WORD; break; + case 0xd: src_ret->addr = &B; src_ret->data_type = DT_LONG_WORD; dst_ret->addr = &Y1; dst_ret->data_type = DT_WORD; break; + case 0xe: src_ret->addr = &A0; src_ret->data_type = DT_WORD; dst_ret->addr = &X1; dst_ret->data_type = DT_WORD; break; + case 0xf: src_ret->addr = &B0; src_ret->data_type = DT_WORD; dst_ret->addr = &Y1; dst_ret->data_type = DT_WORD; break; + } +} + +static void decode_JJJF_table(dsp56k_core* cpustate, UINT16 JJJ, UINT16 F, typed_pointer* src_ret, typed_pointer* dst_ret) +{ + UINT16 switchVal = (JJJ << 1) | F ; + + switch(switchVal) + { + case 0x0: src_ret->addr = &B; src_ret->data_type = DT_LONG_WORD; dst_ret->addr = &A; dst_ret->data_type = DT_LONG_WORD; break; + case 0x1: src_ret->addr = &A; src_ret->data_type = DT_LONG_WORD; dst_ret->addr = &B; dst_ret->data_type = DT_LONG_WORD; break; + case 0x4: src_ret->addr = &X; src_ret->data_type = DT_DOUBLE_WORD; dst_ret->addr = &A; dst_ret->data_type = DT_LONG_WORD; break; + case 0x5: src_ret->addr = &X; src_ret->data_type = DT_DOUBLE_WORD; dst_ret->addr = &B; dst_ret->data_type = DT_LONG_WORD; break; + case 0x6: src_ret->addr = &Y; src_ret->data_type = DT_DOUBLE_WORD; dst_ret->addr = &A; dst_ret->data_type = DT_LONG_WORD; break; + case 0x7: src_ret->addr = &Y; src_ret->data_type = DT_DOUBLE_WORD; dst_ret->addr = &B; dst_ret->data_type = DT_LONG_WORD; break; + case 0x8: src_ret->addr = &X0; src_ret->data_type = DT_WORD; dst_ret->addr = &A; dst_ret->data_type = DT_LONG_WORD; break; + case 0x9: src_ret->addr = &X0; src_ret->data_type = DT_WORD; dst_ret->addr = &B; dst_ret->data_type = DT_LONG_WORD; break; + case 0xa: src_ret->addr = &Y0; src_ret->data_type = DT_WORD; dst_ret->addr = &A; dst_ret->data_type = DT_LONG_WORD; break; + case 0xb: src_ret->addr = &Y0; src_ret->data_type = DT_WORD; dst_ret->addr = &B; dst_ret->data_type = DT_LONG_WORD; break; + case 0xc: src_ret->addr = &X1; src_ret->data_type = DT_WORD; dst_ret->addr = &A; dst_ret->data_type = DT_LONG_WORD; break; + case 0xd: src_ret->addr = &X1; src_ret->data_type = DT_WORD; dst_ret->addr = &B; dst_ret->data_type = DT_LONG_WORD; break; + case 0xe: src_ret->addr = &Y1; src_ret->data_type = DT_WORD; dst_ret->addr = &A; dst_ret->data_type = DT_LONG_WORD; break; + case 0xf: src_ret->addr = &Y1; src_ret->data_type = DT_WORD; dst_ret->addr = &B; dst_ret->data_type = DT_LONG_WORD; break; + } +} + +static void decode_JJF_table(dsp56k_core* cpustate, UINT16 JJ, UINT16 F, typed_pointer* src_ret, typed_pointer* dst_ret) +{ + UINT16 switchVal = (JJ << 1) | F ; + + switch (switchVal) + { + case 0x0: src_ret->addr = &X0; src_ret->data_type = DT_WORD; dst_ret->addr = &A; dst_ret->data_type = DT_LONG_WORD; break; + case 0x1: src_ret->addr = &X0; src_ret->data_type = DT_WORD; dst_ret->addr = &B; dst_ret->data_type = DT_LONG_WORD; break; + case 0x2: src_ret->addr = &Y0; src_ret->data_type = DT_WORD; dst_ret->addr = &A; dst_ret->data_type = DT_LONG_WORD; break; + case 0x3: src_ret->addr = &Y0; src_ret->data_type = DT_WORD; dst_ret->addr = &B; dst_ret->data_type = DT_LONG_WORD; break; + case 0x4: src_ret->addr = &X1; src_ret->data_type = DT_WORD; dst_ret->addr = &A; dst_ret->data_type = DT_LONG_WORD; break; + case 0x5: src_ret->addr = &X1; src_ret->data_type = DT_WORD; dst_ret->addr = &B; dst_ret->data_type = DT_LONG_WORD; break; + case 0x6: src_ret->addr = &Y1; src_ret->data_type = DT_WORD; dst_ret->addr = &A; dst_ret->data_type = DT_LONG_WORD; break; + case 0x7: src_ret->addr = &Y1; src_ret->data_type = DT_WORD; dst_ret->addr = &B; dst_ret->data_type = DT_LONG_WORD; break; + } +} + +static void decode_JF_table(dsp56k_core* cpustate, UINT16 J, UINT16 F, typed_pointer* src_ret, typed_pointer* dst_ret) +{ + UINT16 switchVal = (J << 1) | F ; + + switch (switchVal) + { + case 0x0: src_ret->addr = &A; src_ret->data_type = DT_LONG_WORD; dst_ret->addr = &X; dst_ret->data_type = DT_DOUBLE_WORD; break; + case 0x1: src_ret->addr = &B; src_ret->data_type = DT_LONG_WORD; dst_ret->addr = &X; dst_ret->data_type = DT_DOUBLE_WORD; break; + case 0x2: src_ret->addr = &A; src_ret->data_type = DT_LONG_WORD; dst_ret->addr = &Y; dst_ret->data_type = DT_DOUBLE_WORD; break; + case 0x3: src_ret->addr = &B; src_ret->data_type = DT_LONG_WORD; dst_ret->addr = &Y; dst_ret->data_type = DT_DOUBLE_WORD; break; + } +} + +static void decode_KKK_table(dsp56k_core* cpustate, UINT16 KKK, typed_pointer* dst_ret1, typed_pointer* dst_ret2, void* working) +{ + void *opposite = 0x00 ; + + if (working == &A) opposite = &B ; + else opposite = &A ; + + switch(KKK) + { + case 0x0: dst_ret1->addr = opposite; dst_ret1->data_type = DT_LONG_WORD; dst_ret2->addr = &X0; dst_ret2->data_type = DT_WORD; break; + case 0x1: dst_ret1->addr = &Y0; dst_ret1->data_type = DT_WORD; dst_ret2->addr = &X0; dst_ret2->data_type = DT_WORD; break; + case 0x2: dst_ret1->addr = &X1; dst_ret1->data_type = DT_WORD; dst_ret2->addr = &X0; dst_ret2->data_type = DT_WORD; break; + case 0x3: dst_ret1->addr = &Y1; dst_ret1->data_type = DT_WORD; dst_ret2->addr = &X0; dst_ret2->data_type = DT_WORD; break; + case 0x4: dst_ret1->addr = &X0; dst_ret1->data_type = DT_WORD; dst_ret2->addr = &X1; dst_ret2->data_type = DT_WORD; break; + case 0x5: dst_ret1->addr = &Y0; dst_ret1->data_type = DT_WORD; dst_ret2->addr = &X1; dst_ret2->data_type = DT_WORD; break; + case 0x6: dst_ret1->addr = opposite; dst_ret1->data_type = DT_LONG_WORD; dst_ret2->addr = &Y0; dst_ret2->data_type = DT_WORD; break; + case 0x7: dst_ret1->addr = &Y1; dst_ret1->data_type = DT_WORD; dst_ret2->addr = &X1; dst_ret2->data_type = DT_WORD; break; + } +} + +static void decode_QQF_table(dsp56k_core* cpustate, UINT16 QQ, UINT16 F, void **S1, void **S2, void **D) +{ + UINT16 switchVal = (QQ << 1) | F ; + + switch(switchVal) + { + case 0x0: *S1 = &X0; *S2 = &Y0; *D = &A; break; + case 0x1: *S1 = &X0; *S2 = &Y0; *D = &B; break; + case 0x2: *S1 = &X0; *S2 = &Y1; *D = &A; break; + case 0x3: *S1 = &X0; *S2 = &Y1; *D = &B; break; + case 0x4: *S1 = &X1; *S2 = &Y0; *D = &A; break; + case 0x5: *S1 = &X1; *S2 = &Y0; *D = &B; break; + case 0x6: *S1 = &X1; *S2 = &Y1; *D = &A; break; + case 0x7: *S1 = &X1; *S2 = &Y1; *D = &B; break; + } +} + +static void decode_QQF_special_table(dsp56k_core* cpustate, UINT16 QQ, UINT16 F, void **S1, void **S2, void **D) +{ + UINT16 switchVal = (QQ << 1) | F ; + + switch(switchVal) + { + case 0x0: *S1 = &Y0; *S2 = &X0; *D = &A; break; + case 0x1: *S1 = &Y0; *S2 = &X0; *D = &B; break; + case 0x2: *S1 = &Y1; *S2 = &X0; *D = &A; break; + case 0x3: *S1 = &Y1; *S2 = &X0; *D = &B; break; + case 0x4: *S1 = &X1; *S2 = &Y0; *D = &A; break; + case 0x5: *S1 = &X1; *S2 = &Y0; *D = &B; break; + case 0x6: *S1 = &X1; *S2 = &Y1; *D = &A; break; + case 0x7: *S1 = &X1; *S2 = &Y1; *D = &B; break; + } +} + +static void decode_QQQF_table(dsp56k_core* cpustate, UINT16 QQQ, UINT16 F, void **S1, void **S2, void **D) +{ + UINT16 switchVal = (QQQ << 1) | F; + + switch(switchVal) + { + case 0x0: *S1 = &X0; *S2 = &X0; *D = &A; break; + case 0x1: *S1 = &X0; *S2 = &X0; *D = &B; break; + case 0x2: *S1 = &X1; *S2 = &X0; *D = &A; break; + case 0x3: *S1 = &X1; *S2 = &X0; *D = &B; break; + case 0x4: *S1 = &A1; *S2 = &Y0; *D = &A; break; + case 0x5: *S1 = &A1; *S2 = &Y0; *D = &B; break; + case 0x6: *S1 = &B1; *S2 = &X0; *D = &A; break; + case 0x7: *S1 = &B1; *S2 = &X0; *D = &B; break; + case 0x8: *S1 = &Y0; *S2 = &X0; *D = &A; break; + case 0x9: *S1 = &Y0; *S2 = &X0; *D = &B; break; + case 0xa: *S1 = &Y1; *S2 = &X0; *D = &A; break; + case 0xb: *S1 = &Y1; *S2 = &X0; *D = &B; break; + case 0xc: *S1 = &Y0; *S2 = &X1; *D = &A; break; + case 0xd: *S1 = &Y0; *S2 = &X1; *D = &B; break; + case 0xe: *S1 = &Y1; *S2 = &X1; *D = &A; break; + case 0xf: *S1 = &Y1; *S2 = &X1; *D = &B; break; + } +} + +static void decode_RR_table(dsp56k_core* cpustate, UINT16 RR, typed_pointer* ret) +{ + switch(RR) + { + case 0x00: ret->addr = &R0; ret->data_type = DT_WORD; break; + case 0x01: ret->addr = &R1; ret->data_type = DT_WORD; break; + case 0x02: ret->addr = &R2; ret->data_type = DT_WORD; break; + case 0x03: ret->addr = &R3; ret->data_type = DT_WORD; break; + } +} + +static void decode_TT_table(dsp56k_core* cpustate, UINT16 TT, typed_pointer* ret) +{ + switch(TT) + { + case 0x00: ret->addr = &R0; ret->data_type = DT_WORD; break; + case 0x01: ret->addr = &R1; ret->data_type = DT_WORD; break; + case 0x02: ret->addr = &R2; ret->data_type = DT_WORD; break; + case 0x03: ret->addr = &R3; ret->data_type = DT_WORD; break; + } +} + + +static void decode_uuuuF_table(dsp56k_core* cpustate, UINT16 uuuu, UINT16 F, UINT8 add_sub_other, typed_pointer* src_ret, typed_pointer* dst_ret) +{ + UINT16 switchVal = (uuuu << 1) | F; + + /* Unknown uuuuFs have been seen in the wild */ + add_sub_other = OP_OTHER; + src_ret->addr = NULL; src_ret->data_type = DT_BYTE; + dst_ret->addr = NULL; dst_ret->data_type = DT_BYTE; + + switch(switchVal) + { + case 0x00: add_sub_other = OP_ADD; + src_ret->addr = &X0; src_ret->data_type = DT_WORD; + dst_ret->addr = &A; dst_ret->data_type = DT_LONG_WORD; break; + case 0x08: add_sub_other = OP_SUB; + src_ret->addr = &X0; src_ret->data_type = DT_WORD; + dst_ret->addr = &A; dst_ret->data_type = DT_LONG_WORD; break; + case 0x01: add_sub_other = OP_ADD; + src_ret->addr = &X0; src_ret->data_type = DT_WORD; + dst_ret->addr = &B; dst_ret->data_type = DT_LONG_WORD; break; + case 0x09: add_sub_other = OP_SUB; + src_ret->addr = &X0; src_ret->data_type = DT_WORD; + dst_ret->addr = &B; dst_ret->data_type = DT_LONG_WORD; break; + case 0x02: add_sub_other = OP_ADD; + src_ret->addr = &Y0; src_ret->data_type = DT_WORD; + dst_ret->addr = &A; dst_ret->data_type = DT_LONG_WORD; break; + case 0x0a: add_sub_other = OP_SUB; + src_ret->addr = &Y0; src_ret->data_type = DT_WORD; + dst_ret->addr = &A; dst_ret->data_type = DT_LONG_WORD; break; + case 0x03: add_sub_other = OP_ADD; + src_ret->addr = &Y0; src_ret->data_type = DT_WORD; + dst_ret->addr = &B; dst_ret->data_type = DT_LONG_WORD; break; + case 0x0b: add_sub_other = OP_SUB; + src_ret->addr = &Y0; src_ret->data_type = DT_WORD; + dst_ret->addr = &B; dst_ret->data_type = DT_LONG_WORD; break; + case 0x04: add_sub_other = OP_ADD; + src_ret->addr = &X1; src_ret->data_type = DT_WORD; + dst_ret->addr = &A; dst_ret->data_type = DT_LONG_WORD; break; + case 0x0c: add_sub_other = OP_SUB; + src_ret->addr = &X1; src_ret->data_type = DT_WORD; + dst_ret->addr = &A; dst_ret->data_type = DT_LONG_WORD; break; + case 0x05: add_sub_other = OP_ADD; + src_ret->addr = &X1; src_ret->data_type = DT_WORD; + dst_ret->addr = &B; dst_ret->data_type = DT_LONG_WORD; break; + case 0x0d: add_sub_other = OP_SUB; + src_ret->addr = &X1; src_ret->data_type = DT_WORD; + dst_ret->addr = &B; dst_ret->data_type = DT_LONG_WORD; break; + case 0x06: add_sub_other = OP_ADD; + src_ret->addr = &Y1; src_ret->data_type = DT_WORD; + dst_ret->addr = &A; dst_ret->data_type = DT_LONG_WORD; break; + case 0x0e: add_sub_other = OP_SUB; + src_ret->addr = &Y1; src_ret->data_type = DT_WORD; + dst_ret->addr = &A; dst_ret->data_type = DT_LONG_WORD; break; + case 0x07: add_sub_other = OP_ADD; + src_ret->addr = &Y1; src_ret->data_type = DT_WORD; + dst_ret->addr = &B; dst_ret->data_type = DT_LONG_WORD; break; + case 0x0f: add_sub_other = OP_SUB; + src_ret->addr = &Y1; src_ret->data_type = DT_WORD; + dst_ret->addr = &B; dst_ret->data_type = DT_LONG_WORD; break; + case 0x18: add_sub_other = OP_ADD; + src_ret->addr = &B; src_ret->data_type = DT_LONG_WORD; + dst_ret->addr = &A; dst_ret->data_type = DT_LONG_WORD; break; + case 0x1a: add_sub_other = OP_SUB; + src_ret->addr = &B; src_ret->data_type = DT_LONG_WORD; + dst_ret->addr = &A; dst_ret->data_type = DT_LONG_WORD; break; + case 0x19: add_sub_other = OP_ADD; + src_ret->addr = &A; src_ret->data_type = DT_LONG_WORD; + dst_ret->addr = &B; dst_ret->data_type = DT_LONG_WORD; break; + case 0x1b: add_sub_other = OP_SUB; + src_ret->addr = &A; src_ret->data_type = DT_LONG_WORD; + dst_ret->addr = &B; dst_ret->data_type = DT_LONG_WORD; break; + } +} + +static void decode_Z_table(dsp56k_core* cpustate, UINT16 Z, typed_pointer* ret) +{ + switch(Z) + { + /* Fixed as per the Family Manual addendum */ + case 0x01: ret->addr = &A1; ret->data_type = DT_WORD; break; + case 0x00: ret->addr = &B1; ret->data_type = DT_WORD; break; + } +} + +static void execute_m_table(dsp56k_core* cpustate, int x, UINT16 m) +{ + UINT16 *rX = 0x00 ; + UINT16 *nX = 0x00 ; + + switch(x) + { + case 0x0: rX = &R0; nX = &N0; break; + case 0x1: rX = &R1; nX = &N1; break; + case 0x2: rX = &R2; nX = &N2; break; + case 0x3: rX = &R3; nX = &N3; break; + } + + switch(m) + { + case 0x0: (*rX)++; break; + case 0x1: (*rX) = (*rX)+(*nX); break; + } +} + +static void execute_mm_table(dsp56k_core* cpustate, UINT16 rnum, UINT16 mm) +{ + UINT16 *rX = NULL; + UINT16 *nX = NULL; + + switch(rnum) + { + case 0x0: rX = &R0; nX = &N0; break; + case 0x1: rX = &R1; nX = &N1; break; + case 0x2: rX = &R2; nX = &N2; break; + case 0x3: fatalerror("Dsp56k: Error. execute_mm_table specified R3 as its first source!\n"); break; + } + + switch(mm) + { + case 0x0: (*rX)++; R3++; break; + case 0x1: (*rX)++; R3 = R3 + N3; break; + case 0x2: (*rX) = (*rX) + (*nX); R3++; break; + case 0x3: (*rX) = (*rX) + (*nX); R3 = R3 + N3; break; + } +} + +static void execute_MM_table(dsp56k_core* cpustate, UINT16 rnum, UINT16 MM) +{ + UINT16 *rX = 0x00 ; + UINT16 *nX = 0x00 ; + + switch(rnum) + { + case 0x0: rX = &R0; nX = &N0; break; + case 0x1: rX = &R1; nX = &N1; break; + case 0x2: rX = &R2; nX = &N2; break; + case 0x3: rX = &R3; nX = &N3; break; + } + + switch(MM) + { + case 0x0: /* do nothing */ break; + case 0x1: (*rX)++ ; break; + case 0x2: (*rX)-- ; break; + case 0x3: (*rX) = (*rX)+(*nX) ; break; + } +} + +/* Returns R value */ +static UINT16 execute_q_table(dsp56k_core* cpustate, int RR, UINT16 q) +{ + UINT16 *rX = 0x0000; + UINT16 *nX = 0x0000; + + switch(RR) + { + case 0x0: rX = &R0; nX = &N0; break; + case 0x1: rX = &R1; nX = &N1; break; + case 0x2: rX = &R2; nX = &N2; break; + case 0x3: rX = &R3; nX = &N3; break; + } + + switch(q) + { + case 0x0: /* No permanent changes */ ; return (*rX)+(*nX); + case 0x1: (*rX)--; return (*rX); /* This one is special - it's a *PRE-decrement*! */ + } + + /* Should not get here */ + fatalerror("dsp56k: execute_q_table did something impossible!\n"); + return 0; +} + +static void execute_z_table(dsp56k_core* cpustate, int RR, UINT16 z) +{ + UINT16 *rX = 0x00; + UINT16 *nX = 0x00; + + switch(RR) + { + case 0x0: rX = &R0; nX = &N0; break; + case 0x1: rX = &R1; nX = &N1; break; + case 0x2: rX = &R2; nX = &N2; break; + case 0x3: rX = &R3; nX = &N3; break; + } + + switch(z) + { + case 0x0: (*rX)--; break; + case 0x1: (*rX) = (*rX) + (*nX); break; + } +} + +static UINT16 assemble_address_from_Pppppp_table(dsp56k_core* cpustate, UINT16 P, UINT16 ppppp) +{ + UINT16 destAddr = 0x00 ; + + switch (P) + { + case 0x0: destAddr = ppppp; break; /* TODO: Does this really only address up to 0x32? */ + case 0x1: destAddr = assemble_address_from_IO_short_address(cpustate, ppppp); break; + } + + return destAddr ; +} + +static UINT16 assemble_address_from_IO_short_address(dsp56k_core* cpustate, UINT16 pp) +{ + UINT16 fullAddy = 0xffe0; + fullAddy |= pp; + return fullAddy; +} + +static UINT16 assemble_address_from_6bit_signed_relative_short_address(dsp56k_core* cpustate, UINT16 srs) +{ + UINT16 fullAddy = srs ; + if (fullAddy & 0x0020) + fullAddy |= 0xffc0 ; + + return fullAddy ; +} + +static void dsp56k_process_loop(dsp56k_core* cpustate) +{ + /* TODO: This might not work for dos nested in doForevers */ + if (LF_bit(cpustate) && FV_bit(cpustate)) + { + /* Do Forever*/ + if (PC == LA) + { + LC--; + + cpustate->ppc = PC; + PC = SSH; + } + } + else if (LF_bit(cpustate)) + { + /* Do */ + if (PC == LA) + { + if (LC == 1) + { + /* End of loop processing */ + SR = SSL; /* TODO: A-83. I believe only the Loop Flag comes back here. And maybe the do forever bit too. */ + SP--; + + LA = SSH; + LC = SSL; + SP--; + } + else + { + LC--; + PC = SSH; + } + } + } +} + +static void dsp56k_process_rep(dsp56k_core* cpustate, size_t repSize) +{ + if (cpustate->repFlag) + { + if (PC == cpustate->repAddr) + { + if (LC == 1) + { + /* End of rep processing */ + LC = TEMP; + cpustate->repFlag = 0; + cpustate->repAddr = 0x0000; + } + else + { + LC--; + PC -= repSize; /* A little strange - rewind by the size of the rep'd op */ + } + } + } +} + + +/*************************************************************************** + Parallel Memory Ops +***************************************************************************/ +/* Register to Register Data Move : 0100 IIII .... .... : A-132 */ +static void execute_register_to_register_data_move(dsp56k_core* cpustate, const UINT16 op, typed_pointer* d_register, UINT64* prev_accum_value) +{ + typed_pointer S = {NULL, DT_BYTE}; + typed_pointer D = {NULL, DT_BYTE}; + + decode_IIII_table(cpustate, BITS(op,0x0f00), &S, &D, d_register->addr); + + /* If the source is the same as the ALU destination, use the previous accumulator value */ + if (d_register->addr == S.addr) + { + typed_pointer tempTP; + tempTP.addr = prev_accum_value; + tempTP.data_type = DT_LONG_WORD; + SetDestinationValue(tempTP, D); + } + else + { + SetDestinationValue(S, D); + } +} + +/* Address Register Update : 0011 0zRR .... .... : A-135 */ +static void execute_address_register_update(dsp56k_core* cpustate, const UINT16 op, typed_pointer* d_register, UINT64* prev_accum_value) +{ + execute_z_table(cpustate, BITS(op,0x0300), BITS(op,0x0400)); +} + +/* X Memory Data Move : 1mRR HHHW .... .... : A-137 */ +static void execute_x_memory_data_move(dsp56k_core* cpustate, const UINT16 op, typed_pointer* d_register, UINT64* prev_accum_value) +{ + UINT16 W; + typed_pointer R = {NULL, DT_BYTE}; + typed_pointer SD = {NULL, DT_BYTE}; + + W = BITS(op,0x0100); + decode_HHH_table(cpustate, BITS(op,0x0e00), &SD); + decode_RR_table(cpustate, BITS(op,0x3000),&R); + + if (W) + { + /* From X: to SD */ + UINT16 data = cpustate->data->read_word(ADDRESS(*((UINT16*)R.addr))); + + typed_pointer tempTP; + tempTP.addr = &data; + tempTP.data_type = DT_WORD; + + SetDestinationValue(tempTP, SD); + } + else + { + /* From SD to X: */ + /* If the source is the same as the ALU destination, use the previous accumulator value */ + if (d_register->addr == SD.addr) + { + typed_pointer tempTP; + tempTP.addr = prev_accum_value; + tempTP.data_type = DT_LONG_WORD; + + SetDataMemoryValue(cpustate, tempTP, ADDRESS(*((UINT16*)R.addr))) ; + } + else + { + SetDataMemoryValue(cpustate, SD, ADDRESS(*((UINT16*)R.addr))) ; + } + } + + execute_m_table(cpustate, BITS(op,0x3000), BITS(op,0x4000)); +} + +/* X Memory Data Move : 0101 HHHW .... .... : A-137 */ +/* NOTE: previous accumulator value is not needed since ^F1 is always the opposite accumulator */ +static void execute_x_memory_data_move2(dsp56k_core* cpustate, const UINT16 op, typed_pointer* d_register) +{ + UINT16 W; + UINT16* mem_offset = NULL; + typed_pointer SD = {NULL, DT_BYTE}; + + W = BITS(op,0x0100); + decode_HHH_table(cpustate, BITS(op,0x0e000), &SD); + + if (d_register->addr == &A) + mem_offset = &B1; + else + mem_offset = &A1; + + if (W) + { + /* Write D */ + UINT16 value = cpustate->data->read_word(ADDRESS(*mem_offset)); + typed_pointer tempV = {&value, DT_WORD}; + SetDestinationValue(tempV, SD); + } + else + { + /* Read S */ + SetDataMemoryValue(cpustate, SD, ADDRESS(*mem_offset)); + } +} + +/* X Memory Data Move With Short Displacement : 0000 0101 BBBB BBBB ---- HHHW .... .... : A-139 */ +static void execute_x_memory_data_move_with_short_displacement(dsp56k_core* cpustate, const UINT16 op, const UINT16 op2) +{ + INT8 xx; + UINT8 W; + UINT16 memOffset; + typed_pointer SD = { NULL, DT_BYTE }; + + xx = (INT8)(op & 0x00ff); + W = BITS(op2,0x0100); + decode_HHH_table(cpustate, BITS(op2,0x0e00), &SD); + + memOffset = R2 + (INT16)xx; + + if (W) + { + /* Write D */ + UINT16 tempData = cpustate->data->read_word(ADDRESS(memOffset)); + typed_pointer temp_src = { (void*)&tempData, DT_WORD }; + SetDestinationValue(temp_src, SD); + } + else + { + /* Read S */ + UINT16 tempData = *((UINT16*)SD.addr); + typed_pointer temp_src = { (void*)&tempData, DT_WORD }; + SetDataMemoryValue(cpustate, temp_src, ADDRESS(memOffset)); + } +} + +/* Dual X Memory Data Read : 011m mKKK .rr. .... : A-142*/ +static void execute_dual_x_memory_data_read(dsp56k_core* cpustate, const UINT16 op, typed_pointer* d_register) +{ + typed_pointer tempV; + UINT16 srcVal1 = 0x0000; + UINT16 srcVal2 = 0x0000; + typed_pointer R = {NULL, DT_BYTE}; + typed_pointer D1 = {NULL, DT_BYTE}; + typed_pointer D2 = {NULL, DT_BYTE}; + + decode_RR_table(cpustate, BITS(op,0x0060), &R); + decode_KKK_table(cpustate, BITS(op,0x0700), &D1, &D2, d_register->addr); + + /* Can't do an R3 for S1 */ + if (R.addr == &R3) + fatalerror("Dsp56k: Error. Dual x memory data read specified R3 as its first source!\n"); + + /* The note on A-142 is very interesting. + You can effectively access external memory in the last 64 bytes of X data memory! */ + if (*((UINT16*)D2.addr) >= 0xffc0) + fatalerror("Dsp56k: Unimplemented access to external X Data Memory >= 0xffc0 in Dual X Memory Data Read.\n"); + + /* First memmove */ + srcVal1 = cpustate->data->read_word(ADDRESS(*((UINT16*)R.addr))); + tempV.addr = &srcVal1; + tempV.data_type = DT_WORD; + SetDestinationValue(tempV, D1); + + /* Second memmove */ + srcVal2 = cpustate->data->read_word(ADDRESS(R3)); + tempV.addr = &srcVal2; + tempV.data_type = DT_WORD; + SetDestinationValue(tempV, D2); + + /* Touch up the R regs after all the moves */ + execute_mm_table(cpustate, BITS(op,0x0060), BITS(op,0x1800)); +} + +/*************************************************************************** + Helper Functions +***************************************************************************/ +static UINT16 Dsp56kOpMask(UINT16 cur, UINT16 mask) +{ + int i ; + + UINT16 retVal = (cur & mask) ; + UINT16 temp = 0x0000 ; + int offsetCount = 0 ; + + /* Shift everything right, eliminating 'whitespace' */ + for (i = 0; i < 16; i++) + { + if (mask & (0x1<> i) & 0x1) << offsetCount) ; + offsetCount++ ; + } + } + + return temp ; +} + +static void SetDestinationValue(typed_pointer source, typed_pointer dest) +{ + UINT64 destinationValue = 0 ; + + switch(dest.data_type) + { + /* Copying to an 8-bit value */ + case DT_BYTE: + switch(source.data_type) + { + /* From a ? */ + case DT_BYTE: *((UINT8*)dest.addr) = (*((UINT8*) source.addr)) & 0xff; break; + case DT_WORD: *((UINT8*)dest.addr) = (*((UINT16*)source.addr)) & 0x00ff; break; + case DT_DOUBLE_WORD: *((UINT8*)dest.addr) = (*((UINT32*)source.addr)) & 0x000000ff; break; + case DT_LONG_WORD: *((UINT8*)dest.addr) = (*((UINT64*)source.addr)) & U64(0x00000000000000ff); break; + } + break ; + + /* Copying to a 16-bit value */ + case DT_WORD: + switch(source.data_type) + { + case DT_BYTE: *((UINT16*)dest.addr) = (*((UINT8*) source.addr)) & 0xff; break; + case DT_WORD: *((UINT16*)dest.addr) = (*((UINT16*)source.addr)) & 0xffff; break; + case DT_DOUBLE_WORD: *((UINT16*)dest.addr) = (*((UINT32*)source.addr)) & 0x0000ffff; break; + case DT_LONG_WORD: *((UINT16*)dest.addr) = (*((UINT64*)source.addr)) & U64(0x000000000000ffff); break; /* TODO: Shift limiter action! A-147 */ + } + break ; + + /* Copying to a 32-bit value */ + case DT_DOUBLE_WORD: + switch(source.data_type) + { + case DT_BYTE: *((UINT32*)dest.addr) = (*((UINT8*) source.addr)) & 0xff; break; + case DT_WORD: *((UINT32*)dest.addr) = (*((UINT16*)source.addr)) & 0xffff; break; + case DT_DOUBLE_WORD: *((UINT32*)dest.addr) = (*((UINT32*)source.addr)) & 0xffffffff; break; + case DT_LONG_WORD: *((UINT32*)dest.addr) = (*((UINT64*)source.addr)) & U64(0x00000000ffffffff); break; + } + break ; + + /* Copying to a 64-bit value */ + case DT_LONG_WORD: + switch(source.data_type) + { + case DT_BYTE: *((UINT64*)dest.addr) = (*((UINT8*)source.addr)) & 0xff; break; + + case DT_WORD: destinationValue = (*((UINT16*)source.addr)) << 16; + if (destinationValue & U64(0x0000000080000000)) + destinationValue |= U64(0x000000ff00000000); + *((UINT64*)dest.addr) = (UINT64)destinationValue; break; /* Forget not, yon shift register */ + + case DT_DOUBLE_WORD: *((UINT64*)dest.addr) = (*((UINT32*)source.addr)) & 0xffffffff; break; + case DT_LONG_WORD: *((UINT64*)dest.addr) = (*((UINT64*)source.addr)) & U64(0x000000ffffffffff); break; + } + break ; + } +} + +/* TODO: Wait-state timings! */ +static void SetDataMemoryValue(dsp56k_core* cpustate, typed_pointer source, UINT32 destinationAddr) +{ + switch(source.data_type) + { + case DT_BYTE: cpustate->data->write_word(destinationAddr, (UINT16)( (*((UINT8*) source.addr) & 0xff) ) ) ; break ; + case DT_WORD: cpustate->data->write_word(destinationAddr, (UINT16)( (*((UINT16*)source.addr) & 0xffff) ) ) ; break ; + case DT_DOUBLE_WORD: cpustate->data->write_word(destinationAddr, (UINT16)( (*((UINT32*)source.addr) & 0x0000ffff) ) ) ; break ; + + /* !!! Is this universal ??? */ + /* !!! Forget not, yon shift-limiter !!! */ + case DT_LONG_WORD: cpustate->data->write_word(destinationAddr, (UINT16)( ((*((UINT64*)source.addr)) & U64(0x00000000ffff0000)) >> 16) ) ; break ; + } +} + +/* TODO: Wait-state timings! */ +static void SetProgramMemoryValue(dsp56k_core* cpustate, typed_pointer source, UINT32 destinationAddr) +{ + switch(source.data_type) + { + case DT_BYTE: cpustate->program->write_word(destinationAddr, (UINT16)( (*((UINT8*) source.addr) & 0xff) ) ) ; break ; + case DT_WORD: cpustate->program->write_word(destinationAddr, (UINT16)( (*((UINT16*)source.addr) & 0xffff) ) ) ; break ; + case DT_DOUBLE_WORD: cpustate->program->write_word(destinationAddr, (UINT16)( (*((UINT32*)source.addr) & 0x0000ffff) ) ) ; break ; + + /* !!! Is this universal ??? */ + /* !!! Forget not, yon shift-limiter !!! */ + case DT_LONG_WORD: cpustate->program->write_word(destinationAddr, (UINT16)( ((*((UINT64*)source.addr)) & U64(0x00000000ffff0000)) >> 16) ) ; break ; + } +} diff --git a/src/devices/cpu/dsp56k/dsp56pcu.c b/src/devices/cpu/dsp56k/dsp56pcu.c new file mode 100644 index 00000000000..7ec53891e4c --- /dev/null +++ b/src/devices/cpu/dsp56k/dsp56pcu.c @@ -0,0 +1,488 @@ +// license:BSD-3-Clause +// copyright-holders:Andrew Gardner +#include "dsp56pcu.h" +#include "dsp56mem.h" + +namespace DSP56K +{ +/* ************************************************************************* */ +/* Status Register */ +/* ************************************************************************* */ +/* MR CCR */ +/* |-------------------------------------| |-------------------------------| */ +/* | LF | FV | * | * | S1 | S0 | I1 | I0 | | S | L | E | U | N | Z | V | C | */ +/* |-------------------------------------| |-------------------------------| */ +/* */ +/* ************************************************************************* */ +UINT8 LF_bit(dsp56k_core* cpustate) { return (SR & 0x8000) >> 15; } +UINT8 FV_bit(dsp56k_core* cpustate) { return (SR & 0x4000) >> 14; } +// UINT8 S_bits(dsp56k_core* cpustate) { return (SR & 0x0c00) >> 10; } +UINT8 I_bits(dsp56k_core* cpustate) { return (SR & 0x0300) >> 8; } +UINT8 S_bit (dsp56k_core* cpustate) { return (SR & 0x0080) >> 7; } +UINT8 L_bit (dsp56k_core* cpustate) { return (SR & 0x0040) >> 6; } +UINT8 E_bit (dsp56k_core* cpustate) { return (SR & 0x0020) >> 5; } +UINT8 U_bit (dsp56k_core* cpustate) { return (SR & 0x0010) >> 4; } +UINT8 N_bit (dsp56k_core* cpustate) { return (SR & 0x0008) >> 3; } +UINT8 Z_bit (dsp56k_core* cpustate) { return (SR & 0x0004) >> 2; } +UINT8 V_bit (dsp56k_core* cpustate) { return (SR & 0x0002) >> 1; } +UINT8 C_bit (dsp56k_core* cpustate) { return (SR & 0x0001) >> 0; } + +/* MR setters */ +void LF_bit_set(dsp56k_core* cpustate, UINT8 value) { if (value) (SR |= 0x8000); else (SR &= (~0x8000)); } +void FV_bit_set(dsp56k_core* cpustate, UINT8 value) { if (value) (SR |= 0x4000); else (SR &= (~0x4000)); } +void S_bits_set(dsp56k_core* cpustate, UINT8 value) { value = value & 0x03; SR &= ~(0x0c00); SR |= (value << 10); } +void I_bits_set(dsp56k_core* cpustate, UINT8 value) { value = value & 0x03; SR &= ~(0x0300); SR |= (value << 8); } + +/* CCR setters */ +void S_bit_set(dsp56k_core* cpustate, UINT8 value) { if (value) (SR |= 0x0080); else (SR &= (~0x0080)); } +void L_bit_set(dsp56k_core* cpustate, UINT8 value) { if (value) (SR |= 0x0040); else (SR &= (~0x0040)); } +void E_bit_set(dsp56k_core* cpustate, UINT8 value) { if (value) (SR |= 0x0020); else (SR &= (~0x0020)); } +void U_bit_set(dsp56k_core* cpustate, UINT8 value) { if (value) (SR |= 0x0010); else (SR &= (~0x0010)); } +void N_bit_set(dsp56k_core* cpustate, UINT8 value) { if (value) (SR |= 0x0008); else (SR &= (~0x0008)); } +void Z_bit_set(dsp56k_core* cpustate, UINT8 value) { if (value) (SR |= 0x0004); else (SR &= (~0x0004)); } +void V_bit_set(dsp56k_core* cpustate, UINT8 value) { if (value) (SR |= 0x0002); else (SR &= (~0x0002)); } +void C_bit_set(dsp56k_core* cpustate, UINT8 value) { if (value) (SR |= 0x0001); else (SR &= (~0x0001)); } + + + +/* ************************************************************************* */ +/* Operating Mode Register */ +/* ************************************************************************* */ +/* */ +/* |---------------------------------------------------------------------| */ +/* | * | * | * | * | * | * | * | * | CD | SD | R | SA | * | MC | MB | MA | */ +/* |---------------------------------------------------------------------| */ +/* */ +/* ************************************************************************* */ +// UINT8 CD_bit(dsp56k_core* cpustate) { return ((OMR & 0x0080) != 0); } +// UINT8 SD_bit(dsp56k_core* cpustate) { return ((OMR & 0x0040) != 0); } +// UINT8 R_bit(dsp56k_core* cpustate) { return ((OMR & 0x0020) != 0); } +// UINT8 SA_bit(dsp56k_core* cpustate) { return ((OMR & 0x0010) != 0); } +// UINT8 MC_bit(dsp56k_core* cpustate) { return ((OMR & 0x0004) != 0); } +UINT8 MB_bit(dsp56k_core* cpustate) { return ((OMR & 0x0002) != 0); } +UINT8 MA_bit(dsp56k_core* cpustate) { return ((OMR & 0x0001) != 0); } + +void CD_bit_set(dsp56k_core* cpustate, UINT8 value) { if (value) (OMR |= 0x0080); else (OMR &= (~0x0080)); } +void SD_bit_set(dsp56k_core* cpustate, UINT8 value) { if (value) (OMR |= 0x0040); else (OMR &= (~0x0040)); } +void R_bit_set(dsp56k_core* cpustate, UINT8 value) { if (value) (OMR |= 0x0020); else (OMR &= (~0x0020)); } +void SA_bit_set(dsp56k_core* cpustate, UINT8 value) { if (value) (OMR |= 0x0010); else (OMR &= (~0x0010)); } +void MC_bit_set(dsp56k_core* cpustate, UINT8 value) { if (value) (OMR |= 0x0004); else (OMR &= (~0x0004)); } +void MB_bit_set(dsp56k_core* cpustate, UINT8 value) { if (value) (OMR |= 0x0002); else (OMR &= (~0x0002)); } +void MA_bit_set(dsp56k_core* cpustate, UINT8 value) { if (value) (OMR |= 0x0001); else (OMR &= (~0x0001)); } + +UINT8 dsp56k_operating_mode(dsp56k_core* cpustate) +{ + return ((MB_bit(cpustate) << 1) | MA_bit(cpustate)); +} + + + +/* ************************************************************************* */ +/* Stack Pointer */ +/* ************************************************************************* */ +/* */ +/* |---------------------------------------------------------------------| */ +/* | * | * | * | * | * | * | * | * | * | * | UF | SE | P3 | P2 | P1 | P0 | */ +/* |---------------------------------------------------------------------| */ +/* */ +/* ************************************************************************* */ +UINT8 UF_bit(dsp56k_core* cpustate) { return ((SP & 0x0020) != 0); } +UINT8 SE_bit(dsp56k_core* cpustate) { return ((SP & 0x0010) != 0); } + +//void UF_bit_set(dsp56k_core* cpustate, UINT8 value) {}; +//void SE_bit_set(dsp56k_core* cpustate, UINT8 value) {}; + + + +/*************************************************************************** + INITIALIZATION AND RESET +***************************************************************************/ +void pcu_init(dsp56k_core* cpustate, device_t *device) +{ + /* Init the irq table */ + dsp56k_irq_table_init(); + + /* save states - dsp56k_pcu members */ + device->save_item(NAME(cpustate->PCU.pc)); + device->save_item(NAME(cpustate->PCU.la)); + device->save_item(NAME(cpustate->PCU.lc)); + device->save_item(NAME(cpustate->PCU.sr)); + device->save_item(NAME(cpustate->PCU.omr)); + device->save_item(NAME(cpustate->PCU.sp)); + device->save_item(NAME(cpustate->PCU.ss)); + device->save_item(NAME(cpustate->PCU.pending_interrupts)); + device->save_item(NAME(cpustate->PCU.reset_vector)); +} + +void pcu_reset(dsp56k_core* cpustate) +{ + int i; + + /* When reset is deasserted, set MA, MB, and MC from MODA, MODB, and MODC lines. */ + MA_bit_set(cpustate, cpustate->modA_state); + MB_bit_set(cpustate, cpustate->modB_state); + MC_bit_set(cpustate, cpustate->modC_state); + + /* Reset based on the operating mode. */ + switch(dsp56k_operating_mode(cpustate)) + { + case 0x00: + logerror("Dsp56k in Special Bootstrap Mode 1\n"); + + /* HACK - We don't need to put the bootstrap mode on here since */ + /* we'll simulate it entirely in this function */ + cpustate->bootstrap_mode = BOOTSTRAP_OFF; + + /* HACK - Simply copy over 0x1000 bytes of data located at program memory 0xc000. */ + /* This, in actuality, is handled with the internal boot ROM. */ + for (i = 0; i < 0x800; i++) + { + UINT32 mem_offset = (0xc000<<1) + (i<<1); /* TODO: TEST */ + + /* TODO - DO I HAVE TO FLIP THIS WORD? */ + /* P:$c000 -> Internal P:$0000 low byte */ + /* P:$c001 -> Internal P:$0000 high byte */ + /* ... */ + /* P:$cffe -> Internal P:$07ff low byte */ + /* P:$cfff -> Internal P:$07ff high byte */ + UINT8 mem_value_low = cpustate->program->read_byte(mem_offset); /* TODO: IS THIS READING RIGHT? */ + UINT8 mem_value_high = cpustate->program->read_byte(mem_offset); + cpustate->program_ram[i] = (mem_value_high << 8) || mem_value_low; + } + + /* HACK - Set the PC to 0x0000 as per the boot ROM. */ + PC = 0x0000; + + /* HACK - All done! Set the Operating Mode to 2 as per the boot ROM. */ + MB_bit_set(cpustate, 1); + MA_bit_set(cpustate, 0); + cpustate->PCU.reset_vector = 0xe000; + break; + + case 0x01: + logerror("Dsp56k in Special Bootstrap Mode 2\n"); + + /* HACK - Turn bootstrap mode on. This hijacks the CPU execute loop and lets */ + /* Either the host interface or the SSIO interface suck in all the data */ + /* they need. Once they've had their fill, they turn bootstrap mode off */ + /* and the CPU begins execution at 0x0000; */ + /* HACK - Read bit 15 at 0xc000 to see if we're working with the SSIO or host interface. */ + if (cpustate->program->read_word(0xc000<<1) & 0x8000) + { + cpustate->bootstrap_mode = BOOTSTRAP_SSIX; + logerror("DSP56k : Currently in (hacked) bootstrap mode - reading from SSIx.\n"); + } + else + { + cpustate->bootstrap_mode = BOOTSTRAP_HI; + logerror("DSP56k : Currently in (hacked) bootstrap mode - reading from Host Interface.\n"); + } + + /* HACK - Set the PC to 0x0000 as per the boot ROM. */ + PC = 0x0000; + + /* HACK - Not done yet, but set the Operating Mode to 2 in preparation. */ + MB_bit_set(cpustate, 1); + MA_bit_set(cpustate, 0); + cpustate->PCU.reset_vector = 0xe000; + break; + + case 0x02: + logerror("Dsp56k in Normal Expanded Mode\n"); + PC = 0xe000; + cpustate->PCU.reset_vector = 0xe000; + break; + + case 0x03: + logerror("Dsp56k in Development Expanded Mode\n"); + /* TODO: Disable internal ROM, etc. Likely a tricky thing for MAME? */ + PC = 0x0000; + cpustate->PCU.reset_vector = 0x0000; + break; + } + + /* Set registers properly */ + /* 1-17 Clear Interrupt Priority Register (IPR) */ + IPR = 0x0000; + + /* FM.5-4 */ + I_bits_set(cpustate, 0x03); + S_bits_set(cpustate, 0); + L_bit_set(cpustate, 0); + S_bit_set(cpustate, 0); + FV_bit_set(cpustate, 0); + + /* FM.7-25 */ + E_bit_set(cpustate, 0); + U_bit_set(cpustate, 0); + N_bit_set(cpustate, 0); + V_bit_set(cpustate, 0); + Z_bit_set(cpustate, 0); + + /* FM.5-4+ */ + C_bit_set(cpustate, 0); + LF_bit_set(cpustate, 0); + SP = 0x0000; + + /* FM.5-14 (OMR) */ + SA_bit_set(cpustate, 0); + R_bit_set(cpustate, 0); + SD_bit_set(cpustate, 0); + CD_bit_set(cpustate, 0); + + /* Clear out the pending interrupt list */ + dsp56k_clear_pending_interrupts(cpustate); +} + +/*************************************************************************** + INTERRUPT HANDLING +***************************************************************************/ +struct dsp56k_irq_data +{ + UINT16 irq_vector; + char irq_source[128]; +}; + +dsp56k_irq_data dsp56k_interrupt_sources[32]; + +/* TODO: Figure out how to switch on level versus edge-triggered. */ +void pcu_service_interrupts(dsp56k_core* cpustate) +{ + int i; + + /* Count list of pending interrupts */ + int num_servicable = dsp56k_count_pending_interrupts(cpustate); + + if (num_servicable == 0) + return; + + /* Sort list according to priority */ + dsp56k_sort_pending_interrupts(cpustate, num_servicable); + + /* Service each interrupt in order */ + /* TODO: This just *can't* be right :) */ + for (i = 0; i < num_servicable; i++) + { + const int interrupt_index = cpustate->PCU.pending_interrupts[i]; + + /* Get the priority of the interrupt - a return value of -1 means disabled! */ + INT8 priority = dsp56k_get_irq_priority(cpustate, interrupt_index); + + /* 1-12 Make sure you're not masked out against the Interrupt Mask Bits (disabled is handled for free here) */ + if (priority >= I_bits(cpustate)) + { + /* TODO: Implement long interrupts & fast interrupts correctly! */ + /* Right now they are handled in the JSR & BSR ops. SupahLame. */ + cpustate->ppc = PC; + + /* Are you anything but the Host Command interrupt? */ + if (interrupt_index != 22) + { + /* Execute a normal interrupt */ + PC = dsp56k_interrupt_sources[interrupt_index].irq_vector; + } + else + { + /* The host command input has a floating vector. */ + const UINT16 irq_vector = HV_bits(cpustate) << 1; + + PC = irq_vector; + + /* TODO: 5-9 5-11 Gotta' Clear HC (HCP gets it too) when taking this exception! */ + HC_bit_set(cpustate, 0); + } + } + } + + dsp56k_clear_pending_interrupts(cpustate); +} + + +/* Register an interrupt */ +void dsp56k_add_pending_interrupt(dsp56k_core* cpustate, const char* name) +{ + int i; + int irq_index = dsp56k_get_irq_index_by_tag(name); + + for (i = 0; i < 32; i++) + { + if (cpustate->PCU.pending_interrupts[i] == -1) + { + cpustate->PCU.pending_interrupts[i] = irq_index; + break; + } + } +} + +/* Utility function to construct IRQ table */ +void dsp56k_set_irq_source(UINT8 irq_num, UINT16 iv, const char* source) +{ + dsp56k_interrupt_sources[irq_num].irq_vector = iv; + strcpy(dsp56k_interrupt_sources[irq_num].irq_source, source); +} + +/* Construct a table containing pertient IRQ information */ +void dsp56k_irq_table_init(void) +{ + /* 1-14 + 1-18 */ + /* TODO: Cull host command stuff appropriately */ + /* array index . vector . token */ + dsp56k_set_irq_source(0, 0x0000, "Hardware RESET"); + dsp56k_set_irq_source(1, 0x0002, "Illegal Instruction"); + dsp56k_set_irq_source(2, 0x0004, "Stack Error"); + dsp56k_set_irq_source(3, 0x0006, "Reserved"); + dsp56k_set_irq_source(4, 0x0008, "SWI"); + dsp56k_set_irq_source(5, 0x000a, "IRQA"); + dsp56k_set_irq_source(6, 0x000c, "IRQB"); + dsp56k_set_irq_source(7, 0x000e, "Reserved"); + dsp56k_set_irq_source(8, 0x0010, "SSI0 Receive Data with Exception"); + dsp56k_set_irq_source(9, 0x0012, "SSI0 Receive Data"); + dsp56k_set_irq_source(10, 0x0014, "SSI0 Transmit Data with Exception"); + dsp56k_set_irq_source(11, 0x0016, "SSI0 Transmit Data"); + dsp56k_set_irq_source(12, 0x0018, "SSI1 Receive Data with Exception"); + dsp56k_set_irq_source(13, 0x001a, "SSI1 Receive Data"); + dsp56k_set_irq_source(14, 0x001c, "SSI1 Transmit Data with Exception"); + dsp56k_set_irq_source(15, 0x001e, "SSI1 Transmit Data"); + dsp56k_set_irq_source(16, 0x0020, "Timer Overflow"); + dsp56k_set_irq_source(17, 0x0022, "Timer Compare"); + dsp56k_set_irq_source(18, 0x0024, "Host DMA Receive Data"); + dsp56k_set_irq_source(19, 0x0026, "Host DMA Transmit Data"); + dsp56k_set_irq_source(20, 0x0028, "Host Receive Data"); + dsp56k_set_irq_source(21, 0x002a, "Host Transmit Data"); + dsp56k_set_irq_source(22, 0x002c, "Host Command"); /* Default vector for the host command */ + dsp56k_set_irq_source(23, 0x002e, "Codec Receive/Transmit"); + dsp56k_set_irq_source(24, 0x0030, "Host Command 1"); + dsp56k_set_irq_source(25, 0x0032, "Host Command 2"); + dsp56k_set_irq_source(26, 0x0034, "Host Command 3"); + dsp56k_set_irq_source(27, 0x0036, "Host Command 4"); + dsp56k_set_irq_source(28, 0x0038, "Host Command 5"); + dsp56k_set_irq_source(29, 0x003a, "Host Command 6"); + dsp56k_set_irq_source(30, 0x003c, "Host Command 7"); + dsp56k_set_irq_source(31, 0x003e, "Host Command 8"); +} + +/* Clear all entries from the pending table */ +void dsp56k_clear_pending_interrupts(dsp56k_core* cpustate) +{ + int i; + for (i = 0; i < 32; i++) + { + cpustate->PCU.pending_interrupts[i] = -1; + } +} + +/* Recover number of pending irqs */ +int dsp56k_count_pending_interrupts(dsp56k_core* cpustate) +{ + int numI = 0; + while (cpustate->PCU.pending_interrupts[numI] != -1) + { + numI++; + } + + return numI; +} + +/* Sort the pending irqs by priority */ +void dsp56k_sort_pending_interrupts(dsp56k_core* cpustate, int num) +{ + int i, j; + + /* We're going to be sorting the priorities */ + int priority_list[32]; + for (i = 0; i < num; i++) + { + priority_list[i] = dsp56k_get_irq_priority(cpustate, cpustate->PCU.pending_interrupts[i]); + } + + /* Bubble sort should be good enough for us */ + for (i = 0; i < num; i++) + { + for(j = 0; j < num-1; j++) + { + if (priority_list[j] > priority_list[j+1]) + { + int holder; + + /* Swap priorities */ + holder = priority_list[j+1]; + priority_list[j+1] = priority_list[j]; + priority_list[j] = holder; + + /* Swap irq indices. */ + holder = cpustate->PCU.pending_interrupts[j+1]; + cpustate->PCU.pending_interrupts[j+1] = cpustate->PCU.pending_interrupts[j]; + cpustate->PCU.pending_interrupts[j] = holder; + } + } + } + + /* TODO: 1-17 Now sort each of the priority levels within their categories. */ +} + +/* Given an index into the irq table, return the interrupt's current priority */ +INT8 dsp56k_get_irq_priority(dsp56k_core* cpustate, int index) +{ + /* 1-12 */ + switch (index) + { + /* Non-maskable */ + case 0: return 3; /* Hardware RESET */ + case 1: return 3; /* Illegal Instruction */ + case 2: return 3; /* Stack Error */ + case 3: return 3; /* Reserved */ + case 4: return 3; /* SWI */ + + /* Poll the IPR for these guys. */ + case 5: return irqa_ipl(cpustate); /* IRQA */ + case 6: return irqb_ipl(cpustate); /* IRQB */ + case 7: return -1; /* Reserved */ + case 8: return ssi0_ipl(cpustate); /* SSI0 Receive Data with Exception */ + case 9: return ssi0_ipl(cpustate); /* SSI0 Receive Data */ + case 10: return ssi0_ipl(cpustate); /* SSI0 Transmit Data with Exception */ + case 11: return ssi0_ipl(cpustate); /* SSI0 Transmit Data */ + case 12: return ssi1_ipl(cpustate); /* SSI1 Receive Data with Exception */ + case 13: return ssi1_ipl(cpustate); /* SSI1 Receive Data */ + case 14: return ssi1_ipl(cpustate); /* SSI1 Transmit Data with Exception */ + case 15: return ssi1_ipl(cpustate); /* SSI1 Transmit Data */ + case 16: return tm_ipl(cpustate); /* Timer Overflow */ + case 17: return tm_ipl(cpustate); /* Timer Compare */ + case 18: return host_ipl(cpustate); /* Host DMA Receive Data */ + case 19: return host_ipl(cpustate); /* Host DMA Transmit Data */ + case 20: return host_ipl(cpustate); /* Host Receive Data */ + case 21: return host_ipl(cpustate); /* Host Transmit Data */ + case 22: return host_ipl(cpustate); /* Host Command 0 (Default) */ + case 23: return codec_ipl(cpustate); /* Codec Receive/Transmit */ + case 24: return host_ipl(cpustate); /* Host Command 1 // TODO: Are all host ipl's the same? */ + case 25: return host_ipl(cpustate); /* Host Command 2 */ + case 26: return host_ipl(cpustate); /* Host Command 3 */ + case 27: return host_ipl(cpustate); /* Host Command 4 */ + case 28: return host_ipl(cpustate); /* Host Command 5 */ + case 29: return host_ipl(cpustate); /* Host Command 6 */ + case 30: return host_ipl(cpustate); /* Host Command 7 */ + case 31: return host_ipl(cpustate); /* Host Command 8 */ + + default: break; + } + + return -1; +} + +/* Given an IRQ name, return its index in the irq table */ +int dsp56k_get_irq_index_by_tag(const char* tag) +{ + int i; + for (i = 0; i < 32; i++) + { + if (strcmp(tag, dsp56k_interrupt_sources[i].irq_source) == 0) + { + return i; + } + } + + fatalerror("DSP56K ERROR : IRQ TAG specified incorrectly (get_vector_by_tag) : %s.\n", tag); + // never executed + //return -1; +} + +} // namespace DSP56K diff --git a/src/devices/cpu/dsp56k/dsp56pcu.h b/src/devices/cpu/dsp56k/dsp56pcu.h new file mode 100644 index 00000000000..7463ac11d35 --- /dev/null +++ b/src/devices/cpu/dsp56k/dsp56pcu.h @@ -0,0 +1,150 @@ +// license:BSD-3-Clause +// copyright-holders:Andrew Gardner +#ifndef __DSP56_PCU_H__ +#define __DSP56_PCU_H__ + +#include "dsp56k.h" + +namespace DSP56K +{ +/*************************************************************************** + PCU +***************************************************************************/ +void pcu_reset(dsp56k_core* cpustate); +void pcu_init(dsp56k_core* cpustate, device_t *device); +#define PC (cpustate->PCU.pc) +#define LA (cpustate->PCU.la) +#define LC (cpustate->PCU.lc) +#define SR (cpustate->PCU.sr) +#define OMR (cpustate->PCU.omr) +#define SP (cpustate->PCU.sp) +#define SS (cpustate->PCU.ss) + +#define SSH (SS[SP].w.h) +#define SSL (SS[SP].w.l) + +#define ST0 (SS[0].d) +#define ST1 (SS[1].d) +#define ST2 (SS[2].d) +#define ST3 (SS[3].d) +#define ST4 (SS[4].d) +#define ST5 (SS[5].d) +#define ST6 (SS[6].d) +#define ST7 (SS[7].d) +#define ST8 (SS[8].d) +#define ST9 (SS[9].d) +#define ST10 (SS[10].d) +#define ST11 (SS[11].d) +#define ST12 (SS[12].d) +#define ST13 (SS[13].d) +#define ST14 (SS[14].d) +#define ST15 (SS[15].d) + +/* STATUS REGISTER (SR) BITS (1-25) */ +/* MR */ +UINT8 LF_bit(dsp56k_core* cpustate); +UINT8 FV_bit(dsp56k_core* cpustate); +//UINT8 S_bits(dsp56k_core* cpustate); +UINT8 I_bits(dsp56k_core* cpustate); + +/* CCR - with macros for easy access */ +#define S() (S_bit(cpustate)) +UINT8 S_bit(dsp56k_core* cpustate); +#define L() (L_bit(cpustate)) +UINT8 L_bit(dsp56k_core* cpustate); +#define E() (E_bit(cpustate)) +UINT8 E_bit(dsp56k_core* cpustate); +#define U() (U_bit(cpustate)) +UINT8 U_bit(dsp56k_core* cpustate); +#define N() (N_bit(cpustate)) +UINT8 N_bit(dsp56k_core* cpustate); +#define Z() (Z_bit(cpustate)) +UINT8 Z_bit(dsp56k_core* cpustate); +#define V() (V_bit(cpustate)) +UINT8 V_bit(dsp56k_core* cpustate); +#define C() (C_bit(cpustate)) +UINT8 C_bit(dsp56k_core* cpustate); + +/* MR setters */ +void LF_bit_set(dsp56k_core* cpustate, UINT8 value); +void FV_bit_set(dsp56k_core* cpustate, UINT8 value); +void S_bits_set(dsp56k_core* cpustate, UINT8 value); +void I_bits_set(dsp56k_core* cpustate, UINT8 value); + +/* CCR setters - with macros for easy access */ +#define DSP56K_S_SET() (S_bit_set(cpustate, 1)) +#define DSP56K_S_CLEAR() (S_bit_set(cpustate, 0)) +void S_bit_set(dsp56k_core* cpustate, UINT8 value); +#define DSP56K_L_SET() (L_bit_set(cpustate, 1)) +#define DSP56K_L_CLEAR() (L_bit_set(cpustate, 0)) +void L_bit_set(dsp56k_core* cpustate, UINT8 value); +#define DSP56K_E_SET() (E_bit_set(cpustate, 1)) +#define DSP56K_E_CLEAR() (E_bit_set(cpustate, 0)) +void E_bit_set(dsp56k_core* cpustate, UINT8 value); +#define DSP56K_U_SET() (U_bit_set(cpustate, 1)) +#define DSP56K_U_CLEAR() (U_bit_set(cpustate, 0)) +void U_bit_set(dsp56k_core* cpustate, UINT8 value); +#define DSP56K_N_SET() (N_bit_set(cpustate, 1)) +#define DSP56K_N_CLEAR() (N_bit_set(cpustate, 0)) +void N_bit_set(dsp56k_core* cpustate, UINT8 value); +#define DSP56K_Z_SET() (Z_bit_set(cpustate, 1)) +#define DSP56K_Z_CLEAR() (Z_bit_set(cpustate, 0)) +void Z_bit_set(dsp56k_core* cpustate, UINT8 value); +#define DSP56K_V_SET() (V_bit_set(cpustate, 1)) +#define DSP56K_V_CLEAR() (V_bit_set(cpustate, 0)) +void V_bit_set(dsp56k_core* cpustate, UINT8 value); +#define DSP56K_C_SET() (C_bit_set(cpustate, 1)) +#define DSP56K_C_CLEAR() (C_bit_set(cpustate, 0)) +void C_bit_set(dsp56k_core* cpustate, UINT8 value); + +// TODO: Maybe some functions for Interrupt Mask and Scaling Mode go here? + + +/* 1-28 OPERATING MODE REGISTER (OMR) BITS */ +//UINT8 CD_bit(dsp56k_core* cpustate); +//UINT8 SD_bit(dsp56k_core* cpustate); +//UINT8 R_bit(dsp56k_core* cpustate); +//UINT8 SA_bit(dsp56k_core* cpustate); +//UINT8 MC_bit(dsp56k_core* cpustate); +UINT8 MB_bit(dsp56k_core* cpustate); +UINT8 MA_bit(dsp56k_core* cpustate); + +void CD_bit_set(dsp56k_core* cpustate, UINT8 value); +void SD_bit_set(dsp56k_core* cpustate, UINT8 value); +void R_bit_set(dsp56k_core* cpustate, UINT8 value); +void SA_bit_set(dsp56k_core* cpustate, UINT8 value); +void MC_bit_set(dsp56k_core* cpustate, UINT8 value); +void MB_bit_set(dsp56k_core* cpustate, UINT8 value); +void MA_bit_set(dsp56k_core* cpustate, UINT8 value); + +/* 1-27 STACK POINTER (SP) BITS */ +UINT8 UF_bit(dsp56k_core* cpustate); +UINT8 SE_bit(dsp56k_core* cpustate); + +//void UF_bit_set(dsp56k_core* cpustate, UINT8 value) {}; +//void SE_bit_set(dsp56k_core* cpustate, UINT8 value) {}; + + +// HACK - Bootstrap modes +#define BOOTSTRAP_OFF (0) +#define BOOTSTRAP_SSIX (1) +#define BOOTSTRAP_HI (2) + + +/* PCU IRQ goodies */ +void pcu_service_interrupts(dsp56k_core* cpustate); + +void dsp56k_irq_table_init(void); +void dsp56k_set_irq_source(UINT8 irq_num, UINT16 iv, const char* source); +int dsp56k_get_irq_index_by_tag(const char* tag); + +void dsp56k_add_pending_interrupt(dsp56k_core* cpustate, const char* name); // Call me to add an interrupt to the queue + +void dsp56k_clear_pending_interrupts(dsp56k_core* cpustate); +int dsp56k_count_pending_interrupts(dsp56k_core* cpustate); +void dsp56k_sort_pending_interrupts(dsp56k_core* cpustate, int num); +INT8 dsp56k_get_irq_priority(dsp56k_core* cpustate, int index); + +} // namespace DSP56K + +#endif diff --git a/src/devices/cpu/dsp56k/inst.c b/src/devices/cpu/dsp56k/inst.c new file mode 100644 index 00000000000..d01bbdbcf04 --- /dev/null +++ b/src/devices/cpu/dsp56k/inst.c @@ -0,0 +1,785 @@ +// license:BSD-3-Clause +// copyright-holders:Andrew Gardner +#include "inst.h" +#include "emu.h" + +namespace DSP56K +{ +// Factory +Instruction* Instruction::decodeInstruction(const Opcode* opc, + const UINT16 word0, + const UINT16 word1, + bool shifted) +{ + UINT16 w0 = word0; + UINT16 w1 = word1; + + if (shifted) + { + w0 = w1; + w1 = 0x0000; + } + + /**************************************************************************/ + /* The very funky case of the XMemoryDataMoveWithShortDisplacement */ + /**************************************************************************/ + if ((w0 & 0xff00) == 0x0500) + { + // Avoid "05-- 05--" recursion + if (shifted) return NULL; + + auto_pointer op(decodeInstruction(opc, w0, w1, true)); + if (op) + { + // This parallel move only works for certain trailing instructions. + if (dynamic_cast(op.get()) || + dynamic_cast(op.get()) || + dynamic_cast(op.get()) || + dynamic_cast(op.get()) || + dynamic_cast(op.get()) || + dynamic_cast(op.get()) || + dynamic_cast(op.get()) || + dynamic_cast(op.get()) || + dynamic_cast(op.get()) || + dynamic_cast(op.get()) + /* TODO: More? */) + { + op->m_sizeIncrement = 1; + return op; + } + } + } + + + /**************************************************************************/ + /* Dual X Memory Data Read : 011m mKKK .rr. .... : A-142 */ + /* Quote: (MOVE, MAC(R), MPY(R), ADD, SUB, TFR) */ + /**************************************************************************/ + /* TFR : 011m mKKK 0rr1 F0DD : A-212 */ + if ((w0 & 0xe094) == 0x6010) + { + return global_alloc(Tfr_2(opc, w0, w1)); + } + /* MOVE : 011m mKKK 0rr1 0000 : A-128 */ + if ((w0 & 0xe097) == 0x6017) + { + return global_alloc(Move_2(opc, w0, w1)); + } + /* MAC : 011m mKKK 1xx0 F1QQ : A-122 */ + else if ((w0 & 0xe094) == 0x6084) + { + return global_alloc(Mac_3(opc, w0, w1)); + } + /* MACR: 011m mKKK 1--1 F1QQ : A-124 */ + else if ((w0 & 0xe094) == 0x6094) + { + return global_alloc(Macr_2(opc, w0, w1)); + } + /* MPY : 011m mKKK 1xx0 F0QQ : A-160 */ + else if ((w0 & 0xe094) == 0x6080) + { + return global_alloc(Mpy_2(opc, w0, w1)); + } + /* MPYR : 011m mKKK 1--1 F0QQ : A-162 */ + else if ((w0 & 0xe094) == 0x6090) + { + return global_alloc(Mpyr_2(opc, w0, w1)); + } + /* ADD : 011m mKKK 0rru Fuuu : A-22 */ + /* SUB : 011m mKKK 0rru Fuuu : A-202 */ + else if ((w0 & 0xe080) == 0x6000) + { + return global_alloc(Add_2(opc, w0, w1)); + } + + /****************************************************************************/ + /* X Memory Data Write and Register Data Move : 0001 011k RRDD .... : A-140 */ + /* Quote: (MPY or MAC) */ + /****************************************************************************/ + /* MPY : 0001 0110 RRDD FQQQ : A-160 */ + else if ((w0 & 0xff00) == 0x1600) + { + return global_alloc(Mpy_3(opc, w0, w1)); + } + /* MAC : 0001 0111 RRDD FQQQ : A-122 */ + else if ((w0 & 0xff00) == 0x1700) + { + return global_alloc(Mac_3(opc, w0, w1)); + } + + /****************************************************************/ + /* No Parallel Data Move : 0100 1010 .... .... : A-131 */ + /* Register to Register Data Move : 0100 IIII .... .... : A-133 */ + /* Address Register Update : 0011 0zRR .... .... : A-135 */ + /* X Memory Data Move : 1mRR HHHW .... .... : A-137 */ + /* X Memory Data Move : 0101 HHHW .... .... : A-137 */ + /* Quote: (32 General parallel move instructions) */ + /****************************************************************/ + else if (((w0 & 0xff00) == 0x4a00) || + ((w0 & 0xf000) == 0x4000) || + ((w0 & 0xf800) == 0x3000) || + ((w0 & 0x8000) == 0x8000) || + ((w0 & 0xf000) == 0x5000)) + { + /* Note: There is much overlap down here, so certain ops must come before others */ + + /* CLR : .... .... 0000 F001 : A-60 */ + if ((w0 & 0x00f7) == 0x0001) + { + return global_alloc(Clr(opc, w0, w1)); + } + /* ADD : .... .... 0000 FJJJ : A-22 */ + else if ((w0 & 0x00f0) == 0x0000) + { + return global_alloc(Add(opc, w0, w1)); + } + + /* MOVE : .... .... 0001 0001 : A-128 */ + else if ((w0 & 0x00ff) == 0x0011 || (w0 & 0x00ff) == 0x0019) + // NEW // else if ((w0 & 0x00ff) == 0x0011) + { + return global_alloc(Move(opc, w0, w1)); + } + /* TFR : .... .... 0001 FJJJ : A-212 */ + else if ((w0 & 0x00f0) == 0x0010) + { + return global_alloc(Tfr(opc, w0, w1)); + } + + /* RND : .... .... 0010 F000 : A-188 */ + else if ((w0 & 0x00f7) == 0x0020) + { + return global_alloc(Rnd(opc, w0, w1)); + } + /* TST : .... .... 0010 F001 : A-218 */ + else if ((w0 & 0x00f7) == 0x0021) + { + return global_alloc(Tst(opc, w0, w1)); + } + /* INC : .... .... 0010 F010 : A-104 */ + else if ((w0 & 0x00f7) == 0x0022) + { + return global_alloc(Inc(opc, w0, w1)); + } + /* INC24 : .... .... 0010 F011 : A-106 */ + else if ((w0 & 0x00f7) == 0x0023) + { + return global_alloc(Inc24(opc, w0, w1)); + } + /* OR : .... .... 0010 F1JJ : A-176 */ + else if ((w0 & 0x00f4) == 0x0024) + { + return global_alloc(Or(opc, w0, w1)); + } + + /* ASR : .... .... 0011 F000 : A-32 */ + else if ((w0 & 0x00f7) == 0x0030) + { + return global_alloc(Asr(opc, w0, w1)); + } + /* ASL : .... .... 0011 F001 : A-28 */ + else if ((w0 & 0x00f7) == 0x0031) + { + return global_alloc(Asl(opc, w0, w1)); + } + /* LSR : .... .... 0011 F010 : A-120 */ + else if ((w0 & 0x00f7) == 0x0032) + { + return global_alloc(Lsr(opc, w0, w1)); + } + /* LSL : .... .... 0011 F011 : A-118 */ + else if ((w0 & 0x00f7) == 0x0033) + { + return global_alloc(Lsl(opc, w0, w1)); + } + /* EOR : .... .... 0011 F1JJ : A-94 */ + else if ((w0 & 0x00f4) == 0x0034) + { + return global_alloc(Eor(opc, w0, w1)); + } + + /* SUBL : .... .... 0100 F001 : A-204 */ + else if ((w0 & 0x00f7) == 0x0041) + { + return global_alloc(Subl(opc, w0, w1)); + } + /* SUB : .... .... 0100 FJJJ : A-202 */ + else if ((w0 & 0x00f0) == 0x0040) + { + return global_alloc(Sub(opc, w0, w1)); + } + + /* CLR24 : .... .... 0101 F001 : A-62 */ + else if ((w0 & 0x00f7) == 0x0051) + { + return global_alloc(Clr24(opc, w0, w1)); + } + /* SBC : .... .... 0101 F01J : A-198 */ + else if ((w0 & 0x00f6) == 0x0052) + { + return global_alloc(Sbc(opc, w0, w1)); + } + /* CMP : .... .... 0101 FJJJ : A-64 */ + else if ((w0 & 0x00f0) == 0x0050) + { + return global_alloc(Cmp(opc, w0, w1)); + } + + /* NEG : .... .... 0110 F000 : A-166 */ + else if ((w0 & 0x00f7) == 0x0060) + { + return global_alloc(Neg(opc, w0, w1)); + } + /* NOT : .... .... 0110 F001 : A-174 */ + else if ((w0 & 0x00f7) == 0x0061) + { + return global_alloc(Not(opc, w0, w1)); + } + /* DEC : .... .... 0110 F010 : A-72 */ + else if ((w0 & 0x00f7) == 0x0062) + { + return global_alloc(Dec(opc, w0, w1)); + } + /* DEC24 : .... .... 0110 F011 : A-74 */ + else if ((w0 & 0x00f7) == 0x0063) + { + return global_alloc(Dec24(opc, w0, w1)); + } + /* AND : .... .... 0110 F1JJ : A-24 */ + else if ((w0 & 0x00f4) == 0x0064) + { + return global_alloc(And(opc, w0, w1)); + } + + /* ABS : .... .... 0111 F001 : A-18 */ + if ((w0 & 0x00f7) == 0x0071) + { + return global_alloc(Abs(opc, w0, w1)); + } + /* ROR : .... .... 0111 F010 : A-192 */ + else if ((w0 & 0x00f7) == 0x0072) + { + return global_alloc(Ror(opc, w0, w1)); + } + /* ROL : .... .... 0111 F011 : A-190 */ + else if ((w0 & 0x00f7) == 0x0073) + { + return global_alloc(Rol(opc, w0, w1)); + } + /* CMPM : .... .... 0111 FJJJ : A-66 */ + else if ((w0 & 0x00f0) == 0x0070) + { + return global_alloc(Cmpm(opc, w0, w1)); + } + + /* MPY : .... .... 1k00 FQQQ : A-160 */ + else if ((w0 & 0x00b0) == 0x0080) + { + return global_alloc(Mpy(opc, w0, w1)); + } + /* MPYR : .... .... 1k01 FQQQ : A-162 */ + else if ((w0 & 0x00b0) == 0x0090) + { + return global_alloc(Mpyr(opc, w0, w1)); + } + /* MAC : .... .... 1k10 FQQQ : A-122 */ + else if ((w0 & 0x00b0) == 0x00a0) + { + return global_alloc(Mac(opc, w0, w1)); + } + /* MACR : .... .... 1k11 FQQQ : A-124 */ + else if ((w0 & 0x00b0) == 0x00b0) + { + return global_alloc(Macr(opc, w0, w1)); + } + } + + /******************************/ + /* Remaining non-parallel ops */ + /******************************/ + /* ADC : 0001 0101 0000 F01J : A-20 */ + else if ((w0 & 0xfff6) == 0x1502) + { + return global_alloc(Adc(opc, w0, w1)); + } + /* ANDI : 0001 1EE0 iiii iiii : A-26 */ + /* Note: MoveP sneaks in here if you don't check 0x0600 */ + else if (((w0 & 0xf900) == 0x1800) & ((w0 & 0x0600) != 0x0000)) + { + return global_alloc(Andi(opc, w0, w1)); + } + /* ASL4 : 0001 0101 0011 F001 : A-30 */ + else if ((w0 & 0xfff7) == 0x1531) + { + return global_alloc(Asl4(opc, w0, w1)); + } + /* ASR4 : 0001 0101 0011 F000 : A-34 */ + else if ((w0 & 0xfff7) == 0x1530) + { + return global_alloc(Asr4(opc, w0, w1)); + } + /* ASR16 : 0001 0101 0111 F000 : A-36 */ + else if ((w0 & 0xfff7) == 0x1570) + { + return global_alloc(Asr16(opc, w0, w1)); + } + /* BFCHG : 0001 0100 11Pp pppp BBB1 0010 iiii iiii : A-38 */ + else if (((w0 & 0xffc0) == 0x14c0) && ((w1 & 0x1f00) == 0x1200)) + { + return global_alloc(BfInstruction(opc, w0, w1)); + } + /* BFCHG : 0001 0100 101- --RR BBB1 0010 iiii iiii : A-38 */ + else if (((w0 & 0xfff0) == 0x14b0) && ((w1 & 0x1f00) == 0x1200)) + // NEW // else if (((w0 & 0xffe0) == 0x14a0) && ((w1 & 0x1f00) == 0x1200)) + { + return global_alloc(BfInstruction_2(opc, w0, w1)); + } + /* BFCHG : 0001 0100 100D DDDD BBB1 0010 iiii iiii : A-38 */ + else if (((w0 & 0xffe0) == 0x1480) && ((w1 & 0x1f00) == 0x1200)) + { + return global_alloc(BfInstruction_3(opc, w0, w1)); + } + /* BFCLR : 0001 0100 11Pp pppp BBB0 0100 iiii iiii : A-40 */ + else if (((w0 & 0xffc0) == 0x14c0) && ((w1 & 0x1f00) == 0x0400)) + { + return global_alloc(BfInstruction(opc, w0, w1)); + } + /* BFCLR : 0001 0100 101- --RR BBB0 0100 iiii iiii : A-40 */ + else if (((w0 & 0xfff0) == 0x14b0) && ((w1 & 0x1f00) == 0x0400)) + // NEW // else if (((w0 & 0xffe0) == 0x14a0) && ((w1 & 0x1f00) == 0x0400)) + { + return global_alloc(BfInstruction_2(opc, w0, w1)); + } + /* BFCLR : 0001 0100 100D DDDD BBB0 0100 iiii iiii : A-40 */ + else if (((w0 & 0xffe0) == 0x1480) && ((w1 & 0x1f00) == 0x0400)) + { + return global_alloc(BfInstruction_3(opc, w0, w1)); + } + /* BFSET : 0001 0100 11Pp pppp BBB1 1000 iiii iiii : A-42 */ + else if (((w0 & 0xffc0) == 0x14c0) && ((w1 & 0x1f00) == 0x1800)) + { + return global_alloc(BfInstruction(opc, w0, w1)); + } + /* BFSET : 0001 0100 101- --RR BBB1 1000 iiii iiii : A-42 */ + else if (((w0 & 0xfff0) == 0x14b0) && ((w1 & 0x1f00) == 0x1800)) + // NEW // else if (((w0 & 0xffe0) == 0x14a0) && ((w1 & 0x1f00) == 0x1800)) + { + return global_alloc(BfInstruction_2(opc, w0, w1)); + } + /* BFSET : 0001 0100 100D DDDD BBB1 1000 iiii iiii : A-42 */ + else if (((w0 & 0xffe0) == 0x1480) && ((w1 & 0x1f00) == 0x1800)) + { + return global_alloc(BfInstruction_3(opc, w0, w1)); + } + /* BFTSTH : 0001 0100 01Pp pppp BBB1 0000 iiii iiii : A-44 */ + else if (((w0 & 0xffc0) == 0x1440) && ((w1 & 0x1f00) == 0x1000)) + { + return global_alloc(BfInstruction(opc, w0, w1)); + } + /* BFTSTH : 0001 0100 001- --RR BBB1 0000 iiii iiii : A-44 */ + else if (((w0 & 0xfff0) == 0x1430) && ((w1 & 0x1f00) == 0x1000)) + // NEW // else if (((w0 & 0xffe0) == 0x1420) && ((w1 & 0x1f00) == 0x1000)) + { + return global_alloc(BfInstruction_2(opc, w0, w1)); + } + /* BFTSTH : 0001 0100 000D DDDD BBB1 0000 iiii iiii : A-44 */ + else if (((w0 & 0xffe0) == 0x1400) && ((w1 & 0x1f00) == 0x1000)) + { + return global_alloc(BfInstruction_3(opc, w0, w1)); + } + /* BFTSTL : 0001 0100 01Pp pppp BBB0 0000 iiii iiii : A-46 */ + else if (((w0 & 0xffc0) == 0x1440) && ((w1 & 0x1f00) == 0x0000)) + { + return global_alloc(BfInstruction(opc, w0, w1)); + } + /* BFTSTL : 0001 0100 001- --RR BBB0 0000 iiii iiii : A-46 */ + else if (((w0 & 0xfff0) == 0x1430) && ((w1 & 0x1f00) == 0x0000)) + // NEW // else if (((w0 & 0xffe0) == 0x1420) && ((w1 & 0x1f00) == 0x0000)) + { + return global_alloc(BfInstruction_2(opc, w0, w1)); + } + /* BFTSTL : 0001 0100 000D DDDD BBB0 0000 iiii iiii : A-46 */ + else if (((w0 & 0xffe0) == 0x1400) && ((w1 & 0x1f00) == 0x0000)) + { + return global_alloc(BfInstruction_3(opc, w0, w1)); + } + /* Bcc : 0000 0111 --11 cccc xxxx xxxx xxxx xxxx : A-48 */ + else if (((w0 & 0xff30) == 0x0730) && ((w1 & 0x0000) == 0x0000)) + { + return global_alloc(Bcc(opc, w0, w1)); + } + /* Bcc : 0010 11cc ccee eeee : A-48 */ + else if ((w0 & 0xfc00) == 0x2c00) + { + return global_alloc(Bcc_2(opc, w0, w1)); + } + /* Bcc : 0000 0111 RR10 cccc : A-48 */ + else if ((w0 & 0xff30) == 0x0720) + { + return global_alloc(Bcc_3(opc, w0, w1)); + } + /* BRA : 0000 0001 0011 11-- xxxx xxxx xxxx xxxx : A-50 */ + else if (((w0 & 0xfffc) == 0x013c) && ((w1 & 0x0000) == 0x0000)) + { + return global_alloc(Bra(opc, w0, w1)); + } + /* BRA : 0000 1011 aaaa aaaa : A-50 */ + else if ((w0 & 0xff00) == 0x0b00) + { + return global_alloc(Bra_2(opc, w0, w1)); + } + /* BRA : 0000 0001 0010 11RR : A-50 */ + else if ((w0 & 0xfffc) == 0x012c) + { + return global_alloc(Bra_3(opc, w0, w1)); + } + /* BRKc : 0000 0001 0001 cccc : A-52 */ + else if ((w0 & 0xfff0) == 0x0110) + { + return global_alloc(Brkcc(opc, w0, w1)); + } + /* BScc : 0000 0111 --01 cccc xxxx xxxx xxxx xxxx : A-54 */ + else if (((w0 & 0xff30) == 0x0710) && ((w1 & 0x0000) == 0x0000)) + { + return global_alloc(Bscc(opc, w0, w1)); + } + /* BScc : 0000 0111 RR00 cccc : A-54 */ + else if ((w0 & 0xff30) == 0x0700) + { + return global_alloc(Bscc_2(opc, w0, w1)); + } + /* BSR : 0000 0001 0011 10-- xxxx xxxx xxxx xxxx : A-56 */ + else if (((w0 & 0xfffc) == 0x0138) && ((w1 & 0x0000) == 0x0000)) + { + return global_alloc(Bsr(opc, w0, w1)); + } + /* BSR : 0000 0001 0010 10RR : A-56 */ + else if ((w0 & 0xfffc) == 0x0128) + { + return global_alloc(Bsr_2(opc, w0, w1)); + } + /* CHKAAU : 0000 0000 0000 0100 : A-58 */ + else if ((w0 & 0xffff) == 0x0004) + { + return global_alloc(Chkaau(opc, w0, w1)); + } + /* DEBUG : 0000 0000 0000 0001 : A-68 */ + else if ((w0 & 0xffff) == 0x0001) + { + return global_alloc(Debug(opc, w0, w1)); + } + /* DEBUGcc : 0000 0000 0101 cccc : A-70 */ + else if ((w0 & 0xfff0) == 0x0050) + { + return global_alloc(Debugcc(opc, w0, w1)); + } + /* DIV : 0001 0101 0--0 F1DD : A-76 */ + else if ((w0 & 0xfff4) == 0x1504) + // NEW // else if ((w0 & 0xff94) == 0x1504) + { + return global_alloc(Div(opc, w0, w1)); + } + /* DMAC : 0001 0101 10s1 FsQQ : A-80 */ + else if ((w0 & 0xffd0) == 0x1590) + { + return global_alloc(Dmac(opc, w0, w1)); + } + /* DO : 0000 0000 110- --RR xxxx xxxx xxxx xxxx : A-82 */ + else if (((w0 & 0xffe0) == 0x00c0) && ((w1 & 0x0000) == 0x0000)) // Wait. Huh? + { + return global_alloc(Do(opc, w0, w1)); + } + /* DO : 0000 1110 iiii iiii xxxx xxxx xxxx xxxx : A-82 */ + else if (((w0 & 0xff00) == 0x0e00) && ((w1 & 0x0000) == 0x0000)) // Wait. Huh? + { + return global_alloc(Do_2(opc, w0, w1)); + } + /* DO : 0000 0100 000D DDDD xxxx xxxx xxxx xxxx : A-82 */ + else if (((w0 & 0xffe0) == 0x0400) && ((w1 & 0x0000) == 0x0000)) // Wait. Huh? + { + return global_alloc(Do_3(opc, w0, w1)); + } + /* DO FOREVER : 0000 0000 0000 0010 xxxx xxxx xxxx xxxx : A-88 */ + else if (((w0 & 0xffff) == 0x0002) && ((w1 & 0x0000) == 0x0000)) // Wait. Huh? + { + return global_alloc(DoForever(opc, w0, w1)); + } + /* ENDDO : 0000 0000 0000 1001 : A-92 */ + else if ((w0 & 0xffff) == 0x0009) + { + return global_alloc(Enddo(opc, w0, w1)); + } + /* EXT : 0001 0101 0101 F010 : A-96 */ + else if ((w0 & 0xfff7) == 0x1552) + { + return global_alloc(Ext(opc, w0, w1)); + } + /* ILLEGAL : 0000 0000 0000 1111 : A-98 */ + else if ((w0 & 0xffff) == 0x000f) + { + return global_alloc(Illegal(opc, w0, w1)); + } + /* IMAC : 0001 0101 1010 FQQQ : A-100 */ + else if ((w0 & 0xfff0) == 0x15a0) + { + return global_alloc(Imac(opc, w0, w1)); + } + /* IMPY : 0001 0101 1000 FQQQ : A-102 */ + else if ((w0 & 0xfff0) == 0x1580) + { + return global_alloc(Impy(opc, w0, w1)); + } + /* Jcc : 0000 0110 --11 cccc xxxx xxxx xxxx xxxx : A-108 */ + else if (((w0 & 0xff30) == 0x0630) && ((w1 & 0x0000) == 0x0000)) + { + return global_alloc(Jcc(opc, w0, w1)); + } + /* Jcc : 0000 0110 RR10 cccc : A-108 */ + else if ((w0 & 0xff30) == 0x0620 ) + { + return global_alloc(Jcc_2(opc, w0, w1)); + } + /* JMP : 0000 0001 0011 01-- xxxx xxxx xxxx xxxx : A-110 */ + else if (((w0 & 0xfffc) == 0x0134) && ((w1 & 0x0000) == 0x0000)) + { + return global_alloc(Jmp(opc, w0, w1)); + } + /* JMP : 0000 0001 0010 01RR : A-110 */ + else if ((w0 & 0xfffc) == 0x0124) + { + //JMP2->m_oco = opc; + //JMP2->decode(w0, w1); + //return JMP2; + return global_alloc(Jmp_2(opc, w0, w1)); + } + /* JScc : 0000 0110 --01 cccc xxxx xxxx xxxx xxxx : A-112 */ + else if (((w0 & 0xff30) == 0x0610) && ((w1 & 0x0000) == 0x0000)) + { + return global_alloc(Jscc(opc, w0, w1)); + } + /* JScc : 0000 0110 RR00 cccc : A-112 */ + else if ((w0 & 0xff30) == 0x0600) + { + return global_alloc(Jscc_2(opc, w0, w1)); + } + /* JSR : 0000 0001 0011 00-- xxxx xxxx xxxx xxxx : A-114 */ + else if (((w0 & 0xfffc) == 0x0130) && ((w1 & 0x0000) == 0x0000)) + { + return global_alloc(Jsr(opc, w0, w1)); + } + /* JSR : 0000 1010 AAAA AAAA : A-114 */ + else if ((w0 & 0xff00) == 0x0a00) + { + return global_alloc(Jsr_2(opc, w0, w1)); + } + /* JSR : 0000 0001 0010 00RR : A-114 */ + else if ((w0 & 0xfffc) == 0x0120) + { + return global_alloc(Jsr_3(opc, w0, w1)); + } + /* LEA : 0000 0001 11TT MMRR : A-116 */ + else if ((w0 & 0xffc0) == 0x01c0) + { + return global_alloc(Lea(opc, w0, w1)); + } + /* LEA : 0000 0001 10NN MMRR : A-116 */ + else if ((w0 & 0xffc0) == 0x0180) + { + return global_alloc(Lea_2(opc, w0, w1)); + } + /* MAC(su,uu) : 0001 0101 1110 FsQQ : A-126 */ + else if ((w0 & 0xfff0) == 0x15e0) + { + return global_alloc(Macsuuu(opc, w0, w1)); + } + /* MOVE : 0000 0101 BBBB BBBB ---- HHHW 0001 0001 : A-128 */ +// NEW // else if (((w0 & 0xff00) == 0x0500) && ((w1 & 0x00ff) == 0x0011)) +// NEW // { +// NEW // return global_alloc(Move_3(opc, w0, w1)); +// NEW // } + /* MOVE(C) : 0011 1WDD DDD0 MMRR : A-144 */ + else if ((w0 & 0xf810) == 0x3800) + { + return global_alloc(Movec(opc, w0, w1)); + } + /* MOVE(C) : 0011 1WDD DDD1 q0RR : A-144 */ + else if ((w0 & 0xf814) == 0x3810) + { + return global_alloc(Movec_2(opc, w0, w1)); + } + /* MOVE(C) : 0011 1WDD DDD1 Z11- : A-144 */ + else if ((w0 & 0xf816) == 0x3816) + { + return global_alloc(Movec_3(opc, w0, w1)); + } + /* MOVE(C) : 0011 1WDD DDD1 t10- xxxx xxxx xxxx xxxx : A-144 */ + else if (((w0 & 0xf816) == 0x3814) && ((w1 & 0x0000) == 0x0000)) + { + return global_alloc(Movec_4(opc, w0, w1)); + } + /* MOVE(C) : 0010 10dd dddD DDDD : A-144 */ + else if ((w0 & 0xfc00) == 0x2800) + { + return global_alloc(Movec_5(opc, w0, w1)); + } + /* MOVE(C) : 0000 0101 BBBB BBBB 0011 1WDD DDD0 ---- : A-144 */ + else if (((w0 & 0xff00) == 0x0500) && ((w1 & 0xf810) == 0x3800)) + { + return global_alloc(Movec_6(opc, w0, w1)); + } + /* MOVE(I) : 0010 00DD BBBB BBBB : A-150 */ + else if ((w0 & 0xfc00) == 0x2000) + { + return global_alloc(Movei(opc, w0, w1)); + } + /* MOVE(M) : 0000 001W RR0M MHHH : A-152 */ + else if ((w0 & 0xfe20) == 0x0200) + { + return global_alloc(Movem(opc, w0, w1)); + } + /* MOVE(M) : 0000 001W RR11 mmRR : A-152 */ + else if ((w0 & 0xfe30) == 0x0230) + { + return global_alloc(Movem_2(opc, w0, w1)); + } + /* MOVE(M) : 0000 0101 BBBB BBBB 0000 001W --0- -HHH : A-152 */ + else if (((w0 & 0xff00) == 0x0500) && ((w1 & 0xfe20) == 0x0200)) + { + return global_alloc(Movem_3(opc, w0, w1)); + } + /* MOVE(P) : 0001 100W HH1p pppp : A-156 */ + else if ((w0 & 0xfe20) == 0x1820) + { + return global_alloc(Movep(opc, w0, w1)); + } + /* MOVE(P) : 0000 110W RRmp pppp : A-156 */ + else if ((w0 & 0xfe00) == 0x0c00) + { + return global_alloc(Movep_2(opc, w0, w1)); + } + /* MOVE(S) : 0001 100W HH0a aaaa : A-158 */ + else if ((w0 & 0xfe20) == 0x1800) + { + return global_alloc(Moves(opc, w0, w1)); + } + /* MPY(su,uu) : 0001 0101 1100 FsQQ : A-164 */ + else if ((w0 & 0xfff0) == 0x15c0) + { + return global_alloc(Mpysuuu(opc, w0, w1)); + } + /* NEGC : 0001 0101 0110 F000 : A-168 */ + else if ((w0 & 0xfff7) == 0x1560) + { + return global_alloc(Negc(opc, w0, w1)); + } + /* NOP : 0000 0000 0000 0000 : A-170 */ + else if ((w0 & 0xffff) == 0x0000) + { + return global_alloc(Nop(opc, w0, w1)); + } + /* NORM : 0001 0101 0010 F0RR : A-172 */ + else if ((w0 & 0xfff4) == 0x1520) + { + return global_alloc(Norm(opc, w0, w1)); + } + /* ORI : 0001 1EE1 iiii iiii : A-178 */ + else if ((w0 & 0xf900) == 0x1900) + { + return global_alloc(Ori(opc, w0, w1)); + } + /* REP : 0000 0000 111- --RR : A-180 */ + else if ((w0 & 0xffe0) == 0x00e0) + { + return global_alloc(Rep(opc, w0, w1)); + } + /* REP : 0000 1111 iiii iiii : A-180 */ + else if ((w0 & 0xff00) == 0x0f00) + { + return global_alloc(Rep_2(opc, w0, w1)); + } + /* REP : 0000 0100 001D DDDD : A-180 */ + else if ((w0 & 0xffe0) == 0x0420) + { + return global_alloc(Rep_3(opc, w0, w1)); + } + /* REPcc : 0000 0001 0101 cccc : A-184 */ + else if ((w0 & 0xfff0) == 0x0150) + { + return global_alloc(Repcc(opc, w0, w1)); + } + /* RESET : 0000 0000 0000 1000 : A-186 */ + else if ((w0 & 0xffff) == 0x0008) + { + return global_alloc(Reset(opc, w0, w1)); + } + /* RTI : 0000 0000 0000 0111 : A-194 */ + else if ((w0 & 0xffff) == 0x0007) + { + return global_alloc(Rti(opc, w0, w1)); + } + /* RTS : 0000 0000 0000 0110 : A-196 */ + else if ((w0 & 0xffff) == 0x0006) + { + return global_alloc(Rts(opc, w0, w1)); + } + /* STOP : 0000 0000 0000 1010 : A-200 */ + else if ((w0 & 0xffff) == 0x000a) + { + return global_alloc(Stop(opc, w0, w1)); + } + /* SWAP : 0001 0101 0111 F001 : A-206 */ + else if ((w0 & 0xfff7) == 0x1571) + { + return global_alloc(Swap(opc, w0, w1)); + } + /* SWI : 0000 0000 0000 0101 : A-208 */ + else if ((w0 & 0xffff) == 0x0005) + { + return global_alloc(Swi(opc, w0, w1)); + } + /* Tcc : 0001 00cc ccTT Fh0h : A-210 */ + else if ((w0 & 0xfc02) == 0x1000) + { + return global_alloc(Tcc(opc, w0, w1)); + } + /* TFR(2) : 0001 0101 0000 F00J : A-214 */ + else if ((w0 & 0xfff6) == 0x1500) + { + return global_alloc(Tfr2(opc, w0, w1)); + } + /* TFR(3) : 0010 01mW RRDD FHHH : A-216 */ + else if ((w0 & 0xfc00) == 0x2400) + { + return global_alloc(Tfr3(opc, w0, w1)); + } + /* TST(2) : 0001 0101 0001 -1DD : A-220 */ + else if ((w0 & 0xfffc) == 0x1514) + // NEW // else if ((w0 & 0xfff4) == 0x1514) + { + return global_alloc(Tst2(opc, w0, w1)); + } + /* WAIT : 0000 0000 0000 1011 : A-222 */ + else if ((w0 & 0xffff) == 0x000b) + { + return global_alloc(Wait(opc, w0, w1)); + } + /* ZERO : 0001 0101 0101 F000 : A-224 */ + else if ((w0 & 0xfff7) == 0x1550) + { + return global_alloc(Zero(opc, w0, w1)); + } + /* SHFL : 0001 0101 1101 FQQQ : !!UNDOCUMENTED!! */ + else if ((w0 & 0xfff0) == 0x15d0) + { + return global_alloc(Shfl(opc, w0, w1)); + } + /* SHFR : 0001 0101 1111 FQQQ : !!UNDOCUMENTED!! */ + else if ((w0 & 0xfff0) == 0x15f0) + { + return global_alloc(Shfr(opc, w0, w1)); + } + + return NULL; +} + +} diff --git a/src/devices/cpu/dsp56k/inst.h b/src/devices/cpu/dsp56k/inst.h new file mode 100644 index 00000000000..b83508a7df2 --- /dev/null +++ b/src/devices/cpu/dsp56k/inst.h @@ -0,0 +1,3777 @@ +// license:BSD-3-Clause +// copyright-holders:Andrew Gardner +#ifndef __DSP56K_INSTRUCTION_H__ +#define __DSP56K_INSTRUCTION_H__ + +#include "opcode.h" +#include "tables.h" + +#include "dsp56k.h" +#include "dsp56def.h" +#include "dsp56pcu.h" + +// +// An Instruction is the base class all regular ops inherit from. +// +namespace DSP56K +{ +#define ADDRESS(X) ((X)<<1) +#define UNIMPLEMENTED_OPCODE() osd_printf_error("Unimplemented opcode: PC=%04x | %s;\n", PC, __PRETTY_FUNCTION__); + +class Opcode; + +class Instruction +{ +public: + Instruction(const Opcode* oco) : m_valid(false), + m_oco(oco), + m_sizeIncrement(0), + m_source(iINVALID), + m_destination(iINVALID) { } + virtual ~Instruction() {} + + virtual bool decode(const UINT16 word0, const UINT16 word1) = 0; + virtual void disassemble(std::string& retString) const = 0; + virtual void evaluate(dsp56k_core* cpustate) = 0; + + virtual size_t size() const = 0; + virtual size_t evalSize() const { return size(); } + virtual size_t accumulatorBitsModified() const = 0; // Potentially make this always return ALL (like flags) + virtual size_t flags() const { return 0; } + + static Instruction* decodeInstruction(const Opcode* opc, + const UINT16 word0, + const UINT16 word1, + bool shifted=false); + + bool valid() const { return m_valid; } + + const reg_id& source() const { return m_source; } + const reg_id& destination() const { return m_destination; } + + size_t sizeIncrement() const { return m_sizeIncrement; } + +protected: + bool m_valid; + const Opcode* m_oco; + size_t m_sizeIncrement; + + // Parameters nearly everyone has + reg_id m_source; + reg_id m_destination; +}; + + +//////////////////////////////////////////////////////////////////////////////// +// OPS //////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// + +// ABS : .... .... 0111 F001 : A-18 //////////////////////////////////////////// +class Abs: public Instruction +{ +public: + Abs(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + decode_F_table(BITSn(word0,0x08), m_destination); + return true; + } + void disassemble(std::string& retString) const + { + retString = "abs " + regIdAsString(m_destination); + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 1; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } +}; + +// ADC : 0001 0101 0000 F01J : A-20 //////////////////////////////////////////// +class Adc: public Instruction +{ +public: + Adc(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + decode_JF_table(BITSn(word0,0x0001), BITSn(word0,0x0008), + m_source, m_destination); + return true; + } + void disassemble(std::string& retString) const + { + retString = "adc " + regIdAsString(m_source) + "," + regIdAsString(m_destination); + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 1; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } +}; + +// ADD : .... .... 0000 FJJJ : A-22 //////////////////////////////////////////// +class Add: public Instruction +{ +public: + Add(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + decode_JJJF_table(BITSn(word0,0x07), BITSn(word0,0x08), + m_source, m_destination); + return true; + } + void disassemble(std::string& retString) const + { + retString = "add " + regIdAsString(m_source) + "," + regIdAsString(m_destination); + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 1; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } +}; + +// ??? Odd that i should put the 011m mKKK everywhere ??? TODO +// ADD : 011m mKKK 0rru Fuuu : A-22 //////////////////////////////////////////// +class Add_2: public Instruction +{ +public: + Add_2(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_arg = ""; + m_opcode = ""; + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + decode_uuuuF_table(BITSn(word0,0x17), BITSn(word0,0x08), + m_opcode, m_source, m_destination); + // TODO: m_opcode = "add"; + return true; + } + void disassemble(std::string& retString) const + { + retString = m_opcode + " " + regIdAsString(m_source) + "," + regIdAsString(m_destination); + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 1; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } + +private: + std::string m_opcode; + std::string m_arg; // TODO: get rid of this Add|Sub thing. +}; + +// AND : .... .... 0110 F1JJ : A-24 //////////////////////////////////////////// +class And: public Instruction +{ +public: + And(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + decode_JJF_table(BITSn(word0,0x03),BITSn(word0,0x08), + m_source, m_destination); + return true; + } + void disassemble(std::string& retString) const + { + retString = "and " + regIdAsString(m_source) + "," + regIdAsString(m_destination); + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 1; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE; } +}; + +// ANDI : 0001 1EE0 iiii iiii : A-26 /////////////////////////////////////////// +class Andi: public Instruction +{ +public: + Andi(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_immediate = 0; + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + m_immediate = BITSn(word0,0x00ff); + decode_EE_table(BITSn(word0,0x0600), m_destination); + return true; + } + void disassemble(std::string& retString) const + { + char temp[32]; + sprintf(temp, "#$%x,%s", m_immediate, regIdAsString(m_destination).c_str()); + retString = "andi " + std::string(temp); + // NEW // sprintf(opcode_str, "and(i)"); + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 1; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } + +private: + UINT8 m_immediate; +}; + +// ASL : .... .... 0011 F001 : A-28 //////////////////////////////////////////// +class Asl: public Instruction +{ +public: + Asl(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + decode_F_table(BITSn(word0,0x08), m_destination); + return true; + } + void disassemble(std::string& retString) const + { + retString = "asl " + regIdAsString(m_destination); + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 1; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } +}; + +// ASL4 : 0001 0101 0011 F001 : A-30 /////////////////////////////////////////// +class Asl4: public Instruction +{ +public: + Asl4(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + decode_F_table(BITSn(word0,0x0008), m_destination); + return true; + } + void disassemble(std::string& retString) const + { + retString = "asl4 " + regIdAsString(m_destination); + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 1; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } +}; + +// ASR : .... .... 0011 F000 : A-32 //////////////////////////////////////////// +class Asr: public Instruction +{ +public: + Asr(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + decode_F_table(BITSn(word0,0x08), m_destination); + return true; + } + void disassemble(std::string& retString) const + { + retString = "asr " + regIdAsString(m_destination); + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 1; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } +}; + +// ASR4 : 0001 0101 0011 F000 : A-34 /////////////////////////////////////////// +class Asr4: public Instruction +{ +public: + Asr4(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + decode_F_table(BITSn(word0,0x0008), m_destination); + return true; + } + void disassemble(std::string& retString) const + { + retString = "asr4 " + regIdAsString(m_destination); + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 1; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } +}; + +// ASR16 : 0001 0101 0111 F000 : A-36 ////////////////////////////////////////// +class Asr16: public Instruction +{ +public: + Asr16(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + decode_F_table(BITSn(word0,0x0008), m_destination); + return true; + } + void disassemble(std::string& retString) const + { + retString = "asr16 " + regIdAsString(m_destination); + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 1; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } +}; + +/* BFCHG : 0001 0100 11Pp pppp BBB1 0010 iiii iiii : A-38 */ +/* BFCLR : 0001 0100 11Pp pppp BBB0 0100 iiii iiii : A-40 */ +/* BFSET : 0001 0100 11Pp pppp BBB1 1000 iiii iiii : A-42 */ +/* BFTSTH : 0001 0100 01Pp pppp BBB1 0000 iiii iiii : A-44 */ +/* BFTSTL : 0001 0100 01Pp pppp BBB0 0000 iiii iiii : A-46 */ +class BfInstruction: public Instruction +{ +public: + BfInstruction(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + dString = ""; + m_opcode = ""; + m_iVal = 0x0000; + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + /* Decode the common parts */ + m_iVal = BITSn(word1,0x00ff); + + bfShift upperMiddleLower = decode_BBB_table(BITSn(word1,0xe000)); + switch(upperMiddleLower) + { + case BBB_UPPER: m_iVal <<= 8; break; + case BBB_MIDDLE: m_iVal <<= 4; break; + case BBB_LOWER: m_iVal <<= 0; break; + + case BBB_INVALID: return false; + } + + assemble_D_from_P_table(BITSn(word0,0x0020), BITSn(word0,0x001f), dString); + + if (dString.compare("!!") == 0) + return false; + + switch(BITSn(word1,0x1f00)) + { + case 0x12: m_opcode = "bfchg"; break; + case 0x04: m_opcode = "bfclr"; break; + case 0x18: m_opcode = "bfset"; break; + case 0x10: m_opcode = "bftsth"; break; + case 0x00: m_opcode = "bftstl"; break; + } + return true; + } + void disassemble(std::string& retString) const + { + char temp[32]; + sprintf(temp, "#$%x", m_iVal); + retString = m_opcode + " " + std::string(temp) + "," + dString; + // NEW // sprintf(temp, "#$%04x", iVal); + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 2; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } +private: + UINT16 m_iVal; + std::string m_opcode; + std::string dString; +}; + +/* BFCHG : 0001 0100 101- --RR BBB1 0010 iiii iiii : A-38 */ +/* BFCLR : 0001 0100 101- --RR BBB0 0100 iiii iiii : A-40 */ +/* BFSET : 0001 0100 101- --RR BBB1 1000 iiii iiii : A-42 */ +/* BFTSTH : 0001 0100 001- --RR BBB1 0000 iiii iiii : A-44 */ +/* BFTSTL : 0001 0100 001- --RR BBB0 0000 iiii iiii : A-46 */ +class BfInstruction_2: public Instruction +{ +public: + BfInstruction_2(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_opcode = ""; + m_r = iINVALID; + m_iVal = 0x0000; + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + /* Decode the common parts */ + m_iVal = BITSn(word1,0x00ff); + + bfShift upperMiddleLower = decode_BBB_table(BITSn(word1,0xe000)); + switch(upperMiddleLower) + { + case BBB_UPPER: m_iVal <<= 8; break; + case BBB_MIDDLE: m_iVal <<= 4; break; + case BBB_LOWER: m_iVal <<= 0; break; + + case BBB_INVALID: return false; + } + + decode_RR_table(BITSn(word0,0x0003), m_r); + + if (m_r == iINVALID) + return false; + + switch(BITSn(word1,0x1f00)) + { + case 0x12: m_opcode = "bfchg"; break; + case 0x04: m_opcode = "bfclr"; break; + case 0x18: m_opcode = "bfset"; break; + case 0x10: m_opcode = "bftsth"; break; + case 0x00: m_opcode = "bftstl"; break; + } + return true; + } + void disassemble(std::string& retString) const + { + char temp[32]; + sprintf(temp, "#$%x", m_iVal); + std::string source = temp; + + sprintf(temp, "X:(%s)", regIdAsString(m_r).c_str()); + std::string destination = temp; + + retString = m_opcode + " " + source + "," + destination; + // NEW // sprintf(temp, "#$%04x", m_iVal); + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 2; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } + +private: + reg_id m_r; + UINT16 m_iVal; + std::string m_opcode; +}; + +/* BFCHG : 0001 0100 100D DDDD BBB1 0010 iiii iiii : A-38 */ +/* BFCLR : 0001 0100 100D DDDD BBB0 0100 iiii iiii : A-40 */ +/* BFSET : 0001 0100 100D DDDD BBB1 1000 iiii iiii : A-42 */ +/* BFTSTH : 0001 0100 000D DDDD BBB1 0000 iiii iiii : A-44 */ +/* BFTSTL : 0001 0100 000D DDDD BBB0 0000 iiii iiii : A-46 */ +class BfInstruction_3: public Instruction +{ +public: + BfInstruction_3(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_opcode = ""; + m_iVal = 0x0000; + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + /* Decode the common parts */ + m_iVal = BITSn(word1,0x00ff); + + bfShift upperMiddleLower = decode_BBB_table(BITSn(word1,0xe000)); + switch(upperMiddleLower) + { + case BBB_UPPER: m_iVal <<= 8; break; + case BBB_MIDDLE: m_iVal <<= 4; break; + case BBB_LOWER: m_iVal <<= 0; break; + + case BBB_INVALID: return false; + } + + decode_DDDDD_table(BITSn(word0,0x001f), m_destination); + + if (m_destination == iINVALID) + return false; + + switch(BITSn(word1,0x1f00)) + { + case 0x12: m_opcode = "bfchg"; break; + case 0x04: m_opcode = "bfclr"; break; + case 0x18: m_opcode = "bfset"; break; + case 0x10: m_opcode = "bftsth"; break; + case 0x00: m_opcode = "bftstl"; break; + } + return true; + } + void disassemble(std::string& retString) const + { + char temp[32]; + sprintf(temp, "#$%x", m_iVal); + std::string source = temp; + + retString = m_opcode + " " + source + "," + regIdAsString(m_destination); + // NEW // sprintf(temp, "#$%04x", m_iVal); + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 2; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } + +private: + UINT16 m_iVal; + std::string m_opcode; +}; + +// Bcc : 0000 0111 --11 cccc xxxx xxxx xxxx xxxx : A-48 //////////////////////// +class Bcc: public Instruction +{ +public: + Bcc(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_mnem = oINVALID; + m_immediate = 0; + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + m_immediate = (INT16)word1; + decode_cccc_table(BITSn(word0,0x000f), m_mnem); + return true; + } + void disassemble(std::string& retString) const + { + std::string opcode = "b" + opMnemonicAsString(m_mnem); + // NEW // sprintf(opcode_str, "b.%s", M); + + char temp[32]; + sprintf(temp, ">*+$%x", 2 + m_immediate); + // NEW // sprintf(temp, "$%04x (%d)", pc + 2 + (INT16)word1, (INT16)word1); + retString = opcode + " " + std::string(temp); + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 2; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } + +private: + op_mnem m_mnem; + INT16 m_immediate; +}; + +// Bcc : 0010 11cc ccee eeee : A-48 //////////////////////////////////////////// +class Bcc_2: public Instruction +{ +public: + Bcc_2(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_immediate = 0; + m_mnem = oINVALID; + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + decode_cccc_table(BITSn(word0,0x3c0), m_mnem); + m_immediate = get_6_bit_signed_value(BITSn(word0,0x003f)); + return true; + } + void disassemble(std::string& retString) const + { + std::string opcode = "b" + opMnemonicAsString(m_mnem); + // NEW // sprintf(opcode_str, "b.%s", M); + + char temp[32]; + if (m_immediate >= 0) sprintf(temp, "<*+$%x", m_immediate + 1); + else sprintf(temp, "<*-$%x", 1 - m_immediate - 2); + // NEW // sprintf(temp, "$%04x (%d)", pc + 1 + relativeInt, relativeInt); + + retString = opcode + " " + std::string(temp); + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 1; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } + +private: + op_mnem m_mnem; + INT8 m_immediate; +}; + +// Bcc : 0000 0111 RR10 cccc : A-48 //////////////////////////////////////////// +class Bcc_3: public Instruction +{ +public: + Bcc_3(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_mnem = oINVALID; + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + decode_RR_table(BITSn(word0,0x00c0), m_destination); + decode_cccc_table(BITSn(word0,0x000f), m_mnem); + return true; + } + void disassemble(std::string& retString) const + { + std::string opcode = "b" + opMnemonicAsString(m_mnem); + retString = opcode + " " + regIdAsString(m_destination); + // NEW // sprintf(opcode_str, "b.%s", M); + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 1; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } + +private: + op_mnem m_mnem; +}; + +// BRA : 0000 0001 0011 11-- xxxx xxxx xxxx xxxx : A-50 //////////////////////// +class Bra: public Instruction +{ +public: + Bra(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_immediate = 0; + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + m_immediate = (INT16)word1; + return true; + } + void disassemble(std::string& retString) const + { + char temp[32]; + sprintf(temp, ">*+$%x", 2 + m_immediate); + // NEW // sprintf(temp, "$%04x (%d)", pc + 2 + word1, (INT16)word1); + retString = "bra " + std::string(temp); + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 2; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } + +private: + INT16 m_immediate; +}; + +// BRA : 0000 1011 aaaa aaaa : A-50 //////////////////////////////////////////// +class Bra_2: public Instruction +{ +public: + Bra_2(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_immediate = 0; + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + m_immediate = (INT8)BITSn(word0,0x00ff); + return true; + } + void disassemble(std::string& retString) const + { + char temp[32]; + if (m_immediate >= 0) sprintf(temp, "<*+$%x", 1 + m_immediate); + else sprintf(temp, "<*-$%x", 1 - m_immediate - 2); + // NEW // sprintf(temp, "$%04x (%d)", pc + 1 + iVal, iVal); + retString = "bra " + std::string(temp); + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 1; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } + +private: + INT8 m_immediate; +}; + +// BRA : 0000 0001 0010 11RR : A-50 //////////////////////////////////////////// +class Bra_3: public Instruction +{ +public: + Bra_3(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + decode_RR_table(BITSn(word0,0x0003), m_destination); + return true; + } + void disassemble(std::string& retString) const + { + retString = "bra " + regIdAsString(m_destination); + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 1; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } +}; + +// BRKcc : 0000 0001 0001 cccc : A-52 ////////////////////////////////////////// +class Brkcc: public Instruction +{ +public: + Brkcc(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_mnem = oINVALID; + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + decode_cccc_table(BITSn(word0,0x000f), m_mnem); + return true; + } + void disassemble(std::string& retString) const + { + std::string opcode = "brk" + opMnemonicAsString(m_mnem); + retString = opcode; + // NEW // sprintf(opcode_str, "brk.%s", M); + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 1; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } + +private: + op_mnem m_mnem; +}; + +// BScc : 0000 0111 --01 cccc xxxx xxxx xxxx xxxx : A-54 /////////////////////// +class Bscc: public Instruction +{ +public: + Bscc(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_immediate = 0; + m_mnem = oINVALID; + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + m_immediate = (INT16)word1; + decode_cccc_table(BITSn(word0,0x000f), m_mnem); + return true; + } + void disassemble(std::string& retString) const + { + std::string opcode = "bs" + opMnemonicAsString(m_mnem); + // NEW // sprintf(opcode_str, "bs.%s", M); + + char temp[32]; + if (m_immediate >= 0) sprintf(temp, ">*+$%x", 2 + m_immediate); + else sprintf(temp, ">*-$%x", 1 - m_immediate - 1 - 2); + //sprintf(temp, ">*+$%x", 2 + m_immediate); + // NEW // sprintf(temp, "$%04x (%d)", pc + 2 + (INT16)word1, (INT16)word1); + retString = opcode + " " + std::string(temp); + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 2; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } + size_t flags() const { return DASMFLAG_STEP_OVER; } + +private: + op_mnem m_mnem; + INT16 m_immediate; +}; + +// BScc : 0000 0111 RR00 cccc : A-54 /////////////////////////////////////////// +class Bscc_2: public Instruction +{ +public: + Bscc_2(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_mnem = oINVALID; + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + decode_RR_table(BITSn(word0,0x00c0), m_destination); + decode_cccc_table(BITSn(word0,0x000f), m_mnem); + return true; + } + void disassemble(std::string& retString) const + { + std::string opcode = "bs" + opMnemonicAsString(m_mnem); + retString = opcode + " " + regIdAsString(m_destination); + // NEW // sprintf(opcode_str, "bs.%s", M); + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 1; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } + size_t flags() const { return DASMFLAG_STEP_OVER; } + +private: + op_mnem m_mnem; +}; + +// BSR : 0000 0001 0011 10-- xxxx xxxx xxxx xxxx : A-56 //////////////////////// +class Bsr: public Instruction +{ +public: + Bsr(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_immediate = 0; + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + m_immediate = (INT16)word1; + return true; + } + void disassemble(std::string& retString) const + { + char temp[32]; + if (m_immediate >= 0) sprintf(temp, ">*+$%x", 2 + m_immediate); + else sprintf(temp, ">*-$%x", 1 - m_immediate - 1 - 2); + // NEW // sprintf(temp, "$%04x (%d)", pc + 2 + (INT16)word1, (INT16)word1); + retString = "bsr " + std::string(temp); + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 2; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } + size_t flags() const { return DASMFLAG_STEP_OVER; } + +private: + INT16 m_immediate; +}; + +// BSR : 0000 0001 0010 10RR : A-56 //////////////////////////////////////////// +class Bsr_2: public Instruction +{ +public: + Bsr_2(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + decode_RR_table(BITSn(word0,0x0003), m_destination); + return true; + } + void disassemble(std::string& retString) const + { + retString = "bsr " + regIdAsString(m_destination); + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 1; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } + size_t flags() const { return DASMFLAG_STEP_OVER; } +}; + +// CHKAAU : 0000 0000 0000 0100 : A-58 ///////////////////////////////////////// +class Chkaau: public Instruction +{ +public: + Chkaau(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + return true; + } + void disassemble(std::string& retString) const + { + retString = "chkaau"; + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 1; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } +}; + +// CLR : .... .... 0000 F001 : A-60 //////////////////////////////////////////// +class Clr: public Instruction +{ +public: + Clr(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + decode_F_table(BITSn(word0,0x08), m_destination); + return true; + } + void disassemble(std::string& retString) const + { + retString = "clr " + regIdAsString(m_destination); + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 1; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } +}; + +// CLR24 : .... .... 0101 F001 : A-62 ////////////////////////////////////////// +class Clr24: public Instruction +{ +public: + Clr24(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + decode_F_table(BITSn(word0,0x08), m_destination); + return true; + } + void disassemble(std::string& retString) const + { + retString = "clr24 " + regIdAsString(m_destination); + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 1; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE; } +}; + +// CMP : .... .... 0101 FJJJ : A-64 //////////////////////////////////////////// +class Cmp: public Instruction +{ +public: + Cmp(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + /* Note: This is a JJJF limited in the docs, but other opcodes sneak + in before cmp, so the same decode function can be used. */ + decode_JJJF_table(BITSn(word0,0x07), BITSn(word0,0x08), + m_source, m_destination); + return true; + } + void disassemble(std::string& retString) const + { + retString = "cmp " + regIdAsString(m_source) + "," + regIdAsString(m_destination); + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 1; } + size_t accumulatorBitsModified() const { return BM_NONE; } +}; + +// CMPM : .... .... 0111 FJJJ : A-66 /////////////////////////////////////////// +class Cmpm: public Instruction +{ +public: + Cmpm(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + /* Note: This is a JJJF limited in the docs, but other opcodes sneak + in before cmp, so the same decode function can be used. */ + decode_JJJF_table(BITSn(word0,0x07), BITSn(word0,0x08), + m_source, m_destination); + return true; + } + void disassemble(std::string& retString) const + { + retString = "cmpm " + regIdAsString(m_source) + "," + regIdAsString(m_destination); + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 1; } + size_t accumulatorBitsModified() const { return BM_NONE; } +}; + +// DEBUG : 0000 0000 0000 0001 : A-68 ////////////////////////////////////////// +class Debug: public Instruction +{ +public: + Debug(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + return true; + } + void disassemble(std::string& retString) const + { + retString = "debug"; + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 1; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } +}; + +// DEBUGcc : 0000 0000 0101 cccc : A-70 //////////////////////////////////////// +class Debugcc: public Instruction +{ +public: + Debugcc(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_mnem = oINVALID; + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + decode_cccc_table(BITSn(word0,0x000f), m_mnem); + return true; + } + void disassemble(std::string& retString) const + { + std::string opcode = "debug" + opMnemonicAsString(m_mnem); + retString = opcode; + // NEW // sprintf(opcode_str, "debug.%s", M); + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 1; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } + +private: + op_mnem m_mnem; +}; + +// DEC : .... .... 0110 F010 : A-72 //////////////////////////////////////////// +class Dec: public Instruction +{ +public: + Dec(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + decode_F_table(BITSn(word0,0x08), m_destination); + return true; + } + void disassemble(std::string& retString) const + { + retString = "dec " + regIdAsString(m_destination); + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 1; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } +}; + +// DEC24 : .... .... 0110 F011 : A-74 ////////////////////////////////////////// +class Dec24: public Instruction +{ +public: + Dec24(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + decode_F_table(BITSn(word0,0x08), m_destination); + return true; + } + void disassemble(std::string& retString) const + { + retString = "dec24 " + regIdAsString(m_destination); + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 1; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE; } +}; + +// DIV : 0001 0101 0--0 F1DD : A-76 //////////////////////////////////////////// +class Div: public Instruction +{ +public: + Div(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + decode_DDF_table(BITSn(word0,0x0003), BITSn(word0,0x0008), + m_source, m_destination); + return true; + } + void disassemble(std::string& retString) const + { + retString = "div " + regIdAsString(m_source) + "," + regIdAsString(m_destination); + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 1; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } +}; + +// DMAC : 0001 0101 10s1 FsQQ : A-80 /////////////////////////////////////////// +class Dmac: public Instruction +{ +public: + Dmac(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_mnem = oINVALID; + m_source2 = iINVALID; + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + decode_QQF_special_table(BITSn(word0,0x0003), BITSn(word0,0x0008), + m_source, m_source2, m_destination); + + decode_ss_table(BITSn(word0,0x0024), m_mnem); + if (m_mnem == oINVALID) return false; + return true; + } + void disassemble(std::string& retString) const + { + std::string opcode = "dmac" + opMnemonicAsString(m_mnem); + + retString = opcode + " " + + regIdAsString(m_source) + "," + + regIdAsString(m_source2) + "," + regIdAsString(m_destination); + // NEW // sprintf(opcode_str, "dmac(%s)", A); + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 1; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } + +private: + op_mnem m_mnem; + reg_id m_source2; +}; + +// DO : 0000 0000 110- --RR xxxx xxxx xxxx xxxx : A-82 ///////////////////////// +class Do: public Instruction +{ +public: + Do(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_immediate = 0; + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + m_immediate = word1; + decode_RR_table(BITSn(word0,0x0003), m_source); + return true; + } + void disassemble(std::string& retString) const + { + char temp[32]; + sprintf(temp, "*+$%x", 2 + m_immediate); + std::string destination = temp; + // NEW // sprintf(temp, "X:(R%d),$%02x", Rnum, pc + 2 + word1); + + sprintf(temp, "X:(%s)", regIdAsString(m_source).c_str()); + std::string source = temp; + + retString = "do " + source + "," + destination; + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 2; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } + +private: + UINT16 m_immediate; +}; + +// DO : 0000 1110 iiii iiii xxxx xxxx xxxx xxxx : A-82 ///////////////////////// +class Do_2: public Instruction +{ +public: + Do_2(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_immediate = 0; + m_displacement = 0; + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + m_immediate = BITSn(word0,0x00ff); + m_displacement = word1; + return true; + } + void disassemble(std::string& retString) const + { + char temp[32]; + sprintf(temp, "#<$%x,*+$%x", m_immediate, 2 + m_displacement); + // NEW // sprintf(temp, "#$%02x,$%04x", BITSn(word0,0x00ff), pc + 2 + word1); + retString = "do " + std::string(temp); + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 2; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } + +private: + UINT8 m_immediate; + UINT16 m_displacement; +}; + +// DO : 0000 0100 000D DDDD xxxx xxxx xxxx xxxx : A-82 ///////////////////////// +class Do_3: public Instruction +{ +public: + Do_3(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_displacement = 0; + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + m_displacement = word1; + + decode_DDDDD_table(BITSn(word0,0x001f), m_source); + if (m_source == iSSH) return false; + if (m_source == iINVALID) return false; + return true; + } + void disassemble(std::string& retString) const + { + char temp[32]; + sprintf(temp, "*+$%x", 2 + m_displacement); + // NEW // sprintf(temp, "%s,$%04x", S1, pc + 2 + word1); + retString = "do " + regIdAsString(m_source) + "," + std::string(temp); + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 2; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } + +private: + UINT16 m_displacement; +}; + +// DO FOREVER : 0000 0000 0000 0010 xxxx xxxx xxxx xxxx : A-88 ///////////////// +class DoForever: public Instruction +{ +public: + DoForever(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_displacement = 0; + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + m_displacement = word1; + return true; + } + void disassemble(std::string& retString) const + { + char temp[32]; + sprintf(temp, "*+$%x", m_displacement + 2); + // NEW // sprintf(temp, "*+$%x", pc + word1); + // NEW // sprintf(temp, "$%04x", pc + 2 + word1); + retString = "do forever, " + std::string(temp); + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 2; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } + +private: + UINT16 m_displacement; +}; + +// ENDDO : 0000 0000 0000 1001 : A-92 ////////////////////////////////////////// +class Enddo: public Instruction +{ +public: + Enddo(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + return true; + } + void disassemble(std::string& retString) const + { + retString = "enddo"; + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 1; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } +}; + +// EOR : .... .... 0011 F1JJ : A-94 //////////////////////////////////////////// +class Eor: public Instruction +{ +public: + Eor(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + decode_JJF_table(BITSn(word0,0x03),BITSn(word0,0x08), + m_source, m_destination); + return true; + } + void disassemble(std::string& retString) const + { + retString = "eor " + regIdAsString(m_source) + "," + regIdAsString(m_destination); + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 1; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE; } +}; + +// EXT : 0001 0101 0101 F010 : A-96 //////////////////////////////////////////// +class Ext: public Instruction +{ +public: + Ext(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + decode_F_table(BITSn(word0,0x0008), m_destination); + return true; + } + void disassemble(std::string& retString) const + { + retString = "ext " + regIdAsString(m_destination); + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 1; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } +}; + +// ILLEGAL : 0000 0000 0000 1111 : A-98 //////////////////////////////////////// +class Illegal: public Instruction +{ +public: + Illegal(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + return true; + } + void disassemble(std::string& retString) const + { + retString = "illegal"; + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 1; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } +}; + +// IMAC : 0001 0101 1010 FQQQ : A-100 ////////////////////////////////////////// +class Imac: public Instruction +{ +public: + Imac(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_source2 = iINVALID; + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + decode_QQQF_table(BITSn(word0,0x0007), BITSn(word0,0x0008), + m_source, m_source2, m_destination); + return true; + } + void disassemble(std::string& retString) const + { + retString = "imac " + + regIdAsString(m_source) + "," + + regIdAsString(m_source2) + "," + regIdAsString(m_destination); + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 1; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } + +private: + reg_id m_source2; +}; + +// IMPY : 0001 0101 1000 FQQQ : A-102 ////////////////////////////////////////// +class Impy: public Instruction +{ +public: + Impy(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_source2 = iINVALID; + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + decode_QQQF_table(BITSn(word0,0x0007), BITSn(word0,0x0008), + m_source, m_source2, m_destination); + return true; + } + void disassemble(std::string& retString) const + { + retString = "impy " + + regIdAsString(m_source) + "," + + regIdAsString(m_source2) + "," + regIdAsString(m_destination); + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 1; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } + +private: + reg_id m_source2; +}; + +// INC : .... .... 0010 F010 : A-104 /////////////////////////////////////////// +class Inc: public Instruction +{ +public: + Inc(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + decode_F_table(BITSn(word0,0x08), m_destination); + return true; + } + void disassemble(std::string& retString) const + { + retString = "inc " + regIdAsString(m_destination); + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 1; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } +}; + +// INC24 : .... .... 0010 F011 : A-106 ///////////////////////////////////////// +class Inc24: public Instruction +{ +public: + Inc24(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + decode_F_table(BITSn(word0,0x08), m_destination); + return true; + } + void disassemble(std::string& retString) const + { + retString = "inc24 " + regIdAsString(m_destination); + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 1; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE; } +}; + +// Jcc : 0000 0110 --11 cccc xxxx xxxx xxxx xxxx : A-108 /////////////////////// +class Jcc: public Instruction +{ +public: + Jcc(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_mnem = oINVALID; + m_displacement = 0; + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + m_displacement = word1; + decode_cccc_table(BITSn(word0,0x000f), m_mnem); + return true; + } + void disassemble(std::string& retString) const + { + std::string opcode = "j" + opMnemonicAsString(m_mnem); + // NEW // sprintf(opcode_str, "j.%s", M); + + char temp[32]; + sprintf(temp, ">$%x", m_displacement); + // NEW // sprintf(temp, "$%04x", word1); + retString = opcode + " " + std::string(temp); + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 2; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } + +private: + op_mnem m_mnem; + UINT16 m_displacement; +}; + +// Jcc : 0000 0110 RR10 cccc : A-108 /////////////////////////////////////////// +class Jcc_2: public Instruction +{ +public: + Jcc_2(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_mnem = oINVALID; + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + decode_RR_table(BITSn(word0,0x00c0), m_destination); + decode_cccc_table(BITSn(word0,0x000f), m_mnem); + return true; + } + void disassemble(std::string& retString) const + { + std::string opcode = "j" + opMnemonicAsString(m_mnem); + retString = opcode + " " + regIdAsString(m_destination); + // NEW // sprintf(opcode_str, "j.%s", M); + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 1; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } + +private: + op_mnem m_mnem; +}; + +// JMP : 0000 0001 0011 01-- xxxx xxxx xxxx xxxx : A-110 /////////////////////// +class Jmp: public Instruction +{ +public: + Jmp(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_displacement = 0; + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + m_displacement = word1; + return true; + } + void disassemble(std::string& retString) const + { + char temp[32]; + sprintf(temp, ">$%x", m_displacement); + // NEW // sprintf(temp, "$%04x", word1); + retString = "jmp " + std::string(temp); + } + void evaluate(dsp56k_core* cpustate) + { + cpustate->ppc = PC; + PC = m_displacement; + + /* S L E U N Z V C */ + /* - - - - - - - - */ + } + size_t size() const { return 2; } + size_t evalSize() const { return 0; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } + +private: + UINT16 m_displacement; +}; + +// JMP : 0000 0001 0010 01RR : A-110 /////////////////////////////////////////// +class Jmp_2: public Instruction +{ +public: + Jmp_2(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + decode_RR_table(BITSn(word0,0x0003), m_destination); + return true; + } + void disassemble(std::string& retString) const + { + retString = "jmp " + regIdAsString(m_destination); + } + void evaluate(dsp56k_core* cpustate) + { + cpustate->ppc = PC; + PC = regValue16(cpustate, m_destination); + + /* S L E U N Z V C */ + /* - - - - - - - - */ + } + size_t size() const { return 1; } + size_t evalSize() const { return 0; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } +}; + +//static Jmp_2* JMP2 = new Jmp_2(NULL, 0x0000, 0x0000); + +// JScc : 0000 0110 --01 cccc xxxx xxxx xxxx xxxx : A-112 ////////////////////// +class Jscc: public Instruction +{ +public: + Jscc(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_mnem = oINVALID; + m_displacement = 0; + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + m_displacement = word1; + decode_cccc_table(BITSn(word0,0x000f), m_mnem); + return true; + } + void disassemble(std::string& retString) const + { + std::string opcode = "js" + opMnemonicAsString(m_mnem); + // NEW // sprintf(opcode_str, "js.%s", M); + + char temp[32]; + sprintf(temp, ">$%x", m_displacement); + // NEW // sprintf(temp, "$%04x", word1); + retString = opcode + " " + std::string(temp); + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 2; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } + size_t flags() const { return DASMFLAG_STEP_OVER; } + +private: + op_mnem m_mnem; + UINT16 m_displacement; +}; + +// JScc : 0000 0110 RR00 cccc : A-112 ////////////////////////////////////////// +class Jscc_2: public Instruction +{ +public: + Jscc_2(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_mnem = oINVALID; + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + decode_RR_table(BITSn(word0,0x00c0), m_destination); + decode_cccc_table(BITSn(word0,0x000f), m_mnem); + return true; + } + void disassemble(std::string& retString) const + { + std::string opcode = "js" + opMnemonicAsString(m_mnem); + retString = opcode + " " + regIdAsString(m_destination); + // NEW // sprintf(opcode_str, "js.%s", M); + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 1; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } + size_t flags() const { return DASMFLAG_STEP_OVER; } + +private: + op_mnem m_mnem; +}; + +// JSR : 0000 0001 0011 00-- xxxx xxxx xxxx xxxx : A-114 /////////////////////// +class Jsr: public Instruction +{ +public: + Jsr(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_displacement = 0; + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + m_displacement = word1; + return true; + } + void disassemble(std::string& retString) const + { + char temp[32]; + sprintf(temp, ">$%x", m_displacement); + // NEW // sprintf(temp, "$%04x", word1); + retString = "jsr " + std::string(temp); + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 2; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } + size_t flags() const { return DASMFLAG_STEP_OVER; } + +private: + UINT16 m_displacement; +}; + +// JSR : 0000 1010 AAAA AAAA : A-114 /////////////////////////////////////////// +class Jsr_2: public Instruction +{ +public: + Jsr_2(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_bAddr = 0; + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + m_bAddr = BITSn(word0,0x00ff); + return true; + } + void disassemble(std::string& retString) const + { + char temp[32]; + sprintf(temp, "<$%x", m_bAddr); + // NEW // sprintf(temp, "#$%02x", BITSn(word0,0x00ff)); + retString = "jsr " + std::string(temp); + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 1; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } + size_t flags() const { return DASMFLAG_STEP_OVER; } + +private: + UINT8 m_bAddr; +}; + +// JSR : 0000 0001 0010 00RR : A-114 /////////////////////////////////////////// +class Jsr_3: public Instruction +{ +public: + Jsr_3(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + decode_RR_table(BITSn(word0,0x0003), m_destination); + return true; + } + void disassemble(std::string& retString) const + { + retString = "jsr " + regIdAsString(m_destination); + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 1; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } + size_t flags() const { return DASMFLAG_STEP_OVER; } +}; + +// LEA : 0000 0001 11TT MMRR : A-116 /////////////////////////////////////////// +class Lea: public Instruction +{ +public: + Lea(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_ea = ""; + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + if ((word0 & 0x000c) == 0) return false; // NEW TODO // + + decode_TT_table(BITSn(word0,0x0030), m_destination); + + INT8 rNum = BITSn(word0,0x0003); + assemble_ea_from_MM_table(BITSn(word0,0x000c), rNum, m_ea); + + return true; + } + void disassemble(std::string& retString) const + { + // HACK + retString = "lea " + m_ea + "," + regIdAsString(m_destination); + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 1; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } + +private: + std::string m_ea; +}; + +// LEA : 0000 0001 10NN MMRR : A-116 /////////////////////////////////////////// +class Lea_2: public Instruction +{ +public: + Lea_2(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + if ((word0 & 0x000c) == 0) return false; // NEW TODO // + + decode_NN_table(BITSn(word0,0x0030), m_destination); + + INT8 rNum = BITSn(word0,0x0003); + assemble_ea_from_MM_table(BITSn(word0,0x000c), rNum, m_ea); + + return true; + } + void disassemble(std::string& retString) const + { + // HACK + retString = "lea " + m_ea + "," + regIdAsString(m_destination); + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 1; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } + +private: + std::string m_ea; +}; + +// LSL : .... .... 0011 F011 : A-118 /////////////////////////////////////////// +class Lsl: public Instruction +{ +public: + Lsl(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + decode_F_table(BITSn(word0,0x08), m_destination); + return true; + } + void disassemble(std::string& retString) const + { + retString = "lsl " + regIdAsString(m_destination); + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 1; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE; } +}; + +// LSR : .... .... 0011 F010 : A-120 /////////////////////////////////////////// +class Lsr: public Instruction +{ +public: + Lsr(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + decode_F_table(BITSn(word0,0x08), m_destination); + return true; + } + void disassemble(std::string& retString) const + { + retString = "lsr " + regIdAsString(m_destination); + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 1; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE; } +}; + +// MAC : .... .... 1k10 FQQQ : A-122 /////////////////////////////////////////// +class Mac: public Instruction +{ +public: + Mac(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_sign = ""; + m_source2 = iINVALID; + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + decode_QQQF_table(BITSn(word0,0x07), BITSn(word0,0x08), + m_source, m_source2, m_destination); + + decode_kSign_table(BITSn(word0,0x40), m_sign); + return true; + } + void disassemble(std::string& retString) const + { + std::string ts = m_sign; + if (ts.compare("-") != 0) ts = ""; + retString = "mac " + + ts + + regIdAsString(m_source) + "," + + regIdAsString(m_source2) + "," + regIdAsString(m_destination); + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 1; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } + +private: + reg_id m_source2; + std::string m_sign; +}; + +// MAC : 011m mKKK 1xx0 F1QQ : A-122 /////////////////////////////////////////// +class Mac_2: public Instruction +{ +public: + Mac_2(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_source2 = iINVALID; + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + decode_QQF_table(BITSn(word0,0x03), BITSn(word0,0x08), + m_source, m_source2, m_destination); + return true; + } + void disassemble(std::string& retString) const + { + retString = "mac " + + regIdAsString(m_source) + "," + + regIdAsString(m_source2) + "," + regIdAsString(m_destination); + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 1; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } + +private: + reg_id m_source2; +}; + +// MAC : 0001 0111 RRDD FQQQ : A-122 /////////////////////////////////////////// +class Mac_3: public Instruction +{ +public: + Mac_3(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_source2 = iINVALID; + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + decode_QQQF_table(BITSn(word0,0x0007), BITSn(word0,0x0008), + m_source, m_source2, m_destination); + return true; + } + void disassemble(std::string& retString) const + { + retString = "mac " + + regIdAsString(m_source) + "," + + regIdAsString(m_source2) + "," + regIdAsString(m_destination); + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 1; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } + +private: + reg_id m_source2; +}; + +// MACR : .... .... 1k11 FQQQ : A-124 ////////////////////////////////////////// +class Macr: public Instruction +{ +public: + Macr(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_sign = ""; + m_source2 = iINVALID; + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + decode_QQQF_table(BITSn(word0,0x07), BITSn(word0,0x08), + m_source, m_source2, m_destination); + + decode_kSign_table(BITSn(word0,0x40), m_sign); + return true; + } + void disassemble(std::string& retString) const + { + std::string ts = m_sign; + if (ts.compare("-") != 0) ts = ""; + retString = "macr " + + ts + + regIdAsString(m_source) + "," + + regIdAsString(m_source2) + "," + regIdAsString(m_destination); + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 1; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } + +private: + std::string m_sign; + reg_id m_source2; +}; + +// MACR : 011m mKKK 1--1 F1QQ : A-124 ////////////////////////////////////////// +class Macr_2: public Instruction +{ +public: + Macr_2(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_source2 = iINVALID; + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + decode_QQF_table(BITSn(word0,0x03), BITSn(word0,0x08), + m_source, m_source2, m_destination); + return true; + } + void disassemble(std::string& retString) const + { + retString = "macr " + + regIdAsString(m_source) + "," + + regIdAsString(m_source2) + "," + regIdAsString(m_destination); + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 1; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } + +private: + reg_id m_source2; +}; + +// MAC(su,uu) : 0001 0101 1110 FsQQ : A-126 //////////////////////////////////// +class Macsuuu: public Instruction +{ +public: + Macsuuu(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_mnem = oINVALID; + m_source2 = iINVALID; + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + // Special QQF + decode_QQF_special_table(BITSn(word0,0x0003), BITSn(word0,0x0008), + m_source, m_source2, m_destination); + + decode_s_table(BITSn(word0,0x0004), m_mnem); + return true; + } + void disassemble(std::string& retString) const + { + std::string opcode = "mac" + opMnemonicAsString(m_mnem); + + retString = opcode + " " + + regIdAsString(m_source) + "," + + regIdAsString(m_source2) + "," + regIdAsString(m_destination); + // NEW // sprintf(opcode_str, "mac(%s)", A); + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 1; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } + +private: + op_mnem m_mnem; + reg_id m_source2; +}; + +// MOVE : .... .... 0001 0001 : A-128 ////////////////////////////////////////// +class Move: public Instruction +{ +public: + Move(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_isNop = false; + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + // Equivalent to a NOP (+ parallel move) + + // This insures the debugger matches the reference disassembler + // for the undocumented .... .... 0001 1001 Instruction. + if(BITSn(word0, 0x000f) == 0x0001) + m_destination = iA; + else + m_destination = iB; + + // Hack to match reference disassembler + UINT8 BITSn = (word0 & 0xff00) >> 8; + if (BITSn == 0x4a || BITSn == 0x4b) + m_isNop = true; + + return true; + } + void disassemble(std::string& retString) const + { + if (m_isNop) + retString = "nop"; + else + retString = "move"; + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 1; } + size_t accumulatorBitsModified() const { return BM_NONE; } + +private: + bool m_isNop; +}; + +// MOVE : 011m mKKK 0rr1 0000 : A-128 ////////////////////////////////////////// +class Move_2: public Instruction +{ +public: + Move_2(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + // Amounts to a nop with two parallel moves. + // This insures the debugger matches the reference disassembler + if((word0 & 0x0008) == 0x0008) + m_destination = iB; + else + m_destination = iA; + + return true; + } + void disassemble(std::string& retString) const + { + retString = "move"; + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 1; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } +}; + +// MOVE : 0000 0101 BBBB BBBB ---- HHHW 0001 0001 : A-128 ////////////////////// +class Move_3: public Instruction +{ +public: + Move_3(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_W = 0; + m_b = 0; + m_SD = iINVALID; + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + m_b = BITSn(word0,0x00ff); + m_W = BITSn(word1,0x0100); + decode_HHH_table(BITSn(word1,0x0e00), m_SD); + return true; + } + void disassemble(std::string& retString) const + { + std::string source; + std::string destination; + assemble_reg_from_W_table(m_W, 'X', m_SD, m_b, source, destination); + retString = "move " + source + "," + destination; + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 2; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } + +private: + INT8 m_b; + UINT8 m_W; + reg_id m_SD; +}; + +// MOVE(C) : 0011 1WDD DDD0 MMRR : A-144 /////////////////////////////////////// +class Movec: public Instruction +{ +public: + Movec(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_W = 0; + m_ea = ""; + m_SD = iINVALID; + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + INT8 rNum = BITSn(word0,0x0003); + assemble_ea_from_MM_table(BITSn(word0,0x000c), rNum, m_ea); + + m_W = BITSn(word0,0x0400); + decode_DDDDD_table(BITSn(word0,0x03e0), m_SD); + if (m_SD == iINVALID) return false; + return true; + } + void disassemble(std::string& retString) const + { + std::string source; + std::string destination; + assemble_arguments_from_W_table(m_W, 'X', m_SD, m_ea, source, destination); + retString = "move " + source + "," + destination; + // NEW // sprintf(opcode_str, "move(c)"); + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 1; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } + +private: + INT8 m_W; + reg_id m_SD; + std::string m_ea; +}; + +// MOVE(C) : 0011 1WDD DDD1 q0RR : A-144 /////////////////////////////////////// +class Movec_2: public Instruction +{ +public: + Movec_2(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_W = 0; + m_ea = ""; + m_SD = iINVALID; + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + INT8 rNum = BITSn(word0,0x0003); + assemble_ea_from_q_table(BITSn(word0,0x0008), rNum, m_ea); + + decode_DDDDD_table(BITSn(word0,0x03e0), m_SD); + m_W = BITSn(word0,0x0400); + if (m_SD == iINVALID) return false; + return true; + } + void disassemble(std::string& retString) const + { + std::string source; + std::string destination; + assemble_arguments_from_W_table(m_W, 'X', m_SD, m_ea, source, destination); + retString = "move " + source + "," + destination; + // NEW // sprintf(opcode_str, "move(c)"); + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 1; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } + +private: + INT8 m_W; + reg_id m_SD; + std::string m_ea; +}; + +// MOVE(C) : 0011 1WDD DDD1 Z11- : A-144 /////////////////////////////////////// +class Movec_3: public Instruction +{ +public: + Movec_3(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_W = 0; + m_ea = ""; + m_SD = iINVALID; + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + decode_Z_table(BITSn(word0,0x0008), m_ea); + + decode_DDDDD_table(BITSn(word0,0x03e0), m_SD); + m_W = BITSn(word0,0x0400); + if (m_SD == iINVALID) return false; + return true; + } + void disassemble(std::string& retString) const + { + std::string source; + std::string destination; + assemble_arguments_from_W_table(m_W, 'X', m_SD, m_ea, source, destination); + retString = "move " + source + "," + destination; + // NEW // sprintf(opcode_str, "move(c)"); + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 1; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } + +private: + INT8 m_W; + reg_id m_SD; + std::string m_ea; +}; + +// MOVE(C) : 0011 1WDD DDD1 t10- xxxx xxxx xxxx xxxx : A-144 /////////////////// +class Movec_4: public Instruction +{ +public: + Movec_4(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_t = 0; + m_W = 0; + m_sd = iINVALID; + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + m_value = word1; + m_t = BITSn(word0,0x0008); + m_W = BITSn(word0,0x0400); + + decode_DDDDD_table(BITSn(word0,0x03e0), m_sd); + if (m_sd == iINVALID) return false; + + // TODO: Figure out what this means, exactly. + if ((word0 & 0x000c) == 0x000c && (word0 & 0x0400) == 0x0000) + return false; + + return true; + } + void disassemble(std::string& retString) const + { + std::string ea; + assemble_ea_from_t_table(m_t, m_value, ea); + + retString = "move "; + if (m_W) retString += ea + "," + regIdAsString(m_sd); + else retString += regIdAsString(m_sd) + "," + ea; + // NEW // sprintf(opcode_str, "move(c)"); + } + void evaluate(dsp56k_core* cpustate) + { + if (m_W) + { + if (m_t) + { + setReg16(cpustate, m_value, m_sd); + } + else + { + //UINT16 memValue = memory_read_word_16le(cpustate->data, ADDRESS(m_value)); + //setReg16(cpustate, memValue, m_sd); + } + } + else + { + if (m_t) + { + logerror("DSP561xx|Movec_4: This sure seems like it can't happen."); + } + else + { + //UINT16 regValue = regValue16(cpustate, m_sd); + //memory_write_word_16le(cpustate->data, m_value, regValue); + } + } + + /* S L E U N Z V C */ + /* * ? ? ? ? ? ? ? */ + // All ? bits - If SR is specified as a destination operand, set according to the corresponding + // bit of the source operand. If SR is not specified as a destination operand, L is set if data + // limiting occurred. All ? bits are not affected otherwise. + } + size_t size() const { return 2; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } + +private: + UINT8 m_t; + UINT8 m_W; + UINT16 m_value; + reg_id m_sd; +}; + +// MOVE(C) : 0010 10dd dddD DDDD : A-144 /////////////////////////////////////// +class Movec_5: public Instruction +{ +public: + Movec_5(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + decode_DDDDD_table(BITSn(word0,0x03e0), m_source); + decode_DDDDD_table(BITSn(word0,0x001f), m_destination); + + if (m_source == iINVALID || m_destination == iINVALID) return false; + if (m_source == iSSH && m_destination == iSSH) return false; + return true; + } + void disassemble(std::string& retString) const + { + retString = "move " + regIdAsString(m_source) + "," + regIdAsString(m_destination); + // NEW // sprintf(opcode_str, "move(c)"); + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 1; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } +}; + +// MOVE(C) : 0000 0101 BBBB BBBB 0011 1WDD DDD0 ---- : A-144 /////////////////// +class Movec_6: public Instruction +{ +public: + Movec_6(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_W = 0; + m_b = 0; + m_SD = iINVALID; + m_mnem = oINVALID; + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + m_b = BITSn(word0,0x00ff); + m_W = BITSn(word1,0x0400); + decode_DDDDD_table(BITSn(word1,0x03e0), m_SD); + return true; + } + void disassemble(std::string& retString) const + { + std::string source; + std::string destination; + assemble_reg_from_W_table(m_W, 'X', m_SD, m_b, source, destination); + retString = "move " + source + "," + destination; + // NEW // opcode = "move(c)"; + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 2; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } + +private: + INT8 m_b; + UINT8 m_W; + reg_id m_SD; + op_mnem m_mnem; +}; + +// MOVE(I) : 0010 00DD BBBB BBBB : A-150 /////////////////////////////////////// +class Movei: public Instruction +{ +public: + Movei(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_immediate = 0; + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + m_immediate = (INT8)BITSn(word0,0x00ff); + decode_DD_table(BITSn(word0,0x0300), m_destination); + return true; + } + void disassemble(std::string& retString) const + { + char temp[32]; + if (m_immediate >= 0) sprintf(temp, "#<+$%x", m_immediate); + else sprintf(temp, "#<-$%x", 1 - m_immediate - 1); + // NEW // sprintf(temp, "#$%02x,%s", BITSn(word0,0x00ff), D1); + + retString = "move " + + std::string(temp) + "," + regIdAsString(m_destination); + // NEW // sprintf(opcode_str, "move(i)"); + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 1; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } + +private: + INT8 m_immediate; +}; + +// MOVE(M) : 0000 001W RR0M MHHH : A-152 /////////////////////////////////////// +class Movem: public Instruction +{ +public: + Movem(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_W = 0; + m_ea = ""; + m_SD = iINVALID; + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + INT8 rNum = BITSn(word0,0x00c0); + + decode_HHH_table(BITSn(word0,0x0007), m_SD); + assemble_ea_from_MM_table(BITSn(word0,0x0018), rNum, m_ea); + m_W = BITSn(word0,0x0100); + return true; + } + void disassemble(std::string& retString) const + { + std::string source; + std::string destination; + assemble_arguments_from_W_table(m_W, 'P', m_SD, m_ea, source, destination); + retString = "move " + source + "," + destination; + // NEW // sprintf(opcode_str, "move(m)"); + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 1; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } + +private: + INT8 m_W; + reg_id m_SD; + std::string m_ea; +}; + +// MOVE(M) : 0000 001W RR11 mmRR : A-152 /////////////////////////////////////// +class Movem_2: public Instruction +{ +public: + Movem_2(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_W = 0; + m_ea = ""; + m_ea2 = ""; + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + m_W = BITSn(word0,0x0100); + assemble_eas_from_mm_table(BITSn(word0,0x000c), BITSn(word0,0x00c0), BITSn(word0,0x0003), m_ea, m_ea2); + return true; + } + void disassemble(std::string& retString) const + { + std::string source; + std::string destination; + if (m_W) + { + source = "X:" + m_ea; + destination = "P:" + m_ea2; + } + else + { + source = "P:" + m_ea; + destination = "X:" + m_ea2; + } + retString = "move " + source + "," + destination; + // NEW // sprintf(opcode_str, "move(m)*"); + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 1; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } + +private: + UINT8 m_W; + std::string m_ea; + std::string m_ea2; +}; + +// MOVE(M) : 0000 0101 BBBB BBBB 0000 001W --0- -HHH : A-152 /////////////////// +class Movem_3: public Instruction +{ +public: + Movem_3(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_b = 0; + m_SD = iINVALID; + m_mnem = oINVALID; + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + m_b = BITSn(word0,0x00ff); + m_W = BITSn(word1,0x0100); + decode_HHH_table(BITSn(word1,0x0007), m_SD); + return true; + } + void disassemble(std::string& retString) const + { + std::string source; + std::string destination; + assemble_reg_from_W_table(m_W, 'P', m_SD, m_b, source, destination); + retString = "move " + source + "," + destination; + // NEW // opcode = "move(m)"; + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 2; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } + +private: + INT8 m_b; + UINT8 m_W; + reg_id m_SD; + op_mnem m_mnem; +}; + +// MOVE(P) : 0001 100W HH1p pppp : A-156 /////////////////////////////////////// +class Movep: public Instruction +{ +public: + Movep(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_W = 0; + m_ea = ""; + m_SD = iINVALID; + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + decode_HH_table(BITSn(word0,0x00c0), m_SD); + + assemble_address_from_IO_short_address(BITSn(word0,0x001f), m_ea); + m_ea = "<<$" + m_ea; + + m_W = BITSn(word0,0x0100); + return true; + } + void disassemble(std::string& retString) const + { + std::string source; + std::string destination; + assemble_arguments_from_W_table(m_W, 'X', m_SD, m_ea, source, destination); + retString = "movep " + source + "," + destination; + // NEW // sprintf(opcode_str, "move(p)"); + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 1; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } + +private: + INT8 m_W; + reg_id m_SD; + std::string m_ea; +}; + +// MOVE(P) : 0000 110W RRmp pppp : A-156 /////////////////////////////////////// +class Movep_2: public Instruction +{ +public: + Movep_2(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_W = 0; + m_ea = ""; + m_SD = ""; + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + INT8 rNum = BITSn(word0,0x00c0); + + assemble_ea_from_m_table(BITSn(word0,0x0020), rNum, m_ea); + + std::string fullAddy; /* Convert Short Absolute Address to full 16-bit */ + assemble_address_from_IO_short_address(BITSn(word0,0x001f), fullAddy); + + m_W = BITSn(word0,0x0100); + m_SD = "X:<<$" + fullAddy; + // NEW // sprintf(SD, "X:$%s", fullAddy); + return true; + } + void disassemble(std::string& retString) const + { + std::string source; + std::string destination; + assemble_arguments_from_W_table(m_W, 'X', m_SD, m_ea, source, destination); + retString = "movep " + source + "," + destination; + // NEW // sprintf(opcode_str, "move(p)*"); + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 1; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } + +private: + INT8 m_W; + std::string m_SD; + std::string m_ea; +}; + +// MOVE(S) : 0001 100W HH0a aaaa : A-158 /////////////////////////////////////// +class Moves: public Instruction +{ +public: + Moves(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_W = 0; + m_ea = ""; + m_SD = iINVALID; + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + decode_HH_table(BITSn(word0,0x00c0), m_SD); + + char temp[32]; + sprintf(temp, "<$%x", BITSn(word0,0x001f)); + m_ea = temp; + + m_W = BITSn(word0,0x0100); + return true; + } + void disassemble(std::string& retString) const + { + std::string source; + std::string destination; + assemble_arguments_from_W_table(m_W, 'X', m_SD, m_ea, source, destination); + retString = "moves " + source + "," + destination; + // NEW // sprintf(opcode_str, "move(s)"); + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 1; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } + +private: + INT8 m_W; + reg_id m_SD; + std::string m_ea; +}; + +// MPY : .... .... 1k00 FQQQ : A-160 /////////////////////////////////////////// +class Mpy: public Instruction +{ +public: + Mpy(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_sign = ""; + m_source2 = iINVALID; + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + /* There are inconsistencies with the S1 & S2 operand ordering in the docs, + but since it's a multiply it doesn't matter */ + decode_QQQF_table(BITSn(word0,0x07), BITSn(word0,0x08), + m_source, m_source2, m_destination); + + decode_kSign_table(BITSn(word0,0x40), m_sign); + return true; + } + void disassemble(std::string& retString) const + { + std::string ts = m_sign; + if (ts.compare("-")!=0) ts = ""; + retString = "mpy " + + ts + + regIdAsString(m_source) + "," + + regIdAsString(m_source2) + "," + regIdAsString(m_destination); + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 1; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } + +private: + std::string m_sign; + reg_id m_source2; +}; + +// MPY : 011m mKKK 1xx0 F0QQ : A-160 /////////////////////////////////////////// +class Mpy_2: public Instruction +{ +public: + Mpy_2(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_source2 = iINVALID; + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + decode_QQF_table(BITSn(word0,0x03), BITSn(word0,0x08), + m_source, m_source2, m_destination); + return true; + } + void disassemble(std::string& retString) const + { + retString = "mpy " + + regIdAsString(m_source) + "," + + regIdAsString(m_source2) + "," + regIdAsString(m_destination); + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 1; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } + +private: + reg_id m_source2; +}; + +// MPY : 0001 0110 RRDD FQQQ : A-160 /////////////////////////////////////////// +class Mpy_3: public Instruction +{ +public: + Mpy_3(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_source2 = iINVALID; + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + decode_QQQF_table(BITSn(word0,0x0007), BITSn(word0,0x0008), + m_source, m_source2, m_destination); + return true; + } + void disassemble(std::string& retString) const + { + retString = "mpy " + + regIdAsString(m_source) + "," + + regIdAsString(m_source2) + "," + regIdAsString(m_destination); + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 1; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } + +private: + reg_id m_source2; +}; + +// MPYR : .... .... 1k01 FQQQ : A-162 ////////////////////////////////////////// +class Mpyr: public Instruction +{ +public: + Mpyr(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_sign = "-"; + m_source2 = iINVALID; + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + /* There are inconsistencies with the S1 & S2 operand ordering in the docs, + but since it's a multiply it doesn't matter */ + decode_QQQF_table(BITSn(word0,0x07), BITSn(word0,0x08), + m_source, m_source2, m_destination); + + decode_kSign_table(BITSn(word0,0x40), m_sign); + return true; + } + void disassemble(std::string& retString) const + { + std::string ts = m_sign; + if (ts.compare("-") != 0) ts = ""; + retString = "mpyr " + + ts + + regIdAsString(m_source) + "," + + regIdAsString(m_source2) + "," + regIdAsString(m_destination); + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 1; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } + +private: + std::string m_sign; + reg_id m_source2; +}; + +// MPYR : 011m mKKK 1--1 F0QQ : A-162 ////////////////////////////////////////// +class Mpyr_2: public Instruction +{ +public: + Mpyr_2(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_source2 = iINVALID; + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + decode_QQF_table(BITSn(word0,0x03), BITSn(word0,0x08), + m_source, m_source2, m_destination); + return true; + } + void disassemble(std::string& retString) const + { + retString = "mpyr " + + regIdAsString(m_source) + "," + + regIdAsString(m_source2) + "," + regIdAsString(m_destination); + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 1; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } + +private: + reg_id m_source2; +}; + +// MPY(su,uu) : 0001 0101 1100 FsQQ : A-164 //////////////////////////////////// +class Mpysuuu: public Instruction +{ +public: + Mpysuuu(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_mnem = oINVALID; + m_source2 = iINVALID; + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + decode_QQF_special_table(BITSn(word0,0x0003), BITSn(word0,0x0008), + m_source, m_source2, m_destination); + + decode_s_table(BITSn(word0,0x0004), m_mnem); + return true; + } + void disassemble(std::string& retString) const + { + std::string opcode = "mpy" + opMnemonicAsString(m_mnem); + + retString = opcode + " " + + regIdAsString(m_source) + "," + + regIdAsString(m_source2) + "," + regIdAsString(m_destination); + // NEW // sprintf(opcode_str, "mpy(%s)", A); + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 1; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } + +private: + op_mnem m_mnem; + reg_id m_source2; +}; + +// NEG : .... .... 0110 F000 : A-166 /////////////////////////////////////////// +class Neg: public Instruction +{ +public: + Neg(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + decode_F_table(BITSn(word0,0x08), m_destination); + return true; + } + void disassemble(std::string& retString) const + { + retString = "neg " + regIdAsString(m_destination); + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 1; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } +}; + +// NEGC : 0001 0101 0110 F000 : A-168 ////////////////////////////////////////// +class Negc: public Instruction +{ +public: + Negc(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + decode_F_table(BITSn(word0,0x0008), m_destination); + return true; + } + void disassemble(std::string& retString) const + { + retString = "negc " + regIdAsString(m_destination); + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 1; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } +}; + +// NOP : 0000 0000 0000 0000 : A-170 /////////////////////////////////////////// +class Nop: public Instruction +{ +public: + Nop(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + return true; + } + void disassemble(std::string& retString) const + { + retString = "nop"; + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 1; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } +}; + +// NORM : 0001 0101 0010 F0RR : A-172 ////////////////////////////////////////// +class Norm: public Instruction +{ +public: + Norm(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + decode_F_table(BITSn(word0,0x0008), m_destination); + + decode_RR_table(BITSn(word0,0x0003), m_source); + return true; + } + void disassemble(std::string& retString) const + { + retString = "norm " + regIdAsString(m_source) + "," + regIdAsString(m_destination); + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 1; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } +}; + +// NOT : .... .... 0110 F001 : A-174 /////////////////////////////////////////// +class Not: public Instruction +{ +public: + Not(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + decode_F_table(BITSn(word0,0x08), m_destination); + return true; + } + void disassemble(std::string& retString) const + { + retString = "not " + regIdAsString(m_destination); + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 1; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE; } +}; + +// OR : .... .... 0010 F1JJ : A-176 //////////////////////////////////////////// +class Or: public Instruction +{ +public: + Or(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + decode_JJF_table(BITSn(word0,0x03),BITSn(word0,0x08), + m_source, m_destination); + return true; + } + void disassemble(std::string& retString) const + { + retString = "or " + regIdAsString(m_source) + "," + regIdAsString(m_destination); + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 1; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE; } +}; + +// ORI : 0001 1EE1 iiii iiii : A-178 /////////////////////////////////////////// +class Ori: public Instruction +{ +public: + Ori(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_immediate = 0; + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + m_immediate = BITSn(word0,0x00ff); + decode_EE_table(BITSn(word0,0x0600), m_destination); + return true; + } + void disassemble(std::string& retString) const + { + char temp[32]; + sprintf(temp, "#$%x", m_immediate); + // NEW // sprintf(temp, "#$%02x", BITSn(word0,0x00ff)); + retString = "ori " + std::string(temp) + "," + regIdAsString(m_destination); + // NEW // sprintf(opcode_str, "or(i)"); + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 1; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } + +private: + UINT8 m_immediate; +}; + +// REP : 0000 0000 111- --RR : A-180 /////////////////////////////////////////// +class Rep: public Instruction +{ +public: + Rep(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + decode_RR_table(BITSn(word0,0x0003), m_source); + return true; + } + void disassemble(std::string& retString) const + { + char temp[32]; + sprintf(temp, "X:(%s)", regIdAsString(m_source).c_str()); + retString = "rep " + std::string(temp); + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 1; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } +}; + +// REP : 0000 1111 iiii iiii : A-180 /////////////////////////////////////////// +class Rep_2: public Instruction +{ +public: + Rep_2(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_immediate = 0; + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + m_immediate = BITSn(word0,0x00ff); + return true; + } + void disassemble(std::string& retString) const + { + char temp[32]; + sprintf(temp, "#$%x", m_immediate); + // NEW // sprintf(temp, "#$%02x (%d)", BITSn(word0,0x00ff), BITSn(word0,0x00ff)); + retString = "rep " + std::string(temp); + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 1; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } + +private: + UINT8 m_immediate; +}; + +// REP : 0000 0100 001D DDDD : A-180 /////////////////////////////////////////// +class Rep_3: public Instruction +{ +public: + Rep_3(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + decode_DDDDD_table(BITSn(word0,0x001f), m_source); + if (m_source == iINVALID) return false; + return true; + } + void disassemble(std::string& retString) const + { + retString = "rep " + regIdAsString(m_source); + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 1; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } +}; + +// REPcc : 0000 0001 0101 cccc : A-184 ///////////////////////////////////////// +class Repcc: public Instruction +{ +public: + Repcc(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_mnem = oINVALID; + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + decode_cccc_table(BITSn(word0,0x000f), m_mnem); + return true; + } + void disassemble(std::string& retString) const + { + std::string opcode = "rep" + opMnemonicAsString(m_mnem); + retString = opcode; + // NEW // sprintf(opcode_str, "rep.%s", M); + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 1; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } + +private: + op_mnem m_mnem; +}; + +// RESET : 0000 0000 0000 1000 : A-186 ///////////////////////////////////////// +class Reset: public Instruction +{ +public: + Reset(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + return true; + } + void disassemble(std::string& retString) const + { + retString = "reset"; + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 1; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } +}; + +// RND : .... .... 0010 F000 : A-188 /////////////////////////////////////////// +class Rnd: public Instruction +{ +public: + Rnd(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + decode_F_table(BITSn(word0,0x08), m_destination); + return true; + } + void disassemble(std::string& retString) const + { + retString = "rnd " + regIdAsString(m_destination); + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 1; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } +}; + +// ROL : .... .... 0111 F011 : A-190 /////////////////////////////////////////// +class Rol: public Instruction +{ +public: + Rol(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + decode_F_table(BITSn(word0,0x08), m_destination); + return true; + } + void disassemble(std::string& retString) const + { + retString = "rol " + regIdAsString(m_destination); + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 1; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE; } +}; + +// ROR : .... .... 0111 F010 : A-192 /////////////////////////////////////////// +class Ror: public Instruction +{ +public: + Ror(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + decode_F_table(BITSn(word0,0x08), m_destination); + return true; + } + void disassemble(std::string& retString) const + { + retString = "ror " + regIdAsString(m_destination); + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 1; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE; } +}; + +// RTI : 0000 0000 0000 0111 : A-194 /////////////////////////////////////////// +class Rti: public Instruction +{ +public: + Rti(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + return true; + } + void disassemble(std::string& retString) const + { + retString = "rti"; + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 1; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } + size_t flags() const { return DASMFLAG_STEP_OUT; } +}; + +// RTS : 0000 0000 0000 0110 : A-196 /////////////////////////////////////////// +class Rts: public Instruction +{ +public: + Rts(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + return true; + } + void disassemble(std::string& retString) const + { + retString = "rts"; + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 1; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } + size_t flags() const { return DASMFLAG_STEP_OUT; } +}; + +// SBC : .... .... 0101 F01J : A-198 /////////////////////////////////////////// +class Sbc: public Instruction +{ +public: + Sbc(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + decode_JF_table(BITSn(word0,0x01), BITSn(word0,0x08), + m_source, m_destination); + return true; + } + void disassemble(std::string& retString) const + { + retString = "sbc " + regIdAsString(m_source) + "," + regIdAsString(m_destination); + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 1; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } +}; + +// STOP : 0000 0000 0000 1010 : A-200 ////////////////////////////////////////// +class Stop: public Instruction +{ +public: + Stop(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + return true; + } + void disassemble(std::string& retString) const + { + retString = "stop"; + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 1; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } +}; + +// SUB : .... .... 0100 FJJJ : A-202 /////////////////////////////////////////// +class Sub: public Instruction +{ +public: + Sub(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + decode_JJJF_table(BITSn(word0,0x07), BITSn(word0,0x08), + m_source, m_destination); + return true; + } + void disassemble(std::string& retString) const + { + retString = "sub " + regIdAsString(m_source) + "," + regIdAsString(m_destination); + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 1; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } +}; + +// SUB : 011m mKKK 0rru Fuuu : A-202 /////////////////////////////////////////// +class Sub_2: public Instruction +{ +public: + Sub_2(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_opcode = ""; + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + decode_uuuuF_table(BITSn(word0,0x17), BITSn(word0,0x08), + m_opcode, m_source, m_destination); + + // TODO // m_opcode = "sub"; + return true; + } + void disassemble(std::string& retString) const + { + retString = m_opcode + " " + regIdAsString(m_source) + "," + regIdAsString(m_destination); + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 1; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } + +private: + std::string m_opcode; +}; + +// SUBL : .... .... 0100 F001 : A-204 ////////////////////////////////////////// +class Subl: public Instruction +{ +public: + Subl(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + /* There is only one option for the F table. This is a very strange opcode. */ + if (!BITSn(word0,0x0008)) + { + m_source = iB; + m_destination = iA; + } + else + { + m_source = iA; + m_destination = iB; + } + return true; + } + void disassemble(std::string& retString) const + { + retString = "subl " + regIdAsString(m_source) + "," + regIdAsString(m_destination); + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 1; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } +}; + +// SWAP : 0001 0101 0111 F001 : A-206 ////////////////////////////////////////// +class Swap: public Instruction +{ +public: + Swap(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + decode_F_table(BITSn(word0,0x0008), m_destination); + return true; + } + void disassemble(std::string& retString) const + { + retString = "swap " + regIdAsString(m_destination); + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 1; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } +}; + +// SWI : 0000 0000 0000 0101 : A-208 /////////////////////////////////////////// +class Swi: public Instruction +{ +public: + Swi(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + return true; + } + void disassemble(std::string& retString) const + { + retString = "swi"; + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 1; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } +}; + +// Tcc : 0001 00cc ccTT Fh0h : A-210 /////////////////////////////////////////// +class Tcc: public Instruction +{ +public: + Tcc(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_mnem = oINVALID; + m_destination2 = iINVALID; + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + decode_h0hF_table(BITSn(word0,0x0007),BITSn(word0,0x0008), + m_source, m_destination); + + decode_RR_table(BITSn(word0,0x0030), m_destination2); + + decode_cccc_table(BITSn(word0,0x03c0), m_mnem); + if (m_source != m_destination) + return true; + if (m_destination2 != iR0) + return true; + + return false; + } + void disassemble(std::string& retString) const + { + std::string opcode = "t" + opMnemonicAsString(m_mnem); + // NEW // sprintf(opcode_str, "t.%s", M); + + retString = opcode; + if (m_source != m_destination) + retString += std::string(" ") + regIdAsString(m_source) + "," + regIdAsString(m_destination); + + if (m_destination2 != iR0) + retString += std::string(" R0,") + regIdAsString(m_destination2); + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 1; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } + +private: + op_mnem m_mnem; + reg_id m_destination2; +}; + +// TFR : .... .... 0001 FJJJ : A-212 /////////////////////////////////////////// +class Tfr: public Instruction +{ +public: + Tfr(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + decode_JJJF_table(BITSn(word0,0x07), BITSn(word0,0x08), + m_source, m_destination); + return true; + } + void disassemble(std::string& retString) const + { + retString = "tfr " + regIdAsString(m_source) + "," + regIdAsString(m_destination); + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 1; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } +}; + +// TFR : 011m mKKK 0rr1 F0DD : A-212 /////////////////////////////////////////// +class Tfr_2: public Instruction +{ +public: + Tfr_2(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + decode_DDF_table(BITSn(word0,0x03), BITSn(word0,0x08), + m_source, m_destination); + return true; + } + void disassemble(std::string& retString) const + { + retString = "tfr " + regIdAsString(m_source) + "," + regIdAsString(m_destination); + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 1; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } +}; + +// TFR(2) : 0001 0101 0000 F00J : A-214 //////////////////////////////////////// +class Tfr2: public Instruction +{ +public: + Tfr2(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + decode_JF_table(BITSn(word0,0x0001),BITSn(word0,0x0008), + m_destination, m_source); + return true; + } + void disassemble(std::string& retString) const + { + retString = "tfr2 " + regIdAsString(m_source) + "," + regIdAsString(m_destination); + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 1; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } +}; + +// TFR(3) : 0010 01mW RRDD FHHH : A-216 //////////////////////////////////////// +class Tfr3: public Instruction +{ +public: + Tfr3(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_W = 0; + m_ea = ""; + m_SD = iINVALID; + m_source2 = iINVALID; + m_destination2 = iINVALID; + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + decode_DDF_table(BITSn(word0,0x0030), BITSn(word0,0x0008), + m_destination, m_source); + + decode_HHH_table(BITSn(word0,0x0007), m_SD); + // If the destination of the second move is the same as the first, you're invalid + if (m_SD == m_destination && BITSn(word0,0x0100)) return false; + + INT8 rNum = BITSn(word0,0x00c0); + assemble_ea_from_m_table(BITSn(word0,0x0200), rNum, m_ea); + + m_W = BITSn(word0,0x0100); + return true; + } + void disassemble(std::string& retString) const + { + std::string source2; + std::string destination2; + assemble_arguments_from_W_table(m_W, 'X', m_SD, m_ea, source2, destination2); + retString = "tfr3 " + + regIdAsString(m_source) + "," + regIdAsString(m_destination) + " " + + source2 + "," + destination2; + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 1; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } + +private: + INT8 m_W; + reg_id m_SD; + std::string m_ea; + reg_id m_source2; + reg_id m_destination2; +}; + +// TST : .... .... 0010 F001 : A-218 /////////////////////////////////////////// +class Tst: public Instruction +{ +public: + Tst(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + decode_F_table(BITSn(word0,0x08), m_destination); + return true; + } + void disassemble(std::string& retString) const + { + retString = "tst " + regIdAsString(m_destination); + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 1; } + size_t accumulatorBitsModified() const { return BM_NONE; } +}; + +// TST(2) : 0001 0101 0001 -1DD : A-220 //////////////////////////////////////// +class Tst2: public Instruction +{ +public: + Tst2(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + decode_DD_table(BITSn(word0,0x0003), m_source); + return true; + } + void disassemble(std::string& retString) const + { + retString = "tst2 " + regIdAsString(m_source); + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 1; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } +}; + +// WAIT : 0000 0000 0000 1011 : A-222 ////////////////////////////////////////// +class Wait: public Instruction +{ +public: + Wait(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + return true; + } + void disassemble(std::string& retString) const + { + retString = "wait"; + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 1; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } +}; + +// ZERO : 0001 0101 0101 F000 : A-224 ////////////////////////////////////////// +class Zero: public Instruction +{ +public: + Zero(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + decode_F_table(BITSn(word0,0x0008), m_destination); + return true; + } + void disassemble(std::string& retString) const + { + retString = "zero " + regIdAsString(m_destination); + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 1; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } +}; + +// SHFL : 0001 0101 1101 FQQQ : !!UNDOCUMENTED!! /////////////////////////////// +class Shfl: public Instruction +{ +public: + Shfl(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_source2 = iINVALID; + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + decode_QQQF_table(BITSn(word0,0x0007), BITSn(word0,0x0008), + m_source, m_source2, m_destination); + + // This hackery amounts to a very strange QQQF table... + if (m_source == iX0 && m_source2 == iX0) return false; + if (m_source == iX1 && m_source2 == iX0) return false; + + if (m_source == iY0 && m_source2 == iX1) + { + m_source = iX1; + m_source2 = iY0; + } + if (m_source == iY1 && m_source2 == iX1) + { + m_source = iX1; + m_source2 = iY1; + } + return true; + } + void disassemble(std::string& retString) const + { + retString = "shfl " + + regIdAsString(m_source) + "," + + regIdAsString(m_source2) + "," + regIdAsString(m_destination); + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 1; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } + +private: + reg_id m_source2; +}; + +// SHFR : 0001 0101 1111 FQQQ : !!UNDOCUMENTED!! /////////////////////////////// +class Shfr: public Instruction +{ +public: + Shfr(const Opcode* oco, const UINT16 word0, const UINT16 word1) : Instruction(oco) + { + m_source2 = iINVALID; + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + decode_QQQF_table(BITSn(word0,0x0007), BITSn(word0,0x0008), + m_source, m_source2, m_destination); + + // This hackery amounts to a very strange QQQF table... + if (m_source == iX0 && m_source2 == iX0) return false; + if (m_source == iX1 && m_source2 == iX0) return false; + + if (m_source == iY0 && m_source2 == iX1) + { + m_source = iX1; + m_source2 = iY0; + } + if (m_source == iY1 && m_source2 == iX1) + { + m_source = iX1; + m_source2 = iY1; + } + return true; + } + void disassemble(std::string& retString) const + { + retString = "shfr " + + regIdAsString(m_source) + "," + + regIdAsString(m_source2) + "," + regIdAsString(m_destination); + } + void evaluate(dsp56k_core* cpustate) {} + size_t size() const { return 1; } + size_t accumulatorBitsModified() const { return BM_HIGH | BM_MIDDLE | BM_LOW; } + +private: + reg_id m_source2; +}; + +} +#endif diff --git a/src/devices/cpu/dsp56k/opcode.c b/src/devices/cpu/dsp56k/opcode.c new file mode 100644 index 00000000000..dd71d852650 --- /dev/null +++ b/src/devices/cpu/dsp56k/opcode.c @@ -0,0 +1,80 @@ +// license:BSD-3-Clause +// copyright-holders:Andrew Gardner +#include + +#include "opcode.h" + +namespace DSP56K +{ +Opcode::Opcode(UINT16 w0, UINT16 w1) : m_word0(w0)/*, m_word1(w1)*/ +{ + m_instruction.reset(Instruction::decodeInstruction(this, w0, w1)); + m_parallelMove.reset(ParallelMove::decodeParallelMove(this, w0, w1)); +} + + +Opcode::~Opcode() +{ +} + + +std::string Opcode::disassemble() const +{ + // Duck out early if there isn't a valid op + if (!m_instruction) + return dcString(); + + // Duck out if either has had an explicit error. + if (m_instruction && !m_instruction->valid()) + return dcString(); + if (m_parallelMove && !m_parallelMove->valid()) + return dcString(); + + // Disassemble what you can. + std::string opString = ""; + std::string pmString = ""; + if (m_instruction) m_instruction->disassemble(opString); + if (m_parallelMove) m_parallelMove->disassemble(pmString); + + return opString + " " + pmString; +} + + +void Opcode::evaluate(dsp56k_core* cpustate) const +{ + if (m_instruction) m_instruction->evaluate(cpustate); + if (m_parallelMove) m_parallelMove->evaluate(); +} + + +size_t Opcode::size() const +{ + if (m_instruction && m_instruction->valid()) + return m_instruction->size() + m_instruction->sizeIncrement(); + + // Opcode failed to decode, so push it past dc + return 1; +} + +size_t Opcode::evalSize() const +{ + if (m_instruction && m_instruction->valid()) + return m_instruction->evalSize(); // Probably doesn't matter : + m_instruction->sizeIncrement(); + + // Opcode failed to decode, so push it past dc + return 1; +} + + +const reg_id& Opcode::instSource() const { return m_instruction->source(); } +const reg_id& Opcode::instDestination() const { return m_instruction->destination(); } +size_t Opcode::instAccumulatorBitsModified() const { return m_instruction->accumulatorBitsModified(); } + +std::string Opcode::dcString() const +{ + char tempStr[1024]; + sprintf(tempStr, "dc $%x", m_word0); + return std::string(tempStr); +} + +} diff --git a/src/devices/cpu/dsp56k/opcode.h b/src/devices/cpu/dsp56k/opcode.h new file mode 100644 index 00000000000..66423716ffb --- /dev/null +++ b/src/devices/cpu/dsp56k/opcode.h @@ -0,0 +1,47 @@ +// license:BSD-3-Clause +// copyright-holders:Andrew Gardner +#ifndef __DSP56K_OPCODE_H__ +#define __DSP56K_OPCODE_H__ + +#include "emu.h" +#include "inst.h" +#include "pmove.h" + +#include "dsp56k.h" + +// +// An Opcode contains an instruction and a parallel move operation. +// +namespace DSP56K +{ +class Instruction; +class ParallelMove; + +class Opcode +{ +public: + Opcode(UINT16 w0, UINT16 w1); + virtual ~Opcode(); + + std::string disassemble() const; + void evaluate(dsp56k_core* cpustate) const; + size_t size() const; + size_t evalSize() const; + + // Peek through to the instruction + const reg_id& instSource() const; + const reg_id& instDestination() const; + size_t instAccumulatorBitsModified() const; + +private: + auto_pointer m_instruction; + auto_pointer m_parallelMove; + + UINT16 m_word0; + //UINT16 m_word1; + + std::string dcString() const; +}; + +} +#endif diff --git a/src/devices/cpu/dsp56k/pmove.c b/src/devices/cpu/dsp56k/pmove.c new file mode 100644 index 00000000000..dce702d094b --- /dev/null +++ b/src/devices/cpu/dsp56k/pmove.c @@ -0,0 +1,79 @@ +// license:BSD-3-Clause +// copyright-holders:Andrew Gardner +#include "pmove.h" + +namespace DSP56K +{ +const reg_id& ParallelMove::opSource() const { return m_oco->instSource(); } +const reg_id& ParallelMove::opDestination() const { return m_oco->instDestination(); } +size_t ParallelMove::opAccumulatorBitsModified() const { return m_oco->instAccumulatorBitsModified(); } + + +ParallelMove* ParallelMove::decodeParallelMove(const Opcode* opc, const UINT16 word0, const UINT16 word1) +{ + const UINT16 w0 = word0; + const UINT16 w1 = word1; + + /* Dual X Memory Data Read : 011m mKKK .rr. .... : A-142*/ + if ((w0 & 0xe000) == 0x6000) + { + return global_alloc(DualXMemoryDataRead(opc, w0, w1)); + } + /* X Memory Data Write and Register Data Move : 0001 011k RRDD .... : A-140 */ + else if ((w0 & 0xfe00) == 0x1600) + { + return global_alloc(XMemoryDataWriteAndRegisterDataMove(opc, w0, w1)); + } + else + { + /* 32 General parallel move operations */ + /* Note: It's important that NPDM comes before RtRDM */ + + /* No Parallel Data Move : 0100 1010 .... .... : A-131 */ + if ((w0 & 0xff00) == 0x4a00) + { + return NULL; + } + /* Register to Register Data Move : 0100 IIII .... .... : A-133 */ + else if ((w0 & 0xf000) == 0x4000) + { + return global_alloc(RegisterToRegisterDataMove(opc, w0, w1)); + } + /* Address Register Update : 0011 0zRR .... .... : A-135 */ + else if ((w0 & 0xf800) == 0x3000) + { + return global_alloc(AddressRegisterUpdate(opc, w0, w1)); + } + /* X Memory Data Move : 1mRR HHHW .... .... : A-137 */ + else if ((w0 & 0x8000) == 0x8000) + { + return global_alloc(XMemoryDataMove(opc, w0, w1)); + } + /* X Memory Data Move : 0101 HHHW .... .... : A-137 */ + else if ((w0 & 0xf000) == 0x5000) + { + return global_alloc(XMemoryDataMove_2(opc, w0, w1)); + } + /* X Memory Data Move with short displacement : 0000 0101 BBBB BBBB ---- HHHW .... .... : A-139 */ + else if ((w0 & 0xff00) == 0x0500) + { + // Now check it against all potential double-ups. + // These operations can't have an additional parallel move. + // + // MOVE(M) : 0000 0101 BBBB BBBB 0000 001W --0- -HHH : A-152 + // MOVE(C) : 0000 0101 BBBB BBBB 0011 1WDD DDD0 ---- : A-144 + // MOVE : 0000 0101 BBBB BBBB ---- HHHW 0001 0001 : A-128 + // + if (((w1 & 0xfe20) != 0x0200) && + ((w1 & 0xf810) != 0x3800) && + ((w1 & 0x00ff) != 0x0011)) + { + return global_alloc(XMemoryDataMoveWithShortDisplacement(opc, w0, w1)); + } + } + } + + return NULL; +} + +} diff --git a/src/devices/cpu/dsp56k/pmove.h b/src/devices/cpu/dsp56k/pmove.h new file mode 100644 index 00000000000..8e30a534073 --- /dev/null +++ b/src/devices/cpu/dsp56k/pmove.h @@ -0,0 +1,338 @@ +// license:BSD-3-Clause +// copyright-holders:Andrew Gardner +#ifndef __DSP56K_PARALLEL_MOVE_H__ +#define __DSP56K_PARALLEL_MOVE_H__ + +#include "emu.h" +#include "opcode.h" +#include "tables.h" + +// +// A ParallelMove Object is what all parallel move classes inherit from. +// +namespace DSP56K +{ +class Opcode; + +class ParallelMove +{ +public: + ParallelMove(const Opcode* oco) : m_valid(false), m_oco(oco) { } + virtual ~ParallelMove() {} + + virtual bool decode(const UINT16 word0, const UINT16 word1) = 0; + virtual void disassemble(std::string& retString) const = 0; + virtual void evaluate() = 0; + + static ParallelMove* decodeParallelMove(const Opcode* opc, const UINT16 word0, const UINT16 word1); + + bool valid() const { return m_valid; } + + // Peek through the opcode to see the instruction + const reg_id& opSource() const; + const reg_id& opDestination() const; + size_t opAccumulatorBitsModified() const; + +protected: + bool m_valid; + const Opcode* m_oco; +}; + + +//////////////////////////////////////////////////////////////////////////////// +// PARALLEL MOVES //////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// + +/* X Memory Data Move : 1mRR HHHW .... .... : A-137 */ +class XMemoryDataMove: public ParallelMove +{ +public: + XMemoryDataMove(const Opcode* oco, const UINT16 word0, const UINT16 word1) : ParallelMove(oco) + { + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + reg_id r; + decode_RR_table(BITSn(word0,0x3000), r); + + reg_id SD; + decode_HHH_table(BITSn(word0,0x0e00), SD); + + std::string ea; + assemble_ea_from_m_table(BITSn(word0,0x4000), regIDAsNum(r), ea); + + assemble_arguments_from_W_table(BITSn(word0,0x0100), 'X', SD, ea, + m_source, m_destination); + + // If the destination of the instruction overlaps with our destination, abort. + if (registerOverlap(opDestination(), opAccumulatorBitsModified(), stringAsRegID(m_destination))) + return false; + + return true; + } + void disassemble(std::string& retString) const + { + retString = m_source + "," + m_destination; + } + void evaluate() {} + +private: + std::string m_source; + std::string m_destination; +}; + + +/* X Memory Data Move : 0101 HHHW .... .... : A-137 */ +class XMemoryDataMove_2: public ParallelMove +{ +public: + XMemoryDataMove_2(const Opcode* oco, const UINT16 word0, const UINT16 word1) : ParallelMove(oco) + { + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + std::string ea; + if (opDestination() == iB) + ea = "(A1)"; + else if (opDestination() == iA) + ea = "(B1)"; + else + ea = "(A1)"; + + reg_id SD; + decode_HHH_table(BITSn(word0,0x0e00), SD); + + assemble_arguments_from_W_table(BITSn(word0,0x0100), 'X', SD, ea, + m_source, m_destination); + + // If the destination of the instruction overlaps with our destination, abort. + if (registerOverlap(opDestination(), opAccumulatorBitsModified(), stringAsRegID(m_destination))) + return false; + + return true; + } + void disassemble(std::string& retString) const + { + retString = m_source + "," + m_destination; + } + void evaluate() {} + +private: + std::string m_source; + std::string m_destination; +}; + + +/* Dual X Memory Data Read : 011m mKKK .rr. .... : A-142*/ +class DualXMemoryDataRead: public ParallelMove +{ +public: + DualXMemoryDataRead(const Opcode* oco, const UINT16 word0, const UINT16 word1) : ParallelMove(oco) + { + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + reg_id r; + reg_id D1; + reg_id D2; + std::string ea1 = ""; + std::string ea2 = ""; + + decode_rr_table(BITSn(word0,0x0060), r); + decode_KKK_table(BITSn(word0,0x0700), D1, D2); + assemble_eas_from_mm_table(BITSn(word0,0x1800), regIDAsNum(r), 3, ea1, ea2); + + /* Not documented, but extrapolated from docs on page A-133 */ + if (D1 == iFHAT) + { + if (opDestination() == iB) + D1 = iA; + else if (opDestination() == iA) + D1 = iB; + else + D1 = iA; /* In the case of no data ALU instruction */ + } + + /* D1 and D2 may not specify the same register : A-142 */ + if (r == iR3) return false; + + char temp[32]; + sprintf(temp, "X:%s,%s", ea1.c_str(), regIdAsString(D1).c_str()); + parallelMove = temp; + sprintf(temp, "X:%s,%s", ea2.c_str(), regIdAsString(D2).c_str()); + parallelMove2 = temp; + + return true; + } + void disassemble(std::string& retString) const + { + retString = parallelMove + " " + parallelMove2; + } + void evaluate() {} + +private: + std::string parallelMove; + std::string parallelMove2; +}; + + +/* Register to Register Data Move : 0100 IIII .... .... : A-133 */ +class RegisterToRegisterDataMove: public ParallelMove +{ +public: + RegisterToRegisterDataMove(const Opcode* oco, const UINT16 word0, const UINT16 word1) : ParallelMove(oco) + { + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + decode_IIIIx_table(BITSn(word0,0x0f00), BITSn(word0,0x0008), + m_source, m_destination); + + if (m_source == iINVALID) + return false; + + if (m_source == iF) + m_source = opDestination(); + + if (m_destination == iFHAT) + { + if (opDestination() == iB) + m_destination = iA; + else if (opDestination() == iA) + m_destination = iB; + else + m_destination = iA; /* In the case of no data ALU instruction */ + } + + // Don't return a failure, just let everything fall through (nop). + //if (m_source == "?" && m_destination == "?") + // return false; + + return true; + } + void disassemble(std::string& retString) const + { + // (?,?) is a parallel nop + if (m_source == iWEIRD && m_destination == iWEIRD) + retString = ""; + else + retString = regIdAsString(m_source) + "," + regIdAsString(m_destination); + } + void evaluate() {} + +private: + reg_id m_source; + reg_id m_destination; +}; + + +/* X Memory Data Write and Register Data Move : 0001 011k RRDD .... : A-140 */ +class XMemoryDataWriteAndRegisterDataMove: public ParallelMove +{ +public: + XMemoryDataWriteAndRegisterDataMove(const Opcode* oco, const UINT16 word0, const UINT16 word1) : ParallelMove(oco) + { + pms = ""; + pms2 = ""; + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + reg_id r; + reg_id S; + reg_id Dnot; + char parallel_move_str[128]; + char parallel_move_str2[128]; + + if (opDestination() == iA) Dnot = iB; + else Dnot = iA; + + // NEW // decode_k_table(BITSn(word0,0x0100), Dnot); + decode_RR_table(BITSn(word0,0x00c0), r); + decode_DD_table(BITSn(word0,0x0030), S); + + sprintf(parallel_move_str, "%s,X:(R%d)+N%d", regIdAsString(Dnot).c_str(), regIDAsNum(r), regIDAsNum(r)); + sprintf(parallel_move_str2, "%s,%s", regIdAsString(S).c_str(), regIdAsString(Dnot).c_str()); + pms = parallel_move_str; + pms2 = parallel_move_str2; + return true; + } + void disassemble(std::string& retString) const + { + retString = pms + " " + pms2; + } + void evaluate() {} + +private: + std::string pms; // TODO + std::string pms2; +}; + + +/* Address Register Update : 0011 0zRR .... .... : A-135 */ +class AddressRegisterUpdate: public ParallelMove +{ +public: + AddressRegisterUpdate(const Opcode* oco, const UINT16 word0, const UINT16 word1) : ParallelMove(oco) + { + m_ea = ""; + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + reg_id r; + decode_RR_table(BITSn(word0,0x0300), r); + assemble_ea_from_z_table(BITSn(word0,0x0400), regIDAsNum(r), m_ea); + + return true; + } + void disassemble(std::string& retString) const + { + retString = m_ea; + } + void evaluate() {} + +private: + std::string m_ea; +}; + + +/* X Memory Data Move with short displacement : 0000 0101 BBBB BBBB ---- HHHW .... .... : A-139 */ +class XMemoryDataMoveWithShortDisplacement: public ParallelMove +{ +public: + XMemoryDataMoveWithShortDisplacement(const Opcode* oco, const UINT16 word0, const UINT16 word1) : ParallelMove(oco) + { + m_source = ""; + m_destination = ""; + m_valid = decode(word0, word1); + } + bool decode(const UINT16 word0, const UINT16 word1) + { + INT8 b; + reg_id SD; + std::string args; + + b = (char)(word0 & 0x00ff); + decode_HHH_table(BITSn(word1,0x0e00), SD); + assemble_reg_from_W_table(BITSn(word1,0x0100), 'X', SD, b, m_source, m_destination); + + return true; + } + void disassemble(std::string& retString) const + { + retString = m_source + "," + m_destination; + } + void evaluate() {} + +private: + std::string m_source; + std::string m_destination; +}; + +} +#endif diff --git a/src/devices/cpu/dsp56k/tables.c b/src/devices/cpu/dsp56k/tables.c new file mode 100644 index 00000000000..5837580409e --- /dev/null +++ b/src/devices/cpu/dsp56k/tables.c @@ -0,0 +1,899 @@ +// license:BSD-3-Clause +// copyright-holders:Andrew Gardner +#include +#include +#include + +#include "tables.h" +#include "dsp56def.h" + +namespace DSP56K +{ +/******************/ +/* Table decoding */ +/******************/ +bfShift decode_BBB_table(UINT16 BBB) +{ + switch(BBB) + { + case 0x4: return BBB_UPPER; + case 0x2: return BBB_MIDDLE; + case 0x1: return BBB_LOWER; + } + + return BBB_INVALID; +} + +void decode_cccc_table(const UINT16 cccc, op_mnem& mnemonic) +{ + switch (cccc) + { + case 0x0: mnemonic = oCC; break; + case 0x1: mnemonic = oGE; break; + case 0x2: mnemonic = oNE; break; + case 0x3: mnemonic = oPL; break; + case 0x4: mnemonic = oNN; break; + case 0x5: mnemonic = oEC; break; + case 0x6: mnemonic = oLC; break; + case 0x7: mnemonic = oGT; break; + case 0x8: mnemonic = oCS; break; + case 0x9: mnemonic = oLT; break; + case 0xa: mnemonic = oEQ; break; + case 0xb: mnemonic = oMI; break; + case 0xc: mnemonic = oNR; break; + case 0xd: mnemonic = oES; break; + case 0xe: mnemonic = oLS; break; + case 0xf: mnemonic = oLE; break; + } + +// NEW // switch (cccc) +// NEW // { +// NEW // case 0x0: sprintf(mnemonic, "cc(hs)"); break; +// NEW // case 0x1: sprintf(mnemonic, "ge "); break; +// NEW // case 0x2: sprintf(mnemonic, "ne "); break; +// NEW // case 0x3: sprintf(mnemonic, "pl "); break; +// NEW // case 0x4: sprintf(mnemonic, "nn "); break; +// NEW // case 0x5: sprintf(mnemonic, "ec "); break; +// NEW // case 0x6: sprintf(mnemonic, "lc "); break; +// NEW // case 0x7: sprintf(mnemonic, "gt "); break; +// NEW // case 0x8: sprintf(mnemonic, "cs(lo)"); break; +// NEW // case 0x9: sprintf(mnemonic, "lt "); break; +// NEW // case 0xa: sprintf(mnemonic, "eq "); break; +// NEW // case 0xb: sprintf(mnemonic, "mi "); break; +// NEW // case 0xc: sprintf(mnemonic, "nr "); break; +// NEW // case 0xd: sprintf(mnemonic, "es "); break; +// NEW // case 0xe: sprintf(mnemonic, "ls "); break; +// NEW // case 0xf: sprintf(mnemonic, "le "); break; +// NEW // } +} + +void decode_DDDDD_table(const UINT16 DDDDD, reg_id& SD) +{ + switch(DDDDD) + { + case 0x00: SD = iX0; break; + case 0x01: SD = iY0; break; + case 0x02: SD = iX1; break; + case 0x03: SD = iY1; break; + case 0x04: SD = iA; break; + case 0x05: SD = iB; break; + case 0x06: SD = iA0; break; + case 0x07: SD = iB0; break; + case 0x08: SD = iLC; break; + case 0x09: SD = iSR; break; + case 0x0a: SD = iOMR; break; + case 0x0b: SD = iSP; break; + case 0x0c: SD = iA1; break; + case 0x0d: SD = iB1; break; + case 0x0e: SD = iA2; break; + case 0x0f: SD = iB2; break; + + case 0x10: SD = iR0; break; + case 0x11: SD = iR1; break; + case 0x12: SD = iR2; break; + case 0x13: SD = iR3; break; + case 0x14: SD = iM0; break; + case 0x15: SD = iM1; break; + case 0x16: SD = iM2; break; + case 0x17: SD = iM3; break; + case 0x18: SD = iSSH; break; + case 0x19: SD = iSSL; break; + case 0x1a: SD = iLA; break; + case 0x1b: SD = iINVALID; break; /* no 0x1b */ + case 0x1c: SD = iN0; break; + case 0x1d: SD = iN1; break; + case 0x1e: SD = iN2; break; + case 0x1f: SD = iN3; break; + } +} + +void decode_DD_table(const UINT16 DD, reg_id& SD) +{ + switch (DD) + { + case 0x0: SD = iX0; break; + case 0x1: SD = iY0; break; + case 0x2: SD = iX1; break; + case 0x3: SD = iY1; break; + } +} + +void decode_DDF_table(const UINT16 DD, const UINT16 F, reg_id& S, reg_id& D) +{ + const UINT16 switchVal = (DD << 1) | F; + + switch (switchVal) + { + case 0x0: S = iX0; D = iA; break; + case 0x1: S = iX0; D = iB; break; + case 0x2: S = iY0; D = iA; break; + case 0x3: S = iY0; D = iB; break; + case 0x4: S = iX1; D = iA; break; + case 0x5: S = iX1; D = iB; break; + case 0x6: S = iY1; D = iA; break; + case 0x7: S = iY1; D = iB; break; + } +} + +void decode_EE_table(const UINT16 EE, reg_id& D) +{ + switch(EE) + { + case 0x1: D = iMR; break; + case 0x3: D = iCCR; break; + case 0x2: D = iOMR; break; + } +} + +void decode_F_table(const UINT16 F, reg_id& SD) +{ + switch(F) + { + case 0x0: SD = iA; break; + case 0x1: SD = iB; break; + } +} + +void decode_h0hF_table(const UINT16 h0h, UINT16 F, reg_id& S, reg_id& D) +{ + const UINT16 switchVal = (h0h << 1) | F; + + switch (switchVal) + { + case 0x8: S = iX0; D = iA; break; + case 0x9: S = iX0; D = iB; break; + case 0xa: S = iY0; D = iA; break; + case 0xb: S = iY0; D = iB; break; + case 0x2: S = iA; D = iA; break; + case 0x1: S = iA; D = iB; break; + case 0x0: S = iB; D = iA; break; + case 0x3: S = iB; D = iB; break; + } +} + +void decode_HH_table(const UINT16 HH, reg_id& SD) +{ + switch(HH) + { + case 0x0: SD = iX0; break; + case 0x1: SD = iY0; break; + case 0x2: SD = iA; break; + case 0x3: SD = iB; break; + } +} + +void decode_HHH_table(const UINT16 HHH, reg_id& SD) +{ + switch(HHH) + { + case 0x0: SD = iX0; break; + case 0x1: SD = iY0; break; + case 0x2: SD = iX1; break; + case 0x3: SD = iY1; break; + case 0x4: SD = iA; break; + case 0x5: SD = iB; break; + case 0x6: SD = iA0; break; + case 0x7: SD = iB0; break; + } +} + +void decode_IIIIx_table(const UINT16 IIII, const UINT16 x, reg_id& S, reg_id& D) +{ + S = D = iINVALID; + switch(IIII) + { + case 0x0: S = iX0; D = iFHAT; break; + case 0x1: S = iY0; D = iFHAT; break; + case 0x2: S = iX1; D = iFHAT; break; + case 0x3: S = iY1; D = iFHAT; break; + case 0x4: S = iA; D = iX0; break; + case 0x5: S = iB; D = iY0; break; + case 0x6: S = iA0; D = iX0; break; + case 0x7: S = iB0; D = iY0; break; + case 0x8: if ( x) S = iF; D = iFHAT; break; + case 0x9: if (!x) S = iF; D = iFHAT; break; + case 0xa: S = iWEIRD; D = iWEIRD; break; + case 0xb: S = iWEIRD; D = iWEIRD; break; + case 0xc: S = iA; D = iX1; break; + case 0xd: S = iB; D = iY1; break; + case 0xe: S = iA0; D = iX1; break; + case 0xf: S = iB0; D = iY1; break; + } +} + +void decode_JJJF_table(const UINT16 JJJ, const UINT16 F, reg_id& S, reg_id& D) +{ + const UINT16 switchVal = (JJJ << 1) | F; + + switch(switchVal) + { + case 0x0: S = iB; D = iA; break; + case 0x1: S = iA; D = iB; break; + case 0x2: S = iINVALID; D = iINVALID; break; + case 0x3: S = iINVALID; D = iINVALID; break; + case 0x4: S = iX; D = iA; break; + case 0x5: S = iX; D = iB; break; + case 0x6: S = iY; D = iA; break; + case 0x7: S = iY; D = iB; break; + case 0x8: S = iX0; D = iA; break; + case 0x9: S = iX0; D = iB; break; + case 0xa: S = iY0; D = iA; break; + case 0xb: S = iY0; D = iB; break; + case 0xc: S = iX1; D = iA; break; + case 0xd: S = iX1; D = iB; break; + case 0xe: S = iY1; D = iA; break; + case 0xf: S = iY1; D = iB; break; + } +} + +void decode_JJF_table(const UINT16 JJ, const UINT16 F, reg_id& S, reg_id& D) +{ + const UINT16 switchVal = (JJ << 1) | F; + + switch (switchVal) + { + case 0x0: S = iX0; D = iA; break; + case 0x1: S = iX0; D = iB; break; + case 0x2: S = iY0; D = iA; break; + case 0x3: S = iY0; D = iB; break; + case 0x4: S = iX1; D = iA; break; + case 0x5: S = iX1; D = iB; break; + case 0x6: S = iY1; D = iA; break; + case 0x7: S = iY1; D = iB; break; + } +} + +void decode_JF_table(const UINT16 J, const UINT16 F, reg_id& S, reg_id& D) +{ + const UINT16 switchVal = (J << 1) | F; + + switch(switchVal) + { + case 0x0: S = iX; D = iA; break; + case 0x1: S = iX; D = iB; break; + case 0x2: S = iY; D = iA; break; + case 0x3: S = iY; D = iB; break; + } +} + +// NEW // void decode_k_table(UINT16 k, char *Dnot) +// NEW // { +// NEW // switch(k) +// NEW // { +// NEW // case 0x0: sprintf(Dnot, "B"); break; +// NEW // case 0x1: sprintf(Dnot, "A"); break; +// NEW // } +// NEW // } + +void decode_kSign_table(const UINT16 k, std::string& plusMinus) +{ + switch(k) + { + case 0x0: plusMinus = "+"; break; + case 0x1: plusMinus = "-"; break; + } +} + +void decode_KKK_table(const UINT16 KKK, reg_id& D1, reg_id& D2) +{ + switch(KKK) + { + case 0x0: D1 = iFHAT; D2 = iX0; break; + case 0x1: D1 = iY0; D2 = iX0; break; + case 0x2: D1 = iX1; D2 = iX0; break; + case 0x3: D1 = iY1; D2 = iX0; break; + case 0x4: D1 = iX0; D2 = iX1; break; + case 0x5: D1 = iY0; D2 = iX1; break; + case 0x6: D1 = iFHAT; D2 = iY0; break; + case 0x7: D1 = iY1; D2 = iX1; break; + } +} + +void decode_NN_table(UINT16 NN, reg_id& ret) +{ + switch(NN) + { + case 0x0: ret = iN0; break; + case 0x1: ret = iN1; break; + case 0x2: ret = iN2; break; + case 0x3: ret = iN3; break; + } +} + +void decode_TT_table(UINT16 TT, reg_id& ret) +{ + switch(TT) + { + case 0x0: ret = iR0; break; + case 0x1: ret = iR1; break; + case 0x2: ret = iR2; break; + case 0x3: ret = iR3; break; + } +} + +void decode_QQF_table(const UINT16 QQ, const UINT16 F, reg_id& S1, reg_id& S2, reg_id& D) +{ + const UINT16 switchVal = (QQ << 1) | F; + + switch(switchVal) + { + case 0x0: S1 = iY0; S2 = iX0; D = iA; break; + case 0x1: S1 = iY0; S2 = iX0; D = iB; break; + case 0x2: S1 = iY1; S2 = iX0; D = iA; break; + case 0x3: S1 = iY1; S2 = iX0; D = iB; break; + case 0x4: S1 = iY0; S2 = iX1; D = iA; break; + case 0x5: S1 = iY0; S2 = iX1; D = iB; break; + case 0x6: S1 = iY1; S2 = iX1; D = iA; break; + case 0x7: S1 = iY1; S2 = iX1; D = iB; break; + } +} + +void decode_QQF_special_table(const UINT16 QQ, const UINT16 F, reg_id& S1, reg_id& S2, reg_id& D) +{ + const UINT16 switchVal = (QQ << 1) | F; + + switch(switchVal) + { + case 0x0: S1 = iY0; S2 = iX0; D = iA; break; + case 0x1: S1 = iY0; S2 = iX0; D = iB; break; + case 0x2: S1 = iY1; S2 = iX0; D = iA; break; + case 0x3: S1 = iY1; S2 = iX0; D = iB; break; + case 0x4: S1 = iX1; S2 = iY0; D = iA; break; + case 0x5: S1 = iX1; S2 = iY0; D = iB; break; + case 0x6: S1 = iX1; S2 = iY1; D = iA; break; + case 0x7: S1 = iX1; S2 = iY1; D = iB; break; + } +} + +void decode_QQQF_table(const UINT16 QQQ, const UINT16 F, reg_id& S1, reg_id& S2, reg_id& D) +{ + const UINT16 switchVal = (QQQ << 1) | F; + + switch(switchVal) + { + case 0x0: S1 = iX0; S2 = iX0; D = iA; break; + case 0x1: S1 = iX0; S2 = iX0; D = iB; break; + case 0x2: S1 = iX1; S2 = iX0; D = iA; break; + case 0x3: S1 = iX1; S2 = iX0; D = iB; break; + case 0x4: S1 = iA1; S2 = iY0; D = iA; break; + case 0x5: S1 = iA1; S2 = iY0; D = iB; break; + case 0x6: S1 = iB1; S2 = iX0; D = iA; break; + case 0x7: S1 = iB1; S2 = iX0; D = iB; break; + case 0x8: S1 = iY0; S2 = iX0; D = iA; break; + case 0x9: S1 = iY0; S2 = iX0; D = iB; break; + case 0xa: S1 = iY1; S2 = iX0; D = iA; break; + case 0xb: S1 = iY1; S2 = iX0; D = iB; break; + case 0xc: S1 = iY0; S2 = iX1; D = iA; break; + case 0xd: S1 = iY0; S2 = iX1; D = iB; break; + case 0xe: S1 = iY1; S2 = iX1; D = iA; break; + case 0xf: S1 = iY1; S2 = iX1; D = iB; break; + } +} + +void decode_RR_table(UINT16 RR, reg_id& ret) +{ + switch(RR) + { + case 0x0: ret = iR0; break; + case 0x1: ret = iR1; break; + case 0x2: ret = iR2; break; + case 0x3: ret = iR3; break; + } +} + +void decode_rr_table(UINT16 rr, reg_id& ret) +{ + switch(rr) + { + case 0x0: ret = iR0; break; + case 0x1: ret = iR1; break; + case 0x2: ret = iR2; break; + case 0x3: ret = iR3; break; + } +} + +void decode_s_table(const UINT16 s, op_mnem& arithmetic) +{ + switch(s) + { + case 0x0: arithmetic = oSU; break; + case 0x1: arithmetic = oUU; break; + } +} + +void decode_ss_table(const UINT16 ss, op_mnem& arithmetic) +{ + switch(ss) + { + case 0x0: arithmetic = oSS; break; + case 0x1: arithmetic = oINVALID; break; + // NEW // case 0x1: arithmetic = "ss"; break; + case 0x2: arithmetic = oSU; break; + case 0x3: arithmetic = oUU; break; + } +} + +void decode_uuuuF_table(const UINT16 uuuu, const UINT16 F, std::string& arg, reg_id& S, reg_id& D) +{ + const UINT16 switchVal = (uuuu << 1) | F; + + //D = "sub?"; + //S = "add"; + arg = "invalid"; + + switch(switchVal) + { + case 0x00: arg = "add"; S = iX0; D = iA; break; + case 0x01: arg = "add"; S = iX0; D = iB; break; + case 0x02: arg = "add"; S = iY0; D = iA; break; + case 0x03: arg = "add"; S = iY0; D = iB; break; + case 0x04: arg = "add"; S = iX1; D = iA; break; + case 0x05: arg = "add"; S = iX1; D = iB; break; + case 0x06: arg = "add"; S = iY1; D = iA; break; + case 0x07: arg = "add"; S = iY1; D = iB; break; + + case 0x08: arg = "sub"; S = iX0; D = iA; break; + case 0x09: arg = "sub"; S = iX0; D = iB; break; + case 0x0a: arg = "sub"; S = iY0; D = iA; break; + case 0x0b: arg = "sub"; S = iY0; D = iB; break; + case 0x0c: arg = "sub"; S = iX1; D = iA; break; + case 0x0d: arg = "sub"; S = iX1; D = iB; break; + case 0x0e: arg = "sub"; S = iY1; D = iA; break; + case 0x0f: arg = "sub"; S = iY1; D = iB; break; + + case 0x18: arg = "add"; S = iB; D = iA; break; + case 0x19: arg = "add"; S = iA; D = iB; break; + + case 0x1a: arg = "sub"; S = iB; D = iA; break; + case 0x1b: arg = "sub"; S = iA; D = iB; break; + + case 0x1c: arg = "tfr"; S = iB; D = iA; break; + case 0x1d: arg = "tfr"; S = iA; D = iB; break; + + case 0x1e: arg = "move"; S = iINVALID; D = iINVALID; break; + case 0x1f: arg = "move"; S = iINVALID; D = iINVALID; break; + } +} + +void decode_Z_table(const UINT16 Z, std::string& ea) +{ + /* This is fixed as per the Family Manual errata addendum */ + switch(Z) + { + case 0x1: ea = "(A1)"; break; + case 0x0: ea = "(B1)"; break; + } +} + +void assemble_ea_from_m_table(const UINT16 m, const int n, std::string& ea) +{ + char temp[32]; + switch(m) + { + case 0x0: sprintf(temp, "(R%d)+",n) ; break; + case 0x1: sprintf(temp, "(R%d)+N%d", n, n); break; + } + ea = temp; +} + +void assemble_eas_from_mm_table(UINT16 mm, int n1, int n2, std::string& ea1, std::string& ea2) +{ + char temp1[32]; + char temp2[32]; + switch(mm) + { + case 0x0: sprintf(temp1, "(R%d)+", n1) ; + sprintf(temp2, "(R%d)+", n2) ; break; + case 0x1: sprintf(temp1, "(R%d)+", n1) ; + sprintf(temp2, "(R%d)+N%d", n2, n2); break; + case 0x2: sprintf(temp1, "(R%d)+N%d", n1, n1); + sprintf(temp2, "(R%d)+", n2) ; break; + case 0x3: sprintf(temp1, "(R%d)+N%d", n1, n1); + sprintf(temp2, "(R%d)+N%d", n2, n2); break; + } + ea1 = temp1; + ea2 = temp2; +} + +void assemble_ea_from_MM_table(UINT16 MM, int n, std::string& ea) +{ + char temp[32]; + switch(MM) + { + case 0x0: sprintf(temp, "(R%d)", n) ; break; + case 0x1: sprintf(temp, "(R%d)+", n) ; break; + case 0x2: sprintf(temp, "(R%d)-", n) ; break; + case 0x3: sprintf(temp, "(R%d)+N%d", n, n); break; + } + ea = temp; +} + +void assemble_ea_from_q_table(UINT16 q, int n, std::string& ea) +{ + char temp[32]; + switch(q) + { + case 0x0: sprintf(temp, "(R%d+N%d)", n, n); break; + case 0x1: sprintf(temp, "-(R%d)", n) ; break; + } + ea = temp; +} + +void assemble_ea_from_t_table(UINT16 t, UINT16 val, std::string& ea) +{ + char temp[32]; + switch(t) + { + case 0x0: sprintf(temp, "X:>$%x", val); break; + case 0x1: sprintf(temp, "#>$%x", val); break; + // NEW // case 0x0: sprintf(ea, "X:$%04x", val); break; + // NEW // case 0x1: sprintf(ea, "#$%04x", val); break; + } + ea = temp; +} + +void assemble_ea_from_z_table(UINT16 z, int n, std::string& ea) +{ + char temp[32]; + switch(z) + { + case 0x0: sprintf(temp, "(R%d)-", n) ; break; + case 0x1: sprintf(temp, "(R%d)+N%d", n, n); break; + } + ea = temp; +} + +void assemble_D_from_P_table(UINT16 P, UINT16 ppppp, std::string& D) +{ + char temp[32]; + std::string fullAddy; /* Convert Short Absolute Address to full 16-bit */ + + switch(P) + { + case 0x0: + sprintf(temp, "X:<$%x", ppppp); + // NEW // sprintf(temp, "X:$%02x", ppppp); + break; + case 0x1: + assemble_address_from_IO_short_address(ppppp, fullAddy); + sprintf(temp, "X:<<$%s", fullAddy.c_str()); + // NEW // sprintf(temp, "X:$%s", fullAddy.c_str()); + break; + } + D = temp; +} + +void assemble_arguments_from_W_table(UINT16 W, char ma, const reg_id& SD, const std::string& ea, + std::string& source, std::string& destination) +{ + char temp[32]; + sprintf(temp, "%c:%s", ma, ea.c_str()); + switch(W) + { + case 0x0: source = regIdAsString(SD); destination = temp; break; + case 0x1: source = temp; destination = regIdAsString(SD); break; + } +} + +void assemble_arguments_from_W_table(UINT16 W, char ma, const std::string& SD, const std::string& ea, + std::string& source, std::string& destination) +{ + char temp[32]; + sprintf(temp, "%c:%s", ma, ea.c_str()); + switch(W) + { + case 0x0: source = SD; destination = temp; break; + case 0x1: source = temp; destination = SD; break; + } +} + +void assemble_reg_from_W_table(UINT16 W, char ma, const reg_id& SD, const INT8 xx, std::string& S, std::string& D) +{ + UINT8 abs_xx; + char temp[32]; + char operation[32]; + + if(xx < 0) + sprintf(operation,"-"); + else + sprintf(operation,"+"); + + abs_xx = abs(xx); + + sprintf(temp, "%c:(R2%s$%x)", ma, operation, abs_xx); + // NEW // sprintf(temp, "%c:(R2%s$%02x)", ma, operation, abs_xx); + switch(W) + { + case 0x0: S = regIdAsString(SD); D = temp; break; + case 0x1: S = temp; D = regIdAsString(SD); break; + } +} + +void assemble_address_from_IO_short_address(UINT16 pp, std::string& ea) +{ + char temp[32]; + + UINT16 fullAddy = 0xffe0; + fullAddy |= pp; + + sprintf(temp, "%.04x", fullAddy); + ea = temp; +} + +INT8 get_6_bit_signed_value(UINT16 bits) +{ + UINT16 fullAddy = bits; + if (fullAddy & 0x0020) + fullAddy |= 0xffc0; + + return (INT8)fullAddy; +} + + +/********************/ +/* HELPER FUNCTIONS */ +/********************/ + +UINT16 dsp56k_op_maskn(UINT16 cur, UINT16 mask) +{ + int i; + + UINT16 retVal = (cur & mask); + UINT16 temp = 0x0000; + int offsetCount = 0; + + /* Shift everything right, eliminating 'whitespace'... */ + for (i = 0; i < 16; i++) + { + if (mask & (0x1<> i) & 0x1) << offsetCount); + offsetCount++; + } + } + + return temp; +} + +bool registerOverlap(const reg_id& r0, const size_t bmd, const reg_id& r1) +{ + if (bmd == BM_NONE) + return false; + + if (r0 == r1) + return true; + + if (r0 == iA && (bmd & BM_LOW) && r1 == iA0) return true; + if (r0 == iA && (bmd & BM_MIDDLE) && r1 == iA1) return true; + if (r0 == iA && (bmd & BM_HIGH) && r1 == iA2) return true; + + if (r0 == iB && (bmd & BM_LOW) && r1 == iB0) return true; + if (r0 == iB && (bmd & BM_MIDDLE) && r1 == iB1) return true; + if (r0 == iB && (bmd & BM_HIGH) && r1 == iB2) return true; + + return false; +} + +UINT16 regValue16(dsp56k_core* cpustate, const reg_id& reg) +{ + if (reg == iX0) return X0; + if (reg == iX1) return X1; + if (reg == iY0) return Y0; + if (reg == iY1) return Y1; + + if (reg == iA0) return A0; + if (reg == iA1) return A1; + if (reg == iB0) return B0; + if (reg == iB1) return B1; + + if (reg == iR0) return R0; + if (reg == iR1) return R1; + if (reg == iR2) return R2; + if (reg == iR3) return R3; + + if (reg == iN0) return N0; + if (reg == iN1) return N1; + if (reg == iN2) return N2; + if (reg == iN3) return N3; + + if (reg == iM0) return M0; + if (reg == iM1) return M1; + if (reg == iM2) return M2; + if (reg == iM3) return M3; + + osd_printf_debug("The dsp561xx core is requesting a 16 bit value from non-16 bit register!"); + return 0xdead; +} + +void setReg16(dsp56k_core* cpustate, const UINT16& value, const reg_id& reg) +{ + if (reg == iX0) X0 = value; + if (reg == iX1) X1 = value; + if (reg == iY0) Y0 = value; + if (reg == iY1) Y1 = value; + + if (reg == iA0) A0 = value; + if (reg == iA1) A1 = value; + if (reg == iB0) B0 = value; + if (reg == iB1) B1 = value; + + if (reg == iR0) R0 = value; + if (reg == iR1) R1 = value; + if (reg == iR2) R2 = value; + if (reg == iR3) R3 = value; + + if (reg == iN0) N0 = value; + if (reg == iN1) N1 = value; + if (reg == iN2) N2 = value; + if (reg == iN3) N3 = value; + + if (reg == iM0) M0 = value; + if (reg == iM1) M1 = value; + if (reg == iM2) M2 = value; + if (reg == iM3) M3 = value; +} + +std::string regIdAsString(const reg_id& regId) +{ + switch(regId) + { + case iX: return "X"; + case iX0: return "X0"; + case iX1: return "X1"; + case iY: return "Y"; + case iY0: return "Y0"; + case iY1: return "Y1"; + case iA: return "A"; + case iA0: return "A0"; + case iA1: return "A1"; + case iA2: return "A2"; + case iB: return "B"; + case iB0: return "B0"; + case iB1: return "B1"; + case iB2: return "B2"; + case iR0: return "R0"; + case iR1: return "R1"; + case iR2: return "R2"; + case iR3: return "R3"; + case iN0: return "N0"; + case iN1: return "N1"; + case iN2: return "N2"; + case iN3: return "N3"; + case iM0: return "M0"; + case iM1: return "M1"; + case iM2: return "M2"; + case iM3: return "M3"; + case iLC: return "LC"; + case iSR: return "SR"; + case iOMR: return "OMR"; + case iSP: return "SP"; + case iSSH: return "SSH"; + case iSSL: return "SSL"; + case iLA: return "LA"; + case iMR: return "MR"; + case iCCR: return "CCR"; + case iF: return "F"; + case iFHAT: return "^F"; + case iINVALID: return "!!"; + case iWEIRD: return "?"; + } + + return "INVALID_REG_ID"; +} + +std::string opMnemonicAsString(const op_mnem& mnem) +{ + switch(mnem) + { + case oCC: return "cc"; + case oGE: return "ge"; + case oNE: return "ne"; + case oPL: return "pl"; + case oNN: return "nn"; + case oEC: return "ec"; + case oLC: return "lc"; + case oGT: return "gt"; + case oCS: return "cs"; + case oLT: return "lt"; + case oEQ: return "eq"; + case oMI: return "mi"; + case oNR: return "nr"; + case oES: return "es"; + case oLS: return "ls"; + case oLE: return "le"; + + case oSS: return "ss"; + case oSU: return "su"; + case oUU: return "uu"; + case oINVALID: return "!!"; + } + + return "INVALID_OPCODE_MNEMONIC"; +} + +reg_id stringAsRegID(const std::string& str) +{ + if (str.compare("X")==0) return iX; + if (str.compare("X0") == 0) return iX0; + if (str.compare("X1") == 0) return iX1; + if (str.compare("Y") == 0) return iY; + if (str.compare("Y0") == 0) return iY0; + if (str.compare("Y1") == 0) return iY1; + if (str.compare("A") == 0) return iA; + if (str.compare("A0") == 0) return iA0; + if (str.compare("A1") == 0) return iA1; + if (str.compare("A2") == 0) return iA2; + if (str.compare("B") == 0) return iB; + if (str.compare("B0") == 0) return iB0; + if (str.compare("B1") == 0) return iB1; + if (str.compare("B2") == 0) return iB2; + if (str.compare("R0") == 0) return iR0; + if (str.compare("R1") == 0) return iR1; + if (str.compare("R2") == 0) return iR2; + if (str.compare("R3") == 0) return iR3; + if (str.compare("N0") == 0) return iN0; + if (str.compare("N1") == 0) return iN1; + if (str.compare("N2") == 0) return iN2; + if (str.compare("N3") == 0) return iN3; + if (str.compare("M0") == 0) return iM0; + if (str.compare("M1") == 0) return iM1; + if (str.compare("M2") == 0) return iM2; + if (str.compare("M3") == 0) return iM3; + if (str.compare("LC") == 0) return iLC; + if (str.compare("SR") == 0) return iSR; + if (str.compare("OMR") == 0) return iOMR; + if (str.compare("SP") == 0) return iSP; + if (str.compare("SSH") == 0) return iSSH; + if (str.compare("SSL") == 0) return iSSL; + if (str.compare("LA") == 0) return iLA; + if (str.compare("MR") == 0) return iMR; + if (str.compare("CCR") == 0) return iCCR; + if (str.compare("F") == 0) return iF; + if (str.compare("^F") == 0) return iFHAT; + if (str.compare("!!") == 0) return iINVALID; + if (str.compare("?") == 0)return iWEIRD; + + return iINVALID; +} + +UINT8 regIDAsNum(const reg_id& regId) +{ + if (regId == iR0) return 0; + if (regId == iR1) return 1; + if (regId == iR2) return 2; + if (regId == iR3) return 3; + + if (regId == iN0) return 0; + if (regId == iN1) return 1; + if (regId == iN2) return 2; + if (regId == iN3) return 3; + + if (regId == iM0) return 0; + if (regId == iM1) return 1; + if (regId == iM2) return 2; + if (regId == iM3) return 3; + + return 255; +} + +} diff --git a/src/devices/cpu/dsp56k/tables.h b/src/devices/cpu/dsp56k/tables.h new file mode 100644 index 00000000000..f0bb88f21d8 --- /dev/null +++ b/src/devices/cpu/dsp56k/tables.h @@ -0,0 +1,94 @@ +// license:BSD-3-Clause +// copyright-holders:Andrew Gardner +#ifndef __DSP56K_OPS_H__ +#define __DSP56K_OPS_H__ + +#include +#include + +#include "emu.h" +#include "dsp56k.h" + +namespace DSP56K +{ +#define BITSn(CUR,MASK) (dsp56k_op_maskn(CUR,MASK)) + +enum bitsModified {BM_NONE = 0x0, BM_LOW = 0x1, BM_MIDDLE = 0x2, BM_HIGH = 0x4}; + +enum bfShift {BBB_UPPER, BBB_MIDDLE, BBB_LOWER, BBB_INVALID}; +enum reg_id {iX, iX0, iX1, + iY, iY0, iY1, + iA, iA0, iA1, iA2, + iB, iB0, iB1, iB2, + iR0, iR1, iR2, iR3, + iN0, iN1, iN2, iN3, + iM0, iM1, iM2, iM3, + iLC, iSR, iOMR, iSP, iSSH, iSSL, iLA, iMR, iCCR, + iF, iFHAT, + iINVALID, iWEIRD}; + +enum op_mnem {oCC, oGE, oNE, oPL, + oNN, oEC, oLC, oGT, + oCS, oLT, oEQ, oMI, + oNR, oES, oLS, oLE, + oSS, oSU, oUU, oINVALID}; + + +bfShift decode_BBB_table(UINT16 BBB); +void decode_cccc_table(const UINT16 cccc, op_mnem& mnemonic); +void decode_DDDDD_table(const UINT16 DDDDD, reg_id& SD); +void decode_DD_table(const UINT16 DD, reg_id& SD); +void decode_DDF_table(const UINT16 DD, const UINT16 F, reg_id& S, reg_id& D); +void decode_EE_table(const UINT16 EE, reg_id& D); +void decode_F_table(const UINT16 F, reg_id& SD); +void decode_h0hF_table(const UINT16 h0h, UINT16 F, reg_id& S, reg_id& D); +void decode_HH_table(const UINT16 HH, reg_id& SD); +void decode_HHH_table(const UINT16 HHH, reg_id& SD); +void decode_IIIIx_table(const UINT16 IIII, const UINT16 x, reg_id& S, reg_id& D); +void decode_JJJF_table(const UINT16 JJJ, const UINT16 F, reg_id& S, reg_id& D); +void decode_JJF_table(const UINT16 JJ, const UINT16 F, reg_id& S, reg_id& D); +void decode_JF_table(const UINT16 J, const UINT16 F, reg_id& S, reg_id& D); +void decode_kSign_table(const UINT16 k, std::string& plusMinus); +void decode_KKK_table(const UINT16 KKK, reg_id& D1, reg_id& D2); +void decode_NN_table(UINT16 NN, reg_id& ret); +void decode_TT_table(UINT16 TT, reg_id& ret); +void decode_QQF_table(const UINT16 QQ, const UINT16 F, reg_id& S1, reg_id& S2, reg_id& D); +void decode_QQF_special_table(const UINT16 QQ, const UINT16 F, reg_id& S1, reg_id& S2, reg_id& D); +void decode_QQQF_table(const UINT16 QQQ, const UINT16 F, reg_id& S1, reg_id& S2, reg_id& D); +void decode_RR_table(UINT16 RR, reg_id& ret); +void decode_rr_table(UINT16 rr, reg_id& ret); +void decode_s_table(const UINT16 s, op_mnem& arithmetic); +void decode_ss_table(const UINT16 ss, op_mnem& arithmetic); +void decode_uuuuF_table(const UINT16 uuuu, const UINT16 F, std::string& arg, reg_id& S, reg_id& D); +void decode_Z_table(const UINT16 Z, std::string& ea); + +void assemble_ea_from_m_table(const UINT16 m, const int n, std::string& ea); +void assemble_eas_from_mm_table(UINT16 mm, int n1, int n2, std::string& ea1, std::string& ea2); +void assemble_ea_from_MM_table(UINT16 MM, int n, std::string& ea); +void assemble_ea_from_q_table(UINT16 q, int n, std::string& ea); +void assemble_ea_from_t_table(UINT16 t, UINT16 val, std::string& ea); +void assemble_ea_from_z_table(UINT16 z, int n, std::string& ea); +void assemble_D_from_P_table(UINT16 P, UINT16 ppppp, std::string& D); +void assemble_arguments_from_W_table(UINT16 W, char ma, const reg_id& SD, const std::string& ea, std::string& S, std::string& D); +void assemble_arguments_from_W_table(UINT16 W, char ma, const std::string& SD, const std::string& ea, std::string& S, std::string& D); +void assemble_reg_from_W_table(UINT16 W, char ma, const reg_id& SD, const INT8 xx, std::string& S, std::string& D); +void assemble_address_from_IO_short_address(UINT16 pp, std::string& ea); + +INT8 get_6_bit_signed_value(UINT16 bits); + +// Helpers +UINT16 dsp56k_op_maskn(UINT16 cur, UINT16 mask); + +bool registerOverlap(const reg_id& r0, const size_t bmd, const reg_id& r1); + +UINT16 regValue16(dsp56k_core* cpustate, const reg_id& reg); +void setReg16(dsp56k_core* cpustate, const UINT16& value, const reg_id& reg); + +std::string regIdAsString(const reg_id& regId); +std::string opMnemonicAsString(const op_mnem& mnem); +reg_id stringAsRegID(const std::string& str); +UINT8 regIDAsNum(const reg_id& regId); + + +} +#endif diff --git a/src/devices/cpu/e0c6200/e0c6200.c b/src/devices/cpu/e0c6200/e0c6200.c new file mode 100644 index 00000000000..e0b6a2eb8d2 --- /dev/null +++ b/src/devices/cpu/e0c6200/e0c6200.c @@ -0,0 +1,837 @@ +// license:BSD-3-Clause +// copyright-holders:hap +/* + + Seiko Epson E0C6200 CPU core and E0C62 MCU family + + References: + - 1998 MF297-06a E0C6200/E0C6200A Core CPU Manual + - 1998 MF1049-01a E0C6S46 Technical Manual + + E0C6200 is a CPU core used as the basis of many chips, it is not standalone. + Seiko Epson often changed prefixes of their device names. Depending on when, + the E0C6200 is known as SMC6200, E0C6200, S1C6200. + + TODO: + - RLC is part of the r,q opcodes and requires that r == q, what happens otherwise? + - documentation is conflicting on whether or not the zero flag is set on RLC/RRC + +*/ + +#include "e0c6200.h" +#include "debugger.h" + +#include "e0c6200op.inc" + + +// disasm +void e0c6200_cpu_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + switch (entry.index()) + { + case STATE_GENFLAGS: + strprintf(str, "%c%c%c%c", + (m_f & I_FLAG) ? 'I':'i', + (m_f & D_FLAG) ? 'D':'d', + (m_f & Z_FLAG) ? 'Z':'z', + (m_f & C_FLAG) ? 'C':'c' + ); + break; + + default: break; + } +} + +offs_t e0c6200_cpu_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE(e0c6200); + return CPU_DISASSEMBLE_NAME(e0c6200)(this, buffer, pc, oprom, opram, options); +} + + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +enum +{ + E0C6200_PC=1, E0C6200_A, E0C6200_B, + E0C6200_XP, E0C6200_XH, E0C6200_XL, + E0C6200_YP, E0C6200_YH, E0C6200_YL, + E0C6200_SP +}; + +void e0c6200_cpu_device::device_start() +{ + m_program = &space(AS_PROGRAM); + m_data = &space(AS_DATA); + + // zerofill + m_op = 0; + m_prev_op = 0; + m_irq_vector = 0; + m_irq_id = 0; + m_possible_irq = false; + m_halt = m_sleep = false; + m_pc = 0; + m_prev_pc = 0; + m_npc = 0; + m_jpc = 0; + + m_a = 0; + m_b = 0; + m_xp = m_xh = m_xl = 0; + m_yp = m_yh = m_yl = 0; + m_sp = 0; + m_f = 0; + + // register for savestates + save_item(NAME(m_op)); + save_item(NAME(m_prev_op)); + save_item(NAME(m_irq_vector)); + save_item(NAME(m_irq_id)); + save_item(NAME(m_possible_irq)); + save_item(NAME(m_halt)); + save_item(NAME(m_sleep)); + save_item(NAME(m_pc)); + save_item(NAME(m_prev_pc)); + save_item(NAME(m_npc)); + save_item(NAME(m_jpc)); + save_item(NAME(m_a)); + save_item(NAME(m_b)); + save_item(NAME(m_xp)); + save_item(NAME(m_xh)); + save_item(NAME(m_xl)); + save_item(NAME(m_yp)); + save_item(NAME(m_yh)); + save_item(NAME(m_yl)); + save_item(NAME(m_sp)); + save_item(NAME(m_f)); + + // register state for debugger + state_add(E0C6200_PC, "PC", m_pc).formatstr("%04X"); + state_add(E0C6200_A, "A", m_a).formatstr("%01X"); + state_add(E0C6200_B, "B", m_b).formatstr("%01X"); + state_add(E0C6200_XP, "XP", m_xp).formatstr("%01X"); + state_add(E0C6200_XH, "XH", m_xh).formatstr("%01X"); + state_add(E0C6200_XL, "XL", m_xl).formatstr("%01X"); + state_add(E0C6200_YP, "YP", m_yp).formatstr("%01X"); + state_add(E0C6200_YH, "YH", m_yh).formatstr("%01X"); + state_add(E0C6200_YL, "YL", m_yl).formatstr("%01X"); + state_add(E0C6200_SP, "SP", m_sp).formatstr("%02X"); + + state_add(STATE_GENPC, "curpc", m_pc).formatstr("%04X").noshow(); + state_add(STATE_GENFLAGS, "GENFLAGS", m_f).formatstr("%4s").noshow(); + + m_icountptr = &m_icount; +} + + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void e0c6200_cpu_device::device_reset() +{ + m_halt = m_sleep = false; + m_op = 0xfff; // nop + m_pc = 0x100; + m_f &= 3; // decimal flag is 0 on 6200A, undefined on 6200 +} + + + +//------------------------------------------------- +// execute loop +//------------------------------------------------- + +void e0c6200_cpu_device::do_interrupt() +{ + // interrupt handling takes 13* cycles, plus 1 extra if cpu was halted + // *: 12.5 on E0C6200A, does the cpu osc source change polarity or something? + m_icount -= 13; + if (m_halt) + m_icount--; + + m_halt = m_sleep = false; + push_pc(); + m_f &= ~I_FLAG; + + // page 1 of the current bank + m_pc = (m_pc & 0x1000) | 0x100 | m_irq_vector; + + standard_irq_callback(m_irq_id); +} + +void e0c6200_cpu_device::execute_run() +{ + while (m_icount > 0) + { + // check/handle interrupt, but not right after EI or in the middle of a longjump + if (m_possible_irq && (m_op & 0xfe0) != 0xe40 && (m_op & 0xff8) != 0xf48) + { + m_possible_irq = false; + if (m_f & I_FLAG && check_interrupt()) + { + do_interrupt(); + if (m_icount <= 0) + break; + } + } + + // core cpu not running (peripherals still work) + if (m_halt || m_sleep) + { + m_icount = 0; + break; + } + + // remember previous state, prepare pset-longjump + m_prev_op = m_op; + m_prev_pc = m_pc; + m_jpc = ((m_prev_op & 0xfe0) == 0xe40) ? m_npc : (m_prev_pc & 0x1f00); + + // fetch next opcode + debugger_instruction_hook(this, m_pc); + m_op = m_program->read_word(m_pc << 1) & 0xfff; + m_pc = (m_pc & 0x1000) | ((m_pc + 1) & 0x0fff); + + // minimal opcode time is 5 clock cycles, opcodes take 5, 7, or 12 clock cycles + m_icount -= 5; + + // handle opcode + execute_one(); + } +} + + + +//------------------------------------------------- +// execute one +//------------------------------------------------- + +void e0c6200_cpu_device::execute_one() +{ + // legend: + // X = --.XH.XL 8-bit + // Y = --.YH.YL 8-bit + // IX = XP.XH.XL 12-bit index register + // IY = YP.YH.YL 12-bit index register + // MX = data memory at IX + // MY = data memory at IY + // Mn = data memory at 0-F, via 4-bit immediate param + // r/q = 2-bit param directing to A/B/MX/MY + // i = 4-bit immediate param + // e = 8-bit immediate param + // s = 8-bit immediate branch destination + + switch (m_op & 0xf00) + { + // JP s: jump unconditional + case 0x000: + do_branch(); + break; + + // JP C,s: jump if carry + case 0x200: + do_branch(m_f & C_FLAG); + break; + + // JP NC,s: jump if no carry + case 0x300: + do_branch(~m_f & C_FLAG); + break; + + // JP Z,s: jump if zero + case 0x600: + do_branch(m_f & Z_FLAG); + break; + + // JP NZ,s: jump if not zero + case 0x700: + do_branch(~m_f & Z_FLAG); + break; + + // CALL s: call unconditional (on current bank) + case 0x400: + m_icount -= 2; + push_pc(); + m_pc = (m_pc & 0x1000) | (m_jpc & 0x0f00) | (m_op & 0xff); + break; + + // CALZ s: call zero page (on current bank) + case 0x500: + m_icount -= 2; + push_pc(); + m_pc = (m_pc & 0x1000) | (m_op & 0xff); + break; + + // RETD e: return from subroutine, then LBPX MX,e + case 0x100: + m_icount -= 7; + pop_pc(); + // fall through! + + // LBPX MX,e: load memory with 8-bit immediate data, increment X by 2 + case 0x900: + write_mx(m_op & 0xf); inc_x(); + write_mx(m_op >> 4 & 0xf); inc_x(); + break; + + // LD X,e: load X with 8-bit immediate data + case 0xb00: + m_xh = m_op >> 4 & 0xf; + m_xl = m_op & 0xf; + break; + + // LD Y,e: load Y with 8-bit immediate data + case 0x800: + m_yh = m_op >> 4 & 0xf; + m_yl = m_op & 0xf; + break; + + + default: + switch (m_op) + { + // LD r,q: load register with register + case 0xec0: /* m_a = m_a; */ break; + case 0xec1: m_a = m_b; break; + case 0xec2: m_a = read_mx(); break; + case 0xec3: m_a = read_my(); break; + case 0xec4: m_b = m_a; break; + case 0xec5: /* m_b = m_b; */ break; + case 0xec6: m_b = read_mx(); break; + case 0xec7: m_b = read_my(); break; + case 0xec8: write_mx(m_a); break; + case 0xec9: write_mx(m_b); break; + case 0xeca: write_mx(read_mx()); break; + case 0xecb: write_mx(read_my()); break; + case 0xecc: write_my(m_a); break; + case 0xecd: write_my(m_b); break; + case 0xece: write_my(read_mx()); break; + case 0xecf: write_my(read_my()); break; + + // LDPX r,q: LD r,q, then increment X + case 0xee0: /* m_a = m_a; */ inc_x(); break; + case 0xee1: m_a = m_b; inc_x(); break; + case 0xee2: m_a = read_mx(); inc_x(); break; + case 0xee3: m_a = read_my(); inc_x(); break; + case 0xee4: m_b = m_a; inc_x(); break; + case 0xee5: /* m_b = m_b; */ inc_x(); break; + case 0xee6: m_b = read_mx(); inc_x(); break; + case 0xee7: m_b = read_my(); inc_x(); break; + case 0xee8: write_mx(m_a); inc_x(); break; + case 0xee9: write_mx(m_b); inc_x(); break; + case 0xeea: write_mx(read_mx()); inc_x(); break; + case 0xeeb: write_mx(read_my()); inc_x(); break; + case 0xeec: write_my(m_a); inc_x(); break; + case 0xeed: write_my(m_b); inc_x(); break; + case 0xeee: write_my(read_mx()); inc_x(); break; + case 0xeef: write_my(read_my()); inc_x(); break; + + // LDPY r,q: LD r,q, then increment Y + case 0xef0: /* m_a = m_a; */ inc_y(); break; + case 0xef1: m_a = m_b; inc_y(); break; + case 0xef2: m_a = read_mx(); inc_y(); break; + case 0xef3: m_a = read_my(); inc_y(); break; + case 0xef4: m_b = m_a; inc_y(); break; + case 0xef5: /* m_b = m_b; */ inc_y(); break; + case 0xef6: m_b = read_mx(); inc_y(); break; + case 0xef7: m_b = read_my(); inc_y(); break; + case 0xef8: write_mx(m_a); inc_y(); break; + case 0xef9: write_mx(m_b); inc_y(); break; + case 0xefa: write_mx(read_mx()); inc_y(); break; + case 0xefb: write_mx(read_my()); inc_y(); break; + case 0xefc: write_my(m_a); inc_y(); break; + case 0xefd: write_my(m_b); inc_y(); break; + case 0xefe: write_my(read_mx()); inc_y(); break; + case 0xeff: write_my(read_my()); inc_y(); break; + + // LD Xphl/Yphl,r: load IX/IY with register + case 0xe80: m_xp = m_a; break; + case 0xe81: m_xp = m_b; break; + case 0xe82: m_xp = read_mx(); break; + case 0xe83: m_xp = read_my(); break; + case 0xe84: m_xh = m_a; break; + case 0xe85: m_xh = m_b; break; + case 0xe86: m_xh = read_mx(); break; + case 0xe87: m_xh = read_my(); break; + case 0xe88: m_xl = m_a; break; + case 0xe89: m_xl = m_b; break; + case 0xe8a: m_xl = read_mx(); break; + case 0xe8b: m_xl = read_my(); break; + case 0xe90: m_yp = m_a; break; + case 0xe91: m_yp = m_b; break; + case 0xe92: m_yp = read_mx(); break; + case 0xe93: m_yp = read_my(); break; + case 0xe94: m_yh = m_a; break; + case 0xe95: m_yh = m_b; break; + case 0xe96: m_yh = read_mx(); break; + case 0xe97: m_yh = read_my(); break; + case 0xe98: m_yl = m_a; break; + case 0xe99: m_yl = m_b; break; + case 0xe9a: m_yl = read_mx(); break; + case 0xe9b: m_yl = read_my(); break; + + // LD r,Xphl/Yphl: load register with IX/IY + case 0xea0: m_a = m_xp; break; + case 0xea1: m_b = m_xp; break; + case 0xea2: write_mx(m_xp); break; + case 0xea3: write_my(m_xp); break; + case 0xea4: m_a = m_xh; break; + case 0xea5: m_b = m_xh; break; + case 0xea6: write_mx(m_xh); break; + case 0xea7: write_my(m_xh); break; + case 0xea8: m_a = m_xl; break; + case 0xea9: m_b = m_xl; break; + case 0xeaa: write_mx(m_xl); break; + case 0xeab: write_my(m_xl); break; + case 0xeb0: m_a = m_yp; break; + case 0xeb1: m_b = m_yp; break; + case 0xeb2: write_mx(m_yp); break; + case 0xeb3: write_my(m_yp); break; + case 0xeb4: m_a = m_yh; break; + case 0xeb5: m_b = m_yh; break; + case 0xeb6: write_mx(m_yh); break; + case 0xeb7: write_my(m_yh); break; + case 0xeb8: m_a = m_yl; break; + case 0xeb9: m_b = m_yl; break; + case 0xeba: write_mx(m_yl); break; + case 0xebb: write_my(m_yl); break; + + // LD SPhl,r: load stackpointer with register + case 0xfe0: m_sp = (m_sp & 0xf0) | m_a; break; + case 0xfe1: m_sp = (m_sp & 0xf0) | m_b; break; + case 0xfe2: m_sp = (m_sp & 0xf0) | read_mx(); break; + case 0xfe3: m_sp = (m_sp & 0xf0) | read_my(); break; + case 0xff0: m_sp = (m_sp & 0x0f) | m_a << 4; break; + case 0xff1: m_sp = (m_sp & 0x0f) | m_b << 4; break; + case 0xff2: m_sp = (m_sp & 0x0f) | read_mx() << 4; break; + case 0xff3: m_sp = (m_sp & 0x0f) | read_my() << 4; break; + + // LD r,SPhl: load register with stackpointer + case 0xfe4: m_a = m_sp >> 4 & 0xf; break; + case 0xfe5: m_b = m_sp >> 4 & 0xf; break; + case 0xfe6: write_mx(m_sp >> 4 & 0xf); break; + case 0xfe7: write_my(m_sp >> 4 & 0xf); break; + case 0xff4: m_a = m_sp & 0xf; break; + case 0xff5: m_b = m_sp & 0xf; break; + case 0xff6: write_mx(m_sp & 0xf); break; + case 0xff7: write_my(m_sp & 0xf); break; + + // ADD r,q: add register to register (flags: C, Z) + case 0xa80: m_a = op_add(m_a, m_a, D_FLAG); break; + case 0xa81: m_a = op_add(m_a, m_b, D_FLAG); break; + case 0xa82: m_a = op_add(m_a, read_mx(), D_FLAG); break; + case 0xa83: m_a = op_add(m_a, read_my(), D_FLAG); break; + case 0xa84: m_b = op_add(m_b, m_a, D_FLAG); break; + case 0xa85: m_b = op_add(m_b, m_b, D_FLAG); break; + case 0xa86: m_b = op_add(m_b, read_mx(), D_FLAG); break; + case 0xa87: m_b = op_add(m_b, read_my(), D_FLAG); break; + case 0xa88: write_mx(op_add(read_mx(), m_a, D_FLAG)); break; + case 0xa89: write_mx(op_add(read_mx(), m_b, D_FLAG)); break; + case 0xa8a: write_mx(op_add(read_mx(), read_mx(), D_FLAG)); break; + case 0xa8b: write_mx(op_add(read_mx(), read_my(), D_FLAG)); break; + case 0xa8c: write_my(op_add(read_my(), m_a, D_FLAG)); break; + case 0xa8d: write_my(op_add(read_my(), m_b, D_FLAG)); break; + case 0xa8e: write_my(op_add(read_my(), read_mx(), D_FLAG)); break; + case 0xa8f: write_my(op_add(read_my(), read_my(), D_FLAG)); break; + + // ADC r,q: add with carry register to register (flags: C, Z) + case 0xa90: m_a = op_adc(m_a, m_a, D_FLAG); break; + case 0xa91: m_a = op_adc(m_a, m_b, D_FLAG); break; + case 0xa92: m_a = op_adc(m_a, read_mx(), D_FLAG); break; + case 0xa93: m_a = op_adc(m_a, read_my(), D_FLAG); break; + case 0xa94: m_b = op_adc(m_b, m_a, D_FLAG); break; + case 0xa95: m_b = op_adc(m_b, m_b, D_FLAG); break; + case 0xa96: m_b = op_adc(m_b, read_mx(), D_FLAG); break; + case 0xa97: m_b = op_adc(m_b, read_my(), D_FLAG); break; + case 0xa98: write_mx(op_adc(read_mx(), m_a, D_FLAG)); break; + case 0xa99: write_mx(op_adc(read_mx(), m_b, D_FLAG)); break; + case 0xa9a: write_mx(op_adc(read_mx(), read_mx(), D_FLAG)); break; + case 0xa9b: write_mx(op_adc(read_mx(), read_my(), D_FLAG)); break; + case 0xa9c: write_my(op_adc(read_my(), m_a, D_FLAG)); break; + case 0xa9d: write_my(op_adc(read_my(), m_b, D_FLAG)); break; + case 0xa9e: write_my(op_adc(read_my(), read_mx(), D_FLAG)); break; + case 0xa9f: write_my(op_adc(read_my(), read_my(), D_FLAG)); break; + + // ACPX MX,r: ADC MX,r, then increment X (flags: C, Z) + case 0xf28: write_mx(op_adc(read_mx(), m_a, D_FLAG)); inc_x(); break; + case 0xf29: write_mx(op_adc(read_mx(), m_b, D_FLAG)); inc_x(); break; + case 0xf2a: write_mx(op_adc(read_mx(), read_mx(), D_FLAG)); inc_x(); break; + case 0xf2b: write_mx(op_adc(read_mx(), read_my(), D_FLAG)); inc_x(); break; + + // ACPY MY,r: ADC MY,r, then increment Y (flags: C, Z) + case 0xf2c: write_my(op_adc(read_my(), m_a, D_FLAG)); inc_y(); break; + case 0xf2d: write_my(op_adc(read_my(), m_b, D_FLAG)); inc_y(); break; + case 0xf2e: write_my(op_adc(read_my(), read_mx(), D_FLAG)); inc_y(); break; + case 0xf2f: write_my(op_adc(read_my(), read_my(), D_FLAG)); inc_y(); break; + + // SUB r,q: subtract register from register (flags: C, Z) + case 0xaa0: m_a = op_sub(m_a, m_a, D_FLAG); break; + case 0xaa1: m_a = op_sub(m_a, m_b, D_FLAG); break; + case 0xaa2: m_a = op_sub(m_a, read_mx(), D_FLAG); break; + case 0xaa3: m_a = op_sub(m_a, read_my(), D_FLAG); break; + case 0xaa4: m_b = op_sub(m_b, m_a, D_FLAG); break; + case 0xaa5: m_b = op_sub(m_b, m_b, D_FLAG); break; + case 0xaa6: m_b = op_sub(m_b, read_mx(), D_FLAG); break; + case 0xaa7: m_b = op_sub(m_b, read_my(), D_FLAG); break; + case 0xaa8: write_mx(op_sub(read_mx(), m_a, D_FLAG)); break; + case 0xaa9: write_mx(op_sub(read_mx(), m_b, D_FLAG)); break; + case 0xaaa: write_mx(op_sub(read_mx(), read_mx(), D_FLAG)); break; + case 0xaab: write_mx(op_sub(read_mx(), read_my(), D_FLAG)); break; + case 0xaac: write_my(op_sub(read_my(), m_a, D_FLAG)); break; + case 0xaad: write_my(op_sub(read_my(), m_b, D_FLAG)); break; + case 0xaae: write_my(op_sub(read_my(), read_mx(), D_FLAG)); break; + case 0xaaf: write_my(op_sub(read_my(), read_my(), D_FLAG)); break; + + // SBC r,q: subtract with carry register from register (flags: C, Z) + case 0xab0: m_a = op_sbc(m_a, m_a, D_FLAG); break; + case 0xab1: m_a = op_sbc(m_a, m_b, D_FLAG); break; + case 0xab2: m_a = op_sbc(m_a, read_mx(), D_FLAG); break; + case 0xab3: m_a = op_sbc(m_a, read_my(), D_FLAG); break; + case 0xab4: m_b = op_sbc(m_b, m_a, D_FLAG); break; + case 0xab5: m_b = op_sbc(m_b, m_b, D_FLAG); break; + case 0xab6: m_b = op_sbc(m_b, read_mx(), D_FLAG); break; + case 0xab7: m_b = op_sbc(m_b, read_my(), D_FLAG); break; + case 0xab8: write_mx(op_sbc(read_mx(), m_a, D_FLAG)); break; + case 0xab9: write_mx(op_sbc(read_mx(), m_b, D_FLAG)); break; + case 0xaba: write_mx(op_sbc(read_mx(), read_mx(), D_FLAG)); break; + case 0xabb: write_mx(op_sbc(read_mx(), read_my(), D_FLAG)); break; + case 0xabc: write_my(op_sbc(read_my(), m_a, D_FLAG)); break; + case 0xabd: write_my(op_sbc(read_my(), m_b, D_FLAG)); break; + case 0xabe: write_my(op_sbc(read_my(), read_mx(), D_FLAG)); break; + case 0xabf: write_my(op_sbc(read_my(), read_my(), D_FLAG)); break; + + // SCPX MX,r: SBC MX,r, then increment X (flags: C, Z) + case 0xf38: write_mx(op_sbc(read_mx(), m_a, D_FLAG)); inc_x(); break; + case 0xf39: write_mx(op_sbc(read_mx(), m_b, D_FLAG)); inc_x(); break; + case 0xf3a: write_mx(op_sbc(read_mx(), read_mx(), D_FLAG)); inc_x(); break; + case 0xf3b: write_mx(op_sbc(read_mx(), read_my(), D_FLAG)); inc_x(); break; + + // SCPY MY,r: SBC MY,r, then increment Y (flags: C, Z) + case 0xf3c: write_my(op_sbc(read_my(), m_a, D_FLAG)); inc_y(); break; + case 0xf3d: write_my(op_sbc(read_my(), m_b, D_FLAG)); inc_y(); break; + case 0xf3e: write_my(op_sbc(read_my(), read_mx(), D_FLAG)); inc_y(); break; + case 0xf3f: write_my(op_sbc(read_my(), read_my(), D_FLAG)); inc_y(); break; + + // CP r,q: compare: SUB r,q, but discard result (flags: C, Z, no D flag) + case 0xf00: op_sub(m_a, m_a); break; + case 0xf01: op_sub(m_a, m_b); break; + case 0xf02: op_sub(m_a, read_mx()); break; + case 0xf03: op_sub(m_a, read_my()); break; + case 0xf04: op_sub(m_b, m_a); break; + case 0xf05: op_sub(m_b, m_b); break; + case 0xf06: op_sub(m_b, read_mx()); break; + case 0xf07: op_sub(m_b, read_my()); break; + case 0xf08: op_sub(read_mx(), m_a); break; + case 0xf09: op_sub(read_mx(), m_b); break; + case 0xf0a: op_sub(read_mx(), read_mx()); break; + case 0xf0b: op_sub(read_mx(), read_my()); break; + case 0xf0c: op_sub(read_my(), m_a); break; + case 0xf0d: op_sub(read_my(), m_b); break; + case 0xf0e: op_sub(read_my(), read_mx()); break; + case 0xf0f: op_sub(read_my(), read_my()); break; + + // AND r,q: logical AND register with register (flags: Z) + case 0xac0: m_a = op_and(m_a, m_a); break; + case 0xac1: m_a = op_and(m_a, m_b); break; + case 0xac2: m_a = op_and(m_a, read_mx()); break; + case 0xac3: m_a = op_and(m_a, read_my()); break; + case 0xac4: m_b = op_and(m_b, m_a); break; + case 0xac5: m_b = op_and(m_b, m_b); break; + case 0xac6: m_b = op_and(m_b, read_mx()); break; + case 0xac7: m_b = op_and(m_b, read_my()); break; + case 0xac8: write_mx(op_and(read_mx(), m_a)); break; + case 0xac9: write_mx(op_and(read_mx(), m_b)); break; + case 0xaca: write_mx(op_and(read_mx(), read_mx())); break; + case 0xacb: write_mx(op_and(read_mx(), read_my())); break; + case 0xacc: write_my(op_and(read_my(), m_a)); break; + case 0xacd: write_my(op_and(read_my(), m_b)); break; + case 0xace: write_my(op_and(read_my(), read_mx())); break; + case 0xacf: write_my(op_and(read_my(), read_my())); break; + + // FAN r,q: flag-check: AND r,q, but discard result (flags: Z) + case 0xf10: op_and(m_a, m_a); break; + case 0xf11: op_and(m_a, m_b); break; + case 0xf12: op_and(m_a, read_mx()); break; + case 0xf13: op_and(m_a, read_my()); break; + case 0xf14: op_and(m_b, m_a); break; + case 0xf15: op_and(m_b, m_b); break; + case 0xf16: op_and(m_b, read_mx()); break; + case 0xf17: op_and(m_b, read_my()); break; + case 0xf18: op_and(read_mx(), m_a); break; + case 0xf19: op_and(read_mx(), m_b); break; + case 0xf1a: op_and(read_mx(), read_mx()); break; + case 0xf1b: op_and(read_mx(), read_my()); break; + case 0xf1c: op_and(read_my(), m_a); break; + case 0xf1d: op_and(read_my(), m_b); break; + case 0xf1e: op_and(read_my(), read_mx()); break; + case 0xf1f: op_and(read_my(), read_my()); break; + + // OR r,q: logical OR register with register (flags: Z) + case 0xad0: m_a = op_or(m_a, m_a); break; + case 0xad1: m_a = op_or(m_a, m_b); break; + case 0xad2: m_a = op_or(m_a, read_mx()); break; + case 0xad3: m_a = op_or(m_a, read_my()); break; + case 0xad4: m_b = op_or(m_b, m_a); break; + case 0xad5: m_b = op_or(m_b, m_b); break; + case 0xad6: m_b = op_or(m_b, read_mx()); break; + case 0xad7: m_b = op_or(m_b, read_my()); break; + case 0xad8: write_mx(op_or(read_mx(), m_a)); break; + case 0xad9: write_mx(op_or(read_mx(), m_b)); break; + case 0xada: write_mx(op_or(read_mx(), read_mx())); break; + case 0xadb: write_mx(op_or(read_mx(), read_my())); break; + case 0xadc: write_my(op_or(read_my(), m_a)); break; + case 0xadd: write_my(op_or(read_my(), m_b)); break; + case 0xade: write_my(op_or(read_my(), read_mx())); break; + case 0xadf: write_my(op_or(read_my(), read_my())); break; + + // XOR r,q: exclusive-OR register with register (flags: Z) + case 0xae0: m_a = op_xor(m_a, m_a); break; + case 0xae1: m_a = op_xor(m_a, m_b); break; + case 0xae2: m_a = op_xor(m_a, read_mx()); break; + case 0xae3: m_a = op_xor(m_a, read_my()); break; + case 0xae4: m_b = op_xor(m_b, m_a); break; + case 0xae5: m_b = op_xor(m_b, m_b); break; + case 0xae6: m_b = op_xor(m_b, read_mx()); break; + case 0xae7: m_b = op_xor(m_b, read_my()); break; + case 0xae8: write_mx(op_xor(read_mx(), m_a)); break; + case 0xae9: write_mx(op_xor(read_mx(), m_b)); break; + case 0xaea: write_mx(op_xor(read_mx(), read_mx())); break; + case 0xaeb: write_mx(op_xor(read_mx(), read_my())); break; + case 0xaec: write_my(op_xor(read_my(), m_a)); break; + case 0xaed: write_my(op_xor(read_my(), m_b)); break; + case 0xaee: write_my(op_xor(read_my(), read_mx())); break; + case 0xaef: write_my(op_xor(read_my(), read_my())); break; + + // RLC r(,r): rotate register left through carry (flags: C, Z) + case 0xaf0: m_a = op_rlc(m_a); break; + case 0xaf5: m_b = op_rlc(m_b); break; + case 0xafa: read_mx(); write_mx(op_rlc(read_mx())); break; + case 0xaff: read_my(); write_my(op_rlc(read_my())); break; + + // RRC r: rotate register right through carry (flags: C, Z) + case 0xe8c: m_a = op_rrc(m_a); break; + case 0xe8d: m_b = op_rrc(m_b); break; + case 0xe8e: write_mx(op_rrc(read_mx())); break; + case 0xe8f: write_my(op_rrc(read_my())); break; + + // INC SP: increment stackpointer + case 0xfdb: + m_sp++; + break; + + // DEC SP: decrement stackpointer + case 0xfcb: + m_sp--; + break; + + // PUSH r/Xphl/Yphl/F: push register to stack + case 0xfc0: push(m_a); break; + case 0xfc1: push(m_b); break; + case 0xfc2: push(read_mx()); break; + case 0xfc3: push(read_my()); break; + case 0xfc4: push(m_xp); break; + case 0xfc5: push(m_xh); break; + case 0xfc6: push(m_xl); break; + case 0xfc7: push(m_yp); break; + case 0xfc8: push(m_yh); break; + case 0xfc9: push(m_yl); break; + case 0xfca: push(m_f); break; + + // POP r/Xphl/Yphl/F: pop value from stack + case 0xfd0: m_a = pop(); break; + case 0xfd1: m_b = pop(); break; + case 0xfd2: write_mx(pop()); break; + case 0xfd3: write_my(pop()); break; + case 0xfd4: m_xp = pop(); break; + case 0xfd5: m_xh = pop(); break; + case 0xfd6: m_xl = pop(); break; + case 0xfd7: m_yp = pop(); break; + case 0xfd8: m_yh = pop(); break; + case 0xfd9: m_yl = pop(); break; + case 0xfda: m_f = pop(); m_possible_irq = true; break; + + // RETS: return from subroutine, then skip next instruction + case 0xfde: + m_icount -= 7; + pop_pc(); + m_pc = (m_pc & 0x1000) | ((m_pc + 1) & 0x0fff); + break; + + // RET: return from subroutine + case 0xfdf: + m_icount -= 2; + pop_pc(); + break; + + // JPBA: jump indirect using registers A and B + case 0xfe8: + m_pc = m_jpc | m_b << 4 | m_a; + break; + + // HALT: halt (stop cpu core clock) + case 0xff8: + m_halt = true; + break; + + // SLP: sleep (stop source oscillation) + case 0xff9: + m_sleep = true; + break; + + // NOP5: no operation (5 clock cycles) + case 0xffb: + break; + + // NOP7: no operation (7 clock cycles) + case 0xfff: + m_icount -= 2; + break; + + + default: + switch (m_op & 0xff0) + { + // LD r,i: load register with 4-bit immediate data + case 0xe00: m_a = m_op & 0xf; break; + case 0xe10: m_b = m_op & 0xf; break; + case 0xe20: write_mx(m_op & 0xf); break; + case 0xe30: write_my(m_op & 0xf); break; + + // LDPX MX,i: LD MX,i, then increment X + case 0xe60: + write_mx(m_op & 0xf); inc_x(); + break; + + // LDPY MY,i: LD MY,i, then increment Y + case 0xe70: + write_my(m_op & 0xf); inc_y(); + break; + + // LD A,Mn: load A with memory + case 0xfa0: + m_a = read_mn(); + break; + + // LD B,Mn: load B with memory + case 0xfb0: + m_b = read_mn(); + break; + + // LD Mn,A: load memory with A + case 0xf80: + write_mn(m_a); + break; + + // LD Mn,B: load memory with B + case 0xf90: + write_mn(m_b); + break; + + // INC Mn: increment memory (flags: C, Z) + case 0xf60: + write_mn(op_inc(read_mn())); + break; + + // DEC Mn: decrement memory (flags: C, Z) + case 0xf70: + write_mn(op_dec(read_mn())); + break; + + // ADD r,i: add 4-bit immediate data to register (flags: C, Z) + case 0xc00: m_a = op_add(m_a, m_op & 0xf, D_FLAG); break; + case 0xc10: m_b = op_add(m_b, m_op & 0xf, D_FLAG); break; + case 0xc20: write_mx(op_add(read_mx(), m_op & 0xf, D_FLAG)); break; + case 0xc30: write_my(op_add(read_my(), m_op & 0xf, D_FLAG)); break; + + // ADC r,i: add with carry 4-bit immediate data to register (flags: C, Z) + case 0xc40: m_a = op_adc(m_a, m_op & 0xf, D_FLAG); break; + case 0xc50: m_b = op_adc(m_b, m_op & 0xf, D_FLAG); break; + case 0xc60: write_mx(op_adc(read_mx(), m_op & 0xf, D_FLAG)); break; + case 0xc70: write_my(op_adc(read_my(), m_op & 0xf, D_FLAG)); break; + + // ADC Xhl/Yhl,i: add with carry 4-bit immediate data to X/Y (flags: C, Z, no D flag) + case 0xa00: m_xh = op_adc(m_xh, m_op & 0xf); break; + case 0xa10: m_xl = op_adc(m_xl, m_op & 0xf); break; + case 0xa20: m_yh = op_adc(m_yh, m_op & 0xf); break; + case 0xa30: m_yl = op_adc(m_yl, m_op & 0xf); break; + + // SBC r,i: subtract with carry 4-bit immediate data from register (flags: C, Z) + case 0xd40: m_a = op_sbc(m_a, m_op & 0xf, D_FLAG); break; + case 0xd50: m_b = op_sbc(m_b, m_op & 0xf, D_FLAG); break; + case 0xd60: write_mx(op_sbc(read_mx(), m_op & 0xf, D_FLAG)); break; + case 0xd70: write_my(op_sbc(read_my(), m_op & 0xf, D_FLAG)); break; + + // CP r,i: compare: SUB r,i, but discard result (flags: C, Z, no D flag) + case 0xdc0: op_sub(m_a, m_op & 0xf); break; + case 0xdd0: op_sub(m_b, m_op & 0xf); break; + case 0xde0: op_sub(read_mx(), m_op & 0xf); break; + case 0xdf0: op_sub(read_my(), m_op & 0xf); break; + + // CP XH,i: compare: SUB Xhl/Yhl,i, but discard result (flags: C, Z, no D flag) + case 0xa40: op_sub(m_xh, m_op & 0xf); break; + case 0xa50: op_sub(m_xl, m_op & 0xf); break; + case 0xa60: op_sub(m_yh, m_op & 0xf); break; + case 0xa70: op_sub(m_yl, m_op & 0xf); break; + + // AND r,i: logical AND register with 4-bit immediate data (flags: Z) + case 0xc80: m_a = op_and(m_a, m_op & 0xf); break; + case 0xc90: m_b = op_and(m_b, m_op & 0xf); break; + case 0xca0: write_mx(op_and(read_mx(), m_op & 0xf)); break; + case 0xcb0: write_my(op_and(read_my(), m_op & 0xf)); break; + + // FAN r,i: flag-check: AND r,i, but discard result (flags: Z) + case 0xd80: op_and(m_a, m_op & 0xf); break; + case 0xd90: op_and(m_b, m_op & 0xf); break; + case 0xda0: op_and(read_mx(), m_op & 0xf); break; + case 0xdb0: op_and(read_my(), m_op & 0xf); break; + + // OR r,i: logical OR register with 4-bit immediate data (flags: Z) + case 0xcc0: m_a = op_or(m_a, m_op & 0xf); break; + case 0xcd0: m_b = op_or(m_b, m_op & 0xf); break; + case 0xce0: write_mx(op_or(read_mx(), m_op & 0xf)); break; + case 0xcf0: write_my(op_or(read_my(), m_op & 0xf)); break; + + // XOR r,i: exclusive-OR register with 4-bit immediate data (flags: Z) + case 0xd00: m_a = op_xor(m_a, m_op & 0xf); break; + case 0xd10: m_b = op_xor(m_b, m_op & 0xf); break; + case 0xd20: write_mx(op_xor(read_mx(), m_op & 0xf)); break; + case 0xd30: write_my(op_xor(read_my(), m_op & 0xf)); break; + + // SET F,i: set flag(s), this includes opcodes SCF, SZF, SDF, EI + case 0xf40: + m_icount -= 2; + m_f |= (m_op & 0xf); + m_possible_irq = true; + break; + + // RST F,i: reset flag(s), this includes opcodes RCF, RZF, RDF, DI + case 0xf50: + m_icount -= 2; + m_f &= (m_op & 0xf); + break; + + // PSET p: page set, used to set page/bank before a jump instruction + case 0xe40: case 0xe50: + m_npc = m_op << 8 & 0x1f00; + break; + + + // illegal opcode + default: + logerror("%s unknown opcode $%03X at $%04X\n", tag(), m_op, m_prev_pc); + break; + + } // 0xff0 + break; + + } // 0xfff + break; + + } // 0xf00 (big switch) +} diff --git a/src/devices/cpu/e0c6200/e0c6200.h b/src/devices/cpu/e0c6200/e0c6200.h new file mode 100644 index 00000000000..430cc36f6f8 --- /dev/null +++ b/src/devices/cpu/e0c6200/e0c6200.h @@ -0,0 +1,113 @@ +// license:BSD-3-Clause +// copyright-holders:hap +/* + + Seiko Epson E0C6200 CPU core and E0C62 MCU family + +*/ + +#ifndef _E0C6200_H_ +#define _E0C6200_H_ + +#include "emu.h" + + +class e0c6200_cpu_device : public cpu_device +{ +public: + // construction/destruction + e0c6200_cpu_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, address_map_constructor program, address_map_constructor data, const char *shortname, const char *source) + : cpu_device(mconfig, type, name, tag, owner, clock, shortname, source) + , m_program_config("program", ENDIANNESS_BIG, 16, 13, -1, program) + , m_data_config("data", ENDIANNESS_BIG, 8, 12, 0, data) + { } + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_execute_interface overrides + virtual UINT32 execute_min_cycles() const { return 5; } + virtual UINT32 execute_max_cycles() const { return 14; } // longest opcode is 12 cycles, but interrupt service takes up to 14 + virtual UINT32 execute_input_lines() const { return 1; } + virtual void execute_run(); + virtual void execute_one(); + virtual bool check_interrupt() { return false; } // nothing to do by default + virtual void do_interrupt(); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const { return(spacenum == AS_PROGRAM) ? &m_program_config : ((spacenum == AS_DATA) ? &m_data_config : NULL); } + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const { return 2; } + virtual UINT32 disasm_max_opcode_bytes() const { return 2; } + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + virtual void state_string_export(const device_state_entry &entry, std::string &str); + + address_space_config m_program_config; + address_space_config m_data_config; + address_space *m_program; + address_space *m_data; + + UINT16 m_op; + UINT16 m_prev_op; + UINT8 m_irq_vector; // low 4 bits for new programcounter after interrupt + int m_irq_id; // for standard_irq_callback(id) + bool m_possible_irq; // indicates interrupts need to be re-checked + bool m_halt; // cpu halt state + bool m_sleep; // cpu sleep state + int m_icount; + + UINT16 m_pc; // 13-bit programcounter: 1-bit bank, 4-bit page, 8-bit 'step' + UINT16 m_prev_pc; + UINT16 m_npc; // new bank/page prepared by pset + UINT16 m_jpc; // actual bank/page destination for jumps + + // all work registers are 4-bit + UINT8 m_a; // accumulator + UINT8 m_b; // generic + UINT8 m_xp, m_xh, m_xl; // 12-bit index register when combined + UINT8 m_yp, m_yh, m_yl; // " + UINT8 m_sp; // stackpointer (SPH, SPL) + UINT8 m_f; // flags + + // internal data memory read/write + inline UINT8 read_mx(); + inline UINT8 read_my(); + inline UINT8 read_mn(); + inline void write_mx(UINT8 data); + inline void write_my(UINT8 data); + inline void write_mn(UINT8 data); + + // common stack ops + inline void push(UINT8 data); + inline UINT8 pop(); + inline void push_pc(); + inline void pop_pc(); + + // misc internal helpers + inline void set_cf(UINT8 data); + inline void set_zf(UINT8 data); + inline void inc_x(); + inline void inc_y(); + void do_branch(int condition = 1); + + // opcode handlers + UINT8 op_inc(UINT8 x); + UINT8 op_dec(UINT8 x); + UINT8 op_add(UINT8 x, UINT8 y, int decimal = 0); + UINT8 op_adc(UINT8 x, UINT8 y, int decimal = 0); + UINT8 op_sub(UINT8 x, UINT8 y, int decimal = 0); + UINT8 op_sbc(UINT8 x, UINT8 y, int decimal = 0); + + UINT8 op_and(UINT8 x, UINT8 y); + UINT8 op_or(UINT8 x, UINT8 y); + UINT8 op_xor(UINT8 x, UINT8 y); + UINT8 op_rlc(UINT8 x); + UINT8 op_rrc(UINT8 x); +}; + + + +#endif /* _E0C6200_H_ */ diff --git a/src/devices/cpu/e0c6200/e0c6200d.c b/src/devices/cpu/e0c6200/e0c6200d.c new file mode 100644 index 00000000000..4fc0599ac24 --- /dev/null +++ b/src/devices/cpu/e0c6200/e0c6200d.c @@ -0,0 +1,708 @@ +// license:BSD-3-Clause +// copyright-holders:hap +/* + + Seiko Epson E0C6200 disassembler + +*/ + +#include "emu.h" +#include "debugger.h" +#include "e0c6200.h" + +// opcode mnemonics +enum e_mnemonics +{ + em_JP, em_RETD, em_CALL, em_CALZ, + em_LD, em_LBPX, em_ADC, em_CP, em_ADD, em_SUB, em_SBC, em_AND, em_OR, em_XOR, + em_RLC, em_FAN, em_PSET, em_LDPX, em_LDPY, em_SET, em_RST, em_INC, em_DEC, + em_RRC, em_ACPX, em_ACPY, em_SCPX, em_SCPY, em_PUSH, em_POP, + em_RETS, em_RET, em_JPBA, em_HALT, em_SLP, em_NOP5, em_NOP7, + em_NOT, em_SCF, em_SZF, em_SDF, em_EI, em_DI, em_RDF, em_RZF, em_RCF, em_ILL +}; + +static const char *const em_name[] = +{ + "JP", "RETD", "CALL", "CALZ", + "LD", "LBPX", "ADC", "CP", "ADD", "SUB", "SBC", "AND", "OR", "XOR", + "RLC", "FAN", "PSET", "LDPX", "LDPY", "SET", "RST", "INC", "DEC", + "RRC", "ACPX", "ACPY", "SCPX", "SCPY", "PUSH", "POP", + "RETS", "RET", "JPBA", "HALT", "SLP", "NOP5", "NOP7", + "NOT", "SCF", "SZF", "SDF", "EI", "DI", "RDF", "RZF", "RCF", "?" +}; + +#define _OVER DASMFLAG_STEP_OVER +#define _OUT DASMFLAG_STEP_OUT + +static const UINT32 em_flags[] = +{ + 0, _OUT, _OVER, _OVER, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + _OUT, _OUT, 0, _OVER, _OVER, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + + +// opcode params +enum e_params +{ + ep_S, ep_E, ep_I, ep_R0, ep_R2, ep_R4, ep_Q, + ep_cC, ep_cNC, ep_cZ, ep_cNZ, + ep_A, ep_B, ep_X, ep_Y, ep_MX, ep_MY, ep_XP, ep_XH, ep_XL, ep_YP, ep_YH, ep_YL, + ep_P, ep_F, ep_MN, ep_SP, ep_SPH, ep_SPL +}; + +// 0-digit is number of bits per opcode parameter, 0 bits is literal, +// 0x10-digit is for shift-right, 0x100-digit is special flag for r/q param +static const UINT16 ep_bits[] = +{ + 8, 8, 4, 0x102, 0x122, 0x142, 0x102, + 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 5, 0, 4, 0, 0, 0 +}; + +// redirect for r/q param +static const UINT8 ep_redirect_r[4] = { ep_A, ep_B, ep_MX, ep_MY }; + +// literal opcode parameter +static const char *const ep_name[] = +{ + " ", " ", " ", " ", " ", " ", " ", + "C", "NC", "Z", "NZ", + "A", "B", "X", "Y", "MX", "MY", "XP", "XH", "XL", "YP", "YH", "YL", + " ", "F", " ", "SP", "SPH", "SPL" +}; + + +static char* decode_param(UINT16 opcode, int param, char* buffer) +{ + int bits = ep_bits[param] & 0xf; + int shift = ep_bits[param] >> 4 & 0xf; + UINT16 opmask = opcode >> shift & ((1 << bits) - 1); + + // redirect r/q to A/B/MX/MY + if (ep_bits[param] & 0x100) + param = ep_redirect_r[opmask]; + + // literal param + if (ep_bits[param] == 0) + { + strcpy(buffer, ep_name[param]); + return buffer; + } + + // print value like how it's documented in the manual + char val[10]; + if (bits > 4 || opmask > 9) + sprintf(val, "%02XH", opmask); + else + sprintf(val, "%d", opmask); + + if (param == ep_MN) + sprintf(buffer, "M%s", val); + else + strcpy(buffer, val); + + return buffer; +} + + +CPU_DISASSEMBLE(e0c6200) +{ + UINT16 op = (oprom[1] | oprom[0] << 8) & 0xfff; + + int m = -1; + int p1 = -1; + int p2 = -1; + + // determine id for mnemonic and param(s) + switch (op & 0xf00) + { + // JP s + case 0x000: + m = em_JP; p1 = ep_S; + break; + + // RETD e + case 0x100: + m = em_RETD; p1 = ep_E; + break; + + // JP C,s + case 0x200: + m = em_JP; p1 = ep_cC; p2 = ep_S; + break; + + // JP NC,s + case 0x300: + m = em_JP; p1 = ep_cNC; p2 = ep_S; + break; + + // CALL s + case 0x400: + m = em_CALL; p1 = ep_S; + break; + + // CALZ s + case 0x500: + m = em_CALZ; p1 = ep_S; + break; + + // JP Z,s + case 0x600: + m = em_JP; p1 = ep_cZ; p2 = ep_S; + break; + + // JP NZ,s + case 0x700: + m = em_JP; p1 = ep_cNZ; p2 = ep_S; + break; + + // LD Y,e + case 0x800: + m = em_LD; p1 = ep_Y; p2 = ep_E; + break; + + // LBPX MX,e + case 0x900: + m = em_LBPX; p1 = ep_MX; p2 = ep_E; + break; + + // LD X,e + case 0xb00: + m = em_LD; p1 = ep_X; p2 = ep_E; + break; + + + default: + switch (op) + { + // RLC r + case 0xaf0: case 0xaf5: case 0xafa: case 0xaff: + m = em_RLC; p1 = ep_R0; + break; + + // NOT r + case 0xd0f: case 0xd1f: case 0xd2f: case 0xd3f: + m = em_NOT; p1 = ep_R4; + break; + + // LD XP,r + case 0xe80: case 0xe81: case 0xe82: case 0xe83: + m = em_LD; p1 = ep_XP; p2 = ep_R0; + break; + + // LD XH,r + case 0xe84: case 0xe85: case 0xe86: case 0xe87: + m = em_LD; p1 = ep_XH; p2 = ep_R0; + break; + + // LD XL,r + case 0xe88: case 0xe89: case 0xe8a: case 0xe8b: + m = em_LD; p1 = ep_XL; p2 = ep_R0; + break; + + // RRC r + case 0xe8c: case 0xe8d: case 0xe8e: case 0xe8f: + m = em_RRC; p1 = ep_R0; + break; + + // LD YP,r + case 0xe90: case 0xe91: case 0xe92: case 0xe93: + m = em_LD; p1 = ep_YP; p2 = ep_R0; + break; + + // LD YH,r + case 0xe94: case 0xe95: case 0xe96: case 0xe97: + m = em_LD; p1 = ep_YH; p2 = ep_R0; + break; + + // LD YL,r + case 0xe98: case 0xe99: case 0xe9a: case 0xe9b: + m = em_LD; p1 = ep_YL; p2 = ep_R0; + break; + + // LD r,XP + case 0xea0: case 0xea1: case 0xea2: case 0xea3: + m = em_LD; p1 = ep_R0; p2 = ep_XP; + break; + + // LD r,XH + case 0xea4: case 0xea5: case 0xea6: case 0xea7: + m = em_LD; p1 = ep_R0; p2 = ep_XH; + break; + + // LD r,XL + case 0xea8: case 0xea9: case 0xeaa: case 0xeab: + m = em_LD; p1 = ep_R0; p2 = ep_XL; + break; + + // LD r,YP + case 0xeb0: case 0xeb1: case 0xeb2: case 0xeb3: + m = em_LD; p1 = ep_R0; p2 = ep_YP; + break; + + // LD r,YH + case 0xeb4: case 0xeb5: case 0xeb6: case 0xeb7: + m = em_LD; p1 = ep_R0; p2 = ep_YH; + break; + + // LD r,YL + case 0xeb8: case 0xeb9: case 0xeba: case 0xebb: + m = em_LD; p1 = ep_R0; p2 = ep_YL; + break; + + // INC X + case 0xee0: + m = em_INC; p1 = ep_X; + break; + + // INC Y + case 0xef0: + m = em_INC; p1 = ep_Y; + break; + + // ACPX MX,r + case 0xf28: case 0xf29: case 0xf2a: case 0xf2b: + m = em_ACPX; p1 = ep_MX; p2 = ep_R0; + break; + + // ACPY MY,r + case 0xf2c: case 0xf2d: case 0xf2e: case 0xf2f: + m = em_ACPY; p1 = ep_MY; p2 = ep_R0; + break; + + // SCPX MX,r + case 0xf38: case 0xf39: case 0xf3a: case 0xf3b: + m = em_SCPX; p1 = ep_MX; p2 = ep_R0; + break; + + // SCPY MY,r + case 0xf3c: case 0xf3d: case 0xf3e: case 0xf3f: + m = em_SCPY; p1 = ep_MY; p2 = ep_R0; + break; + + // SCF + case 0xf41: + m = em_SCF; + break; + + // SZF + case 0xf42: + m = em_SZF; + break; + + // SDF + case 0xf44: + m = em_SDF; + break; + + // EI + case 0xf48: + m = em_EI; + break; + + // DI + case 0xf57: + m = em_DI; + break; + + // RDF + case 0xf5b: + m = em_RDF; + break; + + // RZF + case 0xf5d: + m = em_RZF; + break; + + // RCF + case 0xf5e: + m = em_RCF; + break; + + // PUSH r + case 0xfc0: case 0xfc1: case 0xfc2: case 0xfc3: + m = em_PUSH; p1 = ep_R0; + break; + + // PUSH XP + case 0xfc4: + m = em_PUSH; p1 = ep_XP; + break; + + // PUSH XH + case 0xfc5: + m = em_PUSH; p1 = ep_XH; + break; + + // PUSH XL + case 0xfc6: + m = em_PUSH; p1 = ep_XL; + break; + + // PUSH YP + case 0xfc7: + m = em_PUSH; p1 = ep_YP; + break; + + // PUSH YH + case 0xfc8: + m = em_PUSH; p1 = ep_YH; + break; + + // PUSH YL + case 0xfc9: + m = em_PUSH; p1 = ep_YL; + break; + + // PUSH F + case 0xfca: + m = em_PUSH; p1 = ep_F; + break; + + // DEC SP + case 0xfcb: + m = em_DEC; p1 = ep_SP; + break; + + // POP r + case 0xfd0: case 0xfd1: case 0xfd2: case 0xfd3: + m = em_POP; p1 = ep_R0; + break; + + // POP XP + case 0xfd4: + m = em_POP; p1 = ep_XP; + break; + + // POP XH + case 0xfd5: + m = em_POP; p1 = ep_XH; + break; + + // POP XL + case 0xfd6: + m = em_POP; p1 = ep_XL; + break; + + // POP YP + case 0xfd7: + m = em_POP; p1 = ep_YP; + break; + + // POP YH + case 0xfd8: + m = em_POP; p1 = ep_YH; + break; + + // POP YL + case 0xfd9: + m = em_POP; p1 = ep_YL; + break; + + // POP F + case 0xfda: + m = em_POP; p1 = ep_F; + break; + + // INC SP + case 0xfdb: + m = em_INC; p1 = ep_SP; + break; + + // RETS + case 0xfde: + m = em_RETS; + break; + + // RET + case 0xfdf: + m = em_RET; + break; + + // LD SPH,r + case 0xfe0: case 0xfe1: case 0xfe2: case 0xfe3: + m = em_LD; p1 = ep_SPH; p2 = ep_R0; + break; + + // LD r,SPH + case 0xfe4: case 0xfe5: case 0xfe6: case 0xfe7: + m = em_LD; p1 = ep_R0; p2 = ep_SPH; + break; + + // JPBA + case 0xfe8: + m = em_JPBA; + break; + + // LD SPL,r + case 0xff0: case 0xff1: case 0xff2: case 0xff3: + m = em_LD; p1 = ep_SPL; p2 = ep_R0; + break; + + // LD r,SPL + case 0xff4: case 0xff5: case 0xff6: case 0xff7: + m = em_LD; p1 = ep_R0; p2 = ep_SPL; + break; + + // HALT + case 0xff8: + m = em_HALT; + break; + + // SLP + case 0xff9: + m = em_SLP; + break; + + // NOP5 + case 0xffb: + m = em_NOP5; + break; + + // NOP7 + case 0xfff: + m = em_NOP7; + break; + + + default: + switch (op & 0xff0) + { + // ADC XH,i + case 0xa00: + m = em_ADC; p1 = ep_XH; p2 = ep_I; + break; + + // ADC XL,i + case 0xa10: + m = em_ADC; p1 = ep_XL; p2 = ep_I; + break; + + // ADC YH,i + case 0xa20: + m = em_ADC; p1 = ep_YH; p2 = ep_I; + break; + + // ADC YL,i + case 0xa30: + m = em_ADC; p1 = ep_YL; p2 = ep_I; + break; + + // CP XH,i + case 0xa40: + m = em_CP; p1 = ep_XH; p2 = ep_I; + break; + + // CP XL,i + case 0xa50: + m = em_CP; p1 = ep_XL; p2 = ep_I; + break; + + // CP YH,i + case 0xa60: + m = em_CP; p1 = ep_YH; p2 = ep_I; + break; + + // CP YL,i + case 0xa70: + m = em_CP; p1 = ep_YL; p2 = ep_I; + break; + + // ADD r,q + case 0xa80: + m = em_ADD; p1 = ep_R2; p2 = ep_Q; + break; + + // ADC r,q + case 0xa90: + m = em_ADC; p1 = ep_R2; p2 = ep_Q; + break; + + // SUB r,q + case 0xaa0: + m = em_SUB; p1 = ep_R2; p2 = ep_Q; + break; + + // SBC r,q + case 0xab0: + m = em_SBC; p1 = ep_R2; p2 = ep_Q; + break; + + // AND r,q + case 0xac0: + m = em_AND; p1 = ep_R2; p2 = ep_Q; + break; + + // OR r,q + case 0xad0: + m = em_OR; p1 = ep_R2; p2 = ep_Q; + break; + + // XOR r,q + case 0xae0: + m = em_XOR; p1 = ep_R2; p2 = ep_Q; + break; + + // ADD r,i + case 0xc00: case 0xc10: case 0xc20: case 0xc30: + m = em_ADD; p1 = ep_R4; p2 = ep_I; + break; + + // ADC r,i + case 0xc40: case 0xc50: case 0xc60: case 0xc70: + m = em_ADC; p1 = ep_R4; p2 = ep_I; + break; + + // AND r,i + case 0xc80: case 0xc90: case 0xca0: case 0xcb0: + m = em_AND; p1 = ep_R4; p2 = ep_I; + break; + + // OR r,i + case 0xcc0: case 0xcd0: case 0xce0: case 0xcf0: + m = em_OR; p1 = ep_R4; p2 = ep_I; + break; + + // XOR r,i + case 0xd00: case 0xd10: case 0xd20: case 0xd30: + m = em_XOR; p1 = ep_R4; p2 = ep_I; + break; + + // SBC r,i + case 0xd40: case 0xd50: case 0xd60: case 0xd70: + m = em_SBC; p1 = ep_R4; p2 = ep_I; + break; + + // FAN r,i + case 0xd80: case 0xd90: case 0xda0: case 0xdb0: + m = em_FAN; p1 = ep_R4; p2 = ep_I; + break; + + // CP r,i + case 0xdc0: case 0xdd0: case 0xde0: case 0xdf0: + m = em_CP; p1 = ep_R4; p2 = ep_I; + break; + + // LD r,i + case 0xe00: case 0xe10: case 0xe20: case 0xe30: + m = em_LD; p1 = ep_R4; p2 = ep_I; + break; + + // PSET p + case 0xe40: case 0xe50: + m = em_PSET; p1 = ep_P; + break; + + // LDPX MX,i + case 0xe60: + m = em_LDPX; p1 = ep_MX; p2 = ep_I; + break; + + // LDPY MY,i + case 0xe70: + m = em_LDPY; p1 = ep_MY; p2 = ep_I; + break; + + // LD r,q + case 0xec0: + m = em_LD; p1 = ep_R2; p2 = ep_Q; + break; + + // LDPX r,q + case 0xee0: + m = em_LDPX; p1 = ep_R2; p2 = ep_Q; + break; + + // LDPY r,q + case 0xef0: + m = em_LDPY; p1 = ep_R2; p2 = ep_Q; + break; + + // CP r,q + case 0xf00: + m = em_CP; p1 = ep_R2; p2 = ep_Q; + break; + + // FAN r,q + case 0xf10: + m = em_FAN; p1 = ep_R2; p2 = ep_Q; + break; + + // SET F,i + case 0xf40: + m = em_SET; p1 = ep_F; p2 = ep_I; + break; + + // RST F,i + case 0xf50: + m = em_RST; p1 = ep_F; p2 = ep_I; + break; + + // INC Mn + case 0xf60: + m = em_INC; p1 = ep_MN; + break; + + // DEC Mn + case 0xf70: + m = em_DEC; p1 = ep_MN; + break; + + // LD Mn,A + case 0xf80: + m = em_LD; p1 = ep_MN; p2 = ep_A; + break; + + // LD Mn,B + case 0xf90: + m = em_LD; p1 = ep_MN; p2 = ep_B; + break; + + // LD A,Mn + case 0xfa0: + m = em_LD; p1 = ep_A; p2 = ep_MN; + break; + + // LD B,Mn + case 0xfb0: + m = em_LD; p1 = ep_B; p2 = ep_MN; + break; + + + // illegal opcode + default: + m = em_ILL; + break; + + } // 0xff0 + break; + + } // 0xfff + break; + + } // 0xf00 (big switch) + + + // fetch mnemonic + char *dst = buffer; + dst += sprintf(dst, "%-6s", em_name[m]); + + // fetch param(s) + char pbuffer[10]; + if (p1 != -1) + { + dst += sprintf(dst, "%s", decode_param(op, p1, pbuffer)); + if (p2 != -1) + { + dst += sprintf(dst, ",%s", decode_param(op, p2, pbuffer)); + } + } + + return 1 | em_flags[m] | DASMFLAG_SUPPORTED; +} diff --git a/src/devices/cpu/e0c6200/e0c6200op.inc b/src/devices/cpu/e0c6200/e0c6200op.inc new file mode 100644 index 00000000000..09fc07b3c70 --- /dev/null +++ b/src/devices/cpu/e0c6200/e0c6200op.inc @@ -0,0 +1,241 @@ +// license:BSD-3-Clause +// copyright-holders:hap + +// E0C6200 opcode handlers + +enum +{ + C_FLAG = 1, + Z_FLAG = 2, + D_FLAG = 4, + I_FLAG = 8 +}; + + +// internal data memory read/write + +// MX/MY + +inline UINT8 e0c6200_cpu_device::read_mx() +{ + UINT16 address = m_xp << 8 | m_xh << 4 | m_xl; + return m_data->read_byte(address) & 0xf; +} + +inline UINT8 e0c6200_cpu_device::read_my() +{ + UINT16 address = m_yp << 8 | m_yh << 4 | m_yl; + return m_data->read_byte(address) & 0xf; +} + +inline void e0c6200_cpu_device::write_mx(UINT8 data) +{ + UINT16 address = m_xp << 8 | m_xh << 4 | m_xl; + m_data->write_byte(address, data); +} + +inline void e0c6200_cpu_device::write_my(UINT8 data) +{ + UINT16 address = m_yp << 8 | m_yh << 4 | m_yl; + m_data->write_byte(address, data); +} + +// Mn(RP) + +inline UINT8 e0c6200_cpu_device::read_mn() +{ + return m_data->read_byte(m_op & 0xf) & 0xf; +} + +inline void e0c6200_cpu_device::write_mn(UINT8 data) +{ + m_data->write_byte(m_op & 0xf, data); +} + + +// common stack ops + +inline void e0c6200_cpu_device::push(UINT8 data) +{ + m_data->write_byte(--m_sp, data); +} + +inline UINT8 e0c6200_cpu_device::pop() +{ + return m_data->read_byte(m_sp++) & 0xf; +} + +inline void e0c6200_cpu_device::push_pc() +{ + // the highest bit(bank bit) is not pushed onto the stack + push(m_pc >> 8 & 0xf); + push(m_pc >> 4 & 0xf); + push(m_pc & 0xf); +} + +inline void e0c6200_cpu_device::pop_pc() +{ + // the highest bit(bank bit) is unchanged + UINT16 bank = m_pc & 0x1000; + m_pc = pop(); + m_pc |= pop() << 4; + m_pc |= pop() << 8; + m_pc |= bank; +} + + +// misc internal helpers + +inline void e0c6200_cpu_device::set_cf(UINT8 data) +{ + // set carry flag if bit 4 is set, reset otherwise + m_f = (m_f & ~C_FLAG) | ((data & 0x10) ? C_FLAG : 0); +} + +inline void e0c6200_cpu_device::set_zf(UINT8 data) +{ + // set zero flag if 4-bit data is 0, reset otherwise + m_f = (m_f & ~Z_FLAG) | ((data & 0xf) ? 0 : Z_FLAG); +} + +inline void e0c6200_cpu_device::inc_x() +{ + // increment X (XH.XL) + m_xl++; + m_xh = (m_xh + (m_xl >> 4 & 1)) & 0xf; + m_xl &= 0xf; +} + +inline void e0c6200_cpu_device::inc_y() +{ + // increment Y (YH.YL) + m_yl++; + m_yh = (m_yh + (m_yl >> 4 & 1)) & 0xf; + m_yl &= 0xf; +} + +void e0c6200_cpu_device::do_branch(int condition) +{ + // branch on condition + if (condition) + m_pc = m_jpc | (m_op & 0xff); +} + + +// common opcodes (simpler ones are handled directly) +// note: it is implied that all opcodes below except RRC take 7 clock cycles (5 already deducted) + +// arithmetic instructions + +UINT8 e0c6200_cpu_device::op_inc(UINT8 x) +{ + // INC x: increment x (flags: C, Z) + m_icount -= 2; + x++; + set_cf(x); set_zf(x); + return x & 0xf; +} + +UINT8 e0c6200_cpu_device::op_dec(UINT8 x) +{ + // DEC x: decrement x (flags: C, Z) + m_icount -= 2; + x--; + set_cf(x); set_zf(x); + return x & 0xf; +} + +UINT8 e0c6200_cpu_device::op_add(UINT8 x, UINT8 y, int decimal) +{ + // ADD x,y: add y to x (flags: C, Z) + m_icount -= 2; + x += y; + set_cf(x); + + // decimal correction + if (m_f & decimal && x >= 10) + { + x -= 10; + m_f |= C_FLAG; + } + + set_zf(x); + return x & 0xf; +} + +UINT8 e0c6200_cpu_device::op_adc(UINT8 x, UINT8 y, int decimal) +{ + // ADC x,y: add with carry y to x (flags: C, Z) + return op_add(x, y + (m_f & 1), decimal); +} + +UINT8 e0c6200_cpu_device::op_sub(UINT8 x, UINT8 y, int decimal) +{ + // SUB x,y: subtract y from x (flags: C, Z) + m_icount -= 2; + x -= y; + set_cf(x); + + // decimal correction (carry remains same) + if (m_f & decimal && m_f & C_FLAG) + x -= 6; + + set_zf(x); + return x & 0xf; +} + +UINT8 e0c6200_cpu_device::op_sbc(UINT8 x, UINT8 y, int decimal) +{ + // SBC x,y: subtract with carry y from x (flags: C, Z) + return op_sub(x, y + (m_f & 1), decimal); +} + + +// logical instructions + +UINT8 e0c6200_cpu_device::op_and(UINT8 x, UINT8 y) +{ + // AND x,y: logical AND x with y (flags: Z) + m_icount -= 2; + x &= y; + set_zf(x); + return x; +} + +UINT8 e0c6200_cpu_device::op_or(UINT8 x, UINT8 y) +{ + // OR x,y: logical OR x with y (flags: Z) + m_icount -= 2; + x |= y; + set_zf(x); + return x; +} + +UINT8 e0c6200_cpu_device::op_xor(UINT8 x, UINT8 y) +{ + // XOR x,y: exclusive-OR x with y (flags: Z) + m_icount -= 2; + x ^= y; + set_zf(x); + return x; +} + +UINT8 e0c6200_cpu_device::op_rlc(UINT8 x) +{ + // RLC x: rotate x left through carry (flags: C, Z) + m_icount -= 2; + x = (x << 1) | (m_f & 1); + set_cf(x); set_zf(x); + return x & 0xf; +} + +UINT8 e0c6200_cpu_device::op_rrc(UINT8 x) +{ + // RRC x: rotate x right through carry (flags: C, Z) + // note: RRC only takes 5 clock cycles + int c = x & 1; + x = (x >> 1) | (m_f << 3 & 8); + m_f = (m_f & ~C_FLAG) | c; + set_zf(x); + return x & 0xf; +} diff --git a/src/devices/cpu/e0c6200/e0c6s46.c b/src/devices/cpu/e0c6200/e0c6s46.c new file mode 100644 index 00000000000..be131a1e5dc --- /dev/null +++ b/src/devices/cpu/e0c6200/e0c6s46.c @@ -0,0 +1,893 @@ +// license:BSD-3-Clause +// copyright-holders:hap +/* + + Seiko Epson E0C6S46 MCU + QFP5-128pin, see manual for pinout + + TODO: + - OSC3 + - K input interrupts + - finish i/o ports + - serial interface + - buzzer envelope addition + - add mask options to MCFG (eg. buzzer on output port R4x is optional) + +*/ + +#include "e0c6s46.h" + +enum +{ + IRQREG_CLKTIMER = 0, + IRQREG_STOPWATCH, + IRQREG_PRGTIMER, + IRQREG_SERIAL, + IRQREG_INPUT0, + IRQREG_INPUT1 +}; + +const device_type E0C6S46 = &device_creator; + + +// internal memory maps +static ADDRESS_MAP_START(e0c6s46_program, AS_PROGRAM, 16, e0c6s46_device) + AM_RANGE(0x0000, 0x17ff) AM_ROM +ADDRESS_MAP_END + + +static ADDRESS_MAP_START(e0c6s46_data, AS_DATA, 8, e0c6s46_device) + AM_RANGE(0x0000, 0x027f) AM_RAM + AM_RANGE(0x0e00, 0x0e4f) AM_RAM AM_SHARE("vram1") + AM_RANGE(0x0e80, 0x0ecf) AM_RAM AM_SHARE("vram2") + AM_RANGE(0x0f00, 0x0f7f) AM_READWRITE(io_r, io_w) +ADDRESS_MAP_END + + +// device definitions +e0c6s46_device::e0c6s46_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : e0c6200_cpu_device(mconfig, E0C6S46, "E0C6S46", tag, owner, clock, ADDRESS_MAP_NAME(e0c6s46_program), ADDRESS_MAP_NAME(e0c6s46_data), "e0c6s46", __FILE__) + , m_vram1(*this, "vram1") + , m_vram2(*this, "vram2") + , m_pixel_update_handler(NULL) + , m_write_r0(*this), m_write_r1(*this), m_write_r2(*this), m_write_r3(*this), m_write_r4(*this) + , m_read_p0(*this), m_read_p1(*this), m_read_p2(*this), m_read_p3(*this) + , m_write_p0(*this), m_write_p1(*this), m_write_p2(*this), m_write_p3(*this) +{ } + + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void e0c6s46_device::device_start() +{ + e0c6200_cpu_device::device_start(); + + // find ports + m_write_r0.resolve_safe(); + m_write_r1.resolve_safe(); + m_write_r2.resolve_safe(); + m_write_r3.resolve_safe(); + m_write_r4.resolve_safe(); + + m_read_p0.resolve_safe(0); + m_read_p1.resolve_safe(0); + m_read_p2.resolve_safe(0); + m_read_p3.resolve_safe(0); + m_write_p0.resolve_safe(); + m_write_p1.resolve_safe(); + m_write_p2.resolve_safe(); + m_write_p3.resolve_safe(); + + // create timers + m_core_256_handle = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(e0c6s46_device::core_256_cb), this)); + m_core_256_handle->adjust(attotime::from_ticks(64, unscaled_clock())); + m_prgtimer_handle = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(e0c6s46_device::prgtimer_cb), this)); + m_prgtimer_handle->adjust(attotime::never); + m_buzzer_handle = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(e0c6s46_device::buzzer_cb), this)); + m_buzzer_handle->adjust(attotime::never); + + // zerofill + memset(m_port_r, 0x0, sizeof(m_port_r)); + m_r_dir = 0; + memset(m_port_p, 0x0, sizeof(m_port_p)); + m_p_dir = 0; + m_p_pullup = 0; + memset(m_port_k, 0xf, sizeof(m_port_k)); + m_dfk0 = 0xf; + + memset(m_irqflag, 0, sizeof(m_irqflag)); + memset(m_irqmask, 0, sizeof(m_irqmask)); + m_osc = 0; + m_svd = 0; + m_lcd_control = 0; + m_lcd_contrast = 0; + + m_256_src_pulse = 0; + m_watchdog_count = 0; + m_clktimer_count = 0; + + m_stopwatch_on = 0; + m_swl_cur_pulse = 0; + m_swl_slice = 0; + m_swl_count = 0; + m_swh_count = 0; + + m_prgtimer_select = 0; + m_prgtimer_on = 0; + m_prgtimer_src_pulse = 0; + m_prgtimer_cur_pulse = 0; + m_prgtimer_count = 0; + m_prgtimer_reload = 0; + + m_bz_43_on = 0; + m_bz_freq = 0; + m_bz_envelope = 0; + m_bz_duty_ratio = 0; + m_bz_1shot_on = 0; + m_bz_1shot_running = false; + m_bz_1shot_count = 0; + m_bz_pulse = 0; + + // register for savestates + save_item(NAME(m_port_r)); + save_item(NAME(m_r_dir)); + save_item(NAME(m_port_p)); + save_item(NAME(m_p_dir)); + save_item(NAME(m_p_pullup)); + save_item(NAME(m_port_k)); + save_item(NAME(m_dfk0)); + + save_item(NAME(m_irqflag)); + save_item(NAME(m_irqmask)); + save_item(NAME(m_osc)); + save_item(NAME(m_svd)); + save_item(NAME(m_lcd_control)); + save_item(NAME(m_lcd_contrast)); + + save_item(NAME(m_256_src_pulse)); + save_item(NAME(m_watchdog_count)); + save_item(NAME(m_clktimer_count)); + + save_item(NAME(m_stopwatch_on)); + save_item(NAME(m_swl_cur_pulse)); + save_item(NAME(m_swl_slice)); + save_item(NAME(m_swl_count)); + save_item(NAME(m_swh_count)); + + save_item(NAME(m_prgtimer_select)); + save_item(NAME(m_prgtimer_on)); + save_item(NAME(m_prgtimer_src_pulse)); + save_item(NAME(m_prgtimer_cur_pulse)); + save_item(NAME(m_prgtimer_count)); + save_item(NAME(m_prgtimer_reload)); + + save_item(NAME(m_bz_43_on)); + save_item(NAME(m_bz_freq)); + save_item(NAME(m_bz_envelope)); + save_item(NAME(m_bz_duty_ratio)); + save_item(NAME(m_bz_1shot_on)); + save_item(NAME(m_bz_1shot_running)); + save_item(NAME(m_bz_1shot_count)); + save_item(NAME(m_bz_pulse)); +} + + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void e0c6s46_device::device_reset() +{ + e0c6200_cpu_device::device_reset(); + + // reset interrupts + memset(m_irqflag, 0, sizeof(m_irqflag)); + memset(m_irqmask, 0, sizeof(m_irqmask)); + + // reset other i/o + m_data->write_byte(0xf41, 0xf); + m_data->write_byte(0xf54, 0xf); + m_data->write_byte(0xf70, 0x0); + m_data->write_byte(0xf71, 0x8); + m_data->write_byte(0xf73, m_svd & 0xc0); + + m_data->write_byte(0xf74, 0x0); + m_data->write_byte(0xf75, 0x4); + m_data->write_byte(0xf76, 0x3); + m_data->write_byte(0xf77, 0x2); + m_data->write_byte(0xf78, 0x2); + m_data->write_byte(0xf79, 0x0); + m_data->write_byte(0xf7a, 0x0); + m_data->write_byte(0xf7b, 0x0); + m_data->write_byte(0xf7d, 0x0); + m_data->write_byte(0xf7e, 0x0); + + // reset ports + for (int i = 0; i < 5; i++) + write_r(i, m_port_r[i]); + for (int i = 0; i < 4; i++) + write_p(i, m_port_p[i]); +} + + + +//------------------------------------------------- +// execute +//------------------------------------------------- + +void e0c6s46_device::execute_one() +{ + // E0C6S46 has no support for SLP opcode + if (m_op == 0xff9) + return; + + e0c6200_cpu_device::execute_one(); +} + + + +//------------------------------------------------- +// interrupts +//------------------------------------------------- + +bool e0c6s46_device::check_interrupt() +{ + // priority order is not the same as register order + static const int priorder[6] = + { + IRQREG_CLKTIMER, + IRQREG_STOPWATCH, + IRQREG_INPUT0, + IRQREG_INPUT1, + IRQREG_SERIAL, + IRQREG_PRGTIMER, + }; + + // check interrupts from high to low priority + for (int pri = 5; pri >= 0; pri--) + { + // hw glitch note, not emulated: if a new interrupt is requested in the + // middle of handling this interrupt, irq vector may be an OR of 2 vectors + m_irq_vector = 2*pri + 2; + int reg = priorder[pri]; + m_irq_id = reg; + + switch (reg) + { + // other: mask vs flag + default: + if (m_irqflag[reg] & m_irqmask[reg]) + return true; + break; + } + } + + return false; +} + +void e0c6s46_device::execute_set_input(int line, int state) +{ + // only support 8 K input lines at the moment + if (line < 0 || line > 7) + return; + + state = (state) ? 1 : 0; + int port = line >> 2 & 1; + UINT8 bit = 1 << (line & 3); + + m_port_k[port] = (m_port_k[port] & ~bit) | (state ? bit : 0); +} + + + +//------------------------------------------------- +// ports +//------------------------------------------------- + +// R output ports + +void e0c6s46_device::write_r(UINT8 port, UINT8 data) +{ + data &= 0xf; + m_port_r[port] = data; + + // ports R0x-R3x can be high-impedance + UINT8 out = data; + if (port < 4 && !(m_r_dir >> port & 1)) + out = 0xf; + + switch (port) + { + case 0: m_write_r0(port, out, 0xff); break; + case 1: m_write_r1(port, out, 0xff); break; + case 2: m_write_r2(port, out, 0xff); break; + case 3: m_write_r3(port, out, 0xff); break; // TODO: R33 PTCLK/_SRDY + + // R4x: special output + case 4: + // d3: buzzer on: direct output or 1-shot output + if ((data & 8) != m_bz_43_on) + { + m_bz_43_on = data & 8; + reset_buzzer(); + } + write_r4_out(); + break; + } +} + +void e0c6s46_device::write_r4_out() +{ + // R40: _FOUT(clock inverted output) + // R42: FOUT or _BZ + // R43: BZ(buzzer) + UINT8 out = (m_port_r[4] & 2) | (m_bz_pulse << 3) | (m_bz_pulse << 2 ^ 4); + m_write_r4(4, out, 0xff); +} + + +// P I/O ports + +void e0c6s46_device::write_p(UINT8 port, UINT8 data) +{ + data &= 0xf; + m_port_p[port] = data; + + // don't output if port direction is set to input + if (!(m_p_dir >> port & 1)) + return; + + switch (port) + { + case 0: m_write_p0(port, data, 0xff); break; + case 1: m_write_p1(port, data, 0xff); break; + case 2: m_write_p2(port, data, 0xff); break; + case 3: m_write_p3(port, data, 0xff); break; + } +} + +UINT8 e0c6s46_device::read_p(UINT8 port) +{ + // return written value if port direction is set to output + if (m_p_dir >> port & 1) + return m_port_p[port]; + + switch (port) + { + case 0: return m_read_p0(port, 0xff); + case 1: return m_read_p1(port, 0xff); + case 2: return m_read_p2(port, 0xff); + case 3: return m_read_p3(port, 0xff); + } + + return 0; +} + + + +//------------------------------------------------- +// timers +//------------------------------------------------- + +TIMER_CALLBACK_MEMBER(e0c6s46_device::core_256_cb) +{ + // clock-timer, stopwatch timer, and some features of the buzzer all run + // from the same internal 256hz timer (64 ticks high+low at default clock of 32768hz) + m_256_src_pulse ^= 1; + m_core_256_handle->adjust(attotime::from_ticks(64, unscaled_clock())); + + // clock stopwatch on falling edge of pulse+on + m_swl_cur_pulse = m_256_src_pulse | (m_stopwatch_on ^ 1); + if (m_swl_cur_pulse == 0) + clock_stopwatch(); + + // clock 1-shot buzzer on rising edge if it's on + if (m_bz_1shot_on != 0 && m_256_src_pulse == 1) + clock_bz_1shot(); + + // clock-timer is always running, advance it on falling edge + // (handle clock_clktimer last in case of watchdog reset) + if (m_256_src_pulse == 0) + clock_clktimer(); +} + + +// clock-timer + +void e0c6s46_device::clock_watchdog() +{ + // initial reset after 3 to 4 seconds + if (++m_watchdog_count == 4) + { + logerror("%s watchdog reset\n", tag()); + m_watchdog_count = 0; + device_reset(); + } +} + +void e0c6s46_device::clock_clktimer() +{ + m_clktimer_count++; + + // irq on falling edge of 32, 8, 2, 1hz + UINT8 flag = 0; + if ((m_clktimer_count & 0x07) == 0) + flag |= 1; + if ((m_clktimer_count & 0x1f) == 0) + flag |= 2; + if ((m_clktimer_count & 0x7f) == 0) + flag |= 4; + if (m_clktimer_count == 0) + flag |= 8; + + m_irqflag[IRQREG_CLKTIMER] |= flag; + if (m_irqflag[IRQREG_CLKTIMER] & m_irqmask[IRQREG_CLKTIMER]) + m_possible_irq = true; + + // 1hz falling edge also clocks the watchdog timer + if (m_clktimer_count == 0) + clock_watchdog(); +} + + +// stopwatch timer + +void e0c6s46_device::clock_stopwatch() +{ + m_swl_slice++; + + // 1 slice is 3 ticks(256hz) on even and 2 ticks on uneven counts, + // but from count 1 to 2 it's 3 ticks, 6 out of 100 times, to make + // exactly 26/256hz * 6 + 25/256hz * 4 = 1 second + int swl_next = 3 - (m_swl_count & 1); + if (m_swl_count == 1 && !(m_swh_count >> 1 & 1)) + swl_next = 3; + + if (m_swl_slice == swl_next) + { + m_swl_slice = 0; + + // bcd counter, irq on falling edge of 10 and 1hz + m_swl_count = (m_swl_count + 1) % 10; + if (m_swl_count == 0) + { + m_irqflag[IRQREG_STOPWATCH] |= 1; + m_swh_count = (m_swh_count + 1) % 10; + if (m_swh_count == 0) + m_irqflag[IRQREG_STOPWATCH] |= 2; + } + + if (m_irqflag[IRQREG_STOPWATCH] & m_irqmask[IRQREG_STOPWATCH]) + m_possible_irq = true; + } +} + + +// programmable timer + +void e0c6s46_device::clock_prgtimer() +{ + // irq and reload when it reaches zero + if (--m_prgtimer_count == 0) + { + m_irqflag[IRQREG_PRGTIMER] |= 1; + if (m_irqflag[IRQREG_PRGTIMER] & m_irqmask[IRQREG_PRGTIMER]) + m_possible_irq = true; + + // note: a reload of 0 indicates a 256-counter + m_prgtimer_count = m_prgtimer_reload; + } +} + +bool e0c6s46_device::prgtimer_reset_prescaler() +{ + // only 2 to 7 are clock dividers + UINT8 sel = m_prgtimer_select & 7; + if (sel >= 2) + m_prgtimer_handle->adjust(attotime::from_ticks(2 << (sel ^ 7), unscaled_clock())); + + return (sel >= 2); +} + +TIMER_CALLBACK_MEMBER(e0c6s46_device::prgtimer_cb) +{ + // check if it's clocked by osc1, schedule next timeout + if (!prgtimer_reset_prescaler()) + return; + + m_prgtimer_src_pulse ^= 1; + m_prgtimer_cur_pulse = m_prgtimer_src_pulse | (m_prgtimer_on ^ 1); + + // clock prgtimer on falling edge of pulse+on + if (m_prgtimer_cur_pulse == 0) + clock_prgtimer(); +} + + +// buzzer + +void e0c6s46_device::schedule_buzzer() +{ + // only schedule next buzzer timeout if it's on + if (m_bz_43_on != 0 && !m_bz_1shot_running) + return; + + // pulse width differs per frequency selection + int mul = (m_bz_freq & 4) ? 1 : 2; + int high = (m_bz_freq & 2) ? 12 : 8; + int low = 16 + (m_bz_freq << 2 & 0xc); + + // pulse width envelope if it's on + if (m_bz_envelope & 1) + high -= m_bz_duty_ratio; + low -= high; + + m_buzzer_handle->adjust(attotime::from_ticks(m_bz_pulse ? high : low, mul * unscaled_clock())); +} + +TIMER_CALLBACK_MEMBER(e0c6s46_device::buzzer_cb) +{ + // invert pulse wave and write to output + m_bz_pulse ^= 1; + write_r4_out(); + + schedule_buzzer(); +} + +void e0c6s46_device::reset_buzzer() +{ + // don't reset if the timer is running + if (m_buzzer_handle->remaining() == attotime::never) + schedule_buzzer(); +} + +void e0c6s46_device::clock_bz_1shot() +{ + m_bz_1shot_running = true; + + // reload counter the 1st time + if (m_bz_1shot_count == 0) + { + reset_buzzer(); + m_bz_1shot_count = (m_bz_freq & 8) ? 16 : 8; + } + + // stop ringing when counter reaches 0 + else if (--m_bz_1shot_count == 0) + { + m_bz_1shot_on = 0; + m_bz_1shot_running = false; + } +} + + + +//------------------------------------------------- +// LCD Driver +//------------------------------------------------- + +UINT32 e0c6s46_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) +{ + // call this 32 times per second (osc1/1024: 32hz at default clock of 32768hz) + for (int bank = 0; bank < 2; bank++) + { + const UINT8* vram = bank ? m_vram2 : m_vram1; + + // determine operating mode + bool lcd_on = false; + int pixel = 0; + if (m_lcd_control & 8 || (bank == 1 && m_lcd_control & 2)) + pixel = 0; + else if (m_lcd_control & 4) + pixel = 1; + else + lcd_on = true; + + // draw pixels + for (int offset = 0; offset < 0x50; offset++) + { + for (int c = 0; c < 4; c++) + { + if (lcd_on) + pixel = vram[offset] >> c & 1; + + // 16 COM(common) pins, 40 SEG(segment) pins + int seg = offset / 2; + int com = bank * 8 + (offset & 1) * 4 + c; + + if (m_pixel_update_handler != NULL) + m_pixel_update_handler(*this, bitmap, cliprect, m_lcd_contrast, seg, com, pixel); + else if (cliprect.contains(seg, com)) + bitmap.pix16(com, seg) = pixel; + } + } + } + + return 0; +} + + + +//------------------------------------------------- +// internal I/O +//------------------------------------------------- + +READ8_MEMBER(e0c6s46_device::io_r) +{ + switch (offset) + { + // irq flags, masks + case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: + { + // irq flags are reset(acked) when read + UINT8 flag = m_irqflag[offset]; + if (!space.debugger_access()) + m_irqflag[offset] = 0; + return flag; + } + case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: + return m_irqmask[offset-0x10]; + + // K input ports + case 0x40: case 0x42: + return m_port_k[offset >> 1 & 1]; + case 0x41: + return m_dfk0; + + // R output ports + case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: + return m_port_r[offset & 7]; + case 0x7b: + return m_r_dir; + + // P I/O ports + case 0x60: case 0x61: case 0x62: case 0x63: + return read_p(offset & 3); + case 0x7d: + return m_p_dir; + case 0x7e: + return m_p_pullup; + + // clock-timer (lo, hi) + case 0x20: case 0x21: + return m_clktimer_count >> (4 * (offset & 1)) & 0xf; + + // stopwatch timer + case 0x22: + return m_swl_count; + case 0x23: + return m_swh_count; + case 0x77: + return m_stopwatch_on; + + // programmable timer + case 0x24: case 0x25: + return m_prgtimer_count >> (4 * (offset & 1)) & 0xf; + case 0x26: case 0x27: + return m_prgtimer_reload >> (4 * (offset & 1)) & 0xf; + case 0x78: + return m_prgtimer_on; + case 0x79: + return m_prgtimer_select; + + // buzzer + case 0x74: + return m_bz_freq; + case 0x75: + // d3: 1-shot buzzer is on + return m_bz_1shot_on | m_bz_envelope; + + // OSC circuit + case 0x70: + return m_osc; + + // LCD driver + case 0x71: + return m_lcd_control; + case 0x72: + return m_lcd_contrast; + + // SVD circuit (supply voltage detection) + case 0x73: + // d3: criteria voltage* is 0: <=, 1: > source voltage (Vdd-Vss) + // *0,1,2,3: -2.2V, -2.5V, -3.1V, -4.2V, 1 when off + return m_svd | ((m_svd & 4 && m_svd != 7) ? 0 : 8); + + // write-only registers + case 0x76: + break; + + default: + if (!space.debugger_access()) + logerror("%s unknown io_r from $0F%02X at $%04X\n", tag(), offset, m_prev_pc); + break; + } + + return 0; +} + +WRITE8_MEMBER(e0c6s46_device::io_w) +{ + switch (offset) + { + // irq masks + case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: + { + static const UINT8 maskmask[6] = { 0xf, 3, 1, 1, 0xf, 0xf }; + m_irqmask[offset-0x10] = data & maskmask[offset-0x10]; + m_possible_irq = true; + break; + } + + // K input ports + case 0x41: + // d0-d3: K0x irq on 0: rising edge, 1: falling edge + m_dfk0 = data; + break; + + // R output ports + case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: + write_r(offset & 7, data); + break; + case 0x7b: + // d0-d3: Rx* direction 0: high-impedance, 1: output + if (data != m_r_dir) + { + m_r_dir = data; + + // refresh outputs + for (int i = 0; i < 5; i++) + write_r(i, m_port_r[i]); + } + break; + + // P I/O ports + case 0x60: case 0x61: case 0x62: case 0x63: + write_p(offset & 3, data); + break; + case 0x7d: + // d0-d3: Px* direction 0: input, 1: output + if (data != m_p_dir) + { + m_p_dir = data; + + // refresh outputs + for (int i = 0; i < 4; i++) + write_p(i, m_port_p[i]); + } + break; + case 0x7e: + // d0-d3: Px* pull up resistor on/off + m_p_pullup = data; + break; + + // OSC circuit + case 0x70: + // d0,d1: CPU operating voltage + // d2: OSC3 on (high freq) + // d3: clock source OSC1 or OSC3 + if (data & 8) + logerror("%s io_w selected OSC3! PC=$%04X\n", tag(), m_prev_pc); + m_osc = data; + break; + + // LCD driver + case 0x71: + // d0: heavy load protection + // d1: duty 1/16 or 1/8 + // d2,d3: all pixels on,off + m_lcd_control = data; + break; + case 0x72: + // contrast adjustment (0=light, 15=dark) + m_lcd_contrast = data; + break; + + // SVD circuit (supply voltage detection) + case 0x73: + // d0,d1: criteria voltage + // d2: on + m_svd = data & 7; + break; + + // clock-timer + case 0x76: + // d0: reset watchdog + // d1: reset clktimer (hw glitch note, not emulated: this also "sometimes"(when??) + // sets the clktimer interrupt and clocks the watchdog) + if (data & 1) + m_watchdog_count = 0; + if (data & 2) + m_clktimer_count = 0; + break; + + // stopwatch timer + case 0x77: + // d0: run/stop counter + // d1: reset stopwatch + m_stopwatch_on = data & 1; + if (data & 2) + { + m_swh_count = 0; + m_swl_count = 0; + m_swl_slice = 0; + } + if (m_stopwatch_on && m_swl_cur_pulse && !m_256_src_pulse) + { + // clock stopwatch on falling edge of pulse+on + m_swl_cur_pulse = 0; + clock_stopwatch(); + } + break; + + // programmable timer + case 0x26: + m_prgtimer_reload = (m_prgtimer_reload & 0xf0) | data; + break; + case 0x27: + m_prgtimer_reload = (m_prgtimer_reload & 0x0f) | data << 4; + break; + + case 0x78: + // d0: run/stop counter + // d1: reset timer + m_prgtimer_on = data & 1; + if (data & 2) + { + m_prgtimer_count = m_prgtimer_reload; + } + if (m_prgtimer_on && (m_prgtimer_select & 7) >= 2 && m_prgtimer_cur_pulse && !m_prgtimer_src_pulse) + { + // if input clock is osc1, clock timer on falling edge of pulse+on + m_prgtimer_cur_pulse = 0; + clock_prgtimer(); + } + break; + + case 0x79: + // d0-d2: input clock select: 2-7 = osc1 divider 256hz-8192hz, + // 0/1 = K03 input (0 enables noise rejector, no need to emulate that) + // d3: output input clock to output port R33 + if ((data & 7) != (m_prgtimer_select & 7)) + { + m_prgtimer_src_pulse = 0; + m_prgtimer_cur_pulse = m_prgtimer_on ^ 1; + m_prgtimer_select = data; + prgtimer_reset_prescaler(); + } + m_prgtimer_select = data; + break; + + // buzzer + case 0x74: + // d0-d2: frequency (8 steps, 4096hz to ~1170hz) + // d3: 1-shot buzzer duration 31.25ms or 62.5ms + m_bz_freq = data; + break; + case 0x75: + // d0: envelope on/off + // d1: envelope cycle selection + // d2: reset envelope + // d3: trigger one-shot buzzer + if (data & 1) + logerror("%s io_w enabled envelope, PC=$%04X\n", tag(), m_prev_pc); + m_bz_envelope = data & 3; + m_bz_1shot_on |= data & 8; + break; + + // read-only registers + case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: + case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: + case 0x40: case 0x42: + break; + + default: + if (machine().phase() > MACHINE_PHASE_RESET) + logerror("%s unknown io_w $%X to $0F%02X at $%04X\n", tag(), data, offset, m_prev_pc); + break; + } +} diff --git a/src/devices/cpu/e0c6200/e0c6s46.h b/src/devices/cpu/e0c6200/e0c6s46.h new file mode 100644 index 00000000000..0b5f1e8bee3 --- /dev/null +++ b/src/devices/cpu/e0c6200/e0c6s46.h @@ -0,0 +1,182 @@ +// license:BSD-3-Clause +// copyright-holders:hap +/* + + Seiko Epson E0C6S46 MCU + +*/ + +#ifndef _E0C6S46_H_ +#define _E0C6S46_H_ + +#include "e0c6200.h" + + +// I/O ports setup + +// 5 4-bit R output ports +#define MCFG_E0C6S46_WRITE_R_CB(R, _devcb) \ + e0c6s46_device::set_write_r##R##_callback(*device, DEVCB_##_devcb); + +enum +{ + E0C6S46_PORT_R0X = 0, + E0C6S46_PORT_R1X, + E0C6S46_PORT_R2X, + E0C6S46_PORT_R3X, + E0C6S46_PORT_R4X +}; + +// 4 4-bit P I/O ports +#define MCFG_E0C6S46_READ_P_CB(R, _devcb) \ + hmcs40_cpu_device::set_read_r##P##_callback(*device, DEVCB_##_devcb); +#define MCFG_E0C6S46_WRITE_P_CB(R, _devcb) \ + e0c6s46_device::set_write_r##P##_callback(*device, DEVCB_##_devcb); + +enum +{ + E0C6S46_PORT_P0X = 0, + E0C6S46_PORT_P1X, + E0C6S46_PORT_P2X, + E0C6S46_PORT_P3X +}; + +// for the 2 K input ports, use set_input_line(line, state) +enum +{ + E0C6S46_LINE_K00 = 0, + E0C6S46_LINE_K01, + E0C6S46_LINE_K02, + E0C6S46_LINE_K03, + E0C6S46_LINE_K10, + E0C6S46_LINE_K11, + E0C6S46_LINE_K12, + E0C6S46_LINE_K13 +}; + + +// lcd driver +#define MCFG_E0C6S46_PIXEL_UPDATE_CB(_cb) \ + e0c6s46_device::static_set_pixel_update_cb(*device, _cb); + +typedef void (*e0c6s46_pixel_update_func)(device_t &device, bitmap_ind16 &bitmap, const rectangle &cliprect, int contrast, int seg, int com, int state); +#define E0C6S46_PIXEL_UPDATE_CB(name) void name(device_t &device, bitmap_ind16 &bitmap, const rectangle &cliprect, int contrast, int seg, int com, int state) + + +class e0c6s46_device : public e0c6200_cpu_device +{ +public: + e0c6s46_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // static configuration helpers + template static devcb_base &set_write_r0_callback(device_t &device, _Object object) { return downcast(device).m_write_r0.set_callback(object); } + template static devcb_base &set_write_r1_callback(device_t &device, _Object object) { return downcast(device).m_write_r1.set_callback(object); } + template static devcb_base &set_write_r2_callback(device_t &device, _Object object) { return downcast(device).m_write_r2.set_callback(object); } + template static devcb_base &set_write_r3_callback(device_t &device, _Object object) { return downcast(device).m_write_r3.set_callback(object); } + template static devcb_base &set_write_r4_callback(device_t &device, _Object object) { return downcast(device).m_write_r4.set_callback(object); } + + template static devcb_base &set_read_p0_callback(device_t &device, _Object object) { return downcast(device).m_read_p0.set_callback(object); } + template static devcb_base &set_read_p1_callback(device_t &device, _Object object) { return downcast(device).m_read_p1.set_callback(object); } + template static devcb_base &set_read_p2_callback(device_t &device, _Object object) { return downcast(device).m_read_p2.set_callback(object); } + template static devcb_base &set_read_p3_callback(device_t &device, _Object object) { return downcast(device).m_read_p3.set_callback(object); } + template static devcb_base &set_write_p0_callback(device_t &device, _Object object) { return downcast(device).m_write_p0.set_callback(object); } + template static devcb_base &set_write_p1_callback(device_t &device, _Object object) { return downcast(device).m_write_p1.set_callback(object); } + template static devcb_base &set_write_p2_callback(device_t &device, _Object object) { return downcast(device).m_write_p2.set_callback(object); } + template static devcb_base &set_write_p3_callback(device_t &device, _Object object) { return downcast(device).m_write_p3.set_callback(object); } + + static void static_set_pixel_update_cb(device_t &device, e0c6s46_pixel_update_func _cb) { downcast(device).m_pixel_update_handler = _cb; } + + DECLARE_READ8_MEMBER(io_r); + DECLARE_WRITE8_MEMBER(io_w); + + UINT32 screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_execute_interface overrides + virtual UINT32 execute_input_lines() const { return 8; } + virtual void execute_set_input(int line, int state); + virtual void execute_one(); + virtual bool check_interrupt(); + +private: + required_shared_ptr m_vram1; + required_shared_ptr m_vram2; + + UINT8 m_irqflag[6]; + UINT8 m_irqmask[6]; + UINT8 m_osc; + UINT8 m_svd; + + UINT8 m_lcd_control; + UINT8 m_lcd_contrast; + e0c6s46_pixel_update_func m_pixel_update_handler; + + // i/o ports + devcb_write8 m_write_r0, m_write_r1, m_write_r2, m_write_r3, m_write_r4; + devcb_read8 m_read_p0, m_read_p1, m_read_p2, m_read_p3; + devcb_write8 m_write_p0, m_write_p1, m_write_p2, m_write_p3; + void write_r(UINT8 port, UINT8 data); + void write_r4_out(); + void write_p(UINT8 port, UINT8 data); + UINT8 read_p(UINT8 port); + + UINT8 m_port_r[5]; + UINT8 m_r_dir; + UINT8 m_port_p[4]; + UINT8 m_p_dir; + UINT8 m_p_pullup; + UINT8 m_port_k[2]; + UINT8 m_dfk0; + + // timers + int m_256_src_pulse; + emu_timer *m_core_256_handle; + TIMER_CALLBACK_MEMBER(core_256_cb); + + int m_watchdog_count; + void clock_watchdog(); + UINT8 m_clktimer_count; + void clock_clktimer(); + + UINT8 m_stopwatch_on; + int m_swl_cur_pulse; + int m_swl_slice; + int m_swl_count; + int m_swh_count; + void clock_stopwatch(); + + UINT8 m_prgtimer_select; + UINT8 m_prgtimer_on; + int m_prgtimer_src_pulse; + int m_prgtimer_cur_pulse; + UINT8 m_prgtimer_count; + UINT8 m_prgtimer_reload; + emu_timer *m_prgtimer_handle; + TIMER_CALLBACK_MEMBER(prgtimer_cb); + bool prgtimer_reset_prescaler(); + void clock_prgtimer(); + + UINT8 m_bz_43_on; + UINT8 m_bz_freq; + UINT8 m_bz_envelope; + UINT8 m_bz_duty_ratio; + UINT8 m_bz_1shot_on; + bool m_bz_1shot_running; + UINT8 m_bz_1shot_count; + int m_bz_pulse; + emu_timer *m_buzzer_handle; + TIMER_CALLBACK_MEMBER(buzzer_cb); + void schedule_buzzer(); + void reset_buzzer(); + void clock_bz_1shot(); +}; + + + +extern const device_type E0C6S46; + +#endif /* _E0C6S46_H_ */ diff --git a/src/devices/cpu/e132xs/32xsdasm.c b/src/devices/cpu/e132xs/32xsdasm.c new file mode 100644 index 00000000000..f5e9885b220 --- /dev/null +++ b/src/devices/cpu/e132xs/32xsdasm.c @@ -0,0 +1,2142 @@ +// license:BSD-3-Clause +// copyright-holders:Pierpaolo Prazzoli +/* + + Hyperstone disassembler + written by Pierpaolo Prazzoli + +*/ + +#include "emu.h" +#include "debugger.h" +#include "e132xs.h" + +static const char *const L_REG[] = +{ + "L0", "L1", "L2", "L3", "L4", "L5", "L6", "L7", "L8", "L9", + "L10", "L11", "L12", "L13", "L14", "L15", "L16", "L17", "L18", "L19", + "L20", "L21", "L22", "L23", "L24", "L25", "L26", "L27", "L28", "L29", + "L30", "L31", "L32", "L33", "L34", "L35", "L36", "L37", "L38", "L39", + "L40", "L41", "L42", "L43", "L44", "L45", "L46", "L47", "L48", "L49", + "L50", "L51", "L52", "L53", "L54", "L55", "L56", "L57", "L58", "L59", + "L60", "L61", "L62", "L63" +}; + +static const char *const G_REG[] = +{ + "PC", "SR", "FER", "G03", "G04", "G05", "G06", "G07", "G08", "G09", + "G10", "G11", "G12", "G13", "G14", "G15", "G16", "G17", "SP", "UB", + "BCR", "TPR", "TCR", "TR", "WCR", "ISR", "FCR", "MCR", "G28", "G29", + "G30", "G31" +}; + +static const char *const SETxx[] = +{ + "SETADR", "Reserved", "SET1", "SET0", "SETLE", "SETGT", "SETLT", "SETGE", + "SETSE", "SETHT", "SETST", "SETHE", "SETE", "SETNE", "SETV", "SETNV", + "Reserved", "Reserved", "SET1M", "Reserved", "SETLEM", "SETGTM", "SETLTM", "SETGEM", + "SETSEM", "SETTHM", "SETSTM", "SETHEM", "SETEM", "SETNEM", "SETVM", "SETNVM" +}; + +#define DESTCODE(op) ((op & 0x00f0) >> 4) +#define SOURCECODE(op) (op & 0x000f) + +#define SOURCEBIT(op) ((op & 0x100) >> 8) +#define DESTBIT(op) ((op & 0x200) >> 9) + +#define N_VALUE(op) ((((op & 0x100) >> 8) << 4 ) | (op & 0x0f)) + +static int size, global_fp; + +static offs_t base_pc; +static const UINT8 *base_oprom; +#define READ_OP_DASM(p) ((base_oprom[(p) - base_pc] << 8) | base_oprom[(p) + 1 - base_pc]) + + +static void LL_format(char *source, char *dest, UINT16 op) +{ + strcpy(source, L_REG[(SOURCECODE(op)+global_fp)%64]); + strcpy(dest, L_REG[(DESTCODE(op)+global_fp)%64]); +} + +static void LR_format(char *source, char *dest, UINT16 op) +{ + if( SOURCEBIT(op) ) + { + strcpy(source, L_REG[(SOURCECODE(op)+global_fp)%64]); + } + else + { + strcpy(source, G_REG[SOURCECODE(op)]); + } + + strcpy(dest, L_REG[(DESTCODE(op)+global_fp)%64]); +} + +static void RR_format(char *source, char *dest, UINT16 op, unsigned h_flag) +{ + if( SOURCEBIT(op) ) + { + strcpy(source, L_REG[(SOURCECODE(op)+global_fp)%64]); + } + else + { + strcpy(source, G_REG[SOURCECODE(op) + h_flag * 16]); + } + + if( DESTBIT(op) ) + { + strcpy(dest, L_REG[(DESTCODE(op)+global_fp)%64]); + } + else + { + strcpy(dest, G_REG[DESTCODE(op) + h_flag * 16]); + } +} + +static UINT32 LRconst_format(char *source, char *dest, UINT16 op, unsigned *pc) +{ + UINT16 next_op; + UINT32 const_val; + + if( SOURCEBIT(op) ) + { + strcpy(source, L_REG[(SOURCECODE(op)+global_fp)%64]); + } + else + { + strcpy(source, G_REG[SOURCECODE(op)]); + } + + strcpy(dest, L_REG[(DESTCODE(op)+global_fp)%64]); + + size = 4; + + *pc += 2; + next_op = READ_OP_DASM(*pc); + + if( E_BIT(next_op) ) + { + UINT16 next_op2; + + size = 6; + + *pc += 2; + next_op2 = READ_OP_DASM(*pc); + const_val = next_op2; + const_val |= ((next_op & 0x3fff) << 16 ); + + if( S_BIT_CONST(next_op) ) + { + const_val |= 0xc0000000; + } + } + else + { + const_val = next_op & 0x3fff; + + if( S_BIT_CONST(next_op) ) + { + const_val |= 0xffffc000; + } + } + + return const_val; +} + +static UINT32 RRconst_format(char *source, char *dest, UINT16 op, unsigned *pc) +{ + UINT16 next_op; + UINT32 const_val; + + if( SOURCEBIT(op) ) + { + strcpy(source, L_REG[(SOURCECODE(op)+global_fp)%64]); + } + else + { + strcpy(source, G_REG[SOURCECODE(op)]); + } + + if( DESTBIT(op) ) + { + strcpy(dest, L_REG[(DESTCODE(op)+global_fp)%64]); + } + else + { + strcpy(dest, G_REG[DESTCODE(op)]); + } + + size = 4; + + *pc += 2; + next_op = READ_OP_DASM(*pc); + + if( E_BIT(next_op) ) + { + UINT16 next_op2; + + size = 6; + + *pc += 2; + next_op2 = READ_OP_DASM(*pc); + const_val = next_op2; + const_val |= ((next_op & 0x3fff) << 16 ); + + if( S_BIT_CONST(next_op) ) + { + const_val |= 0xc0000000; + } + } + else + { + const_val = next_op & 0x3fff; + + if( S_BIT_CONST(next_op) ) + { + const_val |= 0xffffc000; + } + } + + return const_val; +} + +static INT32 Rimm_format(char *dest, UINT16 op, unsigned *pc, unsigned h_flag) +{ + UINT16 imm1, imm2; + INT32 ret; + + int n = N_VALUE(op); + + if( DESTBIT(op) ) + { + strcpy(dest, L_REG[(DESTCODE(op)+global_fp)%64]); + } + else + { + strcpy(dest, G_REG[DESTCODE(op) + h_flag * 16]); + } + + switch( n ) + { + case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: case 8: + case 9: case 10: case 11: case 12: case 13: case 14: case 15: case 16: + return n; + + case 17: + *pc += 2; + imm1 = READ_OP_DASM(*pc); + *pc += 2; + imm2 = READ_OP_DASM(*pc); + ret = (imm1 << 16) | imm2; + + size = 6; + return ret; + + + case 18: + *pc += 2; + ret = READ_OP_DASM(*pc); + + size = 4; + return ret; + + case 19: + *pc += 2; + ret = (INT32) (0xffff0000 | READ_OP_DASM(*pc)); + + size = 4; + return ret; + + case 20: + return 32; //bit 5 = 1, others = 0 + + case 21: + return 64; //bit 6 = 1, others = 0 + + case 22: + return 128; //bit 7 = 1, others = 0 + + case 23: + return 0x80000000; //bit 31 = 1, others = 0 (2 at the power of 31) + + case 24: + return -8; + + case 25: + return -7; + + case 26: + return -6; + + case 27: + return -5; + + case 28: + return -4; + + case 29: + return -3; + + case 30: + return -2; + + case 31: + return -1; + + default: + return 0; //should never goes here + } +} + +static UINT8 Ln_format(char *dest, UINT16 op) +{ + strcpy(dest, L_REG[(DESTCODE(op)+global_fp)%64]); + + return N_VALUE(op); +} + +static UINT8 Rn_format(char *dest, UINT16 op) +{ + if( DESTBIT(op) ) + { + strcpy(dest, L_REG[(DESTCODE(op)+global_fp)%64]); + } + else + { + strcpy(dest, G_REG[DESTCODE(op)]); + } + + return N_VALUE(op); +} + +static INT32 PCrel_format(UINT16 op, unsigned pc) +{ + INT32 ret; + + if( op & 0x80 ) //bit 7 = 1 + { + UINT16 next; + + size = 4; + + pc += 2; + + next = READ_OP_DASM(pc); + + ret = (op & 0x7f) << 16; + + ret |= (next & 0xfffe); + + if( next & 1 ) + ret |= 0xff800000; //ok? + } + else + { + ret = op & 0x7e; + + if( op & 1 ) + ret |= 0xffffff80; //ok? + } + + return (pc + ret); +} + +static UINT32 RRdis_format(char *source, char *dest, UINT16 op, UINT16 next_op, unsigned pc) +{ + UINT32 ret; + + if( SOURCEBIT(op) ) + { + strcpy(source, L_REG[(SOURCECODE(op)+global_fp)%64]); + } + else + { + strcpy(source, G_REG[SOURCECODE(op)]); + } + + if( DESTBIT(op) ) + { + strcpy(dest, L_REG[(DESTCODE(op)+global_fp)%64]); + } + else + { + strcpy(dest, G_REG[DESTCODE(op)]); + } + + if( E_BIT(next_op) ) + { + UINT16 next; + + size = 6; + + next = READ_OP_DASM(pc + 4); + + ret = next; + ret |= ( ( next_op & 0xfff ) << 16 ); + + if( S_BIT_CONST(next_op) ) + { + ret |= 0xf0000000; + } + } + else + { + ret = next_op & 0xfff; + if( S_BIT_CONST(next_op) ) + { + ret |= 0xfffff000; + } + } + + return ret; +} + +unsigned dasm_hyperstone(char *buffer, unsigned pc, const UINT8 *oprom, unsigned h_flag, int private_fp) +{ + UINT16 op = 0; + UINT8 op_num; + + UINT8 source_code, dest_code, source_bit, dest_bit; + + char source[5] = "\0", dest[5] = "\0"; + UINT32 flags = 0; + + base_pc = pc; + base_oprom = oprom; + + op = READ_OP_DASM(pc); + + size = 2; + + source_code = SOURCECODE(op); + dest_code = DESTCODE(op); + source_bit = SOURCEBIT(op); + dest_bit = DESTBIT(op); + + global_fp = private_fp; + + op_num = (op & 0xff00) >> 8; + + switch( op_num ) + { + // CHK - CHKZ - NOP + case 0x00: case 0x01: case 0x02: case 0x03: + + if( source_bit && dest_bit && source_code == 0 && dest_code == 0 ) + { + sprintf(buffer, "NOP"); + } + else + { + RR_format(source, dest, op, 0); + + if( !source_bit && source_code == SR_REGISTER ) + { + sprintf(buffer, "CHKZ %s, 0", dest); + } + else + { + sprintf(buffer, "CHK %s, %s", dest, source); + } + } + + break; + + // MOVD - RET + case 0x04: case 0x05: case 0x06: case 0x07: + + RR_format(source, dest, op, 0); + + if( dest_code == PC_REGISTER && !dest_bit ) + { + global_fp = 0; + RR_format(source, dest, op, 0); + sprintf(buffer, "RET PC, %s", source); + flags = DASMFLAG_STEP_OUT; + } + else if( source_code == SR_REGISTER && !source_bit ) + { + sprintf(buffer, "MOVD %s, 0", dest); + } + else + { + sprintf(buffer, "MOVD %s, %s", dest, source); + } + + break; + + // DIVU + case 0x08: case 0x09: case 0x0a: case 0x0b: + + RR_format(source, dest, op, 0); + sprintf(buffer, "DIVU %s, %s", dest, source); + + break; + + // DIVS + case 0x0c: case 0x0d: case 0x0e: case 0x0f: + + RR_format(source, dest, op, 0); + sprintf(buffer, "DIVS %s, %s", dest, source); + + break; + + // XMx - XXx + case 0x10: case 0x11: case 0x12: case 0x13: + { + int xcode; + + RR_format(source, dest, op, 0); + + size = 4; + + pc += 2; + op = READ_OP_DASM(pc); + + xcode = X_CODE(op); + + if( xcode < 4 ) + { + UINT16 lim; + + if( E_BIT(op) ) + { + UINT16 next_op; + + size = 6; + + pc += 2; + next_op = READ_OP_DASM(pc); + + lim = ((op & 0xfff) << 16) | next_op; + } + else + { + lim = op & 0xfff; + } + + sprintf(buffer, "XM%x %s, %s, $%x", (UINT8)(float) pow(2.0, xcode), dest, source, lim); + + } + else + { + sprintf(buffer, "XX%x %s, %s, 0", (UINT8)(float) pow(2.0, (xcode - 4)), dest, source); + } + + break; + } + + // MASK + case 0x14: case 0x15: case 0x16: case 0x17: + { + UINT32 const_val = RRconst_format(source, dest, op, &pc); + + sprintf(buffer, "MASK %s, %s, $%x", dest, source, const_val); + + break; + } + + // SUM + case 0x18: case 0x19: case 0x1a: case 0x1b: + { + UINT32 const_val = RRconst_format(source, dest, op, &pc); + + if( source_code == SR_REGISTER && !source_bit ) + { + sprintf(buffer, "SUM %s, C, $%x", dest, const_val); + } + else + { + sprintf(buffer, "SUM %s, %s, $%x", dest, source, const_val); + } + + break; + } + + // SUMS + case 0x1c: case 0x1d: case 0x1e: case 0x1f: + { + UINT32 const_val = RRconst_format(source, dest, op, &pc); + + if( source_code == SR_REGISTER && !source_bit ) + { + sprintf(buffer, "SUMS %s, C, $%x", dest, const_val); + } + else + { + sprintf(buffer, "SUMS %s, %s, $%x", dest, source, const_val); + } + + break; + } + + // CMP + case 0x20: case 0x21: case 0x22: case 0x23: + + RR_format(source, dest, op, 0); + + if( source_code == SR_REGISTER && !source_bit ) + { + sprintf(buffer, "CMP %s, C", dest); + } + else + { + sprintf(buffer, "CMP %s, %s", dest, source); + } + + break; + + // MOV + case 0x24: case 0x25: case 0x26: case 0x27: + + RR_format(source, dest, op, h_flag); + sprintf(buffer, "MOV %s, %s", dest, source); + + break; + + // ADD + case 0x28: case 0x29: case 0x2a: case 0x2b: + + RR_format(source, dest, op, 0); + + if( source_code == SR_REGISTER && !source_bit ) + { + sprintf(buffer, "ADD %s, C", dest); + } + else + { + sprintf(buffer, "ADD %s, %s", dest, source); + } + + break; + + // ADDS + case 0x2c: case 0x2d: case 0x2e: case 0x2f: + + RR_format(source, dest, op, 0); + + if( source_code == SR_REGISTER && !source_bit ) + { + sprintf(buffer, "ADDS %s, C", dest); + } + else + { + sprintf(buffer, "ADDS %s, %s", dest, source); + } + + break; + + // CMPB + case 0x30: case 0x31: case 0x32: case 0x33: + + RR_format(source, dest, op, 0); + sprintf(buffer, "CMPB %s, %s", dest, source); + + break; + + // ANDN + case 0x34: case 0x35: case 0x36: case 0x37: + + RR_format(source, dest, op, 0); + sprintf(buffer, "ANDN %s, %s", dest, source); + + break; + + // OR + case 0x38: case 0x39: case 0x3a: case 0x3b: + + RR_format(source, dest, op, 0); + sprintf(buffer, "OR %s, %s", dest, source); + + break; + + // XOR + case 0x3c: case 0x3d: case 0x3e: case 0x3f: + + RR_format(source, dest, op, 0); + sprintf(buffer, "XOR %s, %s", dest, source); + + break; + + // SUBC + case 0x40: case 0x41: case 0x42: case 0x43: + + RR_format(source, dest, op, 0); + + if( source_code == SR_REGISTER && !source_bit ) + { + sprintf(buffer, "SUBC %s, C", dest); + } + else + { + sprintf(buffer, "SUBC %s, %s", dest, source); + } + + break; + + // NOT + case 0x44: case 0x45: case 0x46: case 0x47: + + RR_format(source, dest, op, 0); + + sprintf(buffer, "NOT %s, %s", dest, source); + + break; + + // SUB + case 0x48: case 0x49: case 0x4a: case 0x4b: + + RR_format(source, dest, op, 0); + + if( source_code == SR_REGISTER && !source_bit ) + { + sprintf(buffer, "SUB %s, C", dest); + } + else + { + sprintf(buffer, "SUB %s, %s", dest, source); + } + + break; + + // SUBS + case 0x4c: case 0x4d: case 0x4e: case 0x4f: + + RR_format(source, dest, op, 0); + + if( source_code == SR_REGISTER && !source_bit ) + { + sprintf(buffer, "SUBS %s, C", dest); + } + else + { + sprintf(buffer, "SUBS %s, %s", dest, source); + } + + break; + + // ADDC + case 0x50: case 0x51: case 0x52: case 0x53: + + RR_format(source, dest, op, 0); + + if( source_code == SR_REGISTER && !source_bit ) + { + sprintf(buffer, "ADDC %s, C", dest); + } + else + { + sprintf(buffer, "ADDC %s, %s", dest, source); + } + + break; + + // AND + case 0x54: case 0x55: case 0x56: case 0x57: + + RR_format(source, dest, op, 0); + sprintf(buffer, "AND %s, %s", dest, source); + + break; + + // NEG + case 0x58: case 0x59: case 0x5a: case 0x5b: + + RR_format(source, dest, op, 0); + + if( source_code == SR_REGISTER && !source_bit ) + { + sprintf(buffer, "NEG %s, C", dest); + } + else + { + sprintf(buffer, "NEG %s, %s", dest, source); + } + + break; + + // NEGS + case 0x5c: case 0x5d: case 0x5e: case 0x5f: + + RR_format(source, dest, op, 0); + + if( source_code == SR_REGISTER && !source_bit ) + { + sprintf(buffer, "NEGS %s, C", dest); + } + else + { + sprintf(buffer, "NEGS %s, %s", dest, source); + } + + break; + + // CMPI + case 0x60: case 0x61: case 0x62: case 0x63: + { + UINT32 imm = Rimm_format(dest, op, &pc, 0); + + sprintf(buffer, "CMPI %s, $%x", dest, imm); + + break; + } + + // MOVI + case 0x64: case 0x65: case 0x66: case 0x67: + { + UINT32 imm = Rimm_format(dest, op, &pc, h_flag); + + sprintf(buffer, "MOVI %s, $%x", dest, imm); + + break; + } + + // ADDI + case 0x68: case 0x69: case 0x6a: case 0x6b: + { + UINT32 imm = Rimm_format(dest, op, &pc, 0); + + if( !N_VALUE(op) ) + { + sprintf(buffer, "ADDI %s, CZ", dest); + } + else + { + sprintf(buffer, "ADDI %s, $%x", dest, imm); + } + + break; + } + + // ADDSI + case 0x6c: case 0x6d: case 0x6e: case 0x6f: + { + UINT32 imm = Rimm_format(dest, op, &pc, 0); + + if( !N_VALUE(op) ) + { + sprintf(buffer, "ADDSI %s, CZ", dest); + } + else + { + sprintf(buffer, "ADDSI %s, $%x", dest, imm); + } + + break; + } + + // CMPBI + case 0x70: case 0x71: case 0x72: case 0x73: + { + UINT32 imm = Rimm_format(dest, op, &pc, 0); + + if( !N_VALUE(op) ) + { + sprintf(buffer, "CMPBI %s, ANYBZ", dest); + } + else + { + if( N_VALUE(op) == 31 ) + imm = 0x7fffffff; //bit 31 = 0, others = 1 + + sprintf(buffer, "CMPBI %s, $%x", dest, imm); + } + + break; + } + + // ANDNI + case 0x74: case 0x75: case 0x76: case 0x77: + { + UINT32 imm = Rimm_format(dest, op, &pc, 0); + + if( N_VALUE(op) == 31 ) + imm = 0x7fffffff; //bit 31 = 0, others = 1 + + sprintf(buffer, "ANDNI %s, $%x", dest, imm); + + break; + } + + // ORI + case 0x78: case 0x79: case 0x7a: case 0x7b: + { + UINT32 imm = Rimm_format(dest, op, &pc, 0); + + sprintf(buffer, "ORI %s, $%x", dest, imm); + + break; + } + + // XORI + case 0x7c: case 0x7d: case 0x7e: case 0x7f: + { + UINT32 imm = Rimm_format(dest, op, &pc, 0); + + sprintf(buffer, "XORI %s, $%x", dest, imm); + + break; + } + + // SHRDI + case 0x80: case 0x81: + { + UINT8 n = Ln_format(dest, op); + + sprintf(buffer, "SHRDI %s, $%x", dest, n); + + break; + } + + // SHRD + case 0x82: + + LL_format(source, dest, op); + + sprintf(buffer, "SHRD %s, %s", dest, source); + + break; + + // SHR + case 0x83: + + LL_format(source, dest, op); + + sprintf(buffer, "SHR %s, %s", dest, source); + + break; + + // SARDI + case 0x84: case 0x85: + { + UINT8 n = Ln_format(dest, op); + + sprintf(buffer, "SARDI %s, $%x", dest, n); + + break; + } + + // SARD + case 0x86: + + LL_format(source, dest, op); + + sprintf(buffer, "SARD %s, %s", dest, source); + + break; + + // SAR + case 0x87: + + LL_format(source, dest, op); + + sprintf(buffer, "SAR %s, %s", dest, source); + + break; + + // SHLDI + case 0x88: case 0x89: + { + UINT8 n = Ln_format(dest, op); + + sprintf(buffer, "SHLDI %s, $%x", dest, n); + + break; + } + + // SHLD + case 0x8a: + + LL_format(source, dest, op); + + sprintf(buffer, "SHLD %s, %s", dest, source); + + break; + + // SHL + case 0x8b: + + LL_format(source, dest, op); + + sprintf(buffer, "SHL %s, %s", dest, source); + + break; + + // RESERVED + case 0x8c: case 0x8d: + case 0xac: case 0xad: case 0xae: case 0xaf: + + sprintf(buffer, "Reserved"); + + break; + + // TESTLZ + case 0x8e: + + LL_format(source, dest, op); + + sprintf(buffer, "TESTLZ %s, %s", dest, source); + + break; + + // ROL + case 0x8f: + + LL_format(source, dest, op); + + sprintf(buffer, "ROL %s, %s", dest, source); + + break; + + // LDxx.D/A/IOD/IOA + case 0x90: case 0x91: case 0x92: case 0x93: + { + UINT16 next_op = READ_OP_DASM(pc + 2); + UINT32 dis = RRdis_format(source, dest, op, next_op, pc); + + if( size == 2 ) + size = 4; + + if( dest_code == SR_REGISTER && !dest_bit ) + { + switch( DD( next_op ) ) + { + case 0: + // LDBS.A + sprintf(buffer, "LDBS.A 0, %s, $%x", source, dis); + break; + + case 1: + // LDBU.A + sprintf(buffer, "LDBU.A 0, %s, $%x", source, dis); + break; + + case 2: + // LDHS.A + if( dis & 1 ) + { + sprintf(buffer, "LDHS.A 0, %s, $%x", source, dis & ~1); + } + // LDHU.A + else + { + sprintf(buffer, "LDHU.A 0, %s, $%x", source, dis & ~1); + } + + break; + + case 3: + // LDD.IOA + if( (dis & 3) == 3 ) + { + sprintf(buffer, "LDD.IOA 0, %s, $%x", source, dis & ~3); + } + // LDW.IOA + else if( (dis & 3) == 2 ) + { + sprintf(buffer, "LDW.IOA 0, %s, $%x", source, dis & ~3); + } + // LDD.A + else if( (dis & 3) == 1 ) + { + sprintf(buffer, "LDD.A 0, %s, $%x", source, dis & ~1); + } + // LDW.A + else + { + sprintf(buffer, "LDW.A 0, %s, $%x", source, dis & ~1); + } + + break; + } + } + else + { + switch( DD( next_op ) ) + { + case 0: + // LDBS.D + sprintf(buffer, "LDBS.D %s, %s, $%x", dest, source, dis); + break; + + case 1: + // LDBU.D + sprintf(buffer, "LDBU.D %s, %s, $%x", dest, source, dis); + break; + + case 2: + // LDHS.D + if( dis & 1 ) + { + sprintf(buffer, "LDHS.D %s, %s, $%x", dest, source, dis & ~1); + } + // LDHU.D + else + { + sprintf(buffer, "LDHU.D %s, %s, $%x", dest, source, dis & ~1); + } + break; + + case 3: + // LDD.IOD + if( (dis & 3) == 3 ) + { + sprintf(buffer, "LDD.IOD %s, %s, $%x", dest, source, dis & ~3); + } + // LDW.IOD + else if( (dis & 3) == 2 ) + { + sprintf(buffer, "LDW.IOD %s, %s, $%x", dest, source, dis & ~3); + } + // LDD.D + else if( (dis & 3) == 1 ) + { + sprintf(buffer, "LDD.D %s, %s, $%x", dest, source, dis & ~1); + } + // LDW.D + else + { + sprintf(buffer, "LDW.D %s, %s, $%x", dest, source, dis & ~1); + } + + break; + } + } + + break; + } + + // LDxx.N/S + case 0x94: case 0x95: case 0x96: case 0x97: + { + UINT16 next_op = READ_OP_DASM(pc + 2); + UINT32 dis = RRdis_format(source, dest, op, next_op, pc); + + if( size == 2 ) + size = 4; + + if( (dest_code == PC_REGISTER && !dest_bit) || (dest_code == SR_REGISTER && !dest_bit) ) + { + sprintf(buffer, "Reserved"); + break; + } + + switch( DD( next_op ) ) + { + case 0: + // LDBS.N + sprintf(buffer, "LDBS.N %s, %s, $%x", dest, source, dis); + break; + + case 1: + // LDBU.N + sprintf(buffer, "LDBU.N %s, %s, $%x", dest, source, dis); + break; + + case 2: + // LDHS.N + if( dis & 1 ) + { + sprintf(buffer, "LDHS.N %s, %s, $%x", dest, source, dis & ~1); + } + // LDHU.N + else + { + sprintf(buffer, "LDHU.N %s, %s, $%x", dest, source, dis & ~1); + } + + break; + + case 3: + // LDW.S + if( (dis & 3) == 3 ) + { + sprintf(buffer, "LDW.S %s, %s, $%x", dest, source, dis & ~3); + } + // Reserved + else if( (dis & 3) == 2 ) + { + sprintf(buffer, "Reserved"); + } + // LDD.N + else if( (dis & 3) == 1 ) + { + sprintf(buffer, "LDD.N %s, %s, $%x", dest, source, dis & ~1); + } + // LDW.N + else + { + sprintf(buffer, "LDW.N %s, %s, $%x", dest, source, dis & ~1); + } + + break; + } + + break; + } + + // STxx.D/A/IOD/IOA + case 0x98: case 0x99: case 0x9a: case 0x9b: + { + UINT16 next_op = READ_OP_DASM(pc + 2); + UINT32 dis = RRdis_format(source, dest, op, next_op, pc); + + if( size == 2 ) + size = 4; + + if( source_code == SR_REGISTER && !source_bit ) + strcpy(source,"0"); + + if( dest_code == SR_REGISTER && !dest_bit ) + { + switch( DD( next_op ) ) + { + case 0: + // STBS.A + sprintf(buffer, "STBS.A 0, %s, $%x", source, dis); + break; + + case 1: + // STBU.A + sprintf(buffer, "STBU.A 0, %s, $%x", source, dis); + break; + + case 2: + // STHS.A + if( dis & 1 ) + { + sprintf(buffer, "STHS.A 0, %s, $%x", source, dis & ~1); + } + // STHU.A + else + { + sprintf(buffer, "STHU.A 0, %s, $%x", source, dis & ~1); + } + + break; + + case 3: + // STD.IOA + if( (dis & 3) == 3 ) + { + sprintf(buffer, "STD.IOA 0, %s, $%x", source, dis & ~3); + } + // STW.IOA + else if( (dis & 3) == 2 ) + { + sprintf(buffer, "STW.IOA 0, %s, $%x", source, dis & ~3); + } + // STD.A + else if( (dis & 3) == 1 ) + { + sprintf(buffer, "STD.A 0, %s, $%x", source, dis & ~1); + } + // STW.A + else + { + sprintf(buffer, "STW.A 0, %s, $%x", source, dis & ~1); + } + + break; + } + } + else + { + switch( DD( next_op ) ) + { + case 0: + // STBS.D + sprintf(buffer, "STBS.D %s, %s, $%x", dest, source, dis); + break; + + case 1: + // STBU.D + sprintf(buffer, "STBU.D %s, %s, $%x", dest, source, dis); + break; + + case 2: + // STHS.D + if( dis & 1 ) + { + sprintf(buffer, "STHS.D %s, %s, $%x", dest, source, dis & ~1); + } + // STHU.D + else + { + sprintf(buffer, "STHU.D %s, %s, $%x", dest, source, dis & ~1); + } + break; + + case 3: + // STD.IOD + if( (dis & 3) == 3 ) + { + sprintf(buffer, "STD.IOD %s, %s, $%x", dest, source, dis & ~3); + } + // STW.IOD + else if( (dis & 3) == 2 ) + { + sprintf(buffer, "STW.IOD %s, %s, $%x", dest, source, dis & ~3); + } + // STD.D + else if( (dis & 3) == 1 ) + { + sprintf(buffer, "STD.D %s, %s, $%x", dest, source, dis & ~1); + } + // STW.D + else + { + sprintf(buffer, "STW.D %s, %s, $%x", dest, source, dis & ~1); + } + + break; + } + } + + break; + } + + // STxx.N/S + case 0x9c: case 0x9d: case 0x9e: case 0x9f: + { + UINT16 next_op = READ_OP_DASM(pc + 2); + UINT32 dis = RRdis_format(source, dest, op, next_op, pc); + + if( size == 2 ) + size = 4; + + if( source_code == SR_REGISTER && !source_bit ) + strcpy(source,"0"); + + if( (dest_code == PC_REGISTER && !dest_bit) || (dest_code == SR_REGISTER && !dest_bit) ) + { + sprintf(buffer, "Reserved"); + break; + } + + switch( DD( next_op ) ) + { + case 0: + // STBS.N + sprintf(buffer, "STBS.N %s, %s, $%x", dest, source, dis); + break; + + case 1: + // STBU.N + sprintf(buffer, "STBU.N %s, %s, $%x", dest, source, dis); + break; + + case 2: + // STHS.N + if( dis & 1 ) + { + sprintf(buffer, "STHS.N %s, %s, $%x", dest, source, dis & ~1); + } + // STHU.N + else + { + sprintf(buffer, "STHU.N %s, %s, $%x", dest, source, dis & ~1); + } + + break; + + case 3: + // STW.S + if( (dis & 3) == 3 ) + { + sprintf(buffer, "STW.S %s, %s, $%x", dest, source, dis & ~3); + } + // Reserved + else if( (dis & 3) == 2 ) + { + sprintf(buffer, "Reserved"); + } + // STD.N + else if( (dis & 3) == 1 ) + { + sprintf(buffer, "STD.N %s, %s, $%x", dest, source, dis & ~1); + } + // STW.N + else + { + sprintf(buffer, "STW.N %s, %s, $%x", dest, source, dis & ~1); + } + + break; + } + + break; + } + + // SHRI + case 0xa0: case 0xa1: case 0xa2: case 0xa3: + { + UINT8 n = Rn_format(dest, op); + + sprintf(buffer, "SHRI %s, $%x", dest, n); + + break; + } + + // SARI + case 0xa4: case 0xa5: case 0xa6: case 0xa7: + { + UINT8 n = Rn_format(dest, op); + + sprintf(buffer, "SARI %s, $%x", dest, n); + + break; + } + + // SHLI + case 0xa8: case 0xa9: case 0xaa: case 0xab: + { + UINT8 n = Rn_format(dest, op); + + sprintf(buffer, "SHLI %s, $%x", dest, n); + + break; + } + + // MULU + case 0xb0: case 0xb1: case 0xb2: case 0xb3: + + RR_format(source, dest, op, 0); + + sprintf(buffer, "MULU %s, %s", dest, source); + + break; + + // MULS + case 0xb4: case 0xb5: case 0xb6: case 0xb7: + + RR_format(source, dest, op, 0); + + sprintf(buffer, "MULS %s, %s", dest, source); + + break; + + // SETxx - SETADR - FETCH + case 0xb8: case 0xb9: case 0xba: case 0xbb: + { + UINT8 n = Rn_format(dest, op); + + if( dest_code == PC_REGISTER && !dest_bit ) + { + sprintf(buffer, "Illegal PC: $%x OP: $%x", pc, op); + } + else if( dest_code == SR_REGISTER && !dest_bit ) + { + sprintf(buffer, "FETCH $%x", (n / 2) + 1); + } + else + { + sprintf(buffer, "%s %s", SETxx[n], dest); + } + + break; + } + + // MUL + case 0xbc: case 0xbd: case 0xbe: case 0xbf: + + RR_format(source, dest, op, 0); + + sprintf(buffer, "MUL %s, %s", dest, source); + + break; + + // FADD + case 0xc0: + + LL_format(source, dest, op); + + sprintf(buffer, "FADD %s, %s", dest, source); + + break; + + // FADDD + case 0xc1: + + LL_format(source, dest, op); + + sprintf(buffer, "FADDD %s, %s", dest, source); + + break; + + // FSUB + case 0xc2: + + LL_format(source, dest, op); + + sprintf(buffer, "FSUB %s, %s", dest, source); + + break; + + // FSUBD + case 0xc3: + + LL_format(source, dest, op); + + sprintf(buffer, "FSUBD %s, %s", dest, source); + + break; + + // FMUL + case 0xc4: + + LL_format(source, dest, op); + + sprintf(buffer, "FMUL %s, %s", dest, source); + + break; + + // FMULD + case 0xc5: + + LL_format(source, dest, op); + + sprintf(buffer, "FMULD %s, %s", dest, source); + + break; + + // FDIV + case 0xc6: + + LL_format(source, dest, op); + + sprintf(buffer, "FDIV %s, %s", dest, source); + + break; + + // FDIVD + case 0xc7: + + LL_format(source, dest, op); + + sprintf(buffer, "FDIVD %s, %s", dest, source); + + break; + + // FCMP + case 0xc8: + + LL_format(source, dest, op); + + sprintf(buffer, "FCMP %s, %s", dest, source); + + break; + + // FCMPD + case 0xc9: + + LL_format(source, dest, op); + + sprintf(buffer, "FCMPD %s, %s", dest, source); + + break; + + // FCMPU + case 0xca: + + LL_format(source, dest, op); + + sprintf(buffer, "FCMPU %s, %s", dest, source); + + break; + + // FCMPUD + case 0xcb: + + LL_format(source, dest, op); + + sprintf(buffer, "FCMPUD %s, %s", dest, source); + + break; + + // FCVT + case 0xcc: + + LL_format(source, dest, op); + + sprintf(buffer, "FCVT %s, %s", dest, source); + + break; + + // FCVTD + case 0xcd: + + LL_format(source, dest, op); + + sprintf(buffer, "FCVTD %s, %s", dest, source); + + break; + + // EXTEND + case 0xce: + { + UINT16 extended_op; + + LL_format(source, dest, op); + + pc += 2; + extended_op = READ_OP_DASM(pc); + + size = 4; + + switch( extended_op ) + { + case 0x100: + case EMUL: + sprintf(buffer, "EMUL %s, %s", dest, source); + break; + + case EMULU: + sprintf(buffer, "EMULU %s, %s", dest, source); + break; + + case EMULS: + sprintf(buffer, "EMULS %s, %s", dest, source); + break; + + case EMAC: + sprintf(buffer, "EMAC %s, %s", dest, source); + break; + + case EMACD: + sprintf(buffer, "EMACD %s, %s", dest, source); + break; + + case EMSUB: + sprintf(buffer, "EMSUB %s, %s", dest, source); + break; + + case EMSUBD: + sprintf(buffer, "EMSUBD %s, %s", dest, source); + break; + + case EHMAC: + sprintf(buffer, "EHMAC %s, %s", dest, source); + break; + + case EHMACD: + sprintf(buffer, "EHMACD %s, %s", dest, source); + break; + + case EHCMULD: + sprintf(buffer, "EHCMULD %s, %s", dest, source); + break; + + case EHCMACD: + sprintf(buffer, "EHCMACD %s, %s", dest, source); + break; + + case EHCSUMD: + sprintf(buffer, "EHCSUMD %s, %s", dest, source); + break; + + case EHCFFTD: + sprintf(buffer, "EHCFFTD %s, %s", dest, source); + break; + + case EHCFFTSD: + sprintf(buffer, "EHCFFTSD %s, %s", dest, source); + break; + + default: + sprintf(buffer, "Ext. OP $%X @ %X\n", extended_op, pc); + logerror(buffer, "Illegal Extended Opcode: %X @ %X\n", extended_op, pc); + break; + } + + break; + } + + // DO + case 0xcf: + + LL_format(source, dest, op); + + sprintf(buffer, "DO %s, %s", dest, source); + + break; + + // LDW.R + case 0xd0: case 0xd1: + + LR_format(source, dest, op); + + sprintf(buffer, "LDW.R %s, %s", dest, source); + + break; + + // LDD.R + case 0xd2: case 0xd3: + + LR_format(source, dest, op); + + sprintf(buffer, "LDD.R %s, %s", dest, source); + + break; + + // LDW.P + case 0xd4: case 0xd5: + + LR_format(source, dest, op); + + sprintf(buffer, "LDW.P %s, %s", dest, source); + + break; + + // LDD.P + case 0xd6: case 0xd7: + + LR_format(source, dest, op); + + sprintf(buffer, "LDD.P %s, %s", dest, source); + + break; + + // STW.R + case 0xd8: case 0xd9: + + LR_format(source, dest, op); + + if( source_code == SR_REGISTER && !source_bit ) + strcpy(source,"0"); + + sprintf(buffer, "STW.R %s, %s", dest, source); + + break; + + // STD.R + case 0xda: case 0xdb: + + LR_format(source, dest, op); + + if( source_code == SR_REGISTER && !source_bit ) + strcpy(source,"0"); + + sprintf(buffer, "STD.R %s, %s", dest, source); + + break; + + // STW.P + case 0xdc: case 0xdd: + + LR_format(source, dest, op); + + if( source_code == SR_REGISTER && !source_bit ) + strcpy(source,"0"); + + sprintf(buffer, "STW.P %s, %s", dest, source); + + break; + + // STD.P + case 0xde: case 0xdf: + + LR_format(source, dest, op); + + if( source_code == SR_REGISTER && !source_bit ) + strcpy(source,"0"); + + sprintf(buffer, "STD.P %s, %s", dest, source); + + break; + + // DBV + case 0xe0: + { + INT32 rel = PCrel_format(op, pc) + 2; + + sprintf(buffer, "DBV $%x", rel); + flags = DASMFLAG_STEP_OVER | DASMFLAG_STEP_OVER_EXTRA(1); + + break; + } + + // DBNV + case 0xe1: + { + INT32 rel = PCrel_format(op, pc) + 2; + + sprintf(buffer, "DBNV $%x", rel); + flags = DASMFLAG_STEP_OVER | DASMFLAG_STEP_OVER_EXTRA(1); + + break; + } + + // DBE + case 0xe2: + { + INT32 rel = PCrel_format(op, pc) + 2; + + sprintf(buffer, "DBE $%x", rel); + flags = DASMFLAG_STEP_OVER | DASMFLAG_STEP_OVER_EXTRA(1); + + break; + } + + // DBNE + case 0xe3: + { + INT32 rel = PCrel_format(op, pc) + 2; + + sprintf(buffer, "DBNE $%x", rel); + flags = DASMFLAG_STEP_OVER | DASMFLAG_STEP_OVER_EXTRA(1); + + break; + } + + // DBC + case 0xe4: + { + INT32 rel = PCrel_format(op, pc) + 2; + + sprintf(buffer, "DBC $%x", rel); + flags = DASMFLAG_STEP_OVER | DASMFLAG_STEP_OVER_EXTRA(1); + + break; + } + + // DBNC + case 0xe5: + { + INT32 rel = PCrel_format(op, pc) + 2; + + sprintf(buffer, "DBNC $%x", rel); + flags = DASMFLAG_STEP_OVER | DASMFLAG_STEP_OVER_EXTRA(1); + + break; + } + + // DBSE + case 0xe6: + { + INT32 rel = PCrel_format(op, pc) + 2; + + sprintf(buffer, "DBSE $%x", rel); + flags = DASMFLAG_STEP_OVER | DASMFLAG_STEP_OVER_EXTRA(1); + + break; + } + + // DBHT + case 0xe7: + { + INT32 rel = PCrel_format(op, pc) + 2; + + sprintf(buffer, "DBHT $%x", rel); + flags = DASMFLAG_STEP_OVER | DASMFLAG_STEP_OVER_EXTRA(1); + + break; + } + + // DBN + case 0xe8: + { + INT32 rel = PCrel_format(op, pc) + 2; + + sprintf(buffer, "DBN $%x", rel); + flags = DASMFLAG_STEP_OVER | DASMFLAG_STEP_OVER_EXTRA(1); + + break; + } + + // DBNN + case 0xe9: + { + INT32 rel = PCrel_format(op, pc) + 2; + + sprintf(buffer, "DBNN $%x", rel); + flags = DASMFLAG_STEP_OVER | DASMFLAG_STEP_OVER_EXTRA(1); + + break; + } + + // DBLE + case 0xea: + { + INT32 rel = PCrel_format(op, pc) + 2; + + sprintf(buffer, "DBLE $%x", rel); + flags = DASMFLAG_STEP_OVER | DASMFLAG_STEP_OVER_EXTRA(1); + + break; + } + + // DBGT + case 0xeb: + { + INT32 rel = PCrel_format(op, pc) + 2; + + sprintf(buffer, "DBGT $%x", rel); + flags = DASMFLAG_STEP_OVER | DASMFLAG_STEP_OVER_EXTRA(1); + + break; + } + + // DBR + case 0xec: + { + INT32 rel = PCrel_format(op, pc) + 2; + + sprintf(buffer, "DBR $%x", rel); + flags = DASMFLAG_STEP_OVER | DASMFLAG_STEP_OVER_EXTRA(1); + + break; + } + + // FRAME + case 0xed: + + global_fp = 0; + LL_format(source, dest, op); + + sprintf(buffer, "FRAME %s, %s", dest, source); + + break; + + // CALL + case 0xee: case 0xef: + { + UINT32 const_val = LRconst_format(source, dest, op, &pc); + + if( source_code == SR_REGISTER && !source_bit ) + { + sprintf(buffer, "CALL %s, 0, $%x", dest, const_val); + flags = DASMFLAG_STEP_OVER; + } + else + { + sprintf(buffer, "CALL %s, %s, $%x", dest, source, const_val); + flags = DASMFLAG_STEP_OVER; + } + + break; + } + + // BV + case 0xf0: + { + INT32 rel = PCrel_format(op, pc) + 2; + + sprintf(buffer, "BV $%x", rel); + + break; + } + + // BNV + case 0xf1: + { + INT32 rel = PCrel_format(op, pc) + 2; + + sprintf(buffer, "BNV $%x", rel); + + break; + } + + // BE + case 0xf2: + { + INT32 rel = PCrel_format(op, pc) + 2; + + sprintf(buffer, "BE $%x", rel); + + break; + } + + // BNE + case 0xf3: + { + INT32 rel = PCrel_format(op, pc) + 2; + + sprintf(buffer, "BNE $%x", rel); + + break; + } + + // BC + case 0xf4: + { + INT32 rel = PCrel_format(op, pc) + 2; + + sprintf(buffer, "BC $%x", rel); + + break; + } + + // BNC + case 0xf5: + { + INT32 rel = PCrel_format(op, pc) + 2; + + sprintf(buffer, "BNC $%x", rel); + + break; + } + + // BSE + case 0xf6: + { + INT32 rel = PCrel_format(op, pc) + 2; + + sprintf(buffer, "BSE $%x", rel); + + break; + } + + // BHT + case 0xf7: + { + INT32 rel = PCrel_format(op, pc) + 2; + + sprintf(buffer, "BHT $%x", rel); + + break; + } + + // BN + case 0xf8: + { + INT32 rel = PCrel_format(op, pc) + 2; + + sprintf(buffer, "BN $%x", rel); + + break; + } + + // BNN + case 0xf9: + { + INT32 rel = PCrel_format(op, pc) + 2; + + sprintf(buffer, "BNN $%x", rel); + + break; + } + + // BLE + case 0xfa: + { + INT32 rel = PCrel_format(op, pc) + 2; + + sprintf(buffer, "BLE $%x", rel); + + break; + } + + // BGT + case 0xfb: + { + INT32 rel = PCrel_format(op, pc) + 2; + + sprintf(buffer, "BGT $%x", rel); + + break; + } + + // BR + case 0xfc: + { + INT32 rel = PCrel_format(op, pc) + 2; + + sprintf(buffer, "BR $%x", rel); + + break; + } + + // TRAPxx - TRAP + case 0xfd: case 0xfe: case 0xff: + { + UINT8 code = ((op & 0x300) >> 6) | (op & 0x03); + UINT8 trapno = (op & 0xfc) >> 2; + + switch( code ) + { + case TRAPLE: + sprintf(buffer, "TRAPLE %d", trapno); + flags = DASMFLAG_STEP_OVER; + + break; + + case TRAPGT: + sprintf(buffer, "TRAPGT %d", trapno); + flags = DASMFLAG_STEP_OVER; + + break; + + case TRAPLT: + sprintf(buffer, "TRAPLT %d", trapno); + flags = DASMFLAG_STEP_OVER; + + break; + + case TRAPGE: + sprintf(buffer, "TRAPGE %d", trapno); + flags = DASMFLAG_STEP_OVER; + + break; + + case TRAPSE: + sprintf(buffer, "TRAPSE %d", trapno); + flags = DASMFLAG_STEP_OVER; + + break; + + case TRAPHT: + sprintf(buffer, "TRAPHT %d", trapno); + flags = DASMFLAG_STEP_OVER; + + break; + + case TRAPST: + sprintf(buffer, "TRAPST %d", trapno); + flags = DASMFLAG_STEP_OVER; + + break; + + case TRAPHE: + sprintf(buffer, "TRAPHE %d", trapno); + flags = DASMFLAG_STEP_OVER; + + break; + + case TRAPE: + sprintf(buffer, "TRAPE %d", trapno); + flags = DASMFLAG_STEP_OVER; + + break; + + case TRAPNE: + sprintf(buffer, "TRAPNE %d", trapno); + flags = DASMFLAG_STEP_OVER; + + break; + + case TRAPV: + sprintf(buffer, "TRAPV %d", trapno); + flags = DASMFLAG_STEP_OVER; + + break; + + case TRAP: + sprintf(buffer, "TRAP %d", trapno); + flags = DASMFLAG_STEP_OVER; + + break; + } + + break; + } + } + + return size | flags | DASMFLAG_SUPPORTED; +} + +CPU_DISASSEMBLE( hyperstone_generic ) +{ + return dasm_hyperstone( buffer, pc, oprom, 0, 0 ); +} diff --git a/src/devices/cpu/e132xs/e132xs.c b/src/devices/cpu/e132xs/e132xs.c new file mode 100644 index 00000000000..fb156aae200 --- /dev/null +++ b/src/devices/cpu/e132xs/e132xs.c @@ -0,0 +1,4980 @@ +// license:BSD-3-Clause +// copyright-holders:Pierpaolo Prazzoli +/******************************************************************** + Hyperstone cpu emulator + written by Pierpaolo Prazzoli + + All the types are compatible, but they have different IRAM size and cycles + + Hyperstone models: + + 16 bits + - E1-16T + - E1-16XT + - E1-16XS + - E1-16XSR + + 32bits + - E1-32N or E1-32T + - E1-32XN or E1-32XT + - E1-32XS + - E1-32XSR + + Hynix models: + + 16 bits + - GMS30C2116 + - GMS30C2216 + + 32bits + - GMS30C2132 + - GMS30C2232 + + TODO: + - some wrong cycle counts + + CHANGELOG: + + Pierpaolo Prazzoli + - Fixed LDxx.N/P/S opcodes not to increment the destination register when + it's the same as the source or "next source" one. + + Pierpaolo Prazzoli + - Removed nested delays + - Added better delay branch support + - Fixed PC seen by a delay instruction, because a delay instruction + should use the delayed PC (thus allowing the execution of software + opcodes too) + + Tomasz Slanina + - Fixed delayed branching for delay instructions longer than 2 bytes + + Pierpaolo Prazzoli + - Added and fixed Timer without hack + + Tomasz Slanina + - Fixed MULU/MULS + - Fixed Carry in ADDC/SUBC + + Pierpaolo Prazzoli + - Fixed software opcodes used as delay instructions + - Added nested delays + + Tomasz Slanina + - Added "undefined" C flag to shift left instructions + + Pierpaolo Prazzoli + - Added interrupts-block for delay instructions + - Fixed get_emu_code_addr + - Added LDW.S and STW.S instructions + - Fixed floating point opcodes + + Tomasz Slanina + - interrputs after call and before frame are prohibited now + - emulation of FCR register + - Floating point opcodes (preliminary) + - Fixed stack addressing in RET/FRAME opcodes + - Fixed bug in SET_RS macro + - Fixed bug in return opcode (S flag) + - Added C/N flags calculation in add/adc/addi/adds/addsi and some shift opcodes + - Added writeback to ROL + - Fixed ROL/SAR/SARD/SHR/SHRD/SHL/SHLD opcode decoding (Local/Global regs) + - Fixed I and T flag in RET opcode + - Fixed XX/XM opcodes + - Fixed MOV opcode, when RD = PC + - Fixed execute_trap() + - Fixed ST opcodes, when when RS = SR + - Added interrupts + - Fixed I/O addressing + + Pierpaolo Prazzoli + - Fixed fetch + - Fixed decode of hyperstone_xm opcode + - Fixed 7 bits difference number in FRAME / RET instructions + - Some debbugger fixes + - Added generic registers decode function + - Some other little fixes. + + MooglyGuy 29/03/2004 + - Changed MOVI to use unsigned values instead of signed, correcting + an ugly glitch when loading 32-bit immediates. + Pierpaolo Prazzoli + - Same fix in get_const + + MooglyGuy - 02/27/04 + - Fixed delayed branching + - const_val for CALL should always have bit 0 clear + + Pierpaolo Prazzoli - 02/25/04 + - Fixed some wrong addresses to address local registers instead of memory + - Fixed FRAME and RET instruction + - Added preliminary I/O space + - Fixed some load / store instructions + + Pierpaolo Prazzoli - 02/20/04 + - Added execute_exception function + - Added FL == 0 always interpreted as 16 + + Pierpaolo Prazzoli - 02/19/04 + - Changed the reset to use the execute_trap(reset) which should be right to set + the initiale state of the cpu + - Added Trace exception + - Set of T flag in RET instruction + - Set I flag in interrupts entries and resetted by a RET instruction + - Added correct set instruction for SR + + Pierpaolo Prazzoli - 10/26/03 + - Changed get_lrconst to get_const and changed it to use the removed GET_CONST_RR + macro. + - Removed the High flag used in some opcodes, it should be used only in + MOV and MOVI instruction. + - Fixed MOV and MOVI instruction. + - Set to 1 FP is SR register at reset. + (From the doc: A Call, Trap or Software instruction increments the FP and sets FL + to 6, thus creating a new stack frame with the length of 6 registers). + + MooglyGuy - 10/25/03 + - Fixed CALL enough that it at least jumps to the right address, no word + yet as to whether or not it's working enough to return. + - Added get_lrconst() to get the const value for the CALL operand, since + apparently using immediate_value() was wrong. The code is ugly, but it + works properly. Vampire 1/2 now gets far enough to try to test its RAM. + - Just from looking at it, CALL apparently doesn't frame properly. I'm not + sure about FRAME, but perhaps it doesn't work properly - I'm not entirely + positive. The return address when vamphalf's memory check routine is + called at FFFFFD7E is stored in register L8, and then the RET instruction + at the end of the routine uses L1 as the return address, so that might + provide some clues as to how it works. + - I'd almost be willing to bet money that there's no framing at all since + the values in L0 - L15 as displayed by the debugger would change during a + CALL or FRAME operation. I'll look when I'm in the mood. + - The mood struck me, and I took a look at SET_L_REG and GET_L_REG. + Apparently no matter what the current frame pointer is they'll always use + local_regs[0] through local_regs[15]. + + MooglyGuy - 08/20/03 + - Added H flag support for MOV and MOVI + - Changed init routine to set S flag on boot. Apparently the CPU defaults to + supervisor mode as opposed to user mode when it powers on, as shown by the + vamphalf power-on routines. Makes sense, too, since if the machine booted + in user mode, it would be impossible to get into supervisor mode. + + Pierpaolo Prazzoli - 08/19/03 + - Added check for D_BIT and S_BIT where PC or SR must or must not be denoted. + (movd, divu, divs, ldxx1, ldxx2, stxx1, stxx2, mulu, muls, set, mul + call, chk) + + MooglyGuy - 08/17/03 + - Working on support for H flag, nothing quite done yet + - Added trap Range Error for CHK PC, PC + - Fixed relative jumps, they have to be taken from the opcode following the + jump minstead of the jump opcode itself. + + Pierpaolo Prazzoli - 08/17/03 + - Fixed get_pcrel() when OP & 0x80 is set. + - Decremented PC by 2 also in MOV, ADD, ADDI, SUM, SUB and added the check if + D_BIT is not set. (when pc is changed they are implicit branch) + + MooglyGuy - 08/17/03 + - Implemented a crude hack to set FL in the SR to 6, since according to the docs + that's supposed to happen each time a trap occurs, apparently including when + the processor starts up. The 3rd opcode executed in vamphalf checks to see if + the FL flag in SR 6, so it's apparently the "correct" behaviour despite the + docs not saying anything on it. If FL is not 6, the branch falls through and + encounters a CHK PC, L2, which at that point will always throw a range trap. + The range trap vector contains 00000000 (CHK PC, PC), which according to the + docs will always throw a range trap (which would effectively lock the system). + This revealed a bug: CHK PC, PC apparently does not throw a range trap, which + needs to be fixed. Now that the "correct" behaviour is hacked in with the FL + flags, it reveals yet another bug in that the branch is interpreted as being + +0x8700. This means that the PC then wraps around to 000082B0, give or take + a few bytes. While it does indeed branch to valid code, I highly doubt that + this is the desired effect. Check for signed/unsigned relative branch, maybe? + + MooglyGuy - 08/16/03 + - Fixed the debugger at least somewhat so that it displays hex instead of decimal, + and so that it disassembles opcodes properly. + - Fixed hyperstone_execute() to increment PC *after* executing the opcode instead of + before. This is probably why vamphalf was booting to fffffff8, but executing at + fffffffa instead. + - Changed execute_trap to decrement PC by 2 so that the next opcode isn't skipped + after a trap + - Changed execute_br to decrement PC by 2 so that the next opcode isn't skipped + after a branch + - Changed hyperstone_movi to decrement PC by 2 when G0 (PC) is modified so that the + next opcode isn't skipped after a branch + - Changed hyperstone_movi to default to a UINT32 being moved into the register + as opposed to a UINT8. This is wrong, the bit width is quite likely to be + dependent on the n field in the Rimm instruction type. However, vamphalf uses + MOVI G0,[FFFF]FBAC (n=$13) since there's apparently no absolute branch opcode. + What kind of CPU is this that it doesn't have an absolute jump in its branch + instructions and you have to use an immediate MOV to do an abs. jump!? + - Replaced usage of logerror() with smf's verboselog() + +*********************************************************************/ + +#include "emu.h" +#include "debugger.h" +#include "e132xs.h" + +#ifdef MAME_DEBUG +#define DEBUG_PRINTF(x) do { osd_printf_debug x; } while (0) +#else +#define DEBUG_PRINTF(x) do { } while (0) +#endif + +// set C in adds/addsi/subs/sums +#define SETCARRYS 0 +#define MISSIONCRAFT_FLAGS 1 + +/* Registers */ + +/* Internal registers */ + +#define SREG (decode)->src_value +#define SREGF (decode)->next_src_value +#define DREG (decode)->dst_value +#define DREGF (decode)->next_dst_value +#define EXTRA_U (decode)->extra.u +#define EXTRA_S (decode)->extra.s + +#define SET_SREG( _data_ ) ((decode)->src_is_local ? set_local_register((decode)->src, (UINT32)_data_) : set_global_register((decode)->src, (UINT32)_data_)) +#define SET_SREGF( _data_ ) ((decode)->src_is_local ? set_local_register((decode)->src + 1, (UINT32)_data_) : set_global_register((decode)->src + 1, (UINT32)_data_)) +#define SET_DREG( _data_ ) ((decode)->dst_is_local ? set_local_register((decode)->dst, (UINT32)_data_) : set_global_register((decode)->dst, (UINT32)_data_)) +#define SET_DREGF( _data_ ) ((decode)->dst_is_local ? set_local_register((decode)->dst + 1, (UINT32)_data_) : set_global_register((decode)->dst + 1, (UINT32)_data_)) + +#define SRC_IS_PC (!(decode)->src_is_local && (decode)->src == PC_REGISTER) +#define DST_IS_PC (!(decode)->dst_is_local && (decode)->dst == PC_REGISTER) +#define SRC_IS_SR (!(decode)->src_is_local && (decode)->src == SR_REGISTER) +#define DST_IS_SR (!(decode)->dst_is_local && (decode)->dst == SR_REGISTER) +#define SAME_SRC_DST (decode)->same_src_dst +#define SAME_SRC_DSTF (decode)->same_src_dstf +#define SAME_SRCF_DST (decode)->same_srcf_dst + +//************************************************************************** +// INTERNAL ADDRESS MAP +//************************************************************************** + +// 4Kb IRAM (On-Chip Memory) + +static ADDRESS_MAP_START( e116_4k_iram_map, AS_PROGRAM, 16, hyperstone_device ) + AM_RANGE(0xc0000000, 0xc0000fff) AM_RAM AM_MIRROR(0x1ffff000) +ADDRESS_MAP_END + +static ADDRESS_MAP_START( e132_4k_iram_map, AS_PROGRAM, 32, hyperstone_device ) + AM_RANGE(0xc0000000, 0xc0000fff) AM_RAM AM_MIRROR(0x1ffff000) +ADDRESS_MAP_END + + +// 8Kb IRAM (On-Chip Memory) + +static ADDRESS_MAP_START( e116_8k_iram_map, AS_PROGRAM, 16, hyperstone_device ) + AM_RANGE(0xc0000000, 0xc0001fff) AM_RAM AM_MIRROR(0x1fffe000) +ADDRESS_MAP_END + +static ADDRESS_MAP_START( e132_8k_iram_map, AS_PROGRAM, 32, hyperstone_device ) + AM_RANGE(0xc0000000, 0xc0001fff) AM_RAM AM_MIRROR(0x1fffe000) +ADDRESS_MAP_END + + +// 16Kb IRAM (On-Chip Memory) + +static ADDRESS_MAP_START( e116_16k_iram_map, AS_PROGRAM, 16, hyperstone_device ) + AM_RANGE(0xc0000000, 0xc0003fff) AM_RAM AM_MIRROR(0x1fffc000) +ADDRESS_MAP_END + +static ADDRESS_MAP_START( e132_16k_iram_map, AS_PROGRAM, 32, hyperstone_device ) + AM_RANGE(0xc0000000, 0xc0003fff) AM_RAM AM_MIRROR(0x1fffc000) +ADDRESS_MAP_END + + +//------------------------------------------------- +// hyperstone_device - constructor +//------------------------------------------------- + +hyperstone_device::hyperstone_device(const machine_config &mconfig, const char *name, const char *tag, device_t *owner, UINT32 clock, + const device_type type, UINT32 prg_data_width, UINT32 io_data_width, address_map_constructor internal_map, const char *shortname, const char *source) + : cpu_device(mconfig, type, name, tag, owner, clock, shortname, source), + m_program_config("program", ENDIANNESS_BIG, prg_data_width, 32, 0, internal_map), + m_io_config("io", ENDIANNESS_BIG, io_data_width, 15), + m_icount(0) +{ + // build the opcode table + for (int op = 0; op < 256; op++) + m_opcode[op] = s_opcodetable[op]; +} + + +//------------------------------------------------- +// e116t_device - constructor +//------------------------------------------------- + +e116t_device::e116t_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : hyperstone_device(mconfig, "E1-16T", tag, owner, clock, E116T, 16, 16, ADDRESS_MAP_NAME(e116_4k_iram_map), "e116t", __FILE__) +{ +} + + +//------------------------------------------------- +// e116xt_device - constructor +//------------------------------------------------- + +e116xt_device::e116xt_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : hyperstone_device(mconfig, "E1-16XT", tag, owner, clock, E116XT, 16, 16, ADDRESS_MAP_NAME(e116_8k_iram_map), "e116xt", __FILE__) +{ +} + + +//------------------------------------------------- +// e116xs_device - constructor +//------------------------------------------------- + +e116xs_device::e116xs_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : hyperstone_device(mconfig, "E1-16XS", tag, owner, clock, E116XS, 16, 16, ADDRESS_MAP_NAME(e116_16k_iram_map), "e116xs", __FILE__) +{ +} + + +//------------------------------------------------- +// e116xsr_device - constructor +//------------------------------------------------- + +e116xsr_device::e116xsr_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : hyperstone_device(mconfig, "E1-16XSR", tag, owner, clock, E116XT, 16, 16, ADDRESS_MAP_NAME(e116_16k_iram_map), "e116xsr", __FILE__) +{ +} + + +//------------------------------------------------- +// e132n_device - constructor +//------------------------------------------------- + +e132n_device::e132n_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : hyperstone_device(mconfig, "E1-32N", tag, owner, clock, E132N, 32, 32, ADDRESS_MAP_NAME(e132_4k_iram_map), "e132n", __FILE__) +{ +} + + +//------------------------------------------------- +// e132t_device - constructor +//------------------------------------------------- + +e132t_device::e132t_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : hyperstone_device(mconfig, "E1-32T", tag, owner, clock, E132T, 32, 32, ADDRESS_MAP_NAME(e132_4k_iram_map), "e132t", __FILE__) +{ +} + + +//------------------------------------------------- +// e132xn_device - constructor +//------------------------------------------------- + +e132xn_device::e132xn_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : hyperstone_device(mconfig, "E1-32XN", tag, owner, clock, E132XN, 32, 32, ADDRESS_MAP_NAME(e132_8k_iram_map), "e132xn", __FILE__) +{ +} + + +//------------------------------------------------- +// e132xt_device - constructor +//------------------------------------------------- + +e132xt_device::e132xt_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : hyperstone_device(mconfig, "E1-32XT", tag, owner, clock, E132XT, 32, 32, ADDRESS_MAP_NAME(e132_8k_iram_map), "e132xt", __FILE__) +{ +} + + +//------------------------------------------------- +// e132xs_device - constructor +//------------------------------------------------- + +e132xs_device::e132xs_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : hyperstone_device(mconfig, "E1-32XS", tag, owner, clock, E132XS, 32, 32, ADDRESS_MAP_NAME(e132_16k_iram_map), "e132xs", __FILE__) +{ +} + + +//------------------------------------------------- +// e132xsr_device - constructor +//------------------------------------------------- + +e132xsr_device::e132xsr_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : hyperstone_device(mconfig, "E1-32XSR", tag, owner, clock, E132XSR, 32, 32, ADDRESS_MAP_NAME(e132_16k_iram_map), "e132xsr", __FILE__) +{ +} + + +//------------------------------------------------- +// gms30c2116_device - constructor +//------------------------------------------------- + +gms30c2116_device::gms30c2116_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : hyperstone_device(mconfig, "GMS30C2116", tag, owner, clock, GMS30C2116, 16, 16, ADDRESS_MAP_NAME(e116_4k_iram_map), "gms30c2116", __FILE__) +{ +} + + +//------------------------------------------------- +// gms30c2132_device - constructor +//------------------------------------------------- + +gms30c2132_device::gms30c2132_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : hyperstone_device(mconfig, "GMS30C2132", tag, owner, clock, GMS30C2132, 32, 32, ADDRESS_MAP_NAME(e132_4k_iram_map), "gms30c2132", __FILE__) +{ +} + + +//------------------------------------------------- +// gms30c2216_device - constructor +//------------------------------------------------- + +gms30c2216_device::gms30c2216_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : hyperstone_device(mconfig, "GMS30C2216", tag, owner, clock, GMS30C2216, 16, 16, ADDRESS_MAP_NAME(e116_8k_iram_map), "gms30c2216", __FILE__) +{ +} + + +//------------------------------------------------- +// gms30c2232_device - constructor +//------------------------------------------------- + +gms30c2232_device::gms30c2232_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : hyperstone_device(mconfig, "GMS30C2232", tag, owner, clock, GMS30C2232, 32, 32, ADDRESS_MAP_NAME(e132_8k_iram_map), "gms30c2232", __FILE__) +{ +} + +/* Return the entry point for a determinated trap */ +UINT32 hyperstone_device::get_trap_addr(UINT8 trapno) +{ + UINT32 addr; + if( m_trap_entry == 0xffffff00 ) /* @ MEM3 */ + { + addr = trapno * 4; + } + else + { + addr = (63 - trapno) * 4; + } + addr |= m_trap_entry; + + return addr; +} + +/* Return the entry point for a determinated emulated code (the one for "extend" opcode is reserved) */ +UINT32 hyperstone_device::get_emu_code_addr(UINT8 num) /* num is OP */ +{ + UINT32 addr; + if( m_trap_entry == 0xffffff00 ) /* @ MEM3 */ + { + addr = (m_trap_entry - 0x100) | ((num & 0xf) << 4); + } + else + { + addr = m_trap_entry | (0x10c | ((0xcf - num) << 4)); + } + return addr; +} + +void hyperstone_device::hyperstone_set_trap_entry(int which) +{ + switch( which ) + { + case E132XS_ENTRY_MEM0: + m_trap_entry = 0x00000000; + break; + + case E132XS_ENTRY_MEM1: + m_trap_entry = 0x40000000; + break; + + case E132XS_ENTRY_MEM2: + m_trap_entry = 0x80000000; + break; + + case E132XS_ENTRY_MEM3: + m_trap_entry = 0xffffff00; + break; + + case E132XS_ENTRY_IRAM: + m_trap_entry = 0xc0000000; + break; + + default: + DEBUG_PRINTF(("Set entry point to a reserved value: %d\n", which)); + break; + } +} + +#define OP m_op +#define PPC m_ppc //previous pc +#define PC m_global_regs[0] //Program Counter +#define SR m_global_regs[1] //Status Register +#define FER m_global_regs[2] //Floating-Point Exception Register +// 03 - 15 General Purpose Registers +// 16 - 17 Reserved +#define SP m_global_regs[18] //Stack Pointer +#define UB m_global_regs[19] //Upper Stack Bound +#define BCR m_global_regs[20] //Bus Control Register +#define TPR m_global_regs[21] //Timer Prescaler Register +#define TCR m_global_regs[22] //Timer Compare Register +#define TR compute_tr() //Timer Register +#define WCR m_global_regs[24] //Watchdog Compare Register +#define ISR m_global_regs[25] //Input Status Register +#define FCR m_global_regs[26] //Function Control Register +#define MCR m_global_regs[27] //Memory Control Register +// 28 - 31 Reserved + +/* SR flags */ +#define GET_C ( SR & 0x00000001) // bit 0 //CARRY +#define GET_Z ((SR & 0x00000002)>>1) // bit 1 //ZERO +#define GET_N ((SR & 0x00000004)>>2) // bit 2 //NEGATIVE +#define GET_V ((SR & 0x00000008)>>3) // bit 3 //OVERFLOW +#define GET_M ((SR & 0x00000010)>>4) // bit 4 //CACHE-MODE +#define GET_H ((SR & 0x00000020)>>5) // bit 5 //HIGHGLOBAL +// bit 6 RESERVED (always 0) +#define GET_I ((SR & 0x00000080)>>7) // bit 7 //INTERRUPT-MODE +#define GET_FTE ((SR & 0x00001f00)>>8) // bits 12 - 8 //Floating-Point Trap Enable +#define GET_FRM ((SR & 0x00006000)>>13) // bits 14 - 13 //Floating-Point Rounding Mode +#define GET_L ((SR & 0x00008000)>>15) // bit 15 //INTERRUPT-LOCK +#define GET_T ((SR & 0x00010000)>>16) // bit 16 //TRACE-MODE +#define GET_P ((SR & 0x00020000)>>17) // bit 17 //TRACE PENDING +#define GET_S ((SR & 0x00040000)>>18) // bit 18 //SUPERVISOR STATE +#define GET_ILC ((SR & 0x00180000)>>19) // bits 20 - 19 //INSTRUCTION-LENGTH +/* if FL is zero it is always interpreted as 16 */ +#define GET_FL ((SR & 0x01e00000) ? ((SR & 0x01e00000)>>21) : 16) // bits 24 - 21 //FRAME LENGTH +#define GET_FP ((SR & 0xfe000000)>>25) // bits 31 - 25 //FRAME POINTER + +#define SET_C(val) (SR = (SR & ~0x00000001) | (val)) +#define SET_Z(val) (SR = (SR & ~0x00000002) | ((val) << 1)) +#define SET_N(val) (SR = (SR & ~0x00000004) | ((val) << 2)) +#define SET_V(val) (SR = (SR & ~0x00000008) | ((val) << 3)) +#define SET_M(val) (SR = (SR & ~0x00000010) | ((val) << 4)) +#define SET_H(val) (SR = (SR & ~0x00000020) | ((val) << 5)) +#define SET_I(val) (SR = (SR & ~0x00000080) | ((val) << 7)) +#define SET_FTE(val) (SR = (SR & ~0x00001f00) | ((val) << 8)) +#define SET_FRM(val) (SR = (SR & ~0x00006000) | ((val) << 13)) +#define SET_L(val) (SR = (SR & ~0x00008000) | ((val) << 15)) +#define SET_T(val) (SR = (SR & ~0x00010000) | ((val) << 16)) +#define SET_P(val) (SR = (SR & ~0x00020000) | ((val) << 17)) +#define SET_S(val) (SR = (SR & ~0x00040000) | ((val) << 18)) +#define SET_ILC(val) (SR = (SR & ~0x00180000) | ((val) << 19)) +#define SET_FL(val) (SR = (SR & ~0x01e00000) | ((val) << 21)) +#define SET_FP(val) (SR = (SR & ~0xfe000000) | ((val) << 25)) + +#define SET_PC(val) PC = ((val) & 0xfffffffe) //PC(0) = 0 +#define SET_SP(val) SP = ((val) & 0xfffffffc) //SP(0) = SP(1) = 0 +#define SET_UB(val) UB = ((val) & 0xfffffffc) //UB(0) = UB(1) = 0 + +#define SET_LOW_SR(val) (SR = (SR & 0xffff0000) | ((val) & 0x0000ffff)) // when SR is addressed, only low 16 bits can be changed + + +#define CHECK_C(x) (SR = (SR & ~0x00000001) | (((x) & (((UINT64)1) << 32)) ? 1 : 0 )) +#define CHECK_VADD(x,y,z) (SR = (SR & ~0x00000008) | ((((x) ^ (z)) & ((y) ^ (z)) & 0x80000000) ? 8: 0)) +#define CHECK_VADD3(x,y,w,z) (SR = (SR & ~0x00000008) | ((((x) ^ (z)) & ((y) ^ (z)) & ((w) ^ (z)) & 0x80000000) ? 8: 0)) +#define CHECK_VSUB(x,y,z) (SR = (SR & ~0x00000008) | ((((z) ^ (y)) & ((y) ^ (x)) & 0x80000000) ? 8: 0)) + + +/* FER flags */ +#define GET_ACCRUED (FER & 0x0000001f) //bits 4 - 0 //Floating-Point Accrued Exceptions +#define GET_ACTUAL (FER & 0x00001f00) //bits 12 - 8 //Floating-Point Actual Exceptions +//other bits are reversed, in particular 7 - 5 for the operating system. +//the user program can only changes the above 2 flags + + +UINT32 hyperstone_device::compute_tr() +{ + UINT64 cycles_since_base = total_cycles() - m_tr_base_cycles; + UINT64 clocks_since_base = cycles_since_base >> m_clck_scale; + return m_tr_base_value + (clocks_since_base / m_tr_clocks_per_tick); +} + +void hyperstone_device::update_timer_prescale() +{ + UINT32 prevtr = compute_tr(); + TPR &= ~0x80000000; + m_clck_scale = (TPR >> 26) & m_clock_scale_mask; + m_clock_cycles_1 = 1 << m_clck_scale; + m_clock_cycles_2 = 2 << m_clck_scale; + m_clock_cycles_4 = 4 << m_clck_scale; + m_clock_cycles_6 = 6 << m_clck_scale; + m_tr_clocks_per_tick = ((TPR >> 16) & 0xff) + 2; + m_tr_base_value = prevtr; + m_tr_base_cycles = total_cycles(); +} + +void hyperstone_device::adjust_timer_interrupt() +{ + UINT64 cycles_since_base = total_cycles() - m_tr_base_cycles; + UINT64 clocks_since_base = cycles_since_base >> m_clck_scale; + UINT64 cycles_until_next_clock = cycles_since_base - (clocks_since_base << m_clck_scale); + + if (cycles_until_next_clock == 0) + cycles_until_next_clock = (UINT64)(1 << m_clck_scale); + + /* special case: if we have a change pending, set a timer to fire then */ + if (TPR & 0x80000000) + { + UINT64 clocks_until_int = m_tr_clocks_per_tick - (clocks_since_base % m_tr_clocks_per_tick); + UINT64 cycles_until_int = (clocks_until_int << m_clck_scale) + cycles_until_next_clock; + m_timer->adjust(cycles_to_attotime(cycles_until_int + 1), 1); + } + + /* else if the timer interrupt is enabled, configure it to fire at the appropriate time */ + else if (!(FCR & 0x00800000)) + { + UINT32 curtr = m_tr_base_value + (clocks_since_base / m_tr_clocks_per_tick); + UINT32 delta = TCR - curtr; + if (delta > 0x80000000) + { + if (!m_timer_int_pending) + m_timer->adjust(attotime::zero); + } + else + { + UINT64 clocks_until_int = mulu_32x32(delta, m_tr_clocks_per_tick); + UINT64 cycles_until_int = (clocks_until_int << m_clck_scale) + cycles_until_next_clock; + m_timer->adjust(cycles_to_attotime(cycles_until_int)); + } + } + + /* otherwise, disable the timer */ + else + m_timer->adjust(attotime::never); +} + +TIMER_CALLBACK_MEMBER( hyperstone_device::timer_callback ) +{ + int update = param; + + /* update the values if necessary */ + if (update) + update_timer_prescale(); + + /* see if the timer is right for firing */ + if (!((compute_tr() - TCR) & 0x80000000)) + m_timer_int_pending = 1; + + /* adjust ourselves for the next time */ + else + adjust_timer_interrupt(); +} + + + + +UINT32 hyperstone_device::get_global_register(UINT8 code) +{ +/* + if( code >= 16 ) + { + switch( code ) + { + case 16: + case 17: + case 28: + case 29: + case 30: + case 31: + DEBUG_PRINTF(("read _Reserved_ Global Register %d @ %08X\n",code,PC)); + break; + + case BCR_REGISTER: + DEBUG_PRINTF(("read write-only BCR register @ %08X\n",PC)); + return 0; + + case TPR_REGISTER: + DEBUG_PRINTF(("read write-only TPR register @ %08X\n",PC)); + return 0; + + case FCR_REGISTER: + DEBUG_PRINTF(("read write-only FCR register @ %08X\n",PC)); + return 0; + + case MCR_REGISTER: + DEBUG_PRINTF(("read write-only MCR register @ %08X\n",PC)); + return 0; + } + } +*/ + if (code == TR_REGISTER) + { + /* it is common to poll this in a loop */ + if (m_icount > m_tr_clocks_per_tick / 2) + m_icount -= m_tr_clocks_per_tick / 2; + return compute_tr(); + } + return m_global_regs[code]; +} + +void hyperstone_device::set_local_register(UINT8 code, UINT32 val) +{ + UINT8 new_code = (code + GET_FP) % 64; + + m_local_regs[new_code] = val; +} + +void hyperstone_device::set_global_register(UINT8 code, UINT32 val) +{ + //TODO: add correct FER set instruction + + if( code == PC_REGISTER ) + { + SET_PC(val); + } + else if( code == SR_REGISTER ) + { + SET_LOW_SR(val); // only a RET instruction can change the full content of SR + SR &= ~0x40; //reserved bit 6 always zero + if (m_intblock < 1) + m_intblock = 1; + } + else + { + UINT32 oldval = m_global_regs[code]; + if( code != ISR_REGISTER ) + m_global_regs[code] = val; + else + DEBUG_PRINTF(("Written to ISR register. PC = %08X\n", PC)); + + //are these set only when privilege bit is set? + if( code >= 16 ) + { + switch( code ) + { + case 18: + SET_SP(val); + break; + + case 19: + SET_UB(val); + break; +/* + case ISR_REGISTER: + DEBUG_PRINTF(("written %08X to read-only ISR register\n",val)); + break; + + case TCR_REGISTER: +// DEBUG_PRINTF(("written %08X to TCR register\n",val)); + break; + + case 23: +// DEBUG_PRINTF(("written %08X to TR register\n",val)); + break; + + case 24: +// DEBUG_PRINTF(("written %08X to WCR register\n",val)); + break; + + case 16: + case 17: + case 28: + case 29: + case 30: + case 31: + DEBUG_PRINTF(("written %08X to _Reserved_ Global Register %d\n",val,code)); + break; + + case BCR_REGISTER: + break; +*/ + case TR_REGISTER: + m_tr_base_value = val; + m_tr_base_cycles = total_cycles(); + adjust_timer_interrupt(); + break; + + case TPR_REGISTER: + if (!(val & 0x80000000)) /* change immediately */ + update_timer_prescale(); + adjust_timer_interrupt(); + break; + + case TCR_REGISTER: + if (oldval != val) + { + adjust_timer_interrupt(); + if (m_intblock < 1) + m_intblock = 1; + } + break; + + case FCR_REGISTER: + if ((oldval ^ val) & 0x00800000) + adjust_timer_interrupt(); + if (m_intblock < 1) + m_intblock = 1; + break; + + case MCR_REGISTER: + // bits 14..12 EntryTableMap + hyperstone_set_trap_entry((val & 0x7000) >> 12); + break; + } + } + } +} + +#define GET_ABS_L_REG(code) m_local_regs[code] +#define SET_L_REG(code, val) set_local_register(code, val) +#define SET_ABS_L_REG(code, val) m_local_regs[code] = val +#define GET_G_REG(code) get_global_register(code) +#define SET_G_REG(code, val) set_global_register(code, val) + +#define S_BIT ((OP & 0x100) >> 8) +#define N_BIT S_BIT +#define D_BIT ((OP & 0x200) >> 9) +#define N_VALUE ((N_BIT << 4) | (OP & 0x0f)) +#define DST_CODE ((OP & 0xf0) >> 4) +#define SRC_CODE (OP & 0x0f) +#define SIGN_BIT(val) ((val & 0x80000000) >> 31) + +#define LOCAL 1 + +static const INT32 immediate_values[32] = +{ + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15, + 16, 0, 0, 0, 32, 64, 128, 0x80000000, + -8, -7, -6, -5, -4, -3, -2, -1 +}; + +#define WRITE_ONLY_REGMASK ((1 << BCR_REGISTER) | (1 << TPR_REGISTER) | (1 << FCR_REGISTER) | (1 << MCR_REGISTER)) + +#define decode_source(decode, local, hflag) \ +do \ +{ \ + if(local) \ + { \ + UINT8 code = (decode)->src; \ + (decode)->src_is_local = 1; \ + code = ((decode)->src + GET_FP) % 64; /* registers offset by frame pointer */\ + SREG = m_local_regs[code]; \ + code = ((decode)->src + 1 + GET_FP) % 64; \ + SREGF = m_local_regs[code]; \ + } \ + else \ + { \ + (decode)->src_is_local = 0; \ + \ + if (!hflag) \ + { \ + SREG = get_global_register((decode)->src); \ + \ + /* bound safe */ \ + if ((decode)->src != 15) \ + SREGF = get_global_register((decode)->src + 1); \ + } \ + else \ + { \ + (decode)->src += 16; \ + \ + SREG = get_global_register((decode)->src); \ + if ((WRITE_ONLY_REGMASK >> (decode)->src) & 1) \ + SREG = 0; /* write-only registers */ \ + else if ((decode)->src == ISR_REGISTER) \ + DEBUG_PRINTF(("read src ISR. PC = %08X\n",PPC)); \ + \ + /* bound safe */ \ + if ((decode)->src != 31) \ + SREGF = get_global_register((decode)->src + 1); \ + } \ + } \ +} while (0) + +#define decode_dest(decode, local, hflag) \ +do \ +{ \ + if(local) \ + { \ + UINT8 code = (decode)->dst; \ + (decode)->dst_is_local = 1; \ + code = ((decode)->dst + GET_FP) % 64; /* registers offset by frame pointer */\ + DREG = m_local_regs[code]; \ + code = ((decode)->dst + 1 + GET_FP) % 64; \ + DREGF = m_local_regs[code]; \ + } \ + else \ + { \ + (decode)->dst_is_local = 0; \ + \ + if (!hflag) \ + { \ + DREG = get_global_register((decode)->dst); \ + \ + /* bound safe */ \ + if ((decode)->dst != 15) \ + DREGF = get_global_register((decode)->dst + 1); \ + } \ + else \ + { \ + (decode)->dst += 16; \ + \ + DREG = get_global_register((decode)->dst); \ + if( (decode)->dst == ISR_REGISTER ) \ + DEBUG_PRINTF(("read dst ISR. PC = %08X\n",PPC)); \ + \ + /* bound safe */ \ + if ((decode)->dst != 31) \ + DREGF = get_global_register((decode)->dst + 1); \ + } \ + } \ +} while (0) + +#define decode_RR(decode, dlocal, slocal) \ +do \ +{ \ + (decode)->src = SRC_CODE; \ + (decode)->dst = DST_CODE; \ + decode_source(decode, slocal, 0); \ + decode_dest(decode, dlocal, 0); \ + \ + if( (slocal) == (dlocal) && SRC_CODE == DST_CODE ) \ + SAME_SRC_DST = 1; \ + \ + if( (slocal) == LOCAL && (dlocal) == LOCAL ) \ + { \ + if( SRC_CODE == ((DST_CODE + 1) % 64) ) \ + SAME_SRC_DSTF = 1; \ + \ + if( ((SRC_CODE + 1) % 64) == DST_CODE ) \ + SAME_SRCF_DST = 1; \ + } \ + else if( (slocal) == 0 && (dlocal) == 0 ) \ + { \ + if( SRC_CODE == (DST_CODE + 1) ) \ + SAME_SRC_DSTF = 1; \ + \ + if( (SRC_CODE + 1) == DST_CODE ) \ + SAME_SRCF_DST = 1; \ + } \ +} while (0) + +#define decode_LL(decode) \ +do \ +{ \ + (decode)->src = SRC_CODE; \ + (decode)->dst = DST_CODE; \ + decode_source(decode, LOCAL, 0); \ + decode_dest(decode, LOCAL, 0); \ + \ + if( SRC_CODE == DST_CODE ) \ + SAME_SRC_DST = 1; \ + \ + if( SRC_CODE == ((DST_CODE + 1) % 64) ) \ + SAME_SRC_DSTF = 1; \ +} while (0) + +#define decode_LR(decode, slocal) \ +do \ +{ \ + (decode)->src = SRC_CODE; \ + (decode)->dst = DST_CODE; \ + decode_source(decode, slocal, 0); \ + decode_dest(decode, LOCAL, 0); \ + \ + if( ((SRC_CODE + 1) % 64) == DST_CODE && slocal == LOCAL ) \ + SAME_SRCF_DST = 1; \ +} while (0) + +#define check_delay_PC() \ +do \ +{ \ + /* if PC is used in a delay instruction, the delayed PC should be used */ \ + if( m_delay.delay_cmd == DELAY_EXECUTE ) \ + { \ + PC = m_delay.delay_pc; \ + m_delay.delay_cmd = NO_DELAY; \ + } \ +} while (0) + +#define decode_immediate(decode, nbit) \ +do \ +{ \ + if (!nbit) \ + EXTRA_U = immediate_values[OP & 0x0f]; \ + else \ + switch( OP & 0x0f ) \ + { \ + default: \ + EXTRA_U = immediate_values[0x10 + (OP & 0x0f)]; \ + break; \ + \ + case 1: \ + m_instruction_length = 3; \ + EXTRA_U = (READ_OP(PC) << 16) | READ_OP(PC + 2); \ + PC += 4; \ + break; \ + \ + case 2: \ + m_instruction_length = 2; \ + EXTRA_U = READ_OP(PC); \ + PC += 2; \ + break; \ + \ + case 3: \ + m_instruction_length = 2; \ + EXTRA_U = 0xffff0000 | READ_OP(PC); \ + PC += 2; \ + break; \ + } \ +} while (0) + +#define decode_const(decode) \ +do \ +{ \ + UINT16 imm_1 = READ_OP(PC); \ + \ + PC += 2; \ + m_instruction_length = 2; \ + \ + if( E_BIT(imm_1) ) \ + { \ + UINT16 imm_2 = READ_OP(PC); \ + \ + PC += 2; \ + m_instruction_length = 3; \ + \ + EXTRA_S = imm_2; \ + EXTRA_S |= ((imm_1 & 0x3fff) << 16); \ + \ + if( S_BIT_CONST(imm_1) ) \ + { \ + EXTRA_S |= 0xc0000000; \ + } \ + } \ + else \ + { \ + EXTRA_S = imm_1 & 0x3fff; \ + \ + if( S_BIT_CONST(imm_1) ) \ + { \ + EXTRA_S |= 0xffffc000; \ + } \ + } \ +} while (0) + +#define decode_pcrel(decode) \ +do \ +{ \ + if( OP & 0x80 ) \ + { \ + UINT16 next = READ_OP(PC); \ + \ + PC += 2; \ + m_instruction_length = 2; \ + \ + EXTRA_S = (OP & 0x7f) << 16; \ + EXTRA_S |= (next & 0xfffe); \ + \ + if( next & 1 ) \ + EXTRA_S |= 0xff800000; \ + } \ + else \ + { \ + EXTRA_S = OP & 0x7e; \ + \ + if( OP & 1 ) \ + EXTRA_S |= 0xffffff80; \ + } \ +} while (0) + +#define decode_dis(decode) \ +do \ +{ \ + UINT16 next_1 = READ_OP(PC); \ + \ + PC += 2; \ + m_instruction_length = 2; \ + \ + (decode)->sub_type = DD(next_1); \ + \ + if( E_BIT(next_1) ) \ + { \ + UINT16 next_2 = READ_OP(PC); \ + \ + PC += 2; \ + m_instruction_length = 3; \ + \ + EXTRA_S = next_2; \ + EXTRA_S |= ((next_1 & 0xfff) << 16); \ + \ + if( S_BIT_CONST(next_1) ) \ + { \ + EXTRA_S |= 0xf0000000; \ + } \ + } \ + else \ + { \ + EXTRA_S = next_1 & 0xfff; \ + \ + if( S_BIT_CONST(next_1) ) \ + { \ + EXTRA_S |= 0xfffff000; \ + } \ + } \ +} while (0) + +#define decode_lim(decode) \ +do \ +{ \ + UINT32 next = READ_OP(PC); \ + PC += 2; \ + m_instruction_length = 2; \ + \ + (decode)->sub_type = X_CODE(next); \ + \ + if( E_BIT(next) ) \ + { \ + EXTRA_U = ((next & 0xfff) << 16) | READ_OP(PC); \ + PC += 2; \ + m_instruction_length = 3; \ + } \ + else \ + { \ + EXTRA_U = next & 0xfff; \ + } \ +} while (0) + +#define RRdecode(decode, dlocal, slocal) \ +do \ +{ \ + check_delay_PC(); \ + decode_RR(decode, dlocal, slocal); \ +} while (0) + +#define RRlimdecode(decode, dlocal, slocal) \ +do \ +{ \ + decode_lim(decode); \ + check_delay_PC(); \ + decode_RR(decode, dlocal, slocal); \ +} while (0) + +#define RRconstdecode(decode, dlocal, slocal) \ +do \ +{ \ + decode_const(decode); \ + check_delay_PC(); \ + decode_RR(decode, dlocal, slocal); \ +} while (0) + +#define RRdisdecode(decode, dlocal, slocal) \ +do \ +{ \ + decode_dis(decode); \ + check_delay_PC(); \ + decode_RR(decode, dlocal, slocal); \ +} while (0) + +#define RRdecodewithHflag(decode, dlocal, slocal) \ +do \ +{ \ + check_delay_PC(); \ + (decode)->src = SRC_CODE; \ + (decode)->dst = DST_CODE; \ + decode_source(decode, slocal, GET_H); \ + decode_dest(decode, dlocal, GET_H); \ + \ + if(GET_H) \ + if(slocal == 0 && dlocal == 0) \ + DEBUG_PRINTF(("MOV with hflag and 2 GRegs! PC = %08X\n",PPC)); \ +} while (0) + +#define Rimmdecode(decode, dlocal, nbit) \ +do \ +{ \ + decode_immediate(decode, nbit); \ + check_delay_PC(); \ + (decode)->dst = DST_CODE; \ + decode_dest(decode, dlocal, 0); \ +} while (0) + +#define Rndecode(decode, dlocal) \ +do \ +{ \ + check_delay_PC(); \ + (decode)->dst = DST_CODE; \ + decode_dest(decode, dlocal, 0); \ +} while (0) + +#define RimmdecodewithHflag(decode, dlocal, nbit) \ +do \ +{ \ + decode_immediate(decode, nbit); \ + check_delay_PC(); \ + (decode)->dst = DST_CODE; \ + decode_dest(decode, dlocal, GET_H); \ +} while (0) + +#define Lndecode(decode) \ +do \ +{ \ + check_delay_PC(); \ + (decode)->dst = DST_CODE; \ + decode_dest(decode, LOCAL, 0); \ +} while (0) + +#define LLdecode(decode) \ +do \ +{ \ + check_delay_PC(); \ + decode_LL(decode); \ +} while (0) + +#define LLextdecode(decode) \ +do \ +{ \ + m_instruction_length = 2; \ + EXTRA_U = READ_OP(PC); \ + PC += 2; \ + check_delay_PC(); \ + decode_LL(decode); \ +} while (0) + +#define LRdecode(decode, slocal) \ +do \ +{ \ + check_delay_PC(); \ + decode_LR(decode, slocal); \ +} while (0) + +#define LRconstdecode(decode, slocal) \ +do \ +{ \ + decode_const(decode); \ + check_delay_PC(); \ + decode_LR(decode, slocal); \ +} while (0) + +#define PCreldecode(decode) \ +do \ +{ \ + decode_pcrel(decode); \ + check_delay_PC(); \ +} while (0) + +#define PCadrdecode(decode) \ +do \ +{ \ + check_delay_PC(); \ +} while (0) + +#define no_decode(decode) \ +do \ +{ \ +} while (0) + + +void hyperstone_device::execute_br(struct hyperstone_device::regs_decode *decode) +{ + PPC = PC; + PC += EXTRA_S; + SET_M(0); + + m_icount -= m_clock_cycles_2; +} + +void hyperstone_device::execute_dbr(struct hyperstone_device::regs_decode *decode) +{ + m_delay.delay_cmd = DELAY_EXECUTE; + m_delay.delay_pc = PC + EXTRA_S; + + m_intblock = 3; +} + + +void hyperstone_device::execute_trap(UINT32 addr) +{ + UINT8 reg; + UINT32 oldSR; + reg = GET_FP + GET_FL; + + SET_ILC(m_instruction_length & 3); + + oldSR = SR; + + SET_FL(6); + SET_FP(reg); + + SET_L_REG(0, (PC & 0xfffffffe) | GET_S); + SET_L_REG(1, oldSR); + + SET_M(0); + SET_T(0); + SET_L(1); + SET_S(1); + + PPC = PC; + PC = addr; + + m_icount -= m_clock_cycles_2; +} + + +void hyperstone_device::execute_int(UINT32 addr) +{ + UINT8 reg; + UINT32 oldSR; + reg = GET_FP + GET_FL; + + SET_ILC(m_instruction_length & 3); + + oldSR = SR; + + SET_FL(2); + SET_FP(reg); + + SET_L_REG(0, (PC & 0xfffffffe) | GET_S); + SET_L_REG(1, oldSR); + + SET_M(0); + SET_T(0); + SET_L(1); + SET_S(1); + SET_I(1); + + PPC = PC; + PC = addr; + + m_icount -= m_clock_cycles_2; +} + +/* TODO: mask Parity Error and Extended Overflow exceptions */ +void hyperstone_device::execute_exception(UINT32 addr) +{ + UINT8 reg; + UINT32 oldSR; + reg = GET_FP + GET_FL; + + SET_ILC(m_instruction_length & 3); + + oldSR = SR; + + SET_FP(reg); + SET_FL(2); + + SET_L_REG(0, (PC & 0xfffffffe) | GET_S); + SET_L_REG(1, oldSR); + + SET_M(0); + SET_T(0); + SET_L(1); + SET_S(1); + + PPC = PC; + PC = addr; + + DEBUG_PRINTF(("EXCEPTION! PPC = %08X PC = %08X\n",PPC-2,PC-2)); + m_icount -= m_clock_cycles_2; +} + +void hyperstone_device::execute_software(struct hyperstone_device::regs_decode *decode) +{ + UINT8 reg; + UINT32 oldSR; + UINT32 addr; + UINT32 stack_of_dst; + + SET_ILC(1); + + addr = get_emu_code_addr((OP & 0xff00) >> 8); + reg = GET_FP + GET_FL; + + //since it's sure the register is in the register part of the stack, + //set the stack address to a value above the highest address + //that can be set by a following frame instruction + stack_of_dst = (SP & ~0xff) + 64*4 + (((GET_FP + decode->dst) % 64) * 4); //converted to 32bits offset + + oldSR = SR; + + SET_FL(6); + SET_FP(reg); + + SET_L_REG(0, stack_of_dst); + SET_L_REG(1, SREG); + SET_L_REG(2, SREGF); + SET_L_REG(3, (PC & 0xfffffffe) | GET_S); + SET_L_REG(4, oldSR); + + SET_M(0); + SET_T(0); + SET_L(1); + + PPC = PC; + PC = addr; +} + + +/* + IRQ lines : + 0 - IO2 (trap 48) + 1 - IO1 (trap 49) + 2 - INT4 (trap 50) + 3 - INT3 (trap 51) + 4 - INT2 (trap 52) + 5 - INT1 (trap 53) + 6 - IO3 (trap 54) + 7 - TIMER (trap 55) +*/ + +#define INT1_LINE_STATE ((ISR >> 0) & 1) +#define INT2_LINE_STATE ((ISR >> 1) & 1) +#define INT3_LINE_STATE ((ISR >> 2) & 1) +#define INT4_LINE_STATE ((ISR >> 3) & 1) +#define IO1_LINE_STATE ((ISR >> 4) & 1) +#define IO2_LINE_STATE ((ISR >> 5) & 1) +#define IO3_LINE_STATE ((ISR >> 6) & 1) + +void hyperstone_device::check_interrupts() +{ + /* Interrupt-Lock flag isn't set */ + if (GET_L || m_intblock > 0) + return; + + /* quick exit if nothing */ + if (!m_timer_int_pending && (ISR & 0x7f) == 0) + return; + + /* IO3 is priority 5; state is in bit 6 of ISR; FCR bit 10 enables input and FCR bit 8 inhibits interrupt */ + if (IO3_LINE_STATE && (FCR & 0x00000500) == 0x00000400) + { + execute_int(get_trap_addr(TRAPNO_IO3)); + standard_irq_callback(IRQ_IO3); + return; + } + + /* timer int might be priority 6 if FCR bits 20-21 == 3; FCR bit 23 inhibits interrupt */ + if (m_timer_int_pending && (FCR & 0x00b00000) == 0x00300000) + { + m_timer_int_pending = 0; + execute_int(get_trap_addr(TRAPNO_TIMER)); + return; + } + + /* INT1 is priority 7; state is in bit 0 of ISR; FCR bit 28 inhibits interrupt */ + if (INT1_LINE_STATE && (FCR & 0x10000000) == 0x00000000) + { + execute_int(get_trap_addr(TRAPNO_INT1)); + standard_irq_callback(IRQ_INT1); + return; + } + + /* timer int might be priority 8 if FCR bits 20-21 == 2; FCR bit 23 inhibits interrupt */ + if (m_timer_int_pending && (FCR & 0x00b00000) == 0x00200000) + { + m_timer_int_pending = 0; + execute_int(get_trap_addr(TRAPNO_TIMER)); + return; + } + + /* INT2 is priority 9; state is in bit 1 of ISR; FCR bit 29 inhibits interrupt */ + if (INT2_LINE_STATE && (FCR & 0x20000000) == 0x00000000) + { + execute_int(get_trap_addr(TRAPNO_INT2)); + standard_irq_callback(IRQ_INT2); + return; + } + + /* timer int might be priority 10 if FCR bits 20-21 == 1; FCR bit 23 inhibits interrupt */ + if (m_timer_int_pending && (FCR & 0x00b00000) == 0x00100000) + { + m_timer_int_pending = 0; + execute_int(get_trap_addr(TRAPNO_TIMER)); + return; + } + + /* INT3 is priority 11; state is in bit 2 of ISR; FCR bit 30 inhibits interrupt */ + if (INT3_LINE_STATE && (FCR & 0x40000000) == 0x00000000) + { + execute_int(get_trap_addr(TRAPNO_INT3)); + standard_irq_callback(IRQ_INT3); + return; + } + + /* timer int might be priority 12 if FCR bits 20-21 == 0; FCR bit 23 inhibits interrupt */ + if (m_timer_int_pending && (FCR & 0x00b00000) == 0x00000000) + { + m_timer_int_pending = 0; + execute_int(get_trap_addr(TRAPNO_TIMER)); + return; + } + + /* INT4 is priority 13; state is in bit 3 of ISR; FCR bit 31 inhibits interrupt */ + if (INT4_LINE_STATE && (FCR & 0x80000000) == 0x00000000) + { + execute_int(get_trap_addr(TRAPNO_INT4)); + standard_irq_callback(IRQ_INT4); + return; + } + + /* IO1 is priority 14; state is in bit 4 of ISR; FCR bit 2 enables input and FCR bit 0 inhibits interrupt */ + if (IO1_LINE_STATE && (FCR & 0x00000005) == 0x00000004) + { + execute_int(get_trap_addr(TRAPNO_IO1)); + standard_irq_callback(IRQ_IO1); + return; + } + + /* IO2 is priority 15; state is in bit 5 of ISR; FCR bit 6 enables input and FCR bit 4 inhibits interrupt */ + if (IO2_LINE_STATE && (FCR & 0x00000050) == 0x00000040) + { + execute_int(get_trap_addr(TRAPNO_IO2)); + standard_irq_callback(IRQ_IO2); + return; + } +} + +void hyperstone_device::device_start() +{ + // Handled entirely by init() and derived classes +} + +void hyperstone_device::init(int scale_mask) +{ + memset(m_global_regs, 0, sizeof(UINT32) * 32); + memset(m_local_regs, 0, sizeof(UINT32) * 64); + m_ppc = 0; + m_op = 0; + m_trap_entry = 0; + m_clock_scale_mask = 0; + m_clck_scale = 0; + m_clock_cycles_1 = 0; + m_clock_cycles_2 = 0; + m_clock_cycles_4 = 0; + m_clock_cycles_6 = 0; + + m_tr_base_cycles = 0; + m_tr_base_value = 0; + m_tr_clocks_per_tick = 0; + m_timer_int_pending = 0; + + m_instruction_length = 0; + m_intblock = 0; + + m_icount = 0; + + m_program = &space(AS_PROGRAM); + m_direct = &m_program->direct(); + m_io = &space(AS_IO); + + m_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(hyperstone_device::timer_callback), this)); + m_clock_scale_mask = scale_mask; + + // register our state for the debugger + std::string tempstr; + state_add(STATE_GENPC, "GENPC", m_global_regs[0]).noshow(); + state_add(STATE_GENFLAGS, "GENFLAGS", m_global_regs[1]).callimport().callexport().formatstr("%40s").noshow(); + state_add(E132XS_PC, "PC", m_global_regs[0]).mask(0xffffffff); + state_add(E132XS_SR, "SR", m_global_regs[1]).mask(0xffffffff); + state_add(E132XS_FER, "FER", m_global_regs[2]).mask(0xffffffff); + state_add(E132XS_G3, "G3", m_global_regs[3]).mask(0xffffffff); + state_add(E132XS_G4, "G4", m_global_regs[4]).mask(0xffffffff); + state_add(E132XS_G5, "G5", m_global_regs[5]).mask(0xffffffff); + state_add(E132XS_G6, "G6", m_global_regs[6]).mask(0xffffffff); + state_add(E132XS_G7, "G7", m_global_regs[7]).mask(0xffffffff); + state_add(E132XS_G8, "G8", m_global_regs[8]).mask(0xffffffff); + state_add(E132XS_G9, "G9", m_global_regs[9]).mask(0xffffffff); + state_add(E132XS_G10, "G10", m_global_regs[10]).mask(0xffffffff); + state_add(E132XS_G11, "G11", m_global_regs[11]).mask(0xffffffff); + state_add(E132XS_G12, "G12", m_global_regs[12]).mask(0xffffffff); + state_add(E132XS_G13, "G13", m_global_regs[13]).mask(0xffffffff); + state_add(E132XS_G14, "G14", m_global_regs[14]).mask(0xffffffff); + state_add(E132XS_G15, "G15", m_global_regs[15]).mask(0xffffffff); + state_add(E132XS_G16, "G16", m_global_regs[16]).mask(0xffffffff); + state_add(E132XS_G17, "G17", m_global_regs[17]).mask(0xffffffff); + state_add(E132XS_SP, "SP", m_global_regs[18]).mask(0xffffffff); + state_add(E132XS_UB, "UB", m_global_regs[19]).mask(0xffffffff); + state_add(E132XS_BCR, "BCR", m_global_regs[20]).mask(0xffffffff); + state_add(E132XS_TPR, "TPR", m_global_regs[21]).mask(0xffffffff); + state_add(E132XS_TCR, "TCR", m_global_regs[22]).mask(0xffffffff); + state_add(E132XS_TR, "TR", m_global_regs[23]).mask(0xffffffff); + state_add(E132XS_WCR, "WCR", m_global_regs[24]).mask(0xffffffff); + state_add(E132XS_ISR, "ISR", m_global_regs[25]).mask(0xffffffff); + state_add(E132XS_FCR, "FCR", m_global_regs[26]).mask(0xffffffff); + state_add(E132XS_MCR, "MCR", m_global_regs[27]).mask(0xffffffff); + state_add(E132XS_G28, "G28", m_global_regs[28]).mask(0xffffffff); + state_add(E132XS_G29, "G29", m_global_regs[29]).mask(0xffffffff); + state_add(E132XS_G30, "G30", m_global_regs[30]).mask(0xffffffff); + state_add(E132XS_G31, "G31", m_global_regs[31]).mask(0xffffffff); + state_add(E132XS_CL0, "CL0", m_local_regs[(0 + GET_FP) % 64]).mask(0xffffffff); + state_add(E132XS_CL1, "CL1", m_local_regs[(1 + GET_FP) % 64]).mask(0xffffffff); + state_add(E132XS_CL2, "CL2", m_local_regs[(2 + GET_FP) % 64]).mask(0xffffffff); + state_add(E132XS_CL3, "CL3", m_local_regs[(3 + GET_FP) % 64]).mask(0xffffffff); + state_add(E132XS_CL4, "CL4", m_local_regs[(4 + GET_FP) % 64]).mask(0xffffffff); + state_add(E132XS_CL5, "CL5", m_local_regs[(5 + GET_FP) % 64]).mask(0xffffffff); + state_add(E132XS_CL6, "CL6", m_local_regs[(6 + GET_FP) % 64]).mask(0xffffffff); + state_add(E132XS_CL7, "CL7", m_local_regs[(7 + GET_FP) % 64]).mask(0xffffffff); + state_add(E132XS_CL8, "CL8", m_local_regs[(8 + GET_FP) % 64]).mask(0xffffffff); + state_add(E132XS_CL9, "CL9", m_local_regs[(9 + GET_FP) % 64]).mask(0xffffffff); + state_add(E132XS_CL10, "CL10", m_local_regs[(10 + GET_FP) % 64]).mask(0xffffffff); + state_add(E132XS_CL11, "CL11", m_local_regs[(11 + GET_FP) % 64]).mask(0xffffffff); + state_add(E132XS_CL12, "CL12", m_local_regs[(12 + GET_FP) % 64]).mask(0xffffffff); + state_add(E132XS_CL13, "CL13", m_local_regs[(13 + GET_FP) % 64]).mask(0xffffffff); + state_add(E132XS_CL14, "CL14", m_local_regs[(14 + GET_FP) % 64]).mask(0xffffffff); + state_add(E132XS_CL15, "CL15", m_local_regs[(15 + GET_FP) % 64]).mask(0xffffffff); + state_add(E132XS_L0, "L0", m_local_regs[0]).mask(0xffffffff); + state_add(E132XS_L1, "L1", m_local_regs[1]).mask(0xffffffff); + state_add(E132XS_L2, "L2", m_local_regs[2]).mask(0xffffffff); + state_add(E132XS_L3, "L3", m_local_regs[3]).mask(0xffffffff); + state_add(E132XS_L4, "L4", m_local_regs[4]).mask(0xffffffff); + state_add(E132XS_L5, "L5", m_local_regs[5]).mask(0xffffffff); + state_add(E132XS_L6, "L6", m_local_regs[6]).mask(0xffffffff); + state_add(E132XS_L7, "L7", m_local_regs[7]).mask(0xffffffff); + state_add(E132XS_L8, "L8", m_local_regs[8]).mask(0xffffffff); + state_add(E132XS_L9, "L9", m_local_regs[9]).mask(0xffffffff); + state_add(E132XS_L10, "L10", m_local_regs[10]).mask(0xffffffff); + state_add(E132XS_L11, "L11", m_local_regs[11]).mask(0xffffffff); + state_add(E132XS_L12, "L12", m_local_regs[12]).mask(0xffffffff); + state_add(E132XS_L13, "L13", m_local_regs[13]).mask(0xffffffff); + state_add(E132XS_L14, "L14", m_local_regs[14]).mask(0xffffffff); + state_add(E132XS_L15, "L15", m_local_regs[15]).mask(0xffffffff); + state_add(E132XS_L16, "L16", m_local_regs[16]).mask(0xffffffff); + state_add(E132XS_L17, "L17", m_local_regs[17]).mask(0xffffffff); + state_add(E132XS_L18, "L18", m_local_regs[18]).mask(0xffffffff); + state_add(E132XS_L19, "L19", m_local_regs[19]).mask(0xffffffff); + state_add(E132XS_L20, "L20", m_local_regs[20]).mask(0xffffffff); + state_add(E132XS_L21, "L21", m_local_regs[21]).mask(0xffffffff); + state_add(E132XS_L22, "L22", m_local_regs[22]).mask(0xffffffff); + state_add(E132XS_L23, "L23", m_local_regs[23]).mask(0xffffffff); + state_add(E132XS_L24, "L24", m_local_regs[24]).mask(0xffffffff); + state_add(E132XS_L25, "L25", m_local_regs[25]).mask(0xffffffff); + state_add(E132XS_L26, "L26", m_local_regs[26]).mask(0xffffffff); + state_add(E132XS_L27, "L27", m_local_regs[27]).mask(0xffffffff); + state_add(E132XS_L28, "L28", m_local_regs[28]).mask(0xffffffff); + state_add(E132XS_L29, "L29", m_local_regs[29]).mask(0xffffffff); + state_add(E132XS_L30, "L30", m_local_regs[30]).mask(0xffffffff); + state_add(E132XS_L31, "L31", m_local_regs[31]).mask(0xffffffff); + state_add(E132XS_L32, "L32", m_local_regs[32]).mask(0xffffffff); + state_add(E132XS_L33, "L33", m_local_regs[33]).mask(0xffffffff); + state_add(E132XS_L34, "L34", m_local_regs[34]).mask(0xffffffff); + state_add(E132XS_L35, "L35", m_local_regs[35]).mask(0xffffffff); + state_add(E132XS_L36, "L36", m_local_regs[36]).mask(0xffffffff); + state_add(E132XS_L37, "L37", m_local_regs[37]).mask(0xffffffff); + state_add(E132XS_L38, "L38", m_local_regs[38]).mask(0xffffffff); + state_add(E132XS_L39, "L39", m_local_regs[39]).mask(0xffffffff); + state_add(E132XS_L40, "L40", m_local_regs[40]).mask(0xffffffff); + state_add(E132XS_L41, "L41", m_local_regs[41]).mask(0xffffffff); + state_add(E132XS_L42, "L42", m_local_regs[42]).mask(0xffffffff); + state_add(E132XS_L43, "L43", m_local_regs[43]).mask(0xffffffff); + state_add(E132XS_L44, "L44", m_local_regs[44]).mask(0xffffffff); + state_add(E132XS_L45, "L45", m_local_regs[45]).mask(0xffffffff); + state_add(E132XS_L46, "L46", m_local_regs[46]).mask(0xffffffff); + state_add(E132XS_L47, "L47", m_local_regs[47]).mask(0xffffffff); + state_add(E132XS_L48, "L48", m_local_regs[48]).mask(0xffffffff); + state_add(E132XS_L49, "L49", m_local_regs[49]).mask(0xffffffff); + state_add(E132XS_L50, "L50", m_local_regs[50]).mask(0xffffffff); + state_add(E132XS_L51, "L51", m_local_regs[51]).mask(0xffffffff); + state_add(E132XS_L52, "L52", m_local_regs[52]).mask(0xffffffff); + state_add(E132XS_L53, "L53", m_local_regs[53]).mask(0xffffffff); + state_add(E132XS_L54, "L54", m_local_regs[54]).mask(0xffffffff); + state_add(E132XS_L55, "L55", m_local_regs[55]).mask(0xffffffff); + state_add(E132XS_L56, "L56", m_local_regs[56]).mask(0xffffffff); + state_add(E132XS_L57, "L57", m_local_regs[57]).mask(0xffffffff); + state_add(E132XS_L58, "L58", m_local_regs[58]).mask(0xffffffff); + state_add(E132XS_L59, "L59", m_local_regs[59]).mask(0xffffffff); + state_add(E132XS_L60, "L60", m_local_regs[60]).mask(0xffffffff); + state_add(E132XS_L61, "L61", m_local_regs[61]).mask(0xffffffff); + state_add(E132XS_L62, "L62", m_local_regs[62]).mask(0xffffffff); + state_add(E132XS_L63, "L63", m_local_regs[63]).mask(0xffffffff); + + save_item(NAME(m_global_regs)); + save_item(NAME(m_local_regs)); + save_item(NAME(m_ppc)); + save_item(NAME(m_trap_entry)); + save_item(NAME(m_delay.delay_pc)); + save_item(NAME(m_instruction_length)); + save_item(NAME(m_intblock)); + save_item(NAME(m_delay.delay_cmd)); + save_item(NAME(m_tr_clocks_per_tick)); + save_item(NAME(m_tr_base_value)); + save_item(NAME(m_tr_base_cycles)); + save_item(NAME(m_timer_int_pending)); + save_item(NAME(m_clck_scale)); + save_item(NAME(m_clock_scale_mask)); + save_item(NAME(m_clock_cycles_1)); + save_item(NAME(m_clock_cycles_2)); + save_item(NAME(m_clock_cycles_4)); + save_item(NAME(m_clock_cycles_6)); + + // set our instruction counter + m_icountptr = &m_icount; +} + +void e116t_device::device_start() +{ + init(0); + m_opcodexor = 0; +} + +void e116xt_device::device_start() +{ + init(3); + m_opcodexor = 0; +} + +void e116xs_device::device_start() +{ + init(7); + m_opcodexor = 0; +} + +void e116xsr_device::device_start() +{ + init(7); + m_opcodexor = 0; +} + +void gms30c2116_device::device_start() +{ + init(0); + m_opcodexor = 0; +} + +void gms30c2216_device::device_start() +{ + init(0); + m_opcodexor = 0; +} + +void e132n_device::device_start() +{ + init(0); + m_opcodexor = WORD_XOR_BE(0); +} + +void e132t_device::device_start() +{ + init(0); + m_opcodexor = WORD_XOR_BE(0); +} + +void e132xn_device::device_start() +{ + init(3); + m_opcodexor = WORD_XOR_BE(0); +} + +void e132xt_device::device_start() +{ + init(3); + m_opcodexor = WORD_XOR_BE(0); +} + +void e132xs_device::device_start() +{ + init(7); + m_opcodexor = WORD_XOR_BE(0); +} + +void e132xsr_device::device_start() +{ + init(7); + m_opcodexor = WORD_XOR_BE(0); +} + +void gms30c2132_device::device_start() +{ + init(0); + m_opcodexor = WORD_XOR_BE(0); +} + +void gms30c2232_device::device_start() +{ + init(0); + m_opcodexor = WORD_XOR_BE(0); +} + +void hyperstone_device::device_reset() +{ + //TODO: Add different reset initializations for BCR, MCR, FCR, TPR + + m_program = &space(AS_PROGRAM); + m_direct = &m_program->direct(); + m_io = &space(AS_IO); + + m_tr_clocks_per_tick = 2; + + hyperstone_set_trap_entry(E132XS_ENTRY_MEM3); /* default entry point @ MEM3 */ + + set_global_register(BCR_REGISTER, ~0); + set_global_register(MCR_REGISTER, ~0); + set_global_register(FCR_REGISTER, ~0); + set_global_register(TPR_REGISTER, 0xc000000); + + PC = get_trap_addr(TRAPNO_RESET); + + SET_FP(0); + SET_FL(2); + + SET_M(0); + SET_T(0); + SET_L(1); + SET_S(1); + + SET_L_REG(0, (PC & 0xfffffffe) | GET_S); + SET_L_REG(1, SR); + + m_icount -= m_clock_cycles_2; +} + +void hyperstone_device::device_stop() +{ + // nothing to do +} + + +//------------------------------------------------- +// memory_space_config - return the configuration +// of the specified address space, or NULL if +// the space doesn't exist +//------------------------------------------------- + +const address_space_config *hyperstone_device::memory_space_config(address_spacenum spacenum) const +{ + if (spacenum == AS_PROGRAM) + { + return &m_program_config; + } + else if (spacenum == AS_IO) + { + return &m_io_config; + } + return NULL; +} + + +//------------------------------------------------- +// state_string_export - export state as a string +// for the debugger +//------------------------------------------------- + +void hyperstone_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + switch (entry.index()) + { + case STATE_GENFLAGS: + strprintf(str, "%c%c%c%c%c%c%c%c%c%c%c%c FTE:%X FRM:%X ILC:%d FL:%d FP:%d", + GET_S ? 'S':'.', + GET_P ? 'P':'.', + GET_T ? 'T':'.', + GET_L ? 'L':'.', + GET_I ? 'I':'.', + m_global_regs[1] & 0x00040 ? '?':'.', + GET_H ? 'H':'.', + GET_M ? 'M':'.', + GET_V ? 'V':'.', + GET_N ? 'N':'.', + GET_Z ? 'Z':'.', + GET_C ? 'C':'.', + GET_FTE, + GET_FRM, + GET_ILC, + GET_FL, + GET_FP); + break; + } +} + + +//------------------------------------------------- +// disasm_min_opcode_bytes - return the length +// of the shortest instruction, in bytes +//------------------------------------------------- + +UINT32 hyperstone_device::disasm_min_opcode_bytes() const +{ + return 2; +} + + +//------------------------------------------------- +// disasm_max_opcode_bytes - return the length +// of the longest instruction, in bytes +//------------------------------------------------- + +UINT32 hyperstone_device::disasm_max_opcode_bytes() const +{ + return 6; +} + + +//------------------------------------------------- +// disasm_disassemble - call the disassembly +// helper function +//------------------------------------------------- + +offs_t hyperstone_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( hyperstone ); + return dasm_hyperstone( buffer, pc, oprom, GET_H, GET_FP ); +} + +/* Opcodes */ + +void hyperstone_device::hyperstone_chk(struct hyperstone_device::regs_decode *decode) +{ + UINT32 addr = get_trap_addr(TRAPNO_RANGE_ERROR); + + if( SRC_IS_SR ) + { + if( DREG == 0 ) + execute_exception(addr); + } + else + { + if( SRC_IS_PC ) + { + if( DREG >= SREG ) + execute_exception(addr); + } + else + { + if( DREG > SREG ) + execute_exception(addr); + } + } + + m_icount -= m_clock_cycles_1; +} + +void hyperstone_device::hyperstone_movd(struct hyperstone_device::regs_decode *decode) +{ + if( DST_IS_PC ) // Rd denotes PC + { + // RET instruction + + UINT8 old_s, old_l; + INT8 difference; // really it's 7 bits + + if( SRC_IS_PC || SRC_IS_SR ) + { + DEBUG_PRINTF(("Denoted PC or SR in RET instruction. PC = %08X\n", PC)); + } + else + { + old_s = GET_S; + old_l = GET_L; + PPC = PC; + + SET_PC(SREG); + SR = (SREGF & 0xffe00000) | ((SREG & 0x01) << 18 ) | (SREGF & 0x3ffff); + if (m_intblock < 1) + m_intblock = 1; + + m_instruction_length = 0; // undefined + + if( (!old_s && GET_S) || (!GET_S && !old_l && GET_L)) + { + UINT32 addr = get_trap_addr(TRAPNO_PRIVILEGE_ERROR); + execute_exception(addr); + } + + difference = GET_FP - ((SP & 0x1fc) >> 2); + + /* convert to 8 bits */ + if(difference > 63) + difference = (INT8)(difference|0x80); + else if( difference < -64 ) + difference = difference & 0x7f; + + if( difference < 0 ) //else it's finished + { + do + { + SP -= 4; + SET_ABS_L_REG(((SP & 0xfc) >> 2), READ_W(SP)); + difference++; + + } while(difference != 0); + } + } + + //TODO: no 1! + m_icount -= m_clock_cycles_1; + } + else if( SRC_IS_SR ) // Rd doesn't denote PC and Rs denotes SR + { + SET_DREG(0); + SET_DREGF(0); + SET_Z(1); + SET_N(0); + + m_icount -= m_clock_cycles_2; + } + else // Rd doesn't denote PC and Rs doesn't denote SR + { + UINT64 tmp; + + SET_DREG(SREG); + SET_DREGF(SREGF); + + tmp = CONCAT_64(SREG, SREGF); + SET_Z( tmp == 0 ? 1 : 0 ); + SET_N( SIGN_BIT(SREG) ); + + m_icount -= m_clock_cycles_2; + } +} + +void hyperstone_device::hyperstone_divu(struct hyperstone_device::regs_decode *decode) +{ + if( SAME_SRC_DST || SAME_SRC_DSTF ) + { + DEBUG_PRINTF(("Denoted the same register code in hyperstone_divu instruction. PC = %08X\n", PC)); + } + else + { + if( SRC_IS_PC || SRC_IS_SR ) + { + DEBUG_PRINTF(("Denoted PC or SR as source register in hyperstone_divu instruction. PC = %08X\n", PC)); + } + else + { + UINT64 dividend; + + dividend = CONCAT_64(DREG, DREGF); + + if( SREG == 0 ) + { + //Rd//Rdf -> undefined + //Z -> undefined + //N -> undefined + UINT32 addr; + SET_V(1); + addr = get_trap_addr(TRAPNO_RANGE_ERROR); + execute_exception(addr); + } + else + { + UINT32 quotient, remainder; + + /* TODO: add quotient overflow */ + quotient = dividend / SREG; + remainder = dividend % SREG; + + SET_DREG(remainder); + SET_DREGF(quotient); + + SET_Z( quotient == 0 ? 1 : 0 ); + SET_N( SIGN_BIT(quotient) ); + SET_V(0); + } + } + } + + m_icount -= 36 << m_clck_scale; +} + +void hyperstone_device::hyperstone_divs(struct hyperstone_device::regs_decode *decode) +{ + if( SAME_SRC_DST || SAME_SRC_DSTF ) + { + DEBUG_PRINTF(("Denoted the same register code in hyperstone_divs instruction. PC = %08X\n", PC)); + } + else + { + if( SRC_IS_PC || SRC_IS_SR ) + { + DEBUG_PRINTF(("Denoted PC or SR as source register in hyperstone_divs instruction. PC = %08X\n", PC)); + } + else + { + INT64 dividend; + + dividend = (INT64) CONCAT_64(DREG, DREGF); + + if( SREG == 0 || (DREG & 0x80000000) ) + { + //Rd//Rdf -> undefined + //Z -> undefined + //N -> undefined + UINT32 addr; + SET_V(1); + addr = get_trap_addr(TRAPNO_RANGE_ERROR); + execute_exception(addr); + } + else + { + INT32 quotient, remainder; + + /* TODO: add quotient overflow */ + quotient = dividend / ((INT32)(SREG)); + remainder = dividend % ((INT32)(SREG)); + + SET_DREG(remainder); + SET_DREGF(quotient); + + SET_Z( quotient == 0 ? 1 : 0 ); + SET_N( SIGN_BIT(quotient) ); + SET_V(0); + } + } + } + + m_icount -= 36 << m_clck_scale; +} + +void hyperstone_device::hyperstone_xm(struct hyperstone_device::regs_decode *decode) +{ + if( SRC_IS_SR || DST_IS_SR || DST_IS_PC ) + { + DEBUG_PRINTF(("Denoted PC or SR in hyperstone_xm. PC = %08X\n", PC)); + } + else + { + switch( decode->sub_type ) // x_code + { + case 0: + case 1: + case 2: + case 3: + if( !SRC_IS_PC && (SREG > EXTRA_U) ) + { + UINT32 addr = get_trap_addr(TRAPNO_RANGE_ERROR); + execute_exception(addr); + } + else if( SRC_IS_PC && (SREG >= EXTRA_U) ) + { + UINT32 addr = get_trap_addr(TRAPNO_RANGE_ERROR); + execute_exception(addr); + } + else + { + SREG <<= decode->sub_type; + } + + break; + + case 4: + case 5: + case 6: + case 7: + decode->sub_type -= 4; + SREG <<= decode->sub_type; + + break; + } + + SET_DREG(SREG); + } + + m_icount -= m_clock_cycles_1; +} + +void hyperstone_device::hyperstone_mask(struct hyperstone_device::regs_decode *decode) +{ + DREG = SREG & EXTRA_U; + + SET_DREG(DREG); + SET_Z( DREG == 0 ? 1 : 0 ); + + m_icount -= m_clock_cycles_1; +} + +void hyperstone_device::hyperstone_sum(struct hyperstone_device::regs_decode *decode) +{ + UINT64 tmp; + + if( SRC_IS_SR ) + SREG = GET_C; + + tmp = (UINT64)(SREG) + (UINT64)(EXTRA_U); + CHECK_C(tmp); + CHECK_VADD(SREG,EXTRA_U,tmp); + + DREG = SREG + EXTRA_U; + + SET_DREG(DREG); + + if( DST_IS_PC ) + SET_M(0); + + SET_Z( DREG == 0 ? 1 : 0 ); + SET_N( SIGN_BIT(DREG) ); + + m_icount -= m_clock_cycles_1; +} + +void hyperstone_device::hyperstone_sums(struct hyperstone_device::regs_decode *decode) +{ + INT32 res; + INT64 tmp; + + if( SRC_IS_SR ) + SREG = GET_C; + + tmp = (INT64)((INT32)(SREG)) + (INT64)(EXTRA_S); + CHECK_VADD(SREG,EXTRA_S,tmp); + +//#if SETCARRYS +// CHECK_C(tmp); +//#endif + + res = (INT32)(SREG) + EXTRA_S; + + SET_DREG(res); + + SET_Z( res == 0 ? 1 : 0 ); + SET_N( SIGN_BIT(res) ); + + m_icount -= m_clock_cycles_1; + + if( GET_V && !SRC_IS_SR ) + { + UINT32 addr = get_trap_addr(TRAPNO_RANGE_ERROR); + execute_exception(addr); + } +} + +void hyperstone_device::hyperstone_cmp(struct hyperstone_device::regs_decode *decode) +{ + UINT64 tmp; + + if( SRC_IS_SR ) + SREG = GET_C; + + if( DREG == SREG ) + SET_Z(1); + else + SET_Z(0); + + if( (INT32) DREG < (INT32) SREG ) + SET_N(1); + else + SET_N(0); + + tmp = (UINT64)(DREG) - (UINT64)(SREG); + CHECK_VSUB(SREG,DREG,tmp); + + if( DREG < SREG ) + SET_C(1); + else + SET_C(0); + + m_icount -= m_clock_cycles_1; +} + +void hyperstone_device::hyperstone_mov(struct hyperstone_device::regs_decode *decode) +{ + if( !GET_S && decode->dst >= 16 ) + { + UINT32 addr = get_trap_addr(TRAPNO_PRIVILEGE_ERROR); + execute_exception(addr); + } + + SET_DREG(SREG); + + if( DST_IS_PC ) + SET_M(0); + + SET_Z( SREG == 0 ? 1 : 0 ); + SET_N( SIGN_BIT(SREG) ); + + m_icount -= m_clock_cycles_1; +} + + +void hyperstone_device::hyperstone_add(struct hyperstone_device::regs_decode *decode) +{ + UINT64 tmp; + + if( SRC_IS_SR ) + SREG = GET_C; + + tmp = (UINT64)(SREG) + (UINT64)(DREG); + CHECK_C(tmp); + CHECK_VADD(SREG,DREG,tmp); + + DREG = SREG + DREG; + SET_DREG(DREG); + + if( DST_IS_PC ) + SET_M(0); + + SET_Z( DREG == 0 ? 1 : 0 ); + SET_N( SIGN_BIT(DREG) ); + + m_icount -= m_clock_cycles_1; +} + +void hyperstone_device::hyperstone_adds(struct hyperstone_device::regs_decode *decode) +{ + INT32 res; + INT64 tmp; + + if( SRC_IS_SR ) + SREG = GET_C; + + tmp = (INT64)((INT32)(SREG)) + (INT64)((INT32)(DREG)); + + CHECK_VADD(SREG,DREG,tmp); + +//#if SETCARRYS +// CHECK_C(tmp); +//#endif + + res = (INT32)(SREG) + (INT32)(DREG); + + SET_DREG(res); + SET_Z( res == 0 ? 1 : 0 ); + SET_N( SIGN_BIT(res) ); + + m_icount -= m_clock_cycles_1; + + if( GET_V ) + { + UINT32 addr = get_trap_addr(TRAPNO_RANGE_ERROR); + execute_exception(addr); + } +} + +void hyperstone_device::hyperstone_cmpb(struct hyperstone_device::regs_decode *decode) +{ + SET_Z( (DREG & SREG) == 0 ? 1 : 0 ); + + m_icount -= m_clock_cycles_1; +} + +void hyperstone_device::hyperstone_andn(struct hyperstone_device::regs_decode *decode) +{ + DREG = DREG & ~SREG; + + SET_DREG(DREG); + SET_Z( DREG == 0 ? 1 : 0 ); + + m_icount -= m_clock_cycles_1; +} + +void hyperstone_device::hyperstone_or(struct hyperstone_device::regs_decode *decode) +{ + DREG = DREG | SREG; + + SET_DREG(DREG); + SET_Z( DREG == 0 ? 1 : 0 ); + + m_icount -= m_clock_cycles_1; +} + +void hyperstone_device::hyperstone_xor(struct hyperstone_device::regs_decode *decode) +{ + DREG = DREG ^ SREG; + + SET_DREG(DREG); + SET_Z( DREG == 0 ? 1 : 0 ); + + m_icount -= m_clock_cycles_1; +} + +void hyperstone_device::hyperstone_subc(struct hyperstone_device::regs_decode *decode) +{ + UINT64 tmp; + + if( SRC_IS_SR ) + { + tmp = (UINT64)(DREG) - (UINT64)(GET_C); + CHECK_VSUB(GET_C,DREG,tmp); + } + else + { + tmp = (UINT64)(DREG) - ((UINT64)(SREG) + (UINT64)(GET_C)); + //CHECK! + CHECK_VSUB(SREG + GET_C,DREG,tmp); + } + + + if( SRC_IS_SR ) + { + DREG = DREG - GET_C; + } + else + { + DREG = DREG - (SREG + GET_C); + } + + CHECK_C(tmp); + + SET_DREG(DREG); + + SET_Z( GET_Z & (DREG == 0 ? 1 : 0) ); + SET_N( SIGN_BIT(DREG) ); + + m_icount -= m_clock_cycles_1; +} + +void hyperstone_device::hyperstone_not(struct hyperstone_device::regs_decode *decode) +{ + SET_DREG(~SREG); + SET_Z( ~SREG == 0 ? 1 : 0 ); + + m_icount -= m_clock_cycles_1; +} + +void hyperstone_device::hyperstone_sub(struct hyperstone_device::regs_decode *decode) +{ + UINT64 tmp; + + if( SRC_IS_SR ) + SREG = GET_C; + + tmp = (UINT64)(DREG) - (UINT64)(SREG); + CHECK_C(tmp); + CHECK_VSUB(SREG,DREG,tmp); + + DREG = DREG - SREG; + SET_DREG(DREG); + + if( DST_IS_PC ) + SET_M(0); + + SET_Z( DREG == 0 ? 1 : 0 ); + SET_N( SIGN_BIT(DREG) ); + + m_icount -= m_clock_cycles_1; +} + +void hyperstone_device::hyperstone_subs(struct hyperstone_device::regs_decode *decode) +{ + INT32 res; + INT64 tmp; + + if( SRC_IS_SR ) + SREG = GET_C; + + tmp = (INT64)((INT32)(DREG)) - (INT64)((INT32)(SREG)); + +//#ifdef SETCARRYS +// CHECK_C(tmp); +//#endif + + CHECK_VSUB(SREG,DREG,tmp); + + res = (INT32)(DREG) - (INT32)(SREG); + + SET_DREG(res); + + SET_Z( res == 0 ? 1 : 0 ); + SET_N( SIGN_BIT(res) ); + + m_icount -= m_clock_cycles_1; + + if( GET_V ) + { + UINT32 addr = get_trap_addr(TRAPNO_RANGE_ERROR); + execute_exception(addr); + } +} + +void hyperstone_device::hyperstone_addc(struct hyperstone_device::regs_decode *decode) +{ + UINT64 tmp; + + if( SRC_IS_SR ) + { + tmp = (UINT64)(DREG) + (UINT64)(GET_C); + CHECK_VADD(DREG,GET_C,tmp); + } + else + { + tmp = (UINT64)(SREG) + (UINT64)(DREG) + (UINT64)(GET_C); + + //CHECK! + //CHECK_VADD1: V = (DREG == 0x7FFF) && (C == 1); + //OVERFLOW = CHECK_VADD1(DREG, C, DREG+C) | CHECK_VADD(SREG, DREG+C, SREG+DREG+C) + /* check if DREG + GET_C overflows */ +// if( (DREG == 0x7FFFFFFF) && (GET_C == 1) ) +// SET_V(1); +// else +// CHECK_VADD(SREG,DREG + GET_C,tmp); + + CHECK_VADD3(SREG,DREG,GET_C,tmp); + } + + + + if( SRC_IS_SR ) + DREG = DREG + GET_C; + else + DREG = SREG + DREG + GET_C; + + CHECK_C(tmp); + + SET_DREG(DREG); + SET_Z( GET_Z & (DREG == 0 ? 1 : 0) ); + SET_N( SIGN_BIT(DREG) ); + + m_icount -= m_clock_cycles_1; +} + +void hyperstone_device::hyperstone_and(struct hyperstone_device::regs_decode *decode) +{ + DREG = DREG & SREG; + + SET_DREG(DREG); + SET_Z( DREG == 0 ? 1 : 0 ); + + m_icount -= m_clock_cycles_1; +} + +void hyperstone_device::hyperstone_neg(struct hyperstone_device::regs_decode *decode) +{ + UINT64 tmp; + + if( SRC_IS_SR ) + SREG = GET_C; + + tmp = -(UINT64)(SREG); + CHECK_C(tmp); + CHECK_VSUB(SREG,0,tmp); + + DREG = -SREG; + + SET_DREG(DREG); + + SET_Z( DREG == 0 ? 1 : 0 ); + SET_N( SIGN_BIT(DREG) ); + + m_icount -= m_clock_cycles_1; +} + +void hyperstone_device::hyperstone_negs(struct hyperstone_device::regs_decode *decode) +{ + INT32 res; + INT64 tmp; + + if( SRC_IS_SR ) + SREG = GET_C; + + tmp = -(INT64)((INT32)(SREG)); + CHECK_VSUB(SREG,0,tmp); + +//#if SETCARRYS +// CHECK_C(tmp); +//#endif + + res = -(INT32)(SREG); + + SET_DREG(res); + + SET_Z( res == 0 ? 1 : 0 ); + SET_N( SIGN_BIT(res) ); + + + m_icount -= m_clock_cycles_1; + + if( GET_V && !SRC_IS_SR ) //trap doesn't occur when source is SR + { + UINT32 addr = get_trap_addr(TRAPNO_RANGE_ERROR); + execute_exception(addr); + } +} + +void hyperstone_device::hyperstone_cmpi(struct hyperstone_device::regs_decode *decode) +{ + UINT64 tmp; + + tmp = (UINT64)(DREG) - (UINT64)(EXTRA_U); + CHECK_VSUB(EXTRA_U,DREG,tmp); + + if( DREG == EXTRA_U ) + SET_Z(1); + else + SET_Z(0); + + if( (INT32) DREG < (INT32) EXTRA_U ) + SET_N(1); + else + SET_N(0); + + if( DREG < EXTRA_U ) + SET_C(1); + else + SET_C(0); + + m_icount -= m_clock_cycles_1; +} + +void hyperstone_device::hyperstone_movi(struct hyperstone_device::regs_decode *decode) +{ + if( !GET_S && decode->dst >= 16 ) + { + UINT32 addr = get_trap_addr(TRAPNO_PRIVILEGE_ERROR); + execute_exception(addr); + } + + SET_DREG(EXTRA_U); + + if( DST_IS_PC ) + SET_M(0); + + SET_Z( EXTRA_U == 0 ? 1 : 0 ); + SET_N( SIGN_BIT(EXTRA_U) ); + +#if MISSIONCRAFT_FLAGS + SET_V(0); // or V undefined ? +#endif + + m_icount -= m_clock_cycles_1; +} + +void hyperstone_device::hyperstone_addi(struct hyperstone_device::regs_decode *decode) +{ + UINT32 imm; + UINT64 tmp; + + if( N_VALUE ) + imm = EXTRA_U; + else + imm = GET_C & ((GET_Z == 0 ? 1 : 0) | (DREG & 0x01)); + + + tmp = (UINT64)(imm) + (UINT64)(DREG); + CHECK_C(tmp); + CHECK_VADD(imm,DREG,tmp); + + DREG = imm + DREG; + SET_DREG(DREG); + + if( DST_IS_PC ) + SET_M(0); + + SET_Z( DREG == 0 ? 1 : 0 ); + SET_N( SIGN_BIT(DREG) ); + + m_icount -= m_clock_cycles_1; +} + +void hyperstone_device::hyperstone_addsi(struct hyperstone_device::regs_decode *decode) +{ + INT32 imm, res; + INT64 tmp; + + if( N_VALUE ) + imm = EXTRA_S; + else + imm = GET_C & ((GET_Z == 0 ? 1 : 0) | (DREG & 0x01)); + + tmp = (INT64)(imm) + (INT64)((INT32)(DREG)); + CHECK_VADD(imm,DREG,tmp); + +//#if SETCARRYS +// CHECK_C(tmp); +//#endif + + res = imm + (INT32)(DREG); + + SET_DREG(res); + + SET_Z( res == 0 ? 1 : 0 ); + SET_N( SIGN_BIT(res) ); + + m_icount -= m_clock_cycles_1; + + if( GET_V ) + { + UINT32 addr = get_trap_addr(TRAPNO_RANGE_ERROR); + execute_exception(addr); + } +} + +void hyperstone_device::hyperstone_cmpbi(struct hyperstone_device::regs_decode *decode) +{ + UINT32 imm; + + if( N_VALUE ) + { + if( N_VALUE == 31 ) + { + imm = 0x7fffffff; // bit 31 = 0, others = 1 + } + else + { + imm = EXTRA_U; + } + + SET_Z( (DREG & imm) == 0 ? 1 : 0 ); + } + else + { + if( (DREG & 0xff000000) == 0 || (DREG & 0x00ff0000) == 0 || + (DREG & 0x0000ff00) == 0 || (DREG & 0x000000ff) == 0 ) + SET_Z(1); + else + SET_Z(0); + } + + m_icount -= m_clock_cycles_1; +} + +void hyperstone_device::hyperstone_andni(struct hyperstone_device::regs_decode *decode) +{ + UINT32 imm; + + if( N_VALUE == 31 ) + imm = 0x7fffffff; // bit 31 = 0, others = 1 + else + imm = EXTRA_U; + + DREG = DREG & ~imm; + + SET_DREG(DREG); + SET_Z( DREG == 0 ? 1 : 0 ); + + m_icount -= m_clock_cycles_1; +} + +void hyperstone_device::hyperstone_ori(struct hyperstone_device::regs_decode *decode) +{ + DREG = DREG | EXTRA_U; + + SET_DREG(DREG); + SET_Z( DREG == 0 ? 1 : 0 ); + + m_icount -= m_clock_cycles_1; +} + +void hyperstone_device::hyperstone_xori(struct hyperstone_device::regs_decode *decode) +{ + DREG = DREG ^ EXTRA_U; + + SET_DREG(DREG); + SET_Z( DREG == 0 ? 1 : 0 ); + + m_icount -= m_clock_cycles_1; +} + +void hyperstone_device::hyperstone_shrdi(struct hyperstone_device::regs_decode *decode) +{ + UINT32 low_order, high_order; + UINT64 val; + + high_order = DREG; + low_order = DREGF; + + val = CONCAT_64(high_order, low_order); + + if( N_VALUE ) + SET_C((val >> (N_VALUE - 1)) & 1); + else + SET_C(0); + + val >>= N_VALUE; + + high_order = EXTRACT_64HI(val); + low_order = EXTRACT_64LO(val); + + SET_DREG(high_order); + SET_DREGF(low_order); + SET_Z( val == 0 ? 1 : 0 ); + SET_N( SIGN_BIT(high_order) ); + + m_icount -= m_clock_cycles_2; +} + +void hyperstone_device::hyperstone_shrd(struct hyperstone_device::regs_decode *decode) +{ + UINT32 low_order, high_order; + UINT64 val; + UINT8 n = SREG & 0x1f; + + // result undefined if Ls denotes the same register as Ld or Ldf + if( SAME_SRC_DST || SAME_SRC_DSTF ) + { + DEBUG_PRINTF(("Denoted same registers in hyperstone_shrd. PC = %08X\n", PC)); + } + else + { + high_order = DREG; + low_order = DREGF; + + val = CONCAT_64(high_order, low_order); + + if( n ) + SET_C((val >> (n - 1)) & 1); + else + SET_C(0); + + val >>= n; + + high_order = EXTRACT_64HI(val); + low_order = EXTRACT_64LO(val); + + SET_DREG(high_order); + SET_DREGF(low_order); + + SET_Z( val == 0 ? 1 : 0 ); + SET_N( SIGN_BIT(high_order) ); + } + + m_icount -= m_clock_cycles_2; +} + +void hyperstone_device::hyperstone_shr(struct hyperstone_device::regs_decode *decode) +{ + UINT32 ret; + UINT8 n; + + n = SREG & 0x1f; + ret = DREG; + + if( n ) + SET_C((ret >> (n - 1)) & 1); + else + SET_C(0); + + ret >>= n; + + SET_DREG(ret); + SET_Z( ret == 0 ? 1 : 0 ); + SET_N( SIGN_BIT(ret) ); + + m_icount -= m_clock_cycles_1; +} + +void hyperstone_device::hyperstone_sardi(struct hyperstone_device::regs_decode *decode) +{ + UINT32 low_order, high_order; + UINT64 val; + UINT8 sign_bit; + + high_order = DREG; + low_order = DREGF; + + val = CONCAT_64(high_order, low_order); + + if( N_VALUE ) + SET_C((val >> (N_VALUE - 1)) & 1); + else + SET_C(0); + + sign_bit = val >> 63; + val >>= N_VALUE; + + if( sign_bit ) + { + int i; + for( i = 0; i < N_VALUE; i++ ) + { + val |= (U64(0x8000000000000000) >> i); + } + } + + high_order = val >> 32; + low_order = val & 0xffffffff; + + SET_DREG(high_order); + SET_DREGF(low_order); + + SET_Z( val == 0 ? 1 : 0 ); + SET_N( SIGN_BIT(high_order) ); + + m_icount -= m_clock_cycles_2; +} + +void hyperstone_device::hyperstone_sard(struct hyperstone_device::regs_decode *decode) +{ + UINT32 low_order, high_order; + UINT64 val; + UINT8 n, sign_bit; + + n = SREG & 0x1f; + + // result undefined if Ls denotes the same register as Ld or Ldf + if( SAME_SRC_DST || SAME_SRC_DSTF ) + { + DEBUG_PRINTF(("Denoted same registers in hyperstone_sard. PC = %08X\n", PC)); + } + else + { + high_order = DREG; + low_order = DREGF; + + val = CONCAT_64(high_order, low_order); + + if( n ) + SET_C((val >> (n - 1)) & 1); + else + SET_C(0); + + sign_bit = val >> 63; + + val >>= n; + + if( sign_bit ) + { + int i; + for( i = 0; i < n; i++ ) + { + val |= (U64(0x8000000000000000) >> i); + } + } + + high_order = val >> 32; + low_order = val & 0xffffffff; + + SET_DREG(high_order); + SET_DREGF(low_order); + SET_Z( val == 0 ? 1 : 0 ); + SET_N( SIGN_BIT(high_order) ); + } + + m_icount -= m_clock_cycles_2; +} + +void hyperstone_device::hyperstone_sar(struct hyperstone_device::regs_decode *decode) +{ + UINT32 ret; + UINT8 n, sign_bit; + + n = SREG & 0x1f; + ret = DREG; + sign_bit = (ret & 0x80000000) >> 31; + + if( n ) + SET_C((ret >> (n - 1)) & 1); + else + SET_C(0); + + ret >>= n; + + if( sign_bit ) + { + int i; + for( i = 0; i < n; i++ ) + { + ret |= (0x80000000 >> i); + } + } + + SET_DREG(ret); + SET_Z( ret == 0 ? 1 : 0 ); + SET_N( SIGN_BIT(ret) ); + + m_icount -= m_clock_cycles_1; +} + +void hyperstone_device::hyperstone_shldi(struct hyperstone_device::regs_decode *decode) +{ + UINT32 low_order, high_order, tmp; + UINT64 val, mask; + + high_order = DREG; + low_order = DREGF; + + val = CONCAT_64(high_order, low_order); + SET_C( (N_VALUE)?(((val<<(N_VALUE-1))&U64(0x8000000000000000))?1:0):0); + mask = ((((UINT64)1) << (32 - N_VALUE)) - 1) ^ 0xffffffff; + tmp = high_order << N_VALUE; + + if( ((high_order & mask) && (!(tmp & 0x80000000))) || + (((high_order & mask) ^ mask) && (tmp & 0x80000000)) ) + SET_V(1); + else + SET_V(0); + + val <<= N_VALUE; + + high_order = EXTRACT_64HI(val); + low_order = EXTRACT_64LO(val); + + SET_DREG(high_order); + SET_DREGF(low_order); + + SET_Z( val == 0 ? 1 : 0 ); + SET_N( SIGN_BIT(high_order) ); + + m_icount -= m_clock_cycles_2; +} + +void hyperstone_device::hyperstone_shld(struct hyperstone_device::regs_decode *decode) +{ + UINT32 low_order, high_order, tmp, n; + UINT64 val, mask; + + n = SREG & 0x1f; + + // result undefined if Ls denotes the same register as Ld or Ldf + if( SAME_SRC_DST || SAME_SRC_DSTF ) + { + DEBUG_PRINTF(("Denoted same registers in hyperstone_shld. PC = %08X\n", PC)); + } + else + { + high_order = DREG; + low_order = DREGF; + + mask = ((((UINT64)1) << (32 - n)) - 1) ^ 0xffffffff; + + val = CONCAT_64(high_order, low_order); + SET_C( (n)?(((val<<(n-1))&U64(0x8000000000000000))?1:0):0); + tmp = high_order << n; + + if( ((high_order & mask) && (!(tmp & 0x80000000))) || + (((high_order & mask) ^ mask) && (tmp & 0x80000000)) ) + SET_V(1); + else + SET_V(0); + + val <<= n; + + high_order = EXTRACT_64HI(val); + low_order = EXTRACT_64LO(val); + + SET_DREG(high_order); + SET_DREGF(low_order); + + SET_Z( val == 0 ? 1 : 0 ); + SET_N( SIGN_BIT(high_order) ); + } + + m_icount -= m_clock_cycles_2; +} + +void hyperstone_device::hyperstone_shl(struct hyperstone_device::regs_decode *decode) +{ + UINT32 base, ret, n; + UINT64 mask; + + n = SREG & 0x1f; + base = DREG; + mask = ((((UINT64)1) << (32 - n)) - 1) ^ 0xffffffff; + SET_C( (n)?(((base<<(n-1))&0x80000000)?1:0):0); + ret = base << n; + + if( ((base & mask) && (!(ret & 0x80000000))) || + (((base & mask) ^ mask) && (ret & 0x80000000)) ) + SET_V(1); + else + SET_V(0); + + SET_DREG(ret); + SET_Z( ret == 0 ? 1 : 0 ); + SET_N( SIGN_BIT(ret) ); + + m_icount -= m_clock_cycles_1; +} + +void hyperstone_device::reserved(struct hyperstone_device::regs_decode *decode) +{ + DEBUG_PRINTF(("Executed Reserved opcode. PC = %08X OP = %04X\n", PC, OP)); +} + +void hyperstone_device::hyperstone_testlz(struct hyperstone_device::regs_decode *decode) +{ + UINT8 zeros = 0; + UINT32 mask; + + for( mask = 0x80000000; ; mask >>= 1 ) + { + if( SREG & mask ) + break; + else + zeros++; + + if( zeros == 32 ) + break; + } + + SET_DREG(zeros); + + m_icount -= m_clock_cycles_2; +} + +void hyperstone_device::hyperstone_rol(struct hyperstone_device::regs_decode *decode) +{ + UINT32 val, base; + UINT8 n; + UINT64 mask; + + n = SREG & 0x1f; + + val = base = DREG; + + mask = ((((UINT64)1) << (32 - n)) - 1) ^ 0xffffffff; + + while( n > 0 ) + { + val = (val << 1) | ((val & 0x80000000) >> 31); + n--; + } + +#ifdef MISSIONCRAFT_FLAGS + + if( ((base & mask) && (!(val & 0x80000000))) || + (((base & mask) ^ mask) && (val & 0x80000000)) ) + SET_V(1); + else + SET_V(0); + +#endif + + SET_DREG(val); + + SET_Z( val == 0 ? 1 : 0 ); + SET_N( SIGN_BIT(val) ); + + m_icount -= m_clock_cycles_1; +} + +//TODO: add trap error +void hyperstone_device::hyperstone_ldxx1(struct hyperstone_device::regs_decode *decode) +{ + UINT32 load; + + if( DST_IS_SR ) + { + switch( decode->sub_type ) + { + case 0: // LDBS.A + + load = READ_B(EXTRA_S); + load |= (load & 0x80) ? 0xffffff00 : 0; + SET_SREG(load); + + break; + + case 1: // LDBU.A + + load = READ_B(EXTRA_S); + SET_SREG(load); + + break; + + case 2: + + load = READ_HW(EXTRA_S & ~1); + + if( EXTRA_S & 1 ) // LDHS.A + { + load |= (load & 0x8000) ? 0xffff0000 : 0; + } + /* + else // LDHU.A + { + // nothing more + } + */ + + SET_SREG(load); + + break; + + case 3: + + if( (EXTRA_S & 3) == 3 ) // LDD.IOA + { + load = IO_READ_W(EXTRA_S & ~3); + SET_SREG(load); + + load = IO_READ_W((EXTRA_S & ~3) + 4); + SET_SREGF(load); + + m_icount -= m_clock_cycles_1; // extra cycle + } + else if( (EXTRA_S & 3) == 2 ) // LDW.IOA + { + load = IO_READ_W(EXTRA_S & ~3); + SET_SREG(load); + } + else if( (EXTRA_S & 3) == 1 ) // LDD.A + { + load = READ_W(EXTRA_S & ~1); + SET_SREG(load); + + load = READ_W((EXTRA_S & ~1) + 4); + SET_SREGF(load); + + m_icount -= m_clock_cycles_1; // extra cycle + } + else // LDW.A + { + load = READ_W(EXTRA_S & ~1); + SET_SREG(load); + } + + break; + } + } + else + { + switch( decode->sub_type ) + { + case 0: // LDBS.D + + load = READ_B(DREG + EXTRA_S); + load |= (load & 0x80) ? 0xffffff00 : 0; + SET_SREG(load); + + break; + + case 1: // LDBU.D + + load = READ_B(DREG + EXTRA_S); + SET_SREG(load); + + break; + + case 2: + + load = READ_HW(DREG + (EXTRA_S & ~1)); + + if( EXTRA_S & 1 ) // LDHS.D + { + load |= (load & 0x8000) ? 0xffff0000 : 0; + } + /* + else // LDHU.D + { + // nothing more + } + */ + + SET_SREG(load); + + break; + + case 3: + + if( (EXTRA_S & 3) == 3 ) // LDD.IOD + { + load = IO_READ_W(DREG + (EXTRA_S & ~3)); + SET_SREG(load); + + load = IO_READ_W(DREG + (EXTRA_S & ~3) + 4); + SET_SREGF(load); + + m_icount -= m_clock_cycles_1; // extra cycle + } + else if( (EXTRA_S & 3) == 2 ) // LDW.IOD + { + load = IO_READ_W(DREG + (EXTRA_S & ~3)); + SET_SREG(load); + } + else if( (EXTRA_S & 3) == 1 ) // LDD.D + { + load = READ_W(DREG + (EXTRA_S & ~1)); + SET_SREG(load); + + load = READ_W(DREG + (EXTRA_S & ~1) + 4); + SET_SREGF(load); + + m_icount -= m_clock_cycles_1; // extra cycle + } + else // LDW.D + { + load = READ_W(DREG + (EXTRA_S & ~1)); + SET_SREG(load); + } + + break; + } + } + + m_icount -= m_clock_cycles_1; +} + +void hyperstone_device::hyperstone_ldxx2(struct hyperstone_device::regs_decode *decode) +{ + UINT32 load; + + if( DST_IS_PC || DST_IS_SR ) + { + DEBUG_PRINTF(("Denoted PC or SR in hyperstone_ldxx2. PC = %08X\n", PC)); + } + else + { + switch( decode->sub_type ) + { + case 0: // LDBS.N + + if(SAME_SRC_DST) + DEBUG_PRINTF(("LDBS.N denoted same regs @ %08X",PPC)); + + load = READ_B(DREG); + load |= (load & 0x80) ? 0xffffff00 : 0; + SET_SREG(load); + + if(!SAME_SRC_DST) + SET_DREG(DREG + EXTRA_S); + + break; + + case 1: // LDBU.N + + if(SAME_SRC_DST) + DEBUG_PRINTF(("LDBU.N denoted same regs @ %08X",PPC)); + + load = READ_B(DREG); + SET_SREG(load); + + if(!SAME_SRC_DST) + SET_DREG(DREG + EXTRA_S); + + break; + + case 2: + + load = READ_HW(DREG); + + if( EXTRA_S & 1 ) // LDHS.N + { + load |= (load & 0x8000) ? 0xffff0000 : 0; + + if(SAME_SRC_DST) + DEBUG_PRINTF(("LDHS.N denoted same regs @ %08X",PPC)); + } + /* + else // LDHU.N + { + // nothing more + } + */ + + SET_SREG(load); + + if(!SAME_SRC_DST) + SET_DREG(DREG + (EXTRA_S & ~1)); + + break; + + case 3: + + if( (EXTRA_S & 3) == 3 ) // LDW.S + { + if(SAME_SRC_DST) + DEBUG_PRINTF(("LDW.S denoted same regs @ %08X",PPC)); + + if(DREG < SP) + SET_SREG(READ_W(DREG)); + else + SET_SREG(GET_ABS_L_REG((DREG & 0xfc) >> 2)); + + if(!SAME_SRC_DST) + SET_DREG(DREG + (EXTRA_S & ~3)); + + m_icount -= m_clock_cycles_2; // extra cycles + } + else if( (EXTRA_S & 3) == 2 ) // Reserved + { + DEBUG_PRINTF(("Executed Reserved instruction in hyperstone_ldxx2. PC = %08X\n", PC)); + } + else if( (EXTRA_S & 3) == 1 ) // LDD.N + { + if(SAME_SRC_DST || SAME_SRCF_DST) + DEBUG_PRINTF(("LDD.N denoted same regs @ %08X",PPC)); + + load = READ_W(DREG); + SET_SREG(load); + + load = READ_W(DREG + 4); + SET_SREGF(load); + + if(!SAME_SRC_DST && !SAME_SRCF_DST) + SET_DREG(DREG + (EXTRA_S & ~1)); + + m_icount -= m_clock_cycles_1; // extra cycle + } + else // LDW.N + { + if(SAME_SRC_DST) + DEBUG_PRINTF(("LDW.N denoted same regs @ %08X",PPC)); + + load = READ_W(DREG); + SET_SREG(load); + + if(!SAME_SRC_DST) + SET_DREG(DREG + (EXTRA_S & ~1)); + } + + break; + } + } + + m_icount -= m_clock_cycles_1; +} + +//TODO: add trap error +void hyperstone_device::hyperstone_stxx1(struct hyperstone_device::regs_decode *decode) +{ + if( SRC_IS_SR ) + SREG = SREGF = 0; + + if( DST_IS_SR ) + { + switch( decode->sub_type ) + { + case 0: // STBS.A + + /* TODO: missing trap on range error */ + WRITE_B(EXTRA_S, SREG & 0xff); + + break; + + case 1: // STBU.A + + WRITE_B(EXTRA_S, SREG & 0xff); + + break; + + case 2: + + WRITE_HW(EXTRA_S & ~1, SREG & 0xffff); + + /* + if( EXTRA_S & 1 ) // STHS.A + { + // TODO: missing trap on range error + } + else // STHU.A + { + // nothing more + } + */ + + break; + + case 3: + + if( (EXTRA_S & 3) == 3 ) // STD.IOA + { + IO_WRITE_W(EXTRA_S & ~3, SREG); + IO_WRITE_W((EXTRA_S & ~3) + 4, SREGF); + + m_icount -= m_clock_cycles_1; // extra cycle + } + else if( (EXTRA_S & 3) == 2 ) // STW.IOA + { + IO_WRITE_W(EXTRA_S & ~3, SREG); + } + else if( (EXTRA_S & 3) == 1 ) // STD.A + { + WRITE_W(EXTRA_S & ~1, SREG); + WRITE_W((EXTRA_S & ~1) + 4, SREGF); + + m_icount -= m_clock_cycles_1; // extra cycle + } + else // STW.A + { + WRITE_W(EXTRA_S & ~1, SREG); + } + + break; + } + } + else + { + switch( decode->sub_type ) + { + case 0: // STBS.D + + /* TODO: missing trap on range error */ + WRITE_B(DREG + EXTRA_S, SREG & 0xff); + + break; + + case 1: // STBU.D + + WRITE_B(DREG + EXTRA_S, SREG & 0xff); + + break; + + case 2: + + WRITE_HW(DREG + (EXTRA_S & ~1), SREG & 0xffff); + + /* + if( EXTRA_S & 1 ) // STHS.D + { + // TODO: missing trap on range error + } + else // STHU.D + { + // nothing more + } + */ + + break; + + case 3: + + if( (EXTRA_S & 3) == 3 ) // STD.IOD + { + IO_WRITE_W(DREG + (EXTRA_S & ~3), SREG); + IO_WRITE_W(DREG + (EXTRA_S & ~3) + 4, SREGF); + + m_icount -= m_clock_cycles_1; // extra cycle + } + else if( (EXTRA_S & 3) == 2 ) // STW.IOD + { + IO_WRITE_W(DREG + (EXTRA_S & ~3), SREG); + } + else if( (EXTRA_S & 3) == 1 ) // STD.D + { + WRITE_W(DREG + (EXTRA_S & ~1), SREG); + WRITE_W(DREG + (EXTRA_S & ~1) + 4, SREGF); + + m_icount -= m_clock_cycles_1; // extra cycle + } + else // STW.D + { + WRITE_W(DREG + (EXTRA_S & ~1), SREG); + } + + break; + } + } + + m_icount -= m_clock_cycles_1; +} + +void hyperstone_device::hyperstone_stxx2(struct hyperstone_device::regs_decode *decode) +{ + if( SRC_IS_SR ) + SREG = SREGF = 0; + + if( DST_IS_PC || DST_IS_SR ) + { + DEBUG_PRINTF(("Denoted PC or SR in hyperstone_stxx2. PC = %08X\n", PC)); + } + else + { + switch( decode->sub_type ) + { + case 0: // STBS.N + + /* TODO: missing trap on range error */ + WRITE_B(DREG, SREG & 0xff); + SET_DREG(DREG + EXTRA_S); + + break; + + case 1: // STBU.N + + WRITE_B(DREG, SREG & 0xff); + SET_DREG(DREG + EXTRA_S); + + break; + + case 2: + + WRITE_HW(DREG, SREG & 0xffff); + SET_DREG(DREG + (EXTRA_S & ~1)); + + /* + if( EXTRA_S & 1 ) // STHS.N + { + // TODO: missing trap on range error + } + else // STHU.N + { + // nothing more + } + */ + + break; + + case 3: + + if( (EXTRA_S & 3) == 3 ) // STW.S + { + if(DREG < SP) + WRITE_W(DREG, SREG); + else + { + if(((DREG & 0xfc) >> 2) == ((decode->src + GET_FP) % 64) && S_BIT == LOCAL) + DEBUG_PRINTF(("STW.S denoted the same local register @ %08X\n",PPC)); + + SET_ABS_L_REG((DREG & 0xfc) >> 2,SREG); + } + + SET_DREG(DREG + (EXTRA_S & ~3)); + + m_icount -= m_clock_cycles_2; // extra cycles + + } + else if( (EXTRA_S & 3) == 2 ) // Reserved + { + DEBUG_PRINTF(("Executed Reserved instruction in hyperstone_stxx2. PC = %08X\n", PC)); + } + else if( (EXTRA_S & 3) == 1 ) // STD.N + { + WRITE_W(DREG, SREG); + SET_DREG(DREG + (EXTRA_S & ~1)); + + if( SAME_SRCF_DST ) + WRITE_W(DREG + 4, SREGF + (EXTRA_S & ~1)); // because DREG == SREGF and DREG has been incremented + else + WRITE_W(DREG + 4, SREGF); + + m_icount -= m_clock_cycles_1; // extra cycle + } + else // STW.N + { + WRITE_W(DREG, SREG); + SET_DREG(DREG + (EXTRA_S & ~1)); + } + + break; + } + } + + m_icount -= m_clock_cycles_1; +} + +void hyperstone_device::hyperstone_shri(struct hyperstone_device::regs_decode *decode) +{ + UINT32 val; + + val = DREG; + + if( N_VALUE ) + SET_C((val >> (N_VALUE - 1)) & 1); + else + SET_C(0); + + val >>= N_VALUE; + + SET_DREG(val); + SET_Z( val == 0 ? 1 : 0 ); + SET_N( SIGN_BIT(val) ); + + m_icount -= m_clock_cycles_1; +} + +void hyperstone_device::hyperstone_sari(struct hyperstone_device::regs_decode *decode) +{ + UINT32 val; + UINT8 sign_bit; + + val = DREG; + sign_bit = (val & 0x80000000) >> 31; + + if( N_VALUE ) + SET_C((val >> (N_VALUE - 1)) & 1); + else + SET_C(0); + + val >>= N_VALUE; + + if( sign_bit ) + { + int i; + for( i = 0; i < N_VALUE; i++ ) + { + val |= (0x80000000 >> i); + } + } + + SET_DREG(val); + SET_Z( val == 0 ? 1 : 0 ); + SET_N( SIGN_BIT(val) ); + + m_icount -= m_clock_cycles_1; +} + +void hyperstone_device::hyperstone_shli(struct hyperstone_device::regs_decode *decode) +{ + UINT32 val, val2; + UINT64 mask; + + val = DREG; + SET_C( (N_VALUE)?(((val<<(N_VALUE-1))&0x80000000)?1:0):0); + mask = ((((UINT64)1) << (32 - N_VALUE)) - 1) ^ 0xffffffff; + val2 = val << N_VALUE; + + if( ((val & mask) && (!(val2 & 0x80000000))) || + (((val & mask) ^ mask) && (val2 & 0x80000000)) ) + SET_V(1); + else + SET_V(0); + + SET_DREG(val2); + SET_Z( val2 == 0 ? 1 : 0 ); + SET_N( SIGN_BIT(val2) ); + + m_icount -= m_clock_cycles_1; +} + +void hyperstone_device::hyperstone_mulu(struct hyperstone_device::regs_decode *decode) +{ + UINT32 low_order, high_order; + UINT64 double_word; + + // PC or SR aren't denoted, else result is undefined + if( SRC_IS_PC || SRC_IS_SR || DST_IS_PC || DST_IS_SR ) + { + DEBUG_PRINTF(("Denoted PC or SR in hyperstone_mulu instruction. PC = %08X\n", PC)); + } + else + { + double_word = (UINT64)SREG *(UINT64)DREG; + + low_order = double_word & 0xffffffff; + high_order = double_word >> 32; + + SET_DREG(high_order); + SET_DREGF(low_order); + + SET_Z( double_word == 0 ? 1 : 0 ); + SET_N( SIGN_BIT(high_order) ); + } + + if(SREG <= 0xffff && DREG <= 0xffff) + m_icount -= m_clock_cycles_4; + else + m_icount -= m_clock_cycles_6; +} + +void hyperstone_device::hyperstone_muls(struct hyperstone_device::regs_decode *decode) +{ + UINT32 low_order, high_order; + INT64 double_word; + + // PC or SR aren't denoted, else result is undefined + if( SRC_IS_PC || SRC_IS_SR || DST_IS_PC || DST_IS_SR ) + { + DEBUG_PRINTF(("Denoted PC or SR in hyperstone_muls instruction. PC = %08X\n", PC)); + } + else + { + double_word = (INT64)(INT32)(SREG) * (INT64)(INT32)(DREG); + low_order = double_word & 0xffffffff; + high_order = double_word >> 32; + + SET_DREG(high_order); + SET_DREGF(low_order); + + SET_Z( double_word == 0 ? 1 : 0 ); + SET_N( SIGN_BIT(high_order) ); + } + + if((SREG >= 0xffff8000 && SREG <= 0x7fff) && (DREG >= 0xffff8000 && DREG <= 0x7fff)) + m_icount -= m_clock_cycles_4; + else + m_icount -= m_clock_cycles_6; +} + +void hyperstone_device::hyperstone_set(struct hyperstone_device::regs_decode *decode) +{ + int n = N_VALUE; + + if( DST_IS_PC ) + { + DEBUG_PRINTF(("Denoted PC in hyperstone_set. PC = %08X\n", PC)); + } + else if( DST_IS_SR ) + { + //TODO: add fetch opcode when there's the pipeline + + //TODO: no 1! + m_icount -= m_clock_cycles_1; + } + else + { + switch( n ) + { + // SETADR + case 0: + { + UINT32 val; + val = (SP & 0xfffffe00) | (GET_FP << 2); + + //plus carry into bit 9 + val += (( (SP & 0x100) && (SIGN_BIT(SR) == 0) ) ? 1 : 0); + + SET_DREG(val); + + break; + } + // Reserved + case 1: + case 16: + case 17: + case 19: + DEBUG_PRINTF(("Used reserved N value (%d) in hyperstone_set. PC = %08X\n", n, PC)); + break; + + // SETxx + case 2: + SET_DREG(1); + break; + + case 3: + SET_DREG(0); + break; + + case 4: + if( GET_N || GET_Z ) + { + SET_DREG(1); + } + else + { + SET_DREG(0); + } + + break; + + case 5: + if( !GET_N && !GET_Z ) + { + SET_DREG(1); + } + else + { + SET_DREG(0); + } + + break; + + case 6: + if( GET_N ) + { + SET_DREG(1); + } + else + { + SET_DREG(0); + } + + break; + + case 7: + if( !GET_N ) + { + SET_DREG(1); + } + else + { + SET_DREG(0); + } + + break; + + case 8: + if( GET_C || GET_Z ) + { + SET_DREG(1); + } + else + { + SET_DREG(0); + } + + break; + + case 9: + if( !GET_C && !GET_Z ) + { + SET_DREG(1); + } + else + { + SET_DREG(0); + } + + break; + + case 10: + if( GET_C ) + { + SET_DREG(1); + } + else + { + SET_DREG(0); + } + + break; + + case 11: + if( !GET_C ) + { + SET_DREG(1); + } + else + { + SET_DREG(0); + } + + break; + + case 12: + if( GET_Z ) + { + SET_DREG(1); + } + else + { + SET_DREG(0); + } + + break; + + case 13: + if( !GET_Z ) + { + SET_DREG(1); + } + else + { + SET_DREG(0); + } + + break; + + case 14: + if( GET_V ) + { + SET_DREG(1); + } + else + { + SET_DREG(0); + } + + break; + + case 15: + if( !GET_V ) + { + SET_DREG(1); + } + else + { + SET_DREG(0); + } + + break; + + case 18: + SET_DREG(-1); + break; + + case 20: + if( GET_N || GET_Z ) + { + SET_DREG(-1); + } + else + { + SET_DREG(0); + } + + break; + + case 21: + if( !GET_N && !GET_Z ) + { + SET_DREG(-1); + } + else + { + SET_DREG(0); + } + + break; + + case 22: + if( GET_N ) + { + SET_DREG(-1); + } + else + { + SET_DREG(0); + } + + break; + + case 23: + if( !GET_N ) + { + SET_DREG(-1); + } + else + { + SET_DREG(0); + } + + break; + + case 24: + if( GET_C || GET_Z ) + { + SET_DREG(-1); + } + else + { + SET_DREG(0); + } + + break; + + case 25: + if( !GET_C && !GET_Z ) + { + SET_DREG(-1); + } + else + { + SET_DREG(0); + } + + break; + + case 26: + if( GET_C ) + { + SET_DREG(-1); + } + else + { + SET_DREG(0); + } + + break; + + case 27: + if( !GET_C ) + { + SET_DREG(-1); + } + else + { + SET_DREG(0); + } + + break; + + case 28: + if( GET_Z ) + { + SET_DREG(-1); + } + else + { + SET_DREG(0); + } + + break; + + case 29: + if( !GET_Z ) + { + SET_DREG(-1); + } + else + { + SET_DREG(0); + } + + break; + + case 30: + if( GET_V ) + { + SET_DREG(-1); + } + else + { + SET_DREG(0); + } + + break; + + case 31: + if( !GET_V ) + { + SET_DREG(-1); + } + else + { + SET_DREG(0); + } + + break; + } + + m_icount -= m_clock_cycles_1; + } +} + +void hyperstone_device::hyperstone_mul(struct hyperstone_device::regs_decode *decode) +{ + UINT32 single_word; + + // PC or SR aren't denoted, else result is undefined + if( SRC_IS_PC || SRC_IS_SR || DST_IS_PC || DST_IS_SR ) + { + DEBUG_PRINTF(("Denoted PC or SR in hyperstone_mul instruction. PC = %08X\n", PC)); + } + else + { + single_word = (SREG * DREG);// & 0xffffffff; // only the low-order word is taken + + SET_DREG(single_word); + + SET_Z( single_word == 0 ? 1 : 0 ); + SET_N( SIGN_BIT(single_word) ); + } + + if((SREG >= 0xffff8000 && SREG <= 0x7fff) && (DREG >= 0xffff8000 && DREG <= 0x7fff)) + m_icount -= 3 << m_clck_scale; + else + m_icount -= 5 << m_clck_scale; +} + +void hyperstone_device::hyperstone_fadd(struct hyperstone_device::regs_decode *decode) +{ + execute_software(decode); + m_icount -= m_clock_cycles_6; +} + +void hyperstone_device::hyperstone_faddd(struct hyperstone_device::regs_decode *decode) +{ + execute_software(decode); + m_icount -= m_clock_cycles_6; +} + +void hyperstone_device::hyperstone_fsub(struct hyperstone_device::regs_decode *decode) +{ + execute_software(decode); + m_icount -= m_clock_cycles_6; +} + +void hyperstone_device::hyperstone_fsubd(struct hyperstone_device::regs_decode *decode) +{ + execute_software(decode); + m_icount -= m_clock_cycles_6; +} + +void hyperstone_device::hyperstone_fmul(struct hyperstone_device::regs_decode *decode) +{ + execute_software(decode); + m_icount -= m_clock_cycles_6; +} + +void hyperstone_device::hyperstone_fmuld(struct hyperstone_device::regs_decode *decode) +{ + execute_software(decode); + m_icount -= m_clock_cycles_6; +} + +void hyperstone_device::hyperstone_fdiv(struct hyperstone_device::regs_decode *decode) +{ + execute_software(decode); + m_icount -= m_clock_cycles_6; +} + +void hyperstone_device::hyperstone_fdivd(struct hyperstone_device::regs_decode *decode) +{ + execute_software(decode); + m_icount -= m_clock_cycles_6; +} + +void hyperstone_device::hyperstone_fcmp(struct hyperstone_device::regs_decode *decode) +{ + execute_software(decode); + m_icount -= m_clock_cycles_6; +} + +void hyperstone_device::hyperstone_fcmpd(struct hyperstone_device::regs_decode *decode) +{ + execute_software(decode); + m_icount -= m_clock_cycles_6; +} + +void hyperstone_device::hyperstone_fcmpu(struct hyperstone_device::regs_decode *decode) +{ + execute_software(decode); + m_icount -= m_clock_cycles_6; +} + +void hyperstone_device::hyperstone_fcmpud(struct hyperstone_device::regs_decode *decode) +{ + execute_software(decode); + m_icount -= m_clock_cycles_6; +} + +void hyperstone_device::hyperstone_fcvt(struct hyperstone_device::regs_decode *decode) +{ + execute_software(decode); + m_icount -= m_clock_cycles_6; +} + +void hyperstone_device::hyperstone_fcvtd(struct hyperstone_device::regs_decode *decode) +{ + execute_software(decode); + m_icount -= m_clock_cycles_6; +} + +void hyperstone_device::hyperstone_extend(struct hyperstone_device::regs_decode *decode) +{ + //TODO: add locks, overflow error and other things + UINT32 vals, vald; + + vals = SREG; + vald = DREG; + + switch( EXTRA_U ) // extended opcode + { + // signed or unsigned multiplication, single word product + case EMUL: + case 0x100: // used in "N" type cpu + { + UINT32 result; + + result = vals * vald; + SET_G_REG(15, result); + + break; + } + // unsigned multiplication, double word product + case EMULU: + { + UINT64 result; + + result = (UINT64)vals * (UINT64)vald; + vals = result >> 32; + vald = result & 0xffffffff; + SET_G_REG(14, vals); + SET_G_REG(15, vald); + + break; + } + // signed multiplication, double word product + case EMULS: + { + INT64 result; + + result = (INT64)(INT32)(vals) * (INT64)(INT32)(vald); + vals = result >> 32; + vald = result & 0xffffffff; + SET_G_REG(14, vals); + SET_G_REG(15, vald); + + break; + } + // signed multiply/add, single word product sum + case EMAC: + { + INT32 result; + + result = (INT32)GET_G_REG(15) + ((INT32)(vals) * (INT32)(vald)); + SET_G_REG(15, result); + + break; + } + // signed multiply/add, double word product sum + case EMACD: + { + INT64 result; + + result = (INT64)CONCAT_64(GET_G_REG(14), GET_G_REG(15)) + (INT64)((INT64)(INT32)(vals) * (INT64)(INT32)(vald)); + + vals = result >> 32; + vald = result & 0xffffffff; + SET_G_REG(14, vals); + SET_G_REG(15, vald); + + break; + } + // signed multiply/substract, single word product difference + case EMSUB: + { + INT32 result; + + result = (INT32)GET_G_REG(15) - ((INT32)(vals) * (INT32)(vald)); + SET_G_REG(15, result); + + break; + } + // signed multiply/substract, double word product difference + case EMSUBD: + { + INT64 result; + + result = (INT64)CONCAT_64(GET_G_REG(14), GET_G_REG(15)) - (INT64)((INT64)(INT32)(vals) * (INT64)(INT32)(vald)); + + vals = result >> 32; + vald = result & 0xffffffff; + SET_G_REG(14, vals); + SET_G_REG(15, vald); + + break; + } + // signed half-word multiply/add, single word product sum + case EHMAC: + { + INT32 result; + + result = (INT32)GET_G_REG(15) + ((INT32)((vald & 0xffff0000) >> 16) * (INT32)((vals & 0xffff0000) >> 16)) + ((INT32)(vald & 0xffff) * (INT32)(vals & 0xffff)); + SET_G_REG(15, result); + + break; + } + // signed half-word multiply/add, double word product sum + case EHMACD: + { + INT64 result; + + result = (INT64)CONCAT_64(GET_G_REG(14), GET_G_REG(15)) + (INT64)((INT64)(INT32)((vald & 0xffff0000) >> 16) * (INT64)(INT32)((vals & 0xffff0000) >> 16)) + ((INT64)(INT32)(vald & 0xffff) * (INT64)(INT32)(vals & 0xffff)); + + vals = result >> 32; + vald = result & 0xffffffff; + SET_G_REG(14, vals); + SET_G_REG(15, vald); + + break; + } + // half-word complex multiply + case EHCMULD: + { + UINT32 result; + + result = (((vald & 0xffff0000) >> 16) * ((vals & 0xffff0000) >> 16)) - ((vald & 0xffff) * (vals & 0xffff)); + SET_G_REG(14, result); + + result = (((vald & 0xffff0000) >> 16) * (vals & 0xffff)) + ((vald & 0xffff) * ((vals & 0xffff0000) >> 16)); + SET_G_REG(15, result); + + break; + } + // half-word complex multiply/add + case EHCMACD: + { + UINT32 result; + + result = GET_G_REG(14) + (((vald & 0xffff0000) >> 16) * ((vals & 0xffff0000) >> 16)) - ((vald & 0xffff) * (vals & 0xffff)); + SET_G_REG(14, result); + + result = GET_G_REG(15) + (((vald & 0xffff0000) >> 16) * (vals & 0xffff)) + ((vald & 0xffff) * ((vals & 0xffff0000) >> 16)); + SET_G_REG(15, result); + + break; + } + // half-word (complex) add/substract + // Ls is not used and should denote the same register as Ld + case EHCSUMD: + { + UINT32 result; + + result = ((((vals & 0xffff0000) >> 16) + GET_G_REG(14)) << 16) & 0xffff0000; + result |= ((vals & 0xffff) + GET_G_REG(15)) & 0xffff; + SET_G_REG(14, result); + + result = ((((vals & 0xffff0000) >> 16) - GET_G_REG(14)) << 16) & 0xffff0000; + result |= ((vals & 0xffff) - GET_G_REG(15)) & 0xffff; + SET_G_REG(15, result); + + break; + } + // half-word (complex) add/substract with fixed point adjustment + // Ls is not used and should denote the same register as Ld + case EHCFFTD: + { + UINT32 result; + + result = ((((vals & 0xffff0000) >> 16) + (GET_G_REG(14) >> 15)) << 16) & 0xffff0000; + result |= ((vals & 0xffff) + (GET_G_REG(15) >> 15)) & 0xffff; + SET_G_REG(14, result); + + result = ((((vals & 0xffff0000) >> 16) - (GET_G_REG(14) >> 15)) << 16) & 0xffff0000; + result |= ((vals & 0xffff) - (GET_G_REG(15) >> 15)) & 0xffff; + SET_G_REG(15, result); + + break; + } + // half-word (complex) add/substract with fixed point adjustment and shift + // Ls is not used and should denote the same register as Ld + case EHCFFTSD: + { + UINT32 result; + + result = (((((vals & 0xffff0000) >> 16) + (GET_G_REG(14) >> 15)) >> 1) << 16) & 0xffff0000; + result |= ((((vals & 0xffff) + (GET_G_REG(15) >> 15)) >> 1) & 0xffff); + SET_G_REG(14, result); + + result = (((((vals & 0xffff0000) >> 16) - (GET_G_REG(14) >> 15)) >> 1) << 16) & 0xffff0000; + result |= ((((vals & 0xffff) - (GET_G_REG(15) >> 15)) >> 1) & 0xffff); + SET_G_REG(15, result); + + break; + } + default: + DEBUG_PRINTF(("Executed Illegal extended opcode (%X). PC = %08X\n", EXTRA_U, PC)); + break; + } + + m_icount -= m_clock_cycles_1; //TODO: with the latency it can change +} + +void hyperstone_device::hyperstone_do(struct hyperstone_device::regs_decode *decode) +{ + fatalerror("Executed hyperstone_do instruction. PC = %08X\n", PPC); +} + +void hyperstone_device::hyperstone_ldwr(struct hyperstone_device::regs_decode *decode) +{ + SET_SREG(READ_W(DREG)); + + m_icount -= m_clock_cycles_1; +} + +void hyperstone_device::hyperstone_lddr(struct hyperstone_device::regs_decode *decode) +{ + SET_SREG(READ_W(DREG)); + SET_SREGF(READ_W(DREG + 4)); + + m_icount -= m_clock_cycles_2; +} + +void hyperstone_device::hyperstone_ldwp(struct hyperstone_device::regs_decode *decode) +{ + SET_SREG(READ_W(DREG)); + + // post increment the destination register if it's different from the source one + // (needed by Hidden Catch) + if(!(decode->src == decode->dst && S_BIT == LOCAL)) + SET_DREG(DREG + 4); + + m_icount -= m_clock_cycles_1; +} + +void hyperstone_device::hyperstone_lddp(struct hyperstone_device::regs_decode *decode) +{ + SET_SREG(READ_W(DREG)); + SET_SREGF(READ_W(DREG + 4)); + + // post increment the destination register if it's different from the source one + // and from the "next source" one + if(!(decode->src == decode->dst && S_BIT == LOCAL) && !SAME_SRCF_DST ) + { + SET_DREG(DREG + 8); + } + else + { + DEBUG_PRINTF(("LDD.P denoted same regs @ %08X",PPC)); + } + + m_icount -= m_clock_cycles_2; +} + +void hyperstone_device::hyperstone_stwr(struct hyperstone_device::regs_decode *decode) +{ + if( SRC_IS_SR ) + SREG = 0; + + WRITE_W(DREG, SREG); + + m_icount -= m_clock_cycles_1; +} + +void hyperstone_device::hyperstone_stdr(struct hyperstone_device::regs_decode *decode) +{ + if( SRC_IS_SR ) + SREG = SREGF = 0; + + WRITE_W(DREG, SREG); + WRITE_W(DREG + 4, SREGF); + + m_icount -= m_clock_cycles_2; +} + +void hyperstone_device::hyperstone_stwp(struct hyperstone_device::regs_decode *decode) +{ + if( SRC_IS_SR ) + SREG = 0; + + WRITE_W(DREG, SREG); + SET_DREG(DREG + 4); + + m_icount -= m_clock_cycles_1; +} + +void hyperstone_device::hyperstone_stdp(struct hyperstone_device::regs_decode *decode) +{ + if( SRC_IS_SR ) + SREG = SREGF = 0; + + WRITE_W(DREG, SREG); + SET_DREG(DREG + 8); + + if( SAME_SRCF_DST ) + WRITE_W(DREG + 4, SREGF + 8); // because DREG == SREGF and DREG has been incremented + else + WRITE_W(DREG + 4, SREGF); + + m_icount -= m_clock_cycles_2; +} + +void hyperstone_device::hyperstone_dbv(struct hyperstone_device::regs_decode *decode) +{ + if( GET_V ) + execute_dbr(decode); + + m_icount -= m_clock_cycles_1; +} + +void hyperstone_device::hyperstone_dbnv(struct hyperstone_device::regs_decode *decode) +{ + if( !GET_V ) + execute_dbr(decode); + + m_icount -= m_clock_cycles_1; +} + +void hyperstone_device::hyperstone_dbe(struct hyperstone_device::regs_decode *decode) //or DBZ +{ + if( GET_Z ) + execute_dbr(decode); + + m_icount -= m_clock_cycles_1; +} + +void hyperstone_device::hyperstone_dbne(struct hyperstone_device::regs_decode *decode) //or DBNZ +{ + if( !GET_Z ) + execute_dbr(decode); + + m_icount -= m_clock_cycles_1; +} + +void hyperstone_device::hyperstone_dbc(struct hyperstone_device::regs_decode *decode) //or DBST +{ + if( GET_C ) + execute_dbr(decode); + + m_icount -= m_clock_cycles_1; +} + +void hyperstone_device::hyperstone_dbnc(struct hyperstone_device::regs_decode *decode) //or DBHE +{ + if( !GET_C ) + execute_dbr(decode); + + m_icount -= m_clock_cycles_1; +} + +void hyperstone_device::hyperstone_dbse(struct hyperstone_device::regs_decode *decode) +{ + if( GET_C || GET_Z ) + execute_dbr(decode); + + m_icount -= m_clock_cycles_1; +} + +void hyperstone_device::hyperstone_dbht(struct hyperstone_device::regs_decode *decode) +{ + if( !GET_C && !GET_Z ) + execute_dbr(decode); + + m_icount -= m_clock_cycles_1; +} + +void hyperstone_device::hyperstone_dbn(struct hyperstone_device::regs_decode *decode) //or DBLT +{ + if( GET_N ) + execute_dbr(decode); + + m_icount -= m_clock_cycles_1; +} + +void hyperstone_device::hyperstone_dbnn(struct hyperstone_device::regs_decode *decode) //or DBGE +{ + if( !GET_N ) + execute_dbr(decode); + + m_icount -= m_clock_cycles_1; +} + +void hyperstone_device::hyperstone_dble(struct hyperstone_device::regs_decode *decode) +{ + if( GET_N || GET_Z ) + execute_dbr(decode); + + m_icount -= m_clock_cycles_1; +} + +void hyperstone_device::hyperstone_dbgt(struct hyperstone_device::regs_decode *decode) +{ + if( !GET_N && !GET_Z ) + execute_dbr(decode); + + m_icount -= m_clock_cycles_1; +} + +void hyperstone_device::hyperstone_dbr(struct hyperstone_device::regs_decode *decode) +{ + execute_dbr(decode); +} + +void hyperstone_device::hyperstone_frame(struct hyperstone_device::regs_decode *decode) +{ + INT8 difference; // really it's 7 bits + UINT8 realfp = GET_FP - SRC_CODE; + + SET_FP(realfp); + SET_FL(DST_CODE); + SET_M(0); + + difference = ((SP & 0x1fc) >> 2) + (64 - 10) - (realfp + GET_FL); + + /* convert to 8 bits */ + if(difference > 63) + difference = (INT8)(difference|0x80); + else if( difference < -64 ) + difference = difference & 0x7f; + + if( difference < 0 ) // else it's finished + { + UINT8 tmp_flag; + + tmp_flag = ( SP >= UB ? 1 : 0 ); + + do + { + WRITE_W(SP, GET_ABS_L_REG((SP & 0xfc) >> 2)); + SP += 4; + difference++; + + } while(difference != 0); + + if( tmp_flag ) + { + UINT32 addr = get_trap_addr(TRAPNO_FRAME_ERROR); + execute_exception(addr); + } + } + + //TODO: no 1! + m_icount -= m_clock_cycles_1; +} + +void hyperstone_device::hyperstone_call(struct hyperstone_device::regs_decode *decode) +{ + if( SRC_IS_SR ) + SREG = 0; + + if( !DST_CODE ) + decode->dst = 16; + + EXTRA_S = (EXTRA_S & ~1) + SREG; + + SET_ILC(m_instruction_length & 3); + + SET_DREG((PC & 0xfffffffe) | GET_S); + SET_DREGF(SR); + + SET_FP(GET_FP + decode->dst); + + SET_FL(6); //default value for call + SET_M(0); + + PPC = PC; + PC = EXTRA_S; // const value + + m_intblock = 2; + + //TODO: add interrupt locks, errors, .... + + //TODO: no 1! + m_icount -= m_clock_cycles_1; +} + +void hyperstone_device::hyperstone_bv(struct hyperstone_device::regs_decode *decode) +{ + if( GET_V ) + execute_br(decode); + else + m_icount -= m_clock_cycles_1; +} + +void hyperstone_device::hyperstone_bnv(struct hyperstone_device::regs_decode *decode) +{ + if( !GET_V ) + execute_br(decode); + else + m_icount -= m_clock_cycles_1; +} + +void hyperstone_device::hyperstone_be(struct hyperstone_device::regs_decode *decode) //or BZ +{ + if( GET_Z ) + execute_br(decode); + else + m_icount -= m_clock_cycles_1; +} + +void hyperstone_device::hyperstone_bne(struct hyperstone_device::regs_decode *decode) //or BNZ +{ + if( !GET_Z ) + execute_br(decode); + else + m_icount -= m_clock_cycles_1; +} + +void hyperstone_device::hyperstone_bc(struct hyperstone_device::regs_decode *decode) //or BST +{ + if( GET_C ) + execute_br(decode); + else + m_icount -= m_clock_cycles_1; +} + +void hyperstone_device::hyperstone_bnc(struct hyperstone_device::regs_decode *decode) //or BHE +{ + if( !GET_C ) + execute_br(decode); + else + m_icount -= m_clock_cycles_1; +} + +void hyperstone_device::hyperstone_bse(struct hyperstone_device::regs_decode *decode) +{ + if( GET_C || GET_Z ) + execute_br(decode); + else + m_icount -= m_clock_cycles_1; +} + +void hyperstone_device::hyperstone_bht(struct hyperstone_device::regs_decode *decode) +{ + if( !GET_C && !GET_Z ) + execute_br(decode); + else + m_icount -= m_clock_cycles_1; +} + +void hyperstone_device::hyperstone_bn(struct hyperstone_device::regs_decode *decode) //or BLT +{ + if( GET_N ) + execute_br(decode); + else + m_icount -= m_clock_cycles_1; +} + +void hyperstone_device::hyperstone_bnn(struct hyperstone_device::regs_decode *decode) //or BGE +{ + if( !GET_N ) + execute_br(decode); + else + m_icount -= m_clock_cycles_1; +} + +void hyperstone_device::hyperstone_ble(struct hyperstone_device::regs_decode *decode) +{ + if( GET_N || GET_Z ) + execute_br(decode); + else + m_icount -= m_clock_cycles_1; +} + +void hyperstone_device::hyperstone_bgt(struct hyperstone_device::regs_decode *decode) +{ + if( !GET_N && !GET_Z ) + execute_br(decode); + else + m_icount -= m_clock_cycles_1; +} + +void hyperstone_device::hyperstone_br(struct hyperstone_device::regs_decode *decode) +{ + execute_br(decode); +} + +void hyperstone_device::hyperstone_trap(struct hyperstone_device::regs_decode *decode) +{ + UINT8 code, trapno; + UINT32 addr; + + trapno = (OP & 0xfc) >> 2; + + addr = get_trap_addr(trapno); + code = ((OP & 0x300) >> 6) | (OP & 0x03); + + switch( code ) + { + case TRAPLE: + if( GET_N || GET_Z ) + execute_trap(addr); + + break; + + case TRAPGT: + if( !GET_N && !GET_Z ) + execute_trap(addr); + + break; + + case TRAPLT: + if( GET_N ) + execute_trap(addr); + + break; + + case TRAPGE: + if( !GET_N ) + execute_trap(addr); + + break; + + case TRAPSE: + if( GET_C || GET_Z ) + execute_trap(addr); + + break; + + case TRAPHT: + if( !GET_C && !GET_Z ) + execute_trap(addr); + + break; + + case TRAPST: + if( GET_C ) + execute_trap(addr); + + break; + + case TRAPHE: + if( !GET_C ) + execute_trap(addr); + + break; + + case TRAPE: + if( GET_Z ) + execute_trap(addr); + + break; + + case TRAPNE: + if( !GET_Z ) + execute_trap(addr); + + break; + + case TRAPV: + if( GET_V ) + execute_trap(addr); + + break; + + case TRAP: + execute_trap(addr); + + break; + } + + m_icount -= m_clock_cycles_1; +} + + +#include "e132xsop.inc" + +//************************************************************************** +// CORE EXECUTION LOOP +//************************************************************************** + +//------------------------------------------------- +// execute_min_cycles - return minimum number of +// cycles it takes for one instruction to execute +//------------------------------------------------- + +UINT32 hyperstone_device::execute_min_cycles() const +{ + return 1; +} + + +//------------------------------------------------- +// execute_max_cycles - return maximum number of +// cycles it takes for one instruction to execute +//------------------------------------------------- + +UINT32 hyperstone_device::execute_max_cycles() const +{ + return 36; +} + + +//------------------------------------------------- +// execute_input_lines - return the number of +// input/interrupt lines +//------------------------------------------------- + +UINT32 hyperstone_device::execute_input_lines() const +{ + return 8; +} + + +void hyperstone_device::execute_set_input(int inputnum, int state) +{ + if (state) + ISR |= 1 << inputnum; + else + ISR &= ~(1 << inputnum); +} + + +//------------------------------------------------- +// execute_run - execute a timeslice's worth of +// opcodes +//------------------------------------------------- + +void hyperstone_device::execute_run() +{ + if (m_intblock < 0) + m_intblock = 0; + + check_interrupts(); + + do + { + UINT32 oldh = SR & 0x00000020; + + PPC = PC; /* copy PC to previous PC */ + debugger_instruction_hook(this, PC); + + OP = READ_OP(PC); + PC += 2; + + m_instruction_length = 1; + + /* execute opcode */ + (this->*m_opcode[(OP & 0xff00) >> 8])(); + + /* clear the H state if it was previously set */ + SR ^= oldh; + + SET_ILC(m_instruction_length & 3); + + if( GET_T && GET_P && m_delay.delay_cmd == NO_DELAY ) /* Not in a Delayed Branch instructions */ + { + UINT32 addr = get_trap_addr(TRAPNO_TRACE_EXCEPTION); + execute_exception(addr); + } + + if (--m_intblock == 0) + check_interrupts(); + + } while( m_icount > 0 ); +} + +const device_type E116T = &device_creator; +const device_type E116XT = &device_creator; +const device_type E116XS = &device_creator; +const device_type E116XSR = &device_creator; +const device_type E132N = &device_creator; +const device_type E132T = &device_creator; +const device_type E132XN = &device_creator; +const device_type E132XT = &device_creator; +const device_type E132XS = &device_creator; +const device_type E132XSR = &device_creator; +const device_type GMS30C2116 = &device_creator; +const device_type GMS30C2132 = &device_creator; +const device_type GMS30C2216 = &device_creator; +const device_type GMS30C2232 = &device_creator; diff --git a/src/devices/cpu/e132xs/e132xs.h b/src/devices/cpu/e132xs/e132xs.h new file mode 100644 index 00000000000..c8f43641ff5 --- /dev/null +++ b/src/devices/cpu/e132xs/e132xs.h @@ -0,0 +1,699 @@ +// license:BSD-3-Clause +// copyright-holders:Pierpaolo Prazzoli +#pragma once + +#ifndef __E132XS_H__ +#define __E132XS_H__ + + +/* + A note about clock multipliers and dividers: + + E1-16[T] and E1-32[T] accept a straight clock + + E1-16X[T|N] and E1-32X[T|N] accept a clock and multiply it + internally by 4; in the emulator, you MUST specify 4 * XTAL + to achieve the correct speed + + E1-16XS[R] and E1-32XS[R] accept a clock and multiply it + internally by 8; in the emulator, you MUST specify 8 * XTAL + to achieve the correct speed +*/ + + + +/* Functions */ + +/*************************************************************************** + COMPILE-TIME DEFINITIONS +***************************************************************************/ + +#define PC_REGISTER 0 +#define SR_REGISTER 1 +#define BCR_REGISTER 20 +#define TPR_REGISTER 21 +#define TCR_REGISTER 22 +#define TR_REGISTER 23 +#define ISR_REGISTER 25 +#define FCR_REGISTER 26 +#define MCR_REGISTER 27 + +#define X_CODE(val) ((val & 0x7000) >> 12) +#define E_BIT(val) ((val & 0x8000) >> 15) +#define S_BIT_CONST(val) ((val & 0x4000) >> 14) +#define DD(val) ((val & 0x3000) >> 12) + + +/* Extended DSP instructions */ +#define EMUL 0x102 +#define EMULU 0x104 +#define EMULS 0x106 +#define EMAC 0x10a +#define EMACD 0x10e +#define EMSUB 0x11a +#define EMSUBD 0x11e +#define EHMAC 0x02a +#define EHMACD 0x02e +#define EHCMULD 0x046 +#define EHCMACD 0x04e +#define EHCSUMD 0x086 +#define EHCFFTD 0x096 +#define EHCFFTSD 0x296 + +/* Delay values */ +#define NO_DELAY 0 +#define DELAY_EXECUTE 1 + +/* IRQ numbers */ +#define IRQ_INT1 0 +#define IRQ_INT2 1 +#define IRQ_INT3 2 +#define IRQ_INT4 3 +#define IRQ_IO1 4 +#define IRQ_IO2 5 +#define IRQ_IO3 6 + +/* Trap numbers */ +#define TRAPNO_IO2 48 +#define TRAPNO_IO1 49 +#define TRAPNO_INT4 50 +#define TRAPNO_INT3 51 +#define TRAPNO_INT2 52 +#define TRAPNO_INT1 53 +#define TRAPNO_IO3 54 +#define TRAPNO_TIMER 55 +#define TRAPNO_RESERVED1 56 +#define TRAPNO_TRACE_EXCEPTION 57 +#define TRAPNO_PARITY_ERROR 58 +#define TRAPNO_EXTENDED_OVERFLOW 59 +#define TRAPNO_RANGE_ERROR 60 +#define TRAPNO_PRIVILEGE_ERROR TRAPNO_RANGE_ERROR +#define TRAPNO_FRAME_ERROR TRAPNO_RANGE_ERROR +#define TRAPNO_RESERVED2 61 +#define TRAPNO_RESET 62 // reserved if not mapped @ MEM3 +#define TRAPNO_ERROR_ENTRY 63 // for instruction code of all ones + +/* Trap codes */ +#define TRAPLE 4 +#define TRAPGT 5 +#define TRAPLT 6 +#define TRAPGE 7 +#define TRAPSE 8 +#define TRAPHT 9 +#define TRAPST 10 +#define TRAPHE 11 +#define TRAPE 12 +#define TRAPNE 13 +#define TRAPV 14 +#define TRAP 15 + +/* Entry point to get trap locations or emulated code associated */ +#define E132XS_ENTRY_MEM0 0 +#define E132XS_ENTRY_MEM1 1 +#define E132XS_ENTRY_MEM2 2 +#define E132XS_ENTRY_IRAM 3 +#define E132XS_ENTRY_MEM3 7 + +/*************************************************************************** + REGISTER ENUMERATION +***************************************************************************/ + +enum +{ + E132XS_PC = 1, + E132XS_SR, + E132XS_FER, + E132XS_G3, + E132XS_G4, + E132XS_G5, + E132XS_G6, + E132XS_G7, + E132XS_G8, + E132XS_G9, + E132XS_G10, + E132XS_G11, + E132XS_G12, + E132XS_G13, + E132XS_G14, + E132XS_G15, + E132XS_G16, + E132XS_G17, + E132XS_SP, + E132XS_UB, + E132XS_BCR, + E132XS_TPR, + E132XS_TCR, + E132XS_TR, + E132XS_WCR, + E132XS_ISR, + E132XS_FCR, + E132XS_MCR, + E132XS_G28, + E132XS_G29, + E132XS_G30, + E132XS_G31, + E132XS_CL0, E132XS_CL1, E132XS_CL2, E132XS_CL3, + E132XS_CL4, E132XS_CL5, E132XS_CL6, E132XS_CL7, + E132XS_CL8, E132XS_CL9, E132XS_CL10,E132XS_CL11, + E132XS_CL12,E132XS_CL13,E132XS_CL14,E132XS_CL15, + E132XS_L0, E132XS_L1, E132XS_L2, E132XS_L3, + E132XS_L4, E132XS_L5, E132XS_L6, E132XS_L7, + E132XS_L8, E132XS_L9, E132XS_L10, E132XS_L11, + E132XS_L12, E132XS_L13, E132XS_L14, E132XS_L15, + E132XS_L16, E132XS_L17, E132XS_L18, E132XS_L19, + E132XS_L20, E132XS_L21, E132XS_L22, E132XS_L23, + E132XS_L24, E132XS_L25, E132XS_L26, E132XS_L27, + E132XS_L28, E132XS_L29, E132XS_L30, E132XS_L31, + E132XS_L32, E132XS_L33, E132XS_L34, E132XS_L35, + E132XS_L36, E132XS_L37, E132XS_L38, E132XS_L39, + E132XS_L40, E132XS_L41, E132XS_L42, E132XS_L43, + E132XS_L44, E132XS_L45, E132XS_L46, E132XS_L47, + E132XS_L48, E132XS_L49, E132XS_L50, E132XS_L51, + E132XS_L52, E132XS_L53, E132XS_L54, E132XS_L55, + E132XS_L56, E132XS_L57, E132XS_L58, E132XS_L59, + E132XS_L60, E132XS_L61, E132XS_L62, E132XS_L63 +}; + +extern unsigned dasm_hyperstone(char *buffer, unsigned pc, const UINT8 *oprom, unsigned h_flag, int private_fp); + +/* Memory access */ +/* read byte */ +#define READ_B(addr) m_program->read_byte((addr)) +/* read half-word */ +#define READ_HW(addr) m_program->read_word((addr) & ~1) +/* read word */ +#define READ_W(addr) m_program->read_dword((addr) & ~3) + +/* write byte */ +#define WRITE_B(addr, data) m_program->write_byte(addr, data) +/* write half-word */ +#define WRITE_HW(addr, data) m_program->write_word((addr) & ~1, data) +/* write word */ +#define WRITE_W(addr, data) m_program->write_dword((addr) & ~3, data) + + +/* I/O access */ +/* read word */ +#define IO_READ_W(addr) m_io->read_dword(((addr) >> 11) & 0x7ffc) +/* write word */ +#define IO_WRITE_W(addr, data) m_io->write_dword(((addr) >> 11) & 0x7ffc, data) + + +#define READ_OP(addr) m_direct->read_word((addr), m_opcodexor) + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> hyperstone_device + +// Used by core CPU interface +class hyperstone_device : public cpu_device +{ +public: + // construction/destruction + hyperstone_device(const machine_config &mconfig, const char *name, const char *tag, device_t *owner, UINT32 clock, + const device_type type, UINT32 prg_data_width, UINT32 io_data_width, address_map_constructor internal_map, const char *shortname, const char *source); + + // public interfaces + +protected: + void init(int scale_mask); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_stop(); + + void make_ops(); + + // device_execute_interface overrides + virtual UINT32 execute_min_cycles() const; + virtual UINT32 execute_max_cycles() const; + virtual UINT32 execute_input_lines() const; + virtual void execute_run(); + virtual void execute_set_input(int inputnum, int state); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const; + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const; + virtual UINT32 disasm_max_opcode_bytes() const; + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + + // device_state_interface overrides + virtual void state_string_export(const device_state_entry &entry, std::string &str); + + // address spaces + const address_space_config m_program_config; + const address_space_config m_io_config; + address_space *m_program; + direct_read_data *m_direct; + address_space *m_io; + + /* Delay information */ + struct delay_info + { + INT32 delay_cmd; + UINT32 delay_pc; + }; + + // CPU registers + UINT32 m_global_regs[32]; + UINT32 m_local_regs[64]; + + /* internal stuff */ + UINT32 m_ppc; // previous pc + UINT16 m_op; // opcode + UINT32 m_trap_entry; // entry point to get trap address + + UINT8 m_clock_scale_mask; + UINT8 m_clck_scale; + UINT8 m_clock_cycles_1; + UINT8 m_clock_cycles_2; + UINT8 m_clock_cycles_4; + UINT8 m_clock_cycles_6; + + UINT64 m_tr_base_cycles; + UINT32 m_tr_base_value; + UINT32 m_tr_clocks_per_tick; + UINT8 m_timer_int_pending; + emu_timer *m_timer; + + delay_info m_delay; + + UINT32 m_opcodexor; + + INT32 m_instruction_length; + INT32 m_intblock; + + // other internal state + int m_icount; + + typedef void (hyperstone_device::*ophandler)(); + + ophandler m_opcode[256]; + + static const ophandler s_opcodetable[256]; + +private: + struct regs_decode + { + UINT8 src, dst; // destination and source register code + UINT32 src_value; // current source register value + UINT32 next_src_value; // current next source register value + UINT32 dst_value; // current destination register value + UINT32 next_dst_value; // current next destination register value + UINT8 sub_type; // sub type opcode (for DD and X_CODE bits) + union + { + UINT32 u; + INT32 s; + } extra; // extra value such as immediate value, const, pcrel, ... + UINT8 src_is_local; + UINT8 dst_is_local; + UINT8 same_src_dst; + UINT8 same_src_dstf; + UINT8 same_srcf_dst; + }; + + // internal functions + void check_interrupts(); + + void set_global_register(UINT8 code, UINT32 val); + void set_local_register(UINT8 code, UINT32 val); + + UINT32 get_global_register(UINT8 code); + + UINT32 get_trap_addr(UINT8 trapno); + UINT32 get_emu_code_addr(UINT8 num); + void hyperstone_set_trap_entry(int which); + UINT32 compute_tr(); + void update_timer_prescale(); + void adjust_timer_interrupt(); + + TIMER_CALLBACK_MEMBER(timer_callback); + + void execute_br(struct regs_decode *decode); + void execute_dbr(struct regs_decode *decode); + void execute_trap(UINT32 addr); + void execute_int(UINT32 addr); + void execute_exception(UINT32 addr); + void execute_software(struct regs_decode *decode); + + void hyperstone_chk(struct regs_decode *decode); + void hyperstone_movd(struct regs_decode *decode); + void hyperstone_divu(struct regs_decode *decode); + void hyperstone_divs(struct regs_decode *decode); + void hyperstone_xm(struct regs_decode *decode); + void hyperstone_mask(struct regs_decode *decode); + void hyperstone_sum(struct regs_decode *decode); + void hyperstone_sums(struct regs_decode *decode); + void hyperstone_cmp(struct regs_decode *decode); + void hyperstone_mov(struct regs_decode *decode); + void hyperstone_add(struct regs_decode *decode); + void hyperstone_adds(struct regs_decode *decode); + void hyperstone_cmpb(struct regs_decode *decode); + void hyperstone_andn(struct regs_decode *decode); + void hyperstone_or(struct regs_decode *decode); + void hyperstone_xor(struct regs_decode *decode); + void hyperstone_subc(struct regs_decode *decode); + void hyperstone_not(struct regs_decode *decode); + void hyperstone_sub(struct regs_decode *decode); + void hyperstone_subs(struct regs_decode *decode); + void hyperstone_addc(struct regs_decode *decode); + void hyperstone_and(struct regs_decode *decode); + void hyperstone_neg(struct regs_decode *decode); + void hyperstone_negs(struct regs_decode *decode); + void hyperstone_cmpi(struct regs_decode *decode); + void hyperstone_movi(struct regs_decode *decode); + void hyperstone_addi(struct regs_decode *decode); + void hyperstone_addsi(struct regs_decode *decode); + void hyperstone_cmpbi(struct regs_decode *decode); + void hyperstone_andni(struct regs_decode *decode); + void hyperstone_ori(struct regs_decode *decode); + void hyperstone_xori(struct regs_decode *decode); + void hyperstone_shrdi(struct regs_decode *decode); + void hyperstone_shrd(struct regs_decode *decode); + void hyperstone_shr(struct regs_decode *decode); + void hyperstone_shri(struct regs_decode *decode); + void hyperstone_sardi(struct regs_decode *decode); + void hyperstone_sard(struct regs_decode *decode); + void hyperstone_sar(struct regs_decode *decode); + void hyperstone_sari(struct regs_decode *decode); + void hyperstone_shldi(struct regs_decode *decode); + void hyperstone_shld(struct regs_decode *decode); + void hyperstone_shl(struct regs_decode *decode); + void hyperstone_shli(struct regs_decode *decode); + void hyperstone_testlz(struct regs_decode *decode); + void hyperstone_rol(struct regs_decode *decode); + void hyperstone_ldxx1(struct regs_decode *decode); + void hyperstone_ldxx2(struct regs_decode *decode); + void hyperstone_stxx1(struct regs_decode *decode); + void hyperstone_stxx2(struct regs_decode *decode); + void hyperstone_mulu(struct regs_decode *decode); + void hyperstone_muls(struct regs_decode *decode); + void hyperstone_mul(struct regs_decode *decode); + void hyperstone_set(struct regs_decode *decode); + + void hyperstone_fadd(struct regs_decode *decode); + void hyperstone_faddd(struct regs_decode *decode); + void hyperstone_fsub(struct regs_decode *decode); + void hyperstone_fsubd(struct regs_decode *decode); + void hyperstone_fmul(struct regs_decode *decode); + void hyperstone_fmuld(struct regs_decode *decode); + void hyperstone_fdiv(struct regs_decode *decode); + void hyperstone_fdivd(struct regs_decode *decode); + + void hyperstone_fcmp(struct regs_decode *decode); + void hyperstone_fcmpd(struct regs_decode *decode); + void hyperstone_fcmpu(struct regs_decode *decode); + void hyperstone_fcmpud(struct regs_decode *decode); + + void hyperstone_fcvt(struct regs_decode *decode); + void hyperstone_fcvtd(struct regs_decode *decode); + + void hyperstone_extend(struct regs_decode *decode); + + void hyperstone_ldwr(struct regs_decode *decode); + void hyperstone_lddr(struct regs_decode *decode); + void hyperstone_ldwp(struct regs_decode *decode); + void hyperstone_lddp(struct regs_decode *decode); + + void hyperstone_stwr(struct regs_decode *decode); + void hyperstone_stdr(struct regs_decode *decode); + void hyperstone_stwp(struct regs_decode *decode); + void hyperstone_stdp(struct regs_decode *decode); + + void hyperstone_dbv(struct regs_decode *decode); + void hyperstone_dbnv(struct regs_decode *decode); + void hyperstone_dbe(struct regs_decode *decode); + void hyperstone_dbne(struct regs_decode *decode); + void hyperstone_dbc(struct regs_decode *decode); + void hyperstone_dbnc(struct regs_decode *decode); + void hyperstone_dbse(struct regs_decode *decode); + void hyperstone_dbht(struct regs_decode *decode); + void hyperstone_dbn(struct regs_decode *decode); + void hyperstone_dbnn(struct regs_decode *decode); + void hyperstone_dble(struct regs_decode *decode); + void hyperstone_dbgt(struct regs_decode *decode); + void hyperstone_dbr(struct regs_decode *decode); + + void hyperstone_frame(struct regs_decode *decode); + void hyperstone_call(struct regs_decode *decode); + + void hyperstone_bv(struct regs_decode *decode); + void hyperstone_bnv(struct regs_decode *decode); + void hyperstone_be(struct regs_decode *decode); + void hyperstone_bne(struct regs_decode *decode); + void hyperstone_bc(struct regs_decode *decode); + void hyperstone_bnc(struct regs_decode *decode); + void hyperstone_bse(struct regs_decode *decode); + void hyperstone_bht(struct regs_decode *decode); + void hyperstone_bn(struct regs_decode *decode); + void hyperstone_bnn(struct regs_decode *decode); + void hyperstone_ble(struct regs_decode *decode); + void hyperstone_bgt(struct regs_decode *decode); + void hyperstone_br(struct regs_decode *decode); + + void hyperstone_trap(struct regs_decode *decode); + void hyperstone_do(struct regs_decode *decode); + + void reserved(struct regs_decode *decode); + + void op00(); void op01(); void op02(); void op03(); void op04(); void op05(); void op06(); void op07(); + void op08(); void op09(); void op0a(); void op0b(); void op0c(); void op0d(); void op0e(); void op0f(); + void op10(); void op11(); void op12(); void op13(); void op14(); void op15(); void op16(); void op17(); + void op18(); void op19(); void op1a(); void op1b(); void op1c(); void op1d(); void op1e(); void op1f(); + void op20(); void op21(); void op22(); void op23(); void op24(); void op25(); void op26(); void op27(); + void op28(); void op29(); void op2a(); void op2b(); void op2c(); void op2d(); void op2e(); void op2f(); + void op30(); void op31(); void op32(); void op33(); void op34(); void op35(); void op36(); void op37(); + void op38(); void op39(); void op3a(); void op3b(); void op3c(); void op3d(); void op3e(); void op3f(); + void op40(); void op41(); void op42(); void op43(); void op44(); void op45(); void op46(); void op47(); + void op48(); void op49(); void op4a(); void op4b(); void op4c(); void op4d(); void op4e(); void op4f(); + void op50(); void op51(); void op52(); void op53(); void op54(); void op55(); void op56(); void op57(); + void op58(); void op59(); void op5a(); void op5b(); void op5c(); void op5d(); void op5e(); void op5f(); + void op60(); void op61(); void op62(); void op63(); void op64(); void op65(); void op66(); void op67(); + void op68(); void op69(); void op6a(); void op6b(); void op6c(); void op6d(); void op6e(); void op6f(); + void op70(); void op71(); void op72(); void op73(); void op74(); void op75(); void op76(); void op77(); + void op78(); void op79(); void op7a(); void op7b(); void op7c(); void op7d(); void op7e(); void op7f(); + void op80(); void op81(); void op82(); void op83(); void op84(); void op85(); void op86(); void op87(); + void op88(); void op89(); void op8a(); void op8b(); void op8c(); void op8d(); void op8e(); void op8f(); + void op90(); void op91(); void op92(); void op93(); void op94(); void op95(); void op96(); void op97(); + void op98(); void op99(); void op9a(); void op9b(); void op9c(); void op9d(); void op9e(); void op9f(); + void opa0(); void opa1(); void opa2(); void opa3(); void opa4(); void opa5(); void opa6(); void opa7(); + void opa8(); void opa9(); void opaa(); void opab(); void opac(); void opad(); void opae(); void opaf(); + void opb0(); void opb1(); void opb2(); void opb3(); void opb4(); void opb5(); void opb6(); void opb7(); + void opb8(); void opb9(); void opba(); void opbb(); void opbc(); void opbd(); void opbe(); void opbf(); + void opc0(); void opc1(); void opc2(); void opc3(); void opc4(); void opc5(); void opc6(); void opc7(); + void opc8(); void opc9(); void opca(); void opcb(); void opcc(); void opcd(); void opce(); void opcf(); + void opd0(); void opd1(); void opd2(); void opd3(); void opd4(); void opd5(); void opd6(); void opd7(); + void opd8(); void opd9(); void opda(); void opdb(); void opdc(); void opdd(); void opde(); void opdf(); + void ope0(); void ope1(); void ope2(); void ope3(); void ope4(); void ope5(); void ope6(); void ope7(); + void ope8(); void ope9(); void opea(); void opeb(); void opec(); void oped(); void opee(); void opef(); + void opf0(); void opf1(); void opf2(); void opf3(); void opf4(); void opf5(); void opf6(); void opf7(); + void opf8(); void opf9(); void opfa(); void opfb(); void opfc(); void opfd(); void opfe(); void opff(); + + void set_irq_line(int irqline, int state); +}; + +// device type definition +extern const device_type E116T; +extern const device_type E116XT; +extern const device_type E116XS; +extern const device_type E116XSR; +extern const device_type E132N; +extern const device_type E132T; +extern const device_type E132XN; +extern const device_type E132XT; +extern const device_type E132XS; +extern const device_type E132XSR; +extern const device_type GMS30C2116; +extern const device_type GMS30C2132; +extern const device_type GMS30C2216; +extern const device_type GMS30C2232; + + +// ======================> e116t_device + +class e116t_device : public hyperstone_device +{ +public: + // construction/destruction + e116t_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual void device_start(); +}; + + +// ======================> e116xt_device + +class e116xt_device : public hyperstone_device +{ +public: + // construction/destruction + e116xt_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual void device_start(); +}; + + +// ======================> e116xs_device + +class e116xs_device : public hyperstone_device +{ +public: + // construction/destruction + e116xs_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual void device_start(); +}; + + +// ======================> e116xsr_device + +class e116xsr_device : public hyperstone_device +{ +public: + // construction/destruction + e116xsr_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual void device_start(); +}; + + +// ======================> e132n_device + +class e132n_device : public hyperstone_device +{ +public: + // construction/destruction + e132n_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual void device_start(); +}; + + +// ======================> e132t_device + +class e132t_device : public hyperstone_device +{ +public: + // construction/destruction + e132t_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual void device_start(); +}; + + +// ======================> e132xn_device + +class e132xn_device : public hyperstone_device +{ +public: + // construction/destruction + e132xn_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual void device_start(); +}; + + +// ======================> e132xt_device + +class e132xt_device : public hyperstone_device +{ +public: + // construction/destruction + e132xt_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual void device_start(); +}; + + +// ======================> e132xs_device + +class e132xs_device : public hyperstone_device +{ +public: + // construction/destruction + e132xs_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual void device_start(); +}; + + +// ======================> e132xsr_device + +class e132xsr_device : public hyperstone_device +{ +public: + // construction/destruction + e132xsr_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual void device_start(); +}; + + +// ======================> gms30c2116_device + +class gms30c2116_device : public hyperstone_device +{ +public: + // construction/destruction + gms30c2116_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual void device_start(); +}; + + +// ======================> gms30c2132_device + +class gms30c2132_device : public hyperstone_device +{ +public: + // construction/destruction + gms30c2132_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual void device_start(); +}; + + +// ======================> gms30c2216_device + +class gms30c2216_device : public hyperstone_device +{ +public: + // construction/destruction + gms30c2216_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual void device_start(); +}; + + +// ======================> gms30c2232_device + +class gms30c2232_device : public hyperstone_device +{ +public: + // construction/destruction + gms30c2232_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual void device_start(); +}; + +#endif /* __E132XS_H__ */ diff --git a/src/devices/cpu/e132xs/e132xsop.inc b/src/devices/cpu/e132xs/e132xsop.inc new file mode 100644 index 00000000000..e37ef914246 --- /dev/null +++ b/src/devices/cpu/e132xs/e132xsop.inc @@ -0,0 +1,1925 @@ +// license:BSD-3-Clause +// copyright-holders:Pierpaolo Prazzoli +#define LOCAL_DECODE_INIT \ + struct regs_decode decode_state; \ + struct regs_decode *decode = &decode_state; \ +\ + /* clear 'current regs / flags' */ \ + decode->src = 0; \ + decode->dst = 0; \ + decode->src_value = 0; \ + decode->next_src_value = 0; \ + decode->dst_value = 0; \ + decode->next_dst_value = 0; \ + decode->sub_type = 0; \ + decode->extra.u = 0; \ + decode->src_is_local = 0; \ + decode->dst_is_local = 0; \ + decode->same_src_dst = 0; \ + decode->same_src_dstf = 0; \ + decode->same_srcf_dst = 0; + +void hyperstone_device::op00() +{ + LOCAL_DECODE_INIT; + RRdecode(decode, 0, 0); + hyperstone_chk(decode); +} + +void hyperstone_device::op01() +{ + LOCAL_DECODE_INIT; + RRdecode(decode, 0, 1); + hyperstone_chk(decode); +} + +void hyperstone_device::op02() +{ + LOCAL_DECODE_INIT; + RRdecode(decode, 1, 0); + hyperstone_chk(decode); +} + +void hyperstone_device::op03() +{ + LOCAL_DECODE_INIT; + RRdecode(decode, 1, 1); + hyperstone_chk(decode); +} + +void hyperstone_device::op04() +{ + LOCAL_DECODE_INIT; + RRdecode(decode, 0, 0); + hyperstone_movd(decode); +} + +void hyperstone_device::op05() +{ + LOCAL_DECODE_INIT; + RRdecode(decode, 0, 1); + hyperstone_movd(decode); +} + +void hyperstone_device::op06() +{ + LOCAL_DECODE_INIT; + RRdecode(decode, 1, 0); + hyperstone_movd(decode); +} + +void hyperstone_device::op07() +{ + LOCAL_DECODE_INIT; + RRdecode(decode, 1, 1); + hyperstone_movd(decode); +} + +void hyperstone_device::op08() +{ + LOCAL_DECODE_INIT; + RRdecode(decode, 0, 0); + hyperstone_divu(decode); +} + +void hyperstone_device::op09() +{ + LOCAL_DECODE_INIT; + RRdecode(decode, 0, 1); + hyperstone_divu(decode); +} + +void hyperstone_device::op0a() +{ + LOCAL_DECODE_INIT; + RRdecode(decode, 1, 0); + hyperstone_divu(decode); +} + +void hyperstone_device::op0b() +{ + LOCAL_DECODE_INIT; + RRdecode(decode, 1, 1); + hyperstone_divu(decode); +} + +void hyperstone_device::op0c() +{ + LOCAL_DECODE_INIT; + RRdecode(decode, 0, 0); + hyperstone_divs(decode); +} + +void hyperstone_device::op0d() +{ + LOCAL_DECODE_INIT; + RRdecode(decode, 0, 1); + hyperstone_divs(decode); +} + +void hyperstone_device::op0e() +{ + LOCAL_DECODE_INIT; + RRdecode(decode, 1, 0); + hyperstone_divs(decode); +} + +void hyperstone_device::op0f() +{ + LOCAL_DECODE_INIT; + RRdecode(decode, 1, 1); + hyperstone_divs(decode); +} + + + +void hyperstone_device::op10() +{ + LOCAL_DECODE_INIT; + RRlimdecode(decode, 0, 0); + hyperstone_xm(decode); +} + +void hyperstone_device::op11() +{ + LOCAL_DECODE_INIT; + RRlimdecode(decode, 0, 1); + hyperstone_xm(decode); +} + +void hyperstone_device::op12() +{ + LOCAL_DECODE_INIT; + RRlimdecode(decode, 1, 0); + hyperstone_xm(decode); +} + +void hyperstone_device::op13() +{ + LOCAL_DECODE_INIT; + RRlimdecode(decode, 1, 1); + hyperstone_xm(decode); +} + +void hyperstone_device::op14() +{ + LOCAL_DECODE_INIT; + RRconstdecode(decode, 0, 0); + hyperstone_mask(decode); +} + +void hyperstone_device::op15() +{ + LOCAL_DECODE_INIT; + RRconstdecode(decode, 0, 1); + hyperstone_mask(decode); +} + +void hyperstone_device::op16() +{ + LOCAL_DECODE_INIT; + RRconstdecode(decode, 1, 0); + hyperstone_mask(decode); +} + +void hyperstone_device::op17() +{ + LOCAL_DECODE_INIT; + RRconstdecode(decode, 1, 1); + hyperstone_mask(decode); +} + +void hyperstone_device::op18() +{ + LOCAL_DECODE_INIT; + RRconstdecode(decode, 0, 0); + hyperstone_sum(decode); +} + +void hyperstone_device::op19() +{ + LOCAL_DECODE_INIT; + RRconstdecode(decode, 0, 1); + hyperstone_sum(decode); +} + +void hyperstone_device::op1a() +{ + LOCAL_DECODE_INIT; + RRconstdecode(decode, 1, 0); + hyperstone_sum(decode); +} + +void hyperstone_device::op1b() +{ + LOCAL_DECODE_INIT; + RRconstdecode(decode, 1, 1); + hyperstone_sum(decode); +} + +void hyperstone_device::op1c() +{ + LOCAL_DECODE_INIT; + RRconstdecode(decode, 0, 0); + hyperstone_sums(decode); +} + +void hyperstone_device::op1d() +{ + LOCAL_DECODE_INIT; + RRconstdecode(decode, 0, 1); + hyperstone_sums(decode); +} + +void hyperstone_device::op1e() +{ + LOCAL_DECODE_INIT; + RRconstdecode(decode, 1, 0); + hyperstone_sums(decode); +} + +void hyperstone_device::op1f() +{ + LOCAL_DECODE_INIT; + RRconstdecode(decode, 1, 1); + hyperstone_sums(decode); +} + + + +void hyperstone_device::op20() +{ + LOCAL_DECODE_INIT; + RRdecode(decode, 0, 0); + hyperstone_cmp(decode); +} + +void hyperstone_device::op21() +{ + LOCAL_DECODE_INIT; + RRdecode(decode, 0, 1); + hyperstone_cmp(decode); +} + +void hyperstone_device::op22() +{ + LOCAL_DECODE_INIT; + RRdecode(decode, 1, 0); + hyperstone_cmp(decode); +} + +void hyperstone_device::op23() +{ + LOCAL_DECODE_INIT; + RRdecode(decode, 1, 1); + hyperstone_cmp(decode); +} + +void hyperstone_device::op24() +{ + LOCAL_DECODE_INIT; + RRdecodewithHflag(decode, 0, 0); + hyperstone_mov(decode); +} + +void hyperstone_device::op25() +{ + LOCAL_DECODE_INIT; + RRdecodewithHflag(decode, 0, 1); + hyperstone_mov(decode); +} + +void hyperstone_device::op26() +{ + LOCAL_DECODE_INIT; + RRdecodewithHflag(decode, 1, 0); + hyperstone_mov(decode); +} + +void hyperstone_device::op27() +{ + LOCAL_DECODE_INIT; + RRdecodewithHflag(decode, 1, 1); + hyperstone_mov(decode); +} + +void hyperstone_device::op28() +{ + LOCAL_DECODE_INIT; + RRdecode(decode, 0, 0); + hyperstone_add(decode); +} + +void hyperstone_device::op29() +{ + LOCAL_DECODE_INIT; + RRdecode(decode, 0, 1); + hyperstone_add(decode); +} + +void hyperstone_device::op2a() +{ + LOCAL_DECODE_INIT; + RRdecode(decode, 1, 0); + hyperstone_add(decode); +} + +void hyperstone_device::op2b() +{ + LOCAL_DECODE_INIT; + RRdecode(decode, 1, 1); + hyperstone_add(decode); +} + +void hyperstone_device::op2c() +{ + LOCAL_DECODE_INIT; + RRdecode(decode, 0, 0); + hyperstone_adds(decode); +} + +void hyperstone_device::op2d() +{ + LOCAL_DECODE_INIT; + RRdecode(decode, 0, 1); + hyperstone_adds(decode); +} + +void hyperstone_device::op2e() +{ + LOCAL_DECODE_INIT; + RRdecode(decode, 1, 0); + hyperstone_adds(decode); +} + +void hyperstone_device::op2f() +{ + LOCAL_DECODE_INIT; + RRdecode(decode, 1, 1); + hyperstone_adds(decode); +} + + + +void hyperstone_device::op30() +{ + LOCAL_DECODE_INIT; + RRdecode(decode, 0, 0); + hyperstone_cmpb(decode); +} + +void hyperstone_device::op31() +{ + LOCAL_DECODE_INIT; + RRdecode(decode, 0, 1); + hyperstone_cmpb(decode); +} + +void hyperstone_device::op32() +{ + LOCAL_DECODE_INIT; + RRdecode(decode, 1, 0); + hyperstone_cmpb(decode); +} + +void hyperstone_device::op33() +{ + LOCAL_DECODE_INIT; + RRdecode(decode, 1, 1); + hyperstone_cmpb(decode); +} + +void hyperstone_device::op34() +{ + LOCAL_DECODE_INIT; + RRdecode(decode, 0, 0); + hyperstone_andn(decode); +} + +void hyperstone_device::op35() +{ + LOCAL_DECODE_INIT; + RRdecode(decode, 0, 1); + hyperstone_andn(decode); +} + +void hyperstone_device::op36() +{ + LOCAL_DECODE_INIT; + RRdecode(decode, 1, 0); + hyperstone_andn(decode); +} + +void hyperstone_device::op37() +{ + LOCAL_DECODE_INIT; + RRdecode(decode, 1, 1); + hyperstone_andn(decode); +} + +void hyperstone_device::op38() +{ + LOCAL_DECODE_INIT; + RRdecode(decode, 0, 0); + hyperstone_or(decode); +} + +void hyperstone_device::op39() +{ + LOCAL_DECODE_INIT; + RRdecode(decode, 0, 1); + hyperstone_or(decode); +} + +void hyperstone_device::op3a() +{ + LOCAL_DECODE_INIT; + RRdecode(decode, 1, 0); + hyperstone_or(decode); +} + +void hyperstone_device::op3b() +{ + LOCAL_DECODE_INIT; + RRdecode(decode, 1, 1); + hyperstone_or(decode); +} + +void hyperstone_device::op3c() +{ + LOCAL_DECODE_INIT; + RRdecode(decode, 0, 0); + hyperstone_xor(decode); +} + +void hyperstone_device::op3d() +{ + LOCAL_DECODE_INIT; + RRdecode(decode, 0, 1); + hyperstone_xor(decode); +} + +void hyperstone_device::op3e() +{ + LOCAL_DECODE_INIT; + RRdecode(decode, 1, 0); + hyperstone_xor(decode); +} + +void hyperstone_device::op3f() +{ + LOCAL_DECODE_INIT; + RRdecode(decode, 1, 1); + hyperstone_xor(decode); +} + + + +void hyperstone_device::op40() +{ + LOCAL_DECODE_INIT; + RRdecode(decode, 0, 0); + hyperstone_subc(decode); +} + +void hyperstone_device::op41() +{ + LOCAL_DECODE_INIT; + RRdecode(decode, 0, 1); + hyperstone_subc(decode); +} + +void hyperstone_device::op42() +{ + LOCAL_DECODE_INIT; + RRdecode(decode, 1, 0); + hyperstone_subc(decode); +} + +void hyperstone_device::op43() +{ + LOCAL_DECODE_INIT; + RRdecode(decode, 1, 1); + hyperstone_subc(decode); +} + +void hyperstone_device::op44() +{ + LOCAL_DECODE_INIT; + RRdecode(decode, 0, 0); + hyperstone_not(decode); +} + +void hyperstone_device::op45() +{ + LOCAL_DECODE_INIT; + RRdecode(decode, 0, 1); + hyperstone_not(decode); +} + +void hyperstone_device::op46() +{ + LOCAL_DECODE_INIT; + RRdecode(decode, 1, 0); + hyperstone_not(decode); +} + +void hyperstone_device::op47() +{ + LOCAL_DECODE_INIT; + RRdecode(decode, 1, 1); + hyperstone_not(decode); +} + +void hyperstone_device::op48() +{ + LOCAL_DECODE_INIT; + RRdecode(decode, 0, 0); + hyperstone_sub(decode); +} + +void hyperstone_device::op49() +{ + LOCAL_DECODE_INIT; + RRdecode(decode, 0, 1); + hyperstone_sub(decode); +} + +void hyperstone_device::op4a() +{ + LOCAL_DECODE_INIT; + RRdecode(decode, 1, 0); + hyperstone_sub(decode); +} + +void hyperstone_device::op4b() +{ + LOCAL_DECODE_INIT; + RRdecode(decode, 1, 1); + hyperstone_sub(decode); +} + +void hyperstone_device::op4c() +{ + LOCAL_DECODE_INIT; + RRdecode(decode, 0, 0); + hyperstone_subs(decode); +} + +void hyperstone_device::op4d() +{ + LOCAL_DECODE_INIT; + RRdecode(decode, 0, 1); + hyperstone_subs(decode); +} + +void hyperstone_device::op4e() +{ + LOCAL_DECODE_INIT; + RRdecode(decode, 1, 0); + hyperstone_subs(decode); +} + +void hyperstone_device::op4f() +{ + LOCAL_DECODE_INIT; + RRdecode(decode, 1, 1); + hyperstone_subs(decode); +} + + + +void hyperstone_device::op50() +{ + LOCAL_DECODE_INIT; + RRdecode(decode, 0, 0); + hyperstone_addc(decode); +} + +void hyperstone_device::op51() +{ + LOCAL_DECODE_INIT; + RRdecode(decode, 0, 1); + hyperstone_addc(decode); +} + +void hyperstone_device::op52() +{ + LOCAL_DECODE_INIT; + RRdecode(decode, 1, 0); + hyperstone_addc(decode); +} + +void hyperstone_device::op53() +{ + LOCAL_DECODE_INIT; + RRdecode(decode, 1, 1); + hyperstone_addc(decode); +} + +void hyperstone_device::op54() +{ + LOCAL_DECODE_INIT; + RRdecode(decode, 0, 0); + hyperstone_and(decode); +} + +void hyperstone_device::op55() +{ + LOCAL_DECODE_INIT; + RRdecode(decode, 0, 1); + hyperstone_and(decode); +} + +void hyperstone_device::op56() +{ + LOCAL_DECODE_INIT; + RRdecode(decode, 1, 0); + hyperstone_and(decode); +} + +void hyperstone_device::op57() +{ + LOCAL_DECODE_INIT; + RRdecode(decode, 1, 1); + hyperstone_and(decode); +} + +void hyperstone_device::op58() +{ + LOCAL_DECODE_INIT; + RRdecode(decode, 0, 0); + hyperstone_neg(decode); +} + +void hyperstone_device::op59() +{ + LOCAL_DECODE_INIT; + RRdecode(decode, 0, 1); + hyperstone_neg(decode); +} + +void hyperstone_device::op5a() +{ + LOCAL_DECODE_INIT; + RRdecode(decode, 1, 0); + hyperstone_neg(decode); +} + +void hyperstone_device::op5b() +{ + LOCAL_DECODE_INIT; + RRdecode(decode, 1, 1); + hyperstone_neg(decode); +} + +void hyperstone_device::op5c() +{ + LOCAL_DECODE_INIT; + RRdecode(decode, 0, 0); + hyperstone_negs(decode); +} + +void hyperstone_device::op5d() +{ + LOCAL_DECODE_INIT; + RRdecode(decode, 0, 1); + hyperstone_negs(decode); +} + +void hyperstone_device::op5e() +{ + LOCAL_DECODE_INIT; + RRdecode(decode, 1, 0); + hyperstone_negs(decode); +} + +void hyperstone_device::op5f() +{ + LOCAL_DECODE_INIT; + RRdecode(decode, 1, 1); + hyperstone_negs(decode); +} + + + +void hyperstone_device::op60() +{ + LOCAL_DECODE_INIT; + Rimmdecode(decode, 0, 0); + hyperstone_cmpi(decode); +} + +void hyperstone_device::op61() +{ + LOCAL_DECODE_INIT; + Rimmdecode(decode, 0, 1); + hyperstone_cmpi(decode); +} + +void hyperstone_device::op62() +{ + LOCAL_DECODE_INIT; + Rimmdecode(decode, 1, 0); + hyperstone_cmpi(decode); +} + +void hyperstone_device::op63() +{ + LOCAL_DECODE_INIT; + Rimmdecode(decode, 1, 1); + hyperstone_cmpi(decode); +} + +void hyperstone_device::op64() +{ + LOCAL_DECODE_INIT; + RimmdecodewithHflag(decode, 0, 0); + hyperstone_movi(decode); +} + +void hyperstone_device::op65() +{ + LOCAL_DECODE_INIT; + RimmdecodewithHflag(decode, 0, 1); + hyperstone_movi(decode); +} + +void hyperstone_device::op66() +{ + LOCAL_DECODE_INIT; + RimmdecodewithHflag(decode, 1, 0); + hyperstone_movi(decode); +} + +void hyperstone_device::op67() +{ + LOCAL_DECODE_INIT; + RimmdecodewithHflag(decode, 1, 1); + hyperstone_movi(decode); +} + +void hyperstone_device::op68() +{ + LOCAL_DECODE_INIT; + Rimmdecode(decode, 0, 0); + hyperstone_addi(decode); +} + +void hyperstone_device::op69() +{ + LOCAL_DECODE_INIT; + Rimmdecode(decode, 0, 1); + hyperstone_addi(decode); +} + +void hyperstone_device::op6a() +{ + LOCAL_DECODE_INIT; + Rimmdecode(decode, 1, 0); + hyperstone_addi(decode); +} + +void hyperstone_device::op6b() +{ + LOCAL_DECODE_INIT; + Rimmdecode(decode, 1, 1); + hyperstone_addi(decode); +} + +void hyperstone_device::op6c() +{ + LOCAL_DECODE_INIT; + Rimmdecode(decode, 0, 0); + hyperstone_addsi(decode); +} + +void hyperstone_device::op6d() +{ + LOCAL_DECODE_INIT; + Rimmdecode(decode, 0, 1); + hyperstone_addsi(decode); +} + +void hyperstone_device::op6e() +{ + LOCAL_DECODE_INIT; + Rimmdecode(decode, 1, 0); + hyperstone_addsi(decode); +} + +void hyperstone_device::op6f() +{ + LOCAL_DECODE_INIT; + Rimmdecode(decode, 1, 1); + hyperstone_addsi(decode); +} + + + +void hyperstone_device::op70() +{ + LOCAL_DECODE_INIT; + Rimmdecode(decode, 0, 0); + hyperstone_cmpbi(decode); +} + +void hyperstone_device::op71() +{ + LOCAL_DECODE_INIT; + Rimmdecode(decode, 0, 1); + hyperstone_cmpbi(decode); +} + +void hyperstone_device::op72() +{ + LOCAL_DECODE_INIT; + Rimmdecode(decode, 1, 0); + hyperstone_cmpbi(decode); +} + +void hyperstone_device::op73() +{ + LOCAL_DECODE_INIT; + Rimmdecode(decode, 1, 1); + hyperstone_cmpbi(decode); +} + +void hyperstone_device::op74() +{ + LOCAL_DECODE_INIT; + Rimmdecode(decode, 0, 0); + hyperstone_andni(decode); +} + +void hyperstone_device::op75() +{ + LOCAL_DECODE_INIT; + Rimmdecode(decode, 0, 1); + hyperstone_andni(decode); +} + +void hyperstone_device::op76() +{ + LOCAL_DECODE_INIT; + Rimmdecode(decode, 1, 0); + hyperstone_andni(decode); +} + +void hyperstone_device::op77() +{ + LOCAL_DECODE_INIT; + Rimmdecode(decode, 1, 1); + hyperstone_andni(decode); +} + +void hyperstone_device::op78() +{ + LOCAL_DECODE_INIT; + Rimmdecode(decode, 0, 0); + hyperstone_ori(decode); +} + +void hyperstone_device::op79() +{ + LOCAL_DECODE_INIT; + Rimmdecode(decode, 0, 1); + hyperstone_ori(decode); +} + +void hyperstone_device::op7a() +{ + LOCAL_DECODE_INIT; + Rimmdecode(decode, 1, 0); + hyperstone_ori(decode); +} + +void hyperstone_device::op7b() +{ + LOCAL_DECODE_INIT; + Rimmdecode(decode, 1, 1); + hyperstone_ori(decode); +} + +void hyperstone_device::op7c() +{ + LOCAL_DECODE_INIT; + Rimmdecode(decode, 0, 0); + hyperstone_xori(decode); +} + +void hyperstone_device::op7d() +{ + LOCAL_DECODE_INIT; + Rimmdecode(decode, 0, 1); + hyperstone_xori(decode); +} + +void hyperstone_device::op7e() +{ + LOCAL_DECODE_INIT; + Rimmdecode(decode, 1, 0); + hyperstone_xori(decode); +} + +void hyperstone_device::op7f() +{ + LOCAL_DECODE_INIT; + Rimmdecode(decode, 1, 1); + hyperstone_xori(decode); +} + + + +void hyperstone_device::op80() +{ + LOCAL_DECODE_INIT; + Lndecode(decode); + hyperstone_shrdi(decode); +} + +void hyperstone_device::op81() +{ + LOCAL_DECODE_INIT; + Lndecode(decode); + hyperstone_shrdi(decode); +} + +void hyperstone_device::op82() +{ + LOCAL_DECODE_INIT; + LLdecode(decode); + hyperstone_shrd(decode); +} + +void hyperstone_device::op83() +{ + LOCAL_DECODE_INIT; + LLdecode(decode); + hyperstone_shr(decode); +} + +void hyperstone_device::op84() +{ + LOCAL_DECODE_INIT; + Lndecode(decode); + hyperstone_sardi(decode); +} + +void hyperstone_device::op85() +{ + LOCAL_DECODE_INIT; + Lndecode(decode); + hyperstone_sardi(decode); +} + +void hyperstone_device::op86() +{ + LOCAL_DECODE_INIT; + LLdecode(decode); + hyperstone_sard(decode); +} + +void hyperstone_device::op87() +{ + LOCAL_DECODE_INIT; + LLdecode(decode); + hyperstone_sar(decode); +} + +void hyperstone_device::op88() +{ + LOCAL_DECODE_INIT; + Lndecode(decode); + hyperstone_shldi(decode); +} + +void hyperstone_device::op89() +{ + LOCAL_DECODE_INIT; + Lndecode(decode); + hyperstone_shldi(decode); +} + +void hyperstone_device::op8a() +{ + LOCAL_DECODE_INIT; + LLdecode(decode); + hyperstone_shld(decode); +} + +void hyperstone_device::op8b() +{ + LOCAL_DECODE_INIT; + LLdecode(decode); + hyperstone_shl(decode); +} + +void hyperstone_device::op8c() +{ + LOCAL_DECODE_INIT; + no_decode(decode); + reserved(decode); +} + +void hyperstone_device::op8d() +{ + LOCAL_DECODE_INIT; + no_decode(decode); + reserved(decode); +} + +void hyperstone_device::op8e() +{ + LOCAL_DECODE_INIT; + LLdecode(decode); + hyperstone_testlz(decode); +} + +void hyperstone_device::op8f() +{ + LOCAL_DECODE_INIT; + LLdecode(decode); + hyperstone_rol(decode); +} + + + +void hyperstone_device::op90() +{ + LOCAL_DECODE_INIT; + RRdisdecode(decode, 0, 0); + hyperstone_ldxx1(decode); +} + +void hyperstone_device::op91() +{ + LOCAL_DECODE_INIT; + RRdisdecode(decode, 0, 1); + hyperstone_ldxx1(decode); +} + +void hyperstone_device::op92() +{ + LOCAL_DECODE_INIT; + RRdisdecode(decode, 1, 0); + hyperstone_ldxx1(decode); +} + +void hyperstone_device::op93() +{ + LOCAL_DECODE_INIT; + RRdisdecode(decode, 1, 1); + hyperstone_ldxx1(decode); +} + +void hyperstone_device::op94() +{ + LOCAL_DECODE_INIT; + RRdisdecode(decode, 0, 0); + hyperstone_ldxx2(decode); +} + +void hyperstone_device::op95() +{ + LOCAL_DECODE_INIT; + RRdisdecode(decode, 0, 1); + hyperstone_ldxx2(decode); +} + +void hyperstone_device::op96() +{ + LOCAL_DECODE_INIT; + RRdisdecode(decode, 1, 0); + hyperstone_ldxx2(decode); +} + +void hyperstone_device::op97() +{ + LOCAL_DECODE_INIT; + RRdisdecode(decode, 1, 1); + hyperstone_ldxx2(decode); +} + +void hyperstone_device::op98() +{ + LOCAL_DECODE_INIT; + RRdisdecode(decode, 0, 0); + hyperstone_stxx1(decode); +} + +void hyperstone_device::op99() +{ + LOCAL_DECODE_INIT; + RRdisdecode(decode, 0, 1); + hyperstone_stxx1(decode); +} + +void hyperstone_device::op9a() +{ + LOCAL_DECODE_INIT; + RRdisdecode(decode, 1, 0); + hyperstone_stxx1(decode); +} + +void hyperstone_device::op9b() +{ + LOCAL_DECODE_INIT; + RRdisdecode(decode, 1, 1); + hyperstone_stxx1(decode); +} + +void hyperstone_device::op9c() +{ + LOCAL_DECODE_INIT; + RRdisdecode(decode, 0, 0); + hyperstone_stxx2(decode); +} + +void hyperstone_device::op9d() +{ + LOCAL_DECODE_INIT; + RRdisdecode(decode, 0, 1); + hyperstone_stxx2(decode); +} + +void hyperstone_device::op9e() +{ + LOCAL_DECODE_INIT; + RRdisdecode(decode, 1, 0); + hyperstone_stxx2(decode); +} + +void hyperstone_device::op9f() +{ + LOCAL_DECODE_INIT; + RRdisdecode(decode, 1, 1); + hyperstone_stxx2(decode); +} + + + +void hyperstone_device::opa0() +{ + LOCAL_DECODE_INIT; + Rndecode(decode, 0); + hyperstone_shri(decode); +} + +void hyperstone_device::opa1() +{ + LOCAL_DECODE_INIT; + Rndecode(decode, 0); + hyperstone_shri(decode); +} + +void hyperstone_device::opa2() +{ + LOCAL_DECODE_INIT; + Rndecode(decode, 1); + hyperstone_shri(decode); +} + +void hyperstone_device::opa3() +{ + LOCAL_DECODE_INIT; + Rndecode(decode, 1); + hyperstone_shri(decode); +} + +void hyperstone_device::opa4() +{ + LOCAL_DECODE_INIT; + Rndecode(decode, 0); + hyperstone_sari(decode); +} + +void hyperstone_device::opa5() +{ + LOCAL_DECODE_INIT; + Rndecode(decode, 0); + hyperstone_sari(decode); +} + +void hyperstone_device::opa6() +{ + LOCAL_DECODE_INIT; + Rndecode(decode, 1); + hyperstone_sari(decode); +} + +void hyperstone_device::opa7() +{ + LOCAL_DECODE_INIT; + Rndecode(decode, 1); + hyperstone_sari(decode); +} + +void hyperstone_device::opa8() +{ + LOCAL_DECODE_INIT; + Rndecode(decode, 0); + hyperstone_shli(decode); +} + +void hyperstone_device::opa9() +{ + LOCAL_DECODE_INIT; + Rndecode(decode, 0); + hyperstone_shli(decode); +} + +void hyperstone_device::opaa() +{ + LOCAL_DECODE_INIT; + Rndecode(decode, 1); + hyperstone_shli(decode); +} + +void hyperstone_device::opab() +{ + LOCAL_DECODE_INIT; + Rndecode(decode, 1); + hyperstone_shli(decode); +} + +void hyperstone_device::opac() +{ + LOCAL_DECODE_INIT; + no_decode(decode); + reserved(decode); +} + +void hyperstone_device::opad() +{ + LOCAL_DECODE_INIT; + no_decode(decode); + reserved(decode); +} + +void hyperstone_device::opae() +{ + LOCAL_DECODE_INIT; + no_decode(decode); + reserved(decode); +} + +void hyperstone_device::opaf() +{ + LOCAL_DECODE_INIT; + no_decode(decode); + reserved(decode); +} + + + +void hyperstone_device::opb0() +{ + LOCAL_DECODE_INIT; + RRdecode(decode, 0, 0); + hyperstone_mulu(decode); +} + +void hyperstone_device::opb1() +{ + LOCAL_DECODE_INIT; + RRdecode(decode, 0, 1); + hyperstone_mulu(decode); +} + +void hyperstone_device::opb2() +{ + LOCAL_DECODE_INIT; + RRdecode(decode, 1, 0); + hyperstone_mulu(decode); +} + +void hyperstone_device::opb3() +{ + LOCAL_DECODE_INIT; + RRdecode(decode, 1, 1); + hyperstone_mulu(decode); +} + +void hyperstone_device::opb4() +{ + LOCAL_DECODE_INIT; + RRdecode(decode, 0, 0); + hyperstone_muls(decode); +} + +void hyperstone_device::opb5() +{ + LOCAL_DECODE_INIT; + RRdecode(decode, 0, 1); + hyperstone_muls(decode); +} + +void hyperstone_device::opb6() +{ + LOCAL_DECODE_INIT; + RRdecode(decode, 1, 0); + hyperstone_muls(decode); +} + +void hyperstone_device::opb7() +{ + LOCAL_DECODE_INIT; + RRdecode(decode, 1, 1); + hyperstone_muls(decode); +} + +void hyperstone_device::opb8() +{ + LOCAL_DECODE_INIT; + Rndecode(decode, 0); + hyperstone_set(decode); +} + +void hyperstone_device::opb9() +{ + LOCAL_DECODE_INIT; + Rndecode(decode, 0); + hyperstone_set(decode); +} + +void hyperstone_device::opba() +{ + LOCAL_DECODE_INIT; + Rndecode(decode, 1); + hyperstone_set(decode); +} + +void hyperstone_device::opbb() +{ + LOCAL_DECODE_INIT; + Rndecode(decode, 1); + hyperstone_set(decode); +} + +void hyperstone_device::opbc() +{ + LOCAL_DECODE_INIT; + RRdecode(decode, 0, 0); + hyperstone_mul(decode); +} + +void hyperstone_device::opbd() +{ + LOCAL_DECODE_INIT; + RRdecode(decode, 0, 1); + hyperstone_mul(decode); +} + +void hyperstone_device::opbe() +{ + LOCAL_DECODE_INIT; + RRdecode(decode, 1, 0); + hyperstone_mul(decode); +} + +void hyperstone_device::opbf() +{ + LOCAL_DECODE_INIT; + RRdecode(decode, 1, 1); + hyperstone_mul(decode); +} + + + +void hyperstone_device::opc0() +{ + LOCAL_DECODE_INIT; + LLdecode(decode); + hyperstone_fadd(decode); +} + +void hyperstone_device::opc1() +{ + LOCAL_DECODE_INIT; + LLdecode(decode); + hyperstone_faddd(decode); +} + +void hyperstone_device::opc2() +{ + LOCAL_DECODE_INIT; + LLdecode(decode); + hyperstone_fsub(decode); +} + +void hyperstone_device::opc3() +{ + LOCAL_DECODE_INIT; + LLdecode(decode); + hyperstone_fsubd(decode); +} + +void hyperstone_device::opc4() +{ + LOCAL_DECODE_INIT; + LLdecode(decode); + hyperstone_fmul(decode); +} + +void hyperstone_device::opc5() +{ + LOCAL_DECODE_INIT; + LLdecode(decode); + hyperstone_fmuld(decode); +} + +void hyperstone_device::opc6() +{ + LOCAL_DECODE_INIT; + LLdecode(decode); + hyperstone_fdiv(decode); +} + +void hyperstone_device::opc7() +{ + LOCAL_DECODE_INIT; + LLdecode(decode); + hyperstone_fdivd(decode); +} + +void hyperstone_device::opc8() +{ + LOCAL_DECODE_INIT; + LLdecode(decode); + hyperstone_fcmp(decode); +} + +void hyperstone_device::opc9() +{ + LOCAL_DECODE_INIT; + LLdecode(decode); + hyperstone_fcmpd(decode); +} + +void hyperstone_device::opca() +{ + LOCAL_DECODE_INIT; + LLdecode(decode); + hyperstone_fcmpu(decode); +} + +void hyperstone_device::opcb() +{ + LOCAL_DECODE_INIT; + LLdecode(decode); + hyperstone_fcmpud(decode); +} + +void hyperstone_device::opcc() +{ + LOCAL_DECODE_INIT; + LLdecode(decode); + hyperstone_fcvt(decode); +} + +void hyperstone_device::opcd() +{ + LOCAL_DECODE_INIT; + LLdecode(decode); + hyperstone_fcvtd(decode); +} + +void hyperstone_device::opce() +{ + LOCAL_DECODE_INIT; + LLextdecode(decode); + hyperstone_extend(decode); +} + +void hyperstone_device::opcf() +{ + LOCAL_DECODE_INIT; + LLdecode(decode); + hyperstone_do(decode); +} + + + +void hyperstone_device::opd0() +{ + LOCAL_DECODE_INIT; + LRdecode(decode, 0); + hyperstone_ldwr(decode); +} + +void hyperstone_device::opd1() +{ + LOCAL_DECODE_INIT; + LRdecode(decode, 1); + hyperstone_ldwr(decode); +} + +void hyperstone_device::opd2() +{ + LOCAL_DECODE_INIT; + LRdecode(decode, 0); + hyperstone_lddr(decode); +} + +void hyperstone_device::opd3() +{ + LOCAL_DECODE_INIT; + LRdecode(decode, 1); + hyperstone_lddr(decode); +} + +void hyperstone_device::opd4() +{ + LOCAL_DECODE_INIT; + LRdecode(decode, 0); + hyperstone_ldwp(decode); +} + +void hyperstone_device::opd5() +{ + LOCAL_DECODE_INIT; + LRdecode(decode, 1); + hyperstone_ldwp(decode); +} + +void hyperstone_device::opd6() +{ + LOCAL_DECODE_INIT; + LRdecode(decode, 0); + hyperstone_lddp(decode); +} + +void hyperstone_device::opd7() +{ + LOCAL_DECODE_INIT; + LRdecode(decode, 1); + hyperstone_lddp(decode); +} + +void hyperstone_device::opd8() +{ + LOCAL_DECODE_INIT; + LRdecode(decode, 0); + hyperstone_stwr(decode); +} + +void hyperstone_device::opd9() +{ + LOCAL_DECODE_INIT; + LRdecode(decode, 1); + hyperstone_stwr(decode); +} + +void hyperstone_device::opda() +{ + LOCAL_DECODE_INIT; + LRdecode(decode, 0); + hyperstone_stdr(decode); +} + +void hyperstone_device::opdb() +{ + LOCAL_DECODE_INIT; + LRdecode(decode, 1); + hyperstone_stdr(decode); +} + +void hyperstone_device::opdc() +{ + LOCAL_DECODE_INIT; + LRdecode(decode, 0); + hyperstone_stwp(decode); +} + +void hyperstone_device::opdd() +{ + LOCAL_DECODE_INIT; + LRdecode(decode, 1); + hyperstone_stwp(decode); +} + +void hyperstone_device::opde() +{ + LOCAL_DECODE_INIT; + LRdecode(decode, 0); + hyperstone_stdp(decode); +} + +void hyperstone_device::opdf() +{ + LOCAL_DECODE_INIT; + LRdecode(decode, 1); + hyperstone_stdp(decode); +} + + + +void hyperstone_device::ope0() +{ + LOCAL_DECODE_INIT; + PCreldecode(decode); + hyperstone_dbv(decode); +} + +void hyperstone_device::ope1() +{ + LOCAL_DECODE_INIT; + PCreldecode(decode); + hyperstone_dbnv(decode); +} + +void hyperstone_device::ope2() +{ + LOCAL_DECODE_INIT; + PCreldecode(decode); + hyperstone_dbe(decode); +} + +void hyperstone_device::ope3() +{ + LOCAL_DECODE_INIT; + PCreldecode(decode); + hyperstone_dbne(decode); +} + +void hyperstone_device::ope4() +{ + LOCAL_DECODE_INIT; + PCreldecode(decode); + hyperstone_dbc(decode); +} + +void hyperstone_device::ope5() +{ + LOCAL_DECODE_INIT; + PCreldecode(decode); + hyperstone_dbnc(decode); +} + +void hyperstone_device::ope6() +{ + LOCAL_DECODE_INIT; + PCreldecode(decode); + hyperstone_dbse(decode); +} + +void hyperstone_device::ope7() +{ + LOCAL_DECODE_INIT; + PCreldecode(decode); + hyperstone_dbht(decode); +} + +void hyperstone_device::ope8() +{ + LOCAL_DECODE_INIT; + PCreldecode(decode); + hyperstone_dbn(decode); +} + +void hyperstone_device::ope9() +{ + LOCAL_DECODE_INIT; + PCreldecode(decode); + hyperstone_dbnn(decode); +} + +void hyperstone_device::opea() +{ + LOCAL_DECODE_INIT; + PCreldecode(decode); + hyperstone_dble(decode); +} + +void hyperstone_device::opeb() +{ + LOCAL_DECODE_INIT; + PCreldecode(decode); + hyperstone_dbgt(decode); +} + +void hyperstone_device::opec() +{ + LOCAL_DECODE_INIT; + PCreldecode(decode); + hyperstone_dbr(decode); +} + +void hyperstone_device::oped() +{ + LOCAL_DECODE_INIT; + LLdecode(decode); + hyperstone_frame(decode); +} + +void hyperstone_device::opee() +{ + LOCAL_DECODE_INIT; + LRconstdecode(decode, 0); + hyperstone_call(decode); +} + +void hyperstone_device::opef() +{ + LOCAL_DECODE_INIT; + LRconstdecode(decode, 1); + hyperstone_call(decode); +} + + + +void hyperstone_device::opf0() +{ + LOCAL_DECODE_INIT; + PCreldecode(decode); + hyperstone_bv(decode); +} + +void hyperstone_device::opf1() +{ + LOCAL_DECODE_INIT; + PCreldecode(decode); + hyperstone_bnv(decode); +} + +void hyperstone_device::opf2() +{ + LOCAL_DECODE_INIT; + PCreldecode(decode); + hyperstone_be(decode); +} + +void hyperstone_device::opf3() +{ + LOCAL_DECODE_INIT; + PCreldecode(decode); + hyperstone_bne(decode); +} + +void hyperstone_device::opf4() +{ + LOCAL_DECODE_INIT; + PCreldecode(decode); + hyperstone_bc(decode); +} + +void hyperstone_device::opf5() +{ + LOCAL_DECODE_INIT; + PCreldecode(decode); + hyperstone_bnc(decode); +} + +void hyperstone_device::opf6() +{ + LOCAL_DECODE_INIT; + PCreldecode(decode); + hyperstone_bse(decode); +} + +void hyperstone_device::opf7() +{ + LOCAL_DECODE_INIT; + PCreldecode(decode); + hyperstone_bht(decode); +} + +void hyperstone_device::opf8() +{ + LOCAL_DECODE_INIT; + PCreldecode(decode); + hyperstone_bn(decode); +} + +void hyperstone_device::opf9() +{ + LOCAL_DECODE_INIT; + PCreldecode(decode); + hyperstone_bnn(decode); +} + +void hyperstone_device::opfa() +{ + LOCAL_DECODE_INIT; + PCreldecode(decode); + hyperstone_ble(decode); +} + +void hyperstone_device::opfb() +{ + LOCAL_DECODE_INIT; + PCreldecode(decode); + hyperstone_bgt(decode); +} + +void hyperstone_device::opfc() +{ + LOCAL_DECODE_INIT; + PCreldecode(decode); + hyperstone_br(decode); +} + +void hyperstone_device::opfd() +{ + LOCAL_DECODE_INIT; + PCadrdecode(decode); + hyperstone_trap(decode); +} + +void hyperstone_device::opfe() +{ + LOCAL_DECODE_INIT; + PCadrdecode(decode); + hyperstone_trap(decode); +} + +void hyperstone_device::opff() +{ + LOCAL_DECODE_INIT; + PCadrdecode(decode); + hyperstone_trap(decode); +} + +const hyperstone_device::ophandler hyperstone_device::s_opcodetable[256] = +{ + &hyperstone_device::op00, &hyperstone_device::op01, &hyperstone_device::op02, &hyperstone_device::op03, + &hyperstone_device::op04, &hyperstone_device::op05, &hyperstone_device::op06, &hyperstone_device::op07, + &hyperstone_device::op08, &hyperstone_device::op09, &hyperstone_device::op0a, &hyperstone_device::op0b, + &hyperstone_device::op0c, &hyperstone_device::op0d, &hyperstone_device::op0e, &hyperstone_device::op0f, + + &hyperstone_device::op10, &hyperstone_device::op11, &hyperstone_device::op12, &hyperstone_device::op13, + &hyperstone_device::op14, &hyperstone_device::op15, &hyperstone_device::op16, &hyperstone_device::op17, + &hyperstone_device::op18, &hyperstone_device::op19, &hyperstone_device::op1a, &hyperstone_device::op1b, + &hyperstone_device::op1c, &hyperstone_device::op1d, &hyperstone_device::op1e, &hyperstone_device::op1f, + + &hyperstone_device::op20, &hyperstone_device::op21, &hyperstone_device::op22, &hyperstone_device::op23, + &hyperstone_device::op24, &hyperstone_device::op25, &hyperstone_device::op26, &hyperstone_device::op27, + &hyperstone_device::op28, &hyperstone_device::op29, &hyperstone_device::op2a, &hyperstone_device::op2b, + &hyperstone_device::op2c, &hyperstone_device::op2d, &hyperstone_device::op2e, &hyperstone_device::op2f, + + &hyperstone_device::op30, &hyperstone_device::op31, &hyperstone_device::op32, &hyperstone_device::op33, + &hyperstone_device::op34, &hyperstone_device::op35, &hyperstone_device::op36, &hyperstone_device::op37, + &hyperstone_device::op38, &hyperstone_device::op39, &hyperstone_device::op3a, &hyperstone_device::op3b, + &hyperstone_device::op3c, &hyperstone_device::op3d, &hyperstone_device::op3e, &hyperstone_device::op3f, + + &hyperstone_device::op40, &hyperstone_device::op41, &hyperstone_device::op42, &hyperstone_device::op43, + &hyperstone_device::op44, &hyperstone_device::op45, &hyperstone_device::op46, &hyperstone_device::op47, + &hyperstone_device::op48, &hyperstone_device::op49, &hyperstone_device::op4a, &hyperstone_device::op4b, + &hyperstone_device::op4c, &hyperstone_device::op4d, &hyperstone_device::op4e, &hyperstone_device::op4f, + + &hyperstone_device::op50, &hyperstone_device::op51, &hyperstone_device::op52, &hyperstone_device::op53, + &hyperstone_device::op54, &hyperstone_device::op55, &hyperstone_device::op56, &hyperstone_device::op57, + &hyperstone_device::op58, &hyperstone_device::op59, &hyperstone_device::op5a, &hyperstone_device::op5b, + &hyperstone_device::op5c, &hyperstone_device::op5d, &hyperstone_device::op5e, &hyperstone_device::op5f, + + &hyperstone_device::op60, &hyperstone_device::op61, &hyperstone_device::op62, &hyperstone_device::op63, + &hyperstone_device::op64, &hyperstone_device::op65, &hyperstone_device::op66, &hyperstone_device::op67, + &hyperstone_device::op68, &hyperstone_device::op69, &hyperstone_device::op6a, &hyperstone_device::op6b, + &hyperstone_device::op6c, &hyperstone_device::op6d, &hyperstone_device::op6e, &hyperstone_device::op6f, + + &hyperstone_device::op70, &hyperstone_device::op71, &hyperstone_device::op72, &hyperstone_device::op73, + &hyperstone_device::op74, &hyperstone_device::op75, &hyperstone_device::op76, &hyperstone_device::op77, + &hyperstone_device::op78, &hyperstone_device::op79, &hyperstone_device::op7a, &hyperstone_device::op7b, + &hyperstone_device::op7c, &hyperstone_device::op7d, &hyperstone_device::op7e, &hyperstone_device::op7f, + + &hyperstone_device::op80, &hyperstone_device::op81, &hyperstone_device::op82, &hyperstone_device::op83, + &hyperstone_device::op84, &hyperstone_device::op85, &hyperstone_device::op86, &hyperstone_device::op87, + &hyperstone_device::op88, &hyperstone_device::op89, &hyperstone_device::op8a, &hyperstone_device::op8b, + &hyperstone_device::op8c, &hyperstone_device::op8d, &hyperstone_device::op8e, &hyperstone_device::op8f, + + &hyperstone_device::op90, &hyperstone_device::op91, &hyperstone_device::op92, &hyperstone_device::op93, + &hyperstone_device::op94, &hyperstone_device::op95, &hyperstone_device::op96, &hyperstone_device::op97, + &hyperstone_device::op98, &hyperstone_device::op99, &hyperstone_device::op9a, &hyperstone_device::op9b, + &hyperstone_device::op9c, &hyperstone_device::op9d, &hyperstone_device::op9e, &hyperstone_device::op9f, + + &hyperstone_device::opa0, &hyperstone_device::opa1, &hyperstone_device::opa2, &hyperstone_device::opa3, + &hyperstone_device::opa4, &hyperstone_device::opa5, &hyperstone_device::opa6, &hyperstone_device::opa7, + &hyperstone_device::opa8, &hyperstone_device::opa9, &hyperstone_device::opaa, &hyperstone_device::opab, + &hyperstone_device::opac, &hyperstone_device::opad, &hyperstone_device::opae, &hyperstone_device::opaf, + + &hyperstone_device::opb0, &hyperstone_device::opb1, &hyperstone_device::opb2, &hyperstone_device::opb3, + &hyperstone_device::opb4, &hyperstone_device::opb5, &hyperstone_device::opb6, &hyperstone_device::opb7, + &hyperstone_device::opb8, &hyperstone_device::opb9, &hyperstone_device::opba, &hyperstone_device::opbb, + &hyperstone_device::opbc, &hyperstone_device::opbd, &hyperstone_device::opbe, &hyperstone_device::opbf, + + &hyperstone_device::opc0, &hyperstone_device::opc1, &hyperstone_device::opc2, &hyperstone_device::opc3, + &hyperstone_device::opc4, &hyperstone_device::opc5, &hyperstone_device::opc6, &hyperstone_device::opc7, + &hyperstone_device::opc8, &hyperstone_device::opc9, &hyperstone_device::opca, &hyperstone_device::opcb, + &hyperstone_device::opcc, &hyperstone_device::opcd, &hyperstone_device::opce, &hyperstone_device::opcf, + + &hyperstone_device::opd0, &hyperstone_device::opd1, &hyperstone_device::opd2, &hyperstone_device::opd3, + &hyperstone_device::opd4, &hyperstone_device::opd5, &hyperstone_device::opd6, &hyperstone_device::opd7, + &hyperstone_device::opd8, &hyperstone_device::opd9, &hyperstone_device::opda, &hyperstone_device::opdb, + &hyperstone_device::opdc, &hyperstone_device::opdd, &hyperstone_device::opde, &hyperstone_device::opdf, + + &hyperstone_device::ope0, &hyperstone_device::ope1, &hyperstone_device::ope2, &hyperstone_device::ope3, + &hyperstone_device::ope4, &hyperstone_device::ope5, &hyperstone_device::ope6, &hyperstone_device::ope7, + &hyperstone_device::ope8, &hyperstone_device::ope9, &hyperstone_device::opea, &hyperstone_device::opeb, + &hyperstone_device::opec, &hyperstone_device::oped, &hyperstone_device::opee, &hyperstone_device::opef, + + &hyperstone_device::opf0, &hyperstone_device::opf1, &hyperstone_device::opf2, &hyperstone_device::opf3, + &hyperstone_device::opf4, &hyperstone_device::opf5, &hyperstone_device::opf6, &hyperstone_device::opf7, + &hyperstone_device::opf8, &hyperstone_device::opf9, &hyperstone_device::opfa, &hyperstone_device::opfb, + &hyperstone_device::opfc, &hyperstone_device::opfd, &hyperstone_device::opfe, &hyperstone_device::opff +}; diff --git a/src/devices/cpu/es5510/es5510.c b/src/devices/cpu/es5510/es5510.c new file mode 100644 index 00000000000..77b88b5d861 --- /dev/null +++ b/src/devices/cpu/es5510/es5510.c @@ -0,0 +1,1226 @@ +// license:BSD-3-Clause +// copyright-holders:Christian Brunschen +/*************************************************************************** + * + * es5510.c - Ensoniq ES5510 (ESP) emulation + * by Christian Brunschen + * + ***************************************************************************/ + +#include +#include "emu.h" +#include "debugger.h" +#include "es5510.h" +#include "cpu/m68000/m68000.h" + +static const INT32 MIN_24 = -(1 << 23); +static const INT32 MAX_24 = (1 << 23) - 1; + +static const INT64 MIN_48 = -(S64(1) << 47); +static const INT64 MAX_48 = (S64(1) << 47) - 1; + +#define SIGN_BIT_24 (0x00800000) +#define GET_SIGN_BIT_24(x) ((x) & SIGN_BIT_24) +#define IS_NEGATIVE(x) (((x) & SIGN_BIT_24) != 0) + +#define CARRY_OUT_24 (0x01000000) + +static inline INT32 SX(INT32 x) { return IS_NEGATIVE(x) ? x | 0xff000000 : x & 0x00ffffff; } +static inline INT32 SC(INT32 x) { return x & 0x00ffffff; } +static inline INT64 SX64(INT64 x) { return (x & S64(0x0000800000000000)) ? x | S64(0xffff000000000000) : x & S64(0x0000ffffffffffff); } +//static inline INT64 SC64(INT64 x) { return x & S64(0x0000ffffffffffff); } + +#define VERBOSE 0 +#define VERBOSE_EXEC 0 + +#if VERBOSE +INLINE void ATTR_PRINTF(1,2) log_to_stderr(const char *format, ...) { + va_list ap; + va_start(ap, format); + vfprintf(stderr, format, ap); + va_end(ap); +} + +#define LOG(x) do { log_to_stderr x; } while(0) +#else +#define LOG(x) +#endif + + +#if VERBOSE_EXEC +static int exec_cc = 0; +#define LOG_EXEC(x) do { if (!exec_cc) LOG(x); } while(0) +#else +#define LOG_EXEC(x) +#endif + +const device_type ES5510 = &device_creator; + +#define FLAG_N (1 << 7) +#define FLAG_C (1 << 6) +#define FLAG_V (1 << 5) +#define FLAG_LT (1 << 4) +#define FLAG_Z (1 << 3) +#define FLAG_NOT (1 << 2) + +#define FLAG_MASK (FLAG_N | FLAG_C | FLAG_V | FLAG_LT | FLAG_Z) + +char *stpcpy_int (char *dst, const char *src) +{ + const size_t len = strlen (src); + return (char *) memcpy (dst, src, len + 1) + len; +} + +inline static UINT8 setFlag(UINT8 ccr, UINT8 flag) { + return ccr | flag; +} + +inline static UINT8 clearFlag(UINT8 ccr, UINT8 flag) { + return ccr & ~flag; +} + +inline static UINT8 setFlagTo(UINT8 ccr, UINT8 flag, bool set) { + return set ? setFlag(ccr, flag) : clearFlag(ccr, flag); +} + +inline static bool isFlagSet(UINT8 ccr, UINT8 flag) { + return (ccr & flag) != 0; +} + +inline static INT32 add(INT32 a, INT32 b, UINT8 &flags) { + INT32 aSign = a & SIGN_BIT_24; + INT32 bSign = b & SIGN_BIT_24; + INT32 result = a + b; + INT32 resultSign = result & SIGN_BIT_24; + bool overflow = (aSign == bSign) && (aSign != resultSign); + bool carry = result & CARRY_OUT_24; + bool negative = resultSign != 0; + bool lessThan = (overflow && !negative) || (!overflow && negative); + flags = setFlagTo(flags, FLAG_C, carry); + flags = setFlagTo(flags, FLAG_N, negative); + flags = setFlagTo(flags, FLAG_Z, result == 0); + flags = setFlagTo(flags, FLAG_V, overflow); + flags = setFlagTo(flags, FLAG_LT, lessThan); + return SC(result); +} + +inline static INT32 saturate(INT32 value, UINT8 &flags, bool negative) { + if (isFlagSet(flags, FLAG_V)) { + setFlagTo(flags, FLAG_N, negative); + return negative ? MIN_24 : MAX_24; + } else { + return value; + } +} + +inline static INT32 negate(INT32 value) { + return ((value ^ 0x00ffffff) + 1) & 0x00ffffff; +} + +inline static INT32 asl(INT32 value, int shift, UINT8 &flags) { + INT32 signBefore = value & SIGN_BIT_24; + INT32 result = value << shift; + INT32 signAfter = result & SIGN_BIT_24; + bool overflow = signBefore != signAfter; + flags = setFlagTo(flags, FLAG_V, overflow); + return saturate(result, flags, signBefore != 0); +} + +es5510_device::es5510_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) +: cpu_device(mconfig, ES5510, "ES5510", tag, owner, clock, "es5510", __FILE__) +{ + // Initialize ESP to mostly zeroed, configured for 64k samples of delay line memory, running (not halted) + halt_asserted = false; + icount = 0; + pc = 0; + state = STATE_HALTED; + memset(gpr, 0, 0xc0 * sizeof(gpr[0])); + ser0r = 0; + ser0l = 0; + ser1r = 0; + ser1l = 0; + ser2r = 0; + ser2l = 0; + ser3r = 0; + ser3l = 0; + machl = 0; + dil = 0; + memsiz = 0x00ffffff; + memmask = 0x00000000; + memincrement = 0x01000000; + memshift = 24; + dlength = 0; + abase = 0; + bbase = 0; + dbase = 0; + sigreg = 1; + mulshift = 1; + ccr = 0; + cmr = 0; + dol[0] = dol[1] = 0; + dol_count = 0; + + memset(instr, 0, 160 * sizeof(instr[0])); + memset(dram, 0, (1<<20) * sizeof(dram[0])); + + dol_latch = 0; + dil_latch = 0; + dadr_latch = 0; + gpr_latch = 0; + instr_latch = 0; + ram_sel = 0; + host_control = 0; + + pc = 0; + memset(&alu, 0, sizeof(alu)); + memset(&mulacc, 0, sizeof(mulacc)); +} + +typedef es5510_device::alu_op_t alu_op_t; +typedef es5510_device::op_select_t op_select_t; +typedef es5510_device::op_src_dst_t op_src_dst_t; + +static inline const char * REGNAME(UINT8 r) { + static char rn[8]; + if (r < 234) { sprintf(rn, "GPR_%02x", r); return rn; } + switch(r) { + case 234: return "SER0R"; + case 235: return "SER0L"; + case 236: return "SER1R"; + case 237: return "SER1L"; + case 238: return "SER2R"; + case 239: return "SER2L"; + case 240: return "SER3R"; + case 241: return "SER3L"; + case 242: return "MACL"; + case 243: return "MACH"; + case 244: return "DIL/MEMSIZ"; + case 245: return "DLENGTH"; + case 246: return "ABASE"; + case 247: return "BBASE"; + case 248: return "DBASE"; + case 249: return "SIGREG"; + case 250: return "CCR"; + case 251: return "CMR"; + case 252: return "MINUS1"; + case 253: return "MIN"; + case 254: return "MAX"; + case 255: return "ZERO"; + } + return NULL; +} + +static inline char * DESCRIBE_REG(char *s, UINT8 r, const char *name) { + if (name && *name) { + return s + sprintf(s, "%s/%s", REGNAME(r), name); + } else { + return stpcpy_int(s, REGNAME(r)); + } + + // never executed + //return 0; +} + +const alu_op_t es5510_device::ALU_OPS[16] = { + { 2, "ADD" }, + { 2, "SUB" }, + { 2, "ADDU" }, + { 2, "SUBU" }, + { 2, "CMP" }, + { 2, "AND" }, + { 2, "OR" }, + { 2, "XOR" }, + { 1, "ABS" }, + { 1, "MOV" }, + { 1, "ASL2" }, + { 1, "ASL8" }, + { 1, "LS15" }, + { 1, "DIFF" }, + { 1, "ASR" }, + { 0, "END" }, +}; + +// The CMP operation is not affected by being skippable +#define OP_CMP (4) + +const op_select_t es5510_device::OPERAND_SELECT[16] = { + { es5510_device::SRC_DST_REG, es5510_device::SRC_DST_REG, es5510_device::SRC_DST_REG, es5510_device::SRC_DST_REG }, + { es5510_device::SRC_DST_REG, es5510_device::SRC_DST_REG, es5510_device::SRC_DST_REG, es5510_device::SRC_DST_DELAY }, + { es5510_device::SRC_DST_REG, es5510_device::SRC_DST_REG, es5510_device::SRC_DST_REG, es5510_device::SRC_DST_BOTH }, + { es5510_device::SRC_DST_REG, es5510_device::SRC_DST_REG, es5510_device::SRC_DST_DELAY, es5510_device::SRC_DST_REG }, + { es5510_device::SRC_DST_REG, es5510_device::SRC_DST_REG, es5510_device::SRC_DST_DELAY, es5510_device::SRC_DST_BOTH }, + { es5510_device::SRC_DST_REG, es5510_device::SRC_DST_DELAY, es5510_device::SRC_DST_REG, es5510_device::SRC_DST_REG }, + { es5510_device::SRC_DST_REG, es5510_device::SRC_DST_DELAY, es5510_device::SRC_DST_DELAY, es5510_device::SRC_DST_REG }, + { es5510_device::SRC_DST_REG, es5510_device::SRC_DST_BOTH, es5510_device::SRC_DST_REG, es5510_device::SRC_DST_REG }, + { es5510_device::SRC_DST_REG, es5510_device::SRC_DST_BOTH, es5510_device::SRC_DST_DELAY, es5510_device::SRC_DST_REG }, + { es5510_device::SRC_DST_DELAY, es5510_device::SRC_DST_REG, es5510_device::SRC_DST_REG, es5510_device::SRC_DST_REG }, + { es5510_device::SRC_DST_DELAY, es5510_device::SRC_DST_REG, es5510_device::SRC_DST_REG, es5510_device::SRC_DST_DELAY }, + { es5510_device::SRC_DST_DELAY, es5510_device::SRC_DST_REG, es5510_device::SRC_DST_REG, es5510_device::SRC_DST_BOTH }, + { es5510_device::SRC_DST_DELAY, es5510_device::SRC_DST_REG, es5510_device::SRC_DST_DELAY, es5510_device::SRC_DST_REG }, + { es5510_device::SRC_DST_DELAY, es5510_device::SRC_DST_REG, es5510_device::SRC_DST_DELAY, es5510_device::SRC_DST_BOTH }, + { es5510_device::SRC_DST_DELAY, es5510_device::SRC_DST_BOTH, es5510_device::SRC_DST_REG, es5510_device::SRC_DST_REG }, + { es5510_device::SRC_DST_DELAY, es5510_device::SRC_DST_BOTH, es5510_device::SRC_DST_DELAY, es5510_device::SRC_DST_REG }, +}; + +static inline char * DESCRIBE_SRC_DST(char *s, UINT8 reg, const char *regname, op_src_dst_t src_dst) { + switch (src_dst) { + case es5510_device::SRC_DST_REG: + return DESCRIBE_REG(s, reg, regname); + case es5510_device::SRC_DST_DELAY: + return stpcpy_int(s, "Delay"); + case es5510_device::SRC_DST_BOTH: + s = DESCRIBE_REG(s, reg, regname); + return stpcpy_int(s, ",Delay"); + } + // should never happen! + return s; +} + +const es5510_device::ram_control_t es5510_device::RAM_CONTROL[8] = { + { es5510_device::RAM_CYCLE_READ, es5510_device::RAM_CONTROL_DELAY, "Read Delay+%06x" }, + { es5510_device::RAM_CYCLE_WRITE, es5510_device::RAM_CONTROL_DELAY, "Write Delay+%06x" }, + { es5510_device::RAM_CYCLE_READ, es5510_device::RAM_CONTROL_TABLE_A, "Read Table A+%06x" }, + { es5510_device::RAM_CYCLE_WRITE, es5510_device::RAM_CONTROL_TABLE_A, "Write Table A+%06x" }, + { es5510_device::RAM_CYCLE_READ, es5510_device::RAM_CONTROL_TABLE_B, "Read Table B+%06x" }, + { es5510_device::RAM_CYCLE_DUMP_FIFO, es5510_device::RAM_CONTROL_DELAY, "Read Delay+%06x and Dump FIFO" }, + { es5510_device::RAM_CYCLE_READ, es5510_device::RAM_CONTROL_IO, "Read from I/O at %06x" }, + { es5510_device::RAM_CYCLE_WRITE, es5510_device::RAM_CONTROL_IO, "Write to I/O at %06x" }, +}; + +static inline char * DESCRIBE_RAM(char *s, UINT8 ramControl, UINT32 gprContents) { + return s + sprintf(s, es5510_device::RAM_CONTROL[ramControl].description, SC(gprContents)); +} + +static inline char * DESCRIBE_ALU(char *s, UINT8 opcode, UINT8 aReg, const char *aName, UINT8 bReg, const char *bName, const op_select_t &opSelect) { + const alu_op_t &op = es5510_device::ALU_OPS[opcode]; + + switch (op.operands) { + case 0: + return stpcpy_int(s, op.opcode); + + case 1: + s += sprintf(s, "%s ", op.opcode); + s = DESCRIBE_SRC_DST(s, bReg, bName, opSelect.alu_src); + s += sprintf(s, " >"); + return DESCRIBE_SRC_DST(s, aReg, aName, opSelect.alu_dst); + + case 2: + s += sprintf(s, "%s ", op.opcode); + s = DESCRIBE_SRC_DST(s, aReg, aName, opSelect.alu_src); + s += sprintf(s, " "); + s = DESCRIBE_REG(s, bReg, bName); + s += sprintf(s, " >"); + return DESCRIBE_SRC_DST(s, aReg, aName, opSelect.alu_dst); + } + return s; +} + +static inline char * DESCRIBE_MAC(char *s, UINT8 mac, UINT8 cReg, const char *cName, UINT8 dReg, const char *dName, const op_select_t &opSelect) +{ + if (mac) + { + s += sprintf(s, "MAC + "); + } + s = DESCRIBE_SRC_DST(s, cReg, cName, opSelect.mac_src); + s += sprintf(s, " * "); + s = DESCRIBE_REG(s, dReg, dName); + s += sprintf(s, " >"); + return DESCRIBE_SRC_DST(s, cReg, cName, opSelect.mac_dst); +} + +static inline char * DESCRIBE_INSTR(char *s, UINT64 instr, UINT32 gpr, const char *aName, const char *bName, const char *cName, const char *dName) +{ + UINT8 dReg = (UINT8)((instr >> 40) & 0xff); + UINT8 cReg = (UINT8)((instr >> 32) & 0xff); + UINT8 bReg = (UINT8)((instr >> 24) & 0xff); + UINT8 aReg = (UINT8)((instr >> 16) & 0xff); + UINT8 aluOpcode = (UINT8)((instr >> 12) & 0x0f); + UINT8 operandSelect = (UINT8)((instr >> 8) & 0x0f); + UINT8 skip = (UINT8)((instr >> 7) & 0x01); + UINT8 mac = (UINT8)((instr >> 6) & 0x01); + UINT8 ramControl = (UINT8)((instr >> 3) & 0x07); + + const op_select_t &opSelect = es5510_device::OPERAND_SELECT[operandSelect]; + + s = DESCRIBE_ALU(s, aluOpcode, aReg, aName, bReg, bName, opSelect); + s += sprintf(s, "; "); + s = DESCRIBE_MAC(s, mac, cReg, cName, dReg, dName, opSelect); + s += sprintf(s, "; "); + s = DESCRIBE_RAM(s, ramControl, gpr); + if (skip) { + s += sprintf(s, "; skippable"); + } + + return s; +} + + +READ8_MEMBER(es5510_device::host_r) +{ + // printf("%06x: DSP read offset %04x (data is %04x)\n",space.device().safe_pc(),offset,dsp_ram[offset]); + + // VFX hack + if (core_stricmp(space.machine().system().name, "vfx") == 0) + { + if (space.device().safe_pc() == 0xc091f0) + { + return space.device().state().state_int(M68K_D2); + } + } + + switch(offset) + { + case 0x00: LOG(("ES5510: Host Read GPR latch[2]: %02x\n", (gpr_latch >> 16) & 0xff)); return (gpr_latch >> 16) & 0xff; + case 0x01: LOG(("ES5510: Host Read GPR latch[1]: %02x\n", (gpr_latch >> 8) & 0xff)); return (gpr_latch >> 8) & 0xff; + case 0x02: LOG(("ES5510: Host Read GPR latch[0]: %02x\n", (gpr_latch >> 0) & 0xff)); return (gpr_latch >> 0) & 0xff; + + case 0x03: LOG(("ES5510: Host Read INSTR latch[5]: %02x\n", (UINT8)((instr_latch >> 40) & 0xff))); return (instr_latch >> 40) & 0xff; + case 0x04: LOG(("ES5510: Host Read INSTR latch[4]: %02x\n", (UINT8)((instr_latch >> 32) & 0xff))); return (instr_latch >> 32) & 0xff; + case 0x05: LOG(("ES5510: Host Read INSTR latch[3]: %02x\n", (UINT8)((instr_latch >> 24) & 0xff))); return (instr_latch >> 24) & 0xff; + case 0x06: LOG(("ES5510: Host Read INSTR latch[2]: %02x\n", (UINT8)((instr_latch >> 16) & 0xff))); return (instr_latch >> 16) & 0xff; + case 0x07: LOG(("ES5510: Host Read INSTR latch[1]: %02x\n", (UINT8)((instr_latch >> 8) & 0xff))); return (instr_latch >> 8) & 0xff; + case 0x08: LOG(("ES5510: Host Read INSTR latch[0]: %02x\n", (UINT8)((instr_latch >> 0) & 0xff))); return (instr_latch >> 0) & 0xff; + + case 0x09: LOG(("ES5510: Host Read DIL latch[2]: %02x\n", (dil_latch >> 16) & 0xff)); return (dil_latch >> 16) & 0xff; + case 0x0a: LOG(("ES5510: Host Read DIL latch[1]: %02x\n", (dil_latch >> 8) & 0xff)); return (dil_latch >> 8) & 0xff; + case 0x0b: LOG(("ES5510: Host Read DIL latch[0]: %02x\n", 0)); return 0; + + case 0x0c: LOG(("ES5510: Host Read DOL latch[2]: %02x\n", (dol_latch >> 16) & 0xff)); return (dol_latch >> 16) & 0xff; + case 0x0d: LOG(("ES5510: Host Read DOL latch[1]: %02x\n", (dol_latch >> 8) & 0xff)); return (dol_latch >> 8) & 0xff; + case 0x0e: LOG(("ES5510: Host Read DOL latch[0]: %02x\n", 0xff)); return 0xff; + + case 0x0f: LOG(("ES5510: Host Read DADR latch[2]: %02x\n", (dadr_latch >> 16) & 0xff)); return (dadr_latch >> 16) & 0xff; + case 0x10: LOG(("ES5510: Host Read DADR latch[1]: %02x\n", (dadr_latch >> 8) & 0xff)); return (dadr_latch >> 8) & 0xff; + case 0x11: LOG(("ES5510: Host Read DADR latch[0]: %02x\n", (dadr_latch >> 0) & 0xff)); return (dadr_latch >> 0) & 0xff; + + case 0x12: LOG(("ES5510: Host Reading Host Control\n")); return 0; // Host Control + + case 0x16: return 0x27; // Program Counter, for test purposes only + } + + // default: 0. + return 0x00; +} + +WRITE8_MEMBER(es5510_device::host_w) +{ +#if VERBOSE + static char buf[1024]; +#endif + switch (offset) { + case 0x00: + gpr_latch = (gpr_latch&0x00ffff) | ((data&0xff)<<16); + LOG(("ES5510: Host Write GPR latch[2] = %02x -> %06x (%d)\n", data, gpr_latch, SX(gpr_latch))); + break; + case 0x01: + gpr_latch = (gpr_latch&0xff00ff) | ((data&0xff)<< 8); + LOG(("ES5510: Host Write GPR latch[1] = %02x -> %06x (%d)\n", data, gpr_latch, SX(gpr_latch))); + break; + case 0x02: + gpr_latch = (gpr_latch&0xffff00) | ((data&0xff)<< 0); + LOG(("ES5510: Host Write GPR latch[0] = %02x -> %06x (%d)\n", data, gpr_latch, SX(gpr_latch))); + break; + + /* 0x03 to 0x08 INSTR Register */ + case 0x03: instr_latch = ((instr_latch&U64(0x00ffffffffff)) | ((INT64)data&0xff)<<40); LOG(("ES5510: Host Write INSTR latch[5] = %02x -> %012" I64FMT "x\n", data, instr_latch)); break; + case 0x04: instr_latch = ((instr_latch&U64(0xff00ffffffff)) | ((INT64)data&0xff)<<32); LOG(("ES5510: Host Write INSTR latch[4] = %02x -> %012" I64FMT "x\n", data, instr_latch)); break; + case 0x05: instr_latch = ((instr_latch&U64(0xffff00ffffff)) | ((INT64)data&0xff)<<24); LOG(("ES5510: Host Write INSTR latch[3] = %02x -> %012" I64FMT "x\n", data, instr_latch)); break; + case 0x06: instr_latch = ((instr_latch&U64(0xffffff00ffff)) | ((INT64)data&0xff)<<16); LOG(("ES5510: Host Write INSTR latch[2] = %02x -> %012" I64FMT "x\n", data, instr_latch)); break; + case 0x07: instr_latch = ((instr_latch&U64(0xffffffff00ff)) | ((INT64)data&0xff)<< 8); LOG(("ES5510: Host Write INSTR latch[1] = %02x -> %012" I64FMT "x\n", data, instr_latch)); break; + case 0x08: instr_latch = ((instr_latch&U64(0xffffffffff00)) | ((INT64)data&0xff)<< 0); LOG(("ES5510: Host Write INSTR latch[0] = %02x -> %012" I64FMT "x\n", data, instr_latch)); break; + + /* 0x09 to 0x0b DIL Register (r/o) */ + + case 0x0c: dol_latch = (dol_latch&0x00ffff) | ((data&0xff)<<16); LOG(("ES5510: Host Write DOL latch[2] = %02x -> %06x (%d)\n", data, dol_latch, SX(dol_latch))); break; + case 0x0d: dol_latch = (dol_latch&0xff00ff) | ((data&0xff)<< 8); LOG(("ES5510: Host Write DOL latch[1] = %02x -> %06x (%d)\n", data, dol_latch, SX(dol_latch))); break; + case 0x0e: dol_latch = (dol_latch&0xffff00) | ((data&0xff)<< 0); LOG(("ES5510: Host Write DOL latch[0] = %02x -> %06x (%d)\n", data, dol_latch, SX(dol_latch))); break; //TODO: docs says that this always returns 0xff + + case 0x0f: + dadr_latch = (dadr_latch&0x00ffff) | ((data&0xff)<<16); + if (ram_sel) + { + dil_latch = dram[dadr_latch] << 8; + } + else + { + dram[dadr_latch] = dol_latch >> 8; + } + break; + + case 0x10: dadr_latch = (dadr_latch&0xff00ff) | ((data&0xff)<< 8); break; + case 0x11: dadr_latch = (dadr_latch&0xffff00) | ((data&0xff)<< 0); break; + + /* 0x12 Host Control */ + + case 0x14: ram_sel = data & 0x80; /* bit 6 is i/o select, everything else is undefined */break; + + /* 0x16 Program Counter (test purpose, r/o?) */ + /* 0x17 Internal Refresh counter (test purpose) */ + /* 0x18 Host Serial Control */ + case 0x18: + LOG(("ES5510: Host Write Host Serial control %02x: %s, %s, ser3 %s, ser2 %s, ser1 %s, ser0 %s\n", data, + data&0x80 ? "Master" : "Slave", + data&0x40 ? "Sony" : "I2S", + data & 0x20 ? "Out" : "In", + data & 0x10 ? "Out" : "In", + data & 0x08 ? "Out" : "In", + data & 0x04 ? "Out" : "In")); + break; + + /* 0x1f Halt enable (w) / Frame Counter (r) */ + case 0x1F: + LOG(("ES5510: Host Write Halt Enable %02x; HALT line is %d\n", data, halt_asserted)); + if (halt_asserted) { + LOG(("ES5510: Host Write to Halt Enable while HALT line is asserted: Halting!\n")); + state = STATE_HALTED; + } + break; + + case 0x80: /* Read select - GPR + INSTR */ + LOG(("ES5510: Host Read INSTR+GPR %02x (%s): %012" I64FMT "x %06x (%d)\n", data, REGNAME(data & 0xff), instr[data] & U64(0xffffffffffff), gpr[data] & 0xffffff, gpr[data])); + + /* Check if an INSTR address is selected */ + if (data < 0xa0) { + instr_latch = instr[data]; + } + if (data < 0xc0) { + gpr_latch = gpr[data] & 0xffffff; + } else if (data >= 0xea) { + gpr_latch = read_reg(data); + } + break; + + case 0xa0: /* Write select - GPR */ + LOG(("ES5510: Host Write GPR %02x (%s): %06x (%d)\n", data, REGNAME(data&0xff), gpr_latch, SX(gpr_latch))); + write_reg(data, gpr_latch); + break; + + case 0xc0: /* Write select - INSTR */ +#if VERBOSE + DESCRIBE_INSTR(buf, instr_latch, gpr[data], NULL, NULL, NULL, NULL); + LOG(("ES5510: Host Write INSTR %02x %012" I64FMT "x: %s\n", data, instr_latch&U64(0xffffffffffff), buf)); +#endif + if (data < 0xa0) { + instr[data] = instr_latch&U64(0xffffffffffff); + } + break; + + case 0xe0: /* Write select - GPR + INSTR */ +#if VERBOSE + DESCRIBE_INSTR(buf, instr_latch, gpr_latch, NULL, NULL, NULL, NULL); + LOG(("ES5510: Host Write INSTR+GPR %02x (%s): %012" I64FMT "x %06x (%d): %s\n", data, REGNAME(data&0xff), instr_latch, gpr_latch, SX(gpr_latch), buf)); +#endif + if (data < 0xa0) { + instr[data] = instr_latch; + } + write_reg(data, gpr_latch); + break; + } +} + +INT16 es5510_device::ser_r(int offset) +{ + switch(offset) + { + case 0: return ser0l; + case 1: return ser0r; + case 2: return ser1l; + case 3: return ser1r; + case 4: return ser2l; + case 5: return ser2r; + case 6: return ser3l; + case 7: return ser3r; + } + return 0; +} + +void es5510_device::ser_w(int offset, INT16 data) +{ + switch(offset) + { + case 0: ser0l = data; break; + case 1: ser0r = data; break; + case 2: ser1l = data; break; + case 3: ser1r = data; break; + case 4: ser2l = data; break; + case 5: ser2r = data; break; + case 6: ser3l = data; break; + case 7: ser3r = data; break; + } +} + +void es5510_device::device_start() { + m_icountptr = &icount; + state_add(STATE_GENPC,"GENPC", pc).noshow(); +} + +void es5510_device::device_reset() { + pc = 0x00; + memset(gpr, 0, sizeof(*gpr) * 0xc0); + memset(instr, 0, sizeof(*instr) * 0xa0); + memset(dram, 0, sizeof(*dram) * (1<<20)); + state = STATE_RUNNING; + dil_latch = dol_latch = dadr_latch = gpr_latch = 0; + instr_latch = UINT64(0); + ram_sel = 0; + host_control = 0; + memset(&ram, 0, sizeof(ram_t)); + memset(&ram_p, 0, sizeof(ram_t)); + memset(&ram_pp, 0, sizeof(ram_t)); +} + +const address_space_config *es5510_device::memory_space_config(address_spacenum spacenum) const { + return 0; +} + +UINT64 es5510_device::execute_clocks_to_cycles(UINT64 clocks) const { + return clocks / 3; +} + +UINT64 es5510_device::execute_cycles_to_clocks(UINT64 cycles) const { + return cycles * 3; +} + +UINT32 es5510_device::execute_min_cycles() const { + return 1; +} + +UINT32 es5510_device::execute_max_cycles() const { + return 1; +} + +UINT32 es5510_device::execute_input_lines() const { + return 1; +} + +void es5510_device::execute_set_input(int linenum, int state) { + if (linenum == ES5510_HALT) { + halt_asserted = (state == ASSERT_LINE); + } +} + +void es5510_device::list_program(void(p)(const char *, ...)) { + LOG(("ES5501: Starting!\n")); + + char buf[1024]; + bool is_written[0x100], is_read[0x100]; + char name[0x100][16]; + int addr; + + for (int i = 0; i < 0x100; i++) { + is_written[i] = is_read[i] = false; + name[i][0] = '\0'; + } + + for (addr = 0; addr < 0xa0; addr++) { + DESCRIBE_INSTR(buf, instr[addr], gpr[addr], NULL, NULL, NULL, NULL); + UINT64 inst = instr[addr]; + UINT8 aReg = (UINT8)((inst >> 16) & 0xff); + UINT8 bReg = (UINT8)((inst >> 24) & 0xff); + UINT8 cReg = (UINT8)((inst >> 32) & 0xff); + UINT8 dReg = (UINT8)((inst >> 40) & 0xff); + UINT8 alu_op = (inst >> 12) & 0x0f; + if (alu_op == 0x0f) { + // END! + break; + } + + UINT8 operandSelect = (UINT8)((inst >> 8) & 0x0f); + const op_select_t &opSelect = OPERAND_SELECT[operandSelect]; + + if (opSelect.mac_src == SRC_DST_REG) { + is_read[cReg] = true; + } + is_read[dReg] = true; + if (opSelect.mac_dst != SRC_DST_DELAY) { // either REG or BOTH + is_written[cReg] = true; + } + + alu_op_t aluOp = ALU_OPS[alu_op]; + if (aluOp.operands == 1) { + if (opSelect.alu_src == SRC_DST_REG) { + is_read[bReg] = true; + } + } else if (aluOp.operands == 2) { + if (opSelect.alu_src == SRC_DST_REG) { + is_read[aReg] = true; + } + is_read[bReg] = true; + } + if (opSelect.mac_dst != SRC_DST_DELAY) { // either REG or BOTH + is_written[aReg] = true; + } + } + + int varIndex = 1; + int constIndex = 1; + for (int i = 0; i < 0xc0; i++) { + if (is_written[i]) { + // this is a variable + sprintf(name[i], "v_%03d", varIndex++); + } else if (is_read[i]) { + // this is only read, so a constant - or possibly something updated by the CPU + sprintf(name[i], "c_%03d", constIndex++); + } else { + name[i][0] = 0; + } + } + for (int i = 0xc0; i < 0x100; i++) { + name[i][0] = 0; + } + + for (addr = 0; addr < 0xa0; addr++) { + UINT8 aReg = (UINT8)((instr[addr] >> 16) & 0xff); + UINT8 bReg = (UINT8)((instr[addr] >> 24) & 0xff); + UINT8 cReg = (UINT8)((instr[addr] >> 32) & 0xff); + UINT8 dReg = (UINT8)((instr[addr] >> 40) & 0xff); + DESCRIBE_INSTR(buf, instr[addr], gpr[addr], name[aReg], name[bReg], name[cReg], name[dReg]); + p("%02x: %012" I64FMT "x %06x (%8d) %s\n", addr, instr[addr], gpr[addr]&0xffffff, SX(gpr[addr]&0xffffff), buf); + } + for (; addr < 0xc0; addr++) { + p("%02x: %06x (%d)\n", addr, gpr[addr]&0xffffff, SX(gpr[addr]&0xffffff)); + } +} + +void es5510_device::execute_run() { + while (icount > 0) { + if (state == STATE_HALTED) { + // Currently halted, sample the HALT line + if (halt_asserted) { + // remain halted + host_control |= 0x04; // Signal Host Access OK + } else { + // start from the beginning at PC 0 + state = STATE_RUNNING; + host_control &= ~0x04; // Signal Host Access not OK + pc = 0; + } + } else { + // currently running, execute one instruction. + +#if VERBOSE_EXEC + char buf[1024]; + DESCRIBE_INSTR(buf, instr[pc], gpr[pc], NULL, NULL, NULL, NULL); + LOG_EXEC(("EXECUTING %02x: %012" I64FMT "x %06x %s\n", pc, instr[pc], gpr[pc]&0xffffff, buf)); +#endif + + ram_pp = ram_p; + ram_p = ram; + + LOG_EXEC(("- T0\n")); + + // *** T0, clock high + // --- nothing to do! + + // *** T0, clock low + // --- Read instruction N + UINT64 instr = this->instr[pc]; + + // --- RAM cycle N-2 (if a Read cycle): data read from bus is stored in DIL + if (ram_pp.cycle != RAM_CYCLE_WRITE) { + if (ram_pp.io) { // read from I/O and store into DIL + dil = 0; // read_io(ram_pp.address);; + } else { // read from DRAM and store into DIL + dil = dram[ram_pp.address] << 8; + LOG_EXEC((" . RAM: read %x (%d) from address %x\n", dil, dil, ram_pp.address)); + } + } + + // --- start of RAM cycle N + ram_control_t ramControl = RAM_CONTROL[((instr >> 3) & 0x07)]; + ram.cycle = ramControl.cycle; + ram.io = ramControl.access == RAM_CONTROL_IO; + + // --- RAM cycle N: read offset N + INT32 offset = gpr[pc]; + switch(ramControl.access) { + case RAM_CONTROL_DELAY: + ram.address = (((dbase + offset) % (dlength + memincrement)) & memmask) >> memshift; + LOG_EXEC((". Ram Control: Delay, base=%x, offset=%x, length=%x => address=%x\n", dbase >> memshift, offset >> memshift, (dlength + memincrement) >> memshift, ram.address)); + break; + case RAM_CONTROL_TABLE_A: + ram.address = ((abase + offset) & memmask) >> memshift; + LOG_EXEC((". Ram Control: table A = %x, offset=%x => address=%x\n", abase >> memshift, offset >> memshift, ram.address)); + break; + case RAM_CONTROL_TABLE_B: + ram.address = ((bbase + offset) & memmask) >> memshift; + LOG_EXEC((". Ram Control: table B = %x, offset=%x => address=%x\n", bbase >> memshift, offset >> memshift, ram.address)); + break; + case RAM_CONTROL_IO: + ram.address = offset & 0x00fffff0; // mask off the low 4 bits + LOG_EXEC((". Ram Control: I/O at address=%x\n", ram.address)); + break; + } + + // *** T1, clock high + // --- Decode instruction N; + // we will do this both here and in stages as the different parts of the instruction complete & recommence. + + LOG_EXEC(("- T1.1\n")); + + UINT8 operandSelect = (UINT8)((instr >> 8) & 0x0f); + const op_select_t &opSelect = OPERAND_SELECT[operandSelect]; + bool skip; + bool skippable = (instr & (0x01 << 7)) != 0; // aka the 'SKIP' bit in the instruction word + if (skippable) { + bool skipConditionSatisfied = (ccr & cmr & FLAG_MASK) != 0; + if (isFlagSet(cmr, FLAG_NOT)) { + skipConditionSatisfied = !skipConditionSatisfied; + } + skip = skipConditionSatisfied; + LOG_EXEC((". skippable: %x vs %x => skippable = %d\n", ccr, cmr, skip)); + } else { + skip = false; + } + + // --- Write Multiplier result N-1 + LOG_EXEC((". write mulacc:\n")); + if (mulacc.write_result) { + mulacc.product = ((INT64)SX(mulacc.cValue) * (INT64)SX(mulacc.dValue)) << mulshift; + if (mulacc.accumulate) { + mulacc.result = mulacc.product + machl; + } else { + mulacc.result = mulacc.product; + } + + if (mulacc.result < MIN_48 || mulacc.result > MAX_48) { + mac_overflow = true; + } else { + mac_overflow = false; + } +#if VERBOSE_EXEC + if (mulacc.cValue || mulacc.dValue || (mulacc.accumulate && machl)) { + LOG_EXEC((". mulacc: %x (%d) * %x (%d) << %d", SX(mulacc.cValue), SX(mulacc.cValue), SX(mulacc.dValue), SX(mulacc.dValue), mulshift)); + if (mulacc.accumulate) LOG_EXEC((" + %llx (%lld) ", machl, machl)); + LOG_EXEC((" = %llx (%lld)", mulacc.result, mulacc.result)); + if (mac_overflow) { + LOG_EXEC((" overflow!\n")); + } else { + LOG_EXEC(("\n")); + } + } +#endif + machl = mulacc.result; + INT32 tmp = mac_overflow ? (machl < 0 ? MIN_24 : MAX_24) : (mulacc.result & U64(0x0000ffffff000000)) >> 24; + if (mulacc.dst & SRC_DST_REG) { + write_reg(mulacc.cReg, tmp); + } + if (mulacc.dst & SRC_DST_DELAY) { + write_to_dol(tmp); + } + } + + // *** T1, clock low + + LOG_EXEC(("- T1.0\n")); + + // --- Start of multiplier cycle N + LOG_EXEC((". start mulacc:\n")); + mulacc.cReg = (UINT8)((instr >> 32) & 0xff); + mulacc.dReg = (UINT8)((instr >> 40) & 0xff); + mulacc.src = opSelect.mac_src; + mulacc.dst = opSelect.mac_dst; + mulacc.accumulate = ((instr >> 6) & 0x01) != 0; + mulacc.write_result = !skip; + + // --- Read Multiplier Operands N + if (mulacc.src == SRC_DST_REG) { + mulacc.cValue = read_reg(mulacc.cReg); + } else { // must be SRC_DST_DELAY + LOG_EXEC((" . reading %x (%d) from dil\n", dil, SX(dil))); + mulacc.cValue = dil; + } + mulacc.dValue = read_reg(mulacc.dReg); + + // *** T2, clock high + + LOG_EXEC(("- T2.1\n")); + + // --- Write ALU Result N-1 + LOG_EXEC((". write ALU:\n")); + if (alu.write_result) { + UINT8 flags = ccr; + alu.result = alu_operation(alu.op, alu.aValue, alu.bValue, flags); + if (alu.dst & SRC_DST_REG) { + write_reg(alu.aReg, alu.result); + } + if (alu.dst & SRC_DST_DELAY) { + write_to_dol(alu.result); + } + if (alu.update_ccr) { + ccr = flags; + } + } + + // *** T2, clock low + + LOG_EXEC(("- T2.0\n")); + + // --- Start of ALU cycle N + LOG_EXEC((". start ALU:\n")); + alu.aReg = (instr >> 16) & 0xff; + alu.bReg = (instr >> 24) & 0xff; + alu.op = (instr >> 12) & 0x0f; + alu.src = opSelect.alu_src; + alu.dst = opSelect.alu_dst; + alu.write_result = !skip; + alu.update_ccr = !skippable || (alu.op == OP_CMP); + + if (alu.op == 0xF) { + alu_operation_end(); + } else { + // --- Read ALU Operands N + alu_op_t aluOp = ALU_OPS[alu.op]; + if (aluOp.operands == 1) { + if (alu.src == SRC_DST_REG) { + alu.bValue = read_reg(alu.bReg); + } else { // must be SRC_DST_DELAY + alu.bValue = dil; + } + } else { + if (alu.src == SRC_DST_REG) { + alu.aValue = read_reg(alu.aReg); + } else { // must be SRC_DST_DELAY + alu.aValue = dil; + } + alu.bValue = read_reg(alu.bReg); + } + } + + // --- RAM cycle N-1 + if (ram_p.cycle != RAM_CYCLE_READ) { + if (ram_p.cycle == RAM_CYCLE_WRITE) { + // If this is a write cycle, write the frontmost DOL value to RAM or I/O + if (ram_p.io) { + // write_io(ram_p.io, dol[0]); + } else { + dram[ram_p.address] = dol[0] >> 8; + LOG_EXEC((" . RAM: writing %x (%d) [of %x (%d)] to address %x\n", dol[0]&0xffff00, SX(dol[0]&0xffff00), dol[0], SX(dol[0]), ram_p.address)); + } + } + // If this is a Write or Dump cycle, eject the frontmost DL value. +#if VERBOSE_EXEC + LOG_EXEC((" . ejecting from DOL: [ ")); + if (dol_count >= 1) LOG_EXEC(("{ %x (%d) }", dol[0], SX(dol[0]))); + if (dol_count == 2) LOG_EXEC((", { %x (%d) }", dol[1], SX(dol[1]))); + LOG_EXEC((" ] -> [ ")); +#endif + dol[0] = dol[1]; + if (dol_count > 0) { + --dol_count; + } +#if VERBOSE_EXEC + if (dol_count >= 1) LOG_EXEC(("{ %x (%d) }", dol[0], SX(dol[0]))); + if (dol_count == 2) LOG_EXEC((", { %x (%d) }", dol[1], SX(dol[1]))); + LOG_EXEC((" ]\n")); +#endif + } + + ++pc; + } + --icount; + } +} + +UINT32 es5510_device::disasm_min_opcode_bytes() const +{ + return 6; +} + +UINT32 es5510_device::disasm_max_opcode_bytes() const +{ + return 6; +} + +offs_t es5510_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + return pc; +} + +#if VERBOSE_EXEC +#define RETURN_GPR(r, x) do { INT32 v = (x); LOG_EXEC((" . reading %x (%d) from gpr_%02x\n", v, SX(v), r)); return v; } while(0) +#define RETURN(r, x) do { INT32 v = (x); LOG_EXEC((" . reading %x (%d) from " #r "\n", v, SX(v))); return v; } while(0) +#define RETURN16(r, x) do { INT16 vv = (x); INT32 v = vv << 8; LOG_EXEC((" . reading %x (%d) as %x (%d) from " #r "\n", vv, vv, v, SX(v))); return v; } while(0) +#else +#define RETURN_GPR(r, x) return x +#define RETURN(r, x) return x +#define RETURN16(r, x) return (x) << 8 +#endif + +INT32 es5510_device::read_reg(UINT8 reg) +{ + if (reg < 0xc0) { + RETURN_GPR(reg, gpr[reg]); + } else { + switch(reg) + { + case 234: RETURN16(ser0r, ser0r); + case 235: RETURN16(ser0l, ser0l); + case 236: RETURN16(ser1r, ser1r); + case 237: RETURN16(ser1l, ser1l); + case 238: RETURN16(ser2r, ser2r); + case 239: RETURN16(ser2l, ser2l); + case 240: RETURN16(ser3r, ser3r); + case 241: RETURN16(ser3l, ser3l); + case 242: /* macl */ RETURN(macl, mac_overflow ? (machl < 0 ? 0x00ffffff : 0x00000000) : (machl >> 0) & 0x00ffffff); + case 243: /* mach */ RETURN(mach, mac_overflow ? (machl < 0 ? MIN_24 : MAX_24) : (machl >> 24) & 0x00ffffff); + case 244: RETURN(dil, dil); // DIL when reading + case 245: RETURN(dlength, dlength); + case 246: RETURN(abase, abase); + case 247: RETURN(bbase, bbase); + case 248: RETURN(dbase, dbase); + case 249: RETURN(sigreg, sigreg); + case 250: RETURN(ccr, ccr); + case 251: RETURN(cmr, cmr); + case 252: RETURN(minus_one, 0x00ffffff); + case 253: RETURN(min, MIN_24); + case 254: RETURN(max, MAX_24); + case 255: RETURN(zero, 0); + default: + // unknown SPR + RETURN(unknown, 0); + } + } +} + +void es5510_device::run_once() +{ + // turn HALT off + set_HALT(false); + + // run for one instruction + icount = 1; + execute_run(); + + // turn HALT on again + set_HALT(true); + + // run ESP to the end of its program, a few instructions at a time + while (state != STATE_HALTED) { + icount = 1; + execute_run(); + } +} + +INT8 countLowOnes(INT32 x) { + INT8 n = 0; + while ((x & 1) == 1) { + ++n; + x >>= 1; + } + return n; +} + +#if VERBOSE_EXEC +#define WRITE_REG(r, x) do { r = value; LOG_EXEC((" . writing %x (%d) to " #r "\n", r, SX(r))); } while(0) +#define WRITE_REG16(r, x) do { r = ((value >> 8) & 0xffff); LOG_EXEC((" . writing %x (%d) as %x (%d) to " #r "\n", value, SX(value), r, r)); } while(0) +#else +#define WRITE_REG(r, x) do { r = value; } while(0) +#define WRITE_REG16(r, x) do { r = ((value >> 8) & 0xffff); } while(0) +#endif + +void es5510_device::write_reg(UINT8 reg, INT32 value) +{ + #if VERBOSE_EXEC + INT64 old; + #endif + value &= 0x00ffffff; + if (reg < 0xc0) { + LOG_EXEC((" . writing %x (%d) to gpr_%02x\n", value, SX(value), reg)); + gpr[reg] = value; + } else { + switch(reg) + { + case 234: WRITE_REG16(ser0r, value); + break; + case 235: WRITE_REG16(ser0l, value); + break; + case 236: WRITE_REG16(ser1r, value); + break; + case 237: WRITE_REG16(ser1l, value); + break; + case 238: WRITE_REG16(ser2r, value); + break; + case 239: WRITE_REG16(ser2l, value); + break; + case 240: WRITE_REG16(ser3r, value); + break; + case 241: WRITE_REG16(ser3l, value); + break; + case 242: /* macl */ { + #if VERBOSE_EXEC + old = machl; + #endif + INT64 masked = machl & (S64(0x00ffffff) << 24); + INT64 shifted = (INT64)(value & 0x00ffffff) << 0; + machl = SX64(masked | shifted); + #if VERBOSE_EXEC + LOG_EXEC((" . writing machl: l -> %06x => %llx -> %llx\n", value, old, machl)); + #endif + break; + } + case 243: /* mach */ { + #if VERBOSE_EXEC + old = machl; + #endif + INT64 masked = machl & (S64(0x00ffffff) << 0); + INT64 shifted = (INT64)(value & 0x00ffffff) << 24; + machl = SX64(masked | shifted); + mac_overflow = false; + #if VERBOSE_EXEC + LOG_EXEC((" . writing machl: h -> %06x => %llx -> %llx\n", value, old, machl)); + #endif + break; + } + case 244: /* MEMSIZ when writing */ + memshift = countLowOnes(value); + memsiz = 0x00ffffff >> (24 - memshift); + memmask = 0x00ffffff & ~memsiz; + memincrement = 1 << memshift; + LOG_EXEC((" . writing %x (%d) to memsiz => memsiz=%x, shift=%d, mask=%x, increment=%x\n", value, SX(value), memsiz, memshift, memmask, memincrement)); + break; + case 245: WRITE_REG(dlength, value); + break; + case 246: WRITE_REG(abase, value); + break; + case 247: WRITE_REG(bbase, value); + break; + case 248: WRITE_REG(dbase, value); + break; + case 249: WRITE_REG(sigreg, (value != 0)); + break; + case 250: WRITE_REG(ccr, (value >> 16) & FLAG_MASK); + break; + case 251: WRITE_REG(cmr, (value >> 16) & (FLAG_MASK | FLAG_NOT)); + break; + case 252: LOG_EXEC((". not writing %x (%d) to minus_one\n", value, SX(value))); // no-op + break; + case 253: LOG_EXEC((". not writing %x (%d) to min\n", value, SX(value))); // no-op + break; + case 254: LOG_EXEC((". not writing %x (%d) to max\n", value, SX(value))); // no-op + break; + case 255: LOG_EXEC((". not writing %x (%d) to zero\n", value, SX(value))); // no-op + break; + default: // unknown register + break; + } + } +} + +void es5510_device::write_to_dol(INT32 value) { +#if VERBOSE_EXEC + LOG_EXEC((". writing %x (%d) to DOL: [ ", value, value)); + if (dol_count >= 1) LOG_EXEC(("{ %x (%d) }", dol[0], SX(dol[0]))); + if (dol_count == 2) LOG_EXEC((", { %x (%d) }", dol[1], SX(dol[1]))); + LOG_EXEC((" ] -> [ ")); +#endif + if (dol_count >= 2) { + dol[0] = dol[1]; + dol[1] = value; + } else { + dol[dol_count++] = value; + } +#if VERBOSE_EXEC + LOG_EXEC(("{%x (%d)}", dol[0], SX(dol[0]))); + if (dol_count == 2) LOG_EXEC((", {%x (%d)}", dol[1], SX(dol[1]))); + LOG_EXEC((" ]\n")); +#endif +} + +void es5510_device::alu_operation_end() { + // Handle the END instruction separately + LOG_EXEC(("ES5510: END\n")); + // sample the HALT line + if (halt_asserted) { + // halt + state = STATE_HALTED; + host_control |= 0x04; // Signal Host Access OK + } + // update the delay line base pointer + dbase -= memincrement; + if (dbase < 0) { + dbase = dlength; + } + // Possibly reset the PC + if (state == STATE_RUNNING) { + pc = 0; + } + +#if VERBOSE_EXEC + // update the verbose-execution counter. + exec_cc = (exec_cc + 1) % 30000; +#endif +} + +INT32 es5510_device::alu_operation(UINT8 op, INT32 a, INT32 b, UINT8 &flags) { + INT32 tmp; + switch(op) { + case 0x0: // ADD + tmp = add(a, b, flags); + return saturate(tmp, flags, (a & 0x00800000) != 0); + + case 0x1: // SUB + tmp = add(a, negate(b), flags); + return saturate(tmp, flags, (a & 0x00800000) != 0); + + case 0x2: // ADDU + return add(a, b, flags); + + case 0x3: // SUBU + return add(a, negate(b), flags); + + case 0x4: // CMP + // perform the subtraction, only for its effect on the flags + add(a, negate(b), flags); + return a; + + case 0x5: // AND + a &= b; + setFlagTo(flags, FLAG_N, (a & 0x0080000000) != 0); + setFlagTo(flags, FLAG_Z, a == 0); + return a; + + case 0x6: // OR + a |= b; + setFlagTo(flags, FLAG_N, (a & 0x0080000000) != 0); + setFlagTo(flags, FLAG_Z, a == 0); + return a; + + case 0x7: // XOR + a ^= b; + setFlagTo(flags, FLAG_N, (a & 0x0080000000) != 0); + setFlagTo(flags, FLAG_Z, a == 0); + return a; + + case 0x8: // ABS + { + clearFlag(flags, FLAG_N); + bool isNegative = (a & 0x00800000) != 0; + setFlagTo(flags, FLAG_C, isNegative); + // Note: the absolute value is calculated by one's complement! + return isNegative ? (0x00ffffff ^ a) : a; + } + + case 0x9: // MOV + return b; + + case 0xA: // ASL2 + return asl(b, 2, flags); + + case 0xB: // ASL8 + return asl(b, 8, flags); + + case 0xC: // LS15 + return (b << 15) & 0x007fffff; + + case 0xD: // DIFF + return add(0x007fffff, negate(b), flags); + + case 0xE: // ASR + return (b >> 1) | (b & 0x00800000); + + case 0xF: // END - handled separately in alu_operation_end() + default: + return 0; + } +} diff --git a/src/devices/cpu/es5510/es5510.h b/src/devices/cpu/es5510/es5510.h new file mode 100644 index 00000000000..b3e12cba119 --- /dev/null +++ b/src/devices/cpu/es5510/es5510.h @@ -0,0 +1,195 @@ +// license:BSD-3-Clause +// copyright-holders:Christian Brunschen +/********************************************************************************************** + * + * es5510.h - Ensoniq ES5510 (ESP) driver + * by Christian Brunschen + * + **********************************************************************************************/ + +#pragma once + +#ifndef __ES5510_H__ +#define __ES5510_H__ + +#include "emu.h" + +class es5510_device : public cpu_device { +public: + es5510_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + DECLARE_READ8_MEMBER(host_r); + DECLARE_WRITE8_MEMBER(host_w); + + INT16 ser_r(int offset); + void ser_w(int offset, INT16 data); + + enum line_t { + ES5510_HALT = 0 + }; + + enum state_t { + STATE_RUNNING = 0, + STATE_HALTED = 1 + }; + + struct alu_op_t { + int operands; + const char * const opcode; + }; + + enum op_src_dst_t { + SRC_DST_REG = 1 << 0, + SRC_DST_DELAY = 1 << 1, + SRC_DST_BOTH = (1 << 0) | (1 << 1) + }; + + struct op_select_t { + const op_src_dst_t alu_src; + const op_src_dst_t alu_dst; + const op_src_dst_t mac_src; + const op_src_dst_t mac_dst; + }; + + enum ram_control_access_t { + RAM_CONTROL_DELAY = 0, + RAM_CONTROL_TABLE_A, + RAM_CONTROL_TABLE_B, + RAM_CONTROL_IO + }; + + enum ram_cycle_t { + RAM_CYCLE_READ = 0, + RAM_CYCLE_WRITE = 1, + RAM_CYCLE_DUMP_FIFO = 2 + }; + + struct ram_control_t { + ram_cycle_t cycle; + ram_control_access_t access; + const char * const description; + }; + + static const alu_op_t ALU_OPS[16]; + static const op_select_t OPERAND_SELECT[16]; + static const ram_control_t RAM_CONTROL[8]; + + struct alu_t { + UINT8 aReg; + UINT8 bReg; + op_src_dst_t src; + op_src_dst_t dst; + UINT8 op; + INT32 aValue; + INT32 bValue; + INT32 result; + bool update_ccr; + bool write_result; + }; + + struct mulacc_t { + UINT8 cReg; + UINT8 dReg; + op_src_dst_t src; + op_src_dst_t dst; + bool accumulate; + INT32 cValue; + INT32 dValue; + INT64 product; + INT64 result; + bool write_result; + }; + + struct ram_t { + INT32 address; // up to 20 bits, left-justified within the right 24 bits of the 32-bit word + bool io; // I/O space, rather than delay line memory + ram_cycle_t cycle; // cycle type + }; + + // direct access to the 'HALT' pin - not just through the + void set_HALT(bool halt) { halt_asserted = halt; } + bool get_HALT() { return halt_asserted; } + + void run_once(); + void list_program(void(p)(const char *, ...)); + + // for testing purposes + UINT64 &_instr(int pc) { return instr[pc % 160]; } + INT16 &_dram(int addr) { return dram[addr & 0xfffff]; } + + // publicly visible for testing purposes + INT32 read_reg(UINT8 reg); + void write_reg(UINT8 reg, INT32 value); + void write_to_dol(INT32 value); + +protected: + virtual void device_start(); + virtual void device_reset(); + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const; + virtual UINT64 execute_clocks_to_cycles(UINT64 clocks) const; + virtual UINT64 execute_cycles_to_clocks(UINT64 cycles) const; + virtual UINT32 execute_min_cycles() const; + virtual UINT32 execute_max_cycles() const; + virtual UINT32 execute_input_lines() const; + virtual void execute_run(); + virtual UINT32 disasm_min_opcode_bytes() const; + virtual UINT32 disasm_max_opcode_bytes() const; + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + virtual void execute_set_input(int linenum, int state); + + INT32 alu_operation(UINT8 op, INT32 aValue, INT32 bValue, UINT8 &flags); + void alu_operation_end(); + +private: + int icount; + bool halt_asserted; + UINT8 pc; + state_t state; + INT32 gpr[0xc0]; // 24 bits, right justified + INT16 ser0r; + INT16 ser0l; + INT16 ser1r; + INT16 ser1l; + INT16 ser2r; + INT16 ser2l; + INT16 ser3r; + INT16 ser3l; + INT64 machl; // 48 bits, right justified and sign extended + bool mac_overflow; // whether reading the MAC register should return a saturated replacement value + INT32 dil; + INT32 memsiz; + INT32 memmask; + INT32 memincrement; + INT8 memshift; + INT32 dlength; + INT32 abase; + INT32 bbase; + INT32 dbase; + INT32 sigreg; + int mulshift; + INT8 ccr; // really, 5 bits, left justified + INT8 cmr; // really, 6 bits, left justified + INT32 dol[2]; + int dol_count; + + UINT64 instr[160]; // 48 bits, right justified + INT16 dram[1<<20]; // there are up to 20 address bits (at least 16 expected), left justified within the 24 bits of a gpr or dadr; we preallocate all of it. + + // latch registers for host interaction + INT32 dol_latch; // 24 bits + INT32 dil_latch; // 24 bits + UINT32 dadr_latch; // 24 bits + INT32 gpr_latch; // 24 bits, holding up to 20 address bits, left justified + UINT64 instr_latch; // 48 bits, right justified + UINT8 ram_sel; // effectively a boolean + UINT8 host_control; // + + // currently executing instruction(s) + alu_t alu; + mulacc_t mulacc; + ram_t ram, ram_p, ram_pp; // ram operations for cycles N, N-1 and N-2 +}; + +extern const device_type ES5510; + +#endif // __ES5510_H__ diff --git a/src/devices/cpu/esrip/esrip.c b/src/devices/cpu/esrip/esrip.c new file mode 100644 index 00000000000..fa7ab139b08 --- /dev/null +++ b/src/devices/cpu/esrip/esrip.c @@ -0,0 +1,1985 @@ +// license:BSD-3-Clause +// copyright-holders:Philip Bennett +/*************************************************************************** + + esrip.c + + Implementation of the Entertainment Sciences + AM29116-based Real Time Image Processor + +***************************************************************************/ + +#include "emu.h" +#include "debugger.h" +#include "esrip.h" + + +/*************************************************************************** + CONSTANTS +***************************************************************************/ + +#define IPT_RAM_SIZE (8192 * sizeof(UINT16)) + + +/*************************************************************************** + MACROS +***************************************************************************/ + +#define RIP_PC (m_pc | ((m_status_out & 1) << 8)) +#define _BIT(x, n) ((x) & (1 << (n))) +#define RISING_EDGE(old_val, new_val, bit) (!(old_val & (1 << bit)) && (new_val & (1 << bit))) + +#define UNHANDLED do {printf("%s:UNHANDLED (%x)\n", __FUNCTION__, inst); assert(0);} while (0) +#define INVALID do {printf("%s:INVALID (%x)\n", __FUNCTION__, inst); assert(0);} while (0) + +#define RAM_ADDR (inst & 0x1f) +#define MODE (inst & 0x8000) +#define WORD_MODE (inst & 0x8000) +#define BYTE_MODE (!WORD_MODE) +#define N ((inst >> 9) & 0xf) +#define OPCODE ((inst >> 5) & 0xf) +#define SRC ((inst >> 9) & 0xf) +#define DST (inst & 0x1f) // TEST + +#define BW_WORD (1 << 15) +#define BW_BYTE (0 << 15) + +#define FLAG_3 (1 << 7) +#define FLAG_2 (1 << 6) +#define FLAG_1 (1 << 5) +#define L_FLAG (1 << 4) +#define V_FLAG (1 << 3) +#define N_FLAG (1 << 2) +#define C_FLAG (1 << 1) +#define Z_FLAG (1 << 0) + +#define CLEAR_FLAGS(a) (m_new_status &= ~(a)) +#define SET_FLAGS(a) (m_new_status |= (a)) + + +/*************************************************************************** + STRUCTURES & TYPEDEFS +***************************************************************************/ + +/*************************************************************************** + PUBLIC FUNCTIONS +***************************************************************************/ + +UINT8 esrip_device::get_rip_status() +{ + return m_status_out; +} + + +/*************************************************************************** + INITIALIZATION AND SHUTDOWN +***************************************************************************/ + +enum ops +{ + ROTR1, TOR1, ROTR2, ROTC, ROTM, BOR2, CRCF, CRCR, + SVSTR, PRT, SOR, TOR2, SHFTR, TEST, NOP, SETST, RSTST, + ROTNR, BONR, BOR1, SONR, SHFTNR, PRTNR, TONR +}; + +void esrip_device::make_ops() +{ + int inst; + + for (inst = 0; inst < 65536; ++inst) + { + int quad = (inst >> 13) & 3; + + if (quad == 0) + { + if (((inst >> 5) & 0xc) == 0xc) + m_optable[inst] = ROTR1; + else + m_optable[inst] = TOR1; + } + else if (quad == 1) + { + if (OPCODE < 2) + m_optable[inst] = ROTR2; + else if (OPCODE < 6) + m_optable[inst] = ROTC; + else + m_optable[inst] = ROTM; + } + else if (quad == 2) + { + if (OPCODE > 11) + m_optable[inst] = BOR2; + else + { + int tmp = (inst >> 5) & 0xff; + + if (tmp == 0x63) + m_optable[inst] = CRCF; + else if (tmp == 0x69) + m_optable[inst] = CRCR; + else if (tmp == 0x7a) + m_optable[inst] = SVSTR; + else + { + if ((SRC > 7) && (SRC < 12)) + m_optable[inst] = PRT; + else if (SRC > 11) + m_optable[inst] = SOR; + else if (SRC < 6) + m_optable[inst] = TOR2; + else + m_optable[inst] = SHFTR; + } + } + } + else + { + if (inst == 0x7140) + m_optable[inst] = NOP; + else + { + int x = (inst & 0xffe0); + if (x == 0x7340) + m_optable[inst] = TEST; + else if (x == 0x7740) + m_optable[inst] = SETST; + else if (x == 0x7540) + m_optable[inst] = RSTST; + else + { + int op = OPCODE; + if (op == 0xc) + { + if ((inst & 0x18) == 0x18) + m_optable[inst] = ROTNR; + else + m_optable[inst] = BONR; + } + else if ((op & 0xc) == 0xc) + m_optable[inst] = BOR1; + else + { + int src = SRC; + + if ((src & 0xc) == 0xc) + m_optable[inst] = SONR; + else if ((src & 0x6) == 0x6) + m_optable[inst] = SHFTNR; + else if (src & 0x8) + m_optable[inst] = PRTNR; + else + m_optable[inst] = TONR; + } + } + } + } + } +} + +void esrip_device::device_start() +{ + /* Register configuration structure callbacks */ + m_fdt_r.resolve_safe(0); + m_fdt_w.resolve_safe(); + m_lbrm = (UINT8*)machine().root_device().memregion(m_lbrm_prom)->base(); + m_status_in.resolve_safe(0); + m_draw.bind_relative_to(*owner()); + + /* Allocate image pointer table RAM */ + m_ipt_ram.resize(IPT_RAM_SIZE/2); + + m_program = &space(AS_PROGRAM); + m_direct = &m_program->direct(); + + // register our state for the debugger + std::string tempstr; + state_add(STATE_GENPC, "GENPC", m_rip_pc).noshow(); + state_add(STATE_GENFLAGS, "GENFLAGS", m_status).callimport().callexport().formatstr("%8s").noshow(); + state_add(ESRIP_PC, "PC:", m_rip_pc).mask(0xffff); + state_add(ESRIP_ACC, "ACC:", m_acc).mask(0xffff); + state_add(ESRIP_DLATCH, "DLATCH:", m_d_latch).mask(0xff); + state_add(ESRIP_ILATCH, "ILATCH:", m_i_latch).mask(0xffff); + state_add(ESRIP_RAM00, "RAM[00]:", m_ram[0x00]).mask(0xffff); + state_add(ESRIP_RAM01, "RAM[01]:", m_ram[0x01]).mask(0xffff); + state_add(ESRIP_RAM02, "RAM[02]:", m_ram[0x02]).mask(0xffff); + state_add(ESRIP_RAM03, "RAM[03]:", m_ram[0x03]).mask(0xffff); + state_add(ESRIP_RAM04, "RAM[04]:", m_ram[0x04]).mask(0xffff); + state_add(ESRIP_RAM05, "RAM[05]:", m_ram[0x05]).mask(0xffff); + state_add(ESRIP_RAM06, "RAM[06]:", m_ram[0x06]).mask(0xffff); + state_add(ESRIP_RAM07, "RAM[07]:", m_ram[0x07]).mask(0xffff); + state_add(ESRIP_RAM08, "RAM[08]:", m_ram[0x08]).mask(0xffff); + state_add(ESRIP_RAM09, "RAM[09]:", m_ram[0x09]).mask(0xffff); + state_add(ESRIP_RAM0A, "RAM[0A]:", m_ram[0x0a]).mask(0xffff); + state_add(ESRIP_RAM0B, "RAM[0B]:", m_ram[0x0b]).mask(0xffff); + state_add(ESRIP_RAM0C, "RAM[0C]:", m_ram[0x0c]).mask(0xffff); + state_add(ESRIP_RAM0D, "RAM[0D]:", m_ram[0x0d]).mask(0xffff); + state_add(ESRIP_RAM0E, "RAM[0E]:", m_ram[0x0e]).mask(0xffff); + state_add(ESRIP_RAM0F, "RAM[0F]:", m_ram[0x0f]).mask(0xffff); + state_add(ESRIP_RAM10, "RAM[10]:", m_ram[0x10]).mask(0xffff); + state_add(ESRIP_RAM11, "RAM[11]:", m_ram[0x11]).mask(0xffff); + state_add(ESRIP_RAM12, "RAM[12]:", m_ram[0x12]).mask(0xffff); + state_add(ESRIP_RAM13, "RAM[13]:", m_ram[0x13]).mask(0xffff); + state_add(ESRIP_RAM14, "RAM[14]:", m_ram[0x14]).mask(0xffff); + state_add(ESRIP_RAM15, "RAM[15]:", m_ram[0x15]).mask(0xffff); + state_add(ESRIP_RAM16, "RAM[16]:", m_ram[0x16]).mask(0xffff); + state_add(ESRIP_RAM17, "RAM[17]:", m_ram[0x17]).mask(0xffff); + state_add(ESRIP_RAM18, "RAM[18]:", m_ram[0x18]).mask(0xffff); + state_add(ESRIP_RAM19, "RAM[19]:", m_ram[0x19]).mask(0xffff); + state_add(ESRIP_RAM1A, "RAM[1A]:", m_ram[0x1a]).mask(0xffff); + state_add(ESRIP_RAM1B, "RAM[1B]:", m_ram[0x1b]).mask(0xffff); + state_add(ESRIP_RAM1C, "RAM[1C]:", m_ram[0x1c]).mask(0xffff); + state_add(ESRIP_RAM1D, "RAM[1D]:", m_ram[0x1d]).mask(0xffff); + state_add(ESRIP_RAM1E, "RAM[1E]:", m_ram[0x1e]).mask(0xffff); + state_add(ESRIP_RAM1F, "RAM[1F]:", m_ram[0x1f]).mask(0xffff); + state_add(ESRIP_STATW, "STAT:", m_status_out).mask(0xffff); + state_add(ESRIP_FDTC, "FDTC:", m_fdt_cnt).mask(0xffff); + state_add(ESRIP_IPTC, "IPTC:", m_ipt_cnt).mask(0xffff); + state_add(ESRIP_XSCALE, "XSCL:", m_x_scale).mask(0xffff); + state_add(ESRIP_YSCALE, "YSCL:", m_y_scale).mask(0xffff); + state_add(ESRIP_BANK, "BANK:", m_img_bank).mask(0xffff); + state_add(ESRIP_LINE, "LINE:", m_line_latch).mask(0xffff); + state_add(ESRIP_FIG, "FIG:", m_fig_latch).mask(0xffff); + state_add(ESRIP_ATTR, "ATTR:", m_attr_latch).mask(0xffff); + state_add(ESRIP_ADRL, "ADRL:", m_adl_latch).mask(0xffff); + state_add(ESRIP_ADRR, "ADRR:", m_adr_latch).mask(0xffff); + state_add(ESRIP_COLR, "COLR:", m_c_latch).mask(0xffff); + state_add(ESRIP_IADDR, "IADR:", m_iaddr_latch).mask(0xffff); + + /* Create the instruction decode lookup table */ + make_ops(); + + /* Register stuff for state saving */ + save_item(NAME(m_acc)); + save_item(NAME(m_ram)); + save_item(NAME(m_d_latch)); + save_item(NAME(m_i_latch)); + save_item(NAME(m_result)); + save_item(NAME(m_new_status)); + save_item(NAME(m_status)); + save_item(NAME(m_inst)); + save_item(NAME(m_immflag)); + save_item(NAME(m_ct)); + save_item(NAME(m_t)); + save_item(NAME(m_l1)); + save_item(NAME(m_l2)); + save_item(NAME(m_l3)); + save_item(NAME(m_l4)); + save_item(NAME(m_l5)); + save_item(NAME(m_l6)); + save_item(NAME(m_l7)); + save_item(NAME(m_pl1)); + save_item(NAME(m_pl2)); + save_item(NAME(m_pl3)); + save_item(NAME(m_pl4)); + save_item(NAME(m_pl5)); + save_item(NAME(m_pl6)); + save_item(NAME(m_pl7)); + save_item(NAME(m_pc)); + save_item(NAME(m_status_out)); + save_item(NAME(m_x_scale)); + save_item(NAME(m_y_scale)); + save_item(NAME(m_img_bank)); + save_item(NAME(m_line_latch)); + save_item(NAME(m_fig_latch)); + save_item(NAME(m_attr_latch)); + save_item(NAME(m_adl_latch)); + save_item(NAME(m_adr_latch)); + save_item(NAME(m_iaddr_latch)); + save_item(NAME(m_c_latch)); + save_item(NAME(m_fdt_cnt)); + save_item(NAME(m_ipt_cnt)); + save_item(NAME(m_fig)); + save_item(NAME(m_fig_cycles)); + save_item(NAME(m_ipt_ram)); + + // set our instruction counter + m_icountptr = &m_icount; + m_icount = 0; +} + + +void esrip_device::device_reset() +{ + m_pc = 0; + + m_pl1 = 0xff; + m_pl2 = 0xff; + m_pl3 = 0xff; + m_pl4 = 0xff; + m_pl5 = 0xff; + m_pl6 = 0xff; + m_pl7 = 0xff; + + m_l1 = 0xff; + m_l2 = 0xff; + m_l3 = 0xff; + m_l4 = 0xff; + m_l5 = 0xff; + m_l6 = 0xff; + m_l7 = 0xff; + + m_status_out = 0; + m_immflag = 0; + + m_rip_pc = (m_pc | ((m_status_out & 1) << 8)); +} + +void esrip_device::device_stop() +{ +} + + +//------------------------------------------------- +// memory_space_config - return the configuration +// of the specified address space, or NULL if +// the space doesn't exist +//------------------------------------------------- + +const address_space_config *esrip_device::memory_space_config(address_spacenum spacenum) const +{ + if (spacenum == AS_PROGRAM) + { + return &m_program_config; + } + return NULL; +} + + +//------------------------------------------------- +// state_string_export - export state as a string +// for the debugger +//------------------------------------------------- + +void esrip_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + switch (entry.index()) + { + case STATE_GENFLAGS: + strprintf(str, "%c%c%c%c%c%c%c%c%c", + (m_status & 0x80) ? '3' : '.', + (m_status & 0x40) ? '2' : '.', + (m_status & 0x20) ? '1' : '.', + (m_status & 0x10) ? 'L' : '.', + (m_status & 0x08) ? 'V' : '.', + (m_status & 0x04) ? 'N' : '.', + (m_status & 0x02) ? 'C' : '.', + (m_status & 0x01) ? 'Z' : '.', + get_hblank() ? 'H' : '.'); + break; + } +} + + +//------------------------------------------------- +// disasm_min_opcode_bytes - return the length +// of the shortest instruction, in bytes +//------------------------------------------------- + +UINT32 esrip_device::disasm_min_opcode_bytes() const +{ + return 8; +} + + +//------------------------------------------------- +// disasm_max_opcode_bytes - return the length +// of the longest instruction, in bytes +//------------------------------------------------- + +UINT32 esrip_device::disasm_max_opcode_bytes() const +{ + return 8; +} + + +//------------------------------------------------- +// disasm_disassemble - call the disassembly +// helper function +//------------------------------------------------- + +offs_t esrip_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( esrip ); + return CPU_DISASSEMBLE_NAME(esrip)(this, buffer, pc, oprom, opram, options); +} + + +/*************************************************************************** + PRIVATE FUNCTIONS +***************************************************************************/ + +int esrip_device::get_hblank() +{ + return machine().first_screen()->hblank(); +} + +/* Return the state of the LBRM line (Y-scaling related) */ +int esrip_device::get_lbrm() +{ + int addr = ((m_y_scale & 0x3f) << 3) | ((m_line_latch >> 3) & 7); + int sel = (m_line_latch & 7); + + UINT8 val = m_lbrm[addr]; + + return (val >> sel) & 1; +} + +int esrip_device::check_jmp(UINT8 jmp_ctrl) +{ + int ret = 0; + + if (~jmp_ctrl & 0x10) + { + switch (jmp_ctrl & 7) + { + /* CT */ case 0: ret = m_ct; break; + /* T1 */ case 4: ret = BIT(m_t, 0); break; + /* T2 */ case 2: ret = BIT(m_t, 1); break; + /* T3 */ case 6: ret = BIT(m_t, 2); break; + /* T4 */ case 1: ret = BIT(m_t, 3); break; + /* /LBRM */ case 5: ret = !get_lbrm(); break; + /* /HBLANK */ case 3: ret = !get_hblank(); break; + /* JMP */ case 7: ret = 0; break; + } + + ret ^= 1; + } + else if (~jmp_ctrl & 0x08) + { + switch (jmp_ctrl & 7) + { + /* CT */ case 0: ret = m_ct; break; + /* T1 */ case 4: ret = BIT(m_t, 0); break; + /* T2 */ case 2: ret = BIT(m_t, 1); break; + /* T3 */ case 6: ret = BIT(m_t, 2); break; + /* T4 */ case 1: ret = BIT(m_t, 3); break; + /* /LBRM */ case 5: ret = !get_lbrm(); break; + /* /FIG */ case 3: ret = !m_fig; break; + /* JMP */ case 7: ret = 1; break; + } + } + else + { + assert(!"RIP: Invalid jump control"); + } + + return ret; +} + + +void esrip_device::calc_z_flag(UINT16 res) +{ + m_new_status &= ~Z_FLAG; + m_new_status |= (res == 0); +} + +void esrip_device::calc_c_flag_add(UINT16 a, UINT16 b) +{ + m_new_status &= ~C_FLAG; + m_new_status |= ((UINT16)(b) > (UINT16)(~(a))) ? 2 : 0; +} + +void esrip_device::calc_c_flag_sub(UINT16 a, UINT16 b) +{ + m_new_status &= ~C_FLAG; + m_new_status |= ((UINT16)(b) <= (UINT16)(a)) ? 2 : 0; +} + +void esrip_device::calc_n_flag(UINT16 res) +{ + m_new_status &= ~N_FLAG; + m_new_status |= (res & 0x8000) ? 4 : 0; +} + +void esrip_device::calc_v_flag_add(UINT16 a, UINT16 b, UINT32 r) +{ + m_new_status &= ~V_FLAG; + m_new_status |= ((a ^ r) & (b ^ r) & 0x8000) ? 8 : 0; +} + +void esrip_device::calc_v_flag_sub(UINT16 a, UINT16 b, UINT32 r) +{ + m_new_status &= ~V_FLAG; + m_new_status |= ((a ^ b) & (r ^ b) & 0x8000) ? 8 : 0; +} + + +/*************************************************************************** + INSTRUCTIONS +***************************************************************************/ + +enum +{ + ACC, + Y_BUS, + STATUS, + RAM +}; + +/************************************* + * + * Single operand + * + *************************************/ + +enum +{ + MOVE = 0xc, + COMP = 0xd, + INC = 0xe, + NEG = 0xf +}; + +enum +{ + SORA = 0x0, + SORY = 0x2, + SORS = 0x3, + SOAR = 0x4, + SODR = 0x6, + SOIR = 0x7, + SOZR = 0x8, + SOZER = 0x9, + SOSER = 0xa, + SORR = 0xb +}; + +UINT16 esrip_device::sor_op(UINT16 r, UINT16 opcode) +{ + UINT32 res = 0; + + switch (opcode) + { + case MOVE: + { + res = r; + CLEAR_FLAGS(V_FLAG | C_FLAG); + calc_n_flag(res); + calc_z_flag(res); + break; + } + case COMP: + { + res = r ^ 0xffff; + CLEAR_FLAGS(V_FLAG | C_FLAG); + calc_n_flag(res); + calc_z_flag(res); + break; + } + case INC: + { + res = r + 1; + calc_v_flag_add(r, 1, res); + calc_n_flag(res); + calc_c_flag_add(r, 1); + calc_z_flag(res); + break; + } + case NEG: + { + res = (r ^ 0xffff) + 1; + calc_v_flag_sub(0, r, res); + calc_n_flag(res); + calc_c_flag_sub(0, r); + calc_z_flag(res); + break; + } + default: assert(0); + } + + return res & 0xffff; +} + +void esrip_device::sor(UINT16 inst) +{ + UINT16 r = 0; + UINT16 dst = 0; + UINT16 res = 0; + + if (BYTE_MODE) + { + printf("Byte Mode! %.4x\n", inst); + UNHANDLED; + } + + switch ((inst >> 5) & 0xf) + { + case SORA: r = m_ram[RAM_ADDR]; dst = ACC; break; + case SORY: r = m_ram[RAM_ADDR]; dst = Y_BUS; break; + case SORS: r = m_ram[RAM_ADDR]; dst = STATUS; break; + case SOAR: r = m_acc; dst = RAM; break; + case SODR: r = m_d_latch; dst = RAM; break; + case SOIR: + { + if (m_immflag == 0) // Macrofiy this? + { + m_i_latch = inst; + m_immflag = 1; + return; + } + else + { + r = m_inst; + dst = RAM; + m_immflag = 0; + } + break; + } + case SOZR: r = 0; dst = RAM; break; + case SORR: r = m_ram[RAM_ADDR]; dst = RAM; break; + default: UNHANDLED; + } + + /* Operation */ + res = sor_op(r, (inst >> 9) & 0xf); + + switch (dst) + { + case Y_BUS: break; + case ACC: m_acc = res; break; + case RAM: m_ram[RAM_ADDR] = res; break; + default: UNHANDLED; + } + + m_result = res; +} + +enum +{ + SOA = 0x4, + SOD = 0x6, + SOI = 0x7, + SOZ = 0x8, + SOZE = 0x9, + SOSE = 0xa +}; + +enum +{ + NRY = 0, + NRA = 1, + NRS = 4, + NRAS = 5 +}; + +void esrip_device::sonr(UINT16 inst) +{ + UINT16 r = 0; + UINT16 res = 0; + + switch ((inst >> 5) & 0xf) + { + case SOA: r = m_acc; break; + case SOD: r = m_d_latch; break; + case SOI: + { + if (m_immflag == 0) + { + m_i_latch = inst; + m_immflag = 1; + return; + } + else + { + r = m_inst; + m_immflag = 0; + } + break; + } + case SOZ: r = 0; break; + default: INVALID; + } + + /* Operation */ + res = sor_op(r, (inst >> 9) & 0xf); + + /* Destination */ + switch (inst & 0x1f) + { + case NRY: break; + case NRA: m_acc = res; break; + default: UNHANDLED; + } + + m_result = res; +} + +/************************************* + * + * Two operand + * + *************************************/ + +enum +{ + SUBR = 0x0, + SUBRC = 0x1, + SUBS = 0x2, + SUBSC = 0x3, + ADD = 0x4, + ADDC = 0x5, + AND = 0x6, + NAND = 0x7, + EXOR = 0x8, + NOR = 0x9, + OR = 0xa, + EXNOR = 0xb +}; + +UINT16 esrip_device::tor_op(UINT16 r, UINT16 s, int opcode) +{ + UINT32 res = 0; + + switch (opcode) + { + case SUBR: + { + res = s - r; + calc_v_flag_sub(s, r, res); + calc_n_flag(res); + calc_c_flag_sub(s, r); + calc_z_flag(res); + break; + } + case SUBRC: assert(0); break; + case SUBS: + { + res = r - s; + calc_v_flag_sub(r, s, res); + calc_n_flag(res); + calc_c_flag_sub(r, s); + calc_z_flag(res); + break; + } + case SUBSC: assert(0); break; + case ADD: + { + res = r + s; + calc_v_flag_add(r, s, res); + calc_n_flag(res); + calc_c_flag_add(r, s); + calc_z_flag(res); + break; + } + case ADDC: + { + // TODO TODO CHECK ME ETC + res = r + s + ((m_status >> 1) & 1); + calc_v_flag_add(r, s, res); + calc_n_flag(res); + calc_c_flag_add(r, s); + calc_z_flag(res); + break; + } + case AND: + { + res = r & s; + CLEAR_FLAGS(V_FLAG | C_FLAG); + calc_n_flag(res); + calc_z_flag(res); + break; + } + case NAND: + { + res = (r & s) ^ 0xffff; + CLEAR_FLAGS(V_FLAG | C_FLAG); + calc_n_flag(res); + calc_z_flag(res); + break; + } + case EXOR: + { + res = r ^ s; + CLEAR_FLAGS(V_FLAG | C_FLAG); + calc_n_flag(res); + calc_z_flag(res); + break; + } + case NOR: + { + res = (r | s) ^ 0xffff; + CLEAR_FLAGS(V_FLAG | C_FLAG); + calc_n_flag(res); + calc_z_flag(res); + break; + } + case OR: + { + res = r | s; + CLEAR_FLAGS(V_FLAG | C_FLAG); + calc_n_flag(res); + calc_z_flag(res); + break; + } + case EXNOR: + { + res = (r ^ s) ^ 0xffff; + CLEAR_FLAGS(V_FLAG | N_FLAG | C_FLAG); + calc_z_flag(res); + break; + } + default: assert(0); + } + + return res & 0xffff; +} + +void esrip_device::tor1(UINT16 inst) +{ + UINT16 r = 0; + UINT16 s = 0; + UINT16 dst = 0; + UINT16 res = 0; + + enum + { + TORAA = 0x0, + TORIA = 0x2, + TODRA = 0x3, + TORAY = 0x8, + TORIY = 0xa, + TODRY = 0xb, + TORAR = 0xc, + TORIR = 0xe, + TODRR = 0xf + }; + + switch (SRC) + { + case TORAA: r = m_ram[RAM_ADDR]; s = m_acc; dst = ACC; break; + case TORIA: + { + if (m_immflag == 0) + { + m_i_latch = inst; + m_immflag = 1; + return; + } + else + { + r = m_ram[RAM_ADDR]; + s = m_inst; + dst = ACC; + m_immflag = 0; + } + break; + } + case TODRA: r = m_d_latch; s = m_ram[RAM_ADDR]; dst = ACC; break; + case TORAY: r = m_ram[RAM_ADDR]; s = m_acc; dst = Y_BUS;break; + case TORIY: + { + if (m_immflag == 0) + { + m_i_latch = inst; + m_immflag = 1; + return; + } + else + { + r = m_ram[RAM_ADDR]; + s = m_inst; + dst = Y_BUS; + m_immflag = 0; + } + break; + } + case TODRY: r = m_d_latch; s = m_ram[RAM_ADDR]; dst = Y_BUS;break; + case TORAR: r = m_ram[RAM_ADDR]; s = m_acc; dst = RAM; break; + case TORIR: + { + if (m_immflag == 0) + { + m_i_latch = inst; + m_immflag = 1; + return; + } + else + { + r = m_ram[RAM_ADDR]; + s = m_inst; + dst = RAM; + m_immflag = 0; + } + break; + } + case TODRR: r = m_d_latch; s = m_ram[RAM_ADDR]; dst = RAM; break; + default: INVALID; + } + + /* Operation */ + res = tor_op(r, s, (inst >> 5) & 0xf); + + /* Destination */ + switch (dst) + { + case ACC: m_acc = res; break; + case Y_BUS: break; + case RAM: m_ram[RAM_ADDR] = res; break; + default: INVALID; + } + + m_result = res; +} + +void esrip_device::tor2(UINT16 inst) +{ + UINT16 r = 0; + UINT16 s = 0; + UINT32 res = 0; + + enum + { + TODAR = 0x1, + TOAIR = 0x2, + TODIR = 0x5 + }; + + switch (SRC) + { + case TODAR: r = m_d_latch; s = m_acc; break; + case TOAIR: + { + if (m_immflag == 0) + { + m_i_latch = inst; + m_immflag = 1; + return; + } + else + { + r = m_acc; + s = m_inst; + m_immflag = 0; + } + break; + } + case TODIR: + { + if (m_immflag == 0) + { + m_i_latch = inst; + m_immflag = 1; + return; + } + else + { + r = m_d_latch; + s = m_inst; + m_immflag = 0; + } + break; + } + default: INVALID; + } + + /* Operation */ + res = tor_op(r, s, (inst >> 5) & 0xf); + + /* Destination is always RAM */ + m_ram[RAM_ADDR] = res; + + m_result = res; +} + +void esrip_device::tonr(UINT16 inst) +{ + enum + { + TODA = 0x1, + TOAI = 0x2, + TODI = 0x5 + }; + + UINT16 r = 0; + UINT16 s = 0; + UINT16 res = 0; + + switch (SRC) + { + case TODA: + { + r = m_d_latch; + s = m_acc; + break; + } + case TOAI: + { + break; + } + case TODI: + { + if (m_immflag == 0) + { + m_i_latch = inst; + m_immflag = 1; + return; + } + else + { + r = m_d_latch; + s = m_inst; + m_immflag = 0; + } + break; + } + default: INVALID; + } + + /* Operation */ + res = tor_op(r, s, (inst >> 5) & 0xf); + + /* Destination */ + switch (DST) + { + case NRY: + break; + case NRA: + m_acc = res; + break; + case NRS: + UNHANDLED; + break; + case NRAS: + UNHANDLED; + break; + default: + INVALID; + } + m_result = res; +} + +/************************************* + * + * Bit operation + * + *************************************/ + +void esrip_device::bonr(UINT16 inst) +{ + enum + { + TSTNA = 0x00, + RSTNA = 0x01, + SETNA = 0x02, + A2NA = 0x04, + S2NA = 0x05, + LD2NA = 0x06, + LDC2NA = 0x07, + TSTND = 0x10, + RSTND = 0x11, + SETND = 0x12, + A2NDY = 0x14, + S2NDY = 0x15, + LD2NY = 0x16, + LDC2NY = 0x17 + }; + + UINT16 res = 0; + + switch (inst & 0x1f) + { + case TSTNA: + { + res = m_acc & (1 << N); + CLEAR_FLAGS(V_FLAG | C_FLAG); + calc_n_flag(res); + calc_z_flag(res); + break; + } + case RSTNA: + { + res = m_acc & ~(1 << N); + CLEAR_FLAGS(V_FLAG | C_FLAG); + calc_n_flag(res); + calc_z_flag(res); + m_acc = res; + break; + } + case SETNA: + { + res = m_acc | (1 << N); + CLEAR_FLAGS(V_FLAG | C_FLAG | Z_FLAG); + calc_n_flag(res); + m_acc = res; + break; + } + case A2NA: + { + UINT16 r = m_acc; + UINT16 s = 1 << N; + res = r + s; + calc_z_flag(res); + calc_n_flag(res); + calc_c_flag_add(r, s); + calc_v_flag_add(r, s, res); + m_acc = res; + break; + } + case S2NA: + { + UINT16 r = m_acc; + UINT16 s = 1 << N; + res = r - s; + calc_z_flag(res); + calc_n_flag(res); + calc_c_flag_sub(r, s); + calc_v_flag_sub(r, s, res); + m_acc = res; + break; + } + + case TSTND: + { + res = m_d_latch & (1 << N); + CLEAR_FLAGS(V_FLAG | C_FLAG); + calc_n_flag(res); + calc_z_flag(res); + break; + } + + case SETND: + { + UINT16 r = m_d_latch; + res = r | (1 << N); + m_d_latch = res; + + CLEAR_FLAGS(V_FLAG | C_FLAG | Z_FLAG); + calc_n_flag(res); + break; + } + case LD2NY: + { + res = (1 << N); + CLEAR_FLAGS(V_FLAG | C_FLAG | Z_FLAG); + calc_n_flag(res); + break; + } + case LDC2NY: + { + res = (1 << N) ^ 0xffff; + CLEAR_FLAGS(Z_FLAG | C_FLAG | V_FLAG); + calc_n_flag(res); + break; + } + + case A2NDY: + { + UINT16 r = m_d_latch; + UINT16 s = 1 << N; + res = r + s; + + calc_z_flag(res); + calc_n_flag(res); + calc_c_flag_add(r, s); + calc_v_flag_add(r, s, res); + break; + } + + default: + UNHANDLED; + } + + m_result = res; +} + +void esrip_device::bor1(UINT16 inst) +{ + enum + { + SETNR = 0xd, + RSTNR = 0xe, + TSTNR = 0xf + }; + + UINT16 res = 0; + + switch ((inst >> 5) & 0xf) + { + case SETNR: + { + res = m_ram[RAM_ADDR] | (1 << N); + m_ram[RAM_ADDR] = res; + CLEAR_FLAGS(V_FLAG | C_FLAG | Z_FLAG); + calc_n_flag(res); + break; + } + case RSTNR: + { + res = m_ram[RAM_ADDR] & ~(1 << N); + m_ram[RAM_ADDR] = res; + CLEAR_FLAGS(V_FLAG | C_FLAG); + calc_n_flag(res); + calc_z_flag(res); + break; + } + case TSTNR: + { + res = m_ram[RAM_ADDR] & (1 << N); + CLEAR_FLAGS(V_FLAG | C_FLAG); + calc_n_flag(res); + calc_z_flag(res); + break; + } + default: INVALID; + } + + m_result = res; +} + +void esrip_device::bor2(UINT16 inst) +{ + enum + { + LD2NR = 0xc, + LDC2NR = 0xd, + A2NR = 0xe, + S2NR = 0xf + }; + + UINT32 res = 0; + + switch ((inst >> 5) & 0xf) + { + case LD2NR: + { + res = 1 << N; + CLEAR_FLAGS(V_FLAG | C_FLAG | Z_FLAG); + calc_n_flag(res); + break; + } + case LDC2NR: + { + res = (1 << N) ^ 0xffff; + CLEAR_FLAGS(V_FLAG | C_FLAG | Z_FLAG); + calc_n_flag(res); + break; + } + case A2NR: + { + UINT16 r = m_ram[RAM_ADDR]; + UINT16 s = 1 << N; + + res = r + s; + calc_v_flag_add(r, s, res); + calc_n_flag(res); + calc_c_flag_add(r, s); + calc_z_flag(res); + break; + } + case S2NR: + { + UINT16 r = m_ram[RAM_ADDR]; + UINT16 s = 1 << N; + + res = r - s; + calc_v_flag_sub(r, s, res); + calc_n_flag(res); + calc_c_flag_sub(r, s); + calc_z_flag(res); + break; + } + default: INVALID; + } + + /* Destination is RAM */ + m_ram[RAM_ADDR] = res; + m_result = res; +} + +/************************************* + * + * Rotate + * + *************************************/ + +/* TODO Combine these */ +void esrip_device::rotr1(UINT16 inst) +{ + enum + { + RTRA = 0xc, + RTRY = 0xd, + RTRR = 0xf + }; + + UINT16 u = 0; + UINT16 dst = 0; + UINT16 res = 0; + int n = N; + + switch ((inst >> 5) & 0xf) + { + case RTRA: u = m_ram[RAM_ADDR]; dst = ACC; break; + case RTRY: u = m_ram[RAM_ADDR]; dst = Y_BUS; break; + case RTRR: u = m_ram[RAM_ADDR]; dst = RAM; break; + default: INVALID; + } + + res = (u << n) | (u >> (16 - n)); + CLEAR_FLAGS(V_FLAG | C_FLAG); + calc_n_flag(res); + calc_z_flag(res); + + switch (dst) + { + case ACC: m_acc = res; break; + case RAM: m_ram[RAM_ADDR] = res; break; + } + + m_result = res; +} + +void esrip_device::rotr2(UINT16 inst) +{ + enum + { + RTAR = 0, + RTDR = 1 + }; + + UINT16 u = 0; + UINT16 res = 0; + + switch ((inst >> 5) & 0xf) + { + case RTAR: u = m_acc; break; + case RTDR: u = m_d_latch; break; + default: INVALID; + } + + res = (u << N) | (u >> (16 - N)); + CLEAR_FLAGS(V_FLAG | C_FLAG); + calc_n_flag(res); + calc_z_flag(res); + m_ram[RAM_ADDR] = res; + + m_result = res; +} + +void esrip_device::rotnr(UINT16 inst) +{ + enum + { + RTDY = 0x18, + RTDA = 0x19, + RTAY = 0x1c, + RTAA = 0x1d + }; + + UINT16 u = 0; + UINT16 res = 0; + UINT16 dst = 0; + + switch (inst & 0x1f) + { + case RTDY: u = m_d_latch; dst = Y_BUS; break; + case RTDA: u = m_d_latch; dst = ACC; break; + case RTAY: u = m_acc; dst = Y_BUS; break; + case RTAA: u = m_acc; dst = ACC; break; + default: INVALID; + } + + res = (u << N) | (u >> (16 - N)); + CLEAR_FLAGS(V_FLAG | C_FLAG); + calc_n_flag(res); + calc_z_flag(res); + + switch (dst) + { + case Y_BUS: break; + case ACC: m_acc = res; break; + case RAM: m_ram[RAM_ADDR] = res; break; + default: UNHANDLED; + } + + m_result = res; +} + +/************************************* + * + * Rotate and compare + * + *************************************/ + +void esrip_device::rotc(UINT16 inst) +{ + UNHANDLED; +} + +/************************************* + * + * Rotate and merge + * + *************************************/ + +void esrip_device::rotm(UINT16 inst) +{ + UNHANDLED; +} + +/************************************* + * + * Prioritize + * + *************************************/ + +void esrip_device::prt(UINT16 inst) +{ + UNHANDLED; +} + +void esrip_device::prtnr(UINT16 inst) +{ + UNHANDLED; +} + + +/************************************* + * + * CRC + * + *************************************/ + +void esrip_device::crcf(UINT16 inst) +{ + UNHANDLED; +} + +void esrip_device::crcr(UINT16 inst) +{ + UNHANDLED; +} + +/************************************* + * + * Single bit shift + * + *************************************/ + +enum +{ + SHUPZ = 0, + SHUP1 = 1, + SHUPL = 2, + SHDNZ = 4, + SHDN1 = 5, + SHDNL = 6, + SHDNC = 7, + SHDNOV = 8 +}; + +#define SET_LINK_flag(x) (m_new_status &= ~L_FLAG); \ + (m_new_status |= x ? L_FLAG : 0) + +UINT16 esrip_device::shift_op(UINT16 u, int opcode) +{ + UINT32 res = 0; + + switch (opcode) + { + case SHUPZ: + { + res = (u << 1); + SET_LINK_flag(u & 0x8000); + CLEAR_FLAGS(V_FLAG | C_FLAG); + calc_n_flag(res); + calc_z_flag(res); + break; + } + case SHUP1: + { + res = (u << 1) | 1; + SET_LINK_flag(u & 0x8000); + CLEAR_FLAGS(V_FLAG | C_FLAG); + calc_n_flag(res); + calc_z_flag(res); + break; + } + case SHUPL: + { + res = (u << 1) | ((m_status & L_FLAG) ? 1 : 0); + SET_LINK_flag(u & 0x8000); + CLEAR_FLAGS(V_FLAG | C_FLAG); + calc_n_flag(res); + calc_z_flag(res); + break; + } + + case SHDNZ: + case SHDN1: + case SHDNL: + case SHDNC: + case SHDNOV: + default: assert(0); + } + + return res; +} + +void esrip_device::shftr(UINT16 inst) +{ + enum + { + SHRR = 6, + SHDR = 7 + }; + + UINT16 u = 0; + UINT16 res = 0; + + switch ((inst >> 9) & 0xf) + { + case SHRR: u = m_ram[RAM_ADDR]; break; + case SHDR: u = m_d_latch; break; + default: INVALID; + } + + res = shift_op(u, (inst >> 5) & 0xf); + + /* Destination is always RAM */ + m_ram[RAM_ADDR] = res; + m_result = res; +} + +void esrip_device::shftnr(UINT16 inst) +{ + enum + { + SHA = 6, + SHD = 7 + }; + + UINT16 u = 0; + UINT16 res = 0; + + switch ((inst >> 9) & 0xf) + { + case SHA: u = m_acc; break; + case SHD: u = m_d_latch; break; + default: INVALID; + } + + res = shift_op(u, (inst >> 5) & 0xf); + + switch (DST) + { + case NRY: break; + case NRA: m_acc = res; break; + default: INVALID; + } + m_result = res; +} + + +/************************************* + * + * Status + * + *************************************/ + +void esrip_device::svstr(UINT16 inst) +{ + UNHANDLED; +} + +void esrip_device::rstst(UINT16 inst) +{ + enum + { + RONCZ = 0x3, + RL = 0x5, + RF1 = 0x6, + RF2 = 0x9, + RF3 = 0xa + }; + + switch (inst & 0x1f) + { + case RONCZ: CLEAR_FLAGS(V_FLAG | N_FLAG | C_FLAG | Z_FLAG); break; + case RL: CLEAR_FLAGS(L_FLAG); break; + case RF1: CLEAR_FLAGS(FLAG_1); break; + case RF2: CLEAR_FLAGS(FLAG_2); break; + case RF3: CLEAR_FLAGS(FLAG_3); break; + } + + m_result = 0; +} + +void esrip_device::setst(UINT16 inst) +{ + enum + { + SONCZ = 0x3, + SL = 0x5, + SF1 = 0x6, + SF2 = 0x9, + SF3 = 0xa + }; + + switch (inst & 0x1f) + { + case SONCZ: SET_FLAGS(V_FLAG | N_FLAG | C_FLAG | Z_FLAG); break; + case SL: SET_FLAGS(L_FLAG); break; + case SF1: SET_FLAGS(FLAG_1); break; + case SF2: SET_FLAGS(FLAG_2); break; + case SF3: SET_FLAGS(FLAG_3); break; + } + + m_result = 0xffff; +} + +void esrip_device::test(UINT16 inst) +{ + enum + { + TNOZ = 0x00, + TNO = 0x02, + TZ = 0x04, + TOVR = 0x06, + TLOW = 0x08, + TC = 0x0a, + TZC = 0x0c, + TN = 0x0e, + TL = 0x10, + TF1 = 0x12, + TF2 = 0x14, + TF3 = 0x16 + }; + + UINT32 res = 0; + + switch (inst & 0x1f) + { + case TNOZ: UNHANDLED; break; + case TNO: UNHANDLED; break; + case TZ: res = m_status & (Z_FLAG); break; + case TOVR: res = m_status & (V_FLAG); break; + case TLOW: UNHANDLED; break; + case TC: res = m_status & (C_FLAG); break; + case TZC: UNHANDLED; break; + case TN: res = m_status & (N_FLAG); break; + case TL: res = m_status & (L_FLAG); break; + case TF1: res = m_status & (FLAG_1); break; + case TF2: res = m_status & (FLAG_2); break; + case TF3: res = m_status & (FLAG_3); break; + default: INVALID; + } + + m_ct = res ? 1 : 0; +} + + +/************************************* + * + * No operation + * + *************************************/ + +void esrip_device::nop(UINT16 inst) +{ + m_result = 0xff; // Undefined +} + +//************************************************************************** +// DEVICE INTERFACE +//************************************************************************** + +const device_type ESRIP = &device_creator; + +//------------------------------------------------- +// esrip_device - constructor +//------------------------------------------------- + +esrip_device::esrip_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : cpu_device(mconfig, ESRIP, "ESRIP", tag, owner, clock, "esrip", __FILE__), + m_program_config("program", ENDIANNESS_BIG, 64, 9, -3), + m_fdt_r(*this), + m_fdt_w(*this), + m_status_in(*this), + m_lbrm_prom(NULL) +{ + // build the opcode table + for (int op = 0; op < 24; op++) + m_opcode[op] = s_opcodetable[op]; +} + + +//************************************************************************** +// STATIC OPCODE TABLES +//************************************************************************** + +const esrip_device::ophandler esrip_device::s_opcodetable[24] = +{ + &esrip_device::rotr1, &esrip_device::tor1, &esrip_device::rotr2, &esrip_device::rotc, + &esrip_device::rotm, &esrip_device::bor2, &esrip_device::crcf, &esrip_device::crcr, + &esrip_device::svstr, &esrip_device::prt, &esrip_device::sor, &esrip_device::tor2, + &esrip_device::shftr, &esrip_device::test, &esrip_device::nop, &esrip_device::setst, + &esrip_device::rstst, &esrip_device::rotnr, &esrip_device::bonr, &esrip_device::bor1, + &esrip_device::sonr, &esrip_device::shftnr, &esrip_device::prtnr, &esrip_device::tonr +}; + + +void esrip_device::am29116_execute(UINT16 inst, int _sre) +{ + /* Status register shadow */ + m_new_status = m_status; + + /* Required for immediate source instructions */ + m_inst = inst; + + if (m_immflag == 1) + inst = m_i_latch; + + (this->*m_opcode[m_optable[inst]])(inst); + + if (!_sre) + { + m_status = m_new_status; + m_t = m_status; + } +} + + +//------------------------------------------------- +// execute_min_cycles - return minimum number of +// cycles it takes for one instruction to execute +//------------------------------------------------- + +UINT32 esrip_device::execute_min_cycles() const +{ + return 1; +} + + +//------------------------------------------------- +// execute_max_cycles - return maximum number of +// cycles it takes for one instruction to execute +//------------------------------------------------- + +UINT32 esrip_device::execute_max_cycles() const +{ + return 1; +} + + +//------------------------------------------------- +// execute_input_lines - return the number of +// input/interrupt lines +//------------------------------------------------- + +UINT32 esrip_device::execute_input_lines() const +{ + return 0; +} + + +//------------------------------------------------- +// execute_set_input - act on a changed input/ +// interrupt line +//------------------------------------------------- + +void esrip_device::execute_set_input(int inputnum, int state) +{ +} + + +void esrip_device::execute_run() +{ + int calldebugger = (machine().debug_flags & DEBUG_FLAG_ENABLED) != 0; + UINT8 status; + + /* I think we can get away with placing this outside of the loop */ + status = m_status_in(*m_program, 0); + + /* Core execution loop */ + do + { + UINT64 inst; + UINT8 next_pc; + UINT16 x_bus = 0; + UINT16 ipt_bus = 0; + UINT16 y_bus = 0; + + int yoe = _BIT(m_l5, 1); + int bl46 = BIT(m_l4, 6); + int bl44 = BIT(m_l4, 4); + + UINT32 in_h; + UINT32 in_l; + + if (m_fig_cycles) + { + if (--m_fig_cycles == 0) + m_fig = 0; + } + + /* /OEY = 1 : Y-bus is high imped */ + if (yoe) + { + /* Status In */ + if (!_BIT(m_l2, 0)) + y_bus = status | (!m_fig << 3); + + /* FDT RAM: /Enable, Direction and /RAM OE */ + else if (!bl44 && !_BIT(m_l2, 3) && bl46) + y_bus = m_fdt_r(*m_program, m_fdt_cnt, 0xffff); + + /* IPT RAM: /Enable and /READ */ + else if (!_BIT(m_l2, 6) && !_BIT(m_l4, 5)) + y_bus = m_ipt_ram[m_ipt_cnt]; + + /* DLE - latch the value on the Y-BUS into the data latch */ + if (_BIT(m_l5, 0)) + m_d_latch = y_bus; + + /* Now execute the AM29116 instruction */ + am29116_execute((m_l7 << 8) | m_l6, BIT(m_l5, 2)); + } + else + { + am29116_execute((m_l7 << 8) | m_l6, BIT(m_l5, 2)); + + y_bus = m_result; + + if (BIT(m_l5, 0)) + m_d_latch = y_bus; + } + + /* Determine what value is on the X-Bus */ + + /* FDT RAM */ + if (!bl44) + x_bus = m_fdt_r(*m_program, m_fdt_cnt, 0xffff); + + /* Buffer is enabled - write direction */ + else if (!BIT(m_l2, 3) && !bl46) + { + if (!yoe) + x_bus = y_bus; + else if ( !BIT(m_l2, 6) && !BIT(m_l4, 5) ) + x_bus = m_ipt_ram[m_ipt_cnt]; + } + + /* IPT BUS */ + if (!BIT(m_l2, 6)) + ipt_bus = m_ipt_ram[m_ipt_cnt]; + else if (!BIT(m_l4, 5)) + { + if (!BIT(m_l5, 1)) + ipt_bus = y_bus; + else + ipt_bus = x_bus; + } + + + /* Write FDT RAM: /Enable, Direction and WRITE */ + if (!BIT(m_l2, 3) && !bl46 && !BIT(m_l4, 3)) + m_fdt_w(*m_program, m_fdt_cnt, x_bus, 0xffff); + + /* Write IPT RAM: /Enable and /WR */ + if (!BIT(m_l2, 7) && !BIT(m_l4, 5)) + m_ipt_ram[m_ipt_cnt] = ipt_bus; + + + if ((((m_l5 >> 3) & 0x1f) & 0x18) != 0x18) + { + if ( check_jmp((m_l5 >> 3) & 0x1f) ) + next_pc = m_l1; + else + next_pc = m_pc + 1; + } + else + next_pc = m_pc + 1; + + m_pl1 = m_l1; + m_pl2 = m_l2; + m_pl3 = m_l3; + m_pl4 = m_l4; + m_pl5 = m_l5; + m_pl6 = m_l6; + m_pl7 = m_l7; + + /* Latch instruction */ + inst = m_direct->read_qword(RIP_PC << 3); + + in_h = inst >> 32; + in_l = inst & 0xffffffff; + + m_l1 = (in_l >> 8); + m_l2 = (in_l >> 16); + m_l3 = (in_l >> 24); + + m_l4 = (in_h >> 0); + m_l5 = (in_h >> 8); + m_l6 = (in_h >> 16); + m_l7 = (in_h >> 24); + + /* Colour latch */ + if (RISING_EDGE(m_pl3, m_l3, 0)) + m_c_latch = (x_bus >> 12) & 0xf; + + /* Right pixel line buffer address */ + if (RISING_EDGE(m_pl3, m_l3, 1)) + m_adr_latch = x_bus & 0xfff; + + /* Left pixel line buffer address */ + if (RISING_EDGE(m_pl3, m_l3, 2)) + m_adl_latch = x_bus & 0xfff; + + /* FIGLD: Start the DMA */ + if (RISING_EDGE(m_pl3, m_l3, 3)) + { + m_attr_latch = x_bus; + + m_fig = 1; + m_fig_cycles = m_draw(m_adl_latch, m_adr_latch, m_fig_latch, m_attr_latch, m_iaddr_latch, m_c_latch, m_x_scale, m_img_bank); + } + + /* X-scale */ + if (RISING_EDGE(m_pl3, m_l3, 4)) + m_x_scale = x_bus >> 8; + + /* Y-scale and image bank */ + if (RISING_EDGE(m_pl4, m_l4, 2)) + { + m_y_scale = x_bus & 0xff; + m_img_bank = (y_bus >> 14) & 3; + } + + /* Image ROM address */ + if (RISING_EDGE(m_pl3, m_l3, 5)) + m_iaddr_latch = y_bus; + + /* IXLLD */ + if (RISING_EDGE(m_pl3, m_l3, 6)) + { + m_line_latch = ipt_bus >> 10; + m_fig_latch = ipt_bus & 0x3ff; + } + + /* Status write */ + if (RISING_EDGE(m_pl3, m_l3, 7)) + m_status_out = y_bus & 0xff; + + /* FDT address counter */ + if (!BIT(m_pl2, 1)) + m_fdt_cnt = y_bus & 0xfff; + else if (BIT(m_pl2, 2)) + m_fdt_cnt = (m_fdt_cnt + 1) & 0xfff; + + /* Now we can alter the IPT address counter */ + if (!BIT(m_pl2, 4)) + m_ipt_cnt = y_bus & 0x1fff; + else if (BIT(m_pl2, 5)) + m_ipt_cnt = (m_ipt_cnt + 1) & 0x1fff; + + if (calldebugger) + debugger_instruction_hook(this, RIP_PC); + + m_pc = next_pc; + m_rip_pc = (m_pc | ((m_status_out & 1) << 8)); + + m_icount--; + } while (m_icount > 0); +} diff --git a/src/devices/cpu/esrip/esrip.h b/src/devices/cpu/esrip/esrip.h new file mode 100644 index 00000000000..ecfba10975d --- /dev/null +++ b/src/devices/cpu/esrip/esrip.h @@ -0,0 +1,283 @@ +// license:BSD-3-Clause +// copyright-holders:Philip Bennett +/*************************************************************************** + + esrip.h + Interface file for the Entertainment Sciences RIP + Written by Phil Bennett + +***************************************************************************/ + +#ifndef _ESRIP_H +#define _ESRIP_H + +#include "emu.h" + +/*************************************************************************** + COMPILE-TIME DEFINITIONS +***************************************************************************/ + + +/*************************************************************************** + GLOBAL CONSTANTS +***************************************************************************/ + +/*************************************************************************** + INTERFACE CONFIGURATION MACROS +***************************************************************************/ +#define ESRIP_DRAW(name) int name(int l, int r, int fig, int attr, int addr, int col, int x_scale, int bank) + +#define MCFG_ESRIP_FDT_R_CALLBACK(_read) \ + devcb = &esrip_device::static_set_fdt_r_callback(*device, DEVCB_##_read); + +#define MCFG_ESRIP_FDT_W_CALLBACK(_write) \ + devcb = &esrip_device::static_set_fdt_w_callback(*device, DEVCB_##_write); + +#define MCFG_ESRIP_STATUS_IN_CALLBACK(_read) \ + devcb = &esrip_device::static_set_status_in_callback(*device, DEVCB_##_read); + +#define MCFG_ESRIP_DRAW_CALLBACK_OWNER(_class, _method) \ + esrip_device::static_set_draw_callback(*device, esrip_draw_delegate(&_class::_method, #_class "::" #_method, downcast<_class *>(owner))); + +#define MCFG_ESRIP_LBRM_PROM(_tag) \ + esrip_device::static_lbrm_prom(*device, _tag); + + +/*************************************************************************** + REGISTER ENUMERATION +***************************************************************************/ + +enum +{ + ESRIP_PC = 1, + ESRIP_ACC, + ESRIP_DLATCH, + ESRIP_ILATCH, + ESRIP_RAM00, + ESRIP_RAM01, + ESRIP_RAM02, + ESRIP_RAM03, + ESRIP_RAM04, + ESRIP_RAM05, + ESRIP_RAM06, + ESRIP_RAM07, + ESRIP_RAM08, + ESRIP_RAM09, + ESRIP_RAM0A, + ESRIP_RAM0B, + ESRIP_RAM0C, + ESRIP_RAM0D, + ESRIP_RAM0E, + ESRIP_RAM0F, + ESRIP_RAM10, + ESRIP_RAM11, + ESRIP_RAM12, + ESRIP_RAM13, + ESRIP_RAM14, + ESRIP_RAM15, + ESRIP_RAM16, + ESRIP_RAM17, + ESRIP_RAM18, + ESRIP_RAM19, + ESRIP_RAM1A, + ESRIP_RAM1B, + ESRIP_RAM1C, + ESRIP_RAM1D, + ESRIP_RAM1E, + ESRIP_RAM1F, + ESRIP_STATW, + ESRIP_FDTC, + ESRIP_IPTC, + ESRIP_XSCALE, + ESRIP_YSCALE, + ESRIP_BANK, + ESRIP_LINE, + ESRIP_FIG, + ESRIP_ATTR, + ESRIP_ADRL, + ESRIP_ADRR, + ESRIP_COLR, + ESRIP_IADDR +}; + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** +typedef device_delegate esrip_draw_delegate; + +// device type definition +extern const device_type ESRIP; + +// ======================> esrip_device + +// Used by core CPU interface +class esrip_device : public cpu_device +{ +public: + // construction/destruction + esrip_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // inline configuration helpers + template static devcb_base &static_set_fdt_r_callback(device_t &device, _Object object) { return downcast(device).m_fdt_r.set_callback(object); } + template static devcb_base &static_set_fdt_w_callback(device_t &device, _Object object) { return downcast(device).m_fdt_w.set_callback(object); } + template static devcb_base &static_set_status_in_callback(device_t &device, _Object object) { return downcast(device).m_status_in.set_callback(object); } + static void static_set_draw_callback(device_t &device, esrip_draw_delegate func) { downcast(device).m_draw = func; } + static void static_lbrm_prom(device_t &device, const char *name) { downcast(device).m_lbrm_prom = name; } + + // public interfaces + UINT8 get_rip_status(); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_stop(); + + void make_ops(); + + // device_execute_interface overrides + virtual UINT32 execute_min_cycles() const; + virtual UINT32 execute_max_cycles() const; + virtual UINT32 execute_input_lines() const; + virtual void execute_run(); + virtual void execute_set_input(int inputnum, int state); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const; + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const; + virtual UINT32 disasm_max_opcode_bytes() const; + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + + // device_state_interface overrides + virtual void state_string_export(const device_state_entry &entry, std::string &str); + + // address spaces + const address_space_config m_program_config; + + // CPU registers + UINT16 m_ram[32]; + UINT16 m_acc; + UINT16 m_d_latch; + UINT16 m_i_latch; + UINT16 m_result; + UINT8 m_new_status; + UINT8 m_status; + UINT16 m_inst; + UINT8 m_immflag; + UINT8 m_ct; + UINT8 m_t; + + /* Instruction latches - current and previous values */ + UINT8 m_l1, m_pl1; + UINT8 m_l2, m_pl2; + UINT8 m_l3, m_pl3; + UINT8 m_l4, m_pl4; + UINT8 m_l5, m_pl5; + UINT8 m_l6, m_pl6; + UINT8 m_l7, m_pl7; + + UINT8 m_pc; + UINT16 m_rip_pc; + UINT8 m_status_out; + + UINT8 m_x_scale; + UINT8 m_y_scale; + UINT8 m_img_bank; + UINT8 m_line_latch; + UINT16 m_fig_latch; + UINT16 m_attr_latch; + UINT16 m_adl_latch; + UINT16 m_adr_latch; + UINT16 m_iaddr_latch; + UINT8 m_c_latch; + + UINT16 m_fdt_cnt; + UINT16 m_ipt_cnt; + + UINT8 m_fig; + UINT16 m_fig_cycles; + + UINT8 m_optable[65536]; + + std::vector m_ipt_ram; + UINT8 *m_lbrm; + + address_space *m_program; + direct_read_data *m_direct; + + int m_icount; + + devcb_read16 m_fdt_r; + devcb_write16 m_fdt_w; + devcb_read8 m_status_in; + esrip_draw_delegate m_draw; + const char *m_lbrm_prom; + + typedef void (esrip_device::*ophandler)(UINT16 inst); + + ophandler m_opcode[24]; + + static const ophandler s_opcodetable[24]; + +private: + int get_hblank(); + int get_lbrm(); + int check_jmp(UINT8 jmp_ctrl); + + // flags + void calc_z_flag(UINT16 res); + void calc_c_flag_add(UINT16 a, UINT16 b); + void calc_c_flag_sub(UINT16 a, UINT16 b); + void calc_n_flag(UINT16 res); + void calc_v_flag_add(UINT16 a, UINT16 b, UINT32 r); + void calc_v_flag_sub(UINT16 a, UINT16 b, UINT32 r); + + // opcodes + UINT16 sor_op(UINT16 r, UINT16 opcode); + void sor(UINT16 inst); + void sonr(UINT16 inst); + + UINT16 tor_op(UINT16 r, UINT16 s, int opcode); + void tonr(UINT16 inst); + void tor1(UINT16 inst); + void tor2(UINT16 inst); + + void bonr(UINT16 inst); + void bor1(UINT16 inst); + void bor2(UINT16 inst); + + void rotr1(UINT16 inst); + void rotr2(UINT16 inst); + void rotnr(UINT16 inst); + void rotc(UINT16 inst); + void rotm(UINT16 inst); + + void prt(UINT16 inst); + void prtnr(UINT16 inst); + + void crcf(UINT16 inst); + void crcr(UINT16 inst); + + UINT16 shift_op(UINT16 u, int opcode); + void shftr(UINT16 inst); + void shftnr(UINT16 inst); + + void svstr(UINT16 inst); + + void rstst(UINT16 inst); + void setst(UINT16 inst); + + void test(UINT16 inst); + + void nop(UINT16 inst); + + void am29116_execute(UINT16 inst, int _sre); +}; + + +CPU_DISASSEMBLE( esrip ); + +#endif /* _ESRIP_H */ diff --git a/src/devices/cpu/esrip/esripdsm.c b/src/devices/cpu/esrip/esripdsm.c new file mode 100644 index 00000000000..8e5a01ae792 --- /dev/null +++ b/src/devices/cpu/esrip/esripdsm.c @@ -0,0 +1,95 @@ +// license:BSD-3-Clause +// copyright-holders:Philip Bennett +/*************************************************************************** + + esripdsm.c + + Implementation of the Entertainment Sciences + AM29116-based Real Time Image Processor + +***************************************************************************/ + +#include "emu.h" +#include "debugger.h" + + +/*************************************************************************** + DISASSEMBLY HOOK (TODO: FINISH) +***************************************************************************/ + +CPU_DISASSEMBLE( esrip ) +{ +#if 0 + static const char* const jmp_types[] = + { + "JCT", + "JT1", + "JT2", + "JT3", + "JT4", + "JLBRM", + "J#HBLANK", + "JMP", + }; + + static const char* const njmp_types[] = + { + "JNCT", + "JNT1", + "JNT2", + "JNT3", + "JNT4", + "JNLBRM", + "J#HBLANK", + " ", + }; +#endif + + UINT64 inst = BIG_ENDIANIZE_INT64(*(UINT64 *)oprom); + + UINT32 inst_hi = inst >> 32; + UINT32 inst_lo = inst & 0xffffffff; + + UINT16 ins = (inst_hi >> 16) & 0xffff; + UINT8 ctrl = (inst_hi >> 8) & 0xff; + UINT8 jmp_dest = (inst_lo >> 8) & 0xff; + + UINT8 jmp_ctrl = (ctrl >> 3) & 0x1f; + + UINT8 ctrl1 = (inst_lo >> 16) & 0xff; + UINT8 ctrl2 = (inst_lo >> 24) & 0xff; + UINT8 ctrl3 = (inst_hi) & 0xff; + + sprintf(buffer, "%.4x %c%c%c%c %.2x %s%s%s%s%s%s%s%s %c%s%s%s %c%c%c%c%c%c%c%c", + ins, + ctrl & 1 ? 'D' : ' ', + ctrl & 2 ? ' ' : 'Y', + ctrl & 4 ? 'S' : ' ', + (~jmp_ctrl & 0x18) ? 'J' : ' ', + jmp_dest, + ctrl1 & 0x01 ? " " : "I ", + ctrl1 & 0x02 ? " " : "FL", + ctrl1 & 0x04 ? "FE" : " ", + ctrl1 & 0x08 ? " " : "FR", + ctrl1 & 0x10 ? " " : "IL", + ctrl1 & 0x20 ? "IE" : " ", + ctrl1 & 0x40 ? " " : "IR", + ctrl1 & 0x80 ? " " : "IW", + + ctrl2 & 0x80 ? ' ' : 'O', + ctrl2 & 0x40 ? " " : "IXLLD", + ctrl2 & 0x20 ? " " : "IADLD", + ctrl2 & 0x10 ? " " : "SCALD", + + ctrl3 & 0x01 ? ' ' : '0', + ctrl3 & 0x02 ? ' ' : '1', + ctrl3 & 0x04 ? ' ' : '2', + ctrl3 & 0x08 ? ' ' : '3', + ctrl3 & 0x10 ? ' ' : '4', + ctrl3 & 0x20 ? ' ' : '5', + ctrl3 & 0x40 ? ' ' : '6', + ctrl3 & 0x80 ? ' ' : '7' + ); + + return 1 | DASMFLAG_SUPPORTED; +} diff --git a/src/devices/cpu/f8/f8.c b/src/devices/cpu/f8/f8.c new file mode 100644 index 00000000000..182638543d7 --- /dev/null +++ b/src/devices/cpu/f8/f8.c @@ -0,0 +1,2074 @@ +// license:BSD-3-Clause +// copyright-holders:Juergen Buchmueller +/***************************************************************************** + * + * f8.c + * Portable F8 emulator (Fairchild 3850) + * + * This work is based on Frank Palazzolo's F8 emulation in a standalone + * Fairchild Channel F emulator and the 'Fairchild F3850 CPU' data sheets. + * + *****************************************************************************/ + +/* PeT 25.June 2001 + added interrupt functionality + */ + +#include "emu.h" +#include "debugger.h" +#include "f8.h" + +#define S 0x01 +#define C 0x02 +#define Z 0x04 +#define O 0x08 +#define I 0x10 + +#define cS 4 +#define cL 6 + + +/* clear all flags */ +#define CLR_OZCS \ + m_w &= ~(O|Z|C|S) + +/* set sign and zero flags (note: the S flag is complementary) */ +#define SET_SZ(n) \ + if (n == 0) \ + m_w |= Z | S; \ + else \ + if (n < 128) \ + m_w |= S + +/* set overflow and carry flags */ +#define SET_OC(n,m) \ + if (n + m > 255) \ + m_w |= C; \ + if ((n&127)+(m&127) > 127) \ + { \ + if (!(m_w & C)) \ + m_w |= O; \ + } \ + else \ + { \ + if (m_w & C) \ + m_w |= O; \ + } + + +const device_type F8 = &device_creator; + + +f8_cpu_device::f8_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : cpu_device(mconfig, F8, "Fairchild F8", tag, owner, clock, "f8", __FILE__) + , m_program_config("program", ENDIANNESS_BIG, 8, 16, 0) + , m_io_config("io", ENDIANNESS_BIG, 8, 8, 0) + , m_pc0(0) + , m_pc1(0) + , m_dc0(0) + , m_dc1(0) + , m_a(0) + , m_w(0) + , m_is(0) + , m_pc(0) +{ + memset(m_r, 0x00, sizeof(m_r)); +} + + +/****************************************************************************** + * ROMC (ROM cycles) + * This is what the Fairchild F8 CPUs use instead of an address bus + * There are 5 control lines and each combination of those lines has + * a special meaning. The devices attached to those control lines all + * have their own program counters (PC0 and PC1) and at least one + * data counter (DC0). + * Currently the emulation does not handle distinct PCs and DCs, but + * only one instance inside the CPU context. + ******************************************************************************/ +void f8_cpu_device::ROMC_00(int insttim) /* SKR - added parameter to tell if */ + /* it is long or short based on inst */ +{ + /* + * Instruction Fetch. The device whose address space includes the + * contents of the PC0 register must place on the data bus the op + * code addressed by PC0; then all devices increment the contents + * of PC0. + */ + + m_dbus = m_direct->read_byte(m_pc0); + m_pc0 += 1; + m_icount -= insttim; /* SKR - ROMC00 is usually short, not short+long, */ + /* but DS is long */ +} + +void f8_cpu_device::ROMC_01() +{ + /* + * The device whose address space includes the contents of the PC0 + * register must place on the data bus the contents of the memory + * location addressed by PC0; then all devices add the 8-bit value + * on the data bus as signed binary number to PC0. + */ + m_dbus = m_direct->read_byte(m_pc0); + m_pc0 += (INT8)m_dbus; + m_icount -= cL; +} + +void f8_cpu_device::ROMC_02() +{ + /* + * The device whose DC0 addresses a memory word within the address + * space of that device must place on the data bus the contents of + * the memory location addressed by DC0; then all devices increment + * DC0. + */ + m_dbus = m_program->read_byte(m_dc0); + m_dc0 += 1; + m_icount -= cL; +} + +void f8_cpu_device::ROMC_03(int insttim) /* SKR - added parameter to tell if */ +{ /* it is long or short based on inst */ + /* + * Similiar to 0x00, except that it is used for immediate operands + * fetches (using PC0) instead of instruction fetches. + */ + m_dbus = m_io = m_direct->read_byte(m_pc0); + m_pc0 += 1; + m_icount -= insttim; +} + +void f8_cpu_device::ROMC_04() +{ + /* + * Copy the contents of PC1 into PC0 + */ + m_pc0 = m_pc1; + m_icount -= cS; +} + +void f8_cpu_device::ROMC_05() +{ + /* + * Store the data bus contents into the memory location pointed + * to by DC0; increment DC0. + */ + m_program->write_byte(m_dc0, m_dbus); + m_dc0 += 1; + m_icount -= cL; +} + +void f8_cpu_device::ROMC_06() +{ + /* + * Place the high order byte of DC0 on the data bus. + */ + m_dbus = m_dc0 >> 8; + m_icount -= cL; +} + +void f8_cpu_device::ROMC_07() +{ + /* + * Place the high order byte of PC1 on the data bus. + */ + m_dbus = m_pc1 >> 8; + m_icount -= cL; +} + +void f8_cpu_device::ROMC_08() +{ + /* + * All devices copy the contents of PC0 into PC1. The CPU outputs + * zero on the data bus in this ROMC state. Load the data bus into + * both halves of PC0, thus clearing the register. + */ + m_pc1 = m_pc0; + m_dbus = 0; + m_pc0 = 0; + m_icount -= cL; +} + +void f8_cpu_device::ROMC_09() +{ + /* + * The device whose address space includes the contents of the DC0 + * register must place the low order byte of DC0 onto the data bus. + */ + m_dbus = m_dc0 & 0xff; + m_icount -= cL; +} + +void f8_cpu_device::ROMC_0A() +{ + /* + * All devices add the 8-bit value on the data bus, treated as + * signed binary number, to the data counter. + */ + m_dc0 += (INT8)m_dbus; + m_icount -= cL; +} + +void f8_cpu_device::ROMC_0B() +{ + /* + * The device whose address space includes the value in PC1 + * must place the low order byte of PC1 onto the data bus. + */ + m_dbus = m_pc1 & 0xff; + m_icount -= cL; +} + +void f8_cpu_device::ROMC_0C() +{ + /* + * The device whose address space includes the contents of the PC0 + * register must place the contents of the memory word addressed + * by PC0 into the data bus; then all devices move the value that + * has just been placed on the data bus into the low order byte of PC0. + */ + m_dbus = m_direct->read_byte(m_pc0); + m_pc0 = (m_pc0 & 0xff00) | m_dbus; + m_icount -= cL; +} + +void f8_cpu_device::ROMC_0D() +{ + /* + * All devices store in PC1 the current contents of PC0, incremented + * by 1; PC0 is unaltered. + */ + m_pc1 = m_pc0 + 1; + m_icount -= cS; +} + +void f8_cpu_device::ROMC_0E() +{ + /* + * The device whose address space includes the contents of the PC0 + * register must place the word addressed by PC0 into the data bus. + * The value on the data bus is then moved to the low order byte + * of DC0 by all devices. + */ + m_dbus = m_direct->read_byte(m_pc0); + m_dc0 = (m_dc0 & 0xff00) | m_dbus; + m_icount -= cL; +} + +void f8_cpu_device::ROMC_0F() +{ + /* + * The interrupting device with highest priority must place the + * low order byte of the interrupt vector on the data bus. + * All devices must copy the contents of PC0 into PC1. All devices + * must move the contents of the data bus into the low order + * byte of PC0. + */ + m_irq_vector = standard_irq_callback(F8_INPUT_LINE_INT_REQ); + m_dbus = m_irq_vector & 0x00ff; + m_pc1 = m_pc0; + m_pc0 = (m_pc0 & 0xff00) | m_dbus; + m_icount -= cL; +} + +void f8_cpu_device::ROMC_10() +{ + /* + * Inhibit any modification to the interrupt priority logic. + */ + m_w |= 0x20; /* ???? */ + m_icount -= cL; +} + +void f8_cpu_device::ROMC_11() +{ + /* + * The device whose address space includes the contents of PC0 + * must place the contents of the addressed memory word on the + * data bus. All devices must then move the contents of the + * data bus to the upper byte of DC0. + */ + m_dbus = m_direct->read_byte(m_pc0); + m_dc0 = (m_dc0 & 0x00ff) | (m_dbus << 8); + m_icount -= cL; +} + +void f8_cpu_device::ROMC_12() +{ + /* + * All devices copy the contents of PC0 into PC1. All devices then + * move the contents of the data bus into the low order byte of PC0. + */ + m_pc1 = m_pc0; + m_pc0 = (m_pc0 & 0xff00) | m_dbus; + m_icount -= cL; +} + +void f8_cpu_device::ROMC_13() +{ + /* + * The interrupting device with highest priority must move the high + * order half of the interrupt vector onto the data bus. All devices + * must then move the contents of the data bus into the high order + * byte of PC0. The interrupting device resets its interrupt circuitry + * (so that it is no longer requesting CPU servicing and can respond + * to another interrupt). + */ + m_dbus = m_irq_vector >> 8; + m_pc0 = (m_pc0 & 0x00ff) | (m_dbus << 8); + m_w&=~I; + m_icount -= cL; +} + +void f8_cpu_device::ROMC_14() +{ + /* + * All devices move the contents of the data bus into the high + * order byte of PC0. + */ + m_pc0 = (m_pc0 & 0x00ff) | (m_dbus << 8); + m_icount -= cL; +} + +void f8_cpu_device::ROMC_15() +{ + /* + * All devices move the contents of the data bus into the high + * order byte of PC1. + */ + m_pc1 = (m_pc1 & 0x00ff) | (m_dbus << 8); + m_icount -= cL; +} + +void f8_cpu_device::ROMC_16() +{ + /* + * All devices move the contents of the data bus into the high + * order byte of DC0. + */ + m_dc0 = (m_dc0 & 0x00ff) | (m_dbus << 8); + m_icount -= cL; +} + +void f8_cpu_device::ROMC_17() +{ + /* + * All devices move the contents of the data bus into the low + * order byte of PC0. + */ + m_pc0 = (m_pc0 & 0xff00) | m_dbus; + m_icount -= cL; +} + +void f8_cpu_device::ROMC_18() +{ + /* + * All devices move the contents of the data bus into the low + * order byte of PC1. + */ + m_pc1 = (m_pc1 & 0xff00) | m_dbus; + m_icount -= cL; +} + +void f8_cpu_device::ROMC_19() +{ + /* + * All devices move the contents of the data bus into the low + * order byte of DC0. + */ + m_dc0 = (m_dc0 & 0xff00) | m_dbus; + m_icount -= cL; +} + +void f8_cpu_device::ROMC_1A() +{ + /* + * During the prior cycle, an I/O port timer or interrupt control + * register was addressed; the device containing the addressed port + * must place the contents of the data bus into the address port. + */ + m_iospace->write_byte(m_io, m_dbus); + m_icount -= cL; +} + +void f8_cpu_device::ROMC_1B() +{ + /* + * During the prior cycle, the data bus specified the address of an + * I/O port. The device containing the addressed I/O port must place + * the contents of the I/O port on the data bus. (Note that the + * contents of timer and interrupt control registers cannot be read + * back onto the data bus). + */ + m_dbus = m_iospace->read_byte(m_io); + m_icount -= cL; +} + +void f8_cpu_device::ROMC_1C(int insttim) /* SKR - added parameter to tell if */ + /* it is long or short based on inst */ +{ + /* + * None. + */ + m_icount -= insttim; +} + +void f8_cpu_device::ROMC_1D() +{ + /* + * Devices with DC0 and DC1 registers must switch registers. + * Devices without a DC1 register perform no operation. + */ + UINT16 tmp = m_dc0; + m_dc0 = m_dc1; + m_dc1 = tmp; + m_icount -= cS; +} + +void f8_cpu_device::ROMC_1E() +{ + /* + * The devices whose address space includes the contents of PC0 + * must place the low order byte of PC0 onto the data bus. + */ + m_dbus = m_pc0 & 0xff; + m_icount -= cL; +} + +void f8_cpu_device::ROMC_1F() +{ + /* + * The devices whose address space includes the contents of PC0 + * must place the high order byte of PC0 onto the data bus. + */ + m_dbus = (m_pc0 >> 8) & 0xff; + m_icount -= cL; +} + +/*********************************** + * illegal opcodes + ***********************************/ +void f8_cpu_device::illegal() +{ + logerror("f8 illegal opcode at 0x%04x: %02x\n", m_pc0, m_dbus); +} + +/*************************************************** + * O Z C S 0000 0000 + * - - - - LR A,KU + ***************************************************/ +void f8_cpu_device::f8_lr_a_ku() +{ + m_a = m_r[12]; +} + +/*************************************************** + * O Z C S 0000 0001 + * - - - - LR A,KL + ***************************************************/ +void f8_cpu_device::f8_lr_a_kl() +{ + m_a = m_r[13]; +} + +/*************************************************** + * O Z C S 0000 0010 + * - - - - LR A,QU + ***************************************************/ +void f8_cpu_device::f8_lr_a_qu() +{ + m_a = m_r[14]; +} + +/*************************************************** + * O Z C S 0000 0011 + * - - - - LR A,QL + ***************************************************/ +void f8_cpu_device::f8_lr_a_ql() +{ + m_a = m_r[15]; +} + +/*************************************************** + * O Z C S 0000 0100 + * - - - - LR KU,A + ***************************************************/ +void f8_cpu_device::f8_lr_ku_a() +{ + m_r[12] = m_a; +} + +/*************************************************** + * O Z C S 0000 0101 + * - - - - LR KL,A + ***************************************************/ +void f8_cpu_device::f8_lr_kl_a() +{ + m_r[13] = m_a; +} + +/*************************************************** + * O Z C S 0000 0110 + * - - - - LR QU,A + ***************************************************/ +void f8_cpu_device::f8_lr_qu_a() +{ + m_r[14] = m_a; +} + +/*************************************************** + * O Z C S 0000 0111 + * - - - - LR QL,A + ***************************************************/ +void f8_cpu_device::f8_lr_ql_a() +{ + m_r[15] = m_a; +} + +/*************************************************** + * O Z C S 0000 1000 + * - - - - LR K,P + ***************************************************/ +void f8_cpu_device::f8_lr_k_p() +{ + ROMC_07(); + m_r[12] = m_dbus; + ROMC_0B(); + m_r[13] = m_dbus; +} + +/*************************************************** + * O Z C S 0000 1001 + * - - - - LR P,K + ***************************************************/ +void f8_cpu_device::f8_lr_p_k() +{ + m_dbus = m_r[12]; + ROMC_15(); + m_dbus = m_r[13]; + ROMC_18(); +} + +/*************************************************** + * O Z C S 0000 1010 + * - - - - LR A,IS + ***************************************************/ +void f8_cpu_device::f8_lr_a_is() +{ + m_a = m_is; +} + +/*************************************************** + * O Z C S 0000 1011 + * - - - - LR IS,A + ***************************************************/ +void f8_cpu_device::f8_lr_is_a() +{ + m_is = m_a & 0x3f; +} + +/*************************************************** + * O Z C S 0000 1100 + * - - - - PK + ***************************************************/ +void f8_cpu_device::f8_pk() +{ + m_dbus = m_r[13]; + ROMC_12(); + m_dbus = m_r[12]; + ROMC_14(); +} + +/*************************************************** + * O Z C S 0000 1101 + * - - - - LR P0,Q + ***************************************************/ +void f8_cpu_device::f8_lr_p0_q() +{ + m_dbus = m_r[15]; + ROMC_17(); + m_dbus = m_r[14]; + ROMC_14(); +} + +/*************************************************** + * O Z C S 0000 1110 + * - - - - LR Q,DC + ***************************************************/ +void f8_cpu_device::f8_lr_q_dc() +{ + ROMC_06(); + m_r[14] = m_dbus; + ROMC_09(); + m_r[15] = m_dbus; +} + +/*************************************************** + * O Z C S 0000 1111 + * - - - - LR DC,Q + ***************************************************/ +void f8_cpu_device::f8_lr_dc_q() +{ + m_dbus = m_r[14]; + ROMC_16(); + m_dbus = m_r[15]; + ROMC_19(); +} + +/*************************************************** + * O Z C S 0001 0000 + * - - - - LR DC,H + ***************************************************/ +void f8_cpu_device::f8_lr_dc_h() +{ + m_dbus = m_r[10]; + ROMC_16(); + m_dbus = m_r[11]; + ROMC_19(); +} + +/*************************************************** + * O Z C S 0001 0001 + * - - - - LR H,DC + ***************************************************/ +void f8_cpu_device::f8_lr_h_dc() +{ + ROMC_06(); + m_r[10] = m_dbus; + ROMC_09(); + m_r[11] = m_dbus; +} + +/*************************************************** + * O Z C S 0001 0010 + * 0 x 0 1 SR 1 + ***************************************************/ +void f8_cpu_device::f8_sr_1() +{ + m_a >>= 1; + CLR_OZCS; + SET_SZ(m_a); +} + +/*************************************************** + * O Z C S 0001 0011 + * 0 x 0 x SL 1 + ***************************************************/ +void f8_cpu_device::f8_sl_1() +{ + m_a <<= 1; + CLR_OZCS; + SET_SZ(m_a); +} + +/*************************************************** + * O Z C S 0001 0100 + * 0 x 0 1 SR 4 + ***************************************************/ +void f8_cpu_device::f8_sr_4() +{ + m_a >>= 4; + CLR_OZCS; + SET_SZ(m_a); +} + +/*************************************************** + * O Z C S 0001 0101 + * 0 x 0 x SL 4 + ***************************************************/ +void f8_cpu_device::f8_sl_4() +{ + m_a <<= 4; + CLR_OZCS; + SET_SZ(m_a); +} + +/*************************************************** + * O Z C S 0001 0110 + * - - - - LM + ***************************************************/ +void f8_cpu_device::f8_lm() +{ + ROMC_02(); + m_a = m_dbus; +} + +/*************************************************** + * O Z C S 0001 0111 + * - - - - ST + ***************************************************/ +void f8_cpu_device::f8_st() +{ + m_dbus = m_a; + ROMC_05(); +} + +/*************************************************** + * O Z C S 0001 1000 + * 0 x 0 x COM + ***************************************************/ +void f8_cpu_device::f8_com() +{ + m_a = ~m_a; + CLR_OZCS; + SET_SZ(m_a); +} + +/*************************************************** + * O Z C S 0001 1001 + * x x x x LNK + ***************************************************/ +void f8_cpu_device::f8_lnk() +{ + if (m_w & C) + { + CLR_OZCS; + SET_OC(m_a,1); + m_a += 1; + } + else + { + CLR_OZCS; + } + SET_SZ(m_a); +} + +/*************************************************** + * O Z C S 0001 1010 + * DI + ***************************************************/ +void f8_cpu_device::f8_di() +{ + ROMC_1C(cS); + m_w &= ~I; +} + +/*************************************************** + * O Z C S 0001 1011 + * EI + ***************************************************/ +void f8_cpu_device::f8_ei() +{ + ROMC_1C(cS); + m_w |= I; +} + +/*************************************************** + * O Z C S 0001 1100 + * POP + ***************************************************/ +void f8_cpu_device::f8_pop() +{ + ROMC_04(); +} + +/*************************************************** + * O Z C S 0001 1101 + * x x x x LR W,J + ***************************************************/ +void f8_cpu_device::f8_lr_w_j() +{ + ROMC_1C(cS); + m_w = m_r[9]; +} + +/*************************************************** + * O Z C S 0001 1110 + * - - - - LR J,W + ***************************************************/ +void f8_cpu_device::f8_lr_j_w() +{ + m_r[9] = m_w; +} + +/*************************************************** + * O Z C S 0001 1111 + * x x x x INC + ***************************************************/ +void f8_cpu_device::f8_inc() +{ + CLR_OZCS; + SET_OC(m_a,1); + m_a += 1; + SET_SZ(m_a); +} + +/*************************************************** + * O Z C S 0010 0000 aaaa aaaa + * - - - - LI aa + ***************************************************/ +void f8_cpu_device::f8_li() +{ + ROMC_03(cL); + m_a = m_dbus; +} + +/*************************************************** + * O Z C S 0010 0001 aaaa aaaa + * 0 x 0 x NI aa + ***************************************************/ +void f8_cpu_device::f8_ni() +{ + ROMC_03(cL); + CLR_OZCS; + m_a &= m_dbus; + SET_SZ(m_a); +} + +/*************************************************** + * O Z C S 0010 0010 aaaa aaaa + * 0 x 0 x OI aa + ***************************************************/ +void f8_cpu_device::f8_oi() +{ + ROMC_03(cL); + CLR_OZCS; + m_a |= m_dbus; + SET_SZ(m_a); +} + +/*************************************************** + * O Z C S 0010 0011 aaaa aaaa + * 0 x 0 x XI aa + ***************************************************/ +void f8_cpu_device::f8_xi() +{ + ROMC_03(cL); + CLR_OZCS; + m_a ^= m_dbus; + SET_SZ(m_a); +} + +/*************************************************** + * O Z C S 0010 0100 aaaa aaaa + * x x x x AI aa + ***************************************************/ +void f8_cpu_device::f8_ai() +{ + ROMC_03(cL); + CLR_OZCS; + SET_OC(m_a,m_dbus); + m_a += m_dbus; + SET_SZ(m_a); +} + +/*************************************************** + * O Z C S 0010 0101 aaaa aaaa + * x x x x CI aa + ***************************************************/ +void f8_cpu_device::f8_ci() +{ + UINT16 tmp = ((UINT8)~m_a) + 1; + ROMC_03(cL); + CLR_OZCS; + SET_OC(tmp,m_dbus); + tmp += m_dbus; + SET_SZ((UINT8)tmp); +} + +/*************************************************** + * O Z C S 0010 0110 aaaa aaaa + * 0 x 0 x IN aa + ***************************************************/ +void f8_cpu_device::f8_in() +{ + ROMC_03(cL); + CLR_OZCS; + ROMC_1B(); + m_a = m_dbus; + SET_SZ(m_a); +} + +/*************************************************** + * O Z C S 0010 0111 aaaa aaaa + * - - - - OUT aa + ***************************************************/ +void f8_cpu_device::f8_out() +{ + ROMC_03(cL); + m_dbus = m_a; + ROMC_1A(); +} + +/*************************************************** + * O Z C S 0010 1000 iiii iiii jjjj jjjj + * - - - - PI iijj + ***************************************************/ +void f8_cpu_device::f8_pi() +{ + ROMC_03(cL); + m_a = m_dbus; + ROMC_0D(); + ROMC_0C(); + m_dbus = m_a; + ROMC_14(); +} + +/*************************************************** + * O Z C S 0010 1001 iiii iiii jjjj jjjj + * - - - - JMP iijj + ***************************************************/ +void f8_cpu_device::f8_jmp() +{ + ROMC_03(cL); + m_a = m_dbus; + ROMC_0C(); + m_dbus = m_a; + ROMC_14(); +} + +/*************************************************** + * O Z C S 0010 1010 iiii iiii jjjj jjjj + * - - - - DCI iijj + ***************************************************/ +void f8_cpu_device::f8_dci() +{ + ROMC_11(); + ROMC_03(cS); + ROMC_0E(); + ROMC_03(cS); +} + +/*************************************************** + * O Z C S 0010 1011 + * - - - - NOP + ***************************************************/ +void f8_cpu_device::f8_nop() +{ +} + +/*************************************************** + * O Z C S 0010 1100 + * - - - - XDC + ***************************************************/ +void f8_cpu_device::f8_xdc() +{ + ROMC_1D(); +} + +/*************************************************** + * O Z C S 0011 rrrr + * x x x x DS r + ***************************************************/ +void f8_cpu_device::f8_ds_r(int r) +{ + CLR_OZCS; + SET_OC(m_r[r], 0xff); + m_r[r] = m_r[r] + 0xff; + SET_SZ(m_r[r]); +} + +/*************************************************** + * O Z C S 0011 1100 + * x x x x DS ISAR + ***************************************************/ +void f8_cpu_device::f8_ds_isar() +{ + CLR_OZCS; + SET_OC(m_r[m_is], 0xff); + m_r[m_is] = m_r[m_is] + 0xff; + SET_SZ(m_r[m_is]); +} + +/*************************************************** + * O Z C S 0011 1101 + * x x x x DS ISAR++ + ***************************************************/ +void f8_cpu_device::f8_ds_isar_i() +{ + CLR_OZCS; + SET_OC(m_r[m_is], 0xff); + m_r[m_is] = m_r[m_is] + 0xff; + SET_SZ(m_r[m_is]); + m_is = (m_is & 0x38) | ((m_is + 1) & 0x07); +} + +/*************************************************** + * O Z C S 0011 1110 + * x x x x DS ISAR-- + ***************************************************/ +void f8_cpu_device::f8_ds_isar_d() +{ + CLR_OZCS; + SET_OC(m_r[m_is], 0xff); + m_r[m_is] = m_r[m_is] + 0xff; + SET_SZ(m_r[m_is]); + m_is = (m_is & 0x38) | ((m_is - 1) & 0x07); +} + +/*************************************************** + * O Z C S 0100 rrrr + * - - - - LR A,r + ***************************************************/ +void f8_cpu_device::f8_lr_a_r(int r) +{ + m_a = m_r[r]; +} + +/*************************************************** + * O Z C S 0100 1100 + * - - - - LR A,ISAR + ***************************************************/ +void f8_cpu_device::f8_lr_a_isar() +{ + m_a = m_r[m_is]; +} + +/*************************************************** + * O Z C S 0100 1101 + * - - - - LR A,ISAR++ + ***************************************************/ +void f8_cpu_device::f8_lr_a_isar_i() +{ + m_a = m_r[m_is]; + m_is = (m_is & 0x38) | ((m_is + 1) & 0x07); +} + +/*************************************************** + * O Z C S 0100 1110 + * - - - - LR A,ISAR-- + ***************************************************/ +void f8_cpu_device::f8_lr_a_isar_d() +{ + m_a = m_r[m_is]; + m_is = (m_is & 0x38) | ((m_is - 1) & 0x07); +} + +/*************************************************** + * O Z C S 0101 rrrr + * - - - - LR r,A + ***************************************************/ +void f8_cpu_device::f8_lr_r_a(int r) +{ + m_r[r] = m_a; +} + +/*************************************************** + * O Z C S 0101 1100 + * - - - - LR ISAR,A + ***************************************************/ +void f8_cpu_device::f8_lr_isar_a() +{ + m_r[m_is] = m_a; +} + +/*************************************************** + * O Z C S 0101 1101 + * - - - - LR ISAR++,A + ***************************************************/ +void f8_cpu_device::f8_lr_isar_i_a() +{ + m_r[m_is] = m_a; + m_is = (m_is & 0x38) | ((m_is + 1) & 0x07); +} + +/*************************************************** + * O Z C S 0101 1110 + * - - - - LR ISAR--,A + ***************************************************/ +void f8_cpu_device::f8_lr_isar_d_a() +{ + m_r[m_is] = m_a; + m_is = (m_is & 0x38) | ((m_is - 1) & 0x07); +} + +/*************************************************** + * O Z C S 0110 0eee + * - - - - LISU e + ***************************************************/ +void f8_cpu_device::f8_lisu(int e) +{ + m_is = (m_is & 0x07) | e; +} + +/*************************************************** + * O Z C S 0110 1eee + * - - - - LISL e + ***************************************************/ +void f8_cpu_device::f8_lisl(int e) +{ + m_is = (m_is & 0x38) | e; +} + +/*************************************************** + * O Z C S 0111 iiii + * - - - - LIS i + ***************************************************/ +void f8_cpu_device::f8_lis(int i) +{ + m_a = i; +} + +/*************************************************** + * O Z C S 1000 0eee aaaa aaaa + * BT e,aa + ***************************************************/ +void f8_cpu_device::f8_bt(int e) +{ + ROMC_1C(cS); + if (m_w & e) + ROMC_01(); /* take the relative branch */ + else + ROMC_03(cS); /* just read the argument on the data bus */ +} + +/*************************************************** + * O Z C S 1000 1000 + * x x x x AM + ***************************************************/ +void f8_cpu_device::f8_am() +{ + ROMC_02(); + CLR_OZCS; + SET_OC(m_a, m_dbus); + m_a += m_dbus; + SET_SZ(m_a); +} + +/*************************************************** + * O Z C S 1000 1001 + * x x x x AMD + ***************************************************/ +void f8_cpu_device::f8_amd() +{ +/*SKR from F8 Guide To programming description of AMD + + binary add the addend to the binary sum of the augend and $66 + *NOTE* the binary addition of the augend to $66 is done before AMD is called + record the status of the carry and intermediate carry + add a factor to the sum based on the carry and intermediate carry: + no carry, no intermediate carry, add $AA + no carry, intermediate carry, add $A0 + carry, no intermediate carry, add $0A + carry, intermediate carry, add $00 + any carry from the low-order digit is suppressed + *NOTE* status flags are updated prior to the factor being added +*/ + + UINT8 augend=m_a; + ROMC_02(); + UINT8 addend=m_dbus; + UINT8 tmp=addend+augend; + + UINT8 c=0; /* high order carry */ + UINT8 ic=0; /* low order carry */ + if(((augend+addend)&0xff0)>0xf0) + c=1; + if((augend&0x0f)+(addend&0x0f)>0x0F) + ic=1; + + CLR_OZCS; + SET_OC(augend,addend); + SET_SZ(tmp); + + if(c==0&&ic==0) + tmp=((tmp+0xa0)&0xf0)+((tmp+0x0a)&0x0f); + if(c==0&&ic==1) + tmp=((tmp+0xa0)&0xf0)+(tmp&0x0f); + if(c==1&&ic==0) + tmp=(tmp&0xf0)+((tmp+0x0a)&0x0f); + + m_a = tmp; +} + +/*************************************************** + * O Z C S 1000 1010 + * 0 x 0 x NM + ***************************************************/ +void f8_cpu_device::f8_nm() +{ + ROMC_02(); + CLR_OZCS; + m_a &= m_dbus; + SET_SZ(m_a); +} + +/*************************************************** + * O Z C S 1000 1011 + * 0 x 0 x OM + ***************************************************/ +void f8_cpu_device::f8_om() +{ + ROMC_02(); + CLR_OZCS; + m_a |= m_dbus; + SET_SZ(m_a); +} + +/*************************************************** + * O Z C S 1000 1100 + * 0 x 0 x XM + ***************************************************/ +void f8_cpu_device::f8_xm() +{ + ROMC_02(); + CLR_OZCS; + m_a ^= m_dbus; + SET_SZ(m_a); +} + +/*************************************************** + * O Z C S 1000 1101 + * x x x x CM + ***************************************************/ +void f8_cpu_device::f8_cm() /* SKR changed to match f8_ci() */ +{ + UINT16 tmp = ((UINT8)~m_a) + 1; + ROMC_02(); + CLR_OZCS; + SET_OC(tmp,m_dbus); + tmp += m_dbus; + SET_SZ((UINT8)tmp); +} + +/*************************************************** + * O Z C S 1000 1110 + * - - - - ADC + ***************************************************/ +void f8_cpu_device::f8_adc() +{ + m_dbus = m_a; + ROMC_0A(); /* add data bus value to DC0 */ +} + +/*************************************************** + * O Z C S 1000 1111 + * - - - - BR7 + ***************************************************/ +void f8_cpu_device::f8_br7() +{ + if ((m_is & 7) == 7) + ROMC_03(cS); /* just read the argument on the data bus */ + else + ROMC_01(); /* take the relative branch */ +} + +/*************************************************** + * O Z C S 1001 tttt aaaa aaaa + * - - - - BF t,aa + ***************************************************/ +void f8_cpu_device::f8_bf(int t) +{ + ROMC_1C(cS); + if (m_w & t) + ROMC_03(cS); /* just read the argument on the data bus */ + else + ROMC_01(); /* take the relative branch */ +} + +/*************************************************** + * O Z C S 1010 000n + * 0 x 0 x INS n (n = 0-1) + ***************************************************/ +void f8_cpu_device::f8_ins_0(int n) +{ + ROMC_1C(cS); + CLR_OZCS; + m_a = m_iospace->read_byte(n); + SET_SZ(m_a); +} + +/*************************************************** + * O Z C S 1010 nnnn + * 0 x 0 x INS n (n = 4-F) + ***************************************************/ +void f8_cpu_device::f8_ins_1(int n) +{ + ROMC_1C(cL); + m_io = n; + ROMC_1B(); + CLR_OZCS; + m_a = m_dbus; + SET_SZ(m_a); +} + +/*************************************************** + * O Z C S 1011 000n + * - - - - OUTS n (n = 0-1) + ***************************************************/ +void f8_cpu_device::f8_outs_0(int n) +{ + ROMC_1C(cS); + m_iospace->write_byte(n, m_a); +} + +/*************************************************** + * O Z C S 1011 nnnn + * - - - - OUTS n (n = 4-F) + ***************************************************/ +void f8_cpu_device::f8_outs_1(int n) +{ + ROMC_1C(cL); + m_io = n; + m_dbus = m_a; + ROMC_1A(); +} + +/*************************************************** + * O Z C S 1100 rrrr + * x x x x AS r + ***************************************************/ +void f8_cpu_device::f8_as(int r) +{ + CLR_OZCS; + SET_OC(m_a, m_r[r]); + m_a += m_r[r]; + SET_SZ(m_a); +} + +/*************************************************** + * O Z C S 1100 1100 + * x x x x AS ISAR + ***************************************************/ +void f8_cpu_device::f8_as_isar() +{ + CLR_OZCS; + SET_OC(m_a, m_r[m_is]); + m_a += m_r[m_is]; + SET_SZ(m_a); +} + +/*************************************************** + * O Z C S 1100 1101 + * x x x x AS ISAR++ + ***************************************************/ +void f8_cpu_device::f8_as_isar_i() +{ + CLR_OZCS; + SET_OC(m_a, m_r[m_is]); + m_a += m_r[m_is]; + SET_SZ(m_a); + m_is = (m_is & 0x38) | ((m_is + 1) & 0x07); +} + +/*************************************************** + * O Z C S 1100 1110 + * x x x x AS ISAR-- + ***************************************************/ +void f8_cpu_device::f8_as_isar_d() +{ + CLR_OZCS; + SET_OC(m_a, m_r[m_is]); + m_a += m_r[m_is]; + SET_SZ(m_a); + m_is = (m_is & 0x38) | ((m_is - 1) & 0x07); +} + +/*************************************************** + * O Z C S 1101 rrrr + * x x x x ASD r + ***************************************************/ +void f8_cpu_device::f8_asd(int r) +{ +/*SKR from F8 Guide To programming description of AMD */ + UINT8 augend=m_a; + ROMC_1C(cS); + UINT8 addend=m_r[r]; + UINT8 tmp=augend+addend; + + UINT8 c=0; + UINT8 ic=0; + if(((augend+addend)&0xff0)>0xf0) + c=1; + if((augend&0x0f)+(addend&0x0f)>0x0F) + ic=1; + + CLR_OZCS; + SET_OC(augend,addend); + SET_SZ(tmp); + + if(c==0&&ic==0) + tmp=((tmp+0xa0)&0xf0)+((tmp+0x0a)&0x0f); + if(c==0&&ic==1) + tmp=((tmp+0xa0)&0xf0)+(tmp&0x0f); + if(c==1&&ic==0) + tmp=(tmp&0xf0)+((tmp+0x0a)&0x0f); + + m_a = tmp; +} + +/*************************************************** + * O Z C S 1101 1100 + * x x x x ASD ISAR + ***************************************************/ +void f8_cpu_device::f8_asd_isar() +{ +/*SKR from F8 Guide To programming description of AMD */ + UINT8 augend=m_a; + ROMC_1C(cS); + UINT8 addend=m_r[m_is]; + UINT8 tmp=augend+addend; + + UINT8 c=0; + UINT8 ic=0; + if(((augend+addend)&0xff0)>0xf0) + c=1; + if((augend&0x0f)+(addend&0x0f)>0x0F) + ic=1; + + CLR_OZCS; + SET_OC(augend,addend); + SET_SZ(tmp); + + if(c==0&&ic==0) + tmp=((tmp+0xa0)&0xf0)+((tmp+0x0a)&0x0f); + if(c==0&&ic==1) + tmp=((tmp+0xa0)&0xf0)+(tmp&0x0f); + if(c==1&&ic==0) + tmp=(tmp&0xf0)+((tmp+0x0a)&0x0f); + + m_a = tmp; +} + +/*************************************************** + * O Z C S 1101 1101 + * x x x x ASD ISAR++ + ***************************************************/ +void f8_cpu_device::f8_asd_isar_i() +{ +/*SKR from F8 Guide To programming description of AMD */ + UINT8 augend=m_a; + ROMC_1C(cS); + UINT8 addend=m_r[m_is]; + UINT8 tmp=augend+addend; + + UINT8 c=0; + UINT8 ic=0; + if(((augend+addend)&0xff0)>0xf0) + c=1; + if((augend&0x0f)+(addend&0x0f)>0x0F) + ic=1; + + CLR_OZCS; + SET_OC(augend,addend); + SET_SZ(tmp); + + if(c==0&&ic==0) + tmp=((tmp+0xa0)&0xf0)+((tmp+0x0a)&0x0f); + if(c==0&&ic==1) + tmp=((tmp+0xa0)&0xf0)+(tmp&0x0f); + if(c==1&&ic==0) + tmp=(tmp&0xf0)+((tmp+0x0a)&0x0f); + + m_a = tmp; + m_is = (m_is & 0x38) | ((m_is + 1) & 0x07); +} + +/*************************************************** + * O Z C S 1101 1110 + * x x x x ASD ISAR-- + ***************************************************/ +void f8_cpu_device::f8_asd_isar_d() +{ +/*SKR from F8 Guide To programming description of AMD */ + UINT8 augend=m_a; + ROMC_1C(cS); + UINT8 addend=m_r[m_is]; + UINT8 tmp=augend+addend; + + UINT8 c=0; + UINT8 ic=0; + if(((augend+addend)&0xff0)>0xf0) + c=1; + if((augend&0x0f)+(addend&0x0f)>0x0F) + ic=1; + + CLR_OZCS; + SET_OC(augend,addend); + SET_SZ(tmp); + + if(c==0&&ic==0) + tmp=((tmp+0xa0)&0xf0)+((tmp+0x0a)&0x0f); + if(c==0&&ic==1) + tmp=((tmp+0xa0)&0xf0)+(tmp&0x0f); + if(c==1&&ic==0) + tmp=(tmp&0xf0)+((tmp+0x0a)&0x0f); + + m_a = tmp; + m_is = (m_is & 0x38) | ((m_is - 1) & 0x07); +} + +/*************************************************** + * O Z C S 1110 rrrr + * 0 x 0 x XS r + ***************************************************/ +void f8_cpu_device::f8_xs(int r) +{ + CLR_OZCS; + m_a ^= m_r[r]; + SET_SZ(m_a); +} + +/*************************************************** + * O Z C S 1110 1100 + * 0 x 0 x XS ISAR + ***************************************************/ +void f8_cpu_device::f8_xs_isar() +{ + CLR_OZCS; + m_a ^= m_r[m_is]; + SET_SZ(m_a); +} + +/*************************************************** + * O Z C S 1110 1101 + * 0 x 0 x XS ISAR++ + ***************************************************/ +void f8_cpu_device::f8_xs_isar_i() +{ + CLR_OZCS; + m_a ^= m_r[m_is]; + SET_SZ(m_a); + m_is = (m_is & 0x38) | ((m_is + 1) & 0x07); +} + +/*************************************************** + * O Z C S 1110 1110 + * 0 x 0 x XS ISAR-- + ***************************************************/ +void f8_cpu_device::f8_xs_isar_d() +{ + CLR_OZCS; + m_a ^= m_r[m_is]; + SET_SZ(m_a); + m_is = (m_is & 0x38) | ((m_is - 1) & 0x07); +} + +/*************************************************** + * O Z C S 1111 rrrr + * 0 x 0 x NS r + ***************************************************/ +void f8_cpu_device::f8_ns(int r) +{ + CLR_OZCS; + m_a &= m_r[r]; + SET_SZ(m_a); +} + +/*************************************************** + * O Z C S 1111 1100 + * 0 x 0 x NS ISAR + ***************************************************/ +void f8_cpu_device::f8_ns_isar() +{ + CLR_OZCS; + m_a &= m_r[m_is]; + SET_SZ(m_a); +} + +/*************************************************** + * O Z C S 1111 1101 + * 0 x 0 x NS ISAR++ + ***************************************************/ +void f8_cpu_device::f8_ns_isar_i() +{ + CLR_OZCS; + m_a &= m_r[m_is]; + SET_SZ(m_a); + m_is = (m_is & 0x38) | ((m_is + 1) & 0x07); +} + +/*************************************************** + * O Z C S 1111 1110 + * 0 x 0 x NS ISAR-- + ***************************************************/ +void f8_cpu_device::f8_ns_isar_d() +{ + CLR_OZCS; + m_a &= m_r[m_is]; + SET_SZ(m_a); + m_is = (m_is & 0x38) | ((m_is - 1) & 0x07); +} + +void f8_cpu_device::device_reset() +{ + UINT8 data; + int i; + + m_pc0 = 0; + m_pc1 = 0; + m_dc0 = 0; + m_dc1 = 0; + m_a = 0; + m_w = 0; + m_is = 0; + m_dbus = 0; + m_io = 0; + m_irq_vector = 0; + memset(m_r, 0, sizeof(m_r)); + m_irq_request = 0; + + m_w&=~I; + + /* save PC0 to PC1 and reset PC0 */ + ROMC_08(); + /* fetch the first opcode */ + ROMC_00(cS); + + /* initialize the timer shift register + * this is an 8 bit polynome counter which can be loaded parallel + * with 0xff the outputs never change and thus the timer is disabled. + * with 0xfe the shifter starts cycling through 255 states until it + * reaches 0xfe again (and then issues an interrupt). + * the counter output values are not sequential, but go like this: + * 0xfe, 0xfd, 0xfb, 0xf7, 0xee, 0xdc ... etc. :-) + * We have to build a lookup table to tell how many cycles a write + + */ + data = 0xfe; /* initial value */ + for (i = 0; i < 256; i++) + { + timer_shifter[i] = data; + if ( (((data >> 3) ^ (data >> 4)) ^ ((data >> 5) ^ (data >> 7))) & 1 ) + { + data <<= 1; + } + else + { + data = (data << 1) | 1; + } + } +} + +/* Execute cycles - returns number of cycles actually run */ +void f8_cpu_device::execute_run() +{ + do + { + UINT8 op=m_dbus; + + m_pc = (m_pc0 - 1) & 0xffff; + debugger_instruction_hook(this, (m_pc0 - 1) & 0xffff); + + switch( op ) + { + /* opcode bitmask */ + case 0x00: /* 0000 0000 */ f8_lr_a_ku(); break; + case 0x01: /* 0000 0001 */ f8_lr_a_kl(); break; + case 0x02: /* 0000 0010 */ f8_lr_a_qu(); break; + case 0x03: /* 0000 0011 */ f8_lr_a_ql(); break; + case 0x04: /* 0000 0100 */ f8_lr_ku_a(); break; + case 0x05: /* 0000 0101 */ f8_lr_kl_a(); break; + case 0x06: /* 0000 0110 */ f8_lr_qu_a(); break; + case 0x07: /* 0000 0111 */ f8_lr_ql_a(); break; + case 0x08: /* 0000 1000 */ f8_lr_k_p(); break; + case 0x09: /* 0000 1001 */ f8_lr_p_k(); break; + case 0x0a: /* 0000 1010 */ f8_lr_a_is(); break; + case 0x0b: /* 0000 1011 */ f8_lr_is_a(); break; + case 0x0c: /* 0000 1100 */ f8_pk(); break; + case 0x0d: /* 0000 1101 */ f8_lr_p0_q(); break; + case 0x0e: /* 0000 1110 */ f8_lr_q_dc(); break; + case 0x0f: /* 0000 1111 */ f8_lr_dc_q(); break; + + case 0x10: /* 0001 0000 */ f8_lr_dc_h(); break; + case 0x11: /* 0001 0001 */ f8_lr_h_dc(); break; + case 0x12: /* 0001 0010 */ f8_sr_1(); break; + case 0x13: /* 0001 0011 */ f8_sl_1(); break; + case 0x14: /* 0001 0100 */ f8_sr_4(); break; + case 0x15: /* 0001 0101 */ f8_sl_4(); break; + case 0x16: /* 0001 0110 */ f8_lm(); break; + case 0x17: /* 0001 0111 */ f8_st(); break; + case 0x18: /* 0001 1000 */ f8_com(); break; + case 0x19: /* 0001 1001 */ f8_lnk(); break; + case 0x1a: /* 0001 1010 */ f8_di(); break; + case 0x1b: /* 0001 1011 */ f8_ei(); break; + case 0x1c: /* 0001 1100 */ f8_pop(); break; + case 0x1d: /* 0001 1101 */ f8_lr_w_j(); break; + case 0x1e: /* 0001 1110 */ f8_lr_j_w(); break; + case 0x1f: /* 0001 1111 */ f8_inc(); break; + + case 0x20: /* 0010 0000 */ f8_li(); break; + case 0x21: /* 0010 0001 */ f8_ni(); break; + case 0x22: /* 0010 0010 */ f8_oi(); break; + case 0x23: /* 0010 0011 */ f8_xi(); break; + case 0x24: /* 0010 0100 */ f8_ai(); break; + case 0x25: /* 0010 0101 */ f8_ci(); break; + case 0x26: /* 0010 0110 */ f8_in(); break; + case 0x27: /* 0010 0111 */ f8_out(); break; + case 0x28: /* 0010 1000 */ f8_pi(); break; + case 0x29: /* 0010 1001 */ f8_jmp(); break; + case 0x2a: /* 0010 1010 */ f8_dci(); break; + case 0x2b: /* 0010 1011 */ f8_nop(); break; + case 0x2c: /* 0010 1100 */ f8_xdc(); break; + case 0x2d: /* 0010 1101 */ illegal(); break; + case 0x2e: /* 0010 1110 */ illegal(); break; + case 0x2f: /* 0010 1111 */ illegal(); break; + + case 0x30: /* 0011 0000 */ f8_ds_r( 0); break; + case 0x31: /* 0011 0001 */ f8_ds_r( 1); break; + case 0x32: /* 0011 0010 */ f8_ds_r( 2); break; + case 0x33: /* 0011 0011 */ f8_ds_r( 3); break; + case 0x34: /* 0011 0100 */ f8_ds_r( 4); break; + case 0x35: /* 0011 0101 */ f8_ds_r( 5); break; + case 0x36: /* 0011 0110 */ f8_ds_r( 6); break; + case 0x37: /* 0011 0111 */ f8_ds_r( 7); break; + case 0x38: /* 0011 1000 */ f8_ds_r( 8); break; + case 0x39: /* 0011 1001 */ f8_ds_r( 9); break; + case 0x3a: /* 0011 1010 */ f8_ds_r(10); break; + case 0x3b: /* 0011 1011 */ f8_ds_r(11); break; + case 0x3c: /* 0011 1100 */ f8_ds_isar(); break; + case 0x3d: /* 0011 1101 */ f8_ds_isar_i(); break; + case 0x3e: /* 0011 1110 */ f8_ds_isar_d(); break; + case 0x3f: /* 0011 1111 */ illegal(); break; + + case 0x40: /* 0100 0000 */ f8_lr_a_r( 0); break; + case 0x41: /* 0100 0001 */ f8_lr_a_r( 1); break; + case 0x42: /* 0100 0010 */ f8_lr_a_r( 2); break; + case 0x43: /* 0100 0011 */ f8_lr_a_r( 3); break; + case 0x44: /* 0100 0100 */ f8_lr_a_r( 4); break; + case 0x45: /* 0100 0101 */ f8_lr_a_r( 5); break; + case 0x46: /* 0100 0110 */ f8_lr_a_r( 6); break; + case 0x47: /* 0100 0111 */ f8_lr_a_r( 7); break; + case 0x48: /* 0100 1000 */ f8_lr_a_r( 8); break; + case 0x49: /* 0100 1001 */ f8_lr_a_r( 9); break; + case 0x4a: /* 0100 1010 */ f8_lr_a_r(10); break; + case 0x4b: /* 0100 1011 */ f8_lr_a_r(11); break; + case 0x4c: /* 0100 1100 */ f8_lr_a_isar(); break; + case 0x4d: /* 0100 1101 */ f8_lr_a_isar_i(); break; + case 0x4e: /* 0100 1110 */ f8_lr_a_isar_d(); break; + case 0x4f: /* 0100 1111 */ illegal(); break; + + case 0x50: /* 0101 0000 */ f8_lr_r_a( 0); break; + case 0x51: /* 0101 0001 */ f8_lr_r_a( 1); break; + case 0x52: /* 0101 0010 */ f8_lr_r_a( 2); break; + case 0x53: /* 0101 0011 */ f8_lr_r_a( 3); break; + case 0x54: /* 0101 0100 */ f8_lr_r_a( 4); break; + case 0x55: /* 0101 0101 */ f8_lr_r_a( 5); break; + case 0x56: /* 0101 0110 */ f8_lr_r_a( 6); break; + case 0x57: /* 0101 0111 */ f8_lr_r_a( 7); break; + case 0x58: /* 0101 1000 */ f8_lr_r_a( 8); break; + case 0x59: /* 0101 1001 */ f8_lr_r_a( 9); break; + case 0x5a: /* 0101 1010 */ f8_lr_r_a(10); break; + case 0x5b: /* 0101 1011 */ f8_lr_r_a(11); break; + case 0x5c: /* 0101 1100 */ f8_lr_isar_a(); break; + case 0x5d: /* 0101 1101 */ f8_lr_isar_i_a(); break; + case 0x5e: /* 0101 1110 */ f8_lr_isar_d_a(); break; + case 0x5f: /* 0101 1111 */ illegal(); break; + + case 0x60: /* 0110 0000 */ f8_lisu(0x00); break; + case 0x61: /* 0110 0001 */ f8_lisu(0x08); break; + case 0x62: /* 0110 0010 */ f8_lisu(0x10); break; + case 0x63: /* 0110 0011 */ f8_lisu(0x18); break; + case 0x64: /* 0110 0100 */ f8_lisu(0x20); break; + case 0x65: /* 0110 0101 */ f8_lisu(0x28); break; + case 0x66: /* 0110 0110 */ f8_lisu(0x30); break; + case 0x67: /* 0110 0111 */ f8_lisu(0x38); break; + case 0x68: /* 0110 1000 */ f8_lisl(0x00); break; + case 0x69: /* 0110 1001 */ f8_lisl(0x01); break; + case 0x6a: /* 0110 1010 */ f8_lisl(0x02); break; + case 0x6b: /* 0110 1011 */ f8_lisl(0x03); break; + case 0x6c: /* 0110 1100 */ f8_lisl(0x04); break; + case 0x6d: /* 0110 1101 */ f8_lisl(0x05); break; + case 0x6e: /* 0110 1110 */ f8_lisl(0x06); break; + case 0x6f: /* 0110 1111 */ f8_lisl(0x07); break; + + case 0x70: /* 0111 0000 */ f8_lis(0x0); break; + case 0x71: /* 0111 0001 */ f8_lis(0x1); break; + case 0x72: /* 0111 0010 */ f8_lis(0x2); break; + case 0x73: /* 0111 0011 */ f8_lis(0x3); break; + case 0x74: /* 0111 0100 */ f8_lis(0x4); break; + case 0x75: /* 0111 0101 */ f8_lis(0x5); break; + case 0x76: /* 0111 0110 */ f8_lis(0x6); break; + case 0x77: /* 0111 0111 */ f8_lis(0x7); break; + case 0x78: /* 0111 1000 */ f8_lis(0x8); break; + case 0x79: /* 0111 1001 */ f8_lis(0x9); break; + case 0x7a: /* 0111 1010 */ f8_lis(0xa); break; + case 0x7b: /* 0111 1011 */ f8_lis(0xb); break; + case 0x7c: /* 0111 1100 */ f8_lis(0xc); break; + case 0x7d: /* 0111 1101 */ f8_lis(0xd); break; + case 0x7e: /* 0111 1110 */ f8_lis(0xe); break; + case 0x7f: /* 0111 1111 */ f8_lis(0xf); break; + + case 0x80: /* 1000 0000 */ f8_bt(0); break; + case 0x81: /* 1000 0001 */ f8_bt(1); break; + case 0x82: /* 1000 0010 */ f8_bt(2); break; + case 0x83: /* 1000 0011 */ f8_bt(3); break; + case 0x84: /* 1000 0100 */ f8_bt(4); break; + case 0x85: /* 1000 0101 */ f8_bt(5); break; + case 0x86: /* 1000 0110 */ f8_bt(6); break; + case 0x87: /* 1000 0111 */ f8_bt(7); break; + case 0x88: /* 1000 1000 */ f8_am(); break; + case 0x89: /* 1000 1001 */ f8_amd(); break; + case 0x8a: /* 1000 1010 */ f8_nm(); break; + case 0x8b: /* 1000 1011 */ f8_om(); break; + case 0x8c: /* 1000 1100 */ f8_xm(); break; + case 0x8d: /* 1000 1101 */ f8_cm(); break; + case 0x8e: /* 1000 1110 */ f8_adc(); break; + case 0x8f: /* 1000 1111 */ f8_br7(); break; + + case 0x90: /* 1001 0000 */ f8_bf(0x0); break; + case 0x91: /* 1001 0001 */ f8_bf(0x1); break; + case 0x92: /* 1001 0010 */ f8_bf(0x2); break; + case 0x93: /* 1001 0011 */ f8_bf(0x3); break; + case 0x94: /* 1001 0100 */ f8_bf(0x4); break; + case 0x95: /* 1001 0101 */ f8_bf(0x5); break; + case 0x96: /* 1001 0110 */ f8_bf(0x6); break; + case 0x97: /* 1001 0111 */ f8_bf(0x7); break; + case 0x98: /* 1001 1000 */ f8_bf(0x8); break; + case 0x99: /* 1001 1001 */ f8_bf(0x9); break; + case 0x9a: /* 1001 1010 */ f8_bf(0xa); break; + case 0x9b: /* 1001 1011 */ f8_bf(0xb); break; + case 0x9c: /* 1001 1100 */ f8_bf(0xc); break; + case 0x9d: /* 1001 1101 */ f8_bf(0xd); break; + case 0x9e: /* 1001 1110 */ f8_bf(0xe); break; + case 0x9f: /* 1001 1111 */ f8_bf(0xf); break; + + case 0xa0: /* 1010 0000 */ f8_ins_0(0x0); break; + case 0xa1: /* 1010 0001 */ f8_ins_0(0x1); break; + case 0xa2: /* 1010 0010 */ illegal(); break; + case 0xa3: /* 1010 0011 */ illegal(); break; + case 0xa4: /* 1010 0100 */ f8_ins_1(0x4); break; + case 0xa5: /* 1010 0101 */ f8_ins_1(0x5); break; + case 0xa6: /* 1010 0110 */ f8_ins_1(0x6); break; + case 0xa7: /* 1010 0111 */ f8_ins_1(0x7); break; + case 0xa8: /* 1010 1000 */ f8_ins_1(0x8); break; + case 0xa9: /* 1010 1001 */ f8_ins_1(0x9); break; + case 0xaa: /* 1010 1010 */ f8_ins_1(0xa); break; + case 0xab: /* 1010 1011 */ f8_ins_1(0xb); break; + case 0xac: /* 1010 1100 */ f8_ins_1(0xc); break; + case 0xad: /* 1010 1101 */ f8_ins_1(0xd); break; + case 0xae: /* 1010 1110 */ f8_ins_1(0xe); break; + case 0xaf: /* 1010 1111 */ f8_ins_1(0xf); break; + + case 0xb0: /* 1011 0000 */ f8_outs_0(0x0); break; + case 0xb1: /* 1011 0001 */ f8_outs_0(0x1); break; + case 0xb2: /* 1011 0010 */ illegal(); break; + case 0xb3: /* 1011 0011 */ illegal(); break; + case 0xb4: /* 1011 0100 */ f8_outs_1(0x4); break; + case 0xb5: /* 1011 0101 */ f8_outs_1(0x5); break; + case 0xb6: /* 1011 0110 */ f8_outs_1(0x6); break; + case 0xb7: /* 1011 0111 */ f8_outs_1(0x7); break; + case 0xb8: /* 1011 1000 */ f8_outs_1(0x8); break; + case 0xb9: /* 1011 1001 */ f8_outs_1(0x9); break; + case 0xba: /* 1011 1010 */ f8_outs_1(0xa); break; + case 0xbb: /* 1011 1011 */ f8_outs_1(0xb); break; + case 0xbc: /* 1011 1100 */ f8_outs_1(0xc); break; + case 0xbd: /* 1011 1101 */ f8_outs_1(0xd); break; + case 0xbe: /* 1011 1110 */ f8_outs_1(0xe); break; + case 0xbf: /* 1011 1111 */ f8_outs_1(0xf); break; + + case 0xc0: /* 1100 0000 */ f8_as(0x0); break; + case 0xc1: /* 1100 0001 */ f8_as(0x1); break; + case 0xc2: /* 1100 0010 */ f8_as(0x2); break; + case 0xc3: /* 1100 0011 */ f8_as(0x3); break; + case 0xc4: /* 1100 0100 */ f8_as(0x4); break; + case 0xc5: /* 1100 0101 */ f8_as(0x5); break; + case 0xc6: /* 1100 0110 */ f8_as(0x6); break; + case 0xc7: /* 1100 0111 */ f8_as(0x7); break; + case 0xc8: /* 1100 1000 */ f8_as(0x8); break; + case 0xc9: /* 1100 1001 */ f8_as(0x9); break; + case 0xca: /* 1100 1010 */ f8_as(0xa); break; + case 0xcb: /* 1100 1011 */ f8_as(0xb); break; + case 0xcc: /* 1100 1100 */ f8_as_isar(); break; + case 0xcd: /* 1100 1101 */ f8_as_isar_i(); break; + case 0xce: /* 1100 1110 */ f8_as_isar_d(); break; + case 0xcf: /* 1100 1111 */ illegal(); break; + + case 0xd0: /* 1101 0000 */ f8_asd(0x0); break; + case 0xd1: /* 1101 0001 */ f8_asd(0x1); break; + case 0xd2: /* 1101 0010 */ f8_asd(0x2); break; + case 0xd3: /* 1101 0011 */ f8_asd(0x3); break; + case 0xd4: /* 1101 0100 */ f8_asd(0x4); break; + case 0xd5: /* 1101 0101 */ f8_asd(0x5); break; + case 0xd6: /* 1101 0110 */ f8_asd(0x6); break; + case 0xd7: /* 1101 0111 */ f8_asd(0x7); break; + case 0xd8: /* 1101 1000 */ f8_asd(0x8); break; + case 0xd9: /* 1101 1001 */ f8_asd(0x9); break; + case 0xda: /* 1101 1010 */ f8_asd(0xa); break; + case 0xdb: /* 1101 1011 */ f8_asd(0xb); break; + case 0xdc: /* 1101 1100 */ f8_asd_isar(); break; + case 0xdd: /* 1101 1101 */ f8_asd_isar_i(); break; + case 0xde: /* 1101 1110 */ f8_asd_isar_d(); break; + case 0xdf: /* 1101 1111 */ illegal(); break; + + case 0xe0: /* 1110 0000 */ f8_xs(0x0); break; + case 0xe1: /* 1110 0001 */ f8_xs(0x1); break; + case 0xe2: /* 1110 0010 */ f8_xs(0x2); break; + case 0xe3: /* 1110 0011 */ f8_xs(0x3); break; + case 0xe4: /* 1110 0100 */ f8_xs(0x4); break; + case 0xe5: /* 1110 0101 */ f8_xs(0x5); break; + case 0xe6: /* 1110 0110 */ f8_xs(0x6); break; + case 0xe7: /* 1110 0111 */ f8_xs(0x7); break; + case 0xe8: /* 1110 1000 */ f8_xs(0x8); break; + case 0xe9: /* 1110 1001 */ f8_xs(0x9); break; + case 0xea: /* 1110 1010 */ f8_xs(0xa); break; + case 0xeb: /* 1110 1011 */ f8_xs(0xb); break; + case 0xec: /* 1110 1100 */ f8_xs_isar(); break; + case 0xed: /* 1110 1101 */ f8_xs_isar_i(); break; + case 0xee: /* 1110 1110 */ f8_xs_isar_d(); break; + case 0xef: /* 1110 1111 */ illegal(); break; + + case 0xf0: /* 1111 0000 */ f8_ns(0x0); break; + case 0xf1: /* 1111 0001 */ f8_ns(0x1); break; + case 0xf2: /* 1111 0010 */ f8_ns(0x2); break; + case 0xf3: /* 1111 0011 */ f8_ns(0x3); break; + case 0xf4: /* 1111 0100 */ f8_ns(0x4); break; + case 0xf5: /* 1111 0101 */ f8_ns(0x5); break; + case 0xf6: /* 1111 0110 */ f8_ns(0x6); break; + case 0xf7: /* 1111 0111 */ f8_ns(0x7); break; + case 0xf8: /* 1111 1000 */ f8_ns(0x8); break; + case 0xf9: /* 1111 1001 */ f8_ns(0x9); break; + case 0xfa: /* 1111 1010 */ f8_ns(0xa); break; + case 0xfb: /* 1111 1011 */ f8_ns(0xb); break; + case 0xfc: /* 1111 1100 */ f8_ns_isar(); break; + case 0xfd: /* 1111 1101 */ f8_ns_isar_i(); break; + case 0xfe: /* 1111 1110 */ f8_ns_isar_d(); break; + case 0xff: /* 1111 1111 */ illegal(); break; + } + switch (op) { + case 0x0d: case 0x1b: case 0x1c: case 0x1d: + case 0x27: case 0x28: case 0x29: + case 0xb4: case 0xb5: case 0xb6: case 0xb7: + case 0xb8: case 0xb9: case 0xba: case 0xbb: + case 0xbc: case 0xbd: case 0xbe: case 0xbf: + ROMC_00(cS); + break; + + default: + if (m_w&I && m_irq_request) + { + ROMC_1C(cL); + ROMC_0F(); + ROMC_13(); + } + if( ( op >= 0x30 ) && ( op <= 0x3f) ) /* SKR - DS is a long cycle inst */ + { + ROMC_00(cL); + } + else + { + ROMC_00(cS); + } + break; + } + } while( m_icount > 0 ); +} + + +void f8_cpu_device::device_start() +{ + // TODO register debug state + m_program = &space(AS_PROGRAM); + m_direct = &m_program->direct(); + m_iospace = &space(AS_IO); + + save_item(NAME(m_pc0)); + save_item(NAME(m_pc1)); + save_item(NAME(m_dc0)); + save_item(NAME(m_dc1)); + save_item(NAME(m_a)); + save_item(NAME(m_w)); + save_item(NAME(m_is)); + save_item(NAME(m_dbus)); + save_item(NAME(m_io)); + save_item(NAME(m_irq_vector)); + save_item(NAME(m_irq_request)); + save_item(NAME(m_r)); + + state_add( F8_PC0, "PC0", m_pc0).formatstr("%04X"); + state_add( F8_PC1, "PC1", m_pc1).formatstr("%04X"); + state_add( F8_DC0, "DC0", m_dc0).formatstr("%04X"); + state_add( F8_DC1, "DC1", m_dc1).formatstr("%04X"); + state_add( F8_W, "W", m_w).formatstr("%02X"); + state_add( F8_A, "A", m_a).formatstr("%02X"); + state_add( F8_IS, "IS", m_is).mask(0x3f).formatstr("%02X"); + state_add( F8_J, "J", m_r[9]).formatstr("%02X"); + state_add( F8_HU, "HU", m_r[10]).formatstr("%02X"); + state_add( F8_HL, "HL", m_r[11]).formatstr("%02X"); + state_add( F8_KU, "KU", m_r[12]).formatstr("%02X"); + state_add( F8_KL, "KL", m_r[13]).formatstr("%02X"); + state_add( F8_QU, "QU", m_r[14]).formatstr("%02X"); + state_add( F8_QL, "QL", m_r[15]).formatstr("%02X"); + state_add( F8_R0, "R0", m_r[0]).formatstr("%02X"); + state_add( F8_R1, "R1", m_r[1]).formatstr("%02X"); + state_add( F8_R2, "R2", m_r[2]).formatstr("%02X"); + state_add( F8_R3, "R3", m_r[3]).formatstr("%02X"); + state_add( F8_R4, "R4", m_r[4]).formatstr("%02X"); + state_add( F8_R5, "R5", m_r[5]).formatstr("%02X"); + state_add( F8_R6, "R6", m_r[6]).formatstr("%02X"); + state_add( F8_R7, "R7", m_r[7]).formatstr("%02X"); + state_add( F8_R8, "R8", m_r[8]).formatstr("%02X"); + state_add( F8_R16, "R16", m_r[16]).formatstr("%02X"); + state_add( F8_R17, "R17", m_r[17]).formatstr("%02X"); + state_add( F8_R18, "R18", m_r[18]).formatstr("%02X"); + state_add( F8_R19, "R19", m_r[19]).formatstr("%02X"); + state_add( F8_R20, "R20", m_r[20]).formatstr("%02X"); + state_add( F8_R21, "R21", m_r[21]).formatstr("%02X"); + state_add( F8_R22, "R22", m_r[22]).formatstr("%02X"); + state_add( F8_R23, "R23", m_r[23]).formatstr("%02X"); + state_add( F8_R24, "R24", m_r[24]).formatstr("%02X"); + state_add( F8_R25, "R25", m_r[25]).formatstr("%02X"); + state_add( F8_R26, "R26", m_r[26]).formatstr("%02X"); + state_add( F8_R27, "R27", m_r[27]).formatstr("%02X"); + state_add( F8_R28, "R28", m_r[28]).formatstr("%02X"); + state_add( F8_R29, "R29", m_r[29]).formatstr("%02X"); + state_add( F8_R30, "R30", m_r[30]).formatstr("%02X"); + state_add( F8_R31, "R31", m_r[31]).formatstr("%02X"); + state_add( F8_R32, "R32", m_r[32]).formatstr("%02X"); + state_add( F8_R33, "R33", m_r[33]).formatstr("%02X"); + state_add( F8_R34, "R34", m_r[34]).formatstr("%02X"); + state_add( F8_R35, "R35", m_r[35]).formatstr("%02X"); + state_add( F8_R36, "R36", m_r[36]).formatstr("%02X"); + state_add( F8_R37, "R37", m_r[37]).formatstr("%02X"); + state_add( F8_R38, "R38", m_r[38]).formatstr("%02X"); + state_add( F8_R39, "R39", m_r[39]).formatstr("%02X"); + state_add( F8_R40, "R40", m_r[40]).formatstr("%02X"); + state_add( F8_R41, "R41", m_r[41]).formatstr("%02X"); + state_add( F8_R42, "R42", m_r[42]).formatstr("%02X"); + state_add( F8_R43, "R43", m_r[43]).formatstr("%02X"); + state_add( F8_R44, "R44", m_r[44]).formatstr("%02X"); + state_add( F8_R45, "R45", m_r[45]).formatstr("%02X"); + state_add( F8_R46, "R46", m_r[46]).formatstr("%02X"); + state_add( F8_R47, "R47", m_r[47]).formatstr("%02X"); + state_add( F8_R48, "R48", m_r[48]).formatstr("%02X"); + state_add( F8_R49, "R49", m_r[49]).formatstr("%02X"); + state_add( F8_R50, "R50", m_r[50]).formatstr("%02X"); + state_add( F8_R51, "R51", m_r[51]).formatstr("%02X"); + state_add( F8_R52, "R52", m_r[52]).formatstr("%02X"); + state_add( F8_R53, "R53", m_r[53]).formatstr("%02X"); + state_add( F8_R54, "R54", m_r[54]).formatstr("%02X"); + state_add( F8_R55, "R55", m_r[55]).formatstr("%02X"); + state_add( F8_R56, "R56", m_r[56]).formatstr("%02X"); + state_add( F8_R57, "R57", m_r[57]).formatstr("%02X"); + state_add( F8_R58, "R58", m_r[58]).formatstr("%02X"); + state_add( F8_R59, "R59", m_r[59]).formatstr("%02X"); + state_add( F8_R60, "R60", m_r[60]).formatstr("%02X"); + state_add( F8_R61, "R61", m_r[61]).formatstr("%02X"); + state_add( F8_R62, "R62", m_r[62]).formatstr("%02X"); + state_add( F8_R63, "R63", m_r[63]).formatstr("%02X"); + + state_add(STATE_GENPC, "curpc", m_pc).formatstr("%04X").noshow(); + state_add(STATE_GENFLAGS, "GENFLAGS", m_w).formatstr("%5s").noshow(); + + m_icountptr = &m_icount; +} + + +void f8_cpu_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + switch (entry.index()) + { + case STATE_GENFLAGS: + strprintf(str, "%c%c%c%c%c", + m_w & 0x10 ? 'I':'.', + m_w & 0x08 ? 'O':'.', + m_w & 0x04 ? 'Z':'.', + m_w & 0x02 ? 'C':'.', + m_w & 0x01 ? 'S':'.'); + break; + } +} + + +offs_t f8_cpu_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( f8 ); + return CPU_DISASSEMBLE_NAME(f8)(this, buffer, pc, oprom, opram, options); +} + + +void f8_cpu_device::execute_set_input( int inptnum, int state ) +{ + m_irq_request = state; +} diff --git a/src/devices/cpu/f8/f8.h b/src/devices/cpu/f8/f8.h new file mode 100644 index 00000000000..a478cf137b1 --- /dev/null +++ b/src/devices/cpu/f8/f8.h @@ -0,0 +1,217 @@ +// license:BSD-3-Clause +// copyright-holders:Juergen Buchmueller +/***************************************************************************** + * + * f8.h + * Portable Fairchild F8 emulator interface + * + *****************************************************************************/ + +#pragma once + +#ifndef __F8_H__ +#define _F8_H + + +enum +{ + F8_PC0=1, F8_PC1, F8_DC0, F8_DC1, F8_W, F8_A, F8_IS, + F8_J, F8_HU, F8_HL, F8_KU, F8_KL, F8_QU, F8_QL, + + F8_R0, F8_R1, F8_R2, F8_R3, F8_R4, F8_R5, F8_R6, F8_R7, F8_R8, + F8_R16, F8_R17, F8_R18, F8_R19, F8_R20, F8_R21, F8_R22, F8_R23, + F8_R24, F8_R25, F8_R26, F8_R27, F8_R28, F8_R29, F8_R30, F8_R31, + F8_R32, F8_R33, F8_R34, F8_R35, F8_R36, F8_R37, F8_R38, F8_R39, + F8_R40, F8_R41, F8_R42, F8_R43, F8_R44, F8_R45, F8_R46, F8_R47, + F8_R48, F8_R49, F8_R50, F8_R51, F8_R52, F8_R53, F8_R54, F8_R55, + F8_R56, F8_R57, F8_R58, F8_R59, F8_R60, F8_R61, F8_R62, F8_R63 +}; + +#define F8_INPUT_LINE_INT_REQ 1 + +class f8_cpu_device : public cpu_device +{ +public: + // construction/destruction + f8_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_execute_interface overrides + virtual UINT32 execute_min_cycles() const { return 1; } + virtual UINT32 execute_max_cycles() const { return 7; } + virtual UINT32 execute_input_lines() const { return 1; } + virtual void execute_run(); + virtual void execute_set_input(int inputnum, int state); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const { return (spacenum == AS_PROGRAM) ? &m_program_config : ( (spacenum == AS_IO) ? &m_io_config : NULL ); } + + // device_state_interface overrides + void state_string_export(const device_state_entry &entry, std::string &str); + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const { return 1; } + virtual UINT32 disasm_max_opcode_bytes() const { return 3; } + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + +private: + address_space_config m_program_config; + address_space_config m_io_config; + + UINT16 m_pc0; /* program counter 0 */ + UINT16 m_pc1; /* program counter 1 */ + UINT16 m_dc0; /* data counter 0 */ + UINT16 m_dc1; /* data counter 1 */ + UINT8 m_a; /* accumulator */ + UINT8 m_w; /* processor status */ + UINT8 m_is; /* scratchpad pointer */ + UINT8 m_dbus; /* data bus value */ + UINT16 m_io; /* last I/O address */ + UINT16 m_irq_vector; + address_space *m_program; + direct_read_data *m_direct; + address_space *m_iospace; + int m_icount; + UINT8 m_r[64]; /* scratchpad RAM */ + int m_irq_request; + + /* timer shifter polynome values (will be used for timer interrupts) */ + UINT8 timer_shifter[256]; + + UINT16 m_pc; // For the debugger + + void ROMC_00(int insttim); + void ROMC_01(); + void ROMC_02(); + void ROMC_03(int insttim); + void ROMC_04(); + void ROMC_05(); + void ROMC_06(); + void ROMC_07(); + void ROMC_08(); + void ROMC_09(); + void ROMC_0A(); + void ROMC_0B(); + void ROMC_0C(); + void ROMC_0D(); + void ROMC_0E(); + void ROMC_0F(); + void ROMC_10(); + void ROMC_11(); + void ROMC_12(); + void ROMC_13(); + void ROMC_14(); + void ROMC_15(); + void ROMC_16(); + void ROMC_17(); + void ROMC_18(); + void ROMC_19(); + void ROMC_1A(); + void ROMC_1B(); + void ROMC_1C(int insttim); + void ROMC_1D(); + void ROMC_1E(); + void ROMC_1F(); + void illegal(); + void f8_lr_a_ku(); + void f8_lr_a_kl(); + void f8_lr_a_qu(); + void f8_lr_a_ql(); + void f8_lr_ku_a(); + void f8_lr_kl_a(); + void f8_lr_qu_a(); + void f8_lr_ql_a(); + void f8_lr_k_p(); + void f8_lr_p_k(); + void f8_lr_a_is(); + void f8_lr_is_a(); + void f8_pk(); + void f8_lr_p0_q(); + void f8_lr_q_dc(); + void f8_lr_dc_q(); + void f8_lr_dc_h(); + void f8_lr_h_dc(); + void f8_sr_1(); + void f8_sl_1(); + void f8_sr_4(); + void f8_sl_4(); + void f8_lm(); + void f8_st(); + void f8_com(); + void f8_lnk(); + void f8_di(); + void f8_ei(); + void f8_pop(); + void f8_lr_w_j(); + void f8_lr_j_w(); + void f8_inc(); + void f8_li(); + void f8_ni(); + void f8_oi(); + void f8_xi(); + void f8_ai(); + void f8_ci(); + void f8_in(); + void f8_out(); + void f8_pi(); + void f8_jmp(); + void f8_dci(); + void f8_nop(); + void f8_xdc(); + void f8_ds_r(int r); + void f8_ds_isar(); + void f8_ds_isar_i(); + void f8_ds_isar_d(); + void f8_lr_a_r(int r); + void f8_lr_a_isar(); + void f8_lr_a_isar_i(); + void f8_lr_a_isar_d(); + void f8_lr_r_a(int r); + void f8_lr_isar_a(); + void f8_lr_isar_i_a(); + void f8_lr_isar_d_a(); + void f8_lisu(int e); + void f8_lisl(int e); + void f8_lis(int i); + void f8_bt(int e); + void f8_am(); + void f8_amd(); + void f8_nm(); + void f8_om(); + void f8_xm(); + void f8_cm(); /* SKR changed to match f8_ci(cpustate); */ + void f8_adc(); + void f8_br7(); + void f8_bf(int t); + void f8_ins_0(int n); + void f8_ins_1(int n); + void f8_outs_0(int n); + void f8_outs_1(int n); + void f8_as(int r); + void f8_as_isar(); + void f8_as_isar_i(); + void f8_as_isar_d(); + void f8_asd(int r); + void f8_asd_isar(); + void f8_asd_isar_i(); + void f8_asd_isar_d(); + void f8_xs(int r); + void f8_xs_isar(); + void f8_xs_isar_i(); + void f8_xs_isar_d(); + void f8_ns(int r); + void f8_ns_isar(); + void f8_ns_isar_i(); + void f8_ns_isar_d(); + +}; + + +extern const device_type F8; + + +#endif /* __F8_H__ */ diff --git a/src/devices/cpu/f8/f8dasm.c b/src/devices/cpu/f8/f8dasm.c new file mode 100644 index 00000000000..03e3d3065ea --- /dev/null +++ b/src/devices/cpu/f8/f8dasm.c @@ -0,0 +1,534 @@ +// license:BSD-3-Clause +// copyright-holders:Juergen Buchmueller +#include "emu.h" +#include "debugger.h" +#include "f8.h" + +static const char *const rname[16] = { + "R0", "R1", "R2", "R3", "R4", "R5", "R6", "R7", + "R8", "J", "HU", "HL", "KU", "KL", "QU", "QL" +}; + +CPU_DISASSEMBLE( f8 ) +{ + unsigned size = 0; + UINT8 op = oprom[size++]; + + switch( op ) + { + /* opcode bitmask */ + case 0x00: /* 0000 0000 */ + sprintf(buffer, "LR A,KU"); + break; + case 0x01: /* 0000 0001 */ + sprintf(buffer, "LR A,KL"); + break; + case 0x02: /* 0000 0010 */ + sprintf(buffer, "LR A,QU"); + break; + case 0x03: /* 0000 0011 */ + sprintf(buffer, "LR A,QL"); + break; + case 0x04: /* 0000 0100 */ + sprintf(buffer, "LR KU,A"); + break; + case 0x05: /* 0000 0101 */ + sprintf(buffer, "LR KL,A"); + break; + case 0x06: /* 0000 0110 */ + sprintf(buffer, "LR QU,A"); + break; + case 0x07: /* 0000 0111 */ + sprintf(buffer, "LR QL,A"); + break; + + case 0x08: /* 0000 1000 */ + sprintf(buffer, "LR K,P"); + break; + case 0x09: /* 0000 1001 */ + sprintf(buffer, "LR P,K"); + break; + case 0x0a: /* 0000 1010 */ + sprintf(buffer, "LR A,IS"); + break; + case 0x0b: /* 0000 1011 */ + sprintf(buffer, "LR IS,A"); + break; + + case 0x0c: /* 0000 1100 */ + sprintf(buffer, "PK") ; + break; + case 0x0d: /* 0000 1101 */ + sprintf(buffer, "LR P0,Q"); + break; + case 0x0e: /* 0000 1110 */ + sprintf(buffer, "LR Q,DC"); + break; + case 0x0f: /* 0000 1111 */ + sprintf(buffer, "LR DC,Q"); + break; + case 0x10: /* 0001 0000 */ + sprintf(buffer, "LR DC,H"); + break; + case 0x11: /* 0001 0001 */ + sprintf(buffer, "LR H,DC"); + break; + case 0x12: /* 0001 0010 */ + sprintf(buffer, "SR 1"); + break; + case 0x13: /* 0001 0011 */ + sprintf(buffer, "SL 1"); + break; + case 0x14: /* 0001 0100 */ + sprintf(buffer, "SR 4"); + break; + case 0x15: /* 0001 0101 */ + sprintf(buffer, "SL 4"); + break; + case 0x16: /* 0001 0110 */ + sprintf(buffer, "LM") ; + break; + case 0x17: /* 0001 0111 */ + sprintf(buffer, "ST"); + break; + case 0x18: /* 0001 1000 */ + sprintf(buffer, "COM"); + break; + case 0x19: /* 0001 1001 */ + sprintf(buffer, "LNK"); + break; + case 0x1a: /* 0001 1010 */ + sprintf(buffer, "DI"); + break; + case 0x1b: /* 0001 1011 */ + sprintf(buffer, "EI"); + break; + case 0x1c: /* 0001 1100 */ + sprintf(buffer, "POP"); + break; + case 0x1d: /* 0001 1101 */ + sprintf(buffer, "LR W,J"); + break; + case 0x1e: /* 0001 1110 */ + sprintf(buffer, "LR J,W"); + break; + case 0x1f: /* 0001 1111 */ + sprintf(buffer, "INC"); + break; + case 0x20: /* 0010 0000 */ + sprintf(buffer, "LI $%02X", oprom[size++]); + break; + case 0x21: /* 0010 0001 */ + sprintf(buffer, "NI $%02X", oprom[size++]); + break; + case 0x22: /* 0010 0010 */ + sprintf(buffer, "OI $%02X", oprom[size++]); + break; + case 0x23: /* 0010 0011 */ + sprintf(buffer, "XI $%02X", oprom[size++]); + break; + case 0x24: /* 0010 0100 */ + sprintf(buffer, "AI $%02X", oprom[size++]); + break; + case 0x25: /* 0010 0101 */ + sprintf(buffer, "CI $%02X", oprom[size++]); + break; + case 0x26: /* 0010 0110 */ + sprintf(buffer, "IN $%02X", oprom[size++]); + break; + case 0x27: /* 0010 0111 */ + sprintf(buffer, "OUT $%02X", oprom[size++]); + break; + case 0x28: /* 0010 1000 */ + sprintf(buffer, "PI $%02X%02X", oprom[size + 0], oprom[size + 1]); + size += 2; + break; + case 0x29: /* 0010 1001 */ + sprintf(buffer, "JMP $%02X%02X", oprom[size + 0], oprom[size + 1]); + size += 2; + break; + case 0x2a: /* 0010 1010 */ + sprintf(buffer, "DCI $%02X%02X", oprom[size + 0], oprom[size + 1]); + size += 2; + break; + case 0x2b: /* 0010 1011 */ + sprintf(buffer, "NOP"); + break; + case 0x2c: /* 0010 1100 */ + sprintf(buffer, "XDC"); + break; + case 0x2d: /* 0010 1101 */ + case 0x2e: /* 0010 1110 */ + case 0x2f: /* 0010 1111 */ + sprintf(buffer, "??? $%02X",op); + break; + + case 0x30: /* 0011 0000 */ + case 0x31: /* 0011 0001 */ + case 0x32: /* 0011 0010 */ + case 0x33: /* 0011 0011 */ + case 0x34: /* 0011 0100 */ + case 0x35: /* 0011 0101 */ + case 0x36: /* 0011 0110 */ + case 0x37: /* 0011 0111 */ + case 0x38: /* 0011 1000 */ + case 0x39: /* 0011 1001 */ + case 0x3a: /* 0011 1010 */ + case 0x3b: /* 0011 1011 */ + sprintf(buffer, "DS %s",rname[op & 15]); + break; + case 0x3c: /* 0011 1100 */ + sprintf(buffer, "DS (IS)"); + break; + case 0x3d: /* 0011 1101 */ + sprintf(buffer, "DS (IS++)"); + break; + case 0x3e: /* 0011 1110 */ + sprintf(buffer, "DS (IS--)"); + break; + case 0x3f: /* 0011 1111 */ + sprintf(buffer, "??? $%02X",op); + break; + + case 0x40: /* 0100 0000 */ + case 0x41: /* 0100 0001 */ + case 0x42: /* 0100 0010 */ + case 0x43: /* 0100 0011 */ + case 0x44: /* 0100 0100 */ + case 0x45: /* 0100 0101 */ + case 0x46: /* 0100 0110 */ + case 0x47: /* 0100 0111 */ + case 0x48: /* 0100 1000 */ + case 0x49: /* 0100 1001 */ + case 0x4a: /* 0100 1010 */ + case 0x4b: /* 0100 1011 */ + sprintf(buffer, "LR A,%s",rname[op & 15]); + break; + case 0x4c: /* 0100 1100 */ + sprintf(buffer, "LR A,(IS)"); + break; + case 0x4d: /* 0100 1101 */ + sprintf(buffer, "LR A,(IS++)"); + break; + case 0x4e: /* 0100 1110 */ + sprintf(buffer, "LR A,(IS--)"); + break; + case 0x4f: /* 0100 1111 */ + sprintf(buffer, "??? $%02X",op); + break; + + case 0x50: /* 0101 0000 */ + case 0x51: /* 0101 0001 */ + case 0x52: /* 0101 0010 */ + case 0x53: /* 0101 0011 */ + case 0x54: /* 0101 0100 */ + case 0x55: /* 0101 0101 */ + case 0x56: /* 0101 0110 */ + case 0x57: /* 0101 0111 */ + case 0x58: /* 0101 1000 */ + case 0x59: /* 0101 1001 */ + case 0x5a: /* 0101 1010 */ + case 0x5b: /* 0101 1011 */ + sprintf(buffer, "LR %s,A",rname[op & 15]); + break; + case 0x5c: /* 0101 1100 */ + sprintf(buffer, "LR (IS),A"); + break; + case 0x5d: /* 0101 1101 */ + sprintf(buffer, "LR (IS++),A"); + break; + case 0x5e: /* 0101 1110 */ + sprintf(buffer, "LR (IS--),A"); + break; + case 0x5f: /* 0101 1111 */ + sprintf(buffer, "??? $%02X",op); + break; + + case 0x60: /* 0110 0000 */ + case 0x61: /* 0110 0001 */ + case 0x62: /* 0110 0010 */ + case 0x63: /* 0110 0011 */ + case 0x64: /* 0110 0100 */ + case 0x65: /* 0110 0101 */ + case 0x66: /* 0110 0110 */ + case 0x67: /* 0110 0111 */ + sprintf(buffer, "LISU $%02X", op & 0x07); + break; + case 0x68: /* 0110 1000 */ + case 0x69: /* 0110 1001 */ + case 0x6a: /* 0110 1010 */ + case 0x6b: /* 0110 1011 */ + case 0x6c: /* 0110 1100 */ + case 0x6d: /* 0110 1101 */ + case 0x6e: /* 0110 1110 */ + case 0x6f: /* 0110 1111 */ + sprintf(buffer, "LISL $%02X", op & 0x07); + break; + + case 0x70: /* 0111 0000 */ + case 0x71: /* 0111 0001 */ + case 0x72: /* 0111 0010 */ + case 0x73: /* 0111 0011 */ + case 0x74: /* 0111 0100 */ + case 0x75: /* 0111 0101 */ + case 0x76: /* 0111 0110 */ + case 0x77: /* 0111 0111 */ + case 0x78: /* 0111 1000 */ + case 0x79: /* 0111 1001 */ + case 0x7a: /* 0111 1010 */ + case 0x7b: /* 0111 1011 */ + case 0x7c: /* 0111 1100 */ + case 0x7d: /* 0111 1101 */ + case 0x7e: /* 0111 1110 */ + case 0x7f: /* 0111 1111 */ + sprintf(buffer, "LIS $%02X", op & 0x0f); + break; + + case 0x81: /* 1000 0001 */ + case 0x85: /* 1000 0101 */ + sprintf(buffer, "BP $%04X", pc + (INT8)oprom[size++] + 1); + break; + + case 0x82: /* 1000 0010 */ + sprintf(buffer, "BC $%04X", pc + (INT8)oprom[size++] + 1); + break; + + case 0x84: /* 1000 0100 */ + sprintf(buffer, "BZ $%04X", pc + (INT8)oprom[size++] + 1); + break; + + case 0x80: /* 1000 0000 */ + case 0x83: /* 1000 0011 */ + case 0x86: /* 1000 0110 */ + case 0x87: /* 1000 0111 */ + sprintf(buffer, "BT $%02X,$%04X", op & 0x07, pc + (INT8)oprom[size++] + 1); + break; + + case 0x88: /* 1000 1000 */ + sprintf(buffer, "AM"); + break; + + case 0x89: /* 1000 1001 */ + sprintf(buffer, "AMD"); + break; + + case 0x8a: /* 1000 1010 */ + sprintf(buffer, "NM"); + break; + + case 0x8b: /* 1000 1011 */ + sprintf(buffer, "OM"); + break; + + case 0x8c: /* 1000 1100 */ + sprintf(buffer, "XM"); + break; + + case 0x8d: /* 1000 1101 */ + sprintf(buffer, "CM"); + break; + + case 0x8e: /* 1000 1110 */ + sprintf(buffer, "ADC"); + break; + + case 0x8f: /* 1000 1111 */ + sprintf(buffer, "BR7 $%04X", pc + (INT8)oprom[size++] + 1); + break; + + case 0x90: /* 1001 0000 */ + sprintf(buffer, "BR $%04X", pc + (INT8)oprom[size++] + 1); + break; + + case 0x91: /* 1001 0001 */ + case 0x95: /* 1001 0101 */ + sprintf(buffer, "BM $%04X", pc + (INT8)oprom[size++] + 1); + break; + + case 0x92: /* 1001 0010 */ + sprintf(buffer, "BNC $%04X", pc + (INT8)oprom[size++] + 1); + break; + + case 0x94: /* 1001 0100 */ + sprintf(buffer, "BNZ $%04X", pc + (INT8)oprom[size++] + 1); + break; + + case 0x98: /* 1001 1000 */ + sprintf(buffer, "BNO $%04X", pc + (INT8)oprom[size++] + 1); + break; + + case 0x93: /* 1001 0011 */ + case 0x96: /* 1001 0110 */ + case 0x97: /* 1001 0111 */ + case 0x99: /* 1001 1001 */ + case 0x9a: /* 1001 1010 */ + case 0x9b: /* 1001 1011 */ + case 0x9c: /* 1001 1100 */ + case 0x9d: /* 1001 1101 */ + case 0x9e: /* 1001 1110 */ + case 0x9f: /* 1001 1111 */ + sprintf(buffer, "BF $%02X,$%04X", op & 0x0f, pc + (INT8)oprom[size++] + 1); + break; + + case 0xa0: /* 1010 0000 */ + case 0xa1: /* 1010 0001 */ + sprintf(buffer, "INS $%02X", (unsigned) (INT8) (op & 0x0F)); + break; + + case 0xa2: /* 1010 0010 */ + case 0xa3: /* 1010 0011 */ + sprintf(buffer, "??? $%02X\n", op); + break; + + case 0xa4: /* 1010 0100 */ + case 0xa5: /* 1010 0101 */ + case 0xa6: /* 1010 0110 */ + case 0xa7: /* 1010 0111 */ + case 0xa8: /* 1010 1000 */ + case 0xa9: /* 1010 1001 */ + case 0xaa: /* 1010 1010 */ + case 0xab: /* 1010 1011 */ + case 0xac: /* 1010 1100 */ + case 0xad: /* 1010 1101 */ + case 0xae: /* 1010 1110 */ + case 0xaf: /* 1010 1111 */ + sprintf(buffer, "INS $%02X", (INT8) op & 0x0f); + break; + + case 0xb0: /* 1011 0000 */ + case 0xb1: /* 1011 0001 */ + sprintf(buffer, "OUTS $%02X", (INT8) op & 0x0f); + break; + + case 0xb2: /* 1011 0010 */ + case 0xb3: /* 1011 0011 */ + sprintf(buffer, "??? $%02X\n", op); + break; + + case 0xb4: /* 1011 0100 */ + case 0xb5: /* 1011 0101 */ + case 0xb6: /* 1011 0110 */ + case 0xb7: /* 1011 0111 */ + case 0xb8: /* 1011 1000 */ + case 0xb9: /* 1011 1001 */ + case 0xba: /* 1011 1010 */ + case 0xbb: /* 1011 1011 */ + case 0xbc: /* 1011 1100 */ + case 0xbd: /* 1011 1101 */ + case 0xbe: /* 1011 1110 */ + case 0xbf: /* 1011 1111 */ + sprintf(buffer, "OUTS $%02X", (unsigned) (INT8) op & 0x0f); + break; + + case 0xc0: /* 1100 0000 */ + case 0xc1: /* 1100 0001 */ + case 0xc2: /* 1100 0010 */ + case 0xc3: /* 1100 0011 */ + case 0xc4: /* 1100 0100 */ + case 0xc5: /* 1100 0101 */ + case 0xc6: /* 1100 0110 */ + case 0xc7: /* 1100 0111 */ + case 0xc8: /* 1100 1000 */ + case 0xc9: /* 1100 1001 */ + case 0xca: /* 1100 1010 */ + case 0xcb: /* 1100 1011 */ + sprintf(buffer, "AS %s", rname[op & 15]); + break; + case 0xcc: /* 1100 1100 */ + sprintf(buffer, "AS (IS)"); + break; + case 0xcd: /* 1100 1101 */ + sprintf(buffer, "AS (IS++)"); + break; + case 0xce: /* 1100 1110 */ + sprintf(buffer, "AS (IS--)"); + break; + case 0xcf: /* 1100 1111 */ + sprintf(buffer, "??? $%02X\n", op); + break; + + case 0xd0: /* 1101 0000 */ + case 0xd1: /* 1101 0001 */ + case 0xd2: /* 1101 0010 */ + case 0xd3: /* 1101 0011 */ + case 0xd4: /* 1101 0100 */ + case 0xd5: /* 1101 0101 */ + case 0xd6: /* 1101 0110 */ + case 0xd7: /* 1101 0111 */ + case 0xd8: /* 1101 1000 */ + case 0xd9: /* 1101 1001 */ + case 0xda: /* 1101 1010 */ + case 0xdb: /* 1101 1011 */ + sprintf(buffer, "ASD %s", rname[op & 15]); + break; + case 0xdc: /* 1101 1100 */ + sprintf(buffer, "ASD (IS)"); + break; + case 0xdd: /* 1101 1101 */ + sprintf(buffer, "ASD (IS++)"); + break; + case 0xde: /* 1101 1110 */ + sprintf(buffer, "ASD (IS--)"); + break; + case 0xdf: /* 1101 1111 */ + sprintf(buffer, "??? $%02X\n", op); + break; + + case 0xe0: /* 1110 0000 */ + case 0xe1: /* 1110 0001 */ + case 0xe2: /* 1110 0010 */ + case 0xe3: /* 1110 0011 */ + case 0xe4: /* 1110 0100 */ + case 0xe5: /* 1110 0101 */ + case 0xe6: /* 1110 0110 */ + case 0xe7: /* 1110 0111 */ + case 0xe8: /* 1110 1000 */ + case 0xe9: /* 1110 1001 */ + case 0xea: /* 1110 1010 */ + case 0xeb: /* 1110 1011 */ + sprintf(buffer, "XS %s", rname[op & 15]); + break; + case 0xec: /* 1110 1100 */ + sprintf(buffer, "XS (IS)"); + break; + case 0xed: /* 1110 1101 */ + sprintf(buffer, "XS (IS++)"); + break; + case 0xee: /* 1110 1110 */ + sprintf(buffer, "XS (IS--)"); + break; + case 0xef: /* 1110 1111 */ + sprintf(buffer, "??? $%02X\n", op); + break; + + + case 0xf0: /* 1111 0000 */ + case 0xf1: /* 1111 0001 */ + case 0xf2: /* 1111 0010 */ + case 0xf3: /* 1111 0011 */ + case 0xf4: /* 1111 0100 */ + case 0xf5: /* 1111 0101 */ + case 0xf6: /* 1111 0110 */ + case 0xf7: /* 1111 0111 */ + case 0xf8: /* 1111 1000 */ + case 0xf9: /* 1111 1001 */ + case 0xfa: /* 1111 1010 */ + case 0xfb: /* 1111 1011 */ + sprintf(buffer, "NS %s", rname[op & 15]); + break; + case 0xfc: /* 1111 1100 */ + sprintf(buffer, "NS (IS)"); + break; + case 0xfd: /* 1111 1101 */ + sprintf(buffer, "NS (IS++)"); + break; + case 0xfe: /* 1111 1110 */ + sprintf(buffer, "NS (IS--)"); + break; + case 0xff: /* 1111 1111 */ + sprintf(buffer, "??? $%02X\n", op); + break; + } + + return size; +} diff --git a/src/devices/cpu/g65816/g65816.c b/src/devices/cpu/g65816/g65816.c new file mode 100644 index 00000000000..03e7320eb89 --- /dev/null +++ b/src/devices/cpu/g65816/g65816.c @@ -0,0 +1,1136 @@ +// license:BSD-3-Clause +// copyright-holders:Karl Stenerud +/* ======================================================================== */ +/* =============================== COPYRIGHT ============================== */ +/* ======================================================================== */ +/* + +G65C816 CPU Emulator V1.00 + +Copyright Karl Stenerud +All rights reserved. + +*/ +/* ======================================================================== */ +/* ================================= NOTES ================================ */ +/* ======================================================================== */ +/* + +Changes: + 1.01 (2010-04-04): + Angelo Salese + - Added boundary checks for MVP and MVN in M mode. + + 1.00 (2008-11-27): + R. Belmont + - Reworked for modern MAME + + 0.94 (2007-06-14): + Zsolt Vasvari + - Removed unnecessary checks from MVP and MVN + + 0.93 (2003-07-05): + Angelo Salese + - Fixed the BCD conversion when using the Decimal Flag in ADC and SBC. + - Removed the two conversion tables for ADC and SBC as they aren't + needed anymore. + + 0.92 (2000-05-28): + Lee Hammerton + - Fixed debugger bug that caused D to be misrepresented. + - Fixed MVN and MVP (they were reversed) + + 0.91 (2000-05-22): + Lee Hammerton + - Fixed reset vector fetch to be little endian + - Fixed disassembler call bug + - Fixed C flag in SBC (should be inverted before operation) + - Fixed JSR to stack PC-1 and RTS to pull PC and add 1 + + Karl Stenerud + - Added correct timing for absolute indexed operations + - SBC: fixed corruption of interim values + + 0.90 (2000-05-17): + Karl Stenerud + - first public release + + +Note on timings: + - For instructions that write to memory (ASL, ASR, LSL, ROL, ROR, DEC, + INC, STA, STZ), the absolute indexed addressing mode takes 1 extra + cycle to complete. + - The spec says fc (JMP axi) is 6 cyles, but elsewhere says 8 cycles + (which is what it should be) + + +TODO general: + - WAI will not stop if RDY is held high. + + - RDY internally held low when WAI executed and returned to hi when RES, + ABORT, NMI, or IRQ asserted. + + - ABORT will terminate WAI instruction but wil not restart the processor + + - If interrupt occurs after ABORT of WAI, processor returns to WAI + instruction. + + - Add one cycle when indexing across page boundary and E=1 except for STA + and STZ instructions. + + - Add 1 cycle if branch is taken. In Emulation (E= 1 ) mode only --add 1 + cycle if the branch is taken and crosses a page boundary. + + - Add 1 cycle in Emulation mode (E=1) for (dir),y; abs,x; and abs,y + addressing modes. + +*/ +/* ======================================================================== */ +/* ================================= DATA ================================= */ +/* ======================================================================== */ + +#include "emu.h" +#include "g65816.h" + + +const device_type G65816 = &device_creator; +const device_type _5A22 = &device_creator<_5a22_device>; + + +g65816_device::g65816_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : cpu_device(mconfig, G65816, "G65C816", tag, owner, clock, "g65c816", __FILE__) + , m_program_config("program", ENDIANNESS_LITTLE, 8, 24, 0) + , m_cpu_type(CPU_TYPE_G65816) +{ +} + + +g65816_device::g65816_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source, int cpu_type, address_map_constructor internal) + : cpu_device(mconfig, type, name, tag, owner, clock, shortname, source) + , m_program_config("program", ENDIANNESS_LITTLE, 8, 24, 0, internal) + , m_cpu_type(cpu_type) +{ +} + + +static ADDRESS_MAP_START(_5a22_map, AS_PROGRAM, 8, _5a22_device) + AM_RANGE(0x4202, 0x4202) AM_MIRROR(0xbf0000) AM_WRITE(wrmpya_w) + AM_RANGE(0x4203, 0x4203) AM_MIRROR(0xbf0000) AM_WRITE(wrmpyb_w) + AM_RANGE(0x4204, 0x4204) AM_MIRROR(0xbf0000) AM_WRITE(wrdivl_w) + AM_RANGE(0x4205, 0x4205) AM_MIRROR(0xbf0000) AM_WRITE(wrdivh_w) + AM_RANGE(0x4206, 0x4206) AM_MIRROR(0xbf0000) AM_WRITE(wrdvdd_w) + + AM_RANGE(0x420d, 0x420d) AM_MIRROR(0xbf0000) AM_WRITE(memsel_w) + + AM_RANGE(0x4214, 0x4214) AM_MIRROR(0xbf0000) AM_READ(rddivl_r) + AM_RANGE(0x4215, 0x4215) AM_MIRROR(0xbf0000) AM_READ(rddivh_r) + AM_RANGE(0x4216, 0x4216) AM_MIRROR(0xbf0000) AM_READ(rdmpyl_r) + AM_RANGE(0x4217, 0x4217) AM_MIRROR(0xbf0000) AM_READ(rdmpyh_r) +ADDRESS_MAP_END + + +_5a22_device::_5a22_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : g65816_device(mconfig, _5A22, "5A22", tag, owner, clock, "5a22", __FILE__, CPU_TYPE_5A22, ADDRESS_MAP_NAME(_5a22_map)) +{ +} + + +void g65816_device::g65816i_set_execution_mode(uint mode) +{ + assert(mode < 5); + switch (mode) + { + case 0: FTABLE_OPCODES = g65816i_opcodes_M0X0; break; + case 1: FTABLE_OPCODES = g65816i_opcodes_M0X1; break; + case 2: FTABLE_OPCODES = g65816i_opcodes_M1X0; break; + case 3: FTABLE_OPCODES = g65816i_opcodes_M1X1; break; + case 4: FTABLE_OPCODES = g65816i_opcodes_E; break; + } + FTABLE_GET_REG = s_g65816_get_reg[mode]; + FTABLE_SET_REG = s_g65816_set_reg[mode]; + FTABLE_SET_LINE = s_g65816_set_line[mode]; + FTABLE_EXECUTE = s_g65816_execute[mode]; +} + + +const g65816_device::get_reg_func g65816_device::s_g65816_get_reg[5] = +{ + &g65816_device::g65816i_get_reg_M0X0, + &g65816_device::g65816i_get_reg_M0X1, + &g65816_device::g65816i_get_reg_M1X0, + &g65816_device::g65816i_get_reg_M1X1, + &g65816_device::g65816i_get_reg_E +}; + +const g65816_device::set_reg_func g65816_device::s_g65816_set_reg[5] = +{ + &g65816_device::g65816i_set_reg_M0X0, + &g65816_device::g65816i_set_reg_M0X1, + &g65816_device::g65816i_set_reg_M1X0, + &g65816_device::g65816i_set_reg_M1X1, + &g65816_device::g65816i_set_reg_E +}; + +const g65816_device::set_line_func g65816_device::s_g65816_set_line[5] = +{ + &g65816_device::g65816i_set_line_M0X0, + &g65816_device::g65816i_set_line_M0X1, + &g65816_device::g65816i_set_line_M1X0, + &g65816_device::g65816i_set_line_M1X1, + &g65816_device::g65816i_set_line_E +}; + +const g65816_device::execute_func g65816_device::s_g65816_execute[5] = +{ + &g65816_device::g65816i_execute_M0X0, + &g65816_device::g65816i_execute_M0X1, + &g65816_device::g65816i_execute_M1X0, + &g65816_device::g65816i_execute_M1X1, + &g65816_device::g65816i_execute_E +}; + + +/* ======================================================================== */ +/* ================================= MEMORY =============================== */ +/* ======================================================================== */ + +#define ADDRESS_65816(A) ((A)&0x00ffffff) + +uint g65816_device::g65816i_read_8_normal(uint address) +{ + address = ADDRESS_65816(address); + CLOCKS -= (bus_5A22_cycle_burst(address)); + return g65816_read_8(address); +} + +uint g65816_device::g65816i_read_8_immediate(uint address) +{ + address = ADDRESS_65816(address); + CLOCKS -= (bus_5A22_cycle_burst(address)); + return g65816_read_8_immediate(address); +} + +uint g65816_device::g65816i_read_8_direct(uint address) +{ + if (FLAG_E) + { + /* force address into zero page */ + address = REGISTER_D + MAKE_UINT_8(address - REGISTER_D); + CLOCKS -= (bus_5A22_cycle_burst(address)); + } + else + { + address = ADDRESS_65816(address); + CLOCKS -= (bus_5A22_cycle_burst(address)); + } + return g65816_read_8(address); +} + +uint g65816_device::g65816i_read_8_vector(uint address) +{ + if (!READ_VECTOR.isnull()) + return READ_VECTOR(*m_program, address, 0xff); + else + return g65816i_read_8_normal(address); +} + +void g65816_device::g65816i_write_8_normal(uint address, uint value) +{ + address = ADDRESS_65816(address); + CLOCKS -= (bus_5A22_cycle_burst(address)); + g65816_write_8(address, MAKE_UINT_8(value)); +} + +void g65816_device::g65816i_write_8_direct(uint address, uint value) +{ + if (FLAG_E) + { + /* force address into zero page */ + address = REGISTER_D + MAKE_UINT_8(address - REGISTER_D); + CLOCKS -= (bus_5A22_cycle_burst(address)); + } + else + { + address = ADDRESS_65816(address); + CLOCKS -= (bus_5A22_cycle_burst(address)); + } + g65816_write_8(address, MAKE_UINT_8(value)); +} + +uint g65816_device::g65816i_read_16_normal(uint address) +{ + return g65816i_read_8_normal(address) | + (g65816i_read_8_normal(address+1)<<8); +} + +uint g65816_device::g65816i_read_16_immediate(uint address) +{ + return g65816i_read_8_immediate(address) | + (g65816i_read_8_immediate(address+1)<<8); +} + +uint g65816_device::g65816i_read_16_direct(uint address) +{ + return g65816i_read_8_direct(address) | + (g65816i_read_8_direct(address+1)<<8); +} + +uint g65816_device::g65816i_read_16_vector(uint address) +{ + return g65816i_read_8_vector(address) | + (g65816i_read_8_vector(address+1)<<8); +} + +void g65816_device::g65816i_write_16_normal(uint address, uint value) +{ + g65816i_write_8_normal(address, value&0xff); + g65816i_write_8_normal(address+1, value>>8); +} + +void g65816_device::g65816i_write_16_direct(uint address, uint value) +{ + g65816i_write_8_direct(address, value&0xff); + g65816i_write_8_direct(address+1, value>>8); +} + +uint g65816_device::g65816i_read_24_normal(uint address) +{ + return g65816i_read_8_normal(address) | + (g65816i_read_8_normal(address+1)<<8) | + (g65816i_read_8_normal(address+2)<<16); +} + +uint g65816_device::g65816i_read_24_immediate(uint address) +{ + return g65816i_read_8_immediate(address) | + (g65816i_read_8_immediate(address+1)<<8) | + (g65816i_read_8_immediate(address+2)<<16); +} + +uint g65816_device::g65816i_read_24_direct(uint address) +{ + return g65816i_read_8_direct(address) | + (g65816i_read_8_direct(address+1)<<8) | + (g65816i_read_8_direct(address+2)<<16); +} + + +/* ======================================================================== */ +/* ================================= STACK ================================ */ +/* ======================================================================== */ + +void g65816_device::g65816i_push_8(uint value) +{ + g65816i_write_8_normal(REGISTER_S, value); + if (FLAG_E) + { + REGISTER_S = MAKE_UINT_8(REGISTER_S-1) | 0x100; + } + else + { + REGISTER_S = MAKE_UINT_16(REGISTER_S-1); + } +} + +uint g65816_device::g65816i_pull_8() +{ + if (FLAG_E) + { + REGISTER_S = MAKE_UINT_8(REGISTER_S+1) | 0x100; + } + else + { + REGISTER_S = MAKE_UINT_16(REGISTER_S+1); + } + return g65816i_read_8_normal(REGISTER_S); +} + +void g65816_device::g65816i_push_16(uint value) +{ + g65816i_push_8(value>>8); + g65816i_push_8(value&0xff); +} + +uint g65816_device::g65816i_pull_16() +{ + uint res = g65816i_pull_8(); + return res | (g65816i_pull_8() << 8); +} + +void g65816_device::g65816i_push_24(uint value) +{ + g65816i_push_8(value>>16); + g65816i_push_8((value>>8)&0xff); + g65816i_push_8(value&0xff); +} + +uint g65816_device::g65816i_pull_24() +{ + uint res = g65816i_pull_8(); + res |= g65816i_pull_8() << 8; + return ((res + 1) & 0xffff) | (g65816i_pull_8() << 16); +} + + +/* ======================================================================== */ +/* ============================ PROGRAM COUNTER =========================== */ +/* ======================================================================== */ + +void g65816_device::g65816i_jump_16(uint address) +{ + REGISTER_PC = MAKE_UINT_16(address); + g65816i_jumping(REGISTER_PC); +} + +void g65816_device::g65816i_jump_24(uint address) +{ + REGISTER_PB = address&0xff0000; + REGISTER_PC = MAKE_UINT_16(address); + g65816i_jumping(REGISTER_PC); +} + +void g65816_device::g65816i_branch_8(uint offset) +{ + if (FLAG_E) + { + uint old_pc = REGISTER_PC; + REGISTER_PC = MAKE_UINT_16(REGISTER_PC + MAKE_INT_8(offset)); + if((REGISTER_PC^old_pc)&0xff00) + CLK(1); + } + else + { + REGISTER_PC = MAKE_UINT_16(REGISTER_PC + MAKE_INT_8(offset)); + } + g65816i_branching(REGISTER_PC); +} + +void g65816_device::g65816i_branch_16(uint offset) +{ + REGISTER_PC = MAKE_UINT_16(REGISTER_PC + offset); + g65816i_branching(REGISTER_PC); +} + + +/* ======================================================================== */ +/* ============================ STATUS REGISTER =========================== */ +/* ======================================================================== */ + +void g65816_device::g65816i_set_flag_mx(uint value) +{ + if (FLAG_M) + { + if(!(value & FLAGPOS_M)) + { + REGISTER_A |= REGISTER_B; + REGISTER_B = 0; + FLAG_M = MFLAG_CLEAR; + } + } + else + { + if(value & FLAGPOS_M) + { + REGISTER_B = REGISTER_A & 0xff00; + REGISTER_A = MAKE_UINT_8(REGISTER_A); + FLAG_M = MFLAG_SET; + } + } + if (FLAG_X) + { + if(!(value & FLAGPOS_X)) + { + FLAG_X = XFLAG_CLEAR; + } + } + else + { + if(value & FLAGPOS_X) + { + REGISTER_X = MAKE_UINT_8(REGISTER_X); + REGISTER_Y = MAKE_UINT_8(REGISTER_Y); + FLAG_X = XFLAG_SET; + } + } + g65816i_set_execution_mode((FLAG_M>>4) | (FLAG_X>>4)); +} + +void g65816_device::g65816i_set_flag_e(uint value) +{ + if (FLAG_E) + { + if(!value) + { + FLAG_E = EFLAG_CLEAR; + g65816i_set_execution_mode(EXECUTION_MODE_M1X1); + } + } + else + { + if(value) + { + if (!FLAG_M) + { + REGISTER_B = REGISTER_A & 0xff00; + REGISTER_A &= 0x00ff; + FLAG_M = MFLAG_SET; + } + if (!FLAG_X) + { + REGISTER_X = MAKE_UINT_8(REGISTER_X); + REGISTER_Y = MAKE_UINT_8(REGISTER_Y); + FLAG_X = XFLAG_SET; + } + REGISTER_S = MAKE_UINT_8(REGISTER_S) | 0x100; + FLAG_E = EFLAG_SET; + g65816i_set_execution_mode(EXECUTION_MODE_E); + } + } +} + +void g65816_device::g65816i_set_flag_i(uint value) +{ + value &= FLAGPOS_I; + if(!FLAG_I || value) + { + FLAG_I = value; + return; + } + FLAG_I = value; +} + +/* Get the Processor Status Register */ +uint g65816_device::g65816i_get_reg_p() +{ + return (FLAG_N&0x80) | + ((FLAG_V>>1)&0x40) | + FLAG_M | + FLAG_X | + FLAG_D | + FLAG_I | + ((!FLAG_Z)<<1) | + ((FLAG_C>>8)&1); +} + +void g65816_device::g65816i_set_reg_p(uint value) +{ + if (FLAG_E) + { + FLAG_N = value; + FLAG_V = value << 1; + FLAG_D = value & FLAGPOS_D; + FLAG_Z = !(value & FLAGPOS_Z); + FLAG_C = value << 8; + g65816i_set_flag_i(value); + } + else + { + FLAG_N = value; + FLAG_V = value << 1; + FLAG_D = value & FLAGPOS_D; + FLAG_Z = !(value & FLAGPOS_Z); + FLAG_C = value << 8; + g65816i_set_flag_mx(value); + g65816i_set_flag_i(value); + } +} + + +/* ======================================================================== */ +/* =============================== INTERRUPTS ============================= */ +/* ======================================================================== */ + +void g65816_device::g65816i_interrupt_hardware(uint vector) +{ + if (FLAG_E) + { + CLK(7); + g65816i_push_16(REGISTER_PC); + g65816i_push_8(g65816i_get_reg_p() & ~FLAGPOS_B); + FLAG_D = DFLAG_CLEAR; + g65816i_set_flag_i(IFLAG_SET); + REGISTER_PB = 0; + g65816i_jump_16(g65816i_read_16_vector(vector)); + standard_irq_callback(0); + } + else + { + CLK(8); + g65816i_push_8(REGISTER_PB>>16); + g65816i_push_16(REGISTER_PC); + g65816i_push_8(g65816i_get_reg_p()); + FLAG_D = DFLAG_CLEAR; + g65816i_set_flag_i(IFLAG_SET); + REGISTER_PB = 0; + g65816i_jump_16(g65816i_read_16_vector(vector)); + standard_irq_callback(0); + } +} + +void g65816_device::g65816i_interrupt_software(uint vector) +{ + if (FLAG_E) + { + CLK(7); + g65816i_push_16(REGISTER_PC); + g65816i_push_8(g65816i_get_reg_p()); + FLAG_D = DFLAG_CLEAR; + g65816i_set_flag_i(IFLAG_SET); + REGISTER_PB = 0; + g65816i_jump_16(g65816i_read_16_normal(vector)); + } + else + { + CLK(8); + g65816i_push_8(REGISTER_PB>>16); + g65816i_push_16(REGISTER_PC); + g65816i_push_8(g65816i_get_reg_p()); + FLAG_D = DFLAG_CLEAR; + g65816i_set_flag_i(IFLAG_SET); + REGISTER_PB = 0; + g65816i_jump_16(g65816i_read_16_normal(vector)); + } +} + +void g65816_device::g65816i_interrupt_nmi() +{ + if (FLAG_E) + { + CLK(7); + g65816i_push_16(REGISTER_PC); + g65816i_push_8(g65816i_get_reg_p() & ~FLAGPOS_B); + FLAG_D = DFLAG_CLEAR; + REGISTER_PB = 0; + g65816i_jump_16(g65816i_read_16_normal((FLAG_E) ? VECTOR_NMI_E : VECTOR_NMI_N)); + } + else + { + CLK(8); + g65816i_push_8(REGISTER_PB>>16); + g65816i_push_16(REGISTER_PC); + g65816i_push_8(g65816i_get_reg_p()); + FLAG_D = DFLAG_CLEAR; + REGISTER_PB = 0; + g65816i_jump_16(g65816i_read_16_normal((FLAG_E) ? VECTOR_NMI_E : VECTOR_NMI_N)); + } +} + + +void g65816_device::g65816i_check_maskable_interrupt() +{ + if(!(CPU_STOPPED & STOP_LEVEL_STOP) && LINE_IRQ && !FLAG_I) + { + g65816i_interrupt_hardware((FLAG_E) ? VECTOR_IRQ_E : VECTOR_IRQ_N); + CPU_STOPPED &= ~STOP_LEVEL_WAI; + LINE_IRQ=0; + } +} + + +uint g65816_device::EA_IMM8() {REGISTER_PC += 1; return REGISTER_PB | MAKE_UINT_16(REGISTER_PC-1);} +uint g65816_device::EA_IMM16() {REGISTER_PC += 2; return REGISTER_PB | MAKE_UINT_16(REGISTER_PC-2);} +uint g65816_device::EA_IMM24() {REGISTER_PC += 3; return REGISTER_PB | MAKE_UINT_16(REGISTER_PC-3);} +uint g65816_device::EA_D() {if(MAKE_UINT_8(REGISTER_D)) CLK(1); return MAKE_UINT_16(REGISTER_D + g65816i_read_8_immediate(EA_IMM8()));} +uint g65816_device::EA_A() {return REGISTER_DB | g65816i_read_16_immediate(EA_IMM16());} +uint g65816_device::EA_AL() {return g65816i_read_24_immediate(EA_IMM24());} +uint g65816_device::EA_DX() {return MAKE_UINT_16(REGISTER_D + g65816i_read_8_immediate(EA_IMM8()) + REGISTER_X);} +uint g65816_device::EA_DY() {return MAKE_UINT_16(REGISTER_D + g65816i_read_8_immediate(EA_IMM8()) + REGISTER_Y);} +uint g65816_device::EA_AX() {uint tmp = EA_A(); if((tmp^(tmp+REGISTER_X))&0xff00) CLK(1); return tmp + REGISTER_X;} +uint g65816_device::EA_ALX() {return EA_AL() + REGISTER_X;} +uint g65816_device::EA_AY() {uint tmp = EA_A(); if((tmp^(tmp+REGISTER_X))&0xff00) CLK(1); return tmp + REGISTER_Y;} +uint g65816_device::EA_DI() {return REGISTER_DB | g65816i_read_16_direct(EA_D());} +uint g65816_device::EA_DLI() {return g65816i_read_24_direct(EA_D());} +uint g65816_device::EA_AI() {return g65816i_read_16_normal(g65816i_read_16_immediate(EA_IMM16()));} +uint g65816_device::EA_ALI() {return g65816i_read_24_normal(EA_A());} +uint g65816_device::EA_DXI() {return REGISTER_DB | g65816i_read_16_direct(EA_DX());} +uint g65816_device::EA_DIY() {uint tmp = REGISTER_DB | g65816i_read_16_direct(EA_D()); if((tmp^(tmp+REGISTER_X))&0xff00) CLK(1); return tmp + REGISTER_Y;} +uint g65816_device::EA_DLIY() {return g65816i_read_24_direct(EA_D()) + REGISTER_Y;} +uint g65816_device::EA_AXI() {return g65816i_read_16_normal(MAKE_UINT_16(g65816i_read_16_immediate(EA_IMM16()) + REGISTER_X));} +uint g65816_device::EA_S() {return MAKE_UINT_16(REGISTER_S + g65816i_read_8_immediate(EA_IMM8()));} +uint g65816_device::EA_SIY() {return MAKE_UINT_16(g65816i_read_16_normal(REGISTER_S + g65816i_read_8_immediate(EA_IMM8())) + REGISTER_Y) | REGISTER_DB;} + + + +/* ======================================================================== */ +/* ================================= API ================================== */ +/* ======================================================================== */ + + +void g65816_device::device_reset() +{ + /* Start the CPU */ + CPU_STOPPED = 0; + + /* Put into emulation mode */ + REGISTER_D = 0; + REGISTER_PB = 0; + REGISTER_DB = 0; + REGISTER_S = (REGISTER_S & 0xff) | 0x100; + REGISTER_X &= 0xff; + REGISTER_Y &= 0xff; + if(!FLAG_M) + { + REGISTER_B = REGISTER_A & 0xff00; + REGISTER_A &= 0xff; + } + FLAG_E = EFLAG_SET; + FLAG_M = MFLAG_SET; + FLAG_X = XFLAG_SET; + + /* Clear D and set I */ + FLAG_D = DFLAG_CLEAR; + FLAG_I = IFLAG_SET; + + /* Clear all pending interrupts (should we really do this?) */ + LINE_IRQ = 0; + LINE_NMI = 0; + IRQ_DELAY = 0; + + /* Set the function tables to emulation mode */ + g65816i_set_execution_mode(EXECUTION_MODE_E); + + /* 6502 expects these, but its not in the 65816 spec */ + FLAG_Z = ZFLAG_CLEAR; + REGISTER_S = 0x1ff; + + /* Fetch the reset vector */ + REGISTER_PC = g65816_read_8(VECTOR_RESET) | (g65816_read_8(VECTOR_RESET+1)<<8); + g65816i_jumping(REGISTER_PB | REGISTER_PC); +} + + +/* Execute some instructions */ +void g65816_device::execute_run() +{ + int clocks = m_ICount; + m_ICount = clocks - (this->*FTABLE_EXECUTE)(m_ICount); +} + + +/* Get the current Program Counter */ +unsigned g65816_device::g65816_get_pc() +{ + return REGISTER_PB | REGISTER_PC; +} + +/* Set the Program Counter */ +void g65816_device::g65816_set_pc(unsigned val) +{ + REGISTER_PC = MAKE_UINT_16(val); + REGISTER_PB = (val >> 16) & 0xFF; + g65816_jumping(REGISTER_PB | REGISTER_PC); +} + +/* Get the current Stack Pointer */ +unsigned g65816_device::g65816_get_sp() +{ + return REGISTER_S; +} + +/* Set the Stack Pointer */ +void g65816_device::g65816_set_sp(unsigned val) +{ + REGISTER_S = FLAG_E ? MAKE_UINT_8(val) | 0x100 : MAKE_UINT_16(val); +} + +/* Get a register */ +unsigned g65816_device::g65816_get_reg(int regnum) +{ + /* Set the function tables to emulation mode if the FTABLE is NULL */ + if( FTABLE_GET_REG == NULL ) + g65816i_set_execution_mode(EXECUTION_MODE_E); + + return (this->*FTABLE_GET_REG)(regnum); +} + +/* Set a register */ +void g65816_device::g65816_set_reg(int regnum, unsigned value) +{ + (this->*FTABLE_SET_REG)(regnum, value); +} + +/* Set an interrupt line */ +void g65816_device::execute_set_input(int line, int state) +{ + (this->*FTABLE_SET_LINE)(line, state); +} + +/* Disassemble an instruction */ +#include "g65816ds.h" + + +offs_t g65816_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + return g65816_disassemble(buffer, (pc & 0x00ffff), (pc & 0xff0000) >> 16, oprom, FLAG_M, FLAG_X); +} + +CPU_DISASSEMBLE( g65816 ) +{ + return g65816_disassemble(buffer, (pc & 0x00ffff), (pc & 0xff0000) >> 16, oprom, 0/*FLAG_M*/, 0/*FLAG_X*/); +} + +void g65816_device::g65816_restore_state() +{ + // restore proper function pointers + g65816i_set_execution_mode((FLAG_M>>4) | (FLAG_X>>4)); + + // make sure the memory system can keep up + g65816i_jumping(REGISTER_PB | REGISTER_PC); +} + +void g65816_device::device_start() +{ + m_a = 0; + m_b = 0; + m_x = 0; + m_y = 0; + m_s = 0; + m_pc = 0; + m_ppc = 0; + m_pb = 0; + m_db = 0; + m_d = 0; + m_flag_e = 0; + m_flag_m = 0; + m_flag_x = 0; + m_flag_n = 0; + m_flag_v = 0; + m_flag_d = 0; + m_flag_i = 0; + m_flag_z = 0; + m_flag_c = 0; + m_line_irq = 0; + m_line_nmi = 0; + m_fastROM = 0; + m_ir = 0; + m_irq_delay = 0; + m_stopped = 0; + m_source = 0; + m_destination = 0; + m_wrmpya = 0; + m_wrmpyb = 0; + m_rdmpy = 0; + m_wrdiv = 0; + m_dvdd = 0; + m_rddiv = 0; + m_opcodes = NULL; + m_get_reg = NULL; + m_set_reg = NULL; + m_set_line = NULL; + m_execute = NULL; + m_debugger_temp = 0; + + m_program = &space(AS_PROGRAM); + + save_item(NAME(m_a)); + save_item(NAME(m_b)); + save_item(NAME(m_x)); + save_item(NAME(m_y)); + save_item(NAME(m_s)); + save_item(NAME(m_pc)); + save_item(NAME(m_ppc)); + save_item(NAME(m_pb)); + save_item(NAME(m_db)); + save_item(NAME(m_d)); + save_item(NAME(m_flag_e)); + save_item(NAME(m_flag_m)); + save_item(NAME(m_flag_x)); + save_item(NAME(m_flag_n)); + save_item(NAME(m_flag_v)); + save_item(NAME(m_flag_d)); + save_item(NAME(m_flag_i)); + save_item(NAME(m_flag_z)); + save_item(NAME(m_flag_c)); + save_item(NAME(m_line_irq)); + save_item(NAME(m_line_nmi)); + save_item(NAME(m_ir)); + save_item(NAME(m_irq_delay)); + save_item(NAME(m_stopped)); + save_item(NAME(m_fastROM)); + + machine().save().register_postload(save_prepost_delegate(FUNC(g65816_device::g65816_restore_state), this)); + + m_rw8_cycles = 1; + m_rw16_cycles = 2; + m_rw24_cycles = 3; + + state_add( G65816_PC, "PC", m_debugger_temp).callimport().callexport().formatstr("%06X"); + state_add( G65816_S, "S", m_s).callimport().formatstr("%04X"); + state_add( G65816_P, "P", m_debugger_temp).callimport().callexport().formatstr("%02X"); + state_add( G65816_A, "A", m_debugger_temp).callimport().callexport().formatstr("%04X"); + state_add( G65816_X, "X", m_x).callimport().formatstr("%04X"); + state_add( G65816_Y, "Y", m_y).callimport().formatstr("%04X"); + state_add( G65816_PB, "PB", m_debugger_temp).callimport().callexport().formatstr("%02X"); + state_add( G65816_DB, "DB", m_debugger_temp).callimport().callexport().formatstr("%02X"); + state_add( G65816_D, "D", m_d).callimport().formatstr("%04X"); + state_add( G65816_E, "E", m_flag_e).mask(0x01).callimport().formatstr("%01X"); + state_add( G65816_NMI_STATE, "NMI", m_line_nmi).mask(0x01).callimport().formatstr("%01X"); + state_add( G65816_IRQ_STATE, "IRQ", m_line_irq).mask(0x01).callimport().formatstr("%01X"); + + state_add( STATE_GENPC, "GENPC", m_debugger_temp).callimport().callexport().formatstr("%06X").noshow(); + state_add( STATE_GENSP, "GENSP", m_debugger_temp).callimport().callexport().formatstr("%06X").noshow(); + state_add( STATE_GENFLAGS, "GENFLAGS", m_debugger_temp).formatstr("%8s").noshow(); + + m_icountptr = &m_ICount; +} + +void g65816_device::state_import(const device_state_entry &entry) +{ + switch (entry.index()) + { + case STATE_GENPC: + g65816_set_pc(m_debugger_temp); + break; + case STATE_GENSP: + g65816_set_sp(m_debugger_temp); + break; + case G65816_PC: + case G65816_PB: + case G65816_DB: + g65816_set_reg(entry.index(), m_debugger_temp); + break; + case G65816_D: + g65816_set_reg(G65816_D, m_d); + break; + case G65816_S: + g65816_set_reg(G65816_S, m_s); + break; + case G65816_P: + g65816_set_reg(G65816_P, m_debugger_temp); + break; + case G65816_E: + g65816_set_reg(G65816_E, m_flag_e); + break; + case G65816_A: + g65816_set_reg(G65816_A, m_debugger_temp); + break; + case G65816_X: + g65816_set_reg(G65816_X, m_x); + break; + case G65816_Y: + g65816_set_reg(G65816_Y, m_y); + break; + case G65816_NMI_STATE: + g65816_set_reg(G65816_NMI_STATE, m_line_nmi); + break; + case G65816_IRQ_STATE: + g65816_set_reg(G65816_IRQ_STATE, m_line_irq); + break; + } +} + +void g65816_device::state_export(const device_state_entry &entry) +{ + switch (entry.index()) + { + case STATE_GENPC: + case G65816_PC: + m_debugger_temp = g65816_get_pc(); + break; + case STATE_GENSP: + m_debugger_temp = g65816_get_sp(); + break; + case G65816_PB: + m_debugger_temp = m_pb>>16; + break; + case G65816_DB: + m_debugger_temp = m_db>>16; + break; + case G65816_P: + m_debugger_temp = (m_flag_n&0x80) | + ((m_flag_v>>1)&0x40) | + m_flag_m | + m_flag_x | + m_flag_d | + m_flag_i | + ((!m_flag_z)<<1) | + ((m_flag_c>>8)&1); + break; + case G65816_A: + m_debugger_temp = m_a | m_b; + break; + } +} + +void g65816_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + switch (entry.index()) + { + case STATE_GENFLAGS: + strprintf(str, "%c%c%c%c%c%c%c%c", + m_flag_n & NFLAG_SET ? 'N':'.', + m_flag_v & VFLAG_SET ? 'V':'.', + m_flag_m & MFLAG_SET ? 'M':'.', + m_flag_x & XFLAG_SET ? 'X':'.', + m_flag_d & DFLAG_SET ? 'D':'.', + + m_flag_i & IFLAG_SET ? 'I':'.', + m_flag_z == 0 ? 'Z':'.', + m_flag_c & CFLAG_SET ? 'C':'.'); + break; + } +} + +void g65816_device::set_read_vector_callback(read8_delegate read_vector) +{ + READ_VECTOR = read_vector; +} + + +/* +SNES specific, used to handle master cycles, based off byuu's BSNES code +*/ + +int g65816_device::bus_5A22_cycle_burst(uint addr) +{ + if(m_cpu_type == CPU_TYPE_G65816) + return 0; + + if(addr & 0x408000) { + if(addr & 0x800000) + return (m_fastROM & 1) ? 6 : 8; + + return 8; + } + if((addr + 0x6000) & 0x4000) return 8; + if((addr - 0x4000) & 0x7e00) return 6; + + return 12; +} + + +void _5a22_device::device_start() +{ + g65816_device::device_start(); + + state_add( _5A22_FASTROM, "fastROM", m_debugger_temp).mask(0x01).callimport().callexport().formatstr("%01X"); + + m_rw8_cycles = 0; + m_rw16_cycles = 0; + m_rw24_cycles = 0; +} + +void _5a22_device::state_import(const device_state_entry &entry) +{ + switch (entry.index()) + { + case _5A22_FASTROM: + g65816_set_reg(_5A22_FASTROM, m_debugger_temp); + break; + default: + g65816_device::state_import(entry); + break; + } +} + +void _5a22_device::state_export(const device_state_entry &entry) +{ + switch (entry.index()) + { + case _5A22_FASTROM: + m_debugger_temp = g65816_get_reg(_5A22_FASTROM); + break; + default: + g65816_device::state_export(entry); + break; + } +} + +void _5a22_device::device_reset() +{ + g65816_device::device_reset(); + + m_fastROM = 0; + m_wrmpya = 0xff; + m_wrdiv = 0xffff; +} + +/* TODO: multiplication / division should actually occur inside CPU_EXECUTE */ +/* (Old note, for reference): multiplication should take 8 CPU cycles & +division 16 CPU cycles, but using these timers breaks e.g. Chrono Trigger +intro and Super Tennis gameplay. On the other hand, timers are needed for the +translation of Breath of Fire 2 to work. More weirdness: we might need to leave +8 CPU cycles for division at first, since using 16 produces bugs (see e.g. +Triforce pieces in Zelda 3 intro) */ + +WRITE8_MEMBER( _5a22_device::wrmpya_w ) +{ + m_wrmpya = data; +} + +WRITE8_MEMBER( _5a22_device::wrmpyb_w ) +{ + m_wrmpyb = data; + m_rdmpy = m_wrmpya * m_wrmpyb; + /* TODO: m_rddiv == 0? */ +} + +WRITE8_MEMBER( _5a22_device::wrdivl_w ) +{ + m_wrdiv = (data) | (m_wrdiv & 0xff00); +} + +WRITE8_MEMBER( _5a22_device::wrdivh_w ) +{ + m_wrdiv = (data << 8) | (m_wrdiv & 0xff); +} + +WRITE8_MEMBER( _5a22_device::wrdvdd_w ) +{ + UINT16 quotient, remainder; + + m_dvdd = data; + + quotient = (m_dvdd == 0) ? 0xffff : m_wrdiv / m_dvdd; + remainder = (m_dvdd == 0) ? 0x000c : m_wrdiv % m_dvdd; + + m_rddiv = quotient; + m_rdmpy = remainder; +} + +WRITE8_MEMBER( _5a22_device::memsel_w ) +{ + m_fastROM = data & 1; +} + +READ8_MEMBER( _5a22_device::rddivl_r ) +{ + return m_rddiv & 0xff; +} + +READ8_MEMBER( _5a22_device::rddivh_r ) +{ + return m_rddiv >> 8; +} + +READ8_MEMBER( _5a22_device::rdmpyl_r ) +{ + return m_rdmpy & 0xff; +} + +READ8_MEMBER( _5a22_device::rdmpyh_r ) +{ + return m_rdmpy >> 8; +} + + +void _5a22_device::set_5a22_map() +{ + space(AS_PROGRAM).install_write_handler(0x4202, 0x4202, 0, 0xbf0000, write8_delegate(FUNC(_5a22_device::wrmpya_w),this)); + space(AS_PROGRAM).install_write_handler(0x4203, 0x4203, 0, 0xbf0000, write8_delegate(FUNC(_5a22_device::wrmpyb_w),this)); + space(AS_PROGRAM).install_write_handler(0x4204, 0x4204, 0, 0xbf0000, write8_delegate(FUNC(_5a22_device::wrdivl_w),this)); + space(AS_PROGRAM).install_write_handler(0x4205, 0x4205, 0, 0xbf0000, write8_delegate(FUNC(_5a22_device::wrdivh_w),this)); + space(AS_PROGRAM).install_write_handler(0x4206, 0x4206, 0, 0xbf0000, write8_delegate(FUNC(_5a22_device::wrdvdd_w),this)); + + space(AS_PROGRAM).install_write_handler(0x420d, 0x420d, 0, 0xbf0000, write8_delegate(FUNC(_5a22_device::memsel_w),this)); + + space(AS_PROGRAM).install_read_handler(0x4214, 0x4214, 0, 0xbf0000, read8_delegate(FUNC(_5a22_device::rddivl_r),this)); + space(AS_PROGRAM).install_read_handler(0x4215, 0x4215, 0, 0xbf0000, read8_delegate(FUNC(_5a22_device::rddivh_r),this)); + space(AS_PROGRAM).install_read_handler(0x4216, 0x4216, 0, 0xbf0000, read8_delegate(FUNC(_5a22_device::rdmpyl_r),this)); + space(AS_PROGRAM).install_read_handler(0x4217, 0x4217, 0, 0xbf0000, read8_delegate(FUNC(_5a22_device::rdmpyh_r),this)); +} + + +/* ======================================================================== */ +/* ============================== END OF FILE ============================= */ +/* ======================================================================== */ diff --git a/src/devices/cpu/g65816/g65816.h b/src/devices/cpu/g65816/g65816.h new file mode 100644 index 00000000000..19b76fb3d31 --- /dev/null +++ b/src/devices/cpu/g65816/g65816.h @@ -0,0 +1,1570 @@ +// license:BSD-3-Clause +// copyright-holders:Karl Stenerud +#pragma once + +#ifndef __G65816_H__ +#define __G65816_H__ + +#include "g65816cm.h" + +/* ======================================================================== */ +/* =============================== COPYRIGHT ============================== */ +/* ======================================================================== */ +/* + +G65C816 CPU Emulator V0.92 + +Copyright Karl Stenerud +All rights reserved. + +*/ +/* ======================================================================== */ +/* ============================= Configuration ============================ */ +/* ======================================================================== */ + +/* GTE Microcircuits G65816 */ + +/* ======================================================================== */ +/* =============================== DEFINES ================================ */ +/* ======================================================================== */ + +/* Interrupt lines - used with g65816_set_irq_line() */ +enum +{ + G65816_LINE_NONE, + G65816_LINE_IRQ, + G65816_LINE_NMI, + G65816_LINE_ABORT, + G65816_LINE_SO, + G65816_LINE_RDY, + G65816_LINE_RESET +}; + +#define G65816_INT_NONE G65816_LINE_NONE +#define G65816_INT_IRQ G65816_LINE_IRQ +#define G65816_INT_NMI G65816_LINE_NMI + + +/* Registers - used by g65816_set_reg() and g65816_get_reg() */ +enum +{ + G65816_PC=1, G65816_S, G65816_P, G65816_A, G65816_X, G65816_Y, + G65816_PB, G65816_DB, G65816_D, G65816_E, + G65816_NMI_STATE, G65816_IRQ_STATE, + _5A22_FASTROM +}; + + +class g65816_device : public cpu_device +{ +public: + // construction/destruction + g65816_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + g65816_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source, int cpu_type, address_map_constructor internal = NULL); + + void set_read_vector_callback(read8_delegate read_vector); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_execute_interface overrides + virtual UINT32 execute_min_cycles() const { return 1; } + virtual UINT32 execute_max_cycles() const { return 20; } + virtual UINT32 execute_input_lines() const { return 5; } + virtual void execute_run(); + virtual void execute_set_input(int inputnum, int state); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const { return (spacenum == AS_PROGRAM) ? &m_program_config : NULL; } + + // device_state_interface overrides + virtual void state_import(const device_state_entry &entry); + virtual void state_export(const device_state_entry &entry); + virtual void state_string_export(const device_state_entry &entry, std::string &str); + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const { return 1; } + virtual UINT32 disasm_max_opcode_bytes() const { return 4; } + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + + address_space_config m_program_config; + + typedef void (g65816_device::*opcode_func) (); + typedef uint (g65816_device::*get_reg_func)(int regnum); + typedef void (g65816_device::*set_reg_func)(int regnum, uint val); + typedef void (g65816_device::*set_line_func)(int line, int state); + typedef int (g65816_device::*execute_func)(int cycles); + + static const opcode_func g65816i_opcodes_M0X0[]; + uint g65816i_get_reg_M0X0(int regnum); + void g65816i_set_reg_M0X0(int regnum, uint val); + void g65816i_set_line_M0X0(int line, int state); + int g65816i_execute_M0X0(int cycles); + + static const opcode_func g65816i_opcodes_M0X1[]; + uint g65816i_get_reg_M0X1(int regnum); + void g65816i_set_reg_M0X1(int regnum, uint val); + void g65816i_set_line_M0X1(int line, int state); + int g65816i_execute_M0X1(int cycles); + + static const opcode_func g65816i_opcodes_M1X0[]; + uint g65816i_get_reg_M1X0(int regnum); + void g65816i_set_reg_M1X0(int regnum, uint val); + void g65816i_set_line_M1X0(int line, int state); + int g65816i_execute_M1X0(int cycles); + + static const opcode_func g65816i_opcodes_M1X1[]; + uint g65816i_get_reg_M1X1(int regnum); + void g65816i_set_reg_M1X1(int regnum, uint val); + void g65816i_set_line_M1X1(int line, int state); + int g65816i_execute_M1X1(int cycles); + + static const opcode_func g65816i_opcodes_E[]; + uint g65816i_get_reg_E(int regnum); + void g65816i_set_reg_E(int regnum, uint val); + void g65816i_set_line_E(int line, int state); + int g65816i_execute_E(int cycles); + + void g65816i_set_execution_mode(uint mode); + int bus_5A22_cycle_burst(uint addr); + unsigned g65816_get_pc(); + void g65816_set_pc(unsigned val); + unsigned g65816_get_sp(); + void g65816_set_sp(unsigned val); + unsigned g65816_get_reg(int regnum); + void g65816_set_reg(int regnum, unsigned value); + void g65816_restore_state(); + uint g65816i_read_8_normal(uint address); + uint g65816i_read_8_immediate(uint address); + uint g65816i_read_8_direct(uint address); + uint g65816i_read_8_vector(uint address); + void g65816i_write_8_normal(uint address, uint value); + void g65816i_write_8_direct(uint address, uint value); + uint g65816i_read_16_normal(uint address); + uint g65816i_read_16_immediate(uint address); + uint g65816i_read_16_direct(uint address); + uint g65816i_read_16_vector(uint address); + void g65816i_write_16_normal(uint address, uint value); + void g65816i_write_16_direct(uint address, uint value); + uint g65816i_read_24_normal(uint address); + uint g65816i_read_24_immediate(uint address); + uint g65816i_read_24_direct(uint address); + void g65816i_push_8(uint value); + uint g65816i_pull_8(); + void g65816i_push_16(uint value); + uint g65816i_pull_16(); + void g65816i_push_24(uint value); + uint g65816i_pull_24(); + void g65816i_jump_16(uint address); + void g65816i_jump_24(uint address); + void g65816i_branch_8(uint offset); + void g65816i_branch_16(uint offset); + void g65816i_set_flag_mx(uint value); + void g65816i_set_flag_e(uint value); + void g65816i_set_flag_i(uint value); + uint g65816i_get_reg_p(); + void g65816i_set_reg_p(uint value); + void g65816i_interrupt_hardware(uint vector); + void g65816i_interrupt_software(uint vector); + void g65816i_interrupt_nmi(); + void g65816i_check_maskable_interrupt(); + uint EA_IMM8(); + uint EA_IMM16(); + uint EA_IMM24(); + uint EA_D(); + uint EA_A(); + uint EA_AL(); + uint EA_DX(); + uint EA_DY(); + uint EA_AX(); + uint EA_ALX(); + uint EA_AY(); + uint EA_DI(); + uint EA_DLI(); + uint EA_AI(); + uint EA_ALI(); + uint EA_DXI(); + uint EA_DIY(); + uint EA_DLIY(); + uint EA_AXI(); + uint EA_S(); + uint EA_SIY(); + + static const get_reg_func s_g65816_get_reg[5]; + static const set_reg_func s_g65816_set_reg[5]; + static const set_line_func s_g65816_set_line[5]; + static const execute_func s_g65816_execute[5]; + + uint m_a; /* Accumulator */ + uint m_b; /* holds high byte of accumulator */ + uint m_x; /* Index Register X */ + uint m_y; /* Index Register Y */ + uint m_s; /* Stack Pointer */ + uint m_pc; /* Program Counter */ + uint m_ppc; /* Previous Program Counter */ + uint m_pb; /* Program Bank (shifted left 16) */ + uint m_db; /* Data Bank (shifted left 16) */ + uint m_d; /* Direct Register */ + uint m_flag_e; /* Emulation Mode Flag */ + uint m_flag_m; /* Memory/Accumulator Select Flag */ + uint m_flag_x; /* Index Select Flag */ + uint m_flag_n; /* Negative Flag */ + uint m_flag_v; /* Overflow Flag */ + uint m_flag_d; /* Decimal Mode Flag */ + uint m_flag_i; /* Interrupt Mask Flag */ + uint m_flag_z; /* Zero Flag (inverted) */ + uint m_flag_c; /* Carry Flag */ + uint m_line_irq; /* Status of the IRQ line */ + uint m_line_nmi; /* Status of the NMI line */ + uint m_fastROM; /* SNES specific */ + uint m_ir; /* Instruction Register */ + uint m_irq_delay; /* delay 1 instruction before checking irq */ + address_space *m_program; + read8_delegate m_read_vector; /* Read vector override */ + uint m_stopped; /* Sets how the CPU is stopped */ + const opcode_func* m_opcodes; + get_reg_func m_get_reg; + set_reg_func m_set_reg; + set_line_func m_set_line; + execute_func m_execute; + uint m_source; + uint m_destination; + int m_ICount; + int m_cpu_type; + UINT8 m_rw8_cycles, m_rw16_cycles, m_rw24_cycles; + UINT32 m_debugger_temp; + + /* 5A22 specific registers */ + UINT8 m_wrmpya, m_wrmpyb; + UINT16 m_rdmpy; + UINT16 m_wrdiv; + UINT8 m_dvdd; + UINT16 m_rddiv; + + void g65816i_00_M0X0(); + void g65816i_01_M0X0(); + void g65816i_02_M0X0(); + void g65816i_03_M0X0(); + void g65816i_04_M0X0(); + void g65816i_05_M0X0(); + void g65816i_06_M0X0(); + void g65816i_07_M0X0(); + void g65816i_08_M0X0(); + void g65816i_09_M0X0(); + void g65816i_0a_M0X0(); + void g65816i_0b_M0X0(); + void g65816i_0c_M0X0(); + void g65816i_0d_M0X0(); + void g65816i_0e_M0X0(); + void g65816i_0f_M0X0(); + void g65816i_10_M0X0(); + void g65816i_11_M0X0(); + void g65816i_12_M0X0(); + void g65816i_13_M0X0(); + void g65816i_14_M0X0(); + void g65816i_15_M0X0(); + void g65816i_16_M0X0(); + void g65816i_17_M0X0(); + void g65816i_18_M0X0(); + void g65816i_19_M0X0(); + void g65816i_1a_M0X0(); + void g65816i_1b_M0X0(); + void g65816i_1c_M0X0(); + void g65816i_1d_M0X0(); + void g65816i_1e_M0X0(); + void g65816i_1f_M0X0(); + void g65816i_20_M0X0(); + void g65816i_21_M0X0(); + void g65816i_22_M0X0(); + void g65816i_23_M0X0(); + void g65816i_24_M0X0(); + void g65816i_25_M0X0(); + void g65816i_26_M0X0(); + void g65816i_27_M0X0(); + void g65816i_28_M0X0(); + void g65816i_29_M0X0(); + void g65816i_2a_M0X0(); + void g65816i_2b_M0X0(); + void g65816i_2c_M0X0(); + void g65816i_2d_M0X0(); + void g65816i_2e_M0X0(); + void g65816i_2f_M0X0(); + void g65816i_30_M0X0(); + void g65816i_31_M0X0(); + void g65816i_32_M0X0(); + void g65816i_33_M0X0(); + void g65816i_34_M0X0(); + void g65816i_35_M0X0(); + void g65816i_36_M0X0(); + void g65816i_37_M0X0(); + void g65816i_38_M0X0(); + void g65816i_39_M0X0(); + void g65816i_3a_M0X0(); + void g65816i_3b_M0X0(); + void g65816i_3c_M0X0(); + void g65816i_3d_M0X0(); + void g65816i_3e_M0X0(); + void g65816i_3f_M0X0(); + void g65816i_40_M0X0(); + void g65816i_41_M0X0(); + void g65816i_42_M0X0(); + void g65816i_43_M0X0(); + void g65816i_44_M0X0(); + void g65816i_45_M0X0(); + void g65816i_46_M0X0(); + void g65816i_47_M0X0(); + void g65816i_48_M0X0(); + void g65816i_49_M0X0(); + void g65816i_4a_M0X0(); + void g65816i_4b_M0X0(); + void g65816i_4c_M0X0(); + void g65816i_4d_M0X0(); + void g65816i_4e_M0X0(); + void g65816i_4f_M0X0(); + void g65816i_50_M0X0(); + void g65816i_51_M0X0(); + void g65816i_52_M0X0(); + void g65816i_53_M0X0(); + void g65816i_54_M0X0(); + void g65816i_55_M0X0(); + void g65816i_56_M0X0(); + void g65816i_57_M0X0(); + void g65816i_58_M0X0(); + void g65816i_59_M0X0(); + void g65816i_5a_M0X0(); + void g65816i_5b_M0X0(); + void g65816i_5c_M0X0(); + void g65816i_5d_M0X0(); + void g65816i_5e_M0X0(); + void g65816i_5f_M0X0(); + void g65816i_60_M0X0(); + void g65816i_61_M0X0(); + void g65816i_62_M0X0(); + void g65816i_63_M0X0(); + void g65816i_64_M0X0(); + void g65816i_65_M0X0(); + void g65816i_66_M0X0(); + void g65816i_67_M0X0(); + void g65816i_68_M0X0(); + void g65816i_69_M0X0(); + void g65816i_6a_M0X0(); + void g65816i_6b_M0X0(); + void g65816i_6c_M0X0(); + void g65816i_6d_M0X0(); + void g65816i_6e_M0X0(); + void g65816i_6f_M0X0(); + void g65816i_70_M0X0(); + void g65816i_71_M0X0(); + void g65816i_72_M0X0(); + void g65816i_73_M0X0(); + void g65816i_74_M0X0(); + void g65816i_75_M0X0(); + void g65816i_76_M0X0(); + void g65816i_77_M0X0(); + void g65816i_78_M0X0(); + void g65816i_79_M0X0(); + void g65816i_7a_M0X0(); + void g65816i_7b_M0X0(); + void g65816i_7c_M0X0(); + void g65816i_7d_M0X0(); + void g65816i_7e_M0X0(); + void g65816i_7f_M0X0(); + void g65816i_80_M0X0(); + void g65816i_81_M0X0(); + void g65816i_82_M0X0(); + void g65816i_83_M0X0(); + void g65816i_84_M0X0(); + void g65816i_85_M0X0(); + void g65816i_86_M0X0(); + void g65816i_87_M0X0(); + void g65816i_88_M0X0(); + void g65816i_89_M0X0(); + void g65816i_8a_M0X0(); + void g65816i_8b_M0X0(); + void g65816i_8c_M0X0(); + void g65816i_8d_M0X0(); + void g65816i_8e_M0X0(); + void g65816i_8f_M0X0(); + void g65816i_90_M0X0(); + void g65816i_91_M0X0(); + void g65816i_92_M0X0(); + void g65816i_93_M0X0(); + void g65816i_94_M0X0(); + void g65816i_95_M0X0(); + void g65816i_96_M0X0(); + void g65816i_97_M0X0(); + void g65816i_98_M0X0(); + void g65816i_99_M0X0(); + void g65816i_9a_M0X0(); + void g65816i_9b_M0X0(); + void g65816i_9c_M0X0(); + void g65816i_9d_M0X0(); + void g65816i_9e_M0X0(); + void g65816i_9f_M0X0(); + void g65816i_a0_M0X0(); + void g65816i_a1_M0X0(); + void g65816i_a2_M0X0(); + void g65816i_a3_M0X0(); + void g65816i_a4_M0X0(); + void g65816i_a5_M0X0(); + void g65816i_a6_M0X0(); + void g65816i_a7_M0X0(); + void g65816i_a8_M0X0(); + void g65816i_a9_M0X0(); + void g65816i_aa_M0X0(); + void g65816i_ab_M0X0(); + void g65816i_ac_M0X0(); + void g65816i_ad_M0X0(); + void g65816i_ae_M0X0(); + void g65816i_af_M0X0(); + void g65816i_b0_M0X0(); + void g65816i_b1_M0X0(); + void g65816i_b2_M0X0(); + void g65816i_b3_M0X0(); + void g65816i_b4_M0X0(); + void g65816i_b5_M0X0(); + void g65816i_b6_M0X0(); + void g65816i_b7_M0X0(); + void g65816i_b8_M0X0(); + void g65816i_b9_M0X0(); + void g65816i_ba_M0X0(); + void g65816i_bb_M0X0(); + void g65816i_bc_M0X0(); + void g65816i_bd_M0X0(); + void g65816i_be_M0X0(); + void g65816i_bf_M0X0(); + void g65816i_c0_M0X0(); + void g65816i_c1_M0X0(); + void g65816i_c2_M0X0(); + void g65816i_c3_M0X0(); + void g65816i_c4_M0X0(); + void g65816i_c5_M0X0(); + void g65816i_c6_M0X0(); + void g65816i_c7_M0X0(); + void g65816i_c8_M0X0(); + void g65816i_c9_M0X0(); + void g65816i_ca_M0X0(); + void g65816i_cb_M0X0(); + void g65816i_cc_M0X0(); + void g65816i_cd_M0X0(); + void g65816i_ce_M0X0(); + void g65816i_cf_M0X0(); + void g65816i_d0_M0X0(); + void g65816i_d1_M0X0(); + void g65816i_d2_M0X0(); + void g65816i_d3_M0X0(); + void g65816i_d4_M0X0(); + void g65816i_d5_M0X0(); + void g65816i_d6_M0X0(); + void g65816i_d7_M0X0(); + void g65816i_d8_M0X0(); + void g65816i_d9_M0X0(); + void g65816i_da_M0X0(); + void g65816i_db_M0X0(); + void g65816i_dc_M0X0(); + void g65816i_dd_M0X0(); + void g65816i_de_M0X0(); + void g65816i_df_M0X0(); + void g65816i_e0_M0X0(); + void g65816i_e1_M0X0(); + void g65816i_e2_M0X0(); + void g65816i_e3_M0X0(); + void g65816i_e4_M0X0(); + void g65816i_e5_M0X0(); + void g65816i_e6_M0X0(); + void g65816i_e7_M0X0(); + void g65816i_e8_M0X0(); + void g65816i_e9_M0X0(); + void g65816i_ea_M0X0(); + void g65816i_eb_M0X0(); + void g65816i_ec_M0X0(); + void g65816i_ed_M0X0(); + void g65816i_ee_M0X0(); + void g65816i_ef_M0X0(); + void g65816i_f0_M0X0(); + void g65816i_f1_M0X0(); + void g65816i_f2_M0X0(); + void g65816i_f3_M0X0(); + void g65816i_f4_M0X0(); + void g65816i_f5_M0X0(); + void g65816i_f6_M0X0(); + void g65816i_f7_M0X0(); + void g65816i_f8_M0X0(); + void g65816i_f9_M0X0(); + void g65816i_fa_M0X0(); + void g65816i_fb_M0X0(); + void g65816i_fc_M0X0(); + void g65816i_fd_M0X0(); + void g65816i_fe_M0X0(); + void g65816i_ff_M0X0(); + void g65816i_00_M0X1(); + void g65816i_01_M0X1(); + void g65816i_02_M0X1(); + void g65816i_03_M0X1(); + void g65816i_04_M0X1(); + void g65816i_05_M0X1(); + void g65816i_06_M0X1(); + void g65816i_07_M0X1(); + void g65816i_08_M0X1(); + void g65816i_09_M0X1(); + void g65816i_0a_M0X1(); + void g65816i_0b_M0X1(); + void g65816i_0c_M0X1(); + void g65816i_0d_M0X1(); + void g65816i_0e_M0X1(); + void g65816i_0f_M0X1(); + void g65816i_10_M0X1(); + void g65816i_11_M0X1(); + void g65816i_12_M0X1(); + void g65816i_13_M0X1(); + void g65816i_14_M0X1(); + void g65816i_15_M0X1(); + void g65816i_16_M0X1(); + void g65816i_17_M0X1(); + void g65816i_18_M0X1(); + void g65816i_19_M0X1(); + void g65816i_1a_M0X1(); + void g65816i_1b_M0X1(); + void g65816i_1c_M0X1(); + void g65816i_1d_M0X1(); + void g65816i_1e_M0X1(); + void g65816i_1f_M0X1(); + void g65816i_20_M0X1(); + void g65816i_21_M0X1(); + void g65816i_22_M0X1(); + void g65816i_23_M0X1(); + void g65816i_24_M0X1(); + void g65816i_25_M0X1(); + void g65816i_26_M0X1(); + void g65816i_27_M0X1(); + void g65816i_28_M0X1(); + void g65816i_29_M0X1(); + void g65816i_2a_M0X1(); + void g65816i_2b_M0X1(); + void g65816i_2c_M0X1(); + void g65816i_2d_M0X1(); + void g65816i_2e_M0X1(); + void g65816i_2f_M0X1(); + void g65816i_30_M0X1(); + void g65816i_31_M0X1(); + void g65816i_32_M0X1(); + void g65816i_33_M0X1(); + void g65816i_34_M0X1(); + void g65816i_35_M0X1(); + void g65816i_36_M0X1(); + void g65816i_37_M0X1(); + void g65816i_38_M0X1(); + void g65816i_39_M0X1(); + void g65816i_3a_M0X1(); + void g65816i_3b_M0X1(); + void g65816i_3c_M0X1(); + void g65816i_3d_M0X1(); + void g65816i_3e_M0X1(); + void g65816i_3f_M0X1(); + void g65816i_40_M0X1(); + void g65816i_41_M0X1(); + void g65816i_42_M0X1(); + void g65816i_43_M0X1(); + void g65816i_44_M0X1(); + void g65816i_45_M0X1(); + void g65816i_46_M0X1(); + void g65816i_47_M0X1(); + void g65816i_48_M0X1(); + void g65816i_49_M0X1(); + void g65816i_4a_M0X1(); + void g65816i_4b_M0X1(); + void g65816i_4c_M0X1(); + void g65816i_4d_M0X1(); + void g65816i_4e_M0X1(); + void g65816i_4f_M0X1(); + void g65816i_50_M0X1(); + void g65816i_51_M0X1(); + void g65816i_52_M0X1(); + void g65816i_53_M0X1(); + void g65816i_54_M0X1(); + void g65816i_55_M0X1(); + void g65816i_56_M0X1(); + void g65816i_57_M0X1(); + void g65816i_58_M0X1(); + void g65816i_59_M0X1(); + void g65816i_5a_M0X1(); + void g65816i_5b_M0X1(); + void g65816i_5c_M0X1(); + void g65816i_5d_M0X1(); + void g65816i_5e_M0X1(); + void g65816i_5f_M0X1(); + void g65816i_60_M0X1(); + void g65816i_61_M0X1(); + void g65816i_62_M0X1(); + void g65816i_63_M0X1(); + void g65816i_64_M0X1(); + void g65816i_65_M0X1(); + void g65816i_66_M0X1(); + void g65816i_67_M0X1(); + void g65816i_68_M0X1(); + void g65816i_69_M0X1(); + void g65816i_6a_M0X1(); + void g65816i_6b_M0X1(); + void g65816i_6c_M0X1(); + void g65816i_6d_M0X1(); + void g65816i_6e_M0X1(); + void g65816i_6f_M0X1(); + void g65816i_70_M0X1(); + void g65816i_71_M0X1(); + void g65816i_72_M0X1(); + void g65816i_73_M0X1(); + void g65816i_74_M0X1(); + void g65816i_75_M0X1(); + void g65816i_76_M0X1(); + void g65816i_77_M0X1(); + void g65816i_78_M0X1(); + void g65816i_79_M0X1(); + void g65816i_7a_M0X1(); + void g65816i_7b_M0X1(); + void g65816i_7c_M0X1(); + void g65816i_7d_M0X1(); + void g65816i_7e_M0X1(); + void g65816i_7f_M0X1(); + void g65816i_80_M0X1(); + void g65816i_81_M0X1(); + void g65816i_82_M0X1(); + void g65816i_83_M0X1(); + void g65816i_84_M0X1(); + void g65816i_85_M0X1(); + void g65816i_86_M0X1(); + void g65816i_87_M0X1(); + void g65816i_88_M0X1(); + void g65816i_89_M0X1(); + void g65816i_8a_M0X1(); + void g65816i_8b_M0X1(); + void g65816i_8c_M0X1(); + void g65816i_8d_M0X1(); + void g65816i_8e_M0X1(); + void g65816i_8f_M0X1(); + void g65816i_90_M0X1(); + void g65816i_91_M0X1(); + void g65816i_92_M0X1(); + void g65816i_93_M0X1(); + void g65816i_94_M0X1(); + void g65816i_95_M0X1(); + void g65816i_96_M0X1(); + void g65816i_97_M0X1(); + void g65816i_98_M0X1(); + void g65816i_99_M0X1(); + void g65816i_9a_M0X1(); + void g65816i_9b_M0X1(); + void g65816i_9c_M0X1(); + void g65816i_9d_M0X1(); + void g65816i_9e_M0X1(); + void g65816i_9f_M0X1(); + void g65816i_a0_M0X1(); + void g65816i_a1_M0X1(); + void g65816i_a2_M0X1(); + void g65816i_a3_M0X1(); + void g65816i_a4_M0X1(); + void g65816i_a5_M0X1(); + void g65816i_a6_M0X1(); + void g65816i_a7_M0X1(); + void g65816i_a8_M0X1(); + void g65816i_a9_M0X1(); + void g65816i_aa_M0X1(); + void g65816i_ab_M0X1(); + void g65816i_ac_M0X1(); + void g65816i_ad_M0X1(); + void g65816i_ae_M0X1(); + void g65816i_af_M0X1(); + void g65816i_b0_M0X1(); + void g65816i_b1_M0X1(); + void g65816i_b2_M0X1(); + void g65816i_b3_M0X1(); + void g65816i_b4_M0X1(); + void g65816i_b5_M0X1(); + void g65816i_b6_M0X1(); + void g65816i_b7_M0X1(); + void g65816i_b8_M0X1(); + void g65816i_b9_M0X1(); + void g65816i_ba_M0X1(); + void g65816i_bb_M0X1(); + void g65816i_bc_M0X1(); + void g65816i_bd_M0X1(); + void g65816i_be_M0X1(); + void g65816i_bf_M0X1(); + void g65816i_c0_M0X1(); + void g65816i_c1_M0X1(); + void g65816i_c2_M0X1(); + void g65816i_c3_M0X1(); + void g65816i_c4_M0X1(); + void g65816i_c5_M0X1(); + void g65816i_c6_M0X1(); + void g65816i_c7_M0X1(); + void g65816i_c8_M0X1(); + void g65816i_c9_M0X1(); + void g65816i_ca_M0X1(); + void g65816i_cb_M0X1(); + void g65816i_cc_M0X1(); + void g65816i_cd_M0X1(); + void g65816i_ce_M0X1(); + void g65816i_cf_M0X1(); + void g65816i_d0_M0X1(); + void g65816i_d1_M0X1(); + void g65816i_d2_M0X1(); + void g65816i_d3_M0X1(); + void g65816i_d4_M0X1(); + void g65816i_d5_M0X1(); + void g65816i_d6_M0X1(); + void g65816i_d7_M0X1(); + void g65816i_d8_M0X1(); + void g65816i_d9_M0X1(); + void g65816i_da_M0X1(); + void g65816i_db_M0X1(); + void g65816i_dc_M0X1(); + void g65816i_dd_M0X1(); + void g65816i_de_M0X1(); + void g65816i_df_M0X1(); + void g65816i_e0_M0X1(); + void g65816i_e1_M0X1(); + void g65816i_e2_M0X1(); + void g65816i_e3_M0X1(); + void g65816i_e4_M0X1(); + void g65816i_e5_M0X1(); + void g65816i_e6_M0X1(); + void g65816i_e7_M0X1(); + void g65816i_e8_M0X1(); + void g65816i_e9_M0X1(); + void g65816i_ea_M0X1(); + void g65816i_eb_M0X1(); + void g65816i_ec_M0X1(); + void g65816i_ed_M0X1(); + void g65816i_ee_M0X1(); + void g65816i_ef_M0X1(); + void g65816i_f0_M0X1(); + void g65816i_f1_M0X1(); + void g65816i_f2_M0X1(); + void g65816i_f3_M0X1(); + void g65816i_f4_M0X1(); + void g65816i_f5_M0X1(); + void g65816i_f6_M0X1(); + void g65816i_f7_M0X1(); + void g65816i_f8_M0X1(); + void g65816i_f9_M0X1(); + void g65816i_fa_M0X1(); + void g65816i_fb_M0X1(); + void g65816i_fc_M0X1(); + void g65816i_fd_M0X1(); + void g65816i_fe_M0X1(); + void g65816i_ff_M0X1(); + void g65816i_00_M1X0(); + void g65816i_01_M1X0(); + void g65816i_02_M1X0(); + void g65816i_03_M1X0(); + void g65816i_04_M1X0(); + void g65816i_05_M1X0(); + void g65816i_06_M1X0(); + void g65816i_07_M1X0(); + void g65816i_08_M1X0(); + void g65816i_09_M1X0(); + void g65816i_0a_M1X0(); + void g65816i_0b_M1X0(); + void g65816i_0c_M1X0(); + void g65816i_0d_M1X0(); + void g65816i_0e_M1X0(); + void g65816i_0f_M1X0(); + void g65816i_10_M1X0(); + void g65816i_11_M1X0(); + void g65816i_12_M1X0(); + void g65816i_13_M1X0(); + void g65816i_14_M1X0(); + void g65816i_15_M1X0(); + void g65816i_16_M1X0(); + void g65816i_17_M1X0(); + void g65816i_18_M1X0(); + void g65816i_19_M1X0(); + void g65816i_1a_M1X0(); + void g65816i_1b_M1X0(); + void g65816i_1c_M1X0(); + void g65816i_1d_M1X0(); + void g65816i_1e_M1X0(); + void g65816i_1f_M1X0(); + void g65816i_20_M1X0(); + void g65816i_21_M1X0(); + void g65816i_22_M1X0(); + void g65816i_23_M1X0(); + void g65816i_24_M1X0(); + void g65816i_25_M1X0(); + void g65816i_26_M1X0(); + void g65816i_27_M1X0(); + void g65816i_28_M1X0(); + void g65816i_29_M1X0(); + void g65816i_2a_M1X0(); + void g65816i_2b_M1X0(); + void g65816i_2c_M1X0(); + void g65816i_2d_M1X0(); + void g65816i_2e_M1X0(); + void g65816i_2f_M1X0(); + void g65816i_30_M1X0(); + void g65816i_31_M1X0(); + void g65816i_32_M1X0(); + void g65816i_33_M1X0(); + void g65816i_34_M1X0(); + void g65816i_35_M1X0(); + void g65816i_36_M1X0(); + void g65816i_37_M1X0(); + void g65816i_38_M1X0(); + void g65816i_39_M1X0(); + void g65816i_3a_M1X0(); + void g65816i_3b_M1X0(); + void g65816i_3c_M1X0(); + void g65816i_3d_M1X0(); + void g65816i_3e_M1X0(); + void g65816i_3f_M1X0(); + void g65816i_40_M1X0(); + void g65816i_41_M1X0(); + void g65816i_42_M1X0(); + void g65816i_43_M1X0(); + void g65816i_44_M1X0(); + void g65816i_45_M1X0(); + void g65816i_46_M1X0(); + void g65816i_47_M1X0(); + void g65816i_48_M1X0(); + void g65816i_49_M1X0(); + void g65816i_4a_M1X0(); + void g65816i_4b_M1X0(); + void g65816i_4c_M1X0(); + void g65816i_4d_M1X0(); + void g65816i_4e_M1X0(); + void g65816i_4f_M1X0(); + void g65816i_50_M1X0(); + void g65816i_51_M1X0(); + void g65816i_52_M1X0(); + void g65816i_53_M1X0(); + void g65816i_54_M1X0(); + void g65816i_55_M1X0(); + void g65816i_56_M1X0(); + void g65816i_57_M1X0(); + void g65816i_58_M1X0(); + void g65816i_59_M1X0(); + void g65816i_5a_M1X0(); + void g65816i_5b_M1X0(); + void g65816i_5c_M1X0(); + void g65816i_5d_M1X0(); + void g65816i_5e_M1X0(); + void g65816i_5f_M1X0(); + void g65816i_60_M1X0(); + void g65816i_61_M1X0(); + void g65816i_62_M1X0(); + void g65816i_63_M1X0(); + void g65816i_64_M1X0(); + void g65816i_65_M1X0(); + void g65816i_66_M1X0(); + void g65816i_67_M1X0(); + void g65816i_68_M1X0(); + void g65816i_69_M1X0(); + void g65816i_6a_M1X0(); + void g65816i_6b_M1X0(); + void g65816i_6c_M1X0(); + void g65816i_6d_M1X0(); + void g65816i_6e_M1X0(); + void g65816i_6f_M1X0(); + void g65816i_70_M1X0(); + void g65816i_71_M1X0(); + void g65816i_72_M1X0(); + void g65816i_73_M1X0(); + void g65816i_74_M1X0(); + void g65816i_75_M1X0(); + void g65816i_76_M1X0(); + void g65816i_77_M1X0(); + void g65816i_78_M1X0(); + void g65816i_79_M1X0(); + void g65816i_7a_M1X0(); + void g65816i_7b_M1X0(); + void g65816i_7c_M1X0(); + void g65816i_7d_M1X0(); + void g65816i_7e_M1X0(); + void g65816i_7f_M1X0(); + void g65816i_80_M1X0(); + void g65816i_81_M1X0(); + void g65816i_82_M1X0(); + void g65816i_83_M1X0(); + void g65816i_84_M1X0(); + void g65816i_85_M1X0(); + void g65816i_86_M1X0(); + void g65816i_87_M1X0(); + void g65816i_88_M1X0(); + void g65816i_89_M1X0(); + void g65816i_8a_M1X0(); + void g65816i_8b_M1X0(); + void g65816i_8c_M1X0(); + void g65816i_8d_M1X0(); + void g65816i_8e_M1X0(); + void g65816i_8f_M1X0(); + void g65816i_90_M1X0(); + void g65816i_91_M1X0(); + void g65816i_92_M1X0(); + void g65816i_93_M1X0(); + void g65816i_94_M1X0(); + void g65816i_95_M1X0(); + void g65816i_96_M1X0(); + void g65816i_97_M1X0(); + void g65816i_98_M1X0(); + void g65816i_99_M1X0(); + void g65816i_9a_M1X0(); + void g65816i_9b_M1X0(); + void g65816i_9c_M1X0(); + void g65816i_9d_M1X0(); + void g65816i_9e_M1X0(); + void g65816i_9f_M1X0(); + void g65816i_a0_M1X0(); + void g65816i_a1_M1X0(); + void g65816i_a2_M1X0(); + void g65816i_a3_M1X0(); + void g65816i_a4_M1X0(); + void g65816i_a5_M1X0(); + void g65816i_a6_M1X0(); + void g65816i_a7_M1X0(); + void g65816i_a8_M1X0(); + void g65816i_a9_M1X0(); + void g65816i_aa_M1X0(); + void g65816i_ab_M1X0(); + void g65816i_ac_M1X0(); + void g65816i_ad_M1X0(); + void g65816i_ae_M1X0(); + void g65816i_af_M1X0(); + void g65816i_b0_M1X0(); + void g65816i_b1_M1X0(); + void g65816i_b2_M1X0(); + void g65816i_b3_M1X0(); + void g65816i_b4_M1X0(); + void g65816i_b5_M1X0(); + void g65816i_b6_M1X0(); + void g65816i_b7_M1X0(); + void g65816i_b8_M1X0(); + void g65816i_b9_M1X0(); + void g65816i_ba_M1X0(); + void g65816i_bb_M1X0(); + void g65816i_bc_M1X0(); + void g65816i_bd_M1X0(); + void g65816i_be_M1X0(); + void g65816i_bf_M1X0(); + void g65816i_c0_M1X0(); + void g65816i_c1_M1X0(); + void g65816i_c2_M1X0(); + void g65816i_c3_M1X0(); + void g65816i_c4_M1X0(); + void g65816i_c5_M1X0(); + void g65816i_c6_M1X0(); + void g65816i_c7_M1X0(); + void g65816i_c8_M1X0(); + void g65816i_c9_M1X0(); + void g65816i_ca_M1X0(); + void g65816i_cb_M1X0(); + void g65816i_cc_M1X0(); + void g65816i_cd_M1X0(); + void g65816i_ce_M1X0(); + void g65816i_cf_M1X0(); + void g65816i_d0_M1X0(); + void g65816i_d1_M1X0(); + void g65816i_d2_M1X0(); + void g65816i_d3_M1X0(); + void g65816i_d4_M1X0(); + void g65816i_d5_M1X0(); + void g65816i_d6_M1X0(); + void g65816i_d7_M1X0(); + void g65816i_d8_M1X0(); + void g65816i_d9_M1X0(); + void g65816i_da_M1X0(); + void g65816i_db_M1X0(); + void g65816i_dc_M1X0(); + void g65816i_dd_M1X0(); + void g65816i_de_M1X0(); + void g65816i_df_M1X0(); + void g65816i_e0_M1X0(); + void g65816i_e1_M1X0(); + void g65816i_e2_M1X0(); + void g65816i_e3_M1X0(); + void g65816i_e4_M1X0(); + void g65816i_e5_M1X0(); + void g65816i_e6_M1X0(); + void g65816i_e7_M1X0(); + void g65816i_e8_M1X0(); + void g65816i_e9_M1X0(); + void g65816i_ea_M1X0(); + void g65816i_eb_M1X0(); + void g65816i_ec_M1X0(); + void g65816i_ed_M1X0(); + void g65816i_ee_M1X0(); + void g65816i_ef_M1X0(); + void g65816i_f0_M1X0(); + void g65816i_f1_M1X0(); + void g65816i_f2_M1X0(); + void g65816i_f3_M1X0(); + void g65816i_f4_M1X0(); + void g65816i_f5_M1X0(); + void g65816i_f6_M1X0(); + void g65816i_f7_M1X0(); + void g65816i_f8_M1X0(); + void g65816i_f9_M1X0(); + void g65816i_fa_M1X0(); + void g65816i_fb_M1X0(); + void g65816i_fc_M1X0(); + void g65816i_fd_M1X0(); + void g65816i_fe_M1X0(); + void g65816i_ff_M1X0(); + void g65816i_00_M1X1(); + void g65816i_01_M1X1(); + void g65816i_02_M1X1(); + void g65816i_03_M1X1(); + void g65816i_04_M1X1(); + void g65816i_05_M1X1(); + void g65816i_06_M1X1(); + void g65816i_07_M1X1(); + void g65816i_08_M1X1(); + void g65816i_09_M1X1(); + void g65816i_0a_M1X1(); + void g65816i_0b_M1X1(); + void g65816i_0c_M1X1(); + void g65816i_0d_M1X1(); + void g65816i_0e_M1X1(); + void g65816i_0f_M1X1(); + void g65816i_10_M1X1(); + void g65816i_11_M1X1(); + void g65816i_12_M1X1(); + void g65816i_13_M1X1(); + void g65816i_14_M1X1(); + void g65816i_15_M1X1(); + void g65816i_16_M1X1(); + void g65816i_17_M1X1(); + void g65816i_18_M1X1(); + void g65816i_19_M1X1(); + void g65816i_1a_M1X1(); + void g65816i_1b_M1X1(); + void g65816i_1c_M1X1(); + void g65816i_1d_M1X1(); + void g65816i_1e_M1X1(); + void g65816i_1f_M1X1(); + void g65816i_20_M1X1(); + void g65816i_21_M1X1(); + void g65816i_22_M1X1(); + void g65816i_23_M1X1(); + void g65816i_24_M1X1(); + void g65816i_25_M1X1(); + void g65816i_26_M1X1(); + void g65816i_27_M1X1(); + void g65816i_28_M1X1(); + void g65816i_29_M1X1(); + void g65816i_2a_M1X1(); + void g65816i_2b_M1X1(); + void g65816i_2c_M1X1(); + void g65816i_2d_M1X1(); + void g65816i_2e_M1X1(); + void g65816i_2f_M1X1(); + void g65816i_30_M1X1(); + void g65816i_31_M1X1(); + void g65816i_32_M1X1(); + void g65816i_33_M1X1(); + void g65816i_34_M1X1(); + void g65816i_35_M1X1(); + void g65816i_36_M1X1(); + void g65816i_37_M1X1(); + void g65816i_38_M1X1(); + void g65816i_39_M1X1(); + void g65816i_3a_M1X1(); + void g65816i_3b_M1X1(); + void g65816i_3c_M1X1(); + void g65816i_3d_M1X1(); + void g65816i_3e_M1X1(); + void g65816i_3f_M1X1(); + void g65816i_40_M1X1(); + void g65816i_41_M1X1(); + void g65816i_42_M1X1(); + void g65816i_43_M1X1(); + void g65816i_44_M1X1(); + void g65816i_45_M1X1(); + void g65816i_46_M1X1(); + void g65816i_47_M1X1(); + void g65816i_48_M1X1(); + void g65816i_49_M1X1(); + void g65816i_4a_M1X1(); + void g65816i_4b_M1X1(); + void g65816i_4c_M1X1(); + void g65816i_4d_M1X1(); + void g65816i_4e_M1X1(); + void g65816i_4f_M1X1(); + void g65816i_50_M1X1(); + void g65816i_51_M1X1(); + void g65816i_52_M1X1(); + void g65816i_53_M1X1(); + void g65816i_54_M1X1(); + void g65816i_55_M1X1(); + void g65816i_56_M1X1(); + void g65816i_57_M1X1(); + void g65816i_58_M1X1(); + void g65816i_59_M1X1(); + void g65816i_5a_M1X1(); + void g65816i_5b_M1X1(); + void g65816i_5c_M1X1(); + void g65816i_5d_M1X1(); + void g65816i_5e_M1X1(); + void g65816i_5f_M1X1(); + void g65816i_60_M1X1(); + void g65816i_61_M1X1(); + void g65816i_62_M1X1(); + void g65816i_63_M1X1(); + void g65816i_64_M1X1(); + void g65816i_65_M1X1(); + void g65816i_66_M1X1(); + void g65816i_67_M1X1(); + void g65816i_68_M1X1(); + void g65816i_69_M1X1(); + void g65816i_6a_M1X1(); + void g65816i_6b_M1X1(); + void g65816i_6c_M1X1(); + void g65816i_6d_M1X1(); + void g65816i_6e_M1X1(); + void g65816i_6f_M1X1(); + void g65816i_70_M1X1(); + void g65816i_71_M1X1(); + void g65816i_72_M1X1(); + void g65816i_73_M1X1(); + void g65816i_74_M1X1(); + void g65816i_75_M1X1(); + void g65816i_76_M1X1(); + void g65816i_77_M1X1(); + void g65816i_78_M1X1(); + void g65816i_79_M1X1(); + void g65816i_7a_M1X1(); + void g65816i_7b_M1X1(); + void g65816i_7c_M1X1(); + void g65816i_7d_M1X1(); + void g65816i_7e_M1X1(); + void g65816i_7f_M1X1(); + void g65816i_80_M1X1(); + void g65816i_81_M1X1(); + void g65816i_82_M1X1(); + void g65816i_83_M1X1(); + void g65816i_84_M1X1(); + void g65816i_85_M1X1(); + void g65816i_86_M1X1(); + void g65816i_87_M1X1(); + void g65816i_88_M1X1(); + void g65816i_89_M1X1(); + void g65816i_8a_M1X1(); + void g65816i_8b_M1X1(); + void g65816i_8c_M1X1(); + void g65816i_8d_M1X1(); + void g65816i_8e_M1X1(); + void g65816i_8f_M1X1(); + void g65816i_90_M1X1(); + void g65816i_91_M1X1(); + void g65816i_92_M1X1(); + void g65816i_93_M1X1(); + void g65816i_94_M1X1(); + void g65816i_95_M1X1(); + void g65816i_96_M1X1(); + void g65816i_97_M1X1(); + void g65816i_98_M1X1(); + void g65816i_99_M1X1(); + void g65816i_9a_M1X1(); + void g65816i_9b_M1X1(); + void g65816i_9c_M1X1(); + void g65816i_9d_M1X1(); + void g65816i_9e_M1X1(); + void g65816i_9f_M1X1(); + void g65816i_a0_M1X1(); + void g65816i_a1_M1X1(); + void g65816i_a2_M1X1(); + void g65816i_a3_M1X1(); + void g65816i_a4_M1X1(); + void g65816i_a5_M1X1(); + void g65816i_a6_M1X1(); + void g65816i_a7_M1X1(); + void g65816i_a8_M1X1(); + void g65816i_a9_M1X1(); + void g65816i_aa_M1X1(); + void g65816i_ab_M1X1(); + void g65816i_ac_M1X1(); + void g65816i_ad_M1X1(); + void g65816i_ae_M1X1(); + void g65816i_af_M1X1(); + void g65816i_b0_M1X1(); + void g65816i_b1_M1X1(); + void g65816i_b2_M1X1(); + void g65816i_b3_M1X1(); + void g65816i_b4_M1X1(); + void g65816i_b5_M1X1(); + void g65816i_b6_M1X1(); + void g65816i_b7_M1X1(); + void g65816i_b8_M1X1(); + void g65816i_b9_M1X1(); + void g65816i_ba_M1X1(); + void g65816i_bb_M1X1(); + void g65816i_bc_M1X1(); + void g65816i_bd_M1X1(); + void g65816i_be_M1X1(); + void g65816i_bf_M1X1(); + void g65816i_c0_M1X1(); + void g65816i_c1_M1X1(); + void g65816i_c2_M1X1(); + void g65816i_c3_M1X1(); + void g65816i_c4_M1X1(); + void g65816i_c5_M1X1(); + void g65816i_c6_M1X1(); + void g65816i_c7_M1X1(); + void g65816i_c8_M1X1(); + void g65816i_c9_M1X1(); + void g65816i_ca_M1X1(); + void g65816i_cb_M1X1(); + void g65816i_cc_M1X1(); + void g65816i_cd_M1X1(); + void g65816i_ce_M1X1(); + void g65816i_cf_M1X1(); + void g65816i_d0_M1X1(); + void g65816i_d1_M1X1(); + void g65816i_d2_M1X1(); + void g65816i_d3_M1X1(); + void g65816i_d4_M1X1(); + void g65816i_d5_M1X1(); + void g65816i_d6_M1X1(); + void g65816i_d7_M1X1(); + void g65816i_d8_M1X1(); + void g65816i_d9_M1X1(); + void g65816i_da_M1X1(); + void g65816i_db_M1X1(); + void g65816i_dc_M1X1(); + void g65816i_dd_M1X1(); + void g65816i_de_M1X1(); + void g65816i_df_M1X1(); + void g65816i_e0_M1X1(); + void g65816i_e1_M1X1(); + void g65816i_e2_M1X1(); + void g65816i_e3_M1X1(); + void g65816i_e4_M1X1(); + void g65816i_e5_M1X1(); + void g65816i_e6_M1X1(); + void g65816i_e7_M1X1(); + void g65816i_e8_M1X1(); + void g65816i_e9_M1X1(); + void g65816i_ea_M1X1(); + void g65816i_eb_M1X1(); + void g65816i_ec_M1X1(); + void g65816i_ed_M1X1(); + void g65816i_ee_M1X1(); + void g65816i_ef_M1X1(); + void g65816i_f0_M1X1(); + void g65816i_f1_M1X1(); + void g65816i_f2_M1X1(); + void g65816i_f3_M1X1(); + void g65816i_f4_M1X1(); + void g65816i_f5_M1X1(); + void g65816i_f6_M1X1(); + void g65816i_f7_M1X1(); + void g65816i_f8_M1X1(); + void g65816i_f9_M1X1(); + void g65816i_fa_M1X1(); + void g65816i_fb_M1X1(); + void g65816i_fc_M1X1(); + void g65816i_fd_M1X1(); + void g65816i_fe_M1X1(); + void g65816i_ff_M1X1(); + void g65816i_00_E(); + void g65816i_01_E(); + void g65816i_02_E(); + void g65816i_03_E(); + void g65816i_04_E(); + void g65816i_05_E(); + void g65816i_06_E(); + void g65816i_07_E(); + void g65816i_08_E(); + void g65816i_09_E(); + void g65816i_0a_E(); + void g65816i_0b_E(); + void g65816i_0c_E(); + void g65816i_0d_E(); + void g65816i_0e_E(); + void g65816i_0f_E(); + void g65816i_10_E(); + void g65816i_11_E(); + void g65816i_12_E(); + void g65816i_13_E(); + void g65816i_14_E(); + void g65816i_15_E(); + void g65816i_16_E(); + void g65816i_17_E(); + void g65816i_18_E(); + void g65816i_19_E(); + void g65816i_1a_E(); + void g65816i_1b_E(); + void g65816i_1c_E(); + void g65816i_1d_E(); + void g65816i_1e_E(); + void g65816i_1f_E(); + void g65816i_20_E(); + void g65816i_21_E(); + void g65816i_22_E(); + void g65816i_23_E(); + void g65816i_24_E(); + void g65816i_25_E(); + void g65816i_26_E(); + void g65816i_27_E(); + void g65816i_28_E(); + void g65816i_29_E(); + void g65816i_2a_E(); + void g65816i_2b_E(); + void g65816i_2c_E(); + void g65816i_2d_E(); + void g65816i_2e_E(); + void g65816i_2f_E(); + void g65816i_30_E(); + void g65816i_31_E(); + void g65816i_32_E(); + void g65816i_33_E(); + void g65816i_34_E(); + void g65816i_35_E(); + void g65816i_36_E(); + void g65816i_37_E(); + void g65816i_38_E(); + void g65816i_39_E(); + void g65816i_3a_E(); + void g65816i_3b_E(); + void g65816i_3c_E(); + void g65816i_3d_E(); + void g65816i_3e_E(); + void g65816i_3f_E(); + void g65816i_40_E(); + void g65816i_41_E(); + void g65816i_42_E(); + void g65816i_43_E(); + void g65816i_44_E(); + void g65816i_45_E(); + void g65816i_46_E(); + void g65816i_47_E(); + void g65816i_48_E(); + void g65816i_49_E(); + void g65816i_4a_E(); + void g65816i_4b_E(); + void g65816i_4c_E(); + void g65816i_4d_E(); + void g65816i_4e_E(); + void g65816i_4f_E(); + void g65816i_50_E(); + void g65816i_51_E(); + void g65816i_52_E(); + void g65816i_53_E(); + void g65816i_54_E(); + void g65816i_55_E(); + void g65816i_56_E(); + void g65816i_57_E(); + void g65816i_58_E(); + void g65816i_59_E(); + void g65816i_5a_E(); + void g65816i_5b_E(); + void g65816i_5c_E(); + void g65816i_5d_E(); + void g65816i_5e_E(); + void g65816i_5f_E(); + void g65816i_60_E(); + void g65816i_61_E(); + void g65816i_62_E(); + void g65816i_63_E(); + void g65816i_64_E(); + void g65816i_65_E(); + void g65816i_66_E(); + void g65816i_67_E(); + void g65816i_68_E(); + void g65816i_69_E(); + void g65816i_6a_E(); + void g65816i_6b_E(); + void g65816i_6c_E(); + void g65816i_6d_E(); + void g65816i_6e_E(); + void g65816i_6f_E(); + void g65816i_70_E(); + void g65816i_71_E(); + void g65816i_72_E(); + void g65816i_73_E(); + void g65816i_74_E(); + void g65816i_75_E(); + void g65816i_76_E(); + void g65816i_77_E(); + void g65816i_78_E(); + void g65816i_79_E(); + void g65816i_7a_E(); + void g65816i_7b_E(); + void g65816i_7c_E(); + void g65816i_7d_E(); + void g65816i_7e_E(); + void g65816i_7f_E(); + void g65816i_80_E(); + void g65816i_81_E(); + void g65816i_82_E(); + void g65816i_83_E(); + void g65816i_84_E(); + void g65816i_85_E(); + void g65816i_86_E(); + void g65816i_87_E(); + void g65816i_88_E(); + void g65816i_89_E(); + void g65816i_8a_E(); + void g65816i_8b_E(); + void g65816i_8c_E(); + void g65816i_8d_E(); + void g65816i_8e_E(); + void g65816i_8f_E(); + void g65816i_90_E(); + void g65816i_91_E(); + void g65816i_92_E(); + void g65816i_93_E(); + void g65816i_94_E(); + void g65816i_95_E(); + void g65816i_96_E(); + void g65816i_97_E(); + void g65816i_98_E(); + void g65816i_99_E(); + void g65816i_9a_E(); + void g65816i_9b_E(); + void g65816i_9c_E(); + void g65816i_9d_E(); + void g65816i_9e_E(); + void g65816i_9f_E(); + void g65816i_a0_E(); + void g65816i_a1_E(); + void g65816i_a2_E(); + void g65816i_a3_E(); + void g65816i_a4_E(); + void g65816i_a5_E(); + void g65816i_a6_E(); + void g65816i_a7_E(); + void g65816i_a8_E(); + void g65816i_a9_E(); + void g65816i_aa_E(); + void g65816i_ab_E(); + void g65816i_ac_E(); + void g65816i_ad_E(); + void g65816i_ae_E(); + void g65816i_af_E(); + void g65816i_b0_E(); + void g65816i_b1_E(); + void g65816i_b2_E(); + void g65816i_b3_E(); + void g65816i_b4_E(); + void g65816i_b5_E(); + void g65816i_b6_E(); + void g65816i_b7_E(); + void g65816i_b8_E(); + void g65816i_b9_E(); + void g65816i_ba_E(); + void g65816i_bb_E(); + void g65816i_bc_E(); + void g65816i_bd_E(); + void g65816i_be_E(); + void g65816i_bf_E(); + void g65816i_c0_E(); + void g65816i_c1_E(); + void g65816i_c2_E(); + void g65816i_c3_E(); + void g65816i_c4_E(); + void g65816i_c5_E(); + void g65816i_c6_E(); + void g65816i_c7_E(); + void g65816i_c8_E(); + void g65816i_c9_E(); + void g65816i_ca_E(); + void g65816i_cb_E(); + void g65816i_cc_E(); + void g65816i_cd_E(); + void g65816i_ce_E(); + void g65816i_cf_E(); + void g65816i_d0_E(); + void g65816i_d1_E(); + void g65816i_d2_E(); + void g65816i_d3_E(); + void g65816i_d4_E(); + void g65816i_d5_E(); + void g65816i_d6_E(); + void g65816i_d7_E(); + void g65816i_d8_E(); + void g65816i_d9_E(); + void g65816i_da_E(); + void g65816i_db_E(); + void g65816i_dc_E(); + void g65816i_dd_E(); + void g65816i_de_E(); + void g65816i_df_E(); + void g65816i_e0_E(); + void g65816i_e1_E(); + void g65816i_e2_E(); + void g65816i_e3_E(); + void g65816i_e4_E(); + void g65816i_e5_E(); + void g65816i_e6_E(); + void g65816i_e7_E(); + void g65816i_e8_E(); + void g65816i_e9_E(); + void g65816i_ea_E(); + void g65816i_eb_E(); + void g65816i_ec_E(); + void g65816i_ed_E(); + void g65816i_ee_E(); + void g65816i_ef_E(); + void g65816i_f0_E(); + void g65816i_f1_E(); + void g65816i_f2_E(); + void g65816i_f3_E(); + void g65816i_f4_E(); + void g65816i_f5_E(); + void g65816i_f6_E(); + void g65816i_f7_E(); + void g65816i_f8_E(); + void g65816i_f9_E(); + void g65816i_fa_E(); + void g65816i_fb_E(); + void g65816i_fc_E(); + void g65816i_fd_E(); + void g65816i_fe_E(); + void g65816i_ff_E(); +}; + + +class _5a22_device : public g65816_device +{ +public: + _5a22_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + DECLARE_WRITE8_MEMBER( wrmpya_w ); + DECLARE_WRITE8_MEMBER( wrmpyb_w ); + DECLARE_WRITE8_MEMBER( wrdivl_w ); + DECLARE_WRITE8_MEMBER( wrdivh_w ); + DECLARE_WRITE8_MEMBER( wrdvdd_w ); + DECLARE_WRITE8_MEMBER( memsel_w ); + DECLARE_READ8_MEMBER( rddivl_r ); + DECLARE_READ8_MEMBER( rddivh_r ); + DECLARE_READ8_MEMBER( rdmpyl_r ); + DECLARE_READ8_MEMBER( rdmpyh_r ); + + void set_5a22_map(); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_state_interface overrides + virtual void state_import(const device_state_entry &entry); + virtual void state_export(const device_state_entry &entry); +}; + + +extern const device_type G65816; +extern const device_type _5A22; + + +#define CPU_TYPE_G65816 0 +#define CPU_TYPE_5A22 1 + + +/* ======================================================================== */ +/* ============================== END OF FILE ============================= */ +/* ======================================================================== */ + +#endif /* __G65816_H__ */ diff --git a/src/devices/cpu/g65816/g65816cm.h b/src/devices/cpu/g65816/g65816cm.h new file mode 100644 index 00000000000..7cfbcdf2cfb --- /dev/null +++ b/src/devices/cpu/g65816/g65816cm.h @@ -0,0 +1,262 @@ +// license:BSD-3-Clause +// copyright-holders:Karl Stenerud +#pragma once + +#ifndef __G65816CM_H__ +#define __G65816CM_H__ + + +#define g65816i_branching(A) +#define g65816i_jumping(A) + + +#undef G65816_CALL_DEBUGGER +#define G65816_CALL_DEBUGGER(x) debugger_instruction_hook(this, x) + +#define g65816_read_8(addr) m_program->read_byte(addr) +#define g65816_write_8(addr,data) m_program->write_byte(addr,data) +#define g65816_read_8_immediate(A) m_program->read_byte(A) +#define g65816_jumping(A) +#define g65816_branching(A) + + +/* ======================================================================== */ +/* ================================ INCLUDES ============================== */ +/* ======================================================================== */ + +#include + + +/* ======================================================================== */ +/* ================================ GENERAL =============================== */ +/* ======================================================================== */ + +/* This should be set to the default size of your processor (min 16 bit) */ +#undef uint +#define uint unsigned int + +#undef uint8 +#define uint8 unsigned char + +#undef int8 + +/* Allow for architectures that don't have 8-bit sizes */ +#if UCHAR_MAX == 0xff +#define int8 signed char +#define MAKE_INT_8(A) (int8)((A)&0xff) +#else +#define int8 int +INLINE int MAKE_INT_8(int A) {return (A & 0x80) ? A | ~0xff : A & 0xff;} +#endif /* UCHAR_MAX == 0xff */ + +#define MAKE_UINT_8(A) ((A)&0xff) +#define MAKE_UINT_16(A) ((A)&0xffff) +#define MAKE_UINT_24(A) ((A)&0xffffff) + +/* Bits */ +#define BIT_0 0x01 +#define BIT_1 0x02 +#define BIT_2 0x04 +#define BIT_3 0x08 +#define BIT_4 0x10 +#define BIT_5 0x20 +#define BIT_6 0x40 +#define BIT_7 0x80 + + +/* ======================================================================== */ +/* ================================== CPU ================================= */ +/* ======================================================================== */ + + +#define REGISTER_A m_a /* Accumulator */ +#define REGISTER_B m_b /* Accumulator hi byte */ +#define REGISTER_X m_x /* Index X Register */ +#define REGISTER_Y m_y /* Index Y Register */ +#define REGISTER_S m_s /* Stack Pointer */ +#define REGISTER_PC m_pc /* Program Counter */ +#define REGISTER_PPC m_ppc /* Previous Program Counter */ +#define REGISTER_PB m_pb /* Program Bank */ +#define REGISTER_DB m_db /* Data Bank */ +#define REGISTER_D m_d /* Direct Register */ +#define FLAG_E m_flag_e /* Emulation Mode Flag */ +#define FLAG_M m_flag_m /* Memory/Accumulator Select Flag */ +#define FLAG_X m_flag_x /* Index Select Flag */ +#define FLAG_N m_flag_n /* Negative Flag */ +#define FLAG_V m_flag_v /* Overflow Flag */ +#define FLAG_D m_flag_d /* Decimal Mode Flag */ +#define FLAG_I m_flag_i /* Interrupt Mask Flag */ +#define FLAG_Z m_flag_z /* Zero Flag (inverted) */ +#define FLAG_C m_flag_c /* Carry Flag */ +#define LINE_IRQ m_line_irq /* Status of the IRQ line */ +#define LINE_NMI m_line_nmi /* Status of the NMI line */ +#define REGISTER_IR m_ir /* Instruction Register */ +#define INT_ACK m_int_ack /* Interrupt Acknowledge function pointer */ +#define READ_VECTOR m_read_vector /* Vector reading override */ +#define CLOCKS m_ICount /* Clock cycles remaining */ +#define IRQ_DELAY m_irq_delay /* Delay 1 instruction before checking IRQ */ +#define CPU_STOPPED m_stopped /* Stopped status of the CPU */ + +#define FTABLE_OPCODES m_opcodes +#define FTABLE_GET_REG m_get_reg +#define FTABLE_SET_REG m_set_reg +#define FTABLE_SET_LINE m_set_line +#define FTABLE_EXECUTE m_execute + +#define SRC m_source /* Source Operand */ +#define DST m_destination /* Destination Operand */ + +#define STOP_LEVEL_WAI 1 +#define STOP_LEVEL_STOP 2 + +#define EXECUTION_MODE_M0X0 0 +#define EXECUTION_MODE_M0X1 1 +#define EXECUTION_MODE_M1X0 2 +#define EXECUTION_MODE_M1X1 3 +#define EXECUTION_MODE_E 4 + +#define VECTOR_RESET 0xfffc /* Reset */ +#define VECTOR_IRQ_E 0xfffe /* Interrupt Request */ +#define VECTOR_NMI_E 0xfffa /* Non-Maskable Interrupt */ +#define VECTOR_ABORT_E 0xfff8 /* ABORT asserted */ +#define VECTOR_BRK_E 0xfffe /* Break Instruction */ +#define VECTOR_COP_E 0xfff4 /* Coprocessor instruction */ + +#define VECTOR_IRQ_N 0xffee /* Interrupt Request */ +#define VECTOR_NMI_N 0xffea /* Non-Maskable Interrupt */ +#define VECTOR_ABORT_N 0xffe8 /* ABORT asserted */ +#define VECTOR_BRK_N 0xffe6 /* Break Instruction */ +#define VECTOR_COP_N 0xffe4 /* Coprocessor instruction */ + + +/* ======================================================================== */ +/* ================================= CLOCK ================================ */ +/* ======================================================================== */ + +#define CLK_OP 1 +#define CLK_R8 m_rw8_cycles +#define CLK_R16 m_rw16_cycles +#define CLK_R24 m_rw24_cycles +#define CLK_W8 m_rw8_cycles +#define CLK_W16 m_rw16_cycles +#define CLK_W24 m_rw24_cycles +#define CLK_RMW8 m_rw8_cycles+m_rw8_cycles + 1 +#define CLK_RMW16 m_rw16_cycles+m_rw16_cycles + 1 + +#define CLK_IMPLIED 1 +#define CLK_IMPLIED 1 +#define CLK_RELATIVE_8 1 +#define CLK_RELATIVE_16 2 +#define CLK_IMM 0 +#define CLK_AI 4 +#define CLK_AXI 4 +#define CLK_A 2 +#define CLK_AL 3 +#define CLK_ALX 3 +#define CLK_AX 2 +#define CLK_AY 2 +#define CLK_D 1 +#define CLK_DI 3 +#define CLK_DIY 3 +#define CLK_DLI 4 +#define CLK_DLIY 4 +#define CLK_DX 2 +#define CLK_DXI 4 +#define CLK_DY 2 +#define CLK_S 2 +#define CLK_SIY 5 + +/* AX and AY addressing modes take 1 extra cycle when writing */ +#define CLK_W_IMM 0 +#define CLK_W_AI 4 +#define CLK_W_AXI 4 +#define CLK_W_A 2 +#define CLK_W_AL 3 +#define CLK_W_ALX 3 +#define CLK_W_AX 3 +#define CLK_W_AY 3 +#define CLK_W_D 1 +#define CLK_W_DI 3 +#define CLK_W_DIY 3 +#define CLK_W_DLI 4 +#define CLK_W_DLIY 4 +#define CLK_W_DX 2 +#define CLK_W_DXI 4 +#define CLK_W_DY 2 +#define CLK_W_S 2 +#define CLK_W_SIY 5 + +#define CLK(A) CLOCKS -= (m_cpu_type == CPU_TYPE_G65816 ? A : A*6) +#define CLK_BUS(A) CLOCKS -= A +#define USE_ALL_CLKS() CLOCKS = 0 + + +/* ======================================================================== */ +/* ============================ STATUS REGISTER =========================== */ +/* ======================================================================== */ + +/* Flag positions in Processor Status Register */ +/* common */ +#define FLAGPOS_N BIT_7 /* Negative */ +#define FLAGPOS_V BIT_6 /* Overflow */ +#define FLAGPOS_D BIT_3 /* Decimal Mode */ +#define FLAGPOS_I BIT_2 /* Interrupt Mask */ +#define FLAGPOS_Z BIT_1 /* Zero */ +#define FLAGPOS_C BIT_0 /* Carry */ +/* emulation */ +#define FLAGPOS_R BIT_5 /* Reserved */ +#define FLAGPOS_B BIT_4 /* BRK Instruction */ +/* native */ +#define FLAGPOS_M BIT_5 /* Mem/Reg Select */ +#define FLAGPOS_X BIT_4 /* Index Select */ + +#define EFLAG_SET 1 +#define EFLAG_CLEAR 0 +#define MFLAG_SET FLAGPOS_M +#define MFLAG_CLEAR 0 +#define XFLAG_SET FLAGPOS_X +#define XFLAG_CLEAR 0 +#define NFLAG_SET 0x80 +#define NFLAG_CLEAR 0 +#define VFLAG_SET 0x80 +#define VFLAG_CLEAR 0 +#define DFLAG_SET FLAGPOS_D +#define DFLAG_CLEAR 0 +#define IFLAG_SET FLAGPOS_I +#define IFLAG_CLEAR 0 +#define BFLAG_SET FLAGPOS_B +#define BFLAG_CLEAR 0 +#define ZFLAG_SET 0 +#define ZFLAG_CLEAR 1 +#define CFLAG_SET 0x100 +#define CFLAG_CLEAR 0 + +/* Codition code tests */ +#define COND_CC() (!(FLAG_C&0x100)) /* Carry Clear */ +#define COND_CS() (FLAG_C&0x100) /* Carry Set */ +#define COND_EQ() (!FLAG_Z) /* Equal */ +#define COND_NE() FLAG_Z /* Not Equal */ +#define COND_MI() (FLAG_N&0x80) /* Minus */ +#define COND_PL() (!(FLAG_N&0x80)) /* Plus */ +#define COND_VC() (!(FLAG_V&0x80)) /* Overflow Clear */ +#define COND_VS() (FLAG_V&0x80) /* Overflow Set */ + +/* Set Overflow flag in math operations */ +#define VFLAG_ADD_8(S, D, R) ((S^R) & (D^R)) +#define VFLAG_ADD_16(S, D, R) (((S^R) & (D^R))>>8) +#define VFLAG_SUB_8(S, D, R) ((S^D) & (R^D)) +#define VFLAG_SUB_16(S, D, R) (((S^D) & (R^D))>>8) + +#define CFLAG_8(A) (A) +#define CFLAG_16(A) ((A)>>8) +#define NFLAG_8(A) (A) +#define NFLAG_16(A) ((A)>>8) + +#define CFLAG_AS_1() ((FLAG_C>>8)&1) + + + +/* ======================================================================== */ +/* ================================== CPU ================================= */ +/* ======================================================================== */ +#endif /* __G65816CM_H__ */ diff --git a/src/devices/cpu/g65816/g65816ds.c b/src/devices/cpu/g65816/g65816ds.c new file mode 100644 index 00000000000..17af208a822 --- /dev/null +++ b/src/devices/cpu/g65816/g65816ds.c @@ -0,0 +1,349 @@ +// license:BSD-3-Clause +// copyright-holders:Karl Stenerud +/* ======================================================================== */ +/* =============================== COPYRIGHT ============================== */ +/* ======================================================================== */ +/* + +G65C816 CPU Emulator V0.90 + +Copyright Karl Stenerud +All rights reserved. + +*/ + + +#include "emu.h" +#include "g65816ds.h" + +#ifdef SEC +#undef SEC +#endif + +#define ADDRESS_65816(A) ((A)&0xffffff) + + +struct g65816_opcode_struct +{ + unsigned char name; + unsigned char flag; + unsigned char ea; +}; + +enum +{ + IMP , ACC , RELB, RELW, IMM , A , AI , AL , ALX , AX , AXI , + AY , D , DI , DIY , DLI , DLIY, DX , DXI , DY , S , SIY , + SIG /*, MVN , MVP , PEA , PEI , PER */ +}; + +enum +{ + I, /* ignore */ + M, /* check m bit */ + X /* check x bit */ +}; + +enum +{ + ADC , AND , ASL , BCC , BCS , BEQ , BIT , BMI , BNE , BPL , BRA , + BRK , BRL , BVC , BVS , CLC , CLD , CLI , CLV , CMP , COP , CPX , + CPY , DEA , DEC , DEX , DEY , EOR , INA , INC , INX , INY , JML , + JMP , JSL , JSR , LDA , LDX , LDY , LSR , MVN , MVP , NOP , ORA , + PEA , PEI , PER , PHA , PHB , PHD , PHK , PHP , PHX , PHY , PLA , + PLB , PLD , PLP , PLX , PLY , REP , ROL , ROR , RTI , RTL , RTS , + SBC , SEC , SED , SEI , SEP , STA , STP , STX , STY , STZ , TAX , + TAY , TCS , TCD , TDC , TRB , TSB , TSC , TSX , TXA , TXS , TXY , + TYA , TYX , WAI , WDM , XBA , XCE +}; + +static const char *const g_opnames[] = +{ + "ADC", "AND", "ASL", "BCC", "BCS", "BEQ", "BIT", "BMI", "BNE", "BPL", "BRA", + "BRK", "BRL", "BVC", "BVS", "CLC", "CLD", "CLI", "CLV", "CMP", "COP", "CPX", + "CPY", "DEA", "DEC", "DEX", "DEY", "EOR", "INA", "INC", "INX", "INY", "JML", + "JMP", "JSL", "JSR", "LDA", "LDX", "LDY", "LSR", "MVN", "MVP", "NOP", "ORA", + "PEA", "PEI", "PER", "PHA", "PHB", "PHD", "PHK", "PHP", "PHX", "PHY", "PLA", + "PLB", "PLD", "PLP", "PLX", "PLY", "REP", "ROL", "ROR", "RTI", "RTL", "RTS", + "SBC", "SEC", "SED", "SEI", "SEP", "STA", "STP", "STX", "STY", "STZ", "TAX", + "TAY", "TCS", "TCD", "TDC", "TRB", "TSB", "TSC", "TSX", "TXA", "TXS", "TXY", + "TYA", "TYX", "WAI", "WDM", "XBA", "XCE" +}; + +static const g65816_opcode_struct g_opcodes[256] = +{ + {BRK, I, SIG }, {ORA, M, DXI }, {COP, I, SIG }, {ORA, M, S }, + {TSB, M, D }, {ORA, M, D }, {ASL, M, D }, {ORA, M, DLI }, + {PHP, I, IMP }, {ORA, M, IMM }, {ASL, M, ACC }, {PHD, I, IMP }, + {TSB, M, A }, {ORA, M, A }, {ASL, M, A }, {ORA, M, AL }, + {BPL, I, RELB}, {ORA, M, DIY }, {ORA, M, DI }, {ORA, M, SIY }, + {TRB, M, D }, {ORA, M, DX }, {ASL, M, DX }, {ORA, M, DLIY}, + {CLC, I, IMP }, {ORA, M, AY }, {INA, I, IMP }, {TCS, I, IMP }, + {TRB, M, A }, {ORA, M, AX }, {ASL, M, AX }, {ORA, M, ALX }, + {JSR, I, A }, {AND, M, DXI }, {JSL, I, AL }, {AND, M, S }, + {BIT, M, D }, {AND, M, D }, {ROL, M, D }, {AND, M, DLI }, + {PLP, I, IMP }, {AND, M, IMM }, {ROL, M, ACC }, {PLD, I, IMP }, + {BIT, M, A }, {AND, M, A }, {ROL, M, A }, {AND, M, AL }, + {BMI, I, RELB}, {AND, M, DIY }, {AND, M, DI }, {AND, M, SIY }, + {BIT, M, DX }, {AND, M, DX }, {ROL, M, DX }, {AND, M, DLIY}, + {SEC, I, IMP }, {AND, M, AY }, {DEA, I, IMP }, {TSC, I, IMP }, + {BIT, M, AX }, {AND, M, AX }, {ROL, M, AX }, {AND, M, ALX }, + {RTI, I, IMP }, {EOR, M, DXI }, {WDM, I, IMP }, {EOR, M, S }, + {MVP, I, MVP }, {EOR, M, D }, {LSR, M, D }, {EOR, M, DLI }, + {PHA, I, IMP }, {EOR, M, IMM }, {LSR, M, ACC }, {PHK, I, IMP }, + {JMP, I, A }, {EOR, M, A }, {LSR, M, A }, {EOR, M, AL }, + {BVC, I, RELB}, {EOR, M, DIY }, {EOR, M, DI }, {EOR, M, SIY }, + {MVN, I, MVN }, {EOR, M, DX }, {LSR, M, DX }, {EOR, M, DLIY}, + {CLI, I, IMP }, {EOR, M, AY }, {PHY, I, IMP }, {TCD, I, IMP }, + {JMP, I, AL }, {EOR, M, AX }, {LSR, M, AX }, {EOR, M, ALX }, + {RTS, I, IMP }, {ADC, M, DXI }, {PER, I, PER }, {ADC, M, S }, + {STZ, M, D }, {ADC, M, D }, {ROR, M, D }, {ADC, M, DLI }, + {PLA, I, IMP }, {ADC, M, IMM }, {ROR, M, ACC }, {RTL, I, IMP }, + {JMP, I, AI }, {ADC, M, A }, {ROR, M, A }, {ADC, M, AL }, + {BVS, I, RELB}, {ADC, M, DIY }, {ADC, M, DI }, {ADC, M, SIY }, + {STZ, M, DX }, {ADC, M, DX }, {ROR, M, DX }, {ADC, M, DLIY}, + {SEI, I, IMP }, {ADC, M, AY }, {PLY, I, IMP }, {TDC, I, IMP }, + {JMP, I, AXI }, {ADC, M, AX }, {ROR, M, AX }, {ADC, M, ALX }, + {BRA, I, RELB}, {STA, M, DXI }, {BRL, I, RELW}, {STA, M, S }, + {STY, X, D }, {STA, M, D }, {STX, X, D }, {STA, M, DLI }, + {DEY, I, IMP }, {BIT, M, IMM }, {TXA, I, IMP }, {PHB, I, IMP }, + {STY, X, A }, {STA, M, A }, {STX, X, A }, {STA, M, AL }, + {BCC, I, RELB}, {STA, M, DIY }, {STA, M, DI }, {STA, M, SIY }, + {STY, X, DX }, {STA, M, DX }, {STX, X, DY }, {STA, M, DLIY}, + {TYA, I, IMP }, {STA, M, AY }, {TXS, I, IMP }, {TXY, I, IMP }, + {STZ, M, A }, {STA, M, AX }, {STZ, M, AX }, {STA, M, ALX }, + {LDY, X, IMM }, {LDA, M, DXI }, {LDX, X, IMM }, {LDA, M, S }, + {LDY, X, D }, {LDA, M, D }, {LDX, X, D }, {LDA, M, DLI }, + {TAY, I, IMP }, {LDA, M, IMM }, {TAX, I, IMP }, {PLB, I, IMP }, + {LDY, X, A }, {LDA, M, A }, {LDX, X, A }, {LDA, M, AL }, + {BCS, I, RELB}, {LDA, M, DIY }, {LDA, M, DI }, {LDA, M, SIY }, + {LDY, X, DX }, {LDA, M, DX }, {LDX, X, DY }, {LDA, M, DLIY}, + {CLV, I, IMP }, {LDA, M, AY }, {TSX, I, IMP }, {TYX, I, IMP }, + {LDY, X, AX }, {LDA, M, AX }, {LDX, X, AY }, {LDA, M, ALX }, + {CPY, X, IMM }, {CMP, M, DXI }, {REP, I, IMM }, {CMP, M, S }, + {CPY, X, D }, {CMP, M, D }, {DEC, M, D }, {CMP, M, DLI }, + {INY, I, IMP }, {CMP, M, IMM }, {DEX, I, IMP }, {WAI, I, IMP }, + {CPY, X, A }, {CMP, M, A }, {DEC, M, A }, {CMP, M, AL }, + {BNE, I, RELB}, {CMP, M, DIY }, {CMP, M, DI }, {CMP, M, SIY }, + {PEI, I, PEI }, {CMP, M, DX }, {DEC, M, DX }, {CMP, M, DLIY}, + {CLD, I, IMP }, {CMP, M, AY }, {PHX, I, IMP }, {STP, I, IMP }, + {JML, I, AI }, {CMP, M, AX }, {DEC, M, AX }, {CMP, M, ALX }, + {CPX, X, IMM }, {SBC, M, DXI }, {SEP, I, IMM }, {SBC, M, S }, + {CPX, X, D }, {SBC, M, D }, {INC, M, D }, {SBC, M, DLI }, + {INX, M, IMP }, {SBC, M, IMM }, {NOP, I, IMP }, {XBA, I, IMP }, + {CPX, X, A }, {SBC, M, A }, {INC, M, A }, {SBC, M, AL }, + {BEQ, I, RELB}, {SBC, M, DIY }, {SBC, M, DI }, {SBC, M, SIY }, + {PEA, I, PEA }, {SBC, M, DX }, {INC, M, DX }, {SBC, M, DLIY}, + {SED, I, IMP }, {SBC, M, AY }, {PLX, I, IMP }, {XCE, I, IMP }, + {JSR, I, AXI }, {SBC, M, AX }, {INC, M, AX }, {SBC, M, ALX } +}; + +static const UINT8 *base_oprom; +static UINT32 base_pc; + +INLINE unsigned int read_8(unsigned int address) +{ + address = ADDRESS_65816(address); + return base_oprom[address - base_pc]; +} + +INLINE unsigned int read_16(unsigned int address) +{ + unsigned int val = read_8(address); + return val | (read_8(address+1)<<8); +} + +INLINE unsigned int read_24(unsigned int address) +{ + unsigned int val = read_8(address); + val |= (read_8(address+1)<<8); + return val | (read_8(address+2)<<16); +} + +INLINE char* int_8_str(unsigned int val) +{ + static char str[20]; + + val &= 0xff; + + if(val & 0x80) + sprintf(str, "-$%x", (0-val) & 0x7f); + else + sprintf(str, "$%x", val & 0x7f); + + return str; +} + +INLINE char* int_16_str(unsigned int val) +{ + static char str[20]; + + val &= 0xffff; + + if(val & 0x8000) + sprintf(str, "-$%x", (0-val) & 0x7fff); + else + sprintf(str, "$%x", val & 0x7fff); + + return str; +} + + +unsigned g65816_disassemble(char* buff, unsigned int pc, unsigned int pb, const UINT8 *oprom, int m_flag, int x_flag) +{ + unsigned int instruction; + const g65816_opcode_struct* opcode; + char* ptr; + int var; + int length = 1; + unsigned int address; + unsigned dasm_flags; + + pb <<= 16; + address = pc | pb; + + base_oprom = oprom; + base_pc = address; + + instruction = read_8(address); + opcode = g_opcodes + instruction; + + strcpy(buff, g_opnames[opcode->name]); + ptr = buff + strlen(buff); + + switch(opcode->name) + { + case JSR: + case JSL: + dasm_flags = DASMFLAG_STEP_OVER; + break; + + case RTI: + case RTL: + case RTS: + dasm_flags = DASMFLAG_STEP_OUT; + break; + + default: + dasm_flags = 0; + break; + } + + switch(opcode->ea) + { + case IMP : + break; + case ACC : + sprintf(ptr, "A"); + break; + case RELB: + var = (INT8) read_8(address+1); + length++; + sprintf(ptr, " %06x (%s)", pb | ((pc + length + var)&0xffff), int_8_str(var)); + break; + case RELW: + case PER : + var = read_16(address+1); + length += 2; + sprintf(ptr, " %06x (%s)", pb | ((pc + length + var)&0xffff), int_16_str(var)); + break; + case IMM : + if((opcode->flag == M && !m_flag) || (opcode->flag == X && !x_flag)) + { + sprintf(ptr, " #$%04x", read_16(address+1)); + length += 2; + } + else + { + sprintf(ptr, " #$%02x", read_8(address+1)); + length++; + } + break; + case A : + case PEA : + sprintf(ptr, " $%04x", read_16(address+1)); + length += 2; + break; + case AI : + sprintf(ptr, " ($%04x)", read_16(address+1)); + length += 2; + break; + case AL : + sprintf(ptr, " $%06x", read_24(address+1)); + length += 3; + break; + case ALX : + sprintf(ptr, " $%06x,X", read_24(address+1)); + length += 3; + break; + case AX : + sprintf(ptr, " $%04x,X", read_16(address+1)); + length += 2; + break; + case AXI : + sprintf(ptr, " ($%04x,X)", read_16(address+1)); + length += 2; + break; + case AY : + sprintf(ptr, " $%04x,Y", read_16(address+1)); + length += 2; + break; + case D : + sprintf(ptr, " $%02x", read_8(address+1)); + length++; + break; + case DI : + case PEI : + sprintf(ptr, " ($%02x)", read_8(address+1)); + length++; + break; + case DIY : + sprintf(ptr, " ($%02x),Y", read_8(address+1)); + length++; + break; + case DLI : + sprintf(ptr, " [$%02x]", read_8(address+1)); + length++; + break; + case DLIY: + sprintf(ptr, " [$%02x],Y", read_8(address+1)); + length++; + break; + case DX : + sprintf(ptr, " $%02x,X", read_8(address+1)); + length++; + break; + case DXI : + sprintf(ptr, " ($%02x,X)", read_8(address+1)); + length++; + break; + case DY : + sprintf(ptr, " $%02x,Y", read_8(address+1)); + length++; + break; + case S : + sprintf(ptr, " %s,S", int_8_str(read_8(address+1))); + length++; + break; + case SIY : + sprintf(ptr, " (%s,S),Y", int_8_str(read_8(address+1))); + length++; + break; + case SIG : + sprintf(ptr, " #$%02x", read_8(address+1)); + length++; + break; + case MVN : + case MVP : + sprintf(ptr, " $%02x, $%02x", read_8(address+2), read_8(address+1)); + length += 2; + break; + } + + return length | DASMFLAG_SUPPORTED | dasm_flags; +} + +CPU_DISASSEMBLE( g65816_generic ) +{ + return g65816_disassemble(buffer, (pc & 0x00ffff), (pc & 0xff0000) >> 16, oprom, 0, 0); +} diff --git a/src/devices/cpu/g65816/g65816ds.h b/src/devices/cpu/g65816/g65816ds.h new file mode 100644 index 00000000000..58b47752ca5 --- /dev/null +++ b/src/devices/cpu/g65816/g65816ds.h @@ -0,0 +1,22 @@ +// license:BSD-3-Clause +// copyright-holders:Karl Stenerud +#pragma once + +#ifndef __G65816DS_H__ +#define __G65816DS_H__ +/* ======================================================================== */ +/* =============================== COPYRIGHT ============================== */ +/* ======================================================================== */ +/* + +G65C816 CPU Emulator V0.92 + +Copyright Karl Stenerud +All rights reserved. + +*/ + +unsigned g65816_disassemble(char* buff, unsigned int pc, unsigned int pb, const UINT8 *oprom, int m_flag, int x_flag); + + +#endif /* __G65816DS_H__ */ diff --git a/src/devices/cpu/g65816/g65816o0.c b/src/devices/cpu/g65816/g65816o0.c new file mode 100644 index 00000000000..5829325bd37 --- /dev/null +++ b/src/devices/cpu/g65816/g65816o0.c @@ -0,0 +1,8 @@ +// license:BSD-3-Clause +// copyright-holders:Karl Stenerud +#include "emu.h" +#include "debugger.h" +#include "g65816.h" +#include "g65816cm.h" +#define EXECUTION_MODE EXECUTION_MODE_M0X0 +#include "g65816op.h" diff --git a/src/devices/cpu/g65816/g65816o1.c b/src/devices/cpu/g65816/g65816o1.c new file mode 100644 index 00000000000..4b277c9abf2 --- /dev/null +++ b/src/devices/cpu/g65816/g65816o1.c @@ -0,0 +1,8 @@ +// license:BSD-3-Clause +// copyright-holders:Karl Stenerud +#include "emu.h" +#include "debugger.h" +#include "g65816.h" +#include "g65816cm.h" +#define EXECUTION_MODE EXECUTION_MODE_M0X1 +#include "g65816op.h" diff --git a/src/devices/cpu/g65816/g65816o2.c b/src/devices/cpu/g65816/g65816o2.c new file mode 100644 index 00000000000..63a8157e961 --- /dev/null +++ b/src/devices/cpu/g65816/g65816o2.c @@ -0,0 +1,8 @@ +// license:BSD-3-Clause +// copyright-holders:Karl Stenerud +#include "emu.h" +#include "debugger.h" +#include "g65816.h" +#include "g65816cm.h" +#define EXECUTION_MODE EXECUTION_MODE_M1X0 +#include "g65816op.h" diff --git a/src/devices/cpu/g65816/g65816o3.c b/src/devices/cpu/g65816/g65816o3.c new file mode 100644 index 00000000000..24cdebf05b6 --- /dev/null +++ b/src/devices/cpu/g65816/g65816o3.c @@ -0,0 +1,8 @@ +// license:BSD-3-Clause +// copyright-holders:Karl Stenerud +#include "emu.h" +#include "debugger.h" +#include "g65816.h" +#include "g65816cm.h" +#define EXECUTION_MODE EXECUTION_MODE_M1X1 +#include "g65816op.h" diff --git a/src/devices/cpu/g65816/g65816o4.c b/src/devices/cpu/g65816/g65816o4.c new file mode 100644 index 00000000000..60262c859fb --- /dev/null +++ b/src/devices/cpu/g65816/g65816o4.c @@ -0,0 +1,8 @@ +// license:BSD-3-Clause +// copyright-holders:Karl Stenerud +#include "emu.h" +#include "debugger.h" +#include "g65816.h" +#include "g65816cm.h" +#define EXECUTION_MODE EXECUTION_MODE_E +#include "g65816op.h" diff --git a/src/devices/cpu/g65816/g65816op.h b/src/devices/cpu/g65816/g65816op.h new file mode 100644 index 00000000000..81f887b3e12 --- /dev/null +++ b/src/devices/cpu/g65816/g65816op.h @@ -0,0 +1,1961 @@ +// license:BSD-3-Clause +// copyright-holders:Karl Stenerud + +/* ======================================================================== */ +/* ============================= CONFIGURATION ============================ */ +/* ======================================================================== */ + +#undef FLAG_SET_E +#undef FLAG_SET_M +#undef FLAG_SET_X +#if EXECUTION_MODE == EXECUTION_MODE_E +#define FLAG_SET_E 1 +#define FLAG_SET_M 1 +#define FLAG_SET_X 1 +#elif EXECUTION_MODE == EXECUTION_MODE_M0X0 +#define FLAG_SET_E 0 +#define FLAG_SET_M 0 +#define FLAG_SET_X 0 +#elif EXECUTION_MODE == EXECUTION_MODE_M0X1 +#define FLAG_SET_E 0 +#define FLAG_SET_M 0 +#define FLAG_SET_X 1 +#elif EXECUTION_MODE == EXECUTION_MODE_M1X0 +#define FLAG_SET_E 0 +#define FLAG_SET_M 1 +#define FLAG_SET_X 0 +#elif EXECUTION_MODE == EXECUTION_MODE_M1X1 +#define FLAG_SET_E 0 +#define FLAG_SET_M 1 +#define FLAG_SET_X 1 +#endif + +#undef VECTOR_IRQ +#undef VECTOR_NMI +#undef VECTOR_ABORT +#undef VECTOR_BRK +#undef VECTOR_COP + +#if FLAG_SET_E +#define VECTOR_IRQ VECTOR_IRQ_E +#define VECTOR_NMI VECTOR_NMI_E +#define VECTOR_ABORT VECTOR_ABORT_E +#define VECTOR_BRK VECTOR_BRK_E +#define VECTOR_COP VECTOR_COP_E +#else /* FLAG_SET_E */ +#define VECTOR_IRQ VECTOR_IRQ_N +#define VECTOR_NMI VECTOR_NMI_N +#define VECTOR_ABORT VECTOR_ABORT_N +#define VECTOR_BRK VECTOR_BRK_N +#define VECTOR_COP VECTOR_COP_N +#endif + + + +/* ======================================================================== */ +/* ========================== EFFECTIVE ADDRESSES ========================= */ +/* ======================================================================== */ + +/* Effective-address based memory access macros */ +#define read_8_NORM(A) g65816i_read_8_normal(A) +#define read_8_IMM(A) g65816i_read_8_immediate(A) +#define read_8_D(A) g65816i_read_8_direct(A) +#define read_8_A(A) g65816i_read_8_normal(A) +#define read_8_AL(A) g65816i_read_8_normal(A) +#define read_8_DX(A) g65816i_read_8_direct(A) +#define read_8_DY(A) g65816i_read_8_direct(A) +#define read_8_AX(A) g65816i_read_8_normal(A) +#define read_8_ALX(A) g65816i_read_8_normal(A) +#define read_8_AY(A) g65816i_read_8_normal(A) +#define read_8_DI(A) g65816i_read_8_normal(A) +#define read_8_DLI(A) g65816i_read_8_normal(A) +#define read_8_AI(A) g65816i_read_8_normal(A) +#define read_8_ALI(A) g65816i_read_8_normal(A) +#define read_8_DXI(A) g65816i_read_8_normal(A) +#define read_8_DIY(A) g65816i_read_8_normal(A) +#define read_8_DLIY(A) g65816i_read_8_normal(A) +#define read_8_AXI(A) g65816i_read_8_normal(A) +#define read_8_S(A) g65816i_read_8_normal(A) +#define read_8_SIY(A) g65816i_read_8_normal(A) + +#define read_16_NORM(A) g65816i_read_16_normal(A) +#define read_16_IMM(A) g65816i_read_16_immediate(A) +#define read_16_D(A) g65816i_read_16_direct(A) +#define read_16_A(A) g65816i_read_16_normal(A) +#define read_16_AL(A) g65816i_read_16_normal(A) +#define read_16_DX(A) g65816i_read_16_direct(A) +#define read_16_DY(A) g65816i_read_16_direct(A) +#define read_16_AX(A) g65816i_read_16_normal(A) +#define read_16_ALX(A) g65816i_read_16_normal(A) +#define read_16_AY(A) g65816i_read_16_normal(A) +#define read_16_DI(A) g65816i_read_16_normal(A) +#define read_16_DLI(A) g65816i_read_16_normal(A) +#define read_16_AI(A) g65816i_read_16_normal(A) +#define read_16_ALI(A) g65816i_read_16_normal(A) +#define read_16_DXI(A) g65816i_read_16_normal(A) +#define read_16_DIY(A) g65816i_read_16_normal(A) +#define read_16_DLIY(A) g65816i_read_16_normal(A) +#define read_16_AXI(A) g65816i_read_16_normal(A) +#define read_16_S(A) g65816i_read_16_normal(A) +#define read_16_SIY(A) g65816i_read_16_normal(A) + +#define read_24_NORM(A) g65816i_read_24_normal(A) +#define read_24_IMM(A) g65816i_read_24_immediate(A) +#define read_24_D(A) g65816i_read_24_direct(A) +#define read_24_A(A) g65816i_read_24_normal(A) +#define read_24_AL(A) g65816i_read_24_normal(A) +#define read_24_DX(A) g65816i_read_24_direct(A) +#define read_24_DY(A) g65816i_read_24_direct(A) +#define read_24_AX(A) g65816i_read_24_normal(A) +#define read_24_ALX(A) g65816i_read_24_normal(A) +#define read_24_AY(A) g65816i_read_24_normal(A) +#define read_24_DI(A) g65816i_read_24_normal(A) +#define read_24_DLI(A) g65816i_read_24_normal(A) +#define read_24_AI(A) g65816i_read_24_normal(A) +#define read_24_ALI(A) g65816i_read_24_normal(A) +#define read_24_DXI(A) g65816i_read_24_normal(A) +#define read_24_DIY(A) g65816i_read_24_normal(A) +#define read_24_DLIY(A) g65816i_read_24_normal(A) +#define read_24_AXI(A) g65816i_read_24_normal(A) +#define read_24_S(A) g65816i_read_24_normal(A) +#define read_24_SIY(A) g65816i_read_24_normal(A) + +#define write_8_NORM(A, V) g65816i_write_8_normal(A, V) +#define write_8_D(A, V) g65816i_write_8_direct(A, V) +#define write_8_A(A, V) g65816i_write_8_normal(A, V) +#define write_8_AL(A, V) g65816i_write_8_normal(A, V) +#define write_8_DX(A, V) g65816i_write_8_direct(A, V) +#define write_8_DY(A, V) g65816i_write_8_direct(A, V) +#define write_8_AX(A, V) g65816i_write_8_normal(A, V) +#define write_8_ALX(A, V) g65816i_write_8_normal(A, V) +#define write_8_AY(A, V) g65816i_write_8_normal(A, V) +#define write_8_DI(A, V) g65816i_write_8_normal(A, V) +#define write_8_DLI(A, V) g65816i_write_8_normal(A, V) +#define write_8_AI(A, V) g65816i_write_8_normal(A, V) +#define write_8_ALI(A, V) g65816i_write_8_normal(A, V) +#define write_8_DXI(A, V) g65816i_write_8_normal(A, V) +#define write_8_DIY(A, V) g65816i_write_8_normal(A, V) +#define write_8_DLIY(A, V) g65816i_write_8_normal(A, V) +#define write_8_AXI(A, V) g65816i_write_8_normal(A, V) +#define write_8_S(A, V) g65816i_write_8_normal(A, V) +#define write_8_SIY(A, V) g65816i_write_8_normal(A, V) + +#define write_16_NORM(A, V) g65816i_write_16_normal(A, V) +#define write_16_D(A, V) g65816i_write_16_direct(A, V) +#define write_16_A(A, V) g65816i_write_16_normal(A, V) +#define write_16_AL(A, V) g65816i_write_16_normal(A, V) +#define write_16_DX(A, V) g65816i_write_16_direct(A, V) +#define write_16_DY(A, V) g65816i_write_16_direct(A, V) +#define write_16_AX(A, V) g65816i_write_16_normal(A, V) +#define write_16_ALX(A, V) g65816i_write_16_normal(A, V) +#define write_16_AY(A, V) g65816i_write_16_normal(A, V) +#define write_16_DI(A, V) g65816i_write_16_normal(A, V) +#define write_16_DLI(A, V) g65816i_write_16_normal(A, V) +#define write_16_AI(A, V) g65816i_write_16_normal(A, V) +#define write_16_ALI(A, V) g65816i_write_16_normal(A, V) +#define write_16_DXI(A, V) g65816i_write_16_normal(A, V) +#define write_16_DIY(A, V) g65816i_write_16_normal(A, V) +#define write_16_DLIY(A, V) g65816i_write_16_normal(A, V) +#define write_16_AXI(A, V) g65816i_write_16_normal(A, V) +#define write_16_S(A, V) g65816i_write_16_normal(A, V) +#define write_16_SIY(A, V) g65816i_write_16_normal(A, V) + + +#define OPER_8_IMM() read_8_IMM(EA_IMM8()) +#define OPER_8_D() read_8_D(EA_D()) +#define OPER_8_A() read_8_A(EA_A()) +#define OPER_8_AL() read_8_AL(EA_AL()) +#define OPER_8_DX() read_8_DX(EA_DX()) +#define OPER_8_DY() read_8_DY(EA_DY()) +#define OPER_8_AX() read_8_AX(EA_AX()) +#define OPER_8_ALX() read_8_ALX(EA_ALX()) +#define OPER_8_AY() read_8_AY(EA_AY()) +#define OPER_8_DI() read_8_DI(EA_DI()) +#define OPER_8_DLI() read_8_DLI(EA_DLI()) +#define OPER_8_AI() read_8_AI(EA_AI()) +#define OPER_8_ALI() read_8_ALI(EA_ALI()) +#define OPER_8_DXI() read_8_DXI(EA_DXI()) +#define OPER_8_DIY() read_8_DIY(EA_DIY()) +#define OPER_8_DLIY() read_8_DLIY(EA_DLIY()) +#define OPER_8_AXI() read_8_AXI(EA_AXI()) +#define OPER_8_S() read_8_S(EA_S()) +#define OPER_8_SIY() read_8_SIY(EA_SIY()) + +#define OPER_16_IMM() read_16_IMM(EA_IMM16()) +#define OPER_16_D() read_16_D(EA_D()) +#define OPER_16_A() read_16_A(EA_A()) +#define OPER_16_AL() read_16_AL(EA_AL()) +#define OPER_16_DX() read_16_DX(EA_DX()) +#define OPER_16_DY() read_16_DY(EA_DY()) +#define OPER_16_AX() read_16_AX(EA_AX()) +#define OPER_16_ALX() read_16_ALX(EA_ALX()) +#define OPER_16_AY() read_16_AY(EA_AY()) +#define OPER_16_DI() read_16_DI(EA_DI()) +#define OPER_16_DLI() read_16_DLI(EA_DLI()) +#define OPER_16_AI() read_16_AI(EA_AI()) +#define OPER_16_ALI() read_16_ALI(EA_ALI()) +#define OPER_16_DXI() read_16_DXI(EA_DXI()) +#define OPER_16_DIY() read_16_DIY(EA_DIY()) +#define OPER_16_DLIY() read_16_DLIY(EA_DLIY()) +#define OPER_16_AXI() read_16_AXI(EA_AXI()) +#define OPER_16_S() read_16_S(EA_S()) +#define OPER_16_SIY() read_16_SIY(EA_SIY()) + +#define OPER_24_IMM() read_24_IMM(EA_IMM24()) +#define OPER_24_D() read_24_D(EA_D()) +#define OPER_24_A() read_24_A(EA_A()) +#define OPER_24_AL() read_24_AL(EA_AL()) +#define OPER_24_DX() read_24_DX(EA_DX()) +#define OPER_24_DY() read_24_DY(EA_DY()) +#define OPER_24_AX() read_24_AX(EA_AX()) +#define OPER_24_ALX() read_24_ALX(EA_ALX()) +#define OPER_24_AY() read_24_AY(EA_AY()) +#define OPER_24_DI() read_24_DI(EA_DI()) +#define OPER_24_DLI() read_24_DLI(EA_DLI()) +#define OPER_24_AI() read_24_AI(EA_AI()) +#define OPER_24_ALI() read_24_ALI(EA_ALI()) +#define OPER_24_DXI() read_24_DXI(EA_DXI()) +#define OPER_24_DIY() read_24_DIY(EA_DIY()) +#define OPER_24_DLIY() read_24_DLIY(EA_DLIY()) +#define OPER_24_AXI() read_24_AXI(EA_AXI()) +#define OPER_24_S() read_24_S(EA_S()) +#define OPER_24_SIY() read_24_SIY(EA_SIY()) + + + +/* ======================================================================== */ +/* =========================== OPERATION MACROS =========================== */ +/* ======================================================================== */ + +/* M6502 Add With Carry */ +#undef OP_ADC +#if FLAG_SET_M +#define OP_ADC(MODE) \ + { \ + unsigned tmp16; \ + CLK(CLK_OP + CLK_R8 + CLK_##MODE); \ + SRC = OPER_8_##MODE(); \ + if(FLAG_D) \ + { \ + INT32 result, r0, r1, carry; \ + r0 = REGISTER_A; \ + r1 = SRC; \ + carry = CFLAG_AS_1(); \ + result = (r0 & 0x0f) + (r1 & 0x0f) + (carry << 0); \ + if (result > 0x09) result += 0x06; \ + carry = result > 0x0f; \ + result = (r0 & 0xf0) + (r1 & 0xf0) + (carry << 4) + (result & 0x0f); \ + FLAG_V = ~(r0 ^ SRC) & (r0 ^ result) & 0x80; \ + if (result > 0x9f) result += 0x60; \ + FLAG_C = (result > 0xff) ? 0x100 : 0; \ + FLAG_N = (result & 0x80); \ + FLAG_Z = REGISTER_A = MAKE_UINT_8(result); \ + } \ + else \ + { \ + FLAG_C = tmp16 = REGISTER_A + SRC + CFLAG_AS_1(); \ + FLAG_V = VFLAG_ADD_8(SRC, REGISTER_A, FLAG_C); \ + FLAG_N = FLAG_Z = REGISTER_A = MAKE_UINT_8(tmp16); \ + } \ + } + +#else +#define OP_ADC(MODE) \ + CLK(CLK_OP + CLK_R16 + CLK_##MODE); \ + SRC = OPER_16_##MODE(); \ + INT32 result, r0, r1, carry; \ + r0 = REGISTER_A; \ + r1 = SRC; \ + carry = CFLAG_AS_1(); \ + if (!FLAG_D) \ + { \ + result = r0 + r1 + carry; \ + } \ + else \ + { \ + result = (r0 & 0x000f) + (r1 & 0x000f) + (carry << 0); \ + if(result > 0x0009) result += 0x0006; \ + carry = result > 0x000f; \ + result = (r0 & 0x00f0) + (r1 & 0x00f0) + (carry << 4) + (result & 0x000f); \ + if(result > 0x009f) result += 0x0060; \ + carry = result > 0x00ff; \ + result = (r0 & 0x0f00) + (r1 & 0x0f00) + (carry << 8) + (result & 0x00ff); \ + if(result > 0x09ff) result += 0x0600; \ + carry = result > 0x0fff; \ + result = (r0 & 0xf000) + (r1 & 0xf000) + (carry << 12) + (result & 0x0fff); \ + } \ + FLAG_V = ~(r0 ^ r1) & (r0 ^ result) & 0x8000; \ + FLAG_V >>= 8; \ + if (FLAG_D && result > 0x9fff) result += 0x6000; \ + FLAG_C = (result > 0xffff) ? 0x100 : 0; \ + FLAG_Z = REGISTER_A = MAKE_UINT_16(result); \ + FLAG_N = NFLAG_16(REGISTER_A); +#endif + +/* M6502 Logical AND with accumulator */ +#undef OP_AND +#if FLAG_SET_M +#define OP_AND(MODE) \ + CLK(CLK_OP + CLK_R8 + CLK_##MODE); \ + FLAG_N = FLAG_Z = REGISTER_A &= OPER_8_##MODE() +#else +#define OP_AND(MODE) \ + CLK(CLK_OP + CLK_R16 + CLK_##MODE); \ + FLAG_Z = REGISTER_A &= OPER_16_##MODE(); \ + FLAG_N = NFLAG_16(REGISTER_A) +#endif + +/* M6502 Arithmetic Shift Left accumulator */ +#undef OP_ASL +#if FLAG_SET_M +#define OP_ASL() \ + CLK(CLK_OP + CLK_IMPLIED); \ + FLAG_C = REGISTER_A << 1; \ + FLAG_N = FLAG_Z = REGISTER_A = MAKE_UINT_8(FLAG_C) +#else +#define OP_ASL() \ + CLK(CLK_OP + CLK_IMPLIED); \ + FLAG_C = REGISTER_A << 1; \ + FLAG_Z = REGISTER_A = MAKE_UINT_16(FLAG_C); \ + FLAG_N = NFLAG_16(FLAG_C); \ + FLAG_C = CFLAG_16(FLAG_C) +#endif + +/* M6502 Arithmetic Shift Left operand */ +#undef OP_ASLM +#if FLAG_SET_M +#define OP_ASLM(MODE) \ + CLK(CLK_OP + CLK_RMW8 + CLK_W_##MODE); \ + DST = EA_##MODE(); \ + FLAG_C = read_8_##MODE(DST) << 1; \ + FLAG_N = FLAG_Z = MAKE_UINT_8(FLAG_C); \ + write_8_##MODE(DST, FLAG_Z) +#else +#define OP_ASLM(MODE) \ + CLK(CLK_OP + CLK_RMW16 + CLK_W_##MODE); \ + DST = EA_##MODE(); \ + FLAG_C = read_16_##MODE(DST) << 1; \ + FLAG_Z = MAKE_UINT_16(FLAG_C); \ + FLAG_N = NFLAG_16(FLAG_C); \ + FLAG_C = CFLAG_16(FLAG_C); \ + write_16_##MODE(DST, FLAG_Z) +#endif + +/* M6502 Branch on Condition Code */ +#undef OP_BCC +#define OP_BCC(COND) \ + DST = OPER_8_IMM(); \ + if(COND) \ + { \ + CLK(CLK_OP + CLK_RELATIVE_8 + 1); \ + g65816i_branch_8(DST); \ + BREAKOUT; \ + } \ + CLK(CLK_OP + CLK_RELATIVE_8); +/* M6502 Set flags according to bits */ +#undef OP_BIT +#if FLAG_SET_M +#define OP_BIT(MODE) \ + CLK(CLK_OP + CLK_R8 + CLK_##MODE); \ + FLAG_N = OPER_8_##MODE(); \ + FLAG_Z = FLAG_N & REGISTER_A; \ + FLAG_V = FLAG_N << 1 +#else +#define OP_BIT(MODE) \ + CLK(CLK_OP + CLK_R16 + CLK_##MODE); \ + FLAG_N = OPER_16_##MODE(); \ + FLAG_Z = FLAG_N & REGISTER_A; \ + FLAG_N = NFLAG_16(FLAG_N); \ + FLAG_V = FLAG_N << 1 +#endif + +/* G65816 Set flags according to bits (immediate addressing mode) */ +#undef OP_BITI +#if FLAG_SET_M +#define OP_BITI() \ + CLK(CLK_OP + CLK_R8 + CLK_IMM); \ + FLAG_Z = REGISTER_A & OPER_8_IMM() +#else +#define OP_BITI() \ + CLK(CLK_OP + CLK_R16 + CLK_IMM); \ + FLAG_Z = REGISTER_A & OPER_16_IMM() +#endif + +/* M6502 Cause a Break interrupt */ +#undef OP_BRK +#define OP_BRK() \ + REGISTER_PC++; \ + g65816i_interrupt_software(VECTOR_BRK) + +/* G65816 Branch Always */ +#undef OP_BRA +#define OP_BRA() \ + CLK(CLK_OP + CLK_IMPLIED + CLK_RELATIVE_8); \ + g65816i_branch_8(OPER_8_IMM()) + +/* G65816 Branch Always Long */ +#undef OP_BRL +#define OP_BRL() \ + CLK(CLK_OP + CLK_IMPLIED + CLK_RELATIVE_16); \ + g65816i_branch_16(OPER_16_IMM()) + +/* M6502 Clear Carry flag */ +#undef OP_CLC +#define OP_CLC() \ + CLK(CLK_OP + CLK_IMPLIED); \ + FLAG_C = CFLAG_CLEAR + +/* M6502 Clear Decimal flag */ +#undef OP_CLD +#define OP_CLD() \ + CLK(CLK_OP + CLK_IMPLIED); \ + FLAG_D = DFLAG_CLEAR + +/* M6502 Clear Interrupt Mask flag */ +#undef OP_CLI +#define OP_CLI() \ + CLK(CLK_OP + CLK_IMPLIED); \ + g65816i_set_flag_i(IFLAG_CLEAR) + +/* M6502 Clear oVerflow flag */ +#undef OP_CLV +#define OP_CLV() \ + CLK(CLK_OP + CLK_IMPLIED); \ + FLAG_V = VFLAG_CLEAR + +/* M6502 Compare operand to accumulator */ +/* Unusual behavior: C flag is inverted */ +#undef OP_CMP +#if FLAG_SET_M +#define OP_CMP(MODE) \ + CLK(CLK_OP + CLK_R8 + CLK_##MODE); \ + FLAG_C = REGISTER_A - OPER_8_##MODE(); \ + FLAG_N = FLAG_Z = MAKE_UINT_8(FLAG_C); \ + FLAG_C ^= CFLAG_SET +#else +#define OP_CMP(MODE) \ + CLK(CLK_OP + CLK_R16 + CLK_##MODE); \ + FLAG_C = REGISTER_A - OPER_16_##MODE(); \ + FLAG_Z = MAKE_UINT_16(FLAG_C); \ + FLAG_N = NFLAG_16(FLAG_C); \ + FLAG_C = ~CFLAG_16(FLAG_C) +#endif + +/* M6502 Compare operand to index register */ +/* Unusual behavior: C flag is inverted */ +#undef OP_CMPX +#if FLAG_SET_X +#define OP_CMPX(REG, MODE) \ + CLK(CLK_OP + CLK_R8 + CLK_##MODE); \ + FLAG_C = REG - OPER_8_##MODE(); \ + FLAG_N = FLAG_Z = MAKE_UINT_8(FLAG_C); \ + FLAG_C ^= CFLAG_SET +#else +#define OP_CMPX(REG, MODE) \ + CLK(CLK_OP + CLK_R16 + CLK_##MODE); \ + FLAG_C = REG - OPER_16_##MODE(); \ + FLAG_Z = MAKE_UINT_16(FLAG_C); \ + FLAG_N = NFLAG_16(FLAG_C); \ + FLAG_C = ~CFLAG_16(FLAG_C) +#endif + +/* G65816 Coprocessor operation */ +#undef OP_COP +#define OP_COP() \ + REGISTER_PC++; \ + g65816i_interrupt_software(VECTOR_COP) + +/* M6502 Decrement accumulator */ +#undef OP_DEC +#if FLAG_SET_M +#define OP_DEC() \ + CLK(CLK_OP + CLK_IMPLIED); \ + FLAG_N = FLAG_Z = REGISTER_A = MAKE_UINT_8(REGISTER_A - 1) +#else +#define OP_DEC() \ + CLK(CLK_OP + CLK_IMPLIED); \ + FLAG_Z = REGISTER_A = MAKE_UINT_16(REGISTER_A - 1); \ + FLAG_N = NFLAG_16(REGISTER_A) +#endif + +/* M6502 Decrement operand */ +#undef OP_DECM +#if FLAG_SET_M +#define OP_DECM(MODE) \ + CLK(CLK_OP + CLK_RMW8 + CLK_W_##MODE); \ + DST = EA_##MODE(); \ + FLAG_N = FLAG_Z = MAKE_UINT_8(read_8_##MODE(DST) - 1); \ + write_8_##MODE(DST, FLAG_Z) +#else +#define OP_DECM(MODE) \ + CLK(CLK_OP + CLK_RMW16 + CLK_W_##MODE); \ + DST = EA_##MODE(); \ + FLAG_Z = MAKE_UINT_16(read_16_##MODE(DST) - 1); \ + FLAG_N = NFLAG_16(FLAG_Z); \ + write_16_##MODE(DST, FLAG_Z) +#endif + +/* M6502 Decrement index register */ +#undef OP_DECX +#if FLAG_SET_X +#define OP_DECX(REG) \ + CLK(CLK_OP + CLK_IMPLIED); \ + FLAG_N = FLAG_Z = REG = MAKE_UINT_8(REG - 1) +#else +#define OP_DECX(REG) \ + CLK(CLK_OP + CLK_IMPLIED); \ + FLAG_Z = REG = MAKE_UINT_16(REG - 1); \ + FLAG_N = NFLAG_16(REG) +#endif + +/* M6502 Exclusive Or operand to accumulator */ +#undef OP_EOR +#if FLAG_SET_M +#define OP_EOR(MODE) \ + CLK(CLK_OP + CLK_R8 + CLK_##MODE); \ + FLAG_N = FLAG_Z = REGISTER_A ^= OPER_8_##MODE() +#else +#define OP_EOR(MODE) \ + CLK(CLK_OP + CLK_R16 + CLK_##MODE); \ + FLAG_Z = REGISTER_A ^= OPER_16_##MODE(); \ + FLAG_N = NFLAG_16(REGISTER_A) +#endif + +/* M6502 Increment accumulator */ +#undef OP_INC +#if FLAG_SET_M +#define OP_INC() \ + CLK(CLK_OP + CLK_IMPLIED); \ + FLAG_N = FLAG_Z = REGISTER_A = MAKE_UINT_8(REGISTER_A + 1) +#else +#define OP_INC() \ + CLK(CLK_OP + CLK_IMPLIED); \ + FLAG_Z = REGISTER_A = MAKE_UINT_16(REGISTER_A + 1); \ + FLAG_N = NFLAG_16(REGISTER_A) +#endif + +/* M6502 Increment operand */ +#undef OP_INCM +#if FLAG_SET_M +#define OP_INCM(MODE) \ + CLK(CLK_OP + CLK_RMW8 + CLK_W_##MODE); \ + DST = EA_##MODE(); \ + FLAG_N = FLAG_Z = MAKE_UINT_8(read_8_##MODE(DST) + 1); \ + write_8_##MODE(DST, FLAG_Z) +#else +#define OP_INCM(MODE) \ + CLK(CLK_OP + CLK_RMW16 + CLK_W_##MODE); \ + DST = EA_##MODE(); \ + FLAG_Z = MAKE_UINT_16(read_16_##MODE(DST) + 1); \ + FLAG_N = NFLAG_16(FLAG_Z); \ + write_16_##MODE(DST, FLAG_Z) +#endif + +/* M6502 Increment index register */ +#undef OP_INCX +#if FLAG_SET_X +#define OP_INCX(REG) \ + CLK(CLK_OP + CLK_IMPLIED); \ + FLAG_N = FLAG_Z = REG = MAKE_UINT_8(REG + 1) +#else +#define OP_INCX(REG) \ + CLK(CLK_OP + CLK_IMPLIED); \ + FLAG_Z = REG = MAKE_UINT_16(REG + 1); \ + FLAG_N = NFLAG_16(REG) +#endif + +/* G65816 Jump Long */ +#undef OP_JMLAI +#define OP_JMLAI() \ + CLK(CLK_OP + CLK_AI + 1); \ + g65816i_jump_24(read_24_A(OPER_16_IMM())) + +/* M6502 Jump */ +#undef OP_JMP +#define OP_JMP(MODE) \ + CLK(CLK_OP + CLK_##MODE); \ + g65816i_jump_16(EA_##MODE()) + +/* M6502 Jump absolute indexed indirect */ +#undef OP_JMPAXI +#define OP_JMPAXI() \ + CLK(CLK_OP + CLK_AXI); \ + g65816i_jump_16(read_16_AXI(REGISTER_PB | (MAKE_UINT_16(OPER_16_IMM() + REGISTER_X)))) + +/* G65816 Jump absolute long */ +#undef OP_JMPAL +#define OP_JMPAL() \ + CLK(CLK_OP + CLK_AL); \ + g65816i_jump_24(EA_AL()) + +/* G65816 Jump to Subroutine Long */ +/* Unusual behavior: stacks PC-1 */ +#undef OP_JSL +#define OP_JSL(MODE) \ + CLK(CLK_OP + CLK_W24 + CLK_##MODE + 1); \ + DST = EA_##MODE(); \ + g65816i_push_8(REGISTER_PB>>16); \ + g65816i_push_16(REGISTER_PC-1); \ + g65816i_jump_24(DST) + +/* M6502 Jump to Subroutine */ +/* Unusual behavior: stacks PC-1 */ +#undef OP_JSR +#define OP_JSR(MODE) \ + CLK(CLK_OP + CLK_W16 + CLK_##MODE); \ + DST = EA_##MODE(); \ + g65816i_push_16(REGISTER_PC-1); \ + g65816i_jump_16(DST) + +/* M6502 Jump to Subroutine */ +/* Unusual behavior: stacks PC-1 */ +#undef OP_JSRAXI +#define OP_JSRAXI() \ + CLK(CLK_OP + CLK_W16 + CLK_AXI); \ + DST = read_16_AXI(REGISTER_PB | (MAKE_UINT_16(OPER_16_IMM() + REGISTER_X))); \ + g65816i_push_16(REGISTER_PC-1); \ + g65816i_jump_16(DST) + +/* M6502 Load accumulator with operand */ +#undef OP_LDA +#if FLAG_SET_M +#define OP_LDA(MODE) \ + CLK(CLK_OP + CLK_R8 + CLK_##MODE); \ + FLAG_N = FLAG_Z = REGISTER_A = OPER_8_##MODE() +#else +#define OP_LDA(MODE) \ + CLK(CLK_OP + CLK_R16 + CLK_##MODE); \ + FLAG_Z = REGISTER_A = OPER_16_##MODE(); \ + FLAG_N = NFLAG_16(REGISTER_A) +#endif + +/* M6502 Load index register with operand */ +#undef OP_LDX +#if FLAG_SET_X +#define OP_LDX(REG, MODE) \ + CLK(CLK_OP + CLK_R8 + CLK_##MODE); \ + FLAG_N = FLAG_Z = REG = OPER_8_##MODE() +#else +#define OP_LDX(REG, MODE) \ + CLK(CLK_OP + CLK_R16 + CLK_##MODE); \ + FLAG_Z = REG = OPER_16_##MODE(); \ + FLAG_N = NFLAG_16(REG) +#endif + +/* M6502 Logical Shift Right accumulator */ +#undef OP_LSR +#if FLAG_SET_M +#define OP_LSR() \ + CLK(CLK_OP + CLK_IMPLIED); \ + FLAG_N = 0; \ + FLAG_C = REGISTER_A << 8; \ + FLAG_Z = REGISTER_A >>= 1 +#else +#define OP_LSR() \ + CLK(CLK_OP + CLK_IMPLIED); \ + FLAG_N = 0; \ + FLAG_C = REGISTER_A << 8; \ + FLAG_Z = REGISTER_A >>= 1 +#endif + +/* M6502 Logical Shift Right operand */ +#undef OP_LSRM +#if FLAG_SET_M +#define OP_LSRM(MODE) \ + CLK(CLK_OP + CLK_RMW8 + CLK_W_##MODE); \ + DST = EA_##MODE(); \ + FLAG_N = 0; \ + FLAG_Z = read_8_##MODE(DST); \ + FLAG_C = FLAG_Z << 8; \ + FLAG_Z >>= 1; \ + write_8_##MODE(DST, FLAG_Z) +#else +#define OP_LSRM(MODE) \ + CLK(CLK_OP + CLK_RMW16 + CLK_W_##MODE); \ + DST = EA_##MODE(); \ + FLAG_N = 0; \ + FLAG_Z = read_16_##MODE(DST); \ + FLAG_C = FLAG_Z << 8; \ + FLAG_Z >>= 1; \ + write_16_##MODE(DST, FLAG_Z) +#endif + +/* G65816 Move Block Negative */ +#undef OP_MVN +#if FLAG_SET_M +#if FLAG_SET_X +#define OP_MVN() \ + DST = OPER_8_IMM()<<16; \ + SRC = OPER_8_IMM()<<16; \ + REGISTER_DB = DST; \ + CLK(7); \ + write_8_NORM(DST | REGISTER_Y, read_8_NORM(SRC | REGISTER_X)); \ + REGISTER_X = MAKE_UINT_8(REGISTER_X+1); \ + REGISTER_Y = MAKE_UINT_8(REGISTER_Y+1); \ + REGISTER_A--; \ + REGISTER_A &= 0xff; \ + if ((REGISTER_A&0xff) != 0xff) \ + {\ + REGISTER_PC -= 3; \ + }\ + else \ + { \ + REGISTER_B -= 0x100;\ + REGISTER_B &= 0xff00; \ + if ((REGISTER_B & 0xff00) != 0xff00)\ + { \ + REGISTER_PC -= 3;\ + } \ + } +#else +#define OP_MVN() \ + DST = OPER_8_IMM()<<16; \ + SRC = OPER_8_IMM()<<16; \ + REGISTER_DB = DST; \ + CLK(7); \ + write_8_NORM(DST | REGISTER_Y, read_8_NORM(SRC | REGISTER_X)); \ + REGISTER_X = MAKE_UINT_16(REGISTER_X+1); \ + REGISTER_Y = MAKE_UINT_16(REGISTER_Y+1); \ + REGISTER_A--; \ + REGISTER_A &= 0xff; \ + if ((REGISTER_A&0xff) != 0xff) \ + {\ + REGISTER_PC -= 3; \ + }\ + else \ + { \ + REGISTER_B -= 0x100;\ + REGISTER_B &= 0xff00; \ + if ((REGISTER_B & 0xff00) != 0xff00)\ + { \ + REGISTER_PC -= 3;\ + } \ + } +#endif +#else +#if FLAG_SET_X +#define OP_MVN() \ + DST = OPER_8_IMM()<<16; \ + SRC = OPER_8_IMM()<<16; \ + REGISTER_DB = DST; \ + REGISTER_A |= REGISTER_B; \ + CLK(7); \ + write_8_NORM(DST | REGISTER_Y, read_8_NORM(SRC | REGISTER_X)); \ + REGISTER_X = MAKE_UINT_8(REGISTER_X+1); \ + REGISTER_Y = MAKE_UINT_8(REGISTER_Y+1); \ + REGISTER_A--; \ + if ((REGISTER_A&0xffff) != 0xffff) \ + {\ + REGISTER_PC -= 3; \ + } +#else +#define OP_MVN() \ + DST = OPER_8_IMM()<<16; \ + SRC = OPER_8_IMM()<<16; \ + REGISTER_DB = DST; \ + REGISTER_A |= REGISTER_B; \ + CLK(7); \ + write_8_NORM(DST | REGISTER_Y, read_8_NORM(SRC | REGISTER_X)); \ + REGISTER_X = MAKE_UINT_16(REGISTER_X+1); \ + REGISTER_Y = MAKE_UINT_16(REGISTER_Y+1); \ + REGISTER_A--; \ + if ((REGISTER_A&0xffff) != 0xffff) \ + {\ + REGISTER_PC -= 3; \ + } +#endif +#endif + +/* G65816 Move Block Positive */ +#undef OP_MVP +#if FLAG_SET_M +#if FLAG_SET_X +#define OP_MVP() \ + DST = OPER_8_IMM()<<16; \ + SRC = OPER_8_IMM()<<16; \ + REGISTER_DB = DST; \ + CLK(7); \ + write_8_NORM(DST | REGISTER_Y, read_8_NORM(SRC | REGISTER_X)); \ + REGISTER_X = MAKE_UINT_8(REGISTER_X-1); \ + REGISTER_Y = MAKE_UINT_8(REGISTER_Y-1); \ + REGISTER_A--; \ + REGISTER_A &= 0xff; \ + if ((REGISTER_A&0xff) != 0xff) \ + {\ + REGISTER_PC -= 3; \ + }\ + else \ + { \ + REGISTER_B -= 0x100;\ + REGISTER_B &= 0xff00; \ + if ((REGISTER_B & 0xff00) != 0xff00)\ + { \ + REGISTER_PC -= 3;\ + } \ + } +#else +#define OP_MVP() \ + DST = OPER_8_IMM()<<16; \ + SRC = OPER_8_IMM()<<16; \ + REGISTER_DB = DST; \ + CLK(7); \ + write_8_NORM(DST | REGISTER_Y, read_8_NORM(SRC | REGISTER_X)); \ + REGISTER_X = MAKE_UINT_16(REGISTER_X-1); \ + REGISTER_Y = MAKE_UINT_16(REGISTER_Y-1); \ + REGISTER_A--; \ + REGISTER_A &= 0xff; \ + if ((REGISTER_A&0xff) != 0xff) \ + {\ + REGISTER_PC -= 3; \ + }\ + else \ + { \ + REGISTER_B -= 0x100;\ + REGISTER_B &= 0xff00; \ + if ((REGISTER_B & 0xff00) != 0xff00)\ + { \ + REGISTER_PC -= 3;\ + } \ + } +#endif +#else +#if FLAG_SET_X +#define OP_MVP() \ + DST = OPER_8_IMM()<<16; \ + SRC = OPER_8_IMM()<<16; \ + REGISTER_DB = DST; \ + REGISTER_A |= REGISTER_B; \ + CLK(7); \ + write_8_NORM(DST | REGISTER_Y, read_8_NORM(SRC | REGISTER_X)); \ + REGISTER_X = MAKE_UINT_8(REGISTER_X-1); \ + REGISTER_Y = MAKE_UINT_8(REGISTER_Y-1); \ + REGISTER_A--; \ + if ((REGISTER_A&0xffff) != 0xffff) \ + {\ + REGISTER_PC -= 3; \ + } +#else +#define OP_MVP() \ + DST = OPER_8_IMM()<<16; \ + SRC = OPER_8_IMM()<<16; \ + REGISTER_DB = DST; \ + REGISTER_A |= REGISTER_B; \ + CLK(7); \ + write_8_NORM(DST | REGISTER_Y, read_8_NORM(SRC | REGISTER_X)); \ + REGISTER_X = MAKE_UINT_16(REGISTER_X-1); \ + REGISTER_Y = MAKE_UINT_16(REGISTER_Y-1); \ + REGISTER_A--; \ + if ((REGISTER_A&0xffff) != 0xffff) \ + {\ + REGISTER_PC -= 3; \ + } +#endif +#endif + +/* M6502 No Operation */ +#undef OP_NOP +#define OP_NOP() \ + CLK(CLK_OP + CLK_IMPLIED) + +/* M6502 Logical OR operand to accumulator */ +#undef OP_ORA +#if FLAG_SET_M +#define OP_ORA(MODE) \ + CLK(CLK_OP + CLK_R8 + CLK_##MODE); \ + FLAG_N = FLAG_Z = REGISTER_A |= OPER_8_ ## MODE() +#else +#define OP_ORA(MODE) \ + CLK(CLK_OP + CLK_R16 + CLK_##MODE); \ + FLAG_Z = REGISTER_A |= OPER_16_##MODE(); \ + FLAG_N = NFLAG_16(REGISTER_A) +#endif + +/* G65816 Push Effective Address */ +#undef OP_PEA +#define OP_PEA() \ + CLK(CLK_OP + CLK_R16 + CLK_W16); \ + g65816i_push_16(OPER_16_IMM()) + +/* G65816 Push Effective Indirect Address */ +#undef OP_PEI +#define OP_PEI() \ + CLK(CLK_OP + CLK_R16 + CLK_W16 + CLK_D); \ + g65816i_push_16(EA_DI()) + +/* G65816 Push Effective PC-Relative Address */ +#undef OP_PER +#define OP_PER() \ + CLK(CLK_OP + CLK_R16 + CLK_W16 + 1); \ + SRC = OPER_16_IMM(); \ + g65816i_push_16(REGISTER_PC + SRC) + +/* M6502 Push accumulator to the stack */ +#undef OP_PHA +#if FLAG_SET_M +#define OP_PHA() \ + CLK(CLK_OP + CLK_W8 + 1); \ + g65816i_push_8(REGISTER_A) +#else +#define OP_PHA() \ + CLK(CLK_OP + CLK_W16 + 1); \ + g65816i_push_16(REGISTER_A) +#endif + +/* M6502 Push index register to the stack */ +#undef OP_PHX +#if FLAG_SET_X +#define OP_PHX(REG) \ + CLK(CLK_OP + CLK_W8 + 1); \ + g65816i_push_8(REG) +#else +#define OP_PHX(REG) \ + CLK(CLK_OP + CLK_W16 + 1); \ + g65816i_push_16(REG) +#endif + +/* G65816 Push data bank register */ +#undef OP_PHB +#define OP_PHB() \ + CLK(CLK_OP + CLK_W8 + 1); \ + g65816i_push_8(REGISTER_DB>>16) + +/* G65816 Push direct register */ +#undef OP_PHD +#define OP_PHD() \ + CLK(CLK_OP + CLK_W16 + 1); \ + g65816i_push_16(REGISTER_D) + +/* G65816 Push program bank register */ +#undef OP_PHK +#define OP_PHK() \ + CLK(CLK_OP + CLK_W8 + 1); \ + g65816i_push_8(REGISTER_PB>>16) + +/* M6502 Push the Processor Status Register to the stack */ +#undef OP_PHP +#define OP_PHP() \ + CLK(CLK_OP + CLK_W8 + 1); \ + g65816i_push_8(g65816i_get_reg_p()) + +/* M6502 Pull accumulator from the stack */ +#undef OP_PLA +#if FLAG_SET_M +#define OP_PLA() \ + CLK(CLK_OP + CLK_R8 + 2); \ + FLAG_N = FLAG_Z = REGISTER_A = g65816i_pull_8() +#else +#define OP_PLA() \ + CLK(CLK_OP + CLK_R16 + 2); \ + FLAG_Z = REGISTER_A = g65816i_pull_16(); \ + FLAG_N = NFLAG_16(FLAG_Z) +#endif + +/* M6502 Pull index register from the stack */ +#undef OP_PLX +#if FLAG_SET_X +#define OP_PLX(REG) \ + CLK(CLK_OP + CLK_R8 + 2); \ + FLAG_N = FLAG_Z = REG = g65816i_pull_8() +#else +#define OP_PLX(REG) \ + CLK(CLK_OP + CLK_R16 + 2); \ + FLAG_Z = REG = g65816i_pull_16(); \ + FLAG_N = NFLAG_16(FLAG_Z) +#endif + +/* G65816 Pull data bank register */ +#undef OP_PLB +#define OP_PLB() \ + CLK(CLK_OP + CLK_R8 + 2); \ + FLAG_N = FLAG_Z = g65816i_pull_8(); \ + REGISTER_DB = FLAG_Z << 16 + +/* G65816 Pull direct register */ +#undef OP_PLD +#define OP_PLD() \ + CLK(CLK_OP + CLK_R16 + 2); \ + FLAG_Z = REGISTER_D = g65816i_pull_16(); \ + FLAG_N = NFLAG_16(FLAG_Z) + +/* M6502 Pull the Processor Status Register from the stack */ +#undef OP_PLP +#define OP_PLP() \ + CLK(CLK_OP + CLK_R8 + 2); \ + g65816i_set_reg_p(g65816i_pull_8()) + +/* G65816 Reset Program status word */ +#undef OP_REP +#define OP_REP() \ + CLK(CLK_OP + CLK_R8 + 1); \ + g65816i_set_reg_p(g65816i_get_reg_p() & ~OPER_8_IMM()) + +/* M6502 Rotate Left the accumulator */ +#undef OP_ROL +#if FLAG_SET_M +#define OP_ROL() \ + CLK(CLK_OP + CLK_IMPLIED); \ + FLAG_C = (REGISTER_A<<1) | CFLAG_AS_1(); \ + FLAG_N = FLAG_Z = REGISTER_A = MAKE_UINT_8(FLAG_C) +#else +#define OP_ROL() \ + CLK(CLK_OP + CLK_IMPLIED); \ + FLAG_C = (REGISTER_A<<1) | CFLAG_AS_1(); \ + FLAG_Z = REGISTER_A = MAKE_UINT_16(FLAG_C); \ + FLAG_N = NFLAG_16(FLAG_C); \ + FLAG_C = CFLAG_16(FLAG_C) +#endif + +/* M6502 Rotate Left an operand */ +#undef OP_ROLM +#if FLAG_SET_M +#define OP_ROLM(MODE) \ + CLK(CLK_OP + CLK_RMW8 + CLK_W_##MODE); \ + DST = EA_##MODE(); \ + FLAG_C = (read_8_##MODE(DST)<<1) | CFLAG_AS_1(); \ + FLAG_N = FLAG_Z = MAKE_UINT_8(FLAG_C); \ + write_8_##MODE(DST, FLAG_Z) +#else +#define OP_ROLM(MODE) \ + CLK(CLK_OP + CLK_RMW16 + CLK_W_##MODE); \ + DST = EA_##MODE(); \ + FLAG_C = (read_16_##MODE(DST)<<1) | CFLAG_AS_1(); \ + FLAG_Z = MAKE_UINT_16(FLAG_C); \ + FLAG_N = NFLAG_16(FLAG_C); \ + FLAG_C = CFLAG_16(FLAG_C); \ + write_16_##MODE(DST, FLAG_Z) +#endif + +/* M6502 Rotate Right the accumulator */ +#undef OP_ROR +#if FLAG_SET_M +#define OP_ROR() \ + CLK(CLK_OP + CLK_IMPLIED); \ + REGISTER_A |= FLAG_C & 0x100; \ + FLAG_C = REGISTER_A << 8; \ + FLAG_N = FLAG_Z = REGISTER_A >>= 1 +#else +#define OP_ROR() \ + CLK(CLK_OP + CLK_IMPLIED); \ + REGISTER_A |= (FLAG_C<<8) & 0x10000; \ + FLAG_C = REGISTER_A << 8; \ + FLAG_Z = REGISTER_A >>= 1; \ + FLAG_N = NFLAG_16(REGISTER_A) +#endif + +/* M6502 Rotate Right an operand */ +#undef OP_RORM +#if FLAG_SET_M +#define OP_RORM(MODE) \ + CLK(CLK_OP + CLK_RMW8 + CLK_W_##MODE); \ + DST = EA_##MODE(); \ + FLAG_Z = read_8_##MODE(DST) | (FLAG_C & 0x100); \ + FLAG_C = FLAG_Z << 8; \ + FLAG_N = FLAG_Z >>= 1; \ + write_8_##MODE(DST, FLAG_Z) +#else +#define OP_RORM(MODE) \ + CLK(CLK_OP + CLK_RMW16 + CLK_W_##MODE); \ + DST = EA_##MODE(); \ + FLAG_Z = read_16_##MODE(DST) | ((FLAG_C<<8) & 0x10000); \ + FLAG_C = FLAG_Z << 8; \ + FLAG_Z >>= 1; \ + FLAG_N = NFLAG_16(FLAG_Z); \ + write_16_##MODE(DST, FLAG_Z) +#endif + +/* M6502 Return from Interrupt */ +#undef OP_RTI +#if FLAG_SET_E +#define OP_RTI() \ + CLK(7); \ + g65816i_set_reg_p(g65816i_pull_8()); \ + g65816i_jump_16(g65816i_pull_16()) +#else +#define OP_RTI() \ + CLK(8); \ + g65816i_set_reg_p(g65816i_pull_8()); \ + g65816i_jump_16(g65816i_pull_16()); \ + REGISTER_PB = g65816i_pull_8() << 16 +#endif + +/* G65816 Return from Subroutine Long */ +/* Unusual behavior: Gets PC and increments */ +#undef OP_RTL +#define OP_RTL() \ + CLK(6); \ + g65816i_jump_24(g65816i_pull_24()) + +/* M6502 Return from Subroutine */ +/* Unusual behavior: Gets PC and increments */ +#undef OP_RTS +#define OP_RTS() \ + CLK(6); \ + g65816i_jump_16(g65816i_pull_16()+1) + +/* M6502 Subtract with Carry */ +/* Unusual behavior: C flag is inverted */ +#undef OP_SBC +#if FLAG_SET_M +#define OP_SBC(MODE) \ + CLK(CLK_OP + CLK_R8 + CLK_##MODE); \ + SRC = OPER_8_##MODE(); \ + if(!FLAG_D) \ + { \ + FLAG_C = ~FLAG_C; \ + FLAG_C = REGISTER_A - SRC - CFLAG_AS_1(); \ + FLAG_V = VFLAG_SUB_8(SRC, REGISTER_A, FLAG_C); \ + FLAG_N = FLAG_Z = REGISTER_A = MAKE_UINT_8(FLAG_C); \ + FLAG_C = ~FLAG_C; \ + BREAKOUT; \ + } \ + else \ + { \ + INT32 result, r0, r1, carry; \ + r0 = REGISTER_A; \ + r1 = SRC; \ + r1 ^= 0xff; \ + carry = CFLAG_AS_1(); \ + result = (r0 & 0x0f) + (r1 & 0x0f) + (carry << 0); \ + if (result <= 0x0f) result -= 0x06; \ + carry = result > 0x0f; \ + result = (r0 & 0xf0) + (r1 & 0xf0) + (carry << 4) + (result & 0x0f); \ + FLAG_V = ~(r0 ^ r1) & (r0 ^ result) & 0x80; \ + if (result <= 0xff) result -= 0x60; \ + FLAG_C = (result > 0xff) ? 0x100 : 0; \ + FLAG_N = (result & 0x80); \ + FLAG_Z = REGISTER_A = MAKE_UINT_8(result); \ + } +#else +#define OP_SBC(MODE) \ + CLK(CLK_OP + CLK_R16 + CLK_##MODE); \ + SRC = OPER_16_##MODE(); \ + INT32 result, r0, r1, carry; \ + r0 = REGISTER_A; \ + r1 = SRC; \ + r1 ^= 0xffff; \ + carry = CFLAG_AS_1(); \ + if (!FLAG_D) \ + { \ + result = r0 + r1 + carry; \ + } \ + else \ + { \ + result = (r0 & 0x000f) + (r1 & 0x000f) + (carry << 0); \ + if(result <= 0x000f) result -= 0x0006; \ + carry = result > 0x000f; \ + result = (r0 & 0x00f0) + (r1 & 0x00f0) + (carry << 4) + (result & 0x000f); \ + if(result <= 0x00ff) result -= 0x0060; \ + carry = result > 0x00ff; \ + result = (r0 & 0x0f00) + (r1 & 0x0f00) + (carry << 8) + (result & 0x00ff); \ + if(result <= 0x0fff) result -= 0x0600; \ + carry = result > 0x0fff; \ + result = (r0 & 0xf000) + (r1 & 0xf000) + (carry << 12) + (result & 0x0fff); \ + } \ + FLAG_V = ~(r0 ^ r1) & (r0 ^ result) & 0x8000; \ + FLAG_V >>= 8; \ + if (FLAG_D && result <= 0xffff) result -= 0x6000; \ + FLAG_C = (result > 0xffff) ? 0x100 : 0; \ + FLAG_Z = REGISTER_A = MAKE_UINT_16(result); \ + FLAG_N = NFLAG_16(REGISTER_A); +#endif + + +/* M6502 Set Carry flag */ +#undef OP_SEC +#define OP_SEC() \ + CLK(CLK_OP + CLK_IMPLIED); \ + FLAG_C = CFLAG_SET + +/* M6502 Set Decimal flag */ +#undef OP_SED +#define OP_SED() \ + CLK(CLK_OP + CLK_IMPLIED); \ + FLAG_D = DFLAG_SET + +/* M6502 Set Interrupt Mask flag */ +#undef OP_SEI +#define OP_SEI() \ + CLK(CLK_OP + CLK_IMPLIED); \ + g65816i_set_flag_i(IFLAG_SET) + +/* G65816 Set Program status word */ +#undef OP_SEP +#define OP_SEP() \ + CLK(CLK_OP + CLK_R8 + 1); \ + g65816i_set_reg_p(g65816i_get_reg_p() | OPER_8_IMM()) + +/* M6502 Store accumulator to memory */ +#undef OP_STA +#if FLAG_SET_M +#define OP_STA(MODE) \ + CLK(CLK_OP + CLK_W8 + CLK_W_##MODE); \ + write_8_##MODE(EA_##MODE(), REGISTER_A) +#else +#define OP_STA(MODE) \ + CLK(CLK_OP + CLK_W16 + CLK_W_##MODE); \ + write_16_##MODE(EA_##MODE(), REGISTER_A) +#endif + +/* M6502 Store index register to memory */ +#undef OP_STX +#if FLAG_SET_X +#define OP_STX(REG, MODE) \ + CLK(CLK_OP + CLK_W8 + CLK_W_##MODE); \ + write_8_##MODE(EA_##MODE(), REG) +#else +#define OP_STX(REG, MODE) \ + CLK(CLK_OP + CLK_W16 + CLK_W_##MODE); \ + write_16_##MODE(EA_##MODE(), REG) +#endif + +/* M6502 Store zero to memory */ +#undef OP_STZ +#if FLAG_SET_M +#define OP_STZ(MODE) \ + CLK(CLK_OP + CLK_W8 + CLK_W_##MODE); \ + write_8_##MODE(EA_##MODE(), 0) +#else +#define OP_STZ(MODE) \ + CLK(CLK_OP + CLK_W16 + CLK_W_##MODE); \ + write_16_##MODE(EA_##MODE(), 0) +#endif + +/* G65816 Stop the clock */ +#undef OP_STP +#define OP_STP() \ + USE_ALL_CLKS(); \ + CPU_STOPPED |= STOP_LEVEL_STOP + +/* M6502 Transfer accumulator to index */ +#undef OP_TAX +#if FLAG_SET_M +#if FLAG_SET_X +#define OP_TAX(REG) \ + CLK(CLK_OP + CLK_IMPLIED); \ + FLAG_Z = REG = REGISTER_A; \ + FLAG_N = NFLAG_8(FLAG_Z) +#else /* FLAG_SET_X */ +#define OP_TAX(REG) \ + CLK(CLK_OP + CLK_IMPLIED); \ + FLAG_Z = REG = REGISTER_B | REGISTER_A; \ + FLAG_N = NFLAG_16(FLAG_Z) +#endif /* FLAG_SET_X */ +#else /* FLAG_SET_M */ +#if FLAG_SET_X +#define OP_TAX(REG) \ + CLK(CLK_OP + CLK_IMPLIED); \ + FLAG_Z = REG = MAKE_UINT_8(REGISTER_A); \ + FLAG_N = NFLAG_8(FLAG_Z) +#else /* FLAG_SET_X */ +#define OP_TAX(REG) \ + CLK(CLK_OP + CLK_IMPLIED); \ + FLAG_Z = REG = REGISTER_A; \ + FLAG_N = NFLAG_16(FLAG_Z) +#endif /* FLAG_SET_X */ +#endif /* FLAG_SET_M */ + + +/* M6502 Transfer index to accumulator */ +#undef OP_TXA +#if FLAG_SET_M +#define OP_TXA(REG) \ + CLK(CLK_OP + CLK_IMPLIED); \ + FLAG_Z = REGISTER_A = MAKE_UINT_8(REG); \ + FLAG_N = NFLAG_8(FLAG_Z) +#else +#define OP_TXA(REG) \ + CLK(CLK_OP + CLK_IMPLIED); \ + FLAG_Z = REGISTER_A = REG; \ + FLAG_N = NFLAG_16(FLAG_Z) +#endif + +/* G65816 Transfer C to direct register */ +#undef OP_TCD +#if FLAG_SET_M +#define OP_TCD() \ + CLK(CLK_OP + CLK_IMPLIED); \ + FLAG_Z = REGISTER_D = REGISTER_A | REGISTER_B; \ + FLAG_N = NFLAG_16(FLAG_Z) +#else +#define OP_TCD() \ + CLK(CLK_OP + CLK_IMPLIED); \ + FLAG_Z = REGISTER_D = REGISTER_A; \ + FLAG_N = NFLAG_16(FLAG_Z) +#endif + +/* G65816 Transfer direct register to C */ +#undef OP_TDC +#if FLAG_SET_M +#define OP_TDC() \ + CLK(CLK_OP + CLK_IMPLIED); \ + FLAG_Z = REGISTER_D; \ + FLAG_N = NFLAG_16(FLAG_Z); \ + REGISTER_A = MAKE_UINT_8(REGISTER_D); \ + REGISTER_B = REGISTER_D & 0xff00 +#else +#define OP_TDC() \ + CLK(CLK_OP + CLK_IMPLIED); \ + FLAG_Z = REGISTER_A = REGISTER_D; \ + FLAG_N = NFLAG_16(FLAG_Z) +#endif + +/* G65816 Transfer C to stack pointer */ +#undef OP_TCS +#if FLAG_SET_E +#define OP_TCS() \ + CLK(CLK_OP + CLK_IMPLIED); \ + REGISTER_S = MAKE_UINT_8(REGISTER_A) | 0x100 +#else +#define OP_TCS() \ + CLK(CLK_OP + CLK_IMPLIED); \ + REGISTER_S = REGISTER_A | REGISTER_B +#endif + +/* G65816 Transfer stack pointer to C */ +#undef OP_TSC +#if FLAG_SET_M +#define OP_TSC() \ + CLK(CLK_OP + CLK_IMPLIED); \ + FLAG_Z = REGISTER_S; \ + FLAG_N = NFLAG_16(FLAG_Z); \ + REGISTER_A = MAKE_UINT_8(REGISTER_S); \ + REGISTER_B = REGISTER_S & 0xff00 +#else +#define OP_TSC() \ + CLK(CLK_OP + CLK_IMPLIED); \ + FLAG_Z = REGISTER_A = REGISTER_S; \ + FLAG_N = NFLAG_16(FLAG_Z) +#endif + +/* M6502 Transfer stack pointer to X */ +#undef OP_TSX +#if FLAG_SET_X +#define OP_TSX() \ + CLK(CLK_OP + CLK_IMPLIED); \ + FLAG_Z = REGISTER_X = MAKE_UINT_8(REGISTER_S); \ + FLAG_N = NFLAG_8(FLAG_Z) +#else +#define OP_TSX() \ + CLK(CLK_OP + CLK_IMPLIED); \ + FLAG_Z = REGISTER_X = REGISTER_S; \ + FLAG_N = NFLAG_16(FLAG_Z) +#endif + +/* M6502 Transfer X to stack pointer */ +#undef OP_TXS +#if FLAG_SET_E +#define OP_TXS() \ + CLK(CLK_OP + CLK_IMPLIED); \ + REGISTER_S = MAKE_UINT_8(REGISTER_X) | 0x100 +#else +#define OP_TXS() \ + CLK(CLK_OP + CLK_IMPLIED); \ + REGISTER_S = REGISTER_X +#endif + +/* G65816 Transfer X to Y */ +#undef OP_TXY +#if FLAG_SET_X +#define OP_TXY() \ + CLK(CLK_OP + CLK_IMPLIED); \ + FLAG_Z = REGISTER_Y = REGISTER_X; \ + FLAG_N = NFLAG_8(FLAG_Z) +#else +#define OP_TXY() \ + CLK(CLK_OP + CLK_IMPLIED); \ + FLAG_Z = REGISTER_Y = REGISTER_X; \ + FLAG_N = NFLAG_16(FLAG_Z) +#endif + +/* G65816 Transfer Y to X */ +#undef OP_TYX +#if FLAG_SET_X +#define OP_TYX() \ + CLK(CLK_OP + CLK_IMPLIED); \ + FLAG_Z = REGISTER_X = REGISTER_Y; \ + FLAG_N = NFLAG_8(FLAG_Z) +#else +#define OP_TYX() \ + CLK(CLK_OP + CLK_IMPLIED); \ + FLAG_Z = REGISTER_X = REGISTER_Y; \ + FLAG_N = NFLAG_16(FLAG_Z) +#endif + +/* G65816 Test and reset bit */ +#undef OP_TRB +#if FLAG_SET_M +#define OP_TRB(MODE) \ + CLK(CLK_OP + CLK_RMW8 + CLK_W_##MODE); \ + DST = EA_##MODE(); \ + FLAG_Z = read_8_##MODE(DST); \ + write_8_##MODE(DST, FLAG_Z & ~REGISTER_A); \ + FLAG_Z &= REGISTER_A +#else +#define OP_TRB(MODE) \ + CLK(CLK_OP + CLK_RMW16 + CLK_W_##MODE); \ + DST = EA_##MODE(); \ + FLAG_Z = read_16_##MODE(DST); \ + write_16_##MODE(DST, FLAG_Z & ~REGISTER_A); \ + FLAG_Z &= REGISTER_A +#endif + +/* G65816 Test and set bit */ +#undef OP_TSB +#if FLAG_SET_M +#define OP_TSB(MODE) \ + CLK(CLK_OP + CLK_RMW8 + CLK_W_##MODE); \ + DST = EA_##MODE(); \ + FLAG_Z = read_8_##MODE(DST); \ + write_8_##MODE(DST, FLAG_Z | REGISTER_A); \ + FLAG_Z &= REGISTER_A +#else +#define OP_TSB(MODE) \ + CLK(CLK_OP + CLK_RMW16 + CLK_W_##MODE); \ + DST = EA_##MODE(); \ + FLAG_Z = read_16_##MODE(DST); \ + write_16_##MODE(DST, FLAG_Z | REGISTER_A); \ + FLAG_Z &= REGISTER_A +#endif + +/* G65816 Wait for interrupt */ +#undef OP_WAI +#define OP_WAI() \ + USE_ALL_CLKS(); \ + CPU_STOPPED |= STOP_LEVEL_WAI + +/* G65816 William D. Mensch, JR. (65816 designer) - future expansion */ +#undef OP_WDM +#define OP_WDM() \ + CLK(CLK_OP + CLK_IMPLIED); \ + REGISTER_PC++ + +/* G65816 Exchange accum high and low bytes */ +#undef OP_XBA +#if FLAG_SET_M +#define OP_XBA() \ + CLK(CLK_OP + CLK_IMPLIED); \ + FLAG_Z = REGISTER_B>>8; \ + REGISTER_B = REGISTER_A<<8; \ + REGISTER_A = FLAG_Z; \ + FLAG_N = NFLAG_8(FLAG_Z) +#else +#define OP_XBA() \ + CLK(CLK_OP + CLK_IMPLIED + 1); \ + FLAG_Z = REGISTER_A >> 8; \ + REGISTER_A = MAKE_UINT_16(REGISTER_A<<8) | FLAG_Z; \ + FLAG_N = NFLAG_8(FLAG_Z) +#endif + +/* G65816 Exchange carry and emulation bits */ +#undef OP_XCE +#define OP_XCE() \ + CLK(CLK_OP + CLK_IMPLIED); \ + SRC = CFLAG_AS_1(); \ + FLAG_C = FLAG_E<<8; \ + g65816i_set_flag_e(SRC) + + + + +/* ======================================================================== */ +/* ======================== OPCODE & FUNCTION TABLES ====================== */ +/* ======================================================================== */ + +#undef OP +#undef O +#undef TABLE_OPCODES +#undef TABLE_FUNCTION + +#if FLAG_SET_E +#define OP(CODE, OPERATION) void g65816_device::g65816i_ ## CODE ## _E() {OPERATION;} +#define O(CODE) &g65816_device::g65816i_ ## CODE ## _E +#define TABLE_OPCODES const g65816_device::opcode_func g65816_device::g65816i_opcodes_E[256] +#define TABLE_FUNCTION(RTYPE, NAME, ARGS) RTYPE g65816_device::g65816i_ ## NAME ## _E ARGS + +#else + +#if !FLAG_SET_M && !FLAG_SET_X +#define OP(CODE, OPERATION) void g65816_device::g65816i_ ## CODE ## _M0X0() {OPERATION;} +#define O(CODE) &g65816_device::g65816i_ ## CODE ## _M0X0 +#define TABLE_OPCODES const g65816_device::opcode_func g65816_device::g65816i_opcodes_M0X0[256] +#define TABLE_FUNCTION(RTYPE, NAME, ARGS) RTYPE g65816_device::g65816i_ ## NAME ## _M0X0 ARGS + +#elif !FLAG_SET_M && FLAG_SET_X + +#define OP(CODE, OPERATION) void g65816_device::g65816i_ ## CODE ## _M0X1() {OPERATION;} +#define O(CODE) &g65816_device::g65816i_ ## CODE ## _M0X1 +#define TABLE_OPCODES const g65816_device::opcode_func g65816_device::g65816i_opcodes_M0X1[256] +#define TABLE_FUNCTION(RTYPE, NAME, ARGS) RTYPE g65816_device::g65816i_ ## NAME ## _M0X1 ARGS + +#elif FLAG_SET_M && !FLAG_SET_X + +#define OP(CODE, OPERATION) void g65816_device::g65816i_ ## CODE ## _M1X0() {OPERATION;} +#define O(CODE) &g65816_device::g65816i_ ## CODE ## _M1X0 +#define TABLE_OPCODES const g65816_device::opcode_func g65816_device::g65816i_opcodes_M1X0[256] +#define TABLE_FUNCTION(RTYPE, NAME, ARGS) RTYPE g65816_device::g65816i_ ## NAME ## _M1X0 ARGS + +#elif FLAG_SET_M && FLAG_SET_X + +#define OP(CODE, OPERATION) void g65816_device::g65816i_ ## CODE ## _M1X1() {OPERATION;} +#define O(CODE) &g65816_device::g65816i_ ## CODE ## _M1X1 +#define TABLE_OPCODES const g65816_device::opcode_func g65816_device::g65816i_opcodes_M1X1[256] +#define TABLE_FUNCTION(RTYPE, NAME, ARGS) RTYPE g65816_device::g65816i_ ## NAME ## _M1X1 ARGS + +#endif +#endif +#define BREAKOUT return + + + +/* OP FUNCTION Comment */ +OP(00, OP_BRK ( ) ) /* BRK */ +OP(01, OP_ORA ( DXI ) ) /* ORA dxi */ +OP(02, OP_COP ( ) ) /* COP (G) */ +OP(03, OP_ORA ( S ) ) /* ORA s (G) */ +OP(04, OP_TSB ( D ) ) /* TSB d (C) */ +OP(05, OP_ORA ( D ) ) /* ORA d */ +OP(06, OP_ASLM ( D ) ) /* ASL d */ +OP(07, OP_ORA ( DLI ) ) /* ORA dli (G) */ +OP(08, OP_PHP ( ) ) /* PHP */ +OP(09, OP_ORA ( IMM ) ) /* ORA imm */ +OP(0a, OP_ASL ( ) ) /* ASL acc */ +OP(0b, OP_PHD ( ) ) /* PHD (G) */ +OP(0c, OP_TSB ( A ) ) /* TSB a (C) */ +OP(0d, OP_ORA ( A ) ) /* ORA a */ +OP(0e, OP_ASLM ( A ) ) /* ASL a */ +OP(0f, OP_ORA ( AL ) ) /* ORA al (G) */ +OP(10, OP_BCC ( COND_PL() ) ) /* BPL */ +OP(11, OP_ORA ( DIY ) ) /* ORA diy */ +OP(12, OP_ORA ( DI ) ) /* ORA di (C) */ +OP(13, OP_ORA ( SIY ) ) /* ORA siy (G) */ +OP(14, OP_TRB ( D ) ) /* TRB d (C) */ +OP(15, OP_ORA ( DX ) ) /* ORA dx */ +OP(16, OP_ASLM ( DX ) ) /* ASL dx */ +OP(17, OP_ORA ( DLIY ) ) /* ORA dliy(C) */ +OP(18, OP_CLC ( ) ) /* CLC */ +OP(19, OP_ORA ( AY ) ) /* ORA ay */ +OP(1a, OP_INC ( ) ) /* INA (C) */ +OP(1b, OP_TCS ( ) ) /* TCS (G) */ +OP(1c, OP_TRB ( A ) ) /* TRB a (C) */ +OP(1d, OP_ORA ( AX ) ) /* ORA ax */ +OP(1e, OP_ASLM ( AX ) ) /* ASL ax */ +OP(1f, OP_ORA ( ALX ) ) /* ORA alx (G) */ +OP(20, OP_JSR ( A ) ) /* JSR a */ +OP(21, OP_AND ( DXI ) ) /* AND dxi */ +OP(22, OP_JSL ( AL ) ) /* JSL al (G) */ +OP(23, OP_AND ( S ) ) /* AND s (G) */ +OP(24, OP_BIT ( D ) ) /* BIT d */ +OP(25, OP_AND ( D ) ) /* AND d */ +OP(26, OP_ROLM ( D ) ) /* ROL d */ +OP(27, OP_AND ( DLI ) ) /* AND dli (G) */ +OP(28, OP_PLP ( ) ) /* PLP */ +OP(29, OP_AND ( IMM ) ) /* AND imm */ +OP(2a, OP_ROL ( ) ) /* ROL acc */ +OP(2b, OP_PLD ( ) ) /* PLD (G) */ +OP(2c, OP_BIT ( A ) ) /* BIT a */ +OP(2d, OP_AND ( A ) ) /* AND a */ +OP(2e, OP_ROLM ( A ) ) /* ROL a */ +OP(2f, OP_AND ( AL ) ) /* AND al (G) */ +OP(30, OP_BCC ( COND_MI() ) ) /* BMI */ +OP(31, OP_AND ( DIY ) ) /* AND diy */ +OP(32, OP_AND ( DI ) ) /* AND di (C) */ +OP(33, OP_AND ( SIY ) ) /* AND siy */ +OP(34, OP_BIT ( DX ) ) /* BIT dx (C) */ +OP(35, OP_AND ( DX ) ) /* AND dx */ +OP(36, OP_ROLM ( DX ) ) /* ROL dx */ +OP(37, OP_AND ( DLIY ) ) /* AND dliy(G) */ +OP(38, OP_SEC ( ) ) /* SEC */ +OP(39, OP_AND ( AY ) ) /* AND ay */ +OP(3a, OP_DEC ( ) ) /* DEA (C) */ +OP(3b, OP_TSC ( ) ) /* TSC (G) */ +OP(3c, OP_BIT ( AX ) ) /* BIT abx (C) */ +OP(3d, OP_AND ( AX ) ) /* AND ax */ +OP(3e, OP_ROLM ( AX ) ) /* ROL ax */ +OP(3f, OP_AND ( ALX ) ) /* AND alx (G) */ +OP(40, OP_RTI ( ) ) /* RTI */ +OP(41, OP_EOR ( DXI ) ) /* EOR dxi */ +OP(42, OP_WDM ( ) ) /* WDM */ +OP(43, OP_EOR ( S ) ) /* EOR s (G) */ +OP(44, OP_MVP ( ) ) /* MVP (G) */ +OP(45, OP_EOR ( D ) ) /* EOR d */ +OP(46, OP_LSRM ( D ) ) /* LSR d */ +OP(47, OP_EOR ( DLI ) ) /* EOR dli (G) */ +OP(48, OP_PHA ( ) ) /* PHA */ +OP(49, OP_EOR ( IMM ) ) /* EOR imm */ +OP(4a, OP_LSR ( ) ) /* LSR acc */ +OP(4b, OP_PHK ( ) ) /* PHK (G) */ +OP(4c, OP_JMP ( A ) ) /* JMP a */ +OP(4d, OP_EOR ( A ) ) /* EOR a */ +OP(4e, OP_LSRM ( A ) ) /* LSR a */ +OP(4f, OP_EOR ( AL ) ) /* EOR al (G) */ +OP(50, OP_BCC ( COND_VC() ) ) /* BVC */ +OP(51, OP_EOR ( DIY ) ) /* EOR diy */ +OP(52, OP_EOR ( DI ) ) /* EOR di (C) */ +OP(53, OP_EOR ( SIY ) ) /* EOR siy (G) */ +OP(54, OP_MVN ( ) ) /* MVN (G) */ +OP(55, OP_EOR ( DX ) ) /* EOR dx */ +OP(56, OP_LSRM ( DX ) ) /* LSR dx */ +OP(57, OP_EOR ( DLIY ) ) /* EOR dliy(G) */ +OP(58, OP_CLI ( ) ) /* CLI */ +OP(59, OP_EOR ( AY ) ) /* EOR ay */ +OP(5a, OP_PHX ( REGISTER_Y ) ) /* PHY (C) */ +OP(5b, OP_TCD ( ) ) /* TCD (G) */ +OP(5c, OP_JMPAL( ) ) /* JMP al (G) */ +OP(5d, OP_EOR ( AX ) ) /* EOR ax */ +OP(5e, OP_LSRM ( AX ) ) /* LSR ax */ +OP(5f, OP_EOR ( ALX ) ) /* EOR alx (G) */ +OP(60, OP_RTS ( ) ) /* RTS */ +OP(61, OP_ADC ( DXI ) ) /* ADC dxi */ +OP(62, OP_PER ( ) ) /* PER (G) */ +OP(63, OP_ADC ( S ) ) /* ADC s (G) */ +OP(64, OP_STZ ( D ) ) /* STZ d (C) */ +OP(65, OP_ADC ( D ) ) /* ADC d */ +OP(66, OP_RORM ( D ) ) /* ROR d */ +OP(67, OP_ADC ( DLI ) ) /* ADC dli (G) */ +OP(68, OP_PLA ( ) ) /* PLA */ +OP(69, OP_ADC ( IMM ) ) /* ADC imm */ +OP(6a, OP_ROR ( ) ) /* ROR acc */ +OP(6b, OP_RTL ( ) ) /* RTL (G) */ +OP(6c, OP_JMP ( AI ) ) /* JMP ai */ +OP(6d, OP_ADC ( A ) ) /* ADC a */ +OP(6e, OP_RORM ( A ) ) /* ROR a */ +OP(6f, OP_ADC ( AL ) ) /* ADC al (G) */ +OP(70, OP_BCC ( COND_VS() ) ) /* BVS */ +OP(71, OP_ADC ( DIY ) ) /* ADC diy */ +OP(72, OP_ADC ( DI ) ) /* ADC di (G) */ +OP(73, OP_ADC ( SIY ) ) /* ADC siy (G) */ +OP(74, OP_STZ ( DX ) ) /* STZ dx (C) */ +OP(75, OP_ADC ( DX ) ) /* ADC dx */ +OP(76, OP_RORM ( DX ) ) /* ROR dx */ +OP(77, OP_ADC ( DLIY ) ) /* ADC dliy(G) */ +OP(78, OP_SEI ( ) ) /* SEI */ +OP(79, OP_ADC ( AY ) ) /* ADC ay */ +OP(7a, OP_PLX ( REGISTER_Y ) ) /* PLY (C) */ +OP(7b, OP_TDC ( ) ) /* TDC (G) */ +OP(7c, OP_JMPAXI( ) ) /* JMP axi (C) */ +OP(7d, OP_ADC ( AX ) ) /* ADC ax */ +OP(7e, OP_RORM ( AX ) ) /* ROR ax */ +OP(7f, OP_ADC ( ALX ) ) /* ADC alx (G) */ +OP(80, OP_BRA ( ) ) /* BRA (C) */ +OP(81, OP_STA ( DXI ) ) /* STA dxi */ +OP(82, OP_BRL ( ) ) /* BRL (G) */ +OP(83, OP_STA ( S ) ) /* STA s (G) */ +OP(84, OP_STX ( REGISTER_Y, D ) ) /* STY d */ +OP(85, OP_STA ( D ) ) /* STA d */ +OP(86, OP_STX ( REGISTER_X, D ) ) /* STX d */ +OP(87, OP_STA ( DLI ) ) /* STA dli (G) */ +OP(88, OP_DECX ( REGISTER_Y ) ) /* DEY */ +OP(89, OP_BITI ( ) ) /* BIT imm (C) */ +OP(8a, OP_TXA ( REGISTER_X ) ) /* TXA */ +OP(8b, OP_PHB ( ) ) /* PHB (G) */ +OP(8c, OP_STX ( REGISTER_Y, A ) ) /* STY a */ +OP(8d, OP_STA ( A ) ) /* STA a */ +OP(8e, OP_STX ( REGISTER_X, A ) ) /* STX a */ +OP(8f, OP_STA ( AL ) ) /* STA al (G) */ +OP(90, OP_BCC ( COND_CC() ) ) /* BCC */ +OP(91, OP_STA ( DIY ) ) /* STA diy */ +OP(92, OP_STA ( DI ) ) /* STA di (C) */ +OP(93, OP_STA ( SIY ) ) /* STA siy (G) */ +OP(94, OP_STX ( REGISTER_Y, DX ) ) /* STY dx */ +OP(95, OP_STA ( DX ) ) /* STA dx */ +OP(96, OP_STX ( REGISTER_X, DY ) ) /* STX dy */ +OP(97, OP_STA ( DLIY ) ) /* STA dliy(G) */ +OP(98, OP_TXA ( REGISTER_Y ) ) /* TYA */ +OP(99, OP_STA ( AY ) ) /* STA ay */ +OP(9a, OP_TXS ( ) ) /* TXS */ +OP(9b, OP_TXY ( ) ) /* TXY (G) */ +OP(9c, OP_STZ ( A ) ) /* STZ a (C) */ +OP(9d, OP_STA ( AX ) ) /* STA ax */ +OP(9e, OP_STZ ( AX ) ) /* STZ ax (C) */ +OP(9f, OP_STA ( ALX ) ) /* STA alx (G) */ +OP(a0, OP_LDX ( REGISTER_Y, IMM ) ) /* LDY imm */ +OP(a1, OP_LDA ( DXI ) ) /* LDA dxi */ +OP(a2, OP_LDX ( REGISTER_X, IMM ) ) /* LDX imm */ +OP(a3, OP_LDA ( S ) ) /* LDA s (G) */ +OP(a4, OP_LDX ( REGISTER_Y, D ) ) /* LDY d */ +OP(a5, OP_LDA ( D ) ) /* LDA d */ +OP(a6, OP_LDX ( REGISTER_X, D ) ) /* LDX d */ +OP(a7, OP_LDA ( DLI ) ) /* LDA dli (G) */ +OP(a8, OP_TAX ( REGISTER_Y ) ) /* TAY */ +OP(a9, OP_LDA ( IMM ) ) /* LDA imm */ +OP(aa, OP_TAX ( REGISTER_X ) ) /* TAX */ +OP(ab, OP_PLB ( ) ) /* PLB (G) */ +OP(ac, OP_LDX ( REGISTER_Y, A ) ) /* LDY a */ +OP(ad, OP_LDA ( A ) ) /* LDA a */ +OP(ae, OP_LDX ( REGISTER_X, A ) ) /* LDX a */ +OP(af, OP_LDA ( AL ) ) /* LDA al (G) */ +OP(b0, OP_BCC ( COND_CS() ) ) /* BCS */ +OP(b1, OP_LDA ( DIY ) ) /* LDA diy */ +OP(b2, OP_LDA ( DI ) ) /* LDA di (C) */ +OP(b3, OP_LDA ( SIY ) ) /* LDA siy (G) */ +OP(b4, OP_LDX ( REGISTER_Y, DX ) ) /* LDY dx */ +OP(b5, OP_LDA ( DX ) ) /* LDA dx */ +OP(b6, OP_LDX ( REGISTER_X, DY ) ) /* LDX dy */ +OP(b7, OP_LDA ( DLIY ) ) /* LDA dliy(G) */ +OP(b8, OP_CLV ( ) ) /* CLV */ +OP(b9, OP_LDA ( AY ) ) /* LDA ay */ +OP(ba, OP_TSX ( ) ) /* TSX */ +OP(bb, OP_TYX ( ) ) /* TYX (G) */ +OP(bc, OP_LDX ( REGISTER_Y, AX ) ) /* LDY ax */ +OP(bd, OP_LDA ( AX ) ) /* LDA ax */ +OP(be, OP_LDX ( REGISTER_X, AY ) ) /* LDX ay */ +OP(bf, OP_LDA ( ALX ) ) /* LDA alx (G) */ +OP(c0, OP_CMPX ( REGISTER_Y, IMM ) ) /* CPY imm */ +OP(c1, OP_CMP ( DXI ) ) /* CMP dxi */ +OP(c2, OP_REP ( ) ) /* REP (G) */ +OP(c3, OP_CMP ( S ) ) /* CMP s (G) */ +OP(c4, OP_CMPX ( REGISTER_Y, D ) ) /* CPY d */ +OP(c5, OP_CMP ( D ) ) /* CMP d */ +OP(c6, OP_DECM ( D ) ) /* DEC d */ +OP(c7, OP_CMP ( DLI ) ) /* CMP dli (G) */ +OP(c8, OP_INCX ( REGISTER_Y ) ) /* INY */ +OP(c9, OP_CMP ( IMM ) ) /* CMP imm */ +OP(ca, OP_DECX ( REGISTER_X ) ) /* DEX */ +OP(cb, OP_WAI ( ) ) /* WAI (G) */ +OP(cc, OP_CMPX ( REGISTER_Y, A ) ) /* CPY a */ +OP(cd, OP_CMP ( A ) ) /* CMP a */ +OP(ce, OP_DECM ( A ) ) /* DEC a */ +OP(cf, OP_CMP ( AL ) ) /* CMP al (G) */ +OP(d0, OP_BCC ( COND_NE() ) ) /* BNE */ +OP(d1, OP_CMP ( DIY ) ) /* CMP diy */ +OP(d2, OP_CMP ( DI ) ) /* CMP di (C) */ +OP(d3, OP_CMP ( SIY ) ) /* CMP siy (G) */ +OP(d4, OP_PEI ( ) ) /* PEI (G) */ +OP(d5, OP_CMP ( DX ) ) /* CMP dx */ +OP(d6, OP_DECM ( DX ) ) /* DEC dx */ +OP(d7, OP_CMP ( DLIY ) ) /* CMP dliy(G) */ +OP(d8, OP_CLD ( ) ) /* CLD */ +OP(d9, OP_CMP ( AY ) ) /* CMP ay */ +OP(da, OP_PHX ( REGISTER_X ) ) /* PHX (C) */ +OP(db, OP_STP ( ) ) /* STP (G) */ +OP(dc, OP_JMLAI( ) ) /* JML ai (G) */ +OP(dd, OP_CMP ( AX ) ) /* CMP ax */ +OP(de, OP_DECM ( AX ) ) /* DEC ax */ +OP(df, OP_CMP ( ALX ) ) /* CMP alx (G) */ +OP(e0, OP_CMPX ( REGISTER_X, IMM ) ) /* CPX imm */ +OP(e1, OP_SBC ( DXI ) ) /* SBC dxi */ +OP(e2, OP_SEP ( ) ) /* SEP imm (G) */ +OP(e3, OP_SBC ( S ) ) /* SBC s (G) */ +OP(e4, OP_CMPX ( REGISTER_X, D ) ) /* CPX d */ +OP(e5, OP_SBC ( D ) ) /* SBC d */ +OP(e6, OP_INCM ( D ) ) /* INC d */ +OP(e7, OP_SBC ( DLI ) ) /* SBC dli (G) */ +OP(e8, OP_INCX ( REGISTER_X ) ) /* INX */ +OP(e9, OP_SBC ( IMM ) ) /* SBC imm */ +OP(ea, OP_NOP ( ) ) /* NOP */ +OP(eb, OP_XBA ( ) ) /* XBA (G) */ +OP(ec, OP_CMPX ( REGISTER_X, A ) ) /* CPX a */ +OP(ed, OP_SBC ( A ) ) /* SBC a */ +OP(ee, OP_INCM ( A ) ) /* INC a */ +OP(ef, OP_SBC ( AL ) ) /* SBC al (G) */ +OP(f0, OP_BCC ( COND_EQ() ) ) /* BEQ */ +OP(f1, OP_SBC ( DIY ) ) /* SBC diy */ +OP(f2, OP_SBC ( DI ) ) /* SBC di (C) */ +OP(f3, OP_SBC ( SIY ) ) /* SBC siy (G) */ +OP(f4, OP_PEA ( ) ) /* PEA (G) */ +OP(f5, OP_SBC ( DX ) ) /* SBC dx */ +OP(f6, OP_INCM ( DX ) ) /* INC dx */ +OP(f7, OP_SBC ( DLIY ) ) /* SBC dliy(G) */ +OP(f8, OP_SED ( ) ) /* SED */ +OP(f9, OP_SBC ( AY ) ) /* SBC ay */ +OP(fa, OP_PLX ( REGISTER_X ) ) /* PLX (C) */ +OP(fb, OP_XCE ( ) ) /* XCE (G) */ +OP(fc, OP_JSRAXI( ) ) /* JSR axi (G) */ +OP(fd, OP_SBC ( AX ) ) /* SBC ax */ +OP(fe, OP_INCM ( AX ) ) /* INC ax */ +OP(ff, OP_SBC ( ALX ) ) /* SBC alx (G) */ + + + +TABLE_OPCODES = +{ + O(00),O(01),O(02),O(03),O(04),O(05),O(06),O(07), + O(08),O(09),O(0a),O(0b),O(0c),O(0d),O(0e),O(0f), + O(10),O(11),O(12),O(13),O(14),O(15),O(16),O(17), + O(18),O(19),O(1a),O(1b),O(1c),O(1d),O(1e),O(1f), + O(20),O(21),O(22),O(23),O(24),O(25),O(26),O(27), + O(28),O(29),O(2a),O(2b),O(2c),O(2d),O(2e),O(2f), + O(30),O(31),O(32),O(33),O(34),O(35),O(36),O(37), + O(38),O(39),O(3a),O(3b),O(3c),O(3d),O(3e),O(3f), + O(40),O(41),O(42),O(43),O(44),O(45),O(46),O(47), + O(48),O(49),O(4a),O(4b),O(4c),O(4d),O(4e),O(4f), + O(50),O(51),O(52),O(53),O(54),O(55),O(56),O(57), + O(58),O(59),O(5a),O(5b),O(5c),O(5d),O(5e),O(5f), + O(60),O(61),O(62),O(63),O(64),O(65),O(66),O(67), + O(68),O(69),O(6a),O(6b),O(6c),O(6d),O(6e),O(6f), + O(70),O(71),O(72),O(73),O(74),O(75),O(76),O(77), + O(78),O(79),O(7a),O(7b),O(7c),O(7d),O(7e),O(7f), + O(80),O(81),O(82),O(83),O(84),O(85),O(86),O(87), + O(88),O(89),O(8a),O(8b),O(8c),O(8d),O(8e),O(8f), + O(90),O(91),O(92),O(93),O(94),O(95),O(96),O(97), + O(98),O(99),O(9a),O(9b),O(9c),O(9d),O(9e),O(9f), + O(a0),O(a1),O(a2),O(a3),O(a4),O(a5),O(a6),O(a7), + O(a8),O(a9),O(aa),O(ab),O(ac),O(ad),O(ae),O(af), + O(b0),O(b1),O(b2),O(b3),O(b4),O(b5),O(b6),O(b7), + O(b8),O(b9),O(ba),O(bb),O(bc),O(bd),O(be),O(bf), + O(c0),O(c1),O(c2),O(c3),O(c4),O(c5),O(c6),O(c7), + O(c8),O(c9),O(ca),O(cb),O(cc),O(cd),O(ce),O(cf), + O(d0),O(d1),O(d2),O(d3),O(d4),O(d5),O(d6),O(d7), + O(d8),O(d9),O(da),O(db),O(dc),O(dd),O(de),O(df), + O(e0),O(e1),O(e2),O(e3),O(e4),O(e5),O(e6),O(e7), + O(e8),O(e9),O(ea),O(eb),O(ec),O(ed),O(ee),O(ef), + O(f0),O(f1),O(f2),O(f3),O(f4),O(f5),O(f6),O(f7), + O(f8),O(f9),O(fa),O(fb),O(fc),O(fd),O(fe),O(ff) +}; + + + +/* Assert or clear a line on the CPU */ +TABLE_FUNCTION(void, set_line, (int line, int state)) +{ + switch(line) + { + case G65816_LINE_IRQ: + switch(state) + { + case CLEAR_LINE: + LINE_IRQ = 0; + return; + case ASSERT_LINE: + case HOLD_LINE: + LINE_IRQ = 1; + } + if(FLAG_I) + { + if(CPU_STOPPED & STOP_LEVEL_WAI) + { + CPU_STOPPED &= ~STOP_LEVEL_WAI; + } + return; + } + return; + case G65816_LINE_NMI: + if(state == CLEAR_LINE) + { + LINE_NMI = 0; + return; + } + if(!LINE_NMI) + { + LINE_NMI = 1; + CPU_STOPPED &= ~STOP_LEVEL_WAI; + if(!CPU_STOPPED) + g65816i_interrupt_nmi(); + } + return; + case G65816_LINE_SO: + FLAG_V = VFLAG_SET; + break; + case G65816_LINE_RESET: + case G65816_LINE_ABORT: + case G65816_LINE_RDY: + return; + } + + LINE_IRQ=1; +} + + + +/* Get a register from the CPU core */ +TABLE_FUNCTION(uint, get_reg, (int regnum)) +{ + switch(regnum) + { + case G65816_A: return REGISTER_B | REGISTER_A; + case G65816_X: return REGISTER_X; + case G65816_Y: return REGISTER_Y; + case STATE_GENSP: return REGISTER_S; + case G65816_S: return REGISTER_S; + case STATE_GENPC: return REGISTER_PC; + case G65816_PC: return REGISTER_PC; + case G65816_PB: return REGISTER_PB >> 16; + case G65816_DB: return REGISTER_DB >> 16; + case G65816_D: return REGISTER_D; + case G65816_P: return g65816i_get_reg_p(); + case G65816_NMI_STATE: return LINE_NMI; + case G65816_IRQ_STATE: return LINE_IRQ; + case STATE_GENPCBASE: return REGISTER_PPC; + case _5A22_FASTROM: return m_fastROM; + } + return 0; +} + + + +TABLE_FUNCTION(void, set_reg, (int regnum, uint val)) +{ + switch(regnum) + { + case STATE_GENPC: case G65816_PC: REGISTER_PC = MAKE_UINT_16(val); break; +#if FLAG_SET_E + case STATE_GENSP: case G65816_S: REGISTER_S = MAKE_UINT_8(val) | 0x100; break; +#else + case STATE_GENSP: case G65816_S: REGISTER_S = MAKE_UINT_16(val); break; +#endif + case G65816_P: g65816i_set_reg_p(val); break; +#if FLAG_SET_M + case G65816_A: REGISTER_A = MAKE_UINT_8(val); REGISTER_B = val&0xff00; break; +#else + case G65816_A: REGISTER_A = MAKE_UINT_16(val); break; +#endif +#if FLAG_SET_X + case G65816_X: REGISTER_X = MAKE_UINT_8(val); break; + case G65816_Y: REGISTER_Y = MAKE_UINT_8(val); break; +#else + case G65816_X: REGISTER_X = MAKE_UINT_16(val); break; + case G65816_Y: REGISTER_Y = MAKE_UINT_16(val); break; +#endif + case G65816_DB: REGISTER_DB = MAKE_UINT_8(val); break; + case G65816_PB: REGISTER_PB = MAKE_UINT_8(val); break; + case G65816_NMI_STATE: (this->*FTABLE_SET_LINE)(G65816_LINE_NMI, val == 0 ? CLEAR_LINE : ASSERT_LINE); break; + case G65816_IRQ_STATE: (this->*FTABLE_SET_LINE)(G65816_LINE_IRQ, val == 0 ? CLEAR_LINE : ASSERT_LINE); break; + case _5A22_FASTROM: m_fastROM = val; break; + } +} + + + +#if EXECUTION_MODE == EXECUTION_MODE_E +#define g65816i_correct_mode() (FLAG_E == EFLAG_SET) +#elif EXECUTION_MODE == EXECUTION_MODE_M0X0 +#define g65816i_correct_mode() ((FLAG_E == EFLAG_CLEAR) && (FLAG_M == MFLAG_CLEAR) && (FLAG_X == XFLAG_CLEAR)) +#elif EXECUTION_MODE == EXECUTION_MODE_M0X1 +#define g65816i_correct_mode() ((FLAG_E == EFLAG_CLEAR) && (FLAG_M == MFLAG_CLEAR) && (FLAG_X == XFLAG_SET)) +#elif EXECUTION_MODE == EXECUTION_MODE_M1X0 +#define g65816i_correct_mode() ((FLAG_E == EFLAG_CLEAR) && (FLAG_M == MFLAG_SET) && (FLAG_X == XFLAG_CLEAR)) +#elif EXECUTION_MODE == EXECUTION_MODE_M1X1 +#define g65816i_correct_mode() ((FLAG_E == EFLAG_CLEAR) && (FLAG_M == MFLAG_SET) && (FLAG_X == XFLAG_SET)) +#else +#error Invalid EXECUTION_MODE +#endif + + + +TABLE_FUNCTION(int, execute, (int clocks)) +{ + // do a check here also in case we're in STOP_WAI mode - this'll clear it when the IRQ happens + g65816i_check_maskable_interrupt(); + + if (!CPU_STOPPED) + { + CLOCKS = clocks; + do + { + /* Note that I'm doing a per-instruction interrupt + * check until this core is working well enough + * to start trying fancy stuff. + */ + g65816i_check_maskable_interrupt(); + + REGISTER_PPC = REGISTER_PC; + G65816_CALL_DEBUGGER(REGISTER_PB | REGISTER_PC); + + REGISTER_PC++; + REGISTER_IR = read_8_IMM(REGISTER_PB | REGISTER_PPC); + (this->*FTABLE_OPCODES[REGISTER_IR])(); + } while((CLOCKS > 0) && g65816i_correct_mode()); + return clocks - CLOCKS; + } + return clocks; +} diff --git a/src/devices/cpu/h6280/6280dasm.c b/src/devices/cpu/h6280/6280dasm.c new file mode 100644 index 00000000000..4a9923ae0dc --- /dev/null +++ b/src/devices/cpu/h6280/6280dasm.c @@ -0,0 +1,254 @@ +// license:BSD-3-Clause +// copyright-holders:Bryan McPhail +/***************************************************************************** + + 6280dasm.c Hudsonsoft Hu6280 (HuC6280/Hu6280a) disassembler + + Copyright Bryan McPhail, mish@tendril.co.uk + + This source code is based (with permission!) on the 6502 emulator by + Juergen Buchmueller. It is released as part of the Mame emulator project. + Let me know if you intend to use this code in any other project. + + + Notes relating to Mame: + + The dasm window shows 'real' memory, as executed by the cpu + The data windows show 'physical' memory, as defined in the memory map + +******************************************************************************/ + +#ifdef __OS2__ +/* To avoid name clash of _brk */ +#define __STRICT_ANSI__ +#endif + +#include "emu.h" + +#define RDOP(addr) (oprom[addr - pc]) +#define RDBYTE(addr) (opram[addr - pc]) +#define RDWORD(addr) (opram[addr - pc] | ( oprom[(addr) + 1 - pc] << 8 )) + +enum addr_mode { + _non=0, /* no additional arguments */ + _acc, /* accumulator */ + _imp, /* implicit */ + _imm, /* immediate */ + _abs, /* absolute */ + _zpg, /* zero page */ + _zpx, /* zero page + X */ + _zpy, /* zero page + Y */ + _zpi, /* zero page indirect */ + _abx, /* absolute + X */ + _aby, /* absolute + Y */ + _rel, /* relative */ + _idx, /* zero page pre indexed */ + _idy, /* zero page post indexed */ + _ind, /* indirect */ + _iax, /* indirect + X */ + _blk, /* block */ + _zrl, /* zero page relative */ + _imz, /* immediate, zero page */ + _izx, /* immediate, zero page + X */ + _ima, /* immediate, absolute */ + _imx /* immediate, absolute + X */ +}; + +enum opcodes { + /* 6502 opcodes */ + _adc=0,_and, _asl, _bcc, _bcs, _beq, _bit, _bmi, + _bne, _bpl, _brk, _bvc, _bvs, _clc, _cld, _cli, + _clv, _cmp, _cpx, _cpy, _dec, _dex, _dey, _eor, + _inc, _inx, _iny, _jmp, _jsr, _lda, _ldx, _ldy, + _lsr, _nop, _ora, _pha, _php, _pla, _plp, _rol, + _ror, _rti, _rts, _sbc, _sec, _sed, _sei, _sta, + _stx, _sty, _tax, _tay, _tsx, _txa, _txs, _tya, + _ill, + + /* Hu6280 extensions */ + _bra, _stz, _trb, _tsb, _dea, _ina, _sax, _bsr, + _phx, _phy, _plx, _ply, _csh, _csl, _tam, _tma, + _cla, _cly, _clx, _st0, _st1, _st2, _tst, _set, + _tdd, _tia, _tii, _tin, _tai, _say, _sxy, + + _sm0, _sm1, _sm2, _sm3, _sm4, _sm5, _sm6, _sm7, + _rm0, _rm1, _rm2, _rm3, _rm4, _rm5, _rm6, _rm7, + + _bs0, _bs1, _bs2, _bs3, _bs4, _bs5, _bs6, _bs7, + _br0, _br1, _br2, _br3, _br4, _br5, _br6, _br7 + +}; + + +static const char *const token[]= +{ + /* 6502 opcodes */ + "adc", "and", "asl", "bcc", "bcs", "beq", "bit", "bmi", + "bne", "bpl", "brk", "bvc", "bvs", "clc", "cld", "cli", + "clv", "cmp", "cpx", "cpy", "dec", "dex", "dey", "eor", + "inc", "inx", "iny", "jmp", "jsr", "lda", "ldx", "ldy", + "lsr", "nop", "ora", "pha", "php", "pla", "plp", "rol", + "ror", "rti", "rts", "sbc", "sec", "sed", "sei", "sta", + "stx", "sty", "tax", "tay", "tsx", "txa", "txs", "tya", + "ill", + + /* Hu6280 extensions */ + "bra", "stz", "trb", "tsb", "dea", "ina", "sax", "bsr", + "phx", "phy", "plx", "ply", "csh", "csl", "tam", "tma", + "cla", "cly", "clx", "st0", "st1", "st2", "tst", "set", + "tdd", "tia", "tii", "tin", "tai", "say", "sxy", + + "smb0", "smb1", "smb2", "smb3", "smb4", "smb5", "smb6", "smb7", + "rmb0", "rmb1", "rmb2", "rmb3", "rmb4", "rmb5", "rmb6", "rmb7", + + "bbs0", "bbs1", "bbs2", "bbs3", "bbs4", "bbs5", "bbs6", "bbs7", + "bbr0", "bbr1", "bbr2", "bbr3", "bbr4", "bbr5", "bbr6", "bbr7" +}; + +static const unsigned char op6280[512]= +{ + _brk,_imp, _ora,_idx, _sxy,_imp, _st0,_imm, _tsb,_zpg, _ora,_zpg, _asl,_zpg, _rm0,_zpg, /* 00 */ + _php,_imp, _ora,_imm, _asl,_acc, _ill,_non, _tsb,_abs, _ora,_abs, _asl,_abs, _br0,_zrl, + _bpl,_rel, _ora,_idy, _ora,_zpi, _st1,_imm, _trb,_zpg, _ora,_zpx, _asl,_zpx, _rm1,_zpg, /* 10 */ + _clc,_imp, _ora,_aby, _ina,_imp, _ill,_non, _trb,_abs, _ora,_abx, _asl,_abx, _br1,_zrl, + _jsr,_abs, _and,_idx, _sax,_imp, _st2,_imm, _bit,_zpg, _and,_zpg, _rol,_zpg, _rm2,_zpg, /* 20 */ + _plp,_imp, _and,_imm, _rol,_acc, _ill,_non, _bit,_abs, _and,_abs, _rol,_abs, _br2,_zrl, + _bmi,_rel, _and,_idy, _and,_zpi, _ill,_non, _bit,_zpx, _and,_zpx, _rol,_zpx, _rm3,_zpg, /* 30 */ + _sec,_imp, _and,_aby, _dea,_imp, _ill,_non, _bit,_abx, _and,_abx, _rol,_abx, _br3,_zrl, + _rti,_imp, _eor,_idx, _say,_imp, _tma,_imm, _bsr,_rel, _eor,_zpg, _lsr,_zpg, _rm4,_zpg, /* 40 */ + _pha,_imp, _eor,_imm, _lsr,_acc, _ill,_non, _jmp,_abs, _eor,_abs, _lsr,_abs, _br4,_zrl, + _bvc,_rel, _eor,_idy, _eor,_zpi, _tam,_imm, _csl,_imp, _eor,_zpx, _lsr,_zpx, _rm5,_zpg, /* 50 */ + _cli,_imp, _eor,_aby, _phy,_imp, _ill,_non, _ill,_non, _eor,_abx, _lsr,_abx, _br5,_zrl, + _rts,_imp, _adc,_idx, _cla,_imp, _ill,_non, _stz,_zpg, _adc,_zpg, _ror,_zpg, _rm6,_zpg, /* 60 */ + _pla,_imp, _adc,_imm, _ror,_acc, _ill,_non, _jmp,_ind, _adc,_abs, _ror,_abs, _br6,_zrl, + _bvs,_rel, _adc,_idy, _adc,_zpi, _tii,_blk, _stz,_zpx, _adc,_zpx, _ror,_zpx, _rm7,_zpg, /* 70 */ + _sei,_imp, _adc,_aby, _ply,_imp, _ill,_non, _jmp,_iax, _adc,_abx, _ror,_abx, _br7,_zrl, + _bra,_rel, _sta,_idx, _clx,_imp, _tst,_imz, _sty,_zpg, _sta,_zpg, _stx,_zpg, _sm0,_zpg, /* 80 */ + _dey,_imp, _bit,_imm, _txa,_imp, _ill,_non, _sty,_abs, _sta,_abs, _stx,_abs, _bs0,_zrl, + _bcc,_rel, _sta,_idy, _sta,_zpi, _tst,_ima, _sty,_zpx, _sta,_zpx, _stx,_zpy, _sm1,_zpg, /* 90 */ + _tya,_imp, _sta,_aby, _txs,_imp, _ill,_non, _stz,_abs, _sta,_abx, _stz,_abx, _bs1,_zrl, + _ldy,_imm, _lda,_idx, _ldx,_imm, _tst,_izx, _ldy,_zpg, _lda,_zpg, _ldx,_zpg, _sm2,_zpg, /* a0 */ + _tay,_imp, _lda,_imm, _tax,_imp, _ill,_non, _ldy,_abs, _lda,_abs, _ldx,_abs, _bs2,_zrl, + _bcs,_rel, _lda,_idy, _lda,_zpi, _tst,_imx, _ldy,_zpx, _lda,_zpx, _ldx,_zpy, _sm3,_zpg, /* b0 */ + _clv,_imp, _lda,_aby, _tsx,_imp, _ill,_non, _ldy,_abx, _lda,_abx, _ldx,_aby, _bs3,_zrl, + _cpy,_imm, _cmp,_idx, _cly,_imp, _tdd,_blk, _cpy,_zpg, _cmp,_zpg, _dec,_zpg, _sm4,_zpg, /* c0 */ + _iny,_imp, _cmp,_imm, _dex,_imp, _ill,_non, _cpy,_abs, _cmp,_abs, _dec,_abs, _bs4,_zrl, + _bne,_rel, _cmp,_idy, _cmp,_zpi, _tin,_blk, _csh,_imp, _cmp,_zpx, _dec,_zpx, _sm5,_zpg, /* d0 */ + _cld,_imp, _cmp,_aby, _phx,_imp, _ill,_non, _ill,_non, _cmp,_abx, _dec,_abx, _bs5,_zrl, + _cpx,_imm, _sbc,_idx, _ill,_non, _tia,_blk, _cpx,_zpg, _sbc,_zpg, _inc,_zpg, _sm6,_zpg, /* e0 */ + _inx,_imp, _sbc,_imm, _nop,_imp, _ill,_non, _cpx,_abs, _sbc,_abs, _inc,_abs, _bs6,_zrl, + _beq,_rel, _sbc,_idy, _sbc,_zpi, _tai,_blk, _set,_imp, _sbc,_zpx, _inc,_zpx, _sm7,_zpg, /* f0 */ + _sed,_imp, _sbc,_aby, _plx,_imp, _ill,_non, _ill,_non, _sbc,_abx, _inc,_abx, _bs7,_zrl +}; + +/***************************************************************************** + * Disassemble a single command and return the number of bytes it uses. + *****************************************************************************/ +CPU_DISASSEMBLE( h6280 ) +{ + UINT32 flags = 0; + int PC, OP, opc, arg; + + PC = pc; + OP = RDOP(PC); + OP = OP << 1; + PC++; + + opc = op6280[OP]; + arg = op6280[OP+1]; + + if (opc == _jsr || opc == _bsr) + flags = DASMFLAG_STEP_OVER; + else if (opc == _rts) + flags = DASMFLAG_STEP_OUT; + + switch(arg) + { + case _acc: + sprintf(buffer,"%-5sa", token[opc]); + break; + case _imp: + sprintf(buffer,"%s", token[opc]); + break; + case _rel: + sprintf(buffer,"%-5s$%04X", token[opc], (PC + 1 + (signed char)RDBYTE(PC)) & 0xffff); + PC+=1; + break; + case _imm: + sprintf(buffer,"%-5s#$%02X", token[opc], RDBYTE(PC)); + PC+=1; + break; + case _zpg: + sprintf(buffer,"%-5s$%02X", token[opc], RDBYTE(PC)); + PC+=1; + break; + case _zpx: + sprintf(buffer,"%-5s$%02X,x", token[opc], RDBYTE(PC)); + PC+=1; + break; + case _zpy: + sprintf(buffer,"%-5s$%02X,y", token[opc], RDBYTE(PC)); + PC+=1; + break; + case _idx: + sprintf(buffer,"%-5s($%02X,x)", token[opc], RDBYTE(PC)); + PC+=1; + break; + case _idy: + sprintf(buffer,"%-5s($%02X),y", token[opc], RDBYTE(PC)); + PC+=1; + break; + case _zpi: + sprintf(buffer,"%-5s($%02X)", token[opc], RDBYTE(PC)); + PC+=1; + break; + case _abs: + sprintf(buffer,"%-5s$%04X", token[opc], RDWORD(PC)); + PC+=2; + break; + case _abx: + sprintf(buffer,"%-5s$%04X,x", token[opc], RDWORD(PC)); + PC+=2; + break; + case _aby: + sprintf(buffer,"%-5s$%04X,y", token[opc], RDWORD(PC)); + PC+=2; + break; + case _ind: + sprintf(buffer,"%-5s($%04X)", token[opc], RDWORD(PC)); + PC+=2; + break; + case _iax: + sprintf(buffer,"%-5s($%04X),X", token[opc], RDWORD(PC)); + PC+=2; + break; + case _blk: + sprintf(buffer,"%-5s$%04X $%04X $%04X", token[opc], RDWORD(PC), RDWORD(PC+2), RDWORD(PC+4)); + PC+=6; + break; + case _zrl: + sprintf(buffer,"%-5s$%02X $%04X", token[opc], RDBYTE(PC), (PC + 2 + (signed char)RDBYTE(PC+1)) & 0xffff); + PC+=2; + break; + case _imz: + sprintf(buffer,"%-5s#$%02X $%02X", token[opc], RDBYTE(PC), RDBYTE(PC+1)); + PC+=2; + break; + case _izx: + sprintf(buffer,"%-5s#$%02X $%02X,x", token[opc], RDBYTE(PC), RDBYTE(PC+1)); + PC+=2; + break; + case _ima: + sprintf(buffer,"%-5s#$%02X $%04X", token[opc], RDBYTE(PC), RDWORD(PC+1)); + PC+=3; + break; + case _imx: + sprintf(buffer,"%-5s#$%02X $%04X,x", token[opc], RDBYTE(PC), RDWORD(PC+1)); + PC+=3; + break; + + default: + sprintf(buffer,"%-5s$%02X", token[opc], OP >> 1); + } + return (PC - pc) | flags | DASMFLAG_SUPPORTED; +} diff --git a/src/devices/cpu/h6280/h6280.c b/src/devices/cpu/h6280/h6280.c new file mode 100644 index 00000000000..f92e0520a12 --- /dev/null +++ b/src/devices/cpu/h6280/h6280.c @@ -0,0 +1,2581 @@ +// license:BSD-3-Clause +// copyright-holders:Bryan McPhail +/***************************************************************************** + + h6280.c - Portable HuC6280 emulator + + Copyright Bryan McPhail, mish@tendril.co.uk + + This source code is based (with permission!) on the 6502 emulator by + Juergen Buchmueller. It is released as part of the Mame emulator project. + Let me know if you intend to use this code in any other project. + + + NOTICE: + + This code is around 99% complete! Several things are unimplemented, + some due to lack of time, some due to lack of documentation, mainly + due to lack of programs using these features. + + csh, csl opcodes are not supported. + + I am unsure if flag B is set upon execution of rti. + + Cycle counts should be quite accurate. + + + Changelog, version 1.02: + JMP + indirect X (0x7c) opcode fixed. + SMB + RMB opcodes fixed in disassembler. + change_pc function calls removed. + TSB & TRB now set flags properly. + BIT opcode altered. + + Changelog, version 1.03: + Swapped IRQ mask for IRQ1 & IRQ2 (thanks Yasuhiro) + + Changelog, version 1.04, 28/9/99-22/10/99: + Adjusted RTI (thanks Karl) + TST opcodes fixed in disassembler (missing break statements in a case!). + TST behaviour fixed. + SMB/RMB/BBS/BBR fixed in disassembler. + + Changelog, version 1.05, 8/12/99-16/12/99: + Added CAB's timer implementation (note: irq ack & timer reload are changed). + Fixed STA IDX. + Fixed B flag setting on BRK. + Assumed CSH & CSL to take 2 cycles each. + + Todo: Performance could be improved by precalculating timer fire position. + + Changelog, version 1.06, 4/5/00 - last opcode bug found? + JMP indirect was doing a EAL++; instead of EAD++; - Obviously causing + a corrupt read when L = 0xff! This fixes Bloody Wolf and Trio The Punch! + + Changelog, version 1.07, 3/9/00: + Changed timer to be single shot - fixes Crude Buster music in level 1. + + Changelog, version 1.08, 8/11/05: (Charles MacDonald) + + Changed timer implementation, no longer single shot and reading the + timer registers returns the count only. Fixes the following: + - Mesopotamia: Music tempo & in-game timer + - Dragon Saber: DDA effects + - Magical Chase: Music tempo and speed regulation + - Cadash: Allows the first level to start + - Turrican: Allows the game to start + + Changed PLX and PLY to set NZ flags. Fixes: + - Afterburner: Graphics unpacking + - Aoi Blink: Collision detection with background + + Fixed the decimal version of ADC/SBC to *not* update the V flag, + only the binary ones do. + + Fixed B flag handling so it is always set outside of an interrupt; + even after being set by PLP and RTI. + + Fixed P state after reset to set I and B, leaving T, D cleared and + NVZC randomized (cleared in this case). + + Fixed interrupt processing order (Timer has highest priority followed + by IRQ1 and finally IRQ2). + + Changelog, version 1.09, 1/07/06: (Rob Bohms) + + Added emulation of the T flag, fixes PCE Ankuku Densetsu title screen + + Changelog, version 1.10, 5/09/07: (Wilbert Pol) + + - Taking of interrupts is delayed to respect a pending instruction already + in the instruction pipeline; fixes After Burner. + - Added 1 cycle for decimal mode ADC and SBC instructions. + - Changed cycle counts for CSH and CSL instructions to 3. + - Added T flag support to the SBC instruction. + - Fixed ADC T flag to set the Z flag based on the value read. + - Added 3 cycle penalty to ADC, AND, EOR, ORA, and SBC instructions + when the T flag is set. + - Fixed cycle count and support for 65536 byte blocks for the TAI, TDD, + TIA, TII, and TIN instructions. + - Fixed RDWORD macro in the disassembler. + - Fixed setting of N and V flags in the TST instructions. + - Removed unneeded debug_mmr code. + - Fixed TSB and TRB instructions. + - Added 1 delay when accessing the VDC or VCE areas. + - Implemented low and high speed cpu modes. + + Changelog, version 1.11, 18/09/07: (Wilbert Pol) + + - Improvements to the handling of taking of delayed interrupts. + +******************************************************************************/ + +#include "h6280.h" +#include "debugger.h" + +/* 6280 flags */ +enum +{ + _fC = 0x01, + _fZ = 0x02, + _fI = 0x04, + _fD = 0x08, + _fB = 0x10, + _fT = 0x20, + _fV = 0x40, + _fN = 0x80 +}; + +/* some shortcuts for improved readability */ +#define A m_a +#define X m_x +#define Y m_y +#define P m_p +#define S m_sp.b.l + +#define EAL m_ea.b.l +#define EAH m_ea.b.h +#define EAW m_ea.w.l +#define EAD m_ea.d + +#define ZPL m_zp.b.l +#define ZPH m_zp.b.h +#define ZPW m_zp.w.l +#define ZPD m_zp.d + +#define PCL m_pc.b.l +#define PCH m_pc.b.h +#define PCW m_pc.w.l +#define PCD m_pc.d + +//************************************************************************** +// DEVICE INTERFACE +//************************************************************************** + +const device_type H6280 = &device_creator; + +//------------------------------------------------- +// h6280_device - constructor +//------------------------------------------------- + +h6280_device::h6280_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : cpu_device(mconfig, H6280, "H6280", tag, owner, clock, "h6280", __FILE__), + m_program_config("program", ENDIANNESS_LITTLE, 8, 21), + m_io_config("io", ENDIANNESS_LITTLE, 8, 2) +{ + // build the opcode table + for (int op = 0; op < 256; op++) + m_opcode[op] = s_opcodetable[op]; +} + + +const h6280_device::ophandler h6280_device::s_opcodetable[256] = +{ + &h6280_device::op_00, &h6280_device::op_01, &h6280_device::op_02, &h6280_device::op_03, &h6280_device::op_04, &h6280_device::op_05, &h6280_device::op_06, &h6280_device::op_07, + &h6280_device::op_08, &h6280_device::op_09, &h6280_device::op_0a, &h6280_device::op_0b, &h6280_device::op_0c, &h6280_device::op_0d, &h6280_device::op_0e, &h6280_device::op_0f, + &h6280_device::op_10, &h6280_device::op_11, &h6280_device::op_12, &h6280_device::op_13, &h6280_device::op_14, &h6280_device::op_15, &h6280_device::op_16, &h6280_device::op_17, + &h6280_device::op_18, &h6280_device::op_19, &h6280_device::op_1a, &h6280_device::op_1b, &h6280_device::op_1c, &h6280_device::op_1d, &h6280_device::op_1e, &h6280_device::op_1f, + &h6280_device::op_20, &h6280_device::op_21, &h6280_device::op_22, &h6280_device::op_23, &h6280_device::op_24, &h6280_device::op_25, &h6280_device::op_26, &h6280_device::op_27, + &h6280_device::op_28, &h6280_device::op_29, &h6280_device::op_2a, &h6280_device::op_2b, &h6280_device::op_2c, &h6280_device::op_2d, &h6280_device::op_2e, &h6280_device::op_2f, + &h6280_device::op_30, &h6280_device::op_31, &h6280_device::op_32, &h6280_device::op_33, &h6280_device::op_34, &h6280_device::op_35, &h6280_device::op_36, &h6280_device::op_37, + &h6280_device::op_38, &h6280_device::op_39, &h6280_device::op_3a, &h6280_device::op_3b, &h6280_device::op_3c, &h6280_device::op_3d, &h6280_device::op_3e, &h6280_device::op_3f, + &h6280_device::op_40, &h6280_device::op_41, &h6280_device::op_42, &h6280_device::op_43, &h6280_device::op_44, &h6280_device::op_45, &h6280_device::op_46, &h6280_device::op_47, + &h6280_device::op_48, &h6280_device::op_49, &h6280_device::op_4a, &h6280_device::op_4b, &h6280_device::op_4c, &h6280_device::op_4d, &h6280_device::op_4e, &h6280_device::op_4f, + &h6280_device::op_50, &h6280_device::op_51, &h6280_device::op_52, &h6280_device::op_53, &h6280_device::op_54, &h6280_device::op_55, &h6280_device::op_56, &h6280_device::op_57, + &h6280_device::op_58, &h6280_device::op_59, &h6280_device::op_5a, &h6280_device::op_5b, &h6280_device::op_5c, &h6280_device::op_5d, &h6280_device::op_5e, &h6280_device::op_5f, + &h6280_device::op_60, &h6280_device::op_61, &h6280_device::op_62, &h6280_device::op_63, &h6280_device::op_64, &h6280_device::op_65, &h6280_device::op_66, &h6280_device::op_67, + &h6280_device::op_68, &h6280_device::op_69, &h6280_device::op_6a, &h6280_device::op_6b, &h6280_device::op_6c, &h6280_device::op_6d, &h6280_device::op_6e, &h6280_device::op_6f, + &h6280_device::op_70, &h6280_device::op_71, &h6280_device::op_72, &h6280_device::op_73, &h6280_device::op_74, &h6280_device::op_75, &h6280_device::op_76, &h6280_device::op_77, + &h6280_device::op_78, &h6280_device::op_79, &h6280_device::op_7a, &h6280_device::op_7b, &h6280_device::op_7c, &h6280_device::op_7d, &h6280_device::op_7e, &h6280_device::op_7f, + &h6280_device::op_80, &h6280_device::op_81, &h6280_device::op_82, &h6280_device::op_83, &h6280_device::op_84, &h6280_device::op_85, &h6280_device::op_86, &h6280_device::op_87, + &h6280_device::op_88, &h6280_device::op_89, &h6280_device::op_8a, &h6280_device::op_8b, &h6280_device::op_8c, &h6280_device::op_8d, &h6280_device::op_8e, &h6280_device::op_8f, + &h6280_device::op_90, &h6280_device::op_91, &h6280_device::op_92, &h6280_device::op_93, &h6280_device::op_94, &h6280_device::op_95, &h6280_device::op_96, &h6280_device::op_97, + &h6280_device::op_98, &h6280_device::op_99, &h6280_device::op_9a, &h6280_device::op_9b, &h6280_device::op_9c, &h6280_device::op_9d, &h6280_device::op_9e, &h6280_device::op_9f, + &h6280_device::op_a0, &h6280_device::op_a1, &h6280_device::op_a2, &h6280_device::op_a3, &h6280_device::op_a4, &h6280_device::op_a5, &h6280_device::op_a6, &h6280_device::op_a7, + &h6280_device::op_a8, &h6280_device::op_a9, &h6280_device::op_aa, &h6280_device::op_ab, &h6280_device::op_ac, &h6280_device::op_ad, &h6280_device::op_ae, &h6280_device::op_af, + &h6280_device::op_b0, &h6280_device::op_b1, &h6280_device::op_b2, &h6280_device::op_b3, &h6280_device::op_b4, &h6280_device::op_b5, &h6280_device::op_b6, &h6280_device::op_b7, + &h6280_device::op_b8, &h6280_device::op_b9, &h6280_device::op_ba, &h6280_device::op_bb, &h6280_device::op_bc, &h6280_device::op_bd, &h6280_device::op_be, &h6280_device::op_bf, + &h6280_device::op_c0, &h6280_device::op_c1, &h6280_device::op_c2, &h6280_device::op_c3, &h6280_device::op_c4, &h6280_device::op_c5, &h6280_device::op_c6, &h6280_device::op_c7, + &h6280_device::op_c8, &h6280_device::op_c9, &h6280_device::op_ca, &h6280_device::op_cb, &h6280_device::op_cc, &h6280_device::op_cd, &h6280_device::op_ce, &h6280_device::op_cf, + &h6280_device::op_d0, &h6280_device::op_d1, &h6280_device::op_d2, &h6280_device::op_d3, &h6280_device::op_d4, &h6280_device::op_d5, &h6280_device::op_d6, &h6280_device::op_d7, + &h6280_device::op_d8, &h6280_device::op_d9, &h6280_device::op_da, &h6280_device::op_db, &h6280_device::op_dc, &h6280_device::op_dd, &h6280_device::op_de, &h6280_device::op_df, + &h6280_device::op_e0, &h6280_device::op_e1, &h6280_device::op_e2, &h6280_device::op_e3, &h6280_device::op_e4, &h6280_device::op_e5, &h6280_device::op_e6, &h6280_device::op_e7, + &h6280_device::op_e8, &h6280_device::op_e9, &h6280_device::op_ea, &h6280_device::op_eb, &h6280_device::op_ec, &h6280_device::op_ed, &h6280_device::op_ee, &h6280_device::op_ef, + &h6280_device::op_f0, &h6280_device::op_f1, &h6280_device::op_f2, &h6280_device::op_f3, &h6280_device::op_f4, &h6280_device::op_f5, &h6280_device::op_f6, &h6280_device::op_f7, + &h6280_device::op_f8, &h6280_device::op_f9, &h6280_device::op_fa, &h6280_device::op_fb, &h6280_device::op_fc, &h6280_device::op_fd, &h6280_device::op_fe, &h6280_device::op_ff +}; + +void h6280_device::device_start() +{ + // register our state for the debugger + state_add(STATE_GENPC, "GENPC", m_pc.w.l).noshow(); + state_add(STATE_GENFLAGS, "GENFLAGS", m_p).callimport().callexport().formatstr("%8s").noshow(); + state_add(H6280_PC, "PC", m_pc.d).mask(0xffff); + state_add(H6280_S, "S", m_sp.b.l).mask(0xff); + state_add(H6280_P, "P", m_p).mask(0xff); + state_add(H6280_A, "A", m_a).mask(0xff); + state_add(H6280_X, "X", m_x).mask(0xff); + state_add(H6280_Y, "Y", m_y).mask(0xff); + state_add(H6280_IRQ_MASK, "IM", m_irq_mask).mask(0xff); + state_add(H6280_TIMER_STATE,"TMR", m_timer_status).mask(0xff); + state_add(H6280_NMI_STATE, "NMI", m_nmi_state).mask(0xf); + state_add(H6280_IRQ1_STATE, "IRQ1", m_irq_state[0]).mask(0xf); + state_add(H6280_IRQ2_STATE, "IRQ2", m_irq_state[1]).mask(0xf); + state_add(H6280_IRQT_STATE, "IRQT", m_irq_state[2]).mask(0xf); + state_add(H6280_M1, "M1", m_mmr[0]).mask(0xff); + state_add(H6280_M2, "M2", m_mmr[1]).mask(0xff); + state_add(H6280_M3, "M3", m_mmr[2]).mask(0xff); + state_add(H6280_M4, "M4", m_mmr[3]).mask(0xff); + state_add(H6280_M5, "M5", m_mmr[4]).mask(0xff); + state_add(H6280_M6, "M6", m_mmr[5]).mask(0xff); + state_add(H6280_M7, "M7", m_mmr[6]).mask(0xff); + state_add(H6280_M8, "M8", m_mmr[7]).mask(0xff); + + save_item(NAME(m_ppc.w.l)); + save_item(NAME(m_pc.w.l)); + save_item(NAME(m_sp.w.l)); + save_item(NAME(m_zp.w.l)); + save_item(NAME(m_ea.w.l)); + save_item(NAME(m_a)); + save_item(NAME(m_x)); + save_item(NAME(m_y)); + save_item(NAME(m_p)); + save_item(NAME(m_mmr)); + save_item(NAME(m_irq_mask)); + save_item(NAME(m_timer_status)); + save_item(NAME(m_timer_ack)); + save_item(NAME(m_clocks_per_cycle)); + save_item(NAME(m_timer_value)); + save_item(NAME(m_timer_load)); + save_item(NAME(m_nmi_state)); + save_item(NAME(m_irq_state[0])); + save_item(NAME(m_irq_state[1])); + save_item(NAME(m_irq_state[2])); + save_item(NAME(m_irq_pending)); + +#if LAZY_FLAGS + save_item(NAME(m_nz)); +#endif + save_item(NAME(m_io_buffer)); + + // set our instruction counter + m_icountptr = &m_icount; + m_icount = 0; + + /* clear pending interrupts */ + for (int i = 0; i < 3; i++) + { + m_irq_state[i] = CLEAR_LINE; + } + m_nmi_state = CLEAR_LINE; +} + +void h6280_device::device_reset() +{ + /* wipe out the h6280 structure */ + m_ppc.d = 0; + m_pc.d = 0; + m_zp.d = 0; + m_ea.d = 0; + m_a = 0; + m_x = 0; + m_y = 0; + m_p = 0; + memset(m_mmr, 0, sizeof(UINT8) * 8); + m_irq_mask = 0; + m_timer_ack = 0; + m_timer_value = 0; +#if LAZY_FLAGS + m_nz = 0; +#endif + m_io_buffer = 0; + + m_program = &space(AS_PROGRAM); + m_direct = &m_program->direct(); + m_io = &space(AS_IO); + + /* set I and B flags */ + P = _fI | _fB; + + /* stack starts at 0x01ff */ + m_sp.d = 0x1ff; + + /* read the reset vector into PC */ + PCL = program_read8(H6280_RESET_VEC); + PCH = program_read8(H6280_RESET_VEC + 1); + + /* CPU starts in low speed mode */ + m_clocks_per_cycle = 4; + + /* timer off by default */ + m_timer_status = 0; + m_timer_load = 128 * 1024; + + m_irq_pending = 0; +} + +void h6280_device::device_stop() +{ + /* nothing */ +} + + +inline UINT32 h6280_device::translated(UINT16 addr) +{ + return ((m_mmr[((addr) >> 13) & 7] << 13) | ((addr) & 0x1fff)); +} + +inline void h6280_device::h6280_cycles(int cyc) +{ + m_icount -= ((cyc) * m_clocks_per_cycle); + m_timer_value -= ((cyc) * m_clocks_per_cycle); +} + +#if LAZY_FLAGS + +#define NZ m_NZ +inline void h6280_device::set_nz(UINT8 n) +{ + P &= ~_fT; + NZ = ((n & _fN) << 8) | n; +} + +#else + +inline void h6280_device::set_nz(UINT8 n) +{ + P = (P & ~(_fN|_fT|_fZ)) | + (n & _fN) | + ((n == 0) ? _fZ : 0); +} + +#endif + +inline void h6280_device::clear_t() +{ + P &= ~_fT; +} + +inline void h6280_device::do_interrupt(UINT16 vector) +{ + h6280_cycles(7); /* 7 cycles for an int */ + push(PCH); + push(PCL); + compose_p(0, _fB); + push(P); + P = (P & ~_fD) | _fI; /* knock out D and set I flag */ + PCL = program_read8(vector); + PCH = program_read8(vector + 1); +} + +inline void h6280_device::check_and_take_irq_lines() +{ + if ( m_nmi_state != CLEAR_LINE ) { + m_nmi_state = CLEAR_LINE; + do_interrupt(H6280_NMI_VEC); + } + else if( !(P & _fI) ) + { + if ( m_irq_state[2] != CLEAR_LINE && + !(m_irq_mask & 0x4) ) + { + do_interrupt(H6280_TIMER_VEC); + } else + if ( m_irq_state[0] != CLEAR_LINE && + !(m_irq_mask & 0x2) ) + { + do_interrupt(H6280_IRQ1_VEC); + standard_irq_callback(0); + } else + if ( m_irq_state[1] != CLEAR_LINE && + !(m_irq_mask & 0x1) ) + { + do_interrupt(H6280_IRQ2_VEC); + standard_irq_callback(1); + } + } +} + +inline void h6280_device::check_irq_lines() +{ + if (!m_irq_pending) + m_irq_pending = 2; +} + +/*************************************************************** + * CHECK_VDC_VCE_PENALTY + * The CPU inserts 1 clock delay when accessing the VDC or VCE + * area. + ***************************************************************/ +inline void h6280_device::check_vdc_vce_penalty(UINT16 addr) +{ + if ( ( translated(addr) & 0x1FF800 ) == 0x1FE000 ) { + h6280_cycles(1); + } +} + +/*************************************************************** + * BRA branch relative + ***************************************************************/ +inline void h6280_device::bra(bool cond) +{ + clear_t(); + if (cond) + { + h6280_cycles(4); + UINT8 tmp = read_opcode_arg(); + PCW++; + EAW = PCW + (signed char)tmp; + PCD = EAD; + } + else + { + PCW++; + h6280_cycles(2); + } +} + +/*************************************************************** + * + * Helper macros to build the effective address + * + ***************************************************************/ + +/*************************************************************** + * EA = zero page address + ***************************************************************/ +inline void h6280_device::ea_zpg() +{ + ZPL = read_opcode_arg(); + PCW++; + EAD = ZPD; +} + +/*************************************************************** + * EA = zero page address - T flag + ***************************************************************/ +inline void h6280_device::ea_tflg() +{ + ZPL = X; + EAD = ZPD; +} + +/*************************************************************** + * EA = zero page address + X + ***************************************************************/ +inline void h6280_device::ea_zpx() +{ + ZPL = read_opcode_arg() + X; + PCW++; + EAD = ZPD; +} + +/*************************************************************** + * EA = zero page address + Y + ***************************************************************/ +inline void h6280_device::ea_zpy() +{ + ZPL = read_opcode_arg() + Y; + PCW++; + EAD = ZPD; +} + +/*************************************************************** + * EA = absolute address + ***************************************************************/ +inline void h6280_device::ea_abs() +{ + EAL = read_opcode_arg(); + PCW++; + EAH = read_opcode_arg(); + PCW++; +} + +/*************************************************************** + * EA = absolute address + X + ***************************************************************/ +inline void h6280_device::ea_abx() +{ + ea_abs(); + EAW += X; +} + +/*************************************************************** + * EA = absolute address + Y + ***************************************************************/ +inline void h6280_device::ea_aby() +{ + ea_abs(); + EAW += Y; +} + +/*************************************************************** + * EA = zero page indirect (65c02 pre indexed w/o X) + ***************************************************************/ +inline void h6280_device::ea_zpi() +{ + ZPL = read_opcode_arg(); + PCW++; + EAD = program_read16z(ZPD); +} + +/*************************************************************** + * EA = zero page + X indirect (pre indexed) + ***************************************************************/ +inline void h6280_device::ea_idx() +{ + ZPL = read_opcode_arg() + X; + PCW++; + EAD = program_read16z(ZPD); +} + +/*************************************************************** + * EA = zero page indirect + Y (post indexed) + ***************************************************************/ +inline void h6280_device::ea_idy() +{ + ZPL = read_opcode_arg(); + PCW++; + EAD = program_read16z(ZPD); + EAW += Y; +} + +/*************************************************************** + * EA = indirect (only used by JMP) + ***************************************************************/ +inline void h6280_device::ea_ind() +{ + ea_abs(); + UINT8 tmp = program_read8(EAD); + EAD++; + EAH = program_read8(EAD); + EAL = tmp; +} + +/*************************************************************** + * EA = indirect plus x (only used by JMP) + ***************************************************************/ +inline void h6280_device::ea_iax() +{ + ea_abs(); + EAD+=X; + UINT8 tmp = program_read8(EAD); + EAD++; + EAH = program_read8(EAD); + EAL = tmp; +} + +inline UINT8 h6280_device::rd_imm() +{ + UINT8 tmp = read_opcode_arg(); + PCW++; + return tmp; +} + +inline UINT8 h6280_device::rd_zpg() +{ + ea_zpg(); + return program_read8z(EAD); +} + +inline UINT8 h6280_device::rd_zpx() +{ + ea_zpx(); + return program_read8z(EAD); +} + +inline UINT8 h6280_device::rd_zpy() +{ + ea_zpy(); + return program_read8z(EAD); +} + +inline UINT8 h6280_device::rd_abs() +{ + ea_abs(); + return program_read8(EAD); +} + +inline UINT8 h6280_device::rd_abx() +{ + ea_abx(); + return program_read8(EAD); +} + +inline UINT8 h6280_device::rd_aby() +{ + ea_aby(); + return program_read8(EAD); +} + +inline UINT8 h6280_device::rd_zpi() +{ + ea_zpi(); + return program_read8(EAD); +} + +inline UINT8 h6280_device::rd_idx() +{ + ea_idx(); + return program_read8(EAD); +} + +inline UINT8 h6280_device::rd_idy() +{ + ea_idy(); + return program_read8(EAD); +} + +inline UINT8 h6280_device::rd_tfl() +{ + ea_tflg(); + return program_read8z(EAD); +} + +inline void h6280_device::wr_zpg(UINT8 tmp) +{ + ea_zpg(); + wb_eaz(tmp); +} + +inline void h6280_device::wr_zpx(UINT8 tmp) +{ + ea_zpx(); + wb_eaz(tmp); +} + +inline void h6280_device::wr_zpy(UINT8 tmp) +{ + ea_zpy(); + wb_eaz(tmp); +} + +inline void h6280_device::wr_abs(UINT8 tmp) +{ + ea_abs(); + wb_ea(tmp); +} + +inline void h6280_device::wr_abx(UINT8 tmp) +{ + ea_abx(); + wb_ea(tmp); +} + +inline void h6280_device::wr_aby(UINT8 tmp) +{ + ea_aby(); + wb_ea(tmp); +} + +inline void h6280_device::wr_zpi(UINT8 tmp) +{ + ea_zpi(); + wb_ea(tmp); +} + +inline void h6280_device::wr_idx(UINT8 tmp) +{ + ea_idx(); + wb_ea(tmp); +} + +inline void h6280_device::wr_idy(UINT8 tmp) +{ + ea_idy(); + wb_ea(tmp); +} + +inline void h6280_device::wb_ea(UINT8 tmp) +{ + program_write8(EAD, tmp); +} + +inline void h6280_device::wb_eaz(UINT8 tmp) +{ + program_write8z(EAD, tmp); +} + +/*************************************************************** + * + * Macros to emulate the 6280 opcodes + * + ***************************************************************/ + +/*************************************************************** + * compose the real flag register by + * including N and Z and set any + * SET and clear any CLR bits also + ***************************************************************/ +#if LAZY_FLAGS + +inline void h6280_device::compose_p(UINT8 SET, UINT8 CLR) +{ + P = (P & ~(_fN | _fZ | CLR)) | + (NZ >> 8) | + ((NZ & 0xff) ? 0 : _fZ) | + SET; +} + +#else + +inline void h6280_device::compose_p(UINT8 SET, UINT8 CLR) +{ + P = (P & ~CLR) | SET; +} + +#endif + +/* 6280 ******************************************************** + * ADC Add with carry + ***************************************************************/ +inline void h6280_device::tadc(UINT8 tmp) +{ + clear_t(); + int tflagtemp = rd_tfl(); + if (P & _fD) + { + int c = (P & _fC); + int lo = (tflagtemp & 0x0f) + (tmp & 0x0f) + c; + int hi = (tflagtemp & 0xf0) + (tmp & 0xf0); + P &= ~_fC; + if (lo > 0x09) + { + hi += 0x10; + lo += 0x06; + } + if (hi > 0x90) + hi += 0x60; + if (hi & 0xff00) + P |= _fC; + tflagtemp = (lo & 0x0f) + (hi & 0xf0); + h6280_cycles(1); + } + else + { + int c = (P & _fC); + int sum = tflagtemp + tmp + c; + P &= ~(_fV | _fC); + if (~(tflagtemp^tmp) & (tflagtemp^sum) & _fN) + P |= _fV; + if (sum & 0xff00) + P |= _fC; + tflagtemp = (UINT8) sum; + } + set_nz(tflagtemp); + wb_eaz(tflagtemp); + h6280_cycles(3); +} + + +inline void h6280_device::adc(UINT8 tmp) +{ + if(P & _fT) + tadc(tmp); + else { + if (P & _fD) + { + int c = (P & _fC); + int lo = (A & 0x0f) + (tmp & 0x0f) + c; + int hi = (A & 0xf0) + (tmp & 0xf0); + P &= ~_fC; + if (lo > 0x09) + { + hi += 0x10; + lo += 0x06; + } + if (hi > 0x90) + hi += 0x60; + if (hi & 0xff00) + P |= _fC; + A = (lo & 0x0f) + (hi & 0xf0); + h6280_cycles(1); + } + else + { + int c = (P & _fC); + int sum = A + tmp + c; + P &= ~(_fV | _fC); + if (~(A^tmp) & (A^sum) & _fN) + P |= _fV; + if (sum & 0xff00) + P |= _fC; + A = (UINT8) sum; + } + set_nz(A); + } +} + +/* 6280 ******************************************************** + * AND Logical and + ***************************************************************/ +inline void h6280_device::tand(UINT8 tmp) +{ + clear_t(); + int tflagtemp = rd_tfl(); + tflagtemp = (UINT8)(tflagtemp & tmp); + wb_eaz(tflagtemp); + set_nz(tflagtemp); + h6280_cycles(3); +} + +inline void h6280_device::and_a(UINT8 tmp) +{ + if(P & _fT) + tand(tmp); + else { + A = (UINT8)(A & tmp); + set_nz(A); + } +} + +/* 6280 ******************************************************** + * ASL Arithmetic shift left + ***************************************************************/ +inline UINT8 h6280_device::asl(UINT8 tmp) +{ + clear_t(); + P = (P & ~_fC) | ((tmp >> 7) & _fC); + tmp = (UINT8)(tmp << 1); + set_nz(tmp); + return tmp; +} + +/* 6280 ******************************************************** + * BBR Branch if bit is reset + ***************************************************************/ +inline void h6280_device::bbr(int bit, UINT8 tmp) +{ + bra(!(tmp & (1<= tmp) + P |= _fC; + set_nz((UINT8)(A - tmp)); +} + +/* 6280 ******************************************************** + * CPX Compare index X + ***************************************************************/ +inline void h6280_device::cpx(UINT8 tmp) +{ + clear_t(); + P &= ~_fC; + if (X >= tmp) + P |= _fC; + set_nz((UINT8)(X - tmp)); +} + +/* 6280 ******************************************************** + * CPY Compare index Y + ***************************************************************/ +inline void h6280_device::cpy(UINT8 tmp) +{ + clear_t(); + P &= ~_fC; + if (Y >= tmp) + P |= _fC; + set_nz((UINT8)(Y - tmp)); +} + +/* 6280 ******************************************************** + * DEC Decrement memory + ***************************************************************/ +inline UINT8 h6280_device::dec(UINT8 tmp) +{ + clear_t(); + tmp = (UINT8)(tmp-1); + set_nz(tmp); + return tmp; +} + +/* 6280 ******************************************************** + * DEX Decrement index X + ***************************************************************/ +inline void h6280_device::dex() +{ + clear_t(); + X = (UINT8)(X - 1); + set_nz(X); +} + +/* 6280 ******************************************************** + * DEY Decrement index Y + ***************************************************************/ +inline void h6280_device::dey() +{ + clear_t(); + Y = (UINT8)(Y - 1); + set_nz(Y); +} + +/* 6280 ******************************************************** + * EOR Logical exclusive or + ***************************************************************/ +inline void h6280_device::teor(UINT8 tmp) +{ + clear_t(); + int tflagtemp = rd_tfl(); + tflagtemp = (UINT8)(tflagtemp ^ tmp); + wb_eaz(tflagtemp); + set_nz(tflagtemp); + h6280_cycles(3); +} + +inline void h6280_device::eor(UINT8 tmp) +{ + if(P & _fT) + teor(tmp); + else { + A = (UINT8)(A ^ tmp); + set_nz(A); + } +} + +/* 6280 ******************************************************** + * INC Increment memory + ***************************************************************/ +inline UINT8 h6280_device::inc(UINT8 tmp) +{ + clear_t(); + tmp = (UINT8)(tmp+1); + set_nz(tmp); + return tmp; +} + +/* 6280 ******************************************************** + * INX Increment index X + ***************************************************************/ +inline void h6280_device::inx() +{ + clear_t(); + X = (UINT8)(X + 1); + set_nz(X); +} + +/* 6280 ******************************************************** + * INY Increment index Y + ***************************************************************/ +inline void h6280_device::iny() +{ + clear_t(); + Y = (UINT8)(Y + 1); + set_nz(Y); +} + +/* 6280 ******************************************************** + * JMP Jump to address + * set PC to the effective address + ***************************************************************/ +inline void h6280_device::jmp() +{ + clear_t(); + PCD = EAD; +} + +/* 6280 ******************************************************** + * JSR Jump to subroutine + * decrement PC (sic!) push PC hi, push PC lo and set + * PC to the effective address + ***************************************************************/ +inline void h6280_device::jsr() +{ + clear_t(); + PCW--; + push(PCH); + push(PCL); + PCD = EAD; +} + +/* 6280 ******************************************************** + * LDA Load accumulator + ***************************************************************/ +inline void h6280_device::lda(UINT8 tmp) +{ + clear_t(); + A = (UINT8)tmp; + set_nz(A); +} + +/* 6280 ******************************************************** + * LDX Load index X + ***************************************************************/ +inline void h6280_device::ldx(UINT8 tmp) +{ + clear_t(); + X = (UINT8)tmp; + set_nz(X); +} + +/* 6280 ******************************************************** + * LDY Load index Y + ***************************************************************/ +inline void h6280_device::ldy(UINT8 tmp) +{ + clear_t(); + Y = (UINT8)tmp; + set_nz(Y); +} + +/* 6280 ******************************************************** + * LSR Logic shift right + * 0 -> [7][6][5][4][3][2][1][0] -> C + ***************************************************************/ +inline UINT8 h6280_device::lsr(UINT8 tmp) +{ + clear_t(); + P = (P & ~_fC) | (tmp & _fC); + tmp = (UINT8)tmp >> 1; + set_nz(tmp); + return tmp; +} + +/* 6280 ******************************************************** + * NOP No operation + ***************************************************************/ +inline void h6280_device::nop() +{ + clear_t(); +} + +/* 6280 ******************************************************** + * ORA Logical inclusive or + ***************************************************************/ + +inline void h6280_device::tora(UINT8 tmp) +{ + clear_t(); + int tflagtemp = rd_tfl(); + tflagtemp = (UINT8)(tflagtemp | tmp); + wb_eaz(tflagtemp); + set_nz(tflagtemp); + h6280_cycles(3); +} + +inline void h6280_device::ora(UINT8 tmp) +{ + if(P & _fT) + tora(tmp); + else { + A = (UINT8)(A | tmp); + set_nz(A); + } +} + +/* 6280 ******************************************************** + * PHA Push accumulator + ***************************************************************/ +inline void h6280_device::pha() +{ + clear_t(); + push(A); +} + +/* 6280 ******************************************************** + * PHP Push processor status (flags) + ***************************************************************/ +inline void h6280_device::php() +{ + clear_t(); + compose_p(0,0); + push(P); +} + +/* 6280 ******************************************************** + * PHX Push index X + ***************************************************************/ +inline void h6280_device::phx() +{ + clear_t(); + push(X); +} + +/* 6280 ******************************************************** + * PHY Push index Y + ***************************************************************/ +inline void h6280_device::phy() +{ + clear_t(); + push(Y); +} + +/* 6280 ******************************************************** + * PLA Pull accumulator + ***************************************************************/ +inline void h6280_device::pla() +{ + clear_t(); + pull(A); + set_nz(A); +} + +/* 6280 ******************************************************** + * PLP Pull processor status (flags) + ***************************************************************/ +inline void h6280_device::plp() +{ +#if LAZY_FLAGS + pull(P); + P |= _fB; + NZ = ((P & _fN) << 8) | + ((P & _fZ) ^ _fZ); + check_irq_lines(); +#else + pull(P); + P |= _fB; + check_irq_lines(); +#endif +} + +/* 6280 ******************************************************** + * PLX Pull index X + ***************************************************************/ +inline void h6280_device::plx() +{ + clear_t(); + pull(X); + set_nz(X); +} + +/* 6280 ******************************************************** + * PLY Pull index Y + ***************************************************************/ +inline void h6280_device::ply() +{ + clear_t(); + pull(Y); + set_nz(Y); +} + +/* 6280 ******************************************************** + * RMB Reset memory bit + ***************************************************************/ +inline UINT8 h6280_device::rmb(int bit, UINT8 tmp) +{ + clear_t(); + tmp &= ~(1<> 8) & _fC); + tmp = (UINT8)tmp9; + set_nz(tmp); + return tmp; +} + +/* 6280 ******************************************************** + * ROR Rotate right + * C -> [7][6][5][4][3][2][1][0] -> new C + ***************************************************************/ +inline UINT8 h6280_device::ror(UINT8 tmp) +{ + clear_t(); + int tmp9 = tmp | (P & _fC) << 8; + P = (P & ~_fC) | (tmp & _fC); + tmp = (UINT8)(tmp9 >> 1); + set_nz(tmp); + return tmp; +} + +/* 6280 ******************************************************** + * RTI Return from interrupt + * pull flags, pull PC lo, pull PC hi and increment PC + ***************************************************************/ +inline void h6280_device::rti() +{ +#if LAZY_FLAGS + pull(P); + P |= _fB; + NZ = ((P & _fN) << 8) | + ((P & _fZ) ^ _fZ); + pull(PCL); + pull(PCH); + check_irq_lines(); +#else + pull(P); + P |= _fB; + pull(PCL); + pull(PCH); + check_irq_lines(); +#endif +} + +/* 6280 ******************************************************** + * RTS Return from subroutine + * pull PC lo, PC hi and increment PC + ***************************************************************/ +inline void h6280_device::rts() +{ + clear_t(); + pull(PCL); + pull(PCH); + PCW++; +} + +/* 6280 ******************************************************** + * SAX Swap accumulator and index X + ***************************************************************/ +inline void h6280_device::sax() +{ + clear_t(); + UINT8 tmp = X; + X = A; + A = tmp; +} + +/* 6280 ******************************************************** + * SAY Swap accumulator and index Y + ***************************************************************/ +inline void h6280_device::say() +{ + clear_t(); + UINT8 tmp = Y; + Y = A; + A = tmp; +} + +/* 6280 ******************************************************** + * SBC Subtract with carry + ***************************************************************/ +inline void h6280_device::tsbc(UINT8 tmp) +{ + clear_t(); + int tflagtemp = rd_tfl(); + if (P & _fD) + { + int c = (P & _fC) ^ _fC; + int sum = tflagtemp - tmp -c; + int lo = (tflagtemp & 0x0f) - (tmp & 0x0f) - c; + int hi = (tflagtemp & 0xf0) - (tmp & 0xf0); + P &= ~_fC; + if (lo & 0xf0) + lo -= 6; + if (lo & 0x80) + hi -= 0x10; + if (hi & 0x0f00) + hi -= 0x60; + if ((sum & 0xff00) == 0) + P |= _fC; + tflagtemp = (lo & 0x0f) + (hi & 0xf0); + h6280_cycles(1); + } + else + { + int c = (P & _fC) ^ _fC; + int sum = tflagtemp - tmp - c; + P &= ~(_fV | _fC); + if ((tflagtemp^tmp) & (tflagtemp^sum) & _fN) + P |= _fV; + if ((sum & 0xff00) == 0) + P |= _fC; + tflagtemp = (UINT8) sum; + } + set_nz(tflagtemp); + wb_eaz(tflagtemp); + h6280_cycles(3); +} + +inline void h6280_device::sbc(UINT8 tmp) +{ + if(P & _fT) + tsbc(tmp); + else { + if (P & _fD) + { + int c = (P & _fC) ^ _fC; + int sum = A - tmp - c; + int lo = (A & 0x0f) - (tmp & 0x0f) - c; + int hi = (A & 0xf0) - (tmp & 0xf0); + P &= ~_fC; + if (lo & 0xf0) + lo -= 6; + if (lo & 0x80) + hi -= 0x10; + if (hi & 0x0f00) + hi -= 0x60; + if ((sum & 0xff00) == 0) + P |= _fC; + A = (lo & 0x0f) + (hi & 0xf0); + h6280_cycles(1); + } + else + { + int c = (P & _fC) ^ _fC; + int sum = A - tmp - c; + P &= ~(_fV | _fC); + if ((A^tmp) & (A^sum) & _fN) + P |= _fV; + if ((sum & 0xff00) == 0) + P |= _fC; + A = (UINT8) sum; + } + set_nz(A); + } +} + +/* 6280 ******************************************************** + * SEC Set carry flag + ***************************************************************/ +inline void h6280_device::sec() +{ + clear_t(); + P |= _fC; +} + +/* 6280 ******************************************************** + * SED Set decimal flag + ***************************************************************/ +inline void h6280_device::sed() +{ + clear_t(); + P |= _fD; +} + +/* 6280 ******************************************************** + * SEI Set interrupt flag + ***************************************************************/ +inline void h6280_device::sei() +{ + clear_t(); + P |= _fI; +} + +/* 6280 ******************************************************** + * SET Set t flag + ***************************************************************/ +inline void h6280_device::set() +{ + P |= _fT; +} + +/* 6280 ******************************************************** + * SMB Set memory bit + ***************************************************************/ +inline UINT8 h6280_device::smb(int bit, UINT8 tmp) +{ + clear_t(); + tmp |= (1<write_byte(0x0000,tmp); +} + +/* 6280 ******************************************************** + * ST1 Store at hardware address 2 + ***************************************************************/ +inline void h6280_device::st1(UINT8 tmp) +{ + clear_t(); + m_io->write_byte(0x0002,tmp); +} + +/* 6280 ******************************************************** + * ST2 Store at hardware address 3 + ***************************************************************/ +inline void h6280_device::st2(UINT8 tmp) +{ + clear_t(); + m_io->write_byte(0x0003,tmp); +} + +/* 6280 ******************************************************** + * STA Store accumulator + ***************************************************************/ +inline UINT8 h6280_device::sta() +{ + clear_t(); + return A; +} + +/* 6280 ******************************************************** + * STX Store index X + ***************************************************************/ +inline UINT8 h6280_device::stx() +{ + clear_t(); + return X; +} + +/* 6280 ******************************************************** + * STY Store index Y + ***************************************************************/ +inline UINT8 h6280_device::sty() +{ + clear_t(); + return Y; +} + +/* 6280 ******************************************************** + * STZ Store zero + ***************************************************************/ +inline UINT8 h6280_device::stz() +{ + clear_t(); + return 0; +} + +/* H6280 ******************************************************* + * SXY Swap index X and index Y + ***************************************************************/ +inline void h6280_device::sxy() +{ + clear_t(); + UINT8 tmp = X; + X = Y; + Y = tmp; +} + +/* H6280 ******************************************************* + * TAI Transfer Alternate Increment + ***************************************************************/ +inline void h6280_device::tai() +{ + clear_t(); + int from = program_read16(PCW); + int to = program_read16(PCW + 2); + int length = program_read16(PCW + 4); + PCW += 6; + int alternate = 0; + if (!length) length = 0x10000; + h6280_cycles( ((6 * length) + 17) ); + while ((length--) != 0) + { + program_write8(to, program_read8(from + alternate)); + to++; + alternate ^= 1; + } +} + +/* H6280 ******************************************************* + * TAM Transfer accumulator to memory mapper register(s) + ***************************************************************/ +inline void h6280_device::tam(UINT8 tmp) +{ + clear_t(); + if (tmp&0x01) m_mmr[0] = A; + if (tmp&0x02) m_mmr[1] = A; + if (tmp&0x04) m_mmr[2] = A; + if (tmp&0x08) m_mmr[3] = A; + if (tmp&0x10) m_mmr[4] = A; + if (tmp&0x20) m_mmr[5] = A; + if (tmp&0x40) m_mmr[6] = A; + if (tmp&0x80) m_mmr[7] = A; +} + +/* 6280 ******************************************************** + * TAX Transfer accumulator to index X + ***************************************************************/ +inline void h6280_device::tax() +{ + clear_t(); + X = A; + set_nz(X); +} + +/* 6280 ******************************************************** + * TAY Transfer accumulator to index Y + ***************************************************************/ +inline void h6280_device::tay() +{ + clear_t(); + Y = A; + set_nz(Y); +} + +/* 6280 ******************************************************** + * TDD Transfer Decrement Decrement + ***************************************************************/ +inline void h6280_device::tdd() +{ + clear_t(); + int from = program_read16(PCW); + int to = program_read16(PCW + 2); + int length = program_read16(PCW + 4); + PCW+=6; + if (!length) length = 0x10000; + h6280_cycles( ((6 * length) + 17) ); + while ((length--) != 0) { + program_write8(to, program_read8(from)); + to--; + from--; + } +} + +/* 6280 ******************************************************** + * TIA Transfer Increment Alternate + ***************************************************************/ +inline void h6280_device::tia() +{ + clear_t(); + int from = program_read16(PCW); + int to = program_read16(PCW + 2); + int length = program_read16(PCW + 4); + PCW+=6; + int alternate=0; + if (!length) length = 0x10000; + h6280_cycles( ((6 * length) + 17) ); + while ((length--) != 0) { + program_write8(to + alternate, program_read8(from)); + from++; + alternate ^= 1; + } +} + +/* 6280 ******************************************************** + * TII Transfer Increment Increment + ***************************************************************/ +inline void h6280_device::tii() +{ + clear_t(); + int from = program_read16(PCW); + int to = program_read16(PCW + 2); + int length = program_read16(PCW + 4); + PCW += 6; + if (!length) length = 0x10000; + h6280_cycles( ((6 * length) + 17) ); + while ((length--) != 0) { + program_write8(to, program_read8(from)); + to++; + from++; + } +} + +/* 6280 ******************************************************** + * TIN Transfer block, source increments every loop + ***************************************************************/ +inline void h6280_device::tin() +{ + clear_t(); + int from = program_read16(PCW); + int to = program_read16(PCW + 2); + int length = program_read16(PCW + 4); + PCW+=6; + if (!length) length = 0x10000; + h6280_cycles( ((6 * length) + 17) ); + while ((length--) != 0) { + program_write8(to, program_read8(from)); + from++; + } +} + +/* 6280 ******************************************************** + * TMA Transfer memory mapper register(s) to accumulator + * the highest bit set in tmp is the one that counts + ***************************************************************/ +inline void h6280_device::tma(UINT8 tmp) +{ + clear_t(); + if (tmp&0x01) A = m_mmr[0]; + if (tmp&0x02) A = m_mmr[1]; + if (tmp&0x04) A = m_mmr[2]; + if (tmp&0x08) A = m_mmr[3]; + if (tmp&0x10) A = m_mmr[4]; + if (tmp&0x20) A = m_mmr[5]; + if (tmp&0x40) A = m_mmr[6]; + if (tmp&0x80) A = m_mmr[7]; +} + +/* 6280 ******************************************************** + * TRB Test and reset bits + ***************************************************************/ +inline UINT8 h6280_device::trb(UINT8 tmp) +{ + clear_t(); + P = (P & ~(_fN|_fV|_fT|_fZ)) + | ((tmp&0x80) ? _fN:0) + | ((tmp&0x40) ? _fV:0) + | ((tmp&~A) ? 0:_fZ); + tmp &= ~A; + return tmp; +} + +/* 6280 ******************************************************** + * TSB Test and set bits + ***************************************************************/ +inline UINT8 h6280_device::tsb(UINT8 tmp) +{ + clear_t(); + P = (P & ~(_fN|_fV|_fT|_fZ)) + | ((tmp&0x80) ? _fN:0) + | ((tmp&0x40) ? _fV:0) + | ((tmp|A) ? 0:_fZ); + tmp |= A; + return tmp; +} + +/* 6280 ******************************************************** + * TSX Transfer stack LSB to index X + ***************************************************************/ +inline void h6280_device::tsx() +{ + clear_t(); + X = S; + set_nz(X); +} + +/* 6280 ******************************************************** + * TST + ***************************************************************/ +inline void h6280_device::tst(UINT8 imm, UINT8 tmp) +{ + P = (P & ~(_fN|_fV|_fT|_fZ)) + | ((tmp&0x80) ? _fN:0) + | ((tmp&0x40) ? _fV:0) + | ((tmp&imm) ? 0:_fZ); +} + +/* 6280 ******************************************************** + * TXA Transfer index X to accumulator + ***************************************************************/ +inline void h6280_device::txa() +{ + clear_t(); + A = X; + set_nz(A); +} + +/* 6280 ******************************************************** + * TXS Transfer index X to stack LSB + * no flags changed (sic!) + ***************************************************************/ +inline void h6280_device::txs() +{ + clear_t(); + S = X; +} + +/* 6280 ******************************************************** + * TYA Transfer index Y to accumulator + ***************************************************************/ +inline void h6280_device::tya() +{ + clear_t(); + A = Y; + set_nz(A); +} + +/* 6280 ******************************************************** + * CSH Set CPU in high speed mode + ***************************************************************/ +inline void h6280_device::csh() +{ + m_clocks_per_cycle = 1; +} + +/* 6280 ******************************************************** + * CSL Set CPU in low speed mode + ***************************************************************/ +inline void h6280_device::csl() +{ + m_clocks_per_cycle = 4; +} + + +#define OP(prefix,opcode) void h6280_device::prefix##_##opcode() + +/***************************************************************************** + ***************************************************************************** + * + * Hu6280 opcodes + * + ***************************************************************************** + * op cycles opc ***********************/ +OP(op,00) { h6280_cycles(8); brk(); } // 8 BRK +OP(op,20) { h6280_cycles(7); ea_abs(); jsr(); } // 7 JSR ABS +OP(op,40) { h6280_cycles(7); rti(); } // 7 RTI +OP(op,60) { h6280_cycles(7); rts(); } // 7 RTS +OP(op,80) { bra(1); } // 4 BRA REL +OP(op,a0) { h6280_cycles(2); ldy(rd_imm()); } // 2 LDY IMM +OP(op,c0) { h6280_cycles(2); cpy(rd_imm()); } // 2 CPY IMM +OP(op,e0) { h6280_cycles(2); cpx(rd_imm()); } // 2 CPX IMM + +OP(op,10) { bpl(); } // 2/4 BPL REL +OP(op,30) { bmi(); } // 2/4 BMI REL +OP(op,50) { bvc(); } // 2/4 BVC REL +OP(op,70) { bvs(); } // 2/4 BVS REL +OP(op,90) { bcc(); } // 2/4 BCC REL +OP(op,b0) { bcs(); } // 2/4 BCS REL +OP(op,d0) { bne(); } // 2/4 BNE REL +OP(op,f0) { beq(); } // 2/4 BEQ REL + +OP(op,01) { h6280_cycles(7); ora(rd_idx()); } // 7 ORA IDX +OP(op,21) { h6280_cycles(7); and_a(rd_idx()); } // 7 AND IDX +OP(op,41) { h6280_cycles(7); eor(rd_idx()); } // 7 EOR IDX +OP(op,61) { h6280_cycles(7); adc(rd_idx()); } // 7 ADC IDX +OP(op,81) { h6280_cycles(7); wr_idx(sta()); } // 7 STA IDX +OP(op,a1) { h6280_cycles(7); lda(rd_idx()); } // 7 LDA IDX +OP(op,c1) { h6280_cycles(7); cmp(rd_idx()); } // 7 CMP IDX +OP(op,e1) { h6280_cycles(7); sbc(rd_idx()); } // 7 SBC IDX + +OP(op,11) { h6280_cycles(7); ora(rd_idy()); } // 7 ORA IDY +OP(op,31) { h6280_cycles(7); and_a(rd_idy()); } // 7 AND IDY +OP(op,51) { h6280_cycles(7); eor(rd_idy()); } // 7 EOR IDY +OP(op,71) { h6280_cycles(7); adc(rd_idy()); } // 7 ADC AZP +OP(op,91) { h6280_cycles(7); wr_idy(sta()); } // 7 STA IDY +OP(op,b1) { h6280_cycles(7); lda(rd_idy()); } // 7 LDA IDY +OP(op,d1) { h6280_cycles(7); cmp(rd_idy()); } // 7 CMP IDY +OP(op,f1) { h6280_cycles(7); sbc(rd_idy()); } // 7 SBC IDY + +OP(op,02) { h6280_cycles(3); sxy(); } // 3 SXY +OP(op,22) { h6280_cycles(3); sax(); } // 3 SAX +OP(op,42) { h6280_cycles(3); say(); } // 3 SAY +OP(op,62) { h6280_cycles(2); cla(); } // 2 CLA +OP(op,82) { h6280_cycles(2); clx(); } // 2 CLX +OP(op,a2) { h6280_cycles(2); ldx(rd_imm()); } // 2 LDX IMM +OP(op,c2) { h6280_cycles(2); cly(); } // 2 CLY +OP(op,e2) { h6280_cycles(2); nop(); } // 2 NOP + +OP(op,12) { h6280_cycles(7); ora(rd_zpi()); } // 7 ORA ZPI +OP(op,32) { h6280_cycles(7); and_a(rd_zpi()); } // 7 AND ZPI +OP(op,52) { h6280_cycles(7); eor(rd_zpi()); } // 7 EOR ZPI +OP(op,72) { h6280_cycles(7); adc(rd_zpi()); } // 7 ADC ZPI +OP(op,92) { h6280_cycles(7); wr_zpi(sta()); } // 7 STA ZPI +OP(op,b2) { h6280_cycles(7); lda(rd_zpi()); } // 7 LDA ZPI +OP(op,d2) { h6280_cycles(7); cmp(rd_zpi()); } // 7 CMP ZPI +OP(op,f2) { h6280_cycles(7); sbc(rd_zpi()); } // 7 SBC ZPI + +OP(op,03) { h6280_cycles(5); st0(rd_imm()); } // 4 + 1 penalty cycle ST0 IMM +OP(op,23) { h6280_cycles(5); st2(rd_imm()); } // 4 + 1 penalty cycle ST2 IMM +OP(op,43) { h6280_cycles(4); tma(rd_imm()); } // 4 TMA +OP(op,63) { h6280_cycles(4); nop(); } // 2 NOP +OP(op,83) { h6280_cycles(7); int imm = rd_imm(); tst(imm, rd_zpg()); } // 7 TST IMM,ZPG +OP(op,a3) { h6280_cycles(7); int imm = rd_imm(); tst(imm, rd_zpx()); } // 7 TST IMM,ZPX +OP(op,c3) { tdd(); } // 6*l+17 TDD XFER +OP(op,e3) { tia(); } // 6*l+17 TIA XFER + +OP(op,13) { h6280_cycles(5); st1(rd_imm()); } // 4 + 1 penalty cycle ST1 +OP(op,33) { h6280_cycles(2); nop(); } // 2 NOP +OP(op,53) { h6280_cycles(5); tam(rd_imm()); } // 5 TAM IMM +OP(op,73) { tii(); } // 6*l+17 TII XFER +OP(op,93) { h6280_cycles(8); int imm = rd_imm(); tst(imm, rd_abs()); } // 8 TST IMM,ABS +OP(op,b3) { h6280_cycles(8); int imm = rd_imm(); tst(imm, rd_abx()); } // 8 TST IMM,ABX +OP(op,d3) { tin(); } // 6*l+17 TIN XFER +OP(op,f3) { tai(); } // 6*l+17 TAI XFER + +OP(op,04) { h6280_cycles(6); wb_eaz(tsb(rd_zpg())); } // 6 TSB ZPG +OP(op,24) { h6280_cycles(4); bit(rd_zpg()); } // 4 BIT ZPG +OP(op,44) { bsr(); } // 8 BSR REL +OP(op,64) { h6280_cycles(4); wr_zpg(stz()); } // 4 STZ ZPG +OP(op,84) { h6280_cycles(4); wr_zpg(sty()); } // 4 STY ZPG +OP(op,a4) { h6280_cycles(4); ldy(rd_zpg()); } // 4 LDY ZPG +OP(op,c4) { h6280_cycles(4); cpy(rd_zpg()); } // 4 CPY ZPG +OP(op,e4) { h6280_cycles(4); cpx(rd_zpg()); } // 4 CPX ZPG + +OP(op,14) { h6280_cycles(6); wb_eaz(trb(rd_zpg())); } // 6 TRB ZPG +OP(op,34) { h6280_cycles(4); bit(rd_zpx()); } // 4 BIT ZPX +OP(op,54) { h6280_cycles(3); csl(); } // 3 CSL +OP(op,74) { h6280_cycles(4); wr_zpx(stz()); } // 4 STZ ZPX +OP(op,94) { h6280_cycles(4); wr_zpx(sty()); } // 4 STY ZPX +OP(op,b4) { h6280_cycles(4); ldy(rd_zpx()); } // 4 LDY ZPX +OP(op,d4) { h6280_cycles(3); csh(); } // 3 CSH +OP(op,f4) { h6280_cycles(2); set(); } // 2 SET + +OP(op,05) { h6280_cycles(4); ora(rd_zpg()); } // 4 ORA ZPG +OP(op,25) { h6280_cycles(4); and_a(rd_zpg()); } // 4 AND ZPG +OP(op,45) { h6280_cycles(4); eor(rd_zpg()); } // 4 EOR ZPG +OP(op,65) { h6280_cycles(4); adc(rd_zpg()); } // 4 ADC ZPG +OP(op,85) { h6280_cycles(4); wr_zpg(sta()); } // 4 STA ZPG +OP(op,a5) { h6280_cycles(4); lda(rd_zpg()); } // 4 LDA ZPG +OP(op,c5) { h6280_cycles(4); cmp(rd_zpg()); } // 4 CMP ZPG +OP(op,e5) { h6280_cycles(4); sbc(rd_zpg()); } // 4 SBC ZPG + +OP(op,15) { h6280_cycles(4); ora(rd_zpx()); } // 4 ORA ZPX +OP(op,35) { h6280_cycles(4); and_a(rd_zpx()); } // 4 AND ZPX +OP(op,55) { h6280_cycles(4); eor(rd_zpx()); } // 4 EOR ZPX +OP(op,75) { h6280_cycles(4); adc(rd_zpx()); } // 4 ADC ZPX +OP(op,95) { h6280_cycles(4); wr_zpx(sta()); } // 4 STA ZPX +OP(op,b5) { h6280_cycles(4); lda(rd_zpx()); } // 4 LDA ZPX +OP(op,d5) { h6280_cycles(4); cmp(rd_zpx()); } // 4 CMP ZPX +OP(op,f5) { h6280_cycles(4); sbc(rd_zpx()); } // 4 SBC ZPX + +OP(op,06) { h6280_cycles(6); wb_eaz(asl(rd_zpg())); } // 6 ASL ZPG +OP(op,26) { h6280_cycles(6); wb_eaz(rol(rd_zpg())); } // 6 ROL ZPG +OP(op,46) { h6280_cycles(6); wb_eaz(lsr(rd_zpg())); } // 6 LSR ZPG +OP(op,66) { h6280_cycles(6); wb_eaz(ror(rd_zpg())); } // 6 ROR ZPG +OP(op,86) { h6280_cycles(4); wr_zpg(stx()); } // 4 STX ZPG +OP(op,a6) { h6280_cycles(4); ldx(rd_zpg()); } // 4 LDX ZPG +OP(op,c6) { h6280_cycles(6); wb_eaz(dec(rd_zpg())); } // 6 DEC ZPG +OP(op,e6) { h6280_cycles(6); wb_eaz(inc(rd_zpg())); } // 6 INC ZPG + +OP(op,16) { h6280_cycles(6); wb_eaz(asl(rd_zpx())); } // 6 ASL ZPX +OP(op,36) { h6280_cycles(6); wb_eaz(rol(rd_zpx())); } // 6 ROL ZPX +OP(op,56) { h6280_cycles(6); wb_eaz(lsr(rd_zpx())); } // 6 LSR ZPX +OP(op,76) { h6280_cycles(6); wb_eaz(ror(rd_zpx())); } // 6 ROR ZPX +OP(op,96) { h6280_cycles(4); wr_zpy(stx()); } // 4 STX ZPY +OP(op,b6) { h6280_cycles(4); ldx(rd_zpy()); } // 4 LDX ZPY +OP(op,d6) { h6280_cycles(6); wb_eaz(dec(rd_zpx())); } // 6 DEC ZPX +OP(op,f6) { h6280_cycles(6); wb_eaz(inc(rd_zpx())); } // 6 INC ZPX + +OP(op,07) { h6280_cycles(7); wb_eaz(rmb(0, rd_zpg())); } // 7 RMB0 ZPG +OP(op,27) { h6280_cycles(7); wb_eaz(rmb(2, rd_zpg())); } // 7 RMB2 ZPG +OP(op,47) { h6280_cycles(7); wb_eaz(rmb(4, rd_zpg())); } // 7 RMB4 ZPG +OP(op,67) { h6280_cycles(7); wb_eaz(rmb(6, rd_zpg())); } // 7 RMB6 ZPG +OP(op,87) { h6280_cycles(7); wb_eaz(smb(0, rd_zpg())); } // 7 SMB0 ZPG +OP(op,a7) { h6280_cycles(7); wb_eaz(smb(2, rd_zpg())); } // 7 SMB2 ZPG +OP(op,c7) { h6280_cycles(7); wb_eaz(smb(4, rd_zpg())); } // 7 SMB4 ZPG +OP(op,e7) { h6280_cycles(7); wb_eaz(smb(6, rd_zpg())); } // 7 SMB6 ZPG + +OP(op,17) { h6280_cycles(7); wb_eaz(rmb(1, rd_zpg())); } // 7 RMB1 ZPG +OP(op,37) { h6280_cycles(7); wb_eaz(rmb(3, rd_zpg())); } // 7 RMB3 ZPG +OP(op,57) { h6280_cycles(7); wb_eaz(rmb(5, rd_zpg())); } // 7 RMB5 ZPG +OP(op,77) { h6280_cycles(7); wb_eaz(rmb(7, rd_zpg())); } // 7 RMB7 ZPG +OP(op,97) { h6280_cycles(7); wb_eaz(smb(1, rd_zpg())); } // 7 SMB1 ZPG +OP(op,b7) { h6280_cycles(7); wb_eaz(smb(3, rd_zpg())); } // 7 SMB3 ZPG +OP(op,d7) { h6280_cycles(7); wb_eaz(smb(5, rd_zpg())); } // 7 SMB5 ZPG +OP(op,f7) { h6280_cycles(7); wb_eaz(smb(7, rd_zpg())); } // 7 SMB7 ZPG + +OP(op,08) { h6280_cycles(3); php(); } // 3 PHP +OP(op,28) { h6280_cycles(4); plp(); } // 4 PLP +OP(op,48) { h6280_cycles(3); pha(); } // 3 PHA +OP(op,68) { h6280_cycles(4); pla(); } // 4 PLA +OP(op,88) { h6280_cycles(2); dey(); } // 2 DEY +OP(op,a8) { h6280_cycles(2); tay(); } // 2 TAY +OP(op,c8) { h6280_cycles(2); iny(); } // 2 INY +OP(op,e8) { h6280_cycles(2); inx(); } // 2 INX + +OP(op,18) { h6280_cycles(2); clc(); } // 2 CLC +OP(op,38) { h6280_cycles(2); sec(); } // 2 SEC +OP(op,58) { h6280_cycles(2); cli(); } // 2 CLI +OP(op,78) { h6280_cycles(2); sei(); } // 2 SEI +OP(op,98) { h6280_cycles(2); tya(); } // 2 TYA +OP(op,b8) { h6280_cycles(2); clv(); } // 2 CLV +OP(op,d8) { h6280_cycles(2); cld(); } // 2 CLD +OP(op,f8) { h6280_cycles(2); sed(); } // 2 SED + +OP(op,09) { h6280_cycles(2); ora(rd_imm()); } // 2 ORA IMM +OP(op,29) { h6280_cycles(2); and_a(rd_imm()); } // 2 AND IMM +OP(op,49) { h6280_cycles(2); eor(rd_imm()); } // 2 EOR IMM +OP(op,69) { h6280_cycles(2); adc(rd_imm()); } // 2 ADC IMM +OP(op,89) { h6280_cycles(2); bit(rd_imm()); } // 2 BIT IMM +OP(op,a9) { h6280_cycles(2); lda(rd_imm()); } // 2 LDA IMM +OP(op,c9) { h6280_cycles(2); cmp(rd_imm()); } // 2 CMP IMM +OP(op,e9) { h6280_cycles(2); sbc(rd_imm()); } // 2 SBC IMM + +OP(op,19) { h6280_cycles(5); ora(rd_aby()); } // 5 ORA ABY +OP(op,39) { h6280_cycles(5); and_a(rd_aby()); } // 5 AND ABY +OP(op,59) { h6280_cycles(5); eor(rd_aby()); } // 5 EOR ABY +OP(op,79) { h6280_cycles(5); adc(rd_aby()); } // 5 ADC ABY +OP(op,99) { h6280_cycles(5); wr_aby(sta()); } // 5 STA ABY +OP(op,b9) { h6280_cycles(5); lda(rd_aby()); } // 5 LDA ABY +OP(op,d9) { h6280_cycles(5); cmp(rd_aby()); } // 5 CMP ABY +OP(op,f9) { h6280_cycles(5); sbc(rd_aby()); } // 5 SBC ABY + +OP(op,0a) { h6280_cycles(2); A = asl(A); } // 2 ASL A +OP(op,2a) { h6280_cycles(2); A = rol(A); } // 2 ROL A +OP(op,4a) { h6280_cycles(2); A = lsr(A); } // 2 LSR A +OP(op,6a) { h6280_cycles(2); A = ror(A); } // 2 ROR A +OP(op,8a) { h6280_cycles(2); txa(); } // 2 TXA +OP(op,aa) { h6280_cycles(2); tax(); } // 2 TAX +OP(op,ca) { h6280_cycles(2); dex(); } // 2 DEX +OP(op,ea) { h6280_cycles(2); nop(); } // 2 NOP + +OP(op,1a) { h6280_cycles(2); A = inc(A); } // 2 INC A +OP(op,3a) { h6280_cycles(2); A = dec(A); } // 2 DEC A +OP(op,5a) { h6280_cycles(3); phy(); } // 3 PHY +OP(op,7a) { h6280_cycles(4); ply(); } // 4 PLY +OP(op,9a) { h6280_cycles(2); txs(); } // 2 TXS +OP(op,ba) { h6280_cycles(2); tsx(); } // 2 TSX +OP(op,da) { h6280_cycles(3); phx(); } // 3 PHX +OP(op,fa) { h6280_cycles(4); plx(); } // 4 PLX + +OP(op,0b) { h6280_cycles(2); nop(); } // 2 NOP +OP(op,2b) { h6280_cycles(2); nop(); } // 2 NOP +OP(op,4b) { h6280_cycles(2); nop(); } // 2 NOP +OP(op,6b) { h6280_cycles(2); nop(); } // 2 NOP +OP(op,8b) { h6280_cycles(2); nop(); } // 2 NOP +OP(op,ab) { h6280_cycles(2); nop(); } // 2 NOP +OP(op,cb) { h6280_cycles(2); nop(); } // 2 NOP +OP(op,eb) { h6280_cycles(2); nop(); } // 2 NOP + +OP(op,1b) { h6280_cycles(2); nop(); } // 2 NOP +OP(op,3b) { h6280_cycles(2); nop(); } // 2 NOP +OP(op,5b) { h6280_cycles(2); nop(); } // 2 NOP +OP(op,7b) { h6280_cycles(2); nop(); } // 2 NOP +OP(op,9b) { h6280_cycles(2); nop(); } // 2 NOP +OP(op,bb) { h6280_cycles(2); nop(); } // 2 NOP +OP(op,db) { h6280_cycles(2); nop(); } // 2 NOP +OP(op,fb) { h6280_cycles(2); nop(); } // 2 NOP + +OP(op,0c) { h6280_cycles(7); wb_ea(tsb(rd_abs())); } // 7 TSB ABS +OP(op,2c) { h6280_cycles(5); bit(rd_abs()); } // 5 BIT ABS +OP(op,4c) { h6280_cycles(4); ea_abs(); jmp(); } // 4 JMP ABS +OP(op,6c) { h6280_cycles(7); ea_ind(); jmp(); } // 7 JMP IND +OP(op,8c) { h6280_cycles(5); wr_abs(sty()); } // 5 STY ABS +OP(op,ac) { h6280_cycles(5); ldy(rd_abs()); } // 5 LDY ABS +OP(op,cc) { h6280_cycles(5); cpy(rd_abs()); } // 5 CPY ABS +OP(op,ec) { h6280_cycles(5); cpx(rd_abs()); } // 5 CPX ABS + +OP(op,1c) { h6280_cycles(7); wb_ea(trb(rd_abs())); } // 7 TRB ABS +OP(op,3c) { h6280_cycles(5); bit(rd_abx()); } // 5 BIT ABX +OP(op,5c) { h6280_cycles(2); nop(); } // 2 NOP +OP(op,7c) { h6280_cycles(7); ea_iax(); jmp(); } // 7 JMP IAX +OP(op,9c) { h6280_cycles(5); wr_abs(stz()); } // 5 STZ ABS +OP(op,bc) { h6280_cycles(5); ldy(rd_abx()); } // 5 LDY ABX +OP(op,dc) { h6280_cycles(2); nop(); } // 2 NOP +OP(op,fc) { h6280_cycles(2); nop(); } // 2 NOP + +OP(op,0d) { h6280_cycles(5); ora(rd_abs()); } // 5 ORA ABS +OP(op,2d) { h6280_cycles(5); and_a(rd_abs()); } // 5 AND ABS +OP(op,4d) { h6280_cycles(5); eor(rd_abs()); } // 5 EOR ABS +OP(op,6d) { h6280_cycles(5); adc(rd_abs()); } // 5 ADC ABS +OP(op,8d) { h6280_cycles(5); wr_abs(sta()); } // 5 STA ABS +OP(op,ad) { h6280_cycles(5); lda(rd_abs()); } // 5 LDA ABS +OP(op,cd) { h6280_cycles(5); cmp(rd_abs()); } // 5 CMP ABS +OP(op,ed) { h6280_cycles(5); sbc(rd_abs()); } // 5 SBC ABS + +OP(op,1d) { h6280_cycles(5); ora(rd_abx()); } // 5 ORA ABX +OP(op,3d) { h6280_cycles(5); and_a(rd_abx()); } // 5 AND ABX +OP(op,5d) { h6280_cycles(5); eor(rd_abx()); } // 5 EOR ABX +OP(op,7d) { h6280_cycles(5); adc(rd_abx()); } // 5 ADC ABX +OP(op,9d) { h6280_cycles(5); wr_abx(sta()); } // 5 STA ABX +OP(op,bd) { h6280_cycles(5); lda(rd_abx()); } // 5 LDA ABX +OP(op,dd) { h6280_cycles(5); cmp(rd_abx()); } // 5 CMP ABX +OP(op,fd) { h6280_cycles(5); sbc(rd_abx()); } // 5 SBC ABX + +OP(op,0e) { h6280_cycles(7); wb_ea(asl(rd_abs())); } // 7 ASL ABS +OP(op,2e) { h6280_cycles(7); wb_ea(rol(rd_abs())); } // 7 ROL ABS +OP(op,4e) { h6280_cycles(7); wb_ea(lsr(rd_abs())); } // 7 LSR ABS +OP(op,6e) { h6280_cycles(7); wb_ea(ror(rd_abs())); } // 7 ROR ABS +OP(op,8e) { h6280_cycles(5); wr_abs(stx()); } // 5 STX ABS +OP(op,ae) { h6280_cycles(5); ldx(rd_abs()); } // 5 LDX ABS +OP(op,ce) { h6280_cycles(7); wb_ea(dec(rd_abs())); } // 7 DEC ABS +OP(op,ee) { h6280_cycles(7); wb_ea(inc(rd_abs())); } // 7 INC ABS + +OP(op,1e) { h6280_cycles(7); wb_ea(asl(rd_abx())); } // 7 ASL ABX +OP(op,3e) { h6280_cycles(7); wb_ea(rol(rd_abx())); } // 7 ROL ABX +OP(op,5e) { h6280_cycles(7); wb_ea(lsr(rd_abx())); } // 7 LSR ABX +OP(op,7e) { h6280_cycles(7); wb_ea(ror(rd_abx())); } // 7 ROR ABX +OP(op,9e) { h6280_cycles(5); wr_abx(stz()); } // 5 STZ ABX +OP(op,be) { h6280_cycles(5); ldx(rd_aby()); } // 5 LDX ABY +OP(op,de) { h6280_cycles(7); wb_ea(dec(rd_abx())); } // 7 DEC ABX +OP(op,fe) { h6280_cycles(7); wb_ea(inc(rd_abx())); } // 7 INC ABX + +OP(op,0f) { h6280_cycles(4); bbr(0, rd_zpg()); } // 6/8 BBR0 ZPG,REL +OP(op,2f) { h6280_cycles(4); bbr(2, rd_zpg()); } // 6/8 BBR2 ZPG,REL +OP(op,4f) { h6280_cycles(4); bbr(4, rd_zpg()); } // 6/8 BBR4 ZPG,REL +OP(op,6f) { h6280_cycles(4); bbr(6, rd_zpg()); } // 6/8 BBR6 ZPG,REL +OP(op,8f) { h6280_cycles(4); bbs(0, rd_zpg()); } // 6/8 BBS0 ZPG,REL +OP(op,af) { h6280_cycles(4); bbs(2, rd_zpg()); } // 6/8 BBS2 ZPG,REL +OP(op,cf) { h6280_cycles(4); bbs(4, rd_zpg()); } // 6/8 BBS4 ZPG,REL +OP(op,ef) { h6280_cycles(4); bbs(6, rd_zpg()); } // 6/8 BBS6 ZPG,REL + +OP(op,1f) { h6280_cycles(4); bbr(1, rd_zpg()); } // 6/8 BBR1 ZPG,REL +OP(op,3f) { h6280_cycles(4); bbr(3, rd_zpg()); } // 6/8 BBR3 ZPG,REL +OP(op,5f) { h6280_cycles(4); bbr(5, rd_zpg()); } // 6/8 BBR5 ZPG,REL +OP(op,7f) { h6280_cycles(4); bbr(7, rd_zpg()); } // 6/8 BBR7 ZPG,REL +OP(op,9f) { h6280_cycles(4); bbs(1, rd_zpg()); } // 6/8 BBS1 ZPG,REL +OP(op,bf) { h6280_cycles(4); bbs(3, rd_zpg()); } // 6/8 BBS3 ZPG,REL +OP(op,df) { h6280_cycles(4); bbs(5, rd_zpg()); } // 6/8 BBS5 ZPG,REL +OP(op,ff) { h6280_cycles(4); bbs(7, rd_zpg()); } // 6/8 BBS7 ZPG,REL + +//------------------------------------------------- +// state_string_export - export state as a string +// for the debugger +//------------------------------------------------- + +void h6280_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + switch (entry.index()) + { + case STATE_GENFLAGS: + strprintf(str, "%c%c%c%c%c%c%c%c", + (m_p & 0x80) ? 'N':'.', + (m_p & 0x40) ? 'V':'.', + (m_p & 0x20) ? 'R':'.', + (m_p & 0x10) ? 'B':'.', + (m_p & 0x08) ? 'D':'.', + (m_p & 0x04) ? 'I':'.', + (m_p & 0x02) ? 'Z':'.', + (m_p & 0x01) ? 'C':'.'); + break; + } +} + + +//------------------------------------------------- +// disasm_min_opcode_bytes - return the length +// of the shortest instruction, in bytes +//------------------------------------------------- + +UINT32 h6280_device::disasm_min_opcode_bytes() const +{ + return 1; +} + + +//------------------------------------------------- +// disasm_max_opcode_bytes - return the length +// of the longest instruction, in bytes +//------------------------------------------------- + +UINT32 h6280_device::disasm_max_opcode_bytes() const +{ + return 7; +} + + +//------------------------------------------------- +// disasm_disassemble - call the disassembly +// helper function +//------------------------------------------------- + +offs_t h6280_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( h6280 ); + return CPU_DISASSEMBLE_NAME(h6280)(this, buffer, pc, oprom, opram, options); +} + + +//------------------------------------------------- +// execute_min_cycles - return minimum number of +// cycles it takes for one instruction to execute +//------------------------------------------------- + +UINT32 h6280_device::execute_min_cycles() const +{ + return 2; +} + + +//------------------------------------------------- +// execute_max_cycles - return maximum number of +// cycles it takes for one instruction to execute +//------------------------------------------------- + +UINT32 h6280_device::execute_max_cycles() const +{ + return 17 + 6*65536; +} + + +//------------------------------------------------- +// execute_input_lines - return the number of +// input/interrupt lines +//------------------------------------------------- + +UINT32 h6280_device::execute_input_lines() const +{ + return 4; +} + + +//------------------------------------------------- +// execute_set_input - act on a changed input/ +// interrupt line +//------------------------------------------------- + +void h6280_device::execute_set_input(int inputnum, int state) +{ + switch(inputnum) + { + case H6280_IRQ1_STATE: + case 0: + set_irq_line(0, state); + break; + case H6280_IRQ2_STATE: + case 1: + set_irq_line(1, state); + break; + case H6280_IRQT_STATE: + case 2: + set_irq_line(2, state); + break; + case H6280_NMI_STATE: + case INPUT_LINE_NMI: + set_irq_line(INPUT_LINE_NMI, state); + break; + } +} + +/*************************************************************** + * program_read8 read memory + ***************************************************************/ +UINT8 h6280_device::program_read8(offs_t addr) +{ + check_vdc_vce_penalty(addr); + return m_program->read_byte(translated(addr)); +} + +/*************************************************************** + * program_write8 write memory + ***************************************************************/ +void h6280_device::program_write8(offs_t addr, UINT8 data) +{ + check_vdc_vce_penalty(addr); + m_program->write_byte(translated(addr), data); +} + +/*************************************************************** + * program_read8z read memory - zero page + ***************************************************************/ +UINT8 h6280_device::program_read8z(offs_t addr) +{ + return m_program->read_byte((m_mmr[1] << 13) | (addr & 0x1fff)); +} + +/*************************************************************** + * program_write8z write memory - zero page + ***************************************************************/ +void h6280_device::program_write8z(offs_t addr, UINT8 data) +{ + m_program->write_byte((m_mmr[1] << 13) | (addr & 0x1fff), data); +} + +/*************************************************************** + * program_read16 read word from memory + ***************************************************************/ +UINT16 h6280_device::program_read16(offs_t addr) +{ + return m_program->read_byte(translated(addr)) | + (m_program->read_byte(translated(addr + 1)) << 8); +} + +/*************************************************************** + * program_read16z read a word from a zero page address + ***************************************************************/ +UINT16 h6280_device::program_read16z(offs_t addr) +{ + if ((addr & 0xff) == 0xff) + { + return m_program->read_byte((m_mmr[1] << 13) | (addr & 0x1fff)) | + (m_program->read_byte((m_mmr[1] << 13) | ((addr - 0xff) & 0x1fff)) << 8); + } + else + { + return m_program->read_byte((m_mmr[1] << 13) | (addr & 0x1fff)) | + (m_program->read_byte((m_mmr[1] << 13) | ((addr + 1) & 0x1fff)) << 8); + } +} + +/*************************************************************** + * push a register onto the stack + ***************************************************************/ +void h6280_device::push(UINT8 value) +{ + m_program->write_byte((m_mmr[1] << 13) | m_sp.d, value); + S--; +} + +/*************************************************************** + * pull a register from the stack + ***************************************************************/ +void h6280_device::pull(UINT8 &value) +{ + S++; + value = m_program->read_byte((m_mmr[1] << 13) | m_sp.d); +} + +/*************************************************************** + * read_opcode read an opcode + ***************************************************************/ +UINT8 h6280_device::read_opcode() +{ + return m_direct->read_byte(translated(PCW)); +} + +/*************************************************************** + * read_opcode_arg read an opcode argument + ***************************************************************/ +UINT8 h6280_device::read_opcode_arg() +{ + return m_direct->read_byte(translated(PCW)); +} + + +//------------------------------------------------- +// execute_run - execute a timeslice's worth of +// opcodes +//------------------------------------------------- + +void h6280_device::execute_run() +{ + int in; + + if (m_irq_pending == 2) + { + m_irq_pending--; + } + + /* Execute instructions */ + do + { + m_ppc = m_pc; + + debugger_instruction_hook(this, PCW); + + /* Execute 1 instruction */ + in = read_opcode(); + PCW++; + (this->*m_opcode[in])(); + + if (m_irq_pending) + { + if (m_irq_pending == 1) + { + if (!(P & _fI)) + { + m_irq_pending--; + check_and_take_irq_lines(); + } + } + else + { + m_irq_pending--; + } + } + + /* Check internal timer */ + if (m_timer_status) + { + if (m_timer_value<=0) + { + if (!m_irq_pending) + { + m_irq_pending = 1; + } + while (m_timer_value <= 0) + { + m_timer_value += m_timer_load; + } + set_irq_line(2, ASSERT_LINE); + } + } + } while (m_icount > 0); +} + + +//************************************************************************** +// IRQ HANDLING +//************************************************************************** + +void h6280_device::set_irq_line(int irqline, int state) +{ + if (irqline == INPUT_LINE_NMI) + { + if (state != ASSERT_LINE) + return; + m_nmi_state = state; + check_irq_lines(); + } + else if (irqline < 3) + { + /* If the state has not changed, just return */ + if (m_irq_state[irqline] == state) + return; + + m_irq_state[irqline] = state; + + check_irq_lines(); + } +} + + +//************************************************************************** +// REGISTER HANDLING +//************************************************************************** + +READ8_MEMBER( h6280_device::irq_status_r ) +{ + int status; + + switch (offset & 3) + { + default: + return m_io_buffer; + case 3: + { + status = 0; + if (m_irq_state[1] != CLEAR_LINE) + status |= 1; /* IRQ 2 */ + if (m_irq_state[0] != CLEAR_LINE) + status |= 2; /* IRQ 1 */ + if (m_irq_state[2] != CLEAR_LINE) + status |= 4; /* TIMER */ + return status | (m_io_buffer & (~H6280_IRQ_MASK)); + } + case 2: + return m_irq_mask | (m_io_buffer & (~H6280_IRQ_MASK)); + } +} + +WRITE8_MEMBER( h6280_device::irq_status_w ) +{ + m_io_buffer = data; + switch (offset & 3) + { + default: + m_io_buffer = data; + break; + + case 2: /* Write irq mask */ + m_irq_mask = data & 0x7; + check_irq_lines(); + break; + + case 3: /* Timer irq ack */ + set_irq_line(2, CLEAR_LINE); + break; + } +} + +READ8_MEMBER( h6280_device::timer_r ) +{ + /* only returns countdown */ + return ((m_timer_value >> 10) & 0x7F) | (m_io_buffer & 0x80); +} + +WRITE8_MEMBER( h6280_device::timer_w ) +{ + m_io_buffer = data; + switch (offset & 1) + { + case 0: /* Counter preload */ + m_timer_load = m_timer_value = ((data & 127) + 1) * 1024; + return; + + case 1: /* Counter enable */ + if (data & 1) + {/* stop -> start causes reload */ + if(m_timer_status == 0) + m_timer_value = m_timer_load; + } + m_timer_status = data & 1; + return; + } +} + +bool h6280_device::memory_translate(address_spacenum spacenum, int intention, offs_t &address) +{ + if (spacenum == AS_PROGRAM) + address = translated(address); + + return TRUE; +} + +UINT8 h6280_device::io_get_buffer() +{ + return m_io_buffer; +} + +void h6280_device::io_set_buffer(UINT8 data) +{ + m_io_buffer = data; +} diff --git a/src/devices/cpu/h6280/h6280.h b/src/devices/cpu/h6280/h6280.h new file mode 100644 index 00000000000..dccf221abf7 --- /dev/null +++ b/src/devices/cpu/h6280/h6280.h @@ -0,0 +1,377 @@ +// license:BSD-3-Clause +// copyright-holders:Bryan McPhail +/***************************************************************************** + + h6280.h Portable Hu6280 emulator interface + + Copyright Bryan McPhail, mish@tendril.co.uk + + This source code is based (with permission!) on the 6502 emulator by + Juergen Buchmueller. It is released as part of the Mame emulator project. + Let me know if you intend to use this code in any other project. + +******************************************************************************/ + +#pragma once + +#ifndef __H6280_H__ +#define __H6280_H__ + +#include "emu.h" + +#define LAZY_FLAGS 0 + +/*************************************************************************** + REGISTER ENUMERATION +***************************************************************************/ + +enum +{ + H6280_PC = 1, + H6280_S, + H6280_P, + H6280_A, + H6280_X, + H6280_Y, + H6280_IRQ_MASK, + H6280_TIMER_STATE, + H6280_NMI_STATE, + H6280_IRQ1_STATE, + H6280_IRQ2_STATE, + H6280_IRQT_STATE, + H6280_M1, + H6280_M2, + H6280_M3, + H6280_M4, + H6280_M5, + H6280_M6, + H6280_M7, + H6280_M8 +}; + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> h6280_device + +// Used by core CPU interface +class h6280_device : public cpu_device +{ +public: + // construction/destruction + h6280_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // public interfaces + void set_irq_line(int irqline, int state); + + DECLARE_READ8_MEMBER( irq_status_r ); + DECLARE_WRITE8_MEMBER( irq_status_w ); + + DECLARE_READ8_MEMBER( timer_r ); + DECLARE_WRITE8_MEMBER( timer_w ); + + /* functions for use by the PSG and joypad port only! */ + UINT8 io_get_buffer(); + void io_set_buffer(UINT8); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_stop(); + + // device_execute_interface overrides + virtual UINT32 execute_min_cycles() const; + virtual UINT32 execute_max_cycles() const; + virtual UINT32 execute_input_lines() const; + virtual void execute_run(); + virtual void execute_set_input(int inputnum, int state); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const { return (spacenum == AS_PROGRAM) ? &m_program_config : ( (spacenum == AS_IO) ? &m_io_config : NULL ); } + virtual bool memory_translate(address_spacenum spacenum, int intention, offs_t &address); + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const; + virtual UINT32 disasm_max_opcode_bytes() const; + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + + // device_state_interface overrides + virtual void state_string_export(const device_state_entry &entry, std::string &str); + + // opcode accessors + UINT8 program_read8(offs_t addr); + void program_write8(offs_t addr, UINT8 data); + UINT8 program_read8z(offs_t addr); + void program_write8z(offs_t addr, UINT8 data); + UINT16 program_read16(offs_t addr); + UINT16 program_read16z(offs_t addr); + void push(UINT8 value); + void pull(UINT8 &value); + UINT8 read_opcode(); + UINT8 read_opcode_arg(); + +#undef PROTOTYPES +#define PROTOTYPES(prefix) \ + void prefix##_00(); void prefix##_01(); void prefix##_02(); void prefix##_03(); \ + void prefix##_04(); void prefix##_05(); void prefix##_06(); void prefix##_07(); \ + void prefix##_08(); void prefix##_09(); void prefix##_0a(); void prefix##_0b(); \ + void prefix##_0c(); void prefix##_0d(); void prefix##_0e(); void prefix##_0f(); \ + void prefix##_10(); void prefix##_11(); void prefix##_12(); void prefix##_13(); \ + void prefix##_14(); void prefix##_15(); void prefix##_16(); void prefix##_17(); \ + void prefix##_18(); void prefix##_19(); void prefix##_1a(); void prefix##_1b(); \ + void prefix##_1c(); void prefix##_1d(); void prefix##_1e(); void prefix##_1f(); \ + void prefix##_20(); void prefix##_21(); void prefix##_22(); void prefix##_23(); \ + void prefix##_24(); void prefix##_25(); void prefix##_26(); void prefix##_27(); \ + void prefix##_28(); void prefix##_29(); void prefix##_2a(); void prefix##_2b(); \ + void prefix##_2c(); void prefix##_2d(); void prefix##_2e(); void prefix##_2f(); \ + void prefix##_30(); void prefix##_31(); void prefix##_32(); void prefix##_33(); \ + void prefix##_34(); void prefix##_35(); void prefix##_36(); void prefix##_37(); \ + void prefix##_38(); void prefix##_39(); void prefix##_3a(); void prefix##_3b(); \ + void prefix##_3c(); void prefix##_3d(); void prefix##_3e(); void prefix##_3f(); \ + void prefix##_40(); void prefix##_41(); void prefix##_42(); void prefix##_43(); \ + void prefix##_44(); void prefix##_45(); void prefix##_46(); void prefix##_47(); \ + void prefix##_48(); void prefix##_49(); void prefix##_4a(); void prefix##_4b(); \ + void prefix##_4c(); void prefix##_4d(); void prefix##_4e(); void prefix##_4f(); \ + void prefix##_50(); void prefix##_51(); void prefix##_52(); void prefix##_53(); \ + void prefix##_54(); void prefix##_55(); void prefix##_56(); void prefix##_57(); \ + void prefix##_58(); void prefix##_59(); void prefix##_5a(); void prefix##_5b(); \ + void prefix##_5c(); void prefix##_5d(); void prefix##_5e(); void prefix##_5f(); \ + void prefix##_60(); void prefix##_61(); void prefix##_62(); void prefix##_63(); \ + void prefix##_64(); void prefix##_65(); void prefix##_66(); void prefix##_67(); \ + void prefix##_68(); void prefix##_69(); void prefix##_6a(); void prefix##_6b(); \ + void prefix##_6c(); void prefix##_6d(); void prefix##_6e(); void prefix##_6f(); \ + void prefix##_70(); void prefix##_71(); void prefix##_72(); void prefix##_73(); \ + void prefix##_74(); void prefix##_75(); void prefix##_76(); void prefix##_77(); \ + void prefix##_78(); void prefix##_79(); void prefix##_7a(); void prefix##_7b(); \ + void prefix##_7c(); void prefix##_7d(); void prefix##_7e(); void prefix##_7f(); \ + void prefix##_80(); void prefix##_81(); void prefix##_82(); void prefix##_83(); \ + void prefix##_84(); void prefix##_85(); void prefix##_86(); void prefix##_87(); \ + void prefix##_88(); void prefix##_89(); void prefix##_8a(); void prefix##_8b(); \ + void prefix##_8c(); void prefix##_8d(); void prefix##_8e(); void prefix##_8f(); \ + void prefix##_90(); void prefix##_91(); void prefix##_92(); void prefix##_93(); \ + void prefix##_94(); void prefix##_95(); void prefix##_96(); void prefix##_97(); \ + void prefix##_98(); void prefix##_99(); void prefix##_9a(); void prefix##_9b(); \ + void prefix##_9c(); void prefix##_9d(); void prefix##_9e(); void prefix##_9f(); \ + void prefix##_a0(); void prefix##_a1(); void prefix##_a2(); void prefix##_a3(); \ + void prefix##_a4(); void prefix##_a5(); void prefix##_a6(); void prefix##_a7(); \ + void prefix##_a8(); void prefix##_a9(); void prefix##_aa(); void prefix##_ab(); \ + void prefix##_ac(); void prefix##_ad(); void prefix##_ae(); void prefix##_af(); \ + void prefix##_b0(); void prefix##_b1(); void prefix##_b2(); void prefix##_b3(); \ + void prefix##_b4(); void prefix##_b5(); void prefix##_b6(); void prefix##_b7(); \ + void prefix##_b8(); void prefix##_b9(); void prefix##_ba(); void prefix##_bb(); \ + void prefix##_bc(); void prefix##_bd(); void prefix##_be(); void prefix##_bf(); \ + void prefix##_c0(); void prefix##_c1(); void prefix##_c2(); void prefix##_c3(); \ + void prefix##_c4(); void prefix##_c5(); void prefix##_c6(); void prefix##_c7(); \ + void prefix##_c8(); void prefix##_c9(); void prefix##_ca(); void prefix##_cb(); \ + void prefix##_cc(); void prefix##_cd(); void prefix##_ce(); void prefix##_cf(); \ + void prefix##_d0(); void prefix##_d1(); void prefix##_d2(); void prefix##_d3(); \ + void prefix##_d4(); void prefix##_d5(); void prefix##_d6(); void prefix##_d7(); \ + void prefix##_d8(); void prefix##_d9(); void prefix##_da(); void prefix##_db(); \ + void prefix##_dc(); void prefix##_dd(); void prefix##_de(); void prefix##_df(); \ + void prefix##_e0(); void prefix##_e1(); void prefix##_e2(); void prefix##_e3(); \ + void prefix##_e4(); void prefix##_e5(); void prefix##_e6(); void prefix##_e7(); \ + void prefix##_e8(); void prefix##_e9(); void prefix##_ea(); void prefix##_eb(); \ + void prefix##_ec(); void prefix##_ed(); void prefix##_ee(); void prefix##_ef(); \ + void prefix##_f0(); void prefix##_f1(); void prefix##_f2(); void prefix##_f3(); \ + void prefix##_f4(); void prefix##_f5(); void prefix##_f6(); void prefix##_f7(); \ + void prefix##_f8(); void prefix##_f9(); void prefix##_fa(); void prefix##_fb(); \ + void prefix##_fc(); void prefix##_fd(); void prefix##_fe(); void prefix##_ff(); + + PROTOTYPES(op) + + UINT32 translated(UINT16 addr); + void h6280_cycles(int cyc); + void set_nz(UINT8 n); + void clear_t(); + void do_interrupt(UINT16 vector); + void check_and_take_irq_lines(); + void check_irq_lines(); + void check_vdc_vce_penalty(UINT16 addr); + void bra(bool cond); + void ea_zpg(); + void ea_tflg(); + void ea_zpx(); + void ea_zpy(); + void ea_abs(); + void ea_abx(); + void ea_aby(); + void ea_zpi(); + void ea_idx(); + void ea_idy(); + void ea_ind(); + void ea_iax(); + UINT8 rd_imm(); + UINT8 rd_zpg(); + UINT8 rd_zpx(); + UINT8 rd_zpy(); + UINT8 rd_abs(); + UINT8 rd_abx(); + UINT8 rd_aby(); + UINT8 rd_zpi(); + UINT8 rd_idx(); + UINT8 rd_idy(); + UINT8 rd_tfl(); + void wr_zpg(UINT8 tmp); + void wr_zpx(UINT8 tmp); + void wr_zpy(UINT8 tmp); + void wr_abs(UINT8 tmp); + void wr_abx(UINT8 tmp); + void wr_aby(UINT8 tmp); + void wr_zpi(UINT8 tmp); + void wr_idx(UINT8 tmp); + void wr_idy(UINT8 tmp); + void wb_ea(UINT8 tmp); + void wb_eaz(UINT8 tmp); + void compose_p(UINT8 set, UINT8 clr); + void tadc(UINT8 tmp); + void adc(UINT8 tmp); + void tand(UINT8 tmp); + void and_a(UINT8 tmp); + UINT8 asl(UINT8 tmp); + void bbr(int bit, UINT8 tmp); + void bbs(int bit, UINT8 tmp); + void bcc(); + void bcs(); + void beq(); + void bit(UINT8 tmp); + void bmi(); + void bne(); + void bpl(); + void brk(); + void bsr(); + void bvc(); + void bvs(); + void cla(); + void clc(); + void cld(); + void cli(); + void clv(); + void clx(); + void cly(); + void cmp(UINT8 tmp); + void cpx(UINT8 tmp); + void cpy(UINT8 tmp); + UINT8 dec(UINT8 tmp); + void dex(); + void dey(); + void teor(UINT8 tmp); + void eor(UINT8 tmp); + UINT8 inc(UINT8 tmp); + void inx(); + void iny(); + void jmp(); + void jsr(); + void lda(UINT8 tmp); + void ldx(UINT8 tmp); + void ldy(UINT8 tmp); + UINT8 lsr(UINT8 tmp); + void nop(); + void tora(UINT8 tmp); + void ora(UINT8 tmp); + void pha(); + void php(); + void phx(); + void phy(); + void pla(); + void plp(); + void plx(); + void ply(); + UINT8 rmb(int bit, UINT8 tmp); + UINT8 rol(UINT8 tmp); + UINT8 ror(UINT8 tmp); + void rti(); + void rts(); + void sax(); + void say(); + void tsbc(UINT8 tmp); + void sbc(UINT8 tmp); + void sec(); + void sed(); + void sei(); + void set(); + UINT8 smb(int bit, UINT8 tmp); + void st0(UINT8 tmp); + void st1(UINT8 tmp); + void st2(UINT8 tmp); + UINT8 sta(); + UINT8 stx(); + UINT8 sty(); + UINT8 stz(); + void sxy(); + void tai(); + void tam(UINT8 tmp); + void tax(); + void tay(); + void tdd(); + void tia(); + void tii(); + void tin(); + void tma(UINT8 tmp); + UINT8 trb(UINT8 tmp); + UINT8 tsb(UINT8 tmp); + void tsx(); + void tst(UINT8 imm, UINT8 tmp); + void txa(); + void txs(); + void tya(); + void csh(); + void csl(); + + enum + { + H6280_RESET_VEC = 0xfffe, + H6280_NMI_VEC = 0xfffc, + H6280_TIMER_VEC = 0xfffa, + H6280_IRQ1_VEC = 0xfff8, + H6280_IRQ2_VEC = 0xfff6 /* Aka BRK vector */ + }; + + // address spaces + const address_space_config m_program_config; + const address_space_config m_io_config; + + // CPU registers + PAIR m_ppc; /* previous program counter */ + PAIR m_pc; /* program counter */ + PAIR m_sp; /* stack pointer (always 100 - 1FF) */ + PAIR m_zp; /* zero page address */ + PAIR m_ea; /* effective address */ + UINT8 m_a; /* Accumulator */ + UINT8 m_x; /* X index register */ + UINT8 m_y; /* Y index register */ + UINT8 m_p; /* Processor status */ + UINT8 m_mmr[8]; /* Hu6280 memory mapper registers */ + UINT8 m_irq_mask; /* interrupt enable/disable */ + UINT8 m_timer_status; /* timer status */ + UINT8 m_timer_ack; /* timer acknowledge */ + UINT8 m_clocks_per_cycle; /* 4 = low speed mode, 1 = high speed mode */ + INT32 m_timer_value; /* timer interrupt */ + INT32 m_timer_load; /* reload value */ + UINT8 m_nmi_state; + UINT8 m_irq_state[3]; + UINT8 m_irq_pending; +#if LAZY_FLAGS + INT32 m_nz; /* last value (lazy N and Z flag) */ +#endif + UINT8 m_io_buffer; /* last value written to the PSG, timer, and interrupt pages */ + + // other internal states + int m_icount; + + // address spaces + address_space *m_program; + address_space *m_io; + direct_read_data *m_direct; + + typedef void (h6280_device::*ophandler)(); + + ophandler m_opcode[256]; + + static const ophandler s_opcodetable[256]; +}; + +extern const device_type H6280; + +#endif /* __H6280_H__ */ diff --git a/src/devices/cpu/h8/h8.c b/src/devices/cpu/h8/h8.c new file mode 100644 index 00000000000..9084c0b76fa --- /dev/null +++ b/src/devices/cpu/h8/h8.c @@ -0,0 +1,1523 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +/*************************************************************************** + + h8.h + + H8-300 base cpu emulation + + +***************************************************************************/ + +#include "emu.h" +#include "debugger.h" +#include "h8.h" + +h8_device::h8_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source, bool mode_a16, address_map_delegate map_delegate) : + cpu_device(mconfig, type, name, tag, owner, clock, shortname, source), + program_config("program", ENDIANNESS_BIG, 16, mode_a16 ? 16 : 24, 0, map_delegate), + io_config("io", ENDIANNESS_BIG, 16, 16, -1) +{ + supports_advanced = false; + mode_advanced = false; + has_exr = false; + mac_saturating = false; + has_trace = false; +} + +void h8_device::device_start() +{ + program = &space(AS_PROGRAM); + direct = &program->direct(); + io = &space(AS_IO); + + state_add(STATE_GENPC, "GENPC", NPC).noshow(); + state_add(STATE_GENPCBASE, "GENPCBASE", PPC).noshow(); + if(has_exr) + state_add(STATE_GENFLAGS, "GENFLAGS", CCR).formatstr("%11s").noshow(); + else + state_add(STATE_GENFLAGS, "GENFLAGS", CCR).formatstr("%8s").noshow(); + state_add(H8_PC, "PC", NPC); + state_add(H8_CCR, "CCR", CCR); + + if(has_exr) + state_add(H8_EXR, "EXR", EXR); + if(!supports_advanced) { + state_add(H8_R0, "R0", R[0]); + state_add(H8_R1, "R1", R[1]); + state_add(H8_R2, "R2", R[2]); + state_add(H8_R3, "R3", R[3]); + state_add(H8_R4, "R4", R[4]); + state_add(H8_R5, "R5", R[5]); + state_add(H8_R6, "R6", R[6]); + state_add(H8_R7, "R7", R[7]); + } else { + state_add(H8_R0, "R0", R[0]).noshow(); + state_add(H8_R1, "R1", R[1]).noshow(); + state_add(H8_R2, "R2", R[2]).noshow(); + state_add(H8_R3, "R3", R[3]).noshow(); + state_add(H8_R4, "R4", R[4]).noshow(); + state_add(H8_R5, "R5", R[5]).noshow(); + state_add(H8_R6, "R6", R[6]).noshow(); + state_add(H8_R7, "R7", R[7]).noshow(); + state_add(H8_E0, "E0", R[8]).noshow(); + state_add(H8_E1, "E1", R[9]).noshow(); + state_add(H8_E2, "E2", R[10]).noshow(); + state_add(H8_E3, "E3", R[11]).noshow(); + state_add(H8_E4, "E4", R[12]).noshow(); + state_add(H8_E5, "E5", R[13]).noshow(); + state_add(H8_E6, "E6", R[14]).noshow(); + state_add(H8_E7, "E7", R[15]).noshow(); + state_add(H8_R0, "ER0", TMPR).callimport().formatstr("%9s"); + state_add(H8_R1, "ER1", TMPR).callimport().formatstr("%9s"); + state_add(H8_R2, "ER2", TMPR).callimport().formatstr("%9s"); + state_add(H8_R3, "ER3", TMPR).callimport().formatstr("%9s"); + state_add(H8_R4, "ER4", TMPR).callimport().formatstr("%9s"); + state_add(H8_R5, "ER5", TMPR).callimport().formatstr("%9s"); + state_add(H8_R6, "ER6", TMPR).callimport().formatstr("%9s"); + state_add(H8_R7, "ER7", TMPR).callimport().formatstr("%9s"); + } + + save_item(NAME(PPC)); + save_item(NAME(NPC)); + save_item(NAME(PC)); + save_item(NAME(PIR)); + save_item(NAME(IR)); + save_item(NAME(R)); + save_item(NAME(EXR)); + save_item(NAME(CCR)); + save_item(NAME(TMP1)); + save_item(NAME(TMP2)); + save_item(NAME(inst_state)); + save_item(NAME(inst_substate)); + save_item(NAME(irq_vector)); + save_item(NAME(taken_irq_vector)); + save_item(NAME(irq_level)); + save_item(NAME(taken_irq_level)); + save_item(NAME(irq_nmi)); + + m_icountptr = &icount; + + PC = 0; + PPC = 0; + NPC = 0; + memset(IR, 0, sizeof(IR)); + memset(R, 0, sizeof(R)); + EXR = 0; + CCR = 0; + MAC = 0; + MACF = 0; + inst_state = STATE_RESET; + inst_substate = 0; +} + +void h8_device::device_reset() +{ + inst_state = STATE_RESET; + inst_substate = 0; + + irq_vector = 0; + irq_level = -1; + irq_nmi = false; + taken_irq_vector = 0; + taken_irq_level = -1; +} + + +UINT32 h8_device::execute_min_cycles() const +{ + return 1; +} + +UINT32 h8_device::execute_max_cycles() const +{ + return 1; +} + +UINT32 h8_device::execute_input_lines() const +{ + return 0; +} + +void h8_device::recompute_bcount(UINT64 event_time) +{ + if(!event_time || event_time >= total_cycles() + icount) { + bcount = 0; + return; + } + bcount = total_cycles() + icount - event_time; +} + +void h8_device::execute_run() +{ + internal_update(total_cycles()); + + if(inst_substate) + do_exec_partial(); + + while(icount > 0) { + while(icount > bcount) { + if(inst_state < 0x10000) { + PPC = NPC; + if(machine().debug_flags & DEBUG_FLAG_ENABLED) + debugger_instruction_hook(this, NPC); + } + do_exec_full(); + } + while(bcount && icount && icount <= bcount) + internal_update(total_cycles() + icount - bcount); + if(inst_substate) + do_exec_partial(); + } +} + +void h8_device::add_event(UINT64 &event_time, UINT64 new_event) +{ + if(!new_event) + return; + if(!event_time || event_time > new_event) + event_time = new_event; +} + +void h8_device::internal_update() +{ + internal_update(total_cycles()); +} + +const address_space_config *h8_device::memory_space_config(address_spacenum spacenum) const +{ + return + spacenum == AS_PROGRAM ? &program_config : + spacenum == AS_IO ? &io_config : NULL; +} + + +void h8_device::state_import(const device_state_entry &entry) +{ + switch(entry.index()) { + case H8_R0: + case H8_R1: + case H8_R2: + case H8_R3: + case H8_R4: + case H8_R5: + case H8_R6: + case H8_R7: { + int r = entry.index() - H8_R0; + R[r + 8] = TMPR >> 16; + R[r] = TMPR; + break; + } + } +} + +void h8_device::state_export(const device_state_entry &entry) +{ +} + +void h8_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + switch(entry.index()) { + case STATE_GENFLAGS: + if(has_exr) + strprintf(str, "%c%c %c%c%c%c%c%c%c%c", + (EXR & EXR_T) ? 'T' : '-', + '0' + (EXR & EXR_I), + (CCR & F_I) ? 'I' : '-', + (CCR & F_UI) ? 'u' : '-', + (CCR & F_H) ? 'H' : '-', + (CCR & F_U) ? 'U' : '-', + (CCR & F_N) ? 'N' : '-', + (CCR & F_Z) ? 'Z' : '-', + (CCR & F_V) ? 'V' : '-', + (CCR & F_C) ? 'C' : '-'); + else + strprintf(str, "%c%c%c%c%c%c%c%c", + (CCR & F_I) ? 'I' : '-', + (CCR & F_UI) ? 'u' : '-', + (CCR & F_H) ? 'H' : '-', + (CCR & F_U) ? 'U' : '-', + (CCR & F_N) ? 'N' : '-', + (CCR & F_Z) ? 'Z' : '-', + (CCR & F_V) ? 'V' : '-', + (CCR & F_C) ? 'C' : '-'); + break; + case H8_R0: + case H8_R1: + case H8_R2: + case H8_R3: + case H8_R4: + case H8_R5: + case H8_R6: + case H8_R7: { + int r = entry.index() - H8_R0; + strprintf(str, "%04x %04x", R[r + 8], R[r]); + break; + } + } +} + + +UINT32 h8_device::disasm_min_opcode_bytes() const +{ + return 2; +} + +UINT32 h8_device::disasm_max_opcode_bytes() const +{ + return 10; +} + +void h8_device::disassemble_am(char *&buffer, int am, offs_t pc, const UINT8 *oprom, UINT32 opcode, int offset) +{ + static const char *const r8_names[16] = { + "r0h", "r1h", "r2h", "r3h", "r4h", "r5h", "r6h", "r7h", + "r0l", "r1l", "r2l", "r3l", "r4l", "r5l", "r6l", "r7l" + }; + + static const char *const r16_names[16] = { + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", + "e0", "e1", "e2", "e3", "e4", "e5", "e6", "e7", + }; + + static const char *const r32_names[88] = { + "er0", "er1", "er2", "er3", "er4", "er5", "er6", "sp", + }; + + switch(am) { + case DASM_r8l: + buffer += sprintf(buffer, "%s", r8_names[opcode & 15]); + break; + + case DASM_r8h: + buffer += sprintf(buffer, "%s", r8_names[(opcode >> 4) & 15]); + break; + + case DASM_r8u: + buffer += sprintf(buffer, "%s", r8_names[(opcode >> 8) & 15]); + break; + + case DASM_r16l: + buffer += sprintf(buffer, "%s", r16_names[opcode & 15]); + break; + + case DASM_r16h: + buffer += sprintf(buffer, "%s", r16_names[(opcode >> 4) & 15]); + break; + + case DASM_r32l: + buffer += sprintf(buffer, "%s", r32_names[opcode & 7]); + break; + + case DASM_r32h: + buffer += sprintf(buffer, "%s", r32_names[(opcode >> 4) & 7]); + break; + + case DASM_r16ih: + buffer += sprintf(buffer, "@%s", r16_names[(opcode >> 4) & 7]); + break; + + case DASM_r16ihh: + buffer += sprintf(buffer, "@%s", r16_names[(opcode >> 20) & 7]); + break; + + case DASM_pr16h: + buffer += sprintf(buffer, "@-%s", r16_names[(opcode >> 4) & 7]); + break; + + case DASM_r16ph: + buffer += sprintf(buffer, "@%s+", r16_names[(opcode >> 4) & 7]); + break; + + case DASM_r16d16h: + buffer += sprintf(buffer, "@(%x, %s)", (oprom[offset-2] << 8) | oprom[offset-1], r16_names[(opcode >> 4) & 7]); + break; + + case DASM_r32ih: + buffer += sprintf(buffer, "@%s", r32_names[(opcode >> 4) & 7]); + break; + + case DASM_r32ihh: + buffer += sprintf(buffer, "@%s", r32_names[(opcode >> 20) & 7]); + break; + + case DASM_pr32h: + buffer += sprintf(buffer, "@-%s", r32_names[(opcode >> 4) & 7]); + break; + + case DASM_r32pl: + buffer += sprintf(buffer, "@%s+", r32_names[opcode & 7]); + break; + + case DASM_r32ph: + buffer += sprintf(buffer, "@%s+", r32_names[(opcode >> 4) & 7]); + break; + + case DASM_r32d16h: + buffer += sprintf(buffer, "@(%x, %s)", (oprom[offset-2] << 8) | oprom[offset-1], r32_names[(opcode >> 4) & 7]); + break; + + case DASM_r32d32hh: + buffer += sprintf(buffer, "@(%x, %s)", (oprom[offset-4] << 24) | (oprom[offset-3] << 16) | (oprom[offset-2] << 8) | oprom[offset-1], r32_names[(opcode >> 20) & 7]); + break; + + case DASM_psp: + buffer += sprintf(buffer, "@-sp"); + break; + + case DASM_spp: + buffer += sprintf(buffer, "@sp+"); + break; + + case DASM_r32n2l: + buffer += sprintf(buffer, "%s-%s", r32_names[opcode & 6], r32_names[(opcode & 6) + 1]); + break; + + case DASM_r32n3l: + buffer += sprintf(buffer, "%s-%s", r32_names[opcode & 4], r32_names[(opcode & 4) + 2]); + break; + + case DASM_r32n4l: + buffer += sprintf(buffer, "%s-%s", r32_names[opcode & 4], r32_names[(opcode & 4) + 3]); + break; + + case DASM_abs8: + buffer += sprintf(buffer, "@%08x", 0xffffff00 | oprom[1]); + break; + + case DASM_abs16: + if(offset >= 6) + buffer += sprintf(buffer, "@%08x", INT16((oprom[offset-4] << 8) | oprom[offset-3])); + else + buffer += sprintf(buffer, "@%08x", INT16((oprom[offset-2] << 8) | oprom[offset-1])); + break; + + case DASM_abs32: + if(offset >= 8) + buffer += sprintf(buffer, "@%08x", (oprom[offset-6] << 24) | (oprom[offset-5] << 16) | (oprom[offset-4] << 8) | oprom[offset-3]); + else + buffer += sprintf(buffer, "@%08x", (oprom[offset-4] << 24) | (oprom[offset-3] << 16) | (oprom[offset-2] << 8) | oprom[offset-1]); + break; + + case DASM_abs8i: + buffer += sprintf(buffer, "@%02x", oprom[1]); + break; + + case DASM_abs16e: + buffer += sprintf(buffer, "%04x", (oprom[2] << 8) | oprom[3]); + break; + + case DASM_abs24e: + buffer += sprintf(buffer, "%08x", (oprom[1] << 16) | (oprom[2] << 8) | oprom[3]); + break; + + case DASM_rel8: + buffer += sprintf(buffer, "%08x", pc + 2 + INT8(oprom[1])); + break; + + case DASM_rel16: + buffer += sprintf(buffer, "%08x", pc + 4 + INT16((oprom[2] << 8) | oprom[3])); + break; + + case DASM_one: + buffer += sprintf(buffer, "#1"); + break; + + case DASM_two: + buffer += sprintf(buffer, "#2"); + break; + + case DASM_four: + buffer += sprintf(buffer, "#4"); + break; + + case DASM_imm2: + buffer += sprintf(buffer, "#%x", (opcode >> 4) & 3); + break; + + case DASM_imm3: + buffer += sprintf(buffer, "#%x", (opcode >> 4) & 7); + break; + + case DASM_imm8: + buffer += sprintf(buffer, "#%02x", oprom[1]); + break; + + case DASM_imm16: + buffer += sprintf(buffer, "#%04x", (oprom[2] << 8) | oprom[3]); + break; + + case DASM_imm32: + buffer += sprintf(buffer, "#%08x", (oprom[2] << 16) | (oprom[3] << 16) | (oprom[4] << 8) | oprom[5]); + break; + + case DASM_ccr: + buffer += sprintf(buffer, "ccr"); + break; + + case DASM_exr: + buffer += sprintf(buffer, "exr"); + break; + + case DASM_macl: + buffer += sprintf(buffer, "macl"); + break; + + case DASM_mach: + buffer += sprintf(buffer, "mach"); + break; + + default: + buffer += sprintf(buffer, "<%d>", am); + break; + } +} + +offs_t h8_device::disassemble_generic(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options, const disasm_entry *table) +{ + UINT32 slot[5]; + slot[0] = (oprom[0] << 8) | oprom[1]; + slot[1] = (oprom[0] << 24) | (oprom[1] << 16) | (oprom[2] << 8) | oprom[3]; + slot[2] = (oprom[0] << 24) | (oprom[1] << 16) | (oprom[4] << 8) | oprom[5]; + slot[3] = (oprom[0] << 24) | (oprom[1] << 16) | (oprom[6] << 8) | oprom[7]; + slot[4] = (oprom[2] << 24) | (oprom[3] << 16) | (oprom[4] << 8) | oprom[5]; + + int inst; + for(inst=0;; inst++) { + const disasm_entry &e = table[inst]; + if((slot[e.slot] & e.mask) == e.val && (slot[0] & e.mask0) == e.val0) + break; + } + const disasm_entry &e = table[inst]; + buffer += sprintf(buffer, "%s", e.opcode); + + if(e.am1 != DASM_none) { + *buffer++ = ' '; + disassemble_am(buffer, e.am1, pc, oprom, slot[e.slot], e.flags & DASMFLAG_LENGTHMASK); + } + if(e.am2 != DASM_none) { + *buffer++ = ','; + *buffer++ = ' '; + disassemble_am(buffer, e.am2, pc, oprom, slot[e.slot], e.flags & DASMFLAG_LENGTHMASK); + } + return e.flags | DASMFLAG_SUPPORTED; +} + +offs_t h8_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + return disassemble_generic(buffer, pc, oprom, opram, options, disasm_entries); +} + +UINT16 h8_device::read16i(UINT32 adr) +{ + icount--; + return direct->read_word(adr & ~1); +} + +UINT16 h8_device::fetch() +{ + UINT16 res = read16i(PC); + PC += 2; + return res; +} + +UINT8 h8_device::read8(UINT32 adr) +{ + icount--; + return program->read_byte(adr); +} + +void h8_device::write8(UINT32 adr, UINT8 data) +{ + // logerror("W %06x %02x\n", adr & 0xffffff, data); + icount--; + program->write_byte(adr, data); +} + +UINT16 h8_device::read16(UINT32 adr) +{ + icount--; + return program->read_word(adr & ~1); +} + +void h8_device::write16(UINT32 adr, UINT16 data) +{ + // logerror("W %06x %04x\n", adr & 0xfffffe, data); + icount--; + program->write_word(adr & ~1, data); +} + +bool h8_device::exr_in_stack() const +{ + return false; +} + +void h8_device::prefetch_done() +{ + if(irq_vector) { + inst_state = STATE_IRQ; + taken_irq_vector = irq_vector; + taken_irq_level = irq_level; + } else if(has_trace && (EXR & EXR_T) && exr_in_stack()) + inst_state = STATE_TRACE; + else + inst_state = IR[0] = PIR; +} + +void h8_device::prefetch_done_noirq() +{ + if(has_trace && (EXR & EXR_T) && exr_in_stack()) + inst_state = STATE_TRACE; + else + inst_state = IR[0] = PIR; +} + +void h8_device::prefetch_done_noirq_notrace() +{ + inst_state = IR[0] = PIR; +} + +void h8_device::set_irq(int _irq_vector, int _irq_level, bool _irq_nmi) +{ + irq_vector = _irq_vector; + irq_level = _irq_level; + irq_nmi = _irq_nmi; +} + +void h8_device::internal(int cycles) +{ + icount -= cycles; +} + +void h8_device::illegal() +{ + throw emu_fatalerror("%s: Illegal instruction at address %x\n", tag(), PPC); +} + +int h8_device::trace_setup() +{ + throw emu_fatalerror("%s: Trace setup called but unimplemented.\n", tag()); +} + +int h8_device::trapa_setup() +{ + throw emu_fatalerror("%s: Trapa setup called but unimplemented.\n", tag()); +} + +UINT8 h8_device::do_addx8(UINT8 v1, UINT8 v2) +{ + UINT16 res = v1 + v2 + (CCR & F_C ? 1 : 0); + CCR &= ~(F_N|F_V|F_Z|F_C|F_H); + if(((v1 & 0xf) + (v2 & 0xf) + (CCR & F_C ? 1 : 0)) & 0x10) + CCR |= F_H; + if(!UINT8(res)) + CCR |= F_Z; + else if(INT8(res) < 0) + CCR |= F_N; + if(~(v1^v2) & (v1^res) & 0x80) + CCR |= F_V; + if(res & 0x100) + CCR |= F_C; + return res; + +} + +UINT8 h8_device::do_subx8(UINT8 v1, UINT8 v2) +{ + UINT16 res = v1 - v2 - (CCR & F_C ? 1 : 0); + CCR &= ~(F_N|F_V|F_Z|F_C|F_H); + if(((v1 & 0xf) - (v2 & 0xf) - (CCR & F_C ? 1 : 0)) & 0x10) + CCR |= F_H; + if(!UINT8(res)) + CCR |= F_Z; + else if(INT8(res) < 0) + CCR |= F_N; + if((v1^v2) & (v1^res) & 0x80) + CCR |= F_V; + if(res & 0x100) + CCR |= F_C; + return res; + +} + +UINT8 h8_device::do_inc8(UINT8 v1, UINT8 v2) +{ + UINT8 res = v1 + v2; + CCR &= ~(F_N|F_V|F_Z); + if(!res) + CCR |= F_Z; + else if(INT8(res) < 0) + CCR |= F_N; + if((v1^v2) & (v1^res) & 0x80) + CCR |= F_V; + return res; +} + +UINT16 h8_device::do_inc16(UINT16 v1, UINT16 v2) +{ + UINT16 res = v1 + v2; + CCR &= ~(F_N|F_V|F_Z); + if(!res) + CCR |= F_Z; + else if(INT16(res) < 0) + CCR |= F_N; + if((v1^v2) & (v1^res) & 0x8000) + CCR |= F_V; + return res; +} + +UINT32 h8_device::do_inc32(UINT32 v1, UINT32 v2) +{ + UINT32 res = v1 + v2; + CCR &= ~(F_N|F_V|F_Z); + if(!res) + CCR |= F_Z; + else if(INT32(res) < 0) + CCR |= F_N; + if((v1^v2) & (v1^res) & 0x80000000) + CCR |= F_V; + return res; +} + +UINT8 h8_device::do_add8(UINT8 v1, UINT8 v2) +{ + UINT16 res = v1 + v2; + CCR &= ~(F_N|F_V|F_Z|F_C|F_H); + if(((v1 & 0xf) + (v2 & 0xf)) & 0x10) + CCR |= F_H; + if(!UINT8(res)) + CCR |= F_Z; + else if(INT8(res) < 0) + CCR |= F_N; + if(~(v1^v2) & (v1^res) & 0x80) + CCR |= F_V; + if(res & 0x100) + CCR |= F_C; + return res; + +} + +UINT16 h8_device::do_add16(UINT16 v1, UINT16 v2) +{ + UINT32 res = v1 + v2; + CCR &= ~(F_N|F_V|F_Z|F_C|F_H); + if(((v1 & 0xfff) + (v2 & 0xffff)) & 0x1000) + CCR |= F_H; + if(!UINT16(res)) + CCR |= F_Z; + else if(INT16(res) < 0) + CCR |= F_N; + if(~(v1^v2) & (v1^res) & 0x8000) + CCR |= F_V; + if(res & 0x10000) + CCR |= F_C; + return res; + +} + +UINT32 h8_device::do_add32(UINT32 v1, UINT32 v2) +{ + UINT64 res = UINT64(v1) + UINT64(v2); + CCR &= ~(F_N|F_V|F_Z|F_C|F_H); + if(((v1 & 0xfffffff) + (v2 & 0xfffffff)) & 0x10000000) + CCR |= F_H; + if(!UINT32(res)) + CCR |= F_Z; + else if(INT32(res) < 0) + CCR |= F_N; + if(~(v1^v2) & (v1^res) & 0x80000000) + CCR |= F_V; + if(res & U64(0x100000000)) + CCR |= F_C; + return res; +} + +UINT8 h8_device::do_dec8(UINT8 v1, UINT8 v2) +{ + UINT8 res = v1 - v2; + CCR &= ~(F_N|F_V|F_Z); + if(!res) + CCR |= F_Z; + else if(INT8(res) < 0) + CCR |= F_N; + if((v1^v2) & (v1^res) & 0x80) + CCR |= F_V; + return res; +} + +UINT16 h8_device::do_dec16(UINT16 v1, UINT16 v2) +{ + UINT16 res = v1 - v2; + CCR &= ~(F_N|F_V|F_Z); + if(!res) + CCR |= F_Z; + else if(INT16(res) < 0) + CCR |= F_N; + if((v1^v2) & (v1^res) & 0x8000) + CCR |= F_V; + return res; +} + +UINT32 h8_device::do_dec32(UINT32 v1, UINT32 v2) +{ + UINT32 res = v1 - v2; + CCR &= ~(F_N|F_V|F_Z); + if(!res) + CCR |= F_Z; + else if(INT32(res) < 0) + CCR |= F_N; + if((v1^v2) & (v1^res) & 0x80000000) + CCR |= F_V; + return res; +} + +UINT8 h8_device::do_sub8(UINT8 v1, UINT8 v2) +{ + UINT16 res = v1 - v2; + CCR &= ~(F_N|F_V|F_Z|F_C|F_H); + if(((v1 & 0xf) - (v2 & 0xf)) & 0x10) + CCR |= F_H; + if(!UINT8(res)) + CCR |= F_Z; + else if(INT8(res) < 0) + CCR |= F_N; + if((v1^v2) & (v1^res) & 0x80) + CCR |= F_V; + if(res & 0x100) + CCR |= F_C; + return res; + +} + +UINT16 h8_device::do_sub16(UINT16 v1, UINT16 v2) +{ + UINT32 res = v1 - v2; + CCR &= ~(F_N|F_V|F_Z|F_C|F_H); + if(((v1 & 0xfff) - (v2 & 0xffff)) & 0x1000) + CCR |= F_H; + if(!UINT16(res)) + CCR |= F_Z; + else if(INT16(res) < 0) + CCR |= F_N; + if((v1^v2) & (v1^res) & 0x8000) + CCR |= F_V; + if(res & 0x10000) + CCR |= F_C; + return res; + +} + +UINT32 h8_device::do_sub32(UINT32 v1, UINT32 v2) +{ + UINT64 res = UINT64(v1) - UINT64(v2); + CCR &= ~(F_N|F_V|F_Z|F_C|F_H); + if(((v1 & 0xfffffff) - (v2 & 0xfffffff)) & 0x10000000) + CCR |= F_H; + if(!UINT32(res)) + CCR |= F_Z; + else if(INT32(res) < 0) + CCR |= F_N; + if((v1^v2) & (v1^res) & 0x80000000) + CCR |= F_V; + if(res & U64(0x100000000)) + CCR |= F_C; + return res; +} + +UINT8 h8_device::do_shal8(UINT8 v) +{ + CCR &= ~(F_N|F_V|F_Z|F_C); + if(v & 0x80) + CCR |= F_C; + if((v & 0xc0) == 0x40 || (v & 0xc0) == 0x80) + CCR |= F_V; + v <<= 1; + if(!v) + CCR |= F_Z; + else if(INT8(v) < 0) + CCR |= F_N; + return v; +} + +UINT16 h8_device::do_shal16(UINT16 v) +{ + CCR &= ~(F_N|F_V|F_Z|F_C); + if(v & 0x8000) + CCR |= F_C; + if((v & 0xc000) == 0x4000 || (v & 0xc000) == 0x8000) + CCR |= F_V; + v <<= 1; + if(!v) + CCR |= F_Z; + else if(INT16(v) < 0) + CCR |= F_N; + return v; +} + +UINT32 h8_device::do_shal32(UINT32 v) +{ + CCR &= ~(F_N|F_V|F_Z|F_C); + if(v & 0x80000000) + CCR |= F_C; + if((v & 0xc0000000) == 0x40000000 || (v & 0xc0000000) == 0x80000000) + CCR |= F_V; + v <<= 1; + if(!v) + CCR |= F_Z; + else if(INT32(v) < 0) + CCR |= F_N; + return v; +} + +UINT8 h8_device::do_shar8(UINT8 v) +{ + CCR &= ~(F_N|F_V|F_Z|F_C); + if(v & 1) + CCR |= F_C; + v >>= 1; + if(!v) + CCR |= F_Z; + else if (v & 0x40) { + v |= 0x80; + CCR |= F_N; + } + return v; +} + +UINT16 h8_device::do_shar16(UINT16 v) +{ + CCR &= ~(F_N|F_V|F_Z|F_C); + if(v & 1) + CCR |= F_C; + v >>= 1; + if(!v) + CCR |= F_Z; + else if (v & 0x4000) { + v |= 0x8000; + CCR |= F_N; + } + return v; +} + +UINT32 h8_device::do_shar32(UINT32 v) +{ + CCR &= ~(F_N|F_V|F_Z|F_C); + if(v & 1) + CCR |= F_C; + v >>= 1; + if(!v) + CCR |= F_Z; + else if (v & 0x40000000) { + v |= 0x80000000; + CCR |= F_N; + } + return v; +} + +UINT8 h8_device::do_shll8(UINT8 v) +{ + CCR &= ~(F_N|F_V|F_Z|F_C); + if(v & 0x80) + CCR |= F_C; + v <<= 1; + if(!v) + CCR |= F_Z; + else if(INT8(v) < 0) + CCR |= F_N; + return v; +} + +UINT16 h8_device::do_shll16(UINT16 v) +{ + CCR &= ~(F_N|F_V|F_Z|F_C); + if(v & 0x8000) + CCR |= F_C; + v <<= 1; + if(!v) + CCR |= F_Z; + else if(INT16(v) < 0) + CCR |= F_N; + return v; +} + +UINT32 h8_device::do_shll32(UINT32 v) +{ + CCR &= ~(F_N|F_V|F_Z|F_C); + if(v & 0x80000000) + CCR |= F_C; + v <<= 1; + if(!v) + CCR |= F_Z; + else if(INT32(v) < 0) + CCR |= F_N; + return v; +} + +UINT8 h8_device::do_shlr8(UINT8 v) +{ + CCR &= ~(F_N|F_V|F_Z|F_C); + if(v & 1) + CCR |= F_C; + v >>= 1; + if(!v) + CCR |= F_Z; + return v; +} + +UINT16 h8_device::do_shlr16(UINT16 v) +{ + CCR &= ~(F_N|F_V|F_Z|F_C); + if(v & 1) + CCR |= F_C; + v >>= 1; + if(!v) + CCR |= F_Z; + return v; +} + +UINT32 h8_device::do_shlr32(UINT32 v) +{ + CCR &= ~(F_N|F_V|F_Z|F_C); + if(v & 1) + CCR |= F_C; + v >>= 1; + if(!v) + CCR |= F_Z; + return v; +} + +UINT8 h8_device::do_shal2_8(UINT8 v) +{ + CCR &= ~(F_N|F_V|F_Z|F_C); + if(v & 0x40) + CCR |= F_C; + if((v & 0xc0) == 0x40 || (v & 0xc0) == 0x80 || + (v & 0x60) == 0x20 || (v & 0x60) == 0x40) + CCR |= F_V; + v <<= 2; + if(!v) + CCR |= F_Z; + else if(INT8(v) < 0) + CCR |= F_N; + return v; +} + +UINT16 h8_device::do_shal2_16(UINT16 v) +{ + CCR &= ~(F_N|F_V|F_Z|F_C); + if(v & 0x4000) + CCR |= F_C; + if((v & 0xc000) == 0x4000 || (v & 0xc000) == 0x8000 || + (v & 0x6000) == 0x2000 || (v & 0x6000) == 0x4000) + CCR |= F_V; + v <<= 2; + if(!v) + CCR |= F_Z; + else if(INT16(v) < 0) + CCR |= F_N; + return v; +} + +UINT32 h8_device::do_shal2_32(UINT32 v) +{ + CCR &= ~(F_N|F_V|F_Z|F_C); + if(v & 0x40000000) + CCR |= F_C; + if((v & 0xc0000000) == 0x40000000 || (v & 0xc0000000) == 0x80000000 || + (v & 0x60000000) == 0x20000000 || (v & 0x60000000) == 0x40000000) + CCR |= F_V; + v <<= 2; + if(!v) + CCR |= F_Z; + else if(INT32(v) < 0) + CCR |= F_N; + return v; +} + +UINT8 h8_device::do_shar2_8(UINT8 v) +{ + CCR &= ~(F_N|F_V|F_Z|F_C); + if(v & 2) + CCR |= F_C; + v >>= 2; + if(!v) + CCR |= F_Z; + else if (v & 0x20) { + v |= 0xc0; + CCR |= F_N; + } + return v; +} + +UINT16 h8_device::do_shar2_16(UINT16 v) +{ + CCR &= ~(F_N|F_V|F_Z|F_C); + if(v & 2) + CCR |= F_C; + v >>= 2; + if(!v) + CCR |= F_Z; + else if (v & 0x2000) { + v |= 0xc000; + CCR |= F_N; + } + return v; +} + +UINT32 h8_device::do_shar2_32(UINT32 v) +{ + CCR &= ~(F_N|F_V|F_Z|F_C); + if(v & 2) + CCR |= F_C; + v >>= 2; + if(!v) + CCR |= F_Z; + else if (v & 0x20000000) { + v |= 0xc0000000; + CCR |= F_N; + } + return v; +} + +UINT8 h8_device::do_shll2_8(UINT8 v) +{ + CCR &= ~(F_N|F_V|F_Z|F_C); + if(v & 0x40) + CCR |= F_C; + v <<= 2; + if(!v) + CCR |= F_Z; + else if(INT8(v) < 0) + CCR |= F_N; + return v; +} + +UINT16 h8_device::do_shll2_16(UINT16 v) +{ + CCR &= ~(F_N|F_V|F_Z|F_C); + if(v & 0x4000) + CCR |= F_C; + v <<= 2; + if(!v) + CCR |= F_Z; + else if(INT16(v) < 0) + CCR |= F_N; + return v; +} + +UINT32 h8_device::do_shll2_32(UINT32 v) +{ + CCR &= ~(F_N|F_V|F_Z|F_C); + if(v & 0x40000000) + CCR |= F_C; + v <<= 2; + if(!v) + CCR |= F_Z; + else if(INT32(v) < 0) + CCR |= F_N; + return v; +} + +UINT8 h8_device::do_shlr2_8(UINT8 v) +{ + CCR &= ~(F_N|F_V|F_Z|F_C); + if(v & 2) + CCR |= F_C; + v >>= 2; + if(!v) + CCR |= F_Z; + return v; +} + +UINT16 h8_device::do_shlr2_16(UINT16 v) +{ + CCR &= ~(F_N|F_V|F_Z|F_C); + if(v & 2) + CCR |= F_C; + v >>= 2; + if(!v) + CCR |= F_Z; + return v; +} + +UINT32 h8_device::do_shlr2_32(UINT32 v) +{ + CCR &= ~(F_N|F_V|F_Z|F_C); + if(v & 2) + CCR |= F_C; + v >>= 2; + if(!v) + CCR |= F_Z; + return v; +} + +UINT8 h8_device::do_rotl8(UINT8 v) +{ + CCR &= ~(F_N|F_V|F_Z|F_C); + if(v & 0x80) + CCR |= F_C; + v = (v << 1) | (v >> 7); + if(!v) + CCR |= F_Z; + else if(INT8(v) < 0) + CCR |= F_N; + return v; +} + +UINT16 h8_device::do_rotl16(UINT16 v) +{ + CCR &= ~(F_N|F_V|F_Z|F_C); + if(v & 0x8000) + CCR |= F_C; + v = (v << 1) | (v >> 15); + if(!v) + CCR |= F_Z; + else if(INT16(v) < 0) + CCR |= F_N; + return v; +} + +UINT32 h8_device::do_rotl32(UINT32 v) +{ + CCR &= ~(F_N|F_V|F_Z|F_C); + if(v & 0x80000000) + CCR |= F_C; + v = (v << 1) | (v >> 31); + if(!v) + CCR |= F_Z; + else if(INT32(v) < 0) + CCR |= F_N; + return v; +} + +UINT8 h8_device::do_rotr8(UINT8 v) +{ + CCR &= ~(F_N|F_V|F_Z|F_C); + if(v & 0x01) + CCR |= F_C; + v = (v << 7) | (v >> 1); + if(!v) + CCR |= F_Z; + else if(INT8(v) < 0) + CCR |= F_N; + return v; +} + +UINT16 h8_device::do_rotr16(UINT16 v) +{ + CCR &= ~(F_N|F_V|F_Z|F_C); + if(v & 0x0001) + CCR |= F_C; + v = (v << 15) | (v >> 1); + if(!v) + CCR |= F_Z; + else if(INT16(v) < 0) + CCR |= F_N; + return v; +} + +UINT32 h8_device::do_rotr32(UINT32 v) +{ + CCR &= ~(F_N|F_V|F_Z|F_C); + if(v & 0x00000001) + CCR |= F_C; + v = (v << 31) | (v >> 1); + if(!v) + CCR |= F_Z; + else if(INT32(v) < 0) + CCR |= F_N; + return v; +} + +UINT8 h8_device::do_rotxl8(UINT8 v) +{ + UINT8 c = CCR & F_C ? 1 : 0; + CCR &= ~(F_N|F_V|F_Z|F_C); + if(v & 0x80) + CCR |= F_C; + v = (v << 1) | c; + if(!v) + CCR |= F_Z; + else if(INT8(v) < 0) + CCR |= F_N; + return v; +} + +UINT16 h8_device::do_rotxl16(UINT16 v) +{ + UINT16 c = CCR & F_C ? 1 : 0; + CCR &= ~(F_N|F_V|F_Z|F_C); + if(v & 0x8000) + CCR |= F_C; + v = (v << 1) | c; + if(!v) + CCR |= F_Z; + else if(INT16(v) < 0) + CCR |= F_N; + return v; +} + +UINT32 h8_device::do_rotxl32(UINT32 v) +{ + UINT32 c = CCR & F_C ? 1 : 0; + CCR &= ~(F_N|F_V|F_Z|F_C); + if(v & 0x80000000) + CCR |= F_C; + v = (v << 1) | c; + if(!v) + CCR |= F_Z; + else if(INT32(v) < 0) + CCR |= F_N; + return v; +} + +UINT8 h8_device::do_rotxr8(UINT8 v) +{ + UINT8 c = CCR & F_C ? 1 : 0; + CCR &= ~(F_N|F_V|F_Z|F_C); + if(v & 0x01) + CCR |= F_C; + v = (v >> 1) | (c << 7); + if(!v) + CCR |= F_Z; + else if(INT8(v) < 0) + CCR |= F_N; + return v; +} + +UINT16 h8_device::do_rotxr16(UINT16 v) +{ + UINT8 c = CCR & F_C ? 1 : 0; + CCR &= ~(F_N|F_V|F_Z|F_C); + if(v & 0x0001) + CCR |= F_C; + v = (v >> 1) | (c << 15); + if(!v) + CCR |= F_Z; + else if(INT16(v) < 0) + CCR |= F_N; + return v; +} + +UINT32 h8_device::do_rotxr32(UINT32 v) +{ + UINT8 c = CCR & F_C ? 1 : 0; + CCR &= ~(F_N|F_V|F_Z|F_C); + if(v & 0x00000001) + CCR |= F_C; + v = (v >> 1) | (c << 31); + if(!v) + CCR |= F_Z; + else if(INT32(v) < 0) + CCR |= F_N; + return v; +} + +UINT8 h8_device::do_rotl2_8(UINT8 v) +{ + CCR &= ~(F_N|F_V|F_Z|F_C); + if(v & 0x40) + CCR |= F_C; + v = (v << 2) | (v >> 6); + if(!v) + CCR |= F_Z; + else if(INT8(v) < 0) + CCR |= F_N; + return v; +} + +UINT16 h8_device::do_rotl2_16(UINT16 v) +{ + CCR &= ~(F_N|F_V|F_Z|F_C); + if(v & 0x4000) + CCR |= F_C; + v = (v << 2) | (v >> 14); + if(!v) + CCR |= F_Z; + else if(INT16(v) < 0) + CCR |= F_N; + return v; +} + +UINT32 h8_device::do_rotl2_32(UINT32 v) +{ + CCR &= ~(F_N|F_V|F_Z|F_C); + if(v & 0x40000000) + CCR |= F_C; + v = (v << 2) | (v >> 30); + if(!v) + CCR |= F_Z; + else if(INT32(v) < 0) + CCR |= F_N; + return v; +} + +UINT8 h8_device::do_rotr2_8(UINT8 v) +{ + CCR &= ~(F_N|F_V|F_Z|F_C); + if(v & 0x02) + CCR |= F_C; + v = (v << 6) | (v >> 2); + if(!v) + CCR |= F_Z; + else if(INT8(v) < 0) + CCR |= F_N; + return v; +} + +UINT16 h8_device::do_rotr2_16(UINT16 v) +{ + CCR &= ~(F_N|F_V|F_Z|F_C); + if(v & 0x0002) + CCR |= F_C; + v = (v << 14) | (v >> 2); + if(!v) + CCR |= F_Z; + else if(INT16(v) < 0) + CCR |= F_N; + return v; +} + +UINT32 h8_device::do_rotr2_32(UINT32 v) +{ + CCR &= ~(F_N|F_V|F_Z|F_C); + if(v & 0x00000002) + CCR |= F_C; + v = (v << 30) | (v >> 2); + if(!v) + CCR |= F_Z; + else if(INT32(v) < 0) + CCR |= F_N; + return v; +} + +UINT8 h8_device::do_rotxl2_8(UINT8 v) +{ + UINT8 c = CCR & F_C ? 1 : 0; + CCR &= ~(F_N|F_V|F_Z|F_C); + if(v & 0x40) + CCR |= F_C; + v = (v << 2) | (c << 1) | ((v >> 6) & 0x01); + if(!v) + CCR |= F_Z; + else if(INT8(v) < 0) + CCR |= F_N; + return v; +} + +UINT16 h8_device::do_rotxl2_16(UINT16 v) +{ + UINT16 c = CCR & F_C ? 1 : 0; + CCR &= ~(F_N|F_V|F_Z|F_C); + if(v & 0x4000) + CCR |= F_C; + v = (v << 2) | (c << 1) | ((v >> 14) & 0x0001); + if(!v) + CCR |= F_Z; + else if(INT16(v) < 0) + CCR |= F_N; + return v; +} + +UINT32 h8_device::do_rotxl2_32(UINT32 v) +{ + UINT32 c = CCR & F_C ? 1 : 0; + CCR &= ~(F_N|F_V|F_Z|F_C); + if(v & 0x40000000) + CCR |= F_C; + v = (v << 2) | (c << 1) | ((v >> 30) & 0x00000001); + if(!v) + CCR |= F_Z; + else if(INT32(v) < 0) + CCR |= F_N; + return v; +} + +UINT8 h8_device::do_rotxr2_8(UINT8 v) +{ + UINT8 c = CCR & F_C ? 1 : 0; + CCR &= ~(F_N|F_V|F_Z|F_C); + if(v & 0x02) + CCR |= F_C; + v = (v >> 2) | (c << 6) | (v << 7); + if(!v) + CCR |= F_Z; + else if(INT8(v) < 0) + CCR |= F_N; + return v; +} + +UINT16 h8_device::do_rotxr2_16(UINT16 v) +{ + UINT16 c = CCR & F_C ? 1 : 0; + CCR &= ~(F_N|F_V|F_Z|F_C); + if(v & 0x0002) + CCR |= F_C; + v = (v >> 2) | (c << 14) | (v << 15); + if(!v) + CCR |= F_Z; + else if(INT16(v) < 0) + CCR |= F_N; + return v; +} + +UINT32 h8_device::do_rotxr2_32(UINT32 v) +{ + UINT32 c = CCR & F_C ? 1 : 0; + CCR &= ~(F_N|F_V|F_Z|F_C); + if(v & 0x00000002) + CCR |= F_C; + v = (v >> 2) | (c << 30) | (v << 31); + if(!v) + CCR |= F_Z; + else if(INT32(v) < 0) + CCR |= F_N; + return v; +} + +void h8_device::set_nzv8(UINT8 v) +{ + CCR &= ~(F_N|F_V|F_Z); + if(!v) + CCR |= F_Z; + else if(INT8(v) < 0) + CCR |= F_N; +} + +void h8_device::set_nzv16(UINT16 v) +{ + CCR &= ~(F_N|F_V|F_Z); + if(!v) + CCR |= F_Z; + else if(INT16(v) < 0) + CCR |= F_N; +} + +void h8_device::set_nzv32(UINT32 v) +{ + CCR &= ~(F_N|F_V|F_Z); + if(!v) + CCR |= F_Z; + else if(INT32(v) < 0) + CCR |= F_N; +} + +void h8_device::set_nz16(UINT16 v) +{ + CCR &= ~(F_N|F_Z); + if(!v) + CCR |= F_Z; + else if(INT16(v) < 0) + CCR |= F_N; +} + +void h8_device::set_nz32(UINT32 v) +{ + CCR &= ~(F_N|F_Z); + if(!v) + CCR |= F_Z; + else if(INT32(v) < 0) + CCR |= F_N; +} + +#include "cpu/h8/h8.inc" diff --git a/src/devices/cpu/h8/h8.h b/src/devices/cpu/h8/h8.h new file mode 100644 index 00000000000..b1880c23b4d --- /dev/null +++ b/src/devices/cpu/h8/h8.h @@ -0,0 +1,475 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +/*************************************************************************** + + h8.h + + H8-300 base cpu emulation + + +***************************************************************************/ + +#ifndef __H8_H__ +#define __H8_H__ + +class h8_device : public cpu_device { +public: + enum { + // digital I/O ports + // ports 4-B are valid on 16-bit H8/3xx, ports 1-9 on 8-bit H8/3xx + // H8S/2394 has 12 ports named 1-6 and A-G + PORT_1, // 0 + PORT_2, // 1 + PORT_3, // 2 + PORT_4, // 3 + PORT_5, // 4 + PORT_6, // 5 + PORT_7, // 6 + PORT_8, // 7 + PORT_9, // 8 + PORT_A, // 9 + PORT_B, // A + PORT_C, // B + PORT_D, // C + PORT_E, // D + PORT_F, // E + PORT_G, // F + + // analog inputs + ADC_0, + ADC_1, + ADC_2, + ADC_3, + ADC_4, + ADC_5, + ADC_6, + ADC_7 + }; + + h8_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source, bool mode_a16, address_map_delegate map_delegate); + + void internal_update(); + + void set_irq(int irq_vector, int irq_level, bool irq_nmi); + +protected: + struct disasm_entry { + int slot; + UINT32 val, mask; + UINT16 val0, mask0; + const char *opcode; + int am1, am2; + offs_t flags; + }; + + enum { + STATE_RESET = 0x10000, + STATE_IRQ = 0x10001, + STATE_TRACE = 0x10002 + }; + + enum { + F_I = 0x80, + F_UI = 0x40, + F_H = 0x20, + F_U = 0x10, + F_N = 0x08, + F_Z = 0x04, + F_V = 0x02, + F_C = 0x01, + + EXR_T = 0x80, + EXR_NC = 0x78, + EXR_I = 0x07 + }; + + enum { + DASM_none, /* no additional arguments */ + + DASM_r8l, /* 8-bits register in bits 0-3 */ + DASM_r8h, /* 8-bits register in bits 4-7 */ + DASM_r8u, /* 8-bits register in bits 8-15 */ + DASM_r16l, /* 16-bits register in bits 0-3 */ + DASM_r16h, /* 16-bits register in bits 4-7 */ + DASM_r32l, /* 32-bits register in bits 0-3 */ + DASM_r32h, /* 32-bits register in bits 4-7 */ + + DASM_r16ih, /* indexed through 16-bits register in bits 4-6 */ + DASM_r16ihh, /* indexed through 16-bits register in bits 4-6 in 4-bytes instruction */ + DASM_pr16h, /* indexed through predecremented 16-bits register in bits 4-6 */ + DASM_r16ph, /* indexed through postincremented 16-bits register in bits 4-6 */ + DASM_r16d16h, /* indexed through 16-bits register in bits 4-6 with 16-bits displacement at end of instruction */ + + DASM_r32ih, /* indexed through 32-bits register in bits 4-6 */ + DASM_r32ihh, /* indexed through 32-bits register in bits 4-6 in 4-bytes instruction */ + DASM_pr32h, /* indexed through predecremented 32-bits register in bits 4-6 */ + DASM_r32pl, /* indexed through postincremented 32-bits register in bits 0-2 */ + DASM_r32ph, /* indexed through postincremented 32-bits register in bits 4-6 */ + DASM_r32d16h, /* indexed through 32-bits register in bits 4-6 with 16-bits displacement at end of instruction */ + DASM_r32d32hh, /* indexed through 32-bits register in bits 20-22 with 32-bits displacement at end of instruction */ + + DASM_psp, /* indexed through predecremented stack pointer */ + DASM_spp, /* indexed through postincremented stack pointer */ + + DASM_r32n2l, /* Block of 2 registers */ + DASM_r32n3l, /* Block of 3 registers */ + DASM_r32n4l, /* Block of 4 registers */ + + DASM_abs8, /* 8-bit address present at +1 */ + DASM_abs16, /* 16-bit address present at end of instruction */ + DASM_abs32, /* 32-bit address present at end of instruction */ + DASM_abs8i, /* 8-bit indirect jump address present at +1 */ + DASM_abs16e, /* 16-bit jump address present at +2 */ + DASM_abs24e, /* 24-bit jump address present at +1 */ + + DASM_rel8, /* 8-bit pc-relative jump address at +1, offset=2 */ + DASM_rel16, /* 16-bit pc-relative jump address at +2, offset=4 */ + + DASM_one, /* immediate value 1 */ + DASM_two, /* immediate value 2 */ + DASM_four, /* immediate value 4 */ + + DASM_imm2, /* 2-bit immediate in bits 4-5 (trapa) */ + DASM_imm3, /* 3-bit immediate in bits 4-6 (bit selection */ + DASM_imm8, /* 8-bit immediate at +1 */ + DASM_imm16, /* 16-bit immediate at +2 */ + DASM_imm32, /* 32-bit immediate at +2 */ + + DASM_ccr, /* internal register ccr */ + DASM_exr, /* internal register exr */ + DASM_macl, /* internal register macl */ + DASM_mach /* internal register mach */ + }; + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_execute_interface overrides + virtual UINT32 execute_min_cycles() const; + virtual UINT32 execute_max_cycles() const; + virtual UINT32 execute_input_lines() const; + virtual void execute_run(); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const; + + // device_state_interface overrides + virtual void state_import(const device_state_entry &entry); + virtual void state_export(const device_state_entry &entry); + virtual void state_string_export(const device_state_entry &entry, std::string &str); + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const; + virtual UINT32 disasm_max_opcode_bytes() const; + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + + address_space_config program_config, io_config; + address_space *program, *io; + direct_read_data *direct; + + UINT32 PPC; /* previous program counter */ + UINT32 NPC; /* next start-of-instruction program counter */ + UINT32 PC; /* program counter */ + UINT16 PIR; /* Prefetched word */ + UINT16 IR[5]; /* Fetched instruction */ + UINT16 R[16]; /* Rn (0-7), En (8-15, h8-300h+) */ + UINT8 EXR; /* Interrupt/trace register (h8s/2000+) */ + UINT8 CCR; /* Condition-code register */ + INT64 MAC; /* Multiply accumulator (h8s/2600+) */ + UINT8 MACF; /* MAC flags (h8s/2600+) */ + UINT32 TMP1, TMP2; + UINT32 TMPR; /* For debugger ER register import */ + + bool has_exr, has_trace, supports_advanced, mode_advanced, mac_saturating; + + int inst_state, inst_substate; + int icount, bcount; + int irq_vector, taken_irq_vector; + int irq_level, taken_irq_level; + bool irq_required, irq_nmi; + + static const disasm_entry disasm_entries[]; + + offs_t disassemble_generic(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options, const disasm_entry *table); + void disassemble_am(char *&buffer, int am, offs_t pc, const UINT8 *oprom, UINT32 opcode, int offset); + + virtual void do_exec_full(); + virtual void do_exec_partial(); + static void add_event(UINT64 &event_time, UINT64 new_event); + virtual bool exr_in_stack() const; + virtual void update_irq_filter() = 0; + virtual void interrupt_taken() = 0; + virtual void internal_update(UINT64 current_time) = 0; + void recompute_bcount(UINT64 event_time); + virtual int trace_setup(); + virtual int trapa_setup(); + virtual void irq_setup() = 0; + + UINT16 read16i(UINT32 adr); + UINT16 fetch(); + inline void fetch(int slot) { IR[slot] = fetch(); } + UINT8 read8(UINT32 adr); + void write8(UINT32 adr, UINT8 data); + UINT16 read16(UINT32 adr); + void write16(UINT32 adr, UINT16 data); + void internal(int cycles); + inline void prefetch() { prefetch_start(); prefetch_done(); } + inline void prefetch_noirq() { prefetch_start(); prefetch_done_noirq(); } + inline void prefetch_noirq_notrace() { prefetch_start(); prefetch_done_noirq_notrace(); } + void prefetch_start() { NPC = PC; PIR = fetch(); } + void prefetch_switch(UINT32 pc, UINT16 ir) { NPC = pc; PC = pc+2; PIR = ir; } + void prefetch_done(); + void prefetch_done_noirq(); + void prefetch_done_noirq_notrace(); + void illegal(); + + UINT8 do_addx8(UINT8 a, UINT8 b); + UINT8 do_subx8(UINT8 a, UINT8 b); + + UINT8 do_inc8(UINT8 a, UINT8 b); + UINT16 do_inc16(UINT16 a, UINT16 b); + UINT32 do_inc32(UINT32 a, UINT32 b); + + UINT8 do_add8(UINT8 a, UINT8 b); + UINT16 do_add16(UINT16 a, UINT16 b); + UINT32 do_add32(UINT32 a, UINT32 b); + + UINT8 do_dec8(UINT8 a, UINT8 b); + UINT16 do_dec16(UINT16 a, UINT16 b); + UINT32 do_dec32(UINT32 a, UINT32 b); + + UINT8 do_sub8(UINT8 a, UINT8 b); + UINT16 do_sub16(UINT16 a, UINT16 b); + UINT32 do_sub32(UINT32 a, UINT32 b); + + UINT8 do_shal8(UINT8 v); + UINT16 do_shal16(UINT16 v); + UINT32 do_shal32(UINT32 v); + + UINT8 do_shar8(UINT8 v); + UINT16 do_shar16(UINT16 v); + UINT32 do_shar32(UINT32 v); + + UINT8 do_shll8(UINT8 v); + UINT16 do_shll16(UINT16 v); + UINT32 do_shll32(UINT32 v); + + UINT8 do_shlr8(UINT8 v); + UINT16 do_shlr16(UINT16 v); + UINT32 do_shlr32(UINT32 v); + + UINT8 do_rotl8(UINT8 v); + UINT16 do_rotl16(UINT16 v); + UINT32 do_rotl32(UINT32 v); + + UINT8 do_rotr8(UINT8 v); + UINT16 do_rotr16(UINT16 v); + UINT32 do_rotr32(UINT32 v); + + UINT8 do_rotxl8(UINT8 v); + UINT16 do_rotxl16(UINT16 v); + UINT32 do_rotxl32(UINT32 v); + + UINT8 do_rotxr8(UINT8 v); + UINT16 do_rotxr16(UINT16 v); + UINT32 do_rotxr32(UINT32 v); + + UINT8 do_shal2_8(UINT8 v); + UINT16 do_shal2_16(UINT16 v); + UINT32 do_shal2_32(UINT32 v); + + UINT8 do_shar2_8(UINT8 v); + UINT16 do_shar2_16(UINT16 v); + UINT32 do_shar2_32(UINT32 v); + + UINT8 do_shll2_8(UINT8 v); + UINT16 do_shll2_16(UINT16 v); + UINT32 do_shll2_32(UINT32 v); + + UINT8 do_shlr2_8(UINT8 v); + UINT16 do_shlr2_16(UINT16 v); + UINT32 do_shlr2_32(UINT32 v); + + UINT8 do_rotl2_8(UINT8 v); + UINT16 do_rotl2_16(UINT16 v); + UINT32 do_rotl2_32(UINT32 v); + + UINT8 do_rotr2_8(UINT8 v); + UINT16 do_rotr2_16(UINT16 v); + UINT32 do_rotr2_32(UINT32 v); + + UINT8 do_rotxl2_8(UINT8 v); + UINT16 do_rotxl2_16(UINT16 v); + UINT32 do_rotxl2_32(UINT32 v); + + UINT8 do_rotxr2_8(UINT8 v); + UINT16 do_rotxr2_16(UINT16 v); + UINT32 do_rotxr2_32(UINT32 v); + + void set_nzv8(UINT8 v); + void set_nzv16(UINT16 v); + void set_nzv32(UINT32 v); + + void set_nz16(UINT16 v); + void set_nz32(UINT32 v); + + inline void r8_w(int reg, UINT8 val) { + if(reg & 8) + R[reg & 7] = (R[reg & 7] & 0xff00) | val; + else + R[reg & 7] = (R[reg & 7] & 0xff) | (val << 8); + } + + inline UINT8 r8_r(int reg) { + if(reg & 8) + return R[reg & 7]; + else + return R[reg & 7] >> 8; + } + + // Note that the decode is so that there's no risk of a h8-300 + // hitting the E registers even with the 0xf mask - the + // instruction would not be called in the first place + // + // Well, except for the instructions where the h8-300 mode is r16 + // and the h8-300h is r32 of course, we have to be careful to mask + // in h8.lst there if the top bit is 1. + + inline void r16_w(int reg, UINT16 val) { R[reg & 0xf] = val; } + inline UINT16 r16_r(int reg) { return R[reg & 0xf]; } + +#define O(o) void o ## _full(); void o ## _partial() + O(add_b_imm8_r8u); O(add_b_r8h_r8l); O(add_w_imm16_r16l); O(add_w_r16h_r16l); + O(adds_l_one_r16l); O(adds_l_two_r16l); O(adds_l_four_r16l); + O(addx_b_imm8_r8u); O(addx_b_r8h_r8l); + O(and_b_imm8_r8u); O(and_w_imm16_r16l); O(and_b_r8h_r8l); + O(andc_imm8_ccr); + O(band_imm3_abs16); O(band_imm3_abs8); O(band_imm3_r8l); O(band_imm3_r16ihh); + O(bcc_rel8); + O(bclr_imm3_abs16); O(bclr_imm3_abs8); O(bclr_imm3_r8l); O(bclr_imm3_r16ihh); O(bclr_r8h_abs16); O(bclr_r8h_abs8); O(bclr_r8h_r8l); O(bclr_r8h_r16ihh); + O(bcs_rel8); + O(beq_rel8); + O(bf_rel8); + O(bge_rel8); + O(bgt_rel8); + O(bhi_rel8); + O(biand_imm3_abs16); O(biand_imm3_abs8); O(biand_imm3_r8l); O(biand_imm3_r16ihh); + O(bild_imm3_abs16); O(bild_imm3_abs8); O(bild_imm3_r8l); O(bild_imm3_r16ihh); + O(bior_imm3_abs16); O(bior_imm3_abs8); O(bior_imm3_r8l); O(bior_imm3_r16ihh); + O(bist_imm3_abs16); O(bist_imm3_abs8); O(bist_imm3_r8l); O(bist_imm3_r16ihh); + O(bixor_imm3_abs16); O(bixor_imm3_abs8); O(bixor_imm3_r8l); O(bixor_imm3_r16ihh); + O(bld_imm3_abs16); O(bld_imm3_abs8); O(bld_imm3_r8l); O(bld_imm3_r16ihh); + O(ble_rel8); + O(bls_rel8); + O(blt_rel8); + O(bmi_rel8); + O(bne_rel8); + O(bnot_imm3_abs16); O(bnot_imm3_abs8); O(bnot_imm3_r8l); O(bnot_imm3_r16ihh); + O(bnot_r8h_abs16); O(bnot_r8h_abs8); O(bnot_r8h_r8l); O(bnot_r8h_r16ihh); + O(bor_imm3_abs16); O(bor_imm3_abs8); O(bor_imm3_r8l); O(bor_imm3_r16ihh); + O(bpl_rel8); + O(bset_imm3_abs16); O(bset_imm3_abs8); O(bset_imm3_r8l); O(bset_imm3_r16ihh); + O(bset_r8h_abs16); O(bset_r8h_abs8); O(bset_r8h_r8l); O(bset_r8h_r16ihh); + O(bsr_rel8); + O(bst_imm3_abs16); O(bst_imm3_abs8); O(bst_imm3_r8l); O(bst_imm3_r16ihh); + O(bt_rel8); + O(btst_imm3_abs16); O(btst_imm3_abs8); O(btst_imm3_r8l); O(btst_imm3_r16ihh); + O(btst_r8h_abs16); O(btst_r8h_abs8); O(btst_r8h_r8l); O(btst_r8h_r16ihh); + O(bvc_rel8); + O(bvs_rel8); + O(bxor_imm3_abs16); O(bxor_imm3_abs8); O(bxor_imm3_r8l); O(bxor_imm3_r16ihh); + O(cmp_b_imm8_r8u); O(cmp_b_r8h_r8l); O(cmp_w_imm16_r16l); O(cmp_w_r16h_r16l); + O(daa_b_r8l); + O(das_b_r8l); + O(dec_b_one_r8l); O(dec_w_one_r16l); O(dec_w_two_r16l); + O(divxu_b_r8h_r16l); + O(eepmov_b); + O(inc_b_one_r8l); + O(jmp_abs8i); O(jmp_abs16e); + O(jsr_abs8i); O(jsr_abs16e); O(jsr_r16h); + O(ldc_imm8_ccr); O(ldc_r8l_ccr); + O(mov_b_abs16_r8l); O(mov_b_abs8_r8u); O(mov_b_imm8_r8u); O(mov_b_r8h_r8l); O(mov_b_r8l_abs16); O(mov_b_r8u_abs8); O(mov_b_r16ih_r8l); O(mov_b_r8l_r16ih); O(mov_b_r16d16h_r8l); O(mov_b_r8l_r16d16h); O(mov_b_r16ph_r8l); O(mov_b_r8l_pr16h); + O(mov_w_abs16_r16l); O(mov_w_imm16_r16l); O(mov_w_r16h_r16l); O(mov_w_r16l_abs16); O(mov_w_r16ih_r16l); O(mov_w_r16l_r16ih); O(mov_w_r16ph_r16l); O(mov_w_r16l_pr16h); O(mov_w_r16l_r16d16h); O(mov_w_r16d16h_r16l); + O(movfpe_abs16_r8l); + O(movtpe_r8l_abs16); + O(mulxu_b_r8h_r16l); + O(neg_b_r8l); + O(nop); + O(not_b_r8l); + O(or_b_imm8_r8u); O(or_b_r8h_r8l); O(or_w_imm16_r16l); + O(orc_imm8_ccr); + O(rotl_b_r8l); + O(rotr_b_r8l); + O(rotxl_b_r8l); + O(rotxr_b_r8l); + O(rte); + O(rts); + O(shal_b_r8l); + O(shar_b_r8l); + O(shll_b_r8l); + O(shlr_b_r8l); + O(sleep); + O(stc_ccr_r8l); O(stc_exr_r8l); + O(sub_b_r8h_r8l); O(sub_w_imm16_r16l); O(sub_w_r16h_r16l); + O(subs_l_one_r16l); O(subs_l_two_r16l); O(subs_l_four_r16l); + O(subx_b_imm8_r8u); O(subx_b_r8h_r8l); + O(xor_b_imm8_r8u); O(xor_b_r8h_r8l); O(xor_w_imm16_r16l); + O(xorc_imm8_ccr); + + O(dispatch_0100); + O(dispatch_01007800); + O(dispatch_0110); + O(dispatch_0120); + O(dispatch_0130); + O(dispatch_0140); + O(dispatch_01407800); + O(dispatch_01407880); + O(dispatch_0141); + O(dispatch_01417800); + O(dispatch_01417880); + O(dispatch_0160); + O(dispatch_01c0); + O(dispatch_01d0); + O(dispatch_01e0); + O(dispatch_01f0); + O(dispatch_6a10); + O(dispatch_6a18); + O(dispatch_6a30); + O(dispatch_6a38); + O(dispatch_7800); + O(dispatch_7b5c); + O(dispatch_7bd4); + O(dispatch_7c00); + O(dispatch_7d00); + O(dispatch_7e00); + O(dispatch_7f00); + + O(state_reset); + O(state_irq); +#undef O +}; + +enum { + H8_PC = 1, + H8_R0, + H8_R1, + H8_R2, + H8_R3, + H8_R4, + H8_R5, + H8_R6, + H8_R7, + H8_E0, + H8_E1, + H8_E2, + H8_E3, + H8_E4, + H8_E5, + H8_E6, + H8_E7, + H8_CCR, + H8_EXR +}; + +#endif diff --git a/src/devices/cpu/h8/h8.lst b/src/devices/cpu/h8/h8.lst new file mode 100644 index 00000000000..3ec1f46fbe4 --- /dev/null +++ b/src/devices/cpu/h8/h8.lst @@ -0,0 +1,2811 @@ +macro bxx_any %cond + prefetch_start(); + TMP2 = read16i(TMP1); + if(%cond) + prefetch_switch(TMP1, TMP2); + prefetch_done(); + +macro bxx_8 %cond + TMP1 = PC + INT8(IR[0]); + bxx_any %cond + +macro bxx_16 %cond + TMP1 = PC + INT16(IR[1]); + bxx_any %cond + +macro bset %bit + TMP1 |= 1 << ((%bit) & 7); + +macro bnot %bit + TMP1 ^= 1 << ((%bit) & 7); + +macro bclr %bit + TMP1 &= ~(1 << ((%bit) & 7)); + +macro btst %bit + if(TMP1 & (1 << ((%bit) & 7))) + CCR &= ~F_Z; + else + CCR |= F_Z; + +macro bor %bit + if(TMP1 & (1 << ((%bit) & 7))) + CCR |= F_C; + +macro bior %bit + if(!(TMP1 & (1 << ((%bit) & 7)))) + CCR |= F_C; + +macro bxor %bit + if(TMP1 & (1 << ((%bit) & 7))) + CCR ^= F_C; + +macro bixor %bit + if(!(TMP1 & (1 << ((%bit) & 7)))) + CCR ^= F_C; + +macro band %bit + if(!(TMP1 & (1 << ((%bit) & 7)))) + CCR &= ~F_C; + +macro biand %bit + if(TMP1 & (1 << ((%bit) & 7))) + CCR &= ~F_C; + +macro bld %bit + if(TMP1 & (1 << ((%bit) & 7))) + CCR |= F_C; + else + CCR &= ~F_C; + +macro bild %bit + if(!(TMP1 & (1 << ((%bit) & 7)))) + CCR |= F_C; + else + CCR &= ~F_C; + +macro bst %bit + if(CCR & F_C) + TMP1 |= 1 << ((%bit) & 7); + else + TMP1 &= ~(1 << ((%bit) & 7)); + +macro bist %bit + if(!(CCR & F_C)) + TMP1 |= 1 << ((%bit) & 7); + else + TMP1 &= ~(1 << ((%bit) & 7)); + +macro jsr16 %opc %spreg + prefetch_start(); + %spreg = r16_r(7) - 2; + r16_w(7, %spreg); + write16(%spreg, %opc); + prefetch_done(); + +macro jsr32 %opc %spreg + prefetch_start(); + if(mode_advanced) { + %spreg = r32_r(7) - 4; + r32_w(7, %spreg); + write16(%spreg, %opc >> 16); + write16(%spreg+2, %opc); + } else { + %spreg = r32_r(7) - 2; + r32_w(7, %spreg); + write16(%spreg, %opc); + } + prefetch_done(); + +10000 reset + CCR |= F_I; + EXR = EXR_I | EXR_NC; + if(mode_advanced) { + IR[0] = read16i(0); + IR[1] = read16i(2); + PC = (IR[0] << 16) | IR[1]; + } else { + PC = read16i(0); + } + update_irq_filter(); + prefetch_noirq(); + +10001 irq o + internal(1); + TMP1 = r16_r(7) - 2; + r16_w(7, TMP1); + write16(TMP1, NPC); + TMP1 = r16_r(7) - 2; + r16_w(7, TMP1); + write16(TMP1, (CCR << 8) | ((PC >> 16) & 0xff)); + PC = read16i(2*taken_irq_vector); + internal(1); + irq_setup(); + update_irq_filter(); + interrupt_taken(); + prefetch_noirq(); + +10001 irq h + internal(1); + TMP1 = r32_r(7) - 2; + r32_w(7, TMP1); + write16(TMP1, NPC); + TMP1 = r32_r(7) - 2; + r32_w(7, TMP1); + write16(TMP1, (CCR << 8) | ((NPC >> 16) & 0xff)); + if(exr_in_stack()) { + TMP1 = r32_r(7) - 2; + r32_w(7, TMP1); + write16(TMP1, EXR << 8); + } + if(mode_advanced) { + IR[0] = read16i(4*taken_irq_vector); + IR[1] = read16i(4*taken_irq_vector+2); + PC = (IR[0] << 16) | IR[1]; + } else { + PC = read16i(2*taken_irq_vector); + } + internal(1); + irq_setup(); + update_irq_filter(); + interrupt_taken(); + prefetch_noirq(); + +10002 trace s20 + internal(1); + TMP1 = r32_r(7) - 2; + r32_w(7, TMP1); + write16(TMP1, NPC); + TMP1 = r32_r(7) - 2; + r32_w(7, TMP1); + write16(TMP1, (CCR << 8) | ((NPC >> 16) & 0xff)); + TMP1 = r32_r(7) - 2; + r32_w(7, TMP1); + write16(TMP1, EXR << 8); + taken_irq_vector = trace_setup(); + if(mode_advanced) { + IR[0] = read16i(4*taken_irq_vector); + IR[1] = read16i(4*taken_irq_vector+2); + PC = (IR[0] << 16) | IR[1]; + } else { + PC = read16i(2*taken_irq_vector); + } + internal(1); + prefetch_noirq(); + +0000 ffff 0 nop - - + prefetch(); + +01006900 ffffff88 0 mov.l r32ih r32l h + prefetch_start(); + TMP2 = r32_r(IR[1] >> 4); + TMP1 = read16(TMP2) << 16; + TMP1 |= read16(TMP2+2); + set_nzv32(TMP1); + r32_w(IR[1], TMP1); + prefetch_done(); + +01006980 ffffff88 0 mov.l r32l r32ih h + prefetch_start(); + TMP2 = r32_r(IR[1] >> 4); + TMP1 = r32_r(IR[1]); + set_nzv32(TMP1); + write16(TMP2, TMP1 >> 16); + write16(TMP2+2, TMP1); + prefetch_done(); + +01006b00 fffffff8 0 mov.l abs16 r32l h + prefetch_start(); + TMP2 = INT16(IR[2]); + TMP1 = read16(TMP2) << 16; + TMP1 |= read16(TMP2+2); + set_nzv32(TMP1); + r32_w(IR[1], TMP1); + prefetch_done(); + +01006b20 fffffff8 0 mov.l abs32 r32l h + prefetch_start(); + TMP2 = (IR[2] << 16) | IR[3]; + TMP1 = read16(TMP2) << 16; + TMP1 |= read16(TMP2+2); + set_nzv32(TMP1); + r32_w(IR[1], TMP1); + prefetch_done(); + +01006b80 fffffff8 0 mov.l r32l abs16 h + prefetch_start(); + TMP1 = r32_r(IR[1]); + TMP2 = INT16(IR[2]); + set_nzv32(TMP1); + write16(TMP2, TMP1 >> 16); + write16(TMP2+2, TMP1); + prefetch_done(); + +01006ba0 fffffff8 0 mov.l r32l abs32 h + prefetch_start(); + TMP1 = r32_r(IR[1]); + TMP2 = (IR[2] << 16) | IR[3]; + set_nzv32(TMP1); + write16(TMP2, TMP1 >> 16); + write16(TMP2+2, TMP1); + prefetch_done(); + +01006d00 ffffff88 0 mov.l r32ph r32l h + prefetch_start(); + internal(1); + TMP2 = r32_r(IR[1] >> 4); + TMP1 = read16(TMP2) << 16; + TMP1 |= read16(TMP2+2); + TMP2 += 4; + r32_w(IR[1] >> 4, TMP2); + set_nzv32(TMP1); + r32_w(IR[1], TMP1); + prefetch_done(); + +01006d80 ffffff88 0 mov.l r32l pr32h h + prefetch_start(); + internal(1); + TMP1 = r32_r(IR[1]); + TMP2 = r32_r(IR[1] >> 4); + TMP2 -= 4; + r32_w(IR[1] >> 4, TMP2); + write16(TMP2, TMP1 >> 16); + write16(TMP2+2, TMP1); + set_nzv32(TMP1); + prefetch_done(); + +01006f00 ffffff88 0 mov.l r32d16h r32l h + prefetch_start(); + TMP1 = r32_r(IR[1] >> 4) + INT16(IR[2]); + TMP2 = read16(TMP1) << 16; + TMP2 |= read16(TMP1+2); + set_nzv32(TMP2); + r32_w(IR[1], TMP2); + prefetch_done(); + +01006f80 ffffff88 0 mov.l r32l r32d16h h + prefetch_start(); + TMP1 = r32_r(IR[1] >> 4) + INT16(IR[2]); + TMP2 = r32_r(IR[1]); + set_nzv32(TMP2); + write16(TMP1, TMP2 >> 16); + write16(TMP1+2, TMP2); + prefetch_done(); + +010078006b20 ffffff0ffff8 0 mov.l r32d32hh r32l h + prefetch_start(); + TMP1 = r32_r(IR[1] >> 4) + (IR[3] << 16) + IR[4]; + TMP2 = read16(TMP1) << 16; + TMP2 |= read16(TMP1+2); + set_nzv32(TMP2); + r32_w(IR[2], TMP2); + prefetch_done(); + +010078006ba0 ffffff0ffff8 0 mov.l r32l r32d32hh h + prefetch_start(); + TMP1 = r32_r(IR[1] >> 4) + (IR[3] << 16) + IR[4]; + TMP2 = r32_r(IR[2]); + set_nzv32(TMP2); + write16(TMP1, TMP2 >> 16); + write16(TMP1+2, TMP2); + prefetch_done(); + +01106d71 fffffff9 0 ldm.l spp r32n2l s20 + prefetch_start(); + internal(1); + TMP1 = r32_r(7); + TMP2 = read16(TMP1) << 16; + TMP2 |= read16(TMP1+2); + r32_w(IR[1], TMP2); + if((IR[1] & 7) == 7) + TMP1 = TMP2; + TMP1 += 4; + r32_w(7, TMP1); + TMP2 = read16(TMP1) << 16; + TMP2 |= read16(TMP1+2); + r32_w(IR[1]-1, TMP2); + TMP1 += 4; + r32_w(7, TMP1); + prefetch_done(); + +01106df0 fffffff9 0 stm.l r32n2l psp s20 + prefetch_start(); + internal(1); + TMP1 = r32_r(7); + TMP1 -= 4; + r32_w(7, TMP1); + TMP2 = r32_r(IR[1]); + write16(TMP1, TMP2 >> 16); + write16(TMP1+2, TMP2); + TMP1 -= 4; + r32_w(7, TMP1); + TMP2 = r32_r(IR[1]+1); + write16(TMP1, TMP2 >> 16); + write16(TMP1+2, TMP2); + prefetch_done(); + +01206d72 fffffffb 0 ldm.l spp r32n3l s20 + prefetch_start(); + internal(1); + TMP1 = r32_r(7); + TMP2 = read16(TMP1) << 16; + TMP2 |= read16(TMP1+2); + r32_w(IR[1], TMP2); + TMP1 += 4; + r32_w(7, TMP1); + TMP2 = read16(TMP1) << 16; + TMP2 |= read16(TMP1+2); + r32_w(IR[1]-1, TMP2); + TMP1 += 4; + r32_w(7, TMP1); + TMP2 = read16(TMP1) << 16; + TMP2 |= read16(TMP1+2); + r32_w(IR[1]-2, TMP2); + TMP1 += 4; + r32_w(7, TMP1); + prefetch_done(); + +01206df0 fffffffb 0 stm.l r32n3l psp s20 + prefetch_start(); + internal(1); + TMP1 = r32_r(7); + TMP1 -= 4; + r32_w(7, TMP1); + TMP2 = r32_r(IR[1]); + write16(TMP1, TMP2 >> 16); + write16(TMP1+2, TMP2); + TMP1 -= 4; + r32_w(7, TMP1); + TMP2 = r32_r(IR[1]+1); + write16(TMP1, TMP2 >> 16); + write16(TMP1+2, TMP2); + TMP1 -= 4; + r32_w(7, TMP1); + TMP2 = r32_r(IR[1]+2); + write16(TMP1, TMP2 >> 16); + write16(TMP1+2, TMP2); + prefetch_done(); + +01306d73 fffffffb 0 ldm.l spp r32n4l s20 + prefetch_start(); + internal(1); + TMP1 = r32_r(7); + TMP2 = read16(TMP1) << 16; + TMP2 |= read16(TMP1+2); + r32_w(IR[1], TMP2); + if((IR[1] & 7) == 7) + TMP1 = TMP2; + TMP1 += 4; + r32_w(7, TMP1); + TMP2 = read16(TMP1) << 16; + TMP2 |= read16(TMP1+2); + r32_w(IR[1]-1, TMP2); + TMP1 += 4; + r32_w(7, TMP1); + TMP2 = read16(TMP1) << 16; + TMP2 |= read16(TMP1+2); + r32_w(IR[1]-2, TMP2); + TMP1 += 4; + r32_w(7, TMP1); + TMP2 = read16(TMP1) << 16; + TMP2 |= read16(TMP1+2); + r32_w(IR[1]-3, TMP2); + TMP1 += 4; + r32_w(7, TMP1); + prefetch_done(); + +01306df0 fffffffb 0 stm.l r32n4l psp s20 + prefetch_start(); + internal(1); + TMP1 = r32_r(7); + TMP1 -= 4; + r32_w(7, TMP1); + TMP2 = r32_r(IR[1]); + write16(TMP1, TMP2 >> 16); + write16(TMP1+2, TMP2); + TMP1 -= 4; + r32_w(7, TMP1); + TMP2 = r32_r(IR[1]+1); + write16(TMP1, TMP2 >> 16); + write16(TMP1+2, TMP2); + TMP1 -= 4; + r32_w(7, TMP1); + TMP2 = r32_r(IR[1]+2); + write16(TMP1, TMP2 >> 16); + write16(TMP1+2, TMP2); + TMP1 -= 4; + r32_w(7, TMP1); + TMP2 = r32_r(IR[1]+3); + write16(TMP1, TMP2 >> 16); + write16(TMP1+2, TMP2); + prefetch_done(); + +01406900 ffffff8f 0 ldc.w r32ih ccr h + prefetch_start(); + TMP1 = r32_r(IR[1] >> 4); + CCR = read16(TMP1) >> 8; + update_irq_filter(); + prefetch_done_noirq(); + +01406980 ffffff8f 0 stc.w ccr r32ih h + prefetch_start(); + TMP1 = r32_r(IR[1] >> 4); + write16(TMP1, (CCR << 8) | CCR); + prefetch_done(); + +01406b00 ffffffff 0 ldc.w abs16 ccr h + prefetch_start(); + TMP1 = INT16(IR[2]); + CCR = read16(TMP1) >> 8; + update_irq_filter(); + prefetch_done_noirq(); + +01406b20 ffffffff 0 ldc.w abs32 ccr h + prefetch_start(); + TMP1 = (IR[2] << 16) | IR[3]; + CCR = read16(TMP1) >> 8; + update_irq_filter(); + prefetch_done_noirq(); + +01406b80 ffffffff 0 stc.w ccr abs16 h + prefetch_start(); + TMP1 = INT16(IR[2]); + write16(TMP1, (CCR << 8) | CCR); + prefetch_done(); + +01406ba0 ffffffff 0 stc.w ccr abs32 h + prefetch_start(); + TMP1 = (IR[2] << 16) | IR[3]; + write16(TMP1, (CCR << 8) | CCR); + prefetch_done(); + +01406d00 ffffff8f 0 ldc.w r32ph ccr h + prefetch_start(); + internal(1); + TMP1 = r32_r(IR[1] >> 4); + r32_w(IR[1] >> 4, TMP1+2); + CCR = read16(TMP1) >> 8; + update_irq_filter(); + prefetch_done_noirq(); + +01406d80 ffffff8f 0 stc.w ccr pr32h h + prefetch_start(); + internal(1); + TMP1 = r32_r(IR[1] >> 4) - 2; + r32_w(IR[1] >> 4, TMP1); + write16(TMP1, (CCR << 8) | CCR); + prefetch_done(); + +01406f00 ffffff8f 0 ldc.w r32d16h ccr h + prefetch_start(); + TMP1 = r32_r(IR[1] >> 4) + INT16(IR[2]); + CCR = read16(TMP1) >> 8; + update_irq_filter(); + prefetch_done_noirq(); + +01406f80 ffffff8f 0 stc.w ccr r32d16h h + prefetch_start(); + TMP1 = r32_r(IR[1] >> 4) + INT16(IR[2]); + write16(TMP1, (CCR << 8) | CCR); + prefetch_done(); + +014078006b20 ffffff8fffff 0 ldc.w r32d32hh ccr h + prefetch_start(); + TMP1 = r32_r(IR[1] >> 4) + (IR[3] << 16) + IR[4]; + CCR = read16(TMP1) >> 8; + update_irq_filter(); + prefetch_done_noirq(); + +014078806ba0 ffffff8fffff 0 stc.w ccr r32d32hh h + prefetch_start(); + TMP1 = r32_r(IR[1] >> 4) + (IR[3] << 16) + IR[4]; + write16(TMP1, (CCR << 8) | CCR); + prefetch_done(); + +01410700 ffffff00 0 ldc imm8 exr s20 + EXR = IR[1]; + update_irq_filter(); + prefetch_noirq(); + +01416900 ffffff8f 0 ldc.w r32ih exr s20 + prefetch_start(); + TMP1 = r32_r(IR[1] >> 4); + EXR = (read16(TMP1) >> 8) | EXR_NC; + update_irq_filter(); + prefetch_done_noirq(); + +01416980 ffffff8f 0 stc.w exr r32ih s20 + prefetch_start(); + TMP1 = r32_r(IR[1] >> 4); + write16(TMP1, (EXR << 8) | EXR); + prefetch_done(); + +01416b00 ffffffff 0 ldc.w abs16 exr s20 + prefetch_start(); + TMP1 = INT16(IR[2]); + EXR = (read16(TMP1) >> 8) | EXR_NC; + update_irq_filter(); + prefetch_done_noirq(); + +01416b20 ffffffff 0 ldc.w abs32 exr s20 + prefetch_start(); + TMP1 = (IR[2] << 16) | IR[3]; + EXR = (read16(TMP1) >> 8) | EXR_NC; + update_irq_filter(); + prefetch_done_noirq(); + +01416b80 ffffffff 0 stc.w exr abs16 s20 + prefetch_start(); + TMP1 = INT16(IR[2]); + write16(TMP1, (EXR << 8) | EXR); + prefetch_done(); + +01416ba0 ffffffff 0 stc.w exr abs32 s20 + prefetch_start(); + TMP1 = (IR[2] << 16) | IR[3]; + write16(TMP1, (EXR << 8) | EXR); + prefetch_done(); + +01416d00 ffffff8f 0 ldc.w r32ph exr s20 + prefetch_start(); + internal(1); + TMP1 = r32_r(IR[1] >> 4); + r32_w(IR[1] >> 4, TMP1+2); + EXR = (read16(TMP1) >> 8) | EXR_NC; + update_irq_filter(); + prefetch_done_noirq(); + +01416d80 ffffff8f 0 stc.w exr pr32h s20 + prefetch_start(); + internal(1); + TMP1 = r32_r(IR[1] >> 4) - 2; + r32_w(IR[1] >> 4, TMP1); + write16(TMP1, (EXR << 8) | EXR); + prefetch_done(); + +01416f00 ffffff8f 0 ldc.w r32d16h exr s20 + prefetch_start(); + TMP1 = r32_r(IR[1] >> 4) + INT16(IR[2]); + EXR = (read16(TMP1) >> 8) | EXR_NC; + update_irq_filter(); + prefetch_done_noirq(); + +01416f80 ffffff8f 0 stc.w exr r32d16h s20 + prefetch_start(); + TMP1 = r32_r(IR[1] >> 4) + INT16(IR[2]); + write16(TMP1, (EXR << 8) | EXR); + prefetch_done(); + +014178006b20 ffffff8fffff 0 ldc.w r32d32hh exr s20 + prefetch_start(); + TMP1 = r32_r(IR[1] >> 4) + (IR[3] << 16) + IR[4]; + EXR = (read16(TMP1) >> 8) | EXR_NC; + update_irq_filter(); + prefetch_done_noirq(); + +014178806ba0 ffffff8fffff 0 stc.w exr r32d32hh s20 + prefetch_start(); + TMP1 = r32_r(IR[1] >> 4) + (IR[3] << 16) + IR[4]; + write16(TMP1, (EXR << 8) | EXR); + prefetch_done(); + +01606d00 ffffff88 0 mac r32ph r32pl s26 + prefetch_start(); + TMP1 = read16(r32_r(IR[1])); + r32_w(IR[1], r32_r(IR[1]) + 2); + TMP2 = read16(r32_r(IR[1] >> 4)); + r32_w(IR[1] >> 4, r32_r(IR[1] >> 4) + 2); + MAC += INT16(TMP1)*INT16(TMP2); + MACF &= ~(F_Z|F_N); + if(MAC) + MACF |= F_Z; + else if(MAC < 0) + MACF |= F_N; + if(mac_saturating) { + if(MAC < -0x80000000LL) { + MAC = -0x80000000LL; + MACF |= F_V; + } else if(MAC > 0x7fffffffLL) { + MAC = 0x7fffffffLL; + MACF |= F_V; + } + } else { + if(MAC < -0x20000000000LL) { + MAC = -0x20000000000LL; + MACF |= F_V; + } else if(MAC > 0x1ffffffffffLL) { + MAC = 0x1ffffffffffLL; + MACF |= F_V; + } + } + prefetch_done(); + +0180 ffff 0 sleep - - + prefetch_start(); + while(!irq_vector) { + eat-all-cycles; + } + prefetch_done(); + +01a0 ffff 0 clrmac - - s26 + prefetch_start(); + internal(1); + MAC = 0; + MACF &= ~F_V; + prefetch_done(); + +01c05000 ffffff00 0 mulxs.b r8h r16l h + prefetch_start(); + TMP1 = INT8(r16_r(IR[1])) * INT8(r8_r(IR[1] >> 4)); + set_nz16(TMP1); + r16_w(IR[1], TMP1); + internal(2); + prefetch_done(); + +01c05200 ffffff08 0 mulxs.w r16h r32l h + prefetch_start(); + TMP1 = INT16(r32_r(IR[1])) * INT16(r16_r(IR[1] >> 4)); + set_nz32(TMP1); + r32_w(IR[1], TMP1); + internal(3); + prefetch_done(); + +01d05100 ffffff00 0 divxs.b r8h r16l h + prefetch_start(); + internal(11); + TMP1 = INT16(r16_r(IR[1])); + TMP2 = INT8(r8_r(IR[1] >> 4)); + CCR &= ~(F_Z|F_N); + if(!TMP2) { + CCR |= F_Z; + } else { + // Conditions: + // p = q*d + r + // abs(r) < abs(d) + // d and r are same sign or r=0 + // p = +20, d = +3 -> q = 6, r = 2 + // p = +20, d = -3 -> q = -6, r = -2 + // p = -20, d = +3 -> q = -7, r = 1 + // p = -20, d = -3 -> q = 7, r = -1 + int q, r; + if(TMP2 < 0) { + if(TMP1 < 0) { // - - + q = (-TMP1) / (-TMP2); + r = (-TMP1) % (-TMP2); + if(r) { + r = r + TMP2; + q++; + } + } else { // + - + CCR |= F_N; + q = -(TMP1 / (-TMP2)); + r = -(TMP1 % (-TMP2)); + } + } else { + if(TMP1 < 0) { // - + + CCR |= F_N; + q = -((-TMP1) / TMP2); + r = (-TMP1) % TMP2; + if(r) { + r = TMP2 - r; + q--; + } + } else { // + + + q = TMP1 / TMP2; + r = TMP1 % TMP2; + } + } + r16_w(IR[1], (q & 0xff) | ((r & 0xff) << 8)); + } + prefetch_done(); + +01d05300 ffffff08 0 divxs.w r16h r32l h + prefetch_start(); + internal(19); + TMP1 = r32_r(IR[1]); + TMP2 = INT16(r16_r(IR[1] >> 4)); + CCR &= ~(F_Z|F_N); + if(!TMP2) { + CCR |= F_Z; + } else { + // Conditions: + // p = q*d + r + // abs(r) < abs(d) + // d and r are same sign or r=0 + // p = +20, d = +3 -> q = 6, r = 2 + // p = +20, d = -3 -> q = -6, r = -2 + // p = -20, d = +3 -> q = -7, r = 1 + // p = -20, d = -3 -> q = 7, r = -1 + int q, r; + if(TMP2 < 0) { + if(TMP1 < 0) { // - - + q = (-TMP1) / (-TMP2); + r = (-TMP1) % (-TMP2); + if(r) { + r = r + TMP2; + q++; + } + } else { // + - + CCR |= F_N; + q = -(TMP1 / (-TMP2)); + r = -(TMP1 % (-TMP2)); + } + } else { + if(TMP1 < 0) { // - + + CCR |= F_N; + q = -((-TMP1) / TMP2); + r = (-TMP1) % TMP2; + if(r) { + r = TMP2 - r; + q--; + } + } else { // + + + q = TMP1 / TMP2; + r = TMP1 % TMP2; + } + } + r32_w(IR[1], (q & 0xffff) | ((r & 0xffff) << 16)); + } + prefetch_done(); + +01e07b0c ffffffaf 0 tas r32ih - s20 + prefetch_start(); + TMP1 = r32_r(IR[1] >> 4); + TMP2 = read8(TMP1); + set_nzv8(TMP2); + write8(TMP1, TMP2 | 0x80); + prefetch_done(); + +01f06400 ffffff88 0 or.l r32h r32l h + TMP1 = r32_r(IR[1] >> 4) | r32_r(IR[1]); + set_nzv32(TMP1); + r32_w(IR[1], TMP1); + prefetch(); + +01f06500 ffffff88 0 xor.l r32h r32l h + TMP1 = r32_r(IR[1] >> 4) ^ r32_r(IR[1]); + set_nzv32(TMP1); + r32_w(IR[1], TMP1); + prefetch(); + +01f06600 ffffff88 0 and.l r32h r32l h + TMP1 = r32_r(IR[1] >> 4) & r32_r(IR[1]); + set_nzv32(TMP1); + r32_w(IR[1], TMP1); + prefetch(); + +0200 fff0 0 stc ccr r8l + r8_w(IR[0], CCR); + prefetch(); + +0210 fff0 0 stc exr r8l s20 + r8_w(IR[0], EXR); + prefetch(); + +0220 fff8 0 stmac mach r32l s26 + r32_w(IR[0], MAC >> 32); + CCR = (CCR & ~(F_V|F_N|F_Z)) | MACF; + prefetch(); + +0230 fff8 0 stmac macl r32l s26 + r32_w(IR[0], MAC); + CCR = (CCR & ~(F_V|F_N|F_Z)) | MACF; + prefetch(); + +0300 fff0 0 ldc r8l ccr + CCR = r8_r(IR[0]); + update_irq_filter(); + prefetch_noirq(); + +0310 fff0 0 ldc r8l exr s20 + EXR = r8_r(IR[0]); + update_irq_filter(); + prefetch_noirq(); + +0320 fff8 0 ldmac r32l mach s26 + prefetch_start(); + internal(1); + TMP1 = r32_r(IR[0]); + if(TMP1 & 0x200) + TMP1 |= 0xfffffc00; + else + TMP1 &= ~0xfffffc00; + MAC = (MAC & 0x00000000ffffffffULL) | (UINT64(TMP1) << 32); + MACF &= ~F_V; + prefetch_done(); + +0330 fff8 0 ldmac r32l macl s26 + prefetch_start(); + internal(1); + MAC = (MAC & 0xffffffff00000000ULL) | r32_r(IR[0]); + MACF &= ~F_V; + prefetch_done(); + +0400 ff00 0 orc imm8 ccr + CCR |= IR[0]; + update_irq_filter(); + prefetch_noirq(); + +0500 ff00 0 xorc imm8 ccr + CCR ^= IR[0]; + update_irq_filter(); + prefetch_noirq(); + +0600 ff00 0 andc imm8 ccr + CCR &= IR[0]; + update_irq_filter(); + prefetch_noirq(); + +0700 ff00 0 ldc imm8 ccr + CCR = IR[0]; + update_irq_filter(); + prefetch_noirq(); + +0800 ff00 0 add.b r8h r8l + r8_w(IR[0], do_add8(r8_r(IR[0]), r8_r(IR[0] >> 4))); + prefetch(); + +0900 ff00 0 add.w r16h r16l + r16_w(IR[0], do_add16(r16_r(IR[0]), r16_r(IR[0] >> 4))); + prefetch(); + +0a00 fff0 0 inc.b one r8l + r8_w(IR[0], do_inc8(r8_r(IR[0]), 1)); + prefetch(); + +0a80 ff88 0 add.l r32h r32l h + r32_w(IR[0], do_add32(r32_r(IR[0]), r32_r(IR[0] >> 4))); + prefetch(); + +0b00 fff8 0 adds.l one r16l o + r16_w(IR[0], r16_r(IR[0])+1); + prefetch(); + +0b00 fff8 0 adds.l one r32l h + r32_w(IR[0], r32_r(IR[0])+1); + prefetch(); + +0b50 fff0 0 inc.w one r16l h + r16_w(IR[0], do_inc16(r16_r(IR[0]), 1)); + prefetch(); + +0b70 fff8 0 inc.l one r32l h + r32_w(IR[0], do_inc32(r32_r(IR[0]), 1)); + prefetch(); + +0b80 fff8 0 adds.l two r16l o + r16_w(IR[0], r16_r(IR[0])+2); + prefetch(); + +0b80 fff8 0 adds.l two r32l h + r32_w(IR[0], r32_r(IR[0])+2); + prefetch(); + +0b90 fff8 0 adds.l four r16l o + r16_w(IR[0], r16_r(IR[0])+4); + prefetch(); + +0b90 fff8 0 adds.l four r32l h + r32_w(IR[0], r32_r(IR[0])+4); + prefetch(); + +0bd0 fff0 0 inc.w two r16l h + r16_w(IR[0], do_inc16(r16_r(IR[0]), 2)); + prefetch(); + +0bf0 fff8 0 inc.l two r32l h + r32_w(IR[0], do_inc32(r32_r(IR[0]), 2)); + prefetch(); + +0c00 ff00 0 mov.b r8h r8l + TMP1 = r8_r(IR[0] >> 4); + set_nzv8(TMP1); + r8_w(IR[0], TMP1); + prefetch(); + +0d00 ff00 0 mov.w r16h r16l + TMP1 = r16_r(IR[0] >> 4); + set_nzv16(TMP1); + r16_w(IR[0], TMP1); + prefetch(); + +0e00 ff00 0 addx.b r8h r8l + r8_w(IR[0], do_addx8(r8_r(IR[0]), r8_r(IR[0] >> 4))); + prefetch(); + +0f00 fff0 0 daa.b r8l - + TMP1 = r8_r(IR[0]); + TMP2 = 0; + if(CCR & F_C) { + if(CCR & F_H) { + if((TMP1 & 0xf0) <= 0x30 && (TMP1 & 0x0f) <= 3) + TMP2 = 0x66; + } else { + if((TMP1 & 0xf0) <= 0x20) + TMP2 = (TMP1 & 0x0f) <= 9 ? 0x60 : 0x66; + } + } else { + if(CCR & F_H) { + if((TMP1 & 0x0f) <= 3) + TMP2 = (TMP1 & 0xf0) <= 0x90 ? 0x06 : 0x66; + } else { + if((TMP1 & 0x0f) <= 9) + TMP2 = (TMP1 & 0xf0) <= 0x90 ? 0x00 : 0x60; + else + TMP2 = (TMP1 & 0xf0) <= 0x80 ? 0x06 : 0x66; + } + } + r8_w(IR[0], do_add8(TMP1, TMP2)); + prefetch(); + +0f80 ff88 0 mov.l r32h r32l h + TMP1 = r32_r(IR[0] >> 4); + set_nzv32(TMP1); + r32_w(IR[0], TMP1); + prefetch(); + +1000 fff0 0 shll.b r8l - + r8_w(IR[0], do_shll8(r8_r(IR[0]))); + prefetch(); + +1010 fff0 0 shll.w r16l - h + r16_w(IR[0], do_shll16(r16_r(IR[0]))); + prefetch(); + +1030 fff8 0 shll.l r32l - h + r32_w(IR[0], do_shll32(r32_r(IR[0]))); + prefetch(); + +1040 fff0 0 shll.b two r8l s20 + r8_w(IR[0], do_shll2_8(r8_r(IR[0]))); + prefetch(); + +1050 fff0 0 shll.w two r16l s20 + r16_w(IR[0], do_shll2_16(r16_r(IR[0]))); + prefetch(); + +1070 fff8 0 shll.l two r32l s20 + r32_w(IR[0], do_shll2_32(r32_r(IR[0]))); + prefetch(); + +1080 fff0 0 shal.b r8l - + r8_w(IR[0], do_shal8(r8_r(IR[0]))); + prefetch(); + +1090 fff0 0 shal.w r16l - h + r16_w(IR[0], do_shal16(r16_r(IR[0]))); + prefetch(); + +10b0 fff8 0 shal.l r32l - h + r32_w(IR[0], do_shal32(r32_r(IR[0]))); + prefetch(); + +10c0 fff0 0 shal.b two r8l s20 + r8_w(IR[0], do_shal2_8(r8_r(IR[0]))); + prefetch(); + +10d0 fff0 0 shal.w two r16l s20 + r16_w(IR[0], do_shal2_16(r16_r(IR[0]))); + prefetch(); + +10f0 fff8 0 shal.l two r32l s20 + r32_w(IR[0], do_shal32(r32_r(IR[0]))); + prefetch(); + +1100 fff0 0 shlr.b r8l - + r8_w(IR[0], do_shlr8(r8_r(IR[0]))); + prefetch(); + +1110 fff0 0 shlr.w r16l - h + r16_w(IR[0], do_shlr16(r16_r(IR[0]))); + prefetch(); + +1130 fff8 0 shlr.l r32l - h + r32_w(IR[0], do_shlr32(r32_r(IR[0]))); + prefetch(); + +1140 fff0 0 shlr.b two r8l s20 + r8_w(IR[0], do_shlr2_8(r8_r(IR[0]))); + prefetch(); + +1150 fff0 0 shlr.w two r16l s20 + r16_w(IR[0], do_shlr2_16(r16_r(IR[0]))); + prefetch(); + +1170 fff8 0 shlr.l two r32l s20 + r32_w(IR[0], do_shlr2_32(r32_r(IR[0]))); + prefetch(); + +1180 fff0 0 shar.b r8l - + r8_w(IR[0], do_shar8(r8_r(IR[0]))); + prefetch(); + +1190 fff0 0 shar.w r16l - h + r16_w(IR[0], do_shar16(r16_r(IR[0]))); + prefetch(); + +11b0 fff8 0 shar.l r32l - h + r32_w(IR[0], do_shar32(r32_r(IR[0]))); + prefetch(); + +11c0 fff0 0 shar.b two r8l s20 + r8_w(IR[0], do_shar2_8(r8_r(IR[0]))); + prefetch(); + +11d0 fff0 0 shar.w two r16l s20 + r16_w(IR[0], do_shar2_16(r16_r(IR[0]))); + prefetch(); + +11f0 fff8 0 shar.l two r32l s20 + r32_w(IR[0], do_shar2_32(r32_r(IR[0]))); + prefetch(); + +1200 fff0 0 rotxl.b r8l - + r8_w(IR[0], do_rotxl8(r8_r(IR[0]))); + prefetch(); + +1210 fff0 0 rotxl.w r16l - h + r16_w(IR[0], do_rotxl16(r16_r(IR[0]))); + prefetch(); + +1230 fff8 0 rotxl.l r32l - h + r32_w(IR[0], do_rotxl32(r32_r(IR[0]))); + prefetch(); + +1240 fff0 0 rotxl.b two r8l s20 + r8_w(IR[0], do_rotxl2_8(r8_r(IR[0]))); + prefetch(); + +1250 fff0 0 rotxl.w two r16l s20 + r16_w(IR[0], do_rotxl2_16(r16_r(IR[0]))); + prefetch(); + +1270 fff8 0 rotxl.l two r32l s20 + r32_w(IR[0], do_rotxl2_32(r32_r(IR[0]))); + prefetch(); + +1280 fff0 0 rotl.b r8l - + r8_w(IR[0], do_rotl8(r8_r(IR[0]))); + prefetch(); + +1290 fff0 0 rotl.w r16l - h + r16_w(IR[0], do_rotl16(r16_r(IR[0]))); + prefetch(); + +12b0 fff8 0 rotl.l r32l - h + r32_w(IR[0], do_rotl32(r32_r(IR[0]))); + prefetch(); + +12c0 fff0 0 rotl.b two r8l s20 + r8_w(IR[0], do_rotl2_8(r8_r(IR[0]))); + prefetch(); + +12d0 fff0 0 rotl.w two r16l s20 + r16_w(IR[0], do_rotl2_16(r16_r(IR[0]))); + prefetch(); + +12f0 fff8 0 rotl.l two r32l s20 + r32_w(IR[0], do_rotl2_32(r32_r(IR[0]))); + prefetch(); + +1300 fff0 0 rotxr.b r8l - + r8_w(IR[0], do_rotxr8(r8_r(IR[0]))); + prefetch(); + +1310 fff0 0 rotxr.w r16l - h + r16_w(IR[0], do_rotxr16(r16_r(IR[0]))); + prefetch(); + +1330 fff8 0 rotxr.l r32l - h + r32_w(IR[0], do_rotxr32(r32_r(IR[0]))); + prefetch(); + +1340 fff0 0 rotxr.b two r8l s20 + r8_w(IR[0], do_rotxr2_8(r8_r(IR[0]))); + prefetch(); + +1350 fff0 0 rotxr.w two r16l s20 + r16_w(IR[0], do_rotxr2_16(r16_r(IR[0]))); + prefetch(); + +1370 fff8 0 rotxr.l two r32l s20 + r32_w(IR[0], do_rotxr2_32(r32_r(IR[0]))); + prefetch(); + +1380 fff0 0 rotr.b r8l - + r8_w(IR[0], do_rotr8(r8_r(IR[0]))); + prefetch(); + +1390 fff0 0 rotr.w r16l - h + r16_w(IR[0], do_rotr16(r16_r(IR[0]))); + prefetch(); + +13b0 fff8 0 rotr.l r32l - h + r32_w(IR[0], do_rotr32(r32_r(IR[0]))); + prefetch(); + +13c0 fff0 0 rotr.b two r8l s20 + r8_w(IR[0], do_rotr2_8(r8_r(IR[0]))); + prefetch(); + +13d0 fff0 0 rotr.w two r16l s20 + r16_w(IR[0], do_rotr2_16(r16_r(IR[0]))); + prefetch(); + +13f0 fff8 0 rotr.l two r32l s20 + r32_w(IR[0], do_rotr2_32(r32_r(IR[0]))); + prefetch(); + +1400 ff00 0 or.b r8h r8l + TMP1 = r8_r(IR[0] >> 4) | r8_r(IR[0]); + set_nzv8(TMP1); + r8_w(IR[0], TMP1); + prefetch(); + +1500 ff00 0 xor.b r8h r8l + TMP1 = r8_r(IR[0] >> 4) ^ r8_r(IR[0]); + set_nzv8(TMP1); + r8_w(IR[0], TMP1); + prefetch(); + +1600 ff00 0 and.b r8h r8l + TMP1 = r8_r(IR[0] >> 4) & r8_r(IR[0]); + set_nzv8(TMP1); + r8_w(IR[0], TMP1); + prefetch(); + +1700 fff0 0 not.b r8l - + TMP1 = ~r8_r(IR[0]); + set_nzv8(TMP1); + r8_w(IR[0], TMP1); + prefetch(); + +1710 fff0 0 not.w r16l - h + TMP1 = ~r16_r(IR[0]); + set_nzv16(TMP1); + r16_w(IR[0], TMP1); + prefetch(); + +1730 fff8 0 not.l r32l - h + TMP1 = ~r32_r(IR[0]); + set_nzv32(TMP1); + r32_w(IR[0], TMP1); + prefetch(); + +1750 fff0 0 extu.w r16l - h + CCR &= ~(F_N|F_Z|F_V); + TMP1 = UINT8(r16_r(IR[0])); + if(!TMP1) + CCR |= F_Z; + r16_w(IR[0], TMP1); + prefetch(); + +1770 fff8 0 extu.l r32l - h + CCR &= ~(F_N|F_Z|F_V); + TMP1 = UINT16(r32_r(IR[0])); + if(!TMP1) + CCR |= F_Z; + r32_w(IR[0], TMP1); + prefetch(); + +1780 fff0 0 neg.b r8l - + r8_w(IR[0], do_sub8(0, r8_r(IR[0]))); + prefetch(); + +1790 fff0 0 neg.w r16l - h + r16_w(IR[0], do_sub16(0, r16_r(IR[0]))); + prefetch(); + +17b0 fff8 0 neg.l r32l - h + r32_w(IR[0], do_sub32(0, r32_r(IR[0]))); + prefetch(); + +17d0 fff0 0 exts.w r16l - h + CCR &= ~(F_N|F_Z|F_V); + TMP1 = INT8(r16_r(IR[0])); + if(!TMP1) + CCR |= F_Z; + r16_w(IR[0], TMP1); + prefetch(); + +17f0 fff8 0 exts.l r32l - h + CCR &= ~(F_N|F_Z|F_V); + TMP1 = INT16(r32_r(IR[0])); + if(!TMP1) + CCR |= F_Z; + r32_w(IR[0], TMP1); + prefetch(); + +1800 ff00 0 sub.b r8h r8l + r8_w(IR[0], do_sub8(r8_r(IR[0]), r8_r(IR[0] >> 4))); + prefetch(); + +1900 ff00 0 sub.w r16h r16l + r16_w(IR[0], do_sub16(r16_r(IR[0]), r16_r(IR[0] >> 4))); + prefetch(); + +1a00 fff0 0 dec.b one r8l + r8_w(IR[0], do_dec8(r8_r(IR[0]), 1)); + prefetch(); + +1a80 ff88 0 sub.l r32h r32l h + r32_w(IR[0], do_sub32(r32_r(IR[0]), r32_r(IR[0] >> 4))); + prefetch(); + +1b00 fff8 0 subs.l one r16l o + r16_w(IR[0], r16_r(IR[0])-1); + prefetch(); + +1b00 fff8 0 subs.l one r32l h + r32_w(IR[0], r32_r(IR[0])-1); + prefetch(); + +1b50 fff0 0 dec.w one r16l + r16_w(IR[0], do_dec16(r16_r(IR[0]), 1)); + prefetch(); + +1b70 fff8 0 dec.l one r32l h + r32_w(IR[0], do_dec32(r32_r(IR[0]), 1)); + prefetch(); + +1b80 fff8 0 subs.l two r16l o + r16_w(IR[0], r16_r(IR[0])-2); + prefetch(); + +1b80 fff8 0 subs.l two r32l h + r32_w(IR[0], r32_r(IR[0])-2); + prefetch(); + +1b90 fff8 0 subs.l four r16l o + r16_w(IR[0], r16_r(IR[0])-4); + prefetch(); + +1b90 fff8 0 subs.l four r32l h + r32_w(IR[0], r32_r(IR[0])-4); + prefetch(); + +1bd0 fff0 0 dec.w two r16l + r16_w(IR[0], do_dec16(r16_r(IR[0]), 2)); + prefetch(); + +1bf0 fff8 0 dec.l two r32l h + r32_w(IR[0], do_dec32(r32_r(IR[0]), 2)); + prefetch(); + +1c00 ff00 0 cmp.b r8h r8l + do_sub8(r8_r(IR[0]), r8_r(IR[0] >> 4)); + prefetch(); + +1d00 ff00 0 cmp.w r16h r16l + do_sub16(r16_r(IR[0]), r16_r(IR[0] >> 4)); + prefetch(); + +1e00 ff00 0 subx.b r8h r8l + r8_w(IR[0], do_subx8(r8_r(IR[0]), r8_r(IR[0] >> 4))); + prefetch(); + +1f00 fff0 0 das.b r8l - + TMP1 = r8_r(IR[0]); + TMP2 = 0; + if(CCR & F_C) { + if(CCR & F_H) { + if((TMP1 & 0xf0) >= 0x60 && (TMP1 & 0x0f) >= 6) + TMP2 = 0x9a; + } else { + if((TMP1 & 0xf0) >= 0x70 && (TMP1 & 0x0f) <= 9) + TMP2 = 0xa0; + } + } else { + if(CCR & F_H) { + if((TMP1 & 0xf0) <= 0x80 && (TMP1 & 0x0f) >= 6) + TMP2 = 0xfa; + } + } + r8_w(IR[0], do_add8(TMP1, TMP2)); + prefetch(); + +1f80 ff88 0 cmp.l r32h r32l h + do_sub32(r32_r(IR[0]), r32_r(IR[0] >> 4)); + prefetch(); + +2000 f000 0 mov.b abs8 r8u + prefetch_start(); + TMP1 = read8(0xffffff00 | IR[0]); + set_nzv8(TMP1); + r8_w(IR[0] >> 8, TMP1); + prefetch_done(); + +3000 f000 0 mov.b r8u abs8 + prefetch_start(); + TMP1 = r8_r(IR[0] >> 8); + set_nzv8(TMP1); + write8(0xffffff00 | IR[0], TMP1); + prefetch_done(); + +4000 ff00 0 bt rel8 - + bxx_8 true + +4100 ff00 0 bf rel8 - + bxx_8 false + +4200 ff00 0 bhi rel8 - + bxx_8 !(CCR & (F_C|F_Z)) + +4300 ff00 0 bls rel8 - + bxx_8 CCR & (F_C|F_Z) + +4400 ff00 0 bcc rel8 - + bxx_8 !(CCR & F_C) + +4500 ff00 0 bcs rel8 - + bxx_8 CCR & F_C + +4600 ff00 0 bne rel8 - + bxx_8 !(CCR & F_Z) + +4700 ff00 0 beq rel8 - + bxx_8 CCR & F_Z + +4800 ff00 0 bvc rel8 - + bxx_8 !(CCR & F_V) + +4900 ff00 0 bvs rel8 - + bxx_8 CCR & F_V + +4a00 ff00 0 bpl rel8 - + bxx_8 !(CCR & F_N) + +4b00 ff00 0 bmi rel8 - + bxx_8 CCR & F_N + +4c00 ff00 0 bge rel8 - + bxx_8 !((CCR & (F_N|F_V)) == F_N || (CCR & (F_N|F_V)) == F_V) + +4d00 ff00 0 blt rel8 - + bxx_8 (CCR & (F_N|F_V)) == F_N || (CCR & (F_N|F_V)) == F_V + +4e00 ff00 0 bgt rel8 - + bxx_8 !((CCR & F_Z) || (CCR & (F_N|F_V)) == F_N || (CCR & (F_N|F_V)) == F_V) + +4f00 ff00 0 ble rel8 - + bxx_8 (CCR & F_Z) || (CCR & (F_N|F_V)) == F_N || (CCR & (F_N|F_V)) == F_V + +5000 ff00 0 mulxu.b r8h r16l + prefetch_start(); + r16_w(IR[0], UINT8(r16_r(IR[0])) * r8_r(IR[0] >> 4)); + internal(2); + prefetch_done(); + +5100 ff00 0 divxu.b r8h r16l + prefetch_start(); + internal(11); + TMP1 = r16_r(IR[0]); + TMP2 = r8_r(IR[0] >> 4); + CCR &= ~(F_Z|F_N); + if(TMP2 & 0x80) + CCR |= F_N; + if(!TMP2) { + CCR |= F_Z; + } else { + int q = TMP1 / TMP2; + int r = TMP1 % TMP2; + r16_w(IR[0], (q & 0xff) | ((r & 0xff) << 8)); + } + prefetch_done(); + +5200 ff08 0 mulxu.w r16h r32l h + prefetch_start(); + r32_w(IR[0], UINT16(r32_r(IR[0])) * r16_r(IR[0] >> 4)); + internal(3); + prefetch_done(); + +5300 ff08 0 divxu.w r16h r32l h + prefetch_start(); + internal(11); + TMP1 = r32_r(IR[0]); + TMP2 = r16_r(IR[0] >> 4); + CCR &= ~(F_Z|F_N); + if(TMP2 & 0x80) + CCR |= F_N; + if(!TMP2) { + CCR |= F_Z; + } else { + int q = TMP1 / TMP2; + int r = TMP1 % TMP2; + r32_w(IR[0], (q & 0xffff) | ((r & 0xffff) << 16)); + } + prefetch_done(); + +5470 ffff 0 rts - - o + fetch(); + TMP1 = r16_r(7); + TMP2 = read16(TMP1); + r16_w(7, TMP1+2); + internal(1); + PC = TMP2; + prefetch(); + +5470 ffff 0 rts - - h + fetch(); + TMP1 = r32_r(7); + if(mode_advanced) { + TMP2 = read16(TMP1) << 16; + TMP2 |= read16(TMP1+2); + r32_w(7, TMP1+4); + } else { + TMP2 = read16(TMP1); + r32_w(7, TMP1+2); + } + internal(1); + PC = TMP2; + prefetch(); + +5500 ff00 0 bsr rel8 - o + TMP2 = PC; + PC += INT8(IR[0]); + jsr16 TMP2 TMP1 + +5500 ff00 0 bsr rel8 - h + TMP2 = PC; + PC += INT8(IR[0]); + jsr32 TMP2 TMP1 + +5670 ffff 0 rte - - o + fetch(); + TMP1 = r16_r(7); + CCR = read16(TMP1) >> 8; + TMP1 = r16_r(7); + TMP2 = read16(TMP1+2); + r16_w(7, TMP1+4); + internal(1); + PC = TMP2; + update_irq_filter(); + prefetch_noirq_notrace(); + +5670 ffff 0 rte - - h + fetch(); + TMP1 = r32_r(7); + if(mode_advanced) { + if(exr_in_stack()) { + EXR = read16(TMP1) >> 8; + TMP1 += 2; + } + TMP2 = read16(TMP1); + CCR = TMP2 >> 8; + TMP2 = (TMP2 & 0xff) << 16; + TMP2 |= read16(TMP1+2); + r32_w(7, TMP1+4); + } else { + TMP2 = read16(TMP1); + r32_w(7, TMP1+2); + } + internal(1); + PC = TMP2; + update_irq_filter(); + prefetch_noirq_notrace(); + +5700 ffcf 0 trapa imm2 - h + internal(1); + TMP1 = r32_r(7) - 2; + r32_w(7, TMP1); + write16(TMP1, NPC); + TMP1 = r32_r(7) - 2; + r32_w(7, TMP1); + write16(TMP1, (CCR << 8) | ((NPC >> 16) & 0xff)); + if(exr_in_stack()) { + TMP1 = r32_r(7) - 2; + r32_w(7, TMP1); + write16(TMP1, EXR << 8); + } + taken_irq_vector = trapa_setup() + ((IR[0] >> 4) & 3); + if(mode_advanced) { + IR[0] = read16i(4*taken_irq_vector); + IR[1] = read16i(4*taken_irq_vector+2); + PC = (IR[0] << 16) | IR[1]; + } else { + PC = read16i(2*taken_irq_vector); + } + internal(1); + update_irq_filter(); + prefetch(); + +5800 ffff 0 bt rel16 - h + bxx_16 true + +5810 ffff 0 bf rel16 - h + bxx_16 false + +5820 ffff 0 bhi rel16 - h + bxx_16 !(CCR & (F_C|F_Z)) + +5830 ffff 0 bls rel16 - h + bxx_16 CCR & (F_C|F_Z) + +5840 ffff 0 bcc rel16 - h + bxx_16 !(CCR & F_C) + +5850 ffff 0 bcs rel16 - h + bxx_16 CCR & F_C + +5860 ffff 0 bne rel16 - h + bxx_16 !(CCR & F_Z) + +5870 ffff 0 beq rel16 - h + bxx_16 CCR & F_Z + +5880 ffff 0 bvc rel16 - h + bxx_16 !(CCR & F_V) + +5890 ffff 0 bvs rel16 - h + bxx_16 CCR & F_V + +58a0 ffff 0 bpl rel16 - h + bxx_16 !(CCR & F_N) + +58b0 ffff 0 bmi rel16 - h + bxx_16 CCR & F_N + +58c0 ffff 0 bge rel16 - h + bxx_16 !((CCR & (F_N|F_V)) == F_N || (CCR & (F_N|F_V)) == F_V) + +58d0 ffff 0 blt rel16 - h + bxx_16 (CCR & (F_N|F_V)) == F_N || (CCR & (F_N|F_V)) == F_V + +58e0 ffff 0 bgt rel16 - h + bxx_16 !((CCR & F_Z) || (CCR & (F_N|F_V)) == F_N || (CCR & (F_N|F_V)) == F_V) + +58f0 ffff 0 ble rel16 - h + bxx_16 (CCR & F_Z) || (CCR & (F_N|F_V)) == F_N || (CCR & (F_N|F_V)) == F_V + +5900 ff8f 0 jmp r32h - h + fetch(); + PC = r32_r(IR[0] >> 4); + prefetch(); + +5a00 ffff 0 jmp abs16e - o + internal(1); + PC = IR[1]; + prefetch(); + +5a00 ff00 0 jmp abs24e - h + internal(1); + PC = ((IR[0] & 0xff) << 16) | IR[1]; + prefetch(); + +5b00 ff00 0 jmp abs8i - o + fetch(); + PC = read16(IR[0] & 0xff); + internal(1); + prefetch(); + +5b00 ff00 0 jmp abs8i - h + fetch(); + if(mode_advanced) { + TMP1 = read16(IR[0] & 0xff) << 16; + TMP1 |= read16((IR[0] & 0xff) + 2); + PC = TMP1; + } else { + PC = read16(IR[0] & 0xff); + } + internal(1); + prefetch(); + +5c00 ffff 0 bsr rel16 - h + internal(1); + TMP2 = PC; + PC += INT16(IR[1]); + jsr32 TMP2 TMP1 + +5d00 ff8f 0 jsr r16h - o + TMP2 = PC; + PC = r16_r(IR[0] >> 4); + jsr16 TMP2 TMP1 + +5d00 ff8f 0 jsr r32h - h + TMP2 = PC; + PC = r32_r(IR[0] >> 4); + jsr32 TMP2 TMP1 + +5e00 ffff 0 jsr abs16e - o + internal(1); + TMP2 = PC; + PC = IR[1]; + jsr16 TMP2 TMP1 + +5e00 ff00 0 jsr abs24e - h + internal(1); + TMP2 = PC; + PC = ((IR[0] & 0xff) << 16) | IR[1]; + jsr32 TMP2 TMP1 + +5f00 ff00 0 jsr abs8i - o + fetch(); + TMP2 = PC; + PC = read16(IR[0] & 0xff); + jsr16 TMP2 TMP1 + +5f00 ff00 0 jsr abs8i - h + fetch(); + TMP2 = PC; + if(mode_advanced) { + TMP1 = read16(IR[0] & 0xff) << 16; + TMP1 |= read16((IR[0] & 0xff) + 2); + PC = TMP1; + } else { + PC = read16(IR[0] & 0xff); + } + jsr32 TMP2 TMP1 + +6000 ff00 0 bset r8h r8l + TMP1 = r8_r(IR[0]); + bset r8_r(IR[0] >> 4) + r8_w(IR[0], TMP1); + prefetch(); + +6100 ff00 0 bnot r8h r8l + TMP1 = r8_r(IR[0]); + bnot r8_r(IR[0] >> 4) + r8_w(IR[0], TMP1); + prefetch(); + +6200 ff00 0 bclr r8h r8l + TMP1 = r8_r(IR[0]); + bclr r8_r(IR[0] >> 4) + r8_w(IR[0], TMP1); + prefetch(); + +6300 ff00 0 btst r8h r8l + TMP1 = r8_r(IR[0]); + btst r8_r(IR[0] >> 4) + prefetch(); + +6400 ff00 0 or.w r16h r16l h + TMP1 = r16_r(IR[0] >> 4) | r16_r(IR[0]); + set_nzv16(TMP1); + r16_w(IR[0], TMP1); + prefetch(); + +6500 ff00 0 xor.w r16h r16l h + TMP1 = r16_r(IR[0] >> 4) ^ r16_r(IR[0]); + set_nzv16(TMP1); + r16_w(IR[0], TMP1); + prefetch(); + +6600 ff00 0 and.w r16h r16l h + TMP1 = r16_r(IR[0] >> 4) & r16_r(IR[0]); + set_nzv16(TMP1); + r16_w(IR[0], TMP1); + prefetch(); + +6700 ff80 0 bst imm3 r8l + TMP1 = r8_r(IR[0]); + bst IR[0] >> 4 + r8_w(IR[0], TMP1); + prefetch(); + +6780 ff80 0 bist imm3 r8l + TMP1 = r8_r(IR[0]); + bist IR[0] >> 4 + r8_w(IR[0], TMP1); + prefetch(); + +6800 ff80 0 mov.b r16ih r8l o + prefetch_start(); + TMP1 = read8(r16_r(IR[0] >> 4)); + set_nzv8(TMP1); + r8_w(IR[0], TMP1); + prefetch_done(); + +6800 ff80 0 mov.b r32ih r8l h + prefetch_start(); + TMP1 = read8(r32_r(IR[0] >> 4)); + set_nzv8(TMP1); + r8_w(IR[0], TMP1); + prefetch_done(); + +6880 ff80 0 mov.b r8l r16ih o + prefetch_start(); + TMP1 = r8_r(IR[0]); + set_nzv8(TMP1); + write8(r16_r((IR[0] >> 4) & 7), TMP1); + prefetch_done(); + +6880 ff80 0 mov.b r8l r32ih h + prefetch_start(); + TMP1 = r8_r(IR[0]); + set_nzv8(TMP1); + write8(r32_r(IR[0] >> 4), TMP1); + prefetch_done(); + +6900 ff88 0 mov.w r16ih r16l o + prefetch_start(); + TMP1 = read16(r16_r(IR[0] >> 4)); + set_nzv16(TMP1); + r16_w(IR[0], TMP1); + prefetch_done(); + +6900 ff80 0 mov.w r32ih r16l h + prefetch_start(); + TMP1 = read16(r32_r(IR[0] >> 4)); + set_nzv16(TMP1); + r16_w(IR[0], TMP1); + prefetch_done(); + +6980 ff88 0 mov.w r16l r16ih o + prefetch_start(); + TMP1 = r16_r(IR[0]); + set_nzv16(TMP1); + write16(r16_r((IR[0] >> 4) & 7), TMP1); + prefetch_done(); + +6980 ff80 0 mov.w r16l r32ih h + prefetch_start(); + TMP1 = r16_r(IR[0]); + set_nzv16(TMP1); + write16(r32_r(IR[0] >> 4), TMP1); + prefetch_done(); + +6a00 fff0 0 mov.b abs16 r8l + prefetch_start(); + TMP1 = read8(INT16(IR[1])); + set_nzv8(TMP1); + r8_w(IR[0], TMP1); + prefetch_done(); + +6a106300 ffffff0f 1 btst r8h abs16 + TMP2 = INT16(IR[1]); + TMP1 = read8(TMP2); + btst r8_r(IR[2] >> 4) + prefetch(); + +6a107300 ffffff8f 1 btst imm3 abs16 + TMP2 = INT16(IR[1]); + TMP1 = read8(TMP2); + btst IR[2] >> 4 + prefetch(); + +6a107400 ffffff8f 1 bor imm3 abs16 + TMP2 = INT16(IR[1]); + TMP1 = read8(TMP2); + bor IR[2] >> 4 + prefetch(); + +6a107480 ffffff8f 1 bior imm3 abs16 + TMP2 = INT16(IR[1]); + TMP1 = read8(TMP2); + bior IR[2] >> 4 + prefetch(); + +6a107500 ffffff8f 1 bxor imm3 abs16 + TMP2 = INT16(IR[1]); + TMP1 = read8(TMP2); + bxor IR[2] >> 4 + prefetch(); + +6a107580 ffffff8f 1 bixor imm3 abs16 + TMP2 = INT16(IR[1]); + TMP1 = read8(TMP2); + bixor IR[2] >> 4 + prefetch(); + +6a107600 ffffff8f 1 band imm3 abs16 + TMP2 = INT16(IR[1]); + TMP1 = read8(TMP2); + band IR[2] >> 4 + prefetch(); + +6a107680 ffffff8f 1 biand imm3 abs16 + TMP2 = INT16(IR[1]); + TMP1 = read8(TMP2); + biand IR[2] >> 4 + prefetch(); + +6a107700 ffffff8f 1 bld imm3 abs16 + TMP2 = INT16(IR[1]); + TMP1 = read8(TMP2); + bld IR[2] >> 4 + prefetch(); + +6a107780 ffffff8f 1 bild imm3 abs16 + TMP2 = INT16(IR[1]); + TMP1 = read8(TMP2); + bild IR[2] >> 4 + prefetch(); + +6a186000 ffffff0f 1 bset r8h abs16 + TMP2 = INT16(IR[1]); + TMP1 = read8(TMP2); + prefetch_start(); + bset r8_r(IR[2] >> 4) + write8(TMP2, TMP1); + prefetch_done(); + +6a186100 ffffff0f 1 bnot r8h abs16 + TMP2 = INT16(IR[1]); + TMP1 = read8(TMP2); + prefetch_start(); + bnot r8_r(IR[2] >> 4) + write8(TMP2, TMP1); + prefetch_done(); + +6a186200 ffffff0f 1 bclr r8h abs16 + TMP2 = INT16(IR[1]); + TMP1 = read8(TMP2); + prefetch_start(); + bclr r8_r(IR[2] >> 4) + write8(TMP2, TMP1); + prefetch_done(); + +6a186700 ffffff8f 1 bst imm3 abs16 + TMP2 = INT16(IR[2]); + TMP1 = read8(TMP2); + prefetch_start(); + bst IR[2] >> 4 + write8(TMP2, TMP1); + prefetch_done(); + +6a186780 ffffff8f 1 bist imm3 abs16 + TMP2 = INT16(IR[1]); + TMP1 = read8(TMP2); + prefetch_start(); + bist IR[2] >> 4 + write8(TMP2, TMP1); + prefetch_done(); + +6a187000 ffffff8f 1 bset imm3 abs16 + TMP2 = INT16(IR[1]); + TMP1 = read8(TMP2); + prefetch_start(); + bset IR[2] >> 4 + write8(TMP2, TMP1); + prefetch_done(); + +6a187100 ffffff8f 1 bnot imm3 abs16 + TMP2 = INT16(IR[1]); + TMP1 = read8(TMP2); + prefetch_start(); + bnot IR[2] >> 4 + write8(TMP2, TMP1); + prefetch_done(); + +6a187200 ffffff8f 1 bclr imm3 abs16 + TMP2 = INT16(IR[1]); + TMP1 = read8(TMP2); + prefetch_start(); + bclr IR[2] >> 4 + write8(TMP2, TMP1); + prefetch_done(); + +6a20 fff0 0 mov.b abs32 r8l h + prefetch_start(); + TMP1 = read8((IR[1] << 16) | IR[2]); + set_nzv8(TMP1); + r8_w(IR[0], TMP1); + prefetch_done(); + +6a306300 ffffff0f 2 btst r8h abs32 h + TMP2 = (IR[1] << 16) | IR[2]; + TMP1 = read8(TMP2); + btst r8_r(IR[3] >> 4) + prefetch(); + +6a307300 ffffff8f 2 btst imm3 abs32 h + TMP2 = (IR[1] << 16) | IR[2]; + TMP1 = read8(TMP2); + btst IR[3] >> 4 + prefetch(); + +6a307400 ffffff8f 2 bor imm3 abs32 h + TMP2 = (IR[1] << 16) | IR[2]; + TMP1 = read8(TMP2); + bor IR[3] >> 4 + prefetch(); + +6a307480 ffffff8f 2 bior imm3 abs32 h + TMP2 = (IR[1] << 16) | IR[2]; + TMP1 = read8(TMP2); + bior IR[3] >> 4 + prefetch(); + +6a307500 ffffff8f 2 bxor imm3 abs32 h + TMP2 = (IR[1] << 16) | IR[2]; + TMP1 = read8(TMP2); + bxor IR[3] >> 4 + prefetch(); + +6a307580 ffffff8f 2 bixor imm3 abs32 h + TMP2 = (IR[1] << 16) | IR[2]; + TMP1 = read8(TMP2); + bixor IR[3] >> 4 + prefetch(); + +6a307600 ffffff8f 2 band imm3 abs32 h + TMP2 = (IR[1] << 16) | IR[2]; + TMP1 = read8(TMP2); + band IR[3] >> 4 + prefetch(); + +6a307680 ffffff8f 2 biand imm3 abs32 h + TMP2 = (IR[1] << 16) | IR[2]; + TMP1 = read8(TMP2); + biand IR[3] >> 4 + prefetch(); + +6a307700 ffffff8f 2 bld imm3 abs32 h + TMP2 = (IR[1] << 16) | IR[2]; + TMP1 = read8(TMP2); + bld IR[3] >> 4 + prefetch(); + +6a307780 ffffff8f 2 bild imm3 abs32 h + TMP2 = (IR[1] << 16) | IR[2]; + TMP1 = read8(TMP2); + bild IR[3] >> 4 + prefetch(); + +6a386000 ffffff0f 2 bset r8h abs32 h + TMP2 = (IR[1] << 16) | IR[2]; + TMP1 = read8(TMP2); + prefetch_start(); + bset r8_r(IR[3] >> 4) + write8(TMP2, TMP1); + prefetch_done(); + +6a386100 ffffff0f 2 bnot r8h abs32 h + TMP2 = (IR[1] << 16) | IR[2]; + TMP1 = read8(TMP2); + prefetch_start(); + bnot r8_r(IR[3] >> 4) + write8(TMP2, TMP1); + prefetch_done(); + +6a386200 ffffff0f 2 bclr r8h abs32 h + TMP2 = (IR[1] << 16) | IR[2]; + TMP1 = read8(TMP2); + prefetch_start(); + bclr r8_r(IR[3] >> 4) + write8(TMP2, TMP1); + prefetch_done(); + +6a386700 ffffff8f 2 bst imm3 abs32 h + TMP2 = (IR[1] << 16) | IR[2]; + TMP1 = read8(TMP2); + prefetch_start(); + bst IR[3] >> 4 + write8(TMP2, TMP1); + prefetch_done(); + +6a386780 ffffff8f 2 bist imm3 abs32 h + TMP2 = (IR[1] << 16) | IR[2]; + TMP1 = read8(TMP2); + prefetch_start(); + bist IR[3] >> 4 + write8(TMP2, TMP1); + prefetch_done(); + +6a387000 ffffff8f 2 bset imm3 abs32 h + TMP2 = (IR[1] << 16) | IR[2]; + TMP1 = read8(TMP2); + prefetch_start(); + bset IR[3] >> 4 + write8(TMP2, TMP1); + prefetch_done(); + +6a387100 ffffff8f 2 bnot imm3 abs32 h + TMP2 = (IR[1] << 16) | IR[2]; + TMP1 = read8(TMP2); + prefetch_start(); + bnot IR[3] >> 4 + write8(TMP2, TMP1); + prefetch_done(); + +6a387200 ffffff8f 2 bclr imm3 abs32 h + TMP2 = (IR[1] << 16) | IR[2]; + TMP1 = read8(TMP2); + prefetch_start(); + bclr IR[3] >> 4 + write8(TMP2, TMP1); + prefetch_done(); + +6a40 fff0 0 movfpe abs16 r8l +6a80 fff0 0 mov.b r8l abs16 + prefetch_start(); + TMP1 = r8_r(IR[0]); + set_nzv8(TMP1); + write8(INT16(IR[1]), TMP1); + prefetch_done(); + +6aa0 fff0 0 mov.b r8l abs32 h + prefetch_start(); + TMP1 = r8_r(IR[0]); + set_nzv8(TMP1); + write8((IR[1] << 16) | IR[2], TMP1); + prefetch_done(); + +6ac0 fff0 0 movtpe r8l abs16 +6b00 fff0 0 mov.w abs16 r16l + prefetch_start(); + TMP1 = read16(INT16(IR[1])); + set_nzv16(TMP1); + r16_w(IR[0], TMP1); + prefetch_done(); + +6b20 fff0 0 mov.w abs32 r16l h + prefetch_start(); + TMP1 = read16((IR[1] << 16) | IR[2]); + set_nzv16(TMP1); + r16_w(IR[0], TMP1); + prefetch_done(); + +6b80 fff0 0 mov.w r16l abs16 + prefetch_start(); + TMP1 = r16_r(IR[0]); + set_nzv16(TMP1); + write16(INT16(IR[1]), TMP1); + prefetch_done(); + +6ba0 fff0 0 mov.w r16l abs32 h + prefetch_start(); + TMP1 = r16_r(IR[0]); + set_nzv16(TMP1); + write16((IR[1] << 16) | IR[2], TMP1); + prefetch_done(); + +6c00 ff80 0 mov.b r16ph r8l o + TMP2 = r16_r(IR[0] >> 4); + prefetch_start(); + internal(1); + TMP1 = read8(TMP2); + TMP2 += 1; + r16_w(IR[0] >> 4, TMP2); + set_nzv8(TMP1); + r8_w(IR[0], TMP1); + prefetch_done(); + +6c00 ff80 0 mov.b r32ph r8l h + TMP2 = r32_r(IR[0] >> 4); + prefetch_start(); + internal(1); + TMP1 = read8(TMP2); + TMP2 += 1; + r32_w(IR[0] >> 4, TMP2); + set_nzv8(TMP1); + r8_w(IR[0], TMP1); + prefetch_done(); + +6c80 ff80 0 mov.b r8l pr16h o + TMP1 = r8_r(IR[0]); + TMP2 = r16_r((IR[0] >> 4) & 7); + prefetch_start(); + internal(1); + TMP2 -= 1; + r16_w((IR[0] >> 4) & 7, TMP2); + set_nzv8(TMP1); + write8(TMP2, TMP1); + prefetch_done(); + +6c80 ff80 0 mov.b r8l pr32h h + TMP1 = r8_r(IR[0]); + TMP2 = r32_r(IR[0] >> 4); + prefetch_start(); + internal(1); + TMP2 -= 1; + r32_w(IR[0] >> 4, TMP2); + set_nzv8(TMP1); + write8(TMP2, TMP1); + prefetch_done(); + +6d00 ff88 0 mov.w r16ph r16l o + TMP2 = r16_r(IR[0] >> 4); + prefetch_start(); + internal(1); + TMP1 = read16(TMP2); + TMP2 += 2; + r16_w(IR[0] >> 4, TMP2); + set_nzv16(TMP1); + r16_w(IR[0], TMP1); + prefetch_done(); + +6d00 ff80 0 mov.w r32ph r16l h + TMP2 = r32_r(IR[0] >> 4); + prefetch_start(); + internal(1); + TMP1 = read16(TMP2); + TMP2 += 2; + r32_w(IR[0] >> 4, TMP2); + set_nzv16(TMP1); + r16_w(IR[0], TMP1); + prefetch_done(); + +6d80 ff88 0 mov.w r16l pr16h o + TMP1 = r16_r(IR[0]); + TMP2 = r16_r((IR[0] >> 4) & 7); + prefetch_start(); + internal(1); + TMP2 -= 2; + r16_w((IR[0] >> 4) & 7, TMP2); + set_nzv16(TMP1); + write16(TMP2, TMP1); + prefetch_done(); + +6d80 ff80 0 mov.w r16l pr32h h + TMP1 = r16_r(IR[0]); + TMP2 = r32_r(IR[0] >> 4); + prefetch_start(); + internal(1); + TMP2 -= 2; + r32_w(IR[0] >> 4, TMP2); + set_nzv16(TMP1); + write16(TMP2, TMP1); + prefetch_done(); + +6e00 ff80 0 mov.b r16d16h r8l o + prefetch_start(); + TMP1 = UINT16(r16_r(IR[0] >> 4) + IR[1]); + TMP2 = read8(TMP1); + set_nzv8(TMP2); + r8_w(IR[0], TMP2); + prefetch_done(); + +6e00 ff80 0 mov.b r32d16h r8l h + prefetch_start(); + TMP1 = r32_r(IR[0] >> 4) + INT16(IR[1]); + TMP2 = read8(TMP1); + set_nzv8(TMP2); + r8_w(IR[0], TMP2); + prefetch_done(); + +6e80 ff80 0 mov.b r8l r16d16h o + prefetch_start(); + TMP1 = UINT16(r16_r((IR[0] >> 4) & 7) + IR[1]); + TMP2 = r8_r(IR[0]); + set_nzv8(TMP2); + write8(TMP1, TMP2); + prefetch_done(); + +6e80 ff80 0 mov.b r8l r32d16h h + prefetch_start(); + TMP1 = r32_r(IR[0] >> 4) + INT16(IR[1]); + TMP2 = r8_r(IR[0]); + set_nzv8(TMP2); + write8(TMP1, TMP2); + prefetch_done(); + +6f00 ff80 0 mov.w r16d16h r16l o + prefetch_start(); + TMP1 = UINT16(r16_r(IR[0] >> 4) + IR[1]); + TMP2 = read16(TMP1); + set_nzv16(TMP2); + r16_w(IR[0], TMP2); + prefetch_done(); + +6f00 ff80 0 mov.w r32d16h r16l h + prefetch_start(); + TMP1 = r32_r(IR[0] >> 4) + INT16(IR[1]); + TMP2 = read16(TMP1); + set_nzv16(TMP2); + r16_w(IR[0], TMP2); + prefetch_done(); + +6f80 ff80 0 mov.w r16l r16d16h o + prefetch_start(); + TMP1 = UINT16(r16_r((IR[0] >> 4) & 7) + IR[1]); + TMP2 = r16_r(IR[0]); + set_nzv16(TMP2); + write16(TMP1, TMP2); + prefetch_done(); + +6f80 ff80 0 mov.w r16l r32d16h h + prefetch_start(); + TMP1 = r32_r(IR[0] >> 4) + INT16(IR[1]); + TMP2 = r16_r(IR[0]); + set_nzv16(TMP2); + write16(TMP1, TMP2); + prefetch_done(); + +7000 ff80 0 bset imm3 r8l + TMP1 = r8_r(IR[0]); + bset IR[0] >> 4 + r8_w(IR[0], TMP1); + prefetch(); + +7100 ff80 0 bnot imm3 r8l + TMP1 = r8_r(IR[0]); + bnot IR[0] >> 4 + r8_w(IR[0], TMP1); + prefetch(); + +7200 ff80 0 bclr imm3 r8l + TMP1 = r8_r(IR[0]); + bclr IR[0] >> 4 + r8_w(IR[0], TMP1); + prefetch(); + +7300 ff80 0 btst imm3 r8l + TMP1 = r8_r(IR[0]); + btst IR[0] >> 4 + prefetch(); + +7400 ff80 0 bor imm3 r8l + TMP1 = r8_r(IR[0]); + bor IR[0] >> 4 + prefetch(); + +7480 ff80 0 bior imm3 r8l + TMP1 = r8_r(IR[0]); + bior IR[0] >> 4 + prefetch(); + +7500 ff80 0 bxor imm3 r8l + TMP1 = r8_r(IR[0]); + bxor IR[0] >> 4 + prefetch(); + +7580 ff80 0 bixor imm3 r8l + TMP1 = r8_r(IR[0]); + bixor IR[0] >> 4 + prefetch(); + +7600 ff80 0 band imm3 r8l + TMP1 = r8_r(IR[0]); + band IR[0] >> 4 + prefetch(); + +7680 ff80 0 biand imm3 r8l + TMP1 = r8_r(IR[0]); + biand IR[0] >> 4 + prefetch(); + +7700 ff80 0 bld imm3 r8l + TMP1 = r8_r(IR[0]); + bld IR[0] >> 4 + prefetch(); + +7780 ff80 0 bild imm3 r8l + TMP1 = r8_r(IR[0]); + bild IR[0] >> 4 + prefetch(); + +78006a20 ff8ffff0 0 mov.b r32d32hh r8l h + prefetch_start(); + TMP1 = r32_r(IR[0] >> 4) + (IR[2] << 16) + IR[3]; + TMP2 = read8(TMP1); + set_nzv8(TMP2); + r8_w(IR[1], TMP2); + prefetch_done(); + +78006aa0 ff8ffff0 0 mov.b r8l r32d32hh h + prefetch_start(); + TMP1 = r32_r(IR[0] >> 4) + (IR[2] << 16) + IR[3]; + TMP2 = r8_r(IR[1]); + set_nzv8(TMP2); + write8(TMP1, TMP2); + prefetch_done(); + +78006b20 ff8ffff0 0 mov.w r32d32hh r16l h + prefetch_start(); + TMP1 = r32_r(IR[0] >> 4) + (IR[2] << 16) + IR[3]; + TMP2 = read16(TMP1); + set_nzv16(TMP2); + r16_w(IR[1], TMP2); + prefetch_done(); + +78006ba0 ff8ffff0 0 mov.w r16l r32d32hh h + prefetch_start(); + TMP1 = r32_r(IR[0] >> 4) + (IR[2] << 16) + IR[3]; + TMP2 = r16_r(IR[1]); + set_nzv16(TMP2); + write16(TMP1, TMP2); + prefetch_done(); + +7900 fff0 0 mov.w imm16 r16l + set_nzv16(IR[1]); + r16_w(IR[0], IR[1]); + prefetch(); + +7910 fff0 0 add.w imm16 r16l + r16_w(IR[0], do_add16(r16_r(IR[0]), IR[1])); + prefetch(); + +7920 fff0 0 cmp.w imm16 r16l + do_sub16(r16_r(IR[0]), IR[1]); + prefetch(); + +7930 fff0 0 sub.w imm16 r16l + r16_w(IR[0], do_sub16(r16_r(IR[0]), IR[1])); + prefetch(); + +7940 fff0 0 or.w imm16 r16l + TMP1 = IR[1] | r16_r(IR[0]); + set_nzv16(TMP1); + r16_w(IR[0], TMP1); + prefetch(); + +7950 fff0 0 xor.w imm16 r16l + TMP1 = IR[1] ^ r16_r(IR[0]); + set_nzv16(TMP1); + r16_w(IR[0], TMP1); + prefetch(); + +7960 fff0 0 and.w imm16 r16l + TMP1 = IR[1] & r16_r(IR[0]); + set_nzv16(TMP1); + r16_w(IR[0], TMP1); + prefetch(); + +7a00 fff8 0 mov.l imm32 r32l h + TMP1 = (IR[1] << 16) | IR[2]; + set_nzv32(TMP1); + r32_w(IR[0], TMP1); + prefetch(); + +7a10 fff8 0 add.l imm32 r32l h + r32_w(IR[0], do_add32(r32_r(IR[0]), (IR[1] << 16) | IR[2])); + prefetch(); + +7a20 fff8 0 cmp.l imm32 r32l h + do_sub32(r32_r(IR[0]), (IR[1] << 16) | IR[2]); + prefetch(); + +7a30 fff8 0 sub.l imm32 r32l h + r32_w(IR[0], do_sub32(r32_r(IR[0]), (IR[1] << 16) | IR[2])); + prefetch(); + +7a40 fff8 0 or.l imm32 r32l h + TMP1 = r32_r(IR[0]) | ((IR[1] << 16) | IR[2]); + set_nzv32(TMP1); + r32_w(IR[0], TMP1); + prefetch(); + +7a50 fff8 0 xor.l imm32 r32l h + TMP1 = r32_r(IR[0]) ^ ((IR[1] << 16) | IR[2]); + set_nzv32(TMP1); + r32_w(IR[0], TMP1); + prefetch(); + +7a60 fff8 0 and.l imm32 r32l h + TMP1 = r32_r(IR[0]) & ((IR[1] << 16) | IR[2]); + set_nzv32(TMP1); + r32_w(IR[0], TMP1); + prefetch(); + +7b5c598f ffffffff 0 eepmov.b - - o + while(r8_r(4)) { + TMP1 = read8(r16_r(5)); + write8(r16_r(6), TMP1); + r16_w(5, r16_r(5)+1); + r16_w(6, r16_r(6)+1); + r8_w(4, r8_r(4)-1); + } + prefetch(); + +7b5c598f ffffffff 0 eepmov.b - - h + while(r8_r(4)) { + TMP1 = read8(r32_r(5)); + write8(r32_r(6), TMP1); + r32_w(5, r32_r(5)+1); + r32_w(6, r32_r(6)+1); + r8_w(4, r8_r(4)-1); + } + prefetch(); + +7bd4598f ffffffff 0 eepmov.w - - h + while(r16_r(4)) { + TMP1 = read8(r32_r(5)); + write8(r32_r(6), TMP1); + r32_w(5, r32_r(5)+1); + r32_w(6, r32_r(6)+1); + r16_w(4, r16_r(4)-1); + } + prefetch(); + +7c006300 ff8fff0f 0 btst r8h r16ihh o + TMP2 = r16_r(IR[0] >> 4); + TMP1 = read8(TMP2); + btst r8_r(IR[1] >> 4) + prefetch(); + +7c006300 ff8fff0f 0 btst r8h r32ihh h + TMP2 = r32_r(IR[0] >> 4); + TMP1 = read8(TMP2); + btst r8_r(IR[1] >> 4) + prefetch(); + +7c007300 ff8fff8f 0 btst imm3 r16ihh o + TMP2 = r16_r(IR[0] >> 4); + TMP1 = read8(TMP2); + btst IR[1] >> 4 + prefetch(); + +7c007300 ff8fff8f 0 btst imm3 r32ihh h + TMP2 = r32_r(IR[0] >> 4); + TMP1 = read8(TMP2); + btst IR[1] >> 4 + prefetch(); + +7c007400 ff8fff8f 0 bor imm3 r16ihh o + TMP2 = r16_r(IR[0] >> 4); + TMP1 = read8(TMP2); + bor IR[1] >> 4 + prefetch(); + +7c007400 ff8fff8f 0 bor imm3 r32ihh h + TMP2 = r32_r(IR[0] >> 4); + TMP1 = read8(TMP2); + bor IR[1] >> 4 + prefetch(); + +7c007480 ff8fff8f 0 bior imm3 r16ihh o + TMP2 = r16_r(IR[0] >> 4); + TMP1 = read8(TMP2); + bior IR[1] >> 4 + prefetch(); + +7c007480 ff8fff8f 0 bior imm3 r32ihh h + TMP2 = r32_r(IR[0] >> 4); + TMP1 = read8(TMP2); + bior IR[1] >> 4 + prefetch(); + +7c007500 ff8fff8f 0 bxor imm3 r16ihh o + TMP2 = r16_r(IR[0] >> 4); + TMP1 = read8(TMP2); + bxor IR[1] >> 4 + prefetch(); + +7c007500 ff8fff8f 0 bxor imm3 r32ihh h + TMP2 = r32_r(IR[0] >> 4); + TMP1 = read8(TMP2); + bxor IR[1] >> 4 + prefetch(); + +7c007580 ff8fff8f 0 bixor imm3 r16ihh o + TMP2 = r16_r(IR[0] >> 4); + TMP1 = read8(TMP2); + bixor IR[1] >> 4 + prefetch(); + +7c007580 ff8fff8f 0 bixor imm3 r32ihh h + TMP2 = r32_r(IR[0] >> 4); + TMP1 = read8(TMP2); + bixor IR[1] >> 4 + prefetch(); + +7c007600 ff8fff8f 0 band imm3 r16ihh o + TMP2 = r16_r(IR[0] >> 4); + TMP1 = read8(TMP2); + band IR[1] >> 4 + prefetch(); + +7c007600 ff8fff8f 0 band imm3 r32ihh h + TMP2 = r32_r(IR[0] >> 4); + TMP1 = read8(TMP2); + band IR[1] >> 4 + prefetch(); + +7c007680 ff8fff8f 0 biand imm3 r16ihh o + TMP2 = r16_r(IR[0] >> 4); + TMP1 = read8(TMP2); + biand IR[1] >> 4 + prefetch(); + +7c007680 ff8fff8f 0 biand imm3 r32ihh h + TMP2 = r32_r(IR[0] >> 4); + TMP1 = read8(TMP2); + biand IR[1] >> 4 + prefetch(); + +7c007700 ff8fff8f 0 bld imm3 r16ihh o + TMP2 = r16_r(IR[0] >> 4); + TMP1 = read8(TMP2); + bld IR[1] >> 4 + prefetch(); + +7c007700 ff8fff8f 0 bld imm3 r32ihh h + TMP2 = r32_r(IR[0] >> 4); + TMP1 = read8(TMP2); + bld IR[1] >> 4 + prefetch(); + +7c007780 ff8fff8f 0 bild imm3 r16ihh o + TMP2 = r16_r(IR[0] >> 4); + TMP1 = read8(TMP2); + bild IR[1] >> 4 + prefetch(); + +7c007780 ff8fff8f 0 bild imm3 r32ihh h + TMP2 = r32_r(IR[0] >> 4); + TMP1 = read8(TMP2); + bild IR[1] >> 4 + prefetch(); + +7d006000 ff8fff0f 0 bset r8h r16ihh o + TMP2 = r16_r(IR[0] >> 4); + TMP1 = read8(TMP2); + bset r8_r(IR[1] >> 4) + prefetch_start(); + write8(TMP2, TMP1); + prefetch_done(); + +7d006000 ff8fff0f 0 bset r8h r32ihh h + TMP2 = r32_r(IR[0] >> 4); + TMP1 = read8(TMP2); + bset r8_r(IR[1] >> 4) + prefetch_start(); + write8(TMP2, TMP1); + prefetch_done(); + +7d006100 ff8fff0f 0 bnot r8h r16ihh o + TMP2 = r16_r(IR[0] >> 4); + TMP1 = read8(TMP2); + bnot r8_r(IR[1] >> 4) + prefetch_start(); + write8(TMP2, TMP1); + prefetch_done(); + +7d006100 ff8fff0f 0 bnot r8h r32ihh h + TMP2 = r32_r(IR[0] >> 4); + TMP1 = read8(TMP2); + bnot r8_r(IR[1] >> 4) + prefetch_start(); + write8(TMP2, TMP1); + prefetch_done(); + +7d006200 ff8fff0f 0 bclr r8h r16ihh o + TMP2 = r16_r(IR[0] >> 4); + TMP1 = read8(TMP2); + bclr r8_r(IR[1] >> 4) + prefetch_start(); + write8(TMP2, TMP1); + prefetch_done(); + +7d006200 ff8fff0f 0 bclr r8h r32ihh h + TMP2 = r32_r(IR[0] >> 4); + TMP1 = read8(TMP2); + bclr r8_r(IR[1] >> 4) + prefetch_start(); + write8(TMP2, TMP1); + prefetch_done(); + +7d006700 ff8fff8f 0 bst imm3 r16ihh o + TMP2 = r16_r(IR[0] >> 4); + TMP1 = read8(TMP2); + bst IR[1] >> 4 + prefetch_start(); + write8(TMP2, TMP1); + prefetch_done(); + +7d006700 ff8fff8f 0 bst imm3 r32ihh h + TMP2 = r32_r(IR[0] >> 4); + TMP1 = read8(TMP2); + bst IR[1] >> 4 + prefetch_start(); + write8(TMP2, TMP1); + prefetch_done(); + +7d006780 ff8fff8f 0 bist imm3 r16ihh o + TMP2 = r16_r(IR[0] >> 4); + TMP1 = read8(TMP2); + bist IR[1] >> 4 + prefetch_start(); + write8(TMP2, TMP1); + prefetch_done(); + +7d006780 ff8fff8f 0 bist imm3 r32ihh h + TMP2 = r32_r(IR[0] >> 4); + TMP1 = read8(TMP2); + bist IR[1] >> 4 + prefetch_start(); + write8(TMP2, TMP1); + prefetch_done(); + +7d007000 ff8fff8f 0 bset imm3 r16ihh o + TMP2 = r16_r(IR[0] >> 4); + TMP1 = read8(TMP2); + bset IR[1] >> 4 + prefetch_start(); + write8(TMP2, TMP1); + prefetch_done(); + +7d007000 ff8fff8f 0 bset imm3 r32ihh h + TMP2 = r32_r(IR[0] >> 4); + TMP1 = read8(TMP2); + bset IR[1] >> 4 + prefetch_start(); + write8(TMP2, TMP1); + prefetch_done(); + +7d007100 ff8fff8f 0 bnot imm3 r16ihh o + TMP2 = r16_r(IR[0] >> 4); + TMP1 = read8(TMP2); + bnot IR[1] >> 4 + prefetch_start(); + write8(TMP2, TMP1); + prefetch_done(); + +7d007100 ff8fff8f 0 bnot imm3 r32ihh h + TMP2 = r32_r(IR[0] >> 4); + TMP1 = read8(TMP2); + bnot IR[1] >> 4 + prefetch_start(); + write8(TMP2, TMP1); + prefetch_done(); + +7d007200 ff8fff8f 0 bclr imm3 r16ihh o + TMP2 = r16_r(IR[0] >> 4); + TMP1 = read8(TMP2); + bclr IR[1] >> 4 + prefetch_start(); + write8(TMP2, TMP1); + prefetch_done(); + +7d007200 ff8fff8f 0 bclr imm3 r32ihh h + TMP2 = r32_r(IR[0] >> 4); + TMP1 = read8(TMP2); + bclr IR[1] >> 4 + prefetch_start(); + write8(TMP2, TMP1); + prefetch_done(); + +7e006300 ff00ff0f 0 btst r8h abs8 + TMP2 = 0xffffff00 | IR[0]; + TMP1 = read8(TMP2); + btst r8_r(IR[1] >> 4) + prefetch(); + +7e007300 ff00ff8f 0 btst imm3 abs8 + TMP2 = 0xffffff00 | IR[0]; + TMP1 = read8(TMP2); + btst IR[1] >> 4 + prefetch(); + +7e007400 ff00ff8f 0 bor imm3 abs8 + TMP2 = 0xffffff00 | IR[0]; + TMP1 = read8(TMP2); + bor IR[1] >> 4 + prefetch(); + +7e007480 ff00ff8f 0 bior imm3 abs8 + TMP2 = 0xffffff00 | IR[0]; + TMP1 = read8(TMP2); + bior IR[1] >> 4 + prefetch(); + +7e007500 ff00ff8f 0 bxor imm3 abs8 + TMP2 = 0xffffff00 | IR[0]; + TMP1 = read8(TMP2); + bxor IR[1] >> 4 + prefetch(); + +7e007580 ff00ff8f 0 bixor imm3 abs8 + TMP2 = 0xffffff00 | IR[0]; + TMP1 = read8(TMP2); + bixor IR[1] >> 4 + prefetch(); + +7e007600 ff00ff8f 0 band imm3 abs8 + TMP2 = 0xffffff00 | IR[0]; + TMP1 = read8(TMP2); + band IR[1] >> 4 + prefetch(); + +7e007680 ff00ff8f 0 biand imm3 abs8 + TMP2 = 0xffffff00 | IR[0]; + TMP1 = read8(TMP2); + biand IR[1] >> 4 + prefetch(); + +7e007700 ff00ff8f 0 bld imm3 abs8 + TMP2 = 0xffffff00 | IR[0]; + TMP1 = read8(TMP2); + bld IR[1] >> 4 + prefetch(); + +7e007780 ff00ff8f 0 bild imm3 abs8 + TMP2 = 0xffffff00 | IR[0]; + TMP1 = read8(TMP2); + bild IR[1] >> 4 + prefetch(); + +7f006000 ff00ff0f 0 bset r8h abs8 + TMP2 = 0xffffff00 | IR[0]; + TMP1 = read8(TMP2); + bset r8_r(IR[1] >> 4) + prefetch_start(); + write8(TMP2, TMP1); + prefetch_done(); + +7f006100 ff00ff0f 0 bnot r8h abs8 + TMP2 = 0xffffff00 | IR[0]; + TMP1 = read8(TMP2); + bnot r8_r(IR[1] >> 4) + prefetch_start(); + write8(TMP2, TMP1); + prefetch_done(); + +7f006200 ff00ff0f 0 bclr r8h abs8 + TMP2 = 0xffffff00 | IR[0]; + TMP1 = read8(TMP2); + bclr r8_r(IR[1] >> 4) + prefetch_start(); + write8(TMP2, TMP1); + prefetch_done(); + +7f006700 ff00ff8f 0 bst imm3 abs8 + TMP2 = 0xffffff00 | IR[0]; + TMP1 = read8(TMP2); + prefetch_start(); + bst IR[0] >> 4 + write8(TMP2, TMP1); + prefetch_done(); + +7f006780 ff00ff8f 0 bist imm3 abs8 + TMP2 = 0xffffff00 | IR[0]; + TMP1 = read8(TMP2); + prefetch_start(); + bist IR[0] >> 4 + write8(TMP2, TMP1); + prefetch_done(); + +7f007000 ff00ff8f 0 bset imm3 abs8 + TMP2 = 0xffffff00 | IR[0]; + TMP1 = read8(TMP2); + prefetch_start(); + bset IR[1] >> 4 + write8(TMP2, TMP1); + prefetch_done(); + +7f007100 ff00ff8f 0 bnot imm3 abs8 + TMP2 = 0xffffff00 | IR[0]; + TMP1 = read8(TMP2); + prefetch_start(); + bnot IR[1] >> 4 + write8(TMP2, TMP1); + prefetch_done(); + +7f007200 ff00ff8f 0 bclr imm3 abs8 + TMP2 = 0xffffff00 | IR[0]; + TMP1 = read8(TMP2); + prefetch_start(); + bclr IR[1] >> 4 + write8(TMP2, TMP1); + prefetch_done(); + +8000 f000 0 add.b imm8 r8u + r8_w(IR[0] >> 8, do_add8(r8_r(IR[0] >> 8), IR[0])); + prefetch(); + +9000 f000 0 addx.b imm8 r8u + r8_w(IR[0] >> 8, do_addx8(r8_r(IR[0] >> 8), IR[0])); + prefetch(); + +a000 f000 0 cmp.b imm8 r8u + do_sub8(r8_r(IR[0]>>8), IR[0]); + prefetch(); + +b000 f000 0 subx.b imm8 r8u + r8_w(IR[0] >> 8, do_subx8(r8_r(IR[0] >> 8), IR[0])); + prefetch(); + +c000 f000 0 or.b imm8 r8u + TMP1 = IR[0] | r8_r(IR[0] >> 8); + set_nzv8(TMP1); + r8_w(IR[0] >> 8, TMP1); + prefetch(); + +d000 f000 0 xor.b imm8 r8u + TMP1 = IR[0] ^ r8_r(IR[0] >> 8); + set_nzv8(TMP1); + r8_w(IR[0] >> 8, TMP1); + prefetch(); + +e000 f000 0 and.b imm8 r8u + TMP1 = IR[0] & r8_r(IR[0] >> 8); + set_nzv8(TMP1); + r8_w(IR[0] >> 8, TMP1); + prefetch(); + +f000 f000 0 mov.b imm8 r8u + set_nzv8(IR[0]); + r8_w(IR[0] >> 8, IR[0]); + prefetch(); diff --git a/src/devices/cpu/h8/h83002.c b/src/devices/cpu/h8/h83002.c new file mode 100644 index 00000000000..451454dca40 --- /dev/null +++ b/src/devices/cpu/h8/h83002.c @@ -0,0 +1,219 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +#include "emu.h" +#include "h83002.h" + +const device_type H83002 = &device_creator; + +h83002_device::h83002_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + h8h_device(mconfig, H83002, "H8/3002", tag, owner, clock, "h83002", __FILE__, address_map_delegate(FUNC(h83002_device::map), this)), + intc(*this, "intc"), + adc(*this, "adc"), + port4(*this, "port4"), + port6(*this, "port6"), + port7(*this, "port7"), + port8(*this, "port8"), + port9(*this, "port9"), + porta(*this, "porta"), + portb(*this, "portb"), + timer16(*this, "timer16"), + timer16_0(*this, "timer16:0"), + timer16_1(*this, "timer16:1"), + timer16_2(*this, "timer16:2"), + timer16_3(*this, "timer16:3"), + timer16_4(*this, "timer16:4"), + sci0(*this, "sci0"), + sci1(*this, "sci1") +{ +} + +static MACHINE_CONFIG_FRAGMENT(h83002) + MCFG_H8H_INTC_ADD("intc") + MCFG_H8_ADC_3337_ADD("adc", "intc", 60) + MCFG_H8_PORT_ADD("port4", h8_device::PORT_4, 0x00, 0x00) + MCFG_H8_PORT_ADD("port6", h8_device::PORT_6, 0x80, 0x80) + MCFG_H8_PORT_ADD("port7", h8_device::PORT_7, 0x00, 0x00) + MCFG_H8_PORT_ADD("port8", h8_device::PORT_8, 0xf0, 0xe0) + MCFG_H8_PORT_ADD("port9", h8_device::PORT_9, 0x00, 0xc0) + MCFG_H8_PORT_ADD("porta", h8_device::PORT_A, 0x00, 0x00) + MCFG_H8_PORT_ADD("portb", h8_device::PORT_B, 0x00, 0x00) + MCFG_H8_TIMER16_ADD("timer16", 5, 0xe0) + MCFG_H8H_TIMER16_CHANNEL_ADD("timer16:0", 2, 2, "intc", 24) + MCFG_H8H_TIMER16_CHANNEL_ADD("timer16:1", 2, 2, "intc", 28) + MCFG_H8H_TIMER16_CHANNEL_ADD("timer16:2", 2, 2, "intc", 32) + MCFG_H8H_TIMER16_CHANNEL_ADD("timer16:3", 2, 2, "intc", 36) + MCFG_H8H_TIMER16_CHANNEL_ADD("timer16:4", 2, 2, "intc", 40) + MCFG_H8_SCI_ADD("sci0", "intc", 52, 53, 54, 55) + MCFG_H8_SCI_ADD("sci1", "intc", 56, 57, 58, 59) +MACHINE_CONFIG_END + +DEVICE_ADDRESS_MAP_START(map, 16, h83002_device) + AM_RANGE(0xfffd10, 0xffff0f) AM_RAM + + AM_RANGE(0xffff60, 0xffff61) AM_DEVREADWRITE8("timer16", h8_timer16_device, tstr_r, tstr_w, 0xff00) + AM_RANGE(0xffff60, 0xffff61) AM_DEVREADWRITE8("timer16", h8_timer16_device, tsyr_r, tsyr_w, 0x00ff) + AM_RANGE(0xffff62, 0xffff63) AM_DEVREADWRITE8("timer16", h8_timer16_device, tmdr_r, tmdr_w, 0xff00) + AM_RANGE(0xffff62, 0xffff63) AM_DEVREADWRITE8("timer16", h8_timer16_device, tfcr_r, tfcr_w, 0x00ff) + AM_RANGE(0xffff64, 0xffff65) AM_DEVREADWRITE8("timer16:0", h8_timer16_channel_device, tcr_r, tcr_w, 0xff00) + AM_RANGE(0xffff64, 0xffff65) AM_DEVREADWRITE8("timer16:0", h8_timer16_channel_device, tior_r, tior_w, 0x00ff) + AM_RANGE(0xffff66, 0xffff67) AM_DEVREADWRITE8("timer16:0", h8_timer16_channel_device, tier_r, tier_w, 0xff00) + AM_RANGE(0xffff66, 0xffff67) AM_DEVREADWRITE8("timer16:0", h8_timer16_channel_device, tsr_r, tsr_w, 0x00ff) + AM_RANGE(0xffff68, 0xffff69) AM_DEVREADWRITE( "timer16:0", h8_timer16_channel_device, tcnt_r, tcnt_w ) + AM_RANGE(0xffff6a, 0xffff6d) AM_DEVREADWRITE( "timer16:0", h8_timer16_channel_device, tgr_r, tgr_w ) + AM_RANGE(0xffff6e, 0xffff6f) AM_DEVREADWRITE8("timer16:1", h8_timer16_channel_device, tcr_r, tcr_w, 0xff00) + AM_RANGE(0xffff6e, 0xffff6f) AM_DEVREADWRITE8("timer16:1", h8_timer16_channel_device, tior_r, tior_w, 0x00ff) + AM_RANGE(0xffff70, 0xffff71) AM_DEVREADWRITE8("timer16:1", h8_timer16_channel_device, tier_r, tier_w, 0xff00) + AM_RANGE(0xffff70, 0xffff71) AM_DEVREADWRITE8("timer16:1", h8_timer16_channel_device, tsr_r, tsr_w, 0x00ff) + AM_RANGE(0xffff72, 0xffff73) AM_DEVREADWRITE( "timer16:1", h8_timer16_channel_device, tcnt_r, tcnt_w ) + AM_RANGE(0xffff74, 0xffff77) AM_DEVREADWRITE( "timer16:1", h8_timer16_channel_device, tgr_r, tgr_w ) + AM_RANGE(0xffff78, 0xffff79) AM_DEVREADWRITE8("timer16:2", h8_timer16_channel_device, tcr_r, tcr_w, 0xff00) + AM_RANGE(0xffff78, 0xffff79) AM_DEVREADWRITE8("timer16:2", h8_timer16_channel_device, tior_r, tior_w, 0x00ff) + AM_RANGE(0xffff7a, 0xffff7b) AM_DEVREADWRITE8("timer16:2", h8_timer16_channel_device, tier_r, tier_w, 0xff00) + AM_RANGE(0xffff7a, 0xffff7b) AM_DEVREADWRITE8("timer16:2", h8_timer16_channel_device, tsr_r, tsr_w, 0x00ff) + AM_RANGE(0xffff7c, 0xffff7d) AM_DEVREADWRITE( "timer16:2", h8_timer16_channel_device, tcnt_r, tcnt_w ) + AM_RANGE(0xffff7e, 0xffff81) AM_DEVREADWRITE( "timer16:2", h8_timer16_channel_device, tgr_r, tgr_w ) + AM_RANGE(0xffff82, 0xffff83) AM_DEVREADWRITE8("timer16:3", h8_timer16_channel_device, tcr_r, tcr_w, 0xff00) + AM_RANGE(0xffff82, 0xffff83) AM_DEVREADWRITE8("timer16:3", h8_timer16_channel_device, tior_r, tior_w, 0x00ff) + AM_RANGE(0xffff84, 0xffff85) AM_DEVREADWRITE8("timer16:3", h8_timer16_channel_device, tier_r, tier_w, 0xff00) + AM_RANGE(0xffff84, 0xffff85) AM_DEVREADWRITE8("timer16:3", h8_timer16_channel_device, tsr_r, tsr_w, 0x00ff) + AM_RANGE(0xffff86, 0xffff87) AM_DEVREADWRITE( "timer16:3", h8_timer16_channel_device, tcnt_r, tcnt_w ) + AM_RANGE(0xffff88, 0xffff8b) AM_DEVREADWRITE( "timer16:3", h8_timer16_channel_device, tgr_r, tgr_w ) + AM_RANGE(0xffff8c, 0xffff8f) AM_DEVREADWRITE( "timer16:3", h8_timer16_channel_device, tbr_r, tbr_w ) + AM_RANGE(0xffff90, 0xffff91) AM_DEVREADWRITE8("timer16", h8_timer16_device, toer_r, toer_w, 0xff00) + AM_RANGE(0xffff90, 0xffff91) AM_DEVREADWRITE8("timer16", h8_timer16_device, tocr_r, tocr_w, 0x00ff) + AM_RANGE(0xffff92, 0xffff93) AM_DEVREADWRITE8("timer16:4", h8_timer16_channel_device, tcr_r, tcr_w, 0xff00) + AM_RANGE(0xffff92, 0xffff93) AM_DEVREADWRITE8("timer16:4", h8_timer16_channel_device, tior_r, tior_w, 0x00ff) + AM_RANGE(0xffff94, 0xffff95) AM_DEVREADWRITE8("timer16:4", h8_timer16_channel_device, tier_r, tier_w, 0xff00) + AM_RANGE(0xffff94, 0xffff95) AM_DEVREADWRITE8("timer16:4", h8_timer16_channel_device, tsr_r, tsr_w, 0x00ff) + AM_RANGE(0xffff96, 0xffff97) AM_DEVREADWRITE( "timer16:4", h8_timer16_channel_device, tcnt_r, tcnt_w ) + AM_RANGE(0xffff98, 0xffff9b) AM_DEVREADWRITE( "timer16:4", h8_timer16_channel_device, tgr_r, tgr_w ) + AM_RANGE(0xffff9c, 0xffff9f) AM_DEVREADWRITE( "timer16:4", h8_timer16_channel_device, tbr_r, tbr_w ) + + AM_RANGE(0xffffb0, 0xffffb1) AM_DEVREADWRITE8("sci0", h8_sci_device, smr_r, smr_w, 0xff00) + AM_RANGE(0xffffb0, 0xffffb1) AM_DEVREADWRITE8("sci0", h8_sci_device, brr_r, brr_w, 0x00ff) + AM_RANGE(0xffffb2, 0xffffb3) AM_DEVREADWRITE8("sci0", h8_sci_device, scr_r, scr_w, 0xff00) + AM_RANGE(0xffffb2, 0xffffb3) AM_DEVREADWRITE8("sci0", h8_sci_device, tdr_r, tdr_w, 0x00ff) + AM_RANGE(0xffffb4, 0xffffb5) AM_DEVREADWRITE8("sci0", h8_sci_device, ssr_r, ssr_w, 0xff00) + AM_RANGE(0xffffb4, 0xffffb5) AM_DEVREAD8( "sci0", h8_sci_device, rdr_r, 0x00ff) + AM_RANGE(0xffffb8, 0xffffb9) AM_DEVREADWRITE8("sci1", h8_sci_device, smr_r, smr_w, 0xff00) + AM_RANGE(0xffffb8, 0xffffb9) AM_DEVREADWRITE8("sci1", h8_sci_device, brr_r, brr_w, 0x00ff) + AM_RANGE(0xffffba, 0xffffbb) AM_DEVREADWRITE8("sci1", h8_sci_device, scr_r, scr_w, 0xff00) + AM_RANGE(0xffffba, 0xffffbb) AM_DEVREADWRITE8("sci1", h8_sci_device, tdr_r, tdr_w, 0x00ff) + AM_RANGE(0xffffbc, 0xffffbd) AM_DEVREADWRITE8("sci1", h8_sci_device, ssr_r, ssr_w, 0xff00) + AM_RANGE(0xffffbc, 0xffffbd) AM_DEVREAD8( "sci1", h8_sci_device, rdr_r, 0x00ff) + AM_RANGE(0xffffc4, 0xffffc5) AM_DEVWRITE8( "port4", h8_port_device, ddr_w, 0x00ff) + AM_RANGE(0xffffc6, 0xffffc7) AM_DEVREADWRITE8("port4", h8_port_device, port_r, dr_w, 0x00ff) + AM_RANGE(0xffffc8, 0xffffc9) AM_DEVWRITE8( "port6", h8_port_device, ddr_w, 0x00ff) + AM_RANGE(0xffffca, 0xffffcb) AM_DEVREADWRITE8("port6", h8_port_device, port_r, dr_w, 0x00ff) + AM_RANGE(0xffffcc, 0xffffcd) AM_DEVWRITE8( "port8", h8_port_device, ddr_w, 0x00ff) + AM_RANGE(0xffffce, 0xffffcf) AM_DEVREAD8( "port7", h8_port_device, port_r, 0xff00) + AM_RANGE(0xffffce, 0xffffcf) AM_DEVREADWRITE8("port8", h8_port_device, port_r, dr_w, 0x00ff) + AM_RANGE(0xffffd0, 0xffffd1) AM_DEVWRITE8( "port9", h8_port_device, ddr_w, 0xff00) + AM_RANGE(0xffffd0, 0xffffd1) AM_DEVWRITE8( "porta", h8_port_device, ddr_w, 0x00ff) + AM_RANGE(0xffffd2, 0xffffd3) AM_DEVREADWRITE8("port9", h8_port_device, port_r, dr_w, 0xff00) + AM_RANGE(0xffffd2, 0xffffd3) AM_DEVREADWRITE8("porta", h8_port_device, port_r, dr_w, 0x00ff) + AM_RANGE(0xffffd4, 0xffffd5) AM_DEVWRITE8( "portb", h8_port_device, ddr_w, 0xff00) + AM_RANGE(0xffffd6, 0xffffd7) AM_DEVREADWRITE8("portb", h8_port_device, port_r, dr_w, 0xff00) + AM_RANGE(0xffffda, 0xffffdb) AM_DEVREADWRITE8("port4", h8_port_device, pcr_r, pcr_w, 0xff00) + + AM_RANGE(0xffffe0, 0xffffe7) AM_DEVREAD8( "adc", h8_adc_device, addr8_r, 0xffff) + AM_RANGE(0xffffe8, 0xffffe9) AM_DEVREADWRITE8("adc", h8_adc_device, adcsr_r, adcsr_w, 0xff00) + AM_RANGE(0xffffe8, 0xffffe9) AM_DEVREADWRITE8("adc", h8_adc_device, adcr_r, adcr_w, 0x00ff) + + AM_RANGE(0xfffff2, 0xfffff3) AM_READWRITE8( syscr_r, syscr_w, 0xff00) + AM_RANGE(0xfffff4, 0xfffff5) AM_DEVREADWRITE8("intc", h8h_intc_device, iscr_r, iscr_w, 0xff00) + AM_RANGE(0xfffff4, 0xfffff5) AM_DEVREADWRITE8("intc", h8h_intc_device, ier_r, ier_w, 0x00ff) + AM_RANGE(0xfffff6, 0xfffff7) AM_DEVREADWRITE8("intc", h8h_intc_device, isr_r, isr_w, 0xff00) + AM_RANGE(0xfffff8, 0xfffff9) AM_DEVREADWRITE8("intc", h8h_intc_device, icr_r, icr_w, 0xffff) +ADDRESS_MAP_END + +machine_config_constructor h83002_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME(h83002); +} + +void h83002_device::execute_set_input(int inputnum, int state) +{ + intc->set_input(inputnum, state); +} + +int h83002_device::trapa_setup() +{ + if(syscr & 0x08) + CCR |= F_I; + else + CCR |= F_I|F_UI; + return 8; +} + +void h83002_device::irq_setup() +{ + if(syscr & 0x08) + CCR |= F_I; + else + CCR |= F_I|F_UI; +} + +void h83002_device::update_irq_filter() +{ + switch(syscr & 0x08) { + case 0x00: + if((CCR & (F_I|F_UI)) == (F_I|F_UI)) + intc->set_filter(2, -1); + else if(CCR & F_I) + intc->set_filter(1, -1); + else + intc->set_filter(0, -1); + break; + case 0x08: + if(CCR & F_I) + intc->set_filter(2, -1); + else + intc->set_filter(0, -1); + break; + } +} + +void h83002_device::interrupt_taken() +{ + standard_irq_callback(intc->interrupt_taken(taken_irq_vector)); +} + +void h83002_device::internal_update(UINT64 current_time) +{ + UINT64 event_time = 0; + + add_event(event_time, adc->internal_update(current_time)); + add_event(event_time, sci0->internal_update(current_time)); + add_event(event_time, sci1->internal_update(current_time)); + add_event(event_time, timer16_0->internal_update(current_time)); + add_event(event_time, timer16_1->internal_update(current_time)); + add_event(event_time, timer16_2->internal_update(current_time)); + add_event(event_time, timer16_3->internal_update(current_time)); + add_event(event_time, timer16_4->internal_update(current_time)); + + recompute_bcount(event_time); +} + +void h83002_device::device_start() +{ + h8h_device::device_start(); +} + +void h83002_device::device_reset() +{ + h8h_device::device_reset(); + syscr = 0x09; +} + +READ8_MEMBER(h83002_device::syscr_r) +{ + return syscr; +} + +WRITE8_MEMBER(h83002_device::syscr_w) +{ + syscr = data; + update_irq_filter(); + logerror("%s: syscr = %02x\n", tag(), data); +} diff --git a/src/devices/cpu/h8/h83002.h b/src/devices/cpu/h8/h83002.h new file mode 100644 index 00000000000..c6b9612fc9c --- /dev/null +++ b/src/devices/cpu/h8/h83002.h @@ -0,0 +1,67 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +/*************************************************************************** + + h83002.h + + H8/3002 + + H8/300H-based mcus. + + +***************************************************************************/ + +#ifndef __H83002_H__ +#define __H83002_H__ + +#include "h8h.h" +#include "h8_adc.h" +#include "h8_port.h" +#include "h8_intc.h" +#include "h8_sci.h" +#include "h8_timer16.h" + +class h83002_device : public h8h_device { +public: + h83002_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + DECLARE_READ8_MEMBER(syscr_r); + DECLARE_WRITE8_MEMBER(syscr_w); + +protected: + required_device intc; + required_device adc; + required_device port4; + required_device port6; + required_device port7; + required_device port8; + required_device port9; + required_device porta; + required_device portb; + required_device timer16; + required_device timer16_0; + required_device timer16_1; + required_device timer16_2; + required_device timer16_3; + required_device timer16_4; + required_device sci0; + required_device sci1; + + UINT8 syscr; + + virtual void update_irq_filter(); + virtual void interrupt_taken(); + virtual int trapa_setup(); + virtual void irq_setup(); + virtual void internal_update(UINT64 current_time); + virtual machine_config_constructor device_mconfig_additions() const; + DECLARE_ADDRESS_MAP(map, 16); + + virtual void device_start(); + virtual void device_reset(); + virtual void execute_set_input(int inputnum, int state); +}; + +extern const device_type H83002; + +#endif diff --git a/src/devices/cpu/h8/h83006.c b/src/devices/cpu/h8/h83006.c new file mode 100644 index 00000000000..2e203a84dbb --- /dev/null +++ b/src/devices/cpu/h8/h83006.c @@ -0,0 +1,271 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +#include "emu.h" +#include "h83006.h" + +const device_type H83006 = &device_creator; +const device_type H83007 = &device_creator; + + +h83006_device::h83006_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + h8h_device(mconfig, type, name, tag, owner, clock, shortname, source, address_map_delegate(FUNC(h83006_device::map), this)), + intc(*this, "intc"), + adc(*this, "adc"), + port4(*this, "port4"), + port6(*this, "port6"), + port7(*this, "port7"), + port8(*this, "port8"), + port9(*this, "port9"), + porta(*this, "porta"), + portb(*this, "portb"), + timer8_0(*this, "timer8_0"), + timer8_1(*this, "timer8_1"), + timer8_2(*this, "timer8_2"), + timer8_3(*this, "timer8_3"), + timer16(*this, "timer16"), + timer16_0(*this, "timer16:0"), + timer16_1(*this, "timer16:1"), + timer16_2(*this, "timer16:2"), + sci0(*this, "sci0"), + sci1(*this, "sci1"), + sci2(*this, "sci2") +{ +} + +h83006_device::h83006_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + h8h_device(mconfig, H83006, "H8/3006", tag, owner, clock, "h83006", __FILE__, address_map_delegate(FUNC(h83006_device::map), this)), + intc(*this, "intc"), + adc(*this, "adc"), + port4(*this, "port4"), + port6(*this, "port6"), + port7(*this, "port7"), + port8(*this, "port8"), + port9(*this, "port9"), + porta(*this, "porta"), + portb(*this, "portb"), + timer8_0(*this, "timer8_0"), + timer8_1(*this, "timer8_1"), + timer8_2(*this, "timer8_2"), + timer8_3(*this, "timer8_3"), + timer16(*this, "timer16"), + timer16_0(*this, "timer16:0"), + timer16_1(*this, "timer16:1"), + timer16_2(*this, "timer16:2"), + sci0(*this, "sci0"), + sci1(*this, "sci1"), + sci2(*this, "sci2") +{ + ram_start = 0xfff720; +} + + +h83007_device::h83007_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + h83006_device(mconfig, H83007, "H8/3007", tag, owner, clock, "h83007", __FILE__) +{ + ram_start = 0xffef20; +} + +static MACHINE_CONFIG_FRAGMENT(h83006) + MCFG_H8H_INTC_ADD("intc") + MCFG_H8_ADC_3006_ADD("adc", "intc", 23) + MCFG_H8_PORT_ADD("port4", h8_device::PORT_4, 0x00, 0x00) + MCFG_H8_PORT_ADD("port6", h8_device::PORT_6, 0x80, 0x80) + MCFG_H8_PORT_ADD("port7", h8_device::PORT_7, 0x00, 0x00) + MCFG_H8_PORT_ADD("port8", h8_device::PORT_8, 0xf0, 0xe0) + MCFG_H8_PORT_ADD("port9", h8_device::PORT_9, 0xc0, 0xc0) + MCFG_H8_PORT_ADD("porta", h8_device::PORT_A, 0x80, 0x00) + MCFG_H8_PORT_ADD("portb", h8_device::PORT_B, 0x00, 0x00) + MCFG_H8H_TIMER8_CHANNEL_ADD("timer8_0", "intc", 36, 38, 39, "timer8_1", h8_timer8_channel_device::CHAIN_OVERFLOW, true, false) + MCFG_H8H_TIMER8_CHANNEL_ADD("timer8_1", "intc", 37, 38, 39, "timer8_0", h8_timer8_channel_device::CHAIN_A, false, false) + MCFG_H8H_TIMER8_CHANNEL_ADD("timer8_2", "intc", 40, 42, 43, "timer8_3", h8_timer8_channel_device::CHAIN_OVERFLOW, false, true) + MCFG_H8H_TIMER8_CHANNEL_ADD("timer8_3", "intc", 41, 42, 43, "timer8_2", h8_timer8_channel_device::CHAIN_A, false, true) + MCFG_H8_TIMER16_ADD("timer16", 3, 0xf8) + MCFG_H8H_TIMER16_CHANNEL_ADD("timer16:0", 2, 2, "intc", 24) + MCFG_H8H_TIMER16_CHANNEL_ADD("timer16:1", 2, 2, "intc", 28) + MCFG_H8H_TIMER16_CHANNEL_ADD("timer16:2", 2, 2, "intc", 32) + MCFG_H8_SCI_ADD("sci0", "intc", 52, 53, 54, 55) + MCFG_H8_SCI_ADD("sci1", "intc", 56, 57, 58, 59) + MCFG_H8_SCI_ADD("sci2", "intc", 60, 61, 62, 63) +MACHINE_CONFIG_END + +DEVICE_ADDRESS_MAP_START(map, 16, h83006_device) + AM_RANGE(0xfee002, 0xfee003) AM_DEVWRITE8( "port4", h8_port_device, ddr_w, 0x00ff) + AM_RANGE(0xfee004, 0xfee005) AM_DEVWRITE8( "port6", h8_port_device, ddr_w, 0x00ff) + AM_RANGE(0xfee006, 0xfee007) AM_DEVWRITE8( "port8", h8_port_device, ddr_w, 0x00ff) + AM_RANGE(0xfee008, 0xfee009) AM_DEVWRITE8( "port9", h8_port_device, ddr_w, 0xff00) + AM_RANGE(0xfee008, 0xfee009) AM_DEVWRITE8( "porta", h8_port_device, ddr_w, 0x00ff) + AM_RANGE(0xfee00a, 0xfee00b) AM_DEVWRITE8( "portb", h8_port_device, ddr_w, 0xff00) + + AM_RANGE(0xfee012, 0xfee013) AM_READWRITE8( syscr_r, syscr_w, 0xff00) + AM_RANGE(0xfee014, 0xfee015) AM_DEVREADWRITE8("intc", h8h_intc_device, iscr_r, iscr_w, 0xff00) + AM_RANGE(0xfee014, 0xfee015) AM_DEVREADWRITE8("intc", h8h_intc_device, ier_r, ier_w, 0x00ff) + AM_RANGE(0xfee016, 0xfee017) AM_DEVREADWRITE8("intc", h8h_intc_device, isr_r, isr_w, 0xff00) + AM_RANGE(0xfee018, 0xfee019) AM_DEVREADWRITE8("intc", h8h_intc_device, icr_r, icr_w, 0xffff) + + AM_RANGE(0xfee03e, 0xfee03f) AM_DEVREADWRITE8("port4", h8_port_device, pcr_r, pcr_w, 0xff00) + + AM_RANGE(ram_start, 0xffff1f) AM_RAM + + AM_RANGE(0xffff60, 0xffff61) AM_DEVREADWRITE8("timer16", h8_timer16_device, tstr_r, tstr_w, 0xff00) + AM_RANGE(0xffff60, 0xffff61) AM_DEVREADWRITE8("timer16", h8_timer16_device, tsyr_r, tsyr_w, 0x00ff) + AM_RANGE(0xffff62, 0xffff63) AM_DEVREADWRITE8("timer16", h8_timer16_device, tmdr_r, tmdr_w, 0xff00) + AM_RANGE(0xffff62, 0xffff63) AM_DEVWRITE8( "timer16", h8_timer16_device, tolr_w, 0x00ff) + AM_RANGE(0xffff64, 0xffff65) AM_DEVREADWRITE8("timer16", h8_timer16_device, tisr_r, tisr_w, 0xffff) + AM_RANGE(0xffff66, 0xffff67) AM_DEVREADWRITE8("timer16", h8_timer16_device, tisrc_r, tisrc_w, 0xff00) + AM_RANGE(0xffff68, 0xffff69) AM_DEVREADWRITE8("timer16:0", h8_timer16_channel_device, tcr_r, tcr_w, 0xff00) + AM_RANGE(0xffff68, 0xffff69) AM_DEVREADWRITE8("timer16:0", h8_timer16_channel_device, tior_r, tior_w, 0x00ff) + AM_RANGE(0xffff6a, 0xffff6b) AM_DEVREADWRITE( "timer16:0", h8_timer16_channel_device, tcnt_r, tcnt_w ) + AM_RANGE(0xffff6c, 0xffff6f) AM_DEVREADWRITE( "timer16:0", h8_timer16_channel_device, tgr_r, tgr_w ) + AM_RANGE(0xffff70, 0xffff71) AM_DEVREADWRITE8("timer16:1", h8_timer16_channel_device, tcr_r, tcr_w, 0xff00) + AM_RANGE(0xffff70, 0xffff71) AM_DEVREADWRITE8("timer16:1", h8_timer16_channel_device, tior_r, tior_w, 0x00ff) + AM_RANGE(0xffff72, 0xffff73) AM_DEVREADWRITE( "timer16:1", h8_timer16_channel_device, tcnt_r, tcnt_w ) + AM_RANGE(0xffff74, 0xffff77) AM_DEVREADWRITE( "timer16:1", h8_timer16_channel_device, tgr_r, tgr_w ) + AM_RANGE(0xffff78, 0xffff79) AM_DEVREADWRITE8("timer16:2", h8_timer16_channel_device, tcr_r, tcr_w, 0xff00) + AM_RANGE(0xffff78, 0xffff79) AM_DEVREADWRITE8("timer16:2", h8_timer16_channel_device, tior_r, tior_w, 0x00ff) + AM_RANGE(0xffff7a, 0xffff7b) AM_DEVREADWRITE( "timer16:2", h8_timer16_channel_device, tcnt_r, tcnt_w ) + AM_RANGE(0xffff7c, 0xffff7f) AM_DEVREADWRITE( "timer16:2", h8_timer16_channel_device, tgr_r, tgr_w ) + AM_RANGE(0xffff80, 0xffff81) AM_DEVREADWRITE8("timer8_0", h8_timer8_channel_device, tcr_r, tcr_w, 0xff00) + AM_RANGE(0xffff80, 0xffff81) AM_DEVREADWRITE8("timer8_1", h8_timer8_channel_device, tcr_r, tcr_w, 0x00ff) + AM_RANGE(0xffff82, 0xffff83) AM_DEVREADWRITE8("timer8_0", h8_timer8_channel_device, tcsr_r, tcsr_w, 0xff00) + AM_RANGE(0xffff82, 0xffff83) AM_DEVREADWRITE8("timer8_1", h8_timer8_channel_device, tcsr_r, tcsr_w, 0x00ff) + AM_RANGE(0xffff84, 0xffff87) AM_DEVREADWRITE8("timer8_0", h8_timer8_channel_device, tcor_r, tcor_w, 0xff00) + AM_RANGE(0xffff84, 0xffff87) AM_DEVREADWRITE8("timer8_1", h8_timer8_channel_device, tcor_r, tcor_w, 0x00ff) + AM_RANGE(0xffff88, 0xffff89) AM_DEVREADWRITE8("timer8_0", h8_timer8_channel_device, tcnt_r, tcnt_w, 0xff00) + AM_RANGE(0xffff88, 0xffff89) AM_DEVREADWRITE8("timer8_1", h8_timer8_channel_device, tcnt_r, tcnt_w, 0x00ff) + AM_RANGE(0xffff90, 0xffff91) AM_DEVREADWRITE8("timer8_2", h8_timer8_channel_device, tcr_r, tcr_w, 0xff00) + AM_RANGE(0xffff90, 0xffff91) AM_DEVREADWRITE8("timer8_3", h8_timer8_channel_device, tcr_r, tcr_w, 0x00ff) + AM_RANGE(0xffff92, 0xffff93) AM_DEVREADWRITE8("timer8_2", h8_timer8_channel_device, tcsr_r, tcsr_w, 0xff00) + AM_RANGE(0xffff92, 0xffff93) AM_DEVREADWRITE8("timer8_3", h8_timer8_channel_device, tcsr_r, tcsr_w, 0x00ff) + AM_RANGE(0xffff94, 0xffff97) AM_DEVREADWRITE8("timer8_2", h8_timer8_channel_device, tcor_r, tcor_w, 0xff00) + AM_RANGE(0xffff94, 0xffff97) AM_DEVREADWRITE8("timer8_3", h8_timer8_channel_device, tcor_r, tcor_w, 0x00ff) + AM_RANGE(0xffff98, 0xffff99) AM_DEVREADWRITE8("timer8_2", h8_timer8_channel_device, tcnt_r, tcnt_w, 0xff00) + AM_RANGE(0xffff98, 0xffff99) AM_DEVREADWRITE8("timer8_3", h8_timer8_channel_device, tcnt_r, tcnt_w, 0x00ff) + + AM_RANGE(0xffffb0, 0xffffb1) AM_DEVREADWRITE8("sci0", h8_sci_device, smr_r, smr_w, 0xff00) + AM_RANGE(0xffffb0, 0xffffb1) AM_DEVREADWRITE8("sci0", h8_sci_device, brr_r, brr_w, 0x00ff) + AM_RANGE(0xffffb2, 0xffffb3) AM_DEVREADWRITE8("sci0", h8_sci_device, scr_r, scr_w, 0xff00) + AM_RANGE(0xffffb2, 0xffffb3) AM_DEVREADWRITE8("sci0", h8_sci_device, tdr_r, tdr_w, 0x00ff) + AM_RANGE(0xffffb4, 0xffffb5) AM_DEVREADWRITE8("sci0", h8_sci_device, ssr_r, ssr_w, 0xff00) + AM_RANGE(0xffffb4, 0xffffb5) AM_DEVREAD8( "sci0", h8_sci_device, rdr_r, 0x00ff) + AM_RANGE(0xffffb6, 0xffffb7) AM_DEVREADWRITE8("sci0", h8_sci_device, scmr_r, scmr_w, 0xff00) + AM_RANGE(0xffffb8, 0xffffb9) AM_DEVREADWRITE8("sci1", h8_sci_device, smr_r, smr_w, 0xff00) + AM_RANGE(0xffffb8, 0xffffb9) AM_DEVREADWRITE8("sci1", h8_sci_device, brr_r, brr_w, 0x00ff) + AM_RANGE(0xffffba, 0xffffbb) AM_DEVREADWRITE8("sci1", h8_sci_device, scr_r, scr_w, 0xff00) + AM_RANGE(0xffffba, 0xffffbb) AM_DEVREADWRITE8("sci1", h8_sci_device, tdr_r, tdr_w, 0x00ff) + AM_RANGE(0xffffbc, 0xffffbd) AM_DEVREADWRITE8("sci1", h8_sci_device, ssr_r, ssr_w, 0xff00) + AM_RANGE(0xffffbc, 0xffffbd) AM_DEVREAD8( "sci1", h8_sci_device, rdr_r, 0x00ff) + AM_RANGE(0xffffbe, 0xffffbf) AM_DEVREADWRITE8("sci1", h8_sci_device, scmr_r, scmr_w, 0xff00) + AM_RANGE(0xffffc0, 0xffffc1) AM_DEVREADWRITE8("sci2", h8_sci_device, smr_r, smr_w, 0xff00) + AM_RANGE(0xffffc0, 0xffffc1) AM_DEVREADWRITE8("sci2", h8_sci_device, brr_r, brr_w, 0x00ff) + AM_RANGE(0xffffc2, 0xffffc3) AM_DEVREADWRITE8("sci2", h8_sci_device, scr_r, scr_w, 0xff00) + AM_RANGE(0xffffc2, 0xffffc3) AM_DEVREADWRITE8("sci2", h8_sci_device, tdr_r, tdr_w, 0x00ff) + AM_RANGE(0xffffc4, 0xffffc5) AM_DEVREADWRITE8("sci2", h8_sci_device, ssr_r, ssr_w, 0xff00) + AM_RANGE(0xffffc4, 0xffffc5) AM_DEVREAD8( "sci2", h8_sci_device, rdr_r, 0x00ff) + AM_RANGE(0xffffc6, 0xffffc7) AM_DEVREADWRITE8("sci2", h8_sci_device, scmr_r, scmr_w, 0xff00) + AM_RANGE(0xffffd2, 0xffffd3) AM_DEVREADWRITE8("port4", h8_port_device, port_r, dr_w, 0x00ff) + AM_RANGE(0xffffd4, 0xffffd5) AM_DEVREADWRITE8("port6", h8_port_device, port_r, dr_w, 0x00ff) + AM_RANGE(0xffffd6, 0xffffd7) AM_DEVREADWRITE8("port7", h8_port_device, port_r, dr_w, 0xff00) + AM_RANGE(0xffffd6, 0xffffd7) AM_DEVREADWRITE8("port8", h8_port_device, port_r, dr_w, 0x00ff) + AM_RANGE(0xffffd8, 0xffffd9) AM_DEVREADWRITE8("port9", h8_port_device, port_r, dr_w, 0xff00) + AM_RANGE(0xffffd8, 0xffffd9) AM_DEVREADWRITE8("porta", h8_port_device, port_r, dr_w, 0x00ff) + AM_RANGE(0xffffda, 0xffffdb) AM_DEVREADWRITE8("portb", h8_port_device, port_r, dr_w, 0xff00) + + AM_RANGE(0xffffe0, 0xffffe7) AM_DEVREAD8( "adc", h8_adc_device, addr8_r, 0xffff) + AM_RANGE(0xffffe8, 0xffffe9) AM_DEVREADWRITE8("adc", h8_adc_device, adcsr_r, adcsr_w, 0xff00) + AM_RANGE(0xffffe8, 0xffffe9) AM_DEVREADWRITE8("adc", h8_adc_device, adcr_r, adcr_w, 0x00ff) +ADDRESS_MAP_END + +machine_config_constructor h83006_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME(h83006); +} + +void h83006_device::execute_set_input(int inputnum, int state) +{ + intc->set_input(inputnum, state); +} + +int h83006_device::trapa_setup() +{ + if(syscr & 0x08) + CCR |= F_I; + else + CCR |= F_I|F_UI; + return 8; +} + +void h83006_device::irq_setup() +{ + if(syscr & 0x08) + CCR |= F_I; + else + CCR |= F_I|F_UI; +} + +void h83006_device::update_irq_filter() +{ + switch(syscr & 0x08) { + case 0x00: + if((CCR & (F_I|F_UI)) == (F_I|F_UI)) + intc->set_filter(2, -1); + else if(CCR & F_I) + intc->set_filter(1, -1); + else + intc->set_filter(0, -1); + break; + case 0x08: + if(CCR & F_I) + intc->set_filter(2, -1); + else + intc->set_filter(0, -1); + break; + } +} + +void h83006_device::interrupt_taken() +{ + standard_irq_callback(intc->interrupt_taken(taken_irq_vector)); +} + +void h83006_device::internal_update(UINT64 current_time) +{ + UINT64 event_time = 0; + + add_event(event_time, adc->internal_update(current_time)); + add_event(event_time, sci0->internal_update(current_time)); + add_event(event_time, sci1->internal_update(current_time)); + add_event(event_time, sci2->internal_update(current_time)); + add_event(event_time, timer8_0->internal_update(current_time)); + add_event(event_time, timer8_1->internal_update(current_time)); + add_event(event_time, timer8_2->internal_update(current_time)); + add_event(event_time, timer8_3->internal_update(current_time)); + add_event(event_time, timer16_0->internal_update(current_time)); + add_event(event_time, timer16_1->internal_update(current_time)); + add_event(event_time, timer16_2->internal_update(current_time)); + + recompute_bcount(event_time); +} + +void h83006_device::device_start() +{ + h8h_device::device_start(); +} + +void h83006_device::device_reset() +{ + h8h_device::device_reset(); + syscr = 0x09; +} + + +READ8_MEMBER(h83006_device::syscr_r) +{ + return syscr; +} + +WRITE8_MEMBER(h83006_device::syscr_w) +{ + syscr = data; + update_irq_filter(); + logerror("%s: syscr = %02x\n", tag(), data); +} diff --git a/src/devices/cpu/h8/h83006.h b/src/devices/cpu/h8/h83006.h new file mode 100644 index 00000000000..3dcd1690f93 --- /dev/null +++ b/src/devices/cpu/h8/h83006.h @@ -0,0 +1,80 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +/*************************************************************************** + + h83006.h + + H8/3006 / H8/3007 + + H8/300H-based mcus. + + +***************************************************************************/ + +#ifndef __H83006_H__ +#define __H83006_H__ + +#include "h8h.h" +#include "h8_adc.h" +#include "h8_port.h" +#include "h8_intc.h" +#include "h8_sci.h" +#include "h8_timer8.h" +#include "h8_timer16.h" + +class h83006_device : public h8h_device { +public: + h83006_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + h83006_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + DECLARE_READ8_MEMBER(syscr_r); + DECLARE_WRITE8_MEMBER(syscr_w); + +protected: + required_device intc; + required_device adc; + required_device port4; + required_device port6; + required_device port7; + required_device port8; + required_device port9; + required_device porta; + required_device portb; + required_device timer8_0; + required_device timer8_1; + required_device timer8_2; + required_device timer8_3; + required_device timer16; + required_device timer16_0; + required_device timer16_1; + required_device timer16_2; + required_device sci0; + required_device sci1; + required_device sci2; + + UINT8 syscr; + UINT32 ram_start; + + virtual void update_irq_filter(); + virtual void interrupt_taken(); + virtual int trapa_setup(); + virtual void irq_setup(); + virtual void internal_update(UINT64 current_time); + virtual machine_config_constructor device_mconfig_additions() const; + DECLARE_ADDRESS_MAP(map, 16); + + virtual void device_start(); + virtual void device_reset(); + virtual void execute_set_input(int inputnum, int state); +}; + + +class h83007_device : public h83006_device { +public: + h83007_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +extern const device_type H83006; +extern const device_type H83007; + +#endif diff --git a/src/devices/cpu/h8/h83008.c b/src/devices/cpu/h8/h83008.c new file mode 100644 index 00000000000..c919008667d --- /dev/null +++ b/src/devices/cpu/h8/h83008.c @@ -0,0 +1,226 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +#include "emu.h" +#include "h83008.h" + +const device_type H83008 = &device_creator; + +h83008_device::h83008_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + h8h_device(mconfig, H83008, "H8/3008", tag, owner, clock, "h83008", __FILE__, address_map_delegate(FUNC(h83008_device::map), this)), + intc(*this, "intc"), + adc(*this, "adc"), + port4(*this, "port4"), + port6(*this, "port6"), + port7(*this, "port7"), + port8(*this, "port8"), + port9(*this, "port9"), + porta(*this, "porta"), + portb(*this, "portb"), + timer8_0(*this, "timer8_0"), + timer8_1(*this, "timer8_1"), + timer8_2(*this, "timer8_2"), + timer8_3(*this, "timer8_3"), + timer16(*this, "timer16"), + timer16_0(*this, "timer16:0"), + timer16_1(*this, "timer16:1"), + timer16_2(*this, "timer16:2"), + sci0(*this, "sci0"), + sci1(*this, "sci1") +{ +} + +static MACHINE_CONFIG_FRAGMENT(h83008) + MCFG_H8H_INTC_ADD("intc") + MCFG_H8_ADC_3006_ADD("adc", "intc", 23) + MCFG_H8_PORT_ADD("port4", h8_device::PORT_4, 0x00, 0x00) + MCFG_H8_PORT_ADD("port6", h8_device::PORT_6, 0x80, 0x80) + MCFG_H8_PORT_ADD("port7", h8_device::PORT_7, 0xff, 0x00) + MCFG_H8_PORT_ADD("port8", h8_device::PORT_8, 0xf0, 0xe0) + MCFG_H8_PORT_ADD("port9", h8_device::PORT_9, 0xc0, 0xc0) + MCFG_H8_PORT_ADD("porta", h8_device::PORT_A, 0x80, 0x00) + MCFG_H8_PORT_ADD("portb", h8_device::PORT_B, 0x00, 0x00) + MCFG_H8H_TIMER8_CHANNEL_ADD("timer8_0", "intc", 36, 38, 39, "timer8_1", h8_timer8_channel_device::CHAIN_OVERFLOW, true, false) + MCFG_H8H_TIMER8_CHANNEL_ADD("timer8_1", "intc", 37, 38, 39, "timer8_0", h8_timer8_channel_device::CHAIN_A, false, false) + MCFG_H8H_TIMER8_CHANNEL_ADD("timer8_2", "intc", 40, 42, 43, "timer8_3", h8_timer8_channel_device::CHAIN_OVERFLOW, false, true) + MCFG_H8H_TIMER8_CHANNEL_ADD("timer8_3", "intc", 41, 42, 43, "timer8_2", h8_timer8_channel_device::CHAIN_A, false, true) + MCFG_H8_TIMER16_ADD("timer16", 3, 0xf8) + MCFG_H8H_TIMER16_CHANNEL_ADD("timer16:0", 2, 2, "intc", 24) + MCFG_H8H_TIMER16_CHANNEL_ADD("timer16:1", 2, 2, "intc", 28) + MCFG_H8H_TIMER16_CHANNEL_ADD("timer16:2", 2, 2, "intc", 32) + MCFG_H8_SCI_ADD("sci0", "intc", 52, 53, 54, 55) + MCFG_H8_SCI_ADD("sci1", "intc", 56, 57, 58, 59) +MACHINE_CONFIG_END + +DEVICE_ADDRESS_MAP_START(map, 16, h83008_device) + AM_RANGE(0xfee002, 0xfee003) AM_DEVWRITE8( "port4", h8_port_device, ddr_w, 0x00ff) + AM_RANGE(0xfee004, 0xfee005) AM_DEVWRITE8( "port6", h8_port_device, ddr_w, 0x00ff) + AM_RANGE(0xfee006, 0xfee007) AM_DEVWRITE8( "port8", h8_port_device, ddr_w, 0x00ff) + AM_RANGE(0xfee008, 0xfee009) AM_DEVWRITE8( "port9", h8_port_device, ddr_w, 0xff00) + AM_RANGE(0xfee008, 0xfee009) AM_DEVWRITE8( "porta", h8_port_device, ddr_w, 0x00ff) + AM_RANGE(0xfee00a, 0xfee00b) AM_DEVWRITE8( "portb", h8_port_device, ddr_w, 0xff00) + + AM_RANGE(0xfee012, 0xfee013) AM_READWRITE8( syscr_r, syscr_w, 0xff00) + AM_RANGE(0xfee014, 0xfee015) AM_DEVREADWRITE8("intc", h8h_intc_device, iscr_r, iscr_w, 0xff00) + AM_RANGE(0xfee014, 0xfee015) AM_DEVREADWRITE8("intc", h8h_intc_device, ier_r, ier_w, 0x00ff) + AM_RANGE(0xfee016, 0xfee017) AM_DEVREADWRITE8("intc", h8h_intc_device, isr_r, isr_w, 0xff00) + AM_RANGE(0xfee018, 0xfee019) AM_DEVREADWRITE8("intc", h8h_intc_device, icr_r, icr_w, 0xffff) + + AM_RANGE(0xfee03e, 0xfee03f) AM_DEVREADWRITE8("port4", h8_port_device, pcr_r, pcr_w, 0xff00) + + AM_RANGE(0xffef20, 0xffff1f) AM_RAM + + AM_RANGE(0xffff60, 0xffff61) AM_DEVREADWRITE8("timer16", h8_timer16_device, tstr_r, tstr_w, 0xff00) + AM_RANGE(0xffff60, 0xffff61) AM_DEVREADWRITE8("timer16", h8_timer16_device, tsyr_r, tsyr_w, 0x00ff) + AM_RANGE(0xffff62, 0xffff63) AM_DEVREADWRITE8("timer16", h8_timer16_device, tmdr_r, tmdr_w, 0xff00) + AM_RANGE(0xffff62, 0xffff63) AM_DEVWRITE8( "timer16", h8_timer16_device, tolr_w, 0x00ff) + AM_RANGE(0xffff64, 0xffff65) AM_DEVREADWRITE8("timer16", h8_timer16_device, tisr_r, tisr_w, 0xffff) + AM_RANGE(0xffff66, 0xffff67) AM_DEVREADWRITE8("timer16", h8_timer16_device, tisrc_r, tisrc_w, 0xff00) + AM_RANGE(0xffff68, 0xffff69) AM_DEVREADWRITE8("timer16:0", h8_timer16_channel_device, tcr_r, tcr_w, 0xff00) + AM_RANGE(0xffff68, 0xffff69) AM_DEVREADWRITE8("timer16:0", h8_timer16_channel_device, tior_r, tior_w, 0x00ff) + AM_RANGE(0xffff6a, 0xffff6b) AM_DEVREADWRITE( "timer16:0", h8_timer16_channel_device, tcnt_r, tcnt_w ) + AM_RANGE(0xffff6c, 0xffff6f) AM_DEVREADWRITE( "timer16:0", h8_timer16_channel_device, tgr_r, tgr_w ) + AM_RANGE(0xffff70, 0xffff71) AM_DEVREADWRITE8("timer16:1", h8_timer16_channel_device, tcr_r, tcr_w, 0xff00) + AM_RANGE(0xffff70, 0xffff71) AM_DEVREADWRITE8("timer16:1", h8_timer16_channel_device, tior_r, tior_w, 0x00ff) + AM_RANGE(0xffff72, 0xffff73) AM_DEVREADWRITE( "timer16:1", h8_timer16_channel_device, tcnt_r, tcnt_w ) + AM_RANGE(0xffff74, 0xffff77) AM_DEVREADWRITE( "timer16:1", h8_timer16_channel_device, tgr_r, tgr_w ) + AM_RANGE(0xffff78, 0xffff79) AM_DEVREADWRITE8("timer16:2", h8_timer16_channel_device, tcr_r, tcr_w, 0xff00) + AM_RANGE(0xffff78, 0xffff79) AM_DEVREADWRITE8("timer16:2", h8_timer16_channel_device, tior_r, tior_w, 0x00ff) + AM_RANGE(0xffff7a, 0xffff7b) AM_DEVREADWRITE( "timer16:2", h8_timer16_channel_device, tcnt_r, tcnt_w ) + AM_RANGE(0xffff7c, 0xffff7f) AM_DEVREADWRITE( "timer16:2", h8_timer16_channel_device, tgr_r, tgr_w ) + AM_RANGE(0xffff80, 0xffff81) AM_DEVREADWRITE8("timer8_0", h8_timer8_channel_device, tcr_r, tcr_w, 0xff00) + AM_RANGE(0xffff80, 0xffff81) AM_DEVREADWRITE8("timer8_1", h8_timer8_channel_device, tcr_r, tcr_w, 0x00ff) + AM_RANGE(0xffff82, 0xffff83) AM_DEVREADWRITE8("timer8_0", h8_timer8_channel_device, tcsr_r, tcsr_w, 0xff00) + AM_RANGE(0xffff82, 0xffff83) AM_DEVREADWRITE8("timer8_1", h8_timer8_channel_device, tcsr_r, tcsr_w, 0x00ff) + AM_RANGE(0xffff84, 0xffff87) AM_DEVREADWRITE8("timer8_0", h8_timer8_channel_device, tcor_r, tcor_w, 0xff00) + AM_RANGE(0xffff84, 0xffff87) AM_DEVREADWRITE8("timer8_1", h8_timer8_channel_device, tcor_r, tcor_w, 0x00ff) + AM_RANGE(0xffff88, 0xffff89) AM_DEVREADWRITE8("timer8_0", h8_timer8_channel_device, tcnt_r, tcnt_w, 0xff00) + AM_RANGE(0xffff88, 0xffff89) AM_DEVREADWRITE8("timer8_1", h8_timer8_channel_device, tcnt_r, tcnt_w, 0x00ff) + AM_RANGE(0xffff90, 0xffff91) AM_DEVREADWRITE8("timer8_2", h8_timer8_channel_device, tcr_r, tcr_w, 0xff00) + AM_RANGE(0xffff90, 0xffff91) AM_DEVREADWRITE8("timer8_3", h8_timer8_channel_device, tcr_r, tcr_w, 0x00ff) + AM_RANGE(0xffff92, 0xffff93) AM_DEVREADWRITE8("timer8_2", h8_timer8_channel_device, tcsr_r, tcsr_w, 0xff00) + AM_RANGE(0xffff92, 0xffff93) AM_DEVREADWRITE8("timer8_3", h8_timer8_channel_device, tcsr_r, tcsr_w, 0x00ff) + AM_RANGE(0xffff94, 0xffff97) AM_DEVREADWRITE8("timer8_2", h8_timer8_channel_device, tcor_r, tcor_w, 0xff00) + AM_RANGE(0xffff94, 0xffff97) AM_DEVREADWRITE8("timer8_3", h8_timer8_channel_device, tcor_r, tcor_w, 0x00ff) + AM_RANGE(0xffff98, 0xffff99) AM_DEVREADWRITE8("timer8_2", h8_timer8_channel_device, tcnt_r, tcnt_w, 0xff00) + AM_RANGE(0xffff98, 0xffff99) AM_DEVREADWRITE8("timer8_3", h8_timer8_channel_device, tcnt_r, tcnt_w, 0x00ff) + + AM_RANGE(0xffffb0, 0xffffb1) AM_DEVREADWRITE8("sci0", h8_sci_device, smr_r, smr_w, 0xff00) + AM_RANGE(0xffffb0, 0xffffb1) AM_DEVREADWRITE8("sci0", h8_sci_device, brr_r, brr_w, 0x00ff) + AM_RANGE(0xffffb2, 0xffffb3) AM_DEVREADWRITE8("sci0", h8_sci_device, scr_r, scr_w, 0xff00) + AM_RANGE(0xffffb2, 0xffffb3) AM_DEVREADWRITE8("sci0", h8_sci_device, tdr_r, tdr_w, 0x00ff) + AM_RANGE(0xffffb4, 0xffffb5) AM_DEVREADWRITE8("sci0", h8_sci_device, ssr_r, ssr_w, 0xff00) + AM_RANGE(0xffffb4, 0xffffb5) AM_DEVREAD8( "sci0", h8_sci_device, rdr_r, 0x00ff) + AM_RANGE(0xffffb6, 0xffffb7) AM_DEVREADWRITE8("sci0", h8_sci_device, scmr_r, scmr_w, 0xff00) + AM_RANGE(0xffffb8, 0xffffb9) AM_DEVREADWRITE8("sci1", h8_sci_device, smr_r, smr_w, 0xff00) + AM_RANGE(0xffffb8, 0xffffb9) AM_DEVREADWRITE8("sci1", h8_sci_device, brr_r, brr_w, 0x00ff) + AM_RANGE(0xffffba, 0xffffbb) AM_DEVREADWRITE8("sci1", h8_sci_device, scr_r, scr_w, 0xff00) + AM_RANGE(0xffffba, 0xffffbb) AM_DEVREADWRITE8("sci1", h8_sci_device, tdr_r, tdr_w, 0x00ff) + AM_RANGE(0xffffbc, 0xffffbd) AM_DEVREADWRITE8("sci1", h8_sci_device, ssr_r, ssr_w, 0xff00) + AM_RANGE(0xffffbc, 0xffffbd) AM_DEVREAD8( "sci1", h8_sci_device, rdr_r, 0x00ff) + AM_RANGE(0xffffbe, 0xffffbf) AM_DEVREADWRITE8("sci1", h8_sci_device, scmr_r, scmr_w, 0xff00) + AM_RANGE(0xffffd2, 0xffffd3) AM_DEVREADWRITE8("port4", h8_port_device, port_r, dr_w, 0x00ff) + AM_RANGE(0xffffd4, 0xffffd5) AM_DEVREADWRITE8("port6", h8_port_device, port_r, dr_w, 0x00ff) + AM_RANGE(0xffffd6, 0xffffd7) AM_DEVREADWRITE8("port7", h8_port_device, port_r, dr_w, 0xff00) + AM_RANGE(0xffffd6, 0xffffd7) AM_DEVREADWRITE8("port8", h8_port_device, port_r, dr_w, 0x00ff) + AM_RANGE(0xffffd8, 0xffffd9) AM_DEVREADWRITE8("port9", h8_port_device, port_r, dr_w, 0xff00) + AM_RANGE(0xffffd8, 0xffffd9) AM_DEVREADWRITE8("porta", h8_port_device, port_r, dr_w, 0x00ff) + AM_RANGE(0xffffda, 0xffffdb) AM_DEVREADWRITE8("portb", h8_port_device, port_r, dr_w, 0xff00) + + AM_RANGE(0xffffe0, 0xffffe7) AM_DEVREAD8( "adc", h8_adc_device, addr8_r, 0xffff) + AM_RANGE(0xffffe8, 0xffffe9) AM_DEVREADWRITE8("adc", h8_adc_device, adcsr_r, adcsr_w, 0xff00) + AM_RANGE(0xffffe8, 0xffffe9) AM_DEVREADWRITE8("adc", h8_adc_device, adcr_r, adcr_w, 0x00ff) +ADDRESS_MAP_END + +machine_config_constructor h83008_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME(h83008); +} + +void h83008_device::execute_set_input(int inputnum, int state) +{ + intc->set_input(inputnum, state); +} + +int h83008_device::trapa_setup() +{ + if(syscr & 0x08) + CCR |= F_I; + else + CCR |= F_I|F_UI; + return 8; +} + +void h83008_device::irq_setup() +{ + if(syscr & 0x08) + CCR |= F_I; + else + CCR |= F_I|F_UI; +} + +void h83008_device::update_irq_filter() +{ + switch(syscr & 0x08) { + case 0x00: + if((CCR & (F_I|F_UI)) == (F_I|F_UI)) + intc->set_filter(2, -1); + else if(CCR & F_I) + intc->set_filter(1, -1); + else + intc->set_filter(0, -1); + break; + case 0x08: + if(CCR & F_I) + intc->set_filter(2, -1); + else + intc->set_filter(0, -1); + break; + } +} + +void h83008_device::interrupt_taken() +{ + standard_irq_callback(intc->interrupt_taken(taken_irq_vector)); +} + +void h83008_device::internal_update(UINT64 current_time) +{ + UINT64 event_time = 0; + + add_event(event_time, adc->internal_update(current_time)); + add_event(event_time, sci0->internal_update(current_time)); + add_event(event_time, sci1->internal_update(current_time)); + add_event(event_time, timer8_0->internal_update(current_time)); + add_event(event_time, timer8_1->internal_update(current_time)); + add_event(event_time, timer8_2->internal_update(current_time)); + add_event(event_time, timer8_3->internal_update(current_time)); + add_event(event_time, timer16_0->internal_update(current_time)); + add_event(event_time, timer16_1->internal_update(current_time)); + add_event(event_time, timer16_2->internal_update(current_time)); + + recompute_bcount(event_time); +} + +void h83008_device::device_start() +{ + h8h_device::device_start(); +} + +void h83008_device::device_reset() +{ + h8h_device::device_reset(); + syscr = 0x09; +} + + +READ8_MEMBER(h83008_device::syscr_r) +{ + return syscr; +} + +WRITE8_MEMBER(h83008_device::syscr_w) +{ + syscr = data; + update_irq_filter(); + logerror("%s: syscr = %02x\n", tag(), data); +} diff --git a/src/devices/cpu/h8/h83008.h b/src/devices/cpu/h8/h83008.h new file mode 100644 index 00000000000..8a26d62ed69 --- /dev/null +++ b/src/devices/cpu/h8/h83008.h @@ -0,0 +1,71 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +/*************************************************************************** + + h83008.h + + H8/3008 + + H8/300H-based mcu. + + +***************************************************************************/ + +#ifndef __H83008_H__ +#define __H83008_H__ + +#include "h8h.h" +#include "h8_adc.h" +#include "h8_port.h" +#include "h8_intc.h" +#include "h8_sci.h" +#include "h8_timer8.h" +#include "h8_timer16.h" + +class h83008_device : public h8h_device { +public: + h83008_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + h83008_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + DECLARE_READ8_MEMBER(syscr_r); + DECLARE_WRITE8_MEMBER(syscr_w); + +protected: + required_device intc; + required_device adc; + required_device port4; + required_device port6; + required_device port7; + required_device port8; + required_device port9; + required_device porta; + required_device portb; + required_device timer8_0; + required_device timer8_1; + required_device timer8_2; + required_device timer8_3; + required_device timer16; + required_device timer16_0; + required_device timer16_1; + required_device timer16_2; + required_device sci0; + required_device sci1; + + UINT8 syscr; + + virtual void update_irq_filter(); + virtual void interrupt_taken(); + virtual int trapa_setup(); + virtual void irq_setup(); + virtual void internal_update(UINT64 current_time); + virtual machine_config_constructor device_mconfig_additions() const; + DECLARE_ADDRESS_MAP(map, 16); + + virtual void device_start(); + virtual void device_reset(); + virtual void execute_set_input(int inputnum, int state); +}; + +extern const device_type H83008; + +#endif diff --git a/src/devices/cpu/h8/h83048.c b/src/devices/cpu/h8/h83048.c new file mode 100644 index 00000000000..8254f5a6c22 --- /dev/null +++ b/src/devices/cpu/h8/h83048.c @@ -0,0 +1,286 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +#include "emu.h" +#include "h83048.h" + +const device_type H83044 = &device_creator; +const device_type H83045 = &device_creator; +const device_type H83047 = &device_creator; +const device_type H83048 = &device_creator; + +h83048_device::h83048_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + h8h_device(mconfig, type, name, tag, owner, clock, shortname, source, address_map_delegate(FUNC(h83048_device::map), this)), + intc(*this, "intc"), + adc(*this, "adc"), + port1(*this, "port1"), + port2(*this, "port2"), + port3(*this, "port3"), + port4(*this, "port4"), + port5(*this, "port5"), + port6(*this, "port6"), + port7(*this, "port7"), + port8(*this, "port8"), + port9(*this, "port9"), + porta(*this, "porta"), + portb(*this, "portb"), + timer16(*this, "timer16"), + timer16_0(*this, "timer16:0"), + timer16_1(*this, "timer16:1"), + timer16_2(*this, "timer16:2"), + timer16_3(*this, "timer16:3"), + timer16_4(*this, "timer16:4"), + sci0(*this, "sci0"), + sci1(*this, "sci1") +{ +} + +h83048_device::h83048_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + h8h_device(mconfig, H83048, "H8/3048", tag, owner, clock, "h83048", __FILE__, address_map_delegate(FUNC(h83048_device::map), this)), + intc(*this, "intc"), + adc(*this, "adc"), + port1(*this, "port1"), + port2(*this, "port2"), + port3(*this, "port3"), + port4(*this, "port4"), + port5(*this, "port5"), + port6(*this, "port6"), + port7(*this, "port7"), + port8(*this, "port8"), + port9(*this, "port9"), + porta(*this, "porta"), + portb(*this, "portb"), + timer16(*this, "timer16"), + timer16_0(*this, "timer16:0"), + timer16_1(*this, "timer16:1"), + timer16_2(*this, "timer16:2"), + timer16_3(*this, "timer16:3"), + timer16_4(*this, "timer16:4"), + sci0(*this, "sci0"), + sci1(*this, "sci1") +{ + ram_start = 0xffef10; +} + +h83044_device::h83044_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + h83048_device(mconfig, H83044, "H8/3044", tag, owner, clock, "h83044", __FILE__) +{ + ram_start = 0xfff710; +} + +h83045_device::h83045_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + h83048_device(mconfig, H83045, "H8/3045", tag, owner, clock, "h83045", __FILE__) +{ + ram_start = 0xfff710; +} + +h83047_device::h83047_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + h83048_device(mconfig, H83047, "H8/3047", tag, owner, clock, "h83047", __FILE__) +{ + ram_start = 0xffef10; +} + +static MACHINE_CONFIG_FRAGMENT(h83048) + MCFG_H8H_INTC_ADD("intc") + MCFG_H8_ADC_3337_ADD("adc", "intc", 60) + MCFG_H8_PORT_ADD("port1", h8_device::PORT_1, 0x00, 0x00) + MCFG_H8_PORT_ADD("port2", h8_device::PORT_2, 0x00, 0x00) + MCFG_H8_PORT_ADD("port3", h8_device::PORT_3, 0x00, 0x00) + MCFG_H8_PORT_ADD("port4", h8_device::PORT_4, 0x00, 0x00) + MCFG_H8_PORT_ADD("port5", h8_device::PORT_5, 0xf0, 0xf0) + MCFG_H8_PORT_ADD("port6", h8_device::PORT_6, 0x80, 0x80) + MCFG_H8_PORT_ADD("port7", h8_device::PORT_7, 0x00, 0x00) + MCFG_H8_PORT_ADD("port8", h8_device::PORT_8, 0xe0, 0xe0) + MCFG_H8_PORT_ADD("port9", h8_device::PORT_9, 0xc0, 0xc0) + MCFG_H8_PORT_ADD("porta", h8_device::PORT_A, 0x00, 0x00) + MCFG_H8_PORT_ADD("portb", h8_device::PORT_B, 0x00, 0x00) + MCFG_H8_TIMER16_ADD("timer16", 5, 0xe0) + MCFG_H8H_TIMER16_CHANNEL_ADD("timer16:0", 2, 2, "intc", 24) + MCFG_H8H_TIMER16_CHANNEL_ADD("timer16:1", 2, 2, "intc", 28) + MCFG_H8H_TIMER16_CHANNEL_ADD("timer16:2", 2, 2, "intc", 32) + MCFG_H8H_TIMER16_CHANNEL_ADD("timer16:3", 2, 2, "intc", 36) + MCFG_H8H_TIMER16_CHANNEL_ADD("timer16:4", 2, 2, "intc", 40) + MCFG_H8_SCI_ADD("sci0", "intc", 52, 53, 54, 55) + MCFG_H8_SCI_ADD("sci1", "intc", 56, 57, 58, 59) +MACHINE_CONFIG_END + +DEVICE_ADDRESS_MAP_START(map, 16, h83048_device) + AM_RANGE(ram_start, 0xffff0f) AM_RAM + + AM_RANGE(0xffff60, 0xffff61) AM_DEVREADWRITE8("timer16", h8_timer16_device, tstr_r, tstr_w, 0xff00) + AM_RANGE(0xffff60, 0xffff61) AM_DEVREADWRITE8("timer16", h8_timer16_device, tsyr_r, tsyr_w, 0x00ff) + AM_RANGE(0xffff62, 0xffff63) AM_DEVREADWRITE8("timer16", h8_timer16_device, tmdr_r, tmdr_w, 0xff00) + AM_RANGE(0xffff62, 0xffff63) AM_DEVREADWRITE8("timer16", h8_timer16_device, tfcr_r, tfcr_w, 0x00ff) + AM_RANGE(0xffff64, 0xffff65) AM_DEVREADWRITE8("timer16:0", h8_timer16_channel_device, tcr_r, tcr_w, 0xff00) + AM_RANGE(0xffff64, 0xffff65) AM_DEVREADWRITE8("timer16:0", h8_timer16_channel_device, tior_r, tior_w, 0x00ff) + AM_RANGE(0xffff66, 0xffff67) AM_DEVREADWRITE8("timer16:0", h8_timer16_channel_device, tier_r, tier_w, 0xff00) + AM_RANGE(0xffff66, 0xffff67) AM_DEVREADWRITE8("timer16:0", h8_timer16_channel_device, tsr_r, tsr_w, 0x00ff) + AM_RANGE(0xffff68, 0xffff69) AM_DEVREADWRITE( "timer16:0", h8_timer16_channel_device, tcnt_r, tcnt_w ) + AM_RANGE(0xffff6a, 0xffff6d) AM_DEVREADWRITE( "timer16:0", h8_timer16_channel_device, tgr_r, tgr_w ) + AM_RANGE(0xffff6e, 0xffff6f) AM_DEVREADWRITE8("timer16:1", h8_timer16_channel_device, tcr_r, tcr_w, 0xff00) + AM_RANGE(0xffff6e, 0xffff6f) AM_DEVREADWRITE8("timer16:1", h8_timer16_channel_device, tior_r, tior_w, 0x00ff) + AM_RANGE(0xffff70, 0xffff71) AM_DEVREADWRITE8("timer16:1", h8_timer16_channel_device, tier_r, tier_w, 0xff00) + AM_RANGE(0xffff70, 0xffff71) AM_DEVREADWRITE8("timer16:1", h8_timer16_channel_device, tsr_r, tsr_w, 0x00ff) + AM_RANGE(0xffff72, 0xffff73) AM_DEVREADWRITE( "timer16:1", h8_timer16_channel_device, tcnt_r, tcnt_w ) + AM_RANGE(0xffff74, 0xffff77) AM_DEVREADWRITE( "timer16:1", h8_timer16_channel_device, tgr_r, tgr_w ) + AM_RANGE(0xffff78, 0xffff79) AM_DEVREADWRITE8("timer16:2", h8_timer16_channel_device, tcr_r, tcr_w, 0xff00) + AM_RANGE(0xffff78, 0xffff79) AM_DEVREADWRITE8("timer16:2", h8_timer16_channel_device, tior_r, tior_w, 0x00ff) + AM_RANGE(0xffff7a, 0xffff7b) AM_DEVREADWRITE8("timer16:2", h8_timer16_channel_device, tier_r, tier_w, 0xff00) + AM_RANGE(0xffff7a, 0xffff7b) AM_DEVREADWRITE8("timer16:2", h8_timer16_channel_device, tsr_r, tsr_w, 0x00ff) + AM_RANGE(0xffff7c, 0xffff7d) AM_DEVREADWRITE( "timer16:2", h8_timer16_channel_device, tcnt_r, tcnt_w ) + AM_RANGE(0xffff7e, 0xffff81) AM_DEVREADWRITE( "timer16:2", h8_timer16_channel_device, tgr_r, tgr_w ) + AM_RANGE(0xffff82, 0xffff83) AM_DEVREADWRITE8("timer16:3", h8_timer16_channel_device, tcr_r, tcr_w, 0xff00) + AM_RANGE(0xffff82, 0xffff83) AM_DEVREADWRITE8("timer16:3", h8_timer16_channel_device, tior_r, tior_w, 0x00ff) + AM_RANGE(0xffff84, 0xffff85) AM_DEVREADWRITE8("timer16:3", h8_timer16_channel_device, tier_r, tier_w, 0xff00) + AM_RANGE(0xffff84, 0xffff85) AM_DEVREADWRITE8("timer16:3", h8_timer16_channel_device, tsr_r, tsr_w, 0x00ff) + AM_RANGE(0xffff86, 0xffff87) AM_DEVREADWRITE( "timer16:3", h8_timer16_channel_device, tcnt_r, tcnt_w ) + AM_RANGE(0xffff88, 0xffff8b) AM_DEVREADWRITE( "timer16:3", h8_timer16_channel_device, tgr_r, tgr_w ) + AM_RANGE(0xffff8c, 0xffff8f) AM_DEVREADWRITE( "timer16:3", h8_timer16_channel_device, tbr_r, tbr_w ) + AM_RANGE(0xffff90, 0xffff91) AM_DEVREADWRITE8("timer16", h8_timer16_device, toer_r, toer_w, 0xff00) + AM_RANGE(0xffff90, 0xffff91) AM_DEVREADWRITE8("timer16", h8_timer16_device, tocr_r, tocr_w, 0x00ff) + AM_RANGE(0xffff92, 0xffff93) AM_DEVREADWRITE8("timer16:4", h8_timer16_channel_device, tcr_r, tcr_w, 0xff00) + AM_RANGE(0xffff92, 0xffff93) AM_DEVREADWRITE8("timer16:4", h8_timer16_channel_device, tior_r, tior_w, 0x00ff) + AM_RANGE(0xffff94, 0xffff95) AM_DEVREADWRITE8("timer16:4", h8_timer16_channel_device, tier_r, tier_w, 0xff00) + AM_RANGE(0xffff94, 0xffff95) AM_DEVREADWRITE8("timer16:4", h8_timer16_channel_device, tsr_r, tsr_w, 0x00ff) + AM_RANGE(0xffff96, 0xffff97) AM_DEVREADWRITE( "timer16:4", h8_timer16_channel_device, tcnt_r, tcnt_w ) + AM_RANGE(0xffff98, 0xffff9b) AM_DEVREADWRITE( "timer16:4", h8_timer16_channel_device, tgr_r, tgr_w ) + AM_RANGE(0xffff9c, 0xffff9f) AM_DEVREADWRITE( "timer16:4", h8_timer16_channel_device, tbr_r, tbr_w ) + + AM_RANGE(0xffffb0, 0xffffb1) AM_DEVREADWRITE8("sci0", h8_sci_device, smr_r, smr_w, 0xff00) + AM_RANGE(0xffffb0, 0xffffb1) AM_DEVREADWRITE8("sci0", h8_sci_device, brr_r, brr_w, 0x00ff) + AM_RANGE(0xffffb2, 0xffffb3) AM_DEVREADWRITE8("sci0", h8_sci_device, scr_r, scr_w, 0xff00) + AM_RANGE(0xffffb2, 0xffffb3) AM_DEVREADWRITE8("sci0", h8_sci_device, tdr_r, tdr_w, 0x00ff) + AM_RANGE(0xffffb4, 0xffffb5) AM_DEVREADWRITE8("sci0", h8_sci_device, ssr_r, ssr_w, 0xff00) + AM_RANGE(0xffffb4, 0xffffb5) AM_DEVREAD8( "sci0", h8_sci_device, rdr_r, 0x00ff) + AM_RANGE(0xffffb8, 0xffffb9) AM_DEVREADWRITE8("sci1", h8_sci_device, smr_r, smr_w, 0xff00) + AM_RANGE(0xffffb8, 0xffffb9) AM_DEVREADWRITE8("sci1", h8_sci_device, brr_r, brr_w, 0x00ff) + AM_RANGE(0xffffba, 0xffffbb) AM_DEVREADWRITE8("sci1", h8_sci_device, scr_r, scr_w, 0xff00) + AM_RANGE(0xffffba, 0xffffbb) AM_DEVREADWRITE8("sci1", h8_sci_device, tdr_r, tdr_w, 0x00ff) + AM_RANGE(0xffffbc, 0xffffbd) AM_DEVREADWRITE8("sci1", h8_sci_device, ssr_r, ssr_w, 0xff00) + AM_RANGE(0xffffbc, 0xffffbd) AM_DEVREAD8( "sci1", h8_sci_device, rdr_r, 0x00ff) + AM_RANGE(0xffffc0, 0xffffc1) AM_DEVWRITE8( "port1", h8_port_device, ddr_w, 0xff00) + AM_RANGE(0xffffc0, 0xffffc1) AM_DEVWRITE8( "port2", h8_port_device, ddr_w, 0x00ff) + AM_RANGE(0xffffc2, 0xffffc3) AM_DEVREADWRITE8("port1", h8_port_device, port_r, dr_w, 0xff00) + AM_RANGE(0xffffc2, 0xffffc3) AM_DEVREADWRITE8("port2", h8_port_device, port_r, dr_w, 0x00ff) + AM_RANGE(0xffffc4, 0xffffc5) AM_DEVWRITE8( "port3", h8_port_device, ddr_w, 0xff00) + AM_RANGE(0xffffc4, 0xffffc5) AM_DEVWRITE8( "port4", h8_port_device, ddr_w, 0x00ff) + AM_RANGE(0xffffc6, 0xffffc7) AM_DEVREADWRITE8("port3", h8_port_device, port_r, dr_w, 0xff00) + AM_RANGE(0xffffc6, 0xffffc7) AM_DEVREADWRITE8("port4", h8_port_device, port_r, dr_w, 0x00ff) + AM_RANGE(0xffffc8, 0xffffc9) AM_DEVWRITE8( "port5", h8_port_device, ddr_w, 0xff00) + AM_RANGE(0xffffc8, 0xffffc9) AM_DEVWRITE8( "port6", h8_port_device, ddr_w, 0x00ff) + AM_RANGE(0xffffca, 0xffffcb) AM_DEVREADWRITE8("port5", h8_port_device, port_r, dr_w, 0xff00) + AM_RANGE(0xffffca, 0xffffcb) AM_DEVREADWRITE8("port6", h8_port_device, port_r, dr_w, 0x00ff) + AM_RANGE(0xffffcc, 0xffffcd) AM_DEVWRITE8( "port8", h8_port_device, ddr_w, 0x00ff) + AM_RANGE(0xffffce, 0xffffcf) AM_DEVREADWRITE8("port7", h8_port_device, port_r, dr_w, 0xff00) + AM_RANGE(0xffffce, 0xffffcf) AM_DEVREADWRITE8("port8", h8_port_device, port_r, dr_w, 0x00ff) + AM_RANGE(0xffffd0, 0xffffd1) AM_DEVWRITE8( "port9", h8_port_device, ddr_w, 0xff00) + AM_RANGE(0xffffd0, 0xffffd1) AM_DEVWRITE8( "porta", h8_port_device, ddr_w, 0x00ff) + AM_RANGE(0xffffd2, 0xffffd3) AM_DEVREADWRITE8("port9", h8_port_device, port_r, dr_w, 0xff00) + AM_RANGE(0xffffd2, 0xffffd3) AM_DEVREADWRITE8("porta", h8_port_device, port_r, dr_w, 0x00ff) + AM_RANGE(0xffffd4, 0xffffd5) AM_DEVWRITE8( "portb", h8_port_device, ddr_w, 0xff00) + AM_RANGE(0xffffd6, 0xffffd7) AM_DEVREADWRITE8("portb", h8_port_device, port_r, dr_w, 0xff00) + AM_RANGE(0xffffd8, 0xffffd9) AM_DEVREADWRITE8("port2", h8_port_device, pcr_r, pcr_w, 0xff00) + AM_RANGE(0xffffda, 0xffffdb) AM_DEVREADWRITE8("port4", h8_port_device, pcr_r, pcr_w, 0xff00) + AM_RANGE(0xffffda, 0xffffdb) AM_DEVREADWRITE8("port5", h8_port_device, pcr_r, pcr_w, 0x00ff) + + AM_RANGE(0xffffe0, 0xffffe7) AM_DEVREAD8( "adc", h8_adc_device, addr8_r, 0xffff) + AM_RANGE(0xffffe8, 0xffffe9) AM_DEVREADWRITE8("adc", h8_adc_device, adcsr_r, adcsr_w, 0xff00) + AM_RANGE(0xffffe8, 0xffffe9) AM_DEVREADWRITE8("adc", h8_adc_device, adcr_r, adcr_w, 0x00ff) + + AM_RANGE(0xfffff2, 0xfffff3) AM_READWRITE8( syscr_r, syscr_w, 0xff00) + + AM_RANGE(0xfffff4, 0xfffff5) AM_DEVREADWRITE8("intc", h8h_intc_device, iscr_r, iscr_w, 0xff00) + AM_RANGE(0xfffff4, 0xfffff5) AM_DEVREADWRITE8("intc", h8h_intc_device, ier_r, ier_w, 0x00ff) + AM_RANGE(0xfffff6, 0xfffff7) AM_DEVREADWRITE8("intc", h8h_intc_device, isr_r, isr_w, 0xff00) + AM_RANGE(0xfffff8, 0xfffff9) AM_DEVREADWRITE8("intc", h8h_intc_device, icr_r, icr_w, 0xffff) +ADDRESS_MAP_END + +machine_config_constructor h83048_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME(h83048); +} + +void h83048_device::execute_set_input(int inputnum, int state) +{ + intc->set_input(inputnum, state); +} + +int h83048_device::trapa_setup() +{ + if(syscr & 0x08) + CCR |= F_I; + else + CCR |= F_I|F_UI; + return 8; +} + +void h83048_device::irq_setup() +{ + if(syscr & 0x08) + CCR |= F_I; + else + CCR |= F_I|F_UI; +} + +void h83048_device::update_irq_filter() +{ + switch(syscr & 0x08) { + case 0x00: + if((CCR & (F_I|F_UI)) == (F_I|F_UI)) + intc->set_filter(2, -1); + else if(CCR & F_I) + intc->set_filter(1, -1); + else + intc->set_filter(0, -1); + break; + case 0x08: + if(CCR & F_I) + intc->set_filter(2, -1); + else + intc->set_filter(0, -1); + break; + } +} + +void h83048_device::interrupt_taken() +{ + standard_irq_callback(intc->interrupt_taken(taken_irq_vector)); +} + +void h83048_device::internal_update(UINT64 current_time) +{ + UINT64 event_time = 0; + + add_event(event_time, adc->internal_update(current_time)); + add_event(event_time, sci0->internal_update(current_time)); + add_event(event_time, sci1->internal_update(current_time)); + add_event(event_time, timer16_0->internal_update(current_time)); + add_event(event_time, timer16_1->internal_update(current_time)); + add_event(event_time, timer16_2->internal_update(current_time)); + add_event(event_time, timer16_3->internal_update(current_time)); + add_event(event_time, timer16_4->internal_update(current_time)); + + recompute_bcount(event_time); +} + +void h83048_device::device_start() +{ + h8h_device::device_start(); +} + +void h83048_device::device_reset() +{ + h8h_device::device_reset(); + syscr = 0x0b; +} + +READ8_MEMBER(h83048_device::syscr_r) +{ + return syscr; +} + +WRITE8_MEMBER(h83048_device::syscr_w) +{ + syscr = data; + update_irq_filter(); + logerror("%s: syscr = %02x\n", tag(), data); +} diff --git a/src/devices/cpu/h8/h83048.h b/src/devices/cpu/h8/h83048.h new file mode 100644 index 00000000000..ecb3ed573d5 --- /dev/null +++ b/src/devices/cpu/h8/h83048.h @@ -0,0 +1,99 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +/*************************************************************************** + + h83048.h + + H8-3048 family emulation + + H8-300H-based mcus. + + Variant ROM RAM + H8/3044 32K 2K + H8/3045 64K 2K + H8/3047 96K 4K + H8/3048 192K 4K + + The 3394, 3396, and 3997 variants are the mask-rom versions. + + +***************************************************************************/ + +#ifndef __H83048_H__ +#define __H83048_H__ + +#include "h8h.h" +#include "h8_adc.h" +#include "h8_port.h" +#include "h8_intc.h" +#include "h8_sci.h" +#include "h8_timer16.h" + +class h83048_device : public h8h_device { +public: + h83048_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + h83048_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + DECLARE_READ8_MEMBER(syscr_r); + DECLARE_WRITE8_MEMBER(syscr_w); + +protected: + required_device intc; + required_device adc; + required_device port1; + required_device port2; + required_device port3; + required_device port4; + required_device port5; + required_device port6; + required_device port7; + required_device port8; + required_device port9; + required_device porta; + required_device portb; + required_device timer16; + required_device timer16_0; + required_device timer16_1; + required_device timer16_2; + required_device timer16_3; + required_device timer16_4; + required_device sci0; + required_device sci1; + + UINT32 ram_start; + UINT8 syscr; + + virtual void update_irq_filter(); + virtual void interrupt_taken(); + virtual int trapa_setup(); + virtual void irq_setup(); + virtual void internal_update(UINT64 current_time); + virtual machine_config_constructor device_mconfig_additions() const; + DECLARE_ADDRESS_MAP(map, 16); + + virtual void device_start(); + virtual void device_reset(); + virtual void execute_set_input(int inputnum, int state); +}; + +class h83044_device : public h83048_device { +public: + h83044_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class h83045_device : public h83048_device { +public: + h83045_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class h83047_device : public h83048_device { +public: + h83047_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +extern const device_type H83044; +extern const device_type H83045; +extern const device_type H83047; +extern const device_type H83048; + +#endif diff --git a/src/devices/cpu/h8/h83337.c b/src/devices/cpu/h8/h83337.c new file mode 100644 index 00000000000..00a353e4347 --- /dev/null +++ b/src/devices/cpu/h8/h83337.c @@ -0,0 +1,247 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +#include "emu.h" +#include "h83337.h" + +const device_type H83334 = &device_creator; +const device_type H83336 = &device_creator; +const device_type H83337 = &device_creator; + + +h83337_device::h83337_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + h8_device(mconfig, type, name, tag, owner, clock, shortname, source, true, address_map_delegate(FUNC(h83337_device::map), this)), + intc(*this, "intc"), + adc(*this, "adc"), + port1(*this, "port1"), + port2(*this, "port2"), + port3(*this, "port3"), + port4(*this, "port4"), + port5(*this, "port5"), + port6(*this, "port6"), + port7(*this, "port7"), + port8(*this, "port8"), + port9(*this, "port9"), + timer8_0(*this, "timer8_0"), + timer8_1(*this, "timer8_1"), + timer16(*this, "timer16"), + timer16_0(*this, "timer16:0"), + sci0(*this, "sci0"), + sci1(*this, "sci1") +{ +} + +h83337_device::h83337_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + h8_device(mconfig, H83337, "H8/3337", tag, owner, clock, "h83337", __FILE__, true, address_map_delegate(FUNC(h83337_device::map), this)), + intc(*this, "intc"), + adc(*this, "adc"), + port1(*this, "port1"), + port2(*this, "port2"), + port3(*this, "port3"), + port4(*this, "port4"), + port5(*this, "port5"), + port6(*this, "port6"), + port7(*this, "port7"), + port8(*this, "port8"), + port9(*this, "port9"), + timer8_0(*this, "timer8_0"), + timer8_1(*this, "timer8_1"), + timer16(*this, "timer16"), + timer16_0(*this, "timer16:0"), + sci0(*this, "sci0"), + sci1(*this, "sci1") +{ + ram_start = 0xf780; +} + +h83334_device::h83334_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + h83337_device(mconfig, H83334, "H8/3334", tag, owner, clock, "h83334", __FILE__) +{ + ram_start = 0xfb80; +} + +h83336_device::h83336_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + h83337_device(mconfig, H83336, "H8/3336", tag, owner, clock, "h83336", __FILE__) +{ + ram_start = 0xf780; +} + +static MACHINE_CONFIG_FRAGMENT(h83337) + MCFG_H8_INTC_ADD("intc") + MCFG_H8_ADC_3337_ADD("adc", "intc", 35) + MCFG_H8_PORT_ADD("port1", h8_device::PORT_1, 0x00, 0x00) + MCFG_H8_PORT_ADD("port2", h8_device::PORT_2, 0x00, 0x00) + MCFG_H8_PORT_ADD("port3", h8_device::PORT_3, 0x00, 0x00) + MCFG_H8_PORT_ADD("port4", h8_device::PORT_4, 0x00, 0x00) + MCFG_H8_PORT_ADD("port5", h8_device::PORT_5, 0xf8, 0xf8) + MCFG_H8_PORT_ADD("port6", h8_device::PORT_6, 0x00, 0x00) + MCFG_H8_PORT_ADD("port7", h8_device::PORT_7, 0x00, 0x00) + MCFG_H8_PORT_ADD("port8", h8_device::PORT_8, 0x80, 0x80) + MCFG_H8_PORT_ADD("port9", h8_device::PORT_9, 0x00, 0x00) + MCFG_H8_TIMER8_CHANNEL_ADD("timer8_0", "intc", 19, 20, 21, 8, 2, 64, 32, 1024, 256) + MCFG_H8_TIMER8_CHANNEL_ADD("timer8_1", "intc", 22, 23, 24, 8, 2, 64, 128, 1024, 2048) + MCFG_H8_TIMER16_ADD("timer16", 1, 0xff) + MCFG_H8_TIMER16_CHANNEL_ADD("timer16:0", 4, 0, "intc", 32) + MCFG_H8_SCI_ADD("sci0", "intc", 27, 28, 29, 30) + MCFG_H8_SCI_ADD("sci1", "intc", 31, 32, 33, 34) +MACHINE_CONFIG_END + +DEVICE_ADDRESS_MAP_START(map, 16, h83337_device) + AM_RANGE(ram_start, 0xff7f) AM_RAM + + AM_RANGE(0xff88, 0xff89) AM_DEVREADWRITE8("sci1", h8_sci_device, smr_r, smr_w, 0xff00) + AM_RANGE(0xff88, 0xff89) AM_DEVREADWRITE8("sci1", h8_sci_device, brr_r, brr_w, 0x00ff) + AM_RANGE(0xff8a, 0xff8b) AM_DEVREADWRITE8("sci1", h8_sci_device, scr_r, scr_w, 0xff00) + AM_RANGE(0xff8a, 0xff8b) AM_DEVREADWRITE8("sci1", h8_sci_device, tdr_r, tdr_w, 0x00ff) + AM_RANGE(0xff8c, 0xff8d) AM_DEVREADWRITE8("sci1", h8_sci_device, ssr_r, ssr_w, 0xff00) + AM_RANGE(0xff8c, 0xff8d) AM_DEVREAD8( "sci1", h8_sci_device, rdr_r, 0x00ff) + AM_RANGE(0xff90, 0xff91) AM_DEVREADWRITE8("timer16:0", h8_timer16_channel_device, tier_r, tier_w, 0xff00) + AM_RANGE(0xff90, 0xff91) AM_DEVREADWRITE8("timer16:0", h8_timer16_channel_device, tsr_r, tsr_w, 0x00ff) + AM_RANGE(0xff92, 0xff93) AM_DEVREADWRITE( "timer16:0", h8_timer16_channel_device, tcnt_r, tcnt_w ) +// AM_RANGE(0xff94, 0xff95) AM_DEVREADWRITE( "timer16:0", h8_timer16_channel_device, ocr_r, ocr_w ) + AM_RANGE(0xff96, 0xff97) AM_DEVREADWRITE8("timer16:0", h8_timer16_channel_device, tcr_r, tcr_w, 0xff00) +// AM_RANGE(0xff96, 0xff97) AM_DEVREADWRITE8("timer16:0", h8_timer16_channel_device, tocr_r, tocr_w, 0x00ff) + AM_RANGE(0xff98, 0xff9f) AM_DEVREAD( "timer16:0", h8_timer16_channel_device, tgr_r ) + + AM_RANGE(0xffac, 0xffad) AM_DEVREADWRITE8("port1", h8_port_device, pcr_r, pcr_w, 0xff00) + AM_RANGE(0xffac, 0xffad) AM_DEVREADWRITE8("port2", h8_port_device, pcr_r, pcr_w, 0x00ff) + AM_RANGE(0xffae, 0xffaf) AM_DEVREADWRITE8("port3", h8_port_device, pcr_r, pcr_w, 0xff00) + AM_RANGE(0xffb0, 0xffb1) AM_DEVWRITE8( "port1", h8_port_device, ddr_w, 0xff00) + AM_RANGE(0xffb0, 0xffb1) AM_DEVWRITE8( "port2", h8_port_device, ddr_w, 0x00ff) + AM_RANGE(0xffb2, 0xffb3) AM_DEVREADWRITE8("port1", h8_port_device, port_r, dr_w, 0xff00) + AM_RANGE(0xffb2, 0xffb3) AM_DEVREADWRITE8("port2", h8_port_device, port_r, dr_w, 0x00ff) + AM_RANGE(0xffb4, 0xffb5) AM_DEVWRITE8( "port3", h8_port_device, ddr_w, 0xff00) + AM_RANGE(0xffb4, 0xffb5) AM_DEVWRITE8( "port4", h8_port_device, ddr_w, 0x00ff) + AM_RANGE(0xffb6, 0xffb7) AM_DEVREADWRITE8("port3", h8_port_device, port_r, dr_w, 0xff00) + AM_RANGE(0xffb6, 0xffb7) AM_DEVREADWRITE8("port4", h8_port_device, port_r, dr_w, 0x00ff) + AM_RANGE(0xffb8, 0xffb9) AM_DEVWRITE8( "port5", h8_port_device, ddr_w, 0xff00) + AM_RANGE(0xffb8, 0xffb9) AM_DEVWRITE8( "port6", h8_port_device, ddr_w, 0x00ff) + AM_RANGE(0xffba, 0xffbb) AM_DEVREADWRITE8("port5", h8_port_device, port_r, dr_w, 0xff00) + AM_RANGE(0xffba, 0xffbb) AM_DEVREADWRITE8("port6", h8_port_device, port_r, dr_w, 0x00ff) + AM_RANGE(0xffbc, 0xffbd) AM_DEVWRITE8( "port8", h8_port_device, ddr_w, 0x00ff) + AM_RANGE(0xffbe, 0xffbf) AM_DEVREADWRITE8("port7", h8_port_device, port_r, dr_w, 0xff00) + AM_RANGE(0xffbe, 0xffbf) AM_DEVREADWRITE8("port8", h8_port_device, port_r, dr_w, 0x00ff) + AM_RANGE(0xffc0, 0xffc1) AM_DEVWRITE8( "port9", h8_port_device, ddr_w, 0xff00) + AM_RANGE(0xffc0, 0xffc1) AM_DEVREADWRITE8("port9", h8_port_device, port_r, dr_w, 0x00ff) + AM_RANGE(0xffc2, 0xffc3) AM_READWRITE8( wscr_r, wscr_w, 0xff00) + AM_RANGE(0xffc2, 0xffc3) AM_READWRITE8( stcr_r, stcr_w, 0x00ff) + AM_RANGE(0xffc4, 0xffc5) AM_READWRITE8( syscr_r, syscr_w, 0xff00) + AM_RANGE(0xffc4, 0xffc5) AM_READWRITE8( mdcr_r, mdcr_w, 0x00ff) + AM_RANGE(0xffc6, 0xffc7) AM_DEVREADWRITE8("intc", h8_intc_device, iscr_r, iscr_w, 0xff00) + AM_RANGE(0xffc6, 0xffc7) AM_DEVREADWRITE8("intc", h8_intc_device, ier_r, ier_w, 0x00ff) + AM_RANGE(0xffc8, 0xffc9) AM_DEVREADWRITE8("timer8_0", h8_timer8_channel_device, tcr_r, tcr_w, 0xff00) + AM_RANGE(0xffc8, 0xffc9) AM_DEVREADWRITE8("timer8_0", h8_timer8_channel_device, tcsr_r, tcsr_w, 0x00ff) + AM_RANGE(0xffca, 0xffcb) AM_DEVREADWRITE8("timer8_0", h8_timer8_channel_device, tcor_r, tcor_w, 0xffff) + AM_RANGE(0xffcc, 0xffcd) AM_DEVREADWRITE8("timer8_0", h8_timer8_channel_device, tcnt_r, tcnt_w, 0xff00) + AM_RANGE(0xffd0, 0xffd1) AM_DEVREADWRITE8("timer8_1", h8_timer8_channel_device, tcr_r, tcr_w, 0xff00) + AM_RANGE(0xffd0, 0xffd1) AM_DEVREADWRITE8("timer8_1", h8_timer8_channel_device, tcsr_r, tcsr_w, 0x00ff) + AM_RANGE(0xffd2, 0xffd3) AM_DEVREADWRITE8("timer8_1", h8_timer8_channel_device, tcor_r, tcor_w, 0xffff) + AM_RANGE(0xffd4, 0xffd5) AM_DEVREADWRITE8("timer8_1", h8_timer8_channel_device, tcnt_r, tcnt_w, 0xff00) + AM_RANGE(0xffd8, 0xffd9) AM_DEVREADWRITE8("sci0", h8_sci_device, smr_r, smr_w, 0xff00) + AM_RANGE(0xffd8, 0xffd9) AM_DEVREADWRITE8("sci0", h8_sci_device, brr_r, brr_w, 0x00ff) + AM_RANGE(0xffda, 0xffdb) AM_DEVREADWRITE8("sci0", h8_sci_device, scr_r, scr_w, 0xff00) + AM_RANGE(0xffda, 0xffdb) AM_DEVREADWRITE8("sci0", h8_sci_device, tdr_r, tdr_w, 0x00ff) + AM_RANGE(0xffdc, 0xffdd) AM_DEVREADWRITE8("sci0", h8_sci_device, ssr_r, ssr_w, 0xff00) + AM_RANGE(0xffdc, 0xffdd) AM_DEVREAD8( "sci0", h8_sci_device, rdr_r, 0x00ff) + + AM_RANGE(0xffe0, 0xffe7) AM_DEVREAD8( "adc", h8_adc_device, addr8_r, 0xffff) + AM_RANGE(0xffe8, 0xffe9) AM_DEVREADWRITE8("adc", h8_adc_device, adcsr_r, adcsr_w, 0xff00) + AM_RANGE(0xffe8, 0xffe9) AM_DEVREADWRITE8("adc", h8_adc_device, adcr_r, adcr_w, 0x00ff) + + AM_RANGE(0xfff2, 0xfff3) AM_DEVREADWRITE8("port6", h8_port_device, pcr_r, pcr_w, 0xff00) +ADDRESS_MAP_END + +machine_config_constructor h83337_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME(h83337); +} + +void h83337_device::execute_set_input(int inputnum, int state) +{ + intc->set_input(inputnum, state); +} + +void h83337_device::irq_setup() +{ + CCR |= F_I; +} + +void h83337_device::update_irq_filter() +{ + if(CCR & F_I) + intc->set_filter(2, -1); + else + intc->set_filter(0, -1); +} + +void h83337_device::interrupt_taken() +{ + standard_irq_callback(intc->interrupt_taken(taken_irq_vector)); +} + +void h83337_device::internal_update(UINT64 current_time) +{ + UINT64 event_time = 0; + + add_event(event_time, adc->internal_update(current_time)); + add_event(event_time, sci0->internal_update(current_time)); + add_event(event_time, sci1->internal_update(current_time)); + add_event(event_time, timer8_0->internal_update(current_time)); + add_event(event_time, timer8_1->internal_update(current_time)); + add_event(event_time, timer16_0->internal_update(current_time)); + + recompute_bcount(event_time); +} + +void h83337_device::device_start() +{ + h8_device::device_start(); +} + +void h83337_device::device_reset() +{ + h8_device::device_reset(); + syscr = 0x09; +} + +READ8_MEMBER(h83337_device::syscr_r) +{ + return syscr; +} + +WRITE8_MEMBER(h83337_device::syscr_w) +{ + syscr = data; + logerror("%s: syscr = %02x\n", tag(), data); +} + +READ8_MEMBER(h83337_device::wscr_r) +{ + return 0x00; +} + +WRITE8_MEMBER(h83337_device::wscr_w) +{ + logerror("%s: wscr = %02x\n", tag(), data); +} + +READ8_MEMBER(h83337_device::stcr_r) +{ + return 0x00; +} + +WRITE8_MEMBER(h83337_device::stcr_w) +{ + logerror("%s: stcr = %02x\n", tag(), data); + timer8_0->set_extra_clock_bit(data & 0x01); + timer8_1->set_extra_clock_bit(data & 0x02); +} + +READ8_MEMBER(h83337_device::mdcr_r) +{ + return 0x00; +} + +WRITE8_MEMBER(h83337_device::mdcr_w) +{ + logerror("%s: mdcr = %02x\n", tag(), data); +} diff --git a/src/devices/cpu/h8/h83337.h b/src/devices/cpu/h8/h83337.h new file mode 100644 index 00000000000..b01580733da --- /dev/null +++ b/src/devices/cpu/h8/h83337.h @@ -0,0 +1,94 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +/*************************************************************************** + + h83337.h + + H8-3337 family emulation + + H8-300-based mcus. + + Variant ROM RAM + H8/3334 32K 1K + H8/3336 48K 2K + H8/3337 60K 2K + + The 3394, 3396, and 3397 variants are the mask-rom versions. + + +***************************************************************************/ + +#ifndef __H83337_H__ +#define __H83337_H__ + +#include "h8.h" +#include "h8_adc.h" +#include "h8_port.h" +#include "h8_intc.h" +#include "h8_timer8.h" +#include "h8_timer16.h" +#include "h8_sci.h" + +class h83337_device : public h8_device { +public: + h83337_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + h83337_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + DECLARE_READ8_MEMBER(wscr_r); + DECLARE_WRITE8_MEMBER(wscr_w); + DECLARE_READ8_MEMBER(stcr_r); + DECLARE_WRITE8_MEMBER(stcr_w); + DECLARE_READ8_MEMBER(syscr_r); + DECLARE_WRITE8_MEMBER(syscr_w); + DECLARE_READ8_MEMBER(mdcr_r); + DECLARE_WRITE8_MEMBER(mdcr_w); + +protected: + required_device intc; + required_device adc; + required_device port1; + required_device port2; + required_device port3; + required_device port4; + required_device port5; + required_device port6; + required_device port7; + required_device port8; + required_device port9; + required_device timer8_0; + required_device timer8_1; + required_device timer16; + required_device timer16_0; + required_device sci0; + required_device sci1; + + UINT8 syscr; + UINT32 ram_start; + + virtual void update_irq_filter(); + virtual void interrupt_taken(); + virtual void irq_setup(); + virtual void internal_update(UINT64 current_time); + virtual machine_config_constructor device_mconfig_additions() const; + DECLARE_ADDRESS_MAP(map, 16); + + virtual void device_start(); + virtual void device_reset(); + virtual void execute_set_input(int inputnum, int state); +}; + +class h83334_device : public h83337_device { +public: + h83334_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class h83336_device : public h83337_device { +public: + h83336_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +extern const device_type H83334; +extern const device_type H83336; +extern const device_type H83337; + +#endif diff --git a/src/devices/cpu/h8/h8_adc.c b/src/devices/cpu/h8/h8_adc.c new file mode 100644 index 00000000000..b1f02f83ca7 --- /dev/null +++ b/src/devices/cpu/h8/h8_adc.c @@ -0,0 +1,501 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +#include "emu.h" +#include "h8_adc.h" + +const device_type H8_ADC_3337 = &device_creator; +const device_type H8_ADC_3006 = &device_creator; +const device_type H8_ADC_2245 = &device_creator; +const device_type H8_ADC_2320 = &device_creator; +const device_type H8_ADC_2357 = &device_creator; +const device_type H8_ADC_2655 = &device_creator; + +h8_adc_device::h8_adc_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + cpu(*this, DEVICE_SELF_OWNER) +{ + suspend_on_interrupt = false; + analog_power_control = false; +} + +void h8_adc_device::set_info(const char *_intc_tag, int _intc_vector) +{ + intc_tag = _intc_tag; + intc_vector = _intc_vector; +} + +READ8_MEMBER(h8_adc_device::addr8_r) +{ + logerror("%s: addr8_r %d %03x\n", tag(), offset, addr[offset >> 1]); + return offset & 1 ? addr[offset >> 1] >> 2 : addr[offset >> 1] << 6; +} + +READ16_MEMBER(h8_adc_device::addr16_r) +{ + logerror("%s: addr16_r %d %03x\n", tag(), offset, addr[offset]); + return addr[offset]; +} + +READ8_MEMBER(h8_adc_device::adcsr_r) +{ + logerror("%s: adcsr_r %02x\n", tag(), adcsr); + return adcsr; +} + +READ8_MEMBER(h8_adc_device::adcr_r) +{ + logerror("%s: adcr_r %02x\n", tag(), adcr); + return adcr; +} + +WRITE8_MEMBER(h8_adc_device::adcsr_w) +{ + logerror("%s: adcsr_w %02x\n", tag(), data); + UINT8 prev = adcsr; + adcsr = (data & 0x7f) | (adcsr & data & F_ADF); + mode_update(); + if((prev & F_ADF) && !(adcsr & F_ADF)) { + if(mode & HALTED) { + mode &= ~HALTED; + if(!(adcsr & F_ADST)) { + sampling(); + conversion_wait(false, false); + } else + done(); + } + } + + if(!(prev & F_ADST) && (adcsr & F_ADST)) + start_conversion(); +} + +WRITE8_MEMBER(h8_adc_device::adcr_w) +{ + logerror("%s: adcr_w %02x\n", tag(), data); + adcr = data; + mode_update(); +} + +WRITE_LINE_MEMBER(h8_adc_device::adtrg_w) +{ + if(state != adtrg) { + adtrg = state; + if(!adtrg && (trigger & T_EXT) && !(adcsr & F_ADST)) { + adcsr |= F_ADST; + start_conversion(); + } + } +} + +void h8_adc_device::set_suspend(bool suspend) +{ +} + +void h8_adc_device::device_start() +{ + io = &cpu->space(AS_IO); + intc = siblingdevice(intc_tag); + save_item(NAME(addr)); + save_item(NAME(buf)); + save_item(NAME(adcsr)); + save_item(NAME(adcr)); + save_item(NAME(trigger)); + save_item(NAME(start_mode)); + save_item(NAME(start_channel)); + save_item(NAME(end_channel)); + save_item(NAME(start_count)); + save_item(NAME(suspend_on_interrupt)); + save_item(NAME(analog_power_control)); + save_item(NAME(mode)); + save_item(NAME(channel)); + save_item(NAME(count)); + save_item(NAME(analog_powered)); + save_item(NAME(next_event)); + save_item(NAME(adtrg)); +} + +void h8_adc_device::device_reset() +{ + memset(addr, 0, sizeof(addr)); + memset(buf, 0, sizeof(buf)); + adcsr = adcr = 0; + trigger = T_SOFT; + start_mode = IDLE; + start_channel = end_channel = 0; + start_count = 1; + mode = IDLE; + channel = 0; + count = 0; + next_event = 0; + mode_update(); + analog_powered = !analog_power_control; + adtrg = true; +} + +void h8_adc_device::done() +{ + mode = IDLE; + adcsr &= ~F_ADST; + if(analog_power_control) + analog_powered = false; +} + +UINT64 h8_adc_device::internal_update(UINT64 current_time) +{ + if(next_event && next_event <= current_time) { + next_event = 0; + timeout(current_time); + } + return next_event; +} + +void h8_adc_device::conversion_wait(bool first, bool poweron, UINT64 current_time) +{ + if(current_time) + next_event = current_time + conversion_time(first, poweron); + else { + next_event = cpu->total_cycles() + conversion_time(first, poweron); + cpu->internal_update(); + } +} + +void h8_adc_device::buffer_value(int port, int buffer) +{ + buf[buffer] = io->read_word(2*(h8_device::ADC_0 + port)); + logerror("%s: adc buffer %d -> %d:%03x\n", tag(), port, buffer, buf[buffer]); +} + +void h8_adc_device::commit_value(int reg, int buffer) +{ + reg &= register_mask; + logerror("%s: adc commit %d -> %d:%03x\n", tag(), buffer, reg, buf[buffer]); + addr[reg] = buf[buffer]; +} + +void h8_adc_device::sampling() +{ + if(mode & COUNTED) + channel = get_channel_index(start_count - count); + if(mode & DUAL) { + buffer_value(channel, 0); + buffer_value(channel+1, 1); + } else + buffer_value(channel); +} + +void h8_adc_device::start_conversion() +{ + mode = start_mode; + channel = start_channel; + count = start_count; + sampling(); + conversion_wait(true, !analog_powered); + analog_powered = true; +} + +void h8_adc_device::timeout(UINT64 current_time) +{ + if(mode & BUFFER) { + do_buffering((mode & DUAL) && (channel & 1)); + if((mode & DUAL) && !(channel & 1)) { + channel++; + conversion_wait(false, false, current_time); + return; + } + } else { + if(mode & DUAL) { + if(channel & 1) + commit_value(channel, 1); + else { + commit_value(channel, 0); + channel++; + conversion_wait(false, false, current_time); + return; + } + } else + commit_value(channel); + } + + if(mode & ROTATE) { + if(channel != end_channel) { + channel++; + sampling(); + conversion_wait(false, false, current_time); + return; + } + channel = start_channel; + } + + if(mode & COUNTED) { + count--; + if(count) { + sampling(); + conversion_wait(false, false, current_time); + return; + } + } + + adcsr |= F_ADF; + if(adcsr & F_ADIE) + intc->internal_interrupt(intc_vector); + + if(mode & REPEAT) { + if(suspend_on_interrupt && (adcsr & F_ADIE)) { + mode |= HALTED; + return; + } + channel = start_channel; + count = start_count; + sampling(); + conversion_wait(false, false, current_time); + return; + } + + done(); +} + +void h8_adc_device::do_buffering(int buffer) +{ + throw emu_fatalerror("%s: Buffering requested but unimplemented for this device\n", tag()); +} + +int h8_adc_device::get_channel_index(int count) +{ + throw emu_fatalerror("%s: Indexing requested but unimplemented for this device\n", tag()); +} + + +h8_adc_3337_device::h8_adc_3337_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + h8_adc_device(mconfig, H8_ADC_3337, "H8 ADC 3337", tag, owner, clock, "h8_adc_3337", __FILE__) +{ + register_mask = 3; +} + +int h8_adc_3337_device::conversion_time(bool first, bool poweron) +{ + int tm; + if(first) + tm = adcsr & 0x08 ? 134 : 266; + else + tm = adcsr & 0x08 ? 128 : 256; + return tm; +} + +void h8_adc_3337_device::mode_update() +{ + trigger = adcr & 0x80 ? T_EXT : T_SOFT; + + if(adcsr & 0x10) { + start_mode = ACTIVE | ROTATE; + start_channel = adcsr & 4; + end_channel = adcsr & 7; + } else { + start_mode = ACTIVE; + start_channel = end_channel = adcsr & 7; + } +} + + +h8_adc_3006_device::h8_adc_3006_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + h8_adc_device(mconfig, H8_ADC_3006, "H8 ADC 3006", tag, owner, clock, "h8_adc_3006", __FILE__) +{ + register_mask = 3; +} + +int h8_adc_3006_device::conversion_time(bool first, bool poweron) +{ + int tm; + if(first) + tm = adcsr & 0x08 ? 70 : 134; + else + tm = adcsr & 0x08 ? 66 : 128; + return tm; +} + +void h8_adc_3006_device::mode_update() +{ + trigger = adcr & 0x80 ? T_EXT|T_TIMER : T_SOFT; + + if(adcsr & 0x10) { + start_mode = ACTIVE | ROTATE; + start_channel = adcsr & 4; + end_channel = adcsr & 7; + } else { + start_mode = ACTIVE; + start_channel = end_channel = adcsr & 7; + } +} + + +h8_adc_2245_device::h8_adc_2245_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + h8_adc_device(mconfig, H8_ADC_2245, "H8 ADC 2245", tag, owner, clock, "h8_adc_2245", __FILE__) +{ + register_mask = 3; +} + +int h8_adc_2245_device::conversion_time(bool first, bool poweron) +{ + int tm; + if(first) + tm = adcsr & 0x08 ? 134 : 266; + else + tm = adcsr & 0x08 ? 128 : 256; + return tm; +} + +void h8_adc_2245_device::mode_update() +{ + trigger = 1 << ((adcr >> 6) & 3); + + if(adcsr & 0x10) { + start_mode = ACTIVE | ROTATE; + start_channel = 0; + end_channel = adcsr & 3; + } else { + start_mode = ACTIVE; + start_channel = end_channel = adcsr & 3; + } +} + + +h8_adc_2320_device::h8_adc_2320_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + h8_adc_device(mconfig, H8_ADC_2320, "H8 ADC 2320", tag, owner, clock, "h8_adc_2320", __FILE__) +{ + register_mask = 3; +} + +int h8_adc_2320_device::conversion_time(bool first, bool poweron) +{ + int tm; + if(first) + if(adcr & 0x04) + tm = adcsr & 0x08 ? 134 : 266; + else + tm = adcsr & 0x08 ? 68 : 580; + else + if(adcr & 0x04) + tm = adcsr & 0x08 ? 128 : 256; + else + tm = adcsr & 0x08 ? 64 : 512; + return tm; +} + +void h8_adc_2320_device::mode_update() +{ + trigger = 1 << ((adcr >> 6) & 3); + + if(adcsr & 0x10) { + start_mode = ACTIVE | ROTATE; + start_channel = adcsr & 4; + end_channel = adcsr & 7; + } else { + start_mode = ACTIVE; + start_channel = end_channel = adcsr & 7; + } +} + + +h8_adc_2357_device::h8_adc_2357_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + h8_adc_device(mconfig, H8_ADC_2357, "H8 ADC 2357", tag, owner, clock, "h8_adc_2357", __FILE__) +{ + register_mask = 3; +} + +int h8_adc_2357_device::conversion_time(bool first, bool poweron) +{ + int tm; + if(first) + tm = adcsr & 0x08 ? 134 : 266; + else + tm = adcsr & 0x08 ? 128 : 256; + return tm; +} + +void h8_adc_2357_device::mode_update() +{ + trigger = 1 << ((adcr >> 6) & 3); + + if(adcsr & 0x10) { + start_mode = ACTIVE | ROTATE; + start_channel = adcsr & 4; + end_channel = adcsr & 7; + } else { + start_mode = ACTIVE; + start_channel = end_channel = adcsr & 7; + } +} + + +h8_adc_2655_device::h8_adc_2655_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + h8_adc_device(mconfig, H8_ADC_2655, "H8 ADC 2655", tag, owner, clock, "h8_adc_2655", __FILE__) +{ + suspend_on_interrupt = true; + register_mask = 7; +} + +int h8_adc_2655_device::conversion_time(bool first, bool poweron) +{ + int tm = adcsr & 0x10 ? 44 : 24; + if(first) + tm += adcsr & 0x10 ? 20 : 10; + if(poweron) + tm += 200; + return tm; +} + +void h8_adc_2655_device::mode_update() +{ + trigger = 1 << ((adcr >> 4) & 3); + analog_power_control = !(adcr & 0x40); + + mode = ACTIVE | (adcr & 0x08 ? REPEAT : 0); + + if(adcsr & 0x03) { + mode |= BUFFER; + + } + + if(adcsr & 0x08) { + mode |= ROTATE; + start_channel = 0; + if(adcr & 0x04) { + mode |= DUAL; + end_channel = (adcsr & 6)+1; + } else + end_channel = adcsr & 7; + } else + start_channel = end_channel = adcsr & 7; + +} + +void h8_adc_2655_device::do_buffering(int buffer) +{ + if((mode & COUNTED) && channel >= 2) { + commit_value(channel, buffer); + return; + } + switch(adcsr & 3) { + case 0: + commit_value(channel, buffer); + break; + case 1: + addr[1] = addr[0]; + commit_value(0, buffer); + break; + case 2: + addr[2+buffer] = addr[buffer]; + commit_value(buffer, buffer); + break; + case 3: + addr[3] = addr[2]; + addr[2] = addr[1]; + addr[1] = addr[0]; + commit_value(0, buffer); + break; + } +} + +int h8_adc_2655_device::get_channel_index(int count) +{ + abort(); +} diff --git a/src/devices/cpu/h8/h8_adc.h b/src/devices/cpu/h8/h8_adc.h new file mode 100644 index 00000000000..5a7a5f67cbb --- /dev/null +++ b/src/devices/cpu/h8/h8_adc.h @@ -0,0 +1,177 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +/*************************************************************************** + + h8_adc.h + + H8 Analog to Digital Converter subsystem + + +***************************************************************************/ + +#ifndef __H8_ADC_H__ +#define __H8_ADC_H__ + +#include "h8.h" +#include "h8_intc.h" + +#define MCFG_H8_ADC_GENERIC_ADD( _tag, _type, intc, vect ) \ + MCFG_DEVICE_ADD( _tag, _type, 0 ) \ + downcast(device)->set_info(intc, vect); + +#define MCFG_H8_ADC_3337_ADD( _tag, intc, vect ) \ + MCFG_H8_ADC_GENERIC_ADD( _tag, H8_ADC_3337, intc, vect ) + +#define MCFG_H8_ADC_3006_ADD( _tag, intc, vect ) \ + MCFG_H8_ADC_GENERIC_ADD( _tag, H8_ADC_3006, intc, vect ) + +#define MCFG_H8_ADC_2245_ADD( _tag, intc, vect ) \ + MCFG_H8_ADC_GENERIC_ADD( _tag, H8_ADC_2245, intc, vect ) + +#define MCFG_H8_ADC_2320_ADD( _tag, intc, vect ) \ + MCFG_H8_ADC_GENERIC_ADD( _tag, H8_ADC_2320, intc, vect ) + +#define MCFG_H8_ADC_2357_ADD( _tag, intc, vect ) \ + MCFG_H8_ADC_GENERIC_ADD( _tag, H8_ADC_2357, intc, vect ) + +#define MCFG_H8_ADC_2655_ADD( _tag, intc, vect ) \ + MCFG_H8_ADC_GENERIC_ADD( _tag, H8_ADC_2655, intc, vect ) + +class h8_adc_device : public device_t { +public: + h8_adc_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + void set_info(const char *intc_tag, int vect); + + DECLARE_READ8_MEMBER(addr8_r); + DECLARE_READ16_MEMBER(addr16_r); + DECLARE_READ8_MEMBER(adcsr_r); + DECLARE_READ8_MEMBER(adcr_r); + DECLARE_WRITE8_MEMBER(adcsr_w); + DECLARE_WRITE8_MEMBER(adcr_w); + DECLARE_WRITE_LINE_MEMBER(adtrg_w); + + void set_suspend(bool suspend); + UINT64 internal_update(UINT64 current_time); + +protected: + required_device cpu; + h8_intc_device *intc; + address_space *io; + const char *intc_tag; + int intc_vector; + + enum { + T_SOFT = 1<<0, + T_TPU = 1<<1, + T_TIMER = 1<<2, + T_EXT = 1<<3 + }; + + enum { + F_ADF = 0x80, + F_ADIE = 0x40, + F_ADST = 0x20 + }; + + enum { + IDLE = 0, + ACTIVE = 1, + HALTED = 2, + REPEAT = 4, + ROTATE = 8, + DUAL = 16, + BUFFER = 32, + COUNTED = 64 + }; + + UINT16 addr[8], buf[2]; + UINT8 adcsr, adcr; + int register_mask; + int trigger, start_mode, start_channel, end_channel, start_count; + bool suspend_on_interrupt, analog_power_control; + int mode, channel, count; + bool analog_powered, adtrg; + UINT64 next_event; + + virtual void device_start(); + virtual void device_reset(); + + void sampling(); + void start_conversion(); + void conversion_wait(bool first, bool poweron, UINT64 current_time = 0); + void buffer_value(int port, int buffer = 0); + void commit_value(int reg, int buffer = 0); + void timeout(UINT64 current_time); + void done(); + + virtual int conversion_time(bool first, bool poweron) = 0; + virtual void mode_update() = 0; + virtual void do_buffering(int buffer); + virtual int get_channel_index(int count); +}; + +class h8_adc_3337_device : public h8_adc_device { +public: + h8_adc_3337_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual int conversion_time(bool first, bool poweron); + virtual void mode_update(); +}; + +class h8_adc_3006_device : public h8_adc_device { +public: + h8_adc_3006_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual int conversion_time(bool first, bool poweron); + virtual void mode_update(); +}; + +class h8_adc_2245_device : public h8_adc_device { +public: + h8_adc_2245_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual int conversion_time(bool first, bool poweron); + virtual void mode_update(); +}; + +class h8_adc_2320_device : public h8_adc_device { +public: + h8_adc_2320_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual int conversion_time(bool first, bool poweron); + virtual void mode_update(); +}; + +class h8_adc_2357_device : public h8_adc_device { +public: + h8_adc_2357_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual int conversion_time(bool first, bool poweron); + virtual void mode_update(); +}; + +class h8_adc_2655_device : public h8_adc_device { +public: + h8_adc_2655_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual int conversion_time(bool first, bool poweron); + virtual void mode_update(); + virtual void do_buffering(int buffer); + virtual int get_channel_index(int count); +}; + +extern const device_type H8_ADC_3337; +extern const device_type H8_ADC_3006; +extern const device_type H8_ADC_2245; +extern const device_type H8_ADC_2320; +extern const device_type H8_ADC_2357; +extern const device_type H8_ADC_2655; + +#endif diff --git a/src/devices/cpu/h8/h8_intc.c b/src/devices/cpu/h8/h8_intc.c new file mode 100644 index 00000000000..e88476fc05c --- /dev/null +++ b/src/devices/cpu/h8/h8_intc.c @@ -0,0 +1,385 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +#include "emu.h" +#include "h8_intc.h" + +const device_type H8_INTC = &device_creator; +const device_type H8H_INTC = &device_creator; +const device_type H8S_INTC = &device_creator; + +h8_intc_device::h8_intc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, H8_INTC, "H8 INTC", tag, owner, clock, "h8_intc", __FILE__), + cpu(*this, DEVICE_SELF_OWNER) +{ + irq_vector_base = 4; + irq_vector_nmi = 3; +} + +h8_intc_device::h8_intc_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + cpu(*this, DEVICE_SELF_OWNER) +{ +} + +void h8_intc_device::device_start() +{ + memset(pending_irqs, 0, sizeof(pending_irqs)); + save_item(NAME(pending_irqs)); + save_item(NAME(irq_type)); + save_item(NAME(nmi_input)); + save_item(NAME(irq_input)); + save_item(NAME(ier)); + save_item(NAME(isr)); + save_item(NAME(iscr)); + save_item(NAME(icr_filter)); + save_item(NAME(ipr_filter)); +} + +void h8_intc_device::device_reset() +{ + memset(irq_type, 0, sizeof(irq_type)); + memset(pending_irqs, 0, sizeof(pending_irqs)); + ier = isr = irq_input = 0x00; + iscr = 0x0000; +} + +int h8_intc_device::interrupt_taken(int vector) +{ + if(0) + logerror("%s: taking internal interrupt %d\n", tag(), vector); + pending_irqs[vector >> 5] &= ~(1 << (vector & 31)); + if(vector >= irq_vector_base && vector < irq_vector_base + 8) { + int irq = vector - irq_vector_base; + if(irq_type[irq] != IRQ_LEVEL || !(irq_input & (1 << irq))) + isr &= ~(1 << irq); + update_irq_state(); + return irq; + } + update_irq_state(); + if(vector == irq_vector_nmi) + return INPUT_LINE_NMI; + return 8; +} + +void h8_intc_device::internal_interrupt(int vector) +{ + if(0) + logerror("%s: internal interrupt %d\n", tag(), vector); + pending_irqs[vector >> 5] |= 1 << (vector & 31); + update_irq_state(); +} + +void h8_intc_device::set_input(int inputnum, int state) +{ + if(inputnum == INPUT_LINE_NMI) { + if(state == ASSERT_LINE && !nmi_input) + pending_irqs[0] |= 1 << irq_vector_nmi; + nmi_input = state == ASSERT_LINE; + update_irq_state(); + } else { + bool set = false; + bool cur = irq_input & (1 << inputnum); + switch(irq_type[inputnum]) { + case IRQ_LEVEL: set = state == ASSERT_LINE; break; + case IRQ_EDGE: set = state == ASSERT_LINE && !cur; break; + case IRQ_DUAL_EDGE: set = (state == ASSERT_LINE && !cur) || (state == CLEAR_LINE && cur); break; + } + if(state == ASSERT_LINE) + irq_input |= 1 << inputnum; + else + irq_input &= ~(1 << inputnum); + if(set) { + isr |= 1 << inputnum; + update_irq_state(); + } + } +} + +void h8_intc_device::set_filter(int _icr_filter, int _ipr_filter) +{ + icr_filter = _icr_filter; + ipr_filter = _ipr_filter; + update_irq_state(); +} + +READ8_MEMBER(h8_intc_device::ier_r) +{ + return ier; +} + +WRITE8_MEMBER(h8_intc_device::ier_w) +{ + ier = data; + logerror("%s: ier = %02x\n", tag(), data); + update_irq_state(); +} + +void h8_intc_device::check_level_irqs(bool force_update) +{ + logerror("%s: irq_input=%02x\n", tag(), irq_input); + bool update = force_update; + for(int i=0; i<8; i++) { + unsigned char mask = 1 << i; + if(irq_type[i] == IRQ_LEVEL && (irq_input & mask) && !(isr & mask)) { + isr |= mask; + update = true; + } + } + if(update) + update_irq_state(); +} + + +READ8_MEMBER(h8_intc_device::iscr_r) +{ + return iscr; +} + +WRITE8_MEMBER(h8_intc_device::iscr_w) +{ + iscr = data; + logerror("%s: iscr = %02x\n", tag(), iscr); + update_irq_types(); +} + +void h8_intc_device::update_irq_types() +{ + for(int i=0; i<8; i++) + switch((iscr >> (i)) & 1) { + case 0: + irq_type[i] = IRQ_LEVEL; + break; + case 1: + irq_type[i] = IRQ_EDGE; + break; + } + check_level_irqs(); +} + +void h8_intc_device::update_irq_state() +{ + pending_irqs[0] &= ~(255 << irq_vector_base); + pending_irqs[0] |= (isr & ier) << irq_vector_base; + + int cur_vector = 0; + int cur_level = -1; + + for(int i=0; i= icr_filter && ipr_pri > ipr_filter) { + int level = ipr_filter == -1 ? icr_pri : ipr_pri; + if(level > cur_level) { + cur_vector = vect; + cur_level = level; + } + } + } + } + cpu->set_irq(cur_vector, cur_level, cur_vector == irq_vector_nmi); +} + +void h8_intc_device::get_priority(int vect, int &icr_pri, int &ipr_pri) const +{ + icr_pri = 0; + ipr_pri = 0; +} + + +h8h_intc_device::h8h_intc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + h8_intc_device(mconfig, H8H_INTC, "H8H INTC", tag, owner, clock, "h8h_intc", __FILE__) +{ + irq_vector_base = 12; + irq_vector_nmi = 7; +} + +h8h_intc_device::h8h_intc_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + h8_intc_device(mconfig, type, name, tag, owner, clock, shortname, source) +{ +} + +void h8h_intc_device::device_start() +{ + h8_intc_device::device_start(); + save_item(NAME(icr)); +} + +void h8h_intc_device::device_reset() +{ + h8_intc_device::device_reset(); + icr = 0x000000; +} + +READ8_MEMBER(h8h_intc_device::isr_r) +{ + return isr; +} + +WRITE8_MEMBER(h8h_intc_device::isr_w) +{ + isr &= data; // edge/level + logerror("%s: isr = %02x / %02x\n", tag(), data, isr); + check_level_irqs(true); +} + +READ8_MEMBER(h8h_intc_device::icr_r) +{ + return icr >> (8*offset); +} + +WRITE8_MEMBER(h8h_intc_device::icr_w) +{ + icr = (icr & (0xff << (8*offset))) | (data << (8*offset)); + logerror("%s: icr %d = %02x\n", tag(), offset, data); +} + +READ8_MEMBER(h8h_intc_device::icrc_r) +{ + return icr_r(space, 2, mem_mask); +} + +WRITE8_MEMBER(h8h_intc_device::icrc_w) +{ + icr_w(space, 2, data, mem_mask); +} + +READ8_MEMBER(h8h_intc_device::iscrh_r) +{ + return iscr >> 8; +} + +WRITE8_MEMBER(h8h_intc_device::iscrh_w) +{ + iscr = (iscr & 0x00ff) | (data << 8); + logerror("%s: iscr = %04x\n", tag(), iscr); + update_irq_types(); +} + +READ8_MEMBER(h8h_intc_device::iscrl_r) +{ + return iscr; +} + +WRITE8_MEMBER(h8h_intc_device::iscrl_w) +{ + iscr = (iscr & 0xff00) | data; + logerror("%s: iscr = %04x\n", tag(), iscr); + update_irq_types(); +} + +void h8h_intc_device::update_irq_types() +{ + for(int i=0; i<8; i++) + switch((iscr >> (2*i)) & 3) { + case 0: + irq_type[i] = IRQ_LEVEL; + break; + case 1: case 2: + irq_type[i] = IRQ_EDGE; + break; + case 3: + irq_type[i] = IRQ_DUAL_EDGE; + break; + } + check_level_irqs(); +} + +const int h8h_intc_device::vector_to_slot[64] = { + -1, -1, -1, -1, -1, -1, -1, -1, // NMI at 7 + -1, -1, -1, -1, 0, 1, 2, 2, // IRQ 0-3 + 3, 3, 3, 3, 4, 4, 4, 4, // IRQ 4-5, (reservedx2), WOVI, CMI, (reserved), ADI + 5, 5, 5, 5, 6, 6, 6, 6, // IMIA0, IMIB0, OVI0, (reserved), IMIA1, IMIB1, OVI1, (reserved) + 7, 7, 7, 7, 8, 8, 8, 8, // IMIA2, IMIB2, OVI2, (reserved), CMIA0, CMIB0, CMIx1, TOVI0/1 + 9, 9, 9, 9, 10, 10, 10, 10, // CMIA2, CMIB2, CMIx3, TOVI2/3, DEND0A, DEND0B, DEND1A, DEND1B + 11, 11, 11, 11, 12, 12, 12, 12, // (reservedx4), ERI0, RXI0, TXI0, TEI0 + 13, 13, 13, 13, 14, 14, 14, 14 // ERI1, RXI1, TXI1, TEI1, ERI2, RXI2, TXI2, TEI2 +}; + +void h8h_intc_device::get_priority(int vect, int &icr_pri, int &ipr_pri) const +{ + ipr_pri = 0; + + if(vect == 7) { + icr_pri = 2; + return; + } + int slot = vector_to_slot[vect]; + if(slot == -1) { + icr_pri = 0; + return; + } + + icr_pri = (icr >> (slot ^ 7)) & 1; +} + +h8s_intc_device::h8s_intc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + h8h_intc_device(mconfig, H8S_INTC, "H8S INTC", tag, owner, clock, "h8s_intc", __FILE__) +{ + irq_vector_base = 16; + irq_vector_nmi = 7; +} + +void h8s_intc_device::device_reset() +{ + h8h_intc_device::device_reset(); + memset(ipr, 0x77, sizeof(ipr)); +} + +READ8_MEMBER(h8s_intc_device::ipr_r) +{ + return ipr[offset]; +} + +WRITE8_MEMBER(h8s_intc_device::ipr_w) +{ + ipr[offset] = data; + logerror("%s: ipr %d = %02x\n", tag(), offset, data); +} + +READ8_MEMBER(h8s_intc_device::iprk_r) +{ + return ipr_r(space, 10, mem_mask); +} + +WRITE8_MEMBER(h8s_intc_device::iprk_w) +{ + ipr_w(space, 10, data, mem_mask); +} + +const int h8s_intc_device::vector_to_slot[92] = { + -1, -1, -1, -1, -1, -1, -1, -1, // NMI at 7 + -1, -1, -1, -1, -1, -1, -1, -1, + 0, 1, 2, 2, 3, 3, 4, 4, // IRQ 0-7 + 5, 6, 7, 8, 9, 9, 9, 9, // SWDTEND, WOVI, CMI, (reserved), ADI + 10, 10, 10, 10, 10, 10, 10, 10, // TGI0A, TGI0B, TGI0C, TGI0D, TGI0V + 11, 11, 11, 11, 12, 12, 12, 12, // TGI1A, TGI1B, TGI1V, TGI1U, TGI2A, TGI2B, TGI2V, TGI2U + 13, 13, 13, 13, 13, 13, 13, 13, // TGI3A, TGI3B, TGI3C, TGI3D, TGI3V + 14, 14, 14, 14, 15, 15, 15, 15, // TGI4A, TGI4B, TGI4V, TGI4U, TGI5A, TGI5B, TGI5V, TGI5U + 16, 16, 16, 16, 17, 17, 17, 17, // CMIA0, CMIB0, OVI0, CMIA1, CMIB1, OVI1 + 18, 18, 18, 18, 18, 18, 18, 18, // DEND0A, DEND0B, DEND1B, DEND1B + 19, 19, 19, 19, 20, 20, 20, 20, // ERI0, RXI0, TXI0, TEI0, ERI1, RXI1, TXI1, TEI1 + 21, 21, 21, 21 // ERI2, RXI2, TXI2, TEI2 +}; + +void h8s_intc_device::get_priority(int vect, int &icr_pri, int &ipr_pri) const +{ + if(vect == 7) { + icr_pri = 2; + ipr_pri = 8; + return; + } + int slot = vector_to_slot[vect]; + if(slot == -1) { + icr_pri = 0; + ipr_pri = 0; + return; + } + + icr_pri = (icr >> (slot ^ 7)) & 1; + ipr_pri = (ipr[slot >> 1] >> (slot & 1 ? 4 : 0)) & 7; +} diff --git a/src/devices/cpu/h8/h8_intc.h b/src/devices/cpu/h8/h8_intc.h new file mode 100644 index 00000000000..b255f80684f --- /dev/null +++ b/src/devices/cpu/h8/h8_intc.h @@ -0,0 +1,120 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +/*************************************************************************** + + h8_intc.h + + H8 interrupt controllers family + + +***************************************************************************/ + +#ifndef __H8_INTC_H__ +#define __H8_INTC_H__ + +#include "h8.h" + +#define MCFG_H8_INTC_ADD( _tag ) \ + MCFG_DEVICE_ADD( _tag, H8_INTC, 0 ) + +#define MCFG_H8H_INTC_ADD( _tag ) \ + MCFG_DEVICE_ADD( _tag, H8H_INTC, 0 ) + +#define MCFG_H8S_INTC_ADD( _tag ) \ + MCFG_DEVICE_ADD( _tag, H8S_INTC, 0 ) + + +class h8_intc_device : public device_t { +public: + h8_intc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + h8_intc_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + int interrupt_taken(int vector); + void internal_interrupt(int vector); + void set_input(int inputnum, int state); + void set_filter(int icr_filter, int ipr_filter); + + DECLARE_READ8_MEMBER(ier_r); + DECLARE_WRITE8_MEMBER(ier_w); + DECLARE_READ8_MEMBER(iscr_r); + DECLARE_WRITE8_MEMBER(iscr_w); + +protected: + enum { IRQ_LEVEL, IRQ_EDGE, IRQ_DUAL_EDGE }; + enum { MAX_VECTORS = 256 }; + + int irq_vector_base; + int irq_vector_nmi; + + required_device cpu; + + UINT32 pending_irqs[MAX_VECTORS/32]; + int irq_type[8]; + bool nmi_input; + UINT8 irq_input; + UINT8 ier; + UINT8 isr; + UINT16 iscr; + int icr_filter, ipr_filter; + + virtual void device_start(); + virtual void device_reset(); + + virtual void get_priority(int vect, int &icr_pri, int &ipr_pri) const; + void update_irq_state(); + void update_irq_types(); + void check_level_irqs(bool force_update = false); +}; + +class h8h_intc_device : public h8_intc_device { +public: + h8h_intc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + h8h_intc_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + DECLARE_READ8_MEMBER(isr_r); + DECLARE_WRITE8_MEMBER(isr_w); + DECLARE_READ8_MEMBER(icr_r); + DECLARE_WRITE8_MEMBER(icr_w); + DECLARE_READ8_MEMBER(icrc_r); + DECLARE_WRITE8_MEMBER(icrc_w); + DECLARE_READ8_MEMBER(iscrh_r); + DECLARE_WRITE8_MEMBER(iscrh_w); + DECLARE_READ8_MEMBER(iscrl_r); + DECLARE_WRITE8_MEMBER(iscrl_w); + +protected: + static const int vector_to_slot[]; + + UINT32 icr; + + virtual void device_start(); + virtual void device_reset(); + + virtual void get_priority(int vect, int &icr_pri, int &ipr_pri) const; + void update_irq_types(); +}; + +class h8s_intc_device : public h8h_intc_device { +public: + h8s_intc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + DECLARE_READ8_MEMBER(ipr_r); + DECLARE_WRITE8_MEMBER(ipr_w); + DECLARE_READ8_MEMBER(iprk_r); + DECLARE_WRITE8_MEMBER(iprk_w); + + void set_mode_8(bool mode_8); + +private: + static const int vector_to_slot[]; + UINT8 ipr[11]; + + virtual void get_priority(int vect, int &icr_pri, int &ipr_pri) const; + virtual void device_reset(); +}; + +extern const device_type H8_INTC; +extern const device_type H8H_INTC; +extern const device_type H8S_INTC; + +#endif diff --git a/src/devices/cpu/h8/h8_port.c b/src/devices/cpu/h8/h8_port.c new file mode 100644 index 00000000000..0f289edc7a3 --- /dev/null +++ b/src/devices/cpu/h8/h8_port.c @@ -0,0 +1,102 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +#include "emu.h" +#include "h8_port.h" + +const device_type H8_PORT = &device_creator; + +h8_port_device::h8_port_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, H8_PORT, "H8 digital port", tag, owner, clock, "h8_digital_port", __FILE__), + cpu(*this, DEVICE_SELF_OWNER) +{ +} + +void h8_port_device::set_info(int _address, UINT8 _default_ddr, UINT8 _mask) +{ + address = 2*_address; + default_ddr = _default_ddr; + mask = _mask; +} + +WRITE8_MEMBER(h8_port_device::ddr_w) +{ + // logerror("%s: ddr_w %02x\n", tag(), data); + ddr = data; + update_output(); +} + +WRITE8_MEMBER(h8_port_device::dr_w) +{ + // logerror("%s: dr_w %02x\n", tag(), data); + dr = data; + update_output(); +} + +READ8_MEMBER(h8_port_device::dr_r) +{ + // logerror("%s: dr_r %02x\n", tag(), (dr | mask) & 0xff); + return dr | mask; +} + +READ8_MEMBER(h8_port_device::port_r) +{ + UINT8 res = mask | (dr & ddr); + if((ddr & ~mask) != UINT8(~mask)) + res |= io->read_word(address) & ~ddr; + + // logerror("%s: port_r %02x (%02x %02x)\n", tag(), res, ddr & ~mask, UINT8(~mask)); + return res; +} + +WRITE8_MEMBER(h8_port_device::pcr_w) +{ + logerror("%s: pcr_w %02x\n", tag(), data); + pcr = data; +} + +READ8_MEMBER(h8_port_device::pcr_r) +{ + logerror("%s: dr_r %02x\n", tag(), (pcr | mask) & 0xff); + return pcr | mask; +} + +WRITE8_MEMBER(h8_port_device::odr_w) +{ + logerror("%s: odr_w %02x\n", tag(), data); + odr = data; +} + +READ8_MEMBER(h8_port_device::odr_r) +{ + logerror("%s: odr_r %02x\n", tag(), (odr | mask) & 0xff); + return odr | ~mask; +} + +void h8_port_device::update_output() +{ + UINT8 res = dr & ddr & ~mask; + if(res != last_output) { + last_output = res; + io->write_word(address, res); + } +} + +void h8_port_device::device_start() +{ + io = &cpu->space(AS_IO); + save_item(NAME(ddr)); + save_item(NAME(dr)); + save_item(NAME(pcr)); + save_item(NAME(odr)); + save_item(NAME(last_output)); + last_output = 0; +} + +void h8_port_device::device_reset() +{ + dr = 0; + ddr = default_ddr; + pcr = 0; + odr = 0; + update_output(); +} diff --git a/src/devices/cpu/h8/h8_port.h b/src/devices/cpu/h8/h8_port.h new file mode 100644 index 00000000000..2ac35b5b48a --- /dev/null +++ b/src/devices/cpu/h8/h8_port.h @@ -0,0 +1,53 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +/*************************************************************************** + + h8_port.h + + H8 8 bits digital port + + +***************************************************************************/ + +#ifndef __H8_PORT_H__ +#define __H8_PORT_H__ + +#include "h8.h" + +#define MCFG_H8_PORT_ADD( _tag, address, ddr, mask ) \ + MCFG_DEVICE_ADD( _tag, H8_PORT, 0 ) \ + downcast(device)->set_info(address, ddr, mask); + +class h8_port_device : public device_t { +public: + h8_port_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + void set_info(int address, UINT8 default_ddr, UINT8 mask); + + DECLARE_WRITE8_MEMBER(ddr_w); + DECLARE_WRITE8_MEMBER(dr_w); + DECLARE_READ8_MEMBER(dr_r); + DECLARE_READ8_MEMBER(port_r); + DECLARE_WRITE8_MEMBER(pcr_w); + DECLARE_READ8_MEMBER(pcr_r); + DECLARE_WRITE8_MEMBER(odr_w); + DECLARE_READ8_MEMBER(odr_r); + +protected: + required_device cpu; + address_space *io; + + int address; + UINT8 default_ddr, ddr, pcr, odr; + UINT8 mask; + UINT8 dr; + UINT8 last_output; + + virtual void device_start(); + virtual void device_reset(); + void update_output(); +}; + +extern const device_type H8_PORT; + +#endif diff --git a/src/devices/cpu/h8/h8_sci.c b/src/devices/cpu/h8/h8_sci.c new file mode 100644 index 00000000000..758e09141f2 --- /dev/null +++ b/src/devices/cpu/h8/h8_sci.c @@ -0,0 +1,692 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +#include "emu.h" +#include "h8_sci.h" + +const device_type H8_SCI = &device_creator; + +const char *const h8_sci_device::state_names[] = { "idle", "start", "bit", "parity", "stop", "last-tick" }; + +h8_sci_device::h8_sci_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, H8_SCI, "H8 Serial Communications Interface", tag, owner, clock, "h8_sci", __FILE__), + cpu(*this, DEVICE_SELF_OWNER), + tx_cb(*this), + clk_cb(*this) +{ + external_clock_period = attotime::never; +} + +void h8_sci_device::set_info(const char *_intc_tag,int eri, int rxi, int txi, int tei) +{ + intc_tag = _intc_tag; + eri_int = eri; + rxi_int = rxi; + txi_int = txi; + tei_int = tei; +} + +void h8_sci_device::set_external_clock_period(const attotime &period) +{ + external_clock_period = period; +} + +WRITE8_MEMBER(h8_sci_device::smr_w) +{ + smr = data; + logerror("%s: smr_w %02x %s %c%c%c%s /%d (%06x)\n", tag(), data, + data & SMR_CA ? "sync" : "async", + data & SMR_CHR ? '7' : '8', + data & SMR_PE ? data & SMR_OE ? 'o' : 'e' : 'n', + data & SMR_STOP ? '2' : '1', + data & SMR_MP ? " mp" : "", + 1 << 2*(data & SMR_CKS), + cpu->pc()); + clock_update(); +} + +READ8_MEMBER(h8_sci_device::smr_r) +{ + logerror("%s: smr_r %02x (%06x)\n", tag(), smr, cpu->pc()); + return smr; +} + +WRITE8_MEMBER(h8_sci_device::brr_w) +{ + brr = data; + logerror("%s: brr_w %02x (%06x)\n", tag(), data, cpu->pc()); + clock_update(); +} + +READ8_MEMBER(h8_sci_device::brr_r) +{ + logerror("%s: brr_r %02x (%06x)\n", tag(), brr, cpu->pc()); + return brr; +} + +bool h8_sci_device::is_sync_start() const +{ + return (smr & SMR_CA) && ((scr & (SCR_TE|SCR_RE)) == (SCR_TE|SCR_RE)); +} + +bool h8_sci_device::has_recv_error() const +{ + return ssr & (SSR_ORER|SSR_PER|SSR_FER); +} + +WRITE8_MEMBER(h8_sci_device::scr_w) +{ + logerror("%s: scr_w %02x%s%s%s%s%s%s clk=%d (%06x)\n", tag(), data, + data & SCR_TIE ? " txi" : "", + data & SCR_RIE ? " rxi" : "", + data & SCR_TE ? " tx" : "", + data & SCR_RE ? " rx" : "", + data & SCR_MPIE ? " mpi" : "", + data & SCR_TEIE ? " tei" : "", + data & SCR_CKE, + cpu->pc()); + + UINT8 delta = scr ^ data; + scr = data; + clock_update(); + + if((delta & SCR_RE) && !(scr & SCR_RE)) { + rx_state = ST_IDLE; + clock_stop(CLK_RX); + } + + if((delta & SCR_RE) && (scr & SCR_RE) && rx_state == ST_IDLE && !has_recv_error() && !is_sync_start()) + rx_start(); + if((delta & SCR_TIE) && (scr & SCR_TIE) && (ssr & SSR_TDRE)) + intc->internal_interrupt(txi_int); + if((delta & SCR_TEIE) && (scr & SCR_TEIE) && (ssr & SSR_TEND)) + intc->internal_interrupt(tei_int); + if((delta & SCR_RIE) && (scr & SCR_RIE) && (ssr & SSR_RDRF)) + intc->internal_interrupt(rxi_int); + if((delta & SCR_RIE) && (scr & SCR_RIE) && has_recv_error()) + intc->internal_interrupt(eri_int); +} + +READ8_MEMBER(h8_sci_device::scr_r) +{ + logerror("%s: scr_r %02x (%06x)\n", tag(), scr, cpu->pc()); + return scr; +} + +WRITE8_MEMBER(h8_sci_device::tdr_w) +{ + logerror("%s: tdr_w %02x (%06x)\n", tag(), data, cpu->pc()); + tdr = data; +} + +READ8_MEMBER(h8_sci_device::tdr_r) +{ + logerror("%s: tdr_r %02x (%06x)\n", tag(), tdr, cpu->pc()); + return tdr; +} + +WRITE8_MEMBER(h8_sci_device::ssr_w) +{ + if(!(scr & SCR_TE)) { + data |= SSR_TDRE; + ssr |= SSR_TDRE; + } + if((ssr & SSR_TDRE) && !(data & SSR_TDRE)) + ssr &= ~SSR_TEND; + ssr = ((ssr & ~SSR_MPBT) | (data & SSR_MPBT)) & (data | (SSR_TEND|SSR_MPB|SSR_MPBT)); + logerror("%s: ssr_w %02x -> %02x (%06x)\n", tag(), data, ssr, cpu->pc()); + + if(tx_state == ST_IDLE && !(ssr & SSR_TDRE)) + tx_start(); + + if((scr & SCR_RE) && rx_state == ST_IDLE && !has_recv_error() && !is_sync_start()) + rx_start(); +} + +READ8_MEMBER(h8_sci_device::ssr_r) +{ + logerror("%s: ssr_r %02x (%06x)\n", tag(), ssr, cpu->pc()); + return ssr; +} + +READ8_MEMBER(h8_sci_device::rdr_r) +{ + logerror("%s: rdr_r %02x (%06x)\n", tag(), rdr, cpu->pc()); + return rdr; +} + +WRITE8_MEMBER(h8_sci_device::scmr_w) +{ + logerror("%s: scmr_w %02x (%06x)\n", tag(), data, cpu->pc()); +} + +READ8_MEMBER(h8_sci_device::scmr_r) +{ + logerror("%s: scmr_r (%06x)\n", tag(), cpu->pc()); + return 0x00; +} + +void h8_sci_device::clock_update() +{ + // Sync: Divider must be the time of a half-period (both edges are used, datarate*2) + // Async: Divider must be the time of one period (only raising edge used, datarate*16) + + divider = 2 << (2*(smr & SMR_CKS)); + divider *= brr+1; + + if(smr & SMR_CA) { + if(scr & SCR_CKE1) + clock_mode = CLKM_EXTERNAL_SYNC; + else + clock_mode = CLKM_INTERNAL_SYNC_OUT; + } else { + if(scr & SCR_CKE1) + clock_mode = CLKM_EXTERNAL_ASYNC; + else if(scr & SCR_CKE0) + clock_mode = CLKM_INTERNAL_ASYNC_OUT; + else + clock_mode = CLKM_INTERNAL_ASYNC; + } + + switch(clock_mode) { + case CLKM_INTERNAL_ASYNC: + logerror("%s: clock internal at %d Hz, async, bitrate %d bps\n", tag(), int(cpu->clock() / divider), int(cpu->clock() / (divider*16))); + break; + case CLKM_INTERNAL_ASYNC_OUT: + logerror("%s: clock internal at %d Hz, async, bitrate %d bps, output\n", tag(), int(cpu->clock() / divider), int(cpu->clock() / (divider*16))); + break; + case CLKM_EXTERNAL_ASYNC: + if(!external_clock_period.is_never()) { + clock_mode = CLKM_EXTERNAL_RATE_ASYNC; + logerror("%s: clock external at %d Hz, async, bitrate %d bps\n", tag(), int(cpu->clock()*internal_to_external_ratio), int(cpu->clock()*internal_to_external_ratio/16)); + } else + logerror("%s: clock external, async\n", tag()); + break; + case CLKM_INTERNAL_SYNC_OUT: + logerror("%s: clock internal at %d Hz, sync, output\n", tag(), int(cpu->clock() / (divider*2))); + break; + + case CLKM_EXTERNAL_SYNC: + if(!external_clock_period.is_never()) { + clock_mode = CLKM_EXTERNAL_RATE_ASYNC; + logerror("%s: clock external at %d Hz, sync\n", tag(), int(cpu->clock()*internal_to_external_ratio)); + } else + logerror("%s: clock external, sync\n", tag()); + break; + } +} + +void h8_sci_device::device_start() +{ + tx_cb.resolve_safe(); + clk_cb.resolve_safe(); + + sync_timer = timer_alloc(0); + + if(external_clock_period.is_never()) { + internal_to_external_ratio = 0; + external_to_internal_ratio = 0; + } else { + external_to_internal_ratio = (external_clock_period*cpu->clock()).as_double(); + internal_to_external_ratio = 1/external_to_internal_ratio; + } + + intc = siblingdevice(intc_tag); + save_item(NAME(rdr)); + save_item(NAME(tdr)); + save_item(NAME(smr)); + save_item(NAME(scr)); + save_item(NAME(ssr)); + save_item(NAME(brr)); + save_item(NAME(rsr)); + save_item(NAME(tsr)); + save_item(NAME(rx_bit)); + save_item(NAME(tx_bit)); + save_item(NAME(rx_state)); + save_item(NAME(tx_state)); + save_item(NAME(tx_parity)); + save_item(NAME(clock_state)); + save_item(NAME(clock_value)); + save_item(NAME(clock_base)); + save_item(NAME(divider)); + save_item(NAME(ext_clock_value)); + save_item(NAME(ext_clock_counter)); + save_item(NAME(cur_sync_time)); +} + +void h8_sci_device::device_reset() +{ + rdr = 0x00; + tdr = 0xff; + smr = 0x00; + scr = 0x00; + ssr = 0x84; + brr = 0xff; + rsr = 0x00; + tsr = 0xff; + rx_bit = 0; + tx_bit = 0; + tx_state = ST_IDLE; + rx_state = ST_IDLE; + clock_state = 0; + clock_mode = CLKM_INTERNAL_ASYNC; + clock_base = 0; + clock_update(); + clock_value = true; + ext_clock_value = true; + ext_clock_counter = 0; + rx_value = true; + clk_cb(clock_value); + tx_cb(1); + cur_sync_time = attotime::never; +} + +void h8_sci_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + // Used only to force system-wide syncs +} + +WRITE_LINE_MEMBER(h8_sci_device::rx_w) +{ + rx_value = state; + logerror("%s: rx=%d\n", tag(), state); + if(!rx_value && !(clock_state & CLK_RX) && rx_state != ST_IDLE) + clock_start(CLK_RX); +} + +WRITE_LINE_MEMBER(h8_sci_device::clk_w) +{ + if(ext_clock_value != state) { + ext_clock_value = state; + if(clock_state) { + switch(clock_mode) { + case CLKM_EXTERNAL_ASYNC: + if(ext_clock_value) { + ext_clock_counter = (ext_clock_counter+1) & 15; + + if((clock_state & CLK_TX) && ext_clock_counter == 0) + tx_dropped_edge(); + if((clock_state & CLK_RX) && ext_clock_counter == 8) + rx_raised_edge(); + } + break; + + case CLKM_EXTERNAL_SYNC: + if((!ext_clock_value) && (clock_state & CLK_TX)) + tx_dropped_edge(); + + else if(ext_clock_value && (clock_state & CLK_RX)) + rx_raised_edge(); + break; + } + } + } +} + +UINT64 h8_sci_device::internal_update(UINT64 current_time) +{ + UINT64 event = 0; + switch(clock_mode) { + case CLKM_INTERNAL_SYNC_OUT: + if(clock_state || !clock_value) { + UINT64 fp = divider*2; + if(current_time >= clock_base) { + UINT64 delta = current_time - clock_base; + if(delta >= fp) { + delta -= fp; + clock_base += fp; + } + assert(delta < fp); + + bool new_clock = delta >= divider; + if(new_clock != clock_value) { + cpu->synchronize(); + if((!new_clock) && (clock_state & CLK_TX)) + tx_dropped_edge(); + + else if(new_clock && (clock_state & CLK_RX)) + rx_raised_edge(); + + clock_value = new_clock; + if(clock_state || clock_value) + clk_cb(clock_value); + } + } + event = clock_base + (clock_value ? fp : divider); + } + break; + + case CLKM_INTERNAL_ASYNC: + case CLKM_INTERNAL_ASYNC_OUT: + if(clock_state || !clock_value) { + UINT64 fp = divider*16; + if(current_time >= clock_base) { + UINT64 delta = current_time - clock_base; + if(delta >= fp) { + delta -= fp; + clock_base += fp; + } + assert(delta < fp); + bool new_clock = delta >= divider*8; + if(new_clock != clock_value) { + cpu->synchronize(); + if((!new_clock) && (clock_state & CLK_TX)) + tx_dropped_edge(); + + else if(new_clock && (clock_state & CLK_RX)) + rx_raised_edge(); + + clock_value = new_clock; + if(clock_mode == CLKM_INTERNAL_ASYNC_OUT && (clock_state || !clock_value)) + clk_cb(clock_value); + } + } + + event = clock_base + (clock_value ? fp : divider*8); + } + break; + + case CLKM_EXTERNAL_RATE_SYNC: + if(clock_state || !clock_value) { + UINT64 ctime = UINT64(current_time*internal_to_external_ratio*2); + if(ctime >= clock_base) { + UINT64 delta = ctime - clock_base; + clock_base += delta & ~1; + delta &= 1; + bool new_clock = delta >= 1; + if(new_clock != clock_value) { + cpu->synchronize(); + if((!new_clock) && (clock_state & CLK_TX)) + tx_dropped_edge(); + + else if(new_clock && (clock_state & CLK_RX)) + rx_raised_edge(); + + clock_value = new_clock; + } + } + + event = UINT64((clock_base + (clock_value ? 2 : 1))*external_to_internal_ratio)+1; + } + break; + + case CLKM_EXTERNAL_RATE_ASYNC: + if(clock_state || !clock_value) { + UINT64 ctime = UINT64(current_time*internal_to_external_ratio); + if(ctime >= clock_base) { + UINT64 delta = ctime - clock_base; + clock_base += delta & ~15; + delta &= 15; + bool new_clock = delta >= 8; + if(new_clock != clock_value) { + cpu->synchronize(); + if((!new_clock) && (clock_state & CLK_TX)) + tx_dropped_edge(); + + else if(new_clock && (clock_state & CLK_RX)) + rx_raised_edge(); + + clock_value = new_clock; + } + } + + event = UINT64((clock_base + (clock_value ? 16 : 8))*external_to_internal_ratio)+1; + } + break; + + case CLKM_EXTERNAL_ASYNC: + case CLKM_EXTERNAL_SYNC: + break;; + } + if(event) { + attotime ctime = machine().time(); + attotime sync_time = attotime::from_ticks(event-10, cpu->clock()); + if(cur_sync_time != sync_time && sync_time > ctime) { + sync_timer->adjust(sync_time - ctime); + cur_sync_time = sync_time; + } + } + + return event; +} + +void h8_sci_device::clock_start(int mode) +{ + // Happens when back-to-back + if(clock_state & mode) + return; + + if(!clock_state) { + cpu->synchronize(); + clock_state = mode; + switch(clock_mode) { + case CLKM_INTERNAL_ASYNC: + case CLKM_INTERNAL_ASYNC_OUT: + case CLKM_INTERNAL_SYNC_OUT: + logerror("%s: Starting internal clock\n", tag()); + clock_base = cpu->total_cycles(); + cpu->internal_update(); + break; + + case CLKM_EXTERNAL_RATE_ASYNC: + logerror("%s: Simulating external clock async\n", tag()); + clock_base = UINT64(cpu->total_cycles()*internal_to_external_ratio); + cpu->internal_update(); + break; + + case CLKM_EXTERNAL_RATE_SYNC: + logerror("%s: Simulating external clock sync\n", tag()); + clock_base = UINT64(cpu->total_cycles()*2*internal_to_external_ratio); + cpu->internal_update(); + break; + + case CLKM_EXTERNAL_ASYNC: + logerror("%s: Waiting for external clock async\n", tag()); + ext_clock_counter = 15; + break; + + case CLKM_EXTERNAL_SYNC: + logerror("%s: Waiting for external clock sync\n", tag()); + break; + } + } else + clock_state |= mode; +} + +void h8_sci_device::clock_stop(int mode) +{ + clock_state &= ~mode; + cpu->internal_update(); +} + +void h8_sci_device::tx_start() +{ + ssr |= SSR_TDRE; + tsr = tdr; + tx_parity = smr & SMR_OE ? 0 : 1; + logerror("%s: start transmit %02x\n", tag(), tsr); + if(scr & SCR_TIE) + intc->internal_interrupt(txi_int); + if(smr & SMR_CA) { + tx_state = ST_BIT; + tx_bit = 8; + } else { + tx_state = ST_START; + tx_bit = 1; + } + clock_start(CLK_TX); + if(rx_state == ST_IDLE && !has_recv_error() && is_sync_start()) + rx_start(); +} + +void h8_sci_device::tx_dropped_edge() +{ + logerror("%s: tx_dropped_edge state=%s bit=%d\n", tag(), state_names[tx_state], tx_bit); + switch(tx_state) { + case ST_START: + tx_cb(false); + assert(tx_bit == 1); + tx_state = ST_BIT; + tx_bit = smr & SMR_CHR ? 7 : 8; + break; + + case ST_BIT: + tx_parity ^= (tsr & 1); + tx_cb(tsr & 1); + tsr >>= 1; + tx_bit--; + if(!tx_bit) { + if(smr & SMR_CA) { + if(!(ssr & SSR_TDRE)) + tx_start(); + else { + tx_state = ST_LAST_TICK; + tx_bit = 0; + } + } else if(smr & SMR_PE) { + tx_state = ST_PARITY; + tx_bit = 1; + } else { + tx_state = ST_STOP; + tx_bit = smr & SMR_STOP ? 2 : 1; + } + } + break; + + case ST_PARITY: + tx_cb(tx_parity); + assert(tx_bit == 1); + tx_state = ST_STOP; + tx_bit = smr & SMR_STOP ? 2 : 1; + break; + + case ST_STOP: + tx_cb(true); + tx_bit--; + if(!tx_bit) { + if(!(ssr & SSR_TDRE)) + tx_start(); + else { + tx_state = ST_LAST_TICK; + tx_bit = 0; + } + } + break; + + case ST_LAST_TICK: + tx_state = ST_IDLE; + tx_bit = 0; + clock_stop(CLK_TX); + tx_cb(1); + ssr |= SSR_TEND; + if(scr & SCR_TEIE) + intc->internal_interrupt(tei_int); + break; + + default: + abort(); + } + logerror("%s: -> state=%s bit=%d\n", tag(), state_names[tx_state], tx_bit); +} + +void h8_sci_device::rx_start() +{ + ssr |= SSR_TDRE; + rx_parity = smr & SMR_OE ? 0 : 1; + rsr = 0x00; + logerror("%s: start receive\n", tag()); + if(smr & SMR_CA) { + rx_state = ST_BIT; + rx_bit = 8; + clock_start(CLK_RX); + } else { + rx_state = ST_START; + rx_bit = 1; + if(!rx_value) + clock_start(CLK_RX); + } +} + +void h8_sci_device::rx_done() +{ + if(!(ssr & SSR_FER)) { + if((smr & SMR_PE) && rx_parity) { + ssr |= SSR_PER; + logerror("%s: Receive parity error\n", tag()); + } else if(ssr & SSR_RDRF) { + ssr |= SSR_ORER; + logerror("%s: Receive overrun\n", tag()); + } else { + ssr |= SSR_RDRF; + logerror("%s: Received %02x\n", tag(), rsr); + rdr = rsr; + } + } + if(scr & SCR_RIE) { + if(has_recv_error()) + intc->internal_interrupt(eri_int); + else + intc->internal_interrupt(rxi_int); + } + if((scr & SCR_RE) && !has_recv_error() && !is_sync_start()) + rx_start(); + else { + clock_stop(CLK_RX); + rx_state = ST_IDLE; + } +} + +void h8_sci_device::rx_raised_edge() +{ + logerror("%s: rx_raised_edge state=%s bit=%d\n", tag(), state_names[rx_state], rx_bit); + switch(rx_state) { + case ST_START: + if(rx_value) { + clock_stop(CLK_RX); + break; + } + rx_state = ST_BIT; + rx_bit = smr & SMR_CHR ? 7 : 8; + break; + + case ST_BIT: + rx_parity ^= rx_value; + rsr >>= 1; + if(rx_value) { + rx_parity = !rx_parity; + rsr |= (smr & (SMR_CA|SMR_CHR)) == SMR_CHR ? 0x40 : 0x80; + } + rx_bit--; + if(!rx_bit) { + if(smr & SMR_CA) + rx_done(); + else if(smr & SMR_PE) { + rx_state = ST_PARITY; + rx_bit = 1; + } else { + rx_state = ST_STOP; + rx_bit = 1; // Always 1 on rx + } + } + break; + + case ST_PARITY: + rx_parity ^= rx_value; + assert(rx_bit == 1); + rx_state = ST_STOP; + rx_bit = 1; + break; + + case ST_STOP: + assert(rx_bit == 1); + if(!rx_value) + ssr |= SSR_FER; + else if((smr & SMR_PE) && rx_parity) + ssr |= SSR_PER; + rx_done(); + break; + + default: + abort(); + } + logerror("%s: -> state=%s, bit=%d\n", tag(), state_names[rx_state], rx_bit); +} diff --git a/src/devices/cpu/h8/h8_sci.h b/src/devices/cpu/h8/h8_sci.h new file mode 100644 index 00000000000..7e93f14dc14 --- /dev/null +++ b/src/devices/cpu/h8/h8_sci.h @@ -0,0 +1,147 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +/*************************************************************************** + + h8_sci.h + + H8 Serial Communications Interface + + +***************************************************************************/ + +#ifndef __H8_SCI_H__ +#define __H8_SCI_H__ + +#include "h8.h" +#include "h8_intc.h" + +#define MCFG_H8_SCI_ADD( _tag, intc, eri, rxi, txi, tei ) \ + MCFG_DEVICE_ADD( _tag, H8_SCI, 0 ) \ + downcast(device)->set_info(intc, eri, rxi, txi, tei); + +#define MCFG_H8_SCI_SET_EXTERNAL_CLOCK_PERIOD(_period) \ + downcast(device)->set_external_clock_period(_period); + +#define MCFG_H8_SCI_TX_CALLBACK(_devcb) \ + devcb = &h8_sci_device::set_tx_cb(*device, DEVCB_##_devcb); + +#define MCFG_H8_SCI_CLK_CALLBACK(_devcb) \ + devcb = &h8_sci_device::set_clk_cb(*device, DEVCB_##_devcb); + +class h8_sci_device : public device_t { +public: + h8_sci_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + void set_info(const char *intc, int eri, int rxi, int txi, int tei); + void set_external_clock_period(const attotime &_period); + + DECLARE_WRITE8_MEMBER(smr_w); + DECLARE_READ8_MEMBER(smr_r); + DECLARE_WRITE8_MEMBER(brr_w); + DECLARE_READ8_MEMBER(brr_r); + DECLARE_WRITE8_MEMBER(scr_w); + DECLARE_READ8_MEMBER(scr_r); + DECLARE_WRITE8_MEMBER(tdr_w); + DECLARE_READ8_MEMBER(tdr_r); + DECLARE_WRITE8_MEMBER(ssr_w); + DECLARE_READ8_MEMBER(ssr_r); + DECLARE_READ8_MEMBER(rdr_r); + DECLARE_WRITE8_MEMBER(scmr_w); + DECLARE_READ8_MEMBER(scmr_r); + + DECLARE_WRITE_LINE_MEMBER(rx_w); + DECLARE_WRITE_LINE_MEMBER(clk_w); + + template static devcb_base &set_tx_cb(device_t &device, _Object object) { return downcast(device).tx_cb.set_callback(object); } + template static devcb_base &set_clk_cb(device_t &device, _Object object) { return downcast(device).clk_cb.set_callback(object); } + + UINT64 internal_update(UINT64 current_time); + +protected: + enum { + ST_IDLE, ST_START, ST_BIT, ST_PARITY, ST_STOP, ST_LAST_TICK + }; + + static const char *const state_names[]; + + enum { + CLK_TX = 1, + CLK_RX = 2 + }; + + enum { + CLKM_INTERNAL_ASYNC, + CLKM_INTERNAL_ASYNC_OUT, + CLKM_EXTERNAL_ASYNC, + CLKM_EXTERNAL_RATE_ASYNC, + CLKM_INTERNAL_SYNC_OUT, + CLKM_EXTERNAL_SYNC, + CLKM_EXTERNAL_RATE_SYNC + }; + + enum { + SMR_CA = 0x80, + SMR_CHR = 0x40, + SMR_PE = 0x20, + SMR_OE = 0x10, + SMR_STOP = 0x08, + SMR_MP = 0x04, + SMR_CKS = 0x03, + + SCR_TIE = 0x80, + SCR_RIE = 0x40, + SCR_TE = 0x20, + SCR_RE = 0x10, + SCR_MPIE = 0x08, + SCR_TEIE = 0x04, + SCR_CKE = 0x03, + SCR_CKE1 = 0x02, + SCR_CKE0 = 0x01, + + SSR_TDRE = 0x80, + SSR_RDRF = 0x40, + SSR_ORER = 0x20, + SSR_FER = 0x10, + SSR_PER = 0x08, + SSR_TEND = 0x04, + SSR_MPB = 0x02, + SSR_MPBT = 0x01 + }; + + required_device cpu; + devcb_write_line tx_cb, clk_cb; + h8_intc_device *intc; + const char *intc_tag; + attotime external_clock_period, cur_sync_time; + double external_to_internal_ratio, internal_to_external_ratio; + emu_timer *sync_timer; + + int eri_int, rxi_int, txi_int, tei_int; + + int tx_state, rx_state, tx_bit, rx_bit, clock_state, clock_mode, tx_parity, rx_parity, ext_clock_counter; + bool clock_value, ext_clock_value, rx_value; + + UINT8 rdr, tdr, smr, scr, ssr, brr, rsr, tsr; + UINT64 clock_base, divider; + + + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + void clock_start(int mode); + void clock_stop(int mode); + void clock_update(); + void tx_start(); + void tx_dropped_edge(); + void rx_start(); + void rx_done(); + void rx_raised_edge(); + + bool is_sync_start() const; + bool has_recv_error() const; +}; + +extern const device_type H8_SCI; + +#endif diff --git a/src/devices/cpu/h8/h8_timer16.c b/src/devices/cpu/h8/h8_timer16.c new file mode 100644 index 00000000000..5714985dd84 --- /dev/null +++ b/src/devices/cpu/h8/h8_timer16.c @@ -0,0 +1,755 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +#include "emu.h" +#include "h8_timer16.h" + +#define LOG_EVENT_TIME 0 + +const device_type H8_TIMER16 = &device_creator; +const device_type H8_TIMER16_CHANNEL = &device_creator; +const device_type H8H_TIMER16_CHANNEL = &device_creator; +const device_type H8S_TIMER16_CHANNEL = &device_creator; + +h8_timer16_channel_device::h8_timer16_channel_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, H8_TIMER16_CHANNEL, "H8 16-bits timer channel", tag, owner, clock, "h8_16bits_timer_channel", __FILE__), + cpu(*this, "^^") +{ + chain_tag = NULL; +} + +h8_timer16_channel_device::h8_timer16_channel_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + cpu(*this, "^^") +{ + chain_tag = NULL; +} + +void h8_timer16_channel_device::set_info(int _tgr_count, int _tbr_count, const char *intc, int irq_base) +{ + tgr_count = _tgr_count; + tbr_count = _tbr_count; + intc_tag = intc; + + interrupt[0] = irq_base++; + interrupt[1] = irq_base++; + interrupt[2] = -1; + interrupt[3] = -1; + interrupt[4] = irq_base; + interrupt[5] = irq_base; +} + +READ8_MEMBER(h8_timer16_channel_device::tcr_r) +{ + return tcr; +} + +WRITE8_MEMBER(h8_timer16_channel_device::tcr_w) +{ + update_counter(); + tcr = data; + logerror("%s: tcr_w %02x\n", tag(), data); + tcr_update(); + recalc_event(); +} + +READ8_MEMBER(h8_timer16_channel_device::tmdr_r) +{ + return 0x00; +} + +WRITE8_MEMBER(h8_timer16_channel_device::tmdr_w) +{ + logerror("%s: tmdr_w %02x\n", tag(), data); +} + +READ8_MEMBER(h8_timer16_channel_device::tior_r) +{ + return 0x00; +} + +WRITE8_MEMBER(h8_timer16_channel_device::tior_w) +{ + logerror("%s: tior_w %d, %02x\n", tag(), offset, data); +} + +void h8_timer16_channel_device::set_ier(UINT8 value) +{ + update_counter(); + ier = value; + recalc_event(); +} + +void h8_timer16_channel_device::set_enable(bool enable) +{ + update_counter(); + channel_active = enable; + recalc_event(); +} + +READ8_MEMBER(h8_timer16_channel_device::tier_r) +{ + return tier; +} + +WRITE8_MEMBER(h8_timer16_channel_device::tier_w) +{ + update_counter(); + logerror("%s: tier_w %02x\n", tag(), data); + tier = data; + tier_update(); + logerror("%s: irq %c%c%c%c%c%c trigger=%d\n", + tag(), + ier & IRQ_A ? 'a' : '.', + ier & IRQ_B ? 'b' : '.', + ier & IRQ_C ? 'c' : '.', + ier & IRQ_D ? 'd' : '.', + ier & IRQ_V ? 'v' : '.', + ier & IRQ_U ? 'u' : '.', + ier & IRQ_TRIG ? 1 : 0); + recalc_event(); +} + +READ8_MEMBER(h8_timer16_channel_device::tsr_r) +{ + return isr_to_sr(); +} + +WRITE8_MEMBER(h8_timer16_channel_device::tsr_w) +{ + logerror("%s: tsr_w %02x\n", tag(), data); + isr_update(data); +} + +READ16_MEMBER(h8_timer16_channel_device::tcnt_r) +{ + update_counter(); + return tcnt; +} + +WRITE16_MEMBER(h8_timer16_channel_device::tcnt_w) +{ + update_counter(); + COMBINE_DATA(&tcnt); + logerror("%s: tcnt_w %04x\n", tag(), tcnt); + recalc_event(); +} + +READ16_MEMBER(h8_timer16_channel_device::tgr_r) +{ + return tgr[offset]; +} + +WRITE16_MEMBER(h8_timer16_channel_device::tgr_w) +{ + update_counter(); + COMBINE_DATA(tgr + offset); + if(1) + logerror("%s: tgr%c_w %04x\n", tag(), 'a'+offset, tgr[offset]); + recalc_event(); +} + +READ16_MEMBER(h8_timer16_channel_device::tbr_r) +{ + return tgr[offset+tgr_count]; +} + +WRITE16_MEMBER(h8_timer16_channel_device::tbr_w) +{ + COMBINE_DATA(tgr + offset + tgr_count); + if(1) + logerror("%s: tbr%c_w %04x\n", tag(), 'a'+offset, tgr[offset]); +} + +void h8_timer16_channel_device::device_start() +{ + intc = owner()->siblingdevice(intc_tag); + channel_active = false; + device_reset(); + + save_item(NAME(tgr_clearing)); + save_item(NAME(tcr)); + save_item(NAME(tier)); + save_item(NAME(ier)); + save_item(NAME(isr)); + save_item(NAME(clock_type)); + save_item(NAME(clock_divider)); + save_item(NAME(tcnt)); + save_item(NAME(tgr)); + save_item(NAME(last_clock_update)); + save_item(NAME(event_time)); + save_item(NAME(phase)); + save_item(NAME(counter_cycle)); + save_item(NAME(counter_incrementing)); + save_item(NAME(channel_active)); +} + +void h8_timer16_channel_device::device_reset() +{ + // Don't touch channel_active here, top level device handles it + tcr = 0; + tcnt = 0; + memset(tgr, 0xff, sizeof(tgr)); + tgr_clearing = TGR_CLEAR_NONE; + clock_type = DIV_1; + clock_divider = 0; + counter_cycle = 0x10000; + phase = 0; + tier = 0x40 & tier_mask; + ier = 0; + isr = 0; + last_clock_update = 0; + event_time = 0; + counter_incrementing = true; +} + +UINT64 h8_timer16_channel_device::internal_update(UINT64 current_time) +{ + if(event_time && current_time >= event_time) { + update_counter(current_time); + if(0) + logerror("%s: Reached event time (%ld), counter=%04x, dt=%d\n", tag(), long(current_time), tcnt, int(current_time - event_time)); + recalc_event(current_time); + } + + return event_time; +} + +void h8_timer16_channel_device::update_counter(UINT64 cur_time) +{ + if(clock_type != DIV_1) + return; + + if(!cur_time) + cur_time = cpu->total_cycles(); + + if(!channel_active) { + last_clock_update = cur_time; + return; + } + + UINT64 base_time = last_clock_update; + UINT64 new_time = cur_time; + if(clock_divider) { + base_time = (base_time + phase) >> clock_divider; + new_time = (new_time + phase) >> clock_divider; + } + if(counter_incrementing) { + int ott = tcnt; + int tt = tcnt + new_time - base_time; + tcnt = tt % counter_cycle; + if(0) + logerror("%s: Updating %d (%ld %ld) (%ld %ld) -> %d/%d\n", + tag(), + ott, + long(last_clock_update), long(cur_time), + long(base_time), long(new_time), + tt, tcnt); + + for(int i=0; iinternal_interrupt(interrupt[i]); + } + if(tt >= 0x10000 && (ier & IRQ_V) && interrupt[4] != -1) { + isr |= IRQ_V; + intc->internal_interrupt(interrupt[4]); + } + } else + tcnt = (((tcnt ^ 0xffff) + new_time - base_time) % counter_cycle) ^ 0xffff; + last_clock_update = cur_time; +} + +void h8_timer16_channel_device::recalc_event(UINT64 cur_time) +{ + if(!channel_active) { + event_time = 0; + return; + } + + bool update_cpu = cur_time == 0; + UINT64 old_event_time = event_time; + + if(clock_type != DIV_1) { + event_time = 0; + if(old_event_time && update_cpu) + cpu->internal_update(); + + return; + } + + if(!cur_time) + cur_time = cpu->total_cycles(); + + if(counter_incrementing) { + UINT32 event_delay = 0xffffffff; + if(tgr_clearing >= 0 && tgr[tgr_clearing]) + counter_cycle = tgr[tgr_clearing]; + else { + counter_cycle = 0x10000; + if(ier & IRQ_V) { + event_delay = counter_cycle - tcnt; + if(!event_delay) + event_delay = counter_cycle; + } + } + for(int i=0; i tcnt) { + if(tcnt >= counter_cycle || tgr[i] <= counter_cycle) + new_delay = tgr[i] - tcnt; + } else if(tgr[i] <= counter_cycle) { + if(tcnt < counter_cycle) + new_delay = (counter_cycle - tcnt) + tgr[i]; + else + new_delay = (0x10000 - tcnt) + tgr[i]; + } + + if(0) + logerror("%s: tcnt=%d tgr%c=%d cycle=%d -> delay=%d\n", + tag(), tcnt, 'a'+i, tgr[i], counter_cycle, new_delay); + if(event_delay > new_delay) + event_delay = new_delay; + } + + if(event_delay != 0xffffffff) + event_time = ((((cur_time + (1ULL << clock_divider) - phase) >> clock_divider) + event_delay - 1) << clock_divider) + phase; + else + event_time = 0; + + if(event_time && LOG_EVENT_TIME) + logerror("%s: next event in %d cycles (%ld)\n", tag(), int(event_time - cpu->total_cycles()), long(event_time)); + + } else { + logerror("decrementing counter\n"); + exit(1); + } + + if(old_event_time != event_time && update_cpu) + cpu->internal_update(); +} + +h8_timer16_device::h8_timer16_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, H8_TIMER16, "H8 16-bits timer", tag, owner, clock, "h8_timer16", __FILE__), + cpu(*this, DEVICE_SELF_OWNER) +{ +} + +void h8_timer16_device::set_info(int count, UINT8 tstr) +{ + timer_count = count; + default_tstr = tstr; +} + +void h8_timer16_device::device_start() +{ + memset(timer_channel, 0, sizeof(timer_channel)); + for(int i=0; i(tm); + } + + save_item(NAME(tstr)); +} + +void h8_timer16_device::device_reset() +{ + tstr = default_tstr; + for(int i=0; iset_enable((tstr >> i) & 1); +} + + +READ8_MEMBER(h8_timer16_device::tstr_r) +{ + return tstr; +} + +WRITE8_MEMBER(h8_timer16_device::tstr_w) +{ + logerror("%s: tstr_w %02x\n", tag(), data); + tstr = data; + for(int i=0; iset_enable((tstr >> i) & 1); +} + +READ8_MEMBER(h8_timer16_device::tsyr_r) +{ + return 0x00; +} + +WRITE8_MEMBER(h8_timer16_device::tsyr_w) +{ + logerror("%s: tsyr_w %02x\n", tag(), data); +} + +READ8_MEMBER(h8_timer16_device::tmdr_r) +{ + return 0x00; +} + +WRITE8_MEMBER(h8_timer16_device::tmdr_w) +{ + logerror("%s: tmdr_w %02x\n", tag(), data); +} + +READ8_MEMBER(h8_timer16_device::tfcr_r) +{ + return 0x00; +} + +WRITE8_MEMBER(h8_timer16_device::tfcr_w) +{ + logerror("%s: tfcr_w %02x\n", tag(), data); +} + +READ8_MEMBER(h8_timer16_device::toer_r) +{ + return 0x00; +} + +WRITE8_MEMBER(h8_timer16_device::toer_w) +{ + logerror("%s: toer_w %02x\n", tag(), data); +} + +READ8_MEMBER(h8_timer16_device::tocr_r) +{ + return 0x00; +} + +WRITE8_MEMBER(h8_timer16_device::tocr_w) +{ + logerror("%s: tocr_w %02x\n", tag(), data); +} + +READ8_MEMBER(h8_timer16_device::tisr_r) +{ + UINT8 r = 0; + for(int i=0; itisr_r(offset) << i; + for(int i=timer_count; i<4; i++) + r |= 0x11 <tisr_w(offset, data >> i); +} + +READ8_MEMBER(h8_timer16_device::tisrc_r) +{ + return tisr_r(space, 2, mem_mask); +} + +WRITE8_MEMBER(h8_timer16_device::tisrc_w) +{ + tisr_w(space, 2, data, mem_mask); +} + +WRITE8_MEMBER(h8_timer16_device::tolr_w) +{ + logerror("%s: tocr_w %02x\n", tag(), data); +} + + + +void h8_timer16_channel_device::tier_update() +{ +} + +void h8_timer16_channel_device::isr_update(UINT8 val) +{ +} + +UINT8 h8_timer16_channel_device::isr_to_sr() const +{ + return 0x00; +} + +void h8_timer16_channel_device::tcr_update() +{ +} + +void h8_timer16_channel_device::tisr_w(int offset, UINT8 value) +{ + update_counter(); + if(!(value & 0x01)) { + switch(offset) { + case 0: + isr &= ~IRQ_A; + break; + case 1: + isr &= ~IRQ_B; + break; + case 2: + isr &= ~IRQ_V; + break; + } + } + if(value & 0x10) { + switch(offset) { + case 0: + ier |= IRQ_A; + break; + case 1: + ier |= IRQ_B; + break; + case 2: + ier |= IRQ_V; + break; + } + } else { + switch(offset) { + case 0: + ier &= ~IRQ_A; + break; + case 1: + ier &= ~IRQ_B; + break; + case 2: + ier &= ~IRQ_V; + break; + } + } + recalc_event(); +} + +UINT8 h8_timer16_channel_device::tisr_r(int offset) const +{ + switch(offset) { + case 0: + return ((ier & IRQ_A) ? 0x10 : 0x00) | ((isr & IRQ_A) ? 0x01 : 0x00); + case 1: + return ((ier & IRQ_B) ? 0x10 : 0x00) | ((isr & IRQ_B) ? 0x01 : 0x00); + case 2: + return ((ier & IRQ_V) ? 0x10 : 0x00) | ((isr & IRQ_V) ? 0x01 : 0x00); + } + return 0x00; +} + +h8h_timer16_channel_device::h8h_timer16_channel_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + h8_timer16_channel_device(mconfig, H8H_TIMER16_CHANNEL, "H8H 16-bits timer channel", tag, owner, clock, "h8h_16bits_timer_channel", __FILE__) +{ +} + +h8h_timer16_channel_device::~h8h_timer16_channel_device() +{ +} + +void h8h_timer16_channel_device::set_info(int _tgr_count, int _tbr_count, const char *intc, int irq_base) +{ + tgr_count = _tgr_count; + tbr_count = _tbr_count; + intc_tag = intc; + + interrupt[0] = irq_base++; + interrupt[1] = irq_base++; + interrupt[2] = -1; + interrupt[3] = -1; + interrupt[4] = irq_base; + interrupt[5] = irq_base; +} + +void h8h_timer16_channel_device::tier_update() +{ + tier = tier | 0xf8; + ier = + (tier & 0x01 ? IRQ_A : 0) | + (tier & 0x02 ? IRQ_B : 0) | + (tier & 0x04 ? IRQ_V : 0); +} + +void h8h_timer16_channel_device::isr_update(UINT8 val) +{ + if(!(val & 1)) + isr &= ~IRQ_A; + if(!(val & 2)) + isr &= ~IRQ_B; + if(!(val & 4)) + isr &= ~IRQ_V; +} + +UINT8 h8h_timer16_channel_device::isr_to_sr() const +{ + return 0xf8 | (isr & IRQ_V ? 4 : 0) | (isr & IRQ_B ? 2 : 0) | (isr & IRQ_A ? 1 : 0); +} + + +void h8h_timer16_channel_device::tcr_update() +{ + switch(tcr & 0x60) { + case 0x00: + tgr_clearing = TGR_CLEAR_NONE; + logerror("%s: No automatic tcnt clearing\n", tag()); + break; + case 0x20: case 0x40: { + tgr_clearing = tcr & 0x20 ? 0 : 1; + logerror("%s: Auto-clear on tgr%c (%04x)\n", tag(), 'a'+tgr_clearing, tgr[tgr_clearing]); + break; + } + case 0x60: + tgr_clearing = TGR_CLEAR_EXT; + logerror("%s: External sync clear\n", tag()); + break; + } + + int count_type = tcr & 7; + if(count_type < 4) { + clock_type = DIV_1; + clock_divider = count_type; + logerror("%s: clock divider %d (%d)\n", tag(), clock_divider, 1 << clock_divider); + if(count_type <= DIV_2) + phase = 0; + else { + switch(tcr & 0x18) { + case 0x00: + phase = 0; + logerror("%s: Phase 0\n", tag()); + break; + case 0x08: + phase = 1 << (clock_divider-1); + logerror("%s: Phase 180\n", tag()); + break; + case 0x10: case 0x18: + phase = 0; + clock_divider--; + logerror("%s: Phase 0+180\n", tag()); + break; + } + } + } else { + clock_type = INPUT_A + (count_type-4); + clock_divider = 0; + phase = 0; + logerror("%s: counting input %c\n", tag(), 'a'+count_type-INPUT_A); + } +} + +h8s_timer16_channel_device::h8s_timer16_channel_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + h8_timer16_channel_device(mconfig, H8S_TIMER16_CHANNEL, "H8S 16-bits timer channel", tag, owner, clock, "h8s_16bits_timer_channel", __FILE__) +{ +} + +h8s_timer16_channel_device::~h8s_timer16_channel_device() +{ +} + +void h8s_timer16_channel_device::set_chain(const char *_chain_tag) +{ + chain_tag = _chain_tag; +} + +void h8s_timer16_channel_device::set_info(int _tgr_count, UINT8 _tier_mask, const char *intc, int irq_base, + int t0, int t1, int t2, int t3, int t4, int t5, int t6, int t7) +{ + tgr_count = _tgr_count; + tbr_count = 0; + tier_mask = _tier_mask; + intc_tag = intc; + + interrupt[0] = irq_base++; + interrupt[1] = irq_base++; + interrupt[2] = tier_mask & 0x04 ? -1 : irq_base++; + interrupt[3] = tier_mask & 0x08 ? -1 : irq_base++; + interrupt[4] = irq_base; + interrupt[5] = tier_mask & 0x20 ? -1 : irq_base++; + + count_types[0] = t0; + count_types[1] = t1; + count_types[2] = t2; + count_types[3] = t3; + count_types[4] = t4; + count_types[5] = t5; + count_types[6] = t6; + count_types[7] = t7; +} + +void h8s_timer16_channel_device::tier_update() +{ + tier = (tier & ~tier_mask) | 0x40; + ier = + (tier & 0x01 ? IRQ_A : 0) | + (tier & 0x02 ? IRQ_B : 0) | + (tier & 0x04 ? IRQ_C : 0) | + (tier & 0x08 ? IRQ_D : 0) | + (tier & 0x10 ? IRQ_V : 0) | + (tier & 0x20 ? IRQ_U : 0) | + (tier & 0x80 ? IRQ_TRIG : 0); +} + +void h8s_timer16_channel_device::isr_update(UINT8 val) +{ + isr &= (val | tier_mask | 0xc0); +} + +UINT8 h8s_timer16_channel_device::isr_to_sr() const +{ + return 0xc0 | isr; +} + +void h8s_timer16_channel_device::tcr_update() +{ + switch(tcr & 0x60) { + case 0x00: + tgr_clearing = TGR_CLEAR_NONE; + logerror("%s: No automatic tcnt clearing\n", tag()); + break; + case 0x20: case 0x40: { + tgr_clearing = tcr & 0x20 ? 0 : 1; + if(tgr_count > 2 && (tcr & 0x80)) + tgr_clearing += 2; + logerror("%s: Auto-clear on tgr%c\n", tag(), 'a'+tgr_clearing); + break; + } + case 0x60: + tgr_clearing = TGR_CLEAR_EXT; + logerror("%s: External sync clear\n", tag()); + break; + } + + int count_type = count_types[tcr & 7]; + if(count_type >= DIV_1 && clock_type <= DIV_4) { + clock_type = DIV_1; + clock_divider = count_type - DIV_1; + logerror("%s: clock divider %d (%d)\n", tag(), clock_divider, 1 << clock_divider); + if(!clock_divider) + phase = 0; + else { + switch(tcr & 0x18) { + case 0x00: + phase = 0; + logerror("%s: Phase 0\n", tag()); + break; + case 0x08: + phase = 1 << (clock_divider-1); + logerror("%s: Phase 180\n", tag()); + break; + case 0x10: case 0x18: + phase = 0; + clock_divider--; + logerror("%s: Phase 0+180\n", tag()); + break; + } + } + + } else if(count_type == CHAIN) { + clock_type = CHAIN; + clock_divider = 0; + phase = 0; + logerror("%s: chained timer\n", tag()); + + } else if(count_type >= INPUT_A && count_type <= INPUT_D) { + clock_type = count_type; + clock_divider = 0; + phase = 0; + logerror("%s: counting input %c\n", tag(), 'a'+count_type-INPUT_A); + } +} diff --git a/src/devices/cpu/h8/h8_timer16.h b/src/devices/cpu/h8/h8_timer16.h new file mode 100644 index 00000000000..e187999625e --- /dev/null +++ b/src/devices/cpu/h8/h8_timer16.h @@ -0,0 +1,207 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +/*************************************************************************** + + h8_timer16.h + + H8 16 bits timer + + +***************************************************************************/ + +#ifndef __H8_TIMER16_H__ +#define __H8_TIMER16_H__ + +#include "h8.h" +#include "h8_intc.h" + +#define MCFG_H8_TIMER16_ADD( _tag, _count, _tstr ) \ + MCFG_DEVICE_ADD( _tag, H8_TIMER16, 0 ) \ + downcast(device)->set_info(_count, _tstr); + +#define MCFG_H8_TIMER16_CHANNEL_ADD( _tag, tgr_count, tbr_count, intc, irq_base ) \ + MCFG_DEVICE_ADD( _tag, H8_TIMER16_CHANNEL, 0 ) \ + downcast(device)->set_info(tgr_count, tbr_count, intc, irq_base); + +#define MCFG_H8H_TIMER16_CHANNEL_ADD( _tag, tgr_count, tbr_count, intc, irq_base ) \ + MCFG_DEVICE_ADD( _tag, H8H_TIMER16_CHANNEL, 0 ) \ + downcast(device)->set_info(tgr_count, tbr_count, intc, irq_base); + +#define MCFG_H8S_TIMER16_CHANNEL_ADD( _tag, tgr_count, tier_mask, intc, irq_base, t0, t1, t2, t3, t4, t5, t6, t7 ) \ + MCFG_DEVICE_ADD( _tag, H8S_TIMER16_CHANNEL, 0 ) \ + downcast(device)->set_info(tgr_count, tier_mask, intc, irq_base, t0, t1, t2, t3, t4, t5, t6, t7); + +#define MCFG_H8S_TIMER16_CHANNEL_SET_CHAIN( _tag ) \ + downcast(device)->set_chain(_tag); + +class h8_timer16_channel_device : public device_t { +public: + enum { + CHAIN, + INPUT_A, + INPUT_B, + INPUT_C, + INPUT_D, + DIV_1, + DIV_2, + DIV_4, + DIV_8, + DIV_16, + DIV_32, + DIV_64, + DIV_128, + DIV_256, + DIV_512, + DIV_1024, + DIV_2048, + DIV_4096 + }; + + enum { + TGR_CLEAR_NONE = -1, + TGR_CLEAR_EXT = -2 + }; + + enum { + IRQ_A = 0x01, + IRQ_B = 0x02, + IRQ_C = 0x04, + IRQ_D = 0x08, + IRQ_V = 0x10, + IRQ_U = 0x20, + IRQ_TRIG = 0x40 + }; + + + h8_timer16_channel_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + h8_timer16_channel_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + void set_info(int tgr_count, int tbr_count, const char *intc, int irq_base); + + DECLARE_READ8_MEMBER(tcr_r); + DECLARE_WRITE8_MEMBER(tcr_w); + DECLARE_READ8_MEMBER(tmdr_r); + DECLARE_WRITE8_MEMBER(tmdr_w); + DECLARE_READ8_MEMBER(tior_r); + DECLARE_WRITE8_MEMBER(tior_w); + DECLARE_READ8_MEMBER(tier_r); + DECLARE_WRITE8_MEMBER(tier_w); + DECLARE_READ8_MEMBER(tsr_r); + DECLARE_WRITE8_MEMBER(tsr_w); + DECLARE_READ8_MEMBER(tocr_r); + DECLARE_WRITE8_MEMBER(tocr_w); + DECLARE_READ16_MEMBER(tcnt_r); + DECLARE_WRITE16_MEMBER(tcnt_w); + DECLARE_READ16_MEMBER(tgr_r); + DECLARE_WRITE16_MEMBER(tgr_w); + DECLARE_READ16_MEMBER(tbr_r); + DECLARE_WRITE16_MEMBER(tbr_w); + + UINT64 internal_update(UINT64 current_time); + void set_ier(UINT8 value); + void set_enable(bool enable); + void tisr_w(int offset, UINT8 data); + UINT8 tisr_r(int offset) const; + +protected: + required_device cpu; + h8_timer16_channel_device *chained_timer; + h8_intc_device *intc; + const char *chain_tag, *intc_tag; + int interrupt[6]; + UINT8 tier_mask; + + int tgr_count, tbr_count; + int tgr_clearing; + UINT8 tcr, tier, ier, isr; + int clock_type, clock_divider; + UINT16 tcnt, tgr[6]; + UINT64 last_clock_update, event_time; + UINT32 phase, counter_cycle; + bool counter_incrementing; + bool channel_active; + + virtual void device_start(); + virtual void device_reset(); + + void update_counter(UINT64 cur_time = 0); + void recalc_event(UINT64 cur_time = 0); + virtual void tcr_update(); + virtual void tier_update(); + virtual void isr_update(UINT8 value); + virtual UINT8 isr_to_sr() const; +}; + +class h8h_timer16_channel_device : public h8_timer16_channel_device { +public: + h8h_timer16_channel_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual ~h8h_timer16_channel_device(); + + void set_info(int tgr_count, int tbr_count, const char *intc, int irq_base); + +protected: + virtual void tcr_update(); + virtual void tier_update(); + virtual void isr_update(UINT8 value); + virtual UINT8 isr_to_sr() const; +}; + +class h8s_timer16_channel_device : public h8_timer16_channel_device { +public: + h8s_timer16_channel_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual ~h8s_timer16_channel_device(); + + void set_info(int tgr_count, UINT8 _tier_mask, const char *intc, int irq_base, + int t0, int t1, int t2, int t3, int t4, int t5, int t6, int t7); + void set_chain(const char *chain_tag); + +protected: + int count_types[8]; + + virtual void tcr_update(); + virtual void tier_update(); + virtual void isr_update(UINT8 value); + virtual UINT8 isr_to_sr() const; +}; + +class h8_timer16_device : public device_t { +public: + h8_timer16_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + void set_info(int timer_count, UINT8 default_tstr); + + DECLARE_READ8_MEMBER(tstr_r); + DECLARE_WRITE8_MEMBER(tstr_w); + DECLARE_READ8_MEMBER(tsyr_r); + DECLARE_WRITE8_MEMBER(tsyr_w); + DECLARE_READ8_MEMBER(tmdr_r); + DECLARE_WRITE8_MEMBER(tmdr_w); + DECLARE_READ8_MEMBER(tfcr_r); + DECLARE_WRITE8_MEMBER(tfcr_w); + DECLARE_READ8_MEMBER(toer_r); + DECLARE_WRITE8_MEMBER(toer_w); + DECLARE_READ8_MEMBER(tocr_r); + DECLARE_WRITE8_MEMBER(tocr_w); + DECLARE_READ8_MEMBER(tisr_r); + DECLARE_WRITE8_MEMBER(tisr_w); + DECLARE_READ8_MEMBER(tisrc_r); + DECLARE_WRITE8_MEMBER(tisrc_w); + DECLARE_WRITE8_MEMBER(tolr_w); + +protected: + required_device cpu; + h8_timer16_channel_device *timer_channel[6]; + int timer_count; + UINT8 default_tstr; + UINT8 tstr; + + virtual void device_start(); + virtual void device_reset(); +}; + +extern const device_type H8_TIMER16; +extern const device_type H8_TIMER16_CHANNEL; +extern const device_type H8H_TIMER16_CHANNEL; +extern const device_type H8S_TIMER16_CHANNEL; + +#endif diff --git a/src/devices/cpu/h8/h8_timer8.c b/src/devices/cpu/h8/h8_timer8.c new file mode 100644 index 00000000000..b652f091c07 --- /dev/null +++ b/src/devices/cpu/h8/h8_timer8.c @@ -0,0 +1,373 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +#include "emu.h" +#include "h8_timer8.h" + +const device_type H8_TIMER8_CHANNEL = &device_creator; +const device_type H8H_TIMER8_CHANNEL = &device_creator; + +h8_timer8_channel_device::h8_timer8_channel_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, H8_TIMER8_CHANNEL, "H8 8-bits timer channel", tag, owner, clock, "h8_8bits_timer_channel", __FILE__), + cpu(*this, "^") +{ +} + +h8_timer8_channel_device::h8_timer8_channel_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + cpu(*this, "^") +{ +} + +void h8_timer8_channel_device::set_info(const char *intc, int _irq_ca, int _irq_cb, int _irq_v, int div1, int div2, int div3, int div4, int div5, int div6) +{ + intc_tag = intc; + irq_ca = _irq_ca; + irq_cb = _irq_cb; + irq_v = _irq_v; + chain_tag = NULL; + chain_type = STOPPED; + has_adte = false; + has_ice = false; + div_tab[0] = div1; + div_tab[1] = div2; + div_tab[2] = div3; + div_tab[3] = div4; + div_tab[4] = div5; + div_tab[5] = div6; +} + +READ8_MEMBER(h8_timer8_channel_device::tcr_r) +{ + return tcr; +} + +WRITE8_MEMBER(h8_timer8_channel_device::tcr_w) +{ + update_counter(); + tcr = data; + update_tcr(); + recalc_event(); +} + +void h8_timer8_channel_device::set_extra_clock_bit(bool bit) +{ + update_counter(); + extra_clock_bit = bit; + update_tcr(); + recalc_event(); +} + +void h8_timer8_channel_device::update_tcr() +{ + switch(tcr & TCR_CKS) { + case 0: + clock_type = STOPPED; + clock_divider = 0; + logerror("%s: clock stopped", tag()); + break; + + case 1: case 2: case 3: + clock_type = DIV; + clock_divider = div_tab[((tcr & TCR_CKS)-1)*2 + extra_clock_bit]; + logerror("%s: clock %dHz", tag(), cpu->clock()/clock_divider); + break; + + case 4: + clock_type = chain_type; + clock_divider = 0; + logerror("%s: clock chained %s", tag(), clock_type == CHAIN_A ? "tcora" : "overflow"); + break; + + case 5: + clock_type = INPUT_UP; + clock_divider = 0; + logerror("%s: clock external raising edge", tag()); + break; + + case 6: + clock_type = INPUT_DOWN; + clock_divider = 0; + logerror("%s: clock external falling edge", tag()); + break; + + case 7: + clock_type = INPUT_UPDOWN; + clock_divider = 0; + logerror("%s: clock external both edges", tag()); + break; + } + + switch(tcr & TCR_CCLR) { + case 0x00: + clear_type = CLEAR_NONE; + logerror(", no clear"); + break; + + case 0x08: + clear_type = CLEAR_A; + logerror(", clear on tcora"); + break; + + case 0x10: + clear_type = CLEAR_B; + logerror(", clear on tcorb"); + break; + + case 0x18: + clear_type = CLEAR_EXTERNAL; + logerror(", clear on external"); + break; + } + + logerror(", irq=%c%c%c\n", + tcr & TCR_CMIEB ? 'b' : '-', + tcr & TCR_CMIEA ? 'a' : '-', + tcr & TCR_OVIE ? 'o' : '-'); +} + +READ8_MEMBER(h8_timer8_channel_device::tcsr_r) +{ + return tcsr; +} + +WRITE8_MEMBER(h8_timer8_channel_device::tcsr_w) +{ + update_counter(); + + UINT8 mask = has_adte || has_ice ? 0x1f : 0x0f; + tcsr = (tcsr & ~mask) | (data & mask); + tcsr &= data | 0x1f; + + logerror("%s: tcsr_w %02x\n", tag(), tcsr); + + recalc_event(); +} + +READ8_MEMBER(h8_timer8_channel_device::tcor_r) +{ + return tcor[offset]; +} + +WRITE8_MEMBER(h8_timer8_channel_device::tcor_w) +{ + update_counter(); + tcor[offset] = data; + logerror("%s: tcor%c_w %02x\n", tag(), 'a'+offset, data); + recalc_event(); +} + +READ8_MEMBER(h8_timer8_channel_device::tcnt_r) +{ + update_counter(); + recalc_event(); + return tcnt; +} + +WRITE8_MEMBER(h8_timer8_channel_device::tcnt_w) +{ + update_counter(); + tcnt = data; + logerror("%s: tcnt_w %02x\n", tag(), data); + recalc_event(); +} + +void h8_timer8_channel_device::device_start() +{ + intc = siblingdevice(intc_tag); + if(chain_tag) + chained_timer = siblingdevice(chain_tag); + else + chained_timer = NULL; +} + +void h8_timer8_channel_device::device_reset() +{ + tcr = 0x00; + tcsr = has_adte || has_ice ? 0x00 : 0x10; + tcor[0] = 0xff; + tcor[1] = 0xff; + tcnt = 0x00; + counter_cycle = 0x100; + clock_type = STOPPED; + clock_divider = 0; + clear_type = CLEAR_NONE; + last_clock_update = 0; + event_time = 0; + extra_clock_bit = false; +} + +UINT64 h8_timer8_channel_device::internal_update(UINT64 current_time) +{ + if(event_time && current_time >= event_time) { + update_counter(current_time); + if(0) + logerror("%s: Reached event time (%ld), counter=%02x, dt=%d\n", tag(), long(current_time), tcnt, int(current_time - event_time)); + recalc_event(current_time); + } + + return event_time; +} + +void h8_timer8_channel_device::update_counter(UINT64 cur_time) +{ + if(clock_type != DIV) + return; + + if(!cur_time) + cur_time = cpu->total_cycles(); + + UINT64 base_time = (last_clock_update + clock_divider/2) / clock_divider; + UINT64 new_time = (cur_time + clock_divider/2) / clock_divider; + + int tt = tcnt + new_time - base_time; + tcnt = tt % counter_cycle; + + if(tt == tcor[0] || tcnt == tcor[0]) { + if(chained_timer) + chained_timer->chained_timer_tcora(); + + if(!(tcsr & TCSR_CMFA)) { + tcsr |= TCSR_CMFA; + if(tcr & TCR_CMIEA) + intc->internal_interrupt(irq_ca); + } + } + + if(!(tcsr & TCSR_CMFB) && (tt == tcor[1] || tcnt == tcor[1])) { + tcsr |= TCSR_CMFB; + if(tcr & TCR_CMIEB) + intc->internal_interrupt(irq_cb); + } + + if(tt >= 0x100) { + if(chained_timer) + chained_timer->chained_timer_overflow(); + if(!(tcsr & TCSR_OVF)) { + tcsr |= TCSR_OVF; + if(tcr & TCR_OVIE) + intc->internal_interrupt(irq_v); + } + } + last_clock_update = cur_time; +} + +void h8_timer8_channel_device::recalc_event(UINT64 cur_time) +{ + bool update_cpu = cur_time == 0; + UINT64 old_event_time = event_time; + + if(clock_type != DIV) { + event_time = 0; + if(old_event_time && update_cpu) + cpu->internal_update(); + return; + } + + if(!cur_time) + cur_time = cpu->total_cycles(); + + UINT32 event_delay = 0xffffffff; + if(clear_type == CLEAR_A || clear_type == CLEAR_B) + counter_cycle = tcor[clear_type - CLEAR_A]; + else { + counter_cycle = 0x100; + event_delay = counter_cycle - tcnt; + if(!event_delay) + event_delay = counter_cycle; + } + + for(int i=0; i<2; i++) { + UINT32 new_delay = 0xffffffff; + if(tcor[i] > tcnt) { + if(tcnt >= counter_cycle || tcor[i] <= counter_cycle) + new_delay = tcor[i] - tcnt; + } else if(tcor[i] <= counter_cycle) { + if(tcnt < counter_cycle) + new_delay = (counter_cycle - tcnt) + tcor[i]; + else + new_delay = (0x100 - tcnt) + tcor[i]; + } + if(event_delay > new_delay) + event_delay = new_delay; + } + + if(event_delay != 0xffffffff) + event_time = ((((cur_time + clock_divider) / clock_divider) + event_delay - 1) * clock_divider) + clock_divider/2; + else + event_time = 0; + + if(old_event_time != event_time && update_cpu) + cpu->internal_update(); +} + +void h8_timer8_channel_device::chained_timer_overflow() +{ + if(clock_type == CHAIN_OVERFLOW) + timer_tick(); +} + +void h8_timer8_channel_device::chained_timer_tcora() +{ + if(clock_type == CHAIN_A) + timer_tick(); +} + +void h8_timer8_channel_device::timer_tick() +{ + tcnt++; + + if(tcnt == tcor[0]) { + if(chained_timer) + chained_timer->chained_timer_tcora(); + + if(!(tcsr & TCSR_CMFA)) { + tcsr |= TCSR_CMFA; + if(tcr & TCR_CMIEA) + intc->internal_interrupt(irq_ca); + } + } + + if(!(tcsr & TCSR_CMFB) && tcnt == tcor[1]) { + tcsr |= TCSR_CMFB; + if(tcr & TCR_CMIEB) + intc->internal_interrupt(irq_cb); + } + + if(tcnt == 0x00) { + if(chained_timer) + chained_timer->chained_timer_overflow(); + if(!(tcsr & TCSR_OVF)) { + tcsr |= TCSR_OVF; + if(tcr & TCR_OVIE) + intc->internal_interrupt(irq_v); + } + } +} + +h8h_timer8_channel_device::h8h_timer8_channel_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + h8_timer8_channel_device(mconfig, H8H_TIMER8_CHANNEL, "H8H 8-bits timer channel", tag, owner, clock, "h8h_8bits_timer_channel", __FILE__) +{ +} + +h8h_timer8_channel_device::~h8h_timer8_channel_device() +{ +} + +void h8h_timer8_channel_device::set_info(const char *intc, int _irq_ca, int _irq_cb, int _irq_v, const char *_chain_tag, int _chain_type, bool _has_adte, bool _has_ice) +{ + intc_tag = intc; + irq_ca = _irq_ca; + irq_cb = _irq_cb; + irq_v = _irq_v; + chain_tag = _chain_tag; + chain_type = _chain_type; + has_adte = _has_adte; + has_ice = _has_ice; + // The extra clock bit is not used for h8h+ + div_tab[0] = 8; + div_tab[1] = 8; + div_tab[2] = 64; + div_tab[3] = 64; + div_tab[4] = 8192; + div_tab[5] = 8192; +} diff --git a/src/devices/cpu/h8/h8_timer8.h b/src/devices/cpu/h8/h8_timer8.h new file mode 100644 index 00000000000..d58677097e5 --- /dev/null +++ b/src/devices/cpu/h8/h8_timer8.h @@ -0,0 +1,113 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +/*************************************************************************** + + h8_timer8.h + + H8 8 bits timer + + +***************************************************************************/ + +#ifndef __H8_TIMER8_H__ +#define __H8_TIMER8_H__ + +#include "h8.h" +#include "h8_intc.h" + +#define MCFG_H8_TIMER8_CHANNEL_ADD( _tag, intc, irq_ca, irq_cb, irq_v, div1, div2, div3, div4, div5, div6 ) \ + MCFG_DEVICE_ADD( _tag, H8_TIMER8_CHANNEL, 0 ) \ + downcast(device)->set_info(intc, irq_ca, irq_cb, irq_v, div1, div2, div3, div4, div5, div6); + +#define MCFG_H8H_TIMER8_CHANNEL_ADD( _tag, intc, irq_ca, irq_cb, irq_v, chain, chain_mode, has_adte, has_ice ) \ + MCFG_DEVICE_ADD( _tag, H8H_TIMER8_CHANNEL, 0 ) \ + downcast(device)->set_info(intc, irq_ca, irq_cb, irq_v, chain, chain_mode, has_adte, has_ice); + +class h8_timer8_channel_device : public device_t { +public: + enum { + STOPPED, + CHAIN_A, + CHAIN_OVERFLOW, + INPUT_UP, + INPUT_DOWN, + INPUT_UPDOWN, + DIV + }; + + h8_timer8_channel_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + h8_timer8_channel_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + void set_info(const char *intc, int irq_ca, int irq_cb, int irq_v, int div1, int div2, int div3, int div4, int div5, int div6); + + DECLARE_READ8_MEMBER(tcr_r); + DECLARE_WRITE8_MEMBER(tcr_w); + DECLARE_READ8_MEMBER(tcsr_r); + DECLARE_WRITE8_MEMBER(tcsr_w); + DECLARE_READ8_MEMBER(tcor_r); + DECLARE_WRITE8_MEMBER(tcor_w); + DECLARE_READ8_MEMBER(tcnt_r); + DECLARE_WRITE8_MEMBER(tcnt_w); + + UINT64 internal_update(UINT64 current_time); + void set_extra_clock_bit(bool bit); + + void chained_timer_overflow(); + void chained_timer_tcora(); + +protected: + enum { + TCR_CKS = 0x07, + TCR_CCLR = 0x18, + TCR_OVIE = 0x20, + TCR_CMIEA = 0x40, + TCR_CMIEB = 0x80, + + TCSR_OS = 0x0f, + TCSR_ADTE = 0x10, + TCSR_OVF = 0x20, + TCSR_CMFA = 0x40, + TCSR_CMFB = 0x80 + }; + + enum { + CLEAR_NONE, + CLEAR_A, + CLEAR_B, + CLEAR_EXTERNAL + }; + + required_device cpu; + h8_timer8_channel_device *chained_timer; + h8_intc_device *intc; + const char *chain_tag, *intc_tag; + int irq_ca, irq_cb, irq_v, chain_type; + int div_tab[6]; + UINT8 tcor[2]; + UINT8 tcr, tcsr, tcnt; + bool extra_clock_bit, has_adte, has_ice; + int clock_type, clock_divider, clear_type, counter_cycle; + UINT64 last_clock_update, event_time; + + virtual void device_start(); + virtual void device_reset(); + + void update_counter(UINT64 cur_time = 0); + void recalc_event(UINT64 cur_time = 0); + + void timer_tick(); + void update_tcr(); +}; + +class h8h_timer8_channel_device : public h8_timer8_channel_device { +public: + h8h_timer8_channel_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual ~h8h_timer8_channel_device(); + + void set_info(const char *intc, int irq_ca, int irq_cb, int irq_v, const char *chain_tag, int chain_type, bool has_adte, bool has_ice); +}; + +extern const device_type H8_TIMER8_CHANNEL; +extern const device_type H8H_TIMER8_CHANNEL; + +#endif diff --git a/src/devices/cpu/h8/h8h.c b/src/devices/cpu/h8/h8h.c new file mode 100644 index 00000000000..89615fadad5 --- /dev/null +++ b/src/devices/cpu/h8/h8h.c @@ -0,0 +1,18 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +#include "emu.h" +#include "h8h.h" + +h8h_device::h8h_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source, address_map_delegate map_delegate) : + h8_device(mconfig, type, name, tag, owner, clock, shortname, source, false, map_delegate) +{ + supports_advanced = true; + mode_advanced = true; +} + +offs_t h8h_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + return disassemble_generic(buffer, pc, oprom, opram, options, disasm_entries); +} + +#include "cpu/h8/h8h.inc" diff --git a/src/devices/cpu/h8/h8h.h b/src/devices/cpu/h8/h8h.h new file mode 100644 index 00000000000..2fb500b77f8 --- /dev/null +++ b/src/devices/cpu/h8/h8h.h @@ -0,0 +1,109 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +/*************************************************************************** + + h8h.h + + H8-300H base cpu emulation + + Adds 32-bits support and a bunch of other stuff. + + +***************************************************************************/ + +#ifndef __H8H_H__ +#define __H8H_H__ + +#include "h8.h" + +class h8h_device : public h8_device { +public: + h8h_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source, address_map_delegate map_delegate); + +protected: + static const disasm_entry disasm_entries[]; + + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + + virtual void do_exec_full(); + virtual void do_exec_partial(); + + inline void r32_w(int reg, UINT32 val) { R[reg & 7] = val; R[(reg & 7) | 8] = val >> 16; } + inline UINT32 r32_r(int reg) const { return R[reg & 7] | (R[(reg & 7) | 8] << 16); } + +#define O(o) void o ## _full(); void o ## _partial() + + O(add_l_r32h_r32l); O(add_l_imm32_r32l); + O(adds_l_four_r32l); O(adds_l_one_r32l); O(adds_l_two_r32l); + O(and_l_r32h_r32l); O(and_l_imm32_r32l); O(and_w_r16h_r16l); + O(band_imm3_abs32); O(band_imm3_r32ihh); + O(bcc_rel16); + O(bclr_imm3_abs32); O(bclr_imm3_r32ihh); O(bclr_r8h_abs32); O(bclr_r8h_r32ihh); + O(bcs_rel16); + O(beq_rel16); + O(bf_rel16); + O(bge_rel16); + O(bgt_rel16); + O(bhi_rel16); + O(biand_imm3_abs32); O(biand_imm3_r32ihh); + O(bild_imm3_abs32); O(bild_imm3_r32ihh); + O(bior_imm3_abs32); O(bior_imm3_r32ihh); + O(bist_imm3_abs32); O(bist_imm3_r32ihh); + O(bixor_imm3_abs32); O(bixor_imm3_r32ihh); + O(bld_imm3_abs32); O(bld_imm3_r32ihh); + O(ble_rel16); + O(bls_rel16); + O(blt_rel16); + O(bmi_rel16); + O(bne_rel16); + O(bnot_imm3_abs32); O(bnot_imm3_r32ihh); O(bnot_r8h_abs32); O(bnot_r8h_r32ihh); + O(bor_imm3_abs32); O(bor_imm3_r32ihh); + O(bpl_rel16); + O(bset_imm3_abs32); O(bset_imm3_r32ihh); O(bset_r8h_abs32); O(bset_r8h_r32ihh); + O(bsr_rel16); O(bsr_rel8); + O(bst_imm3_abs32); O(bst_imm3_r32ihh); + O(bt_rel16); + O(btst_imm3_abs32); O(btst_imm3_r32ihh); O(btst_r8h_abs32); O(btst_r8h_r32ihh); + O(bvc_rel16); + O(bvs_rel16); + O(bxor_imm3_abs32); O(bxor_imm3_r32ihh); + O(cmp_l_r32h_r32l); O(cmp_l_imm32_r32l); + O(dec_l_one_r32l); O(dec_l_two_r32l); + O(divxs_b_r8h_r16l); O(divxs_w_r16h_r32l); + O(divxu_w_r16h_r32l); + O(eepmov_b); O(eepmov_w); + O(exts_b_r8l); O(exts_l_r32l); O(exts_w_r16l); + O(extu_b_r8l); O(extu_l_r32l); O(extu_w_r16l); + O(inc_l_one_r32l); O(inc_l_two_r32l); O(inc_w_one_r16l); O(inc_w_two_r16l); + O(jmp_abs8i); O(jmp_abs24e); O(jmp_r32h); + O(jsr_abs8i); O(jsr_abs16e); O(jsr_abs24e); O(jsr_r32h); + O(ldc_w_abs16_ccr); O(ldc_w_abs32_ccr); O(ldc_w_r32d16h_ccr); O(ldc_w_r32d32hh_ccr); O(ldc_w_r32ih_ccr); O(ldc_w_r32ph_ccr); + O(mov_b_abs32_r8l); O(mov_b_r32d16h_r8l); O(mov_b_r32d32hh_r8l); O(mov_b_r32ih_r8l); O(mov_b_r32ph_r8l); O(mov_b_r8l_abs32); O(mov_b_r8l_pr32h); O(mov_b_r8l_r32d16h); O(mov_b_r8l_r32d32hh); O(mov_b_r8l_r32ih); + O(mov_l_abs16_r32l); O(mov_l_abs32_r32l); O(mov_l_r32d16h_r32l); O(mov_l_r32d32hh_r32l); O(mov_l_r32h_r32l); O(mov_l_r32ih_r32l); O(mov_l_r32l_abs16); O(mov_l_r32l_abs32); O(mov_l_r32l_pr32h); O(mov_l_r32l_r32d16h); O(mov_l_r32l_r32d32hh); O(mov_l_r32l_r32ih); O(mov_l_r32ph_r32l); + O(mov_w_abs32_r16l); O(mov_l_imm32_r32l); O(mov_w_r16l_abs32); O(mov_w_r16l_pr32h); O(mov_w_r16l_r32d16h); O(mov_w_r16l_r32d32hh); O(mov_w_r16l_r32ih); O(mov_w_r32d16h_r16l); O(mov_w_r32d32hh_r16l); O(mov_w_r32ih_r16l); O(mov_w_r32ph_r16l); + O(mulxs_b_r8h_r16l); O(mulxs_w_r16h_r32l); + O(mulxu_w_r16h_r32l); + O(neg_l_r32l); O(neg_w_r16l); + O(not_l_r32l); O(not_w_r16l); + O(or_l_r32h_r32l); O(or_l_imm32_r32l); O(or_w_r16h_r16l); + O(rotl_l_r32l); O(rotl_w_r16l); + O(rotr_l_r32l); O(rotr_w_r16l); + O(rotxl_l_r32l); O(rotxl_w_r16l); + O(rotxr_l_r32l); O(rotxr_w_r16l); + O(rte); + O(rts); + O(shal_l_r32l); O(shal_w_r16l); + O(shar_l_r32l); O(shar_w_r16l); + O(shll_l_r32l); O(shll_w_r16l); + O(shlr_l_r32l); O(shlr_w_r16l); + O(stc_w_ccr_abs16); O(stc_w_ccr_abs32); O(stc_w_ccr_pr32h); O(stc_w_ccr_r32d16h); O(stc_w_ccr_r32d32hh); O(stc_w_ccr_r32ih); + O(sub_l_r32h_r32l); O(sub_l_imm32_r32l); + O(subs_l_four_r32l); O(subs_l_one_r32l); O(subs_l_two_r32l); + O(trapa_imm2); + O(xor_l_r32h_r32l); O(xor_l_imm32_r32l); O(xor_w_r16h_r16l); + + O(state_irq); +#undef O +}; + +#endif diff --git a/src/devices/cpu/h8/h8make.py b/src/devices/cpu/h8/h8make.py new file mode 100644 index 00000000000..929b5d14c4e --- /dev/null +++ b/src/devices/cpu/h8/h8make.py @@ -0,0 +1,474 @@ +#!/usr/bin/python + +from __future__ import print_function + +USAGE = """ +Usage: +%s h8.lst h8.inc (type = o/h/s20/s26) +""" +import sys + +def name_to_type(name): + if name == "o": + return 0 + if name == "h": + return 1 + if name == "s20": + return 2 + if name == "s26": + return 3 + sys.stderr.write("Unknown chip type name %s\n" % name) + sys.exit(1) + +def type_to_device(dtype): + if dtype == 0: + return "h8_device" + if dtype == 1: + return "h8h_device" + if dtype == 2: + return "h8s2000_device" + return "h8s2600_device" + +def hexsplit(str): + res = [] + for i in range(0, len(str), 2): + res.append(int(str[i:i+2], 16)) + return res + +def has_memory(ins): + for s in ["read", "write", "sp_push", "sp_pop", "sp32_push", "sp32_pop", "fetch(", "prefetch_start(", "prefetch(", "prefetch_noirq("]: + if s in ins: + return True + return False + +def has_eat(ins): + if "eat-all-cycles" in ins: + return True + return False + +def save_full_one(f, t, name, source): + print("void %s::%s_full()" % (t, name), file=f) + print("{", file=f) + substate = 1 + for line in source: + if has_memory(line): + print("\tif(icount <= bcount) { inst_substate = %d; return; }" % substate, file=f) + print(line, file=f) + substate += 1 + elif has_eat(line): + print("\tif(icount) icount = bcount; inst_substate = %d; return;" % substate, file=f) + substate += 1 + else: + print(line, file=f) + print("}", file=f) + print("", file=f) + +def save_partial_one(f, t, name, source): + print("void %s::%s_partial()" % (t, name), file=f) + print("{", file=f) + print("switch(inst_substate) {", file=f) + print("case 0:", file=f) + substate = 1 + for line in source: + if has_memory(line): + print("\tif(icount <= bcount) { inst_substate = %d; return; }" % substate, file=f) + print("case %d:;" % substate, file=f) + print(line, file=f) + substate += 1 + elif has_eat(line): + print("\tif(icount) icount = bcount; inst_substate = %d; return;" % substate, file=f) + print("case %d:;" % substate, file=f) + substate += 1 + else: + print(line, file=f) + print("\tbreak;", file=f) + print("}", file=f) + print("\tinst_substate = 0;", file=f) + print("}", file=f) + print("", file=f) + +class Hash: + def __init__(self, premask): + self.mask = 0x00 + self.enabled = False + self.premask = premask + self.d = {} + + def get(self, val, premask): + if val in self.d: + h = self.d[val] + if h.premask != premask: + sys.stderr.write("Premask conflict\n") + sys.exit(1) + return h + h = Hash(premask) + self.d[val] = h + return h + + def set(self, val, opc): + if val in self.d: + sys.stderr.write("Collision on %s\n" % opc.description()) + sys.exit(1) + self.d[val] = opc + +class Opcode: + def __init__(self, val, mask, skip, name, am1, am2, otype, dtype): + self.name = name + self.val = hexsplit(val) + self.mask = hexsplit(mask) + self.skip = int(skip) + self.am1 = am1 + self.am2 = am2 + self.source = [] + self.otype = otype + self.enabled = otype == -1 or (otype == 0 and dtype == 0) or (otype != 0 and dtype >= otype) + self.needed = self.enabled and (otype == dtype or (otype == -1 and dtype == 0)) + if dtype == 0 and (am1 == "r16l" or am2 == "r16l"): + self.mask[len(self.mask) - 1] |= 0x08 + if dtype == 0 and (am1 == "r16h" or am2 == "r16h"): + self.mask[len(self.mask) - 1] |= 0x80 + extra_words = 0 + if (am1 == "abs16" or am2 == "abs16" or am1 == "abs16e" or am1 == "abs24e") and self.skip == 0: + extra_words += 1 + if (am1 == "abs32" or am2 == "abs32") and self.skip == 0: + extra_words += 2 + if am1 == "imm16" or am1 == "rel16" or am1 == "r16d16h" or am2 == "r16d16h" or am1 == "r32d16h" or am2 == "r32d16h": + extra_words += 1 + if am1 == "imm32" or am1 == "r32d32hh" or am2 == "r32d32hh": + extra_words += 2 + self.extra_words = extra_words + base_offset = len(self.val)/2 + self.skip + for i in range(0, extra_words): + self.source.append("\tfetch(%d);\n" % (i+base_offset)) + + def description(self): + return "%s %s %s" % (self.name, self.am1, self.am2) + + def add_source_line(self, line): + self.source.append(line) + + def is_dispatch(self): + return False + + def function_name(self): + n = self.name.replace(".", "_") + if self.am1 != "-": + n = n + "_" + self.am1 + if self.am2 != "-": + n = n + "_" + self.am2 + return n + + def save_dasm(self, f): + if len(self.mask) == 2: + mask = (self.mask[0] << 8) | self.mask[1] + val = (self.val[0] << 8) | self.val[1] + mask2 = 0 + val2 = 0 + slot = 0 + elif len(self.mask) == 4: + mask = (self.mask[0] << 24) | (self.mask[1] << 16) | (self.mask[2] << 8) | self.mask[3] + val = (self.val[0] << 24) | (self.val[1] << 16) | (self.val[2] << 8) | self.val[3] + mask2 = 0 + val2 = 0 + slot = self.skip + 1 + else: + mask = (self.mask[2] << 24) | (self.mask[3] << 16) | (self.mask[4] << 8) | self.mask[5] + val = (self.val[2] << 24) | (self.val[3] << 16) | (self.val[4] << 8) | self.val[5] + mask2 = (self.mask[0] << 8) | self.mask[1] + val2 = (self.val[0] << 8) | self.val[1] + slot = 4 + + size = len(self.val) + 2*self.skip + 2*self.extra_words + + if self.name == "jsr" or self.name == "bsr": + flags = "%d | DASMFLAG_STEP_OVER" % size + elif self.name == "rts" or self.name == "rte": + flags = "%d | DASMFLAG_STEP_OUT" % size + else: + flags = "%d" % size + + print("\t{ %d, 0x%08x, 0x%08x, 0x%04x, 0x%04x, \"%s\", DASM_%s, DASM_%s, %s }, // %s" % ( slot, val, mask, val2, mask2, self.name, self.am1 if self.am1 != "-" else "none", self.am2 if self.am2 != "-" else "none", flags, "needed" if self.needed else "inherited"), file=f) + +class Special: + def __init__(self, val, name, otype, dtype): + self.name = name + self.val = int(val, 16) + self.enabled = otype == -1 or (otype == 0 and dtype == 0) or (otype != 0 and dtype >= otype) + self.needed = otype == dtype or (otype == -1 and dtype == 0) + self.source = [] + + def add_source_line(self, line): + self.source.append(line) + +class Macro: + def __init__(self, tokens): + self.name = tokens[1] + self.params = [] + for i in range(2, len(tokens)): + self.params.append(tokens[i]) + self.source = [] + + def add_source_line(self, line): + self.source.append(line) + + def apply(self, target, tokens): + values = [] + if len(self.params) > 1: + for i in range(0, len(self.params)-1): + values.append(tokens[i+1]) + lval = "" + for i in range(len(self.params)-1, len(tokens)-1): + if lval != "": + lval += " " + lval = lval + tokens[i+1] + values.append(lval) + for i in range(0, len(self.source)): + line = self.source[i] + for j in range(0, len(self.params)): + line = line.replace(self.params[j], values[j]) + target.add_source_line(line) + +class DispatchStep: + def __init__(self, id, pos, opc): + self.id = id + self.pos = pos + self.name = "" + self.enabled = False + self.mask = opc.mask[pos-1] + for i in range(0, pos): + self.name += "%02x" % opc.val[i] + if pos == 2: + self.skip = opc.skip + else: + self.skip = 0 + + def is_dispatch(self): + return True + + def source(self): + start = self.pos // 2 + end = start + self.skip + s = [] + for i in range(start, end+1): + s.append("\tIR[%d] = fetch();" % i) + s.append("\tinst_state = 0x%x0000 | IR[%d];" % (self.id, end)) + return s + + +class OpcodeList: + def __init__(self, fname, dtype): + self.opcode_info = [] + self.dispatch_info = [] + self.states_info = [] + self.dispatch = {} + self.macros = {} + try: + f = open(fname, "r") + except Exception: + err = sys.exc_info()[1] + sys.stderr.write("Cannot read opcodes file %s [%s]\n" % (fname, err)) + sys.exit(1) + + inf = None + for line in f: + if line.startswith("#"): + continue + line = line.rstrip() + if not line: + continue + if line.startswith(" ") or line.startswith("\t"): + if inf is not None: + # append instruction to last opcode, maybe expand a macro + tokens = line.split() + if tokens[0] in self.macros: + self.macros[tokens[0]].apply(inf, tokens) + else: + inf.add_source_line(line) + else: + # New opcode + tokens = line.split() + if tokens[0] == "macro": + inf = Macro(tokens) + self.macros[inf.name] = inf + elif len(tokens) == 2 or len(tokens) == 3: + if len(tokens) >= 3: + otype = name_to_type(tokens[2]) + else: + otype = -1 + inf = Special(tokens[0], tokens[1], otype, dtype) + self.states_info.append(inf) + else: + if len(tokens) >= 7: + otype = name_to_type(tokens[6]) + else: + otype = -1 + if otype == -1 or dtype == 0 or (otype != 0 and dtype != 0): + inf = Opcode(tokens[0], tokens[1], tokens[2], tokens[3], tokens[4], tokens[5], otype, dtype) + self.opcode_info.append(inf) + else: + inf = None + + def get(self, i): + if i in self.dispatch: + return self.dispatch[i] + h = Hash(0) + self.dispatch[i] = h + return h + + def build_dispatch(self): + for opc in self.opcode_info: + for i in range(0, len(opc.val)): + v = opc.val[i] + if i == 0: + h = self.get(0) + if opc.enabled: + h.mask = h.mask | opc.mask[i] + h.enabled = True + if (i & 1) == 0: + h = h.get(v, opc.mask[i]) + elif i == len(opc.val)-1: + if opc.enabled: + h.set(v, opc) + else: + if v in h.d: + d = h.d[v] + if not d.is_dispatch(): + sys.stderr.write("Collision on %s\n" % opc.description()) + sys.exit(1) + if opc.enabled: + d.enabled = True + h = self.get(d.id) + else: + d = DispatchStep(len(self.dispatch_info)+2, i+1, opc) + self.dispatch_info.append(d) + if opc.enabled: + d.enabled = True + h.set(v, d) + h = self.get(d.id) + + def save_dasm(self, f, dname): + print("const %s::disasm_entry %s::disasm_entries[] = {" % (dname, dname), file=f) + for opc in self.opcode_info: + if opc.enabled: + opc.save_dasm(f) + print("\t{ 0, 0, 0, 0, 0, \"illegal\", 0, 0, 2 },", file=f) + print("};", file=f) + print("", file=f) + + def save_opcodes(self, f, t): + for opc in self.opcode_info: + if opc.needed: + save_full_one(f, t, opc.function_name(), opc.source) + save_partial_one(f, t, opc.function_name(), opc.source) + + for sta in self.states_info: + if sta.needed: + save_full_one(f, t, "state_" + sta.name, sta.source) + save_partial_one(f, t, "state_" + sta.name, sta.source) + + def save_dispatch(self, f, t): + for dsp in self.dispatch_info: + save_full_one(f, t, "dispatch_" + dsp.name, dsp.source()) + save_partial_one(f, t, "dispatch_" + dsp.name, dsp.source()) + + def save_exec(self, f, t, dtype, v): + print("void %s::do_exec_%s()" % (t, v), file=f) + print("{", file=f) + print("\tswitch(inst_state >> 16) {", file=f) + for i in range(0, len(self.dispatch_info)+2): + if i == 1: + print("\tcase 0x01: {", file=f) + print("\t\tswitch(inst_state & 0xffff) {", file=f) + for sta in self.states_info: + if sta.enabled: + print("\t\tcase 0x%02x: state_%s_%s(); break;" % (sta.val & 0xffff, sta.name, v), file=f) + print("\t\t}", file=f) + print("\t\tbreak;", file=f) + print("\t}", file=f) + else: + if i == 0 or self.dispatch_info[i-2].enabled: + print("\tcase 0x%02x: {" % i, file=f) + h = self.get(i) + print("\t\tswitch((inst_state >> 8) & 0x%02x) {" % h.mask, file=f) + for val, h2 in sorted(h.d.items()): + if h2.enabled: + fmask = h2.premask | (h.mask ^ 0xff) + c = "" + s = 0 + while s < 0x100: + c += "case 0x%02x: " % (val | s) + s += 1 + while s & fmask: + s += s & fmask + print("\t\t%s{" % c, file=f) + if h2.mask == 0x00: + n = h2.d[0] + if n.is_dispatch(): + print("\t\t\tdispatch_%s_%s();" % (n.name, v), file=f) + else: + print("\t\t\t%s_%s();" % (n.function_name(), v), file=f) + print("\t\t\tbreak;", file=f) + else: + print("\t\t\tswitch(inst_state & 0x%02x) {" % h2.mask, file=f) + if i == 0: + mpos = 1 + else: + mpos = self.dispatch_info[i-2].pos + 1 + for val2, n in sorted(h2.d.items()): + if n.enabled: + fmask = h2.mask ^ 0xff + if n.is_dispatch(): + fmask = fmask | n.mask + else: + fmask = fmask | n.mask[mpos] + c = "" + s = 0 + while s < 0x100: + c += "case 0x%02x: " % (val2 | s) + s += 1 + while s & fmask: + s += s & fmask + if n.is_dispatch(): + print("\t\t\t%sdispatch_%s_%s(); break;" % (c, n.name, v), file=f) + else: + print("\t\t\t%s%s_%s(); break;" % (c, n.function_name(), v), file=f) + print("\t\t\tdefault: illegal(); break;", file=f) + print("\t\t\t}", file=f) + print("\t\t\tbreak;", file=f) + print("\t\t}", file=f) + print("\t\tdefault: illegal(); break;", file=f) + print("\t\t}", file=f) + print("\t\tbreak;", file=f) + print("\t}", file=f) + print("\t}", file=f) + print("}", file=f) + +def main(argv): + if len(argv) != 4: + print(USAGE % argv[0]) + return 1 + + dtype = name_to_type(argv[2]) + dname = type_to_device(dtype) + opcodes = OpcodeList(argv[1], dtype) + + try: + f = open(argv[3], "w") + except Exception: + err = sys.exc_info()[1] + sys.stderr.write("cannot write file %s [%s]\n" % (argv[3], err)) + sys.exit(1) + + opcodes.build_dispatch() + opcodes.save_dasm(f, dname) + opcodes.save_opcodes(f, dname) + if dtype == 0: + opcodes.save_dispatch(f, dname) + opcodes.save_exec(f, dname, dtype, "full") + opcodes.save_exec(f, dname, dtype, "partial") + f.close() + +# ====================================================================== +if __name__ == "__main__": + sys.exit(main(sys.argv)) + diff --git a/src/devices/cpu/h8/h8s2000.c b/src/devices/cpu/h8/h8s2000.c new file mode 100644 index 00000000000..4686e718666 --- /dev/null +++ b/src/devices/cpu/h8/h8s2000.c @@ -0,0 +1,17 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +#include "emu.h" +#include "h8s2000.h" + +h8s2000_device::h8s2000_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source, address_map_delegate map_delegate) : + h8h_device(mconfig, type, name, tag, owner, clock, shortname, source, map_delegate) +{ + has_exr = true; +} + +offs_t h8s2000_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + return disassemble_generic(buffer, pc, oprom, opram, options, disasm_entries); +} + +#include "cpu/h8/h8s2000.inc" diff --git a/src/devices/cpu/h8/h8s2000.h b/src/devices/cpu/h8/h8s2000.h new file mode 100644 index 00000000000..8b0c7ef1f7f --- /dev/null +++ b/src/devices/cpu/h8/h8s2000.h @@ -0,0 +1,51 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +/*************************************************************************** + + h8s2000.h + + H8S-2000 base cpu emulation + + Adds the exr register, the move multiple instructions, the shifts by + two, tas and optionally the trace mode. + + +***************************************************************************/ + +#ifndef __H8S2000_H__ +#define __H8S2000_H__ + +#include "h8h.h" + +class h8s2000_device : public h8h_device { +public: + h8s2000_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source, address_map_delegate map_delegate); + +protected: + static const disasm_entry disasm_entries[]; + + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + + virtual void do_exec_full(); + virtual void do_exec_partial(); + +#define O(o) void o ## _full(); void o ## _partial() + O(ldc_imm8_exr); O(ldc_r8l_exr); O(ldc_w_abs16_exr); O(ldc_w_abs32_exr); O(ldc_w_r32d16h_exr); O(ldc_w_r32d32hh_exr); O(ldc_w_r32ih_exr); O(ldc_w_r32ph_exr); + O(ldm_l_spp_r32n2l); O(ldm_l_spp_r32n3l); O(ldm_l_spp_r32n4l); + O(rotl_b_two_r8l); O(rotl_l_two_r32l); O(rotl_w_two_r16l); + O(rotr_b_two_r8l); O(rotr_l_two_r32l); O(rotr_w_two_r16l); + O(rotxl_b_two_r8l); O(rotxl_l_two_r32l); O(rotxl_w_two_r16l); + O(rotxr_b_two_r8l); O(rotxr_l_two_r32l); O(rotxr_w_two_r16l); + O(shal_b_two_r8l); O(shal_l_two_r32l); O(shal_w_two_r16l); + O(shar_b_two_r8l); O(shar_l_two_r32l); O(shar_w_two_r16l); + O(shll_b_two_r8l); O(shll_l_two_r32l); O(shll_w_two_r16l); + O(shlr_b_two_r8l); O(shlr_l_two_r32l); O(shlr_w_two_r16l); + O(stc_exr_r8l);O(stc_w_exr_abs16); O(stc_w_exr_abs32); O(stc_w_exr_pr32h); O(stc_w_exr_r32d16h); O(stc_w_exr_r32d32hh); O(stc_w_exr_r32ih); + O(stm_l_r32n2l_psp); O(stm_l_r32n3l_psp); O(stm_l_r32n4l_psp); + O(tas_r32ih); + + O(state_trace); +#undef O +}; + +#endif diff --git a/src/devices/cpu/h8/h8s2245.c b/src/devices/cpu/h8/h8s2245.c new file mode 100644 index 00000000000..ca0e4b54c74 --- /dev/null +++ b/src/devices/cpu/h8/h8s2245.c @@ -0,0 +1,347 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +#include "emu.h" +#include "h8s2245.h" + +const device_type H8S2241 = &device_creator; +const device_type H8S2242 = &device_creator; +const device_type H8S2245 = &device_creator; +const device_type H8S2246 = &device_creator; + + +h8s2245_device::h8s2245_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + h8s2000_device(mconfig, type, name, tag, owner, clock, shortname, source, address_map_delegate(FUNC(h8s2245_device::map), this)), + intc(*this, "intc"), + adc(*this, "adc"), + port1(*this, "port1"), + port2(*this, "port2"), + port3(*this, "port3"), + port4(*this, "port4"), + port5(*this, "port5"), + porta(*this, "porta"), + portb(*this, "portb"), + portc(*this, "portc"), + portd(*this, "portd"), + porte(*this, "porte"), + portf(*this, "portf"), + portg(*this, "portg"), + timer8_0(*this, "timer8_0"), + timer8_1(*this, "timer8_1"), + timer16(*this, "timer16"), + timer16_0(*this, "timer16:0"), + timer16_1(*this, "timer16:1"), + timer16_2(*this, "timer16:2"), + sci0(*this, "sci0"), + sci1(*this, "sci1"), + sci2(*this, "sci2") +{ +} + +h8s2245_device::h8s2245_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + h8s2000_device(mconfig, H8S2245, "H8S/2245", tag, owner, clock, "h8s2245", __FILE__, address_map_delegate(FUNC(h8s2245_device::map), this)), + intc(*this, "intc"), + adc(*this, "adc"), + port1(*this, "port1"), + port2(*this, "port2"), + port3(*this, "port3"), + port4(*this, "port4"), + port5(*this, "port5"), + porta(*this, "porta"), + portb(*this, "portb"), + portc(*this, "portc"), + portd(*this, "portd"), + porte(*this, "porte"), + portf(*this, "portf"), + portg(*this, "portg"), + timer8_0(*this, "timer8_0"), + timer8_1(*this, "timer8_1"), + timer16(*this, "timer16"), + timer16_0(*this, "timer16:0"), + timer16_1(*this, "timer16:1"), + timer16_2(*this, "timer16:2"), + sci0(*this, "sci0"), + sci1(*this, "sci1"), + sci2(*this, "sci2") +{ + ram_start = 0xffec00; +} + +h8s2241_device::h8s2241_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + h8s2245_device(mconfig, H8S2241, "H8S/2241", tag, owner, clock, "h8s2241", __FILE__) +{ + ram_start = 0xffec00; +} + +h8s2242_device::h8s2242_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + h8s2245_device(mconfig, H8S2242, "H8S/2242", tag, owner, clock, "h8s2242", __FILE__) +{ + ram_start = 0xffdc00; +} + +h8s2246_device::h8s2246_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + h8s2245_device(mconfig, H8S2246, "H8S/2246", tag, owner, clock, "h8s2246", __FILE__) +{ + ram_start = 0xffdc00; +} + +static MACHINE_CONFIG_FRAGMENT(h8s2245) + MCFG_H8S_INTC_ADD("intc") + MCFG_H8_ADC_2245_ADD("adc", "intc", 28) + MCFG_H8_PORT_ADD("port1", h8_device::PORT_1, 0x00, 0x00) + MCFG_H8_PORT_ADD("port2", h8_device::PORT_2, 0x00, 0x00) + MCFG_H8_PORT_ADD("port3", h8_device::PORT_3, 0xc0, 0xc0) + MCFG_H8_PORT_ADD("port4", h8_device::PORT_4, 0xf0, 0xf0) + MCFG_H8_PORT_ADD("port5", h8_device::PORT_5, 0xf0, 0xf0) + MCFG_H8_PORT_ADD("porta", h8_device::PORT_A, 0xf0, 0xf0) + MCFG_H8_PORT_ADD("portb", h8_device::PORT_B, 0x00, 0x00) + MCFG_H8_PORT_ADD("portc", h8_device::PORT_C, 0x00, 0x00) + MCFG_H8_PORT_ADD("portd", h8_device::PORT_D, 0x00, 0x00) + MCFG_H8_PORT_ADD("porte", h8_device::PORT_E, 0x00, 0x00) + MCFG_H8_PORT_ADD("portf", h8_device::PORT_F, 0x00, 0x00) + MCFG_H8_PORT_ADD("portg", h8_device::PORT_G, 0xe0, 0x00) + MCFG_H8H_TIMER8_CHANNEL_ADD("timer8_0", "intc", 64, 65, 66, "timer8_1", h8_timer8_channel_device::CHAIN_OVERFLOW, true, false) + MCFG_H8H_TIMER8_CHANNEL_ADD("timer8_1", "intc", 68, 69, 70, "timer8_0", h8_timer8_channel_device::CHAIN_A, false, false) + MCFG_H8_TIMER16_ADD("timer16", 3, 0x00) + MCFG_H8S_TIMER16_CHANNEL_ADD("timer16:0", 4, 0x60, "intc", 32, + h8_timer16_channel_device::DIV_1, + h8_timer16_channel_device::DIV_4, + h8_timer16_channel_device::DIV_16, + h8_timer16_channel_device::DIV_64, + h8_timer16_channel_device::INPUT_A, + h8_timer16_channel_device::INPUT_B, + h8_timer16_channel_device::INPUT_C, + h8_timer16_channel_device::INPUT_D) + MCFG_H8S_TIMER16_CHANNEL_ADD("timer16:1", 2, 0x4c, "intc", 40, + h8_timer16_channel_device::DIV_1, + h8_timer16_channel_device::DIV_4, + h8_timer16_channel_device::DIV_16, + h8_timer16_channel_device::DIV_64, + h8_timer16_channel_device::INPUT_A, + h8_timer16_channel_device::INPUT_B, + h8_timer16_channel_device::DIV_256, + h8_timer16_channel_device::CHAIN) + MCFG_H8S_TIMER16_CHANNEL_SET_CHAIN("timer16:2") + MCFG_H8S_TIMER16_CHANNEL_ADD("timer16:2", 2, 0x4c, "intc", 44, + h8_timer16_channel_device::DIV_1, + h8_timer16_channel_device::DIV_4, + h8_timer16_channel_device::DIV_16, + h8_timer16_channel_device::DIV_64, + h8_timer16_channel_device::INPUT_A, + h8_timer16_channel_device::INPUT_B, + h8_timer16_channel_device::INPUT_C, + h8_timer16_channel_device::DIV_1024) + MCFG_H8_SCI_ADD("sci0", "intc", 80, 81, 82, 83) + MCFG_H8_SCI_ADD("sci1", "intc", 84, 85, 86, 87) + MCFG_H8_SCI_ADD("sci2", "intc", 88, 89, 90, 91) +MACHINE_CONFIG_END + +DEVICE_ADDRESS_MAP_START(map, 16, h8s2245_device) + AM_RANGE(ram_start, 0xfffbff) AM_RAM + + AM_RANGE(0xfffeb0, 0xfffeb1) AM_DEVWRITE8( "port1", h8_port_device, ddr_w, 0xff00) + AM_RANGE(0xfffeb0, 0xfffeb1) AM_DEVWRITE8( "port2", h8_port_device, ddr_w, 0x00ff) + AM_RANGE(0xfffeb2, 0xfffeb3) AM_DEVWRITE8( "port3", h8_port_device, ddr_w, 0xff00) + AM_RANGE(0xfffeb4, 0xfffeb5) AM_DEVWRITE8( "port5", h8_port_device, ddr_w, 0xff00) + AM_RANGE(0xfffeb8, 0xfffeb9) AM_DEVWRITE8( "porta", h8_port_device, ddr_w, 0x00ff) + AM_RANGE(0xfffeba, 0xfffebb) AM_DEVWRITE8( "portb", h8_port_device, ddr_w, 0xff00) + AM_RANGE(0xfffeba, 0xfffebb) AM_DEVWRITE8( "portc", h8_port_device, ddr_w, 0x00ff) + AM_RANGE(0xfffebc, 0xfffebd) AM_DEVWRITE8( "portd", h8_port_device, ddr_w, 0xff00) + AM_RANGE(0xfffebc, 0xfffebd) AM_DEVWRITE8( "porte", h8_port_device, ddr_w, 0x00ff) + AM_RANGE(0xfffebe, 0xfffebf) AM_DEVWRITE8( "portf", h8_port_device, ddr_w, 0xff00) + AM_RANGE(0xfffebe, 0xfffebf) AM_DEVWRITE8( "portg", h8_port_device, ddr_w, 0x00ff) + AM_RANGE(0xfffec0, 0xfffec1) AM_DEVREADWRITE8("intc", h8s_intc_device, icr_r, icr_w, 0xffff) + AM_RANGE(0xfffec2, 0xfffec3) AM_DEVREADWRITE8("intc", h8s_intc_device, icrc_r, icrc_w, 0xff00) + AM_RANGE(0xffff2c, 0xffff2d) AM_DEVREADWRITE8("intc", h8s_intc_device, iscrh_r, iscrh_w, 0xff00) + AM_RANGE(0xffff2c, 0xffff2d) AM_DEVREADWRITE8("intc", h8s_intc_device, iscrl_r, iscrl_w, 0x00ff) + AM_RANGE(0xffff2e, 0xffff2f) AM_DEVREADWRITE8("intc", h8s_intc_device, ier_r, ier_w, 0xff00) + AM_RANGE(0xffff2e, 0xffff2f) AM_DEVREADWRITE8("intc", h8s_intc_device, isr_r, isr_w, 0x00ff) + AM_RANGE(0xffff38, 0xffff39) AM_READWRITE8( syscr_r, syscr_w, 0x00ff) + + AM_RANGE(0xffff50, 0xffff51) AM_DEVREAD8( "port1", h8_port_device, port_r, 0xff00) + AM_RANGE(0xffff50, 0xffff51) AM_DEVREAD8( "port2", h8_port_device, port_r, 0x00ff) + AM_RANGE(0xffff52, 0xffff53) AM_DEVREAD8( "port3", h8_port_device, port_r, 0xff00) + AM_RANGE(0xffff52, 0xffff53) AM_DEVREAD8( "port4", h8_port_device, port_r, 0x00ff) + AM_RANGE(0xffff54, 0xffff55) AM_DEVREAD8( "port5", h8_port_device, port_r, 0xff00) + AM_RANGE(0xffff58, 0xffff59) AM_DEVREAD8( "porta", h8_port_device, port_r, 0x00ff) + AM_RANGE(0xffff5a, 0xffff5b) AM_DEVREAD8( "portb", h8_port_device, port_r, 0xff00) + AM_RANGE(0xffff5a, 0xffff5b) AM_DEVREAD8( "portc", h8_port_device, port_r, 0x00ff) + AM_RANGE(0xffff5c, 0xffff5d) AM_DEVREAD8( "portd", h8_port_device, port_r, 0xff00) + AM_RANGE(0xffff5c, 0xffff5d) AM_DEVREAD8( "porte", h8_port_device, port_r, 0x00ff) + AM_RANGE(0xffff5e, 0xffff5f) AM_DEVREAD8( "portf", h8_port_device, port_r, 0xff00) + AM_RANGE(0xffff5e, 0xffff5f) AM_DEVREAD8( "portg", h8_port_device, port_r, 0x00ff) + AM_RANGE(0xffff60, 0xffff61) AM_DEVREADWRITE8("port1", h8_port_device, dr_r, dr_w, 0xff00) + AM_RANGE(0xffff60, 0xffff61) AM_DEVREADWRITE8("port2", h8_port_device, dr_r, dr_w, 0x00ff) + AM_RANGE(0xffff62, 0xffff63) AM_DEVREADWRITE8("port3", h8_port_device, dr_r, dr_w, 0xff00) + AM_RANGE(0xffff64, 0xffff65) AM_DEVREADWRITE8("port5", h8_port_device, dr_r, dr_w, 0xff00) + AM_RANGE(0xffff68, 0xffff69) AM_DEVREADWRITE8("porta", h8_port_device, dr_r, dr_w, 0x00ff) + AM_RANGE(0xffff6a, 0xffff6b) AM_DEVREADWRITE8("portb", h8_port_device, dr_r, dr_w, 0xff00) + AM_RANGE(0xffff6a, 0xffff6b) AM_DEVREADWRITE8("portc", h8_port_device, dr_r, dr_w, 0x00ff) + AM_RANGE(0xffff6c, 0xffff6d) AM_DEVREADWRITE8("portd", h8_port_device, dr_r, dr_w, 0xff00) + AM_RANGE(0xffff6c, 0xffff6d) AM_DEVREADWRITE8("porte", h8_port_device, dr_r, dr_w, 0x00ff) + AM_RANGE(0xffff6e, 0xffff6f) AM_DEVREADWRITE8("portf", h8_port_device, dr_r, dr_w, 0xff00) + AM_RANGE(0xffff6e, 0xffff6f) AM_DEVREADWRITE8("portg", h8_port_device, dr_r, dr_w, 0x00ff) + AM_RANGE(0xffff70, 0xffff71) AM_DEVREADWRITE8("porta", h8_port_device, pcr_r, pcr_w, 0xff00) + AM_RANGE(0xffff70, 0xffff71) AM_DEVREADWRITE8("portb", h8_port_device, pcr_r, pcr_w, 0x00ff) + AM_RANGE(0xffff72, 0xffff73) AM_DEVREADWRITE8("portc", h8_port_device, pcr_r, pcr_w, 0xff00) + AM_RANGE(0xffff72, 0xffff73) AM_DEVREADWRITE8("portd", h8_port_device, pcr_r, pcr_w, 0x00ff) + AM_RANGE(0xffff74, 0xffff75) AM_DEVREADWRITE8("porte", h8_port_device, pcr_r, pcr_w, 0xff00) + AM_RANGE(0xffff76, 0xffff77) AM_DEVREADWRITE8("port3", h8_port_device, odr_r, odr_w, 0xff00) + AM_RANGE(0xffff76, 0xffff77) AM_DEVREADWRITE8("porta", h8_port_device, odr_r, odr_w, 0x00ff) + AM_RANGE(0xffff78, 0xffff79) AM_DEVREADWRITE8("sci0", h8_sci_device, smr_r, smr_w, 0xff00) + AM_RANGE(0xffff78, 0xffff79) AM_DEVREADWRITE8("sci0", h8_sci_device, brr_r, brr_w, 0x00ff) + AM_RANGE(0xffff7a, 0xffff7b) AM_DEVREADWRITE8("sci0", h8_sci_device, scr_r, scr_w, 0xff00) + AM_RANGE(0xffff7a, 0xffff7b) AM_DEVREADWRITE8("sci0", h8_sci_device, tdr_r, tdr_w, 0x00ff) + AM_RANGE(0xffff7c, 0xffff7d) AM_DEVREADWRITE8("sci0", h8_sci_device, ssr_r, ssr_w, 0xff00) + AM_RANGE(0xffff7c, 0xffff7d) AM_DEVREAD8( "sci0", h8_sci_device, rdr_r, 0x00ff) + AM_RANGE(0xffff7e, 0xffff7f) AM_DEVREADWRITE8("sci0", h8_sci_device, scmr_r, scmr_w, 0xff00) + AM_RANGE(0xffff80, 0xffff81) AM_DEVREADWRITE8("sci1", h8_sci_device, smr_r, smr_w, 0xff00) + AM_RANGE(0xffff80, 0xffff81) AM_DEVREADWRITE8("sci1", h8_sci_device, brr_r, brr_w, 0x00ff) + AM_RANGE(0xffff82, 0xffff83) AM_DEVREADWRITE8("sci1", h8_sci_device, scr_r, scr_w, 0xff00) + AM_RANGE(0xffff82, 0xffff83) AM_DEVREADWRITE8("sci1", h8_sci_device, tdr_r, tdr_w, 0x00ff) + AM_RANGE(0xffff84, 0xffff85) AM_DEVREADWRITE8("sci1", h8_sci_device, ssr_r, ssr_w, 0xff00) + AM_RANGE(0xffff84, 0xffff85) AM_DEVREAD8( "sci1", h8_sci_device, rdr_r, 0x00ff) + AM_RANGE(0xffff86, 0xffff87) AM_DEVREADWRITE8("sci1", h8_sci_device, scmr_r, scmr_w, 0xff00) + AM_RANGE(0xffff88, 0xffff89) AM_DEVREADWRITE8("sci2", h8_sci_device, smr_r, smr_w, 0xff00) + AM_RANGE(0xffff88, 0xffff89) AM_DEVREADWRITE8("sci2", h8_sci_device, brr_r, brr_w, 0x00ff) + AM_RANGE(0xffff8a, 0xffff8b) AM_DEVREADWRITE8("sci2", h8_sci_device, scr_r, scr_w, 0xff00) + AM_RANGE(0xffff8a, 0xffff8b) AM_DEVREADWRITE8("sci2", h8_sci_device, tdr_r, tdr_w, 0x00ff) + AM_RANGE(0xffff8c, 0xffff8d) AM_DEVREADWRITE8("sci2", h8_sci_device, ssr_r, ssr_w, 0xff00) + AM_RANGE(0xffff8c, 0xffff8d) AM_DEVREAD8( "sci2", h8_sci_device, rdr_r, 0x00ff) + AM_RANGE(0xffff8e, 0xffff8f) AM_DEVREADWRITE8("sci2", h8_sci_device, scmr_r, scmr_w, 0xff00) + AM_RANGE(0xffff90, 0xffff97) AM_DEVREAD8( "adc", h8_adc_device, addr8_r, 0xffff) + AM_RANGE(0xffff98, 0xffff99) AM_DEVREADWRITE8("adc", h8_adc_device, adcsr_r, adcsr_w, 0xff00) + AM_RANGE(0xffff98, 0xffff99) AM_DEVREADWRITE8("adc", h8_adc_device, adcr_r, adcr_w, 0x00ff) + AM_RANGE(0xffffb0, 0xffffb1) AM_DEVREADWRITE8("timer8_0", h8_timer8_channel_device, tcr_r, tcr_w, 0xff00) + AM_RANGE(0xffffb0, 0xffffb1) AM_DEVREADWRITE8("timer8_1", h8_timer8_channel_device, tcr_r, tcr_w, 0x00ff) + AM_RANGE(0xffffb2, 0xffffb3) AM_DEVREADWRITE8("timer8_0", h8_timer8_channel_device, tcsr_r, tcsr_w, 0xff00) + AM_RANGE(0xffffb2, 0xffffb3) AM_DEVREADWRITE8("timer8_1", h8_timer8_channel_device, tcsr_r, tcsr_w, 0x00ff) + AM_RANGE(0xffffb4, 0xffffb7) AM_DEVREADWRITE8("timer8_0", h8_timer8_channel_device, tcor_r, tcor_w, 0xff00) + AM_RANGE(0xffffb4, 0xffffb7) AM_DEVREADWRITE8("timer8_1", h8_timer8_channel_device, tcor_r, tcor_w, 0x00ff) + AM_RANGE(0xffffb8, 0xffffb9) AM_DEVREADWRITE8("timer8_0", h8_timer8_channel_device, tcnt_r, tcnt_w, 0xff00) + AM_RANGE(0xffffb8, 0xffffb9) AM_DEVREADWRITE8("timer8_1", h8_timer8_channel_device, tcnt_r, tcnt_w, 0x00ff) + AM_RANGE(0xffffc0, 0xffffc1) AM_DEVREADWRITE8("timer16", h8_timer16_device, tstr_r, tstr_w, 0xff00) + AM_RANGE(0xffffc0, 0xffffc1) AM_DEVREADWRITE8("timer16", h8_timer16_device, tsyr_r, tsyr_w, 0x00ff) + AM_RANGE(0xffffd0, 0xffffd1) AM_DEVREADWRITE8("timer16:0", h8_timer16_channel_device, tcr_r, tcr_w, 0xff00) + AM_RANGE(0xffffd0, 0xffffd1) AM_DEVREADWRITE8("timer16:0", h8_timer16_channel_device, tmdr_r, tmdr_w, 0x00ff) + AM_RANGE(0xffffd2, 0xffffd3) AM_DEVREADWRITE8("timer16:0", h8_timer16_channel_device, tior_r, tior_w, 0xffff) + AM_RANGE(0xffffd4, 0xffffd5) AM_DEVREADWRITE8("timer16:0", h8_timer16_channel_device, tier_r, tier_w, 0xff00) + AM_RANGE(0xffffd4, 0xffffd5) AM_DEVREADWRITE8("timer16:0", h8_timer16_channel_device, tsr_r, tsr_w, 0x00ff) + AM_RANGE(0xffffd6, 0xffffd7) AM_DEVREADWRITE( "timer16:0", h8_timer16_channel_device, tcnt_r, tcnt_w ) + AM_RANGE(0xffffd8, 0xffffdf) AM_DEVREADWRITE( "timer16:0", h8_timer16_channel_device, tgr_r, tgr_w ) + AM_RANGE(0xffffe0, 0xffffe1) AM_DEVREADWRITE8("timer16:1", h8_timer16_channel_device, tcr_r, tcr_w, 0xff00) + AM_RANGE(0xffffe0, 0xffffe1) AM_DEVREADWRITE8("timer16:1", h8_timer16_channel_device, tmdr_r, tmdr_w, 0x00ff) + AM_RANGE(0xffffe2, 0xffffe3) AM_DEVREADWRITE8("timer16:1", h8_timer16_channel_device, tior_r, tior_w, 0xff00) + AM_RANGE(0xffffe4, 0xffffe5) AM_DEVREADWRITE8("timer16:1", h8_timer16_channel_device, tier_r, tier_w, 0xff00) + AM_RANGE(0xffffe4, 0xffffe5) AM_DEVREADWRITE8("timer16:1", h8_timer16_channel_device, tsr_r, tsr_w, 0x00ff) + AM_RANGE(0xffffe6, 0xffffe7) AM_DEVREADWRITE( "timer16:1", h8_timer16_channel_device, tcnt_r, tcnt_w ) + AM_RANGE(0xffffe8, 0xffffeb) AM_DEVREADWRITE( "timer16:1", h8_timer16_channel_device, tgr_r, tgr_w ) + AM_RANGE(0xfffff0, 0xfffff1) AM_DEVREADWRITE8("timer16:2", h8_timer16_channel_device, tcr_r, tcr_w, 0xff00) + AM_RANGE(0xfffff0, 0xfffff1) AM_DEVREADWRITE8("timer16:2", h8_timer16_channel_device, tmdr_r, tmdr_w, 0x00ff) + AM_RANGE(0xfffff2, 0xfffff3) AM_DEVREADWRITE8("timer16:2", h8_timer16_channel_device, tior_r, tior_w, 0xff00) + AM_RANGE(0xfffff4, 0xfffff5) AM_DEVREADWRITE8("timer16:2", h8_timer16_channel_device, tier_r, tier_w, 0xff00) + AM_RANGE(0xfffff4, 0xfffff5) AM_DEVREADWRITE8("timer16:2", h8_timer16_channel_device, tsr_r, tsr_w, 0x00ff) + AM_RANGE(0xfffff6, 0xfffff7) AM_DEVREADWRITE( "timer16:2", h8_timer16_channel_device, tcnt_r, tcnt_w ) + AM_RANGE(0xfffff8, 0xfffffb) AM_DEVREADWRITE( "timer16:2", h8_timer16_channel_device, tgr_r, tgr_w ) + +ADDRESS_MAP_END + +machine_config_constructor h8s2245_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME(h8s2245); +} + +void h8s2245_device::execute_set_input(int inputnum, int state) +{ + intc->set_input(inputnum, state); +} + +bool h8s2245_device::exr_in_stack() const +{ + return false; +} + +int h8s2245_device::trapa_setup() +{ + if(syscr & 0x10) + CCR |= F_I|F_UI; + else + CCR |= F_I; + return 8; +} + +void h8s2245_device::irq_setup() +{ + switch(syscr & 0x30) { + case 0x00: + CCR |= F_I; + break; + case 0x10: + CCR |= F_I|F_UI; + break; + } +} + +void h8s2245_device::update_irq_filter() +{ + switch(syscr & 0x30) { + case 0x00: + if(CCR & F_I) + intc->set_filter(2, -1); + else + intc->set_filter(0, -1); + break; + case 0x10: + if((CCR & (F_I|F_UI)) == (F_I|F_UI)) + intc->set_filter(2, -1); + else if(CCR & F_I) + intc->set_filter(1, -1); + else + intc->set_filter(0, -1); + break; + } +} + +void h8s2245_device::interrupt_taken() +{ + standard_irq_callback(intc->interrupt_taken(taken_irq_vector)); +} + +void h8s2245_device::internal_update(UINT64 current_time) +{ + UINT64 event_time = 0; + + add_event(event_time, adc->internal_update(current_time)); + add_event(event_time, sci0->internal_update(current_time)); + add_event(event_time, sci1->internal_update(current_time)); + add_event(event_time, sci2->internal_update(current_time)); + add_event(event_time, timer8_0->internal_update(current_time)); + add_event(event_time, timer8_1->internal_update(current_time)); + add_event(event_time, timer16_0->internal_update(current_time)); + add_event(event_time, timer16_1->internal_update(current_time)); + add_event(event_time, timer16_2->internal_update(current_time)); + + recompute_bcount(event_time); +} + +void h8s2245_device::device_start() +{ + h8s2000_device::device_start(); +} + +void h8s2245_device::device_reset() +{ + h8s2000_device::device_reset(); + syscr = 0x01; +} + +READ8_MEMBER(h8s2245_device::syscr_r) +{ + return syscr; +} + +WRITE8_MEMBER(h8s2245_device::syscr_w) +{ + syscr = data; + update_irq_filter(); + logerror("%s: syscr = %02x\n", tag(), data); +} diff --git a/src/devices/cpu/h8/h8s2245.h b/src/devices/cpu/h8/h8s2245.h new file mode 100644 index 00000000000..257c1d0f35a --- /dev/null +++ b/src/devices/cpu/h8/h8s2245.h @@ -0,0 +1,102 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +/*************************************************************************** + + h8s2245.h + + H8S-2245 family emulation + + H8S/2000-based mcus. + + Variant ROM RAM + H8S/2241 32K 4K + H8S/2242 32K 8K + H8S/2245 128K 4K + H8S/2246 128K 8K + + + +***************************************************************************/ + +#ifndef __H8S2245_H__ +#define __H8S2245_H__ + +#include "h8s2000.h" +#include "h8_adc.h" +#include "h8_port.h" +#include "h8_intc.h" +#include "h8_sci.h" +#include "h8_timer8.h" +#include "h8_timer16.h" + +class h8s2245_device : public h8s2000_device { +public: + h8s2245_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + h8s2245_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + DECLARE_READ8_MEMBER(syscr_r); + DECLARE_WRITE8_MEMBER(syscr_w); + +protected: + required_device intc; + required_device adc; + required_device port1; + required_device port2; + required_device port3; + required_device port4; + required_device port5; + required_device porta; + required_device portb; + required_device portc; + required_device portd; + required_device porte; + required_device portf; + required_device portg; + required_device timer8_0; + required_device timer8_1; + required_device timer16; + required_device timer16_0; + required_device timer16_1; + required_device timer16_2; + required_device sci0; + required_device sci1; + required_device sci2; + + UINT32 ram_start; + UINT8 syscr; + + virtual bool exr_in_stack() const; + virtual void update_irq_filter(); + virtual void interrupt_taken(); + virtual int trapa_setup(); + virtual void irq_setup(); + virtual void internal_update(UINT64 current_time); + virtual machine_config_constructor device_mconfig_additions() const; + DECLARE_ADDRESS_MAP(map, 16); + + virtual void device_start(); + virtual void device_reset(); + virtual void execute_set_input(int inputnum, int state); +}; + +class h8s2241_device : public h8s2245_device { +public: + h8s2241_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class h8s2242_device : public h8s2245_device { +public: + h8s2242_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class h8s2246_device : public h8s2245_device { +public: + h8s2246_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +extern const device_type H8S2241; +extern const device_type H8S2242; +extern const device_type H8S2245; +extern const device_type H8S2246; + +#endif diff --git a/src/devices/cpu/h8/h8s2320.c b/src/devices/cpu/h8/h8s2320.c new file mode 100644 index 00000000000..d168ade1060 --- /dev/null +++ b/src/devices/cpu/h8/h8s2320.c @@ -0,0 +1,456 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +#include "emu.h" +#include "h8s2320.h" + +const device_type H8S2320 = &device_creator; +const device_type H8S2321 = &device_creator; +const device_type H8S2322 = &device_creator; +const device_type H8S2323 = &device_creator; +const device_type H8S2324 = &device_creator; +const device_type H8S2326 = &device_creator; +const device_type H8S2327 = &device_creator; +const device_type H8S2328 = &device_creator; +const device_type H8S2329 = &device_creator; + + +h8s2320_device::h8s2320_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + h8s2000_device(mconfig, type, name, tag, owner, clock, shortname, source, address_map_delegate(FUNC(h8s2320_device::map), this)), + intc(*this, "intc"), + adc(*this, "adc"), + port1(*this, "port1"), + port2(*this, "port2"), + port3(*this, "port3"), + port4(*this, "port4"), + port5(*this, "port5"), + port6(*this, "port6"), + porta(*this, "porta"), + portb(*this, "portb"), + portc(*this, "portc"), + portd(*this, "portd"), + porte(*this, "porte"), + portf(*this, "portf"), + portg(*this, "portg"), + timer8_0(*this, "timer8_0"), + timer8_1(*this, "timer8_1"), + timer16(*this, "timer16"), + timer16_0(*this, "timer16:0"), + timer16_1(*this, "timer16:1"), + timer16_2(*this, "timer16:2"), + timer16_3(*this, "timer16:3"), + timer16_4(*this, "timer16:4"), + timer16_5(*this, "timer16:5"), + sci0(*this, "sci0"), + sci1(*this, "sci1"), + sci2(*this, "sci2") +{ +} + +h8s2320_device::h8s2320_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + h8s2000_device(mconfig, H8S2320, "H8S/2320", tag, owner, clock, "h8s2320", __FILE__, address_map_delegate(FUNC(h8s2320_device::map), this)), + intc(*this, "intc"), + adc(*this, "adc"), + port1(*this, "port1"), + port2(*this, "port2"), + port3(*this, "port3"), + port4(*this, "port4"), + port5(*this, "port5"), + port6(*this, "port6"), + porta(*this, "porta"), + portb(*this, "portb"), + portc(*this, "portc"), + portd(*this, "portd"), + porte(*this, "porte"), + portf(*this, "portf"), + portg(*this, "portg"), + timer8_0(*this, "timer8_0"), + timer8_1(*this, "timer8_1"), + timer16(*this, "timer16"), + timer16_0(*this, "timer16:0"), + timer16_1(*this, "timer16:1"), + timer16_2(*this, "timer16:2"), + timer16_3(*this, "timer16:3"), + timer16_4(*this, "timer16:4"), + timer16_5(*this, "timer16:5"), + sci0(*this, "sci0"), + sci1(*this, "sci1"), + sci2(*this, "sci2") +{ + ram_start = 0xffec00; +} + +h8s2321_device::h8s2321_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + h8s2320_device(mconfig, H8S2321, "H8S/2321", tag, owner, clock, "h8s2321", __FILE__) +{ + ram_start = 0xffec00; +} + +h8s2322_device::h8s2322_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + h8s2320_device(mconfig, H8S2322, "H8S/2322", tag, owner, clock, "h8s2322", __FILE__) +{ + ram_start = 0xffdc00; +} + +h8s2323_device::h8s2323_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + h8s2320_device(mconfig, H8S2323, "H8S/2323", tag, owner, clock, "h8s2323", __FILE__) +{ + ram_start = 0xffdc00; +} + +h8s2324_device::h8s2324_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + h8s2320_device(mconfig, H8S2324, "H8S/2324", tag, owner, clock, "h8s2324", __FILE__) +{ + ram_start = 0xff7c00; +} + +h8s2326_device::h8s2326_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + h8s2320_device(mconfig, H8S2326, "H8S/2326", tag, owner, clock, "h8s2326", __FILE__) +{ + ram_start = 0xffdc00; +} + +h8s2327_device::h8s2327_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + h8s2320_device(mconfig, H8S2327, "H8S/2327", tag, owner, clock, "h8s2327", __FILE__) +{ + ram_start = 0xffdc00; +} + +h8s2328_device::h8s2328_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + h8s2320_device(mconfig, H8S2328, "H8S/2328", tag, owner, clock, "h8s2328", __FILE__) +{ + ram_start = 0xffdc00; +} + +h8s2329_device::h8s2329_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + h8s2320_device(mconfig, H8S2329, "H8S/2329", tag, owner, clock, "h8s2329", __FILE__) +{ + ram_start = 0xff7c00; +} + +static MACHINE_CONFIG_FRAGMENT(h8s2320) + MCFG_H8S_INTC_ADD("intc") + MCFG_H8_ADC_2320_ADD("adc", "intc", 28) + MCFG_H8_PORT_ADD("port1", h8_device::PORT_1, 0x00, 0x00) + MCFG_H8_PORT_ADD("port2", h8_device::PORT_2, 0x00, 0x00) + MCFG_H8_PORT_ADD("port3", h8_device::PORT_3, 0xc0, 0xc0) + MCFG_H8_PORT_ADD("port4", h8_device::PORT_4, 0x00, 0x00) + MCFG_H8_PORT_ADD("port5", h8_device::PORT_5, 0xf0, 0xf0) + MCFG_H8_PORT_ADD("port6", h8_device::PORT_6, 0x00, 0x00) + MCFG_H8_PORT_ADD("porta", h8_device::PORT_A, 0x00, 0x00) + MCFG_H8_PORT_ADD("portb", h8_device::PORT_B, 0x00, 0x00) + MCFG_H8_PORT_ADD("portc", h8_device::PORT_C, 0x00, 0x00) + MCFG_H8_PORT_ADD("portd", h8_device::PORT_D, 0x00, 0x00) + MCFG_H8_PORT_ADD("porte", h8_device::PORT_E, 0x00, 0x00) + MCFG_H8_PORT_ADD("portf", h8_device::PORT_F, 0x00, 0x00) + MCFG_H8_PORT_ADD("portg", h8_device::PORT_G, 0xe0, 0xe0) + MCFG_H8H_TIMER8_CHANNEL_ADD("timer8_0", "intc", 64, 65, 66, "timer8_1", h8_timer8_channel_device::CHAIN_OVERFLOW, true, false) + MCFG_H8H_TIMER8_CHANNEL_ADD("timer8_1", "intc", 68, 69, 70, "timer8_0", h8_timer8_channel_device::CHAIN_A, false, false) + MCFG_H8_TIMER16_ADD("timer16", 6, 0x00) + MCFG_H8S_TIMER16_CHANNEL_ADD("timer16:0", 4, 0x60, "intc", 32, + h8_timer16_channel_device::DIV_1, + h8_timer16_channel_device::DIV_4, + h8_timer16_channel_device::DIV_16, + h8_timer16_channel_device::DIV_64, + h8_timer16_channel_device::INPUT_A, + h8_timer16_channel_device::INPUT_B, + h8_timer16_channel_device::INPUT_C, + h8_timer16_channel_device::INPUT_D) + MCFG_H8S_TIMER16_CHANNEL_ADD("timer16:1", 2, 0x4c, "intc", 40, + h8_timer16_channel_device::DIV_1, + h8_timer16_channel_device::DIV_4, + h8_timer16_channel_device::DIV_16, + h8_timer16_channel_device::DIV_64, + h8_timer16_channel_device::INPUT_A, + h8_timer16_channel_device::INPUT_B, + h8_timer16_channel_device::DIV_256, + h8_timer16_channel_device::CHAIN) + MCFG_H8S_TIMER16_CHANNEL_SET_CHAIN("timer16:2") + MCFG_H8S_TIMER16_CHANNEL_ADD("timer16:2", 2, 0x4c, "intc", 44, + h8_timer16_channel_device::DIV_1, + h8_timer16_channel_device::DIV_4, + h8_timer16_channel_device::DIV_16, + h8_timer16_channel_device::DIV_64, + h8_timer16_channel_device::INPUT_A, + h8_timer16_channel_device::INPUT_B, + h8_timer16_channel_device::INPUT_C, + h8_timer16_channel_device::DIV_1024) + MCFG_H8S_TIMER16_CHANNEL_ADD("timer16:3", 4, 0x60, "intc", 48, + h8_timer16_channel_device::DIV_1, + h8_timer16_channel_device::DIV_4, + h8_timer16_channel_device::DIV_16, + h8_timer16_channel_device::DIV_64, + h8_timer16_channel_device::INPUT_A, + h8_timer16_channel_device::DIV_1024, + h8_timer16_channel_device::DIV_256, + h8_timer16_channel_device::DIV_4096) + MCFG_H8S_TIMER16_CHANNEL_ADD("timer16:4", 2, 0x4c, "intc", 56, + h8_timer16_channel_device::DIV_1, + h8_timer16_channel_device::DIV_4, + h8_timer16_channel_device::DIV_16, + h8_timer16_channel_device::DIV_64, + h8_timer16_channel_device::INPUT_A, + h8_timer16_channel_device::INPUT_C, + h8_timer16_channel_device::DIV_1024, + h8_timer16_channel_device::CHAIN) + MCFG_H8S_TIMER16_CHANNEL_SET_CHAIN("timer16:5") + MCFG_H8S_TIMER16_CHANNEL_ADD("timer16:5", 2, 0x4c, "intc", 60, + h8_timer16_channel_device::DIV_1, + h8_timer16_channel_device::DIV_4, + h8_timer16_channel_device::DIV_16, + h8_timer16_channel_device::DIV_64, + h8_timer16_channel_device::INPUT_A, + h8_timer16_channel_device::INPUT_C, + h8_timer16_channel_device::DIV_256, + h8_timer16_channel_device::INPUT_D) + MCFG_H8_SCI_ADD("sci0", "intc", 80, 81, 82, 83) + MCFG_H8_SCI_ADD("sci1", "intc", 84, 85, 86, 87) + MCFG_H8_SCI_ADD("sci2", "intc", 88, 89, 90, 91) +MACHINE_CONFIG_END + +DEVICE_ADDRESS_MAP_START(map, 16, h8s2320_device) + AM_RANGE(ram_start, 0xfffbff) AM_RAM + + AM_RANGE(0xfffe80, 0xfffe81) AM_DEVREADWRITE8("timer16:3", h8_timer16_channel_device, tcr_r, tcr_w, 0xff00) + AM_RANGE(0xfffe80, 0xfffe81) AM_DEVREADWRITE8("timer16:3", h8_timer16_channel_device, tmdr_r, tmdr_w, 0x00ff) + AM_RANGE(0xfffe82, 0xfffe83) AM_DEVREADWRITE8("timer16:3", h8_timer16_channel_device, tior_r, tior_w, 0xffff) + AM_RANGE(0xfffe84, 0xfffe85) AM_DEVREADWRITE8("timer16:3", h8_timer16_channel_device, tier_r, tier_w, 0xff00) + AM_RANGE(0xfffe84, 0xfffe85) AM_DEVREADWRITE8("timer16:3", h8_timer16_channel_device, tsr_r, tsr_w, 0x00ff) + AM_RANGE(0xfffe86, 0xfffe87) AM_DEVREADWRITE( "timer16:3", h8_timer16_channel_device, tcnt_r, tcnt_w ) + AM_RANGE(0xfffe88, 0xfffe8f) AM_DEVREADWRITE( "timer16:3", h8_timer16_channel_device, tgr_r, tgr_w ) + AM_RANGE(0xfffe90, 0xfffe91) AM_DEVREADWRITE8("timer16:4", h8_timer16_channel_device, tcr_r, tcr_w, 0xff00) + AM_RANGE(0xfffe90, 0xfffe91) AM_DEVREADWRITE8("timer16:4", h8_timer16_channel_device, tmdr_r, tmdr_w, 0x00ff) + AM_RANGE(0xfffe92, 0xfffe93) AM_DEVREADWRITE8("timer16:4", h8_timer16_channel_device, tior_r, tior_w, 0xff00) + AM_RANGE(0xfffe94, 0xfffe95) AM_DEVREADWRITE8("timer16:4", h8_timer16_channel_device, tier_r, tier_w, 0xff00) + AM_RANGE(0xfffe94, 0xfffe95) AM_DEVREADWRITE8("timer16:4", h8_timer16_channel_device, tsr_r, tsr_w, 0x00ff) + AM_RANGE(0xfffe96, 0xfffe97) AM_DEVREADWRITE( "timer16:4", h8_timer16_channel_device, tcnt_r, tcnt_w ) + AM_RANGE(0xfffe98, 0xfffe9b) AM_DEVREADWRITE( "timer16:4", h8_timer16_channel_device, tgr_r, tgr_w ) + AM_RANGE(0xfffea0, 0xfffea1) AM_DEVREADWRITE8("timer16:5", h8_timer16_channel_device, tcr_r, tcr_w, 0xff00) + AM_RANGE(0xfffea0, 0xfffea1) AM_DEVREADWRITE8("timer16:5", h8_timer16_channel_device, tmdr_r, tmdr_w, 0x00ff) + AM_RANGE(0xfffea2, 0xfffea3) AM_DEVREADWRITE8("timer16:5", h8_timer16_channel_device, tior_r, tior_w, 0xff00) + AM_RANGE(0xfffea4, 0xfffea5) AM_DEVREADWRITE8("timer16:5", h8_timer16_channel_device, tier_r, tier_w, 0xff00) + AM_RANGE(0xfffea4, 0xfffea5) AM_DEVREADWRITE8("timer16:5", h8_timer16_channel_device, tsr_r, tsr_w, 0x00ff) + AM_RANGE(0xfffea6, 0xfffea7) AM_DEVREADWRITE( "timer16:5", h8_timer16_channel_device, tcnt_r, tcnt_w ) + AM_RANGE(0xfffea8, 0xfffeab) AM_DEVREADWRITE( "timer16:5", h8_timer16_channel_device, tgr_r, tgr_w ) + AM_RANGE(0xfffeb0, 0xfffeb1) AM_DEVWRITE8( "port1", h8_port_device, ddr_w, 0xff00) + AM_RANGE(0xfffeb0, 0xfffeb1) AM_DEVWRITE8( "port2", h8_port_device, ddr_w, 0x00ff) + AM_RANGE(0xfffeb2, 0xfffeb3) AM_DEVWRITE8( "port3", h8_port_device, ddr_w, 0xff00) + AM_RANGE(0xfffeb4, 0xfffeb5) AM_DEVWRITE8( "port5", h8_port_device, ddr_w, 0xff00) + AM_RANGE(0xfffeb4, 0xfffeb5) AM_DEVWRITE8( "port6", h8_port_device, ddr_w, 0x00ff) + AM_RANGE(0xfffeb8, 0xfffeb9) AM_DEVWRITE8( "porta", h8_port_device, ddr_w, 0x00ff) + AM_RANGE(0xfffeba, 0xfffebb) AM_DEVWRITE8( "portb", h8_port_device, ddr_w, 0xff00) + AM_RANGE(0xfffeba, 0xfffebb) AM_DEVWRITE8( "portc", h8_port_device, ddr_w, 0x00ff) + AM_RANGE(0xfffebc, 0xfffebd) AM_DEVWRITE8( "portd", h8_port_device, ddr_w, 0xff00) + AM_RANGE(0xfffebc, 0xfffebd) AM_DEVWRITE8( "porte", h8_port_device, ddr_w, 0x00ff) + AM_RANGE(0xfffebe, 0xfffebf) AM_DEVWRITE8( "portf", h8_port_device, ddr_w, 0xff00) + AM_RANGE(0xfffebe, 0xfffebf) AM_DEVWRITE8( "portg", h8_port_device, ddr_w, 0x00ff) + AM_RANGE(0xfffec0, 0xfffec1) AM_DEVREADWRITE8("intc", h8s_intc_device, icr_r, icr_w, 0xffff) + AM_RANGE(0xfffec2, 0xfffec3) AM_DEVREADWRITE8("intc", h8s_intc_device, icrc_r, icrc_w, 0xff00) + AM_RANGE(0xfffec4, 0xfffecd) AM_DEVREADWRITE8("intc", h8s_intc_device, ipr_r, ipr_w, 0xffff) + AM_RANGE(0xfffece, 0xfffecf) AM_DEVREADWRITE8("intc", h8s_intc_device, iprk_r, iprk_w, 0xff00) + AM_RANGE(0xffff2c, 0xffff2d) AM_DEVREADWRITE8("intc", h8s_intc_device, iscrh_r, iscrh_w, 0xff00) + AM_RANGE(0xffff2c, 0xffff2d) AM_DEVREADWRITE8("intc", h8s_intc_device, iscrl_r, iscrl_w, 0x00ff) + AM_RANGE(0xffff2e, 0xffff2f) AM_DEVREADWRITE8("intc", h8s_intc_device, ier_r, ier_w, 0xff00) + AM_RANGE(0xffff2e, 0xffff2f) AM_DEVREADWRITE8("intc", h8s_intc_device, isr_r, isr_w, 0x00ff) + AM_RANGE(0xffff38, 0xffff39) AM_READWRITE8( syscr_r, syscr_w, 0x00ff) + + AM_RANGE(0xffff50, 0xffff51) AM_DEVREAD8( "port1", h8_port_device, port_r, 0xff00) + AM_RANGE(0xffff50, 0xffff51) AM_DEVREAD8( "port2", h8_port_device, port_r, 0x00ff) + AM_RANGE(0xffff52, 0xffff53) AM_DEVREAD8( "port3", h8_port_device, port_r, 0xff00) + AM_RANGE(0xffff52, 0xffff53) AM_DEVREAD8( "port4", h8_port_device, port_r, 0x00ff) + AM_RANGE(0xffff54, 0xffff55) AM_DEVREAD8( "port5", h8_port_device, port_r, 0xff00) + AM_RANGE(0xffff54, 0xffff55) AM_DEVREAD8( "port6", h8_port_device, port_r, 0x00ff) + AM_RANGE(0xffff58, 0xffff59) AM_DEVREAD8( "porta", h8_port_device, port_r, 0x00ff) + AM_RANGE(0xffff5a, 0xffff5b) AM_DEVREAD8( "portb", h8_port_device, port_r, 0xff00) + AM_RANGE(0xffff5a, 0xffff5b) AM_DEVREAD8( "portc", h8_port_device, port_r, 0x00ff) + AM_RANGE(0xffff5c, 0xffff5d) AM_DEVREAD8( "portd", h8_port_device, port_r, 0xff00) + AM_RANGE(0xffff5c, 0xffff5d) AM_DEVREAD8( "porte", h8_port_device, port_r, 0x00ff) + AM_RANGE(0xffff5e, 0xffff5f) AM_DEVREAD8( "portf", h8_port_device, port_r, 0xff00) + AM_RANGE(0xffff5e, 0xffff5f) AM_DEVREAD8( "portg", h8_port_device, port_r, 0x00ff) + AM_RANGE(0xffff60, 0xffff61) AM_DEVREADWRITE8("port1", h8_port_device, dr_r, dr_w, 0xff00) + AM_RANGE(0xffff60, 0xffff61) AM_DEVREADWRITE8("port2", h8_port_device, dr_r, dr_w, 0x00ff) + AM_RANGE(0xffff62, 0xffff63) AM_DEVREADWRITE8("port3", h8_port_device, dr_r, dr_w, 0xff00) + AM_RANGE(0xffff64, 0xffff65) AM_DEVREADWRITE8("port5", h8_port_device, dr_r, dr_w, 0xff00) + AM_RANGE(0xffff64, 0xffff65) AM_DEVREADWRITE8("port6", h8_port_device, dr_r, dr_w, 0x00ff) + AM_RANGE(0xffff68, 0xffff69) AM_DEVREADWRITE8("porta", h8_port_device, dr_r, dr_w, 0x00ff) + AM_RANGE(0xffff6a, 0xffff6b) AM_DEVREADWRITE8("portb", h8_port_device, dr_r, dr_w, 0xff00) + AM_RANGE(0xffff6a, 0xffff6b) AM_DEVREADWRITE8("portc", h8_port_device, dr_r, dr_w, 0x00ff) + AM_RANGE(0xffff6c, 0xffff6d) AM_DEVREADWRITE8("portd", h8_port_device, dr_r, dr_w, 0xff00) + AM_RANGE(0xffff6c, 0xffff6d) AM_DEVREADWRITE8("porte", h8_port_device, dr_r, dr_w, 0x00ff) + AM_RANGE(0xffff6e, 0xffff6f) AM_DEVREADWRITE8("portf", h8_port_device, dr_r, dr_w, 0xff00) + AM_RANGE(0xffff6e, 0xffff6f) AM_DEVREADWRITE8("portg", h8_port_device, dr_r, dr_w, 0x00ff) + AM_RANGE(0xffff70, 0xffff71) AM_DEVREADWRITE8("porta", h8_port_device, pcr_r, pcr_w, 0xff00) + AM_RANGE(0xffff70, 0xffff71) AM_DEVREADWRITE8("portb", h8_port_device, pcr_r, pcr_w, 0x00ff) + AM_RANGE(0xffff72, 0xffff73) AM_DEVREADWRITE8("portc", h8_port_device, pcr_r, pcr_w, 0xff00) + AM_RANGE(0xffff72, 0xffff73) AM_DEVREADWRITE8("portd", h8_port_device, pcr_r, pcr_w, 0x00ff) + AM_RANGE(0xffff74, 0xffff75) AM_DEVREADWRITE8("porte", h8_port_device, pcr_r, pcr_w, 0xff00) + AM_RANGE(0xffff76, 0xffff77) AM_DEVREADWRITE8("port3", h8_port_device, odr_r, odr_w, 0xff00) + AM_RANGE(0xffff76, 0xffff77) AM_DEVREADWRITE8("porta", h8_port_device, odr_r, odr_w, 0x00ff) + AM_RANGE(0xffff78, 0xffff79) AM_DEVREADWRITE8("sci0", h8_sci_device, smr_r, smr_w, 0xff00) + AM_RANGE(0xffff78, 0xffff79) AM_DEVREADWRITE8("sci0", h8_sci_device, brr_r, brr_w, 0x00ff) + AM_RANGE(0xffff7a, 0xffff7b) AM_DEVREADWRITE8("sci0", h8_sci_device, scr_r, scr_w, 0xff00) + AM_RANGE(0xffff7a, 0xffff7b) AM_DEVREADWRITE8("sci0", h8_sci_device, tdr_r, tdr_w, 0x00ff) + AM_RANGE(0xffff7c, 0xffff7d) AM_DEVREADWRITE8("sci0", h8_sci_device, ssr_r, ssr_w, 0xff00) + AM_RANGE(0xffff7c, 0xffff7d) AM_DEVREAD8( "sci0", h8_sci_device, rdr_r, 0x00ff) + AM_RANGE(0xffff7e, 0xffff7f) AM_DEVREADWRITE8("sci0", h8_sci_device, scmr_r, scmr_w, 0xff00) + AM_RANGE(0xffff80, 0xffff81) AM_DEVREADWRITE8("sci1", h8_sci_device, smr_r, smr_w, 0xff00) + AM_RANGE(0xffff80, 0xffff81) AM_DEVREADWRITE8("sci1", h8_sci_device, brr_r, brr_w, 0x00ff) + AM_RANGE(0xffff82, 0xffff83) AM_DEVREADWRITE8("sci1", h8_sci_device, scr_r, scr_w, 0xff00) + AM_RANGE(0xffff82, 0xffff83) AM_DEVREADWRITE8("sci1", h8_sci_device, tdr_r, tdr_w, 0x00ff) + AM_RANGE(0xffff84, 0xffff85) AM_DEVREADWRITE8("sci1", h8_sci_device, ssr_r, ssr_w, 0xff00) + AM_RANGE(0xffff84, 0xffff85) AM_DEVREAD8( "sci1", h8_sci_device, rdr_r, 0x00ff) + AM_RANGE(0xffff86, 0xffff87) AM_DEVREADWRITE8("sci1", h8_sci_device, scmr_r, scmr_w, 0xff00) + AM_RANGE(0xffff88, 0xffff89) AM_DEVREADWRITE8("sci2", h8_sci_device, smr_r, smr_w, 0xff00) + AM_RANGE(0xffff88, 0xffff89) AM_DEVREADWRITE8("sci2", h8_sci_device, brr_r, brr_w, 0x00ff) + AM_RANGE(0xffff8a, 0xffff8b) AM_DEVREADWRITE8("sci2", h8_sci_device, scr_r, scr_w, 0xff00) + AM_RANGE(0xffff8a, 0xffff8b) AM_DEVREADWRITE8("sci2", h8_sci_device, tdr_r, tdr_w, 0x00ff) + AM_RANGE(0xffff8c, 0xffff8d) AM_DEVREADWRITE8("sci2", h8_sci_device, ssr_r, ssr_w, 0xff00) + AM_RANGE(0xffff8c, 0xffff8d) AM_DEVREAD8( "sci2", h8_sci_device, rdr_r, 0x00ff) + AM_RANGE(0xffff8e, 0xffff8f) AM_DEVREADWRITE8("sci2", h8_sci_device, scmr_r, scmr_w, 0xff00) + AM_RANGE(0xffff90, 0xffff97) AM_DEVREAD8( "adc", h8_adc_device, addr8_r, 0xffff) + AM_RANGE(0xffff98, 0xffff99) AM_DEVREADWRITE8("adc", h8_adc_device, adcsr_r, adcsr_w, 0xff00) + AM_RANGE(0xffff98, 0xffff99) AM_DEVREADWRITE8("adc", h8_adc_device, adcr_r, adcr_w, 0x00ff) + + AM_RANGE(0xffffb0, 0xffffb1) AM_DEVREADWRITE8("timer8_0", h8_timer8_channel_device, tcr_r, tcr_w, 0xff00) + AM_RANGE(0xffffb0, 0xffffb1) AM_DEVREADWRITE8("timer8_1", h8_timer8_channel_device, tcr_r, tcr_w, 0x00ff) + AM_RANGE(0xffffb2, 0xffffb3) AM_DEVREADWRITE8("timer8_0", h8_timer8_channel_device, tcsr_r, tcsr_w, 0xff00) + AM_RANGE(0xffffb2, 0xffffb3) AM_DEVREADWRITE8("timer8_1", h8_timer8_channel_device, tcsr_r, tcsr_w, 0x00ff) + AM_RANGE(0xffffb4, 0xffffb7) AM_DEVREADWRITE8("timer8_0", h8_timer8_channel_device, tcor_r, tcor_w, 0xff00) + AM_RANGE(0xffffb4, 0xffffb7) AM_DEVREADWRITE8("timer8_1", h8_timer8_channel_device, tcor_r, tcor_w, 0x00ff) + AM_RANGE(0xffffb8, 0xffffb9) AM_DEVREADWRITE8("timer8_0", h8_timer8_channel_device, tcnt_r, tcnt_w, 0xff00) + AM_RANGE(0xffffb8, 0xffffb9) AM_DEVREADWRITE8("timer8_1", h8_timer8_channel_device, tcnt_r, tcnt_w, 0x00ff) + + AM_RANGE(0xffffc0, 0xffffc1) AM_DEVREADWRITE8("timer16", h8_timer16_device, tstr_r, tstr_w, 0xff00) + AM_RANGE(0xffffc0, 0xffffc1) AM_DEVREADWRITE8("timer16", h8_timer16_device, tsyr_r, tsyr_w, 0x00ff) + + AM_RANGE(0xffffd0, 0xffffd1) AM_DEVREADWRITE8("timer16:0", h8_timer16_channel_device, tcr_r, tcr_w, 0xff00) + AM_RANGE(0xffffd0, 0xffffd1) AM_DEVREADWRITE8("timer16:0", h8_timer16_channel_device, tmdr_r, tmdr_w, 0x00ff) + AM_RANGE(0xffffd2, 0xffffd3) AM_DEVREADWRITE8("timer16:0", h8_timer16_channel_device, tior_r, tior_w, 0xffff) + AM_RANGE(0xffffd4, 0xffffd5) AM_DEVREADWRITE8("timer16:0", h8_timer16_channel_device, tier_r, tier_w, 0xff00) + AM_RANGE(0xffffd4, 0xffffd5) AM_DEVREADWRITE8("timer16:0", h8_timer16_channel_device, tsr_r, tsr_w, 0x00ff) + AM_RANGE(0xffffd6, 0xffffd7) AM_DEVREADWRITE( "timer16:0", h8_timer16_channel_device, tcnt_r, tcnt_w ) + AM_RANGE(0xffffd8, 0xffffdf) AM_DEVREADWRITE( "timer16:0", h8_timer16_channel_device, tgr_r, tgr_w ) + AM_RANGE(0xffffe0, 0xffffe1) AM_DEVREADWRITE8("timer16:1", h8_timer16_channel_device, tcr_r, tcr_w, 0xff00) + AM_RANGE(0xffffe0, 0xffffe1) AM_DEVREADWRITE8("timer16:1", h8_timer16_channel_device, tmdr_r, tmdr_w, 0x00ff) + AM_RANGE(0xffffe2, 0xffffe3) AM_DEVREADWRITE8("timer16:1", h8_timer16_channel_device, tior_r, tior_w, 0xff00) + AM_RANGE(0xffffe4, 0xffffe5) AM_DEVREADWRITE8("timer16:1", h8_timer16_channel_device, tier_r, tier_w, 0xff00) + AM_RANGE(0xffffe4, 0xffffe5) AM_DEVREADWRITE8("timer16:1", h8_timer16_channel_device, tsr_r, tsr_w, 0x00ff) + AM_RANGE(0xffffe6, 0xffffe7) AM_DEVREADWRITE( "timer16:1", h8_timer16_channel_device, tcnt_r, tcnt_w ) + AM_RANGE(0xffffe8, 0xffffeb) AM_DEVREADWRITE( "timer16:1", h8_timer16_channel_device, tgr_r, tgr_w ) + AM_RANGE(0xfffff0, 0xfffff1) AM_DEVREADWRITE8("timer16:2", h8_timer16_channel_device, tcr_r, tcr_w, 0xff00) + AM_RANGE(0xfffff0, 0xfffff1) AM_DEVREADWRITE8("timer16:2", h8_timer16_channel_device, tmdr_r, tmdr_w, 0x00ff) + AM_RANGE(0xfffff2, 0xfffff3) AM_DEVREADWRITE8("timer16:2", h8_timer16_channel_device, tior_r, tior_w, 0xff00) + AM_RANGE(0xfffff4, 0xfffff5) AM_DEVREADWRITE8("timer16:2", h8_timer16_channel_device, tier_r, tier_w, 0xff00) + AM_RANGE(0xfffff4, 0xfffff5) AM_DEVREADWRITE8("timer16:2", h8_timer16_channel_device, tsr_r, tsr_w, 0x00ff) + AM_RANGE(0xfffff6, 0xfffff7) AM_DEVREADWRITE( "timer16:2", h8_timer16_channel_device, tcnt_r, tcnt_w ) + AM_RANGE(0xfffff8, 0xfffffb) AM_DEVREADWRITE( "timer16:2", h8_timer16_channel_device, tgr_r, tgr_w ) +ADDRESS_MAP_END + +machine_config_constructor h8s2320_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME(h8s2320); +} + +void h8s2320_device::execute_set_input(int inputnum, int state) +{ + intc->set_input(inputnum, state); +} + +bool h8s2320_device::exr_in_stack() const +{ + return syscr & 0x20; +} + +int h8s2320_device::trace_setup() +{ + CCR |= F_I; + EXR &= ~EXR_T; + return 5; +} + +int h8s2320_device::trapa_setup() +{ + CCR |= F_I; + if(syscr & 0x20) + EXR &= ~EXR_T; + return 8; +} + +void h8s2320_device::irq_setup() +{ + switch(syscr & 0x30) { + case 0x00: + CCR |= F_I; + break; + case 0x20: + EXR = EXR & (EXR_NC); + if(taken_irq_level == 8) + EXR |= 7; + else + EXR |= taken_irq_level; + break; + } +} + +void h8s2320_device::update_irq_filter() +{ + switch(syscr & 0x30) { + case 0x00: + if(CCR & F_I) + intc->set_filter(2, -1); + else + intc->set_filter(0, -1); + break; + case 0x20: + intc->set_filter(0, EXR & 7); + break; + } +} + +void h8s2320_device::interrupt_taken() +{ + standard_irq_callback(intc->interrupt_taken(taken_irq_vector)); +} + +void h8s2320_device::internal_update(UINT64 current_time) +{ + UINT64 event_time = 0; + + add_event(event_time, adc->internal_update(current_time)); + add_event(event_time, sci0->internal_update(current_time)); + add_event(event_time, sci1->internal_update(current_time)); + add_event(event_time, sci2->internal_update(current_time)); + add_event(event_time, timer8_0->internal_update(current_time)); + add_event(event_time, timer8_1->internal_update(current_time)); + add_event(event_time, timer16_0->internal_update(current_time)); + add_event(event_time, timer16_1->internal_update(current_time)); + add_event(event_time, timer16_2->internal_update(current_time)); + add_event(event_time, timer16_3->internal_update(current_time)); + add_event(event_time, timer16_4->internal_update(current_time)); + add_event(event_time, timer16_5->internal_update(current_time)); + + recompute_bcount(event_time); +} + +void h8s2320_device::device_start() +{ + h8s2000_device::device_start(); +} + +void h8s2320_device::device_reset() +{ + h8s2000_device::device_reset(); + syscr = 0x01; +} + +READ8_MEMBER(h8s2320_device::syscr_r) +{ + return syscr; +} + +WRITE8_MEMBER(h8s2320_device::syscr_w) +{ + syscr = data; + mac_saturating = syscr & 0x80; + update_irq_filter(); + logerror("%s: syscr = %02x\n", tag(), data); +} diff --git a/src/devices/cpu/h8/h8s2320.h b/src/devices/cpu/h8/h8s2320.h new file mode 100644 index 00000000000..f3ff765daf6 --- /dev/null +++ b/src/devices/cpu/h8/h8s2320.h @@ -0,0 +1,143 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +/*************************************************************************** + + h8s2320.h + + H8S-2320 family emulation + + H8S/2600-based mcus. + + Variant ROM RAM + H8S/2320 - 4K + H8S/2321 - 4K + H8S/2322 - 8K + H8S/2323 32K 8K + H8S/2324 - 32K + H8S/2326 512K 8K + H8S/2327 128K 8K + H8S/2328 256K 8K + H8S/2329 384K 32K + + + +***************************************************************************/ + +#ifndef __H8S2320_H__ +#define __H8S2320_H__ + +#include "h8s2000.h" +#include "h8_adc.h" +#include "h8_port.h" +#include "h8_intc.h" +#include "h8_sci.h" +#include "h8_timer8.h" +#include "h8_timer16.h" + +class h8s2320_device : public h8s2000_device { +public: + h8s2320_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + h8s2320_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + DECLARE_READ8_MEMBER(syscr_r); + DECLARE_WRITE8_MEMBER(syscr_w); + +protected: + required_device intc; + required_device adc; + required_device port1; + required_device port2; + required_device port3; + required_device port4; + required_device port5; + required_device port6; + required_device porta; + required_device portb; + required_device portc; + required_device portd; + required_device porte; + required_device portf; + required_device portg; + required_device timer8_0; + required_device timer8_1; + required_device timer16; + required_device timer16_0; + required_device timer16_1; + required_device timer16_2; + required_device timer16_3; + required_device timer16_4; + required_device timer16_5; + required_device sci0; + required_device sci1; + required_device sci2; + + UINT32 ram_start; + UINT8 syscr; + + virtual bool exr_in_stack() const; + virtual void update_irq_filter(); + virtual void interrupt_taken(); + virtual int trace_setup(); + virtual int trapa_setup(); + virtual void irq_setup(); + virtual void internal_update(UINT64 current_time); + virtual machine_config_constructor device_mconfig_additions() const; + DECLARE_ADDRESS_MAP(map, 16); + + virtual void device_start(); + virtual void device_reset(); + virtual void execute_set_input(int inputnum, int state); +}; + +class h8s2321_device : public h8s2320_device { +public: + h8s2321_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class h8s2322_device : public h8s2320_device { +public: + h8s2322_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class h8s2323_device : public h8s2320_device { +public: + h8s2323_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class h8s2324_device : public h8s2320_device { +public: + h8s2324_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class h8s2326_device : public h8s2320_device { +public: + h8s2326_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class h8s2327_device : public h8s2320_device { +public: + h8s2327_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class h8s2328_device : public h8s2320_device { +public: + h8s2328_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class h8s2329_device : public h8s2320_device { +public: + h8s2329_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +extern const device_type H8S2320; +extern const device_type H8S2321; +extern const device_type H8S2322; +extern const device_type H8S2323; +extern const device_type H8S2324; +extern const device_type H8S2326; +extern const device_type H8S2327; +extern const device_type H8S2328; +extern const device_type H8S2329; + + +#endif diff --git a/src/devices/cpu/h8/h8s2357.c b/src/devices/cpu/h8/h8s2357.c new file mode 100644 index 00000000000..56248a29c3a --- /dev/null +++ b/src/devices/cpu/h8/h8s2357.c @@ -0,0 +1,427 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +#include "emu.h" +#include "h8s2357.h" + +const device_type H8S2357 = &device_creator; +const device_type H8S2352 = &device_creator; +const device_type H8S2398 = &device_creator; +const device_type H8S2394 = &device_creator; +const device_type H8S2392 = &device_creator; +const device_type H8S2390 = &device_creator; + +h8s2357_device::h8s2357_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + h8s2000_device(mconfig, type, name, tag, owner, clock, shortname, source, address_map_delegate(FUNC(h8s2357_device::map), this)), + intc(*this, "intc"), + adc(*this, "adc"), + port1(*this, "port1"), + port2(*this, "port2"), + port3(*this, "port3"), + port4(*this, "port4"), + port5(*this, "port5"), + port6(*this, "port6"), + porta(*this, "porta"), + portb(*this, "portb"), + portc(*this, "portc"), + portd(*this, "portd"), + porte(*this, "porte"), + portf(*this, "portf"), + portg(*this, "portg"), + timer8_0(*this, "timer8_0"), + timer8_1(*this, "timer8_1"), + timer16(*this, "timer16"), + timer16_0(*this, "timer16:0"), + timer16_1(*this, "timer16:1"), + timer16_2(*this, "timer16:2"), + timer16_3(*this, "timer16:3"), + timer16_4(*this, "timer16:4"), + timer16_5(*this, "timer16:5"), + sci0(*this, "sci0"), + sci1(*this, "sci1"), + sci2(*this, "sci2") +{ +} + +h8s2357_device::h8s2357_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + h8s2000_device(mconfig, H8S2357, "H8S/2357", tag, owner, clock, "h8s2357", __FILE__, address_map_delegate(FUNC(h8s2357_device::map), this)), + intc(*this, "intc"), + adc(*this, "adc"), + port1(*this, "port1"), + port2(*this, "port2"), + port3(*this, "port3"), + port4(*this, "port4"), + port5(*this, "port5"), + port6(*this, "port6"), + porta(*this, "porta"), + portb(*this, "portb"), + portc(*this, "portc"), + portd(*this, "portd"), + porte(*this, "porte"), + portf(*this, "portf"), + portg(*this, "portg"), + timer8_0(*this, "timer8_0"), + timer8_1(*this, "timer8_1"), + timer16(*this, "timer16"), + timer16_0(*this, "timer16:0"), + timer16_1(*this, "timer16:1"), + timer16_2(*this, "timer16:2"), + timer16_3(*this, "timer16:3"), + timer16_4(*this, "timer16:4"), + timer16_5(*this, "timer16:5"), + sci0(*this, "sci0"), + sci1(*this, "sci1"), + sci2(*this, "sci2") +{ + ram_start = 0xffdc00; +} + +h8s2352_device::h8s2352_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + h8s2357_device(mconfig, H8S2352, "H8S/2352", tag, owner, clock, "h8s2352", __FILE__) +{ + ram_start = 0xffdc00; +} + +h8s2398_device::h8s2398_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + h8s2357_device(mconfig, H8S2398, "H8S/2398", tag, owner, clock, "h8s2398", __FILE__) +{ + ram_start = 0xffdc00; +} + +h8s2394_device::h8s2394_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + h8s2357_device(mconfig, H8S2394, "H8S/2394", tag, owner, clock, "h8s2394", __FILE__) +{ + ram_start = 0xff7c00; +} + +h8s2392_device::h8s2392_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + h8s2357_device(mconfig, H8S2392, "H8S/2392", tag, owner, clock, "h8s2392", __FILE__) +{ + ram_start = 0xffdc00; +} + +h8s2390_device::h8s2390_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + h8s2357_device(mconfig, H8S2390, "H8S/2390", tag, owner, clock, "h8s2390", __FILE__) +{ + ram_start = 0xffec00; +} + +static MACHINE_CONFIG_FRAGMENT(h8s2357) + MCFG_H8S_INTC_ADD("intc") + MCFG_H8_ADC_2357_ADD("adc", "intc", 28) + MCFG_H8_PORT_ADD("port1", h8_device::PORT_1, 0x00, 0x00) + MCFG_H8_PORT_ADD("port2", h8_device::PORT_2, 0x00, 0x00) + MCFG_H8_PORT_ADD("port3", h8_device::PORT_3, 0xc0, 0xc0) + MCFG_H8_PORT_ADD("port4", h8_device::PORT_4, 0x00, 0x00) + MCFG_H8_PORT_ADD("port5", h8_device::PORT_5, 0xf0, 0xf0) + MCFG_H8_PORT_ADD("port6", h8_device::PORT_6, 0x00, 0x00) + MCFG_H8_PORT_ADD("porta", h8_device::PORT_A, 0x00, 0x00) + MCFG_H8_PORT_ADD("portb", h8_device::PORT_B, 0x00, 0x00) + MCFG_H8_PORT_ADD("portc", h8_device::PORT_C, 0x00, 0x00) + MCFG_H8_PORT_ADD("portd", h8_device::PORT_D, 0x00, 0x00) + MCFG_H8_PORT_ADD("porte", h8_device::PORT_E, 0x00, 0x00) + MCFG_H8_PORT_ADD("portf", h8_device::PORT_F, 0x00, 0x00) + MCFG_H8_PORT_ADD("portg", h8_device::PORT_G, 0xe0, 0xe0) + MCFG_H8H_TIMER8_CHANNEL_ADD("timer8_0", "intc", 64, 65, 66, "timer8_1", h8_timer8_channel_device::CHAIN_OVERFLOW, true, false) + MCFG_H8H_TIMER8_CHANNEL_ADD("timer8_1", "intc", 68, 69, 70, "timer8_0", h8_timer8_channel_device::CHAIN_A, false, false) + MCFG_H8_TIMER16_ADD("timer16", 6, 0x00) + MCFG_H8S_TIMER16_CHANNEL_ADD("timer16:0", 4, 0x60, "intc", 32, + h8_timer16_channel_device::DIV_1, + h8_timer16_channel_device::DIV_4, + h8_timer16_channel_device::DIV_16, + h8_timer16_channel_device::DIV_64, + h8_timer16_channel_device::INPUT_A, + h8_timer16_channel_device::INPUT_B, + h8_timer16_channel_device::INPUT_C, + h8_timer16_channel_device::INPUT_D) + MCFG_H8S_TIMER16_CHANNEL_ADD("timer16:1", 2, 0x4c, "intc", 40, + h8_timer16_channel_device::DIV_1, + h8_timer16_channel_device::DIV_4, + h8_timer16_channel_device::DIV_16, + h8_timer16_channel_device::DIV_64, + h8_timer16_channel_device::INPUT_A, + h8_timer16_channel_device::INPUT_B, + h8_timer16_channel_device::DIV_256, + h8_timer16_channel_device::CHAIN) + MCFG_H8S_TIMER16_CHANNEL_SET_CHAIN("timer16:2") + MCFG_H8S_TIMER16_CHANNEL_ADD("timer16:2", 2, 0x4c, "intc", 44, + h8_timer16_channel_device::DIV_1, + h8_timer16_channel_device::DIV_4, + h8_timer16_channel_device::DIV_16, + h8_timer16_channel_device::DIV_64, + h8_timer16_channel_device::INPUT_A, + h8_timer16_channel_device::INPUT_B, + h8_timer16_channel_device::INPUT_C, + h8_timer16_channel_device::DIV_1024) + MCFG_H8S_TIMER16_CHANNEL_ADD("timer16:3", 4, 0x60, "intc", 48, + h8_timer16_channel_device::DIV_1, + h8_timer16_channel_device::DIV_4, + h8_timer16_channel_device::DIV_16, + h8_timer16_channel_device::DIV_64, + h8_timer16_channel_device::INPUT_A, + h8_timer16_channel_device::DIV_1024, + h8_timer16_channel_device::DIV_256, + h8_timer16_channel_device::DIV_4096) + MCFG_H8S_TIMER16_CHANNEL_ADD("timer16:4", 2, 0x4c, "intc", 56, + h8_timer16_channel_device::DIV_1, + h8_timer16_channel_device::DIV_4, + h8_timer16_channel_device::DIV_16, + h8_timer16_channel_device::DIV_64, + h8_timer16_channel_device::INPUT_A, + h8_timer16_channel_device::INPUT_C, + h8_timer16_channel_device::DIV_1024, + h8_timer16_channel_device::CHAIN) + MCFG_H8S_TIMER16_CHANNEL_SET_CHAIN("timer16:5") + MCFG_H8S_TIMER16_CHANNEL_ADD("timer16:5", 2, 0x4c, "intc", 60, + h8_timer16_channel_device::DIV_1, + h8_timer16_channel_device::DIV_4, + h8_timer16_channel_device::DIV_16, + h8_timer16_channel_device::DIV_64, + h8_timer16_channel_device::INPUT_A, + h8_timer16_channel_device::INPUT_C, + h8_timer16_channel_device::DIV_256, + h8_timer16_channel_device::INPUT_D) + MCFG_H8_SCI_ADD("sci0", "intc", 80, 81, 82, 83) + MCFG_H8_SCI_ADD("sci1", "intc", 84, 85, 86, 87) + MCFG_H8_SCI_ADD("sci2", "intc", 88, 89, 90, 91) +MACHINE_CONFIG_END + +DEVICE_ADDRESS_MAP_START(map, 16, h8s2357_device) + AM_RANGE(ram_start, 0xfffbff) AM_RAM + AM_RANGE(0xfffe80, 0xfffe81) AM_DEVREADWRITE8("timer16:3", h8_timer16_channel_device, tcr_r, tcr_w, 0xff00) + AM_RANGE(0xfffe80, 0xfffe81) AM_DEVREADWRITE8("timer16:3", h8_timer16_channel_device, tmdr_r, tmdr_w, 0x00ff) + AM_RANGE(0xfffe82, 0xfffe83) AM_DEVREADWRITE8("timer16:3", h8_timer16_channel_device, tior_r, tior_w, 0xffff) + AM_RANGE(0xfffe84, 0xfffe85) AM_DEVREADWRITE8("timer16:3", h8_timer16_channel_device, tier_r, tier_w, 0xff00) + AM_RANGE(0xfffe84, 0xfffe85) AM_DEVREADWRITE8("timer16:3", h8_timer16_channel_device, tsr_r, tsr_w, 0x00ff) + AM_RANGE(0xfffe86, 0xfffe87) AM_DEVREADWRITE( "timer16:3", h8_timer16_channel_device, tcnt_r, tcnt_w ) + AM_RANGE(0xfffe88, 0xfffe8f) AM_DEVREADWRITE( "timer16:3", h8_timer16_channel_device, tgr_r, tgr_w ) + AM_RANGE(0xfffe90, 0xfffe91) AM_DEVREADWRITE8("timer16:4", h8_timer16_channel_device, tcr_r, tcr_w, 0xff00) + AM_RANGE(0xfffe90, 0xfffe91) AM_DEVREADWRITE8("timer16:4", h8_timer16_channel_device, tmdr_r, tmdr_w, 0x00ff) + AM_RANGE(0xfffe92, 0xfffe93) AM_DEVREADWRITE8("timer16:4", h8_timer16_channel_device, tior_r, tior_w, 0xff00) + AM_RANGE(0xfffe94, 0xfffe95) AM_DEVREADWRITE8("timer16:4", h8_timer16_channel_device, tier_r, tier_w, 0xff00) + AM_RANGE(0xfffe94, 0xfffe95) AM_DEVREADWRITE8("timer16:4", h8_timer16_channel_device, tsr_r, tsr_w, 0x00ff) + AM_RANGE(0xfffe96, 0xfffe97) AM_DEVREADWRITE( "timer16:4", h8_timer16_channel_device, tcnt_r, tcnt_w ) + AM_RANGE(0xfffe98, 0xfffe9b) AM_DEVREADWRITE( "timer16:4", h8_timer16_channel_device, tgr_r, tgr_w ) + AM_RANGE(0xfffea0, 0xfffea1) AM_DEVREADWRITE8("timer16:5", h8_timer16_channel_device, tcr_r, tcr_w, 0xff00) + AM_RANGE(0xfffea0, 0xfffea1) AM_DEVREADWRITE8("timer16:5", h8_timer16_channel_device, tmdr_r, tmdr_w, 0x00ff) + AM_RANGE(0xfffea2, 0xfffea3) AM_DEVREADWRITE8("timer16:5", h8_timer16_channel_device, tior_r, tior_w, 0xff00) + AM_RANGE(0xfffea4, 0xfffea5) AM_DEVREADWRITE8("timer16:5", h8_timer16_channel_device, tier_r, tier_w, 0xff00) + AM_RANGE(0xfffea4, 0xfffea5) AM_DEVREADWRITE8("timer16:5", h8_timer16_channel_device, tsr_r, tsr_w, 0x00ff) + AM_RANGE(0xfffea6, 0xfffea7) AM_DEVREADWRITE( "timer16:5", h8_timer16_channel_device, tcnt_r, tcnt_w ) + AM_RANGE(0xfffea8, 0xfffeab) AM_DEVREADWRITE( "timer16:5", h8_timer16_channel_device, tgr_r, tgr_w ) + AM_RANGE(0xfffeb0, 0xfffeb1) AM_DEVWRITE8( "port1", h8_port_device, ddr_w, 0xff00) + AM_RANGE(0xfffeb0, 0xfffeb1) AM_DEVWRITE8( "port1", h8_port_device, ddr_w, 0xff00) + AM_RANGE(0xfffeb0, 0xfffeb1) AM_DEVWRITE8( "port2", h8_port_device, ddr_w, 0x00ff) + AM_RANGE(0xfffeb2, 0xfffeb3) AM_DEVWRITE8( "port3", h8_port_device, ddr_w, 0xff00) + AM_RANGE(0xfffeb4, 0xfffeb5) AM_DEVWRITE8( "port5", h8_port_device, ddr_w, 0xff00) + AM_RANGE(0xfffeb4, 0xfffeb5) AM_DEVWRITE8( "port6", h8_port_device, ddr_w, 0x00ff) + AM_RANGE(0xfffeb8, 0xfffeb9) AM_DEVWRITE8( "porta", h8_port_device, ddr_w, 0x00ff) + AM_RANGE(0xfffeba, 0xfffebb) AM_DEVWRITE8( "portb", h8_port_device, ddr_w, 0xff00) + AM_RANGE(0xfffeba, 0xfffebb) AM_DEVWRITE8( "portc", h8_port_device, ddr_w, 0x00ff) + AM_RANGE(0xfffebc, 0xfffebd) AM_DEVWRITE8( "portd", h8_port_device, ddr_w, 0xff00) + AM_RANGE(0xfffebc, 0xfffebd) AM_DEVWRITE8( "porte", h8_port_device, ddr_w, 0x00ff) + AM_RANGE(0xfffebe, 0xfffebf) AM_DEVWRITE8( "portf", h8_port_device, ddr_w, 0xff00) + AM_RANGE(0xfffebe, 0xfffebf) AM_DEVWRITE8( "portg", h8_port_device, ddr_w, 0x00ff) + AM_RANGE(0xfffec4, 0xfffecd) AM_DEVREADWRITE8("intc", h8s_intc_device, ipr_r, ipr_w, 0xffff) + AM_RANGE(0xfffece, 0xfffecf) AM_DEVREADWRITE8("intc", h8s_intc_device, iprk_r, iprk_w, 0xff00) + AM_RANGE(0xffff2c, 0xffff2d) AM_DEVREADWRITE8("intc", h8s_intc_device, iscrh_r, iscrh_w, 0xff00) + AM_RANGE(0xffff2c, 0xffff2d) AM_DEVREADWRITE8("intc", h8s_intc_device, iscrl_r, iscrl_w, 0x00ff) + AM_RANGE(0xffff2e, 0xffff2f) AM_DEVREADWRITE8("intc", h8s_intc_device, ier_r, ier_w, 0xff00) + AM_RANGE(0xffff2e, 0xffff2f) AM_DEVREADWRITE8("intc", h8s_intc_device, isr_r, isr_w, 0x00ff) + AM_RANGE(0xffff38, 0xffff39) AM_READWRITE8( syscr_r, syscr_w, 0x00ff) + AM_RANGE(0xffff50, 0xffff51) AM_DEVREAD8( "port1", h8_port_device, port_r, 0xff00) + AM_RANGE(0xffff50, 0xffff51) AM_DEVREAD8( "port2", h8_port_device, port_r, 0x00ff) + AM_RANGE(0xffff52, 0xffff53) AM_DEVREAD8( "port3", h8_port_device, port_r, 0xff00) + AM_RANGE(0xffff52, 0xffff53) AM_DEVREAD8( "port4", h8_port_device, port_r, 0x00ff) + AM_RANGE(0xffff54, 0xffff55) AM_DEVREAD8( "port5", h8_port_device, port_r, 0xff00) + AM_RANGE(0xffff54, 0xffff55) AM_DEVREAD8( "port6", h8_port_device, port_r, 0x00ff) + AM_RANGE(0xffff58, 0xffff59) AM_DEVREAD8( "porta", h8_port_device, port_r, 0x00ff) + AM_RANGE(0xffff5a, 0xffff5b) AM_DEVREAD8( "portb", h8_port_device, port_r, 0xff00) + AM_RANGE(0xffff5a, 0xffff5b) AM_DEVREAD8( "portc", h8_port_device, port_r, 0x00ff) + AM_RANGE(0xffff5c, 0xffff5d) AM_DEVREAD8( "portd", h8_port_device, port_r, 0xff00) + AM_RANGE(0xffff5c, 0xffff5d) AM_DEVREAD8( "porte", h8_port_device, port_r, 0x00ff) + AM_RANGE(0xffff5e, 0xffff5f) AM_DEVREAD8( "portf", h8_port_device, port_r, 0xff00) + AM_RANGE(0xffff5e, 0xffff5f) AM_DEVREAD8( "portg", h8_port_device, port_r, 0x00ff) + AM_RANGE(0xffff60, 0xffff61) AM_DEVREADWRITE8("port1", h8_port_device, dr_r, dr_w, 0xff00) + AM_RANGE(0xffff60, 0xffff61) AM_DEVREADWRITE8("port2", h8_port_device, dr_r, dr_w, 0x00ff) + AM_RANGE(0xffff62, 0xffff63) AM_DEVREADWRITE8("port3", h8_port_device, dr_r, dr_w, 0xff00) + AM_RANGE(0xffff64, 0xffff65) AM_DEVREADWRITE8("port5", h8_port_device, dr_r, dr_w, 0xff00) + AM_RANGE(0xffff64, 0xffff65) AM_DEVREADWRITE8("port6", h8_port_device, dr_r, dr_w, 0x00ff) + AM_RANGE(0xffff68, 0xffff69) AM_DEVREADWRITE8("porta", h8_port_device, dr_r, dr_w, 0x00ff) + AM_RANGE(0xffff6a, 0xffff6b) AM_DEVREADWRITE8("portb", h8_port_device, dr_r, dr_w, 0xff00) + AM_RANGE(0xffff6a, 0xffff6b) AM_DEVREADWRITE8("portc", h8_port_device, dr_r, dr_w, 0x00ff) + AM_RANGE(0xffff6c, 0xffff6d) AM_DEVREADWRITE8("portd", h8_port_device, dr_r, dr_w, 0xff00) + AM_RANGE(0xffff6c, 0xffff6d) AM_DEVREADWRITE8("porte", h8_port_device, dr_r, dr_w, 0x00ff) + AM_RANGE(0xffff6e, 0xffff6f) AM_DEVREADWRITE8("portf", h8_port_device, dr_r, dr_w, 0xff00) + AM_RANGE(0xffff6e, 0xffff6f) AM_DEVREADWRITE8("portg", h8_port_device, dr_r, dr_w, 0x00ff) + AM_RANGE(0xffff70, 0xffff71) AM_DEVREADWRITE8("porta", h8_port_device, pcr_r, pcr_w, 0xff00) + AM_RANGE(0xffff70, 0xffff71) AM_DEVREADWRITE8("portb", h8_port_device, pcr_r, pcr_w, 0x00ff) + AM_RANGE(0xffff72, 0xffff73) AM_DEVREADWRITE8("portc", h8_port_device, pcr_r, pcr_w, 0xff00) + AM_RANGE(0xffff72, 0xffff73) AM_DEVREADWRITE8("portd", h8_port_device, pcr_r, pcr_w, 0x00ff) + AM_RANGE(0xffff74, 0xffff75) AM_DEVREADWRITE8("porte", h8_port_device, pcr_r, pcr_w, 0xff00) + AM_RANGE(0xffff76, 0xffff77) AM_DEVREADWRITE8("port3", h8_port_device, odr_r, odr_w, 0xff00) + AM_RANGE(0xffff76, 0xffff77) AM_DEVREADWRITE8("porta", h8_port_device, odr_r, odr_w, 0x00ff) + AM_RANGE(0xffff78, 0xffff79) AM_DEVREADWRITE8("sci0", h8_sci_device, smr_r, smr_w, 0xff00) + AM_RANGE(0xffff78, 0xffff79) AM_DEVREADWRITE8("sci0", h8_sci_device, brr_r, brr_w, 0x00ff) + AM_RANGE(0xffff7a, 0xffff7b) AM_DEVREADWRITE8("sci0", h8_sci_device, scr_r, scr_w, 0xff00) + AM_RANGE(0xffff7a, 0xffff7b) AM_DEVREADWRITE8("sci0", h8_sci_device, tdr_r, tdr_w, 0x00ff) + AM_RANGE(0xffff7c, 0xffff7d) AM_DEVREADWRITE8("sci0", h8_sci_device, ssr_r, ssr_w, 0xff00) + AM_RANGE(0xffff7c, 0xffff7d) AM_DEVREAD8( "sci0", h8_sci_device, rdr_r, 0x00ff) + AM_RANGE(0xffff7e, 0xffff7f) AM_DEVREADWRITE8("sci0", h8_sci_device, scmr_r, scmr_w, 0xff00) + AM_RANGE(0xffff80, 0xffff81) AM_DEVREADWRITE8("sci1", h8_sci_device, smr_r, smr_w, 0xff00) + AM_RANGE(0xffff80, 0xffff81) AM_DEVREADWRITE8("sci1", h8_sci_device, brr_r, brr_w, 0x00ff) + AM_RANGE(0xffff82, 0xffff83) AM_DEVREADWRITE8("sci1", h8_sci_device, scr_r, scr_w, 0xff00) + AM_RANGE(0xffff82, 0xffff83) AM_DEVREADWRITE8("sci1", h8_sci_device, tdr_r, tdr_w, 0x00ff) + AM_RANGE(0xffff84, 0xffff85) AM_DEVREADWRITE8("sci1", h8_sci_device, ssr_r, ssr_w, 0xff00) + AM_RANGE(0xffff84, 0xffff85) AM_DEVREAD8( "sci1", h8_sci_device, rdr_r, 0x00ff) + AM_RANGE(0xffff86, 0xffff87) AM_DEVREADWRITE8("sci1", h8_sci_device, scmr_r, scmr_w, 0xff00) + AM_RANGE(0xffff88, 0xffff89) AM_DEVREADWRITE8("sci2", h8_sci_device, smr_r, smr_w, 0xff00) + AM_RANGE(0xffff88, 0xffff89) AM_DEVREADWRITE8("sci2", h8_sci_device, brr_r, brr_w, 0x00ff) + AM_RANGE(0xffff8a, 0xffff8b) AM_DEVREADWRITE8("sci2", h8_sci_device, scr_r, scr_w, 0xff00) + AM_RANGE(0xffff8a, 0xffff8b) AM_DEVREADWRITE8("sci2", h8_sci_device, tdr_r, tdr_w, 0x00ff) + AM_RANGE(0xffff8c, 0xffff8d) AM_DEVREADWRITE8("sci2", h8_sci_device, ssr_r, ssr_w, 0xff00) + AM_RANGE(0xffff8c, 0xffff8d) AM_DEVREAD8( "sci2", h8_sci_device, rdr_r, 0x00ff) + AM_RANGE(0xffff8e, 0xffff8f) AM_DEVREADWRITE8("sci2", h8_sci_device, scmr_r, scmr_w, 0xff00) + AM_RANGE(0xffff90, 0xffff97) AM_DEVREAD8( "adc", h8_adc_device, addr8_r, 0xffff) + AM_RANGE(0xffff98, 0xffff99) AM_DEVREADWRITE8("adc", h8_adc_device, adcsr_r, adcsr_w, 0xff00) + AM_RANGE(0xffff98, 0xffff99) AM_DEVREADWRITE8("adc", h8_adc_device, adcr_r, adcr_w, 0x00ff) + AM_RANGE(0xffffb0, 0xffffb1) AM_DEVREADWRITE8("timer8_0", h8_timer8_channel_device, tcr_r, tcr_w, 0xff00) + AM_RANGE(0xffffb0, 0xffffb1) AM_DEVREADWRITE8("timer8_1", h8_timer8_channel_device, tcr_r, tcr_w, 0x00ff) + AM_RANGE(0xffffb2, 0xffffb3) AM_DEVREADWRITE8("timer8_0", h8_timer8_channel_device, tcsr_r, tcsr_w, 0xff00) + AM_RANGE(0xffffb2, 0xffffb3) AM_DEVREADWRITE8("timer8_1", h8_timer8_channel_device, tcsr_r, tcsr_w, 0x00ff) + AM_RANGE(0xffffb4, 0xffffb7) AM_DEVREADWRITE8("timer8_0", h8_timer8_channel_device, tcor_r, tcor_w, 0xff00) + AM_RANGE(0xffffb4, 0xffffb7) AM_DEVREADWRITE8("timer8_1", h8_timer8_channel_device, tcor_r, tcor_w, 0x00ff) + AM_RANGE(0xffffb8, 0xffffb9) AM_DEVREADWRITE8("timer8_0", h8_timer8_channel_device, tcnt_r, tcnt_w, 0xff00) + AM_RANGE(0xffffb8, 0xffffb9) AM_DEVREADWRITE8("timer8_1", h8_timer8_channel_device, tcnt_r, tcnt_w, 0x00ff) + AM_RANGE(0xffffc0, 0xffffc1) AM_DEVREADWRITE8("timer16", h8_timer16_device, tstr_r, tstr_w, 0xff00) + AM_RANGE(0xffffc0, 0xffffc1) AM_DEVREADWRITE8("timer16", h8_timer16_device, tsyr_r, tsyr_w, 0x00ff) + AM_RANGE(0xffffd0, 0xffffd1) AM_DEVREADWRITE8("timer16:0", h8_timer16_channel_device, tcr_r, tcr_w, 0xff00) + AM_RANGE(0xffffd0, 0xffffd1) AM_DEVREADWRITE8("timer16:0", h8_timer16_channel_device, tmdr_r, tmdr_w, 0x00ff) + AM_RANGE(0xffffd2, 0xffffd3) AM_DEVREADWRITE8("timer16:0", h8_timer16_channel_device, tior_r, tior_w, 0xffff) + AM_RANGE(0xffffd4, 0xffffd5) AM_DEVREADWRITE8("timer16:0", h8_timer16_channel_device, tier_r, tier_w, 0xff00) + AM_RANGE(0xffffd4, 0xffffd5) AM_DEVREADWRITE8("timer16:0", h8_timer16_channel_device, tsr_r, tsr_w, 0x00ff) + AM_RANGE(0xffffd6, 0xffffd7) AM_DEVREADWRITE( "timer16:0", h8_timer16_channel_device, tcnt_r, tcnt_w ) + AM_RANGE(0xffffd8, 0xffffdf) AM_DEVREADWRITE( "timer16:0", h8_timer16_channel_device, tgr_r, tgr_w ) + AM_RANGE(0xffffe0, 0xffffe1) AM_DEVREADWRITE8("timer16:1", h8_timer16_channel_device, tcr_r, tcr_w, 0xff00) + AM_RANGE(0xffffe0, 0xffffe1) AM_DEVREADWRITE8("timer16:1", h8_timer16_channel_device, tmdr_r, tmdr_w, 0x00ff) + AM_RANGE(0xffffe2, 0xffffe3) AM_DEVREADWRITE8("timer16:1", h8_timer16_channel_device, tior_r, tior_w, 0xff00) + AM_RANGE(0xffffe4, 0xffffe5) AM_DEVREADWRITE8("timer16:1", h8_timer16_channel_device, tier_r, tier_w, 0xff00) + AM_RANGE(0xffffe4, 0xffffe5) AM_DEVREADWRITE8("timer16:1", h8_timer16_channel_device, tsr_r, tsr_w, 0x00ff) + AM_RANGE(0xffffe6, 0xffffe7) AM_DEVREADWRITE( "timer16:1", h8_timer16_channel_device, tcnt_r, tcnt_w ) + AM_RANGE(0xffffe8, 0xffffeb) AM_DEVREADWRITE( "timer16:1", h8_timer16_channel_device, tgr_r, tgr_w ) + AM_RANGE(0xfffff0, 0xfffff1) AM_DEVREADWRITE8("timer16:2", h8_timer16_channel_device, tcr_r, tcr_w, 0xff00) + AM_RANGE(0xfffff0, 0xfffff1) AM_DEVREADWRITE8("timer16:2", h8_timer16_channel_device, tmdr_r, tmdr_w, 0x00ff) + AM_RANGE(0xfffff2, 0xfffff3) AM_DEVREADWRITE8("timer16:2", h8_timer16_channel_device, tior_r, tior_w, 0xff00) + AM_RANGE(0xfffff4, 0xfffff5) AM_DEVREADWRITE8("timer16:2", h8_timer16_channel_device, tier_r, tier_w, 0xff00) + AM_RANGE(0xfffff4, 0xfffff5) AM_DEVREADWRITE8("timer16:2", h8_timer16_channel_device, tsr_r, tsr_w, 0x00ff) + AM_RANGE(0xfffff6, 0xfffff7) AM_DEVREADWRITE( "timer16:2", h8_timer16_channel_device, tcnt_r, tcnt_w ) + AM_RANGE(0xfffff8, 0xfffffb) AM_DEVREADWRITE( "timer16:2", h8_timer16_channel_device, tgr_r, tgr_w ) +ADDRESS_MAP_END + +machine_config_constructor h8s2357_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME(h8s2357); +} + +void h8s2357_device::execute_set_input(int inputnum, int state) +{ + intc->set_input(inputnum, state); +} + +bool h8s2357_device::exr_in_stack() const +{ + return syscr & 0x20; +} + +int h8s2357_device::trace_setup() +{ + CCR |= F_I; + EXR &= ~EXR_T; + return 5; +} + +int h8s2357_device::trapa_setup() +{ + CCR |= F_I; + if(syscr & 0x20) + EXR &= ~EXR_T; + return 8; +} + +void h8s2357_device::irq_setup() +{ + switch(syscr & 0x30) { + case 0x00: + CCR |= F_I; + break; + case 0x20: + EXR = EXR & (EXR_NC); + if(taken_irq_level == 8) + EXR |= 7; + else + EXR |= taken_irq_level; + break; + } +} + +void h8s2357_device::update_irq_filter() +{ + switch(syscr & 0x20) { + case 0x00: + if(CCR & F_I) + intc->set_filter(2, -1); + else + intc->set_filter(0, -1); + break; + case 0x20: + intc->set_filter(0, EXR & 7); + break; + } +} + +void h8s2357_device::interrupt_taken() +{ + standard_irq_callback(intc->interrupt_taken(taken_irq_vector)); +} + +void h8s2357_device::internal_update(UINT64 current_time) +{ + UINT64 event_time = 0; + + add_event(event_time, adc->internal_update(current_time)); + add_event(event_time, sci0->internal_update(current_time)); + add_event(event_time, sci1->internal_update(current_time)); + add_event(event_time, sci2->internal_update(current_time)); + add_event(event_time, timer8_0->internal_update(current_time)); + add_event(event_time, timer8_1->internal_update(current_time)); + add_event(event_time, timer16_0->internal_update(current_time)); + add_event(event_time, timer16_1->internal_update(current_time)); + add_event(event_time, timer16_2->internal_update(current_time)); + add_event(event_time, timer16_3->internal_update(current_time)); + add_event(event_time, timer16_4->internal_update(current_time)); + add_event(event_time, timer16_5->internal_update(current_time)); + + recompute_bcount(event_time); +} + +void h8s2357_device::device_start() +{ + h8s2000_device::device_start(); +} + +void h8s2357_device::device_reset() +{ + h8s2000_device::device_reset(); + syscr = 0x01; +} + +READ8_MEMBER(h8s2357_device::syscr_r) +{ + return syscr; +} + +WRITE8_MEMBER(h8s2357_device::syscr_w) +{ + syscr = data; + update_irq_filter(); + logerror("%s: syscr = %02x\n", tag(), data); +} diff --git a/src/devices/cpu/h8/h8s2357.h b/src/devices/cpu/h8/h8s2357.h new file mode 100644 index 00000000000..042207fc67e --- /dev/null +++ b/src/devices/cpu/h8/h8s2357.h @@ -0,0 +1,122 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +/*************************************************************************** + + h8s2357.h + + H8S-2357 family emulation + + H8S/2000-based mcus. + + Variant ROM RAM + H8S/2357 128K 8K + H8S/2352 - 8K + H8S/2398 256K 8K + H8S/2394 - 32K + H8S/2392 - 8K + H8S/2390 - 4K + + + +***************************************************************************/ + +#ifndef __H8S2357_H__ +#define __H8S2357_H__ + +#include "h8s2000.h" +#include "h8_adc.h" +#include "h8_port.h" +#include "h8_intc.h" +#include "h8_sci.h" +#include "h8_timer8.h" +#include "h8_timer16.h" + +class h8s2357_device : public h8s2000_device { +public: + h8s2357_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + h8s2357_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + DECLARE_READ8_MEMBER(syscr_r); + DECLARE_WRITE8_MEMBER(syscr_w); + +protected: + required_device intc; + required_device adc; + required_device port1; + required_device port2; + required_device port3; + required_device port4; + required_device port5; + required_device port6; + required_device porta; + required_device portb; + required_device portc; + required_device portd; + required_device porte; + required_device portf; + required_device portg; + required_device timer8_0; + required_device timer8_1; + required_device timer16; + required_device timer16_0; + required_device timer16_1; + required_device timer16_2; + required_device timer16_3; + required_device timer16_4; + required_device timer16_5; + required_device sci0; + required_device sci1; + required_device sci2; + + UINT32 ram_start; + unsigned char syscr; + + virtual bool exr_in_stack() const; + virtual void update_irq_filter(); + virtual void interrupt_taken(); + virtual int trace_setup(); + virtual int trapa_setup(); + virtual void irq_setup(); + virtual void internal_update(UINT64 current_time); + virtual machine_config_constructor device_mconfig_additions() const; + DECLARE_ADDRESS_MAP(map, 16); + + virtual void device_start(); + virtual void device_reset(); + virtual void execute_set_input(int inputnum, int state); +}; + +class h8s2352_device : public h8s2357_device { +public: + h8s2352_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class h8s2398_device : public h8s2357_device { +public: + h8s2398_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class h8s2394_device : public h8s2357_device { +public: + h8s2394_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class h8s2392_device : public h8s2357_device { +public: + h8s2392_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class h8s2390_device : public h8s2357_device { +public: + h8s2390_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +extern const device_type H8S2357; +extern const device_type H8S2352; +extern const device_type H8S2398; +extern const device_type H8S2394; +extern const device_type H8S2392; +extern const device_type H8S2390; + + +#endif diff --git a/src/devices/cpu/h8/h8s2600.c b/src/devices/cpu/h8/h8s2600.c new file mode 100644 index 00000000000..a72cf591a19 --- /dev/null +++ b/src/devices/cpu/h8/h8s2600.c @@ -0,0 +1,16 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +#include "emu.h" +#include "h8s2600.h" + +h8s2600_device::h8s2600_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source, address_map_delegate map_delegate) : + h8s2000_device(mconfig, type, name, tag, owner, clock, shortname, source, map_delegate) +{ +} + +offs_t h8s2600_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + return disassemble_generic(buffer, pc, oprom, opram, options, disasm_entries); +} + +#include "cpu/h8/h8s2600.inc" diff --git a/src/devices/cpu/h8/h8s2600.h b/src/devices/cpu/h8/h8s2600.h new file mode 100644 index 00000000000..5f224361734 --- /dev/null +++ b/src/devices/cpu/h8/h8s2600.h @@ -0,0 +1,39 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +/*************************************************************************** + + h8s2600.h + + H8S-2600 base cpu emulation + + Adds the multiply-and-accumulate register and related instructions + + +***************************************************************************/ + +#ifndef __H8S2600_H__ +#define __H8S2600_H__ + +#include "h8s2000.h" + +class h8s2600_device : public h8s2000_device { +public: + h8s2600_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source, address_map_delegate map_delegate); + +protected: + static const disasm_entry disasm_entries[]; + + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + + virtual void do_exec_full(); + virtual void do_exec_partial(); + +#define O(o) void o ## _full(); void o ## _partial() + O(clrmac); + O(ldmac_r32l_mach); O(ldmac_r32l_macl); + O(mac_r32ph_r32pl); + O(stmac_mach_r32l); O(stmac_macl_r32l); +#undef O +}; + +#endif diff --git a/src/devices/cpu/h8/h8s2655.c b/src/devices/cpu/h8/h8s2655.c new file mode 100644 index 00000000000..cedce054d48 --- /dev/null +++ b/src/devices/cpu/h8/h8s2655.c @@ -0,0 +1,434 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +#include "emu.h" +#include "h8s2655.h" + +const device_type H8S2655 = &device_creator; +const device_type H8S2653 = &device_creator; + +h8s2655_device::h8s2655_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + h8s2600_device(mconfig, type, name, tag, owner, clock, shortname, source, address_map_delegate(FUNC(h8s2655_device::map), this)), + intc(*this, "intc"), + adc(*this, "adc"), + port1(*this, "port1"), + port2(*this, "port2"), + port3(*this, "port3"), + port4(*this, "port4"), + port5(*this, "port5"), + port6(*this, "port6"), + porta(*this, "porta"), + portb(*this, "portb"), + portc(*this, "portc"), + portd(*this, "portd"), + porte(*this, "porte"), + portf(*this, "portf"), + portg(*this, "portg"), + timer8_0(*this, "timer8_0"), + timer8_1(*this, "timer8_1"), + timer16(*this, "timer16"), + timer16_0(*this, "timer16:0"), + timer16_1(*this, "timer16:1"), + timer16_2(*this, "timer16:2"), + timer16_3(*this, "timer16:3"), + timer16_4(*this, "timer16:4"), + timer16_5(*this, "timer16:5"), + sci0(*this, "sci0"), + sci1(*this, "sci1"), + sci2(*this, "sci2") +{ + has_trace = true; +} + +h8s2655_device::h8s2655_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + h8s2600_device(mconfig, H8S2655, "H8S/2655", tag, owner, clock, "h8s2655", __FILE__, address_map_delegate(FUNC(h8s2655_device::map), this)), + intc(*this, "intc"), + adc(*this, "adc"), + port1(*this, "port1"), + port2(*this, "port2"), + port3(*this, "port3"), + port4(*this, "port4"), + port5(*this, "port5"), + port6(*this, "port6"), + porta(*this, "porta"), + portb(*this, "portb"), + portc(*this, "portc"), + portd(*this, "portd"), + porte(*this, "porte"), + portf(*this, "portf"), + portg(*this, "portg"), + timer8_0(*this, "timer8_0"), + timer8_1(*this, "timer8_1"), + timer16(*this, "timer16"), + timer16_0(*this, "timer16:0"), + timer16_1(*this, "timer16:1"), + timer16_2(*this, "timer16:2"), + timer16_3(*this, "timer16:3"), + timer16_4(*this, "timer16:4"), + timer16_5(*this, "timer16:5"), + sci0(*this, "sci0"), + sci1(*this, "sci1"), + sci2(*this, "sci2") + +{ + has_trace = true; +} + +h8s2653_device::h8s2653_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + h8s2655_device(mconfig, H8S2653, "H8S/2653", tag, owner, clock, "h8s2653", __FILE__) +{ +} + +static MACHINE_CONFIG_FRAGMENT(h8s2655) + MCFG_H8S_INTC_ADD("intc") + MCFG_H8_ADC_2655_ADD("adc", "intc", 28) + MCFG_H8_PORT_ADD("port1", h8_device::PORT_1, 0x00, 0x00) + MCFG_H8_PORT_ADD("port2", h8_device::PORT_2, 0x00, 0x00) + MCFG_H8_PORT_ADD("port3", h8_device::PORT_3, 0xc0, 0xc0) + MCFG_H8_PORT_ADD("port4", h8_device::PORT_4, 0x00, 0x00) + MCFG_H8_PORT_ADD("port5", h8_device::PORT_5, 0xf0, 0xf0) + MCFG_H8_PORT_ADD("port6", h8_device::PORT_6, 0x00, 0x00) + MCFG_H8_PORT_ADD("porta", h8_device::PORT_A, 0x00, 0x00) + MCFG_H8_PORT_ADD("portb", h8_device::PORT_B, 0x00, 0x00) + MCFG_H8_PORT_ADD("portc", h8_device::PORT_C, 0x00, 0x00) + MCFG_H8_PORT_ADD("portd", h8_device::PORT_D, 0x00, 0x00) + MCFG_H8_PORT_ADD("porte", h8_device::PORT_E, 0x00, 0x00) + MCFG_H8_PORT_ADD("portf", h8_device::PORT_F, 0x00, 0x00) + MCFG_H8_PORT_ADD("portg", h8_device::PORT_G, 0xe0, 0xe0) + MCFG_H8H_TIMER8_CHANNEL_ADD("timer8_0", "intc", 64, 65, 66, "timer8_1", h8_timer8_channel_device::CHAIN_OVERFLOW, true, false) + MCFG_H8H_TIMER8_CHANNEL_ADD("timer8_1", "intc", 68, 69, 70, "timer8_0", h8_timer8_channel_device::CHAIN_A, false, false) + MCFG_H8_TIMER16_ADD("timer16", 6, 0x00) + MCFG_H8S_TIMER16_CHANNEL_ADD("timer16:0", 4, 0x60, "intc", 32, + h8_timer16_channel_device::DIV_1, + h8_timer16_channel_device::DIV_4, + h8_timer16_channel_device::DIV_16, + h8_timer16_channel_device::DIV_64, + h8_timer16_channel_device::INPUT_A, + h8_timer16_channel_device::INPUT_B, + h8_timer16_channel_device::INPUT_C, + h8_timer16_channel_device::INPUT_D) + MCFG_H8S_TIMER16_CHANNEL_ADD("timer16:1", 2, 0x4c, "intc", 40, + h8_timer16_channel_device::DIV_1, + h8_timer16_channel_device::DIV_4, + h8_timer16_channel_device::DIV_16, + h8_timer16_channel_device::DIV_64, + h8_timer16_channel_device::INPUT_A, + h8_timer16_channel_device::INPUT_B, + h8_timer16_channel_device::DIV_256, + h8_timer16_channel_device::CHAIN) + MCFG_H8S_TIMER16_CHANNEL_SET_CHAIN("timer16:2") + MCFG_H8S_TIMER16_CHANNEL_ADD("timer16:2", 2, 0x4c, "intc", 44, + h8_timer16_channel_device::DIV_1, + h8_timer16_channel_device::DIV_4, + h8_timer16_channel_device::DIV_16, + h8_timer16_channel_device::DIV_64, + h8_timer16_channel_device::INPUT_A, + h8_timer16_channel_device::INPUT_B, + h8_timer16_channel_device::INPUT_C, + h8_timer16_channel_device::DIV_1024) + MCFG_H8S_TIMER16_CHANNEL_ADD("timer16:3", 4, 0x60, "intc", 48, + h8_timer16_channel_device::DIV_1, + h8_timer16_channel_device::DIV_4, + h8_timer16_channel_device::DIV_16, + h8_timer16_channel_device::DIV_64, + h8_timer16_channel_device::INPUT_A, + h8_timer16_channel_device::DIV_1024, + h8_timer16_channel_device::DIV_256, + h8_timer16_channel_device::DIV_4096) + MCFG_H8S_TIMER16_CHANNEL_ADD("timer16:4", 2, 0x4c, "intc", 56, + h8_timer16_channel_device::DIV_1, + h8_timer16_channel_device::DIV_4, + h8_timer16_channel_device::DIV_16, + h8_timer16_channel_device::DIV_64, + h8_timer16_channel_device::INPUT_A, + h8_timer16_channel_device::INPUT_C, + h8_timer16_channel_device::DIV_1024, + h8_timer16_channel_device::CHAIN) + MCFG_H8S_TIMER16_CHANNEL_SET_CHAIN("timer16:5") + MCFG_H8S_TIMER16_CHANNEL_ADD("timer16:5", 2, 0x4c, "intc", 60, + h8_timer16_channel_device::DIV_1, + h8_timer16_channel_device::DIV_4, + h8_timer16_channel_device::DIV_16, + h8_timer16_channel_device::DIV_64, + h8_timer16_channel_device::INPUT_A, + h8_timer16_channel_device::INPUT_C, + h8_timer16_channel_device::DIV_256, + h8_timer16_channel_device::INPUT_D) + MCFG_H8_SCI_ADD("sci0", "intc", 80, 81, 82, 83) + MCFG_H8_SCI_ADD("sci1", "intc", 84, 85, 86, 87) + MCFG_H8_SCI_ADD("sci2", "intc", 88, 89, 90, 91) +MACHINE_CONFIG_END + +DEVICE_ADDRESS_MAP_START(map, 16, h8s2655_device) + AM_RANGE(0xffec00, 0xfffbff) AM_RAM + AM_RANGE(0xfffe80, 0xfffe81) AM_DEVREADWRITE8("timer16:3", h8_timer16_channel_device, tcr_r, tcr_w, 0xff00) + AM_RANGE(0xfffe80, 0xfffe81) AM_DEVREADWRITE8("timer16:3", h8_timer16_channel_device, tmdr_r, tmdr_w, 0x00ff) + AM_RANGE(0xfffe82, 0xfffe83) AM_DEVREADWRITE8("timer16:3", h8_timer16_channel_device, tior_r, tior_w, 0xffff) + AM_RANGE(0xfffe84, 0xfffe85) AM_DEVREADWRITE8("timer16:3", h8_timer16_channel_device, tier_r, tier_w, 0xff00) + AM_RANGE(0xfffe84, 0xfffe85) AM_DEVREADWRITE8("timer16:3", h8_timer16_channel_device, tsr_r, tsr_w, 0x00ff) + AM_RANGE(0xfffe86, 0xfffe87) AM_DEVREADWRITE( "timer16:3", h8_timer16_channel_device, tcnt_r, tcnt_w ) + AM_RANGE(0xfffe88, 0xfffe8f) AM_DEVREADWRITE( "timer16:3", h8_timer16_channel_device, tgr_r, tgr_w ) + AM_RANGE(0xfffe90, 0xfffe91) AM_DEVREADWRITE8("timer16:4", h8_timer16_channel_device, tcr_r, tcr_w, 0xff00) + AM_RANGE(0xfffe90, 0xfffe91) AM_DEVREADWRITE8("timer16:4", h8_timer16_channel_device, tmdr_r, tmdr_w, 0x00ff) + AM_RANGE(0xfffe92, 0xfffe93) AM_DEVREADWRITE8("timer16:4", h8_timer16_channel_device, tior_r, tior_w, 0xff00) + AM_RANGE(0xfffe94, 0xfffe95) AM_DEVREADWRITE8("timer16:4", h8_timer16_channel_device, tier_r, tier_w, 0xff00) + AM_RANGE(0xfffe94, 0xfffe95) AM_DEVREADWRITE8("timer16:4", h8_timer16_channel_device, tsr_r, tsr_w, 0x00ff) + AM_RANGE(0xfffe96, 0xfffe97) AM_DEVREADWRITE( "timer16:4", h8_timer16_channel_device, tcnt_r, tcnt_w ) + AM_RANGE(0xfffe98, 0xfffe9b) AM_DEVREADWRITE( "timer16:4", h8_timer16_channel_device, tgr_r, tgr_w ) + AM_RANGE(0xfffea0, 0xfffea1) AM_DEVREADWRITE8("timer16:5", h8_timer16_channel_device, tcr_r, tcr_w, 0xff00) + AM_RANGE(0xfffea0, 0xfffea1) AM_DEVREADWRITE8("timer16:5", h8_timer16_channel_device, tmdr_r, tmdr_w, 0x00ff) + AM_RANGE(0xfffea2, 0xfffea3) AM_DEVREADWRITE8("timer16:5", h8_timer16_channel_device, tior_r, tior_w, 0xff00) + AM_RANGE(0xfffea4, 0xfffea5) AM_DEVREADWRITE8("timer16:5", h8_timer16_channel_device, tier_r, tier_w, 0xff00) + AM_RANGE(0xfffea4, 0xfffea5) AM_DEVREADWRITE8("timer16:5", h8_timer16_channel_device, tsr_r, tsr_w, 0x00ff) + AM_RANGE(0xfffea6, 0xfffea7) AM_DEVREADWRITE( "timer16:5", h8_timer16_channel_device, tcnt_r, tcnt_w ) + AM_RANGE(0xfffea8, 0xfffeab) AM_DEVREADWRITE( "timer16:5", h8_timer16_channel_device, tgr_r, tgr_w ) + AM_RANGE(0xfffeb0, 0xfffeb1) AM_DEVWRITE8( "port1", h8_port_device, ddr_w, 0xff00) + AM_RANGE(0xfffeb0, 0xfffeb1) AM_DEVWRITE8( "port2", h8_port_device, ddr_w, 0x00ff) + AM_RANGE(0xfffeb2, 0xfffeb3) AM_DEVWRITE8( "port3", h8_port_device, ddr_w, 0xff00) + AM_RANGE(0xfffeb4, 0xfffeb5) AM_DEVWRITE8( "port5", h8_port_device, ddr_w, 0xff00) + AM_RANGE(0xfffeb4, 0xfffeb5) AM_DEVWRITE8( "port6", h8_port_device, ddr_w, 0x00ff) + AM_RANGE(0xfffeb8, 0xfffeb9) AM_DEVWRITE8( "porta", h8_port_device, ddr_w, 0x00ff) + AM_RANGE(0xfffeba, 0xfffebb) AM_DEVWRITE8( "portb", h8_port_device, ddr_w, 0xff00) + AM_RANGE(0xfffeba, 0xfffebb) AM_DEVWRITE8( "portc", h8_port_device, ddr_w, 0x00ff) + AM_RANGE(0xfffebc, 0xfffebd) AM_DEVWRITE8( "portd", h8_port_device, ddr_w, 0xff00) + AM_RANGE(0xfffebc, 0xfffebd) AM_DEVWRITE8( "porte", h8_port_device, ddr_w, 0x00ff) + AM_RANGE(0xfffebe, 0xfffebf) AM_DEVWRITE8( "portf", h8_port_device, ddr_w, 0xff00) + AM_RANGE(0xfffebe, 0xfffebf) AM_DEVWRITE8( "portg", h8_port_device, ddr_w, 0x00ff) + AM_RANGE(0xfffec0, 0xfffec1) AM_DEVREADWRITE8("intc", h8s_intc_device, icr_r, icr_w, 0xffff) + AM_RANGE(0xfffec2, 0xfffec3) AM_DEVREADWRITE8("intc", h8s_intc_device, icrc_r, icrc_w, 0xff00) + AM_RANGE(0xfffec4, 0xfffecd) AM_DEVREADWRITE8("intc", h8s_intc_device, ipr_r, ipr_w, 0xffff) + AM_RANGE(0xfffece, 0xfffecf) AM_DEVREADWRITE8("intc", h8s_intc_device, iprk_r, iprk_w, 0xff00) + AM_RANGE(0xffff2c, 0xffff2d) AM_DEVREADWRITE8("intc", h8s_intc_device, iscrh_r, iscrh_w, 0xff00) + AM_RANGE(0xffff2c, 0xffff2d) AM_DEVREADWRITE8("intc", h8s_intc_device, iscrl_r, iscrl_w, 0x00ff) + AM_RANGE(0xffff2e, 0xffff2f) AM_DEVREADWRITE8("intc", h8s_intc_device, ier_r, ier_w, 0xff00) + AM_RANGE(0xffff2e, 0xffff2f) AM_DEVREADWRITE8("intc", h8s_intc_device, isr_r, isr_w, 0x00ff) + AM_RANGE(0xffff38, 0xffff39) AM_READWRITE8( syscr_r, syscr_w, 0x00ff) + AM_RANGE(0xffff50, 0xffff51) AM_DEVREAD8( "port1", h8_port_device, port_r, 0xff00) + AM_RANGE(0xffff50, 0xffff51) AM_DEVREAD8( "port2", h8_port_device, port_r, 0x00ff) + AM_RANGE(0xffff52, 0xffff53) AM_DEVREAD8( "port3", h8_port_device, port_r, 0xff00) + AM_RANGE(0xffff52, 0xffff53) AM_DEVREAD8( "port4", h8_port_device, port_r, 0x00ff) + AM_RANGE(0xffff54, 0xffff55) AM_DEVREAD8( "port5", h8_port_device, port_r, 0xff00) + AM_RANGE(0xffff54, 0xffff55) AM_DEVREAD8( "port6", h8_port_device, port_r, 0x00ff) + AM_RANGE(0xffff58, 0xffff59) AM_DEVREAD8( "porta", h8_port_device, port_r, 0x00ff) + AM_RANGE(0xffff5a, 0xffff5b) AM_DEVREAD8( "portb", h8_port_device, port_r, 0xff00) + AM_RANGE(0xffff5a, 0xffff5b) AM_DEVREAD8( "portc", h8_port_device, port_r, 0x00ff) + AM_RANGE(0xffff5c, 0xffff5d) AM_DEVREAD8( "portd", h8_port_device, port_r, 0xff00) + AM_RANGE(0xffff5c, 0xffff5d) AM_DEVREAD8( "porte", h8_port_device, port_r, 0x00ff) + AM_RANGE(0xffff5e, 0xffff5f) AM_DEVREAD8( "portf", h8_port_device, port_r, 0xff00) + AM_RANGE(0xffff5e, 0xffff5f) AM_DEVREAD8( "portg", h8_port_device, port_r, 0x00ff) + AM_RANGE(0xffff60, 0xffff61) AM_DEVREADWRITE8("port1", h8_port_device, dr_r, dr_w, 0xff00) + AM_RANGE(0xffff60, 0xffff61) AM_DEVREADWRITE8("port2", h8_port_device, dr_r, dr_w, 0x00ff) + AM_RANGE(0xffff62, 0xffff63) AM_DEVREADWRITE8("port3", h8_port_device, dr_r, dr_w, 0xff00) + AM_RANGE(0xffff64, 0xffff65) AM_DEVREADWRITE8("port5", h8_port_device, dr_r, dr_w, 0xff00) + AM_RANGE(0xffff64, 0xffff65) AM_DEVREADWRITE8("port6", h8_port_device, dr_r, dr_w, 0x00ff) + AM_RANGE(0xffff68, 0xffff69) AM_DEVREADWRITE8("porta", h8_port_device, dr_r, dr_w, 0x00ff) + AM_RANGE(0xffff6a, 0xffff6b) AM_DEVREADWRITE8("portb", h8_port_device, dr_r, dr_w, 0xff00) + AM_RANGE(0xffff6a, 0xffff6b) AM_DEVREADWRITE8("portc", h8_port_device, dr_r, dr_w, 0x00ff) + AM_RANGE(0xffff6c, 0xffff6d) AM_DEVREADWRITE8("portd", h8_port_device, dr_r, dr_w, 0xff00) + AM_RANGE(0xffff6c, 0xffff6d) AM_DEVREADWRITE8("porte", h8_port_device, dr_r, dr_w, 0x00ff) + AM_RANGE(0xffff6e, 0xffff6f) AM_DEVREADWRITE8("portf", h8_port_device, dr_r, dr_w, 0xff00) + AM_RANGE(0xffff6e, 0xffff6f) AM_DEVREADWRITE8("portg", h8_port_device, dr_r, dr_w, 0x00ff) + AM_RANGE(0xffff70, 0xffff71) AM_DEVREADWRITE8("porta", h8_port_device, pcr_r, pcr_w, 0xff00) + AM_RANGE(0xffff70, 0xffff71) AM_DEVREADWRITE8("portb", h8_port_device, pcr_r, pcr_w, 0x00ff) + AM_RANGE(0xffff72, 0xffff73) AM_DEVREADWRITE8("portc", h8_port_device, pcr_r, pcr_w, 0xff00) + AM_RANGE(0xffff72, 0xffff73) AM_DEVREADWRITE8("portd", h8_port_device, pcr_r, pcr_w, 0x00ff) + AM_RANGE(0xffff74, 0xffff75) AM_DEVREADWRITE8("porte", h8_port_device, pcr_r, pcr_w, 0xff00) + AM_RANGE(0xffff76, 0xffff77) AM_DEVREADWRITE8("port3", h8_port_device, odr_r, odr_w, 0xff00) + AM_RANGE(0xffff76, 0xffff77) AM_DEVREADWRITE8("porta", h8_port_device, odr_r, odr_w, 0x00ff) + AM_RANGE(0xffff78, 0xffff79) AM_DEVREADWRITE8("sci0", h8_sci_device, smr_r, smr_w, 0xff00) + AM_RANGE(0xffff78, 0xffff79) AM_DEVREADWRITE8("sci0", h8_sci_device, brr_r, brr_w, 0x00ff) + AM_RANGE(0xffff7a, 0xffff7b) AM_DEVREADWRITE8("sci0", h8_sci_device, scr_r, scr_w, 0xff00) + AM_RANGE(0xffff7a, 0xffff7b) AM_DEVREADWRITE8("sci0", h8_sci_device, tdr_r, tdr_w, 0x00ff) + AM_RANGE(0xffff7c, 0xffff7d) AM_DEVREADWRITE8("sci0", h8_sci_device, ssr_r, ssr_w, 0xff00) + AM_RANGE(0xffff7c, 0xffff7d) AM_DEVREAD8( "sci0", h8_sci_device, rdr_r, 0x00ff) + AM_RANGE(0xffff7e, 0xffff7f) AM_DEVREADWRITE8("sci0", h8_sci_device, scmr_r, scmr_w, 0xff00) + AM_RANGE(0xffff80, 0xffff81) AM_DEVREADWRITE8("sci1", h8_sci_device, smr_r, smr_w, 0xff00) + AM_RANGE(0xffff80, 0xffff81) AM_DEVREADWRITE8("sci1", h8_sci_device, brr_r, brr_w, 0x00ff) + AM_RANGE(0xffff82, 0xffff83) AM_DEVREADWRITE8("sci1", h8_sci_device, scr_r, scr_w, 0xff00) + AM_RANGE(0xffff82, 0xffff83) AM_DEVREADWRITE8("sci1", h8_sci_device, tdr_r, tdr_w, 0x00ff) + AM_RANGE(0xffff84, 0xffff85) AM_DEVREADWRITE8("sci1", h8_sci_device, ssr_r, ssr_w, 0xff00) + AM_RANGE(0xffff84, 0xffff85) AM_DEVREAD8( "sci1", h8_sci_device, rdr_r, 0x00ff) + AM_RANGE(0xffff86, 0xffff87) AM_DEVREADWRITE8("sci1", h8_sci_device, scmr_r, scmr_w, 0xff00) + AM_RANGE(0xffff88, 0xffff89) AM_DEVREADWRITE8("sci2", h8_sci_device, smr_r, smr_w, 0xff00) + AM_RANGE(0xffff88, 0xffff89) AM_DEVREADWRITE8("sci2", h8_sci_device, brr_r, brr_w, 0x00ff) + AM_RANGE(0xffff8a, 0xffff8b) AM_DEVREADWRITE8("sci2", h8_sci_device, scr_r, scr_w, 0xff00) + AM_RANGE(0xffff8a, 0xffff8b) AM_DEVREADWRITE8("sci2", h8_sci_device, tdr_r, tdr_w, 0x00ff) + AM_RANGE(0xffff8c, 0xffff8d) AM_DEVREADWRITE8("sci2", h8_sci_device, ssr_r, ssr_w, 0xff00) + AM_RANGE(0xffff8c, 0xffff8d) AM_DEVREAD8( "sci2", h8_sci_device, rdr_r, 0x00ff) + AM_RANGE(0xffff8e, 0xffff8f) AM_DEVREADWRITE8("sci2", h8_sci_device, scmr_r, scmr_w, 0xff00) + AM_RANGE(0xffff90, 0xffff9f) AM_DEVREAD( "adc", h8_adc_device, addr16_r ) + AM_RANGE(0xffffa0, 0xffffa1) AM_DEVREADWRITE8("adc", h8_adc_device, adcsr_r, adcsr_w, 0xff00) + AM_RANGE(0xffffa0, 0xffffa1) AM_DEVREADWRITE8("adc", h8_adc_device, adcr_r, adcr_w, 0x00ff) + AM_RANGE(0xffffb0, 0xffffb1) AM_DEVREADWRITE8("timer8_0", h8_timer8_channel_device, tcr_r, tcr_w, 0xff00) + AM_RANGE(0xffffb0, 0xffffb1) AM_DEVREADWRITE8("timer8_1", h8_timer8_channel_device, tcr_r, tcr_w, 0x00ff) + AM_RANGE(0xffffb2, 0xffffb3) AM_DEVREADWRITE8("timer8_0", h8_timer8_channel_device, tcsr_r, tcsr_w, 0xff00) + AM_RANGE(0xffffb2, 0xffffb3) AM_DEVREADWRITE8("timer8_1", h8_timer8_channel_device, tcsr_r, tcsr_w, 0x00ff) + AM_RANGE(0xffffb4, 0xffffb7) AM_DEVREADWRITE8("timer8_0", h8_timer8_channel_device, tcor_r, tcor_w, 0xff00) + AM_RANGE(0xffffb4, 0xffffb7) AM_DEVREADWRITE8("timer8_1", h8_timer8_channel_device, tcor_r, tcor_w, 0x00ff) + AM_RANGE(0xffffb8, 0xffffb9) AM_DEVREADWRITE8("timer8_0", h8_timer8_channel_device, tcnt_r, tcnt_w, 0xff00) + AM_RANGE(0xffffb8, 0xffffb9) AM_DEVREADWRITE8("timer8_1", h8_timer8_channel_device, tcnt_r, tcnt_w, 0x00ff) + AM_RANGE(0xffffc0, 0xffffc1) AM_DEVREADWRITE8("timer16", h8_timer16_device, tstr_r, tstr_w, 0xff00) + AM_RANGE(0xffffc0, 0xffffc1) AM_DEVREADWRITE8("timer16", h8_timer16_device, tsyr_r, tsyr_w, 0x00ff) + AM_RANGE(0xffffd0, 0xffffd1) AM_DEVREADWRITE8("timer16:0", h8_timer16_channel_device, tcr_r, tcr_w, 0xff00) + AM_RANGE(0xffffd0, 0xffffd1) AM_DEVREADWRITE8("timer16:0", h8_timer16_channel_device, tmdr_r, tmdr_w, 0x00ff) + AM_RANGE(0xffffd2, 0xffffd3) AM_DEVREADWRITE8("timer16:0", h8_timer16_channel_device, tior_r, tior_w, 0xffff) + AM_RANGE(0xffffd4, 0xffffd5) AM_DEVREADWRITE8("timer16:0", h8_timer16_channel_device, tier_r, tier_w, 0xff00) + AM_RANGE(0xffffd4, 0xffffd5) AM_DEVREADWRITE8("timer16:0", h8_timer16_channel_device, tsr_r, tsr_w, 0x00ff) + AM_RANGE(0xffffd6, 0xffffd7) AM_DEVREADWRITE( "timer16:0", h8_timer16_channel_device, tcnt_r, tcnt_w ) + AM_RANGE(0xffffd8, 0xffffdf) AM_DEVREADWRITE( "timer16:0", h8_timer16_channel_device, tgr_r, tgr_w ) + AM_RANGE(0xffffe0, 0xffffe1) AM_DEVREADWRITE8("timer16:1", h8_timer16_channel_device, tcr_r, tcr_w, 0xff00) + AM_RANGE(0xffffe0, 0xffffe1) AM_DEVREADWRITE8("timer16:1", h8_timer16_channel_device, tmdr_r, tmdr_w, 0x00ff) + AM_RANGE(0xffffe2, 0xffffe3) AM_DEVREADWRITE8("timer16:1", h8_timer16_channel_device, tior_r, tior_w, 0xff00) + AM_RANGE(0xffffe4, 0xffffe5) AM_DEVREADWRITE8("timer16:1", h8_timer16_channel_device, tier_r, tier_w, 0xff00) + AM_RANGE(0xffffe4, 0xffffe5) AM_DEVREADWRITE8("timer16:1", h8_timer16_channel_device, tsr_r, tsr_w, 0x00ff) + AM_RANGE(0xffffe6, 0xffffe7) AM_DEVREADWRITE( "timer16:1", h8_timer16_channel_device, tcnt_r, tcnt_w ) + AM_RANGE(0xffffe8, 0xffffeb) AM_DEVREADWRITE( "timer16:1", h8_timer16_channel_device, tgr_r, tgr_w ) + AM_RANGE(0xfffff0, 0xfffff1) AM_DEVREADWRITE8("timer16:2", h8_timer16_channel_device, tcr_r, tcr_w, 0xff00) + AM_RANGE(0xfffff0, 0xfffff1) AM_DEVREADWRITE8("timer16:2", h8_timer16_channel_device, tmdr_r, tmdr_w, 0x00ff) + AM_RANGE(0xfffff2, 0xfffff3) AM_DEVREADWRITE8("timer16:2", h8_timer16_channel_device, tior_r, tior_w, 0xff00) + AM_RANGE(0xfffff4, 0xfffff5) AM_DEVREADWRITE8("timer16:2", h8_timer16_channel_device, tier_r, tier_w, 0xff00) + AM_RANGE(0xfffff4, 0xfffff5) AM_DEVREADWRITE8("timer16:2", h8_timer16_channel_device, tsr_r, tsr_w, 0x00ff) + AM_RANGE(0xfffff6, 0xfffff7) AM_DEVREADWRITE( "timer16:2", h8_timer16_channel_device, tcnt_r, tcnt_w ) + AM_RANGE(0xfffff8, 0xfffffb) AM_DEVREADWRITE( "timer16:2", h8_timer16_channel_device, tgr_r, tgr_w ) +ADDRESS_MAP_END + +machine_config_constructor h8s2655_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME(h8s2655); +} + +void h8s2655_device::execute_set_input(int inputnum, int state) +{ + intc->set_input(inputnum, state); +} + +bool h8s2655_device::exr_in_stack() const +{ + return syscr & 0x20; +} + +int h8s2655_device::trace_setup() +{ + if(syscr & 0x10) + CCR |= F_I|F_UI; + else + CCR |= F_I; + EXR &= ~EXR_T; + return 5; +} + +int h8s2655_device::trapa_setup() +{ + if(syscr & 0x10) + CCR |= F_I|F_UI; + else + CCR |= F_I; + if(syscr & 0x20) + EXR &= ~EXR_T; + return 8; +} + +void h8s2655_device::irq_setup() +{ + switch(syscr & 0x30) { + case 0x00: + CCR |= F_I; + break; + case 0x10: + CCR |= F_I|F_UI; + break; + case 0x20: + EXR = EXR & (EXR_NC); + if(taken_irq_level == 8) + EXR |= 7; + else + EXR |= taken_irq_level; + break; + case 0x30: + CCR |= F_I|F_UI; + EXR = EXR & (EXR_NC); + if(taken_irq_level == 8) + EXR |= 7; + else + EXR |= taken_irq_level; + break; + } +} + +void h8s2655_device::update_irq_filter() +{ + switch(syscr & 0x30) { + case 0x00: + if(CCR & F_I) + intc->set_filter(2, -1); + else + intc->set_filter(0, -1); + break; + case 0x10: + if((CCR & (F_I|F_UI)) == (F_I|F_UI)) + intc->set_filter(2, -1); + else if(CCR & F_I) + intc->set_filter(1, -1); + else + intc->set_filter(0, -1); + break; + case 0x20: + intc->set_filter(0, EXR & 7); + break; + case 0x30: + if((CCR & (F_I|F_UI)) == (F_I|F_UI)) + intc->set_filter(2, EXR & 7); + else if(CCR & F_I) + intc->set_filter(1, EXR & 7); + else + intc->set_filter(0, EXR & 7); + break; + } +} + +void h8s2655_device::interrupt_taken() +{ + standard_irq_callback(intc->interrupt_taken(taken_irq_vector)); +} + +void h8s2655_device::internal_update(UINT64 current_time) +{ + UINT64 event_time = 0; + + add_event(event_time, adc->internal_update(current_time)); + add_event(event_time, sci0->internal_update(current_time)); + add_event(event_time, sci1->internal_update(current_time)); + add_event(event_time, sci2->internal_update(current_time)); + add_event(event_time, timer8_0->internal_update(current_time)); + add_event(event_time, timer8_1->internal_update(current_time)); + add_event(event_time, timer16_0->internal_update(current_time)); + add_event(event_time, timer16_1->internal_update(current_time)); + add_event(event_time, timer16_2->internal_update(current_time)); + add_event(event_time, timer16_3->internal_update(current_time)); + add_event(event_time, timer16_4->internal_update(current_time)); + add_event(event_time, timer16_5->internal_update(current_time)); + + recompute_bcount(event_time); +} + +void h8s2655_device::device_start() +{ + h8s2600_device::device_start(); +} + +void h8s2655_device::device_reset() +{ + h8s2600_device::device_reset(); + syscr = 0x01; +} + +READ8_MEMBER(h8s2655_device::syscr_r) +{ + return syscr; +} + +WRITE8_MEMBER(h8s2655_device::syscr_w) +{ + syscr = data; + update_irq_filter(); + logerror("%s: syscr = %02x\n", tag(), data); +} diff --git a/src/devices/cpu/h8/h8s2655.h b/src/devices/cpu/h8/h8s2655.h new file mode 100644 index 00000000000..89b76187bd1 --- /dev/null +++ b/src/devices/cpu/h8/h8s2655.h @@ -0,0 +1,88 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +/*************************************************************************** + + h8s2655.h + + H8S-2655 family emulation (H8S/2653 and H8S/2655) + + They're both H8S/2600-based mcus, with 128K internal rom for the 2655 + and 64K for the 2653. + + +***************************************************************************/ + +#ifndef __H8S2655_H__ +#define __H8S2655_H__ + +#include "h8s2600.h" +#include "h8_adc.h" +#include "h8_port.h" +#include "h8_intc.h" +#include "h8_timer8.h" +#include "h8_timer16.h" +#include "h8_sci.h" + +class h8s2655_device : public h8s2600_device { +public: + h8s2655_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + h8s2655_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + DECLARE_READ8_MEMBER(syscr_r); + DECLARE_WRITE8_MEMBER(syscr_w); + +protected: + required_device intc; + required_device adc; + required_device port1; + required_device port2; + required_device port3; + required_device port4; + required_device port5; + required_device port6; + required_device porta; + required_device portb; + required_device portc; + required_device portd; + required_device porte; + required_device portf; + required_device portg; + required_device timer8_0; + required_device timer8_1; + required_device timer16; + required_device timer16_0; + required_device timer16_1; + required_device timer16_2; + required_device timer16_3; + required_device timer16_4; + required_device timer16_5; + required_device sci0; + required_device sci1; + required_device sci2; + + UINT8 syscr; + + virtual bool exr_in_stack() const; + virtual void update_irq_filter(); + virtual void interrupt_taken(); + virtual int trace_setup(); + virtual int trapa_setup(); + virtual void irq_setup(); + virtual void internal_update(UINT64 current_time); + virtual machine_config_constructor device_mconfig_additions() const; + DECLARE_ADDRESS_MAP(map, 16); + + virtual void device_start(); + virtual void device_reset(); + virtual void execute_set_input(int inputnum, int state); +}; + +class h8s2653_device : public h8s2655_device { +public: + h8s2653_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +extern const device_type H8S2655; +extern const device_type H8S2653; + +#endif diff --git a/src/devices/cpu/hcd62121/hcd62121.c b/src/devices/cpu/hcd62121/hcd62121.c new file mode 100644 index 00000000000..f45ebdbe03d --- /dev/null +++ b/src/devices/cpu/hcd62121/hcd62121.c @@ -0,0 +1,530 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +/********************************************************************** + + Hitachi hcd62121 cpu core emulation. + +The Hitachi hcd62121 is the custom cpu which was used in the Casio +CFX-9850 (and maybe some other things too). + +This CPU core is based on the information provided by Martin Poupe. +Martin Poupe's site can be found at http://martin.poupe.org/casio/ + +**********************************************************************/ + +#include "emu.h" +#include "debugger.h" +#include "hcd62121.h" + + +/* From the battery check routine at 20:e874 it looks like + bit 3 of the flag register should be the Zero flag. */ +#define _FLAG_Z 0x08 +#define _FLAG_C 0x02 +#define _FLAG_ZL 0x04 +#define _FLAG_CL 0x01 +#define _FLAG_ZH 0x10 + + +const device_type HCD62121 = &device_creator; + + +hcd62121_cpu_device::hcd62121_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : cpu_device(mconfig, HCD62121, "Hitachi HCD62121", tag, owner, clock, "hcd62121", __FILE__) + , m_program_config("program", ENDIANNESS_BIG, 8, 24, 0) + , m_io_config("io", ENDIANNESS_BIG, 8, 8, 0) + , m_sp(0) + , m_ip(0) + , m_dsize(0) + , m_cseg(0) + , m_dseg(0) + , m_sseg(0) + , m_f(0) + , m_lar(0) +{ +} + + +UINT8 hcd62121_cpu_device::read_op() +{ + UINT8 d = m_program->read_byte( ( m_cseg << 16 ) | m_ip ); + m_ip++; + return d; +} + + +UINT8 hcd62121_cpu_device::datasize( UINT8 op ) +{ + switch( op & 0x03 ) + { + case 0: + return 1; + case 1: + return 2; + case 2: + return ( m_dsize >> 4 ) + 1; + case 3: + return ( m_dsize & 0x0f ) + 1; + } + return 1; +} + + +void hcd62121_cpu_device::read_reg( int size, UINT8 op1 ) +{ + int i; + + if ( op1 & 0x80 ) + { + for ( i = 0; i < size; i++ ) + m_temp1[i] = m_reg[ ( op1 - i ) & 0x7f ]; + } + else + { + for ( i = 0; i < size; i++ ) + m_temp1[i] = m_reg[ ( op1 + i ) & 0x7f ]; + } +} + + +void hcd62121_cpu_device::write_reg( int size, UINT8 op1 ) +{ + int i; + + if ( op1 & 0x80 ) + { + for ( i = 0; i < size; i++ ) + m_reg[ ( op1 - i ) & 0x7f ] = m_temp1[i]; + } + else + { + for ( i = 0; i < size; i++ ) + m_reg[ ( op1 + i ) & 0x7f ] = m_temp1[i]; + } +} + + +void hcd62121_cpu_device::read_regreg( int size, UINT8 op1, UINT8 op2, bool op_is_logical ) +{ + int i; + + for ( i = 0; i < size; i++ ) + m_temp1[i] = m_reg[ (op1 + i) & 0x7f]; + + if ( op1 & 0x80 ) + { + /* Second operand is an immediate value */ + m_temp2[0] = op2; + for ( i = 1; i < size; i++ ) + m_temp2[i] = op_is_logical ? op2 : 0; + } + else + { + /* Second operand is a register */ + for ( i = 0; i < size; i++ ) + m_temp2[i] = m_reg[ (op2 + i) & 0x7f ]; + } + + if ( ! ( op1 & 0x80 ) && ! ( op2 & 0x80 ) ) + { + /* We need to swap parameters */ + for ( i = 0; i < size; i++ ) + { + UINT8 v = m_temp1[i]; + m_temp1[i] = m_temp2[i]; + m_temp2[i] = v; + } + } +} + + +void hcd62121_cpu_device::write_regreg( int size, UINT8 op1, UINT8 op2 ) +{ + int i; + + if ( ( op1 & 0x80 ) || ( op2 & 0x80 ) ) + { + /* store in reg1 */ + for ( i = 0; i < size; i++ ) + m_reg[ (op1 + i) & 0x7f] = m_temp1[i]; + } + else + { + /* store in reg2 */ + for ( i = 0; i < size; i++ ) + m_reg[ (op2 + i) & 0x7f] = m_temp1[i]; + } +} + + +void hcd62121_cpu_device::read_iregreg( int size, UINT8 op1, UINT8 op2 ) +{ + int i; + UINT16 ad; + + ad = m_reg[ ( 0x40 | op1 ) & 0x7f ] | ( m_reg[ ( 0x40 | ( op1 + 1 ) ) & 0x7f ] << 8 ); + + for ( i = 0; i < size; i++ ) + { + m_temp1[i] = m_program->read_byte( ( m_dseg << 16 ) | ad ); + ad += ( op1 & 0x40 ) ? -1 : 1; + } + m_lar = ad; + + if ( op1 & 0x80 ) + { + m_temp2[0] = op2; + for ( i = 1; i < size; i++ ) + m_temp2[i] = 0; + } + else + { + for ( i = 0; i < size; i++ ) + m_temp2[i] = m_reg[ (op2 + i) & 0x7f ]; + } + + if ( ! ( op1 & 0x80 ) && ! ( op2 & 0x80 ) ) + { + /* We need to swap parameters */ + for ( i = 0; i < size; i++ ) + { + UINT8 v = m_temp1[i]; + m_temp1[i] = m_temp2[i]; + m_temp2[i] = v; + } + } +} + + +void hcd62121_cpu_device::write_iregreg( int size, UINT8 op1, UINT8 op2 ) +{ + int i; + + if ( ( op1 & 0x80 ) || ( op2 & 0x80 ) ) + { + /* store in (reg1) */ + UINT16 ad = m_reg[ ( 0x40 | op1 ) & 0x7f ] | ( m_reg[ ( 0x40 | ( op1 + 1 ) ) & 0x7f ] << 8 ); + + for ( i = 0; i < size; i++ ) + { + m_program->write_byte( ( m_dseg << 16 ) | ad, m_temp1[i] ); + ad += ( op1 & 0x40 ) ? -1 : 1; + } + m_lar = ad; + } + else + { + /* store in reg2 */ + for ( i = 0; i < size; i++ ) + m_reg[ (op2 + i) & 0x7f] = m_temp1[i]; + } +} + + +void hcd62121_cpu_device::write_iregreg2( int size, UINT8 op1, UINT8 op2 ) +{ + int i; + + if ( ( op1 & 0x80 ) || ( op2 & 0x80 ) ) + { + /* store in reg2 */ + for ( i = 0; i < size; i++ ) + m_reg[ (op2 + i) & 0x7f] = m_temp2[i]; + } + else + { + /* store in (reg1) */ + UINT16 ad = m_reg[ ( 0x40 | op1 ) & 0x7f ] | ( m_reg[ ( 0x40 | ( op1 + 1 ) ) & 0x7f ] << 8 ); + + for ( i = 0; i < size; i++ ) + { + m_program->write_byte( ( m_dseg << 16 ) | ad, m_temp2[i] ); + ad += ( op1 & 0x40 ) ? -1 : 1; + } + m_lar = ad; + } +} + + +int hcd62121_cpu_device::check_cond( UINT8 op ) +{ + switch ( op & 0x07 ) + { + case 0x00: /* ZH set */ + if ( m_f & _FLAG_ZH ) + return 1; + break; + + case 0x01: /* ZL set */ + if ( m_f & _FLAG_ZL ) + return 1; + break; + + case 0x02: /* C set */ + if ( m_f & _FLAG_C ) + return 1; + break; + + case 0x03: /* Z set */ + if ( m_f & _FLAG_Z ) + return 1; + break; + + case 0x04: /* Z or C set */ + if ( m_f & ( _FLAG_Z | _FLAG_C ) ) + return 1; + break; + + case 0x05: /* CL set */ + if ( m_f & _FLAG_CL ) + return 1; + break; + + case 0x06: /* C clear */ + if ( ! ( m_f & _FLAG_C ) ) + return 1; + break; + + case 0x07: /* Z clear */ + if ( ! ( m_f & _FLAG_Z ) ) + return 1; + break; + } + + return 0; +} + + +void hcd62121_cpu_device::device_start() +{ + m_program = &space(AS_PROGRAM); + m_io = &space(AS_IO); + + save_item( NAME(m_prev_pc) ); + save_item( NAME(m_sp) ); + save_item( NAME(m_ip) ); + save_item( NAME(m_dsize) ); + save_item( NAME(m_cseg) ); + save_item( NAME(m_dseg) ); + save_item( NAME(m_sseg) ); + save_item( NAME(m_f) ); + save_item( NAME(m_lar) ); + save_item( NAME(m_reg) ); + save_item( NAME(m_temp1) ); + save_item( NAME(m_temp2) ); + + // Register state for debugger + state_add( STATE_GENPC, "curpc", m_ip ).callimport().callexport().formatstr("%8s"); + state_add( STATE_GENFLAGS, "GENFLAGS", m_f ).callimport().callexport().formatstr("%12s").noshow(); + + state_add( HCD62121_IP, "IP", m_ip ).callimport().callexport().formatstr("%04X"); + state_add( HCD62121_SP, "SP", m_sp ).callimport().callexport().formatstr("%04X"); + state_add( HCD62121_LAR, "LAR", m_lar ).callimport().callexport().formatstr("%04X"); + state_add( HCD62121_CS, "CS", m_cseg ).callimport().callexport().formatstr("%02X"); + state_add( HCD62121_DS, "DS", m_dseg ).callimport().callexport().formatstr("%02X"); + state_add( HCD62121_SS, "SS", m_sseg ).callimport().callexport().formatstr("%02X"); + state_add( HCD62121_DSIZE, "DSIZE", m_dsize ).callimport().callexport().formatstr("%02X"); + state_add( HCD62121_F, "F", m_f ).callimport().callexport().formatstr("%02X"); + + state_add( HCD62121_R00, "R00", m_reg[0x00] ).callimport().callexport().formatstr("%8s"); + state_add( HCD62121_R04, "R04", m_reg[0x00] ).callimport().callexport().formatstr("%8s"); + state_add( HCD62121_R08, "R08", m_reg[0x00] ).callimport().callexport().formatstr("%8s"); + state_add( HCD62121_R0C, "R0C", m_reg[0x00] ).callimport().callexport().formatstr("%8s"); + state_add( HCD62121_R10, "R10", m_reg[0x00] ).callimport().callexport().formatstr("%8s"); + state_add( HCD62121_R14, "R14", m_reg[0x00] ).callimport().callexport().formatstr("%8s"); + state_add( HCD62121_R18, "R18", m_reg[0x00] ).callimport().callexport().formatstr("%8s"); + state_add( HCD62121_R1C, "R1C", m_reg[0x00] ).callimport().callexport().formatstr("%8s"); + state_add( HCD62121_R20, "R20", m_reg[0x00] ).callimport().callexport().formatstr("%8s"); + state_add( HCD62121_R24, "R24", m_reg[0x00] ).callimport().callexport().formatstr("%8s"); + state_add( HCD62121_R28, "R28", m_reg[0x00] ).callimport().callexport().formatstr("%8s"); + state_add( HCD62121_R2C, "R2C", m_reg[0x00] ).callimport().callexport().formatstr("%8s"); + state_add( HCD62121_R30, "R30", m_reg[0x00] ).callimport().callexport().formatstr("%8s"); + state_add( HCD62121_R34, "R34", m_reg[0x00] ).callimport().callexport().formatstr("%8s"); + state_add( HCD62121_R38, "R38", m_reg[0x00] ).callimport().callexport().formatstr("%8s"); + state_add( HCD62121_R3C, "R3C", m_reg[0x00] ).callimport().callexport().formatstr("%8s"); + state_add( HCD62121_R40, "R40", m_reg[0x00] ).callimport().callexport().formatstr("%8s"); + state_add( HCD62121_R44, "R44", m_reg[0x00] ).callimport().callexport().formatstr("%8s"); + state_add( HCD62121_R48, "R48", m_reg[0x00] ).callimport().callexport().formatstr("%8s"); + state_add( HCD62121_R4C, "R4C", m_reg[0x00] ).callimport().callexport().formatstr("%8s"); + state_add( HCD62121_R50, "R50", m_reg[0x00] ).callimport().callexport().formatstr("%8s"); + state_add( HCD62121_R54, "R54", m_reg[0x00] ).callimport().callexport().formatstr("%8s"); + state_add( HCD62121_R58, "R58", m_reg[0x00] ).callimport().callexport().formatstr("%8s"); + state_add( HCD62121_R5C, "R5C", m_reg[0x00] ).callimport().callexport().formatstr("%8s"); + state_add( HCD62121_R60, "R60", m_reg[0x00] ).callimport().callexport().formatstr("%8s"); + state_add( HCD62121_R64, "R64", m_reg[0x00] ).callimport().callexport().formatstr("%8s"); + state_add( HCD62121_R68, "R68", m_reg[0x00] ).callimport().callexport().formatstr("%8s"); + state_add( HCD62121_R6C, "R6C", m_reg[0x00] ).callimport().callexport().formatstr("%8s"); + state_add( HCD62121_R70, "R70", m_reg[0x00] ).callimport().callexport().formatstr("%8s"); + state_add( HCD62121_R74, "R74", m_reg[0x00] ).callimport().callexport().formatstr("%8s"); + state_add( HCD62121_R78, "R78", m_reg[0x00] ).callimport().callexport().formatstr("%8s"); + state_add( HCD62121_R7C, "R7C", m_reg[0x00] ).callimport().callexport().formatstr("%8s"); + + m_icountptr = &m_icount; +} + + +void hcd62121_cpu_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + switch (entry.index()) + { + case STATE_GENPC: + strprintf(str, "%06X", (m_cseg << 16) | m_ip); + break; + + case STATE_GENFLAGS: + strprintf(str, "%s-%s-%s-%c-%c", + m_f & _FLAG_ZH ? "ZH":"__", + m_f & _FLAG_CL ? "CL":"__", + m_f & _FLAG_ZL ? "ZL":"__", + m_f & _FLAG_C ? 'C':'_', + m_f & _FLAG_Z ? 'Z':'_' + ); + + break; + + case HCD62121_R00: + strprintf(str, "%02X%02X%02X%02X", m_reg[0x00], m_reg[0x01], m_reg[0x02], m_reg[0x03]); + break; + case HCD62121_R04: + strprintf(str, "%02X%02X%02X%02X", m_reg[0x04], m_reg[0x05], m_reg[0x06], m_reg[0x07]); + break; + case HCD62121_R08: + strprintf(str, "%02X%02X%02X%02X", m_reg[0x08], m_reg[0x09], m_reg[0x0A], m_reg[0x0B]); + break; + case HCD62121_R0C: + strprintf(str, "%02X%02X%02X%02X", m_reg[0x0C], m_reg[0x0D], m_reg[0x0E], m_reg[0x0F]); + break; + case HCD62121_R10: + strprintf(str, "%02X%02X%02X%02X", m_reg[0x10], m_reg[0x11], m_reg[0x12], m_reg[0x13]); + break; + case HCD62121_R14: + strprintf(str, "%02X%02X%02X%02X", m_reg[0x14], m_reg[0x15], m_reg[0x16], m_reg[0x17]); + break; + case HCD62121_R18: + strprintf(str, "%02X%02X%02X%02X", m_reg[0x18], m_reg[0x19], m_reg[0x1A], m_reg[0x1B]); + break; + case HCD62121_R1C: + strprintf(str, "%02X%02X%02X%02X", m_reg[0x1C], m_reg[0x1D], m_reg[0x1E], m_reg[0x1F]); + break; + case HCD62121_R20: + strprintf(str, "%02X%02X%02X%02X", m_reg[0x20], m_reg[0x21], m_reg[0x22], m_reg[0x23]); + break; + case HCD62121_R24: + strprintf(str, "%02X%02X%02X%02X", m_reg[0x24], m_reg[0x25], m_reg[0x26], m_reg[0x27]); + break; + case HCD62121_R28: + strprintf(str, "%02X%02X%02X%02X", m_reg[0x28], m_reg[0x29], m_reg[0x2A], m_reg[0x2B]); + break; + case HCD62121_R2C: + strprintf(str, "%02X%02X%02X%02X", m_reg[0x2C], m_reg[0x2D], m_reg[0x2E], m_reg[0x2F]); + break; + case HCD62121_R30: + strprintf(str, "%02X%02X%02X%02X", m_reg[0x30], m_reg[0x31], m_reg[0x32], m_reg[0x33]); + break; + case HCD62121_R34: + strprintf(str, "%02X%02X%02X%02X", m_reg[0x34], m_reg[0x35], m_reg[0x36], m_reg[0x37]); + break; + case HCD62121_R38: + strprintf(str, "%02X%02X%02X%02X", m_reg[0x38], m_reg[0x39], m_reg[0x3A], m_reg[0x3B]); + break; + case HCD62121_R3C: + strprintf(str, "%02X%02X%02X%02X", m_reg[0x3C], m_reg[0x3D], m_reg[0x3E], m_reg[0x3F]); + break; + case HCD62121_R40: + strprintf(str, "%02X%02X%02X%02X", m_reg[0x40], m_reg[0x41], m_reg[0x42], m_reg[0x43]); + break; + case HCD62121_R44: + strprintf(str, "%02X%02X%02X%02X", m_reg[0x44], m_reg[0x45], m_reg[0x46], m_reg[0x47]); + break; + case HCD62121_R48: + strprintf(str, "%02X%02X%02X%02X", m_reg[0x48], m_reg[0x49], m_reg[0x4A], m_reg[0x4B]); + break; + case HCD62121_R4C: + strprintf(str, "%02X%02X%02X%02X", m_reg[0x4C], m_reg[0x4D], m_reg[0x4E], m_reg[0x4F]); + break; + case HCD62121_R50: + strprintf(str, "%02X%02X%02X%02X", m_reg[0x50], m_reg[0x51], m_reg[0x52], m_reg[0x53]); + break; + case HCD62121_R54: + strprintf(str, "%02X%02X%02X%02X", m_reg[0x54], m_reg[0x55], m_reg[0x56], m_reg[0x57]); + break; + case HCD62121_R58: + strprintf(str, "%02X%02X%02X%02X", m_reg[0x58], m_reg[0x59], m_reg[0x5A], m_reg[0x5B]); + break; + case HCD62121_R5C: + strprintf(str, "%02X%02X%02X%02X", m_reg[0x5C], m_reg[0x5D], m_reg[0x5E], m_reg[0x5F]); + break; + case HCD62121_R60: + strprintf(str, "%02X%02X%02X%02X", m_reg[0x60], m_reg[0x61], m_reg[0x62], m_reg[0x63]); + break; + case HCD62121_R64: + strprintf(str, "%02X%02X%02X%02X", m_reg[0x64], m_reg[0x65], m_reg[0x66], m_reg[0x67]); + break; + case HCD62121_R68: + strprintf(str, "%02X%02X%02X%02X", m_reg[0x68], m_reg[0x69], m_reg[0x6A], m_reg[0x6B]); + break; + case HCD62121_R6C: + strprintf(str, "%02X%02X%02X%02X", m_reg[0x6C], m_reg[0x6D], m_reg[0x6E], m_reg[0x6F]); + break; + case HCD62121_R70: + strprintf(str, "%02X%02X%02X%02X", m_reg[0x70], m_reg[0x71], m_reg[0x72], m_reg[0x73]); + break; + case HCD62121_R74: + strprintf(str, "%02X%02X%02X%02X", m_reg[0x74], m_reg[0x75], m_reg[0x76], m_reg[0x77]); + break; + case HCD62121_R78: + strprintf(str, "%02X%02X%02X%02X", m_reg[0x78], m_reg[0x79], m_reg[0x7A], m_reg[0x7B]); + break; + case HCD62121_R7C: + strprintf(str, "%02X%02X%02X%02X", m_reg[0x7C], m_reg[0x7D], m_reg[0x7E], m_reg[0x7F]); + break; + } +} + + +void hcd62121_cpu_device::device_reset() +{ + m_sp = 0x0000; + m_ip = 0x0000; + m_cseg = 0; + m_dseg = 0; + m_sseg = 0; + m_lar = 0; + m_f = 0; + m_dsize = 0; + + for( int i = 0; i < 0x80; i++ ) + { + m_reg[i] = 0; + } +} + + +void hcd62121_cpu_device::execute_run() +{ + do + { + UINT32 pc = ( m_cseg << 16 ) | m_ip; + UINT8 op; + + debugger_instruction_hook(this, pc); + m_prev_pc = pc; + + op = read_op(); + + m_icount -= 4; + + switch ( op ) + { +#include "hcd62121_ops.h" + }; + + } while (m_icount > 0); +} + + +offs_t hcd62121_cpu_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( hcd62121 ); + return CPU_DISASSEMBLE_NAME(hcd62121)(this, buffer, pc, oprom, opram, options); +} diff --git a/src/devices/cpu/hcd62121/hcd62121.h b/src/devices/cpu/hcd62121/hcd62121.h new file mode 100644 index 00000000000..feaa1bf6533 --- /dev/null +++ b/src/devices/cpu/hcd62121/hcd62121.h @@ -0,0 +1,100 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +#ifndef __HCD62121_H__ +#define __HCD62121_H__ + + +enum +{ + HCD62121_IP=1, HCD62121_SP, HCD62121_F, HCD62121_LAR, + HCD62121_CS, HCD62121_DS, HCD62121_SS, HCD62121_DSIZE, + /* 128 byte register file */ + HCD62121_R00, HCD62121_R04, HCD62121_R08, HCD62121_R0C, + HCD62121_R10, HCD62121_R14, HCD62121_R18, HCD62121_R1C, + HCD62121_R20, HCD62121_R24, HCD62121_R28, HCD62121_R2C, + HCD62121_R30, HCD62121_R34, HCD62121_R38, HCD62121_R3C, + HCD62121_R40, HCD62121_R44, HCD62121_R48, HCD62121_R4C, + HCD62121_R50, HCD62121_R54, HCD62121_R58, HCD62121_R5C, + HCD62121_R60, HCD62121_R64, HCD62121_R68, HCD62121_R6C, + HCD62121_R70, HCD62121_R74, HCD62121_R78, HCD62121_R7C +}; + + +/* I/O ports */ +enum +{ + /* Output ports */ + HCD62121_KOL=0x00, + HCD62121_KOH, + /* Input ports */ + HCD62121_KI, + /* Other I/O ports */ + HCD62121_IN0 +}; + + +class hcd62121_cpu_device : public cpu_device +{ +public: + // construction/destruction + hcd62121_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_execute_interface overrides + virtual UINT32 execute_min_cycles() const { return 4; } + virtual UINT32 execute_max_cycles() const { return 48; } + virtual UINT32 execute_input_lines() const { return 2; } + virtual void execute_run(); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const { return (spacenum == AS_PROGRAM) ? &m_program_config : ( (spacenum == AS_IO) ? &m_io_config : NULL ); } + + // device_state_interface overrides + void state_string_export(const device_state_entry &entry, std::string &str); + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const { return 1; } + virtual UINT32 disasm_max_opcode_bytes() const { return 18; } + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + + UINT8 read_op(); + UINT8 datasize( UINT8 op ); + void read_reg( int size, UINT8 op1 ); + void write_reg( int size, UINT8 op1 ); + void read_regreg( int size, UINT8 op1, UINT8 op2, bool op_is_logical ); + void write_regreg( int size, UINT8 op1, UINT8 op2 ); + void read_iregreg( int size, UINT8 op1, UINT8 op2 ); + void write_iregreg( int size, UINT8 op1, UINT8 op2 ); + void write_iregreg2( int size, UINT8 op1, UINT8 op2 ); + int check_cond( UINT8 op ); + + address_space_config m_program_config; + address_space_config m_io_config; + + UINT32 m_prev_pc; + UINT16 m_sp; + UINT16 m_ip; + UINT8 m_dsize; + UINT8 m_cseg; + UINT8 m_dseg; + UINT8 m_sseg; + UINT8 m_f; + UINT16 m_lar; + UINT8 m_reg[0x80]; + UINT8 m_temp1[0x10]; + UINT8 m_temp2[0x10]; + + address_space *m_program; + address_space *m_io; + int m_icount; +}; + + +extern const device_type HCD62121; + + +#endif /* __HCD62121_H__ */ diff --git a/src/devices/cpu/hcd62121/hcd62121_ops.h b/src/devices/cpu/hcd62121/hcd62121_ops.h new file mode 100644 index 00000000000..7ede44b3105 --- /dev/null +++ b/src/devices/cpu/hcd62121/hcd62121_ops.h @@ -0,0 +1,1023 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol + +#define HCD62121_MSK \ + { \ + int i; \ + UINT8 mskres = 1; \ + \ + for ( i = 0; i < size; i++ ) \ + { \ + if ( ( m_temp1[i] & m_temp2[i] ) != m_temp2[i] ) \ + mskres = 0; \ + } \ + \ + if ( mskres ) \ + m_f &= ~_FLAG_Z; \ + else \ + m_f |= _FLAG_Z; \ + } + +#define HCD62121_IMSK \ + { \ + int i; \ + UINT8 mskres = 1; \ + UINT8 set_zero = 0; \ + \ + for ( i = 0; i < size; i++ ) \ + { \ + if ( ( m_temp1[i] & ~m_temp2[i] ) != ~m_temp2[i] ) \ + mskres = 0; \ + if ( m_temp1[i] | m_temp2[i] ) \ + set_zero = 1; \ + } \ + \ + if ( set_zero ) \ + m_f |= _FLAG_Z; \ + else \ + m_f &= ~_FLAG_Z; \ + \ + if ( mskres ) \ + m_f &= ~_FLAG_C; \ + else \ + m_f |= _FLAG_C; \ + } + + +#define HCD62121_AND \ + { \ + int i; \ + UINT8 is_zero = 1; \ + \ + for ( i = 0; i < size; i++ ) \ + { \ + m_temp1[i] = m_temp1[i] & m_temp2[i]; \ + if ( m_temp1[i] ) \ + is_zero = 0; \ + } \ + \ + if ( is_zero ) \ + m_f |= _FLAG_Z; \ + else \ + m_f &= ~_FLAG_Z; \ + \ + if ( m_temp1[0] & 0x0f ) \ + m_f &= ~_FLAG_ZL; \ + else \ + m_f |= _FLAG_ZL; \ + \ + if ( m_temp1[0] & 0xf0 ) \ + m_f &= ~_FLAG_ZH; \ + else \ + m_f |= _FLAG_ZH; \ + } + +#define HCD62121_OR \ + { \ + int i; \ + UINT8 is_zero = 1; \ + \ + for ( i = 0; i < size; i++ ) \ + { \ + m_temp1[i] = m_temp1[i] | m_temp2[i]; \ + if ( m_temp1[i] ) \ + is_zero = 0; \ + } \ + \ + if ( is_zero ) \ + m_f |= _FLAG_Z; \ + else \ + m_f &= ~_FLAG_Z; \ + \ + if ( m_temp1[0] & 0x0f ) \ + m_f &= ~_FLAG_ZL; \ + else \ + m_f |= _FLAG_ZL; \ + \ + if ( m_temp1[0] & 0xf0 ) \ + m_f &= ~_FLAG_ZH; \ + else \ + m_f |= _FLAG_ZH; \ + } + +#define HCD62121_XOR \ + { \ + int i; \ + UINT8 is_zero = 1; \ + \ + for ( i = 0; i < size; i++ ) \ + { \ + m_temp1[i] = m_temp1[i] ^ m_temp2[i]; \ + if ( m_temp1[i] ) \ + is_zero = 0; \ + } \ + \ + if ( is_zero ) \ + m_f |= _FLAG_Z; \ + else \ + m_f &= ~_FLAG_Z; \ + \ + if ( m_temp1[0] & 0x0f ) \ + m_f &= ~_FLAG_ZL; \ + else \ + m_f |= _FLAG_ZL; \ + \ + if ( m_temp1[0] & 0xf0 ) \ + m_f &= ~_FLAG_ZH; \ + else \ + m_f |= _FLAG_ZH; \ + } + +#define HCD62121_ADD \ + { \ + int i; \ + UINT8 is_zero = 1, carry = 0; \ + \ + if ( ( m_temp1[0] & 0x0f ) + ( m_temp2[0] & 0x0f ) > 15 ) \ + m_f |= _FLAG_CL; \ + else \ + m_f &= ~_FLAG_CL; \ + \ + for ( i = 0; i < size; i++ ) \ + { \ + UINT16 res = m_temp1[i] + m_temp2[i] + carry; \ + \ + m_temp1[i] = res & 0xff; \ + if ( m_temp1[i] ) \ + is_zero = 0; \ + \ + carry = ( res & 0xff00 ) ? 1 : 0; \ + } \ + \ + if ( is_zero ) \ + m_f |= _FLAG_Z; \ + else \ + m_f &= ~_FLAG_Z; \ + \ + if ( carry ) \ + m_f |= _FLAG_C; \ + else \ + m_f &= ~_FLAG_C; \ + \ + if ( m_temp1[0] & 0x0f ) \ + m_f &= ~_FLAG_ZL; \ + else \ + m_f |= _FLAG_ZL; \ + \ + if ( m_temp1[0] & 0xf0 ) \ + m_f &= ~_FLAG_ZH; \ + else \ + m_f |= _FLAG_ZH; \ + } + +/* BCD ADD */ +#define HCD62121_ADDB \ + { \ + int i; \ + UINT8 is_zero = 1, carry = 0; \ + \ + if ( ( m_temp1[0] & 0x0f ) + ( m_temp2[0] & 0x0f ) > 9 ) \ + m_f |= _FLAG_CL; \ + else \ + m_f &= ~_FLAG_CL; \ + \ + for ( i = 0; i < size; i++ ) \ + { \ + UINT16 res = ( m_temp1[i] & 0x0f ) + ( m_temp2[i] & 0x0f ) + carry; \ + \ + carry = 0; \ + if ( res > 9 ) \ + { \ + res += 6; \ + } \ + res += ( m_temp1[i] & 0xf0 ) + ( m_temp2[i] & 0xf0 ); \ + if ( res > 0x9f ) \ + { \ + res += 0x60; \ + } \ + m_temp1[i] = res & 0xff; \ + if ( m_temp1[i] ) \ + is_zero = 0; \ + \ + carry = ( res & 0xff00 ) ? 1 : 0; \ + } \ + \ + if ( is_zero ) \ + m_f |= _FLAG_Z; \ + else \ + m_f &= ~_FLAG_Z; \ + \ + if ( carry ) \ + m_f |= _FLAG_C; \ + else \ + m_f &= ~_FLAG_C; \ + \ + if ( m_temp1[0] & 0x0f ) \ + m_f &= ~_FLAG_ZL; \ + else \ + m_f |= _FLAG_ZL; \ + \ + if ( m_temp1[0] & 0xf0 ) \ + m_f &= ~_FLAG_ZH; \ + else \ + m_f |= _FLAG_ZH; \ + } + +#define HCD62121_SUB \ + { \ + int i; \ + UINT8 is_zero = 1, carry = 0; \ + \ + if ( ( m_temp1[0] & 0x0f ) < ( m_temp2[0] & 0x0f ) ) \ + m_f |= _FLAG_CL; \ + else \ + m_f &= ~_FLAG_CL; \ + \ + for ( i = 0; i < size; i++ ) \ + { \ + UINT16 res = m_temp1[i] - m_temp2[i] - carry; \ + \ + m_temp1[i] = res & 0xff; \ + if ( m_temp1[i] ) \ + is_zero = 0; \ + \ + carry = ( res & 0xff00 ) ? 1 : 0; \ + } \ + \ + if ( is_zero ) \ + m_f |= _FLAG_Z; \ + else \ + m_f &= ~_FLAG_Z; \ + \ + if ( carry ) \ + m_f |= _FLAG_C; \ + else \ + m_f &= ~_FLAG_C; \ + \ + if ( m_temp1[0] & 0x0f ) \ + m_f &= ~_FLAG_ZL; \ + else \ + m_f |= _FLAG_ZL; \ + \ + if ( m_temp1[0] & 0xf0 ) \ + m_f &= ~_FLAG_ZH; \ + else \ + m_f |= _FLAG_ZH; \ + } + +#define HCD62121_PUSHW(source) \ + { \ + UINT16 address = source; \ + m_program->write_byte( ( m_sseg << 16 ) | m_sp, ( address ) & 0xff ); \ + m_sp--; \ + m_program->write_byte( ( m_sseg << 16 ) | m_sp, ( address ) >> 8 ); \ + m_sp--; \ + } + +#define HCD62121_POPW(dest) \ + { \ + UINT16 res; \ + m_sp++; \ + res = m_program->read_byte( ( m_sseg << 16 ) | m_sp ) << 8; \ + m_sp++; \ + res |= m_program->read_byte( ( m_sseg << 16 ) | m_sp ); \ + dest = res; \ + } + +case 0x04: /* mskb r1,r2 */ +case 0x05: /* mskw r1,r2 */ +case 0x06: /* mskq r1,r2 */ +case 0x07: /* mskt r1,r2 */ + { + int size = datasize( op ); + UINT8 reg1 = read_op(); + UINT8 reg2 = read_op(); + + read_regreg( size, reg1, reg2, false ); + + HCD62121_MSK; + } + break; + +case 0x08: /* shb r1,4 */ +case 0x09: /* shw r1,4 */ +case 0x0A: /* shq r1,4 */ +case 0x0B: /* sht r1,4 */ + /* Shift is a nibble shift! */ + { + int i; + int size = datasize( op ); + UINT8 reg1 = read_op(); + UINT8 d1 = 0, d2 = 0; + + read_reg( size, reg1 ); + + for ( i = 0; i < size; i++ ) + { + if ( reg1 & 0x80 ) + { + d1 = ( m_temp1[i] & 0x0f ) << 4; + m_temp1[i] = ( m_temp1[i] >> 4 ) | d2; + } + else + { + d1 = ( m_temp1[i] & 0xf0 ) >> 4; + m_temp1[i] = ( m_temp1[i] << 4 ) | d2; + } + d2 = d1; + } + + write_reg( size, reg1 ); + } + break; + +case 0x0C: /* testb r1,r2 */ +case 0x0D: /* testw r1,r2 */ +case 0x0E: /* testq r1,r2 */ +case 0x0F: /* testt r1,r2 */ + { + int size = datasize( op ); + UINT8 reg1 = read_op(); + UINT8 reg2 = read_op(); + + read_regreg( size, reg1, reg2, false ); + + HCD62121_AND; + } + break; + +case 0x10: /* xorb r1,r2 */ +case 0x11: /* xorw r1,r2 */ +case 0x12: /* xorq r1,r2 */ +case 0x13: /* xort r1,r2 */ + { + int size = datasize( op ); + UINT8 reg1 = read_op(); + UINT8 reg2 = read_op(); + + read_regreg( size, reg1, reg2, false ); + + HCD62121_XOR; + + write_regreg( size, reg1, reg2 ); + } + break; + +case 0x14: /* cmpb r1,r2 */ +case 0x15: /* cmpw r1,r2 */ +case 0x16: /* cmpq r1,r2 */ +case 0x17: /* cmpt r1,r2 */ + { + int size = datasize( op ); + UINT8 reg1 = read_op(); + UINT8 reg2 = read_op(); + + read_regreg( size, reg1, reg2, false ); + + HCD62121_SUB; + } + break; + +case 0x18: /* movb r1,r2 */ +case 0x19: /* movw r1,r2 */ +case 0x1A: /* movq r1,r2 */ +case 0x1B: /* movt r1,r2 */ + { + int i; + int size = datasize( op ); + UINT8 reg1 = read_op(); + UINT8 reg2 = read_op(); + + read_regreg( size, reg1, reg2, false ); + + for ( i = 0; i < size; i++ ) + m_temp1[i] = m_temp2[i]; + + write_regreg( size, reg1, reg2 ); + } + break; + +case 0x1C: /* imskb r1,r2 */ +case 0x1D: /* imskw r1,r2 */ +case 0x1E: /* imskq r1,r2 */ +case 0x1F: /* imskt r1,r2 */ + { + int size = datasize( op ); + UINT8 reg1 = read_op(); + UINT8 reg2 = read_op(); + + read_regreg( size, reg1, reg2, false ); + + HCD62121_IMSK; + } + break; + +case 0x20: /* shrb r1 */ +case 0x21: /* shrw r1 */ +case 0x22: /* shrq r1 */ +case 0x23: /* shrt r1 */ + /* Shift is a single shift! */ + { + int i; + int size = datasize( op ); + UINT8 reg1 = read_op(); + UINT8 d1 = 0, d2 = 0; + + read_reg( size, reg1 ); + + for ( i = 0; i < size; i++ ) + { + d1 = ( m_temp1[i] & 0x01 ) << 7; + m_temp1[i] = ( m_temp1[i] >> 1 ) | d2; + d2 = d1; + } + + write_reg( size, reg1 ); + } + break; + +case 0x24: /* orb r1,r2 */ +case 0x25: /* orw r1,r2 */ +case 0x26: /* orq r1,r2 */ +case 0x27: /* ort r1,r2 */ + { + int size = datasize( op ); + UINT8 reg1 = read_op(); + UINT8 reg2 = read_op(); + + read_regreg( size, reg1, reg2, false ); + + HCD62121_OR; + + write_regreg( size, reg1, reg2 ); + } + break; + +case 0x28: /* shlb r1 */ +case 0x29: /* shlw r1 */ +case 0x2A: /* shlq r1 */ +case 0x2B: /* shlt r1 */ + /* Shift is a single shift! */ + { + int i; + int size = datasize( op ); + UINT8 reg1 = read_op(); + UINT8 d1 = 0, d2 = 0; + + read_reg( size, reg1 ); + + for ( i = 0; i < size; i++ ) + { + d1 = ( m_temp1[i] & 0x80 ) >> 7; + m_temp1[i] = ( m_temp1[i] << 1 ) | d2; + d2 = d1; + } + + write_reg( size, reg1 ); + } + break; + +case 0x2C: /* andb r1,r2 */ +case 0x2D: /* andw r1,r2 */ +case 0x2E: /* andq r1,r2 */ +case 0x2F: /* andt r1,r2 */ + { + int size = datasize( op ); + UINT8 reg1 = read_op(); + UINT8 reg2 = read_op(); + + read_regreg( size, reg1, reg2, true ); + + HCD62121_AND; + + write_regreg( size, reg1, reg2 ); + } + break; + +case 0x34: /* subb r1,r2 */ +case 0x35: /* subw r1,r2 */ +case 0x36: /* subq r1,r2 */ +case 0x37: /* subt r1,r2 */ + { + int size = datasize( op ); + UINT8 reg1 = read_op(); + UINT8 reg2 = read_op(); + + read_regreg( size, reg1, reg2, false ); + + HCD62121_SUB; + + write_regreg( size, reg1, reg2 ); + } + break; + +case 0x38: /* adbb r1,r2 */ +case 0x39: /* adbw r1,r2 */ +case 0x3A: /* adbq r1,r2 */ +case 0x3B: /* adbt r1,r2 */ + { + int size = datasize( op ); + UINT8 reg1 = read_op(); + UINT8 reg2 = read_op(); + + read_regreg( size, reg1, reg2, false ); + + HCD62121_ADDB; + + write_regreg( size, reg1, reg2 ); + } + break; + +case 0x3C: /* addb r1,r2 */ +case 0x3D: /* addw r1,r2 */ +case 0x3E: /* addq r1,r2 */ +case 0x3F: /* addt r1,r2 */ + { + int size = datasize( op ); + UINT8 reg1 = read_op(); + UINT8 reg2 = read_op(); + + read_regreg( size, reg1, reg2, false ); + + HCD62121_ADD; + + write_regreg( size, reg1, reg2 ); + } + break; + +case 0x4C: /* testb ir1,r2 */ +case 0x4D: /* testw ir1,r2 */ +case 0x4E: /* testq ir1,r2 */ +case 0x4F: /* testt ir1,r2 */ + { + int size = datasize( op ); + UINT8 reg1 = read_op(); + UINT8 reg2 = read_op(); + + read_iregreg( size, reg1, reg2 ); + + HCD62121_AND; + } + break; + +case 0x54: /* cmpb ir1,r2 */ +case 0x55: /* cmpw ir1,r2 */ +case 0x56: /* cmpq ir1,r2 */ +case 0x57: /* cmpt ir1,r2 */ + { + int size = datasize( op ); + UINT8 reg1 = read_op(); + UINT8 reg2 = read_op(); + + read_iregreg( size, reg1, reg2 ); + + HCD62121_SUB; + } + break; + +case 0x58: /* movb ir1,r2 */ +case 0x59: /* movw ir1,r2 */ +case 0x5A: /* movq ir1,r2 */ +case 0x5B: /* movt ir1,r2 */ + { + int i; + int size = datasize( op ); + UINT8 reg1 = read_op(); + UINT8 reg2 = read_op(); + + read_iregreg( size, reg1, reg2 ); + + for ( i = 0; i < size; i++ ) + m_temp1[i] = m_temp2[i]; + + write_iregreg( size, reg1, reg2 ); + } + break; + +case 0x64: /* orb ir1,r2 */ +case 0x65: /* orb ir1,r2 */ +case 0x66: /* orb ir1,r2 */ +case 0x67: /* orb ir1,r2 */ + { + int size = datasize( op ); + UINT8 reg1 = read_op(); + UINT8 reg2 = read_op(); + + read_iregreg( size, reg1, reg2 ); + + HCD62121_OR; + + write_iregreg( size, reg1, reg2 ); + } + break; + +case 0x6C: /* andb ir1,r2 */ +case 0x6D: /* andw ir1,r2 */ +case 0x6E: /* andq ir1,r2 */ +case 0x6F: /* andt ir1,r2 */ + { + int size = datasize( op ); + UINT8 reg1 = read_op(); + UINT8 reg2 = read_op(); + + read_iregreg( size, reg1, reg2 ); + + HCD62121_AND; + + write_iregreg( size, reg1, reg2 ); + } + break; + +case 0x7C: /* addb ir1,r2 */ +case 0x7D: /* addw ir1,r2 */ +case 0x7E: /* addq ir1,r2 */ +case 0x7F: /* addt ir1,r2 */ + { + int size = datasize( op ); + UINT8 reg1 = read_op(); + UINT8 reg2 = read_op(); + + read_iregreg( size, reg1, reg2 ); + + HCD62121_ADD; + + write_iregreg( size, reg1, reg2 ); + } + break; + +case 0x88: /* jump _a16 */ + m_ip = ( read_op() << 8 ) | read_op(); + break; + +case 0x89: /* jumpf cs:a16 */ + { + UINT8 cs = read_op(); + UINT8 a1 = read_op(); + UINT8 a2 = read_op(); + + m_cseg = cs; + m_ip = ( a1 << 8 ) | a2; + } + break; + +case 0x8A: /* call a16 */ + { + UINT8 a1 = read_op(); + UINT8 a2 = read_op(); + + HCD62121_PUSHW( m_ip ); + + m_ip = ( a1 << 8 ) | a2; + } + break; + +case 0x8C: /* unk_8C */ +case 0x8D: /* unk_8D */ +case 0x8E: /* unk_8E */ + logerror( "%02x:%04x: unimplemented instruction %02x encountered\n", m_cseg, m_ip-1, op ); + break; + +case 0x90: /* retzh */ +case 0x91: /* retzl */ +case 0x92: /* retc */ +case 0x93: /* retz */ +case 0x94: /* retzc */ +case 0x95: /* retcl */ +case 0x96: /* retnc */ +case 0x97: /* retnz */ + if ( check_cond( op ) ) + HCD62121_POPW( m_ip ); + break; + +case 0x98: /* jump (r1) */ + { + UINT8 reg1 = read_op(); + UINT16 ad = m_reg[ ( reg1 | 0x40 ) & 0x7f ] << 8; + + if ( reg1 & 0x40 ) + ad |= m_reg[ ( ( reg1 - 1 ) | 0x40 ) & 0x7f ]; + else + ad |= m_reg[ ( ( reg1 + 1 ) | 0x40 ) & 0x7f ]; + + m_ip = ad; + } + break; + +case 0x9F: /* ret */ + HCD62121_POPW( m_ip ); + break; + +case 0xA0: /* jmpzh a16 */ +case 0xA1: /* jmpzl a16 */ +case 0xA2: /* jmpc a16 */ +case 0xA3: /* jmpz a16 */ +case 0xA4: /* jmpzc a16 */ +case 0xA5: /* jmpcl a16 */ +case 0xA6: /* jmpnc a16 */ +case 0xA7: /* jmpnz a16 */ + { + UINT8 a1 = read_op(); + UINT8 a2 = read_op(); + + if ( check_cond( op ) ) + m_ip = ( a1 << 8 ) | a2; + } + break; + +case 0xA8: /* callzh a16 */ +case 0xA9: /* callzl a16 */ +case 0xAA: /* callc a16 */ +case 0xAB: /* callz a16 */ +case 0xAC: /* callzc a16 */ +case 0xAD: /* callcl a16 */ +case 0xAE: /* callnc a16 */ +case 0xAF: /* callnz a16 */ + { + UINT8 a1 = read_op(); + UINT8 a2 = read_op(); + + if ( check_cond( op ) ) + { + HCD62121_PUSHW( m_ip ); + + m_ip = ( a1 << 8 ) | a2; + } + } + break; + +case 0xB1: /* unk_B1 reg/i8 */ +case 0xB3: /* unk_B3 reg/i8 */ + logerror( "%02x:%04x: unimplemented instruction %02x encountered\n", m_cseg, m_ip-1, op ); + read_op(); + break; + +case 0xB4: /* out koh,reg */ + m_io->write_byte( HCD62121_KOH, m_reg[ read_op() & 0x7f ] ); + break; + +case 0xB5: /* out koh,i8 */ + m_io->write_byte( HCD62121_KOH, read_op() ); + break; + +case 0xB6: /* out kol,reg */ + m_io->write_byte( HCD62121_KOL, m_reg[ read_op() & 0x7f ] ); + break; + +case 0xB7: /* out kol,i8 */ + m_io->write_byte( HCD62121_KOL, read_op() ); + break; + +case 0xB9: /* unk_B9 reg/i8 */ + logerror( "%02x:%04x: unimplemented instruction %02x encountered\n", m_cseg, m_ip-1, op ); + read_op(); + break; + +case 0xBB: /* jmpcl? a16 */ + logerror( "%02x:%04x: unimplemented instruction %02x encountered\n", m_cseg, m_ip-1, op ); + { + UINT8 a1 = read_op(); + UINT8 a2 = read_op(); + + if ( m_f & _FLAG_CL ) + m_ip = ( a1 << 8 ) | a2; + } + break; + +case 0xBF: /* jmpncl? a16 */ + logerror( "%02x:%04x: unimplemented instruction %02x encountered\n", m_cseg, m_ip-1, op ); + { + UINT8 a1 = read_op(); + UINT8 a2 = read_op(); + + if ( ! ( m_f & _FLAG_CL ) ) + m_ip = ( a1 << 8 ) | a2; + } + break; + +case 0xC0: /* movb reg,i8 */ +case 0xC1: /* movw reg,i16 */ +case 0xC2: /* movw reg,i64 */ +case 0xC3: /* movw reg,i80 */ + { + int i; + int size = datasize( op ); + UINT8 reg = read_op(); + + for( i = 0; i < size; i++ ) + { + m_reg[(reg + i) & 0x7f] = read_op(); + } + } + break; + +case 0xC4: /* movb (lar),r1 / r1,(lar) */ +case 0xC5: /* movw (lar),r1 / r1,(lar) */ +case 0xC6: /* movq (lar),r1 / r1,(lar) */ +case 0xC7: /* movt (lar),r1 / r1,(lar) */ + { + int i; + int size = datasize( op ); + UINT8 reg1 = read_op(); + UINT8 reg2 = read_op(); + int pre_inc = 0; + int post_inc = 1; + + switch( reg1 & 0x60 ) + { + case 0x00: + pre_inc = 0; + post_inc = 1; + break; + case 0x20: + pre_inc = 1; + post_inc = 0; + break; + case 0x40: + pre_inc = 0; + post_inc = -1; + break; + case 0x60: + pre_inc = -1; + post_inc = 0; + break; + } + + if ( ( reg1 & 0x80 ) || ( reg2 & 0x80 ) ) + { + /* (lar) <- r1 */ + for ( i = 0; i < size; i++ ) + { + m_lar += pre_inc; + m_program->write_byte( ( m_dseg << 16 ) | m_lar, m_reg[ ( reg2 + i ) & 0x7f ] ); + m_lar += post_inc; + } + } + else + { + /* r1 <- (lar) */ + for ( i = 0; i < size; i++ ) + { + m_lar += pre_inc; + m_reg[ ( reg2 + i ) & 0x7f ] = m_program->read_byte( ( m_dseg << 16 ) | m_lar ); + m_lar += post_inc; + } + } + } + break; + +case 0xCC: /* swapb ir1,r2 */ +case 0xCD: /* swapw ir1,r2 */ +case 0xCE: /* swapq ir1,r2 */ +case 0xCF: /* swapt ir1,r2? */ + { + int i; + int size = datasize( op ); + UINT8 reg1 = read_op(); + UINT8 reg2 = read_op(); + + read_iregreg( size, reg1, reg2 ); + + for ( i = 0; i < size; i++ ) + { + UINT8 d = m_temp1[i]; + m_temp1[i] = m_temp2[i]; + m_temp2[i] = d; + } + + write_iregreg( size, reg1, reg2 ); + write_iregreg2( size, reg1, reg2 ); + } + break; + +case 0xD0: /* movb cs,reg */ + m_cseg = m_reg[ read_op() & 0x7f ]; + break; + +case 0xD1: /* movb cs,i8 */ + m_cseg = read_op(); + break; + +case 0xD2: /* movb dsize,reg */ + m_dsize = m_reg[ read_op() & 0x7f ]; + break; + +case 0xD3: /* movb dsize,i8 */ + m_dsize = read_op(); + break; + +case 0xD4: /* movb ss,reg */ + m_sseg = m_reg[ read_op() & 0x7f ]; + break; + +case 0xD5: /* movb ss,i8 */ + m_sseg = read_op(); + break; + +case 0xD6: /* movw sp,reg */ + { + UINT8 reg1 = read_op(); + + m_sp = m_reg[ reg1 & 0x7f ] | ( m_reg[ ( reg1 + 1 ) & 0x7f ] << 8 ); + } + break; + +case 0xD7: /* movw sp,i16 */ + m_sp = read_op() << 8; + m_sp |= read_op(); + break; + +case 0xD8: /* movb f,reg */ + m_f = m_reg[ read_op() & 0x7f ]; + break; + +case 0xD9: /* movb f,i8 */ + m_f = read_op(); + break; + +case 0xDC: /* movb ds,reg */ + m_dseg = m_reg[ read_op() & 0x7f ]; + break; + +case 0xDD: /* movb ds,i8 */ + m_dseg = read_op(); + break; + +case 0xDE: /* movw lar,reg */ + { + UINT8 reg1 = read_op(); + + m_lar = m_reg[ reg1 & 0x7f ] | ( m_reg[ ( reg1 + 1 ) & 0x7f ] << 8 ); + } + break; + +case 0xE0: /* in0 reg */ + { + UINT8 reg1 = read_op(); + + m_reg[ reg1 & 0x7f ] = m_io->read_byte( HCD62121_IN0 ); + } + break; + +case 0xE1: /* unk_E1 reg/i8 (in?) */ + logerror( "%02x:%04x: unimplemented instruction %02x encountered\n", m_cseg, m_ip-1, op ); + read_op(); + break; + +case 0xE2: /* in kb, reg */ + m_reg[ read_op() & 0x7f ] = m_io->read_byte( HCD62121_KI ); + break; + +case 0xE3: /* unk_e3 reg/i8 (in?) */ +case 0xE4: /* unk_e4 reg/i8 (in?) */ +case 0xE5: /* unk_e5 reg/i8 (in?) */ +case 0xE6: /* unk_e6 reg/i8 (in?) */ +case 0xE7: /* unk_e7 reg/i8 (in?) */ + logerror( "%02x:%04x: unimplemented instruction %02x encountered\n", m_cseg, m_ip-1, op ); + read_op(); + break; + +case 0xE8: /* movw r1,lar */ + { + UINT8 reg1 = read_op(); + + m_reg[ reg1 & 0x7f ] = m_lar & 0xff; + m_reg[ ( reg1 + 1 ) & 0x7f ] = m_lar >> 8; + } + break; + +case 0xEB: /* movw reg,ss */ + { + UINT8 reg1 = read_op(); + + m_reg[ reg1 & 0x7f ] = m_sp & 0xff; + m_reg[ ( reg1 + 1 ) & 0x7f ] = m_sp >> 8; + } + break; + +case 0xEF: /* movb reg,ss */ + m_reg[ read_op() & 0x7f ] = m_sseg; + break; + +case 0xF0: /* unk_F0 reg/i8 (out?) */ +case 0xF1: /* unk_F1 reg/i8 (out?) */ +case 0xF2: /* unk_F2 reg/i8 (out?) */ +case 0xF3: /* unk_F3 reg/i8 (out?) */ +case 0xF4: /* unk_F4 reg/i8 (out?) */ +case 0xF5: /* unk_F5 reg/i8 (out?) */ +case 0xF6: /* unk_F6 reg/i8 (out?) */ +case 0xF7: /* unk_F7 reg/i8 (out?) */ + logerror( "%02x:%04x: unimplemented instruction %02x encountered\n", m_cseg, m_ip-1, op ); + read_op(); + break; + +case 0xFC: /* unk_FC */ +case 0xFD: /* unk_FD */ +case 0xFE: /* unk_FE */ + logerror( "%02x:%04x: unimplemented instruction %02x encountered\n", m_cseg, m_ip-1, op ); + break; + +case 0xFF: /* nop */ + break; + +default: + /*logerror*/fatalerror( "%02x:%04x: unimplemented instruction %02x encountered\n", m_cseg, m_ip-1, op ); diff --git a/src/devices/cpu/hcd62121/hcd62121d.c b/src/devices/cpu/hcd62121/hcd62121d.c new file mode 100644 index 00000000000..2283c0682af --- /dev/null +++ b/src/devices/cpu/hcd62121/hcd62121d.c @@ -0,0 +1,356 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol + +#include "emu.h" +#include "debugger.h" +#include "hcd62121.h" + +#ifdef _MSC_VER +#undef _SP +#endif + +enum +{ + _REG=1, /* register */ + _REGREG, /* register1, register2, or register2, register1 or register1, imm byte */ + _IRG, /* register indirect */ + _IRGREG, /* 2 register indirect */ + _A16, /* 16bit address */ + _A24, /* seg:address */ + _F, /* flag register */ + _CS, /* cs register */ + _DS, /* ds register */ + _SS, /* ss register */ + _PC, /* program counter */ + _SP, /* stack pointer */ + _I8, /* immediate 8 bit value */ + _I16, /* immediate 16 bit value */ + _I64, /* immediate 64 bit value */ + _I80, /* immediate 80 bit value */ + _ILR, /* indirect last address register access */ + _LAR, /* last address register */ + _DSZ, /* dsize register? */ + _TIM, /* timing related register? */ + _KLO, /* KO1 - KO8 output lines */ + _KHI, /* KO9 - KO14(?) output lines */ + _KI, /* K input lines */ + _4 /* for nibble shifts */ +}; + +struct hcd62121_dasm +{ + const char *str; + UINT8 arg1; + UINT8 arg2; +}; + + +static const hcd62121_dasm hcd62121_ops[256] = +{ + /* 0x00 */ + { "un00?", 0, 0 }, { "un01?", 0, 0 }, { "un02?", 0, 0 }, { "un03?", 0, 0 }, + { "mskb", _REGREG, 0 }, { "mskw", _REGREG, 0 }, { "mskq", _REGREG, 0 }, { "mskt", _REGREG, 0 }, + { "sh?b", _REG, _4 }, { "sh?w", _REG, _4 }, { "sh?q", _REG, _4 }, { "sh?t", _REG, _4 }, + { "tstb", _REGREG, 0 }, { "tstw", _REGREG, 0 }, { "tstq", _REGREG, 0 }, { "tstt", _REGREG, 0 }, + { "xorb", _REGREG, 0 }, { "xorw", _REGREG, 0 }, { "xorq", _REGREG, 0 }, { "xort", _REGREG, 0 }, + { "cmpb", _REGREG, 0 }, { "cmpw", _REGREG, 0 }, { "cmpq", _REGREG, 0 }, { "cmpt", _REGREG, 0 }, + { "movb", _REGREG, 0 }, { "movw", _REGREG, 0 }, { "movq", _REGREG, 0 }, { "movt", _REGREG, 0 }, + { "imskb", _REGREG, 0 }, { "imskw", _REGREG, 0 }, { "imskq", _REGREG, 0 }, { "imskt", _REGREG, 0 }, + + /* 0x20 */ + { "shrb", _REG, 0 }, { "shrw", _REG, 0 }, { "shrq", _REG, 0 }, { "shrt", _REG, 0 }, + { "orb", _REGREG, 0 }, { "orw", _REGREG, 0 }, { "orq", _REGREG, 0 }, { "ort", _REGREG, 0 }, + { "shlb", _REG, 0 }, { "shlw", _REG, 0 }, { "shlq", _REG, 0 }, { "shlt", _REG, 0 }, + { "andb", _REGREG, 0 }, { "andw", _REGREG, 0 }, { "andq", _REGREG, 0 }, { "andt", _REGREG, 0 }, + { "sbbb", _REGREG, 0 }, { "sbbw", _REGREG, 0 }, { "sbbq", _REGREG, 0 }, { "sbbt", _REGREG, 0 }, /* BCD SUB */ + { "subb", _REGREG, 0 }, { "subw", _REGREG, 0 }, { "subq", _REGREG, 0 }, { "subt", _REGREG, 0 }, + { "adbb", _REGREG, 0 }, { "adbw", _REGREG, 0 }, { "adbq", _REGREG, 0 }, { "adbt", _REGREG, 0 }, /* BCD ADD */ + { "addb", _REGREG, 0 }, { "addw", _REGREG, 0 }, { "addq", _REGREG, 0 }, { "addt", _REGREG, 0 }, + + /* 0x40 */ + { "shrb?", _IRG, 0 }, { "shrw?", _IRG, 0 }, { "shrq?", _IRG, 0 }, { "shrt?", _IRG, 0 }, + { "mskb", _IRGREG, 0 }, { "mskw", _IRGREG, 0 }, { "mskq", _IRGREG, 0 }, { "mskt", _IRGREG, 0 }, + { "shrb", _IRG, 0 }, { "shrw", _IRG, 0 }, { "shrq", _IRG, 0 }, { "shrt", _IRG, 0 }, + { "tstb", _IRGREG, 0 }, { "tstw", _IRGREG, 0 }, { "tstq", _IRGREG, 0 }, { "tstt", _IRGREG, 0 }, + { "xorb", _IRGREG, 0 }, { "xorw", _IRGREG, 0 }, { "xorq", _IRGREG, 0 }, { "xort", _IRGREG, 0 }, + { "cmpb", _IRGREG, 0 }, { "cmpw", _IRGREG, 0 }, { "cmpq", _IRGREG, 0 }, { "cmpt", _IRGREG, 0 }, + { "movb", _IRGREG, 0 }, { "movw", _IRGREG, 0 }, { "movq", _IRGREG, 0 }, { "movt", _IRGREG, 0 }, + { "imskb", _IRGREG, 0 }, { "imskw", _IRGREG, 0 }, { "imskq", _IRGREG, 0 }, { "imskt", _IRGREG, 0 }, + + /* 0x60 */ + { "shrb", _IRG, 0 }, { "shrw", _IRG, 0 }, { "shrq", _IRG, 0 }, { "shrt", _IRG, 0 }, + { "orb", _IRGREG, 0 }, { "orw", _IRGREG, 0 }, { "orq", _IRGREG, 0 }, { "ort", _IRGREG, 0 }, + { "shlb", _IRG, 0 }, { "shlw", _IRG, 0 }, { "shlq", _IRG, 0 }, { "shlt", _IRG, 0 }, + { "andb", _IRGREG, 0 }, { "andw", _IRGREG, 0 }, { "andq", _IRGREG, 0 }, { "andt", _IRGREG, 0 }, + { "sbbb", _IRGREG, 0 }, { "sbbw", _IRGREG, 0 }, { "sbbq", _IRGREG, 0 }, { "sbbt", _IRGREG, 0 }, /* BCD SUB */ + { "subb", _IRGREG, 0 }, { "subw", _IRGREG, 0 }, { "subq", _IRGREG, 0 }, { "subt", _IRGREG, 0 }, + { "adbb", _IRGREG, 0 }, { "adbw", _IRGREG, 0 }, { "adbq", _IRGREG, 0 }, { "adbt", _IRGREG, 0 }, /* BCD ADD */ + { "addb", _IRGREG, 0 }, { "addw", _IRGREG, 0 }, { "addq", _IRGREG, 0 }, { "addt", _IRGREG, 0 }, + + /* 0x80 */ + { "un80?", 0, 0 }, { "un81?", 0, 0 }, { "un82?", 0, 0 }, { "un83?", 0, 0 }, + { "un84?", 0, 0 }, { "un85?", 0, 0 }, { "un86?", 0, 0 }, { "un87?", 0, 0 }, + { "jump", _A16, 0 }, { "jump", _A24, 0 }, { "call", _A16, 0 }, { "un8b?", 0, 0 }, + { "un8C?", 0, 0 }, { "un8D?", 0, 0 }, { "un8E?", 0, 0 }, { "un8F?", 0, 0 }, + { "retzh", 0, 0 }, { "retzl", 0, 0 }, { "retc", 0, 0 }, { "retz", 0, 0 }, + { "retzc", 0, 0 }, { "retcl", 0, 0 }, { "retnc", 0, 0 }, { "retnz", 0, 0 }, + { "jump", _IRG, 0 }, { "un99?", 0, 0 }, { "un9A?", 0, 0 }, { "un9b?", 0, 0 }, + { "un9C?", 0, 0 }, { "un9D?", 0, 0 }, { "reti", 0, 0 }, { "ret", 0, 0 }, + + /* 0xa0 */ + { "jmpzh", _A16, 0 }, { "jmpzl", _A16, 0 }, { "jmpc", _A16, 0 }, { "jmpz", _A16, 0 }, + { "jmpzc", _A16, 0 }, { "jmpcl", _A16, 0 }, { "jmpnc", _A16, 0 }, { "jmpnz", _A16, 0 }, + { "callzh", _A16, 0 }, { "callzl", _A16, 0 }, { "callc", _A16, 0 }, { "callz", _A16, 0 }, + { "callzc", _A16, 0 }, { "callcl", _A16, 0 }, { "callnc", _A16, 0 }, { "callnz", _A16, 0 }, + { "unB0?", 0, 0 }, { "unB1?", _I8, 0 }, { "unB2?", 0, 0 }, { "unB3?", _I8, 0 }, + { "out", _KHI, _REG }, { "out", _KHI, _I8 }, { "out", _KLO, _REG }, { "out", _KLO, _I8 }, + { "unB8?", 0, 0 }, { "unB9?", _I8, 0 }, { "unBA?", 0, 0 }, { "jmpcl?", _A16, 0 }, + { "unBC?", 0, 0 }, { "unBD?", 0, 0 }, { "unBE?", 0, 0 }, { "jmpncl?", _A16, 0 }, + + /* 0xc0 */ + { "movb", _REG, _I8 }, { "movw", _REG, _I16 }, { "movq", _REG, _I64 }, { "movt", _REG, _I80 }, + { "movb", _ILR, _ILR }, { "movw", _ILR, _ILR }, { "movq", _ILR, _ILR }, { "movt", _ILR, _ILR }, + { "unC8?", 0, 0 }, { "unC9?", 0, 0 }, { "unCA?", 0, 0 }, { "unCb?", 0, 0 }, + { "swapb", _IRGREG, 0 }, { "swapw", _IRGREG, 0 }, { "swapq", _IRGREG, 0 }, { "swapt", _IRGREG, 0 }, + { "movb", _CS, _REG }, { "movb", _CS, _I8 }, { "movb", _DSZ, _REG }, { "movb", _DSZ, _I8 }, + { "movb", _SS, _REG }, { "movb", _SS, _I8 }, { "movw", _SP, _REG }, { "movw", _SP, _I16 }, + { "movb", _F, _REG }, { "movb", _F, _I8 }, { "unDA?", 0, 0 }, { "unDb?", 0, 0 }, + { "movb", _DS, _REG }, { "movb", _DS, _I8 }, { "movw", _LAR, _REG }, { "movw?", _LAR, _I16 }, + + /* 0xe0 */ + { "in0", _REG, 0 }, { "unE1?", _I8, 0 }, { "in", _REG, _KI }, { "movb", _REG, _DSZ }, + { "movb", _REG, _F }, { "movb", _REG, _TIM }, { "unE6?", _I8, 0 }, { "unE7?", _I8, 0 }, + { "movw", _REG, _LAR }, { "movw?", _REG, _LAR }, { "movw", _REG, _PC }, { "movw", _REG, _SP }, + { "unEC?", 0, 0 }, { "movb", _REG, _DS }, { "movb", _REG, _CS }, { "movb", _REG, _SS }, + { "unF0?", _I8, 0 }, { "unF1?", _I8, 0 }, { "unF2?", _I8, 0 }, { "unF3?", _I8, 0 }, + { "unF4?", _I8, 0 }, { "unF5?", _I8, 0 }, { "unF6?", _I8, 0 }, { "unF7?", _I8, 0 }, + { "unF8?", 0, 0 }, { "unF9?", 0, 0 }, { "unFA?", 0, 0 }, { "unFb?", 0, 0 }, + { "unFC?", 0, 0 }, { "unFD?", 0, 0 }, { "unFE?", 0, 0 }, { "nop", 0, 0 } +}; + + +CPU_DISASSEMBLE( hcd62121 ) +{ + UINT8 op, op1=0, op2=0; + int pos = 0; + const hcd62121_dasm *inst; + + op = oprom[pos++]; + + inst = &hcd62121_ops[op]; + + /* Special case for nibble shift instruction */ + if ( inst->arg2 == _4 ) + buffer += sprintf(buffer,"sh%c%c ", ( oprom[pos] & 0x80 ) ? 'l' : 'r', inst->str[3]); + else + buffer += sprintf(buffer,"%-8s", inst->str); + + switch( inst->arg1 ) + { + case _REGREG: + op1 = oprom[pos++]; + op2 = oprom[pos++]; + if ( op1 & 0x80 ) + { + buffer += sprintf( buffer, "r%02x,0x%02x", op1 & 0x7f, op2 ); + } + else + { + if ( op2 & 0x80 ) + buffer += sprintf( buffer, "r%02x,r%02x", op1 & 0x7f, op2 & 0x7f ); + else + buffer += sprintf( buffer, "r%02x,r%02x", op2 & 0x7f, op1 & 0x7f ); + } + break; + case _REG: + buffer += sprintf( buffer, "r%02x", oprom[pos++] & 0x7f ); + break; + case _IRGREG: + /* bit 6 = direction. 0 - regular, 1 - reverse */ + op1 = oprom[pos++]; + op2 = oprom[pos++]; + if ( op1 & 0x80 ) + { + buffer += sprintf( buffer, "(r%02x),0x%02x", 0x40 | ( op1 & 0x3f ), op2 ); + } + else + { + if ( op2 & 0x80 ) + buffer += sprintf( buffer, "(r%02x%s),r%02x", 0x40 | ( op1 & 0x3f ), (op1 & 0x40) ? ".r" : "", op2 & 0x7f ); + else + buffer += sprintf( buffer, "r%02x,(r%02x%s)", op2 & 0x7f, 0x40 | ( op1 & 0x3f ), (op1 & 0x40) ? ".r" : "" ); + } + break; + case _IRG: + /* bit 6 = direction. 0 - regular, 1 - reverse */ + op1 = oprom[pos++]; + buffer += sprintf( buffer, "(r%02x%s)", 0x40 | ( op1 & 0x3f ), (op1 & 0x40) ? ".r" : "" ); + break; + case _F: + buffer += sprintf( buffer, "F" ); + break; + case _CS: + buffer += sprintf( buffer, "CS" ); + break; + case _DS: + buffer += sprintf( buffer, "DS" ); + break; + case _SS: + buffer += sprintf( buffer, "SS" ); + break; + case _PC: + buffer += sprintf( buffer, "PC" ); + break; + case _SP: + buffer += sprintf( buffer, "SP" ); + break; + case _I8: + buffer += sprintf( buffer, "0x%02x", oprom[pos++] ); + break; + case _I16: + case _A16: + buffer += sprintf( buffer, "0x%02x", oprom[pos++] ); + buffer += sprintf( buffer, "%02x", oprom[pos++] ); + break; + case _I64: + buffer += sprintf( buffer, "0x%02x", oprom[pos++] ); + buffer += sprintf( buffer, "%02x", oprom[pos++] ); + buffer += sprintf( buffer, "%02x", oprom[pos++] ); + buffer += sprintf( buffer, "%02x", oprom[pos++] ); + buffer += sprintf( buffer, "%02x", oprom[pos++] ); + buffer += sprintf( buffer, "%02x", oprom[pos++] ); + buffer += sprintf( buffer, "%02x", oprom[pos++] ); + buffer += sprintf( buffer, "%02x", oprom[pos++] ); + break; + case _I80: + buffer += sprintf( buffer, "0x%02x", oprom[pos++] ); + buffer += sprintf( buffer, "%02x", oprom[pos++] ); + buffer += sprintf( buffer, "%02x", oprom[pos++] ); + buffer += sprintf( buffer, "%02x", oprom[pos++] ); + buffer += sprintf( buffer, "%02x", oprom[pos++] ); + buffer += sprintf( buffer, "%02x", oprom[pos++] ); + buffer += sprintf( buffer, "%02x", oprom[pos++] ); + buffer += sprintf( buffer, "%02x", oprom[pos++] ); + buffer += sprintf( buffer, "%02x", oprom[pos++] ); + buffer += sprintf( buffer, "%02x", oprom[pos++] ); + break; + case _A24: + buffer += sprintf( buffer, "0x%02x:", oprom[pos++] ); + buffer += sprintf( buffer, "0x%02x", oprom[pos++] ); + buffer += sprintf( buffer, "%02x", oprom[pos++] ); + break; + case _ILR: + op1 = oprom[pos++]; + op2 = oprom[pos++]; + if ( ( op1 & 0x80 ) || ( op2 & 0x80 ) ) + { + /* (lar),reg */ + buffer += sprintf( buffer, "(%slar%s),r%02x", (op1 & 0x20) ? ( (op1 & 0x40) ? "--" : "++" ) : "", (op1 & 0x20) ? "" : ( (op1 & 0x40) ? "--" : "++" ), op2 & 0x7f ); + } + else + { + /* reg,(lar) */ + buffer += sprintf( buffer, "r%02x,(%slar%s)", op2 & 0x7f, (op1 & 0x20) ? ( (op1 & 0x40) ? "--" : "++" ) : "", (op1 & 0x20) ? "" : ( (op1 & 0x40) ? "--" : "++" ) ); + } + break; + case _LAR: + buffer += sprintf( buffer, "lar" ); + break; + case _DSZ: + buffer += sprintf( buffer, "dsize" ); + break; + case _TIM: + buffer += sprintf( buffer, "TIM?" ); + break; + case _KLO: + buffer += sprintf( buffer, "KOL" ); + break; + case _KHI: + buffer += sprintf( buffer, "KOH" ); + break; + default: + break; + } + + switch( inst->arg2 ) + { + case _REG: + buffer += sprintf( buffer, ",r%02x", oprom[pos++] & 0x7f ); + break; + case _F: + buffer += sprintf( buffer, ",F" ); + break; + case _CS: + buffer += sprintf( buffer, ",CS" ); + break; + case _DS: + buffer += sprintf( buffer, ",DS" ); + break; + case _SS: + buffer += sprintf( buffer, ",SS" ); + break; + case _PC: + buffer += sprintf( buffer, ",PC" ); + break; + case _SP: + buffer += sprintf( buffer, ",SP" ); + break; + case _I8: + buffer += sprintf( buffer, ",0x%02x", oprom[pos++] ); + break; + case _I16: + case _A16: + buffer += sprintf( buffer, ",0x%02x", oprom[pos++] ); + buffer += sprintf( buffer, "%02x", oprom[pos++] ); + break; + case _I64: + buffer += sprintf( buffer, ",0x%02x", oprom[pos++] ); + buffer += sprintf( buffer, "%02x", oprom[pos++] ); + buffer += sprintf( buffer, "%02x", oprom[pos++] ); + buffer += sprintf( buffer, "%02x", oprom[pos++] ); + buffer += sprintf( buffer, "%02x", oprom[pos++] ); + buffer += sprintf( buffer, "%02x", oprom[pos++] ); + buffer += sprintf( buffer, "%02x", oprom[pos++] ); + buffer += sprintf( buffer, "%02x", oprom[pos++] ); + break; + case _I80: + buffer += sprintf( buffer, ",0x%02x", oprom[pos++] ); + buffer += sprintf( buffer, "%02x", oprom[pos++] ); + buffer += sprintf( buffer, "%02x", oprom[pos++] ); + buffer += sprintf( buffer, "%02x", oprom[pos++] ); + buffer += sprintf( buffer, "%02x", oprom[pos++] ); + buffer += sprintf( buffer, "%02x", oprom[pos++] ); + buffer += sprintf( buffer, "%02x", oprom[pos++] ); + buffer += sprintf( buffer, "%02x", oprom[pos++] ); + buffer += sprintf( buffer, "%02x", oprom[pos++] ); + buffer += sprintf( buffer, "%02x", oprom[pos++] ); + break; + case _A24: + buffer += sprintf( buffer, ",0x%02x:", oprom[pos++] ); + buffer += sprintf( buffer, "0x%02x", oprom[pos++] ); + buffer += sprintf( buffer, "%02x", oprom[pos++] ); + break; + case _ILR: + /* Implemented by _ILR section for arg1 */ + break; + case _LAR: + buffer += sprintf( buffer, ",lar" ); + break; + case _DSZ: + buffer += sprintf( buffer, ",dsize" ); + break; + case _TIM: + buffer += sprintf( buffer, ",TIM?" ); + break; + case _KI: + buffer += sprintf( buffer, ",KI" ); + break; + case _4: + buffer += sprintf( buffer, ",4" ); + break; + default: + break; + } + + return pos | DASMFLAG_SUPPORTED; +} diff --git a/src/devices/cpu/hd61700/hd61700.c b/src/devices/cpu/hd61700/hd61700.c new file mode 100644 index 00000000000..9e8276c6bc0 --- /dev/null +++ b/src/devices/cpu/hd61700/hd61700.c @@ -0,0 +1,2992 @@ +// license:BSD-3-Clause +// copyright-holders:Sandro Ronco +/****************************************************************************** + + Hitachi HD61700 cpu core emulation. + by Sandro Ronco + + This CPU core is based on documentations works done by: + - Piotr Piatek ( http://www.pisi.com.pl/piotr433/pb1000he.htm ) + - BLUE ( http://www.geocities.jp/hd61700lab/ ) + + The HD61700 has 0x1800 bytes of internal ROM accessed as 16bit with address + shift by -1 (mapped from 0x0000 to 0x0c00), the external memory is accessed + with a 8bit data bus, this core emulate all memory as 16bit access with + address shifted by -1 and in the memory above 0x0c00 only the lower 8bit + are used. + + TODO: + - dasm don't decode some mnemonics + - CPU fast/slow mode + - probably other minor things + +******************************************************************************/ + +#include "emu.h" +#include "debugger.h" +#include "hd61700.h" + +// internal ROM +#define INT_ROM 0x0c00 + +// 5 bit registers +#define REG_SX m_regsir[0] +#define REG_SY m_regsir[1] +#define REG_SZ m_regsir[2] +#define READ_SREG(a) (m_regsir[((a)>>5) & 0x03] & 0x1f) +#define WRITE_SREG(a,d) (m_regsir[((a)>>5) & 0x03] = (d) & 0x1f) + +// 8 bit registers +#define REG_PE m_reg8bit[0] +#define REG_PD m_reg8bit[1] +#define REG_IB m_reg8bit[2] +#define REG_UA m_reg8bit[3] +#define REG_IA m_reg8bit[4] +#define REG_IE m_reg8bit[5] +#define REG_TM m_reg8bit[7] +#define READ_REG8(a) (m_reg8bit[(a) & 0x07]) +#define WRITE_REG8(a,d) (m_reg8bit[(a) & 0x07] = d) + +// 16 bit registers +#define REG_IX m_reg16bit[0] +#define REG_IY m_reg16bit[1] +#define REG_IZ m_reg16bit[2] +#define REG_US m_reg16bit[3] +#define REG_SS m_reg16bit[4] +#define REG_KY m_reg16bit[5] + +// main registers +#define READ_REG(a) (m_regmain[(a) & 0x1f]) +#define WRITE_REG(a,d) (m_regmain[(a) & 0x1f] = d) +#define COPY_REG(d,s) (m_regmain[(d) & 0x1f] = m_regmain[(s) & 0x1f]) +#define REG_GET16(r) (((m_regmain[((r)) & 0x1f]<<0)) | (m_regmain[((r) + 1) & 0x1f]<<8)) +#define REG_PUT16(r,d) do{(m_regmain[(r) & 0x1f] = (((d)>>0) & 0xff)); (m_regmain[((r)+1)&0x1f]=(((d)>>8)&0xff));}while(0) + +// opcode +#define GET_REG_IDX(a,b) (((a<<2) & 0x04) | ((b>>5) & 0x03)) +#define RESTORE_REG(o,r,pr) r = (o&0x02) ? r : pr +#define COND_WRITE_REG(o,a,d) if (o&0x08) WRITE_REG(a,d) +#define GET_IM3(d) (((d>>5)&0x07) + 1) + +// flags +#define SET_FLAG_C m_flags |= FLAG_C +#define CLEAR_FLAG_Z m_flags |= FLAG_Z +#define CLEAR_FLAG_LZ m_flags |= FLAG_LZ +#define CLEAR_FLAG_UZ m_flags |= FLAG_UZ +#define CLEAR_FLAGS m_flags &= ~(FLAG_Z | FLAG_C | FLAG_LZ | FLAG_UZ) + +#define CHECK_FLAG_Z(d) if((d) != 0) CLEAR_FLAG_Z +#define CHECK_FLAG_C(d,l) if (d > l) SET_FLAG_C +#define CHECK_FLAGB_LZ(d) if(((d) & 0x0f) != 0) CLEAR_FLAG_LZ +#define CHECK_FLAGB_UZ(d) if(((d) & 0xf0) != 0) CLEAR_FLAG_UZ +#define CHECK_FLAGW_LZ(d) if(((d) & 0x0f00) != 0) CLEAR_FLAG_LZ +#define CHECK_FLAGW_UZ(d) if(((d) & 0xf000) != 0) CLEAR_FLAG_UZ +#define CHECK_FLAGB_UZ_LZ(d) do{CHECK_FLAGB_LZ(d); CHECK_FLAGB_UZ(d);}while(0) +#define CHECK_FLAGW_UZ_LZ(d) do{CHECK_FLAGW_LZ(d); CHECK_FLAGW_UZ(d);}while(0) + +//CPU state +#define CPU_FAST 0x01 +#define CPU_SLP 0x02 + +/* HD61700 IRQ vector */ +static const UINT16 irq_vector[] = {0x0032, 0x0042, 0x0052, 0x0062, 0x0072}; + +//************************************************************************** +// HD61700 DEVICE +//************************************************************************** + +const device_type HD61700 = &device_creator; + +//------------------------------------------------- +// hd61700_cpu_device - constructor +//------------------------------------------------- + +hd61700_cpu_device::hd61700_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : cpu_device(mconfig, HD61700, "HD61700", tag, owner, clock, "hd61700", __FILE__), + m_program_config("program", ENDIANNESS_BIG, 16, 18, -1), + m_ppc(0x0000), + m_curpc(0x0000), + m_pc(0), + m_flags(0), + m_lcd_ctrl_cb(*this), + m_lcd_read_cb(*this), + m_lcd_write_cb(*this), + m_kb_read_cb(*this), + m_kb_write_cb(*this), + m_port_read_cb(*this), + m_port_write_cb(*this) +{ + // ... +} + + +//------------------------------------------------- +// device_start - start up the device +//------------------------------------------------- + +void hd61700_cpu_device::device_start() +{ + m_program = &space(AS_PROGRAM); + + m_sec_timer = timer_alloc(SEC_TIMER); + m_sec_timer->adjust(attotime::from_seconds(1), 0, attotime::from_seconds(1)); + + m_lcd_ctrl_cb.resolve_safe(); + m_lcd_read_cb.resolve_safe(0xff); + m_lcd_write_cb.resolve_safe(); + m_kb_read_cb.resolve_safe(0xff); + m_kb_write_cb.resolve_safe(); + m_port_read_cb.resolve_safe(0xff); + m_port_write_cb.resolve_safe(); + + // save state + save_item(NAME(m_ppc)); + save_item(NAME(m_curpc)); + save_item(NAME(m_pc)); + save_item(NAME(m_flags)); + save_item(NAME(m_fetch_addr)); + save_item(NAME(m_irq_status)); + save_item(NAME(m_state)); + save_item(NAME(prev_ua)); + save_item(NAME(m_regsir)); + save_item(NAME(m_reg8bit)); + save_item(NAME(m_reg16bit)); + save_item(NAME(m_regmain)); + save_item(NAME(m_lines_status)); + + memset(m_regsir, 0, sizeof(m_regsir)); + memset(m_reg8bit, 0, sizeof(m_reg8bit)); + memset(m_reg16bit, 0, sizeof(m_reg16bit)); + memset(m_regmain, 0, sizeof(m_regmain)); + + // register state for debugger + state_add(HD61700_PC, "pc", m_pc).callimport().callexport().formatstr("%04X"); + state_add(HD61700_F, "f", m_flags).callimport().callexport().formatstr("%02X"); + state_add(HD61700_SX, "SX", REG_SX).callimport().callexport().formatstr("%02X"); + state_add(HD61700_SY, "SY", REG_SY).callimport().callexport().formatstr("%02X"); + state_add(HD61700_SZ, "SZ", REG_SZ).callimport().callexport().formatstr("%02X"); + + state_add(HD61700_PE, "pe", REG_PE).callimport().callexport().formatstr("%02X"); + state_add(HD61700_PD, "pd", REG_PD).callimport().callexport().formatstr("%02X"); + state_add(HD61700_IB, "ib", REG_IB).callimport().callexport().formatstr("%02X"); + state_add(HD61700_UA, "ua", REG_UA).callimport().callexport().formatstr("%02X"); + state_add(HD61700_IA, "ia", REG_IA).callimport().callexport().formatstr("%02X"); + state_add(HD61700_IE, "ie", REG_IE).callimport().callexport().formatstr("%02X"); + state_add(HD61700_TM, "tm", REG_TM).callimport().callexport().formatstr("%02X"); + + state_add(HD61700_IX, "ix", REG_IX).callimport().callexport().formatstr("%04X"); + state_add(HD61700_IY, "iy", REG_IY).callimport().callexport().formatstr("%04X"); + state_add(HD61700_IZ, "iz", REG_IZ).callimport().callexport().formatstr("%04X"); + state_add(HD61700_US, "us", REG_US).callimport().callexport().formatstr("%04X"); + state_add(HD61700_SS, "ss", REG_SS).callimport().callexport().formatstr("%04X"); + state_add(HD61700_KY, "ky", REG_KY).callimport().callexport().formatstr("%04X"); + + for (int ireg=0; ireg<32; ireg++) + { + std::string tmpstr; + state_add(HD61700_MAINREG + ireg, strformat(tmpstr, "R%d", ireg).c_str(), m_regmain[ireg]).callimport().callexport().formatstr("%02X"); + } + + state_add(STATE_GENPC, "curpc", m_curpc).callimport().callexport().formatstr("%8s").noshow(); + state_add(STATE_GENPCBASE, "curpcbase", m_ppc).callimport().callexport().formatstr("%8s").noshow(); + state_add(STATE_GENFLAGS, "GENFLAGS", m_flags).mask(0xff).formatstr("%8s").noshow(); + + // set our instruction counter + m_icountptr = &m_icount; +} + + +//------------------------------------------------- +// device_reset - reset up the device +//------------------------------------------------- + +void hd61700_cpu_device::device_reset() +{ + m_ppc = 0x0000; + m_curpc = 0x0000; + set_pc(0x0000); + m_flags = FLAG_SW; + m_state = 0; + m_irq_status = 0; + prev_ua = 0; + + memset(m_regsir, 0, sizeof(m_regsir)); + memset(m_reg8bit, 0, sizeof(m_reg8bit)); + memset(m_reg16bit, 0, sizeof(m_reg16bit)); + memset(m_regmain, 0, sizeof(m_regmain)); + + for (int i=0;i<6; i++) + m_lines_status[i] = CLEAR_LINE; +} + + + +//------------------------------------------------- +// device_timer - handler timer events +//------------------------------------------------- +void hd61700_cpu_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch(id) + { + case SEC_TIMER: + REG_TM++; + if ((REG_TM&0x3f) == 60) + { + REG_TM = (REG_TM & 0xc0) + 0x40; + + if (((REG_IE>>3) & (1<=0; i--) + { + if (REG_IB & (1<>8)&0xff); + push(REG_SS, (m_pc>>0)&0xff); + + set_pc(irq_vector[i]); + m_icount -= 12; + return true; + } + } + + return false; +} + + +//------------------------------------------------- +// execute - execute for the provided number of +// cycles +//------------------------------------------------- + +void hd61700_cpu_device::execute_run() +{ + do + { + debugger_instruction_hook(this, m_curpc); + + // verify that CPU is not in sleep + if (m_state & CPU_SLP) + { + m_icount -= 6; + } + else + { + UINT8 op; + + check_irqs(); + + m_ppc = m_curpc; + + // instruction fetch + op = read_op(); + + // execute the instruction + switch ( op ) + { + case 0x00: //adc + case 0x01: //sbc + case 0x08: //ad + case 0x09: //sb + { + UINT8 arg = read_op(); + UINT8 src = READ_REG(get_sir_im8(arg)); + UINT16 res = READ_REG(arg) + ((op&1) ? -src : +src); + + COND_WRITE_REG(op, arg, res & 0xff); + + CLEAR_FLAGS; + CHECK_FLAG_Z(res & 0xff); + CHECK_FLAGB_UZ_LZ(res); + CHECK_FLAG_C(res, 0xff); + + check_optional_jr(arg); + m_icount -= 3; + } + break; + + case 0x02: //ld + { + UINT8 arg = read_op(); + COPY_REG(arg, get_sir_im8(arg)); + + check_optional_jr(arg); + m_icount -= 3; + } + break; + + case 0x04: //anc + case 0x05: //nac + case 0x06: //orc + case 0x07: //xrc + case 0x0c: //an + case 0x0d: //na + case 0x0e: //or + case 0x0f: //xr + { + UINT8 arg = read_op(); + + UINT8 res = make_logic(op, READ_REG(arg), READ_REG(get_sir_im8(arg))); + + COND_WRITE_REG(op, arg, res); + + CLEAR_FLAGS; + CHECK_FLAG_Z(res & 0xff); + CHECK_FLAGB_UZ_LZ(res); + + //na(c) and or(c) always set C flag + if ((op&3) == 1 || (op&3) == 2) + SET_FLAG_C; + + check_optional_jr(arg); + m_icount -= 3; + } + break; + + case 0x0a: //adb + case 0x0b: //sbb + { + UINT8 arg = read_op(); + UINT16 res; + + if (op & 0x01) + res = make_bcd_sub(READ_REG(arg), READ_REG(get_sir_im8(arg))); + else + res = make_bcd_add(READ_REG(arg), READ_REG(get_sir_im8(arg))); + + WRITE_REG(arg, res & 0xff); + + CLEAR_FLAGS; + CHECK_FLAG_Z(res & 0xff); + CHECK_FLAGB_UZ_LZ(res); + CHECK_FLAG_C(res, 0xff); + + check_optional_jr(arg); + m_icount -= 3; + } + break; + + case 0x10: //st + { + UINT8 arg = read_op(); + UINT8 src = get_sir_im8(arg); + UINT16 offset = REG_GET16(src); + + mem_writebyte(REG_UA>>4, offset, READ_REG(arg)); + + check_optional_jr(arg); + m_icount -= 8; + } + break; + + case 0x11: //ld + { + UINT8 arg = read_op(); + UINT8 src = get_sir_im8(arg); + UINT16 offset = REG_GET16(src); + + WRITE_REG(arg, mem_readbyte(REG_UA>>4, offset)); + + check_optional_jr(arg); + m_icount -= 8; + } + break; + + case 0x12: //stl + { + UINT8 arg = read_op(); + m_lcd_write_cb((offs_t)0, READ_REG(arg)); + + check_optional_jr(arg); + m_icount -= 11; + } + break; + + case 0x13: //ldl + { + UINT8 arg = read_op(); + UINT8 res = m_lcd_read_cb(0); + + WRITE_REG(arg, res); + + check_optional_jr(arg); + m_icount -= 11; + } + break; + + case 0x14: //ppo/pfl + { + UINT8 arg = read_op(); + + if (arg & 0x40) + { + m_flags = (m_flags & 0x0f) | (READ_REG(arg) & 0xf0); + } + else + { + m_lcd_ctrl_cb((offs_t)0, READ_REG(arg)); + } + + check_optional_jr(arg); + m_icount -= 3; + } + break; + + case 0x15: //psr + { + UINT8 arg = read_op(); + WRITE_SREG(arg, READ_REG(arg)&0x1f); + + check_optional_jr(arg); + m_icount -= 3; + } + break; + + case 0x16: //pst + case 0x17: //pst + { + UINT8 arg = read_op(); + UINT8 src = READ_REG(arg); + UINT8 idx = GET_REG_IDX(op, arg); + + switch (idx) + { + case 0: //PE + case 1: //PD + WRITE_REG8(idx, src); + m_port_write_cb((offs_t)0, REG_PD & REG_PE); + break; + case 2: //IB + REG_IB = (REG_IB & 0x1f) | (src & 0xe0); + break; + case 3: //UA + WRITE_REG8(idx, src); + break; + case 4: //IA + m_kb_write_cb((offs_t)0, src); + WRITE_REG8(idx, src); + break; + case 5: //IE + REG_IB &= (((src>>3)&0x1f) | 0xe0); + m_irq_status &= ((src>>3)&0x1f); + WRITE_REG8(idx, src); + break; + case 6: //TM + case 7: //TM + // read-only + break; + } + + check_optional_jr(arg); + m_icount -= 3; + } + break; + + case 0x18: + { + UINT8 arg = read_op(); + UINT8 op1 = (arg>>5) & 0x03; + switch (op1) + { + case 0x00: //rod + case 0x02: //bid + { + UINT8 src = READ_REG(arg); + UINT8 res = (src>>1)&0x7f; + + if (!(op1&0x02)) + res = res | ((m_flags&FLAG_C) !=0 )<<7; + + WRITE_REG(arg, res); + + CLEAR_FLAGS; + CHECK_FLAG_Z(res & 0xff); + CHECK_FLAGB_UZ_LZ(res); + if (src&0x01) SET_FLAG_C; + } + break; + + case 0x01: //rou + case 0x03: //biu + { + UINT8 src = READ_REG(arg); + UINT8 res = (src<<1)&0xfe; + + if (!(op1&0x02)) + res = res | ((m_flags&FLAG_C) !=0 )<<0; + + WRITE_REG(arg, res); + + CLEAR_FLAGS; + CHECK_FLAG_Z(res & 0xff); + CHECK_FLAGB_UZ_LZ(res); + if (src&0x80) SET_FLAG_C; + } + break; + } + + check_optional_jr(arg); + m_icount -= 3; + } + break; + + case 0x1a: + { + UINT8 arg = read_op(); + UINT8 op1 = (arg>>5) & 0x03; + switch (op1) + { + case 0x00: //did + case 0x01: //diu + { + UINT8 res; + + if (op1&0x01) + res = (READ_REG(arg)<<4)&0xf0; + else + res = (READ_REG(arg)>>4)&0x0f; + + WRITE_REG(arg, res); + + CLEAR_FLAGS; + CHECK_FLAG_Z(res & 0xff); + CHECK_FLAGB_UZ_LZ(res); + } + break; + case 0x02: //byd + case 0x03: //byu + { + WRITE_REG(arg, 0); + CLEAR_FLAGS; + break; + } + } + + check_optional_jr(arg); + m_icount -= 3; + } + break; + + case 0x1b: //cmp/inv + { + UINT8 arg = read_op(); + UINT8 res = ~(READ_REG(arg)); + if (!(arg & 0x40)) res++; + + WRITE_REG(arg, res); + + CLEAR_FLAGS; + CHECK_FLAG_Z(res & 0xff); + CHECK_FLAGB_UZ_LZ(res); + if (res || (arg & 0x40)) SET_FLAG_C; + + check_optional_jr(arg); + m_icount -= 3; + } + break; + + case 0x1c: //gpo/gfl + { + UINT8 arg = read_op(); + UINT8 src = 0xff; + + if (arg&0x40) + { + src = m_flags; + } + else + { + src = m_port_read_cb(0); + src&=(~REG_PE); + } + + WRITE_REG(arg, src); + + check_optional_jr(arg); + m_icount -= 3; + } + break; + + case 0x1d: //gsr + { + UINT8 arg = read_op(); + WRITE_REG(arg, READ_SREG(arg)); + check_optional_jr(arg); + m_icount -= 3; + } + break; + + case 0x1e: //gst + case 0x1f: //gst + { + UINT8 arg = read_op(); + UINT8 idx = GET_REG_IDX(op, arg); + WRITE_REG(arg, READ_REG8(idx)); + check_optional_jr(arg); + m_icount -= 3; + } + break; + + case 0x20: //st + case 0x22: //sti + { + UINT8 arg = read_op(); + UINT16 prev_ir = REG_IX; + REG_IX += get_sign_mreg(arg); + + mem_writebyte(REG_UA>>4, REG_IX++, READ_REG(arg)); + + RESTORE_REG(op, REG_IX, prev_ir); + + m_icount -= 8; + } + break; + + case 0x21: //st + case 0x23: //sti + { + UINT8 arg = read_op(); + UINT16 prev_ir = REG_IZ; + REG_IZ += get_sign_mreg(arg); + + mem_writebyte(REG_UA>>6, REG_IZ++, READ_REG(arg)); + + RESTORE_REG(op, REG_IZ, prev_ir); + + m_icount -= 8; + } + break; + + case 0x24: //std + { + UINT8 arg = read_op(); + REG_IX += get_sign_mreg(arg); + + mem_writebyte(REG_UA>>4, REG_IX, READ_REG(arg)); + m_icount -= 6; + } + break; + + case 0x25: //std + { + UINT8 arg = read_op(); + REG_IZ += get_sign_mreg(arg); + + mem_writebyte(REG_UA>>6, REG_IZ, READ_REG(arg)); + m_icount -= 6; + } + break; + + case 0x26: //phs + { + UINT8 arg = read_op(); + + push(REG_SS, READ_REG(arg)); + m_icount -= 9; + } + break; + case 0x27: //phu + { + UINT8 arg = read_op(); + + push(REG_US, READ_REG(arg)); + m_icount -= 9; + } + break; + + case 0x28: //ld + case 0x2a: //ldi + { + UINT8 arg = read_op(); + UINT16 prev_ir = REG_IX; + REG_IX += get_sign_mreg(arg); + + WRITE_REG(arg, mem_readbyte(REG_UA>>4, REG_IX++)); + + RESTORE_REG(op, REG_IX, prev_ir); + + m_icount -= 8; + } + break; + + case 0x29: //ld + case 0x2b: //ldi + { + UINT8 arg = read_op(); + UINT16 prev_ir = REG_IZ; + REG_IZ += get_sign_mreg(arg); + + WRITE_REG(arg, mem_readbyte(REG_UA>>6, REG_IZ++)); + + RESTORE_REG(op, REG_IZ, prev_ir); + + m_icount -= 8; + } + break; + + case 0x2c: //ldd + { + UINT8 arg = read_op(); + REG_IX += get_sign_mreg(arg); + + WRITE_REG(arg, mem_readbyte(REG_UA>>4, REG_IX)); + + m_icount -= 6; + } + break; + + case 0x2d: //ldd + { + UINT8 arg = read_op(); + REG_IZ += get_sign_mreg(arg); + + WRITE_REG(arg, mem_readbyte(REG_UA>>6, REG_IZ)); + + m_icount -= 6; + } + break; + + case 0x2e: //pps + { + UINT8 arg = read_op(); + WRITE_REG(arg, pop(REG_SS)); + + m_icount -= 11; + } + break; + case 0x2f: //ppu + { + UINT8 arg = read_op(); + WRITE_REG(arg, pop(REG_US)); + + m_icount -= 11; + } + break; + + case 0x30: //jp z + case 0x31: //jp nc + case 0x32: //jp lz + case 0x33: //jp uz + case 0x34: //jp nz + case 0x35: //jp c + case 0x36: //jp nlz + case 0x37: //unconditional jp + { + UINT8 lsb = read_op(); + if (m_pc < INT_ROM) read_op(); + UINT8 msb = read_op(); + + if (check_cond(op)) + set_pc((msb<<8) | lsb); + m_icount -= 3; + } + break; + + case 0x38: //adc + case 0x3a: //sbc + case 0x3c: //ad + case 0x3e: //sb + { + UINT8 arg = read_op(); + UINT16 offset = REG_IX + get_sign_mreg(arg); + UINT8 src = mem_readbyte(REG_UA>>4, offset); + + UINT16 res = src + ((op & 2) ? -READ_REG(arg) : +READ_REG(arg)) ; + + if ((op & 4)) + mem_writebyte(REG_UA>>4, offset, res & 0xff); + + CLEAR_FLAGS; + CHECK_FLAG_Z(res & 0xff); + CHECK_FLAGB_UZ_LZ(res); + CHECK_FLAG_C(res, 0xff); + + m_icount -= 9; + } + break; + + case 0x39: //adc + case 0x3b: //sbc + case 0x3d: //ad + case 0x3f: //sb + { + UINT8 arg = read_op(); + UINT16 offset = REG_IZ + get_sign_mreg(arg); + UINT8 src = mem_readbyte(REG_UA>>6, offset); + + UINT16 res = src + ((op & 2) ? -READ_REG(arg) : +READ_REG(arg)) ; + + if ((op & 4)) + mem_writebyte(REG_UA>>6, offset, res & 0xff); + + CLEAR_FLAGS; + CHECK_FLAG_Z(res & 0xff); + CHECK_FLAGB_UZ_LZ(res); + CHECK_FLAG_C(res, 0xff); + + m_icount -= 9; + } + break; + + case 0x40: //adc + case 0x41: //sbc + case 0x48: //ad + case 0x49: //sb + { + UINT8 arg = read_op(); + UINT8 src = read_op(); + UINT16 res = READ_REG(arg) + ((op&1) ? -src : +src); + + COND_WRITE_REG(op, arg, res & 0xff); + + CLEAR_FLAGS; + CHECK_FLAG_Z(res & 0xff); + CHECK_FLAGB_UZ_LZ(res); + CHECK_FLAG_C(res, 0xff); + + check_optional_jr(arg); + m_icount -= 3; + } + break; + + case 0x42: //ld + { + UINT8 arg = read_op(); + UINT8 src = read_op() ; + + WRITE_REG(arg, src); + + check_optional_jr(arg); + m_icount -= 3; + } + break; + + case 0x44: //anc + case 0x45: //nac + case 0x46: //orc + case 0x47: //xrc + case 0x4c: //an + case 0x4d: //na + case 0x4e: //or + case 0x4f: //xr + { + UINT8 arg = read_op(); + UINT8 src = read_op(); + + UINT8 res = make_logic(op, READ_REG(arg), src); + + COND_WRITE_REG(op, arg, res); + + CLEAR_FLAGS; + CHECK_FLAG_Z(res & 0xff); + CHECK_FLAGB_UZ_LZ(res); + + //na(c) and or(c) always set C flag + if ((op&3) == 1 || (op&3) == 2) + SET_FLAG_C; + + check_optional_jr(arg); + m_icount -= 3; + } + break; + + case 0x4a: //adb + case 0x4b: //sbb + { + UINT8 arg = read_op(); + UINT8 src = read_op(); + UINT16 res; + + if (op & 0x01) + res = make_bcd_sub(READ_REG(arg), src); + else + res = make_bcd_add(READ_REG(arg), src); + + WRITE_REG(arg, res & 0xff); + + CLEAR_FLAGS; + CHECK_FLAG_Z(res & 0xff); + CHECK_FLAGB_UZ_LZ(res); + CHECK_FLAG_C(res, 0xff); + + check_optional_jr(arg); + m_icount -= 3; + } + break; + + case 0x50: //st + { + UINT8 arg = read_op(); + UINT8 src = read_op(); + UINT16 offset = REG_GET16(READ_SREG(arg)); + + mem_writebyte(REG_UA>>4, offset, src); + m_icount -= 8; + } + break; + + case 0x51: //ld + { + UINT8 arg = read_op(); + UINT8 src = read_op(); + + WRITE_REG(arg, src); + m_icount -= 8; + } + break; + + case 0x52: //stl + { + UINT8 arg = read_op(); + m_lcd_write_cb((offs_t)0, arg); + + m_icount -= 12; + } + break; + + case 0x54: //ppo/pfl + { + UINT8 arg = read_op(); + UINT8 src = read_op(); + + if (arg & 0x40) + { + m_flags = (m_flags & 0x0f) | (src & 0xf0); + } + else + { + m_lcd_ctrl_cb((offs_t)0, src); + } + + m_icount -= 3; + } + break; + + case 0x55: //psr + { + UINT8 arg = read_op(); + WRITE_SREG(arg, arg&0x1f); + + m_icount -= 3; + } + break; + + case 0x56: //pst + case 0x57: //pst + { + UINT8 arg = read_op(); + UINT8 src = read_op(); + UINT8 idx = GET_REG_IDX(op, arg); + + switch (idx) + { + case 0: //PE + case 1: //PD + WRITE_REG8(idx, src); + m_port_write_cb((offs_t)0, REG_PD & REG_PE); + break; + case 2: //IB + REG_IB = (REG_IB & 0x1f) | (src & 0xe0); + break; + case 3: //UA + WRITE_REG8(idx, src); + break; + case 4: //IA + m_kb_write_cb((offs_t)0, src); + WRITE_REG8(idx, src); + break; + case 5: //IE + REG_IB &= (((src>>3)&0x1f) | 0xe0); + m_irq_status &= ((src>>3)&0x1f); + WRITE_REG8(idx, src); + break; + case 6: //TM + case 7: //TM + // read-only + break; + } + + m_icount -= 3; + } + break; + + case 0x58: //bups + case 0x59: //bdns + { + UINT8 arg = read_op(); + UINT8 tmp; + UINT16 res; + + for(;;) + { + tmp = mem_readbyte(REG_UA>>4, REG_IX); + mem_writebyte(REG_UA>>6, REG_IZ, tmp); + + res = tmp - arg; + if (REG_IX == REG_IY || !res) + break; + + REG_IX += ((op&1) ? -1 : +1); + REG_IZ += ((op&1) ? -1 : +1); + m_icount -= 6; + } + + CLEAR_FLAGS; + CHECK_FLAG_Z(res & 0xff); + CHECK_FLAGB_UZ_LZ(res); + CHECK_FLAG_C(res, 0xff); + + m_icount -= 9; + } + break; + + case 0x5c: //sup + case 0x5d: //sdn + { + UINT8 arg = read_op(); + UINT16 res; + + for(;;) + { + res = mem_readbyte(REG_UA>>4, REG_IX) - arg; + + if (REG_IX == REG_IY || !res) + break; + + REG_IX += ((op&1) ? -1 : +1); + m_icount -= 6; + } + + CLEAR_FLAGS; + CHECK_FLAG_Z(res & 0xff); + CHECK_FLAGB_UZ_LZ(res); + CHECK_FLAG_C(res, 0xff); + + m_icount -= 9; + } + break; + + case 0x60: //st + case 0x62: //sti + { + UINT8 arg = read_op(); + UINT16 prev_ir = REG_IX; + REG_IX += get_sign_im8(arg); + + mem_writebyte(REG_UA>>4, REG_IX++, READ_REG(arg)); + + RESTORE_REG(op, REG_IX, prev_ir); + + m_icount -= 8; + } + break; + + case 0x61: //st + case 0x63: //sti + { + UINT8 arg = read_op(); + UINT16 prev_ir = REG_IZ; + REG_IZ += get_sign_im8(arg); + + mem_writebyte(REG_UA>>6, REG_IZ++, READ_REG(arg)); + + RESTORE_REG(op, REG_IZ, prev_ir); + m_icount -= 8; + } + break; + + case 0x64: //std + { + UINT8 arg = read_op(); + REG_IX += get_sign_im8(arg); + + mem_writebyte(REG_UA>>4, REG_IX, READ_REG(arg)); + m_icount -= 6; + } + break; + + case 0x65: //std + { + UINT8 arg = read_op(); + REG_IZ += get_sign_im8(arg); + + mem_writebyte(REG_UA>>6, REG_IZ, READ_REG(arg)); + m_icount -= 6; + } + break; + + case 0x68: //ld + case 0x6a: //ldi + { + UINT8 arg = read_op(); + UINT16 prev_ir = REG_IX; + REG_IX += get_sign_im8(arg); + + WRITE_REG(arg, mem_readbyte(REG_UA>>4, REG_IX++)); + + RESTORE_REG(op, REG_IX, prev_ir); + m_icount -= 8; + } + break; + + case 0x69: //ld + case 0x6b: //ldi + { + UINT8 arg = read_op(); + UINT16 prev_ir = REG_IZ; + REG_IZ += get_sign_im8(arg); + + WRITE_REG(arg, mem_readbyte(REG_UA>>6, REG_IZ++)); + + RESTORE_REG(op, REG_IZ, prev_ir); + m_icount -= 8; + } + break; + + case 0x6c: //ldd + { + UINT8 arg = read_op(); + REG_IX += get_sign_im8(arg); + + WRITE_REG(arg, mem_readbyte(REG_UA>>4, REG_IX)); + m_icount -= 6; + } + break; + + case 0x6d: //ldd + { + UINT8 arg = read_op(); + REG_IZ += get_sign_im8(arg); + + WRITE_REG(arg, mem_readbyte(REG_UA>>6, REG_IZ)); + m_icount -= 6; + } + break; + + case 0x70: //cal z + case 0x71: //cal nc + case 0x72: //cal lz + case 0x73: //cal uz + case 0x74: //cal nz + case 0x75: //cal c + case 0x76: //cal nlz + case 0x77: //unconditional cal + { + UINT8 lsb = read_op(); + if (m_pc < INT_ROM) read_op(); + UINT8 msb = read_op(); + + if (check_cond(op)) + { + m_pc--; + push(REG_SS, (m_pc>>8)&0xff); + push(REG_SS, (m_pc>>0)&0xff); + + set_pc((msb<<8) | lsb); + m_icount -= 6; + } + m_icount -= 3; + } + break; + + case 0x78: //adc + case 0x7a: //sbc + case 0x7c: //ad + case 0x7e: //sb + { + UINT8 arg = read_op(); + UINT16 offset = REG_IX + get_sign_im8(arg); + UINT8 src = mem_readbyte(REG_UA>>4, offset); + + UINT16 res = src + ((op & 2) ? -READ_REG(arg) : +READ_REG(arg)) ; + + if ((op & 4)) + mem_writebyte(REG_UA>>4, offset, res & 0xff); + + CLEAR_FLAGS; + CHECK_FLAG_Z(res & 0xff); + CHECK_FLAGB_UZ_LZ(res); + CHECK_FLAG_C(res, 0xff); + + m_icount -= 9; + } + break; + + case 0x79: //adc + case 0x7b: //sbc + case 0x7d: //ad + case 0x7f: //sb + { + UINT8 arg = read_op(); + UINT16 offset = REG_IZ + get_sign_im8(arg); + UINT8 src = mem_readbyte(REG_UA>>6, offset); + + UINT16 res = src + ((op & 2) ? -READ_REG(arg) : +READ_REG(arg)) ; + + if ((op & 4)) + mem_writebyte(REG_UA>>6, offset, res & 0xff); + + CLEAR_FLAGS; + CHECK_FLAG_Z(res & 0xff); + CHECK_FLAGB_UZ_LZ(res); + CHECK_FLAG_C(res, 0xff); + + m_icount -= 9; + } + break; + + case 0x80: //adcw + case 0x81: //sbcw + case 0x88: //adw + case 0x89: //sbw + { + UINT8 arg = read_op(); + UINT8 src = get_sir_im8(arg); + UINT32 res = REG_GET16(arg) + ((op & 0x01) ? -REG_GET16(src) : +REG_GET16(src)); + + if (op & 0x08) REG_PUT16(arg, res&0xffff); + + CLEAR_FLAGS; + CHECK_FLAG_Z(res & 0xffff); + CHECK_FLAGW_UZ_LZ(res); + CHECK_FLAG_C(res, 0xffff); + + check_optional_jr(arg); + m_icount -= 8; + } + break; + + case 0x82: //ldw + { + UINT8 arg = read_op(); + UINT8 src = get_sir_im8(arg); + + COPY_REG(arg, src); + COPY_REG(arg+1, src+1); + + check_optional_jr(arg); + m_icount -= 8; + } + break; + + case 0x84: //ancw + case 0x85: //nacw + case 0x86: //orcw + case 0x87: //xrcw + case 0x8c: //anw + case 0x8d: //naw + case 0x8e: //orw + case 0x8f: //xrw + { + UINT8 arg = read_op(); + UINT8 src = get_sir_im8(arg); + + UINT8 res0 = make_logic(op, READ_REG(arg), READ_REG(src)); + COND_WRITE_REG(op, arg, res0); + + UINT8 res1 = make_logic(op, READ_REG(arg+1), READ_REG(src+1)); + COND_WRITE_REG(op, arg+1, res1); + + CLEAR_FLAGS; + CHECK_FLAG_Z(res0 || res1); + CHECK_FLAGB_UZ_LZ(res1); + + //na(c) and or(c) always set C flag + if ((op&3) == 1 || (op&3) == 2) + SET_FLAG_C; + + check_optional_jr(arg); + m_icount -= 8; + } + break; + + case 0x8a: //adbw + case 0x8b: //sbbw + { + UINT8 arg = read_op(); + UINT8 src = get_sir_im8(arg); + UINT16 res0, res1; + + if (op & 0x01) + res0 = make_bcd_sub(READ_REG(arg), READ_REG(src)); + else + res0 = make_bcd_add(READ_REG(arg), READ_REG(src)); + + WRITE_REG(arg, res0 & 0xff); + + res1 = (res0>0xff) ? 1 : 0 ; + + if (op & 0x01) + res1 = make_bcd_sub(READ_REG(arg+1), READ_REG(src+1) + res1); + else + res1 = make_bcd_add(READ_REG(arg+1), READ_REG(src+1) + res1); + + WRITE_REG(arg+1, res1 & 0xff); + + CLEAR_FLAGS; + CHECK_FLAG_Z(res0 || res1); + CHECK_FLAGB_UZ_LZ(res1); + CHECK_FLAG_C(res1, 0xff); + + check_optional_jr(arg); + m_icount -= 8; + } + break; + + case 0x90: //stw + { + UINT8 arg = read_op(); + UINT8 src = get_sir_im8(arg); + UINT16 offset = REG_GET16(src); + + mem_writebyte(REG_UA>>4, offset+0, READ_REG(arg+0)); + mem_writebyte(REG_UA>>4, offset+1, READ_REG(arg+1)); + + check_optional_jr(arg); + m_icount -= 11; + } + break; + + case 0x91: //ldw + { + UINT8 arg = read_op(); + UINT8 src = get_sir_im8(arg); + UINT16 offset = REG_GET16(src); + + WRITE_REG(arg+0, mem_readbyte(REG_UA>>4, offset+0)); + WRITE_REG(arg+1, mem_readbyte(REG_UA>>4, offset+1)); + + check_optional_jr(arg); + m_icount -= 11; + } + break; + + case 0x92: //stlw + { + UINT8 arg = read_op(); + + m_lcd_write_cb((offs_t)0, READ_REG(arg)); + m_lcd_write_cb((offs_t)0, READ_REG(arg+1)); + + check_optional_jr(arg); + m_icount -= 19; + } + break; + + case 0x93: //ldcw + { + UINT8 arg = read_op(); + UINT8 reg0, reg1; + + reg0 = m_lcd_read_cb(0); + reg1 = m_lcd_read_cb(0); + + WRITE_REG(arg+0, reg0); + WRITE_REG(arg+1, reg1); + + check_optional_jr(arg); + m_icount -= 19; + } + break; + + case 0x96: //pre + case 0x97: //pre + { + UINT8 arg = read_op(); + UINT8 idx = GET_REG_IDX(op, arg); + + if (idx < 5) + m_reg16bit[idx] = REG_GET16(arg); + + check_optional_jr(arg); + m_icount -= 8; + } + break; + + case 0x98: //rodw + { + UINT8 arg = read_op(); + UINT8 op1 = (arg>>5) & 0x03; + switch (op1) + { + case 0x00: //rodw + case 0x02: //bidw + { + UINT16 src = REG_GET16(arg-1); + UINT16 res = (src>>1)&0x7fff; + + if (!(op1&0x02)) + res = res | ((m_flags&FLAG_C) !=0 )<<15; + + REG_PUT16(arg-1, res); + + CLEAR_FLAGS; + CHECK_FLAG_Z(res & 0xffff); + CHECK_FLAGB_UZ_LZ(res); + if (src&0x01) SET_FLAG_C; + } + break; + + case 0x01: //rouw + case 0x03: //biuw + { + UINT16 src = REG_GET16(arg); + UINT16 res = (src<<1)&0xfffe; + + if (!(op1&0x02)) + res = res | ((m_flags&FLAG_C) !=0 )<<0; + + REG_PUT16(arg, res); + + CLEAR_FLAGS; + CHECK_FLAG_Z(res & 0xffff); + CHECK_FLAGW_UZ_LZ(res); + if (src&0x8000) SET_FLAG_C; + } + break; + } + + check_optional_jr(arg); + m_icount -= 11; + } + break; + + case 0x9a: + { + UINT8 arg = read_op(); + UINT8 op1 = (arg>>5) & 0x03; + switch (op1) + { + case 0x00: //didw + { + UINT16 src = (REG_GET16(arg-1)>>4)&0x0fff; + REG_PUT16(arg-1, src); + + CLEAR_FLAGS; + CHECK_FLAG_Z(src & 0xffff); + CHECK_FLAGB_UZ_LZ(src); + } + break; + + case 0x01: //diuw + { + UINT16 src = (REG_GET16(arg)<<4)&0xfff0; + REG_PUT16(arg, src); + + CLEAR_FLAGS; + CHECK_FLAG_Z(src & 0xffff); + CHECK_FLAGW_UZ_LZ(src); + } + break; + + case 0x02: //bydw + { + UINT8 src = READ_REG(arg); + + WRITE_REG(arg, 0); + WRITE_REG(arg-1, src); + + CLEAR_FLAGS; + CHECK_FLAG_Z(src & 0xff); + CHECK_FLAGB_UZ_LZ(src); + } + break; + + case 0x03: //byuw + { + UINT8 src = READ_REG(arg); + + WRITE_REG(arg, 0); + WRITE_REG(arg+1, src); + + CLEAR_FLAGS; + CHECK_FLAG_Z(src & 0xff); + CHECK_FLAGB_UZ_LZ(src); + } + break; + } + + check_optional_jr(arg); + m_icount -= 11; + } + break; + + case 0x9b: //cmpw/invw + { + UINT8 arg = read_op(); + UINT16 res = ~(REG_GET16(arg)); + if (!(arg & 0x40)) res++; + + REG_PUT16(arg, res); + + CLEAR_FLAGS; + CHECK_FLAG_Z(res & 0xffff); + CHECK_FLAGW_UZ_LZ(res); + + if (res || (arg & 0x40)) SET_FLAG_C; + + check_optional_jr(arg); + m_icount -= 8; + } + break; + + case 0x9c: //gpow/gflw + { + UINT8 arg = read_op(); + UINT8 reg0, reg1; + + if (arg&0x40) + { + reg0 = reg1 = m_flags; + } + else + { + reg0 = m_port_read_cb(0); + reg1 = m_port_read_cb(0); + + reg0&=(~REG_PE); + reg1&=(~REG_PE); + + } + + WRITE_REG(arg+0, reg0); + WRITE_REG(arg+1, reg1); + + check_optional_jr(arg); + m_icount -= 8; + } + break; + + case 0x9e: //gre + case 0x9f: //gre + { + UINT8 arg = read_op(); + UINT8 idx = GET_REG_IDX(op, arg); + UINT16 src; + + if (idx >= 5) + { + UINT16 port = m_kb_read_cb(0); + src = (REG_KY & 0x0f00) | (port & 0xf0ff); + } + else + src = m_reg16bit[idx]; + + REG_PUT16(arg, src); + + check_optional_jr(arg); + m_icount -= 8; + } + break; + + case 0xa0: //stw + case 0xa2: //stiw + { + UINT8 arg = read_op(); + UINT16 prev_ir = REG_IX; + UINT8 ir_inc = READ_REG(get_sir_im8(arg)); + + REG_IX += ((arg & 0x80) ? -ir_inc : +ir_inc); + + mem_writebyte(REG_UA>>4, REG_IX++, READ_REG(arg+0)); + mem_writebyte(REG_UA>>4, REG_IX++, READ_REG(arg+1)); + + RESTORE_REG(op, REG_IX, prev_ir); + m_icount -= 11; + } + break; + + case 0xa1: //stw + case 0xa3: //stiw + { + UINT8 arg = read_op(); + UINT16 prev_ir = REG_IZ; + UINT8 ir_inc = READ_REG(get_sir_im8(arg)); + + REG_IZ += ((arg & 0x80) ? -ir_inc : +ir_inc); + + mem_writebyte(REG_UA>>6, REG_IZ++, READ_REG(arg+0)); + mem_writebyte(REG_UA>>6, REG_IZ++, READ_REG(arg+1)); + + RESTORE_REG(op, REG_IZ, prev_ir); + m_icount -= 11; + } + break; + + case 0xa4: //stdw + { + UINT8 arg = read_op(); + UINT8 ir_inc = READ_REG(get_sir_im8(arg)); + + REG_IX += ((arg & 0x80) ? -ir_inc : +ir_inc); + + mem_writebyte(REG_UA>>4, REG_IX--, READ_REG(arg-0)); + mem_writebyte(REG_UA>>4, REG_IX, READ_REG(arg-1)); + + m_icount -= 9; + } + break; + case 0xa5: //stdw + { + UINT8 arg = read_op(); + UINT8 ir_inc = READ_REG(get_sir_im8(arg)); + + REG_IZ += ((arg & 0x80) ? -ir_inc : +ir_inc); + + mem_writebyte(REG_UA>>6, REG_IZ--, READ_REG(arg-0)); + mem_writebyte(REG_UA>>6, REG_IZ, READ_REG(arg-1)); + + m_icount -= 9; + } + break; + + case 0xa6: //phsw + { + UINT8 arg = read_op(); + push(REG_SS, READ_REG(arg)); + push(REG_SS, READ_REG(arg-1)); + + m_icount -= 12; + } + break; + case 0xa7: //phuw + { + UINT8 arg = read_op(); + push(REG_US, READ_REG(arg)); + push(REG_US, READ_REG(arg-1)); + + m_icount -= 12; + } + break; + + case 0xa8: //ldw + case 0xaa: //ldiw + { + UINT8 arg = read_op(); + UINT16 prev_ir = REG_IX; + UINT8 ir_inc = READ_REG(get_sir_im8(arg)); + + REG_IX += ((arg & 0x80) ? -ir_inc : +ir_inc); + + WRITE_REG(arg+0, mem_readbyte(REG_UA>>4, REG_IX++)); + WRITE_REG(arg+1, mem_readbyte(REG_UA>>4, REG_IX++)); + + RESTORE_REG(op, REG_IX, prev_ir); + + m_icount -= 11; + } + break; + + case 0xa9: //ldw + case 0xab: //ldiw + { + UINT8 arg = read_op(); + UINT16 prev_ir = REG_IZ; + UINT8 ir_inc = READ_REG(get_sir_im8(arg)); + + REG_IZ += ((arg & 0x80) ? -ir_inc : +ir_inc); + + WRITE_REG(arg+0, mem_readbyte(REG_UA>>6, REG_IZ++)); + WRITE_REG(arg+1, mem_readbyte(REG_UA>>6, REG_IZ++)); + + RESTORE_REG(op, REG_IZ, prev_ir); + + m_icount -= 11; + } + break; + + case 0xac: //lddw + { + UINT8 arg = read_op(); + UINT8 ir_inc = READ_REG(get_sir_im8(arg)); + + REG_IX += ((arg & 0x80) ? -ir_inc : +ir_inc); + + WRITE_REG(arg-0, mem_readbyte(REG_UA>>4, REG_IX--)); + WRITE_REG(arg-1, mem_readbyte(REG_UA>>4, REG_IX)); + + m_icount -= 9; + } + break; + + case 0xad: //lddw + { + UINT8 arg = read_op(); + UINT8 ir_inc = READ_REG(get_sir_im8(arg)); + + REG_IZ += ((arg & 0x80) ? -ir_inc : +ir_inc); + + WRITE_REG(arg-0, mem_readbyte(REG_UA>>6, REG_IZ--)); + WRITE_REG(arg-1, mem_readbyte(REG_UA>>6, REG_IZ)); + + m_icount -= 9; + } + break; + + case 0xae: //ppsw + case 0xaf: //ppuw + { + UINT8 arg = read_op(); + + WRITE_REG(arg, pop((op&1) ? REG_US : REG_SS)); + WRITE_REG(arg+1, pop((op&1) ? REG_US : REG_SS)); + + m_icount -= 14; + } + break; + + case 0xb0: //jr z + case 0xb1: //jr nc + case 0xb2: //jr lz + case 0xb3: //jr uz + case 0xb4: //jr nz + case 0xb5: //jr c + case 0xb6: //jr nlz + case 0xb7: //unconditional jr + { + UINT8 arg = read_op(); + UINT32 new_pc = m_pc-1 + get_im_7(arg); + + if (check_cond(op)) + set_pc(new_pc); + m_icount -= 3; + } + break; + + case 0xb8: //adcw + case 0xbc: //adw + { + UINT8 arg = read_op(); + UINT8 ir_inc = READ_REG(get_sir_im8(arg)); + + UINT16 offset = REG_IX + ((arg & 0x80) ? -ir_inc : +ir_inc); + + UINT16 src0 = mem_readbyte(REG_UA>>4, offset) + READ_REG(arg); + UINT16 src1 = mem_readbyte(REG_UA>>4, offset+1) + READ_REG(arg+1) + ((src0>0xff) ? 1 : 0); + + if (op&0x04) + { + mem_writebyte(REG_UA>>4, offset+0, src0 & 0xff); + mem_writebyte(REG_UA>>4, offset+1, src1 & 0xff); + } + + CLEAR_FLAGS; + CHECK_FLAGB_UZ_LZ(src1); + CHECK_FLAG_Z(src0 || src1); + CHECK_FLAG_C(src1, 0xff); + + m_icount -= 15; + } + break; + + case 0xba: //sbcw + case 0xbe: //sbw + { + UINT8 arg = read_op(); + UINT8 ir_inc = READ_REG(get_sir_im8(arg)); + + UINT16 offset = REG_IX + ((arg & 0x80) ? -ir_inc : +ir_inc); + + UINT16 src0 = mem_readbyte(REG_UA>>4, offset) - READ_REG(arg); + UINT16 src1 = mem_readbyte(REG_UA>>4, offset+1) - READ_REG(arg+1) - ((src0>0xff) ? 1 : 0); + + if (op&0x04) + { + mem_writebyte(REG_UA>>4, offset+0, src0 & 0xff); + mem_writebyte(REG_UA>>4, offset+1, src1 & 0xff); + } + + CLEAR_FLAGS; + CHECK_FLAGB_UZ_LZ(src1); + CHECK_FLAG_Z(src0 || src1); + CHECK_FLAG_C(src1, 0xff); + + m_icount -= 15; + } + break; + + case 0xb9: //adcw + case 0xbd: //adw + { + UINT8 arg = read_op(); + UINT8 ir_inc = READ_REG(get_sir_im8(arg)); + + UINT16 offset = REG_IZ + ((arg & 0x80) ? -ir_inc : +ir_inc); + + UINT16 src0 = mem_readbyte(REG_UA>>6, offset) + READ_REG(arg); + UINT16 src1 = mem_readbyte(REG_UA>>6, offset+1) + READ_REG(arg+1) + ((src0>0xff) ? 1 : 0); + + if (op&0x04) + { + mem_writebyte(REG_UA>>6, offset+0, src0 & 0xff); + mem_writebyte(REG_UA>>6, offset+1, src1 & 0xff); + } + + CLEAR_FLAGS; + CHECK_FLAGB_UZ_LZ(src1); + CHECK_FLAG_Z(src0 || src1); + CHECK_FLAG_C(src1, 0xff); + + m_icount -= 15; + } + break; + + case 0xbb: //sbcw + case 0xbf: //sbw + { + UINT8 arg = read_op(); + UINT8 ir_inc = READ_REG(get_sir_im8(arg)); + + UINT16 offset = REG_IZ + ((arg & 0x80) ? -ir_inc : +ir_inc); + + UINT16 src0 = mem_readbyte(REG_UA>>6, offset) - READ_REG(arg); + UINT16 src1 = mem_readbyte(REG_UA>>6, offset+1) - READ_REG(arg+1) - ((src0>0xff) ? 1 : 0); + + if (op&0x04) + { + mem_writebyte(REG_UA>>6, offset+0, src0 & 0xff); + mem_writebyte(REG_UA>>6, offset+1, src1 & 0xff); + } + + CLEAR_FLAGS; + CHECK_FLAGB_UZ_LZ(src1); + CHECK_FLAG_Z(src0 || src1); + CHECK_FLAG_C(src1, 0xff); + + m_icount -= 15; + } + break; + + case 0xc0: //adbcm + case 0xc1: //sbbcm + case 0xc8: //adbm + case 0xc9: //sbbm + { + UINT8 arg = read_op(); + UINT8 arg1 = read_op(); + UINT8 dst = arg; + UINT8 src = get_sir_im8(arg, arg1); + UINT8 c, f; + UINT16 res = 0; + + c = f = 0; + for (int n=GET_IM3(arg1); n>0; n--) + { + if (op & 0x01) + res = make_bcd_sub(READ_REG(dst), READ_REG(src) + c); + else + res = make_bcd_add(READ_REG(dst), READ_REG(src) + c); + + c = (res > 0xff) ? 1 : 0; + + COND_WRITE_REG(op, dst, res&0xff); + + f |= (res&0xff); + dst++; src++; + + m_icount -= 5; + } + + CLEAR_FLAGS; + CHECK_FLAG_Z(f); + CHECK_FLAGB_UZ_LZ(res); + CHECK_FLAG_C(res, 0xff); + + check_optional_jr(arg); + m_icount -= 2; + } + break; + + case 0xc2: //ldm + { + UINT8 arg = read_op(); + UINT8 arg1 = read_op(); + UINT8 dst = arg; + UINT8 src = get_sir_im8(arg, arg1); + + for (int n=GET_IM3(arg1); n>0; n--) + { + COPY_REG(dst++, src++); + m_icount -= 5; + } + + check_optional_jr(arg); + m_icount -= 2; + } + break; + + case 0xc4: //ancm + case 0xc5: //nacm + case 0xc6: //orcm + case 0xc7: //xrcm + case 0xcc: //anm + case 0xcd: //nam + case 0xce: //orm + case 0xcf: //xrm + { + UINT8 arg = read_op(); + UINT8 arg1 = read_op(); + UINT8 dst = arg; + UINT8 src = get_sir_im8(arg, arg1); + UINT8 res = 0, f = 0; + + for (int n=GET_IM3(arg1); n>0; n--) + { + res = make_logic(op, READ_REG(dst), READ_REG(src)); + + COND_WRITE_REG(op, dst, res); + + f |= res; + + dst++; src++; + + m_icount -= 3; + } + + CLEAR_FLAGS; + CHECK_FLAG_Z(f); + CHECK_FLAGB_UZ_LZ(res); + + //na(c) and or(c) always set C flag + if ((op&3) == 1 || (op&3) == 2) + SET_FLAG_C; + + check_optional_jr(arg); + } + break; + + case 0xca: //adbm + case 0xcb: //sbbm + { + UINT8 arg = read_op(); + UINT8 arg1 = read_op(); + UINT8 dst = arg; + UINT16 res = 0; + UINT8 src, f; + src = arg1 & 0x1f; + f = 0; + + for (int n=GET_IM3(arg1); n>0; n--) + { + if (op & 0x01) + res = make_bcd_sub(READ_REG(dst), src); + else + res = make_bcd_add(READ_REG(dst), src); + + src = (res > 0xff) ? 1 : 0; + + COND_WRITE_REG(op, dst, res&0xff); + + f |= (res&0xff); + dst++; + + m_icount -= 5; + } + + CLEAR_FLAGS; + CHECK_FLAG_Z(f); + CHECK_FLAGB_UZ_LZ(res); + CHECK_FLAG_C(res, 0xff); + + check_optional_jr(arg); + m_icount -= 2; + } + break; + + case 0xd0: //stw + { + UINT8 arg = read_op(); + UINT16 offset = REG_GET16(READ_SREG(arg)); + + mem_writebyte(REG_UA>>4, offset+0, read_op()); + mem_writebyte(REG_UA>>4, offset+1, read_op()); + + m_icount -= 11; + } + break; + + case 0xd1: //ldw + { + UINT8 arg = read_op(); + UINT8 reg0 = read_op(); + UINT8 reg1 = read_op(); + + WRITE_REG(arg+0, reg0); + WRITE_REG(arg+1, reg1); + m_icount -= 11; + } + break; + + case 0xd2: //stlm + { + UINT8 arg = read_op(); + UINT8 arg1 = read_op(); + + for (int n=GET_IM3(arg1); n>0; n--) + { + m_lcd_write_cb((offs_t)0, READ_REG(arg)); + + arg++; + m_icount -= 8; + } + + m_icount -= 3; + } + break; + + case 0xd3: //ldlm + { + UINT8 arg = read_op(); + UINT8 arg1 = read_op(); + UINT8 src; + + for (int n=GET_IM3(arg1); n>0; n--) + { + src = m_lcd_read_cb(0); + + WRITE_REG(arg, src++); + + m_icount -= 8; + } + + m_icount -= 3; + } + break; + + case 0xd6: //pre + case 0xd7: //pre + { + UINT8 arg = read_op(); + UINT8 lsb = read_op(); + UINT8 msb = read_op(); + UINT8 idx = GET_REG_IDX(op, arg); + + if (idx < 5) + m_reg16bit[idx] = (msb<<8) | lsb; + + m_icount -= 8; + } + break; + + case 0xd8: //bup + case 0xd9: //bdn + { + UINT8 src; + for(;;) + { + src = mem_readbyte(REG_UA>>4, REG_IX); + mem_writebyte(REG_UA>>6, REG_IZ, src); + + if (REG_IX == REG_IY) + break; + + REG_IX += ((op&1) ? -1 : +1); + REG_IZ += ((op&1) ? -1 : +1); + m_icount -= 6; + } + + m_icount -= 9; + } + break; + + case 0xda: + { + UINT8 arg = read_op(); + UINT8 op1 = (arg>>5) & 0x03; + switch (op1) + { + case 0x00: //didm + { + UINT8 arg1 = read_op(); + UINT8 r1 = 0, r2 = 0; + + for (int n=GET_IM3(arg1); n>0; n--) + { + r2 = r1; + r1 = READ_REG(arg); + r2 = ((r1>>4)&0x0f) | ((r2<<4)&0xf0); + WRITE_REG(arg--, r2); + m_icount -= 5; + } + + CLEAR_FLAGS; + CHECK_FLAGB_UZ_LZ(r2); + CHECK_FLAG_Z(r2); + } + break; + + case 0x01: //dium + { + UINT8 arg1 = read_op(); + UINT8 r1 = 0, r2 = 0; + + for (int n=GET_IM3(arg1); n>0; n--) + { + r2 = r1; + r1 = READ_REG(arg); + r2 = ((r1<<4)&0xf0) | ((r2>>4)&0x0f); + WRITE_REG(arg++, r2); + m_icount -= 5; + } + + CLEAR_FLAGS; + CHECK_FLAGB_UZ_LZ(r2); + CHECK_FLAG_Z(r2); + } + break; + + case 0x02: //bydm + { + UINT8 arg1 = read_op(); + UINT8 r1 = 0, r2 = 0, f = 0; + + for (int n=GET_IM3(arg1); n>0; n--) + { + r2 = r1; + r1 = READ_REG(arg); + WRITE_REG(arg--, r2); + f |= r2; + m_icount -= 5; + } + + CLEAR_FLAGS; + CHECK_FLAGB_UZ_LZ(r2); + CHECK_FLAG_Z(f); + } + break; + + case 0x03: //byum + { + UINT8 arg1 = read_op(); + UINT8 r1 = 0, r2 = 0, f = 0; + + for (int n=GET_IM3(arg1); n>0; n--) + { + r2 = r1; + r1 = READ_REG(arg); + WRITE_REG(arg++, r2); + f |= r2; + m_icount -= 5; + } + + CLEAR_FLAGS; + CHECK_FLAGB_UZ_LZ(r2); + CHECK_FLAG_Z(f); + } + break; + } + } + break; + + case 0xdb: //cmpm/invm + { + UINT8 arg = read_op(); + UINT8 arg1 = read_op(); + UINT8 r1 = 0, r2 = 0, f = 0; + + r2 = (arg&0x40) ? 0 : 1; + + for (int n=GET_IM3(arg1); n>0; n--) + { + r1 = r2 + (~READ_REG(arg)); + WRITE_REG(arg++, r1); + if (r1) r2 = 0; + + f |= r1; + + m_icount -= 5; + } + + CLEAR_FLAGS; + CHECK_FLAG_Z(f); + CHECK_FLAGB_UZ_LZ(r1); + if (f != 0 || (arg & 0x40)) + SET_FLAG_C; + } + break; + + case 0xdc: //sup + case 0xdd: //sdn + { + UINT8 arg = read_op(); + UINT16 res; + + for(;;) + { + res = mem_readbyte(REG_UA>>4, REG_IX) - READ_REG(arg); + + if (REG_IX == REG_IY || !res) + break; + + REG_IX += ((op&1) ? -1 : +1); + m_icount -= 6; + } + + CLEAR_FLAGS; + CHECK_FLAG_Z(res & 0xff); + CHECK_FLAGB_UZ_LZ(res); + CHECK_FLAG_C(res, 0xff); + + m_icount -= 9; + } + break; + + case 0xde: //jp + { + UINT8 arg = read_op(); + set_pc(REG_GET16(arg)); + + m_icount -= 5; + } + break; + + case 0xdf: //jp + { + UINT8 arg = read_op(); + UINT16 offset = REG_GET16(arg); + UINT8 lsb = mem_readbyte(REG_UA>>4, offset+0); + UINT8 msb = mem_readbyte(REG_UA>>4, offset+1); + + set_pc((msb<<8) | lsb); + + m_icount -= 5; + } + break; + + case 0xe0: //stm + case 0xe2: //stim + { + UINT8 arg = read_op(); + UINT8 arg1 = read_op(); + UINT16 prev_ir = REG_IX; + UINT8 ir_inc = READ_REG(get_sir_im8(arg, arg1)); + + REG_IX += ((arg & 0x80) ? -ir_inc : +ir_inc); + + for (int n=GET_IM3(arg1); n>0; n--) + { + mem_writebyte(REG_UA>>4, REG_IX++, READ_REG(arg++)); + m_icount -= 3; + } + + RESTORE_REG(op, REG_IX, prev_ir); + + m_icount -= 5; + } + break; + + case 0xe1: //stm + case 0xe3: //stim + { + UINT8 arg = read_op(); + UINT8 arg1 = read_op(); + UINT16 prev_ir = REG_IZ; + UINT8 ir_inc = READ_REG(get_sir_im8(arg, arg1)); + + REG_IZ += ((arg & 0x80) ? -ir_inc : +ir_inc); + + for (int n=GET_IM3(arg1); n>0; n--) + { + mem_writebyte(REG_UA>>6, REG_IZ++, READ_REG(arg++)); + m_icount -= 3; + } + + RESTORE_REG(op, REG_IZ, prev_ir); + + m_icount -= 5; + } + break; + + case 0xe4: //stdm + { + UINT8 arg = read_op(); + UINT8 arg1 = read_op(); + UINT8 ir_inc = READ_REG(get_sir_im8(arg, arg1)); + + REG_IX += ((arg & 0x80) ? -ir_inc : +ir_inc); + + for (int n=GET_IM3(arg1); n>0; n--) + { + mem_writebyte(REG_UA>>4, REG_IX--, READ_REG(arg--)); + m_icount -= 3; + } + + REG_IX++;//todo + + m_icount -= 3; + } + break; + + case 0xe5: //stdm + { + UINT8 arg = read_op(); + UINT8 arg1 = read_op(); + UINT8 ir_inc = READ_REG(get_sir_im8(arg, arg1)); + + REG_IZ += ((arg & 0x80) ? -ir_inc : +ir_inc); + + for (int n=GET_IM3(arg1); n>0; n--) + { + mem_writebyte(REG_UA>>6, REG_IZ--, READ_REG(arg--)); + m_icount -= 3; + } + + REG_IZ++; + + m_icount -= 3; + } + break; + + case 0xe6: //phsm + case 0xe7: //phum + { + UINT8 arg = read_op(); + UINT8 arg1 = read_op(); + + for (int n=GET_IM3(arg1); n>0; n--) + { + push((op&1) ? REG_US : REG_SS, READ_REG(arg--)); + + m_icount -= 3; + } + + m_icount -= 3; + } + break; + + case 0xe8: //ldm + case 0xea: //ldim + { + UINT8 arg = read_op(); + UINT8 arg1 = read_op(); + UINT16 prev_ir = REG_IX; + UINT8 ir_inc = READ_REG(get_sir_im8(arg, arg1)); + + REG_IX += ((arg & 0x80) ? -ir_inc : +ir_inc); + + for (int n=GET_IM3(arg1); n>0; n--) + { + WRITE_REG(arg++, mem_readbyte(REG_UA>>4, REG_IX++)); + m_icount -= 3; + } + + RESTORE_REG(op, REG_IX, prev_ir); + + m_icount -= 5; + } + break; + + case 0xe9: //ldm + case 0xeb: //ldim + { + UINT8 arg = read_op(); + UINT8 arg1 = read_op(); + UINT16 prev_ir = REG_IZ; + UINT8 ir_inc = READ_REG(get_sir_im8(arg, arg1)); + + REG_IZ += ((arg & 0x80) ? -ir_inc : +ir_inc); + + for (int n=GET_IM3(arg1); n>0; n--) + { + WRITE_REG(arg++, mem_readbyte(REG_UA>>6, REG_IZ++)); + m_icount -= 3; + } + + RESTORE_REG(op, REG_IZ, prev_ir); + + m_icount -= 5; + } + break; + + case 0xec: //lddm + { + UINT8 arg = read_op(); + UINT8 arg1 = read_op(); + UINT8 ir_inc = READ_REG(get_sir_im8(arg, arg1)); + + REG_IX += ((arg & 0x80) ? -ir_inc : +ir_inc); + + for (int n=GET_IM3(arg1); n>0; n--) + { + WRITE_REG(arg--, mem_readbyte(REG_UA>>4, REG_IX--)); + m_icount -= 3; + } + + REG_IX++; + + m_icount -= 3; + } + break; + + case 0xed: //lddm + { + UINT8 arg = read_op(); + UINT8 arg1 = read_op(); + UINT8 ir_inc = READ_REG(get_sir_im8(arg, arg1)); + + REG_IZ += ((arg & 0x80) ? -ir_inc : +ir_inc); + + for (int n=GET_IM3(arg1); n>0; n--) + { + WRITE_REG(arg--, mem_readbyte(REG_UA>>6, REG_IZ--)); + m_icount -= 3; + } + + REG_IZ++; + + m_icount -= 3; + } + break; + + case 0xee: //ppsm + case 0xef: //ppum + { + UINT8 arg = read_op(); + UINT8 arg1 = read_op(); + + for (int n=GET_IM3(arg1); n>0; n--) + { + WRITE_REG(arg++, pop((op&1) ? REG_US : REG_SS)); + m_icount -= 3; + } + + m_icount -= 5; + } + break; + + case 0xf0: //rtn z + case 0xf1: //rtn nc + case 0xf2: //rtn lz + case 0xf3: //rtn uz + case 0xf4: //rtn nz + case 0xf5: //rtn c + case 0xf6: //rtn nlz + case 0xf7: //unconditional rtn + { + if (check_cond(op)) + { + UINT8 lsb = pop(REG_SS) ; + UINT8 msb = pop(REG_SS); + + set_pc((((msb<<8) | (lsb<<0)) + 1)); + } + m_icount -= 3; + } + break; + + case 0xf8: //nop + m_icount -= 3; + break; + + case 0xf9: //clt + REG_TM = 0; + m_icount -= 3; + break; + + case 0xfa: //fst + m_state |= CPU_FAST; + m_icount -= 3; + break; + + case 0xfb: //slw + m_state &= ~CPU_FAST; + m_icount -= 3; + break; + + case 0xfd: //rtni + { + UINT8 lsb = pop(REG_SS); + UINT8 msb = pop(REG_SS); + + set_pc((msb<<8) | (lsb<<0)); + + m_icount -= 5; + } + //fall through + + case 0xfc: //cani + { + for (UINT8 arg=0x10; arg>0; arg>>=1) + { + if (REG_IB & arg) + { + REG_IB &= (~arg); + m_irq_status &= (~arg); + break; + } + } + + m_icount -= 3; + } + break; + + case 0xfe: //off + { + set_pc(0); + REG_UA = REG_IA = 0; + REG_IX = REG_IY = REG_IZ = 0; + REG_PE = 0; + REG_IE = (REG_IE&0x0c) | ((REG_IB>>1) & 0x10); + REG_IB &= 0xe3; + if (m_flags & FLAG_SW) + m_flags |= FLAG_APO; + else + m_flags &= ~FLAG_APO; + + m_state |= CPU_SLP; + + m_irq_status = 0; + m_lcd_ctrl_cb((offs_t)0, 0); + m_kb_write_cb((offs_t)0, 0); + m_icount -= 3; + } + break; + + case 0xff: //trp + { + m_pc--; + push(REG_SS, (m_pc>>8)&0xff); + push(REG_SS, (m_pc>>0)&0xff); + set_pc(0x0022); + m_icount -= 9; + } + break; + + case 0x03: + case 0x19: + case 0x43: + case 0x53: + case 0x5a: + case 0x5b: + case 0x5e: + case 0x5f: + case 0x66: + case 0x67: + case 0x6e: + case 0x6f: + case 0x83: + case 0x94: + case 0x95: + case 0x99: + case 0x9d: + case 0xc3: + case 0xd4: + case 0xd5: + logerror( "%06x: illegal instruction %02x encountered\n", m_pc, op ); + break; + + default: + logerror( "%06x: unimplemented instruction %02x encountered\n", m_pc, op ); + break; + } + } + + //if is in the internal ROM align the pc + if ((m_fetch_addr&1) && m_pc < INT_ROM) + set_pc((m_fetch_addr+1)>>1); + + m_icount -= 3; + } while (m_icount > 0); +} + + +//------------------------------------------------- +// execute_set_input +//------------------------------------------------- + +void hd61700_cpu_device::execute_set_input(int inputnum, int state) +{ + switch (inputnum) + { + case INPUT_LINE_RESET: + REG_UA = 0; + REG_IA = 0; + REG_IX = 0; + REG_IY = 0; + REG_IZ = 0; + REG_PE = 0; + REG_IE = 0; + REG_IB = 0; + m_state &= ~(CPU_SLP | CPU_FAST); + set_pc(0x0000); + break; + case HD61700_KEY_INT: //level sensitive line + if (((REG_IE>>3) & (1<>3) & (1<>3) & (1<>3) & (1<read_word(addr18<<1); + + if (!(m_fetch_addr&1)) + data = (data>>8) ; + } + else + { + if (m_fetch_addr&1) + data = m_program->read_word((addr18+1)<<1); + else + data = m_program->read_word((addr18+0)<<1); + } + + m_fetch_addr += ((m_pc > INT_ROM) ? 2 : 1); + + m_pc = m_fetch_addr>>1; + + m_curpc = make_18bit_addr((m_irq_status) ? 0 : prev_ua, m_pc); + + prev_ua = REG_UA; + + return (data&0xff); +} + +inline UINT8 hd61700_cpu_device::mem_readbyte(UINT8 segment, UINT16 offset) +{ + return m_program->read_word(make_18bit_addr(segment, offset)<<1) & 0xff; +} + +inline void hd61700_cpu_device::mem_writebyte(UINT8 segment, UINT16 offset, UINT8 data) +{ + m_program->write_word(make_18bit_addr(segment, offset)<<1, data); +} + +inline UINT32 hd61700_cpu_device::make_18bit_addr(UINT8 segment, UINT16 offset) +{ + if (offset >= ((REG_IB>>6) & 0x03) * 0x4000) + return (UINT32)((offset | ((segment&0x03)<<16)) & 0x3ffff); + else + return offset; +} + +inline void hd61700_cpu_device::push(UINT16 &offset, UINT8 data) +{ + offset--; + mem_writebyte(REG_UA>>2, offset, data); +} + +inline UINT8 hd61700_cpu_device::pop(UINT16 &offset) +{ + UINT8 data = mem_readbyte(REG_UA>>2, offset); + offset++; + return data; +} + +inline int hd61700_cpu_device::check_cond(UINT32 op) +{ + switch ( op & 0x07 ) + { + case 0x00: // Z set + if ( !(m_flags & FLAG_Z) ) + return 1; + break; + + case 0x01: // NC set + if ( !(m_flags & FLAG_C) ) + return 1; + break; + + case 0x02: // LZ set + if ( !(m_flags & FLAG_LZ) ) + return 1; + break; + + case 0x03: // UZ set + if ( !(m_flags & FLAG_UZ) ) + return 1; + break; + + case 0x04: // NZ set + if ( m_flags & FLAG_Z ) + return 1; + break; + + case 0x05: // C set + if ( m_flags & FLAG_C ) + return 1; + break; + + case 0x06: // NLZ clear + if ( m_flags & FLAG_LZ ) + return 1; + break; + + case 0x07: // unconditional + return 1; + } + + return 0; +} + +inline UINT8 hd61700_cpu_device::make_logic(UINT8 type, UINT8 d1, UINT8 d2) +{ + switch (type&3) + { + case 0: //and + return d1 & d2; + case 1: //nand + return ~(d1 & d2); + case 2: //or + return d1 | d2; + case 3: //xor + return d1 ^ d2; + default: + return 0x00; + } +} + +inline void hd61700_cpu_device::check_optional_jr(UINT8 arg) +{ + if (arg & 0x80) + { + if (m_pc < INT_ROM && !(m_fetch_addr&1)) read_op(); + + UINT8 arg1 = read_op(); + + UINT32 new_pc = m_pc + get_im_7(arg1) - 1; + + set_pc(new_pc); + m_icount -= 3; + } +} + +inline UINT8 hd61700_cpu_device::get_sir_im8(UINT8 arg) +{ + if (((arg>>5) & 0x03) == 0x03) + { + UINT8 arg1 = read_op(); + + return arg1&0x1f; + } + else + { + return READ_SREG(arg)&0x1f; + } +} + +inline UINT8 hd61700_cpu_device::get_sir_im8(UINT8 arg, UINT8 arg1) +{ + if (((arg>>5) & 0x03) == 0x03) + { + return arg1&0x1f; + } + else + { + return READ_SREG(arg)&0x1f; + } +} + +inline int hd61700_cpu_device::get_sign_mreg(UINT8 arg) +{ + int res = READ_REG(get_sir_im8(arg)); + + if (arg & 0x80) res = -res; + + return res; +} + +inline int hd61700_cpu_device::get_sign_im8(UINT8 arg) +{ + int res = read_op(); + + if (arg & 0x80) res = -res; + + return res; +} + +inline int hd61700_cpu_device::get_im_7(UINT8 data) +{ + if (data&0x80) + return 0x80 - data; + else + return data; +} + +inline UINT16 hd61700_cpu_device::make_bcd_sub(UINT8 arg1, UINT8 arg2) +{ + UINT32 ret = (arg1&0x0f) - (arg2&0x0f); + UINT8 carry; + + if (ret > 0x09) + { + ret = (ret - 0x06) & 0x0f; + carry = 1; + } + else + carry = 0; + + ret += ((arg1&0xf0) - (arg2&0xf0) - (carry<<4)); + + if (ret > 0x9f) + { + ret = (ret - 0x60) & 0x0ff; + carry = 1; + } + else + carry = 0; + + ret -= (carry<<8); + + return ret; +} + +inline UINT16 hd61700_cpu_device::make_bcd_add(UINT8 arg1, UINT8 arg2) +{ + UINT32 ret = (arg1&0x0f) + (arg2&0x0f); + UINT8 carry; + + if (ret > 0x09) + { + ret = (ret + 0x06) & 0x0f; + carry = 1; + } + else + carry = 0; + + ret += ((arg1&0xf0) + (arg2&0xf0) + (carry<<4)); + + if (ret > 0x9f) + { + ret = (ret + 0x60) & 0x0ff; + carry = 1; + } + else + carry = 0; + + ret += (carry<<8); + + return ret; +} diff --git a/src/devices/cpu/hd61700/hd61700.h b/src/devices/cpu/hd61700/hd61700.h new file mode 100644 index 00000000000..d903b8ecff7 --- /dev/null +++ b/src/devices/cpu/hd61700/hd61700.h @@ -0,0 +1,171 @@ +// license:BSD-3-Clause +// copyright-holders:Sandro Ronco +/********************************************************************** + + Hitachi HD61700 + +**********************************************************************/ + +#pragma once + +#ifndef __HD61700_H__ +#define __HD61700_H__ + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_HD61700_LCD_CTRL_CB(_devcb) \ + devcb = &hd61700_cpu_device::set_lcd_ctrl_callback(*device, DEVCB_##_devcb); + +#define MCFG_HD61700_LCD_WRITE_CB(_devcb) \ + devcb = &hd61700_cpu_device::set_lcd_write_callback(*device, DEVCB_##_devcb); + +#define MCFG_HD61700_LCD_READ_CB(_devcb) \ + devcb = &hd61700_cpu_device::set_lcd_read_callback(*device, DEVCB_##_devcb); + +#define MCFG_HD61700_KB_WRITE_CB(_devcb) \ + devcb = &hd61700_cpu_device::set_kb_write_callback(*device, DEVCB_##_devcb); + +#define MCFG_HD61700_KB_READ_CB(_devcb) \ + devcb = &hd61700_cpu_device::set_kb_read_callback(*device, DEVCB_##_devcb); + +#define MCFG_HD61700_PORT_WRITE_CB(_devcb) \ + devcb = &hd61700_cpu_device::set_port_write_callback(*device, DEVCB_##_devcb); + +#define MCFG_HD61700_PORT_READ_CB(_devcb) \ + devcb = &hd61700_cpu_device::set_port_read_callback(*device, DEVCB_##_devcb); + + +//************************************************************************** +// DEFINITIONS +//************************************************************************** + +// registers +enum +{ + HD61700_PC=1, HD61700_F, HD61700_SX, HD61700_SY, HD61700_SZ, HD61700_PE, HD61700_PD, + HD61700_IB, HD61700_UA, HD61700_IA, HD61700_IE, HD61700_TM, HD61700_IX, + HD61700_IY, HD61700_IZ, HD61700_US, HD61700_SS, HD61700_KY, HD61700_MAINREG +}; + +// input lines +enum +{ + HD61700_ON_INT, + HD61700_TIMER_INT, + HD61700_INT2, + HD61700_KEY_INT, + HD61700_INT1, + HD61700_SW +}; + + +// ======================> hd61700_cpu_device + +class hd61700_cpu_device : public cpu_device +{ +public: + // construction/destruction + hd61700_cpu_device(const machine_config &mconfig, const char *_tag, device_t *_owner, UINT32 _clock); + + template static devcb_base &set_lcd_ctrl_callback(device_t &device, _Object object) { return downcast(device).m_lcd_ctrl_cb.set_callback(object); } + template static devcb_base &set_lcd_write_callback(device_t &device, _Object object) { return downcast(device).m_lcd_write_cb.set_callback(object); } + template static devcb_base &set_lcd_read_callback(device_t &device, _Object object) { return downcast(device).m_lcd_read_cb.set_callback(object); } + template static devcb_base &set_kb_write_callback(device_t &device, _Object object) { return downcast(device).m_kb_write_cb.set_callback(object); } + template static devcb_base &set_kb_read_callback(device_t &device, _Object object) { return downcast(device).m_kb_read_cb.set_callback(object); } + template static devcb_base &set_port_write_callback(device_t &device, _Object object) { return downcast(device).m_port_write_cb.set_callback(object); } + template static devcb_base &set_port_read_callback(device_t &device, _Object object) { return downcast(device).m_port_read_cb.set_callback(object); } + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + // device_execute_interface overrides + virtual UINT32 execute_min_cycles() const { return 1; } + virtual UINT32 execute_max_cycles() const { return 52; } + virtual UINT32 execute_input_lines() const { return 6; } + virtual void execute_run(); + virtual void execute_set_input(int inputnum, int state); + + // device_state_interface overrides + virtual void state_import(const device_state_entry &entry); + void state_string_export(const device_state_entry &entry, std::string &str); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const { return (spacenum == AS_PROGRAM) ? &m_program_config : NULL; } + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const { return 1; } + virtual UINT32 disasm_max_opcode_bytes() const { return 16; } + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + + // interrupts + bool check_irqs(void); + + // inline helpers + inline void set_pc(INT32 new_pc); + inline UINT8 read_op(); + inline UINT8 mem_readbyte(UINT8 segment, UINT16 offset); + inline void mem_writebyte(UINT8 segment, UINT16 offset, UINT8 data); + inline UINT32 make_18bit_addr(UINT8 segment, UINT16 offset); + inline int check_cond( UINT32 op ); + inline void push(UINT16 &offset, UINT8 data); + inline UINT8 pop(UINT16 &offset); + inline UINT8 make_logic(UINT8 type, UINT8 d1, UINT8 d2); + inline void check_optional_jr(UINT8 arg); + inline UINT8 get_sir_im8(UINT8 arg); + inline UINT8 get_sir_im8(UINT8 arg, UINT8 arg1); + inline int get_sign_mreg(UINT8 op1); + inline int get_sign_im8(UINT8 op1); + inline int get_im_7(UINT8 data); + inline UINT16 make_bcd_sub(UINT8 arg1, UINT8 arg2); + inline UINT16 make_bcd_add(UINT8 arg1, UINT8 arg2); + +protected: + + // internal state + address_space_config m_program_config; + static const device_timer_id SEC_TIMER = 1; + emu_timer *m_sec_timer; + + offs_t m_ppc; + offs_t m_curpc; + UINT16 m_pc; + UINT8 m_flags; + UINT32 m_fetch_addr; + UINT8 m_regsir[3]; // 5bit register (sx, sy, sz) + UINT8 m_reg8bit[8]; // 8bit register (pe, pd, ib, ua, ia, ie, tm, tm) + UINT16 m_reg16bit[8]; // 16bit register (ix, iy, iz, us, ss, ky, ky, ky) + UINT8 m_regmain[0x20]; // main registers + UINT8 m_irq_status; + UINT8 m_state; + UINT8 prev_ua; + int m_lines_status[6]; + int m_icount; + + address_space *m_program; + + devcb_write8 m_lcd_ctrl_cb; //lcd control + devcb_read8 m_lcd_read_cb; //lcd data read + devcb_write8 m_lcd_write_cb; //lcd data write + devcb_read16 m_kb_read_cb; //keyboard matrix read + devcb_write8 m_kb_write_cb; //keyboard matrix write + devcb_read8 m_port_read_cb; //8 bit port read + devcb_write8 m_port_write_cb; //8 bit port write + + // flag definitions + static const int FLAG_Z = 0x80; + static const int FLAG_C = 0x40; + static const int FLAG_LZ = 0x20; + static const int FLAG_UZ = 0x10; + static const int FLAG_SW = 0x08; + static const int FLAG_APO = 0x04; +}; + +extern const device_type HD61700; + + +#endif /* __HD61700_H__ */ diff --git a/src/devices/cpu/hd61700/hd61700d.c b/src/devices/cpu/hd61700/hd61700d.c new file mode 100644 index 00000000000..719fade4f49 --- /dev/null +++ b/src/devices/cpu/hd61700/hd61700d.c @@ -0,0 +1,439 @@ +// license:BSD-3-Clause +// copyright-holders:Sandro Ronco +#include "emu.h" +#include "debugger.h" +#include "hd61700.h" + +#define EXT_ROM (pc > 0x0c00) +#define INC_POS pos += (type+1) +#define POS (pos + type) + +static const char *const reg_5b[4] = {"sx", "sy", "sz", "sz"}; +static const char *const reg_8b[8] = {"pe", "pd", "ib", "ua", "ia", "ie", "tm", "tm"}; +static const char *const reg_16b[8] = {"ix", "iy", "iz", "us", "ss", "ky", "ky", "ky"}; +static const char *const jp_cond[8] = {"z", "nc", "lz", "uz", "nz", "c", "nlz"}; + +enum +{ + OP_NULL=0, + OP_IM16, + OP_IM16A, + OP_IM3, + OP_IM5, + OP_IM7, + OP_IM8, + OP_IM8I, + OP_IM8_, + OP_IR_IM3, + OP_IR_IM8, + OP_IR_IM8_, + OP_JX_COND, + OP_MREG, + OP_MREG2, + OP_MR_SIR, + OP_MR_SIRI, + OP_REG16, + OP_REG16_, + OP_REG8, + OP_REG8_, + OP_REGIM8, + OP_RMSIM3, + OP_RSIR +}; + +struct hd61700_dasm +{ + const char *str; + UINT8 arg1; + UINT8 arg2; + bool optjr; +}; + +static const hd61700_dasm hd61700_ops[256] = +{ + // 0x00 + { "adc", OP_MREG, OP_MR_SIR, 1 }, { "sbc", OP_MREG, OP_MR_SIR, 1 }, + { "ld", OP_MREG, OP_MR_SIR, 1 }, { "illegal", OP_NULL, OP_NULL, 0 }, + { "anc", OP_MREG, OP_MR_SIR, 1 }, { "nac", OP_MREG, OP_MR_SIR, 1 }, + { "orc", OP_MREG, OP_MR_SIR, 1 }, { "xrc", OP_MREG, OP_MR_SIR, 1 }, + { "ad", OP_MREG, OP_MR_SIR, 1 }, { "sb", OP_MREG, OP_MR_SIR, 1 }, + { "adb", OP_MREG, OP_MR_SIR, 1 }, { "sbb", OP_MREG, OP_MR_SIR, 1 }, + { "an", OP_MREG, OP_MR_SIR, 1 }, { "na", OP_MREG, OP_MR_SIR, 1 }, + { "or", OP_MREG, OP_MR_SIR, 1 }, { "xr", OP_MREG, OP_MR_SIR, 1 }, + + // 0x10 + { "st", OP_MREG, OP_MR_SIRI, 1 }, { "ld", OP_MREG, OP_MR_SIRI,1 }, + { "stl", OP_MREG2, OP_NULL, 1 }, { "ldl", OP_MREG2, OP_NULL, 1 }, + { "???", OP_MREG2, OP_NULL, 1 }, { "psr", OP_RSIR, OP_MREG2, 1 }, + { "pst", OP_REG8, OP_MREG2, 1 }, { "pst", OP_REG8, OP_MREG2, 1 }, + { "???", OP_MREG2, OP_NULL, 1 }, { "illegal", OP_NULL, OP_NULL, 0 }, + { "???", OP_MREG2, OP_NULL, 1 }, { "???", OP_MREG2, OP_NULL, 1 }, + { "???", OP_MREG2, OP_NULL, 1 }, { "gsr", OP_RSIR, OP_MREG2, 1 }, + { "gst", OP_REG8, OP_MREG2, 1 }, { "gst", OP_REG8, OP_MREG2, 1 }, + + // 0x20 + { "st", OP_MREG, OP_IR_IM8_, 0 }, { "st", OP_MREG, OP_IR_IM8_,0 }, + { "sti", OP_MREG, OP_IR_IM8_, 0 }, { "sti", OP_MREG, OP_IR_IM8_,0 }, + { "std", OP_MREG, OP_IR_IM8_, 0 }, { "std", OP_MREG, OP_IR_IM8_,0 }, + { "phs", OP_MREG2, OP_NULL, 0 }, { "phu", OP_MREG2, OP_NULL, 0 }, + { "ld", OP_MREG, OP_IR_IM8_, 0 }, { "ld", OP_MREG, OP_IR_IM8_,0 }, + { "ldi", OP_MREG, OP_IR_IM8_, 0 }, { "ldi", OP_MREG, OP_IR_IM8_,0 }, + { "ldd", OP_MREG, OP_IR_IM8_, 0 }, { "ldd", OP_MREG, OP_IR_IM8_,0 }, + { "pps", OP_MREG2, OP_NULL, 0 }, { "ppu", OP_MREG2, OP_NULL, 0 }, + + // 0x30 + { "jp", OP_JX_COND, OP_IM16A, 0 }, { "jp", OP_JX_COND, OP_IM16A, 0 }, + { "jp", OP_JX_COND, OP_IM16A, 0 }, { "jp", OP_JX_COND, OP_IM16A, 0 }, + { "jp", OP_JX_COND, OP_IM16A, 0 }, { "jp", OP_JX_COND, OP_IM16A, 0 }, + { "jp", OP_JX_COND, OP_IM16A, 0 }, { "jp", OP_IM16A, OP_NULL, 0 }, + { "adc", OP_IR_IM8, OP_MREG2, 0 }, { "adc", OP_IR_IM8, OP_MREG2, 0 }, + { "sbc", OP_IR_IM8, OP_MREG2, 0 }, { "sbc", OP_IR_IM8, OP_MREG2, 0 }, + { "ad", OP_IR_IM8, OP_MREG2, 0 }, { "ad", OP_IR_IM8, OP_MREG2, 0 }, + { "sb", OP_IR_IM8, OP_MREG2, 0 }, { "sb", OP_IR_IM8, OP_MREG2, 0 }, + + // 0x40 + { "adc", OP_MREG2, OP_IM8, 1 }, { "sbc", OP_MREG2, OP_IM8, 1 }, + { "ld", OP_MREG2, OP_IM8, 1 }, { "illegal", OP_NULL, OP_NULL, 0 }, + { "anc", OP_MREG2, OP_IM8, 1 }, { "nac", OP_MREG2, OP_IM8, 1 }, + { "orc", OP_MREG2, OP_IM8, 1 }, { "xrc", OP_MREG2, OP_IM8, 1 }, + { "ad", OP_MREG2, OP_IM8, 1 }, { "sb", OP_MREG2, OP_IM8, 1 }, + { "adb", OP_MREG2, OP_IM8, 1 }, { "sbb", OP_MREG2, OP_IM8, 1 }, + { "an", OP_MREG2, OP_IM8, 1 }, { "na", OP_MREG2, OP_IM8, 1 }, + { "or", OP_MREG2, OP_IM8, 1 }, { "xr", OP_MREG2, OP_IM8, 1 }, + + // 0x50 + { "st", OP_IM8I, OP_MREG2, 0 }, { "st", OP_IM8, OP_MREG2,0 }, + { "stl", OP_IM8_, OP_NULL, 0 }, { "illegal", OP_NULL, OP_NULL, 0 }, + { "???", OP_IM8_, OP_NULL, 0 }, { "psr", OP_RSIR, OP_IM5, 0 }, + { "pst", OP_REG8_, OP_IM8, 0 }, { "pst", OP_REG8_, OP_IM8, 0 }, + { "bups", OP_IM8_, OP_NULL, 0 }, { "bdns", OP_IM8_, OP_NULL, 0 }, + { "illegal", OP_NULL, OP_NULL, 0 }, { "illegal", OP_NULL, OP_NULL, 0 }, + { "sup", OP_IM8_, OP_NULL, 0 }, { "sdn", OP_IM8_, OP_NULL, 0 }, + { "illegal", OP_NULL, OP_NULL, 0 }, { "illegal", OP_NULL, OP_NULL, 0 }, + + // 0x60 + { "st", OP_MREG2, OP_REGIM8, 0 }, { "st", OP_MREG2, OP_REGIM8, 0 }, + { "sti", OP_MREG2, OP_REGIM8, 0 }, { "sti", OP_MREG2, OP_REGIM8, 0 }, + { "std", OP_MREG2, OP_REGIM8, 0 }, { "std", OP_MREG2, OP_REGIM8, 0 }, + { "illegal", OP_NULL, OP_NULL, 0 }, { "illegal", OP_NULL, OP_NULL, 0 }, + { "ld", OP_MREG2, OP_REGIM8, 0 }, { "ld", OP_MREG2, OP_REGIM8, 0 }, + { "ldi", OP_MREG2, OP_REGIM8, 0 }, { "ldi", OP_MREG2, OP_REGIM8, 0 }, + { "ldd", OP_MREG2, OP_REGIM8, 0 }, { "ldd", OP_MREG2, OP_REGIM8, 0 }, + { "illegal", OP_NULL, OP_NULL, 0 }, { "illegal", OP_NULL, OP_NULL, 0 }, + + // 0x70 + { "cal", OP_JX_COND, OP_IM16A, 0 }, { "cal", OP_JX_COND, OP_IM16A, 0 }, + { "cal", OP_JX_COND, OP_IM16A, 0 }, { "cal", OP_JX_COND, OP_IM16A, 0 }, + { "cal", OP_JX_COND, OP_IM16A, 0 }, { "cal", OP_JX_COND, OP_IM16A, 0 }, + { "cal", OP_JX_COND, OP_IM16A, 0 }, { "cal", OP_IM16A, OP_NULL, 0 }, + { "adc", OP_REGIM8, OP_MREG2, 0 }, { "adc", OP_REGIM8, OP_MREG2, 0 }, + { "sbc", OP_REGIM8, OP_MREG2, 0 }, { "sbc", OP_REGIM8, OP_MREG2, 0 }, + { "ad", OP_REGIM8, OP_MREG2, 0 }, { "ad ", OP_REGIM8, OP_MREG2, 0 }, + { "sb", OP_REGIM8, OP_MREG2, 0 }, { "sb", OP_REGIM8, OP_MREG2, 0 }, + + // 0x80 + { "adcw", OP_MREG, OP_MR_SIR, 1 }, { "sbcw", OP_MREG, OP_MR_SIR, 1 }, + { "ldw", OP_MREG, OP_MR_SIR, 1 }, { "illegal", OP_NULL, OP_NULL, 0 }, + { "ancw", OP_MREG, OP_MR_SIR, 1 }, { "nacw", OP_MREG, OP_MR_SIR, 1 }, + { "orcw", OP_MREG, OP_MR_SIR, 1 }, { "xrcw", OP_MREG, OP_MR_SIR, 1 }, + { "adw", OP_MREG, OP_MR_SIR, 1 }, { "sbw", OP_MREG, OP_MR_SIR, 1 }, + { "adbw", OP_MREG, OP_MR_SIR, 1 }, { "sbbw", OP_MREG, OP_MR_SIR, 1 }, + { "anw", OP_MREG, OP_MR_SIR, 1 }, { "naw", OP_MREG, OP_MR_SIR, 1 }, + { "orw", OP_MREG, OP_MR_SIR, 1 }, { "xrw", OP_MREG, OP_MR_SIR, 1 }, + + // 0x90 + { "stw", OP_MREG, OP_MR_SIRI,1 }, { "ldw", OP_MREG, OP_MR_SIRI,1 }, + { "stlw", OP_MREG2, OP_NULL, 1 }, { "ldlw", OP_MREG2, OP_NULL, 1 }, + { "illegal", OP_NULL, OP_NULL, 0 }, { "illegal", OP_NULL, OP_NULL, 0 }, + { "pre", OP_REG16, OP_MREG2, 1 }, { "pre", OP_REG16, OP_MREG2, 1 }, + { "???", OP_MREG2, OP_NULL, 1 }, { "illegal", OP_NULL, OP_NULL, 0 }, + { "???", OP_MREG2, OP_NULL, 1 }, { "???", OP_MREG2, OP_NULL, 1 }, + { "???", OP_MREG2, OP_NULL, 1 }, { "illegal", OP_NULL, OP_NULL, 0 }, + { "gre", OP_REG16, OP_MREG2, 1 }, { "gre", OP_REG16, OP_MREG2, 1 }, + + // 0xa0 + { "stw", OP_MREG, OP_IR_IM8_, 0 }, { "stw", OP_MREG, OP_IR_IM8_, 0 }, + { "stiw", OP_MREG, OP_IR_IM8_, 0 }, { "stiw", OP_MREG, OP_IR_IM8_, 0 }, + { "stdw", OP_MREG, OP_IR_IM8_, 0 }, { "stdw", OP_MREG, OP_IR_IM8_, 0 }, + { "phsw", OP_MREG2, OP_NULL, 0 }, { "phuw", OP_MREG2, OP_NULL, 0 }, + { "ldw", OP_MREG, OP_IR_IM8_, 0 }, { "ldw", OP_MREG, OP_IR_IM8_, 0 }, + { "ldiw", OP_MREG, OP_IR_IM8_, 0 }, { "ldiw", OP_MREG, OP_IR_IM8_, 0 }, + { "lddw", OP_MREG, OP_IR_IM8_, 0 }, { "lddw", OP_MREG, OP_IR_IM8_, 0 }, + { "ppsw", OP_MREG2, OP_NULL, 0 }, { "ppuw", OP_MREG2, OP_NULL, 0 }, + + // 0xb0 + { "jr", OP_JX_COND, OP_IM7, 0 }, { "jr", OP_JX_COND, OP_IM7, 0 }, + { "jr", OP_JX_COND, OP_IM7, 0 }, { "jr", OP_JX_COND, OP_IM7, 0 }, + { "jr", OP_JX_COND, OP_IM7, 0 }, { "jr", OP_JX_COND, OP_IM7, 0 }, + { "jr", OP_JX_COND, OP_IM7, 0 }, { "jr", OP_IM7, OP_NULL, 0 }, + { "adcw", OP_IR_IM8, OP_MREG, 0 }, { "adcw", OP_IR_IM8, OP_MREG, 0 }, + { "sbcw", OP_IR_IM8, OP_MREG, 0 }, { "sbcw", OP_IR_IM8, OP_MREG, 0 }, + { "adw", OP_IR_IM8, OP_MREG, 0 }, { "adw", OP_IR_IM8, OP_MREG, 0 }, + { "sbw", OP_IR_IM8, OP_MREG, 0 }, { "sbw", OP_IR_IM8, OP_MREG, 0 }, + + // 0xc0 + { "adbcm",OP_MREG, OP_RMSIM3, 1 }, { "sdbcm",OP_MREG, OP_RMSIM3, 1 }, + { "ldm", OP_MREG, OP_RMSIM3, 1 }, { "illegal", OP_NULL, OP_NULL, 0 }, + { "ancm", OP_MREG, OP_RMSIM3, 1 }, { "nacm", OP_MREG, OP_RMSIM3, 1 }, + { "orcm", OP_MREG, OP_RMSIM3, 1 }, { "xrcm", OP_MREG, OP_RMSIM3, 1 }, + { "adbm", OP_MREG, OP_RMSIM3, 1 }, { "sbbm", OP_MREG, OP_RMSIM3, 1 }, + { "adbm", OP_MREG, OP_RMSIM3, 1 }, { "sbbm", OP_MREG, OP_RMSIM3, 1 }, + { "anm", OP_MREG, OP_RMSIM3, 1 }, { "nam", OP_MREG, OP_RMSIM3, 1 }, + { "orm", OP_MREG, OP_RMSIM3, 1 }, { "xrm", OP_MREG, OP_RMSIM3, 1 }, + + // 0xd0 + { "stw", OP_IM16, OP_MR_SIR, 0 }, { "ldw", OP_MREG2, OP_IM16, 0 }, + { "stlm", OP_MREG2, OP_IM3, 0 }, { "ldlm", OP_MREG2, OP_IM3, 0 }, + { "illegal", OP_NULL, OP_NULL, 0 }, { "illegal", OP_NULL, OP_NULL, 0 }, + { "pre", OP_REG16_, OP_IM16, 0 }, { "pre", OP_REG16_, OP_IM16, 0 }, + { "bup", OP_NULL, OP_NULL, 0 }, { "bnd", OP_NULL, OP_NULL, 0 }, + { "???", OP_MREG2, OP_IM3, 0 }, { "???", OP_MREG2, OP_IM3, 0 }, + { "sup", OP_MREG, OP_NULL, 0 }, { "sdn", OP_MREG, OP_NULL, 0 }, + { "jp", OP_MREG, OP_NULL, 0 }, { "jp", OP_MREG, OP_NULL, 0 }, + + // 0xe0 + { "stm", OP_MREG, OP_IR_IM3, 0 }, { "stm", OP_MREG, OP_IR_IM3, 0 }, + { "stim", OP_MREG, OP_IR_IM3, 0 }, { "stim", OP_MREG, OP_IR_IM3, 0 }, + { "stdm", OP_MREG, OP_IR_IM3, 0 }, { "stdm", OP_MREG, OP_IR_IM3, 0 }, + { "phsm", OP_MREG2, OP_IM3, 0 }, { "phum", OP_MREG2, OP_IM3, 0 }, + { "ldm", OP_MREG, OP_IR_IM3, 0 }, { "ldm", OP_MREG, OP_IR_IM3, 0 }, + { "ldim", OP_MREG, OP_IR_IM3, 0 }, { "ldim", OP_MREG, OP_IR_IM3, 0 }, + { "lddm", OP_MREG, OP_IR_IM3, 0 }, { "lddm", OP_MREG, OP_IR_IM3, 0 }, + { "ppsm", OP_MREG2, OP_IM3, 0 }, { "ppum", OP_MREG2, OP_IM3, 0 }, + + // 0xf0 + { "rtn", OP_JX_COND, OP_NULL, 0 }, { "rtn", OP_JX_COND, OP_NULL, 0 }, + { "rtn", OP_JX_COND, OP_NULL, 0 }, { "rtn", OP_JX_COND, OP_NULL, 0 }, + { "rtn", OP_JX_COND, OP_NULL, 0 }, { "rtn", OP_JX_COND, OP_NULL, 0 }, + { "rtn", OP_JX_COND, OP_NULL, 0 }, { "rtn", OP_NULL, OP_NULL, 0 }, + { "nop", OP_JX_COND, OP_NULL, 0 }, { "clt", OP_NULL, OP_NULL, 0 }, + { "fst", OP_NULL, OP_NULL, 0 }, { "slw", OP_NULL, OP_NULL, 0 }, + { "can", OP_NULL, OP_NULL, 0 }, { "rtni", OP_NULL, OP_NULL, 0 }, + { "off", OP_NULL, OP_NULL, 0 }, { "trp", OP_NULL, OP_NULL, 0 }, +}; + + +inline int dasm_im8(char *buffer, UINT16 pc, int arg, const UINT8 *oprom, int &pos, int type) +{ + if (((arg>>5) & 0x03) == 0x03) + { + INC_POS; + UINT8 ret = sprintf( buffer, "0x%02x", oprom[POS] & 0x1f ); + return ret; + } + else + { + return sprintf( buffer, "%s", reg_5b[(arg>>5) & 0x03] ); + } +} + + +inline int dasm_im8(char *buffer, UINT16 pc, int arg, int arg1, const UINT8 *oprom, int &pos) +{ + if (((arg>>5) & 0x03) == 0x03) + { + return sprintf( buffer, "0x%02x", arg1 & 0x1f ); + } + else + { + return sprintf( buffer, "%s", reg_5b[(arg>>5) & 0x03] ); + } +} + + +int dasm_arg(char *buffer, UINT8 op, UINT16 pc, int arg, const UINT8 *oprom, int &pos) +{ + char* buffer_start = buffer; + int type = EXT_ROM; + + switch( arg ) + { + case OP_MREG: + case OP_MREG2: + buffer += sprintf( buffer, "$%02u", oprom[POS] & 0x1f ); + if (arg == OP_MREG2) INC_POS; + break; + + case OP_RSIR: + buffer += sprintf( buffer, "%s", reg_5b[(oprom[POS]>>5) & 0x03] ); + break; + + case OP_REG8: + case OP_REG8_: + buffer += sprintf( buffer, "%s", reg_8b[(BIT(op,0)<<2) + ((oprom[POS]>>5&3))]); + if (arg == OP_REG8_) INC_POS; + break; + + case OP_MR_SIR: + buffer += dasm_im8(buffer, pc, oprom[POS], oprom, pos, type); + INC_POS; + break; + + case OP_IR_IM8: + case OP_IR_IM8_: + buffer += sprintf( buffer, "(%s%s", (op&1) ? "iz": "ix", (oprom[POS]&0x80) ? "-": "+"); + buffer += dasm_im8(buffer, pc, oprom[POS], oprom, pos, type); + buffer += sprintf( buffer, ")"); + if (arg == OP_IR_IM8_) INC_POS; + break; + + case OP_IM8_: + INC_POS; + case OP_IM8: + buffer += sprintf( buffer, "0x%02x", oprom[POS] ); + INC_POS; + break; + + case OP_IM8I: + buffer += sprintf( buffer, "(0x%02x)", oprom[POS] ); + INC_POS; + break; + + case OP_REGIM8: + buffer += sprintf( buffer, "(%s%s", (op&1) ? "iz": "ix", (oprom[POS]&0x80) ? "-": "+"); + buffer += sprintf( buffer, "%x)", oprom[POS] & 0x1f); + INC_POS; + break; + + case OP_JX_COND: + buffer += sprintf( buffer, "%s", jp_cond[op & 0x07] ); + break; + + + case OP_RMSIM3: + { + UINT8 tmp = oprom[POS]; + INC_POS; + buffer += dasm_im8(buffer, pc, tmp, oprom[POS], oprom, pos); + buffer += sprintf( buffer, ", 0x%02x", ((tmp>>5)&7)+1); + INC_POS; + } + break; + + case OP_IR_IM3: + { + UINT8 tmp = oprom[POS]; + INC_POS; + buffer += sprintf( buffer, "(%s%s", (op&1) ? "iz": "ix", (tmp&0x80) ? "-": "+"); + buffer += dasm_im8(buffer, pc, tmp, oprom[POS], oprom, pos); + buffer += sprintf( buffer, "), 0x%02x", ((oprom[POS]>>5)&7)+1 ); + INC_POS; + } + break; + + case OP_IM3: + buffer += sprintf( buffer, "0x%02x", ((oprom[POS]>>5)&7)+1 ); + INC_POS; + break; + + case OP_MR_SIRI: + buffer += sprintf( buffer, "("); + buffer += dasm_im8(buffer, pc, oprom[POS], oprom, pos, type); + buffer += sprintf( buffer, ")"); + INC_POS; + break; + + case OP_IM7: + { + int tmp = oprom[POS]; + if (tmp&0x80) tmp = 0x80 - tmp; + + buffer += sprintf( buffer, "0x%04x", (pc + tmp + EXT_ROM) & 0xffff ); + INC_POS; + } + break; + + case OP_IM5: + buffer += sprintf( buffer, "0x%02x", oprom[POS]&0x1f ); + INC_POS; + break; + + case OP_REG16: + case OP_REG16_: + buffer += sprintf( buffer, "%s", reg_16b[(BIT(op,0)<<2) + ((oprom[POS]>>5&3))]); + if (arg == OP_REG16_) INC_POS; + break; + + case OP_IM16: + case OP_IM16A: + { + UINT8 tmp1 = oprom[POS]; + INC_POS; + if (!EXT_ROM && arg == OP_IM16A) INC_POS; + UINT8 tmp2 = oprom[POS]; + buffer += sprintf( buffer, "0x%04x", ((tmp2<<8) | tmp1)); + INC_POS; + } + break; + + case OP_NULL: + break; + } + + return buffer - buffer_start; +} + +UINT32 get_dasmflags(UINT8 op) +{ + switch (op) + { + case 0x30: case 0x31: case 0x32: case 0x33: //jp + case 0x34: case 0x35: case 0x36: case 0x37: //jp + case 0x70: case 0x71: case 0x72: case 0x73: //cal + case 0x74: case 0x75: case 0x76: case 0x77: //cal + case 0xb0: case 0xb1: case 0xb2: case 0xb3: //jr + case 0xb4: case 0xb5: case 0xb6: case 0xb7: //jr + case 0xde: //jp + case 0xdf: //jp + return DASMFLAG_STEP_OVER; + case 0xf0: case 0xf1: case 0xf2: case 0xf3: //rtn + case 0xf4: case 0xf5: case 0xf6: case 0xf7: //rtn + case 0xfd: //rtni + return DASMFLAG_STEP_OUT; + } + + return 0; +} + + +CPU_DISASSEMBLE( hd61700 ) +{ + const hd61700_dasm *inst; + UINT32 dasmflags = 0; + UINT8 op, op1; + int pos = 0, type = EXT_ROM; + + op = oprom[POS]; + INC_POS; + + dasmflags = get_dasmflags(op); + + op1 = oprom[POS]; + + inst = &hd61700_ops[op]; + + buffer += sprintf(buffer,"%-8s", inst->str); + + //dasm first arg + buffer += dasm_arg(buffer, op, pc, inst->arg1, oprom, pos); + + //if present dasm second arg + if (inst->arg2 != OP_NULL) + { + buffer += sprintf(buffer,", "); + buffer += dasm_arg(buffer, op, pc, inst->arg2, oprom, pos); + } + + //if required add the optional jr + if (inst->optjr == true && BIT(op1, 7)) + { + buffer += sprintf( buffer, ", jr "); + buffer += dasm_arg(buffer, op, pc+1, OP_IM7, oprom, pos); + + dasmflags = DASMFLAG_STEP_OVER; + } + + if (pos&1) INC_POS; + + return (pos>>1) | dasmflags | DASMFLAG_SUPPORTED; +} diff --git a/src/devices/cpu/hmcs40/hmcs40.c b/src/devices/cpu/hmcs40/hmcs40.c new file mode 100644 index 00000000000..d76385cf2ba --- /dev/null +++ b/src/devices/cpu/hmcs40/hmcs40.c @@ -0,0 +1,827 @@ +// license:BSD-3-Clause +// copyright-holders:hap +/* + + Hitachi HMCS40 MCU family cores + + References: + - 1985 #AP1 Hitachi 4-bit Single-Chip Microcomputer Data Book + - 1988 HMCS400 Series Handbook (note: *400 is a newer MCU series, with similarities) + - opcode decoding by Tatsuyuki Satoh, Olivier Galibert, Kevin Horton, Lord Nightmare + +*/ + +#define IS_PMOS 0 +#define IS_CMOS ~0 + +#include "hmcs40.h" +#include "debugger.h" + + +// MCU types + +// HMCS42/C/CL +//const device_type HD38702 = &device_creator; // PMOS, 28 pins, 22 I/O lines, (512+32)x10 ROM, 32x4 RAM, no B or SPY register +//const device_type HD44700 = &device_creator; // CMOS version +//const device_type HD44708 = &device_creator; // CMOS version, low-power + +// HMCS43/C/CL +const device_type HD38750 = &device_creator; // PMOS, 42 pins, 32 I/O lines, (1024+64)x10 ROM, 80x4 RAM +const device_type HD38755 = &device_creator; // ceramic filter oscillator type +const device_type HD44750 = &device_creator; // CMOS version +const device_type HD44758 = &device_creator; // CMOS version, low-power + +// HMCS44A/C/CL +const device_type HD38800 = &device_creator; // PMOS, 42 pins, 32 I/O lines, (2048+128)x10 ROM, 160x4 RAM +const device_type HD38805 = &device_creator; // ceramic filter oscillator type +const device_type HD44801 = &device_creator; // CMOS version +const device_type HD44808 = &device_creator; // CMOS version, low-power + +// HMCS45A/C/CL +const device_type HD38820 = &device_creator; // PMOS, 54 pins(QFP) or 64 pins(DIP), 44 I/O lines, (2048+128)x10 ROM, 160x4 RAM +const device_type HD38825 = &device_creator; // ceramic filter oscillator type +const device_type HD44820 = &device_creator; // CMOS version +const device_type HD44828 = &device_creator; // CMOS version, low-power + +// HMCS46C/CL (no PMOS version exists) +//const device_type HD44840 = &device_creator; // CMOS, 42 pins, 32 I/O lines, 4096x10 ROM, 256x4 RAM +//const device_type HD44848 = &device_creator; // CMOS, low-power + +// HMCS47A/C/CL +//const device_type HD38870 = &device_creator; // PMOS, 54 pins(QFP) or 64 pins(DIP), 44 I/O lines, 4096x10 ROM, 256x4 RAM +//const device_type HD44860 = &device_creator; // CMOS version +//const device_type HD44868 = &device_creator; // CMOS version, low-power + + +// internal memory maps +static ADDRESS_MAP_START(program_1k, AS_PROGRAM, 16, hmcs40_cpu_device) + AM_RANGE(0x0000, 0x03ff) AM_ROM + AM_RANGE(0x0780, 0x07bf) AM_ROM // patterns on page 30 +ADDRESS_MAP_END + +static ADDRESS_MAP_START(program_2k, AS_PROGRAM, 16, hmcs40_cpu_device) + AM_RANGE(0x0000, 0x07ff) AM_ROM + AM_RANGE(0x0f40, 0x0fbf) AM_ROM // patterns on page 61,62 +ADDRESS_MAP_END + + +static ADDRESS_MAP_START(data_80x4, AS_DATA, 8, hmcs40_cpu_device) + AM_RANGE(0x00, 0x3f) AM_RAM + AM_RANGE(0x40, 0x4f) AM_RAM AM_MIRROR(0x30) +ADDRESS_MAP_END + +static ADDRESS_MAP_START(data_160x4, AS_DATA, 8, hmcs40_cpu_device) + AM_RANGE(0x00, 0x7f) AM_RAM + AM_RANGE(0x80, 0x8f) AM_RAM AM_MIRROR(0x30) + AM_RANGE(0xc0, 0xcf) AM_RAM AM_MIRROR(0x30) +ADDRESS_MAP_END + + +// device definitions +hmcs43_cpu_device::hmcs43_cpu_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, UINT16 polarity, const char *shortname) + : hmcs40_cpu_device(mconfig, type, name, tag, owner, clock, HMCS40_FAMILY_HMCS43, polarity, 3 /* stack levels */, 10 /* pc width */, 11 /* prg width */, ADDRESS_MAP_NAME(program_1k), 7 /* data width */, ADDRESS_MAP_NAME(data_80x4), shortname, __FILE__) +{ } + +hd38750_device::hd38750_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : hmcs43_cpu_device(mconfig, HD38750, "HD38750", tag, owner, clock, IS_PMOS, "hd38750") +{ } +hd38755_device::hd38755_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : hmcs43_cpu_device(mconfig, HD38755, "HD38755", tag, owner, clock, IS_PMOS, "hd38755") +{ } +hd44750_device::hd44750_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : hmcs43_cpu_device(mconfig, HD44750, "HD44750", tag, owner, clock, IS_CMOS, "hd44750") +{ } +hd44758_device::hd44758_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : hmcs43_cpu_device(mconfig, HD44758, "HD44758", tag, owner, clock, IS_CMOS, "hd44758") +{ } + + +hmcs44_cpu_device::hmcs44_cpu_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, UINT16 polarity, const char *shortname) + : hmcs40_cpu_device(mconfig, type, name, tag, owner, clock, HMCS40_FAMILY_HMCS44, polarity, 4, 11, 12, ADDRESS_MAP_NAME(program_2k), 8, ADDRESS_MAP_NAME(data_160x4), shortname, __FILE__) +{ } + +hd38800_device::hd38800_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : hmcs44_cpu_device(mconfig, HD38800, "HD38800", tag, owner, clock, IS_PMOS, "hd38800") +{ } +hd38805_device::hd38805_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : hmcs44_cpu_device(mconfig, HD38805, "HD38805", tag, owner, clock, IS_PMOS, "hd38805") +{ } +hd44801_device::hd44801_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : hmcs44_cpu_device(mconfig, HD44801, "HD44801", tag, owner, clock, IS_CMOS, "hd44801") +{ } +hd44808_device::hd44808_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : hmcs44_cpu_device(mconfig, HD44808, "HD44808", tag, owner, clock, IS_CMOS, "hd44808") +{ } + + +hmcs45_cpu_device::hmcs45_cpu_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, UINT16 polarity, const char *shortname) + : hmcs40_cpu_device(mconfig, type, name, tag, owner, clock, HMCS40_FAMILY_HMCS45, polarity, 4, 11, 12, ADDRESS_MAP_NAME(program_2k), 8, ADDRESS_MAP_NAME(data_160x4), shortname, __FILE__) +{ } + +hd38820_device::hd38820_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : hmcs45_cpu_device(mconfig, HD38820, "HD38820", tag, owner, clock, IS_PMOS, "hd38820") +{ } +hd38825_device::hd38825_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : hmcs45_cpu_device(mconfig, HD38825, "HD38825", tag, owner, clock, IS_PMOS, "hd38825") +{ } +hd44820_device::hd44820_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : hmcs45_cpu_device(mconfig, HD44820, "HD44820", tag, owner, clock, IS_CMOS, "hd44820") +{ } +hd44828_device::hd44828_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : hmcs45_cpu_device(mconfig, HD44828, "HD44828", tag, owner, clock, IS_CMOS, "hd44828") +{ } + + +// disasm +void hmcs40_cpu_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + switch (entry.index()) + { + case STATE_GENFLAGS: + strprintf(str, "%c%c", + m_c ? 'C':'c', + m_s ? 'S':'s' + ); + break; + + default: break; + } +} + +offs_t hmcs40_cpu_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE(hmcs40); + return CPU_DISASSEMBLE_NAME(hmcs40)(this, buffer, pc, oprom, opram, options); +} + + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +enum +{ + HMCS40_PC=1, HMCS40_A, HMCS40_B, + HMCS40_X, HMCS40_SPX, HMCS40_Y, HMCS40_SPY +}; + +void hmcs40_cpu_device::device_start() +{ + m_program = &space(AS_PROGRAM); + m_data = &space(AS_DATA); + m_prgmask = (1 << m_prgwidth) - 1; + m_datamask = (1 << m_datawidth) - 1; + m_pcmask = (1 << m_pcwidth) - 1; + + m_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(hmcs40_cpu_device::simple_timer_cb), this)); + reset_prescaler(); + + // resolve callbacks + m_read_r0.resolve_safe(0); + m_read_r1.resolve_safe(0); + m_read_r2.resolve_safe(0); + m_read_r3.resolve_safe(0); + m_read_r4.resolve_safe(0); + m_read_r5.resolve_safe(0); + m_read_r6.resolve_safe(0); + m_read_r7.resolve_safe(0); + + m_write_r0.resolve_safe(); + m_write_r1.resolve_safe(); + m_write_r2.resolve_safe(); + m_write_r3.resolve_safe(); + m_write_r4.resolve_safe(); + m_write_r5.resolve_safe(); + m_write_r6.resolve_safe(); + m_write_r7.resolve_safe(); + + m_read_d.resolve_safe(0); + m_write_d.resolve_safe(); + + // zerofill + memset(m_stack, 0, sizeof(m_stack)); + m_op = 0; + m_prev_op = 0; + m_i = 0; + m_eint_line = 0; + m_halt = 0; + m_pc = 0; + m_prev_pc = 0; + m_page = 0; + m_a = 0; + m_b = 0; + m_x = 0; + m_spx = 0; + m_y = 0; + m_spy = 0; + m_s = 1; + m_c = 0; + m_tc = 0; + m_cf = 0; + m_ie = 0; + m_iri = m_irt = 0; + memset(m_if, 0, sizeof(m_if)); + m_tf = 0; + memset(m_int, 0, sizeof(m_int)); + memset(m_r, 0, sizeof(m_r)); + m_d = 0; + + // register for savestates + save_item(NAME(m_stack)); + save_item(NAME(m_op)); + save_item(NAME(m_prev_op)); + save_item(NAME(m_i)); + save_item(NAME(m_eint_line)); + save_item(NAME(m_halt)); + save_item(NAME(m_timer_halted_remain)); + save_item(NAME(m_pc)); + save_item(NAME(m_prev_pc)); + save_item(NAME(m_page)); + save_item(NAME(m_a)); + save_item(NAME(m_b)); + save_item(NAME(m_x)); + save_item(NAME(m_spx)); + save_item(NAME(m_y)); + save_item(NAME(m_spy)); + save_item(NAME(m_s)); + save_item(NAME(m_c)); + save_item(NAME(m_tc)); + save_item(NAME(m_cf)); + save_item(NAME(m_ie)); + save_item(NAME(m_iri)); + save_item(NAME(m_irt)); + save_item(NAME(m_if)); + save_item(NAME(m_tf)); + save_item(NAME(m_int)); + + save_item(NAME(m_r)); + save_item(NAME(m_d)); + + // register state for debugger + state_add(HMCS40_PC, "PC", m_pc).formatstr("%04X"); + state_add(HMCS40_A, "A", m_a).formatstr("%01X"); + state_add(HMCS40_B, "B", m_b).formatstr("%01X"); + state_add(HMCS40_X, "X", m_x).formatstr("%01X"); + state_add(HMCS40_SPX, "SPX", m_spx).formatstr("%01X"); + state_add(HMCS40_Y, "Y", m_y).formatstr("%01X"); + state_add(HMCS40_SPY, "SPY", m_spy).formatstr("%01X"); + + state_add(STATE_GENPC, "curpc", m_pc).formatstr("%04X").noshow(); + state_add(STATE_GENFLAGS, "GENFLAGS", m_s).formatstr("%2s").noshow(); + + m_icountptr = &m_icount; +} + + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void hmcs40_cpu_device::device_reset() +{ + m_pc = m_pcmask; + m_prev_op = m_op = 0; + + // clear interrupts + m_cf = 0; + m_ie = 0; + m_iri = m_irt = 0; + m_if[0] = m_if[1] = m_tf = 1; + + // clear i/o + m_d = m_polarity; + for (int i = 0; i < 16; i++) + hmcs40_cpu_device::write_d(i, 0); + + for (int i = 0; i < 8; i++) + hmcs40_cpu_device::write_r(i, 0); +} + + + +//------------------------------------------------- +// i/o handling +//------------------------------------------------- + +UINT8 hmcs40_cpu_device::read_r(int index) +{ + index &= 7; + UINT8 inp = 0; + + switch (index) + { + case 0: inp = m_read_r0(index, 0xff); break; + case 1: inp = m_read_r1(index, 0xff); break; + case 2: inp = m_read_r2(index, 0xff); break; + case 3: inp = m_read_r3(index, 0xff); break; + case 4: inp = m_read_r4(index, 0xff); break; + case 5: inp = m_read_r5(index, 0xff); break; + case 6: inp = m_read_r6(index, 0xff); break; + case 7: inp = m_read_r7(index, 0xff); break; + } + + return ((inp ^ m_polarity) | m_r[index]) & 0xf; +} + +void hmcs40_cpu_device::write_r(int index, UINT8 data) +{ + index &= 7; + data = (data ^ m_polarity) & 0xf; + m_r[index] = data; + + switch (index) + { + case 0: m_write_r0(index, data, 0xff); break; + case 1: m_write_r1(index, data, 0xff); break; + case 2: m_write_r2(index, data, 0xff); break; + case 3: m_write_r3(index, data, 0xff); break; + case 4: m_write_r4(index, data, 0xff); break; + case 5: m_write_r5(index, data, 0xff); break; + case 6: m_write_r6(index, data, 0xff); break; + case 7: m_write_r7(index, data, 0xff); break; + } +} + +int hmcs40_cpu_device::read_d(int index) +{ + index &= 15; + + return ((m_read_d(index, 0xffff) ^ m_polarity) | m_d) >> index & 1; +} + +void hmcs40_cpu_device::write_d(int index, int state) +{ + index &= 15; + state = (((state) ? 1 : 0) ^ m_polarity) & 1; + + m_d = (m_d & ~(1 << index)) | state << index; + m_write_d(index, m_d, 0xffff); +} + +// HMCS43: +// R0 is input-only, R1 is i/o, R2,R3 are output-only, no R4-R7 +// D0-D3 are i/o, D4-D15 are output-only + +UINT8 hmcs43_cpu_device::read_r(int index) +{ + index &= 7; + + if (index >= 2) + logerror("%s read from %s port R%d at $%04X\n", tag(), (index >= 4) ? "unknown" : "output", index, m_prev_pc); + + return hmcs40_cpu_device::read_r(index); +} + +void hmcs43_cpu_device::write_r(int index, UINT8 data) +{ + index &= 7; + + if (index != 0 && index < 4) + hmcs40_cpu_device::write_r(index, data); + else + logerror("%s ineffective write to port R%d = $%X at $%04X\n", tag(), index, data & 0xf, m_prev_pc); +} + +int hmcs43_cpu_device::read_d(int index) +{ + index &= 15; + + if (index >= 4) + logerror("%s read from output pin D%d at $%04X\n", tag(), index, m_prev_pc); + + return hmcs40_cpu_device::read_d(index); +} + +// HMCS44: +// R0-R3 are i/o, R4,R5 are extra registers, no R6,R7 +// D0-D15 are i/o + +UINT8 hmcs44_cpu_device::read_r(int index) +{ + index &= 7; + + if (index >= 6) + logerror("%s read from unknown port R%d at $%04X\n", tag(), index, m_prev_pc); + + return hmcs40_cpu_device::read_r(index); +} + +void hmcs44_cpu_device::write_r(int index, UINT8 data) +{ + index &= 7; + + if (index < 6) + hmcs40_cpu_device::write_r(index, data); + else + logerror("%s ineffective write to port R%d = $%X at $%04X\n", tag(), index, data & 0xf, m_prev_pc); +} + +// HMCS45: +// R0-R5 are i/o, R6 is output-only, no R7 +// D0-D15 are i/o + +UINT8 hmcs45_cpu_device::read_r(int index) +{ + index &= 7; + + if (index >= 6) + logerror("%s read from %s port R%d at $%04X\n", tag(), (index == 7) ? "unknown" : "output", index, m_prev_pc); + + return hmcs40_cpu_device::read_r(index); +} + +void hmcs45_cpu_device::write_r(int index, UINT8 data) +{ + index &= 7; + + if (index != 7) + hmcs40_cpu_device::write_r(index, data); + else + logerror("%s ineffective write to port R%d = $%X at $%04X\n", tag(), index, data & 0xf, m_prev_pc); +} + + + +//------------------------------------------------- +// interrupt/timer handling +//------------------------------------------------- + +void hmcs40_cpu_device::do_interrupt() +{ + m_icount--; + push_stack(); + m_ie = 0; + + // line 0/1 for external interrupt, let's use 2 for t/c interrupt + int line = (m_iri) ? m_eint_line : 2; + + // vector $3f, on page 0(timer/counter), or page 1(external) + // external interrupt has priority over t/c interrupt + m_pc = 0x3f | (m_iri ? 0x40 : 0); + if (m_iri) + m_iri = 0; + else + m_irt = 0; + + standard_irq_callback(line); +} + +void hmcs40_cpu_device::execute_set_input(int line, int state) +{ + state = (state) ? 1 : 0; + + // halt/unhalt mcu + if (line == HMCS40_INPUT_LINE_HLT && state != m_halt) + { + if (state) + { + m_timer_halted_remain = m_timer->remaining(); + m_timer->reset(); + } + else + m_timer->adjust(m_timer_halted_remain); + + m_halt = state; + return; + } + + if (line != 0 && line != 1) + return; + + // external interrupt request on rising edge + if (state && !m_int[line]) + { + if (!m_if[line]) + { + m_eint_line = line; + m_iri = 1; + m_if[line] = 1; + } + + // clock tc if it is in counter mode + if (m_cf && line == 1) + increment_tc(); + } + + m_int[line] = state; +} + +void hmcs40_cpu_device::reset_prescaler() +{ + // reset 6-bit timer prescaler + attotime base = attotime::from_ticks(4 * 64, unscaled_clock()); + m_timer->adjust(base); +} + +TIMER_CALLBACK_MEMBER( hmcs40_cpu_device::simple_timer_cb ) +{ + // timer prescaler overflow + if (!m_cf) + increment_tc(); + + reset_prescaler(); +} + +void hmcs40_cpu_device::increment_tc() +{ + // increment timer/counter + m_tc = (m_tc + 1) & 0xf; + + // timer interrupt request on overflow + if (m_tc == 0 && !m_tf) + { + m_irt = 1; + m_tf = 1; + } +} + + + +//------------------------------------------------- +// execute +//------------------------------------------------- + +inline void hmcs40_cpu_device::increment_pc() +{ + // PC lower bits is a LFSR identical to TI TMS1000 + UINT8 mask = 0x3f; + UINT8 low = m_pc & mask; + int fb = (low << 1 & 0x20) == (low & 0x20); + + if (low == (mask >> 1)) + fb = 1; + else if (low == mask) + fb = 0; + + m_pc = (m_pc & ~mask) | ((m_pc << 1 | fb) & mask); +} + +void hmcs40_cpu_device::execute_run() +{ + // in HLT state, the internal clock is not running + if (m_halt) + { + m_icount = 0; + return; + } + + while (m_icount > 0) + { + // LPU is handled 1 cycle later + if ((m_prev_op & 0x3e0) == 0x340) + m_pc = ((m_page << 6) | (m_pc & 0x3f)) & m_pcmask; + + // remember previous state + m_prev_op = m_op; + m_prev_pc = m_pc; + + // check/handle interrupt, but not in the middle of a long jump + if (m_ie && (m_iri || m_irt) && (m_prev_op & 0x3e0) != 0x340) + { + do_interrupt(); + if (m_icount <= 0) + break; + } + + // fetch next opcode + debugger_instruction_hook(this, m_pc); + m_icount--; + m_op = m_program->read_word(m_pc << 1) & 0x3ff; + m_i = BITSWAP8(m_op,7,6,5,4,0,1,2,3) & 0xf; // reversed bit-order for 4-bit immediate param (except for XAMR, REDD, SEDD) + increment_pc(); + + // handle opcode + switch (m_op) + { + /* 0x000 */ + + case 0x000: case 0x001: case 0x002: case 0x003: + op_xsp(); break; + case 0x004: case 0x005: case 0x006: case 0x007: + op_sem(); break; + case 0x008: case 0x009: case 0x00a: case 0x00b: + op_lam(); break; + case 0x010: case 0x011: case 0x012: case 0x013: case 0x014: case 0x015: case 0x016: case 0x017: + case 0x018: case 0x019: case 0x01a: case 0x01b: case 0x01c: case 0x01d: case 0x01e: case 0x01f: + op_lmiiy(); break; + case 0x020: case 0x021: case 0x022: case 0x023: + op_lbm(); break; + case 0x024: + op_blem(); break; + case 0x030: + op_amc(); break; + case 0x034: + op_am(); break; + case 0x03c: + op_lta(); break; + + case 0x040: + op_lxa(); break; + case 0x045: + op_das(); break; + case 0x046: + op_daa(); break; + case 0x04c: + op_rec(); break; + case 0x04f: + op_sec(); break; + case 0x050: + op_lya(); break; + case 0x054: + op_iy(); break; + case 0x058: + op_ayy(); break; + case 0x060: + op_lba(); break; + case 0x064: + op_ib(); break; + case 0x070: case 0x071: case 0x072: case 0x073: case 0x074: case 0x075: case 0x076: case 0x077: + case 0x078: case 0x079: case 0x07a: case 0x07b: case 0x07c: case 0x07d: case 0x07e: case 0x07f: + op_lai(); break; + + case 0x080: case 0x081: case 0x082: case 0x083: case 0x084: case 0x085: case 0x086: case 0x087: + case 0x088: case 0x089: case 0x08a: case 0x08b: case 0x08c: case 0x08d: case 0x08e: case 0x08f: + op_ai(); break; + case 0x090: + op_sed(); break; + case 0x094: + op_td(); break; + case 0x0a0: + op_seif1(); break; + case 0x0a1: + op_secf(); break; + case 0x0a2: + op_seif0(); break; + case 0x0a4: + op_seie(); break; + case 0x0a5: + op_setf(); break; + + case 0x0c0: case 0x0c1: case 0x0c2: case 0x0c3: case 0x0c4: case 0x0c5: case 0x0c6: case 0x0c7: + op_lar(); break; + case 0x0d0: case 0x0d1: case 0x0d2: case 0x0d3: case 0x0d4: case 0x0d5: case 0x0d6: case 0x0d7: + case 0x0d8: case 0x0d9: case 0x0da: case 0x0db: case 0x0dc: case 0x0dd: case 0x0de: case 0x0df: + op_sedd(); break; + case 0x0e0: case 0x0e1: case 0x0e2: case 0x0e3: case 0x0e4: case 0x0e5: case 0x0e6: case 0x0e7: + op_lbr(); break; + case 0x0f0: case 0x0f1: case 0x0f2: case 0x0f3: case 0x0f4: case 0x0f5: case 0x0f6: case 0x0f7: + case 0x0f8: case 0x0f9: case 0x0fa: case 0x0fb: case 0x0fc: case 0x0fd: case 0x0fe: case 0x0ff: + op_xamr(); break; + + + /* 0x100 */ + + case 0x110: case 0x111: + op_lmaiy(); break; + case 0x114: case 0x115: + op_lmady(); break; + case 0x118: + op_lay(); break; + case 0x120: + op_or(); break; + case 0x124: + op_anem(); break; + + case 0x140: case 0x141: case 0x142: case 0x143: case 0x144: case 0x145: case 0x146: case 0x147: + case 0x148: case 0x149: case 0x14a: case 0x14b: case 0x14c: case 0x14d: case 0x14e: case 0x14f: + op_lxi(); break; + case 0x150: case 0x151: case 0x152: case 0x153: case 0x154: case 0x155: case 0x156: case 0x157: + case 0x158: case 0x159: case 0x15a: case 0x15b: case 0x15c: case 0x15d: case 0x15e: case 0x15f: + op_lyi(); break; + case 0x160: case 0x161: case 0x162: case 0x163: case 0x164: case 0x165: case 0x166: case 0x167: + case 0x168: case 0x169: case 0x16a: case 0x16b: case 0x16c: case 0x16d: case 0x16e: case 0x16f: + op_lbi(); break; + case 0x170: case 0x171: case 0x172: case 0x173: case 0x174: case 0x175: case 0x176: case 0x177: + case 0x178: case 0x179: case 0x17a: case 0x17b: case 0x17c: case 0x17d: case 0x17e: case 0x17f: + op_lti(); break; + + case 0x1a0: + op_tif1(); break; + case 0x1a1: + op_ti1(); break; + case 0x1a2: + op_tif0(); break; + case 0x1a3: + op_ti0(); break; + case 0x1a5: + op_ttf(); break; + + case 0x1c0: case 0x1c1: case 0x1c2: case 0x1c3: case 0x1c4: case 0x1c5: case 0x1c6: case 0x1c7: + case 0x1c8: case 0x1c9: case 0x1ca: case 0x1cb: case 0x1cc: case 0x1cd: case 0x1ce: case 0x1cf: + case 0x1d0: case 0x1d1: case 0x1d2: case 0x1d3: case 0x1d4: case 0x1d5: case 0x1d6: case 0x1d7: + case 0x1d8: case 0x1d9: case 0x1da: case 0x1db: case 0x1dc: case 0x1dd: case 0x1de: case 0x1df: + case 0x1e0: case 0x1e1: case 0x1e2: case 0x1e3: case 0x1e4: case 0x1e5: case 0x1e6: case 0x1e7: + case 0x1e8: case 0x1e9: case 0x1ea: case 0x1eb: case 0x1ec: case 0x1ed: case 0x1ee: case 0x1ef: + case 0x1f0: case 0x1f1: case 0x1f2: case 0x1f3: case 0x1f4: case 0x1f5: case 0x1f6: case 0x1f7: + case 0x1f8: case 0x1f9: case 0x1fa: case 0x1fb: case 0x1fc: case 0x1fd: case 0x1fe: case 0x1ff: + op_br(); break; + + + /* 0x200 */ + + case 0x200: case 0x201: case 0x202: case 0x203: + op_tm(); break; + case 0x204: case 0x205: case 0x206: case 0x207: + op_rem(); break; + case 0x208: case 0x209: case 0x20a: case 0x20b: + op_xma(); break; + case 0x210: case 0x211: case 0x212: case 0x213: case 0x214: case 0x215: case 0x216: case 0x217: + case 0x218: case 0x219: case 0x21a: case 0x21b: case 0x21c: case 0x21d: case 0x21e: case 0x21f: + op_mnei(); break; + case 0x220: case 0x221: case 0x222: case 0x223: + op_xmb(); break; + case 0x224: + op_rotr(); break; + case 0x225: + op_rotl(); break; + case 0x230: + op_smc(); break; + case 0x234: + op_alem(); break; + case 0x23c: + op_lat(); break; + + case 0x240: + op_laspx(); break; + case 0x244: + op_nega(); break; + case 0x24f: + op_tc(); break; + case 0x250: + op_laspy(); break; + case 0x254: + op_dy(); break; + case 0x258: + op_syy(); break; + case 0x260: + op_lab(); break; + case 0x267: + op_db(); break; + case 0x270: case 0x271: case 0x272: case 0x273: case 0x274: case 0x275: case 0x276: case 0x277: + case 0x278: case 0x279: case 0x27a: case 0x27b: case 0x27c: case 0x27d: case 0x27e: case 0x27f: + op_alei(); break; + + case 0x280: case 0x281: case 0x282: case 0x283: case 0x284: case 0x285: case 0x286: case 0x287: + case 0x288: case 0x289: case 0x28a: case 0x28b: case 0x28c: case 0x28d: case 0x28e: case 0x28f: + op_ynei(); break; + case 0x290: + op_red(); break; + case 0x2a0: + op_reif1(); break; + case 0x2a1: + op_recf(); break; + case 0x2a2: + op_reif0(); break; + case 0x2a4: + op_reie(); break; + case 0x2a5: + op_retf(); break; + + case 0x2c0: case 0x2c1: case 0x2c2: case 0x2c3: case 0x2c4: case 0x2c5: case 0x2c6: case 0x2c7: + op_lra(); break; + case 0x2d0: case 0x2d1: case 0x2d2: case 0x2d3: case 0x2d4: case 0x2d5: case 0x2d6: case 0x2d7: + case 0x2d8: case 0x2d9: case 0x2da: case 0x2db: case 0x2dc: case 0x2dd: case 0x2de: case 0x2df: + op_redd(); break; + case 0x2e0: case 0x2e1: case 0x2e2: case 0x2e3: case 0x2e4: case 0x2e5: case 0x2e6: case 0x2e7: + op_lrb(); break; + + + /* 0x300 */ + case 0x320: + op_comb(); break; + case 0x324: + op_bnem(); break; + + case 0x340: case 0x341: case 0x342: case 0x343: case 0x344: case 0x345: case 0x346: case 0x347: + case 0x348: case 0x349: case 0x34a: case 0x34b: case 0x34c: case 0x34d: case 0x34e: case 0x34f: + case 0x350: case 0x351: case 0x352: case 0x353: case 0x354: case 0x355: case 0x356: case 0x357: + case 0x358: case 0x359: case 0x35a: case 0x35b: case 0x35c: case 0x35d: case 0x35e: case 0x35f: + op_lpu(); break; + case 0x360: case 0x361: case 0x362: case 0x363: case 0x364: case 0x365: case 0x366: case 0x367: + op_tbr(); break; + case 0x368: case 0x369: case 0x36a: case 0x36b: case 0x36c: case 0x36d: case 0x36e: case 0x36f: + op_p(); break; + + case 0x3a4: + op_rtni(); break; + case 0x3a7: + op_rtn(); break; + + case 0x3c0: case 0x3c1: case 0x3c2: case 0x3c3: case 0x3c4: case 0x3c5: case 0x3c6: case 0x3c7: + case 0x3c8: case 0x3c9: case 0x3ca: case 0x3cb: case 0x3cc: case 0x3cd: case 0x3ce: case 0x3cf: + case 0x3d0: case 0x3d1: case 0x3d2: case 0x3d3: case 0x3d4: case 0x3d5: case 0x3d6: case 0x3d7: + case 0x3d8: case 0x3d9: case 0x3da: case 0x3db: case 0x3dc: case 0x3dd: case 0x3de: case 0x3df: + case 0x3e0: case 0x3e1: case 0x3e2: case 0x3e3: case 0x3e4: case 0x3e5: case 0x3e6: case 0x3e7: + case 0x3e8: case 0x3e9: case 0x3ea: case 0x3eb: case 0x3ec: case 0x3ed: case 0x3ee: case 0x3ef: + case 0x3f0: case 0x3f1: case 0x3f2: case 0x3f3: case 0x3f4: case 0x3f5: case 0x3f6: case 0x3f7: + case 0x3f8: case 0x3f9: case 0x3fa: case 0x3fb: case 0x3fc: case 0x3fd: case 0x3fe: case 0x3ff: + op_cal(); break; + + + default: + op_illegal(); break; + } /* big switch */ + } +} diff --git a/src/devices/cpu/hmcs40/hmcs40.h b/src/devices/cpu/hmcs40/hmcs40.h new file mode 100644 index 00000000000..c7862ec76b5 --- /dev/null +++ b/src/devices/cpu/hmcs40/hmcs40.h @@ -0,0 +1,475 @@ +// license:BSD-3-Clause +// copyright-holders:hap +/* + + Hitachi HMCS40 MCU family cores + +*/ + +#ifndef _HMCS40_H_ +#define _HMCS40_H_ + +#include "emu.h" + + +// I/O ports setup + +// max 8 4-bit R ports +#define MCFG_HMCS40_READ_R_CB(R, _devcb) \ + hmcs40_cpu_device::set_read_r##R##_callback(*device, DEVCB_##_devcb); +#define MCFG_HMCS40_WRITE_R_CB(R, _devcb) \ + hmcs40_cpu_device::set_write_r##R##_callback(*device, DEVCB_##_devcb); + +// 16-bit discrete +#define MCFG_HMCS40_READ_D_CB(_devcb) \ + hmcs40_cpu_device::set_read_d_callback(*device, DEVCB_##_devcb); +#define MCFG_HMCS40_WRITE_D_CB(_devcb) \ + hmcs40_cpu_device::set_write_d_callback(*device, DEVCB_##_devcb); + +enum +{ + HMCS40_PORT_R0X = 0, + HMCS40_PORT_R1X, + HMCS40_PORT_R2X, + HMCS40_PORT_R3X, + HMCS40_PORT_R4X, + HMCS40_PORT_R5X, + HMCS40_PORT_R6X, + HMCS40_PORT_R7X +}; + +enum +{ + HMCS40_INPUT_LINE_INT0 = 0, + HMCS40_INPUT_LINE_INT1, + HMCS40_INPUT_LINE_HLT +}; + +enum +{ + HMCS40_FAMILY_HMCS42 = 0, + HMCS40_FAMILY_HMCS43, + HMCS40_FAMILY_HMCS44, + HMCS40_FAMILY_HMCS45, + HMCS40_FAMILY_HMCS46, + HMCS40_FAMILY_HMCS47 +}; + + +// pinout reference + +/* + _________________ + D3 1 |* | 42 D2 + D4 2 | | 41 D1 + D5 3 | | 40 D0 + D6 4 | | 39 R33 + D7 5 | | 38 R32 + D8 6 | | 37 R31 + D9 7 | | 36 R30 + D10 8 | | 35 R23 ....................................... + D11 9 | | 34 R22 : + D12 10 | HD38750 | 33 R21 : + D13 11 | HD38800 | 32 R20 : + D14 12 | | 31 INT1 : + D15 13 | | 30 INT0 : _________________ + Vdisp 14 | | 29 R13 : D4 1 |* | 64 D3 + RESET 15 | | 28 R12 : D5 2 | | 63 D2 + Vbb 16 | | 27 R11 : D6 3 | | 62 D1 + Vdd 17 | | 26 R10 : D7 4 | | 61 D0 + OSC 18 | | 25 R03 : D8 5 | | 60 R63 + 19 | | 24 R02 : D9 6 | | 59 R62 + /TEST 20 | | 23 R01 : 7 | | 58 + Vss 21 |_________________| 22 R00 : 8 | | 57 + 9 | | 56 + D10 10 | | 55 R61 + D8 D7 D6 D5 D4 D3 D2 D1 D0 D11 11 | | 54 R60 + 5 4 3 2 1 54 53 52 51 50 D12 12 | | 53 R33 + __________________________________ D13 13 | | 52 R32 + / | D14 14 | | 51 R31 + D9 6 | | 49 R63 D15 15 | | 50 R30 + D10 7 | | 48 R62 R40 16 | | 49 R23 + D11 8 | | 47 R61 R41 17 | | 48 R22 + D12 9 | | 46 R60 R42 18 | | 47 R21 + D13 10 | | 45 R33 R43 19 | | 46 R20 + D14 11 | | 44 R32 R50 20 | | 45 INT1 + D15 12 | | 43 R31 R51 21 | | 44 INT0 + R40 13 | HD38820 | 42 R30 R52 22 | HD38820 | 43 R13 + R41 14 | (FP-54 pkg) | 41 R23 R53 23 | (DP-64S pkg) | 42 R12 + R42 15 | | 40 R22 Vdisp 24 | | 41 + R43 16 | | 39 R21 25 | | 40 + R50 17 | | 38 R20 RESET 26 | | 39 + R51 18 | | 37 INT1 Vbb 27 | | 38 R11 + R52 19 | | 36 INT0 Vdd 28 | | 37 R10 + R53 20 | | 35 R13 OSC 29 | | 36 R03 + Vdisp 21 | | 34 R12 30 | | 35 R02 + RESET 22 | | 33 R11 /TEST 31 | | 34 R01 + |__________________________________| Vss 32 |_________________| 33 R00 + + 23 24 25 26 27 28 29 30 31 32 + Vbb | OSC | Vss R00 | R02 | R10 + Vdd /TEST R01 R03 +*/ + + +class hmcs40_cpu_device : public cpu_device +{ +public: + // construction/destruction + hmcs40_cpu_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, int family, UINT16 polarity, int stack_levels, int pcwidth, int prgwidth, address_map_constructor program, int datawidth, address_map_constructor data, const char *shortname, const char *source) + : cpu_device(mconfig, type, name, tag, owner, clock, shortname, source) + , m_program_config("program", ENDIANNESS_LITTLE, 16, prgwidth, -1, program) + , m_data_config("data", ENDIANNESS_LITTLE, 8, datawidth, 0, data) + , m_pcwidth(pcwidth) + , m_prgwidth(prgwidth) + , m_datawidth(datawidth) + , m_family(family) + , m_polarity(polarity) + , m_stack_levels(stack_levels) + , m_read_r0(*this), m_read_r1(*this), m_read_r2(*this), m_read_r3(*this), m_read_r4(*this), m_read_r5(*this), m_read_r6(*this), m_read_r7(*this) + , m_write_r0(*this), m_write_r1(*this), m_write_r2(*this), m_write_r3(*this), m_write_r4(*this), m_write_r5(*this), m_write_r6(*this), m_write_r7(*this) + , m_read_d(*this) + , m_write_d(*this) + { } + + // static configuration helpers + template static devcb_base &set_read_r0_callback(device_t &device, _Object object) { return downcast(device).m_read_r0.set_callback(object); } + template static devcb_base &set_read_r1_callback(device_t &device, _Object object) { return downcast(device).m_read_r1.set_callback(object); } + template static devcb_base &set_read_r2_callback(device_t &device, _Object object) { return downcast(device).m_read_r2.set_callback(object); } + template static devcb_base &set_read_r3_callback(device_t &device, _Object object) { return downcast(device).m_read_r3.set_callback(object); } + template static devcb_base &set_read_r4_callback(device_t &device, _Object object) { return downcast(device).m_read_r4.set_callback(object); } + template static devcb_base &set_read_r5_callback(device_t &device, _Object object) { return downcast(device).m_read_r5.set_callback(object); } + template static devcb_base &set_read_r6_callback(device_t &device, _Object object) { return downcast(device).m_read_r6.set_callback(object); } + template static devcb_base &set_read_r7_callback(device_t &device, _Object object) { return downcast(device).m_read_r7.set_callback(object); } + + template static devcb_base &set_write_r0_callback(device_t &device, _Object object) { return downcast(device).m_write_r0.set_callback(object); } + template static devcb_base &set_write_r1_callback(device_t &device, _Object object) { return downcast(device).m_write_r1.set_callback(object); } + template static devcb_base &set_write_r2_callback(device_t &device, _Object object) { return downcast(device).m_write_r2.set_callback(object); } + template static devcb_base &set_write_r3_callback(device_t &device, _Object object) { return downcast(device).m_write_r3.set_callback(object); } + template static devcb_base &set_write_r4_callback(device_t &device, _Object object) { return downcast(device).m_write_r4.set_callback(object); } + template static devcb_base &set_write_r5_callback(device_t &device, _Object object) { return downcast(device).m_write_r5.set_callback(object); } + template static devcb_base &set_write_r6_callback(device_t &device, _Object object) { return downcast(device).m_write_r6.set_callback(object); } + template static devcb_base &set_write_r7_callback(device_t &device, _Object object) { return downcast(device).m_write_r7.set_callback(object); } + + template static devcb_base &set_read_d_callback(device_t &device, _Object object) { return downcast(device).m_read_d.set_callback(object); } + template static devcb_base &set_write_d_callback(device_t &device, _Object object) { return downcast(device).m_write_d.set_callback(object); } + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_execute_interface overrides + virtual UINT64 execute_clocks_to_cycles(UINT64 clocks) const { return (clocks + 4 - 1) / 4; } // 4 cycles per machine cycle + virtual UINT64 execute_cycles_to_clocks(UINT64 cycles) const { return (cycles * 4); } // " + virtual UINT32 execute_min_cycles() const { return 1; } + virtual UINT32 execute_max_cycles() const { return 2; } + virtual UINT32 execute_input_lines() const { return 2+1; } // 3rd one is internal + virtual void execute_set_input(int line, int state); + virtual void execute_run(); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const { return(spacenum == AS_PROGRAM) ? &m_program_config : ((spacenum == AS_DATA) ? &m_data_config : NULL); } + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const { return 2; } + virtual UINT32 disasm_max_opcode_bytes() const { return 2; } + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + void state_string_export(const device_state_entry &entry, std::string &str); + + address_space_config m_program_config; + address_space_config m_data_config; + address_space *m_program; + address_space *m_data; + + int m_pcwidth; // Program Counter bit-width + int m_prgwidth; + int m_datawidth; + int m_pcmask; + int m_prgmask; + int m_datamask; + int m_family; // MCU family (42-47) + UINT16 m_polarity; // i/o polarity (pmos vs cmos) + int m_stack_levels; // number of callstack levels + UINT16 m_stack[4]; // max 4 + UINT16 m_op; // current opcode + UINT16 m_prev_op; + UINT8 m_i; // 4-bit immediate opcode param + int m_eint_line; // which input_line caused an interrupt + emu_timer *m_timer; + int m_halt; // internal HLT state + attotime m_timer_halted_remain; + int m_icount; + + UINT16 m_pc; // Program Counter + UINT16 m_prev_pc; + UINT8 m_page; // LPU prepared page + UINT8 m_a; // 4-bit Accumulator + UINT8 m_b; // 4-bit B register + UINT8 m_x; // 1/3/4-bit X register + UINT8 m_spx; // 1/3/4-bit SPX register + UINT8 m_y; // 4-bit Y register + UINT8 m_spy; // 4-bit SPY register + UINT8 m_s; // Status F/F (F/F = flip-flop) + UINT8 m_c; // Carry F/F + UINT8 m_tc; // Timer/Counter + UINT8 m_cf; // CF F/F (timer mode or counter mode) + UINT8 m_ie; // I/E(Interrupt Enable) F/F + UINT8 m_iri; // external interrupt pending I/RI F/F + UINT8 m_irt; // timer interrupt pending I/RT F/F + UINT8 m_if[2]; // external interrupt mask IF0,1 F/F + UINT8 m_tf; // timer interrupt mask TF F/F + UINT8 m_int[2]; // INT0/1 pins state + UINT8 m_r[8]; // R outputs state + UINT16 m_d; // D pins state + + // i/o handlers + devcb_read8 m_read_r0, m_read_r1, m_read_r2, m_read_r3, m_read_r4, m_read_r5, m_read_r6, m_read_r7; + devcb_write8 m_write_r0, m_write_r1, m_write_r2, m_write_r3, m_write_r4, m_write_r5, m_write_r6, m_write_r7; + devcb_read16 m_read_d; + devcb_write16 m_write_d; + + // misc internal helpers + void increment_pc(); + + UINT8 ram_r(); + void ram_w(UINT8 data); + void pop_stack(); + void push_stack(); + + virtual UINT8 read_r(int index); + virtual void write_r(int index, UINT8 data); + virtual int read_d(int index); + virtual void write_d(int index, int state); + + void reset_prescaler(); + TIMER_CALLBACK_MEMBER( simple_timer_cb ); + void increment_tc(); + void do_interrupt(); + + // opcode handlers + void op_illegal(); + + void op_lab(); + void op_lba(); + void op_lay(); + void op_laspx(); + void op_laspy(); + void op_xamr(); + + void op_lxa(); + void op_lya(); + void op_lxi(); + void op_lyi(); + void op_iy(); + void op_dy(); + void op_ayy(); + void op_syy(); + void op_xsp(); + + void op_lam(); + void op_lbm(); + void op_xma(); + void op_xmb(); + void op_lmaiy(); + void op_lmady(); + + void op_lmiiy(); + void op_lai(); + void op_lbi(); + + void op_ai(); + void op_ib(); + void op_db(); + void op_amc(); + void op_smc(); + void op_am(); + void op_daa(); + void op_das(); + void op_nega(); + void op_comb(); + void op_sec(); + void op_rec(); + void op_tc(); + void op_rotl(); + void op_rotr(); + void op_or(); + + void op_mnei(); + void op_ynei(); + void op_anem(); + void op_bnem(); + void op_alei(); + void op_alem(); + void op_blem(); + + void op_sem(); + void op_rem(); + void op_tm(); + + void op_br(); + void op_cal(); + void op_lpu(); + void op_tbr(); + void op_rtn(); + + void op_seie(); + void op_seif0(); + void op_seif1(); + void op_setf(); + void op_secf(); + void op_reie(); + void op_reif0(); + void op_reif1(); + void op_retf(); + void op_recf(); + void op_ti0(); + void op_ti1(); + void op_tif0(); + void op_tif1(); + void op_ttf(); + void op_lti(); + void op_lta(); + void op_lat(); + void op_rtni(); + + void op_sed(); + void op_red(); + void op_td(); + void op_sedd(); + void op_redd(); + void op_lar(); + void op_lbr(); + void op_lra(); + void op_lrb(); + void op_p(); +}; + + +class hmcs43_cpu_device : public hmcs40_cpu_device +{ +public: + hmcs43_cpu_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, UINT16 polarity, const char *shortname); + +protected: + // overrides + virtual UINT8 read_r(int index); + virtual void write_r(int index, UINT8 data); + virtual int read_d(int index); +}; + +class hd38750_device : public hmcs43_cpu_device +{ +public: + hd38750_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class hd38755_device : public hmcs43_cpu_device +{ +public: + hd38755_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class hd44750_device : public hmcs43_cpu_device +{ +public: + hd44750_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class hd44758_device : public hmcs43_cpu_device +{ +public: + hd44758_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +class hmcs44_cpu_device : public hmcs40_cpu_device +{ +public: + hmcs44_cpu_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, UINT16 polarity, const char *shortname); + +protected: + // overrides + virtual UINT8 read_r(int index); + virtual void write_r(int index, UINT8 data); +}; + +class hd38800_device : public hmcs44_cpu_device +{ +public: + hd38800_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class hd38805_device : public hmcs44_cpu_device +{ +public: + hd38805_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class hd44801_device : public hmcs44_cpu_device +{ +public: + hd44801_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class hd44808_device : public hmcs44_cpu_device +{ +public: + hd44808_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +class hmcs45_cpu_device : public hmcs40_cpu_device +{ +public: + hmcs45_cpu_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, UINT16 polarity, const char *shortname); + +protected: + // overrides + virtual UINT8 read_r(int index); + virtual void write_r(int index, UINT8 data); +}; + +class hd38820_device : public hmcs45_cpu_device +{ +public: + hd38820_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class hd38825_device : public hmcs45_cpu_device +{ +public: + hd38825_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class hd44820_device : public hmcs45_cpu_device +{ +public: + hd44820_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class hd44828_device : public hmcs45_cpu_device +{ +public: + hd44828_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + + +extern const device_type HD38750; +extern const device_type HD38755; +extern const device_type HD44750; +extern const device_type HD44758; + +extern const device_type HD38800; +extern const device_type HD38805; +extern const device_type HD44801; +extern const device_type HD44808; + +extern const device_type HD38820; +extern const device_type HD38825; +extern const device_type HD44820; +extern const device_type HD44828; + + +#endif /* _HMCS40_H_ */ diff --git a/src/devices/cpu/hmcs40/hmcs40d.c b/src/devices/cpu/hmcs40/hmcs40d.c new file mode 100644 index 00000000000..b63ba1fde4d --- /dev/null +++ b/src/devices/cpu/hmcs40/hmcs40d.c @@ -0,0 +1,232 @@ +// license:BSD-3-Clause +// copyright-holders:hap +/* + + Hitachi HMCS40 MCU family disassembler + + NOTE: start offset(basepc) is $3F, not 0 + +*/ + +#include "emu.h" +#include "debugger.h" +#include "hmcs40.h" + + +enum e_mnemonics +{ + mILL, + mLAB, mLBA, mLAY, mLASPX, mLASPY, mXAMR, + mLXA, mLYA, mLXI, mLYI, mIY, mDY, mAYY, mSYY, mXSP, + mLAM, mLBM, mXMA, mXMB, mLMAIY, mLMADY, + mLMIIY, mLAI, mLBI, + mAI, mIB, mDB, mAMC, mSMC, mAM, mDAA, mDAS, mNEGA, mCOMB, mSEC, mREC, mTC, mROTL, mROTR, mOR, + mMNEI, mYNEI, mANEM, mBNEM, mALEI, mALEM, mBLEM, + mSEM, mREM, mTM, + mBR, mCAL, mLPU, mTBR, mRTN, + mSEIE, mSEIF0, mSEIF1, mSETF, mSECF, mREIE, mREIF0, mREIF1, mRETF, mRECF, mTI0, mTI1, mTIF0, mTIF1, mTTF, mLTI, mLTA, mLAT, mRTNI, + mSED, mRED, mTD, mSEDD, mREDD, mLAR, mLBR, mLRA, mLRB, mP, + mNOP +}; + +static const char *const s_mnemonics[] = +{ + "?", + "LAB", "LBA", "LAY", "LASPX", "LASPY", "XAMR", + "LXA", "LYA", "LXI", "LYI", "IY", "DY", "AYY", "SYY", "XSP", + "LAM", "LBM", "XMA", "XMB", "LMAIY", "LMADY", + "LMIIY", "LAI", "LBI", + "AI", "IB", "DB", "AMC", "SMC", "AM", "DAA", "DAS", "NEGA", "COMB", "SEC", "REC", "TC", "ROTL", "ROTR", "OR", + "MNEI", "YNEI", "ANEM", "BNEM", "ALEI", "ALEM", "BLEM", + "SEM", "REM", "TM", + "BR", "CAL", "LPU", "TBR", "RTN", + "SEIE", "SEIF0", "SEIF1", "SETF", "SECF", "REIE", "REIF0", "REIF1", "RETF", "RECF", "TI0", "TI1", "TIF0", "TIF1", "TTF", "LTI", "LTA", "LAT", "RTNI", + "SED", "RED", "TD", "SEDD", "REDD", "LAR", "LBR", "LRA", "LRB", "P", + "NOP" +}; + +// number of bits per opcode parameter, 99 means (XY) parameter, negative means reversed bit-order +static const INT8 s_bits[] = +{ + 0, + 0, 0, 0, 0, 0, 4, + 0, 0, -4, -4, 0, 0, 0, 0, 99, + 99, 99, 99, 99, 99, 99, + -4, -4, -4, + -4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -4, -4, 0, 0, -4, 0, 0, + 2, 2, 2, + 6, 6, 5, 3, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -4, 0, 0, 0, + 0, 0, 0, 4, 4, 3, 3, 3, 3, 3, + 0 +}; + +#define _OVER DASMFLAG_STEP_OVER +#define _OUT DASMFLAG_STEP_OUT + +static const UINT32 s_flags[] = +{ + 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, + 0, _OVER, 0, 0, _OUT, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, _OUT, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0 +}; + +// next program counter in sequence (relative) +static const INT8 s_next_pc[0x40] = +{ + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 32+0x40 /* rollback */, + -32, -31, -30, -29, -28, -27, -26, -25, -24, -23, -22, -21, -20, -19, -18, -17, + -15, -14, -13, -12, -11, -10, -9, -8, -7, -6, -5, -4, -3, -2, -1, -1 +}; + + +static const UINT8 hmcs40_mnemonic[0x400] = +{ +/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ + /* 0x000 */ + mNOP, mXSP, mXSP, mXSP, mSEM, mSEM, mSEM, mSEM, mLAM, mLAM, mLAM, mLAM, 0, 0, 0, 0, + mLMIIY,mLMIIY,mLMIIY,mLMIIY,mLMIIY,mLMIIY,mLMIIY,mLMIIY,mLMIIY,mLMIIY,mLMIIY,mLMIIY,mLMIIY,mLMIIY,mLMIIY,mLMIIY, + mLBM, mLBM, mLBM, mLBM, mBLEM, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + mAMC, 0, 0, 0, mAM, 0, 0, 0, 0, 0, 0, 0, mLTA, 0, 0, 0, + /* 0x040 */ + mLXA, 0, 0, 0, 0, mDAS, mDAA, 0, 0, 0, 0, 0, mREC, 0, 0, mSEC, + mLYA, 0, 0, 0, mIY, 0, 0, 0, mAYY, 0, 0, 0, 0, 0, 0, 0, + mLBA, 0, 0, 0, mIB, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + mLAI, mLAI, mLAI, mLAI, mLAI, mLAI, mLAI, mLAI, mLAI, mLAI, mLAI, mLAI, mLAI, mLAI, mLAI, mLAI, + /* 0x080 */ + mAI, mAI, mAI, mAI, mAI, mAI, mAI, mAI, mAI, mAI, mAI, mAI, mAI, mAI, mAI, mAI, + mSED, 0, 0, 0, mTD, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + mSEIF1,mSECF, mSEIF0,0, mSEIE, mSETF, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x0c0 */ + mLAR, mLAR, mLAR, mLAR, mLAR, mLAR, mLAR, mLAR, 0, 0, 0, 0, 0, 0, 0, 0, + mSEDD, mSEDD, mSEDD, mSEDD, mSEDD, mSEDD, mSEDD, mSEDD, mSEDD, mSEDD, mSEDD, mSEDD, mSEDD, mSEDD, mSEDD, mSEDD, + mLBR, mLBR, mLBR, mLBR, mLBR, mLBR, mLBR, mLBR, 0, 0, 0, 0, 0, 0, 0, 0, + mXAMR, mXAMR, mXAMR, mXAMR, mXAMR, mXAMR, mXAMR, mXAMR, mXAMR, mXAMR, mXAMR, mXAMR, mXAMR, mXAMR, mXAMR, mXAMR, + +/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ + /* 0x100 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + mLMAIY,mLMAIY,0, 0, mLMADY,mLMADY,0, 0, mLAY, 0, 0, 0, 0, 0, 0, 0, + mOR, 0, 0, 0, mANEM, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x140 */ + mLXI, mLXI, mLXI, mLXI, mLXI, mLXI, mLXI, mLXI, mLXI, mLXI, mLXI, mLXI, mLXI, mLXI, mLXI, mLXI, + mLYI, mLYI, mLYI, mLYI, mLYI, mLYI, mLYI, mLYI, mLYI, mLYI, mLYI, mLYI, mLYI, mLYI, mLYI, mLYI, + mLBI, mLBI, mLBI, mLBI, mLBI, mLBI, mLBI, mLBI, mLBI, mLBI, mLBI, mLBI, mLBI, mLBI, mLBI, mLBI, + mLTI, mLTI, mLTI, mLTI, mLTI, mLTI, mLTI, mLTI, mLTI, mLTI, mLTI, mLTI, mLTI, mLTI, mLTI, mLTI, + /* 0x180 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + mTIF1, mTI1, mTIF0, mTI0, 0, mTTF, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x1c0 */ + mBR, mBR, mBR, mBR, mBR, mBR, mBR, mBR, mBR, mBR, mBR, mBR, mBR, mBR, mBR, mBR, + mBR, mBR, mBR, mBR, mBR, mBR, mBR, mBR, mBR, mBR, mBR, mBR, mBR, mBR, mBR, mBR, + mBR, mBR, mBR, mBR, mBR, mBR, mBR, mBR, mBR, mBR, mBR, mBR, mBR, mBR, mBR, mBR, + mBR, mBR, mBR, mBR, mBR, mBR, mBR, mBR, mBR, mBR, mBR, mBR, mBR, mBR, mBR, mBR, + +/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ + /* 0x200 */ + mTM, mTM, mTM, mTM, mREM, mREM, mREM, mREM, mXMA, mXMA, mXMA, mXMA, 0, 0, 0, 0, + mMNEI, mMNEI, mMNEI, mMNEI, mMNEI, mMNEI, mMNEI, mMNEI, mMNEI, mMNEI, mMNEI, mMNEI, mMNEI, mMNEI, mMNEI, mMNEI, + mXMB, mXMB, mXMB, mXMB, mROTR, mROTL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + mSMC, 0, 0, 0, mALEM, 0, 0, 0, 0, 0, 0, 0, mLAT, 0, 0, 0, + /* 0x240 */ + mLASPX,0, 0, 0, mNEGA, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, mTC, + mLASPY,0, 0, 0, mDY, 0, 0, 0, mSYY, 0, 0, 0, 0, 0, 0, 0, + mLAB, 0, 0, 0, 0, 0, 0, mDB, 0, 0, 0, 0, 0, 0, 0, 0, + mALEI, mALEI, mALEI, mALEI, mALEI, mALEI, mALEI, mALEI, mALEI, mALEI, mALEI, mALEI, mALEI, mALEI, mALEI, mALEI, + /* 0x280 */ + mYNEI, mYNEI, mYNEI, mYNEI, mYNEI, mYNEI, mYNEI, mYNEI, mYNEI, mYNEI, mYNEI, mYNEI, mYNEI, mYNEI, mYNEI, mYNEI, + mRED, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + mREIF1,mRECF, mREIF0,0, mREIE, mRETF, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x2c0 */ + mLRA, mLRA, mLRA, mLRA, mLRA, mLRA, mLRA, mLRA, 0, 0, 0, 0, 0, 0, 0, 0, + mREDD, mREDD, mREDD, mREDD, mREDD, mREDD, mREDD, mREDD, mREDD, mREDD, mREDD, mREDD, mREDD, mREDD, mREDD, mREDD, + mLRB, mLRB, mLRB, mLRB, mLRB, mLRB, mLRB, mLRB, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + +/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ + /* 0x300 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + mCOMB, 0, 0, 0, mBNEM, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x340 */ + mLPU, mLPU, mLPU, mLPU, mLPU, mLPU, mLPU, mLPU, mLPU, mLPU, mLPU, mLPU, mLPU, mLPU, mLPU, mLPU, + mLPU, mLPU, mLPU, mLPU, mLPU, mLPU, mLPU, mLPU, mLPU, mLPU, mLPU, mLPU, mLPU, mLPU, mLPU, mLPU, + mTBR, mTBR, mTBR, mTBR, mTBR, mTBR, mTBR, mTBR, mP, mP, mP, mP, mP, mP, mP, mP, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x380 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, mRTNI, 0, 0, mRTN, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x3c0 */ + mCAL, mCAL, mCAL, mCAL, mCAL, mCAL, mCAL, mCAL, mCAL, mCAL, mCAL, mCAL, mCAL, mCAL, mCAL, mCAL, + mCAL, mCAL, mCAL, mCAL, mCAL, mCAL, mCAL, mCAL, mCAL, mCAL, mCAL, mCAL, mCAL, mCAL, mCAL, mCAL, + mCAL, mCAL, mCAL, mCAL, mCAL, mCAL, mCAL, mCAL, mCAL, mCAL, mCAL, mCAL, mCAL, mCAL, mCAL, mCAL, + mCAL, mCAL, mCAL, mCAL, mCAL, mCAL, mCAL, mCAL, mCAL, mCAL, mCAL, mCAL, mCAL, mCAL, mCAL, mCAL +}; + + + +CPU_DISASSEMBLE(hmcs40) +{ + UINT16 op = (oprom[0] | oprom[1] << 8) & 0x3ff; + char *dst = buffer; + UINT8 instr = hmcs40_mnemonic[op]; + INT8 bits = s_bits[instr]; + + // special case for (XY) opcode + if (bits == 99) + { + dst += sprintf(dst, "%s", s_mnemonics[instr]); + + if (op & 1) + dst += sprintf(dst, "X"); + if (op & 2) + dst += sprintf(dst, "Y"); + } + else + { + dst += sprintf(dst, "%-6s ", s_mnemonics[instr]); + + // opcode parameter + if (bits != 0) + { + UINT8 param = op; + + // reverse bits + if (bits < 0) + { + param = BITSWAP8(param,0,1,2,3,4,5,6,7); + param >>= (8 + bits); + bits = -bits; + } + + param &= ((1 << bits) - 1); + + if (bits > 5) + dst += sprintf(dst, "$%02X", param); + else + dst += sprintf(dst, "%d", param); + } + } + + int pos = s_next_pc[pc & 0x3f] & DASMFLAG_LENGTHMASK; + return pos | s_flags[instr] | DASMFLAG_SUPPORTED; +} diff --git a/src/devices/cpu/hmcs40/hmcs40op.c b/src/devices/cpu/hmcs40/hmcs40op.c new file mode 100644 index 00000000000..f6faab90360 --- /dev/null +++ b/src/devices/cpu/hmcs40/hmcs40op.c @@ -0,0 +1,681 @@ +// license:BSD-3-Clause +// copyright-holders:hap + +// HMCS40 opcode handlers + +#include "hmcs40.h" + + +// internal helpers + +inline UINT8 hmcs40_cpu_device::ram_r() +{ + UINT8 address = (m_x << 4 | m_y) & m_datamask; + return m_data->read_byte(address) & 0xf; +} + +inline void hmcs40_cpu_device::ram_w(UINT8 data) +{ + UINT8 address = (m_x << 4 | m_y) & m_datamask; + m_data->write_byte(address, data & 0xf); +} + +void hmcs40_cpu_device::pop_stack() +{ + m_pc = m_stack[0] & m_pcmask; + for (int i = 0; i < m_stack_levels-1; i++) + m_stack[i] = m_stack[i+1]; +} + +void hmcs40_cpu_device::push_stack() +{ + for (int i = m_stack_levels-1; i >= 1; i--) + m_stack[i] = m_stack[i-1]; + m_stack[0] = m_pc; +} + + + +// instruction set + +void hmcs40_cpu_device::op_illegal() +{ + logerror("%s unknown opcode $%03X at $%04X\n", tag(), m_op, m_prev_pc); +} + + +// Register-to-Register Instruction + +void hmcs40_cpu_device::op_lab() +{ + // LAB: Load A from B + m_a = m_b; +} + +void hmcs40_cpu_device::op_lba() +{ + // LBA: Load B from A + m_b = m_a; +} + +void hmcs40_cpu_device::op_lay() +{ + // LAY: Load A from Y + m_a = m_y; +} + +void hmcs40_cpu_device::op_laspx() +{ + // LASPX: Load A from SPX + m_a = m_spx; +} + +void hmcs40_cpu_device::op_laspy() +{ + // LASPY: Load A from SPY + m_a = m_spy; +} + +void hmcs40_cpu_device::op_xamr() +{ + // XAMR m: Exchange A and MR(m) + + // determine MR(Memory Register) location + UINT8 address = m_op & 0xf; + + // HMCS42: MR0 on file 0, MR4-MR15 on file 4 (there is no file 1-3) + // HMCS43: MR0-MR3 on file 0-3, MR4-MR15 on file 4 + if (m_family == HMCS40_FAMILY_HMCS42 || m_family == HMCS40_FAMILY_HMCS43) + address |= (address < 4) ? (address << 4) : 0x40; + + // HMCS44/45/46/47: all on last file + else + address |= 0xf0; + + address &= m_datamask; + UINT8 old_a = m_a; + m_a = m_data->read_byte(address) & 0xf; + m_data->write_byte(address, old_a & 0xf); +} + + +// RAM Address Instruction + +void hmcs40_cpu_device::op_lxa() +{ + // LXA: Load X from A + m_x = m_a; +} + +void hmcs40_cpu_device::op_lya() +{ + // LYA: Load Y from A + m_y = m_a; +} + +void hmcs40_cpu_device::op_lxi() +{ + // LXI i: Load X from Immediate + m_x = m_i; +} + +void hmcs40_cpu_device::op_lyi() +{ + // LYI i: Load Y from Immediate + m_y = m_i; +} + +void hmcs40_cpu_device::op_iy() +{ + // IY: Increment Y + m_y = (m_y + 1) & 0xf; + m_s = (m_y != 0); +} + +void hmcs40_cpu_device::op_dy() +{ + // DY: Decrement Y + m_y = (m_y - 1) & 0xf; + m_s = (m_y != 0xf); +} + +void hmcs40_cpu_device::op_ayy() +{ + // AYY: Add A to Y + m_y += m_a; + m_s = m_y >> 4 & 1; + m_y &= 0xf; +} + +void hmcs40_cpu_device::op_syy() +{ + // SYY: Subtract A from Y + m_y -= m_a; + m_s = ~m_y >> 4 & 1; + m_y &= 0xf; +} + +void hmcs40_cpu_device::op_xsp() +{ + // XSP (XY): Exchange X and SPX, Y and SPY, or NOP if 0 + if (m_op & 1) + { + UINT8 old_x = m_x; + m_x = m_spx; + m_spx = old_x; + } + if (m_op & 2) + { + UINT8 old_y = m_y; + m_y = m_spy; + m_spy = old_y; + } +} + + +// Ram Register Instruction + +void hmcs40_cpu_device::op_lam() +{ + // LAM (XY): Load A from Memory + m_a = ram_r(); + op_xsp(); +} + +void hmcs40_cpu_device::op_lbm() +{ + // LBM (XY): Load B from Memory + m_b = ram_r(); + op_xsp(); +} + +void hmcs40_cpu_device::op_xma() +{ + // XMA (XY): Exchange Memory and A + UINT8 old_a = m_a; + m_a = ram_r(); + ram_w(old_a); + op_xsp(); +} + +void hmcs40_cpu_device::op_xmb() +{ + // XMB (XY): Exchange Memory and B + UINT8 old_b = m_b; + m_b = ram_r(); + ram_w(old_b); + op_xsp(); +} + +void hmcs40_cpu_device::op_lmaiy() +{ + // LMAIY (X): Load Memory from A, Increment Y + ram_w(m_a); + op_iy(); + op_xsp(); +} + +void hmcs40_cpu_device::op_lmady() +{ + // LMADY (X): Load Memory from A, Decrement Y + ram_w(m_a); + op_dy(); + op_xsp(); +} + + +// Immediate Instruction + +void hmcs40_cpu_device::op_lmiiy() +{ + // LMIIY i: Load Memory from Immediate, Increment Y + ram_w(m_i); + op_iy(); +} + +void hmcs40_cpu_device::op_lai() +{ + // LAI i: Load A from Immediate + m_a = m_i; +} + +void hmcs40_cpu_device::op_lbi() +{ + // LBI i: Load B from Immediate + m_b = m_i; +} + + +// Arithmetic Instruction + +void hmcs40_cpu_device::op_ai() +{ + // AI i: Add Immediate to A + m_a += (m_i); + m_s = m_a >> 4 & 1; + m_a &= 0xf; +} + +void hmcs40_cpu_device::op_ib() +{ + // IB: Increment B + m_b = (m_b + 1) & 0xf; + m_s = (m_b != 0); +} + +void hmcs40_cpu_device::op_db() +{ + // DB: Decrement B + m_b = (m_b - 1) & 0xf; + m_s = (m_b != 0xf); +} + +void hmcs40_cpu_device::op_amc() +{ + // AMC: Add A to Memory with Carry + m_a += ram_r() + m_c; + m_c = m_a >> 4 & 1; + m_s = m_c; + m_a &= 0xf; +} + +void hmcs40_cpu_device::op_smc() +{ + // SMC: Subtract A from Memory with Carry + m_a = ram_r() - m_a - (m_c ^ 1); + m_c = ~m_a >> 4 & 1; + m_s = m_c; + m_a &= 0xf; +} + +void hmcs40_cpu_device::op_am() +{ + // AM: Add A to Memory + m_a += ram_r(); + m_s = m_a >> 4 & 1; + m_a &= 0xf; +} + +void hmcs40_cpu_device::op_daa() +{ + // DAA: Decimal Adjust for Addition + if (m_c || m_a > 9) + { + m_a = (m_a + 6) & 0xf; + m_c = 1; + } +} + +void hmcs40_cpu_device::op_das() +{ + // DAS: Decimal Adjust for Subtraction + if (!m_c || m_a > 9) + { + m_a = (m_a + 10) & 0xf; + m_c = 0; + } +} + +void hmcs40_cpu_device::op_nega() +{ + // NEGA: Negate A + m_a = (0 - m_a) & 0xf; +} + +void hmcs40_cpu_device::op_comb() +{ + // COMB: Complement B + m_b ^= 0xf; +} + +void hmcs40_cpu_device::op_sec() +{ + // SEC: Set Carry + m_c = 1; +} + +void hmcs40_cpu_device::op_rec() +{ + // REC: Reset Carry + m_c = 0; +} + +void hmcs40_cpu_device::op_tc() +{ + // TC: Test Carry + m_s = m_c; +} + +void hmcs40_cpu_device::op_rotl() +{ + // ROTL: Rotate Left A with Carry + m_a = m_a << 1 | m_c; + m_c = m_a >> 4 & 1; + m_a &= 0xf; +} + +void hmcs40_cpu_device::op_rotr() +{ + // ROTR: Rotate Right A with Carry + UINT8 c = m_a & 1; + m_a = m_a >> 1 | m_c << 3; + m_c = c; +} + +void hmcs40_cpu_device::op_or() +{ + // OR: OR A and B + m_a |= m_b; +} + + +// Compare Instruction + +void hmcs40_cpu_device::op_mnei() +{ + // MNEI i: Memory Not Equal to Immediate + m_s = (ram_r() != (m_i)); +} + +void hmcs40_cpu_device::op_ynei() +{ + // YNEI i: Y Not Equal to Immediate + m_s = (m_y != (m_i)); +} + +void hmcs40_cpu_device::op_anem() +{ + // ANEM: A Not Equal to Memory + m_s = (m_a != ram_r()); +} + +void hmcs40_cpu_device::op_bnem() +{ + // BNEM: B Not Equal to Memory + m_s = (m_b != ram_r()); +} + +void hmcs40_cpu_device::op_alei() +{ + // ALEI i: A Less or Equal to Immediate + m_s = (m_a <= (m_i)); +} + +void hmcs40_cpu_device::op_alem() +{ + // ALEM: A Less or Equal to Memory + m_s = (m_a <= ram_r()); +} + +void hmcs40_cpu_device::op_blem() +{ + // BLEM: B Less or Equal to Memory + m_s = (m_b <= ram_r()); +} + + +// RAM Bit Manipulation Instruction + +void hmcs40_cpu_device::op_sem() +{ + // SEM n: Set Memory Bit + ram_w(ram_r() | (1 << (m_op & 3))); +} + +void hmcs40_cpu_device::op_rem() +{ + // REM n: Reset Memory Bit + ram_w(ram_r() & ~(1 << (m_op & 3))); +} + +void hmcs40_cpu_device::op_tm() +{ + // TM n: Test Memory Bit + m_s = ram_r() >> (m_op & 3) & 1; +} + + +// ROM Address Instruction + +void hmcs40_cpu_device::op_br() +{ + // BR a: Branch on Status 1 + if (m_s) + m_pc = (m_pc & ~0x3f) | (m_op & 0x3f); + else + m_s = 1; +} + +void hmcs40_cpu_device::op_cal() +{ + // CAL a: Subroutine Jump on Status 1 + if (m_s) + { + push_stack(); + m_pc = m_op & 0x3f; // short calls default to page 0 + } + else + m_s = 1; +} + +void hmcs40_cpu_device::op_lpu() +{ + // LPU u: Load Program Counter Upper on Status 1 + if (m_s) + m_page = m_op & 0x1f; + else + m_op = 0; // fake nop +} + +void hmcs40_cpu_device::op_tbr() +{ + // TBR p: Table Branch + UINT16 address = m_a | m_b << 4 | m_c << 8 | (m_op & 7) << 9 | (m_pc & ~0x3f); + m_pc = address & m_pcmask; +} + +void hmcs40_cpu_device::op_rtn() +{ + // RTN: Return from Subroutine + pop_stack(); +} + + +// Interrupt Instruction + +void hmcs40_cpu_device::op_seie() +{ + // SEIE: Set I/E + m_ie = 1; +} + +void hmcs40_cpu_device::op_seif0() +{ + // SEIF0: Set IF0 + m_if[0] = 1; +} + +void hmcs40_cpu_device::op_seif1() +{ + // SEIF1: Set IF1 + m_if[1] = 1; +} + +void hmcs40_cpu_device::op_setf() +{ + // SETF: Set TF + m_tf = 1; +} + +void hmcs40_cpu_device::op_secf() +{ + // SECF: Set CF + m_cf = 1; +} + +void hmcs40_cpu_device::op_reie() +{ + // REIE: Reset I/E + m_ie = 0; +} + +void hmcs40_cpu_device::op_reif0() +{ + // REIF0: Reset IF0 + m_if[0] = 0; +} + +void hmcs40_cpu_device::op_reif1() +{ + // REIF1: Reset IF1 + m_if[1] = 0; +} + +void hmcs40_cpu_device::op_retf() +{ + // RETF: Reset TF + m_tf = 0; +} + +void hmcs40_cpu_device::op_recf() +{ + // RECF: Reset CF + m_cf = 0; +} + +void hmcs40_cpu_device::op_ti0() +{ + // TI0: Test INT0 + m_s = m_int[0]; +} + +void hmcs40_cpu_device::op_ti1() +{ + // TI1: Test INT1 + m_s = m_int[1]; +} + +void hmcs40_cpu_device::op_tif0() +{ + // TIF0: Test IF0 + m_s = m_if[0]; +} + +void hmcs40_cpu_device::op_tif1() +{ + // TIF1: Test IF1 + m_s = m_if[1]; +} + +void hmcs40_cpu_device::op_ttf() +{ + // TTF: Test TF + m_s = m_tf; +} + +void hmcs40_cpu_device::op_lti() +{ + // LTI i: Load Timer/Counter from Immediate + m_tc = m_i; + reset_prescaler(); +} + +void hmcs40_cpu_device::op_lta() +{ + // LTA: Load Timer/Counter from A + m_tc = m_a; + reset_prescaler(); +} + +void hmcs40_cpu_device::op_lat() +{ + // LAT: Load A from Timer/Counter + m_a = m_tc; +} + +void hmcs40_cpu_device::op_rtni() +{ + // RTNI: Return from Interrupt + op_seie(); + op_rtn(); +} + + +// Input/Output Instruction + +void hmcs40_cpu_device::op_sed() +{ + // SED: Set Discrete I/O Latch + write_d(m_y, 1); +} + +void hmcs40_cpu_device::op_red() +{ + // RED: Reset Discrete I/O Latch + write_d(m_y, 0); +} + +void hmcs40_cpu_device::op_td() +{ + // TD: Test Discrete I/O Latch + m_s = read_d(m_y); +} + +void hmcs40_cpu_device::op_sedd() +{ + // SEDD n: Set Discrete I/O Latch Direct + write_d(m_op & 0xf, 1); +} + +void hmcs40_cpu_device::op_redd() +{ + // REDD n: Reset Discrete I/O Latch Direct + write_d(m_op & 0xf, 0); +} + +void hmcs40_cpu_device::op_lar() +{ + // LAR p: Load A from R-Port Register + m_a = read_r(m_op & 7); +} + +void hmcs40_cpu_device::op_lbr() +{ + // LBR p: Load B from R-Port Register + m_b = read_r(m_op & 7); +} + +void hmcs40_cpu_device::op_lra() +{ + // LRA p: Load R-Port Register from A + write_r(m_op & 7, m_a); +} + +void hmcs40_cpu_device::op_lrb() +{ + // LRB p: Load R-Port Register from B + write_r(m_op & 7, m_b); +} + +void hmcs40_cpu_device::op_p() +{ + // P p: Pattern Generation + m_icount--; + UINT16 address = m_a | m_b << 4 | m_c << 8 | (m_op & 7) << 9 | (m_pc & ~0x3f); + UINT16 o = m_program->read_word((address & m_prgmask) << 1); + + // destination is determined by the 2 highest bits + if (o & 0x100) + { + // B3 B2 B1 B0 A0 A1 A2 A3 + m_a = BITSWAP8(o,7,6,5,4,0,1,2,3) & 0xf; + m_b = o >> 4 & 0xf; + } + if (o & 0x200) + { + // R20 R21 R22 R23 R30 R31 R32 R33 + o = BITSWAP8(o,0,1,2,3,4,5,6,7); + write_r(2, o & 0xf); + write_r(3, o >> 4 & 0xf); + } +} diff --git a/src/devices/cpu/hphybrid/hphybrid.c b/src/devices/cpu/hphybrid/hphybrid.c new file mode 100644 index 00000000000..027a37e03ed --- /dev/null +++ b/src/devices/cpu/hphybrid/hphybrid.c @@ -0,0 +1,961 @@ +// license:BSD-3-Clause +// copyright-holders:F. Ulivi + +#include "emu.h" +#include "debugger.h" +#include "hphybrid.h" + +enum { + HPHYBRID_A, + HPHYBRID_B, + HPHYBRID_C, + HPHYBRID_D, + HPHYBRID_P, + HPHYBRID_R, + HPHYBRID_IV, + HPHYBRID_PA, + HPHYBRID_DMAPA, + HPHYBRID_DMAMA, + HPHYBRID_DMAC, + HPHYBRID_I +}; + +#define BIT_MASK(n) (1U << (n)) + +// Macros to clear/set single bits +#define BIT_CLR(w , n) ((w) &= ~BIT_MASK(n)) +#define BIT_SET(w , n) ((w) |= BIT_MASK(n)) + +// Bits in m_flags +#define HPHYBRID_C_BIT 0 // Carry/extend +#define HPHYBRID_O_BIT 1 // Overflow +#define HPHYBRID_CB_BIT 2 // Cb +#define HPHYBRID_DB_BIT 3 // Db +#define HPHYBRID_INTEN_BIT 4 // Interrupt enable +#define HPHYBRID_DMAEN_BIT 5 // DMA enable +#define HPHYBRID_DMADIR_BIT 6 // DMA direction (1 = OUT) +#define HPHYBRID_HALT_BIT 7 // Halt flag +#define HPHYBRID_IRH_BIT 8 // IRH requested +#define HPHYBRID_IRL_BIT 9 // IRL requested +#define HPHYBRID_IRH_SVC_BIT 10 // IRH in service +#define HPHYBRID_IRL_SVC_BIT 11 // IRL in service +#define HPHYBRID_DMAR_BIT 12 // DMA request + +#define HPHYBRID_IV_MASK 0xfff0 // IV mask + +#define CURRENT_PA (m_reg_PA[ 0 ]) + +#define HP_RESET_ADDR 0x0020 + +const device_type HP_5061_3011 = &device_creator; + +WRITE_LINE_MEMBER(hp_hybrid_cpu_device::dmar_w) +{ + if (state) { + BIT_SET(m_flags , HPHYBRID_DMAR_BIT); + } else { + BIT_CLR(m_flags , HPHYBRID_DMAR_BIT); + } +} + +hp_hybrid_cpu_device::hp_hybrid_cpu_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname) +: cpu_device(mconfig, type, name, tag, owner, clock, shortname, __FILE__), + m_program_config("program", ENDIANNESS_BIG, 16, 16, -1), + m_io_config("io", ENDIANNESS_BIG, 16, 6, -1) +{ +} + +void hp_hybrid_cpu_device::device_start() +{ + m_reg_A = 0; + m_reg_B = 0; + m_reg_P = HP_RESET_ADDR; + m_reg_R = 0; + m_reg_C = 0; + m_reg_D = 0; + m_reg_IV = 0; + m_reg_PA[ 0 ] = 0; + m_reg_PA[ 1 ] = 0; + m_reg_PA[ 2 ] = 0; + m_flags = 0; + m_dmapa = 0; + m_dmama = 0; + m_dmac = 0; + m_reg_I = 0; + + { + state_add(HPHYBRID_A, "A", m_reg_A); + state_add(HPHYBRID_B, "B", m_reg_B); + state_add(HPHYBRID_C, "C", m_reg_C); + state_add(HPHYBRID_D, "D", m_reg_D); + state_add(HPHYBRID_P, "P", m_reg_P); + state_add(STATE_GENPC, "GENPC", m_reg_P).noshow(); + state_add(HPHYBRID_R, "R", m_reg_R); + state_add(STATE_GENSP, "GENSP", m_reg_R).noshow(); + state_add(HPHYBRID_IV, "IV", m_reg_IV); + state_add(HPHYBRID_PA, "PA", m_reg_PA[ 0 ]); + state_add(STATE_GENFLAGS, "GENFLAGS", m_flags).noshow().formatstr("%9s"); + state_add(HPHYBRID_DMAPA , "DMAPA" , m_dmapa).noshow(); + state_add(HPHYBRID_DMAMA , "DMAMA" , m_dmama).noshow(); + state_add(HPHYBRID_DMAC , "DMAC" , m_dmac).noshow(); + state_add(HPHYBRID_I , "I" , m_reg_I).noshow(); + } + + m_program = &space(AS_PROGRAM); + m_direct = &m_program->direct(); + m_io = &space(AS_IO); + + save_item(NAME(m_reg_A)); + save_item(NAME(m_reg_B)); + save_item(NAME(m_reg_C)); + save_item(NAME(m_reg_D)); + save_item(NAME(m_reg_P)); + save_item(NAME(m_reg_R)); + save_item(NAME(m_reg_IV)); + save_item(NAME(m_reg_PA[0])); + save_item(NAME(m_reg_PA[1])); + save_item(NAME(m_reg_PA[2])); + save_item(NAME(m_flags)); + save_item(NAME(m_dmapa)); + save_item(NAME(m_dmama)); + save_item(NAME(m_dmac)); + save_item(NAME(m_reg_I)); + + m_icountptr = &m_icount; +} + +void hp_hybrid_cpu_device::device_reset() +{ + m_reg_P = HP_RESET_ADDR; + m_reg_I = RM(m_reg_P); + m_flags = 0; +} + +void hp_hybrid_cpu_device::execute_run() +{ + do { + if (BIT(m_flags , HPHYBRID_DMAEN_BIT) && BIT(m_flags , HPHYBRID_DMAR_BIT)) { + handle_dma(); + } else { + debugger_instruction_hook(this, m_reg_P); + + // Check for interrupts + check_for_interrupts(); + + m_reg_I = execute_one(m_reg_I); + } + } while (m_icount > 0); +} + +void hp_hybrid_cpu_device::execute_set_input(int inputnum, int state) +{ + if (inputnum < HPHYBRID_INT_LVLS) { + if (state) { + BIT_SET(m_flags , HPHYBRID_IRH_BIT + inputnum); + } else { + BIT_CLR(m_flags , HPHYBRID_IRH_BIT + inputnum); + } + } +} + +/** + * Execute 1 instruction + * + * @param opcode Opcode to be executed + * + * @return Next opcode to be executed + */ +UINT16 hp_hybrid_cpu_device::execute_one(UINT16 opcode) +{ + if ((opcode & 0x7fe0) == 0x7000) { + // EXE + m_icount -= 8; + return RM(opcode & 0x1f); + } else { + m_reg_P = execute_one_sub(opcode); + return RM(m_reg_P); + } +} + +/** + * Execute 1 instruction (except EXE) + * + * @param opcode Opcode to be executed (no EXE instructions) + * + * @return new value of P register + */ +UINT16 hp_hybrid_cpu_device::execute_one_sub(UINT16 opcode) +{ + UINT16 ea; + UINT16 tmp; + + switch (opcode & 0x7800) { + case 0x0000: + // LDA + m_icount -= 13; + m_reg_A = RM(get_ea(opcode)); + break; + + case 0x0800: + // LDB + m_icount -= 13; + m_reg_B = RM(get_ea(opcode)); + break; + + case 0x1000: + // CPA + m_icount -= 16; + if (m_reg_A != RM(get_ea(opcode))) { + // Skip next instruction + return m_reg_P + 2; + } + break; + + case 0x1800: + // CPB + m_icount -= 16; + if (m_reg_B != RM(get_ea(opcode))) { + // Skip next instruction + return m_reg_P + 2; + } + break; + + case 0x2000: + // ADA + m_icount -= 13; + do_add(m_reg_A , RM(get_ea(opcode))); + break; + + case 0x2800: + // ADB + m_icount -= 13; + do_add(m_reg_B , RM(get_ea(opcode))); + break; + + case 0x3000: + // STA + m_icount -= 13; + WM(get_ea(opcode) , m_reg_A); + break; + + case 0x3800: + // STB + m_icount -= 13; + WM(get_ea(opcode) , m_reg_B); + break; + + case 0x4000: + // JSM + m_icount -= 17; + WM(++m_reg_R , m_reg_P); + return get_ea(opcode); + + case 0x4800: + // ISZ + m_icount -= 19; + ea = get_ea(opcode); + tmp = RM(ea) + 1; + WM(ea , tmp); + if (tmp == 0) { + // Skip next instruction + return m_reg_P + 2; + } + break; + + case 0x5000: + // AND + m_icount -= 13; + m_reg_A &= RM(get_ea(opcode)); + break; + + case 0x5800: + // DSZ + m_icount -= 19; + ea = get_ea(opcode); + tmp = RM(ea) - 1; + WM(ea , tmp); + if (tmp == 0) { + // Skip next instruction + return m_reg_P + 2; + } + break; + + case 0x6000: + // IOR + m_icount -= 13; + m_reg_A |= RM(get_ea(opcode)); + break; + + case 0x6800: + // JMP + m_icount -= 8; + return get_ea(opcode); + + default: + switch (opcode & 0xfec0) { + case 0x7400: + // RZA + // SZA + m_icount -= 14; + return get_skip_addr(opcode , m_reg_A == 0); + + case 0x7440: + // RIA + // SIA + m_icount -= 14; + return get_skip_addr(opcode , m_reg_A++ == 0); + + case 0x7480: + // SFS + // SFC + m_icount -= 14; + // TODO: read flag bit + return get_skip_addr(opcode , true); + + case 0x7C00: + // RZB + // SZB + m_icount -= 14; + return get_skip_addr(opcode , m_reg_B == 0); + + case 0x7C40: + // RIB + // SIB + m_icount -= 14; + return get_skip_addr(opcode , m_reg_B++ == 0); + + case 0x7c80: + // SSS + // SSC + m_icount -= 14; + // TODO: read status bit + return get_skip_addr(opcode , true); + + case 0x7cc0: + // SHS + // SHC + m_icount -= 14; + return get_skip_addr(opcode , !BIT(m_flags , HPHYBRID_HALT_BIT)); + + default: + switch (opcode & 0xfe00) { + case 0x7600: + // SLA + // RLA + m_icount -= 14; + return get_skip_addr_sc(opcode , m_reg_A , 0); + + case 0x7e00: + // SLB + // RLB + m_icount -= 14; + return get_skip_addr_sc(opcode , m_reg_B , 0); + + case 0xf400: + // SAP + // SAM + m_icount -= 14; + return get_skip_addr_sc(opcode , m_reg_A , 15); + + case 0xf600: + // SOC + // SOS + m_icount -= 14; + return get_skip_addr_sc(opcode , m_flags , HPHYBRID_O_BIT); + + case 0xfc00: + // SBP + // SBM + m_icount -= 14; + return get_skip_addr_sc(opcode , m_reg_B , 15); + + case 0xfe00: + // SEC + // SES + m_icount -= 14; + return get_skip_addr_sc(opcode , m_flags , HPHYBRID_C_BIT); + + default: + switch (opcode & 0xfff0) { + case 0xf100: + // AAR + tmp = (opcode & 0xf) + 1; + m_icount -= (9 + tmp); + // A shift by 16 positions is equivalent to a shift by 15 + tmp = tmp > 15 ? 15 : tmp; + m_reg_A = ((m_reg_A ^ 0x8000) >> tmp) - (0x8000 >> tmp); + break; + + case 0xf900: + // ABR + tmp = (opcode & 0xf) + 1; + m_icount -= (9 + tmp); + tmp = tmp > 15 ? 15 : tmp; + m_reg_B = ((m_reg_B ^ 0x8000) >> tmp) - (0x8000 >> tmp); + break; + + case 0xf140: + // SAR + tmp = (opcode & 0xf) + 1; + m_icount -= (9 + tmp); + m_reg_A >>= tmp; + break; + + case 0xf940: + // SBR + tmp = (opcode & 0xf) + 1; + m_icount -= (9 + tmp); + m_reg_B >>= tmp; + break; + + case 0xf180: + // SAL + tmp = (opcode & 0xf) + 1; + m_icount -= (9 + tmp); + m_reg_A <<= tmp; + break; + + case 0xf980: + // SBL + tmp = (opcode & 0xf) + 1; + m_icount -= (9 + tmp); + m_reg_B <<= tmp; + break; + + case 0xf1c0: + // RAR + tmp = (opcode & 0xf) + 1; + m_icount -= (9 + tmp); + m_reg_A = (m_reg_A >> tmp) | (m_reg_A << (16 - tmp)); + break; + + case 0xf9c0: + // RBR + tmp = (opcode & 0xf) + 1; + m_icount -= (9 + tmp); + m_reg_B = (m_reg_B >> tmp) | (m_reg_B << (16 - tmp)); + break; + + default: + if ((opcode & 0xf760) == 0x7160) { + // Place/withdraw instructions + m_icount -= 23; + do_pw(opcode); + } else if ((opcode & 0xff80) == 0xf080) { + // RET + m_icount -= 16; + if (BIT(opcode , 6)) { + // Pop PA stack + if (BIT(m_flags , HPHYBRID_IRH_SVC_BIT)) { + BIT_CLR(m_flags , HPHYBRID_IRH_SVC_BIT); + memmove(&m_reg_PA[ 0 ] , &m_reg_PA[ 1 ] , HPHYBRID_INT_LVLS); + } else if (BIT(m_flags , HPHYBRID_IRL_SVC_BIT)) { + BIT_CLR(m_flags , HPHYBRID_IRL_SVC_BIT); + memmove(&m_reg_PA[ 0 ] , &m_reg_PA[ 1 ] , HPHYBRID_INT_LVLS); + } + } + tmp = RM(m_reg_R--) + (opcode & 0x1f); + return BIT(opcode , 5) ? tmp - 0x20 : tmp; + } else { + switch (opcode) { + case 0x7100: + // SDO + m_icount -= 12; + BIT_SET(m_flags , HPHYBRID_DMADIR_BIT); + break; + + case 0x7108: + // SDI + m_icount -= 12; + BIT_CLR(m_flags , HPHYBRID_DMADIR_BIT); + break; + + case 0x7110: + // EIR + m_icount -= 12; + BIT_SET(m_flags , HPHYBRID_INTEN_BIT); + break; + + case 0x7118: + // DIR + m_icount -= 12; + BIT_CLR(m_flags , HPHYBRID_INTEN_BIT); + break; + + case 0x7120: + // DMA + m_icount -= 12; + BIT_SET(m_flags , HPHYBRID_DMAEN_BIT); + break; + + case 0x7138: + // DDR + m_icount -= 12; + BIT_CLR(m_flags , HPHYBRID_DMAEN_BIT); + break; + + case 0x7140: + // DBL + m_icount -= 12; + BIT_CLR(m_flags , HPHYBRID_DB_BIT); + break; + + case 0x7148: + // CBL + m_icount -= 12; + BIT_CLR(m_flags , HPHYBRID_CB_BIT); + break; + + case 0x7150: + // DBU + m_icount -= 12; + BIT_SET(m_flags , HPHYBRID_DB_BIT); + break; + + case 0x7158: + // CBU + m_icount -= 12; + BIT_SET(m_flags , HPHYBRID_CB_BIT); + break; + + case 0xf020: + // TCA + m_icount -= 9; + m_reg_A = ~m_reg_A; + do_add(m_reg_A , 1); + break; + + case 0xf060: + // CMA + m_icount -= 9; + m_reg_A = ~m_reg_A; + break; + + case 0xf820: + // TCB + m_icount -= 9; + m_reg_B = ~m_reg_B; + do_add(m_reg_B , 1); + break; + + case 0xf860: + // CMB + m_icount -= 9; + m_reg_B = ~m_reg_B; + break; + + default: + // Unrecognized instructions: NOP + // Execution time is fictional + m_icount -= 6; + } + } + } + } + } + } + + return m_reg_P + 1; +} + +void hp_hybrid_cpu_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + if (entry.index() == STATE_GENFLAGS) { + strprintf(str, "%s %s %c %c", + BIT(m_flags , HPHYBRID_DB_BIT) ? "Db":"..", + BIT(m_flags , HPHYBRID_CB_BIT) ? "Cb":"..", + BIT(m_flags , HPHYBRID_O_BIT) ? 'O':'.', + BIT(m_flags , HPHYBRID_C_BIT) ? 'E':'.'); + } +} + +offs_t hp_hybrid_cpu_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE(hp_hybrid); + return CPU_DISASSEMBLE_NAME(hp_hybrid)(this, buffer, pc, oprom, opram, options); +} + +UINT16 hp_hybrid_cpu_device::get_ea(UINT16 opcode) +{ + UINT16 base; + UINT16 off; + + if (BIT(opcode , 10)) { + // Current page + base = m_reg_P; + } else { + // Base page + base = 0; + } + + off = opcode & 0x3ff; + if (off & 0x200) { + off -= 0x400; + } + + base += off; + + if (BIT(opcode , 15)) { + // Indirect addressing + m_icount -= 6; + return RM(base); + } else { + // Direct addressing + return base; + } +} + +void hp_hybrid_cpu_device::do_add(UINT16& addend1 , UINT16 addend2) +{ + UINT32 tmp = addend1 + addend2; + + if (BIT(tmp , 16)) { + // Carry + BIT_SET(m_flags , HPHYBRID_C_BIT); + } + + if (BIT((tmp ^ addend1) & (tmp ^ addend2) , 15)) { + // Overflow + BIT_SET(m_flags , HPHYBRID_O_BIT); + } + + addend1 = (UINT16)tmp; +} + +UINT16 hp_hybrid_cpu_device::get_skip_addr(UINT16 opcode , bool condition) const +{ + bool skip_val = BIT(opcode , 8) != 0; + + if (condition == skip_val) { + UINT16 off = opcode & 0x1f; + + if (BIT(opcode , 5)) { + off -= 0x20; + } + return m_reg_P + off; + } else { + return m_reg_P + 1; + } +} + +UINT16 hp_hybrid_cpu_device::get_skip_addr_sc(UINT16 opcode , UINT16& v , unsigned n) +{ + bool val = BIT(v , n); + + if (BIT(opcode , 7)) { + if (BIT(opcode , 6)) { + BIT_SET(v , n); + } else { + BIT_CLR(v , n); + } + } + + return get_skip_addr(opcode , val); +} + +void hp_hybrid_cpu_device::do_pw(UINT16 opcode) +{ + UINT16 tmp; + UINT16 reg_addr = opcode & 7; + UINT16 *ptr_reg; + UINT16 b_mask; + + if (BIT(opcode , 3)) { + ptr_reg = &m_reg_D; + b_mask = BIT_MASK(HPHYBRID_DB_BIT); + } else { + ptr_reg = &m_reg_C; + b_mask = BIT_MASK(HPHYBRID_CB_BIT); + } + + if (BIT(opcode , 4)) { + // Withdraw + if (BIT(opcode , 11)) { + // Byte + UINT32 tmp_addr = (UINT32)(*ptr_reg); + if (m_flags & b_mask) { + tmp_addr |= 0x10000; + } + tmp = RM((UINT16)(tmp_addr >> 1)); + if (BIT(tmp_addr , 0)) { + tmp &= 0xff; + } else { + tmp >>= 8; + } + } else { + // Word + tmp = RM(*ptr_reg); + } + WM(reg_addr , tmp); + + if (BIT(opcode , 7)) { + // Post-decrement + if ((*ptr_reg)-- == 0) { + m_flags ^= b_mask; + } + } else { + // Post-increment + if (++(*ptr_reg) == 0) { + m_flags ^= b_mask; + } + } + } else { + // Place + if (BIT(opcode , 7)) { + // Pre-decrement + if ((*ptr_reg)-- == 0) { + m_flags ^= b_mask; + } + } else { + // Pre-increment + if (++(*ptr_reg) == 0) { + m_flags ^= b_mask; + } + } + tmp = RM(reg_addr); + if (BIT(opcode , 11)) { + // Byte + UINT32 tmp_addr = (UINT32)(*ptr_reg); + if (m_flags & b_mask) { + tmp_addr |= 0x10000; + } + WMB(tmp_addr , (UINT8)tmp); + } else { + // Word + WM(*ptr_reg , tmp); + } + } +} + +void hp_hybrid_cpu_device::check_for_interrupts(void) +{ + if (!BIT(m_flags , HPHYBRID_INTEN_BIT) || BIT(m_flags , HPHYBRID_IRH_SVC_BIT)) { + return; + } + + int irqline; + + if (BIT(m_flags , HPHYBRID_IRH_BIT)) { + // Service high-level interrupt + BIT_SET(m_flags , HPHYBRID_IRH_SVC_BIT); + irqline = HPHYBRID_IRH; + } else if (BIT(m_flags , HPHYBRID_IRL_BIT) && !BIT(m_flags , HPHYBRID_IRL_SVC_BIT)) { + // Service low-level interrupt + BIT_SET(m_flags , HPHYBRID_IRL_SVC_BIT); + irqline = HPHYBRID_IRL; + } else { + return; + } + + // Get interrupt vector in low byte + UINT8 vector = (UINT8)standard_irq_callback(irqline); + UINT8 new_PA; + + // Get highest numbered 1 + // Don't know what happens if vector is 0, here we assume bit 7 = 1 + if (vector == 0) { + new_PA = 7; + } else { + for (new_PA = 7; new_PA && !BIT(vector , 7); new_PA--, vector <<= 1) { + } + } + if (irqline == HPHYBRID_IRH) { + BIT_SET(new_PA , 3); + } + + // Push PA stack + memmove(&m_reg_PA[ 1 ] , &m_reg_PA[ 0 ] , HPHYBRID_INT_LVLS); + + CURRENT_PA = new_PA; + + // Is this correct? Patent @ pg 210 suggests that the whole interrupt recognition sequence + // lasts for 32 cycles (6 are already accounted for in get_ea for one indirection) + m_icount -= 26; + + // Do a double-indirect JSM IV,I instruction + WM(++m_reg_R , m_reg_P); + m_reg_P = RM(get_ea(0xc008)); + m_reg_I = RM(m_reg_P); +} + +void hp_hybrid_cpu_device::handle_dma(void) +{ + // Patent hints at the fact that terminal count is detected by bit 15 of dmac being 1 after decrementing + bool tc = BIT(--m_dmac , 15) != 0; + UINT16 tmp; + + if (BIT(m_flags , HPHYBRID_DMADIR_BIT)) { + // "Outward" DMA: memory -> peripheral + tmp = RM(m_dmama++); + WIO(m_dmapa , tc ? 2 : 0 , tmp); + m_icount -= 10; + } else { + // "Inward" DMA: peripheral -> memory + tmp = RIO(m_dmapa , tc ? 2 : 0); + WM(m_dmama++ , tmp); + m_icount -= 9; + } + + // This is the one of the biggest question marks: is the DMA automatically disabled on TC? + // Here we assume it is. After all it would make no difference because there is no way + // to read the DMA enable flag back, so each time the DMA is needed it has to be enabled again. + if (tc) { + BIT_CLR(m_flags , HPHYBRID_DMAEN_BIT); + } +} + +UINT16 hp_hybrid_cpu_device::RM(UINT16 addr) +{ + UINT16 tmp; + + if (addr <= HP_REG_LAST_ADDR) { + // Memory mapped registers + switch (addr) { + case HP_REG_A_ADDR: + return m_reg_A; + + case HP_REG_B_ADDR: + return m_reg_B; + + case HP_REG_P_ADDR: + return m_reg_P; + + case HP_REG_R_ADDR: + return m_reg_R; + + case HP_REG_R4_ADDR: + case HP_REG_R5_ADDR: + case HP_REG_R6_ADDR: + case HP_REG_R7_ADDR: + return RIO(CURRENT_PA , addr - HP_REG_R4_ADDR); + + case HP_REG_IV_ADDR: + // Correct? + if (!BIT(m_flags , HPHYBRID_IRH_SVC_BIT) && !BIT(m_flags , HPHYBRID_IRL_SVC_BIT)) { + return m_reg_IV; + } else { + return m_reg_IV | CURRENT_PA; + } + + case HP_REG_PA_ADDR: + return CURRENT_PA; + + case HP_REG_DMAPA_ADDR: + tmp = m_dmapa & HP_REG_PA_MASK; + if (BIT(m_flags , HPHYBRID_CB_BIT)) { + BIT_SET(tmp , 15); + } + if (BIT(m_flags , HPHYBRID_DB_BIT)) { + BIT_SET(tmp , 14); + } + return tmp; + + case HP_REG_DMAMA_ADDR: + return m_dmama; + + case HP_REG_DMAC_ADDR: + return m_dmac; + + case HP_REG_C_ADDR: + return m_reg_C; + + case HP_REG_D_ADDR: + return m_reg_D; + + default: + // Unknown registers are returned as 0 + return 0; + } + } else { + return m_direct->read_word((offs_t)addr << 1); + } +} + +void hp_hybrid_cpu_device::WM(UINT16 addr , UINT16 v) +{ + if (addr <= HP_REG_LAST_ADDR) { + // Memory mapped registers + switch (addr) { + case HP_REG_A_ADDR: + m_reg_A = v; + break; + + case HP_REG_B_ADDR: + m_reg_B = v; + break; + + case HP_REG_P_ADDR: + m_reg_P = v; + break; + + case HP_REG_R_ADDR: + m_reg_R = v; + break; + + case HP_REG_R4_ADDR: + case HP_REG_R5_ADDR: + case HP_REG_R6_ADDR: + case HP_REG_R7_ADDR: + WIO(CURRENT_PA , addr - HP_REG_R4_ADDR , v); + break; + + case HP_REG_IV_ADDR: + m_reg_IV = v & HP_REG_IV_MASK; + break; + + case HP_REG_PA_ADDR: + CURRENT_PA = v & HP_REG_PA_MASK; + break; + + case HP_REG_DMAPA_ADDR: + m_dmapa = v & HP_REG_PA_MASK; + break; + + case HP_REG_DMAMA_ADDR: + m_dmama = v; + break; + + case HP_REG_DMAC_ADDR: + m_dmac = v; + break; + + case HP_REG_C_ADDR: + m_reg_C = v; + break; + + case HP_REG_D_ADDR: + m_reg_D = v; + break; + + default: + // Unknown registers are silently discarded + break; + } + } else { + m_program->write_word((offs_t)addr << 1 , v); + } +} + +void hp_hybrid_cpu_device::WMB(UINT32 addr , UINT8 v) +{ + if (addr <= (HP_REG_LAST_ADDR * 2 + 1)) { + // Cannot write bytes to registers + } else { + m_program->write_byte(addr , v); + } +} + +UINT16 hp_hybrid_cpu_device::RIO(UINT8 pa , UINT8 ic) +{ + return m_io->read_word(HP_MAKE_IOADDR(pa, ic) << 1); +} + +void hp_hybrid_cpu_device::WIO(UINT8 pa , UINT8 ic , UINT16 v) +{ + m_io->write_word(HP_MAKE_IOADDR(pa, ic) << 1 , v); +} + +hp_5061_3011_cpu_device::hp_5061_3011_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) +: hp_hybrid_cpu_device(mconfig, HP_5061_3011, "HP_5061_3011", tag, owner, clock, "5061-3011") +{ +} diff --git a/src/devices/cpu/hphybrid/hphybrid.h b/src/devices/cpu/hphybrid/hphybrid.h new file mode 100644 index 00000000000..7683cce28b6 --- /dev/null +++ b/src/devices/cpu/hphybrid/hphybrid.h @@ -0,0 +1,146 @@ +// license:BSD-3-Clause +// copyright-holders:F. Ulivi +// +// ***************************************** +// Emulator for HP "hybrid" processor series +// ***************************************** +// +// The HP hybrid processor series is composed of a few different models with different +// capabilities. The series was derived from HP's own 2116 processor by translating a +// discrete implementation of the 1960s into a multi-chip module (hence the "hybrid" name). +// This emulator currently supports the 5061-3011 version only. +// +// For this emulator I mainly relied on these sources: +// - http://www.hp9845.net/ website +// - HP manual "Assembly development ROM manual for the HP9845": this is the most precious +// and "enabling" resource of all +// - US Patent 4,180,854 describing the HP9845 system +// - Study of disassembly of firmware of HP64000 system +// - A lot of "educated" guessing + +#ifndef _HPHYBRID_H_ +#define _HPHYBRID_H_ + +// Input lines +#define HPHYBRID_IRH 0 // High-level interrupt +#define HPHYBRID_IRL 1 // Low-level interrupt +#define HPHYBRID_INT_LVLS 2 // Levels of interrupt + +#define HPHYBRID_DMAR 2 // DMA request +#define HPHYBRID_HALT 3 // "Halt" input +#define HPHYBRID_STS 4 // "Status" input +#define HPHYBRID_FLG 5 // "Flag" input + +// I/O addressing space (16-bit wide) +// Addresses into this space are composed as follows: +// b[5..2] = Peripheral address 0..15 +// b[1..0] = Register address (IC) 0..3 +#define HP_IOADDR_PA_SHIFT 2 +#define HP_IOADDR_IC_SHIFT 0 + +// Compose an I/O address from PA & IC +#define HP_MAKE_IOADDR(pa , ic) (((pa) << HP_IOADDR_PA_SHIFT) | ((ic) << HP_IOADDR_IC_SHIFT)) + +// Addresses of memory mapped registers +#define HP_REG_A_ADDR 0x0000 +#define HP_REG_B_ADDR 0x0001 +#define HP_REG_P_ADDR 0x0002 +#define HP_REG_R_ADDR 0x0003 +#define HP_REG_R4_ADDR 0x0004 +#define HP_REG_R5_ADDR 0x0005 +#define HP_REG_R6_ADDR 0x0006 +#define HP_REG_R7_ADDR 0x0007 +#define HP_REG_IV_ADDR 0x0008 +#define HP_REG_PA_ADDR 0x0009 +#define HP_REG_DMAPA_ADDR 0x000B +#define HP_REG_DMAMA_ADDR 0x000C +#define HP_REG_DMAC_ADDR 0x000D +#define HP_REG_C_ADDR 0x000e +#define HP_REG_D_ADDR 0x000f +#define HP_REG_LAST_ADDR 0x001f + +#define HP_REG_IV_MASK 0xfff0 +#define HP_REG_PA_MASK 0x000f + +class hp_hybrid_cpu_device : public cpu_device +{ +public: + DECLARE_WRITE_LINE_MEMBER(dmar_w); + +protected: + hp_hybrid_cpu_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_execute_interface overrides + virtual UINT32 execute_min_cycles() const { return 6; } + virtual UINT32 execute_max_cycles() const { return 25; } + virtual UINT32 execute_input_lines() const { return 2; } + virtual UINT32 execute_default_irq_vector() const { return 0xffff; } + virtual void execute_run(); + virtual void execute_set_input(int inputnum, int state); + + UINT16 execute_one(UINT16 opcode); + UINT16 execute_one_sub(UINT16 opcode); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const { return (spacenum == AS_PROGRAM) ? &m_program_config : ( (spacenum == AS_IO) ? &m_io_config : NULL ); } + + // device_state_interface overrides + void state_string_export(const device_state_entry &entry, std::string &str); + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const { return 2; } + virtual UINT32 disasm_max_opcode_bytes() const { return 2; } + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + +private: + address_space_config m_program_config; + address_space_config m_io_config; + + address_space *m_program; + direct_read_data *m_direct; + address_space *m_io; + int m_icount; + + // State of processor + UINT16 m_reg_A; // Register A + UINT16 m_reg_B; // Register B + UINT16 m_reg_P; // Register P + UINT16 m_reg_R; // Register R + UINT16 m_reg_C; // Register C + UINT16 m_reg_D; // Register D + UINT16 m_reg_IV; // Register IV + UINT8 m_reg_PA[ HPHYBRID_INT_LVLS + 1 ]; // Stack of register PA (4 bit-long) + UINT16 m_flags; // Flags (carry, overflow, cb, db, int en, dma en, dma dir) + UINT8 m_dmapa; // DMA peripheral address (4 bits) + UINT16 m_dmama; // DMA address + UINT16 m_dmac; // DMA counter + UINT16 m_reg_I; // Instruction register + + UINT16 get_ea(UINT16 opcode); + void do_add(UINT16& addend1 , UINT16 addend2); + UINT16 get_skip_addr(UINT16 opcode , bool condition) const; + UINT16 get_skip_addr_sc(UINT16 opcode , UINT16& v , unsigned n); + void do_pw(UINT16 opcode); + void check_for_interrupts(void); + void handle_dma(void); + + UINT16 RM(UINT16 addr); + void WM(UINT16 addr , UINT16 v); + void WMB(UINT32 addr , UINT8 v); + UINT16 RIO(UINT8 pa , UINT8 ic); + void WIO(UINT8 pa , UINT8 ic , UINT16 v); +}; + +class hp_5061_3011_cpu_device : public hp_hybrid_cpu_device +{ +public: + hp_5061_3011_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +extern const device_type HP_5061_3011; + +#endif /* _HPHYBRID_H_ */ diff --git a/src/devices/cpu/hphybrid/hphybrid_dasm.c b/src/devices/cpu/hphybrid/hphybrid_dasm.c new file mode 100644 index 00000000000..e9eddf49a96 --- /dev/null +++ b/src/devices/cpu/hphybrid/hphybrid_dasm.c @@ -0,0 +1,281 @@ +// license:BSD-3-Clause +// copyright-holders:F. Ulivi +// ******************************************************************************** +// * HP "hybrid" processor disassembler +// ******************************************************************************** + +#include "emu.h" +#include "debugger.h" +#include "hphybrid.h" + +typedef void (*fn_dis_param)(char *buffer , offs_t pc , UINT16 opcode); + +typedef struct { + UINT16 m_op_mask; + UINT16 m_opcode; + const char *m_mnemonic; + fn_dis_param m_param_fn; + UINT32 m_dasm_flags; +} dis_entry_t; + +static void addr_2_str(char *buffer , UINT16 addr , bool indirect) +{ + char *s = buffer + strlen(buffer); + + s += sprintf(s , "$%04x" , addr); + + switch (addr) { + case HP_REG_A_ADDR: + strcpy(s , "(A)"); + break; + + case HP_REG_B_ADDR: + strcpy(s , "(B)"); + break; + + case HP_REG_P_ADDR: + strcpy(s , "(P)"); + break; + + case HP_REG_R_ADDR: + strcpy(s , "(R)"); + break; + + case HP_REG_R4_ADDR: + strcpy(s , "(R4)"); + break; + + case HP_REG_R5_ADDR: + strcpy(s , "(R5)"); + break; + + case HP_REG_R6_ADDR: + strcpy(s , "(R6)"); + break; + + case HP_REG_R7_ADDR: + strcpy(s , "(R7)"); + break; + + case HP_REG_IV_ADDR: + strcpy(s , "(IV)"); + break; + + case HP_REG_PA_ADDR: + strcpy(s , "(PA)"); + break; + + case HP_REG_DMAPA_ADDR: + strcpy(s , "(DMAPA)"); + break; + + case HP_REG_DMAMA_ADDR: + strcpy(s , "(DMAMA)"); + break; + + case HP_REG_DMAC_ADDR: + strcpy(s , "(DMAC)"); + break; + + case HP_REG_C_ADDR: + strcpy(s , "(C)"); + break; + + case HP_REG_D_ADDR: + strcpy(s , "(D)"); + break; + } + + if (indirect) { + strcat(s , ",I"); + } +} + +static void param_none(char *buffer , offs_t pc , UINT16 opcode) +{ +} + +static void param_loc(char *buffer , offs_t pc , UINT16 opcode) +{ + UINT16 base; + UINT16 off; + + if (opcode & 0x0400) { + // Current page + base = pc; + } else { + // Base page + base = 0; + } + + off = opcode & 0x3ff; + if (off & 0x200) { + off -= 0x400; + } + + addr_2_str(buffer , base + off , (opcode & 0x8000) != 0); +} + +static void param_addr32(char *buffer , offs_t pc , UINT16 opcode) +{ + addr_2_str(buffer , opcode & 0x1f , (opcode & 0x8000) != 0); +} + +static void param_skip(char *buffer , offs_t pc , UINT16 opcode) +{ + UINT16 off = opcode & 0x3f; + if (off & 0x20) { + off -= 0x40; + } + addr_2_str(buffer , pc + off , false); +} + +static void param_skip_sc(char *buffer , offs_t pc , UINT16 opcode) +{ + param_skip(buffer, pc, opcode); + + if (opcode & 0x80) { + if (opcode & 0x40) { + strcat(buffer , ",S"); + } else { + strcat(buffer , ",C"); + } + } +} + +static void param_ret(char *buffer , offs_t pc , UINT16 opcode) +{ + char *s = buffer + strlen(buffer); + + int off = opcode & 0x3f; + + if (off & 0x20) { + off -= 0x40; + } + + s += sprintf(s , "%d" , off); + if (opcode & 0x40) { + strcpy(s , ",P"); + } +} + +static void param_n16(char *buffer , offs_t pc , UINT16 opcode) +{ + char *s = buffer + strlen(buffer); + + sprintf(s , "%u" , (opcode & 0xf) + 1); +} + +static void param_reg_id(char *buffer , offs_t pc , UINT16 opcode) +{ + addr_2_str(buffer, opcode & 7, false); + + if (opcode & 0x80) { + strcat(buffer , ",D"); + } else { + strcat(buffer , ",I"); + } +} + +static const dis_entry_t dis_table[] = { + // *** BPC Instructions *** + {0xffff , 0x0000 , "NOP" , param_none , 0 }, + {0x7800 , 0x0000 , "LDA" , param_loc , 0 }, + {0x7800 , 0x0800 , "LDB" , param_loc , 0 }, + {0x7800 , 0x1000 , "CPA" , param_loc , 0 }, + {0x7800 , 0x1800 , "CPB" , param_loc , 0 }, + {0x7800 , 0x2000 , "ADA" , param_loc , 0 }, + {0x7800 , 0x2800 , "ADB" , param_loc , 0 }, + {0x7800 , 0x3000 , "STA" , param_loc , 0 }, + {0x7800 , 0x3800 , "STB" , param_loc , 0 }, + {0x7800 , 0x4000 , "JSM" , param_loc , DASMFLAG_STEP_OVER }, + {0x7800 , 0x4800 , "ISZ" , param_loc , 0 }, + {0x7800 , 0x5000 , "AND" , param_loc , 0 }, + {0x7800 , 0x5800 , "DSZ" , param_loc , 0 }, + {0x7800 , 0x6000 , "IOR" , param_loc , 0 }, + {0x7800 , 0x6800 , "JMP" , param_loc , 0 }, + {0x7fe0 , 0x7000 , "EXE" , param_addr32 , 0 }, + {0xffc0 , 0x7400 , "RZA" , param_skip , 0 }, + {0xffc0 , 0x7C00 , "RZB" , param_skip , 0 }, + {0xffc0 , 0x7440 , "RIA" , param_skip , 0 }, + {0xffc0 , 0x7C40 , "RIB" , param_skip , 0 }, + {0xffc0 , 0x7500 , "SZA" , param_skip , 0 }, + {0xffc0 , 0x7D00 , "SZB" , param_skip , 0 }, + {0xffc0 , 0x7540 , "SIA" , param_skip , 0 }, + {0xffc0 , 0x7D40 , "SIB" , param_skip , 0 }, + {0xffc0 , 0x7480 , "SFS" , param_skip , 0 }, + {0xffc0 , 0x7580 , "SFC" , param_skip , 0 }, + {0xffc0 , 0x7c80 , "SSS" , param_skip , 0 }, + {0xffc0 , 0x7d80 , "SSC" , param_skip , 0 }, + {0xffc0 , 0x7cc0 , "SHS" , param_skip , 0 }, + {0xffc0 , 0x7dc0 , "SHC" , param_skip , 0 }, + {0xff00 , 0x7600 , "SLA" , param_skip_sc , 0 }, + {0xff00 , 0x7e00 , "SLB" , param_skip_sc , 0 }, + {0xff00 , 0x7700 , "RLA" , param_skip_sc , 0 }, + {0xff00 , 0x7f00 , "RLB" , param_skip_sc , 0 }, + {0xff00 , 0xf400 , "SAP" , param_skip_sc , 0 }, + {0xff00 , 0xfc00 , "SBP" , param_skip_sc , 0 }, + {0xff00 , 0xf500 , "SAM" , param_skip_sc , 0 }, + {0xff00 , 0xfd00 , "SBM" , param_skip_sc , 0 }, + {0xff00 , 0xf600 , "SOC" , param_skip_sc , 0 }, + {0xff00 , 0xf700 , "SOS" , param_skip_sc , 0 }, + {0xff00 , 0xfe00 , "SEC" , param_skip_sc , 0 }, + {0xff00 , 0xff00 , "SES" , param_skip_sc , 0 }, + {0xffff , 0xf020 , "TCA" , param_none , 0 }, + {0xffff , 0xf820 , "TCB" , param_none , 0 }, + {0xffff , 0xf060 , "CMA" , param_none , 0 }, + {0xffff , 0xf860 , "CMB" , param_none , 0 }, + {0xff80 , 0xf080 , "RET" , param_ret , DASMFLAG_STEP_OUT }, + {0xfff0 , 0xf100 , "AAR" , param_n16 , 0 }, + {0xfff0 , 0xf900 , "ABR" , param_n16 , 0 }, + {0xffff , 0xf14f , "CLA" , param_none , 0 }, + {0xfff0 , 0xf140 , "SAR" , param_n16 , 0 }, + {0xffff , 0xf94f , "CLB" , param_none , 0 }, + {0xfff0 , 0xf940 , "SBR" , param_n16 , 0 }, + {0xfff0 , 0xf180 , "SAL" , param_n16 , 0 }, + {0xfff0 , 0xf980 , "SBL" , param_n16 , 0 }, + {0xfff0 , 0xf1c0 , "RAR" , param_n16 , 0 }, + {0xfff0 , 0xf9c0 , "RBR" , param_n16 , 0 }, + // *** IOC Instructions *** + {0xffff , 0x7100 , "SDO" , param_none , 0 }, + {0xffff , 0x7108 , "SDI" , param_none , 0 }, + {0xffff , 0x7110 , "EIR" , param_none , 0 }, + {0xffff , 0x7118 , "DIR" , param_none , 0 }, + {0xffff , 0x7120 , "DMA" , param_none , 0 }, + {0xffff , 0x7128 , "PCM" , param_none , 0 }, + {0xffff , 0x7138 , "DDR" , param_none , 0 }, + {0xffff , 0x7140 , "DBL" , param_none , 0 }, + {0xffff , 0x7148 , "CBL" , param_none , 0 }, + {0xffff , 0x7150 , "DBU" , param_none , 0 }, + {0xffff , 0x7158 , "CBU" , param_none , 0 }, + {0xff78 , 0x7160 , "PWC" , param_reg_id , 0 }, + {0xff78 , 0x7168 , "PWD" , param_reg_id , 0 }, + {0xff78 , 0x7960 , "PBC" , param_reg_id , 0 }, + {0xff78 , 0x7968 , "PBD" , param_reg_id , 0 }, + {0xff78 , 0x7170 , "WWC" , param_reg_id , 0 }, + {0xff78 , 0x7178 , "WWD" , param_reg_id , 0 }, + {0xff78 , 0x7970 , "WBC" , param_reg_id , 0 }, + {0xff78 , 0x7978 , "WBD" , param_reg_id , 0 }, + // *** END *** + {0 , 0 , NULL , NULL , 0 } +}; + +CPU_DISASSEMBLE(hp_hybrid) +{ + UINT16 opcode = ((UINT16)oprom[ 0 ] << 8) | oprom[ 1 ]; + const dis_entry_t *p; + + for (p = dis_table; p->m_op_mask; p++) { + if ((opcode & p->m_op_mask) == p->m_opcode) { + strcpy(buffer , p->m_mnemonic); + strcat(buffer , " "); + p->m_param_fn(buffer , pc , opcode); + return 1 | p->m_dasm_flags | DASMFLAG_SUPPORTED; + } + } + + // Unknown opcode + strcpy(buffer , "???"); + + return 1 | DASMFLAG_SUPPORTED; +} diff --git a/src/devices/cpu/i386/cycles.h b/src/devices/cpu/i386/cycles.h new file mode 100644 index 00000000000..a04e54da8e0 --- /dev/null +++ b/src/devices/cpu/i386/cycles.h @@ -0,0 +1,677 @@ +// license:BSD-3-Clause +// copyright-holders:Ville Linde, Barry Rodewald, Carl, Philip Bennett + +#pragma once + +#ifndef __CYCLES_H__ +#define __CYCLES_H__ + +enum X86_CYCLES +{ + CYCLES_MOV_REG_REG, + CYCLES_MOV_REG_MEM, + CYCLES_MOV_MEM_REG, + CYCLES_MOV_IMM_REG, + CYCLES_MOV_IMM_MEM, + CYCLES_MOV_ACC_MEM, + CYCLES_MOV_MEM_ACC, + CYCLES_MOV_REG_SREG, + CYCLES_MOV_MEM_SREG, + CYCLES_MOV_SREG_REG, + CYCLES_MOV_SREG_MEM, + CYCLES_MOVSX_REG_REG, + CYCLES_MOVSX_MEM_REG, + CYCLES_MOVZX_REG_REG, + CYCLES_MOVZX_MEM_REG, + CYCLES_PUSH_RM, + CYCLES_PUSH_REG_SHORT, + CYCLES_PUSH_SREG, + CYCLES_PUSH_IMM, + CYCLES_PUSHA, + CYCLES_POP_RM, + CYCLES_POP_REG_SHORT, + CYCLES_POP_SREG, + CYCLES_POPA, + CYCLES_XCHG_REG_REG, + CYCLES_XCHG_REG_MEM, + CYCLES_IN, + CYCLES_IN_VAR, + CYCLES_OUT, + CYCLES_OUT_VAR, + CYCLES_LEA, + CYCLES_LDS, + CYCLES_LES, + CYCLES_LFS, + CYCLES_LGS, + CYCLES_LSS, + CYCLES_CLC, + CYCLES_CLD, + CYCLES_CLI, + CYCLES_CLTS, + CYCLES_CMC, + CYCLES_LAHF, + CYCLES_POPF, + CYCLES_PUSHF, + CYCLES_SAHF, + CYCLES_STC, + CYCLES_STD, + CYCLES_STI, + CYCLES_ALU_REG_REG, + CYCLES_ALU_REG_MEM, + CYCLES_ALU_MEM_REG, + CYCLES_ALU_IMM_REG, + CYCLES_ALU_IMM_MEM, + CYCLES_ALU_IMM_ACC, + CYCLES_INC_REG, + CYCLES_INC_MEM, + CYCLES_DEC_REG, + CYCLES_DEC_MEM, + CYCLES_CMP_REG_REG, + CYCLES_CMP_REG_MEM, + CYCLES_CMP_MEM_REG, + CYCLES_CMP_IMM_REG, + CYCLES_CMP_IMM_MEM, + CYCLES_CMP_IMM_ACC, + CYCLES_TEST_REG_REG, + CYCLES_TEST_REG_MEM, + CYCLES_TEST_IMM_REG, + CYCLES_TEST_IMM_MEM, + CYCLES_TEST_IMM_ACC, + CYCLES_NEG_REG, + CYCLES_NEG_MEM, + CYCLES_AAA, + CYCLES_AAS, + CYCLES_DAA, + CYCLES_DAS, + CYCLES_MUL8_ACC_REG, + CYCLES_MUL8_ACC_MEM, + CYCLES_MUL16_ACC_REG, + CYCLES_MUL16_ACC_MEM, + CYCLES_MUL32_ACC_REG, + CYCLES_MUL32_ACC_MEM, + CYCLES_IMUL8_ACC_REG, + CYCLES_IMUL8_ACC_MEM, + CYCLES_IMUL16_ACC_REG, + CYCLES_IMUL16_ACC_MEM, + CYCLES_IMUL32_ACC_REG, + CYCLES_IMUL32_ACC_MEM, + CYCLES_IMUL8_REG_REG, + CYCLES_IMUL8_REG_MEM, + CYCLES_IMUL16_REG_REG, + CYCLES_IMUL16_REG_MEM, + CYCLES_IMUL32_REG_REG, + CYCLES_IMUL32_REG_MEM, + CYCLES_IMUL16_REG_IMM_REG, + CYCLES_IMUL16_MEM_IMM_REG, + CYCLES_IMUL32_REG_IMM_REG, + CYCLES_IMUL32_MEM_IMM_REG, + CYCLES_DIV8_ACC_REG, + CYCLES_DIV8_ACC_MEM, + CYCLES_DIV16_ACC_REG, + CYCLES_DIV16_ACC_MEM, + CYCLES_DIV32_ACC_REG, + CYCLES_DIV32_ACC_MEM, + CYCLES_IDIV8_ACC_REG, + CYCLES_IDIV8_ACC_MEM, + CYCLES_IDIV16_ACC_REG, + CYCLES_IDIV16_ACC_MEM, + CYCLES_IDIV32_ACC_REG, + CYCLES_IDIV32_ACC_MEM, + CYCLES_AAD, + CYCLES_AAM, + CYCLES_CBW, + CYCLES_CWD, + CYCLES_ROTATE_REG, + CYCLES_ROTATE_MEM, + CYCLES_ROTATE_CARRY_REG, + CYCLES_ROTATE_CARRY_MEM, + CYCLES_SHLD_REG, + CYCLES_SHLD_MEM, + CYCLES_SHRD_REG, + CYCLES_SHRD_MEM, + CYCLES_NOT_REG, + CYCLES_NOT_MEM, + CYCLES_CMPS, + CYCLES_INS, + CYCLES_LODS, + CYCLES_MOVS, + CYCLES_OUTS, + CYCLES_SCAS, + CYCLES_STOS, + CYCLES_XLAT, + CYCLES_REP_CMPS_BASE, + CYCLES_REP_INS_BASE, + CYCLES_REP_LODS_BASE, + CYCLES_REP_MOVS_BASE, + CYCLES_REP_OUTS_BASE, + CYCLES_REP_SCAS_BASE, + CYCLES_REP_STOS_BASE, + CYCLES_REP_CMPS, + CYCLES_REP_INS, + CYCLES_REP_LODS, + CYCLES_REP_MOVS, + CYCLES_REP_OUTS, + CYCLES_REP_SCAS, + CYCLES_REP_STOS, + CYCLES_BSF_BASE, + CYCLES_BSF, + CYCLES_BSR_BASE, + CYCLES_BSR, + CYCLES_BT_IMM_REG, + CYCLES_BT_IMM_MEM, + CYCLES_BT_REG_REG, + CYCLES_BT_REG_MEM, + CYCLES_BTC_IMM_REG, + CYCLES_BTC_IMM_MEM, + CYCLES_BTC_REG_REG, + CYCLES_BTC_REG_MEM, + CYCLES_BTR_IMM_REG, + CYCLES_BTR_IMM_MEM, + CYCLES_BTR_REG_REG, + CYCLES_BTR_REG_MEM, + CYCLES_BTS_IMM_REG, + CYCLES_BTS_IMM_MEM, + CYCLES_BTS_REG_REG, + CYCLES_BTS_REG_MEM, + CYCLES_CALL, // E8 + CYCLES_CALL_REG, // FF /2 + CYCLES_CALL_MEM, // FF /2 + CYCLES_CALL_INTERSEG, // 9A + CYCLES_CALL_REG_INTERSEG, // FF /3 + CYCLES_CALL_MEM_INTERSEG, // FF /3 + CYCLES_JMP_SHORT, // EB + CYCLES_JMP, // E9 + CYCLES_JMP_REG, // FF /4 + CYCLES_JMP_MEM, // FF /4 + CYCLES_JMP_INTERSEG, // EA + CYCLES_JMP_REG_INTERSEG, // FF /5 + CYCLES_JMP_MEM_INTERSEG, // FF /5 + CYCLES_RET, // C3 + CYCLES_RET_IMM, // C2 + CYCLES_RET_INTERSEG, // CB + CYCLES_RET_IMM_INTERSEG, // CA + CYCLES_JCC_DISP8, + CYCLES_JCC_FULL_DISP, + CYCLES_JCC_DISP8_NOBRANCH, + CYCLES_JCC_FULL_DISP_NOBRANCH, + CYCLES_JCXZ, + CYCLES_JCXZ_NOBRANCH, + CYCLES_LOOP, + CYCLES_LOOPZ, + CYCLES_LOOPNZ, + CYCLES_SETCC_REG, + CYCLES_SETCC_MEM, + CYCLES_ENTER, + CYCLES_LEAVE, + CYCLES_INT, + CYCLES_INT3, + CYCLES_INTO_OF1, + CYCLES_INTO_OF0, + CYCLES_BOUND_IN_RANGE, + CYCLES_BOUND_OUT_RANGE, + CYCLES_IRET, + CYCLES_HLT, + CYCLES_MOV_REG_CR0, + CYCLES_MOV_REG_CR2, + CYCLES_MOV_REG_CR3, + CYCLES_MOV_CR_REG, + CYCLES_MOV_REG_DR0_3, + CYCLES_MOV_REG_DR6_7, + CYCLES_MOV_DR6_7_REG, + CYCLES_MOV_DR0_3_REG, + CYCLES_MOV_REG_TR6_7, + CYCLES_MOV_TR6_7_REG, + CYCLES_NOP, + CYCLES_WAIT, + CYCLES_ARPL_REG, + CYCLES_ARPL_MEM, + CYCLES_LAR_REG, + CYCLES_LAR_MEM, + CYCLES_LGDT, + CYCLES_LIDT, + CYCLES_LLDT_REG, + CYCLES_LLDT_MEM, + CYCLES_LMSW_REG, + CYCLES_LMSW_MEM, + CYCLES_LSL_REG, + CYCLES_LSL_MEM, + CYCLES_LTR_REG, + CYCLES_LTR_MEM, + CYCLES_SGDT, + CYCLES_SIDT, + CYCLES_SLDT_REG, + CYCLES_SLDT_MEM, + CYCLES_SMSW_REG, + CYCLES_SMSW_MEM, + CYCLES_STR_REG, + CYCLES_STR_MEM, + CYCLES_VERR_REG, + CYCLES_VERR_MEM, + CYCLES_VERW_REG, + CYCLES_VERW_MEM, + CYCLES_LOCK, + + CYCLES_BSWAP, + CYCLES_CMPXCHG8B, + CYCLES_CMPXCHG, + CYCLES_CPUID, + CYCLES_CPUID_EAX1, + CYCLES_INVD, + CYCLES_XADD, + CYCLES_RDTSC, + CYCLES_RSM, + CYCLES_RDMSR, + + CYCLES_FABS, + CYCLES_FADD, + CYCLES_FBLD, + CYCLES_FBSTP, + CYCLES_FCHS, + CYCLES_FCLEX, + CYCLES_FCOM, + CYCLES_FCOS, + CYCLES_FDECSTP, + CYCLES_FDISI, + CYCLES_FDIV, + CYCLES_FDIVR, + CYCLES_FENI, + CYCLES_FFREE, + CYCLES_FIADD, + CYCLES_FICOM, + CYCLES_FIDIV, + CYCLES_FILD, + CYCLES_FIMUL, + CYCLES_FINCSTP, + CYCLES_FINIT, + CYCLES_FIST, + CYCLES_FISUB, + CYCLES_FLD, + CYCLES_FLDZ, + CYCLES_FLD1, + CYCLES_FLDL2E, + CYCLES_FLDL2T, + CYCLES_FLDLG2, + CYCLES_FLDLN2, + CYCLES_FLDPI, + CYCLES_FLDCW, + CYCLES_FLDENV, + CYCLES_FMUL, + CYCLES_FNOP, + CYCLES_FPATAN, + CYCLES_FPREM, + CYCLES_FPREM1, + CYCLES_FPTAN, + CYCLES_FRNDINT, + CYCLES_FRSTOR, + CYCLES_FSAVE, + CYCLES_FSCALE, + CYCLES_FSETPM, + CYCLES_FSIN, + CYCLES_FSINCOS, + CYCLES_FSQRT, + CYCLES_FST, + CYCLES_FSTCW, + CYCLES_FSTENV, + CYCLES_FSTSW, + CYCLES_FSUB, + CYCLES_FSUBR, + CYCLES_FTST, + CYCLES_FUCOM, + CYCLES_FXAM, + CYCLES_FXCH, + CYCLES_FXTRACT, + CYCLES_FYL2X, + CYCLES_FYL2XPI, + CYCLES_CMPXCHG_REG_REG_T, + CYCLES_CMPXCHG_REG_REG_F, + CYCLES_CMPXCHG_REG_MEM_T, + CYCLES_CMPXCHG_REG_MEM_F, + CYCLES_XADD_REG_REG, + CYCLES_XADD_REG_MEM, + + CYCLES_NUM_OPCODES +}; + + +#define X86_NUM_CPUS 4 +#define CPU_CYCLES_I386 0 +#define CPU_CYCLES_I486 1 +#define CPU_CYCLES_PENTIUM 2 +#define CPU_CYCLES_MEDIAGX 3 + + +struct X86_CYCLE_TABLE +{ + X86_CYCLES op; + UINT8 cpu_cycles[X86_NUM_CPUS][2]; +}; + +static const X86_CYCLE_TABLE x86_cycle_table[] = +{ + // opcode rm/pmode + // i386 i486 pentium mediagx + { CYCLES_MOV_REG_REG, { { 2, 2 }, { 1, 1 }, { 1, 1 }, { 1, 1 } } }, + { CYCLES_MOV_REG_MEM, { { 2, 2 }, { 1, 1 }, { 1, 1 }, { 1, 1 } } }, + { CYCLES_MOV_MEM_REG, { { 4, 4 }, { 1, 1 }, { 1, 1 }, { 1, 1 } } }, + { CYCLES_MOV_IMM_REG, { { 2, 2 }, { 1, 1 }, { 1, 1 }, { 1, 1 } } }, + { CYCLES_MOV_IMM_MEM, { { 2, 2 }, { 1, 1 }, { 1, 1 }, { 1, 1 } } }, + { CYCLES_MOV_ACC_MEM, { { 2, 2 }, { 1, 1 }, { 1, 1 }, { 1, 1 } } }, + { CYCLES_MOV_MEM_ACC, { { 4, 4 }, { 1, 1 }, { 1, 1 }, { 1, 1 } } }, + { CYCLES_MOV_REG_SREG, { { 2, 18 }, { 3, 3 }, { 2, 2 }, { 1, 6 } } }, + { CYCLES_MOV_MEM_SREG, { { 5, 19 }, { 9, 9 }, { 3, 3 }, { 1, 6 } } }, + { CYCLES_MOV_SREG_REG, { { 2, 2 }, { 3, 3 }, { 1, 1 }, { 1, 6 } } }, + { CYCLES_MOV_SREG_MEM, { { 2, 2 }, { 3, 3 }, { 1, 1 }, { 1, 6 } } }, + { CYCLES_MOVSX_REG_REG, { { 3, 3 }, { 3, 3 }, { 3, 3 }, { 1, 1 } } }, + { CYCLES_MOVSX_MEM_REG, { { 6, 6 }, { 3, 3 }, { 3, 3 }, { 1, 1 } } }, + { CYCLES_MOVZX_REG_REG, { { 3, 3 }, { 3, 3 }, { 3, 3 }, { 1, 1 } } }, + { CYCLES_MOVZX_MEM_REG, { { 6, 6 }, { 3, 3 }, { 3, 3 }, { 1, 1 } } }, + { CYCLES_PUSH_RM, { { 5, 5 }, { 4, 4 }, { 2, 2 }, { 3, 3 } } }, + { CYCLES_PUSH_REG_SHORT, { { 2, 2 }, { 1, 1 }, { 1, 1 }, { 1, 1 } } }, + { CYCLES_PUSH_SREG, { { 2, 2 }, { 3, 3 }, { 1, 1 }, { 1, 1 } } }, + { CYCLES_PUSH_IMM, { { 2, 2 }, { 1, 1 }, { 1, 1 }, { 1, 1 } } }, + { CYCLES_PUSHA, { { 18, 18 }, { 11, 11 }, { 5, 5 }, { 11, 11 } } }, + { CYCLES_POP_RM, { { 5, 5 }, { 4, 4 }, { 3, 3 }, { 4, 4 } } }, + { CYCLES_POP_REG_SHORT, { { 4, 4 }, { 4, 4 }, { 1, 1 }, { 1, 1 } } }, + { CYCLES_POP_SREG, { { 7, 21 }, { 3, 3 }, { 3, 3 }, { 1, 6 } } }, + { CYCLES_POPA, { { 24, 24 }, { 9, 9 }, { 5, 5 }, { 9, 9 } } }, + { CYCLES_XCHG_REG_REG, { { 3, 3 }, { 3, 3 }, { 3, 3 }, { 1, 1 } } }, + { CYCLES_XCHG_REG_MEM, { { 5, 5 }, { 5, 5 }, { 3, 3 }, { 1, 1 } } }, + { CYCLES_IN, { { 12, 26 }, { 14, 27 }, { 7, 19 }, { 8, 8 } } }, + { CYCLES_IN_VAR, { { 13, 27 }, { 14, 27 }, { 7, 19 }, { 8, 8 } } }, + { CYCLES_OUT, { { 10, 24 }, { 16, 29 }, { 12, 24 }, { 14, 14 } } }, + { CYCLES_OUT_VAR, { { 11, 25 }, { 16, 29 }, { 12, 24 }, { 14, 14 } } }, + { CYCLES_LEA, { { 2, 2 }, { 1, 1 }, { 1, 1 }, { 1, 1 } } }, + { CYCLES_LDS, { { 7, 22 }, { 6, 12 }, { 4, 4 }, { 4, 9 } } }, + { CYCLES_LES, { { 7, 22 }, { 6, 12 }, { 4, 4 }, { 4, 9 } } }, + { CYCLES_LFS, { { 7, 22 }, { 6, 12 }, { 4, 4 }, { 4, 9 } } }, + { CYCLES_LGS, { { 7, 22 }, { 6, 12 }, { 4, 4 }, { 4, 9 } } }, + { CYCLES_LSS, { { 7, 22 }, { 6, 12 }, { 4, 4 }, { 4, 10 } } }, + { CYCLES_CLC, { { 2, 2 }, { 2, 2 }, { 2, 2 }, { 1, 1 } } }, + { CYCLES_CLD, { { 2, 2 }, { 2, 2 }, { 2, 2 }, { 4, 4 } } }, + { CYCLES_CLI, { { 8, 8 }, { 5, 5 }, { 7, 7 }, { 6, 6 } } }, + { CYCLES_CLTS, { { 6, 6 }, { 7, 7 }, { 10, 10 }, { 7, 7 } } }, + { CYCLES_CMC, { { 2, 2 }, { 2, 2 }, { 2, 2 }, { 3, 3 } } }, + { CYCLES_LAHF, { { 2, 2 }, { 3, 3 }, { 2, 2 }, { 2, 2 } } }, + { CYCLES_POPF, { { 5, 5 }, { 9, 9 }, { 6, 6 }, { 8, 8 } } }, + { CYCLES_PUSHF, { { 4, 4 }, { 4, 4 }, { 9, 9 }, { 2, 2 } } }, + { CYCLES_SAHF, { { 3, 3 }, { 2, 2 }, { 2, 2 }, { 1, 1 } } }, + { CYCLES_STC, { { 2, 2 }, { 2, 2 }, { 2, 2 }, { 1, 1 } } }, + { CYCLES_STD, { { 2, 2 }, { 2, 2 }, { 2, 2 }, { 4, 4 } } }, + { CYCLES_STI, { { 8, 8 }, { 5, 5 }, { 7, 7 }, { 6, 6 } } }, + { CYCLES_ALU_REG_REG, { { 2, 2 }, { 1, 1 }, { 1, 1 }, { 1, 1 } } }, + { CYCLES_ALU_REG_MEM, { { 7, 7 }, { 3, 3 }, { 3, 3 }, { 1, 1 } } }, + { CYCLES_ALU_MEM_REG, { { 6, 6 }, { 2, 2 }, { 2, 2 }, { 1, 1 } } }, + { CYCLES_ALU_IMM_REG, { { 2, 2 }, { 1, 1 }, { 1, 1 }, { 1, 1 } } }, + { CYCLES_ALU_IMM_MEM, { { 7, 7 }, { 3, 3 }, { 3, 3 }, { 1, 1 } } }, + { CYCLES_ALU_IMM_ACC, { { 2, 2 }, { 1, 1 }, { 1, 1 }, { 1, 1 } } }, + { CYCLES_INC_REG, { { 2, 2 }, { 1, 1 }, { 1, 1 }, { 1, 1 } } }, + { CYCLES_INC_MEM, { { 6, 6 }, { 3, 3 }, { 3, 3 }, { 1, 1 } } }, + { CYCLES_DEC_REG, { { 2, 2 }, { 1, 1 }, { 1, 1 }, { 1, 1 } } }, + { CYCLES_DEC_MEM, { { 6, 6 }, { 3, 3 }, { 3, 3 }, { 1, 1 } } }, + { CYCLES_CMP_REG_REG, { { 2, 2 }, { 1, 1 }, { 1, 1 }, { 1, 1 } } }, + { CYCLES_CMP_REG_MEM, { { 5, 5 }, { 2, 2 }, { 2, 2 }, { 1, 1 } } }, + { CYCLES_CMP_MEM_REG, { { 6, 6 }, { 2, 2 }, { 2, 2 }, { 1, 1 } } }, + { CYCLES_CMP_IMM_REG, { { 2, 2 }, { 1, 1 }, { 1, 1 }, { 1, 1 } } }, + { CYCLES_CMP_IMM_MEM, { { 5, 5 }, { 2, 2 }, { 2, 2 }, { 1, 1 } } }, + { CYCLES_CMP_IMM_ACC, { { 2, 2 }, { 1, 1 }, { 1, 1 }, { 1, 1 } } }, + { CYCLES_TEST_REG_REG, { { 2, 2 }, { 1, 1 }, { 1, 1 }, { 1, 1 } } }, + { CYCLES_TEST_REG_MEM, { { 5, 5 }, { 2, 2 }, { 2, 2 }, { 1, 1 } } }, + { CYCLES_TEST_IMM_REG, { { 2, 2 }, { 1, 1 }, { 1, 1 }, { 1, 1 } } }, + { CYCLES_TEST_IMM_MEM, { { 5, 5 }, { 2, 2 }, { 2, 2 }, { 1, 1 } } }, + { CYCLES_TEST_IMM_ACC, { { 2, 2 }, { 1, 1 }, { 1, 1 }, { 1, 1 } } }, + { CYCLES_NEG_REG, { { 2, 2 }, { 1, 1 }, { 1, 1 }, { 1, 1 } } }, + { CYCLES_NEG_MEM, { { 6, 6 }, { 3, 3 }, { 3, 3 }, { 1, 1 } } }, + { CYCLES_AAA, { { 4, 4 }, { 3, 3 }, { 3, 3 }, { 3, 3 } } }, + { CYCLES_AAS, { { 4, 4 }, { 3, 3 }, { 3, 3 }, { 3, 3 } } }, + { CYCLES_DAA, { { 4, 4 }, { 2, 2 }, { 3, 3 }, { 2, 2 } } }, + { CYCLES_DAS, { { 4, 4 }, { 2, 2 }, { 3, 3 }, { 2, 2 } } }, + { CYCLES_MUL8_ACC_REG, { { 17, 17 }, { 13, 13 }, { 11, 11 }, { 4, 4 } } }, + { CYCLES_MUL8_ACC_MEM, { { 20, 20 }, { 13, 13 }, { 11, 11 }, { 4, 4 } } }, + { CYCLES_MUL16_ACC_REG, { { 25, 25 }, { 13, 13 }, { 11, 11 }, { 5, 5 } } }, + { CYCLES_MUL16_ACC_MEM, { { 28, 28 }, { 13, 13 }, { 11, 11 }, { 5, 5 } } }, + { CYCLES_MUL32_ACC_REG, { { 41, 41 }, { 13, 13 }, { 10, 10 }, { 15, 15 } } }, + { CYCLES_MUL32_ACC_MEM, { { 44, 44 }, { 13, 13 }, { 10, 10 }, { 15, 15 } } }, + { CYCLES_IMUL8_ACC_REG, { { 17, 17 }, { 18, 18 }, { 11, 11 }, { 4, 4 } } }, + { CYCLES_IMUL8_ACC_MEM, { { 20, 20 }, { 18, 18 }, { 11, 11 }, { 4, 4 } } }, + { CYCLES_IMUL16_ACC_REG, { { 25, 25 }, { 26, 26 }, { 11, 11 }, { 5, 5 } } }, + { CYCLES_IMUL16_ACC_MEM, { { 28, 28 }, { 26, 26 }, { 11, 11 }, { 5, 5 } } }, + { CYCLES_IMUL32_ACC_REG, { { 41, 41 }, { 42, 42 }, { 10, 10 }, { 15, 15 } } }, + { CYCLES_IMUL32_ACC_MEM, { { 44, 44 }, { 42, 42 }, { 10, 10 }, { 15, 15 } } }, + { CYCLES_IMUL8_REG_REG, { { 17, 17 }, { 13, 13 }, { 10, 10 }, { 4, 4 } } }, + { CYCLES_IMUL8_REG_MEM, { { 20, 20 }, { 13, 13 }, { 10, 10 }, { 4, 4 } } }, + { CYCLES_IMUL16_REG_REG, { { 25, 25 }, { 13, 13 }, { 10, 10 }, { 5, 5 } } }, + { CYCLES_IMUL16_REG_MEM, { { 28, 28 }, { 13, 13 }, { 10, 10 }, { 5, 5 } } }, + { CYCLES_IMUL32_REG_REG, { { 41, 41 }, { 13, 13 }, { 10, 10 }, { 15, 15 } } }, + { CYCLES_IMUL32_REG_MEM, { { 44, 44 }, { 13, 13 }, { 10, 10 }, { 15, 15 } } }, + { CYCLES_IMUL16_REG_IMM_REG,{ { 26, 26 }, { 26, 26 }, { 10, 10 }, { 6, 6 } } }, + { CYCLES_IMUL16_MEM_IMM_REG,{ { 27, 27 }, { 26, 26 }, { 10, 10 }, { 6, 6 } } }, + { CYCLES_IMUL32_REG_IMM_REG,{ { 42, 42 }, { 42, 42 }, { 10, 10 }, { 16, 16 } } }, + { CYCLES_IMUL32_MEM_IMM_REG,{ { 43, 43 }, { 42, 42 }, { 10, 10 }, { 16, 16 } } }, + { CYCLES_DIV8_ACC_REG, { { 14, 14 }, { 16, 16 }, { 17, 17 }, { 20, 20 } } }, + { CYCLES_DIV8_ACC_MEM, { { 17, 17 }, { 16, 16 }, { 17, 17 }, { 20, 20 } } }, + { CYCLES_DIV16_ACC_REG, { { 22, 22 }, { 24, 24 }, { 25, 25 }, { 29, 29 } } }, + { CYCLES_DIV16_ACC_MEM, { { 25, 25 }, { 24, 24 }, { 25, 25 }, { 29, 29 } } }, + { CYCLES_DIV32_ACC_REG, { { 38, 38 }, { 40, 40 }, { 41, 41 }, { 45, 45 } } }, + { CYCLES_DIV32_ACC_MEM, { { 41, 41 }, { 40, 40 }, { 41, 41 }, { 45, 45 } } }, + { CYCLES_IDIV8_ACC_REG, { { 19, 19 }, { 19, 19 }, { 22, 22 }, { 20, 20 } } }, + { CYCLES_IDIV8_ACC_MEM, { { 22, 22 }, { 20, 20 }, { 22, 22 }, { 20, 20 } } }, + { CYCLES_IDIV16_ACC_REG, { { 27, 27 }, { 27, 27 }, { 30, 30 }, { 29, 29 } } }, + { CYCLES_IDIV16_ACC_MEM, { { 30, 30 }, { 28, 28 }, { 30, 30 }, { 29, 29 } } }, + { CYCLES_IDIV32_ACC_REG, { { 43, 43 }, { 43, 43 }, { 46, 46 }, { 45, 45 } } }, + { CYCLES_IDIV32_ACC_MEM, { { 46, 46 }, { 44, 44 }, { 46, 46 }, { 45, 45 } } }, + { CYCLES_AAD, { { 19, 19 }, { 14, 14 }, { 10, 10 }, { 7, 7 } } }, + { CYCLES_AAM, { { 17, 17 }, { 15, 15 }, { 18, 18 }, { 19, 19 } } }, + { CYCLES_CBW, { { 3, 3 }, { 3, 3 }, { 3, 3 }, { 3, 3 } } }, + { CYCLES_CWD, { { 2, 2 }, { 3, 3 }, { 2, 2 }, { 2, 2 } } }, + { CYCLES_ROTATE_REG, { { 3, 3 }, { 3, 3 }, { 1, 1 }, { 2, 2 } } }, + { CYCLES_ROTATE_MEM, { { 7, 7 }, { 4, 4 }, { 3, 3 }, { 2, 2 } } }, + { CYCLES_ROTATE_CARRY_REG, { { 9, 9 }, { 8, 8 }, { 7, 7 }, { 8, 8 } } }, + { CYCLES_ROTATE_CARRY_MEM, { { 10, 10 }, { 9, 9 }, { 8, 8 }, { 8, 8 } } }, + { CYCLES_SHLD_REG, { { 3, 3 }, { 2, 2 }, { 4, 4 }, { 3, 3 } } }, + { CYCLES_SHLD_MEM, { { 7, 7 }, { 3, 3 }, { 4, 4 }, { 6, 6 } } }, + { CYCLES_SHRD_REG, { { 3, 3 }, { 2, 2 }, { 4, 4 }, { 3, 3 } } }, + { CYCLES_SHRD_MEM, { { 7, 7 }, { 3, 3 }, { 4, 4 }, { 6, 6 } } }, + { CYCLES_NOT_REG, { { 2, 2 }, { 1, 1 }, { 1, 1 }, { 1, 1 } } }, + { CYCLES_NOT_MEM, { { 6, 6 }, { 3, 3 }, { 3, 3 }, { 1, 1 } } }, + { CYCLES_CMPS, { { 10, 10 }, { 8, 8 }, { 5, 5 }, { 6, 6 } } }, + { CYCLES_INS, { { 15, 29 }, { 17, 30 }, { 9, 22 }, { 11, 11 } } }, + { CYCLES_LODS, { { 5, 5 }, { 5, 5 }, { 2, 2 }, { 3, 3 } } }, + { CYCLES_MOVS, { { 8, 8 }, { 7, 7 }, { 4, 4 }, { 6, 6 } } }, + { CYCLES_OUTS, { { 14, 28 }, { 17, 30 }, { 13, 25 }, { 15, 15 } } }, + { CYCLES_SCAS, { { 8, 8 }, { 6, 6 }, { 4, 4 }, { 2, 2 } } }, + { CYCLES_STOS, { { 5, 5 }, { 5, 5 }, { 3, 3 }, { 2, 2 } } }, + { CYCLES_XLAT, { { 5, 5 }, { 4, 4 }, { 4, 4 }, { 5, 5 } } }, + { CYCLES_REP_CMPS_BASE, { { 5, 5 }, { 0, 0 }, { 0, 0 }, { 11, 11 } } }, + { CYCLES_REP_INS_BASE, { { 14, 8 }, { 0, 0 }, { 0, 0 }, { 17, 17 } } }, + { CYCLES_REP_LODS_BASE, { { 5, 5 }, { 0, 0 }, { 0, 0 }, { 9, 9 } } }, + { CYCLES_REP_MOVS_BASE, { { 8, 8 }, { 0, 0 }, { 0, 0 }, { 12, 12 } } }, + { CYCLES_REP_OUTS_BASE, { { 12, 6 }, { 0, 0 }, { 0, 0 }, { 24, 24 } } }, + { CYCLES_REP_SCAS_BASE, { { 5, 5 }, { 0, 0 }, { 0, 0 }, { 9, 9 } } }, + { CYCLES_REP_STOS_BASE, { { 5, 5 }, { 0, 0 }, { 0, 0 }, { 9, 9 } } }, + { CYCLES_REP_CMPS, { { 5, 5 }, { 8, 8 }, { 5, 5 }, { 4, 4 } } }, + { CYCLES_REP_INS, { { 14, 8 }, { 17, 30 }, { 9, 22 }, { 4, 4 } } }, + { CYCLES_REP_LODS, { { 5, 5 }, { 5, 5 }, { 2, 2 }, { 2, 2 } } }, + { CYCLES_REP_MOVS, { { 8, 8 }, { 7, 7 }, { 4, 4 }, { 2, 2 } } }, + { CYCLES_REP_OUTS, { { 12, 6 }, { 17, 30 }, { 13, 25 }, { 4, 4 } } }, + { CYCLES_REP_SCAS, { { 5, 5 }, { 6, 6 }, { 4, 4 }, { 3, 3 } } }, + { CYCLES_REP_STOS, { { 5, 5 }, { 5, 5 }, { 3, 3 }, { 2, 2 } } }, + { CYCLES_BSF_BASE, { { 11, 11 }, { 6, 6 }, { 6, 6 }, { 4, 4 } } }, + { CYCLES_BSF, { { 3, 3 }, { 1, 1 }, { 1, 1 }, { 1, 1 } } }, + { CYCLES_BSR_BASE, { { 9, 9 }, { 6, 6 }, { 7, 7 }, { 4, 4 } } }, + { CYCLES_BSR, { { 3, 3 }, { 1, 1 }, { 1, 1 }, { 1, 1 } } }, + { CYCLES_BT_IMM_REG, { { 3, 3 }, { 3, 3 }, { 4, 4 }, { 1, 1 } } }, + { CYCLES_BT_IMM_MEM, { { 6, 6 }, { 6, 6 }, { 4, 4 }, { 1, 1 } } }, + { CYCLES_BT_REG_REG, { { 3, 3 }, { 3, 3 }, { 4, 4 }, { 1, 1 } } }, + { CYCLES_BT_REG_MEM, { { 12, 12 }, { 12, 12 }, { 9, 9 }, { 7, 7 } } }, + { CYCLES_BTC_IMM_REG, { { 6, 6 }, { 6, 6 }, { 7, 7 }, { 2, 2 } } }, + { CYCLES_BTC_IMM_MEM, { { 8, 8 }, { 8, 8 }, { 8, 8 }, { 2, 2 } } }, + { CYCLES_BTC_REG_REG, { { 6, 6 }, { 6, 6 }, { 7, 7 }, { 2, 2 } } }, + { CYCLES_BTC_REG_MEM, { { 13, 13 }, { 13, 13 }, { 13, 13 }, { 8, 8 } } }, + { CYCLES_BTR_IMM_REG, { { 6, 6 }, { 6, 6 }, { 7, 7 }, { 2, 2 } } }, + { CYCLES_BTR_IMM_MEM, { { 8, 8 }, { 8, 8 }, { 8, 8 }, { 2, 2 } } }, + { CYCLES_BTR_REG_REG, { { 6, 6 }, { 6, 6 }, { 7, 7 }, { 2, 2 } } }, + { CYCLES_BTR_REG_MEM, { { 13, 13 }, { 13, 13 }, { 13, 13 }, { 8, 8 } } }, + { CYCLES_BTS_IMM_REG, { { 6, 6 }, { 6, 6 }, { 7, 7 }, { 2, 2 } } }, + { CYCLES_BTS_IMM_MEM, { { 8, 8 }, { 8, 8 }, { 8, 8 }, { 2, 2 } } }, + { CYCLES_BTS_REG_REG, { { 6, 6 }, { 6, 6 }, { 7, 7 }, { 2, 2 } } }, + { CYCLES_BTS_REG_MEM, { { 13, 13 }, { 13, 13 }, { 13, 13 }, { 8, 8 } } }, + { CYCLES_CALL, { { 7, 7 }, { 3, 3 }, { 1, 1 }, { 3, 3 } } }, + { CYCLES_CALL_REG, { { 7, 7 }, { 5, 5 }, { 2, 2 }, { 3, 3 } } }, + { CYCLES_CALL_MEM, { { 10, 10 }, { 5, 5 }, { 2, 2 }, { 4, 4 } } }, + { CYCLES_CALL_INTERSEG, { { 17, 34 }, { 18, 20 }, { 4, 13 }, { 9, 14 } } }, + { CYCLES_CALL_REG_INTERSEG, { { 22, 38 }, { 17, 20 }, { 4, 14 }, { 11, 15 } } }, + { CYCLES_CALL_MEM_INTERSEG, { { 22, 38 }, { 17, 20 }, { 4, 14 }, { 11, 15 } } }, + { CYCLES_JMP_SHORT, { { 7, 7 }, { 3, 3 }, { 1, 1 }, { 1, 1 } } }, + { CYCLES_JMP, { { 7, 7 }, { 3, 3 }, { 1, 1 }, { 1, 1 } } }, + { CYCLES_JMP_REG, { { 7, 7 }, { 5, 5 }, { 2, 2 }, { 1, 1 } } }, + { CYCLES_JMP_MEM, { { 10, 10 }, { 5, 5 }, { 2, 2 }, { 3, 3 } } }, + { CYCLES_JMP_INTERSEG, { { 12, 27 }, { 17, 19 }, { 3, 3 }, { 8, 12 } } }, + { CYCLES_JMP_REG_INTERSEG, { { 17, 31 }, { 13, 18 }, { 4, 4 }, { 10, 10 } } }, + { CYCLES_JMP_MEM_INTERSEG, { { 17, 31 }, { 13, 18 }, { 4, 4 }, { 10, 13 } } }, + { CYCLES_RET, { { 10, 10 }, { 5, 5 }, { 2, 2 }, { 3, 3 } } }, + { CYCLES_RET_IMM, { { 10, 10 }, { 5, 5 }, { 2, 2 }, { 3, 3 } } }, + { CYCLES_RET_INTERSEG, { { 18, 32 }, { 13, 13 }, { 4, 4 }, { 10, 13 } } }, + { CYCLES_RET_IMM_INTERSEG, { { 18, 32 }, { 14, 14 }, { 4, 4 }, { 10, 13 } } }, + { CYCLES_JCC_DISP8, { { 7, 7 }, { 3, 3 }, { 1, 1 }, { 1, 1 } } }, + { CYCLES_JCC_FULL_DISP, { { 7, 7 }, { 3, 3 }, { 1, 1 }, { 1, 1 } } }, + { CYCLES_JCC_DISP8_NOBRANCH,{ { 3, 3 }, { 1, 1 }, { 1, 1 }, { 1, 1 } } }, + { CYCLES_JCC_FULL_DISP_NOBRANCH,{ { 3, 3 }, { 1, 1 }, { 1, 1 }, { 1, 1 } } }, + { CYCLES_JCXZ, { { 9, 9 }, { 1, 1 }, { 1, 1 }, { 2, 2 } } }, + { CYCLES_JCXZ_NOBRANCH, { { 5, 5 }, { 1, 1 }, { 1, 1 }, { 2, 2 } } }, + { CYCLES_LOOP, { { 11, 11 }, { 6, 6 }, { 5, 5 }, { 2, 2 } } }, + { CYCLES_LOOPZ, { { 11, 11 }, { 9, 9 }, { 8, 8 }, { 2, 2 } } }, + { CYCLES_LOOPNZ, { { 11, 11 }, { 9, 9 }, { 8, 8 }, { 2, 2 } } }, + { CYCLES_SETCC_REG, { { 4, 4 }, { 3, 3 }, { 2, 2 }, { 1, 1 } } }, + { CYCLES_SETCC_MEM, { { 5, 5 }, { 4, 4 }, { 2, 2 }, { 1, 1 } } }, + { CYCLES_ENTER, { { 10, 10 }, { 14, 14 }, { 11, 11 }, { 13, 13 } } }, + { CYCLES_LEAVE, { { 4, 4 }, { 5, 5 }, { 3, 3 }, { 1, 1 } } }, + { CYCLES_INT, { { 37, 37 }, { 30, 30 }, { 16, 16 }, { 19, 19 } } }, + { CYCLES_INT3, { { 33, 33 }, { 26, 26 }, { 13, 13 }, { 19, 19 } } }, + { CYCLES_INTO_OF1, { { 35, 35 }, { 28, 28 }, { 13, 13 }, { 19, 19 } } }, + { CYCLES_INTO_OF0, { { 3, 3 }, { 3, 3 }, { 4, 4 }, { 4, 4 } } }, + { CYCLES_BOUND_IN_RANGE, { { 10, 10 }, { 7, 7 }, { 8, 8 }, { 7, 7 } } }, + { CYCLES_BOUND_OUT_RANGE, { { 44, 44 }, { 7, 7 }, { 8, 8 }, { 8, 8 } } }, + { CYCLES_IRET, { { 22, 22 }, { 15, 15 }, { 8, 8 }, { 13, 13 } } }, + { CYCLES_HLT, { { 5, 5 }, { 4, 4 }, { 4, 4 }, { 10, 10 } } }, + { CYCLES_MOV_REG_CR0, { { 11, 11 }, { 16, 16 }, { 16, 16 }, { 20, 18 } } }, + { CYCLES_MOV_REG_CR2, { { 4, 4 }, { 4, 4 }, { 4, 4 }, { 5, 5 } } }, + { CYCLES_MOV_REG_CR3, { { 5, 5 }, { 4, 4 }, { 4, 4 }, { 5, 6 } } }, + { CYCLES_MOV_CR_REG, { { 6, 6 }, { 4, 4 }, { 4, 4 }, { 6, 6 } } }, + { CYCLES_MOV_REG_DR0_3, { { 22, 22 }, { 10, 10 }, { 10, 10 }, { 10, 10 } } }, + { CYCLES_MOV_REG_DR6_7, { { 16, 16 }, { 10, 10 }, { 10, 10 }, { 10, 10 } } }, + { CYCLES_MOV_DR6_7_REG, { { 14, 14 }, { 11, 11 }, { 11, 11 }, { 9, 9 } } }, + { CYCLES_MOV_DR0_3_REG, { { 22, 22 }, { 11, 11 }, { 11, 11 }, { 9, 9 } } }, + { CYCLES_MOV_REG_TR6_7, { { 12, 12 }, { 4, 4 }, { 4, 4 }, { 11, 11 } } }, + { CYCLES_MOV_TR6_7_REG, { { 12, 12 }, { 3, 3 }, { 3, 3 }, { 3, 3 } } }, + { CYCLES_NOP, { { 3, 3 }, { 1, 1 }, { 1, 1 }, { 1, 1 } } }, + { CYCLES_WAIT, { { 7, 7 }, { 1, 1 }, { 1, 1 }, { 1, 1 } } }, + { CYCLES_ARPL_REG, { { 0, 20 }, { 0, 9 }, { 0, 7 }, { 0, 9 } } }, + { CYCLES_ARPL_MEM, { { 0, 21 }, { 0, 9 }, { 0, 7 }, { 0, 9 } } }, + { CYCLES_LAR_REG, { { 0, 15 }, { 11, 11 }, { 8, 8 }, { 0, 9 } } }, + { CYCLES_LAR_MEM, { { 0, 16 }, { 11, 11 }, { 8, 8 }, { 0, 9 } } }, + { CYCLES_LGDT, { { 11, 11 }, { 11, 11 }, { 6, 6 }, { 10, 10 } } }, + { CYCLES_LIDT, { { 11, 11 }, { 11, 11 }, { 6, 6 }, { 10, 10 } } }, + { CYCLES_LLDT_REG, { { 0, 20 }, { 11, 11 }, { 9, 9 }, { 0, 8 } } }, + { CYCLES_LLDT_MEM, { { 0, 24 }, { 11, 11 }, { 9, 9 }, { 0, 8 } } }, + { CYCLES_LMSW_REG, { { 11, 11 }, { 13, 13 }, { 8, 8 }, { 11, 11 } } }, + { CYCLES_LMSW_MEM, { { 14, 14 }, { 13, 13 }, { 8, 8 }, { 11, 11 } } }, + { CYCLES_LSL_REG, { { 0, 21 }, { 10, 10 }, { 8, 8 }, { 0, 9 } } }, + { CYCLES_LSL_MEM, { { 0, 22 }, { 10, 10 }, { 8, 8 }, { 0, 9 } } }, + { CYCLES_LTR_REG, { { 0, 23 }, { 20, 20 }, { 10, 10 }, { 0, 9 } } }, + { CYCLES_LTR_MEM, { { 0, 27 }, { 20, 20 }, { 10, 10 }, { 0, 9 } } }, + { CYCLES_SGDT, { { 9, 9 }, { 10, 10 }, { 4, 4 }, { 6, 6 } } }, + { CYCLES_SIDT, { { 9, 9 }, { 10, 10 }, { 4, 4 }, { 6, 6 } } }, + { CYCLES_SLDT_REG, { { 0, 2 }, { 2, 2 }, { 2, 2 }, { 0, 1 } } }, + { CYCLES_SLDT_MEM, { { 0, 2 }, { 3, 3 }, { 2, 2 }, { 0, 1 } } }, + { CYCLES_SMSW_REG, { { 2, 2 }, { 2, 2 }, { 4, 4 }, { 4, 4 } } }, + { CYCLES_SMSW_MEM, { { 2, 2 }, { 3, 3 }, { 4, 4 }, { 4, 4 } } }, + { CYCLES_STR_REG, { { 0, 2 }, { 2, 2 }, { 2, 2 }, { 0, 3 } } }, + { CYCLES_STR_MEM, { { 0, 2 }, { 3, 3 }, { 2, 2 }, { 0, 3 } } }, + { CYCLES_VERR_REG, { { 0, 10 }, { 11, 11 }, { 7, 7 }, { 0, 8 } } }, + { CYCLES_VERR_MEM, { { 0, 11 }, { 11, 11 }, { 7, 7 }, { 0, 8 } } }, + { CYCLES_VERW_REG, { { 0, 15 }, { 11, 11 }, { 7, 7 }, { 0, 8 } } }, + { CYCLES_VERW_MEM, { { 0, 16 }, { 11, 11 }, { 7, 7 }, { 0, 8 } } }, + { CYCLES_LOCK, { { 0, 0 }, { 1, 1 }, { 1, 1 }, { 1, 1 } } }, + + // i486+ + { CYCLES_BSWAP, { { 0, 0 }, { 1, 1 }, { 1, 1 }, { 6, 6 } } }, + { CYCLES_CMPXCHG, { { 0, 0 }, { 6, 6 }, { 5, 5 }, { 6, 6 } } }, + { CYCLES_INVD, { { 0, 0 }, { 4, 4 }, { 15, 15 }, { 20, 20 } } }, + { CYCLES_XADD, { { 0, 0 }, { 4, 4 }, { 4, 4 }, { 2, 2 } } }, + + // Pentium+ + { CYCLES_CMPXCHG8B, { { 0, 0 }, { 0, 0 }, { 10, 10 }, { 6, 6 } } }, + { CYCLES_CPUID, { { 0, 0 }, { 0, 0 }, { 14, 14 }, { 12, 12 } } }, + { CYCLES_CPUID_EAX1, { { 0, 0 }, { 0, 0 }, { 14, 14 }, { 12, 12 } } }, + { CYCLES_RDTSC, { { 0, 0 }, { 0, 0 }, { 20, 20 }, { 1, 1 } } }, + { CYCLES_RSM, { { 0, 0 }, { 0, 0 }, { 82, 82 }, { 57, 57 } } }, + { CYCLES_RDMSR, { { 0, 0 }, { 0, 0 }, { 20, 20 }, { 1, 1 } } }, + + // FPU + { CYCLES_FABS, { { 0, 0 }, { 3, 3 }, { 1, 1 }, { 1, 1 } } }, + { CYCLES_FADD, { { 0, 0 }, { 8, 8 }, { 3, 3 }, { 1, 1 } } }, + { CYCLES_FBLD, { { 0, 0 }, { 70, 70 }, { 48, 48 }, { 1, 1 } } }, + { CYCLES_FBSTP, { { 0, 0 }, {172,172 }, {148,148 }, { 1, 1 } } }, + { CYCLES_FCHS, { { 0, 0 }, { 6, 6 }, { 1, 1 }, { 1, 1 } } }, + { CYCLES_FCLEX, { { 0, 0 }, { 7, 7 }, { 9, 9 }, { 1, 1 } } }, + { CYCLES_FCOM, { { 0, 0 }, { 4, 4 }, { 4, 4 }, { 1, 1 } } }, + { CYCLES_FCOS, { { 0, 0 }, {255,255 }, {124,124 }, { 1, 1 } } }, + { CYCLES_FDECSTP, { { 0, 0 }, { 3, 3 }, { 1, 1 }, { 1, 1 } } }, + { CYCLES_FDISI, { { 0, 0 }, { 3, 3 }, { 1, 1 }, { 1, 1 } } }, + { CYCLES_FDIV, { { 0, 0 }, { 73, 73 }, { 39, 39 }, { 1, 1 } } }, + { CYCLES_FDIVR, { { 0, 0 }, { 73, 73 }, { 39, 39 }, { 1, 1 } } }, + { CYCLES_FENI, { { 0, 0 }, { 3, 3 }, { 1, 1 }, { 1, 1 } } }, + { CYCLES_FFREE, { { 0, 0 }, { 3, 3 }, { 1, 1 }, { 1, 1 } } }, + { CYCLES_FIADD, { { 0, 0 }, { 20, 20 }, { 7, 7 }, { 1, 1 } } }, + { CYCLES_FICOM, { { 0, 0 }, { 16, 16 }, { 8, 8 }, { 1, 1 } } }, + { CYCLES_FIDIV, { { 0, 0 }, { 85, 85 }, { 42, 42 }, { 1, 1 } } }, + { CYCLES_FILD, { { 0, 0 }, { 13, 13 }, { 3, 3 }, { 1, 1 } } }, + { CYCLES_FIMUL, { { 0, 0 }, { 23, 23 }, { 7, 7 }, { 1, 1 } } }, + { CYCLES_FINCSTP, { { 0, 0 }, { 3, 3 }, { 1, 1 }, { 1, 1 } } }, + { CYCLES_FINIT, { { 0, 0 }, { 17, 17 }, { 16, 16 }, { 1, 1 } } }, + { CYCLES_FIST, { { 0, 0 }, { 29, 29 }, { 6, 6 }, { 1, 1 } } }, + { CYCLES_FISUB, { { 0, 0 }, { 20, 20 }, { 7, 7 }, { 1, 1 } } }, + { CYCLES_FLD, { { 0, 0 }, { 4, 4 }, { 1, 1 }, { 1, 1 } } }, + { CYCLES_FLDZ, { { 0, 0 }, { 4, 4 }, { 2, 2 }, { 1, 1 } } }, + { CYCLES_FLD1, { { 0, 0 }, { 4, 4 }, { 2, 2 }, { 1, 1 } } }, + { CYCLES_FLDL2E, { { 0, 0 }, { 8, 8 }, { 5, 5 }, { 1, 1 } } }, + { CYCLES_FLDL2T, { { 0, 0 }, { 8, 8 }, { 5, 5 }, { 1, 1 } } }, + { CYCLES_FLDLG2, { { 0, 0 }, { 8, 8 }, { 5, 5 }, { 1, 1 } } }, + { CYCLES_FLDLN2, { { 0, 0 }, { 8, 8 }, { 5, 5 }, { 1, 1 } } }, + { CYCLES_FLDPI, { { 0, 0 }, { 8, 8 }, { 5, 5 }, { 1, 1 } } }, + { CYCLES_FLDCW, { { 0, 0 }, { 4, 4 }, { 7, 7 }, { 1, 1 } } }, + { CYCLES_FLDENV, { { 0, 0 }, { 44, 44 }, { 37, 37 }, { 1, 1 } } }, + { CYCLES_FMUL, { { 0, 0 }, { 16, 16 }, { 3, 3 }, { 1, 1 } } }, + { CYCLES_FNOP, { { 0, 0 }, { 3, 3 }, { 1, 1 }, { 1, 1 } } }, + { CYCLES_FPATAN, { { 0, 0 }, {218,218 }, {173,173 }, { 1, 1 } } }, + { CYCLES_FPREM, { { 0, 0 }, { 70, 70 }, { 16, 16 }, { 1, 1 } } }, + { CYCLES_FPREM1, { { 0, 0 }, { 72, 72 }, { 20, 20 }, { 1, 1 } } }, + { CYCLES_FPTAN, { { 0, 0 }, {200,200 }, {173,173 }, { 1, 1 } } }, + { CYCLES_FRNDINT, { { 0, 0 }, { 21, 21 }, { 9, 9 }, { 1, 1 } } }, + { CYCLES_FRSTOR, { { 0, 0 }, {131,131 }, { 75, 75 }, { 1, 1 } } }, + { CYCLES_FSAVE, { { 0, 0 }, {154,154 }, {127,127 }, { 1, 1 } } }, + { CYCLES_FSCALE, { { 0, 0 }, { 30, 30 }, { 20, 20 }, { 1, 1 } } }, + { CYCLES_FSETPM, { { 0, 0 }, { 3, 3 }, { 1, 1 }, { 1, 1 } } }, + { CYCLES_FSIN, { { 0, 0 }, {255,255 }, {126,126 }, { 1, 1 } } }, + { CYCLES_FSINCOS, { { 0, 0 }, {255,255 }, {137,137 }, { 1, 1 } } }, + { CYCLES_FSQRT, { { 0, 0 }, { 83, 83 }, { 70, 70 }, { 1, 1 } } }, + { CYCLES_FST, { { 0, 0 }, { 3, 3 }, { 1, 1 }, { 1, 1 } } }, + { CYCLES_FSTCW, { { 0, 0 }, { 3, 3 }, { 2, 2 }, { 1, 1 } } }, + { CYCLES_FSTENV, { { 0, 0 }, { 67, 67 }, { 48, 48 }, { 1, 1 } } }, + { CYCLES_FSTSW, { { 0, 0 }, { 3, 3 }, { 2, 2 }, { 1, 1 } } }, + { CYCLES_FSUB, { { 0, 0 }, { 8, 8 }, { 3, 3 }, { 1, 1 } } }, + { CYCLES_FSUBR, { { 0, 0 }, { 8, 8 }, { 3, 3 }, { 1, 1 } } }, + { CYCLES_FTST, { { 0, 0 }, { 4, 4 }, { 4, 4 }, { 1, 1 } } }, + { CYCLES_FUCOM, { { 0, 0 }, { 4, 4 }, { 4, 4 }, { 1, 1 } } }, + { CYCLES_FXAM, { { 0, 0 }, { 8, 8 }, { 21, 21 }, { 1, 1 } } }, + { CYCLES_FXCH, { { 0, 0 }, { 4, 4 }, { 1, 1 }, { 1, 1 } } }, + { CYCLES_FXTRACT, { { 0, 0 }, { 16, 16 }, { 13, 13 }, { 1, 1 } } }, + { CYCLES_FYL2X, { { 0, 0 }, {196,196 }, {111,111 }, { 1, 1 } } }, + { CYCLES_FYL2XPI, { { 0, 0 }, {171,171 }, {103,103 }, { 1, 1 } } }, + { CYCLES_CMPXCHG_REG_REG_T, { { 0, 0 }, { 6, 6 }, { 6, 6 }, { 6, 6 } } }, + { CYCLES_CMPXCHG_REG_REG_F, { { 0, 0 }, { 9, 9 }, { 9, 9 }, { 9, 9 } } }, + { CYCLES_CMPXCHG_REG_MEM_T, { { 0, 0 }, { 7, 7 }, { 7, 7 }, { 7, 7 } } }, + { CYCLES_CMPXCHG_REG_MEM_F, { { 0, 0 }, { 10, 10 }, { 10, 10 }, { 10, 10 } } }, +}; + +#endif /* __CYCLES_H__ */ diff --git a/src/devices/cpu/i386/i386.c b/src/devices/cpu/i386/i386.c new file mode 100644 index 00000000000..9f6b218ed9e --- /dev/null +++ b/src/devices/cpu/i386/i386.c @@ -0,0 +1,4525 @@ +// license:BSD-3-Clause +// copyright-holders:Ville Linde, Barry Rodewald, Carl, Philip Bennett +/* + Intel 386 emulator + + Written by Ville Linde + + Currently supports: + Intel 386 + Intel 486 + Intel Pentium + Cyrix MediaGX + Intel Pentium MMX + Intel Pentium Pro + Intel Pentium II + Intel Pentium III + Intel Pentium 4 +*/ + +#include "emu.h" +#include "debugger.h" +#include "i386priv.h" +#include "i386.h" + +#include "debug/debugcpu.h" + +/* seems to be defined on mingw-gcc */ +#undef i386 + +const device_type I386 = &device_creator; +const device_type I386SX = &device_creator; +const device_type I486 = &device_creator; +const device_type PENTIUM = &device_creator; +const device_type MEDIAGX = &device_creator; +const device_type PENTIUM_PRO = &device_creator; +const device_type PENTIUM_MMX = &device_creator; +const device_type PENTIUM2 = &device_creator; +const device_type PENTIUM3 = &device_creator; +const device_type PENTIUM4 = &device_creator; + + +i386_device::i386_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : cpu_device(mconfig, I386, "I386", tag, owner, clock, "i386", __FILE__) + , m_program_config("program", ENDIANNESS_LITTLE, 32, 32, 0) + , m_io_config("io", ENDIANNESS_LITTLE, 32, 16, 0) + , m_smiact(*this) +{ + m_program_config.m_logaddr_width = 32; + m_program_config.m_page_shift = 12; +} + + +i386_device::i386_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source, int program_data_width, int program_addr_width, int io_data_width) + : cpu_device(mconfig, type, name, tag, owner, clock, shortname, source) + , m_program_config("program", ENDIANNESS_LITTLE, program_data_width, program_addr_width, 0) + , m_io_config("io", ENDIANNESS_LITTLE, io_data_width, 16, 0) + , m_smiact(*this) +{ + m_program_config.m_logaddr_width = 32; + m_program_config.m_page_shift = 12; +} + +i386SX_device::i386SX_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : i386_device(mconfig, I386SX, "I386SX", tag, owner, clock, "i386sx", __FILE__, 16, 24, 16) +{ +} + +i486_device::i486_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : i386_device(mconfig, I486, "I486", tag, owner, clock, "i486", __FILE__) +{ +} + +pentium_device::pentium_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : i386_device(mconfig, PENTIUM, "PENTIUM", tag, owner, clock, "pentium", __FILE__) +{ +} + +pentium_device::pentium_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : i386_device(mconfig, type, name, tag, owner, clock, shortname, source) +{ +} + +mediagx_device::mediagx_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : i386_device(mconfig, MEDIAGX, "MEDIAGX", tag, owner, clock, "mediagx", __FILE__) +{ +} + +pentium_pro_device::pentium_pro_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : pentium_device(mconfig, PENTIUM_PRO, "Pentium Pro", tag, owner, clock, "pentium_pro", __FILE__) +{ +} + +pentium_mmx_device::pentium_mmx_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : pentium_device(mconfig, PENTIUM_MMX, "Pentium MMX", tag, owner, clock, "pentium_mmx", __FILE__) +{ +} + +pentium2_device::pentium2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : pentium_device(mconfig, PENTIUM2, "Pentium II", tag, owner, clock, "pentium2", __FILE__) +{ +} + +pentium3_device::pentium3_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : pentium_device(mconfig, PENTIUM3, "Pentium III", tag, owner, clock, "pentium3", __FILE__) +{ +} + +pentium4_device::pentium4_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : pentium_device(mconfig, PENTIUM4, "Pentium 4", tag, owner, clock, "pentium4", __FILE__) +{ +} + + +int i386_parity_table[256]; +MODRM_TABLE i386_MODRM_table[256]; + +#define FAULT(fault,error) {m_ext = 1; i386_trap_with_error(fault,0,0,error); return;} +#define FAULT_EXP(fault,error) {m_ext = 1; i386_trap_with_error(fault,0,trap_level+1,error); return;} + +/*************************************************************************/ + +UINT32 i386_device::i386_load_protected_mode_segment(I386_SREG *seg, UINT64 *desc ) +{ + UINT32 v1,v2; + UINT32 base, limit; + int entry; + + if(!seg->selector) + { + seg->flags = 0; + seg->base = 0; + seg->limit = 0; + seg->d = 0; + seg->valid = false; + return 0; + } + + if ( seg->selector & 0x4 ) + { + base = m_ldtr.base; + limit = m_ldtr.limit; + } else { + base = m_gdtr.base; + limit = m_gdtr.limit; + } + + entry = seg->selector & ~0x7; + if (limit == 0 || entry + 7 > limit) + return 0; + + v1 = READ32PL0(base + entry ); + v2 = READ32PL0(base + entry + 4 ); + + seg->flags = (v2 >> 8) & 0xf0ff; + seg->base = (v2 & 0xff000000) | ((v2 & 0xff) << 16) | ((v1 >> 16) & 0xffff); + seg->limit = (v2 & 0xf0000) | (v1 & 0xffff); + if (seg->flags & 0x8000) + seg->limit = (seg->limit << 12) | 0xfff; + seg->d = (seg->flags & 0x4000) ? 1 : 0; + seg->valid = true; + + if(desc) + *desc = ((UINT64)v2<<32)|v1; + return 1; +} + +void i386_device::i386_load_call_gate(I386_CALL_GATE *gate) +{ + UINT32 v1,v2; + UINT32 base,limit; + int entry; + + if ( gate->segment & 0x4 ) + { + base = m_ldtr.base; + limit = m_ldtr.limit; + } else { + base = m_gdtr.base; + limit = m_gdtr.limit; + } + + entry = gate->segment & ~0x7; + if (limit == 0 || entry + 7 > limit) + return; + + v1 = READ32PL0(base + entry ); + v2 = READ32PL0(base + entry + 4 ); + + /* Note that for task gates, offset and dword_count are not used */ + gate->selector = (v1 >> 16) & 0xffff; + gate->offset = (v1 & 0x0000ffff) | (v2 & 0xffff0000); + gate->ar = (v2 >> 8) & 0xff; + gate->dword_count = v2 & 0x001f; + gate->present = (gate->ar >> 7) & 0x01; + gate->dpl = (gate->ar >> 5) & 0x03; +} + +void i386_device::i386_set_descriptor_accessed(UINT16 selector) +{ + // assume the selector is valid, we don't need to check it again + UINT32 base, addr; + UINT8 rights; + if(!(selector & ~3)) + return; + + if ( selector & 0x4 ) + base = m_ldtr.base; + else + base = m_gdtr.base; + + addr = base + (selector & ~7) + 5; + i386_translate_address(TRANSLATE_READ, &addr, NULL); + rights = m_program->read_byte(addr); + // Should a fault be thrown if the table is read only? + m_program->write_byte(addr, rights | 1); +} + +void i386_device::i386_load_segment_descriptor(int segment ) +{ + if (PROTECTED_MODE) + { + if (!V8086_MODE) + { + i386_load_protected_mode_segment(&m_sreg[segment], NULL ); + if(m_sreg[segment].selector) + i386_set_descriptor_accessed(m_sreg[segment].selector); + } + else + { + m_sreg[segment].base = m_sreg[segment].selector << 4; + m_sreg[segment].limit = 0xffff; + m_sreg[segment].flags = (segment == CS) ? 0x00fb : 0x00f3; + m_sreg[segment].d = 0; + m_sreg[segment].valid = true; + } + } + else + { + m_sreg[segment].base = m_sreg[segment].selector << 4; + m_sreg[segment].d = 0; + m_sreg[segment].valid = true; + + if( segment == CS && !m_performed_intersegment_jump ) + m_sreg[segment].base |= 0xfff00000; + } +} + +/* Retrieves the stack selector located in the current TSS */ +UINT32 i386_device::i386_get_stack_segment(UINT8 privilege) +{ + UINT32 ret; + if(privilege >= 3) + return 0; + + if(m_task.flags & 8) + ret = READ32PL0((m_task.base+8) + (8*privilege)); + else + ret = READ16PL0((m_task.base+4) + (4*privilege)); + + return ret; +} + +/* Retrieves the stack pointer located in the current TSS */ +UINT32 i386_device::i386_get_stack_ptr(UINT8 privilege) +{ + UINT32 ret; + if(privilege >= 3) + return 0; + + if(m_task.flags & 8) + ret = READ32PL0((m_task.base+4) + (8*privilege)); + else + ret = READ16PL0((m_task.base+2) + (4*privilege)); + + return ret; +} + +UINT32 i386_device::get_flags() +{ + UINT32 f = 0x2; + f |= m_CF; + f |= m_PF << 2; + f |= m_AF << 4; + f |= m_ZF << 6; + f |= m_SF << 7; + f |= m_TF << 8; + f |= m_IF << 9; + f |= m_DF << 10; + f |= m_OF << 11; + f |= m_IOP1 << 12; + f |= m_IOP2 << 13; + f |= m_NT << 14; + f |= m_RF << 16; + f |= m_VM << 17; + f |= m_AC << 18; + f |= m_VIF << 19; + f |= m_VIP << 20; + f |= m_ID << 21; + return (m_eflags & ~m_eflags_mask) | (f & m_eflags_mask); +} + +void i386_device::set_flags(UINT32 f ) +{ + m_CF = (f & 0x1) ? 1 : 0; + m_PF = (f & 0x4) ? 1 : 0; + m_AF = (f & 0x10) ? 1 : 0; + m_ZF = (f & 0x40) ? 1 : 0; + m_SF = (f & 0x80) ? 1 : 0; + m_TF = (f & 0x100) ? 1 : 0; + m_IF = (f & 0x200) ? 1 : 0; + m_DF = (f & 0x400) ? 1 : 0; + m_OF = (f & 0x800) ? 1 : 0; + m_IOP1 = (f & 0x1000) ? 1 : 0; + m_IOP2 = (f & 0x2000) ? 1 : 0; + m_NT = (f & 0x4000) ? 1 : 0; + m_RF = (f & 0x10000) ? 1 : 0; + m_VM = (f & 0x20000) ? 1 : 0; + m_AC = (f & 0x40000) ? 1 : 0; + m_VIF = (f & 0x80000) ? 1 : 0; + m_VIP = (f & 0x100000) ? 1 : 0; + m_ID = (f & 0x200000) ? 1 : 0; + m_eflags = f & m_eflags_mask; +} + +void i386_device::sib_byte(UINT8 mod, UINT32* out_ea, UINT8* out_segment) +{ + UINT32 ea = 0; + UINT8 segment = 0; + UINT8 scale, i, base; + UINT8 sib = FETCH(); + scale = (sib >> 6) & 0x3; + i = (sib >> 3) & 0x7; + base = sib & 0x7; + + switch( base ) + { + case 0: ea = REG32(EAX); segment = DS; break; + case 1: ea = REG32(ECX); segment = DS; break; + case 2: ea = REG32(EDX); segment = DS; break; + case 3: ea = REG32(EBX); segment = DS; break; + case 4: ea = REG32(ESP); segment = SS; break; + case 5: + if( mod == 0 ) { + ea = FETCH32(); + segment = DS; + } else if( mod == 1 ) { + ea = REG32(EBP); + segment = SS; + } else if( mod == 2 ) { + ea = REG32(EBP); + segment = SS; + } + break; + case 6: ea = REG32(ESI); segment = DS; break; + case 7: ea = REG32(EDI); segment = DS; break; + } + switch( i ) + { + case 0: ea += REG32(EAX) * (1 << scale); break; + case 1: ea += REG32(ECX) * (1 << scale); break; + case 2: ea += REG32(EDX) * (1 << scale); break; + case 3: ea += REG32(EBX) * (1 << scale); break; + case 4: break; + case 5: ea += REG32(EBP) * (1 << scale); break; + case 6: ea += REG32(ESI) * (1 << scale); break; + case 7: ea += REG32(EDI) * (1 << scale); break; + } + *out_ea = ea; + *out_segment = segment; +} + +void i386_device::modrm_to_EA(UINT8 mod_rm, UINT32* out_ea, UINT8* out_segment) +{ + INT8 disp8; + INT16 disp16; + INT32 disp32; + UINT8 mod = (mod_rm >> 6) & 0x3; + UINT8 rm = mod_rm & 0x7; + UINT32 ea; + UINT8 segment; + + if( mod_rm >= 0xc0 ) + fatalerror("i386: Called modrm_to_EA with modrm value %02X!\n",mod_rm); + + + if( m_address_size ) { + switch( rm ) + { + default: + case 0: ea = REG32(EAX); segment = DS; break; + case 1: ea = REG32(ECX); segment = DS; break; + case 2: ea = REG32(EDX); segment = DS; break; + case 3: ea = REG32(EBX); segment = DS; break; + case 4: sib_byte(mod, &ea, &segment ); break; + case 5: + if( mod == 0 ) { + ea = FETCH32(); segment = DS; + } else { + ea = REG32(EBP); segment = SS; + } + break; + case 6: ea = REG32(ESI); segment = DS; break; + case 7: ea = REG32(EDI); segment = DS; break; + } + if( mod == 1 ) { + disp8 = FETCH(); + ea += (INT32)disp8; + } else if( mod == 2 ) { + disp32 = FETCH32(); + ea += disp32; + } + + if( m_segment_prefix ) + segment = m_segment_override; + + *out_ea = ea; + *out_segment = segment; + + } else { + switch( rm ) + { + default: + case 0: ea = REG16(BX) + REG16(SI); segment = DS; break; + case 1: ea = REG16(BX) + REG16(DI); segment = DS; break; + case 2: ea = REG16(BP) + REG16(SI); segment = SS; break; + case 3: ea = REG16(BP) + REG16(DI); segment = SS; break; + case 4: ea = REG16(SI); segment = DS; break; + case 5: ea = REG16(DI); segment = DS; break; + case 6: + if( mod == 0 ) { + ea = FETCH16(); segment = DS; + } else { + ea = REG16(BP); segment = SS; + } + break; + case 7: ea = REG16(BX); segment = DS; break; + } + if( mod == 1 ) { + disp8 = FETCH(); + ea += (INT32)disp8; + } else if( mod == 2 ) { + disp16 = FETCH16(); + ea += (INT32)disp16; + } + + if( m_segment_prefix ) + segment = m_segment_override; + + *out_ea = ea & 0xffff; + *out_segment = segment; + } +} + +UINT32 i386_device::GetNonTranslatedEA(UINT8 modrm,UINT8 *seg) +{ + UINT8 segment; + UINT32 ea; + modrm_to_EA(modrm, &ea, &segment ); + if(seg) *seg = segment; + return ea; +} + +UINT32 i386_device::GetEA(UINT8 modrm, int rwn) +{ + UINT8 segment; + UINT32 ea; + modrm_to_EA(modrm, &ea, &segment ); + return i386_translate(segment, ea, rwn ); +} + +/* Check segment register for validity when changing privilege level after an RETF */ +void i386_device::i386_check_sreg_validity(int reg) +{ + UINT16 selector = m_sreg[reg].selector; + UINT8 CPL = m_CPL; + UINT8 DPL,RPL; + I386_SREG desc; + int invalid = 0; + + memset(&desc, 0, sizeof(desc)); + desc.selector = selector; + i386_load_protected_mode_segment(&desc,NULL); + DPL = (desc.flags >> 5) & 0x03; // descriptor privilege level + RPL = selector & 0x03; + + /* Must be within the relevant descriptor table limits */ + if(selector & 0x04) + { + if((selector & ~0x07) > m_ldtr.limit) + invalid = 1; + } + else + { + if((selector & ~0x07) > m_gdtr.limit) + invalid = 1; + } + + /* Must be either a data or readable code segment */ + if(((desc.flags & 0x0018) == 0x0018 && (desc.flags & 0x0002)) || (desc.flags & 0x0018) == 0x0010) + invalid = 0; + else + invalid = 1; + + /* If a data segment or non-conforming code segment, then either DPL >= CPL or DPL >= RPL */ + if(((desc.flags & 0x0018) == 0x0018 && (desc.flags & 0x0004) == 0) || (desc.flags & 0x0018) == 0x0010) + { + if((DPL < CPL) || (DPL < RPL)) + invalid = 1; + } + + /* if segment is invalid, then segment register is nulled */ + if(invalid != 0) + { + m_sreg[reg].selector = 0; + i386_load_segment_descriptor(reg); + } +} + +int i386_device::i386_limit_check(int seg, UINT32 offset) +{ + if(PROTECTED_MODE && !V8086_MODE) + { + if((m_sreg[seg].flags & 0x0018) == 0x0010 && m_sreg[seg].flags & 0x0004) // if expand-down data segment + { + // compare if greater then 0xffffffff when we're passed the access size + if((offset <= m_sreg[seg].limit) || ((m_sreg[seg].d)?0:(offset > 0xffff))) + { + logerror("Limit check at 0x%08x failed. Segment %04x, limit %08x, offset %08x (expand-down)\n",m_pc,m_sreg[seg].selector,m_sreg[seg].limit,offset); + return 1; + } + } + else + { + if(offset > m_sreg[seg].limit) + { + logerror("Limit check at 0x%08x failed. Segment %04x, limit %08x, offset %08x\n",m_pc,m_sreg[seg].selector,m_sreg[seg].limit,offset); + return 1; + } + } + } + return 0; +} + +void i386_device::i386_sreg_load(UINT16 selector, UINT8 reg, bool *fault) +{ + // Checks done when MOV changes a segment register in protected mode + UINT8 CPL,RPL,DPL; + + CPL = m_CPL; + RPL = selector & 0x0003; + + if(!PROTECTED_MODE || V8086_MODE) + { + m_sreg[reg].selector = selector; + i386_load_segment_descriptor(reg); + if(fault) *fault = false; + return; + } + + if(fault) *fault = true; + if(reg == SS) + { + I386_SREG stack; + + memset(&stack, 0, sizeof(stack)); + stack.selector = selector; + i386_load_protected_mode_segment(&stack,NULL); + DPL = (stack.flags >> 5) & 0x03; + + if((selector & ~0x0003) == 0) + { + logerror("SReg Load (%08x): Selector is null.\n",m_pc); + FAULT(FAULT_GP,0) + } + if(selector & 0x0004) // LDT + { + if((selector & ~0x0007) > m_ldtr.limit) + { + logerror("SReg Load (%08x): Selector is out of LDT bounds.\n",m_pc); + FAULT(FAULT_GP,selector & ~0x03) + } + } + else // GDT + { + if((selector & ~0x0007) > m_gdtr.limit) + { + logerror("SReg Load (%08x): Selector is out of GDT bounds.\n",m_pc); + FAULT(FAULT_GP,selector & ~0x03) + } + } + if (RPL != CPL) + { + logerror("SReg Load (%08x): Selector RPL does not equal CPL.\n",m_pc); + FAULT(FAULT_GP,selector & ~0x03) + } + if(((stack.flags & 0x0018) != 0x10) && (stack.flags & 0x0002) != 0) + { + logerror("SReg Load (%08x): Segment is not a writable data segment.\n",m_pc); + FAULT(FAULT_GP,selector & ~0x03) + } + if(DPL != CPL) + { + logerror("SReg Load (%08x): Segment DPL does not equal CPL.\n",m_pc); + FAULT(FAULT_GP,selector & ~0x03) + } + if(!(stack.flags & 0x0080)) + { + logerror("SReg Load (%08x): Segment is not present.\n",m_pc); + FAULT(FAULT_SS,selector & ~0x03) + } + } + if(reg == DS || reg == ES || reg == FS || reg == GS) + { + I386_SREG desc; + + if((selector & ~0x0003) == 0) + { + m_sreg[reg].selector = selector; + i386_load_segment_descriptor(reg ); + if(fault) *fault = false; + return; + } + + memset(&desc, 0, sizeof(desc)); + desc.selector = selector; + i386_load_protected_mode_segment(&desc,NULL); + DPL = (desc.flags >> 5) & 0x03; + + if(selector & 0x0004) // LDT + { + if((selector & ~0x0007) > m_ldtr.limit) + { + logerror("SReg Load (%08x): Selector is out of LDT bounds.\n",m_pc); + FAULT(FAULT_GP,selector & ~0x03) + } + } + else // GDT + { + if((selector & ~0x0007) > m_gdtr.limit) + { + logerror("SReg Load (%08x): Selector is out of GDT bounds.\n",m_pc); + FAULT(FAULT_GP,selector & ~0x03) + } + } + if((desc.flags & 0x0018) != 0x10) + { + if((((desc.flags & 0x0002) != 0) && ((desc.flags & 0x0018) != 0x18)) || !(desc.flags & 0x10)) + { + logerror("SReg Load (%08x): Segment is not a data segment or readable code segment.\n",m_pc); + FAULT(FAULT_GP,selector & ~0x03) + } + } + if(((desc.flags & 0x0018) == 0x10) || ((!(desc.flags & 0x0004)) && ((desc.flags & 0x0018) == 0x18))) + { + // if data or non-conforming code segment + if((RPL > DPL) || (CPL > DPL)) + { + logerror("SReg Load (%08x): Selector RPL or CPL is not less or equal to segment DPL.\n",m_pc); + FAULT(FAULT_GP,selector & ~0x03) + } + } + if(!(desc.flags & 0x0080)) + { + logerror("SReg Load (%08x): Segment is not present.\n",m_pc); + FAULT(FAULT_NP,selector & ~0x03) + } + } + + m_sreg[reg].selector = selector; + i386_load_segment_descriptor(reg ); + if(fault) *fault = false; +} + +void i386_device::i386_trap(int irq, int irq_gate, int trap_level) +{ + /* I386 Interrupts/Traps/Faults: + * + * 0x00 Divide by zero + * 0x01 Debug exception + * 0x02 NMI + * 0x03 Int3 + * 0x04 Overflow + * 0x05 Array bounds check + * 0x06 Illegal Opcode + * 0x07 FPU not available + * 0x08 Double fault + * 0x09 Coprocessor segment overrun + * 0x0a Invalid task state + * 0x0b Segment not present + * 0x0c Stack exception + * 0x0d General Protection Fault + * 0x0e Page fault + * 0x0f Reserved + * 0x10 Coprocessor error + */ + UINT32 v1, v2; + UINT32 offset, oldflags = get_flags(); + UINT16 segment; + int entry = irq * (PROTECTED_MODE ? 8 : 4); + int SetRPL = 0; + m_lock = false; + + if( !(PROTECTED_MODE) ) + { + /* 16-bit */ + PUSH16(oldflags & 0xffff ); + PUSH16(m_sreg[CS].selector ); + if(irq == 3 || irq == 4 || irq == 9 || irq_gate == 1) + PUSH16(m_eip ); + else + PUSH16(m_prev_eip ); + + m_sreg[CS].selector = READ16(m_idtr.base + entry + 2 ); + m_eip = READ16(m_idtr.base + entry ); + + m_TF = 0; + m_IF = 0; + } + else + { + int type; + UINT16 flags; + I386_SREG desc; + UINT8 CPL = m_CPL, DPL = 0; //, RPL = 0; + + /* 32-bit */ + v1 = READ32PL0(m_idtr.base + entry ); + v2 = READ32PL0(m_idtr.base + entry + 4 ); + offset = (v2 & 0xffff0000) | (v1 & 0xffff); + segment = (v1 >> 16) & 0xffff; + type = (v2>>8) & 0x1F; + flags = (v2>>8) & 0xf0ff; + + if(trap_level == 2) + { + logerror("IRQ: Double fault.\n"); + FAULT_EXP(FAULT_DF,0); + } + if(trap_level >= 3) + { + logerror("IRQ: Triple fault. CPU reset.\n"); + set_input_line(INPUT_LINE_RESET, PULSE_LINE); + return; + } + + /* segment privilege checks */ + if(entry >= m_idtr.limit) + { + logerror("IRQ (%08x): Vector %02xh is past IDT limit.\n",m_pc,entry); + FAULT_EXP(FAULT_GP,entry+2) + } + /* segment must be interrupt gate, trap gate, or task gate */ + if(type != 0x05 && type != 0x06 && type != 0x07 && type != 0x0e && type != 0x0f) + { + logerror("IRQ#%02x (%08x): Vector segment %04x is not an interrupt, trap or task gate.\n",irq,m_pc,segment); + FAULT_EXP(FAULT_GP,entry+2) + } + + if(m_ext == 0) // if software interrupt (caused by INT/INTO/INT3) + { + if(((flags >> 5) & 0x03) < CPL) + { + logerror("IRQ (%08x): Software IRQ - gate DPL is less than CPL.\n",m_pc); + FAULT_EXP(FAULT_GP,entry+2) + } + if(V8086_MODE) + { + if((!m_IOP1 || !m_IOP2) && (m_opcode != 0xcc)) + { + logerror("IRQ (%08x): Is in Virtual 8086 mode and IOPL != 3.\n",m_pc); + FAULT(FAULT_GP,0) + } + + } + } + + if((flags & 0x0080) == 0) + { + logerror("IRQ: Vector segment is not present.\n"); + FAULT_EXP(FAULT_NP,entry+2) + } + + if(type == 0x05) + { + /* Task gate */ + memset(&desc, 0, sizeof(desc)); + desc.selector = segment; + i386_load_protected_mode_segment(&desc,NULL); + if(segment & 0x04) + { + logerror("IRQ: Task gate: TSS is not in the GDT.\n"); + FAULT_EXP(FAULT_TS,segment & ~0x03); + } + else + { + if(segment > m_gdtr.limit) + { + logerror("IRQ: Task gate: TSS is past GDT limit.\n"); + FAULT_EXP(FAULT_TS,segment & ~0x03); + } + } + if((desc.flags & 0x000f) != 0x09 && (desc.flags & 0x000f) != 0x01) + { + logerror("IRQ: Task gate: TSS is not an available TSS.\n"); + FAULT_EXP(FAULT_TS,segment & ~0x03); + } + if((desc.flags & 0x0080) == 0) + { + logerror("IRQ: Task gate: TSS is not present.\n"); + FAULT_EXP(FAULT_NP,segment & ~0x03); + } + if(!(irq == 3 || irq == 4 || irq == 9 || irq_gate == 1)) + m_eip = m_prev_eip; + if(desc.flags & 0x08) + i386_task_switch(desc.selector,1); + else + i286_task_switch(desc.selector,1); + return; + } + else + { + /* Interrupt or Trap gate */ + memset(&desc, 0, sizeof(desc)); + desc.selector = segment; + i386_load_protected_mode_segment(&desc,NULL); + CPL = m_CPL; // current privilege level + DPL = (desc.flags >> 5) & 0x03; // descriptor privilege level +// RPL = segment & 0x03; // requested privilege level + + if((segment & ~0x03) == 0) + { + logerror("IRQ: Gate segment is null.\n"); + FAULT_EXP(FAULT_GP,m_ext) + } + if(segment & 0x04) + { + if((segment & ~0x07) > m_ldtr.limit) + { + logerror("IRQ: Gate segment is past LDT limit.\n"); + FAULT_EXP(FAULT_GP,(segment & 0x03)+m_ext) + } + } + else + { + if((segment & ~0x07) > m_gdtr.limit) + { + logerror("IRQ: Gate segment is past GDT limit.\n"); + FAULT_EXP(FAULT_GP,(segment & 0x03)+m_ext) + } + } + if((desc.flags & 0x0018) != 0x18) + { + logerror("IRQ: Gate descriptor is not a code segment.\n"); + FAULT_EXP(FAULT_GP,(segment & 0x03)+m_ext) + } + if((desc.flags & 0x0080) == 0) + { + logerror("IRQ: Gate segment is not present.\n"); + FAULT_EXP(FAULT_NP,(segment & 0x03)+m_ext) + } + if((desc.flags & 0x0004) == 0 && (DPL < CPL)) + { + /* IRQ to inner privilege */ + I386_SREG stack; + UINT32 newESP,oldSS,oldESP; + + if(V8086_MODE && DPL) + { + logerror("IRQ: Gate to CPL>0 from VM86 mode.\n"); + FAULT_EXP(FAULT_GP,segment & ~0x03); + } + /* Check new stack segment in TSS */ + memset(&stack, 0, sizeof(stack)); + stack.selector = i386_get_stack_segment(DPL); + i386_load_protected_mode_segment(&stack,NULL); + oldSS = m_sreg[SS].selector; + if(flags & 0x0008) + oldESP = REG32(ESP); + else + oldESP = REG16(SP); + if((stack.selector & ~0x03) == 0) + { + logerror("IRQ: New stack selector is null.\n"); + FAULT_EXP(FAULT_GP,m_ext) + } + if(stack.selector & 0x04) + { + if((stack.selector & ~0x07) > m_ldtr.base) + { + logerror("IRQ: New stack selector is past LDT limit.\n"); + FAULT_EXP(FAULT_TS,(stack.selector & ~0x03)+m_ext) + } + } + else + { + if((stack.selector & ~0x07) > m_gdtr.base) + { + logerror("IRQ: New stack selector is past GDT limit.\n"); + FAULT_EXP(FAULT_TS,(stack.selector & ~0x03)+m_ext) + } + } + if((stack.selector & 0x03) != DPL) + { + logerror("IRQ: New stack selector RPL is not equal to code segment DPL.\n"); + FAULT_EXP(FAULT_TS,(stack.selector & ~0x03)+m_ext) + } + if(((stack.flags >> 5) & 0x03) != DPL) + { + logerror("IRQ: New stack segment DPL is not equal to code segment DPL.\n"); + FAULT_EXP(FAULT_TS,(stack.selector & ~0x03)+m_ext) + } + if(((stack.flags & 0x0018) != 0x10) && (stack.flags & 0x0002) != 0) + { + logerror("IRQ: New stack segment is not a writable data segment.\n"); + FAULT_EXP(FAULT_TS,(stack.selector & ~0x03)+m_ext) // #TS(stack selector + EXT) + } + if((stack.flags & 0x0080) == 0) + { + logerror("IRQ: New stack segment is not present.\n"); + FAULT_EXP(FAULT_SS,(stack.selector & ~0x03)+m_ext) // #TS(stack selector + EXT) + } + newESP = i386_get_stack_ptr(DPL); + if(type & 0x08) // 32-bit gate + { + if(((newESP < (V8086_MODE?36:20)) && !(stack.flags & 0x4)) || ((~stack.limit < (~(newESP - 1) + (V8086_MODE?36:20))) && (stack.flags & 0x4))) + { + logerror("IRQ: New stack has no space for return addresses.\n"); + FAULT_EXP(FAULT_SS,0) + } + } + else // 16-bit gate + { + newESP &= 0xffff; + if(((newESP < (V8086_MODE?18:10)) && !(stack.flags & 0x4)) || ((~stack.limit < (~(newESP - 1) + (V8086_MODE?18:10))) && (stack.flags & 0x4))) + { + logerror("IRQ: New stack has no space for return addresses.\n"); + FAULT_EXP(FAULT_SS,0) + } + } + if(offset > desc.limit) + { + logerror("IRQ: New EIP is past code segment limit.\n"); + FAULT_EXP(FAULT_GP,0) + } + /* change CPL before accessing the stack */ + m_CPL = DPL; + /* check for page fault at new stack TODO: check if stack frame crosses page boundary */ + WRITE_TEST(stack.base+newESP-1); + /* Load new stack segment descriptor */ + m_sreg[SS].selector = stack.selector; + i386_load_protected_mode_segment(&m_sreg[SS],NULL); + i386_set_descriptor_accessed(stack.selector); + REG32(ESP) = newESP; + if(V8086_MODE) + { + //logerror("IRQ (%08x): Interrupt during V8086 task\n",m_pc); + if(type & 0x08) + { + PUSH32(m_sreg[GS].selector & 0xffff); + PUSH32(m_sreg[FS].selector & 0xffff); + PUSH32(m_sreg[DS].selector & 0xffff); + PUSH32(m_sreg[ES].selector & 0xffff); + } + else + { + PUSH16(m_sreg[GS].selector); + PUSH16(m_sreg[FS].selector); + PUSH16(m_sreg[DS].selector); + PUSH16(m_sreg[ES].selector); + } + m_sreg[GS].selector = 0; + m_sreg[FS].selector = 0; + m_sreg[DS].selector = 0; + m_sreg[ES].selector = 0; + m_VM = 0; + i386_load_segment_descriptor(GS); + i386_load_segment_descriptor(FS); + i386_load_segment_descriptor(DS); + i386_load_segment_descriptor(ES); + } + if(type & 0x08) + { + // 32-bit gate + PUSH32(oldSS); + PUSH32(oldESP); + } + else + { + // 16-bit gate + PUSH16(oldSS); + PUSH16(oldESP); + } + SetRPL = 1; + } + else + { + int stack_limit; + if((desc.flags & 0x0004) || (DPL == CPL)) + { + /* IRQ to same privilege */ + if(V8086_MODE && !m_ext) + { + logerror("IRQ: Gate to same privilege from VM86 mode.\n"); + FAULT_EXP(FAULT_GP,segment & ~0x03); + } + if(type == 0x0e || type == 0x0f) // 32-bit gate + stack_limit = 10; + else + stack_limit = 6; + // TODO: Add check for error code (2 extra bytes) + if(REG32(ESP) < stack_limit) + { + logerror("IRQ: Stack has no space left (needs %i bytes).\n",stack_limit); + FAULT_EXP(FAULT_SS,0) + } + if(offset > desc.limit) + { + logerror("IRQ: Gate segment offset is past segment limit.\n"); + FAULT_EXP(FAULT_GP,0) + } + SetRPL = 1; + } + else + { + logerror("IRQ: Gate descriptor is non-conforming, and DPL does not equal CPL.\n"); + FAULT_EXP(FAULT_GP,segment) + } + } + } + UINT32 tempSP = REG32(ESP); + try + { + // this is ugly but the alternative is worse + if(type != 0x0e && type != 0x0f) // if not 386 interrupt or trap gate + { + PUSH16(oldflags & 0xffff ); + PUSH16(m_sreg[CS].selector ); + if(irq == 3 || irq == 4 || irq == 9 || irq_gate == 1) + PUSH16(m_eip ); + else + PUSH16(m_prev_eip ); + } + else + { + PUSH32(oldflags & 0x00ffffff ); + PUSH32(m_sreg[CS].selector ); + if(irq == 3 || irq == 4 || irq == 9 || irq_gate == 1) + PUSH32(m_eip ); + else + PUSH32(m_prev_eip ); + } + } + catch(UINT64 e) + { + REG32(ESP) = tempSP; + throw e; + } + if(SetRPL != 0) + segment = (segment & ~0x03) | m_CPL; + m_sreg[CS].selector = segment; + m_eip = offset; + + if(type == 0x0e || type == 0x06) + m_IF = 0; + m_TF = 0; + m_NT = 0; + } + + i386_load_segment_descriptor(CS); + CHANGE_PC(m_eip); + +} + +void i386_device::i386_trap_with_error(int irq, int irq_gate, int trap_level, UINT32 error) +{ + i386_trap(irq,irq_gate,trap_level); + if(irq == 8 || irq == 10 || irq == 11 || irq == 12 || irq == 13 || irq == 14) + { + // for these exceptions, an error code is pushed onto the stack by the processor. + // no error code is pushed for software interrupts, either. + if(PROTECTED_MODE) + { + UINT32 entry = irq * 8; + UINT32 v2,type; + v2 = READ32PL0(m_idtr.base + entry + 4 ); + type = (v2>>8) & 0x1F; + if(type == 5) + { + v2 = READ32PL0(m_idtr.base + entry); + v2 = READ32PL0(m_gdtr.base + ((v2 >> 16) & 0xfff8) + 4); + type = (v2>>8) & 0x1F; + } + if(type >= 9) + PUSH32(error); + else + PUSH16(error); + } + else + PUSH16(error); + } +} + + +void i386_device::i286_task_switch(UINT16 selector, UINT8 nested) +{ + UINT32 tss; + I386_SREG seg; + UINT16 old_task; + UINT8 ar_byte; // access rights byte + + /* TODO: Task State Segment privilege checks */ + + /* For tasks that aren't nested, clear the busy bit in the task's descriptor */ + if(nested == 0) + { + if(m_task.segment & 0x0004) + { + ar_byte = READ8(m_ldtr.base + (m_task.segment & ~0x0007) + 5); + WRITE8(m_ldtr.base + (m_task.segment & ~0x0007) + 5,ar_byte & ~0x02); + } + else + { + ar_byte = READ8(m_gdtr.base + (m_task.segment & ~0x0007) + 5); + WRITE8(m_gdtr.base + (m_task.segment & ~0x0007) + 5,ar_byte & ~0x02); + } + } + + /* Save the state of the current task in the current TSS (TR register base) */ + tss = m_task.base; + WRITE16(tss+0x0e,m_eip & 0x0000ffff); + WRITE16(tss+0x10,get_flags() & 0x0000ffff); + WRITE16(tss+0x12,REG16(AX)); + WRITE16(tss+0x14,REG16(CX)); + WRITE16(tss+0x16,REG16(DX)); + WRITE16(tss+0x18,REG16(BX)); + WRITE16(tss+0x1a,REG16(SP)); + WRITE16(tss+0x1c,REG16(BP)); + WRITE16(tss+0x1e,REG16(SI)); + WRITE16(tss+0x20,REG16(DI)); + WRITE16(tss+0x22,m_sreg[ES].selector); + WRITE16(tss+0x24,m_sreg[CS].selector); + WRITE16(tss+0x26,m_sreg[SS].selector); + WRITE16(tss+0x28,m_sreg[DS].selector); + + old_task = m_task.segment; + + /* Load task register with the selector of the incoming task */ + m_task.segment = selector; + memset(&seg, 0, sizeof(seg)); + seg.selector = m_task.segment; + i386_load_protected_mode_segment(&seg,NULL); + m_task.limit = seg.limit; + m_task.base = seg.base; + m_task.flags = seg.flags; + + /* Set TS bit in CR0 */ + m_cr[0] |= 0x08; + + /* Load incoming task state from the new task's TSS */ + tss = m_task.base; + m_ldtr.segment = READ16(tss+0x2a) & 0xffff; + seg.selector = m_ldtr.segment; + i386_load_protected_mode_segment(&seg,NULL); + m_ldtr.limit = seg.limit; + m_ldtr.base = seg.base; + m_ldtr.flags = seg.flags; + m_eip = READ16(tss+0x0e); + set_flags(READ16(tss+0x10)); + REG16(AX) = READ16(tss+0x12); + REG16(CX) = READ16(tss+0x14); + REG16(DX) = READ16(tss+0x16); + REG16(BX) = READ16(tss+0x18); + REG16(SP) = READ16(tss+0x1a); + REG16(BP) = READ16(tss+0x1c); + REG16(SI) = READ16(tss+0x1e); + REG16(DI) = READ16(tss+0x20); + m_sreg[ES].selector = READ16(tss+0x22) & 0xffff; + i386_load_segment_descriptor(ES); + m_sreg[CS].selector = READ16(tss+0x24) & 0xffff; + i386_load_segment_descriptor(CS); + m_sreg[SS].selector = READ16(tss+0x26) & 0xffff; + i386_load_segment_descriptor(SS); + m_sreg[DS].selector = READ16(tss+0x28) & 0xffff; + i386_load_segment_descriptor(DS); + + /* Set the busy bit in the new task's descriptor */ + if(selector & 0x0004) + { + ar_byte = READ8(m_ldtr.base + (selector & ~0x0007) + 5); + WRITE8(m_ldtr.base + (selector & ~0x0007) + 5,ar_byte | 0x02); + } + else + { + ar_byte = READ8(m_gdtr.base + (selector & ~0x0007) + 5); + WRITE8(m_gdtr.base + (selector & ~0x0007) + 5,ar_byte | 0x02); + } + + /* For nested tasks, we write the outgoing task's selector to the back-link field of the new TSS, + and set the NT flag in the EFLAGS register */ + if(nested != 0) + { + WRITE16(tss+0,old_task); + m_NT = 1; + } + CHANGE_PC(m_eip); + + m_CPL = (m_sreg[SS].flags >> 5) & 3; +// printf("286 Task Switch from selector %04x to %04x\n",old_task,selector); +} + +void i386_device::i386_task_switch(UINT16 selector, UINT8 nested) +{ + UINT32 tss; + I386_SREG seg; + UINT16 old_task; + UINT8 ar_byte; // access rights byte + UINT32 oldcr3 = m_cr[3]; + + /* TODO: Task State Segment privilege checks */ + + /* For tasks that aren't nested, clear the busy bit in the task's descriptor */ + if(nested == 0) + { + if(m_task.segment & 0x0004) + { + ar_byte = READ8(m_ldtr.base + (m_task.segment & ~0x0007) + 5); + WRITE8(m_ldtr.base + (m_task.segment & ~0x0007) + 5,ar_byte & ~0x02); + } + else + { + ar_byte = READ8(m_gdtr.base + (m_task.segment & ~0x0007) + 5); + WRITE8(m_gdtr.base + (m_task.segment & ~0x0007) + 5,ar_byte & ~0x02); + } + } + + /* Save the state of the current task in the current TSS (TR register base) */ + tss = m_task.base; + WRITE32(tss+0x1c,m_cr[3]); // correct? + WRITE32(tss+0x20,m_eip); + WRITE32(tss+0x24,get_flags()); + WRITE32(tss+0x28,REG32(EAX)); + WRITE32(tss+0x2c,REG32(ECX)); + WRITE32(tss+0x30,REG32(EDX)); + WRITE32(tss+0x34,REG32(EBX)); + WRITE32(tss+0x38,REG32(ESP)); + WRITE32(tss+0x3c,REG32(EBP)); + WRITE32(tss+0x40,REG32(ESI)); + WRITE32(tss+0x44,REG32(EDI)); + WRITE32(tss+0x48,m_sreg[ES].selector); + WRITE32(tss+0x4c,m_sreg[CS].selector); + WRITE32(tss+0x50,m_sreg[SS].selector); + WRITE32(tss+0x54,m_sreg[DS].selector); + WRITE32(tss+0x58,m_sreg[FS].selector); + WRITE32(tss+0x5c,m_sreg[GS].selector); + + old_task = m_task.segment; + + /* Load task register with the selector of the incoming task */ + m_task.segment = selector; + memset(&seg, 0, sizeof(seg)); + seg.selector = m_task.segment; + i386_load_protected_mode_segment(&seg,NULL); + m_task.limit = seg.limit; + m_task.base = seg.base; + m_task.flags = seg.flags; + + /* Set TS bit in CR0 */ + m_cr[0] |= 0x08; + + /* Load incoming task state from the new task's TSS */ + tss = m_task.base; + m_ldtr.segment = READ32(tss+0x60) & 0xffff; + seg.selector = m_ldtr.segment; + i386_load_protected_mode_segment(&seg,NULL); + m_ldtr.limit = seg.limit; + m_ldtr.base = seg.base; + m_ldtr.flags = seg.flags; + m_eip = READ32(tss+0x20); + set_flags(READ32(tss+0x24)); + REG32(EAX) = READ32(tss+0x28); + REG32(ECX) = READ32(tss+0x2c); + REG32(EDX) = READ32(tss+0x30); + REG32(EBX) = READ32(tss+0x34); + REG32(ESP) = READ32(tss+0x38); + REG32(EBP) = READ32(tss+0x3c); + REG32(ESI) = READ32(tss+0x40); + REG32(EDI) = READ32(tss+0x44); + m_sreg[ES].selector = READ32(tss+0x48) & 0xffff; + i386_load_segment_descriptor(ES); + m_sreg[CS].selector = READ32(tss+0x4c) & 0xffff; + i386_load_segment_descriptor(CS); + m_sreg[SS].selector = READ32(tss+0x50) & 0xffff; + i386_load_segment_descriptor(SS); + m_sreg[DS].selector = READ32(tss+0x54) & 0xffff; + i386_load_segment_descriptor(DS); + m_sreg[FS].selector = READ32(tss+0x58) & 0xffff; + i386_load_segment_descriptor(FS); + m_sreg[GS].selector = READ32(tss+0x5c) & 0xffff; + i386_load_segment_descriptor(GS); + /* For nested tasks, we write the outgoing task's selector to the back-link field of the new TSS, + and set the NT flag in the EFLAGS register before setting cr3 as the old tss address might be gone */ + if(nested != 0) + { + WRITE32(tss+0,old_task); + m_NT = 1; + } + m_cr[3] = READ32(tss+0x1c); // CR3 (PDBR) + if(oldcr3 != m_cr[3]) + vtlb_flush_dynamic(m_vtlb); + + /* Set the busy bit in the new task's descriptor */ + if(selector & 0x0004) + { + ar_byte = READ8(m_ldtr.base + (selector & ~0x0007) + 5); + WRITE8(m_ldtr.base + (selector & ~0x0007) + 5,ar_byte | 0x02); + } + else + { + ar_byte = READ8(m_gdtr.base + (selector & ~0x0007) + 5); + WRITE8(m_gdtr.base + (selector & ~0x0007) + 5,ar_byte | 0x02); + } + + CHANGE_PC(m_eip); + + m_CPL = (m_sreg[SS].flags >> 5) & 3; +// printf("386 Task Switch from selector %04x to %04x\n",old_task,selector); +} + +void i386_device::i386_check_irq_line() +{ + if(!m_smm && m_smi) + { + pentium_smi(); + return; + } + + /* Check if the interrupts are enabled */ + if ( (m_irq_state) && m_IF ) + { + m_cycles -= 2; + i386_trap(standard_irq_callback(0), 1, 0); + } +} + +void i386_device::i386_protected_mode_jump(UINT16 seg, UINT32 off, int indirect, int operand32) +{ + I386_SREG desc; + I386_CALL_GATE call_gate; + UINT8 CPL,DPL,RPL; + UINT8 SetRPL = 0; + UINT16 segment = seg; + UINT32 offset = off; + + /* Check selector is not null */ + if((segment & ~0x03) == 0) + { + logerror("JMP: Segment is null.\n"); + FAULT(FAULT_GP,0) + } + /* Selector is within descriptor table limit */ + if((segment & 0x04) == 0) + { + /* check GDT limit */ + if((segment & ~0x07) > (m_gdtr.limit)) + { + logerror("JMP: Segment is past GDT limit.\n"); + FAULT(FAULT_GP,segment & 0xfffc) + } + } + else + { + /* check LDT limit */ + if((segment & ~0x07) > (m_ldtr.limit)) + { + logerror("JMP: Segment is past LDT limit.\n"); + FAULT(FAULT_GP,segment & 0xfffc) + } + } + /* Determine segment type */ + memset(&desc, 0, sizeof(desc)); + desc.selector = segment; + i386_load_protected_mode_segment(&desc,NULL); + CPL = m_CPL; // current privilege level + DPL = (desc.flags >> 5) & 0x03; // descriptor privilege level + RPL = segment & 0x03; // requested privilege level + if((desc.flags & 0x0018) == 0x0018) + { + /* code segment */ + if((desc.flags & 0x0004) == 0) + { + /* non-conforming */ + if(RPL > CPL) + { + logerror("JMP: RPL %i is less than CPL %i\n",RPL,CPL); + FAULT(FAULT_GP,segment & 0xfffc) + } + if(DPL != CPL) + { + logerror("JMP: DPL %i is not equal CPL %i\n",DPL,CPL); + FAULT(FAULT_GP,segment & 0xfffc) + } + } + else + { + /* conforming */ + if(DPL > CPL) + { + logerror("JMP: DPL %i is less than CPL %i\n",DPL,CPL); + FAULT(FAULT_GP,segment & 0xfffc) + } + } + SetRPL = 1; + if((desc.flags & 0x0080) == 0) + { + logerror("JMP: Segment is not present\n"); + FAULT(FAULT_NP,segment & 0xfffc) + } + if(offset > desc.limit) + { + logerror("JMP: Offset is past segment limit\n"); + FAULT(FAULT_GP,0) + } + } + else + { + if((desc.flags & 0x0010) != 0) + { + logerror("JMP: Segment is a data segment\n"); + FAULT(FAULT_GP,segment & 0xfffc) // #GP (cannot execute code in a data segment) + } + else + { + switch(desc.flags & 0x000f) + { + case 0x01: // 286 Available TSS + case 0x09: // 386 Available TSS + logerror("JMP: Available 386 TSS at %08x\n",m_pc); + memset(&desc, 0, sizeof(desc)); + desc.selector = segment; + i386_load_protected_mode_segment(&desc,NULL); + DPL = (desc.flags >> 5) & 0x03; // descriptor privilege level + if(DPL < CPL) + { + logerror("JMP: TSS: DPL %i is less than CPL %i\n",DPL,CPL); + FAULT(FAULT_GP,segment & 0xfffc) + } + if(DPL < RPL) + { + logerror("JMP: TSS: DPL %i is less than TSS RPL %i\n",DPL,RPL); + FAULT(FAULT_GP,segment & 0xfffc) + } + if((desc.flags & 0x0080) == 0) + { + logerror("JMP: TSS: Segment is not present\n"); + FAULT(FAULT_GP,segment & 0xfffc) + } + if(desc.flags & 0x0008) + i386_task_switch(desc.selector,0); + else + i286_task_switch(desc.selector,0); + return; + case 0x04: // 286 Call Gate + case 0x0c: // 386 Call Gate + //logerror("JMP: Call gate at %08x\n",m_pc); + SetRPL = 1; + memset(&call_gate, 0, sizeof(call_gate)); + call_gate.segment = segment; + i386_load_call_gate(&call_gate); + DPL = call_gate.dpl; + if(DPL < CPL) + { + logerror("JMP: Call Gate: DPL %i is less than CPL %i\n",DPL,CPL); + FAULT(FAULT_GP,segment & 0xfffc) + } + if(DPL < RPL) + { + logerror("JMP: Call Gate: DPL %i is less than RPL %i\n",DPL,RPL); + FAULT(FAULT_GP,segment & 0xfffc) + } + if((desc.flags & 0x0080) == 0) + { + logerror("JMP: Call Gate: Segment is not present\n"); + FAULT(FAULT_NP,segment & 0xfffc) + } + /* Now we examine the segment that the call gate refers to */ + if(call_gate.selector == 0) + { + logerror("JMP: Call Gate: Gate selector is null\n"); + FAULT(FAULT_GP,0) + } + if(call_gate.selector & 0x04) + { + if((call_gate.selector & ~0x07) > m_ldtr.limit) + { + logerror("JMP: Call Gate: Gate Selector is past LDT segment limit\n"); + FAULT(FAULT_GP,call_gate.selector & 0xfffc) + } + } + else + { + if((call_gate.selector & ~0x07) > m_gdtr.limit) + { + logerror("JMP: Call Gate: Gate Selector is past GDT segment limit\n"); + FAULT(FAULT_GP,call_gate.selector & 0xfffc) + } + } + desc.selector = call_gate.selector; + i386_load_protected_mode_segment(&desc,NULL); + DPL = (desc.flags >> 5) & 0x03; + if((desc.flags & 0x0018) != 0x18) + { + logerror("JMP: Call Gate: Gate does not point to a code segment\n"); + FAULT(FAULT_GP,call_gate.selector & 0xfffc) + } + if((desc.flags & 0x0004) == 0) + { // non-conforming + if(DPL != CPL) + { + logerror("JMP: Call Gate: Gate DPL does not equal CPL\n"); + FAULT(FAULT_GP,call_gate.selector & 0xfffc) + } + } + else + { // conforming + if(DPL > CPL) + { + logerror("JMP: Call Gate: Gate DPL is greater than CPL\n"); + FAULT(FAULT_GP,call_gate.selector & 0xfffc) + } + } + if((desc.flags & 0x0080) == 0) + { + logerror("JMP: Call Gate: Gate Segment is not present\n"); + FAULT(FAULT_NP,call_gate.selector & 0xfffc) + } + if(call_gate.offset > desc.limit) + { + logerror("JMP: Call Gate: Gate offset is past Gate segment limit\n"); + FAULT(FAULT_GP,call_gate.selector & 0xfffc) + } + segment = call_gate.selector; + offset = call_gate.offset; + break; + case 0x05: // Task Gate + logerror("JMP: Task gate at %08x\n",m_pc); + memset(&call_gate, 0, sizeof(call_gate)); + call_gate.segment = segment; + i386_load_call_gate(&call_gate); + DPL = call_gate.dpl; + if(DPL < CPL) + { + logerror("JMP: Task Gate: Gate DPL %i is less than CPL %i\n",DPL,CPL); + FAULT(FAULT_GP,segment & 0xfffc) + } + if(DPL < RPL) + { + logerror("JMP: Task Gate: Gate DPL %i is less than CPL %i\n",DPL,CPL); + FAULT(FAULT_GP,segment & 0xfffc) + } + if(call_gate.present == 0) + { + logerror("JMP: Task Gate: Gate is not present.\n"); + FAULT(FAULT_GP,segment & 0xfffc) + } + /* Check the TSS that the task gate points to */ + desc.selector = call_gate.selector; + i386_load_protected_mode_segment(&desc,NULL); + DPL = (desc.flags >> 5) & 0x03; // descriptor privilege level + RPL = call_gate.selector & 0x03; // requested privilege level + if(call_gate.selector & 0x04) + { + logerror("JMP: Task Gate TSS: TSS must be global.\n"); + FAULT(FAULT_GP,call_gate.selector & 0xfffc) + } + else + { + if((call_gate.selector & ~0x07) > m_gdtr.limit) + { + logerror("JMP: Task Gate TSS: TSS is past GDT limit.\n"); + FAULT(FAULT_GP,call_gate.selector & 0xfffc) + } + } + if((call_gate.ar & 0x000f) == 0x0009 || (call_gate.ar & 0x000f) == 0x0001) + { + logerror("JMP: Task Gate TSS: Segment is not an available TSS.\n"); + FAULT(FAULT_GP,call_gate.selector & 0xfffc) + } + if(call_gate.present == 0) + { + logerror("JMP: Task Gate TSS: TSS is not present.\n"); + FAULT(FAULT_NP,call_gate.selector & 0xfffc) + } + if(call_gate.ar & 0x08) + i386_task_switch(call_gate.selector,0); + else + i286_task_switch(call_gate.selector,0); + return; + default: // invalid segment type + logerror("JMP: Invalid segment type (%i) to jump to.\n",desc.flags & 0x000f); + FAULT(FAULT_GP,segment & 0xfffc) + } + } + } + + if(SetRPL != 0) + segment = (segment & ~0x03) | m_CPL; + if(operand32 == 0) + m_eip = offset & 0x0000ffff; + else + m_eip = offset; + m_sreg[CS].selector = segment; + m_performed_intersegment_jump = 1; + i386_load_segment_descriptor(CS); + CHANGE_PC(m_eip); +} + +void i386_device::i386_protected_mode_call(UINT16 seg, UINT32 off, int indirect, int operand32) +{ + I386_SREG desc; + I386_CALL_GATE gate; + UINT8 SetRPL = 0; + UINT8 CPL, DPL, RPL; + UINT16 selector = seg; + UINT32 offset = off; + int x; + + if((selector & ~0x03) == 0) + { + logerror("CALL (%08x): Selector is null.\n",m_pc); + FAULT(FAULT_GP,0) // #GP(0) + } + if(selector & 0x04) + { + if((selector & ~0x07) > m_ldtr.limit) + { + logerror("CALL: Selector is past LDT limit.\n"); + FAULT(FAULT_GP,selector & ~0x03) // #GP(selector) + } + } + else + { + if((selector & ~0x07) > m_gdtr.limit) + { + logerror("CALL: Selector is past GDT limit.\n"); + FAULT(FAULT_GP,selector & ~0x03) // #GP(selector) + } + } + + /* Determine segment type */ + memset(&desc, 0, sizeof(desc)); + desc.selector = selector; + i386_load_protected_mode_segment(&desc,NULL); + CPL = m_CPL; // current privilege level + DPL = (desc.flags >> 5) & 0x03; // descriptor privilege level + RPL = selector & 0x03; // requested privilege level + if((desc.flags & 0x0018) == 0x18) // is a code segment + { + if(desc.flags & 0x0004) + { + /* conforming */ + if(DPL > CPL) + { + logerror("CALL: Code segment DPL %i is greater than CPL %i\n",DPL,CPL); + FAULT(FAULT_GP,selector & ~0x03) // #GP(selector) + } + } + else + { + /* non-conforming */ + if(RPL > CPL) + { + logerror("CALL: RPL %i is greater than CPL %i\n",RPL,CPL); + FAULT(FAULT_GP,selector & ~0x03) // #GP(selector) + } + if(DPL != CPL) + { + logerror("CALL: Code segment DPL %i is not equal to CPL %i\n",DPL,CPL); + FAULT(FAULT_GP,selector & ~0x03) // #GP(selector) + } + } + SetRPL = 1; + if((desc.flags & 0x0080) == 0) + { + logerror("CALL (%08x): Code segment is not present.\n",m_pc); + FAULT(FAULT_NP,selector & ~0x03) // #NP(selector) + } + if (operand32 != 0) // if 32-bit + { + if(i386_limit_check(SS, REG32(ESP) - 8)) + { + logerror("CALL (%08x): Stack has no room for return address.\n",m_pc); + FAULT(FAULT_SS,0) // #SS(0) + } + } + else + { + if(i386_limit_check(SS, (REG16(SP) - 4) & 0xffff)) + { + logerror("CALL (%08x): Stack has no room for return address.\n",m_pc); + FAULT(FAULT_SS,0) // #SS(0) + } + } + if(offset > desc.limit) + { + logerror("CALL: EIP is past segment limit.\n"); + FAULT(FAULT_GP,0) // #GP(0) + } + } + else + { + /* special segment type */ + if(desc.flags & 0x0010) + { + logerror("CALL: Segment is a data segment.\n"); + FAULT(FAULT_GP,desc.selector & ~0x03) // #GP(selector) + } + else + { + switch(desc.flags & 0x000f) + { + case 0x01: // Available 286 TSS + case 0x09: // Available 386 TSS + logerror("CALL: Available TSS at %08x\n",m_pc); + if(DPL < CPL) + { + logerror("CALL: TSS: DPL is less than CPL.\n"); + FAULT(FAULT_TS,selector & ~0x03) // #TS(selector) + } + if(DPL < RPL) + { + logerror("CALL: TSS: DPL is less than RPL.\n"); + FAULT(FAULT_TS,selector & ~0x03) // #TS(selector) + } + if(desc.flags & 0x0002) + { + logerror("CALL: TSS: TSS is busy.\n"); + FAULT(FAULT_TS,selector & ~0x03) // #TS(selector) + } + if((desc.flags & 0x0080) == 0) + { + logerror("CALL: TSS: Segment %02x is not present.\n",selector); + FAULT(FAULT_NP,selector & ~0x03) // #NP(selector) + } + if(desc.flags & 0x08) + i386_task_switch(desc.selector,1); + else + i286_task_switch(desc.selector,1); + return; + case 0x04: // 286 call gate + case 0x0c: // 386 call gate + if((desc.flags & 0x000f) == 0x04) + operand32 = 0; + else + operand32 = 1; + memset(&gate, 0, sizeof(gate)); + gate.segment = selector; + i386_load_call_gate(&gate); + DPL = gate.dpl; + //logerror("CALL: Call gate at %08x (%i parameters)\n",m_pc,gate.dword_count); + if(DPL < CPL) + { + logerror("CALL: Call gate DPL %i is less than CPL %i.\n",DPL,CPL); + FAULT(FAULT_GP,desc.selector & ~0x03) // #GP(selector) + } + if(DPL < RPL) + { + logerror("CALL: Call gate DPL %i is less than RPL %i.\n",DPL,RPL); + FAULT(FAULT_GP,desc.selector & ~0x03) // #GP(selector) + } + if(gate.present == 0) + { + logerror("CALL: Call gate is not present.\n"); + FAULT(FAULT_NP,desc.selector & ~0x03) // #GP(selector) + } + desc.selector = gate.selector; + if((gate.selector & ~0x03) == 0) + { + logerror("CALL: Call gate: Segment is null.\n"); + FAULT(FAULT_GP,0) // #GP(0) + } + if(desc.selector & 0x04) + { + if((desc.selector & ~0x07) > m_ldtr.limit) + { + logerror("CALL: Call gate: Segment is past LDT limit\n"); + FAULT(FAULT_GP,desc.selector & ~0x03) // #GP(selector) + } + } + else + { + if((desc.selector & ~0x07) > m_gdtr.limit) + { + logerror("CALL: Call gate: Segment is past GDT limit\n"); + FAULT(FAULT_GP,desc.selector & ~0x03) // #GP(selector) + } + } + i386_load_protected_mode_segment(&desc,NULL); + if((desc.flags & 0x0018) != 0x18) + { + logerror("CALL: Call gate: Segment is not a code segment.\n"); + FAULT(FAULT_GP,desc.selector & ~0x03) // #GP(selector) + } + DPL = ((desc.flags >> 5) & 0x03); + if(DPL > CPL) + { + logerror("CALL: Call gate: Segment DPL %i is greater than CPL %i.\n",DPL,CPL); + FAULT(FAULT_GP,desc.selector & ~0x03) // #GP(selector) + } + if((desc.flags & 0x0080) == 0) + { + logerror("CALL (%08x): Code segment is not present.\n",m_pc); + FAULT(FAULT_NP,desc.selector & ~0x03) // #NP(selector) + } + if(DPL < CPL && (desc.flags & 0x0004) == 0) + { + I386_SREG stack; + I386_SREG temp; + UINT32 oldSS,oldESP; + /* more privilege */ + /* Check new SS segment for privilege level from TSS */ + memset(&stack, 0, sizeof(stack)); + stack.selector = i386_get_stack_segment(DPL); + i386_load_protected_mode_segment(&stack,NULL); + if((stack.selector & ~0x03) == 0) + { + logerror("CALL: Call gate: TSS selector is null\n"); + FAULT(FAULT_TS,0) // #TS(0) + } + if(stack.selector & 0x04) + { + if((stack.selector & ~0x07) > m_ldtr.limit) + { + logerror("CALL: Call gate: TSS selector is past LDT limit\n"); + FAULT(FAULT_TS,stack.selector) // #TS(SS selector) + } + } + else + { + if((stack.selector & ~0x07) > m_gdtr.limit) + { + logerror("CALL: Call gate: TSS selector is past GDT limit\n"); + FAULT(FAULT_TS,stack.selector) // #TS(SS selector) + } + } + if((stack.selector & 0x03) != DPL) + { + logerror("CALL: Call gate: Stack selector RPL does not equal code segment DPL %i\n",DPL); + FAULT(FAULT_TS,stack.selector) // #TS(SS selector) + } + if(((stack.flags >> 5) & 0x03) != DPL) + { + logerror("CALL: Call gate: Stack DPL does not equal code segment DPL %i\n",DPL); + FAULT(FAULT_TS,stack.selector) // #TS(SS selector) + } + if((stack.flags & 0x0018) != 0x10 && (stack.flags & 0x0002)) + { + logerror("CALL: Call gate: Stack segment is not a writable data segment\n"); + FAULT(FAULT_TS,stack.selector) // #TS(SS selector) + } + if((stack.flags & 0x0080) == 0) + { + logerror("CALL: Call gate: Stack segment is not present\n"); + FAULT(FAULT_SS,stack.selector) // #SS(SS selector) + } + UINT32 newESP = i386_get_stack_ptr(DPL); + if(!stack.d) + { + newESP &= 0xffff; + } + if(operand32 != 0) + { + if(newESP < ((gate.dword_count & 0x1f) + 16)) + { + logerror("CALL: Call gate: New stack has no room for 32-bit return address and parameters.\n"); + FAULT(FAULT_SS,0) // #SS(0) + } + if(gate.offset > desc.limit) + { + logerror("CALL: Call gate: EIP is past segment limit.\n"); + FAULT(FAULT_GP,0) // #GP(0) + } + } + else + { + if(newESP < ((gate.dword_count & 0x1f) + 8)) + { + logerror("CALL: Call gate: New stack has no room for 16-bit return address and parameters.\n"); + FAULT(FAULT_SS,0) // #SS(0) + } + if((gate.offset & 0xffff) > desc.limit) + { + logerror("CALL: Call gate: IP is past segment limit.\n"); + FAULT(FAULT_GP,0) // #GP(0) + } + } + selector = gate.selector; + offset = gate.offset; + + m_CPL = (stack.flags >> 5) & 0x03; + /* check for page fault at new stack */ + WRITE_TEST(stack.base+newESP-1); + /* switch to new stack */ + oldSS = m_sreg[SS].selector; + m_sreg[SS].selector = i386_get_stack_segment(m_CPL); + if(operand32 != 0) + { + oldESP = REG32(ESP); + } + else + { + oldESP = REG16(SP); + } + i386_load_segment_descriptor(SS ); + REG32(ESP) = newESP; + + if(operand32 != 0) + { + PUSH32(oldSS); + PUSH32(oldESP); + } + else + { + PUSH16(oldSS); + PUSH16(oldESP & 0xffff); + } + + memset(&temp, 0, sizeof(temp)); + temp.selector = oldSS; + i386_load_protected_mode_segment(&temp,NULL); + /* copy parameters from old stack to new stack */ + for(x=(gate.dword_count & 0x1f)-1;x>=0;x--) + { + UINT32 addr = oldESP + (operand32?(x*4):(x*2)); + addr = temp.base + (temp.d?addr:(addr&0xffff)); + if(operand32) + PUSH32(READ32(addr)); + else + PUSH16(READ16(addr)); + } + SetRPL = 1; + } + else + { + /* same privilege */ + if (operand32 != 0) // if 32-bit + { + if(i386_limit_check(SS, REG32(ESP) - 8)) + { + logerror("CALL: Stack has no room for return address.\n"); + FAULT(FAULT_SS,0) // #SS(0) + } + selector = gate.selector; + offset = gate.offset; + } + else + { + if(i386_limit_check(SS, (REG16(SP) - 4) & 0xffff)) + { + logerror("CALL: Stack has no room for return address.\n"); + FAULT(FAULT_SS,0) // #SS(0) + } + selector = gate.selector; + offset = gate.offset & 0xffff; + } + if(offset > desc.limit) + { + logerror("CALL: EIP is past segment limit.\n"); + FAULT(FAULT_GP,0) // #GP(0) + } + SetRPL = 1; + } + break; + case 0x05: // task gate + logerror("CALL: Task gate at %08x\n",m_pc); + memset(&gate, 0, sizeof(gate)); + gate.segment = selector; + i386_load_call_gate(&gate); + DPL = gate.dpl; + if(DPL < CPL) + { + logerror("CALL: Task Gate: Gate DPL is less than CPL.\n"); + FAULT(FAULT_TS,selector & ~0x03) // #TS(selector) + } + if(DPL < RPL) + { + logerror("CALL: Task Gate: Gate DPL is less than RPL.\n"); + FAULT(FAULT_TS,selector & ~0x03) // #TS(selector) + } + if((gate.ar & 0x0080) == 0) + { + logerror("CALL: Task Gate: Gate is not present.\n"); + FAULT(FAULT_NP,selector & ~0x03) // #NP(selector) + } + /* Check the TSS that the task gate points to */ + desc.selector = gate.selector; + i386_load_protected_mode_segment(&desc,NULL); + if(gate.selector & 0x04) + { + logerror("CALL: Task Gate: TSS is not global.\n"); + FAULT(FAULT_TS,gate.selector & ~0x03) // #TS(selector) + } + else + { + if((gate.selector & ~0x07) > m_gdtr.limit) + { + logerror("CALL: Task Gate: TSS is past GDT limit.\n"); + FAULT(FAULT_TS,gate.selector & ~0x03) // #TS(selector) + } + } + if(desc.flags & 0x0002) + { + logerror("CALL: Task Gate: TSS is busy.\n"); + FAULT(FAULT_TS,gate.selector & ~0x03) // #TS(selector) + } + if((desc.flags & 0x0080) == 0) + { + logerror("CALL: Task Gate: TSS is not present.\n"); + FAULT(FAULT_NP,gate.selector & ~0x03) // #TS(selector) + } + if(desc.flags & 0x08) + i386_task_switch(desc.selector,1); // with nesting + else + i286_task_switch(desc.selector,1); + return; + default: + logerror("CALL: Invalid special segment type (%i) to jump to.\n",desc.flags & 0x000f); + FAULT(FAULT_GP,selector & ~0x07) // #GP(selector) + } + } + } + + if(SetRPL != 0) + selector = (selector & ~0x03) | m_CPL; + + UINT32 tempSP = REG32(ESP); + try + { + // this is ugly but the alternative is worse + if(operand32 == 0) + { + /* 16-bit operand size */ + PUSH16(m_sreg[CS].selector ); + PUSH16(m_eip & 0x0000ffff ); + m_sreg[CS].selector = selector; + m_performed_intersegment_jump = 1; + m_eip = offset; + i386_load_segment_descriptor(CS); + } + else + { + /* 32-bit operand size */ + PUSH32(m_sreg[CS].selector ); + PUSH32(m_eip ); + m_sreg[CS].selector = selector; + m_performed_intersegment_jump = 1; + m_eip = offset; + i386_load_segment_descriptor(CS ); + } + } + catch(UINT64 e) + { + REG32(ESP) = tempSP; + throw e; + } + + CHANGE_PC(m_eip); +} + +void i386_device::i386_protected_mode_retf(UINT8 count, UINT8 operand32) +{ + UINT32 newCS, newEIP; + I386_SREG desc; + UINT8 CPL, RPL, DPL; + + UINT32 ea = i386_translate(SS, (STACK_32BIT)?REG32(ESP):REG16(SP), 0); + + if(operand32 == 0) + { + newEIP = READ16(ea) & 0xffff; + newCS = READ16(ea+2) & 0xffff; + } + else + { + newEIP = READ32(ea); + newCS = READ32(ea+4) & 0xffff; + } + + memset(&desc, 0, sizeof(desc)); + desc.selector = newCS; + i386_load_protected_mode_segment(&desc,NULL); + CPL = m_CPL; // current privilege level + DPL = (desc.flags >> 5) & 0x03; // descriptor privilege level + RPL = newCS & 0x03; + + if(RPL < CPL) + { + logerror("RETF (%08x): Return segment RPL is less than CPL.\n",m_pc); + FAULT(FAULT_GP,newCS & ~0x03) + } + + if(RPL == CPL) + { + /* same privilege level */ + if((newCS & ~0x03) == 0) + { + logerror("RETF: Return segment is null.\n"); + FAULT(FAULT_GP,0) + } + if(newCS & 0x04) + { + if((newCS & ~0x07) >= m_ldtr.limit) + { + logerror("RETF: Return segment is past LDT limit.\n"); + FAULT(FAULT_GP,newCS & ~0x03) + } + } + else + { + if((newCS & ~0x07) >= m_gdtr.limit) + { + logerror("RETF: Return segment is past GDT limit.\n"); + FAULT(FAULT_GP,newCS & ~0x03) + } + } + if((desc.flags & 0x0018) != 0x0018) + { + logerror("RETF: Return segment is not a code segment.\n"); + FAULT(FAULT_GP,newCS & ~0x03) + } + if(desc.flags & 0x0004) + { + if(DPL > RPL) + { + logerror("RETF: Conforming code segment DPL is greater than CS RPL.\n"); + FAULT(FAULT_GP,newCS & ~0x03) + } + } + else + { + if(DPL != RPL) + { + logerror("RETF: Non-conforming code segment DPL does not equal CS RPL.\n"); + FAULT(FAULT_GP,newCS & ~0x03) + } + } + if((desc.flags & 0x0080) == 0) + { + logerror("RETF (%08x): Code segment is not present.\n",m_pc); + FAULT(FAULT_NP,newCS & ~0x03) + } + if(newEIP > desc.limit) + { + logerror("RETF: EIP is past code segment limit.\n"); + FAULT(FAULT_GP,0) + } + if(operand32 == 0) + { + UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP)); + if(i386_limit_check(SS,offset+count+3) != 0) + { + logerror("RETF (%08x): SP is past stack segment limit.\n",m_pc); + FAULT(FAULT_SS,0) + } + } + else + { + UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP)); + if(i386_limit_check(SS,offset+count+7) != 0) + { + logerror("RETF: ESP is past stack segment limit.\n"); + FAULT(FAULT_SS,0) + } + } + if(operand32 == 0) + REG16(SP) += (4+count); + else + REG32(ESP) += (8+count); + } + else if(RPL > CPL) + { + UINT32 newSS, newESP; // when changing privilege + /* outer privilege level */ + if(operand32 == 0) + { + UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP)); + if(i386_limit_check(SS,offset+count+7) != 0) + { + logerror("RETF (%08x): SP is past stack segment limit.\n",m_pc); + FAULT(FAULT_SS,0) + } + } + else + { + UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP)); + if(i386_limit_check(SS,offset+count+15) != 0) + { + logerror("RETF: ESP is past stack segment limit.\n"); + FAULT(FAULT_SS,0) + } + } + /* Check CS selector and descriptor */ + if((newCS & ~0x03) == 0) + { + logerror("RETF: CS segment is null.\n"); + FAULT(FAULT_GP,0) + } + if(newCS & 0x04) + { + if((newCS & ~0x07) >= m_ldtr.limit) + { + logerror("RETF: CS segment selector is past LDT limit.\n"); + FAULT(FAULT_GP,newCS & ~0x03) + } + } + else + { + if((newCS & ~0x07) >= m_gdtr.limit) + { + logerror("RETF: CS segment selector is past GDT limit.\n"); + FAULT(FAULT_GP,newCS & ~0x03) + } + } + if((desc.flags & 0x0018) != 0x0018) + { + logerror("RETF: CS segment is not a code segment.\n"); + FAULT(FAULT_GP,newCS & ~0x03) + } + if(desc.flags & 0x0004) + { + if(DPL > RPL) + { + logerror("RETF: Conforming CS segment DPL is greater than return selector RPL.\n"); + FAULT(FAULT_GP,newCS & ~0x03) + } + } + else + { + if(DPL != RPL) + { + logerror("RETF: Non-conforming CS segment DPL is not equal to return selector RPL.\n"); + FAULT(FAULT_GP,newCS & ~0x03) + } + } + if((desc.flags & 0x0080) == 0) + { + logerror("RETF: CS segment is not present.\n"); + FAULT(FAULT_NP,newCS & ~0x03) + } + if(newEIP > desc.limit) + { + logerror("RETF: EIP is past return CS segment limit.\n"); + FAULT(FAULT_GP,0) + } + + if(operand32 == 0) + { + ea += count+4; + newESP = READ16(ea) & 0xffff; + newSS = READ16(ea+2) & 0xffff; + } + else + { + ea += count+8; + newESP = READ32(ea); + newSS = READ32(ea+4) & 0xffff; + } + + /* Check SS selector and descriptor */ + desc.selector = newSS; + i386_load_protected_mode_segment(&desc,NULL); + DPL = (desc.flags >> 5) & 0x03; // descriptor privilege level + if((newSS & ~0x07) == 0) + { + logerror("RETF: SS segment is null.\n"); + FAULT(FAULT_GP,0) + } + if(newSS & 0x04) + { + if((newSS & ~0x07) > m_ldtr.limit) + { + logerror("RETF (%08x): SS segment selector is past LDT limit.\n",m_pc); + FAULT(FAULT_GP,newSS & ~0x03) + } + } + else + { + if((newSS & ~0x07) > m_gdtr.limit) + { + logerror("RETF (%08x): SS segment selector is past GDT limit.\n",m_pc); + FAULT(FAULT_GP,newSS & ~0x03) + } + } + if((newSS & 0x03) != RPL) + { + logerror("RETF: SS segment RPL is not equal to CS segment RPL.\n"); + FAULT(FAULT_GP,newSS & ~0x03) + } + if((desc.flags & 0x0018) != 0x0010 || (desc.flags & 0x0002) == 0) + { + logerror("RETF: SS segment is not a writable data segment.\n"); + FAULT(FAULT_GP,newSS & ~0x03) + } + if(((desc.flags >> 5) & 0x03) != RPL) + { + logerror("RETF: SS DPL is not equal to CS segment RPL.\n"); + FAULT(FAULT_GP,newSS & ~0x03) + } + if((desc.flags & 0x0080) == 0) + { + logerror("RETF: SS segment is not present.\n"); + FAULT(FAULT_GP,newSS & ~0x03) + } + m_CPL = newCS & 0x03; + + /* Load new SS:(E)SP */ + if(operand32 == 0) + REG16(SP) = (newESP+count) & 0xffff; + else + REG32(ESP) = newESP+count; + m_sreg[SS].selector = newSS; + i386_load_segment_descriptor(SS ); + + /* Check that DS, ES, FS and GS are valid for the new privilege level */ + i386_check_sreg_validity(DS); + i386_check_sreg_validity(ES); + i386_check_sreg_validity(FS); + i386_check_sreg_validity(GS); + } + + /* Load new CS:(E)IP */ + if(operand32 == 0) + m_eip = newEIP & 0xffff; + else + m_eip = newEIP; + m_sreg[CS].selector = newCS; + i386_load_segment_descriptor(CS ); + CHANGE_PC(m_eip); +} + +void i386_device::i386_protected_mode_iret(int operand32) +{ + UINT32 newCS, newEIP; + UINT32 newSS, newESP; // when changing privilege + I386_SREG desc,stack; + UINT8 CPL, RPL, DPL; + UINT32 newflags; + + CPL = m_CPL; + UINT32 ea = i386_translate(SS, (STACK_32BIT)?REG32(ESP):REG16(SP), 0); + if(operand32 == 0) + { + newEIP = READ16(ea) & 0xffff; + newCS = READ16(ea+2) & 0xffff; + newflags = READ16(ea+4) & 0xffff; + } + else + { + newEIP = READ32(ea); + newCS = READ32(ea+4) & 0xffff; + newflags = READ32(ea+8); + } + + if(V8086_MODE) + { + UINT32 oldflags = get_flags(); + if(!m_IOP1 || !m_IOP2) + { + logerror("IRET (%08x): Is in Virtual 8086 mode and IOPL != 3.\n",m_pc); + FAULT(FAULT_GP,0) + } + if(operand32 == 0) + { + m_eip = newEIP & 0xffff; + m_sreg[CS].selector = newCS & 0xffff; + newflags &= ~(3<<12); + newflags |= (((oldflags>>12)&3)<<12); // IOPL cannot be changed in V86 mode + set_flags((newflags & 0xffff) | (oldflags & ~0xffff)); + REG16(SP) += 6; + } + else + { + m_eip = newEIP; + m_sreg[CS].selector = newCS & 0xffff; + newflags &= ~(3<<12); + newflags |= 0x20000 | (((oldflags>>12)&3)<<12); // IOPL and VM cannot be changed in V86 mode + set_flags(newflags); + REG32(ESP) += 12; + } + } + else if(NESTED_TASK) + { + UINT32 task = READ32(m_task.base); + /* Task Return */ + logerror("IRET (%08x): Nested task return.\n",m_pc); + /* Check back-link selector in TSS */ + if(task & 0x04) + { + logerror("IRET: Task return: Back-linked TSS is not in GDT.\n"); + FAULT(FAULT_TS,task & ~0x03) + } + if((task & ~0x07) >= m_gdtr.limit) + { + logerror("IRET: Task return: Back-linked TSS is not in GDT.\n"); + FAULT(FAULT_TS,task & ~0x03) + } + memset(&desc, 0, sizeof(desc)); + desc.selector = task; + i386_load_protected_mode_segment(&desc,NULL); + if((desc.flags & 0x001f) != 0x000b) + { + logerror("IRET (%08x): Task return: Back-linked TSS is not a busy TSS.\n",m_pc); + FAULT(FAULT_TS,task & ~0x03) + } + if((desc.flags & 0x0080) == 0) + { + logerror("IRET: Task return: Back-linked TSS is not present.\n"); + FAULT(FAULT_NP,task & ~0x03) + } + if(desc.flags & 0x08) + i386_task_switch(desc.selector,0); + else + i286_task_switch(desc.selector,0); + return; + } + else + { + if(newflags & 0x00020000) // if returning to virtual 8086 mode + { + // 16-bit iret can't reach here + newESP = READ32(ea+12); + newSS = READ32(ea+16) & 0xffff; + /* Return to v86 mode */ + //logerror("IRET (%08x): Returning to Virtual 8086 mode.\n",m_pc); + if(CPL != 0) + { + UINT32 oldflags = get_flags(); + newflags = (newflags & ~0x00003000) | (oldflags & 0x00003000); + } + set_flags(newflags); + m_eip = POP32() & 0xffff; // high 16 bits are ignored + m_sreg[CS].selector = POP32() & 0xffff; + POP32(); // already set flags + newESP = POP32(); + newSS = POP32() & 0xffff; + m_sreg[ES].selector = POP32() & 0xffff; + m_sreg[DS].selector = POP32() & 0xffff; + m_sreg[FS].selector = POP32() & 0xffff; + m_sreg[GS].selector = POP32() & 0xffff; + REG32(ESP) = newESP; // all 32 bits are loaded + m_sreg[SS].selector = newSS; + i386_load_segment_descriptor(ES); + i386_load_segment_descriptor(DS); + i386_load_segment_descriptor(FS); + i386_load_segment_descriptor(GS); + i386_load_segment_descriptor(SS); + m_CPL = 3; // Virtual 8086 tasks are always run at CPL 3 + } + else + { + if(operand32 == 0) + { + UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP)); + if(i386_limit_check(SS,offset+3) != 0) + { + logerror("IRET: Data on stack is past SS limit.\n"); + FAULT(FAULT_SS,0) + } + } + else + { + UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP)); + if(i386_limit_check(SS,offset+7) != 0) + { + logerror("IRET: Data on stack is past SS limit.\n"); + FAULT(FAULT_SS,0) + } + } + RPL = newCS & 0x03; + if(RPL < CPL) + { + logerror("IRET (%08x): Return CS RPL is less than CPL.\n",m_pc); + FAULT(FAULT_GP,newCS & ~0x03) + } + if(RPL == CPL) + { + /* return to same privilege level */ + if(operand32 == 0) + { + UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP)); + if(i386_limit_check(SS,offset+5) != 0) + { + logerror("IRET (%08x): Data on stack is past SS limit.\n",m_pc); + FAULT(FAULT_SS,0) + } + } + else + { + UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP)); + if(i386_limit_check(SS,offset+11) != 0) + { + logerror("IRET (%08x): Data on stack is past SS limit.\n",m_pc); + FAULT(FAULT_SS,0) + } + } + if((newCS & ~0x03) == 0) + { + logerror("IRET: Return CS selector is null.\n"); + FAULT(FAULT_GP,0) + } + if(newCS & 0x04) + { + if((newCS & ~0x07) >= m_ldtr.limit) + { + logerror("IRET: Return CS selector (%04x) is past LDT limit.\n",newCS); + FAULT(FAULT_GP,newCS & ~0x03) + } + } + else + { + if((newCS & ~0x07) >= m_gdtr.limit) + { + logerror("IRET: Return CS selector is past GDT limit.\n"); + FAULT(FAULT_GP,newCS & ~0x03) + } + } + memset(&desc, 0, sizeof(desc)); + desc.selector = newCS; + i386_load_protected_mode_segment(&desc,NULL); + DPL = (desc.flags >> 5) & 0x03; // descriptor privilege level + RPL = newCS & 0x03; + if((desc.flags & 0x0018) != 0x0018) + { + logerror("IRET (%08x): Return CS segment is not a code segment.\n",m_pc); + FAULT(FAULT_GP,newCS & ~0x07) + } + if(desc.flags & 0x0004) + { + if(DPL > RPL) + { + logerror("IRET: Conforming return CS DPL is greater than CS RPL.\n"); + FAULT(FAULT_GP,newCS & ~0x03) + } + } + else + { + if(DPL != RPL) + { + logerror("IRET: Non-conforming return CS DPL is not equal to CS RPL.\n"); + FAULT(FAULT_GP,newCS & ~0x03) + } + } + if((desc.flags & 0x0080) == 0) + { + logerror("IRET: Return CS segment is not present.\n"); + FAULT(FAULT_NP,newCS & ~0x03) + } + if(newEIP > desc.limit) + { + logerror("IRET: Return EIP is past return CS limit.\n"); + FAULT(FAULT_GP,0) + } + + if(CPL != 0) + { + UINT32 oldflags = get_flags(); + newflags = (newflags & ~0x00003000) | (oldflags & 0x00003000); + } + + if(operand32 == 0) + { + m_eip = newEIP; + m_sreg[CS].selector = newCS; + set_flags(newflags); + REG16(SP) += 6; + } + else + { + m_eip = newEIP; + m_sreg[CS].selector = newCS & 0xffff; + set_flags(newflags); + REG32(ESP) += 12; + } + } + else if(RPL > CPL) + { + /* return to outer privilege level */ + memset(&desc, 0, sizeof(desc)); + desc.selector = newCS; + i386_load_protected_mode_segment(&desc,NULL); + DPL = (desc.flags >> 5) & 0x03; // descriptor privilege level + RPL = newCS & 0x03; + if(operand32 == 0) + { + UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP)); + if(i386_limit_check(SS,offset+9) != 0) + { + logerror("IRET: SP is past SS limit.\n"); + FAULT(FAULT_SS,0) + } + } + else + { + UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP)); + if(i386_limit_check(SS,offset+19) != 0) + { + logerror("IRET: ESP is past SS limit.\n"); + FAULT(FAULT_SS,0) + } + } + /* Check CS selector and descriptor */ + if((newCS & ~0x03) == 0) + { + logerror("IRET: Return CS selector is null.\n"); + FAULT(FAULT_GP,0) + } + if(newCS & 0x04) + { + if((newCS & ~0x07) >= m_ldtr.limit) + { + logerror("IRET: Return CS selector is past LDT limit.\n"); + FAULT(FAULT_GP,newCS & ~0x03); + } + } + else + { + if((newCS & ~0x07) >= m_gdtr.limit) + { + logerror("IRET: Return CS selector is past GDT limit.\n"); + FAULT(FAULT_GP,newCS & ~0x03); + } + } + if((desc.flags & 0x0018) != 0x0018) + { + logerror("IRET: Return CS segment is not a code segment.\n"); + FAULT(FAULT_GP,newCS & ~0x03) + } + if(desc.flags & 0x0004) + { + if(DPL > RPL) + { + logerror("IRET: Conforming return CS DPL is greater than CS RPL.\n"); + FAULT(FAULT_GP,newCS & ~0x03) + } + } + else + { + if(DPL != RPL) + { + logerror("IRET: Non-conforming return CS DPL does not equal CS RPL.\n"); + FAULT(FAULT_GP,newCS & ~0x03) + } + } + if((desc.flags & 0x0080) == 0) + { + logerror("IRET: Return CS segment is not present.\n"); + FAULT(FAULT_NP,newCS & ~0x03) + } + + /* Check SS selector and descriptor */ + if(operand32 == 0) + { + newESP = READ16(ea+6) & 0xffff; + newSS = READ16(ea+8) & 0xffff; + } + else + { + newESP = READ32(ea+12); + newSS = READ32(ea+16) & 0xffff; + } + memset(&stack, 0, sizeof(stack)); + stack.selector = newSS; + i386_load_protected_mode_segment(&stack,NULL); + DPL = (stack.flags >> 5) & 0x03; + if((newSS & ~0x03) == 0) + { + logerror("IRET: Return SS selector is null.\n"); + FAULT(FAULT_GP,0) + } + if(newSS & 0x04) + { + if((newSS & ~0x07) >= m_ldtr.limit) + { + logerror("IRET: Return SS selector is past LDT limit.\n"); + FAULT(FAULT_GP,newSS & ~0x03); + } + } + else + { + if((newSS & ~0x07) >= m_gdtr.limit) + { + logerror("IRET: Return SS selector is past GDT limit.\n"); + FAULT(FAULT_GP,newSS & ~0x03); + } + } + if((newSS & 0x03) != RPL) + { + logerror("IRET: Return SS RPL is not equal to return CS RPL.\n"); + FAULT(FAULT_GP,newSS & ~0x03) + } + if((stack.flags & 0x0018) != 0x0010) + { + logerror("IRET: Return SS segment is not a data segment.\n"); + FAULT(FAULT_GP,newSS & ~0x03) + } + if((stack.flags & 0x0002) == 0) + { + logerror("IRET: Return SS segment is not writable.\n"); + FAULT(FAULT_GP,newSS & ~0x03) + } + if(DPL != RPL) + { + logerror("IRET: Return SS DPL does not equal SS RPL.\n"); + FAULT(FAULT_GP,newSS & ~0x03) + } + if((stack.flags & 0x0080) == 0) + { + logerror("IRET: Return SS segment is not present.\n"); + FAULT(FAULT_NP,newSS & ~0x03) + } + if(newEIP > desc.limit) + { + logerror("IRET: EIP is past return CS limit.\n"); + FAULT(FAULT_GP,0) + } + +// if(operand32 == 0) +// REG16(SP) += 10; +// else +// REG32(ESP) += 20; + + // IOPL can only change if CPL is zero + if(CPL != 0) + { + UINT32 oldflags = get_flags(); + newflags = (newflags & ~0x00003000) | (oldflags & 0x00003000); + } + + if(operand32 == 0) + { + m_eip = newEIP & 0xffff; + m_sreg[CS].selector = newCS; + set_flags(newflags); + REG16(SP) = newESP & 0xffff; + m_sreg[SS].selector = newSS; + } + else + { + m_eip = newEIP; + m_sreg[CS].selector = newCS & 0xffff; + set_flags(newflags); + REG32(ESP) = newESP; + m_sreg[SS].selector = newSS & 0xffff; + } + m_CPL = newCS & 0x03; + i386_load_segment_descriptor(SS); + + /* Check that DS, ES, FS and GS are valid for the new privilege level */ + i386_check_sreg_validity(DS); + i386_check_sreg_validity(ES); + i386_check_sreg_validity(FS); + i386_check_sreg_validity(GS); + } + } + } + + i386_load_segment_descriptor(CS); + CHANGE_PC(m_eip); +} + +#include "cycles.h" + +static UINT8 *cycle_table_rm[X86_NUM_CPUS]; +static UINT8 *cycle_table_pm[X86_NUM_CPUS]; + +#define CYCLES_NUM(x) (m_cycles -= (x)) + +void i386_device::CYCLES(int x) +{ + if (PROTECTED_MODE) + { + m_cycles -= m_cycle_table_pm[x]; + } + else + { + m_cycles -= m_cycle_table_rm[x]; + } +} + +void i386_device::CYCLES_RM(int modrm, int r, int m) +{ + if (modrm >= 0xc0) + { + if (PROTECTED_MODE) + { + m_cycles -= m_cycle_table_pm[r]; + } + else + { + m_cycles -= m_cycle_table_rm[r]; + } + } + else + { + if (PROTECTED_MODE) + { + m_cycles -= m_cycle_table_pm[m]; + } + else + { + m_cycles -= m_cycle_table_rm[m]; + } + } +} + +void i386_device::build_cycle_table() +{ + int i, j; + for (j=0; j < X86_NUM_CPUS; j++) + { + cycle_table_rm[j] = auto_alloc_array(machine(), UINT8, CYCLES_NUM_OPCODES); + cycle_table_pm[j] = auto_alloc_array(machine(), UINT8, CYCLES_NUM_OPCODES); + + for (i=0; i < sizeof(x86_cycle_table)/sizeof(X86_CYCLE_TABLE); i++) + { + int opcode = x86_cycle_table[i].op; + cycle_table_rm[j][opcode] = x86_cycle_table[i].cpu_cycles[j][0]; + cycle_table_pm[j][opcode] = x86_cycle_table[i].cpu_cycles[j][1]; + } + } +} + +void i386_device::report_invalid_opcode() +{ +#ifndef DEBUG_MISSING_OPCODE + logerror("i386: Invalid opcode %02X at %08X %s\n", m_opcode, m_pc - 1, m_lock ? "with lock" : ""); +#else + logerror("i386: Invalid opcode"); + for (int a = 0; a < m_opcode_bytes_length; a++) + logerror(" %02X", m_opcode_bytes[a]); + logerror(" at %08X\n", m_opcode_pc); +#endif +} + +void i386_device::report_invalid_modrm(const char* opcode, UINT8 modrm) +{ +#ifndef DEBUG_MISSING_OPCODE + logerror("i386: Invalid %s modrm %01X at %08X\n", opcode, modrm, m_pc - 2); +#else + logerror("i386: Invalid %s modrm %01X", opcode, modrm); + for (int a = 0; a < m_opcode_bytes_length; a++) + logerror(" %02X", m_opcode_bytes[a]); + logerror(" at %08X\n", m_opcode_pc); +#endif + i386_trap(6, 0, 0); +} + + +#include "i386ops.inc" +#include "i386op16.inc" +#include "i386op32.inc" +#include "i486ops.inc" +#include "pentops.inc" +#include "x87ops.inc" +#include "i386ops.h" + +void i386_device::i386_decode_opcode() +{ + m_opcode = FETCH(); + + if(m_lock && !m_lock_table[0][m_opcode]) + return i386_invalid(); + + if( m_operand_size ) + (this->*m_opcode_table1_32[m_opcode])(); + else + (this->*m_opcode_table1_16[m_opcode])(); +} + +/* Two-byte opcode 0f xx */ +void i386_device::i386_decode_two_byte() +{ + m_opcode = FETCH(); + + if(m_lock && !m_lock_table[1][m_opcode]) + return i386_invalid(); + + if( m_operand_size ) + (this->*m_opcode_table2_32[m_opcode])(); + else + (this->*m_opcode_table2_16[m_opcode])(); +} + +/* Three-byte opcode 0f 38 xx */ +void i386_device::i386_decode_three_byte38() +{ + m_opcode = FETCH(); + + if (m_operand_size) + (this->*m_opcode_table338_32[m_opcode])(); + else + (this->*m_opcode_table338_16[m_opcode])(); +} + +/* Three-byte opcode 0f 3a xx */ +void i386_device::i386_decode_three_byte3a() +{ + m_opcode = FETCH(); + + if (m_operand_size) + (this->*m_opcode_table33a_32[m_opcode])(); + else + (this->*m_opcode_table33a_16[m_opcode])(); +} + +/* Three-byte opcode prefix 66 0f xx */ +void i386_device::i386_decode_three_byte66() +{ + m_opcode = FETCH(); + if( m_operand_size ) + (this->*m_opcode_table366_32[m_opcode])(); + else + (this->*m_opcode_table366_16[m_opcode])(); +} + +/* Three-byte opcode prefix f2 0f xx */ +void i386_device::i386_decode_three_bytef2() +{ + m_opcode = FETCH(); + if( m_operand_size ) + (this->*m_opcode_table3f2_32[m_opcode])(); + else + (this->*m_opcode_table3f2_16[m_opcode])(); +} + +/* Three-byte opcode prefix f3 0f */ +void i386_device::i386_decode_three_bytef3() +{ + m_opcode = FETCH(); + if( m_operand_size ) + (this->*m_opcode_table3f3_32[m_opcode])(); + else + (this->*m_opcode_table3f3_16[m_opcode])(); +} + +/* Four-byte opcode prefix 66 0f 38 xx */ +void i386_device::i386_decode_four_byte3866() +{ + m_opcode = FETCH(); + if (m_operand_size) + (this->*m_opcode_table46638_32[m_opcode])(); + else + (this->*m_opcode_table46638_16[m_opcode])(); +} + +/* Four-byte opcode prefix 66 0f 3a xx */ +void i386_device::i386_decode_four_byte3a66() +{ + m_opcode = FETCH(); + if (m_operand_size) + (this->*m_opcode_table4663a_32[m_opcode])(); + else + (this->*m_opcode_table4663a_16[m_opcode])(); +} + +/* Four-byte opcode prefix f2 0f 38 xx */ +void i386_device::i386_decode_four_byte38f2() +{ + m_opcode = FETCH(); + if (m_operand_size) + (this->*m_opcode_table4f238_32[m_opcode])(); + else + (this->*m_opcode_table4f238_16[m_opcode])(); +} + +/* Four-byte opcode prefix f2 0f 3a xx */ +void i386_device::i386_decode_four_byte3af2() +{ + m_opcode = FETCH(); + if (m_operand_size) + (this->*m_opcode_table4f23a_32[m_opcode])(); + else + (this->*m_opcode_table4f23a_16[m_opcode])(); +} + +/* Four-byte opcode prefix f3 0f 38 xx */ +void i386_device::i386_decode_four_byte38f3() +{ + m_opcode = FETCH(); + if (m_operand_size) + (this->*m_opcode_table4f338_32[m_opcode])(); + else + (this->*m_opcode_table4f338_16[m_opcode])(); +} + + +/*************************************************************************/ + +UINT8 i386_device::read8_debug(UINT32 ea, UINT8 *data) +{ + UINT32 address = ea; + + if(!i386_translate_address(TRANSLATE_DEBUG_MASK,&address,NULL)) + return 0; + + address &= m_a20_mask; + *data = m_program->read_byte(address); + return 1; +} + +UINT32 i386_device::i386_get_debug_desc(I386_SREG *seg) +{ + UINT32 base, limit, address; + union { UINT8 b[8]; UINT32 w[2]; } data; + UINT8 ret; + int entry; + + if ( seg->selector & 0x4 ) + { + base = m_ldtr.base; + limit = m_ldtr.limit; + } else { + base = m_gdtr.base; + limit = m_gdtr.limit; + } + + entry = seg->selector & ~0x7; + if (limit == 0 || entry + 7 > limit) + return 0; + + address = entry + base; + + // todo: bigendian + ret = read8_debug( address+0, &data.b[0] ); + ret += read8_debug( address+1, &data.b[1] ); + ret += read8_debug( address+2, &data.b[2] ); + ret += read8_debug( address+3, &data.b[3] ); + ret += read8_debug( address+4, &data.b[4] ); + ret += read8_debug( address+5, &data.b[5] ); + ret += read8_debug( address+6, &data.b[6] ); + ret += read8_debug( address+7, &data.b[7] ); + + if(ret != 8) + return 0; + + seg->flags = (data.w[1] >> 8) & 0xf0ff; + seg->base = (data.w[1] & 0xff000000) | ((data.w[1] & 0xff) << 16) | ((data.w[0] >> 16) & 0xffff); + seg->limit = (data.w[1] & 0xf0000) | (data.w[0] & 0xffff); + if (seg->flags & 0x8000) + seg->limit = (seg->limit << 12) | 0xfff; + seg->d = (seg->flags & 0x4000) ? 1 : 0; + seg->valid = (seg->selector & ~3)?(true):(false); + + return seg->valid; +} + +UINT64 i386_device::debug_segbase(symbol_table &table, int params, const UINT64 *param) +{ + UINT32 result; + I386_SREG seg; + + if(param[0] > 65535) + return 0; + + if (PROTECTED_MODE && !V8086_MODE) + { + memset(&seg, 0, sizeof(seg)); + seg.selector = param[0]; + if(!i386_get_debug_desc(&seg)) + return 0; + result = seg.base; + } + else + { + result = param[0] << 4; + } + return result; +} + +UINT64 i386_device::debug_seglimit(symbol_table &table, int params, const UINT64 *param) +{ + UINT32 result = 0; + I386_SREG seg; + + if (PROTECTED_MODE && !V8086_MODE) + { + memset(&seg, 0, sizeof(seg)); + seg.selector = param[0]; + if(!i386_get_debug_desc(&seg)) + return 0; + result = seg.limit; + } + return result; +} + +UINT64 i386_device::debug_segofftovirt(symbol_table &table, int params, const UINT64 *param) +{ + UINT32 result = 0; + I386_SREG seg; + + if(param[0] > 65535) + return 0; + + if (PROTECTED_MODE && !V8086_MODE) + { + memset(&seg, 0, sizeof(seg)); + seg.selector = param[0]; + if(!i386_get_debug_desc(&seg)) + return 0; + if((seg.flags & 0x0090) != 0x0090) // not system and present + return 0; + if((seg.flags & 0x0018) == 0x0010 && seg.flags & 0x0004) // expand down + { + if(param[1] <= seg.limit) + return 0; + } + else + { + if(param[1] > seg.limit) + return 0; + } + result = seg.base+param[1]; + } + else + { + if(param[1] > 65535) + return 0; + + result = (param[0] << 4) + param[1]; + } + return result; +} + +UINT64 i386_device::debug_virttophys(symbol_table &table, int params, const UINT64 *param) +{ + UINT32 result = param[0]; + + if(!i386_translate_address(TRANSLATE_DEBUG_MASK,&result,NULL)) + return 0; + return result; +} + +UINT64 i386_debug_segbase(symbol_table &table, void *ref, int params, const UINT64 *param) +{ + i386_device *i386 = (i386_device *)(ref); + return i386->debug_segbase(table, params, param); +} + +UINT64 i386_debug_seglimit(symbol_table &table, void *ref, int params, const UINT64 *param) +{ + i386_device *i386 = (i386_device *)(ref); + return i386->debug_seglimit(table, params, param); +} + +UINT64 i386_debug_segofftovirt(symbol_table &table, void *ref, int params, const UINT64 *param) +{ + i386_device *i386 = (i386_device *)(ref); + return i386->debug_segofftovirt(table, params, param); +} + +static UINT64 i386_debug_virttophys(symbol_table &table, void *ref, int params, const UINT64 *param) +{ + i386_device *i386 = (i386_device *)(ref); + return i386->debug_virttophys(table, params, param); +} + +void i386_device::device_debug_setup() +{ + debug()->symtable().add("segbase", (void *)this, 1, 1, i386_debug_segbase); + debug()->symtable().add("seglimit", (void *)this, 1, 1, i386_debug_seglimit); + debug()->symtable().add("segofftovirt", (void *)this, 2, 2, i386_debug_segofftovirt); + debug()->symtable().add("virttophys", (void *)this, 1, 1, i386_debug_virttophys); +} + +/*************************************************************************/ + +void i386_device::i386_postload() +{ + int i; + for (i = 0; i < 6; i++) + i386_load_segment_descriptor(i); + CHANGE_PC(m_eip); +} + +void i386_device::i386_common_init(int tlbsize) +{ + int i, j; + static const int regs8[8] = {AL,CL,DL,BL,AH,CH,DH,BH}; + static const int regs16[8] = {AX,CX,DX,BX,SP,BP,SI,DI}; + static const int regs32[8] = {EAX,ECX,EDX,EBX,ESP,EBP,ESI,EDI}; + + assert((sizeof(XMM_REG)/sizeof(double)) == 2); + + build_cycle_table(); + + for( i=0; i < 256; i++ ) { + int c=0; + for( j=0; j < 8; j++ ) { + if( i & (1 << j) ) + c++; + } + i386_parity_table[i] = ~(c & 0x1) & 0x1; + } + + for( i=0; i < 256; i++ ) { + i386_MODRM_table[i].reg.b = regs8[(i >> 3) & 0x7]; + i386_MODRM_table[i].reg.w = regs16[(i >> 3) & 0x7]; + i386_MODRM_table[i].reg.d = regs32[(i >> 3) & 0x7]; + + i386_MODRM_table[i].rm.b = regs8[i & 0x7]; + i386_MODRM_table[i].rm.w = regs16[i & 0x7]; + i386_MODRM_table[i].rm.d = regs32[i & 0x7]; + } + + m_program = &space(AS_PROGRAM); + m_direct = &m_program->direct(); + m_io = &space(AS_IO); + m_vtlb = vtlb_alloc(this, AS_PROGRAM, 0, tlbsize); + m_smi = false; + m_debugger_temp = 0; + m_lock = false; + + zero_state(); + + save_item(NAME(m_reg.d)); + save_item(NAME(m_sreg[ES].selector)); + save_item(NAME(m_sreg[ES].base)); + save_item(NAME(m_sreg[ES].limit)); + save_item(NAME(m_sreg[ES].flags)); + save_item(NAME(m_sreg[ES].d)); + save_item(NAME(m_sreg[CS].selector)); + save_item(NAME(m_sreg[CS].base)); + save_item(NAME(m_sreg[CS].limit)); + save_item(NAME(m_sreg[CS].flags)); + save_item(NAME(m_sreg[CS].d)); + save_item(NAME(m_sreg[SS].selector)); + save_item(NAME(m_sreg[SS].base)); + save_item(NAME(m_sreg[SS].limit)); + save_item(NAME(m_sreg[SS].flags)); + save_item(NAME(m_sreg[SS].d)); + save_item(NAME(m_sreg[DS].selector)); + save_item(NAME(m_sreg[DS].base)); + save_item(NAME(m_sreg[DS].limit)); + save_item(NAME(m_sreg[DS].flags)); + save_item(NAME(m_sreg[DS].d)); + save_item(NAME(m_sreg[FS].selector)); + save_item(NAME(m_sreg[FS].base)); + save_item(NAME(m_sreg[FS].limit)); + save_item(NAME(m_sreg[FS].flags)); + save_item(NAME(m_sreg[FS].d)); + save_item(NAME(m_sreg[GS].selector)); + save_item(NAME(m_sreg[GS].base)); + save_item(NAME(m_sreg[GS].limit)); + save_item(NAME(m_sreg[GS].flags)); + save_item(NAME(m_sreg[GS].d)); + save_item(NAME(m_eip)); + save_item(NAME(m_prev_eip)); + save_item(NAME(m_CF)); + save_item(NAME(m_DF)); + save_item(NAME(m_SF)); + save_item(NAME(m_OF)); + save_item(NAME(m_ZF)); + save_item(NAME(m_PF)); + save_item(NAME(m_AF)); + save_item(NAME(m_IF)); + save_item(NAME(m_TF)); + save_item(NAME(m_cr)); + save_item(NAME(m_dr)); + save_item(NAME(m_tr)); + save_item(NAME(m_idtr.base)); + save_item(NAME(m_idtr.limit)); + save_item(NAME(m_gdtr.base)); + save_item(NAME(m_gdtr.limit)); + save_item(NAME(m_task.base)); + save_item(NAME(m_task.segment)); + save_item(NAME(m_task.limit)); + save_item(NAME(m_task.flags)); + save_item(NAME(m_ldtr.base)); + save_item(NAME(m_ldtr.segment)); + save_item(NAME(m_ldtr.limit)); + save_item(NAME(m_ldtr.flags)); + save_item(NAME(m_irq_state)); + save_item(NAME(m_performed_intersegment_jump)); + save_item(NAME(m_mxcsr)); + save_item(NAME(m_smm)); + save_item(NAME(m_smi_latched)); + save_item(NAME(m_smi)); + save_item(NAME(m_nmi_masked)); + save_item(NAME(m_nmi_latched)); + save_item(NAME(m_smbase)); + save_item(NAME(m_lock)); + machine().save().register_postload(save_prepost_delegate(FUNC(i386_device::i386_postload), this)); + + m_smiact.resolve_safe(); + + m_icountptr = &m_cycles; +} + +void i386_device::device_start() +{ + i386_common_init(32); + + build_opcode_table(OP_I386); + m_cycle_table_rm = cycle_table_rm[CPU_CYCLES_I386]; + m_cycle_table_pm = cycle_table_pm[CPU_CYCLES_I386]; + + register_state_i386(); +} + +void i386_device::register_state_i386() +{ + state_add( I386_PC, "PC", m_pc).formatstr("%08X"); + state_add( I386_EIP, "EIP", m_eip).callimport().formatstr("%08X"); + state_add( I386_AL, "~AL", REG8(AL)).formatstr("%02X"); + state_add( I386_AH, "~AH", REG8(AH)).formatstr("%02X"); + state_add( I386_BL, "~BL", REG8(BL)).formatstr("%02X"); + state_add( I386_BH, "~BH", REG8(BH)).formatstr("%02X"); + state_add( I386_CL, "~CL", REG8(CL)).formatstr("%02X"); + state_add( I386_CH, "~CH", REG8(CH)).formatstr("%02X"); + state_add( I386_DL, "~DL", REG8(DL)).formatstr("%02X"); + state_add( I386_DH, "~DH", REG8(DH)).formatstr("%02X"); + state_add( I386_AX, "~AX", REG16(AX)).formatstr("%04X"); + state_add( I386_BX, "~BX", REG16(BX)).formatstr("%04X"); + state_add( I386_CX, "~CX", REG16(CX)).formatstr("%04X"); + state_add( I386_DX, "~DX", REG16(DX)).formatstr("%04X"); + state_add( I386_SI, "~SI", REG16(SI)).formatstr("%04X"); + state_add( I386_DI, "~DI", REG16(DI)).formatstr("%04X"); + state_add( I386_BP, "~BP", REG16(BP)).formatstr("%04X"); + state_add( I386_SP, "~SP", REG16(SP)).formatstr("%04X"); + state_add( I386_IP, "~IP", m_debugger_temp).mask(0xffff).callimport().callexport().formatstr("%04X"); + state_add( I386_EAX, "EAX", m_reg.d[EAX]).formatstr("%08X"); + state_add( I386_EBX, "EBX", m_reg.d[EBX]).formatstr("%08X"); + state_add( I386_ECX, "ECX", m_reg.d[ECX]).formatstr("%08X"); + state_add( I386_EDX, "EDX", m_reg.d[EDX]).formatstr("%08X"); + state_add( I386_EBP, "EBP", m_reg.d[EBP]).formatstr("%08X"); + state_add( I386_ESP, "ESP", m_reg.d[ESP]).formatstr("%08X"); + state_add( I386_ESI, "ESI", m_reg.d[ESI]).formatstr("%08X"); + state_add( I386_EDI, "EDI", m_reg.d[EDI]).formatstr("%08X"); + state_add( I386_EFLAGS, "EFLAGS", m_eflags).formatstr("%08X"); + state_add( I386_CS, "CS", m_sreg[CS].selector).callimport().formatstr("%04X"); + state_add( I386_CS_BASE, "CSBASE", m_sreg[CS].base).formatstr("%08X"); + state_add( I386_CS_LIMIT, "CSLIMIT", m_sreg[CS].limit).formatstr("%08X"); + state_add( I386_CS_FLAGS, "CSFLAGS", m_sreg[CS].flags).mask(0xf0ff).formatstr("%04X"); + state_add( I386_SS, "SS", m_sreg[SS].selector).callimport().formatstr("%04X"); + state_add( I386_SS_BASE, "SSBASE", m_sreg[SS].base).formatstr("%08X"); + state_add( I386_SS_LIMIT, "SSLIMIT", m_sreg[SS].limit).formatstr("%08X"); + state_add( I386_SS_FLAGS, "SSFLAGS", m_sreg[SS].flags).mask(0xf0ff).formatstr("%04X"); + state_add( I386_DS, "DS", m_sreg[DS].selector).callimport().formatstr("%04X"); + state_add( I386_DS_BASE, "DSBASE", m_sreg[DS].base).formatstr("%08X"); + state_add( I386_DS_LIMIT, "DSLIMIT", m_sreg[DS].limit).formatstr("%08X"); + state_add( I386_DS_FLAGS, "DSFLAGS", m_sreg[DS].flags).mask(0xf0ff).formatstr("%04X"); + state_add( I386_ES, "ES", m_sreg[ES].selector).callimport().formatstr("%04X"); + state_add( I386_ES_BASE, "ESBASE", m_sreg[ES].base).formatstr("%08X"); + state_add( I386_ES_LIMIT, "ESLIMIT", m_sreg[ES].limit).formatstr("%08X"); + state_add( I386_ES_FLAGS, "ESFLAGS", m_sreg[ES].flags).mask(0xf0ff).formatstr("%04X"); + state_add( I386_FS, "FS", m_sreg[FS].selector).callimport().formatstr("%04X"); + state_add( I386_FS_BASE, "FSBASE", m_sreg[FS].base).formatstr("%08X"); + state_add( I386_FS_LIMIT, "FSLIMIT", m_sreg[FS].limit).formatstr("%08X"); + state_add( I386_FS_FLAGS, "FSFLAGS", m_sreg[FS].flags).mask(0xf0ff).formatstr("%04X"); + state_add( I386_GS, "GS", m_sreg[GS].selector).callimport().formatstr("%04X"); + state_add( I386_GS_BASE, "GSBASE", m_sreg[GS].base).formatstr("%08X"); + state_add( I386_GS_LIMIT, "GSLIMIT", m_sreg[GS].limit).formatstr("%08X"); + state_add( I386_GS_FLAGS, "GSFLAGS", m_sreg[GS].flags).mask(0xf0ff).formatstr("%04X"); + state_add( I386_CR0, "CR0", m_cr[0]).formatstr("%08X"); + state_add( I386_CR1, "CR1", m_cr[1]).formatstr("%08X"); + state_add( I386_CR2, "CR2", m_cr[2]).formatstr("%08X"); + state_add( I386_CR3, "CR3", m_cr[3]).formatstr("%08X"); + state_add( I386_CR4, "CR4", m_cr[4]).formatstr("%08X"); + state_add( I386_DR0, "DR0", m_dr[0]).formatstr("%08X"); + state_add( I386_DR1, "DR1", m_dr[1]).formatstr("%08X"); + state_add( I386_DR2, "DR2", m_dr[2]).formatstr("%08X"); + state_add( I386_DR3, "DR3", m_dr[3]).formatstr("%08X"); + state_add( I386_DR4, "DR4", m_dr[4]).formatstr("%08X"); + state_add( I386_DR5, "DR5", m_dr[5]).formatstr("%08X"); + state_add( I386_DR6, "DR6", m_dr[6]).formatstr("%08X"); + state_add( I386_DR7, "DR7", m_dr[7]).formatstr("%08X"); + state_add( I386_TR6, "TR6", m_tr[6]).formatstr("%08X"); + state_add( I386_TR7, "TR7", m_tr[7]).formatstr("%08X"); + state_add( I386_GDTR_BASE, "GDTRBASE", m_gdtr.base).formatstr("%08X"); + state_add( I386_GDTR_LIMIT, "GDTRLIMIT", m_gdtr.limit).formatstr("%04X"); + state_add( I386_IDTR_BASE, "IDTRBASE", m_idtr.base).formatstr("%08X"); + state_add( I386_IDTR_LIMIT, "IDTRLIMIT", m_idtr.limit).formatstr("%04X"); + state_add( I386_LDTR, "LDTR", m_ldtr.segment).formatstr("%04X"); + state_add( I386_LDTR_BASE, "LDTRBASE", m_ldtr.base).formatstr("%08X"); + state_add( I386_LDTR_LIMIT, "LDTRLIMIT", m_ldtr.limit).formatstr("%08X"); + state_add( I386_LDTR_FLAGS, "LDTRFLAGS", m_ldtr.flags).mask(0xf0ff).formatstr("%04X"); + state_add( I386_TR, "TR", m_task.segment).formatstr("%04X"); + state_add( I386_TR_BASE, "TRBASE", m_task.base).formatstr("%08X"); + state_add( I386_TR_LIMIT, "TRLIMIT", m_task.limit).formatstr("%08X"); + state_add( I386_TR_FLAGS, "TRFLAGS", m_task.flags).mask(0xf0ff).formatstr("%04X"); + state_add( I386_CPL, "CPL", m_CPL).formatstr("%01X"); + + state_add( STATE_GENPC, "GENPC", m_pc).noshow(); + state_add( STATE_GENFLAGS, "GENFLAGS", m_debugger_temp).formatstr("%8s").noshow(); + state_add( STATE_GENSP, "GENSP", REG32(ESP)).noshow(); +} + +void i386_device::register_state_i386_x87() +{ + register_state_i386(); + + state_add( X87_CTRL, "x87_CW", m_x87_cw).formatstr("%04X"); + state_add( X87_STATUS, "x87_SW", m_x87_sw).formatstr("%04X"); + state_add( X87_TAG, "x87_TAG", m_x87_tw).formatstr("%04X"); + state_add( X87_ST0, "ST0", m_debugger_temp ).formatstr("%15s"); + state_add( X87_ST1, "ST1", m_debugger_temp ).formatstr("%15s"); + state_add( X87_ST2, "ST2", m_debugger_temp ).formatstr("%15s"); + state_add( X87_ST3, "ST3", m_debugger_temp ).formatstr("%15s"); + state_add( X87_ST4, "ST4", m_debugger_temp ).formatstr("%15s"); + state_add( X87_ST5, "ST5", m_debugger_temp ).formatstr("%15s"); + state_add( X87_ST6, "ST6", m_debugger_temp ).formatstr("%15s"); + state_add( X87_ST7, "ST7", m_debugger_temp ).formatstr("%15s"); +} + +void i386_device::register_state_i386_x87_xmm() +{ + register_state_i386_x87(); + + state_add( SSE_XMM0, "XMM0", m_debugger_temp ).formatstr("%32s"); + state_add( SSE_XMM1, "XMM1", m_debugger_temp ).formatstr("%32s"); + state_add( SSE_XMM2, "XMM2", m_debugger_temp ).formatstr("%32s"); + state_add( SSE_XMM3, "XMM3", m_debugger_temp ).formatstr("%32s"); + state_add( SSE_XMM4, "XMM4", m_debugger_temp ).formatstr("%32s"); + state_add( SSE_XMM5, "XMM5", m_debugger_temp ).formatstr("%32s"); + state_add( SSE_XMM6, "XMM6", m_debugger_temp ).formatstr("%32s"); + state_add( SSE_XMM7, "XMM7", m_debugger_temp ).formatstr("%32s"); + +} + +void i386_device::state_import(const device_state_entry &entry) +{ + switch (entry.index()) + { + case I386_EIP: + CHANGE_PC(m_eip); + break; + case I386_IP: + m_eip = ( m_eip & ~0xffff ) | ( m_debugger_temp & 0xffff); + CHANGE_PC(m_eip); + break; + case I386_CS: + i386_load_segment_descriptor(CS); + break; + case I386_SS: + i386_load_segment_descriptor(SS); + break; + case I386_DS: + i386_load_segment_descriptor(DS); + break; + case I386_ES: + i386_load_segment_descriptor(ES); + break; + case I386_FS: + i386_load_segment_descriptor(FS); + break; + case I386_GS: + i386_load_segment_descriptor(GS); + break; + } +} + +void i386_device::state_export(const device_state_entry &entry) +{ + switch (entry.index()) + { + case I386_IP: + m_debugger_temp = m_eip & 0xffff; + break; + } +} + +void i386_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + switch (entry.index()) + { + case STATE_GENFLAGS: + strprintf(str, "%08X", get_flags()); + break; + case X87_ST0: + strprintf(str, "%f", fx80_to_double(ST(0))); + break; + case X87_ST1: + strprintf(str, "%f", fx80_to_double(ST(1))); + break; + case X87_ST2: + strprintf(str, "%f", fx80_to_double(ST(2))); + break; + case X87_ST3: + strprintf(str, "%f", fx80_to_double(ST(3))); + break; + case X87_ST4: + strprintf(str, "%f", fx80_to_double(ST(4))); + break; + case X87_ST5: + strprintf(str, "%f", fx80_to_double(ST(5))); + break; + case X87_ST6: + strprintf(str, "%f", fx80_to_double(ST(6))); + break; + case X87_ST7: + strprintf(str, "%f", fx80_to_double(ST(7))); + break; + case SSE_XMM0: + strprintf(str, "%08x%08x%08x%08x", XMM(0).d[3], XMM(0).d[2], XMM(0).d[1], XMM(0).d[0]); + break; + case SSE_XMM1: + strprintf(str, "%08x%08x%08x%08x", XMM(1).d[3], XMM(1).d[2], XMM(1).d[1], XMM(1).d[0]); + break; + case SSE_XMM2: + strprintf(str, "%08x%08x%08x%08x", XMM(2).d[3], XMM(2).d[2], XMM(2).d[1], XMM(2).d[0]); + break; + case SSE_XMM3: + strprintf(str, "%08x%08x%08x%08x", XMM(3).d[3], XMM(3).d[2], XMM(3).d[1], XMM(3).d[0]); + break; + case SSE_XMM4: + strprintf(str, "%08x%08x%08x%08x", XMM(4).d[3], XMM(4).d[2], XMM(4).d[1], XMM(4).d[0]); + break; + case SSE_XMM5: + strprintf(str, "%08x%08x%08x%08x", XMM(5).d[3], XMM(5).d[2], XMM(5).d[1], XMM(5).d[0]); + break; + case SSE_XMM6: + strprintf(str, "%08x%08x%08x%08x", XMM(6).d[3], XMM(6).d[2], XMM(6).d[1], XMM(6).d[0]); + break; + case SSE_XMM7: + strprintf(str, "%08x%08x%08x%08x", XMM(7).d[3], XMM(7).d[2], XMM(7).d[1], XMM(7).d[0]); + break; + } +} + +void i386_device::build_opcode_table(UINT32 features) +{ + int i; + for (i=0; i < 256; i++) + { + m_opcode_table1_16[i] = &i386_device::i386_invalid; + m_opcode_table1_32[i] = &i386_device::i386_invalid; + m_opcode_table2_16[i] = &i386_device::i386_invalid; + m_opcode_table2_32[i] = &i386_device::i386_invalid; + m_opcode_table366_16[i] = &i386_device::i386_invalid; + m_opcode_table366_32[i] = &i386_device::i386_invalid; + m_opcode_table3f2_16[i] = &i386_device::i386_invalid; + m_opcode_table3f2_32[i] = &i386_device::i386_invalid; + m_opcode_table3f3_16[i] = &i386_device::i386_invalid; + m_opcode_table3f3_32[i] = &i386_device::i386_invalid; + m_lock_table[0][i] = false; + m_lock_table[1][i] = false; + } + + for (i=0; i < sizeof(s_x86_opcode_table)/sizeof(X86_OPCODE); i++) + { + const X86_OPCODE *op = &s_x86_opcode_table[i]; + + if ((op->flags & features)) + { + if (op->flags & OP_2BYTE) + { + m_opcode_table2_32[op->opcode] = op->handler32; + m_opcode_table2_16[op->opcode] = op->handler16; + m_opcode_table366_32[op->opcode] = op->handler32; + m_opcode_table366_16[op->opcode] = op->handler16; + m_lock_table[1][op->opcode] = op->lockable; + } + else if (op->flags & OP_3BYTE66) + { + m_opcode_table366_32[op->opcode] = op->handler32; + m_opcode_table366_16[op->opcode] = op->handler16; + } + else if (op->flags & OP_3BYTEF2) + { + m_opcode_table3f2_32[op->opcode] = op->handler32; + m_opcode_table3f2_16[op->opcode] = op->handler16; + } + else if (op->flags & OP_3BYTEF3) + { + m_opcode_table3f3_32[op->opcode] = op->handler32; + m_opcode_table3f3_16[op->opcode] = op->handler16; + } + else if (op->flags & OP_3BYTE38) + { + m_opcode_table338_32[op->opcode] = op->handler32; + m_opcode_table338_16[op->opcode] = op->handler16; + } + else if (op->flags & OP_3BYTE3A) + { + m_opcode_table33a_32[op->opcode] = op->handler32; + m_opcode_table33a_16[op->opcode] = op->handler16; + } + else if (op->flags & OP_4BYTE3866) + { + m_opcode_table46638_32[op->opcode] = op->handler32; + m_opcode_table46638_16[op->opcode] = op->handler16; + } + else if (op->flags & OP_4BYTE3A66) + { + m_opcode_table4663a_32[op->opcode] = op->handler32; + m_opcode_table4663a_16[op->opcode] = op->handler16; + } + else if (op->flags & OP_4BYTE38F2) + { + m_opcode_table4f238_32[op->opcode] = op->handler32; + m_opcode_table4f238_16[op->opcode] = op->handler16; + } + else if (op->flags & OP_4BYTE3AF2) + { + m_opcode_table4f23a_32[op->opcode] = op->handler32; + m_opcode_table4f23a_16[op->opcode] = op->handler16; + } + else if (op->flags & OP_4BYTE38F3) + { + m_opcode_table4f338_32[op->opcode] = op->handler32; + m_opcode_table4f338_16[op->opcode] = op->handler16; + } + else + { + m_opcode_table1_32[op->opcode] = op->handler32; + m_opcode_table1_16[op->opcode] = op->handler16; + m_lock_table[0][op->opcode] = op->lockable; + } + } + } +} + +void i386_device::zero_state() +{ + memset( &m_reg, 0, sizeof(m_reg) ); + memset( m_sreg, 0, sizeof(m_sreg) ); + m_eip = 0; + m_pc = 0; + m_prev_eip = 0; + m_eflags = 0; + m_eflags_mask = 0; + m_CF = 0; + m_DF = 0; + m_SF = 0; + m_OF = 0; + m_ZF = 0; + m_PF = 0; + m_AF = 0; + m_IF = 0; + m_TF = 0; + m_IOP1 = 0; + m_IOP2 = 0; + m_NT = 0; + m_RF = 0; + m_VM = 0; + m_AC = 0; + m_VIF = 0; + m_VIP = 0; + m_ID = 0; + m_CPL = 0; + m_performed_intersegment_jump = 0; + m_delayed_interrupt_enable = 0; + memset( m_cr, 0, sizeof(m_cr) ); + memset( m_dr, 0, sizeof(m_dr) ); + memset( m_tr, 0, sizeof(m_tr) ); + memset( &m_gdtr, 0, sizeof(m_gdtr) ); + memset( &m_idtr, 0, sizeof(m_idtr) ); + memset( &m_task, 0, sizeof(m_task) ); + memset( &m_ldtr, 0, sizeof(m_ldtr) ); + m_ext = 0; + m_halted = 0; + m_operand_size = 0; + m_xmm_operand_size = 0; + m_address_size = 0; + m_operand_prefix = 0; + m_address_prefix = 0; + m_segment_prefix = 0; + m_segment_override = 0; + m_cycles = 0; + m_base_cycles = 0; + m_opcode = 0; + m_irq_state = 0; + m_a20_mask = 0; + m_cpuid_max_input_value_eax = 0; + m_cpuid_id0 = 0; + m_cpuid_id1 = 0; + m_cpuid_id2 = 0; + m_cpu_version = 0; + m_feature_flags = 0; + m_tsc = 0; + m_perfctr[0] = m_perfctr[1] = 0; + memset( m_x87_reg, 0, sizeof(m_x87_reg) ); + m_x87_cw = 0; + m_x87_sw = 0; + m_x87_tw = 0; + m_x87_data_ptr = 0; + m_x87_inst_ptr = 0; + m_x87_opcode = 0; + memset( m_sse_reg, 0, sizeof(m_sse_reg) ); + m_mxcsr = 0; + m_smm = false; + m_smi = false; + m_smi_latched = false; + m_nmi_masked = false; + m_nmi_latched = false; + m_smbase = 0; + memset( m_opcode_bytes, 0, sizeof(m_opcode_bytes) ); + m_opcode_pc = 0; + m_opcode_bytes_length = 0; +} + +void i386_device::device_reset() +{ + zero_state(); + vtlb_flush_dynamic(m_vtlb); + + m_sreg[CS].selector = 0xf000; + m_sreg[CS].base = 0xffff0000; + m_sreg[CS].limit = 0xffff; + m_sreg[CS].flags = 0x9b; + m_sreg[CS].valid = true; + + m_sreg[DS].base = m_sreg[ES].base = m_sreg[FS].base = m_sreg[GS].base = m_sreg[SS].base = 0x00000000; + m_sreg[DS].limit = m_sreg[ES].limit = m_sreg[FS].limit = m_sreg[GS].limit = m_sreg[SS].limit = 0xffff; + m_sreg[DS].flags = m_sreg[ES].flags = m_sreg[FS].flags = m_sreg[GS].flags = m_sreg[SS].flags = 0x0092; + m_sreg[DS].valid = m_sreg[ES].valid = m_sreg[FS].valid = m_sreg[GS].valid = m_sreg[SS].valid =true; + + m_idtr.base = 0; + m_idtr.limit = 0x3ff; + m_smm = false; + m_smi_latched = false; + m_nmi_masked = false; + m_nmi_latched = false; + + m_a20_mask = ~0; + + m_cr[0] = 0x7fffffe0; // reserved bits set to 1 + m_eflags = 0; + m_eflags_mask = 0x00037fd7; + m_eip = 0xfff0; + + // [11:8] Family + // [ 7:4] Model + // [ 3:0] Stepping ID + // Family 3 (386), Model 0 (DX), Stepping 8 (D1) + REG32(EAX) = 0; + REG32(EDX) = (3 << 8) | (0 << 4) | (8); + + m_CPL = 0; + + CHANGE_PC(m_eip); +} + +void i386_device::pentium_smi() +{ + UINT32 smram_state = m_smbase + 0xfe00; + UINT32 old_cr0 = m_cr[0]; + UINT32 old_flags = get_flags(); + + if(m_smm) + return; + + m_cr[0] &= ~(0x8000000d); + set_flags(2); + if(!m_smiact.isnull()) + m_smiact(true); + m_smm = true; + m_smi_latched = false; + + // save state + WRITE32(m_cr[4], smram_state+SMRAM_IP5_CR4); + WRITE32(m_sreg[ES].limit, smram_state+SMRAM_IP5_ESLIM); + WRITE32(m_sreg[ES].base, smram_state+SMRAM_IP5_ESBASE); + WRITE32(m_sreg[ES].flags, smram_state+SMRAM_IP5_ESACC); + WRITE32(m_sreg[CS].limit, smram_state+SMRAM_IP5_CSLIM); + WRITE32(m_sreg[CS].base, smram_state+SMRAM_IP5_CSBASE); + WRITE32(m_sreg[CS].flags, smram_state+SMRAM_IP5_CSACC); + WRITE32(m_sreg[SS].limit, smram_state+SMRAM_IP5_SSLIM); + WRITE32(m_sreg[SS].base, smram_state+SMRAM_IP5_SSBASE); + WRITE32(m_sreg[SS].flags, smram_state+SMRAM_IP5_SSACC); + WRITE32(m_sreg[DS].limit, smram_state+SMRAM_IP5_DSLIM); + WRITE32(m_sreg[DS].base, smram_state+SMRAM_IP5_DSBASE); + WRITE32(m_sreg[DS].flags, smram_state+SMRAM_IP5_DSACC); + WRITE32(m_sreg[FS].limit, smram_state+SMRAM_IP5_FSLIM); + WRITE32(m_sreg[FS].base, smram_state+SMRAM_IP5_FSBASE); + WRITE32(m_sreg[FS].flags, smram_state+SMRAM_IP5_FSACC); + WRITE32(m_sreg[GS].limit, smram_state+SMRAM_IP5_GSLIM); + WRITE32(m_sreg[GS].base, smram_state+SMRAM_IP5_GSBASE); + WRITE32(m_sreg[GS].flags, smram_state+SMRAM_IP5_GSACC); + WRITE32(m_ldtr.flags, smram_state+SMRAM_IP5_LDTACC); + WRITE32(m_ldtr.limit, smram_state+SMRAM_IP5_LDTLIM); + WRITE32(m_ldtr.base, smram_state+SMRAM_IP5_LDTBASE); + WRITE32(m_gdtr.limit, smram_state+SMRAM_IP5_GDTLIM); + WRITE32(m_gdtr.base, smram_state+SMRAM_IP5_GDTBASE); + WRITE32(m_idtr.limit, smram_state+SMRAM_IP5_IDTLIM); + WRITE32(m_idtr.base, smram_state+SMRAM_IP5_IDTBASE); + WRITE32(m_task.limit, smram_state+SMRAM_IP5_TRLIM); + WRITE32(m_task.base, smram_state+SMRAM_IP5_TRBASE); + WRITE32(m_task.flags, smram_state+SMRAM_IP5_TRACC); + + WRITE32(m_sreg[ES].selector, smram_state+SMRAM_ES); + WRITE32(m_sreg[CS].selector, smram_state+SMRAM_CS); + WRITE32(m_sreg[SS].selector, smram_state+SMRAM_SS); + WRITE32(m_sreg[DS].selector, smram_state+SMRAM_DS); + WRITE32(m_sreg[FS].selector, smram_state+SMRAM_FS); + WRITE32(m_sreg[GS].selector, smram_state+SMRAM_GS); + WRITE32(m_ldtr.segment, smram_state+SMRAM_LDTR); + WRITE32(m_task.segment, smram_state+SMRAM_TR); + + WRITE32(m_dr[7], smram_state+SMRAM_DR7); + WRITE32(m_dr[6], smram_state+SMRAM_DR6); + WRITE32(REG32(EAX), smram_state+SMRAM_EAX); + WRITE32(REG32(ECX), smram_state+SMRAM_ECX); + WRITE32(REG32(EDX), smram_state+SMRAM_EDX); + WRITE32(REG32(EBX), smram_state+SMRAM_EBX); + WRITE32(REG32(ESP), smram_state+SMRAM_ESP); + WRITE32(REG32(EBP), smram_state+SMRAM_EBP); + WRITE32(REG32(ESI), smram_state+SMRAM_ESI); + WRITE32(REG32(EDI), smram_state+SMRAM_EDI); + WRITE32(m_eip, smram_state+SMRAM_EIP); + WRITE32(old_flags, smram_state+SMRAM_EAX); + WRITE32(m_cr[3], smram_state+SMRAM_CR3); + WRITE32(old_cr0, smram_state+SMRAM_CR0); + + m_sreg[DS].selector = m_sreg[ES].selector = m_sreg[FS].selector = m_sreg[GS].selector = m_sreg[SS].selector = 0; + m_sreg[DS].base = m_sreg[ES].base = m_sreg[FS].base = m_sreg[GS].base = m_sreg[SS].base = 0x00000000; + m_sreg[DS].limit = m_sreg[ES].limit = m_sreg[FS].limit = m_sreg[GS].limit = m_sreg[SS].limit = 0xffffffff; + m_sreg[DS].flags = m_sreg[ES].flags = m_sreg[FS].flags = m_sreg[GS].flags = m_sreg[SS].flags = 0x8093; + m_sreg[DS].valid = m_sreg[ES].valid = m_sreg[FS].valid = m_sreg[GS].valid = m_sreg[SS].valid =true; + m_sreg[CS].selector = 0x3000; // pentium only, ppro sel = smbase >> 4 + m_sreg[CS].base = m_smbase; + m_sreg[CS].limit = 0xffffffff; + m_sreg[CS].flags = 0x809b; + m_sreg[CS].valid = true; + m_cr[4] = 0; + m_dr[7] = 0x400; + m_eip = 0x8000; + + m_nmi_masked = true; + CHANGE_PC(m_eip); +} + +void i386_device::execute_set_input(int irqline, int state) +{ + if ( irqline == INPUT_LINE_A20 ) + { + i386_set_a20_line( state ); + return; + } + if ( irqline == INPUT_LINE_NMI ) + { + if ( state != CLEAR_LINE && m_halted) + { + m_halted = 0; + } + + /* NMI (I do not think that this is 100% right) */ + if(m_nmi_masked) + { + m_nmi_latched = true; + return; + } + if ( state ) + i386_trap(2, 1, 0); + } + else + { + if (irqline >= 0 && irqline <= MAX_INPUT_LINES) + { + if ( state != CLEAR_LINE && m_halted ) + { + m_halted = 0; + } + + m_irq_state = state; + } + } +} + +void pentium_device::execute_set_input(int irqline, int state) +{ + if ( irqline == INPUT_LINE_SMI ) + { + if ( !m_smi && state && m_smm ) + { + m_smi_latched = true; + } + m_smi = state; + } + else + { + i386_device::execute_set_input(irqline, state); + } +} + +void i386_device::i386_set_a20_line(int state) +{ + if (state) + { + m_a20_mask = ~0; + } + else + { + m_a20_mask = ~(1 << 20); + } + // TODO: how does A20M and the tlb interact + vtlb_flush_dynamic(m_vtlb); +} + +void i386_device::execute_run() +{ + int cycles = m_cycles; + m_base_cycles = cycles; + CHANGE_PC(m_eip); + + if (m_halted) + { + m_tsc += cycles; + m_cycles = 0; + return; + } + + while( m_cycles > 0 ) + { + i386_check_irq_line(); + m_operand_size = m_sreg[CS].d; + m_xmm_operand_size = 0; + m_address_size = m_sreg[CS].d; + m_operand_prefix = 0; + m_address_prefix = 0; + + m_ext = 1; + int old_tf = m_TF; + + m_segment_prefix = 0; + m_prev_eip = m_eip; + + debugger_instruction_hook(this, m_pc); + + if(m_delayed_interrupt_enable != 0) + { + m_IF = 1; + m_delayed_interrupt_enable = 0; + } +#ifdef DEBUG_MISSING_OPCODE + m_opcode_bytes_length = 0; + m_opcode_pc = m_pc; +#endif + try + { + i386_decode_opcode(); + if(m_TF && old_tf) + { + m_prev_eip = m_eip; + m_ext = 1; + i386_trap(1,0,0); + } + if(m_lock && (m_opcode != 0xf0)) + m_lock = false; + } + catch(UINT64 e) + { + m_ext = 1; + i386_trap_with_error(e&0xffffffff,0,0,e>>32); + } + } + m_tsc += (cycles - m_cycles); +} + +/*************************************************************************/ + +bool i386_device::memory_translate(address_spacenum spacenum, int intention, offs_t &address) +{ + bool ret = true; + if(spacenum == AS_PROGRAM) + ret = i386_translate_address(intention, &address, NULL); + address &= m_a20_mask; + return ret; +} + +offs_t i386_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + return i386_dasm_one(buffer, pc, oprom, m_sreg[CS].d ? 32 : 16); +} + + +/*****************************************************************************/ +/* Intel 486 */ + + +void i486_device::device_start() +{ + i386_common_init(32); + + build_opcode_table(OP_I386 | OP_FPU | OP_I486); + build_x87_opcode_table(); + m_cycle_table_rm = cycle_table_rm[CPU_CYCLES_I486]; + m_cycle_table_pm = cycle_table_pm[CPU_CYCLES_I486]; + + register_state_i386_x87(); +} + +void i486_device::device_reset() +{ + zero_state(); + vtlb_flush_dynamic(m_vtlb); + + m_sreg[CS].selector = 0xf000; + m_sreg[CS].base = 0xffff0000; + m_sreg[CS].limit = 0xffff; + m_sreg[CS].flags = 0x009b; + + m_sreg[DS].base = m_sreg[ES].base = m_sreg[FS].base = m_sreg[GS].base = m_sreg[SS].base = 0x00000000; + m_sreg[DS].limit = m_sreg[ES].limit = m_sreg[FS].limit = m_sreg[GS].limit = m_sreg[SS].limit = 0xffff; + m_sreg[DS].flags = m_sreg[ES].flags = m_sreg[FS].flags = m_sreg[GS].flags = m_sreg[SS].flags = 0x0092; + + m_idtr.base = 0; + m_idtr.limit = 0x3ff; + + m_a20_mask = ~0; + + m_cr[0] = 0x00000010; + m_eflags = 0; + m_eflags_mask = 0x00077fd7; + m_eip = 0xfff0; + m_smm = false; + m_smi_latched = false; + m_nmi_masked = false; + m_nmi_latched = false; + + x87_reset(); + + // [11:8] Family + // [ 7:4] Model + // [ 3:0] Stepping ID + // Family 4 (486), Model 0/1 (DX), Stepping 3 + REG32(EAX) = 0; + REG32(EDX) = (4 << 8) | (0 << 4) | (3); + + CHANGE_PC(m_eip); +} + + +/*****************************************************************************/ +/* Pentium */ + + +void pentium_device::device_start() +{ + // 64 dtlb small, 8 dtlb large, 32 itlb + i386_common_init(96); + register_state_i386_x87(); + + build_opcode_table(OP_I386 | OP_FPU | OP_I486 | OP_PENTIUM); + build_x87_opcode_table(); + m_cycle_table_rm = cycle_table_rm[CPU_CYCLES_PENTIUM]; + m_cycle_table_pm = cycle_table_pm[CPU_CYCLES_PENTIUM]; +} + +void pentium_device::device_reset() +{ + zero_state(); + vtlb_flush_dynamic(m_vtlb); + + m_sreg[CS].selector = 0xf000; + m_sreg[CS].base = 0xffff0000; + m_sreg[CS].limit = 0xffff; + m_sreg[CS].flags = 0x009b; + + m_sreg[DS].base = m_sreg[ES].base = m_sreg[FS].base = m_sreg[GS].base = m_sreg[SS].base = 0x00000000; + m_sreg[DS].limit = m_sreg[ES].limit = m_sreg[FS].limit = m_sreg[GS].limit = m_sreg[SS].limit = 0xffff; + m_sreg[DS].flags = m_sreg[ES].flags = m_sreg[FS].flags = m_sreg[GS].flags = m_sreg[SS].flags = 0x0092; + + m_idtr.base = 0; + m_idtr.limit = 0x3ff; + + m_a20_mask = ~0; + + m_cr[0] = 0x00000010; + m_eflags = 0x00200000; + m_eflags_mask = 0x003f7fd7; + m_eip = 0xfff0; + m_mxcsr = 0x1f80; + m_smm = false; + m_smi_latched = false; + m_smbase = 0x30000; + m_nmi_masked = false; + m_nmi_latched = false; + + x87_reset(); + + // [11:8] Family + // [ 7:4] Model + // [ 3:0] Stepping ID + // Family 5 (Pentium), Model 2 (75 - 200MHz), Stepping 5 + REG32(EAX) = 0; + REG32(EDX) = (5 << 8) | (2 << 4) | (5); + + m_cpuid_id0 = 0x756e6547; // Genu + m_cpuid_id1 = 0x49656e69; // ineI + m_cpuid_id2 = 0x6c65746e; // ntel + + m_cpuid_max_input_value_eax = 0x01; + m_cpu_version = REG32(EDX); + + // [ 0:0] FPU on chip + // [ 2:2] I/O breakpoints + // [ 4:4] Time Stamp Counter + // [ 5:5] Pentium CPU style model specific registers + // [ 7:7] Machine Check Exception + // [ 8:8] CMPXCHG8B instruction + m_feature_flags = 0x000001bf; + + CHANGE_PC(m_eip); +} + + +/*****************************************************************************/ +/* Cyrix MediaGX */ + + +void mediagx_device::device_start() +{ + // probably 32 unified + i386_common_init(32); + register_state_i386_x87(); + + build_x87_opcode_table(); + build_opcode_table(OP_I386 | OP_FPU | OP_I486 | OP_PENTIUM | OP_CYRIX); + m_cycle_table_rm = cycle_table_rm[CPU_CYCLES_MEDIAGX]; + m_cycle_table_pm = cycle_table_pm[CPU_CYCLES_MEDIAGX]; +} + +void mediagx_device::device_reset() +{ + zero_state(); + vtlb_flush_dynamic(m_vtlb); + + m_sreg[CS].selector = 0xf000; + m_sreg[CS].base = 0xffff0000; + m_sreg[CS].limit = 0xffff; + m_sreg[CS].flags = 0x009b; + + m_sreg[DS].base = m_sreg[ES].base = m_sreg[FS].base = m_sreg[GS].base = m_sreg[SS].base = 0x00000000; + m_sreg[DS].limit = m_sreg[ES].limit = m_sreg[FS].limit = m_sreg[GS].limit = m_sreg[SS].limit = 0xffff; + m_sreg[DS].flags = m_sreg[ES].flags = m_sreg[FS].flags = m_sreg[GS].flags = m_sreg[SS].flags = 0x0092; + + m_idtr.base = 0; + m_idtr.limit = 0x3ff; + + m_a20_mask = ~0; + + m_cr[0] = 0x00000010; + m_eflags = 0x00200000; + m_eflags_mask = 0x00277fd7; /* TODO: is this correct? */ + m_eip = 0xfff0; + m_smm = false; + m_smi_latched = false; + m_nmi_masked = false; + m_nmi_latched = false; + + x87_reset(); + + // [11:8] Family + // [ 7:4] Model + // [ 3:0] Stepping ID + // Family 4, Model 4 (MediaGX) + REG32(EAX) = 0; + REG32(EDX) = (4 << 8) | (4 << 4) | (1); /* TODO: is this correct? */ + + m_cpuid_id0 = 0x69727943; // Cyri + m_cpuid_id1 = 0x736e4978; // xIns + m_cpuid_id2 = 0x6d616574; // tead + + m_cpuid_max_input_value_eax = 0x01; + m_cpu_version = REG32(EDX); + + // [ 0:0] FPU on chip + m_feature_flags = 0x00000001; + + CHANGE_PC(m_eip); +} + +/*****************************************************************************/ +/* Intel Pentium Pro */ + +void pentium_pro_device::device_start() +{ + // 64 dtlb small, 32 itlb + i386_common_init(96); + register_state_i386_x87(); + + build_x87_opcode_table(); + build_opcode_table(OP_I386 | OP_FPU | OP_I486 | OP_PENTIUM | OP_PPRO); + m_cycle_table_rm = cycle_table_rm[CPU_CYCLES_PENTIUM]; // TODO: generate own cycle tables + m_cycle_table_pm = cycle_table_pm[CPU_CYCLES_PENTIUM]; // TODO: generate own cycle tables +} + +void pentium_pro_device::device_reset() +{ + zero_state(); + vtlb_flush_dynamic(m_vtlb); + + m_sreg[CS].selector = 0xf000; + m_sreg[CS].base = 0xffff0000; + m_sreg[CS].limit = 0xffff; + m_sreg[CS].flags = 0x009b; + + m_sreg[DS].base = m_sreg[ES].base = m_sreg[FS].base = m_sreg[GS].base = m_sreg[SS].base = 0x00000000; + m_sreg[DS].limit = m_sreg[ES].limit = m_sreg[FS].limit = m_sreg[GS].limit = m_sreg[SS].limit = 0xffff; + m_sreg[DS].flags = m_sreg[ES].flags = m_sreg[FS].flags = m_sreg[GS].flags = m_sreg[SS].flags = 0x0092; + + m_idtr.base = 0; + m_idtr.limit = 0x3ff; + + m_a20_mask = ~0; + + m_cr[0] = 0x60000010; + m_eflags = 0x00200000; + m_eflags_mask = 0x00277fd7; /* TODO: is this correct? */ + m_eip = 0xfff0; + m_mxcsr = 0x1f80; + m_smm = false; + m_smi_latched = false; + m_smbase = 0x30000; + m_nmi_masked = false; + m_nmi_latched = false; + + x87_reset(); + + // [11:8] Family + // [ 7:4] Model + // [ 3:0] Stepping ID + // Family 6, Model 1 (Pentium Pro) + REG32(EAX) = 0; + REG32(EDX) = (6 << 8) | (1 << 4) | (1); /* TODO: is this correct? */ + + m_cpuid_id0 = 0x756e6547; // Genu + m_cpuid_id1 = 0x49656e69; // ineI + m_cpuid_id2 = 0x6c65746e; // ntel + + m_cpuid_max_input_value_eax = 0x02; + m_cpu_version = REG32(EDX); + + // [ 0:0] FPU on chip + // [ 2:2] I/O breakpoints + // [ 4:4] Time Stamp Counter + // [ 5:5] Pentium CPU style model specific registers + // [ 7:7] Machine Check Exception + // [ 8:8] CMPXCHG8B instruction + // [15:15] CMOV and FCMOV + // No MMX + m_feature_flags = 0x000081bf; + + CHANGE_PC(m_eip); +} + + +/*****************************************************************************/ +/* Intel Pentium MMX */ + +void pentium_mmx_device::device_start() +{ + // 64 dtlb small, 8 dtlb large, 32 itlb small, 2 itlb large + i386_common_init(96); + register_state_i386_x87(); + + build_x87_opcode_table(); + build_opcode_table(OP_I386 | OP_FPU | OP_I486 | OP_PENTIUM | OP_MMX); + m_cycle_table_rm = cycle_table_rm[CPU_CYCLES_PENTIUM]; // TODO: generate own cycle tables + m_cycle_table_pm = cycle_table_pm[CPU_CYCLES_PENTIUM]; // TODO: generate own cycle tables +} + +void pentium_mmx_device::device_reset() +{ + zero_state(); + vtlb_flush_dynamic(m_vtlb); + + m_sreg[CS].selector = 0xf000; + m_sreg[CS].base = 0xffff0000; + m_sreg[CS].limit = 0xffff; + m_sreg[CS].flags = 0x009b; + + m_sreg[DS].base = m_sreg[ES].base = m_sreg[FS].base = m_sreg[GS].base = m_sreg[SS].base = 0x00000000; + m_sreg[DS].limit = m_sreg[ES].limit = m_sreg[FS].limit = m_sreg[GS].limit = m_sreg[SS].limit = 0xffff; + m_sreg[DS].flags = m_sreg[ES].flags = m_sreg[FS].flags = m_sreg[GS].flags = m_sreg[SS].flags = 0x0092; + + m_idtr.base = 0; + m_idtr.limit = 0x3ff; + + m_a20_mask = ~0; + + m_cr[0] = 0x60000010; + m_eflags = 0x00200000; + m_eflags_mask = 0x00277fd7; /* TODO: is this correct? */ + m_eip = 0xfff0; + m_mxcsr = 0x1f80; + m_smm = false; + m_smi_latched = false; + m_smbase = 0x30000; + m_nmi_masked = false; + m_nmi_latched = false; + + x87_reset(); + + // [11:8] Family + // [ 7:4] Model + // [ 3:0] Stepping ID + // Family 5, Model 4 (P55C) + REG32(EAX) = 0; + REG32(EDX) = (5 << 8) | (4 << 4) | (1); + + m_cpuid_id0 = 0x756e6547; // Genu + m_cpuid_id1 = 0x49656e69; // ineI + m_cpuid_id2 = 0x6c65746e; // ntel + + m_cpuid_max_input_value_eax = 0x01; + m_cpu_version = REG32(EDX); + + // [ 0:0] FPU on chip + // [ 2:2] I/O breakpoints + // [ 4:4] Time Stamp Counter + // [ 5:5] Pentium CPU style model specific registers + // [ 7:7] Machine Check Exception + // [ 8:8] CMPXCHG8B instruction + // [23:23] MMX instructions + m_feature_flags = 0x008001bf; + + CHANGE_PC(m_eip); +} + +/*****************************************************************************/ +/* Intel Pentium II */ + +void pentium2_device::device_start() +{ + // 64 dtlb small, 8 dtlb large, 32 itlb small, 2 itlb large + i386_common_init(96); + register_state_i386_x87(); + + build_x87_opcode_table(); + build_opcode_table(OP_I386 | OP_FPU | OP_I486 | OP_PENTIUM | OP_PPRO | OP_MMX); + m_cycle_table_rm = cycle_table_rm[CPU_CYCLES_PENTIUM]; // TODO: generate own cycle tables + m_cycle_table_pm = cycle_table_pm[CPU_CYCLES_PENTIUM]; // TODO: generate own cycle tables +} + +void pentium2_device::device_reset() +{ + zero_state(); + vtlb_flush_dynamic(m_vtlb); + + m_sreg[CS].selector = 0xf000; + m_sreg[CS].base = 0xffff0000; + m_sreg[CS].limit = 0xffff; + m_sreg[CS].flags = 0x009b; + + m_sreg[DS].base = m_sreg[ES].base = m_sreg[FS].base = m_sreg[GS].base = m_sreg[SS].base = 0x00000000; + m_sreg[DS].limit = m_sreg[ES].limit = m_sreg[FS].limit = m_sreg[GS].limit = m_sreg[SS].limit = 0xffff; + m_sreg[DS].flags = m_sreg[ES].flags = m_sreg[FS].flags = m_sreg[GS].flags = m_sreg[SS].flags = 0x0092; + + m_idtr.base = 0; + m_idtr.limit = 0x3ff; + + m_a20_mask = ~0; + + m_cr[0] = 0x60000010; + m_eflags = 0x00200000; + m_eflags_mask = 0x00277fd7; /* TODO: is this correct? */ + m_eip = 0xfff0; + m_mxcsr = 0x1f80; + m_smm = false; + m_smi_latched = false; + m_smbase = 0x30000; + m_nmi_masked = false; + m_nmi_latched = false; + + x87_reset(); + + // [11:8] Family + // [ 7:4] Model + // [ 3:0] Stepping ID + // Family 6, Model 3 (Pentium II / Klamath) + REG32(EAX) = 0; + REG32(EDX) = (6 << 8) | (3 << 4) | (1); /* TODO: is this correct? */ + + m_cpuid_id0 = 0x756e6547; // Genu + m_cpuid_id1 = 0x49656e69; // ineI + m_cpuid_id2 = 0x6c65746e; // ntel + + m_cpuid_max_input_value_eax = 0x02; + m_cpu_version = REG32(EDX); + + // [ 0:0] FPU on chip + m_feature_flags = 0x008081bf; // TODO: enable relevant flags here + + CHANGE_PC(m_eip); +} + +/*****************************************************************************/ +/* Intel Pentium III */ + +void pentium3_device::device_start() +{ + // 64 dtlb small, 8 dtlb large, 32 itlb small, 2 itlb large + i386_common_init(96); + register_state_i386_x87_xmm(); + + build_x87_opcode_table(); + build_opcode_table(OP_I386 | OP_FPU | OP_I486 | OP_PENTIUM | OP_PPRO | OP_MMX | OP_SSE); + m_cycle_table_rm = cycle_table_rm[CPU_CYCLES_PENTIUM]; // TODO: generate own cycle tables + m_cycle_table_pm = cycle_table_pm[CPU_CYCLES_PENTIUM]; // TODO: generate own cycle tables +} + +void pentium3_device::device_reset() +{ + zero_state(); + vtlb_flush_dynamic(m_vtlb); + + m_sreg[CS].selector = 0xf000; + m_sreg[CS].base = 0xffff0000; + m_sreg[CS].limit = 0xffff; + m_sreg[CS].flags = 0x009b; + + m_sreg[DS].base = m_sreg[ES].base = m_sreg[FS].base = m_sreg[GS].base = m_sreg[SS].base = 0x00000000; + m_sreg[DS].limit = m_sreg[ES].limit = m_sreg[FS].limit = m_sreg[GS].limit = m_sreg[SS].limit = 0xffff; + m_sreg[DS].flags = m_sreg[ES].flags = m_sreg[FS].flags = m_sreg[GS].flags = m_sreg[SS].flags = 0x0092; + + m_idtr.base = 0; + m_idtr.limit = 0x3ff; + + m_a20_mask = ~0; + + m_cr[0] = 0x60000010; + m_eflags = 0x00200000; + m_eflags_mask = 0x00277fd7; /* TODO: is this correct? */ + m_eip = 0xfff0; + m_mxcsr = 0x1f80; + m_smm = false; + m_smi_latched = false; + m_smbase = 0x30000; + m_nmi_masked = false; + m_nmi_latched = false; + + x87_reset(); + + // [11:8] Family + // [ 7:4] Model + // [ 3:0] Stepping ID + // Family 6, Model 8 (Pentium III / Coppermine) + REG32(EAX) = 0; + REG32(EDX) = (6 << 8) | (8 << 4) | (10); + + m_cpuid_id0 = 0x756e6547; // Genu + m_cpuid_id1 = 0x49656e69; // ineI + m_cpuid_id2 = 0x6c65746e; // ntel + + m_cpuid_max_input_value_eax = 0x03; + m_cpu_version = REG32(EDX); + + // [ 0:0] FPU on chip + // [ 4:4] Time Stamp Counter + // [ D:D] PTE Global Bit + m_feature_flags = 0x00002011; // TODO: enable relevant flags here + + CHANGE_PC(m_eip); +} + +/*****************************************************************************/ +/* Intel Pentium 4 */ + +void pentium4_device::device_start() +{ + // 128 dtlb, 64 itlb + i386_common_init(196); + register_state_i386_x87_xmm(); + + build_x87_opcode_table(); + build_opcode_table(OP_I386 | OP_FPU | OP_I486 | OP_PENTIUM | OP_PPRO | OP_MMX | OP_SSE | OP_SSE2); + m_cycle_table_rm = cycle_table_rm[CPU_CYCLES_PENTIUM]; // TODO: generate own cycle tables + m_cycle_table_pm = cycle_table_pm[CPU_CYCLES_PENTIUM]; // TODO: generate own cycle tables +} + +void pentium4_device::device_reset() +{ + zero_state(); + vtlb_flush_dynamic(m_vtlb); + + m_sreg[CS].selector = 0xf000; + m_sreg[CS].base = 0xffff0000; + m_sreg[CS].limit = 0xffff; + m_sreg[CS].flags = 0x009b; + + m_sreg[DS].base = m_sreg[ES].base = m_sreg[FS].base = m_sreg[GS].base = m_sreg[SS].base = 0x00000000; + m_sreg[DS].limit = m_sreg[ES].limit = m_sreg[FS].limit = m_sreg[GS].limit = m_sreg[SS].limit = 0xffff; + m_sreg[DS].flags = m_sreg[ES].flags = m_sreg[FS].flags = m_sreg[GS].flags = m_sreg[SS].flags = 0x0092; + + m_idtr.base = 0; + m_idtr.limit = 0x3ff; + + m_a20_mask = ~0; + + m_cr[0] = 0x60000010; + m_eflags = 0x00200000; + m_eflags_mask = 0x00277fd7; /* TODO: is this correct? */ + m_eip = 0xfff0; + m_mxcsr = 0x1f80; + m_smm = false; + m_smi_latched = false; + m_smbase = 0x30000; + m_nmi_masked = false; + m_nmi_latched = false; + + x87_reset(); + + // [27:20] Extended family + // [19:16] Extended model + // [13:12] Type + // [11: 8] Family + // [ 7: 4] Model + // [ 3: 0] Stepping ID + // Family 15, Model 0 (Pentium 4 / Willamette) + REG32(EAX) = 0; + REG32(EDX) = (0 << 20) | (0xf << 8) | (0 << 4) | (1); + + m_cpuid_id0 = 0x756e6547; // Genu + m_cpuid_id1 = 0x49656e69; // ineI + m_cpuid_id2 = 0x6c65746e; // ntel + + m_cpuid_max_input_value_eax = 0x02; + m_cpu_version = REG32(EDX); + + // [ 0:0] FPU on chip + m_feature_flags = 0x00000001; // TODO: enable relevant flags here + + CHANGE_PC(m_eip); +} diff --git a/src/devices/cpu/i386/i386.h b/src/devices/cpu/i386/i386.h new file mode 100644 index 00000000000..237001be9ac --- /dev/null +++ b/src/devices/cpu/i386/i386.h @@ -0,0 +1,1536 @@ +// license:BSD-3-Clause +// copyright-holders:Ville Linde, Barry Rodewald, Carl, Philip Bennett +#pragma once + +#ifndef __I386INTF_H__ +#define __I386INTF_H__ + +#include "softfloat/milieu.h" +#include "softfloat/softfloat.h" +#include "debug/debugcpu.h" +#include "cpu/vtlb.h" + + +#define INPUT_LINE_A20 1 +#define INPUT_LINE_SMI 2 + + +// mingw has this defined for 32-bit compiles +#undef i386 + + +#define MCFG_I386_SMIACT(_devcb) \ + i386_device::set_smiact(*device, DEVCB_##_devcb); + + +class i386_device : public cpu_device +{ +public: + // construction/destruction + i386_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + i386_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source, int program_data_width=32, int program_addr_width=32, int io_data_width=32); + + // static configuration helpers + template static devcb_base &set_smiact(device_t &device, _Object object) { return downcast(device).m_smiact.set_callback(object); } + + UINT64 debug_segbase(symbol_table &table, int params, const UINT64 *param); + UINT64 debug_seglimit(symbol_table &table, int params, const UINT64 *param); + UINT64 debug_segofftovirt(symbol_table &table, int params, const UINT64 *param); + UINT64 debug_virttophys(symbol_table &table, int params, const UINT64 *param); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_debug_setup(); + + // device_execute_interface overrides + virtual UINT32 execute_min_cycles() const { return 1; } + virtual UINT32 execute_max_cycles() const { return 40; } + virtual UINT32 execute_input_lines() const { return 32; } + virtual void execute_run(); + virtual void execute_set_input(int inputnum, int state); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const { return (spacenum == AS_PROGRAM) ? &m_program_config : ( (spacenum == AS_IO) ? &m_io_config : NULL ); } + virtual bool memory_translate(address_spacenum spacenum, int intention, offs_t &address); + + // device_state_interface overrides + virtual void state_import(const device_state_entry &entry); + virtual void state_export(const device_state_entry &entry); + virtual void state_string_export(const device_state_entry &entry, std::string &str); + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const { return 1; } + virtual UINT32 disasm_max_opcode_bytes() const { return 15; } + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + + address_space_config m_program_config; + address_space_config m_io_config; + +union I386_GPR { + UINT32 d[8]; + UINT16 w[16]; + UINT8 b[32]; +}; + +struct I386_SREG { + UINT16 selector; + UINT16 flags; + UINT32 base; + UINT32 limit; + int d; // Operand size + bool valid; +}; + +struct I386_SYS_TABLE { + UINT32 base; + UINT16 limit; +}; + +struct I386_SEG_DESC { + UINT16 segment; + UINT16 flags; + UINT32 base; + UINT32 limit; +}; + +union XMM_REG { + UINT8 b[16]; + UINT16 w[8]; + UINT32 d[4]; + UINT64 q[2]; + INT8 c[16]; + INT16 s[8]; + INT32 i[4]; + INT64 l[2]; + float f[4]; + double f64[2]; +}; + +union MMX_REG { + UINT32 d[2]; + INT32 i[2]; + UINT16 w[4]; + INT16 s[4]; + UINT8 b[8]; + INT8 c[8]; + float f[2]; + UINT64 q; + INT64 l; +}; + +struct I386_CALL_GATE +{ + UINT16 segment; + UINT16 selector; + UINT32 offset; + UINT8 ar; // access rights + UINT8 dpl; + UINT8 dword_count; + UINT8 present; +}; + + typedef void (i386_device::*i386_modrm_func)(UINT8 modrm); + typedef void (i386_device::*i386_op_func)(); + struct X86_OPCODE { + UINT8 opcode; + UINT32 flags; + i386_op_func handler16; + i386_op_func handler32; + bool lockable; + }; + static const X86_OPCODE s_x86_opcode_table[]; + + I386_GPR m_reg; + I386_SREG m_sreg[6]; + UINT32 m_eip; + UINT32 m_pc; + UINT32 m_prev_eip; + UINT32 m_eflags; + UINT32 m_eflags_mask; + UINT8 m_CF; + UINT8 m_DF; + UINT8 m_SF; + UINT8 m_OF; + UINT8 m_ZF; + UINT8 m_PF; + UINT8 m_AF; + UINT8 m_IF; + UINT8 m_TF; + UINT8 m_IOP1; + UINT8 m_IOP2; + UINT8 m_NT; + UINT8 m_RF; + UINT8 m_VM; + UINT8 m_AC; + UINT8 m_VIF; + UINT8 m_VIP; + UINT8 m_ID; + + UINT8 m_CPL; // current privilege level + + UINT8 m_performed_intersegment_jump; + UINT8 m_delayed_interrupt_enable; + + UINT32 m_cr[5]; // Control registers + UINT32 m_dr[8]; // Debug registers + UINT32 m_tr[8]; // Test registers + + I386_SYS_TABLE m_gdtr; // Global Descriptor Table Register + I386_SYS_TABLE m_idtr; // Interrupt Descriptor Table Register + I386_SEG_DESC m_task; // Task register + I386_SEG_DESC m_ldtr; // Local Descriptor Table Register + + UINT8 m_ext; // external interrupt + + int m_halted; + + int m_operand_size; + int m_xmm_operand_size; + int m_address_size; + int m_operand_prefix; + int m_address_prefix; + + int m_segment_prefix; + int m_segment_override; + + int m_cycles; + int m_base_cycles; + UINT8 m_opcode; + + UINT8 m_irq_state; + address_space *m_program; + direct_read_data *m_direct; + address_space *m_io; + UINT32 m_a20_mask; + + int m_cpuid_max_input_value_eax; + UINT32 m_cpuid_id0, m_cpuid_id1, m_cpuid_id2; + UINT32 m_cpu_version; + UINT32 m_feature_flags; + UINT64 m_tsc; + UINT64 m_perfctr[2]; + + // FPU + floatx80 m_x87_reg[8]; + + UINT16 m_x87_cw; + UINT16 m_x87_sw; + UINT16 m_x87_tw; + UINT64 m_x87_data_ptr; + UINT64 m_x87_inst_ptr; + UINT16 m_x87_opcode; + + i386_modrm_func m_opcode_table_x87_d8[256]; + i386_modrm_func m_opcode_table_x87_d9[256]; + i386_modrm_func m_opcode_table_x87_da[256]; + i386_modrm_func m_opcode_table_x87_db[256]; + i386_modrm_func m_opcode_table_x87_dc[256]; + i386_modrm_func m_opcode_table_x87_dd[256]; + i386_modrm_func m_opcode_table_x87_de[256]; + i386_modrm_func m_opcode_table_x87_df[256]; + + // SSE + XMM_REG m_sse_reg[8]; + UINT32 m_mxcsr; + + i386_op_func m_opcode_table1_16[256]; + i386_op_func m_opcode_table1_32[256]; + i386_op_func m_opcode_table2_16[256]; + i386_op_func m_opcode_table2_32[256]; + i386_op_func m_opcode_table338_16[256]; + i386_op_func m_opcode_table338_32[256]; + i386_op_func m_opcode_table33a_16[256]; + i386_op_func m_opcode_table33a_32[256]; + i386_op_func m_opcode_table366_16[256]; + i386_op_func m_opcode_table366_32[256]; + i386_op_func m_opcode_table3f2_16[256]; + i386_op_func m_opcode_table3f2_32[256]; + i386_op_func m_opcode_table3f3_16[256]; + i386_op_func m_opcode_table3f3_32[256]; + i386_op_func m_opcode_table46638_16[256]; + i386_op_func m_opcode_table46638_32[256]; + i386_op_func m_opcode_table4f238_16[256]; + i386_op_func m_opcode_table4f238_32[256]; + i386_op_func m_opcode_table4f338_16[256]; + i386_op_func m_opcode_table4f338_32[256]; + i386_op_func m_opcode_table4663a_16[256]; + i386_op_func m_opcode_table4663a_32[256]; + i386_op_func m_opcode_table4f23a_16[256]; + i386_op_func m_opcode_table4f23a_32[256]; + + bool m_lock_table[2][256]; + + UINT8 *m_cycle_table_pm; + UINT8 *m_cycle_table_rm; + + vtlb_state *m_vtlb; + + bool m_smm; + bool m_smi; + bool m_smi_latched; + bool m_nmi_masked; + bool m_nmi_latched; + UINT32 m_smbase; + devcb_write_line m_smiact; + bool m_lock; + + // bytes in current opcode, debug only + UINT8 m_opcode_bytes[16]; + UINT32 m_opcode_pc; + int m_opcode_bytes_length; + + UINT64 m_debugger_temp; + + void register_state_i386(); + void register_state_i386_x87(); + void register_state_i386_x87_xmm(); + inline UINT32 i386_translate(int segment, UINT32 ip, int rwn); + inline vtlb_entry get_permissions(UINT32 pte, int wp); + bool i386_translate_address(int intention, offs_t *address, vtlb_entry *entry); + inline int translate_address(int pl, int type, UINT32 *address, UINT32 *error); + inline void CHANGE_PC(UINT32 pc); + inline void NEAR_BRANCH(INT32 offs); + inline UINT8 FETCH(); + inline UINT16 FETCH16(); + inline UINT32 FETCH32(); + inline UINT8 READ8(UINT32 ea); + inline UINT16 READ16(UINT32 ea); + inline UINT32 READ32(UINT32 ea); + inline UINT64 READ64(UINT32 ea); + inline UINT8 READ8PL0(UINT32 ea); + inline UINT16 READ16PL0(UINT32 ea); + inline UINT32 READ32PL0(UINT32 ea); + inline void WRITE_TEST(UINT32 ea); + inline void WRITE8(UINT32 ea, UINT8 value); + inline void WRITE16(UINT32 ea, UINT16 value); + inline void WRITE32(UINT32 ea, UINT32 value); + inline void WRITE64(UINT32 ea, UINT64 value); + inline UINT8 OR8(UINT8 dst, UINT8 src); + inline UINT16 OR16(UINT16 dst, UINT16 src); + inline UINT32 OR32(UINT32 dst, UINT32 src); + inline UINT8 AND8(UINT8 dst, UINT8 src); + inline UINT16 AND16(UINT16 dst, UINT16 src); + inline UINT32 AND32(UINT32 dst, UINT32 src); + inline UINT8 XOR8(UINT8 dst, UINT8 src); + inline UINT16 XOR16(UINT16 dst, UINT16 src); + inline UINT32 XOR32(UINT32 dst, UINT32 src); + inline UINT8 SBB8(UINT8 dst, UINT8 src, UINT8 b); + inline UINT16 SBB16(UINT16 dst, UINT16 src, UINT16 b); + inline UINT32 SBB32(UINT32 dst, UINT32 src, UINT32 b); + inline UINT8 ADC8(UINT8 dst, UINT8 src, UINT8 c); + inline UINT16 ADC16(UINT16 dst, UINT16 src, UINT8 c); + inline UINT32 ADC32(UINT32 dst, UINT32 src, UINT32 c); + inline UINT8 INC8(UINT8 dst); + inline UINT16 INC16(UINT16 dst); + inline UINT32 INC32(UINT32 dst); + inline UINT8 DEC8(UINT8 dst); + inline UINT16 DEC16(UINT16 dst); + inline UINT32 DEC32(UINT32 dst); + inline void PUSH16(UINT16 value); + inline void PUSH32(UINT32 value); + inline void PUSH8(UINT8 value); + inline UINT8 POP8(); + inline UINT16 POP16(); + inline UINT32 POP32(); + inline void BUMP_SI(int adjustment); + inline void BUMP_DI(int adjustment); + inline void check_ioperm(offs_t port, UINT8 mask); + inline UINT8 READPORT8(offs_t port); + inline void WRITEPORT8(offs_t port, UINT8 value); + inline UINT16 READPORT16(offs_t port); + inline void WRITEPORT16(offs_t port, UINT16 value); + inline UINT32 READPORT32(offs_t port); + inline void WRITEPORT32(offs_t port, UINT32 value); + UINT64 pentium_msr_read(UINT32 offset,UINT8 *valid_msr); + void pentium_msr_write(UINT32 offset, UINT64 data, UINT8 *valid_msr); + UINT64 p6_msr_read(UINT32 offset,UINT8 *valid_msr); + void p6_msr_write(UINT32 offset, UINT64 data, UINT8 *valid_msr); + UINT64 piv_msr_read(UINT32 offset,UINT8 *valid_msr); + void piv_msr_write(UINT32 offset, UINT64 data, UINT8 *valid_msr); + inline UINT64 MSR_READ(UINT32 offset,UINT8 *valid_msr); + inline void MSR_WRITE(UINT32 offset, UINT64 data, UINT8 *valid_msr); + UINT32 i386_load_protected_mode_segment(I386_SREG *seg, UINT64 *desc ); + void i386_load_call_gate(I386_CALL_GATE *gate); + void i386_set_descriptor_accessed(UINT16 selector); + void i386_load_segment_descriptor(int segment ); + UINT32 i386_get_stack_segment(UINT8 privilege); + UINT32 i386_get_stack_ptr(UINT8 privilege); + UINT32 get_flags(); + void set_flags(UINT32 f ); + void sib_byte(UINT8 mod, UINT32* out_ea, UINT8* out_segment); + void modrm_to_EA(UINT8 mod_rm, UINT32* out_ea, UINT8* out_segment); + UINT32 GetNonTranslatedEA(UINT8 modrm,UINT8 *seg); + UINT32 GetEA(UINT8 modrm, int rwn); + void i386_check_sreg_validity(int reg); + int i386_limit_check(int seg, UINT32 offset); + void i386_sreg_load(UINT16 selector, UINT8 reg, bool *fault); + void i386_trap(int irq, int irq_gate, int trap_level); + void i386_trap_with_error(int irq, int irq_gate, int trap_level, UINT32 error); + void i286_task_switch(UINT16 selector, UINT8 nested); + void i386_task_switch(UINT16 selector, UINT8 nested); + void i386_check_irq_line(); + void i386_protected_mode_jump(UINT16 seg, UINT32 off, int indirect, int operand32); + void i386_protected_mode_call(UINT16 seg, UINT32 off, int indirect, int operand32); + void i386_protected_mode_retf(UINT8 count, UINT8 operand32); + void i386_protected_mode_iret(int operand32); + void build_cycle_table(); + void report_invalid_opcode(); + void report_invalid_modrm(const char* opcode, UINT8 modrm); + void i386_decode_opcode(); + void i386_decode_two_byte(); + void i386_decode_three_byte38(); + void i386_decode_three_byte3a(); + void i386_decode_three_byte66(); + void i386_decode_three_bytef2(); + void i386_decode_three_bytef3(); + void i386_decode_four_byte3866(); + void i386_decode_four_byte3a66(); + void i386_decode_four_byte38f2(); + void i386_decode_four_byte3af2(); + void i386_decode_four_byte38f3(); + UINT8 read8_debug(UINT32 ea, UINT8 *data); + UINT32 i386_get_debug_desc(I386_SREG *seg); + inline void CYCLES(int x); + inline void CYCLES_RM(int modrm, int r, int m); + UINT8 i386_shift_rotate8(UINT8 modrm, UINT32 value, UINT8 shift); + void i386_adc_rm8_r8(); + void i386_adc_r8_rm8(); + void i386_adc_al_i8(); + void i386_add_rm8_r8(); + void i386_add_r8_rm8(); + void i386_add_al_i8(); + void i386_and_rm8_r8(); + void i386_and_r8_rm8(); + void i386_and_al_i8(); + void i386_clc(); + void i386_cld(); + void i386_cli(); + void i386_cmc(); + void i386_cmp_rm8_r8(); + void i386_cmp_r8_rm8(); + void i386_cmp_al_i8(); + void i386_cmpsb(); + void i386_in_al_i8(); + void i386_in_al_dx(); + void i386_ja_rel8(); + void i386_jbe_rel8(); + void i386_jc_rel8(); + void i386_jg_rel8(); + void i386_jge_rel8(); + void i386_jl_rel8(); + void i386_jle_rel8(); + void i386_jnc_rel8(); + void i386_jno_rel8(); + void i386_jnp_rel8(); + void i386_jns_rel8(); + void i386_jnz_rel8(); + void i386_jo_rel8(); + void i386_jp_rel8(); + void i386_js_rel8(); + void i386_jz_rel8(); + void i386_jmp_rel8(); + void i386_lahf(); + void i386_lodsb(); + void i386_mov_rm8_r8(); + void i386_mov_r8_rm8(); + void i386_mov_rm8_i8(); + void i386_mov_r32_cr(); + void i386_mov_r32_dr(); + void i386_mov_cr_r32(); + void i386_mov_dr_r32(); + void i386_mov_al_m8(); + void i386_mov_m8_al(); + void i386_mov_rm16_sreg(); + void i386_mov_sreg_rm16(); + void i386_mov_al_i8(); + void i386_mov_cl_i8(); + void i386_mov_dl_i8(); + void i386_mov_bl_i8(); + void i386_mov_ah_i8(); + void i386_mov_ch_i8(); + void i386_mov_dh_i8(); + void i386_mov_bh_i8(); + void i386_movsb(); + void i386_or_rm8_r8(); + void i386_or_r8_rm8(); + void i386_or_al_i8(); + void i386_out_al_i8(); + void i386_out_al_dx(); + void i386_arpl(); + void i386_push_i8(); + void i386_ins_generic(int size); + void i386_insb(); + void i386_insw(); + void i386_insd(); + void i386_outs_generic(int size); + void i386_outsb(); + void i386_outsw(); + void i386_outsd(); + void i386_repeat(int invert_flag); + void i386_rep(); + void i386_repne(); + void i386_sahf(); + void i386_sbb_rm8_r8(); + void i386_sbb_r8_rm8(); + void i386_sbb_al_i8(); + void i386_scasb(); + void i386_setalc(); + void i386_seta_rm8(); + void i386_setbe_rm8(); + void i386_setc_rm8(); + void i386_setg_rm8(); + void i386_setge_rm8(); + void i386_setl_rm8(); + void i386_setle_rm8(); + void i386_setnc_rm8(); + void i386_setno_rm8(); + void i386_setnp_rm8(); + void i386_setns_rm8(); + void i386_setnz_rm8(); + void i386_seto_rm8(); + void i386_setp_rm8(); + void i386_sets_rm8(); + void i386_setz_rm8(); + void i386_stc(); + void i386_std(); + void i386_sti(); + void i386_stosb(); + void i386_sub_rm8_r8(); + void i386_sub_r8_rm8(); + void i386_sub_al_i8(); + void i386_test_al_i8(); + void i386_test_rm8_r8(); + void i386_xchg_r8_rm8(); + void i386_xor_rm8_r8(); + void i386_xor_r8_rm8(); + void i386_xor_al_i8(); + void i386_group80_8(); + void i386_groupC0_8(); + void i386_groupD0_8(); + void i386_groupD2_8(); + void i386_groupF6_8(); + void i386_groupFE_8(); + void i386_segment_CS(); + void i386_segment_DS(); + void i386_segment_ES(); + void i386_segment_FS(); + void i386_segment_GS(); + void i386_segment_SS(); + void i386_operand_size(); + void i386_address_size(); + void i386_nop(); + void i386_int3(); + void i386_int(); + void i386_into(); + void i386_escape(); + void i386_hlt(); + void i386_decimal_adjust(int direction); + void i386_daa(); + void i386_das(); + void i386_aaa(); + void i386_aas(); + void i386_aad(); + void i386_aam(); + void i386_clts(); + void i386_wait(); + void i386_lock(); + void i386_mov_r32_tr(); + void i386_mov_tr_r32(); + void i386_loadall(); + void i386_invalid(); + void i386_xlat(); + UINT16 i386_shift_rotate16(UINT8 modrm, UINT32 value, UINT8 shift); + void i386_adc_rm16_r16(); + void i386_adc_r16_rm16(); + void i386_adc_ax_i16(); + void i386_add_rm16_r16(); + void i386_add_r16_rm16(); + void i386_add_ax_i16(); + void i386_and_rm16_r16(); + void i386_and_r16_rm16(); + void i386_and_ax_i16(); + void i386_bsf_r16_rm16(); + void i386_bsr_r16_rm16(); + void i386_bt_rm16_r16(); + void i386_btc_rm16_r16(); + void i386_btr_rm16_r16(); + void i386_bts_rm16_r16(); + void i386_call_abs16(); + void i386_call_rel16(); + void i386_cbw(); + void i386_cmp_rm16_r16(); + void i386_cmp_r16_rm16(); + void i386_cmp_ax_i16(); + void i386_cmpsw(); + void i386_cwd(); + void i386_dec_ax(); + void i386_dec_cx(); + void i386_dec_dx(); + void i386_dec_bx(); + void i386_dec_sp(); + void i386_dec_bp(); + void i386_dec_si(); + void i386_dec_di(); + void i386_imul_r16_rm16(); + void i386_imul_r16_rm16_i16(); + void i386_imul_r16_rm16_i8(); + void i386_in_ax_i8(); + void i386_in_ax_dx(); + void i386_inc_ax(); + void i386_inc_cx(); + void i386_inc_dx(); + void i386_inc_bx(); + void i386_inc_sp(); + void i386_inc_bp(); + void i386_inc_si(); + void i386_inc_di(); + void i386_iret16(); + void i386_ja_rel16(); + void i386_jbe_rel16(); + void i386_jc_rel16(); + void i386_jg_rel16(); + void i386_jge_rel16(); + void i386_jl_rel16(); + void i386_jle_rel16(); + void i386_jnc_rel16(); + void i386_jno_rel16(); + void i386_jnp_rel16(); + void i386_jns_rel16(); + void i386_jnz_rel16(); + void i386_jo_rel16(); + void i386_jp_rel16(); + void i386_js_rel16(); + void i386_jz_rel16(); + void i386_jcxz16(); + void i386_jmp_rel16(); + void i386_jmp_abs16(); + void i386_lea16(); + void i386_enter16(); + void i386_leave16(); + void i386_lodsw(); + void i386_loop16(); + void i386_loopne16(); + void i386_loopz16(); + void i386_mov_rm16_r16(); + void i386_mov_r16_rm16(); + void i386_mov_rm16_i16(); + void i386_mov_ax_m16(); + void i386_mov_m16_ax(); + void i386_mov_ax_i16(); + void i386_mov_cx_i16(); + void i386_mov_dx_i16(); + void i386_mov_bx_i16(); + void i386_mov_sp_i16(); + void i386_mov_bp_i16(); + void i386_mov_si_i16(); + void i386_mov_di_i16(); + void i386_movsw(); + void i386_movsx_r16_rm8(); + void i386_movzx_r16_rm8(); + void i386_or_rm16_r16(); + void i386_or_r16_rm16(); + void i386_or_ax_i16(); + void i386_out_ax_i8(); + void i386_out_ax_dx(); + void i386_pop_ax(); + void i386_pop_cx(); + void i386_pop_dx(); + void i386_pop_bx(); + void i386_pop_sp(); + void i386_pop_bp(); + void i386_pop_si(); + void i386_pop_di(); + bool i386_pop_seg16(int segment); + void i386_pop_ds16(); + void i386_pop_es16(); + void i386_pop_fs16(); + void i386_pop_gs16(); + void i386_pop_ss16(); + void i386_pop_rm16(); + void i386_popa(); + void i386_popf(); + void i386_push_ax(); + void i386_push_cx(); + void i386_push_dx(); + void i386_push_bx(); + void i386_push_sp(); + void i386_push_bp(); + void i386_push_si(); + void i386_push_di(); + void i386_push_cs16(); + void i386_push_ds16(); + void i386_push_es16(); + void i386_push_fs16(); + void i386_push_gs16(); + void i386_push_ss16(); + void i386_push_i16(); + void i386_pusha(); + void i386_pushf(); + void i386_ret_near16_i16(); + void i386_ret_near16(); + void i386_sbb_rm16_r16(); + void i386_sbb_r16_rm16(); + void i386_sbb_ax_i16(); + void i386_scasw(); + void i386_shld16_i8(); + void i386_shld16_cl(); + void i386_shrd16_i8(); + void i386_shrd16_cl(); + void i386_stosw(); + void i386_sub_rm16_r16(); + void i386_sub_r16_rm16(); + void i386_sub_ax_i16(); + void i386_test_ax_i16(); + void i386_test_rm16_r16(); + void i386_xchg_ax_cx(); + void i386_xchg_ax_dx(); + void i386_xchg_ax_bx(); + void i386_xchg_ax_sp(); + void i386_xchg_ax_bp(); + void i386_xchg_ax_si(); + void i386_xchg_ax_di(); + void i386_xchg_r16_rm16(); + void i386_xor_rm16_r16(); + void i386_xor_r16_rm16(); + void i386_xor_ax_i16(); + void i386_group81_16(); + void i386_group83_16(); + void i386_groupC1_16(); + void i386_groupD1_16(); + void i386_groupD3_16(); + void i386_groupF7_16(); + void i386_groupFF_16(); + void i386_group0F00_16(); + void i386_group0F01_16(); + void i386_group0FBA_16(); + void i386_lar_r16_rm16(); + void i386_lsl_r16_rm16(); + void i386_bound_r16_m16_m16(); + void i386_retf16(); + void i386_retf_i16(); + bool i386_load_far_pointer16(int s); + void i386_lds16(); + void i386_lss16(); + void i386_les16(); + void i386_lfs16(); + void i386_lgs16(); + UINT32 i386_shift_rotate32(UINT8 modrm, UINT32 value, UINT8 shift); + void i386_adc_rm32_r32(); + void i386_adc_r32_rm32(); + void i386_adc_eax_i32(); + void i386_add_rm32_r32(); + void i386_add_r32_rm32(); + void i386_add_eax_i32(); + void i386_and_rm32_r32(); + void i386_and_r32_rm32(); + void i386_and_eax_i32(); + void i386_bsf_r32_rm32(); + void i386_bsr_r32_rm32(); + void i386_bt_rm32_r32(); + void i386_btc_rm32_r32(); + void i386_btr_rm32_r32(); + void i386_bts_rm32_r32(); + void i386_call_abs32(); + void i386_call_rel32(); + void i386_cdq(); + void i386_cmp_rm32_r32(); + void i386_cmp_r32_rm32(); + void i386_cmp_eax_i32(); + void i386_cmpsd(); + void i386_cwde(); + void i386_dec_eax(); + void i386_dec_ecx(); + void i386_dec_edx(); + void i386_dec_ebx(); + void i386_dec_esp(); + void i386_dec_ebp(); + void i386_dec_esi(); + void i386_dec_edi(); + void i386_imul_r32_rm32(); + void i386_imul_r32_rm32_i32(); + void i386_imul_r32_rm32_i8(); + void i386_in_eax_i8(); + void i386_in_eax_dx(); + void i386_inc_eax(); + void i386_inc_ecx(); + void i386_inc_edx(); + void i386_inc_ebx(); + void i386_inc_esp(); + void i386_inc_ebp(); + void i386_inc_esi(); + void i386_inc_edi(); + void i386_iret32(); + void i386_ja_rel32(); + void i386_jbe_rel32(); + void i386_jc_rel32(); + void i386_jg_rel32(); + void i386_jge_rel32(); + void i386_jl_rel32(); + void i386_jle_rel32(); + void i386_jnc_rel32(); + void i386_jno_rel32(); + void i386_jnp_rel32(); + void i386_jns_rel32(); + void i386_jnz_rel32(); + void i386_jo_rel32(); + void i386_jp_rel32(); + void i386_js_rel32(); + void i386_jz_rel32(); + void i386_jcxz32(); + void i386_jmp_rel32(); + void i386_jmp_abs32(); + void i386_lea32(); + void i386_enter32(); + void i386_leave32(); + void i386_lodsd(); + void i386_loop32(); + void i386_loopne32(); + void i386_loopz32(); + void i386_mov_rm32_r32(); + void i386_mov_r32_rm32(); + void i386_mov_rm32_i32(); + void i386_mov_eax_m32(); + void i386_mov_m32_eax(); + void i386_mov_eax_i32(); + void i386_mov_ecx_i32(); + void i386_mov_edx_i32(); + void i386_mov_ebx_i32(); + void i386_mov_esp_i32(); + void i386_mov_ebp_i32(); + void i386_mov_esi_i32(); + void i386_mov_edi_i32(); + void i386_movsd(); + void i386_movsx_r32_rm8(); + void i386_movsx_r32_rm16(); + void i386_movzx_r32_rm8(); + void i386_movzx_r32_rm16(); + void i386_or_rm32_r32(); + void i386_or_r32_rm32(); + void i386_or_eax_i32(); + void i386_out_eax_i8(); + void i386_out_eax_dx(); + void i386_pop_eax(); + void i386_pop_ecx(); + void i386_pop_edx(); + void i386_pop_ebx(); + void i386_pop_esp(); + void i386_pop_ebp(); + void i386_pop_esi(); + void i386_pop_edi(); + bool i386_pop_seg32(int segment); + void i386_pop_ds32(); + void i386_pop_es32(); + void i386_pop_fs32(); + void i386_pop_gs32(); + void i386_pop_ss32(); + void i386_pop_rm32(); + void i386_popad(); + void i386_popfd(); + void i386_push_eax(); + void i386_push_ecx(); + void i386_push_edx(); + void i386_push_ebx(); + void i386_push_esp(); + void i386_push_ebp(); + void i386_push_esi(); + void i386_push_edi(); + void i386_push_cs32(); + void i386_push_ds32(); + void i386_push_es32(); + void i386_push_fs32(); + void i386_push_gs32(); + void i386_push_ss32(); + void i386_push_i32(); + void i386_pushad(); + void i386_pushfd(); + void i386_ret_near32_i16(); + void i386_ret_near32(); + void i386_sbb_rm32_r32(); + void i386_sbb_r32_rm32(); + void i386_sbb_eax_i32(); + void i386_scasd(); + void i386_shld32_i8(); + void i386_shld32_cl(); + void i386_shrd32_i8(); + void i386_shrd32_cl(); + void i386_stosd(); + void i386_sub_rm32_r32(); + void i386_sub_r32_rm32(); + void i386_sub_eax_i32(); + void i386_test_eax_i32(); + void i386_test_rm32_r32(); + void i386_xchg_eax_ecx(); + void i386_xchg_eax_edx(); + void i386_xchg_eax_ebx(); + void i386_xchg_eax_esp(); + void i386_xchg_eax_ebp(); + void i386_xchg_eax_esi(); + void i386_xchg_eax_edi(); + void i386_xchg_r32_rm32(); + void i386_xor_rm32_r32(); + void i386_xor_r32_rm32(); + void i386_xor_eax_i32(); + void i386_group81_32(); + void i386_group83_32(); + void i386_groupC1_32(); + void i386_groupD1_32(); + void i386_groupD3_32(); + void i386_groupF7_32(); + void i386_groupFF_32(); + void i386_group0F00_32(); + void i386_group0F01_32(); + void i386_group0FBA_32(); + void i386_lar_r32_rm32(); + void i386_lsl_r32_rm32(); + void i386_bound_r32_m32_m32(); + void i386_retf32(); + void i386_retf_i32(); + void i386_load_far_pointer32(int s); + void i386_lds32(); + void i386_lss32(); + void i386_les32(); + void i386_lfs32(); + void i386_lgs32(); + void i486_cpuid(); + void i486_invd(); + void i486_wbinvd(); + void i486_cmpxchg_rm8_r8(); + void i486_cmpxchg_rm16_r16(); + void i486_cmpxchg_rm32_r32(); + void i486_xadd_rm8_r8(); + void i486_xadd_rm16_r16(); + void i486_xadd_rm32_r32(); + void i486_group0F01_16(); + void i486_group0F01_32(); + void i486_bswap_eax(); + void i486_bswap_ecx(); + void i486_bswap_edx(); + void i486_bswap_ebx(); + void i486_bswap_esp(); + void i486_bswap_ebp(); + void i486_bswap_esi(); + void i486_bswap_edi(); + void i486_mov_cr_r32(); + inline void MMXPROLOG(); + inline void READMMX(UINT32 ea,MMX_REG &r); + inline void WRITEMMX(UINT32 ea,MMX_REG &r); + inline void READXMM(UINT32 ea,XMM_REG &r); + inline void WRITEXMM(UINT32 ea,XMM_REG &r); + inline void READXMM_LO64(UINT32 ea,XMM_REG &r); + inline void WRITEXMM_LO64(UINT32 ea,XMM_REG &r); + inline void READXMM_HI64(UINT32 ea,XMM_REG &r); + inline void WRITEXMM_HI64(UINT32 ea,XMM_REG &r); + void pentium_rdmsr(); + void pentium_wrmsr(); + void pentium_rdtsc(); + void pentium_ud2(); + void pentium_rsm(); + void pentium_prefetch_m8(); + void pentium_cmovo_r16_rm16(); + void pentium_cmovo_r32_rm32(); + void pentium_cmovno_r16_rm16(); + void pentium_cmovno_r32_rm32(); + void pentium_cmovb_r16_rm16(); + void pentium_cmovb_r32_rm32(); + void pentium_cmovae_r16_rm16(); + void pentium_cmovae_r32_rm32(); + void pentium_cmove_r16_rm16(); + void pentium_cmove_r32_rm32(); + void pentium_cmovne_r16_rm16(); + void pentium_cmovne_r32_rm32(); + void pentium_cmovbe_r16_rm16(); + void pentium_cmovbe_r32_rm32(); + void pentium_cmova_r16_rm16(); + void pentium_cmova_r32_rm32(); + void pentium_cmovs_r16_rm16(); + void pentium_cmovs_r32_rm32(); + void pentium_cmovns_r16_rm16(); + void pentium_cmovns_r32_rm32(); + void pentium_cmovp_r16_rm16(); + void pentium_cmovp_r32_rm32(); + void pentium_cmovnp_r16_rm16(); + void pentium_cmovnp_r32_rm32(); + void pentium_cmovl_r16_rm16(); + void pentium_cmovl_r32_rm32(); + void pentium_cmovge_r16_rm16(); + void pentium_cmovge_r32_rm32(); + void pentium_cmovle_r16_rm16(); + void pentium_cmovle_r32_rm32(); + void pentium_cmovg_r16_rm16(); + void pentium_cmovg_r32_rm32(); + void pentium_movnti_m16_r16(); + void pentium_movnti_m32_r32(); + void i386_cyrix_special(); + void i386_cyrix_unknown(); + void pentium_cmpxchg8b_m64(); + void pentium_movntq_m64_r64(); + void pentium_maskmovq_r64_r64(); + void pentium_popcnt_r16_rm16(); + void pentium_popcnt_r32_rm32(); + void pentium_tzcnt_r16_rm16(); + void pentium_tzcnt_r32_rm32(); + void mmx_group_0f71(); + void mmx_group_0f72(); + void mmx_group_0f73(); + void mmx_psrlw_r64_rm64(); + void mmx_psrld_r64_rm64(); + void mmx_psrlq_r64_rm64(); + void mmx_paddq_r64_rm64(); + void mmx_pmullw_r64_rm64(); + void mmx_psubusb_r64_rm64(); + void mmx_psubusw_r64_rm64(); + void mmx_pand_r64_rm64(); + void mmx_paddusb_r64_rm64(); + void mmx_paddusw_r64_rm64(); + void mmx_pandn_r64_rm64(); + void mmx_psraw_r64_rm64(); + void mmx_psrad_r64_rm64(); + void mmx_pmulhw_r64_rm64(); + void mmx_psubsb_r64_rm64(); + void mmx_psubsw_r64_rm64(); + void mmx_por_r64_rm64(); + void mmx_paddsb_r64_rm64(); + void mmx_paddsw_r64_rm64(); + void mmx_pxor_r64_rm64(); + void mmx_psllw_r64_rm64(); + void mmx_pslld_r64_rm64(); + void mmx_psllq_r64_rm64(); + void mmx_pmaddwd_r64_rm64(); + void mmx_psubb_r64_rm64(); + void mmx_psubw_r64_rm64(); + void mmx_psubd_r64_rm64(); + void mmx_paddb_r64_rm64(); + void mmx_paddw_r64_rm64(); + void mmx_paddd_r64_rm64(); + void mmx_emms(); + void i386_cyrix_svdc(); + void i386_cyrix_rsdc(); + void i386_cyrix_svldt(); + void i386_cyrix_rsldt(); + void i386_cyrix_svts(); + void i386_cyrix_rsts(); + void mmx_movd_r64_rm32(); + void mmx_movq_r64_rm64(); + void mmx_movd_rm32_r64(); + void mmx_movq_rm64_r64(); + void mmx_pcmpeqb_r64_rm64(); + void mmx_pcmpeqw_r64_rm64(); + void mmx_pcmpeqd_r64_rm64(); + void mmx_pshufw_r64_rm64_i8(); + void mmx_punpcklbw_r64_r64m32(); + void mmx_punpcklwd_r64_r64m32(); + void mmx_punpckldq_r64_r64m32(); + void mmx_packsswb_r64_rm64(); + void mmx_pcmpgtb_r64_rm64(); + void mmx_pcmpgtw_r64_rm64(); + void mmx_pcmpgtd_r64_rm64(); + void mmx_packuswb_r64_rm64(); + void mmx_punpckhbw_r64_rm64(); + void mmx_punpckhwd_r64_rm64(); + void mmx_punpckhdq_r64_rm64(); + void mmx_packssdw_r64_rm64(); + void sse_group_0fae(); + void sse_group_660f71(); + void sse_group_660f72(); + void sse_group_660f73(); + void sse_cvttps2dq_r128_rm128(); + void sse_cvtss2sd_r128_r128m32(); + void sse_cvttss2si_r32_r128m32(); + void sse_cvtss2si_r32_r128m32(); + void sse_cvtsi2ss_r128_rm32(); + void sse_cvtpi2ps_r128_rm64(); + void sse_cvttps2pi_r64_r128m64(); + void sse_cvtps2pi_r64_r128m64(); + void sse_cvtps2pd_r128_r128m64(); + void sse_cvtdq2ps_r128_rm128(); + void sse_cvtdq2pd_r128_r128m64(); + void sse_movss_r128_rm128(); + void sse_movss_rm128_r128(); + void sse_movsldup_r128_rm128(); + void sse_movshdup_r128_rm128(); + void sse_movaps_r128_rm128(); + void sse_movaps_rm128_r128(); + void sse_movups_r128_rm128(); + void sse_movups_rm128_r128(); + void sse_movlps_r128_m64(); + void sse_movlps_m64_r128(); + void sse_movhps_r128_m64(); + void sse_movhps_m64_r128(); + void sse_movntps_m128_r128(); + void sse_movmskps_r16_r128(); + void sse_movmskps_r32_r128(); + void sse_movq2dq_r128_r64(); + void sse_movdqu_r128_rm128(); + void sse_movdqu_rm128_r128(); + void sse_movd_m128_rm32(); + void sse_movdqa_m128_rm128(); + void sse_movq_r128_r128m64(); + void sse_movd_rm32_r128(); + void sse_movdqa_rm128_r128(); + void sse_pmovmskb_r16_r64(); + void sse_pmovmskb_r32_r64(); + void sse_xorps(); + void sse_addps(); + void sse_sqrtps_r128_rm128(); + void sse_rsqrtps_r128_rm128(); + void sse_rcpps_r128_rm128(); + void sse_andps_r128_rm128(); + void sse_andnps_r128_rm128(); + void sse_orps_r128_rm128(); + void sse_mulps(); + void sse_subps(); + void sse_minps(); + void sse_divps(); + void sse_maxps(); + void sse_maxss_r128_r128m32(); + void sse_addss(); + void sse_subss(); + void sse_mulss(); + void sse_divss(); + void sse_rcpss_r128_r128m32(); + void sse_sqrtss_r128_r128m32(); + void sse_rsqrtss_r128_r128m32(); + void sse_minss_r128_r128m32(); + void sse_comiss_r128_r128m32(); + void sse_ucomiss_r128_r128m32(); + void sse_shufps(); + void sse_punpcklbw_r128_rm128(); + void sse_punpcklwd_r128_rm128(); + void sse_punpckldq_r128_rm128(); + void sse_punpcklqdq_r128_rm128(); + void sse_unpcklps_r128_rm128(); + void sse_unpckhps_r128_rm128(); + void sse_cmpps_r128_rm128_i8(); + void sse_cmpss_r128_r128m32_i8(); + void sse_pinsrw_r64_r16m16_i8(); + void sse_pinsrw_r64_r32m16_i8(); + void sse_pinsrw_r128_r32m16_i8(); + void sse_pextrw_r16_r64_i8(); + void sse_pextrw_r32_r64_i8(); + void sse_pextrw_reg_r128_i8(); + void sse_pminub_r64_rm64(); + void sse_pmaxub_r64_rm64(); + void sse_pavgb_r64_rm64(); + void sse_pavgw_r64_rm64(); + void sse_pmulhuw_r64_rm64(); + void sse_pminsw_r64_rm64(); + void sse_pmaxsw_r64_rm64(); + void sse_pmuludq_r64_rm64(); + void sse_psadbw_r64_rm64(); + void sse_psubq_r64_rm64(); + void sse_pshufhw_r128_rm128_i8(); + void sse_packsswb_r128_rm128(); + void sse_packssdw_r128_rm128(); + void sse_pcmpgtb_r128_rm128(); + void sse_pcmpgtw_r128_rm128(); + void sse_pcmpgtd_r128_rm128(); + void sse_packuswb_r128_rm128(); + void sse_punpckhbw_r128_rm128(); + void sse_punpckhwd_r128_rm128(); + void sse_unpckhdq_r128_rm128(); + void sse_punpckhqdq_r128_rm128(); + void sse_pcmpeqb_r128_rm128(); + void sse_pcmpeqw_r128_rm128(); + void sse_pcmpeqd_r128_rm128(); + void sse_paddq_r128_rm128(); + void sse_pmullw_r128_rm128(); + void sse_pmuludq_r128_rm128(); + void sse_psubq_r128_rm128(); + void sse_paddb_r128_rm128(); + void sse_paddw_r128_rm128(); + void sse_paddd_r128_rm128(); + void sse_psubusb_r128_rm128(); + void sse_psubusw_r128_rm128(); + void sse_pminub_r128_rm128(); + void sse_pand_r128_rm128(); + void sse_pandn_r128_rm128(); + void sse_paddusb_r128_rm128(); + void sse_paddusw_r128_rm128(); + void sse_pmaxub_r128_rm128(); + void sse_pmulhuw_r128_rm128(); + void sse_pmulhw_r128_rm128(); + void sse_psubsw_r128_rm128(); + void sse_psubsb_r128_rm128(); + void sse_pminsw_r128_rm128(); + void sse_pmaxsw_r128_rm128(); + void sse_paddsb_r128_rm128(); + void sse_paddsw_r128_rm128(); + void sse_por_r128_rm128(); + void sse_pxor_r128_rm128(); + void sse_pmaddwd_r128_rm128(); + void sse_psubb_r128_rm128(); + void sse_psubw_r128_rm128(); + void sse_psubd_r128_rm128(); + void sse_psadbw_r128_rm128(); + void sse_pavgb_r128_rm128(); + void sse_pavgw_r128_rm128(); + void sse_pmovmskb_r32_r128(); + void sse_maskmovdqu_r128_r128(); + void sse_andpd_r128_rm128(); + void sse_andnpd_r128_rm128(); + void sse_orpd_r128_rm128(); + void sse_xorpd_r128_rm128(); + void sse_unpcklpd_r128_rm128(); + void sse_unpckhpd_r128_rm128(); + void sse_shufpd_r128_rm128_i8(); + void sse_pshufd_r128_rm128_i8(); + void sse_pshuflw_r128_rm128_i8(); + void sse_movmskpd_r32_r128(); + void sse_ucomisd_r128_r128m64(); + void sse_comisd_r128_r128m64(); + void sse_psrlw_r128_rm128(); + void sse_psrld_r128_rm128(); + void sse_psrlq_r128_rm128(); + void sse_psllw_r128_rm128(); + void sse_pslld_r128_rm128(); + void sse_psllq_r128_rm128(); + void sse_psraw_r128_rm128(); + void sse_psrad_r128_rm128(); + void sse_movntdq_m128_r128(); + void sse_cvttpd2dq_r128_rm128(); + void sse_movq_r128m64_r128(); + void sse_addsubpd_r128_rm128(); + void sse_cmppd_r128_rm128_i8(); + void sse_haddpd_r128_rm128(); + void sse_hsubpd_r128_rm128(); + void sse_sqrtpd_r128_rm128(); + void sse_cvtpi2pd_r128_rm64(); + void sse_cvttpd2pi_r64_rm128(); + void sse_cvtpd2pi_r64_rm128(); + void sse_cvtpd2ps_r128_rm128(); + void sse_cvtps2dq_r128_rm128(); + void sse_addpd_r128_rm128(); + void sse_mulpd_r128_rm128(); + void sse_subpd_r128_rm128(); + void sse_minpd_r128_rm128(); + void sse_divpd_r128_rm128(); + void sse_maxpd_r128_rm128(); + void sse_movntpd_m128_r128(); + void sse_movapd_r128_rm128(); + void sse_movapd_rm128_r128(); + void sse_movhpd_r128_m64(); + void sse_movhpd_m64_r128(); + void sse_movupd_r128_rm128(); + void sse_movupd_rm128_r128(); + void sse_movlpd_r128_m64(); + void sse_movlpd_m64_r128(); + void sse_movsd_r128_r128m64(); + void sse_movsd_r128m64_r128(); + void sse_movddup_r128_r128m64(); + void sse_cvtsi2sd_r128_rm32(); + void sse_cvttsd2si_r32_r128m64(); + void sse_cvtsd2si_r32_r128m64(); + void sse_sqrtsd_r128_r128m64(); + void sse_addsd_r128_r128m64(); + void sse_mulsd_r128_r128m64(); + void sse_cvtsd2ss_r128_r128m64(); + void sse_subsd_r128_r128m64(); + void sse_minsd_r128_r128m64(); + void sse_divsd_r128_r128m64(); + void sse_maxsd_r128_r128m64(); + void sse_haddps_r128_rm128(); + void sse_hsubps_r128_rm128(); + void sse_cmpsd_r128_r128m64_i8(); + void sse_addsubps_r128_rm128(); + void sse_movdq2q_r64_r128(); + void sse_cvtpd2dq_r128_rm128(); + void sse_lddqu_r128_m128(); + inline void sse_predicate_compare_single(UINT8 imm8, XMM_REG d, XMM_REG s); + inline void sse_predicate_compare_double(UINT8 imm8, XMM_REG d, XMM_REG s); + inline void sse_predicate_compare_single_scalar(UINT8 imm8, XMM_REG d, XMM_REG s); + inline void sse_predicate_compare_double_scalar(UINT8 imm8, XMM_REG d, XMM_REG s); + inline floatx80 READ80(UINT32 ea); + inline void WRITE80(UINT32 ea, floatx80 t); + inline void x87_set_stack_top(int top); + inline void x87_set_tag(int reg, int tag); + void x87_write_stack(int i, floatx80 value, int update_tag); + inline void x87_set_stack_underflow(); + inline void x87_set_stack_overflow(); + int x87_inc_stack(); + int x87_dec_stack(); + int x87_check_exceptions(); + inline void x87_write_cw(UINT16 cw); + void x87_reset(); + floatx80 x87_add(floatx80 a, floatx80 b); + floatx80 x87_sub(floatx80 a, floatx80 b); + floatx80 x87_mul(floatx80 a, floatx80 b); + floatx80 x87_div(floatx80 a, floatx80 b); + void x87_fadd_m32real(UINT8 modrm); + void x87_fadd_m64real(UINT8 modrm); + void x87_fadd_st_sti(UINT8 modrm); + void x87_fadd_sti_st(UINT8 modrm); + void x87_faddp(UINT8 modrm); + void x87_fiadd_m32int(UINT8 modrm); + void x87_fiadd_m16int(UINT8 modrm); + void x87_fsub_m32real(UINT8 modrm); + void x87_fsub_m64real(UINT8 modrm); + void x87_fsub_st_sti(UINT8 modrm); + void x87_fsub_sti_st(UINT8 modrm); + void x87_fsubp(UINT8 modrm); + void x87_fisub_m32int(UINT8 modrm); + void x87_fisub_m16int(UINT8 modrm); + void x87_fsubr_m32real(UINT8 modrm); + void x87_fsubr_m64real(UINT8 modrm); + void x87_fsubr_st_sti(UINT8 modrm); + void x87_fsubr_sti_st(UINT8 modrm); + void x87_fsubrp(UINT8 modrm); + void x87_fisubr_m32int(UINT8 modrm); + void x87_fisubr_m16int(UINT8 modrm); + void x87_fdiv_m32real(UINT8 modrm); + void x87_fdiv_m64real(UINT8 modrm); + void x87_fdiv_st_sti(UINT8 modrm); + void x87_fdiv_sti_st(UINT8 modrm); + void x87_fdivp(UINT8 modrm); + void x87_fidiv_m32int(UINT8 modrm); + void x87_fidiv_m16int(UINT8 modrm); + void x87_fdivr_m32real(UINT8 modrm); + void x87_fdivr_m64real(UINT8 modrm); + void x87_fdivr_st_sti(UINT8 modrm); + void x87_fdivr_sti_st(UINT8 modrm); + void x87_fdivrp(UINT8 modrm); + void x87_fidivr_m32int(UINT8 modrm); + void x87_fidivr_m16int(UINT8 modrm); + void x87_fmul_m32real(UINT8 modrm); + void x87_fmul_m64real(UINT8 modrm); + void x87_fmul_st_sti(UINT8 modrm); + void x87_fmul_sti_st(UINT8 modrm); + void x87_fmulp(UINT8 modrm); + void x87_fimul_m32int(UINT8 modrm); + void x87_fimul_m16int(UINT8 modrm); + void x87_fprem(UINT8 modrm); + void x87_fprem1(UINT8 modrm); + void x87_fsqrt(UINT8 modrm); + void x87_f2xm1(UINT8 modrm); + void x87_fyl2x(UINT8 modrm); + void x87_fyl2xp1(UINT8 modrm); + void x87_fptan(UINT8 modrm); + void x87_fpatan(UINT8 modrm); + void x87_fsin(UINT8 modrm); + void x87_fcos(UINT8 modrm); + void x87_fsincos(UINT8 modrm); + void x87_fld_m32real(UINT8 modrm); + void x87_fld_m64real(UINT8 modrm); + void x87_fld_m80real(UINT8 modrm); + void x87_fld_sti(UINT8 modrm); + void x87_fild_m16int(UINT8 modrm); + void x87_fild_m32int(UINT8 modrm); + void x87_fild_m64int(UINT8 modrm); + void x87_fbld(UINT8 modrm); + void x87_fst_m32real(UINT8 modrm); + void x87_fst_m64real(UINT8 modrm); + void x87_fst_sti(UINT8 modrm); + void x87_fstp_m32real(UINT8 modrm); + void x87_fstp_m64real(UINT8 modrm); + void x87_fstp_m80real(UINT8 modrm); + void x87_fstp_sti(UINT8 modrm); + void x87_fist_m16int(UINT8 modrm); + void x87_fist_m32int(UINT8 modrm); + void x87_fistp_m16int(UINT8 modrm); + void x87_fistp_m32int(UINT8 modrm); + void x87_fistp_m64int(UINT8 modrm); + void x87_fbstp(UINT8 modrm); + void x87_fld1(UINT8 modrm); + void x87_fldl2t(UINT8 modrm); + void x87_fldl2e(UINT8 modrm); + void x87_fldpi(UINT8 modrm); + void x87_fldlg2(UINT8 modrm); + void x87_fldln2(UINT8 modrm); + void x87_fldz(UINT8 modrm); + void x87_fnop(UINT8 modrm); + void x87_fchs(UINT8 modrm); + void x87_fabs(UINT8 modrm); + void x87_fscale(UINT8 modrm); + void x87_frndint(UINT8 modrm); + void x87_fxtract(UINT8 modrm); + void x87_ftst(UINT8 modrm); + void x87_fxam(UINT8 modrm); + void x87_fcmovb_sti(UINT8 modrm); + void x87_fcmove_sti(UINT8 modrm); + void x87_fcmovbe_sti(UINT8 modrm); + void x87_fcmovu_sti(UINT8 modrm); + void x87_fcmovnb_sti(UINT8 modrm); + void x87_fcmovne_sti(UINT8 modrm); + void x87_fcmovnbe_sti(UINT8 modrm); + void x87_fcmovnu_sti(UINT8 modrm); + void x87_ficom_m16int(UINT8 modrm); + void x87_ficom_m32int(UINT8 modrm); + void x87_ficomp_m16int(UINT8 modrm); + void x87_ficomp_m32int(UINT8 modrm); + void x87_fcom_m32real(UINT8 modrm); + void x87_fcom_m64real(UINT8 modrm); + void x87_fcom_sti(UINT8 modrm); + void x87_fcomp_m32real(UINT8 modrm); + void x87_fcomp_m64real(UINT8 modrm); + void x87_fcomp_sti(UINT8 modrm); + void x87_fcomi_sti(UINT8 modrm); + void x87_fcomip_sti(UINT8 modrm); + void x87_fucomi_sti(UINT8 modrm); + void x87_fucomip_sti(UINT8 modrm); + void x87_fcompp(UINT8 modrm); + void x87_fucom_sti(UINT8 modrm); + void x87_fucomp_sti(UINT8 modrm); + void x87_fucompp(UINT8 modrm); + void x87_fdecstp(UINT8 modrm); + void x87_fincstp(UINT8 modrm); + void x87_fclex(UINT8 modrm); + void x87_ffree(UINT8 modrm); + void x87_finit(UINT8 modrm); + void x87_fldcw(UINT8 modrm); + void x87_fstcw(UINT8 modrm); + void x87_fldenv(UINT8 modrm); + void x87_fstenv(UINT8 modrm); + void x87_fsave(UINT8 modrm); + void x87_frstor(UINT8 modrm); + void x87_fxch(UINT8 modrm); + void x87_fxch_sti(UINT8 modrm); + void x87_fstsw_ax(UINT8 modrm); + void x87_fstsw_m2byte(UINT8 modrm); + void x87_invalid(UINT8 modrm); + void i386_x87_group_d8(); + void i386_x87_group_d9(); + void i386_x87_group_da(); + void i386_x87_group_db(); + void i386_x87_group_dc(); + void i386_x87_group_dd(); + void i386_x87_group_de(); + void i386_x87_group_df(); + void build_x87_opcode_table_d8(); + void build_x87_opcode_table_d9(); + void build_x87_opcode_table_da(); + void build_x87_opcode_table_db(); + void build_x87_opcode_table_dc(); + void build_x87_opcode_table_dd(); + void build_x87_opcode_table_de(); + void build_x87_opcode_table_df(); + void build_x87_opcode_table(); + void i386_postload(); + void i386_common_init(int tlbsize); + void build_opcode_table(UINT32 features); + void pentium_smi(); + void zero_state(); + void i386_set_a20_line(int state); + +}; + + +class i386SX_device : public i386_device +{ +public: + // construction/destruction + i386SX_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +class i486_device : public i386_device +{ +public: + // construction/destruction + i486_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual void device_start(); + virtual void device_reset(); +}; + + +class pentium_device : public i386_device +{ +public: + // construction/destruction + pentium_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + pentium_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + +protected: + virtual void execute_set_input(int inputnum, int state); + virtual void device_start(); + virtual void device_reset(); +}; + + +class mediagx_device : public i386_device +{ +public: + // construction/destruction + mediagx_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual void device_start(); + virtual void device_reset(); +}; + + +class pentium_pro_device : public pentium_device +{ +public: + // construction/destruction + pentium_pro_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual void device_start(); + virtual void device_reset(); +}; + + +class pentium_mmx_device : public pentium_device +{ +public: + // construction/destruction + pentium_mmx_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual void device_start(); + virtual void device_reset(); +}; + + +class pentium2_device : public pentium_device +{ +public: + // construction/destruction + pentium2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual void device_start(); + virtual void device_reset(); +}; + + +class pentium3_device : public pentium_device +{ +public: + // construction/destruction + pentium3_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual void device_start(); + virtual void device_reset(); +}; + + +class pentium4_device : public pentium_device +{ +public: + // construction/destruction + pentium4_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual void device_start(); + virtual void device_reset(); +}; + + +extern const device_type I386; +extern const device_type I386SX; +extern const device_type I486; +extern const device_type PENTIUM; +extern const device_type MEDIAGX; +extern const device_type PENTIUM_PRO; +extern const device_type PENTIUM_MMX; +extern const device_type PENTIUM2; +extern const device_type PENTIUM3; +extern const device_type PENTIUM4; + + +#endif /* __I386INTF_H__ */ diff --git a/src/devices/cpu/i386/i386dasm.c b/src/devices/cpu/i386/i386dasm.c new file mode 100644 index 00000000000..18e5557b4b5 --- /dev/null +++ b/src/devices/cpu/i386/i386dasm.c @@ -0,0 +1,3126 @@ +// license:BSD-3-Clause +// copyright-holders:Ville Linde, Peter Ferrie +/* + i386 Disassembler + + Written by Ville Linde +*/ + +#include "emu.h" + +enum +{ + PARAM_REG = 1, /* 16 or 32-bit register */ + PARAM_REG8, /* 8-bit register */ + PARAM_REG16, /* 16-bit register */ + PARAM_REG32, /* 32-bit register */ + PARAM_REG3264, /* 32-bit or 64-bit register */ + PARAM_REG2_32, /* 32-bit register */ + PARAM_MMX, /* MMX register */ + PARAM_MMX2, /* MMX register in modrm */ + PARAM_XMM, /* XMM register */ + PARAM_RM, /* 16 or 32-bit memory or register */ + PARAM_RM8, /* 8-bit memory or register */ + PARAM_RM16, /* 16-bit memory or register */ + PARAM_RM32, /* 32-bit memory or register */ + PARAM_RMPTR, /* 16 or 32-bit memory or register */ + PARAM_RMPTR8, /* 8-bit memory or register */ + PARAM_RMPTR16, /* 16-bit memory or register */ + PARAM_RMPTR32, /* 32-bit memory or register */ + PARAM_RMXMM, /* 32 or 64-bit memory or register */ + PARAM_REGORXMM, /* 32 or 64-bit register or XMM register */ + PARAM_M64, /* 64-bit memory */ + PARAM_M64PTR, /* 64-bit memory */ + PARAM_MMXM, /* 64-bit memory or MMX register */ + PARAM_XMMM, /* 128-bit memory or XMM register */ + PARAM_I4, /* 4-bit signed immediate */ + PARAM_I8, /* 8-bit signed immediate */ + PARAM_I16, /* 16-bit signed immediate */ + PARAM_UI8, /* 8-bit unsigned immediate */ + PARAM_UI16, /* 16-bit unsigned immediate */ + PARAM_IMM, /* 16 or 32-bit immediate */ + PARAM_IMM64, /* 16, 32 or 64-bit immediate */ + PARAM_ADDR, /* 16:16 or 16:32 address */ + PARAM_REL, /* 16 or 32-bit PC-relative displacement */ + PARAM_REL8, /* 8-bit PC-relative displacement */ + PARAM_MEM_OFFS, /* 16 or 32-bit mem offset */ + PARAM_PREIMP, /* prefix with implicit register */ + PARAM_SREG, /* segment register */ + PARAM_CREG, /* control register */ + PARAM_DREG, /* debug register */ + PARAM_TREG, /* test register */ + PARAM_1, /* used by shift/rotate instructions */ + PARAM_AL, + PARAM_CL, + PARAM_DL, + PARAM_BL, + PARAM_AH, + PARAM_CH, + PARAM_DH, + PARAM_BH, + PARAM_DX, + PARAM_EAX, /* EAX or AX */ + PARAM_ECX, /* ECX or CX */ + PARAM_EDX, /* EDX or DX */ + PARAM_EBX, /* EBX or BX */ + PARAM_ESP, /* ESP or SP */ + PARAM_EBP, /* EBP or BP */ + PARAM_ESI, /* ESI or SI */ + PARAM_EDI, /* EDI or DI */ + PARAM_XMM0, + PARAM_XMM64, /* 64-bit memory or XMM register */ + PARAM_XMM32, /* 32-bit memory or XMM register */ + PARAM_XMM16 /* 16-bit memory or XMM register */ +}; + +enum +{ + MODRM = 1, + GROUP, + FPU, + OP_SIZE, + ADDR_SIZE, + TWO_BYTE, + PREFIX, + SEG_CS, + SEG_DS, + SEG_ES, + SEG_FS, + SEG_GS, + SEG_SS, + ISREX, + THREE_BYTE /* [prefix] 0f op1 op2 and then mod/rm */ +}; + +#define FLAGS_MASK 0x0ff +#define VAR_NAME 0x100 +#define VAR_NAME4 0x200 +#define ALWAYS64 0x400 +#define SPECIAL64 0x800 +#define SPECIAL64_ENT(x) (SPECIAL64 | ((x) << 24)) +#define GROUP_MOD 0x1000 + +struct I386_OPCODE { + const char *mnemonic; + UINT32 flags; + UINT32 param1; + UINT32 param2; + UINT32 param3; + offs_t dasm_flags; +}; + +struct GROUP_OP { + char mnemonic[32]; + const I386_OPCODE *opcode; +}; + +static const UINT8 *opcode_ptr; +static const UINT8 *opcode_ptr_base; + +static const I386_OPCODE i386_opcode_table1[256] = +{ + // 0x00 + {"add", MODRM, PARAM_RM8, PARAM_REG8, 0 }, + {"add", MODRM, PARAM_RM, PARAM_REG, 0 }, + {"add", MODRM, PARAM_REG8, PARAM_RM8, 0 }, + {"add", MODRM, PARAM_REG, PARAM_RM, 0 }, + {"add", 0, PARAM_AL, PARAM_UI8, 0 }, + {"add", 0, PARAM_EAX, PARAM_IMM, 0 }, + {"push es", 0, 0, 0, 0 }, + {"pop es", 0, 0, 0, 0 }, + {"or", MODRM, PARAM_RM8, PARAM_REG8, 0 }, + {"or", MODRM, PARAM_RM, PARAM_REG, 0 }, + {"or", MODRM, PARAM_REG8, PARAM_RM8, 0 }, + {"or", MODRM, PARAM_REG, PARAM_RM, 0 }, + {"or", 0, PARAM_AL, PARAM_UI8, 0 }, + {"or", 0, PARAM_EAX, PARAM_IMM, 0 }, + {"push cs", 0, 0, 0, 0 }, + {"two_byte", TWO_BYTE, 0, 0, 0 }, + // 0x10 + {"adc", MODRM, PARAM_RM8, PARAM_REG8, 0 }, + {"adc", MODRM, PARAM_RM, PARAM_REG, 0 }, + {"adc", MODRM, PARAM_REG8, PARAM_RM8, 0 }, + {"adc", MODRM, PARAM_REG, PARAM_RM, 0 }, + {"adc", 0, PARAM_AL, PARAM_UI8, 0 }, + {"adc", 0, PARAM_EAX, PARAM_IMM, 0 }, + {"push ss", 0, 0, 0, 0 }, + {"pop ss", 0, 0, 0, 0 }, + {"sbb", MODRM, PARAM_RM8, PARAM_REG8, 0 }, + {"sbb", MODRM, PARAM_RM, PARAM_REG, 0 }, + {"sbb", MODRM, PARAM_REG8, PARAM_RM8, 0 }, + {"sbb", MODRM, PARAM_REG, PARAM_RM, 0 }, + {"sbb", 0, PARAM_AL, PARAM_UI8, 0 }, + {"sbb", 0, PARAM_EAX, PARAM_IMM, 0 }, + {"push ds", 0, 0, 0, 0 }, + {"pop ds", 0, 0, 0, 0 }, + // 0x20 + {"and", MODRM, PARAM_RM8, PARAM_REG8, 0 }, + {"and", MODRM, PARAM_RM, PARAM_REG, 0 }, + {"and", MODRM, PARAM_REG8, PARAM_RM8, 0 }, + {"and", MODRM, PARAM_REG, PARAM_RM, 0 }, + {"and", 0, PARAM_AL, PARAM_UI8, 0 }, + {"and", 0, PARAM_EAX, PARAM_IMM, 0 }, + {"seg_es", SEG_ES, 0, 0, 0 }, + {"daa", 0, 0, 0, 0 }, + {"sub", MODRM, PARAM_RM8, PARAM_REG8, 0 }, + {"sub", MODRM, PARAM_RM, PARAM_REG, 0 }, + {"sub", MODRM, PARAM_REG8, PARAM_RM8, 0 }, + {"sub", MODRM, PARAM_REG, PARAM_RM, 0 }, + {"sub", 0, PARAM_AL, PARAM_UI8, 0 }, + {"sub", 0, PARAM_EAX, PARAM_IMM, 0 }, + {"seg_cs", SEG_CS, 0, 0, 0 }, + {"das", 0, 0, 0, 0 }, + // 0x30 + {"xor", MODRM, PARAM_RM8, PARAM_REG8, 0 }, + {"xor", MODRM, PARAM_RM, PARAM_REG, 0 }, + {"xor", MODRM, PARAM_REG8, PARAM_RM8, 0 }, + {"xor", MODRM, PARAM_REG, PARAM_RM, 0 }, + {"xor", 0, PARAM_AL, PARAM_UI8, 0 }, + {"xor", 0, PARAM_EAX, PARAM_IMM, 0 }, + {"seg_ss", SEG_SS, 0, 0, 0 }, + {"aaa", 0, 0, 0, 0 }, + {"cmp", MODRM, PARAM_RM8, PARAM_REG8, 0 }, + {"cmp", MODRM, PARAM_RM, PARAM_REG, 0 }, + {"cmp", MODRM, PARAM_REG8, PARAM_RM8, 0 }, + {"cmp", MODRM, PARAM_REG, PARAM_RM, 0 }, + {"cmp", 0, PARAM_AL, PARAM_UI8, 0 }, + {"cmp", 0, PARAM_EAX, PARAM_IMM, 0 }, + {"seg_ds", SEG_DS, 0, 0, 0 }, + {"aas", 0, 0, 0, 0 }, + // 0x40 + {"inc", ISREX, PARAM_EAX, 0, 0 }, + {"inc", ISREX, PARAM_ECX, 0, 0 }, + {"inc", ISREX, PARAM_EDX, 0, 0 }, + {"inc", ISREX, PARAM_EBX, 0, 0 }, + {"inc", ISREX, PARAM_ESP, 0, 0 }, + {"inc", ISREX, PARAM_EBP, 0, 0 }, + {"inc", ISREX, PARAM_ESI, 0, 0 }, + {"inc", ISREX, PARAM_EDI, 0, 0 }, + {"dec", ISREX, PARAM_EAX, 0, 0 }, + {"dec", ISREX, PARAM_ECX, 0, 0 }, + {"dec", ISREX, PARAM_EDX, 0, 0 }, + {"dec", ISREX, PARAM_EBX, 0, 0 }, + {"dec", ISREX, PARAM_ESP, 0, 0 }, + {"dec", ISREX, PARAM_EBP, 0, 0 }, + {"dec", ISREX, PARAM_ESI, 0, 0 }, + {"dec", ISREX, PARAM_EDI, 0, 0 }, + // 0x50 + {"push", ALWAYS64, PARAM_EAX, 0, 0 }, + {"push", ALWAYS64, PARAM_ECX, 0, 0 }, + {"push", ALWAYS64, PARAM_EDX, 0, 0 }, + {"push", ALWAYS64, PARAM_EBX, 0, 0 }, + {"push", ALWAYS64, PARAM_ESP, 0, 0 }, + {"push", ALWAYS64, PARAM_EBP, 0, 0 }, + {"push", ALWAYS64, PARAM_ESI, 0, 0 }, + {"push", ALWAYS64, PARAM_EDI, 0, 0 }, + {"pop", ALWAYS64, PARAM_EAX, 0, 0 }, + {"pop", ALWAYS64, PARAM_ECX, 0, 0 }, + {"pop", ALWAYS64, PARAM_EDX, 0, 0 }, + {"pop", ALWAYS64, PARAM_EBX, 0, 0 }, + {"pop", ALWAYS64, PARAM_ESP, 0, 0 }, + {"pop", ALWAYS64, PARAM_EBP, 0, 0 }, + {"pop", ALWAYS64, PARAM_ESI, 0, 0 }, + {"pop", ALWAYS64, PARAM_EDI, 0, 0 }, + // 0x60 + {"pusha\0pushad\0",VAR_NAME,0, 0, 0 }, + {"popa\0popad\0", VAR_NAME,0, 0, 0 }, + {"bound", MODRM, PARAM_REG, PARAM_RM, 0 }, + {"arpl", MODRM | SPECIAL64_ENT(0),PARAM_RM, PARAM_REG16, 0 }, + {"seg_fs", SEG_FS, 0, 0, 0 }, + {"seg_gs", SEG_GS, 0, 0, 0 }, + {"op_size", OP_SIZE, 0, 0, 0 }, + {"addr_size", ADDR_SIZE, 0, 0, 0 }, + {"push", 0, PARAM_IMM, 0, 0 }, + {"imul", MODRM, PARAM_REG, PARAM_RM, PARAM_IMM }, + {"push", 0, PARAM_I8, 0, 0 }, + {"imul", MODRM, PARAM_REG, PARAM_RM, PARAM_I8 }, + {"insb", 0, 0, 0, 0 }, + {"insw\0insd\0insd",VAR_NAME, 0, 0, 0 }, + {"outsb", 0, PARAM_PREIMP, 0, 0 }, + {"outsw\0outsd\0outsd",VAR_NAME, PARAM_PREIMP, 0, 0 }, + // 0x70 + {"jo", 0, PARAM_REL8, 0, 0 }, + {"jno", 0, PARAM_REL8, 0, 0 }, + {"jb", 0, PARAM_REL8, 0, 0 }, + {"jae", 0, PARAM_REL8, 0, 0 }, + {"je", 0, PARAM_REL8, 0, 0 }, + {"jne", 0, PARAM_REL8, 0, 0 }, + {"jbe", 0, PARAM_REL8, 0, 0 }, + {"ja", 0, PARAM_REL8, 0, 0 }, + {"js", 0, PARAM_REL8, 0, 0 }, + {"jns", 0, PARAM_REL8, 0, 0 }, + {"jp", 0, PARAM_REL8, 0, 0 }, + {"jnp", 0, PARAM_REL8, 0, 0 }, + {"jl", 0, PARAM_REL8, 0, 0 }, + {"jge", 0, PARAM_REL8, 0, 0 }, + {"jle", 0, PARAM_REL8, 0, 0 }, + {"jg", 0, PARAM_REL8, 0, 0 }, + // 0x80 + {"group80", GROUP, 0, 0, 0 }, + {"group81", GROUP, 0, 0, 0 }, + {"group80", GROUP, 0, 0, 0 }, + {"group83", GROUP, 0, 0, 0 }, + {"test", MODRM, PARAM_RM8, PARAM_REG8, 0 }, + {"test", MODRM, PARAM_RM, PARAM_REG, 0 }, + {"xchg", MODRM, PARAM_REG8, PARAM_RM8, 0 }, + {"xchg", MODRM, PARAM_REG, PARAM_RM, 0 }, + {"mov", MODRM, PARAM_RM8, PARAM_REG8, 0 }, + {"mov", MODRM, PARAM_RM, PARAM_REG, 0 }, + {"mov", MODRM, PARAM_REG8, PARAM_RM8, 0 }, + {"mov", MODRM, PARAM_REG, PARAM_RM, 0 }, + {"mov", MODRM, PARAM_RM, PARAM_SREG, 0 }, + {"lea", MODRM, PARAM_REG, PARAM_RM, 0 }, + {"mov", MODRM, PARAM_SREG, PARAM_RM, 0 }, + {"pop", MODRM, PARAM_RM, 0, 0 }, + // 0x90 + {"nop\0???\0???\0pause", VAR_NAME4, 0, 0, 0 }, + {"xchg", 0, PARAM_EAX, PARAM_ECX, 0 }, + {"xchg", 0, PARAM_EAX, PARAM_EDX, 0 }, + {"xchg", 0, PARAM_EAX, PARAM_EBX, 0 }, + {"xchg", 0, PARAM_EAX, PARAM_ESP, 0 }, + {"xchg", 0, PARAM_EAX, PARAM_EBP, 0 }, + {"xchg", 0, PARAM_EAX, PARAM_ESI, 0 }, + {"xchg", 0, PARAM_EAX, PARAM_EDI, 0 }, + {"cbw\0cwde\0cdqe", VAR_NAME, 0, 0, 0 }, + {"cwd\0cdq\0cqo", VAR_NAME, 0, 0, 0 }, + {"call", ALWAYS64, PARAM_ADDR, 0, 0, DASMFLAG_STEP_OVER}, + {"wait", 0, 0, 0, 0 }, + {"pushf\0pushfd\0pushfq",VAR_NAME, 0, 0, 0 }, + {"popf\0popfd\0popfq",VAR_NAME, 0, 0, 0 }, + {"sahf", 0, 0, 0, 0 }, + {"lahf", 0, 0, 0, 0 }, + // 0xa0 + {"mov", 0, PARAM_AL, PARAM_MEM_OFFS, 0 }, + {"mov", 0, PARAM_EAX, PARAM_MEM_OFFS, 0 }, + {"mov", 0, PARAM_MEM_OFFS, PARAM_AL, 0 }, + {"mov", 0, PARAM_MEM_OFFS, PARAM_EAX, 0 }, + {"movsb", 0, PARAM_PREIMP, 0, 0 }, + {"movsw\0movsd\0movsq",VAR_NAME, PARAM_PREIMP, 0, 0 }, + {"cmpsb", 0, PARAM_PREIMP, 0, 0 }, + {"cmpsw\0cmpsd\0cmpsq",VAR_NAME, PARAM_PREIMP, 0, 0 }, + {"test", 0, PARAM_AL, PARAM_UI8, 0 }, + {"test", 0, PARAM_EAX, PARAM_IMM, 0 }, + {"stosb", 0, 0, 0, 0 }, + {"stosw\0stosd\0stosq",VAR_NAME, 0, 0, 0 }, + {"lodsb", 0, PARAM_PREIMP, 0, 0 }, + {"lodsw\0lodsd\0lodsq",VAR_NAME, PARAM_PREIMP, 0, 0 }, + {"scasb", 0, 0, 0, 0 }, + {"scasw\0scasd\0scasq",VAR_NAME, 0, 0, 0 }, + // 0xb0 + {"mov", 0, PARAM_AL, PARAM_UI8, 0 }, + {"mov", 0, PARAM_CL, PARAM_UI8, 0 }, + {"mov", 0, PARAM_DL, PARAM_UI8, 0 }, + {"mov", 0, PARAM_BL, PARAM_UI8, 0 }, + {"mov", 0, PARAM_AH, PARAM_UI8, 0 }, + {"mov", 0, PARAM_CH, PARAM_UI8, 0 }, + {"mov", 0, PARAM_DH, PARAM_UI8, 0 }, + {"mov", 0, PARAM_BH, PARAM_UI8, 0 }, + {"mov", 0, PARAM_EAX, PARAM_IMM64, 0 }, + {"mov", 0, PARAM_ECX, PARAM_IMM64, 0 }, + {"mov", 0, PARAM_EDX, PARAM_IMM64, 0 }, + {"mov", 0, PARAM_EBX, PARAM_IMM64, 0 }, + {"mov", 0, PARAM_ESP, PARAM_IMM64, 0 }, + {"mov", 0, PARAM_EBP, PARAM_IMM64, 0 }, + {"mov", 0, PARAM_ESI, PARAM_IMM64, 0 }, + {"mov", 0, PARAM_EDI, PARAM_IMM64, 0 }, + // 0xc0 + {"groupC0", GROUP, 0, 0, 0 }, + {"groupC1", GROUP, 0, 0, 0 }, + {"ret", 0, PARAM_UI16, 0, 0, DASMFLAG_STEP_OUT}, + {"ret", 0, 0, 0, 0, DASMFLAG_STEP_OUT}, + {"les", MODRM, PARAM_REG, PARAM_RM, 0 }, + {"lds", MODRM, PARAM_REG, PARAM_RM, 0 }, + {"mov", MODRM, PARAM_RMPTR8, PARAM_UI8, 0 }, + {"mov", MODRM, PARAM_RMPTR, PARAM_IMM, 0 }, + {"enter", 0, PARAM_UI16, PARAM_UI8, 0 }, + {"leave", 0, 0, 0, 0 }, + {"retf", 0, PARAM_UI16, 0, 0, DASMFLAG_STEP_OUT}, + {"retf", 0, 0, 0, 0, DASMFLAG_STEP_OUT}, + {"int 3", 0, 0, 0, 0, DASMFLAG_STEP_OVER}, + {"int", 0, PARAM_UI8, 0, 0, DASMFLAG_STEP_OVER}, + {"into", 0, 0, 0, 0 }, + {"iret", 0, 0, 0, 0, DASMFLAG_STEP_OUT}, + // 0xd0 + {"groupD0", GROUP, 0, 0, 0 }, + {"groupD1", GROUP, 0, 0, 0 }, + {"groupD2", GROUP, 0, 0, 0 }, + {"groupD3", GROUP, 0, 0, 0 }, + {"aam", 0, PARAM_UI8, 0, 0 }, + {"aad", 0, PARAM_UI8, 0, 0 }, + {"salc", 0, 0, 0, 0 }, //AMD docs name it + {"xlat", 0, 0, 0, 0 }, + {"escape", FPU, 0, 0, 0 }, + {"escape", FPU, 0, 0, 0 }, + {"escape", FPU, 0, 0, 0 }, + {"escape", FPU, 0, 0, 0 }, + {"escape", FPU, 0, 0, 0 }, + {"escape", FPU, 0, 0, 0 }, + {"escape", FPU, 0, 0, 0 }, + {"escape", FPU, 0, 0, 0 }, + // 0xe0 + {"loopne", 0, PARAM_REL8, 0, 0, DASMFLAG_STEP_OVER}, + {"loopz", 0, PARAM_REL8, 0, 0, DASMFLAG_STEP_OVER}, + {"loop", 0, PARAM_REL8, 0, 0, DASMFLAG_STEP_OVER}, + {"jcxz\0jecxz\0jrcxz",VAR_NAME, PARAM_REL8, 0, 0 }, + {"in", 0, PARAM_AL, PARAM_UI8, 0 }, + {"in", 0, PARAM_EAX, PARAM_UI8, 0 }, + {"out", 0, PARAM_UI8, PARAM_AL, 0 }, + {"out", 0, PARAM_UI8, PARAM_EAX, 0 }, + {"call", 0, PARAM_REL, 0, 0, DASMFLAG_STEP_OVER}, + {"jmp", 0, PARAM_REL, 0, 0 }, + {"jmp", 0, PARAM_ADDR, 0, 0 }, + {"jmp", 0, PARAM_REL8, 0, 0 }, + {"in", 0, PARAM_AL, PARAM_DX, 0 }, + {"in", 0, PARAM_EAX, PARAM_DX, 0 }, + {"out", 0, PARAM_DX, PARAM_AL, 0 }, + {"out", 0, PARAM_DX, PARAM_EAX, 0 }, + // 0xf0 + {"lock", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"repne", PREFIX, 0, 0, 0 }, + {"rep", PREFIX, 0, 0, 0 }, + {"hlt", 0, 0, 0, 0 }, + {"cmc", 0, 0, 0, 0 }, + {"groupF6", GROUP, 0, 0, 0 }, + {"groupF7", GROUP, 0, 0, 0 }, + {"clc", 0, 0, 0, 0 }, + {"stc", 0, 0, 0, 0 }, + {"cli", 0, 0, 0, 0 }, + {"sti", 0, 0, 0, 0 }, + {"cld", 0, 0, 0, 0 }, + {"std", 0, 0, 0, 0 }, + {"groupFE", GROUP, 0, 0, 0 }, + {"groupFF", GROUP, 0, 0, 0 } +}; + +static const I386_OPCODE x64_opcode_alt[] = +{ + {"movsxd", MODRM | ALWAYS64,PARAM_REG, PARAM_RMPTR32, 0 }, +}; + +static const I386_OPCODE i386_opcode_table2[256] = +{ + // 0x00 + {"group0F00", GROUP, 0, 0, 0 }, + {"group0F01", GROUP, 0, 0, 0 }, + {"lar", MODRM, PARAM_REG, PARAM_RM, 0 }, + {"lsl", MODRM, PARAM_REG, PARAM_RM, 0 }, + {"???", 0, 0, 0, 0 }, + {"syscall", 0, 0, 0, 0 }, + {"clts", 0, 0, 0, 0 }, + {"sysret", 0, 0, 0, 0 }, + {"invd", 0, 0, 0, 0 }, + {"wbinvd", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"ud2", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"group0F0D", GROUP, 0, 0, 0 }, //AMD only + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + // 0x10 + {"movups\0" + "movupd\0" + "movsd\0" + "movss", MODRM|VAR_NAME4,PARAM_XMM, PARAM_XMMM, 0 }, + {"movups\0" + "movupd\0" + "movsd\0" + "movss", MODRM|VAR_NAME4,PARAM_XMMM, PARAM_XMM, 0 }, + {"group0F12", GROUP|GROUP_MOD, 0, 0, 0 }, + {"movlps\0" + "movlpd\0" + "???\0" + "???", MODRM|VAR_NAME4,PARAM_XMMM, PARAM_XMM, 0 }, + {"unpcklps\0" + "unpcklpd\0" + "???\0" + "???", MODRM|VAR_NAME4,PARAM_XMM, PARAM_XMMM, 0 }, + {"unpckhps\0" + "unpckhpd\0" + "???\0" + "???", MODRM|VAR_NAME4,PARAM_XMM, PARAM_XMMM, 0 }, + { "group0F16", GROUP|GROUP_MOD, 0, 0, 0 }, + {"movhps\0" + "movhpd\0" + "???\0" + "???", MODRM|VAR_NAME4,PARAM_XMMM, PARAM_XMM, 0 }, + {"group0F18", GROUP, 0, 0, 0 }, + {"nop_hint", 0, PARAM_RMPTR8, 0, 0 }, + {"nop_hint", 0, PARAM_RMPTR8, 0, 0 }, + {"nop_hint", 0, PARAM_RMPTR8, 0, 0 }, + {"nop_hint", 0, PARAM_RMPTR8, 0, 0 }, + {"nop_hint", 0, PARAM_RMPTR8, 0, 0 }, + {"nop_hint", 0, PARAM_RMPTR8, 0, 0 }, + {"nop_hint", 0, PARAM_RMPTR8, 0, 0 }, + // 0x20 + {"mov", MODRM, PARAM_REG2_32, PARAM_CREG, 0 }, + {"mov", MODRM, PARAM_REG2_32, PARAM_DREG, 0 }, + {"mov", MODRM, PARAM_CREG, PARAM_REG2_32, 0 }, + {"mov", MODRM, PARAM_DREG, PARAM_REG2_32, 0 }, + {"mov", MODRM, PARAM_REG2_32, PARAM_TREG, 0 }, + {"???", 0, 0, 0, 0 }, + {"mov", MODRM, PARAM_TREG, PARAM_REG2_32, 0 }, + {"???", 0, 0, 0, 0 }, + {"movaps\0" + "movapd\0" + "???\0" + "???", MODRM|VAR_NAME4,PARAM_XMM, PARAM_XMMM, 0 }, + {"movaps\0" + "movapd\0" + "???\0" + "???", MODRM|VAR_NAME4,PARAM_XMMM, PARAM_XMM, 0 }, + {"cvtpi2ps\0" + "cvtpi2pd\0" + "cvtsi2sd\0" + "cvtsi2ss", MODRM|VAR_NAME4,PARAM_XMM, PARAM_RMXMM, 0 }, + {"movntps\0" + "movntpd\0" + "???\0" + "???", MODRM|VAR_NAME4,PARAM_XMMM, PARAM_XMM, 0 }, + {"cvttps2pi\0" + "cvttpd2pi\0" + "cvttsd2si\0" + "cvttss2si", MODRM|VAR_NAME4,PARAM_REGORXMM, PARAM_XMMM, 0 }, + {"cvtps2pi\0" + "cvtpd2pi\0" + "cvtsd2si\0" + "cvtss2si", MODRM|VAR_NAME4,PARAM_REGORXMM, PARAM_XMMM, 0 }, + {"ucomiss\0" + "ucomisd\0" + "???\0" + "???", MODRM|VAR_NAME4,PARAM_XMM, PARAM_XMMM, 0 }, + {"comiss\0" + "comisd\0" + "???\0" + "???", MODRM|VAR_NAME4,PARAM_XMM, PARAM_XMMM, 0 }, + // 0x30 + {"wrmsr", 0, 0, 0, 0 }, + {"rdtsc", 0, 0, 0, 0 }, + {"rdmsr", 0, 0, 0, 0 }, + {"rdpmc", 0, 0, 0, 0 }, + {"sysenter", 0, 0, 0, 0 }, + {"sysexit", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"three_byte", THREE_BYTE, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"three_byte", THREE_BYTE, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + // 0x40 + {"cmovo", MODRM, PARAM_REG, PARAM_RM, 0 }, + {"cmovno", MODRM, PARAM_REG, PARAM_RM, 0 }, + {"cmovb", MODRM, PARAM_REG, PARAM_RM, 0 }, + {"cmovae", MODRM, PARAM_REG, PARAM_RM, 0 }, + {"cmove", MODRM, PARAM_REG, PARAM_RM, 0 }, + {"cmovne", MODRM, PARAM_REG, PARAM_RM, 0 }, + {"cmovbe", MODRM, PARAM_REG, PARAM_RM, 0 }, + {"cmova", MODRM, PARAM_REG, PARAM_RM, 0 }, + {"cmovs", MODRM, PARAM_REG, PARAM_RM, 0 }, + {"cmovns", MODRM, PARAM_REG, PARAM_RM, 0 }, + {"cmovpe", MODRM, PARAM_REG, PARAM_RM, 0 }, + {"cmovpo", MODRM, PARAM_REG, PARAM_RM, 0 }, + {"cmovl", MODRM, PARAM_REG, PARAM_RM, 0 }, + {"cmovge", MODRM, PARAM_REG, PARAM_RM, 0 }, + {"cmovle", MODRM, PARAM_REG, PARAM_RM, 0 }, + {"cmovg", MODRM, PARAM_REG, PARAM_RM, 0 }, + // 0x50 + {"movmskps\0" + "movmskpd\0" + "???\0" + "???", MODRM|VAR_NAME4,PARAM_REG3264, PARAM_XMMM, 0 }, + {"sqrtps\0" + "sqrtpd\0" + "sqrtsd\0" + "sqrtss", MODRM|VAR_NAME4,PARAM_XMM, PARAM_XMMM, 0 }, + {"rsqrtps\0" + "???\0" + "???\0" + "rsqrtss", MODRM|VAR_NAME4,PARAM_XMM, PARAM_XMMM, 0 }, + {"rcpps\0" + "???\0" + "???\0" + "rcpss", MODRM|VAR_NAME4,PARAM_XMM, PARAM_XMMM, 0 }, + {"andps\0" + "andpd\0" + "???\0" + "???", MODRM|VAR_NAME4,PARAM_XMM, PARAM_XMMM, 0 }, + {"andnps\0" + "andnpd\0" + "???\0" + "???", MODRM|VAR_NAME4,PARAM_XMM, PARAM_XMMM, 0 }, + {"orps\0" + "orpd\0" + "???\0" + "???", MODRM|VAR_NAME4,PARAM_XMM, PARAM_XMMM, 0 }, + {"xorps\0" + "xorpd\0" + "???\0" + "???", MODRM|VAR_NAME4,PARAM_XMM, PARAM_XMMM, 0 }, + {"addps\0" + "addpd\0" + "addsd\0" + "addss", MODRM|VAR_NAME4,PARAM_XMM, PARAM_XMMM, 0 }, + {"mulps\0" + "mulpd\0" + "mulsd\0" + "mulss", MODRM|VAR_NAME4,PARAM_XMM, PARAM_XMMM, 0 }, + {"cvtps2pd\0" + "cvtpd2ps\0" + "cvtsd2ss\0" + "cvtss2sd", MODRM|VAR_NAME4,PARAM_XMM, PARAM_XMMM, 0 }, + {"cvtdq2ps\0" + "cvtps2dq\0" + "???\0" + "cvttps2dq", MODRM|VAR_NAME4,PARAM_XMM, PARAM_XMMM, 0 }, + {"subps\0" + "subpd\0" + "subsd\0" + "subss", MODRM|VAR_NAME4,PARAM_XMM, PARAM_XMMM, 0 }, + {"minps\0" + "minpd\0" + "minsd\0" + "minss", MODRM|VAR_NAME4,PARAM_XMM, PARAM_XMMM, 0 }, + {"divps\0" + "divpd\0" + "divsd\0" + "divss", MODRM|VAR_NAME4,PARAM_XMM, PARAM_XMMM, 0 }, + {"maxps\0" + "maxpd\0" + "maxsd\0" + "maxss", MODRM|VAR_NAME4,PARAM_XMM, PARAM_XMMM, 0 }, + // 0x60 + {"punpcklbw", MODRM, PARAM_MMX, PARAM_MMXM, 0 }, + {"punpcklwd", MODRM, PARAM_MMX, PARAM_MMXM, 0 }, + {"punpckldq", MODRM, PARAM_MMX, PARAM_MMXM, 0 }, + {"packsswb", MODRM, PARAM_MMX, PARAM_MMXM, 0 }, + {"pcmpgtb", MODRM, PARAM_MMX, PARAM_MMXM, 0 }, + {"pcmpgtw", MODRM, PARAM_MMX, PARAM_MMXM, 0 }, + {"pcmpgtd", MODRM, PARAM_MMX, PARAM_MMXM, 0 }, + {"packuswb", MODRM, PARAM_MMX, PARAM_MMXM, 0 }, + {"punpckhbw", MODRM, PARAM_MMX, PARAM_MMXM, 0 }, + {"punpckhwd", MODRM, PARAM_MMX, PARAM_MMXM, 0 }, + {"punpckhdq", MODRM, PARAM_MMX, PARAM_MMXM, 0 }, + {"packssdw", MODRM, PARAM_MMX, PARAM_MMXM, 0 }, + {"???\0" + "punpcklqdq\0" + "???\0" + "???\0", MODRM|VAR_NAME4, PARAM_XMM, PARAM_XMMM, 0 }, + {"???\0" + "punpckhqdq\0" + "???\0" + "???\0", MODRM|VAR_NAME4, PARAM_XMM, PARAM_XMMM, 0 }, + {"movd", MODRM, PARAM_MMX, PARAM_RM, 0 }, + {"movq\0" + "movdqa\0" + "???\0" + "movdqu", MODRM|VAR_NAME4,PARAM_MMX, PARAM_MMXM, 0 }, + // 0x70 + {"pshufw\0" + "pshufd\0" + "pshuflw\0" + "pshufhw", MODRM|VAR_NAME4,PARAM_MMX, PARAM_MMXM, PARAM_UI8 }, + {"group0F71", GROUP, 0, 0, 0 }, + {"group0F72", GROUP, 0, 0, 0 }, + {"group0F73", GROUP, 0, 0, 0 }, + {"pcmpeqb", MODRM, PARAM_MMX, PARAM_MMXM, 0 }, + {"pcmpeqw", MODRM, PARAM_MMX, PARAM_MMXM, 0 }, + {"pcmpeqd", MODRM, PARAM_MMX, PARAM_MMXM, 0 }, + {"emms", 0, 0, 0, 0 }, + {"vmread", MODRM, PARAM_RM, PARAM_REG, 0 }, + {"vmwrite", MODRM, PARAM_RM, PARAM_REG, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???\0" + "haddpd\0" + "haddps\0" + "???", MODRM|VAR_NAME4,PARAM_MMX, PARAM_MMXM, 0 }, + {"???\0" + "hsubpd\0" + "hsubps\0" + "???", MODRM|VAR_NAME4,PARAM_MMX, PARAM_MMXM, 0 }, + {"movd\0" + "movd\0" + "???\0" + "movq", MODRM|VAR_NAME4,PARAM_RM, PARAM_MMX, 0 }, + {"movq\0" + "movdqa\0" + "???\0" + "movdqu", MODRM|VAR_NAME4,PARAM_MMXM, PARAM_MMX, 0 }, + // 0x80 + {"jo", 0, PARAM_REL, 0, 0 }, + {"jno", 0, PARAM_REL, 0, 0 }, + {"jb", 0, PARAM_REL, 0, 0 }, + {"jae", 0, PARAM_REL, 0, 0 }, + {"je", 0, PARAM_REL, 0, 0 }, + {"jne", 0, PARAM_REL, 0, 0 }, + {"jbe", 0, PARAM_REL, 0, 0 }, + {"ja", 0, PARAM_REL, 0, 0 }, + {"js", 0, PARAM_REL, 0, 0 }, + {"jns", 0, PARAM_REL, 0, 0 }, + {"jp", 0, PARAM_REL, 0, 0 }, + {"jnp", 0, PARAM_REL, 0, 0 }, + {"jl", 0, PARAM_REL, 0, 0 }, + {"jge", 0, PARAM_REL, 0, 0 }, + {"jle", 0, PARAM_REL, 0, 0 }, + {"jg", 0, PARAM_REL, 0, 0 }, + // 0x90 + {"seto", MODRM, PARAM_RMPTR8, 0, 0 }, + {"setno", MODRM, PARAM_RMPTR8, 0, 0 }, + {"setb", MODRM, PARAM_RMPTR8, 0, 0 }, + {"setae", MODRM, PARAM_RMPTR8, 0, 0 }, + {"sete", MODRM, PARAM_RMPTR8, 0, 0 }, + {"setne", MODRM, PARAM_RMPTR8, 0, 0 }, + {"setbe", MODRM, PARAM_RMPTR8, 0, 0 }, + {"seta", MODRM, PARAM_RMPTR8, 0, 0 }, + {"sets", MODRM, PARAM_RMPTR8, 0, 0 }, + {"setns", MODRM, PARAM_RMPTR8, 0, 0 }, + {"setp", MODRM, PARAM_RMPTR8, 0, 0 }, + {"setnp", MODRM, PARAM_RMPTR8, 0, 0 }, + {"setl", MODRM, PARAM_RMPTR8, 0, 0 }, + {"setge", MODRM, PARAM_RMPTR8, 0, 0 }, + {"setle", MODRM, PARAM_RMPTR8, 0, 0 }, + {"setg", MODRM, PARAM_RMPTR8, 0, 0 }, + // 0xa0 + {"push fs", 0, 0, 0, 0 }, + {"pop fs", 0, 0, 0, 0 }, + {"cpuid", 0, 0, 0, 0 }, + {"bt", MODRM, PARAM_RM, PARAM_REG, 0 }, + {"shld", MODRM, PARAM_RM, PARAM_REG, PARAM_UI8 }, + {"shld", MODRM, PARAM_RM, PARAM_REG, PARAM_CL }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"push gs", 0, 0, 0, 0 }, + {"pop gs", 0, 0, 0, 0 }, + {"rsm", 0, 0, 0, 0 }, + {"bts", MODRM, PARAM_RM, PARAM_REG, 0 }, + {"shrd", MODRM, PARAM_RM, PARAM_REG, PARAM_UI8 }, + {"shrd", MODRM, PARAM_RM, PARAM_REG, PARAM_CL }, + {"group0FAE", GROUP, 0, 0, 0 }, + {"imul", MODRM, PARAM_REG, PARAM_RM, 0 }, + // 0xb0 + {"cmpxchg", MODRM, PARAM_RM8, PARAM_REG, 0 }, + {"cmpxchg", MODRM, PARAM_RM, PARAM_REG, 0 }, + {"lss", MODRM, PARAM_REG, PARAM_RM, 0 }, + {"btr", MODRM, PARAM_RM, PARAM_REG, 0 }, + {"lfs", MODRM, PARAM_REG, PARAM_RM, 0 }, + {"lgs", MODRM, PARAM_REG, PARAM_RM, 0 }, + {"movzx", MODRM, PARAM_REG, PARAM_RMPTR8, 0 }, + {"movzx", MODRM, PARAM_REG, PARAM_RMPTR16, 0 }, + {"???\0" + "???\0" + "???\0" + "popcnt", MODRM|VAR_NAME4, PARAM_REG, PARAM_RM16, 0 }, + {"ud2", 0, 0, 0, 0 }, + {"group0FBA", GROUP, 0, 0, 0 }, + {"btc", MODRM, PARAM_RM, PARAM_REG, 0 }, + {"bsf\0" + "???\0" + "???\0" + "tzcnt", MODRM|VAR_NAME4, PARAM_REG, PARAM_RM, 0 }, + {"bsr\0" + "???\0" + "???\0" + "lzcnt", MODRM|VAR_NAME4, PARAM_REG, PARAM_RM, 0, DASMFLAG_STEP_OVER}, + {"movsx", MODRM, PARAM_REG, PARAM_RMPTR8, 0 }, + {"movsx", MODRM, PARAM_REG, PARAM_RMPTR16, 0 }, + // 0xc0 + {"xadd", MODRM, PARAM_RM8, PARAM_REG, 0 }, + {"xadd", MODRM, PARAM_RM, PARAM_REG, 0 }, + {"cmpps\0" + "cmppd\0" + "cmpsd\0" + "cmpss", MODRM|VAR_NAME4,PARAM_XMM, PARAM_XMMM, 0 }, + {"movnti", MODRM, PARAM_RM, PARAM_REG, 0 }, + {"pinsrw", MODRM, PARAM_MMX, PARAM_RM, PARAM_UI8 }, + {"pextrw", MODRM, PARAM_MMX, PARAM_RM, PARAM_UI8 }, + {"shufps\0" + "shufpd\0" + "???\0" + "???", MODRM|VAR_NAME4,PARAM_XMM, PARAM_XMMM, PARAM_UI8 }, + {"group0FC7", GROUP, 0, 0, 0 }, + {"bswap", 0, PARAM_EAX, 0, 0 }, + {"bswap", 0, PARAM_ECX, 0, 0 }, + {"bswap", 0, PARAM_EDX, 0, 0 }, + {"bswap", 0, PARAM_EBX, 0, 0 }, + {"bswap", 0, PARAM_ESP, 0, 0 }, + {"bswap", 0, PARAM_EBP, 0, 0 }, + {"bswap", 0, PARAM_ESI, 0, 0 }, + {"bswap", 0, PARAM_EDI, 0, 0 }, + // 0xd0 + {"???\0" + "addsubpd\0" + "addsubps\0" + "???\0", MODRM|VAR_NAME4,PARAM_XMM, PARAM_XMMM, 0 }, + {"psrlw", MODRM, PARAM_MMX, PARAM_MMXM, 0 }, + {"psrld", MODRM, PARAM_MMX, PARAM_MMXM, 0 }, + {"psrlq", MODRM, PARAM_MMX, PARAM_MMXM, 0 }, + {"paddq", MODRM, PARAM_MMX, PARAM_MMXM, 0 }, + {"pmullw", MODRM, PARAM_MMX, PARAM_MMXM, 0 }, + {"???\0" + "movq\0" + "movdq2q\0" + "movq2dq", MODRM|VAR_NAME4,PARAM_MMX, PARAM_MMXM, 0 }, + {"pmovmskb", MODRM, PARAM_REG3264, PARAM_MMXM, 0 }, + {"psubusb", MODRM, PARAM_MMX, PARAM_MMXM, 0 }, + {"psubusw", MODRM, PARAM_MMX, PARAM_MMXM, 0 }, + {"pminub", MODRM, PARAM_MMX, PARAM_MMXM, 0 }, + {"pand", MODRM, PARAM_MMX, PARAM_MMXM, 0 }, + {"paddusb", MODRM, PARAM_MMX, PARAM_MMXM, 0 }, + {"paddusw", MODRM, PARAM_MMX, PARAM_MMXM, 0 }, + {"pmaxub", MODRM, PARAM_MMX, PARAM_MMXM, 0 }, + {"pandn", MODRM, PARAM_MMX, PARAM_MMXM, 0 }, + // 0xe0 + {"pavgb", MODRM, PARAM_MMX, PARAM_MMXM, 0 }, + {"psraw", MODRM, PARAM_MMX, PARAM_MMXM, 0 }, + {"psrad", MODRM, PARAM_MMX, PARAM_MMXM, 0 }, + {"pavgw", MODRM, PARAM_MMX, PARAM_MMXM, 0 }, + {"pmulhuw", MODRM, PARAM_MMX, PARAM_MMXM, 0 }, + {"pmulhw", MODRM, PARAM_MMX, PARAM_MMXM, 0 }, + {"???\0" + "cvttpd2dq\0" + "cvtpd2dq\0" + "cvtdq2pd", MODRM|VAR_NAME4,PARAM_XMM, PARAM_XMMM, 0 }, + {"movntq\0" + "movntdq\0" + "???\0" + "???\0", MODRM|VAR_NAME4, PARAM_M64, PARAM_MMX, 0 }, + {"psubsb", MODRM, PARAM_MMX, PARAM_MMXM, 0 }, + {"psubsw", MODRM, PARAM_MMX, PARAM_MMXM, 0 }, + {"pminsw", MODRM, PARAM_MMX, PARAM_MMXM, 0 }, + {"por", MODRM, PARAM_MMX, PARAM_MMXM, 0 }, + {"paddsb", MODRM, PARAM_MMX, PARAM_MMXM, 0 }, + {"paddsw", MODRM, PARAM_MMX, PARAM_MMXM, 0 }, + {"pmaxsw", MODRM, PARAM_MMX, PARAM_MMXM, 0 }, + {"pxor", MODRM, PARAM_MMX, PARAM_MMXM, 0 }, + // 0xf0 + {"???\0" + "???\0" + "lddqu\0" + "???", MODRM|VAR_NAME4,PARAM_XMM, PARAM_XMMM, 0 }, + {"psllw", MODRM, PARAM_MMX, PARAM_MMXM, 0 }, + {"pslld", MODRM, PARAM_MMX, PARAM_MMXM, 0 }, + {"psllq", MODRM, PARAM_MMX, PARAM_MMXM, 0 }, + {"pmuludq", MODRM, PARAM_MMX, PARAM_MMXM, 0 }, + {"pmaddwd", MODRM, PARAM_MMX, PARAM_MMXM, 0 }, + {"psadbw", MODRM, PARAM_MMX, PARAM_MMXM, 0 }, + {"maskmovq\0" + "maskmovdqu\0" + "???\0" + "???", MODRM|VAR_NAME4,PARAM_MMX, PARAM_MMXM, 0 }, + {"psubb", MODRM, PARAM_MMX, PARAM_MMXM, 0 }, + {"psubw", MODRM, PARAM_MMX, PARAM_MMXM, 0 }, + {"psubd", MODRM, PARAM_MMX, PARAM_MMXM, 0 }, + {"psubq", MODRM, PARAM_MMX, PARAM_MMXM, 0 }, + {"paddb", MODRM, PARAM_MMX, PARAM_MMXM, 0 }, + {"paddw", MODRM, PARAM_MMX, PARAM_MMXM, 0 }, + {"paddd", MODRM, PARAM_MMX, PARAM_MMXM, 0 }, + {"???", 0, 0, 0, 0 } +}; + +static const I386_OPCODE i386_opcode_table0F38[256] = +{ + // 0x00 + {"pshufb\0" + "pshufb\0" + "???\0" + "???", MODRM|VAR_NAME4, PARAM_XMM, PARAM_XMMM, 0 }, + {"phaddw\0" + "phaddw\0" + "???\0" + "???", MODRM|VAR_NAME4, PARAM_XMM, PARAM_XMMM, 0 }, + {"phaddd\0" + "phadd\0" + "???\0" + "???", MODRM|VAR_NAME4, PARAM_XMM, PARAM_XMMM, 0 }, + {"phaddsw\0" + "phaddsw\0" + "???\0" + "???", MODRM|VAR_NAME4, PARAM_XMM, PARAM_XMMM, 0 }, + {"pmaddubsw\0" + "pmaddubsw\0" + "???\0" + "???", MODRM|VAR_NAME4, PARAM_XMM, PARAM_XMMM, 0 }, + {"phsubw\0" + "phsubw\0" + "???\0" + "???", MODRM|VAR_NAME4, PARAM_XMM, PARAM_XMMM, 0 }, + {"phsubd\0" + "phsubd\0" + "???\0" + "???", MODRM|VAR_NAME4, PARAM_XMM, PARAM_XMMM, 0 }, + {"phsubsw\0" + "phsubsw\0" + "???\0" + "???", MODRM|VAR_NAME4, PARAM_XMM, PARAM_XMMM, 0 }, + {"psignb\0" + "psignb\0" + "???\0" + "???", MODRM|VAR_NAME4, PARAM_XMM, PARAM_XMMM, 0 }, + {"psignw\0" + "psignw\0" + "???\0" + "???", MODRM|VAR_NAME4, PARAM_XMM, PARAM_XMMM, 0 }, + {"psignd\0" + "psignd\0" + "???\0" + "???", MODRM|VAR_NAME4, PARAM_XMM, PARAM_XMMM, 0 }, + {"pmulhrsw\0" + "pmulhrsw\0" + "???\0" + "???", MODRM|VAR_NAME4, PARAM_XMM, PARAM_XMMM, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + // 0x10 + {"???\0" + "pblendvb\0" + "???\0" + "???", MODRM|VAR_NAME4, PARAM_XMM, PARAM_XMMM, PARAM_XMM0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???\0" + "blendvps\0" + "???\0" + "???", MODRM|VAR_NAME4, PARAM_XMM, PARAM_XMMM, PARAM_XMM0 }, + {"???\0" + "blendvpd\0" + "???\0" + "???", MODRM|VAR_NAME4, PARAM_XMM, PARAM_XMMM, PARAM_XMM0 }, + {"???", 0, 0, 0, 0 }, + {"???\0" + "ptest\0" + "???\0" + "???", MODRM|VAR_NAME4, PARAM_XMM, PARAM_XMMM, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"pabsb\0" + "pabsb\0" + "???\0" + "???", MODRM|VAR_NAME4, PARAM_XMM, PARAM_XMMM, 0 }, + {"pabsw\0" + "pabsw\0" + "???\0" + "???", MODRM|VAR_NAME4, PARAM_XMM, PARAM_XMMM, 0 }, + {"pabsd\0" + "pabsd\0" + "???\0" + "???", MODRM|VAR_NAME4, PARAM_XMM, PARAM_XMMM, 0 }, + {"???", 0, 0, 0, 0 }, + // 0x20 + {"???\0" + "pmovsxbw\0" + "???\0" + "???", MODRM|VAR_NAME4, PARAM_XMM, PARAM_XMM64, 0 }, + {"???\0" + "pmovsxbd\0" + "???\0" + "???", MODRM|VAR_NAME4, PARAM_XMM, PARAM_XMM32, 0 }, + {"???\0" + "pmovsxbq\0" + "???\0" + "???", MODRM|VAR_NAME4, PARAM_XMM, PARAM_XMM16, 0 }, + {"???\0" + "pmovsxwd\0" + "???\0" + "???", MODRM|VAR_NAME4, PARAM_XMM, PARAM_XMM64, 0 }, + {"???\0" + "pmovsxwq\0" + "???\0" + "???", MODRM|VAR_NAME4, PARAM_XMM, PARAM_XMM32, 0 }, + {"???\0" + "pmovsxdq\0" + "???\0" + "???", MODRM|VAR_NAME4, PARAM_XMM, PARAM_XMM64, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???\0" + "pmuldq\0" + "???\0" + "???", MODRM|VAR_NAME4, PARAM_XMM, PARAM_XMMM, 0 }, + {"???\0" + "pcmpeqq\0" + "???\0" + "???", MODRM|VAR_NAME4, PARAM_XMM, PARAM_XMMM, 0 }, + {"???\0" + "movntdqa\0" + "???\0" + "???", MODRM|VAR_NAME4, PARAM_XMM, PARAM_XMMM, 0 }, + {"???\0" + "packusdw\0" + "???\0" + "???", MODRM|VAR_NAME4, PARAM_XMM, PARAM_XMMM, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + // 0x30 + {"???\0" + "pmovzxbw\0" + "???\0" + "???", MODRM|VAR_NAME4, PARAM_XMM, PARAM_XMM64, 0 }, + {"???\0" + "pmovzxbd\0" + "???\0" + "???", MODRM|VAR_NAME4, PARAM_XMM, PARAM_XMM32, 0 }, + {"???\0" + "pmovzxbq\0" + "???\0" + "???", MODRM|VAR_NAME4, PARAM_XMM, PARAM_XMM16, 0 }, + {"???\0" + "pmovzxwd\0" + "???\0" + "???", MODRM|VAR_NAME4, PARAM_XMM, PARAM_XMM64, 0 }, + {"???\0" + "pmovzxwq\0" + "???\0" + "???", MODRM|VAR_NAME4, PARAM_XMM, PARAM_XMM32, 0 }, + {"???\0" + "pmovzxdq\0" + "???\0" + "???", MODRM|VAR_NAME4, PARAM_XMM, PARAM_XMM64, 0 }, + {"???", 0, 0, 0, 0 }, + {"???\0" + "pcmpgtq\0" + "???\0" + "???", MODRM|VAR_NAME4, PARAM_XMM, PARAM_XMMM, 0 }, + {"???\0" + "pminsb\0" + "???\0" + "???", MODRM|VAR_NAME4, PARAM_XMM, PARAM_XMMM, 0 }, + {"???\0" + "pminsd\0" + "???\0" + "???", MODRM|VAR_NAME4, PARAM_XMM, PARAM_XMMM, 0 }, + {"???\0" + "pminuw\0" + "???\0" + "???", MODRM|VAR_NAME4, PARAM_XMM, PARAM_XMMM, 0 }, + {"???\0" + "pminud\0" + "???\0" + "???", MODRM|VAR_NAME4, PARAM_XMM, PARAM_XMMM, 0 }, + {"???\0" + "pmaxsb\0" + "???\0" + "???", MODRM|VAR_NAME4, PARAM_XMM, PARAM_XMMM, 0 }, + {"???\0" + "pmaxsd\0" + "???\0" + "???", MODRM|VAR_NAME4, PARAM_XMM, PARAM_XMMM, 0 }, + {"???\0" + "pmaxuw\0" + "???\0" + "???", MODRM|VAR_NAME4, PARAM_XMM, PARAM_XMMM, 0 }, + {"???\0" + "pmaxud\0" + "???\0" + "???", MODRM|VAR_NAME4, PARAM_XMM, PARAM_XMMM, 0 }, + // 0x40 + {"???\0" + "pmulld\0" + "???\0" + "???", MODRM|VAR_NAME4, PARAM_XMM, PARAM_XMMM, 0 }, + {"???\0" + "phminposuw\0" + "???\0" + "???", MODRM|VAR_NAME4, PARAM_XMM, PARAM_XMMM, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + // 0x50 + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + // 0x60 + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + // 0x70 + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + // 0x80 + {"???\0" + "invept\0" + "???\0" + "???", MODRM|VAR_NAME4, PARAM_REG32, PARAM_XMMM, 0 }, + {"???\0" + "invvpid\0" + "???\0" + "???", MODRM|VAR_NAME4, PARAM_REG32, PARAM_XMMM, 0 }, + {"???\0" + "invpcid\0" + "???\0" + "???", MODRM|VAR_NAME4, PARAM_REG32, PARAM_XMMM, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + // 0x90 + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + // 0xa0 + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + // 0xb0 + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + // 0xc0 + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + // 0xd0 + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???\0" + "aesimc\0" + "???\0" + "???", MODRM|VAR_NAME4, PARAM_XMM, PARAM_XMMM, 0 }, + {"???\0" + "aesenc\0" + "???\0" + "???", MODRM|VAR_NAME4, PARAM_XMM, PARAM_XMMM, 0 }, + {"???\0" + "aesenclast\0" + "???\0" + "???", MODRM|VAR_NAME4, PARAM_XMM, PARAM_XMMM, 0 }, + {"???\0" + "aesdec\0" + "???\0" + "???", MODRM|VAR_NAME4, PARAM_XMM, PARAM_XMMM, 0 }, + {"???\0" + "aesdeclast\0" + "???\0" + "???", MODRM|VAR_NAME4, PARAM_XMM, PARAM_XMMM, 0 }, + // 0xe0 + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + // 0xf0 + {"movbe\0" + "???\0" + "crc32\0" + "???", MODRM|VAR_NAME4, PARAM_REG32, PARAM_RMPTR, 0 }, // not quite correct + {"movbe\0" + "???\0" + "crc32\0" + "???", MODRM|VAR_NAME4, PARAM_RMPTR, PARAM_REG32, 0 }, // not quite correct + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, +}; + +static const I386_OPCODE i386_opcode_table0F3A[256] = +{ + // 0x00 + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???\0" + "roundps\0" + "???\0" + "???", MODRM|VAR_NAME4, PARAM_XMM, PARAM_XMMM, PARAM_UI8 }, + {"???\0" + "roundpd\0" + "???\0" + "???", MODRM|VAR_NAME4, PARAM_XMM, PARAM_XMMM, PARAM_UI8 }, + {"???\0" + "roundss\0" + "???\0" + "???", MODRM|VAR_NAME4, PARAM_XMM, PARAM_XMMM, PARAM_UI8 }, + {"???\0" + "roundsd\0" + "???\0" + "???", MODRM|VAR_NAME4, PARAM_XMM, PARAM_XMMM, PARAM_UI8 }, + {"???\0" + "blendps\0" + "???\0" + "???", MODRM|VAR_NAME4, PARAM_XMM, PARAM_XMMM, PARAM_UI8 }, + {"???\0" + "blendpd\0" + "???\0" + "???", MODRM|VAR_NAME4, PARAM_XMM, PARAM_XMMM, PARAM_UI8 }, + {"???\0" + "pblendw\0" + "???\0" + "???", MODRM|VAR_NAME4, PARAM_XMM, PARAM_XMMM, PARAM_UI8 }, + {"palignr\0" + "palignr\0" + "???\0" + "???", MODRM|VAR_NAME4, PARAM_XMM, PARAM_XMMM, PARAM_UI8 }, + // 0x10 + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???\0" + "pextrb\0" + "???\0" + "???", MODRM|VAR_NAME4, PARAM_RM8, PARAM_XMM, PARAM_UI8 }, + {"???\0" + "pextrw\0" + "???\0" + "???", MODRM|VAR_NAME4, PARAM_RM16, PARAM_XMM, PARAM_UI8 }, + {"???\0" + "pextrd\0" + "???\0" + "???", MODRM|VAR_NAME4, PARAM_RM8, PARAM_XMM, PARAM_UI8 }, + {"???\0" + "extractps\0" + "???\0" + "???", MODRM|VAR_NAME4, PARAM_RM32, PARAM_XMM, PARAM_UI8 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + // 0x20 + {"???\0" + "pinsrb\0" + "???\0" + "???", MODRM|VAR_NAME4, PARAM_XMM, PARAM_RM8, PARAM_UI8 }, + {"???\0" + "insertps\0" + "???\0" + "???", MODRM|VAR_NAME4, PARAM_XMM, PARAM_RM8, PARAM_UI8 }, + {"???\0" + "pinsrd\0" + "???\0" + "???", MODRM|VAR_NAME4, PARAM_XMM, PARAM_RM32, PARAM_UI8 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + // 0x30 + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + // 0x40 + {"???\0" + "dpps\0" + "???\0" + "???", MODRM|VAR_NAME4, PARAM_XMM, PARAM_XMMM, PARAM_UI8 }, + {"???\0" + "dppd\0" + "???\0" + "???", MODRM|VAR_NAME4, PARAM_XMM, PARAM_XMMM, PARAM_UI8 }, + {"???\0" + "mpsadbw\0" + "???\0" + "???", MODRM|VAR_NAME4, PARAM_XMM, PARAM_XMMM, PARAM_UI8 }, + {"???", 0, 0, 0, 0 }, + {"???\0" + "pclmulqdq\0" + "???\0" + "???", MODRM|VAR_NAME4, PARAM_XMM, PARAM_XMMM, PARAM_UI8 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + // 0x50 + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + // 0x60 + {"???\0" + "pcmestrm\0" + "???\0" + "???", MODRM|VAR_NAME4, PARAM_XMM, PARAM_XMMM, PARAM_UI8 }, + {"???\0" + "pcmestri\0" + "???\0" + "???", MODRM|VAR_NAME4, PARAM_XMM, PARAM_XMMM, PARAM_UI8 }, + {"???\0" + "pcmistrm\0" + "???\0" + "???", MODRM|VAR_NAME4, PARAM_XMM, PARAM_XMMM, PARAM_UI8 }, + {"???\0" + "pcmistri\0" + "???\0" + "???", MODRM|VAR_NAME4, PARAM_XMM, PARAM_XMMM, PARAM_UI8 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + // 0x70 + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + // 0x80 + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + // 0x90 + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + // 0xa0 + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + // 0xb0 + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + // 0xc0 + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + // 0xd0 + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???\0" + "aeskeygenassist\0" + "???\0" + "???", MODRM|VAR_NAME4, PARAM_XMM, PARAM_XMMM, PARAM_UI8 }, + // 0xe0 + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + // 0xf0 + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, +}; + +static const I386_OPCODE group80_table[8] = +{ + {"add", 0, PARAM_RMPTR8, PARAM_UI8, 0 }, + {"or", 0, PARAM_RMPTR8, PARAM_UI8, 0 }, + {"adc", 0, PARAM_RMPTR8, PARAM_UI8, 0 }, + {"sbb", 0, PARAM_RMPTR8, PARAM_UI8, 0 }, + {"and", 0, PARAM_RMPTR8, PARAM_UI8, 0 }, + {"sub", 0, PARAM_RMPTR8, PARAM_UI8, 0 }, + {"xor", 0, PARAM_RMPTR8, PARAM_UI8, 0 }, + {"cmp", 0, PARAM_RMPTR8, PARAM_UI8, 0 } +}; + +static const I386_OPCODE group81_table[8] = +{ + {"add", 0, PARAM_RMPTR, PARAM_IMM, 0 }, + {"or", 0, PARAM_RMPTR, PARAM_IMM, 0 }, + {"adc", 0, PARAM_RMPTR, PARAM_IMM, 0 }, + {"sbb", 0, PARAM_RMPTR, PARAM_IMM, 0 }, + {"and", 0, PARAM_RMPTR, PARAM_IMM, 0 }, + {"sub", 0, PARAM_RMPTR, PARAM_IMM, 0 }, + {"xor", 0, PARAM_RMPTR, PARAM_IMM, 0 }, + {"cmp", 0, PARAM_RMPTR, PARAM_IMM, 0 } +}; + +static const I386_OPCODE group83_table[8] = +{ + {"add", 0, PARAM_RMPTR, PARAM_I8, 0 }, + {"or", 0, PARAM_RMPTR, PARAM_I8, 0 }, + {"adc", 0, PARAM_RMPTR, PARAM_I8, 0 }, + {"sbb", 0, PARAM_RMPTR, PARAM_I8, 0 }, + {"and", 0, PARAM_RMPTR, PARAM_I8, 0 }, + {"sub", 0, PARAM_RMPTR, PARAM_I8, 0 }, + {"xor", 0, PARAM_RMPTR, PARAM_I8, 0 }, + {"cmp", 0, PARAM_RMPTR, PARAM_I8, 0 } +}; + +static const I386_OPCODE groupC0_table[8] = +{ + {"rol", 0, PARAM_RMPTR8, PARAM_UI8, 0 }, + {"ror", 0, PARAM_RMPTR8, PARAM_UI8, 0 }, + {"rcl", 0, PARAM_RMPTR8, PARAM_UI8, 0 }, + {"rcr", 0, PARAM_RMPTR8, PARAM_UI8, 0 }, + {"shl", 0, PARAM_RMPTR8, PARAM_UI8, 0 }, + {"shr", 0, PARAM_RMPTR8, PARAM_UI8, 0 }, + {"sal", 0, PARAM_RMPTR8, PARAM_UI8, 0 }, + {"sar", 0, PARAM_RMPTR8, PARAM_UI8, 0 } +}; + +static const I386_OPCODE groupC1_table[8] = +{ + {"rol", 0, PARAM_RMPTR, PARAM_UI8, 0 }, + {"ror", 0, PARAM_RMPTR, PARAM_UI8, 0 }, + {"rcl", 0, PARAM_RMPTR, PARAM_UI8, 0 }, + {"rcr", 0, PARAM_RMPTR, PARAM_UI8, 0 }, + {"shl", 0, PARAM_RMPTR, PARAM_UI8, 0 }, + {"shr", 0, PARAM_RMPTR, PARAM_UI8, 0 }, + {"sal", 0, PARAM_RMPTR, PARAM_UI8, 0 }, + {"sar", 0, PARAM_RMPTR, PARAM_UI8, 0 } +}; + +static const I386_OPCODE groupD0_table[8] = +{ + {"rol", 0, PARAM_RMPTR8, PARAM_1, 0 }, + {"ror", 0, PARAM_RMPTR8, PARAM_1, 0 }, + {"rcl", 0, PARAM_RMPTR8, PARAM_1, 0 }, + {"rcr", 0, PARAM_RMPTR8, PARAM_1, 0 }, + {"shl", 0, PARAM_RMPTR8, PARAM_1, 0 }, + {"shr", 0, PARAM_RMPTR8, PARAM_1, 0 }, + {"sal", 0, PARAM_RMPTR8, PARAM_1, 0 }, + {"sar", 0, PARAM_RMPTR8, PARAM_1, 0 } +}; + +static const I386_OPCODE groupD1_table[8] = +{ + {"rol", 0, PARAM_RMPTR, PARAM_1, 0 }, + {"ror", 0, PARAM_RMPTR, PARAM_1, 0 }, + {"rcl", 0, PARAM_RMPTR, PARAM_1, 0 }, + {"rcr", 0, PARAM_RMPTR, PARAM_1, 0 }, + {"shl", 0, PARAM_RMPTR, PARAM_1, 0 }, + {"shr", 0, PARAM_RMPTR, PARAM_1, 0 }, + {"sal", 0, PARAM_RMPTR, PARAM_1, 0 }, + {"sar", 0, PARAM_RMPTR, PARAM_1, 0 } +}; + +static const I386_OPCODE groupD2_table[8] = +{ + {"rol", 0, PARAM_RMPTR8, PARAM_CL, 0 }, + {"ror", 0, PARAM_RMPTR8, PARAM_CL, 0 }, + {"rcl", 0, PARAM_RMPTR8, PARAM_CL, 0 }, + {"rcr", 0, PARAM_RMPTR8, PARAM_CL, 0 }, + {"shl", 0, PARAM_RMPTR8, PARAM_CL, 0 }, + {"shr", 0, PARAM_RMPTR8, PARAM_CL, 0 }, + {"sal", 0, PARAM_RMPTR8, PARAM_CL, 0 }, + {"sar", 0, PARAM_RMPTR8, PARAM_CL, 0 } +}; + +static const I386_OPCODE groupD3_table[8] = +{ + {"rol", 0, PARAM_RMPTR, PARAM_CL, 0 }, + {"ror", 0, PARAM_RMPTR, PARAM_CL, 0 }, + {"rcl", 0, PARAM_RMPTR, PARAM_CL, 0 }, + {"rcr", 0, PARAM_RMPTR, PARAM_CL, 0 }, + {"shl", 0, PARAM_RMPTR, PARAM_CL, 0 }, + {"shr", 0, PARAM_RMPTR, PARAM_CL, 0 }, + {"sal", 0, PARAM_RMPTR, PARAM_CL, 0 }, + {"sar", 0, PARAM_RMPTR, PARAM_CL, 0 } +}; + +static const I386_OPCODE groupF6_table[8] = +{ + {"test", 0, PARAM_RMPTR8, PARAM_UI8, 0 }, + {"test", 0, PARAM_RMPTR8, PARAM_UI8, 0 }, + {"not", 0, PARAM_RMPTR8, 0, 0 }, + {"neg", 0, PARAM_RMPTR8, 0, 0 }, + {"mul", 0, PARAM_RMPTR8, 0, 0 }, + {"imul", 0, PARAM_RMPTR8, 0, 0 }, + {"div", 0, PARAM_RMPTR8, 0, 0 }, + {"idiv", 0, PARAM_RMPTR8, 0, 0 } +}; + +static const I386_OPCODE groupF7_table[8] = +{ + {"test", 0, PARAM_RMPTR, PARAM_IMM, 0 }, + {"test", 0, PARAM_RMPTR, PARAM_IMM, 0 }, + {"not", 0, PARAM_RMPTR, 0, 0 }, + {"neg", 0, PARAM_RMPTR, 0, 0 }, + {"mul", 0, PARAM_RMPTR, 0, 0 }, + {"imul", 0, PARAM_RMPTR, 0, 0 }, + {"div", 0, PARAM_RMPTR, 0, 0 }, + {"idiv", 0, PARAM_RMPTR, 0, 0 } +}; + +static const I386_OPCODE groupFE_table[8] = +{ + {"inc", 0, PARAM_RMPTR8, 0, 0 }, + {"dec", 0, PARAM_RMPTR8, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 } +}; + +static const I386_OPCODE groupFF_table[8] = +{ + {"inc", 0, PARAM_RMPTR, 0, 0 }, + {"dec", 0, PARAM_RMPTR, 0, 0 }, + {"call", ALWAYS64, PARAM_RMPTR, 0, 0, DASMFLAG_STEP_OVER}, + {"call far ptr ",0, PARAM_RM, 0, 0, DASMFLAG_STEP_OVER}, + {"jmp", ALWAYS64, PARAM_RMPTR, 0, 0 }, + {"jmp far ptr ",0, PARAM_RM, 0, 0 }, + {"push", 0, PARAM_RMPTR, 0, 0 }, + {"???", 0, 0, 0, 0 } +}; + +static const I386_OPCODE group0F00_table[8] = +{ + {"sldt", 0, PARAM_RM, 0, 0 }, + {"str", 0, PARAM_RM, 0, 0 }, + {"lldt", 0, PARAM_RM, 0, 0 }, + {"ltr", 0, PARAM_RM, 0, 0 }, + {"verr", 0, PARAM_RM, 0, 0 }, + {"verw", 0, PARAM_RM, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 } +}; + +static const I386_OPCODE group0F01_table[8] = +{ + {"sgdt", 0, PARAM_RM, 0, 0 }, + {"sidt", 0, PARAM_RM, 0, 0 }, + {"lgdt", 0, PARAM_RM, 0, 0 }, + {"lidt", 0, PARAM_RM, 0, 0 }, + {"smsw", 0, PARAM_RM, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"lmsw", 0, PARAM_RM, 0, 0 }, + {"invlpg", 0, PARAM_RM, 0, 0 } +}; + +static const I386_OPCODE group0F0D_table[8] = +{ + {"prefetch", 0, PARAM_RM8, 0, 0 }, + {"prefetchw", 0, PARAM_RM8, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 } +}; + +static const I386_OPCODE group0F12_table[4] = +{ + { "movlps\0" + "movlpd\0" + "movddup\0" + "movsldup", VAR_NAME4,PARAM_XMM, PARAM_XMMM, 0 }, + { "movlps\0" + "movlpd\0" + "movddup\0" + "movsldup", VAR_NAME4,PARAM_XMM, PARAM_XMMM, 0 }, + { "movlps\0" + "movlpd\0" + "movddup\0" + "movsldup", VAR_NAME4,PARAM_XMM, PARAM_XMMM, 0 }, + { "movhlps\0" + "???\0" + "movddup\0" + "movsldup", VAR_NAME4,PARAM_XMM, PARAM_XMMM, 0 } +}; + +static const I386_OPCODE group0F16_table[4] = +{ + { "movhps\0" + "movhpd\0" + "???\0" + "movshdup", VAR_NAME4,PARAM_XMM, PARAM_XMMM, 0 }, + { "movhps\0" + "movhpd\0" + "???\0" + "movshdup", VAR_NAME4,PARAM_XMM, PARAM_XMMM, 0 }, + { "movhps\0" + "movhpd\0" + "???\0" + "movshdup", VAR_NAME4,PARAM_XMM, PARAM_XMMM, 0 }, + { "movlhps\0" + "movhpd\0" + "???\0" + "movshdup", VAR_NAME4,PARAM_XMM, PARAM_XMMM, 0 } +}; + +static const I386_OPCODE group0F18_table[8] = +{ + {"prefetchnta", 0, PARAM_RM8, 0, 0 }, + {"prefetch0", 0, PARAM_RM8, 0, 0 }, + {"prefetch1", 0, PARAM_RM8, 0, 0 }, + {"prefetch2", 0, PARAM_RM8, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 } +}; + +static const I386_OPCODE group0F71_table[8] = +{ + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"psrlw", 0, PARAM_MMX2, PARAM_UI8, 0 }, + {"???", 0, 0, 0, 0 }, + {"psraw", 0, PARAM_MMX2, PARAM_UI8, 0 }, + {"???", 0, 0, 0, 0 }, + {"psllw", 0, PARAM_MMX2, PARAM_UI8, 0 }, + {"???", 0, 0, 0, 0 } +}; + +static const I386_OPCODE group0F72_table[8] = +{ + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"psrld", 0, PARAM_MMX2, PARAM_UI8, 0 }, + {"???", 0, 0, 0, 0 }, + {"psrad", 0, PARAM_MMX2, PARAM_UI8, 0 }, + {"???", 0, 0, 0, 0 }, + {"pslld", 0, PARAM_MMX2, PARAM_UI8, 0 }, + {"???", 0, 0, 0, 0 } +}; + +static const I386_OPCODE group0F73_table[8] = +{ + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"psrlq", 0, PARAM_MMX2, PARAM_UI8, 0 }, + {"psrldq", 0, PARAM_MMX2, PARAM_UI8, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"psllq", 0, PARAM_MMX2, PARAM_UI8, 0 }, + {"pslldq", 0, PARAM_MMX2, PARAM_UI8, 0 }, +}; + +static const I386_OPCODE group0FAE_table[8] = +{ + {"fxsave", 0, PARAM_RM, 0, 0 }, + {"fxrstor", 0, PARAM_RM, 0, 0 }, + {"ldmxcsr", 0, PARAM_RM, 0, 0 }, + {"stmxscr", 0, PARAM_RM, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"lfence", 0, 0, 0, 0 }, + {"mfence", 0, 0, 0, 0 }, + {"sfence", 0, 0, 0, 0 } +}; + + +static const I386_OPCODE group0FBA_table[8] = +{ + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"bt", 0, PARAM_RM, PARAM_UI8, 0 }, + {"bts", 0, PARAM_RM, PARAM_UI8, 0 }, + {"btr", 0, PARAM_RM, PARAM_UI8, 0 }, + {"btc", 0, PARAM_RM, PARAM_UI8, 0 } +}; + +static const I386_OPCODE group0FC7_table[8] = +{ + {"???", 0, 0, 0, 0 }, + {"cmpxchg8b", MODRM, PARAM_M64PTR, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"vmptrld\0" + "vmclear\0" + "???\0" + "vmxon", MODRM|VAR_NAME4, PARAM_M64PTR, 0, 0 }, + {"vmptrtst", MODRM, PARAM_M64PTR, 0, 0 } +}; + +static const GROUP_OP group_op_table[] = +{ + { "group80", group80_table }, + { "group81", group81_table }, + { "group83", group83_table }, + { "groupC0", groupC0_table }, + { "groupC1", groupC1_table }, + { "groupD0", groupD0_table }, + { "groupD1", groupD1_table }, + { "groupD2", groupD2_table }, + { "groupD3", groupD3_table }, + { "groupF6", groupF6_table }, + { "groupF7", groupF7_table }, + { "groupFE", groupFE_table }, + { "groupFF", groupFF_table }, + { "group0F00", group0F00_table }, + { "group0F01", group0F01_table }, + { "group0F0D", group0F0D_table }, + { "group0F12", group0F12_table }, + { "group0F16", group0F16_table }, + { "group0F18", group0F18_table }, + { "group0F71", group0F71_table }, + { "group0F72", group0F72_table }, + { "group0F73", group0F73_table }, + { "group0FAE", group0FAE_table }, + { "group0FBA", group0FBA_table }, + { "group0FC7", group0FC7_table } +}; + + + +static const char *const i386_reg[3][16] = +{ + {"ax", "cx", "dx", "bx", "sp", "bp", "si", "di", "r8w", "r9w", "r10w","r11w","r12w","r13w","r14w","r15w"}, + {"eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi", "r8d", "r9d", "r10d","r11d","r12d","r13d","r14d","r15d"}, + {"rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"} +}; + +static const char *const i386_reg8[8] = {"al", "cl", "dl", "bl", "ah", "ch", "dh", "bh"}; +static const char *const i386_reg8rex[16] = {"al", "cl", "dl", "bl", "spl", "bpl", "sil", "dil", "r8l", "r9l", "r10l", "r11l", "r12l", "r13l", "r14l", "r15l"}; +static const char *const i386_sreg[8] = {"es", "cs", "ss", "ds", "fs", "gs", "???", "???"}; + +static int address_size; +static int operand_size; +static int address_prefix; +static int operand_prefix; +static int max_length; +static UINT64 pc; +static UINT8 modrm; +static UINT32 segment; +static offs_t dasm_flags; +static char modrm_string[256]; +static UINT8 rex, regex, sibex, rmex; +static UINT8 pre0f; +static UINT8 curmode; + +#define MODRM_REG1 ((modrm >> 3) & 0x7) +#define MODRM_REG2 (modrm & 0x7) +#define MODRM_MOD ((modrm >> 6) & 0x3) + +INLINE UINT8 FETCH(void) +{ + if ((opcode_ptr - opcode_ptr_base) + 1 > max_length) + return 0xff; + pc++; + return *opcode_ptr++; +} + +#if 0 +INLINE UINT16 FETCH16(void) +{ + UINT16 d; + if ((opcode_ptr - opcode_ptr_base) + 2 > max_length) + return 0xffff; + d = opcode_ptr[0] | (opcode_ptr[1] << 8); + opcode_ptr += 2; + pc += 2; + return d; +} +#endif + +INLINE UINT32 FETCH32(void) +{ + UINT32 d; + if ((opcode_ptr - opcode_ptr_base) + 4 > max_length) + return 0xffffffff; + d = opcode_ptr[0] | (opcode_ptr[1] << 8) | (opcode_ptr[2] << 16) | (opcode_ptr[3] << 24); + opcode_ptr += 4; + pc += 4; + return d; +} + +INLINE UINT8 FETCHD(void) +{ + if ((opcode_ptr - opcode_ptr_base) + 1 > max_length) + return 0xff; + pc++; + return *opcode_ptr++; +} + +INLINE UINT16 FETCHD16(void) +{ + UINT16 d; + if ((opcode_ptr - opcode_ptr_base) + 2 > max_length) + return 0xffff; + d = opcode_ptr[0] | (opcode_ptr[1] << 8); + opcode_ptr += 2; + pc += 2; + return d; +} + +INLINE UINT32 FETCHD32(void) +{ + UINT32 d; + if ((opcode_ptr - opcode_ptr_base) + 4 > max_length) + return 0xffffffff; + d = opcode_ptr[0] | (opcode_ptr[1] << 8) | (opcode_ptr[2] << 16) | (opcode_ptr[3] << 24); + opcode_ptr += 4; + pc += 4; + return d; +} + +static char *hexstring(UINT32 value, int digits) +{ + static char buffer[20]; + buffer[0] = '0'; + if (digits) + sprintf(&buffer[1], "%0*Xh", digits, value); + else + sprintf(&buffer[1], "%Xh", value); + return (buffer[1] >= '0' && buffer[1] <= '9') ? &buffer[1] : &buffer[0]; +} + +static char *hexstring64(UINT32 lo, UINT32 hi) +{ + static char buffer[40]; + buffer[0] = '0'; + if (hi != 0) + sprintf(&buffer[1], "%X%08Xh", hi, lo); + else + sprintf(&buffer[1], "%Xh", lo); + return (buffer[1] >= '0' && buffer[1] <= '9') ? &buffer[1] : &buffer[0]; +} + +static char *hexstringpc(UINT64 pc) +{ + if (curmode == 64) + return hexstring64((UINT32)pc, (UINT32)(pc >> 32)); + else + return hexstring((UINT32)pc, 0); +} + +static char *shexstring(UINT32 value, int digits, int always) +{ + static char buffer[20]; + if (value >= 0x80000000) + sprintf(buffer, "-%s", hexstring(-value, digits)); + else if (always) + sprintf(buffer, "+%s", hexstring(value, digits)); + else + return hexstring(value, digits); + return buffer; +} + +static char* handle_sib_byte( char* s, UINT8 mod ) +{ + UINT32 i32; + UINT8 scale, i, base; + UINT8 sib = FETCHD(); + + scale = (sib >> 6) & 0x3; + i = ((sib >> 3) & 0x7) | sibex; + base = (sib & 0x7) | rmex; + + if (base == 5 && mod == 0) { + i32 = FETCH32(); + s += sprintf( s, "%s", hexstring(i32, 0) ); + } else if (base != 5 || mod != 3) + s += sprintf( s, "%s", i386_reg[address_size][base] ); + + if ( i != 4 ) { + s += sprintf( s, "+%s", i386_reg[address_size][i] ); + if (scale) + s += sprintf( s, "*%d", 1 << scale ); + } + return s; +} + +static void handle_modrm(char* s) +{ + INT8 disp8; + INT16 disp16; + INT32 disp32; + UINT8 mod, rm; + + modrm = FETCHD(); + mod = (modrm >> 6) & 0x3; + rm = (modrm & 0x7) | rmex; + + if( modrm >= 0xc0 ) + return; + + switch(segment) + { + case SEG_CS: s += sprintf( s, "cs:" ); break; + case SEG_DS: s += sprintf( s, "ds:" ); break; + case SEG_ES: s += sprintf( s, "es:" ); break; + case SEG_FS: s += sprintf( s, "fs:" ); break; + case SEG_GS: s += sprintf( s, "gs:" ); break; + case SEG_SS: s += sprintf( s, "ss:" ); break; + } + + s += sprintf( s, "[" ); + if( address_size == 2 ) { + if ((rm & 7) == 4) + s = handle_sib_byte( s, mod ); + else if ((rm & 7) == 5 && mod == 0) { + disp32 = FETCHD32(); + s += sprintf( s, "rip%s", shexstring(disp32, 0, TRUE) ); + } else + s += sprintf( s, "%s", i386_reg[2][rm]); + if( mod == 1 ) { + disp8 = FETCHD(); + if (disp8 != 0) + s += sprintf( s, "%s", shexstring((INT32)disp8, 0, TRUE) ); + } else if( mod == 2 ) { + disp32 = FETCHD32(); + if (disp32 != 0) + s += sprintf( s, "%s", shexstring(disp32, 0, TRUE) ); + } + } else if (address_size == 1) { + if ((rm & 7) == 4) + s = handle_sib_byte( s, mod ); + else if ((rm & 7) == 5 && mod == 0) { + disp32 = FETCHD32(); + if (curmode == 64) + s += sprintf( s, "eip%s", shexstring(disp32, 0, TRUE) ); + else + s += sprintf( s, "%s", hexstring(disp32, 0) ); + } else + s += sprintf( s, "%s", i386_reg[1][rm]); + if( mod == 1 ) { + disp8 = FETCHD(); + if (disp8 != 0) + s += sprintf( s, "%s", shexstring((INT32)disp8, 0, TRUE) ); + } else if( mod == 2 ) { + disp32 = FETCHD32(); + if (disp32 != 0) + s += sprintf( s, "%s", shexstring(disp32, 0, TRUE) ); + } + } else { + switch( rm ) + { + case 0: s += sprintf( s, "bx+si" ); break; + case 1: s += sprintf( s, "bx+di" ); break; + case 2: s += sprintf( s, "bp+si" ); break; + case 3: s += sprintf( s, "bp+di" ); break; + case 4: s += sprintf( s, "si" ); break; + case 5: s += sprintf( s, "di" ); break; + case 6: + if( mod == 0 ) { + disp16 = FETCHD16(); + s += sprintf( s, "%s", hexstring((unsigned) (UINT16) disp16, 0) ); + } else { + s += sprintf( s, "bp" ); + } + break; + case 7: s += sprintf( s, "bx" ); break; + } + if( mod == 1 ) { + disp8 = FETCHD(); + if (disp8 != 0) + s += sprintf( s, "%s", shexstring((INT32)disp8, 0, TRUE) ); + } else if( mod == 2 ) { + disp16 = FETCHD16(); + if (disp16 != 0) + s += sprintf( s, "%s", shexstring((INT32)disp16, 0, TRUE) ); + } + } + s += sprintf( s, "]" ); +} + +static char* handle_param(char* s, UINT32 param) +{ + UINT8 i8; + UINT16 i16; + UINT32 i32; + UINT16 ptr; + UINT32 addr; + INT8 d8; + INT16 d16; + INT32 d32; + + switch(param) + { + case PARAM_REG: + s += sprintf( s, "%s", i386_reg[operand_size][MODRM_REG1 | regex] ); + break; + + case PARAM_REG8: + s += sprintf( s, "%s", (rex ? i386_reg8rex : i386_reg8)[MODRM_REG1 | regex] ); + break; + + case PARAM_REG16: + s += sprintf( s, "%s", i386_reg[0][MODRM_REG1 | regex] ); + break; + + case PARAM_REG32: + s += sprintf( s, "%s", i386_reg[1][MODRM_REG1 | regex] ); + break; + + case PARAM_REG3264: + s += sprintf( s, "%s", i386_reg[(operand_size == 2) ? 2 : 1][MODRM_REG1 | regex] ); + break; + + case PARAM_MMX: + if (pre0f == 0x66 || pre0f == 0xf2 || pre0f == 0xf3) + s += sprintf( s, "xmm%d", MODRM_REG1 | regex ); + else + s += sprintf( s, "mm%d", MODRM_REG1 | regex ); + break; + + case PARAM_MMX2: + if (pre0f == 0x66 || pre0f == 0xf2 || pre0f == 0xf3) + s += sprintf( s, "xmm%d", MODRM_REG2 | regex ); + else + s += sprintf( s, "mm%d", MODRM_REG2 | regex ); + break; + + case PARAM_XMM: + s += sprintf( s, "xmm%d", MODRM_REG1 | regex ); + break; + + case PARAM_REGORXMM: + if (pre0f != 0xf2 && pre0f != 0xf3) + s += sprintf( s, "xmm%d", MODRM_REG1 | regex ); + else + s += sprintf( s, "%s", i386_reg[(operand_size == 2) ? 2 : 1][MODRM_REG1 | regex] ); + break; + + case PARAM_REG2_32: + s += sprintf( s, "%s", i386_reg[1][MODRM_REG2 | rmex] ); + break; + + case PARAM_RM: + case PARAM_RMPTR: + if( modrm >= 0xc0 ) { + s += sprintf( s, "%s", i386_reg[operand_size][MODRM_REG2 | rmex] ); + } else { + if (param == PARAM_RMPTR) + { + if( operand_size == 2 ) + s += sprintf( s, "qword ptr " ); + else if (operand_size == 1) + s += sprintf( s, "dword ptr " ); + else + s += sprintf( s, "word ptr " ); + } + s += sprintf( s, "%s", modrm_string ); + } + break; + + case PARAM_RM8: + case PARAM_RMPTR8: + if( modrm >= 0xc0 ) { + s += sprintf( s, "%s", (rex ? i386_reg8rex : i386_reg8)[MODRM_REG2 | rmex] ); + } else { + if (param == PARAM_RMPTR8) + s += sprintf( s, "byte ptr " ); + s += sprintf( s, "%s", modrm_string ); + } + break; + + case PARAM_RM16: + case PARAM_RMPTR16: + if( modrm >= 0xc0 ) { + s += sprintf( s, "%s", i386_reg[0][MODRM_REG2 | rmex] ); + } else { + if (param == PARAM_RMPTR16) + s += sprintf( s, "word ptr " ); + s += sprintf( s, "%s", modrm_string ); + } + break; + + case PARAM_RM32: + case PARAM_RMPTR32: + if( modrm >= 0xc0 ) { + s += sprintf( s, "%s", i386_reg[1][MODRM_REG2 | rmex] ); + } else { + if (param == PARAM_RMPTR32) + s += sprintf( s, "dword ptr " ); + s += sprintf( s, "%s", modrm_string ); + } + break; + + case PARAM_RMXMM: + if( modrm >= 0xc0 ) { + if (pre0f != 0xf2 && pre0f != 0xf3) + s += sprintf( s, "xmm%d", MODRM_REG2 | rmex ); + else + s += sprintf( s, "%s", i386_reg[(operand_size == 2) ? 2 : 1][MODRM_REG2 | rmex] ); + } else { + if (param == PARAM_RMPTR32) + s += sprintf( s, "dword ptr " ); + s += sprintf( s, "%s", modrm_string ); + } + break; + + case PARAM_M64: + case PARAM_M64PTR: + if( modrm >= 0xc0 ) { + s += sprintf( s, "???" ); + } else { + if (param == PARAM_M64PTR) + s += sprintf( s, "qword ptr " ); + s += sprintf( s, "%s", modrm_string ); + } + break; + + case PARAM_MMXM: + if( modrm >= 0xc0 ) { + if (pre0f == 0x66 || pre0f == 0xf2 || pre0f == 0xf3) + s += sprintf( s, "xmm%d", MODRM_REG2 | rmex ); + else + s += sprintf( s, "mm%d", MODRM_REG2 | rmex ); + } else { + s += sprintf( s, "%s", modrm_string ); + } + break; + + case PARAM_XMMM: + if( modrm >= 0xc0 ) { + s += sprintf( s, "xmm%d", MODRM_REG2 | rmex ); + } else { + s += sprintf( s, "%s", modrm_string ); + } + break; + + case PARAM_I4: + i8 = FETCHD(); + s += sprintf( s, "%d", i8 & 0x0f ); + break; + + case PARAM_I8: + i8 = FETCHD(); + s += sprintf( s, "%s", shexstring((INT8)i8, 0, FALSE) ); + break; + + case PARAM_I16: + i16 = FETCHD16(); + s += sprintf( s, "%s", shexstring((INT16)i16, 0, FALSE) ); + break; + + case PARAM_UI8: + i8 = FETCHD(); + s += sprintf( s, "%s", shexstring((UINT8)i8, 0, FALSE) ); + break; + + case PARAM_UI16: + i16 = FETCHD16(); + s += sprintf( s, "%s", shexstring((UINT16)i16, 0, FALSE) ); + break; + + case PARAM_IMM64: + if (operand_size == 2) { + UINT32 lo32 = FETCHD32(); + i32 = FETCHD32(); + s += sprintf( s, "%s", hexstring64(lo32, i32) ); + } else if( operand_size ) { + i32 = FETCHD32(); + s += sprintf( s, "%s", hexstring(i32, 0) ); + } else { + i16 = FETCHD16(); + s += sprintf( s, "%s", hexstring(i16, 0) ); + } + break; + + case PARAM_IMM: + if( operand_size ) { + i32 = FETCHD32(); + s += sprintf( s, "%s", hexstring(i32, 0) ); + } else { + i16 = FETCHD16(); + s += sprintf( s, "%s", hexstring(i16, 0) ); + } + break; + + case PARAM_ADDR: + if( operand_size ) { + addr = FETCHD32(); + ptr = FETCHD16(); + s += sprintf( s, "%s:", hexstring(ptr, 4) ); + s += sprintf( s, "%s", hexstring(addr, 0) ); + } else { + addr = FETCHD16(); + ptr = FETCHD16(); + s += sprintf( s, "%s:", hexstring(ptr, 4) ); + s += sprintf( s, "%s", hexstring(addr, 0) ); + } + break; + + case PARAM_REL: + if( operand_size ) { + d32 = FETCHD32(); + s += sprintf( s, "%s", hexstringpc(pc + d32) ); + } else { + /* make sure to keep the relative offset within the segment */ + d16 = FETCHD16(); + s += sprintf( s, "%s", hexstringpc((pc & 0xFFFF0000) | ((pc + d16) & 0x0000FFFF)) ); + } + break; + + case PARAM_REL8: + d8 = FETCHD(); + s += sprintf( s, "%s", hexstringpc(pc + d8) ); + break; + + case PARAM_MEM_OFFS: + switch(segment) + { + case SEG_CS: s += sprintf( s, "cs:" ); break; + case SEG_DS: s += sprintf( s, "ds:" ); break; + case SEG_ES: s += sprintf( s, "es:" ); break; + case SEG_FS: s += sprintf( s, "fs:" ); break; + case SEG_GS: s += sprintf( s, "gs:" ); break; + case SEG_SS: s += sprintf( s, "ss:" ); break; + } + + if( address_size ) { + i32 = FETCHD32(); + s += sprintf( s, "[%s]", hexstring(i32, 0) ); + } else { + i16 = FETCHD16(); + s += sprintf( s, "[%s]", hexstring(i16, 0) ); + } + break; + + case PARAM_PREIMP: + switch(segment) + { + case SEG_CS: s += sprintf( s, "cs:" ); break; + case SEG_DS: s += sprintf( s, "ds:" ); break; + case SEG_ES: s += sprintf( s, "es:" ); break; + case SEG_FS: s += sprintf( s, "fs:" ); break; + case SEG_GS: s += sprintf( s, "gs:" ); break; + case SEG_SS: s += sprintf( s, "ss:" ); break; + } + break; + + case PARAM_SREG: + s += sprintf( s, "%s", i386_sreg[MODRM_REG1] ); + break; + + case PARAM_CREG: + s += sprintf( s, "cr%d", MODRM_REG1 | regex ); + break; + + case PARAM_TREG: + s += sprintf( s, "tr%d", MODRM_REG1 | regex ); + break; + + case PARAM_DREG: + s += sprintf( s, "dr%d", MODRM_REG1 | regex ); + break; + + case PARAM_1: + s += sprintf( s, "1" ); + break; + + case PARAM_DX: + s += sprintf( s, "dx" ); + break; + + case PARAM_XMM0: + s += sprintf( s, "xmm0" ); + break; + + case PARAM_AL: s += sprintf( s, "al" ); break; + case PARAM_CL: s += sprintf( s, "cl" ); break; + case PARAM_DL: s += sprintf( s, "dl" ); break; + case PARAM_BL: s += sprintf( s, "bl" ); break; + case PARAM_AH: s += sprintf( s, "ah" ); break; + case PARAM_CH: s += sprintf( s, "ch" ); break; + case PARAM_DH: s += sprintf( s, "dh" ); break; + case PARAM_BH: s += sprintf( s, "bh" ); break; + + case PARAM_EAX: s += sprintf( s, "%s", i386_reg[operand_size][0 | rmex] ); break; + case PARAM_ECX: s += sprintf( s, "%s", i386_reg[operand_size][1 | rmex] ); break; + case PARAM_EDX: s += sprintf( s, "%s", i386_reg[operand_size][2 | rmex] ); break; + case PARAM_EBX: s += sprintf( s, "%s", i386_reg[operand_size][3 | rmex] ); break; + case PARAM_ESP: s += sprintf( s, "%s", i386_reg[operand_size][4 | rmex] ); break; + case PARAM_EBP: s += sprintf( s, "%s", i386_reg[operand_size][5 | rmex] ); break; + case PARAM_ESI: s += sprintf( s, "%s", i386_reg[operand_size][6 | rmex] ); break; + case PARAM_EDI: s += sprintf( s, "%s", i386_reg[operand_size][7 | rmex] ); break; + } + return s; +} + +static void handle_fpu(char *s, UINT8 op1, UINT8 op2) +{ + switch (op1 & 0x7) + { + case 0: // Group D8 + { + if (op2 < 0xc0) + { + pc--; // adjust fetch pointer, so modrm byte read again + opcode_ptr--; + handle_modrm( modrm_string ); + switch ((op2 >> 3) & 0x7) + { + case 0: sprintf(s, "fadd dword ptr %s", modrm_string); break; + case 1: sprintf(s, "fmul dword ptr %s", modrm_string); break; + case 2: sprintf(s, "fcom dword ptr %s", modrm_string); break; + case 3: sprintf(s, "fcomp dword ptr %s", modrm_string); break; + case 4: sprintf(s, "fsub dword ptr %s", modrm_string); break; + case 5: sprintf(s, "fsubr dword ptr %s", modrm_string); break; + case 6: sprintf(s, "fdiv dword ptr %s", modrm_string); break; + case 7: sprintf(s, "fdivr dword ptr %s", modrm_string); break; + } + } + else + { + switch ((op2 >> 3) & 0x7) + { + case 0: sprintf(s, "fadd st(0),st(%d)", op2 & 0x7); break; + case 1: sprintf(s, "fmul st(0),st(%d)", op2 & 0x7); break; + case 2: sprintf(s, "fcom st(0),st(%d)", op2 & 0x7); break; + case 3: sprintf(s, "fcomp st(0),st(%d)", op2 & 0x7); break; + case 4: sprintf(s, "fsub st(0),st(%d)", op2 & 0x7); break; + case 5: sprintf(s, "fsubr st(0),st(%d)", op2 & 0x7); break; + case 6: sprintf(s, "fdiv st(0),st(%d)", op2 & 0x7); break; + case 7: sprintf(s, "fdivr st(0),st(%d)", op2 & 0x7); break; + } + } + break; + } + + case 1: // Group D9 + { + if (op2 < 0xc0) + { + pc--; // adjust fetch pointer, so modrm byte read again + opcode_ptr--; + handle_modrm( modrm_string ); + switch ((op2 >> 3) & 0x7) + { + case 0: sprintf(s, "fld dword ptr %s", modrm_string); break; + case 1: sprintf(s, "??? (FPU)"); break; + case 2: sprintf(s, "fst dword ptr %s", modrm_string); break; + case 3: sprintf(s, "fstp dword ptr %s", modrm_string); break; + case 4: sprintf(s, "fldenv word ptr %s", modrm_string); break; + case 5: sprintf(s, "fldcw word ptr %s", modrm_string); break; + case 6: sprintf(s, "fstenv word ptr %s", modrm_string); break; + case 7: sprintf(s, "fstcw word ptr %s", modrm_string); break; + } + } + else + { + switch (op2 & 0x3f) + { + case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: + sprintf(s, "fld st(0),st(%d)", op2 & 0x7); break; + + case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f: + sprintf(s, "fxch st(0),st(%d)", op2 & 0x7); break; + + case 0x10: sprintf(s, "fnop"); break; + case 0x20: sprintf(s, "fchs"); break; + case 0x21: sprintf(s, "fabs"); break; + case 0x24: sprintf(s, "ftst"); break; + case 0x25: sprintf(s, "fxam"); break; + case 0x28: sprintf(s, "fld1"); break; + case 0x29: sprintf(s, "fldl2t"); break; + case 0x2a: sprintf(s, "fldl2e"); break; + case 0x2b: sprintf(s, "fldpi"); break; + case 0x2c: sprintf(s, "fldlg2"); break; + case 0x2d: sprintf(s, "fldln2"); break; + case 0x2e: sprintf(s, "fldz"); break; + case 0x30: sprintf(s, "f2xm1"); break; + case 0x31: sprintf(s, "fyl2x"); break; + case 0x32: sprintf(s, "fptan"); break; + case 0x33: sprintf(s, "fpatan"); break; + case 0x34: sprintf(s, "fxtract"); break; + case 0x35: sprintf(s, "fprem1"); break; + case 0x36: sprintf(s, "fdecstp"); break; + case 0x37: sprintf(s, "fincstp"); break; + case 0x38: sprintf(s, "fprem"); break; + case 0x39: sprintf(s, "fyl2xp1"); break; + case 0x3a: sprintf(s, "fsqrt"); break; + case 0x3b: sprintf(s, "fsincos"); break; + case 0x3c: sprintf(s, "frndint"); break; + case 0x3d: sprintf(s, "fscale"); break; + case 0x3e: sprintf(s, "fsin"); break; + case 0x3f: sprintf(s, "fcos"); break; + + default: sprintf(s, "??? (FPU)"); break; + } + } + break; + } + + case 2: // Group DA + { + if (op2 < 0xc0) + { + pc--; // adjust fetch pointer, so modrm byte read again + opcode_ptr--; + handle_modrm( modrm_string ); + switch ((op2 >> 3) & 0x7) + { + case 0: sprintf(s, "fiadd dword ptr %s", modrm_string); break; + case 1: sprintf(s, "fimul dword ptr %s", modrm_string); break; + case 2: sprintf(s, "ficom dword ptr %s", modrm_string); break; + case 3: sprintf(s, "ficomp dword ptr %s", modrm_string); break; + case 4: sprintf(s, "fisub dword ptr %s", modrm_string); break; + case 5: sprintf(s, "fisubr dword ptr %s", modrm_string); break; + case 6: sprintf(s, "fidiv dword ptr %s", modrm_string); break; + case 7: sprintf(s, "fidivr dword ptr %s", modrm_string); break; + } + } + else + { + switch (op2 & 0x3f) + { + case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: + sprintf(s, "fcmovb st(0),st(%d)", op2 & 0x7); break; + + case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f: + sprintf(s, "fcmove st(0),st(%d)", op2 & 0x7); break; + + case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17: + sprintf(s, "fcmovbe st(0),st(%d)", op2 & 0x7); break; + + case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f: + sprintf(s, "fcmovu st(0),st(%d)", op2 & 0x7); break; + case 0x29: + sprintf(s, "fucompp"); break; + + default: sprintf(s, "??? (FPU)"); break; + + } + } + break; + } + + case 3: // Group DB + { + if (op2 < 0xc0) + { + pc--; // adjust fetch pointer, so modrm byte read again + opcode_ptr--; + handle_modrm( modrm_string ); + switch ((op2 >> 3) & 0x7) + { + case 0: sprintf(s, "fild dword ptr %s", modrm_string); break; + case 1: sprintf(s, "fisttp dword ptr %s", modrm_string); break; + case 2: sprintf(s, "fist dword ptr %s", modrm_string); break; + case 3: sprintf(s, "fistp dword ptr %s", modrm_string); break; + case 4: sprintf(s, "??? (FPU)"); break; + case 5: sprintf(s, "fld tword ptr %s", modrm_string); break; + case 6: sprintf(s, "??? (FPU)"); break; + case 7: sprintf(s, "fstp tword ptr %s", modrm_string); break; + } + } + else + { + switch (op2 & 0x3f) + { + case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: + sprintf(s, "fcmovnb st(0),st(%d)", op2 & 0x7); break; + + case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f: + sprintf(s, "fcmovne st(0),st(%d)", op2 & 0x7); break; + + case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17: + sprintf(s, "fcmovnbe st(0),st(%d)", op2 & 0x7); break; + + case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f: + sprintf(s, "fcmovnu st(0),st(%d)", op2 & 0x7); break; + + case 0x22: sprintf(s, "fclex"); break; + case 0x23: sprintf(s, "finit"); break; + + case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: case 0x2f: + sprintf(s, "fucomi st(0),st(%d)", op2 & 0x7); break; + + case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37: + sprintf(s, "fcomi st(0),st(%d)", op2 & 0x7); break; + + default: sprintf(s, "??? (FPU)"); break; + } + } + break; + } + + case 4: // Group DC + { + if (op2 < 0xc0) + { + pc--; // adjust fetch pointer, so modrm byte read again + opcode_ptr--; + handle_modrm( modrm_string ); + switch ((op2 >> 3) & 0x7) + { + case 0: sprintf(s, "fadd qword ptr %s", modrm_string); break; + case 1: sprintf(s, "fmul qword ptr %s", modrm_string); break; + case 2: sprintf(s, "fcom qword ptr %s", modrm_string); break; + case 3: sprintf(s, "fcomp qword ptr %s", modrm_string); break; + case 4: sprintf(s, "fsub qword ptr %s", modrm_string); break; + case 5: sprintf(s, "fsubr qword ptr %s", modrm_string); break; + case 6: sprintf(s, "fdiv qword ptr %s", modrm_string); break; + case 7: sprintf(s, "fdivr qword ptr %s", modrm_string); break; + } + } + else + { + switch (op2 & 0x3f) + { + case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: + sprintf(s, "fadd st(%d),st(0)", op2 & 0x7); break; + + case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f: + sprintf(s, "fmul st(%d),st(0)", op2 & 0x7); break; + + case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27: + sprintf(s, "fsubr st(%d),st(0)", op2 & 0x7); break; + + case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: case 0x2f: + sprintf(s, "fsub st(%d),st(0)", op2 & 0x7); break; + + case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37: + sprintf(s, "fdivr st(%d),st(0)", op2 & 0x7); break; + + case 0x38: case 0x39: case 0x3a: case 0x3b: case 0x3c: case 0x3d: case 0x3e: case 0x3f: + sprintf(s, "fdiv st(%d),st(0)", op2 & 0x7); break; + + default: sprintf(s, "??? (FPU)"); break; + } + } + break; + } + + case 5: // Group DD + { + if (op2 < 0xc0) + { + pc--; // adjust fetch pointer, so modrm byte read again + opcode_ptr--; + handle_modrm( modrm_string ); + switch ((op2 >> 3) & 0x7) + { + case 0: sprintf(s, "fld qword ptr %s", modrm_string); break; + case 1: sprintf(s, "fisttp qword ptr %s", modrm_string); break; + case 2: sprintf(s, "fst qword ptr %s", modrm_string); break; + case 3: sprintf(s, "fstp qword ptr %s", modrm_string); break; + case 4: sprintf(s, "frstor %s", modrm_string); break; + case 5: sprintf(s, "??? (FPU)"); break; + case 6: sprintf(s, "fsave %s", modrm_string); break; + case 7: sprintf(s, "fstsw word ptr %s", modrm_string); break; + } + } + else + { + switch (op2 & 0x3f) + { + case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: + sprintf(s, "ffree st(%d)", op2 & 0x7); break; + + case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17: + sprintf(s, "fst st(%d)", op2 & 0x7); break; + + case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f: + sprintf(s, "fstp st(%d)", op2 & 0x7); break; + + case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27: + sprintf(s, "fucom st(%d), st(0)", op2 & 0x7); break; + + case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: case 0x2f: + sprintf(s, "fucomp st(%d)", op2 & 0x7); break; + + default: sprintf(s, "??? (FPU)"); break; + } + } + break; + } + + case 6: // Group DE + { + if (op2 < 0xc0) + { + pc--; // adjust fetch pointer, so modrm byte read again + opcode_ptr--; + handle_modrm( modrm_string ); + switch ((op2 >> 3) & 0x7) + { + case 0: sprintf(s, "fiadd word ptr %s", modrm_string); break; + case 1: sprintf(s, "fimul word ptr %s", modrm_string); break; + case 2: sprintf(s, "ficom word ptr %s", modrm_string); break; + case 3: sprintf(s, "ficomp word ptr %s", modrm_string); break; + case 4: sprintf(s, "fisub word ptr %s", modrm_string); break; + case 5: sprintf(s, "fisubr word ptr %s", modrm_string); break; + case 6: sprintf(s, "fidiv word ptr %s", modrm_string); break; + case 7: sprintf(s, "fidivr word ptr %s", modrm_string); break; + } + } + else + { + switch (op2 & 0x3f) + { + case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: + sprintf(s, "faddp st(%d)", op2 & 0x7); break; + + case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f: + sprintf(s, "fmulp st(%d)", op2 & 0x7); break; + + case 0x19: sprintf(s, "fcompp"); break; + + case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27: + sprintf(s, "fsubrp st(%d)", op2 & 0x7); break; + + case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: case 0x2f: + sprintf(s, "fsubp st(%d)", op2 & 0x7); break; + + case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37: + sprintf(s, "fdivrp st(%d), st(0)", op2 & 0x7); break; + + case 0x38: case 0x39: case 0x3a: case 0x3b: case 0x3c: case 0x3d: case 0x3e: case 0x3f: + sprintf(s, "fdivp st(%d)", op2 & 0x7); break; + + default: sprintf(s, "??? (FPU)"); break; + } + } + break; + } + + case 7: // Group DF + { + if (op2 < 0xc0) + { + pc--; // adjust fetch pointer, so modrm byte read again + opcode_ptr--; + handle_modrm( modrm_string ); + switch ((op2 >> 3) & 0x7) + { + case 0: sprintf(s, "fild word ptr %s", modrm_string); break; + case 1: sprintf(s, "fisttp word ptr %s", modrm_string); break; + case 2: sprintf(s, "fist word ptr %s", modrm_string); break; + case 3: sprintf(s, "fistp word ptr %s", modrm_string); break; + case 4: sprintf(s, "fbld %s", modrm_string); break; + case 5: sprintf(s, "fild qword ptr %s", modrm_string); break; + case 6: sprintf(s, "fbstp %s", modrm_string); break; + case 7: sprintf(s, "fistp qword ptr %s", modrm_string); break; + } + } + else + { + switch (op2 & 0x3f) + { + case 0x20: sprintf(s, "fstsw ax"); break; + + case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: case 0x2f: + sprintf(s, "fucomip st(%d)", op2 & 0x7); break; + + case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37: + sprintf(s, "fcomip st(%d),st(0)", op2 & 0x7); break; + + default: sprintf(s, "??? (FPU)"); break; + } + } + break; + } + } +} + +static void decode_opcode(char *s, const I386_OPCODE *op, UINT8 op1) +{ + int i; + UINT8 op2; + + if ((op->flags & SPECIAL64) && (address_size == 2)) + op = &x64_opcode_alt[op->flags >> 24]; + + switch( op->flags & FLAGS_MASK ) + { + case ISREX: + if (curmode == 64) + { + rex = op1; + operand_size = (op1 & 8) ? 2 : 1; + regex = (op1 << 1) & 8; + sibex = (op1 << 2) & 8; + rmex = (op1 << 3) & 8; + op2 = FETCH(); + decode_opcode( s, &i386_opcode_table1[op2], op1 ); + return; + } + break; + + case OP_SIZE: + rex = regex = sibex = rmex = 0; + if (operand_size < 2 && operand_prefix == 0) + { + operand_size ^= 1; + operand_prefix = 1; + } + op2 = FETCH(); + decode_opcode( s, &i386_opcode_table1[op2], op2 ); + return; + + case ADDR_SIZE: + rex = regex = sibex = rmex = 0; + if(address_prefix == 0) + { + if (curmode != 64) + address_size ^= 1; + else + address_size ^= 3; + address_prefix = 1; + } + op2 = FETCH(); + decode_opcode( s, &i386_opcode_table1[op2], op2 ); + return; + + case TWO_BYTE: + if (&opcode_ptr[-2] >= opcode_ptr_base) + pre0f = opcode_ptr[-2]; + op2 = FETCHD(); + decode_opcode( s, &i386_opcode_table2[op2], op1 ); + return; + + case THREE_BYTE: + op2 = FETCHD(); + if (opcode_ptr[-2] == 0x38) + decode_opcode( s, &i386_opcode_table0F38[op2], op1 ); + else + decode_opcode( s, &i386_opcode_table0F3A[op2], op1 ); + return; + + case SEG_CS: + case SEG_DS: + case SEG_ES: + case SEG_FS: + case SEG_GS: + case SEG_SS: + rex = regex = sibex = rmex = 0; + segment = op->flags; + op2 = FETCH(); + decode_opcode( s, &i386_opcode_table1[op2], op2 ); + return; + + case PREFIX: + op2 = FETCH(); + if ((op2 != 0x0f) && (op2 != 0x90)) + s += sprintf( s, "%-7s ", op->mnemonic ); + if ((op2 == 0x90) && !pre0f) + pre0f = op1; + decode_opcode( s, &i386_opcode_table1[op2], op2 ); + return; + + case GROUP: + handle_modrm( modrm_string ); + for( i=0; i < ARRAY_LENGTH(group_op_table); i++ ) { + if( strcmp(op->mnemonic, group_op_table[i].mnemonic) == 0 ) { + if (op->flags & GROUP_MOD) + decode_opcode( s, &group_op_table[i].opcode[MODRM_MOD], op1 ); + else + decode_opcode( s, &group_op_table[i].opcode[MODRM_REG1], op1 ); + return; + } + } + goto handle_unknown; + + case FPU: + op2 = FETCHD(); + handle_fpu( s, op1, op2); + return; + + case MODRM: + handle_modrm( modrm_string ); + break; + } + + if ((op->flags & ALWAYS64) && curmode == 64) + operand_size = 2; + + if ((op->flags & VAR_NAME) && operand_size > 0) + { + const char *mnemonic = op->mnemonic + strlen(op->mnemonic) + 1; + if (operand_size == 2) + mnemonic += strlen(mnemonic) + 1; + s += sprintf( s, "%-7s ", mnemonic ); + } + else if (op->flags & VAR_NAME4) + { + const char *mnemonic = op->mnemonic; + int which = (pre0f == 0xf3) ? 3 : (pre0f == 0xf2) ? 2 : (pre0f == 0x66) ? 1 : 0; + while (which--) + mnemonic += strlen(mnemonic) + 1; + s += sprintf( s, "%-7s ", mnemonic ); + } + else + s += sprintf( s, "%-7s ", op->mnemonic ); + dasm_flags = op->dasm_flags; + + if( op->param1 != 0 ) { + s = handle_param( s, op->param1 ); + } + + if( op->param2 != 0 ) { + s += sprintf( s, "," ); + s = handle_param( s, op->param2 ); + } + + if( op->param3 != 0 ) { + s += sprintf( s, "," ); + s = handle_param( s, op->param3 ); + } + return; + +handle_unknown: + sprintf(s, "???"); +} + +int i386_dasm_one_ex(char *buffer, UINT64 eip, const UINT8 *oprom, int mode) +{ + UINT8 op; + + opcode_ptr = opcode_ptr_base = oprom; + switch(mode) + { + case 1: /* 8086/8088/80186/80188 */ + address_size = 0; + operand_size = 0; + max_length = 8; /* maximum without redundant prefixes - not enforced by chip */ + break; + case 2: /* 80286 */ + address_size = 0; + operand_size = 0; + max_length = 10; + break; + case 16: /* 80386+ 16-bit code segment */ + address_size = 0; + operand_size = 0; + max_length = 15; + break; + case 32: /* 80386+ 32-bit code segment */ + address_size = 1; + operand_size = 1; + max_length = 15; + break; + case 64: /* x86_64 */ + address_size = 2; + operand_size = 1; + max_length = 15; + break; + } + pc = eip; + dasm_flags = 0; + segment = 0; + curmode = mode; + pre0f = 0; + rex = regex = sibex = rmex = 0; + address_prefix = 0; + operand_prefix = 0; + + op = FETCH(); + + decode_opcode( buffer, &i386_opcode_table1[op], op ); + return (pc-eip) | dasm_flags | DASMFLAG_SUPPORTED; +} + +int i386_dasm_one(char *buffer, offs_t eip, const UINT8 *oprom, int mode) +{ + return i386_dasm_one_ex(buffer, eip, oprom, mode); +} + +CPU_DISASSEMBLE( x86_16 ) +{ + return i386_dasm_one_ex(buffer, pc, oprom, 16); +} + +CPU_DISASSEMBLE( x86_32 ) +{ + return i386_dasm_one_ex(buffer, pc, oprom, 32); +} + +CPU_DISASSEMBLE( x86_64 ) +{ + return i386_dasm_one_ex(buffer, pc, oprom, 64); +} diff --git a/src/devices/cpu/i386/i386op16.inc b/src/devices/cpu/i386/i386op16.inc new file mode 100644 index 00000000000..9456f8931b2 --- /dev/null +++ b/src/devices/cpu/i386/i386op16.inc @@ -0,0 +1,3783 @@ +// license:BSD-3-Clause +// copyright-holders:Ville Linde, Barry Rodewald, Carl, Philip Bennett +UINT16 i386_device::i386_shift_rotate16(UINT8 modrm, UINT32 value, UINT8 shift) +{ + UINT32 src = value & 0xffff; + UINT16 dst = value; + + if( shift == 0 ) { + CYCLES_RM(modrm, 3, 7); + } else if( shift == 1 ) { + switch( (modrm >> 3) & 0x7 ) + { + case 0: /* ROL rm16, 1 */ + m_CF = (src & 0x8000) ? 1 : 0; + dst = (src << 1) + m_CF; + m_OF = ((src ^ dst) & 0x8000) ? 1 : 0; + CYCLES_RM(modrm, CYCLES_ROTATE_REG, CYCLES_ROTATE_MEM); + break; + case 1: /* ROR rm16, 1 */ + m_CF = (src & 0x1) ? 1 : 0; + dst = (m_CF << 15) | (src >> 1); + m_OF = ((src ^ dst) & 0x8000) ? 1 : 0; + CYCLES_RM(modrm, CYCLES_ROTATE_REG, CYCLES_ROTATE_MEM); + break; + case 2: /* RCL rm16, 1 */ + dst = (src << 1) + m_CF; + m_CF = (src & 0x8000) ? 1 : 0; + m_OF = ((src ^ dst) & 0x8000) ? 1 : 0; + CYCLES_RM(modrm, CYCLES_ROTATE_CARRY_REG, CYCLES_ROTATE_CARRY_MEM); + break; + case 3: /* RCR rm16, 1 */ + dst = (m_CF << 15) | (src >> 1); + m_CF = src & 0x1; + m_OF = ((src ^ dst) & 0x8000) ? 1 : 0; + CYCLES_RM(modrm, CYCLES_ROTATE_CARRY_REG, CYCLES_ROTATE_CARRY_MEM); + break; + case 4: /* SHL/SAL rm16, 1 */ + case 6: + dst = src << 1; + m_CF = (src & 0x8000) ? 1 : 0; + m_OF = (((m_CF << 15) ^ dst) & 0x8000) ? 1 : 0; + SetSZPF16(dst); + CYCLES_RM(modrm, CYCLES_ROTATE_REG, CYCLES_ROTATE_MEM); + break; + case 5: /* SHR rm16, 1 */ + dst = src >> 1; + m_CF = src & 0x1; + m_OF = (dst & 0x8000) ? 1 : 0; + SetSZPF16(dst); + CYCLES_RM(modrm, CYCLES_ROTATE_REG, CYCLES_ROTATE_MEM); + break; + case 7: /* SAR rm16, 1 */ + dst = (INT16)(src) >> 1; + m_CF = src & 0x1; + m_OF = 0; + SetSZPF16(dst); + CYCLES_RM(modrm, CYCLES_ROTATE_REG, CYCLES_ROTATE_MEM); + break; + } + } else { + switch( (modrm >> 3) & 0x7 ) + { + case 0: /* ROL rm16, i8 */ + if(!(shift & 15)) + { + if(shift & 16) + { + m_CF = src & 1; + m_OF = (src & 1) ^ ((src >> 15) & 1); + } + break; + } + shift &= 15; + dst = ((src & ((UINT16)0xffff >> shift)) << shift) | + ((src & ((UINT16)0xffff << (16-shift))) >> (16-shift)); + m_CF = dst & 0x1; + m_OF = (dst & 1) ^ (dst >> 15); + CYCLES_RM(modrm, CYCLES_ROTATE_REG, CYCLES_ROTATE_MEM); + break; + case 1: /* ROR rm16, i8 */ + if(!(shift & 15)) + { + if(shift & 16) + { + m_CF = (src >> 15) & 1; + m_OF = ((src >> 15) & 1) ^ ((src >> 14) & 1); + } + break; + } + shift &= 15; + dst = ((src & ((UINT16)0xffff << shift)) >> shift) | + ((src & ((UINT16)0xffff >> (16-shift))) << (16-shift)); + m_CF = (dst >> 15) & 1; + m_OF = ((dst >> 15) ^ (dst >> 14)) & 1; + CYCLES_RM(modrm, CYCLES_ROTATE_REG, CYCLES_ROTATE_MEM); + break; + case 2: /* RCL rm16, i8 */ + shift %= 17; + dst = ((src & ((UINT16)0xffff >> shift)) << shift) | + ((src & ((UINT16)0xffff << (17-shift))) >> (17-shift)) | + (m_CF << (shift-1)); + if(shift) m_CF = (src >> (16-shift)) & 0x1; + m_OF = m_CF ^ ((dst >> 15) & 1); + CYCLES_RM(modrm, CYCLES_ROTATE_CARRY_REG, CYCLES_ROTATE_CARRY_MEM); + break; + case 3: /* RCR rm16, i8 */ + shift %= 17; + dst = ((src & ((UINT16)0xffff << shift)) >> shift) | + ((src & ((UINT16)0xffff >> (16-shift))) << (17-shift)) | + (m_CF << (16-shift)); + if(shift) m_CF = (src >> (shift-1)) & 0x1; + m_OF = ((dst >> 15) ^ (dst >> 14)) & 1; + CYCLES_RM(modrm, CYCLES_ROTATE_CARRY_REG, CYCLES_ROTATE_CARRY_MEM); + break; + case 4: /* SHL/SAL rm16, i8 */ + case 6: + shift &= 31; + dst = src << shift; + m_CF = (shift <= 16) && (src & (1 << (16-shift))); + SetSZPF16(dst); + CYCLES_RM(modrm, CYCLES_ROTATE_REG, CYCLES_ROTATE_MEM); + break; + case 5: /* SHR rm16, i8 */ + shift &= 31; + dst = src >> shift; + m_CF = (src & (1 << (shift-1))) ? 1 : 0; + SetSZPF16(dst); + CYCLES_RM(modrm, CYCLES_ROTATE_REG, CYCLES_ROTATE_MEM); + break; + case 7: /* SAR rm16, i8 */ + shift &= 31; + dst = (INT16)src >> shift; + m_CF = (src & (1 << (shift-1))) ? 1 : 0; + SetSZPF16(dst); + CYCLES_RM(modrm, CYCLES_ROTATE_REG, CYCLES_ROTATE_MEM); + break; + } + + } + return dst; +} + + + +void i386_device::i386_adc_rm16_r16() // Opcode 0x11 +{ + UINT16 src, dst; + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + src = LOAD_REG16(modrm); + dst = LOAD_RM16(modrm); + dst = ADC16(dst, src, m_CF); + STORE_RM16(modrm, dst); + CYCLES(CYCLES_ALU_REG_REG); + } else { + UINT32 ea = GetEA(modrm,1); + src = LOAD_REG16(modrm); + dst = READ16(ea); + dst = ADC16(dst, src, m_CF); + WRITE16(ea, dst); + CYCLES(CYCLES_ALU_REG_MEM); + } +} + +void i386_device::i386_adc_r16_rm16() // Opcode 0x13 +{ + UINT16 src, dst; + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + src = LOAD_RM16(modrm); + dst = LOAD_REG16(modrm); + dst = ADC16(dst, src, m_CF); + STORE_REG16(modrm, dst); + CYCLES(CYCLES_ALU_REG_REG); + } else { + UINT32 ea = GetEA(modrm,0); + src = READ16(ea); + dst = LOAD_REG16(modrm); + dst = ADC16(dst, src, m_CF); + STORE_REG16(modrm, dst); + CYCLES(CYCLES_ALU_MEM_REG); + } +} + +void i386_device::i386_adc_ax_i16() // Opcode 0x15 +{ + UINT16 src, dst; + src = FETCH16(); + dst = REG16(AX); + dst = ADC16(dst, src, m_CF); + REG16(AX) = dst; + CYCLES(CYCLES_ALU_IMM_ACC); +} + +void i386_device::i386_add_rm16_r16() // Opcode 0x01 +{ + UINT16 src, dst; + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + src = LOAD_REG16(modrm); + dst = LOAD_RM16(modrm); + dst = ADD16(dst, src); + STORE_RM16(modrm, dst); + CYCLES(CYCLES_ALU_REG_REG); + } else { + UINT32 ea = GetEA(modrm,1); + src = LOAD_REG16(modrm); + dst = READ16(ea); + dst = ADD16(dst, src); + WRITE16(ea, dst); + CYCLES(CYCLES_ALU_REG_MEM); + } +} + +void i386_device::i386_add_r16_rm16() // Opcode 0x03 +{ + UINT16 src, dst; + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + src = LOAD_RM16(modrm); + dst = LOAD_REG16(modrm); + dst = ADD16(dst, src); + STORE_REG16(modrm, dst); + CYCLES(CYCLES_ALU_REG_REG); + } else { + UINT32 ea = GetEA(modrm,0); + src = READ16(ea); + dst = LOAD_REG16(modrm); + dst = ADD16(dst, src); + STORE_REG16(modrm, dst); + CYCLES(CYCLES_ALU_MEM_REG); + } +} + +void i386_device::i386_add_ax_i16() // Opcode 0x05 +{ + UINT16 src, dst; + src = FETCH16(); + dst = REG16(AX); + dst = ADD16(dst, src); + REG16(AX) = dst; + CYCLES(CYCLES_ALU_IMM_ACC); +} + +void i386_device::i386_and_rm16_r16() // Opcode 0x21 +{ + UINT16 src, dst; + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + src = LOAD_REG16(modrm); + dst = LOAD_RM16(modrm); + dst = AND16(dst, src); + STORE_RM16(modrm, dst); + CYCLES(CYCLES_ALU_REG_REG); + } else { + UINT32 ea = GetEA(modrm,1); + src = LOAD_REG16(modrm); + dst = READ16(ea); + dst = AND16(dst, src); + WRITE16(ea, dst); + CYCLES(CYCLES_ALU_REG_MEM); + } +} + +void i386_device::i386_and_r16_rm16() // Opcode 0x23 +{ + UINT16 src, dst; + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + src = LOAD_RM16(modrm); + dst = LOAD_REG16(modrm); + dst = AND16(dst, src); + STORE_REG16(modrm, dst); + CYCLES(CYCLES_ALU_REG_REG); + } else { + UINT32 ea = GetEA(modrm,0); + src = READ16(ea); + dst = LOAD_REG16(modrm); + dst = AND16(dst, src); + STORE_REG16(modrm, dst); + CYCLES(CYCLES_ALU_MEM_REG); + } +} + +void i386_device::i386_and_ax_i16() // Opcode 0x25 +{ + UINT16 src, dst; + src = FETCH16(); + dst = REG16(AX); + dst = AND16(dst, src); + REG16(AX) = dst; + CYCLES(CYCLES_ALU_IMM_ACC); +} + +void i386_device::i386_bsf_r16_rm16() // Opcode 0x0f bc +{ + UINT16 src, dst, temp; + UINT8 modrm = FETCH(); + + if( modrm >= 0xc0 ) { + src = LOAD_RM16(modrm); + } else { + UINT32 ea = GetEA(modrm,0); + src = READ16(ea); + } + + dst = 0; + + if( src == 0 ) { + m_ZF = 1; + } else { + m_ZF = 0; + temp = 0; + while( (src & (1 << temp)) == 0 ) { + temp++; + dst = temp; + CYCLES(CYCLES_BSF); + } + STORE_REG16(modrm, dst); + } + CYCLES(CYCLES_BSF_BASE); +} + +void i386_device::i386_bsr_r16_rm16() // Opcode 0x0f bd +{ + UINT16 src, dst, temp; + UINT8 modrm = FETCH(); + + if( modrm >= 0xc0 ) { + src = LOAD_RM16(modrm); + } else { + UINT32 ea = GetEA(modrm,0); + src = READ16(ea); + } + + dst = 0; + + if( src == 0 ) { + m_ZF = 1; + } else { + m_ZF = 0; + dst = temp = 15; + while( (src & (1 << temp)) == 0 ) { + temp--; + dst = temp; + CYCLES(CYCLES_BSR); + } + STORE_REG16(modrm, dst); + } + CYCLES(CYCLES_BSR_BASE); +} + + +void i386_device::i386_bt_rm16_r16() // Opcode 0x0f a3 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + UINT16 dst = LOAD_RM16(modrm); + UINT16 bit = LOAD_REG16(modrm); + + if( dst & (1 << (bit & 0xf)) ) + m_CF = 1; + else + m_CF = 0; + + CYCLES(CYCLES_BT_REG_REG); + } else { + UINT8 segment; + UINT32 ea = GetNonTranslatedEA(modrm,&segment); + UINT16 bit = LOAD_REG16(modrm); + ea += 2*(bit/16); + ea = i386_translate(segment,(m_address_size)?ea:(ea&0xffff),0); + bit %= 16; + UINT16 dst = READ16(ea); + + if( dst & (1 << bit) ) + m_CF = 1; + else + m_CF = 0; + + CYCLES(CYCLES_BT_REG_MEM); + } +} + +void i386_device::i386_btc_rm16_r16() // Opcode 0x0f bb +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + UINT16 dst = LOAD_RM16(modrm); + UINT16 bit = LOAD_REG16(modrm); + + if( dst & (1 << (bit & 0xf)) ) + m_CF = 1; + else + m_CF = 0; + dst ^= (1 << (bit & 0xf)); + + STORE_RM16(modrm, dst); + CYCLES(CYCLES_BTC_REG_REG); + } else { + UINT8 segment; + UINT32 ea = GetNonTranslatedEA(modrm,&segment); + UINT16 bit = LOAD_REG16(modrm); + ea += 2*(bit/16); + ea = i386_translate(segment,(m_address_size)?ea:(ea&0xffff),1); + bit %= 16; + UINT16 dst = READ16(ea); + + if( dst & (1 << bit) ) + m_CF = 1; + else + m_CF = 0; + dst ^= (1 << bit); + + WRITE16(ea, dst); + CYCLES(CYCLES_BTC_REG_MEM); + } +} + +void i386_device::i386_btr_rm16_r16() // Opcode 0x0f b3 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + UINT16 dst = LOAD_RM16(modrm); + UINT16 bit = LOAD_REG16(modrm); + + if( dst & (1 << (bit & 0xf)) ) + m_CF = 1; + else + m_CF = 0; + dst &= ~(1 << (bit & 0xf)); + + STORE_RM16(modrm, dst); + CYCLES(CYCLES_BTR_REG_REG); + } else { + UINT8 segment; + UINT32 ea = GetNonTranslatedEA(modrm,&segment); + UINT16 bit = LOAD_REG16(modrm); + ea += 2*(bit/16); + ea = i386_translate(segment,(m_address_size)?ea:(ea&0xffff),1); + bit %= 16; + UINT16 dst = READ16(ea); + + if( dst & (1 << bit) ) + m_CF = 1; + else + m_CF = 0; + dst &= ~(1 << bit); + + WRITE16(ea, dst); + CYCLES(CYCLES_BTR_REG_MEM); + } +} + +void i386_device::i386_bts_rm16_r16() // Opcode 0x0f ab +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + UINT16 dst = LOAD_RM16(modrm); + UINT16 bit = LOAD_REG16(modrm); + + if( dst & (1 << (bit & 0xf)) ) + m_CF = 1; + else + m_CF = 0; + dst |= (1 << (bit & 0xf)); + + STORE_RM16(modrm, dst); + CYCLES(CYCLES_BTS_REG_REG); + } else { + UINT8 segment; + UINT32 ea = GetNonTranslatedEA(modrm,&segment); + UINT16 bit = LOAD_REG16(modrm); + ea += 2*(bit/16); + ea = i386_translate(segment,(m_address_size)?ea:(ea&0xffff),1); + bit %= 16; + UINT16 dst = READ16(ea); + + if( dst & (1 << bit) ) + m_CF = 1; + else + m_CF = 0; + dst |= (1 << bit); + + WRITE16(ea, dst); + CYCLES(CYCLES_BTS_REG_MEM); + } +} + +void i386_device::i386_call_abs16() // Opcode 0x9a +{ + UINT16 offset = FETCH16(); + UINT16 ptr = FETCH16(); + + if( PROTECTED_MODE && !V8086_MODE) + { + i386_protected_mode_call(ptr,offset,0,0); + } + else + { + PUSH16(m_sreg[CS].selector ); + PUSH16(m_eip ); + m_sreg[CS].selector = ptr; + m_performed_intersegment_jump = 1; + m_eip = offset; + i386_load_segment_descriptor(CS); + } + CYCLES(CYCLES_CALL_INTERSEG); /* TODO: Timing = 17 + m */ + CHANGE_PC(m_eip); +} + +void i386_device::i386_call_rel16() // Opcode 0xe8 +{ + INT16 disp = FETCH16(); + + PUSH16(m_eip ); + if (m_sreg[CS].d) + { + m_eip += disp; + } + else + { + m_eip = (m_eip + disp) & 0xffff; + } + CHANGE_PC(m_eip); + CYCLES(CYCLES_CALL); /* TODO: Timing = 7 + m */ +} + +void i386_device::i386_cbw() // Opcode 0x98 +{ + REG16(AX) = (INT16)((INT8)REG8(AL)); + CYCLES(CYCLES_CBW); +} + +void i386_device::i386_cmp_rm16_r16() // Opcode 0x39 +{ + UINT16 src, dst; + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + src = LOAD_REG16(modrm); + dst = LOAD_RM16(modrm); + SUB16(dst, src); + CYCLES(CYCLES_CMP_REG_REG); + } else { + UINT32 ea = GetEA(modrm,0); + src = LOAD_REG16(modrm); + dst = READ16(ea); + SUB16(dst, src); + CYCLES(CYCLES_CMP_REG_MEM); + } +} + +void i386_device::i386_cmp_r16_rm16() // Opcode 0x3b +{ + UINT16 src, dst; + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + src = LOAD_RM16(modrm); + dst = LOAD_REG16(modrm); + SUB16(dst, src); + CYCLES(CYCLES_CMP_REG_REG); + } else { + UINT32 ea = GetEA(modrm,0); + src = READ16(ea); + dst = LOAD_REG16(modrm); + SUB16(dst, src); + CYCLES(CYCLES_CMP_MEM_REG); + } +} + +void i386_device::i386_cmp_ax_i16() // Opcode 0x3d +{ + UINT16 src, dst; + src = FETCH16(); + dst = REG16(AX); + SUB16(dst, src); + CYCLES(CYCLES_CMP_IMM_ACC); +} + +void i386_device::i386_cmpsw() // Opcode 0xa7 +{ + UINT32 eas, ead; + UINT16 src, dst; + if( m_segment_prefix ) { + eas = i386_translate(m_segment_override, m_address_size ? REG32(ESI) : REG16(SI), 0 ); + } else { + eas = i386_translate(DS, m_address_size ? REG32(ESI) : REG16(SI), 0 ); + } + ead = i386_translate(ES, m_address_size ? REG32(EDI) : REG16(DI), 0 ); + src = READ16(eas); + dst = READ16(ead); + SUB16(src,dst); + BUMP_SI(2); + BUMP_DI(2); + CYCLES(CYCLES_CMPS); +} + +void i386_device::i386_cwd() // Opcode 0x99 +{ + if( REG16(AX) & 0x8000 ) { + REG16(DX) = 0xffff; + } else { + REG16(DX) = 0x0000; + } + CYCLES(CYCLES_CWD); +} + +void i386_device::i386_dec_ax() // Opcode 0x48 +{ + REG16(AX) = DEC16(REG16(AX) ); + CYCLES(CYCLES_DEC_REG); +} + +void i386_device::i386_dec_cx() // Opcode 0x49 +{ + REG16(CX) = DEC16(REG16(CX) ); + CYCLES(CYCLES_DEC_REG); +} + +void i386_device::i386_dec_dx() // Opcode 0x4a +{ + REG16(DX) = DEC16(REG16(DX) ); + CYCLES(CYCLES_DEC_REG); +} + +void i386_device::i386_dec_bx() // Opcode 0x4b +{ + REG16(BX) = DEC16(REG16(BX) ); + CYCLES(CYCLES_DEC_REG); +} + +void i386_device::i386_dec_sp() // Opcode 0x4c +{ + REG16(SP) = DEC16(REG16(SP) ); + CYCLES(CYCLES_DEC_REG); +} + +void i386_device::i386_dec_bp() // Opcode 0x4d +{ + REG16(BP) = DEC16(REG16(BP) ); + CYCLES(CYCLES_DEC_REG); +} + +void i386_device::i386_dec_si() // Opcode 0x4e +{ + REG16(SI) = DEC16(REG16(SI) ); + CYCLES(CYCLES_DEC_REG); +} + +void i386_device::i386_dec_di() // Opcode 0x4f +{ + REG16(DI) = DEC16(REG16(DI) ); + CYCLES(CYCLES_DEC_REG); +} + +void i386_device::i386_imul_r16_rm16() // Opcode 0x0f af +{ + UINT8 modrm = FETCH(); + INT32 result; + INT32 src, dst; + if( modrm >= 0xc0 ) { + src = (INT32)(INT16)LOAD_RM16(modrm); + CYCLES(CYCLES_IMUL16_REG_REG); /* TODO: Correct multiply timing */ + } else { + UINT32 ea = GetEA(modrm,0); + src = (INT32)(INT16)READ16(ea); + CYCLES(CYCLES_IMUL16_REG_MEM); /* TODO: Correct multiply timing */ + } + + dst = (INT32)(INT16)LOAD_REG16(modrm); + result = src * dst; + + STORE_REG16(modrm, (UINT16)result); + + m_CF = m_OF = !(result == (INT32)(INT16)result); +} + +void i386_device::i386_imul_r16_rm16_i16() // Opcode 0x69 +{ + UINT8 modrm = FETCH(); + INT32 result; + INT32 src, dst; + if( modrm >= 0xc0 ) { + dst = (INT32)(INT16)LOAD_RM16(modrm); + CYCLES(CYCLES_IMUL16_REG_IMM_REG); /* TODO: Correct multiply timing */ + } else { + UINT32 ea = GetEA(modrm,0); + dst = (INT32)(INT16)READ16(ea); + CYCLES(CYCLES_IMUL16_MEM_IMM_REG); /* TODO: Correct multiply timing */ + } + + src = (INT32)(INT16)FETCH16(); + result = src * dst; + + STORE_REG16(modrm, (UINT16)result); + + m_CF = m_OF = !(result == (INT32)(INT16)result); +} + +void i386_device::i386_imul_r16_rm16_i8() // Opcode 0x6b +{ + UINT8 modrm = FETCH(); + INT32 result; + INT32 src, dst; + if( modrm >= 0xc0 ) { + dst = (INT32)(INT16)LOAD_RM16(modrm); + CYCLES(CYCLES_IMUL16_REG_IMM_REG); /* TODO: Correct multiply timing */ + } else { + UINT32 ea = GetEA(modrm,0); + dst = (INT32)(INT16)READ16(ea); + CYCLES(CYCLES_IMUL16_MEM_IMM_REG); /* TODO: Correct multiply timing */ + } + + src = (INT32)(INT8)FETCH(); + result = src * dst; + + STORE_REG16(modrm, (UINT16)result); + + m_CF = m_OF = !(result == (INT32)(INT16)result); +} + +void i386_device::i386_in_ax_i8() // Opcode 0xe5 +{ + UINT16 port = FETCH(); + UINT16 data = READPORT16(port); + REG16(AX) = data; + CYCLES(CYCLES_IN_VAR); +} + +void i386_device::i386_in_ax_dx() // Opcode 0xed +{ + UINT16 port = REG16(DX); + UINT16 data = READPORT16(port); + REG16(AX) = data; + CYCLES(CYCLES_IN); +} + +void i386_device::i386_inc_ax() // Opcode 0x40 +{ + REG16(AX) = INC16(REG16(AX) ); + CYCLES(CYCLES_INC_REG); +} + +void i386_device::i386_inc_cx() // Opcode 0x41 +{ + REG16(CX) = INC16(REG16(CX) ); + CYCLES(CYCLES_INC_REG); +} + +void i386_device::i386_inc_dx() // Opcode 0x42 +{ + REG16(DX) = INC16(REG16(DX) ); + CYCLES(CYCLES_INC_REG); +} + +void i386_device::i386_inc_bx() // Opcode 0x43 +{ + REG16(BX) = INC16(REG16(BX) ); + CYCLES(CYCLES_INC_REG); +} + +void i386_device::i386_inc_sp() // Opcode 0x44 +{ + REG16(SP) = INC16(REG16(SP) ); + CYCLES(CYCLES_INC_REG); +} + +void i386_device::i386_inc_bp() // Opcode 0x45 +{ + REG16(BP) = INC16(REG16(BP) ); + CYCLES(CYCLES_INC_REG); +} + +void i386_device::i386_inc_si() // Opcode 0x46 +{ + REG16(SI) = INC16(REG16(SI) ); + CYCLES(CYCLES_INC_REG); +} + +void i386_device::i386_inc_di() // Opcode 0x47 +{ + REG16(DI) = INC16(REG16(DI) ); + CYCLES(CYCLES_INC_REG); +} + +void i386_device::i386_iret16() // Opcode 0xcf +{ + if( PROTECTED_MODE ) + { + i386_protected_mode_iret(0); + } + else + { + /* TODO: #SS(0) exception */ + /* TODO: #GP(0) exception */ + m_eip = POP16(); + m_sreg[CS].selector = POP16(); + set_flags(POP16() ); + i386_load_segment_descriptor(CS); + CHANGE_PC(m_eip); + } + CYCLES(CYCLES_IRET); +} + +void i386_device::i386_ja_rel16() // Opcode 0x0f 87 +{ + INT16 disp = FETCH16(); + if( m_CF == 0 && m_ZF == 0 ) { + if (m_sreg[CS].d) + { + m_eip += disp; + } + else + { + m_eip = (m_eip + disp) & 0xffff; + } + CHANGE_PC(m_eip); + CYCLES(CYCLES_JCC_FULL_DISP); /* TODO: Timing = 7 + m */ + } else { + CYCLES(CYCLES_JCC_FULL_DISP_NOBRANCH); + } +} + +void i386_device::i386_jbe_rel16() // Opcode 0x0f 86 +{ + INT16 disp = FETCH16(); + if( m_CF != 0 || m_ZF != 0 ) { + if (m_sreg[CS].d) + { + m_eip += disp; + } + else + { + m_eip = (m_eip + disp) & 0xffff; + } + CHANGE_PC(m_eip); + CYCLES(CYCLES_JCC_FULL_DISP); /* TODO: Timing = 7 + m */ + } else { + CYCLES(CYCLES_JCC_FULL_DISP_NOBRANCH); + } +} + +void i386_device::i386_jc_rel16() // Opcode 0x0f 82 +{ + INT16 disp = FETCH16(); + if( m_CF != 0 ) { + if (m_sreg[CS].d) + { + m_eip += disp; + } + else + { + m_eip = (m_eip + disp) & 0xffff; + } + CHANGE_PC(m_eip); + CYCLES(CYCLES_JCC_FULL_DISP); /* TODO: Timing = 7 + m */ + } else { + CYCLES(CYCLES_JCC_FULL_DISP_NOBRANCH); + } +} + +void i386_device::i386_jg_rel16() // Opcode 0x0f 8f +{ + INT16 disp = FETCH16(); + if( m_ZF == 0 && (m_SF == m_OF) ) { + if (m_sreg[CS].d) + { + m_eip += disp; + } + else + { + m_eip = (m_eip + disp) & 0xffff; + } + CHANGE_PC(m_eip); + CYCLES(CYCLES_JCC_FULL_DISP); /* TODO: Timing = 7 + m */ + } else { + CYCLES(CYCLES_JCC_FULL_DISP_NOBRANCH); + } +} + +void i386_device::i386_jge_rel16() // Opcode 0x0f 8d +{ + INT16 disp = FETCH16(); + if(m_SF == m_OF) { + if (m_sreg[CS].d) + { + m_eip += disp; + } + else + { + m_eip = (m_eip + disp) & 0xffff; + } + CHANGE_PC(m_eip); + CYCLES(CYCLES_JCC_FULL_DISP); /* TODO: Timing = 7 + m */ + } else { + CYCLES(CYCLES_JCC_FULL_DISP_NOBRANCH); + } +} + +void i386_device::i386_jl_rel16() // Opcode 0x0f 8c +{ + INT16 disp = FETCH16(); + if( (m_SF != m_OF) ) { + if (m_sreg[CS].d) + { + m_eip += disp; + } + else + { + m_eip = (m_eip + disp) & 0xffff; + } + CHANGE_PC(m_eip); + CYCLES(CYCLES_JCC_FULL_DISP); /* TODO: Timing = 7 + m */ + } else { + CYCLES(CYCLES_JCC_FULL_DISP_NOBRANCH); + } +} + +void i386_device::i386_jle_rel16() // Opcode 0x0f 8e +{ + INT16 disp = FETCH16(); + if( m_ZF != 0 || (m_SF != m_OF) ) { + if (m_sreg[CS].d) + { + m_eip += disp; + } + else + { + m_eip = (m_eip + disp) & 0xffff; + } + CHANGE_PC(m_eip); + CYCLES(CYCLES_JCC_FULL_DISP); /* TODO: Timing = 7 + m */ + } else { + CYCLES(CYCLES_JCC_FULL_DISP_NOBRANCH); + } +} + +void i386_device::i386_jnc_rel16() // Opcode 0x0f 83 +{ + INT16 disp = FETCH16(); + if( m_CF == 0 ) { + if (m_sreg[CS].d) + { + m_eip += disp; + } + else + { + m_eip = (m_eip + disp) & 0xffff; + } + CHANGE_PC(m_eip); + CYCLES(CYCLES_JCC_FULL_DISP); /* TODO: Timing = 7 + m */ + } else { + CYCLES(CYCLES_JCC_FULL_DISP_NOBRANCH); + } +} + +void i386_device::i386_jno_rel16() // Opcode 0x0f 81 +{ + INT16 disp = FETCH16(); + if( m_OF == 0 ) { + if (m_sreg[CS].d) + { + m_eip += disp; + } + else + { + m_eip = (m_eip + disp) & 0xffff; + } + CHANGE_PC(m_eip); + CYCLES(CYCLES_JCC_FULL_DISP); /* TODO: Timing = 7 + m */ + } else { + CYCLES(CYCLES_JCC_FULL_DISP_NOBRANCH); + } +} + +void i386_device::i386_jnp_rel16() // Opcode 0x0f 8b +{ + INT16 disp = FETCH16(); + if( m_PF == 0 ) { + if (m_sreg[CS].d) + { + m_eip += disp; + } + else + { + m_eip = (m_eip + disp) & 0xffff; + } + CHANGE_PC(m_eip); + CYCLES(CYCLES_JCC_FULL_DISP); /* TODO: Timing = 7 + m */ + } else { + CYCLES(CYCLES_JCC_FULL_DISP_NOBRANCH); + } +} + +void i386_device::i386_jns_rel16() // Opcode 0x0f 89 +{ + INT16 disp = FETCH16(); + if( m_SF == 0 ) { + if (m_sreg[CS].d) + { + m_eip += disp; + } + else + { + m_eip = (m_eip + disp) & 0xffff; + } + CHANGE_PC(m_eip); + CYCLES(CYCLES_JCC_FULL_DISP); /* TODO: Timing = 7 + m */ + } else { + CYCLES(CYCLES_JCC_FULL_DISP_NOBRANCH); + } +} + +void i386_device::i386_jnz_rel16() // Opcode 0x0f 85 +{ + INT16 disp = FETCH16(); + if( m_ZF == 0 ) { + if (m_sreg[CS].d) + { + m_eip += disp; + } + else + { + m_eip = (m_eip + disp) & 0xffff; + } + CHANGE_PC(m_eip); + CYCLES(CYCLES_JCC_FULL_DISP); /* TODO: Timing = 7 + m */ + } else { + CYCLES(CYCLES_JCC_FULL_DISP_NOBRANCH); + } +} + +void i386_device::i386_jo_rel16() // Opcode 0x0f 80 +{ + INT16 disp = FETCH16(); + if( m_OF != 0 ) { + if (m_sreg[CS].d) + { + m_eip += disp; + } + else + { + m_eip = (m_eip + disp) & 0xffff; + } + CHANGE_PC(m_eip); + CYCLES(CYCLES_JCC_FULL_DISP); /* TODO: Timing = 7 + m */ + } else { + CYCLES(CYCLES_JCC_FULL_DISP_NOBRANCH); + } +} + +void i386_device::i386_jp_rel16() // Opcode 0x0f 8a +{ + INT16 disp = FETCH16(); + if( m_PF != 0 ) { + if (m_sreg[CS].d) + { + m_eip += disp; + } + else + { + m_eip = (m_eip + disp) & 0xffff; + } + CHANGE_PC(m_eip); + CYCLES(CYCLES_JCC_FULL_DISP); /* TODO: Timing = 7 + m */ + } else { + CYCLES(CYCLES_JCC_FULL_DISP_NOBRANCH); + } +} + +void i386_device::i386_js_rel16() // Opcode 0x0f 88 +{ + INT16 disp = FETCH16(); + if( m_SF != 0 ) { + if (m_sreg[CS].d) + { + m_eip += disp; + } + else + { + m_eip = (m_eip + disp) & 0xffff; + } + CHANGE_PC(m_eip); + CYCLES(CYCLES_JCC_FULL_DISP); /* TODO: Timing = 7 + m */ + } else { + CYCLES(CYCLES_JCC_FULL_DISP_NOBRANCH); + } +} + +void i386_device::i386_jz_rel16() // Opcode 0x0f 84 +{ + INT16 disp = FETCH16(); + if( m_ZF != 0 ) { + if (m_sreg[CS].d) + { + m_eip += disp; + } + else + { + m_eip = (m_eip + disp) & 0xffff; + } + CHANGE_PC(m_eip); + CYCLES(CYCLES_JCC_FULL_DISP); /* TODO: Timing = 7 + m */ + } else { + CYCLES(CYCLES_JCC_FULL_DISP_NOBRANCH); + } +} + +void i386_device::i386_jcxz16() // Opcode 0xe3 +{ + INT8 disp = FETCH(); + int val = (m_address_size)?(REG32(ECX) == 0):(REG16(CX) == 0); + if( val ) { + if (m_sreg[CS].d) + { + m_eip += disp; + } + else + { + m_eip = (m_eip + disp) & 0xffff; + } + CHANGE_PC(m_eip); + CYCLES(CYCLES_JCXZ); /* TODO: Timing = 9 + m */ + } else { + CYCLES(CYCLES_JCXZ_NOBRANCH); + } +} + +void i386_device::i386_jmp_rel16() // Opcode 0xe9 +{ + INT16 disp = FETCH16(); + + if (m_sreg[CS].d) + { + m_eip += disp; + } + else + { + m_eip = (m_eip + disp) & 0xffff; + } + CHANGE_PC(m_eip); + CYCLES(CYCLES_JMP); /* TODO: Timing = 7 + m */ +} + +void i386_device::i386_jmp_abs16() // Opcode 0xea +{ + UINT16 address = FETCH16(); + UINT16 segment = FETCH16(); + + if( PROTECTED_MODE && !V8086_MODE) + { + i386_protected_mode_jump(segment,address,0,0); + } + else + { + m_eip = address; + m_sreg[CS].selector = segment; + m_performed_intersegment_jump = 1; + i386_load_segment_descriptor(CS); + CHANGE_PC(m_eip); + } + CYCLES(CYCLES_JMP_INTERSEG); +} + +void i386_device::i386_lea16() // Opcode 0x8d +{ + UINT8 modrm = FETCH(); + UINT32 ea = GetNonTranslatedEA(modrm,NULL); + STORE_REG16(modrm, ea); + CYCLES(CYCLES_LEA); +} + +void i386_device::i386_enter16() // Opcode 0xc8 +{ + UINT16 framesize = FETCH16(); + UINT8 level = FETCH() % 32; + UINT8 x; + UINT16 frameptr; + PUSH16(REG16(BP)); + + if(!STACK_32BIT) + frameptr = REG16(SP); + else + frameptr = REG32(ESP); + + if(level > 0) + { + for(x=1;x= 0xc0 ) { + src = LOAD_REG16(modrm); + STORE_RM16(modrm, src); + CYCLES(CYCLES_MOV_REG_REG); + } else { + UINT32 ea = GetEA(modrm,1); + src = LOAD_REG16(modrm); + WRITE16(ea, src); + CYCLES(CYCLES_MOV_REG_MEM); + } +} + +void i386_device::i386_mov_r16_rm16() // Opcode 0x8b +{ + UINT16 src; + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + src = LOAD_RM16(modrm); + STORE_REG16(modrm, src); + CYCLES(CYCLES_MOV_REG_REG); + } else { + UINT32 ea = GetEA(modrm,0); + src = READ16(ea); + STORE_REG16(modrm, src); + CYCLES(CYCLES_MOV_MEM_REG); + } +} + +void i386_device::i386_mov_rm16_i16() // Opcode 0xc7 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + UINT16 value = FETCH16(); + STORE_RM16(modrm, value); + CYCLES(CYCLES_MOV_IMM_REG); + } else { + UINT32 ea = GetEA(modrm,1); + UINT16 value = FETCH16(); + WRITE16(ea, value); + CYCLES(CYCLES_MOV_IMM_MEM); + } +} + +void i386_device::i386_mov_ax_m16() // Opcode 0xa1 +{ + UINT32 offset, ea; + if( m_address_size ) { + offset = FETCH32(); + } else { + offset = FETCH16(); + } + /* TODO: Not sure if this is correct... */ + if( m_segment_prefix ) { + ea = i386_translate(m_segment_override, offset, 0 ); + } else { + ea = i386_translate(DS, offset, 0 ); + } + REG16(AX) = READ16(ea); + CYCLES(CYCLES_MOV_MEM_ACC); +} + +void i386_device::i386_mov_m16_ax() // Opcode 0xa3 +{ + UINT32 offset, ea; + if( m_address_size ) { + offset = FETCH32(); + } else { + offset = FETCH16(); + } + /* TODO: Not sure if this is correct... */ + if( m_segment_prefix ) { + ea = i386_translate(m_segment_override, offset, 1 ); + } else { + ea = i386_translate(DS, offset, 1 ); + } + WRITE16(ea, REG16(AX) ); + CYCLES(CYCLES_MOV_ACC_MEM); +} + +void i386_device::i386_mov_ax_i16() // Opcode 0xb8 +{ + REG16(AX) = FETCH16(); + CYCLES(CYCLES_MOV_IMM_REG); +} + +void i386_device::i386_mov_cx_i16() // Opcode 0xb9 +{ + REG16(CX) = FETCH16(); + CYCLES(CYCLES_MOV_IMM_REG); +} + +void i386_device::i386_mov_dx_i16() // Opcode 0xba +{ + REG16(DX) = FETCH16(); + CYCLES(CYCLES_MOV_IMM_REG); +} + +void i386_device::i386_mov_bx_i16() // Opcode 0xbb +{ + REG16(BX) = FETCH16(); + CYCLES(CYCLES_MOV_IMM_REG); +} + +void i386_device::i386_mov_sp_i16() // Opcode 0xbc +{ + REG16(SP) = FETCH16(); + CYCLES(CYCLES_MOV_IMM_REG); +} + +void i386_device::i386_mov_bp_i16() // Opcode 0xbd +{ + REG16(BP) = FETCH16(); + CYCLES(CYCLES_MOV_IMM_REG); +} + +void i386_device::i386_mov_si_i16() // Opcode 0xbe +{ + REG16(SI) = FETCH16(); + CYCLES(CYCLES_MOV_IMM_REG); +} + +void i386_device::i386_mov_di_i16() // Opcode 0xbf +{ + REG16(DI) = FETCH16(); + CYCLES(CYCLES_MOV_IMM_REG); +} + +void i386_device::i386_movsw() // Opcode 0xa5 +{ + UINT32 eas, ead; + UINT16 v; + if( m_segment_prefix ) { + eas = i386_translate(m_segment_override, m_address_size ? REG32(ESI) : REG16(SI), 0 ); + } else { + eas = i386_translate(DS, m_address_size ? REG32(ESI) : REG16(SI), 0 ); + } + ead = i386_translate(ES, m_address_size ? REG32(EDI) : REG16(DI), 1 ); + v = READ16(eas); + WRITE16(ead, v); + BUMP_SI(2); + BUMP_DI(2); + CYCLES(CYCLES_MOVS); +} + +void i386_device::i386_movsx_r16_rm8() // Opcode 0x0f be +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + INT16 src = (INT8)LOAD_RM8(modrm); + STORE_REG16(modrm, src); + CYCLES(CYCLES_MOVSX_REG_REG); + } else { + UINT32 ea = GetEA(modrm,0); + INT16 src = (INT8)READ8(ea); + STORE_REG16(modrm, src); + CYCLES(CYCLES_MOVSX_MEM_REG); + } +} + +void i386_device::i386_movzx_r16_rm8() // Opcode 0x0f b6 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + UINT16 src = (UINT8)LOAD_RM8(modrm); + STORE_REG16(modrm, src); + CYCLES(CYCLES_MOVZX_REG_REG); + } else { + UINT32 ea = GetEA(modrm,0); + UINT16 src = (UINT8)READ8(ea); + STORE_REG16(modrm, src); + CYCLES(CYCLES_MOVZX_MEM_REG); + } +} + +void i386_device::i386_or_rm16_r16() // Opcode 0x09 +{ + UINT16 src, dst; + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + src = LOAD_REG16(modrm); + dst = LOAD_RM16(modrm); + dst = OR16(dst, src); + STORE_RM16(modrm, dst); + CYCLES(CYCLES_ALU_REG_REG); + } else { + UINT32 ea = GetEA(modrm,1); + src = LOAD_REG16(modrm); + dst = READ16(ea); + dst = OR16(dst, src); + WRITE16(ea, dst); + CYCLES(CYCLES_ALU_REG_MEM); + } +} + +void i386_device::i386_or_r16_rm16() // Opcode 0x0b +{ + UINT16 src, dst; + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + src = LOAD_RM16(modrm); + dst = LOAD_REG16(modrm); + dst = OR16(dst, src); + STORE_REG16(modrm, dst); + CYCLES(CYCLES_ALU_REG_REG); + } else { + UINT32 ea = GetEA(modrm,0); + src = READ16(ea); + dst = LOAD_REG16(modrm); + dst = OR16(dst, src); + STORE_REG16(modrm, dst); + CYCLES(CYCLES_ALU_MEM_REG); + } +} + +void i386_device::i386_or_ax_i16() // Opcode 0x0d +{ + UINT16 src, dst; + src = FETCH16(); + dst = REG16(AX); + dst = OR16(dst, src); + REG16(AX) = dst; + CYCLES(CYCLES_ALU_IMM_ACC); +} + +void i386_device::i386_out_ax_i8() // Opcode 0xe7 +{ + UINT16 port = FETCH(); + UINT16 data = REG16(AX); + WRITEPORT16(port, data); + CYCLES(CYCLES_OUT_VAR); +} + +void i386_device::i386_out_ax_dx() // Opcode 0xef +{ + UINT16 port = REG16(DX); + UINT16 data = REG16(AX); + WRITEPORT16(port, data); + CYCLES(CYCLES_OUT); +} + +void i386_device::i386_pop_ax() // Opcode 0x58 +{ + UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP)); + if(i386_limit_check(SS,offset+1) == 0) + REG16(AX) = POP16(); + else + FAULT(FAULT_SS,0) + CYCLES(CYCLES_POP_REG_SHORT); +} + +void i386_device::i386_pop_cx() // Opcode 0x59 +{ + UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP)); + if(i386_limit_check(SS,offset+1) == 0) + REG16(CX) = POP16(); + else + FAULT(FAULT_SS,0) + CYCLES(CYCLES_POP_REG_SHORT); +} + +void i386_device::i386_pop_dx() // Opcode 0x5a +{ + UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP)); + if(i386_limit_check(SS,offset+1) == 0) + REG16(DX) = POP16(); + else + FAULT(FAULT_SS,0) + CYCLES(CYCLES_POP_REG_SHORT); +} + +void i386_device::i386_pop_bx() // Opcode 0x5b +{ + UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP)); + if(i386_limit_check(SS,offset+1) == 0) + REG16(BX) = POP16(); + else + FAULT(FAULT_SS,0) + CYCLES(CYCLES_POP_REG_SHORT); +} + +void i386_device::i386_pop_sp() // Opcode 0x5c +{ + UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP)); + if(i386_limit_check(SS,offset+1) == 0) + REG16(SP) = POP16(); + else + FAULT(FAULT_SS,0) + CYCLES(CYCLES_POP_REG_SHORT); +} + +void i386_device::i386_pop_bp() // Opcode 0x5d +{ + UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP)); + if(i386_limit_check(SS,offset+1) == 0) + REG16(BP) = POP16(); + else + FAULT(FAULT_SS,0) + CYCLES(CYCLES_POP_REG_SHORT); +} + +void i386_device::i386_pop_si() // Opcode 0x5e +{ + UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP)); + if(i386_limit_check(SS,offset+1) == 0) + REG16(SI) = POP16(); + else + FAULT(FAULT_SS,0) + CYCLES(CYCLES_POP_REG_SHORT); +} + +void i386_device::i386_pop_di() // Opcode 0x5f +{ + UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP)); + if(i386_limit_check(SS,offset+1) == 0) + REG16(DI) = POP16(); + else + FAULT(FAULT_SS,0) + CYCLES(CYCLES_POP_REG_SHORT); +} + +bool i386_device::i386_pop_seg16(int segment) +{ + UINT32 ea, offset = (STACK_32BIT ? REG32(ESP) : REG16(SP)); + UINT16 value; + bool fault; + if(i386_limit_check(SS,offset+1) == 0) + { + ea = i386_translate(SS, offset, 0); + value = READ16(ea); + i386_sreg_load(value, segment, &fault); + if(fault) return false; + if(STACK_32BIT) + REG32(ESP) = offset + 2; + else + REG16(SP) = offset + 2; + } + else + { + m_ext = 1; + i386_trap_with_error(FAULT_SS,0,0,0); + return false; + } + CYCLES(CYCLES_POP_SREG); + return true; +} + +void i386_device::i386_pop_ds16() // Opcode 0x1f +{ + i386_pop_seg16(DS); +} + +void i386_device::i386_pop_es16() // Opcode 0x07 +{ + i386_pop_seg16(ES); +} + +void i386_device::i386_pop_fs16() // Opcode 0x0f a1 +{ + i386_pop_seg16(FS); +} + +void i386_device::i386_pop_gs16() // Opcode 0x0f a9 +{ + i386_pop_seg16(GS); +} + +void i386_device::i386_pop_ss16() // Opcode 0x17 +{ + if(!i386_pop_seg16(SS)) return; + if(m_IF != 0) // if external interrupts are enabled + { + m_IF = 0; // reset IF for the next instruction + m_delayed_interrupt_enable = 1; + } +} + +void i386_device::i386_pop_rm16() // Opcode 0x8f +{ + UINT8 modrm = FETCH(); + UINT16 value; + UINT32 ea, offset = (STACK_32BIT ? REG32(ESP) : REG16(SP)); + + if(i386_limit_check(SS,offset+1) == 0) + { + UINT32 temp_sp = REG32(ESP); + value = POP16(); + + if( modrm >= 0xc0 ) { + STORE_RM16(modrm, value); + } else { + ea = GetEA(modrm,1); + try + { + WRITE16(ea, value); + } + catch(UINT64 e) + { + REG32(ESP) = temp_sp; + throw e; + } + } + } + else + FAULT(FAULT_SS,0) + CYCLES(CYCLES_POP_RM); +} + +void i386_device::i386_popa() // Opcode 0x61 +{ + UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP)); + + if(i386_limit_check(SS,offset+15) == 0) + { + REG16(DI) = POP16(); + REG16(SI) = POP16(); + REG16(BP) = POP16(); + REG16(SP) += 2; + REG16(BX) = POP16(); + REG16(DX) = POP16(); + REG16(CX) = POP16(); + REG16(AX) = POP16(); + } + else + FAULT(FAULT_SS,0) + CYCLES(CYCLES_POPA); +} + +void i386_device::i386_popf() // Opcode 0x9d +{ + UINT32 value; + UINT32 current = get_flags(); + UINT8 IOPL = (current >> 12) & 0x03; + UINT32 mask = 0x7fd5; + UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP)); + + // IOPL can only change if CPL is 0 + if(m_CPL != 0) + mask &= ~0x00003000; + + // IF can only change if CPL is at least as privileged as IOPL + if(m_CPL > IOPL) + mask &= ~0x00000200; + + if(V8086_MODE) + { + if(IOPL < 3) + { + logerror("POPFD(%08x): IOPL < 3 while in V86 mode.\n",m_pc); + FAULT(FAULT_GP,0) // #GP(0) + } + mask &= ~0x00003000; // IOPL cannot be changed while in V8086 mode + } + + if(i386_limit_check(SS,offset+1) == 0) + { + value = POP16(); + set_flags((current & ~mask) | (value & mask)); // mask out reserved bits + } + else + FAULT(FAULT_SS,0) + CYCLES(CYCLES_POPF); +} + +void i386_device::i386_push_ax() // Opcode 0x50 +{ + UINT32 offset; + if(STACK_32BIT) + offset = REG32(ESP) - 2; + else + offset = (REG16(SP) - 2) & 0xffff; + if(i386_limit_check(SS,offset) == 0) + PUSH16(REG16(AX) ); + else + FAULT(FAULT_SS,0) + CYCLES(CYCLES_PUSH_REG_SHORT); +} + +void i386_device::i386_push_cx() // Opcode 0x51 +{ + UINT32 offset; + if(STACK_32BIT) + offset = REG32(ESP) - 2; + else + offset = (REG16(SP) - 2) & 0xffff; + if(i386_limit_check(SS,offset) == 0) + PUSH16(REG16(CX) ); + else + FAULT(FAULT_SS,0) + CYCLES(CYCLES_PUSH_REG_SHORT); +} + +void i386_device::i386_push_dx() // Opcode 0x52 +{ + UINT32 offset; + if(STACK_32BIT) + offset = REG32(ESP) - 2; + else + offset = (REG16(SP) - 2) & 0xffff; + if(i386_limit_check(SS,offset) == 0) + PUSH16(REG16(DX) ); + else + FAULT(FAULT_SS,0) + CYCLES(CYCLES_PUSH_REG_SHORT); +} + +void i386_device::i386_push_bx() // Opcode 0x53 +{ + UINT32 offset; + if(STACK_32BIT) + offset = REG32(ESP) - 2; + else + offset = (REG16(SP) - 2) & 0xffff; + if(i386_limit_check(SS,offset) == 0) + PUSH16(REG16(BX) ); + else + FAULT(FAULT_SS,0) + CYCLES(CYCLES_PUSH_REG_SHORT); +} + +void i386_device::i386_push_sp() // Opcode 0x54 +{ + UINT32 offset; + if(STACK_32BIT) + offset = REG32(ESP) - 2; + else + offset = (REG16(SP) - 2) & 0xffff; + if(i386_limit_check(SS,offset) == 0) + PUSH16(REG16(SP) ); + else + FAULT(FAULT_SS,0) + CYCLES(CYCLES_PUSH_REG_SHORT); +} + +void i386_device::i386_push_bp() // Opcode 0x55 +{ + UINT32 offset; + if(STACK_32BIT) + offset = REG32(ESP) - 2; + else + offset = (REG16(SP) - 2) & 0xffff; + if(i386_limit_check(SS,offset) == 0) + PUSH16(REG16(BP) ); + else + FAULT(FAULT_SS,0) + CYCLES(CYCLES_PUSH_REG_SHORT); +} + +void i386_device::i386_push_si() // Opcode 0x56 +{ + UINT32 offset; + if(STACK_32BIT) + offset = REG32(ESP) - 2; + else + offset = (REG16(SP) - 2) & 0xffff; + if(i386_limit_check(SS,offset) == 0) + PUSH16(REG16(SI) ); + else + FAULT(FAULT_SS,0) + CYCLES(CYCLES_PUSH_REG_SHORT); +} + +void i386_device::i386_push_di() // Opcode 0x57 +{ + UINT32 offset; + if(STACK_32BIT) + offset = REG32(ESP) - 2; + else + offset = (REG16(SP) - 2) & 0xffff; + if(i386_limit_check(SS,offset) == 0) + PUSH16(REG16(DI) ); + else + FAULT(FAULT_SS,0) + CYCLES(CYCLES_PUSH_REG_SHORT); +} + +void i386_device::i386_push_cs16() // Opcode 0x0e +{ + UINT32 offset; + if(STACK_32BIT) + offset = REG32(ESP) - 2; + else + offset = (REG16(SP) - 2) & 0xffff; + if(i386_limit_check(SS,offset) == 0) + PUSH16(m_sreg[CS].selector ); + else + FAULT(FAULT_SS,0) + CYCLES(CYCLES_PUSH_SREG); +} + +void i386_device::i386_push_ds16() // Opcode 0x1e +{ + UINT32 offset; + if(STACK_32BIT) + offset = REG32(ESP) - 2; + else + offset = (REG16(SP) - 2) & 0xffff; + if(i386_limit_check(SS,offset) == 0) + PUSH16(m_sreg[DS].selector ); + else + FAULT(FAULT_SS,0) + CYCLES(CYCLES_PUSH_SREG); +} + +void i386_device::i386_push_es16() // Opcode 0x06 +{ + UINT32 offset; + if(STACK_32BIT) + offset = REG32(ESP) - 2; + else + offset = (REG16(SP) - 2) & 0xffff; + if(i386_limit_check(SS,offset) == 0) + PUSH16(m_sreg[ES].selector ); + else + FAULT(FAULT_SS,0) + CYCLES(CYCLES_PUSH_SREG); +} + +void i386_device::i386_push_fs16() // Opcode 0x0f a0 +{ + UINT32 offset; + if(STACK_32BIT) + offset = REG32(ESP) - 2; + else + offset = (REG16(SP) - 2) & 0xffff; + if(i386_limit_check(SS,offset) == 0) + PUSH16(m_sreg[FS].selector ); + else + FAULT(FAULT_SS,0) + CYCLES(CYCLES_PUSH_SREG); +} + +void i386_device::i386_push_gs16() // Opcode 0x0f a8 +{ + UINT32 offset; + if(STACK_32BIT) + offset = REG32(ESP) - 2; + else + offset = (REG16(SP) - 2) & 0xffff; + if(i386_limit_check(SS,offset) == 0) + PUSH16(m_sreg[GS].selector ); + else + FAULT(FAULT_SS,0) + CYCLES(CYCLES_PUSH_SREG); +} + +void i386_device::i386_push_ss16() // Opcode 0x16 +{ + UINT32 offset; + if(STACK_32BIT) + offset = REG32(ESP) - 2; + else + offset = (REG16(SP) - 2) & 0xffff; + if(i386_limit_check(SS,offset) == 0) + PUSH16(m_sreg[SS].selector ); + else + FAULT(FAULT_SS,0) + CYCLES(CYCLES_PUSH_SREG); +} + +void i386_device::i386_push_i16() // Opcode 0x68 +{ + UINT16 value = FETCH16(); + UINT32 offset; + if(STACK_32BIT) + offset = REG32(ESP) - 2; + else + offset = (REG16(SP) - 2) & 0xffff; + if(i386_limit_check(SS,offset) == 0) + PUSH16(value); + else + FAULT(FAULT_SS,0) + CYCLES(CYCLES_PUSH_IMM); +} + +void i386_device::i386_pusha() // Opcode 0x60 +{ + UINT16 temp = REG16(SP); + UINT32 offset; + if(STACK_32BIT) + offset = REG32(ESP) - 16; + else + offset = (REG16(SP) - 16) & 0xffff; + if(i386_limit_check(SS,offset) == 0) + { + PUSH16(REG16(AX) ); + PUSH16(REG16(CX) ); + PUSH16(REG16(DX) ); + PUSH16(REG16(BX) ); + PUSH16(temp ); + PUSH16(REG16(BP) ); + PUSH16(REG16(SI) ); + PUSH16(REG16(DI) ); + } + else + FAULT(FAULT_SS,0) + CYCLES(CYCLES_PUSHA); +} + +void i386_device::i386_pushf() // Opcode 0x9c +{ + UINT32 offset; + if(STACK_32BIT) + offset = REG32(ESP) - 2; + else + offset = (REG16(SP) - 2) & 0xffff; + if(i386_limit_check(SS,offset) == 0) + PUSH16(get_flags() & 0xffff ); + else + FAULT(FAULT_SS,0) + CYCLES(CYCLES_PUSHF); +} + +void i386_device::i386_ret_near16_i16() // Opcode 0xc2 +{ + INT16 disp = FETCH16(); + m_eip = POP16(); + REG16(SP) += disp; + CHANGE_PC(m_eip); + CYCLES(CYCLES_RET_IMM); /* TODO: Timing = 10 + m */ +} + +void i386_device::i386_ret_near16() // Opcode 0xc3 +{ + m_eip = POP16(); + CHANGE_PC(m_eip); + CYCLES(CYCLES_RET); /* TODO: Timing = 10 + m */ +} + +void i386_device::i386_sbb_rm16_r16() // Opcode 0x19 +{ + UINT16 src, dst; + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + src = LOAD_REG16(modrm); + dst = LOAD_RM16(modrm); + dst = SBB16(dst, src, m_CF); + STORE_RM16(modrm, dst); + CYCLES(CYCLES_ALU_REG_REG); + } else { + UINT32 ea = GetEA(modrm,1); + src = LOAD_REG16(modrm); + dst = READ16(ea); + dst = SBB16(dst, src, m_CF); + WRITE16(ea, dst); + CYCLES(CYCLES_ALU_REG_MEM); + } +} + +void i386_device::i386_sbb_r16_rm16() // Opcode 0x1b +{ + UINT16 src, dst; + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + src = LOAD_RM16(modrm); + dst = LOAD_REG16(modrm); + dst = SBB16(dst, src, m_CF); + STORE_REG16(modrm, dst); + CYCLES(CYCLES_ALU_REG_REG); + } else { + UINT32 ea = GetEA(modrm,0); + src = READ16(ea); + dst = LOAD_REG16(modrm); + dst = SBB16(dst, src, m_CF); + STORE_REG16(modrm, dst); + CYCLES(CYCLES_ALU_MEM_REG); + } +} + +void i386_device::i386_sbb_ax_i16() // Opcode 0x1d +{ + UINT16 src, dst; + src = FETCH16(); + dst = REG16(AX); + dst = SBB16(dst, src, m_CF); + REG16(AX) = dst; + CYCLES(CYCLES_ALU_IMM_ACC); +} + +void i386_device::i386_scasw() // Opcode 0xaf +{ + UINT32 eas; + UINT16 src, dst; + eas = i386_translate(ES, m_address_size ? REG32(EDI) : REG16(DI), 0 ); + src = READ16(eas); + dst = REG16(AX); + SUB16(dst, src); + BUMP_DI(2); + CYCLES(CYCLES_SCAS); +} + +void i386_device::i386_shld16_i8() // Opcode 0x0f a4 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + UINT16 dst = LOAD_RM16(modrm); + UINT16 upper = LOAD_REG16(modrm); + UINT8 shift = FETCH(); + shift &= 31; + if( shift == 0 ) { + } else if( shift > 15 ) { + m_CF = (upper & (1 << (16-shift))) ? 1 : 0; + // ppro and above should be (dst >> (32-shift)) + dst = (upper << (shift-16)) | (upper >> (32-shift)); + m_OF = m_CF ^ (dst >> 15); + SetSZPF16(dst); + } else { + m_CF = (dst & (1 << (16-shift))) ? 1 : 0; + dst = (dst << shift) | (upper >> (16-shift)); + m_OF = m_CF ^ (dst >> 15); + SetSZPF16(dst); + } + STORE_RM16(modrm, dst); + CYCLES(CYCLES_SHLD_REG); + } else { + UINT32 ea = GetEA(modrm,1); + UINT16 dst = READ16(ea); + UINT16 upper = LOAD_REG16(modrm); + UINT8 shift = FETCH(); + shift &= 31; + if( shift == 0 ) { + } else if( shift > 15 ) { + m_CF = (upper & (1 << (16-shift))) ? 1 : 0; + dst = (upper << (shift-16)) | (upper >> (32-shift)); + m_OF = m_CF ^ (dst >> 15); + SetSZPF16(dst); + } else { + m_CF = (dst & (1 << (16-shift))) ? 1 : 0; + dst = (dst << shift) | (upper >> (16-shift)); + m_OF = m_CF ^ (dst >> 15); + SetSZPF16(dst); + } + WRITE16(ea, dst); + CYCLES(CYCLES_SHLD_MEM); + } +} + +void i386_device::i386_shld16_cl() // Opcode 0x0f a5 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + UINT16 dst = LOAD_RM16(modrm); + UINT16 upper = LOAD_REG16(modrm); + UINT8 shift = REG8(CL); + shift &= 31; + if( shift == 0 ) { + } else if( shift > 15 ) { + m_CF = (upper & (1 << (16-shift))) ? 1 : 0; + dst = (upper << (shift-16)) | (upper >> (32-shift)); + m_OF = m_CF ^ (dst >> 15); + SetSZPF16(dst); + } else { + m_CF = (dst & (1 << (16-shift))) ? 1 : 0; + dst = (dst << shift) | (upper >> (16-shift)); + m_OF = m_CF ^ (dst >> 15); + SetSZPF16(dst); + } + STORE_RM16(modrm, dst); + CYCLES(CYCLES_SHLD_REG); + } else { + UINT32 ea = GetEA(modrm,1); + UINT16 dst = READ16(ea); + UINT16 upper = LOAD_REG16(modrm); + UINT8 shift = REG8(CL); + shift &= 31; + if( shift == 0 ) { + } else if( shift > 15 ) { + m_CF = (upper & (1 << (16-shift))) ? 1 : 0; + dst = (upper << (shift-16)) | (upper >> (32-shift)); + m_OF = m_CF ^ (dst >> 15); + SetSZPF16(dst); + } else { + m_CF = (dst & (1 << (16-shift))) ? 1 : 0; + dst = (dst << shift) | (upper >> (16-shift)); + m_OF = m_CF ^ (dst >> 15); + SetSZPF16(dst); + } + WRITE16(ea, dst); + CYCLES(CYCLES_SHLD_MEM); + } +} + +void i386_device::i386_shrd16_i8() // Opcode 0x0f ac +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + UINT16 dst = LOAD_RM16(modrm); + UINT16 upper = LOAD_REG16(modrm); + UINT8 shift = FETCH(); + shift &= 31; + if( shift == 0) { + } else if( shift > 15 ) { + m_CF = (upper & (1 << (shift-1))) ? 1 : 0; + dst = (upper >> (shift-16)) | (upper << (32-shift)); + m_OF = ((dst >> 15) ^ (dst >> 14)) & 1; + SetSZPF16(dst); + } else { + m_CF = (dst & (1 << (shift-1))) ? 1 : 0; + dst = (dst >> shift) | (upper << (16-shift)); + m_OF = ((dst >> 15) ^ (dst >> 14)) & 1; + SetSZPF16(dst); + } + STORE_RM16(modrm, dst); + CYCLES(CYCLES_SHRD_REG); + } else { + UINT32 ea = GetEA(modrm,1); + UINT16 dst = READ16(ea); + UINT16 upper = LOAD_REG16(modrm); + UINT8 shift = FETCH(); + shift &= 31; + if( shift == 0) { + } else if( shift > 15 ) { + m_CF = (upper & (1 << (shift-1))) ? 1 : 0; + dst = (upper >> (shift-16)) | (upper << (32-shift)); + m_OF = ((dst >> 15) ^ (dst >> 14)) & 1; + SetSZPF16(dst); + } else { + m_CF = (dst & (1 << (shift-1))) ? 1 : 0; + dst = (dst >> shift) | (upper << (16-shift)); + m_OF = ((dst >> 15) ^ (dst >> 14)) & 1; + SetSZPF16(dst); + } + WRITE16(ea, dst); + CYCLES(CYCLES_SHRD_MEM); + } +} + +void i386_device::i386_shrd16_cl() // Opcode 0x0f ad +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + UINT16 dst = LOAD_RM16(modrm); + UINT16 upper = LOAD_REG16(modrm); + UINT8 shift = REG8(CL); + shift &= 31; + if( shift == 0) { + } else if( shift > 15 ) { + m_CF = (upper & (1 << (shift-1))) ? 1 : 0; + dst = (upper >> (shift-16)) | (upper << (32-shift)); + m_OF = ((dst >> 15) ^ (dst >> 14)) & 1; + SetSZPF16(dst); + } else { + m_CF = (dst & (1 << (shift-1))) ? 1 : 0; + dst = (dst >> shift) | (upper << (16-shift)); + m_OF = ((dst >> 15) ^ (dst >> 14)) & 1; + SetSZPF16(dst); + } + STORE_RM16(modrm, dst); + CYCLES(CYCLES_SHRD_REG); + } else { + UINT32 ea = GetEA(modrm,1); + UINT16 dst = READ16(ea); + UINT16 upper = LOAD_REG16(modrm); + UINT8 shift = REG8(CL); + shift &= 31; + if( shift == 0) { + } else if( shift > 15 ) { + m_CF = (upper & (1 << (shift-1))) ? 1 : 0; + dst = (upper >> (shift-16)) | (upper << (32-shift)); + m_OF = ((dst >> 15) ^ (dst >> 14)) & 1; + SetSZPF16(dst); + } else { + m_CF = (dst & (1 << (shift-1))) ? 1 : 0; + dst = (dst >> shift) | (upper << (16-shift)); + m_OF = ((dst >> 15) ^ (dst >> 14)) & 1; + SetSZPF16(dst); + } + WRITE16(ea, dst); + CYCLES(CYCLES_SHRD_MEM); + } +} + +void i386_device::i386_stosw() // Opcode 0xab +{ + UINT32 ead; + ead = i386_translate(ES, m_address_size ? REG32(EDI) : REG16(DI), 1 ); + WRITE16(ead, REG16(AX)); + BUMP_DI(2); + CYCLES(CYCLES_STOS); +} + +void i386_device::i386_sub_rm16_r16() // Opcode 0x29 +{ + UINT16 src, dst; + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + src = LOAD_REG16(modrm); + dst = LOAD_RM16(modrm); + dst = SUB16(dst, src); + STORE_RM16(modrm, dst); + CYCLES(CYCLES_ALU_REG_REG); + } else { + UINT32 ea = GetEA(modrm,1); + src = LOAD_REG16(modrm); + dst = READ16(ea); + dst = SUB16(dst, src); + WRITE16(ea, dst); + CYCLES(CYCLES_ALU_REG_MEM); + } +} + +void i386_device::i386_sub_r16_rm16() // Opcode 0x2b +{ + UINT16 src, dst; + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + src = LOAD_RM16(modrm); + dst = LOAD_REG16(modrm); + dst = SUB16(dst, src); + STORE_REG16(modrm, dst); + CYCLES(CYCLES_ALU_REG_REG); + } else { + UINT32 ea = GetEA(modrm,0); + src = READ16(ea); + dst = LOAD_REG16(modrm); + dst = SUB16(dst, src); + STORE_REG16(modrm, dst); + CYCLES(CYCLES_ALU_MEM_REG); + } +} + +void i386_device::i386_sub_ax_i16() // Opcode 0x2d +{ + UINT16 src, dst; + src = FETCH16(); + dst = REG16(AX); + dst = SUB16(dst, src); + REG16(AX) = dst; + CYCLES(CYCLES_ALU_IMM_ACC); +} + +void i386_device::i386_test_ax_i16() // Opcode 0xa9 +{ + UINT16 src = FETCH16(); + UINT16 dst = REG16(AX); + dst = src & dst; + SetSZPF16(dst); + m_CF = 0; + m_OF = 0; + CYCLES(CYCLES_TEST_IMM_ACC); +} + +void i386_device::i386_test_rm16_r16() // Opcode 0x85 +{ + UINT16 src, dst; + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + src = LOAD_REG16(modrm); + dst = LOAD_RM16(modrm); + dst = src & dst; + SetSZPF16(dst); + m_CF = 0; + m_OF = 0; + CYCLES(CYCLES_TEST_REG_REG); + } else { + UINT32 ea = GetEA(modrm,0); + src = LOAD_REG16(modrm); + dst = READ16(ea); + dst = src & dst; + SetSZPF16(dst); + m_CF = 0; + m_OF = 0; + CYCLES(CYCLES_TEST_REG_MEM); + } +} + +void i386_device::i386_xchg_ax_cx() // Opcode 0x91 +{ + UINT16 temp; + temp = REG16(AX); + REG16(AX) = REG16(CX); + REG16(CX) = temp; + CYCLES(CYCLES_XCHG_REG_REG); +} + +void i386_device::i386_xchg_ax_dx() // Opcode 0x92 +{ + UINT16 temp; + temp = REG16(AX); + REG16(AX) = REG16(DX); + REG16(DX) = temp; + CYCLES(CYCLES_XCHG_REG_REG); +} + +void i386_device::i386_xchg_ax_bx() // Opcode 0x93 +{ + UINT16 temp; + temp = REG16(AX); + REG16(AX) = REG16(BX); + REG16(BX) = temp; + CYCLES(CYCLES_XCHG_REG_REG); +} + +void i386_device::i386_xchg_ax_sp() // Opcode 0x94 +{ + UINT16 temp; + temp = REG16(AX); + REG16(AX) = REG16(SP); + REG16(SP) = temp; + CYCLES(CYCLES_XCHG_REG_REG); +} + +void i386_device::i386_xchg_ax_bp() // Opcode 0x95 +{ + UINT16 temp; + temp = REG16(AX); + REG16(AX) = REG16(BP); + REG16(BP) = temp; + CYCLES(CYCLES_XCHG_REG_REG); +} + +void i386_device::i386_xchg_ax_si() // Opcode 0x96 +{ + UINT16 temp; + temp = REG16(AX); + REG16(AX) = REG16(SI); + REG16(SI) = temp; + CYCLES(CYCLES_XCHG_REG_REG); +} + +void i386_device::i386_xchg_ax_di() // Opcode 0x97 +{ + UINT16 temp; + temp = REG16(AX); + REG16(AX) = REG16(DI); + REG16(DI) = temp; + CYCLES(CYCLES_XCHG_REG_REG); +} + +void i386_device::i386_xchg_r16_rm16() // Opcode 0x87 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + UINT16 src = LOAD_RM16(modrm); + UINT16 dst = LOAD_REG16(modrm); + STORE_REG16(modrm, src); + STORE_RM16(modrm, dst); + CYCLES(CYCLES_XCHG_REG_REG); + } else { + UINT32 ea = GetEA(modrm,1); + UINT16 src = READ16(ea); + UINT16 dst = LOAD_REG16(modrm); + STORE_REG16(modrm, src); + WRITE16(ea, dst); + CYCLES(CYCLES_XCHG_REG_MEM); + } +} + +void i386_device::i386_xor_rm16_r16() // Opcode 0x31 +{ + UINT16 src, dst; + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + src = LOAD_REG16(modrm); + dst = LOAD_RM16(modrm); + dst = XOR16(dst, src); + STORE_RM16(modrm, dst); + CYCLES(CYCLES_ALU_REG_REG); + } else { + UINT32 ea = GetEA(modrm,1); + src = LOAD_REG16(modrm); + dst = READ16(ea); + dst = XOR16(dst, src); + WRITE16(ea, dst); + CYCLES(CYCLES_ALU_REG_MEM); + } +} + +void i386_device::i386_xor_r16_rm16() // Opcode 0x33 +{ + UINT16 src, dst; + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + src = LOAD_RM16(modrm); + dst = LOAD_REG16(modrm); + dst = XOR16(dst, src); + STORE_REG16(modrm, dst); + CYCLES(CYCLES_ALU_REG_REG); + } else { + UINT32 ea = GetEA(modrm,0); + src = READ16(ea); + dst = LOAD_REG16(modrm); + dst = XOR16(dst, src); + STORE_REG16(modrm, dst); + CYCLES(CYCLES_ALU_MEM_REG); + } +} + +void i386_device::i386_xor_ax_i16() // Opcode 0x35 +{ + UINT16 src, dst; + src = FETCH16(); + dst = REG16(AX); + dst = XOR16(dst, src); + REG16(AX) = dst; + CYCLES(CYCLES_ALU_IMM_ACC); +} + + + +void i386_device::i386_group81_16() // Opcode 0x81 +{ + UINT32 ea; + UINT16 src, dst; + UINT8 modrm = FETCH(); + + switch( (modrm >> 3) & 0x7 ) + { + case 0: // ADD Rm16, i16 + if( modrm >= 0xc0 ) { + dst = LOAD_RM16(modrm); + src = FETCH16(); + dst = ADD16(dst, src); + STORE_RM16(modrm, dst); + CYCLES(CYCLES_ALU_REG_REG); + } else { + ea = GetEA(modrm,1); + dst = READ16(ea); + src = FETCH16(); + dst = ADD16(dst, src); + WRITE16(ea, dst); + CYCLES(CYCLES_ALU_REG_MEM); + } + break; + case 1: // OR Rm16, i16 + if( modrm >= 0xc0 ) { + dst = LOAD_RM16(modrm); + src = FETCH16(); + dst = OR16(dst, src); + STORE_RM16(modrm, dst); + CYCLES(CYCLES_ALU_REG_REG); + } else { + ea = GetEA(modrm,1); + dst = READ16(ea); + src = FETCH16(); + dst = OR16(dst, src); + WRITE16(ea, dst); + CYCLES(CYCLES_ALU_REG_MEM); + } + break; + case 2: // ADC Rm16, i16 + if( modrm >= 0xc0 ) { + dst = LOAD_RM16(modrm); + src = FETCH16(); + dst = ADC16(dst, src, m_CF); + STORE_RM16(modrm, dst); + CYCLES(CYCLES_ALU_REG_REG); + } else { + ea = GetEA(modrm,1); + dst = READ16(ea); + src = FETCH16(); + dst = ADC16(dst, src, m_CF); + WRITE16(ea, dst); + CYCLES(CYCLES_ALU_REG_MEM); + } + break; + case 3: // SBB Rm16, i16 + if( modrm >= 0xc0 ) { + dst = LOAD_RM16(modrm); + src = FETCH16(); + dst = SBB16(dst, src, m_CF); + STORE_RM16(modrm, dst); + CYCLES(CYCLES_ALU_REG_REG); + } else { + ea = GetEA(modrm,1); + dst = READ16(ea); + src = FETCH16(); + dst = SBB16(dst, src, m_CF); + WRITE16(ea, dst); + CYCLES(CYCLES_ALU_REG_MEM); + } + break; + case 4: // AND Rm16, i16 + if( modrm >= 0xc0 ) { + dst = LOAD_RM16(modrm); + src = FETCH16(); + dst = AND16(dst, src); + STORE_RM16(modrm, dst); + CYCLES(CYCLES_ALU_REG_REG); + } else { + ea = GetEA(modrm,1); + dst = READ16(ea); + src = FETCH16(); + dst = AND16(dst, src); + WRITE16(ea, dst); + CYCLES(CYCLES_ALU_REG_MEM); + } + break; + case 5: // SUB Rm16, i16 + if( modrm >= 0xc0 ) { + dst = LOAD_RM16(modrm); + src = FETCH16(); + dst = SUB16(dst, src); + STORE_RM16(modrm, dst); + CYCLES(CYCLES_ALU_REG_REG); + } else { + ea = GetEA(modrm,1); + dst = READ16(ea); + src = FETCH16(); + dst = SUB16(dst, src); + WRITE16(ea, dst); + CYCLES(CYCLES_ALU_REG_MEM); + } + break; + case 6: // XOR Rm16, i16 + if( modrm >= 0xc0 ) { + dst = LOAD_RM16(modrm); + src = FETCH16(); + dst = XOR16(dst, src); + STORE_RM16(modrm, dst); + CYCLES(CYCLES_ALU_REG_REG); + } else { + ea = GetEA(modrm,1); + dst = READ16(ea); + src = FETCH16(); + dst = XOR16(dst, src); + WRITE16(ea, dst); + CYCLES(CYCLES_ALU_REG_MEM); + } + break; + case 7: // CMP Rm16, i16 + if( modrm >= 0xc0 ) { + dst = LOAD_RM16(modrm); + src = FETCH16(); + SUB16(dst, src); + CYCLES(CYCLES_CMP_REG_REG); + } else { + ea = GetEA(modrm,0); + dst = READ16(ea); + src = FETCH16(); + SUB16(dst, src); + CYCLES(CYCLES_CMP_REG_MEM); + } + break; + } +} + +void i386_device::i386_group83_16() // Opcode 0x83 +{ + UINT32 ea; + UINT16 src, dst; + UINT8 modrm = FETCH(); + + switch( (modrm >> 3) & 0x7 ) + { + case 0: // ADD Rm16, i16 + if( modrm >= 0xc0 ) { + dst = LOAD_RM16(modrm); + src = (UINT16)(INT16)(INT8)FETCH(); + dst = ADD16(dst, src); + STORE_RM16(modrm, dst); + CYCLES(CYCLES_ALU_REG_REG); + } else { + ea = GetEA(modrm,1); + dst = READ16(ea); + src = (UINT16)(INT16)(INT8)FETCH(); + dst = ADD16(dst, src); + WRITE16(ea, dst); + CYCLES(CYCLES_ALU_REG_MEM); + } + break; + case 1: // OR Rm16, i16 + if( modrm >= 0xc0 ) { + dst = LOAD_RM16(modrm); + src = (UINT16)(INT16)(INT8)FETCH(); + dst = OR16(dst, src); + STORE_RM16(modrm, dst); + CYCLES(CYCLES_ALU_REG_REG); + } else { + ea = GetEA(modrm,1); + dst = READ16(ea); + src = (UINT16)(INT16)(INT8)FETCH(); + dst = OR16(dst, src); + WRITE16(ea, dst); + CYCLES(CYCLES_ALU_REG_MEM); + } + break; + case 2: // ADC Rm16, i16 + if( modrm >= 0xc0 ) { + dst = LOAD_RM16(modrm); + src = (UINT16)(INT16)(INT8)FETCH(); + dst = ADC16(dst, src, m_CF); + STORE_RM16(modrm, dst); + CYCLES(CYCLES_ALU_REG_REG); + } else { + ea = GetEA(modrm,1); + dst = READ16(ea); + src = (UINT16)(INT16)(INT8)FETCH(); + dst = ADC16(dst, src, m_CF); + WRITE16(ea, dst); + CYCLES(CYCLES_ALU_REG_MEM); + } + break; + case 3: // SBB Rm16, i16 + if( modrm >= 0xc0 ) { + dst = LOAD_RM16(modrm); + src = ((UINT16)(INT16)(INT8)FETCH()); + dst = SBB16(dst, src, m_CF); + STORE_RM16(modrm, dst); + CYCLES(CYCLES_ALU_REG_REG); + } else { + ea = GetEA(modrm,1); + dst = READ16(ea); + src = ((UINT16)(INT16)(INT8)FETCH()); + dst = SBB16(dst, src, m_CF); + WRITE16(ea, dst); + CYCLES(CYCLES_ALU_REG_MEM); + } + break; + case 4: // AND Rm16, i16 + if( modrm >= 0xc0 ) { + dst = LOAD_RM16(modrm); + src = (UINT16)(INT16)(INT8)FETCH(); + dst = AND16(dst, src); + STORE_RM16(modrm, dst); + CYCLES(CYCLES_ALU_REG_REG); + } else { + ea = GetEA(modrm,1); + dst = READ16(ea); + src = (UINT16)(INT16)(INT8)FETCH(); + dst = AND16(dst, src); + WRITE16(ea, dst); + CYCLES(CYCLES_ALU_REG_MEM); + } + break; + case 5: // SUB Rm16, i16 + if( modrm >= 0xc0 ) { + dst = LOAD_RM16(modrm); + src = (UINT16)(INT16)(INT8)FETCH(); + dst = SUB16(dst, src); + STORE_RM16(modrm, dst); + CYCLES(CYCLES_ALU_REG_REG); + } else { + ea = GetEA(modrm,1); + dst = READ16(ea); + src = (UINT16)(INT16)(INT8)FETCH(); + dst = SUB16(dst, src); + WRITE16(ea, dst); + CYCLES(CYCLES_ALU_REG_MEM); + } + break; + case 6: // XOR Rm16, i16 + if( modrm >= 0xc0 ) { + dst = LOAD_RM16(modrm); + src = (UINT16)(INT16)(INT8)FETCH(); + dst = XOR16(dst, src); + STORE_RM16(modrm, dst); + CYCLES(CYCLES_ALU_REG_REG); + } else { + ea = GetEA(modrm,1); + dst = READ16(ea); + src = (UINT16)(INT16)(INT8)FETCH(); + dst = XOR16(dst, src); + WRITE16(ea, dst); + CYCLES(CYCLES_ALU_REG_MEM); + } + break; + case 7: // CMP Rm16, i16 + if( modrm >= 0xc0 ) { + dst = LOAD_RM16(modrm); + src = (UINT16)(INT16)(INT8)FETCH(); + SUB16(dst, src); + CYCLES(CYCLES_CMP_REG_REG); + } else { + ea = GetEA(modrm,0); + dst = READ16(ea); + src = (UINT16)(INT16)(INT8)FETCH(); + SUB16(dst, src); + CYCLES(CYCLES_CMP_REG_MEM); + } + break; + } +} + +void i386_device::i386_groupC1_16() // Opcode 0xc1 +{ + UINT16 dst; + UINT8 modrm = FETCH(); + UINT8 shift; + + if( modrm >= 0xc0 ) { + dst = LOAD_RM16(modrm); + shift = FETCH() & 0x1f; + dst = i386_shift_rotate16(modrm, dst, shift); + STORE_RM16(modrm, dst); + } else { + UINT32 ea = GetEA(modrm,1); + dst = READ16(ea); + shift = FETCH() & 0x1f; + dst = i386_shift_rotate16(modrm, dst, shift); + WRITE16(ea, dst); + } +} + +void i386_device::i386_groupD1_16() // Opcode 0xd1 +{ + UINT16 dst; + UINT8 modrm = FETCH(); + + if( modrm >= 0xc0 ) { + dst = LOAD_RM16(modrm); + dst = i386_shift_rotate16(modrm, dst, 1); + STORE_RM16(modrm, dst); + } else { + UINT32 ea = GetEA(modrm,1); + dst = READ16(ea); + dst = i386_shift_rotate16(modrm, dst, 1); + WRITE16(ea, dst); + } +} + +void i386_device::i386_groupD3_16() // Opcode 0xd3 +{ + UINT16 dst; + UINT8 modrm = FETCH(); + + if( modrm >= 0xc0 ) { + dst = LOAD_RM16(modrm); + dst = i386_shift_rotate16(modrm, dst, REG8(CL)); + STORE_RM16(modrm, dst); + } else { + UINT32 ea = GetEA(modrm,1); + dst = READ16(ea); + dst = i386_shift_rotate16(modrm, dst, REG8(CL)); + WRITE16(ea, dst); + } +} + +void i386_device::i386_groupF7_16() // Opcode 0xf7 +{ + UINT8 modrm = FETCH(); + + switch( (modrm >> 3) & 0x7 ) + { + case 0: /* TEST Rm16, i16 */ + if( modrm >= 0xc0 ) { + UINT16 dst = LOAD_RM16(modrm); + UINT16 src = FETCH16(); + dst &= src; + m_CF = m_OF = m_AF = 0; + SetSZPF16(dst); + CYCLES(CYCLES_TEST_IMM_REG); + } else { + UINT32 ea = GetEA(modrm,0); + UINT16 dst = READ16(ea); + UINT16 src = FETCH16(); + dst &= src; + m_CF = m_OF = m_AF = 0; + SetSZPF16(dst); + CYCLES(CYCLES_TEST_IMM_MEM); + } + break; + case 2: /* NOT Rm16 */ + if( modrm >= 0xc0 ) { + UINT16 dst = LOAD_RM16(modrm); + dst = ~dst; + STORE_RM16(modrm, dst); + CYCLES(CYCLES_NOT_REG); + } else { + UINT32 ea = GetEA(modrm,1); + UINT16 dst = READ16(ea); + dst = ~dst; + WRITE16(ea, dst); + CYCLES(CYCLES_NOT_MEM); + } + break; + case 3: /* NEG Rm16 */ + if( modrm >= 0xc0 ) { + UINT16 dst = LOAD_RM16(modrm); + dst = SUB16(0, dst ); + STORE_RM16(modrm, dst); + CYCLES(CYCLES_NEG_REG); + } else { + UINT32 ea = GetEA(modrm,1); + UINT16 dst = READ16(ea); + dst = SUB16(0, dst ); + WRITE16(ea, dst); + CYCLES(CYCLES_NEG_MEM); + } + break; + case 4: /* MUL AX, Rm16 */ + { + UINT32 result; + UINT16 src, dst; + if( modrm >= 0xc0 ) { + src = LOAD_RM16(modrm); + CYCLES(CYCLES_MUL16_ACC_REG); /* TODO: Correct multiply timing */ + } else { + UINT32 ea = GetEA(modrm,0); + src = READ16(ea); + CYCLES(CYCLES_MUL16_ACC_MEM); /* TODO: Correct multiply timing */ + } + + dst = REG16(AX); + result = (UINT32)src * (UINT32)dst; + REG16(DX) = (UINT16)(result >> 16); + REG16(AX) = (UINT16)result; + + m_CF = m_OF = (REG16(DX) != 0); + } + break; + case 5: /* IMUL AX, Rm16 */ + { + INT32 result; + INT32 src, dst; + if( modrm >= 0xc0 ) { + src = (INT32)(INT16)LOAD_RM16(modrm); + CYCLES(CYCLES_IMUL16_ACC_REG); /* TODO: Correct multiply timing */ + } else { + UINT32 ea = GetEA(modrm,0); + src = (INT32)(INT16)READ16(ea); + CYCLES(CYCLES_IMUL16_ACC_MEM); /* TODO: Correct multiply timing */ + } + + dst = (INT32)(INT16)REG16(AX); + result = src * dst; + + REG16(DX) = (UINT16)(result >> 16); + REG16(AX) = (UINT16)result; + + m_CF = m_OF = !(result == (INT32)(INT16)result); + } + break; + case 6: /* DIV AX, Rm16 */ + { + UINT32 quotient, remainder, result; + UINT16 src; + if( modrm >= 0xc0 ) { + src = LOAD_RM16(modrm); + CYCLES(CYCLES_DIV16_ACC_REG); + } else { + UINT32 ea = GetEA(modrm,0); + src = READ16(ea); + CYCLES(CYCLES_DIV16_ACC_MEM); + } + + quotient = ((UINT32)(REG16(DX)) << 16) | (UINT32)(REG16(AX)); + if( src ) { + remainder = quotient % (UINT32)src; + result = quotient / (UINT32)src; + if( result > 0xffff ) { + /* TODO: Divide error */ + } else { + REG16(DX) = (UINT16)remainder; + REG16(AX) = (UINT16)result; + + // this flag is actually undefined, enable on non-cyrix + if (m_cpuid_id0 != 0x69727943) + m_CF = 1; + } + } else { + i386_trap(0, 0, 0); + } + } + break; + case 7: /* IDIV AX, Rm16 */ + { + INT32 quotient, remainder, result; + UINT16 src; + if( modrm >= 0xc0 ) { + src = LOAD_RM16(modrm); + CYCLES(CYCLES_IDIV16_ACC_REG); + } else { + UINT32 ea = GetEA(modrm,0); + src = READ16(ea); + CYCLES(CYCLES_IDIV16_ACC_MEM); + } + + quotient = (((INT32)REG16(DX)) << 16) | ((UINT32)REG16(AX)); + if( src ) { + remainder = quotient % (INT32)(INT16)src; + result = quotient / (INT32)(INT16)src; + if( result > 0xffff ) { + /* TODO: Divide error */ + } else { + REG16(DX) = (UINT16)remainder; + REG16(AX) = (UINT16)result; + + // this flag is actually undefined, enable on non-cyrix + if (m_cpuid_id0 != 0x69727943) + m_CF = 1; + } + } else { + i386_trap(0, 0, 0); + } + } + break; + } +} + +void i386_device::i386_groupFF_16() // Opcode 0xff +{ + UINT8 modrm = FETCH(); + + switch( (modrm >> 3) & 0x7 ) + { + case 0: /* INC Rm16 */ + if( modrm >= 0xc0 ) { + UINT16 dst = LOAD_RM16(modrm); + dst = INC16(dst); + STORE_RM16(modrm, dst); + CYCLES(CYCLES_INC_REG); + } else { + UINT32 ea = GetEA(modrm,1); + UINT16 dst = READ16(ea); + dst = INC16(dst); + WRITE16(ea, dst); + CYCLES(CYCLES_INC_MEM); + } + break; + case 1: /* DEC Rm16 */ + if( modrm >= 0xc0 ) { + UINT16 dst = LOAD_RM16(modrm); + dst = DEC16(dst); + STORE_RM16(modrm, dst); + CYCLES(CYCLES_DEC_REG); + } else { + UINT32 ea = GetEA(modrm,1); + UINT16 dst = READ16(ea); + dst = DEC16(dst); + WRITE16(ea, dst); + CYCLES(CYCLES_DEC_MEM); + } + break; + case 2: /* CALL Rm16 */ + { + UINT16 address; + if( modrm >= 0xc0 ) { + address = LOAD_RM16(modrm); + CYCLES(CYCLES_CALL_REG); /* TODO: Timing = 7 + m */ + } else { + UINT32 ea = GetEA(modrm,0); + address = READ16(ea); + CYCLES(CYCLES_CALL_MEM); /* TODO: Timing = 10 + m */ + } + PUSH16(m_eip ); + m_eip = address; + CHANGE_PC(m_eip); + } + break; + case 3: /* CALL FAR Rm16 */ + { + UINT16 address, selector; + if( modrm >= 0xc0 ) + { + report_invalid_modrm("groupFF_16", modrm); + } + else + { + UINT32 ea = GetEA(modrm,0); + address = READ16(ea + 0); + selector = READ16(ea + 2); + CYCLES(CYCLES_CALL_MEM_INTERSEG); /* TODO: Timing = 10 + m */ + + if(PROTECTED_MODE && !V8086_MODE) + { + i386_protected_mode_call(selector,address,1,0); + } + else + { + PUSH16(m_sreg[CS].selector ); + PUSH16(m_eip ); + m_sreg[CS].selector = selector; + m_performed_intersegment_jump = 1; + i386_load_segment_descriptor(CS ); + m_eip = address; + CHANGE_PC(m_eip); + } + } + } + break; + case 4: /* JMP Rm16 */ + { + UINT16 address; + if( modrm >= 0xc0 ) { + address = LOAD_RM16(modrm); + CYCLES(CYCLES_JMP_REG); /* TODO: Timing = 7 + m */ + } else { + UINT32 ea = GetEA(modrm,0); + address = READ16(ea); + CYCLES(CYCLES_JMP_MEM); /* TODO: Timing = 10 + m */ + } + m_eip = address; + CHANGE_PC(m_eip); + } + break; + case 5: /* JMP FAR Rm16 */ + { + UINT16 address, selector; + + if( modrm >= 0xc0 ) + { + report_invalid_modrm("groupFF_16", modrm); + } + else + { + UINT32 ea = GetEA(modrm,0); + address = READ16(ea + 0); + selector = READ16(ea + 2); + CYCLES(CYCLES_JMP_MEM_INTERSEG); /* TODO: Timing = 10 + m */ + if(PROTECTED_MODE && !V8086_MODE) + { + i386_protected_mode_jump(selector,address,1,0); + } + else + { + m_sreg[CS].selector = selector; + m_performed_intersegment_jump = 1; + i386_load_segment_descriptor(CS ); + m_eip = address; + CHANGE_PC(m_eip); + } + } + } + break; + case 6: /* PUSH Rm16 */ + { + UINT16 value; + if( modrm >= 0xc0 ) { + value = LOAD_RM16(modrm); + } else { + UINT32 ea = GetEA(modrm,0); + value = READ16(ea); + } + PUSH16(value); + CYCLES(CYCLES_PUSH_RM); + } + break; + default: + report_invalid_modrm("groupFF_16", modrm); + break; + } +} + +void i386_device::i386_group0F00_16() // Opcode 0x0f 00 +{ + UINT32 address, ea; + UINT8 modrm = FETCH(); + I386_SREG seg; + UINT8 result; + + switch( (modrm >> 3) & 0x7 ) + { + case 0: /* SLDT */ + if ( PROTECTED_MODE && !V8086_MODE ) + { + if( modrm >= 0xc0 ) { + STORE_RM16(modrm, m_ldtr.segment); + CYCLES(CYCLES_SLDT_REG); + } else { + ea = GetEA(modrm,1); + WRITE16(ea, m_ldtr.segment); + CYCLES(CYCLES_SLDT_MEM); + } + } + else + { + i386_trap(6, 0, 0); + } + break; + case 1: /* STR */ + if ( PROTECTED_MODE && !V8086_MODE ) + { + if( modrm >= 0xc0 ) { + STORE_RM16(modrm, m_task.segment); + CYCLES(CYCLES_STR_REG); + } else { + ea = GetEA(modrm,1); + WRITE16(ea, m_task.segment); + CYCLES(CYCLES_STR_MEM); + } + } + else + { + i386_trap(6, 0, 0); + } + break; + case 2: /* LLDT */ + if ( PROTECTED_MODE && !V8086_MODE ) + { + if(m_CPL) + FAULT(FAULT_GP,0) + if( modrm >= 0xc0 ) { + address = LOAD_RM16(modrm); + m_ldtr.segment = address; + CYCLES(CYCLES_LLDT_REG); + } else { + ea = GetEA(modrm,0); + m_ldtr.segment = READ16(ea); + CYCLES(CYCLES_LLDT_MEM); + } + memset(&seg, 0, sizeof(seg)); + seg.selector = m_ldtr.segment; + i386_load_protected_mode_segment(&seg,NULL); + m_ldtr.limit = seg.limit; + m_ldtr.base = seg.base; + m_ldtr.flags = seg.flags; + } + else + { + i386_trap(6, 0, 0); + } + break; + + case 3: /* LTR */ + if ( PROTECTED_MODE && !V8086_MODE ) + { + if(m_CPL) + FAULT(FAULT_GP,0) + if( modrm >= 0xc0 ) { + address = LOAD_RM16(modrm); + m_task.segment = address; + CYCLES(CYCLES_LTR_REG); + } else { + ea = GetEA(modrm,0); + m_task.segment = READ16(ea); + CYCLES(CYCLES_LTR_MEM); + } + memset(&seg, 0, sizeof(seg)); + seg.selector = m_task.segment; + i386_load_protected_mode_segment(&seg,NULL); + + UINT32 addr = ((seg.selector & 4) ? m_ldtr.base : m_gdtr.base) + (seg.selector & ~7) + 5; + i386_translate_address(TRANSLATE_READ, &addr, NULL); + m_program->write_byte(addr, (seg.flags & 0xff) | 2); + + m_task.limit = seg.limit; + m_task.base = seg.base; + m_task.flags = seg.flags | 2; + } + else + { + i386_trap(6, 0, 0); + } + break; + + case 4: /* VERR */ + if ( PROTECTED_MODE && !V8086_MODE ) + { + result = 1; + if( modrm >= 0xc0 ) { + address = LOAD_RM16(modrm); + CYCLES(CYCLES_VERR_REG); + } else { + ea = GetEA(modrm,0); + address = READ16(ea); + CYCLES(CYCLES_VERR_MEM); + } + memset(&seg, 0, sizeof(seg)); + seg.selector = address; + result = i386_load_protected_mode_segment(&seg,NULL); + // check if the segment is a code or data segment (not a special segment type, like a TSS, gate, LDT...) + if(!(seg.flags & 0x10)) + result = 0; + // check that the segment is readable + if(seg.flags & 0x10) // is code or data segment + { + if(seg.flags & 0x08) // is code segment, so check if it's readable + { + if(!(seg.flags & 0x02)) + { + result = 0; + } + else + { // check if conforming, these are always readable, regardless of privilege + if(!(seg.flags & 0x04)) + { + // if not conforming, then we must check privilege levels (TODO: current privilege level check) + if(((seg.flags >> 5) & 0x03) < (address & 0x03)) + result = 0; + } + } + } + } + // check that the descriptor privilege is greater or equal to the selector's privilege level and the current privilege (TODO) + SetZF(result); + } + else + { + i386_trap(6, 0, 0); + logerror("i386: VERR: Exception - Running in real mode or virtual 8086 mode.\n"); + } + break; + + case 5: /* VERW */ + if ( PROTECTED_MODE && !V8086_MODE ) + { + result = 1; + if( modrm >= 0xc0 ) { + address = LOAD_RM16(modrm); + CYCLES(CYCLES_VERW_REG); + } else { + ea = GetEA(modrm,0); + address = READ16(ea); + CYCLES(CYCLES_VERW_MEM); + } + memset(&seg, 0, sizeof(seg)); + seg.selector = address; + result = i386_load_protected_mode_segment(&seg,NULL); + // check if the segment is a code or data segment (not a special segment type, like a TSS, gate, LDT...) + if(!(seg.flags & 0x10)) + result = 0; + // check that the segment is writable + if(seg.flags & 0x10) // is code or data segment + { + if(seg.flags & 0x08) // is code segment (and thus, not writable) + { + result = 0; + } + else + { // is data segment + if(!(seg.flags & 0x02)) + result = 0; + } + } + // check that the descriptor privilege is greater or equal to the selector's privilege level and the current privilege (TODO) + if(((seg.flags >> 5) & 0x03) < (address & 0x03)) + result = 0; + SetZF(result); + } + else + { + i386_trap(6, 0, 0); + logerror("i386: VERW: Exception - Running in real mode or virtual 8086 mode.\n"); + } + break; + + default: + report_invalid_modrm("group0F00_16", modrm); + break; + } +} + +void i386_device::i386_group0F01_16() // Opcode 0x0f 01 +{ + UINT8 modrm = FETCH(); + UINT16 address; + UINT32 ea; + + switch( (modrm >> 3) & 0x7 ) + { + case 0: /* SGDT */ + { + if( modrm >= 0xc0 ) { + address = LOAD_RM16(modrm); + ea = i386_translate(CS, address, 1 ); + } else { + ea = GetEA(modrm,1); + } + WRITE16(ea, m_gdtr.limit); + WRITE32(ea + 2, m_gdtr.base); + CYCLES(CYCLES_SGDT); + break; + } + case 1: /* SIDT */ + { + if (modrm >= 0xc0) + { + address = LOAD_RM16(modrm); + ea = i386_translate(CS, address, 1 ); + } + else + { + ea = GetEA(modrm,1); + } + WRITE16(ea, m_idtr.limit); + WRITE32(ea + 2, m_idtr.base); + CYCLES(CYCLES_SIDT); + break; + } + case 2: /* LGDT */ + { + if(PROTECTED_MODE && m_CPL) + FAULT(FAULT_GP,0) + if( modrm >= 0xc0 ) { + address = LOAD_RM16(modrm); + ea = i386_translate(CS, address, 0 ); + } else { + ea = GetEA(modrm,0); + } + m_gdtr.limit = READ16(ea); + m_gdtr.base = READ32(ea + 2) & 0xffffff; + CYCLES(CYCLES_LGDT); + break; + } + case 3: /* LIDT */ + { + if(PROTECTED_MODE && m_CPL) + FAULT(FAULT_GP,0) + if( modrm >= 0xc0 ) { + address = LOAD_RM16(modrm); + ea = i386_translate(CS, address, 0 ); + } else { + ea = GetEA(modrm,0); + } + m_idtr.limit = READ16(ea); + m_idtr.base = READ32(ea + 2) & 0xffffff; + CYCLES(CYCLES_LIDT); + break; + } + case 4: /* SMSW */ + { + if( modrm >= 0xc0 ) { + STORE_RM16(modrm, m_cr[0]); + CYCLES(CYCLES_SMSW_REG); + } else { + ea = GetEA(modrm,1); + WRITE16(ea, m_cr[0]); + CYCLES(CYCLES_SMSW_MEM); + } + break; + } + case 6: /* LMSW */ + { + if(PROTECTED_MODE && m_CPL) + FAULT(FAULT_GP,0) + UINT16 b; + if( modrm >= 0xc0 ) { + b = LOAD_RM16(modrm); + CYCLES(CYCLES_LMSW_REG); + } else { + ea = GetEA(modrm,0); + CYCLES(CYCLES_LMSW_MEM); + b = READ16(ea); + } + if(PROTECTED_MODE) + b |= 0x0001; // cannot return to real mode using this instruction. + m_cr[0] &= ~0x0000000f; + m_cr[0] |= b & 0x0000000f; + break; + } + default: + report_invalid_modrm("group0F01_16", modrm); + break; + } +} + +void i386_device::i386_group0FBA_16() // Opcode 0x0f ba +{ + UINT8 modrm = FETCH(); + + switch( (modrm >> 3) & 0x7 ) + { + case 4: /* BT Rm16, i8 */ + if( modrm >= 0xc0 ) { + UINT16 dst = LOAD_RM16(modrm); + UINT8 bit = FETCH(); + + if( dst & (1 << bit) ) + m_CF = 1; + else + m_CF = 0; + + CYCLES(CYCLES_BT_IMM_REG); + } else { + UINT32 ea = GetEA(modrm,0); + UINT16 dst = READ16(ea); + UINT8 bit = FETCH(); + + if( dst & (1 << bit) ) + m_CF = 1; + else + m_CF = 0; + + CYCLES(CYCLES_BT_IMM_MEM); + } + break; + case 5: /* BTS Rm16, i8 */ + if( modrm >= 0xc0 ) { + UINT16 dst = LOAD_RM16(modrm); + UINT8 bit = FETCH(); + + if( dst & (1 << bit) ) + m_CF = 1; + else + m_CF = 0; + dst |= (1 << bit); + + STORE_RM16(modrm, dst); + CYCLES(CYCLES_BTS_IMM_REG); + } else { + UINT32 ea = GetEA(modrm,1); + UINT16 dst = READ16(ea); + UINT8 bit = FETCH(); + + if( dst & (1 << bit) ) + m_CF = 1; + else + m_CF = 0; + dst |= (1 << bit); + + WRITE16(ea, dst); + CYCLES(CYCLES_BTS_IMM_MEM); + } + break; + case 6: /* BTR Rm16, i8 */ + if( modrm >= 0xc0 ) { + UINT16 dst = LOAD_RM16(modrm); + UINT8 bit = FETCH(); + + if( dst & (1 << bit) ) + m_CF = 1; + else + m_CF = 0; + dst &= ~(1 << bit); + + STORE_RM16(modrm, dst); + CYCLES(CYCLES_BTR_IMM_REG); + } else { + UINT32 ea = GetEA(modrm,1); + UINT16 dst = READ16(ea); + UINT8 bit = FETCH(); + + if( dst & (1 << bit) ) + m_CF = 1; + else + m_CF = 0; + dst &= ~(1 << bit); + + WRITE16(ea, dst); + CYCLES(CYCLES_BTR_IMM_MEM); + } + break; + case 7: /* BTC Rm16, i8 */ + if( modrm >= 0xc0 ) { + UINT16 dst = LOAD_RM16(modrm); + UINT8 bit = FETCH(); + + if( dst & (1 << bit) ) + m_CF = 1; + else + m_CF = 0; + dst ^= (1 << bit); + + STORE_RM16(modrm, dst); + CYCLES(CYCLES_BTC_IMM_REG); + } else { + UINT32 ea = GetEA(modrm,1); + UINT16 dst = READ16(ea); + UINT8 bit = FETCH(); + + if( dst & (1 << bit) ) + m_CF = 1; + else + m_CF = 0; + dst ^= (1 << bit); + + WRITE16(ea, dst); + CYCLES(CYCLES_BTC_IMM_MEM); + } + break; + default: + report_invalid_modrm("group0FBA_16", modrm); + break; + } +} + +void i386_device::i386_lar_r16_rm16() // Opcode 0x0f 0x02 +{ + UINT8 modrm = FETCH(); + I386_SREG seg; + UINT8 type; + + if(PROTECTED_MODE && !V8086_MODE) + { + memset(&seg,0,sizeof(seg)); + if(modrm >= 0xc0) + { + seg.selector = LOAD_RM16(modrm); + CYCLES(CYCLES_LAR_REG); + } + else + { + UINT32 ea = GetEA(modrm,0); + seg.selector = READ16(ea); + CYCLES(CYCLES_LAR_MEM); + } + if(seg.selector == 0) + { + SetZF(0); // not a valid segment + // logerror("i386 (%08x): LAR: Selector %04x is invalid type.\n",m_pc,seg.selector); + } + else + { + if(!i386_load_protected_mode_segment(&seg,NULL)) + { + SetZF(0); + return; + } + UINT8 DPL = (seg.flags >> 5) & 3; + if(((DPL < m_CPL) || (DPL < (seg.selector & 3))) && ((seg.flags & 0x1c) != 0x1c)) + { + SetZF(0); + return; + } + if(!(seg.flags & 0x10)) // special segment + { + // check for invalid segment types + type = seg.flags & 0x000f; + if(type == 0x00 || type == 0x08 || type == 0x0a || type == 0x0d) + { + SetZF(0); // invalid segment type + } + else + { + STORE_REG16(modrm,(seg.flags << 8) & 0xff00); + SetZF(1); + } + } + else + { // data or code segment (both are valid for LAR) + STORE_REG16(modrm,(seg.flags << 8) & 0xff00); + SetZF(1); + } + } + } + else + { + // illegal opcode + i386_trap(6,0, 0); + logerror("i386: LAR: Exception - running in real mode or virtual 8086 mode.\n"); + } +} + +void i386_device::i386_lsl_r16_rm16() // Opcode 0x0f 0x03 +{ + UINT8 modrm = FETCH(); + UINT32 limit; + I386_SREG seg; + + if(PROTECTED_MODE && !V8086_MODE) + { + memset(&seg, 0, sizeof(seg)); + if(modrm >= 0xc0) + { + seg.selector = LOAD_RM16(modrm); + } + else + { + UINT32 ea = GetEA(modrm,0); + seg.selector = READ16(ea); + } + if(seg.selector == 0) + { + SetZF(0); // not a valid segment + } + else + { + UINT8 type; + if(!i386_load_protected_mode_segment(&seg,NULL)) + { + SetZF(0); + return; + } + UINT8 DPL = (seg.flags >> 5) & 3; + if(((DPL < m_CPL) || (DPL < (seg.selector & 3))) && ((seg.flags & 0x1c) != 0x1c)) + { + SetZF(0); + return; + } + type = seg.flags & 0x1f; + switch(type) + { + case 0: + case 4: + case 5: + case 6: + case 7: + case 8: + case 10: + case 12: + case 13: + case 14: + case 15: + SetZF(0); + return; + default: + limit = seg.limit; + STORE_REG16(modrm,limit & 0x0000ffff); + SetZF(1); + } + } + } + else + i386_trap(6, 0, 0); +} + +void i386_device::i386_bound_r16_m16_m16() // Opcode 0x62 +{ + UINT8 modrm; + INT16 val, low, high; + + modrm = FETCH(); + + if (modrm >= 0xc0) + { + low = high = LOAD_RM16(modrm); + } + else + { + UINT32 ea = GetEA(modrm,0); + low = READ16(ea + 0); + high = READ16(ea + 2); + } + val = LOAD_REG16(modrm); + + if ((val < low) || (val > high)) + { + CYCLES(CYCLES_BOUND_OUT_RANGE); + i386_trap(5, 0, 0); + } + else + { + CYCLES(CYCLES_BOUND_IN_RANGE); + } +} + +void i386_device::i386_retf16() // Opcode 0xcb +{ + if(PROTECTED_MODE && !V8086_MODE) + { + i386_protected_mode_retf(0,0); + } + else + { + m_eip = POP16(); + m_sreg[CS].selector = POP16(); + i386_load_segment_descriptor(CS ); + CHANGE_PC(m_eip); + } + + CYCLES(CYCLES_RET_INTERSEG); +} + +void i386_device::i386_retf_i16() // Opcode 0xca +{ + UINT16 count = FETCH16(); + + if(PROTECTED_MODE && !V8086_MODE) + { + i386_protected_mode_retf(count,0); + } + else + { + m_eip = POP16(); + m_sreg[CS].selector = POP16(); + i386_load_segment_descriptor(CS ); + CHANGE_PC(m_eip); + REG16(SP) += count; + } + + CYCLES(CYCLES_RET_IMM_INTERSEG); +} + +bool i386_device::i386_load_far_pointer16(int s) +{ + UINT8 modrm = FETCH(); + UINT16 selector; + + if( modrm >= 0xc0 ) { + //logerror("i386: load_far_pointer16 NYI\n"); // don't log, NT will use this a lot + i386_trap(6, 0, 0); + return false; + } else { + UINT32 ea = GetEA(modrm,0); + STORE_REG16(modrm, READ16(ea + 0)); + selector = READ16(ea + 2); + i386_sreg_load(selector,s,NULL); + } + return true; +} + +void i386_device::i386_lds16() // Opcode 0xc5 +{ + if(i386_load_far_pointer16(DS)) + CYCLES(CYCLES_LDS); +} + +void i386_device::i386_lss16() // Opcode 0x0f 0xb2 +{ + if(i386_load_far_pointer16(SS)) + CYCLES(CYCLES_LSS); +} + +void i386_device::i386_les16() // Opcode 0xc4 +{ + if(i386_load_far_pointer16(ES)) + CYCLES(CYCLES_LES); +} + +void i386_device::i386_lfs16() // Opcode 0x0f 0xb4 +{ + if(i386_load_far_pointer16(FS)) + CYCLES(CYCLES_LFS); +} + +void i386_device::i386_lgs16() // Opcode 0x0f 0xb5 +{ + if(i386_load_far_pointer16(GS)) + CYCLES(CYCLES_LGS); +} diff --git a/src/devices/cpu/i386/i386op32.inc b/src/devices/cpu/i386/i386op32.inc new file mode 100644 index 00000000000..96b3baddb1c --- /dev/null +++ b/src/devices/cpu/i386/i386op32.inc @@ -0,0 +1,3585 @@ +// license:BSD-3-Clause +// copyright-holders:Ville Linde, Barry Rodewald, Carl, Philip Bennett +UINT32 i386_device::i386_shift_rotate32(UINT8 modrm, UINT32 value, UINT8 shift) +{ + UINT32 dst, src; + dst = value; + src = value; + + if( shift == 0 ) { + CYCLES_RM(modrm, 3, 7); + } else if( shift == 1 ) { + switch( (modrm >> 3) & 0x7 ) + { + case 0: /* ROL rm32, 1 */ + m_CF = (src & 0x80000000) ? 1 : 0; + dst = (src << 1) + m_CF; + m_OF = ((src ^ dst) & 0x80000000) ? 1 : 0; + CYCLES_RM(modrm, CYCLES_ROTATE_REG, CYCLES_ROTATE_MEM); + break; + case 1: /* ROR rm32, 1 */ + m_CF = (src & 0x1) ? 1 : 0; + dst = (m_CF << 31) | (src >> 1); + m_OF = ((src ^ dst) & 0x80000000) ? 1 : 0; + CYCLES_RM(modrm, CYCLES_ROTATE_REG, CYCLES_ROTATE_MEM); + break; + case 2: /* RCL rm32, 1 */ + dst = (src << 1) + m_CF; + m_CF = (src & 0x80000000) ? 1 : 0; + m_OF = ((src ^ dst) & 0x80000000) ? 1 : 0; + CYCLES_RM(modrm, CYCLES_ROTATE_CARRY_REG, CYCLES_ROTATE_CARRY_MEM); + break; + case 3: /* RCR rm32, 1 */ + dst = (m_CF << 31) | (src >> 1); + m_CF = src & 0x1; + m_OF = ((src ^ dst) & 0x80000000) ? 1 : 0; + CYCLES_RM(modrm, CYCLES_ROTATE_CARRY_REG, CYCLES_ROTATE_CARRY_MEM); + break; + case 4: /* SHL/SAL rm32, 1 */ + case 6: + dst = src << 1; + m_CF = (src & 0x80000000) ? 1 : 0; + m_OF = (((m_CF << 31) ^ dst) & 0x80000000) ? 1 : 0; + SetSZPF32(dst); + CYCLES_RM(modrm, CYCLES_ROTATE_REG, CYCLES_ROTATE_MEM); + break; + case 5: /* SHR rm32, 1 */ + dst = src >> 1; + m_CF = src & 0x1; + m_OF = (src & 0x80000000) ? 1 : 0; + SetSZPF32(dst); + CYCLES_RM(modrm, CYCLES_ROTATE_REG, CYCLES_ROTATE_MEM); + break; + case 7: /* SAR rm32, 1 */ + dst = (INT32)(src) >> 1; + m_CF = src & 0x1; + m_OF = 0; + SetSZPF32(dst); + CYCLES_RM(modrm, CYCLES_ROTATE_REG, CYCLES_ROTATE_MEM); + break; + } + + } else { + shift &= 31; + switch( (modrm >> 3) & 0x7 ) + { + case 0: /* ROL rm32, i8 */ + dst = ((src & ((UINT32)0xffffffff >> shift)) << shift) | + ((src & ((UINT32)0xffffffff << (32-shift))) >> (32-shift)); + m_CF = dst & 0x1; + m_OF = (dst & 1) ^ (dst >> 31); + CYCLES_RM(modrm, CYCLES_ROTATE_REG, CYCLES_ROTATE_MEM); + break; + case 1: /* ROR rm32, i8 */ + dst = ((src & ((UINT32)0xffffffff << shift)) >> shift) | + ((src & ((UINT32)0xffffffff >> (32-shift))) << (32-shift)); + m_CF = (dst >> 31) & 0x1; + m_OF = ((dst >> 31) ^ (dst >> 30)) & 1; + CYCLES_RM(modrm, CYCLES_ROTATE_REG, CYCLES_ROTATE_MEM); + break; + case 2: /* RCL rm32, i8 */ + dst = ((src & ((UINT32)0xffffffff >> shift)) << shift) | + ((src & ((UINT32)0xffffffff << (33-shift))) >> (33-shift)) | + (m_CF << (shift-1)); + m_CF = (src >> (32-shift)) & 0x1; + m_OF = m_CF ^ ((dst >> 31) & 1); + CYCLES_RM(modrm, CYCLES_ROTATE_CARRY_REG, CYCLES_ROTATE_CARRY_MEM); + break; + case 3: /* RCR rm32, i8 */ + dst = ((src & ((UINT32)0xffffffff << shift)) >> shift) | + ((src & ((UINT32)0xffffffff >> (32-shift))) << (33-shift)) | + (m_CF << (32-shift)); + m_CF = (src >> (shift-1)) & 0x1; + m_OF = ((dst >> 31) ^ (dst >> 30)) & 1; + CYCLES_RM(modrm, CYCLES_ROTATE_CARRY_REG, CYCLES_ROTATE_CARRY_MEM); + break; + case 4: /* SHL/SAL rm32, i8 */ + case 6: + dst = src << shift; + m_CF = (src & (1 << (32-shift))) ? 1 : 0; + SetSZPF32(dst); + CYCLES_RM(modrm, CYCLES_ROTATE_REG, CYCLES_ROTATE_MEM); + break; + case 5: /* SHR rm32, i8 */ + dst = src >> shift; + m_CF = (src & (1 << (shift-1))) ? 1 : 0; + SetSZPF32(dst); + CYCLES_RM(modrm, CYCLES_ROTATE_REG, CYCLES_ROTATE_MEM); + break; + case 7: /* SAR rm32, i8 */ + dst = (INT32)src >> shift; + m_CF = (src & (1 << (shift-1))) ? 1 : 0; + SetSZPF32(dst); + CYCLES_RM(modrm, CYCLES_ROTATE_REG, CYCLES_ROTATE_MEM); + break; + } + + } + return dst; +} + + + +void i386_device::i386_adc_rm32_r32() // Opcode 0x11 +{ + UINT32 src, dst; + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + src = LOAD_REG32(modrm); + dst = LOAD_RM32(modrm); + dst = ADC32(dst, src, m_CF); + STORE_RM32(modrm, dst); + CYCLES(CYCLES_ALU_REG_REG); + } else { + UINT32 ea = GetEA(modrm,1); + src = LOAD_REG32(modrm); + dst = READ32(ea); + dst = ADC32(dst, src, m_CF); + WRITE32(ea, dst); + CYCLES(CYCLES_ALU_REG_MEM); + } +} + +void i386_device::i386_adc_r32_rm32() // Opcode 0x13 +{ + UINT32 src, dst; + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + src = LOAD_RM32(modrm); + dst = LOAD_REG32(modrm); + dst = ADC32(dst, src, m_CF); + STORE_REG32(modrm, dst); + CYCLES(CYCLES_ALU_REG_REG); + } else { + UINT32 ea = GetEA(modrm,0); + src = READ32(ea); + dst = LOAD_REG32(modrm); + dst = ADC32(dst, src, m_CF); + STORE_REG32(modrm, dst); + CYCLES(CYCLES_ALU_MEM_REG); + } +} + +void i386_device::i386_adc_eax_i32() // Opcode 0x15 +{ + UINT32 src, dst; + src = FETCH32(); + dst = REG32(EAX); + dst = ADC32(dst, src, m_CF); + REG32(EAX) = dst; + CYCLES(CYCLES_ALU_IMM_ACC); +} + +void i386_device::i386_add_rm32_r32() // Opcode 0x01 +{ + UINT32 src, dst; + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + src = LOAD_REG32(modrm); + dst = LOAD_RM32(modrm); + dst = ADD32(dst, src); + STORE_RM32(modrm, dst); + CYCLES(CYCLES_ALU_REG_REG); + } else { + UINT32 ea = GetEA(modrm,1); + src = LOAD_REG32(modrm); + dst = READ32(ea); + dst = ADD32(dst, src); + WRITE32(ea, dst); + CYCLES(CYCLES_ALU_REG_MEM); + } +} + +void i386_device::i386_add_r32_rm32() // Opcode 0x03 +{ + UINT32 src, dst; + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + src = LOAD_RM32(modrm); + dst = LOAD_REG32(modrm); + dst = ADD32(dst, src); + STORE_REG32(modrm, dst); + CYCLES(CYCLES_ALU_REG_REG); + } else { + UINT32 ea = GetEA(modrm,0); + src = READ32(ea); + dst = LOAD_REG32(modrm); + dst = ADD32(dst, src); + STORE_REG32(modrm, dst); + CYCLES(CYCLES_ALU_MEM_REG); + } +} + +void i386_device::i386_add_eax_i32() // Opcode 0x05 +{ + UINT32 src, dst; + src = FETCH32(); + dst = REG32(EAX); + dst = ADD32(dst, src); + REG32(EAX) = dst; + CYCLES(CYCLES_ALU_IMM_ACC); +} + +void i386_device::i386_and_rm32_r32() // Opcode 0x21 +{ + UINT32 src, dst; + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + src = LOAD_REG32(modrm); + dst = LOAD_RM32(modrm); + dst = AND32(dst, src); + STORE_RM32(modrm, dst); + CYCLES(CYCLES_ALU_REG_REG); + } else { + UINT32 ea = GetEA(modrm,1); + src = LOAD_REG32(modrm); + dst = READ32(ea); + dst = AND32(dst, src); + WRITE32(ea, dst); + CYCLES(CYCLES_ALU_REG_MEM); + } +} + +void i386_device::i386_and_r32_rm32() // Opcode 0x23 +{ + UINT32 src, dst; + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + src = LOAD_RM32(modrm); + dst = LOAD_REG32(modrm); + dst = AND32(dst, src); + STORE_REG32(modrm, dst); + CYCLES(CYCLES_ALU_REG_REG); + } else { + UINT32 ea = GetEA(modrm,0); + src = READ32(ea); + dst = LOAD_REG32(modrm); + dst = AND32(dst, src); + STORE_REG32(modrm, dst); + CYCLES(CYCLES_ALU_MEM_REG); + } +} + +void i386_device::i386_and_eax_i32() // Opcode 0x25 +{ + UINT32 src, dst; + src = FETCH32(); + dst = REG32(EAX); + dst = AND32(dst, src); + REG32(EAX) = dst; + CYCLES(CYCLES_ALU_IMM_ACC); +} + +void i386_device::i386_bsf_r32_rm32() // Opcode 0x0f bc +{ + UINT32 src, dst, temp; + UINT8 modrm = FETCH(); + + if( modrm >= 0xc0 ) { + src = LOAD_RM32(modrm); + } else { + UINT32 ea = GetEA(modrm,0); + src = READ32(ea); + } + + dst = 0; + + if( src == 0 ) { + m_ZF = 1; + } else { + m_ZF = 0; + temp = 0; + while( (src & (1 << temp)) == 0 ) { + temp++; + dst = temp; + CYCLES(CYCLES_BSF); + } + STORE_REG32(modrm, dst); + } + CYCLES(CYCLES_BSF_BASE); +} + +void i386_device::i386_bsr_r32_rm32() // Opcode 0x0f bd +{ + UINT32 src, dst, temp; + UINT8 modrm = FETCH(); + + if( modrm >= 0xc0 ) { + src = LOAD_RM32(modrm); + } else { + UINT32 ea = GetEA(modrm,0); + src = READ32(ea); + } + + dst = 0; + + if( src == 0 ) { + m_ZF = 1; + } else { + m_ZF = 0; + dst = temp = 31; + while( (src & (1 << temp)) == 0 ) { + temp--; + dst = temp; + CYCLES(CYCLES_BSR); + } + STORE_REG32(modrm, dst); + } + CYCLES(CYCLES_BSR_BASE); +} + +void i386_device::i386_bt_rm32_r32() // Opcode 0x0f a3 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + UINT32 dst = LOAD_RM32(modrm); + UINT32 bit = LOAD_REG32(modrm); + + if( dst & (1 << bit) ) + m_CF = 1; + else + m_CF = 0; + + CYCLES(CYCLES_BT_REG_REG); + } else { + UINT8 segment; + UINT32 ea = GetNonTranslatedEA(modrm,&segment); + UINT32 bit = LOAD_REG32(modrm); + ea += 4*(bit/32); + ea = i386_translate(segment,(m_address_size)?ea:(ea&0xffff),0); + bit %= 32; + UINT32 dst = READ32(ea); + + if( dst & (1 << bit) ) + m_CF = 1; + else + m_CF = 0; + + CYCLES(CYCLES_BT_REG_MEM); + } +} + +void i386_device::i386_btc_rm32_r32() // Opcode 0x0f bb +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + UINT32 dst = LOAD_RM32(modrm); + UINT32 bit = LOAD_REG32(modrm); + + if( dst & (1 << bit) ) + m_CF = 1; + else + m_CF = 0; + dst ^= (1 << bit); + + STORE_RM32(modrm, dst); + CYCLES(CYCLES_BTC_REG_REG); + } else { + UINT8 segment; + UINT32 ea = GetNonTranslatedEA(modrm,&segment); + UINT32 bit = LOAD_REG32(modrm); + ea += 4*(bit/32); + ea = i386_translate(segment,(m_address_size)?ea:(ea&0xffff),1); + bit %= 32; + UINT32 dst = READ32(ea); + + if( dst & (1 << bit) ) + m_CF = 1; + else + m_CF = 0; + dst ^= (1 << bit); + + WRITE32(ea, dst); + CYCLES(CYCLES_BTC_REG_MEM); + } +} + +void i386_device::i386_btr_rm32_r32() // Opcode 0x0f b3 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + UINT32 dst = LOAD_RM32(modrm); + UINT32 bit = LOAD_REG32(modrm); + + if( dst & (1 << bit) ) + m_CF = 1; + else + m_CF = 0; + dst &= ~(1 << bit); + + STORE_RM32(modrm, dst); + CYCLES(CYCLES_BTR_REG_REG); + } else { + UINT8 segment; + UINT32 ea = GetNonTranslatedEA(modrm,&segment); + UINT32 bit = LOAD_REG32(modrm); + ea += 4*(bit/32); + ea = i386_translate(segment,(m_address_size)?ea:(ea&0xffff),1); + bit %= 32; + UINT32 dst = READ32(ea); + + if( dst & (1 << bit) ) + m_CF = 1; + else + m_CF = 0; + dst &= ~(1 << bit); + + WRITE32(ea, dst); + CYCLES(CYCLES_BTR_REG_MEM); + } +} + +void i386_device::i386_bts_rm32_r32() // Opcode 0x0f ab +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + UINT32 dst = LOAD_RM32(modrm); + UINT32 bit = LOAD_REG32(modrm); + + if( dst & (1 << bit) ) + m_CF = 1; + else + m_CF = 0; + dst |= (1 << bit); + + STORE_RM32(modrm, dst); + CYCLES(CYCLES_BTS_REG_REG); + } else { + UINT8 segment; + UINT32 ea = GetNonTranslatedEA(modrm,&segment); + UINT32 bit = LOAD_REG32(modrm); + ea += 4*(bit/32); + ea = i386_translate(segment,(m_address_size)?ea:(ea&0xffff),1); + bit %= 32; + UINT32 dst = READ32(ea); + + if( dst & (1 << bit) ) + m_CF = 1; + else + m_CF = 0; + dst |= (1 << bit); + + WRITE32(ea, dst); + CYCLES(CYCLES_BTS_REG_MEM); + } +} + +void i386_device::i386_call_abs32() // Opcode 0x9a +{ + UINT32 offset = FETCH32(); + UINT16 ptr = FETCH16(); + + if(PROTECTED_MODE && !V8086_MODE) + { + i386_protected_mode_call(ptr,offset,0,1); + } + else + { + PUSH32(m_sreg[CS].selector ); + PUSH32(m_eip ); + m_sreg[CS].selector = ptr; + m_performed_intersegment_jump = 1; + m_eip = offset; + i386_load_segment_descriptor(CS); + } + CYCLES(CYCLES_CALL_INTERSEG); + CHANGE_PC(m_eip); +} + +void i386_device::i386_call_rel32() // Opcode 0xe8 +{ + INT32 disp = FETCH32(); + PUSH32(m_eip ); + m_eip += disp; + CHANGE_PC(m_eip); + CYCLES(CYCLES_CALL); /* TODO: Timing = 7 + m */ +} + +void i386_device::i386_cdq() // Opcode 0x99 +{ + if( REG32(EAX) & 0x80000000 ) { + REG32(EDX) = 0xffffffff; + } else { + REG32(EDX) = 0x00000000; + } + CYCLES(CYCLES_CWD); +} + +void i386_device::i386_cmp_rm32_r32() // Opcode 0x39 +{ + UINT32 src, dst; + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + src = LOAD_REG32(modrm); + dst = LOAD_RM32(modrm); + SUB32(dst, src); + CYCLES(CYCLES_CMP_REG_REG); + } else { + UINT32 ea = GetEA(modrm,0); + src = LOAD_REG32(modrm); + dst = READ32(ea); + SUB32(dst, src); + CYCLES(CYCLES_CMP_REG_MEM); + } +} + +void i386_device::i386_cmp_r32_rm32() // Opcode 0x3b +{ + UINT32 src, dst; + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + src = LOAD_RM32(modrm); + dst = LOAD_REG32(modrm); + SUB32(dst, src); + CYCLES(CYCLES_CMP_REG_REG); + } else { + UINT32 ea = GetEA(modrm,0); + src = READ32(ea); + dst = LOAD_REG32(modrm); + SUB32(dst, src); + CYCLES(CYCLES_CMP_MEM_REG); + } +} + +void i386_device::i386_cmp_eax_i32() // Opcode 0x3d +{ + UINT32 src, dst; + src = FETCH32(); + dst = REG32(EAX); + SUB32(dst, src); + CYCLES(CYCLES_CMP_IMM_ACC); +} + +void i386_device::i386_cmpsd() // Opcode 0xa7 +{ + UINT32 eas, ead, src, dst; + if( m_segment_prefix ) { + eas = i386_translate(m_segment_override, m_address_size ? REG32(ESI) : REG16(SI), 0 ); + } else { + eas = i386_translate(DS, m_address_size ? REG32(ESI) : REG16(SI), 0 ); + } + ead = i386_translate(ES, m_address_size ? REG32(EDI) : REG16(DI), 0 ); + src = READ32(eas); + dst = READ32(ead); + SUB32(src,dst); + BUMP_SI(4); + BUMP_DI(4); + CYCLES(CYCLES_CMPS); +} + +void i386_device::i386_cwde() // Opcode 0x98 +{ + REG32(EAX) = (INT32)((INT16)REG16(AX)); + CYCLES(CYCLES_CBW); +} + +void i386_device::i386_dec_eax() // Opcode 0x48 +{ + REG32(EAX) = DEC32(REG32(EAX) ); + CYCLES(CYCLES_DEC_REG); +} + +void i386_device::i386_dec_ecx() // Opcode 0x49 +{ + REG32(ECX) = DEC32(REG32(ECX) ); + CYCLES(CYCLES_DEC_REG); +} + +void i386_device::i386_dec_edx() // Opcode 0x4a +{ + REG32(EDX) = DEC32(REG32(EDX) ); + CYCLES(CYCLES_DEC_REG); +} + +void i386_device::i386_dec_ebx() // Opcode 0x4b +{ + REG32(EBX) = DEC32(REG32(EBX) ); + CYCLES(CYCLES_DEC_REG); +} + +void i386_device::i386_dec_esp() // Opcode 0x4c +{ + REG32(ESP) = DEC32(REG32(ESP) ); + CYCLES(CYCLES_DEC_REG); +} + +void i386_device::i386_dec_ebp() // Opcode 0x4d +{ + REG32(EBP) = DEC32(REG32(EBP) ); + CYCLES(CYCLES_DEC_REG); +} + +void i386_device::i386_dec_esi() // Opcode 0x4e +{ + REG32(ESI) = DEC32(REG32(ESI) ); + CYCLES(CYCLES_DEC_REG); +} + +void i386_device::i386_dec_edi() // Opcode 0x4f +{ + REG32(EDI) = DEC32(REG32(EDI) ); + CYCLES(CYCLES_DEC_REG); +} + +void i386_device::i386_imul_r32_rm32() // Opcode 0x0f af +{ + UINT8 modrm = FETCH(); + INT64 result; + INT64 src, dst; + if( modrm >= 0xc0 ) { + src = (INT64)(INT32)LOAD_RM32(modrm); + CYCLES(CYCLES_IMUL32_REG_REG); /* TODO: Correct multiply timing */ + } else { + UINT32 ea = GetEA(modrm,0); + src = (INT64)(INT32)READ32(ea); + CYCLES(CYCLES_IMUL32_REG_REG); /* TODO: Correct multiply timing */ + } + + dst = (INT64)(INT32)LOAD_REG32(modrm); + result = src * dst; + + STORE_REG32(modrm, (UINT32)result); + + m_CF = m_OF = !(result == (INT64)(INT32)result); +} + +void i386_device::i386_imul_r32_rm32_i32() // Opcode 0x69 +{ + UINT8 modrm = FETCH(); + INT64 result; + INT64 src, dst; + if( modrm >= 0xc0 ) { + dst = (INT64)(INT32)LOAD_RM32(modrm); + CYCLES(CYCLES_IMUL32_REG_IMM_REG); /* TODO: Correct multiply timing */ + } else { + UINT32 ea = GetEA(modrm,0); + dst = (INT64)(INT32)READ32(ea); + CYCLES(CYCLES_IMUL32_MEM_IMM_REG); /* TODO: Correct multiply timing */ + } + + src = (INT64)(INT32)FETCH32(); + result = src * dst; + + STORE_REG32(modrm, (UINT32)result); + + m_CF = m_OF = !(result == (INT64)(INT32)result); +} + +void i386_device::i386_imul_r32_rm32_i8() // Opcode 0x6b +{ + UINT8 modrm = FETCH(); + INT64 result; + INT64 src, dst; + if( modrm >= 0xc0 ) { + dst = (INT64)(INT32)LOAD_RM32(modrm); + CYCLES(CYCLES_IMUL32_REG_IMM_REG); /* TODO: Correct multiply timing */ + } else { + UINT32 ea = GetEA(modrm,0); + dst = (INT64)(INT32)READ32(ea); + CYCLES(CYCLES_IMUL32_MEM_IMM_REG); /* TODO: Correct multiply timing */ + } + + src = (INT64)(INT8)FETCH(); + result = src * dst; + + STORE_REG32(modrm, (UINT32)result); + + m_CF = m_OF = !(result == (INT64)(INT32)result); +} + +void i386_device::i386_in_eax_i8() // Opcode 0xe5 +{ + UINT16 port = FETCH(); + UINT32 data = READPORT32(port); + REG32(EAX) = data; + CYCLES(CYCLES_IN_VAR); +} + +void i386_device::i386_in_eax_dx() // Opcode 0xed +{ + UINT16 port = REG16(DX); + UINT32 data = READPORT32(port); + REG32(EAX) = data; + CYCLES(CYCLES_IN); +} + +void i386_device::i386_inc_eax() // Opcode 0x40 +{ + REG32(EAX) = INC32(REG32(EAX) ); + CYCLES(CYCLES_INC_REG); +} + +void i386_device::i386_inc_ecx() // Opcode 0x41 +{ + REG32(ECX) = INC32(REG32(ECX) ); + CYCLES(CYCLES_INC_REG); +} + +void i386_device::i386_inc_edx() // Opcode 0x42 +{ + REG32(EDX) = INC32(REG32(EDX) ); + CYCLES(CYCLES_INC_REG); +} + +void i386_device::i386_inc_ebx() // Opcode 0x43 +{ + REG32(EBX) = INC32(REG32(EBX) ); + CYCLES(CYCLES_INC_REG); +} + +void i386_device::i386_inc_esp() // Opcode 0x44 +{ + REG32(ESP) = INC32(REG32(ESP) ); + CYCLES(CYCLES_INC_REG); +} + +void i386_device::i386_inc_ebp() // Opcode 0x45 +{ + REG32(EBP) = INC32(REG32(EBP) ); + CYCLES(CYCLES_INC_REG); +} + +void i386_device::i386_inc_esi() // Opcode 0x46 +{ + REG32(ESI) = INC32(REG32(ESI) ); + CYCLES(CYCLES_INC_REG); +} + +void i386_device::i386_inc_edi() // Opcode 0x47 +{ + REG32(EDI) = INC32(REG32(EDI) ); + CYCLES(CYCLES_INC_REG); +} + +void i386_device::i386_iret32() // Opcode 0xcf +{ + if( PROTECTED_MODE ) + { + i386_protected_mode_iret(1); + } + else + { + /* TODO: #SS(0) exception */ + /* TODO: #GP(0) exception */ + m_eip = POP32(); + m_sreg[CS].selector = POP32() & 0xffff; + set_flags(POP32() ); + i386_load_segment_descriptor(CS); + CHANGE_PC(m_eip); + } + CYCLES(CYCLES_IRET); +} + +void i386_device::i386_ja_rel32() // Opcode 0x0f 87 +{ + INT32 disp = FETCH32(); + if( m_CF == 0 && m_ZF == 0 ) { + m_eip += disp; + CHANGE_PC(m_eip); + CYCLES(CYCLES_JCC_FULL_DISP); /* TODO: Timing = 7 + m */ + } else { + CYCLES(CYCLES_JCC_FULL_DISP_NOBRANCH); + } +} + +void i386_device::i386_jbe_rel32() // Opcode 0x0f 86 +{ + INT32 disp = FETCH32(); + if( m_CF != 0 || m_ZF != 0 ) { + m_eip += disp; + CHANGE_PC(m_eip); + CYCLES(CYCLES_JCC_FULL_DISP); /* TODO: Timing = 7 + m */ + } else { + CYCLES(CYCLES_JCC_FULL_DISP_NOBRANCH); + } +} + +void i386_device::i386_jc_rel32() // Opcode 0x0f 82 +{ + INT32 disp = FETCH32(); + if( m_CF != 0 ) { + m_eip += disp; + CHANGE_PC(m_eip); + CYCLES(CYCLES_JCC_FULL_DISP); /* TODO: Timing = 7 + m */ + } else { + CYCLES(CYCLES_JCC_FULL_DISP_NOBRANCH); + } +} + +void i386_device::i386_jg_rel32() // Opcode 0x0f 8f +{ + INT32 disp = FETCH32(); + if( m_ZF == 0 && (m_SF == m_OF) ) { + m_eip += disp; + CHANGE_PC(m_eip); + CYCLES(CYCLES_JCC_FULL_DISP); /* TODO: Timing = 7 + m */ + } else { + CYCLES(CYCLES_JCC_FULL_DISP_NOBRANCH); + } +} + +void i386_device::i386_jge_rel32() // Opcode 0x0f 8d +{ + INT32 disp = FETCH32(); + if(m_SF == m_OF) { + m_eip += disp; + CHANGE_PC(m_eip); + CYCLES(CYCLES_JCC_FULL_DISP); /* TODO: Timing = 7 + m */ + } else { + CYCLES(CYCLES_JCC_FULL_DISP_NOBRANCH); + } +} + +void i386_device::i386_jl_rel32() // Opcode 0x0f 8c +{ + INT32 disp = FETCH32(); + if( (m_SF != m_OF) ) { + m_eip += disp; + CHANGE_PC(m_eip); + CYCLES(CYCLES_JCC_FULL_DISP); /* TODO: Timing = 7 + m */ + } else { + CYCLES(CYCLES_JCC_FULL_DISP_NOBRANCH); + } +} + +void i386_device::i386_jle_rel32() // Opcode 0x0f 8e +{ + INT32 disp = FETCH32(); + if( m_ZF != 0 || (m_SF != m_OF) ) { + m_eip += disp; + CHANGE_PC(m_eip); + CYCLES(CYCLES_JCC_FULL_DISP); /* TODO: Timing = 7 + m */ + } else { + CYCLES(CYCLES_JCC_FULL_DISP_NOBRANCH); + } +} + +void i386_device::i386_jnc_rel32() // Opcode 0x0f 83 +{ + INT32 disp = FETCH32(); + if( m_CF == 0 ) { + m_eip += disp; + CHANGE_PC(m_eip); + CYCLES(CYCLES_JCC_FULL_DISP); /* TODO: Timing = 7 + m */ + } else { + CYCLES(CYCLES_JCC_FULL_DISP_NOBRANCH); + } +} + +void i386_device::i386_jno_rel32() // Opcode 0x0f 81 +{ + INT32 disp = FETCH32(); + if( m_OF == 0 ) { + m_eip += disp; + CHANGE_PC(m_eip); + CYCLES(CYCLES_JCC_FULL_DISP); /* TODO: Timing = 7 + m */ + } else { + CYCLES(CYCLES_JCC_FULL_DISP_NOBRANCH); + } +} + +void i386_device::i386_jnp_rel32() // Opcode 0x0f 8b +{ + INT32 disp = FETCH32(); + if( m_PF == 0 ) { + m_eip += disp; + CHANGE_PC(m_eip); + CYCLES(CYCLES_JCC_FULL_DISP); /* TODO: Timing = 7 + m */ + } else { + CYCLES(CYCLES_JCC_FULL_DISP_NOBRANCH); + } +} + +void i386_device::i386_jns_rel32() // Opcode 0x0f 89 +{ + INT32 disp = FETCH32(); + if( m_SF == 0 ) { + m_eip += disp; + CHANGE_PC(m_eip); + CYCLES(CYCLES_JCC_FULL_DISP); /* TODO: Timing = 7 + m */ + } else { + CYCLES(CYCLES_JCC_FULL_DISP_NOBRANCH); + } +} + +void i386_device::i386_jnz_rel32() // Opcode 0x0f 85 +{ + INT32 disp = FETCH32(); + if( m_ZF == 0 ) { + m_eip += disp; + CHANGE_PC(m_eip); + CYCLES(CYCLES_JCC_FULL_DISP); /* TODO: Timing = 7 + m */ + } else { + CYCLES(CYCLES_JCC_FULL_DISP_NOBRANCH); + } +} + +void i386_device::i386_jo_rel32() // Opcode 0x0f 80 +{ + INT32 disp = FETCH32(); + if( m_OF != 0 ) { + m_eip += disp; + CHANGE_PC(m_eip); + CYCLES(CYCLES_JCC_FULL_DISP); /* TODO: Timing = 7 + m */ + } else { + CYCLES(CYCLES_JCC_FULL_DISP_NOBRANCH); + } +} + +void i386_device::i386_jp_rel32() // Opcode 0x0f 8a +{ + INT32 disp = FETCH32(); + if( m_PF != 0 ) { + m_eip += disp; + CHANGE_PC(m_eip); + CYCLES(CYCLES_JCC_FULL_DISP); /* TODO: Timing = 7 + m */ + } else { + CYCLES(CYCLES_JCC_FULL_DISP_NOBRANCH); + } +} + +void i386_device::i386_js_rel32() // Opcode 0x0f 88 +{ + INT32 disp = FETCH32(); + if( m_SF != 0 ) { + m_eip += disp; + CHANGE_PC(m_eip); + CYCLES(CYCLES_JCC_FULL_DISP); /* TODO: Timing = 7 + m */ + } else { + CYCLES(CYCLES_JCC_FULL_DISP_NOBRANCH); + } +} + +void i386_device::i386_jz_rel32() // Opcode 0x0f 84 +{ + INT32 disp = FETCH32(); + if( m_ZF != 0 ) { + m_eip += disp; + CHANGE_PC(m_eip); + CYCLES(CYCLES_JCC_FULL_DISP); /* TODO: Timing = 7 + m */ + } else { + CYCLES(CYCLES_JCC_FULL_DISP_NOBRANCH); + } +} + +void i386_device::i386_jcxz32() // Opcode 0xe3 +{ + INT8 disp = FETCH(); + int val = (m_address_size)?(REG32(ECX) == 0):(REG16(CX) == 0); + if( val ) { + m_eip += disp; + CHANGE_PC(m_eip); + CYCLES(CYCLES_JCXZ); /* TODO: Timing = 9 + m */ + } else { + CYCLES(CYCLES_JCXZ_NOBRANCH); + } +} + +void i386_device::i386_jmp_rel32() // Opcode 0xe9 +{ + UINT32 disp = FETCH32(); + /* TODO: Segment limit */ + m_eip += disp; + CHANGE_PC(m_eip); + CYCLES(CYCLES_JMP); /* TODO: Timing = 7 + m */ +} + +void i386_device::i386_jmp_abs32() // Opcode 0xea +{ + UINT32 address = FETCH32(); + UINT16 segment = FETCH16(); + + if( PROTECTED_MODE && !V8086_MODE) + { + i386_protected_mode_jump(segment,address,0,1); + } + else + { + m_eip = address; + m_sreg[CS].selector = segment; + m_performed_intersegment_jump = 1; + i386_load_segment_descriptor(CS); + CHANGE_PC(m_eip); + } + CYCLES(CYCLES_JMP_INTERSEG); +} + +void i386_device::i386_lea32() // Opcode 0x8d +{ + UINT8 modrm = FETCH(); + UINT32 ea = GetNonTranslatedEA(modrm,NULL); + if (!m_address_size) + { + ea &= 0xffff; + } + STORE_REG32(modrm, ea); + CYCLES(CYCLES_LEA); +} + +void i386_device::i386_enter32() // Opcode 0xc8 +{ + UINT16 framesize = FETCH16(); + UINT8 level = FETCH() % 32; + UINT8 x; + UINT32 frameptr; + PUSH32(REG32(EBP)); + if(!STACK_32BIT) + frameptr = REG16(SP); + else + frameptr = REG32(ESP); + + if(level > 0) + { + for(x=1;x= 0xc0 ) { + src = LOAD_REG32(modrm); + STORE_RM32(modrm, src); + CYCLES(CYCLES_MOV_REG_REG); + } else { + UINT32 ea = GetEA(modrm,1); + src = LOAD_REG32(modrm); + WRITE32(ea, src); + CYCLES(CYCLES_MOV_REG_MEM); + } +} + +void i386_device::i386_mov_r32_rm32() // Opcode 0x8b +{ + UINT32 src; + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + src = LOAD_RM32(modrm); + STORE_REG32(modrm, src); + CYCLES(CYCLES_MOV_REG_REG); + } else { + UINT32 ea = GetEA(modrm,0); + src = READ32(ea); + STORE_REG32(modrm, src); + CYCLES(CYCLES_MOV_MEM_REG); + } +} + +void i386_device::i386_mov_rm32_i32() // Opcode 0xc7 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + UINT32 value = FETCH32(); + STORE_RM32(modrm, value); + CYCLES(CYCLES_MOV_IMM_REG); + } else { + UINT32 ea = GetEA(modrm,1); + UINT32 value = FETCH32(); + WRITE32(ea, value); + CYCLES(CYCLES_MOV_IMM_MEM); + } +} + +void i386_device::i386_mov_eax_m32() // Opcode 0xa1 +{ + UINT32 offset, ea; + if( m_address_size ) { + offset = FETCH32(); + } else { + offset = FETCH16(); + } + if( m_segment_prefix ) { + ea = i386_translate(m_segment_override, offset, 0 ); + } else { + ea = i386_translate(DS, offset, 0 ); + } + REG32(EAX) = READ32(ea); + CYCLES(CYCLES_MOV_MEM_ACC); +} + +void i386_device::i386_mov_m32_eax() // Opcode 0xa3 +{ + UINT32 offset, ea; + if( m_address_size ) { + offset = FETCH32(); + } else { + offset = FETCH16(); + } + if( m_segment_prefix ) { + ea = i386_translate(m_segment_override, offset, 1 ); + } else { + ea = i386_translate(DS, offset, 1 ); + } + WRITE32(ea, REG32(EAX) ); + CYCLES(CYCLES_MOV_ACC_MEM); +} + +void i386_device::i386_mov_eax_i32() // Opcode 0xb8 +{ + REG32(EAX) = FETCH32(); + CYCLES(CYCLES_MOV_IMM_REG); +} + +void i386_device::i386_mov_ecx_i32() // Opcode 0xb9 +{ + REG32(ECX) = FETCH32(); + CYCLES(CYCLES_MOV_IMM_REG); +} + +void i386_device::i386_mov_edx_i32() // Opcode 0xba +{ + REG32(EDX) = FETCH32(); + CYCLES(CYCLES_MOV_IMM_REG); +} + +void i386_device::i386_mov_ebx_i32() // Opcode 0xbb +{ + REG32(EBX) = FETCH32(); + CYCLES(CYCLES_MOV_IMM_REG); +} + +void i386_device::i386_mov_esp_i32() // Opcode 0xbc +{ + REG32(ESP) = FETCH32(); + CYCLES(CYCLES_MOV_IMM_REG); +} + +void i386_device::i386_mov_ebp_i32() // Opcode 0xbd +{ + REG32(EBP) = FETCH32(); + CYCLES(CYCLES_MOV_IMM_REG); +} + +void i386_device::i386_mov_esi_i32() // Opcode 0xbe +{ + REG32(ESI) = FETCH32(); + CYCLES(CYCLES_MOV_IMM_REG); +} + +void i386_device::i386_mov_edi_i32() // Opcode 0xbf +{ + REG32(EDI) = FETCH32(); + CYCLES(CYCLES_MOV_IMM_REG); +} + +void i386_device::i386_movsd() // Opcode 0xa5 +{ + UINT32 eas, ead, v; + if( m_segment_prefix ) { + eas = i386_translate(m_segment_override, m_address_size ? REG32(ESI) : REG16(SI), 0 ); + } else { + eas = i386_translate(DS, m_address_size ? REG32(ESI) : REG16(SI), 0 ); + } + ead = i386_translate(ES, m_address_size ? REG32(EDI) : REG16(DI), 1 ); + v = READ32(eas); + WRITE32(ead, v); + BUMP_SI(4); + BUMP_DI(4); + CYCLES(CYCLES_MOVS); +} + +void i386_device::i386_movsx_r32_rm8() // Opcode 0x0f be +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + INT32 src = (INT8)LOAD_RM8(modrm); + STORE_REG32(modrm, src); + CYCLES(CYCLES_MOVSX_REG_REG); + } else { + UINT32 ea = GetEA(modrm,0); + INT32 src = (INT8)READ8(ea); + STORE_REG32(modrm, src); + CYCLES(CYCLES_MOVSX_MEM_REG); + } +} + +void i386_device::i386_movsx_r32_rm16() // Opcode 0x0f bf +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + INT32 src = (INT16)LOAD_RM16(modrm); + STORE_REG32(modrm, src); + CYCLES(CYCLES_MOVSX_REG_REG); + } else { + UINT32 ea = GetEA(modrm,0); + INT32 src = (INT16)READ16(ea); + STORE_REG32(modrm, src); + CYCLES(CYCLES_MOVSX_MEM_REG); + } +} + +void i386_device::i386_movzx_r32_rm8() // Opcode 0x0f b6 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + UINT32 src = (UINT8)LOAD_RM8(modrm); + STORE_REG32(modrm, src); + CYCLES(CYCLES_MOVZX_REG_REG); + } else { + UINT32 ea = GetEA(modrm,0); + UINT32 src = (UINT8)READ8(ea); + STORE_REG32(modrm, src); + CYCLES(CYCLES_MOVZX_MEM_REG); + } +} + +void i386_device::i386_movzx_r32_rm16() // Opcode 0x0f b7 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + UINT32 src = (UINT16)LOAD_RM16(modrm); + STORE_REG32(modrm, src); + CYCLES(CYCLES_MOVZX_REG_REG); + } else { + UINT32 ea = GetEA(modrm,0); + UINT32 src = (UINT16)READ16(ea); + STORE_REG32(modrm, src); + CYCLES(CYCLES_MOVZX_MEM_REG); + } +} + +void i386_device::i386_or_rm32_r32() // Opcode 0x09 +{ + UINT32 src, dst; + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + src = LOAD_REG32(modrm); + dst = LOAD_RM32(modrm); + dst = OR32(dst, src); + STORE_RM32(modrm, dst); + CYCLES(CYCLES_ALU_REG_REG); + } else { + UINT32 ea = GetEA(modrm,1); + src = LOAD_REG32(modrm); + dst = READ32(ea); + dst = OR32(dst, src); + WRITE32(ea, dst); + CYCLES(CYCLES_ALU_REG_MEM); + } +} + +void i386_device::i386_or_r32_rm32() // Opcode 0x0b +{ + UINT32 src, dst; + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + src = LOAD_RM32(modrm); + dst = LOAD_REG32(modrm); + dst = OR32(dst, src); + STORE_REG32(modrm, dst); + CYCLES(CYCLES_ALU_REG_REG); + } else { + UINT32 ea = GetEA(modrm,0); + src = READ32(ea); + dst = LOAD_REG32(modrm); + dst = OR32(dst, src); + STORE_REG32(modrm, dst); + CYCLES(CYCLES_ALU_MEM_REG); + } +} + +void i386_device::i386_or_eax_i32() // Opcode 0x0d +{ + UINT32 src, dst; + src = FETCH32(); + dst = REG32(EAX); + dst = OR32(dst, src); + REG32(EAX) = dst; + CYCLES(CYCLES_ALU_IMM_ACC); +} + +void i386_device::i386_out_eax_i8() // Opcode 0xe7 +{ + UINT16 port = FETCH(); + UINT32 data = REG32(EAX); + WRITEPORT32(port, data); + CYCLES(CYCLES_OUT_VAR); +} + +void i386_device::i386_out_eax_dx() // Opcode 0xef +{ + UINT16 port = REG16(DX); + UINT32 data = REG32(EAX); + WRITEPORT32(port, data); + CYCLES(CYCLES_OUT); +} + +void i386_device::i386_pop_eax() // Opcode 0x58 +{ + UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP)); + if(i386_limit_check(SS,offset+3) == 0) + REG32(EAX) = POP32(); + else + FAULT(FAULT_SS,0) + CYCLES(CYCLES_POP_REG_SHORT); +} + +void i386_device::i386_pop_ecx() // Opcode 0x59 +{ + UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP)); + if(i386_limit_check(SS,offset+3) == 0) + REG32(ECX) = POP32(); + else + FAULT(FAULT_SS,0) + CYCLES(CYCLES_POP_REG_SHORT); +} + +void i386_device::i386_pop_edx() // Opcode 0x5a +{ + UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP)); + if(i386_limit_check(SS,offset+3) == 0) + REG32(EDX) = POP32(); + else + FAULT(FAULT_SS,0) + CYCLES(CYCLES_POP_REG_SHORT); +} + +void i386_device::i386_pop_ebx() // Opcode 0x5b +{ + UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP)); + if(i386_limit_check(SS,offset+3) == 0) + REG32(EBX) = POP32(); + else + FAULT(FAULT_SS,0) + CYCLES(CYCLES_POP_REG_SHORT); +} + +void i386_device::i386_pop_esp() // Opcode 0x5c +{ + UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP)); + if(i386_limit_check(SS,offset+3) == 0) + REG32(ESP) = POP32(); + else + FAULT(FAULT_SS,0) + CYCLES(CYCLES_POP_REG_SHORT); +} + +void i386_device::i386_pop_ebp() // Opcode 0x5d +{ + UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP)); + if(i386_limit_check(SS,offset+3) == 0) + REG32(EBP) = POP32(); + else + FAULT(FAULT_SS,0) + CYCLES(CYCLES_POP_REG_SHORT); +} + +void i386_device::i386_pop_esi() // Opcode 0x5e +{ + UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP)); + if(i386_limit_check(SS,offset+3) == 0) + REG32(ESI) = POP32(); + else + FAULT(FAULT_SS,0) + CYCLES(CYCLES_POP_REG_SHORT); +} + +void i386_device::i386_pop_edi() // Opcode 0x5f +{ + UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP)); + if(i386_limit_check(SS,offset+3) == 0) + REG32(EDI) = POP32(); + else + FAULT(FAULT_SS,0) + CYCLES(CYCLES_POP_REG_SHORT); +} + +bool i386_device::i386_pop_seg32(int segment) +{ + UINT32 ea, offset = (STACK_32BIT ? REG32(ESP) : REG16(SP)); + UINT32 value; + bool fault; + if(i386_limit_check(SS,offset+3) == 0) + { + ea = i386_translate(SS, offset, 0); + value = READ32(ea); + i386_sreg_load(value, segment, &fault); + if(fault) return false; + if(STACK_32BIT) + REG32(ESP) = offset + 4; + else + REG16(SP) = offset + 4; + } + else + { + m_ext = 1; + i386_trap_with_error(FAULT_SS,0,0,0); + return false; + } + CYCLES(CYCLES_POP_SREG); + return true; +} + +void i386_device::i386_pop_ds32() // Opcode 0x1f +{ + i386_pop_seg32(DS); +} + +void i386_device::i386_pop_es32() // Opcode 0x07 +{ + i386_pop_seg32(ES); +} + +void i386_device::i386_pop_fs32() // Opcode 0x0f a1 +{ + i386_pop_seg32(FS); +} + +void i386_device::i386_pop_gs32() // Opcode 0x0f a9 +{ + i386_pop_seg32(GS); +} + +void i386_device::i386_pop_ss32() // Opcode 0x17 +{ + if(!i386_pop_seg32(SS)) return; + if(m_IF != 0) // if external interrupts are enabled + { + m_IF = 0; // reset IF for the next instruction + m_delayed_interrupt_enable = 1; + } +} + +void i386_device::i386_pop_rm32() // Opcode 0x8f +{ + UINT8 modrm = FETCH(); + UINT32 value; + UINT32 ea, offset = (STACK_32BIT ? REG32(ESP) : REG16(SP)); + if(i386_limit_check(SS,offset+3) == 0) + { + // be careful here, if the write references the esp register + // it expects the post-pop value but esp must be wound back + // if the write faults + UINT32 temp_sp = REG32(ESP); + value = POP32(); + + if( modrm >= 0xc0 ) { + STORE_RM32(modrm, value); + } else { + ea = GetEA(modrm,1); + try + { + WRITE32(ea, value); + } + catch(UINT64 e) + { + REG32(ESP) = temp_sp; + throw e; + } + } + } + else + FAULT(FAULT_SS,0) + CYCLES(CYCLES_POP_RM); +} + +void i386_device::i386_popad() // Opcode 0x61 +{ + UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP)); + if(i386_limit_check(SS,offset+31) == 0) + { + REG32(EDI) = POP32(); + REG32(ESI) = POP32(); + REG32(EBP) = POP32(); + REG32(ESP) += 4; + REG32(EBX) = POP32(); + REG32(EDX) = POP32(); + REG32(ECX) = POP32(); + REG32(EAX) = POP32(); + } + else + FAULT(FAULT_SS,0) + CYCLES(CYCLES_POPA); +} + +void i386_device::i386_popfd() // Opcode 0x9d +{ + UINT32 value; + UINT32 current = get_flags(); + UINT8 IOPL = (current >> 12) & 0x03; + UINT32 mask = 0x00257fd5; // VM, VIP and VIF cannot be set by POPF/POPFD + UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP)); + + // IOPL can only change if CPL is 0 + if(m_CPL != 0) + mask &= ~0x00003000; + + // IF can only change if CPL is at least as privileged as IOPL + if(m_CPL > IOPL) + mask &= ~0x00000200; + + if(V8086_MODE) + { + if(IOPL < 3) + { + logerror("POPFD(%08x): IOPL < 3 while in V86 mode.\n",m_pc); + FAULT(FAULT_GP,0) // #GP(0) + } + mask &= ~0x00003000; // IOPL cannot be changed while in V8086 mode + } + + if(i386_limit_check(SS,offset+3) == 0) + { + value = POP32(); + value &= ~0x00010000; // RF will always return zero + set_flags((current & ~mask) | (value & mask)); // mask out reserved bits + } + else + FAULT(FAULT_SS,0) + CYCLES(CYCLES_POPF); +} + +void i386_device::i386_push_eax() // Opcode 0x50 +{ + UINT32 offset; + if(STACK_32BIT) + offset = REG32(ESP) - 4; + else + offset = (REG16(SP) - 4) & 0xffff; + if(i386_limit_check(SS,offset) == 0) + PUSH32(REG32(EAX) ); + else + FAULT(FAULT_SS,0) + CYCLES(CYCLES_PUSH_REG_SHORT); +} + +void i386_device::i386_push_ecx() // Opcode 0x51 +{ + UINT32 offset; + if(STACK_32BIT) + offset = REG32(ESP) - 4; + else + offset = (REG16(SP) - 4) & 0xffff; + if(i386_limit_check(SS,offset) == 0) + PUSH32(REG32(ECX) ); + else + FAULT(FAULT_SS,0) + CYCLES(CYCLES_PUSH_REG_SHORT); +} + +void i386_device::i386_push_edx() // Opcode 0x52 +{ + UINT32 offset; + if(STACK_32BIT) + offset = REG32(ESP) - 4; + else + offset = (REG16(SP) - 4) & 0xffff; + if(i386_limit_check(SS,offset) == 0) + PUSH32(REG32(EDX) ); + else + FAULT(FAULT_SS,0) + CYCLES(CYCLES_PUSH_REG_SHORT); +} + +void i386_device::i386_push_ebx() // Opcode 0x53 +{ + UINT32 offset; + if(STACK_32BIT) + offset = REG32(ESP) - 4; + else + offset = (REG16(SP) - 4) & 0xffff; + if(i386_limit_check(SS,offset) == 0) + PUSH32(REG32(EBX) ); + else + FAULT(FAULT_SS,0) + CYCLES(CYCLES_PUSH_REG_SHORT); +} + +void i386_device::i386_push_esp() // Opcode 0x54 +{ + UINT32 offset; + if(STACK_32BIT) + offset = REG32(ESP) - 4; + else + offset = (REG16(SP) - 4) & 0xffff; + if(i386_limit_check(SS,offset) == 0) + PUSH32(REG32(ESP) ); + else + FAULT(FAULT_SS,0) + CYCLES(CYCLES_PUSH_REG_SHORT); +} + +void i386_device::i386_push_ebp() // Opcode 0x55 +{ + UINT32 offset; + if(STACK_32BIT) + offset = REG32(ESP) - 4; + else + offset = (REG16(SP) - 4) & 0xffff; + if(i386_limit_check(SS,offset) == 0) + PUSH32(REG32(EBP) ); + else + FAULT(FAULT_SS,0) + CYCLES(CYCLES_PUSH_REG_SHORT); +} + +void i386_device::i386_push_esi() // Opcode 0x56 +{ + UINT32 offset; + if(STACK_32BIT) + offset = REG32(ESP) - 4; + else + offset = (REG16(SP) - 4) & 0xffff; + if(i386_limit_check(SS,offset) == 0) + PUSH32(REG32(ESI) ); + else + FAULT(FAULT_SS,0) + CYCLES(CYCLES_PUSH_REG_SHORT); +} + +void i386_device::i386_push_edi() // Opcode 0x57 +{ + UINT32 offset; + if(STACK_32BIT) + offset = REG32(ESP) - 4; + else + offset = (REG16(SP) - 4) & 0xffff; + if(i386_limit_check(SS,offset) == 0) + PUSH32(REG32(EDI) ); + else + FAULT(FAULT_SS,0) + CYCLES(CYCLES_PUSH_REG_SHORT); +} + +void i386_device::i386_push_cs32() // Opcode 0x0e +{ + UINT32 offset; + if(STACK_32BIT) + offset = REG32(ESP) - 4; + else + offset = (REG16(SP) - 4) & 0xffff; + if(i386_limit_check(SS,offset) == 0) + PUSH32(m_sreg[CS].selector ); + else + FAULT(FAULT_SS,0) + CYCLES(CYCLES_PUSH_SREG); +} + +void i386_device::i386_push_ds32() // Opcode 0x1e +{ + UINT32 offset; + if(STACK_32BIT) + offset = REG32(ESP) - 4; + else + offset = (REG16(SP) - 4) & 0xffff; + if(i386_limit_check(SS,offset) == 0) + PUSH32(m_sreg[DS].selector ); + else + FAULT(FAULT_SS,0) + CYCLES(CYCLES_PUSH_SREG); +} + +void i386_device::i386_push_es32() // Opcode 0x06 +{ + UINT32 offset; + if(STACK_32BIT) + offset = REG32(ESP) - 4; + else + offset = (REG16(SP) - 4) & 0xffff; + if(i386_limit_check(SS,offset) == 0) + PUSH32(m_sreg[ES].selector ); + else + FAULT(FAULT_SS,0) + CYCLES(CYCLES_PUSH_SREG); +} + +void i386_device::i386_push_fs32() // Opcode 0x0f a0 +{ + UINT32 offset; + if(STACK_32BIT) + offset = REG32(ESP) - 4; + else + offset = (REG16(SP) - 4) & 0xffff; + if(i386_limit_check(SS,offset) == 0) + PUSH32(m_sreg[FS].selector ); + else + FAULT(FAULT_SS,0) + CYCLES(CYCLES_PUSH_SREG); +} + +void i386_device::i386_push_gs32() // Opcode 0x0f a8 +{ + UINT32 offset; + if(STACK_32BIT) + offset = REG32(ESP) - 4; + else + offset = (REG16(SP) - 4) & 0xffff; + if(i386_limit_check(SS,offset) == 0) + PUSH32(m_sreg[GS].selector ); + else + FAULT(FAULT_SS,0) + CYCLES(CYCLES_PUSH_SREG); +} + +void i386_device::i386_push_ss32() // Opcode 0x16 +{ + UINT32 offset; + if(STACK_32BIT) + offset = REG32(ESP) - 4; + else + offset = (REG16(SP) - 4) & 0xffff; + if(i386_limit_check(SS,offset) == 0) + PUSH32(m_sreg[SS].selector ); + else + FAULT(FAULT_SS,0) + CYCLES(CYCLES_PUSH_SREG); +} + +void i386_device::i386_push_i32() // Opcode 0x68 +{ + UINT32 value = FETCH32(); + UINT32 offset; + if(STACK_32BIT) + offset = REG32(ESP) - 4; + else + offset = (REG16(SP) - 4) & 0xffff; + if(i386_limit_check(SS,offset) == 0) + PUSH32(value); + else + FAULT(FAULT_SS,0) + CYCLES(CYCLES_PUSH_IMM); +} + +void i386_device::i386_pushad() // Opcode 0x60 +{ + UINT32 temp = REG32(ESP); + UINT32 offset; + if(STACK_32BIT) + offset = REG32(ESP) - 32; + else + offset = (REG16(SP) - 32) & 0xffff; + if(i386_limit_check(SS,offset) == 0) + { + PUSH32(REG32(EAX) ); + PUSH32(REG32(ECX) ); + PUSH32(REG32(EDX) ); + PUSH32(REG32(EBX) ); + PUSH32(temp ); + PUSH32(REG32(EBP) ); + PUSH32(REG32(ESI) ); + PUSH32(REG32(EDI) ); + } + else + FAULT(FAULT_SS,0) + CYCLES(CYCLES_PUSHA); +} + +void i386_device::i386_pushfd() // Opcode 0x9c +{ + if(!m_IOP1 && !m_IOP2 && V8086_MODE) + FAULT(FAULT_GP,0) + UINT32 offset; + if(STACK_32BIT) + offset = REG32(ESP) - 4; + else + offset = (REG16(SP) - 4) & 0xffff; + if(i386_limit_check(SS,offset) == 0) + PUSH32(get_flags() & 0x00fcffff ); + else + FAULT(FAULT_SS,0) + CYCLES(CYCLES_PUSHF); +} + +void i386_device::i386_ret_near32_i16() // Opcode 0xc2 +{ + INT16 disp = FETCH16(); + m_eip = POP32(); + REG32(ESP) += disp; + CHANGE_PC(m_eip); + CYCLES(CYCLES_RET_IMM); /* TODO: Timing = 10 + m */ +} + +void i386_device::i386_ret_near32() // Opcode 0xc3 +{ + m_eip = POP32(); + CHANGE_PC(m_eip); + CYCLES(CYCLES_RET); /* TODO: Timing = 10 + m */ +} + +void i386_device::i386_sbb_rm32_r32() // Opcode 0x19 +{ + UINT32 src, dst; + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + src = LOAD_REG32(modrm); + dst = LOAD_RM32(modrm); + dst = SBB32(dst, src, m_CF); + STORE_RM32(modrm, dst); + CYCLES(CYCLES_ALU_REG_REG); + } else { + UINT32 ea = GetEA(modrm,1); + src = LOAD_REG32(modrm); + dst = READ32(ea); + dst = SBB32(dst, src, m_CF); + WRITE32(ea, dst); + CYCLES(CYCLES_ALU_REG_MEM); + } +} + +void i386_device::i386_sbb_r32_rm32() // Opcode 0x1b +{ + UINT32 src, dst; + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + src = LOAD_RM32(modrm); + dst = LOAD_REG32(modrm); + dst = SBB32(dst, src, m_CF); + STORE_REG32(modrm, dst); + CYCLES(CYCLES_ALU_REG_REG); + } else { + UINT32 ea = GetEA(modrm,0); + src = READ32(ea); + dst = LOAD_REG32(modrm); + dst = SBB32(dst, src, m_CF); + STORE_REG32(modrm, dst); + CYCLES(CYCLES_ALU_MEM_REG); + } +} + +void i386_device::i386_sbb_eax_i32() // Opcode 0x1d +{ + UINT32 src, dst; + src = FETCH32(); + dst = REG32(EAX); + dst = SBB32(dst, src, m_CF); + REG32(EAX) = dst; + CYCLES(CYCLES_ALU_IMM_ACC); +} + +void i386_device::i386_scasd() // Opcode 0xaf +{ + UINT32 eas, src, dst; + eas = i386_translate(ES, m_address_size ? REG32(EDI) : REG16(DI), 0 ); + src = READ32(eas); + dst = REG32(EAX); + SUB32(dst, src); + BUMP_DI(4); + CYCLES(CYCLES_SCAS); +} + +void i386_device::i386_shld32_i8() // Opcode 0x0f a4 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + UINT32 dst = LOAD_RM32(modrm); + UINT32 upper = LOAD_REG32(modrm); + UINT8 shift = FETCH(); + shift &= 31; + if( shift == 0 ) { + } else { + m_CF = (dst & (1 << (32-shift))) ? 1 : 0; + dst = (dst << shift) | (upper >> (32-shift)); + m_OF = m_CF ^ (dst >> 31); + SetSZPF32(dst); + } + STORE_RM32(modrm, dst); + CYCLES(CYCLES_SHLD_REG); + } else { + UINT32 ea = GetEA(modrm,1); + UINT32 dst = READ32(ea); + UINT32 upper = LOAD_REG32(modrm); + UINT8 shift = FETCH(); + shift &= 31; + if( shift == 0 ) { + } else { + m_CF = (dst & (1 << (32-shift))) ? 1 : 0; + dst = (dst << shift) | (upper >> (32-shift)); + m_OF = m_CF ^ (dst >> 31); + SetSZPF32(dst); + } + WRITE32(ea, dst); + CYCLES(CYCLES_SHLD_MEM); + } +} + +void i386_device::i386_shld32_cl() // Opcode 0x0f a5 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + UINT32 dst = LOAD_RM32(modrm); + UINT32 upper = LOAD_REG32(modrm); + UINT8 shift = REG8(CL); + shift &= 31; + if( shift == 0 ) { + } else { + m_CF = (dst & (1 << (32-shift))) ? 1 : 0; + dst = (dst << shift) | (upper >> (32-shift)); + m_OF = m_CF ^ (dst >> 31); + SetSZPF32(dst); + } + STORE_RM32(modrm, dst); + CYCLES(CYCLES_SHLD_REG); + } else { + UINT32 ea = GetEA(modrm,1); + UINT32 dst = READ32(ea); + UINT32 upper = LOAD_REG32(modrm); + UINT8 shift = REG8(CL); + shift &= 31; + if( shift == 0 ) { + } else { + m_CF = (dst & (1 << (32-shift))) ? 1 : 0; + dst = (dst << shift) | (upper >> (32-shift)); + m_OF = m_CF ^ (dst >> 31); + SetSZPF32(dst); + } + WRITE32(ea, dst); + CYCLES(CYCLES_SHLD_MEM); + } +} + +void i386_device::i386_shrd32_i8() // Opcode 0x0f ac +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + UINT32 dst = LOAD_RM32(modrm); + UINT32 upper = LOAD_REG32(modrm); + UINT8 shift = FETCH(); + shift &= 31; + if( shift == 0 ) { + } else { + m_CF = (dst & (1 << (shift-1))) ? 1 : 0; + dst = (dst >> shift) | (upper << (32-shift)); + m_OF = ((dst >> 31) ^ (dst >> 30)) & 1; + SetSZPF32(dst); + } + STORE_RM32(modrm, dst); + CYCLES(CYCLES_SHRD_REG); + } else { + UINT32 ea = GetEA(modrm,1); + UINT32 dst = READ32(ea); + UINT32 upper = LOAD_REG32(modrm); + UINT8 shift = FETCH(); + shift &= 31; + if( shift == 0 ) { + } else { + m_CF = (dst & (1 << (shift-1))) ? 1 : 0; + dst = (dst >> shift) | (upper << (32-shift)); + m_OF = ((dst >> 31) ^ (dst >> 30)) & 1; + SetSZPF32(dst); + } + WRITE32(ea, dst); + CYCLES(CYCLES_SHRD_MEM); + } +} + +void i386_device::i386_shrd32_cl() // Opcode 0x0f ad +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + UINT32 dst = LOAD_RM32(modrm); + UINT32 upper = LOAD_REG32(modrm); + UINT8 shift = REG8(CL); + shift &= 31; + if( shift == 0 ) { + } else { + m_CF = (dst & (1 << (shift-1))) ? 1 : 0; + dst = (dst >> shift) | (upper << (32-shift)); + m_OF = ((dst >> 31) ^ (dst >> 30)) & 1; + SetSZPF32(dst); + } + STORE_RM32(modrm, dst); + CYCLES(CYCLES_SHRD_REG); + } else { + UINT32 ea = GetEA(modrm,1); + UINT32 dst = READ32(ea); + UINT32 upper = LOAD_REG32(modrm); + UINT8 shift = REG8(CL); + shift &= 31; + if( shift == 0 ) { + } else { + m_CF = (dst & (1 << (shift-1))) ? 1 : 0; + dst = (dst >> shift) | (upper << (32-shift)); + m_OF = ((dst >> 31) ^ (dst >> 30)) & 1; + SetSZPF32(dst); + } + WRITE32(ea, dst); + CYCLES(CYCLES_SHRD_MEM); + } +} + +void i386_device::i386_stosd() // Opcode 0xab +{ + UINT32 eas = i386_translate(ES, m_address_size ? REG32(EDI) : REG16(DI), 1 ); + WRITE32(eas, REG32(EAX)); + BUMP_DI(4); + CYCLES(CYCLES_STOS); +} + +void i386_device::i386_sub_rm32_r32() // Opcode 0x29 +{ + UINT32 src, dst; + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + src = LOAD_REG32(modrm); + dst = LOAD_RM32(modrm); + dst = SUB32(dst, src); + STORE_RM32(modrm, dst); + CYCLES(CYCLES_ALU_REG_REG); + } else { + UINT32 ea = GetEA(modrm,1); + src = LOAD_REG32(modrm); + dst = READ32(ea); + dst = SUB32(dst, src); + WRITE32(ea, dst); + CYCLES(CYCLES_ALU_REG_MEM); + } +} + +void i386_device::i386_sub_r32_rm32() // Opcode 0x2b +{ + UINT32 src, dst; + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + src = LOAD_RM32(modrm); + dst = LOAD_REG32(modrm); + dst = SUB32(dst, src); + STORE_REG32(modrm, dst); + CYCLES(CYCLES_ALU_REG_REG); + } else { + UINT32 ea = GetEA(modrm,1); + src = READ32(ea); + dst = LOAD_REG32(modrm); + dst = SUB32(dst, src); + STORE_REG32(modrm, dst); + CYCLES(CYCLES_ALU_MEM_REG); + } +} + +void i386_device::i386_sub_eax_i32() // Opcode 0x2d +{ + UINT32 src, dst; + src = FETCH32(); + dst = REG32(EAX); + dst = SUB32(dst, src); + REG32(EAX) = dst; + CYCLES(CYCLES_ALU_IMM_ACC); +} + +void i386_device::i386_test_eax_i32() // Opcode 0xa9 +{ + UINT32 src = FETCH32(); + UINT32 dst = REG32(EAX); + dst = src & dst; + SetSZPF32(dst); + m_CF = 0; + m_OF = 0; + CYCLES(CYCLES_TEST_IMM_ACC); +} + +void i386_device::i386_test_rm32_r32() // Opcode 0x85 +{ + UINT32 src, dst; + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + src = LOAD_REG32(modrm); + dst = LOAD_RM32(modrm); + dst = src & dst; + SetSZPF32(dst); + m_CF = 0; + m_OF = 0; + CYCLES(CYCLES_TEST_REG_REG); + } else { + UINT32 ea = GetEA(modrm,0); + src = LOAD_REG32(modrm); + dst = READ32(ea); + dst = src & dst; + SetSZPF32(dst); + m_CF = 0; + m_OF = 0; + CYCLES(CYCLES_TEST_REG_MEM); + } +} + +void i386_device::i386_xchg_eax_ecx() // Opcode 0x91 +{ + UINT32 temp; + temp = REG32(EAX); + REG32(EAX) = REG32(ECX); + REG32(ECX) = temp; + CYCLES(CYCLES_XCHG_REG_REG); +} + +void i386_device::i386_xchg_eax_edx() // Opcode 0x92 +{ + UINT32 temp; + temp = REG32(EAX); + REG32(EAX) = REG32(EDX); + REG32(EDX) = temp; + CYCLES(CYCLES_XCHG_REG_REG); +} + +void i386_device::i386_xchg_eax_ebx() // Opcode 0x93 +{ + UINT32 temp; + temp = REG32(EAX); + REG32(EAX) = REG32(EBX); + REG32(EBX) = temp; + CYCLES(CYCLES_XCHG_REG_REG); +} + +void i386_device::i386_xchg_eax_esp() // Opcode 0x94 +{ + UINT32 temp; + temp = REG32(EAX); + REG32(EAX) = REG32(ESP); + REG32(ESP) = temp; + CYCLES(CYCLES_XCHG_REG_REG); +} + +void i386_device::i386_xchg_eax_ebp() // Opcode 0x95 +{ + UINT32 temp; + temp = REG32(EAX); + REG32(EAX) = REG32(EBP); + REG32(EBP) = temp; + CYCLES(CYCLES_XCHG_REG_REG); +} + +void i386_device::i386_xchg_eax_esi() // Opcode 0x96 +{ + UINT32 temp; + temp = REG32(EAX); + REG32(EAX) = REG32(ESI); + REG32(ESI) = temp; + CYCLES(CYCLES_XCHG_REG_REG); +} + +void i386_device::i386_xchg_eax_edi() // Opcode 0x97 +{ + UINT32 temp; + temp = REG32(EAX); + REG32(EAX) = REG32(EDI); + REG32(EDI) = temp; + CYCLES(CYCLES_XCHG_REG_REG); +} + +void i386_device::i386_xchg_r32_rm32() // Opcode 0x87 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + UINT32 src = LOAD_RM32(modrm); + UINT32 dst = LOAD_REG32(modrm); + STORE_REG32(modrm, src); + STORE_RM32(modrm, dst); + CYCLES(CYCLES_XCHG_REG_REG); + } else { + UINT32 ea = GetEA(modrm,1); + UINT32 src = READ32(ea); + UINT32 dst = LOAD_REG32(modrm); + WRITE32(ea, dst); + STORE_REG32(modrm, src); + CYCLES(CYCLES_XCHG_REG_MEM); + } +} + +void i386_device::i386_xor_rm32_r32() // Opcode 0x31 +{ + UINT32 src, dst; + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + src = LOAD_REG32(modrm); + dst = LOAD_RM32(modrm); + dst = XOR32(dst, src); + STORE_RM32(modrm, dst); + CYCLES(CYCLES_ALU_REG_REG); + } else { + UINT32 ea = GetEA(modrm,1); + src = LOAD_REG32(modrm); + dst = READ32(ea); + dst = XOR32(dst, src); + WRITE32(ea, dst); + CYCLES(CYCLES_ALU_REG_MEM); + } +} + +void i386_device::i386_xor_r32_rm32() // Opcode 0x33 +{ + UINT32 src, dst; + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + src = LOAD_RM32(modrm); + dst = LOAD_REG32(modrm); + dst = XOR32(dst, src); + STORE_REG32(modrm, dst); + CYCLES(CYCLES_ALU_REG_REG); + } else { + UINT32 ea = GetEA(modrm,0); + src = READ32(ea); + dst = LOAD_REG32(modrm); + dst = XOR32(dst, src); + STORE_REG32(modrm, dst); + CYCLES(CYCLES_ALU_MEM_REG); + } +} + +void i386_device::i386_xor_eax_i32() // Opcode 0x35 +{ + UINT32 src, dst; + src = FETCH32(); + dst = REG32(EAX); + dst = XOR32(dst, src); + REG32(EAX) = dst; + CYCLES(CYCLES_ALU_IMM_ACC); +} + + + +void i386_device::i386_group81_32() // Opcode 0x81 +{ + UINT32 ea; + UINT32 src, dst; + UINT8 modrm = FETCH(); + + switch( (modrm >> 3) & 0x7 ) + { + case 0: // ADD Rm32, i32 + if( modrm >= 0xc0 ) { + dst = LOAD_RM32(modrm); + src = FETCH32(); + dst = ADD32(dst, src); + STORE_RM32(modrm, dst); + CYCLES(CYCLES_ALU_REG_REG); + } else { + ea = GetEA(modrm,1); + dst = READ32(ea); + src = FETCH32(); + dst = ADD32(dst, src); + WRITE32(ea, dst); + CYCLES(CYCLES_ALU_REG_MEM); + } + break; + case 1: // OR Rm32, i32 + if( modrm >= 0xc0 ) { + dst = LOAD_RM32(modrm); + src = FETCH32(); + dst = OR32(dst, src); + STORE_RM32(modrm, dst); + CYCLES(CYCLES_ALU_REG_REG); + } else { + ea = GetEA(modrm,1); + dst = READ32(ea); + src = FETCH32(); + dst = OR32(dst, src); + WRITE32(ea, dst); + CYCLES(CYCLES_ALU_REG_MEM); + } + break; + case 2: // ADC Rm32, i32 + if( modrm >= 0xc0 ) { + dst = LOAD_RM32(modrm); + src = FETCH32(); + dst = ADC32(dst, src, m_CF); + STORE_RM32(modrm, dst); + CYCLES(CYCLES_ALU_REG_REG); + } else { + ea = GetEA(modrm,1); + dst = READ32(ea); + src = FETCH32(); + dst = ADC32(dst, src, m_CF); + WRITE32(ea, dst); + CYCLES(CYCLES_ALU_REG_MEM); + } + break; + case 3: // SBB Rm32, i32 + if( modrm >= 0xc0 ) { + dst = LOAD_RM32(modrm); + src = FETCH32(); + dst = SBB32(dst, src, m_CF); + STORE_RM32(modrm, dst); + CYCLES(CYCLES_ALU_REG_REG); + } else { + ea = GetEA(modrm,1); + dst = READ32(ea); + src = FETCH32(); + dst = SBB32(dst, src, m_CF); + WRITE32(ea, dst); + CYCLES(CYCLES_ALU_REG_MEM); + } + break; + case 4: // AND Rm32, i32 + if( modrm >= 0xc0 ) { + dst = LOAD_RM32(modrm); + src = FETCH32(); + dst = AND32(dst, src); + STORE_RM32(modrm, dst); + CYCLES(CYCLES_ALU_REG_REG); + } else { + ea = GetEA(modrm,1); + dst = READ32(ea); + src = FETCH32(); + dst = AND32(dst, src); + WRITE32(ea, dst); + CYCLES(CYCLES_ALU_REG_MEM); + } + break; + case 5: // SUB Rm32, i32 + if( modrm >= 0xc0 ) { + dst = LOAD_RM32(modrm); + src = FETCH32(); + dst = SUB32(dst, src); + STORE_RM32(modrm, dst); + CYCLES(CYCLES_ALU_REG_REG); + } else { + ea = GetEA(modrm,1); + dst = READ32(ea); + src = FETCH32(); + dst = SUB32(dst, src); + WRITE32(ea, dst); + CYCLES(CYCLES_ALU_REG_MEM); + } + break; + case 6: // XOR Rm32, i32 + if( modrm >= 0xc0 ) { + dst = LOAD_RM32(modrm); + src = FETCH32(); + dst = XOR32(dst, src); + STORE_RM32(modrm, dst); + CYCLES(CYCLES_ALU_REG_REG); + } else { + ea = GetEA(modrm,1); + dst = READ32(ea); + src = FETCH32(); + dst = XOR32(dst, src); + WRITE32(ea, dst); + CYCLES(CYCLES_ALU_REG_MEM); + } + break; + case 7: // CMP Rm32, i32 + if( modrm >= 0xc0 ) { + dst = LOAD_RM32(modrm); + src = FETCH32(); + SUB32(dst, src); + CYCLES(CYCLES_CMP_REG_REG); + } else { + ea = GetEA(modrm,0); + dst = READ32(ea); + src = FETCH32(); + SUB32(dst, src); + CYCLES(CYCLES_CMP_REG_MEM); + } + break; + } +} + +void i386_device::i386_group83_32() // Opcode 0x83 +{ + UINT32 ea; + UINT32 src, dst; + UINT8 modrm = FETCH(); + + switch( (modrm >> 3) & 0x7 ) + { + case 0: // ADD Rm32, i32 + if( modrm >= 0xc0 ) { + dst = LOAD_RM32(modrm); + src = (UINT32)(INT32)(INT8)FETCH(); + dst = ADD32(dst, src); + STORE_RM32(modrm, dst); + CYCLES(CYCLES_ALU_REG_REG); + } else { + ea = GetEA(modrm,1); + dst = READ32(ea); + src = (UINT32)(INT32)(INT8)FETCH(); + dst = ADD32(dst, src); + WRITE32(ea, dst); + CYCLES(CYCLES_ALU_REG_MEM); + } + break; + case 1: // OR Rm32, i32 + if( modrm >= 0xc0 ) { + dst = LOAD_RM32(modrm); + src = (UINT32)(INT32)(INT8)FETCH(); + dst = OR32(dst, src); + STORE_RM32(modrm, dst); + CYCLES(CYCLES_ALU_REG_REG); + } else { + ea = GetEA(modrm,1); + dst = READ32(ea); + src = (UINT32)(INT32)(INT8)FETCH(); + dst = OR32(dst, src); + WRITE32(ea, dst); + CYCLES(CYCLES_ALU_REG_MEM); + } + break; + case 2: // ADC Rm32, i32 + if( modrm >= 0xc0 ) { + dst = LOAD_RM32(modrm); + src = (UINT32)(INT32)(INT8)FETCH(); + dst = ADC32(dst, src, m_CF); + STORE_RM32(modrm, dst); + CYCLES(CYCLES_ALU_REG_REG); + } else { + ea = GetEA(modrm,1); + dst = READ32(ea); + src = (UINT32)(INT32)(INT8)FETCH(); + dst = ADC32(dst, src, m_CF); + WRITE32(ea, dst); + CYCLES(CYCLES_ALU_REG_MEM); + } + break; + case 3: // SBB Rm32, i32 + if( modrm >= 0xc0 ) { + dst = LOAD_RM32(modrm); + src = ((UINT32)(INT32)(INT8)FETCH()); + dst = SBB32(dst, src, m_CF); + STORE_RM32(modrm, dst); + CYCLES(CYCLES_ALU_REG_REG); + } else { + ea = GetEA(modrm,1); + dst = READ32(ea); + src = ((UINT32)(INT32)(INT8)FETCH()); + dst = SBB32(dst, src, m_CF); + WRITE32(ea, dst); + CYCLES(CYCLES_ALU_REG_MEM); + } + break; + case 4: // AND Rm32, i32 + if( modrm >= 0xc0 ) { + dst = LOAD_RM32(modrm); + src = (UINT32)(INT32)(INT8)FETCH(); + dst = AND32(dst, src); + STORE_RM32(modrm, dst); + CYCLES(CYCLES_ALU_REG_REG); + } else { + ea = GetEA(modrm,1); + dst = READ32(ea); + src = (UINT32)(INT32)(INT8)FETCH(); + dst = AND32(dst, src); + WRITE32(ea, dst); + CYCLES(CYCLES_ALU_REG_MEM); + } + break; + case 5: // SUB Rm32, i32 + if( modrm >= 0xc0 ) { + dst = LOAD_RM32(modrm); + src = (UINT32)(INT32)(INT8)FETCH(); + dst = SUB32(dst, src); + STORE_RM32(modrm, dst); + CYCLES(CYCLES_ALU_REG_REG); + } else { + ea = GetEA(modrm,1); + dst = READ32(ea); + src = (UINT32)(INT32)(INT8)FETCH(); + dst = SUB32(dst, src); + WRITE32(ea, dst); + CYCLES(CYCLES_ALU_REG_MEM); + } + break; + case 6: // XOR Rm32, i32 + if( modrm >= 0xc0 ) { + dst = LOAD_RM32(modrm); + src = (UINT32)(INT32)(INT8)FETCH(); + dst = XOR32(dst, src); + STORE_RM32(modrm, dst); + CYCLES(CYCLES_ALU_REG_REG); + } else { + ea = GetEA(modrm,1); + dst = READ32(ea); + src = (UINT32)(INT32)(INT8)FETCH(); + dst = XOR32(dst, src); + WRITE32(ea, dst); + CYCLES(CYCLES_ALU_REG_MEM); + } + break; + case 7: // CMP Rm32, i32 + if( modrm >= 0xc0 ) { + dst = LOAD_RM32(modrm); + src = (UINT32)(INT32)(INT8)FETCH(); + SUB32(dst, src); + CYCLES(CYCLES_CMP_REG_REG); + } else { + ea = GetEA(modrm,0); + dst = READ32(ea); + src = (UINT32)(INT32)(INT8)FETCH(); + SUB32(dst, src); + CYCLES(CYCLES_CMP_REG_MEM); + } + break; + } +} + +void i386_device::i386_groupC1_32() // Opcode 0xc1 +{ + UINT32 dst; + UINT8 modrm = FETCH(); + UINT8 shift; + + if( modrm >= 0xc0 ) { + dst = LOAD_RM32(modrm); + shift = FETCH() & 0x1f; + dst = i386_shift_rotate32(modrm, dst, shift); + STORE_RM32(modrm, dst); + } else { + UINT32 ea = GetEA(modrm,1); + dst = READ32(ea); + shift = FETCH() & 0x1f; + dst = i386_shift_rotate32(modrm, dst, shift); + WRITE32(ea, dst); + } +} + +void i386_device::i386_groupD1_32() // Opcode 0xd1 +{ + UINT32 dst; + UINT8 modrm = FETCH(); + + if( modrm >= 0xc0 ) { + dst = LOAD_RM32(modrm); + dst = i386_shift_rotate32(modrm, dst, 1); + STORE_RM32(modrm, dst); + } else { + UINT32 ea = GetEA(modrm,1); + dst = READ32(ea); + dst = i386_shift_rotate32(modrm, dst, 1); + WRITE32(ea, dst); + } +} + +void i386_device::i386_groupD3_32() // Opcode 0xd3 +{ + UINT32 dst; + UINT8 modrm = FETCH(); + + if( modrm >= 0xc0 ) { + dst = LOAD_RM32(modrm); + dst = i386_shift_rotate32(modrm, dst, REG8(CL)); + STORE_RM32(modrm, dst); + } else { + UINT32 ea = GetEA(modrm,1); + dst = READ32(ea); + dst = i386_shift_rotate32(modrm, dst, REG8(CL)); + WRITE32(ea, dst); + } +} + +void i386_device::i386_groupF7_32() // Opcode 0xf7 +{ + UINT8 modrm = FETCH(); + + switch( (modrm >> 3) & 0x7 ) + { + case 0: /* TEST Rm32, i32 */ + if( modrm >= 0xc0 ) { + UINT32 dst = LOAD_RM32(modrm); + UINT32 src = FETCH32(); + dst &= src; + m_CF = m_OF = m_AF = 0; + SetSZPF32(dst); + CYCLES(CYCLES_TEST_IMM_REG); + } else { + UINT32 ea = GetEA(modrm,0); + UINT32 dst = READ32(ea); + UINT32 src = FETCH32(); + dst &= src; + m_CF = m_OF = m_AF = 0; + SetSZPF32(dst); + CYCLES(CYCLES_TEST_IMM_MEM); + } + break; + case 2: /* NOT Rm32 */ + if( modrm >= 0xc0 ) { + UINT32 dst = LOAD_RM32(modrm); + dst = ~dst; + STORE_RM32(modrm, dst); + CYCLES(CYCLES_NOT_REG); + } else { + UINT32 ea = GetEA(modrm,1); + UINT32 dst = READ32(ea); + dst = ~dst; + WRITE32(ea, dst); + CYCLES(CYCLES_NOT_MEM); + } + break; + case 3: /* NEG Rm32 */ + if( modrm >= 0xc0 ) { + UINT32 dst = LOAD_RM32(modrm); + dst = SUB32(0, dst ); + STORE_RM32(modrm, dst); + CYCLES(CYCLES_NEG_REG); + } else { + UINT32 ea = GetEA(modrm,1); + UINT32 dst = READ32(ea); + dst = SUB32(0, dst ); + WRITE32(ea, dst); + CYCLES(CYCLES_NEG_MEM); + } + break; + case 4: /* MUL EAX, Rm32 */ + { + UINT64 result; + UINT32 src, dst; + if( modrm >= 0xc0 ) { + src = LOAD_RM32(modrm); + CYCLES(CYCLES_MUL32_ACC_REG); /* TODO: Correct multiply timing */ + } else { + UINT32 ea = GetEA(modrm,0); + src = READ32(ea); + CYCLES(CYCLES_MUL32_ACC_MEM); /* TODO: Correct multiply timing */ + } + + dst = REG32(EAX); + result = (UINT64)src * (UINT64)dst; + REG32(EDX) = (UINT32)(result >> 32); + REG32(EAX) = (UINT32)result; + + m_CF = m_OF = (REG32(EDX) != 0); + } + break; + case 5: /* IMUL EAX, Rm32 */ + { + INT64 result; + INT64 src, dst; + if( modrm >= 0xc0 ) { + src = (INT64)(INT32)LOAD_RM32(modrm); + CYCLES(CYCLES_IMUL32_ACC_REG); /* TODO: Correct multiply timing */ + } else { + UINT32 ea = GetEA(modrm,0); + src = (INT64)(INT32)READ32(ea); + CYCLES(CYCLES_IMUL32_ACC_MEM); /* TODO: Correct multiply timing */ + } + + dst = (INT64)(INT32)REG32(EAX); + result = src * dst; + + REG32(EDX) = (UINT32)(result >> 32); + REG32(EAX) = (UINT32)result; + + m_CF = m_OF = !(result == (INT64)(INT32)result); + } + break; + case 6: /* DIV EAX, Rm32 */ + { + UINT64 quotient, remainder, result; + UINT32 src; + if( modrm >= 0xc0 ) { + src = LOAD_RM32(modrm); + CYCLES(CYCLES_DIV32_ACC_REG); + } else { + UINT32 ea = GetEA(modrm,0); + src = READ32(ea); + CYCLES(CYCLES_DIV32_ACC_MEM); + } + + quotient = ((UINT64)(REG32(EDX)) << 32) | (UINT64)(REG32(EAX)); + if( src ) { + remainder = quotient % (UINT64)src; + result = quotient / (UINT64)src; + if( result > 0xffffffff ) { + /* TODO: Divide error */ + } else { + REG32(EDX) = (UINT32)remainder; + REG32(EAX) = (UINT32)result; + } + } else { + i386_trap(0, 0, 0); + } + } + break; + case 7: /* IDIV EAX, Rm32 */ + { + INT64 quotient, remainder, result; + UINT32 src; + if( modrm >= 0xc0 ) { + src = LOAD_RM32(modrm); + CYCLES(CYCLES_IDIV32_ACC_REG); + } else { + UINT32 ea = GetEA(modrm,0); + src = READ32(ea); + CYCLES(CYCLES_IDIV32_ACC_MEM); + } + + quotient = (((INT64)REG32(EDX)) << 32) | ((UINT64)REG32(EAX)); + if( src ) { + remainder = quotient % (INT64)(INT32)src; + result = quotient / (INT64)(INT32)src; + if( result > 0xffffffff ) { + /* TODO: Divide error */ + } else { + REG32(EDX) = (UINT32)remainder; + REG32(EAX) = (UINT32)result; + } + } else { + i386_trap(0, 0, 0); + } + } + break; + } +} + +void i386_device::i386_groupFF_32() // Opcode 0xff +{ + UINT8 modrm = FETCH(); + + switch( (modrm >> 3) & 0x7 ) + { + case 0: /* INC Rm32 */ + if( modrm >= 0xc0 ) { + UINT32 dst = LOAD_RM32(modrm); + dst = INC32(dst); + STORE_RM32(modrm, dst); + CYCLES(CYCLES_INC_REG); + } else { + UINT32 ea = GetEA(modrm,1); + UINT32 dst = READ32(ea); + dst = INC32(dst); + WRITE32(ea, dst); + CYCLES(CYCLES_INC_MEM); + } + break; + case 1: /* DEC Rm32 */ + if( modrm >= 0xc0 ) { + UINT32 dst = LOAD_RM32(modrm); + dst = DEC32(dst); + STORE_RM32(modrm, dst); + CYCLES(CYCLES_DEC_REG); + } else { + UINT32 ea = GetEA(modrm,1); + UINT32 dst = READ32(ea); + dst = DEC32(dst); + WRITE32(ea, dst); + CYCLES(CYCLES_DEC_MEM); + } + break; + case 2: /* CALL Rm32 */ + { + UINT32 address; + if( modrm >= 0xc0 ) { + address = LOAD_RM32(modrm); + CYCLES(CYCLES_CALL_REG); /* TODO: Timing = 7 + m */ + } else { + UINT32 ea = GetEA(modrm,0); + address = READ32(ea); + CYCLES(CYCLES_CALL_MEM); /* TODO: Timing = 10 + m */ + } + PUSH32(m_eip ); + m_eip = address; + CHANGE_PC(m_eip); + } + break; + case 3: /* CALL FAR Rm32 */ + { + UINT16 selector; + UINT32 address; + + if( modrm >= 0xc0 ) + { + report_invalid_modrm("groupFF_32", modrm); + } + else + { + UINT32 ea = GetEA(modrm,0); + address = READ32(ea + 0); + selector = READ16(ea + 4); + CYCLES(CYCLES_CALL_MEM_INTERSEG); /* TODO: Timing = 10 + m */ + if(PROTECTED_MODE && !V8086_MODE) + { + i386_protected_mode_call(selector,address,1,1); + } + else + { + PUSH32(m_sreg[CS].selector ); + PUSH32(m_eip ); + m_sreg[CS].selector = selector; + m_performed_intersegment_jump = 1; + i386_load_segment_descriptor(CS ); + m_eip = address; + CHANGE_PC(m_eip); + } + } + } + break; + case 4: /* JMP Rm32 */ + { + UINT32 address; + if( modrm >= 0xc0 ) { + address = LOAD_RM32(modrm); + CYCLES(CYCLES_JMP_REG); /* TODO: Timing = 7 + m */ + } else { + UINT32 ea = GetEA(modrm,0); + address = READ32(ea); + CYCLES(CYCLES_JMP_MEM); /* TODO: Timing = 10 + m */ + } + m_eip = address; + CHANGE_PC(m_eip); + } + break; + case 5: /* JMP FAR Rm32 */ + { + UINT16 selector; + UINT32 address; + + if( modrm >= 0xc0 ) + { + report_invalid_modrm("groupFF_32", modrm); + } + else + { + UINT32 ea = GetEA(modrm,0); + address = READ32(ea + 0); + selector = READ16(ea + 4); + CYCLES(CYCLES_JMP_MEM_INTERSEG); /* TODO: Timing = 10 + m */ + if(PROTECTED_MODE && !V8086_MODE) + { + i386_protected_mode_jump(selector,address,1,1); + } + else + { + m_sreg[CS].selector = selector; + m_performed_intersegment_jump = 1; + i386_load_segment_descriptor(CS ); + m_eip = address; + CHANGE_PC(m_eip); + } + } + } + break; + case 6: /* PUSH Rm32 */ + { + UINT32 value; + if( modrm >= 0xc0 ) { + value = LOAD_RM32(modrm); + } else { + UINT32 ea = GetEA(modrm,0); + value = READ32(ea); + } + PUSH32(value); + CYCLES(CYCLES_PUSH_RM); + } + break; + default: + report_invalid_modrm("groupFF_32", modrm); + break; + } +} + +void i386_device::i386_group0F00_32() // Opcode 0x0f 00 +{ + UINT32 address, ea; + UINT8 modrm = FETCH(); + I386_SREG seg; + UINT8 result; + + switch( (modrm >> 3) & 0x7 ) + { + case 0: /* SLDT */ + if ( PROTECTED_MODE && !V8086_MODE ) + { + if( modrm >= 0xc0 ) { + STORE_RM32(modrm, m_ldtr.segment); + CYCLES(CYCLES_SLDT_REG); + } else { + ea = GetEA(modrm,1); + WRITE16(ea, m_ldtr.segment); + CYCLES(CYCLES_SLDT_MEM); + } + } + else + { + i386_trap(6, 0, 0); + } + break; + case 1: /* STR */ + if ( PROTECTED_MODE && !V8086_MODE ) + { + if( modrm >= 0xc0 ) { + STORE_RM32(modrm, m_task.segment); + CYCLES(CYCLES_STR_REG); + } else { + ea = GetEA(modrm,1); + WRITE16(ea, m_task.segment); + CYCLES(CYCLES_STR_MEM); + } + } + else + { + i386_trap(6, 0, 0); + } + break; + case 2: /* LLDT */ + if ( PROTECTED_MODE && !V8086_MODE ) + { + if(m_CPL) + FAULT(FAULT_GP,0) + if( modrm >= 0xc0 ) { + address = LOAD_RM32(modrm); + m_ldtr.segment = address; + CYCLES(CYCLES_LLDT_REG); + } else { + ea = GetEA(modrm,0); + m_ldtr.segment = READ32(ea); + CYCLES(CYCLES_LLDT_MEM); + } + memset(&seg, 0, sizeof(seg)); + seg.selector = m_ldtr.segment; + i386_load_protected_mode_segment(&seg,NULL); + m_ldtr.limit = seg.limit; + m_ldtr.base = seg.base; + m_ldtr.flags = seg.flags; + } + else + { + i386_trap(6, 0, 0); + } + break; + + case 3: /* LTR */ + if ( PROTECTED_MODE && !V8086_MODE ) + { + if(m_CPL) + FAULT(FAULT_GP,0) + if( modrm >= 0xc0 ) { + address = LOAD_RM32(modrm); + m_task.segment = address; + CYCLES(CYCLES_LTR_REG); + } else { + ea = GetEA(modrm,0); + m_task.segment = READ32(ea); + CYCLES(CYCLES_LTR_MEM); + } + memset(&seg, 0, sizeof(seg)); + seg.selector = m_task.segment; + i386_load_protected_mode_segment(&seg,NULL); + + UINT32 addr = ((seg.selector & 4) ? m_ldtr.base : m_gdtr.base) + (seg.selector & ~7) + 5; + i386_translate_address(TRANSLATE_READ, &addr, NULL); + m_program->write_byte(addr, (seg.flags & 0xff) | 2); + + m_task.limit = seg.limit; + m_task.base = seg.base; + m_task.flags = seg.flags | 2; + } + else + { + i386_trap(6, 0, 0); + } + break; + + case 4: /* VERR */ + if ( PROTECTED_MODE && !V8086_MODE ) + { + if( modrm >= 0xc0 ) { + address = LOAD_RM32(modrm); + CYCLES(CYCLES_VERR_REG); + } else { + ea = GetEA(modrm,0); + address = READ32(ea); + CYCLES(CYCLES_VERR_MEM); + } + memset(&seg, 0, sizeof(seg)); + seg.selector = address; + result = i386_load_protected_mode_segment(&seg,NULL); + // check if the segment is a code or data segment (not a special segment type, like a TSS, gate, LDT...) + if(!(seg.flags & 0x10)) + result = 0; + // check that the segment is readable + if(seg.flags & 0x10) // is code or data segment + { + if(seg.flags & 0x08) // is code segment, so check if it's readable + { + if(!(seg.flags & 0x02)) + { + result = 0; + } + else + { // check if conforming, these are always readable, regardless of privilege + if(!(seg.flags & 0x04)) + { + // if not conforming, then we must check privilege levels (TODO: current privilege level check) + if(((seg.flags >> 5) & 0x03) < (address & 0x03)) + result = 0; + } + } + } + } + // check that the descriptor privilege is greater or equal to the selector's privilege level and the current privilege (TODO) + SetZF(result); + } + else + { + i386_trap(6, 0, 0); + logerror("i386: VERR: Exception - Running in real mode or virtual 8086 mode.\n"); + } + break; + + case 5: /* VERW */ + if ( PROTECTED_MODE && !V8086_MODE ) + { + if( modrm >= 0xc0 ) { + address = LOAD_RM16(modrm); + CYCLES(CYCLES_VERW_REG); + } else { + ea = GetEA(modrm,0); + address = READ16(ea); + CYCLES(CYCLES_VERW_MEM); + } + memset(&seg, 0, sizeof(seg)); + seg.selector = address; + result = i386_load_protected_mode_segment(&seg,NULL); + // check if the segment is a code or data segment (not a special segment type, like a TSS, gate, LDT...) + if(!(seg.flags & 0x10)) + result = 0; + // check that the segment is writable + if(seg.flags & 0x10) // is code or data segment + { + if(seg.flags & 0x08) // is code segment (and thus, not writable) + { + result = 0; + } + else + { // is data segment + if(!(seg.flags & 0x02)) + result = 0; + } + } + // check that the descriptor privilege is greater or equal to the selector's privilege level and the current privilege (TODO) + if(((seg.flags >> 5) & 0x03) < (address & 0x03)) + result = 0; + SetZF(result); + } + else + { + i386_trap(6, 0, 0); + logerror("i386: VERW: Exception - Running in real mode or virtual 8086 mode.\n"); + } + break; + + default: + report_invalid_modrm("group0F00_32", modrm); + break; + } +} + +void i386_device::i386_group0F01_32() // Opcode 0x0f 01 +{ + UINT8 modrm = FETCH(); + UINT32 address, ea; + + switch( (modrm >> 3) & 0x7 ) + { + case 0: /* SGDT */ + { + if( modrm >= 0xc0 ) { + address = LOAD_RM32(modrm); + ea = i386_translate(CS, address, 1 ); + } else { + ea = GetEA(modrm,1); + } + WRITE16(ea, m_gdtr.limit); + WRITE32(ea + 2, m_gdtr.base); + CYCLES(CYCLES_SGDT); + break; + } + case 1: /* SIDT */ + { + if (modrm >= 0xc0) + { + address = LOAD_RM32(modrm); + ea = i386_translate(CS, address, 1 ); + } + else + { + ea = GetEA(modrm,1); + } + WRITE16(ea, m_idtr.limit); + WRITE32(ea + 2, m_idtr.base); + CYCLES(CYCLES_SIDT); + break; + } + case 2: /* LGDT */ + { + if(PROTECTED_MODE && m_CPL) + FAULT(FAULT_GP,0) + if( modrm >= 0xc0 ) { + address = LOAD_RM32(modrm); + ea = i386_translate(CS, address, 0 ); + } else { + ea = GetEA(modrm,0); + } + m_gdtr.limit = READ16(ea); + m_gdtr.base = READ32(ea + 2); + CYCLES(CYCLES_LGDT); + break; + } + case 3: /* LIDT */ + { + if(PROTECTED_MODE && m_CPL) + FAULT(FAULT_GP,0) + if( modrm >= 0xc0 ) { + address = LOAD_RM32(modrm); + ea = i386_translate(CS, address, 0 ); + } else { + ea = GetEA(modrm,0); + } + m_idtr.limit = READ16(ea); + m_idtr.base = READ32(ea + 2); + CYCLES(CYCLES_LIDT); + break; + } + case 4: /* SMSW */ + { + if( modrm >= 0xc0 ) { + // smsw stores all of cr0 into register + STORE_RM32(modrm, m_cr[0]); + CYCLES(CYCLES_SMSW_REG); + } else { + /* always 16-bit memory operand */ + ea = GetEA(modrm,1); + WRITE16(ea, m_cr[0]); + CYCLES(CYCLES_SMSW_MEM); + } + break; + } + case 6: /* LMSW */ + { + if(PROTECTED_MODE && m_CPL) + FAULT(FAULT_GP,0) + UINT16 b; + if( modrm >= 0xc0 ) { + b = LOAD_RM16(modrm); + CYCLES(CYCLES_LMSW_REG); + } else { + ea = GetEA(modrm,0); + CYCLES(CYCLES_LMSW_MEM); + b = READ16(ea); + } + if(PROTECTED_MODE) + b |= 0x0001; // cannot return to real mode using this instruction. + m_cr[0] &= ~0x0000000f; + m_cr[0] |= b & 0x0000000f; + break; + } + default: + report_invalid_modrm("group0F01_32", modrm); + break; + } +} + +void i386_device::i386_group0FBA_32() // Opcode 0x0f ba +{ + UINT8 modrm = FETCH(); + + switch( (modrm >> 3) & 0x7 ) + { + case 4: /* BT Rm32, i8 */ + if( modrm >= 0xc0 ) { + UINT32 dst = LOAD_RM32(modrm); + UINT8 bit = FETCH(); + + if( dst & (1 << bit) ) + m_CF = 1; + else + m_CF = 0; + + CYCLES(CYCLES_BT_IMM_REG); + } else { + UINT32 ea = GetEA(modrm,0); + UINT32 dst = READ32(ea); + UINT8 bit = FETCH(); + + if( dst & (1 << bit) ) + m_CF = 1; + else + m_CF = 0; + + CYCLES(CYCLES_BT_IMM_MEM); + } + break; + case 5: /* BTS Rm32, i8 */ + if( modrm >= 0xc0 ) { + UINT32 dst = LOAD_RM32(modrm); + UINT8 bit = FETCH(); + + if( dst & (1 << bit) ) + m_CF = 1; + else + m_CF = 0; + dst |= (1 << bit); + + STORE_RM32(modrm, dst); + CYCLES(CYCLES_BTS_IMM_REG); + } else { + UINT32 ea = GetEA(modrm,1); + UINT32 dst = READ32(ea); + UINT8 bit = FETCH(); + + if( dst & (1 << bit) ) + m_CF = 1; + else + m_CF = 0; + dst |= (1 << bit); + + WRITE32(ea, dst); + CYCLES(CYCLES_BTS_IMM_MEM); + } + break; + case 6: /* BTR Rm32, i8 */ + if( modrm >= 0xc0 ) { + UINT32 dst = LOAD_RM32(modrm); + UINT8 bit = FETCH(); + + if( dst & (1 << bit) ) + m_CF = 1; + else + m_CF = 0; + dst &= ~(1 << bit); + + STORE_RM32(modrm, dst); + CYCLES(CYCLES_BTR_IMM_REG); + } else { + UINT32 ea = GetEA(modrm,1); + UINT32 dst = READ32(ea); + UINT8 bit = FETCH(); + + if( dst & (1 << bit) ) + m_CF = 1; + else + m_CF = 0; + dst &= ~(1 << bit); + + WRITE32(ea, dst); + CYCLES(CYCLES_BTR_IMM_MEM); + } + break; + case 7: /* BTC Rm32, i8 */ + if( modrm >= 0xc0 ) { + UINT32 dst = LOAD_RM32(modrm); + UINT8 bit = FETCH(); + + if( dst & (1 << bit) ) + m_CF = 1; + else + m_CF = 0; + dst ^= (1 << bit); + + STORE_RM32(modrm, dst); + CYCLES(CYCLES_BTC_IMM_REG); + } else { + UINT32 ea = GetEA(modrm,1); + UINT32 dst = READ32(ea); + UINT8 bit = FETCH(); + + if( dst & (1 << bit) ) + m_CF = 1; + else + m_CF = 0; + dst ^= (1 << bit); + + WRITE32(ea, dst); + CYCLES(CYCLES_BTC_IMM_MEM); + } + break; + default: + report_invalid_modrm("group0FBA_32", modrm); + break; + } +} + +void i386_device::i386_lar_r32_rm32() // Opcode 0x0f 0x02 +{ + UINT8 modrm = FETCH(); + I386_SREG seg; + UINT8 type; + + if(PROTECTED_MODE && !V8086_MODE) + { + memset(&seg,0,sizeof(seg)); + if(modrm >= 0xc0) + { + seg.selector = LOAD_RM32(modrm); + CYCLES(CYCLES_LAR_REG); + } + else + { + UINT32 ea = GetEA(modrm,0); + seg.selector = READ32(ea); + CYCLES(CYCLES_LAR_MEM); + } + if(seg.selector == 0) + { + SetZF(0); // not a valid segment + } + else + { + UINT64 desc; + if(!i386_load_protected_mode_segment(&seg,&desc)) + { + SetZF(0); + return; + } + UINT8 DPL = (seg.flags >> 5) & 3; + if(((DPL < m_CPL) || (DPL < (seg.selector & 3))) && ((seg.flags & 0x1c) != 0x1c)) + { + SetZF(0); + return; + } + if(!(seg.flags & 0x10)) // special segment + { + // check for invalid segment types + type = seg.flags & 0x000f; + if(type == 0x00 || type == 0x08 || type == 0x0a || type == 0x0d) + { + SetZF(0); // invalid segment type + } + else + { + STORE_REG32(modrm,(desc>>32) & 0x00ffff00); + SetZF(1); + } + } + else + { + STORE_REG32(modrm,(desc>>32) & 0x00ffff00); + SetZF(1); + } + } + } + else + { + // illegal opcode + i386_trap(6,0, 0); + logerror("i386: LAR: Exception - running in real mode or virtual 8086 mode.\n"); + } +} + +void i386_device::i386_lsl_r32_rm32() // Opcode 0x0f 0x03 +{ + UINT8 modrm = FETCH(); + UINT32 limit; + I386_SREG seg; + + if(PROTECTED_MODE && !V8086_MODE) + { + memset(&seg, 0, sizeof(seg)); + if(modrm >= 0xc0) + { + seg.selector = LOAD_RM32(modrm); + } + else + { + UINT32 ea = GetEA(modrm,0); + seg.selector = READ32(ea); + } + if(seg.selector == 0) + { + SetZF(0); // not a valid segment + } + else + { + UINT8 type; + if(!i386_load_protected_mode_segment(&seg,NULL)) + { + SetZF(0); + return; + } + UINT8 DPL = (seg.flags >> 5) & 3; + if(((DPL < m_CPL) || (DPL < (seg.selector & 3))) && ((seg.flags & 0x1c) != 0x1c)) + { + SetZF(0); + return; + } + type = seg.flags & 0x1f; + switch(type) + { + case 0: + case 4: + case 5: + case 6: + case 7: + case 8: + case 10: + case 12: + case 13: + case 14: + case 15: + SetZF(0); + return; + default: + limit = seg.limit; + STORE_REG32(modrm,limit); + SetZF(1); + } + } + } + else + i386_trap(6, 0, 0); +} + +void i386_device::i386_bound_r32_m32_m32() // Opcode 0x62 +{ + UINT8 modrm; + INT32 val, low, high; + + modrm = FETCH(); + + if (modrm >= 0xc0) + { + low = high = LOAD_RM32(modrm); + } + else + { + UINT32 ea = GetEA(modrm,0); + low = READ32(ea + 0); + high = READ32(ea + 4); + } + val = LOAD_REG32(modrm); + + if ((val < low) || (val > high)) + { + CYCLES(CYCLES_BOUND_OUT_RANGE); + i386_trap(5, 0, 0); + } + else + { + CYCLES(CYCLES_BOUND_IN_RANGE); + } +} + +void i386_device::i386_retf32() // Opcode 0xcb +{ + if(PROTECTED_MODE && !V8086_MODE) + { + i386_protected_mode_retf(0,1); + } + else + { + m_eip = POP32(); + m_sreg[CS].selector = POP32(); + i386_load_segment_descriptor(CS ); + CHANGE_PC(m_eip); + } + + CYCLES(CYCLES_RET_INTERSEG); +} + +void i386_device::i386_retf_i32() // Opcode 0xca +{ + UINT16 count = FETCH16(); + + if(PROTECTED_MODE && !V8086_MODE) + { + i386_protected_mode_retf(count,1); + } + else + { + m_eip = POP32(); + m_sreg[CS].selector = POP32(); + i386_load_segment_descriptor(CS ); + CHANGE_PC(m_eip); + REG32(ESP) += count; + } + + CYCLES(CYCLES_RET_IMM_INTERSEG); +} + +void i386_device::i386_load_far_pointer32(int s) +{ + UINT8 modrm = FETCH(); + UINT16 selector; + + if( modrm >= 0xc0 ) { + report_invalid_modrm("load_far_pointer32", modrm); + } else { + UINT32 ea = GetEA(modrm,0); + STORE_REG32(modrm, READ32(ea + 0)); + selector = READ16(ea + 4); + i386_sreg_load(selector,s,NULL); + } +} + +void i386_device::i386_lds32() // Opcode 0xc5 +{ + i386_load_far_pointer32(DS); + CYCLES(CYCLES_LDS); +} + +void i386_device::i386_lss32() // Opcode 0x0f 0xb2 +{ + i386_load_far_pointer32(SS); + CYCLES(CYCLES_LSS); +} + +void i386_device::i386_les32() // Opcode 0xc4 +{ + i386_load_far_pointer32(ES); + CYCLES(CYCLES_LES); +} + +void i386_device::i386_lfs32() // Opcode 0x0f 0xb4 +{ + i386_load_far_pointer32(FS); + CYCLES(CYCLES_LFS); +} + +void i386_device::i386_lgs32() // Opcode 0x0f 0xb5 +{ + i386_load_far_pointer32(GS); + CYCLES(CYCLES_LGS); +} diff --git a/src/devices/cpu/i386/i386ops.h b/src/devices/cpu/i386/i386ops.h new file mode 100644 index 00000000000..2760b9cf410 --- /dev/null +++ b/src/devices/cpu/i386/i386ops.h @@ -0,0 +1,876 @@ +// license:BSD-3-Clause +// copyright-holders:Ville Linde, Barry Rodewald, Carl, Philip Bennett +#define OP_I386 0x1 +#define OP_FPU 0x2 +#define OP_I486 0x4 +#define OP_PENTIUM 0x8 +#define OP_MMX 0x10 +#define OP_PPRO 0x20 +#define OP_SSE 0x40 +#define OP_SSE2 0x80 +#define OP_SSE3 0x100 +#define OP_CYRIX 0x8000 +#define OP_2BYTE 0x80000000 +#define OP_3BYTE66 0x40000000 +#define OP_3BYTEF2 0x20000000 +#define OP_3BYTEF3 0x10000000 +#define OP_3BYTE38 0x08000000 +#define OP_3BYTE3A 0x04000000 +#define OP_4BYTE3866 0x02000000 +#define OP_4BYTE3A66 0x01000000 +#define OP_4BYTE38F2 0x00800000 +#define OP_4BYTE3AF2 0x00400000 +#define OP_4BYTE38F3 0x00200000 + +const i386_device::X86_OPCODE i386_device::s_x86_opcode_table[] = +{ +// Opcode Flags 16-bit handler 32-bit handler + { 0x00, OP_I386, &i386_device::i386_add_rm8_r8, &i386_device::i386_add_rm8_r8, true }, + { 0x01, OP_I386, &i386_device::i386_add_rm16_r16, &i386_device::i386_add_rm32_r32, true }, + { 0x02, OP_I386, &i386_device::i386_add_r8_rm8, &i386_device::i386_add_r8_rm8, false}, + { 0x03, OP_I386, &i386_device::i386_add_r16_rm16, &i386_device::i386_add_r32_rm32, false}, + { 0x04, OP_I386, &i386_device::i386_add_al_i8, &i386_device::i386_add_al_i8, false}, + { 0x05, OP_I386, &i386_device::i386_add_ax_i16, &i386_device::i386_add_eax_i32, false}, + { 0x06, OP_I386, &i386_device::i386_push_es16, &i386_device::i386_push_es32, false}, + { 0x07, OP_I386, &i386_device::i386_pop_es16, &i386_device::i386_pop_es32, false}, + { 0x08, OP_I386, &i386_device::i386_or_rm8_r8, &i386_device::i386_or_rm8_r8, true }, + { 0x09, OP_I386, &i386_device::i386_or_rm16_r16, &i386_device::i386_or_rm32_r32, true }, + { 0x0A, OP_I386, &i386_device::i386_or_r8_rm8, &i386_device::i386_or_r8_rm8, false}, + { 0x0B, OP_I386, &i386_device::i386_or_r16_rm16, &i386_device::i386_or_r32_rm32, false}, + { 0x0C, OP_I386, &i386_device::i386_or_al_i8, &i386_device::i386_or_al_i8, false}, + { 0x0D, OP_I386, &i386_device::i386_or_ax_i16, &i386_device::i386_or_eax_i32, false}, + { 0x0E, OP_I386, &i386_device::i386_push_cs16, &i386_device::i386_push_cs32, false}, + { 0x0F, OP_I386, &i386_device::i386_decode_two_byte, &i386_device::i386_decode_two_byte, true }, + { 0x10, OP_I386, &i386_device::i386_adc_rm8_r8, &i386_device::i386_adc_rm8_r8, true }, + { 0x11, OP_I386, &i386_device::i386_adc_rm16_r16, &i386_device::i386_adc_rm32_r32, true }, + { 0x12, OP_I386, &i386_device::i386_adc_r8_rm8, &i386_device::i386_adc_r8_rm8, false}, + { 0x13, OP_I386, &i386_device::i386_adc_r16_rm16, &i386_device::i386_adc_r32_rm32, false}, + { 0x14, OP_I386, &i386_device::i386_adc_al_i8, &i386_device::i386_adc_al_i8, false}, + { 0x15, OP_I386, &i386_device::i386_adc_ax_i16, &i386_device::i386_adc_eax_i32, false}, + { 0x16, OP_I386, &i386_device::i386_push_ss16, &i386_device::i386_push_ss32, false}, + { 0x17, OP_I386, &i386_device::i386_pop_ss16, &i386_device::i386_pop_ss32, false}, + { 0x18, OP_I386, &i386_device::i386_sbb_rm8_r8, &i386_device::i386_sbb_rm8_r8, true }, + { 0x19, OP_I386, &i386_device::i386_sbb_rm16_r16, &i386_device::i386_sbb_rm32_r32, true }, + { 0x1A, OP_I386, &i386_device::i386_sbb_r8_rm8, &i386_device::i386_sbb_r8_rm8, false}, + { 0x1B, OP_I386, &i386_device::i386_sbb_r16_rm16, &i386_device::i386_sbb_r32_rm32, false}, + { 0x1C, OP_I386, &i386_device::i386_sbb_al_i8, &i386_device::i386_sbb_al_i8, false}, + { 0x1D, OP_I386, &i386_device::i386_sbb_ax_i16, &i386_device::i386_sbb_eax_i32, false}, + { 0x1E, OP_I386, &i386_device::i386_push_ds16, &i386_device::i386_push_ds32, false}, + { 0x1F, OP_I386, &i386_device::i386_pop_ds16, &i386_device::i386_pop_ds32, false}, + { 0x20, OP_I386, &i386_device::i386_and_rm8_r8, &i386_device::i386_and_rm8_r8, true }, + { 0x21, OP_I386, &i386_device::i386_and_rm16_r16, &i386_device::i386_and_rm32_r32, true }, + { 0x22, OP_I386, &i386_device::i386_and_r8_rm8, &i386_device::i386_and_r8_rm8, false}, + { 0x23, OP_I386, &i386_device::i386_and_r16_rm16, &i386_device::i386_and_r32_rm32, false}, + { 0x24, OP_I386, &i386_device::i386_and_al_i8, &i386_device::i386_and_al_i8, false}, + { 0x25, OP_I386, &i386_device::i386_and_ax_i16, &i386_device::i386_and_eax_i32, false}, + { 0x26, OP_I386, &i386_device::i386_segment_ES, &i386_device::i386_segment_ES, false}, + { 0x27, OP_I386, &i386_device::i386_daa, &i386_device::i386_daa, false}, + { 0x28, OP_I386, &i386_device::i386_sub_rm8_r8, &i386_device::i386_sub_rm8_r8, true }, + { 0x29, OP_I386, &i386_device::i386_sub_rm16_r16, &i386_device::i386_sub_rm32_r32, true }, + { 0x2A, OP_I386, &i386_device::i386_sub_r8_rm8, &i386_device::i386_sub_r8_rm8, false}, + { 0x2B, OP_I386, &i386_device::i386_sub_r16_rm16, &i386_device::i386_sub_r32_rm32, false}, + { 0x2C, OP_I386, &i386_device::i386_sub_al_i8, &i386_device::i386_sub_al_i8, false}, + { 0x2D, OP_I386, &i386_device::i386_sub_ax_i16, &i386_device::i386_sub_eax_i32, false}, + { 0x2E, OP_I386, &i386_device::i386_segment_CS, &i386_device::i386_segment_CS, false}, + { 0x2F, OP_I386, &i386_device::i386_das, &i386_device::i386_das, false}, + { 0x30, OP_I386, &i386_device::i386_xor_rm8_r8, &i386_device::i386_xor_rm8_r8, true }, + { 0x31, OP_I386, &i386_device::i386_xor_rm16_r16, &i386_device::i386_xor_rm32_r32, true }, + { 0x32, OP_I386, &i386_device::i386_xor_r8_rm8, &i386_device::i386_xor_r8_rm8, false}, + { 0x33, OP_I386, &i386_device::i386_xor_r16_rm16, &i386_device::i386_xor_r32_rm32, false}, + { 0x34, OP_I386, &i386_device::i386_xor_al_i8, &i386_device::i386_xor_al_i8, false}, + { 0x35, OP_I386, &i386_device::i386_xor_ax_i16, &i386_device::i386_xor_eax_i32, false}, + { 0x36, OP_I386, &i386_device::i386_segment_SS, &i386_device::i386_segment_SS, false}, + { 0x37, OP_I386, &i386_device::i386_aaa, &i386_device::i386_aaa, false}, + { 0x38, OP_I386, &i386_device::i386_cmp_rm8_r8, &i386_device::i386_cmp_rm8_r8, false}, + { 0x39, OP_I386, &i386_device::i386_cmp_rm16_r16, &i386_device::i386_cmp_rm32_r32, false}, + { 0x3A, OP_I386, &i386_device::i386_cmp_r8_rm8, &i386_device::i386_cmp_r8_rm8, false}, + { 0x3B, OP_I386, &i386_device::i386_cmp_r16_rm16, &i386_device::i386_cmp_r32_rm32, false}, + { 0x3C, OP_I386, &i386_device::i386_cmp_al_i8, &i386_device::i386_cmp_al_i8, false}, + { 0x3D, OP_I386, &i386_device::i386_cmp_ax_i16, &i386_device::i386_cmp_eax_i32, false}, + { 0x3E, OP_I386, &i386_device::i386_segment_DS, &i386_device::i386_segment_DS, false}, + { 0x3F, OP_I386, &i386_device::i386_aas, &i386_device::i386_aas, false}, + { 0x40, OP_I386, &i386_device::i386_inc_ax, &i386_device::i386_inc_eax, false}, + { 0x41, OP_I386, &i386_device::i386_inc_cx, &i386_device::i386_inc_ecx, false}, + { 0x42, OP_I386, &i386_device::i386_inc_dx, &i386_device::i386_inc_edx, false}, + { 0x43, OP_I386, &i386_device::i386_inc_bx, &i386_device::i386_inc_ebx, false}, + { 0x44, OP_I386, &i386_device::i386_inc_sp, &i386_device::i386_inc_esp, false}, + { 0x45, OP_I386, &i386_device::i386_inc_bp, &i386_device::i386_inc_ebp, false}, + { 0x46, OP_I386, &i386_device::i386_inc_si, &i386_device::i386_inc_esi, false}, + { 0x47, OP_I386, &i386_device::i386_inc_di, &i386_device::i386_inc_edi, false}, + { 0x48, OP_I386, &i386_device::i386_dec_ax, &i386_device::i386_dec_eax, false}, + { 0x49, OP_I386, &i386_device::i386_dec_cx, &i386_device::i386_dec_ecx, false}, + { 0x4A, OP_I386, &i386_device::i386_dec_dx, &i386_device::i386_dec_edx, false}, + { 0x4B, OP_I386, &i386_device::i386_dec_bx, &i386_device::i386_dec_ebx, false}, + { 0x4C, OP_I386, &i386_device::i386_dec_sp, &i386_device::i386_dec_esp, false}, + { 0x4D, OP_I386, &i386_device::i386_dec_bp, &i386_device::i386_dec_ebp, false}, + { 0x4E, OP_I386, &i386_device::i386_dec_si, &i386_device::i386_dec_esi, false}, + { 0x4F, OP_I386, &i386_device::i386_dec_di, &i386_device::i386_dec_edi, false}, + { 0x50, OP_I386, &i386_device::i386_push_ax, &i386_device::i386_push_eax, false}, + { 0x51, OP_I386, &i386_device::i386_push_cx, &i386_device::i386_push_ecx, false}, + { 0x52, OP_I386, &i386_device::i386_push_dx, &i386_device::i386_push_edx, false}, + { 0x53, OP_I386, &i386_device::i386_push_bx, &i386_device::i386_push_ebx, false}, + { 0x54, OP_I386, &i386_device::i386_push_sp, &i386_device::i386_push_esp, false}, + { 0x55, OP_I386, &i386_device::i386_push_bp, &i386_device::i386_push_ebp, false}, + { 0x56, OP_I386, &i386_device::i386_push_si, &i386_device::i386_push_esi, false}, + { 0x57, OP_I386, &i386_device::i386_push_di, &i386_device::i386_push_edi, false}, + { 0x58, OP_I386, &i386_device::i386_pop_ax, &i386_device::i386_pop_eax, false}, + { 0x59, OP_I386, &i386_device::i386_pop_cx, &i386_device::i386_pop_ecx, false}, + { 0x5A, OP_I386, &i386_device::i386_pop_dx, &i386_device::i386_pop_edx, false}, + { 0x5B, OP_I386, &i386_device::i386_pop_bx, &i386_device::i386_pop_ebx, false}, + { 0x5C, OP_I386, &i386_device::i386_pop_sp, &i386_device::i386_pop_esp, false}, + { 0x5D, OP_I386, &i386_device::i386_pop_bp, &i386_device::i386_pop_ebp, false}, + { 0x5E, OP_I386, &i386_device::i386_pop_si, &i386_device::i386_pop_esi, false}, + { 0x5F, OP_I386, &i386_device::i386_pop_di, &i386_device::i386_pop_edi, false}, + { 0x60, OP_I386, &i386_device::i386_pusha, &i386_device::i386_pushad, false}, + { 0x61, OP_I386, &i386_device::i386_popa, &i386_device::i386_popad, false}, + { 0x62, OP_I386, &i386_device::i386_bound_r16_m16_m16, &i386_device::i386_bound_r32_m32_m32, false}, + { 0x63, OP_I386, &i386_device::i386_arpl, &i386_device::i386_arpl, false}, + { 0x64, OP_I386, &i386_device::i386_segment_FS, &i386_device::i386_segment_FS, false}, + { 0x65, OP_I386, &i386_device::i386_segment_GS, &i386_device::i386_segment_GS, false}, + { 0x66, OP_I386, &i386_device::i386_operand_size, &i386_device::i386_operand_size, false}, + { 0x67, OP_I386, &i386_device::i386_address_size, &i386_device::i386_address_size, false}, + { 0x68, OP_I386, &i386_device::i386_push_i16, &i386_device::i386_push_i32, false}, + { 0x69, OP_I386, &i386_device::i386_imul_r16_rm16_i16, &i386_device::i386_imul_r32_rm32_i32, false}, + { 0x6A, OP_I386, &i386_device::i386_push_i8, &i386_device::i386_push_i8, false}, + { 0x6B, OP_I386, &i386_device::i386_imul_r16_rm16_i8, &i386_device::i386_imul_r32_rm32_i8, false}, + { 0x6C, OP_I386, &i386_device::i386_insb, &i386_device::i386_insb, false}, + { 0x6D, OP_I386, &i386_device::i386_insw, &i386_device::i386_insd, false}, + { 0x6E, OP_I386, &i386_device::i386_outsb, &i386_device::i386_outsb, false}, + { 0x6F, OP_I386, &i386_device::i386_outsw, &i386_device::i386_outsd, false}, + { 0x70, OP_I386, &i386_device::i386_jo_rel8, &i386_device::i386_jo_rel8, false}, + { 0x71, OP_I386, &i386_device::i386_jno_rel8, &i386_device::i386_jno_rel8, false}, + { 0x72, OP_I386, &i386_device::i386_jc_rel8, &i386_device::i386_jc_rel8, false}, + { 0x73, OP_I386, &i386_device::i386_jnc_rel8, &i386_device::i386_jnc_rel8, false}, + { 0x74, OP_I386, &i386_device::i386_jz_rel8, &i386_device::i386_jz_rel8, false}, + { 0x75, OP_I386, &i386_device::i386_jnz_rel8, &i386_device::i386_jnz_rel8, false}, + { 0x76, OP_I386, &i386_device::i386_jbe_rel8, &i386_device::i386_jbe_rel8, false}, + { 0x77, OP_I386, &i386_device::i386_ja_rel8, &i386_device::i386_ja_rel8, false}, + { 0x78, OP_I386, &i386_device::i386_js_rel8, &i386_device::i386_js_rel8, false}, + { 0x79, OP_I386, &i386_device::i386_jns_rel8, &i386_device::i386_jns_rel8, false}, + { 0x7A, OP_I386, &i386_device::i386_jp_rel8, &i386_device::i386_jp_rel8, false}, + { 0x7B, OP_I386, &i386_device::i386_jnp_rel8, &i386_device::i386_jnp_rel8, false}, + { 0x7C, OP_I386, &i386_device::i386_jl_rel8, &i386_device::i386_jl_rel8, false}, + { 0x7D, OP_I386, &i386_device::i386_jge_rel8, &i386_device::i386_jge_rel8, false}, + { 0x7E, OP_I386, &i386_device::i386_jle_rel8, &i386_device::i386_jle_rel8, false}, + { 0x7F, OP_I386, &i386_device::i386_jg_rel8, &i386_device::i386_jg_rel8, false}, + { 0x80, OP_I386, &i386_device::i386_group80_8, &i386_device::i386_group80_8, true }, + { 0x81, OP_I386, &i386_device::i386_group81_16, &i386_device::i386_group81_32, true }, + { 0x82, OP_I386, &i386_device::i386_group80_8, &i386_device::i386_group80_8, true }, + { 0x83, OP_I386, &i386_device::i386_group83_16, &i386_device::i386_group83_32, true }, + { 0x84, OP_I386, &i386_device::i386_test_rm8_r8, &i386_device::i386_test_rm8_r8, false}, + { 0x85, OP_I386, &i386_device::i386_test_rm16_r16, &i386_device::i386_test_rm32_r32, false}, + { 0x86, OP_I386, &i386_device::i386_xchg_r8_rm8, &i386_device::i386_xchg_r8_rm8, true }, + { 0x87, OP_I386, &i386_device::i386_xchg_r16_rm16, &i386_device::i386_xchg_r32_rm32, true }, + { 0x88, OP_I386, &i386_device::i386_mov_rm8_r8, &i386_device::i386_mov_rm8_r8, false}, + { 0x89, OP_I386, &i386_device::i386_mov_rm16_r16, &i386_device::i386_mov_rm32_r32, false}, + { 0x8A, OP_I386, &i386_device::i386_mov_r8_rm8, &i386_device::i386_mov_r8_rm8, false}, + { 0x8B, OP_I386, &i386_device::i386_mov_r16_rm16, &i386_device::i386_mov_r32_rm32, false}, + { 0x8C, OP_I386, &i386_device::i386_mov_rm16_sreg, &i386_device::i386_mov_rm16_sreg, false}, + { 0x8D, OP_I386, &i386_device::i386_lea16, &i386_device::i386_lea32, false}, + { 0x8E, OP_I386, &i386_device::i386_mov_sreg_rm16, &i386_device::i386_mov_sreg_rm16, false}, + { 0x8F, OP_I386, &i386_device::i386_pop_rm16, &i386_device::i386_pop_rm32, false}, + { 0x90, OP_I386, &i386_device::i386_nop, &i386_device::i386_nop, false}, + { 0x91, OP_I386, &i386_device::i386_xchg_ax_cx, &i386_device::i386_xchg_eax_ecx, false}, + { 0x92, OP_I386, &i386_device::i386_xchg_ax_dx, &i386_device::i386_xchg_eax_edx, false}, + { 0x93, OP_I386, &i386_device::i386_xchg_ax_bx, &i386_device::i386_xchg_eax_ebx, false}, + { 0x94, OP_I386, &i386_device::i386_xchg_ax_sp, &i386_device::i386_xchg_eax_esp, false}, + { 0x95, OP_I386, &i386_device::i386_xchg_ax_bp, &i386_device::i386_xchg_eax_ebp, false}, + { 0x96, OP_I386, &i386_device::i386_xchg_ax_si, &i386_device::i386_xchg_eax_esi, false}, + { 0x97, OP_I386, &i386_device::i386_xchg_ax_di, &i386_device::i386_xchg_eax_edi, false}, + { 0x98, OP_I386, &i386_device::i386_cbw, &i386_device::i386_cwde, false}, + { 0x99, OP_I386, &i386_device::i386_cwd, &i386_device::i386_cdq, false}, + { 0x9A, OP_I386, &i386_device::i386_call_abs16, &i386_device::i386_call_abs32, false}, + { 0x9B, OP_I386, &i386_device::i386_wait, &i386_device::i386_wait, false}, + { 0x9C, OP_I386, &i386_device::i386_pushf, &i386_device::i386_pushfd, false}, + { 0x9D, OP_I386, &i386_device::i386_popf, &i386_device::i386_popfd, false}, + { 0x9E, OP_I386, &i386_device::i386_sahf, &i386_device::i386_sahf, false}, + { 0x9F, OP_I386, &i386_device::i386_lahf, &i386_device::i386_lahf, false}, + { 0xA0, OP_I386, &i386_device::i386_mov_al_m8, &i386_device::i386_mov_al_m8, false}, + { 0xA1, OP_I386, &i386_device::i386_mov_ax_m16, &i386_device::i386_mov_eax_m32, false}, + { 0xA2, OP_I386, &i386_device::i386_mov_m8_al, &i386_device::i386_mov_m8_al, false}, + { 0xA3, OP_I386, &i386_device::i386_mov_m16_ax, &i386_device::i386_mov_m32_eax, false}, + { 0xA4, OP_I386, &i386_device::i386_movsb, &i386_device::i386_movsb, false}, + { 0xA5, OP_I386, &i386_device::i386_movsw, &i386_device::i386_movsd, false}, + { 0xA6, OP_I386, &i386_device::i386_cmpsb, &i386_device::i386_cmpsb, false}, + { 0xA7, OP_I386, &i386_device::i386_cmpsw, &i386_device::i386_cmpsd, false}, + { 0xA8, OP_I386, &i386_device::i386_test_al_i8, &i386_device::i386_test_al_i8, false}, + { 0xA9, OP_I386, &i386_device::i386_test_ax_i16, &i386_device::i386_test_eax_i32, false}, + { 0xAA, OP_I386, &i386_device::i386_stosb, &i386_device::i386_stosb, false}, + { 0xAB, OP_I386, &i386_device::i386_stosw, &i386_device::i386_stosd, false}, + { 0xAC, OP_I386, &i386_device::i386_lodsb, &i386_device::i386_lodsb, false}, + { 0xAD, OP_I386, &i386_device::i386_lodsw, &i386_device::i386_lodsd, false}, + { 0xAE, OP_I386, &i386_device::i386_scasb, &i386_device::i386_scasb, false}, + { 0xAF, OP_I386, &i386_device::i386_scasw, &i386_device::i386_scasd, false}, + { 0xB0, OP_I386, &i386_device::i386_mov_al_i8, &i386_device::i386_mov_al_i8, false}, + { 0xB1, OP_I386, &i386_device::i386_mov_cl_i8, &i386_device::i386_mov_cl_i8, false}, + { 0xB2, OP_I386, &i386_device::i386_mov_dl_i8, &i386_device::i386_mov_dl_i8, false}, + { 0xB3, OP_I386, &i386_device::i386_mov_bl_i8, &i386_device::i386_mov_bl_i8, false}, + { 0xB4, OP_I386, &i386_device::i386_mov_ah_i8, &i386_device::i386_mov_ah_i8, false}, + { 0xB5, OP_I386, &i386_device::i386_mov_ch_i8, &i386_device::i386_mov_ch_i8, false}, + { 0xB6, OP_I386, &i386_device::i386_mov_dh_i8, &i386_device::i386_mov_dh_i8, false}, + { 0xB7, OP_I386, &i386_device::i386_mov_bh_i8, &i386_device::i386_mov_bh_i8, false}, + { 0xB8, OP_I386, &i386_device::i386_mov_ax_i16, &i386_device::i386_mov_eax_i32, false}, + { 0xB9, OP_I386, &i386_device::i386_mov_cx_i16, &i386_device::i386_mov_ecx_i32, false}, + { 0xBA, OP_I386, &i386_device::i386_mov_dx_i16, &i386_device::i386_mov_edx_i32, false}, + { 0xBB, OP_I386, &i386_device::i386_mov_bx_i16, &i386_device::i386_mov_ebx_i32, false}, + { 0xBC, OP_I386, &i386_device::i386_mov_sp_i16, &i386_device::i386_mov_esp_i32, false}, + { 0xBD, OP_I386, &i386_device::i386_mov_bp_i16, &i386_device::i386_mov_ebp_i32, false}, + { 0xBE, OP_I386, &i386_device::i386_mov_si_i16, &i386_device::i386_mov_esi_i32, false}, + { 0xBF, OP_I386, &i386_device::i386_mov_di_i16, &i386_device::i386_mov_edi_i32, false}, + { 0xC0, OP_I386, &i386_device::i386_groupC0_8, &i386_device::i386_groupC0_8, false}, + { 0xC1, OP_I386, &i386_device::i386_groupC1_16, &i386_device::i386_groupC1_32, false}, + { 0xC2, OP_I386, &i386_device::i386_ret_near16_i16, &i386_device::i386_ret_near32_i16, false}, + { 0xC3, OP_I386, &i386_device::i386_ret_near16, &i386_device::i386_ret_near32, false}, + { 0xC4, OP_I386, &i386_device::i386_les16, &i386_device::i386_les32, false}, + { 0xC5, OP_I386, &i386_device::i386_lds16, &i386_device::i386_lds32, false}, + { 0xC6, OP_I386, &i386_device::i386_mov_rm8_i8, &i386_device::i386_mov_rm8_i8, false}, + { 0xC7, OP_I386, &i386_device::i386_mov_rm16_i16, &i386_device::i386_mov_rm32_i32, false}, + { 0xC8, OP_I386, &i386_device::i386_enter16, &i386_device::i386_enter32, false}, + { 0xC9, OP_I386, &i386_device::i386_leave16, &i386_device::i386_leave32, false}, + { 0xCA, OP_I386, &i386_device::i386_retf_i16, &i386_device::i386_retf_i32, false}, + { 0xCB, OP_I386, &i386_device::i386_retf16, &i386_device::i386_retf32, false}, + { 0xCC, OP_I386, &i386_device::i386_int3, &i386_device::i386_int3, false}, + { 0xCD, OP_I386, &i386_device::i386_int, &i386_device::i386_int, false}, + { 0xCE, OP_I386, &i386_device::i386_into, &i386_device::i386_into, false}, + { 0xCF, OP_I386, &i386_device::i386_iret16, &i386_device::i386_iret32, false}, + { 0xD0, OP_I386, &i386_device::i386_groupD0_8, &i386_device::i386_groupD0_8, false}, + { 0xD1, OP_I386, &i386_device::i386_groupD1_16, &i386_device::i386_groupD1_32, false}, + { 0xD2, OP_I386, &i386_device::i386_groupD2_8, &i386_device::i386_groupD2_8, false}, + { 0xD3, OP_I386, &i386_device::i386_groupD3_16, &i386_device::i386_groupD3_32, false}, + { 0xD4, OP_I386, &i386_device::i386_aam, &i386_device::i386_aam, false}, + { 0xD5, OP_I386, &i386_device::i386_aad, &i386_device::i386_aad, false}, + { 0xD6, OP_I386, &i386_device::i386_setalc, &i386_device::i386_setalc, false}, + { 0xD7, OP_I386, &i386_device::i386_xlat, &i386_device::i386_xlat, false}, + { 0xD8, OP_I386, &i386_device::i386_escape, &i386_device::i386_escape, false}, + { 0xD9, OP_I386, &i386_device::i386_escape, &i386_device::i386_escape, false}, + { 0xDA, OP_I386, &i386_device::i386_escape, &i386_device::i386_escape, false}, + { 0xDB, OP_I386, &i386_device::i386_escape, &i386_device::i386_escape, false}, + { 0xDC, OP_I386, &i386_device::i386_escape, &i386_device::i386_escape, false}, + { 0xDD, OP_I386, &i386_device::i386_escape, &i386_device::i386_escape, false}, + { 0xDE, OP_I386, &i386_device::i386_escape, &i386_device::i386_escape, false}, + { 0xDF, OP_I386, &i386_device::i386_escape, &i386_device::i386_escape, false}, + { 0xD8, OP_FPU, &i386_device::i386_x87_group_d8, &i386_device::i386_x87_group_d8, false}, + { 0xD9, OP_FPU, &i386_device::i386_x87_group_d9, &i386_device::i386_x87_group_d9, false}, + { 0xDA, OP_FPU, &i386_device::i386_x87_group_da, &i386_device::i386_x87_group_da, false}, + { 0xDB, OP_FPU, &i386_device::i386_x87_group_db, &i386_device::i386_x87_group_db, false}, + { 0xDC, OP_FPU, &i386_device::i386_x87_group_dc, &i386_device::i386_x87_group_dc, false}, + { 0xDD, OP_FPU, &i386_device::i386_x87_group_dd, &i386_device::i386_x87_group_dd, false}, + { 0xDE, OP_FPU, &i386_device::i386_x87_group_de, &i386_device::i386_x87_group_de, false}, + { 0xDF, OP_FPU, &i386_device::i386_x87_group_df, &i386_device::i386_x87_group_df, false}, + { 0xE0, OP_I386, &i386_device::i386_loopne16, &i386_device::i386_loopne32, false}, + { 0xE1, OP_I386, &i386_device::i386_loopz16, &i386_device::i386_loopz32, false}, + { 0xE2, OP_I386, &i386_device::i386_loop16, &i386_device::i386_loop32, false}, + { 0xE3, OP_I386, &i386_device::i386_jcxz16, &i386_device::i386_jcxz32, false}, + { 0xE4, OP_I386, &i386_device::i386_in_al_i8, &i386_device::i386_in_al_i8, false}, + { 0xE5, OP_I386, &i386_device::i386_in_ax_i8, &i386_device::i386_in_eax_i8, false}, + { 0xE6, OP_I386, &i386_device::i386_out_al_i8, &i386_device::i386_out_al_i8, false}, + { 0xE7, OP_I386, &i386_device::i386_out_ax_i8, &i386_device::i386_out_eax_i8, false}, + { 0xE8, OP_I386, &i386_device::i386_call_rel16, &i386_device::i386_call_rel32, false}, + { 0xE9, OP_I386, &i386_device::i386_jmp_rel16, &i386_device::i386_jmp_rel32, false}, + { 0xEA, OP_I386, &i386_device::i386_jmp_abs16, &i386_device::i386_jmp_abs32, false}, + { 0xEB, OP_I386, &i386_device::i386_jmp_rel8, &i386_device::i386_jmp_rel8, false}, + { 0xEC, OP_I386, &i386_device::i386_in_al_dx, &i386_device::i386_in_al_dx, false}, + { 0xED, OP_I386, &i386_device::i386_in_ax_dx, &i386_device::i386_in_eax_dx, false}, + { 0xEE, OP_I386, &i386_device::i386_out_al_dx, &i386_device::i386_out_al_dx, false}, + { 0xEF, OP_I386, &i386_device::i386_out_ax_dx, &i386_device::i386_out_eax_dx, false}, + { 0xF0, OP_I386, &i386_device::i386_lock, &i386_device::i386_lock, false}, + { 0xF1, OP_I386, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0xF2, OP_I386, &i386_device::i386_repne, &i386_device::i386_repne, false}, + { 0xF3, OP_I386, &i386_device::i386_rep, &i386_device::i386_rep, false}, + { 0xF4, OP_I386, &i386_device::i386_hlt, &i386_device::i386_hlt, false}, + { 0xF5, OP_I386, &i386_device::i386_cmc, &i386_device::i386_cmc, false}, + { 0xF6, OP_I386, &i386_device::i386_groupF6_8, &i386_device::i386_groupF6_8, true }, + { 0xF7, OP_I386, &i386_device::i386_groupF7_16, &i386_device::i386_groupF7_32, true }, + { 0xF8, OP_I386, &i386_device::i386_clc, &i386_device::i386_clc, false}, + { 0xF9, OP_I386, &i386_device::i386_stc, &i386_device::i386_stc, false}, + { 0xFA, OP_I386, &i386_device::i386_cli, &i386_device::i386_cli, false}, + { 0xFB, OP_I386, &i386_device::i386_sti, &i386_device::i386_sti, false}, + { 0xFC, OP_I386, &i386_device::i386_cld, &i386_device::i386_cld, false}, + { 0xFD, OP_I386, &i386_device::i386_std, &i386_device::i386_std, false}, + { 0xFE, OP_I386, &i386_device::i386_groupFE_8, &i386_device::i386_groupFE_8, true }, + { 0xFF, OP_I386, &i386_device::i386_groupFF_16, &i386_device::i386_groupFF_32, true }, + /* 0F ?? */ + { 0x00, OP_2BYTE|OP_I386, &i386_device::i386_group0F00_16, &i386_device::i386_group0F00_32, false}, + { 0x01, OP_2BYTE|OP_I386, &i386_device::i386_group0F01_16, &i386_device::i386_group0F01_32, false}, + { 0x01, OP_2BYTE|OP_I486, &i386_device::i486_group0F01_16, &i386_device::i486_group0F01_32, false}, + { 0x02, OP_2BYTE|OP_I386, &i386_device::i386_lar_r16_rm16, &i386_device::i386_lar_r32_rm32, false}, + { 0x03, OP_2BYTE|OP_I386, &i386_device::i386_lsl_r16_rm16, &i386_device::i386_lsl_r32_rm32, false}, + { 0x06, OP_2BYTE|OP_I386, &i386_device::i386_clts, &i386_device::i386_clts, false}, + { 0x07, OP_2BYTE|OP_I386, &i386_device::i386_loadall, &i386_device::i386_loadall, false}, + { 0x08, OP_2BYTE|OP_I486, &i386_device::i486_invd, &i386_device::i486_invd, false}, + { 0x09, OP_2BYTE|OP_I486, &i386_device::i486_wbinvd, &i386_device::i486_wbinvd, false}, + { 0x0B, OP_2BYTE|OP_PENTIUM, &i386_device::pentium_ud2, &i386_device::pentium_ud2, false}, + { 0x10, OP_2BYTE|OP_SSE, &i386_device::sse_movups_r128_rm128, &i386_device::sse_movups_r128_rm128, false}, + { 0x11, OP_2BYTE|OP_SSE, &i386_device::sse_movups_rm128_r128, &i386_device::sse_movups_rm128_r128, false}, + { 0x12, OP_2BYTE|OP_SSE, &i386_device::sse_movlps_r128_m64, &i386_device::sse_movlps_r128_m64, false}, + { 0x13, OP_2BYTE|OP_SSE, &i386_device::sse_movlps_m64_r128, &i386_device::sse_movlps_m64_r128, false}, + { 0x14, OP_2BYTE|OP_SSE, &i386_device::sse_unpcklps_r128_rm128, &i386_device::sse_unpcklps_r128_rm128, false}, + { 0x15, OP_2BYTE|OP_SSE, &i386_device::sse_unpckhps_r128_rm128, &i386_device::sse_unpckhps_r128_rm128, false}, + { 0x16, OP_2BYTE|OP_SSE, &i386_device::sse_movhps_r128_m64, &i386_device::sse_movhps_r128_m64, false}, + { 0x17, OP_2BYTE|OP_SSE, &i386_device::sse_movhps_m64_r128, &i386_device::sse_movhps_m64_r128, false}, + { 0x18, OP_2BYTE|OP_PENTIUM, &i386_device::pentium_prefetch_m8, &i386_device::pentium_prefetch_m8, false}, + { 0x20, OP_2BYTE|OP_I386, &i386_device::i386_mov_r32_cr, &i386_device::i386_mov_r32_cr, false}, + { 0x21, OP_2BYTE|OP_I386, &i386_device::i386_mov_r32_dr, &i386_device::i386_mov_r32_dr, false}, + { 0x22, OP_2BYTE|OP_I386, &i386_device::i386_mov_cr_r32, &i386_device::i386_mov_cr_r32, false}, + { 0x22, OP_2BYTE|OP_I486, &i386_device::i486_mov_cr_r32, &i386_device::i486_mov_cr_r32, false}, + { 0x23, OP_2BYTE|OP_I386, &i386_device::i386_mov_dr_r32, &i386_device::i386_mov_dr_r32, false}, + { 0x24, OP_2BYTE|OP_I386, &i386_device::i386_mov_r32_tr, &i386_device::i386_mov_r32_tr, false}, + { 0x26, OP_2BYTE|OP_I386, &i386_device::i386_mov_tr_r32, &i386_device::i386_mov_tr_r32, false}, + { 0x28, OP_2BYTE|OP_SSE, &i386_device::sse_movaps_r128_rm128, &i386_device::sse_movaps_r128_rm128, false}, + { 0x29, OP_2BYTE|OP_SSE, &i386_device::sse_movaps_rm128_r128, &i386_device::sse_movaps_rm128_r128, false}, + { 0x2a, OP_2BYTE|OP_SSE, &i386_device::sse_cvtpi2ps_r128_rm64, &i386_device::sse_cvtpi2ps_r128_rm64, false}, + { 0x2b, OP_2BYTE|OP_SSE, &i386_device::sse_movntps_m128_r128, &i386_device::sse_movntps_m128_r128, false}, + { 0x2c, OP_2BYTE|OP_SSE, &i386_device::sse_cvttps2pi_r64_r128m64, &i386_device::sse_cvttps2pi_r64_r128m64,false}, + { 0x2d, OP_2BYTE|OP_SSE, &i386_device::sse_cvtps2pi_r64_r128m64, &i386_device::sse_cvtps2pi_r64_r128m64,false}, + { 0x2e, OP_2BYTE|OP_SSE, &i386_device::sse_ucomiss_r128_r128m32, &i386_device::sse_ucomiss_r128_r128m32,false}, + { 0x2f, OP_2BYTE|OP_SSE, &i386_device::sse_comiss_r128_r128m32, &i386_device::sse_comiss_r128_r128m32, false}, + { 0x30, OP_2BYTE|OP_PENTIUM, &i386_device::pentium_wrmsr, &i386_device::pentium_wrmsr, false}, + { 0x31, OP_2BYTE|OP_PENTIUM, &i386_device::pentium_rdtsc, &i386_device::pentium_rdtsc, false}, + { 0x32, OP_2BYTE|OP_PENTIUM, &i386_device::pentium_rdmsr, &i386_device::pentium_rdmsr, false}, + { 0x38, OP_2BYTE|OP_PENTIUM, &i386_device::i386_decode_three_byte38, &i386_device::i386_decode_three_byte38,false}, + { 0x3A, OP_2BYTE|OP_PENTIUM, &i386_device::i386_decode_three_byte3a, &i386_device::i386_decode_three_byte3a,false}, + { 0x3A, OP_2BYTE|OP_CYRIX, &i386_device::i386_cyrix_special, &i386_device::i386_cyrix_special, false}, + { 0x3B, OP_2BYTE|OP_CYRIX, &i386_device::i386_cyrix_special, &i386_device::i386_cyrix_special, false}, + { 0x3C, OP_2BYTE|OP_CYRIX, &i386_device::i386_cyrix_special, &i386_device::i386_cyrix_special, false}, + { 0x3D, OP_2BYTE|OP_CYRIX, &i386_device::i386_cyrix_special, &i386_device::i386_cyrix_special, false}, + { 0x40, OP_2BYTE|OP_PENTIUM, &i386_device::pentium_cmovo_r16_rm16, &i386_device::pentium_cmovo_r32_rm32, false}, + { 0x41, OP_2BYTE|OP_PENTIUM, &i386_device::pentium_cmovno_r16_rm16, &i386_device::pentium_cmovno_r32_rm32, false}, + { 0x42, OP_2BYTE|OP_PENTIUM, &i386_device::pentium_cmovb_r16_rm16, &i386_device::pentium_cmovb_r32_rm32, false}, + { 0x43, OP_2BYTE|OP_PENTIUM, &i386_device::pentium_cmovae_r16_rm16, &i386_device::pentium_cmovae_r32_rm32, false}, + { 0x44, OP_2BYTE|OP_PENTIUM, &i386_device::pentium_cmove_r16_rm16, &i386_device::pentium_cmove_r32_rm32, false}, + { 0x45, OP_2BYTE|OP_PENTIUM, &i386_device::pentium_cmovne_r16_rm16, &i386_device::pentium_cmovne_r32_rm32, false}, + { 0x46, OP_2BYTE|OP_PENTIUM, &i386_device::pentium_cmovbe_r16_rm16, &i386_device::pentium_cmovbe_r32_rm32, false}, + { 0x47, OP_2BYTE|OP_PENTIUM, &i386_device::pentium_cmova_r16_rm16, &i386_device::pentium_cmova_r32_rm32, false}, + { 0x48, OP_2BYTE|OP_PENTIUM, &i386_device::pentium_cmovs_r16_rm16, &i386_device::pentium_cmovs_r32_rm32, false}, + { 0x49, OP_2BYTE|OP_PENTIUM, &i386_device::pentium_cmovns_r16_rm16, &i386_device::pentium_cmovns_r32_rm32, false}, + { 0x4a, OP_2BYTE|OP_PENTIUM, &i386_device::pentium_cmovp_r16_rm16, &i386_device::pentium_cmovp_r32_rm32, false}, + { 0x4b, OP_2BYTE|OP_PENTIUM, &i386_device::pentium_cmovnp_r16_rm16, &i386_device::pentium_cmovnp_r32_rm32, false}, + { 0x4c, OP_2BYTE|OP_PENTIUM, &i386_device::pentium_cmovl_r16_rm16, &i386_device::pentium_cmovl_r32_rm32, false}, + { 0x4d, OP_2BYTE|OP_PENTIUM, &i386_device::pentium_cmovge_r16_rm16, &i386_device::pentium_cmovge_r32_rm32, false}, + { 0x4e, OP_2BYTE|OP_PENTIUM, &i386_device::pentium_cmovle_r16_rm16, &i386_device::pentium_cmovle_r32_rm32, false}, + { 0x4f, OP_2BYTE|OP_PENTIUM, &i386_device::pentium_cmovg_r16_rm16, &i386_device::pentium_cmovg_r32_rm32, false}, + { 0x50, OP_2BYTE|OP_SSE, &i386_device::sse_movmskps_r16_r128, &i386_device::sse_movmskps_r32_r128, false}, + { 0x51, OP_2BYTE|OP_SSE, &i386_device::sse_sqrtps_r128_rm128, &i386_device::sse_sqrtps_r128_rm128, false}, + { 0x52, OP_2BYTE|OP_SSE, &i386_device::sse_rsqrtps_r128_rm128, &i386_device::sse_rsqrtps_r128_rm128, false}, + { 0x53, OP_2BYTE|OP_SSE, &i386_device::sse_rcpps_r128_rm128, &i386_device::sse_rcpps_r128_rm128, false}, + { 0x54, OP_2BYTE|OP_SSE, &i386_device::sse_andps_r128_rm128, &i386_device::sse_andps_r128_rm128, false}, + { 0x55, OP_2BYTE|OP_SSE, &i386_device::sse_andnps_r128_rm128, &i386_device::sse_andnps_r128_rm128, false}, + { 0x56, OP_2BYTE|OP_SSE, &i386_device::sse_orps_r128_rm128, &i386_device::sse_orps_r128_rm128, false}, + { 0x57, OP_2BYTE|OP_SSE, &i386_device::sse_xorps, &i386_device::sse_xorps, false}, + { 0x58, OP_2BYTE|OP_SSE, &i386_device::sse_addps, &i386_device::sse_addps, false}, + { 0x59, OP_2BYTE|OP_SSE, &i386_device::sse_mulps, &i386_device::sse_mulps, false}, + { 0x5a, OP_2BYTE|OP_SSE, &i386_device::sse_cvtps2pd_r128_r128m64, &i386_device::sse_cvtps2pd_r128_r128m64,false}, + { 0x5b, OP_2BYTE|OP_SSE, &i386_device::sse_cvtdq2ps_r128_rm128, &i386_device::sse_cvtdq2ps_r128_rm128, false}, + { 0x5c, OP_2BYTE|OP_SSE, &i386_device::sse_subps, &i386_device::sse_subps, false}, + { 0x5d, OP_2BYTE|OP_SSE, &i386_device::sse_minps, &i386_device::sse_minps, false}, + { 0x5e, OP_2BYTE|OP_SSE, &i386_device::sse_divps, &i386_device::sse_divps, false}, + { 0x5f, OP_2BYTE|OP_SSE, &i386_device::sse_maxps, &i386_device::sse_maxps, false}, + { 0x60, OP_2BYTE|OP_MMX, &i386_device::mmx_punpcklbw_r64_r64m32, &i386_device::mmx_punpcklbw_r64_r64m32,false}, + { 0x61, OP_2BYTE|OP_MMX, &i386_device::mmx_punpcklwd_r64_r64m32, &i386_device::mmx_punpcklwd_r64_r64m32,false}, + { 0x62, OP_2BYTE|OP_MMX, &i386_device::mmx_punpckldq_r64_r64m32, &i386_device::mmx_punpckldq_r64_r64m32,false}, + { 0x63, OP_2BYTE|OP_MMX, &i386_device::mmx_packsswb_r64_rm64, &i386_device::mmx_packsswb_r64_rm64, false}, + { 0x64, OP_2BYTE|OP_MMX, &i386_device::mmx_pcmpgtb_r64_rm64, &i386_device::mmx_pcmpgtb_r64_rm64, false}, + { 0x65, OP_2BYTE|OP_MMX, &i386_device::mmx_pcmpgtw_r64_rm64, &i386_device::mmx_pcmpgtw_r64_rm64, false}, + { 0x66, OP_2BYTE|OP_MMX, &i386_device::mmx_pcmpgtd_r64_rm64, &i386_device::mmx_pcmpgtd_r64_rm64, false}, + { 0x67, OP_2BYTE|OP_MMX, &i386_device::mmx_packuswb_r64_rm64, &i386_device::mmx_packuswb_r64_rm64, false}, + { 0x68, OP_2BYTE|OP_MMX, &i386_device::mmx_punpckhbw_r64_rm64, &i386_device::mmx_punpckhbw_r64_rm64, false}, + { 0x69, OP_2BYTE|OP_MMX, &i386_device::mmx_punpckhwd_r64_rm64, &i386_device::mmx_punpckhwd_r64_rm64, false}, + { 0x6a, OP_2BYTE|OP_MMX, &i386_device::mmx_punpckhdq_r64_rm64, &i386_device::mmx_punpckhdq_r64_rm64, false}, + { 0x6b, OP_2BYTE|OP_MMX, &i386_device::mmx_packssdw_r64_rm64, &i386_device::mmx_packssdw_r64_rm64, false}, + { 0x6e, OP_2BYTE|OP_MMX, &i386_device::mmx_movd_r64_rm32, &i386_device::mmx_movd_r64_rm32, false}, + { 0x6f, OP_2BYTE|OP_MMX, &i386_device::mmx_movq_r64_rm64, &i386_device::mmx_movq_r64_rm64, false}, + { 0x70, OP_2BYTE|OP_MMX, &i386_device::mmx_pshufw_r64_rm64_i8, &i386_device::mmx_pshufw_r64_rm64_i8, false}, + { 0x71, OP_2BYTE|OP_MMX, &i386_device::mmx_group_0f71, &i386_device::mmx_group_0f71, false}, + { 0x72, OP_2BYTE|OP_MMX, &i386_device::mmx_group_0f72, &i386_device::mmx_group_0f72, false}, + { 0x73, OP_2BYTE|OP_MMX, &i386_device::mmx_group_0f73, &i386_device::mmx_group_0f73, false}, + { 0x74, OP_2BYTE|OP_CYRIX, &i386_device::i386_cyrix_unknown, &i386_device::i386_cyrix_unknown, false}, + { 0x74, OP_2BYTE|OP_MMX, &i386_device::mmx_pcmpeqb_r64_rm64, &i386_device::mmx_pcmpeqb_r64_rm64, false}, + { 0x75, OP_2BYTE|OP_MMX, &i386_device::mmx_pcmpeqw_r64_rm64, &i386_device::mmx_pcmpeqw_r64_rm64, false}, + { 0x76, OP_2BYTE|OP_MMX, &i386_device::mmx_pcmpeqd_r64_rm64, &i386_device::mmx_pcmpeqd_r64_rm64, false}, + { 0x77, OP_2BYTE|OP_MMX, &i386_device::mmx_emms, &i386_device::mmx_emms, false}, + { 0x78, OP_2BYTE|OP_CYRIX, &i386_device::i386_cyrix_svdc, &i386_device::i386_cyrix_svdc, false}, + { 0x79, OP_2BYTE|OP_CYRIX, &i386_device::i386_cyrix_rsdc, &i386_device::i386_cyrix_rsdc, false}, + { 0x7a, OP_2BYTE|OP_CYRIX, &i386_device::i386_cyrix_svldt, &i386_device::i386_cyrix_svldt, false}, + { 0x7b, OP_2BYTE|OP_CYRIX, &i386_device::i386_cyrix_rsldt, &i386_device::i386_cyrix_rsldt, false}, + { 0x7c, OP_2BYTE|OP_CYRIX, &i386_device::i386_cyrix_svts, &i386_device::i386_cyrix_svts, false}, + { 0x7d, OP_2BYTE|OP_CYRIX, &i386_device::i386_cyrix_rsts, &i386_device::i386_cyrix_rsts, false}, + { 0x7e, OP_2BYTE|OP_MMX, &i386_device::mmx_movd_rm32_r64, &i386_device::mmx_movd_rm32_r64, false}, + { 0x7f, OP_2BYTE|OP_MMX, &i386_device::mmx_movq_rm64_r64, &i386_device::mmx_movq_rm64_r64, false}, + { 0x80, OP_2BYTE|OP_I386, &i386_device::i386_jo_rel16, &i386_device::i386_jo_rel32, false}, + { 0x81, OP_2BYTE|OP_I386, &i386_device::i386_jno_rel16, &i386_device::i386_jno_rel32, false}, + { 0x82, OP_2BYTE|OP_I386, &i386_device::i386_jc_rel16, &i386_device::i386_jc_rel32, false}, + { 0x83, OP_2BYTE|OP_I386, &i386_device::i386_jnc_rel16, &i386_device::i386_jnc_rel32, false}, + { 0x84, OP_2BYTE|OP_I386, &i386_device::i386_jz_rel16, &i386_device::i386_jz_rel32, false}, + { 0x85, OP_2BYTE|OP_I386, &i386_device::i386_jnz_rel16, &i386_device::i386_jnz_rel32, false}, + { 0x86, OP_2BYTE|OP_I386, &i386_device::i386_jbe_rel16, &i386_device::i386_jbe_rel32, false}, + { 0x87, OP_2BYTE|OP_I386, &i386_device::i386_ja_rel16, &i386_device::i386_ja_rel32, false}, + { 0x88, OP_2BYTE|OP_I386, &i386_device::i386_js_rel16, &i386_device::i386_js_rel32, false}, + { 0x89, OP_2BYTE|OP_I386, &i386_device::i386_jns_rel16, &i386_device::i386_jns_rel32, false}, + { 0x8A, OP_2BYTE|OP_I386, &i386_device::i386_jp_rel16, &i386_device::i386_jp_rel32, false}, + { 0x8B, OP_2BYTE|OP_I386, &i386_device::i386_jnp_rel16, &i386_device::i386_jnp_rel32, false}, + { 0x8C, OP_2BYTE|OP_I386, &i386_device::i386_jl_rel16, &i386_device::i386_jl_rel32, false}, + { 0x8D, OP_2BYTE|OP_I386, &i386_device::i386_jge_rel16, &i386_device::i386_jge_rel32, false}, + { 0x8E, OP_2BYTE|OP_I386, &i386_device::i386_jle_rel16, &i386_device::i386_jle_rel32, false}, + { 0x8F, OP_2BYTE|OP_I386, &i386_device::i386_jg_rel16, &i386_device::i386_jg_rel32, false}, + { 0x90, OP_2BYTE|OP_I386, &i386_device::i386_seto_rm8, &i386_device::i386_seto_rm8, false}, + { 0x91, OP_2BYTE|OP_I386, &i386_device::i386_setno_rm8, &i386_device::i386_setno_rm8, false}, + { 0x92, OP_2BYTE|OP_I386, &i386_device::i386_setc_rm8, &i386_device::i386_setc_rm8, false}, + { 0x93, OP_2BYTE|OP_I386, &i386_device::i386_setnc_rm8, &i386_device::i386_setnc_rm8, false}, + { 0x94, OP_2BYTE|OP_I386, &i386_device::i386_setz_rm8, &i386_device::i386_setz_rm8, false}, + { 0x95, OP_2BYTE|OP_I386, &i386_device::i386_setnz_rm8, &i386_device::i386_setnz_rm8, false}, + { 0x96, OP_2BYTE|OP_I386, &i386_device::i386_setbe_rm8, &i386_device::i386_setbe_rm8, false}, + { 0x97, OP_2BYTE|OP_I386, &i386_device::i386_seta_rm8, &i386_device::i386_seta_rm8, false}, + { 0x98, OP_2BYTE|OP_I386, &i386_device::i386_sets_rm8, &i386_device::i386_sets_rm8, false}, + { 0x99, OP_2BYTE|OP_I386, &i386_device::i386_setns_rm8, &i386_device::i386_setns_rm8, false}, + { 0x9A, OP_2BYTE|OP_I386, &i386_device::i386_setp_rm8, &i386_device::i386_setp_rm8, false}, + { 0x9B, OP_2BYTE|OP_I386, &i386_device::i386_setnp_rm8, &i386_device::i386_setnp_rm8, false}, + { 0x9C, OP_2BYTE|OP_I386, &i386_device::i386_setl_rm8, &i386_device::i386_setl_rm8, false}, + { 0x9D, OP_2BYTE|OP_I386, &i386_device::i386_setge_rm8, &i386_device::i386_setge_rm8, false}, + { 0x9E, OP_2BYTE|OP_I386, &i386_device::i386_setle_rm8, &i386_device::i386_setle_rm8, false}, + { 0x9F, OP_2BYTE|OP_I386, &i386_device::i386_setg_rm8, &i386_device::i386_setg_rm8, false}, + { 0xA0, OP_2BYTE|OP_I386, &i386_device::i386_push_fs16, &i386_device::i386_push_fs32, false}, + { 0xA1, OP_2BYTE|OP_I386, &i386_device::i386_pop_fs16, &i386_device::i386_pop_fs32, false}, + { 0xA2, OP_2BYTE|OP_I486, &i386_device::i486_cpuid, &i386_device::i486_cpuid, false}, + { 0xA3, OP_2BYTE|OP_I386, &i386_device::i386_bt_rm16_r16, &i386_device::i386_bt_rm32_r32, false}, + { 0xA4, OP_2BYTE|OP_I386, &i386_device::i386_shld16_i8, &i386_device::i386_shld32_i8, false}, + { 0xA5, OP_2BYTE|OP_I386, &i386_device::i386_shld16_cl, &i386_device::i386_shld32_cl, false}, + { 0xA8, OP_2BYTE|OP_I386, &i386_device::i386_push_gs16, &i386_device::i386_push_gs32, false}, + { 0xA9, OP_2BYTE|OP_I386, &i386_device::i386_pop_gs16, &i386_device::i386_pop_gs32, false}, + { 0xAA, OP_2BYTE|OP_PENTIUM, &i386_device::pentium_rsm, &i386_device::pentium_rsm, false}, + { 0xAB, OP_2BYTE|OP_I386, &i386_device::i386_bts_rm16_r16, &i386_device::i386_bts_rm32_r32, true }, + { 0xAC, OP_2BYTE|OP_I386, &i386_device::i386_shrd16_i8, &i386_device::i386_shrd32_i8, false}, + { 0xAD, OP_2BYTE|OP_I386, &i386_device::i386_shrd16_cl, &i386_device::i386_shrd32_cl, false}, + { 0xAE, OP_2BYTE|OP_SSE, &i386_device::sse_group_0fae, &i386_device::sse_group_0fae, false}, + { 0xAF, OP_2BYTE|OP_I386, &i386_device::i386_imul_r16_rm16, &i386_device::i386_imul_r32_rm32, false}, + { 0xB0, OP_2BYTE|OP_I486, &i386_device::i486_cmpxchg_rm8_r8, &i386_device::i486_cmpxchg_rm8_r8, true }, + { 0xB1, OP_2BYTE|OP_I486, &i386_device::i486_cmpxchg_rm16_r16, &i386_device::i486_cmpxchg_rm32_r32, true }, + { 0xB2, OP_2BYTE|OP_I386, &i386_device::i386_lss16, &i386_device::i386_lss32, false}, + { 0xB3, OP_2BYTE|OP_I386, &i386_device::i386_btr_rm16_r16, &i386_device::i386_btr_rm32_r32, true }, + { 0xB4, OP_2BYTE|OP_I386, &i386_device::i386_lfs16, &i386_device::i386_lfs32, false}, + { 0xB5, OP_2BYTE|OP_I386, &i386_device::i386_lgs16, &i386_device::i386_lgs32, false}, + { 0xB6, OP_2BYTE|OP_I386, &i386_device::i386_movzx_r16_rm8, &i386_device::i386_movzx_r32_rm8, false}, + { 0xB7, OP_2BYTE|OP_I386, &i386_device::i386_invalid, &i386_device::i386_movzx_r32_rm16, false}, + { 0xBA, OP_2BYTE|OP_I386, &i386_device::i386_group0FBA_16, &i386_device::i386_group0FBA_32, true }, + { 0xBB, OP_2BYTE|OP_I386, &i386_device::i386_btc_rm16_r16, &i386_device::i386_btc_rm32_r32, true }, + { 0xBC, OP_2BYTE|OP_I386, &i386_device::i386_bsf_r16_rm16, &i386_device::i386_bsf_r32_rm32, false}, + { 0xBD, OP_2BYTE|OP_I386, &i386_device::i386_bsr_r16_rm16, &i386_device::i386_bsr_r32_rm32, false}, + { 0xBE, OP_2BYTE|OP_I386, &i386_device::i386_movsx_r16_rm8, &i386_device::i386_movsx_r32_rm8, false}, + { 0xBF, OP_2BYTE|OP_I386, &i386_device::i386_invalid, &i386_device::i386_movsx_r32_rm16, false}, + { 0xC0, OP_2BYTE|OP_I486, &i386_device::i486_xadd_rm8_r8, &i386_device::i486_xadd_rm8_r8, true }, + { 0xC1, OP_2BYTE|OP_I486, &i386_device::i486_xadd_rm16_r16, &i386_device::i486_xadd_rm32_r32, true }, + { 0xC2, OP_2BYTE|OP_SSE, &i386_device::sse_cmpps_r128_rm128_i8, &i386_device::sse_cmpps_r128_rm128_i8, false}, + { 0xC3, OP_2BYTE|OP_PENTIUM, &i386_device::pentium_movnti_m16_r16, &i386_device::pentium_movnti_m32_r32, false}, + { 0xC4, OP_2BYTE|OP_SSE, &i386_device::sse_pinsrw_r64_r16m16_i8, &i386_device::sse_pinsrw_r64_r32m16_i8,false}, + { 0xC5, OP_2BYTE|OP_SSE, &i386_device::sse_pextrw_r16_r64_i8, &i386_device::sse_pextrw_r32_r64_i8, false}, + { 0xC6, OP_2BYTE|OP_SSE, &i386_device::sse_shufps, &i386_device::sse_shufps, false}, + { 0xC7, OP_2BYTE|OP_PENTIUM, &i386_device::pentium_cmpxchg8b_m64, &i386_device::pentium_cmpxchg8b_m64, true }, + { 0xC8, OP_2BYTE|OP_I486, &i386_device::i486_bswap_eax, &i386_device::i486_bswap_eax, false}, + { 0xC9, OP_2BYTE|OP_I486, &i386_device::i486_bswap_ecx, &i386_device::i486_bswap_ecx, false}, + { 0xCA, OP_2BYTE|OP_I486, &i386_device::i486_bswap_edx, &i386_device::i486_bswap_edx, false}, + { 0xCB, OP_2BYTE|OP_I486, &i386_device::i486_bswap_ebx, &i386_device::i486_bswap_ebx, false}, + { 0xCC, OP_2BYTE|OP_I486, &i386_device::i486_bswap_esp, &i386_device::i486_bswap_esp, false}, + { 0xCD, OP_2BYTE|OP_I486, &i386_device::i486_bswap_ebp, &i386_device::i486_bswap_ebp, false}, + { 0xCE, OP_2BYTE|OP_I486, &i386_device::i486_bswap_esi, &i386_device::i486_bswap_esi, false}, + { 0xCF, OP_2BYTE|OP_I486, &i386_device::i486_bswap_edi, &i386_device::i486_bswap_edi, false}, + { 0xD1, OP_2BYTE|OP_MMX, &i386_device::mmx_psrlw_r64_rm64, &i386_device::mmx_psrlw_r64_rm64, false}, + { 0xD2, OP_2BYTE|OP_MMX, &i386_device::mmx_psrld_r64_rm64, &i386_device::mmx_psrld_r64_rm64, false}, + { 0xD3, OP_2BYTE|OP_MMX, &i386_device::mmx_psrlq_r64_rm64, &i386_device::mmx_psrlq_r64_rm64, false}, + { 0xD4, OP_2BYTE|OP_MMX, &i386_device::mmx_paddq_r64_rm64, &i386_device::mmx_paddq_r64_rm64, false}, + { 0xD5, OP_2BYTE|OP_MMX, &i386_device::mmx_pmullw_r64_rm64, &i386_device::mmx_pmullw_r64_rm64, false}, + { 0xD7, OP_2BYTE|OP_SSE, &i386_device::sse_pmovmskb_r16_r64, &i386_device::sse_pmovmskb_r32_r64, false}, + { 0xD8, OP_2BYTE|OP_MMX, &i386_device::mmx_psubusb_r64_rm64, &i386_device::mmx_psubusb_r64_rm64, false}, + { 0xD9, OP_2BYTE|OP_MMX, &i386_device::mmx_psubusw_r64_rm64, &i386_device::mmx_psubusw_r64_rm64, false}, + { 0xDA, OP_2BYTE|OP_SSE, &i386_device::sse_pminub_r64_rm64, &i386_device::sse_pminub_r64_rm64, false}, + { 0xDB, OP_2BYTE|OP_MMX, &i386_device::mmx_pand_r64_rm64, &i386_device::mmx_pand_r64_rm64, false}, + { 0xDC, OP_2BYTE|OP_MMX, &i386_device::mmx_paddusb_r64_rm64, &i386_device::mmx_paddusb_r64_rm64, false}, + { 0xDD, OP_2BYTE|OP_MMX, &i386_device::mmx_paddusw_r64_rm64, &i386_device::mmx_paddusw_r64_rm64, false}, + { 0xDE, OP_2BYTE|OP_SSE, &i386_device::sse_pmaxub_r64_rm64, &i386_device::sse_pmaxub_r64_rm64, false}, + { 0xDF, OP_2BYTE|OP_MMX, &i386_device::mmx_pandn_r64_rm64, &i386_device::mmx_pandn_r64_rm64, false}, + { 0xE0, OP_2BYTE|OP_SSE, &i386_device::sse_pavgb_r64_rm64, &i386_device::sse_pavgb_r64_rm64, false}, + { 0xE1, OP_2BYTE|OP_MMX, &i386_device::mmx_psraw_r64_rm64, &i386_device::mmx_psraw_r64_rm64, false}, + { 0xE2, OP_2BYTE|OP_MMX, &i386_device::mmx_psrad_r64_rm64, &i386_device::mmx_psrad_r64_rm64, false}, + { 0xE3, OP_2BYTE|OP_SSE, &i386_device::sse_pavgw_r64_rm64, &i386_device::sse_pavgw_r64_rm64, false}, + { 0xE4, OP_2BYTE|OP_SSE, &i386_device::sse_pmulhuw_r64_rm64, &i386_device::sse_pmulhuw_r64_rm64, false}, + { 0xE5, OP_2BYTE|OP_MMX, &i386_device::mmx_pmulhw_r64_rm64, &i386_device::mmx_pmulhw_r64_rm64, false}, + { 0xE7, OP_2BYTE|OP_PENTIUM, &i386_device::pentium_movntq_m64_r64, &i386_device::pentium_movntq_m64_r64, false}, + { 0xE8, OP_2BYTE|OP_MMX, &i386_device::mmx_psubsb_r64_rm64, &i386_device::mmx_psubsb_r64_rm64, false}, + { 0xE9, OP_2BYTE|OP_MMX, &i386_device::mmx_psubsw_r64_rm64, &i386_device::mmx_psubsw_r64_rm64, false}, + { 0xEA, OP_2BYTE|OP_SSE, &i386_device::sse_pminsw_r64_rm64, &i386_device::sse_pminsw_r64_rm64, false}, + { 0xEB, OP_2BYTE|OP_MMX, &i386_device::mmx_por_r64_rm64, &i386_device::mmx_por_r64_rm64, false}, + { 0xEC, OP_2BYTE|OP_MMX, &i386_device::mmx_paddsb_r64_rm64, &i386_device::mmx_paddsb_r64_rm64, false}, + { 0xED, OP_2BYTE|OP_MMX, &i386_device::mmx_paddsw_r64_rm64, &i386_device::mmx_paddsw_r64_rm64, false}, + { 0xEE, OP_2BYTE|OP_SSE, &i386_device::sse_pmaxsw_r64_rm64, &i386_device::sse_pmaxsw_r64_rm64, false}, + { 0xEF, OP_2BYTE|OP_MMX, &i386_device::mmx_pxor_r64_rm64, &i386_device::mmx_pxor_r64_rm64, false}, + { 0xF1, OP_2BYTE|OP_MMX, &i386_device::mmx_psllw_r64_rm64, &i386_device::mmx_psllw_r64_rm64, false}, + { 0xF2, OP_2BYTE|OP_MMX, &i386_device::mmx_pslld_r64_rm64, &i386_device::mmx_pslld_r64_rm64, false}, + { 0xF3, OP_2BYTE|OP_MMX, &i386_device::mmx_psllq_r64_rm64, &i386_device::mmx_psllq_r64_rm64, false}, + { 0xF4, OP_2BYTE|OP_SSE, &i386_device::sse_pmuludq_r64_rm64, &i386_device::sse_pmuludq_r64_rm64, false}, + { 0xF5, OP_2BYTE|OP_MMX, &i386_device::mmx_pmaddwd_r64_rm64, &i386_device::mmx_pmaddwd_r64_rm64, false}, + { 0xF6, OP_2BYTE|OP_SSE, &i386_device::sse_psadbw_r64_rm64, &i386_device::sse_psadbw_r64_rm64, false}, + { 0xf7, OP_2BYTE|OP_PENTIUM, &i386_device::pentium_maskmovq_r64_r64, &i386_device::pentium_maskmovq_r64_r64,false}, + { 0xF8, OP_2BYTE|OP_MMX, &i386_device::mmx_psubb_r64_rm64, &i386_device::mmx_psubb_r64_rm64, false}, + { 0xF9, OP_2BYTE|OP_MMX, &i386_device::mmx_psubw_r64_rm64, &i386_device::mmx_psubw_r64_rm64, false}, + { 0xFA, OP_2BYTE|OP_MMX, &i386_device::mmx_psubd_r64_rm64, &i386_device::mmx_psubd_r64_rm64, false}, + { 0xFB, OP_2BYTE|OP_SSE, &i386_device::sse_psubq_r64_rm64, &i386_device::sse_psubq_r64_rm64, false}, + { 0xFC, OP_2BYTE|OP_MMX, &i386_device::mmx_paddb_r64_rm64, &i386_device::mmx_paddb_r64_rm64, false}, + { 0xFD, OP_2BYTE|OP_MMX, &i386_device::mmx_paddw_r64_rm64, &i386_device::mmx_paddw_r64_rm64, false}, + { 0xFE, OP_2BYTE|OP_MMX, &i386_device::mmx_paddd_r64_rm64, &i386_device::mmx_paddd_r64_rm64, false}, + /* F3 0F ?? */ + { 0x10, OP_3BYTEF3|OP_SSE, &i386_device::sse_movss_r128_rm128, &i386_device::sse_movss_r128_rm128, false}, + { 0x11, OP_3BYTEF3|OP_SSE, &i386_device::sse_movss_rm128_r128, &i386_device::sse_movss_rm128_r128, false}, + { 0x12, OP_3BYTEF3|OP_SSE, &i386_device::sse_movsldup_r128_rm128, &i386_device::sse_movsldup_r128_rm128, false}, + { 0x16, OP_3BYTEF3|OP_SSE, &i386_device::sse_movshdup_r128_rm128, &i386_device::sse_movshdup_r128_rm128, false}, + { 0x2A, OP_3BYTEF3|OP_SSE, &i386_device::sse_cvtsi2ss_r128_rm32, &i386_device::sse_cvtsi2ss_r128_rm32, false}, + { 0x2C, OP_3BYTEF3|OP_SSE, &i386_device::sse_cvttss2si_r32_r128m32, &i386_device::sse_cvttss2si_r32_r128m32,false}, + { 0x2D, OP_3BYTEF3|OP_SSE, &i386_device::sse_cvtss2si_r32_r128m32, &i386_device::sse_cvtss2si_r32_r128m32,false}, + { 0x51, OP_3BYTEF3|OP_SSE, &i386_device::sse_sqrtss_r128_r128m32, &i386_device::sse_sqrtss_r128_r128m32, false}, + { 0x52, OP_3BYTEF3|OP_SSE, &i386_device::sse_rsqrtss_r128_r128m32, &i386_device::sse_rsqrtss_r128_r128m32,false}, + { 0x53, OP_3BYTEF3|OP_SSE, &i386_device::sse_rcpss_r128_r128m32, &i386_device::sse_rcpss_r128_r128m32, false}, + { 0x58, OP_3BYTEF3|OP_SSE, &i386_device::sse_addss, &i386_device::sse_addss, false}, + { 0x59, OP_3BYTEF3|OP_SSE, &i386_device::sse_mulss, &i386_device::sse_mulss, false}, + { 0x5A, OP_3BYTEF3|OP_SSE, &i386_device::sse_cvtss2sd_r128_r128m32, &i386_device::sse_cvtss2sd_r128_r128m32,false}, + { 0x5B, OP_3BYTEF3|OP_SSE, &i386_device::sse_cvttps2dq_r128_rm128, &i386_device::sse_cvttps2dq_r128_rm128,false}, + { 0x5C, OP_3BYTEF3|OP_SSE, &i386_device::sse_subss, &i386_device::sse_subss, false}, + { 0x5D, OP_3BYTEF3|OP_SSE, &i386_device::sse_minss_r128_r128m32, &i386_device::sse_minss_r128_r128m32, false}, + { 0x5E, OP_3BYTEF3|OP_SSE, &i386_device::sse_divss, &i386_device::sse_divss, false}, + { 0x5F, OP_3BYTEF3|OP_SSE, &i386_device::sse_maxss_r128_r128m32, &i386_device::sse_maxss_r128_r128m32, false}, + { 0x6F, OP_3BYTEF3|OP_SSE, &i386_device::sse_movdqu_r128_rm128, &i386_device::sse_movdqu_r128_rm128, false}, + { 0x70, OP_3BYTEF3|OP_SSE, &i386_device::sse_pshufhw_r128_rm128_i8, &i386_device::sse_pshufhw_r128_rm128_i8,false}, + { 0x7E, OP_3BYTEF3|OP_SSE, &i386_device::sse_movq_r128_r128m64, &i386_device::sse_movq_r128_r128m64, false}, + { 0x7F, OP_3BYTEF3|OP_SSE, &i386_device::sse_movdqu_rm128_r128, &i386_device::sse_movdqu_rm128_r128, false}, + { 0xAE, OP_3BYTE66|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0xB8, OP_3BYTEF3|OP_PENTIUM, &i386_device::pentium_popcnt_r16_rm16, &i386_device::pentium_popcnt_r32_rm32, false}, + { 0xBC, OP_3BYTEF3|OP_PENTIUM, &i386_device::pentium_tzcnt_r16_rm16, &i386_device::pentium_tzcnt_r32_rm32, false}, + { 0xC2, OP_3BYTEF3|OP_SSE, &i386_device::sse_cmpss_r128_r128m32_i8, &i386_device::sse_cmpss_r128_r128m32_i8,false}, + { 0xC7, OP_3BYTEF2|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0xD6, OP_3BYTEF3|OP_SSE, &i386_device::sse_movq2dq_r128_r64, &i386_device::sse_movq2dq_r128_r64, false}, + { 0xE6, OP_3BYTEF3|OP_SSE, &i386_device::sse_cvtdq2pd_r128_r128m64, &i386_device::sse_cvtdq2pd_r128_r128m64,false}, + /* F2 0F ?? */ + { 0x10, OP_3BYTEF2|OP_SSE, &i386_device::sse_movsd_r128_r128m64, &i386_device::sse_movsd_r128_r128m64, false}, + { 0x11, OP_3BYTEF2|OP_SSE, &i386_device::sse_movsd_r128m64_r128, &i386_device::sse_movsd_r128m64_r128, false}, + { 0x12, OP_3BYTEF2|OP_SSE, &i386_device::sse_movddup_r128_r128m64, &i386_device::sse_movddup_r128_r128m64,false}, + { 0x2A, OP_3BYTEF2|OP_SSE, &i386_device::sse_cvtsi2sd_r128_rm32, &i386_device::sse_cvtsi2sd_r128_rm32, false}, + { 0x2C, OP_3BYTEF2|OP_SSE, &i386_device::sse_cvttsd2si_r32_r128m64, &i386_device::sse_cvttsd2si_r32_r128m64,false}, + { 0x2D, OP_3BYTEF2|OP_SSE, &i386_device::sse_cvtsd2si_r32_r128m64, &i386_device::sse_cvtsd2si_r32_r128m64,false}, + { 0x51, OP_3BYTEF2|OP_SSE, &i386_device::sse_sqrtsd_r128_r128m64, &i386_device::sse_sqrtsd_r128_r128m64, false}, + { 0x58, OP_3BYTEF2|OP_SSE, &i386_device::sse_addsd_r128_r128m64, &i386_device::sse_addsd_r128_r128m64, false}, + { 0x59, OP_3BYTEF2|OP_SSE, &i386_device::sse_mulsd_r128_r128m64, &i386_device::sse_mulsd_r128_r128m64, false}, + { 0x5A, OP_3BYTEF2|OP_SSE, &i386_device::sse_cvtsd2ss_r128_r128m64, &i386_device::sse_cvtsd2ss_r128_r128m64,false}, + { 0x5C, OP_3BYTEF2|OP_SSE, &i386_device::sse_subsd_r128_r128m64, &i386_device::sse_subsd_r128_r128m64, false}, + { 0x5D, OP_3BYTEF2|OP_SSE, &i386_device::sse_minsd_r128_r128m64, &i386_device::sse_minsd_r128_r128m64, false}, + { 0x5E, OP_3BYTEF2|OP_SSE, &i386_device::sse_divsd_r128_r128m64, &i386_device::sse_divsd_r128_r128m64, false}, + { 0x5F, OP_3BYTEF2|OP_SSE, &i386_device::sse_maxsd_r128_r128m64, &i386_device::sse_maxsd_r128_r128m64, false}, + { 0x70, OP_3BYTEF2|OP_SSE, &i386_device::sse_pshuflw_r128_rm128_i8, &i386_device::sse_pshuflw_r128_rm128_i8,false}, + { 0x7C, OP_3BYTEF2|OP_SSE, &i386_device::sse_haddps_r128_rm128, &i386_device::sse_haddps_r128_rm128, false}, + { 0x7D, OP_3BYTEF2|OP_SSE, &i386_device::sse_hsubps_r128_rm128, &i386_device::sse_hsubps_r128_rm128, false}, + { 0xC2, OP_3BYTEF2|OP_SSE, &i386_device::sse_cmpsd_r128_r128m64_i8, &i386_device::sse_cmpsd_r128_r128m64_i8,false}, + { 0xD0, OP_3BYTEF2|OP_SSE, &i386_device::sse_addsubps_r128_rm128, &i386_device::sse_addsubps_r128_rm128, false}, + { 0xD6, OP_3BYTEF2|OP_SSE, &i386_device::sse_movdq2q_r64_r128, &i386_device::sse_movdq2q_r64_r128, false}, + { 0xE6, OP_3BYTEF2|OP_SSE, &i386_device::sse_cvtpd2dq_r128_rm128, &i386_device::sse_cvtpd2dq_r128_rm128, false}, + { 0xF0, OP_3BYTEF2|OP_SSE, &i386_device::sse_lddqu_r128_m128, &i386_device::sse_lddqu_r128_m128, false}, + /* 66 0F ?? */ + { 0x10, OP_3BYTE66|OP_SSE, &i386_device::sse_movupd_r128_rm128, &i386_device::sse_movupd_r128_rm128, false}, + { 0x11, OP_3BYTE66|OP_SSE, &i386_device::sse_movupd_rm128_r128, &i386_device::sse_movupd_rm128_r128, false}, + { 0x12, OP_3BYTE66|OP_SSE, &i386_device::sse_movlpd_r128_m64, &i386_device::sse_movlpd_r128_m64, false}, + { 0x13, OP_3BYTE66|OP_SSE, &i386_device::sse_movlpd_m64_r128, &i386_device::sse_movlpd_m64_r128, false}, + { 0x14, OP_3BYTE66|OP_SSE, &i386_device::sse_unpcklpd_r128_rm128, &i386_device::sse_unpcklpd_r128_rm128, false}, + { 0x15, OP_3BYTE66|OP_SSE, &i386_device::sse_unpckhpd_r128_rm128, &i386_device::sse_unpckhpd_r128_rm128, false}, + { 0x16, OP_3BYTE66|OP_SSE, &i386_device::sse_movhpd_r128_m64, &i386_device::sse_movhpd_r128_m64, false}, + { 0x17, OP_3BYTE66|OP_SSE, &i386_device::sse_movhpd_m64_r128, &i386_device::sse_movhpd_m64_r128, false}, + { 0x28, OP_3BYTE66|OP_SSE, &i386_device::sse_movapd_r128_rm128, &i386_device::sse_movapd_r128_rm128, false}, + { 0x29, OP_3BYTE66|OP_SSE, &i386_device::sse_movapd_rm128_r128, &i386_device::sse_movapd_rm128_r128, false}, + { 0x2A, OP_3BYTE66|OP_SSE, &i386_device::sse_cvtpi2pd_r128_rm64, &i386_device::sse_cvtpi2pd_r128_rm64, false}, + { 0x2B, OP_3BYTE66|OP_SSE, &i386_device::sse_movntpd_m128_r128, &i386_device::sse_movntpd_m128_r128, false}, + { 0x2C, OP_3BYTE66|OP_SSE, &i386_device::sse_cvttpd2pi_r64_rm128, &i386_device::sse_cvttpd2pi_r64_rm128, false}, + { 0x2D, OP_3BYTE66|OP_SSE, &i386_device::sse_cvtpd2pi_r64_rm128, &i386_device::sse_cvtpd2pi_r64_rm128, false}, + { 0x2E, OP_3BYTE66|OP_SSE, &i386_device::sse_ucomisd_r128_r128m64, &i386_device::sse_ucomisd_r128_r128m64,false}, + { 0x2F, OP_3BYTE66|OP_SSE, &i386_device::sse_comisd_r128_r128m64, &i386_device::sse_comisd_r128_r128m64, false}, + { 0x50, OP_3BYTE66|OP_SSE, &i386_device::sse_movmskpd_r32_r128, &i386_device::sse_movmskpd_r32_r128, false}, + { 0x51, OP_3BYTE66|OP_SSE, &i386_device::sse_sqrtpd_r128_rm128, &i386_device::sse_sqrtpd_r128_rm128, false}, + { 0x54, OP_3BYTE66|OP_SSE, &i386_device::sse_andpd_r128_rm128, &i386_device::sse_andpd_r128_rm128, false}, + { 0x55, OP_3BYTE66|OP_SSE, &i386_device::sse_andnpd_r128_rm128, &i386_device::sse_andnpd_r128_rm128, false}, + { 0x56, OP_3BYTE66|OP_SSE, &i386_device::sse_orpd_r128_rm128, &i386_device::sse_orpd_r128_rm128, false}, + { 0x57, OP_3BYTE66|OP_SSE, &i386_device::sse_xorpd_r128_rm128, &i386_device::sse_xorpd_r128_rm128, false}, + { 0x58, OP_3BYTE66|OP_SSE, &i386_device::sse_addpd_r128_rm128, &i386_device::sse_addpd_r128_rm128, false}, + { 0x59, OP_3BYTE66|OP_SSE, &i386_device::sse_mulpd_r128_rm128, &i386_device::sse_mulpd_r128_rm128, false}, + { 0x5A, OP_3BYTE66|OP_SSE, &i386_device::sse_cvtpd2ps_r128_rm128, &i386_device::sse_cvtpd2ps_r128_rm128, false}, + { 0x5B, OP_3BYTE66|OP_SSE, &i386_device::sse_cvtps2dq_r128_rm128, &i386_device::sse_cvtps2dq_r128_rm128, false}, + { 0x5C, OP_3BYTE66|OP_SSE, &i386_device::sse_subpd_r128_rm128, &i386_device::sse_subpd_r128_rm128, false}, + { 0x5D, OP_3BYTE66|OP_SSE, &i386_device::sse_minpd_r128_rm128, &i386_device::sse_minpd_r128_rm128, false}, + { 0x5E, OP_3BYTE66|OP_SSE, &i386_device::sse_divpd_r128_rm128, &i386_device::sse_divpd_r128_rm128, false}, + { 0x5F, OP_3BYTE66|OP_SSE, &i386_device::sse_maxpd_r128_rm128, &i386_device::sse_maxpd_r128_rm128, false}, + { 0x60, OP_3BYTE66|OP_SSE, &i386_device::sse_punpcklbw_r128_rm128, &i386_device::sse_punpcklbw_r128_rm128,false}, + { 0x61, OP_3BYTE66|OP_SSE, &i386_device::sse_punpcklwd_r128_rm128, &i386_device::sse_punpcklwd_r128_rm128,false}, + { 0x62, OP_3BYTE66|OP_SSE, &i386_device::sse_punpckldq_r128_rm128, &i386_device::sse_punpckldq_r128_rm128,false}, + { 0x63, OP_3BYTE66|OP_SSE, &i386_device::sse_packsswb_r128_rm128, &i386_device::sse_packsswb_r128_rm128, false}, + { 0x64, OP_3BYTE66|OP_SSE, &i386_device::sse_pcmpgtb_r128_rm128, &i386_device::sse_pcmpgtb_r128_rm128, false}, + { 0x65, OP_3BYTE66|OP_SSE, &i386_device::sse_pcmpgtw_r128_rm128, &i386_device::sse_pcmpgtw_r128_rm128, false}, + { 0x66, OP_3BYTE66|OP_SSE, &i386_device::sse_pcmpgtd_r128_rm128, &i386_device::sse_pcmpgtd_r128_rm128, false}, + { 0x67, OP_3BYTE66|OP_SSE, &i386_device::sse_packuswb_r128_rm128, &i386_device::sse_packuswb_r128_rm128, false}, + { 0x68, OP_3BYTE66|OP_SSE, &i386_device::sse_punpckhbw_r128_rm128, &i386_device::sse_punpckhbw_r128_rm128,false}, + { 0x69, OP_3BYTE66|OP_SSE, &i386_device::sse_punpckhwd_r128_rm128, &i386_device::sse_punpckhwd_r128_rm128,false}, + { 0x6A, OP_3BYTE66|OP_SSE, &i386_device::sse_unpckhdq_r128_rm128, &i386_device::sse_unpckhdq_r128_rm128, false}, + { 0x6B, OP_3BYTE66|OP_SSE, &i386_device::sse_packssdw_r128_rm128, &i386_device::sse_packssdw_r128_rm128, false}, + { 0x6C, OP_3BYTE66|OP_SSE, &i386_device::sse_punpcklqdq_r128_rm128, &i386_device::sse_punpcklqdq_r128_rm128,false}, + { 0x6D, OP_3BYTE66|OP_SSE, &i386_device::sse_punpckhqdq_r128_rm128, &i386_device::sse_punpckhqdq_r128_rm128,false}, + { 0x6E, OP_3BYTE66|OP_SSE, &i386_device::sse_movd_m128_rm32, &i386_device::sse_movd_m128_rm32, false}, + { 0x6F, OP_3BYTE66|OP_SSE, &i386_device::sse_movdqa_m128_rm128, &i386_device::sse_movdqa_m128_rm128, false}, + { 0x70, OP_3BYTE66|OP_SSE, &i386_device::sse_pshufd_r128_rm128_i8, &i386_device::sse_pshufd_r128_rm128_i8,false}, + { 0x71, OP_3BYTE66|OP_SSE, &i386_device::sse_group_660f71, &i386_device::sse_group_660f71, false}, + { 0x72, OP_3BYTE66|OP_SSE, &i386_device::sse_group_660f72, &i386_device::sse_group_660f72, false}, + { 0x73, OP_3BYTE66|OP_SSE, &i386_device::sse_group_660f73, &i386_device::sse_group_660f73, false}, + { 0x74, OP_3BYTE66|OP_SSE, &i386_device::sse_pcmpeqb_r128_rm128, &i386_device::sse_pcmpeqb_r128_rm128, false}, + { 0x75, OP_3BYTE66|OP_SSE, &i386_device::sse_pcmpeqw_r128_rm128, &i386_device::sse_pcmpeqw_r128_rm128, false}, + { 0x76, OP_3BYTE66|OP_SSE, &i386_device::sse_pcmpeqd_r128_rm128, &i386_device::sse_pcmpeqd_r128_rm128, false}, + { 0x7C, OP_3BYTE66|OP_SSE, &i386_device::sse_haddpd_r128_rm128, &i386_device::sse_haddpd_r128_rm128, false}, + { 0x7D, OP_3BYTE66|OP_SSE, &i386_device::sse_hsubpd_r128_rm128, &i386_device::sse_hsubpd_r128_rm128, false}, + { 0x7E, OP_3BYTE66|OP_SSE, &i386_device::sse_movd_rm32_r128, &i386_device::sse_movd_rm32_r128, false}, + { 0x7F, OP_3BYTE66|OP_SSE, &i386_device::sse_movdqa_rm128_r128, &i386_device::sse_movdqa_rm128_r128, false}, + { 0xC2, OP_3BYTE66|OP_SSE, &i386_device::sse_cmppd_r128_rm128_i8, &i386_device::sse_cmppd_r128_rm128_i8, false}, + { 0xC4, OP_3BYTE66|OP_SSE, &i386_device::sse_pinsrw_r128_r32m16_i8, &i386_device::sse_pinsrw_r128_r32m16_i8,false}, + { 0xC5, OP_3BYTE66|OP_SSE, &i386_device::sse_pextrw_reg_r128_i8, &i386_device::sse_pextrw_reg_r128_i8, false}, + { 0xC6, OP_3BYTE66|OP_SSE, &i386_device::sse_shufpd_r128_rm128_i8, &i386_device::sse_shufpd_r128_rm128_i8,false}, + { 0xC7, OP_3BYTE66|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0xD0, OP_3BYTE66|OP_SSE, &i386_device::sse_addsubpd_r128_rm128, &i386_device::sse_addsubpd_r128_rm128, false}, + { 0xD1, OP_3BYTE66|OP_SSE, &i386_device::sse_psrlw_r128_rm128, &i386_device::sse_psrlw_r128_rm128, false}, + { 0xD2, OP_3BYTE66|OP_SSE, &i386_device::sse_psrld_r128_rm128, &i386_device::sse_psrld_r128_rm128, false}, + { 0xD3, OP_3BYTE66|OP_SSE, &i386_device::sse_psrlq_r128_rm128, &i386_device::sse_psrlq_r128_rm128, false}, + { 0xD4, OP_3BYTE66|OP_SSE, &i386_device::sse_paddq_r128_rm128, &i386_device::sse_paddq_r128_rm128, false}, + { 0xD5, OP_3BYTE66|OP_SSE, &i386_device::sse_pmullw_r128_rm128, &i386_device::sse_pmullw_r128_rm128, false}, + { 0xD6, OP_3BYTE66|OP_SSE, &i386_device::sse_movq_r128m64_r128, &i386_device::sse_movq_r128m64_r128, false}, + { 0xD7, OP_3BYTE66|OP_SSE, &i386_device::sse_pmovmskb_r32_r128, &i386_device::sse_pmovmskb_r32_r128, false}, + { 0xD8, OP_3BYTE66|OP_SSE, &i386_device::sse_psubusb_r128_rm128, &i386_device::sse_psubusb_r128_rm128, false}, + { 0xD9, OP_3BYTE66|OP_SSE, &i386_device::sse_psubusw_r128_rm128, &i386_device::sse_psubusw_r128_rm128, false}, + { 0xDA, OP_3BYTE66|OP_SSE, &i386_device::sse_pminub_r128_rm128, &i386_device::sse_pminub_r128_rm128, false}, + { 0xDB, OP_3BYTE66|OP_SSE, &i386_device::sse_pand_r128_rm128, &i386_device::sse_pand_r128_rm128, false}, + { 0xDC, OP_3BYTE66|OP_SSE, &i386_device::sse_paddusb_r128_rm128, &i386_device::sse_paddusb_r128_rm128, false}, + { 0xDD, OP_3BYTE66|OP_SSE, &i386_device::sse_paddusw_r128_rm128, &i386_device::sse_paddusw_r128_rm128, false}, + { 0xDE, OP_3BYTE66|OP_SSE, &i386_device::sse_pmaxub_r128_rm128, &i386_device::sse_pmaxub_r128_rm128, false}, + { 0xDF, OP_3BYTE66|OP_SSE, &i386_device::sse_pandn_r128_rm128, &i386_device::sse_pandn_r128_rm128, false}, + { 0xE0, OP_3BYTE66|OP_SSE, &i386_device::sse_pavgb_r128_rm128, &i386_device::sse_pavgb_r128_rm128, false}, + { 0xE1, OP_3BYTE66|OP_SSE, &i386_device::sse_psraw_r128_rm128, &i386_device::sse_psraw_r128_rm128, false}, + { 0xE2, OP_3BYTE66|OP_SSE, &i386_device::sse_psrad_r128_rm128, &i386_device::sse_psrad_r128_rm128, false}, + { 0xE3, OP_3BYTE66|OP_SSE, &i386_device::sse_pavgw_r128_rm128, &i386_device::sse_pavgw_r128_rm128, false}, + { 0xE4, OP_3BYTE66|OP_SSE, &i386_device::sse_pmulhuw_r128_rm128, &i386_device::sse_pmulhuw_r128_rm128, false}, + { 0xE5, OP_3BYTE66|OP_SSE, &i386_device::sse_pmulhw_r128_rm128, &i386_device::sse_pmulhw_r128_rm128, false}, + { 0xE6, OP_3BYTE66|OP_SSE, &i386_device::sse_cvttpd2dq_r128_rm128, &i386_device::sse_cvttpd2dq_r128_rm128,false}, + { 0xE7, OP_3BYTE66|OP_SSE, &i386_device::sse_movntdq_m128_r128, &i386_device::sse_movntdq_m128_r128, false}, + { 0xE8, OP_3BYTE66|OP_SSE, &i386_device::sse_psubsb_r128_rm128, &i386_device::sse_psubsb_r128_rm128, false}, + { 0xE9, OP_3BYTE66|OP_SSE, &i386_device::sse_psubsw_r128_rm128, &i386_device::sse_psubsw_r128_rm128, false}, + { 0xEA, OP_3BYTE66|OP_SSE, &i386_device::sse_pminsw_r128_rm128, &i386_device::sse_pminsw_r128_rm128, false}, + { 0xEB, OP_3BYTE66|OP_SSE, &i386_device::sse_por_r128_rm128, &i386_device::sse_por_r128_rm128, false}, + { 0xEC, OP_3BYTE66|OP_SSE, &i386_device::sse_paddsb_r128_rm128, &i386_device::sse_paddsb_r128_rm128, false}, + { 0xED, OP_3BYTE66|OP_SSE, &i386_device::sse_paddsw_r128_rm128, &i386_device::sse_paddsw_r128_rm128, false}, + { 0xEE, OP_3BYTE66|OP_SSE, &i386_device::sse_pmaxsw_r128_rm128, &i386_device::sse_pmaxsw_r128_rm128, false}, + { 0xEF, OP_3BYTE66|OP_SSE, &i386_device::sse_pxor_r128_rm128, &i386_device::sse_pxor_r128_rm128, false}, + { 0xF1, OP_3BYTE66|OP_SSE, &i386_device::sse_psllw_r128_rm128, &i386_device::sse_psllw_r128_rm128, false}, + { 0xF2, OP_3BYTE66|OP_SSE, &i386_device::sse_pslld_r128_rm128, &i386_device::sse_pslld_r128_rm128, false}, + { 0xF3, OP_3BYTE66|OP_SSE, &i386_device::sse_psllq_r128_rm128, &i386_device::sse_psllq_r128_rm128, false}, + { 0xF4, OP_3BYTE66|OP_SSE, &i386_device::sse_pmuludq_r128_rm128, &i386_device::sse_pmuludq_r128_rm128, false}, + { 0xF5, OP_3BYTE66|OP_SSE, &i386_device::sse_pmaddwd_r128_rm128, &i386_device::sse_pmaddwd_r128_rm128, false}, + { 0xF6, OP_3BYTE66|OP_SSE, &i386_device::sse_psadbw_r128_rm128, &i386_device::sse_psadbw_r128_rm128, false}, + { 0xF7, OP_3BYTE66|OP_SSE, &i386_device::sse_maskmovdqu_r128_r128, &i386_device::sse_maskmovdqu_r128_r128,false}, + { 0xF8, OP_3BYTE66|OP_SSE, &i386_device::sse_psubb_r128_rm128, &i386_device::sse_psubb_r128_rm128, false}, + { 0xF9, OP_3BYTE66|OP_SSE, &i386_device::sse_psubw_r128_rm128, &i386_device::sse_psubw_r128_rm128, false}, + { 0xFA, OP_3BYTE66|OP_SSE, &i386_device::sse_psubd_r128_rm128, &i386_device::sse_psubd_r128_rm128, false}, + { 0xFB, OP_3BYTE66|OP_SSE, &i386_device::sse_psubq_r128_rm128, &i386_device::sse_psubq_r128_rm128, false}, + { 0xFC, OP_3BYTE66|OP_SSE, &i386_device::sse_paddb_r128_rm128, &i386_device::sse_paddb_r128_rm128, false}, + { 0xFD, OP_3BYTE66|OP_SSE, &i386_device::sse_paddw_r128_rm128, &i386_device::sse_paddw_r128_rm128, false}, + { 0xFE, OP_3BYTE66|OP_SSE, &i386_device::sse_paddd_r128_rm128, &i386_device::sse_paddd_r128_rm128, false}, + /* 0F 38 ?? */ + { 0x00, OP_3BYTE38|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x01, OP_3BYTE38|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x02, OP_3BYTE38|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x03, OP_3BYTE38|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x04, OP_3BYTE38|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x05, OP_3BYTE38|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x06, OP_3BYTE38|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x07, OP_3BYTE38|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x08, OP_3BYTE38|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x09, OP_3BYTE38|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x0A, OP_3BYTE38|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x0B, OP_3BYTE38|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x1C, OP_3BYTE38|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x1D, OP_3BYTE38|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x1E, OP_3BYTE38|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0xF0, OP_3BYTE38|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0xF1, OP_3BYTE38|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0xF2, OP_3BYTE38|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0xF3, OP_3BYTE38|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0xF5, OP_3BYTE38|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0xF7, OP_3BYTE38|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + /* 0F 3A ?? */ + { 0x0F, OP_3BYTE3A|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + /* 66 0F 38 ?? */ + { 0x00, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x01, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x02, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x03, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x04, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x05, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x06, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x07, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x08, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x09, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x0A, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x0B, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x0C, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x0D, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x0E, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x0F, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x10, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x13, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x14, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x15, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x16, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x17, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x18, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x19, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x1A, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x1C, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x1D, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x1E, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x20, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x21, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x22, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x23, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x24, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x25, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x28, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x29, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x2A, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x2B, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x2C, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x2D, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x2E, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x2F, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x30, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x31, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x32, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x33, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x34, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x35, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x36, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x37, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x38, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x39, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x3A, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x3B, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x3C, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x3D, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x3E, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x3F, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x40, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x41, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x45, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x46, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x47, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x58, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x59, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x5A, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x78, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x79, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x80, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x81, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x82, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x8C, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x8E, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x90, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x91, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x92, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x93, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x96, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x97, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x98, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x99, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x9A, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x9B, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x9C, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x9D, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x9E, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x9F, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0xA6, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0xA7, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0xA8, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0xA9, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0xAA, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0xAB, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0xAC, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0xAD, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0xAE, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0xAF, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0xB6, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0xB7, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0xB8, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0xB9, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0xBA, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0xBB, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0xBC, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0xBD, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0xBE, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0xBF, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0xDB, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0xDC, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0xDD, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0xDE, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0xDF, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0xF0, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0xF1, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0xF3, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0xF6, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0xF7, OP_4BYTE3866|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + /* F2 0F 38 ?? */ + { 0xF0, OP_4BYTE38F2|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0xF1, OP_4BYTE38F2|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0xF3, OP_4BYTE38F2|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0xF5, OP_4BYTE38F2|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0xF6, OP_4BYTE38F2|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0xF7, OP_4BYTE38F2|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + /* F3 0F 38 ?? */ + { 0xF3, OP_4BYTE38F3|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0xF5, OP_4BYTE38F3|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0xF6, OP_4BYTE38F3|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0xF7, OP_4BYTE38F3|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + /* 66 0F 3A ?? */ + { 0x00, OP_4BYTE3A66|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x01, OP_4BYTE3A66|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x02, OP_4BYTE3A66|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x04, OP_4BYTE3A66|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x05, OP_4BYTE3A66|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x06, OP_4BYTE3A66|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x08, OP_4BYTE3A66|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x09, OP_4BYTE3A66|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x0A, OP_4BYTE3A66|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x0B, OP_4BYTE3A66|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x0C, OP_4BYTE3A66|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x0D, OP_4BYTE3A66|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x0E, OP_4BYTE3A66|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x0F, OP_4BYTE3A66|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x14, OP_4BYTE3A66|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x15, OP_4BYTE3A66|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x16, OP_4BYTE3A66|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x17, OP_4BYTE3A66|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x18, OP_4BYTE3A66|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x19, OP_4BYTE3A66|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x1D, OP_4BYTE3A66|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x20, OP_4BYTE3A66|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x21, OP_4BYTE3A66|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x22, OP_4BYTE3A66|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x38, OP_4BYTE3A66|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x39, OP_4BYTE3A66|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x40, OP_4BYTE3A66|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x41, OP_4BYTE3A66|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x42, OP_4BYTE3A66|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x44, OP_4BYTE3A66|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x46, OP_4BYTE3A66|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x4A, OP_4BYTE3A66|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x4B, OP_4BYTE3A66|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x4C, OP_4BYTE3A66|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x60, OP_4BYTE3A66|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x61, OP_4BYTE3A66|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x62, OP_4BYTE3A66|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0x63, OP_4BYTE3A66|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + { 0xDF, OP_4BYTE3A66|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false}, + /* F2 0F 3A ?? */ + { 0xF0, OP_4BYTE3AF2|OP_SSE, &i386_device::i386_invalid, &i386_device::i386_invalid, false} +}; diff --git a/src/devices/cpu/i386/i386ops.inc b/src/devices/cpu/i386/i386ops.inc new file mode 100644 index 00000000000..291c493233b --- /dev/null +++ b/src/devices/cpu/i386/i386ops.inc @@ -0,0 +1,2540 @@ +// license:BSD-3-Clause +// copyright-holders:Ville Linde, Barry Rodewald, Carl, Philip Bennett +UINT8 i386_device::i386_shift_rotate8(UINT8 modrm, UINT32 value, UINT8 shift) +{ + UINT32 src = value & 0xff; + UINT8 dst = value; + + if( shift == 0 ) { + CYCLES_RM(modrm, 3, 7); + } else if( shift == 1 ) { + switch( (modrm >> 3) & 0x7 ) + { + case 0: /* ROL rm8, 1 */ + m_CF = (src & 0x80) ? 1 : 0; + dst = (src << 1) + m_CF; + m_OF = ((src ^ dst) & 0x80) ? 1 : 0; + CYCLES_RM(modrm, CYCLES_ROTATE_REG, CYCLES_ROTATE_MEM); + break; + case 1: /* ROR rm8, 1 */ + m_CF = (src & 0x1) ? 1 : 0; + dst = (m_CF << 7) | (src >> 1); + m_OF = ((src ^ dst) & 0x80) ? 1 : 0; + CYCLES_RM(modrm, CYCLES_ROTATE_REG, CYCLES_ROTATE_MEM); + break; + case 2: /* RCL rm8, 1 */ + dst = (src << 1) + m_CF; + m_CF = (src & 0x80) ? 1 : 0; + m_OF = ((src ^ dst) & 0x80) ? 1 : 0; + CYCLES_RM(modrm, CYCLES_ROTATE_CARRY_REG, CYCLES_ROTATE_CARRY_MEM); + break; + case 3: /* RCR rm8, 1 */ + dst = (m_CF << 7) | (src >> 1); + m_CF = src & 0x1; + m_OF = ((src ^ dst) & 0x80) ? 1 : 0; + CYCLES_RM(modrm, CYCLES_ROTATE_CARRY_REG, CYCLES_ROTATE_CARRY_MEM); + break; + case 4: /* SHL/SAL rm8, 1 */ + case 6: + dst = src << 1; + m_CF = (src & 0x80) ? 1 : 0; + m_OF = (((m_CF << 7) ^ dst) & 0x80) ? 1 : 0; + SetSZPF8(dst); + CYCLES_RM(modrm, CYCLES_ROTATE_REG, CYCLES_ROTATE_MEM); + break; + case 5: /* SHR rm8, 1 */ + dst = src >> 1; + m_CF = src & 0x1; + m_OF = (dst & 0x80) ? 1 : 0; + SetSZPF8(dst); + CYCLES_RM(modrm, CYCLES_ROTATE_REG, CYCLES_ROTATE_MEM); + break; + case 7: /* SAR rm8, 1 */ + dst = (INT8)(src) >> 1; + m_CF = src & 0x1; + m_OF = 0; + SetSZPF8(dst); + CYCLES_RM(modrm, CYCLES_ROTATE_REG, CYCLES_ROTATE_MEM); + break; + } + + } else { + switch( (modrm >> 3) & 0x7 ) + { + case 0: /* ROL rm8, i8 */ + if(!(shift & 7)) + { + if(shift & 0x18) + { + m_CF = src & 1; + m_OF = (src & 1) ^ ((src >> 7) & 1); + } + break; + } + shift &= 7; + dst = ((src & ((UINT8)0xff >> shift)) << shift) | + ((src & ((UINT8)0xff << (8-shift))) >> (8-shift)); + m_CF = dst & 0x1; + m_OF = (dst & 1) ^ (dst >> 7); + CYCLES_RM(modrm, CYCLES_ROTATE_REG, CYCLES_ROTATE_MEM); + break; + case 1: /* ROR rm8, i8 */ + if(!(shift & 7)) + { + if(shift & 0x18) + { + m_CF = (src >> 7) & 1; + m_OF = ((src >> 7) & 1) ^ ((src >> 6) & 1); + } + break; + } + shift &= 7; + dst = ((src & ((UINT8)0xff << shift)) >> shift) | + ((src & ((UINT8)0xff >> (8-shift))) << (8-shift)); + m_CF = (dst >> 7) & 1; + m_OF = ((dst >> 7) ^ (dst >> 6)) & 1; + CYCLES_RM(modrm, CYCLES_ROTATE_REG, CYCLES_ROTATE_MEM); + break; + case 2: /* RCL rm8, i8 */ + shift %= 9; + dst = ((src & ((UINT8)0xff >> shift)) << shift) | + ((src & ((UINT8)0xff << (9-shift))) >> (9-shift)) | + (m_CF << (shift-1)); + if(shift) m_CF = (src >> (8-shift)) & 0x1; + m_OF = m_CF ^ ((dst >> 7) & 1); + CYCLES_RM(modrm, CYCLES_ROTATE_CARRY_REG, CYCLES_ROTATE_CARRY_MEM); + break; + case 3: /* RCR rm8, i8 */ + shift %= 9; + dst = ((src & ((UINT8)0xff << shift)) >> shift) | + ((src & ((UINT8)0xff >> (8-shift))) << (9-shift)) | + (m_CF << (8-shift)); + if(shift) m_CF = (src >> (shift-1)) & 0x1; + m_OF = ((dst >> 7) ^ (dst >> 6)) & 1; + CYCLES_RM(modrm, CYCLES_ROTATE_CARRY_REG, CYCLES_ROTATE_CARRY_MEM); + break; + case 4: /* SHL/SAL rm8, i8 */ + case 6: + shift &= 31; + dst = src << shift; + m_CF = (shift <= 8) && ((src >> (8 - shift)) & 1); + SetSZPF8(dst); + CYCLES_RM(modrm, CYCLES_ROTATE_REG, CYCLES_ROTATE_MEM); + break; + case 5: /* SHR rm8, i8 */ + shift &= 31; + dst = src >> shift; + m_CF = (src & (1 << (shift-1))) ? 1 : 0; + SetSZPF8(dst); + CYCLES_RM(modrm, CYCLES_ROTATE_REG, CYCLES_ROTATE_MEM); + break; + case 7: /* SAR rm8, i8 */ + shift &= 31; + dst = (INT8)src >> shift; + m_CF = (src & (1 << (shift-1))) ? 1 : 0; + SetSZPF8(dst); + CYCLES_RM(modrm, CYCLES_ROTATE_REG, CYCLES_ROTATE_MEM); + break; + } + } + + return dst; +} + + + +void i386_device::i386_adc_rm8_r8() // Opcode 0x10 +{ + UINT8 src, dst; + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + src = LOAD_REG8(modrm); + dst = LOAD_RM8(modrm); + dst = ADC8(dst, src, m_CF); + STORE_RM8(modrm, dst); + CYCLES(CYCLES_ALU_REG_REG); + } else { + UINT32 ea = GetEA(modrm,1); + src = LOAD_REG8(modrm); + dst = READ8(ea); + dst = ADC8(dst, src, m_CF); + WRITE8(ea, dst); + CYCLES(CYCLES_ALU_REG_MEM); + } +} + +void i386_device::i386_adc_r8_rm8() // Opcode 0x12 +{ + UINT8 src, dst; + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + src = LOAD_RM8(modrm); + dst = LOAD_REG8(modrm); + dst = ADC8(dst, src, m_CF); + STORE_REG8(modrm, dst); + CYCLES(CYCLES_ALU_REG_REG); + } else { + UINT32 ea = GetEA(modrm,0); + src = READ8(ea); + dst = LOAD_REG8(modrm); + dst = ADC8(dst, src, m_CF); + STORE_REG8(modrm, dst); + CYCLES(CYCLES_ALU_MEM_REG); + } +} + +void i386_device::i386_adc_al_i8() // Opcode 0x14 +{ + UINT8 src, dst; + src = FETCH(); + dst = REG8(AL); + dst = ADC8(dst, src, m_CF); + REG8(AL) = dst; + CYCLES(CYCLES_ALU_IMM_ACC); +} + +void i386_device::i386_add_rm8_r8() // Opcode 0x00 +{ + UINT8 src, dst; + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + src = LOAD_REG8(modrm); + dst = LOAD_RM8(modrm); + dst = ADD8(dst, src); + STORE_RM8(modrm, dst); + CYCLES(CYCLES_ALU_REG_REG); + } else { + UINT32 ea = GetEA(modrm,1); + src = LOAD_REG8(modrm); + dst = READ8(ea); + dst = ADD8(dst, src); + WRITE8(ea, dst); + CYCLES(CYCLES_ALU_REG_MEM); + } +} + +void i386_device::i386_add_r8_rm8() // Opcode 0x02 +{ + UINT8 src, dst; + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + src = LOAD_RM8(modrm); + dst = LOAD_REG8(modrm); + dst = ADD8(dst, src); + STORE_REG8(modrm, dst); + CYCLES(CYCLES_ALU_REG_REG); + } else { + UINT32 ea = GetEA(modrm,0); + src = READ8(ea); + dst = LOAD_REG8(modrm); + dst = ADD8(dst, src); + STORE_REG8(modrm, dst); + CYCLES(CYCLES_ALU_MEM_REG); + } +} + +void i386_device::i386_add_al_i8() // Opcode 0x04 +{ + UINT8 src, dst; + src = FETCH(); + dst = REG8(AL); + dst = ADD8(dst, src); + REG8(AL) = dst; + CYCLES(CYCLES_ALU_IMM_ACC); +} + +void i386_device::i386_and_rm8_r8() // Opcode 0x20 +{ + UINT8 src, dst; + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + src = LOAD_REG8(modrm); + dst = LOAD_RM8(modrm); + dst = AND8(dst, src); + STORE_RM8(modrm, dst); + CYCLES(CYCLES_ALU_REG_REG); + } else { + UINT32 ea = GetEA(modrm,1); + src = LOAD_REG8(modrm); + dst = READ8(ea); + dst = AND8(dst, src); + WRITE8(ea, dst); + CYCLES(CYCLES_ALU_REG_MEM); + } +} + +void i386_device::i386_and_r8_rm8() // Opcode 0x22 +{ + UINT8 src, dst; + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + src = LOAD_RM8(modrm); + dst = LOAD_REG8(modrm); + dst = AND8(dst, src); + STORE_REG8(modrm, dst); + CYCLES(CYCLES_ALU_REG_REG); + } else { + UINT32 ea = GetEA(modrm,0); + src = READ8(ea); + dst = LOAD_REG8(modrm); + dst = AND8(dst, src); + STORE_REG8(modrm, dst); + CYCLES(CYCLES_ALU_MEM_REG); + } +} + +void i386_device::i386_and_al_i8() // Opcode 0x24 +{ + UINT8 src, dst; + src = FETCH(); + dst = REG8(AL); + dst = AND8(dst, src); + REG8(AL) = dst; + CYCLES(CYCLES_ALU_IMM_ACC); +} + +void i386_device::i386_clc() // Opcode 0xf8 +{ + m_CF = 0; + CYCLES(CYCLES_CLC); +} + +void i386_device::i386_cld() // Opcode 0xfc +{ + m_DF = 0; + CYCLES(CYCLES_CLD); +} + +void i386_device::i386_cli() // Opcode 0xfa +{ + if(PROTECTED_MODE) + { + UINT8 IOPL = m_IOP1 | (m_IOP2 << 1); + if(m_CPL > IOPL) + FAULT(FAULT_GP,0); + } + m_IF = 0; + CYCLES(CYCLES_CLI); +} + +void i386_device::i386_cmc() // Opcode 0xf5 +{ + m_CF ^= 1; + CYCLES(CYCLES_CMC); +} + +void i386_device::i386_cmp_rm8_r8() // Opcode 0x38 +{ + UINT8 src, dst; + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + src = LOAD_REG8(modrm); + dst = LOAD_RM8(modrm); + SUB8(dst, src); + CYCLES(CYCLES_CMP_REG_REG); + } else { + UINT32 ea = GetEA(modrm,0); + src = LOAD_REG8(modrm); + dst = READ8(ea); + SUB8(dst, src); + CYCLES(CYCLES_CMP_REG_MEM); + } +} + +void i386_device::i386_cmp_r8_rm8() // Opcode 0x3a +{ + UINT8 src, dst; + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + src = LOAD_RM8(modrm); + dst = LOAD_REG8(modrm); + SUB8(dst, src); + CYCLES(CYCLES_CMP_REG_REG); + } else { + UINT32 ea = GetEA(modrm,0); + src = READ8(ea); + dst = LOAD_REG8(modrm); + SUB8(dst, src); + CYCLES(CYCLES_CMP_MEM_REG); + } +} + +void i386_device::i386_cmp_al_i8() // Opcode 0x3c +{ + UINT8 src, dst; + src = FETCH(); + dst = REG8(AL); + SUB8(dst, src); + CYCLES(CYCLES_CMP_IMM_ACC); +} + +void i386_device::i386_cmpsb() // Opcode 0xa6 +{ + UINT32 eas, ead; + UINT8 src, dst; + if( m_segment_prefix ) { + eas = i386_translate(m_segment_override, m_address_size ? REG32(ESI) : REG16(SI), 0 ); + } else { + eas = i386_translate(DS, m_address_size ? REG32(ESI) : REG16(SI), 0 ); + } + ead = i386_translate(ES, m_address_size ? REG32(EDI) : REG16(DI), 0 ); + src = READ8(eas); + dst = READ8(ead); + SUB8(src, dst); + BUMP_SI(1); + BUMP_DI(1); + CYCLES(CYCLES_CMPS); +} + +void i386_device::i386_in_al_i8() // Opcode 0xe4 +{ + UINT16 port = FETCH(); + UINT8 data = READPORT8(port); + REG8(AL) = data; + CYCLES(CYCLES_IN_VAR); +} + +void i386_device::i386_in_al_dx() // Opcode 0xec +{ + UINT16 port = REG16(DX); + UINT8 data = READPORT8(port); + REG8(AL) = data; + CYCLES(CYCLES_IN); +} + +void i386_device::i386_ja_rel8() // Opcode 0x77 +{ + INT8 disp = FETCH(); + if( m_CF == 0 && m_ZF == 0 ) { + NEAR_BRANCH(disp); + CYCLES(CYCLES_JCC_DISP8); /* TODO: Timing = 7 + m */ + } else { + CYCLES(CYCLES_JCC_DISP8_NOBRANCH); + } +} + +void i386_device::i386_jbe_rel8() // Opcode 0x76 +{ + INT8 disp = FETCH(); + if( m_CF != 0 || m_ZF != 0 ) { + NEAR_BRANCH(disp); + CYCLES(CYCLES_JCC_DISP8); /* TODO: Timing = 7 + m */ + } else { + CYCLES(CYCLES_JCC_DISP8_NOBRANCH); + } +} + +void i386_device::i386_jc_rel8() // Opcode 0x72 +{ + INT8 disp = FETCH(); + if( m_CF != 0 ) { + NEAR_BRANCH(disp); + CYCLES(CYCLES_JCC_DISP8); /* TODO: Timing = 7 + m */ + } else { + CYCLES(CYCLES_JCC_DISP8_NOBRANCH); + } +} + +void i386_device::i386_jg_rel8() // Opcode 0x7f +{ + INT8 disp = FETCH(); + if( m_ZF == 0 && (m_SF == m_OF) ) { + NEAR_BRANCH(disp); + CYCLES(CYCLES_JCC_DISP8); /* TODO: Timing = 7 + m */ + } else { + CYCLES(CYCLES_JCC_DISP8_NOBRANCH); + } +} + +void i386_device::i386_jge_rel8() // Opcode 0x7d +{ + INT8 disp = FETCH(); + if(m_SF == m_OF) { + NEAR_BRANCH(disp); + CYCLES(CYCLES_JCC_DISP8); /* TODO: Timing = 7 + m */ + } else { + CYCLES(CYCLES_JCC_DISP8_NOBRANCH); + } +} + +void i386_device::i386_jl_rel8() // Opcode 0x7c +{ + INT8 disp = FETCH(); + if( (m_SF != m_OF) ) { + NEAR_BRANCH(disp); + CYCLES(CYCLES_JCC_DISP8); /* TODO: Timing = 7 + m */ + } else { + CYCLES(CYCLES_JCC_DISP8_NOBRANCH); + } +} + +void i386_device::i386_jle_rel8() // Opcode 0x7e +{ + INT8 disp = FETCH(); + if( m_ZF != 0 || (m_SF != m_OF) ) { + NEAR_BRANCH(disp); + CYCLES(CYCLES_JCC_DISP8); /* TODO: Timing = 7 + m */ + } else { + CYCLES(CYCLES_JCC_DISP8_NOBRANCH); + } +} + +void i386_device::i386_jnc_rel8() // Opcode 0x73 +{ + INT8 disp = FETCH(); + if( m_CF == 0 ) { + NEAR_BRANCH(disp); + CYCLES(CYCLES_JCC_DISP8); /* TODO: Timing = 7 + m */ + } else { + CYCLES(CYCLES_JCC_DISP8_NOBRANCH); + } +} + +void i386_device::i386_jno_rel8() // Opcode 0x71 +{ + INT8 disp = FETCH(); + if( m_OF == 0 ) { + NEAR_BRANCH(disp); + CYCLES(CYCLES_JCC_DISP8); /* TODO: Timing = 7 + m */ + } else { + CYCLES(CYCLES_JCC_DISP8_NOBRANCH); + } +} + +void i386_device::i386_jnp_rel8() // Opcode 0x7b +{ + INT8 disp = FETCH(); + if( m_PF == 0 ) { + NEAR_BRANCH(disp); + CYCLES(CYCLES_JCC_DISP8); /* TODO: Timing = 7 + m */ + } else { + CYCLES(CYCLES_JCC_DISP8_NOBRANCH); + } +} + +void i386_device::i386_jns_rel8() // Opcode 0x79 +{ + INT8 disp = FETCH(); + if( m_SF == 0 ) { + NEAR_BRANCH(disp); + CYCLES(CYCLES_JCC_DISP8); /* TODO: Timing = 7 + m */ + } else { + CYCLES(CYCLES_JCC_DISP8_NOBRANCH); + } +} + +void i386_device::i386_jnz_rel8() // Opcode 0x75 +{ + INT8 disp = FETCH(); + if( m_ZF == 0 ) { + NEAR_BRANCH(disp); + CYCLES(CYCLES_JCC_DISP8); /* TODO: Timing = 7 + m */ + } else { + CYCLES(CYCLES_JCC_DISP8_NOBRANCH); + } +} + +void i386_device::i386_jo_rel8() // Opcode 0x70 +{ + INT8 disp = FETCH(); + if( m_OF != 0 ) { + NEAR_BRANCH(disp); + CYCLES(CYCLES_JCC_DISP8); /* TODO: Timing = 7 + m */ + } else { + CYCLES(CYCLES_JCC_DISP8_NOBRANCH); + } +} + +void i386_device::i386_jp_rel8() // Opcode 0x7a +{ + INT8 disp = FETCH(); + if( m_PF != 0 ) { + NEAR_BRANCH(disp); + CYCLES(CYCLES_JCC_DISP8); /* TODO: Timing = 7 + m */ + } else { + CYCLES(CYCLES_JCC_DISP8_NOBRANCH); + } +} + +void i386_device::i386_js_rel8() // Opcode 0x78 +{ + INT8 disp = FETCH(); + if( m_SF != 0 ) { + NEAR_BRANCH(disp); + CYCLES(CYCLES_JCC_DISP8); /* TODO: Timing = 7 + m */ + } else { + CYCLES(CYCLES_JCC_DISP8_NOBRANCH); + } +} + +void i386_device::i386_jz_rel8() // Opcode 0x74 +{ + INT8 disp = FETCH(); + if( m_ZF != 0 ) { + NEAR_BRANCH(disp); + CYCLES(CYCLES_JCC_DISP8); /* TODO: Timing = 7 + m */ + } else { + CYCLES(CYCLES_JCC_DISP8_NOBRANCH); + } +} + +void i386_device::i386_jmp_rel8() // Opcode 0xeb +{ + INT8 disp = FETCH(); + NEAR_BRANCH(disp); + CYCLES(CYCLES_JMP_SHORT); /* TODO: Timing = 7 + m */ +} + +void i386_device::i386_lahf() // Opcode 0x9f +{ + REG8(AH) = get_flags() & 0xd7; + CYCLES(CYCLES_LAHF); +} + +void i386_device::i386_lodsb() // Opcode 0xac +{ + UINT32 eas; + if( m_segment_prefix ) { + eas = i386_translate(m_segment_override, m_address_size ? REG32(ESI) : REG16(SI), 0 ); + } else { + eas = i386_translate(DS, m_address_size ? REG32(ESI) : REG16(SI), 0 ); + } + REG8(AL) = READ8(eas); + BUMP_SI(1); + CYCLES(CYCLES_LODS); +} + +void i386_device::i386_mov_rm8_r8() // Opcode 0x88 +{ + UINT8 src; + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + src = LOAD_REG8(modrm); + STORE_RM8(modrm, src); + CYCLES(CYCLES_MOV_REG_REG); + } else { + UINT32 ea = GetEA(modrm,1); + src = LOAD_REG8(modrm); + WRITE8(ea, src); + CYCLES(CYCLES_MOV_REG_MEM); + } +} + +void i386_device::i386_mov_r8_rm8() // Opcode 0x8a +{ + UINT8 src; + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + src = LOAD_RM8(modrm); + STORE_REG8(modrm, src); + CYCLES(CYCLES_MOV_REG_REG); + } else { + UINT32 ea = GetEA(modrm,0); + src = READ8(ea); + STORE_REG8(modrm, src); + CYCLES(CYCLES_MOV_MEM_REG); + } +} + +void i386_device::i386_mov_rm8_i8() // Opcode 0xc6 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + UINT8 value = FETCH(); + STORE_RM8(modrm, value); + CYCLES(CYCLES_MOV_IMM_REG); + } else { + UINT32 ea = GetEA(modrm,1); + UINT8 value = FETCH(); + WRITE8(ea, value); + CYCLES(CYCLES_MOV_IMM_MEM); + } +} + +void i386_device::i386_mov_r32_cr() // Opcode 0x0f 20 +{ + if(PROTECTED_MODE && m_CPL) + FAULT(FAULT_GP, 0); + UINT8 modrm = FETCH(); + UINT8 cr = (modrm >> 3) & 0x7; + + STORE_RM32(modrm, m_cr[cr]); + CYCLES(CYCLES_MOV_CR_REG); +} + +void i386_device::i386_mov_r32_dr() // Opcode 0x0f 21 +{ + if(PROTECTED_MODE && m_CPL) + FAULT(FAULT_GP, 0); + UINT8 modrm = FETCH(); + UINT8 dr = (modrm >> 3) & 0x7; + + STORE_RM32(modrm, m_dr[dr]); + switch(dr) + { + case 0: + case 1: + case 2: + case 3: + CYCLES(CYCLES_MOV_REG_DR0_3); + break; + case 6: + case 7: + CYCLES(CYCLES_MOV_REG_DR6_7); + break; + } +} + +void i386_device::i386_mov_cr_r32() // Opcode 0x0f 22 +{ + if(PROTECTED_MODE && m_CPL) + FAULT(FAULT_GP, 0); + UINT8 modrm = FETCH(); + UINT8 cr = (modrm >> 3) & 0x7; + UINT32 data = LOAD_RM32(modrm); + switch(cr) + { + case 0: + data &= 0xfffeffff; // wp not supported on 386 + CYCLES(CYCLES_MOV_REG_CR0); + break; + case 2: CYCLES(CYCLES_MOV_REG_CR2); break; + case 3: + CYCLES(CYCLES_MOV_REG_CR3); + vtlb_flush_dynamic(m_vtlb); + break; + case 4: CYCLES(1); break; // TODO + default: + logerror("i386: mov_cr_r32 CR%d!\n", cr); + return; + } + m_cr[cr] = data; +} + +void i386_device::i386_mov_dr_r32() // Opcode 0x0f 23 +{ + if(PROTECTED_MODE && m_CPL) + FAULT(FAULT_GP, 0); + UINT8 modrm = FETCH(); + UINT8 dr = (modrm >> 3) & 0x7; + + m_dr[dr] = LOAD_RM32(modrm); + switch(dr) + { + case 0: + case 1: + case 2: + case 3: + CYCLES(CYCLES_MOV_DR0_3_REG); + break; + case 6: + case 7: + CYCLES(CYCLES_MOV_DR6_7_REG); + break; + default: + logerror("i386: mov_dr_r32 DR%d!\n", dr); + return; + } +} + +void i386_device::i386_mov_al_m8() // Opcode 0xa0 +{ + UINT32 offset, ea; + if( m_address_size ) { + offset = FETCH32(); + } else { + offset = FETCH16(); + } + /* TODO: Not sure if this is correct... */ + if( m_segment_prefix ) { + ea = i386_translate(m_segment_override, offset, 0 ); + } else { + ea = i386_translate(DS, offset, 0 ); + } + REG8(AL) = READ8(ea); + CYCLES(CYCLES_MOV_IMM_MEM); +} + +void i386_device::i386_mov_m8_al() // Opcode 0xa2 +{ + UINT32 offset, ea; + if( m_address_size ) { + offset = FETCH32(); + } else { + offset = FETCH16(); + } + /* TODO: Not sure if this is correct... */ + if( m_segment_prefix ) { + ea = i386_translate(m_segment_override, offset, 1 ); + } else { + ea = i386_translate(DS, offset, 1 ); + } + WRITE8(ea, REG8(AL) ); + CYCLES(CYCLES_MOV_MEM_ACC); +} + +void i386_device::i386_mov_rm16_sreg() // Opcode 0x8c +{ + UINT8 modrm = FETCH(); + int s = (modrm >> 3) & 0x7; + + if( modrm >= 0xc0 ) { + if(m_operand_size) + STORE_RM32(modrm, m_sreg[s].selector); + else + STORE_RM16(modrm, m_sreg[s].selector); + CYCLES(CYCLES_MOV_SREG_REG); + } else { + UINT32 ea = GetEA(modrm,1); + WRITE16(ea, m_sreg[s].selector); + CYCLES(CYCLES_MOV_SREG_MEM); + } +} + +void i386_device::i386_mov_sreg_rm16() // Opcode 0x8e +{ + UINT16 selector; + UINT8 modrm = FETCH(); + bool fault; + int s = (modrm >> 3) & 0x7; + + if( modrm >= 0xc0 ) { + selector = LOAD_RM16(modrm); + CYCLES(CYCLES_MOV_REG_SREG); + } else { + UINT32 ea = GetEA(modrm,0); + selector = READ16(ea); + CYCLES(CYCLES_MOV_MEM_SREG); + } + + i386_sreg_load(selector,s,&fault); + if((s == SS) && !fault) + { + if(m_IF != 0) // if external interrupts are enabled + { + m_IF = 0; // reset IF for the next instruction + m_delayed_interrupt_enable = 1; + } + } +} + +void i386_device::i386_mov_al_i8() // Opcode 0xb0 +{ + REG8(AL) = FETCH(); + CYCLES(CYCLES_MOV_IMM_REG); +} + +void i386_device::i386_mov_cl_i8() // Opcode 0xb1 +{ + REG8(CL) = FETCH(); + CYCLES(CYCLES_MOV_IMM_REG); +} + +void i386_device::i386_mov_dl_i8() // Opcode 0xb2 +{ + REG8(DL) = FETCH(); + CYCLES(CYCLES_MOV_IMM_REG); +} + +void i386_device::i386_mov_bl_i8() // Opcode 0xb3 +{ + REG8(BL) = FETCH(); + CYCLES(CYCLES_MOV_IMM_REG); +} + +void i386_device::i386_mov_ah_i8() // Opcode 0xb4 +{ + REG8(AH) = FETCH(); + CYCLES(CYCLES_MOV_IMM_REG); +} + +void i386_device::i386_mov_ch_i8() // Opcode 0xb5 +{ + REG8(CH) = FETCH(); + CYCLES(CYCLES_MOV_IMM_REG); +} + +void i386_device::i386_mov_dh_i8() // Opcode 0xb6 +{ + REG8(DH) = FETCH(); + CYCLES(CYCLES_MOV_IMM_REG); +} + +void i386_device::i386_mov_bh_i8() // Opcode 0xb7 +{ + REG8(BH) = FETCH(); + CYCLES(CYCLES_MOV_IMM_REG); +} + +void i386_device::i386_movsb() // Opcode 0xa4 +{ + UINT32 eas, ead; + UINT8 v; + if( m_segment_prefix ) { + eas = i386_translate(m_segment_override, m_address_size ? REG32(ESI) : REG16(SI), 0 ); + } else { + eas = i386_translate(DS, m_address_size ? REG32(ESI) : REG16(SI), 0 ); + } + ead = i386_translate(ES, m_address_size ? REG32(EDI) : REG16(DI), 1 ); + v = READ8(eas); + WRITE8(ead, v); + BUMP_SI(1); + BUMP_DI(1); + CYCLES(CYCLES_MOVS); +} + +void i386_device::i386_or_rm8_r8() // Opcode 0x08 +{ + UINT8 src, dst; + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + src = LOAD_REG8(modrm); + dst = LOAD_RM8(modrm); + dst = OR8(dst, src); + STORE_RM8(modrm, dst); + CYCLES(CYCLES_ALU_REG_REG); + } else { + UINT32 ea = GetEA(modrm,1); + src = LOAD_REG8(modrm); + dst = READ8(ea); + dst = OR8(dst, src); + WRITE8(ea, dst); + CYCLES(CYCLES_ALU_REG_MEM); + } +} + +void i386_device::i386_or_r8_rm8() // Opcode 0x0a +{ + UINT8 src, dst; + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + src = LOAD_RM8(modrm); + dst = LOAD_REG8(modrm); + dst = OR8(dst, src); + STORE_REG8(modrm, dst); + CYCLES(CYCLES_ALU_REG_REG); + } else { + UINT32 ea = GetEA(modrm,0); + src = READ8(ea); + dst = LOAD_REG8(modrm); + dst = OR8(dst, src); + STORE_REG8(modrm, dst); + CYCLES(CYCLES_ALU_MEM_REG); + } +} + +void i386_device::i386_or_al_i8() // Opcode 0x0c +{ + UINT8 src, dst; + src = FETCH(); + dst = REG8(AL); + dst = OR8(dst, src); + REG8(EAX) = dst; + CYCLES(CYCLES_ALU_IMM_ACC); +} + +void i386_device::i386_out_al_i8() // Opcode 0xe6 +{ + UINT16 port = FETCH(); + UINT8 data = REG8(AL); + WRITEPORT8(port, data); + CYCLES(CYCLES_OUT_VAR); +} + +void i386_device::i386_out_al_dx() // Opcode 0xee +{ + UINT16 port = REG16(DX); + UINT8 data = REG8(AL); + WRITEPORT8(port, data); + CYCLES(CYCLES_OUT); +} + + +void i386_device::i386_arpl() // Opcode 0x63 +{ + UINT16 src, dst; + UINT8 modrm = FETCH(); + UINT8 flag = 0; + + if(PROTECTED_MODE && !V8086_MODE) + { + if( modrm >= 0xc0 ) { + src = LOAD_REG16(modrm); + dst = LOAD_RM16(modrm); + if( (dst&0x3) < (src&0x3) ) { + dst = (dst&0xfffc) | (src&0x3); + flag = 1; + STORE_RM16(modrm, dst); + } + } else { + UINT32 ea = GetEA(modrm,1); + src = LOAD_REG16(modrm); + dst = READ16(ea); + if( (dst&0x3) < (src&0x3) ) { + dst = (dst&0xfffc) | (src&0x3); + flag = 1; + WRITE16(ea, dst); + } + } + SetZF(flag); + } + else + i386_trap(6, 0, 0); // invalid opcode in real mode or v8086 mode +} + +void i386_device::i386_push_i8() // Opcode 0x6a +{ + UINT8 value = FETCH(); + PUSH8(value); + CYCLES(CYCLES_PUSH_IMM); +} + +void i386_device::i386_ins_generic(int size) +{ + UINT32 ead; + UINT8 vb; + UINT16 vw; + UINT32 vd; + + ead = i386_translate(ES, m_address_size ? REG32(EDI) : REG16(DI), 1 ); + + switch(size) { + case 1: + vb = READPORT8(REG16(DX)); + WRITE8(ead, vb); + break; + case 2: + vw = READPORT16(REG16(DX)); + WRITE16(ead, vw); + break; + case 4: + vd = READPORT32(REG16(DX)); + WRITE32(ead, vd); + break; + } + + if(m_address_size) + REG32(EDI) += ((m_DF) ? -1 : 1) * size; + else + REG16(DI) += ((m_DF) ? -1 : 1) * size; + CYCLES(CYCLES_INS); // TODO: Confirm this value +} + +void i386_device::i386_insb() // Opcode 0x6c +{ + i386_ins_generic(1); +} + +void i386_device::i386_insw() // Opcode 0x6d +{ + i386_ins_generic(2); +} + +void i386_device::i386_insd() // Opcode 0x6d +{ + i386_ins_generic(4); +} + +void i386_device::i386_outs_generic(int size) +{ + UINT32 eas; + UINT8 vb; + UINT16 vw; + UINT32 vd; + + if( m_segment_prefix ) { + eas = i386_translate(m_segment_override, m_address_size ? REG32(ESI) : REG16(SI), 0 ); + } else { + eas = i386_translate(DS, m_address_size ? REG32(ESI) : REG16(SI), 0 ); + } + + switch(size) { + case 1: + vb = READ8(eas); + WRITEPORT8(REG16(DX), vb); + break; + case 2: + vw = READ16(eas); + WRITEPORT16(REG16(DX), vw); + break; + case 4: + vd = READ32(eas); + WRITEPORT32(REG16(DX), vd); + break; + } + + if(m_address_size) + REG32(ESI) += ((m_DF) ? -1 : 1) * size; + else + REG16(SI) += ((m_DF) ? -1 : 1) * size; + CYCLES(CYCLES_OUTS); // TODO: Confirm this value +} + +void i386_device::i386_outsb() // Opcode 0x6e +{ + i386_outs_generic(1); +} + +void i386_device::i386_outsw() // Opcode 0x6f +{ + i386_outs_generic(2); +} + +void i386_device::i386_outsd() // Opcode 0x6f +{ + i386_outs_generic(4); +} + +void i386_device::i386_repeat(int invert_flag) +{ + UINT32 repeated_eip = m_eip; + UINT32 repeated_pc = m_pc; + UINT8 opcode; // = FETCH(); +// UINT32 eas, ead; + UINT32 count; + INT32 cycle_base = 0, cycle_adjustment = 0; + UINT8 prefix_flag=1; + UINT8 *flag = NULL; + + + do { + repeated_eip = m_eip; + repeated_pc = m_pc; + opcode = FETCH(); + switch(opcode) { + case 0x0f: + if (invert_flag == 0) + i386_decode_three_bytef3(); // sse f3 0f + else + i386_decode_three_bytef2(); // sse f2 0f + return; + case 0x26: + m_segment_override=ES; + m_segment_prefix=1; + break; + case 0x2e: + m_segment_override=CS; + m_segment_prefix=1; + break; + case 0x36: + m_segment_override=SS; + m_segment_prefix=1; + break; + case 0x3e: + m_segment_override=DS; + m_segment_prefix=1; + break; + case 0x64: + m_segment_override=FS; + m_segment_prefix=1; + break; + case 0x65: + m_segment_override=GS; + m_segment_prefix=1; + break; + case 0x66: + m_operand_size ^= 1; + m_xmm_operand_size ^= 1; + break; + case 0x67: + m_address_size ^= 1; + break; + default: + prefix_flag=0; + } + } while (prefix_flag); + + + if( m_segment_prefix ) { + // FIXME: the following does not work if both address override and segment override are used + i386_translate(m_segment_override, m_sreg[m_segment_prefix].d ? REG32(ESI) : REG16(SI), -1 ); + } else { + //eas = + i386_translate(DS, m_address_size ? REG32(ESI) : REG16(SI), -1 ); + } + i386_translate(ES, m_address_size ? REG32(EDI) : REG16(DI), -1 ); + + switch(opcode) + { + case 0x6c: + case 0x6d: + /* INSB, INSW, INSD */ + // TODO: cycle count + cycle_base = 8; + cycle_adjustment = -4; + flag = NULL; + break; + + case 0x6e: + case 0x6f: + /* OUTSB, OUTSW, OUTSD */ + // TODO: cycle count + cycle_base = 8; + cycle_adjustment = -4; + flag = NULL; + break; + + case 0xa4: + case 0xa5: + /* MOVSB, MOVSW, MOVSD */ + cycle_base = 8; + cycle_adjustment = -4; + flag = NULL; + break; + + case 0xa6: + case 0xa7: + /* CMPSB, CMPSW, CMPSD */ + cycle_base = 5; + cycle_adjustment = -1; + flag = &m_ZF; + break; + + case 0xac: + case 0xad: + /* LODSB, LODSW, LODSD */ + cycle_base = 5; + cycle_adjustment = 1; + flag = NULL; + break; + + case 0xaa: + case 0xab: + /* STOSB, STOSW, STOSD */ + cycle_base = 5; + cycle_adjustment = 0; + flag = NULL; + break; + + case 0xae: + case 0xaf: + /* SCASB, SCASW, SCASD */ + cycle_base = 5; + cycle_adjustment = 0; + flag = &m_ZF; + break; + + case 0x90: + CYCLES(CYCLES_NOP); + return; + + case 0xc2: // sigh + case 0xc3: + m_pc--; + return; + + default: + fatalerror("i386: Invalid REP/opcode %02X combination\n",opcode); + break; + } + + if( m_address_size ) { + if( REG32(ECX) == 0 ) + return; + } else { + if( REG16(CX) == 0 ) + return; + } + + /* now actually perform the repeat */ + CYCLES_NUM(cycle_base); + do + { + m_eip = repeated_eip; + m_pc = repeated_pc; + try + { + i386_decode_opcode(); + } + catch (UINT64 e) + { + m_eip = m_prev_eip; + throw e; + } + + CYCLES_NUM(cycle_adjustment); + + if (m_address_size) + count = --REG32(ECX); + else + count = --REG16(CX); + if (m_cycles <= 0) + goto outofcycles; + } + while( count && (!flag || (invert_flag ? !*flag : *flag)) ); + return; + +outofcycles: + /* if we run out of cycles to execute, and we are still in the repeat, we need + * to exit this instruction in such a way to go right back into it when we have + * time to execute cycles */ + if(flag && (invert_flag ? *flag : !*flag)) + return; + m_eip = m_prev_eip; + CHANGE_PC(m_eip); + CYCLES_NUM(-cycle_base); +} + +void i386_device::i386_rep() // Opcode 0xf3 +{ + i386_repeat(0); +} + +void i386_device::i386_repne() // Opcode 0xf2 +{ + i386_repeat(1); +} + +void i386_device::i386_sahf() // Opcode 0x9e +{ + set_flags((get_flags() & 0xffffff00) | (REG8(AH) & 0xd7) ); + CYCLES(CYCLES_SAHF); +} + +void i386_device::i386_sbb_rm8_r8() // Opcode 0x18 +{ + UINT8 src, dst; + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + src = LOAD_REG8(modrm); + dst = LOAD_RM8(modrm); + dst = SBB8(dst, src, m_CF); + STORE_RM8(modrm, dst); + CYCLES(CYCLES_ALU_REG_REG); + } else { + UINT32 ea = GetEA(modrm,1); + src = LOAD_REG8(modrm); + dst = READ8(ea); + dst = SBB8(dst, src, m_CF); + WRITE8(ea, dst); + CYCLES(CYCLES_ALU_REG_MEM); + } +} + +void i386_device::i386_sbb_r8_rm8() // Opcode 0x1a +{ + UINT8 src, dst; + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + src = LOAD_RM8(modrm); + dst = LOAD_REG8(modrm); + dst = SBB8(dst, src, m_CF); + STORE_REG8(modrm, dst); + CYCLES(CYCLES_ALU_REG_REG); + } else { + UINT32 ea = GetEA(modrm,0); + src = READ8(ea); + dst = LOAD_REG8(modrm); + dst = SBB8(dst, src, m_CF); + STORE_REG8(modrm, dst); + CYCLES(CYCLES_ALU_MEM_REG); + } +} + +void i386_device::i386_sbb_al_i8() // Opcode 0x1c +{ + UINT8 src, dst; + src = FETCH(); + dst = REG8(AL); + dst = SBB8(dst, src, m_CF); + REG8(EAX) = dst; + CYCLES(CYCLES_ALU_IMM_ACC); +} + +void i386_device::i386_scasb() // Opcode 0xae +{ + UINT32 eas; + UINT8 src, dst; + eas = i386_translate(ES, m_address_size ? REG32(EDI) : REG16(DI), 0 ); + src = READ8(eas); + dst = REG8(AL); + SUB8(dst, src); + BUMP_DI(1); + CYCLES(CYCLES_SCAS); +} + +void i386_device::i386_setalc() // Opcode 0xd6 (undocumented) +{ + if( m_CF ) { + REG8(AL) = 0xff; + } else { + REG8(AL) = 0; + } + CYCLES(3); +} + +void i386_device::i386_seta_rm8() // Opcode 0x0f 97 +{ + UINT8 modrm = FETCH(); + UINT8 value = 0; + if( m_CF == 0 && m_ZF == 0 ) { + value = 1; + } + if( modrm >= 0xc0 ) { + STORE_RM8(modrm, value); + CYCLES(CYCLES_SETCC_REG); + } else { + UINT32 ea = GetEA(modrm,1); + WRITE8(ea, value); + CYCLES(CYCLES_SETCC_MEM); + } +} + +void i386_device::i386_setbe_rm8() // Opcode 0x0f 96 +{ + UINT8 modrm = FETCH(); + UINT8 value = 0; + if( m_CF != 0 || m_ZF != 0 ) { + value = 1; + } + if( modrm >= 0xc0 ) { + STORE_RM8(modrm, value); + CYCLES(CYCLES_SETCC_REG); + } else { + UINT32 ea = GetEA(modrm,1); + WRITE8(ea, value); + CYCLES(CYCLES_SETCC_MEM); + } +} + +void i386_device::i386_setc_rm8() // Opcode 0x0f 92 +{ + UINT8 modrm = FETCH(); + UINT8 value = 0; + if( m_CF != 0 ) { + value = 1; + } + if( modrm >= 0xc0 ) { + STORE_RM8(modrm, value); + CYCLES(CYCLES_SETCC_REG); + } else { + UINT32 ea = GetEA(modrm,1); + WRITE8(ea, value); + CYCLES(CYCLES_SETCC_MEM); + } +} + +void i386_device::i386_setg_rm8() // Opcode 0x0f 9f +{ + UINT8 modrm = FETCH(); + UINT8 value = 0; + if( m_ZF == 0 && (m_SF == m_OF) ) { + value = 1; + } + if( modrm >= 0xc0 ) { + STORE_RM8(modrm, value); + CYCLES(CYCLES_SETCC_REG); + } else { + UINT32 ea = GetEA(modrm,1); + WRITE8(ea, value); + CYCLES(CYCLES_SETCC_MEM); + } +} + +void i386_device::i386_setge_rm8() // Opcode 0x0f 9d +{ + UINT8 modrm = FETCH(); + UINT8 value = 0; + if(m_SF == m_OF) { + value = 1; + } + if( modrm >= 0xc0 ) { + STORE_RM8(modrm, value); + CYCLES(CYCLES_SETCC_REG); + } else { + UINT32 ea = GetEA(modrm,1); + WRITE8(ea, value); + CYCLES(CYCLES_SETCC_MEM); + } +} + +void i386_device::i386_setl_rm8() // Opcode 0x0f 9c +{ + UINT8 modrm = FETCH(); + UINT8 value = 0; + if( m_SF != m_OF ) { + value = 1; + } + if( modrm >= 0xc0 ) { + STORE_RM8(modrm, value); + CYCLES(CYCLES_SETCC_REG); + } else { + UINT32 ea = GetEA(modrm,1); + WRITE8(ea, value); + CYCLES(CYCLES_SETCC_MEM); + } +} + +void i386_device::i386_setle_rm8() // Opcode 0x0f 9e +{ + UINT8 modrm = FETCH(); + UINT8 value = 0; + if( m_ZF != 0 || (m_SF != m_OF) ) { + value = 1; + } + if( modrm >= 0xc0 ) { + STORE_RM8(modrm, value); + CYCLES(CYCLES_SETCC_REG); + } else { + UINT32 ea = GetEA(modrm,1); + WRITE8(ea, value); + CYCLES(CYCLES_SETCC_MEM); + } +} + +void i386_device::i386_setnc_rm8() // Opcode 0x0f 93 +{ + UINT8 modrm = FETCH(); + UINT8 value = 0; + if( m_CF == 0 ) { + value = 1; + } + if( modrm >= 0xc0 ) { + STORE_RM8(modrm, value); + CYCLES(CYCLES_SETCC_REG); + } else { + UINT32 ea = GetEA(modrm,1); + WRITE8(ea, value); + CYCLES(CYCLES_SETCC_MEM); + } +} + +void i386_device::i386_setno_rm8() // Opcode 0x0f 91 +{ + UINT8 modrm = FETCH(); + UINT8 value = 0; + if( m_OF == 0 ) { + value = 1; + } + if( modrm >= 0xc0 ) { + STORE_RM8(modrm, value); + CYCLES(CYCLES_SETCC_REG); + } else { + UINT32 ea = GetEA(modrm,1); + WRITE8(ea, value); + CYCLES(CYCLES_SETCC_MEM); + } +} + +void i386_device::i386_setnp_rm8() // Opcode 0x0f 9b +{ + UINT8 modrm = FETCH(); + UINT8 value = 0; + if( m_PF == 0 ) { + value = 1; + } + if( modrm >= 0xc0 ) { + STORE_RM8(modrm, value); + CYCLES(CYCLES_SETCC_REG); + } else { + UINT32 ea = GetEA(modrm,1); + WRITE8(ea, value); + CYCLES(CYCLES_SETCC_MEM); + } +} + +void i386_device::i386_setns_rm8() // Opcode 0x0f 99 +{ + UINT8 modrm = FETCH(); + UINT8 value = 0; + if( m_SF == 0 ) { + value = 1; + } + if( modrm >= 0xc0 ) { + STORE_RM8(modrm, value); + CYCLES(CYCLES_SETCC_REG); + } else { + UINT32 ea = GetEA(modrm,1); + WRITE8(ea, value); + CYCLES(CYCLES_SETCC_MEM); + } +} + +void i386_device::i386_setnz_rm8() // Opcode 0x0f 95 +{ + UINT8 modrm = FETCH(); + UINT8 value = 0; + if( m_ZF == 0 ) { + value = 1; + } + if( modrm >= 0xc0 ) { + STORE_RM8(modrm, value); + CYCLES(CYCLES_SETCC_REG); + } else { + UINT32 ea = GetEA(modrm,1); + WRITE8(ea, value); + CYCLES(CYCLES_SETCC_MEM); + } +} + +void i386_device::i386_seto_rm8() // Opcode 0x0f 90 +{ + UINT8 modrm = FETCH(); + UINT8 value = 0; + if( m_OF != 0 ) { + value = 1; + } + if( modrm >= 0xc0 ) { + STORE_RM8(modrm, value); + CYCLES(CYCLES_SETCC_REG); + } else { + UINT32 ea = GetEA(modrm,1); + WRITE8(ea, value); + CYCLES(CYCLES_SETCC_MEM); + } +} + +void i386_device::i386_setp_rm8() // Opcode 0x0f 9a +{ + UINT8 modrm = FETCH(); + UINT8 value = 0; + if( m_PF != 0 ) { + value = 1; + } + if( modrm >= 0xc0 ) { + STORE_RM8(modrm, value); + CYCLES(CYCLES_SETCC_REG); + } else { + UINT32 ea = GetEA(modrm,1); + WRITE8(ea, value); + CYCLES(CYCLES_SETCC_MEM); + } +} + +void i386_device::i386_sets_rm8() // Opcode 0x0f 98 +{ + UINT8 modrm = FETCH(); + UINT8 value = 0; + if( m_SF != 0 ) { + value = 1; + } + if( modrm >= 0xc0 ) { + STORE_RM8(modrm, value); + CYCLES(CYCLES_SETCC_REG); + } else { + UINT32 ea = GetEA(modrm,1); + WRITE8(ea, value); + CYCLES(CYCLES_SETCC_MEM); + } +} + +void i386_device::i386_setz_rm8() // Opcode 0x0f 94 +{ + UINT8 modrm = FETCH(); + UINT8 value = 0; + if( m_ZF != 0 ) { + value = 1; + } + if( modrm >= 0xc0 ) { + STORE_RM8(modrm, value); + CYCLES(CYCLES_SETCC_REG); + } else { + UINT32 ea = GetEA(modrm,1); + WRITE8(ea, value); + CYCLES(CYCLES_SETCC_MEM); + } +} + +void i386_device::i386_stc() // Opcode 0xf9 +{ + m_CF = 1; + CYCLES(CYCLES_STC); +} + +void i386_device::i386_std() // Opcode 0xfd +{ + m_DF = 1; + CYCLES(CYCLES_STD); +} + +void i386_device::i386_sti() // Opcode 0xfb +{ + if(PROTECTED_MODE) + { + UINT8 IOPL = m_IOP1 | (m_IOP2 << 1); + if(m_CPL > IOPL) + FAULT(FAULT_GP,0); + } + m_delayed_interrupt_enable = 1; // IF is set after the next instruction. + CYCLES(CYCLES_STI); +} + +void i386_device::i386_stosb() // Opcode 0xaa +{ + UINT32 ead; + ead = i386_translate(ES, m_address_size ? REG32(EDI) : REG16(DI), 1 ); + WRITE8(ead, REG8(AL)); + BUMP_DI(1); + CYCLES(CYCLES_STOS); +} + +void i386_device::i386_sub_rm8_r8() // Opcode 0x28 +{ + UINT8 src, dst; + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + src = LOAD_REG8(modrm); + dst = LOAD_RM8(modrm); + dst = SUB8(dst, src); + STORE_RM8(modrm, dst); + CYCLES(CYCLES_ALU_REG_REG); + } else { + UINT32 ea = GetEA(modrm,1); + src = LOAD_REG8(modrm); + dst = READ8(ea); + dst = SUB8(dst, src); + WRITE8(ea, dst); + CYCLES(CYCLES_ALU_REG_MEM); + } +} + +void i386_device::i386_sub_r8_rm8() // Opcode 0x2a +{ + UINT8 src, dst; + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + src = LOAD_RM8(modrm); + dst = LOAD_REG8(modrm); + dst = SUB8(dst, src); + STORE_REG8(modrm, dst); + CYCLES(CYCLES_ALU_REG_REG); + } else { + UINT32 ea = GetEA(modrm,0); + src = READ8(ea); + dst = LOAD_REG8(modrm); + dst = SUB8(dst, src); + STORE_REG8(modrm, dst); + CYCLES(CYCLES_ALU_MEM_REG); + } +} + +void i386_device::i386_sub_al_i8() // Opcode 0x2c +{ + UINT8 src, dst; + src = FETCH(); + dst = REG8(EAX); + dst = SUB8(dst, src); + REG8(EAX) = dst; + CYCLES(CYCLES_ALU_IMM_ACC); +} + +void i386_device::i386_test_al_i8() // Opcode 0xa8 +{ + UINT8 src = FETCH(); + UINT8 dst = REG8(AL); + dst = src & dst; + SetSZPF8(dst); + m_CF = 0; + m_OF = 0; + CYCLES(CYCLES_ALU_IMM_ACC); +} + +void i386_device::i386_test_rm8_r8() // Opcode 0x84 +{ + UINT8 src, dst; + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + src = LOAD_REG8(modrm); + dst = LOAD_RM8(modrm); + dst = src & dst; + SetSZPF8(dst); + m_CF = 0; + m_OF = 0; + CYCLES(CYCLES_TEST_REG_REG); + } else { + UINT32 ea = GetEA(modrm,0); + src = LOAD_REG8(modrm); + dst = READ8(ea); + dst = src & dst; + SetSZPF8(dst); + m_CF = 0; + m_OF = 0; + CYCLES(CYCLES_TEST_REG_MEM); + } +} + +void i386_device::i386_xchg_r8_rm8() // Opcode 0x86 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + UINT8 src = LOAD_RM8(modrm); + UINT8 dst = LOAD_REG8(modrm); + STORE_REG8(modrm, src); + STORE_RM8(modrm, dst); + CYCLES(CYCLES_XCHG_REG_REG); + } else { + UINT32 ea = GetEA(modrm,1); + UINT8 src = READ8(ea); + UINT8 dst = LOAD_REG8(modrm); + WRITE8(ea, dst); + STORE_REG8(modrm, src); + CYCLES(CYCLES_XCHG_REG_MEM); + } +} + +void i386_device::i386_xor_rm8_r8() // Opcode 0x30 +{ + UINT8 src, dst; + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + src = LOAD_REG8(modrm); + dst = LOAD_RM8(modrm); + dst = XOR8(dst, src); + STORE_RM8(modrm, dst); + CYCLES(CYCLES_ALU_REG_REG); + } else { + UINT32 ea = GetEA(modrm,1); + src = LOAD_REG8(modrm); + dst = READ8(ea); + dst = XOR8(dst, src); + WRITE8(ea, dst); + CYCLES(CYCLES_ALU_REG_MEM); + } +} + +void i386_device::i386_xor_r8_rm8() // Opcode 0x32 +{ + UINT32 src, dst; + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + src = LOAD_RM8(modrm); + dst = LOAD_REG8(modrm); + dst = XOR8(dst, src); + STORE_REG8(modrm, dst); + CYCLES(CYCLES_ALU_REG_REG); + } else { + UINT32 ea = GetEA(modrm,0); + src = READ8(ea); + dst = LOAD_REG8(modrm); + dst = XOR8(dst, src); + STORE_REG8(modrm, dst); + CYCLES(CYCLES_ALU_MEM_REG); + } +} + +void i386_device::i386_xor_al_i8() // Opcode 0x34 +{ + UINT8 src, dst; + src = FETCH(); + dst = REG8(AL); + dst = XOR8(dst, src); + REG8(AL) = dst; + CYCLES(CYCLES_ALU_IMM_ACC); +} + + + +void i386_device::i386_group80_8() // Opcode 0x80 +{ + UINT32 ea; + UINT8 src, dst; + UINT8 modrm = FETCH(); + + switch( (modrm >> 3) & 0x7 ) + { + case 0: // ADD Rm8, i8 + if( modrm >= 0xc0 ) { + dst = LOAD_RM8(modrm); + src = FETCH(); + dst = ADD8(dst, src); + STORE_RM8(modrm, dst); + CYCLES(CYCLES_ALU_REG_REG); + } else { + ea = GetEA(modrm,0); + dst = READ8(ea); + src = FETCH(); + dst = ADD8(dst, src); + WRITE8(ea, dst); + CYCLES(CYCLES_ALU_REG_MEM); + } + break; + case 1: // OR Rm8, i8 + if( modrm >= 0xc0 ) { + dst = LOAD_RM8(modrm); + src = FETCH(); + dst = OR8(dst, src); + STORE_RM8(modrm, dst); + CYCLES(CYCLES_ALU_REG_REG); + } else { + ea = GetEA(modrm,1); + dst = READ8(ea); + src = FETCH(); + dst = OR8(dst, src); + WRITE8(ea, dst); + CYCLES(CYCLES_ALU_REG_MEM); + } + break; + case 2: // ADC Rm8, i8 + if( modrm >= 0xc0 ) { + dst = LOAD_RM8(modrm); + src = FETCH(); + dst = ADC8(dst, src, m_CF); + STORE_RM8(modrm, dst); + CYCLES(CYCLES_ALU_REG_REG); + } else { + ea = GetEA(modrm,1); + dst = READ8(ea); + src = FETCH(); + dst = ADC8(dst, src, m_CF); + WRITE8(ea, dst); + CYCLES(CYCLES_ALU_REG_MEM); + } + break; + case 3: // SBB Rm8, i8 + if( modrm >= 0xc0 ) { + dst = LOAD_RM8(modrm); + src = FETCH(); + dst = SBB8(dst, src, m_CF); + STORE_RM8(modrm, dst); + CYCLES(CYCLES_ALU_REG_REG); + } else { + ea = GetEA(modrm,1); + dst = READ8(ea); + src = FETCH(); + dst = SBB8(dst, src, m_CF); + WRITE8(ea, dst); + CYCLES(CYCLES_ALU_REG_MEM); + } + break; + case 4: // AND Rm8, i8 + if( modrm >= 0xc0 ) { + dst = LOAD_RM8(modrm); + src = FETCH(); + dst = AND8(dst, src); + STORE_RM8(modrm, dst); + CYCLES(CYCLES_ALU_REG_REG); + } else { + ea = GetEA(modrm,1); + dst = READ8(ea); + src = FETCH(); + dst = AND8(dst, src); + WRITE8(ea, dst); + CYCLES(CYCLES_ALU_REG_MEM); + } + break; + case 5: // SUB Rm8, i8 + if( modrm >= 0xc0 ) { + dst = LOAD_RM8(modrm); + src = FETCH(); + dst = SUB8(dst, src); + STORE_RM8(modrm, dst); + CYCLES(CYCLES_ALU_REG_REG); + } else { + ea = GetEA(modrm,1); + dst = READ8(ea); + src = FETCH(); + dst = SUB8(dst, src); + WRITE8(ea, dst); + CYCLES(CYCLES_ALU_REG_MEM); + } + break; + case 6: // XOR Rm8, i8 + if( modrm >= 0xc0 ) { + dst = LOAD_RM8(modrm); + src = FETCH(); + dst = XOR8(dst, src); + STORE_RM8(modrm, dst); + CYCLES(CYCLES_ALU_REG_REG); + } else { + ea = GetEA(modrm,1); + dst = READ8(ea); + src = FETCH(); + dst = XOR8(dst, src); + WRITE8(ea, dst); + CYCLES(CYCLES_ALU_REG_MEM); + } + break; + case 7: // CMP Rm8, i8 + if( modrm >= 0xc0 ) { + dst = LOAD_RM8(modrm); + src = FETCH(); + SUB8(dst, src); + CYCLES(CYCLES_CMP_REG_REG); + } else { + ea = GetEA(modrm,0); + dst = READ8(ea); + src = FETCH(); + SUB8(dst, src); + CYCLES(CYCLES_CMP_REG_MEM); + } + break; + } +} + +void i386_device::i386_groupC0_8() // Opcode 0xc0 +{ + UINT8 dst; + UINT8 modrm = FETCH(); + UINT8 shift; + + if( modrm >= 0xc0 ) { + dst = LOAD_RM8(modrm); + shift = FETCH() & 0x1f; + dst = i386_shift_rotate8(modrm, dst, shift); + STORE_RM8(modrm, dst); + } else { + UINT32 ea = GetEA(modrm,1); + dst = READ8(ea); + shift = FETCH() & 0x1f; + dst = i386_shift_rotate8(modrm, dst, shift); + WRITE8(ea, dst); + } +} + +void i386_device::i386_groupD0_8() // Opcode 0xd0 +{ + UINT8 dst; + UINT8 modrm = FETCH(); + + if( modrm >= 0xc0 ) { + dst = LOAD_RM8(modrm); + dst = i386_shift_rotate8(modrm, dst, 1); + STORE_RM8(modrm, dst); + } else { + UINT32 ea = GetEA(modrm,1); + dst = READ8(ea); + dst = i386_shift_rotate8(modrm, dst, 1); + WRITE8(ea, dst); + } +} + +void i386_device::i386_groupD2_8() // Opcode 0xd2 +{ + UINT8 dst; + UINT8 modrm = FETCH(); + + if( modrm >= 0xc0 ) { + dst = LOAD_RM8(modrm); + dst = i386_shift_rotate8(modrm, dst, REG8(CL)); + STORE_RM8(modrm, dst); + } else { + UINT32 ea = GetEA(modrm,1); + dst = READ8(ea); + dst = i386_shift_rotate8(modrm, dst, REG8(CL)); + WRITE8(ea, dst); + } +} + +void i386_device::i386_groupF6_8() // Opcode 0xf6 +{ + UINT8 modrm = FETCH(); + + switch( (modrm >> 3) & 0x7 ) + { + case 0: /* TEST Rm8, i8 */ + if( modrm >= 0xc0 ) { + UINT8 dst = LOAD_RM8(modrm); + UINT8 src = FETCH(); + dst &= src; + m_CF = m_OF = m_AF = 0; + SetSZPF8(dst); + CYCLES(CYCLES_TEST_IMM_REG); + } else { + UINT32 ea = GetEA(modrm,0); + UINT8 dst = READ8(ea); + UINT8 src = FETCH(); + dst &= src; + m_CF = m_OF = m_AF = 0; + SetSZPF8(dst); + CYCLES(CYCLES_TEST_IMM_MEM); + } + break; + case 2: /* NOT Rm8 */ + if( modrm >= 0xc0 ) { + UINT8 dst = LOAD_RM8(modrm); + dst = ~dst; + STORE_RM8(modrm, dst); + CYCLES(CYCLES_NOT_REG); + } else { + UINT32 ea = GetEA(modrm,1); + UINT8 dst = READ8(ea); + dst = ~dst; + WRITE8(ea, dst); + CYCLES(CYCLES_NOT_MEM); + } + break; + case 3: /* NEG Rm8 */ + if( modrm >= 0xc0 ) { + UINT8 dst = LOAD_RM8(modrm); + dst = SUB8(0, dst ); + STORE_RM8(modrm, dst); + CYCLES(CYCLES_NEG_REG); + } else { + UINT32 ea = GetEA(modrm,1); + UINT8 dst = READ8(ea); + dst = SUB8(0, dst ); + WRITE8(ea, dst); + CYCLES(CYCLES_NEG_MEM); + } + break; + case 4: /* MUL AL, Rm8 */ + { + UINT16 result; + UINT8 src, dst; + if( modrm >= 0xc0 ) { + src = LOAD_RM8(modrm); + CYCLES(CYCLES_MUL8_ACC_REG); /* TODO: Correct multiply timing */ + } else { + UINT32 ea = GetEA(modrm,0); + src = READ8(ea); + CYCLES(CYCLES_MUL8_ACC_MEM); /* TODO: Correct multiply timing */ + } + + dst = REG8(AL); + result = (UINT16)src * (UINT16)dst; + REG16(AX) = (UINT16)result; + + m_CF = m_OF = (REG16(AX) > 0xff); + } + break; + case 5: /* IMUL AL, Rm8 */ + { + INT16 result; + INT16 src, dst; + if( modrm >= 0xc0 ) { + src = (INT16)(INT8)LOAD_RM8(modrm); + CYCLES(CYCLES_IMUL8_ACC_REG); /* TODO: Correct multiply timing */ + } else { + UINT32 ea = GetEA(modrm,0); + src = (INT16)(INT8)READ8(ea); + CYCLES(CYCLES_IMUL8_ACC_MEM); /* TODO: Correct multiply timing */ + } + + dst = (INT16)(INT8)REG8(AL); + result = src * dst; + + REG16(AX) = (UINT16)result; + + m_CF = m_OF = !(result == (INT16)(INT8)result); + } + break; + case 6: /* DIV AL, Rm8 */ + { + UINT16 quotient, remainder, result; + UINT8 src; + if( modrm >= 0xc0 ) { + src = LOAD_RM8(modrm); + CYCLES(CYCLES_DIV8_ACC_REG); + } else { + UINT32 ea = GetEA(modrm,0); + src = READ8(ea); + CYCLES(CYCLES_DIV8_ACC_MEM); + } + + quotient = (UINT16)REG16(AX); + if( src ) { + remainder = quotient % (UINT16)src; + result = quotient / (UINT16)src; + if( result > 0xff ) { + /* TODO: Divide error */ + } else { + REG8(AH) = (UINT8)remainder & 0xff; + REG8(AL) = (UINT8)result & 0xff; + + // this flag is actually undefined, enable on non-cyrix + if (m_cpuid_id0 != 0x69727943) + m_CF = 1; + } + } else { + i386_trap(0, 0, 0); + } + } + break; + case 7: /* IDIV AL, Rm8 */ + { + INT16 quotient, remainder, result; + UINT8 src; + if( modrm >= 0xc0 ) { + src = LOAD_RM8(modrm); + CYCLES(CYCLES_IDIV8_ACC_REG); + } else { + UINT32 ea = GetEA(modrm,0); + src = READ8(ea); + CYCLES(CYCLES_IDIV8_ACC_MEM); + } + + quotient = (INT16)REG16(AX); + if( src ) { + remainder = quotient % (INT16)(INT8)src; + result = quotient / (INT16)(INT8)src; + if( result > 0xff ) { + /* TODO: Divide error */ + } else { + REG8(AH) = (UINT8)remainder & 0xff; + REG8(AL) = (UINT8)result & 0xff; + + // this flag is actually undefined, enable on non-cyrix + if (m_cpuid_id0 != 0x69727943) + m_CF = 1; + } + } else { + i386_trap(0, 0, 0); + } + } + break; + } +} + +void i386_device::i386_groupFE_8() // Opcode 0xfe +{ + UINT8 modrm = FETCH(); + + switch( (modrm >> 3) & 0x7 ) + { + case 0: /* INC Rm8 */ + if( modrm >= 0xc0 ) { + UINT8 dst = LOAD_RM8(modrm); + dst = INC8(dst); + STORE_RM8(modrm, dst); + CYCLES(CYCLES_INC_REG); + } else { + UINT32 ea = GetEA(modrm,1); + UINT8 dst = READ8(ea); + dst = INC8(dst); + WRITE8(ea, dst); + CYCLES(CYCLES_INC_MEM); + } + break; + case 1: /* DEC Rm8 */ + if( modrm >= 0xc0 ) { + UINT8 dst = LOAD_RM8(modrm); + dst = DEC8(dst); + STORE_RM8(modrm, dst); + CYCLES(CYCLES_DEC_REG); + } else { + UINT32 ea = GetEA(modrm,1); + UINT8 dst = READ8(ea); + dst = DEC8(dst); + WRITE8(ea, dst); + CYCLES(CYCLES_DEC_MEM); + } + break; + case 6: /* PUSH Rm8*/ + { + UINT8 value; + if( modrm >= 0xc0 ) { + value = LOAD_RM8(modrm); + } else { + UINT32 ea = GetEA(modrm,0); + value = READ8(ea); + } + if( m_operand_size ) { + PUSH32(value); + } else { + PUSH16(value); + } + CYCLES(CYCLES_PUSH_RM); + } + break; + default: + report_invalid_modrm("groupFE_8", modrm); + break; + } +} + + + +void i386_device::i386_segment_CS() // Opcode 0x2e +{ + m_segment_prefix = 1; + m_segment_override = CS; + + i386_decode_opcode(); +} + +void i386_device::i386_segment_DS() // Opcode 0x3e +{ + m_segment_prefix = 1; + m_segment_override = DS; + CYCLES(0); // TODO: Specify cycle count + i386_decode_opcode(); +} + +void i386_device::i386_segment_ES() // Opcode 0x26 +{ + m_segment_prefix = 1; + m_segment_override = ES; + CYCLES(0); // TODO: Specify cycle count + i386_decode_opcode(); +} + +void i386_device::i386_segment_FS() // Opcode 0x64 +{ + m_segment_prefix = 1; + m_segment_override = FS; + CYCLES(1); // TODO: Specify cycle count + i386_decode_opcode(); +} + +void i386_device::i386_segment_GS() // Opcode 0x65 +{ + m_segment_prefix = 1; + m_segment_override = GS; + CYCLES(1); // TODO: Specify cycle count + i386_decode_opcode(); +} + +void i386_device::i386_segment_SS() // Opcode 0x36 +{ + m_segment_prefix = 1; + m_segment_override = SS; + CYCLES(0); // TODO: Specify cycle count + i386_decode_opcode(); +} + +void i386_device::i386_operand_size() // Opcode prefix 0x66 +{ + if(m_operand_prefix == 0) + { + m_operand_size ^= 1; + m_xmm_operand_size ^= 1; + m_operand_prefix = 1; + } + m_opcode = FETCH(); + if (m_opcode == 0x0f) + i386_decode_three_byte66(); + else + { + if( m_operand_size ) + (this->*m_opcode_table1_32[m_opcode])(); + else + (this->*m_opcode_table1_16[m_opcode])(); + } +} + +void i386_device::i386_address_size() // Opcode 0x67 +{ + if(m_address_prefix == 0) + { + m_address_size ^= 1; + m_address_prefix = 1; + } + i386_decode_opcode(); +} + +void i386_device::i386_nop() // Opcode 0x90 +{ + CYCLES(CYCLES_NOP); +} + +void i386_device::i386_int3() // Opcode 0xcc +{ + CYCLES(CYCLES_INT3); + m_ext = 0; // not an external interrupt + i386_trap(3, 1, 0); + m_ext = 1; +} + +void i386_device::i386_int() // Opcode 0xcd +{ + int interrupt = FETCH(); + CYCLES(CYCLES_INT); + m_ext = 0; // not an external interrupt + i386_trap(interrupt, 1, 0); + m_ext = 1; +} + +void i386_device::i386_into() // Opcode 0xce +{ + if( m_OF ) { + m_ext = 0; + i386_trap(4, 1, 0); + m_ext = 1; + CYCLES(CYCLES_INTO_OF1); + } + else + { + CYCLES(CYCLES_INTO_OF0); + } +} + +static UINT32 i386_escape_ea; // hack around GCC 4.6 error because we need the side effects of GetEA() +void i386_device::i386_escape() // Opcodes 0xd8 - 0xdf +{ + UINT8 modrm = FETCH(); + if(modrm < 0xc0) + { + i386_escape_ea = GetEA(modrm,0); + } + CYCLES(3); // TODO: confirm this + (void) LOAD_RM8(modrm); +} + +void i386_device::i386_hlt() // Opcode 0xf4 +{ + if(PROTECTED_MODE && m_CPL != 0) + FAULT(FAULT_GP,0); + m_halted = 1; + CYCLES(CYCLES_HLT); + if (m_cycles > 0) + m_cycles = 0; +} + +void i386_device::i386_decimal_adjust(int direction) +{ + UINT8 tmpAL = REG8(AL); + UINT8 tmpCF = m_CF; + + if (m_AF || ((REG8(AL) & 0xf) > 9)) + { + UINT16 t= (UINT16)REG8(AL) + (direction * 0x06); + REG8(AL) = (UINT8)t&0xff; + m_AF = 1; + if (t & 0x100) + m_CF = 1; + if (direction > 0) + tmpAL = REG8(AL); + } + + if (tmpCF || (tmpAL > 0x99)) + { + REG8(AL) += (direction * 0x60); + m_CF = 1; + } + + SetSZPF8(REG8(AL)); +} + +void i386_device::i386_daa() // Opcode 0x27 +{ + i386_decimal_adjust(+1); + CYCLES(CYCLES_DAA); +} + +void i386_device::i386_das() // Opcode 0x2f +{ + i386_decimal_adjust(-1); + CYCLES(CYCLES_DAS); +} + +void i386_device::i386_aaa() // Opcode 0x37 +{ + if( ( (REG8(AL) & 0x0f) > 9) || (m_AF != 0) ) { + REG16(AX) = REG16(AX) + 6; + REG8(AH) = REG8(AH) + 1; + m_AF = 1; + m_CF = 1; + } else { + m_AF = 0; + m_CF = 0; + } + REG8(AL) = REG8(AL) & 0x0f; + CYCLES(CYCLES_AAA); +} + +void i386_device::i386_aas() // Opcode 0x3f +{ + if (m_AF || ((REG8(AL) & 0xf) > 9)) + { + REG16(AX) -= 6; + REG8(AH) -= 1; + m_AF = 1; + m_CF = 1; + } + else + { + m_AF = 0; + m_CF = 0; + } + REG8(AL) &= 0x0f; + CYCLES(CYCLES_AAS); +} + +void i386_device::i386_aad() // Opcode 0xd5 +{ + UINT8 tempAL = REG8(AL); + UINT8 tempAH = REG8(AH); + UINT8 i = FETCH(); + + REG8(AL) = (tempAL + (tempAH * i)) & 0xff; + REG8(AH) = 0; + SetSZPF8( REG8(AL) ); + CYCLES(CYCLES_AAD); +} + +void i386_device::i386_aam() // Opcode 0xd4 +{ + UINT8 tempAL = REG8(AL); + UINT8 i = FETCH(); + + if(!i) + { + i386_trap(0, 0, 0); + return; + } + REG8(AH) = tempAL / i; + REG8(AL) = tempAL % i; + SetSZPF8( REG8(AL) ); + CYCLES(CYCLES_AAM); +} + +void i386_device::i386_clts() // Opcode 0x0f 0x06 +{ + // Privileged instruction, CPL must be zero. Can be used in real or v86 mode. + if(PROTECTED_MODE && m_CPL != 0) + FAULT(FAULT_GP,0) + m_cr[0] &= ~0x08; /* clear TS bit */ + CYCLES(CYCLES_CLTS); +} + +void i386_device::i386_wait() // Opcode 0x9B +{ + // TODO +} + +void i386_device::i386_lock() // Opcode 0xf0 +{ + // lock doesn't depend on iopl on 386 + m_lock = true; + CYCLES(CYCLES_LOCK); // TODO: Determine correct cycle count + i386_decode_opcode(); +} + +void i386_device::i386_mov_r32_tr() // Opcode 0x0f 24 +{ + FETCH(); + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::i386_mov_tr_r32() // Opcode 0x0f 26 +{ + FETCH(); + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::i386_loadall() // Opcode 0x0f 0x07 (0x0f 0x05 on 80286), undocumented +{ + fatalerror("i386: LOADALL unimplemented at %08X\n", m_pc - 1); +} + +void i386_device::i386_invalid() +{ + report_invalid_opcode(); + i386_trap(6, 0, 0); +} + +void i386_device::i386_xlat() // Opcode 0xd7 +{ + UINT32 ea; + if( m_segment_prefix ) { + if(!m_address_size) + { + ea = i386_translate(m_segment_override, REG16(BX) + REG8(AL), 0 ); + } + else + { + ea = i386_translate(m_segment_override, REG32(EBX) + REG8(AL), 0 ); + } + } else { + if(!m_address_size) + { + ea = i386_translate(DS, REG16(BX) + REG8(AL), 0 ); + } + else + { + ea = i386_translate(DS, REG32(EBX) + REG8(AL), 0 ); + } + } + REG8(AL) = READ8(ea); + CYCLES(CYCLES_XLAT); +} diff --git a/src/devices/cpu/i386/i386priv.h b/src/devices/cpu/i386/i386priv.h new file mode 100644 index 00000000000..c1f6ecea94c --- /dev/null +++ b/src/devices/cpu/i386/i386priv.h @@ -0,0 +1,1410 @@ +// license:BSD-3-Clause +// copyright-holders:Ville Linde, Barry Rodewald, Carl, Philip Bennett +#pragma once + +#ifndef __I386_H__ +#define __I386_H__ + +#include "i386.h" + +//#define DEBUG_MISSING_OPCODE + +#define I386OP(XX) i386_##XX +#define I486OP(XX) i486_##XX +#define PENTIUMOP(XX) pentium_##XX +#define MMXOP(XX) mmx_##XX +#define SSEOP(XX) sse_##XX + +extern int i386_dasm_one(char *buffer, UINT32 pc, const UINT8 *oprom, int mode); + +enum SREGS { ES, CS, SS, DS, FS, GS }; + +enum BREGS +{ + AL = NATIVE_ENDIAN_VALUE_LE_BE(0,3), + AH = NATIVE_ENDIAN_VALUE_LE_BE(1,2), + CL = NATIVE_ENDIAN_VALUE_LE_BE(4,7), + CH = NATIVE_ENDIAN_VALUE_LE_BE(5,6), + DL = NATIVE_ENDIAN_VALUE_LE_BE(8,11), + DH = NATIVE_ENDIAN_VALUE_LE_BE(9,10), + BL = NATIVE_ENDIAN_VALUE_LE_BE(12,15), + BH = NATIVE_ENDIAN_VALUE_LE_BE(13,14) +}; + +enum WREGS +{ + AX = NATIVE_ENDIAN_VALUE_LE_BE(0,1), + CX = NATIVE_ENDIAN_VALUE_LE_BE(2,3), + DX = NATIVE_ENDIAN_VALUE_LE_BE(4,5), + BX = NATIVE_ENDIAN_VALUE_LE_BE(6,7), + SP = NATIVE_ENDIAN_VALUE_LE_BE(8,9), + BP = NATIVE_ENDIAN_VALUE_LE_BE(10,11), + SI = NATIVE_ENDIAN_VALUE_LE_BE(12,13), + DI = NATIVE_ENDIAN_VALUE_LE_BE(14,15) +}; + +enum DREGS { EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI }; + +enum +{ + I386_PC = 0, + + /* 8-bit registers */ + I386_AL, + I386_AH, + I386_BL, + I386_BH, + I386_CL, + I386_CH, + I386_DL, + I386_DH, + + /* 16-bit registers */ + I386_AX, + I386_BX, + I386_CX, + I386_DX, + I386_BP, + I386_SP, + I386_SI, + I386_DI, + I386_IP, + + /* 32-bit registers */ + I386_EAX, + I386_ECX, + I386_EDX, + I386_EBX, + I386_EBP, + I386_ESP, + I386_ESI, + I386_EDI, + I386_EIP, + + /* segment registers */ + I386_CS, + I386_CS_BASE, + I386_CS_LIMIT, + I386_CS_FLAGS, + I386_SS, + I386_SS_BASE, + I386_SS_LIMIT, + I386_SS_FLAGS, + I386_DS, + I386_DS_BASE, + I386_DS_LIMIT, + I386_DS_FLAGS, + I386_ES, + I386_ES_BASE, + I386_ES_LIMIT, + I386_ES_FLAGS, + I386_FS, + I386_FS_BASE, + I386_FS_LIMIT, + I386_FS_FLAGS, + I386_GS, + I386_GS_BASE, + I386_GS_LIMIT, + I386_GS_FLAGS, + + /* other */ + I386_EFLAGS, + + I386_CR0, + I386_CR1, + I386_CR2, + I386_CR3, + I386_CR4, + + I386_DR0, + I386_DR1, + I386_DR2, + I386_DR3, + I386_DR4, + I386_DR5, + I386_DR6, + I386_DR7, + + I386_TR6, + I386_TR7, + + I386_GDTR_BASE, + I386_GDTR_LIMIT, + I386_IDTR_BASE, + I386_IDTR_LIMIT, + I386_TR, + I386_TR_BASE, + I386_TR_LIMIT, + I386_TR_FLAGS, + I386_LDTR, + I386_LDTR_BASE, + I386_LDTR_LIMIT, + I386_LDTR_FLAGS, + + I386_CPL, + + X87_CTRL, + X87_STATUS, + X87_TAG, + X87_ST0, + X87_ST1, + X87_ST2, + X87_ST3, + X87_ST4, + X87_ST5, + X87_ST6, + X87_ST7, + + SSE_XMM0, + SSE_XMM1, + SSE_XMM2, + SSE_XMM3, + SSE_XMM4, + SSE_XMM5, + SSE_XMM6, + SSE_XMM7 +}; + +enum +{ + /* mmx registers aliased to x87 ones */ + MMX_MM0=X87_ST0, + MMX_MM1=X87_ST1, + MMX_MM2=X87_ST2, + MMX_MM3=X87_ST3, + MMX_MM4=X87_ST4, + MMX_MM5=X87_ST5, + MMX_MM6=X87_ST6, + MMX_MM7=X87_ST7 +}; + +enum smram +{ + SMRAM_SMBASE = 0xF8, + SMRAM_SMREV = 0xFC, + SMRAM_IORSRT = 0x100, + SMRAM_AHALT = 0x102, + SMRAM_IOEDI = 0x104, + SMRAM_IOECX = 0x108, + SMRAM_IOESI = 0x10C, + + SMRAM_ES = 0x1A8, + SMRAM_CS = 0x1AC, + SMRAM_SS = 0x1B0, + SMRAM_DS = 0x1B4, + SMRAM_FS = 0x1B8, + SMRAM_GS = 0x1BC, + SMRAM_LDTR = 0x1C0, + SMRAM_TR = 0x1C4, + SMRAM_DR7 = 0x1C8, + SMRAM_DR6 = 0x1CC, + SMRAM_EAX = 0x1D0, + SMRAM_ECX = 0x1D4, + SMRAM_EDX = 0x1D8, + SMRAM_EBX = 0x1DC, + SMRAM_ESP = 0x1E0, + SMRAM_EBP = 0x1E4, + SMRAM_ESI = 0x1E8, + SMRAM_EDI = 0x1EC, + SMRAM_EIP = 0x1F0, + SMRAM_EFLAGS = 0x1F4, + SMRAM_CR3 = 0x1F8, + SMRAM_CR0 = 0x1FC +}; + +enum smram_intel_p5 +{ + SMRAM_IP5_IOEIP = 0x110, + SMRAM_IP5_CR4 = 0x128, + SMRAM_IP5_ESLIM = 0x130, + SMRAM_IP5_ESBASE = 0x134, + SMRAM_IP5_ESACC = 0x138, + SMRAM_IP5_CSLIM = 0x13C, + SMRAM_IP5_CSBASE = 0x140, + SMRAM_IP5_CSACC = 0x144, + SMRAM_IP5_SSLIM = 0x148, + SMRAM_IP5_SSBASE = 0x14C, + SMRAM_IP5_SSACC = 0x150, + SMRAM_IP5_DSLIM = 0x154, + SMRAM_IP5_DSBASE = 0x158, + SMRAM_IP5_DSACC = 0x15C, + SMRAM_IP5_FSLIM = 0x160, + SMRAM_IP5_FSBASE = 0x164, + SMRAM_IP5_FSACC = 0x168, + SMRAM_IP5_GSLIM = 0x16C, + SMRAM_IP5_GSBASE = 0x170, + SMRAM_IP5_GSACC = 0x174, + SMRAM_IP5_LDTLIM = 0x178, + SMRAM_IP5_LDTBASE = 0x17C, + SMRAM_IP5_LDTACC = 0x180, + SMRAM_IP5_GDTLIM = 0x184, + SMRAM_IP5_GDTBASE = 0x188, + SMRAM_IP5_GDTACC = 0x18C, + SMRAM_IP5_IDTLIM = 0x190, + SMRAM_IP5_IDTBASE = 0x194, + SMRAM_IP5_IDTACC = 0x198, + SMRAM_IP5_TRLIM = 0x19C, + SMRAM_IP5_TRBASE = 0x1A0, + SMRAM_IP5_TRACC = 0x1A4 +}; + +/* Protected mode exceptions */ +#define FAULT_UD 6 // Invalid Opcode +#define FAULT_NM 7 // Coprocessor not available +#define FAULT_DF 8 // Double Fault +#define FAULT_TS 10 // Invalid TSS +#define FAULT_NP 11 // Segment or Gate not present +#define FAULT_SS 12 // Stack fault +#define FAULT_GP 13 // General Protection Fault +#define FAULT_PF 14 // Page Fault +#define FAULT_MF 16 // Match (Coprocessor) Fault + +/* MXCSR Control and Status Register */ +#define MXCSR_IE (1<<0) // Invalid Operation Flag +#define MXCSR_DE (1<<1) // Denormal Flag +#define MXCSR_ZE (1<<2) // Divide-by-Zero Flag +#define MXCSR_OE (1<<3) // Overflow Flag +#define MXCSR_UE (1<<4) // Underflow Flag +#define MXCSR_PE (1<<5) // Precision Flag +#define MXCSR_DAZ (1<<6) // Denormals Are Zeros +#define MXCSR_IM (1<<7) // Invalid Operation Mask +#define MXCSR_DM (1<<8) // Denormal Operation Mask +#define MXCSR_ZM (1<<9) // Divide-by-Zero Mask +#define MXCSR_OM (1<<10) // Overflow Mask +#define MXCSR_UM (1<<11) // Underflow Mask +#define MXCSR_PM (1<<12) // Precision Mask +#define MXCSR_RC (3<<13) // Rounding Control +#define MXCSR_FZ (1<<15) // Flush to Zero + +union MMX_REG { + UINT32 d[2]; + INT32 i[2]; + UINT16 w[4]; + INT16 s[4]; + UINT8 b[8]; + INT8 c[8]; + float f[2]; + UINT64 q; + INT64 l; +}; + +extern int i386_parity_table[256]; + +#define FAULT_THROW(fault,error) { throw (UINT64)(fault | (UINT64)error << 32); } +#define PF_THROW(error) { m_cr[2] = address; FAULT_THROW(FAULT_PF,error); } + +#define PROTECTED_MODE (m_cr[0] & 0x1) +#define STACK_32BIT (m_sreg[SS].d) +#define V8086_MODE (m_VM) +#define NESTED_TASK (m_NT) +#define WP (m_cr[0] & 0x10000) + +#define SetOF_Add32(r,s,d) (m_OF = (((r) ^ (s)) & ((r) ^ (d)) & 0x80000000) ? 1: 0) +#define SetOF_Add16(r,s,d) (m_OF = (((r) ^ (s)) & ((r) ^ (d)) & 0x8000) ? 1 : 0) +#define SetOF_Add8(r,s,d) (m_OF = (((r) ^ (s)) & ((r) ^ (d)) & 0x80) ? 1 : 0) + +#define SetOF_Sub32(r,s,d) (m_OF = (((d) ^ (s)) & ((d) ^ (r)) & 0x80000000) ? 1 : 0) +#define SetOF_Sub16(r,s,d) (m_OF = (((d) ^ (s)) & ((d) ^ (r)) & 0x8000) ? 1 : 0) +#define SetOF_Sub8(r,s,d) (m_OF = (((d) ^ (s)) & ((d) ^ (r)) & 0x80) ? 1 : 0) + +#define SetCF8(x) {m_CF = ((x) & 0x100) ? 1 : 0; } +#define SetCF16(x) {m_CF = ((x) & 0x10000) ? 1 : 0; } +#define SetCF32(x) {m_CF = ((x) & (((UINT64)1) << 32)) ? 1 : 0; } + +#define SetSF(x) (m_SF = (x)) +#define SetZF(x) (m_ZF = (x)) +#define SetAF(x,y,z) (m_AF = (((x) ^ ((y) ^ (z))) & 0x10) ? 1 : 0) +#define SetPF(x) (m_PF = i386_parity_table[(x) & 0xFF]) + +#define SetSZPF8(x) {m_ZF = ((UINT8)(x)==0); m_SF = ((x)&0x80) ? 1 : 0; m_PF = i386_parity_table[x & 0xFF]; } +#define SetSZPF16(x) {m_ZF = ((UINT16)(x)==0); m_SF = ((x)&0x8000) ? 1 : 0; m_PF = i386_parity_table[x & 0xFF]; } +#define SetSZPF32(x) {m_ZF = ((UINT32)(x)==0); m_SF = ((x)&0x80000000) ? 1 : 0; m_PF = i386_parity_table[x & 0xFF]; } + +#define MMX(n) (*((MMX_REG *)(&m_x87_reg[(n)].low))) +#define XMM(n) m_sse_reg[(n)] + +/***********************************************************************************/ + +struct MODRM_TABLE { + struct { + int b; + int w; + int d; + } reg; + struct { + int b; + int w; + int d; + } rm; +}; + +extern MODRM_TABLE i386_MODRM_table[256]; + +#define REG8(x) (m_reg.b[x]) +#define REG16(x) (m_reg.w[x]) +#define REG32(x) (m_reg.d[x]) + +#define LOAD_REG8(x) (REG8(i386_MODRM_table[x].reg.b)) +#define LOAD_REG16(x) (REG16(i386_MODRM_table[x].reg.w)) +#define LOAD_REG32(x) (REG32(i386_MODRM_table[x].reg.d)) +#define LOAD_RM8(x) (REG8(i386_MODRM_table[x].rm.b)) +#define LOAD_RM16(x) (REG16(i386_MODRM_table[x].rm.w)) +#define LOAD_RM32(x) (REG32(i386_MODRM_table[x].rm.d)) + +#define STORE_REG8(x, value) (REG8(i386_MODRM_table[x].reg.b) = value) +#define STORE_REG16(x, value) (REG16(i386_MODRM_table[x].reg.w) = value) +#define STORE_REG32(x, value) (REG32(i386_MODRM_table[x].reg.d) = value) +#define STORE_RM8(x, value) (REG8(i386_MODRM_table[x].rm.b) = value) +#define STORE_RM16(x, value) (REG16(i386_MODRM_table[x].rm.w) = value) +#define STORE_RM32(x, value) (REG32(i386_MODRM_table[x].rm.d) = value) + +#define SWITCH_ENDIAN_32(x) (((((x) << 24) & (0xff << 24)) | (((x) << 8) & (0xff << 16)) | (((x) >> 8) & (0xff << 8)) | (((x) >> 24) & (0xff << 0)))) + +/***********************************************************************************/ + +UINT32 i386_device::i386_translate(int segment, UINT32 ip, int rwn) +{ + // TODO: segment limit access size, execution permission, handle exception thrown from exception handler + if(PROTECTED_MODE && !V8086_MODE && (rwn != -1)) + { + if(!(m_sreg[segment].valid)) + FAULT_THROW((segment==SS)?FAULT_SS:FAULT_GP, 0); + if(i386_limit_check(segment, ip)) + FAULT_THROW((segment==SS)?FAULT_SS:FAULT_GP, 0); + if((rwn == 0) && ((m_sreg[segment].flags & 8) && !(m_sreg[segment].flags & 2))) + FAULT_THROW(FAULT_GP, 0); + if((rwn == 1) && ((m_sreg[segment].flags & 8) || !(m_sreg[segment].flags & 2))) + FAULT_THROW(FAULT_GP, 0); + } + return m_sreg[segment].base + ip; +} + +#define VTLB_FLAG_DIRTY 0x100 + +vtlb_entry i386_device::get_permissions(UINT32 pte, int wp) +{ + vtlb_entry ret = VTLB_READ_ALLOWED | ((pte & 4) ? VTLB_USER_READ_ALLOWED : 0); + if(!wp) + ret |= VTLB_WRITE_ALLOWED; + if(pte & 2) + ret |= VTLB_WRITE_ALLOWED | ((pte & 4) ? VTLB_USER_WRITE_ALLOWED : 0); + return ret; +} + +bool i386_device::i386_translate_address(int intention, offs_t *address, vtlb_entry *entry) +{ + UINT32 a = *address; + UINT32 pdbr = m_cr[3] & 0xfffff000; + UINT32 directory = (a >> 22) & 0x3ff; + UINT32 table = (a >> 12) & 0x3ff; + vtlb_entry perm = 0; + bool ret = false; + bool user = (intention & TRANSLATE_USER_MASK) ? true : false; + bool write = (intention & TRANSLATE_WRITE) ? true : false; + bool debug = (intention & TRANSLATE_DEBUG_MASK) ? true : false; + + if(!(m_cr[0] & 0x80000000)) + { + if(entry) + *entry = 0x77; + return true; + } + + UINT32 page_dir = m_program->read_dword(pdbr + directory * 4); + if(page_dir & 1) + { + if ((page_dir & 0x80) && (m_cr[4] & 0x10)) + { + a = (page_dir & 0xffc00000) | (a & 0x003fffff); + if(debug) + { + *address = a; + return true; + } + perm = get_permissions(page_dir, WP); + if(write && (!(perm & VTLB_WRITE_ALLOWED) || (user && !(perm & VTLB_USER_WRITE_ALLOWED)))) + ret = false; + else if(user && !(perm & VTLB_USER_READ_ALLOWED)) + ret = false; + else + { + if(write) + perm |= VTLB_FLAG_DIRTY; + if(!(page_dir & 0x40) && write) + m_program->write_dword(pdbr + directory * 4, page_dir | 0x60); + else if(!(page_dir & 0x20)) + m_program->write_dword(pdbr + directory * 4, page_dir | 0x20); + ret = true; + } + } + else + { + UINT32 page_entry = m_program->read_dword((page_dir & 0xfffff000) + (table * 4)); + if(!(page_entry & 1)) + ret = false; + else + { + a = (page_entry & 0xfffff000) | (a & 0xfff); + if(debug) + { + *address = a; + return true; + } + perm = get_permissions(page_entry, WP); + if(write && (!(perm & VTLB_WRITE_ALLOWED) || (user && !(perm & VTLB_USER_WRITE_ALLOWED)))) + ret = false; + else if(user && !(perm & VTLB_USER_READ_ALLOWED)) + ret = false; + else + { + if(write) + perm |= VTLB_FLAG_DIRTY; + if(!(page_dir & 0x20)) + m_program->write_dword(pdbr + directory * 4, page_dir | 0x20); + if(!(page_entry & 0x40) && write) + m_program->write_dword((page_dir & 0xfffff000) + (table * 4), page_entry | 0x60); + else if(!(page_entry & 0x20)) + m_program->write_dword((page_dir & 0xfffff000) + (table * 4), page_entry | 0x20); + ret = true; + } + } + } + } + else + ret = false; + if(entry) + *entry = perm; + if(ret) + *address = a; + return ret; +} + +//#define TEST_TLB + +int i386_device::translate_address(int pl, int type, UINT32 *address, UINT32 *error) +{ + if(!(m_cr[0] & 0x80000000)) // Some (very few) old OS's won't work with this + return TRUE; + + const vtlb_entry *table = vtlb_table(m_vtlb); + UINT32 index = *address >> 12; + vtlb_entry entry = table[index]; + if(type == TRANSLATE_FETCH) + type = TRANSLATE_READ; + if(pl == 3) + type |= TRANSLATE_USER_MASK; +#ifdef TEST_TLB + UINT32 test_addr = *address; +#endif + + if(!(entry & VTLB_FLAG_VALID) || ((type & TRANSLATE_WRITE) && !(entry & VTLB_FLAG_DIRTY))) + { + if(!i386_translate_address(type, address, &entry)) + { + *error = ((type & TRANSLATE_WRITE) ? 2 : 0) | ((m_CPL == 3) ? 4 : 0); + if(entry) + *error |= 1; + return FALSE; + } + vtlb_dynload(m_vtlb, index, *address, entry); + return TRUE; + } + if(!(entry & (1 << type))) + { + *error = ((type & TRANSLATE_WRITE) ? 2 : 0) | ((m_CPL == 3) ? 4 : 0) | 1; + return FALSE; + } + *address = (entry & 0xfffff000) | (*address & 0xfff); +#ifdef TEST_TLB + int test_ret = i386_translate_address(type | TRANSLATE_DEBUG_MASK, &test_addr, NULL); + if(!test_ret || (test_addr != *address)) + logerror("TLB-PTE mismatch! %06X %06X %06x\n", *address, test_addr, m_pc); +#endif + return TRUE; +} + +void i386_device::CHANGE_PC(UINT32 pc) +{ + m_pc = i386_translate(CS, pc, -1 ); +} + +void i386_device::NEAR_BRANCH(INT32 offs) +{ + /* TODO: limit */ + m_eip += offs; + m_pc += offs; +} + +UINT8 i386_device::FETCH() +{ + UINT8 value; + UINT32 address = m_pc, error; + + if(!translate_address(m_CPL,TRANSLATE_FETCH,&address,&error)) + PF_THROW(error); + + value = m_direct->read_byte(address & m_a20_mask); +#ifdef DEBUG_MISSING_OPCODE + m_opcode_bytes[m_opcode_bytes_length] = value; + m_opcode_bytes_length = (m_opcode_bytes_length + 1) & 15; +#endif + m_eip++; + m_pc++; + return value; +} +UINT16 i386_device::FETCH16() +{ + UINT16 value; + UINT32 address = m_pc, error; + + if( address & 0x1 ) { /* Unaligned read */ + value = (FETCH() << 0); + value |= (FETCH() << 8); + } else { + if(!translate_address(m_CPL,TRANSLATE_FETCH,&address,&error)) + PF_THROW(error); + address &= m_a20_mask; + value = m_direct->read_word(address); + m_eip += 2; + m_pc += 2; + } + return value; +} +UINT32 i386_device::FETCH32() +{ + UINT32 value; + UINT32 address = m_pc, error; + + if( m_pc & 0x3 ) { /* Unaligned read */ + value = (FETCH() << 0); + value |= (FETCH() << 8); + value |= (FETCH() << 16); + value |= (FETCH() << 24); + } else { + if(!translate_address(m_CPL,TRANSLATE_FETCH,&address,&error)) + PF_THROW(error); + + address &= m_a20_mask; + value = m_direct->read_dword(address); + m_eip += 4; + m_pc += 4; + } + return value; +} + +UINT8 i386_device::READ8(UINT32 ea) +{ + UINT32 address = ea, error; + + if(!translate_address(m_CPL,TRANSLATE_READ,&address, &error)) + PF_THROW(error); + + address &= m_a20_mask; + return m_program->read_byte(address); +} +UINT16 i386_device::READ16(UINT32 ea) +{ + UINT16 value; + UINT32 address = ea, error; + + if( ea & 0x1 ) { /* Unaligned read */ + value = (READ8( address+0 ) << 0); + value |= (READ8( address+1 ) << 8); + } else { + if(!translate_address(m_CPL,TRANSLATE_READ,&address,&error)) + PF_THROW(error); + + address &= m_a20_mask; + value = m_program->read_word( address ); + } + return value; +} +UINT32 i386_device::READ32(UINT32 ea) +{ + UINT32 value; + UINT32 address = ea, error; + + if( ea & 0x3 ) { /* Unaligned read */ + value = (READ8( address+0 ) << 0); + value |= (READ8( address+1 ) << 8); + value |= (READ8( address+2 ) << 16), + value |= (READ8( address+3 ) << 24); + } else { + if(!translate_address(m_CPL,TRANSLATE_READ,&address,&error)) + PF_THROW(error); + + address &= m_a20_mask; + value = m_program->read_dword( address ); + } + return value; +} + +UINT64 i386_device::READ64(UINT32 ea) +{ + UINT64 value; + UINT32 address = ea, error; + + if( ea & 0x7 ) { /* Unaligned read */ + value = (((UINT64) READ8( address+0 )) << 0); + value |= (((UINT64) READ8( address+1 )) << 8); + value |= (((UINT64) READ8( address+2 )) << 16); + value |= (((UINT64) READ8( address+3 )) << 24); + value |= (((UINT64) READ8( address+4 )) << 32); + value |= (((UINT64) READ8( address+5 )) << 40); + value |= (((UINT64) READ8( address+6 )) << 48); + value |= (((UINT64) READ8( address+7 )) << 56); + } else { + if(!translate_address(m_CPL,TRANSLATE_READ,&address,&error)) + PF_THROW(error); + + address &= m_a20_mask; + value = (((UINT64) m_program->read_dword( address+0 )) << 0); + value |= (((UINT64) m_program->read_dword( address+4 )) << 32); + } + return value; +} +UINT8 i386_device::READ8PL0(UINT32 ea) +{ + UINT32 address = ea, error; + + if(!translate_address(0,TRANSLATE_READ,&address,&error)) + PF_THROW(error); + + address &= m_a20_mask; + return m_program->read_byte(address); +} +UINT16 i386_device::READ16PL0(UINT32 ea) +{ + UINT16 value; + UINT32 address = ea, error; + + if( ea & 0x1 ) { /* Unaligned read */ + value = (READ8PL0( address+0 ) << 0); + value |= (READ8PL0( address+1 ) << 8); + } else { + if(!translate_address(0,TRANSLATE_READ,&address,&error)) + PF_THROW(error); + + address &= m_a20_mask; + value = m_program->read_word( address ); + } + return value; +} + +UINT32 i386_device::READ32PL0(UINT32 ea) +{ + UINT32 value; + UINT32 address = ea, error; + + if( ea & 0x3 ) { /* Unaligned read */ + value = (READ8PL0( address+0 ) << 0); + value |= (READ8PL0( address+1 ) << 8); + value |= (READ8PL0( address+2 ) << 16); + value |= (READ8PL0( address+3 ) << 24); + } else { + if(!translate_address(0,TRANSLATE_READ,&address,&error)) + PF_THROW(error); + + address &= m_a20_mask; + value = m_program->read_dword( address ); + } + return value; +} + +void i386_device::WRITE_TEST(UINT32 ea) +{ + UINT32 address = ea, error; + if(!translate_address(m_CPL,TRANSLATE_WRITE,&address,&error)) + PF_THROW(error); +} + +void i386_device::WRITE8(UINT32 ea, UINT8 value) +{ + UINT32 address = ea, error; + + if(!translate_address(m_CPL,TRANSLATE_WRITE,&address,&error)) + PF_THROW(error); + + address &= m_a20_mask; + m_program->write_byte(address, value); +} +void i386_device::WRITE16(UINT32 ea, UINT16 value) +{ + UINT32 address = ea, error; + + if( ea & 0x1 ) { /* Unaligned write */ + WRITE8( address+0, value & 0xff ); + WRITE8( address+1, (value >> 8) & 0xff ); + } else { + if(!translate_address(m_CPL,TRANSLATE_WRITE,&address,&error)) + PF_THROW(error); + + address &= m_a20_mask; + m_program->write_word(address, value); + } +} +void i386_device::WRITE32(UINT32 ea, UINT32 value) +{ + UINT32 address = ea, error; + + if( ea & 0x3 ) { /* Unaligned write */ + WRITE8( address+0, value & 0xff ); + WRITE8( address+1, (value >> 8) & 0xff ); + WRITE8( address+2, (value >> 16) & 0xff ); + WRITE8( address+3, (value >> 24) & 0xff ); + } else { + if(!translate_address(m_CPL,TRANSLATE_WRITE,&address,&error)) + PF_THROW(error); + + ea &= m_a20_mask; + m_program->write_dword(address, value); + } +} + +void i386_device::WRITE64(UINT32 ea, UINT64 value) +{ + UINT32 address = ea, error; + + if( ea & 0x7 ) { /* Unaligned write */ + WRITE8( address+0, value & 0xff ); + WRITE8( address+1, (value >> 8) & 0xff ); + WRITE8( address+2, (value >> 16) & 0xff ); + WRITE8( address+3, (value >> 24) & 0xff ); + WRITE8( address+4, (value >> 32) & 0xff ); + WRITE8( address+5, (value >> 40) & 0xff ); + WRITE8( address+6, (value >> 48) & 0xff ); + WRITE8( address+7, (value >> 56) & 0xff ); + } else { + if(!translate_address(m_CPL,TRANSLATE_WRITE,&address,&error)) + PF_THROW(error); + + ea &= m_a20_mask; + m_program->write_dword(address+0, value & 0xffffffff); + m_program->write_dword(address+4, (value >> 32) & 0xffffffff); + } +} + +/***********************************************************************************/ + +UINT8 i386_device::OR8(UINT8 dst, UINT8 src) +{ + UINT8 res = dst | src; + m_CF = m_OF = 0; + SetSZPF8(res); + return res; +} +UINT16 i386_device::OR16(UINT16 dst, UINT16 src) +{ + UINT16 res = dst | src; + m_CF = m_OF = 0; + SetSZPF16(res); + return res; +} +UINT32 i386_device::OR32(UINT32 dst, UINT32 src) +{ + UINT32 res = dst | src; + m_CF = m_OF = 0; + SetSZPF32(res); + return res; +} + +UINT8 i386_device::AND8(UINT8 dst, UINT8 src) +{ + UINT8 res = dst & src; + m_CF = m_OF = 0; + SetSZPF8(res); + return res; +} +UINT16 i386_device::AND16(UINT16 dst, UINT16 src) +{ + UINT16 res = dst & src; + m_CF = m_OF = 0; + SetSZPF16(res); + return res; +} +UINT32 i386_device::AND32(UINT32 dst, UINT32 src) +{ + UINT32 res = dst & src; + m_CF = m_OF = 0; + SetSZPF32(res); + return res; +} + +UINT8 i386_device::XOR8(UINT8 dst, UINT8 src) +{ + UINT8 res = dst ^ src; + m_CF = m_OF = 0; + SetSZPF8(res); + return res; +} +UINT16 i386_device::XOR16(UINT16 dst, UINT16 src) +{ + UINT16 res = dst ^ src; + m_CF = m_OF = 0; + SetSZPF16(res); + return res; +} +UINT32 i386_device::XOR32(UINT32 dst, UINT32 src) +{ + UINT32 res = dst ^ src; + m_CF = m_OF = 0; + SetSZPF32(res); + return res; +} + +#define SUB8(dst, src) SBB8(dst, src, 0) +UINT8 i386_device::SBB8(UINT8 dst, UINT8 src, UINT8 b) +{ + UINT16 res = (UINT16)dst - (UINT16)src - (UINT8)b; + SetCF8(res); + SetOF_Sub8(res,src,dst); + SetAF(res,src,dst); + SetSZPF8(res); + return (UINT8)res; +} + +#define SUB16(dst, src) SBB16(dst, src, 0) +UINT16 i386_device::SBB16(UINT16 dst, UINT16 src, UINT16 b) +{ + UINT32 res = (UINT32)dst - (UINT32)src - (UINT32)b; + SetCF16(res); + SetOF_Sub16(res,src,dst); + SetAF(res,src,dst); + SetSZPF16(res); + return (UINT16)res; +} + +#define SUB32(dst, src) SBB32(dst, src, 0) +UINT32 i386_device::SBB32(UINT32 dst, UINT32 src, UINT32 b) +{ + UINT64 res = (UINT64)dst - (UINT64)src - (UINT64) b; + SetCF32(res); + SetOF_Sub32(res,src,dst); + SetAF(res,src,dst); + SetSZPF32(res); + return (UINT32)res; +} + +#define ADD8(dst, src) ADC8(dst, src, 0) +UINT8 i386_device::ADC8(UINT8 dst, UINT8 src, UINT8 c) +{ + UINT16 res = (UINT16)dst + (UINT16)src + (UINT16)c; + SetCF8(res); + SetOF_Add8(res,src,dst); + SetAF(res,src,dst); + SetSZPF8(res); + return (UINT8)res; +} + +#define ADD16(dst, src) ADC16(dst, src, 0) +UINT16 i386_device::ADC16(UINT16 dst, UINT16 src, UINT8 c) +{ + UINT32 res = (UINT32)dst + (UINT32)src + (UINT32)c; + SetCF16(res); + SetOF_Add16(res,src,dst); + SetAF(res,src,dst); + SetSZPF16(res); + return (UINT16)res; +} + +#define ADD32(dst, src) ADC32(dst, src, 0) +UINT32 i386_device::ADC32(UINT32 dst, UINT32 src, UINT32 c) +{ + UINT64 res = (UINT64)dst + (UINT64)src + (UINT64) c; + SetCF32(res); + SetOF_Add32(res,src,dst); + SetAF(res,src,dst); + SetSZPF32(res); + return (UINT32)res; +} + +UINT8 i386_device::INC8(UINT8 dst) +{ + UINT16 res = (UINT16)dst + 1; + SetOF_Add8(res,1,dst); + SetAF(res,1,dst); + SetSZPF8(res); + return (UINT8)res; +} +UINT16 i386_device::INC16(UINT16 dst) +{ + UINT32 res = (UINT32)dst + 1; + SetOF_Add16(res,1,dst); + SetAF(res,1,dst); + SetSZPF16(res); + return (UINT16)res; +} +UINT32 i386_device::INC32(UINT32 dst) +{ + UINT64 res = (UINT64)dst + 1; + SetOF_Add32(res,1,dst); + SetAF(res,1,dst); + SetSZPF32(res); + return (UINT32)res; +} + +UINT8 i386_device::DEC8(UINT8 dst) +{ + UINT16 res = (UINT16)dst - 1; + SetOF_Sub8(res,1,dst); + SetAF(res,1,dst); + SetSZPF8(res); + return (UINT8)res; +} +UINT16 i386_device::DEC16(UINT16 dst) +{ + UINT32 res = (UINT32)dst - 1; + SetOF_Sub16(res,1,dst); + SetAF(res,1,dst); + SetSZPF16(res); + return (UINT16)res; +} +UINT32 i386_device::DEC32(UINT32 dst) +{ + UINT64 res = (UINT64)dst - 1; + SetOF_Sub32(res,1,dst); + SetAF(res,1,dst); + SetSZPF32(res); + return (UINT32)res; +} + + + +void i386_device::PUSH16(UINT16 value) +{ + UINT32 ea, new_esp; + if( STACK_32BIT ) { + new_esp = REG32(ESP) - 2; + ea = i386_translate(SS, new_esp, 1); + WRITE16(ea, value ); + REG32(ESP) = new_esp; + } else { + new_esp = (REG16(SP) - 2) & 0xffff; + ea = i386_translate(SS, new_esp, 1); + WRITE16(ea, value ); + REG16(SP) = new_esp; + } +} +void i386_device::PUSH32(UINT32 value) +{ + UINT32 ea, new_esp; + if( STACK_32BIT ) { + new_esp = REG32(ESP) - 4; + ea = i386_translate(SS, new_esp, 1); + WRITE32(ea, value ); + REG32(ESP) = new_esp; + } else { + new_esp = (REG16(SP) - 4) & 0xffff; + ea = i386_translate(SS, new_esp, 1); + WRITE32(ea, value ); + REG16(SP) = new_esp; + } +} +void i386_device::PUSH8(UINT8 value) +{ + if( m_operand_size ) { + PUSH32((INT32)(INT8)value); + } else { + PUSH16((INT16)(INT8)value); + } +} + +UINT8 i386_device::POP8() +{ + UINT8 value; + UINT32 ea, new_esp; + if( STACK_32BIT ) { + new_esp = REG32(ESP) + 1; + ea = i386_translate(SS, new_esp - 1, 0); + value = READ8(ea ); + REG32(ESP) = new_esp; + } else { + new_esp = REG16(SP) + 1; + ea = i386_translate(SS, (new_esp - 1) & 0xffff, 0); + value = READ8(ea ); + REG16(SP) = new_esp; + } + return value; +} +UINT16 i386_device::POP16() +{ + UINT16 value; + UINT32 ea, new_esp; + if( STACK_32BIT ) { + new_esp = REG32(ESP) + 2; + ea = i386_translate(SS, new_esp - 2, 0); + value = READ16(ea ); + REG32(ESP) = new_esp; + } else { + new_esp = REG16(SP) + 2; + ea = i386_translate(SS, (new_esp - 2) & 0xffff, 0); + value = READ16(ea ); + REG16(SP) = new_esp; + } + return value; +} +UINT32 i386_device::POP32() +{ + UINT32 value; + UINT32 ea, new_esp; + if( STACK_32BIT ) { + new_esp = REG32(ESP) + 4; + ea = i386_translate(SS, new_esp - 4, 0); + value = READ32(ea ); + REG32(ESP) = new_esp; + } else { + new_esp = REG16(SP) + 4; + ea = i386_translate(SS, (new_esp - 4) & 0xffff, 0); + value = READ32(ea ); + REG16(SP) = new_esp; + } + return value; +} + +void i386_device::BUMP_SI(int adjustment) +{ + if ( m_address_size ) + REG32(ESI) += ((m_DF) ? -adjustment : +adjustment); + else + REG16(SI) += ((m_DF) ? -adjustment : +adjustment); +} + +void i386_device::BUMP_DI(int adjustment) +{ + if ( m_address_size ) + REG32(EDI) += ((m_DF) ? -adjustment : +adjustment); + else + REG16(DI) += ((m_DF) ? -adjustment : +adjustment); +} + + + +/*********************************************************************************** + I/O ACCESS +***********************************************************************************/ + +void i386_device::check_ioperm(offs_t port, UINT8 mask) +{ + UINT8 IOPL, map; + UINT16 IOPB; + UINT32 address; + + if(!PROTECTED_MODE) + return; + + IOPL = m_IOP1 | (m_IOP2 << 1); + if(!V8086_MODE && (m_CPL <= IOPL)) + return; + + if((m_task.limit < 0x67) || ((m_task.flags & 0xd) != 9)) + FAULT_THROW(FAULT_GP,0); + + address = m_task.base; + IOPB = READ16PL0(address+0x66); + if((IOPB+(port/8)) > m_task.limit) + FAULT_THROW(FAULT_GP,0); + + map = READ8PL0(address+IOPB+(port/8)); + map >>= (port%8); + if(map & mask) + FAULT_THROW(FAULT_GP,0); +} + +UINT8 i386_device::READPORT8(offs_t port) +{ + check_ioperm(port, 1); + return m_io->read_byte(port); +} + +void i386_device::WRITEPORT8(offs_t port, UINT8 value) +{ + check_ioperm(port, 1); + m_io->write_byte(port, value); +} + +UINT16 i386_device::READPORT16(offs_t port) +{ + if (port & 1) + { + UINT16 value = READPORT8(port); + value |= (READPORT8(port + 1) << 8); + return value; + } + else + { + check_ioperm(port, 3); + return m_io->read_word(port); + } +} + +void i386_device::WRITEPORT16(offs_t port, UINT16 value) +{ + if (port & 1) + { + WRITEPORT8(port, value & 0xff); + WRITEPORT8(port + 1, (value >> 8) & 0xff); + } + else + { + check_ioperm(port, 3); + m_io->write_word(port, value); + } +} + +UINT32 i386_device::READPORT32(offs_t port) +{ + if (port & 3) + { + UINT32 value = READPORT8(port); + value |= (READPORT8(port + 1) << 8); + value |= (READPORT8(port + 2) << 16); + value |= (READPORT8(port + 3) << 24); + return value; + } + else + { + check_ioperm(port, 0xf); + return m_io->read_dword(port); + } +} + +void i386_device::WRITEPORT32(offs_t port, UINT32 value) +{ + if (port & 3) + { + WRITEPORT8(port, value & 0xff); + WRITEPORT8(port + 1, (value >> 8) & 0xff); + WRITEPORT8(port + 2, (value >> 16) & 0xff); + WRITEPORT8(port + 3, (value >> 24) & 0xff); + } + else + { + check_ioperm(port, 0xf); + m_io->write_dword(port, value); + } +} + +/*********************************************************************************** + MSR ACCESS +***********************************************************************************/ + +// Pentium MSR handling +UINT64 i386_device::pentium_msr_read(UINT32 offset,UINT8 *valid_msr) +{ + switch(offset) + { + // Machine Check Exception (TODO) + case 0x00: + *valid_msr = 1; + popmessage("RDMSR: Reading P5_MC_ADDR"); + return 0; + case 0x01: + *valid_msr = 1; + popmessage("RDMSR: Reading P5_MC_TYPE"); + return 0; + // Time Stamp Counter + case 0x10: + *valid_msr = 1; + popmessage("RDMSR: Reading TSC"); + return m_tsc; + // Event Counters (TODO) + case 0x11: // CESR + *valid_msr = 1; + popmessage("RDMSR: Reading CESR"); + return 0; + case 0x12: // CTR0 + *valid_msr = 1; + return m_perfctr[0]; + case 0x13: // CTR1 + *valid_msr = 1; + return m_perfctr[1]; + default: + if(!(offset & ~0xf)) // 2-f are test registers + { + *valid_msr = 1; + logerror("RDMSR: Reading test MSR %x", offset); + return 0; + } + logerror("RDMSR: invalid P5 MSR read %08x at %08x\n",offset,m_pc-2); + *valid_msr = 0; + return 0; + } + return -1; +} + +void i386_device::pentium_msr_write(UINT32 offset, UINT64 data, UINT8 *valid_msr) +{ + switch(offset) + { + // Machine Check Exception (TODO) + case 0x00: + popmessage("WRMSR: Writing P5_MC_ADDR"); + *valid_msr = 1; + break; + case 0x01: + popmessage("WRMSR: Writing P5_MC_TYPE"); + *valid_msr = 1; + break; + // Time Stamp Counter + case 0x10: + m_tsc = data; + popmessage("WRMSR: Writing to TSC"); + *valid_msr = 1; + break; + // Event Counters (TODO) + case 0x11: // CESR + popmessage("WRMSR: Writing to CESR"); + *valid_msr = 1; + break; + case 0x12: // CTR0 + m_perfctr[0] = data; + *valid_msr = 1; + break; + case 0x13: // CTR1 + m_perfctr[1] = data; + *valid_msr = 1; + break; + default: + if(!(offset & ~0xf)) // 2-f are test registers + { + *valid_msr = 1; + logerror("WRMSR: Writing test MSR %x", offset); + break; + } + logerror("WRMSR: invalid MSR write %08x (%08x%08x) at %08x\n",offset,(UINT32)(data >> 32),(UINT32)data,m_pc-2); + *valid_msr = 0; + break; + } +} + +// P6 (Pentium Pro, Pentium II, Pentium III) MSR handling +UINT64 i386_device::p6_msr_read(UINT32 offset,UINT8 *valid_msr) +{ + switch(offset) + { + // Machine Check Exception (TODO) + case 0x00: + *valid_msr = 1; + popmessage("RDMSR: Reading P5_MC_ADDR"); + return 0; + case 0x01: + *valid_msr = 1; + popmessage("RDMSR: Reading P5_MC_TYPE"); + return 0; + // Time Stamp Counter + case 0x10: + *valid_msr = 1; + popmessage("RDMSR: Reading TSC"); + return m_tsc; + // Performance Counters (TODO) + case 0xc1: // PerfCtr0 + *valid_msr = 1; + return m_perfctr[0]; + case 0xc2: // PerfCtr1 + *valid_msr = 1; + return m_perfctr[1]; + default: + logerror("RDMSR: unimplemented register called %08x at %08x\n",offset,m_pc-2); + *valid_msr = 1; + return 0; + } + return -1; +} + +void i386_device::p6_msr_write(UINT32 offset, UINT64 data, UINT8 *valid_msr) +{ + switch(offset) + { + // Time Stamp Counter + case 0x10: + m_tsc = data; + popmessage("WRMSR: Writing to TSC"); + *valid_msr = 1; + break; + // Performance Counters (TODO) + case 0xc1: // PerfCtr0 + m_perfctr[0] = data; + *valid_msr = 1; + break; + case 0xc2: // PerfCtr1 + m_perfctr[1] = data; + *valid_msr = 1; + break; + default: + logerror("WRMSR: unimplemented register called %08x (%08x%08x) at %08x\n",offset,(UINT32)(data >> 32),(UINT32)data,m_pc-2); + *valid_msr = 1; + break; + } +} + + +// PIV (Pentium 4+) +UINT64 i386_device::piv_msr_read(UINT32 offset,UINT8 *valid_msr) +{ + switch(offset) + { + default: + logerror("RDMSR: unimplemented register called %08x at %08x\n",offset,m_pc-2); + *valid_msr = 1; + return 0; + } + return -1; +} + +void i386_device::piv_msr_write(UINT32 offset, UINT64 data, UINT8 *valid_msr) +{ + switch(offset) + { + default: + logerror("WRMSR: unimplemented register called %08x (%08x%08x) at %08x\n",offset,(UINT32)(data >> 32),(UINT32)data,m_pc-2); + *valid_msr = 1; + break; + } +} + +UINT64 i386_device::MSR_READ(UINT32 offset,UINT8 *valid_msr) +{ + UINT64 res; + UINT8 cpu_type = (m_cpu_version >> 8) & 0x0f; + + *valid_msr = 0; + + switch(cpu_type) + { + case 5: // Pentium + res = pentium_msr_read(offset,valid_msr); + break; + case 6: // Pentium Pro, Pentium II, Pentium III + res = p6_msr_read(offset,valid_msr); + break; + case 15: // Pentium 4+ + res = piv_msr_read(offset,valid_msr); + break; + default: + res = 0; + break; + } + + return res; +} + +void i386_device::MSR_WRITE(UINT32 offset, UINT64 data, UINT8 *valid_msr) +{ + *valid_msr = 0; + UINT8 cpu_type = (m_cpu_version >> 8) & 0x0f; + + switch(cpu_type) + { + case 5: // Pentium + pentium_msr_write(offset,data,valid_msr); + break; + case 6: // Pentium Pro, Pentium II, Pentium III + p6_msr_write(offset,data,valid_msr); + break; + case 15: // Pentium 4+ + piv_msr_write(offset,data,valid_msr); + break; + } +} + +#endif /* __I386_H__ */ diff --git a/src/devices/cpu/i386/i486ops.inc b/src/devices/cpu/i386/i486ops.inc new file mode 100644 index 00000000000..d22f6c079c3 --- /dev/null +++ b/src/devices/cpu/i386/i486ops.inc @@ -0,0 +1,516 @@ +// license:BSD-3-Clause +// copyright-holders:Ville Linde, Barry Rodewald, Carl, Philip Bennett +// Intel 486+ specific opcodes + +void i386_device::i486_cpuid() // Opcode 0x0F A2 +{ + if (m_cpuid_id0 == 0) + { + // this 486 doesn't support the CPUID instruction + logerror("CPUID not supported at %08x!\n", m_eip); + i386_trap(6, 0, 0); + } + else + { + switch (REG32(EAX)) + { + case 0: + { + REG32(EAX) = m_cpuid_max_input_value_eax; + REG32(EBX) = m_cpuid_id0; + REG32(ECX) = m_cpuid_id2; + REG32(EDX) = m_cpuid_id1; + CYCLES(CYCLES_CPUID); + break; + } + + case 1: + { + REG32(EAX) = m_cpu_version; + REG32(EDX) = m_feature_flags; + CYCLES(CYCLES_CPUID_EAX1); + break; + } + } + } +} + +void i386_device::i486_invd() // Opcode 0x0f 08 +{ + // Nothing to do ? + CYCLES(CYCLES_INVD); +} + +void i386_device::i486_wbinvd() // Opcode 0x0f 09 +{ + // Nothing to do ? +} + +void i386_device::i486_cmpxchg_rm8_r8() // Opcode 0x0f b0 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + UINT8 dst = LOAD_RM8(modrm); + UINT8 src = LOAD_REG8(modrm); + + if( REG8(AL) == dst ) { + STORE_RM8(modrm, src); + m_ZF = 1; + CYCLES(CYCLES_CMPXCHG_REG_REG_T); + } else { + REG8(AL) = dst; + m_ZF = 0; + CYCLES(CYCLES_CMPXCHG_REG_REG_F); + } + } else { + // TODO: Check write if needed + UINT32 ea = GetEA(modrm,0); + UINT8 dst = READ8(ea); + UINT8 src = LOAD_REG8(modrm); + + if( REG8(AL) == dst ) { + WRITE8(ea, src); + m_ZF = 1; + CYCLES(CYCLES_CMPXCHG_REG_MEM_T); + } else { + REG8(AL) = dst; + m_ZF = 0; + CYCLES(CYCLES_CMPXCHG_REG_MEM_F); + } + } +} + +void i386_device::i486_cmpxchg_rm16_r16() // Opcode 0x0f b1 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + UINT16 dst = LOAD_RM16(modrm); + UINT16 src = LOAD_REG16(modrm); + + if( REG16(AX) == dst ) { + STORE_RM16(modrm, src); + m_ZF = 1; + CYCLES(CYCLES_CMPXCHG_REG_REG_T); + } else { + REG16(AX) = dst; + m_ZF = 0; + CYCLES(CYCLES_CMPXCHG_REG_REG_F); + } + } else { + UINT32 ea = GetEA(modrm,0); + UINT16 dst = READ16(ea); + UINT16 src = LOAD_REG16(modrm); + + if( REG16(AX) == dst ) { + WRITE16(ea, src); + m_ZF = 1; + CYCLES(CYCLES_CMPXCHG_REG_MEM_T); + } else { + REG16(AX) = dst; + m_ZF = 0; + CYCLES(CYCLES_CMPXCHG_REG_MEM_F); + } + } +} + +void i386_device::i486_cmpxchg_rm32_r32() // Opcode 0x0f b1 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + UINT32 dst = LOAD_RM32(modrm); + UINT32 src = LOAD_REG32(modrm); + + if( REG32(EAX) == dst ) { + STORE_RM32(modrm, src); + m_ZF = 1; + CYCLES(CYCLES_CMPXCHG_REG_REG_T); + } else { + REG32(EAX) = dst; + m_ZF = 0; + CYCLES(CYCLES_CMPXCHG_REG_REG_F); + } + } else { + UINT32 ea = GetEA(modrm,0); + UINT32 dst = READ32(ea); + UINT32 src = LOAD_REG32(modrm); + + if( REG32(EAX) == dst ) { + WRITE32(ea, src); + m_ZF = 1; + CYCLES(CYCLES_CMPXCHG_REG_MEM_T); + } else { + REG32(EAX) = dst; + m_ZF = 0; + CYCLES(CYCLES_CMPXCHG_REG_MEM_F); + } + } +} + +void i386_device::i486_xadd_rm8_r8() // Opcode 0x0f c0 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + UINT8 dst = LOAD_RM8(modrm); + UINT8 src = LOAD_REG8(modrm); + STORE_REG8(modrm, dst); + STORE_RM8(modrm, dst + src); + CYCLES(CYCLES_XADD_REG_REG); + } else { + UINT32 ea = GetEA(modrm,1); + UINT8 dst = READ8(ea); + UINT8 src = LOAD_REG8(modrm); + WRITE8(ea, dst + src); + STORE_REG8(modrm, dst); + CYCLES(CYCLES_XADD_REG_MEM); + } +} + +void i386_device::i486_xadd_rm16_r16() // Opcode 0x0f c1 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + UINT16 dst = LOAD_RM16(modrm); + UINT16 src = LOAD_REG16(modrm); + STORE_REG16(modrm, dst); + STORE_RM16(modrm, dst + src); + CYCLES(CYCLES_XADD_REG_REG); + } else { + UINT32 ea = GetEA(modrm,1); + UINT16 dst = READ16(ea); + UINT16 src = LOAD_REG16(modrm); + WRITE16(ea, dst + src); + STORE_REG16(modrm, dst); + CYCLES(CYCLES_XADD_REG_MEM); + } +} + +void i386_device::i486_xadd_rm32_r32() // Opcode 0x0f c1 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + UINT32 dst = LOAD_RM32(modrm); + UINT32 src = LOAD_REG32(modrm); + STORE_REG32(modrm, dst); + STORE_RM32(modrm, dst + src); + CYCLES(CYCLES_XADD_REG_REG); + } else { + UINT32 ea = GetEA(modrm,1); + UINT32 dst = READ32(ea); + UINT32 src = LOAD_REG32(modrm); + WRITE32(ea, dst + src); + STORE_REG32(modrm, dst); + CYCLES(CYCLES_XADD_REG_MEM); + } +} + +void i386_device::i486_group0F01_16() // Opcode 0x0f 01 +{ + UINT8 modrm = FETCH(); + UINT16 address; + UINT32 ea; + + switch( (modrm >> 3) & 0x7 ) + { + case 0: /* SGDT */ + { + if( modrm >= 0xc0 ) { + address = LOAD_RM16(modrm); + ea = i386_translate( CS, address, 1 ); + } else { + ea = GetEA(modrm,1); + } + WRITE16(ea, m_gdtr.limit); + WRITE32(ea + 2, m_gdtr.base & 0xffffff); + CYCLES(CYCLES_SGDT); + break; + } + case 1: /* SIDT */ + { + if (modrm >= 0xc0) + { + address = LOAD_RM16(modrm); + ea = i386_translate( CS, address, 1 ); + } + else + { + ea = GetEA(modrm,1); + } + WRITE16(ea, m_idtr.limit); + WRITE32(ea + 2, m_idtr.base & 0xffffff); + CYCLES(CYCLES_SIDT); + break; + } + case 2: /* LGDT */ + { + if(PROTECTED_MODE && m_CPL) + FAULT(FAULT_GP,0) + if( modrm >= 0xc0 ) { + address = LOAD_RM16(modrm); + ea = i386_translate( CS, address, 0 ); + } else { + ea = GetEA(modrm,0); + } + m_gdtr.limit = READ16(ea); + m_gdtr.base = READ32(ea + 2) & 0xffffff; + CYCLES(CYCLES_LGDT); + break; + } + case 3: /* LIDT */ + { + if(PROTECTED_MODE && m_CPL) + FAULT(FAULT_GP,0) + if( modrm >= 0xc0 ) { + address = LOAD_RM16(modrm); + ea = i386_translate( CS, address, 0 ); + } else { + ea = GetEA(modrm,0); + } + m_idtr.limit = READ16(ea); + m_idtr.base = READ32(ea + 2) & 0xffffff; + CYCLES(CYCLES_LIDT); + break; + } + case 4: /* SMSW */ + { + if( modrm >= 0xc0 ) { + STORE_RM16(modrm, m_cr[0]); + CYCLES(CYCLES_SMSW_REG); + } else { + ea = GetEA(modrm,1); + WRITE16(ea, m_cr[0]); + CYCLES(CYCLES_SMSW_MEM); + } + break; + } + case 6: /* LMSW */ + { + UINT16 b; + if(PROTECTED_MODE && m_CPL) + FAULT(FAULT_GP,0) + if( modrm >= 0xc0 ) { + b = LOAD_RM16(modrm); + CYCLES(CYCLES_LMSW_REG); + } else { + ea = GetEA(modrm,0); + CYCLES(CYCLES_LMSW_MEM); + b = READ16(ea); + } + if(PROTECTED_MODE) + b |= 0x0001; // cannot return to real mode using this instruction. + m_cr[0] &= ~0x0000000f; + m_cr[0] |= b & 0x0000000f; + break; + } + case 7: /* INVLPG */ + { + if(PROTECTED_MODE && m_CPL) + FAULT(FAULT_GP,0) + if(modrm >= 0xc0) + { + logerror("i486: invlpg with modrm %02X\n", modrm); + FAULT(FAULT_UD,0) + } + ea = GetEA(modrm,-1); + CYCLES(25); // TODO: add to cycles.h + vtlb_flush_address(m_vtlb, ea); + break; + } + default: + report_invalid_modrm("group0F01_16", modrm); + break; + } +} + +void i386_device::i486_group0F01_32() // Opcode 0x0f 01 +{ + UINT8 modrm = FETCH(); + UINT32 address, ea; + + switch( (modrm >> 3) & 0x7 ) + { + case 0: /* SGDT */ + { + if( modrm >= 0xc0 ) { + address = LOAD_RM32(modrm); + ea = i386_translate( CS, address, 1 ); + } else { + ea = GetEA(modrm,1); + } + WRITE16(ea, m_gdtr.limit); + WRITE32(ea + 2, m_gdtr.base); + CYCLES(CYCLES_SGDT); + break; + } + case 1: /* SIDT */ + { + if (modrm >= 0xc0) + { + address = LOAD_RM32(modrm); + ea = i386_translate( CS, address, 1 ); + } + else + { + ea = GetEA(modrm,1); + } + WRITE16(ea, m_idtr.limit); + WRITE32(ea + 2, m_idtr.base); + CYCLES(CYCLES_SIDT); + break; + } + case 2: /* LGDT */ + { + if(PROTECTED_MODE && m_CPL) + FAULT(FAULT_GP,0) + if( modrm >= 0xc0 ) { + address = LOAD_RM32(modrm); + ea = i386_translate( CS, address, 0 ); + } else { + ea = GetEA(modrm,0); + } + m_gdtr.limit = READ16(ea); + m_gdtr.base = READ32(ea + 2); + CYCLES(CYCLES_LGDT); + break; + } + case 3: /* LIDT */ + { + if(PROTECTED_MODE && m_CPL) + FAULT(FAULT_GP,0) + if( modrm >= 0xc0 ) { + address = LOAD_RM32(modrm); + ea = i386_translate( CS, address, 0 ); + } else { + ea = GetEA(modrm,0); + } + m_idtr.limit = READ16(ea); + m_idtr.base = READ32(ea + 2); + CYCLES(CYCLES_LIDT); + break; + } + case 4: /* SMSW */ + { + if( modrm >= 0xc0 ) { + STORE_RM32(modrm, m_cr[0] & 0xffff); + CYCLES(CYCLES_SMSW_REG); + } else { + /* always 16-bit memory operand */ + ea = GetEA(modrm,1); + WRITE16(ea, m_cr[0]); + CYCLES(CYCLES_SMSW_MEM); + } + break; + } + case 6: /* LMSW */ + { + if(PROTECTED_MODE && m_CPL) + FAULT(FAULT_GP,0) + UINT16 b; + if( modrm >= 0xc0 ) { + b = LOAD_RM16(modrm); + CYCLES(CYCLES_LMSW_REG); + } else { + ea = GetEA(modrm,0); + CYCLES(CYCLES_LMSW_MEM); + b = READ16(ea); + } + if(PROTECTED_MODE) + b |= 0x0001; // cannot return to real mode using this instruction. + m_cr[0] &= ~0x0000000f; + m_cr[0] |= b & 0x0000000f; + break; + } + case 7: /* INVLPG */ + { + if(PROTECTED_MODE && m_CPL) + FAULT(FAULT_GP,0) + if(modrm >= 0xc0) + { + logerror("i486: invlpg with modrm %02X\n", modrm); + FAULT(FAULT_UD,0) + } + ea = GetEA(modrm,-1); + CYCLES(25); // TODO: add to cycles.h + vtlb_flush_address(m_vtlb, ea); + break; + } + default: + report_invalid_modrm("group0F01_32", modrm); + break; + } +} + +void i386_device::i486_bswap_eax() // Opcode 0x0f 38 +{ + REG32(EAX) = SWITCH_ENDIAN_32(REG32(EAX)); + CYCLES(1); // TODO +} + +void i386_device::i486_bswap_ecx() // Opcode 0x0f 39 +{ + REG32(ECX) = SWITCH_ENDIAN_32(REG32(ECX)); + CYCLES(1); // TODO +} + +void i386_device::i486_bswap_edx() // Opcode 0x0f 3A +{ + REG32(EDX) = SWITCH_ENDIAN_32(REG32(EDX)); + CYCLES(1); // TODO +} + +void i386_device::i486_bswap_ebx() // Opcode 0x0f 3B +{ + REG32(EBX) = SWITCH_ENDIAN_32(REG32(EBX)); + CYCLES(1); // TODO +} + +void i386_device::i486_bswap_esp() // Opcode 0x0f 3C +{ + REG32(ESP) = SWITCH_ENDIAN_32(REG32(ESP)); + CYCLES(1); // TODO +} + +void i386_device::i486_bswap_ebp() // Opcode 0x0f 3D +{ + REG32(EBP) = SWITCH_ENDIAN_32(REG32(EBP)); + CYCLES(1); // TODO +} + +void i386_device::i486_bswap_esi() // Opcode 0x0f 3E +{ + REG32(ESI) = SWITCH_ENDIAN_32(REG32(ESI)); + CYCLES(1); // TODO +} + +void i386_device::i486_bswap_edi() // Opcode 0x0f 3F +{ + REG32(EDI) = SWITCH_ENDIAN_32(REG32(EDI)); + CYCLES(1); // TODO +} + +void i386_device::i486_mov_cr_r32() // Opcode 0x0f 22 +{ + if(PROTECTED_MODE && m_CPL) + FAULT(FAULT_GP, 0); + UINT8 modrm = FETCH(); + UINT8 cr = (modrm >> 3) & 0x7; + UINT32 oldcr = m_cr[cr]; + UINT32 data = LOAD_RM32(modrm); + switch(cr) + { + case 0: + CYCLES(CYCLES_MOV_REG_CR0); + if((oldcr ^ m_cr[cr]) & 0x80010000) + vtlb_flush_dynamic(m_vtlb); + break; + case 2: CYCLES(CYCLES_MOV_REG_CR2); break; + case 3: + CYCLES(CYCLES_MOV_REG_CR3); + vtlb_flush_dynamic(m_vtlb); + break; + case 4: CYCLES(1); break; // TODO + default: + logerror("i386: mov_cr_r32 CR%d!\n", cr); + return; + } + m_cr[cr] = data; +} diff --git a/src/devices/cpu/i386/pentops.inc b/src/devices/cpu/i386/pentops.inc new file mode 100644 index 00000000000..34dad95afda --- /dev/null +++ b/src/devices/cpu/i386/pentops.inc @@ -0,0 +1,6654 @@ +// license:BSD-3-Clause +// copyright-holders:Ville Linde, Barry Rodewald, Carl, Philip Bennett, Samuele Zannoli +// Pentium+ specific opcodes + +extern flag float32_is_nan( float32 a ); // since its not defined in softfloat.h +extern flag float64_is_nan( float64 a ); // since its not defined in softfloat.h + +void i386_device::MMXPROLOG() +{ + //m_x87_sw &= ~(X87_SW_TOP_MASK << X87_SW_TOP_SHIFT); // top = 0 + m_x87_tw = 0; // tag word = 0 +} + +void i386_device::READMMX(UINT32 ea,MMX_REG &r) +{ + r.q=READ64(ea); +} + +void i386_device::WRITEMMX(UINT32 ea,MMX_REG &r) +{ + WRITE64(ea, r.q); +} + +void i386_device::READXMM(UINT32 ea,XMM_REG &r) +{ + r.q[0]=READ64(ea); + r.q[1]=READ64(ea+8); +} + +void i386_device::WRITEXMM(UINT32 ea,i386_device::XMM_REG &r) +{ + WRITE64(ea, r.q[0]); + WRITE64(ea+8, r.q[1]); +} + +void i386_device::READXMM_LO64(UINT32 ea,i386_device::XMM_REG &r) +{ + r.q[0]=READ64(ea); +} + +void i386_device::WRITEXMM_LO64(UINT32 ea,i386_device::XMM_REG &r) +{ + WRITE64(ea, r.q[0]); +} + +void i386_device::READXMM_HI64(UINT32 ea,i386_device::XMM_REG &r) +{ + r.q[1]=READ64(ea); +} + +void i386_device::WRITEXMM_HI64(UINT32 ea,i386_device::XMM_REG &r) +{ + WRITE64(ea, r.q[1]); +} + +void i386_device::pentium_rdmsr() // Opcode 0x0f 32 +{ + UINT64 data; + UINT8 valid_msr = 0; + + data = MSR_READ(REG32(ECX),&valid_msr); + REG32(EDX) = data >> 32; + REG32(EAX) = data & 0xffffffff; + + if(m_CPL != 0 || valid_msr == 0) // if current privilege level isn't 0 or the register isn't recognized ... + FAULT(FAULT_GP,0) // ... throw a general exception fault + + CYCLES(CYCLES_RDMSR); +} + +void i386_device::pentium_wrmsr() // Opcode 0x0f 30 +{ + UINT64 data; + UINT8 valid_msr = 0; + + data = (UINT64)REG32(EAX); + data |= (UINT64)(REG32(EDX)) << 32; + + MSR_WRITE(REG32(ECX),data,&valid_msr); + + if(m_CPL != 0 || valid_msr == 0) // if current privilege level isn't 0 or the register isn't recognized + FAULT(FAULT_GP,0) // ... throw a general exception fault + + CYCLES(1); // TODO: correct cycle count (~30-45) +} + +void i386_device::pentium_rdtsc() // Opcode 0x0f 31 +{ + UINT64 ts = m_tsc + (m_base_cycles - m_cycles); + REG32(EAX) = (UINT32)(ts); + REG32(EDX) = (UINT32)(ts >> 32); + + CYCLES(CYCLES_RDTSC); +} + +void i386_device::pentium_ud2() // Opcode 0x0f 0b +{ + i386_trap(6, 0, 0); +} + +void i386_device::pentium_rsm() +{ + UINT32 smram_state = m_smbase + 0xfe00; + if(!m_smm) + { + logerror("i386: Invalid RSM outside SMM at %08X\n", m_pc - 1); + i386_trap(6, 0, 0); + return; + } + + // load state, no sanity checks anywhere + m_smbase = READ32(smram_state+SMRAM_SMBASE); + m_cr[4] = READ32(smram_state+SMRAM_IP5_CR4); + m_sreg[ES].limit = READ32(smram_state+SMRAM_IP5_ESLIM); + m_sreg[ES].base = READ32(smram_state+SMRAM_IP5_ESBASE); + m_sreg[ES].flags = READ32(smram_state+SMRAM_IP5_ESACC); + m_sreg[CS].limit = READ32(smram_state+SMRAM_IP5_CSLIM); + m_sreg[CS].base = READ32(smram_state+SMRAM_IP5_CSBASE); + m_sreg[CS].flags = READ32(smram_state+SMRAM_IP5_CSACC); + m_sreg[SS].limit = READ32(smram_state+SMRAM_IP5_SSLIM); + m_sreg[SS].base = READ32(smram_state+SMRAM_IP5_SSBASE); + m_sreg[SS].flags = READ32(smram_state+SMRAM_IP5_SSACC); + m_sreg[DS].limit = READ32(smram_state+SMRAM_IP5_DSLIM); + m_sreg[DS].base = READ32(smram_state+SMRAM_IP5_DSBASE); + m_sreg[DS].flags = READ32(smram_state+SMRAM_IP5_DSACC); + m_sreg[FS].limit = READ32(smram_state+SMRAM_IP5_FSLIM); + m_sreg[FS].base = READ32(smram_state+SMRAM_IP5_FSBASE); + m_sreg[FS].flags = READ32(smram_state+SMRAM_IP5_FSACC); + m_sreg[GS].limit = READ32(smram_state+SMRAM_IP5_GSLIM); + m_sreg[GS].base = READ32(smram_state+SMRAM_IP5_GSBASE); + m_sreg[GS].flags = READ32(smram_state+SMRAM_IP5_GSACC); + m_ldtr.flags = READ32(smram_state+SMRAM_IP5_LDTACC); + m_ldtr.limit = READ32(smram_state+SMRAM_IP5_LDTLIM); + m_ldtr.base = READ32(smram_state+SMRAM_IP5_LDTBASE); + m_gdtr.limit = READ32(smram_state+SMRAM_IP5_GDTLIM); + m_gdtr.base = READ32(smram_state+SMRAM_IP5_GDTBASE); + m_idtr.limit = READ32(smram_state+SMRAM_IP5_IDTLIM); + m_idtr.base = READ32(smram_state+SMRAM_IP5_IDTBASE); + m_task.limit = READ32(smram_state+SMRAM_IP5_TRLIM); + m_task.base = READ32(smram_state+SMRAM_IP5_TRBASE); + m_task.flags = READ32(smram_state+SMRAM_IP5_TRACC); + + m_sreg[ES].selector = READ32(smram_state+SMRAM_ES); + m_sreg[CS].selector = READ32(smram_state+SMRAM_CS); + m_sreg[SS].selector = READ32(smram_state+SMRAM_SS); + m_sreg[DS].selector = READ32(smram_state+SMRAM_DS); + m_sreg[FS].selector = READ32(smram_state+SMRAM_FS); + m_sreg[GS].selector = READ32(smram_state+SMRAM_GS); + m_ldtr.segment = READ32(smram_state+SMRAM_LDTR); + m_task.segment = READ32(smram_state+SMRAM_TR); + + m_dr[7] = READ32(smram_state+SMRAM_DR7); + m_dr[6] = READ32(smram_state+SMRAM_DR6); + REG32(EAX) = READ32(smram_state+SMRAM_EAX); + REG32(ECX) = READ32(smram_state+SMRAM_ECX); + REG32(EDX) = READ32(smram_state+SMRAM_EDX); + REG32(EBX) = READ32(smram_state+SMRAM_EBX); + REG32(ESP) = READ32(smram_state+SMRAM_ESP); + REG32(EBP) = READ32(smram_state+SMRAM_EBP); + REG32(ESI) = READ32(smram_state+SMRAM_ESI); + REG32(EDI) = READ32(smram_state+SMRAM_EDI); + m_eip = READ32(smram_state+SMRAM_EIP); + m_eflags = READ32(smram_state+SMRAM_EAX); + m_cr[3] = READ32(smram_state+SMRAM_CR3); + m_cr[0] = READ32(smram_state+SMRAM_CR0); + + m_CPL = (m_sreg[SS].flags >> 13) & 3; // cpl == dpl of ss + + for(int i = 0; i < GS; i++) + { + if(PROTECTED_MODE && !V8086_MODE) + { + m_sreg[i].valid = m_sreg[i].selector ? true : false; + m_sreg[i].d = (m_sreg[i].flags & 0x4000) ? 1 : 0; + } + else + m_sreg[i].valid = true; + } + + if(!m_smiact.isnull()) + m_smiact(false); + m_smm = false; + + CHANGE_PC(m_eip); + m_nmi_masked = false; + if(m_smi_latched) + { + pentium_smi(); + return; + } + if(m_nmi_latched) + { + m_nmi_latched = false; + i386_trap(2, 1, 0); + } +} + +void i386_device::pentium_prefetch_m8() // Opcode 0x0f 18 +{ + UINT8 modrm = FETCH(); + UINT32 ea = GetEA(modrm,0); + CYCLES(1+(ea & 1)); // TODO: correct cycle count +} + +void i386_device::pentium_cmovo_r16_rm16() // Opcode 0x0f 40 +{ + UINT16 src; + UINT8 modrm = FETCH(); + + if( modrm >= 0xc0 ) + { + if (m_OF == 1) + { + src = LOAD_RM16(modrm); + STORE_REG16(modrm, src); + } + CYCLES(1); // TODO: correct cycle count + } + else + { + UINT32 ea = GetEA(modrm,0); + if (m_OF == 1) + { + src = READ16(ea); + STORE_REG16(modrm, src); + } + CYCLES(1); // TODO: correct cycle count + } +} + +void i386_device::pentium_cmovo_r32_rm32() // Opcode 0x0f 40 +{ + UINT32 src; + UINT8 modrm = FETCH(); + + if( modrm >= 0xc0 ) + { + if (m_OF == 1) + { + src = LOAD_RM32(modrm); + STORE_REG32(modrm, src); + } + CYCLES(1); // TODO: correct cycle count + } + else + { + UINT32 ea = GetEA(modrm,0); + if (m_OF == 1) + { + src = READ32(ea); + STORE_REG32(modrm, src); + } + CYCLES(1); // TODO: correct cycle count + } +} + +void i386_device::pentium_cmovno_r16_rm16() // Opcode 0x0f 41 +{ + UINT16 src; + UINT8 modrm = FETCH(); + + if( modrm >= 0xc0 ) + { + if (m_OF == 0) + { + src = LOAD_RM16(modrm); + STORE_REG16(modrm, src); + } + CYCLES(1); // TODO: correct cycle count + } + else + { + UINT32 ea = GetEA(modrm,0); + if (m_OF == 0) + { + src = READ16(ea); + STORE_REG16(modrm, src); + } + CYCLES(1); // TODO: correct cycle count + } +} + +void i386_device::pentium_cmovno_r32_rm32() // Opcode 0x0f 41 +{ + UINT32 src; + UINT8 modrm = FETCH(); + + if( modrm >= 0xc0 ) + { + if (m_OF == 0) + { + src = LOAD_RM32(modrm); + STORE_REG32(modrm, src); + } + CYCLES(1); // TODO: correct cycle count + } + else + { + UINT32 ea = GetEA(modrm,0); + if (m_OF == 0) + { + src = READ32(ea); + STORE_REG32(modrm, src); + } + CYCLES(1); // TODO: correct cycle count + } +} + +void i386_device::pentium_cmovb_r16_rm16() // Opcode 0x0f 42 +{ + UINT16 src; + UINT8 modrm = FETCH(); + + if( modrm >= 0xc0 ) + { + if (m_CF == 1) + { + src = LOAD_RM16(modrm); + STORE_REG16(modrm, src); + } + CYCLES(1); // TODO: correct cycle count + } + else + { + UINT32 ea = GetEA(modrm,0); + if (m_CF == 1) + { + src = READ16(ea); + STORE_REG16(modrm, src); + } + CYCLES(1); // TODO: correct cycle count + } +} + +void i386_device::pentium_cmovb_r32_rm32() // Opcode 0x0f 42 +{ + UINT32 src; + UINT8 modrm = FETCH(); + + if( modrm >= 0xc0 ) + { + if (m_CF == 1) + { + src = LOAD_RM32(modrm); + STORE_REG32(modrm, src); + } + CYCLES(1); // TODO: correct cycle count + } + else + { + UINT32 ea = GetEA(modrm,0); + if (m_CF == 1) + { + src = READ32(ea); + STORE_REG32(modrm, src); + } + CYCLES(1); // TODO: correct cycle count + } +} + +void i386_device::pentium_cmovae_r16_rm16() // Opcode 0x0f 43 +{ + UINT16 src; + UINT8 modrm = FETCH(); + + if( modrm >= 0xc0 ) + { + if (m_CF == 0) + { + src = LOAD_RM16(modrm); + STORE_REG16(modrm, src); + } + CYCLES(1); // TODO: correct cycle count + } + else + { + UINT32 ea = GetEA(modrm,0); + if (m_CF == 0) + { + src = READ16(ea); + STORE_REG16(modrm, src); + } + CYCLES(1); // TODO: correct cycle count + } +} + +void i386_device::pentium_cmovae_r32_rm32() // Opcode 0x0f 43 +{ + UINT32 src; + UINT8 modrm = FETCH(); + + if( modrm >= 0xc0 ) + { + if (m_CF == 0) + { + src = LOAD_RM32(modrm); + STORE_REG32(modrm, src); + } + CYCLES(1); // TODO: correct cycle count + } + else + { + UINT32 ea = GetEA(modrm,0); + if (m_CF == 0) + { + src = READ32(ea); + STORE_REG32(modrm, src); + } + CYCLES(1); // TODO: correct cycle count + } +} + +void i386_device::pentium_cmove_r16_rm16() // Opcode 0x0f 44 +{ + UINT16 src; + UINT8 modrm = FETCH(); + + if( modrm >= 0xc0 ) + { + if (m_ZF == 1) + { + src = LOAD_RM16(modrm); + STORE_REG16(modrm, src); + } + CYCLES(1); // TODO: correct cycle count + } + else + { + UINT32 ea = GetEA(modrm,0); + if (m_ZF == 1) + { + src = READ16(ea); + STORE_REG16(modrm, src); + } + CYCLES(1); // TODO: correct cycle count + } +} + +void i386_device::pentium_cmove_r32_rm32() // Opcode 0x0f 44 +{ + UINT32 src; + UINT8 modrm = FETCH(); + + if( modrm >= 0xc0 ) + { + if (m_ZF == 1) + { + src = LOAD_RM32(modrm); + STORE_REG32(modrm, src); + } + CYCLES(1); // TODO: correct cycle count + } + else + { + UINT32 ea = GetEA(modrm,0); + if (m_ZF == 1) + { + src = READ32(ea); + STORE_REG32(modrm, src); + } + CYCLES(1); // TODO: correct cycle count + } +} + +void i386_device::pentium_cmovne_r16_rm16() // Opcode 0x0f 45 +{ + UINT16 src; + UINT8 modrm = FETCH(); + + if( modrm >= 0xc0 ) + { + if (m_ZF == 0) + { + src = LOAD_RM16(modrm); + STORE_REG16(modrm, src); + } + CYCLES(1); // TODO: correct cycle count + } + else + { + UINT32 ea = GetEA(modrm,0); + if (m_ZF == 0) + { + src = READ16(ea); + STORE_REG16(modrm, src); + } + CYCLES(1); // TODO: correct cycle count + } +} + +void i386_device::pentium_cmovne_r32_rm32() // Opcode 0x0f 45 +{ + UINT32 src; + UINT8 modrm = FETCH(); + + if( modrm >= 0xc0 ) + { + if (m_ZF == 0) + { + src = LOAD_RM32(modrm); + STORE_REG32(modrm, src); + } + CYCLES(1); // TODO: correct cycle count + } + else + { + UINT32 ea = GetEA(modrm,0); + if (m_ZF == 0) + { + src = READ32(ea); + STORE_REG32(modrm, src); + } + CYCLES(1); // TODO: correct cycle count + } +} + +void i386_device::pentium_cmovbe_r16_rm16() // Opcode 0x0f 46 +{ + UINT16 src; + UINT8 modrm = FETCH(); + + if( modrm >= 0xc0 ) + { + if ((m_CF == 1) || (m_ZF == 1)) + { + src = LOAD_RM16(modrm); + STORE_REG16(modrm, src); + } + CYCLES(1); // TODO: correct cycle count + } + else + { + UINT32 ea = GetEA(modrm,0); + if ((m_CF == 1) || (m_ZF == 1)) + { + src = READ16(ea); + STORE_REG16(modrm, src); + } + CYCLES(1); // TODO: correct cycle count + } +} + +void i386_device::pentium_cmovbe_r32_rm32() // Opcode 0x0f 46 +{ + UINT32 src; + UINT8 modrm = FETCH(); + + if( modrm >= 0xc0 ) + { + if ((m_CF == 1) || (m_ZF == 1)) + { + src = LOAD_RM32(modrm); + STORE_REG32(modrm, src); + } + CYCLES(1); // TODO: correct cycle count + } + else + { + UINT32 ea = GetEA(modrm,0); + if ((m_CF == 1) || (m_ZF == 1)) + { + src = READ32(ea); + STORE_REG32(modrm, src); + } + CYCLES(1); // TODO: correct cycle count + } +} + +void i386_device::pentium_cmova_r16_rm16() // Opcode 0x0f 47 +{ + UINT16 src; + UINT8 modrm = FETCH(); + + if( modrm >= 0xc0 ) + { + if ((m_CF == 0) && (m_ZF == 0)) + { + src = LOAD_RM16(modrm); + STORE_REG16(modrm, src); + } + CYCLES(1); // TODO: correct cycle count + } + else + { + UINT32 ea = GetEA(modrm,0); + if ((m_CF == 0) && (m_ZF == 0)) + { + src = READ16(ea); + STORE_REG16(modrm, src); + } + CYCLES(1); // TODO: correct cycle count + } +} + +void i386_device::pentium_cmova_r32_rm32() // Opcode 0x0f 47 +{ + UINT32 src; + UINT8 modrm = FETCH(); + + if( modrm >= 0xc0 ) + { + if ((m_CF == 0) && (m_ZF == 0)) + { + src = LOAD_RM32(modrm); + STORE_REG32(modrm, src); + } + CYCLES(1); // TODO: correct cycle count + } + else + { + UINT32 ea = GetEA(modrm,0); + if ((m_CF == 0) && (m_ZF == 0)) + { + src = READ32(ea); + STORE_REG32(modrm, src); + } + CYCLES(1); // TODO: correct cycle count + } +} + +void i386_device::pentium_cmovs_r16_rm16() // Opcode 0x0f 48 +{ + UINT16 src; + UINT8 modrm = FETCH(); + + if( modrm >= 0xc0 ) + { + if (m_SF == 1) + { + src = LOAD_RM16(modrm); + STORE_REG16(modrm, src); + } + CYCLES(1); // TODO: correct cycle count + } + else + { + UINT32 ea = GetEA(modrm,0); + if (m_SF == 1) + { + src = READ16(ea); + STORE_REG16(modrm, src); + } + CYCLES(1); // TODO: correct cycle count + } +} + +void i386_device::pentium_cmovs_r32_rm32() // Opcode 0x0f 48 +{ + UINT32 src; + UINT8 modrm = FETCH(); + + if( modrm >= 0xc0 ) + { + if (m_SF == 1) + { + src = LOAD_RM32(modrm); + STORE_REG32(modrm, src); + } + CYCLES(1); // TODO: correct cycle count + } + else + { + UINT32 ea = GetEA(modrm,0); + if (m_SF == 1) + { + src = READ32(ea); + STORE_REG32(modrm, src); + } + CYCLES(1); // TODO: correct cycle count + } +} + +void i386_device::pentium_cmovns_r16_rm16() // Opcode 0x0f 49 +{ + UINT16 src; + UINT8 modrm = FETCH(); + + if( modrm >= 0xc0 ) + { + if (m_SF == 0) + { + src = LOAD_RM16(modrm); + STORE_REG16(modrm, src); + } + CYCLES(1); // TODO: correct cycle count + } + else + { + UINT32 ea = GetEA(modrm,0); + if (m_SF == 0) + { + src = READ16(ea); + STORE_REG16(modrm, src); + } + CYCLES(1); // TODO: correct cycle count + } +} + +void i386_device::pentium_cmovns_r32_rm32() // Opcode 0x0f 49 +{ + UINT32 src; + UINT8 modrm = FETCH(); + + if( modrm >= 0xc0 ) + { + if (m_SF == 0) + { + src = LOAD_RM32(modrm); + STORE_REG32(modrm, src); + } + CYCLES(1); // TODO: correct cycle count + } + else + { + UINT32 ea = GetEA(modrm,0); + if (m_SF == 0) + { + src = READ32(ea); + STORE_REG32(modrm, src); + } + CYCLES(1); // TODO: correct cycle count + } +} + +void i386_device::pentium_cmovp_r16_rm16() // Opcode 0x0f 4a +{ + UINT16 src; + UINT8 modrm = FETCH(); + + if( modrm >= 0xc0 ) + { + if (m_PF == 1) + { + src = LOAD_RM16(modrm); + STORE_REG16(modrm, src); + } + CYCLES(1); // TODO: correct cycle count + } + else + { + UINT32 ea = GetEA(modrm,0); + if (m_PF == 1) + { + src = READ16(ea); + STORE_REG16(modrm, src); + } + CYCLES(1); // TODO: correct cycle count + } +} + +void i386_device::pentium_cmovp_r32_rm32() // Opcode 0x0f 4a +{ + UINT32 src; + UINT8 modrm = FETCH(); + + if( modrm >= 0xc0 ) + { + if (m_PF == 1) + { + src = LOAD_RM32(modrm); + STORE_REG32(modrm, src); + } + CYCLES(1); // TODO: correct cycle count + } + else + { + UINT32 ea = GetEA(modrm,0); + if (m_PF == 1) + { + src = READ32(ea); + STORE_REG32(modrm, src); + } + CYCLES(1); // TODO: correct cycle count + } +} + +void i386_device::pentium_cmovnp_r16_rm16() // Opcode 0x0f 4b +{ + UINT16 src; + UINT8 modrm = FETCH(); + + if( modrm >= 0xc0 ) + { + if (m_PF == 0) + { + src = LOAD_RM16(modrm); + STORE_REG16(modrm, src); + } + CYCLES(1); // TODO: correct cycle count + } + else + { + UINT32 ea = GetEA(modrm,0); + if (m_PF == 0) + { + src = READ16(ea); + STORE_REG16(modrm, src); + } + CYCLES(1); // TODO: correct cycle count + } +} + +void i386_device::pentium_cmovnp_r32_rm32() // Opcode 0x0f 4b +{ + UINT32 src; + UINT8 modrm = FETCH(); + + if( modrm >= 0xc0 ) + { + if (m_PF == 0) + { + src = LOAD_RM32(modrm); + STORE_REG32(modrm, src); + } + CYCLES(1); // TODO: correct cycle count + } + else + { + UINT32 ea = GetEA(modrm,0); + if (m_PF == 0) + { + src = READ32(ea); + STORE_REG32(modrm, src); + } + CYCLES(1); // TODO: correct cycle count + } +} + +void i386_device::pentium_cmovl_r16_rm16() // Opcode 0x0f 4c +{ + UINT16 src; + UINT8 modrm = FETCH(); + + if( modrm >= 0xc0 ) + { + if (m_SF != m_OF) + { + src = LOAD_RM16(modrm); + STORE_REG16(modrm, src); + } + CYCLES(1); // TODO: correct cycle count + } + else + { + UINT32 ea = GetEA(modrm,0); + if (m_SF != m_OF) + { + src = READ16(ea); + STORE_REG16(modrm, src); + } + CYCLES(1); // TODO: correct cycle count + } +} + +void i386_device::pentium_cmovl_r32_rm32() // Opcode 0x0f 4c +{ + UINT32 src; + UINT8 modrm = FETCH(); + + if( modrm >= 0xc0 ) + { + if (m_SF != m_OF) + { + src = LOAD_RM32(modrm); + STORE_REG32(modrm, src); + } + CYCLES(1); // TODO: correct cycle count + } + else + { + UINT32 ea = GetEA(modrm,0); + if (m_SF != m_OF) + { + src = READ32(ea); + STORE_REG32(modrm, src); + } + CYCLES(1); // TODO: correct cycle count + } +} + +void i386_device::pentium_cmovge_r16_rm16() // Opcode 0x0f 4d +{ + UINT16 src; + UINT8 modrm = FETCH(); + + if( modrm >= 0xc0 ) + { + if (m_SF == m_OF) + { + src = LOAD_RM16(modrm); + STORE_REG16(modrm, src); + } + CYCLES(1); // TODO: correct cycle count + } + else + { + UINT32 ea = GetEA(modrm,0); + if (m_SF == m_OF) + { + src = READ16(ea); + STORE_REG16(modrm, src); + } + CYCLES(1); // TODO: correct cycle count + } +} + +void i386_device::pentium_cmovge_r32_rm32() // Opcode 0x0f 4d +{ + UINT32 src; + UINT8 modrm = FETCH(); + + if( modrm >= 0xc0 ) + { + if (m_SF == m_OF) + { + src = LOAD_RM32(modrm); + STORE_REG32(modrm, src); + } + CYCLES(1); // TODO: correct cycle count + } + else + { + UINT32 ea = GetEA(modrm,0); + if (m_SF == m_OF) + { + src = READ32(ea); + STORE_REG32(modrm, src); + } + CYCLES(1); // TODO: correct cycle count + } +} + +void i386_device::pentium_cmovle_r16_rm16() // Opcode 0x0f 4e +{ + UINT16 src; + UINT8 modrm = FETCH(); + + if( modrm >= 0xc0 ) + { + if ((m_ZF == 1) || (m_SF != m_OF)) + { + src = LOAD_RM16(modrm); + STORE_REG16(modrm, src); + } + CYCLES(1); // TODO: correct cycle count + } + else + { + UINT32 ea = GetEA(modrm,0); + if ((m_ZF == 1) || (m_SF != m_OF)) + { + src = READ16(ea); + STORE_REG16(modrm, src); + } + CYCLES(1); // TODO: correct cycle count + } +} + +void i386_device::pentium_cmovle_r32_rm32() // Opcode 0x0f 4e +{ + UINT32 src; + UINT8 modrm = FETCH(); + + if( modrm >= 0xc0 ) + { + if ((m_ZF == 1) || (m_SF != m_OF)) + { + src = LOAD_RM32(modrm); + STORE_REG32(modrm, src); + } + CYCLES(1); // TODO: correct cycle count + } + else + { + UINT32 ea = GetEA(modrm,0); + if ((m_ZF == 1) || (m_SF != m_OF)) + { + src = READ32(ea); + STORE_REG32(modrm, src); + } + CYCLES(1); // TODO: correct cycle count + } +} + +void i386_device::pentium_cmovg_r16_rm16() // Opcode 0x0f 4f +{ + UINT16 src; + UINT8 modrm = FETCH(); + + if( modrm >= 0xc0 ) + { + if ((m_ZF == 0) && (m_SF == m_OF)) + { + src = LOAD_RM16(modrm); + STORE_REG16(modrm, src); + } + CYCLES(1); // TODO: correct cycle count + } + else + { + UINT32 ea = GetEA(modrm,0); + if ((m_ZF == 0) && (m_SF == m_OF)) + { + src = READ16(ea); + STORE_REG16(modrm, src); + } + CYCLES(1); // TODO: correct cycle count + } +} + +void i386_device::pentium_cmovg_r32_rm32() // Opcode 0x0f 4f +{ + UINT32 src; + UINT8 modrm = FETCH(); + + if( modrm >= 0xc0 ) + { + if ((m_ZF == 0) && (m_SF == m_OF)) + { + src = LOAD_RM32(modrm); + STORE_REG32(modrm, src); + } + CYCLES(1); // TODO: correct cycle count + } + else + { + UINT32 ea = GetEA(modrm,0); + if ((m_ZF == 0) && (m_SF == m_OF)) + { + src = READ32(ea); + STORE_REG32(modrm, src); + } + CYCLES(1); // TODO: correct cycle count + } +} + +void i386_device::pentium_movnti_m16_r16() // Opcode 0f c3 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + // unsupported by cpu + CYCLES(1); // TODO: correct cycle count + } else { + // since cache is not implemented + UINT32 ea = GetEA(modrm, 0); + WRITE16(ea,LOAD_RM16(modrm)); + CYCLES(1); // TODO: correct cycle count + } +} + +void i386_device::pentium_movnti_m32_r32() // Opcode 0f c3 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + // unsupported by cpu + CYCLES(1); // TODO: correct cycle count + } else { + // since cache is not implemented + UINT32 ea = GetEA(modrm, 0); + WRITE32(ea,LOAD_RM32(modrm)); + CYCLES(1); // TODO: correct cycle count + } +} + +void i386_device::i386_cyrix_special() // Opcode 0x0f 3a-3d +{ +/* +0f 3a BB0_RESET (set BB0 pointer = base) +0f 3b BB1_RESET (set BB1 pointer = base) +0f 3c CPU_WRITE (write special CPU memory-mapped register, [ebx] = eax) +0f 3d CPU_READ (read special CPU memory-mapped register, eax, = [ebx]) +*/ + + CYCLES(1); +} + +void i386_device::i386_cyrix_unknown() // Opcode 0x0f 74 +{ + logerror("Unemulated 0x0f 0x74 opcode called\n"); + + CYCLES(1); +} + +void i386_device::pentium_cmpxchg8b_m64() // Opcode 0x0f c7 +{ + UINT8 modm = FETCH(); + if( modm >= 0xc0 ) { + report_invalid_modrm("cmpxchg8b_m64", modm); + } else { + UINT32 ea = GetEA(modm, 0); + UINT64 value = READ64(ea); + UINT64 edx_eax = (((UINT64) REG32(EDX)) << 32) | REG32(EAX); + UINT64 ecx_ebx = (((UINT64) REG32(ECX)) << 32) | REG32(EBX); + + if( value == edx_eax ) { + WRITE64(ea, ecx_ebx); + m_ZF = 1; + CYCLES(CYCLES_CMPXCHG_REG_MEM_T); + } else { + REG32(EDX) = (UINT32) (value >> 32); + REG32(EAX) = (UINT32) (value >> 0); + m_ZF = 0; + CYCLES(CYCLES_CMPXCHG_REG_MEM_F); + } + } +} + +void i386_device::pentium_movntq_m64_r64() // Opcode 0f e7 +{ + //MMXPROLOG(); // TODO: check if needed + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + CYCLES(1); // unsupported + } else { + // since cache is not implemented + UINT32 ea = GetEA(modrm, 0); + WRITEMMX(ea, MMX((modrm >> 3) & 0x7)); + CYCLES(1); // TODO: correct cycle count + } +} + +void i386_device::pentium_maskmovq_r64_r64() // Opcode 0f f7 +{ + int s,m,n; + UINT8 modm = FETCH(); + UINT32 ea = GetEA(7, 0); // ds:di/edi/rdi register + MMXPROLOG(); + s=(modm >> 3) & 7; + m=modm & 7; + for (n=0;n <= 7;n++) + if (MMX(m).b[n] & 127) + WRITE8(ea+n, MMX(s).b[n]); +} + +void i386_device::sse_maskmovdqu_r128_r128() // Opcode 66 0f f7 +{ + int s,m,n; + UINT8 modm = FETCH(); + UINT32 ea = GetEA(7, 0); // ds:di/edi/rdi register + s=(modm >> 3) & 7; + m=modm & 7; + for (n=0;n < 16;n++) + if (XMM(m).b[n] & 127) + WRITE8(ea+n, XMM(s).b[n]); +} + +void i386_device::pentium_popcnt_r16_rm16() // Opcode f3 0f b8 +{ + UINT16 src; + UINT8 modrm = FETCH(); + int n,count; + + if( modrm >= 0xc0 ) { + src = LOAD_RM16(modrm); + } else { + UINT32 ea = GetEA(modrm,0); + src = READ16(ea); + } + count=0; + for (n=0;n < 16;n++) { + count=count+(src & 1); + src=src >> 1; + } + STORE_REG16(modrm, count); + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::pentium_popcnt_r32_rm32() // Opcode f3 0f b8 +{ + UINT32 src; + UINT8 modrm = FETCH(); + int n,count; + + if( modrm >= 0xc0 ) { + src = LOAD_RM32(modrm); + } else { + UINT32 ea = GetEA(modrm,0); + src = READ32(ea); + } + count=0; + for (n=0;n < 32;n++) { + count=count+(src & 1); + src=src >> 1; + } + STORE_REG32(modrm, count); + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::pentium_tzcnt_r16_rm16() +{ + // for CPUs that don't support TZCNT, fall back to BSF + i386_bsf_r16_rm16(); + // TODO: actually implement TZCNT +} + +void i386_device::pentium_tzcnt_r32_rm32() +{ + // for CPUs that don't support TZCNT, fall back to BSF + i386_bsf_r32_rm32(); + // TODO: actually implement TZCNT +} + +INLINE INT8 SaturatedSignedWordToSignedByte(INT16 word) +{ + if (word > 127) + return 127; + if (word < -128) + return -128; + return (INT8)word; +} + +INLINE UINT8 SaturatedSignedWordToUnsignedByte(INT16 word) +{ + if (word > 255) + return 255; + if (word < 0) + return 0; + return (UINT8)word; +} + +INLINE INT16 SaturatedSignedDwordToSignedWord(INT32 dword) +{ + if (dword > 32767) + return 32767; + if (dword < -32768) + return -32768; + return (INT16)dword; +} + +INLINE UINT16 SaturatedSignedDwordToUnsignedWord(INT32 dword) +{ + if (dword > 65535) + return 65535; + if (dword < 0) + return 0; + return (UINT16)dword; +} + +void i386_device::mmx_group_0f71() // Opcode 0f 71 +{ + UINT8 modm = FETCH(); + UINT8 imm8 = FETCH(); + MMXPROLOG(); + if( modm >= 0xc0 ) { + switch ( (modm & 0x38) >> 3 ) + { + case 2: // psrlw + MMX(modm & 7).w[0]=MMX(modm & 7).w[0] >> imm8; + MMX(modm & 7).w[1]=MMX(modm & 7).w[1] >> imm8; + MMX(modm & 7).w[2]=MMX(modm & 7).w[2] >> imm8; + MMX(modm & 7).w[3]=MMX(modm & 7).w[3] >> imm8; + break; + case 4: // psraw + MMX(modm & 7).s[0]=MMX(modm & 7).s[0] >> imm8; + MMX(modm & 7).s[1]=MMX(modm & 7).s[1] >> imm8; + MMX(modm & 7).s[2]=MMX(modm & 7).s[2] >> imm8; + MMX(modm & 7).s[3]=MMX(modm & 7).s[3] >> imm8; + break; + case 6: // psllw + MMX(modm & 7).w[0]=MMX(modm & 7).w[0] << imm8; + MMX(modm & 7).w[1]=MMX(modm & 7).w[1] << imm8; + MMX(modm & 7).w[2]=MMX(modm & 7).w[2] << imm8; + MMX(modm & 7).w[3]=MMX(modm & 7).w[3] << imm8; + break; + default: + report_invalid_modrm("mmx_group0f71", modm); + } + } +} + +void i386_device::sse_group_660f71() // Opcode 66 0f 71 +{ + UINT8 modm = FETCH(); + UINT8 imm8 = FETCH(); + if (modm >= 0xc0) { + switch ((modm & 0x38) >> 3) + { + case 2: // psrlw + for (int n = 0; n < 8;n++) + XMM(modm & 7).w[n] = XMM(modm & 7).w[n] >> imm8; + break; + case 4: // psraw + for (int n = 0; n < 8;n++) + XMM(modm & 7).s[n] = XMM(modm & 7).s[n] >> imm8; + break; + case 6: // psllw + for (int n = 0; n < 8;n++) + XMM(modm & 7).w[n] = XMM(modm & 7).w[n] << imm8; + break; + default: + report_invalid_modrm("mmx_group660f71", modm); + } + } +} + +void i386_device::mmx_group_0f72() // Opcode 0f 72 +{ + UINT8 modm = FETCH(); + UINT8 imm8 = FETCH(); + MMXPROLOG(); + if( modm >= 0xc0 ) { + switch ( (modm & 0x38) >> 3 ) + { + case 2: // psrld + MMX(modm & 7).d[0]=MMX(modm & 7).d[0] >> imm8; + MMX(modm & 7).d[1]=MMX(modm & 7).d[1] >> imm8; + break; + case 4: // psrad + MMX(modm & 7).i[0]=MMX(modm & 7).i[0] >> imm8; + MMX(modm & 7).i[1]=MMX(modm & 7).i[1] >> imm8; + break; + case 6: // pslld + MMX(modm & 7).d[0]=MMX(modm & 7).d[0] << imm8; + MMX(modm & 7).d[1]=MMX(modm & 7).d[1] << imm8; + break; + default: + report_invalid_modrm("mmx_group0f72", modm); + } + } +} + +void i386_device::sse_group_660f72() // Opcode 66 0f 72 +{ + UINT8 modm = FETCH(); + UINT8 imm8 = FETCH(); + if (modm >= 0xc0) { + switch ((modm & 0x38) >> 3) + { + case 2: // psrld + for (int n = 0; n < 4;n++) + XMM(modm & 7).d[n] = XMM(modm & 7).d[n] >> imm8; + break; + case 4: // psrad + for (int n = 0; n < 4;n++) + XMM(modm & 7).i[n] = XMM(modm & 7).i[n] >> imm8; + break; + case 6: // pslld + for (int n = 0; n < 4;n++) + XMM(modm & 7).d[n] = XMM(modm & 7).d[n] << imm8; + break; + default: + report_invalid_modrm("mmx_group660f72", modm); + } + } +} + +void i386_device::mmx_group_0f73() // Opcode 0f 73 +{ + UINT8 modm = FETCH(); + UINT8 imm8 = FETCH(); + MMXPROLOG(); + if( modm >= 0xc0 ) { + switch ( (modm & 0x38) >> 3 ) + { + case 2: // psrlq + MMX(modm & 7).q = imm8 > 63 ? 0 : MMX(modm & 7).q >> imm8; + break; + case 6: // psllq + MMX(modm & 7).q = imm8 > 63 ? 0 : MMX(modm & 7).q << imm8; + break; + default: + report_invalid_modrm("mmx_group0f73", modm); + } + } +} + +void i386_device::sse_group_660f73() // Opcode 66 0f 73 +{ + UINT64 t0; + UINT8 modm = FETCH(); + UINT8 imm8 = FETCH(); + if (modm >= 0xc0) { + switch ((modm & 0x38) >> 3) + { + case 2: // psrlq + XMM(modm & 7).q[0] = imm8 > 63 ? 0 : XMM(modm & 7).q[0] >> imm8; + XMM(modm & 7).q[1] = imm8 > 63 ? 0 : XMM(modm & 7).q[1] >> imm8; + break; + case 3: // psrldq + if (imm8 >= 16) + { + XMM(modm & 7).q[0] = 0; + XMM(modm & 7).q[1] = 0; + } + else if (imm8 >= 8) + { + imm8 = (imm8 & 7) << 3; + XMM(modm & 7).q[0] = XMM(modm & 7).q[1] >> imm8; + XMM(modm & 7).q[1] = 0; + } + else if (imm8) + { + t0 = XMM(modm & 7).q[0]; + imm8 = imm8 << 3; + XMM(modm & 7).q[0] = (XMM(modm & 7).q[1] << (64 - imm8)) | (t0 >> imm8); + XMM(modm & 7).q[1] = t0 >> imm8; + } + break; + case 6: // psllq + XMM(modm & 7).q[0] = imm8 > 63 ? 0 : XMM(modm & 7).q[0] << imm8; + XMM(modm & 7).q[1] = imm8 > 63 ? 0 : XMM(modm & 7).q[1] << imm8; + break; + case 7: // pslldq + if (imm8 >= 16) + { + XMM(modm & 7).q[0] = 0; + XMM(modm & 7).q[1] = 0; + } + else if (imm8 >= 8) + { + imm8 = (imm8 & 7) << 3; + XMM(modm & 7).q[1] = XMM(modm & 7).q[0] << imm8; + XMM(modm & 7).q[0] = 0; + } + else if (imm8) + { + imm8 = imm8 << 3; + XMM(modm & 7).q[1] = (XMM(modm & 7).q[0] >> (64 - imm8)) | (XMM(modm & 7).q[1] << imm8); + XMM(modm & 7).q[0] = XMM(modm & 7).q[0] << imm8; + } + break; + default: + report_invalid_modrm("sse_group660f73", modm); + } + } +} + +void i386_device::mmx_psrlw_r64_rm64() // Opcode 0f d1 +{ + MMXPROLOG(); + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + int count=(int)MMX(modrm & 7).q; + MMX((modrm >> 3) & 0x7).w[0]=MMX((modrm >> 3) & 0x7).w[0] >> count; + MMX((modrm >> 3) & 0x7).w[1]=MMX((modrm >> 3) & 0x7).w[1] >> count; + MMX((modrm >> 3) & 0x7).w[2]=MMX((modrm >> 3) & 0x7).w[2] >> count; + MMX((modrm >> 3) & 0x7).w[3]=MMX((modrm >> 3) & 0x7).w[3] >> count; + } else { + MMX_REG src; + UINT32 ea = GetEA(modrm, 0); + READMMX(ea, src); + int count=(int)src.q; + MMX((modrm >> 3) & 0x7).w[0]=MMX((modrm >> 3) & 0x7).w[0] >> count; + MMX((modrm >> 3) & 0x7).w[1]=MMX((modrm >> 3) & 0x7).w[1] >> count; + MMX((modrm >> 3) & 0x7).w[2]=MMX((modrm >> 3) & 0x7).w[2] >> count; + MMX((modrm >> 3) & 0x7).w[3]=MMX((modrm >> 3) & 0x7).w[3] >> count; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::mmx_psrld_r64_rm64() // Opcode 0f d2 +{ + MMXPROLOG(); + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + int count=(int)MMX(modrm & 7).q; + MMX((modrm >> 3) & 0x7).d[0]=MMX((modrm >> 3) & 0x7).d[0] >> count; + MMX((modrm >> 3) & 0x7).d[1]=MMX((modrm >> 3) & 0x7).d[1] >> count; + } else { + MMX_REG src; + UINT32 ea = GetEA(modrm, 0); + READMMX(ea, src); + int count=(int)src.q; + MMX((modrm >> 3) & 0x7).d[0]=MMX((modrm >> 3) & 0x7).d[0] >> count; + MMX((modrm >> 3) & 0x7).d[1]=MMX((modrm >> 3) & 0x7).d[1] >> count; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::mmx_psrlq_r64_rm64() // Opcode 0f d3 +{ + MMXPROLOG(); + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + int count=(int)MMX(modrm & 7).q; + MMX((modrm >> 3) & 0x7).q=MMX((modrm >> 3) & 0x7).q >> count; + } else { + MMX_REG src; + UINT32 ea = GetEA(modrm, 0); + READMMX(ea, src); + int count=(int)src.q; + MMX((modrm >> 3) & 0x7).q=MMX((modrm >> 3) & 0x7).q >> count; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::mmx_paddq_r64_rm64() // Opcode 0f d4 +{ + MMXPROLOG(); + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + MMX((modrm >> 3) & 0x7).q=MMX((modrm >> 3) & 0x7).q+MMX(modrm & 7).q; + } else { + MMX_REG src; + UINT32 ea = GetEA(modrm, 0); + READMMX(ea, src); + MMX((modrm >> 3) & 0x7).q=MMX((modrm >> 3) & 0x7).q+src.q; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::mmx_pmullw_r64_rm64() // Opcode 0f d5 +{ + MMXPROLOG(); + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + MMX((modrm >> 3) & 0x7).w[0]=(UINT32)((INT32)MMX((modrm >> 3) & 0x7).s[0]*(INT32)MMX(modrm & 7).s[0]) & 0xffff; + MMX((modrm >> 3) & 0x7).w[1]=(UINT32)((INT32)MMX((modrm >> 3) & 0x7).s[1]*(INT32)MMX(modrm & 7).s[1]) & 0xffff; + MMX((modrm >> 3) & 0x7).w[2]=(UINT32)((INT32)MMX((modrm >> 3) & 0x7).s[2]*(INT32)MMX(modrm & 7).s[2]) & 0xffff; + MMX((modrm >> 3) & 0x7).w[3]=(UINT32)((INT32)MMX((modrm >> 3) & 0x7).s[3]*(INT32)MMX(modrm & 7).s[3]) & 0xffff; + } else { + MMX_REG src; + UINT32 ea = GetEA(modrm, 0); + READMMX(ea, src); + MMX((modrm >> 3) & 0x7).w[0]=(UINT32)((INT32)MMX((modrm >> 3) & 0x7).s[0]*(INT32)src.s[0]) & 0xffff; + MMX((modrm >> 3) & 0x7).w[1]=(UINT32)((INT32)MMX((modrm >> 3) & 0x7).s[1]*(INT32)src.s[1]) & 0xffff; + MMX((modrm >> 3) & 0x7).w[2]=(UINT32)((INT32)MMX((modrm >> 3) & 0x7).s[2]*(INT32)src.s[2]) & 0xffff; + MMX((modrm >> 3) & 0x7).w[3]=(UINT32)((INT32)MMX((modrm >> 3) & 0x7).s[3]*(INT32)src.s[3]) & 0xffff; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::mmx_psubusb_r64_rm64() // Opcode 0f d8 +{ + int n; + MMXPROLOG(); + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + for (n=0;n < 8;n++) + MMX((modrm >> 3) & 0x7).b[n]=MMX((modrm >> 3) & 0x7).b[n] < MMX(modrm & 7).b[n] ? 0 : MMX((modrm >> 3) & 0x7).b[n]-MMX(modrm & 7).b[n]; + } else { + MMX_REG src; + UINT32 ea = GetEA(modrm, 0); + READMMX(ea, src); + for (n=0;n < 8;n++) + MMX((modrm >> 3) & 0x7).b[n]=MMX((modrm >> 3) & 0x7).b[n] < src.b[n] ? 0 : MMX((modrm >> 3) & 0x7).b[n]-src.b[n]; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::mmx_psubusw_r64_rm64() // Opcode 0f d9 +{ + int n; + MMXPROLOG(); + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + for (n=0;n < 4;n++) + MMX((modrm >> 3) & 0x7).w[n]=MMX((modrm >> 3) & 0x7).w[n] < MMX(modrm & 7).w[n] ? 0 : MMX((modrm >> 3) & 0x7).w[n]-MMX(modrm & 7).w[n]; + } else { + MMX_REG src; + UINT32 ea = GetEA(modrm, 0); + READMMX(ea, src); + for (n=0;n < 4;n++) + MMX((modrm >> 3) & 0x7).w[n]=MMX((modrm >> 3) & 0x7).w[n] < src.w[n] ? 0 : MMX((modrm >> 3) & 0x7).w[n]-src.w[n]; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::mmx_pand_r64_rm64() // Opcode 0f db +{ + MMXPROLOG(); + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + MMX((modrm >> 3) & 0x7).q=MMX((modrm >> 3) & 0x7).q & MMX(modrm & 7).q; + } else { + MMX_REG src; + UINT32 ea = GetEA(modrm, 0); + READMMX(ea, src); + MMX((modrm >> 3) & 0x7).q=MMX((modrm >> 3) & 0x7).q & src.q; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::mmx_paddusb_r64_rm64() // Opcode 0f dc +{ + int n; + MMXPROLOG(); + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + for (n=0;n < 8;n++) + MMX((modrm >> 3) & 0x7).b[n]=MMX((modrm >> 3) & 0x7).b[n] > (0xff-MMX(modrm & 7).b[n]) ? 0xff : MMX((modrm >> 3) & 0x7).b[n]+MMX(modrm & 7).b[n]; + } else { + MMX_REG src; + UINT32 ea = GetEA(modrm, 0); + READMMX(ea, src); + for (n=0;n < 8;n++) + MMX((modrm >> 3) & 0x7).b[n]=MMX((modrm >> 3) & 0x7).b[n] > (0xff-src.b[n]) ? 0xff : MMX((modrm >> 3) & 0x7).b[n]+src.b[n]; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::mmx_paddusw_r64_rm64() // Opcode 0f dd +{ + int n; + MMXPROLOG(); + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + for (n=0;n < 4;n++) + MMX((modrm >> 3) & 0x7).w[n]=MMX((modrm >> 3) & 0x7).w[n] > (0xffff-MMX(modrm & 7).w[n]) ? 0xffff : MMX((modrm >> 3) & 0x7).w[n]+MMX(modrm & 7).w[n]; + } else { + MMX_REG src; + UINT32 ea = GetEA(modrm, 0); + READMMX(ea, src); + for (n=0;n < 4;n++) + MMX((modrm >> 3) & 0x7).w[n]=MMX((modrm >> 3) & 0x7).w[n] > (0xffff-src.w[n]) ? 0xffff : MMX((modrm >> 3) & 0x7).w[n]+src.w[n]; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::mmx_pandn_r64_rm64() // Opcode 0f df +{ + MMXPROLOG(); + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + MMX((modrm >> 3) & 0x7).q=(~MMX((modrm >> 3) & 0x7).q) & MMX(modrm & 7).q; + } else { + MMX_REG src; + UINT32 ea = GetEA(modrm, 0); + READMMX(ea, src); + MMX((modrm >> 3) & 0x7).q=(~MMX((modrm >> 3) & 0x7).q) & src.q; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::mmx_psraw_r64_rm64() // Opcode 0f e1 +{ + MMXPROLOG(); + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + int count=(int)MMX(modrm & 7).q; + MMX((modrm >> 3) & 0x7).s[0]=MMX((modrm >> 3) & 0x7).s[0] >> count; + MMX((modrm >> 3) & 0x7).s[1]=MMX((modrm >> 3) & 0x7).s[1] >> count; + MMX((modrm >> 3) & 0x7).s[2]=MMX((modrm >> 3) & 0x7).s[2] >> count; + MMX((modrm >> 3) & 0x7).s[3]=MMX((modrm >> 3) & 0x7).s[3] >> count; + } else { + MMX_REG src; + UINT32 ea = GetEA(modrm, 0); + READMMX(ea, src); + int count=(int)src.q; + MMX((modrm >> 3) & 0x7).s[0]=MMX((modrm >> 3) & 0x7).s[0] >> count; + MMX((modrm >> 3) & 0x7).s[1]=MMX((modrm >> 3) & 0x7).s[1] >> count; + MMX((modrm >> 3) & 0x7).s[2]=MMX((modrm >> 3) & 0x7).s[2] >> count; + MMX((modrm >> 3) & 0x7).s[3]=MMX((modrm >> 3) & 0x7).s[3] >> count; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::mmx_psrad_r64_rm64() // Opcode 0f e2 +{ + MMXPROLOG(); + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + int count=(int)MMX(modrm & 7).q; + MMX((modrm >> 3) & 0x7).i[0]=MMX((modrm >> 3) & 0x7).i[0] >> count; + MMX((modrm >> 3) & 0x7).i[1]=MMX((modrm >> 3) & 0x7).i[1] >> count; + } else { + MMX_REG src; + UINT32 ea = GetEA(modrm, 0); + READMMX(ea, src); + int count=(int)src.q; + MMX((modrm >> 3) & 0x7).i[0]=MMX((modrm >> 3) & 0x7).i[0] >> count; + MMX((modrm >> 3) & 0x7).i[1]=MMX((modrm >> 3) & 0x7).i[1] >> count; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::mmx_pmulhw_r64_rm64() // Opcode 0f e5 +{ + MMXPROLOG(); + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + MMX((modrm >> 3) & 0x7).w[0]=(UINT32)((INT32)MMX((modrm >> 3) & 0x7).s[0]*(INT32)MMX(modrm & 7).s[0]) >> 16; + MMX((modrm >> 3) & 0x7).w[1]=(UINT32)((INT32)MMX((modrm >> 3) & 0x7).s[1]*(INT32)MMX(modrm & 7).s[1]) >> 16; + MMX((modrm >> 3) & 0x7).w[2]=(UINT32)((INT32)MMX((modrm >> 3) & 0x7).s[2]*(INT32)MMX(modrm & 7).s[2]) >> 16; + MMX((modrm >> 3) & 0x7).w[3]=(UINT32)((INT32)MMX((modrm >> 3) & 0x7).s[3]*(INT32)MMX(modrm & 7).s[3]) >> 16; + } else { + MMX_REG src; + UINT32 ea = GetEA(modrm, 0); + READMMX(ea, src); + MMX((modrm >> 3) & 0x7).w[0]=(UINT32)((INT32)MMX((modrm >> 3) & 0x7).s[0]*(INT32)src.s[0]) >> 16; + MMX((modrm >> 3) & 0x7).w[1]=(UINT32)((INT32)MMX((modrm >> 3) & 0x7).s[1]*(INT32)src.s[1]) >> 16; + MMX((modrm >> 3) & 0x7).w[2]=(UINT32)((INT32)MMX((modrm >> 3) & 0x7).s[2]*(INT32)src.s[2]) >> 16; + MMX((modrm >> 3) & 0x7).w[3]=(UINT32)((INT32)MMX((modrm >> 3) & 0x7).s[3]*(INT32)src.s[3]) >> 16; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::mmx_psubsb_r64_rm64() // Opcode 0f e8 +{ + int n; + MMXPROLOG(); + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + for (n=0;n < 8;n++) + MMX((modrm >> 3) & 0x7).c[n]=SaturatedSignedWordToSignedByte((INT16)MMX((modrm >> 3) & 0x7).c[n] - (INT16)MMX(modrm & 7).c[n]); + } else { + MMX_REG s; + UINT32 ea = GetEA(modrm, 0); + READMMX(ea, s); + for (n=0;n < 8;n++) + MMX((modrm >> 3) & 0x7).c[n]=SaturatedSignedWordToSignedByte((INT16)MMX((modrm >> 3) & 0x7).c[n] - (INT16)s.c[n]); + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::mmx_psubsw_r64_rm64() // Opcode 0f e9 +{ + int n; + MMXPROLOG(); + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + for (n=0;n < 4;n++) + MMX((modrm >> 3) & 0x7).s[n]=SaturatedSignedDwordToSignedWord((INT32)MMX((modrm >> 3) & 0x7).s[n] - (INT32)MMX(modrm & 7).s[n]); + } else { + MMX_REG s; + UINT32 ea = GetEA(modrm, 0); + READMMX(ea, s); + for (n=0;n < 4;n++) + MMX((modrm >> 3) & 0x7).s[n]=SaturatedSignedDwordToSignedWord((INT32)MMX((modrm >> 3) & 0x7).s[n] - (INT32)s.s[n]); + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::mmx_por_r64_rm64() // Opcode 0f eb +{ + MMXPROLOG(); + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + MMX((modrm >> 3) & 0x7).q=MMX((modrm >> 3) & 0x7).q | MMX(modrm & 7).q; + } else { + MMX_REG s; + UINT32 ea = GetEA(modrm, 0); + READMMX(ea, s); + MMX((modrm >> 3) & 0x7).q=MMX((modrm >> 3) & 0x7).q | s.q; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::mmx_paddsb_r64_rm64() // Opcode 0f ec +{ + int n; + MMXPROLOG(); + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + for (n=0;n < 8;n++) + MMX((modrm >> 3) & 0x7).c[n]=SaturatedSignedWordToSignedByte((INT16)MMX((modrm >> 3) & 0x7).c[n] + (INT16)MMX(modrm & 7).c[n]); + } else { + MMX_REG s; + UINT32 ea = GetEA(modrm, 0); + READMMX(ea, s); + for (n=0;n < 8;n++) + MMX((modrm >> 3) & 0x7).c[n]=SaturatedSignedWordToSignedByte((INT16)MMX((modrm >> 3) & 0x7).c[n] + (INT16)s.c[n]); + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::mmx_paddsw_r64_rm64() // Opcode 0f ed +{ + int n; + MMXPROLOG(); + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + for (n=0;n < 4;n++) + MMX((modrm >> 3) & 0x7).s[n]=SaturatedSignedDwordToSignedWord((INT32)MMX((modrm >> 3) & 0x7).s[n] + (INT32)MMX(modrm & 7).s[n]); + } else { + MMX_REG s; + UINT32 ea = GetEA(modrm, 0); + READMMX(ea, s); + for (n=0;n < 4;n++) + MMX((modrm >> 3) & 0x7).s[n]=SaturatedSignedDwordToSignedWord((INT32)MMX((modrm >> 3) & 0x7).s[n] + (INT32)s.s[n]); + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::mmx_pxor_r64_rm64() // Opcode 0f ef +{ + MMXPROLOG(); + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + MMX((modrm >> 3) & 0x7).q=MMX((modrm >> 3) & 0x7).q ^ MMX(modrm & 7).q; + } else { + MMX_REG s; + UINT32 ea = GetEA(modrm, 0); + READMMX(ea, s); + MMX((modrm >> 3) & 0x7).q=MMX((modrm >> 3) & 0x7).q ^ s.q; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::mmx_psllw_r64_rm64() // Opcode 0f f1 +{ + MMXPROLOG(); + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + int count=(int)MMX(modrm & 7).q; + MMX((modrm >> 3) & 0x7).w[0]=MMX((modrm >> 3) & 0x7).w[0] << count; + MMX((modrm >> 3) & 0x7).w[1]=MMX((modrm >> 3) & 0x7).w[1] << count; + MMX((modrm >> 3) & 0x7).w[2]=MMX((modrm >> 3) & 0x7).w[2] << count; + MMX((modrm >> 3) & 0x7).w[3]=MMX((modrm >> 3) & 0x7).w[3] << count; + } else { + MMX_REG s; + UINT32 ea = GetEA(modrm, 0); + READMMX(ea, s); + int count=(int)s.q; + MMX((modrm >> 3) & 0x7).w[0]=MMX((modrm >> 3) & 0x7).w[0] << count; + MMX((modrm >> 3) & 0x7).w[1]=MMX((modrm >> 3) & 0x7).w[1] << count; + MMX((modrm >> 3) & 0x7).w[2]=MMX((modrm >> 3) & 0x7).w[2] << count; + MMX((modrm >> 3) & 0x7).w[3]=MMX((modrm >> 3) & 0x7).w[3] << count; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::mmx_pslld_r64_rm64() // Opcode 0f f2 +{ + MMXPROLOG(); + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + int count=(int)MMX(modrm & 7).q; + MMX((modrm >> 3) & 0x7).d[0]=MMX((modrm >> 3) & 0x7).d[0] << count; + MMX((modrm >> 3) & 0x7).d[1]=MMX((modrm >> 3) & 0x7).d[1] << count; + } else { + MMX_REG s; + UINT32 ea = GetEA(modrm, 0); + READMMX(ea, s); + int count=(int)s.q; + MMX((modrm >> 3) & 0x7).d[0]=MMX((modrm >> 3) & 0x7).d[0] << count; + MMX((modrm >> 3) & 0x7).d[1]=MMX((modrm >> 3) & 0x7).d[1] << count; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::mmx_psllq_r64_rm64() // Opcode 0f f3 +{ + MMXPROLOG(); + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + int count=(int)MMX(modrm & 7).q; + MMX((modrm >> 3) & 0x7).q=MMX((modrm >> 3) & 0x7).q << count; + } else { + MMX_REG s; + UINT32 ea = GetEA(modrm, 0); + READMMX(ea, s); + int count=(int)s.q; + MMX((modrm >> 3) & 0x7).q=MMX((modrm >> 3) & 0x7).q << count; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::mmx_pmaddwd_r64_rm64() // Opcode 0f f5 +{ + MMXPROLOG(); + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + MMX((modrm >> 3) & 0x7).i[0]=(INT32)MMX((modrm >> 3) & 0x7).s[0]*(INT32)MMX(modrm & 7).s[0]+ + (INT32)MMX((modrm >> 3) & 0x7).s[1]*(INT32)MMX(modrm & 7).s[1]; + MMX((modrm >> 3) & 0x7).i[1]=(INT32)MMX((modrm >> 3) & 0x7).s[2]*(INT32)MMX(modrm & 7).s[2]+ + (INT32)MMX((modrm >> 3) & 0x7).s[3]*(INT32)MMX(modrm & 7).s[3]; + } else { + MMX_REG s; + UINT32 ea = GetEA(modrm, 0); + READMMX(ea, s); + MMX((modrm >> 3) & 0x7).i[0]=(INT32)MMX((modrm >> 3) & 0x7).s[0]*(INT32)s.s[0]+ + (INT32)MMX((modrm >> 3) & 0x7).s[1]*(INT32)s.s[1]; + MMX((modrm >> 3) & 0x7).i[1]=(INT32)MMX((modrm >> 3) & 0x7).s[2]*(INT32)s.s[2]+ + (INT32)MMX((modrm >> 3) & 0x7).s[3]*(INT32)s.s[3]; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::mmx_psubb_r64_rm64() // Opcode 0f f8 +{ + int n; + MMXPROLOG(); + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + for (n=0;n < 8;n++) + MMX((modrm >> 3) & 0x7).b[n]=MMX((modrm >> 3) & 0x7).b[n] - MMX(modrm & 7).b[n]; + } else { + MMX_REG s; + UINT32 ea = GetEA(modrm, 0); + READMMX(ea, s); + for (n=0;n < 8;n++) + MMX((modrm >> 3) & 0x7).b[n]=MMX((modrm >> 3) & 0x7).b[n] - s.b[n]; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::mmx_psubw_r64_rm64() // Opcode 0f f9 +{ + int n; + MMXPROLOG(); + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + for (n=0;n < 4;n++) + MMX((modrm >> 3) & 0x7).w[n]=MMX((modrm >> 3) & 0x7).w[n] - MMX(modrm & 7).w[n]; + } else { + MMX_REG s; + UINT32 ea = GetEA(modrm, 0); + READMMX(ea, s); + for (n=0;n < 4;n++) + MMX((modrm >> 3) & 0x7).w[n]=MMX((modrm >> 3) & 0x7).w[n] - s.w[n]; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::mmx_psubd_r64_rm64() // Opcode 0f fa +{ + int n; + MMXPROLOG(); + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + for (n=0;n < 2;n++) + MMX((modrm >> 3) & 0x7).d[n]=MMX((modrm >> 3) & 0x7).d[n] - MMX(modrm & 7).d[n]; + } else { + MMX_REG s; + UINT32 ea = GetEA(modrm, 0); + READMMX(ea, s); + for (n=0;n < 2;n++) + MMX((modrm >> 3) & 0x7).d[n]=MMX((modrm >> 3) & 0x7).d[n] - s.d[n]; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::mmx_paddb_r64_rm64() // Opcode 0f fc +{ + int n; + MMXPROLOG(); + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + for (n=0;n < 8;n++) + MMX((modrm >> 3) & 0x7).b[n]=MMX((modrm >> 3) & 0x7).b[n] + MMX(modrm & 7).b[n]; + } else { + MMX_REG s; + UINT32 ea = GetEA(modrm, 0); + READMMX(ea, s); + for (n=0;n < 8;n++) + MMX((modrm >> 3) & 0x7).b[n]=MMX((modrm >> 3) & 0x7).b[n] + s.b[n]; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::mmx_paddw_r64_rm64() // Opcode 0f fd +{ + int n; + MMXPROLOG(); + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + for (n=0;n < 4;n++) + MMX((modrm >> 3) & 0x7).w[n]=MMX((modrm >> 3) & 0x7).w[n] + MMX(modrm & 7).w[n]; + } else { + MMX_REG s; + UINT32 ea = GetEA(modrm, 0); + READMMX(ea, s); + for (n=0;n < 4;n++) + MMX((modrm >> 3) & 0x7).w[n]=MMX((modrm >> 3) & 0x7).w[n] + s.w[n]; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::mmx_paddd_r64_rm64() // Opcode 0f fe +{ + int n; + MMXPROLOG(); + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + for (n=0;n < 2;n++) + MMX((modrm >> 3) & 0x7).d[n]=MMX((modrm >> 3) & 0x7).d[n] + MMX(modrm & 7).d[n]; + } else { + MMX_REG s; + UINT32 ea = GetEA(modrm, 0); + READMMX(ea, s); + for (n=0;n < 2;n++) + MMX((modrm >> 3) & 0x7).d[n]=MMX((modrm >> 3) & 0x7).d[n] + s.d[n]; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::mmx_emms() // Opcode 0f 77 +{ + m_x87_tw = 0xffff; // tag word = 0xffff + // TODO + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::i386_cyrix_svdc() // Opcode 0f 78 +{ + UINT8 modrm = FETCH(); + + if( modrm < 0xc0 ) { + UINT32 ea = GetEA(modrm,0); + int index = (modrm >> 3) & 7; + int limit; + switch (index) + { + case 0: + { + index = ES; + break; + } + + case 2: + { + index = SS; + break; + } + + case 3: + { + index = DS; + break; + } + + case 4: + { + index = FS; + break; + } + + case 5: + { + index = GS; + break; + } + + default: + { + i386_trap(6, 0, 0); + } + } + + limit = m_sreg[index].limit; + + if (m_sreg[index].flags & 0x8000) //G bit + { + limit >>= 12; + } + + WRITE16(ea + 0, limit); + WRITE32(ea + 2, m_sreg[index].base); + WRITE16(ea + 5, m_sreg[index].flags); //replace top 8 bits of base + WRITE8(ea + 7, m_sreg[index].base >> 24); + WRITE16(ea + 8, m_sreg[index].selector); + } else { + i386_trap(6, 0, 0); + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::i386_cyrix_rsdc() // Opcode 0f 79 +{ + UINT8 modrm = FETCH(); + + if( modrm < 0xc0 ) { + UINT32 ea = GetEA(modrm,0); + int index = (modrm >> 3) & 7; + UINT16 flags; + UINT32 base; + UINT32 limit; + switch (index) + { + case 0: + { + index = ES; + break; + } + + case 2: + { + index = SS; + break; + } + + case 3: + { + index = DS; + break; + } + + case 4: + { + index = FS; + break; + } + + case 5: + { + index = GS; + break; + } + + default: + { + i386_trap(6, 0, 0); + } + } + + base = (READ32(ea + 2) & 0x00ffffff) | (READ8(ea + 7) << 24); + flags = READ16(ea + 5); + limit = READ16(ea + 0) | ((flags & 3) << 16); + + if (flags & 0x8000) //G bit + { + limit = (limit << 12) | 0xfff; + } + + m_sreg[index].selector = READ16(ea + 8); + m_sreg[index].flags = flags; + m_sreg[index].base = base; + m_sreg[index].limit = limit; + } else { + i386_trap(6, 0, 0); + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::i386_cyrix_svldt() // Opcode 0f 7a +{ + if ( PROTECTED_MODE && !V8086_MODE ) + { + UINT8 modrm = FETCH(); + + if( !(modrm & 0xf8) ) { + UINT32 ea = GetEA(modrm,0); + UINT32 limit = m_ldtr.limit; + + if (m_ldtr.flags & 0x8000) //G bit + { + limit >>= 12; + } + + WRITE16(ea + 0, limit); + WRITE32(ea + 2, m_ldtr.base); + WRITE16(ea + 5, m_ldtr.flags); //replace top 8 bits of base + WRITE8(ea + 7, m_ldtr.base >> 24); + WRITE16(ea + 8, m_ldtr.segment); + } else { + i386_trap(6, 0, 0); + } + } else { + i386_trap(6, 0, 0); + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::i386_cyrix_rsldt() // Opcode 0f 7b +{ + if ( PROTECTED_MODE && !V8086_MODE ) + { + if(m_CPL) + FAULT(FAULT_GP,0) + + UINT8 modrm = FETCH(); + + if( !(modrm & 0xf8) ) { + UINT32 ea = GetEA(modrm,0); + UINT16 flags = READ16(ea + 5); + UINT32 base = (READ32(ea + 2) | 0x00ffffff) | (READ8(ea + 7) << 24); + UINT32 limit = READ16(ea + 0) | ((flags & 3) << 16); + I386_SREG seg; + + if (flags & 0x8000) //G bit + { + limit = (limit << 12) | 0xfff; + } + + memset(&seg, 0, sizeof(seg)); + seg.selector = READ16(ea + 8); + i386_load_protected_mode_segment(&seg,NULL); + m_ldtr.limit = limit; + m_ldtr.base = base; + m_ldtr.flags = flags; + } else { + i386_trap(6, 0, 0); + } + } else { + i386_trap(6, 0, 0); + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::i386_cyrix_svts() // Opcode 0f 7c +{ + if ( PROTECTED_MODE ) + { + UINT8 modrm = FETCH(); + + if( !(modrm & 0xf8) ) { + UINT32 ea = GetEA(modrm,0); + UINT32 limit = m_task.limit; + + if (m_task.flags & 0x8000) //G bit + { + limit >>= 12; + } + + WRITE16(ea + 0, limit); + WRITE32(ea + 2, m_task.base); + WRITE16(ea + 5, m_task.flags); //replace top 8 bits of base + WRITE8(ea + 7, m_task.base >> 24); + WRITE16(ea + 8, m_task.segment); + } else { + i386_trap(6, 0, 0); + } + } else { + i386_trap(6, 0, 0); + } +} + +void i386_device::i386_cyrix_rsts() // Opcode 0f 7d +{ + if ( PROTECTED_MODE ) + { + if(m_CPL) + FAULT(FAULT_GP,0) + + UINT8 modrm = FETCH(); + + if( !(modrm & 0xf8) ) { + UINT32 ea = GetEA(modrm,0); + UINT16 flags = READ16(ea + 5); + UINT32 base = (READ32(ea + 2) | 0x00ffffff) | (READ8(ea + 7) << 24); + UINT32 limit = READ16(ea + 0) | ((flags & 3) << 16); + + if (flags & 0x8000) //G bit + { + limit = (limit << 12) | 0xfff; + } + m_task.segment = READ16(ea + 8); + m_task.limit = limit; + m_task.base = base; + m_task.flags = flags; + } else { + i386_trap(6, 0, 0); + } + } else { + i386_trap(6, 0, 0); + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::mmx_movd_r64_rm32() // Opcode 0f 6e +{ + MMXPROLOG(); + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + MMX((modrm >> 3) & 0x7).d[0]=LOAD_RM32(modrm); + } else { + UINT32 ea = GetEA(modrm, 0); + MMX((modrm >> 3) & 0x7).d[0]=READ32(ea); + } + MMX((modrm >> 3) & 0x7).d[1]=0; + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::mmx_movq_r64_rm64() // Opcode 0f 6f +{ + MMXPROLOG(); + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + MMX((modrm >> 3) & 0x7).l=MMX(modrm & 0x7).l; + } else { + UINT32 ea = GetEA(modrm, 0); + READMMX(ea, MMX((modrm >> 3) & 0x7)); + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::mmx_movd_rm32_r64() // Opcode 0f 7e +{ + MMXPROLOG(); + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + STORE_RM32(modrm, MMX((modrm >> 3) & 0x7).d[0]); + } else { + UINT32 ea = GetEA(modrm, 0); + WRITE32(ea, MMX((modrm >> 3) & 0x7).d[0]); + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::mmx_movq_rm64_r64() // Opcode 0f 7f +{ + MMXPROLOG(); + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + MMX(modrm & 0x7)=MMX((modrm >> 3) & 0x7); + } else { + UINT32 ea = GetEA(modrm, 0); + WRITEMMX(ea, MMX((modrm >> 3) & 0x7)); + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::mmx_pcmpeqb_r64_rm64() // Opcode 0f 74 +{ + int c; + MMXPROLOG(); + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + int s,d; + s=modrm & 0x7; + d=(modrm >> 3) & 0x7; + for (c=0;c <= 7;c++) + MMX(d).b[c]=(MMX(d).b[c] == MMX(s).b[c]) ? 0xff : 0; + } else { + MMX_REG s; + int d=(modrm >> 3) & 0x7; + UINT32 ea = GetEA(modrm, 0); + READMMX(ea, s); + for (c=0;c <= 7;c++) + MMX(d).b[c]=(MMX(d).b[c] == s.b[c]) ? 0xff : 0; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::mmx_pcmpeqw_r64_rm64() // Opcode 0f 75 +{ + MMXPROLOG(); + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + int s,d; + s=modrm & 0x7; + d=(modrm >> 3) & 0x7; + MMX(d).w[0]=(MMX(d).w[0] == MMX(s).w[0]) ? 0xffff : 0; + MMX(d).w[1]=(MMX(d).w[1] == MMX(s).w[1]) ? 0xffff : 0; + MMX(d).w[2]=(MMX(d).w[2] == MMX(s).w[2]) ? 0xffff : 0; + MMX(d).w[3]=(MMX(d).w[3] == MMX(s).w[3]) ? 0xffff : 0; + } else { + MMX_REG s; + int d=(modrm >> 3) & 0x7; + UINT32 ea = GetEA(modrm, 0); + READMMX(ea, s); + MMX(d).w[0]=(MMX(d).w[0] == s.w[0]) ? 0xffff : 0; + MMX(d).w[1]=(MMX(d).w[1] == s.w[1]) ? 0xffff : 0; + MMX(d).w[2]=(MMX(d).w[2] == s.w[2]) ? 0xffff : 0; + MMX(d).w[3]=(MMX(d).w[3] == s.w[3]) ? 0xffff : 0; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::mmx_pcmpeqd_r64_rm64() // Opcode 0f 76 +{ + MMXPROLOG(); + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + int s,d; + s=modrm & 0x7; + d=(modrm >> 3) & 0x7; + MMX(d).d[0]=(MMX(d).d[0] == MMX(s).d[0]) ? 0xffffffff : 0; + MMX(d).d[1]=(MMX(d).d[1] == MMX(s).d[1]) ? 0xffffffff : 0; + } else { + MMX_REG s; + int d=(modrm >> 3) & 0x7; + UINT32 ea = GetEA(modrm, 0); + READMMX(ea, s); + MMX(d).d[0]=(MMX(d).d[0] == s.d[0]) ? 0xffffffff : 0; + MMX(d).d[1]=(MMX(d).d[1] == s.d[1]) ? 0xffffffff : 0; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::mmx_pshufw_r64_rm64_i8() // Opcode 0f 70 +{ + MMXPROLOG(); + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + MMX_REG t; + int s,d; + UINT8 imm8 = FETCH(); + s=modrm & 0x7; + d=(modrm >> 3) & 0x7; + t.q=MMX(s).q; + MMX(d).w[0]=t.w[imm8 & 3]; + MMX(d).w[1]=t.w[(imm8 >> 2) & 3]; + MMX(d).w[2]=t.w[(imm8 >> 4) & 3]; + MMX(d).w[3]=t.w[(imm8 >> 6) & 3]; + } else { + MMX_REG s; + int d=(modrm >> 3) & 0x7; + UINT32 ea = GetEA(modrm, 0); + UINT8 imm8 = FETCH(); + READMMX(ea, s); + MMX(d).w[0]=s.w[imm8 & 3]; + MMX(d).w[1]=s.w[(imm8 >> 2) & 3]; + MMX(d).w[2]=s.w[(imm8 >> 4) & 3]; + MMX(d).w[3]=s.w[(imm8 >> 6) & 3]; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_punpcklbw_r128_rm128() // Opcode 66 0f 60 +{ + UINT8 modrm = FETCH(); + if (modrm >= 0xc0) { + XMM_REG xd,xs; + int s, d; + s = modrm & 0x7; + d = (modrm >> 3) & 0x7; + xd.l[0] = XMM(d).l[0]; + xs.l[0] = XMM(s).l[0]; + XMM(d).b[0] = xd.b[0]; + XMM(d).b[1] = xs.b[0]; + XMM(d).b[2] = xd.b[1]; + XMM(d).b[3] = xs.b[1]; + XMM(d).b[4] = xd.b[2]; + XMM(d).b[5] = xs.b[2]; + XMM(d).b[6] = xd.b[3]; + XMM(d).b[7] = xs.b[3]; + XMM(d).b[8] = xd.b[4]; + XMM(d).b[9] = xs.b[4]; + XMM(d).b[10] = xd.b[5]; + XMM(d).b[11] = xs.b[5]; + XMM(d).b[12] = xd.b[6]; + XMM(d).b[13] = xs.b[6]; + XMM(d).b[14] = xd.b[7]; + XMM(d).b[15] = xs.b[7]; + } + else { + XMM_REG xd, xs; + int d = (modrm >> 3) & 0x7; + UINT32 ea = GetEA(modrm, 0); + xd.l[0] = XMM(d).l[0]; + xs.q[0] = READ64(ea); + for (int n = 0; n < 8; n++) { + XMM(d).b[n << 1] = xd.b[n]; + XMM(d).b[(n << 1) | 1] = xs.b[n]; + } + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_punpcklwd_r128_rm128() +{ + UINT8 modrm = FETCH(); + if (modrm >= 0xc0) { + XMM_REG xd, xs; + int s, d; + s = modrm & 0x7; + d = (modrm >> 3) & 0x7; + xd.l[0] = XMM(d).l[0]; + xs.l[0] = XMM(s).l[0]; + for (int n = 0; n < 4; n++) { + XMM(d).w[n << 1] = xd.w[n]; + XMM(d).w[(n << 1) | 1] = xs.w[n]; + } + } + else { + XMM_REG xd, xs; + int d = (modrm >> 3) & 0x7; + UINT32 ea = GetEA(modrm, 0); + xd.l[0] = XMM(d).l[0]; + xs.q[0] = READ64(ea); + for (int n = 0; n < 4; n++) { + XMM(d).w[n << 1] = xd.w[n]; + XMM(d).w[(n << 1) | 1] = xs.w[n]; + } + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_punpckldq_r128_rm128() +{ + UINT8 modrm = FETCH(); + if (modrm >= 0xc0) { + XMM_REG xd, xs; + int s, d; + s = modrm & 0x7; + d = (modrm >> 3) & 0x7; + xd.l[0] = XMM(d).l[0]; + xs.l[0] = XMM(s).l[0]; + for (int n = 0; n < 2; n++) { + XMM(d).d[n << 1] = xd.d[n]; + XMM(d).d[(n << 1) | 1] = xs.d[n]; + } + } + else { + XMM_REG xd, xs; + int d = (modrm >> 3) & 0x7; + UINT32 ea = GetEA(modrm, 0); + xd.l[0] = XMM(d).l[0]; + xs.q[0] = READ64(ea); + for (int n = 0; n < 2; n++) { + XMM(d).d[n << 1] = xd.d[n]; + XMM(d).d[(n << 1) | 1] = xs.d[n]; + } + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_punpcklqdq_r128_rm128() +{ + UINT8 modrm = FETCH(); + if (modrm >= 0xc0) { + XMM_REG xd, xs; + int s, d; + s = modrm & 0x7; + d = (modrm >> 3) & 0x7; + xd.l[0] = XMM(d).l[0]; + xs.l[0] = XMM(s).l[0]; + XMM(d).q[0] = xd.q[0]; + XMM(d).q[1] = xs.q[0]; + } + else { + XMM_REG xd, xs; + int d = (modrm >> 3) & 0x7; + UINT32 ea = GetEA(modrm, 0); + xd.l[0] = XMM(d).l[0]; + xs.q[0] = READ64(ea); + XMM(d).q[0] = xd.q[0]; + XMM(d).q[1] = xs.q[0]; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::mmx_punpcklbw_r64_r64m32() // Opcode 0f 60 +{ + MMXPROLOG(); + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + UINT32 t; + int s,d; + s=modrm & 0x7; + d=(modrm >> 3) & 0x7; + t=MMX(d).d[0]; + MMX(d).b[0]=t & 0xff; + MMX(d).b[1]=MMX(s).b[0]; + MMX(d).b[2]=(t >> 8) & 0xff; + MMX(d).b[3]=MMX(s).b[1]; + MMX(d).b[4]=(t >> 16) & 0xff; + MMX(d).b[5]=MMX(s).b[2]; + MMX(d).b[6]=(t >> 24) & 0xff; + MMX(d).b[7]=MMX(s).b[3]; + } else { + UINT32 s,t; + int d=(modrm >> 3) & 0x7; + UINT32 ea = GetEA(modrm, 0); + s = READ32(ea); + t=MMX(d).d[0]; + MMX(d).b[0]=t & 0xff; + MMX(d).b[1]=s & 0xff; + MMX(d).b[2]=(t >> 8) & 0xff; + MMX(d).b[3]=(s >> 8) & 0xff; + MMX(d).b[4]=(t >> 16) & 0xff; + MMX(d).b[5]=(s >> 16) & 0xff; + MMX(d).b[6]=(t >> 24) & 0xff; + MMX(d).b[7]=(s >> 24) & 0xff; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::mmx_punpcklwd_r64_r64m32() // Opcode 0f 61 +{ + MMXPROLOG(); + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + UINT16 t; + int s,d; + s=modrm & 0x7; + d=(modrm >> 3) & 0x7; + t=MMX(d).w[1]; + MMX(d).w[0]=MMX(d).w[0]; + MMX(d).w[1]=MMX(s).w[0]; + MMX(d).w[2]=t; + MMX(d).w[3]=MMX(s).w[1]; + } else { + UINT32 s; + UINT16 t; + int d=(modrm >> 3) & 0x7; + UINT32 ea = GetEA(modrm, 0); + s = READ32(ea); + t=MMX(d).w[1]; + MMX(d).w[0]=MMX(d).w[0]; + MMX(d).w[1]=s & 0xffff; + MMX(d).w[2]=t; + MMX(d).w[3]=(s >> 16) & 0xffff; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::mmx_punpckldq_r64_r64m32() // Opcode 0f 62 +{ + MMXPROLOG(); + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + int s,d; + s=modrm & 0x7; + d=(modrm >> 3) & 0x7; + MMX(d).d[0]=MMX(d).d[0]; + MMX(d).d[1]=MMX(s).d[0]; + } else { + UINT32 s; + int d=(modrm >> 3) & 0x7; + UINT32 ea = GetEA(modrm, 0); + s = READ32(ea); + MMX(d).d[0]=MMX(d).d[0]; + MMX(d).d[1]=s; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::mmx_packsswb_r64_rm64() // Opcode 0f 63 +{ + MMXPROLOG(); + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + int s,d; + s=modrm & 0x7; + d=(modrm >> 3) & 0x7; + MMX(d).c[0]=SaturatedSignedWordToSignedByte(MMX(d).s[0]); + MMX(d).c[1]=SaturatedSignedWordToSignedByte(MMX(d).s[1]); + MMX(d).c[2]=SaturatedSignedWordToSignedByte(MMX(d).s[2]); + MMX(d).c[3]=SaturatedSignedWordToSignedByte(MMX(d).s[3]); + MMX(d).c[4]=SaturatedSignedWordToSignedByte(MMX(s).s[0]); + MMX(d).c[5]=SaturatedSignedWordToSignedByte(MMX(s).s[1]); + MMX(d).c[6]=SaturatedSignedWordToSignedByte(MMX(s).s[2]); + MMX(d).c[7]=SaturatedSignedWordToSignedByte(MMX(s).s[3]); + } else { + MMX_REG s; + int d=(modrm >> 3) & 0x7; + UINT32 ea = GetEA(modrm, 0); + READMMX(ea, s); + MMX(d).c[0]=SaturatedSignedWordToSignedByte(MMX(d).s[0]); + MMX(d).c[1]=SaturatedSignedWordToSignedByte(MMX(d).s[1]); + MMX(d).c[2]=SaturatedSignedWordToSignedByte(MMX(d).s[2]); + MMX(d).c[3]=SaturatedSignedWordToSignedByte(MMX(d).s[3]); + MMX(d).c[4]=SaturatedSignedWordToSignedByte(s.s[0]); + MMX(d).c[5]=SaturatedSignedWordToSignedByte(s.s[1]); + MMX(d).c[6]=SaturatedSignedWordToSignedByte(s.s[2]); + MMX(d).c[7]=SaturatedSignedWordToSignedByte(s.s[3]); + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::mmx_pcmpgtb_r64_rm64() // Opcode 0f 64 +{ + int c; + MMXPROLOG(); + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + int s,d; + s=modrm & 0x7; + d=(modrm >> 3) & 0x7; + for (c=0;c <= 7;c++) + MMX(d).b[c]=(MMX(d).c[c] > MMX(s).c[c]) ? 0xff : 0; + } else { + MMX_REG s; + int d=(modrm >> 3) & 0x7; + UINT32 ea = GetEA(modrm, 0); + READMMX(ea, s); + for (c=0;c <= 7;c++) + MMX(d).b[c]=(MMX(d).c[c] > s.c[c]) ? 0xff : 0; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::mmx_pcmpgtw_r64_rm64() // Opcode 0f 65 +{ + int c; + MMXPROLOG(); + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + int s,d; + s=modrm & 0x7; + d=(modrm >> 3) & 0x7; + for (c=0;c <= 3;c++) + MMX(d).w[c]=(MMX(d).s[c] > MMX(s).s[c]) ? 0xffff : 0; + } else { + MMX_REG s; + int d=(modrm >> 3) & 0x7; + UINT32 ea = GetEA(modrm, 0); + READMMX(ea, s); + for (c=0;c <= 3;c++) + MMX(d).w[c]=(MMX(d).s[c] > s.s[c]) ? 0xffff : 0; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::mmx_pcmpgtd_r64_rm64() // Opcode 0f 66 +{ + int c; + MMXPROLOG(); + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + int s,d; + s=modrm & 0x7; + d=(modrm >> 3) & 0x7; + for (c=0;c <= 1;c++) + MMX(d).d[c]=(MMX(d).i[c] > MMX(s).i[c]) ? 0xffffffff : 0; + } else { + MMX_REG s; + int d=(modrm >> 3) & 0x7; + UINT32 ea = GetEA(modrm, 0); + READMMX(ea, s); + for (c=0;c <= 1;c++) + MMX(d).d[c]=(MMX(d).i[c] > s.i[c]) ? 0xffffffff : 0; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::mmx_packuswb_r64_rm64() // Opcode 0f 67 +{ + MMXPROLOG(); + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + MMX_REG ds, sd; + int s,d; + s=modrm & 0x7; + d=(modrm >> 3) & 0x7; + ds.q = MMX(d).q; + sd.q = MMX(s).q; + MMX(d).b[0]=SaturatedSignedWordToUnsignedByte(ds.s[0]); + MMX(d).b[1]=SaturatedSignedWordToUnsignedByte(ds.s[1]); + MMX(d).b[2]=SaturatedSignedWordToUnsignedByte(ds.s[2]); + MMX(d).b[3]=SaturatedSignedWordToUnsignedByte(ds.s[3]); + MMX(d).b[4]=SaturatedSignedWordToUnsignedByte(sd.s[0]); + MMX(d).b[5]=SaturatedSignedWordToUnsignedByte(sd.s[1]); + MMX(d).b[6]=SaturatedSignedWordToUnsignedByte(sd.s[2]); + MMX(d).b[7]=SaturatedSignedWordToUnsignedByte(sd.s[3]); + } else { + MMX_REG s,t; + int d=(modrm >> 3) & 0x7; + UINT32 ea = GetEA(modrm, 0); + READMMX(ea, s); + t.q = MMX(d).q; + MMX(d).b[0]=SaturatedSignedWordToUnsignedByte(t.s[0]); + MMX(d).b[1]=SaturatedSignedWordToUnsignedByte(t.s[1]); + MMX(d).b[2]=SaturatedSignedWordToUnsignedByte(t.s[2]); + MMX(d).b[3]=SaturatedSignedWordToUnsignedByte(t.s[3]); + MMX(d).b[4]=SaturatedSignedWordToUnsignedByte(s.s[0]); + MMX(d).b[5]=SaturatedSignedWordToUnsignedByte(s.s[1]); + MMX(d).b[6]=SaturatedSignedWordToUnsignedByte(s.s[2]); + MMX(d).b[7]=SaturatedSignedWordToUnsignedByte(s.s[3]); + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::mmx_punpckhbw_r64_rm64() // Opcode 0f 68 +{ + MMXPROLOG(); + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + int s,d; + s=modrm & 0x7; + d=(modrm >> 3) & 0x7; + MMX(d).b[0]=MMX(d).b[4]; + MMX(d).b[1]=MMX(s).b[4]; + MMX(d).b[2]=MMX(d).b[5]; + MMX(d).b[3]=MMX(s).b[5]; + MMX(d).b[4]=MMX(d).b[6]; + MMX(d).b[5]=MMX(s).b[6]; + MMX(d).b[6]=MMX(d).b[7]; + MMX(d).b[7]=MMX(s).b[7]; + } else { + MMX_REG s; + int d=(modrm >> 3) & 0x7; + UINT32 ea = GetEA(modrm, 0); + READMMX(ea, s); + MMX(d).b[0]=MMX(d).b[4]; + MMX(d).b[1]=s.b[4]; + MMX(d).b[2]=MMX(d).b[5]; + MMX(d).b[3]=s.b[5]; + MMX(d).b[4]=MMX(d).b[6]; + MMX(d).b[5]=s.b[6]; + MMX(d).b[6]=MMX(d).b[7]; + MMX(d).b[7]=s.b[7]; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::mmx_punpckhwd_r64_rm64() // Opcode 0f 69 +{ + MMXPROLOG(); + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + int s,d; + s=modrm & 0x7; + d=(modrm >> 3) & 0x7; + MMX(d).w[0]=MMX(d).w[2]; + MMX(d).w[1]=MMX(s).w[2]; + MMX(d).w[2]=MMX(d).w[3]; + MMX(d).w[3]=MMX(s).w[3]; + } else { + MMX_REG s; + int d=(modrm >> 3) & 0x7; + UINT32 ea = GetEA(modrm, 0); + READMMX(ea, s); + MMX(d).w[0]=MMX(d).w[2]; + MMX(d).w[1]=s.w[2]; + MMX(d).w[2]=MMX(d).w[3]; + MMX(d).w[3]=s.w[3]; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::mmx_punpckhdq_r64_rm64() // Opcode 0f 6a +{ + MMXPROLOG(); + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + int s,d; + s=modrm & 0x7; + d=(modrm >> 3) & 0x7; + MMX(d).d[0]=MMX(d).d[1]; + MMX(d).d[1]=MMX(s).d[1]; + } else { + MMX_REG s; + int d=(modrm >> 3) & 0x7; + UINT32 ea = GetEA(modrm, 0); + READMMX(ea, s); + MMX(d).d[0]=MMX(d).d[1]; + MMX(d).d[1]=s.d[1]; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::mmx_packssdw_r64_rm64() // Opcode 0f 6b +{ + MMXPROLOG(); + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + int s,d; + INT32 t1, t2, t3, t4; + s=modrm & 0x7; + d=(modrm >> 3) & 0x7; + t1 = MMX(d).i[0]; + t2 = MMX(d).i[1]; + t3 = MMX(s).i[0]; + t4 = MMX(s).i[1]; + MMX(d).s[0] = SaturatedSignedDwordToSignedWord(t1); + MMX(d).s[1] = SaturatedSignedDwordToSignedWord(t2); + MMX(d).s[2] = SaturatedSignedDwordToSignedWord(t3); + MMX(d).s[3] = SaturatedSignedDwordToSignedWord(t4); + } + else { + MMX_REG s; + INT32 t1, t2; + int d=(modrm >> 3) & 0x7; + UINT32 ea = GetEA(modrm, 0); + READMMX(ea, s); + t1 = MMX(d).i[0]; + t2 = MMX(d).i[1]; + MMX(d).s[0] = SaturatedSignedDwordToSignedWord(t1); + MMX(d).s[1] = SaturatedSignedDwordToSignedWord(t2); + MMX(d).s[2] = SaturatedSignedDwordToSignedWord(s.i[0]); + MMX(d).s[3] = SaturatedSignedDwordToSignedWord(s.i[1]); + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_group_0fae() // Opcode 0f ae +{ + UINT8 modm = FETCH(); + if( modm == 0xf8 ) { + logerror("Unemulated SFENCE opcode called\n"); + CYCLES(1); // sfence instruction + } else if( modm == 0xf0 ) { + CYCLES(1); // mfence instruction + } else if( modm == 0xe8 ) { + CYCLES(1); // lfence instruction + } else if( modm < 0xc0 ) { + UINT32 ea; + switch ( (modm & 0x38) >> 3 ) + { + case 2: // ldmxcsr m32 + ea = GetEA(modm, 0); + m_mxcsr = READ32(ea); + break; + case 3: // stmxcsr m32 + ea = GetEA(modm, 0); + WRITE32(ea, m_mxcsr); + break; + case 7: // clflush m8 + GetNonTranslatedEA(modm, NULL); + break; + default: + report_invalid_modrm("sse_group_0fae", modm); + } + } else { + report_invalid_modrm("sse_group_0fae", modm); + } +} + +void i386_device::sse_cvttps2dq_r128_rm128() // Opcode f3 0f 5b +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + XMM((modrm >> 3) & 0x7).i[0]=(INT32)XMM(modrm & 0x7).f[0]; + XMM((modrm >> 3) & 0x7).i[1]=(INT32)XMM(modrm & 0x7).f[1]; + XMM((modrm >> 3) & 0x7).i[2]=(INT32)XMM(modrm & 0x7).f[2]; + XMM((modrm >> 3) & 0x7).i[3]=(INT32)XMM(modrm & 0x7).f[3]; + } else { + XMM_REG src; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, src); + XMM((modrm >> 3) & 0x7).i[0]=(INT32)src.f[0]; + XMM((modrm >> 3) & 0x7).i[1]=(INT32)src.f[1]; + XMM((modrm >> 3) & 0x7).i[2]=(INT32)src.f[2]; + XMM((modrm >> 3) & 0x7).i[3]=(INT32)src.f[3]; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_cvtss2sd_r128_r128m32() // Opcode f3 0f 5a +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + XMM((modrm >> 3) & 0x7).f64[0] = XMM(modrm & 0x7).f[0]; + } else { + XMM_REG s; + UINT32 ea = GetEA(modrm, 0); + s.d[0] = READ32(ea); + XMM((modrm >> 3) & 0x7).f64[0] = s.f[0]; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_cvttss2si_r32_r128m32() // Opcode f3 0f 2c +{ + INT32 src; + UINT8 modrm = FETCH(); // get mordm byte + if( modrm >= 0xc0 ) { // if bits 7-6 are 11 the source is a xmm register (low doubleword) + src = (INT32)XMM(modrm & 0x7).f[0^NATIVE_ENDIAN_VALUE_LE_BE(0,1)]; + } else { // otherwise is a memory address + XMM_REG t; + UINT32 ea = GetEA(modrm, 0); + t.d[0] = READ32(ea); + src = (INT32)t.f[0]; + } + STORE_REG32(modrm, (UINT32)src); + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_cvtss2si_r32_r128m32() // Opcode f3 0f 2d +{ + INT32 src; + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + src = (INT32)XMM(modrm & 0x7).f[0]; + } else { + XMM_REG t; + UINT32 ea = GetEA(modrm, 0); + t.d[0] = READ32(ea); + src = (INT32)t.f[0]; + } + STORE_REG32(modrm, (UINT32)src); + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_cvtsi2ss_r128_rm32() // Opcode f3 0f 2a +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + XMM((modrm >> 3) & 0x7).f[0] = (INT32)LOAD_RM32(modrm); + } else { + UINT32 ea = GetEA(modrm, 0); + XMM((modrm >> 3) & 0x7).f[0] = (INT32)READ32(ea); + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_cvtpi2ps_r128_rm64() // Opcode 0f 2a +{ + UINT8 modrm = FETCH(); + MMXPROLOG(); + if( modrm >= 0xc0 ) { + XMM((modrm >> 3) & 0x7).f[0] = (float)MMX(modrm & 0x7).i[0]; + XMM((modrm >> 3) & 0x7).f[1] = (float)MMX(modrm & 0x7).i[1]; + } else { + MMX_REG r; + UINT32 ea = GetEA(modrm, 0); + READMMX(ea, r); + XMM((modrm >> 3) & 0x7).f[0] = (float)r.i[0]; + XMM((modrm >> 3) & 0x7).f[1] = (float)r.i[1]; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_cvttps2pi_r64_r128m64() // Opcode 0f 2c +{ + UINT8 modrm = FETCH(); + MMXPROLOG(); + if( modrm >= 0xc0 ) { + MMX((modrm >> 3) & 0x7).i[0] = XMM(modrm & 0x7).f[0]; + MMX((modrm >> 3) & 0x7).i[1] = XMM(modrm & 0x7).f[1]; + } else { + XMM_REG r; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, r); + XMM((modrm >> 3) & 0x7).i[0] = r.f[0]; + XMM((modrm >> 3) & 0x7).i[1] = r.f[1]; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_cvtps2pi_r64_r128m64() // Opcode 0f 2d +{ + UINT8 modrm = FETCH(); + MMXPROLOG(); + if( modrm >= 0xc0 ) { + MMX((modrm >> 3) & 0x7).i[0] = XMM(modrm & 0x7).f[0]; + MMX((modrm >> 3) & 0x7).i[1] = XMM(modrm & 0x7).f[1]; + } else { + XMM_REG r; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, r); + XMM((modrm >> 3) & 0x7).i[0] = r.f[0]; + XMM((modrm >> 3) & 0x7).i[1] = r.f[1]; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_cvtps2pd_r128_r128m64() // Opcode 0f 5a +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + XMM((modrm >> 3) & 0x7).f64[0] = (double)XMM(modrm & 0x7).f[0]; + XMM((modrm >> 3) & 0x7).f64[1] = (double)XMM(modrm & 0x7).f[1]; + } else { + MMX_REG r; + UINT32 ea = GetEA(modrm, 0); + READMMX(ea, r); + XMM((modrm >> 3) & 0x7).f64[0] = (double)r.f[0]; + XMM((modrm >> 3) & 0x7).f64[1] = (double)r.f[1]; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_cvtdq2ps_r128_rm128() // Opcode 0f 5b +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + XMM((modrm >> 3) & 0x7).f[0] = (float)XMM(modrm & 0x7).i[0]; + XMM((modrm >> 3) & 0x7).f[1] = (float)XMM(modrm & 0x7).i[1]; + XMM((modrm >> 3) & 0x7).f[2] = (float)XMM(modrm & 0x7).i[2]; + XMM((modrm >> 3) & 0x7).f[3] = (float)XMM(modrm & 0x7).i[3]; + } else { + XMM_REG r; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, r); + XMM((modrm >> 3) & 0x7).f[0] = (float)r.i[0]; + XMM((modrm >> 3) & 0x7).f[1] = (float)r.i[1]; + XMM((modrm >> 3) & 0x7).f[2] = (float)r.i[2]; + XMM((modrm >> 3) & 0x7).f[3] = (float)r.i[3]; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_cvtdq2pd_r128_r128m64() // Opcode f3 0f e6 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + XMM((modrm >> 3) & 0x7).f64[0] = (double)XMM(modrm & 0x7).i[0]; + XMM((modrm >> 3) & 0x7).f64[1] = (double)XMM(modrm & 0x7).i[1]; + } else { + MMX_REG s; + UINT32 ea = GetEA(modrm, 0); + READMMX(ea, s); + XMM((modrm >> 3) & 0x7).f64[0] = (double)s.i[0]; + XMM((modrm >> 3) & 0x7).f64[1] = (double)s.i[1]; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_movss_r128_rm128() // Opcode f3 0f 10 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + XMM((modrm >> 3) & 0x7).d[0] = XMM(modrm & 0x7).d[0]; + } else { + UINT32 ea = GetEA(modrm, 0); + XMM((modrm >> 3) & 0x7).d[0] = READ32(ea); + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_movss_rm128_r128() // Opcode f3 0f 11 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + XMM(modrm & 0x7).d[0] = XMM((modrm >> 3) & 0x7).d[0]; + } else { + UINT32 ea = GetEA(modrm, 0); + WRITE32(ea, XMM((modrm >> 3) & 0x7).d[0]); + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_movsldup_r128_rm128() // Opcode f3 0f 12 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + XMM((modrm >> 3) & 0x7).d[0] = XMM(modrm & 0x7).d[0]; + XMM((modrm >> 3) & 0x7).d[1] = XMM(modrm & 0x7).d[0]; + XMM((modrm >> 3) & 0x7).d[2] = XMM(modrm & 0x7).d[2]; + XMM((modrm >> 3) & 0x7).d[3] = XMM(modrm & 0x7).d[2]; + } else { + XMM_REG src; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, src); + XMM((modrm >> 3) & 0x7).d[0] = src.d[0]; + XMM((modrm >> 3) & 0x7).d[1] = src.d[0]; + XMM((modrm >> 3) & 0x7).d[2] = src.d[2]; + XMM((modrm >> 3) & 0x7).d[3] = src.d[2]; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_movshdup_r128_rm128() // Opcode f3 0f 16 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + XMM((modrm >> 3) & 0x7).d[0] = XMM(modrm & 0x7).d[1]; + XMM((modrm >> 3) & 0x7).d[1] = XMM(modrm & 0x7).d[1]; + XMM((modrm >> 3) & 0x7).d[2] = XMM(modrm & 0x7).d[3]; + XMM((modrm >> 3) & 0x7).d[3] = XMM(modrm & 0x7).d[3]; + } else { + XMM_REG src; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, src); + XMM((modrm >> 3) & 0x7).d[0] = src.d[1]; + XMM((modrm >> 3) & 0x7).d[1] = src.d[1]; + XMM((modrm >> 3) & 0x7).d[2] = src.d[3]; + XMM((modrm >> 3) & 0x7).d[3] = src.d[3]; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_movaps_r128_rm128() // Opcode 0f 28 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + XMM((modrm >> 3) & 0x7) = XMM(modrm & 0x7); + } else { + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, XMM((modrm >> 3) & 0x7)); + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_movaps_rm128_r128() // Opcode 0f 29 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + XMM(modrm & 0x7) = XMM((modrm >> 3) & 0x7); + } else { + UINT32 ea = GetEA(modrm, 0); + WRITEXMM(ea, XMM((modrm >> 3) & 0x7)); + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_movups_r128_rm128() // Opcode 0f 10 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + XMM((modrm >> 3) & 0x7) = XMM(modrm & 0x7); + } else { + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, XMM((modrm >> 3) & 0x7)); // address does not need to be 16-byte aligned + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_movupd_r128_rm128() // Opcode 66 0f 10 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + XMM((modrm >> 3) & 0x7) = XMM(modrm & 0x7); + } else { + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, XMM((modrm >> 3) & 0x7)); // address does not need to be 16-byte aligned + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_movups_rm128_r128() // Opcode 0f 11 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + XMM(modrm & 0x7) = XMM((modrm >> 3) & 0x7); + } else { + UINT32 ea = GetEA(modrm, 0); + WRITEXMM(ea, XMM((modrm >> 3) & 0x7)); // address does not need to be 16-byte aligned + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_movupd_rm128_r128() // Opcode 66 0f 11 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + XMM(modrm & 0x7) = XMM((modrm >> 3) & 0x7); + } else { + UINT32 ea = GetEA(modrm, 0); + WRITEXMM(ea, XMM((modrm >> 3) & 0x7)); // address does not need to be 16-byte aligned + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_movlps_r128_m64() // Opcode 0f 12 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + // MOVHLPS opcode + XMM((modrm >> 3) & 0x7).q[0] = XMM(modrm & 0x7).q[1]; + CYCLES(1); // TODO: correct cycle count + } else { + // MOVLPS opcode + UINT32 ea = GetEA(modrm, 0); + READXMM_LO64(ea, XMM((modrm >> 3) & 0x7)); + CYCLES(1); // TODO: correct cycle count + } +} + +void i386_device::sse_movlpd_r128_m64() // Opcode 66 0f 12 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + CYCLES(1); // TODO: correct cycle count + } else { + // MOVLPS opcode + UINT32 ea = GetEA(modrm, 0); + READXMM_LO64(ea, XMM((modrm >> 3) & 0x7)); + CYCLES(1); // TODO: correct cycle count + } +} + +void i386_device::sse_movlps_m64_r128() // Opcode 0f 13 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + // unsupported by cpu + CYCLES(1); // TODO: correct cycle count + } else { + UINT32 ea = GetEA(modrm, 0); + WRITEXMM_LO64(ea, XMM((modrm >> 3) & 0x7)); + CYCLES(1); // TODO: correct cycle count + } +} + +void i386_device::sse_movlpd_m64_r128() // Opcode 66 0f 13 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + // unsupported by cpu + CYCLES(1); // TODO: correct cycle count + } else { + UINT32 ea = GetEA(modrm, 0); + WRITEXMM_LO64(ea, XMM((modrm >> 3) & 0x7)); + CYCLES(1); // TODO: correct cycle count + } +} + +void i386_device::sse_movhps_r128_m64() // Opcode 0f 16 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + // MOVLHPS opcode + XMM((modrm >> 3) & 0x7).q[1] = XMM(modrm & 0x7).q[0]; + CYCLES(1); // TODO: correct cycle count + } else { + // MOVHPS opcode + UINT32 ea = GetEA(modrm, 0); + READXMM_HI64(ea, XMM((modrm >> 3) & 0x7)); + CYCLES(1); // TODO: correct cycle count + } +} + +void i386_device::sse_movhpd_r128_m64() // Opcode 66 0f 16 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + // unsupported by cpu + CYCLES(1); // TODO: correct cycle count + } else { + // MOVHPS opcode + UINT32 ea = GetEA(modrm, 0); + READXMM_HI64(ea, XMM((modrm >> 3) & 0x7)); + CYCLES(1); // TODO: correct cycle count + } +} + +void i386_device::sse_movhps_m64_r128() // Opcode 0f 17 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + // unsupported by cpu + CYCLES(1); // TODO: correct cycle count + } else { + UINT32 ea = GetEA(modrm, 0); + WRITEXMM_HI64(ea, XMM((modrm >> 3) & 0x7)); + CYCLES(1); // TODO: correct cycle count + } +} + +void i386_device::sse_movhpd_m64_r128() // Opcode 66 0f 17 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + // unsupported by cpu + CYCLES(1); // TODO: correct cycle count + } else { + UINT32 ea = GetEA(modrm, 0); + WRITEXMM_HI64(ea, XMM((modrm >> 3) & 0x7)); + CYCLES(1); // TODO: correct cycle count + } +} + +void i386_device::sse_movntps_m128_r128() // Opcode 0f 2b +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + // unsupported by cpu + CYCLES(1); // TODO: correct cycle count + } else { + // since cache is not implemented + UINT32 ea = GetEA(modrm, 0); + WRITEXMM(ea, XMM((modrm >> 3) & 0x7)); + CYCLES(1); // TODO: correct cycle count + } +} + +void i386_device::sse_movmskps_r16_r128() // Opcode 0f 50 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + int b; + b=(XMM(modrm & 0x7).d[0] >> 31) & 1; + b=b | ((XMM(modrm & 0x7).d[1] >> 30) & 2); + b=b | ((XMM(modrm & 0x7).d[2] >> 29) & 4); + b=b | ((XMM(modrm & 0x7).d[3] >> 28) & 8); + STORE_REG16(modrm, b); + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_movmskps_r32_r128() // Opcode 0f 50 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + int b; + b=(XMM(modrm & 0x7).d[0] >> 31) & 1; + b=b | ((XMM(modrm & 0x7).d[1] >> 30) & 2); + b=b | ((XMM(modrm & 0x7).d[2] >> 29) & 4); + b=b | ((XMM(modrm & 0x7).d[3] >> 28) & 8); + STORE_REG32(modrm, b); + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_movmskpd_r32_r128() // Opcode 66 0f 50 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + int b; + b=(XMM(modrm & 0x7).q[0] >> 63) & 1; + b=b | ((XMM(modrm & 0x7).q[1] >> 62) & 2); + STORE_REG32(modrm, b); + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_movq2dq_r128_r64() // Opcode f3 0f d6 +{ + MMXPROLOG(); + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + XMM((modrm >> 3) & 0x7).q[0] = MMX(modrm & 7).q; + XMM((modrm >> 3) & 0x7).q[1] = 0; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_movdqu_r128_rm128() // Opcode f3 0f 6f +{ + MMXPROLOG(); + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + XMM((modrm >> 3) & 0x7).q[0] = XMM(modrm & 0x7).q[0]; + XMM((modrm >> 3) & 0x7).q[1] = XMM(modrm & 0x7).q[1]; + } else { + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, XMM((modrm >> 3) & 0x7)); + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_movdqu_rm128_r128() // Opcode f3 0f 7f +{ + MMXPROLOG(); + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + XMM(modrm & 0x7).q[0] = XMM((modrm >> 3) & 0x7).q[0]; + XMM(modrm & 0x7).q[1] = XMM((modrm >> 3) & 0x7).q[1]; + } else { + UINT32 ea = GetEA(modrm, 0); + WRITEXMM(ea, XMM((modrm >> 3) & 0x7)); + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_movd_m128_rm32() // Opcode 66 0f 6e +{ + UINT8 modrm = FETCH(); + if (modrm >= 0xc0) { + XMM((modrm >> 3) & 0x7).d[0] = LOAD_RM32(modrm); + } + else { + UINT32 ea = GetEA(modrm, 0); + XMM((modrm >> 3) & 0x7).d[0] = READ32(ea); + } + XMM((modrm >> 3) & 0x7).d[1] = 0; + XMM((modrm >> 3) & 0x7).q[1] = 0; + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_movdqa_m128_rm128() // Opcode 66 0f 6f +{ + UINT8 modrm = FETCH(); + if (modrm >= 0xc0) { + XMM((modrm >> 3) & 0x7).q[0] = XMM(modrm & 0x7).q[0]; + XMM((modrm >> 3) & 0x7).q[1] = XMM(modrm & 0x7).q[1]; + } + else { + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, XMM((modrm >> 3) & 0x7)); + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_movq_r128_r128m64() // Opcode f3 0f 7e +{ + MMXPROLOG(); + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + XMM((modrm >> 3) & 0x7).q[0] = XMM(modrm & 0x7).q[0]; + XMM((modrm >> 3) & 0x7).q[1] = 0; + } else { + UINT32 ea = GetEA(modrm, 0); + XMM((modrm >> 3) & 0x7).q[0] = READ64(ea); + XMM((modrm >> 3) & 0x7).q[1] = 0; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_movd_rm32_r128() // Opcode 66 0f 7e +{ + UINT8 modrm = FETCH(); + if (modrm >= 0xc0) { + STORE_RM32(modrm, XMM((modrm >> 3) & 0x7).d[0]); + } + else { + UINT32 ea = GetEA(modrm, 0); + WRITE32(ea, XMM((modrm >> 3) & 0x7).d[0]); + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_movdqa_rm128_r128() // Opcode 66 0f 7f +{ + UINT8 modrm = FETCH(); + if (modrm >= 0xc0) { + XMM(modrm & 0x7).q[0] = XMM((modrm >> 3) & 0x7).q[0]; + XMM(modrm & 0x7).q[1] = XMM((modrm >> 3) & 0x7).q[1]; + } + else { + UINT32 ea = GetEA(modrm, 0); + WRITEXMM(ea, XMM((modrm >> 3) & 0x7)); + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_pmovmskb_r16_r64() // Opcode 0f d7 +{ + //MMXPROLOG(); + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + int b; + b=(MMX(modrm & 0x7).b[0] >> 7) & 1; + b=b | ((MMX(modrm & 0x7).b[1] >> 6) & 2); + b=b | ((MMX(modrm & 0x7).b[2] >> 5) & 4); + b=b | ((MMX(modrm & 0x7).b[3] >> 4) & 8); + b=b | ((MMX(modrm & 0x7).b[4] >> 3) & 16); + b=b | ((MMX(modrm & 0x7).b[5] >> 2) & 32); + b=b | ((MMX(modrm & 0x7).b[6] >> 1) & 64); + b=b | ((MMX(modrm & 0x7).b[7] >> 0) & 128); + STORE_REG16(modrm, b); + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_pmovmskb_r32_r64() // Opcode 0f d7 +{ + //MMXPROLOG(); + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + int b; + b=(MMX(modrm & 0x7).b[0] >> 7) & 1; + b=b | ((MMX(modrm & 0x7).b[1] >> 6) & 2); + b=b | ((MMX(modrm & 0x7).b[2] >> 5) & 4); + b=b | ((MMX(modrm & 0x7).b[3] >> 4) & 8); + b=b | ((MMX(modrm & 0x7).b[4] >> 3) & 16); + b=b | ((MMX(modrm & 0x7).b[5] >> 2) & 32); + b=b | ((MMX(modrm & 0x7).b[6] >> 1) & 64); + b=b | ((MMX(modrm & 0x7).b[7] >> 0) & 128); + STORE_REG32(modrm, b); + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_pmovmskb_r32_r128() // Opcode 66 0f d7 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + UINT32 b; + b=(XMM(modrm & 0x7).b[0] >> 7) & 1; + b=b | ((XMM(modrm & 0x7).b[1] >> 6) & 2); + b=b | ((XMM(modrm & 0x7).b[2] >> 5) & 4); + b=b | ((XMM(modrm & 0x7).b[3] >> 4) & 8); + b=b | ((XMM(modrm & 0x7).b[4] >> 3) & 16); + b=b | ((XMM(modrm & 0x7).b[5] >> 2) & 32); + b=b | ((XMM(modrm & 0x7).b[6] >> 1) & 64); + b=b | ((XMM(modrm & 0x7).b[7] >> 0) & 128); + b=b | ((XMM(modrm & 0x7).b[8] << 1) & 256); + b=b | ((XMM(modrm & 0x7).b[9] << 2) & 512); + b=b | ((XMM(modrm & 0x7).b[10] << 3) & 1024); + b=b | ((XMM(modrm & 0x7).b[11] << 4) & 2048); + b=b | ((XMM(modrm & 0x7).b[12] << 5) & 4096); + b=b | ((XMM(modrm & 0x7).b[13] << 6) & 8192); + b=b | ((XMM(modrm & 0x7).b[14] << 7) & 16384); + b=b | ((XMM(modrm & 0x7).b[15] << 8) & 32768); + STORE_REG32(modrm, b); + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_xorps() // Opcode 0f 57 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + XMM((modrm >> 3) & 0x7).d[0] = XMM((modrm >> 3) & 0x7).d[0] ^ XMM(modrm & 0x7).d[0]; + XMM((modrm >> 3) & 0x7).d[1] = XMM((modrm >> 3) & 0x7).d[1] ^ XMM(modrm & 0x7).d[1]; + XMM((modrm >> 3) & 0x7).d[2] = XMM((modrm >> 3) & 0x7).d[2] ^ XMM(modrm & 0x7).d[2]; + XMM((modrm >> 3) & 0x7).d[3] = XMM((modrm >> 3) & 0x7).d[3] ^ XMM(modrm & 0x7).d[3]; + } else { + XMM_REG src; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, src); + XMM((modrm >> 3) & 0x7).d[0] = XMM((modrm >> 3) & 0x7).d[0] ^ src.d[0]; + XMM((modrm >> 3) & 0x7).d[1] = XMM((modrm >> 3) & 0x7).d[1] ^ src.d[1]; + XMM((modrm >> 3) & 0x7).d[2] = XMM((modrm >> 3) & 0x7).d[2] ^ src.d[2]; + XMM((modrm >> 3) & 0x7).d[3] = XMM((modrm >> 3) & 0x7).d[3] ^ src.d[3]; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_xorpd_r128_rm128() // Opcode 66 0f 57 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + XMM((modrm >> 3) & 0x7).q[0] = XMM((modrm >> 3) & 0x7).q[0] ^ XMM(modrm & 0x7).q[0]; + XMM((modrm >> 3) & 0x7).q[1] = XMM((modrm >> 3) & 0x7).q[1] ^ XMM(modrm & 0x7).q[1]; + } else { + XMM_REG src; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, src); + XMM((modrm >> 3) & 0x7).q[0] = XMM((modrm >> 3) & 0x7).q[0] ^ src.q[0]; + XMM((modrm >> 3) & 0x7).q[1] = XMM((modrm >> 3) & 0x7).q[1] ^ src.q[1]; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_addps() // Opcode 0f 58 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + XMM((modrm >> 3) & 0x7).f[0] = XMM((modrm >> 3) & 0x7).f[0] + XMM(modrm & 0x7).f[0]; + XMM((modrm >> 3) & 0x7).f[1] = XMM((modrm >> 3) & 0x7).f[1] + XMM(modrm & 0x7).f[1]; + XMM((modrm >> 3) & 0x7).f[2] = XMM((modrm >> 3) & 0x7).f[2] + XMM(modrm & 0x7).f[2]; + XMM((modrm >> 3) & 0x7).f[3] = XMM((modrm >> 3) & 0x7).f[3] + XMM(modrm & 0x7).f[3]; + } else { + XMM_REG src; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, src); + XMM((modrm >> 3) & 0x7).f[0] = XMM((modrm >> 3) & 0x7).f[0] + src.f[0]; + XMM((modrm >> 3) & 0x7).f[1] = XMM((modrm >> 3) & 0x7).f[1] + src.f[1]; + XMM((modrm >> 3) & 0x7).f[2] = XMM((modrm >> 3) & 0x7).f[2] + src.f[2]; + XMM((modrm >> 3) & 0x7).f[3] = XMM((modrm >> 3) & 0x7).f[3] + src.f[3]; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_sqrtps_r128_rm128() // Opcode 0f 51 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + XMM((modrm >> 3) & 0x7).f[0] = sqrt(XMM(modrm & 0x7).f[0]); + XMM((modrm >> 3) & 0x7).f[1] = sqrt(XMM(modrm & 0x7).f[1]); + XMM((modrm >> 3) & 0x7).f[2] = sqrt(XMM(modrm & 0x7).f[2]); + XMM((modrm >> 3) & 0x7).f[3] = sqrt(XMM(modrm & 0x7).f[3]); + } else { + XMM_REG src; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, src); + XMM((modrm >> 3) & 0x7).f[0] = sqrt(src.f[0]); + XMM((modrm >> 3) & 0x7).f[1] = sqrt(src.f[1]); + XMM((modrm >> 3) & 0x7).f[2] = sqrt(src.f[2]); + XMM((modrm >> 3) & 0x7).f[3] = sqrt(src.f[3]); + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_rsqrtps_r128_rm128() // Opcode 0f 52 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + XMM((modrm >> 3) & 0x7).f[0] = 1.0 / sqrt(XMM(modrm & 0x7).f[0]); + XMM((modrm >> 3) & 0x7).f[1] = 1.0 / sqrt(XMM(modrm & 0x7).f[1]); + XMM((modrm >> 3) & 0x7).f[2] = 1.0 / sqrt(XMM(modrm & 0x7).f[2]); + XMM((modrm >> 3) & 0x7).f[3] = 1.0 / sqrt(XMM(modrm & 0x7).f[3]); + } else { + XMM_REG src; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, src); + XMM((modrm >> 3) & 0x7).f[0] = 1.0 / sqrt(src.f[0]); + XMM((modrm >> 3) & 0x7).f[1] = 1.0 / sqrt(src.f[1]); + XMM((modrm >> 3) & 0x7).f[2] = 1.0 / sqrt(src.f[2]); + XMM((modrm >> 3) & 0x7).f[3] = 1.0 / sqrt(src.f[3]); + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_rcpps_r128_rm128() // Opcode 0f 53 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + XMM((modrm >> 3) & 0x7).f[0] = 1.0f / XMM(modrm & 0x7).f[0]; + XMM((modrm >> 3) & 0x7).f[1] = 1.0f / XMM(modrm & 0x7).f[1]; + XMM((modrm >> 3) & 0x7).f[2] = 1.0f / XMM(modrm & 0x7).f[2]; + XMM((modrm >> 3) & 0x7).f[3] = 1.0f / XMM(modrm & 0x7).f[3]; + } else { + XMM_REG src; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, src); + XMM((modrm >> 3) & 0x7).f[0] = 1.0f / src.f[0]; + XMM((modrm >> 3) & 0x7).f[1] = 1.0f / src.f[1]; + XMM((modrm >> 3) & 0x7).f[2] = 1.0f / src.f[2]; + XMM((modrm >> 3) & 0x7).f[3] = 1.0f / src.f[3]; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_andps_r128_rm128() // Opcode 0f 54 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + XMM((modrm >> 3) & 0x7).q[0] = XMM((modrm >> 3) & 0x7).q[0] & XMM(modrm & 0x7).q[0]; + XMM((modrm >> 3) & 0x7).q[1] = XMM((modrm >> 3) & 0x7).q[1] & XMM(modrm & 0x7).q[1]; + } else { + XMM_REG src; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, src); + XMM((modrm >> 3) & 0x7).q[0] = XMM((modrm >> 3) & 0x7).q[0] & src.q[0]; + XMM((modrm >> 3) & 0x7).q[1] = XMM((modrm >> 3) & 0x7).q[1] & src.q[1]; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_andpd_r128_rm128() // Opcode 66 0f 54 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + XMM((modrm >> 3) & 0x7).q[0] = XMM((modrm >> 3) & 0x7).q[0] & XMM(modrm & 0x7).q[0]; + XMM((modrm >> 3) & 0x7).q[1] = XMM((modrm >> 3) & 0x7).q[1] & XMM(modrm & 0x7).q[1]; + } else { + XMM_REG src; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, src); + XMM((modrm >> 3) & 0x7).q[0] = XMM((modrm >> 3) & 0x7).q[0] & src.q[0]; + XMM((modrm >> 3) & 0x7).q[1] = XMM((modrm >> 3) & 0x7).q[1] & src.q[1]; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_andnps_r128_rm128() // Opcode 0f 55 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + XMM((modrm >> 3) & 0x7).q[0] = ~(XMM((modrm >> 3) & 0x7).q[0]) & XMM(modrm & 0x7).q[0]; + XMM((modrm >> 3) & 0x7).q[1] = ~(XMM((modrm >> 3) & 0x7).q[1]) & XMM(modrm & 0x7).q[1]; + } else { + XMM_REG src; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, src); + XMM((modrm >> 3) & 0x7).q[0] = ~(XMM((modrm >> 3) & 0x7).q[0]) & src.q[0]; + XMM((modrm >> 3) & 0x7).q[1] = ~(XMM((modrm >> 3) & 0x7).q[1]) & src.q[1]; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_andnpd_r128_rm128() // Opcode 66 0f 55 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + XMM((modrm >> 3) & 0x7).q[0] = ~(XMM((modrm >> 3) & 0x7).q[0]) & XMM(modrm & 0x7).q[0]; + XMM((modrm >> 3) & 0x7).q[1] = ~(XMM((modrm >> 3) & 0x7).q[1]) & XMM(modrm & 0x7).q[1]; + } else { + XMM_REG src; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, src); + XMM((modrm >> 3) & 0x7).q[0] = ~(XMM((modrm >> 3) & 0x7).q[0]) & src.q[0]; + XMM((modrm >> 3) & 0x7).q[1] = ~(XMM((modrm >> 3) & 0x7).q[1]) & src.q[1]; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_orps_r128_rm128() // Opcode 0f 56 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + XMM((modrm >> 3) & 0x7).q[0] = XMM((modrm >> 3) & 0x7).q[0] | XMM(modrm & 0x7).q[0]; + XMM((modrm >> 3) & 0x7).q[1] = XMM((modrm >> 3) & 0x7).q[1] | XMM(modrm & 0x7).q[1]; + } else { + XMM_REG src; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, src); + XMM((modrm >> 3) & 0x7).q[0] = XMM((modrm >> 3) & 0x7).q[0] | src.q[0]; + XMM((modrm >> 3) & 0x7).q[1] = XMM((modrm >> 3) & 0x7).q[1] | src.q[1]; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_orpd_r128_rm128() // Opcode 66 0f 56 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + XMM((modrm >> 3) & 0x7).q[0] = XMM((modrm >> 3) & 0x7).q[0] | XMM(modrm & 0x7).q[0]; + XMM((modrm >> 3) & 0x7).q[1] = XMM((modrm >> 3) & 0x7).q[1] | XMM(modrm & 0x7).q[1]; + } else { + XMM_REG src; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, src); + XMM((modrm >> 3) & 0x7).q[0] = XMM((modrm >> 3) & 0x7).q[0] | src.q[0]; + XMM((modrm >> 3) & 0x7).q[1] = XMM((modrm >> 3) & 0x7).q[1] | src.q[1]; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_mulps() // Opcode 0f 59 ???? +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + XMM((modrm >> 3) & 0x7).f[0] = XMM((modrm >> 3) & 0x7).f[0] * XMM(modrm & 0x7).f[0]; + XMM((modrm >> 3) & 0x7).f[1] = XMM((modrm >> 3) & 0x7).f[1] * XMM(modrm & 0x7).f[1]; + XMM((modrm >> 3) & 0x7).f[2] = XMM((modrm >> 3) & 0x7).f[2] * XMM(modrm & 0x7).f[2]; + XMM((modrm >> 3) & 0x7).f[3] = XMM((modrm >> 3) & 0x7).f[3] * XMM(modrm & 0x7).f[3]; + } else { + XMM_REG src; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, src); + XMM((modrm >> 3) & 0x7).f[0] = XMM((modrm >> 3) & 0x7).f[0] * src.f[0]; + XMM((modrm >> 3) & 0x7).f[1] = XMM((modrm >> 3) & 0x7).f[1] * src.f[1]; + XMM((modrm >> 3) & 0x7).f[2] = XMM((modrm >> 3) & 0x7).f[2] * src.f[2]; + XMM((modrm >> 3) & 0x7).f[3] = XMM((modrm >> 3) & 0x7).f[3] * src.f[3]; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_subps() // Opcode 0f 5c +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + XMM((modrm >> 3) & 0x7).f[0] = XMM((modrm >> 3) & 0x7).f[0] - XMM(modrm & 0x7).f[0]; + XMM((modrm >> 3) & 0x7).f[1] = XMM((modrm >> 3) & 0x7).f[1] - XMM(modrm & 0x7).f[1]; + XMM((modrm >> 3) & 0x7).f[2] = XMM((modrm >> 3) & 0x7).f[2] - XMM(modrm & 0x7).f[2]; + XMM((modrm >> 3) & 0x7).f[3] = XMM((modrm >> 3) & 0x7).f[3] - XMM(modrm & 0x7).f[3]; + } else { + XMM_REG src; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, src); + XMM((modrm >> 3) & 0x7).f[0] = XMM((modrm >> 3) & 0x7).f[0] - src.f[0]; + XMM((modrm >> 3) & 0x7).f[1] = XMM((modrm >> 3) & 0x7).f[1] - src.f[1]; + XMM((modrm >> 3) & 0x7).f[2] = XMM((modrm >> 3) & 0x7).f[2] - src.f[2]; + XMM((modrm >> 3) & 0x7).f[3] = XMM((modrm >> 3) & 0x7).f[3] - src.f[3]; + } + CYCLES(1); // TODO: correct cycle count +} + +INLINE float sse_min_single(float src1, float src2) +{ + /*if ((src1 == 0) && (src2 == 0)) + return src2; + if (src1 = SNaN) + return src2; + if (src2 = SNaN) + return src2;*/ + if (src1 < src2) + return src1; + return src2; +} + +INLINE double sse_min_double(double src1, double src2) +{ + /*if ((src1 == 0) && (src2 == 0)) + return src2; + if (src1 = SNaN) + return src2; + if (src2 = SNaN) + return src2;*/ + if (src1 < src2) + return src1; + return src2; +} + +void i386_device::sse_minps() // Opcode 0f 5d +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + XMM((modrm >> 3) & 0x7).f[0] = sse_min_single(XMM((modrm >> 3) & 0x7).f[0], XMM(modrm & 0x7).f[0]); + XMM((modrm >> 3) & 0x7).f[1] = sse_min_single(XMM((modrm >> 3) & 0x7).f[1], XMM(modrm & 0x7).f[1]); + XMM((modrm >> 3) & 0x7).f[2] = sse_min_single(XMM((modrm >> 3) & 0x7).f[2], XMM(modrm & 0x7).f[2]); + XMM((modrm >> 3) & 0x7).f[3] = sse_min_single(XMM((modrm >> 3) & 0x7).f[3], XMM(modrm & 0x7).f[3]); + } else { + XMM_REG src; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, src); + XMM((modrm >> 3) & 0x7).f[0] = sse_min_single(XMM((modrm >> 3) & 0x7).f[0], src.f[0]); + XMM((modrm >> 3) & 0x7).f[1] = sse_min_single(XMM((modrm >> 3) & 0x7).f[1], src.f[1]); + XMM((modrm >> 3) & 0x7).f[2] = sse_min_single(XMM((modrm >> 3) & 0x7).f[2], src.f[2]); + XMM((modrm >> 3) & 0x7).f[3] = sse_min_single(XMM((modrm >> 3) & 0x7).f[3], src.f[3]); + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_divps() // Opcode 0f 5e +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + XMM((modrm >> 3) & 0x7).f[0] = XMM((modrm >> 3) & 0x7).f[0] / XMM(modrm & 0x7).f[0]; + XMM((modrm >> 3) & 0x7).f[1] = XMM((modrm >> 3) & 0x7).f[1] / XMM(modrm & 0x7).f[1]; + XMM((modrm >> 3) & 0x7).f[2] = XMM((modrm >> 3) & 0x7).f[2] / XMM(modrm & 0x7).f[2]; + XMM((modrm >> 3) & 0x7).f[3] = XMM((modrm >> 3) & 0x7).f[3] / XMM(modrm & 0x7).f[3]; + } else { + XMM_REG src; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, src); + XMM((modrm >> 3) & 0x7).f[0] = XMM((modrm >> 3) & 0x7).f[0] / src.f[0]; + XMM((modrm >> 3) & 0x7).f[1] = XMM((modrm >> 3) & 0x7).f[1] / src.f[1]; + XMM((modrm >> 3) & 0x7).f[2] = XMM((modrm >> 3) & 0x7).f[2] / src.f[2]; + XMM((modrm >> 3) & 0x7).f[3] = XMM((modrm >> 3) & 0x7).f[3] / src.f[3]; + } + CYCLES(1); // TODO: correct cycle count +} + +INLINE float sse_max_single(float src1, float src2) +{ + /*if ((src1 == 0) && (src2 == 0)) + return src2; + if (src1 = SNaN) + return src2; + if (src2 = SNaN) + return src2;*/ + if (src1 > src2) + return src1; + return src2; +} + +INLINE double sse_max_double(double src1, double src2) +{ + /*if ((src1 == 0) && (src2 == 0)) + return src2; + if (src1 = SNaN) + return src2; + if (src2 = SNaN) + return src2;*/ + if (src1 > src2) + return src1; + return src2; +} + +void i386_device::sse_maxps() // Opcode 0f 5f +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + XMM((modrm >> 3) & 0x7).f[0] = sse_max_single(XMM((modrm >> 3) & 0x7).f[0], XMM(modrm & 0x7).f[0]); + XMM((modrm >> 3) & 0x7).f[1] = sse_max_single(XMM((modrm >> 3) & 0x7).f[1], XMM(modrm & 0x7).f[1]); + XMM((modrm >> 3) & 0x7).f[2] = sse_max_single(XMM((modrm >> 3) & 0x7).f[2], XMM(modrm & 0x7).f[2]); + XMM((modrm >> 3) & 0x7).f[3] = sse_max_single(XMM((modrm >> 3) & 0x7).f[3], XMM(modrm & 0x7).f[3]); + } else { + XMM_REG src; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, src); + XMM((modrm >> 3) & 0x7).f[0] = sse_max_single(XMM((modrm >> 3) & 0x7).f[0], src.f[0]); + XMM((modrm >> 3) & 0x7).f[1] = sse_max_single(XMM((modrm >> 3) & 0x7).f[1], src.f[1]); + XMM((modrm >> 3) & 0x7).f[2] = sse_max_single(XMM((modrm >> 3) & 0x7).f[2], src.f[2]); + XMM((modrm >> 3) & 0x7).f[3] = sse_max_single(XMM((modrm >> 3) & 0x7).f[3], src.f[3]); + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_maxss_r128_r128m32() // Opcode f3 0f 5f +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + XMM((modrm >> 3) & 0x7).f[0] = sse_max_single(XMM((modrm >> 3) & 0x7).f[0], XMM(modrm & 0x7).f[0]); + } else { + XMM_REG src; + UINT32 ea = GetEA(modrm, 0); + src.d[0]=READ32(ea); + XMM((modrm >> 3) & 0x7).f[0] = sse_max_single(XMM((modrm >> 3) & 0x7).f[0], src.f[0]); + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_addss() // Opcode f3 0f 58 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + XMM((modrm >> 3) & 0x7).f[0] = XMM((modrm >> 3) & 0x7).f[0] + XMM(modrm & 0x7).f[0]; + } else { + XMM_REG src; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, src); + XMM((modrm >> 3) & 0x7).f[0] = XMM((modrm >> 3) & 0x7).f[0] + src.f[0]; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_subss() // Opcode f3 0f 5c +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + XMM((modrm >> 3) & 0x7).f[0] = XMM((modrm >> 3) & 0x7).f[0] - XMM(modrm & 0x7).f[0]; + } else { + XMM_REG src; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, src); + XMM((modrm >> 3) & 0x7).f[0] = XMM((modrm >> 3) & 0x7).f[0] - src.f[0]; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_mulss() // Opcode f3 0f 5e +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + XMM((modrm >> 3) & 0x7).f[0] = XMM((modrm >> 3) & 0x7).f[0] * XMM(modrm & 0x7).f[0]; + } else { + XMM_REG src; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, src); + XMM((modrm >> 3) & 0x7).f[0] = XMM((modrm >> 3) & 0x7).f[0] * src.f[0]; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_divss() // Opcode 0f 59 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + XMM((modrm >> 3) & 0x7).f[0] = XMM((modrm >> 3) & 0x7).f[0] / XMM(modrm & 0x7).f[0]; + } else { + XMM_REG src; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, src); + XMM((modrm >> 3) & 0x7).f[0] = XMM((modrm >> 3) & 0x7).f[0] / src.f[0]; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_rcpss_r128_r128m32() // Opcode f3 0f 53 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + XMM((modrm >> 3) & 0x7).f[0] = 1.0f / XMM(modrm & 0x7).f[0]; + } else { + XMM_REG s; + UINT32 ea = GetEA(modrm, 0); + s.d[0]=READ32(ea); + XMM((modrm >> 3) & 0x7).f[0] = 1.0f / s.f[0]; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_sqrtss_r128_r128m32() // Opcode f3 0f 51 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + XMM((modrm >> 3) & 0x7).f[0] = sqrt(XMM(modrm & 0x7).f[0]); + } else { + XMM_REG s; + UINT32 ea = GetEA(modrm, 0); + s.d[0]=READ32(ea); + XMM((modrm >> 3) & 0x7).f[0] = sqrt(s.f[0]); + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_rsqrtss_r128_r128m32() // Opcode f3 0f 52 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + XMM((modrm >> 3) & 0x7).f[0] = 1.0 / sqrt(XMM(modrm & 0x7).f[0]); + } else { + XMM_REG s; + UINT32 ea = GetEA(modrm, 0); + s.d[0]=READ32(ea); + XMM((modrm >> 3) & 0x7).f[0] = 1.0 / sqrt(s.f[0]); + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_minss_r128_r128m32() // Opcode f3 0f 5d +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + XMM((modrm >> 3) & 0x7).f[0] = XMM((modrm >> 3) & 0x7).f[0] < XMM(modrm & 0x7).f[0] ? XMM((modrm >> 3) & 0x7).f[0] : XMM(modrm & 0x7).f[0]; + } else { + XMM_REG s; + UINT32 ea = GetEA(modrm, 0); + s.d[0] = READ32(ea); + XMM((modrm >> 3) & 0x7).f[0] = XMM((modrm >> 3) & 0x7).f[0] < s.f[0] ? XMM((modrm >> 3) & 0x7).f[0] : s.f[0]; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_comiss_r128_r128m32() // Opcode 0f 2f +{ + float32 a,b; + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + a = XMM((modrm >> 3) & 0x7).d[0]; + b = XMM(modrm & 0x7).d[0]; + } else { + XMM_REG src; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, src); + a = XMM((modrm >> 3) & 0x7).d[0]; + b = src.d[0]; + } + m_OF=0; + m_SF=0; + m_AF=0; + if (float32_is_nan(a) || float32_is_nan(b)) + { + m_ZF = 1; + m_PF = 1; + m_CF = 1; + } + else + { + m_ZF = 0; + m_PF = 0; + m_CF = 0; + if (float32_eq(a, b)) + m_ZF = 1; + if (float32_lt(a, b)) + m_CF = 1; + } + // should generate exception when at least one of the operands is either QNaN or SNaN + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_comisd_r128_r128m64() // Opcode 66 0f 2f +{ + float64 a,b; + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + a = XMM((modrm >> 3) & 0x7).q[0]; + b = XMM(modrm & 0x7).q[0]; + } else { + XMM_REG src; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, src); + a = XMM((modrm >> 3) & 0x7).q[0]; + b = src.q[0]; + } + m_OF=0; + m_SF=0; + m_AF=0; + if (float64_is_nan(a) || float64_is_nan(b)) + { + m_ZF = 1; + m_PF = 1; + m_CF = 1; + } + else + { + m_ZF = 0; + m_PF = 0; + m_CF = 0; + if (float64_eq(a, b)) + m_ZF = 1; + if (float64_lt(a, b)) + m_CF = 1; + } + // should generate exception when at least one of the operands is either QNaN or SNaN + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_ucomiss_r128_r128m32() // Opcode 0f 2e +{ + float32 a,b; + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + a = XMM((modrm >> 3) & 0x7).d[0]; + b = XMM(modrm & 0x7).d[0]; + } else { + XMM_REG src; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, src); + a = XMM((modrm >> 3) & 0x7).d[0]; + b = src.d[0]; + } + m_OF=0; + m_SF=0; + m_AF=0; + if (float32_is_nan(a) || float32_is_nan(b)) + { + m_ZF = 1; + m_PF = 1; + m_CF = 1; + } + else + { + m_ZF = 0; + m_PF = 0; + m_CF = 0; + if (float32_eq(a, b)) + m_ZF = 1; + if (float32_lt(a, b)) + m_CF = 1; + } + // should generate exception when at least one of the operands is SNaN + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_ucomisd_r128_r128m64() // Opcode 66 0f 2e +{ + float64 a,b; + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + a = XMM((modrm >> 3) & 0x7).q[0]; + b = XMM(modrm & 0x7).q[0]; + } else { + XMM_REG src; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, src); + a = XMM((modrm >> 3) & 0x7).q[0]; + b = src.q[0]; + } + m_OF=0; + m_SF=0; + m_AF=0; + if (float64_is_nan(a) || float64_is_nan(b)) + { + m_ZF = 1; + m_PF = 1; + m_CF = 1; + } + else + { + m_ZF = 0; + m_PF = 0; + m_CF = 0; + if (float64_eq(a, b)) + m_ZF = 1; + if (float64_lt(a, b)) + m_CF = 1; + } + // should generate exception when at least one of the operands is SNaN + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_shufps() // Opcode 0f c6 +{ + UINT8 modrm = FETCH(); + UINT8 sel = FETCH(); + int m1,m2,m3,m4; + int s,d; + m1=sel & 3; + m2=(sel >> 2) & 3; + m3=(sel >> 4) & 3; + m4=(sel >> 6) & 3; + s=modrm & 0x7; + d=(modrm >> 3) & 0x7; + if( modrm >= 0xc0 ) { + UINT32 t1,t2,t3,t4; + t1=XMM(d).d[m1]; + t2=XMM(d).d[m2]; + t3=XMM(s).d[m3]; + t4=XMM(s).d[m4]; + XMM(d).d[0]=t1; + XMM(d).d[1]=t2; + XMM(d).d[2]=t3; + XMM(d).d[3]=t4; + } else { + UINT32 t1,t2; + XMM_REG src; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, src); + t1=XMM(d).d[m1]; + t2=XMM(d).d[m2]; + XMM(d).d[0]=t1; + XMM(d).d[1]=t2; + XMM(d).d[2]=src.d[m3]; + XMM(d).d[3]=src.d[m4]; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_shufpd_r128_rm128_i8() // Opcode 66 0f c6 +{ + UINT8 modrm = FETCH(); + UINT8 sel = FETCH(); + int m1,m2; + int s,d; + m1=sel & 1; + m2=(sel >> 1) & 1; + s=modrm & 0x7; + d=(modrm >> 3) & 0x7; + if( modrm >= 0xc0 ) { + UINT64 t1,t2; + t1=XMM(d).q[m1]; + t2=XMM(s).q[m2]; + XMM(d).q[0]=t1; + XMM(d).q[1]=t2; + } else { + UINT64 t1; + XMM_REG src; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, src); + t1=XMM(d).q[m1]; + XMM(d).q[0]=t1; + XMM(d).q[1]=src.q[m2]; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_unpcklps_r128_rm128() // Opcode 0f 14 +{ + UINT8 modrm = FETCH(); + int s,d; + UINT32 t1, t2, t3, t4; + s=modrm & 0x7; + d=(modrm >> 3) & 0x7; + if( modrm >= 0xc0 ) { + t1 = XMM(s).d[1]; + t2 = XMM(d).d[1]; + t3 = XMM(s).d[0]; + t4 = XMM(d).d[0]; + XMM(d).d[3]=t1; + XMM(d).d[2]=t2; + XMM(d).d[1]=t3; + XMM(d).d[0]=t4; + } else { + XMM_REG src; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, src); + t2 = XMM(d).d[1]; + XMM(d).d[3]=src.d[1]; + XMM(d).d[2]=t2; + XMM(d).d[1]=src.d[0]; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_unpcklpd_r128_rm128() // Opcode 66 0f 14 +{ + UINT8 modrm = FETCH(); + int s,d; + s=modrm & 0x7; + d=(modrm >> 3) & 0x7; + if( modrm >= 0xc0 ) { + XMM(d).q[1]=XMM(s).q[0]; + XMM(d).q[0]=XMM(d).q[0]; + } else { + XMM_REG src; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, src); + XMM(d).q[1]=src.q[0]; + XMM(d).q[0]=XMM(d).q[0]; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_unpckhps_r128_rm128() // Opcode 0f 15 +{ + UINT8 modrm = FETCH(); + int s,d; + UINT32 t1, t2, t3, t4; + s=modrm & 0x7; + d=(modrm >> 3) & 0x7; + if( modrm >= 0xc0 ) { + t1 = XMM(d).d[2]; + t2 = XMM(s).d[2]; + t3 = XMM(d).d[3]; + t4 = XMM(s).d[3]; + XMM(d).d[0]=t1; + XMM(d).d[1]=t2; + XMM(d).d[2]=t3; + XMM(d).d[3]=t4; + } else { + XMM_REG src; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, src); + t1 = XMM(d).d[2]; + t2 = XMM(d).d[3]; + XMM(d).d[0]=t1; + XMM(d).d[1]=src.d[2]; + XMM(d).d[2]=t2; + XMM(d).d[3]=src.d[3]; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_unpckhpd_r128_rm128() // Opcode 66 0f 15 +{ + UINT8 modrm = FETCH(); + int s,d; + s=modrm & 0x7; + d=(modrm >> 3) & 0x7; + if( modrm >= 0xc0 ) { + XMM(d).q[0]=XMM(d).q[1]; + XMM(d).q[1]=XMM(s).q[1]; + } else { + XMM_REG src; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, src); + XMM(d).q[0]=XMM(d).q[1]; + XMM(d).q[1]=src.q[1]; + } + CYCLES(1); // TODO: correct cycle count +} + +INLINE bool sse_issingleordered(float op1, float op2) +{ + // TODO: true when at least one of the two source operands being compared is a NaN + return (op1 != op1) || (op1 != op2); +} + +INLINE bool sse_issingleunordered(float op1, float op2) +{ + // TODO: true when neither source operand is a NaN + return !((op1 != op1) || (op1 != op2)); +} + +INLINE bool sse_isdoubleordered(double op1, double op2) +{ + // TODO: true when at least one of the two source operands being compared is a NaN + return (op1 != op1) || (op1 != op2); +} + +INLINE bool sse_isdoubleunordered(double op1, double op2) +{ + // TODO: true when neither source operand is a NaN + return !((op1 != op1) || (op1 != op2)); +} + +void i386_device::sse_predicate_compare_single(UINT8 imm8, XMM_REG d, XMM_REG s) +{ + switch (imm8 & 7) + { + case 0: + d.d[0]=d.f[0] == s.f[0] ? 0xffffffff : 0; + d.d[1]=d.f[1] == s.f[1] ? 0xffffffff : 0; + d.d[2]=d.f[2] == s.f[2] ? 0xffffffff : 0; + d.d[3]=d.f[3] == s.f[3] ? 0xffffffff : 0; + break; + case 1: + d.d[0]=d.f[0] < s.f[0] ? 0xffffffff : 0; + d.d[1]=d.f[1] < s.f[1] ? 0xffffffff : 0; + d.d[2]=d.f[2] < s.f[2] ? 0xffffffff : 0; + d.d[3]=d.f[3] < s.f[3] ? 0xffffffff : 0; + break; + case 2: + d.d[0]=d.f[0] <= s.f[0] ? 0xffffffff : 0; + d.d[1]=d.f[1] <= s.f[1] ? 0xffffffff : 0; + d.d[2]=d.f[2] <= s.f[2] ? 0xffffffff : 0; + d.d[3]=d.f[3] <= s.f[3] ? 0xffffffff : 0; + break; + case 3: + d.d[0]=sse_issingleunordered(d.f[0], s.f[0]) ? 0xffffffff : 0; + d.d[1]=sse_issingleunordered(d.f[1], s.f[1]) ? 0xffffffff : 0; + d.d[2]=sse_issingleunordered(d.f[2], s.f[2]) ? 0xffffffff : 0; + d.d[3]=sse_issingleunordered(d.f[3], s.f[3]) ? 0xffffffff : 0; + break; + case 4: + d.d[0]=d.f[0] != s.f[0] ? 0xffffffff : 0; + d.d[1]=d.f[1] != s.f[1] ? 0xffffffff : 0; + d.d[2]=d.f[2] != s.f[2] ? 0xffffffff : 0; + d.d[3]=d.f[3] != s.f[3] ? 0xffffffff : 0; + break; + case 5: + d.d[0]=d.f[0] < s.f[0] ? 0 : 0xffffffff; + d.d[1]=d.f[1] < s.f[1] ? 0 : 0xffffffff; + d.d[2]=d.f[2] < s.f[2] ? 0 : 0xffffffff; + d.d[3]=d.f[3] < s.f[3] ? 0 : 0xffffffff; + break; + case 6: + d.d[0]=d.f[0] <= s.f[0] ? 0 : 0xffffffff; + d.d[1]=d.f[1] <= s.f[1] ? 0 : 0xffffffff; + d.d[2]=d.f[2] <= s.f[2] ? 0 : 0xffffffff; + d.d[3]=d.f[3] <= s.f[3] ? 0 : 0xffffffff; + break; + case 7: + d.d[0]=sse_issingleordered(d.f[0], s.f[0]) ? 0xffffffff : 0; + d.d[1]=sse_issingleordered(d.f[1], s.f[1]) ? 0xffffffff : 0; + d.d[2]=sse_issingleordered(d.f[2], s.f[2]) ? 0xffffffff : 0; + d.d[3]=sse_issingleordered(d.f[3], s.f[3]) ? 0xffffffff : 0; + break; + } +} + +void i386_device::sse_predicate_compare_double(UINT8 imm8, XMM_REG d, XMM_REG s) +{ + switch (imm8 & 7) + { + case 0: + d.q[0]=d.f64[0] == s.f64[0] ? U64(0xffffffffffffffff) : 0; + d.q[1]=d.f64[1] == s.f64[1] ? U64(0xffffffffffffffff) : 0; + break; + case 1: + d.q[0]=d.f64[0] < s.f64[0] ? U64(0xffffffffffffffff) : 0; + d.q[1]=d.f64[1] < s.f64[1] ? U64(0xffffffffffffffff) : 0; + break; + case 2: + d.q[0]=d.f64[0] <= s.f64[0] ? U64(0xffffffffffffffff) : 0; + d.q[1]=d.f64[1] <= s.f64[1] ? U64(0xffffffffffffffff) : 0; + break; + case 3: + d.q[0]=sse_isdoubleunordered(d.f64[0], s.f64[0]) ? U64(0xffffffffffffffff) : 0; + d.q[1]=sse_isdoubleunordered(d.f64[1], s.f64[1]) ? U64(0xffffffffffffffff) : 0; + break; + case 4: + d.q[0]=d.f64[0] != s.f64[0] ? U64(0xffffffffffffffff) : 0; + d.q[1]=d.f64[1] != s.f64[1] ? U64(0xffffffffffffffff) : 0; + break; + case 5: + d.q[0]=d.f64[0] < s.f64[0] ? 0 : U64(0xffffffffffffffff); + d.q[1]=d.f64[1] < s.f64[1] ? 0 : U64(0xffffffffffffffff); + break; + case 6: + d.q[0]=d.f64[0] <= s.f64[0] ? 0 : U64(0xffffffffffffffff); + d.q[1]=d.f64[1] <= s.f64[1] ? 0 : U64(0xffffffffffffffff); + break; + case 7: + d.q[0]=sse_isdoubleordered(d.f64[0], s.f64[0]) ? U64(0xffffffffffffffff) : 0; + d.q[1]=sse_isdoubleordered(d.f64[1], s.f64[1]) ? U64(0xffffffffffffffff) : 0; + break; + } +} + +void i386_device::sse_predicate_compare_single_scalar(UINT8 imm8, XMM_REG d, XMM_REG s) +{ + switch (imm8 & 7) + { + case 0: + d.d[0]=d.f[0] == s.f[0] ? 0xffffffff : 0; + break; + case 1: + d.d[0]=d.f[0] < s.f[0] ? 0xffffffff : 0; + break; + case 2: + d.d[0]=d.f[0] <= s.f[0] ? 0xffffffff : 0; + break; + case 3: + d.d[0]=sse_issingleunordered(d.f[0], s.f[0]) ? 0xffffffff : 0; + break; + case 4: + d.d[0]=d.f[0] != s.f[0] ? 0xffffffff : 0; + break; + case 5: + d.d[0]=d.f[0] < s.f[0] ? 0 : 0xffffffff; + break; + case 6: + d.d[0]=d.f[0] <= s.f[0] ? 0 : 0xffffffff; + break; + case 7: + d.d[0]=sse_issingleordered(d.f[0], s.f[0]) ? 0xffffffff : 0; + break; + } +} + +void i386_device::sse_predicate_compare_double_scalar(UINT8 imm8, XMM_REG d, XMM_REG s) +{ + switch (imm8 & 7) + { + case 0: + d.q[0]=d.f64[0] == s.f64[0] ? U64(0xffffffffffffffff) : 0; + break; + case 1: + d.q[0]=d.f64[0] < s.f64[0] ? U64(0xffffffffffffffff) : 0; + break; + case 2: + d.q[0]=d.f64[0] <= s.f64[0] ? U64(0xffffffffffffffff) : 0; + break; + case 3: + d.q[0]=sse_isdoubleunordered(d.f64[0], s.f64[0]) ? U64(0xffffffffffffffff) : 0; + break; + case 4: + d.q[0]=d.f64[0] != s.f64[0] ? U64(0xffffffffffffffff) : 0; + break; + case 5: + d.q[0]=d.f64[0] < s.f64[0] ? 0 : U64(0xffffffffffffffff); + break; + case 6: + d.q[0]=d.f64[0] <= s.f64[0] ? 0 : U64(0xffffffffffffffff); + break; + case 7: + d.q[0]=sse_isdoubleordered(d.f64[0], s.f64[0]) ? U64(0xffffffffffffffff) : 0; + break; + } +} + +void i386_device::sse_cmpps_r128_rm128_i8() // Opcode 0f c2 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + int s,d; + UINT8 imm8 = FETCH(); + s=modrm & 0x7; + d=(modrm >> 3) & 0x7; + sse_predicate_compare_single(imm8, XMM(d), XMM(s)); + } else { + int d; + XMM_REG s; + UINT32 ea = GetEA(modrm, 0); + UINT8 imm8 = FETCH(); + READXMM(ea, s); + d=(modrm >> 3) & 0x7; + sse_predicate_compare_single(imm8, XMM(d), s); + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_cmppd_r128_rm128_i8() // Opcode 66 0f c2 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + int s,d; + UINT8 imm8 = FETCH(); + s=modrm & 0x7; + d=(modrm >> 3) & 0x7; + sse_predicate_compare_double(imm8, XMM(d), XMM(s)); + } else { + int d; + XMM_REG s; + UINT32 ea = GetEA(modrm, 0); + UINT8 imm8 = FETCH(); + READXMM(ea, s); + d=(modrm >> 3) & 0x7; + sse_predicate_compare_double(imm8, XMM(d), s); + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_cmpss_r128_r128m32_i8() // Opcode f3 0f c2 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + int s,d; + UINT8 imm8 = FETCH(); + s=modrm & 0x7; + d=(modrm >> 3) & 0x7; + sse_predicate_compare_single_scalar(imm8, XMM(d), XMM(s)); + } else { + int d; + XMM_REG s; + UINT32 ea = GetEA(modrm, 0); + UINT8 imm8 = FETCH(); + s.d[0]=READ32(ea); + d=(modrm >> 3) & 0x7; + sse_predicate_compare_single_scalar(imm8, XMM(d), s); + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_pinsrw_r64_r16m16_i8() // Opcode 0f c4, 16bit register +{ + MMXPROLOG(); + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + UINT8 imm8 = FETCH(); + UINT16 v = LOAD_RM16(modrm); + if (m_xmm_operand_size) + XMM((modrm >> 3) & 0x7).w[imm8 & 7] = v; + else + MMX((modrm >> 3) & 0x7).w[imm8 & 3] = v; + } else { + UINT32 ea = GetEA(modrm, 0); + UINT8 imm8 = FETCH(); + UINT16 v = READ16(ea); + if (m_xmm_operand_size) + XMM((modrm >> 3) & 0x7).w[imm8 & 7] = v; + else + MMX((modrm >> 3) & 0x7).w[imm8 & 3] = v; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_pinsrw_r64_r32m16_i8() // Opcode 0f c4, 32bit register +{ + MMXPROLOG(); + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + UINT8 imm8 = FETCH(); + UINT16 v = (UINT16)LOAD_RM32(modrm); + MMX((modrm >> 3) & 0x7).w[imm8 & 3] = v; + } else { + UINT32 ea = GetEA(modrm, 0); + UINT8 imm8 = FETCH(); + UINT16 v = READ16(ea); + MMX((modrm >> 3) & 0x7).w[imm8 & 3] = v; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_pinsrw_r128_r32m16_i8() // Opcode 66 0f c4 +{ + UINT8 modrm = FETCH(); + if (modrm >= 0xc0) { + UINT8 imm8 = FETCH(); + UINT16 v = (UINT16)LOAD_RM32(modrm); + XMM((modrm >> 3) & 0x7).w[imm8 & 7] = v; + } + else { + UINT32 ea = GetEA(modrm, 0); + UINT8 imm8 = FETCH(); + UINT16 v = READ16(ea); + XMM((modrm >> 3) & 0x7).w[imm8 & 7] = v; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_pextrw_r16_r64_i8() // Opcode 0f c5 +{ + //MMXPROLOG(); + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + UINT8 imm8 = FETCH(); + if (m_xmm_operand_size) + STORE_REG16(modrm, XMM(modrm & 0x7).w[imm8 & 7]); + else + STORE_REG16(modrm, MMX(modrm & 0x7).w[imm8 & 3]); + } else { + //UINT8 imm8 = FETCH(); + report_invalid_modrm("pextrw_r16_r64_i8", modrm); + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_pextrw_r32_r64_i8() // Opcode 0f c5 +{ + //MMXPROLOG(); + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + UINT8 imm8 = FETCH(); + STORE_REG32(modrm, MMX(modrm & 0x7).w[imm8 & 3]); + } else { + //UINT8 imm8 = FETCH(); + report_invalid_modrm("pextrw_r32_r64_i8", modrm); + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_pextrw_reg_r128_i8() // Opcode 66 0f c5 +{ + UINT8 modrm = FETCH(); + if (modrm >= 0xc0) { + UINT8 imm8 = FETCH(); + STORE_REG32(modrm, XMM(modrm & 0x7).w[imm8 & 7]); + } + else { + //UINT8 imm8 = FETCH(); + report_invalid_modrm("sse_pextrw_reg_r128_i8", modrm); + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_pminub_r64_rm64() // Opcode 0f da +{ + int n; + MMXPROLOG(); + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + for (n=0;n < 8;n++) + MMX((modrm >> 3) & 0x7).b[n] = MMX((modrm >> 3) & 0x7).b[n] < MMX(modrm & 0x7).b[n] ? MMX((modrm >> 3) & 0x7).b[n] : MMX(modrm & 0x7).b[n]; + } else { + MMX_REG s; + UINT32 ea = GetEA(modrm, 0); + READMMX(ea, s); + for (n=0;n < 8;n++) + MMX((modrm >> 3) & 0x7).b[n] = MMX((modrm >> 3) & 0x7).b[n] < s.b[n] ? MMX((modrm >> 3) & 0x7).b[n] : s.b[n]; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_pminub_r128_rm128() // Opcode 66 0f da +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + for (int n=0;n < 16;n++) + XMM((modrm >> 3) & 0x7).b[n] = XMM((modrm >> 3) & 0x7).b[n] < XMM(modrm & 0x7).b[n] ? XMM((modrm >> 3) & 0x7).b[n] : XMM(modrm & 0x7).b[n]; + } else { + XMM_REG s; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, s); + for (int n=0;n < 16;n++) + XMM((modrm >> 3) & 0x7).b[n] = XMM((modrm >> 3) & 0x7).b[n] < s.b[n] ? XMM((modrm >> 3) & 0x7).b[n] : s.b[n]; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_pmaxub_r64_rm64() // Opcode 0f de +{ + int n; + MMXPROLOG(); + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + for (n=0;n < 8;n++) + MMX((modrm >> 3) & 0x7).b[n] = MMX((modrm >> 3) & 0x7).b[n] > MMX(modrm & 0x7).b[n] ? MMX((modrm >> 3) & 0x7).b[n] : MMX(modrm & 0x7).b[n]; + } else { + MMX_REG s; + UINT32 ea = GetEA(modrm, 0); + READMMX(ea, s); + for (n=0;n < 8;n++) + MMX((modrm >> 3) & 0x7).b[n] = MMX((modrm >> 3) & 0x7).b[n] > s.b[n] ? MMX((modrm >> 3) & 0x7).b[n] : s.b[n]; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_pavgb_r64_rm64() // Opcode 0f e0 +{ + int n; + MMXPROLOG(); + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + for (n=0;n < 8;n++) + MMX((modrm >> 3) & 0x7).b[n] = ((UINT16)MMX((modrm >> 3) & 0x7).b[n] + (UINT16)MMX(modrm & 0x7).b[n] + 1) >> 1; + } else { + MMX_REG s; + UINT32 ea = GetEA(modrm, 0); + READMMX(ea, s); + for (n=0;n < 8;n++) + MMX((modrm >> 3) & 0x7).b[n] = ((UINT16)MMX((modrm >> 3) & 0x7).b[n] + (UINT16)s.b[n] + 1) >> 1; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_pavgw_r64_rm64() // Opcode 0f e3 +{ + int n; + MMXPROLOG(); + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + for (n=0;n < 4;n++) + MMX((modrm >> 3) & 0x7).w[n] = ((UINT32)MMX((modrm >> 3) & 0x7).w[n] + (UINT32)MMX(modrm & 0x7).w[n] + 1) >> 1; + } else { + MMX_REG s; + UINT32 ea = GetEA(modrm, 0); + READMMX(ea, s); + for (n=0;n < 4;n++) + MMX((modrm >> 3) & 0x7).w[n] = ((UINT32)MMX((modrm >> 3) & 0x7).w[n] + (UINT32)s.w[n] + 1) >> 1; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_pmulhuw_r64_rm64() // Opcode 0f e4 +{ + MMXPROLOG(); + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + MMX((modrm >> 3) & 0x7).w[0]=((UINT32)MMX((modrm >> 3) & 0x7).w[0]*(UINT32)MMX(modrm & 7).w[0]) >> 16; + MMX((modrm >> 3) & 0x7).w[1]=((UINT32)MMX((modrm >> 3) & 0x7).w[1]*(UINT32)MMX(modrm & 7).w[1]) >> 16; + MMX((modrm >> 3) & 0x7).w[2]=((UINT32)MMX((modrm >> 3) & 0x7).w[2]*(UINT32)MMX(modrm & 7).w[2]) >> 16; + MMX((modrm >> 3) & 0x7).w[3]=((UINT32)MMX((modrm >> 3) & 0x7).w[3]*(UINT32)MMX(modrm & 7).w[3]) >> 16; + } else { + MMX_REG s; + UINT32 ea = GetEA(modrm, 0); + READMMX(ea, s); + MMX((modrm >> 3) & 0x7).w[0]=((UINT32)MMX((modrm >> 3) & 0x7).w[0]*(UINT32)s.w[0]) >> 16; + MMX((modrm >> 3) & 0x7).w[1]=((UINT32)MMX((modrm >> 3) & 0x7).w[1]*(UINT32)s.w[1]) >> 16; + MMX((modrm >> 3) & 0x7).w[2]=((UINT32)MMX((modrm >> 3) & 0x7).w[2]*(UINT32)s.w[2]) >> 16; + MMX((modrm >> 3) & 0x7).w[3]=((UINT32)MMX((modrm >> 3) & 0x7).w[3]*(UINT32)s.w[3]) >> 16; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_pminsw_r64_rm64() // Opcode 0f ea +{ + int n; + MMXPROLOG(); + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + for (n=0;n < 4;n++) + MMX((modrm >> 3) & 0x7).s[n] = MMX((modrm >> 3) & 0x7).s[n] < MMX(modrm & 0x7).s[n] ? MMX((modrm >> 3) & 0x7).s[n] : MMX(modrm & 0x7).s[n]; + } else { + MMX_REG s; + UINT32 ea = GetEA(modrm, 0); + READMMX(ea, s); + for (n=0;n < 4;n++) + MMX((modrm >> 3) & 0x7).s[n] = MMX((modrm >> 3) & 0x7).s[n] < s.s[n] ? MMX((modrm >> 3) & 0x7).s[n] : s.s[n]; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_pmaxsw_r64_rm64() // Opcode 0f ee +{ + int n; + MMXPROLOG(); + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + for (n=0;n < 4;n++) + MMX((modrm >> 3) & 0x7).s[n] = MMX((modrm >> 3) & 0x7).s[n] > MMX(modrm & 0x7).s[n] ? MMX((modrm >> 3) & 0x7).s[n] : MMX(modrm & 0x7).s[n]; + } else { + MMX_REG s; + UINT32 ea = GetEA(modrm, 0); + READMMX(ea, s); + for (n=0;n < 4;n++) + MMX((modrm >> 3) & 0x7).s[n] = MMX((modrm >> 3) & 0x7).s[n] > s.s[n] ? MMX((modrm >> 3) & 0x7).s[n] : s.s[n]; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_pmuludq_r64_rm64() // Opcode 0f f4 +{ + MMXPROLOG(); + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + MMX((modrm >> 3) & 0x7).q = (UINT64)MMX((modrm >> 3) & 0x7).d[0] * (UINT64)MMX(modrm & 0x7).d[0]; + } else { + MMX_REG s; + UINT32 ea = GetEA(modrm, 0); + READMMX(ea, s); + MMX((modrm >> 3) & 0x7).q = (UINT64)MMX((modrm >> 3) & 0x7).d[0] * (UINT64)s.d[0]; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_pmuludq_r128_rm128() // Opcode 66 0f f4 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + XMM((modrm >> 3) & 0x7).q[0] = (UINT64)XMM((modrm >> 3) & 0x7).d[0] * (UINT64)XMM(modrm & 0x7).d[0]; + XMM((modrm >> 3) & 0x7).q[1] = (UINT64)XMM((modrm >> 3) & 0x7).d[2] * (UINT64)XMM(modrm & 0x7).d[2]; + } else { + XMM_REG s; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, s); + XMM((modrm >> 3) & 0x7).q[0] = (UINT64)XMM((modrm >> 3) & 0x7).d[0] * (UINT64)s.d[0]; + XMM((modrm >> 3) & 0x7).q[1] = (UINT64)XMM((modrm >> 3) & 0x7).d[2] * (UINT64)s.d[2]; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_psadbw_r64_rm64() // Opcode 0f f6 +{ + int n; + INT32 temp; + MMXPROLOG(); + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + temp=0; + for (n=0;n < 8;n++) + temp += abs((INT32)MMX((modrm >> 3) & 0x7).b[n] - (INT32)MMX(modrm & 0x7).b[n]); + MMX((modrm >> 3) & 0x7).l=(UINT64)temp & 0xffff; + } else { + MMX_REG s; + UINT32 ea = GetEA(modrm, 0); + READMMX(ea, s); + temp=0; + for (n=0;n < 8;n++) + temp += abs((INT32)MMX((modrm >> 3) & 0x7).b[n] - (INT32)s.b[n]); + MMX((modrm >> 3) & 0x7).l=(UINT64)temp & 0xffff; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_psubq_r64_rm64() // Opcode 0f fb +{ + MMXPROLOG(); + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + MMX((modrm >> 3) & 0x7).q=MMX((modrm >> 3) & 0x7).q - MMX(modrm & 7).q; + } else { + MMX_REG s; + UINT32 ea = GetEA(modrm, 0); + READMMX(ea, s); + MMX((modrm >> 3) & 0x7).q=MMX((modrm >> 3) & 0x7).q - s.q; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_psubq_r128_rm128() // Opcode 66 0f fb +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + XMM((modrm >> 3) & 0x7).q[0]=XMM((modrm >> 3) & 0x7).q[0] - XMM(modrm & 7).q[0]; + XMM((modrm >> 3) & 0x7).q[1]=XMM((modrm >> 3) & 0x7).q[1] - XMM(modrm & 7).q[1]; + } else { + XMM_REG s; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, s); + XMM((modrm >> 3) & 0x7).q[0]=XMM((modrm >> 3) & 0x7).q[0] - s.q[0]; + XMM((modrm >> 3) & 0x7).q[1]=XMM((modrm >> 3) & 0x7).q[1] - s.q[1]; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_pshufd_r128_rm128_i8() // Opcode 66 0f 70 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + XMM_REG t; + int s,d; + UINT8 imm8 = FETCH(); + s=modrm & 0x7; + d=(modrm >> 3) & 0x7; + t.q[0]=XMM(s).q[0]; + t.q[1]=XMM(s).q[1]; + XMM(d).d[0]=t.d[imm8 & 3]; + XMM(d).d[1]=t.d[(imm8 >> 2) & 3]; + XMM(d).d[2]=t.d[(imm8 >> 4) & 3]; + XMM(d).d[3]=t.d[(imm8 >> 6) & 3]; + } else { + XMM_REG s; + int d=(modrm >> 3) & 0x7; + UINT32 ea = GetEA(modrm, 0); + UINT8 imm8 = FETCH(); + READXMM(ea, s); + XMM(d).d[0]=s.d[(imm8 & 3)]; + XMM(d).d[1]=s.d[((imm8 >> 2) & 3)]; + XMM(d).d[2]=s.d[((imm8 >> 4) & 3)]; + XMM(d).d[3]=s.d[((imm8 >> 6) & 3)]; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_pshuflw_r128_rm128_i8() // Opcode f2 0f 70 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + XMM_REG t; + int s,d; + UINT8 imm8 = FETCH(); + s=modrm & 0x7; + d=(modrm >> 3) & 0x7; + t.q[0]=XMM(s).q[0]; + XMM(d).q[1]=XMM(s).q[1]; + XMM(d).w[0]=t.w[imm8 & 3]; + XMM(d).w[1]=t.w[(imm8 >> 2) & 3]; + XMM(d).w[2]=t.w[(imm8 >> 4) & 3]; + XMM(d).w[3]=t.w[(imm8 >> 6) & 3]; + } else { + XMM_REG s; + int d=(modrm >> 3) & 0x7; + UINT32 ea = GetEA(modrm, 0); + UINT8 imm8 = FETCH(); + READXMM(ea, s); + XMM(d).q[1]=s.q[1]; + XMM(d).w[0]=s.w[imm8 & 3]; + XMM(d).w[1]=s.w[(imm8 >> 2) & 3]; + XMM(d).w[2]=s.w[(imm8 >> 4) & 3]; + XMM(d).w[3]=s.w[(imm8 >> 6) & 3]; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_pshufhw_r128_rm128_i8() // Opcode f3 0f 70 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + XMM_REG t; + int s,d; + UINT8 imm8 = FETCH(); + s=modrm & 0x7; + d=(modrm >> 3) & 0x7; + t.q[0]=XMM(s).q[1]; + XMM(d).q[0]=XMM(s).q[0]; + XMM(d).w[4]=t.w[imm8 & 3]; + XMM(d).w[5]=t.w[(imm8 >> 2) & 3]; + XMM(d).w[6]=t.w[(imm8 >> 4) & 3]; + XMM(d).w[7]=t.w[(imm8 >> 6) & 3]; + } else { + XMM_REG s; + int d=(modrm >> 3) & 0x7; + UINT32 ea = GetEA(modrm, 0); + UINT8 imm8 = FETCH(); + READXMM(ea, s); + XMM(d).q[0]=s.q[0]; + XMM(d).w[4]=s.w[4 + (imm8 & 3)]; + XMM(d).w[5]=s.w[4 + ((imm8 >> 2) & 3)]; + XMM(d).w[6]=s.w[4 + ((imm8 >> 4) & 3)]; + XMM(d).w[7]=s.w[4 + ((imm8 >> 6) & 3)]; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_packsswb_r128_rm128() // Opcode 66 0f 63 +{ + UINT8 modrm = FETCH(); + if (modrm >= 0xc0) { + XMM_REG t; + int s, d; + s = modrm & 0x7; + d = (modrm >> 3) & 0x7; + t.q[0] = XMM(s).q[0]; + t.q[1] = XMM(s).q[1]; + for (int n = 0; n < 8; n++) + XMM(d).c[n] = SaturatedSignedWordToSignedByte(XMM(d).s[n]); + for (int n = 0; n < 8; n++) + XMM(d).c[n+8] = SaturatedSignedWordToSignedByte(t.s[n]); + } + else { + XMM_REG s; + int d = (modrm >> 3) & 0x7; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, s); + for (int n = 0; n < 8; n++) + XMM(d).c[n] = SaturatedSignedWordToSignedByte(XMM(d).s[n]); + for (int n = 0; n < 8; n++) + XMM(d).c[n + 8] = SaturatedSignedWordToSignedByte(s.s[n]); + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_packssdw_r128_rm128() // Opcode 66 0f 6b +{ + UINT8 modrm = FETCH(); + if (modrm >= 0xc0) { + XMM_REG t; + int s, d; + s = modrm & 0x7; + d = (modrm >> 3) & 0x7; + t.q[0] = XMM(s).q[0]; + t.q[1] = XMM(s).q[1]; + XMM(d).s[0] = SaturatedSignedDwordToSignedWord(XMM(d).i[0]); + XMM(d).s[1] = SaturatedSignedDwordToSignedWord(XMM(d).i[1]); + XMM(d).s[2] = SaturatedSignedDwordToSignedWord(XMM(d).i[2]); + XMM(d).s[3] = SaturatedSignedDwordToSignedWord(XMM(d).i[3]); + XMM(d).s[4] = SaturatedSignedDwordToSignedWord(t.i[0]); + XMM(d).s[5] = SaturatedSignedDwordToSignedWord(t.i[1]); + XMM(d).s[6] = SaturatedSignedDwordToSignedWord(t.i[2]); + XMM(d).s[7] = SaturatedSignedDwordToSignedWord(t.i[3]); + } + else { + XMM_REG s; + int d = (modrm >> 3) & 0x7; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, s); + XMM(d).s[0] = SaturatedSignedDwordToSignedWord(XMM(d).i[0]); + XMM(d).s[1] = SaturatedSignedDwordToSignedWord(XMM(d).i[1]); + XMM(d).s[2] = SaturatedSignedDwordToSignedWord(XMM(d).i[2]); + XMM(d).s[3] = SaturatedSignedDwordToSignedWord(XMM(d).i[3]); + XMM(d).s[4] = SaturatedSignedDwordToSignedWord(s.i[0]); + XMM(d).s[5] = SaturatedSignedDwordToSignedWord(s.i[1]); + XMM(d).s[6] = SaturatedSignedDwordToSignedWord(s.i[2]); + XMM(d).s[7] = SaturatedSignedDwordToSignedWord(s.i[3]); + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_pcmpgtb_r128_rm128() // Opcode 66 0f 64 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + int s,d; + s=modrm & 0x7; + d=(modrm >> 3) & 0x7; + for (int c=0;c <= 15;c++) + XMM(d).b[c]=(XMM(d).c[c] > XMM(s).c[c]) ? 0xff : 0; + } else { + XMM_REG s; + int d=(modrm >> 3) & 0x7; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, s); + for (int c=0;c <= 15;c++) + XMM(d).b[c]=(XMM(d).c[c] > s.c[c]) ? 0xff : 0; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_pcmpgtw_r128_rm128() // Opcode 66 0f 65 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + int s,d; + s=modrm & 0x7; + d=(modrm >> 3) & 0x7; + for (int c=0;c <= 7;c++) + XMM(d).w[c]=(XMM(d).s[c] > XMM(s).s[c]) ? 0xffff : 0; + } else { + XMM_REG s; + int d=(modrm >> 3) & 0x7; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, s); + for (int c=0;c <= 7;c++) + XMM(d).w[c]=(XMM(d).s[c] > s.s[c]) ? 0xffff : 0; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_pcmpgtd_r128_rm128() // Opcode 66 0f 66 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + int s,d; + s=modrm & 0x7; + d=(modrm >> 3) & 0x7; + for (int c=0;c <= 3;c++) + XMM(d).d[c]=(XMM(d).i[c] > XMM(s).i[c]) ? 0xffffffff : 0; + } else { + XMM_REG s; + int d=(modrm >> 3) & 0x7; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, s); + for (int c=0;c <= 3;c++) + XMM(d).d[c]=(XMM(d).i[c] > s.i[c]) ? 0xffffffff : 0; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_packuswb_r128_rm128() // Opcode 66 0f 67 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + XMM_REG t; + int s,d; + s=modrm & 0x7; + d=(modrm >> 3) & 0x7; + t.q[0] = XMM(s).q[0]; + t.q[1] = XMM(s).q[1]; + for (int n = 0; n < 8;n++) + XMM(d).b[n]=SaturatedSignedWordToUnsignedByte(XMM(d).s[n]); + for (int n = 0; n < 8;n++) + XMM(d).b[n+8]=SaturatedSignedWordToUnsignedByte(t.s[n]); + } else { + XMM_REG s; + int d=(modrm >> 3) & 0x7; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, s); + for (int n = 0; n < 8;n++) + XMM(d).b[n]=SaturatedSignedWordToUnsignedByte(XMM(d).s[n]); + for (int n = 0; n < 8;n++) + XMM(d).b[n+8]=SaturatedSignedWordToUnsignedByte(s.s[n]); + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_punpckhbw_r128_rm128() // Opcode 66 0f 68 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + XMM_REG t; + int s,d; + s=modrm & 0x7; + d=(modrm >> 3) & 0x7; + t.q[1] = XMM(s).q[1]; + for (int n = 0; n < 16; n += 2) { + XMM(d).b[n]=XMM(d).b[8+(n >> 1)]; + XMM(d).b[n+1]=t.b[8+(n >> 1)]; + } + } else { + XMM_REG s; + int d=(modrm >> 3) & 0x7; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, s); + for (int n = 0; n < 16; n += 2) { + XMM(d).b[n]=XMM(d).b[8+(n >> 1)]; + XMM(d).b[n+1]=s.b[8+(n >> 1)]; + } + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_punpckhwd_r128_rm128() // Opcode 66 0f 69 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + XMM_REG t; + int s,d; + s=modrm & 0x7; + d=(modrm >> 3) & 0x7; + t.q[1] = XMM(s).q[1]; + for (int n = 0; n < 8; n += 2) { + XMM(d).w[n]=XMM(d).w[4+(n >> 1)]; + XMM(d).w[n+1]=t.w[4+(n >> 1)]; + } + } else { + XMM_REG s; + int d=(modrm >> 3) & 0x7; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, s); + for (int n = 0; n < 8; n += 2) { + XMM(d).w[n]=XMM(d).w[4+(n >> 1)]; + XMM(d).w[n+1]=s.w[4+(n >> 1)]; + } + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_unpckhdq_r128_rm128() // Opcode 66 0f 6a +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + XMM_REG t; + int s,d; + s=modrm & 0x7; + d=(modrm >> 3) & 0x7; + t.q[1] = XMM(s).q[1]; + XMM(d).d[0]=XMM(d).d[2]; + XMM(d).d[1]=t.d[2]; + XMM(d).d[2]=XMM(d).d[3]; + XMM(d).d[3]=t.d[3]; + } else { + XMM_REG s; + int d=(modrm >> 3) & 0x7; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, s); + XMM(d).d[0]=XMM(d).d[2]; + XMM(d).d[1]=s.d[2]; + XMM(d).d[2]=XMM(d).d[3]; + XMM(d).d[3]=s.d[3]; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_punpckhqdq_r128_rm128() // Opcode 66 0f 6d +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + XMM_REG t; + int s,d; + s=modrm & 0x7; + d=(modrm >> 3) & 0x7; + t.q[1] = XMM(s).q[1]; + XMM(d).q[0]=XMM(d).q[1]; + XMM(d).q[1]=t.q[1]; + } else { + XMM_REG s; + int d=(modrm >> 3) & 0x7; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, s); + XMM(d).q[0]=XMM(d).q[1]; + XMM(d).q[1]=s.q[1]; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_pcmpeqb_r128_rm128() // Opcode 66 0f 74 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + int s,d; + s=modrm & 0x7; + d=(modrm >> 3) & 0x7; + for (int c=0;c <= 15;c++) + XMM(d).b[c]=(XMM(d).c[c] == XMM(s).c[c]) ? 0xff : 0; + } else { + XMM_REG s; + int d=(modrm >> 3) & 0x7; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, s); + for (int c=0;c <= 15;c++) + XMM(d).b[c]=(XMM(d).c[c] == s.c[c]) ? 0xff : 0; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_pcmpeqw_r128_rm128() // Opcode 66 0f 75 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + int s,d; + s=modrm & 0x7; + d=(modrm >> 3) & 0x7; + for (int c=0;c <= 7;c++) + XMM(d).w[c]=(XMM(d).s[c] == XMM(s).s[c]) ? 0xffff : 0; + } else { + XMM_REG s; + int d=(modrm >> 3) & 0x7; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, s); + for (int c=0;c <= 7;c++) + XMM(d).w[c]=(XMM(d).s[c] == s.s[c]) ? 0xffff : 0; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_pcmpeqd_r128_rm128() // Opcode 66 0f 76 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + int s,d; + s=modrm & 0x7; + d=(modrm >> 3) & 0x7; + for (int c=0;c <= 3;c++) + XMM(d).d[c]=(XMM(d).i[c] == XMM(s).i[c]) ? 0xffffffff : 0; + } else { + XMM_REG s; + int d=(modrm >> 3) & 0x7; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, s); + for (int c=0;c <= 3;c++) + XMM(d).d[c]=(XMM(d).i[c] == s.i[c]) ? 0xffffffff : 0; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_paddq_r128_rm128() // Opcode 66 0f d4 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + int s,d; + s=modrm & 0x7; + d=(modrm >> 3) & 0x7; + XMM(d).q[0]=XMM(d).q[0]+XMM(s).q[0]; + XMM(d).q[1]=XMM(d).q[1]+XMM(s).q[1]; + } else { + XMM_REG src; + int d=(modrm >> 3) & 0x7; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, src); + XMM(d).q[0]=XMM(d).q[0]+src.q[0]; + XMM(d).q[1]=XMM(d).q[1]+src.q[1]; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_pmullw_r128_rm128() // Opcode 66 0f d5 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + int s,d; + s=modrm & 0x7; + d=(modrm >> 3) & 0x7; + for (int n = 0; n < 8;n++) + XMM(d).w[n]=(UINT32)((INT32)XMM(d).s[n]*(INT32)XMM(s).s[n]) & 0xffff; + } else { + XMM_REG src; + int d; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, src); + d=(modrm >> 3) & 0x7; + for (int n = 0; n < 8;n++) + XMM(d).w[n]=(UINT32)((INT32)XMM(d).s[n]*(INT32)src.s[n]) & 0xffff; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_paddb_r128_rm128() // Opcode 66 0f fc +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + for (int n=0;n < 16;n++) + XMM((modrm >> 3) & 0x7).b[n]=XMM((modrm >> 3) & 0x7).b[n] + XMM(modrm & 7).b[n]; + } else { + XMM_REG s; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, s); + for (int n=0;n < 16;n++) + XMM((modrm >> 3) & 0x7).b[n]=XMM((modrm >> 3) & 0x7).b[n] + s.b[n]; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_paddw_r128_rm128() // Opcode 66 0f fd +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + for (int n=0;n < 8;n++) + XMM((modrm >> 3) & 0x7).w[n]=XMM((modrm >> 3) & 0x7).w[n] + XMM(modrm & 7).w[n]; + } else { + XMM_REG s; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, s); + for (int n=0;n < 8;n++) + XMM((modrm >> 3) & 0x7).w[n]=XMM((modrm >> 3) & 0x7).w[n] + s.w[n]; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_paddd_r128_rm128() // Opcode 66 0f fe +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + for (int n=0;n < 4;n++) + XMM((modrm >> 3) & 0x7).d[n]=XMM((modrm >> 3) & 0x7).d[n] + XMM(modrm & 7).d[n]; + } else { + XMM_REG s; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, s); + for (int n=0;n < 4;n++) + XMM((modrm >> 3) & 0x7).d[n]=XMM((modrm >> 3) & 0x7).d[n] + s.d[n]; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_psubusb_r128_rm128() // Opcode 66 0f d8 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + for (int n=0;n < 16;n++) + XMM((modrm >> 3) & 0x7).b[n]=XMM((modrm >> 3) & 0x7).b[n] < XMM(modrm & 7).b[n] ? 0 : XMM((modrm >> 3) & 0x7).b[n]-XMM(modrm & 7).b[n]; + } else { + XMM_REG src; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, src); + for (int n=0;n < 16;n++) + XMM((modrm >> 3) & 0x7).b[n]=XMM((modrm >> 3) & 0x7).b[n] < src.b[n] ? 0 : XMM((modrm >> 3) & 0x7).b[n]-src.b[n]; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_psubusw_r128_rm128() // Opcode 66 0f d9 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + for (int n=0;n < 8;n++) + XMM((modrm >> 3) & 0x7).w[n]=XMM((modrm >> 3) & 0x7).w[n] < XMM(modrm & 7).w[n] ? 0 : XMM((modrm >> 3) & 0x7).w[n]-XMM(modrm & 7).w[n]; + } else { + XMM_REG src; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, src); + for (int n=0;n < 8;n++) + XMM((modrm >> 3) & 0x7).w[n]=XMM((modrm >> 3) & 0x7).w[n] < src.w[n] ? 0 : XMM((modrm >> 3) & 0x7).w[n]-src.w[n]; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_pand_r128_rm128() // Opcode 66 0f db +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + XMM((modrm >> 3) & 0x7).q[0]=XMM((modrm >> 3) & 0x7).q[0] & XMM(modrm & 7).q[0]; + XMM((modrm >> 3) & 0x7).q[1]=XMM((modrm >> 3) & 0x7).q[1] & XMM(modrm & 7).q[1]; + } else { + XMM_REG src; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, src); + XMM((modrm >> 3) & 0x7).q[0]=XMM((modrm >> 3) & 0x7).q[0] & src.q[0]; + XMM((modrm >> 3) & 0x7).q[1]=XMM((modrm >> 3) & 0x7).q[1] & src.q[1]; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_pandn_r128_rm128() // Opcode 66 0f df +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + XMM((modrm >> 3) & 0x7).q[0]=(~XMM((modrm >> 3) & 0x7).q[0]) & XMM(modrm & 7).q[0]; + XMM((modrm >> 3) & 0x7).q[1]=(~XMM((modrm >> 3) & 0x7).q[1]) & XMM(modrm & 7).q[1]; + } else { + XMM_REG src; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, src); + XMM((modrm >> 3) & 0x7).q[0]=(~XMM((modrm >> 3) & 0x7).q[0]) & src.q[0]; + XMM((modrm >> 3) & 0x7).q[1]=(~XMM((modrm >> 3) & 0x7).q[1]) & src.q[1]; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_paddusb_r128_rm128() // Opcode 66 0f dc +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + for (int n=0;n < 16;n++) + XMM((modrm >> 3) & 0x7).b[n]=XMM((modrm >> 3) & 0x7).b[n] > (0xff-XMM(modrm & 7).b[n]) ? 0xff : XMM((modrm >> 3) & 0x7).b[n]+XMM(modrm & 7).b[n]; + } else { + XMM_REG src; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, src); + for (int n=0;n < 16;n++) + XMM((modrm >> 3) & 0x7).b[n]=XMM((modrm >> 3) & 0x7).b[n] > (0xff-src.b[n]) ? 0xff : XMM((modrm >> 3) & 0x7).b[n]+src.b[n]; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_paddusw_r128_rm128() // Opcode 66 0f dd +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + for (int n=0;n < 8;n++) + XMM((modrm >> 3) & 0x7).w[n]=XMM((modrm >> 3) & 0x7).w[n] > (0xffff-XMM(modrm & 7).w[n]) ? 0xffff : XMM((modrm >> 3) & 0x7).w[n]+XMM(modrm & 7).w[n]; + } else { + XMM_REG src; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, src); + for (int n=0;n < 8;n++) + XMM((modrm >> 3) & 0x7).w[n]=XMM((modrm >> 3) & 0x7).w[n] > (0xffff-src.w[n]) ? 0xffff : XMM((modrm >> 3) & 0x7).w[n]+src.w[n]; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_pmaxub_r128_rm128() // Opcode 66 0f de +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + for (int n=0;n < 16;n++) + XMM((modrm >> 3) & 0x7).b[n] = XMM((modrm >> 3) & 0x7).b[n] > XMM(modrm & 0x7).b[n] ? XMM((modrm >> 3) & 0x7).b[n] : XMM(modrm & 0x7).b[n]; + } else { + XMM_REG s; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, s); + for (int n=0;n < 16;n++) + XMM((modrm >> 3) & 0x7).b[n] = XMM((modrm >> 3) & 0x7).b[n] > s.b[n] ? XMM((modrm >> 3) & 0x7).b[n] : s.b[n]; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_pmulhuw_r128_rm128() // Opcode 66 0f e4 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + for (int n=0;n < 8;n++) + XMM((modrm >> 3) & 0x7).w[n]=((UINT32)XMM((modrm >> 3) & 0x7).w[n]*(UINT32)XMM(modrm & 7).w[n]) >> 16; + } else { + XMM_REG s; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, s); + for (int n=0;n < 8;n++) + XMM((modrm >> 3) & 0x7).w[n]=((UINT32)XMM((modrm >> 3) & 0x7).w[n]*(UINT32)s.w[n]) >> 16; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_pmulhw_r128_rm128() // Opcode 66 0f e5 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + for (int n=0;n < 8;n++) + XMM((modrm >> 3) & 0x7).w[n]=(UINT32)((INT32)XMM((modrm >> 3) & 0x7).s[n]*(INT32)XMM(modrm & 7).s[n]) >> 16; + } else { + XMM_REG src; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, src); + for (int n=0;n < 8;n++) + XMM((modrm >> 3) & 0x7).w[n]=(UINT32)((INT32)XMM((modrm >> 3) & 0x7).s[n]*(INT32)src.s[n]) >> 16; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_psubsb_r128_rm128() // Opcode 66 0f e8 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + for (int n=0;n < 16;n++) + XMM((modrm >> 3) & 0x7).c[n]=SaturatedSignedWordToSignedByte((INT16)XMM((modrm >> 3) & 0x7).c[n] - (INT16)XMM(modrm & 7).c[n]); + } else { + XMM_REG s; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, s); + for (int n=0;n < 16;n++) + XMM((modrm >> 3) & 0x7).c[n]=SaturatedSignedWordToSignedByte((INT16)XMM((modrm >> 3) & 0x7).c[n] - (INT16)s.c[n]); + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_psubsw_r128_rm128() // Opcode 66 0f e9 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + for (int n=0;n < 8;n++) + XMM((modrm >> 3) & 0x7).s[n]=SaturatedSignedDwordToSignedWord((INT32)XMM((modrm >> 3) & 0x7).s[n] - (INT32)XMM(modrm & 7).s[n]); + } else { + XMM_REG s; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, s); + for (int n=0;n < 8;n++) + XMM((modrm >> 3) & 0x7).s[n]=SaturatedSignedDwordToSignedWord((INT32)XMM((modrm >> 3) & 0x7).s[n] - (INT32)s.s[n]); + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_pminsw_r128_rm128() // Opcode 66 0f ea +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + for (int n=0;n < 8;n++) + XMM((modrm >> 3) & 0x7).s[n] = XMM((modrm >> 3) & 0x7).s[n] < XMM(modrm & 0x7).s[n] ? XMM((modrm >> 3) & 0x7).s[n] : XMM(modrm & 0x7).s[n]; + } else { + XMM_REG s; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, s); + for (int n=0;n < 8;n++) + XMM((modrm >> 3) & 0x7).s[n] = XMM((modrm >> 3) & 0x7).s[n] < s.s[n] ? XMM((modrm >> 3) & 0x7).s[n] : s.s[n]; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_pmaxsw_r128_rm128() // Opcode 66 0f ee +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + for (int n=0;n < 8;n++) + XMM((modrm >> 3) & 0x7).s[n] = XMM((modrm >> 3) & 0x7).s[n] > XMM(modrm & 0x7).s[n] ? XMM((modrm >> 3) & 0x7).s[n] : XMM(modrm & 0x7).s[n]; + } else { + XMM_REG s; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, s); + for (int n=0;n < 8;n++) + XMM((modrm >> 3) & 0x7).s[n] = XMM((modrm >> 3) & 0x7).s[n] > s.s[n] ? XMM((modrm >> 3) & 0x7).s[n] : s.s[n]; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_paddsb_r128_rm128() // Opcode 66 0f ec +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + for (int n=0;n < 16;n++) + XMM((modrm >> 3) & 0x7).c[n]=SaturatedSignedWordToSignedByte((INT16)XMM((modrm >> 3) & 0x7).c[n] + (INT16)XMM(modrm & 7).c[n]); + } else { + XMM_REG s; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, s); + for (int n=0;n < 16;n++) + XMM((modrm >> 3) & 0x7).c[n]=SaturatedSignedWordToSignedByte((INT16)XMM((modrm >> 3) & 0x7).c[n] + (INT16)s.c[n]); + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_paddsw_r128_rm128() // Opcode 66 0f ed +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + for (int n=0;n < 8;n++) + XMM((modrm >> 3) & 0x7).s[n]=SaturatedSignedDwordToSignedWord((INT32)XMM((modrm >> 3) & 0x7).s[n] + (INT32)XMM(modrm & 7).s[n]); + } else { + XMM_REG s; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, s); + for (int n=0;n < 8;n++) + XMM((modrm >> 3) & 0x7).s[n]=SaturatedSignedDwordToSignedWord((INT32)XMM((modrm >> 3) & 0x7).s[n] + (INT32)s.s[n]); + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_por_r128_rm128() // Opcode 66 0f eb +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + XMM((modrm >> 3) & 0x7).q[0]=XMM((modrm >> 3) & 0x7).q[0] | XMM(modrm & 7).q[0]; + XMM((modrm >> 3) & 0x7).q[1]=XMM((modrm >> 3) & 0x7).q[1] | XMM(modrm & 7).q[1]; + } else { + XMM_REG s; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, s); + XMM((modrm >> 3) & 0x7).q[0]=XMM((modrm >> 3) & 0x7).q[0] | s.q[0]; + XMM((modrm >> 3) & 0x7).q[1]=XMM((modrm >> 3) & 0x7).q[1] | s.q[1]; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_pxor_r128_rm128() // Opcode 66 0f ef +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + XMM((modrm >> 3) & 0x7).q[0]=XMM((modrm >> 3) & 0x7).q[0] ^ XMM(modrm & 7).q[0]; + XMM((modrm >> 3) & 0x7).q[1]=XMM((modrm >> 3) & 0x7).q[1] ^ XMM(modrm & 7).q[1]; + } else { + XMM_REG s; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, s); + XMM((modrm >> 3) & 0x7).q[0]=XMM((modrm >> 3) & 0x7).q[0] ^ s.q[0]; + XMM((modrm >> 3) & 0x7).q[1]=XMM((modrm >> 3) & 0x7).q[1] ^ s.q[1]; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_pmaddwd_r128_rm128() // Opcode 66 0f f5 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + for (int n=0;n < 4;n++) + XMM((modrm >> 3) & 0x7).i[n]=(INT32)XMM((modrm >> 3) & 0x7).s[n]*(INT32)XMM(modrm & 7).s[n]+ + (INT32)XMM((modrm >> 3) & 0x7).s[n]*(INT32)XMM(modrm & 7).s[n]; + } else { + XMM_REG s; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, s); + for (int n=0;n < 4;n++) + XMM((modrm >> 3) & 0x7).i[n]=(INT32)XMM((modrm >> 3) & 0x7).s[n]*(INT32)s.s[n]+ + (INT32)XMM((modrm >> 3) & 0x7).s[n]*(INT32)s.s[n]; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_psubb_r128_rm128() // Opcode 66 0f f8 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + for (int n=0;n < 16;n++) + XMM((modrm >> 3) & 0x7).b[n]=XMM((modrm >> 3) & 0x7).b[n] - XMM(modrm & 7).b[n]; + } else { + XMM_REG s; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, s); + for (int n=0;n < 16;n++) + XMM((modrm >> 3) & 0x7).b[n]=XMM((modrm >> 3) & 0x7).b[n] - s.b[n]; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_psubw_r128_rm128() // Opcode 66 0f f9 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + for (int n=0;n < 8;n++) + XMM((modrm >> 3) & 0x7).w[n]=XMM((modrm >> 3) & 0x7).w[n] - XMM(modrm & 7).w[n]; + } else { + XMM_REG s; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, s); + for (int n=0;n < 8;n++) + XMM((modrm >> 3) & 0x7).w[n]=XMM((modrm >> 3) & 0x7).w[n] - s.w[n]; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_psubd_r128_rm128() // Opcode 66 0f fa +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + for (int n=0;n < 4;n++) + XMM((modrm >> 3) & 0x7).d[n]=XMM((modrm >> 3) & 0x7).d[n] - XMM(modrm & 7).d[n]; + } else { + XMM_REG s; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, s); + for (int n=0;n < 4;n++) + XMM((modrm >> 3) & 0x7).d[n]=XMM((modrm >> 3) & 0x7).d[n] - s.d[n]; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_psadbw_r128_rm128() // Opcode 66 0f f6 +{ + INT32 temp; + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + temp=0; + for (int n=0;n < 8;n++) + temp += abs((INT32)XMM((modrm >> 3) & 0x7).b[n] - (INT32)XMM(modrm & 0x7).b[n]); + XMM((modrm >> 3) & 0x7).l[0]=(UINT64)temp & 0xffff; + temp=0; + for (int n=8;n < 16;n++) + temp += abs((INT32)XMM((modrm >> 3) & 0x7).b[n] - (INT32)XMM(modrm & 0x7).b[n]); + XMM((modrm >> 3) & 0x7).l[1]=(UINT64)temp & 0xffff; + } else { + XMM_REG s; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, s); + temp=0; + for (int n=0;n < 8;n++) + temp += abs((INT32)XMM((modrm >> 3) & 0x7).b[n] - (INT32)s.b[n]); + XMM((modrm >> 3) & 0x7).l[0]=(UINT64)temp & 0xffff; + temp=0; + for (int n=8;n < 16;n++) + temp += abs((INT32)XMM((modrm >> 3) & 0x7).b[n] - (INT32)s.b[n]); + XMM((modrm >> 3) & 0x7).l[1]=(UINT64)temp & 0xffff; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_pavgb_r128_rm128() // Opcode 66 0f e0 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + for (int n=0;n < 16;n++) + XMM((modrm >> 3) & 0x7).b[n] = ((UINT16)XMM((modrm >> 3) & 0x7).b[n] + (UINT16)XMM(modrm & 0x7).b[n] + 1) >> 1; + } else { + XMM_REG s; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, s); + for (int n=0;n < 16;n++) + XMM((modrm >> 3) & 0x7).b[n] = ((UINT16)XMM((modrm >> 3) & 0x7).b[n] + (UINT16)s.b[n] + 1) >> 1; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_pavgw_r128_rm128() // Opcode 66 0f e3 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + for (int n=0;n < 8;n++) + XMM((modrm >> 3) & 0x7).w[n] = ((UINT32)XMM((modrm >> 3) & 0x7).w[n] + (UINT32)XMM(modrm & 0x7).w[n] + 1) >> 1; + } else { + XMM_REG s; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, s); + for (int n=0;n < 8;n++) + XMM((modrm >> 3) & 0x7).w[n] = ((UINT32)XMM((modrm >> 3) & 0x7).w[n] + (UINT32)s.w[n] + 1) >> 1; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_psrlw_r128_rm128() // Opcode 66 0f d1 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + int count=(int)XMM(modrm & 7).q[0]; + for (int n=0; n < 8;n++) + XMM((modrm >> 3) & 0x7).w[n]=XMM((modrm >> 3) & 0x7).w[n] >> count; + } else { + XMM_REG src; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, src); + int count=(int)src.q[0]; + for (int n=0; n < 8;n++) + XMM((modrm >> 3) & 0x7).w[n]=XMM((modrm >> 3) & 0x7).w[n] >> count; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_psrld_r128_rm128() // Opcode 66 0f d2 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + int count=(int)XMM(modrm & 7).q[0]; + XMM((modrm >> 3) & 0x7).d[0]=XMM((modrm >> 3) & 0x7).d[0] >> count; + XMM((modrm >> 3) & 0x7).d[1]=XMM((modrm >> 3) & 0x7).d[1] >> count; + XMM((modrm >> 3) & 0x7).d[2]=XMM((modrm >> 3) & 0x7).d[2] >> count; + XMM((modrm >> 3) & 0x7).d[3]=XMM((modrm >> 3) & 0x7).d[3] >> count; + } else { + XMM_REG src; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, src); + int count=(int)src.q[0]; + XMM((modrm >> 3) & 0x7).d[0]=XMM((modrm >> 3) & 0x7).d[0] >> count; + XMM((modrm >> 3) & 0x7).d[1]=XMM((modrm >> 3) & 0x7).d[1] >> count; + XMM((modrm >> 3) & 0x7).d[2]=XMM((modrm >> 3) & 0x7).d[2] >> count; + XMM((modrm >> 3) & 0x7).d[3]=XMM((modrm >> 3) & 0x7).d[3] >> count; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_psrlq_r128_rm128() // Opcode 66 0f d3 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + int count=(int)XMM(modrm & 7).q[0]; + XMM((modrm >> 3) & 0x7).q[0]=XMM((modrm >> 3) & 0x7).q[0] >> count; + XMM((modrm >> 3) & 0x7).q[1]=XMM((modrm >> 3) & 0x7).q[1] >> count; + } else { + XMM_REG src; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, src); + int count=(int)src.q[0]; + XMM((modrm >> 3) & 0x7).q[0]=XMM((modrm >> 3) & 0x7).q[0] >> count; + XMM((modrm >> 3) & 0x7).q[1]=XMM((modrm >> 3) & 0x7).q[1] >> count; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_psllw_r128_rm128() // Opcode 66 0f f1 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + int count=(int)XMM(modrm & 7).q[0]; + for (int n=0; n < 8;n++) + XMM((modrm >> 3) & 0x7).w[n]=XMM((modrm >> 3) & 0x7).w[n] << count; + } else { + XMM_REG s; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, s); + int count=(int)s.q[0]; + for (int n=0; n < 8;n++) + XMM((modrm >> 3) & 0x7).w[n]=XMM((modrm >> 3) & 0x7).w[n] << count; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_pslld_r128_rm128() // Opcode 66 0f f2 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + int count=(int)XMM(modrm & 7).q[0]; + XMM((modrm >> 3) & 0x7).d[0]=XMM((modrm >> 3) & 0x7).d[0] << count; + XMM((modrm >> 3) & 0x7).d[1]=XMM((modrm >> 3) & 0x7).d[1] << count; + XMM((modrm >> 3) & 0x7).d[2]=XMM((modrm >> 3) & 0x7).d[2] << count; + XMM((modrm >> 3) & 0x7).d[3]=XMM((modrm >> 3) & 0x7).d[3] << count; + } else { + XMM_REG s; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, s); + int count=(int)s.q[0]; + XMM((modrm >> 3) & 0x7).d[0]=XMM((modrm >> 3) & 0x7).d[0] << count; + XMM((modrm >> 3) & 0x7).d[1]=XMM((modrm >> 3) & 0x7).d[1] << count; + XMM((modrm >> 3) & 0x7).d[2]=XMM((modrm >> 3) & 0x7).d[2] << count; + XMM((modrm >> 3) & 0x7).d[3]=XMM((modrm >> 3) & 0x7).d[3] << count; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_psllq_r128_rm128() // Opcode 66 0f f3 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + int count=(int)XMM(modrm & 7).q[0]; + XMM((modrm >> 3) & 0x7).q[0]=XMM((modrm >> 3) & 0x7).q[0] << count; + XMM((modrm >> 3) & 0x7).q[1]=XMM((modrm >> 3) & 0x7).q[1] << count; + } else { + XMM_REG s; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, s); + int count=(int)s.q[0]; + XMM((modrm >> 3) & 0x7).q[0]=XMM((modrm >> 3) & 0x7).q[0] << count; + XMM((modrm >> 3) & 0x7).q[1]=XMM((modrm >> 3) & 0x7).q[1] << count; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_psraw_r128_rm128() // Opcode 66 0f e1 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + int count=(int)XMM(modrm & 7).q[0]; + for (int n=0; n < 8;n++) + XMM((modrm >> 3) & 0x7).s[n]=XMM((modrm >> 3) & 0x7).s[n] >> count; + } else { + XMM_REG src; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, src); + int count=(int)src.q[0]; + for (int n=0; n < 8;n++) + XMM((modrm >> 3) & 0x7).s[n]=XMM((modrm >> 3) & 0x7).s[n] >> count; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_psrad_r128_rm128() // Opcode 66 0f e2 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + int count=(int)XMM(modrm & 7).q[0]; + XMM((modrm >> 3) & 0x7).i[0]=XMM((modrm >> 3) & 0x7).i[0] >> count; + XMM((modrm >> 3) & 0x7).i[1]=XMM((modrm >> 3) & 0x7).i[1] >> count; + XMM((modrm >> 3) & 0x7).i[2]=XMM((modrm >> 3) & 0x7).i[2] >> count; + XMM((modrm >> 3) & 0x7).i[3]=XMM((modrm >> 3) & 0x7).i[3] >> count; + } else { + XMM_REG src; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, src); + int count=(int)src.q[0]; + XMM((modrm >> 3) & 0x7).i[0]=XMM((modrm >> 3) & 0x7).i[0] >> count; + XMM((modrm >> 3) & 0x7).i[1]=XMM((modrm >> 3) & 0x7).i[1] >> count; + XMM((modrm >> 3) & 0x7).i[2]=XMM((modrm >> 3) & 0x7).i[2] >> count; + XMM((modrm >> 3) & 0x7).i[3]=XMM((modrm >> 3) & 0x7).i[3] >> count; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_movntdq_m128_r128() // Opcode 66 0f e7 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + CYCLES(1); // unsupported + } else { + // since cache is not implemented + UINT32 ea = GetEA(modrm, 0); + WRITEXMM(ea, XMM((modrm >> 3) & 0x7)); + CYCLES(1); // TODO: correct cycle count + } +} + +void i386_device::sse_cvttpd2dq_r128_rm128() // Opcode 66 0f e6 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + XMM((modrm >> 3) & 0x7).i[0]=(INT32)XMM((modrm >> 3) & 0x7).f64[0]; + XMM((modrm >> 3) & 0x7).i[1]=(INT32)XMM((modrm >> 3) & 0x7).f64[1]; + XMM((modrm >> 3) & 0x7).q[1] = 0; + } else { + XMM_REG src; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, src); + XMM((modrm >> 3) & 0x7).i[0]=(INT32)src.f64[0]; + XMM((modrm >> 3) & 0x7).i[1]=(INT32)src.f64[1]; + XMM((modrm >> 3) & 0x7).q[1] = 0; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_movq_r128m64_r128() // Opcode 66 0f d6 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + XMM(modrm & 0x7).q[0]=XMM((modrm >> 3) & 0x7).q[0]; + XMM(modrm & 0x7).q[1] = 0; + } else { + UINT32 ea = GetEA(modrm, 0); + WRITE64(ea, XMM((modrm >> 3) & 0x7).q[0]); + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_addsubpd_r128_rm128() // Opcode 66 0f d0 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + int s, d; + s=modrm & 0x7; + d=(modrm >> 3) & 0x7; + XMM(d).f64[0]=XMM(d).f64[0]-XMM(s).f64[0]; + XMM(d).f64[1]=XMM(d).f64[1]+XMM(s).f64[1]; + } else { + XMM_REG src; + int d; + UINT32 ea = GetEA(modrm, 0); + d=(modrm >> 3) & 0x7; + READXMM(ea, src); + XMM(d).f64[0]=XMM(d).f64[0]-src.f64[0]; + XMM(d).f64[1]=XMM(d).f64[1]+src.f64[1]; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_haddpd_r128_rm128() // Opcode 66 0f 7c +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + int s, d; + s=modrm & 0x7; + d=(modrm >> 3) & 0x7; + XMM(d).f64[0]=XMM(d).f64[0]+XMM(d).f64[1]; + XMM(d).f64[1]=XMM(s).f64[0]+XMM(s).f64[1]; + } else { + XMM_REG src; + int d; + UINT32 ea = GetEA(modrm, 0); + d=(modrm >> 3) & 0x7; + READXMM(ea, src); + XMM(d).f64[0]=XMM(d).f64[0]+XMM(d).f64[1]; + XMM(d).f64[1]=src.f64[0]+src.f64[1]; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_hsubpd_r128_rm128() // Opcode 66 0f 7d +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + int s, d; + s=modrm & 0x7; + d=(modrm >> 3) & 0x7; + XMM(d).f64[0]=XMM(d).f64[0]-XMM(d).f64[1]; + XMM(d).f64[1]=XMM(s).f64[0]-XMM(s).f64[1]; + } else { + XMM_REG src; + int d; + UINT32 ea = GetEA(modrm, 0); + d=(modrm >> 3) & 0x7; + READXMM(ea, src); + XMM(d).f64[0]=XMM(d).f64[0]-XMM(d).f64[1]; + XMM(d).f64[1]=src.f64[0]-src.f64[1]; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_sqrtpd_r128_rm128() // Opcode 66 0f 51 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + int s, d; + s=modrm & 0x7; + d=(modrm >> 3) & 0x7; + XMM(d).f64[0]=sqrt(XMM(s).f64[0]); + XMM(d).f64[1]=sqrt(XMM(s).f64[1]); + } else { + XMM_REG src; + int d; + UINT32 ea = GetEA(modrm, 0); + d=(modrm >> 3) & 0x7; + READXMM(ea, src); + XMM(d).f64[0]=sqrt(src.f64[0]); + XMM(d).f64[1]=sqrt(src.f64[1]); + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_cvtpi2pd_r128_rm64() // Opcode 66 0f 2a +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + MMXPROLOG(); + XMM((modrm >> 3) & 0x7).f64[0] = (double)MMX(modrm & 0x7).i[0]; + XMM((modrm >> 3) & 0x7).f64[1] = (double)MMX(modrm & 0x7).i[1]; + } else { + MMX_REG r; + UINT32 ea = GetEA(modrm, 0); + READMMX(ea, r); + XMM((modrm >> 3) & 0x7).f64[0] = (double)r.i[0]; + XMM((modrm >> 3) & 0x7).f64[1] = (double)r.i[1]; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_cvttpd2pi_r64_rm128() // Opcode 66 0f 2c +{ + UINT8 modrm = FETCH(); + MMXPROLOG(); + if( modrm >= 0xc0 ) { + MMX((modrm >> 3) & 0x7).i[0] = XMM(modrm & 0x7).f64[0]; + MMX((modrm >> 3) & 0x7).i[1] = XMM(modrm & 0x7).f64[1]; + } else { + XMM_REG r; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, r); + MMX((modrm >> 3) & 0x7).i[0] = r.f64[0]; + MMX((modrm >> 3) & 0x7).i[1] = r.f64[1]; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_cvtpd2pi_r64_rm128() // Opcode 66 0f 2d +{ + UINT8 modrm = FETCH(); + MMXPROLOG(); + if( modrm >= 0xc0 ) { + MMX((modrm >> 3) & 0x7).i[0] = XMM(modrm & 0x7).f64[0]; + MMX((modrm >> 3) & 0x7).i[1] = XMM(modrm & 0x7).f64[1]; + } else { + XMM_REG r; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, r); + MMX((modrm >> 3) & 0x7).i[0] = r.f64[0]; + MMX((modrm >> 3) & 0x7).i[1] = r.f64[1]; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_cvtpd2ps_r128_rm128() // Opcode 66 0f 5a +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + XMM((modrm >> 3) & 0x7).f[0] = (float)XMM(modrm & 0x7).f64[0]; + XMM((modrm >> 3) & 0x7).f[1] = (float)XMM(modrm & 0x7).f64[1]; + XMM((modrm >> 3) & 0x7).q[1] = 0; + } else { + XMM_REG r; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, r); + XMM((modrm >> 3) & 0x7).f[0] = (float)r.f64[0]; + XMM((modrm >> 3) & 0x7).f[1] = (float)r.f64[1]; + XMM((modrm >> 3) & 0x7).q[1] = 0; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_cvtps2dq_r128_rm128() // Opcode 66 0f 5b +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + XMM((modrm >> 3) & 0x7).i[0] = XMM(modrm & 0x7).f[0]; + XMM((modrm >> 3) & 0x7).i[1] = XMM(modrm & 0x7).f[1]; + XMM((modrm >> 3) & 0x7).i[2] = XMM(modrm & 0x7).f[2]; + XMM((modrm >> 3) & 0x7).i[3] = XMM(modrm & 0x7).f[3]; + } else { + XMM_REG r; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, r); + XMM((modrm >> 3) & 0x7).i[0] = r.f[0]; + XMM((modrm >> 3) & 0x7).i[1] = r.f[1]; + XMM((modrm >> 3) & 0x7).i[2] = r.f[2]; + XMM((modrm >> 3) & 0x7).i[3] = r.f[3]; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_addpd_r128_rm128() // Opcode 66 0f 58 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + XMM((modrm >> 3) & 0x7).f64[0] = XMM((modrm >> 3) & 0x7).f64[0] + XMM(modrm & 0x7).f64[0]; + XMM((modrm >> 3) & 0x7).f64[1] = XMM((modrm >> 3) & 0x7).f64[1] + XMM(modrm & 0x7).f64[1]; + } else { + XMM_REG src; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, src); + XMM((modrm >> 3) & 0x7).f64[0] = XMM((modrm >> 3) & 0x7).f64[0] + src.f64[0]; + XMM((modrm >> 3) & 0x7).f64[1] = XMM((modrm >> 3) & 0x7).f64[1] + src.f64[1]; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_mulpd_r128_rm128() // Opcode 66 0f 59 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + XMM((modrm >> 3) & 0x7).f64[0] = XMM((modrm >> 3) & 0x7).f64[0] * XMM(modrm & 0x7).f64[0]; + XMM((modrm >> 3) & 0x7).f64[1] = XMM((modrm >> 3) & 0x7).f64[1] * XMM(modrm & 0x7).f64[1]; + } else { + XMM_REG src; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, src); + XMM((modrm >> 3) & 0x7).f64[0] = XMM((modrm >> 3) & 0x7).f64[0] * src.f64[0]; + XMM((modrm >> 3) & 0x7).f64[1] = XMM((modrm >> 3) & 0x7).f64[1] * src.f64[1]; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_subpd_r128_rm128() // Opcode 66 0f 5c +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + XMM((modrm >> 3) & 0x7).f64[0] = XMM((modrm >> 3) & 0x7).f64[0] - XMM(modrm & 0x7).f64[0]; + XMM((modrm >> 3) & 0x7).f64[1] = XMM((modrm >> 3) & 0x7).f64[1] - XMM(modrm & 0x7).f64[1]; + } else { + XMM_REG src; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, src); + XMM((modrm >> 3) & 0x7).f64[0] = XMM((modrm >> 3) & 0x7).f64[0] - src.f64[0]; + XMM((modrm >> 3) & 0x7).f64[1] = XMM((modrm >> 3) & 0x7).f64[1] - src.f64[1]; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_minpd_r128_rm128() // Opcode 66 0f 5d +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + XMM((modrm >> 3) & 0x7).f64[0] = sse_min_double(XMM((modrm >> 3) & 0x7).f64[0], XMM(modrm & 0x7).f64[0]); + XMM((modrm >> 3) & 0x7).f64[1] = sse_min_double(XMM((modrm >> 3) & 0x7).f64[1], XMM(modrm & 0x7).f64[1]); + } else { + XMM_REG src; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, src); + XMM((modrm >> 3) & 0x7).f64[0] = sse_min_double(XMM((modrm >> 3) & 0x7).f64[0], src.f64[0]); + XMM((modrm >> 3) & 0x7).f64[1] = sse_min_double(XMM((modrm >> 3) & 0x7).f64[1], src.f64[1]); + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_divpd_r128_rm128() // Opcode 66 0f 5e +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + XMM((modrm >> 3) & 0x7).f64[0] = XMM((modrm >> 3) & 0x7).f64[0] / XMM(modrm & 0x7).f64[0]; + XMM((modrm >> 3) & 0x7).f64[1] = XMM((modrm >> 3) & 0x7).f64[1] / XMM(modrm & 0x7).f64[1]; + } else { + XMM_REG src; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, src); + XMM((modrm >> 3) & 0x7).f64[0] = XMM((modrm >> 3) & 0x7).f64[0] / src.f64[0]; + XMM((modrm >> 3) & 0x7).f64[1] = XMM((modrm >> 3) & 0x7).f64[1] / src.f64[1]; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_maxpd_r128_rm128() // Opcode 66 0f 5f +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + XMM((modrm >> 3) & 0x7).f64[0] = sse_max_double(XMM((modrm >> 3) & 0x7).f64[0], XMM(modrm & 0x7).f64[0]); + XMM((modrm >> 3) & 0x7).f64[1] = sse_max_double(XMM((modrm >> 3) & 0x7).f64[1], XMM(modrm & 0x7).f64[1]); + } else { + XMM_REG src; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, src); + XMM((modrm >> 3) & 0x7).f64[0] = sse_max_double(XMM((modrm >> 3) & 0x7).f64[0], src.f64[0]); + XMM((modrm >> 3) & 0x7).f64[1] = sse_max_double(XMM((modrm >> 3) & 0x7).f64[1], src.f64[1]); + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_movntpd_m128_r128() // Opcode 66 0f 2b +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + // unsupported by cpu + CYCLES(1); // TODO: correct cycle count + } else { + // since cache is not implemented + UINT32 ea = GetEA(modrm, 0); + WRITEXMM(ea, XMM((modrm >> 3) & 0x7)); + CYCLES(1); // TODO: correct cycle count + } +} + +void i386_device::sse_movapd_r128_rm128() // Opcode 66 0f 28 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + XMM((modrm >> 3) & 0x7) = XMM(modrm & 0x7); + } else { + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, XMM((modrm >> 3) & 0x7)); + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_movapd_rm128_r128() // Opcode 66 0f 29 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + XMM(modrm & 0x7) = XMM((modrm >> 3) & 0x7); + } else { + UINT32 ea = GetEA(modrm, 0); + WRITEXMM(ea, XMM((modrm >> 3) & 0x7)); + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_movsd_r128_r128m64() // Opcode f2 0f 10 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + XMM((modrm >> 3) & 0x7).q[0] = XMM(modrm & 0x7).q[0]; + } else { + UINT32 ea = GetEA(modrm, 0); + READXMM_LO64(ea, XMM((modrm >> 3) & 0x7)); + XMM((modrm >> 3) & 0x7).q[1] = 0; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_movsd_r128m64_r128() // Opcode f2 0f 11 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + XMM(modrm & 0x7).q[0] = XMM((modrm >> 3) & 0x7).q[0]; + } else { + UINT32 ea = GetEA(modrm, 0); + WRITEXMM_LO64(ea, XMM((modrm >> 3) & 0x7)); + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_movddup_r128_r128m64() // Opcode f2 0f 12 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + XMM((modrm >> 3) & 0x7).q[0] = XMM(modrm & 0x7).q[0]; + XMM((modrm >> 3) & 0x7).q[1] = XMM((modrm >> 3) & 0x7).q[0]; + } else { + UINT32 ea = GetEA(modrm, 0); + READXMM_LO64(ea, XMM((modrm >> 3) & 0x7)); + XMM((modrm >> 3) & 0x7).q[1] = XMM((modrm >> 3) & 0x7).q[0]; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_cvtsi2sd_r128_rm32() // Opcode f2 0f 2a +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + XMM((modrm >> 3) & 0x7).f64[0] = (INT32)LOAD_RM32(modrm); + } else { + UINT32 ea = GetEA(modrm, 0); + XMM((modrm >> 3) & 0x7).f64[0] = (INT32)READ32(ea); + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_cvttsd2si_r32_r128m64() // Opcode f2 0f 2c +{ + INT32 src; + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + src = (INT32)XMM(modrm & 0x7).f64[0]; + } else { // otherwise is a memory address + XMM_REG t; + UINT32 ea = GetEA(modrm, 0); + READXMM_LO64(ea, t); + src = (INT32)t.f64[0]; + } + STORE_REG32(modrm, (UINT32)src); + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_cvtsd2si_r32_r128m64() // Opcode f2 0f 2d +{ + INT32 src; + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + src = (INT32)XMM(modrm & 0x7).f64[0]; + } else { // otherwise is a memory address + XMM_REG t; + UINT32 ea = GetEA(modrm, 0); + READXMM_LO64(ea, t); + src = (INT32)t.f64[0]; + } + STORE_REG32(modrm, (UINT32)src); + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_sqrtsd_r128_r128m64() // Opcode f2 0f 51 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + int s, d; + s=modrm & 0x7; + d=(modrm >> 3) & 0x7; + XMM(d).f64[0]=sqrt(XMM(s).f64[0]); + } else { + XMM_REG src; + int d; + UINT32 ea = GetEA(modrm, 0); + d=(modrm >> 3) & 0x7; + READXMM(ea, src); + XMM(d).f64[0]=sqrt(src.f64[0]); + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_addsd_r128_r128m64() // Opcode f2 0f 58 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + XMM((modrm >> 3) & 0x7).f64[0] = XMM((modrm >> 3) & 0x7).f64[0] + XMM(modrm & 0x7).f64[0]; + } else { + XMM_REG src; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, src); + XMM((modrm >> 3) & 0x7).f64[0] = XMM((modrm >> 3) & 0x7).f64[0] + src.f64[0]; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_mulsd_r128_r128m64() // Opcode f2 0f 59 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + XMM((modrm >> 3) & 0x7).f64[0] = XMM((modrm >> 3) & 0x7).f64[0] * XMM(modrm & 0x7).f64[0]; + } else { + XMM_REG src; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, src); + XMM((modrm >> 3) & 0x7).f64[0] = XMM((modrm >> 3) & 0x7).f64[0] * src.f64[0]; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_cvtsd2ss_r128_r128m64() // Opcode f2 0f 5a +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + XMM((modrm >> 3) & 0x7).f[0] = XMM(modrm & 0x7).f64[0]; + } else { + XMM_REG s; + UINT32 ea = GetEA(modrm, 0); + READXMM_LO64(ea, s); + XMM((modrm >> 3) & 0x7).f[0] = s.f64[0]; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_subsd_r128_r128m64() // Opcode f2 0f 5c +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + XMM((modrm >> 3) & 0x7).f64[0] = XMM((modrm >> 3) & 0x7).f64[0] - XMM(modrm & 0x7).f64[0]; + } else { + XMM_REG src; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, src); + XMM((modrm >> 3) & 0x7).f64[0] = XMM((modrm >> 3) & 0x7).f64[0] - src.f64[0]; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_minsd_r128_r128m64() // Opcode f2 0f 5d +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + XMM((modrm >> 3) & 0x7).f64[0] = sse_min_double(XMM((modrm >> 3) & 0x7).f64[0], XMM(modrm & 0x7).f64[0]); + } else { + XMM_REG src; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, src); + XMM((modrm >> 3) & 0x7).f64[0] = sse_min_double(XMM((modrm >> 3) & 0x7).f64[0], src.f64[0]); + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_divsd_r128_r128m64() // Opcode f2 0f 5e +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + XMM((modrm >> 3) & 0x7).f64[0] = XMM((modrm >> 3) & 0x7).f64[0] / XMM(modrm & 0x7).f64[0]; + } else { + XMM_REG src; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, src); + XMM((modrm >> 3) & 0x7).f64[0] = XMM((modrm >> 3) & 0x7).f64[0] / src.f64[0]; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_maxsd_r128_r128m64() // Opcode f2 0f 5f +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + XMM((modrm >> 3) & 0x7).f64[0] = sse_max_double(XMM((modrm >> 3) & 0x7).f64[0], XMM(modrm & 0x7).f64[0]); + } else { + XMM_REG src; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, src); + XMM((modrm >> 3) & 0x7).f64[0] = sse_max_double(XMM((modrm >> 3) & 0x7).f64[0], src.f64[0]); + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_haddps_r128_rm128() // Opcode f2 0f 7c +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + int s, d; + float f1, f2, f3, f4; + s=modrm & 0x7; + d=(modrm >> 3) & 0x7; + f1=XMM(d).f[0]+XMM(d).f[1]; + f2=XMM(d).f[2]+XMM(d).f[3]; + f3=XMM(s).f[0]+XMM(s).f[1]; + f4=XMM(s).f[2]+XMM(s).f[3]; + XMM(d).f[0]=f1; + XMM(d).f[1]=f2; + XMM(d).f[2]=f3; + XMM(d).f[3]=f4; + } else { + XMM_REG src; + int d; + float f1, f2; + UINT32 ea = GetEA(modrm, 0); + d=(modrm >> 3) & 0x7; + READXMM(ea, src); + f1=XMM(d).f[0]+XMM(d).f[1]; + f2=XMM(d).f[2]+XMM(d).f[3]; + XMM(d).f[0]=f1; + XMM(d).f[1]=f2; + XMM(d).f[2]=src.f[0]+src.f[1]; + XMM(d).f[3]=src.f[2]+src.f[3]; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_hsubps_r128_rm128() // Opcode f2 0f 7d +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + int s, d; + float f1, f2, f3, f4; + s=modrm & 0x7; + d=(modrm >> 3) & 0x7; + f1=XMM(d).f[0]-XMM(d).f[1]; + f2=XMM(d).f[2]-XMM(d).f[3]; + f3=XMM(s).f[0]-XMM(s).f[1]; + f4=XMM(s).f[2]-XMM(s).f[3]; + XMM(d).f[0]=f1; + XMM(d).f[1]=f2; + XMM(d).f[2]=f3; + XMM(d).f[3]=f4; + } else { + XMM_REG src; + int d; + float f1, f2; + UINT32 ea = GetEA(modrm, 0); + d=(modrm >> 3) & 0x7; + READXMM(ea, src); + f1=XMM(d).f[0]-XMM(d).f[1]; + f2=XMM(d).f[2]-XMM(d).f[3]; + XMM(d).f[0]=f1; + XMM(d).f[1]=f2; + XMM(d).f[2]=src.f[0]-src.f[1]; + XMM(d).f[3]=src.f[2]-src.f[3]; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_cmpsd_r128_r128m64_i8() // Opcode f2 0f c2 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + int s,d; + UINT8 imm8 = FETCH(); + s=modrm & 0x7; + d=(modrm >> 3) & 0x7; + sse_predicate_compare_double_scalar(imm8, XMM(d), XMM(s)); + } else { + int d; + XMM_REG s; + UINT32 ea = GetEA(modrm, 0); + UINT8 imm8 = FETCH(); + READXMM_LO64(ea, s); + d=(modrm >> 3) & 0x7; + sse_predicate_compare_double_scalar(imm8, XMM(d), s); + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_addsubps_r128_rm128() // Opcode f2 0f d0 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + XMM((modrm >> 3) & 0x7).f[0]=XMM((modrm >> 3) & 0x7).f[0] - XMM(modrm & 0x7).f[0]; + XMM((modrm >> 3) & 0x7).f[1]=XMM((modrm >> 3) & 0x7).f[1] + XMM(modrm & 0x7).f[1]; + XMM((modrm >> 3) & 0x7).f[2]=XMM((modrm >> 3) & 0x7).f[2] - XMM(modrm & 0x7).f[2]; + XMM((modrm >> 3) & 0x7).f[3]=XMM((modrm >> 3) & 0x7).f[3] + XMM(modrm & 0x7).f[3]; + } else { + XMM_REG src; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, src); + XMM((modrm >> 3) & 0x7).f[0]=XMM((modrm >> 3) & 0x7).f[0] - src.f[0]; + XMM((modrm >> 3) & 0x7).f[1]=XMM((modrm >> 3) & 0x7).f[1] + src.f[1]; + XMM((modrm >> 3) & 0x7).f[2]=XMM((modrm >> 3) & 0x7).f[2] - src.f[2]; + XMM((modrm >> 3) & 0x7).f[3]=XMM((modrm >> 3) & 0x7).f[3] + src.f[3]; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_movdq2q_r64_r128() // Opcode f2 0f d6 +{ + UINT8 modrm = FETCH(); + MMXPROLOG(); + if( modrm >= 0xc0 ) { + MMX((modrm >> 3) & 0x7).q = XMM(modrm & 0x7).q[0]; + CYCLES(1); // TODO: correct cycle count + } else { + // unsupported by cpu + CYCLES(1); // TODO: correct cycle count + } +} + +void i386_device::sse_cvtpd2dq_r128_rm128() // Opcode f2 0f e6 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + XMM((modrm >> 3) & 0x7).i[0]=(INT32)XMM((modrm >> 3) & 0x7).f64[0]; + XMM((modrm >> 3) & 0x7).i[1]=(INT32)XMM((modrm >> 3) & 0x7).f64[1]; + XMM((modrm >> 3) & 0x7).q[1] = 0; + } else { + XMM_REG src; + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, src); + XMM((modrm >> 3) & 0x7).i[0]=(INT32)src.f64[0]; + XMM((modrm >> 3) & 0x7).i[1]=(INT32)src.f64[1]; + XMM((modrm >> 3) & 0x7).q[1] = 0; + } + CYCLES(1); // TODO: correct cycle count +} + +void i386_device::sse_lddqu_r128_m128() // Opcode f2 0f f0 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + // unsupported by cpu + CYCLES(1); // TODO: correct cycle count + } else { + UINT32 ea = GetEA(modrm, 0); + READXMM(ea, XMM((modrm >> 3) & 0x7)); + } +} diff --git a/src/devices/cpu/i386/x87ops.inc b/src/devices/cpu/i386/x87ops.inc new file mode 100644 index 00000000000..9306a7a5727 --- /dev/null +++ b/src/devices/cpu/i386/x87ops.inc @@ -0,0 +1,5113 @@ +// license:BSD-3-Clause +// copyright-holders:Philip Bennett +/*************************************************************************** + + x87 FPU emulation + + TODO: + - 80-bit precision for F2XM1, FYL2X, FPATAN + - Figure out why SoftFloat trig extensions produce bad values + - Cycle counts for all processors (currently using 486 counts) + - Precision-dependent cycle counts for divide instructions + - Last instruction, operand pointers etc. + - Fix FLDENV, FSTENV, FSAVE, FRSTOR and FPREM + - Status word C2 updates to reflect round up/down + - Handling of invalid and denormal numbers + - Remove redundant operand checks + - Exceptions + +***************************************************************************/ + +#include + + +/************************************* + * + * Defines + * + *************************************/ + +#define X87_SW_IE 0x0001 +#define X87_SW_DE 0x0002 +#define X87_SW_ZE 0x0004 +#define X87_SW_OE 0x0008 +#define X87_SW_UE 0x0010 +#define X87_SW_PE 0x0020 +#define X87_SW_SF 0x0040 +#define X87_SW_ES 0x0080 +#define X87_SW_C0 0x0100 +#define X87_SW_C1 0x0200 +#define X87_SW_C2 0x0400 +#define X87_SW_TOP_SHIFT 11 +#define X87_SW_TOP_MASK 7 +#define X87_SW_C3 0x4000 +#define X87_SW_BUSY 0x8000 + +#define X87_CW_IM 0x0001 +#define X87_CW_DM 0x0002 +#define X87_CW_ZM 0x0004 +#define X87_CW_OM 0x0008 +#define X87_CW_UM 0x0010 +#define X87_CW_PM 0x0020 +#define X87_CW_PC_SHIFT 8 +#define X87_CW_PC_MASK 3 +#define X87_CW_PC_SINGLE 0 +#define X87_CW_PC_DOUBLE 2 +#define X87_CW_PC_EXTEND 3 +#define X87_CW_RC_SHIFT 10 +#define X87_CW_RC_MASK 3 +#define X87_CW_RC_NEAREST 0 +#define X87_CW_RC_DOWN 1 +#define X87_CW_RC_UP 2 +#define X87_CW_RC_ZERO 3 + +#define X87_TW_MASK 3 +#define X87_TW_VALID 0 +#define X87_TW_ZERO 1 +#define X87_TW_SPECIAL 2 +#define X87_TW_EMPTY 3 + + +/************************************* + * + * Macros + * + *************************************/ + +#define ST_TO_PHYS(x) (((m_x87_sw >> X87_SW_TOP_SHIFT) + (x)) & X87_SW_TOP_MASK) +#define ST(x) (m_x87_reg[ST_TO_PHYS(x)]) +#define X87_TW_FIELD_SHIFT(x) ((x) << 1) +#define X87_TAG(x) ((m_x87_tw >> X87_TW_FIELD_SHIFT(x)) & X87_TW_MASK) +#define X87_RC ((m_x87_cw >> X87_CW_RC_SHIFT) & X87_CW_RC_MASK) +#define X87_IS_ST_EMPTY(x) (X87_TAG(ST_TO_PHYS(x)) == X87_TW_EMPTY) +#define X87_SW_C3_0 X87_SW_C0 + +#define UNIMPLEMENTED fatalerror("Unimplemented x87 op: %s (PC:%x)\n", __FUNCTION__, m_pc) + + +/************************************* + * + * Constants + * + *************************************/ + +static const floatx80 fx80_zero = { 0x0000, U64(0x0000000000000000) }; +static const floatx80 fx80_one = { 0x3fff, U64(0x8000000000000000) }; + +static const floatx80 fx80_ninf = { 0xffff, U64(0x8000000000000000) }; +static const floatx80 fx80_inan = { 0xffff, U64(0xc000000000000000) }; + +/* Maps x87 round modes to SoftFloat round modes */ +static const int x87_to_sf_rc[4] = +{ + float_round_nearest_even, + float_round_down, + float_round_up, + float_round_to_zero, +}; + + +/************************************* + * + * SoftFloat helpers + * + *************************************/ + +extern flag floatx80_is_nan( floatx80 a ); + +extern flag floatx80_is_signaling_nan(floatx80 a); + +INLINE flag floatx80_is_quiet_nan(floatx80 a) +{ + bits64 aLow; + + aLow = a.low & ~LIT64(0x4000000000000000); + return + ((a.high & 0x7FFF) == 0x7FFF) + && (bits64)(aLow << 1) + && (a.low != aLow); +} + +INLINE int floatx80_is_zero(floatx80 fx) +{ + return (((fx.high & 0x7fff) == 0) && ((fx.low << 1) == 0)); +} + +INLINE int floatx80_is_inf(floatx80 fx) +{ + return (((fx.high & 0x7fff) == 0x7fff) && ((fx.low << 1) == 0)); +} + +INLINE int floatx80_is_denormal(floatx80 fx) +{ + return (((fx.high & 0x7fff) == 0) && + ((fx.low & U64(0x8000000000000000)) == 0) && + ((fx.low << 1) != 0)); +} + +INLINE floatx80 floatx80_abs(floatx80 fx) +{ + fx.high &= 0x7fff; + return fx; +} + +INLINE double fx80_to_double(floatx80 fx) +{ + UINT64 d = floatx80_to_float64(fx); + return *(double*)&d; +} + +INLINE floatx80 double_to_fx80(double in) +{ + return float64_to_floatx80(*(UINT64*)&in); +} + +floatx80 i386_device::READ80(UINT32 ea) +{ + floatx80 t; + + t.low = READ64(ea); + t.high = READ16(ea + 8); + + return t; +} + +void i386_device::WRITE80(UINT32 ea, floatx80 t) +{ + WRITE64(ea, t.low); + WRITE16(ea + 8, t.high); +} + + +/************************************* + * + * x87 stack handling + * + *************************************/ + +void i386_device::x87_set_stack_top(int top) +{ + m_x87_sw &= ~(X87_SW_TOP_MASK << X87_SW_TOP_SHIFT); + m_x87_sw |= (top << X87_SW_TOP_SHIFT); +} + +void i386_device::x87_set_tag(int reg, int tag) +{ + int shift = X87_TW_FIELD_SHIFT(reg); + + m_x87_tw &= ~(X87_TW_MASK << shift); + m_x87_tw |= (tag << shift); +} + +void i386_device::x87_write_stack(int i, floatx80 value, int update_tag) +{ + ST(i) = value; + + if (update_tag) + { + int tag; + + if (floatx80_is_zero(value)) + { + tag = X87_TW_ZERO; + } + else if (floatx80_is_inf(value) || floatx80_is_nan(value)) + { + tag = X87_TW_SPECIAL; + } + else + { + tag = X87_TW_VALID; + } + + x87_set_tag(ST_TO_PHYS(i), tag); + } +} + +void i386_device::x87_set_stack_underflow() +{ + m_x87_sw &= ~X87_SW_C1; + m_x87_sw |= X87_SW_IE | X87_SW_SF; +} + +void i386_device::x87_set_stack_overflow() +{ + m_x87_sw |= X87_SW_C1 | X87_SW_IE | X87_SW_SF; +} + +int i386_device::x87_inc_stack() +{ + int ret = 1; + + // Check for stack underflow + if (X87_IS_ST_EMPTY(0)) + { + ret = 0; + x87_set_stack_underflow(); + + // Don't update the stack if the exception is unmasked + if (~m_x87_cw & X87_CW_IM) + return ret; + } + + x87_set_tag(ST_TO_PHYS(0), X87_TW_EMPTY); + x87_set_stack_top(ST_TO_PHYS(1)); + return ret; +} + +int i386_device::x87_dec_stack() +{ + int ret = 1; + + // Check for stack overflow + if (!X87_IS_ST_EMPTY(7)) + { + ret = 0; + x87_set_stack_overflow(); + + // Don't update the stack if the exception is unmasked + if (~m_x87_cw & X87_CW_IM) + return ret; + } + + x87_set_stack_top(ST_TO_PHYS(7)); + return ret; +} + + +/************************************* + * + * Exception handling + * + *************************************/ + +int i386_device::x87_check_exceptions() +{ + /* Update the exceptions from SoftFloat */ + if (float_exception_flags & float_flag_invalid) + { + m_x87_sw |= X87_SW_IE; + float_exception_flags &= ~float_flag_invalid; + } + if (float_exception_flags & float_flag_overflow) + { + m_x87_sw |= X87_SW_OE; + float_exception_flags &= ~float_flag_overflow; + } + if (float_exception_flags & float_flag_underflow) + { + m_x87_sw |= X87_SW_UE; + float_exception_flags &= ~float_flag_underflow; + } + if (float_exception_flags & float_flag_inexact) + { + m_x87_sw |= X87_SW_PE; + float_exception_flags &= ~float_flag_inexact; + } + + if ((m_x87_sw & ~m_x87_cw) & 0x3f) + { + // m_device->execute().set_input_line(INPUT_LINE_FERR, RAISE_LINE); + logerror("Unmasked x87 exception (CW:%.4x, SW:%.4x)\n", m_x87_cw, m_x87_sw); + if (m_cr[0] & 0x20) // FIXME: 486 and up only + { + m_ext = 1; + i386_trap(FAULT_MF, 0, 0); + } + return 0; + } + + return 1; +} + +void i386_device::x87_write_cw(UINT16 cw) +{ + m_x87_cw = cw; + + /* Update the SoftFloat rounding mode */ + float_rounding_mode = x87_to_sf_rc[(m_x87_cw >> X87_CW_RC_SHIFT) & X87_CW_RC_MASK]; +} + +void i386_device::x87_reset() +{ + x87_write_cw(0x0037f); + + m_x87_sw = 0; + m_x87_tw = 0xffff; + + // TODO: FEA=0, FDS=0, FIP=0 FOP=0 FCS=0 + m_x87_data_ptr = 0; + m_x87_inst_ptr = 0; + m_x87_opcode = 0; +} + + +/************************************* + * + * Core arithmetic + * + *************************************/ + +floatx80 i386_device::x87_add(floatx80 a, floatx80 b) +{ + floatx80 result = { 0 }; + + switch ((m_x87_cw >> X87_CW_PC_SHIFT) & X87_CW_PC_MASK) + { + case X87_CW_PC_SINGLE: + { + float32 a32 = floatx80_to_float32(a); + float32 b32 = floatx80_to_float32(b); + result = float32_to_floatx80(float32_add(a32, b32)); + break; + } + case X87_CW_PC_DOUBLE: + { + float64 a64 = floatx80_to_float64(a); + float64 b64 = floatx80_to_float64(b); + result = float64_to_floatx80(float64_add(a64, b64)); + break; + } + case X87_CW_PC_EXTEND: + { + result = floatx80_add(a, b); + break; + } + } + + return result; +} + +floatx80 i386_device::x87_sub(floatx80 a, floatx80 b) +{ + floatx80 result = { 0 }; + + switch ((m_x87_cw >> X87_CW_PC_SHIFT) & X87_CW_PC_MASK) + { + case X87_CW_PC_SINGLE: + { + float32 a32 = floatx80_to_float32(a); + float32 b32 = floatx80_to_float32(b); + result = float32_to_floatx80(float32_sub(a32, b32)); + break; + } + case X87_CW_PC_DOUBLE: + { + float64 a64 = floatx80_to_float64(a); + float64 b64 = floatx80_to_float64(b); + result = float64_to_floatx80(float64_sub(a64, b64)); + break; + } + case X87_CW_PC_EXTEND: + { + result = floatx80_sub(a, b); + break; + } + } + + return result; +} + +floatx80 i386_device::x87_mul(floatx80 a, floatx80 b) +{ + floatx80 val = { 0 }; + + switch ((m_x87_cw >> X87_CW_PC_SHIFT) & X87_CW_PC_MASK) + { + case X87_CW_PC_SINGLE: + { + float32 a32 = floatx80_to_float32(a); + float32 b32 = floatx80_to_float32(b); + val = float32_to_floatx80(float32_mul(a32, b32)); + break; + } + case X87_CW_PC_DOUBLE: + { + float64 a64 = floatx80_to_float64(a); + float64 b64 = floatx80_to_float64(b); + val = float64_to_floatx80(float64_mul(a64, b64)); + break; + } + case X87_CW_PC_EXTEND: + { + val = floatx80_mul(a, b); + break; + } + } + + return val; +} + + +floatx80 i386_device::x87_div(floatx80 a, floatx80 b) +{ + floatx80 val = { 0 }; + + switch ((m_x87_cw >> X87_CW_PC_SHIFT) & X87_CW_PC_MASK) + { + case X87_CW_PC_SINGLE: + { + float32 a32 = floatx80_to_float32(a); + float32 b32 = floatx80_to_float32(b); + val = float32_to_floatx80(float32_div(a32, b32)); + break; + } + case X87_CW_PC_DOUBLE: + { + float64 a64 = floatx80_to_float64(a); + float64 b64 = floatx80_to_float64(b); + val = float64_to_floatx80(float64_div(a64, b64)); + break; + } + case X87_CW_PC_EXTEND: + { + val = floatx80_div(a, b); + break; + } + } + return val; +} + + +/************************************* + * + * Instructions + * + *************************************/ + +/************************************* + * + * Add + * + *************************************/ + +void i386_device::x87_fadd_m32real(UINT8 modrm) +{ + floatx80 result; + + UINT32 ea = GetEA(modrm, 0); + if (X87_IS_ST_EMPTY(0)) + { + x87_set_stack_underflow(); + result = fx80_inan; + } + else + { + UINT32 m32real = READ32(ea); + + floatx80 a = ST(0); + floatx80 b = float32_to_floatx80(m32real); + + if ((floatx80_is_signaling_nan(a) || floatx80_is_signaling_nan(b)) + || (floatx80_is_inf(a) && floatx80_is_inf(b) && ((a.high ^ b.high) & 0x8000))) + { + m_x87_sw |= X87_SW_IE; + result = fx80_inan; + } + else + { + result = x87_add(a, b); + } + } + + if (x87_check_exceptions()) + x87_write_stack(0, result, TRUE); + + CYCLES(8); +} + +void i386_device::x87_fadd_m64real(UINT8 modrm) +{ + floatx80 result; + + UINT32 ea = GetEA(modrm, 0); + if (X87_IS_ST_EMPTY(0)) + { + x87_set_stack_underflow(); + result = fx80_inan; + } + else + { + UINT64 m64real = READ64(ea); + + floatx80 a = ST(0); + floatx80 b = float64_to_floatx80(m64real); + + if ((floatx80_is_signaling_nan(a) || floatx80_is_signaling_nan(b)) + || (floatx80_is_inf(a) && floatx80_is_inf(b) && ((a.high ^ b.high) & 0x8000))) + { + m_x87_sw |= X87_SW_IE; + result = fx80_inan; + } + else + { + result = x87_add(a, b); + } + } + + if (x87_check_exceptions()) + x87_write_stack(0, result, TRUE); + + CYCLES(8); +} + +void i386_device::x87_fadd_st_sti(UINT8 modrm) +{ + floatx80 result; + int i = modrm & 7; + + if (X87_IS_ST_EMPTY(0) || X87_IS_ST_EMPTY(i)) + { + x87_set_stack_underflow(); + result = fx80_inan; + } + else + { + floatx80 a = ST(0); + floatx80 b = ST(i); + + if ((floatx80_is_signaling_nan(a) || floatx80_is_signaling_nan(b)) + || (floatx80_is_inf(a) && floatx80_is_inf(b) && ((a.high ^ b.high) & 0x8000))) + { + m_x87_sw |= X87_SW_IE; + result = fx80_inan; + } + else + { + result = x87_add(a, b); + } + } + + if (x87_check_exceptions()) + x87_write_stack(0, result, TRUE); + + CYCLES(8); +} + +void i386_device::x87_fadd_sti_st(UINT8 modrm) +{ + floatx80 result; + int i = modrm & 7; + + if (X87_IS_ST_EMPTY(0) || X87_IS_ST_EMPTY(i)) + { + x87_set_stack_underflow(); + result = fx80_inan; + } + else + { + floatx80 a = ST(0); + floatx80 b = ST(i); + + if ((floatx80_is_signaling_nan(a) || floatx80_is_signaling_nan(b)) + || (floatx80_is_inf(a) && floatx80_is_inf(b) && ((a.high ^ b.high) & 0x8000))) + { + m_x87_sw |= X87_SW_IE; + result = fx80_inan; + } + else + { + result = x87_add(a, b); + } + } + + if (x87_check_exceptions()) + x87_write_stack(i, result, TRUE); + + CYCLES(8); +} + +void i386_device::x87_faddp(UINT8 modrm) +{ + floatx80 result; + int i = modrm & 7; + + if (X87_IS_ST_EMPTY(0) || X87_IS_ST_EMPTY(i)) + { + x87_set_stack_underflow(); + result = fx80_inan; + } + else + { + floatx80 a = ST(0); + floatx80 b = ST(i); + + if ((floatx80_is_signaling_nan(a) || floatx80_is_signaling_nan(b)) + || (floatx80_is_inf(a) && floatx80_is_inf(b) && ((a.high ^ b.high) & 0x8000))) + { + m_x87_sw |= X87_SW_IE; + result = fx80_inan; + } + else + { + result = x87_add(a, b); + } + } + + if (x87_check_exceptions()) + { + x87_write_stack(i, result, TRUE); + x87_inc_stack(); + } + + CYCLES(8); +} + +void i386_device::x87_fiadd_m32int(UINT8 modrm) +{ + floatx80 result; + + UINT32 ea = GetEA(modrm, 0); + if (X87_IS_ST_EMPTY(0)) + { + x87_set_stack_underflow(); + result = fx80_inan; + } + else + { + INT32 m32int = READ32(ea); + + floatx80 a = ST(0); + floatx80 b = int32_to_floatx80(m32int); + + if ((floatx80_is_signaling_nan(a) || floatx80_is_signaling_nan(b)) + || (floatx80_is_inf(a) && floatx80_is_inf(b) && ((a.high ^ b.high) & 0x8000))) + { + m_x87_sw |= X87_SW_IE; + result = fx80_inan; + } + else + { + result = x87_add(a, b); + } + } + + if (x87_check_exceptions()) + x87_write_stack(0, result, TRUE); + + CYCLES(19); +} + +void i386_device::x87_fiadd_m16int(UINT8 modrm) +{ + floatx80 result; + + UINT32 ea = GetEA(modrm, 0); + if (X87_IS_ST_EMPTY(0)) + { + x87_set_stack_underflow(); + result = fx80_inan; + } + else + { + INT16 m16int = READ16(ea); + + floatx80 a = ST(0); + floatx80 b = int32_to_floatx80(m16int); + + if ((floatx80_is_signaling_nan(a) || floatx80_is_signaling_nan(b)) + || (floatx80_is_inf(a) && floatx80_is_inf(b) && ((a.high ^ b.high) & 0x8000))) + { + m_x87_sw |= X87_SW_IE; + result = fx80_inan; + } + else + { + result = x87_add(a, b); + } + } + + if (x87_check_exceptions()) + x87_write_stack(0, result, TRUE); + + CYCLES(20); +} + + +/************************************* + * + * Subtract + * + *************************************/ + +void i386_device::x87_fsub_m32real(UINT8 modrm) +{ + floatx80 result; + + UINT32 ea = GetEA(modrm, 0); + if (X87_IS_ST_EMPTY(0)) + { + x87_set_stack_underflow(); + result = fx80_inan; + } + else + { + UINT32 m32real = READ32(ea); + + floatx80 a = ST(0); + floatx80 b = float32_to_floatx80(m32real); + + if ((floatx80_is_signaling_nan(a) || floatx80_is_signaling_nan(b)) + || (floatx80_is_inf(a) && floatx80_is_inf(b) && ((a.high ^ b.high) & 0x8000))) + { + m_x87_sw |= X87_SW_IE; + result = fx80_inan; + } + else + { + result = x87_sub(a, b); + } + } + + if (x87_check_exceptions()) + x87_write_stack(0, result, TRUE); + + CYCLES(8); +} + +void i386_device::x87_fsub_m64real(UINT8 modrm) +{ + floatx80 result; + + UINT32 ea = GetEA(modrm, 0); + if (X87_IS_ST_EMPTY(0)) + { + x87_set_stack_underflow(); + result = fx80_inan; + } + else + { + UINT64 m64real = READ64(ea); + + floatx80 a = ST(0); + floatx80 b = float64_to_floatx80(m64real); + + if ((floatx80_is_signaling_nan(a) || floatx80_is_signaling_nan(b)) + || (floatx80_is_inf(a) && floatx80_is_inf(b) && ((a.high ^ b.high) & 0x8000))) + { + m_x87_sw |= X87_SW_IE; + result = fx80_inan; + } + else + { + result = x87_sub(a, b); + } + } + + if (x87_check_exceptions()) + x87_write_stack(0, result, TRUE); + + CYCLES(8); +} + +void i386_device::x87_fsub_st_sti(UINT8 modrm) +{ + floatx80 result; + int i = modrm & 7; + + if (X87_IS_ST_EMPTY(0) || X87_IS_ST_EMPTY(i)) + { + x87_set_stack_underflow(); + result = fx80_inan; + } + else + { + floatx80 a = ST(0); + floatx80 b = ST(i); + + if ((floatx80_is_signaling_nan(a) || floatx80_is_signaling_nan(b)) + || (floatx80_is_inf(a) && floatx80_is_inf(b) && ((a.high ^ b.high) & 0x8000))) + { + m_x87_sw |= X87_SW_IE; + result = fx80_inan; + } + else + { + result = x87_sub(a, b); + } + } + + if (x87_check_exceptions()) + x87_write_stack(0, result, TRUE); + + CYCLES(8); +} + +void i386_device::x87_fsub_sti_st(UINT8 modrm) +{ + floatx80 result; + int i = modrm & 7; + + if (X87_IS_ST_EMPTY(0) || X87_IS_ST_EMPTY(i)) + { + x87_set_stack_underflow(); + result = fx80_inan; + } + else + { + floatx80 a = ST(i); + floatx80 b = ST(0); + + if ((floatx80_is_signaling_nan(a) || floatx80_is_signaling_nan(b)) + || (floatx80_is_inf(a) && floatx80_is_inf(b) && ((a.high ^ b.high) & 0x8000))) + { + m_x87_sw |= X87_SW_IE; + result = fx80_inan; + } + else + { + result = x87_sub(a, b); + } + } + + if (x87_check_exceptions()) + x87_write_stack(i, result, TRUE); + + CYCLES(8); +} + +void i386_device::x87_fsubp(UINT8 modrm) +{ + floatx80 result; + int i = modrm & 7; + + if (X87_IS_ST_EMPTY(0) || X87_IS_ST_EMPTY(i)) + { + x87_set_stack_underflow(); + result = fx80_inan; + } + else + { + floatx80 a = ST(i); + floatx80 b = ST(0); + + if ((floatx80_is_signaling_nan(a) || floatx80_is_signaling_nan(b)) + || (floatx80_is_inf(a) && floatx80_is_inf(b) && ((a.high ^ b.high) & 0x8000))) + { + m_x87_sw |= X87_SW_IE; + result = fx80_inan; + } + else + { + result = x87_sub(a, b); + } + } + + if (x87_check_exceptions()) + { + x87_write_stack(i, result, TRUE); + x87_inc_stack(); + } + + CYCLES(8); +} + +void i386_device::x87_fisub_m32int(UINT8 modrm) +{ + floatx80 result; + + UINT32 ea = GetEA(modrm, 0); + if (X87_IS_ST_EMPTY(0)) + { + x87_set_stack_underflow(); + result = fx80_inan; + } + else + { + INT32 m32int = READ32(ea); + + floatx80 a = ST(0); + floatx80 b = int32_to_floatx80(m32int); + + if ((floatx80_is_signaling_nan(a) || floatx80_is_signaling_nan(b)) + || (floatx80_is_inf(a) && floatx80_is_inf(b) && ((a.high ^ b.high) & 0x8000))) + { + m_x87_sw |= X87_SW_IE; + result = fx80_inan; + } + else + { + result = x87_sub(a, b); + } + } + + if (x87_check_exceptions()) + x87_write_stack(0, result, TRUE); + + CYCLES(19); +} + +void i386_device::x87_fisub_m16int(UINT8 modrm) +{ + floatx80 result; + + UINT32 ea = GetEA(modrm, 0); + if (X87_IS_ST_EMPTY(0)) + { + x87_set_stack_underflow(); + result = fx80_inan; + } + else + { + INT16 m16int = READ16(ea); + + floatx80 a = ST(0); + floatx80 b = int32_to_floatx80(m16int); + + if ((floatx80_is_signaling_nan(a) || floatx80_is_signaling_nan(b)) + || (floatx80_is_inf(a) && floatx80_is_inf(b) && ((a.high ^ b.high) & 0x8000))) + { + m_x87_sw |= X87_SW_IE; + result = fx80_inan; + } + else + { + result = x87_sub(a, b); + } + } + + if (x87_check_exceptions()) + x87_write_stack(0, result, TRUE); + + CYCLES(20); +} + + +/************************************* + * + * Reverse Subtract + * + *************************************/ + +void i386_device::x87_fsubr_m32real(UINT8 modrm) +{ + floatx80 result; + + UINT32 ea = GetEA(modrm, 0); + if (X87_IS_ST_EMPTY(0)) + { + x87_set_stack_underflow(); + result = fx80_inan; + } + else + { + UINT32 m32real = READ32(ea); + + floatx80 a = float32_to_floatx80(m32real); + floatx80 b = ST(0); + + if ((floatx80_is_signaling_nan(a) || floatx80_is_signaling_nan(b)) + || (floatx80_is_inf(a) && floatx80_is_inf(b) && ((a.high ^ b.high) & 0x8000))) + { + m_x87_sw |= X87_SW_IE; + result = fx80_inan; + } + else + { + result = x87_sub(a, b); + } + } + + if (x87_check_exceptions()) + x87_write_stack(0, result, TRUE); + + CYCLES(8); +} + +void i386_device::x87_fsubr_m64real(UINT8 modrm) +{ + floatx80 result; + + UINT32 ea = GetEA(modrm, 0); + if (X87_IS_ST_EMPTY(0)) + { + x87_set_stack_underflow(); + result = fx80_inan; + } + else + { + UINT64 m64real = READ64(ea); + + floatx80 a = float64_to_floatx80(m64real); + floatx80 b = ST(0); + + if ((floatx80_is_signaling_nan(a) || floatx80_is_signaling_nan(b)) + || (floatx80_is_inf(a) && floatx80_is_inf(b) && ((a.high ^ b.high) & 0x8000))) + { + m_x87_sw |= X87_SW_IE; + result = fx80_inan; + } + else + { + result = x87_sub(a, b); + } + } + + if (x87_check_exceptions()) + x87_write_stack(0, result, TRUE); + + CYCLES(8); +} + +void i386_device::x87_fsubr_st_sti(UINT8 modrm) +{ + floatx80 result; + int i = modrm & 7; + + if (X87_IS_ST_EMPTY(0) || X87_IS_ST_EMPTY(i)) + { + x87_set_stack_underflow(); + result = fx80_inan; + } + else + { + floatx80 a = ST(i); + floatx80 b = ST(0); + + if ((floatx80_is_signaling_nan(a) || floatx80_is_signaling_nan(b)) + || (floatx80_is_inf(a) && floatx80_is_inf(b) && ((a.high ^ b.high) & 0x8000))) + { + m_x87_sw |= X87_SW_IE; + result = fx80_inan; + } + else + { + result = x87_sub(a, b); + } + } + + if (x87_check_exceptions()) + x87_write_stack(0, result, TRUE); + + CYCLES(8); +} + +void i386_device::x87_fsubr_sti_st(UINT8 modrm) +{ + floatx80 result; + int i = modrm & 7; + + if (X87_IS_ST_EMPTY(0) || X87_IS_ST_EMPTY(i)) + { + x87_set_stack_underflow(); + result = fx80_inan; + } + else + { + floatx80 a = ST(0); + floatx80 b = ST(i); + + if ((floatx80_is_signaling_nan(a) || floatx80_is_signaling_nan(b)) + || (floatx80_is_inf(a) && floatx80_is_inf(b) && ((a.high ^ b.high) & 0x8000))) + { + m_x87_sw |= X87_SW_IE; + result = fx80_inan; + } + else + { + result = x87_sub(a, b); + } + } + + if (x87_check_exceptions()) + x87_write_stack(i, result, TRUE); + + CYCLES(8); +} + +void i386_device::x87_fsubrp(UINT8 modrm) +{ + floatx80 result; + int i = modrm & 7; + + if (X87_IS_ST_EMPTY(0) || X87_IS_ST_EMPTY(i)) + { + x87_set_stack_underflow(); + result = fx80_inan; + } + else + { + floatx80 a = ST(0); + floatx80 b = ST(i); + + if ((floatx80_is_signaling_nan(a) || floatx80_is_signaling_nan(b)) + || (floatx80_is_inf(a) && floatx80_is_inf(b) && ((a.high ^ b.high) & 0x8000))) + { + m_x87_sw |= X87_SW_IE; + result = fx80_inan; + } + else + { + result = x87_sub(a, b); + } + } + + if (x87_check_exceptions()) + { + x87_write_stack(i, result, TRUE); + x87_inc_stack(); + } + + CYCLES(8); +} + +void i386_device::x87_fisubr_m32int(UINT8 modrm) +{ + floatx80 result; + + UINT32 ea = GetEA(modrm, 0); + if (X87_IS_ST_EMPTY(0)) + { + x87_set_stack_underflow(); + result = fx80_inan; + } + else + { + INT32 m32int = READ32(ea); + + floatx80 a = int32_to_floatx80(m32int); + floatx80 b = ST(0); + + if ((floatx80_is_signaling_nan(a) || floatx80_is_signaling_nan(b)) + || (floatx80_is_inf(a) && floatx80_is_inf(b) && ((a.high ^ b.high) & 0x8000))) + { + m_x87_sw |= X87_SW_IE; + result = fx80_inan; + } + else + { + result = x87_sub(a, b); + } + } + + if (x87_check_exceptions()) + x87_write_stack(0, result, TRUE); + + CYCLES(19); +} + +void i386_device::x87_fisubr_m16int(UINT8 modrm) +{ + floatx80 result; + + UINT32 ea = GetEA(modrm, 0); + if (X87_IS_ST_EMPTY(0)) + { + x87_set_stack_underflow(); + result = fx80_inan; + } + else + { + INT16 m16int = READ16(ea); + + floatx80 a = int32_to_floatx80(m16int); + floatx80 b = ST(0); + + if ((floatx80_is_signaling_nan(a) || floatx80_is_signaling_nan(b)) + || (floatx80_is_inf(a) && floatx80_is_inf(b) && ((a.high ^ b.high) & 0x8000))) + { + m_x87_sw |= X87_SW_IE; + result = fx80_inan; + } + else + { + result = x87_sub(a, b); + } + } + + if (x87_check_exceptions()) + x87_write_stack(0, result, TRUE); + + CYCLES(20); +} + + +/************************************* + * + * Divide + * + *************************************/ + +void i386_device::x87_fdiv_m32real(UINT8 modrm) +{ + floatx80 result; + + UINT32 ea = GetEA(modrm, 0); + if (X87_IS_ST_EMPTY(0)) + { + x87_set_stack_underflow(); + result = fx80_inan; + } + else + { + UINT32 m32real = READ32(ea); + + floatx80 a = ST(0); + floatx80 b = float32_to_floatx80(m32real); + + if (floatx80_is_signaling_nan(a) || floatx80_is_signaling_nan(b)) + { + m_x87_sw |= X87_SW_IE; + result = fx80_inan; + } + else + { + result = x87_div(a, b); + } + } + + if (x87_check_exceptions()) + x87_write_stack(0, result, TRUE); + + // 73, 62, 35 + CYCLES(73); +} + +void i386_device::x87_fdiv_m64real(UINT8 modrm) +{ + floatx80 result; + + UINT32 ea = GetEA(modrm, 0); + if (X87_IS_ST_EMPTY(0)) + { + x87_set_stack_underflow(); + result = fx80_inan; + } + else + { + UINT64 m64real = READ64(ea); + + floatx80 a = ST(0); + floatx80 b = float64_to_floatx80(m64real); + + if (floatx80_is_signaling_nan(a) || floatx80_is_signaling_nan(b)) + { + m_x87_sw |= X87_SW_IE; + result = fx80_inan; + } + else + { + result = x87_div(a, b); + } + } + + if (x87_check_exceptions()) + x87_write_stack(0, result, TRUE); + + // 73, 62, 35 + CYCLES(73); +} + +void i386_device::x87_fdiv_st_sti(UINT8 modrm) +{ + int i = modrm & 7; + floatx80 result; + + if (X87_IS_ST_EMPTY(0) || X87_IS_ST_EMPTY(i)) + { + x87_set_stack_underflow(); + result = fx80_inan; + } + else + { + floatx80 a = ST(0); + floatx80 b = ST(i); + + if (floatx80_is_signaling_nan(a) || floatx80_is_signaling_nan(b)) + { + m_x87_sw |= X87_SW_IE; + result = fx80_inan; + } + else + { + result = x87_div(a, b); + } + } + + if (x87_check_exceptions()) + { + x87_write_stack(0, result, TRUE); + } + + // 73, 62, 35 + CYCLES(73); +} + +void i386_device::x87_fdiv_sti_st(UINT8 modrm) +{ + int i = modrm & 7; + floatx80 result; + + if (X87_IS_ST_EMPTY(0) || X87_IS_ST_EMPTY(i)) + { + x87_set_stack_underflow(); + result = fx80_inan; + } + else + { + floatx80 a = ST(i); + floatx80 b = ST(0); + + if (floatx80_is_signaling_nan(a) || floatx80_is_signaling_nan(b)) + { + m_x87_sw |= X87_SW_IE; + result = fx80_inan; + } + else + { + result = x87_div(a, b); + } + } + + if (x87_check_exceptions()) + { + x87_write_stack(i, result, TRUE); + } + + // 73, 62, 35 + CYCLES(73); +} + +void i386_device::x87_fdivp(UINT8 modrm) +{ + int i = modrm & 7; + floatx80 result; + + if (X87_IS_ST_EMPTY(0) || X87_IS_ST_EMPTY(i)) + { + x87_set_stack_underflow(); + result = fx80_inan; + } + else + { + floatx80 a = ST(i); + floatx80 b = ST(0); + + if (floatx80_is_signaling_nan(a) || floatx80_is_signaling_nan(b)) + { + m_x87_sw |= X87_SW_IE; + result = fx80_inan; + } + else + { + result = x87_div(a, b); + } + } + + if (x87_check_exceptions()) + { + x87_write_stack(i, result, TRUE); + x87_inc_stack(); + } + + // 73, 62, 35 + CYCLES(73); +} + +void i386_device::x87_fidiv_m32int(UINT8 modrm) +{ + floatx80 result; + + UINT32 ea = GetEA(modrm, 0); + if (X87_IS_ST_EMPTY(0)) + { + x87_set_stack_underflow(); + result = fx80_inan; + } + else + { + INT32 m32int = READ32(ea); + + floatx80 a = ST(0); + floatx80 b = int32_to_floatx80(m32int); + + if (floatx80_is_signaling_nan(a) || floatx80_is_signaling_nan(b)) + { + m_x87_sw |= X87_SW_IE; + result = fx80_inan; + } + else + { + result = x87_div(a, b); + } + } + + if (x87_check_exceptions()) + x87_write_stack(0, result, TRUE); + + // 73, 62, 35 + CYCLES(73); +} + +void i386_device::x87_fidiv_m16int(UINT8 modrm) +{ + floatx80 result; + + UINT32 ea = GetEA(modrm, 0); + if (X87_IS_ST_EMPTY(0)) + { + x87_set_stack_underflow(); + result = fx80_inan; + } + else + { + INT16 m16int = READ32(ea); + + floatx80 a = ST(0); + floatx80 b = int32_to_floatx80(m16int); + + if (floatx80_is_signaling_nan(a) || floatx80_is_signaling_nan(b)) + { + m_x87_sw |= X87_SW_IE; + result = fx80_inan; + } + else + { + result = x87_div(a, b); + } + } + + if (x87_check_exceptions()) + x87_write_stack(0, result, TRUE); + + // 73, 62, 35 + CYCLES(73); +} + + +/************************************* + * + * Reverse Divide + * + *************************************/ + +void i386_device::x87_fdivr_m32real(UINT8 modrm) +{ + floatx80 result; + + UINT32 ea = GetEA(modrm, 0); + if (X87_IS_ST_EMPTY(0)) + { + x87_set_stack_underflow(); + result = fx80_inan; + } + else + { + UINT32 m32real = READ32(ea); + + floatx80 a = float32_to_floatx80(m32real); + floatx80 b = ST(0); + + if (floatx80_is_signaling_nan(a) || floatx80_is_signaling_nan(b)) + { + m_x87_sw |= X87_SW_IE; + result = fx80_inan; + } + else + { + result = x87_div(a, b); + } + } + + if (x87_check_exceptions()) + x87_write_stack(0, result, TRUE); + + // 73, 62, 35 + CYCLES(73); +} + +void i386_device::x87_fdivr_m64real(UINT8 modrm) +{ + floatx80 result; + + UINT32 ea = GetEA(modrm, 0); + if (X87_IS_ST_EMPTY(0)) + { + x87_set_stack_underflow(); + result = fx80_inan; + } + else + { + UINT64 m64real = READ64(ea); + + floatx80 a = float64_to_floatx80(m64real); + floatx80 b = ST(0); + + if (floatx80_is_signaling_nan(a) || floatx80_is_signaling_nan(b)) + { + m_x87_sw |= X87_SW_IE; + result = fx80_inan; + } + else + { + result = x87_div(a, b); + } + } + + if (x87_check_exceptions()) + x87_write_stack(0, result, TRUE); + + // 73, 62, 35 + CYCLES(73); +} + +void i386_device::x87_fdivr_st_sti(UINT8 modrm) +{ + int i = modrm & 7; + floatx80 result; + + if (X87_IS_ST_EMPTY(0) || X87_IS_ST_EMPTY(i)) + { + x87_set_stack_underflow(); + result = fx80_inan; + } + else + { + floatx80 a = ST(i); + floatx80 b = ST(0); + + if (floatx80_is_signaling_nan(a) || floatx80_is_signaling_nan(b)) + { + m_x87_sw |= X87_SW_IE; + result = fx80_inan; + } + else + { + result = x87_div(a, b); + } + } + + if (x87_check_exceptions()) + { + x87_write_stack(0, result, TRUE); + } + + // 73, 62, 35 + CYCLES(73); +} + +void i386_device::x87_fdivr_sti_st(UINT8 modrm) +{ + int i = modrm & 7; + floatx80 result; + + if (X87_IS_ST_EMPTY(0) || X87_IS_ST_EMPTY(i)) + { + x87_set_stack_underflow(); + result = fx80_inan; + } + else + { + floatx80 a = ST(0); + floatx80 b = ST(i); + + if (floatx80_is_signaling_nan(a) || floatx80_is_signaling_nan(b)) + { + m_x87_sw |= X87_SW_IE; + result = fx80_inan; + } + else + { + result = x87_div(a, b); + } + } + + if (x87_check_exceptions()) + { + x87_write_stack(i, result, TRUE); + } + + // 73, 62, 35 + CYCLES(73); +} + +void i386_device::x87_fdivrp(UINT8 modrm) +{ + int i = modrm & 7; + floatx80 result; + + if (X87_IS_ST_EMPTY(0) || X87_IS_ST_EMPTY(i)) + { + x87_set_stack_underflow(); + result = fx80_inan; + } + else + { + floatx80 a = ST(0); + floatx80 b = ST(i); + + if (floatx80_is_signaling_nan(a) || floatx80_is_signaling_nan(b)) + { + m_x87_sw |= X87_SW_IE; + result = fx80_inan; + } + else + { + result = x87_div(a, b); + } + } + + if (x87_check_exceptions()) + { + x87_write_stack(i, result, TRUE); + x87_inc_stack(); + } + + // 73, 62, 35 + CYCLES(73); +} + + +void i386_device::x87_fidivr_m32int(UINT8 modrm) +{ + floatx80 result; + + UINT32 ea = GetEA(modrm, 0); + if (X87_IS_ST_EMPTY(0)) + { + x87_set_stack_underflow(); + result = fx80_inan; + } + else + { + INT32 m32int = READ32(ea); + + floatx80 a = int32_to_floatx80(m32int); + floatx80 b = ST(0); + + if (floatx80_is_signaling_nan(a) || floatx80_is_signaling_nan(b)) + { + m_x87_sw |= X87_SW_IE; + result = fx80_inan; + } + else + { + result = x87_div(a, b); + } + } + + if (x87_check_exceptions()) + x87_write_stack(0, result, TRUE); + + // 73, 62, 35 + CYCLES(73); +} + +void i386_device::x87_fidivr_m16int(UINT8 modrm) +{ + floatx80 result; + + UINT32 ea = GetEA(modrm, 0); + if (X87_IS_ST_EMPTY(0)) + { + x87_set_stack_underflow(); + result = fx80_inan; + } + else + { + INT16 m16int = READ32(ea); + + floatx80 a = int32_to_floatx80(m16int); + floatx80 b = ST(0); + + if (floatx80_is_signaling_nan(a) || floatx80_is_signaling_nan(b)) + { + m_x87_sw |= X87_SW_IE; + result = fx80_inan; + } + else + { + result = x87_div(a, b); + } + } + + if (x87_check_exceptions()) + x87_write_stack(0, result, TRUE); + + // 73, 62, 35 + CYCLES(73); +} + + +/************************************* + * + * Multiply + * + *************************************/ + +void i386_device::x87_fmul_m32real(UINT8 modrm) +{ + floatx80 result; + + UINT32 ea = GetEA(modrm, 0); + if (X87_IS_ST_EMPTY(0)) + { + x87_set_stack_underflow(); + result = fx80_inan; + } + else + { + UINT32 m32real = READ32(ea); + + floatx80 a = ST(0); + floatx80 b = float32_to_floatx80(m32real); + + if (floatx80_is_signaling_nan(a) || floatx80_is_signaling_nan(b)) + { + m_x87_sw |= X87_SW_IE; + result = fx80_inan; + } + else + { + result = x87_mul(a, b); + } + } + + if (x87_check_exceptions()) + x87_write_stack(0, result, TRUE); + + CYCLES(11); +} + +void i386_device::x87_fmul_m64real(UINT8 modrm) +{ + floatx80 result; + + UINT32 ea = GetEA(modrm, 0); + if (X87_IS_ST_EMPTY(0)) + { + x87_set_stack_underflow(); + result = fx80_inan; + } + else + { + UINT64 m64real = READ64(ea); + + floatx80 a = ST(0); + floatx80 b = float64_to_floatx80(m64real); + + if (floatx80_is_signaling_nan(a) || floatx80_is_signaling_nan(b)) + { + m_x87_sw |= X87_SW_IE; + result = fx80_inan; + } + else + { + result = x87_mul(a, b); + } + } + + if (x87_check_exceptions()) + x87_write_stack(0, result, TRUE); + + CYCLES(14); +} + +void i386_device::x87_fmul_st_sti(UINT8 modrm) +{ + floatx80 result; + int i = modrm & 7; + + if (X87_IS_ST_EMPTY(0) || X87_IS_ST_EMPTY(i)) + { + x87_set_stack_underflow(); + result = fx80_inan; + } + else + { + floatx80 a = ST(0); + floatx80 b = ST(i); + + if (floatx80_is_signaling_nan(a) || floatx80_is_signaling_nan(b)) + { + m_x87_sw |= X87_SW_IE; + result = fx80_inan; + } + else + { + result = x87_mul(a, b); + } + } + + if (x87_check_exceptions()) + x87_write_stack(0, result, TRUE); + + CYCLES(16); +} + +void i386_device::x87_fmul_sti_st(UINT8 modrm) +{ + floatx80 result; + int i = modrm & 7; + + if (X87_IS_ST_EMPTY(0) || X87_IS_ST_EMPTY(i)) + { + x87_set_stack_underflow(); + result = fx80_inan; + } + else + { + floatx80 a = ST(0); + floatx80 b = ST(i); + + if (floatx80_is_signaling_nan(a) || floatx80_is_signaling_nan(b)) + { + m_x87_sw |= X87_SW_IE; + result = fx80_inan; + } + else + { + result = x87_mul(a, b); + } + } + + if (x87_check_exceptions()) + x87_write_stack(i, result, TRUE); + + CYCLES(16); +} + +void i386_device::x87_fmulp(UINT8 modrm) +{ + floatx80 result; + int i = modrm & 7; + + if (X87_IS_ST_EMPTY(0) || X87_IS_ST_EMPTY(i)) + { + x87_set_stack_underflow(); + result = fx80_inan; + } + else + { + floatx80 a = ST(0); + floatx80 b = ST(i); + + if (floatx80_is_signaling_nan(a) || floatx80_is_signaling_nan(b)) + { + m_x87_sw |= X87_SW_IE; + result = fx80_inan; + } + else + { + result = x87_mul(a, b); + } + } + + if (x87_check_exceptions()) + { + x87_write_stack(i, result, TRUE); + x87_inc_stack(); + } + + CYCLES(16); +} + +void i386_device::x87_fimul_m32int(UINT8 modrm) +{ + floatx80 result; + + UINT32 ea = GetEA(modrm, 0); + if (X87_IS_ST_EMPTY(0)) + { + x87_set_stack_underflow(); + result = fx80_inan; + } + else + { + INT32 m32int = READ32(ea); + + floatx80 a = ST(0); + floatx80 b = int32_to_floatx80(m32int); + + if (floatx80_is_signaling_nan(a) || floatx80_is_signaling_nan(b)) + { + m_x87_sw |= X87_SW_IE; + result = fx80_inan; + } + else + { + result = x87_mul(a, b); + } + } + + if (x87_check_exceptions()) + x87_write_stack(0, result, TRUE); + + CYCLES(22); +} + +void i386_device::x87_fimul_m16int(UINT8 modrm) +{ + floatx80 result; + + UINT32 ea = GetEA(modrm, 0); + if (X87_IS_ST_EMPTY(0)) + { + x87_set_stack_underflow(); + result = fx80_inan; + } + else + { + INT16 m16int = READ16(ea); + + floatx80 a = ST(0); + floatx80 b = int32_to_floatx80(m16int); + + if (floatx80_is_signaling_nan(a) || floatx80_is_signaling_nan(b)) + { + m_x87_sw |= X87_SW_IE; + result = fx80_inan; + } + else + { + result = x87_mul(a, b); + } + } + + if (x87_check_exceptions()) + x87_write_stack(0, result, TRUE); + + CYCLES(22); +} + +/************************************* +* +* Conditional Move +* +*************************************/ + +void i386_device::x87_fcmovb_sti(UINT8 modrm) +{ + floatx80 result; + int i = modrm & 7; + + if (m_CF == 1) + { + if (X87_IS_ST_EMPTY(i)) + { + x87_set_stack_underflow(); + result = fx80_inan; + } + else + result = ST(i); + + if (x87_check_exceptions()) + { + ST(0) = result; + } + } + + CYCLES(4); +} + +void i386_device::x87_fcmove_sti(UINT8 modrm) +{ + floatx80 result; + int i = modrm & 7; + + if (m_ZF == 1) + { + if (X87_IS_ST_EMPTY(i)) + { + x87_set_stack_underflow(); + result = fx80_inan; + } + else + result = ST(i); + + if (x87_check_exceptions()) + { + ST(0) = result; + } + } + + CYCLES(4); +} + +void i386_device::x87_fcmovbe_sti(UINT8 modrm) +{ + floatx80 result; + int i = modrm & 7; + + if ((m_CF | m_ZF) == 1) + { + if (X87_IS_ST_EMPTY(i)) + { + x87_set_stack_underflow(); + result = fx80_inan; + } + else + result = ST(i); + + if (x87_check_exceptions()) + { + ST(0) = result; + } + } + + CYCLES(4); +} + +void i386_device::x87_fcmovu_sti(UINT8 modrm) +{ + floatx80 result; + int i = modrm & 7; + + if (m_PF == 1) + { + if (X87_IS_ST_EMPTY(i)) + { + x87_set_stack_underflow(); + result = fx80_inan; + } + else + result = ST(i); + + if (x87_check_exceptions()) + { + ST(0) = result; + } + } + + CYCLES(4); +} + +void i386_device::x87_fcmovnb_sti(UINT8 modrm) +{ + floatx80 result; + int i = modrm & 7; + + if (m_CF == 0) + { + if (X87_IS_ST_EMPTY(i)) + { + x87_set_stack_underflow(); + result = fx80_inan; + } + else + result = ST(i); + + if (x87_check_exceptions()) + { + ST(0) = result; + } + } + + CYCLES(4); +} + +void i386_device::x87_fcmovne_sti(UINT8 modrm) +{ + floatx80 result; + int i = modrm & 7; + + if (m_ZF == 0) + { + if (X87_IS_ST_EMPTY(i)) + { + x87_set_stack_underflow(); + result = fx80_inan; + } + else + result = ST(i); + + if (x87_check_exceptions()) + { + ST(0) = result; + } + } + + CYCLES(4); +} + +void i386_device::x87_fcmovnbe_sti(UINT8 modrm) +{ + floatx80 result; + int i = modrm & 7; + + if ((m_CF == 0) && (m_ZF == 0)) + { + if (X87_IS_ST_EMPTY(i)) + { + x87_set_stack_underflow(); + result = fx80_inan; + } + else + result = ST(i); + + if (x87_check_exceptions()) + { + ST(0) = result; + } + } + + CYCLES(4); +} + +void i386_device::x87_fcmovnu_sti(UINT8 modrm) +{ + floatx80 result; + int i = modrm & 7; + + if (m_PF == 0) + { + if (X87_IS_ST_EMPTY(i)) + { + x87_set_stack_underflow(); + result = fx80_inan; + } + else + result = ST(i); + + if (x87_check_exceptions()) + { + ST(0) = result; + } + } + + CYCLES(4); +} + +/************************************* + * + * Miscellaneous arithmetic + * + *************************************/ + +void i386_device::x87_fprem(UINT8 modrm) +{ + floatx80 result; + + if (X87_IS_ST_EMPTY(0) || X87_IS_ST_EMPTY(1)) + { + x87_set_stack_underflow(); + result = fx80_inan; + } + else + { + floatx80 a0 = ST(0); + floatx80 b1 = ST(1); + + m_x87_sw &= ~X87_SW_C2; + + //int d=extractFloatx80Exp(a0)-extractFloatx80Exp(b1); + int d = (a0.high & 0x7FFF) - (b1.high & 0x7FFF); + if (d < 64) { + floatx80 t=floatx80_div(a0, b1); + int64 q = floatx80_to_int64_round_to_zero(t); + floatx80 qf = int64_to_floatx80(q); + floatx80 tt = floatx80_mul(b1, qf); + result = floatx80_sub(a0, tt); + // C2 already 0 + m_x87_sw &= ~(X87_SW_C0|X87_SW_C3|X87_SW_C1); + if (q & 1) + m_x87_sw |= X87_SW_C1; + if (q & 2) + m_x87_sw |= X87_SW_C3; + if (q & 4) + m_x87_sw |= X87_SW_C0; + } + else { + m_x87_sw |= X87_SW_C2; + int n = 63; + int e = 1 << (d - n); + floatx80 ef = int32_to_floatx80(e); + floatx80 t=floatx80_div(a0, b1); + floatx80 td = floatx80_div(t, ef); + int64 qq = floatx80_to_int64_round_to_zero(td); + floatx80 qqf = int64_to_floatx80(qq); + floatx80 tt = floatx80_mul(b1, qqf); + floatx80 ttt = floatx80_mul(tt, ef); + result = floatx80_sub(a0, ttt); + } + } + + if (x87_check_exceptions()) + x87_write_stack(0, result, TRUE); + + CYCLES(84); +} + +void i386_device::x87_fprem1(UINT8 modrm) +{ + floatx80 result; + + if (X87_IS_ST_EMPTY(0) || X87_IS_ST_EMPTY(1)) + { + x87_set_stack_underflow(); + result = fx80_inan; + } + else + { + floatx80 a = ST(0); + floatx80 b = ST(1); + + m_x87_sw &= ~X87_SW_C2; + + // TODO: Implement Cx bits + result = floatx80_rem(a, b); + } + + if (x87_check_exceptions()) + x87_write_stack(0, result, TRUE); + + CYCLES(94); +} + +void i386_device::x87_fsqrt(UINT8 modrm) +{ + floatx80 result; + + if (X87_IS_ST_EMPTY(0)) + { + x87_set_stack_underflow(); + result = fx80_inan; + } + else + { + floatx80 value = ST(0); + + if ((!floatx80_is_zero(value) && (value.high & 0x8000)) || + floatx80_is_denormal(value)) + { + m_x87_sw |= X87_SW_IE; + result = fx80_inan; + } + else + { + result = floatx80_sqrt(value); + } + } + + if (x87_check_exceptions()) + x87_write_stack(0, result, TRUE); + + CYCLES(8); +} + +/************************************* + * + * Trigonometric + * + *************************************/ + +void i386_device::x87_f2xm1(UINT8 modrm) +{ + floatx80 result; + + if (X87_IS_ST_EMPTY(0)) + { + x87_set_stack_underflow(); + result = fx80_inan; + } + else + { + // TODO: Inaccurate + double x = fx80_to_double(ST(0)); + double res = pow(2.0, x) - 1; + result = double_to_fx80(res); + } + + if (x87_check_exceptions()) + { + x87_write_stack(0, result, TRUE); + } + + CYCLES(242); +} + +void i386_device::x87_fyl2x(UINT8 modrm) +{ + floatx80 result; + + if (X87_IS_ST_EMPTY(0) || X87_IS_ST_EMPTY(1)) + { + x87_set_stack_underflow(); + result = fx80_inan; + } + else + { + floatx80 x = ST(0); + floatx80 y = ST(1); + + if (x.high & 0x8000) + { + m_x87_sw |= X87_SW_IE; + result = fx80_inan; + } + else + { + // TODO: Inaccurate + double d64 = fx80_to_double(x); + double l2x = log(d64)/log(2.0); + result = floatx80_mul(double_to_fx80(l2x), y); + } + } + + if (x87_check_exceptions()) + { + x87_write_stack(1, result, TRUE); + x87_inc_stack(); + } + + CYCLES(250); +} + +void i386_device::x87_fyl2xp1(UINT8 modrm) +{ + floatx80 result; + + if (X87_IS_ST_EMPTY(0) || X87_IS_ST_EMPTY(1)) + { + x87_set_stack_underflow(); + result = fx80_inan; + } + else + { + floatx80 x = ST(0); + floatx80 y = ST(1); + + // TODO: Inaccurate + double d64 = fx80_to_double(x); + double l2x1 = log(d64 + 1.0)/log(2.0); + result = floatx80_mul(double_to_fx80(l2x1), y); + } + + if (x87_check_exceptions()) + { + x87_write_stack(1, result, TRUE); + x87_inc_stack(); + } + + CYCLES(313); +} + +void i386_device::x87_fptan(UINT8 modrm) +{ + floatx80 result1, result2; + + if (X87_IS_ST_EMPTY(0)) + { + x87_set_stack_underflow(); + result1 = fx80_inan; + result2 = fx80_inan; + } + else if (!X87_IS_ST_EMPTY(7)) + { + x87_set_stack_overflow(); + result1 = fx80_inan; + result2 = fx80_inan; + } + else + { + result1 = ST(0); + result2 = fx80_one; + +#if 0 // TODO: Function produces bad values + if (floatx80_ftan(result1) != -1) + m_x87_sw &= ~X87_SW_C2; + else + m_x87_sw |= X87_SW_C2; +#else + double x = fx80_to_double(result1); + x = tan(x); + result1 = double_to_fx80(x); + + m_x87_sw &= ~X87_SW_C2; +#endif + } + + if (x87_check_exceptions()) + { + x87_write_stack(0, result1, TRUE); + x87_dec_stack(); + x87_write_stack(0, result2, TRUE); + } + + CYCLES(244); +} + +void i386_device::x87_fpatan(UINT8 modrm) +{ + floatx80 result; + + if (X87_IS_ST_EMPTY(0)) + { + x87_set_stack_underflow(); + result = fx80_inan; + } + else + { + // TODO: Inaccurate + double val = atan2(fx80_to_double(ST(1)) , fx80_to_double(ST(0))); + result = double_to_fx80(val); + } + + if (x87_check_exceptions()) + { + x87_write_stack(1, result, TRUE); + x87_inc_stack(); + } + + CYCLES(289); +} + +void i386_device::x87_fsin(UINT8 modrm) +{ + floatx80 result; + + if (X87_IS_ST_EMPTY(0)) + { + x87_set_stack_underflow(); + result = fx80_inan; + } + else + { + result = ST(0); + +#if 0 // TODO: Function produces bad values + if (floatx80_fsin(result) != -1) + m_x87_sw &= ~X87_SW_C2; + else + m_x87_sw |= X87_SW_C2; +#else + double x = fx80_to_double(result); + x = sin(x); + result = double_to_fx80(x); + + m_x87_sw &= ~X87_SW_C2; +#endif + } + + if (x87_check_exceptions()) + x87_write_stack(0, result, TRUE); + + CYCLES(241); +} + +void i386_device::x87_fcos(UINT8 modrm) +{ + floatx80 result; + + if (X87_IS_ST_EMPTY(0)) + { + x87_set_stack_underflow(); + result = fx80_inan; + } + else + { + result = ST(0); + +#if 0 // TODO: Function produces bad values + if (floatx80_fcos(result) != -1) + m_x87_sw &= ~X87_SW_C2; + else + m_x87_sw |= X87_SW_C2; +#else + double x = fx80_to_double(result); + x = cos(x); + result = double_to_fx80(x); + + m_x87_sw &= ~X87_SW_C2; +#endif + } + + if (x87_check_exceptions()) + x87_write_stack(0, result, TRUE); + + CYCLES(241); +} + +void i386_device::x87_fsincos(UINT8 modrm) +{ + floatx80 s_result, c_result; + + if (X87_IS_ST_EMPTY(0)) + { + x87_set_stack_underflow(); + s_result = c_result = fx80_inan; + } + else if (!X87_IS_ST_EMPTY(7)) + { + x87_set_stack_overflow(); + s_result = c_result = fx80_inan; + } + else + { + extern int sf_fsincos(floatx80 a, floatx80 *sin_a, floatx80 *cos_a); + + s_result = c_result = ST(0); + +#if 0 // TODO: Function produces bad values + if (sf_fsincos(s_result, &s_result, &c_result) != -1) + m_x87_sw &= ~X87_SW_C2; + else + m_x87_sw |= X87_SW_C2; +#else + double s = fx80_to_double(s_result); + double c = fx80_to_double(c_result); + s = sin(s); + c = cos(c); + + s_result = double_to_fx80(s); + c_result = double_to_fx80(c); + + m_x87_sw &= ~X87_SW_C2; +#endif + } + + if (x87_check_exceptions()) + { + x87_write_stack(0, s_result, TRUE); + x87_dec_stack(); + x87_write_stack(0, c_result, TRUE); + } + + CYCLES(291); +} + + +/************************************* + * + * Load data + * + *************************************/ + +void i386_device::x87_fld_m32real(UINT8 modrm) +{ + floatx80 value; + + UINT32 ea = GetEA(modrm, 0); + if (x87_dec_stack()) + { + UINT32 m32real = READ32(ea); + + value = float32_to_floatx80(m32real); + + m_x87_sw &= ~X87_SW_C1; + + if (floatx80_is_signaling_nan(value) || floatx80_is_denormal(value)) + { + m_x87_sw |= X87_SW_IE; + value = fx80_inan; + } + } + else + { + value = fx80_inan; + } + + if (x87_check_exceptions()) + x87_write_stack(0, value, TRUE); + + CYCLES(3); +} + +void i386_device::x87_fld_m64real(UINT8 modrm) +{ + floatx80 value; + + UINT32 ea = GetEA(modrm, 0); + if (x87_dec_stack()) + { + UINT64 m64real = READ64(ea); + + value = float64_to_floatx80(m64real); + + m_x87_sw &= ~X87_SW_C1; + + if (floatx80_is_signaling_nan(value) || floatx80_is_denormal(value)) + { + m_x87_sw |= X87_SW_IE; + value = fx80_inan; + } + } + else + { + value = fx80_inan; + } + + if (x87_check_exceptions()) + x87_write_stack(0, value, TRUE); + + CYCLES(3); +} + +void i386_device::x87_fld_m80real(UINT8 modrm) +{ + floatx80 value; + + UINT32 ea = GetEA(modrm, 0); + if (x87_dec_stack()) + { + m_x87_sw &= ~X87_SW_C1; + value = READ80(ea); + } + else + { + value = fx80_inan; + } + + if (x87_check_exceptions()) + x87_write_stack(0, value, TRUE); + + CYCLES(6); +} + +void i386_device::x87_fld_sti(UINT8 modrm) +{ + floatx80 value; + + if (x87_dec_stack()) + { + m_x87_sw &= ~X87_SW_C1; + value = ST((modrm + 1) & 7); + } + else + { + value = fx80_inan; + } + + if (x87_check_exceptions()) + x87_write_stack(0, value, TRUE); + + CYCLES(4); +} + +void i386_device::x87_fild_m16int(UINT8 modrm) +{ + floatx80 value; + + UINT32 ea = GetEA(modrm, 0); + if (!x87_dec_stack()) + { + value = fx80_inan; + } + else + { + m_x87_sw &= ~X87_SW_C1; + + INT16 m16int = READ16(ea); + value = int32_to_floatx80(m16int); + } + + if (x87_check_exceptions()) + x87_write_stack(0, value, TRUE); + + CYCLES(13); +} + +void i386_device::x87_fild_m32int(UINT8 modrm) +{ + floatx80 value; + + UINT32 ea = GetEA(modrm, 0); + if (!x87_dec_stack()) + { + value = fx80_inan; + } + else + { + m_x87_sw &= ~X87_SW_C1; + + INT32 m32int = READ32(ea); + value = int32_to_floatx80(m32int); + } + + if (x87_check_exceptions()) + x87_write_stack(0, value, TRUE); + + CYCLES(9); +} + +void i386_device::x87_fild_m64int(UINT8 modrm) +{ + floatx80 value; + + UINT32 ea = GetEA(modrm, 0); + if (!x87_dec_stack()) + { + value = fx80_inan; + } + else + { + m_x87_sw &= ~X87_SW_C1; + + INT64 m64int = READ64(ea); + value = int64_to_floatx80(m64int); + } + + if (x87_check_exceptions()) + x87_write_stack(0, value, TRUE); + + CYCLES(10); +} + +void i386_device::x87_fbld(UINT8 modrm) +{ + floatx80 value; + + UINT32 ea = GetEA(modrm, 0); + if (!x87_dec_stack()) + { + value = fx80_inan; + } + else + { + m_x87_sw &= ~X87_SW_C1; + + UINT64 m64val = 0; + UINT16 sign; + + value = READ80(ea); + + sign = value.high & 0x8000; + m64val += ((value.high >> 4) & 0xf) * 10; + m64val += ((value.high >> 0) & 0xf); + + for (int i = 60; i >= 0; i -= 4) + { + m64val *= 10; + m64val += (value.low >> i) & 0xf; + } + + value = int64_to_floatx80(m64val); + value.high |= sign; + } + + if (x87_check_exceptions()) + x87_write_stack(0, value, TRUE); + + CYCLES(75); +} + + +/************************************* + * + * Store data + * + *************************************/ + +void i386_device::x87_fst_m32real(UINT8 modrm) +{ + floatx80 value; + + UINT32 ea = GetEA(modrm, 1); + if (X87_IS_ST_EMPTY(0)) + { + x87_set_stack_underflow(); + value = fx80_inan; + } + else + { + m_x87_sw &= ~X87_SW_C1; + value = ST(0); + } + + if (x87_check_exceptions()) + { + UINT32 m32real = floatx80_to_float32(value); + WRITE32(ea, m32real); + } + + CYCLES(7); +} + +void i386_device::x87_fst_m64real(UINT8 modrm) +{ + floatx80 value; + + UINT32 ea = GetEA(modrm, 1); + if (X87_IS_ST_EMPTY(0)) + { + x87_set_stack_underflow(); + value = fx80_inan; + } + else + { + m_x87_sw &= ~X87_SW_C1; + value = ST(0); + } + + if (x87_check_exceptions()) + { + UINT64 m64real = floatx80_to_float64(value); + WRITE64(ea, m64real); + } + + CYCLES(8); +} + +void i386_device::x87_fst_sti(UINT8 modrm) +{ + int i = modrm & 7; + floatx80 value; + + if (X87_IS_ST_EMPTY(0)) + { + x87_set_stack_underflow(); + value = fx80_inan; + } + else + { + m_x87_sw &= ~X87_SW_C1; + value = ST(0); + } + + if (x87_check_exceptions()) + x87_write_stack(i, value, TRUE); + + CYCLES(3); +} + +void i386_device::x87_fstp_m32real(UINT8 modrm) +{ + floatx80 value; + + UINT32 ea = GetEA(modrm, 1); + if (X87_IS_ST_EMPTY(0)) + { + x87_set_stack_underflow(); + value = fx80_inan; + } + else + { + m_x87_sw &= ~X87_SW_C1; + value = ST(0); + } + + if (x87_check_exceptions()) + { + UINT32 m32real = floatx80_to_float32(value); + WRITE32(ea, m32real); + x87_inc_stack(); + } + + CYCLES(7); +} + +void i386_device::x87_fstp_m64real(UINT8 modrm) +{ + floatx80 value; + + if (X87_IS_ST_EMPTY(0)) + { + x87_set_stack_underflow(); + value = fx80_inan; + } + else + { + m_x87_sw &= ~X87_SW_C1; + value = ST(0); + } + + + UINT32 ea = GetEA(modrm, 1); + if (x87_check_exceptions()) + { + UINT64 m64real = floatx80_to_float64(value); + WRITE64(ea, m64real); + x87_inc_stack(); + } + + CYCLES(8); +} + +void i386_device::x87_fstp_m80real(UINT8 modrm) +{ + floatx80 value; + + if (X87_IS_ST_EMPTY(0)) + { + x87_set_stack_underflow(); + value = fx80_inan; + } + else + { + m_x87_sw &= ~X87_SW_C1; + value = ST(0); + } + + UINT32 ea = GetEA(modrm, 1); + if (x87_check_exceptions()) + { + WRITE80(ea, value); + x87_inc_stack(); + } + + CYCLES(6); +} + +void i386_device::x87_fstp_sti(UINT8 modrm) +{ + int i = modrm & 7; + floatx80 value; + + if (X87_IS_ST_EMPTY(0)) + { + x87_set_stack_underflow(); + value = fx80_inan; + } + else + { + m_x87_sw &= ~X87_SW_C1; + value = ST(0); + } + + if (x87_check_exceptions()) + { + x87_write_stack(i, value, TRUE); + x87_inc_stack(); + } + + CYCLES(3); +} + +void i386_device::x87_fist_m16int(UINT8 modrm) +{ + INT16 m16int; + + if (X87_IS_ST_EMPTY(0)) + { + x87_set_stack_underflow(); + m16int = -32768; + } + else + { + floatx80 fx80 = floatx80_round_to_int(ST(0)); + + floatx80 lowerLim = int32_to_floatx80(-32768); + floatx80 upperLim = int32_to_floatx80(32767); + + m_x87_sw &= ~X87_SW_C1; + + if (!floatx80_lt(fx80, lowerLim) && floatx80_le(fx80, upperLim)) + m16int = floatx80_to_int32(fx80); + else + m16int = -32768; + } + + UINT32 ea = GetEA(modrm, 1); + if (x87_check_exceptions()) + { + WRITE16(ea, m16int); + } + + CYCLES(29); +} + +void i386_device::x87_fist_m32int(UINT8 modrm) +{ + INT32 m32int; + + if (X87_IS_ST_EMPTY(0)) + { + x87_set_stack_underflow(); + m32int = 0x80000000; + } + else + { + floatx80 fx80 = floatx80_round_to_int(ST(0)); + + floatx80 lowerLim = int32_to_floatx80(0x80000000); + floatx80 upperLim = int32_to_floatx80(0x7fffffff); + + m_x87_sw &= ~X87_SW_C1; + + if (!floatx80_lt(fx80, lowerLim) && floatx80_le(fx80, upperLim)) + m32int = floatx80_to_int32(fx80); + else + m32int = 0x80000000; + } + + UINT32 ea = GetEA(modrm, 1); + if (x87_check_exceptions()) + { + WRITE32(ea, m32int); + } + + CYCLES(28); +} + +void i386_device::x87_fistp_m16int(UINT8 modrm) +{ + INT16 m16int; + + if (X87_IS_ST_EMPTY(0)) + { + x87_set_stack_underflow(); + m16int = (UINT16)0x8000; + } + else + { + floatx80 fx80 = floatx80_round_to_int(ST(0)); + + floatx80 lowerLim = int32_to_floatx80(-32768); + floatx80 upperLim = int32_to_floatx80(32767); + + m_x87_sw &= ~X87_SW_C1; + + if (!floatx80_lt(fx80, lowerLim) && floatx80_le(fx80, upperLim)) + m16int = floatx80_to_int32(fx80); + else + m16int = (UINT16)0x8000; + } + + UINT32 ea = GetEA(modrm, 1); + if (x87_check_exceptions()) + { + WRITE16(ea, m16int); + x87_inc_stack(); + } + + CYCLES(29); +} + +void i386_device::x87_fistp_m32int(UINT8 modrm) +{ + INT32 m32int; + + if (X87_IS_ST_EMPTY(0)) + { + x87_set_stack_underflow(); + m32int = 0x80000000; + } + else + { + floatx80 fx80 = floatx80_round_to_int(ST(0)); + + floatx80 lowerLim = int32_to_floatx80(0x80000000); + floatx80 upperLim = int32_to_floatx80(0x7fffffff); + + m_x87_sw &= ~X87_SW_C1; + + if (!floatx80_lt(fx80, lowerLim) && floatx80_le(fx80, upperLim)) + m32int = floatx80_to_int32(fx80); + else + m32int = 0x80000000; + } + + UINT32 ea = GetEA(modrm, 1); + if (x87_check_exceptions()) + { + WRITE32(ea, m32int); + x87_inc_stack(); + } + + CYCLES(29); +} + +void i386_device::x87_fistp_m64int(UINT8 modrm) +{ + INT64 m64int; + + if (X87_IS_ST_EMPTY(0)) + { + x87_set_stack_underflow(); + m64int = U64(0x8000000000000000); + } + else + { + floatx80 fx80 = floatx80_round_to_int(ST(0)); + + floatx80 lowerLim = int64_to_floatx80(U64(0x8000000000000000)); + floatx80 upperLim = int64_to_floatx80(U64(0x7fffffffffffffff)); + + m_x87_sw &= ~X87_SW_C1; + + if (!floatx80_lt(fx80, lowerLim) && floatx80_le(fx80, upperLim)) + m64int = floatx80_to_int64(fx80); + else + m64int = U64(0x8000000000000000); + } + + UINT32 ea = GetEA(modrm, 1); + if (x87_check_exceptions()) + { + WRITE64(ea, m64int); + x87_inc_stack(); + } + + CYCLES(29); +} + +void i386_device::x87_fbstp(UINT8 modrm) +{ + floatx80 result; + + if (X87_IS_ST_EMPTY(0)) + { + x87_set_stack_underflow(); + result = fx80_inan; + } + else + { + UINT64 u64 = floatx80_to_int64(floatx80_abs(ST(0))); + result.low = 0; + + for (int i = 0; i < 64; i += 4) + { + result.low += (u64 % 10) << i; + u64 /= 10; + } + + result.high = (u64 % 10); + result.high += ((u64 / 10) % 10) << 4; + result.high |= ST(0).high & 0x8000; + } + + UINT32 ea = GetEA(modrm, 1); + if (x87_check_exceptions()) + { + WRITE80(ea, result); + x87_inc_stack(); + } + + CYCLES(175); +} + + +/************************************* + * + * Constant load + * + *************************************/ + +void i386_device::x87_fld1(UINT8 modrm) +{ + floatx80 value; + int tag; + + if (x87_dec_stack()) + { + m_x87_sw &= ~X87_SW_C1; + value = fx80_one; + tag = X87_TW_VALID; + } + else + { + value = fx80_inan; + tag = X87_TW_SPECIAL; + } + + if (x87_check_exceptions()) + { + x87_set_tag(ST_TO_PHYS(0), tag); + x87_write_stack(0, value, FALSE); + } + + CYCLES(4); +} + +void i386_device::x87_fldl2t(UINT8 modrm) +{ + floatx80 value; + int tag; + + if (x87_dec_stack()) + { + tag = X87_TW_VALID; + value.high = 0x4000; + + if (X87_RC == X87_CW_RC_UP) + value.low = U64(0xd49a784bcd1b8aff); + else + value.low = U64(0xd49a784bcd1b8afe); + + m_x87_sw &= ~X87_SW_C1; + } + else + { + value = fx80_inan; + tag = X87_TW_SPECIAL; + } + + if (x87_check_exceptions()) + { + x87_set_tag(ST_TO_PHYS(0), tag); + x87_write_stack(0, value, FALSE); + } + + CYCLES(8); +} + +void i386_device::x87_fldl2e(UINT8 modrm) +{ + floatx80 value; + int tag; + + if (x87_dec_stack()) + { + int rc = X87_RC; + tag = X87_TW_VALID; + value.high = 0x3fff; + + if (rc == X87_CW_RC_UP || rc == X87_CW_RC_NEAREST) + value.low = U64(0xb8aa3b295c17f0bc); + else + value.low = U64(0xb8aa3b295c17f0bb); + + m_x87_sw &= ~X87_SW_C1; + } + else + { + value = fx80_inan; + tag = X87_TW_SPECIAL; + } + + if (x87_check_exceptions()) + { + x87_set_tag(ST_TO_PHYS(0), tag); + x87_write_stack(0, value, FALSE); + } + + CYCLES(8); +} + +void i386_device::x87_fldpi(UINT8 modrm) +{ + floatx80 value; + int tag; + + if (x87_dec_stack()) + { + int rc = X87_RC; + tag = X87_TW_VALID; + value.high = 0x4000; + + if (rc == X87_CW_RC_UP || rc == X87_CW_RC_NEAREST) + value.low = U64(0xc90fdaa22168c235); + else + value.low = U64(0xc90fdaa22168c234); + + m_x87_sw &= ~X87_SW_C1; + } + else + { + value = fx80_inan; + tag = X87_TW_SPECIAL; + } + + if (x87_check_exceptions()) + { + x87_set_tag(ST_TO_PHYS(0), tag); + x87_write_stack(0, value, FALSE); + } + + CYCLES(8); +} + +void i386_device::x87_fldlg2(UINT8 modrm) +{ + floatx80 value; + int tag; + + if (x87_dec_stack()) + { + int rc = X87_RC; + tag = X87_TW_VALID; + value.high = 0x3ffd; + + if (rc == X87_CW_RC_UP || rc == X87_CW_RC_NEAREST) + value.low = U64(0x9a209a84fbcff799); + else + value.low = U64(0x9a209a84fbcff798); + + m_x87_sw &= ~X87_SW_C1; + } + else + { + value = fx80_inan; + tag = X87_TW_SPECIAL; + } + + if (x87_check_exceptions()) + { + x87_set_tag(ST_TO_PHYS(0), tag); + x87_write_stack(0, value, FALSE); + } + + CYCLES(8); +} + +void i386_device::x87_fldln2(UINT8 modrm) +{ + floatx80 value; + int tag; + + if (x87_dec_stack()) + { + int rc = X87_RC; + tag = X87_TW_VALID; + value.high = 0x3ffe; + + if (rc == X87_CW_RC_UP || rc == X87_CW_RC_NEAREST) + value.low = U64(0xb17217f7d1cf79ac); + else + value.low = U64(0xb17217f7d1cf79ab); + + m_x87_sw &= ~X87_SW_C1; + } + else + { + value = fx80_inan; + tag = X87_TW_SPECIAL; + } + + if (x87_check_exceptions()) + { + x87_set_tag(ST_TO_PHYS(0), tag); + x87_write_stack(0, value, FALSE); + } + + CYCLES(8); +} + +void i386_device::x87_fldz(UINT8 modrm) +{ + floatx80 value; + int tag; + + if (x87_dec_stack()) + { + value = fx80_zero; + tag = X87_TW_ZERO; + m_x87_sw &= ~X87_SW_C1; + } + else + { + value = fx80_inan; + tag = X87_TW_SPECIAL; + } + + if (x87_check_exceptions()) + { + x87_set_tag(ST_TO_PHYS(0), tag); + x87_write_stack(0, value, FALSE); + } + + CYCLES(4); +} + + +/************************************* + * + * Miscellaneous + * + *************************************/ + +void i386_device::x87_fnop(UINT8 modrm) +{ + CYCLES(3); +} + +void i386_device::x87_fchs(UINT8 modrm) +{ + floatx80 value; + + if (X87_IS_ST_EMPTY(0)) + { + x87_set_stack_underflow(); + value = fx80_inan; + } + else + { + m_x87_sw &= ~X87_SW_C1; + + value = ST(0); + value.high ^= 0x8000; + } + + if (x87_check_exceptions()) + x87_write_stack(0, value, FALSE); + + CYCLES(6); +} + +void i386_device::x87_fabs(UINT8 modrm) +{ + floatx80 value; + + if (X87_IS_ST_EMPTY(0)) + { + x87_set_stack_underflow(); + value = fx80_inan; + } + else + { + m_x87_sw &= ~X87_SW_C1; + + value = ST(0); + value.high &= 0x7fff; + } + + if (x87_check_exceptions()) + x87_write_stack(0, value, FALSE); + + CYCLES(6); +} + +void i386_device::x87_fscale(UINT8 modrm) +{ + floatx80 value; + + if (X87_IS_ST_EMPTY(0) || X87_IS_ST_EMPTY(1)) + { + x87_set_stack_underflow(); + value = fx80_inan; + } + else + { + m_x87_sw &= ~X87_SW_C1; + value = ST(0); + + // Set the rounding mode to truncate + UINT16 old_cw = m_x87_cw; + UINT16 new_cw = (old_cw & ~(X87_CW_RC_MASK << X87_CW_RC_SHIFT)) | (X87_CW_RC_ZERO << X87_CW_RC_SHIFT); + x87_write_cw(new_cw); + + // Interpret ST(1) as an integer + UINT32 st1 = floatx80_to_int32(floatx80_round_to_int(ST(1))); + + // Restore the rounding mode + x87_write_cw(old_cw); + + // Get the unbiased exponent of ST(0) + INT16 exp = (ST(0).high & 0x7fff) - 0x3fff; + + // Calculate the new exponent + exp = (exp + st1 + 0x3fff) & 0x7fff; + + // Write it back + value.high = (value.high & ~0x7fff) + exp; + } + + if (x87_check_exceptions()) + x87_write_stack(0, value, FALSE); + + CYCLES(31); +} + +void i386_device::x87_frndint(UINT8 modrm) +{ + floatx80 value; + + if (X87_IS_ST_EMPTY(0)) + { + x87_set_stack_underflow(); + value = fx80_inan; + } + else + { + m_x87_sw &= ~X87_SW_C1; + + value = floatx80_round_to_int(ST(0)); + } + + if (x87_check_exceptions()) + x87_write_stack(0, value, TRUE); + + CYCLES(21); +} + +void i386_device::x87_fxtract(UINT8 modrm) +{ + floatx80 sig80, exp80; + + if (X87_IS_ST_EMPTY(0)) + { + x87_set_stack_underflow(); + sig80 = exp80 = fx80_inan; + } + else if (!X87_IS_ST_EMPTY(7)) + { + x87_set_stack_overflow(); + sig80 = exp80 = fx80_inan; + } + else + { + floatx80 value = ST(0); + + if (floatx80_eq(value, fx80_zero)) + { + m_x87_sw |= X87_SW_ZE; + + exp80 = fx80_ninf; + sig80 = fx80_zero; + } + else + { + // Extract the unbiased exponent + exp80 = int32_to_floatx80((value.high & 0x7fff) - 0x3fff); + + // For the significand, replicate the original value and set its true exponent to 0. + sig80 = value; + sig80.high &= ~0x7fff; + sig80.high |= 0x3fff; + } + } + + if (x87_check_exceptions()) + { + x87_write_stack(0, exp80, TRUE); + x87_dec_stack(); + x87_write_stack(0, sig80, TRUE); + } + + CYCLES(21); +} + +/************************************* + * + * Comparison + * + *************************************/ + +void i386_device::x87_ftst(UINT8 modrm) +{ + if (X87_IS_ST_EMPTY(0)) + { + x87_set_stack_underflow(); + m_x87_sw |= X87_SW_C3 | X87_SW_C2 | X87_SW_C0; + } + else + { + m_x87_sw &= ~(X87_SW_C3 | X87_SW_C2 | X87_SW_C1 | X87_SW_C0); + + if (floatx80_is_nan(ST(0))) + { + m_x87_sw |= X87_SW_C0 | X87_SW_C2 | X87_SW_C3; + m_x87_sw |= X87_SW_IE; + } + else + { + if (floatx80_eq(ST(0), fx80_zero)) + m_x87_sw |= X87_SW_C3; + + if (floatx80_lt(ST(0), fx80_zero)) + m_x87_sw |= X87_SW_C0; + } + } + + x87_check_exceptions(); + + CYCLES(4); +} + +void i386_device::x87_fxam(UINT8 modrm) +{ + floatx80 value = ST(0); + + m_x87_sw &= ~(X87_SW_C3 | X87_SW_C2 | X87_SW_C1 | X87_SW_C0); + + // TODO: Unsupported and denormal values + if (X87_IS_ST_EMPTY(0)) + { + m_x87_sw |= X87_SW_C3 | X87_SW_C0; + } + else if (floatx80_is_zero(value)) + { + m_x87_sw |= X87_SW_C3; + } + if (floatx80_is_nan(value)) + { + m_x87_sw |= X87_SW_C0; + } + else if (floatx80_is_inf(value)) + { + m_x87_sw |= X87_SW_C2 | X87_SW_C0; + } + else + { + m_x87_sw |= X87_SW_C2; + } + + if (value.high & 0x8000) + m_x87_sw |= X87_SW_C1; + + CYCLES(8); +} + +void i386_device::x87_ficom_m16int(UINT8 modrm) +{ + UINT32 ea = GetEA(modrm, 0); + if (X87_IS_ST_EMPTY(0)) + { + x87_set_stack_underflow(); + m_x87_sw |= X87_SW_C3 | X87_SW_C2 | X87_SW_C0; + } + else + { + m_x87_sw &= ~(X87_SW_C3 | X87_SW_C2 | X87_SW_C1 | X87_SW_C0); + + INT16 m16int = READ16(ea); + + floatx80 a = ST(0); + floatx80 b = int32_to_floatx80(m16int); + + if (floatx80_is_nan(a)) + { + m_x87_sw |= X87_SW_C0 | X87_SW_C2 | X87_SW_C3; + m_x87_sw |= X87_SW_IE; + } + else + { + if (floatx80_eq(a, b)) + m_x87_sw |= X87_SW_C3; + + if (floatx80_lt(a, b)) + m_x87_sw |= X87_SW_C0; + } + } + + x87_check_exceptions(); + + CYCLES(16); +} + +void i386_device::x87_ficom_m32int(UINT8 modrm) +{ + UINT32 ea = GetEA(modrm, 0); + if (X87_IS_ST_EMPTY(0)) + { + x87_set_stack_underflow(); + m_x87_sw |= X87_SW_C3 | X87_SW_C2 | X87_SW_C0; + } + else + { + m_x87_sw &= ~(X87_SW_C3 | X87_SW_C2 | X87_SW_C1 | X87_SW_C0); + + INT32 m32int = READ32(ea); + + floatx80 a = ST(0); + floatx80 b = int32_to_floatx80(m32int); + + if (floatx80_is_nan(a)) + { + m_x87_sw |= X87_SW_C0 | X87_SW_C2 | X87_SW_C3; + m_x87_sw |= X87_SW_IE; + } + else + { + if (floatx80_eq(a, b)) + m_x87_sw |= X87_SW_C3; + + if (floatx80_lt(a, b)) + m_x87_sw |= X87_SW_C0; + } + } + + x87_check_exceptions(); + + CYCLES(15); +} + +void i386_device::x87_ficomp_m16int(UINT8 modrm) +{ + UINT32 ea = GetEA(modrm, 0); + if (X87_IS_ST_EMPTY(0)) + { + x87_set_stack_underflow(); + m_x87_sw |= X87_SW_C3 | X87_SW_C2 | X87_SW_C0; + } + else + { + m_x87_sw &= ~(X87_SW_C3 | X87_SW_C2 | X87_SW_C1 | X87_SW_C0); + + INT16 m16int = READ16(ea); + + floatx80 a = ST(0); + floatx80 b = int32_to_floatx80(m16int); + + if (floatx80_is_nan(a)) + { + m_x87_sw |= X87_SW_C0 | X87_SW_C2 | X87_SW_C3; + m_x87_sw |= X87_SW_IE; + } + else + { + if (floatx80_eq(a, b)) + m_x87_sw |= X87_SW_C3; + + if (floatx80_lt(a, b)) + m_x87_sw |= X87_SW_C0; + } + } + + if (x87_check_exceptions()) + x87_inc_stack(); + + CYCLES(16); +} + +void i386_device::x87_ficomp_m32int(UINT8 modrm) +{ + UINT32 ea = GetEA(modrm, 0); + if (X87_IS_ST_EMPTY(0)) + { + x87_set_stack_underflow(); + m_x87_sw |= X87_SW_C3 | X87_SW_C2 | X87_SW_C0; + } + else + { + m_x87_sw &= ~(X87_SW_C3 | X87_SW_C2 | X87_SW_C1 | X87_SW_C0); + + INT32 m32int = READ32(ea); + + floatx80 a = ST(0); + floatx80 b = int32_to_floatx80(m32int); + + if (floatx80_is_nan(a)) + { + m_x87_sw |= X87_SW_C0 | X87_SW_C2 | X87_SW_C3; + m_x87_sw |= X87_SW_IE; + } + else + { + if (floatx80_eq(a, b)) + m_x87_sw |= X87_SW_C3; + + if (floatx80_lt(a, b)) + m_x87_sw |= X87_SW_C0; + } + } + + if (x87_check_exceptions()) + x87_inc_stack(); + + CYCLES(15); +} + + +void i386_device::x87_fcom_m32real(UINT8 modrm) +{ + UINT32 ea = GetEA(modrm, 0); + if (X87_IS_ST_EMPTY(0)) + { + x87_set_stack_underflow(); + m_x87_sw |= X87_SW_C3 | X87_SW_C2 | X87_SW_C0; + } + else + { + m_x87_sw &= ~(X87_SW_C3 | X87_SW_C2 | X87_SW_C1 | X87_SW_C0); + + UINT32 m32real = READ32(ea); + + floatx80 a = ST(0); + floatx80 b = float32_to_floatx80(m32real); + + if (floatx80_is_nan(a) || floatx80_is_nan(b)) + { + m_x87_sw |= X87_SW_C0 | X87_SW_C2 | X87_SW_C3; + m_x87_sw |= X87_SW_IE; + } + else + { + if (floatx80_eq(a, b)) + m_x87_sw |= X87_SW_C3; + + if (floatx80_lt(a, b)) + m_x87_sw |= X87_SW_C0; + } + } + + x87_check_exceptions(); + + CYCLES(4); +} + +void i386_device::x87_fcom_m64real(UINT8 modrm) +{ + UINT32 ea = GetEA(modrm, 0); + if (X87_IS_ST_EMPTY(0)) + { + x87_set_stack_underflow(); + m_x87_sw |= X87_SW_C3 | X87_SW_C2 | X87_SW_C0; + } + else + { + m_x87_sw &= ~(X87_SW_C3 | X87_SW_C2 | X87_SW_C1 | X87_SW_C0); + + UINT64 m64real = READ64(ea); + + floatx80 a = ST(0); + floatx80 b = float64_to_floatx80(m64real); + + if (floatx80_is_nan(a) || floatx80_is_nan(b)) + { + m_x87_sw |= X87_SW_C0 | X87_SW_C2 | X87_SW_C3; + m_x87_sw |= X87_SW_IE; + } + else + { + if (floatx80_eq(a, b)) + m_x87_sw |= X87_SW_C3; + + if (floatx80_lt(a, b)) + m_x87_sw |= X87_SW_C0; + } + } + + x87_check_exceptions(); + + CYCLES(4); +} + +void i386_device::x87_fcom_sti(UINT8 modrm) +{ + int i = modrm & 7; + + if (X87_IS_ST_EMPTY(0) || X87_IS_ST_EMPTY(i)) + { + x87_set_stack_underflow(); + m_x87_sw |= X87_SW_C3 | X87_SW_C2 | X87_SW_C0; + } + else + { + m_x87_sw &= ~(X87_SW_C3 | X87_SW_C2 | X87_SW_C1 | X87_SW_C0); + + floatx80 a = ST(0); + floatx80 b = ST(i); + + if (floatx80_is_nan(a) || floatx80_is_nan(b)) + { + m_x87_sw |= X87_SW_C0 | X87_SW_C2 | X87_SW_C3; + m_x87_sw |= X87_SW_IE; + } + else + { + if (floatx80_eq(a, b)) + m_x87_sw |= X87_SW_C3; + + if (floatx80_lt(a, b)) + m_x87_sw |= X87_SW_C0; + } + } + + x87_check_exceptions(); + + CYCLES(4); +} + +void i386_device::x87_fcomp_m32real(UINT8 modrm) +{ + UINT32 ea = GetEA(modrm, 0); + if (X87_IS_ST_EMPTY(0)) + { + x87_set_stack_underflow(); + m_x87_sw |= X87_SW_C3 | X87_SW_C2 | X87_SW_C0; + } + else + { + m_x87_sw &= ~(X87_SW_C3 | X87_SW_C2 | X87_SW_C1 | X87_SW_C0); + + UINT32 m32real = READ32(ea); + + floatx80 a = ST(0); + floatx80 b = float32_to_floatx80(m32real); + + if (floatx80_is_nan(a) || floatx80_is_nan(b)) + { + m_x87_sw |= X87_SW_C0 | X87_SW_C2 | X87_SW_C3; + m_x87_sw |= X87_SW_IE; + } + else + { + if (floatx80_eq(a, b)) + m_x87_sw |= X87_SW_C3; + + if (floatx80_lt(a, b)) + m_x87_sw |= X87_SW_C0; + } + } + + if (x87_check_exceptions()) + x87_inc_stack(); + + CYCLES(4); +} + +void i386_device::x87_fcomp_m64real(UINT8 modrm) +{ + UINT32 ea = GetEA(modrm, 0); + if (X87_IS_ST_EMPTY(0)) + { + x87_set_stack_underflow(); + m_x87_sw |= X87_SW_C3 | X87_SW_C2 | X87_SW_C0; + } + else + { + m_x87_sw &= ~(X87_SW_C3 | X87_SW_C2 | X87_SW_C1 | X87_SW_C0); + + UINT64 m64real = READ64(ea); + + floatx80 a = ST(0); + floatx80 b = float64_to_floatx80(m64real); + + if (floatx80_is_nan(a) || floatx80_is_nan(b)) + { + m_x87_sw |= X87_SW_C0 | X87_SW_C2 | X87_SW_C3; + m_x87_sw |= X87_SW_IE; + } + else + { + if (floatx80_eq(a, b)) + m_x87_sw |= X87_SW_C3; + + if (floatx80_lt(a, b)) + m_x87_sw |= X87_SW_C0; + } + } + + if (x87_check_exceptions()) + x87_inc_stack(); + + CYCLES(4); +} + +void i386_device::x87_fcomp_sti(UINT8 modrm) +{ + int i = modrm & 7; + + if (X87_IS_ST_EMPTY(0) || X87_IS_ST_EMPTY(i)) + { + x87_set_stack_underflow(); + m_x87_sw |= X87_SW_C3 | X87_SW_C2 | X87_SW_C0; + } + else + { + m_x87_sw &= ~(X87_SW_C3 | X87_SW_C2 | X87_SW_C1 | X87_SW_C0); + + floatx80 a = ST(0); + floatx80 b = ST(i); + + if (floatx80_is_nan(a) || floatx80_is_nan(b)) + { + m_x87_sw |= X87_SW_C0 | X87_SW_C2 | X87_SW_C3; + m_x87_sw |= X87_SW_IE; + } + else + { + if (floatx80_eq(a, b)) + m_x87_sw |= X87_SW_C3; + + if (floatx80_lt(a, b)) + m_x87_sw |= X87_SW_C0; + } + } + + if (x87_check_exceptions()) + x87_inc_stack(); + + CYCLES(4); +} + +void i386_device::x87_fcomi_sti(UINT8 modrm) +{ + int i = modrm & 7; + + if (X87_IS_ST_EMPTY(0) || X87_IS_ST_EMPTY(i)) + { + x87_set_stack_underflow(); + m_ZF = 1; + m_PF = 1; + m_CF = 1; + } + else + { + m_x87_sw &= ~X87_SW_C1; + + floatx80 a = ST(0); + floatx80 b = ST(i); + + if (floatx80_is_nan(a) || floatx80_is_nan(b)) + { + m_ZF = 1; + m_PF = 1; + m_CF = 1; + m_x87_sw |= X87_SW_IE; + } + else + { + m_ZF = 0; + m_PF = 0; + m_CF = 0; + + if (floatx80_eq(a, b)) + m_ZF = 1; + + if (floatx80_lt(a, b)) + m_CF = 1; + } + } + + x87_check_exceptions(); + + CYCLES(4); // TODO: correct cycle count +} + +void i386_device::x87_fcomip_sti(UINT8 modrm) +{ + int i = modrm & 7; + + if (X87_IS_ST_EMPTY(0) || X87_IS_ST_EMPTY(i)) + { + x87_set_stack_underflow(); + m_ZF = 1; + m_PF = 1; + m_CF = 1; + } + else + { + m_x87_sw &= ~X87_SW_C1; + + floatx80 a = ST(0); + floatx80 b = ST(i); + + if (floatx80_is_nan(a) || floatx80_is_nan(b)) + { + m_ZF = 1; + m_PF = 1; + m_CF = 1; + m_x87_sw |= X87_SW_IE; + } + else + { + m_ZF = 0; + m_PF = 0; + m_CF = 0; + + if (floatx80_eq(a, b)) + m_ZF = 1; + + if (floatx80_lt(a, b)) + m_CF = 1; + } + } + + if (x87_check_exceptions()) + x87_inc_stack(); + + CYCLES(4); // TODO: correct cycle count +} + +void i386_device::x87_fucomi_sti(UINT8 modrm) +{ + int i = modrm & 7; + + if (X87_IS_ST_EMPTY(0) || X87_IS_ST_EMPTY(i)) + { + x87_set_stack_underflow(); + m_ZF = 1; + m_PF = 1; + m_CF = 1; + } + else + { + m_x87_sw &= ~X87_SW_C1; + + floatx80 a = ST(0); + floatx80 b = ST(i); + + if (floatx80_is_quiet_nan(a) || floatx80_is_quiet_nan(b)) + { + m_ZF = 1; + m_PF = 1; + m_CF = 1; + } + else if (floatx80_is_nan(a) || floatx80_is_nan(b)) + { + m_ZF = 1; + m_PF = 1; + m_CF = 1; + m_x87_sw |= X87_SW_IE; + } + else + { + m_ZF = 0; + m_PF = 0; + m_CF = 0; + + if (floatx80_eq(a, b)) + m_ZF = 1; + + if (floatx80_lt(a, b)) + m_CF = 1; + } + } + + x87_check_exceptions(); + + CYCLES(4); // TODO: correct cycle count +} + +void i386_device::x87_fucomip_sti(UINT8 modrm) +{ + int i = modrm & 7; + + if (X87_IS_ST_EMPTY(0) || X87_IS_ST_EMPTY(i)) + { + x87_set_stack_underflow(); + m_ZF = 1; + m_PF = 1; + m_CF = 1; + } + else + { + m_x87_sw &= ~X87_SW_C1; + + floatx80 a = ST(0); + floatx80 b = ST(i); + + if (floatx80_is_quiet_nan(a) || floatx80_is_quiet_nan(b)) + { + m_ZF = 1; + m_PF = 1; + m_CF = 1; + } + else if (floatx80_is_nan(a) || floatx80_is_nan(b)) + { + m_ZF = 1; + m_PF = 1; + m_CF = 1; + m_x87_sw |= X87_SW_IE; + } + else + { + m_ZF = 0; + m_PF = 0; + m_CF = 0; + + if (floatx80_eq(a, b)) + m_ZF = 1; + + if (floatx80_lt(a, b)) + m_CF = 1; + } + } + + if (x87_check_exceptions()) + x87_inc_stack(); + + CYCLES(4); // TODO: correct cycle count +} + +void i386_device::x87_fcompp(UINT8 modrm) +{ + if (X87_IS_ST_EMPTY(0) || X87_IS_ST_EMPTY(1)) + { + x87_set_stack_underflow(); + m_x87_sw |= X87_SW_C3 | X87_SW_C2 | X87_SW_C0; + } + else + { + m_x87_sw &= ~(X87_SW_C3 | X87_SW_C2 | X87_SW_C1 | X87_SW_C0); + + floatx80 a = ST(0); + floatx80 b = ST(1); + + if (floatx80_is_nan(a) || floatx80_is_nan(b)) + { + m_x87_sw |= X87_SW_C0 | X87_SW_C2 | X87_SW_C3; + m_x87_sw |= X87_SW_IE; + } + else + { + if (floatx80_eq(a, b)) + m_x87_sw |= X87_SW_C3; + + if (floatx80_lt(a, b)) + m_x87_sw |= X87_SW_C0; + } + } + + if (x87_check_exceptions()) + { + x87_inc_stack(); + x87_inc_stack(); + } + + CYCLES(5); +} + + +/************************************* + * + * Unordererd comparison + * + *************************************/ + +void i386_device::x87_fucom_sti(UINT8 modrm) +{ + int i = modrm & 7; + + if (X87_IS_ST_EMPTY(0) || X87_IS_ST_EMPTY(i)) + { + x87_set_stack_underflow(); + m_x87_sw |= X87_SW_C3 | X87_SW_C2 | X87_SW_C0; + } + else + { + m_x87_sw &= ~(X87_SW_C3 | X87_SW_C2 | X87_SW_C1 | X87_SW_C0); + + floatx80 a = ST(0); + floatx80 b = ST(i); + + if (floatx80_is_nan(a) || floatx80_is_nan(b)) + { + m_x87_sw |= X87_SW_C0 | X87_SW_C2 | X87_SW_C3; + + if (floatx80_is_signaling_nan(a) || floatx80_is_signaling_nan(b)) + m_x87_sw |= X87_SW_IE; + } + else + { + if (floatx80_eq(a, b)) + m_x87_sw |= X87_SW_C3; + + if (floatx80_lt(a, b)) + m_x87_sw |= X87_SW_C0; + } + } + + x87_check_exceptions(); + + CYCLES(4); +} + +void i386_device::x87_fucomp_sti(UINT8 modrm) +{ + int i = modrm & 7; + + if (X87_IS_ST_EMPTY(0) || X87_IS_ST_EMPTY(i)) + { + x87_set_stack_underflow(); + m_x87_sw |= X87_SW_C3 | X87_SW_C2 | X87_SW_C0; + } + else + { + m_x87_sw &= ~(X87_SW_C3 | X87_SW_C2 | X87_SW_C1 | X87_SW_C0); + + floatx80 a = ST(0); + floatx80 b = ST(i); + + if (floatx80_is_nan(a) || floatx80_is_nan(b)) + { + m_x87_sw |= X87_SW_C0 | X87_SW_C2 | X87_SW_C3; + + if (floatx80_is_signaling_nan(a) || floatx80_is_signaling_nan(b)) + m_x87_sw |= X87_SW_IE; + } + else + { + if (floatx80_eq(a, b)) + m_x87_sw |= X87_SW_C3; + + if (floatx80_lt(a, b)) + m_x87_sw |= X87_SW_C0; + } + } + + if (x87_check_exceptions()) + x87_inc_stack(); + + CYCLES(4); +} + +void i386_device::x87_fucompp(UINT8 modrm) +{ + if (X87_IS_ST_EMPTY(0) || X87_IS_ST_EMPTY(1)) + { + x87_set_stack_underflow(); + m_x87_sw |= X87_SW_C3 | X87_SW_C2 | X87_SW_C0; + } + else + { + m_x87_sw &= ~(X87_SW_C3 | X87_SW_C2 | X87_SW_C1 | X87_SW_C0); + + floatx80 a = ST(0); + floatx80 b = ST(1); + + if (floatx80_is_nan(a) || floatx80_is_nan(b)) + { + m_x87_sw |= X87_SW_C0 | X87_SW_C2 | X87_SW_C3; + + if (floatx80_is_signaling_nan(a) || floatx80_is_signaling_nan(b)) + m_x87_sw |= X87_SW_IE; + } + else + { + if (floatx80_eq(a, b)) + m_x87_sw |= X87_SW_C3; + + if (floatx80_lt(a, b)) + m_x87_sw |= X87_SW_C0; + } + } + + if (x87_check_exceptions()) + { + x87_inc_stack(); + x87_inc_stack(); + } + + CYCLES(4); +} + + +/************************************* + * + * Control + * + *************************************/ + +void i386_device::x87_fdecstp(UINT8 modrm) +{ + m_x87_sw &= ~X87_SW_C1; + + x87_dec_stack(); + x87_check_exceptions(); + + CYCLES(3); +} + +void i386_device::x87_fincstp(UINT8 modrm) +{ + m_x87_sw &= ~X87_SW_C1; + + x87_inc_stack(); + x87_check_exceptions(); + + CYCLES(3); +} + +void i386_device::x87_fclex(UINT8 modrm) +{ + m_x87_sw &= ~0x80ff; + + CYCLES(7); +} + +void i386_device::x87_ffree(UINT8 modrm) +{ + x87_set_tag(ST_TO_PHYS(modrm & 7), X87_TW_EMPTY); + + CYCLES(3); +} + +void i386_device::x87_finit(UINT8 modrm) +{ + x87_reset(); + + CYCLES(17); +} + +void i386_device::x87_fldcw(UINT8 modrm) +{ + UINT32 ea = GetEA(modrm, 0); + UINT16 cw = READ16(ea); + + x87_write_cw(cw); + + x87_check_exceptions(); + + CYCLES(4); +} + +void i386_device::x87_fstcw(UINT8 modrm) +{ + UINT32 ea = GetEA(modrm, 1); + WRITE16(ea, m_x87_cw); + + CYCLES(3); +} + +void i386_device::x87_fldenv(UINT8 modrm) +{ + // TODO: Pointers and selectors + UINT32 ea = GetEA(modrm, 0); + + if (m_operand_size) + { + // 32-bit real/protected mode + x87_write_cw(READ16(ea)); + m_x87_sw = READ16(ea + 4); + m_x87_tw = READ16(ea + 8); + } + else + { + // 16-bit real/protected mode + x87_write_cw(READ16(ea)); + m_x87_sw = READ16(ea + 2); + m_x87_tw = READ16(ea + 4); + } + + x87_check_exceptions(); + + CYCLES((m_cr[0] & 1) ? 34 : 44); +} + +void i386_device::x87_fstenv(UINT8 modrm) +{ + UINT32 ea = GetEA(modrm, 1); + + // TODO: Pointers and selectors + switch((m_cr[0] & 1)|(m_operand_size & 1)<<1) + { + case 0: // 16-bit real mode + WRITE16(ea + 0, m_x87_cw); + WRITE16(ea + 2, m_x87_sw); + WRITE16(ea + 4, m_x87_tw); +// WRITE16(ea + 6, m_fpu_inst_ptr & 0xffff); +// WRITE16(ea + 8, (m_fpu_opcode & 0x07ff) | ((m_fpu_inst_ptr & 0x0f0000) >> 4)); +// WRITE16(ea + 10, m_fpu_data_ptr & 0xffff); +// WRITE16(ea + 12, (m_fpu_inst_ptr & 0x0f0000) >> 4); + break; + case 1: // 16-bit protected mode + WRITE16(ea + 0, m_x87_cw); + WRITE16(ea + 2, m_x87_sw); + WRITE16(ea + 4, m_x87_tw); +// WRITE16(ea + 6, m_fpu_inst_ptr & 0xffff); +// WRITE16(ea + 8, (m_fpu_opcode & 0x07ff) | ((m_fpu_inst_ptr & 0x0f0000) >> 4)); +// WRITE16(ea + 10, m_fpu_data_ptr & 0xffff); +// WRITE16(ea + 12, (m_fpu_inst_ptr & 0x0f0000) >> 4); + break; + case 2: // 32-bit real mode + WRITE16(ea + 0, m_x87_cw); + WRITE16(ea + 4, m_x87_sw); + WRITE16(ea + 8, m_x87_tw); +// WRITE16(ea + 12, m_fpu_inst_ptr & 0xffff); +// WRITE16(ea + 8, (m_fpu_opcode & 0x07ff) | ((m_fpu_inst_ptr & 0x0f0000) >> 4)); +// WRITE16(ea + 20, m_fpu_data_ptr & 0xffff); +// WRITE16(ea + 12, ((m_fpu_inst_ptr & 0x0f0000) >> 4)); +// WRITE32(ea + 24, (m_fpu_data_ptr >> 16) << 12); + break; + case 3: // 32-bit protected mode + WRITE16(ea + 0, m_x87_cw); + WRITE16(ea + 4, m_x87_sw); + WRITE16(ea + 8, m_x87_tw); +// WRITE32(ea + 12, m_fpu_inst_ptr); +// WRITE32(ea + 16, m_fpu_opcode); +// WRITE32(ea + 20, m_fpu_data_ptr); +// WRITE32(ea + 24, m_fpu_inst_ptr); + break; + } + + CYCLES((m_cr[0] & 1) ? 56 : 67); +} + +void i386_device::x87_fsave(UINT8 modrm) +{ + UINT32 ea = GetEA(modrm, 1); + + // TODO: Pointers and selectors + switch((m_cr[0] & 1)|(m_operand_size & 1)<<1) + { + case 0: // 16-bit real mode + WRITE16(ea + 0, m_x87_cw); + WRITE16(ea + 2, m_x87_sw); + WRITE16(ea + 4, m_x87_tw); +// WRITE16(ea + 6, m_fpu_inst_ptr & 0xffff); +// WRITE16(ea + 8, (m_fpu_opcode & 0x07ff) | ((m_fpu_inst_ptr & 0x0f0000) >> 4)); +// WRITE16(ea + 10, m_fpu_data_ptr & 0xffff); +// WRITE16(ea + 12, (m_fpu_inst_ptr & 0x0f0000) >> 4); + ea += 14; + break; + case 1: // 16-bit protected mode + WRITE16(ea + 0, m_x87_cw); + WRITE16(ea + 2, m_x87_sw); + WRITE16(ea + 4, m_x87_tw); +// WRITE16(ea + 6, m_fpu_inst_ptr & 0xffff); +// WRITE16(ea + 8, (m_fpu_opcode & 0x07ff) | ((m_fpu_inst_ptr & 0x0f0000) >> 4)); +// WRITE16(ea + 10, m_fpu_data_ptr & 0xffff); +// WRITE16(ea + 12, (m_fpu_inst_ptr & 0x0f0000) >> 4); + ea += 14; + break; + case 2: // 32-bit real mode + WRITE16(ea + 0, m_x87_cw); + WRITE16(ea + 4, m_x87_sw); + WRITE16(ea + 8, m_x87_tw); +// WRITE16(ea + 12, m_fpu_inst_ptr & 0xffff); +// WRITE16(ea + 8, (m_fpu_opcode & 0x07ff) | ((m_fpu_inst_ptr & 0x0f0000) >> 4)); +// WRITE16(ea + 20, m_fpu_data_ptr & 0xffff); +// WRITE16(ea + 12, ((m_fpu_inst_ptr & 0x0f0000) >> 4)); +// WRITE32(ea + 24, (m_fpu_data_ptr >> 16) << 12); + ea += 28; + break; + case 3: // 32-bit protected mode + WRITE16(ea + 0, m_x87_cw); + WRITE16(ea + 4, m_x87_sw); + WRITE16(ea + 8, m_x87_tw); +// WRITE32(ea + 12, m_fpu_inst_ptr); +// WRITE32(ea + 16, m_fpu_opcode); +// WRITE32(ea + 20, m_fpu_data_ptr); +// WRITE32(ea + 24, m_fpu_inst_ptr); + ea += 28; + break; + } + + for (int i = 0; i < 8; ++i) + WRITE80(ea + i*10, ST(i)); + + CYCLES((m_cr[0] & 1) ? 56 : 67); +} + +void i386_device::x87_frstor(UINT8 modrm) +{ + UINT32 ea = GetEA(modrm, 0); + + // TODO: Pointers and selectors + switch((m_cr[0] & 1)|(m_operand_size & 1)<<1) + { + case 0: // 16-bit real mode + x87_write_cw(READ16(ea)); + m_x87_sw = READ16(ea + 2); + m_x87_tw = READ16(ea + 4); +// WRITE16(ea + 6, m_fpu_inst_ptr & 0xffff); +// WRITE16(ea + 8, (m_fpu_opcode & 0x07ff) | ((m_fpu_inst_ptr & 0x0f0000) >> 4)); +// WRITE16(ea + 10, m_fpu_data_ptr & 0xffff); +// WRITE16(ea + 12, (m_fpu_inst_ptr & 0x0f0000) >> 4); + ea += 14; + break; + case 1: // 16-bit protected mode + x87_write_cw(READ16(ea)); + m_x87_sw = READ16(ea + 2); + m_x87_tw = READ16(ea + 4); +// WRITE16(ea + 6, m_fpu_inst_ptr & 0xffff); +// WRITE16(ea + 8, (m_fpu_opcode & 0x07ff) | ((m_fpu_inst_ptr & 0x0f0000) >> 4)); +// WRITE16(ea + 10, m_fpu_data_ptr & 0xffff); +// WRITE16(ea + 12, (m_fpu_inst_ptr & 0x0f0000) >> 4); + ea += 14; + break; + case 2: // 32-bit real mode + x87_write_cw(READ16(ea)); + m_x87_sw = READ16(ea + 4); + m_x87_tw = READ16(ea + 8); +// WRITE16(ea + 12, m_fpu_inst_ptr & 0xffff); +// WRITE16(ea + 8, (m_fpu_opcode & 0x07ff) | ((m_fpu_inst_ptr & 0x0f0000) >> 4)); +// WRITE16(ea + 20, m_fpu_data_ptr & 0xffff); +// WRITE16(ea + 12, ((m_fpu_inst_ptr & 0x0f0000) >> 4)); +// WRITE32(ea + 24, (m_fpu_data_ptr >> 16) << 12); + ea += 28; + break; + case 3: // 32-bit protected mode + x87_write_cw(READ16(ea)); + m_x87_sw = READ16(ea + 4); + m_x87_tw = READ16(ea + 8); +// WRITE32(ea + 12, m_fpu_inst_ptr); +// WRITE32(ea + 16, m_fpu_opcode); +// WRITE32(ea + 20, m_fpu_data_ptr); +// WRITE32(ea + 24, m_fpu_inst_ptr); + ea += 28; + break; + } + + for (int i = 0; i < 8; ++i) + x87_write_stack(i, READ80(ea + i*10), FALSE); + + CYCLES((m_cr[0] & 1) ? 34 : 44); +} + +void i386_device::x87_fxch(UINT8 modrm) +{ + if (X87_IS_ST_EMPTY(0) || X87_IS_ST_EMPTY(1)) + x87_set_stack_underflow(); + + if (x87_check_exceptions()) + { + floatx80 tmp = ST(0); + ST(0) = ST(1); + ST(1) = tmp; + + // Swap the tags + int tag0 = X87_TAG(ST_TO_PHYS(0)); + x87_set_tag(ST_TO_PHYS(0), X87_TAG(ST_TO_PHYS(1))); + x87_set_tag(ST_TO_PHYS(1), tag0); + } + + CYCLES(4); +} + +void i386_device::x87_fxch_sti(UINT8 modrm) +{ + int i = modrm & 7; + + if (X87_IS_ST_EMPTY(0)) + { + ST(0) = fx80_inan; + x87_set_tag(ST_TO_PHYS(0), X87_TW_SPECIAL); + x87_set_stack_underflow(); + } + if (X87_IS_ST_EMPTY(i)) + { + ST(i) = fx80_inan; + x87_set_tag(ST_TO_PHYS(i), X87_TW_SPECIAL); + x87_set_stack_underflow(); + } + + if (x87_check_exceptions()) + { + floatx80 tmp = ST(0); + ST(0) = ST(i); + ST(i) = tmp; + + // Swap the tags + int tag0 = X87_TAG(ST_TO_PHYS(0)); + x87_set_tag(ST_TO_PHYS(0), X87_TAG(ST_TO_PHYS(i))); + x87_set_tag(ST_TO_PHYS(i), tag0); + } + + CYCLES(4); +} + +void i386_device::x87_fstsw_ax(UINT8 modrm) +{ + REG16(AX) = m_x87_sw; + + CYCLES(3); +} + +void i386_device::x87_fstsw_m2byte(UINT8 modrm) +{ + UINT32 ea = GetEA(modrm, 1); + + WRITE16(ea, m_x87_sw); + + CYCLES(3); +} + +void i386_device::x87_invalid(UINT8 modrm) +{ + // TODO + fatalerror("x87 invalid instruction (PC:%.4x)\n", m_pc); +} + + + +/************************************* + * + * Instruction dispatch + * + *************************************/ + +void i386_device::i386_x87_group_d8() +{ + UINT8 modrm = FETCH(); + (this->*m_opcode_table_x87_d8[modrm])(modrm); +} + +void i386_device::i386_x87_group_d9() +{ + UINT8 modrm = FETCH(); + (this->*m_opcode_table_x87_d9[modrm])(modrm); +} + +void i386_device::i386_x87_group_da() +{ + UINT8 modrm = FETCH(); + (this->*m_opcode_table_x87_da[modrm])(modrm); +} + +void i386_device::i386_x87_group_db() +{ + UINT8 modrm = FETCH(); + (this->*m_opcode_table_x87_db[modrm])(modrm); +} + +void i386_device::i386_x87_group_dc() +{ + UINT8 modrm = FETCH(); + (this->*m_opcode_table_x87_dc[modrm])(modrm); +} + +void i386_device::i386_x87_group_dd() +{ + UINT8 modrm = FETCH(); + (this->*m_opcode_table_x87_dd[modrm])(modrm); +} + +void i386_device::i386_x87_group_de() +{ + UINT8 modrm = FETCH(); + (this->*m_opcode_table_x87_de[modrm])(modrm); +} + +void i386_device::i386_x87_group_df() +{ + UINT8 modrm = FETCH(); + (this->*m_opcode_table_x87_df[modrm])(modrm); +} + + +/************************************* + * + * Opcode table building + * + *************************************/ + +void i386_device::build_x87_opcode_table_d8() +{ + int modrm = 0; + + for (modrm = 0; modrm < 0x100; ++modrm) + { + i386_modrm_func ptr = &i386_device::x87_invalid; + + if (modrm < 0xc0) + { + switch ((modrm >> 3) & 0x7) + { + case 0x00: ptr = &i386_device::x87_fadd_m32real; break; + case 0x01: ptr = &i386_device::x87_fmul_m32real; break; + case 0x02: ptr = &i386_device::x87_fcom_m32real; break; + case 0x03: ptr = &i386_device::x87_fcomp_m32real; break; + case 0x04: ptr = &i386_device::x87_fsub_m32real; break; + case 0x05: ptr = &i386_device::x87_fsubr_m32real; break; + case 0x06: ptr = &i386_device::x87_fdiv_m32real; break; + case 0x07: ptr = &i386_device::x87_fdivr_m32real; break; + } + } + else + { + switch (modrm) + { + case 0xc0: case 0xc1: case 0xc2: case 0xc3: case 0xc4: case 0xc5: case 0xc6: case 0xc7: ptr = &i386_device::x87_fadd_st_sti; break; + case 0xc8: case 0xc9: case 0xca: case 0xcb: case 0xcc: case 0xcd: case 0xce: case 0xcf: ptr = &i386_device::x87_fmul_st_sti; break; + case 0xd0: case 0xd1: case 0xd2: case 0xd3: case 0xd4: case 0xd5: case 0xd6: case 0xd7: ptr = &i386_device::x87_fcom_sti; break; + case 0xd8: case 0xd9: case 0xda: case 0xdb: case 0xdc: case 0xdd: case 0xde: case 0xdf: ptr = &i386_device::x87_fcomp_sti; break; + case 0xe0: case 0xe1: case 0xe2: case 0xe3: case 0xe4: case 0xe5: case 0xe6: case 0xe7: ptr = &i386_device::x87_fsub_st_sti; break; + case 0xe8: case 0xe9: case 0xea: case 0xeb: case 0xec: case 0xed: case 0xee: case 0xef: ptr = &i386_device::x87_fsubr_st_sti; break; + case 0xf0: case 0xf1: case 0xf2: case 0xf3: case 0xf4: case 0xf5: case 0xf6: case 0xf7: ptr = &i386_device::x87_fdiv_st_sti; break; + case 0xf8: case 0xf9: case 0xfa: case 0xfb: case 0xfc: case 0xfd: case 0xfe: case 0xff: ptr = &i386_device::x87_fdivr_st_sti; break; + } + } + + m_opcode_table_x87_d8[modrm] = ptr; + } +} + + +void i386_device::build_x87_opcode_table_d9() +{ + int modrm = 0; + + for (modrm = 0; modrm < 0x100; ++modrm) + { + i386_modrm_func ptr = &i386_device::x87_invalid; + + if (modrm < 0xc0) + { + switch ((modrm >> 3) & 0x7) + { + case 0x00: ptr = &i386_device::x87_fld_m32real; break; + case 0x02: ptr = &i386_device::x87_fst_m32real; break; + case 0x03: ptr = &i386_device::x87_fstp_m32real; break; + case 0x04: ptr = &i386_device::x87_fldenv; break; + case 0x05: ptr = &i386_device::x87_fldcw; break; + case 0x06: ptr = &i386_device::x87_fstenv; break; + case 0x07: ptr = &i386_device::x87_fstcw; break; + } + } + else + { + switch (modrm) + { + case 0xc0: + case 0xc1: + case 0xc2: + case 0xc3: + case 0xc4: + case 0xc5: + case 0xc6: + case 0xc7: ptr = &i386_device::x87_fld_sti; break; + + case 0xc8: + case 0xc9: + case 0xca: + case 0xcb: + case 0xcc: + case 0xcd: + case 0xce: + case 0xcf: ptr = &i386_device::x87_fxch_sti; break; + + case 0xd0: ptr = &i386_device::x87_fnop; break; + case 0xe0: ptr = &i386_device::x87_fchs; break; + case 0xe1: ptr = &i386_device::x87_fabs; break; + case 0xe4: ptr = &i386_device::x87_ftst; break; + case 0xe5: ptr = &i386_device::x87_fxam; break; + case 0xe8: ptr = &i386_device::x87_fld1; break; + case 0xe9: ptr = &i386_device::x87_fldl2t; break; + case 0xea: ptr = &i386_device::x87_fldl2e; break; + case 0xeb: ptr = &i386_device::x87_fldpi; break; + case 0xec: ptr = &i386_device::x87_fldlg2; break; + case 0xed: ptr = &i386_device::x87_fldln2; break; + case 0xee: ptr = &i386_device::x87_fldz; break; + case 0xf0: ptr = &i386_device::x87_f2xm1; break; + case 0xf1: ptr = &i386_device::x87_fyl2x; break; + case 0xf2: ptr = &i386_device::x87_fptan; break; + case 0xf3: ptr = &i386_device::x87_fpatan; break; + case 0xf4: ptr = &i386_device::x87_fxtract; break; + case 0xf5: ptr = &i386_device::x87_fprem1; break; + case 0xf6: ptr = &i386_device::x87_fdecstp; break; + case 0xf7: ptr = &i386_device::x87_fincstp; break; + case 0xf8: ptr = &i386_device::x87_fprem; break; + case 0xf9: ptr = &i386_device::x87_fyl2xp1; break; + case 0xfa: ptr = &i386_device::x87_fsqrt; break; + case 0xfb: ptr = &i386_device::x87_fsincos; break; + case 0xfc: ptr = &i386_device::x87_frndint; break; + case 0xfd: ptr = &i386_device::x87_fscale; break; + case 0xfe: ptr = &i386_device::x87_fsin; break; + case 0xff: ptr = &i386_device::x87_fcos; break; + } + } + + m_opcode_table_x87_d9[modrm] = ptr; + } +} + +void i386_device::build_x87_opcode_table_da() +{ + int modrm = 0; + + for (modrm = 0; modrm < 0x100; ++modrm) + { + i386_modrm_func ptr = &i386_device::x87_invalid; + + if (modrm < 0xc0) + { + switch ((modrm >> 3) & 0x7) + { + case 0x00: ptr = &i386_device::x87_fiadd_m32int; break; + case 0x01: ptr = &i386_device::x87_fimul_m32int; break; + case 0x02: ptr = &i386_device::x87_ficom_m32int; break; + case 0x03: ptr = &i386_device::x87_ficomp_m32int; break; + case 0x04: ptr = &i386_device::x87_fisub_m32int; break; + case 0x05: ptr = &i386_device::x87_fisubr_m32int; break; + case 0x06: ptr = &i386_device::x87_fidiv_m32int; break; + case 0x07: ptr = &i386_device::x87_fidivr_m32int; break; + } + } + else + { + switch (modrm) + { + case 0xc0: case 0xc1: case 0xc2: case 0xc3: case 0xc4: case 0xc5: case 0xc6: case 0xc7: ptr = &i386_device::x87_fcmovb_sti; break; + case 0xc8: case 0xc9: case 0xca: case 0xcb: case 0xcc: case 0xcd: case 0xce: case 0xcf: ptr = &i386_device::x87_fcmove_sti; break; + case 0xd0: case 0xd1: case 0xd2: case 0xd3: case 0xd4: case 0xd5: case 0xd6: case 0xd7: ptr = &i386_device::x87_fcmovbe_sti; break; + case 0xd8: case 0xd9: case 0xda: case 0xdb: case 0xdc: case 0xdd: case 0xde: case 0xdf: ptr = &i386_device::x87_fcmovu_sti; break; + case 0xe9: ptr = &i386_device::x87_fucompp; break; + } + } + + m_opcode_table_x87_da[modrm] = ptr; + } +} + + +void i386_device::build_x87_opcode_table_db() +{ + int modrm = 0; + + for (modrm = 0; modrm < 0x100; ++modrm) + { + i386_modrm_func ptr = &i386_device::x87_invalid; + + if (modrm < 0xc0) + { + switch ((modrm >> 3) & 0x7) + { + case 0x00: ptr = &i386_device::x87_fild_m32int; break; + case 0x02: ptr = &i386_device::x87_fist_m32int; break; + case 0x03: ptr = &i386_device::x87_fistp_m32int; break; + case 0x05: ptr = &i386_device::x87_fld_m80real; break; + case 0x07: ptr = &i386_device::x87_fstp_m80real; break; + } + } + else + { + switch (modrm) + { + case 0xc0: case 0xc1: case 0xc2: case 0xc3: case 0xc4: case 0xc5: case 0xc6: case 0xc7: ptr = &i386_device::x87_fcmovnb_sti; break; + case 0xc8: case 0xc9: case 0xca: case 0xcb: case 0xcc: case 0xcd: case 0xce: case 0xcf: ptr = &i386_device::x87_fcmovne_sti; break; + case 0xd0: case 0xd1: case 0xd2: case 0xd3: case 0xd4: case 0xd5: case 0xd6: case 0xd7: ptr = &i386_device::x87_fcmovnbe_sti; break; + case 0xd8: case 0xd9: case 0xda: case 0xdb: case 0xdc: case 0xdd: case 0xde: case 0xdf: ptr = &i386_device::x87_fcmovnu_sti; break; + case 0xe0: ptr = &i386_device::x87_fnop; break; /* FENI */ + case 0xe1: ptr = &i386_device::x87_fnop; break; /* FDISI */ + case 0xe2: ptr = &i386_device::x87_fclex; break; + case 0xe3: ptr = &i386_device::x87_finit; break; + case 0xe4: ptr = &i386_device::x87_fnop; break; /* FSETPM */ + case 0xe8: case 0xe9: case 0xea: case 0xeb: case 0xec: case 0xed: case 0xee: case 0xef: ptr = &i386_device::x87_fucomi_sti; break; + case 0xf0: case 0xf1: case 0xf2: case 0xf3: case 0xf4: case 0xf5: case 0xf6: case 0xf7: ptr = &i386_device::x87_fcomi_sti; break; + } + } + + m_opcode_table_x87_db[modrm] = ptr; + } +} + + +void i386_device::build_x87_opcode_table_dc() +{ + int modrm = 0; + + for (modrm = 0; modrm < 0x100; ++modrm) + { + i386_modrm_func ptr = &i386_device::x87_invalid; + + if (modrm < 0xc0) + { + switch ((modrm >> 3) & 0x7) + { + case 0x00: ptr = &i386_device::x87_fadd_m64real; break; + case 0x01: ptr = &i386_device::x87_fmul_m64real; break; + case 0x02: ptr = &i386_device::x87_fcom_m64real; break; + case 0x03: ptr = &i386_device::x87_fcomp_m64real; break; + case 0x04: ptr = &i386_device::x87_fsub_m64real; break; + case 0x05: ptr = &i386_device::x87_fsubr_m64real; break; + case 0x06: ptr = &i386_device::x87_fdiv_m64real; break; + case 0x07: ptr = &i386_device::x87_fdivr_m64real; break; + } + } + else + { + switch (modrm) + { + case 0xc0: case 0xc1: case 0xc2: case 0xc3: case 0xc4: case 0xc5: case 0xc6: case 0xc7: ptr = &i386_device::x87_fadd_sti_st; break; + case 0xc8: case 0xc9: case 0xca: case 0xcb: case 0xcc: case 0xcd: case 0xce: case 0xcf: ptr = &i386_device::x87_fmul_sti_st; break; + case 0xe0: case 0xe1: case 0xe2: case 0xe3: case 0xe4: case 0xe5: case 0xe6: case 0xe7: ptr = &i386_device::x87_fsubr_sti_st; break; + case 0xe8: case 0xe9: case 0xea: case 0xeb: case 0xec: case 0xed: case 0xee: case 0xef: ptr = &i386_device::x87_fsub_sti_st; break; + case 0xf0: case 0xf1: case 0xf2: case 0xf3: case 0xf4: case 0xf5: case 0xf6: case 0xf7: ptr = &i386_device::x87_fdivr_sti_st; break; + case 0xf8: case 0xf9: case 0xfa: case 0xfb: case 0xfc: case 0xfd: case 0xfe: case 0xff: ptr = &i386_device::x87_fdiv_sti_st; break; + } + } + + m_opcode_table_x87_dc[modrm] = ptr; + } +} + + +void i386_device::build_x87_opcode_table_dd() +{ + int modrm = 0; + + for (modrm = 0; modrm < 0x100; ++modrm) + { + i386_modrm_func ptr = &i386_device::x87_invalid; + + if (modrm < 0xc0) + { + switch ((modrm >> 3) & 0x7) + { + case 0x00: ptr = &i386_device::x87_fld_m64real; break; + case 0x02: ptr = &i386_device::x87_fst_m64real; break; + case 0x03: ptr = &i386_device::x87_fstp_m64real; break; + case 0x04: ptr = &i386_device::x87_frstor; break; + case 0x06: ptr = &i386_device::x87_fsave; break; + case 0x07: ptr = &i386_device::x87_fstsw_m2byte; break; + } + } + else + { + switch (modrm) + { + case 0xc0: case 0xc1: case 0xc2: case 0xc3: case 0xc4: case 0xc5: case 0xc6: case 0xc7: ptr = &i386_device::x87_ffree; break; + case 0xc8: case 0xc9: case 0xca: case 0xcb: case 0xcc: case 0xcd: case 0xce: case 0xcf: ptr = &i386_device::x87_fxch_sti; break; + case 0xd0: case 0xd1: case 0xd2: case 0xd3: case 0xd4: case 0xd5: case 0xd6: case 0xd7: ptr = &i386_device::x87_fst_sti; break; + case 0xd8: case 0xd9: case 0xda: case 0xdb: case 0xdc: case 0xdd: case 0xde: case 0xdf: ptr = &i386_device::x87_fstp_sti; break; + case 0xe0: case 0xe1: case 0xe2: case 0xe3: case 0xe4: case 0xe5: case 0xe6: case 0xe7: ptr = &i386_device::x87_fucom_sti; break; + case 0xe8: case 0xe9: case 0xea: case 0xeb: case 0xec: case 0xed: case 0xee: case 0xef: ptr = &i386_device::x87_fucomp_sti; break; + } + } + + m_opcode_table_x87_dd[modrm] = ptr; + } +} + + +void i386_device::build_x87_opcode_table_de() +{ + int modrm = 0; + + for (modrm = 0; modrm < 0x100; ++modrm) + { + i386_modrm_func ptr = &i386_device::x87_invalid; + + if (modrm < 0xc0) + { + switch ((modrm >> 3) & 0x7) + { + case 0x00: ptr = &i386_device::x87_fiadd_m16int; break; + case 0x01: ptr = &i386_device::x87_fimul_m16int; break; + case 0x02: ptr = &i386_device::x87_ficom_m16int; break; + case 0x03: ptr = &i386_device::x87_ficomp_m16int; break; + case 0x04: ptr = &i386_device::x87_fisub_m16int; break; + case 0x05: ptr = &i386_device::x87_fisubr_m16int; break; + case 0x06: ptr = &i386_device::x87_fidiv_m16int; break; + case 0x07: ptr = &i386_device::x87_fidivr_m16int; break; + } + } + else + { + switch (modrm) + { + case 0xc0: case 0xc1: case 0xc2: case 0xc3: case 0xc4: case 0xc5: case 0xc6: case 0xc7: ptr = &i386_device::x87_faddp; break; + case 0xc8: case 0xc9: case 0xca: case 0xcb: case 0xcc: case 0xcd: case 0xce: case 0xcf: ptr = &i386_device::x87_fmulp; break; + case 0xd9: ptr = &i386_device::x87_fcompp; break; + case 0xe0: case 0xe1: case 0xe2: case 0xe3: case 0xe4: case 0xe5: case 0xe6: case 0xe7: ptr = &i386_device::x87_fsubrp; break; + case 0xe8: case 0xe9: case 0xea: case 0xeb: case 0xec: case 0xed: case 0xee: case 0xef: ptr = &i386_device::x87_fsubp; break; + case 0xf0: case 0xf1: case 0xf2: case 0xf3: case 0xf4: case 0xf5: case 0xf6: case 0xf7: ptr = &i386_device::x87_fdivrp; break; + case 0xf8: case 0xf9: case 0xfa: case 0xfb: case 0xfc: case 0xfd: case 0xfe: case 0xff: ptr = &i386_device::x87_fdivp; break; + } + } + + m_opcode_table_x87_de[modrm] = ptr; + } +} + + +void i386_device::build_x87_opcode_table_df() +{ + int modrm = 0; + + for (modrm = 0; modrm < 0x100; ++modrm) + { + i386_modrm_func ptr = &i386_device::x87_invalid; + + if (modrm < 0xc0) + { + switch ((modrm >> 3) & 0x7) + { + case 0x00: ptr = &i386_device::x87_fild_m16int; break; + case 0x02: ptr = &i386_device::x87_fist_m16int; break; + case 0x03: ptr = &i386_device::x87_fistp_m16int; break; + case 0x04: ptr = &i386_device::x87_fbld; break; + case 0x05: ptr = &i386_device::x87_fild_m64int; break; + case 0x06: ptr = &i386_device::x87_fbstp; break; + case 0x07: ptr = &i386_device::x87_fistp_m64int; break; + } + } + else + { + switch (modrm) + { + case 0xe0: ptr = &i386_device::x87_fstsw_ax; break; + case 0xe8: case 0xe9: case 0xea: case 0xeb: case 0xec: case 0xed: case 0xee: case 0xef: ptr = &i386_device::x87_fucomip_sti; break; + case 0xf0: case 0xf1: case 0xf2: case 0xf3: case 0xf4: case 0xf5: case 0xf6: case 0xf7: ptr = &i386_device::x87_fcomip_sti; break; + } + } + + m_opcode_table_x87_df[modrm] = ptr; + } +} + +void i386_device::build_x87_opcode_table() +{ + build_x87_opcode_table_d8(); + build_x87_opcode_table_d9(); + build_x87_opcode_table_da(); + build_x87_opcode_table_db(); + build_x87_opcode_table_dc(); + build_x87_opcode_table_dd(); + build_x87_opcode_table_de(); + build_x87_opcode_table_df(); +} diff --git a/src/devices/cpu/i4004/4004dasm.c b/src/devices/cpu/i4004/4004dasm.c new file mode 100644 index 00000000000..2e76c14b3b5 --- /dev/null +++ b/src/devices/cpu/i4004/4004dasm.c @@ -0,0 +1,133 @@ +// license:BSD-3-Clause +// copyright-holders:Miodrag Milanovic +/***************************************************************************** + * + * 4004dasm.c + * + * Intel 4004 CPU Disassembly + * + *****************************************************************************/ + +#include "emu.h" + +#define OP(A) oprom[(A) - PC] +#define ARG(A) opram[(A) - PC] + +CPU_DISASSEMBLE( i4004 ) +{ + UINT32 flags = 0; + UINT8 op; + unsigned PC = pc; + UINT16 page = PC & 0x0f00; + switch (op = OP(pc++)) + { + case 0x00: sprintf (buffer,"nop"); break; + case 0x11: sprintf (buffer,"jnt $%03x",page | ARG(pc)); pc++; break; + case 0x12: sprintf (buffer,"jc $%03x",page | ARG(pc)); pc++; break; + case 0x14: sprintf (buffer,"jz $%03x",page | ARG(pc)); pc++; break; + case 0x19: sprintf (buffer,"jt $%03x",page | ARG(pc)); pc++; break; + case 0x1a: sprintf (buffer,"jnc $%03x",page | ARG(pc)); pc++; break; + case 0x1c: sprintf (buffer,"jnz $%03x",page | ARG(pc)); pc++; break; + case 0x10: case 0x13: case 0x15: case 0x16: + case 0x17: case 0x18: case 0x1b: case 0x1d: + case 0x1e: case 0x1f: + sprintf (buffer,"jcn $%01x,$%03x",op & 0x0f,page | ARG(pc)); pc++; break; + case 0x20: case 0x22: case 0x24: case 0x26: + case 0x28: case 0x2a: case 0x2c: case 0x2e: + sprintf (buffer,"fim $%01x,$%02x",op & 0x0f,OP(pc)); pc++; break; + case 0x21: case 0x23: case 0x25: case 0x27: + case 0x29: case 0x2b: case 0x2d: case 0x2f: + sprintf (buffer,"src $%01x",(op & 0x0f)-1); break; + case 0x30: case 0x32: case 0x34: case 0x36: + case 0x38: case 0x3a: case 0x3c: case 0x3e: + sprintf (buffer,"fin $%01x",op & 0x0f); break; + case 0x31: case 0x33: case 0x35: case 0x37: + case 0x39: case 0x3b: case 0x3d: case 0x3f: + sprintf (buffer,"jin $%01x",(op & 0x0f)-1); break; + case 0x40: case 0x41: case 0x42: case 0x43: + case 0x44: case 0x45: case 0x46: case 0x47: + case 0x48: case 0x49: case 0x4a: case 0x4b: + case 0x4c: case 0x4d: case 0x4e: case 0x4f: + sprintf (buffer,"jun $%01x%02x",op & 0x0f,ARG(pc)); pc++; break; + case 0x50: case 0x51: case 0x52: case 0x53: + case 0x54: case 0x55: case 0x56: case 0x57: + case 0x58: case 0x59: case 0x5a: case 0x5b: + case 0x5c: case 0x5d: case 0x5e: case 0x5f: + sprintf (buffer,"jms $%01x%02x",op & 0x0f,ARG(pc)); pc++; break; + case 0x60: case 0x61: case 0x62: case 0x63: + case 0x64: case 0x65: case 0x66: case 0x67: + case 0x68: case 0x69: case 0x6a: case 0x6b: + case 0x6c: case 0x6d: case 0x6e: case 0x6f: + sprintf (buffer,"inc $%01x",op & 0x0f); break; + case 0x70: case 0x71: case 0x72: case 0x73: + case 0x74: case 0x75: case 0x76: case 0x77: + case 0x78: case 0x79: case 0x7a: case 0x7b: + case 0x7c: case 0x7d: case 0x7e: case 0x7f: + sprintf (buffer,"isz $%01x,%03x",op & 0x0f,page | ARG(pc)); pc++; break; + case 0x80: case 0x81: case 0x82: case 0x83: + case 0x84: case 0x85: case 0x86: case 0x87: + case 0x88: case 0x89: case 0x8a: case 0x8b: + case 0x8c: case 0x8d: case 0x8e: case 0x8f: + sprintf (buffer,"add $%01x",op & 0x0f); break; + case 0x90: case 0x91: case 0x92: case 0x93: + case 0x94: case 0x95: case 0x96: case 0x97: + case 0x98: case 0x99: case 0x9a: case 0x9b: + case 0x9c: case 0x9d: case 0x9e: case 0x9f: + sprintf (buffer,"sub $%01x",op & 0x0f); break; + case 0xa0: case 0xa1: case 0xa2: case 0xa3: + case 0xa4: case 0xa5: case 0xa6: case 0xa7: + case 0xa8: case 0xa9: case 0xaa: case 0xab: + case 0xac: case 0xad: case 0xae: case 0xaf: + sprintf (buffer,"ld $%01x",op & 0x0f); break; + case 0xb0: case 0xb1: case 0xb2: case 0xb3: + case 0xb4: case 0xb5: case 0xb6: case 0xb7: + case 0xb8: case 0xb9: case 0xba: case 0xbb: + case 0xbc: case 0xbd: case 0xbe: case 0xbf: + sprintf (buffer,"xch $%01x",op & 0x0f); break; + case 0xc0: case 0xc1: case 0xc2: case 0xc3: + case 0xc4: case 0xc5: case 0xc6: case 0xc7: + case 0xc8: case 0xc9: case 0xca: case 0xcb: + case 0xcc: case 0xcd: case 0xce: case 0xcf: + sprintf (buffer,"bbl $%01x",op & 0x0f); break; + case 0xd0: case 0xd1: case 0xd2: case 0xd3: + case 0xd4: case 0xd5: case 0xd6: case 0xd7: + case 0xd8: case 0xd9: case 0xda: case 0xdb: + case 0xdc: case 0xdd: case 0xde: case 0xdf: + sprintf (buffer,"ldm $%01x",op & 0x0f); break; + + case 0xe0: sprintf (buffer,"wrm"); break; + case 0xe1: sprintf (buffer,"wmp"); break; + case 0xe2: sprintf (buffer,"wrr"); break; + case 0xe3: sprintf (buffer,"wpm"); break; + case 0xe4: sprintf (buffer,"wr0"); break; + case 0xe5: sprintf (buffer,"wr1"); break; + case 0xe6: sprintf (buffer,"wr2"); break; + case 0xe7: sprintf (buffer,"wr3"); break; + case 0xe8: sprintf (buffer,"sbm"); break; + case 0xe9: sprintf (buffer,"rdm"); break; + case 0xea: sprintf (buffer,"rdr"); break; + case 0xeb: sprintf (buffer,"adm"); break; + case 0xec: sprintf (buffer,"rd0"); break; + case 0xed: sprintf (buffer,"rd1"); break; + case 0xee: sprintf (buffer,"rd2"); break; + case 0xef: sprintf (buffer,"rd3"); break; + + case 0xf0: sprintf (buffer,"clb"); break; + case 0xf1: sprintf (buffer,"clc"); break; + case 0xf2: sprintf (buffer,"iac"); break; + case 0xf3: sprintf (buffer,"cmc"); break; + case 0xf4: sprintf (buffer,"cma"); break; + case 0xf5: sprintf (buffer,"ral"); break; + case 0xf6: sprintf (buffer,"rar"); break; + case 0xf7: sprintf (buffer,"tcc"); break; + case 0xf8: sprintf (buffer,"dac"); break; + case 0xf9: sprintf (buffer,"tcs"); break; + case 0xfa: sprintf (buffer,"stc"); break; + case 0xfb: sprintf (buffer,"daa"); break; + case 0xfc: sprintf (buffer,"kbp"); break; + case 0xfd: sprintf (buffer,"dcl"); break; + + default : sprintf (buffer,"illegal"); break; + } + return (pc - PC) | flags | DASMFLAG_SUPPORTED; +} diff --git a/src/devices/cpu/i4004/i4004.c b/src/devices/cpu/i4004/i4004.c new file mode 100644 index 00000000000..c6e65cb27ee --- /dev/null +++ b/src/devices/cpu/i4004/i4004.c @@ -0,0 +1,529 @@ +// license:BSD-3-Clause +// copyright-holders:Miodrag Milanovic +/***************************************************************************** + * + * i4004.c + * + * Intel 4004 CPU + * + *****************************************************************************/ +#include "emu.h" +#include "debugger.h" +#include "i4004.h" + + +static const UINT8 kbp_table[] = { 0x00,0x01,0x02,0x0f,0x03,0x0f,0x0f,0x0f,0x04,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f }; + + +/*************************************************************************** + MACROS +***************************************************************************/ +#define GET_PC (m_ADDR[m_pc_pos]) + + +const device_type I4004 = &device_creator; + + +i4004_cpu_device::i4004_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : cpu_device(mconfig, I4004, "Intel I4004", tag, owner, clock, "i4004", __FILE__) + , m_program_config("program", ENDIANNESS_LITTLE, 8, 12, 0) + , m_io_config("io", ENDIANNESS_LITTLE, 8, 6, 0) + , m_data_config("data", ENDIANNESS_LITTLE, 8, 12, 0) +{ + m_is_octal = true; +} + + +UINT8 i4004_cpu_device::ROP() +{ + UINT8 retVal = m_direct->read_byte(GET_PC.w.l); + GET_PC.w.l = (GET_PC.w.l + 1) & 0x0fff; + m_PC = GET_PC; + return retVal; +} + +UINT8 i4004_cpu_device::READ_ROM() +{ + return m_direct->read_byte((GET_PC.w.l & 0x0f00) | m_R[0]); +} + +void i4004_cpu_device::WPM() +{ + UINT8 t = (m_program->read_byte(m_RAM.d) << 4) | m_A; + m_program->write_byte((GET_PC.w.l & 0x0f00) | m_RAM.d, t); +} + + +UINT8 i4004_cpu_device::ARG() +{ + UINT8 retVal = m_direct->read_byte(GET_PC.w.l); + GET_PC.w.l = (GET_PC.w.l + 1) & 0x0fff; + m_PC = GET_PC; + return retVal; +} + +UINT8 i4004_cpu_device::RM() +{ + return m_data->read_byte(m_RAM.d) & 0x0f; +} + +UINT8 i4004_cpu_device::RMS(UINT32 a) +{ + return m_data->read_byte((m_RAM.d & 0xff0) + a) >> 4; +} + +void i4004_cpu_device::WM(UINT8 v) +{ + UINT8 t = m_data->read_byte(m_RAM.d); + m_data->write_byte(m_RAM.d, (t & 0xf0) | v); +} + + +void i4004_cpu_device::WMP(UINT8 v) +{ + m_io->write_byte((m_RAM.d >> 6) | 0x10, v & 0x0f); +} + +void i4004_cpu_device::WMS(UINT32 a, UINT8 v) +{ + UINT8 t = m_data->read_byte((m_RAM.d & 0xff0) + a); + m_data->write_byte((m_RAM.d & 0xff0) + a, (t & 0x0f) | (v<<4)); +} + +UINT8 i4004_cpu_device::RIO() +{ + return m_io->read_byte(m_RAM.b.l >> 4) & 0x0f; +} + +void i4004_cpu_device::WIO(UINT8 v) +{ + m_io->write_byte(m_RAM.b.l >> 4, v & 0x0f); +} + +UINT8 i4004_cpu_device::GET_REG(UINT8 num) +{ + UINT8 r = m_R[num>>1]; + if (num & 1) { + return r & 0x0f; + } else { + return (r >> 4) & 0x0f; + } +} + +void i4004_cpu_device::SET_REG(UINT8 num, UINT8 val) +{ + if (num & 1) { + m_R[num>>1] = (m_R[num>>1] & 0xf0) + (val & 0x0f); + } else { + m_R[num>>1] = (m_R[num>>1] & 0x0f) + ((val & 0x0f) << 4); + } +} + +void i4004_cpu_device::PUSH_STACK() +{ + m_pc_pos = (m_pc_pos + 1) & m_addr_mask; +} + +void i4004_cpu_device::POP_STACK() +{ + m_ADDR[m_pc_pos].d = 0; + m_pc_pos = (m_pc_pos - 1) & m_addr_mask; +} + +void i4004_cpu_device::set_test(UINT8 val) +{ + m_TEST = val; +} + +void i4004_cpu_device::execute_one(int opcode) +{ + m_icount -= 8; + switch (opcode) + { + case 0x00: /* NOP */ + /* no op */ + break; + case 0x10: case 0x11: case 0x12: case 0x13: + case 0x14: case 0x15: case 0x16: case 0x17: + case 0x18: case 0x19: case 0x1a: case 0x1b: + case 0x1c: case 0x1d: case 0x1e: case 0x1f: /* JCN */ + { + UINT8 arg = ARG(); + + UINT8 C1 = BIT(opcode,3); + UINT8 C2 = BIT(opcode,2); + UINT8 C3 = BIT(opcode,1); + UINT8 C4 = BIT(opcode,0); + UINT8 JUMP = (((m_A == 0) ? 1 : 0) & C2) | ((m_C) & C3) | ((m_TEST ^ 1) & C4); + m_icount -= 8; + + if(((C1 ^ 1) & JUMP) | (C1 & (JUMP ^ 1))) { + GET_PC.w.l = (GET_PC.w.l & 0x0f00) | arg; + m_PC = GET_PC; + } + } + break; + case 0x20: case 0x22: case 0x24: case 0x26: + case 0x28: case 0x2a: case 0x2c: case 0x2e: /* FIM */ + m_icount -= 8; + m_R[(opcode & 0x0f)>>1] = ROP(); + break; + case 0x21: case 0x23: case 0x25: case 0x27: + case 0x29: case 0x2b: case 0x2d: case 0x2f: /* SRC */ + m_RAM.b.l = m_R[(opcode & 0x0f)>>1]; + break; + case 0x30: case 0x32: case 0x34: case 0x36: + case 0x38: case 0x3a: case 0x3c: case 0x3e: /* FIN */ + m_icount -= 8; + m_R[(opcode & 0x0f)>>1] = READ_ROM(); + break; + case 0x31: case 0x33: case 0x35: case 0x37: + case 0x39: case 0x3b: case 0x3d: case 0x3f: /* JIN */ + GET_PC.w.l = (GET_PC.w.l & 0x0f00) | m_R[(opcode & 0x0f)>>1]; + m_PC = GET_PC; + break; + case 0x40: case 0x41: case 0x42: case 0x43: + case 0x44: case 0x45: case 0x46: case 0x47: + case 0x48: case 0x49: case 0x4a: case 0x4b: + case 0x4c: case 0x4d: case 0x4e: case 0x4f: /* JUN */ + m_icount -= 8; + GET_PC.w.l = ((opcode & 0x0f) << 8) | ARG(); + m_PC = GET_PC; + break; + case 0x50: case 0x51: case 0x52: case 0x53: + case 0x54: case 0x55: case 0x56: case 0x57: + case 0x58: case 0x59: case 0x5a: case 0x5b: + case 0x5c: case 0x5d: case 0x5e: case 0x5f: /* JMS */ + { + UINT16 newPC = ((opcode & 0x0f) << 8) | ARG(); + m_icount -= 8; + PUSH_STACK(); + GET_PC.w.l = newPC; + m_PC = GET_PC; + } + break; + case 0x60: case 0x61: case 0x62: case 0x63: + case 0x64: case 0x65: case 0x66: case 0x67: + case 0x68: case 0x69: case 0x6a: case 0x6b: + case 0x6c: case 0x6d: case 0x6e: case 0x6f: /* INC */ + SET_REG(opcode & 0x0f, GET_REG(opcode & 0x0f) + 1); + break; + case 0x70: case 0x71: case 0x72: case 0x73: + case 0x74: case 0x75: case 0x76: case 0x77: + case 0x78: case 0x79: case 0x7a: case 0x7b: + case 0x7c: case 0x7d: case 0x7e: case 0x7f: /* ISZ */ + { + UINT8 val = (GET_REG(opcode & 0x0f) + 1) & 0xf; + UINT16 addr = ARG(); + m_icount -= 8; + SET_REG(opcode & 0x0f, val); + if (val!=0) { + GET_PC.w.l = (GET_PC.w.l & 0x0f00) | addr; + } + m_PC = GET_PC; + } + 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: /* ADD */ + { + UINT8 acc = m_A + GET_REG(opcode & 0x0f) + m_C; + m_A = acc & 0x0f; + m_C = (acc >> 4) & 1; + } + break; + case 0x90: case 0x91: case 0x92: case 0x93: + case 0x94: case 0x95: case 0x96: case 0x97: + case 0x98: case 0x99: case 0x9a: case 0x9b: + case 0x9c: case 0x9d: case 0x9e: case 0x9f: /* SUB */ + { + UINT8 acc = m_A + (GET_REG(opcode & 0x0f) ^ 0x0f) + (m_C ^ 1); + m_A = acc & 0x0f; + m_C = (acc >> 4) & 1; + } + break; + case 0xa0: case 0xa1: case 0xa2: case 0xa3: + case 0xa4: case 0xa5: case 0xa6: case 0xa7: + case 0xa8: case 0xa9: case 0xaa: case 0xab: + case 0xac: case 0xad: case 0xae: case 0xaf: /* LD */ + m_A = GET_REG(opcode & 0x0f); + break; + case 0xb0: case 0xb1: case 0xb2: case 0xb3: + case 0xb4: case 0xb5: case 0xb6: case 0xb7: + case 0xb8: case 0xb9: case 0xba: case 0xbb: + case 0xbc: case 0xbd: case 0xbe: case 0xbf: /* XCH */ + { + UINT8 temp = m_A; + m_A = GET_REG(opcode & 0x0f); + SET_REG(opcode & 0x0f, temp); + } + break; + case 0xc0: case 0xc1: case 0xc2: case 0xc3: + case 0xc4: case 0xc5: case 0xc6: case 0xc7: + case 0xc8: case 0xc9: case 0xca: case 0xcb: + case 0xcc: case 0xcd: case 0xce: case 0xcf: /* BBL */ + POP_STACK(); + m_A = opcode & 0x0f; + m_PC = GET_PC; + break; + case 0xd0: case 0xd1: case 0xd2: case 0xd3: + case 0xd4: case 0xd5: case 0xd6: case 0xd7: + case 0xd8: case 0xd9: case 0xda: case 0xdb: + case 0xdc: case 0xdd: case 0xde: case 0xdf: /* LDM */ + m_A = opcode & 0x0f; + break; + case 0xe0: /* WRM */ + WM(m_A); + break; + case 0xe1: /* WMP */ + WMP(m_A); + break; + case 0xe2: /* WRR */ + WIO(m_A); + break; + case 0xe3: /* WPM */ + WPM(); + break; + case 0xe4: /* WR0 */ + WMS(0,m_A); + break; + case 0xe5: /* WR1 */ + WMS(1,m_A); + break; + case 0xe6: /* WR2 */ + WMS(2,m_A); + break; + case 0xe7: /* WR3 */ + WMS(3,m_A); + break; + case 0xe8: /* SBM */ + m_A = m_A + (RM() ^ 0x0f) + (m_C ^ 1); + m_C = m_A >> 4; + m_A &= 0x0f; + break; + case 0xe9: /* RDM */ + m_A = RM(); + break; + case 0xea: /* RDR */ + m_A = RIO(); + break; + case 0xeb: /* ADM */ + m_A += RM() + m_C; + m_C = m_A >> 4; + m_A &= 0x0f; + break; + case 0xec: /* RD0 */ + m_A = RMS(0); + break; + case 0xed: /* RD1 */ + m_A = RMS(1); + break; + case 0xee: /* RD2 */ + m_A = RMS(2); + break; + case 0xef: /* RD3 */ + m_A = RMS(3); + break; + + case 0xf0: /* CLB */ + m_A = 0; + m_C = 0; + break; + case 0xf1: /* CLC */ + m_C = 0; + break; + case 0xf2: /* IAC */ + m_A += 1; + m_C = m_A >> 4; + m_A &= 0x0f; + break; + case 0xf3: /* CMC */ + m_C ^= 1; + break; + case 0xf4: /* CMA */ + m_A ^= 0x0f; + break; + case 0xf5: /* RAL */ + m_A = (m_A << 1) | m_C; + m_C = m_A >> 4; + m_A &= 0x0f; + break; + case 0xf6: /* RAR */ + { + UINT8 c = m_A & 1; + m_A = (m_A >> 1) | (m_C << 3); + m_C = c; + } + break; + case 0xf7: /* TCC */ + m_A = m_C; + m_C = 0; + break; + case 0xf8: /* DAC */ + m_A = m_A + 0x0f; + m_C = m_A >> 4; + m_A &= 0x0f; + break; + case 0xf9: /* TCS */ + m_A = m_C ? 10 : 9; + m_C = 0; + break; + case 0xfa: /* STC */ + m_C = 1; + break; + case 0xfb: /* DAA */ + if (m_C || (m_A > 9)) { + m_A += 6; + } + if (m_A > 0x0f) { + // it is unaffected if it is in range + m_C = 1; + } + m_A &= 0x0f; + break; + case 0xfc: /* KBP */ + m_A = kbp_table[m_A]; + break; + case 0xfd: /* DCL */ + m_RAM.b.h = m_A; + break; + } +} + + +/*************************************************************************** + COMMON EXECUTION +***************************************************************************/ + +void i4004_cpu_device::execute_run() +{ + do + { + debugger_instruction_hook(this, GET_PC.d); + execute_one(ROP()); + + } while (m_icount > 0); +} + +/*************************************************************************** + CORE INITIALIZATION +***************************************************************************/ + +void i4004_cpu_device::device_start() +{ + /* set up the state table */ + { + state_add(I4004_PC, "PC", m_PC.w.l).mask(0x0fff); + state_add(STATE_GENPC, "GENPC", m_PC.w.l).mask(0x0fff).noshow(); + state_add(STATE_GENFLAGS, "GENFLAGS", m_flags).mask(0x0f).callimport().callexport().noshow().formatstr("%4s"); + state_add(I4004_A, "A", m_A).mask(0x0f); + + std::string tempstr; + for (int regnum = 0; regnum < 8; regnum++) + { + state_add(I4004_R01 + regnum, strformat(tempstr, "R%X%X", regnum * 2, regnum * 2 + 1).c_str(), m_R[regnum]); + } + + for (int addrnum = 0; addrnum < 4; addrnum++) + { + state_add(I4004_ADDR1 + addrnum, strformat(tempstr, "ADDR%d", addrnum + 1).c_str(), m_ADDR[addrnum].w.l).mask(0xfff); + } + + state_add(I4004_RAM, "RAM", m_RAM.w.l).mask(0x0fff); + } + + m_program = &space(AS_PROGRAM); + m_direct = &m_program->direct(); + m_data = &space(AS_DATA); + m_io = &space(AS_IO); + + save_item(NAME(m_PC)); + save_item(NAME(m_A)); + save_item(NAME(m_C)); + save_item(NAME(m_TEST)); + save_item(NAME(m_pc_pos)); + save_item(NAME(m_ADDR[0])); + save_item(NAME(m_ADDR[1])); + save_item(NAME(m_ADDR[2])); + save_item(NAME(m_ADDR[3])); + save_item(NAME(m_R[0])); + save_item(NAME(m_R[1])); + save_item(NAME(m_R[2])); + save_item(NAME(m_R[3])); + save_item(NAME(m_R[4])); + save_item(NAME(m_R[5])); + save_item(NAME(m_R[6])); + save_item(NAME(m_R[7])); + save_item(NAME(m_RAM)); + + m_icountptr = &m_icount; +} + + +/*************************************************************************** + COMMON RESET +***************************************************************************/ + +void i4004_cpu_device::device_reset() +{ + m_addr_mask = 3; + m_C = 0; + m_pc_pos = 0; + m_A = 0; + memset(m_R,0,8); + memset(m_ADDR,0,sizeof(m_ADDR)); + m_RAM.d = 0; + m_PC = GET_PC; + +} + + + +/*************************************************************************** + COMMON STATE IMPORT/EXPORT +***************************************************************************/ + +void i4004_cpu_device::state_import(const device_state_entry &entry) +{ + switch (entry.index()) + { + case STATE_GENFLAGS: + m_C = (m_flags >> 1) & 1; + m_TEST = (m_flags >> 0) & 1; + break; + } +} + +void i4004_cpu_device::state_export(const device_state_entry &entry) +{ + switch (entry.index()) + { + case STATE_GENFLAGS: + m_flags = ((m_A == 0) ? 0x04 : 0x00) | + (m_C ? 0x02 : 0x00) | + (m_TEST ? 0x01 : 0x00); + break; + } +} + +void i4004_cpu_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + switch (entry.index()) + { + case STATE_GENFLAGS: + strprintf(str, ".%c%c%c", + (m_A==0) ? 'Z':'.', + m_C ? 'C':'.', + m_TEST ? 'T':'.'); + break; + } +} + +offs_t i4004_cpu_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( i4004 ); + return CPU_DISASSEMBLE_NAME(i4004)(this, buffer, pc, oprom, opram, options); +} + +// case CPUINFO_IS_OCTAL: info->i = true; break; diff --git a/src/devices/cpu/i4004/i4004.h b/src/devices/cpu/i4004/i4004.h new file mode 100644 index 00000000000..956218f3723 --- /dev/null +++ b/src/devices/cpu/i4004/i4004.h @@ -0,0 +1,110 @@ +// license:BSD-3-Clause +// copyright-holders:Miodrag Milanovic +#ifndef __I4004_H__ +#define __I4004_H__ + + + +/*************************************************************************** + CONSTANTS +***************************************************************************/ + +enum +{ + I4004_PC, + I4004_A, + I4004_R01, I4004_R23, I4004_R45, I4004_R67, I4004_R89, I4004_RAB, I4004_RCD, I4004_REF, + I4004_ADDR1,I4004_ADDR2,I4004_ADDR3,I4004_ADDR4,I4004_RAM, + I4004_GENPC = STATE_GENPC, + I4004_GENSP = STATE_GENSP, + I4004_GENPCBASE = STATE_GENPCBASE +}; + +/*************************************************************************** + TYPE DEFINITIONS +***************************************************************************/ + +class i4004_cpu_device : public cpu_device +{ +public: + // construction/destruction + i4004_cpu_device(const machine_config &mconfig, const char *_tag, device_t *_owner, UINT32 _clock); + + void set_test(UINT8 val); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_execute_interface overrides + virtual UINT32 execute_min_cycles() const { return 8; } + virtual UINT32 execute_max_cycles() const { return 16; } + virtual void execute_run(); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const + { + switch (spacenum) + { + case AS_PROGRAM: return &m_program_config; + case AS_IO: return &m_io_config; + case AS_DATA: return &m_data_config; + default: return NULL; + } + } + + // device_state_interface overrides + virtual void state_import(const device_state_entry &entry); + virtual void state_export(const device_state_entry &entry); + virtual void state_string_export(const device_state_entry &entry, std::string &str); + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const { return 1; } + virtual UINT32 disasm_max_opcode_bytes() const { return 2; } + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + + UINT8 ROP(); + UINT8 READ_ROM(); + void WPM(); + UINT8 ARG(); + UINT8 RM(); + UINT8 RMS(UINT32 a); + void WM(UINT8 v); + void WMP(UINT8 v); + void WMS(UINT32 a, UINT8 v); + UINT8 RIO(); + void WIO(UINT8 v); + UINT8 GET_REG(UINT8 num); + void SET_REG(UINT8 num, UINT8 val); + void PUSH_STACK(); + void POP_STACK(); + void execute_one(int opcode); + + address_space_config m_program_config; + address_space_config m_io_config; + address_space_config m_data_config; + + UINT8 m_A; // Accumulator + UINT8 m_R[8]; + PAIR m_ADDR[4]; // Address registers + PAIR m_RAM; + UINT8 m_C; // Carry flag + UINT8 m_TEST; // Test PIN status + PAIR m_PC; // It is in fact one of ADDR regs + UINT8 m_flags; // used for I/O only + + address_space *m_program; + direct_read_data *m_direct; + address_space *m_data; + address_space *m_io; + int m_icount; + int m_pc_pos; // PC possition in ADDR + int m_addr_mask; +}; + + +extern const device_type I4004; + + +#endif diff --git a/src/devices/cpu/i8008/8008dasm.c b/src/devices/cpu/i8008/8008dasm.c new file mode 100644 index 00000000000..d5f1e082d5e --- /dev/null +++ b/src/devices/cpu/i8008/8008dasm.c @@ -0,0 +1,115 @@ +// license:BSD-3-Clause +// copyright-holders:Miodrag Milanovic +/***************************************************************************** + * + * 8008dasm.c + * + * Intel 8008 CPU Disassembly + * + *****************************************************************************/ + +#include "emu.h" + +#define OP(A) oprom[(A) - PC] +#define ARG(A) opram[(A) - PC] + +static const char reg[] = { 'a', 'b', 'c', 'd', 'e', 'h', 'l', 'm' }; +static const char flag_names[] = { 'c', 'z', 's', 'p' }; + +CPU_DISASSEMBLE( i8008 ) +{ + UINT32 flags = 0; + unsigned PC = pc; + UINT8 op = OP(pc++); + switch (op >> 6) + { + case 0x03: // starting with 11 + if (op==0xff) { + sprintf (buffer,"hlt"); + } else { + sprintf (buffer,"l%c%c",reg[(op >> 3) & 7],reg[op & 7]); + } + break; + case 0x00: // starting with 00 + switch(op & 7) { + case 0 : if(((op >> 3) & 7)==0) { + sprintf (buffer,"hlt"); + } else { + if(((op >> 3) & 7)==7) { + sprintf (buffer,"illegal"); + } else { + sprintf (buffer,"in%c",reg[(op >> 3) & 7]); + } + } + break; + case 1 : if(((op >> 3) & 7)==0) { + sprintf (buffer,"hlt"); + } else { + if(((op >> 3) & 7)==7) { + sprintf (buffer,"illegal"); + } else { + sprintf (buffer,"dc%c",reg[(op >> 3) & 7]); + } + } + break; + case 2 : { + switch((op >> 3) & 7) { + case 0 : sprintf (buffer,"rlc"); break; + case 1 : sprintf (buffer,"rrc"); break; + case 2 : sprintf (buffer,"ral"); break; + case 3 : sprintf (buffer,"rar"); break; + default : sprintf (buffer,"illegal"); break; + } + } + break; + case 3 : sprintf (buffer,"r%c%c",(BIT(op,5) ? 't' : 'f'),flag_names[(op>>3)&3]); break; + case 4 : { + switch((op >> 3) & 7) { + case 0 : sprintf (buffer,"adi %02x",ARG(pc)); pc++; break; + case 1 : sprintf (buffer,"aci %02x",ARG(pc)); pc++; break; + case 2 : sprintf (buffer,"sui %02x",ARG(pc)); pc++; break; + case 3 : sprintf (buffer,"sbi %02x",ARG(pc)); pc++; break; + case 4 : sprintf (buffer,"ndi %02x",ARG(pc)); pc++; break; + case 5 : sprintf (buffer,"xri %02x",ARG(pc)); pc++; break; + case 6 : sprintf (buffer,"ori %02x",ARG(pc)); pc++; break; + case 7 : sprintf (buffer,"cpi %02x",ARG(pc)); pc++; break; + } + } + break; + case 5 : sprintf (buffer,"rst %02x",(op>>3) & 7); break; + case 6 : sprintf (buffer,"l%ci %02x",reg[(op >> 3) & 7],ARG(pc)); pc++; break; + case 7 : sprintf (buffer,"ret"); break; + } + break; + case 0x01: // starting with 01 + switch(op & 7) { + case 0 : sprintf (buffer,"j%c%c %02x%02x",(BIT(op,5)? 't' : 'f'),flag_names[(op>>3)&3], ARG(pc+1) & 0x3f,ARG(pc)); pc+=2; break; + case 2 : sprintf (buffer,"c%c%c %02x%02x",(BIT(op,5)? 't' : 'f'),flag_names[(op>>3)&3], ARG(pc+1) & 0x3f,ARG(pc)); pc+=2; break; + case 4 : sprintf (buffer,"jmp %02x%02x",ARG(pc+1) & 0x3f,ARG(pc)); pc+=2; break; + case 6 : sprintf (buffer,"cal %02x%02x",ARG(pc+1) & 0x3f,ARG(pc)); pc+=2; break; + case 1 : + case 3 : + case 5 : + case 7 : if (((op>>4)&3)==0) { + sprintf (buffer,"inp %02x",(op >> 1) & 0x07); + } else { + sprintf (buffer,"out %02x",(op >> 1) & 0x1f); + } + break; + } + break; + case 0x02: // starting with 10 + switch((op >> 3) & 7) { + case 0 : sprintf (buffer,"ad%c",reg[op & 7]); break; + case 1 : sprintf (buffer,"ac%c",reg[op & 7]); break; + case 2 : sprintf (buffer,"su%c",reg[op & 7]); break; + case 3 : sprintf (buffer,"sb%c",reg[op & 7]); break; + case 4 : sprintf (buffer,"nd%c",reg[op & 7]); break; + case 5 : sprintf (buffer,"xr%c",reg[op & 7]); break; + case 6 : sprintf (buffer,"or%c",reg[op & 7]); break; + case 7 : sprintf (buffer,"cp%c",reg[op & 7]); break; + } + break; + } + return (pc - PC) | flags | DASMFLAG_SUPPORTED; +} diff --git a/src/devices/cpu/i8008/i8008.c b/src/devices/cpu/i8008/i8008.c new file mode 100644 index 00000000000..9527185339a --- /dev/null +++ b/src/devices/cpu/i8008/i8008.c @@ -0,0 +1,700 @@ +// license:BSD-3-Clause +// copyright-holders:Miodrag Milanovic +/***************************************************************************** + * + * i8008.c + * + * Intel 8008 CPU + * + *****************************************************************************/ +#include "emu.h" +#include "debugger.h" +#include "i8008.h" + +//************************************************************************** +// MACROS +//************************************************************************** + +#define REG_1 ((opcode >> 3) & 7) +#define REG_2 (opcode & 7) +#define GET_PC (m_ADDR[m_pc_pos]) + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +// device type definition +const device_type I8008 = &device_creator; + +//************************************************************************** +// DEVICE INTERFACE +//************************************************************************** + +//------------------------------------------------- +// i8008_device - constructor +//------------------------------------------------- +i8008_device::i8008_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : cpu_device(mconfig, I8008, "i8008", tag, owner, clock, "i8008", __FILE__), + m_program_config("program", ENDIANNESS_LITTLE, 8, 14), + m_io_config("io", ENDIANNESS_LITTLE, 8, 8), + m_program(0), + m_direct(0) +{ + // set our instruction counter + m_icountptr = &m_icount; +} + +//------------------------------------------------- +// device_start - start up the device +//------------------------------------------------- + +void i8008_device::device_start() +{ + // find address spaces + m_program = &space(AS_PROGRAM); + m_direct = &m_program->direct(); + m_io = &space(AS_IO); + + // save state + save_item(NAME(m_PC)); + save_item(NAME(m_A)); + save_item(NAME(m_B)); + save_item(NAME(m_C)); + save_item(NAME(m_D)); + save_item(NAME(m_E)); + save_item(NAME(m_H)); + save_item(NAME(m_L)); + save_item(NAME(m_CF)); + save_item(NAME(m_SF)); + save_item(NAME(m_ZF)); + save_item(NAME(m_PF)); + save_item(NAME(m_pc_pos)); + save_item(NAME(m_ADDR[0])); + save_item(NAME(m_ADDR[1])); + save_item(NAME(m_ADDR[2])); + save_item(NAME(m_ADDR[3])); + save_item(NAME(m_ADDR[4])); + save_item(NAME(m_ADDR[5])); + save_item(NAME(m_ADDR[6])); + save_item(NAME(m_ADDR[7])); + save_item(NAME(m_HALT)); + save_item(NAME(m_irq_state)); + + // register our state for the debugger + state_add(I8008_PC, "PC", m_PC.w.l).mask(0x3fff); + state_add(STATE_GENPC, "GENPC", m_PC.w.l).mask(0x3fff).noshow(); + state_add(STATE_GENFLAGS, "GENFLAGS", m_flags).mask(0x0f).callimport().callexport().noshow().formatstr("%4s"); + state_add(I8008_A, "A", m_A); + state_add(I8008_B, "B", m_B); + state_add(I8008_C, "C", m_C); + state_add(I8008_D, "D", m_D); + state_add(I8008_E, "E", m_E); + state_add(I8008_H, "H", m_H); + state_add(I8008_L, "L", m_L); + + std::string tempstr; + for (int addrnum = 0; addrnum < 8; addrnum++) + state_add(I8008_ADDR1 + addrnum, strformat(tempstr, "ADDR%d", addrnum + 1).c_str(), m_ADDR[addrnum].w.l).mask(0xfff); + + init_tables(); +} + +void i8008_device::init_tables (void) +{ + int i; + UINT8 p; + for (i = 0; i < 256; i++) + { + p = 0; + if (BIT(i,0)) p++; + if (BIT(i,1)) p++; + if (BIT(i,2)) p++; + if (BIT(i,3)) p++; + if (BIT(i,4)) p++; + if (BIT(i,5)) p++; + if (BIT(i,6)) p++; + if (BIT(i,7)) p++; + m_PARITY[i] = ((p&1) ? 0 : 1); + } +} + +//------------------------------------------------- +// device_reset - reset the device +//------------------------------------------------- + +void i8008_device::device_reset() +{ + m_CF = m_SF = m_ZF = m_PF = 0; + m_A = m_B = m_C = m_D = m_E = m_H = m_L = 0; + m_PC.d = 0; + m_pc_pos = 0; + m_HALT = 0; + m_irq_state = CLEAR_LINE; + memset(m_ADDR,0,sizeof(m_ADDR)); +} + +//------------------------------------------------- +// memory_space_config - return the configuration +// of the specified address space, or NULL if +// the space doesn't exist +//------------------------------------------------- + +const address_space_config *i8008_device::memory_space_config(address_spacenum spacenum) const +{ + return (spacenum == AS_PROGRAM) ? &m_program_config : + (spacenum == AS_IO) ? &m_io_config : + NULL; +} + +//------------------------------------------------- +// state_import - import state into the device, +// after it has been set +//------------------------------------------------- + +void i8008_device::state_import(const device_state_entry &entry) +{ + switch (entry.index()) + { + case STATE_GENFLAGS: + m_CF = (m_flags >> 3) & 1; + m_ZF = (m_flags >> 2) & 1; + m_SF = (m_flags >> 1) & 1; + m_PF = (m_flags >> 0) & 1; + break; + } +} + +//------------------------------------------------- +// state_export - export state from the device, +// to a known location where it can be read +//------------------------------------------------- + +void i8008_device::state_export(const device_state_entry &entry) +{ + switch (entry.index()) + { + case STATE_GENFLAGS: + m_flags = (m_CF ? 0x08 : 0x00) | + (m_ZF ? 0x04 : 0x00) | + (m_SF ? 0x02 : 0x00) | + (m_PF ? 0x01 : 0x00); + break; + } +} + +//------------------------------------------------- +// state_string_export - export state as a string +// for the debugger +//------------------------------------------------- + +void i8008_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + switch (entry.index()) + { + case STATE_GENFLAGS: + strprintf(str, "%c%c%c%c", + m_CF ? 'C':'.', + m_ZF ? 'Z':'.', + m_SF ? 'S':'.', + m_PF ? 'P':'.'); + break; + } +} + +//------------------------------------------------- +// disasm_min_opcode_bytes - return the length +// of the shortest instruction, in bytes +//------------------------------------------------- + +UINT32 i8008_device::disasm_min_opcode_bytes() const +{ + return 1; +} + +//------------------------------------------------- +// disasm_max_opcode_bytes - return the length +// of the longest instruction, in bytes +//------------------------------------------------- + +UINT32 i8008_device::disasm_max_opcode_bytes() const +{ + return 3; +} + +//------------------------------------------------- +// disasm_disassemble - call the disassembly +// helper function +//------------------------------------------------- + +offs_t i8008_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( i8008 ); + return CPU_DISASSEMBLE_NAME(i8008)(this, buffer, pc, oprom, opram, options); +} + +//************************************************************************** +// EXECUTION +//************************************************************************** + +//------------------------------------------------- +// execute_min_cycles - return minimum number of +// cycles it takes for one instruction to execute +//------------------------------------------------- + +UINT32 i8008_device::execute_min_cycles() const +{ + return 8; +} + +//------------------------------------------------- +// execute_max_cycles - return maximum number of +// cycles it takes for one instruction to execute +//------------------------------------------------- + +UINT32 i8008_device::execute_max_cycles() const +{ + return 16; +} + +//------------------------------------------------- +// execute_set_input - set input and IRQ lines +//------------------------------------------------- + +void i8008_device::execute_set_input(int inputnum, int state) +{ + m_irq_state = state; +} + +//------------------------------------------------- +// execute_run - execute until our icount expires +//------------------------------------------------- + +void i8008_device::execute_run() +{ + do + { + if (m_irq_state != CLEAR_LINE) { + take_interrupt(); + } + debugger_instruction_hook(this, m_PC.d); + execute_one(rop()); + } while (m_icount > 0); +} + +inline void i8008_device::illegal(UINT8 opcode) +{ + if ((machine().debug_flags & DEBUG_FLAG_ENABLED) != 0) + { + logerror("I8008 illegal instruction %04X $%02X\n", m_PC.w.l, opcode); + } +} + +void i8008_device::take_interrupt() +{ + if (m_HALT) { + GET_PC.w.l = (GET_PC.w.l + 1) & 0x3fff; + m_PC = GET_PC; + m_HALT = 0; + } + // For now only support one byte operation to be executed + execute_one(standard_irq_callback(0)); +} + +inline void i8008_device::execute_one(int opcode) +{ + UINT16 tmp; + + switch (opcode >> 6) + { + case 0x03: // starting with 11 + if (opcode==0xff) { + // HLT + m_icount -= 4; + GET_PC.w.l = GET_PC.w.l - 1; + m_PC = GET_PC; + m_HALT = 1; + } else { + // Lrr + m_icount -= 5; + if (REG_1==7) m_icount -= 2; + if (REG_2==7) m_icount -= 3; + set_reg(REG_1, get_reg(REG_2)); + } + break; + case 0x00: // starting with 00 + switch(opcode & 7) { + case 0 : if(((opcode >> 3) & 7)==0) { + // HLT + m_icount -= 4; + GET_PC.w.l = GET_PC.w.l - 1; + m_PC = GET_PC; + m_HALT = 1; + } else { + if(((opcode >> 3) & 7)==7) { + // ILLEGAL + m_icount -= 5; + illegal(opcode); + } else { + // INr + m_icount -= 5; + tmp = get_reg(REG_1) + 1; + set_reg(REG_1, tmp & 0xff); + update_flags(tmp & 0xff); + } + } + break; + case 1 : if(((opcode >> 3) & 7)==0) { + // HLT + m_icount -= 4; + GET_PC.w.l = GET_PC.w.l - 1; + m_PC = GET_PC; + m_HALT = 1; + } else { + if(((opcode >> 3) & 7)==7) { + // ILLEGAL + m_icount -= 5; + illegal(opcode); + } else { + // DCr + m_icount -= 5; + tmp = get_reg(REG_1) - 1; + set_reg(REG_1, tmp & 0xff); + update_flags(tmp & 0xff); + } + } + break; + case 2 : { + // All instuction from this group have same timing + m_icount -= 5; + switch((opcode >> 3) & 7) { + case 0 : + // RLC + tmp = m_A; + m_A = (m_A << 1) | BIT(tmp,7); + m_CF = BIT(tmp,7); + break; + case 1 : + // RRC + tmp = m_A; + m_A = (m_A >> 1) | (BIT(tmp,0) ? 0x80 : 0x00); + m_CF = BIT(tmp,0); + break; + case 2 : + // RAL + tmp = m_A; + m_A = (m_A << 1) | m_CF; + m_CF = BIT(tmp,7); + break; + case 3 : + // RAR + tmp = m_A; + m_A = (m_A >> 1) | (m_CF ? 0x80 : 0x00); + m_CF = BIT(tmp,0); + break; + default : + // ILLEGAL + illegal(opcode); + break; + } + } + break; + case 3 : + // Rcc + { + m_icount -= 3; + if (do_condition(opcode)==1) { + m_icount -= 2; + pop_stack(); + m_PC = GET_PC; + } + } + break; + case 4 : { + m_icount -= 8; + switch((opcode >> 3) & 7) { + case 0 : + // ADI + tmp = get_reg(0) + arg(); + set_reg(0,tmp & 0xff); + update_flags(tmp & 0xff); + m_CF = (tmp >> 8) & 1; + break; + case 1 : + // ACI + tmp = get_reg(0) + arg() + m_CF; + set_reg(0,tmp & 0xff); + update_flags(tmp & 0xff); + m_CF = (tmp >> 8) & 1; + break; + case 2 : + // SUI + tmp = get_reg(0) - arg(); + set_reg(0,tmp & 0xff); + update_flags(tmp & 0xff); + m_CF = (tmp >> 8) & 1; + break; + case 3 : + // SBI + tmp = get_reg(0) - arg() - m_CF; + set_reg(0,tmp & 0xff); + update_flags(tmp & 0xff); + m_CF = (tmp >> 8) & 1; + break; + case 4 : + // NDI + tmp = get_reg(0) & arg(); + set_reg(0,tmp & 0xff); + update_flags(tmp & 0xff); + m_CF = 0; + break; + case 5 : + // XRI + tmp = get_reg(0) ^ arg(); + set_reg(0,tmp & 0xff); + update_flags(tmp & 0xff); + m_CF = 0; + break; + case 6 : + // ORI + tmp = get_reg(0) | arg(); + set_reg(0,tmp & 0xff); + update_flags(tmp & 0xff); + m_CF = 0; + break; + case 7 : + // CPI + tmp = get_reg(0) - arg(); + update_flags(tmp & 0xff); + m_CF = (tmp >> 8) & 1; + break; + } + } + break; + case 5 : // RST + m_icount -= 5; + push_stack(); + GET_PC.w.l = opcode & 0x38; + m_PC = GET_PC; + break; + case 6 : // LrI + m_icount -= 8; + if (REG_1==7) m_icount -= 1; // LMI + set_reg(REG_1, arg()); + break; + case 7 : // RET + m_icount -= 5; + pop_stack(); + m_PC = GET_PC; + break; + } + break; + + case 0x01: // starting with 01 + switch(opcode & 7) { + case 0 : + // Jcc + m_icount -= 9; + tmp = get_addr(); + if (do_condition(opcode)==1) { + m_icount -= 2; + GET_PC.w.l = tmp; + m_PC = GET_PC; + } + break; + case 2 : + // Ccc + m_icount -= 9; + tmp = get_addr(); + if (do_condition(opcode)==1) { + m_icount -= 2; + push_stack(); + GET_PC.w.l = tmp; + m_PC = GET_PC; + } + break; + case 4 : + // JMP + m_icount -= 11; + GET_PC.w.l = get_addr(); + m_PC = GET_PC; + break; + case 6 : + // CAL + m_icount -= 11; + tmp = get_addr(); + push_stack(); + GET_PC.w.l = tmp; + m_PC = GET_PC; + break; + default : + if (((opcode>>4)&3)==0) { + // INP + m_icount -= 8; + m_A = m_io->read_byte((opcode >> 1) & 0x1f); + } else { + // OUT + m_icount -= 6; + m_io->write_byte((opcode >> 1) & 0x1f, m_A); + } + break; + } + break; + case 0x02: // starting with 10 + m_icount -= 5; + if ((opcode & 7)==7) m_icount -= 3; // operations with memory + switch((opcode >> 3) & 7) { + case 0 : + // ADx + tmp = get_reg(0) + get_reg(opcode & 7); + set_reg(0,tmp & 0xff); + update_flags(tmp & 0xff); + m_CF = (tmp >> 8) & 1; + break; + case 1 : + // ACx + tmp = get_reg(0) + get_reg(opcode & 7) + m_CF; + set_reg(0,tmp & 0xff); + update_flags(tmp & 0xff); + m_CF = (tmp >> 8) & 1; + break; + case 2 : + // SUx + tmp = get_reg(0) - get_reg(opcode & 7); + set_reg(0,tmp & 0xff); + update_flags(tmp & 0xff); + m_CF = (tmp >> 8) & 1; + break; + case 3 : + // SBx + tmp = get_reg(0) - get_reg(opcode & 7) - m_CF; + set_reg(0,tmp & 0xff); + update_flags(tmp & 0xff); + m_CF = (tmp >> 8) & 1; + break; + case 4 : + // NDx + tmp = get_reg(0) & get_reg(opcode & 7); + set_reg(0,tmp & 0xff); + update_flags(tmp & 0xff); + m_CF = 0; + break; + case 5 : + // XRx + tmp = get_reg(0) ^ get_reg(opcode & 7); + set_reg(0,tmp & 0xff); + update_flags(tmp & 0xff); + m_CF = 0; + break; + case 6 : + // ORx + tmp = get_reg(0) | get_reg(opcode & 7); + set_reg(0,tmp & 0xff); + update_flags(tmp & 0xff); + m_CF = 0; + break; + case 7 : + // CPx + tmp = get_reg(0) - get_reg(opcode & 7); + update_flags(tmp & 0xff); + m_CF = (tmp >> 8) & 1; + break; + } + break; + } +} + +/*************************************************************************** + INLINE FUNCTIONS +***************************************************************************/ + +inline void i8008_device::push_stack() +{ + m_pc_pos = (m_pc_pos + 1) & 7; +} + +inline void i8008_device::pop_stack() +{ + m_ADDR[m_pc_pos].d = 0; + m_pc_pos = (m_pc_pos - 1) & 7; +} + +inline UINT8 i8008_device::rop() +{ + UINT8 retVal = m_direct->read_byte(GET_PC.w.l); + GET_PC.w.l = (GET_PC.w.l + 1) & 0x3fff; + m_PC = GET_PC; + return retVal; +} + +inline UINT8 i8008_device::get_reg(UINT8 reg) +{ + UINT8 retVal; + switch(reg) { + case 0 : retVal = m_A; break; + case 1 : retVal = m_B; break; + case 2 : retVal = m_C; break; + case 3 : retVal = m_D; break; + case 4 : retVal = m_E; break; + case 5 : retVal = m_H; break; + case 6 : retVal = m_L; break; + default: retVal = m_program->read_byte((m_H << 8) + m_L); break; + } + return retVal; +} + +inline void i8008_device::set_reg(UINT8 reg, UINT8 val) +{ + switch(reg) { + case 0 : m_A = val; break; + case 1 : m_B = val; break; + case 2 : m_C = val; break; + case 3 : m_D = val; break; + case 4 : m_E = val; break; + case 5 : m_H = val; break; + case 6 : m_L = val; break; + default: m_program->write_byte((m_H << 8) + m_L, val); break; + } +} + +inline UINT8 i8008_device::arg() +{ + UINT8 retVal = m_direct->read_byte(GET_PC.w.l); + GET_PC.w.l = (GET_PC.w.l + 1) & 0x3fff; + m_PC = GET_PC; + return retVal; +} + +inline void i8008_device::update_flags(UINT8 val) +{ + m_ZF = (val == 0) ? 1 : 0; + m_SF = (val & 0x80) ? 1 : 0; + m_PF = m_PARITY[val]; +} + +inline UINT8 i8008_device::do_condition(UINT8 val) +{ + UINT8 v = (val >> 5) & 1; + UINT8 cond = 0; + switch((val>> 3) & 0x03) { + case 0 : + if (m_CF==v) cond = 1; + break; + case 1 : + if (m_ZF==v) cond = 1; + break; + case 2 : + if (m_SF==v) cond = 1; + break; + case 3 : + if (m_PF==v) cond = 1; + break; + } + return cond; +} + +inline UINT16 i8008_device::get_addr() +{ + UINT8 lo = arg(); + UINT8 hi = arg(); + return ((hi & 0x3f) << 8) + lo; +} diff --git a/src/devices/cpu/i8008/i8008.h b/src/devices/cpu/i8008/i8008.h new file mode 100644 index 00000000000..c9cbecce7aa --- /dev/null +++ b/src/devices/cpu/i8008/i8008.h @@ -0,0 +1,103 @@ +// license:BSD-3-Clause +// copyright-holders:Miodrag Milanovic +#ifndef __I8008_H__ +#define __I8008_H__ + +//************************************************************************** +// ENUMERATIONS +//************************************************************************** + +enum +{ + I8008_PC, + I8008_A,I8008_B,I8008_C,I8008_D,I8008_E,I8008_H,I8008_L, + I8008_ADDR1,I8008_ADDR2,I8008_ADDR3,I8008_ADDR4,I8008_ADDR5,I8008_ADDR6,I8008_ADDR7,I8008_ADDR8, + + I8008_GENPC = STATE_GENPC, + I8008_GENSP = STATE_GENSP, + I8008_GENPCBASE = STATE_GENPCBASE +}; + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class i8008_device; + +// ======================> asap_device +class i8008_device : public cpu_device +{ +public: + // construction/destruction + i8008_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_execute_interface overrides + virtual UINT32 execute_min_cycles() const; + virtual UINT32 execute_max_cycles() const; + virtual void execute_run(); + virtual void execute_set_input(int inputnum, int state); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const; + + // device_state_interface overrides + virtual void state_import(const device_state_entry &entry); + virtual void state_export(const device_state_entry &entry); + virtual void state_string_export(const device_state_entry &entry, std::string &str); + + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const; + virtual UINT32 disasm_max_opcode_bytes() const; + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + + virtual void execute_one(int opcode); + + void push_stack(); + void pop_stack(); + UINT8 rop(); + UINT8 get_reg(UINT8 reg); + void set_reg(UINT8 reg, UINT8 val); + UINT8 arg(); + void update_flags(UINT8 val); + UINT8 do_condition(UINT8 val); + UINT16 get_addr(); + void illegal(UINT8 opcode); + void take_interrupt(); + void init_tables(void); + + int m_pc_pos; // PC possition in ADDR + int m_icount; + + // configuration + const address_space_config m_program_config; + const address_space_config m_io_config; + + UINT8 m_A,m_B,m_C,m_D,m_E,m_H,m_L; + PAIR m_PC; // It is in fact one of ADDR regs + PAIR m_ADDR[8]; // Address registers + UINT8 m_CF; // Carry flag + UINT8 m_ZF; // Zero flag + UINT8 m_SF; // Sign flag + UINT8 m_PF; // Parity flag + UINT8 m_HALT; + UINT8 m_flags; // temporary I/O only + + UINT8 m_irq_state; + + UINT8 m_PARITY[256]; + + address_space *m_program; + address_space *m_io; + direct_read_data *m_direct; +}; + +// device type definition +extern const device_type I8008; + +#endif diff --git a/src/devices/cpu/i8085/8085dasm.c b/src/devices/cpu/i8085/8085dasm.c new file mode 100644 index 00000000000..e68bdfac337 --- /dev/null +++ b/src/devices/cpu/i8085/8085dasm.c @@ -0,0 +1,545 @@ +// license:BSD-3-Clause +// copyright-holders:Juergen Buchmueller +/***************************************************************************** + * + * 8085dasm.c + * Portable I8085A disassembler + * + *****************************************************************************/ + +#include "emu.h" + +/* 8080/8085A mnemonics were more irritation than information + What would you guess "CP $3456" to mean? It's not compare, + but call if plus ... therefore: */ +//#define Z80_MNEMONICS + +#define OP(A) oprom[(A) - PC] +#define ARG(A) opram[(A) - PC] +#define ARGW(A) (opram[(A) - PC] | (opram[(A) + 1 - PC] << 8)) + +CPU_DISASSEMBLE( i8085 ) +{ + UINT32 flags = 0; + UINT8 op; + unsigned PC = pc; + switch (op = OP(pc++)) + { +#ifdef Z80_MNEMONICS + case 0x00: sprintf (buffer,"nop"); break; + case 0x01: sprintf (buffer,"ld bc,$%04x", ARGW(pc)); pc+=2; break; + case 0x02: sprintf (buffer,"ld (bc),a"); break; + case 0x03: sprintf (buffer,"inc bc"); break; + case 0x04: sprintf (buffer,"inc b"); break; + case 0x05: sprintf (buffer,"dec b"); break; + case 0x06: sprintf (buffer,"ld b,$%02x", ARG(pc)); pc++; break; + case 0x07: sprintf (buffer,"rlca"); break; + case 0x08: sprintf (buffer,"sub hl,bc (*)"); break; + case 0x09: sprintf (buffer,"add hl,bc"); break; + case 0x0a: sprintf (buffer,"ld a,(bc)"); break; + case 0x0b: sprintf (buffer,"dec bc"); break; + case 0x0c: sprintf (buffer,"inc c"); break; + case 0x0d: sprintf (buffer,"dec c"); break; + case 0x0e: sprintf (buffer,"ld c,$%02x", ARG(pc)); pc++; break; + case 0x0f: sprintf (buffer,"rrca"); break; + case 0x10: sprintf (buffer,"sra hl (*)"); break; + case 0x11: sprintf (buffer,"ld de,$%04x", ARGW(pc)); pc+=2; break; + case 0x12: sprintf (buffer,"ld (de),a"); break; + case 0x13: sprintf (buffer,"inc de"); break; + case 0x14: sprintf (buffer,"inc d"); break; + case 0x15: sprintf (buffer,"dec d"); break; + case 0x16: sprintf (buffer,"ld d,$%02x", ARG(pc)); pc++; break; + case 0x17: sprintf (buffer,"rla"); break; + case 0x18: sprintf (buffer,"rl de (*)"); break; + case 0x19: sprintf (buffer,"add hl,de"); break; + case 0x1a: sprintf (buffer,"ld a,(de)"); break; + case 0x1b: sprintf (buffer,"dec de"); break; + case 0x1c: sprintf (buffer,"inc e"); break; + case 0x1d: sprintf (buffer,"dec e"); break; + case 0x1e: sprintf (buffer,"ld e,$%02x", ARG(pc)); pc++; break; + case 0x1f: sprintf (buffer,"rra"); break; + case 0x20: sprintf (buffer,"rim"); break; + case 0x21: sprintf (buffer,"ld hl,$%04x", ARGW(pc)); pc+=2; break; + case 0x22: sprintf (buffer,"ld ($%04x),hl", ARGW(pc)); pc+=2;break; + case 0x23: sprintf (buffer,"inc hl"); break; + case 0x24: sprintf (buffer,"inc h"); break; + case 0x25: sprintf (buffer,"dec h"); break; + case 0x26: sprintf (buffer,"ld h,$%02x", ARG(pc)); pc++; break; + case 0x27: sprintf (buffer,"daa"); break; + case 0x28: sprintf (buffer,"ld de,hl+$%02x (*)",ARG(pc));pc++;break; + case 0x29: sprintf (buffer,"add hl,hl"); break; + case 0x2a: sprintf (buffer,"ld hl,($%04x)", ARGW(pc)); pc+=2;break; + case 0x2b: sprintf (buffer,"dec hl"); break; + case 0x2c: sprintf (buffer,"inc l"); break; + case 0x2d: sprintf (buffer,"dec l"); break; + case 0x2e: sprintf (buffer,"ld l,$%02x", ARG(pc)); pc++; break; + case 0x2f: sprintf (buffer,"cpl"); break; + case 0x30: sprintf (buffer,"sim"); break; + case 0x31: sprintf (buffer,"ld sp,$%04x", ARGW(pc)); pc+=2; break; + case 0x32: sprintf (buffer,"ld ($%04x),a", ARGW(pc)); pc+=2; break; + case 0x33: sprintf (buffer,"inc sp"); break; + case 0x34: sprintf (buffer,"inc (hl)"); break; + case 0x35: sprintf (buffer,"dec (hl)"); break; + case 0x36: sprintf (buffer,"ld (hl),$%02x", ARG(pc)); pc++; break; + case 0x37: sprintf (buffer,"scf"); break; + case 0x38: sprintf (buffer,"ld de,sp+$%02x (*)",ARG(pc));pc++;break; + case 0x39: sprintf (buffer,"add hl,sp"); break; + case 0x3a: sprintf (buffer,"ld a,($%04x)", ARGW(pc)); pc+=2; break; + case 0x3b: sprintf (buffer,"dec sp"); break; + case 0x3c: sprintf (buffer,"inc a"); break; + case 0x3d: sprintf (buffer,"dec a"); break; + case 0x3e: sprintf (buffer,"ld a,$%02x", ARG(pc)); pc++; break; + case 0x3f: sprintf (buffer,"ccf"); break; + case 0x40: sprintf (buffer,"ld b,b"); break; + case 0x41: sprintf (buffer,"ld b,c"); break; + case 0x42: sprintf (buffer,"ld b,d"); break; + case 0x43: sprintf (buffer,"ld b,e"); break; + case 0x44: sprintf (buffer,"ld b,h"); break; + case 0x45: sprintf (buffer,"ld b,l"); break; + case 0x46: sprintf (buffer,"ld b,(hl)"); break; + case 0x47: sprintf (buffer,"ld b,a"); break; + case 0x48: sprintf (buffer,"ld c,b"); break; + case 0x49: sprintf (buffer,"ld c,c"); break; + case 0x4a: sprintf (buffer,"ld c,d"); break; + case 0x4b: sprintf (buffer,"ld c,e"); break; + case 0x4c: sprintf (buffer,"ld c,h"); break; + case 0x4d: sprintf (buffer,"ld c,l"); break; + case 0x4e: sprintf (buffer,"ld c,(hl)"); break; + case 0x4f: sprintf (buffer,"ld c,a"); break; + case 0x50: sprintf (buffer,"ld d,b"); break; + case 0x51: sprintf (buffer,"ld d,c"); break; + case 0x52: sprintf (buffer,"ld d,d"); break; + case 0x53: sprintf (buffer,"ld d,e"); break; + case 0x54: sprintf (buffer,"ld d,h"); break; + case 0x55: sprintf (buffer,"ld d,l"); break; + case 0x56: sprintf (buffer,"ld d,(hl)"); break; + case 0x57: sprintf (buffer,"ld d,a"); break; + case 0x58: sprintf (buffer,"ld e,b"); break; + case 0x59: sprintf (buffer,"ld e,c"); break; + case 0x5a: sprintf (buffer,"ld e,d"); break; + case 0x5b: sprintf (buffer,"ld e,e"); break; + case 0x5c: sprintf (buffer,"ld e,h"); break; + case 0x5d: sprintf (buffer,"ld e,l"); break; + case 0x5e: sprintf (buffer,"ld e,(hl)"); break; + case 0x5f: sprintf (buffer,"ld e,a"); break; + case 0x60: sprintf (buffer,"ld h,b"); break; + case 0x61: sprintf (buffer,"ld h,c"); break; + case 0x62: sprintf (buffer,"ld h,d"); break; + case 0x63: sprintf (buffer,"ld h,e"); break; + case 0x64: sprintf (buffer,"ld h,h"); break; + case 0x65: sprintf (buffer,"ld h,l"); break; + case 0x66: sprintf (buffer,"ld h,(hl)"); break; + case 0x67: sprintf (buffer,"ld h,a"); break; + case 0x68: sprintf (buffer,"ld l,b"); break; + case 0x69: sprintf (buffer,"ld l,c"); break; + case 0x6a: sprintf (buffer,"ld l,d"); break; + case 0x6b: sprintf (buffer,"ld l,e"); break; + case 0x6c: sprintf (buffer,"ld l,h"); break; + case 0x6d: sprintf (buffer,"ld l,l"); break; + case 0x6e: sprintf (buffer,"ld l,(hl)"); break; + case 0x6f: sprintf (buffer,"ld l,a"); break; + case 0x70: sprintf (buffer,"ld (hl),b"); break; + case 0x71: sprintf (buffer,"ld (hl),c"); break; + case 0x72: sprintf (buffer,"ld (hl),d"); break; + case 0x73: sprintf (buffer,"ld (hl),e"); break; + case 0x74: sprintf (buffer,"ld (hl),h"); break; + case 0x75: sprintf (buffer,"ld (hl),l"); break; + case 0x76: sprintf (buffer,"halt"); break; + case 0x77: sprintf (buffer,"ld (hl),a"); break; + case 0x78: sprintf (buffer,"ld a,b"); break; + case 0x79: sprintf (buffer,"ld a,c"); break; + case 0x7a: sprintf (buffer,"ld a,d"); break; + case 0x7b: sprintf (buffer,"ld a,e"); break; + case 0x7c: sprintf (buffer,"ld a,h"); break; + case 0x7d: sprintf (buffer,"ld a,l"); break; + case 0x7e: sprintf (buffer,"ld a,(hl)"); break; + case 0x7f: sprintf (buffer,"ld a,a"); break; + case 0x80: sprintf (buffer,"add a,b"); break; + case 0x81: sprintf (buffer,"add a,c"); break; + case 0x82: sprintf (buffer,"add a,d"); break; + case 0x83: sprintf (buffer,"add a,e"); break; + case 0x84: sprintf (buffer,"add a,h"); break; + case 0x85: sprintf (buffer,"add a,l"); break; + case 0x86: sprintf (buffer,"add a,(hl)"); break; + case 0x87: sprintf (buffer,"add a,a"); break; + case 0x88: sprintf (buffer,"adc a,b"); break; + case 0x89: sprintf (buffer,"adc a,c"); break; + case 0x8a: sprintf (buffer,"adc a,d"); break; + case 0x8b: sprintf (buffer,"adc a,e"); break; + case 0x8c: sprintf (buffer,"adc a,h"); break; + case 0x8d: sprintf (buffer,"adc a,l"); break; + case 0x8e: sprintf (buffer,"adc a,(hl)"); break; + case 0x8f: sprintf (buffer,"adc a,a"); break; + case 0x90: sprintf (buffer,"sub b"); break; + case 0x91: sprintf (buffer,"sub c"); break; + case 0x92: sprintf (buffer,"sub d"); break; + case 0x93: sprintf (buffer,"sub e"); break; + case 0x94: sprintf (buffer,"sub h"); break; + case 0x95: sprintf (buffer,"sub l"); break; + case 0x96: sprintf (buffer,"sub (hl)"); break; + case 0x97: sprintf (buffer,"sub a"); break; + case 0x98: sprintf (buffer,"sbc a,b"); break; + case 0x99: sprintf (buffer,"sbc a,c"); break; + case 0x9a: sprintf (buffer,"sbc a,d"); break; + case 0x9b: sprintf (buffer,"sbc a,e"); break; + case 0x9c: sprintf (buffer,"sbc a,h"); break; + case 0x9d: sprintf (buffer,"sbc a,l"); break; + case 0x9e: sprintf (buffer,"sbc a,(hl)"); break; + case 0x9f: sprintf (buffer,"sbc a,a"); break; + case 0xa0: sprintf (buffer,"and b"); break; + case 0xa1: sprintf (buffer,"and c"); break; + case 0xa2: sprintf (buffer,"and d"); break; + case 0xa3: sprintf (buffer,"and e"); break; + case 0xa4: sprintf (buffer,"and h"); break; + case 0xa5: sprintf (buffer,"and l"); break; + case 0xa6: sprintf (buffer,"and (hl)"); break; + case 0xa7: sprintf (buffer,"and a"); break; + case 0xa8: sprintf (buffer,"xor b"); break; + case 0xa9: sprintf (buffer,"xor c"); break; + case 0xaa: sprintf (buffer,"xor d"); break; + case 0xab: sprintf (buffer,"xor e"); break; + case 0xac: sprintf (buffer,"xor h"); break; + case 0xad: sprintf (buffer,"xor l"); break; + case 0xae: sprintf (buffer,"xor (hl)"); break; + case 0xaf: sprintf (buffer,"xor a"); break; + case 0xb0: sprintf (buffer,"or b"); break; + case 0xb1: sprintf (buffer,"or c"); break; + case 0xb2: sprintf (buffer,"or d"); break; + case 0xb3: sprintf (buffer,"or e"); break; + case 0xb4: sprintf (buffer,"or h"); break; + case 0xb5: sprintf (buffer,"or l"); break; + case 0xb6: sprintf (buffer,"or (hl)"); break; + case 0xb7: sprintf (buffer,"or a"); break; + case 0xb8: sprintf (buffer,"cp b"); break; + case 0xb9: sprintf (buffer,"cp c"); break; + case 0xba: sprintf (buffer,"cp d"); break; + case 0xbb: sprintf (buffer,"cp e"); break; + case 0xbc: sprintf (buffer,"cp h"); break; + case 0xbd: sprintf (buffer,"cp l"); break; + case 0xbe: sprintf (buffer,"cp (hl)"); break; + case 0xbf: sprintf (buffer,"cp a"); break; + case 0xc0: sprintf (buffer,"ret nz"); flags = DASMFLAG_STEP_OUT; break; + case 0xc1: sprintf (buffer,"pop bc"); break; + case 0xc2: sprintf (buffer,"jp nz,$%04x", ARGW(pc)); pc+=2; break; + case 0xc3: sprintf (buffer,"jp $%04x", ARGW(pc)); pc+=2; break; + case 0xc4: sprintf (buffer,"call nz,$%04x", ARGW(pc)); pc+=2; flags = DASMFLAG_STEP_OVER; break; + case 0xc5: sprintf (buffer,"push bc"); break; + case 0xc6: sprintf (buffer,"add a,$%02x", ARG(pc)); pc++; break; + case 0xc7: sprintf (buffer,"rst $00"); flags = DASMFLAG_STEP_OVER; break; + case 0xc8: sprintf (buffer,"ret z"); flags = DASMFLAG_STEP_OUT; break; + case 0xc9: sprintf (buffer,"ret"); flags = DASMFLAG_STEP_OUT; break; + case 0xca: sprintf (buffer,"jp z,$%04x", ARGW(pc)); pc+=2; break; + case 0xcb: sprintf (buffer,"rst v,$40 (*)"); flags = DASMFLAG_STEP_OVER; break; + case 0xcc: sprintf (buffer,"call z,$%04x", ARGW(pc)); pc+=2; flags = DASMFLAG_STEP_OVER; break; + case 0xcd: sprintf (buffer,"call $%04x", ARGW(pc)); pc+=2; flags = DASMFLAG_STEP_OVER; break; + case 0xce: sprintf (buffer,"adc a,$%02x", ARG(pc)); pc++; break; + case 0xcf: sprintf (buffer,"rst $08"); flags = DASMFLAG_STEP_OVER; break; + case 0xd0: sprintf (buffer,"ret nc"); flags = DASMFLAG_STEP_OUT; break; + case 0xd1: sprintf (buffer,"pop de"); break; + case 0xd2: sprintf (buffer,"jp nc,$%04x", ARGW(pc)); pc+=2; break; + case 0xd3: sprintf (buffer,"out ($%02x),a", ARG(pc)); pc++; break; + case 0xd4: sprintf (buffer,"call nc,$%04x", ARGW(pc)); pc+=2; flags = DASMFLAG_STEP_OVER; break; + case 0xd5: sprintf (buffer,"push de"); break; + case 0xd6: sprintf (buffer,"sub $%02x", ARG(pc)); pc++; break; + case 0xd7: sprintf (buffer,"rst $10"); flags = DASMFLAG_STEP_OVER; break; + case 0xd8: sprintf (buffer,"ret c"); break; + case 0xd9: sprintf (buffer,"ld (de),hl (*)"); break; + case 0xda: sprintf (buffer,"jp c,$%04x", ARGW(pc)); pc+=2; break; + case 0xdb: sprintf (buffer,"in a,($%02x)", ARG(pc)); pc++; break; + case 0xdc: sprintf (buffer,"call c,$%04x", ARGW(pc)); pc+=2; flags = DASMFLAG_STEP_OVER; break; + case 0xdd: sprintf (buffer,"jp nx,$%04x (*)",ARGW(pc));pc+=2;break; + case 0xde: sprintf (buffer,"sub $%02x", ARG(pc)); pc++; break; + case 0xdf: sprintf (buffer,"rst $18"); flags = DASMFLAG_STEP_OVER; break; + case 0xe0: sprintf (buffer,"ret pe"); break; + case 0xe1: sprintf (buffer,"pop hl"); break; + case 0xe2: sprintf (buffer,"jp pe,$%04x", ARGW(pc)); pc+=2; break; + case 0xe3: sprintf (buffer,"ex (sp),hl"); break; + case 0xe4: sprintf (buffer,"call pe,$%04x", ARGW(pc)); pc+=2; flags = DASMFLAG_STEP_OVER; break; + case 0xe5: sprintf (buffer,"push hl"); break; + case 0xe6: sprintf (buffer,"and $%02x", ARG(pc)); pc++; break; + case 0xe7: sprintf (buffer,"rst $20"); flags = DASMFLAG_STEP_OVER; break; + case 0xe8: sprintf (buffer,"ret po"); break; + case 0xe9: sprintf (buffer,"jp (hl)"); break; + case 0xea: sprintf (buffer,"jp po,$%04x", ARGW(pc)); pc+=2; break; + case 0xeb: sprintf (buffer,"ex de,hl"); break; + case 0xec: sprintf (buffer,"call po,$%04x", ARGW(pc)); pc+=2; flags = DASMFLAG_STEP_OVER; break; + case 0xed: sprintf (buffer,"ld hl,(de) (*)"); break; + case 0xee: sprintf (buffer,"xor $%02x", ARG(pc)); pc++; break; + case 0xef: sprintf (buffer,"rst $28"); flags = DASMFLAG_STEP_OVER; break; + case 0xf0: sprintf (buffer,"ret p"); break; + case 0xf1: sprintf (buffer,"pop af"); break; + case 0xf2: sprintf (buffer,"jp p,$%04x", ARGW(pc)); pc+=2; break; + case 0xf3: sprintf (buffer,"di"); break; + case 0xf4: sprintf (buffer,"cp $%04x", ARGW(pc)); pc+=2; break; + case 0xf5: sprintf (buffer,"push af"); break; + case 0xf6: sprintf (buffer,"or $%02x", ARG(pc)); pc++; break; + case 0xf7: sprintf (buffer,"rst $30"); flags = DASMFLAG_STEP_OVER; break; + case 0xf8: sprintf (buffer,"ret m"); break; + case 0xf9: sprintf (buffer,"ld sp,hl"); break; + case 0xfa: sprintf (buffer,"jp m,$%04x", ARGW(pc)); pc+=2; break; + case 0xfb: sprintf (buffer,"ei"); break; + case 0xfc: sprintf (buffer,"call m,$%04x", ARGW(pc)); pc+=2; flags = DASMFLAG_STEP_OVER; break; + case 0xfd: sprintf (buffer,"jp x,$%04x (*)",ARGW(pc));pc+=2; break; + case 0xfe: sprintf (buffer,"cp $%02x", ARG(pc)); pc++; break; + case 0xff: sprintf (buffer,"rst $38"); flags = DASMFLAG_STEP_OVER; break; +#else + case 0x00: sprintf (buffer,"nop"); break; + case 0x01: sprintf (buffer,"lxi b,$%04x", ARGW(pc)); pc+=2; break; + case 0x02: sprintf (buffer,"stax b"); break; + case 0x03: sprintf (buffer,"inx b"); break; + case 0x04: sprintf (buffer,"inr b"); break; + case 0x05: sprintf (buffer,"dcr b"); break; + case 0x06: sprintf (buffer,"mvi b,$%02x", ARG(pc)); pc++; break; + case 0x07: sprintf (buffer,"rlc"); break; + case 0x08: sprintf (buffer,"dsub (*)"); break; + case 0x09: sprintf (buffer,"dad b"); break; + case 0x0a: sprintf (buffer,"ldax b"); break; + case 0x0b: sprintf (buffer,"dcx b"); break; + case 0x0c: sprintf (buffer,"inr c"); break; + case 0x0d: sprintf (buffer,"dcr c"); break; + case 0x0e: sprintf (buffer,"mvi c,$%02x", ARG(pc)); pc++; break; + case 0x0f: sprintf (buffer,"rrc"); break; + case 0x10: sprintf (buffer,"asrh (*)"); break; + case 0x11: sprintf (buffer,"lxi d,$%04x", ARGW(pc)); pc+=2; break; + case 0x12: sprintf (buffer,"stax d"); break; + case 0x13: sprintf (buffer,"inx d"); break; + case 0x14: sprintf (buffer,"inr d"); break; + case 0x15: sprintf (buffer,"dcr d"); break; + case 0x16: sprintf (buffer,"mvi d,$%02x", ARG(pc)); pc++; break; + case 0x17: sprintf (buffer,"ral"); break; + case 0x18: sprintf (buffer,"rlde (*)"); break; + case 0x19: sprintf (buffer,"dad d"); break; + case 0x1a: sprintf (buffer,"ldax d"); break; + case 0x1b: sprintf (buffer,"dcx d"); break; + case 0x1c: sprintf (buffer,"inr e"); break; + case 0x1d: sprintf (buffer,"dcr e"); break; + case 0x1e: sprintf (buffer,"mvi e,$%02x", ARG(pc)); pc++; break; + case 0x1f: sprintf (buffer,"rar"); break; + case 0x20: sprintf (buffer,"rim"); break; + case 0x21: sprintf (buffer,"lxi h,$%04x", ARGW(pc)); pc+=2; break; + case 0x22: sprintf (buffer,"shld $%04x", ARGW(pc)); pc+=2; break; + case 0x23: sprintf (buffer,"inx h"); break; + case 0x24: sprintf (buffer,"inr h"); break; + case 0x25: sprintf (buffer,"dcr h"); break; + case 0x26: sprintf (buffer,"mvi h,$%02x", ARG(pc)); pc++; break; + case 0x27: sprintf (buffer,"daa"); break; + case 0x28: sprintf (buffer,"ldeh $%02x (*)", ARG(pc)); pc++; break; + case 0x29: sprintf (buffer,"dad h"); break; + case 0x2a: sprintf (buffer,"lhld $%04x", ARGW(pc)); pc+=2; break; + case 0x2b: sprintf (buffer,"dcx h"); break; + case 0x2c: sprintf (buffer,"inr l"); break; + case 0x2d: sprintf (buffer,"dcr l"); break; + case 0x2e: sprintf (buffer,"mvi l,$%02x", ARG(pc)); pc++; break; + case 0x2f: sprintf (buffer,"cma"); break; + case 0x30: sprintf (buffer,"sim"); break; + case 0x31: sprintf (buffer,"lxi sp,$%04x", ARGW(pc)); pc+=2; break; + case 0x32: sprintf (buffer,"stax $%04x", ARGW(pc)); pc+=2; break; + case 0x33: sprintf (buffer,"inx sp"); break; + case 0x34: sprintf (buffer,"inr m"); break; + case 0x35: sprintf (buffer,"dcr m"); break; + case 0x36: sprintf (buffer,"mvi m,$%02x", ARG(pc)); pc++; break; + case 0x37: sprintf (buffer,"stc"); break; + case 0x38: sprintf (buffer,"ldes $%02x", ARG(pc)); pc++; break; + case 0x39: sprintf (buffer,"dad sp"); break; + case 0x3a: sprintf (buffer,"ldax $%04x", ARGW(pc)); pc+=2; break; + case 0x3b: sprintf (buffer,"dcx sp"); break; + case 0x3c: sprintf (buffer,"inr a"); break; + case 0x3d: sprintf (buffer,"dcr a"); break; + case 0x3e: sprintf (buffer,"mvi a,$%02x", ARG(pc)); pc++; break; + case 0x3f: sprintf (buffer,"cmf"); break; + case 0x40: sprintf (buffer,"mov b,b"); break; + case 0x41: sprintf (buffer,"mov b,c"); break; + case 0x42: sprintf (buffer,"mov b,d"); break; + case 0x43: sprintf (buffer,"mov b,e"); break; + case 0x44: sprintf (buffer,"mov b,h"); break; + case 0x45: sprintf (buffer,"mov b,l"); break; + case 0x46: sprintf (buffer,"mov b,m"); break; + case 0x47: sprintf (buffer,"mov b,a"); break; + case 0x48: sprintf (buffer,"mov c,b"); break; + case 0x49: sprintf (buffer,"mov c,c"); break; + case 0x4a: sprintf (buffer,"mov c,d"); break; + case 0x4b: sprintf (buffer,"mov c,e"); break; + case 0x4c: sprintf (buffer,"mov c,h"); break; + case 0x4d: sprintf (buffer,"mov c,l"); break; + case 0x4e: sprintf (buffer,"mov c,m"); break; + case 0x4f: sprintf (buffer,"mov c,a"); break; + case 0x50: sprintf (buffer,"mov d,b"); break; + case 0x51: sprintf (buffer,"mov d,c"); break; + case 0x52: sprintf (buffer,"mov d,d"); break; + case 0x53: sprintf (buffer,"mov d,e"); break; + case 0x54: sprintf (buffer,"mov d,h"); break; + case 0x55: sprintf (buffer,"mov d,l"); break; + case 0x56: sprintf (buffer,"mov d,m"); break; + case 0x57: sprintf (buffer,"mov d,a"); break; + case 0x58: sprintf (buffer,"mov e,b"); break; + case 0x59: sprintf (buffer,"mov e,c"); break; + case 0x5a: sprintf (buffer,"mov e,d"); break; + case 0x5b: sprintf (buffer,"mov e,e"); break; + case 0x5c: sprintf (buffer,"mov e,h"); break; + case 0x5d: sprintf (buffer,"mov e,l"); break; + case 0x5e: sprintf (buffer,"mov e,m"); break; + case 0x5f: sprintf (buffer,"mov e,a"); break; + case 0x60: sprintf (buffer,"mov h,b"); break; + case 0x61: sprintf (buffer,"mov h,c"); break; + case 0x62: sprintf (buffer,"mov h,d"); break; + case 0x63: sprintf (buffer,"mov h,e"); break; + case 0x64: sprintf (buffer,"mov h,h"); break; + case 0x65: sprintf (buffer,"mov h,l"); break; + case 0x66: sprintf (buffer,"mov h,m"); break; + case 0x67: sprintf (buffer,"mov h,a"); break; + case 0x68: sprintf (buffer,"mov l,b"); break; + case 0x69: sprintf (buffer,"mov l,c"); break; + case 0x6a: sprintf (buffer,"mov l,d"); break; + case 0x6b: sprintf (buffer,"mov l,e"); break; + case 0x6c: sprintf (buffer,"mov l,h"); break; + case 0x6d: sprintf (buffer,"mov l,l"); break; + case 0x6e: sprintf (buffer,"mov l,m"); break; + case 0x6f: sprintf (buffer,"mov l,a"); break; + case 0x70: sprintf (buffer,"mov m,b"); break; + case 0x71: sprintf (buffer,"mov m,c"); break; + case 0x72: sprintf (buffer,"mov m,d"); break; + case 0x73: sprintf (buffer,"mov m,e"); break; + case 0x74: sprintf (buffer,"mov m,h"); break; + case 0x75: sprintf (buffer,"mov m,l"); break; + case 0x76: sprintf (buffer,"hlt"); break; + case 0x77: sprintf (buffer,"mov m,a"); break; + case 0x78: sprintf (buffer,"mov a,b"); break; + case 0x79: sprintf (buffer,"mov a,c"); break; + case 0x7a: sprintf (buffer,"mov a,d"); break; + case 0x7b: sprintf (buffer,"mov a,e"); break; + case 0x7c: sprintf (buffer,"mov a,h"); break; + case 0x7d: sprintf (buffer,"mov a,l"); break; + case 0x7e: sprintf (buffer,"mov a,m"); break; + case 0x7f: sprintf (buffer,"mov a,a"); break; + case 0x80: sprintf (buffer,"add b"); break; + case 0x81: sprintf (buffer,"add c"); break; + case 0x82: sprintf (buffer,"add d"); break; + case 0x83: sprintf (buffer,"add e"); break; + case 0x84: sprintf (buffer,"add h"); break; + case 0x85: sprintf (buffer,"add l"); break; + case 0x86: sprintf (buffer,"add m"); break; + case 0x87: sprintf (buffer,"add a"); break; + case 0x88: sprintf (buffer,"adc b"); break; + case 0x89: sprintf (buffer,"adc c"); break; + case 0x8a: sprintf (buffer,"adc d"); break; + case 0x8b: sprintf (buffer,"adc e"); break; + case 0x8c: sprintf (buffer,"adc h"); break; + case 0x8d: sprintf (buffer,"adc l"); break; + case 0x8e: sprintf (buffer,"adc m"); break; + case 0x8f: sprintf (buffer,"adc a"); break; + case 0x90: sprintf (buffer,"sub b"); break; + case 0x91: sprintf (buffer,"sub c"); break; + case 0x92: sprintf (buffer,"sub d"); break; + case 0x93: sprintf (buffer,"sub e"); break; + case 0x94: sprintf (buffer,"sub h"); break; + case 0x95: sprintf (buffer,"sub l"); break; + case 0x96: sprintf (buffer,"sub m"); break; + case 0x97: sprintf (buffer,"sub a"); break; + case 0x98: sprintf (buffer,"sbb b"); break; + case 0x99: sprintf (buffer,"sbb c"); break; + case 0x9a: sprintf (buffer,"sbb d"); break; + case 0x9b: sprintf (buffer,"sbb e"); break; + case 0x9c: sprintf (buffer,"sbb h"); break; + case 0x9d: sprintf (buffer,"sbb l"); break; + case 0x9e: sprintf (buffer,"sbb m"); break; + case 0x9f: sprintf (buffer,"sbb a"); break; + case 0xa0: sprintf (buffer,"ana b"); break; + case 0xa1: sprintf (buffer,"ana c"); break; + case 0xa2: sprintf (buffer,"ana d"); break; + case 0xa3: sprintf (buffer,"ana e"); break; + case 0xa4: sprintf (buffer,"ana h"); break; + case 0xa5: sprintf (buffer,"ana l"); break; + case 0xa6: sprintf (buffer,"ana m"); break; + case 0xa7: sprintf (buffer,"ana a"); break; + case 0xa8: sprintf (buffer,"xra b"); break; + case 0xa9: sprintf (buffer,"xra c"); break; + case 0xaa: sprintf (buffer,"xra d"); break; + case 0xab: sprintf (buffer,"xra e"); break; + case 0xac: sprintf (buffer,"xra h"); break; + case 0xad: sprintf (buffer,"xra l"); break; + case 0xae: sprintf (buffer,"xra m"); break; + case 0xaf: sprintf (buffer,"xra a"); break; + case 0xb0: sprintf (buffer,"ora b"); break; + case 0xb1: sprintf (buffer,"ora c"); break; + case 0xb2: sprintf (buffer,"ora d"); break; + case 0xb3: sprintf (buffer,"ora e"); break; + case 0xb4: sprintf (buffer,"ora h"); break; + case 0xb5: sprintf (buffer,"ora l"); break; + case 0xb6: sprintf (buffer,"ora m"); break; + case 0xb7: sprintf (buffer,"ora a"); break; + case 0xb8: sprintf (buffer,"cmp b"); break; + case 0xb9: sprintf (buffer,"cmp c"); break; + case 0xba: sprintf (buffer,"cmp d"); break; + case 0xbb: sprintf (buffer,"cmp e"); break; + case 0xbc: sprintf (buffer,"cmp h"); break; + case 0xbd: sprintf (buffer,"cmp l"); break; + case 0xbe: sprintf (buffer,"cmp m"); break; + case 0xbf: sprintf (buffer,"cmp a"); break; + case 0xc0: sprintf (buffer,"rnz"); flags = DASMFLAG_STEP_OUT; break; + case 0xc1: sprintf (buffer,"pop b"); break; + case 0xc2: sprintf (buffer,"jnz $%04x", ARGW(pc)); pc+=2; break; + case 0xc3: sprintf (buffer,"jmp $%04x", ARGW(pc)); pc+=2; break; + case 0xc4: sprintf (buffer,"cnz $%04x", ARGW(pc)); pc+=2; flags = DASMFLAG_STEP_OVER; break; + case 0xc5: sprintf (buffer,"push b"); break; + case 0xc6: sprintf (buffer,"adi $%02x", ARG(pc)); pc++; break; + case 0xc7: sprintf (buffer,"rst 0"); flags = DASMFLAG_STEP_OVER; break; + case 0xc8: sprintf (buffer,"rz"); flags = DASMFLAG_STEP_OUT; break; + case 0xc9: sprintf (buffer,"ret"); flags = DASMFLAG_STEP_OUT; break; + case 0xca: sprintf (buffer,"jz $%04x", ARGW(pc)); pc+=2; break; + case 0xcb: sprintf (buffer,"rstv 8 (*)"); flags = DASMFLAG_STEP_OVER; break; + case 0xcc: sprintf (buffer,"cz $%04x", ARGW(pc)); pc+=2; flags = DASMFLAG_STEP_OVER; break; + case 0xcd: sprintf (buffer,"call $%04x", ARGW(pc)); pc+=2; flags = DASMFLAG_STEP_OVER; break; + case 0xce: sprintf (buffer,"aci $%02x", ARG(pc)); pc++; break; + case 0xcf: sprintf (buffer,"rst 1"); flags = DASMFLAG_STEP_OVER; break; + case 0xd0: sprintf (buffer,"rnc"); flags = DASMFLAG_STEP_OUT; break; + case 0xd1: sprintf (buffer,"pop d"); break; + case 0xd2: sprintf (buffer,"jnc $%04x", ARGW(pc)); pc+=2; break; + case 0xd3: sprintf (buffer,"out $%02x", ARG(pc)); pc++; break; + case 0xd4: sprintf (buffer,"cnc $%04x", ARGW(pc)); pc+=2; flags = DASMFLAG_STEP_OVER; break; + case 0xd5: sprintf (buffer,"push d"); break; + case 0xd6: sprintf (buffer,"sui $%02x", ARG(pc)); pc++; break; + case 0xd7: sprintf (buffer,"rst 2"); flags = DASMFLAG_STEP_OVER; break; + case 0xd8: sprintf (buffer,"rc"); flags = DASMFLAG_STEP_OUT; break; + case 0xd9: sprintf (buffer,"shlx d (*)"); break; + case 0xda: sprintf (buffer,"jc $%04x", ARGW(pc)); pc+=2; break; + case 0xdb: sprintf (buffer,"in $%02x", ARG(pc)); pc++; break; + case 0xdc: sprintf (buffer,"cc $%04x", ARGW(pc)); pc+=2; flags = DASMFLAG_STEP_OVER; break; + case 0xdd: sprintf (buffer,"jnx $%04x (*)", ARGW(pc)); pc+=2; break; + case 0xde: sprintf (buffer,"sbi $%02x", ARG(pc)); pc++; break; + case 0xdf: sprintf (buffer,"rst 3"); flags = DASMFLAG_STEP_OVER; break; + case 0xe0: sprintf (buffer,"rpo"); flags = DASMFLAG_STEP_OUT; break; + case 0xe1: sprintf (buffer,"pop h"); break; + case 0xe2: sprintf (buffer,"jpo $%04x", ARGW(pc)); pc+=2; break; + case 0xe3: sprintf (buffer,"xthl"); break; + case 0xe4: sprintf (buffer,"cpo $%04x", ARGW(pc)); pc+=2; flags = DASMFLAG_STEP_OVER; break; + case 0xe5: sprintf (buffer,"push h"); break; + case 0xe6: sprintf (buffer,"ani $%02x", ARG(pc)); pc++; break; + case 0xe7: sprintf (buffer,"rst 4"); flags = DASMFLAG_STEP_OVER; break; + case 0xe8: sprintf (buffer,"rpe"); flags = DASMFLAG_STEP_OUT; break; + case 0xe9: sprintf (buffer,"pchl"); break; + case 0xea: sprintf (buffer,"jpe $%04x", ARGW(pc)); pc+=2; break; + case 0xeb: sprintf (buffer,"xchg"); break; + case 0xec: sprintf (buffer,"cpe $%04x", ARGW(pc)); pc+=2; flags = DASMFLAG_STEP_OVER; break; + case 0xed: sprintf (buffer,"lhlx d (*)"); break; + case 0xee: sprintf (buffer,"xri $%02x", ARG(pc)); pc++; break; + case 0xef: sprintf (buffer,"rst 5"); flags = DASMFLAG_STEP_OVER; break; + case 0xf0: sprintf (buffer,"rp"); flags = DASMFLAG_STEP_OUT; break; + case 0xf1: sprintf (buffer,"pop a"); break; + case 0xf2: sprintf (buffer,"jp $%04x", ARGW(pc)); pc+=2; break; + case 0xf3: sprintf (buffer,"di"); break; + case 0xf4: sprintf (buffer,"cp $%04x", ARGW(pc)); pc+=2; break; + case 0xf5: sprintf (buffer,"push a"); break; + case 0xf6: sprintf (buffer,"ori $%02x", ARG(pc)); pc++; break; + case 0xf7: sprintf (buffer,"rst 6"); flags = DASMFLAG_STEP_OVER; break; + case 0xf8: sprintf (buffer,"rm"); flags = DASMFLAG_STEP_OUT; break; + case 0xf9: sprintf (buffer,"sphl"); break; + case 0xfa: sprintf (buffer,"jm $%04x", ARGW(pc)); pc+=2; break; + case 0xfb: sprintf (buffer,"ei"); break; + case 0xfc: sprintf (buffer,"cm $%04x", ARGW(pc)); pc+=2; flags = DASMFLAG_STEP_OVER; break; + case 0xfd: sprintf (buffer,"jx $%04x (*)", ARGW(pc)); pc+=2; break; + case 0xfe: sprintf (buffer,"cpi $%02x", ARG(pc)); pc++; break; + case 0xff: sprintf (buffer,"rst 7"); flags = DASMFLAG_STEP_OVER; break; +#endif + } + return (pc - PC) | flags | DASMFLAG_SUPPORTED; +} diff --git a/src/devices/cpu/i8085/i8085.c b/src/devices/cpu/i8085/i8085.c new file mode 100644 index 00000000000..3e278f64d6c --- /dev/null +++ b/src/devices/cpu/i8085/i8085.c @@ -0,0 +1,1097 @@ +// license:BSD-3-Clause +// copyright-holders:Juergen Buchmueller, hap +/***************************************************************************** + * + * i8085.c + * Portable I8085A emulator V1.2 + * + * Copyright Juergen Buchmueller, all rights reserved. + * Partially based on information out of Z80Em by Marcel De Kogel + * + * changes in V1.3 + * - Added undocumented opcodes for the 8085A, based on a german + * book about microcomputers: "Mikrocomputertechnik mit dem + * Prozessor 8085A". + * - This book also suggest that INX/DCX should modify the X flag bit + * for a LSB to MSB carry and + * - that jumps take 10 T-states only when they're executed, 7 when + * they're skipped. + * Thanks for the info and a copy of the tables go to Timo Sachsenberg + * + * changes in V1.2 + * - corrected cycle counts for these classes of opcodes + * Thanks go to Jim Battle + * + * 808x Z80 + * DEC A 5 4 \ + * INC A 5 4 \ + * LD A,B 5 4 >-- Z80 is faster + * JP (HL) 5 4 / + * CALL cc,nnnn: 11/17 10/17 / + * + * INC HL 5 6 \ + * DEC HL 5 6 \ + * LD SP,HL 5 6 \ + * ADD HL,BC 10 11 \ + * INC (HL) 10 11 >-- 8080 is faster + * DEC (HL) 10 11 / + * IN A,(#) 10 11 / + * OUT (#),A 10 11 / + * EX (SP),HL 18 19 / + * + * Revisions: + * + * xx-xx-2002 Acho A. Tang + * - 8085 emulation was in fact never used. It's been treated as a plain 8080. + * - protected IRQ0 vector from being overwritten + * - modified interrupt handler to properly process 8085-specific IRQ's + * - corrected interrupt masking, RIM and SIM behaviors according to Intel's documentation + * + * 20-Jul-2002 Krzysztof Strzecha + * - SBB r instructions should affect parity flag. + * Fixed only for non x86 asm version (#define i8080_EXACT 1). + * There are probably more opcodes which should affect this flag, but don't. + * - JPO nnnn and JPE nnnn opcodes in disassembler were misplaced. Fixed. + * - Undocumented i8080 opcodes added: + * 08h, 10h, 18h, 20h, 28h, 30h, 38h - NOP + * 0CBh - JMP + * 0D9h - RET + * 0DDh, 0EDh, 0FDh - CALL + * Thanks for the info go to Anton V. Ignatichev. + * + * 08-Dec-2002 Krzysztof Strzecha + * - ADC r instructions should affect parity flag. + * Fixed only for non x86 asm version (#define i8080_EXACT 1). + * There are probably more opcodes which should affect this flag, but don't. + * + * 05-Sep-2003 Krzysztof Strzecha + * - INR r, DCR r, ADD r, SUB r, CMP r instructions should affect parity flag. + * Fixed only for non x86 asm version (#define i8080_EXACT 1). + * + * 23-Dec-2006 Tomasz Slanina + * - SIM fixed + * + * 28-Jan-2007 Zsolt Vasvari + * - Removed archaic i8080_EXACT flag. + * + * 08-June-2008 Miodrag Milanovic + * - Flag setting fix for some instructions and cycle count update + * + * August 2009, hap + * - removed DAA table + * - fixed accidental double memory reads due to macro overuse + * - fixed cycle deduction on unconditional CALL / RET + * - added cycle tables and cleaned up big switch source layout (1 tab = 4 spaces) + * - removed HLT cycle eating (earlier, HLT after EI could theoretically fail) + * - fixed parity flag on add/sub/cmp + * - renamed temp register XX to official name WZ + * - renamed flags from Z80 style S Z Y H X V N C to S Z X5 H X3 P V C, and + * fixed X5 / V flags where accidentally broken due to flag names confusion + * + * 21-Aug-2009, Curt Coder + * - added 8080A variant + * - refactored callbacks to use devcb + * + * October 2012, hap + * - fixed H flag on subtraction opcodes + * - on 8080, don't push the unsupported flags(X5, X3, V) to stack + * - 8080 passes on 8080/8085 CPU Exerciser, 8085 errors only on the DAA test + * (ref: http://www.idb.me.uk/sunhillow/8080.html - tests only 8080 opcodes) + * + *****************************************************************************/ + +#include "emu.h" +#include "debugger.h" +#include "i8085.h" +#include "i8085cpu.h" + +#define VERBOSE 0 + +#define LOG(x) do { if (VERBOSE) logerror x; } while (0) + +#define CPUTYPE_8080 0 +#define CPUTYPE_8085 1 + + + +/*************************************************************************** + MACROS +***************************************************************************/ + +#define IS_8080() (m_cputype == CPUTYPE_8080) +#define IS_8085() (m_cputype == CPUTYPE_8085) + + + +/*************************************************************************** + STATIC TABLES +***************************************************************************/ + +/* cycles lookup */ +const UINT8 i8085a_cpu_device::lut_cycles_8080[256]={ +/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ +/* 0 */ 4, 10,7, 5, 5, 5, 7, 4, 4, 10,7, 5, 5, 5, 7, 4, +/* 1 */ 4, 10,7, 5, 5, 5, 7, 4, 4, 10,7, 5, 5, 5, 7, 4, +/* 2 */ 4, 10,16,5, 5, 5, 7, 4, 4, 10,16,5, 5, 5, 7, 4, +/* 3 */ 4, 10,13,5, 10,10,10,4, 4, 10,13,5, 5, 5, 7, 4, +/* 4 */ 5, 5, 5, 5, 5, 5, 7, 5, 5, 5, 5, 5, 5, 5, 7, 5, +/* 5 */ 5, 5, 5, 5, 5, 5, 7, 5, 5, 5, 5, 5, 5, 5, 7, 5, +/* 6 */ 5, 5, 5, 5, 5, 5, 7, 5, 5, 5, 5, 5, 5, 5, 7, 5, +/* 7 */ 7, 7, 7, 7, 7, 7, 7, 7, 5, 5, 5, 5, 5, 5, 7, 5, +/* 8 */ 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, +/* 9 */ 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, +/* A */ 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, +/* B */ 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, +/* C */ 5, 10,10,10,11,11,7, 11,5, 10,10,10,11,11,7, 11, +/* D */ 5, 10,10,10,11,11,7, 11,5, 10,10,10,11,11,7, 11, +/* E */ 5, 10,10,18,11,11,7, 11,5, 5, 10,5, 11,11,7, 11, +/* F */ 5, 10,10,4, 11,11,7, 11,5, 5, 10,4, 11,11,7, 11 }; +const UINT8 i8085a_cpu_device::lut_cycles_8085[256]={ +/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ +/* 0 */ 4, 10,7, 6, 4, 4, 7, 4, 10,10,7, 6, 4, 4, 7, 4, +/* 1 */ 7, 10,7, 6, 4, 4, 7, 4, 10,10,7, 6, 4, 4, 7, 4, +/* 2 */ 7, 10,16,6, 4, 4, 7, 4, 10,10,16,6, 4, 4, 7, 4, +/* 3 */ 7, 10,13,6, 10,10,10,4, 10,10,13,6, 4, 4, 7, 4, +/* 4 */ 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, +/* 5 */ 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, +/* 6 */ 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, +/* 7 */ 7, 7, 7, 7, 7, 7, 5, 7, 4, 4, 4, 4, 4, 4, 7, 4, +/* 8 */ 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, +/* 9 */ 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, +/* A */ 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, +/* B */ 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, +/* C */ 6, 10,10,10,11,12,7, 12,6, 10,10,12,11,11,7, 12, +/* D */ 6, 10,10,10,11,12,7, 12,6, 10,10,10,11,10,7, 12, +/* E */ 6, 10,10,16,11,12,7, 12,6, 6, 10,5, 11,10,7, 12, +/* F */ 6, 10,10,4, 11,12,7, 12,6, 6, 10,4, 11,10,7, 12 }; + +/* special cases (partially taken care of elsewhere): + base c taken? not taken? +M_RET 8080 5 +6(11) -0 (conditional) +M_RET 8085 6 +6(12) -0 (conditional) +M_JMP 8080 10 +0 -0 +M_JMP 8085 10 +0 -3(7) +M_CALL 8080 11 +6(17) -0 +M_CALL 8085 11 +7(18) -2(9) + +*/ + + +const device_type I8080 = &device_creator; +const device_type I8080A = &device_creator; +const device_type I8085A = &device_creator; + + +i8085a_cpu_device::i8085a_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : cpu_device(mconfig, I8085A, "8085A", tag, owner, clock, "i8085a", __FILE__) + , m_program_config("program", ENDIANNESS_LITTLE, 8, 16, 0) + , m_io_config("io", ENDIANNESS_LITTLE, 8, 8, 0) + , m_out_status_func(*this) + , m_out_inte_func(*this) + , m_in_sid_func(*this) + , m_out_sod_func(*this) + , m_cputype(CPUTYPE_8085) +{ +} + + +i8085a_cpu_device::i8085a_cpu_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source, int cputype) + : cpu_device(mconfig, type, name, tag, owner, clock, shortname, source) + , m_program_config("program", ENDIANNESS_LITTLE, 8, 16, 0) + , m_io_config("io", ENDIANNESS_LITTLE, 8, 8, 0) + , m_out_status_func(*this) + , m_out_inte_func(*this) + , m_in_sid_func(*this) + , m_out_sod_func(*this) + , m_cputype(cputype) +{ +} + + +i8080_cpu_device::i8080_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : i8085a_cpu_device(mconfig, I8080, "8080", tag, owner, clock, "i8080", __FILE__, CPUTYPE_8080) +{ +} + + +i8080a_cpu_device::i8080a_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : i8085a_cpu_device(mconfig, I8080A, "8080A", tag, owner, clock, "i8080a", __FILE__, CPUTYPE_8080) +{ +} + + +void i8085a_cpu_device::set_sod(int state) +{ + if (state != 0 && m_sod_state == 0) + { + m_sod_state = 1; + m_out_sod_func(m_sod_state); + } + else if (state == 0 && m_sod_state != 0) + { + m_sod_state = 0; + m_out_sod_func(m_sod_state); + } +} + + +void i8085a_cpu_device::set_inte(int state) +{ + if (state != 0 && (m_IM & IM_IE) == 0) + { + m_IM |= IM_IE; + m_out_inte_func(1); + } + else if (state == 0 && (m_IM & IM_IE) != 0) + { + m_IM &= ~IM_IE; + m_out_inte_func(0); + } +} + + +void i8085a_cpu_device::set_status(UINT8 status) +{ + if (status != m_STATUS) + m_out_status_func(status); + + m_STATUS = status; +} + + +UINT8 i8085a_cpu_device::get_rim_value() +{ + UINT8 result = m_IM; + int sid = m_in_sid_func(); + + /* copy live RST5.5 and RST6.5 states */ + result &= ~(IM_I65 | IM_I55); + if (m_irq_state[I8085_RST65_LINE]) result |= IM_I65; + if (m_irq_state[I8085_RST55_LINE]) result |= IM_I55; + + /* fetch the SID bit if we have a callback */ + result = (result & 0x7f) | (sid ? 0x80 : 0); + + return result; +} + + +void i8085a_cpu_device::break_halt_for_interrupt() +{ + /* de-halt if necessary */ + if (m_HALT) + { + m_PC.w.l++; + m_HALT = 0; + set_status(0x26); /* int ack while halt */ + } + else + set_status(0x23); /* int ack */ +} + + +UINT8 i8085a_cpu_device::ROP() +{ + set_status(0xa2); // instruction fetch + return m_direct->read_byte(m_PC.w.l++); +} + +UINT8 i8085a_cpu_device::ARG() +{ + return m_direct->read_byte(m_PC.w.l++); +} + +UINT16 i8085a_cpu_device::ARG16() +{ + UINT16 w; + w = m_direct->read_byte(m_PC.d); + m_PC.w.l++; + w += m_direct->read_byte(m_PC.d) << 8; + m_PC.w.l++; + return w; +} + +UINT8 i8085a_cpu_device::RM(UINT32 a) +{ + set_status(0x82); // memory read + return m_program->read_byte(a); +} + +void i8085a_cpu_device::WM(UINT32 a, UINT8 v) +{ + set_status(0x00); // memory write + m_program->write_byte(a, v); +} + + +void i8085a_cpu_device::check_for_interrupts() +{ + /* TRAP is the highest priority */ + if (m_trap_pending) + { + /* the first RIM after a TRAP reflects the original IE state; remember it here, + setting the high bit to indicate it is valid */ + m_trap_im_copy = m_IM | 0x80; + + /* reset the pending state */ + m_trap_pending = FALSE; + + /* break out of HALT state and call the IRQ ack callback */ + break_halt_for_interrupt(); + standard_irq_callback(INPUT_LINE_NMI); + + /* push the PC and jump to $0024 */ + M_PUSH(PC); + set_inte(0); + m_PC.w.l = ADDR_TRAP; + m_icount -= 11; + } + + /* followed by RST7.5 */ + else if ((m_IM & IM_I75) && !(m_IM & IM_M75) && (m_IM & IM_IE)) + { + /* reset the pending state (which is CPU-visible via the RIM instruction) */ + m_IM &= ~IM_I75; + + /* break out of HALT state and call the IRQ ack callback */ + break_halt_for_interrupt(); + standard_irq_callback(I8085_RST75_LINE); + + /* push the PC and jump to $003C */ + M_PUSH(PC); + set_inte(0); + m_PC.w.l = ADDR_RST75; + m_icount -= 11; + } + + /* followed by RST6.5 */ + else if (m_irq_state[I8085_RST65_LINE] && !(m_IM & IM_M65) && (m_IM & IM_IE)) + { + /* break out of HALT state and call the IRQ ack callback */ + break_halt_for_interrupt(); + standard_irq_callback(I8085_RST65_LINE); + + /* push the PC and jump to $0034 */ + M_PUSH(PC); + set_inte(0); + m_PC.w.l = ADDR_RST65; + m_icount -= 11; + } + + /* followed by RST5.5 */ + else if (m_irq_state[I8085_RST55_LINE] && !(m_IM & IM_M55) && (m_IM & IM_IE)) + { + /* break out of HALT state and call the IRQ ack callback */ + break_halt_for_interrupt(); + standard_irq_callback(I8085_RST55_LINE); + + /* push the PC and jump to $002C */ + M_PUSH(PC); + set_inte(0); + m_PC.w.l = ADDR_RST55; + m_icount -= 11; + } + + /* followed by classic INTR */ + else if (m_irq_state[I8085_INTR_LINE] && (m_IM & IM_IE)) + { + UINT32 vector = 0; + + /* break out of HALT state and call the IRQ ack callback */ + break_halt_for_interrupt(); + vector = standard_irq_callback(I8085_INTR_LINE); + + /* use the resulting vector as an opcode to execute */ + set_inte(0); + switch (vector & 0xff0000) + { + case 0xcd0000: /* CALL nnnn */ + m_icount -= 7; + M_PUSH(PC); + case 0xc30000: /* JMP nnnn */ + m_icount -= 10; + m_PC.d = vector & 0xffff; + break; + + default: + LOG(("i8085 take int $%02x\n", vector)); + execute_one(vector & 0xff); + break; + } + } +} + + +void i8085a_cpu_device::execute_one(int opcode) +{ + m_icount -= lut_cycles[opcode]; + + switch (opcode) + { + case 0x00: break; /* NOP */ + case 0x01: m_BC.w.l = ARG16(); break; /* LXI B,nnnn */ + case 0x02: WM(m_BC.d, m_AF.b.h); break; /* STAX B */ + case 0x03: m_BC.w.l++; /* INX B */ + if (IS_8085()) { if (m_BC.w.l == 0x0000) m_AF.b.l |= X5F; else m_AF.b.l &= ~X5F; } + break; + case 0x04: M_INR(m_BC.b.h); break; /* INR B */ + case 0x05: M_DCR(m_BC.b.h); break; /* DCR B */ + case 0x06: M_MVI(m_BC.b.h); break; /* MVI B,nn */ + case 0x07: M_RLC; break; /* RLC */ + + case 0x08: if (IS_8085()) { M_DSUB(); } /* DSUB */ + /* else { ; } */ /* NOP undocumented */ + break; + case 0x09: M_DAD(BC); break; /* DAD B */ + case 0x0a: m_AF.b.h = RM(m_BC.d); break; /* LDAX B */ + case 0x0b: m_BC.w.l--; /* DCX B */ + if (IS_8085()) { if (m_BC.w.l == 0xffff) m_AF.b.l |= X5F; else m_AF.b.l &= ~X5F; } + break; + case 0x0c: M_INR(m_BC.b.l); break; /* INR C */ + case 0x0d: M_DCR(m_BC.b.l); break; /* DCR C */ + case 0x0e: M_MVI(m_BC.b.l); break; /* MVI C,nn */ + case 0x0f: M_RRC; break; /* RRC */ + + case 0x10: if (IS_8085()) { /* ASRH */ + m_AF.b.l = (m_AF.b.l & ~CF) | (m_HL.b.l & CF); + m_HL.w.l = (m_HL.w.l >> 1); + } /* else { ; } */ /* NOP undocumented */ + break; + case 0x11: m_DE.w.l = ARG16(); break; /* LXI D,nnnn */ + case 0x12: WM(m_DE.d, m_AF.b.h); break; /* STAX D */ + case 0x13: m_DE.w.l++; /* INX D */ + if (IS_8085()) { if (m_DE.w.l == 0x0000) m_AF.b.l |= X5F; else m_AF.b.l &= ~X5F; } + break; + case 0x14: M_INR(m_DE.b.h); break; /* INR D */ + case 0x15: M_DCR(m_DE.b.h); break; /* DCR D */ + case 0x16: M_MVI(m_DE.b.h); break; /* MVI D,nn */ + case 0x17: M_RAL; break; /* RAL */ + + case 0x18: if (IS_8085()) { /* RLDE */ + m_AF.b.l = (m_AF.b.l & ~(CF | VF)) | (m_DE.b.h >> 7); + m_DE.w.l = (m_DE.w.l << 1) | (m_DE.w.l >> 15); + if (0 != (((m_DE.w.l >> 15) ^ m_AF.b.l) & CF)) m_AF.b.l |= VF; + } /* else { ; } */ /* NOP undocumented */ + break; + case 0x19: M_DAD(DE); break; /* DAD D */ + case 0x1a: m_AF.b.h = RM(m_DE.d); break; /* LDAX D */ + case 0x1b: m_DE.w.l--; /* DCX D */ + if (IS_8085()) { if (m_DE.w.l == 0xffff) m_AF.b.l |= X5F; else m_AF.b.l &= ~X5F; } + break; + case 0x1c: M_INR(m_DE.b.l); break; /* INR E */ + case 0x1d: M_DCR(m_DE.b.l); break; /* DCR E */ + case 0x1e: M_MVI(m_DE.b.l); break; /* MVI E,nn */ + case 0x1f: M_RAR; break; /* RAR */ + + case 0x20: if (IS_8085()) { /* RIM */ + m_AF.b.h = get_rim_value(); + + /* if we have remembered state from taking a TRAP, fix up the IE flag here */ + if (m_trap_im_copy & 0x80) m_AF.b.h = (m_AF.b.h & ~IM_IE) | (m_trap_im_copy & IM_IE); + m_trap_im_copy = 0; + } /* else { ; } */ /* NOP undocumented */ + break; + case 0x21: m_HL.w.l = ARG16(); break; /* LXI H,nnnn */ + case 0x22: m_WZ.w.l = ARG16(); /* SHLD nnnn */ + WM(m_WZ.d, m_HL.b.l); m_WZ.w.l++; + WM(m_WZ.d, m_HL.b.h); + break; + case 0x23: m_HL.w.l++; /* INX H */ + if (IS_8085()) { if (m_HL.w.l == 0x0000) m_AF.b.l |= X5F; else m_AF.b.l &= ~X5F; } + break; + case 0x24: M_INR(m_HL.b.h); break; /* INR H */ + case 0x25: M_DCR(m_HL.b.h); break; /* DCR H */ + case 0x26: M_MVI(m_HL.b.h); break; /* MVI H,nn */ + case 0x27: m_WZ.b.h = m_AF.b.h; /* DAA */ + if (IS_8085() && m_AF.b.l&VF) { + if ((m_AF.b.l&HF) | ((m_AF.b.h&0xf)>9)) m_WZ.b.h-=6; + if ((m_AF.b.l&CF) | (m_AF.b.h>0x99)) m_WZ.b.h-=0x60; + } + else { + if ((m_AF.b.l&HF) | ((m_AF.b.h&0xf)>9)) m_WZ.b.h+=6; + if ((m_AF.b.l&CF) | (m_AF.b.h>0x99)) m_WZ.b.h+=0x60; + } + + m_AF.b.l=(m_AF.b.l&3) | (m_AF.b.h&0x28) | (m_AF.b.h>0x99) | ((m_AF.b.h^m_WZ.b.h)&0x10) | ZSP[m_WZ.b.h]; + m_AF.b.h=m_WZ.b.h; + break; + + case 0x28: if (IS_8085()) { /* LDEH nn */ + m_WZ.d = ARG(); + m_DE.d = (m_HL.d + m_WZ.d) & 0xffff; + } /* else { ; } */ /* NOP undocumented */ + break; + case 0x29: M_DAD(HL); break; /* DAD H */ + case 0x2a: m_WZ.d = ARG16(); /* LHLD nnnn */ + m_HL.b.l = RM(m_WZ.d); m_WZ.w.l++; + m_HL.b.h = RM(m_WZ.d); + break; + case 0x2b: m_HL.w.l--; /* DCX H */ + if (IS_8085()) { if (m_HL.w.l == 0xffff) m_AF.b.l |= X5F; else m_AF.b.l &= ~X5F; } + break; + case 0x2c: M_INR(m_HL.b.l); break; /* INR L */ + case 0x2d: M_DCR(m_HL.b.l); break; /* DCR L */ + case 0x2e: M_MVI(m_HL.b.l); break; /* MVI L,nn */ + case 0x2f: m_AF.b.h ^= 0xff; /* CMA */ + if (IS_8085()) m_AF.b.l |= HF | VF; + break; + + case 0x30: if (IS_8085()) { /* SIM */ + /* if bit 3 is set, bits 0-2 become the new masks */ + if (m_AF.b.h & 0x08) { + m_IM &= ~(IM_M55 | IM_M65 | IM_M75 | IM_I55 | IM_I65); + m_IM |= m_AF.b.h & (IM_M55 | IM_M65 | IM_M75); + + /* update live state based on the new masks */ + if ((m_IM & IM_M55) == 0 && m_irq_state[I8085_RST55_LINE]) m_IM |= IM_I55; + if ((m_IM & IM_M65) == 0 && m_irq_state[I8085_RST65_LINE]) m_IM |= IM_I65; + } + + /* bit if 4 is set, the 7.5 flip-flop is cleared */ + if (m_AF.b.h & 0x10) m_IM &= ~IM_I75; + + /* if bit 6 is set, then bit 7 is the new SOD state */ + if (m_AF.b.h & 0x40) set_sod(m_AF.b.h >> 7); + + /* check for revealed interrupts */ + check_for_interrupts(); + } /* else { ; } */ /* NOP undocumented */ + break; + case 0x31: m_SP.w.l = ARG16(); break; /* LXI SP,nnnn */ + case 0x32: m_WZ.d = ARG16(); /* STAX nnnn */ + WM(m_WZ.d, m_AF.b.h); + break; + case 0x33: m_SP.w.l++; /* INX SP */ + if (IS_8085()) { if (m_SP.w.l == 0x0000) m_AF.b.l |= X5F; else m_AF.b.l &= ~X5F; } + break; + case 0x34: m_WZ.b.l = RM(m_HL.d); /* INR M */ + M_INR(m_WZ.b.l); + WM(m_HL.d, m_WZ.b.l); + break; + case 0x35: m_WZ.b.l = RM(m_HL.d); /* DCR M */ + M_DCR(m_WZ.b.l); + WM(m_HL.d, m_WZ.b.l); + break; + case 0x36: m_WZ.b.l = ARG(); /* MVI M,nn */ + WM(m_HL.d, m_WZ.b.l); + break; + case 0x37: m_AF.b.l = (m_AF.b.l & 0xfe) | CF; break; /* STC */ + + case 0x38: if (IS_8085()) { /* LDES nn */ + m_WZ.d = ARG(); + m_DE.d = (m_SP.d + m_WZ.d) & 0xffff; + } /* else { ; } */ /* NOP undocumented */ + break; + case 0x39: M_DAD(SP); break; /* DAD SP */ + case 0x3a: m_WZ.d = ARG16(); /* LDAX nnnn */ + m_AF.b.h = RM(m_WZ.d); + break; + case 0x3b: m_SP.w.l--; /* DCX SP */ + if (IS_8085()) { if (m_SP.w.l == 0xffff) m_AF.b.l |= X5F; else m_AF.b.l &= ~X5F; } + break; + case 0x3c: M_INR(m_AF.b.h); break; /* INR A */ + case 0x3d: M_DCR(m_AF.b.h); break; /* DCR A */ + case 0x3e: M_MVI(m_AF.b.h); break; /* MVI A,nn */ + case 0x3f: m_AF.b.l = (m_AF.b.l & 0xfe) | (~m_AF.b.l & CF); break; /* CMC */ + + case 0x40: break; /* MOV B,B */ + case 0x41: m_BC.b.h = m_BC.b.l; break; /* MOV B,C */ + case 0x42: m_BC.b.h = m_DE.b.h; break; /* MOV B,D */ + case 0x43: m_BC.b.h = m_DE.b.l; break; /* MOV B,E */ + case 0x44: m_BC.b.h = m_HL.b.h; break; /* MOV B,H */ + case 0x45: m_BC.b.h = m_HL.b.l; break; /* MOV B,L */ + case 0x46: m_BC.b.h = RM(m_HL.d); break; /* MOV B,M */ + case 0x47: m_BC.b.h = m_AF.b.h; break; /* MOV B,A */ + + case 0x48: m_BC.b.l = m_BC.b.h; break; /* MOV C,B */ + case 0x49: break; /* MOV C,C */ + case 0x4a: m_BC.b.l = m_DE.b.h; break; /* MOV C,D */ + case 0x4b: m_BC.b.l = m_DE.b.l; break; /* MOV C,E */ + case 0x4c: m_BC.b.l = m_HL.b.h; break; /* MOV C,H */ + case 0x4d: m_BC.b.l = m_HL.b.l; break; /* MOV C,L */ + case 0x4e: m_BC.b.l = RM(m_HL.d); break; /* MOV C,M */ + case 0x4f: m_BC.b.l = m_AF.b.h; break; /* MOV C,A */ + + case 0x50: m_DE.b.h = m_BC.b.h; break; /* MOV D,B */ + case 0x51: m_DE.b.h = m_BC.b.l; break; /* MOV D,C */ + case 0x52: break; /* MOV D,D */ + case 0x53: m_DE.b.h = m_DE.b.l; break; /* MOV D,E */ + case 0x54: m_DE.b.h = m_HL.b.h; break; /* MOV D,H */ + case 0x55: m_DE.b.h = m_HL.b.l; break; /* MOV D,L */ + case 0x56: m_DE.b.h = RM(m_HL.d); break; /* MOV D,M */ + case 0x57: m_DE.b.h = m_AF.b.h; break; /* MOV D,A */ + + case 0x58: m_DE.b.l = m_BC.b.h; break; /* MOV E,B */ + case 0x59: m_DE.b.l = m_BC.b.l; break; /* MOV E,C */ + case 0x5a: m_DE.b.l = m_DE.b.h; break; /* MOV E,D */ + case 0x5b: break; /* MOV E,E */ + case 0x5c: m_DE.b.l = m_HL.b.h; break; /* MOV E,H */ + case 0x5d: m_DE.b.l = m_HL.b.l; break; /* MOV E,L */ + case 0x5e: m_DE.b.l = RM(m_HL.d); break; /* MOV E,M */ + case 0x5f: m_DE.b.l = m_AF.b.h; break; /* MOV E,A */ + + case 0x60: m_HL.b.h = m_BC.b.h; break; /* MOV H,B */ + case 0x61: m_HL.b.h = m_BC.b.l; break; /* MOV H,C */ + case 0x62: m_HL.b.h = m_DE.b.h; break; /* MOV H,D */ + case 0x63: m_HL.b.h = m_DE.b.l; break; /* MOV H,E */ + case 0x64: break; /* MOV H,H */ + case 0x65: m_HL.b.h = m_HL.b.l; break; /* MOV H,L */ + case 0x66: m_HL.b.h = RM(m_HL.d); break; /* MOV H,M */ + case 0x67: m_HL.b.h = m_AF.b.h; break; /* MOV H,A */ + + case 0x68: m_HL.b.l = m_BC.b.h; break; /* MOV L,B */ + case 0x69: m_HL.b.l = m_BC.b.l; break; /* MOV L,C */ + case 0x6a: m_HL.b.l = m_DE.b.h; break; /* MOV L,D */ + case 0x6b: m_HL.b.l = m_DE.b.l; break; /* MOV L,E */ + case 0x6c: m_HL.b.l = m_HL.b.h; break; /* MOV L,H */ + case 0x6d: break; /* MOV L,L */ + case 0x6e: m_HL.b.l = RM(m_HL.d); break; /* MOV L,M */ + case 0x6f: m_HL.b.l = m_AF.b.h; break; /* MOV L,A */ + + case 0x70: WM(m_HL.d, m_BC.b.h); break; /* MOV M,B */ + case 0x71: WM(m_HL.d, m_BC.b.l); break; /* MOV M,C */ + case 0x72: WM(m_HL.d, m_DE.b.h); break; /* MOV M,D */ + case 0x73: WM(m_HL.d, m_DE.b.l); break; /* MOV M,E */ + case 0x74: WM(m_HL.d, m_HL.b.h); break; /* MOV M,H */ + case 0x75: WM(m_HL.d, m_HL.b.l); break; /* MOV M,L */ + case 0x76: m_PC.w.l--; m_HALT = 1; /* HLT */ + set_status(0x8a); // halt acknowledge + break; + case 0x77: WM(m_HL.d, m_AF.b.h); break; /* MOV M,A */ + + case 0x78: m_AF.b.h = m_BC.b.h; break; /* MOV A,B */ + case 0x79: m_AF.b.h = m_BC.b.l; break; /* MOV A,C */ + case 0x7a: m_AF.b.h = m_DE.b.h; break; /* MOV A,D */ + case 0x7b: m_AF.b.h = m_DE.b.l; break; /* MOV A,E */ + case 0x7c: m_AF.b.h = m_HL.b.h; break; /* MOV A,H */ + case 0x7d: m_AF.b.h = m_HL.b.l; break; /* MOV A,L */ + case 0x7e: m_AF.b.h = RM(m_HL.d); break; /* MOV A,M */ + case 0x7f: break; /* MOV A,A */ + + case 0x80: M_ADD(m_BC.b.h); break; /* ADD B */ + case 0x81: M_ADD(m_BC.b.l); break; /* ADD C */ + case 0x82: M_ADD(m_DE.b.h); break; /* ADD D */ + case 0x83: M_ADD(m_DE.b.l); break; /* ADD E */ + case 0x84: M_ADD(m_HL.b.h); break; /* ADD H */ + case 0x85: M_ADD(m_HL.b.l); break; /* ADD L */ + case 0x86: m_WZ.b.l = RM(m_HL.d); M_ADD(m_WZ.b.l); break; /* ADD M */ + case 0x87: M_ADD(m_AF.b.h); break; /* ADD A */ + + case 0x88: M_ADC(m_BC.b.h); break; /* ADC B */ + case 0x89: M_ADC(m_BC.b.l); break; /* ADC C */ + case 0x8a: M_ADC(m_DE.b.h); break; /* ADC D */ + case 0x8b: M_ADC(m_DE.b.l); break; /* ADC E */ + case 0x8c: M_ADC(m_HL.b.h); break; /* ADC H */ + case 0x8d: M_ADC(m_HL.b.l); break; /* ADC L */ + case 0x8e: m_WZ.b.l = RM(m_HL.d); M_ADC(m_WZ.b.l); break; /* ADC M */ + case 0x8f: M_ADC(m_AF.b.h); break; /* ADC A */ + + case 0x90: M_SUB(m_BC.b.h); break; /* SUB B */ + case 0x91: M_SUB(m_BC.b.l); break; /* SUB C */ + case 0x92: M_SUB(m_DE.b.h); break; /* SUB D */ + case 0x93: M_SUB(m_DE.b.l); break; /* SUB E */ + case 0x94: M_SUB(m_HL.b.h); break; /* SUB H */ + case 0x95: M_SUB(m_HL.b.l); break; /* SUB L */ + case 0x96: m_WZ.b.l = RM(m_HL.d); M_SUB(m_WZ.b.l); break; /* SUB M */ + case 0x97: M_SUB(m_AF.b.h); break; /* SUB A */ + + case 0x98: M_SBB(m_BC.b.h); break; /* SBB B */ + case 0x99: M_SBB(m_BC.b.l); break; /* SBB C */ + case 0x9a: M_SBB(m_DE.b.h); break; /* SBB D */ + case 0x9b: M_SBB(m_DE.b.l); break; /* SBB E */ + case 0x9c: M_SBB(m_HL.b.h); break; /* SBB H */ + case 0x9d: M_SBB(m_HL.b.l); break; /* SBB L */ + case 0x9e: m_WZ.b.l = RM(m_HL.d); M_SBB(m_WZ.b.l); break; /* SBB M */ + case 0x9f: M_SBB(m_AF.b.h); break; /* SBB A */ + + case 0xa0: M_ANA(m_BC.b.h); break; /* ANA B */ + case 0xa1: M_ANA(m_BC.b.l); break; /* ANA C */ + case 0xa2: M_ANA(m_DE.b.h); break; /* ANA D */ + case 0xa3: M_ANA(m_DE.b.l); break; /* ANA E */ + case 0xa4: M_ANA(m_HL.b.h); break; /* ANA H */ + case 0xa5: M_ANA(m_HL.b.l); break; /* ANA L */ + case 0xa6: m_WZ.b.l = RM(m_HL.d); M_ANA(m_WZ.b.l); break; /* ANA M */ + case 0xa7: M_ANA(m_AF.b.h); break; /* ANA A */ + + case 0xa8: M_XRA(m_BC.b.h); break; /* XRA B */ + case 0xa9: M_XRA(m_BC.b.l); break; /* XRA C */ + case 0xaa: M_XRA(m_DE.b.h); break; /* XRA D */ + case 0xab: M_XRA(m_DE.b.l); break; /* XRA E */ + case 0xac: M_XRA(m_HL.b.h); break; /* XRA H */ + case 0xad: M_XRA(m_HL.b.l); break; /* XRA L */ + case 0xae: m_WZ.b.l = RM(m_HL.d); M_XRA(m_WZ.b.l); break; /* XRA M */ + case 0xaf: M_XRA(m_AF.b.h); break; /* XRA A */ + + case 0xb0: M_ORA(m_BC.b.h); break; /* ORA B */ + case 0xb1: M_ORA(m_BC.b.l); break; /* ORA C */ + case 0xb2: M_ORA(m_DE.b.h); break; /* ORA D */ + case 0xb3: M_ORA(m_DE.b.l); break; /* ORA E */ + case 0xb4: M_ORA(m_HL.b.h); break; /* ORA H */ + case 0xb5: M_ORA(m_HL.b.l); break; /* ORA L */ + case 0xb6: m_WZ.b.l = RM(m_HL.d); M_ORA(m_WZ.b.l); break; /* ORA M */ + case 0xb7: M_ORA(m_AF.b.h); break; /* ORA A */ + + case 0xb8: M_CMP(m_BC.b.h); break; /* CMP B */ + case 0xb9: M_CMP(m_BC.b.l); break; /* CMP C */ + case 0xba: M_CMP(m_DE.b.h); break; /* CMP D */ + case 0xbb: M_CMP(m_DE.b.l); break; /* CMP E */ + case 0xbc: M_CMP(m_HL.b.h); break; /* CMP H */ + case 0xbd: M_CMP(m_HL.b.l); break; /* CMP L */ + case 0xbe: m_WZ.b.l = RM(m_HL.d); M_CMP(m_WZ.b.l); break; /* CMP M */ + case 0xbf: M_CMP(m_AF.b.h); break; /* CMP A */ + + case 0xc0: M_RET( !(m_AF.b.l & ZF) ); break; /* RNZ */ + case 0xc1: M_POP(BC); break; /* POP B */ + case 0xc2: M_JMP( !(m_AF.b.l & ZF) ); break; /* JNZ nnnn */ + case 0xc3: M_JMP(1); break; /* JMP nnnn */ + case 0xc4: M_CALL( !(m_AF.b.l & ZF) ); break; /* CNZ nnnn */ + case 0xc5: M_PUSH(BC); break; /* PUSH B */ + case 0xc6: m_WZ.b.l = ARG(); M_ADD(m_WZ.b.l); break; /* ADI nn */ + case 0xc7: M_RST(0); break; /* RST 0 */ + + case 0xc8: M_RET( m_AF.b.l & ZF ); break; /* RZ */ + case 0xc9: M_POP(PC); break; /* RET */ + case 0xca: M_JMP( m_AF.b.l & ZF ); break; /* JZ nnnn */ + case 0xcb: if (IS_8085()) { /* RST V */ + if (m_AF.b.l & VF) { M_RST(8); } + else m_icount += 6; // RST not taken + } else { M_JMP(1); } /* JMP nnnn undocumented */ + break; + case 0xcc: M_CALL( m_AF.b.l & ZF ); break; /* CZ nnnn */ + case 0xcd: M_CALL(1); break; /* CALL nnnn */ + case 0xce: m_WZ.b.l = ARG(); M_ADC(m_WZ.b.l); break; /* ACI nn */ + case 0xcf: M_RST(1); break; /* RST 1 */ + + case 0xd0: M_RET( !(m_AF.b.l & CF) ); break; /* RNC */ + case 0xd1: M_POP(DE); break; /* POP D */ + case 0xd2: M_JMP( !(m_AF.b.l & CF) ); break; /* JNC nnnn */ + case 0xd3: M_OUT; break; /* OUT nn */ + case 0xd4: M_CALL( !(m_AF.b.l & CF) ); break; /* CNC nnnn */ + case 0xd5: M_PUSH(DE); break; /* PUSH D */ + case 0xd6: m_WZ.b.l = ARG(); M_SUB(m_WZ.b.l); break; /* SUI nn */ + case 0xd7: M_RST(2); break; /* RST 2 */ + + case 0xd8: M_RET( m_AF.b.l & CF ); break; /* RC */ + case 0xd9: if (IS_8085()) { /* SHLX */ + m_WZ.w.l = m_DE.w.l; + WM(m_WZ.d, m_HL.b.l); m_WZ.w.l++; + WM(m_WZ.d, m_HL.b.h); + } else { M_POP(PC); } /* RET undocumented */ + break; + case 0xda: M_JMP( m_AF.b.l & CF ); break; /* JC nnnn */ + case 0xdb: M_IN; break; /* IN nn */ + case 0xdc: M_CALL( m_AF.b.l & CF ); break; /* CC nnnn */ + case 0xdd: if (IS_8085()) { M_JMP( !(m_AF.b.l & X5F) ); } /* JNX nnnn */ + else { M_CALL(1); } /* CALL nnnn undocumented */ + break; + case 0xde: m_WZ.b.l = ARG(); M_SBB(m_WZ.b.l); break; /* SBI nn */ + case 0xdf: M_RST(3); break; /* RST 3 */ + + case 0xe0: M_RET( !(m_AF.b.l & PF) ); break; /* RPO */ + case 0xe1: M_POP(HL); break; /* POP H */ + case 0xe2: M_JMP( !(m_AF.b.l & PF) ); break; /* JPO nnnn */ + case 0xe3: M_POP(WZ); M_PUSH(HL); /* XTHL */ + m_HL.d = m_WZ.d; + break; + case 0xe4: M_CALL( !(m_AF.b.l & PF) ); break; /* CPO nnnn */ + case 0xe5: M_PUSH(HL); break; /* PUSH H */ + case 0xe6: m_WZ.b.l = ARG(); M_ANA(m_WZ.b.l); break; /* ANI nn */ + case 0xe7: M_RST(4); break; /* RST 4 */ + + case 0xe8: M_RET( m_AF.b.l & PF ); break; /* RPE */ + case 0xe9: m_PC.d = m_HL.w.l; break; /* PCHL */ + case 0xea: M_JMP( m_AF.b.l & PF ); break; /* JPE nnnn */ + case 0xeb: m_WZ.d = m_DE.d; /* XCHG */ + m_DE.d = m_HL.d; + m_HL.d = m_WZ.d; + break; + case 0xec: M_CALL( m_AF.b.l & PF ); break; /* CPE nnnn */ + case 0xed: if (IS_8085()) { /* LHLX */ + m_WZ.w.l = m_DE.w.l; + m_HL.b.l = RM(m_WZ.d); m_WZ.w.l++; + m_HL.b.h = RM(m_WZ.d); + } else { M_CALL(1); } /* CALL nnnn undocumented */ + break; + case 0xee: m_WZ.b.l = ARG(); M_XRA(m_WZ.b.l); break; /* XRI nn */ + case 0xef: M_RST(5); break; /* RST 5 */ + + case 0xf0: M_RET( !(m_AF.b.l&SF) ); break; /* RP */ + case 0xf1: M_POP(AF); break; /* POP A */ + case 0xf2: M_JMP( !(m_AF.b.l & SF) ); break; /* JP nnnn */ + case 0xf3: set_inte(0); break; /* DI */ + case 0xf4: M_CALL( !(m_AF.b.l & SF) ); break; /* CP nnnn */ + case 0xf5: if (IS_8080()) m_AF.b.l = (m_AF.b.l&~(X3F|X5F))|VF; // on 8080, VF=1 and X3F=0 and X5F=0 always! (we don't have to check for it elsewhere) + M_PUSH(AF); break; /* PUSH A */ + case 0xf6: m_WZ.b.l = ARG(); M_ORA(m_WZ.b.l); break; /* ORI nn */ + case 0xf7: M_RST(6); break; /* RST 6 */ + + case 0xf8: M_RET( m_AF.b.l & SF ); break; /* RM */ + case 0xf9: m_SP.d = m_HL.d; break; /* SPHL */ + case 0xfa: M_JMP( m_AF.b.l & SF ); break; /* JM nnnn */ + case 0xfb: set_inte(1); m_after_ei = 2; break; /* EI */ + case 0xfc: M_CALL( m_AF.b.l & SF ); break; /* CM nnnn */ + case 0xfd: if (IS_8085()) { M_JMP( m_AF.b.l & X5F ); } /* JX nnnn */ + else { M_CALL(1); } /* CALL nnnn undocumented */ + break; + case 0xfe: m_WZ.b.l = ARG(); M_CMP(m_WZ.b.l); break; /* CPI nn */ + case 0xff: M_RST(7); break; /* RST 7 */ + } +} + + +/*************************************************************************** + COMMON EXECUTION +***************************************************************************/ + +void i8085a_cpu_device::execute_run() +{ + /* check for TRAPs before diving in (can't do others because of after_ei) */ + if (m_trap_pending || m_after_ei == 0) + check_for_interrupts(); + + do + { + debugger_instruction_hook(this, m_PC.d); + + /* the instruction after an EI does not take an interrupt, so + we cannot check immediately; handle post-EI behavior here */ + if (m_after_ei != 0 && --m_after_ei == 0) + check_for_interrupts(); + + /* here we go... */ + execute_one(ROP()); + + } while (m_icount > 0); +} + + + +/*************************************************************************** + CORE INITIALIZATION +***************************************************************************/ + +void i8085a_cpu_device::init_tables() +{ + UINT8 zs; + int i, p; + for (i = 0; i < 256; i++) + { + /* cycles */ + lut_cycles[i] = m_cputype?lut_cycles_8085[i]:lut_cycles_8080[i]; + + /* flags */ + zs = 0; + if (i==0) zs |= ZF; + if (i&128) zs |= SF; + p = 0; + if (i&1) ++p; + if (i&2) ++p; + if (i&4) ++p; + if (i&8) ++p; + if (i&16) ++p; + if (i&32) ++p; + if (i&64) ++p; + if (i&128) ++p; + ZS[i] = zs; + ZSP[i] = zs | ((p&1) ? 0 : PF); + } +} + + +void i8085a_cpu_device::device_start() +{ + m_PC.d = 0; + m_SP.d = 0; + m_AF.d = 0; + m_BC.d = 0; + m_DE.d = 0; + m_HL.d = 0; + m_WZ.d = 0; + m_HALT = 0; + m_IM = 0; + m_STATUS = 0; + m_after_ei = 0; + m_nmi_state = 0; + m_irq_state[3] = m_irq_state[2] = m_irq_state[1] = m_irq_state[0] = 0; + m_trap_pending = 0; + m_trap_im_copy = 0; + m_sod_state = 0; + m_ietemp = 0; + + init_tables(); + + /* set up the state table */ + { + state_add(I8085_PC, "PC", m_PC.w.l); + state_add(STATE_GENPC, "GENPC", m_PC.w.l).noshow(); + state_add(I8085_SP, "SP", m_SP.w.l); + state_add(STATE_GENSP, "GENSP", m_SP.w.l).noshow(); + state_add(STATE_GENFLAGS, "GENFLAGS", m_AF.b.l).noshow().formatstr("%8s"); + state_add(I8085_A, "A", m_AF.b.h).noshow(); + state_add(I8085_B, "B", m_BC.b.h).noshow(); + state_add(I8085_C, "C", m_BC.b.l).noshow(); + state_add(I8085_D, "D", m_DE.b.h).noshow(); + state_add(I8085_E, "E", m_DE.b.l).noshow(); + state_add(I8085_F, "F", m_AF.b.l).noshow(); + state_add(I8085_H, "H", m_HL.b.h).noshow(); + state_add(I8085_L, "L", m_HL.b.l).noshow(); + state_add(I8085_AF, "AF", m_AF.w.l); + state_add(I8085_BC, "BC", m_BC.w.l); + state_add(I8085_DE, "DE", m_DE.w.l); + state_add(I8085_HL, "HL", m_HL.w.l); + state_add(I8085_STATUS, "STATUS", m_STATUS); + state_add(I8085_SOD, "SOD", m_sod_state).mask(0x1); + state_add(I8085_SID, "SID", m_ietemp).mask(0x1).callimport().callexport(); + state_add(I8085_INTE, "INTE", m_ietemp).mask(0x1).callimport().callexport(); + } + + m_program = &space(AS_PROGRAM); + m_direct = &m_program->direct(); + m_io = &space(AS_IO); + + /* resolve callbacks */ + m_out_status_func.resolve_safe(); + m_out_inte_func.resolve_safe(); + m_in_sid_func.resolve_safe(0); + m_out_sod_func.resolve_safe(); + + /* register for state saving */ + save_item(NAME(m_PC.w.l)); + save_item(NAME(m_SP.w.l)); + save_item(NAME(m_AF.w.l)); + save_item(NAME(m_BC.w.l)); + save_item(NAME(m_DE.w.l)); + save_item(NAME(m_HL.w.l)); + save_item(NAME(m_HALT)); + save_item(NAME(m_IM)); + save_item(NAME(m_STATUS)); + save_item(NAME(m_after_ei)); + save_item(NAME(m_nmi_state)); + save_item(NAME(m_irq_state)); + save_item(NAME(m_trap_pending)); + save_item(NAME(m_trap_im_copy)); + save_item(NAME(m_sod_state)); + + m_icountptr = &m_icount; +} + + +/*************************************************************************** + COMMON RESET +***************************************************************************/ + +void i8085a_cpu_device::device_reset() +{ + m_PC.d = 0; + m_HALT = 0; + m_IM &= ~IM_I75; + m_IM |= IM_M55 | IM_M65 | IM_M75; + m_after_ei = FALSE; + m_trap_pending = FALSE; + m_trap_im_copy = 0; + set_inte(0); + set_sod(0); +} + + + +/*************************************************************************** + COMMON STATE IMPORT/EXPORT +***************************************************************************/ + +void i8085a_cpu_device::state_import(const device_state_entry &entry) +{ + switch (entry.index()) + { + case I8085_SID: + if (m_ietemp) + m_IM |= IM_SID; + else + m_IM &= ~IM_SID; + break; + + case I8085_INTE: + if (m_ietemp) + m_IM |= IM_IE; + else + m_IM &= ~IM_IE; + break; + + default: + fatalerror("CPU_IMPORT_STATE(i808x) called for unexpected value\n"); + } +} + + +void i8085a_cpu_device::state_export(const device_state_entry &entry) +{ + switch (entry.index()) + { + case I8085_SID: + { + int sid = m_in_sid_func(); + + m_ietemp = ((m_IM & IM_SID) != 0); + m_ietemp = (sid != 0); + } + break; + + case I8085_INTE: + m_ietemp = ((m_IM & IM_IE) != 0); + break; + + default: + fatalerror("CPU_EXPORT_STATE(i808x) called for unexpected value\n"); + } +} + +void i8085a_cpu_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + switch (entry.index()) + { + case STATE_GENFLAGS: + strprintf(str, "%c%c%c%c%c%c%c%c", + m_AF.b.l & 0x80 ? 'S':'.', + m_AF.b.l & 0x40 ? 'Z':'.', + m_AF.b.l & 0x20 ? 'X':'.', // X5 + m_AF.b.l & 0x10 ? 'H':'.', + m_AF.b.l & 0x08 ? '?':'.', + m_AF.b.l & 0x04 ? 'P':'.', + m_AF.b.l & 0x02 ? 'V':'.', + m_AF.b.l & 0x01 ? 'C':'.'); + break; + } +} + + +void i8085a_cpu_device::execute_set_input(int irqline, int state) +{ + int newstate = (state != CLEAR_LINE); + + /* NMI is edge-triggered */ + if (irqline == INPUT_LINE_NMI) + { + if (!m_nmi_state && newstate) + m_trap_pending = TRUE; + m_nmi_state = newstate; + } + + /* RST7.5 is edge-triggered */ + else if (irqline == I8085_RST75_LINE) + { + if (!m_irq_state[I8085_RST75_LINE] && newstate) + m_IM |= IM_I75; + m_irq_state[I8085_RST75_LINE] = newstate; + } + + /* remaining sources are level triggered */ + else if (irqline < ARRAY_LENGTH(m_irq_state)) + m_irq_state[irqline] = state; +} + + +offs_t i8085a_cpu_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( i8085 ); + return CPU_DISASSEMBLE_NAME(i8085)(this, buffer, pc, oprom, opram, options); +} diff --git a/src/devices/cpu/i8085/i8085.h b/src/devices/cpu/i8085/i8085.h new file mode 100644 index 00000000000..a0e8f5d8d3a --- /dev/null +++ b/src/devices/cpu/i8085/i8085.h @@ -0,0 +1,181 @@ +// license:BSD-3-Clause +// copyright-holders:Juergen Buchmueller, hap + +#ifndef __I8085_H__ +#define __I8085_H__ + + +/*************************************************************************** + CONSTANTS +***************************************************************************/ + +enum +{ + I8085_PC, I8085_SP, I8085_AF, I8085_BC, I8085_DE, I8085_HL, + I8085_A, I8085_B, I8085_C, I8085_D, I8085_E, I8085_F, I8085_H, I8085_L, + I8085_STATUS, I8085_SOD, I8085_SID, I8085_INTE, + I8085_HALT, I8085_IM, + + I8085_GENPC = STATE_GENPC, + I8085_GENSP = STATE_GENSP, + I8085_GENPCBASE = STATE_GENPCBASE +}; + +#define I8085_INTR_LINE 0 +#define I8085_RST55_LINE 1 +#define I8085_RST65_LINE 2 +#define I8085_RST75_LINE 3 + +#define I8085_STATUS_INTA 0x01 +#define I8085_STATUS_WO 0x02 +#define I8085_STATUS_STACK 0x04 +#define I8085_STATUS_HLTA 0x08 +#define I8085_STATUS_OUT 0x10 +#define I8085_STATUS_M1 0x20 +#define I8085_STATUS_INP 0x40 +#define I8085_STATUS_MEMR 0x80 + + +/* STATUS changed callback */ +#define MCFG_I8085A_STATUS(_devcb) \ + i8085a_cpu_device::set_out_status_func(*device, DEVCB_##_devcb); + +/* INTE changed callback */ +#define MCFG_I8085A_INTE(_devcb) \ + i8085a_cpu_device::set_out_inte_func(*device, DEVCB_##_devcb); + +/* SID changed callback (8085A only) */ +#define MCFG_I8085A_SID(_devcb) \ + i8085a_cpu_device::set_in_sid_func(*device, DEVCB_##_devcb); + +/* SOD changed callback (8085A only) */ +#define MCFG_I8085A_SOD(_devcb) \ + i8085a_cpu_device::set_out_sod_func(*device, DEVCB_##_devcb); + + +class i8085a_cpu_device : public cpu_device +{ +public: + // construction/destruction + i8085a_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + i8085a_cpu_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source, int cputype); + + // static configuration helpers + template static devcb_base &set_out_status_func(device_t &device, _Object object) { return downcast(device).m_out_status_func.set_callback(object); } + template static devcb_base &set_out_inte_func(device_t &device, _Object object) { return downcast(device).m_out_inte_func.set_callback(object); } + template static devcb_base &set_in_sid_func(device_t &device, _Object object) { return downcast(device).m_in_sid_func.set_callback(object); } + template static devcb_base &set_out_sod_func(device_t &device, _Object object) { return downcast(device).m_out_sod_func.set_callback(object); } + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_execute_interface overrides + virtual UINT32 execute_min_cycles() const { return 4; } + virtual UINT32 execute_max_cycles() const { return 16; } + virtual UINT32 execute_input_lines() const { return 4; } + virtual UINT32 execute_default_irq_vector() const { return 0xff; } + virtual void execute_run(); + virtual void execute_set_input(int inputnum, int state); + virtual UINT64 execute_clocks_to_cycles(UINT64 clocks) const { return (clocks + 2 - 1) / 2; } + virtual UINT64 execute_cycles_to_clocks(UINT64 cycles) const { return (cycles * 2); } + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const { return (spacenum == AS_PROGRAM) ? &m_program_config : ( (spacenum == AS_IO) ? &m_io_config : NULL ); } + + // device_state_interface overrides + void state_string_export(const device_state_entry &entry, std::string &str); + void state_export(const device_state_entry &entry); + void state_import(const device_state_entry &entry); + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const { return 1; } + virtual UINT32 disasm_max_opcode_bytes() const { return 3; } + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + +private: + address_space_config m_program_config; + address_space_config m_io_config; + + devcb_write8 m_out_status_func; + devcb_write_line m_out_inte_func; + devcb_read_line m_in_sid_func; + devcb_write_line m_out_sod_func; + + int m_cputype; /* 0 8080, 1 8085A */ + PAIR m_PC,m_SP,m_AF,m_BC,m_DE,m_HL,m_WZ; + UINT8 m_HALT; + UINT8 m_IM; /* interrupt mask (8085A only) */ + UINT8 m_STATUS; /* status word */ + + UINT8 m_after_ei; /* post-EI processing; starts at 2, check for ints at 0 */ + UINT8 m_nmi_state; /* raw NMI line state */ + UINT8 m_irq_state[4]; /* raw IRQ line states */ + UINT8 m_trap_pending; /* TRAP interrupt latched? */ + UINT8 m_trap_im_copy; /* copy of IM register when TRAP was taken */ + UINT8 m_sod_state; /* state of the SOD line */ + + UINT8 m_ietemp; /* import/export temp space */ + + address_space *m_program; + direct_read_data *m_direct; + address_space *m_io; + int m_icount; + + /* cycles lookup */ + static const UINT8 lut_cycles_8080[256]; + static const UINT8 lut_cycles_8085[256]; + UINT8 lut_cycles[256]; + /* flags lookup */ + UINT8 ZS[256]; + UINT8 ZSP[256]; + + void set_sod(int state); + void set_inte(int state); + void set_status(UINT8 status); + UINT8 get_rim_value(); + void break_halt_for_interrupt(); + UINT8 ROP(); + UINT8 ARG(); + UINT16 ARG16(); + UINT8 RM(UINT32 a); + void WM(UINT32 a, UINT8 v); + void check_for_interrupts(); + void execute_one(int opcode); + void init_tables(); + +}; + + +class i8080_cpu_device : public i8085a_cpu_device +{ +public: + // construction/destruction + i8080_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual UINT32 execute_input_lines() const { return 1; } + virtual UINT64 execute_clocks_to_cycles(UINT64 clocks) const { return clocks; } + virtual UINT64 execute_cycles_to_clocks(UINT64 cycles) const { return cycles; } +}; + + +class i8080a_cpu_device : public i8085a_cpu_device +{ +public: + // construction/destruction + i8080a_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual UINT32 execute_input_lines() const { return 1; } + virtual UINT64 execute_clocks_to_cycles(UINT64 clocks) const { return clocks; } + virtual UINT64 execute_cycles_to_clocks(UINT64 cycles) const { return cycles; } +}; + + +extern const device_type I8080; +extern const device_type I8080A; +extern const device_type I8085A; + +#endif diff --git a/src/devices/cpu/i8085/i8085cpu.h b/src/devices/cpu/i8085/i8085cpu.h new file mode 100644 index 00000000000..5ccecf3cd95 --- /dev/null +++ b/src/devices/cpu/i8085/i8085cpu.h @@ -0,0 +1,188 @@ +// license:BSD-3-Clause +// copyright-holders:Juergen Buchmueller, hap +/******************************************************* + * + * Portable (hopefully ;-) 8085A emulator + * + * Written by J. Buchmueller for use with MAME + * + * Partially based on Z80Em by Marcel De Kogel + * + * CPU related macros + * + *******************************************************/ + + +#define SF 0x80 +#define ZF 0x40 +#define X5F 0x20 +#define HF 0x10 +#define X3F 0x08 +#define PF 0x04 +#define VF 0x02 +#define CF 0x01 + +#define IM_SID 0x80 +#define IM_I75 0x40 +#define IM_I65 0x20 +#define IM_I55 0x10 +#define IM_IE 0x08 +#define IM_M75 0x04 +#define IM_M65 0x02 +#define IM_M55 0x01 + +#define ADDR_TRAP 0x0024 +#define ADDR_RST55 0x002c +#define ADDR_RST65 0x0034 +#define ADDR_RST75 0x003c +#define ADDR_INTR 0x0038 + + +#define M_MVI(R) R=ARG() + +/* rotate */ +#define M_RLC { \ + m_AF.b.h = (m_AF.b.h << 1) | (m_AF.b.h >> 7); \ + m_AF.b.l = (m_AF.b.l & 0xfe) | (m_AF.b.h & CF); \ +} + +#define M_RRC { \ + m_AF.b.l = (m_AF.b.l & 0xfe) | (m_AF.b.h & CF); \ + m_AF.b.h = (m_AF.b.h >> 1) | (m_AF.b.h << 7); \ +} + +#define M_RAL { \ + int c = m_AF.b.l&CF; \ + m_AF.b.l = (m_AF.b.l & 0xfe) | (m_AF.b.h >> 7); \ + m_AF.b.h = (m_AF.b.h << 1) | c; \ +} + +#define M_RAR { \ + int c = (m_AF.b.l&CF) << 7; \ + m_AF.b.l = (m_AF.b.l & 0xfe) | (m_AF.b.h & CF); \ + m_AF.b.h = (m_AF.b.h >> 1) | c; \ +} + +/* logical */ +#define M_ORA(R) m_AF.b.h|=R; m_AF.b.l=ZSP[m_AF.b.h] +#define M_XRA(R) m_AF.b.h^=R; m_AF.b.l=ZSP[m_AF.b.h] +#define M_ANA(R) {UINT8 hc = ((m_AF.b.h | R)<<1) & HF; m_AF.b.h&=R; m_AF.b.l=ZSP[m_AF.b.h]; if(IS_8085()) { m_AF.b.l |= HF; } else {m_AF.b.l |= hc; } } + +/* increase / decrease */ +#define M_INR(R) {UINT8 hc = ((R & 0x0f) == 0x0f) ? HF : 0; ++R; m_AF.b.l= (m_AF.b.l & CF ) | ZSP[R] | hc; } +#define M_DCR(R) {UINT8 hc = ((R & 0x0f) != 0x00) ? HF : 0; --R; m_AF.b.l= (m_AF.b.l & CF ) | ZSP[R] | hc | VF; } + +/* arithmetic */ +#define M_ADD(R) { \ + int q = m_AF.b.h+R; \ + m_AF.b.l=ZSP[q&255]|((q>>8)&CF)|((m_AF.b.h^q^R)&HF); \ + m_AF.b.h=q; \ +} + +#define M_ADC(R) { \ + int q = m_AF.b.h+R+(m_AF.b.l&CF); \ + m_AF.b.l=ZSP[q&255]|((q>>8)&CF)|((m_AF.b.h^q^R)&HF); \ + m_AF.b.h=q; \ +} + +#define M_SUB(R) { \ + int q = m_AF.b.h-R; \ + m_AF.b.l=ZSP[q&255]|((q>>8)&CF)|(~(m_AF.b.h^q^R)&HF)|VF; \ + m_AF.b.h=q; \ +} + +#define M_SBB(R) { \ + int q = m_AF.b.h-R-(m_AF.b.l&CF); \ + m_AF.b.l=ZSP[q&255]|((q>>8)&CF)|(~(m_AF.b.h^q^R)&HF)|VF; \ + m_AF.b.h=q; \ +} + +#define M_CMP(R) { \ + int q = m_AF.b.h-R; \ + m_AF.b.l=ZSP[q&255]|((q>>8)&CF)|(~(m_AF.b.h^q^R)&HF)|VF; \ +} + +#define M_DAD(R) { \ + int q = m_HL.d + m_##R.d; \ + m_AF.b.l = (m_AF.b.l & ~CF) | (q>>16 & CF ); \ + m_HL.w.l = q; \ +} + +// DSUB is 8085-only, not sure if H flag handling is correct +#define M_DSUB() { \ + int q = m_HL.b.l-m_BC.b.l; \ + m_AF.b.l=ZS[q&255]|((q>>8)&CF)|VF| \ + ((m_HL.b.l^q^m_BC.b.l)&HF)| \ + (((m_BC.b.l^m_HL.b.l)&(m_HL.b.l^q)&SF)>>5); \ + m_HL.b.l=q; \ + q = m_HL.b.h-m_BC.b.h-(m_AF.b.l&CF); \ + m_AF.b.l=ZS[q&255]|((q>>8)&CF)|VF| \ + ((m_HL.b.h^q^m_BC.b.h)&HF)| \ + (((m_BC.b.h^m_HL.b.h)&(m_HL.b.h^q)&SF)>>5); \ + if (m_HL.b.l!=0) m_AF.b.l&=~ZF; \ +} + +/* i/o */ +#define M_IN \ + m_STATUS = 0x42; \ + m_WZ.d=ARG(); \ + m_AF.b.h=m_io->read_byte(m_WZ.d); + +#define M_OUT \ + m_STATUS = 0x10; \ + m_WZ.d=ARG(); \ + m_io->write_byte(m_WZ.d,m_AF.b.h) + +/* stack */ +#define M_PUSH(R) { \ + m_STATUS = 0x04; \ + m_program->write_byte(--m_SP.w.l, m_##R.b.h); \ + m_program->write_byte(--m_SP.w.l, m_##R.b.l); \ +} + +#define M_POP(R) { \ + m_STATUS = 0x86; \ + m_##R.b.l = m_program->read_byte(m_SP.w.l++); \ + m_##R.b.h = m_program->read_byte(m_SP.w.l++); \ +} + +/* jumps */ +// On 8085 jump if condition is not satisfied is shorter +#define M_JMP(cc) { \ + if (cc) { \ + m_PC.w.l = ARG16(); \ + } else { \ + m_PC.w.l += 2; \ + m_icount += (IS_8085()) ? 3 : 0; \ + } \ +} + +// On 8085 call if condition is not satisfied is 9 ticks +#define M_CALL(cc) \ +{ \ + if (cc) \ + { \ + UINT16 a = ARG16(); \ + m_icount -= (IS_8085()) ? 7 : 6 ; \ + M_PUSH(PC); \ + m_PC.d = a; \ + } else { \ + m_PC.w.l += 2; \ + m_icount += (IS_8085()) ? 2 : 0; \ + } \ +} + +// conditional RET only +#define M_RET(cc) \ +{ \ + if (cc) \ + { \ + m_icount -= 6; \ + M_POP(PC); \ + } \ +} + +#define M_RST(nn) { \ + M_PUSH(PC); \ + m_PC.d = 8 * nn; \ +} diff --git a/src/devices/cpu/i8089/i8089.c b/src/devices/cpu/i8089/i8089.c new file mode 100644 index 00000000000..b81869bda1d --- /dev/null +++ b/src/devices/cpu/i8089/i8089.c @@ -0,0 +1,380 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best,Carl +/*************************************************************************** + + Intel 8089 I/O Processor + +***************************************************************************/ + +#include "i8089.h" +#include "i8089_channel.h" + + +//************************************************************************** +// MACROS/CONSTANTS +//************************************************************************** + +#define VERBOSE 1 + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type I8089 = &device_creator; + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// i8089_device - constructor +//------------------------------------------------- + +i8089_device::i8089_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + cpu_device(mconfig, I8089, "I8089", tag, owner, clock, "i8089", __FILE__), + m_icount(0), + m_ch1(*this, "1"), + m_ch2(*this, "2"), + m_write_sintr1(*this), + m_write_sintr2(*this), + m_sysbus(0), + m_scb(0), + m_soc(0), + m_master(false), + m_current_tp(0), + m_ca(0), + m_sel(0) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void i8089_device::device_start() +{ + // set our instruction counter + m_icountptr = &m_icount; + + // resolve callbacks + m_write_sintr1.resolve_safe(); + m_write_sintr2.resolve_safe(); + + // register debugger states + state_add(SYSBUS, "SYSBUS", m_sysbus).mask(0x01).formatstr("%1s"); + state_add(SCB, "SCB", m_scb).mask(0xfffff); + state_add(SOC, "SOC", m_soc).mask(0x03).formatstr("%2s"); + state_add_divider(DIVIDER1); + state_add(CH1_GA, "CH1 GA", m_ch1->m_r[i8089_channel::GA].w).mask(0xfffff).formatstr("%8s"); + state_add(CH1_GB, "CH1 GB", m_ch1->m_r[i8089_channel::GB].w).mask(0xfffff).formatstr("%8s"); + state_add(CH1_GC, "CH1 GC", m_ch1->m_r[i8089_channel::GC].w).mask(0xfffff).formatstr("%8s"); + state_add(CH1_TP, "CH1 TP", m_ch1->m_r[i8089_channel::TP].w).mask(0xfffff).formatstr("%8s"); + state_add(CH1_BC, "CH1 BC", m_ch1->m_r[i8089_channel::BC].w).mask(0xffff); + state_add(CH1_IX, "CH1 IX", m_ch1->m_r[i8089_channel::IX].w).mask(0xffff); + state_add(CH1_CC, "CH1 CC", m_ch1->m_r[i8089_channel::CC].w).mask(0xffff); + state_add(CH1_MC, "CH1 MC", m_ch1->m_r[i8089_channel::MC].w).mask(0xffff); + state_add(CH1_CP, "CH1 CP", m_ch1->m_r[i8089_channel::CP].w).mask(0xfffff); + state_add(CH1_PP, "CH1 PP", m_ch1->m_r[i8089_channel::PP].w).mask(0xfffff); + state_add(CH1_PSW, "CH1 PSW", m_ch1->m_r[i8089_channel::PSW].w).callimport().callexport().formatstr("%12s"); + state_add_divider(DIVIDER2); + state_add(CH2_GA, "CH2 GA", m_ch2->m_r[i8089_channel::GA].w).mask(0xfffff).formatstr("%8s"); + state_add(CH2_GB, "CH2 GB", m_ch2->m_r[i8089_channel::GB].w).mask(0xfffff).formatstr("%8s"); + state_add(CH2_GC, "CH2 GC", m_ch2->m_r[i8089_channel::GC].w).mask(0xfffff).formatstr("%8s"); + state_add(CH2_TP, "CH2 TP", m_ch2->m_r[i8089_channel::TP].w).mask(0xfffff).formatstr("%8s"); + state_add(CH2_BC, "CH2 BC", m_ch2->m_r[i8089_channel::BC].w).mask(0xffff); + state_add(CH2_IX, "CH2 IX", m_ch2->m_r[i8089_channel::IX].w).mask(0xffff); + state_add(CH2_CC, "CH2 CC", m_ch2->m_r[i8089_channel::CC].w).mask(0xffff); + state_add(CH2_MC, "CH2 MC", m_ch2->m_r[i8089_channel::MC].w).mask(0xffff); + state_add(CH2_CP, "CH2 CP", m_ch2->m_r[i8089_channel::CP].w).mask(0xfffff); + state_add(CH2_PP, "CH2 PP", m_ch2->m_r[i8089_channel::PP].w).mask(0xfffff); + state_add(CH2_PSW, "CH2 PSW", m_ch2->m_r[i8089_channel::PSW].w).callimport().callexport().formatstr("%12s"); + state_add(STATE_GENPC, "GENPC", m_current_tp).mask(0xfffff).noshow(); + + // register for save states + save_item(NAME(m_sysbus)); + save_item(NAME(m_scb)); + save_item(NAME(m_soc)); + save_item(NAME(m_master)); + save_item(NAME(m_ca)); + save_item(NAME(m_sel)); + save_item(NAME(m_last_chan)); + + // assign memory spaces + m_mem = &space(AS_PROGRAM); + m_io = &space(AS_IO); +} + +//------------------------------------------------- +// device_config_complete - perform any +// operations now that the configuration is +// complete +//------------------------------------------------- + +void i8089_device::device_config_complete() +{ + m_program_config = address_space_config("program", ENDIANNESS_LITTLE, m_databus_width, 20); + m_io_config = address_space_config("io", ENDIANNESS_LITTLE, m_databus_width, 16); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void i8089_device::device_reset() +{ + m_initialized = false; + m_last_chan = 0; +} + +//------------------------------------------------- +// memory_space_config - device-specific address +// space configurations +//------------------------------------------------- + +const address_space_config *i8089_device::memory_space_config(address_spacenum spacenum) const +{ + switch (spacenum) + { + case AS_PROGRAM: return &m_program_config; + case AS_IO: return &m_io_config; + default: return NULL; + } +} + +//------------------------------------------------- +// disasm_disassemble - disassembler +//------------------------------------------------- + +offs_t i8089_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE(i8089); + return CPU_DISASSEMBLE_NAME(i8089)(this, buffer, pc, oprom, opram, options); +} + +//------------------------------------------------- +// state_string_export - export state as a string +// for the debugger +//------------------------------------------------- + +void i8089_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + i8089_channel *ch = m_ch1; + + if (entry.index() >= CH2_GA && entry.index() <= CH2_PSW) + ch = m_ch2; + + switch (entry.index()) + { + case SYSBUS: + strprintf(str, "%c", sysbus_width() ? 'W' : '.'); + break; + case SOC: + strprintf(str, "%c%c", remotebus_width() ? 'I' : '.', request_grant() ? 'R' : '.'); + break; + case CH1_GA: + case CH2_GA: + strprintf(str, "%d %05X", ch->m_r[i8089_channel::GA].t & 1, ch->m_r[i8089_channel::GA].w); + break; + case CH1_GB: + case CH2_GB: + strprintf(str, "%d %05X", ch->m_r[i8089_channel::GB].t & 1, ch->m_r[i8089_channel::GB].w); + break; + case CH1_GC: + case CH2_GC: + strprintf(str, "%d %05X", ch->m_r[i8089_channel::GC].t & 1, ch->m_r[i8089_channel::GC].w); + break; + case CH1_TP: + case CH2_TP: + strprintf(str, "%d %05X", ch->m_r[i8089_channel::TP].t & 1, ch->m_r[i8089_channel::TP].w); + break; + case CH1_PSW: + case CH2_PSW: + strprintf(str, "%c%s%c%s%s%s%c%c", + BIT(ch->m_r[i8089_channel::PSW].w, 7) ? 'P':'.', + BIT(ch->m_r[i8089_channel::PSW].w, 6) ? "XF":"..", + BIT(ch->m_r[i8089_channel::PSW].w, 5) ? 'B':'.', + BIT(ch->m_r[i8089_channel::PSW].w, 4) ? "IS":"..", + BIT(ch->m_r[i8089_channel::PSW].w, 3) ? "IC":"..", + BIT(ch->m_r[i8089_channel::PSW].w, 2) ? "TB":"..", + BIT(ch->m_r[i8089_channel::PSW].w, 1) ? 'S':'.', + BIT(ch->m_r[i8089_channel::PSW].w, 0) ? 'D':'.'); + break; + } +} + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( i8089 ) + MCFG_I8089_CHANNEL_ADD("1") + MCFG_I8089_CHANNEL_SINTR(WRITELINE(i8089_device, ch1_sintr_w)) + MCFG_I8089_CHANNEL_ADD("2") + MCFG_I8089_CHANNEL_SINTR(WRITELINE(i8089_device, ch2_sintr_w)) +MACHINE_CONFIG_END + +machine_config_constructor i8089_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( i8089 ); +} + + +//************************************************************************** +// IMPLEMENTATION +//************************************************************************** + +// the i8089 actually executes a program from internal rom here: +// +// MOVB SYSBUS from FFFF6 +// LPD System Configuration Block from FFFF8 +// MOVB SOC from (SCB) +// LPD Control Pointer (CP) from (SCB) + 2 +// MOVBI "00" to CP + 1 (clear busy flag) + +void i8089_device::initialize() +{ + assert(!m_initialized); + + // get system bus width + m_sysbus = m_mem->read_byte(0xffff6); + + // get system configuration block address + UINT16 scb_offset = read_word(0, 0xffff8); + UINT16 scb_segment = read_word(0, 0xffffa); + m_scb = ((scb_segment << 4) + scb_offset) & 0x0fffff; + + // get system operation command + m_soc = read_byte(0, m_scb); + m_master = !m_sel; + + // get control block address + UINT16 cb_offset = read_word(0, m_scb + 2); + UINT16 cb_segment = read_word(0, m_scb + 4); + offs_t cb_address = ((cb_segment << 4) + cb_offset) & 0x0fffff; + + // initialize channels + m_ch1->set_reg(i8089_channel::CP, cb_address); + m_ch2->set_reg(i8089_channel::CP, cb_address + 8); + + // clear busy + UINT16 ccw = read_word(0, cb_address); + write_word(0, cb_address, ccw & 0x00ff); + + // done + m_initialized = true; + + // output some debug info + if (VERBOSE) + { + logerror("%s('%s'): ---- initializing ----\n", shortname(), basetag()); + logerror("%s('%s'): %s system bus\n", shortname(), basetag(), sysbus_width() ? "16-bit" : "8-bit"); + logerror("%s('%s'): system configuration block location: %06x\n", shortname(), basetag(), m_scb); + logerror("%s('%s'): %s remote bus\n", shortname(), basetag(), remotebus_width() ? "16-bit" : "8-bit"); + logerror("%s('%s'): request/grant: %d\n", shortname(), basetag(), request_grant()); + logerror("%s('%s'): is %s\n", shortname(), basetag(), m_master ? "master" : "slave"); + logerror("%s('%s'): channel control block location: %06x\n", shortname(), basetag(), cb_address); + } +} + +UINT8 i8089_device::read_byte(bool space, offs_t address) +{ + return (space ? m_io : m_mem)->read_byte(address); +} + +UINT16 i8089_device::read_word(bool space, offs_t address) +{ + UINT16 data = 0xffff; + address_space *aspace = (space ? m_io : m_mem); + + if (sysbus_width() && !(address & 1)) + { + data = aspace->read_word(address); + } + else + { + data = aspace->read_byte(address); + data |= aspace->read_byte(address + 1) << 8; + } + + return data; +} + +void i8089_device::write_byte(bool space, offs_t address, UINT8 data) +{ + (space ? m_io : m_mem)->write_byte(address, data); +} + +void i8089_device::write_word(bool space, offs_t address, UINT16 data) +{ + address_space *aspace = (space ? m_io : m_mem); + + if (sysbus_width() && !(address & 1)) + { + aspace->write_word(address, data); + } + else + { + aspace->write_byte(address, data & 0xff); + aspace->write_byte(address + 1, (data >> 8) & 0xff); + } +} + +void i8089_device::execute_run() +{ + do + { + bool next_chan; + + if(m_ch1->chan_prio() < m_ch2->chan_prio()) + next_chan = 0; + else if(m_ch1->chan_prio() > m_ch2->chan_prio()) + next_chan = 1; + else if(m_ch1->priority() && !m_ch2->priority()) + next_chan = 0; + else if(!m_ch1->priority() && m_ch2->priority()) + next_chan = 1; + else + next_chan = !m_last_chan; + + m_last_chan = next_chan; + if(!next_chan) + m_icount -= m_ch1->execute_run(); + else + m_icount -= m_ch2->execute_run(); + } + while (m_icount > 0); +} + + +//************************************************************************** +// EXTERNAL INPUTS +//************************************************************************** + +WRITE_LINE_MEMBER( i8089_device::ca_w ) +{ + if (VERBOSE) + logerror("%s('%s'): ca_w: %u\n", shortname(), basetag(), state); + + if (m_ca == 1 && state == 0) + { + if (!m_initialized) + initialize(); + else + { + if (m_sel == 0) + m_ch1->ca(); + else + m_ch2->ca(); + } + } + + m_ca = state; +} + +WRITE_LINE_MEMBER( i8089_device::drq1_w ) { m_ch1->drq_w(state); } +WRITE_LINE_MEMBER( i8089_device::drq2_w ) { m_ch2->drq_w(state); } +WRITE_LINE_MEMBER( i8089_device::ext1_w ) { m_ch1->ext_w(state); } +WRITE_LINE_MEMBER( i8089_device::ext2_w ) { m_ch2->ext_w(state); } diff --git a/src/devices/cpu/i8089/i8089.h b/src/devices/cpu/i8089/i8089.h new file mode 100644 index 00000000000..f40607bdc7c --- /dev/null +++ b/src/devices/cpu/i8089/i8089.h @@ -0,0 +1,158 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best,Carl +/*************************************************************************** + + Intel 8089 I/O Processor + +***************************************************************************/ + +#pragma once + +#ifndef __I8089_H__ +#define __I8089_H__ + +#include "emu.h" +#include "i8089_channel.h" + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_I8089_DATABUS_WIDTH(_databus_width) \ + i8089_device::set_databus_width(*device, _databus_width); + +#define MCFG_I8089_SINTR1(_sintr1) \ + downcast(device)->set_sintr1_callback(DEVCB_##_sintr1); + +#define MCFG_I8089_SINTR2(_sintr2) \ + downcast(device)->set_sintr2_callback(DEVCB_##_sintr2); + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// forward declaration +class i8089_channel; + +// ======================> i8089_device + +class i8089_device : public cpu_device +{ + friend class i8089_channel; + +public: + // construction/destruction + i8089_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // callbacks + template void set_sintr1_callback(_sintr1 sintr1) { m_write_sintr1.set_callback(sintr1); } + template void set_sintr2_callback(_sintr2 sintr2) { m_write_sintr2.set_callback(sintr2); } + + // static configuration helpers + static void set_databus_width(device_t &device, UINT8 databus_width) { downcast(device).m_databus_width = databus_width; } + + // input lines + DECLARE_WRITE_LINE_MEMBER( ca_w ); + DECLARE_WRITE_LINE_MEMBER( sel_w ) { m_sel = state; } + DECLARE_WRITE_LINE_MEMBER( drq1_w ); + DECLARE_WRITE_LINE_MEMBER( drq2_w ); + DECLARE_WRITE_LINE_MEMBER( ext1_w ); + DECLARE_WRITE_LINE_MEMBER( ext2_w ); + + // internal communication + DECLARE_WRITE_LINE_MEMBER( ch1_sintr_w ) { m_write_sintr1(state); } + DECLARE_WRITE_LINE_MEMBER( ch2_sintr_w ) { m_write_sintr2(state); } + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_config_complete(); + virtual void device_reset(); + + // device_execute_interface overrides + virtual void execute_run(); + + int m_icount; + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const; + + address_space_config m_program_config; + address_space_config m_io_config; + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const { return 1; } + virtual UINT32 disasm_max_opcode_bytes() const { return 7; } + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + + // device_state_interface overrides + virtual void state_string_export(const device_state_entry &entry, std::string &str); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + +private: + bool sysbus_width() { return BIT(m_sysbus, 0); } + bool remotebus_width() { return BIT(m_soc, 0); } + bool request_grant() { return BIT(m_soc, 1); } + + UINT8 read_byte(bool space, offs_t address); + UINT16 read_word(bool space, offs_t address); + void write_byte(bool space, offs_t address, UINT8 data); + void write_word(bool space, offs_t address, UINT16 data); + + required_device m_ch1; + required_device m_ch2; + + devcb_write_line m_write_sintr1; + devcb_write_line m_write_sintr2; + + void initialize(); + + UINT8 m_databus_width; + address_space *m_mem; + address_space *m_io; + + // register indexes for the debugger state + enum + { + SYSBUS, + SCB, + SOC, + DIVIDER1, + CH1_GA, CH1_GB, CH1_GC, + CH1_TP, CH1_BC, CH1_IX, + CH1_CC, CH1_MC, CH1_CP, + CH1_PP, CH1_PSW, + DIVIDER2, + CH2_GA, CH2_GB, CH2_GC, + CH2_TP, CH2_BC, CH2_IX, + CH2_CC, CH2_MC, CH2_CP, + CH2_PP, CH2_PSW + }; + + // system configuration + UINT8 m_sysbus; + offs_t m_scb; + UINT8 m_soc; + + bool m_initialized; + bool m_master; + + // task pointer for the currently executing channel + offs_t m_current_tp; + + // state of input pins + int m_ca; + int m_sel; + bool m_last_chan; +}; + + +// device type definition +extern const device_type I8089; + + +#endif /* __I8089_H__ */ diff --git a/src/devices/cpu/i8089/i8089_channel.c b/src/devices/cpu/i8089/i8089_channel.c new file mode 100644 index 00000000000..fe7666ac17c --- /dev/null +++ b/src/devices/cpu/i8089/i8089_channel.c @@ -0,0 +1,848 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best,Carl +/*************************************************************************** + + Intel 8089 I/O Processor + + I/O channel + +***************************************************************************/ + +#include "emu.h" +#include "debugger.h" +#include "i8089_channel.h" + + +//************************************************************************** +// MACROS/CONSTANTS +//************************************************************************** + +#define VERBOSE 1 +#define VERBOSE_DMA 1 + +// channel control register fields +#define CC_TMC ((m_r[CC].w >> 0) & 0x07) // terminate on masked compare +#define CC_TBC ((m_r[CC].w >> 3) & 0x03) // terminate on byte count +#define CC_TX ((m_r[CC].w >> 5) & 0x03) // terminate on external signal +#define CC_TS ((m_r[CC].w >> 7) & 0x01) // terminate on single transfer +#define CC_CHAIN ((m_r[CC].w >> 8) & 0x01) // chaining +#define CC_LOCK ((m_r[CC].w >> 9) & 0x01) // actuate lock +#define CC_SOURCE ((m_r[CC].w >> 10) & 0x01) // source register +#define CC_SYNC ((m_r[CC].w >> 11) & 0x03) // synchronization +#define CC_TRANS ((m_r[CC].w >> 13) & 0x01) // translation +#define CC_FUNC ((m_r[CC].w >> 14) & 0x03) // function + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type I8089_CHANNEL = &device_creator; + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// i8089_channel - constructor +//------------------------------------------------- + +i8089_channel::i8089_channel(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, I8089_CHANNEL, "Intel 8089 I/O Channel", tag, owner, clock, "i8089_channel", __FILE__), + m_write_sintr(*this), + m_iop(NULL), + m_icount(0), + m_xfer_pending(false), + m_dma_value(0), + m_dma_state(DMA_IDLE), + m_drq(0), + m_prio(PRIO_IDLE) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void i8089_channel::device_start() +{ + // get parent device + m_iop = downcast(owner()); + + // resolve callbacks + m_write_sintr.resolve_safe(); + + // register for save states + save_item(NAME(m_xfer_pending)); + save_item(NAME(m_dma_value)); + save_item(NAME(m_dma_state)); + save_item(NAME(m_drq)); + save_item(NAME(m_prio)); + + for (int i = 0; i < ARRAY_LENGTH(m_r); i++) + { + save_item(NAME(m_r[i].w), i); + save_item(NAME(m_r[i].t), i); + } +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void i8089_channel::device_reset() +{ + m_xfer_pending = false; + + // initialize registers + for (int i = 0; i < ARRAY_LENGTH(m_r); i++) + { + m_r[i].w = 0; + m_r[i].t = 0; + } + m_prio = PRIO_IDLE; +} + + +//************************************************************************** +// IMPLEMENTATION +//************************************************************************** + +void i8089_channel::set_reg(int reg, UINT32 value, int tag) +{ + if((reg == BC) || (reg == IX) || (reg == CC) || (reg == MC)) + { + m_r[reg].w = value & 0xffff; + if((reg == CC) && executing()) + m_prio = chained() ? PRIO_PROG_CHAIN : PRIO_PROG; + return; + } + m_r[reg].w = value & 0xfffff; + + if(reg == PP) + { + m_r[PP].t = 0; + return; + } + + if (tag != -1) + m_r[reg].t = tag; + + if (reg == TP) + m_iop->m_current_tp = value; +} + +// channel status +bool i8089_channel::executing() { return BIT(m_r[PSW].w, 2); } +bool i8089_channel::transferring() { return BIT(m_r[PSW].w, 6); } +bool i8089_channel::priority() { return BIT(m_r[PSW].w, 7); } +int i8089_channel::chan_prio() { return m_prio; } +bool i8089_channel::chained() { return CC_CHAIN; } +bool i8089_channel::lock() { return CC_LOCK; } + +INT16 i8089_channel::displacement(int wb) +{ + INT16 displacement = 0; + + if (wb == 1) + { + displacement = (INT16)((INT8)m_iop->read_byte(m_r[TP].t, m_r[TP].w)); + set_reg(TP, m_r[TP].w + 1); + } + else if (wb == 2) + { + displacement = (INT16)m_iop->read_word(m_r[TP].t, m_r[TP].w); + set_reg(TP, m_r[TP].w + 2); + } + + return displacement; +} + +UINT32 i8089_channel::offset(int aa, int mm, int w) +{ + UINT32 offset = 0; + switch(aa) + { + case 0: + offset = m_r[mm].w; + break; + case 1: + offset = m_r[mm].w + m_iop->read_byte(m_r[TP].t, m_r[TP].w); + set_reg(TP, m_r[TP].w + 1); + break; + case 2: + offset = m_r[mm].w + m_r[IX].w; + break; + case 3: + offset = m_r[mm].w + m_r[IX].w; + set_reg(IX, m_r[IX].w + (w ? 2 : 1)); + break; + } + return offset & 0xfffff; +} + +INT8 i8089_channel::imm8() +{ + INT8 imm8 = (INT8)m_iop->read_byte(m_r[TP].t, m_r[TP].w); + set_reg(TP, m_r[TP].w + 1); + return imm8; +} + +INT16 i8089_channel::imm16() +{ + INT16 imm16 = (INT16)m_iop->read_word(m_r[TP].t, m_r[TP].w); + set_reg(TP, m_r[TP].w + 2); + return imm16; +} + +// adjust task pointer and continue execution +void i8089_channel::terminate_dma(int offset) +{ + if (VERBOSE) + logerror("%s('%s'): terminating dma transfer\n", shortname(), tag()); + + set_reg(TP, m_r[TP].w + offset); + m_r[PSW].w |= 1 << 2; + m_r[PSW].w &= ~(1 << 6); + m_dma_state = DMA_IDLE; +} + +int i8089_channel::execute_run() +{ + m_icount = 0; + + if (chan_prio() == PRIO_CHAN_ATTN) + { + attention(); + return m_icount++; + } + + // active transfer? + if (transferring()) + { + // new transfer? + if (executing()) + { + // we are no longer executing task blocks + m_r[PSW].w &= ~(1 << 2); + m_xfer_pending = false; + + if (VERBOSE) + { + logerror("%s('%s'): ---- starting dma transfer ----\n", shortname(), tag()); + logerror("%s('%s'): ga = %06x, gb = %06x, gc = %06x\n", shortname(), tag(), m_r[GA].w, m_r[GB].w, m_r[GC].w); + logerror("%s('%s'): bc = %04x, cc = %04x, mc = %04x\n", shortname(), tag(), m_r[BC].w, m_r[CC].w, m_r[MC].w); + } + } + + switch (m_dma_state) + { + case DMA_IDLE: + if (VERBOSE_DMA) + logerror("%s('%s'): entering state: DMA_IDLE (bc = %04x)\n", shortname(), tag(), m_r[BC].w); + + // synchronize on source? + if (CC_SYNC == 0x01) + m_dma_state = DMA_WAIT_FOR_SOURCE_DRQ; + else + m_dma_state = DMA_FETCH; + break; + + case DMA_WAIT_FOR_SOURCE_DRQ: + if (m_drq) + m_dma_state = DMA_FETCH; + break; + + case DMA_FETCH: + if (VERBOSE_DMA) + logerror("%s('%s'): entering state: DMA_FETCH\n", shortname(), tag()); + + // source is 16-bit? + if (BIT(m_r[PSW].w, 1)) + { + m_dma_value = m_iop->read_word(m_r[GA + CC_SOURCE].t, m_r[GA + CC_SOURCE].w); + if(CC_FUNC & 1) + m_r[GA + CC_SOURCE].w += 2; + m_r[BC].w -= 2; + } + // destination is 16-bit, byte count is even + else if (BIT(m_r[PSW].w, 0) && !(m_r[BC].w & 1)) + { + m_dma_value = m_iop->read_byte(m_r[GA + CC_SOURCE].t, m_r[GA + CC_SOURCE].w); + if(CC_FUNC & 1) + m_r[GA + CC_SOURCE].w++; + m_r[BC].w--; + } + // destination is 16-bit, byte count is odd + else if (BIT(m_r[PSW].w, 0) && (m_r[BC].w & 1)) + { + m_dma_value |= m_iop->read_byte(m_r[GA + CC_SOURCE].t, m_r[GA + CC_SOURCE].w) << 8; + if(CC_FUNC & 1) + m_r[GA + CC_SOURCE].w++; + m_r[BC].w--; + } + // 8-bit transfer + else + { + m_dma_value = m_iop->read_byte(m_r[GA + CC_SOURCE].t, m_r[GA + CC_SOURCE].w); + if(CC_FUNC & 1) + m_r[GA + CC_SOURCE].w++; + m_r[BC].w--; + } + + m_r[BC].w &= 0xffff; + m_r[GA + CC_SOURCE].w &= 0xfffff; + + if (VERBOSE_DMA) + logerror("[ %04x ]\n", m_dma_value); + + if (BIT(m_r[PSW].w, 0) && (m_r[BC].w & 1)) + m_dma_state = DMA_FETCH; + else if (CC_TRANS) + m_dma_state = DMA_TRANSLATE; + else if (CC_SYNC == 0x02) + m_dma_state = DMA_WAIT_FOR_DEST_DRQ; + else + m_dma_state = DMA_STORE; + + break; + + case DMA_TRANSLATE: + fatalerror("%s('%s'): dma translate requested\n", shortname(), tag()); + + case DMA_WAIT_FOR_DEST_DRQ: + if (m_drq) + m_dma_state = DMA_STORE; + break; + + case DMA_STORE: + if (VERBOSE_DMA) + logerror("%s('%s'): entering state: DMA_STORE", shortname(), tag()); + + // destination is 16-bit? + if (BIT(m_r[PSW].w, 0)) + { + m_iop->write_word(m_r[GB - CC_SOURCE].t, m_r[GB - CC_SOURCE].w, m_dma_value); + if(CC_FUNC & 2) + m_r[GB - CC_SOURCE].w += 2; + + if (VERBOSE_DMA) + logerror("[ %04x ]\n", m_dma_value); + } + // destination is 8-bit + else + { + m_iop->write_byte(m_r[GB - CC_SOURCE].t, m_r[GB - CC_SOURCE].w, m_dma_value & 0xff); + if(CC_FUNC & 2) + m_r[GB - CC_SOURCE].w++; + + if (VERBOSE_DMA) + logerror("[ %02x ]\n", m_dma_value & 0xff); + } + + m_r[GB - CC_SOURCE].w &= 0xfffff; + + if (CC_TMC & 0x03) + m_dma_state = DMA_COMPARE; + else + m_dma_state = DMA_TERMINATE; + + break; + + case DMA_COMPARE: + fatalerror("%s('%s'): dma compare requested\n", shortname(), tag()); + + case DMA_TERMINATE: + if (VERBOSE_DMA) + logerror("%s('%s'): entering state: DMA_TERMINATE\n", shortname(), tag()); + + // terminate on masked compare? + if (CC_TMC & 0x03) + fatalerror("%s('%s'): terminate on masked compare not supported\n", shortname(), tag()); + + // terminate on byte count? + else if (CC_TBC && m_r[BC].w == 0) + terminate_dma((CC_TBC - 1) * 4); + + // terminate on single transfer + else if (CC_TS) + fatalerror("%s('%s'): terminate on single transfer not supported\n", shortname(), tag()); + + // not terminated, continue transfer + else + // do we need to read another byte? + if (BIT(m_r[PSW].w, 1) && !BIT(m_r[PSW].w, 0)) + if (CC_SYNC == 0x02) + m_dma_state = DMA_WAIT_FOR_DEST_DRQ; + else + m_dma_state = DMA_STORE_BYTE_HIGH; + + // transfer done + else + m_dma_state = DMA_IDLE; + + break; + + case DMA_STORE_BYTE_HIGH: + if (VERBOSE_DMA) + logerror("%s('%s'): entering state: DMA_STORE_BYTE_HIGH[ %02x ]\n", shortname(), tag(), (m_dma_value >> 8) & 0xff); + + m_iop->write_byte(m_r[GA - CC_SOURCE].t, m_r[GB - CC_SOURCE].w, (m_dma_value >> 8) & 0xff); + m_r[GB - CC_SOURCE].w++; + m_dma_state = DMA_TERMINATE; + + break; + } + + m_icount++; + } + + // executing task block instructions? + else if (executing()) + { + // call debugger + debugger_instruction_hook(m_iop, m_iop->m_current_tp); + + // dma transfer pending? + if (m_xfer_pending) + { + m_r[PSW].w |= 1 << 6; + m_prio = PRIO_DMA; + } + else + m_prio = chained() ? PRIO_PROG_CHAIN : PRIO_PROG; + + // fetch first two instruction bytes + UINT16 op = m_iop->read_word(m_r[TP].t, m_r[TP].w); + set_reg(TP, m_r[TP].w + 2); + + // extract parameters + UINT8 params = op & 0xff; + UINT8 opcode = (op >> 8) & 0xff; + + int brp = (params >> 5) & 0x07; + int wb = (params >> 3) & 0x03; + int aa = (params >> 1) & 0x03; + int w = (params >> 0) & 0x01; + int opc = (opcode >> 2) & 0x3f; + int mm = (opcode >> 0) & 0x03; + + // fix-up so we can use our register array + if (mm == BC) mm = PP; + + UINT32 o; + UINT16 off, seg; + + switch (opc) + { + case 0x00: // control + switch (brp) + { + case 0: nop(); break; + case 1: invalid(opc); break; + case 2: sintr(); break; + case 3: xfer(); break; + default: wid(BIT(brp, 1), BIT(brp, 0)); + } + break; + + case 0x02: // lpdi + off = (UINT16)imm16(); + seg = (UINT16)imm16(); + lpdi(brp, seg, off); + break; + + case 0x08: // add(b)i r, i + if (w) addi_ri(brp, imm16()); + else addbi_ri(brp, imm8()); + break; + + case 0x09: // or(b)i r, i + if (w) ori_ri(brp, imm16()); + else orbi_ri(brp, imm8()); + break; + + case 0x0a: // and(b)i r, i + if (w) andi_ri(brp, imm16()); + else andbi_ri(brp, imm8()); + break; + + case 0x0b: // not r + not_r(brp); + break; + + case 0x0c: // mov(b)i r, i + if (w) movi_ri(brp, imm16()); + else movbi_ri(brp, imm8()); + break; + + case 0x0e: // inc r + inc_r(brp); + break; + + case 0x0f: // dec r + dec_r(brp); + break; + + case 0x10: // jnz r + jnz_r(brp, displacement(wb)); + break; + + case 0x11: // jz r + jz_r(brp, displacement(wb)); + break; + + case 0x12: // hlt + if (BIT(brp, 0)) hlt(); + else invalid(opc); + break; + + case 0x13: // mov(b)i m, i + o = offset(aa, mm, w); + if (w) movi_mi(mm, imm16(), o); + else movbi_mi(mm, imm8(), o); + break; + + case 0x20: // mov(b) r, m + if (w) mov_rm(brp, mm, offset(aa, mm, w)); + else movb_rm(brp, mm, offset(aa, mm, w)); + break; + + case 0x21: // mov(b) m, r + if (w) mov_mr(mm, brp, offset(aa, mm, w)); + else movb_mr(mm, brp, offset(aa, mm, w)); + break; + + case 0x22: // lpd + o = offset(aa, mm, w); + lpd(brp, mm, o); + break; + + case 0x23: // movp p, m + movp_pm(brp, mm, offset(aa, mm, w)); + break; + + case 0x24: // mov(b) m, m + { + o = offset(aa, mm, w); + UINT16 op2 = m_iop->read_word(m_r[TP].t, m_r[TP].w); + set_reg(TP, m_r[TP].w + 2); + int mm2 = (op2 >> 8) & 0x03; + + if (w) mov_mm(mm, mm2, o, offset((op2 >> 1) & 0x03, mm2, w)); + else movb_mm(mm, mm2, o, offset((op2 >> 1) & 0x03, mm2, w)); + break; + } + + case 0x25: // tsl m, i, d + { + o = offset(aa, mm, w); + INT8 i = imm8(); + tsl(mm, i, imm8(), o); + break; + } + + case 0x26: // movp m, p + movp_mp(mm, brp, offset(aa, mm, w)); + break; + + case 0x27: // call + o = offset(aa, mm, w); + call(mm, displacement(wb), o); + break; + + case 0x28: // add(b) r, m + if (w) add_rm(brp, mm, offset(aa, mm, w)); + else addb_rm(brp, mm, offset(aa, mm, w)); + break; + + case 0x29: // or(b) r, m + if (w) or_rm(brp, mm, offset(aa, mm, w)); + else orb_rm(brp, mm, offset(aa, mm, w)); + break; + + case 0x2a: // and(b) r, m + if (w) and_rm(brp, mm, offset(aa, mm, w)); + else andb_rm(brp, mm, offset(aa, mm, w)); + break; + + case 0x2b: // not(b) r, m + if (w) not_rm(brp, mm, offset(aa, mm, w)); + else notb_rm(brp, mm, offset(aa, mm, w)); + break; + + case 0x2c: // jmce m, d + o = offset(aa, mm, w); + jmce(mm, displacement(wb), o); + break; + + case 0x2d: // jmcne m, d + o = offset(aa, mm, w); + jmcne(mm, displacement(wb), o); + break; + + case 0x2e: // jnbt m, b, d + o = offset(aa, mm, w); + jnbt(mm, brp, displacement(wb), o); + break; + + case 0x2f: // jbt m, b, d + o = offset(aa, mm, w); + jbt(mm, brp, displacement(wb), o); + break; + + case 0x30: // add(b)i m, i + o = offset(aa, mm, w); + if (w) addi_mi(mm, imm16(), o); + else addbi_mi(mm, imm8(), o); + break; + + case 0x31: // or(b)i m, i + o = offset(aa, mm, w); + if (w) ori_mi(mm, imm16(), o); + else orbi_mi(mm, imm8(), o); + break; + + case 0x32: // and(b)i m, i + o = offset(aa, mm, w); + if (w) andi_mi(mm, imm16(), o); + else andbi_mi(mm, imm8(), o); + break; + + case 0x34: // add(b) m, r + if (w) add_mr(mm, brp, offset(aa, mm, w)); + else addb_mr(mm, brp, offset(aa, mm, w)); + break; + + case 0x35: // or(b) m, r + if (w) or_mr(mm, brp, offset(aa, mm, w)); + else orb_mr(mm, brp, offset(aa, mm, w)); + break; + + case 0x36: // and(b) m, r + if (w) and_mr(mm, brp, offset(aa, mm, w)); + else andb_mr(mm, brp, offset(aa, mm, w)); + break; + + case 0x37: // not(b) m + if (w) not_m(mm, offset(aa, mm, w)); + else notb_m(mm, offset(aa, mm, w)); + break; + + case 0x38: // jnz m + o = offset(aa, mm, w); + if(w) jnz_m(mm, displacement(wb), o); + else jnzb(mm, displacement(wb), o); + break; + + case 0x39: // jz m + o = offset(aa, mm, w); + if(w) jz_m(mm, displacement(wb), o); + else jzb(mm, displacement(wb), o); + break; + + case 0x3a: // inc(b) m + if (w) inc_m(mm, offset(aa, mm, w)); + else incb(mm, offset(aa, mm, w)); + break; + + case 0x3b: // dec(b) m + if (w) dec_m(mm, offset(aa, mm, w)); + else decb(mm, offset(aa, mm, w)); + break; + + case 0x3d: // setb + setb(mm, brp, offset(aa, mm, w)); + break; + + case 0x3e: // clr + clr(mm, brp, offset(aa, mm, w)); + break; + + default: + invalid(opc); + } + + m_icount++; + } + + // nothing to do + else + { + m_icount++; + } + + return m_icount; +} + +void i8089_channel::examine_ccw(UINT8 ccw) +{ + // priority and bus load limit, bit 7 and 5 + m_r[PSW].w = (m_r[PSW].w & 0x5f) | (ccw & 0xa0); + + // acknowledge interrupt + if (BIT(ccw, 4)) + { + m_write_sintr(0); + m_r[PSW].w &= ~(1 << 5); + } + + // interrupt enable + if (BIT(ccw, 5)) + { + if (BIT(ccw, 4)) + m_r[PSW].w &= ~(1 << 4); + else + m_r[PSW].w |= 1 << 4; + } +} + +void i8089_channel::attention() +{ + // examine control byte + UINT8 ccw = m_iop->read_byte(m_r[CP].t, m_r[CP].w); + + switch (ccw & 0x07) + { + // no channel command + case 0: + if (VERBOSE) + logerror("%s('%s'): command received: update psw\n", shortname(), tag()); + + if(executing()) + m_prio = chained() ? PRIO_PROG_CHAIN : PRIO_PROG; + else if(transferring()) + m_prio = PRIO_DMA; + else + m_prio = PRIO_IDLE; + + examine_ccw(ccw); + break; + + // start channel, tb in local space + case 1: + if (VERBOSE) + logerror("%s('%s'): command received: start channel in local space\n", shortname(), tag()); + + examine_ccw(ccw); + + lpd(PP, CP, m_r[CP].w + 2); + movp_pm(TP, PP, m_r[PP].w); + movbi_mi(CP, (INT8) 0xff, m_r[CP].w + 1); + m_r[TP].t = 1; + + m_r[PSW].w |= 1 << 2; + m_prio = chained() ? PRIO_PROG_CHAIN : PRIO_PROG; + + if (VERBOSE) + { + logerror("%s('%s'): ---- starting channel ----\n", shortname(), tag()); + logerror("%s('%s'): parameter block address: %06x\n", shortname(), tag(), m_r[PP].w); + logerror("%s('%s'): task pointer: %04x\n", shortname(), tag(), m_r[TP].w); + } + + break; + + // reserved + case 2: + if (VERBOSE) + logerror("%s('%s'): command received: invalid command 010\n", shortname(), tag()); + m_prio = PRIO_IDLE; + + break; + + // start channel, tb in system space + case 3: + if (VERBOSE) + logerror("%s('%s'): command received: start channel in system space\n", shortname(), tag()); + + examine_ccw(ccw); + + lpd(PP, CP, m_r[CP].w + 2); + lpd(TP, PP, m_r[PP].w); + movbi_mi(CP, (INT8) 0xff, m_r[CP].w + 1); + + m_r[PSW].w |= 1 << 2; + m_prio = chained() ? PRIO_PROG_CHAIN : PRIO_PROG; + + if (VERBOSE) + { + logerror("%s('%s'): ---- starting channel ----\n", shortname(), tag()); + logerror("%s('%s'): parameter block address: %06x\n", shortname(), tag(), m_r[PP].w); + logerror("%s('%s'): task pointer: %06x\n", shortname(), tag(), m_r[TP].w); + } + + break; + + case 4: + if (VERBOSE) + logerror("%s('%s'): command received: invalid command 100\n", shortname(), tag()); + m_prio = PRIO_IDLE; + + break; + + // continue channel processing + case 5: + if (VERBOSE) + logerror("%s('%s'): command received: continue channel processing\n", shortname(), tag()); + + // restore task pointer and parameter block + movp_pm(TP, PP, m_r[PP].w); + movb_rm(PSW, PP, m_r[PP].w + 3); + movbi_mi(CP, (INT8) 0xff, m_r[CP].w + 1); + + m_r[PSW].w |= 1 << 2; + m_prio = chained() ? PRIO_PROG_CHAIN : PRIO_PROG; + + if (VERBOSE) + { + logerror("%s('%s'): ---- continuing channel ----\n", shortname(), tag()); + logerror("%s('%s'): task pointer: %06x\n", shortname(), tag(), m_r[TP].w); + } + + break; + + // halt channel, save tp + case 6: + if (VERBOSE) + logerror("%s('%s'): command received: halt channel and save tp\n", shortname(), tag()); + + // save task pointer and psw to parameter block + movp_mp(PP, TP, m_r[TP].w); + movb_mr(PP, PSW, m_r[PP].w + 3); + hlt(); + + break; + + // halt channel, don't save tp + case 7: + if (VERBOSE) + logerror("%s('%s'): command received: halt channel\n", shortname(), tag()); + + hlt(); + + break; + } +} + +void i8089_channel::ca() +{ + m_prio = PRIO_CHAN_ATTN; +} + +WRITE_LINE_MEMBER( i8089_channel::ext_w ) +{ + if (VERBOSE) + logerror("%s('%s'): ext_w: %d\n", shortname(), tag(), state); + if(transferring() && state) + terminate_dma((CC_TX - 1) * 4); +} + +WRITE_LINE_MEMBER( i8089_channel::drq_w ) +{ + if (VERBOSE) + logerror("%s('%s'): drq_w: %d\n", shortname(), tag(), state); + + m_drq = state; +} diff --git a/src/devices/cpu/i8089/i8089_channel.h b/src/devices/cpu/i8089/i8089_channel.h new file mode 100644 index 00000000000..7c1f5a6e445 --- /dev/null +++ b/src/devices/cpu/i8089/i8089_channel.h @@ -0,0 +1,224 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best,Carl +/*************************************************************************** + + Intel 8089 I/O Processor + + I/O channel + +***************************************************************************/ + +#pragma once + +#ifndef __I8089_CHANNEL_H__ +#define __I8089_CHANNEL_H__ + +#include "emu.h" +#include "i8089.h" + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_I8089_CHANNEL_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, I8089_CHANNEL, 0) + +#define MCFG_I8089_CHANNEL_SINTR(_sintr) \ + downcast(device)->set_sintr_callback(DEVCB_##_sintr); + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// forward declaration +class i8089_device; + +class i8089_channel : public device_t +{ +public: + // construction/destruction + i8089_channel(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + template void set_sintr_callback(_sintr sintr) { m_write_sintr.set_callback(sintr); } + + // set register + void set_reg(int reg, UINT32 value, int tag = -1); + + int execute_run(); + void attention(); + + // channel status + bool executing(); + bool transferring(); + bool priority(); + int chan_prio(); + bool chained(); + bool lock(); + void ca(); + + DECLARE_WRITE_LINE_MEMBER( ext_w ); + DECLARE_WRITE_LINE_MEMBER( drq_w ); + + // register + enum + { + GA, // 20-bit general purpose address a + GB, // 20-bit general purpose address b + GC, // 20-bit general purpose address c + BC, // byte count + TP, // 20-bit task pointer + IX, // byte count + CC, // mask compare + MC, // channel control + + // internal use register + CP, // 20-bit control block pointer + PP, // 20-bit parameter pointer + PSW, // program status word + + NUM_REGS + }; + + struct + { + UINT32 w; // 20-bit address + bool t; // tag-bit + } + m_r[11]; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + +private: + + // opcodes + void add_rm(int r, int m, int o); + void add_mr(int m, int r, int o); + void addb_rm(int r, int m, int o); + void addb_mr(int m, int r, int o); + void addbi_ri(int r, INT8 i); + void addbi_mi(int m, INT8 i, int o); + void addi_ri(int r, INT16 i); + void addi_mi(int m, INT16 i, int o); + void and_rm(int r, int m, int o); + void and_mr(int m, int r, int o); + void andb_rm(int r, int m, int o); + void andb_mr(int m, int r, int o); + void andbi_ri(int r, INT8 i); + void andbi_mi(int m, INT8 i, int o); + void andi_ri(int r, INT16 i); + void andi_mi(int m, INT16 i, int o); + void call(int m, INT16 d, int o); + void clr(int m, int b, int o); + void dec_r(int r); + void dec_m(int m, int o); + void decb(int m, int o); + void hlt(); + void inc_r(int r); + void inc_m(int m, int o); + void incb(int m, int o); + void jbt(int m, int b, INT16 d, int o); + void jmce(int m, INT16 d, int o); + void jmcne(int m, INT16 d, int o); + void jnbt(int m, int b, INT16 d, int o); + void jnz_r(int r, INT16 d); + void jnz_m(int m, INT16 d, int o); + void jnzb(int m, INT16 d, int o); + void jz_r(int r, INT16 d); + void jz_m(int m, INT16 d, int o); + void jzb(int m, INT16 d, int o); + void lpd(int p, int m, int o); + void lpdi(int p, int s, int o); + void mov_mr(int m, int r, int o); + void mov_rm(int r, int m, int o); + void mov_mm(int m1, int m2, int o1, int o2); + void movb_mr(int m, int r, int o); + void movb_rm(int r, int m, int o); + void movb_mm(int m1, int m2, int o1, int o2); + void movbi_ri(int r, INT8 i); + void movbi_mi(int m, INT8 i, int o); + void movi_ri(int r, INT16 i); + void movi_mi(int m, INT16 i, int o); + void movp_mp(int m, int p, int o); + void movp_pm(int p, int m, int o); + void nop(); + void not_r(int r); + void not_m(int m, int o); + void not_rm(int r, int m, int o); + void notb_m(int m, int o); + void notb_rm(int r, int m, int o); + void or_rm(int r, int m, int o); + void or_mr(int m, int r, int o); + void orb_rm(int r, int m, int o); + void orb_mr(int m, int r, int o); + void orbi_ri(int r, INT8 i); + void orbi_mi(int m, INT8 i, int o); + void ori_ri(int r, INT16 i); + void ori_mi(int m, INT16 i, int o); + void setb(int m, int b, int o); + void sintr(); + void tsl(int m, INT8 i, INT8 d, int o); + void wid(int s, int d); + void xfer(); + void invalid(int opc); + + // instruction fetch + INT16 displacement(int wb); + UINT32 offset(int aa, int mm, int w); + INT8 imm8(); + INT16 imm16(); + + void examine_ccw(UINT8 ccw); + + devcb_write_line m_write_sintr; + + i8089_device *m_iop; + + int m_icount; + + // dma + void terminate_dma(int offset); + + bool m_xfer_pending; + UINT16 m_dma_value; + int m_dma_state; + bool m_drq; + + // dma state + enum + { + DMA_IDLE, + DMA_WAIT_FOR_SOURCE_DRQ, + DMA_FETCH, + DMA_TRANSLATE, + DMA_WAIT_FOR_DEST_DRQ, + DMA_STORE, + DMA_STORE_BYTE_HIGH, + DMA_COMPARE, + DMA_TERMINATE + }; + + int m_prio; + + // priority + enum + { + PRIO_DMA = 1, + PRIO_DMA_TERM = 1, + PRIO_PROG_CHAIN = 1, + PRIO_CHAN_ATTN, + PRIO_PROG, + PRIO_IDLE + }; +}; + + +// device type definition +extern const device_type I8089_CHANNEL; + + +#endif /* __I8089_CHANNEL_H__ */ diff --git a/src/devices/cpu/i8089/i8089_dasm.c b/src/devices/cpu/i8089/i8089_dasm.c new file mode 100644 index 00000000000..d1f62621f3c --- /dev/null +++ b/src/devices/cpu/i8089/i8089_dasm.c @@ -0,0 +1,447 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best +/*************************************************************************** + + Intel 8089 I/O Processor + + Disassembler + +***************************************************************************/ + +#include "emu.h" + +class i8089_instruction +{ +public: + i8089_instruction(offs_t pc, const UINT8 *oprom) : + m_oprom(oprom), m_ppc(pc), m_pc(0), m_flags(DASMFLAG_SUPPORTED) + { + // instruction + m_brp = (oprom[0] >> 5) & 0x07; + m_wb = (oprom[0] >> 3) & 0x03; + m_aa = (oprom[0] >> 1) & 0x03; + m_w = (oprom[0] >> 0) & 0x01; + m_opc = (oprom[1] >> 2) & 0x3f; + m_mm = (oprom[1] >> 0) & 0x03; + + // clear buffers + memset(m_buffer, 0, sizeof(m_buffer)); + memset(m_offset, 0, sizeof(m_offset)); + + // start working + disassemble(); + } + + char *buffer() { return m_buffer; } + int length() { return m_pc; } + int flags() { return m_flags; } + +private: + const UINT8 *m_oprom; + + char m_buffer[256]; + char m_offset[100]; + offs_t m_ppc; + int m_pc; + + // decoded instruction + int m_brp; + int m_wb; + int m_aa; + int m_w; + int m_opc; + int m_mm; + + // dasm flags + int m_flags; + + // register names + static const char *m_reg[]; + + // register index + enum + { + GA, // 20-bit general purpose address a + GB, // 20-bit general purpose address b + GC, // 20-bit general purpose address c + BC, // byte count + TP, // 20-bit task pointer + IX, // index + CC, // mask compare + MC // channel control + }; + + // fetch 1-byte value + UINT8 fetch_value8() + { + UINT8 i = m_oprom[m_pc]; + m_pc += 1; + return i; + } + + // fetch 2-byte value + UINT16 fetch_value16() + { + UINT16 i = m_oprom[m_pc] | m_oprom[m_pc + 1] << 8; + m_pc += 2; + return i; + } + + // fetch a 1 or 2 byte immediate value + UINT16 fetch_immediate() + { + return (m_wb & 1) ? fetch_value8() : fetch_value16(); + } + + // print memory offset + void offset() + { + const char *mm_name[] = { "ga", "gb", "gc", "pp" }; + + switch (m_aa) + { + case 0: sprintf(m_offset, "[%s]", mm_name[m_mm]); break; + case 1: sprintf(m_offset, "[%s].%02x", mm_name[m_mm], m_oprom[m_pc]); m_pc++; break; + case 2: sprintf(m_offset, "[%s+ix]", mm_name[m_mm]); break; + case 3: sprintf(m_offset, "[%s+ix+]", mm_name[m_mm]); break; + } + } + + // to register or memory from immediate + void from_i(const char *instr8, const char *instr16, const char *target) + { + if (m_w == 0 && m_wb == 1) + sprintf(m_buffer, "%s %s, %02x", instr8, target, fetch_immediate()); + else if (m_w == 1 && m_wb == 2) + sprintf(m_buffer, "%s %s, %04x", instr16, target, fetch_immediate()); + else + invalid(); + } + + // register, immediate + void inst_ri(const char *instr8, const char *instr16) + { + if (m_mm == 0) + from_i(instr8, instr16, m_reg[m_brp]); + else + invalid(); + } + + // register + void inst_r(const char *instr) + { + if (m_mm == 0 && m_w == 0 && m_aa == 0 && m_wb == 0) + sprintf(m_buffer, "%s %s", instr, m_reg[m_brp]); + else + invalid(); + } + + // jump register + void inst_jr(const char *instr8, const char *instr16) + { + UINT16 i = fetch_immediate(); + if (m_mm == 0 && m_w == 0 && m_wb == 1) + sprintf(m_buffer, "%s %s, %05x", instr8, m_reg[m_brp], m_ppc + m_pc + (INT8) i); + else if (m_mm == 0 && m_w == 0 && m_wb == 2) + sprintf(m_buffer, "%s %s, %05x", instr16, m_reg[m_brp], m_ppc + m_pc + (INT16) i); + else + invalid(); + } + + // memory immediate + void inst_mi(const char *instr8, const char *instr16) + { + offset(); + from_i(instr8, instr16, m_offset); + } + + // register memory + void inst_rm(const char *instr8, const char *instr16) + { + offset(); + if (m_w == 0 && m_wb == 0) + sprintf(m_buffer, "%s %s, %s", instr8, m_reg[m_brp], m_offset); + else if (m_w == 1 && m_wb == 0) + sprintf(m_buffer, "%s %s, %s", instr16, m_reg[m_brp], m_offset); + else + invalid(); + } + + // jump memory + void inst_jm(const char *jump8short, const char *jump8long) + { + offset(); + UINT16 i = fetch_immediate(); + if (m_w == 0 && m_wb == 1 && m_brp == 0) + sprintf(m_buffer, "%s %s, %05x", jump8short, m_offset, m_ppc + m_pc + (INT8) i); + else if (m_w == 0 && m_wb == 2 && m_brp == 0) + sprintf(m_buffer, "%s %s, %05x", jump8long, m_offset, m_ppc + m_pc + (INT16) i); + else + invalid(); + } + + // jump memory bit + void inst_jmb(const char *jump8short, const char *jump8long) + { + offset(); + UINT16 i = fetch_immediate(); + if (m_w == 0 && m_wb == 1) + sprintf(m_buffer, "%s %s, %d, %05x", jump8short, m_offset, m_brp, m_ppc + m_pc + (INT8) i); + else if (m_w == 0 && m_wb == 2) + sprintf(m_buffer, "%s %s, %d, %05x", jump8long, m_offset, m_brp, m_ppc + m_pc + (INT16) i); + else + invalid(); + } + + // memory register + void inst_mr(const char *instr8, const char *instr16) + { + offset(); + if (m_w == 0 && m_wb == 0) + sprintf(m_buffer, "%s %s, %s", instr8, m_offset, m_reg[m_brp]); + else if (m_w == 1 && m_wb == 0) + sprintf(m_buffer, "%s %s, %s", instr16, m_offset, m_reg[m_brp]); + else + invalid(); + } + + // pointer memory + void inst_pm(const char *instr16) + { + offset(); + if (m_w == 1 && m_wb == 0) + sprintf(m_buffer, "%s %s, %s", instr16, m_reg[m_brp], m_offset); + else + invalid(); + } + + // memory pointer + void inst_mp(const char *instr16) + { + offset(); + if (m_w == 1 && m_wb == 0) + sprintf(m_buffer, "%s %s, %s", instr16, m_offset, m_reg[m_brp]); + else + invalid(); + } + + // jump memory + void inst_j16(const char *jump8short, const char *jump16short, const char *jump8long, const char *jump16long) + { + offset(); + UINT16 i = fetch_immediate(); + if (m_w == 0 && m_wb == 1) + sprintf(m_buffer, "%s %s, %05x", jump8short, m_offset, m_ppc + m_pc + (INT8) i); + else if (m_w == 1 && m_wb == 1) + sprintf(m_buffer, "%s %s, %05x", jump16short, m_offset, m_ppc + m_pc + (INT8) i); + else if (m_w == 0 && m_wb == 2) + sprintf(m_buffer, "%s %s, %05x", jump8long, m_offset, m_ppc + m_pc + (INT16) i); + else if (m_w == 1 && m_wb == 2) + sprintf(m_buffer, "%s %s, %05x", jump16long, m_offset, m_ppc + m_pc + (INT16) i); + else + invalid(); + } + + // memory + void inst_m(const char *instr8, const char *instr16) + { + offset(); + if (m_w == 0 && m_wb == 0) + sprintf(m_buffer, "%s %s", instr8, m_offset); + else if (m_w == 1 && m_wb == 0) + sprintf(m_buffer, "%s %s", instr16, m_offset); + else + invalid(); + } + + // memory bit + void inst_b(const char *instr) + { + offset(); + if (m_w == 0 && m_wb == 0) + sprintf(m_buffer, "%s %s, %d", instr, m_offset, m_brp); + else + invalid(); + } + + // invalid instruction + void invalid() + { + sprintf(m_buffer, "???"); + } + + void disassemble() + { + m_pc += 2; + + switch (m_opc) + { + case 0x00: + if (m_mm == 0 && m_w == 0 && m_aa == 0 && m_wb == 0) + { + switch (m_brp) + { + case 0: sprintf(m_buffer, "nop"); break; + case 1: invalid(); break; + case 2: sprintf(m_buffer, "sintr"); break; + case 3: sprintf(m_buffer, "xfer"); break; + case 4: sprintf(m_buffer, "wid 8, 8"); break; + case 5: sprintf(m_buffer, "wid 8, 16"); break; + case 6: sprintf(m_buffer, "wid 16, 8"); break; + case 7: sprintf(m_buffer, "wid 16, 16"); break; + } + } + else + invalid(); + break; + + case 0x02: + if (m_w == 1 && m_aa == 0 && m_wb == 2) + { + UINT16 offs = fetch_immediate(); + UINT16 segm = fetch_immediate(); + sprintf(m_buffer, "lpdi %s, %05x", m_reg[m_brp], ((segm << 4) + offs) & 0xfffff); + } + else + invalid(); + break; + + case 0x08: + if (m_mm == 0) + { + UINT16 i = fetch_immediate(); + + if (m_w == 0 && m_aa == 0 && m_wb == 1 && m_brp == TP) + sprintf(m_buffer, "jmp %05x", m_ppc + m_pc + (INT8) i); + else if (m_w == 1 && m_aa == 0 && m_wb == 2 && m_brp == TP) + sprintf(m_buffer, "ljmp %05x", m_ppc + m_pc + (INT16) i); + else if (m_w == 0 && m_wb == 1) + sprintf(m_buffer, "addbi %s, %02x", m_reg[m_brp], i); + else if (m_w == 1 && m_wb == 2) + sprintf(m_buffer, "addi %s, %04x", m_reg[m_brp], i); + else + invalid(); + } + else + invalid(); + break; + + case 0x09: inst_ri("orbi", "ori"); break; + case 0x0a: inst_ri("andbi", "andi"); break; + case 0x0b: inst_r("not"); break; + case 0x0c: inst_ri("movbi", "movi"); break; + case 0x0e: inst_r("inc"); break; + case 0x0f: inst_r("dec"); break; + case 0x10: inst_jr("jnz", "ljnz"); break; + case 0x11: inst_jr("jz", "ljz"); break; + + case 0x12: + if (m_mm == 0 && m_w == 0 && m_aa == 0 && m_wb == 0 && m_brp == 1) + sprintf(m_buffer, "hlt"); + else + invalid(); + break; + + case 0x13: inst_mi("movbi", "movi"); break; + case 0x20: inst_rm("movb", "mov"); break; + case 0x21: inst_mr("movb", "mov"); break; + case 0x22: inst_pm("lpd"); break; + case 0x23: inst_pm("movp"); break; + + case 0x24: + if (m_wb == 0) + { + offset(); + + i8089_instruction *tmp = new i8089_instruction(m_pc, m_oprom + m_pc); + m_pc += tmp->length(); + + if (m_w == 0) + sprintf(m_buffer, "movb %s, %s", tmp->buffer(), m_offset); + else + sprintf(m_buffer, "mov %s, %s", tmp->buffer(), m_offset); + + delete(tmp); + } + else + invalid(); + break; + + case 0x25: + if (m_w == 0 && m_wb == 3 && m_brp == 0) + { + offset(); + UINT16 i = fetch_immediate(); + int displacement = (INT8) fetch_immediate(); + sprintf(m_buffer, "tsl %s, %02x, %05x", m_offset, i, m_ppc + m_pc + displacement); + } + else + invalid(); + break; + + case 0x26: inst_mp("movp"); break; + + case 0x27: + if (m_w == 1 && m_brp == TP && (m_wb == 1 || m_wb == 2)) + { + offset(); + UINT16 i = fetch_immediate(); + + if (m_wb == 1) + sprintf(m_buffer, "call %s, %05x", m_offset, m_ppc + m_pc + (INT8) i); + else if (m_wb == 2) + sprintf(m_buffer, "lcall %s, %05x", m_offset, m_ppc + m_pc + (INT16) i); + + m_flags |= DASMFLAG_STEP_OVER; + } + else + invalid(); + break; + + case 0x28: inst_rm("addb", "add"); break; + case 0x29: inst_rm("orb", "or"); break; + case 0x2a: inst_rm("andb", "and"); break; + case 0x2b: inst_rm("notb", "not"); break; + case 0x2c: inst_jm("jmce", "ljmce"); break; + case 0x2d: inst_jm("jmcne", "ljmcne"); break; + case 0x2e: inst_jmb("jnbt", "ljnbt"); break; + case 0x2f: inst_jmb("jbt", "ljbt"); break; + case 0x30: inst_mi("addbi", "addi"); break; + case 0x31: inst_mi("orbi", "ori"); break; + case 0x32: inst_mi("andbi", "andi"); break; + + case 0x33: + offset(); + sprintf(m_buffer, "%s", m_offset); + break; + + case 0x34: inst_mr("addb", "add"); break; + case 0x35: inst_mr("orb", "or"); break; + case 0x36: inst_mr("andb", "and"); break; + case 0x37: inst_mr("notb", "not"); break; + case 0x38: inst_j16("jnzb", "jnz", "ljnzb", "ljnz"); break; + case 0x39: inst_j16("jzb", "jz", "ljzb", "ljz"); break; + case 0x3a: inst_m("incb", "inc"); break; + case 0x3b: inst_m("decb", "dec"); break; + case 0x3d: inst_b("setb"); break; + case 0x3e: inst_b("clr"); break; + + default: + invalid(); + } + } +}; + +const char *i8089_instruction::m_reg[] = +{ + "ga", "gb", "gc", "bc", "tp", "ix", "cc", "mc" +}; + +CPU_DISASSEMBLE( i8089 ) +{ + i8089_instruction *i = new i8089_instruction(pc, oprom); + strcpy(buffer, i->buffer()); + offs_t result = i->length() | i->flags(); + delete(i); + return result; +} diff --git a/src/devices/cpu/i8089/i8089_ops.c b/src/devices/cpu/i8089/i8089_ops.c new file mode 100644 index 00000000000..09c8f5cd037 --- /dev/null +++ b/src/devices/cpu/i8089/i8089_ops.c @@ -0,0 +1,415 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best,Carl +/*************************************************************************** + + Intel 8089 I/O Processor + + Opcode implementations + +***************************************************************************/ + +#include "emu.h" +#include "i8089_channel.h" + +#define UNIMPLEMENTED logerror("%s('%s'): unimplemented opcode: %s\n", shortname(), tag(), __FUNCTION__); + +#define LWR(m, o) ((INT16)m_iop->read_word(m_r[m].t, o)) +#define LBR(m, o) ((INT8)m_iop->read_byte(m_r[m].t, o)) +#define SWR(m, o, d) (m_iop->write_word(m_r[m].t, o, d)) +#define SBR(m, o, d) (m_iop->write_byte(m_r[m].t, o, d)) + +void i8089_channel::add_rm(int r, int m, int o) +{ + set_reg(r, m_r[r].w + LWR(m, o)); +} + +void i8089_channel::add_mr(int m, int r, int o) +{ + SWR(m, o, LWR(m, o) + m_r[r].w); +} + +void i8089_channel::addb_rm(int r, int m, int o) +{ + set_reg(r, m_r[r].w + LBR(m, o)); +} + +void i8089_channel::addb_mr(int m, int r, int o) +{ + SBR(m, o, LBR(m, o) + m_r[r].w); +} + +void i8089_channel::addbi_ri(int r, INT8 i) +{ + set_reg(r, m_r[r].w + i); +} + +void i8089_channel::addbi_mi(int m, INT8 i, int o) +{ + SBR(m, o, LBR(m, o) + i); +} + +void i8089_channel::addi_ri(int r, INT16 i) +{ + set_reg(r, m_r[r].w + i); +} + +void i8089_channel::addi_mi(int m, INT16 i, int o) +{ + SWR(m, o, LWR(m, o) + i); +} + +void i8089_channel::and_rm(int r, int m, int o) +{ + set_reg(r, m_r[r].w & LWR(m, o)); +} + +void i8089_channel::and_mr(int m, int r, int o) +{ + SWR(m, o, LWR(m, o) & m_r[r].w); +} + +void i8089_channel::andb_rm(int r, int m, int o) +{ + set_reg(r, m_r[r].w & (INT16)LBR(m, o)); +} + +void i8089_channel::andb_mr(int m, int r, int o) +{ + SBR(m, o, LBR(m, o) & m_r[r].w); +} + +void i8089_channel::andbi_ri(int r, INT8 i) +{ + set_reg(r, m_r[r].w & (INT16)i); +} + +void i8089_channel::andbi_mi(int m, INT8 i, int o) +{ + SBR(m, o, LBR(m, o) & i); +} + +void i8089_channel::andi_ri(int r, INT16 i) +{ + set_reg(r, m_r[r].w & i); +} + +void i8089_channel::andi_mi(int m, INT16 i, int o) +{ + SWR(m, o, LWR(m, o) & i); +} + +void i8089_channel::call(int m, INT16 d, int o) +{ + movp_mp(m, TP, o); + set_reg(TP, m_r[TP].w + d); +} + +void i8089_channel::clr(int m, int b, int o) +{ + SBR(m, o, LBR(m, o) & ~(1<> 8))) + set_reg(TP, m_r[TP].w + d); +} + +void i8089_channel::jmcne(int m, INT16 d, int o) +{ + if((LBR(m, o) ^ (m_r[MC].w & 0xff)) & (m_r[MC].w >> 8)) + set_reg(TP, m_r[TP].w + d); +} + +void i8089_channel::jnbt(int m, int b, INT16 d, int o) +{ + if(!(LBR(m, o) & (1<read_word(m_r[m].t, o); + UINT16 segment = m_iop->read_word(m_r[m].t, o + 2); + + set_reg(p, ((segment << 4) + offset) & 0xfffff, 0); +} + +// load pointer from immediate data +void i8089_channel::lpdi(int p, int s, int o) +{ + set_reg(p, (s << 4) + (o & 0xffff), 0); +} + +void i8089_channel::mov_mr(int m, int r, int o) +{ + SWR(m, o, m_r[r].w); +} + +void i8089_channel::mov_rm(int r, int m, int o) +{ + set_reg(r, (INT32)LWR(m, o), 1); +} + +void i8089_channel::mov_mm(int m1, int m2, int o1, int o2) +{ + SWR(m2, o2, LWR(m1, o1)); +} + +// move register to memory byte +void i8089_channel::movb_mr(int m, int r, int o) +{ + m_iop->write_byte(m_r[m].t, o, m_r[r].w & 0xff); +} + +// move memory byte to register +void i8089_channel::movb_rm(int r, int m, int o) +{ + UINT8 byte = m_iop->read_byte(m_r[m].t, o); + set_reg(r, (BIT(byte, 7) ? 0xfff00 : 0x00000) | byte, 1); +} + +// move memory byte to memory byte +void i8089_channel::movb_mm(int m1, int m2, int o1, int o2) +{ + UINT8 byte = m_iop->read_byte(m_r[m1].t, o1); + m_iop->write_byte(m_r[m2].t, o2, byte); +} + +// move immediate byte to register +void i8089_channel::movbi_ri(int r, INT8 i) +{ + set_reg(r, (BIT(i, 7) ? 0xfff00 : 0x00000) | (i & 0xff), 1); +} + +// move immediate byte to memory byte +void i8089_channel::movbi_mi(int m, INT8 i, int o) +{ + m_iop->write_byte(m_r[m].t, o, i & 0xff); +} + +// move immediate word to register +void i8089_channel::movi_ri(int r, INT16 i) +{ + set_reg(r, (BIT(i, 15) ? 0xf0000 : 0x00000) | (i & 0xffff), 1); +} + +// move immediate word to memory word +void i8089_channel::movi_mi(int m, INT16 i, int o) +{ + m_iop->write_word(m_r[m].t, o, (BIT(i, 15) ? 0xf0000 : 0x00000) | (i & 0xffff)); +} + +// move pointer to memory (store) +void i8089_channel::movp_mp(int m, int p, int o) +{ + m_iop->write_word(m_r[m].t, o, m_r[p].w & 0xffff); + m_iop->write_byte(m_r[m].t, o + 2, ((m_r[p].w >> 12) & 0xf0) | (m_r[p].t << 3)); +} + +// move memory to pointer (restore) +void i8089_channel::movp_pm(int p, int m, int o) +{ + UINT16 offset = m_iop->read_word(m_r[m].t, o); + UINT16 segment = m_iop->read_byte(m_r[m].t, o + 2); + + set_reg(p, (((segment & 0xf0) << 12) + offset) & 0xfffff, segment >> 3 & 0x01); +} + +// no operation +void i8089_channel::nop() +{ +} + +void i8089_channel::not_r(int r) +{ + set_reg(r, ~m_r[r].w); +} + +void i8089_channel::not_m(int m, int o) +{ + SWR(m, o, ~LWR(m, o)); +} + +void i8089_channel::not_rm(int r, int m, int o) +{ + set_reg(r, ~(INT32)LWR(m, o)); +} + +void i8089_channel::notb_m(int m, int o) +{ + SBR(m, o, ~LBR(m, o)); +} + +void i8089_channel::notb_rm(int r, int m, int o) +{ + set_reg(r, ~(INT32)LBR(m, o)); +} + +void i8089_channel::or_rm(int r, int m, int o) +{ + set_reg(r, m_r[r].w | LWR(m, o)); +} + +void i8089_channel::or_mr(int m, int r, int o) +{ + SWR(m, o, LWR(m, o) | m_r[r].w); +} + +void i8089_channel::orb_rm(int r, int m, int o) +{ + set_reg(r, m_r[r].w | (INT16)LBR(m, o)); +} + +void i8089_channel::orb_mr(int m, int r, int o) +{ + SBR(m, o, LBR(m, o) | m_r[r].w); +} + +void i8089_channel::orbi_ri(int r, INT8 i) +{ + set_reg(r, m_r[r].w | (INT16)i); +} + +void i8089_channel::orbi_mi(int m, INT8 i, int o) +{ + SBR(m, o, LBR(m, o) | i); +} + +void i8089_channel::ori_ri(int r, INT16 i) +{ + set_reg(r, m_r[r].w | i); +} + +void i8089_channel::ori_mi(int m, INT16 i, int o) +{ + SWR(m, o, LWR(m, o) | i); +} + +void i8089_channel::setb(int m, int b, int o) +{ + SBR(m, o, LBR(m, o) | (1<; +const device_type I80188 = &device_creator; + +i80188_cpu_device::i80188_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : i80186_cpu_device(mconfig, I80188, "I80188", tag, owner, clock, "i80188", __FILE__, 8) +{ + memcpy(m_timing, m_i80186_timing, sizeof(m_i80186_timing)); + m_fetch_xor = 0; + static_set_irq_acknowledge_callback(*this, device_irq_acknowledge_delegate(FUNC(i80186_cpu_device::int_callback), this)); +} + +i80186_cpu_device::i80186_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : i8086_common_cpu_device(mconfig, I80186, "I80186", tag, owner, clock, "i80186", __FILE__) + , m_program_config("program", ENDIANNESS_LITTLE, 16, 20, 0) + , m_io_config("io", ENDIANNESS_LITTLE, 16, 16, 0) + , m_read_slave_ack_func(*this) + , m_out_chip_select_func(*this) + , m_out_tmrout0_func(*this) + , m_out_tmrout1_func(*this) +{ + memcpy(m_timing, m_i80186_timing, sizeof(m_i80186_timing)); + m_fetch_xor = BYTE_XOR_LE(0); + static_set_irq_acknowledge_callback(*this, device_irq_acknowledge_delegate(FUNC(i80186_cpu_device::int_callback), this)); +} + +i80186_cpu_device::i80186_cpu_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source, int data_bus_size) + : i8086_common_cpu_device(mconfig, type, name, tag, owner, clock, shortname, source) + , m_program_config("program", ENDIANNESS_LITTLE, data_bus_size, 20, 0) + , m_io_config("io", ENDIANNESS_LITTLE, data_bus_size, 16, 0) + , m_read_slave_ack_func(*this) + , m_out_chip_select_func(*this) + , m_out_tmrout0_func(*this) + , m_out_tmrout1_func(*this) +{ +} + +UINT8 i80186_cpu_device::fetch_op() +{ + UINT8 data = m_direct->read_byte(pc(), m_fetch_xor); + m_ip++; + return data; +} + +UINT8 i80186_cpu_device::fetch() +{ + UINT8 data = m_direct->read_byte(pc(), m_fetch_xor); + m_ip++; + return data; +} + +void i80186_cpu_device::execute_run() +{ + while(m_icount > 0 ) + { + if ( m_seg_prefix_next ) + { + m_seg_prefix = true; + m_seg_prefix_next = false; + } + else + { + m_prev_ip = m_ip; + m_seg_prefix = false; + + /* Dispatch IRQ */ + if ( m_pending_irq && m_no_interrupt == 0 ) + { + if ( m_pending_irq & NMI_IRQ ) + { + interrupt(2); + m_pending_irq &= ~NMI_IRQ; + m_halt = false; + } + else if ( m_IF ) + { + /* the actual vector is retrieved after pushing flags */ + /* and clearing the IF */ + interrupt(-1); + m_halt = false; + } + } + + if(m_halt) + { + m_icount = 0; + return; + } + + /* No interrupt allowed between last instruction and this one */ + if ( m_no_interrupt ) + { + m_no_interrupt--; + } + + /* trap should allow one instruction to be executed */ + if ( m_fire_trap ) + { + if ( m_fire_trap >= 2 ) + { + interrupt(1); + m_fire_trap = 0; + } + else + { + m_fire_trap++; + } + } + } + + debugger_instruction_hook( this, pc() ); + + UINT8 op = fetch_op(); + + switch(op) + { + case 0x60: // i_pusha + { + UINT32 tmp = m_regs.w[SP]; + + PUSH(m_regs.w[AX]); + PUSH(m_regs.w[CX]); + PUSH(m_regs.w[DX]); + PUSH(m_regs.w[BX]); + PUSH(tmp); + PUSH(m_regs.w[BP]); + PUSH(m_regs.w[SI]); + PUSH(m_regs.w[DI]); + CLK(PUSHA); + } + break; + + case 0x61: // i_popa + m_regs.w[DI] = POP(); + m_regs.w[SI] = POP(); + m_regs.w[BP] = POP(); + POP(); + m_regs.w[BX] = POP(); + m_regs.w[DX] = POP(); + m_regs.w[CX] = POP(); + m_regs.w[AX] = POP(); + CLK(POPA); + break; + + case 0x62: // i_bound + { + UINT32 low,high,tmp; + m_modrm = fetch(); + low = GetRMWord(); + high = GetnextRMWord(); + tmp = RegWord(); + if (tmphigh) + interrupt(5); + CLK(BOUND); + logerror("%s: %06x: bound %04x high %04x low %04x tmp\n", tag(), pc(), high, low, tmp); + } + break; + + case 0x68: // i_push_d16 + PUSH( fetch_word() ); + CLK(PUSH_IMM); + break; + + case 0x69: // i_imul_d16 + { + UINT32 tmp; + DEF_r16w(); + tmp = fetch_word(); + m_dst = (INT32)((INT16)m_src)*(INT32)((INT16)tmp); + m_CarryVal = m_OverVal = (((INT32)m_dst) >> 15 != 0) && (((INT32)m_dst) >> 15 != -1); + RegWord(m_dst); + CLKM(IMUL_RRI16, IMUL_RMI16); + } + break; + + case 0x6a: // i_push_d8 + PUSH( (UINT16)((INT16)((INT8)fetch())) ); + CLK(PUSH_IMM); + break; + + case 0x6b: // i_imul_d8 + { + UINT32 src2; + DEF_r16w(); + src2= (UINT16)((INT16)((INT8)fetch())); + m_dst = (INT32)((INT16)m_src)*(INT32)((INT16)src2); + m_CarryVal = m_OverVal = (((INT32)m_dst) >> 15 != 0) && (((INT32)m_dst) >> 15 != -1); + RegWord(m_dst); + CLKM(IMUL_RRI8, IMUL_RMI8); + } + break; + + case 0x6c: // i_insb + i_insb(); + break; + + case 0x6d: // i_insw + i_insw(); + break; + + case 0x6e: // i_outsb + i_outsb(); + break; + + case 0x6f: // i_outsw + i_outsw(); + break; + + case 0x8e: // i_mov_sregw + m_modrm = fetch(); + m_src = GetRMWord(); + CLKM(MOV_SR,MOV_SM); + switch (m_modrm & 0x38) + { + case 0x00: /* mov es,ew */ + m_sregs[ES] = m_src; + break; + case 0x10: /* mov ss,ew */ + m_sregs[SS] = m_src; + m_no_interrupt = 1; + break; + case 0x18: /* mov ds,ew */ + m_sregs[DS] = m_src; + break; + default: + logerror("%s: %06x: Mov Sreg - Invalid register\n", tag(), pc()); + m_ip = m_prev_ip; + interrupt(6); + break; + } + break; + + case 0xc0: // i_rotshft_bd8 + { + UINT8 c; + m_modrm = fetch(); + m_src = GetRMByte(); + m_dst = m_src; + c = fetch() & 0x1f; + CLKM(ROT_REG_BASE,ROT_M8_BASE); + m_icount -= m_timing[ROT_REG_BIT] * c; + if (c) + { + switch ( m_modrm & 0x38 ) + { + case 0x00: do { ROL_BYTE(); c--; } while (c>0); PutbackRMByte(m_dst); break; + case 0x08: do { ROR_BYTE(); c--; } while (c>0); PutbackRMByte(m_dst); break; + case 0x10: do { ROLC_BYTE(); c--; } while (c>0); PutbackRMByte(m_dst); break; + case 0x18: do { RORC_BYTE(); c--; } while (c>0); PutbackRMByte(m_dst); break; + case 0x30: + case 0x20: SHL_BYTE(c); break; + case 0x28: SHR_BYTE(c); break; + case 0x38: SHRA_BYTE(c); break; + } + } + } + break; + + case 0xc1: // i_rotshft_wd8 + { + UINT8 c; + m_modrm = fetch(); + m_src = GetRMWord(); + m_dst = m_src; + c = fetch() & 0x1f; + CLKM(ROT_REG_BASE,ROT_M16_BASE); + m_icount -= m_timing[ROT_REG_BIT] * c; + if (c) + { + switch ( m_modrm & 0x38 ) + { + case 0x00: do { ROL_WORD(); c--; } while (c>0); PutbackRMWord(m_dst); break; + case 0x08: do { ROR_WORD(); c--; } while (c>0); PutbackRMWord(m_dst); break; + case 0x10: do { ROLC_WORD(); c--; } while (c>0); PutbackRMWord(m_dst); break; + case 0x18: do { RORC_WORD(); c--; } while (c>0); PutbackRMWord(m_dst); break; + case 0x30: + case 0x20: SHL_WORD(c); break; + case 0x28: SHR_WORD(c); break; + case 0x38: SHRA_WORD(c); break; + } + } + } + break; + + case 0xc8: // i_enter + { + UINT16 nb = fetch(); + UINT32 level; + + nb |= fetch() << 8; + level = fetch(); + CLK(!level ? ENTER0 : (level == 1) ? ENTER1 : ENTER_BASE); + if(level > 1) + m_icount -= level * m_timing[ENTER_COUNT]; + PUSH(m_regs.w[BP]); + m_regs.w[BP] = m_regs.w[SP]; + m_regs.w[SP] -= nb; + for (int i=1; i0); PutbackRMByte(m_dst); break; + case 0x08: do { ROR_BYTE(); c--; } while (c>0); PutbackRMByte(m_dst); break; + case 0x10: do { ROLC_BYTE(); c--; } while (c>0); PutbackRMByte(m_dst); break; + case 0x18: do { RORC_BYTE(); c--; } while (c>0); PutbackRMByte(m_dst); break; + case 0x30: + case 0x20: SHL_BYTE(c); break; + case 0x28: SHR_BYTE(c); break; + case 0x38: SHRA_BYTE(c); break; + } + } + } + break; + + case 0xd3: // i_rotshft_wcl + { + UINT8 c; + + m_modrm = fetch(); + m_src = GetRMWord(); + m_dst = m_src; + c = m_regs.b[CL] & 0x1f; + CLKM(ROT_REG_BASE,ROT_M16_BASE); + m_icount -= m_timing[ROT_REG_BIT] * c; + if (c) + { + switch ( m_modrm & 0x38 ) + { + case 0x00: do { ROL_WORD(); c--; } while (c>0); PutbackRMWord(m_dst); break; + case 0x08: do { ROR_WORD(); c--; } while (c>0); PutbackRMWord(m_dst); break; + case 0x10: do { ROLC_WORD(); c--; } while (c>0); PutbackRMWord(m_dst); break; + case 0x18: do { RORC_WORD(); c--; } while (c>0); PutbackRMWord(m_dst); break; + case 0x30: + case 0x20: SHL_WORD(c); break; + case 0x28: SHR_WORD(c); break; + case 0x38: SHRA_WORD(c); break; + } + } + } + break; + + case 0xd8: // i_esc + case 0xd9: + case 0xda: + case 0xdb: + case 0xdc: + case 0xdd: + case 0xde: + case 0xdf: + if(m_reloc & 0x8000) + { + m_ip = m_prev_ip; + interrupt(7); + break; + } + m_modrm = fetch(); + GetRMByte(); + CLK(NOP); + // The 80187 has the FSTSW AX instruction + if((m_modrm == 0xe0) && (op == 0xdf)) + m_regs.w[AX] = 0xffff; // FPU not present + break; + + case 0xf2: // i_repne + case 0xf3: + { + bool pass = false; + UINT8 next = repx_op(); + UINT16 c = m_regs.w[CX]; + + switch (next) + { + case 0x6c: CLK(OVERRIDE); if (c) do { i_insb(); c--; } while (c>0 && m_icount>0); m_regs.w[CX]=c; m_seg_prefix = false; m_seg_prefix_next = false; break; + case 0x6d: CLK(OVERRIDE); if (c) do { i_insw(); c--; } while (c>0 && m_icount>0); m_regs.w[CX]=c; m_seg_prefix = false; m_seg_prefix_next = false; break; + case 0x6e: CLK(OVERRIDE); if (c) do { i_outsb(); c--; } while (c>0 && m_icount>0); m_regs.w[CX]=c; m_seg_prefix = false; m_seg_prefix_next = false; break; + case 0x6f: CLK(OVERRIDE); if (c) do { i_outsw(); c--; } while (c>0 && m_icount>0); m_regs.w[CX]=c; m_seg_prefix = false; m_seg_prefix_next = false; break; + default: + // Decrement IP and pass on + m_ip -= 1 + (m_seg_prefix_next ? 1 : 0); + pass = true; + break; + } + if(!pass) + { + if(c) + m_ip = m_prev_ip; + break; + } + } + // through to default + default: + if(!common_op(op)) + { + m_icount -= 10; // UD fault timing? + logerror("%s: %06x: Invalid Opcode %02x\n", tag(), pc(), op); + m_ip = m_prev_ip; + interrupt(6); // 80186 has #UD + break; + } + } + } +} + +void i80186_cpu_device::device_start() +{ + i8086_common_cpu_device::device_start(); + state_add( I8086_ES, "ES", m_sregs[ES] ).callimport().callexport().formatstr("%04X"); + state_add( I8086_CS, "CS", m_sregs[CS] ).callimport().callexport().formatstr("%04X"); + state_add( I8086_SS, "SS", m_sregs[SS] ).callimport().callexport().formatstr("%04X"); + state_add( I8086_DS, "DS", m_sregs[DS] ).callimport().callexport().formatstr("%04X"); + state_add( I8086_VECTOR, "V", m_int_vector).callimport().callexport().formatstr("%02X"); + + state_add(STATE_GENPC, "curpc", m_pc).callimport().callexport().formatstr("%05X"); + + // register for savestates + save_item(NAME(m_timer[0].control)); + save_item(NAME(m_timer[0].maxA)); + save_item(NAME(m_timer[0].maxB)); + save_item(NAME(m_timer[0].active_count)); + save_item(NAME(m_timer[0].count)); + save_item(NAME(m_timer[1].control)); + save_item(NAME(m_timer[1].maxA)); + save_item(NAME(m_timer[1].maxB)); + save_item(NAME(m_timer[1].active_count)); + save_item(NAME(m_timer[1].count)); + save_item(NAME(m_timer[2].control)); + save_item(NAME(m_timer[2].maxA)); + save_item(NAME(m_timer[2].count)); + save_item(NAME(m_dma[0].source)); + save_item(NAME(m_dma[0].dest)); + save_item(NAME(m_dma[0].count)); + save_item(NAME(m_dma[0].control)); + save_item(NAME(m_dma[1].source)); + save_item(NAME(m_dma[1].dest)); + save_item(NAME(m_dma[1].count)); + save_item(NAME(m_dma[1].control)); + save_item(NAME(m_intr.pending)); + save_item(NAME(m_intr.ack_mask)); + save_item(NAME(m_intr.priority_mask)); + save_item(NAME(m_intr.in_service)); + save_item(NAME(m_intr.request)); + save_item(NAME(m_intr.status)); + save_item(NAME(m_intr.poll_status)); + save_item(NAME(m_intr.timer)); + save_item(NAME(m_intr.dma)); + save_item(NAME(m_intr.ext)); + save_item(NAME(m_intr.ext_state)); + save_item(NAME(m_mem.lower)); + save_item(NAME(m_mem.upper)); + save_item(NAME(m_mem.middle)); + save_item(NAME(m_mem.middle_size)); + save_item(NAME(m_mem.peripheral)); + save_item(NAME(m_reloc)); + + // zerofill + memset(m_timer, 0, sizeof(m_timer)); + memset(m_dma, 0, sizeof(m_dma)); + memset(&m_intr, 0, sizeof(intr_state)); + memset(&m_mem, 0, sizeof(mem_state)); + m_reloc = 0; + + m_timer[0].int_timer = timer_alloc(TIMER_INT0); + m_timer[1].int_timer = timer_alloc(TIMER_INT1); + m_timer[2].int_timer = timer_alloc(TIMER_INT2); + + m_out_tmrout0_func.resolve_safe(); + m_out_tmrout1_func.resolve_safe(); + m_read_slave_ack_func.resolve_safe(0); + m_out_chip_select_func.resolve_safe(); +} + +void i80186_cpu_device::device_reset() +{ + i8086_common_cpu_device::device_reset(); + /* reset the interrupt state */ + m_intr.priority_mask = 0x0007; + m_intr.timer = 0x000f; + m_intr.dma[0] = 0x000f; + m_intr.dma[1] = 0x000f; + m_intr.ext[0] = 0x000f; + m_intr.ext[1] = 0x000f; + m_intr.ext[2] = 0x000f; + m_intr.ext[3] = 0x000f; + m_intr.in_service = 0x0000; + + m_intr.pending = 0x0000; + m_intr.ack_mask = 0x0000; + m_intr.request = 0x0000; + m_intr.status = 0x0000; + m_intr.poll_status = 0x0000; + m_intr.ext_state = 0x00; + m_reloc = 0x20ff; + + for (int i = 0; i < ARRAY_LENGTH(m_dma); i++) + { + m_dma[i].drq_state = false; + m_dma[i].control = 0; + } + + for (int i = 0; i < ARRAY_LENGTH(m_timer); i++) + { + m_timer[i].control = 0; + m_timer[i].maxA = 0; + m_timer[i].maxB = 0; + m_timer[i].active_count = false; + m_timer[i].count = 0; + } +} + +UINT8 i80186_cpu_device::read_port_byte(UINT16 port) +{ + if(!(m_reloc & 0x1000) && (port >> 8) == (m_reloc & 0xff)) + { + UINT16 ret = internal_port_r(*m_io, (port >> 1) - ((m_reloc & 0xff) << 7), (port & 1) ? 0xff00 : 0x00ff); + return (port & 1) ? (ret >> 8) : (ret & 0xff); + } + return m_io->read_byte(port); +} + +UINT16 i80186_cpu_device::read_port_word(UINT16 port) +{ + if(!(m_reloc & 0x1000) && (port >> 8) == (m_reloc & 0xff)) + { + if(port & 1) + { + UINT8 low = read_port_byte(port); + return read_port_byte(port + 1) << 8 | low; + } + return internal_port_r(*m_io, (port >> 1) - ((m_reloc & 0xff) << 7)); + } + return m_io->read_word_unaligned(port); +} + +void i80186_cpu_device::write_port_byte(UINT16 port, UINT8 data) +{ + if(!(m_reloc & 0x1000) && (port >> 8) == (m_reloc & 0xff)) + internal_port_w(*m_io, (port >> 1) - ((m_reloc & 0xff) << 7), (port & 1) ? (data << 8) : data, (port & 1) ? 0xff00 : 0x00ff); + else + m_io->write_byte(port, data); +} + +void i80186_cpu_device::write_port_word(UINT16 port, UINT16 data) +{ + if(!(m_reloc & 0x1000) && (port >> 8) == (m_reloc & 0xff)) + { + if(port & 1) + { + write_port_byte(port, data & 0xff); + write_port_byte(port + 1, data >> 8); + } + else + internal_port_w(*m_io, (port >> 1) - ((m_reloc & 0xff) << 7), data); + } + else + m_io->write_word_unaligned(port, data); +} + +/************************************* + * + * 80186 interrupt controller + * + *************************************/ +IRQ_CALLBACK_MEMBER(i80186_cpu_device::int_callback) +{ + UINT8 vector; + UINT16 old; + UINT16 oldreq; + + if (LOG_INTERRUPTS) + logerror("(%f) **** Acknowledged interrupt vector %02X\n", machine().time().as_double(), m_intr.poll_status & 0x1f); + + /* clear the interrupt */ + set_input_line(0, CLEAR_LINE); + m_intr.pending = 0; + + oldreq = m_intr.request; + + /* clear the request and set the in-service bit */ + if(m_intr.ack_mask & 0xf0) + { + int i; + for(i = 0; i < 4; i++) + if((m_intr.ack_mask >> (i + 4)) & 1) + break; + if(!(m_intr.ext[i] & EXTINT_CTRL_LTM)) + m_intr.request &= ~m_intr.ack_mask; + } + else + m_intr.request &= ~m_intr.ack_mask; + + if((LOG_INTERRUPTS) && (m_intr.request!=oldreq)) + logerror("intr.request changed from %02X to %02X\n",oldreq,m_intr.request); + + old = m_intr.in_service; + + m_intr.in_service |= m_intr.ack_mask; + + if((LOG_INTERRUPTS) && (m_intr.in_service!=old)) + logerror("intr.in_service changed from %02X to %02X\n",old,m_intr.in_service); + + if (m_intr.ack_mask == 0x0001) + { + switch (m_intr.poll_status & 0x1f) + { + case 0x08: m_intr.status &= ~0x01; break; + case 0x12: m_intr.status &= ~0x02; break; + case 0x13: m_intr.status &= ~0x04; break; + } + } + m_intr.ack_mask = 0; + + /* a request no longer pending */ + m_intr.poll_status &= ~0x8000; + + /* return the vector */ + switch(m_intr.poll_status & 0x1F) + { + case 0x0C: vector = (m_intr.ext[0] & EXTINT_CTRL_CASCADE) ? m_read_slave_ack_func(0) : (m_intr.poll_status & 0x1f); break; + case 0x0D: vector = (m_intr.ext[1] & EXTINT_CTRL_CASCADE) ? m_read_slave_ack_func(1) : (m_intr.poll_status & 0x1f); break; + default: + vector = m_intr.poll_status & 0x1f; break; + } + + if (LOG_INTERRUPTS) + { + logerror("intr.ext[0]=%04X intr.ext[1]=%04X\n",m_intr.ext[0],m_intr.ext[1]); + logerror("Int %02X Calling vector %02X\n",m_intr.poll_status,vector); + } + + return vector; +} + + +void i80186_cpu_device::update_interrupt_state() +{ + int new_vector = 0; + int Priority; + int IntNo; + + if (LOG_INTERRUPTS) + logerror("update_interrupt_status: req=%04X stat=%04X serv=%04X priority_mask=%4X\n", m_intr.request, m_intr.status, m_intr.in_service, m_intr.priority_mask); + + /* loop over priorities */ + for (Priority = 0; Priority <= m_intr.priority_mask; Priority++) + { + /* note: by checking 4 bits, we also verify that the mask is off */ + if ((m_intr.timer & 0x0F) == Priority) + { + /* if we're already servicing something at this level, don't generate anything new */ + if (m_intr.in_service & 0x01) + return; + + /* if there's something pending, generate an interrupt */ + if (m_intr.status & 0x07) + { + if (m_intr.status & 1) + new_vector = 0x08; + else if (m_intr.status & 2) + new_vector = 0x12; + else if (m_intr.status & 4) + new_vector = 0x13; + else + logerror("Invalid timer interrupt!\n"); + + /* set the clear mask and generate the int */ + m_intr.ack_mask = 0x0001; + goto generate_int; + } + } + + /* check DMA interrupts */ + for (IntNo = 0; IntNo < 2; IntNo++) + if ((m_intr.dma[IntNo] & 0x0F) == Priority) + { + /* if we're already servicing something at this level, don't generate anything new */ + if (m_intr.in_service & (0x04 << IntNo)) + return; + + /* if there's something pending, generate an interrupt */ + if (m_intr.request & (0x04 << IntNo)) + { + new_vector = 0x0a + IntNo; + + /* set the clear mask and generate the int */ + m_intr.ack_mask = 0x0004 << IntNo; + goto generate_int; + } + } + + /* check external interrupts */ + for (IntNo = 0; IntNo < 4; IntNo++) + { + if ((m_intr.ext[IntNo] & 0x0F) == Priority) + { + if (LOG_INTERRUPTS) + logerror("Int%d priority=%d\n",IntNo,Priority); + + /* if we're already servicing something at this level, don't generate anything new */ + if ((m_intr.in_service & (0x10 << IntNo)) && !(m_intr.ext[IntNo] & EXTINT_CTRL_SFNM)) + return; + + /* if there's something pending, generate an interrupt */ + if (m_intr.request & (0x10 << IntNo)) + { + if((IntNo >= 2) && (m_intr.ext[IntNo - 2] & EXTINT_CTRL_CASCADE)) + { + logerror("i186: %06x: irq %d use when set for cascade mode\n", pc(), IntNo); + m_intr.request &= ~(0x10 << IntNo); + continue; + } + /* otherwise, generate an interrupt for this request */ + new_vector = 0x0c + IntNo; + + /* set the clear mask and generate the int */ + m_intr.ack_mask = 0x0010 << IntNo; + goto generate_int; + } + else if ((m_intr.in_service & (0x10 << IntNo)) && (m_intr.ext[IntNo] & EXTINT_CTRL_SFNM)) + return; // if an irq is in service and sfnm is enabled, stop here + } + } + } + m_intr.pending = 0; + set_input_line(0, CLEAR_LINE); + return; + +generate_int: + /* generate the appropriate interrupt */ + m_intr.poll_status = 0x8000 | new_vector; + if (!m_intr.pending) + set_input_line(0, ASSERT_LINE); + m_intr.pending = 1; + if (LOG_INTERRUPTS) logerror("(%f) **** Requesting interrupt vector %02X\n", machine().time().as_double(), new_vector); +} + + +void i80186_cpu_device::handle_eoi(int data) +{ + int Priority; + int IntNo; + int handled=0; + + /* specific case */ + if (!(data & 0x8000)) + { + /* turn off the appropriate in-service bit */ + switch (data & 0x1f) + { + case 0x08: m_intr.in_service &= ~0x01; break; + case 0x12: m_intr.in_service &= ~0x01; break; + case 0x13: m_intr.in_service &= ~0x01; break; + case 0x0a: m_intr.in_service &= ~0x04; break; + case 0x0b: m_intr.in_service &= ~0x08; break; + case 0x0c: m_intr.in_service &= ~0x10; break; + case 0x0d: m_intr.in_service &= ~0x20; break; + case 0x0e: m_intr.in_service &= ~0x40; break; + case 0x0f: m_intr.in_service &= ~0x80; break; + default: logerror("%05X:ERROR - 80186 EOI with unknown vector %02X\n", pc(), data & 0x1f); + } + if (LOG_INTERRUPTS) logerror("(%f) **** Got EOI for vector %02X\n", machine().time().as_double(), data & 0x1f); + } + + /* non-specific case */ + else + { + /* loop over priorities */ + for (Priority = 0; ((Priority <= 7) && !handled); Priority++) + { + /* check for in-service timers */ + if ((m_intr.timer & 0x07) == Priority && (m_intr.in_service & 0x01)) + { + m_intr.in_service &= ~0x01; + if (LOG_INTERRUPTS) logerror("(%f) **** Got EOI for timer\n", machine().time().as_double()); + handled=1; + } + + /* check for in-service DMA interrupts */ + for (IntNo = 0; ((IntNo < 2) && !handled) ; IntNo++) + if ((m_intr.dma[IntNo] & 0x07) == Priority && (m_intr.in_service & (0x04 << IntNo))) + { + m_intr.in_service &= ~(0x04 << IntNo); + if (LOG_INTERRUPTS) logerror("(%f) **** Got EOI for DMA%d\n", machine().time().as_double(), IntNo); + handled=1; + } + + /* check external interrupts */ + for (IntNo = 0; ((IntNo < 4) && !handled) ; IntNo++) + if ((m_intr.ext[IntNo] & 0x07) == Priority && (m_intr.in_service & (0x10 << IntNo))) + { + m_intr.in_service &= ~(0x10 << IntNo); + if (LOG_INTERRUPTS) logerror("(%f) **** Got EOI for INT%d\n", machine().time().as_double(), IntNo); + handled=1; + } + } + } + update_interrupt_state(); +} + +/* Trigger an external interrupt, optionally supplying the vector to take */ +void i80186_cpu_device::external_int(UINT16 intno, int state) +{ + if (!(m_intr.ext_state & (1 << intno)) == !state) + return; + + if (LOG_INTERRUPTS_EXT) logerror("generating external int %02X\n",intno); + + if (!state) + { + m_intr.request &= ~(0x10 << intno); + m_intr.ack_mask &= ~(0x10 << intno); + m_intr.ext_state &= ~(1 << intno); + } + else // Turn on the requested request bit and handle interrupt + { + m_intr.request |= (0x10 << intno); + m_intr.ext_state |= (1 << intno); + } + update_interrupt_state(); +} + +/************************************* + * + * 80186 internal timers + * + *************************************/ + +void i80186_cpu_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch(id) + { + case TIMER_INT0: + case TIMER_INT1: + case TIMER_INT2: + { + int which = param; + timer_state *t = &m_timer[which]; + + if (LOG_TIMER) logerror("Hit interrupt callback for timer %d\n", which); + + /* set the max count bit */ + t->control |= 0x0020; + + /* request an interrupt */ + if (t->control & 0x2000) + { + m_intr.status |= 0x01 << which; + update_interrupt_state(); + if (LOG_TIMER) logerror(" Generating timer interrupt\n"); + } + + if(which == 2) + { + if((m_dma[0].control & (TIMER_DRQ | ST_STOP)) == TIMER_DRQ) + drq_callback(0); + if((m_dma[1].control & (TIMER_DRQ | ST_STOP)) == TIMER_DRQ) + drq_callback(1); + if((m_timer[0].control & 0x800c) == 0x8008) + inc_timer(0); + if((m_timer[1].control & 0x800c) == 0x8008) + inc_timer(1); + } + else + { + if(!(t->control & 2)) + { + if(which) + m_out_tmrout1_func(1); + else + m_out_tmrout0_func(1); + } + else + { + if(which) + m_out_tmrout1_func(t->active_count); + else + m_out_tmrout0_func(t->active_count); + } + } + + /* if we're continuous, reset */ + if (t->control & 0x0001) + { + int count; + if((t->control & 2) && (which != 2)) + { + count = t->active_count ? t->maxA : t->maxB; + t->active_count = !t->active_count; + } + else + count = t->maxA; + + count = count ? count : 0x10000; + if(!(t->control & 4)) + t->int_timer->adjust((attotime::from_hz(clock()/8) * count), which); + if (LOG_TIMER) logerror(" Repriming interrupt\n"); + } + else + { + t->int_timer->adjust(attotime::never, which); + t->control &= ~0x8000; + } + t->count = 0; + break; + } + + default: + break; + } +} + + +void i80186_cpu_device::internal_timer_sync(int which) +{ + timer_state *t = &m_timer[which]; + + /* if we have a timing timer running, adjust the count */ + if ((t->control & 0x8000) && !(t->control & 0x0c)) + t->count = (((which != 2) && t->active_count) ? t->maxB : t->maxA) - t->int_timer->remaining().as_ticks(clock() / 8); +} + +void i80186_cpu_device::inc_timer(int which) +{ + timer_state *t = &m_timer[which]; + + t->count++; + if (t->control & 2) + { + if (t->count == (t->active_count ? t->maxB : t->maxA)) + device_timer(*t->int_timer, which, which, NULL); + } + else if (t->count == t->maxA) + device_timer(*t->int_timer, which, which, NULL); +} + +void i80186_cpu_device::internal_timer_update(int which, int new_count, int new_maxA, int new_maxB, int new_control) +{ + timer_state *t = &m_timer[which]; + int update_int_timer = 0; + + if (LOG_TIMER) + logerror("internal_timer_update: %d, new_count=%d, new_maxA=%d, new_maxB=%d,new_control=%d\n", which, new_count, new_maxA, new_maxB, new_control); + + /* if we have a new count and we're on, update things */ + if (new_count != -1) + { + if (t->control & 0x8000) + { + internal_timer_sync(which); + update_int_timer = 1; + } + t->count = new_count; + } + + /* if we have a new max and we're on, update things */ + if (new_maxA != -1 && new_maxA != t->maxA) + { + if (t->control & 0x8000) + { + internal_timer_sync(which); + update_int_timer = 1; + } + + t->maxA = new_maxA; + + if (new_maxA == 0) + { + new_maxA = 0x10000; + } + } + + /* if we have a new max and we're on, update things */ + if (new_maxB != -1 && new_maxB != t->maxB) + { + if (t->control & 0x8000) + { + internal_timer_sync(which); + update_int_timer = 1; + } + + t->maxB = new_maxB; + + if (new_maxB == 0) + { + new_maxB = 0x10000; + } + } + + /* handle control changes */ + if (new_control != -1) + { + int diff; + UINT16 resbits = (which == 2) ? 0x1fde : 0x1fc0; + + /* merge back in the bits we don't modify */ + new_control = (new_control & ~resbits) | (t->control & resbits); + + /* handle the /INH bit */ + if (!(new_control & 0x4000)) + new_control = (new_control & ~0x8000) | (t->control & 0x8000); + new_control &= ~0x4000; + + /* check for control bits we don't handle */ + diff = new_control ^ t->control; + if (diff & 0x0010) + logerror("%05X:ERROR! -unsupported timer mode %04X\n", pc(), new_control); + + /* if we have real changes, update things */ + if (diff != 0) + { + /* if we're going off, make sure our timers are gone */ + if ((diff & 0x8000) && !(new_control & 0x8000)) + { + /* compute the final count */ + internal_timer_sync(which); + update_int_timer = 1; + } + + /* if we're going on, start the timers running except with external clock or prescale */ + else if ((diff & 0x8000) && (new_control & 0x8000) && !(new_control & 0xc)) + { + update_int_timer = 1; + } + + /* if something about the interrupt timer changed, force an update */ + if (!(diff & 0x8000) && (diff & 0x2000)) + { + internal_timer_sync(which); + update_int_timer = 1; + } + } + + /* set the new control register */ + t->control = new_control; + } + + /* update the interrupt timer */ + if (update_int_timer) + { + t->active_count = 0; + if ((t->control & 0x8000) && !(t->control & 4)) + { + int diff = t->maxA - t->count; + if (diff <= 0) + diff += 0x10000; + t->int_timer->adjust(attotime::from_hz(clock()/8) * diff, which); + if (LOG_TIMER) logerror("Set interrupt timer for %d\n", which); + } + else + { + t->int_timer->adjust(attotime::never, which); + } + } +} + + + +/************************************* + * + * 80186 internal DMA + * + *************************************/ + +void i80186_cpu_device::update_dma_control(int which, int new_control) +{ + dma_state *d = &m_dma[which]; + int diff; + + /* handle the CHG bit */ + if (!(new_control & CHG_NOCHG)) + new_control = (new_control & ~ST_STOP) | (d->control & ST_STOP); + new_control &= ~CHG_NOCHG; + + /* check for control bits we don't handle */ + diff = new_control ^ d->control; + if ((LOG_DMA) && (diff & 0x6811)) + logerror("%05X:ERROR! - unsupported DMA mode %04X\n", pc(), new_control); + + if (LOG_DMA) logerror("Initiated DMA %d - count = %04X, source = %04X, dest = %04X\n", which, d->count, d->source, d->dest); + + /* set the new control register */ + d->control = new_control; +} + +void i80186_cpu_device::drq_callback(int which) +{ + dma_state *dma = &m_dma[which]; + + UINT16 dma_word; + UINT8 dma_byte; + UINT8 incdec_size; + + if (LOG_DMA>1) + logerror("Control=%04X, src=%05X, dest=%05X, count=%04X\n",dma->control,dma->source,dma->dest,dma->count); + + if (!(dma->control & ST_STOP)) + { + if(LOG_DMA) + logerror("%05X:ERROR! - drq%d with dma channel stopped\n", pc(), which); + return; + } + + address_space *dest_space = (dma->control & DEST_MIO) ? m_program : m_io; + address_space *src_space = (dma->control & SRC_MIO) ? m_program : m_io; + + // Do the transfer, 80188 is incapable of word transfers + if ((dma->control & BYTE_WORD) && (m_program->data_width() == 16)) + { + dma_word = src_space->read_word_unaligned(dma->source); + dest_space->write_word_unaligned(dma->dest, dma_word); + incdec_size = 2; + } + else + { + dma_byte = src_space->read_byte(dma->source); + dest_space->write_byte(dma->dest, dma_byte); + incdec_size = 1; + } + + // Increment or Decrement destination and source pointers as needed + switch (dma->control & DEST_INCDEC_MASK) + { + case DEST_DECREMENT: + dma->dest -= incdec_size; + break; + case DEST_INCREMENT: + dma->dest += incdec_size; + break; + } + + switch (dma->control & SRC_INCDEC_MASK) + { + case SRC_DECREMENT: + dma->source -= incdec_size; + break; + case SRC_INCREMENT: + dma->source += incdec_size; + break; + } + + // decrement count + dma->count -= 1; + + // Terminate if count is zero, and terminate flag set + if (((dma->control & TERMINATE_ON_ZERO) || !(dma->control & SYNC_MASK)) && (dma->count == 0)) + { + dma->control &= ~ST_STOP; + if (LOG_DMA) logerror("DMA terminated\n"); + } + + // Interrupt if count is zero, and interrupt flag set + if ((dma->control & INTERRUPT_ON_ZERO) && (dma->count == 0)) + { + if (LOG_DMA>1) logerror("DMA%d - requesting interrupt: count = %04X, source = %04X\n", which, dma->count, dma->source); + m_intr.request |= 0x04 << which; + update_interrupt_state(); + } +} + +READ16_MEMBER(i80186_cpu_device::internal_port_r) +{ + int temp, which; + + switch (offset) + { + case 0x11: + logerror("%05X:ERROR - read from 80186 EOI\n", pc()); + break; + + case 0x12: + if (LOG_PORTS) logerror("%05X:read 80186 interrupt poll\n", pc()); + if (m_intr.poll_status & 0x8000) + int_callback(*this, 0); + return m_intr.poll_status; + + case 0x13: + if (LOG_PORTS) logerror("%05X:read 80186 interrupt poll status\n", pc()); + return m_intr.poll_status; + + case 0x14: + if (LOG_PORTS) logerror("%05X:read 80186 interrupt mask\n", pc()); + temp = (m_intr.timer >> 3) & 0x01; + temp |= (m_intr.dma[0] >> 1) & 0x04; + temp |= (m_intr.dma[1] >> 0) & 0x08; + temp |= (m_intr.ext[0] << 1) & 0x10; + temp |= (m_intr.ext[1] << 2) & 0x20; + temp |= (m_intr.ext[2] << 3) & 0x40; + temp |= (m_intr.ext[3] << 4) & 0x80; + return temp; + + case 0x15: + if (LOG_PORTS) logerror("%05X:read 80186 interrupt priority mask\n", pc()); + return m_intr.priority_mask; + + case 0x16: + if (LOG_PORTS) logerror("%05X:read 80186 interrupt in-service\n", pc()); + return m_intr.in_service; + + case 0x17: + if (LOG_PORTS) logerror("%05X:read 80186 interrupt request\n", pc()); + temp = m_intr.request & ~0x0001; + if (m_intr.status & 0x0007) + temp |= 1; + return temp; + + case 0x18: + if (LOG_PORTS) logerror("%05X:read 80186 interrupt status\n", pc()); + return m_intr.status; + + case 0x19: + if (LOG_PORTS) logerror("%05X:read 80186 timer interrupt control\n", pc()); + return m_intr.timer; + + case 0x1a: + if (LOG_PORTS) logerror("%05X:read 80186 DMA 0 interrupt control\n", pc()); + return m_intr.dma[0]; + + case 0x1b: + if (LOG_PORTS) logerror("%05X:read 80186 DMA 1 interrupt control\n", pc()); + return m_intr.dma[1]; + + case 0x1c: + if (LOG_PORTS) logerror("%05X:read 80186 INT 0 interrupt control\n", pc()); + return m_intr.ext[0]; + + case 0x1d: + if (LOG_PORTS) logerror("%05X:read 80186 INT 1 interrupt control\n", pc()); + return m_intr.ext[1]; + + case 0x1e: + if (LOG_PORTS) logerror("%05X:read 80186 INT 2 interrupt control\n", pc()); + return m_intr.ext[2]; + + case 0x1f: + if (LOG_PORTS) logerror("%05X:read 80186 INT 3 interrupt control\n", pc()); + return m_intr.ext[3]; + + case 0x28: + case 0x2c: + case 0x30: + if (LOG_PORTS) logerror("%05X:read 80186 Timer %d count\n", pc(), (offset - 0x28) / 4); + which = (offset - 0x28) / 4; + if (ACCESSING_BITS_0_7) + internal_timer_sync(which); + return m_timer[which].count; + + case 0x29: + case 0x2d: + case 0x31: + if (LOG_PORTS) logerror("%05X:read 80186 Timer %d max A\n", pc(), (offset - 0x29) / 4); + which = (offset - 0x29) / 4; + return m_timer[which].maxA; + + case 0x2a: + case 0x2e: + logerror("%05X:read 80186 Timer %d max B\n", pc(), (offset - 0x2a) / 4); + which = (offset - 0x2a) / 4; + return m_timer[which].maxB; + + case 0x2b: + case 0x2f: + case 0x33: + if (LOG_PORTS) logerror("%05X:read 80186 Timer %d control\n", pc(), (offset - 0x2b) / 4); + which = (offset - 0x2b) / 4; + return m_timer[which].control; + + case 0x50: + if (LOG_PORTS) logerror("%05X:read 80186 upper chip select\n", pc()); + return m_mem.upper; + + case 0x51: + if (LOG_PORTS) logerror("%05X:read 80186 lower chip select\n", pc()); + return m_mem.lower; + + case 0x52: + if (LOG_PORTS) logerror("%05X:read 80186 peripheral chip select\n", pc()); + return m_mem.peripheral; + + case 0x53: + if (LOG_PORTS) logerror("%05X:read 80186 middle chip select\n", pc()); + return m_mem.middle; + + case 0x54: + if (LOG_PORTS) logerror("%05X:read 80186 middle P chip select\n", pc()); + return m_mem.middle_size; + + case 0x60: + case 0x68: + if (LOG_PORTS) logerror("%05X:read 80186 DMA%d lower source address\n", pc(), (offset - 0x60) / 8); + which = (offset - 0x60) / 8; + return m_dma[which].source; + + case 0x61: + case 0x69: + if (LOG_PORTS) logerror("%05X:read 80186 DMA%d upper source address\n", pc(), (offset - 0x61) / 8); + which = (offset - 0x61) / 8; + return m_dma[which].source >> 16; + + case 0x62: + case 0x6a: + if (LOG_PORTS) logerror("%05X:read 80186 DMA%d lower dest address\n", pc(), (offset - 0x62) / 8); + which = (offset - 0x62) / 8; + return m_dma[which].dest; + + case 0x63: + case 0x6b: + if (LOG_PORTS) logerror("%05X:read 80186 DMA%d upper dest address\n", pc(), (offset - 0x63) / 8); + which = (offset - 0x63) / 8; + return m_dma[which].dest >> 16; + + case 0x64: + case 0x6c: + if (LOG_PORTS) logerror("%05X:read 80186 DMA%d transfer count\n", pc(), (offset - 0x64) / 8); + which = (offset - 0x64) / 8; + return m_dma[which].count; + + case 0x65: + case 0x6d: + if (LOG_PORTS) logerror("%05X:read 80186 DMA%d control\n", pc(), (offset - 0x65) / 8); + which = (offset - 0x65) / 8; + return m_dma[which].control; + + case 0x7f: + return m_reloc; + + default: + logerror("%05X:read 80186 port %02X\n", pc(), offset); + break; + } + + return 0x0000; +} + +/************************************* + * + * 80186 internal I/O writes + * + *************************************/ + +WRITE16_MEMBER(i80186_cpu_device::internal_port_w) +{ + int which; + + switch (offset) + { + case 0x11: + if (LOG_PORTS) logerror("%05X:80186 EOI = %04X\n", pc(), data); + handle_eoi(0x8000); + update_interrupt_state(); + break; + + case 0x12: + logerror("%05X:ERROR - write to 80186 interrupt poll = %04X\n", pc(), data); + break; + + case 0x13: + logerror("%05X:ERROR - write to 80186 interrupt poll status = %04X\n", pc(), data); + break; + + case 0x14: + if (LOG_PORTS) logerror("%05X:80186 interrupt mask = %04X\n", pc(), data); + m_intr.timer = (m_intr.timer & ~0x08) | ((data << 3) & 0x08); + m_intr.dma[0] = (m_intr.dma[0] & ~0x08) | ((data << 1) & 0x08); + m_intr.dma[1] = (m_intr.dma[1] & ~0x08) | ((data << 0) & 0x08); + m_intr.ext[0] = (m_intr.ext[0] & ~0x08) | ((data >> 1) & 0x08); + m_intr.ext[1] = (m_intr.ext[1] & ~0x08) | ((data >> 2) & 0x08); + m_intr.ext[2] = (m_intr.ext[2] & ~0x08) | ((data >> 3) & 0x08); + m_intr.ext[3] = (m_intr.ext[3] & ~0x08) | ((data >> 4) & 0x08); + update_interrupt_state(); + break; + + case 0x15: + if (LOG_PORTS) logerror("%05X:80186 interrupt priority mask = %04X\n", pc(), data); + m_intr.priority_mask = data & 0x0007; + update_interrupt_state(); + break; + + case 0x16: + if (LOG_PORTS) logerror("%05X:80186 interrupt in-service = %04X\n", pc(), data); + m_intr.in_service = data & 0x00ff; + update_interrupt_state(); + break; + + case 0x17: + if (LOG_PORTS) logerror("%05X:80186 interrupt request = %04X\n", pc(), data); + m_intr.request = (m_intr.request & ~0x00c0) | (data & 0x00c0); + update_interrupt_state(); + break; + + case 0x18: + if (LOG_PORTS) logerror("%05X:WARNING - wrote to 80186 interrupt status = %04X\n", pc(), data); + m_intr.status = (m_intr.status & ~0x8007) | (data & 0x8007); + update_interrupt_state(); + break; + + case 0x19: + if (LOG_PORTS) logerror("%05X:80186 timer interrupt contol = %04X\n", pc(), data); + m_intr.timer = data & 0x000f; + update_interrupt_state(); + break; + + case 0x1a: + if (LOG_PORTS) logerror("%05X:80186 DMA 0 interrupt control = %04X\n", pc(), data); + m_intr.dma[0] = data & 0x000f; + update_interrupt_state(); + break; + + case 0x1b: + if (LOG_PORTS) logerror("%05X:80186 DMA 1 interrupt control = %04X\n", pc(), data); + m_intr.dma[1] = data & 0x000f; + update_interrupt_state(); + break; + + case 0x1c: + if (LOG_PORTS) logerror("%05X:80186 INT 0 interrupt control = %04X\n", pc(), data); + m_intr.ext[0] = data & 0x007f; + update_interrupt_state(); + break; + + case 0x1d: + if (LOG_PORTS) logerror("%05X:80186 INT 1 interrupt control = %04X\n", pc(), data); + m_intr.ext[1] = data & 0x007f; + update_interrupt_state(); + break; + + case 0x1e: + if (LOG_PORTS) logerror("%05X:80186 INT 2 interrupt control = %04X\n", pc(), data); + m_intr.ext[2] = data & 0x001f; + update_interrupt_state(); + break; + + case 0x1f: + if (LOG_PORTS) logerror("%05X:80186 INT 3 interrupt control = %04X\n", pc(), data); + m_intr.ext[3] = data & 0x001f; + update_interrupt_state(); + break; + + case 0x28: + case 0x2c: + case 0x30: + if (LOG_PORTS) logerror("%05X:80186 Timer %d count = %04X\n", pc(), (offset - 0x28) / 4, data); + which = (offset - 0x28) / 4; + internal_timer_update(which, data, -1, -1, -1); + break; + + case 0x29: + case 0x2d: + case 0x31: + if (LOG_PORTS) logerror("%05X:80186 Timer %d max A = %04X\n", pc(), (offset - 0x29) / 4, data); + which = (offset - 0x29) / 4; + internal_timer_update(which, -1, data, -1, -1); + break; + + case 0x2a: + case 0x2e: + if (LOG_PORTS) logerror("%05X:80186 Timer %d max B = %04X\n", pc(), (offset - 0x2a) / 4, data); + which = (offset - 0x2a) / 4; + internal_timer_update(which, -1, -1, data, -1); + break; + + case 0x2b: + case 0x2f: + case 0x33: + if (LOG_PORTS) logerror("%05X:80186 Timer %d control = %04X\n", pc(), (offset - 0x2b) / 4, data); + which = (offset - 0x2b) / 4; + internal_timer_update(which, -1, -1, -1, data); + break; + + case 0x50: + if (LOG_PORTS) logerror("%05X:80186 upper chip select = %04X\n", pc(), data); + m_mem.upper = data | 0xc038; + m_out_chip_select_func(0, m_mem.upper, 0xffff); + break; + + case 0x51: + if (LOG_PORTS) logerror("%05X:80186 lower chip select = %04X\n", pc(), data); + m_mem.lower = (data & 0x3fff) | 0x0038; + m_out_chip_select_func(1, m_mem.lower, 0xffff); + break; + + case 0x52: + if (LOG_PORTS) logerror("%05X:80186 peripheral chip select = %04X\n", pc(), data); + m_mem.peripheral = data | 0x0038; + m_out_chip_select_func(2, m_mem.peripheral, 0xffff); + break; + + case 0x53: + if (LOG_PORTS) logerror("%05X:80186 middle chip select = %04X\n", pc(), data); + m_mem.middle = data | 0x01f8; + m_out_chip_select_func(3, m_mem.middle, 0xffff); + break; + + case 0x54: + if (LOG_PORTS) logerror("%05X:80186 middle P chip select = %04X\n", pc(), data); + m_mem.middle_size = data | 0x8038; + m_out_chip_select_func(4, m_mem.middle_size, 0xffff); + break; + + case 0x60: + case 0x68: + if (LOG_PORTS) logerror("%05X:80186 DMA%d lower source address = %04X\n", pc(), (offset - 0x60) / 8, data); + which = (offset - 0x60) / 8; + m_dma[which].source = (m_dma[which].source & ~0x0ffff) | (data & 0x0ffff); + break; + + case 0x61: + case 0x69: + if (LOG_PORTS) logerror("%05X:80186 DMA%d upper source address = %04X\n", pc(), (offset - 0x61) / 8, data); + which = (offset - 0x61) / 8; + m_dma[which].source = (m_dma[which].source & ~0xf0000) | ((data << 16) & 0xf0000); + break; + + case 0x62: + case 0x6a: + if (LOG_PORTS) logerror("%05X:80186 DMA%d lower dest address = %04X\n", pc(), (offset - 0x62) / 8, data); + which = (offset - 0x62) / 8; + m_dma[which].dest = (m_dma[which].dest & ~0x0ffff) | (data & 0x0ffff); + break; + + case 0x63: + case 0x6b: + if (LOG_PORTS) logerror("%05X:80186 DMA%d upper dest address = %04X\n", pc(), (offset - 0x63) / 8, data); + which = (offset - 0x63) / 8; + m_dma[which].dest = (m_dma[which].dest & ~0xf0000) | ((data << 16) & 0xf0000); + break; + + case 0x64: + case 0x6c: + if (LOG_PORTS) logerror("%05X:80186 DMA%d transfer count = %04X\n", pc(), (offset - 0x64) / 8, data); + which = (offset - 0x64) / 8; + m_dma[which].count = data; + break; + + case 0x65: + case 0x6d: + if (LOG_PORTS) logerror("%05X:80186 DMA%d control = %04X\n", pc(), (offset - 0x65) / 8, data); + which = (offset - 0x65) / 8; + update_dma_control(which, data); + if((m_dma[which].control & (SYNC_MASK | ST_STOP | TIMER_DRQ)) == ST_STOP) + { + // TODO: don't do this + while(m_dma[which].control & ST_STOP) + drq_callback(which); + } + break; + + case 0x7f: + if (LOG_PORTS) logerror("%05X:80186 relocation register = %04X\n", pc(), data); + if ((data & 0x1fff) != (m_reloc & 0x1fff)) + { + UINT32 newmap = (data & 0xfff) << 8; + UINT32 oldmap = (m_reloc & 0xfff) << 8; + if (!(data & 0x1000) || ((data & 0x1000) && (m_reloc & 0x1000))) + m_program->unmap_readwrite(oldmap, oldmap + 0xff); + if (data & 0x1000) // TODO: make work with 80188 if needed + m_program->install_readwrite_handler(newmap, newmap + 0xff, read16_delegate(FUNC(i80186_cpu_device::internal_port_r), this), write16_delegate(FUNC(i80186_cpu_device::internal_port_w), this)); + } + m_reloc = data; + + break; + + default: + logerror("%05X:80186 port %02X = %04X\n", pc(), offset, data); + break; + } +} diff --git a/src/devices/cpu/i86/i186.h b/src/devices/cpu/i86/i186.h new file mode 100644 index 00000000000..af7302e729a --- /dev/null +++ b/src/devices/cpu/i86/i186.h @@ -0,0 +1,151 @@ +// license:BSD-3-Clause +// copyright-holders:Carl +#ifndef I186_H__ +#define I186_H__ + +#include "emu.h" +#include "i86.h" + +extern const device_type I80186; +extern const device_type I80188; + +class i80186_cpu_device : public i8086_common_cpu_device +{ +public: + // construction/destruction + i80186_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + i80186_cpu_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source, int data_bus_size); + + template static devcb_base &static_set_read_slave_ack_callback(device_t &device, _Object object) { return downcast(device).m_read_slave_ack_func.set_callback(object); } + template static devcb_base &static_set_chip_select_callback(device_t &device, _Object object) { return downcast(device).m_out_chip_select_func.set_callback(object); } + template static devcb_base &static_set_tmrout0_handler(device_t &device, _Object object) { return downcast(device).m_out_tmrout0_func.set_callback(object); } + template static devcb_base &static_set_tmrout1_handler(device_t &device, _Object object) { return downcast(device).m_out_tmrout1_func.set_callback(object); } + + IRQ_CALLBACK_MEMBER(int_callback); + DECLARE_WRITE_LINE_MEMBER(drq0_w) { if(state) drq_callback(0); m_dma[0].drq_state = state; } + DECLARE_WRITE_LINE_MEMBER(drq1_w) { if(state) drq_callback(1); m_dma[1].drq_state = state; } + DECLARE_WRITE_LINE_MEMBER(tmrin0_w) { if(state && (m_timer[0].control & 0x8004) == 0x8004) { inc_timer(0); } } + DECLARE_WRITE_LINE_MEMBER(tmrin1_w) { if(state && (m_timer[1].control & 0x8004) == 0x8004) { inc_timer(1); } } + DECLARE_WRITE_LINE_MEMBER(int0_w) { external_int(0, state); } + DECLARE_WRITE_LINE_MEMBER(int1_w) { external_int(1, state); } + DECLARE_WRITE_LINE_MEMBER(int2_w) { external_int(2, state); } + DECLARE_WRITE_LINE_MEMBER(int3_w) { external_int(3, state); } + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const { return (spacenum == AS_PROGRAM) ? &m_program_config : ( (spacenum == AS_IO) ? &m_io_config : NULL ); } + +protected: + // device_execute_interface overrides + virtual UINT64 execute_clocks_to_cycles(UINT64 clocks) const { return (clocks / 2); } + virtual UINT64 execute_cycles_to_clocks(UINT64 cycles) const { return (cycles * 2); } + virtual void execute_run(); + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + virtual UINT32 execute_input_lines() const { return 1; } + virtual UINT8 fetch_op(); + virtual UINT8 fetch(); + UINT32 pc() { return m_pc = (m_sregs[CS] << 4) + m_ip; } + + virtual UINT8 read_port_byte(UINT16 port); + virtual UINT16 read_port_word(UINT16 port); + virtual void write_port_byte(UINT16 port, UINT8 data); + virtual void write_port_word(UINT16 port, UINT16 data); + + static const UINT8 m_i80186_timing[200]; + +private: + void update_interrupt_state(); + void handle_eoi(int data); + void external_int(UINT16 intno, int state); + void internal_timer_sync(int which); + void internal_timer_update(int which, int new_count, int new_maxA, int new_maxB, int new_control); + void update_dma_control(int which, int new_control); + void drq_callback(int which); + void inc_timer(int which); + DECLARE_READ16_MEMBER(internal_port_r); + DECLARE_WRITE16_MEMBER(internal_port_w); + + struct mem_state + { + UINT16 lower; + UINT16 upper; + UINT16 middle; + UINT16 middle_size; + UINT16 peripheral; + }; + + struct timer_state + { + UINT16 control; + UINT16 maxA; + UINT16 maxB; + bool active_count; + UINT16 count; + emu_timer *int_timer; + }; + + struct dma_state + { + bool drq_state; + UINT32 source; + UINT32 dest; + UINT16 count; + UINT16 control; + }; + + struct intr_state + { + UINT8 pending; + UINT16 ack_mask; + UINT16 priority_mask; + UINT16 in_service; + UINT16 request; + UINT16 status; + UINT16 poll_status; + UINT16 timer; + UINT16 dma[2]; + UINT16 ext[4]; + UINT8 ext_state; + }; + + timer_state m_timer[3]; + dma_state m_dma[2]; + intr_state m_intr; + mem_state m_mem; + + static const device_timer_id TIMER_INT0 = 0; + static const device_timer_id TIMER_INT1 = 1; + static const device_timer_id TIMER_INT2 = 2; + + UINT16 m_reloc; + + address_space_config m_program_config; + address_space_config m_io_config; + + devcb_read8 m_read_slave_ack_func; + devcb_write16 m_out_chip_select_func; + devcb_write_line m_out_tmrout0_func; + devcb_write_line m_out_tmrout1_func; +}; + +class i80188_cpu_device : public i80186_cpu_device +{ +public: + // construction/destruction + i80188_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +#define MCFG_80186_IRQ_SLAVE_ACK(_devcb) \ + devcb = &i80186_cpu_device::static_set_read_slave_ack_callback(*device, DEVCB_##_devcb); + +#define MCFG_80186_CHIP_SELECT_CB(_devcb) \ + devcb = &i80186_cpu_device::static_set_chip_select_callback(*device, DEVCB_##_devcb); + +#define MCFG_80186_TMROUT0_HANDLER(_devcb) \ + devcb = &i80186_cpu_device::static_set_tmrout0_handler(*device, DEVCB_##_devcb); + +#define MCFG_80186_TMROUT1_HANDLER(_devcb) \ + devcb = &i80186_cpu_device::static_set_tmrout1_handler(*device, DEVCB_##_devcb); + +#endif diff --git a/src/devices/cpu/i86/i286.c b/src/devices/cpu/i86/i286.c new file mode 100644 index 00000000000..e6314b9cf83 --- /dev/null +++ b/src/devices/cpu/i86/i286.c @@ -0,0 +1,1989 @@ +// license:BSD-3-Clause +// copyright-holders:Carl +#include "i286.h" +#include "debugger.h" +#include "i86inline.h" + +/* + * Descriptor format + * Data Segment + * 48. . . . . . .40. . . . . . .32. . . . . . .24. . . . . . .16. . . . . . . 8. . . . . . . 0 + * P|DPL|1|0|E|W|A| BASE 23-16 | BASE 15-0 | LIMIT | + * Code Segment + * 48. . . . . . .40. . . . . . .32. . . . . . .24. . . . . . .16. . . . . . . 8. . . . . . . 0 + * P|DPL|1|1|C|R|A| BASE 23-16 | BASE 15-0 | LIMIT | + * System + * 48. . . . . . .40. . . . . . .32. . . . . . .24. . . . . . .16. . . . . . . 8. . . . . . . 0 + * P|DPL|0| TYPE | BASE 23-16 | BASE 15-0 | LIMIT | + * + * P == Present + * A == Accessed + * E == Expand Down + * W == Read/Write + * C == Conforming + * R == Readable + * DPL == Descriptor Privilege Level + * + * Bits 48-64 are ignored but reserved for the 80386 + */ + +#define LIMIT(desc) (desc[0]&0xffff) +#define BASE(desc) ((desc[1]&0xffff)|((desc[2]&0xff)<<16)) +#define RIGHTS(desc) ((desc[2]>>8)&0xff) + +#define ACCESS(r) (r&1) +#define SET_ACC(desc) (desc[2]|=0x100) +#define RW(r) ((r>>1)&1) +#define READ(r) ((r>>1)&1) +#define CONF(r) ((r>>2)&1) +#define EXPDOWN(r) ((r>>2)&1) +#define CODE(r) ((r>>3)&1) +#define SEGDESC(r) ((r>>4)&1) +#define DPL(r) ((r>>5)&3) +#define PRES(r) ((r>>7)&1) +#define GATE(r) (r&31) +#define GATESEL(desc) (desc[1]) +#define GATEOFF(desc) (desc[0]) +#define GATECNT(desc) (desc[2]&31) + +#define RPL(s) (s&3) +#define IDX(s) (s&(~7)) +#define IDXTBL(s) (s&(~3)) +#define TBL(s) (s&4) + +#define TSSDESCIDLE 1 +#define LDTDESC 2 +#define TSSDESCBUSY 3 +#define CALLGATE 4 +#define TASKGATE 5 +#define INTGATE 6 +#define TRAPGATE 7 + +#define TSS_BACK 0 +#define TSS_SP0 1 +#define TSS_SS0 2 +#define TSS_SP1 3 +#define TSS_SS1 4 +#define TSS_SP2 5 +#define TSS_SS2 6 +#define TSS_IP 7 +#define TSS_FLAG 8 +#define TSS_AX 9 +#define TSS_CX 10 +#define TSS_DX 11 +#define TSS_BX 12 +#define TSS_SP 13 +#define TSS_BP 14 +#define TSS_SI 15 +#define TSS_DI 16 +#define TSS_ES 17 +#define TSS_CS 18 +#define TSS_SS 19 +#define TSS_DS 20 +#define TSS_LDT 21 + +#define PMAX(a,b) ((a; + +i80286_cpu_device::i80286_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : i8086_common_cpu_device(mconfig, I80286, "I80286", tag, owner, clock, "i80286", __FILE__) + , m_program_config("program", ENDIANNESS_LITTLE, 16, 24, 0) + , m_io_config("io", ENDIANNESS_LITTLE, 16, 16, 0) + , m_out_shutdown_func(*this) +{ + memcpy(m_timing, m_i80286_timing, sizeof(m_i80286_timing)); + m_amask = 0xffffff; + m_fetch_xor = BYTE_XOR_LE(0); + memset(m_sregs, 0x00, sizeof(m_sregs)); + m_sregs[CS] = 0xf000; + memset(m_base, 0x00, sizeof(m_base)); + m_base[CS] = 0xff0000; + memset(m_limit, 0x00, sizeof(m_limit)); + m_limit[CS] = m_limit[SS] = m_limit[DS] = m_limit[ES] = 0xffff; + memset(m_rights, 0x00, sizeof(m_rights)); + m_rights[DS] = m_rights[SS] = m_rights[ES] = 0x93; + memset(&m_gdtr, 0x00, sizeof(m_gdtr)); + memset(&m_idtr, 0x00, sizeof(m_idtr)); + m_idtr.limit = 0x3ff; + memset(&m_ldtr, 0x00, sizeof(m_ldtr)); + memset(&m_tr, 0x00, sizeof(m_tr)); + m_msw = 0xfff0; +} + +void i80286_cpu_device::device_reset() +{ + i8086_common_cpu_device::device_reset(); + m_MF = 0; + m_NT = 0; + m_IOPL = 0; + m_msw = 0xfff0; + m_limit[CS] = m_limit[SS] = m_limit[DS] = m_limit[ES] = 0xffff; + m_sregs[DS] = m_sregs[SS] = m_sregs[ES] = 0; + m_base[DS] = m_base[SS] = m_base[ES] = 0; + m_rights[DS] = m_rights[SS] = m_rights[ES] = 0x93; + m_rights[CS] = 0x9b; + m_valid[CS] = m_valid[SS] = m_valid[DS] = m_valid[ES] = true; + m_idtr.base = 0; + m_idtr.limit = 0x3ff; + m_gdtr.base = m_ldtr.base = m_tr.base = 0; + m_gdtr.limit = m_ldtr.limit = m_tr.limit = 0; + m_ldtr.rights = m_tr.rights = 0; + m_ldtr.sel = m_tr.sel = 0; + m_sregs[CS] = 0xf000; + m_base[CS] = 0xff0000; + m_ip = 0xfff0; + m_trap_level = 0; + m_shutdown = false; + m_out_shutdown_func(false); +} + +void i80286_cpu_device::device_start() +{ + i8086_common_cpu_device::device_start(); + save_item(NAME(m_trap_level)); + save_item(NAME(m_msw)); + save_item(NAME(m_base)); + save_item(NAME(m_limit)); + save_item(NAME(m_rights)); + save_item(NAME(m_valid)); + save_item(NAME(m_gdtr.base)); + save_item(NAME(m_gdtr.limit)); + save_item(NAME(m_idtr.base)); + save_item(NAME(m_idtr.limit)); + save_item(NAME(m_ldtr.sel)); + save_item(NAME(m_ldtr.base)); + save_item(NAME(m_ldtr.limit)); + save_item(NAME(m_ldtr.rights)); + save_item(NAME(m_tr.sel)); + save_item(NAME(m_tr.base)); + save_item(NAME(m_tr.limit)); + save_item(NAME(m_tr.rights)); + save_item(NAME(m_amask)); + save_item(NAME(m_shutdown)); + + state_add( I286_ES, "ES", m_sregs[ES] ).callimport().callexport().formatstr("%04X"); + state_add( I286_ES_BASE, "ESBASE", m_base[ES]).callimport().callexport().formatstr("%06X"); + state_add( I286_ES_LIMIT, "ESLIMIT", m_limit[ES]).callimport().callexport().formatstr("%04X"); + state_add( I286_ES_FLAGS, "ESFLAGS", m_rights[ES]).callimport().callexport().formatstr("%02X"); + state_add( I286_CS, "CS", m_sregs[CS] ).callimport().callexport().formatstr("%04X"); + state_add( I286_CS_BASE, "CSBASE", m_base[CS]).callimport().callexport().formatstr("%06X"); + state_add( I286_CS_LIMIT, "CSLIMIT", m_limit[CS]).callimport().callexport().formatstr("%04X"); + state_add( I286_CS_FLAGS, "CSFLAGS", m_rights[CS]).callimport().callexport().formatstr("%02X"); + state_add( I286_SS, "SS", m_sregs[SS] ).callimport().callexport().formatstr("%04X"); + state_add( I286_SS_BASE, "SSBASE", m_base[SS]).callimport().callexport().formatstr("%06X"); + state_add( I286_SS_LIMIT, "SSLIMIT", m_limit[SS]).callimport().callexport().formatstr("%04X"); + state_add( I286_SS_FLAGS, "SSFLAGS", m_rights[SS]).callimport().callexport().formatstr("%02X"); + state_add( I286_DS, "DS", m_sregs[DS] ).callimport().callexport().formatstr("%04X"); + state_add( I286_DS_BASE, "DSBASE", m_base[DS]).callimport().callexport().formatstr("%06X"); + state_add( I286_DS_LIMIT, "DSLIMIT", m_limit[DS]).callimport().callexport().formatstr("%04X"); + state_add( I286_DS_FLAGS, "DSFLAGS", m_rights[DS]).callimport().callexport().formatstr("%02X"); + state_add( I286_GDTR_BASE, "GDTRBASE", m_gdtr.base).callimport().callexport().formatstr("%06X"); + state_add( I286_GDTR_LIMIT, "GDTRLIMIT", m_gdtr.limit).callimport().callexport().formatstr("%04X"); + state_add( I286_IDTR_BASE, "IDTRBASE", m_idtr.base).callimport().callexport().formatstr("%06X"); + state_add( I286_IDTR_LIMIT, "IDTRLIMIT", m_idtr.limit).callimport().callexport().formatstr("%04X"); + state_add( I286_LDTR, "LDTR", m_ldtr.sel ).callimport().callexport().formatstr("%04X"); + state_add( I286_LDTR_BASE, "LDTRBASE", m_ldtr.base).callimport().callexport().formatstr("%06X"); + state_add( I286_LDTR_LIMIT, "LDTRLIMIT", m_ldtr.limit).callimport().callexport().formatstr("%04X"); + state_add( I286_LDTR_FLAGS, "LDTRFLAGS", m_ldtr.rights).callimport().callexport().formatstr("%02X"); + state_add( I286_TR, "TR", m_tr.sel ).callimport().callexport().formatstr("%04X"); + state_add( I286_TR_BASE, "TRBASE", m_tr.base).callimport().callexport().formatstr("%06X"); + state_add( I286_TR_LIMIT, "TRLIMIT", m_tr.limit).callimport().callexport().formatstr("%04X"); + state_add( I286_TR_FLAGS, "TRFLAGS", m_tr.rights).callimport().callexport().formatstr("%02X"); + state_add( I286_MSW, "MSW", m_msw ).callimport().callexport().formatstr("%04X"); + state_add( I286_VECTOR, "V", m_int_vector).callimport().callexport().formatstr("%02X"); + + state_add(STATE_GENPC, "curpc", m_pc).callimport().callexport().formatstr("%06X"); + m_out_shutdown_func.resolve_safe(); +} + +void i80286_cpu_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + switch (entry.index()) + { + case STATE_GENPC: + strprintf(str, "%08X", pc()); + break; + + case STATE_GENFLAGS: + { + UINT16 flags = CompressFlags(); + strprintf(str, "%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c", + flags & 0x8000 ? '0':'.', + flags & 0x4000 ? 'N':'.', + flags & 0x2000 ? 'I':'.', + flags & 0x1000 ? 'I':'.', + flags & 0x0800 ? 'O':'.', + flags & 0x0400 ? 'D':'.', + flags & 0x0200 ? 'I':'.', + flags & 0x0100 ? 'T':'.', + flags & 0x0080 ? 'S':'.', + flags & 0x0040 ? 'Z':'.', + flags & 0x0020 ? '0':'.', + flags & 0x0010 ? 'A':'.', + flags & 0x0008 ? '0':'.', + flags & 0x0004 ? 'P':'.', + flags & 0x0002 ? '1':'.', + flags & 0x0001 ? 'C':'.'); + } + break; + } +} + +bool i80286_cpu_device::memory_translate(address_spacenum spacenum, int intention, offs_t &address) +{ + if(spacenum == AS_PROGRAM) + address &= m_amask; + + return TRUE; +} + +void i80286_cpu_device::execute_set_input(int inptnum, int state) +{ + if(inptnum == INPUT_LINE_NMI) + { + if(m_nmi_state == state) + { + return; + } + m_nmi_state = state; + if(state != CLEAR_LINE) + { + m_pending_irq |= NMI_IRQ; + } + } + else if(inptnum == INPUT_LINE_A20) + m_amask = m_a20_callback.isnull() ? 0xffffff : m_a20_callback(state); + else + { + m_irq_state = state; + if(state == CLEAR_LINE) + { + m_pending_irq &= ~INT_IRQ; + } + else + { + m_pending_irq |= INT_IRQ; + } + } +} +// when a cpu reset happens on a AT the bios checks for 9 in byte 0xf +// of the nvram. if yes, after init, it sets the stack pointer to the value in 0040:0067 +// in the bios data segment then pops es and ds off that stack, does popa then a far ret. + +void i80286_cpu_device::trap(UINT32 error) +{ + int error_code = error & 0xffff; + UINT16 number = error >> 16; + if(error_code == 0xffff) + error_code = -1; + m_ip = m_prev_ip; + try + { + switch(number) + { + case FAULT_DE: + case FAULT_TS: + case FAULT_NP: + case FAULT_SS: + case FAULT_GP: + m_trap_level++; + if(m_trap_level == 2) + throw TRAP(FAULT_DF,0); + if(m_trap_level == 3) + break; + interrupt_descriptor(number,1,error_code); + break; + case FAULT_DF: + interrupt_descriptor(number,1,0); + break; + default: + interrupt_descriptor(number,1,-1); + } + } + catch(UINT32 e) + { + trap(e); + } + if(m_trap_level == 3) + { + m_shutdown = true; + m_out_shutdown_func(true); + } + m_trap_level = 0; +} + +UINT32 i80286_cpu_device::selector_address(UINT16 sel) +{ + UINT32 base; + UINT16 limit; + if(TBL(sel)) + { + base = m_ldtr.base; + limit = m_ldtr.limit; + } + else + { + base = m_gdtr.base; + limit = m_gdtr.limit; + } + return ((IDX(sel) >= limit) || !IDXTBL(sel) ? -1 : base + IDX(sel)); +} + +int i80286_cpu_device::verify(UINT16 selector, int operation, UINT8 rights, bool valid) +{ + if(!IDXTBL(selector) && !valid) + return FAULT_GP; + if(!SEGDESC(rights)) + return FAULT_GP; + + switch (operation) + { + case I8086_READ: + if(CODE(rights) && !READ(rights)) + return FAULT_GP; + break; + case I8086_WRITE: + if(CODE(rights) || !RW(rights)) + return FAULT_GP; + break; + case I8086_FETCH: + if(!CODE(rights)) + return FAULT_GP; + break; + } + return 0; +} + +void i80286_cpu_device::pop_seg(int reg) +{ + UINT16 sel; + if(PM) + check_permission(SS, m_regs.w[SP], 2, I8086_READ); + sel = read_word(m_base[SS] + m_regs.w[SP]); + data_descriptor(reg, sel); + m_regs.w[SP] += 2; +} + +void i80286_cpu_device::data_descriptor(int reg, UINT16 selector, int cpl, UINT32 trap, UINT16 offset, int size) +{ + if(PM) + { + UINT16 desc[3]; + UINT8 r; + UINT32 addr; + if((reg != SS) && !IDXTBL(selector)) + { + m_sregs[reg] = 0; + m_limit[reg] = 0; + m_base[reg] = 0; + m_rights[reg] = 0; + m_valid[reg] = 0; + return; + } + + if((addr = selector_address(selector)) == -1) + throw trap; + + desc[0] = read_word(addr); + desc[1] = read_word(addr + 2); + desc[2] = read_word(addr + 4); + r = RIGHTS(desc); + + if(!SEGDESC(r)) + throw trap; + + if(reg == SS) + { + if(!IDXTBL(selector)) + throw trap; + if(DPL(r) != cpl) + throw trap; + if(RPL(selector) != cpl) + throw trap; + if(!RW(r) || CODE(r)) + throw trap; + if(!PRES(r)) + throw TRAP(FAULT_SS, (IDXTBL(selector) + (trap & 1))); + } + else + { + if((DPL(r) < PMAX(cpl, RPL(selector))) && (!CODE(r) || (CODE(r) && !CONF(r)))) + throw trap; + if(CODE(r) && !READ(r)) + throw trap; + if(!PRES(r)) + throw TRAP(FAULT_NP, (IDXTBL(selector) + (trap & 1))); + } + + if(offset + size) + { + if((CODE(r) || !EXPDOWN(r)) && ((offset + size - 1) > LIMIT(desc))) + throw (reg==SS) ? TRAP(FAULT_SS, (trap & 1)) : trap; + + if(!CODE(r) && EXPDOWN(r) && ((offset <= LIMIT(desc)) || ((offset + size - 1) > 0xffff))) + throw (reg==SS) ? TRAP(FAULT_SS, (trap & 1)) : trap; + } + + SET_ACC(desc); + write_word(addr + 4, desc[2]); + m_sregs[reg] = selector; + m_limit[reg] = LIMIT(desc); + m_base[reg] = BASE(desc); + m_rights[reg] = RIGHTS(desc); + } + else + { + m_sregs[reg] = selector; + m_base[reg] = selector << 4; + } + m_valid[reg] = 1; +} + +void i80286_cpu_device::data_descriptor(int reg, UINT16 selector) +{ + data_descriptor(reg, selector, CPL, TRAP(FAULT_GP,IDXTBL(selector))); +} + +void i80286_cpu_device::switch_task(UINT16 ntask, int type) +{ + UINT16 ndesc[3], desc[3], ntss[22], otss[22], flags; + UINT8 r, lr; + UINT32 naddr, oaddr, ldtaddr; + int i; + logerror("i286: %06x This program uses TSSs, how rare. Please report this to the developers.\n", pc()); + + if(TBL(ntask)) + throw TRAP(FAULT_TS, IDXTBL(ntask)); + + if((naddr = selector_address(ntask)) == -1) + throw TRAP(FAULT_TS, IDXTBL(ntask)); + + oaddr = selector_address(m_tr.sel); + ndesc[0] = read_word(naddr); + ndesc[1] = read_word(naddr + 2); + ndesc[2] = read_word(naddr + 4); + desc[2] = read_word(oaddr + 4); + r = RIGHTS(ndesc); + + if(SEGDESC(r) || ((GATE(r) & ~2) != TSSDESCIDLE)) + throw TRAP(FAULT_GP, IDXTBL(ntask)); + + if(!PRES(r)) + throw TRAP(FAULT_NP, IDXTBL(ntask)); + + if(LIMIT(ndesc) < 43) + throw TRAP(FAULT_TS, IDXTBL(ntask)); + + flags = CompressFlags(); + + if(type == NT_CALL) + write_word(BASE(ndesc) + TSS_BACK * 2, m_tr.sel); + + if(type == NT_IRET) + flags &= ~0x4000; + + otss[TSS_IP] = m_ip; + otss[TSS_FLAG] = flags; + otss[TSS_AX] = m_regs.w[AX]; + otss[TSS_CX] = m_regs.w[CX]; + otss[TSS_DX] = m_regs.w[DX]; + otss[TSS_BX] = m_regs.w[BX]; + otss[TSS_SP] = m_regs.w[SP]; + otss[TSS_BP] = m_regs.w[BP]; + otss[TSS_SI] = m_regs.w[SI]; + otss[TSS_DI] = m_regs.w[DI]; + otss[TSS_ES] = m_sregs[ES]; + otss[TSS_CS] = m_sregs[CS]; + otss[TSS_SS] = m_sregs[SS]; + otss[TSS_DS] = m_sregs[DS]; + + for (i = 14; i < 42; i += 2) + write_word(m_tr.base + i, otss[i / 2]); + + for (i = 0; i < 44; i += 2) + ntss[i / 2] = read_word(BASE(ndesc) + i); + + // jmp does both + if(type != NT_CALL) + { + desc[2] &= ~0x200; // mark idle + write_word(oaddr + 4, desc[2]); + } + + if(type != NT_IRET) + { + ndesc[2] |= 0x200; + write_word(naddr + 4, ndesc[2]); + } + + m_tr.sel = ntask; + m_tr.limit = LIMIT(ndesc); + m_tr.base = BASE(ndesc); + m_tr.rights = RIGHTS(ndesc); + + load_flags(ntss[TSS_FLAG], 0); + m_regs.w[AX] = ntss[TSS_AX]; + m_regs.w[CX] = ntss[TSS_CX]; + m_regs.w[DX] = ntss[TSS_DX]; + m_regs.w[BX] = ntss[TSS_BX]; + m_regs.w[SP] = ntss[TSS_SP]; + m_regs.w[BP] = ntss[TSS_BP]; + m_regs.w[SI] = ntss[TSS_SI]; + m_regs.w[DI] = ntss[TSS_DI]; + + if(TBL(ntss[TSS_LDT])) + throw TRAP(FAULT_TS, IDXTBL(ntss[TSS_LDT])); + + if(IDXTBL(ntss[TSS_LDT])) + { + if((ldtaddr = selector_address(ntss[TSS_LDT])) == -1) + throw TRAP(FAULT_TS, IDXTBL(ntss[TSS_LDT])); + + desc[0] = read_word(ldtaddr); + desc[1] = read_word(ldtaddr + 2); + desc[2] = read_word(ldtaddr + 4); + lr = RIGHTS(desc); + + if(SEGDESC(lr) || (GATE(lr) != LDTDESC)) + throw TRAP(FAULT_TS, IDXTBL(ntss[TSS_LDT])); + + if(!PRES(lr)) + throw TRAP(FAULT_TS, IDXTBL(ntss[TSS_LDT])); + + m_ldtr.sel = ntss[TSS_LDT]; + m_ldtr.limit = LIMIT(desc); + m_ldtr.base = BASE(desc); + m_ldtr.rights = RIGHTS(desc); + } + else + { + m_ldtr.sel = 0; + m_ldtr.limit = 0; + m_ldtr.base = 0; + m_ldtr.rights = 0; + } + + if(type == NT_CALL) + m_NT = 1; + + m_msw |= 8; + // Docs explicitly say SS is loaded first. Why? Because the DPL + // of the TSS is compared to the DPL of SS which is CPL + data_descriptor(SS, ntss[TSS_SS], RPL(ntss[TSS_CS]), TRAP(FAULT_TS, IDXTBL(ntss[TSS_SS]))); + + try + { + code_descriptor(ntss[TSS_CS], ntss[TSS_IP], 0); + } + catch (UINT32 e) + { + int error_code = e & 0xffff; + if(error_code == FAULT_GP) + e = TRAP(FAULT_TS, (e >> 16)); // #NP fault is correct + throw e; + } + + data_descriptor(ES, ntss[TSS_ES], CPL, TRAP(FAULT_TS, IDXTBL(ntss[TSS_ES]))); + data_descriptor(DS, ntss[TSS_DS], CPL, TRAP(FAULT_TS, IDXTBL(ntss[TSS_DS]))); +} + +void i80286_cpu_device::code_descriptor(UINT16 selector, UINT16 offset, int gate) +{ + if(PM) + { + UINT16 desc[3]; + UINT8 r; + UINT32 addr; + if((addr = selector_address(selector)) == -1) + throw TRAP(FAULT_GP, IDXTBL(selector)); + + desc[0] = read_word(addr); + desc[1] = read_word(addr + 2); + desc[2] = read_word(addr + 4); + r = RIGHTS(desc); + + if(SEGDESC(r)) + { + if(!CODE(r)) + throw TRAP(FAULT_GP, IDXTBL(selector)); + + if(CONF(r)) + { + if(DPL(r) > CPL) + throw TRAP(FAULT_GP, IDXTBL(selector)); + } + else + if((RPL(selector) > CPL) || (DPL(r) != CPL)) + throw TRAP(FAULT_GP, IDXTBL(selector)); + + if(!PRES(r)) + throw TRAP(FAULT_NP, IDXTBL(selector)); // this order is important + + if(offset > LIMIT(desc)) + throw TRAP(FAULT_GP, 0); + + SET_ACC(desc); + write_word(addr + 4, desc[2]); + m_sregs[CS] = IDXTBL(selector) | CPL; + m_limit[CS] = LIMIT(desc); + m_base[CS] = BASE(desc); + m_rights[CS] = RIGHTS(desc); + m_ip = offset; + } + else + { // systemdescriptor + UINT16 gatesel = GATESEL(desc); + + if(!gate) + throw TRAP(FAULT_GP, IDXTBL(selector)); // tss cs must be segment + if(DPL(r) < PMAX(CPL,RPL(selector))) + throw TRAP(FAULT_GP, IDXTBL(selector)); + if(!PRES(r)) + throw TRAP(FAULT_NP, IDXTBL(selector)); + + switch (GATE(r)) + { + case CALLGATE: + { + UINT16 gatedesc[3]; + if((addr = selector_address(gatesel)) == -1) + throw TRAP(FAULT_GP, IDXTBL(gatesel)); + + gatedesc[0] = read_word(addr); + gatedesc[1] = read_word(addr + 2); + gatedesc[2] = read_word(addr + 4); + r = RIGHTS(gatedesc); + + if(!CODE(r) || !SEGDESC(r)) + throw TRAP(FAULT_GP, IDXTBL(gatesel)); + if(DPL(r) > CPL) + throw TRAP(FAULT_GP, IDXTBL(gatesel)); + if(!PRES(r)) + throw TRAP(FAULT_NP, IDXTBL(gatesel)); + + if(GATEOFF(desc) > LIMIT(gatedesc)) + throw TRAP(FAULT_GP,0); + + if (!CONF(r) && (DPL(r) < CPL)) + { + // inner call + UINT16 tss_ss, tss_sp, oldss, oldsp; + UINT32 oldstk; + int i; + if(gate == NT_JMP) + throw TRAP(FAULT_GP, IDXTBL(gatesel)); // can't jmp to inner + + tss_ss = read_word(m_tr.base+TSS_SS0*2+(DPL(r)*4)); + tss_sp = read_word(m_tr.base+TSS_SP0*2+(DPL(r)*4)); + + oldss = m_sregs[SS]; + oldsp = m_regs.w[SP]; + oldstk = m_base[SS] + oldsp; + data_descriptor(SS, tss_ss, DPL(r), TRAP(FAULT_TS,IDXTBL(tss_ss)), tss_sp-8-(GATECNT(desc)*2), 8+(GATECNT(desc)*2)); + m_regs.w[SP] = tss_sp; + PUSH(oldss); + PUSH(oldsp); + for(i = GATECNT(desc)-1; i >= 0; i--) + PUSH(read_word(oldstk+(i*2))); + } + else + check_permission(SS, m_regs.w[SP]-4, 4, I8086_READ); + + SET_ACC(gatedesc); + write_word(addr+4, gatedesc[2]); + m_sregs[CS]=IDXTBL(gatesel) | DPL(r); + m_limit[CS]=LIMIT(gatedesc); + m_base[CS]=BASE(gatedesc); + m_rights[CS]=RIGHTS(gatedesc); + m_ip=GATEOFF(desc); + break; + } + + case TASKGATE: + selector = gatesel; + if((addr = selector_address(selector)) == -1) + throw TRAP(FAULT_GP, IDXTBL(selector)); + + desc[2] = read_word(addr+4); + r = RIGHTS(desc); + if (SEGDESC(r) || (GATE(r) != TSSDESCIDLE)) + throw TRAP(FAULT_GP,IDXTBL(selector)); + + case TSSDESCIDLE: + switch_task(selector, gate); + load_flags(CompressFlags(), CPL); + break; + + default: + throw TRAP(FAULT_GP,IDXTBL(selector)); + } + } + } + else + { + m_ip = offset; + m_sregs[CS]=selector; + m_base[CS]=selector<<4; + m_rights[CS]=0x9b; + m_limit[CS]=0xffff; + } +} + +void i80286_cpu_device::interrupt_descriptor(int number, int hwint, int error) +{ + UINT16 desc[3], gatesel, flags = CompressFlags(); + UINT8 r; + hwint = hwint ? 1 : 0; + + if(number == -1) + { + number = standard_irq_callback(0); + + m_irq_state = CLEAR_LINE; + m_pending_irq &= ~INT_IRQ; + hwint = 1; + } + + if(!PM) + { + PUSH(flags & ~0xf000); + m_TF = m_IF = 0; + + UINT16 dest_off = read_word(number * 4 + 0); + UINT16 dest_seg = read_word(number * 4 + 2); + + PUSH(m_sregs[CS]); + PUSH(m_ip); + code_descriptor(dest_seg, dest_off, 0); + return; + } + + if((number << 3) >= m_idtr.limit) + throw TRAP(FAULT_GP, (number * 8 + 2 + hwint)); + + desc[0] = read_word(m_idtr.base + (number << 3)); + desc[1] = read_word(m_idtr.base + (number << 3) + 2); + desc[2] = read_word(m_idtr.base + (number << 3) + 4); + + r = RIGHTS(desc); + if(!hwint && (DPL(r) < CPL)) + throw TRAP(FAULT_GP, (number * 8 + 2 + hwint)); + if(!PRES(r)) + throw TRAP(FAULT_NP, (number * 8 + 2 + hwint)); + gatesel = GATESEL(desc); + + switch (GATE(r)) + { + case TASKGATE: + try + { + switch_task(gatesel, NT_CALL); + } + catch (UINT32 e) + { + throw e + hwint; + } + if((hwint == 1) && (error != -1)) + PUSH(error); + load_flags(CompressFlags(), CPL); // new flags + break; + + case INTGATE: + case TRAPGATE: + { + UINT16 gatedesc[3]; + UINT32 addr; + + if((addr = selector_address(gatesel)) == -1) + throw TRAP(FAULT_GP, (IDXTBL(gatesel) + hwint)); + + gatedesc[0] = read_word(addr); + gatedesc[1] = read_word(addr + 2); + gatedesc[2] = read_word(addr + 4); + r = RIGHTS(gatedesc); + if(!CODE(r) || !SEGDESC(r)) + throw TRAP(FAULT_GP, (IDXTBL(gatesel) + hwint)); + if(DPL(r) > CPL) + throw TRAP(FAULT_GP, (IDXTBL(gatesel) + hwint)); + if(!PRES(r)) + throw TRAP(FAULT_NP, (IDXTBL(gatesel) + hwint)); + if(GATEOFF(desc) > LIMIT(gatedesc)) + throw TRAP(FAULT_GP, hwint); + + if(!CONF(r) && (DPL(r) < CPL)) + { + // inner call + UINT16 tss_ss, tss_sp, oldss, oldsp; + tss_ss = read_word(m_tr.base + TSS_SS0 * 2 + (DPL(r) * 4)); + tss_sp = read_word(m_tr.base + TSS_SP0 * 2 + (DPL(r) * 4)); + + oldss = m_sregs[SS]; + oldsp = m_regs.w[SP]; + data_descriptor(SS, tss_ss, DPL(r), TRAP(FAULT_TS, (IDXTBL(tss_ss) + hwint)), tss_sp - ((error != -1) ? 12 : 10), (error != -1) ? 12 : 10); + m_regs.w[SP] = tss_sp; + PUSH(oldss); + PUSH(oldsp); + } + else + check_permission(SS, m_regs.w[SP] - ((error != -1) ? 8 : 6), (error != -1) ? 8 : 6, I8086_READ); + + SET_ACC(gatedesc); + write_word(addr + 4, gatedesc[2]); + PUSH(flags); + PUSH(m_sregs[CS]); + PUSH(m_ip); + if((hwint == 1) && (error != -1)) + PUSH(error); + m_sregs[CS] = IDXTBL(gatesel) | DPL(r); + m_limit[CS] = LIMIT(gatedesc); + m_base[CS] = BASE(gatedesc); + m_rights[CS] = RIGHTS(gatedesc); + m_ip = GATEOFF(desc); + m_TF = 0; + m_NT = 0; + if(GATE(RIGHTS(desc)) == INTGATE) + m_IF = 0; + break; + } + default: + throw TRAP(FAULT_GP, (number * 8 + 2 + hwint)); + } +} + +UINT8 i80286_cpu_device::read_port_byte(UINT16 port) +{ + if(PM && (CPL > m_IOPL)) + throw TRAP(FAULT_GP, 0); + return m_io->read_byte(port); +} + +UINT16 i80286_cpu_device::read_port_word(UINT16 port) +{ + if(PM && (CPL > m_IOPL)) + throw TRAP(FAULT_GP, 0); + return m_io->read_word_unaligned(port); +} + +void i80286_cpu_device::write_port_byte(UINT16 port, UINT8 data) +{ + if(PM && (CPL > m_IOPL)) + throw TRAP(FAULT_GP, 0); + m_io->write_byte(port, data); +} + +void i80286_cpu_device::write_port_word(UINT16 port, UINT16 data) +{ + if(PM && (CPL > m_IOPL)) + throw TRAP(FAULT_GP, 0); + m_io->write_word_unaligned(port, data); +} + +UINT8 i80286_cpu_device::fetch_op() +{ + UINT8 data; + if(m_ip > m_limit[CS]) + throw TRAP(FAULT_GP, 0); + + data = m_direct->read_byte( pc() & m_amask, m_fetch_xor ); + m_ip++; + return data; +} + +UINT8 i80286_cpu_device::fetch() +{ + UINT8 data; + if(m_ip > m_limit[CS]) + throw TRAP(FAULT_GP, 0); + + data = m_direct->read_byte( pc() & m_amask, m_fetch_xor ); + m_ip++; + return data; +} + +UINT32 i80286_cpu_device::calc_addr(int seg, UINT16 offset, int size, int op, bool override) +{ + seg = (m_seg_prefix && (seg==DS || seg==SS) && override) ? m_prefix_seg : seg; + if(op != I8086_NONE) + check_permission(seg, offset, size, op); + + return (m_base[seg] + offset) & (op != I8086_NONE ? m_amask : 0xffffff); +} + +void i80286_cpu_device::execute_run() +{ + while(m_icount > 0 ) + { + try + { + if ( m_seg_prefix_next ) + { + m_seg_prefix = true; + m_seg_prefix_next = false; + } + else + { + m_prev_ip = m_ip; + m_seg_prefix = false; + + /* Dispatch IRQ */ + if ( m_pending_irq && m_no_interrupt == 0 ) + { + if ( m_pending_irq & NMI_IRQ ) + { + interrupt_descriptor(NMI, 1, -1); + m_pending_irq &= ~NMI_IRQ; + m_halt = false; + m_shutdown = false; + m_out_shutdown_func(false); + } + else if ( m_IF ) + { + interrupt_descriptor(-1, 1, -1); + m_halt = false; + } + } + + if(m_halt || m_shutdown) + { + m_icount = 0; + return; + } + + /* No interrupt allowed between last instruction and this one */ + if ( m_no_interrupt ) + { + m_no_interrupt--; + } + + /* trap should allow one instruction to be executed */ + if ( m_fire_trap ) + { + if ( m_fire_trap >= 2 ) + { + interrupt(1); + m_fire_trap = 0; + } + else + { + m_fire_trap++; + } + } + } + + debugger_instruction_hook( this, pc() & m_amask ); + + UINT8 op = fetch_op(); + + switch(op) + { + case 0x07: // i_pop_es + pop_seg(ES); + CLK(POP_SEG); + break; + + case 0x0f: + { + unsigned next = fetch_op(); + UINT16 desc[3], tmp, msw, sel; + UINT8 r; + UINT32 addr; + + switch (next) + { + case 0: + if(!PM) + throw TRAP(FAULT_UD, (UINT16)-1); + m_modrm = fetch(); + switch (m_modrm & 0x38) + { + case 0: /* sldt */ + PutRMWord(m_ldtr.sel); + break; + + case 8: /* str */ + PutRMWord(m_tr.sel); + break; + + case 0x10: /* lldt */ + if(CPL != 0) + throw TRAP(FAULT_GP, 0); + sel = GetRMWord(); + if(TBL(sel)) + throw TRAP(FAULT_GP, IDXTBL(sel)); + if(IDXTBL(sel)) + { + if(IDX(sel) >= m_gdtr.limit) + throw TRAP(FAULT_GP, IDXTBL(sel)); + addr = m_gdtr.base + IDX(sel); + desc[0] = read_word(addr); + desc[1] = read_word(addr + 2); + desc[2] = read_word(addr + 4); + r = RIGHTS(desc); + if(SEGDESC(r) || (GATE(r) != LDTDESC)) + throw TRAP(FAULT_GP, IDXTBL(sel)); + if(!PRES(r)) + throw TRAP(FAULT_NP, IDXTBL(sel)); + } + else + { + desc[0] = 0; + desc[1] = 0; + desc[2] = 0; + } + m_ldtr.sel = sel; + m_ldtr.limit = LIMIT(desc); + m_ldtr.base = BASE(desc); + m_ldtr.rights = RIGHTS(desc); + break; + + case 0x18: /* ltr */ + if(CPL != 0) + throw TRAP(FAULT_GP, 0); + sel = GetRMWord(); + if((addr = selector_address(sel)) == -1) + throw TRAP(FAULT_GP, IDXTBL(sel)); + desc[0] = read_word(addr); + desc[1] = read_word(addr + 2); + desc[2] = read_word(addr + 4); + r = RIGHTS(desc); + if(SEGDESC(r) || (GATE(r) != TSSDESCIDLE)) + throw TRAP(FAULT_GP, IDXTBL(sel)); + if(!PRES(r)) + throw TRAP(FAULT_NP, IDXTBL(sel)); + desc[2] |= 0x200; // mark busy + write_word(addr + 4, desc[2]); + m_tr.sel = sel; + m_tr.limit = LIMIT(desc); + m_tr.base = BASE(desc); + m_tr.rights = RIGHTS(desc); + break; + + case 0x20: /* verr */ + tmp = GetRMWord(); + if((addr = selector_address(tmp)) == -1) + m_ZeroVal = 1; + else + { + desc[2] = read_word(addr + 4); + r = RIGHTS(desc); + m_ZeroVal = verify(tmp, I8086_READ, RIGHTS(desc), 0); + m_ZeroVal = m_ZeroVal || (CODE(r) && CONF(r) ? 0 : (DPL(r) < PMAX(RPL(tmp),CPL))); + } + break; + + case 0x28: /* verw */ + tmp = GetRMWord(); + if((addr = selector_address(tmp)) == -1) + m_ZeroVal = 1; + else + { + desc[2] = read_word(addr + 4); + r = RIGHTS(desc); + m_ZeroVal = verify(tmp, I8086_WRITE, RIGHTS(desc), 0); + m_ZeroVal = m_ZeroVal || (DPL(r) < PMAX(RPL(tmp),CPL)); + } + break; + + default: + throw TRAP(FAULT_UD, (UINT16)-1); + } + break; + case 1: + { + UINT32 ea; + m_modrm = fetch(); + if((m_modrm >= 0xc0) && (m_modrm < 0xe0)) + throw TRAP(FAULT_UD, (UINT16)-1); + switch (m_modrm & 0x38) + { + case 0: /* sgdt */ + ea = get_ea(6, I8086_WRITE); + write_word(ea, m_gdtr.limit); + write_word(ea + 2, m_gdtr.base & 0xffff); + write_word(ea + 4, 0xff00 | m_gdtr.base >> 16); + break; + case 8: /* sidt */ + ea = get_ea(6, I8086_WRITE); + write_word(ea, m_idtr.limit); + write_word(ea + 2, m_idtr.base & 0xffff); + write_word(ea + 4, 0xff00 | m_idtr.base >> 16); + break; + case 0x10: /* lgdt */ + if(PM && (CPL != 0)) + throw TRAP(FAULT_GP, 0); + ea = get_ea(6, I8086_READ); + m_gdtr.limit = read_word(ea); + m_gdtr.base = read_word(ea + 2) | (read_byte(ea + 4) << 16); + break; + case 0x18: /* lidt */ + if(PM && (CPL != 0)) + throw TRAP(FAULT_GP, 0); + ea = get_ea(6, I8086_READ); + m_idtr.limit = read_word(ea); + m_idtr.base = read_word(ea + 2) | (read_byte(ea + 4) << 16); + break; + case 0x20: /* smsw */ + PutRMWord(m_msw); + break; + case 0x30: /* lmsw */ + if(PM && (CPL != 0)) + throw TRAP(FAULT_GP, 0); + msw = GetRMWord(); + m_msw = (m_msw & 1) | msw; + break; + default: + throw TRAP(FAULT_UD, (UINT16)-1); + } + break; + } + case 2: /* LAR */ + if(!PM) + throw TRAP(FAULT_UD, (UINT16)-1); + m_modrm = fetch_op(); + tmp = GetRMWord(); + if((addr = selector_address(tmp)) == -1) + m_ZeroVal = 1; + else + { + desc[2] = read_word(addr + 4); + r = RIGHTS(desc); + if(!SEGDESC(r) && ((GATE(r) > TRAPGATE) || !GATE(r))) + m_ZeroVal = 1; + else if(DPL(r) >= PMAX(RPL(tmp),CPL) || (SEGDESC(r) && CODE(r) && CONF(r))) + { + m_ZeroVal = 0; + // rights are expected to be in upper byte + RegWord(r << 8); + } + else + m_ZeroVal = 1; + } + break; + case 3: /* LSL */ + if(!PM) + throw TRAP(FAULT_UD, (UINT16)-1); + m_modrm = fetch_op(); + tmp = GetRMWord(); + if((addr = selector_address(tmp)) == -1) + m_ZeroVal = 1; + else + { + desc[2] = read_word(addr + 4); + r = RIGHTS(desc); + if(!SEGDESC(r) && ((GATE(r) >= CALLGATE) || !GATE(r))) + m_ZeroVal = 1; // not valid for gates + else if(DPL(r) >= PMAX(RPL(tmp),CPL) || (SEGDESC(r) && CODE(r) && CONF(r))) + { + m_ZeroVal = 0; + RegWord(read_word(addr)); + } + else + m_ZeroVal = 1; + } + break; + case 5: /* loadall */ + if(PM && (CPL != 0)) + throw TRAP(FAULT_GP, 0); + m_msw = (m_msw & 1) | read_word(0x806); + m_tr.sel = read_word(0x816); + ExpandFlags(read_word(0x818)); + m_ip = read_word(0x81a); + m_ldtr.sel = read_word(0x81c); + m_sregs[DS] = read_word(0x81e); + m_sregs[SS] = read_word(0x820); + m_sregs[CS] = read_word(0x822); + m_sregs[ES] = read_word(0x824); + m_regs.w[DI] = read_word(0x826); + m_regs.w[SI] = read_word(0x828); + m_regs.w[BP] = read_word(0x82a); + m_regs.w[SP] = read_word(0x82c); + m_regs.w[BX] = read_word(0x82e); + m_regs.w[DX] = read_word(0x830); + m_regs.w[CX] = read_word(0x832); + m_regs.w[AX] = read_word(0x834); + // loadall uses base-rights-limit order +#define LOADDESC(addr, sreg) { desc[1] = read_word(addr); desc[2] = read_word(addr+2); desc[0] = read_word(addr+4); \ +m_base[sreg] = BASE(desc); m_rights[sreg] = RIGHTS(desc); \ +m_limit[sreg] = LIMIT(desc); } + LOADDESC(0x836, ES); + LOADDESC(0x83C, CS); + LOADDESC(0x842, SS); + LOADDESC(0x848, DS); +#undef LOADDESC + // void cast supresses warning +#define LOADDESC(addr, reg, r) { desc[1] = read_word(addr); desc[2] = read_word(addr+2); desc[0] = read_word(addr+4); \ +reg.base = BASE(desc); (void)(r); reg.limit = LIMIT(desc); } + LOADDESC(0x84e, m_gdtr, 1); + LOADDESC(0x854, m_ldtr, m_ldtr.rights = RIGHTS(desc)); + LOADDESC(0x85a, m_idtr, 1); + LOADDESC(0x860, m_tr, m_tr.rights = RIGHTS(desc)); +#undef LOADDESC + break; + + case 6: /* clts */ + if(PM && (CPL != 0)) + throw TRAP(FAULT_GP, 0); + m_msw &= ~8; + break; + default: + throw TRAP(FAULT_UD, (UINT16)-1); + } + break; + } + + case 0x17: // i_pop_ss + pop_seg(SS); + CLK(POP_SEG); + m_no_interrupt = 1; + break; + + case 0x1f: // i_pop_ds + pop_seg(DS); + CLK(POP_SEG); + break; + + case 0x54: // i_push_sp + PUSH(m_regs.w[SP]); + CLK(PUSH_R16); + break; + + case 0x60: // i_pusha + { + check_permission(SS, m_regs.w[SP]-16, 16, I8086_WRITE); + UINT32 tmp = m_regs.w[SP]; + PUSH(m_regs.w[AX]); + PUSH(m_regs.w[CX]); + PUSH(m_regs.w[DX]); + PUSH(m_regs.w[BX]); + PUSH(tmp); + PUSH(m_regs.w[BP]); + PUSH(m_regs.w[SI]); + PUSH(m_regs.w[DI]); + CLK(PUSHA); + } + break; + + case 0x61: // i_popa + check_permission(SS, m_regs.w[SP], 16, I8086_READ); + m_regs.w[DI] = POP(); + m_regs.w[SI] = POP(); + m_regs.w[BP] = POP(); + POP(); + m_regs.w[BX] = POP(); + m_regs.w[DX] = POP(); + m_regs.w[CX] = POP(); + m_regs.w[AX] = POP(); + CLK(POPA); + break; + + case 0x62: // i_bound + { + UINT32 low,high,tmp; + m_modrm = fetch(); + low = GetRMWord(); + high = GetnextRMWord(); + tmp = RegWord(); + if (tmphigh) + interrupt(5); + CLK(BOUND); + logerror("%s: %06x: bound %04x high %04x low %04x tmp\n", tag(), pc(), high, low, tmp); + } + break; + + case 0x63: // arpl + { + UINT16 tmp, source; + if (!PM) throw TRAP(FAULT_UD,(UINT16)-1); + + m_modrm=fetch_op(); + tmp=GetRMWord(); + source=RegWord(); + + if (RPL(tmp)> 15 != 0) && (((INT32)m_dst) >> 15 != -1); + RegWord(m_dst); + CLKM(IMUL_RRI16, IMUL_RMI16); + } + break; + + case 0x6a: // i_push_d8 + PUSH( (UINT16)((INT16)((INT8)fetch())) ); + CLK(PUSH_IMM); + break; + + case 0x6b: // i_imul_d8 + { + UINT32 src2; + DEF_r16w(); + src2= (UINT16)((INT16)((INT8)fetch())); + m_dst = (INT32)((INT16)m_src)*(INT32)((INT16)src2); + m_CarryVal = m_OverVal = (((INT32)m_dst) >> 15 != 0) && (((INT32)m_dst) >> 15 != -1); + RegWord(m_dst); + CLKM(IMUL_RRI8, IMUL_RMI8); + } + break; + + case 0x6c: // i_insb + i_insb(); + break; + + case 0x6d: // i_insw + i_insw(); + break; + + case 0x6e: // i_outsb + i_outsb(); + break; + + case 0x6f: // i_outsw + i_outsw(); + break; + + case 0x8c: // i_mov_wsreg + m_modrm = fetch(); + if((m_modrm & 0x38) > 0x18) + { + logerror("%s: %06x: Mov Sreg - Invalid register\n", tag(), pc()); + throw TRAP(FAULT_UD, (UINT16)-1); + } + PutRMWord(m_sregs[(m_modrm & 0x38) >> 3]); + CLKM(MOV_RS,MOV_MS); + break; + + case 0x8e: // i_mov_sregw + m_modrm = fetch(); + m_src = GetRMWord(); + CLKM(MOV_SR,MOV_SM); + switch (m_modrm & 0x38) + { + case 0x00: /* mov es,ew */ + data_descriptor(ES, m_src); + break; + case 0x10: /* mov ss,ew */ + data_descriptor(SS, m_src); + m_no_interrupt = 1; + break; + case 0x18: /* mov ds,ew */ + data_descriptor(DS, m_src); + break; + default: + logerror("%s: %06x: Mov Sreg - Invalid register\n", tag(), pc()); + throw TRAP(FAULT_UD, (UINT16)-1); + } + break; + + case 0x8f: // i_popw + { + m_modrm = fetch(); + UINT16 tmp = read_word(calc_addr(SS, m_regs.w[SP], 2, I8086_READ, false)); + PutRMWord( tmp ); + m_regs.w[SP] += 2; + CLKM(POP_R16,POP_M16); + break; + } + + case 0x9a: // i_call_far + { + UINT16 cs = m_sregs[CS]; + UINT16 tmp = fetch_word(); + UINT16 tmp2 = fetch_word(); + UINT16 ip = m_ip; + code_descriptor(tmp2, tmp, NT_CALL); + PUSH(cs); + PUSH(ip); + CLK(CALL_FAR); + } + break; + + case 0x9b: // i_wait + if((m_msw & 0x0a) == 0x0a) + throw TRAP(FAULT_NM, (UINT16)-1); + CLK(WAIT); + break; + + case 0x9c: // pushf + { + UINT16 flags = CompressFlags(); + if(!PM) + flags &= ~0xf000; + PUSH(flags); + CLK(PUSHF); + break; + } + + case 0x9d: // popf + { + UINT16 flags; + flags = POP(); + CLK(POPF); + load_flags(flags, CPL); + break; + } + + case 0xc0: // i_rotshft_bd8 + { + UINT8 c; + m_modrm = fetch(); + m_src = GetRMByte(); + m_dst = m_src; + c = fetch() & 0x1f; + CLKM(ROT_REG_BASE,ROT_M8_BASE); + m_icount -= m_timing[ROT_REG_BIT] * c; + if (c) + { + switch ( m_modrm & 0x38 ) + { + case 0x00: do { ROL_BYTE(); c--; } while (c>0); PutbackRMByte(m_dst); break; + case 0x08: do { ROR_BYTE(); c--; } while (c>0); PutbackRMByte(m_dst); break; + case 0x10: do { ROLC_BYTE(); c--; } while (c>0); PutbackRMByte(m_dst); break; + case 0x18: do { RORC_BYTE(); c--; } while (c>0); PutbackRMByte(m_dst); break; + case 0x30: + case 0x20: SHL_BYTE(c); break; + case 0x28: SHR_BYTE(c); break; + case 0x38: SHRA_BYTE(c); break; + } + } + } + break; + + case 0xc1: // i_rotshft_wd8 + { + UINT8 c; + m_modrm = fetch(); + m_src = GetRMWord(); + m_dst = m_src; + c = fetch() & 0x1f; + CLKM(ROT_REG_BASE,ROT_M16_BASE); + m_icount -= m_timing[ROT_REG_BIT] * c; + if (c) + { + switch ( m_modrm & 0x38 ) + { + case 0x00: do { ROL_WORD(); c--; } while (c>0); PutbackRMWord(m_dst); break; + case 0x08: do { ROR_WORD(); c--; } while (c>0); PutbackRMWord(m_dst); break; + case 0x10: do { ROLC_WORD(); c--; } while (c>0); PutbackRMWord(m_dst); break; + case 0x18: do { RORC_WORD(); c--; } while (c>0); PutbackRMWord(m_dst); break; + case 0x30: + case 0x20: SHL_WORD(c); break; + case 0x28: SHR_WORD(c); break; + case 0x38: SHRA_WORD(c); break; + } + } + } + break; + + case 0xc4: // i_les_dw + { + m_modrm = fetch(); + if(m_modrm >= 0xc0) + throw TRAP(FAULT_UD, (UINT16)-1); + UINT16 tmp = GetRMWord(); + data_descriptor(ES, GetnextRMWord()); + RegWord(tmp); + CLK(LOAD_PTR); + break; + } + + case 0xc5: // i_lds_dw + { + m_modrm = fetch(); + if(m_modrm >= 0xc0) + throw TRAP(FAULT_UD, (UINT16)-1); + UINT16 tmp = GetRMWord(); + data_descriptor(DS, GetnextRMWord()); + RegWord(tmp); + CLK(LOAD_PTR); + break; + } + + case 0xc8: // i_enter + { + UINT16 nb = fetch(); + UINT32 level; + + nb |= fetch() << 8; + level = fetch(); + CLK(!level ? ENTER0 : (level == 1) ? ENTER1 : ENTER_BASE); + if(level > 1) + m_icount -= level * m_timing[ENTER_COUNT]; + PUSH(m_regs.w[BP]); + m_regs.w[BP] = m_regs.w[SP]; + m_regs.w[SP] -= nb; + for (int i=1; i0); PutbackRMByte(m_dst); break; + case 0x08: do { ROR_BYTE(); c--; } while (c>0); PutbackRMByte(m_dst); break; + case 0x10: do { ROLC_BYTE(); c--; } while (c>0); PutbackRMByte(m_dst); break; + case 0x18: do { RORC_BYTE(); c--; } while (c>0); PutbackRMByte(m_dst); break; + case 0x30: + case 0x20: SHL_BYTE(c); break; + case 0x28: SHR_BYTE(c); break; + case 0x38: SHRA_BYTE(c); break; + } + } + } + break; + + case 0xd3: // i_rotshft_wcl + { + UINT8 c; + + m_modrm = fetch(); + m_src = GetRMWord(); + m_dst = m_src; + c = m_regs.b[CL] & 0x1f; + CLKM(ROT_REG_BASE,ROT_M16_BASE); + m_icount -= m_timing[ROT_REG_BIT] * c; + if (c) + { + switch ( m_modrm & 0x38 ) + { + case 0x00: do { ROL_WORD(); c--; } while (c>0); PutbackRMWord(m_dst); break; + case 0x08: do { ROR_WORD(); c--; } while (c>0); PutbackRMWord(m_dst); break; + case 0x10: do { ROLC_WORD(); c--; } while (c>0); PutbackRMWord(m_dst); break; + case 0x18: do { RORC_WORD(); c--; } while (c>0); PutbackRMWord(m_dst); break; + case 0x30: + case 0x20: SHL_WORD(c); break; + case 0x28: SHR_WORD(c); break; + case 0x38: SHRA_WORD(c); break; + } + } + } + break; + + case 0xd8: // i_esc + case 0xd9: + case 0xda: + case 0xdb: + case 0xdc: + case 0xdd: + case 0xde: + case 0xdf: + if((m_msw & 8) || (m_msw & 4)) + throw TRAP(FAULT_NM, (UINT16)-1); + m_modrm = fetch(); + GetRMByte(); + CLK(NOP); + if((m_modrm == 0xe0) && (op == 0xdf)) + m_regs.w[AX] = 0xffff; // FPU not present + break; + + case 0xea: // i_jmp_far + { + UINT16 tmp = fetch_word(); + UINT16 tmp1 = fetch_word(); + code_descriptor(tmp1, tmp, NT_JMP); + CLK(JMP_FAR); + break; + } + + case 0xf0: // i_lock + if(PM && (CPL > m_IOPL)) + throw TRAP(FAULT_GP, 0); + logerror("%s: %06x: Warning - BUSLOCK\n", tag(), pc()); + m_no_interrupt = 1; + CLK(NOP); + break; + + case 0xf4: // i_hlt + if(PM && (CPL > m_IOPL)) + throw TRAP(FAULT_GP, 0); + m_icount = 0; + m_halt = true; + break; + + case 0xfa: // i_cli + if(PM && (CPL > m_IOPL)) + throw TRAP(FAULT_GP, 0); + m_IF = 0; + CLK(FLAG_OPS); + break; + + case 0xfb: // i_sti + if(PM && (CPL > m_IOPL)) + throw TRAP(FAULT_GP, 0); + m_IF = 1; + CLK(FLAG_OPS); + break; + + case 0xff: // i_ffpre + { + UINT32 tmp, tmp1; + m_modrm = fetch(); + tmp = GetRMWord(); + switch ( m_modrm & 0x38 ) + { + case 0x00: /* INC */ + tmp1 = tmp+1; + m_OverVal = (tmp==0x7fff); + set_AF(tmp1,tmp,1); + set_SZPF_Word(tmp1); + PutbackRMWord(tmp1); + CLKM(INCDEC_R16,INCDEC_M16); + break; + case 0x08: /* DEC */ + tmp1 = tmp-1; + m_OverVal = (tmp==0x8000); + set_AF(tmp1,tmp,1); + set_SZPF_Word(tmp1); + PutbackRMWord(tmp1); + CLKM(INCDEC_R16,INCDEC_M16); + break; + case 0x10: /* CALL */ + PUSH(m_ip); + m_ip = tmp; + CLKM(CALL_R16,CALL_M16); + break; + case 0x18: /* CALL FAR */ + { + UINT16 ip = m_ip; + tmp1 = m_sregs[CS]; + code_descriptor(GetnextRMWord(), tmp, NT_CALL); + PUSH(tmp1); + PUSH(ip); + CLK(CALL_M32); + break; + } + case 0x20: /* JMP */ + m_ip = tmp; + CLKM(JMP_R16,JMP_M16); + break; + case 0x28: /* JMP FAR */ + code_descriptor(GetnextRMWord(), tmp, NT_JMP); + CLK(JMP_M32); + break; + case 0x30: + PUSH(tmp); + CLKM(PUSH_R16,PUSH_M16); + break; + default: + logerror("%s: %06x: FF Pre with unimplemented mod\n", tag(), pc()); + throw TRAP(FAULT_UD,(UINT16)-1); + } + } + break; + + case 0xf2: // i_repne + case 0xf3: + { + bool pass = false; + UINT8 next = repx_op(); + UINT16 c = m_regs.w[CX]; + + switch (next) + { + case 0x6c: CLK(OVERRIDE); if (c) do { i_insb(); c--; } while (c>0 && m_icount>0); m_regs.w[CX]=c; m_seg_prefix = false; m_seg_prefix_next = false; break; + case 0x6d: CLK(OVERRIDE); if (c) do { i_insw(); c--; } while (c>0 && m_icount>0); m_regs.w[CX]=c; m_seg_prefix = false; m_seg_prefix_next = false; break; + case 0x6e: CLK(OVERRIDE); if (c) do { i_outsb(); c--; } while (c>0 && m_icount>0); m_regs.w[CX]=c; m_seg_prefix = false; m_seg_prefix_next = false; break; + case 0x6f: CLK(OVERRIDE); if (c) do { i_outsw(); c--; } while (c>0 && m_icount>0); m_regs.w[CX]=c; m_seg_prefix = false; m_seg_prefix_next = false; break; + default: + // Decrement IP and pass on + m_ip -= 1 + (m_seg_prefix_next ? 1 : 0); + pass = true; + } + if(!pass) + { + if(c) + m_ip = m_prev_ip; + break; + } + } + + default: + if(!common_op(op)) + { + m_icount -= 10; // UD fault timing? + logerror("%s: %06x: Invalid Opcode %02x\n", tag(), pc(), op); + m_ip = m_prev_ip; + throw TRAP(FAULT_UD, (UINT16)-1); + } + break; + } + } + catch(UINT32 e) + { + trap(e); + } + } +} + + +void i80286_cpu_device::load_flags(UINT16 flags, int cpl) +{ + UINT16 oldflags = CompressFlags(); + flags &= ~0x8000; + if(PM && cpl) + { + UINT16 mask = 0x3000; + if(cpl > m_IOPL) + mask |= 0x200; + flags &= ~mask; + flags |= (oldflags & mask); + } + else if(!PM) + (flags &= ~0xf000); + ExpandFlags(flags); + + if(m_TF) + m_fire_trap = 1; +} + +UINT16 i80286_cpu_device::far_return(int iret, int bytes) +{ + UINT16 sel, off, flags = 0; + int spaddr; + + if(PM && m_NT && iret) + { + switch_task(read_word(m_tr.base + TSS_BACK * 2), NT_IRET); + return CompressFlags(); + } + + // must be restartable + if(PM) + check_permission(SS, m_regs.w[SP], (iret ? 6 : 4), I8086_READ); + + spaddr = (m_base[SS] + m_regs.w[SP]) & m_amask; + off = read_word(spaddr); + sel = read_word(spaddr + 2); + if(iret) + flags = read_word(spaddr + 4); + + if(PM) + { + UINT16 desc[3], newsp, newss; + int addr, r; + + if((addr = selector_address(sel)) == -1) + throw TRAP(FAULT_GP, IDXTBL(sel)); + + if(RPL(sel) < CPL) + throw TRAP(FAULT_GP, IDXTBL(sel)); + desc[0] = read_word(addr); + desc[1] = read_word(addr + 2); + desc[2] = read_word(addr + 4); + r = RIGHTS(desc); + + if(!CODE(r) || !SEGDESC(r)) + throw TRAP(FAULT_GP, IDXTBL(sel)); + if(CONF(r)) + { + if(DPL(r) > RPL(sel)) + throw TRAP(FAULT_GP, IDXTBL(sel)); + } + else if(DPL(r) != RPL(sel)) + throw TRAP(FAULT_GP, IDXTBL(sel)); + + if(!PRES(r)) + throw TRAP(FAULT_NP, IDXTBL(sel)); + if(off > LIMIT(desc)) + throw TRAP(FAULT_GP, 0); + if(CPL < RPL(sel)) + { + check_permission(SS, m_regs.w[SP] + (iret ? 6 : 4) + bytes, 4, I8086_READ); + newsp = read_word(spaddr + ((iret ? 6 : 4) + bytes)); + newss = read_word(spaddr + ((iret ? 8 : 6) + bytes)); + data_descriptor(SS, newss, RPL(sel), TRAP(FAULT_GP, IDXTBL(newss))); + m_regs.w[SP] = newsp + bytes; + } + else + m_regs.w[SP] += (iret ? 6 : 4) + bytes; + SET_ACC(desc); + write_word(addr + 4, desc[2]); + m_sregs[CS] = sel; + m_limit[CS] = LIMIT(desc); + m_base[CS] = BASE(desc); + m_rights[CS] = RIGHTS(desc); + m_ip = off; + + // docs say check rpl but windows doesn't like it + r = m_rights[DS]; + if(verify(m_sregs[DS], I8086_READ, r, 0) || (CODE(r) && CONF(r) ? 0 : (DPL(r) < CPL))) + data_descriptor(DS, 0); + r = m_rights[ES]; + if(verify(m_sregs[ES], I8086_READ, r, 0) || (CODE(r) && CONF(r) ? 0 : (DPL(r) < CPL))) + data_descriptor(ES, 0); + } + else + { + m_regs.w[SP] += (iret ? 6 : 4) + bytes; + m_sregs[CS] = sel; + m_base[CS] = sel << 4; + m_rights[CS] = 0x9b; + m_limit[CS] = 0xffff; + m_ip = off; + } + + return flags; +} + +void i80286_cpu_device::check_permission(UINT8 check_seg, UINT32 offset, UINT16 size, int operation) +{ + int trap = 0; + UINT8 rights; + if(PM) + { + rights = m_rights[check_seg]; + trap = verify(m_sregs[check_seg], operation, rights, m_valid[check_seg]); + if((CODE(rights) || !EXPDOWN(rights)) && ((offset+size-1) > m_limit[check_seg])) + trap = FAULT_GP; + if(!CODE(rights) && EXPDOWN(rights) && ((offset <= m_limit[check_seg]) || ((offset + size - 1) > 0xffff))) + trap = FAULT_GP; + + if((trap == FAULT_GP) && (check_seg == SS)) + trap = FAULT_SS; + if(trap) + throw TRAP(trap, 0); + } +} diff --git a/src/devices/cpu/i86/i286.h b/src/devices/cpu/i86/i286.h new file mode 100644 index 00000000000..64a0355bf6b --- /dev/null +++ b/src/devices/cpu/i86/i286.h @@ -0,0 +1,164 @@ +// license:BSD-3-Clause +// copyright-holders:Carl +#ifndef I286_H_ +#define I286_H_ + +#include "i86.h" +#define INPUT_LINE_A20 1 + +extern const device_type I80286; + +enum +{ // same order as I8086 registers + I286_PC = 0, + + I286_IP, + I286_AX, + I286_CX, + I286_DX, + I286_BX, + I286_SP, + I286_BP, + I286_SI, + I286_DI, + I286_FLAGS, + + I286_ES, + I286_CS, + I286_SS, + I286_DS, + + I286_VECTOR, + I286_PENDING, + + I286_ES_BASE, + I286_ES_LIMIT, + I286_ES_FLAGS, + I286_CS_BASE, + I286_CS_LIMIT, + I286_CS_FLAGS, + I286_SS_BASE, + I286_SS_LIMIT, + I286_SS_FLAGS, + I286_DS_BASE, + I286_DS_LIMIT, + I286_DS_FLAGS, + + I286_MSW, + + I286_GDTR_BASE, + I286_GDTR_LIMIT, + I286_IDTR_BASE, + I286_IDTR_LIMIT, + I286_TR, + I286_TR_BASE, + I286_TR_LIMIT, + I286_TR_FLAGS, + I286_LDTR, + I286_LDTR_BASE, + I286_LDTR_LIMIT, + I286_LDTR_FLAGS +}; + +class i80286_cpu_device : public i8086_common_cpu_device +{ +public: + // construction/destruction + i80286_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const { return (spacenum == AS_PROGRAM) ? &m_program_config : ( (spacenum == AS_IO) ? &m_io_config : NULL ); } + + typedef delegate a20_cb; + static void static_set_a20_callback(device_t &device, a20_cb object) { downcast(device).m_a20_callback = object; } + template static devcb_base &static_set_shutdown_callback(device_t &device, _Object object) { return downcast(device).m_out_shutdown_func.set_callback(object); } + +protected: + virtual void execute_run(); + virtual void device_reset(); + virtual void device_start(); + virtual void state_string_export(const device_state_entry &entry, std::string &str); + virtual UINT32 execute_input_lines() const { return 1; } + virtual void execute_set_input(int inputnum, int state); + bool memory_translate(address_spacenum spacenum, int intention, offs_t &address); + + virtual void interrupt(int int_num, int trap = 1) { if(trap) throw TRAP(int_num, (UINT16)-1); else interrupt_descriptor(int_num, 0, 0); } + virtual UINT8 read_port_byte(UINT16 port); + virtual UINT16 read_port_word(UINT16 port); + virtual void write_port_byte(UINT16 port, UINT8 data); + virtual void write_port_word(UINT16 port, UINT16 data); + + // Executing instructions + virtual UINT8 fetch_op(); + virtual UINT8 fetch(); + virtual UINT32 calc_addr(int seg, UINT16 offset, int size, int op, bool override = true); + +private: + void check_permission(UINT8 check_seg, UINT32 offset, UINT16 size, int operation); + void code_descriptor(UINT16 selector, UINT16 offset, int gate); + void data_descriptor(int reg, UINT16 selector); + void data_descriptor(int reg, UINT16 selector, int cpl, UINT32 trap, UINT16 offset = 0, int size = 0); + UINT16 far_return(int iret, int bytes); + void interrupt_descriptor(int number, int hwint, int error); + void load_flags(UINT16 flags, int cpl); + void pop_seg(int reg); + UINT32 selector_address(UINT16 sel); + void switch_task(UINT16 ntask, int type); + void trap(UINT32 error); + int verify(UINT16 selector, int operation, UINT8 rights, bool valid); + UINT32 pc() { return m_pc = m_base[CS] + m_ip; } + + int m_trap_level; + UINT16 m_msw; + UINT32 m_base[4]; + UINT16 m_limit[4]; + UINT8 m_rights[4]; + bool m_valid[4]; + UINT32 m_amask; + + struct { + UINT32 base; + UINT16 limit; + } m_gdtr, m_idtr; + struct { + UINT16 sel; + UINT32 base; + UINT16 limit; + UINT8 rights; + } m_ldtr, m_tr; + + UINT32 TRAP(UINT16 fault, UINT16 code) { return ((((UINT32)fault&0xffff)<<16)|(code&0xffff)); } + + address_space_config m_program_config; + address_space_config m_io_config; + static const UINT8 m_i80286_timing[200]; + + enum { + FAULT_DE = 0, + FAULT_DB, + NMI, + FAULT_BP, + FAULT_OF, + FAULT_BR, + FAULT_UD, + FAULT_NM, + FAULT_DF, + FAULT_MP, + FAULT_TS, + FAULT_NP, + FAULT_SS, + FAULT_GP + }; + + a20_cb m_a20_callback; + bool m_shutdown; + devcb_write_line m_out_shutdown_func; +}; + +#define MCFG_80286_A20(_class, _a20_cb) \ + i80286_cpu_device::static_set_a20_callback(*device, i80286_cpu_device::a20_cb(FUNC(_class::_a20_cb), (_class *)owner)); + +#define MCFG_80286_SHUTDOWN(_devcb) \ + devcb = &i80286_cpu_device::static_set_shutdown_callback(*device, DEVCB_##_devcb); + +#endif /* I286_H_ */ diff --git a/src/devices/cpu/i86/i86.c b/src/devices/cpu/i86/i86.c new file mode 100644 index 00000000000..9c8d5a75465 --- /dev/null +++ b/src/devices/cpu/i86/i86.c @@ -0,0 +1,2403 @@ +// license:BSD-3-Clause +// copyright-holders:Carl +/**************************************************************************** + + NEC V20/V30/V33 emulator modified back to a 8086/80186 emulator + + (Re)Written June-September 2000 by Bryan McPhail (mish@tendril.co.uk) based + on code by Oliver Bergmann (Raul_Bloodworth@hotmail.com) who based code + on the i286 emulator by Fabrice Frances which had initial work based on + David Hedley's pcemu(!). + +****************************************************************************/ + +#include "emu.h" +#include "debugger.h" +#include "i86.h" +#include "i86inline.h" + +#define I8086_NMI_INT_VECTOR 2 + +const UINT8 i8086_cpu_device::m_i8086_timing[] = +{ + 51,32, /* exception, IRET */ + 2, 0, 4, 2, /* INTs */ + 2, /* segment overrides */ + 2, 4, 4, /* flag operations */ + 4, 4,83,60, /* arithmetic adjusts */ + 4, 4, /* decimal adjusts */ + 2, 5, /* sign extension */ + 2,24, 2, 2, 3,11, /* misc */ + + 15,15,15, /* direct JMPs */ + 11,18,24, /* indirect JMPs */ + 19,28, /* direct CALLs */ + 16,21,37, /* indirect CALLs */ + 20,32,24,31, /* returns */ + 4,16, 6,18, /* conditional JMPs */ + 5,17, 6,18, /* loops */ + + 10,14, 8,12, /* port reads */ + 10,14, 8,12, /* port writes */ + + 2, 8, 9, /* move, 8-bit */ + 4,10, /* move, 8-bit immediate */ + 2, 8, 9, /* move, 16-bit */ + 4,10, /* move, 16-bit immediate */ + 10,10,10,10, /* move, AL/AX memory */ + 2, 8, 2, 9, /* move, segment registers */ + 4,17, /* exchange, 8-bit */ + 4,17, 3, /* exchange, 16-bit */ + + 15,24,14,14, /* pushes */ + 12,25,12,12, /* pops */ + + 3, 9,16, /* ALU ops, 8-bit */ + 4,17,10, /* ALU ops, 8-bit immediate */ + 3, 9,16, /* ALU ops, 16-bit */ + 4,17,10, /* ALU ops, 16-bit immediate */ + 4,17,10, /* ALU ops, 16-bit w/8-bit immediate */ + 70,118,76,128, /* MUL */ + 80,128,86,138, /* IMUL */ + 80,144,86,154, /* DIV */ + 101,165,107,175,/* IDIV */ + 3, 2,15,15, /* INC/DEC */ + 3, 3,16,16, /* NEG/NOT */ + + 2, 8, 4, /* reg shift/rotate */ + 15,20, 4, /* m8 shift/rotate */ + 15,20, 4, /* m16 shift/rotate */ + + 22, 9,21, /* CMPS 8-bit */ + 22, 9,21, /* CMPS 16-bit */ + 15, 9,14, /* SCAS 8-bit */ + 15, 9,14, /* SCAS 16-bit */ + 12, 9,11, /* LODS 8-bit */ + 12, 9,11, /* LODS 16-bit */ + 11, 9,10, /* STOS 8-bit */ + 11, 9,10, /* STOS 16-bit */ + 18, 9,17, /* MOVS 8-bit */ + 18, 9,17, /* MOVS 16-bit */ +}; + +/***************************************************************************/ +/* cpu state */ +/***************************************************************************/ + + +/***************************************************************************/ + +const device_type I8086 = &device_creator; +const device_type I8088 = &device_creator; + +i8088_cpu_device::i8088_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : i8086_cpu_device(mconfig, I8088, "I8088", tag, owner, clock, "i8088", __FILE__, 8) +{ + memcpy(m_timing, m_i8086_timing, sizeof(m_i8086_timing)); + m_fetch_xor = 0; +} + +i8086_cpu_device::i8086_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : i8086_common_cpu_device(mconfig, I8086, "I8086", tag, owner, clock, "i8086", __FILE__) + , m_program_config("program", ENDIANNESS_LITTLE, 16, 20, 0) + , m_io_config("io", ENDIANNESS_LITTLE, 16, 16, 0) +{ + memcpy(m_timing, m_i8086_timing, sizeof(m_i8086_timing)); + m_fetch_xor = BYTE_XOR_LE(0); +} + +i8086_cpu_device::i8086_cpu_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source, int data_bus_size) + : i8086_common_cpu_device(mconfig, type, name, tag, owner, clock, shortname, source) + , m_program_config("program", ENDIANNESS_LITTLE, data_bus_size, 20, 0) + , m_io_config("io", ENDIANNESS_LITTLE, data_bus_size, 16, 0) +{ +} + +UINT8 i8086_cpu_device::fetch_op() +{ + UINT8 data; + data = m_direct->read_byte(pc(), m_fetch_xor); + m_ip++; + return data; +} + +UINT8 i8086_cpu_device::fetch() +{ + UINT8 data; + data = m_direct->read_byte(pc(), m_fetch_xor); + m_ip++; + return data; +} + +void i8086_cpu_device::execute_run() +{ + while(m_icount > 0 ) + { + if ( m_seg_prefix_next ) + { + m_seg_prefix = true; + m_seg_prefix_next = false; + } + else + { + m_prev_ip = m_ip; + m_seg_prefix = false; + + /* Dispatch IRQ */ + if ( m_pending_irq && m_no_interrupt == 0 ) + { + if ( m_pending_irq & NMI_IRQ ) + { + interrupt(I8086_NMI_INT_VECTOR); + m_pending_irq &= ~NMI_IRQ; + } + else if ( m_IF ) + { + /* the actual vector is retrieved after pushing flags */ + /* and clearing the IF */ + interrupt(-1); + } + } + + /* No interrupt allowed between last instruction and this one */ + if ( m_no_interrupt ) + { + m_no_interrupt--; + } + + /* trap should allow one instruction to be executed */ + if ( m_fire_trap ) + { + if ( m_fire_trap >= 2 ) + { + interrupt(1); + m_fire_trap = 0; + } + else + { + m_fire_trap++; + } + } + } + + if (!m_seg_prefix) + { + debugger_instruction_hook( this, pc() ); + } + + UINT8 op = fetch_op(); + + switch(op) + { + case 0x0f: + m_sregs[CS] = POP(); + CLK(POP_SEG); + break; + + case 0xd2: // i_rotshft_bcl + { + UINT8 c; + + m_modrm = fetch(); + m_src = GetRMByte(); + m_dst = m_src; + c = m_regs.b[CL]; + CLKM(ROT_REG_BASE,ROT_M8_BASE); + m_icount -= m_timing[ROT_REG_BIT] * c; + if (c) + { + switch ( m_modrm & 0x38 ) + { + case 0x00: do { ROL_BYTE(); c--; } while (c>0); PutbackRMByte(m_dst); break; + case 0x08: do { ROR_BYTE(); c--; } while (c>0); PutbackRMByte(m_dst); break; + case 0x10: do { ROLC_BYTE(); c--; } while (c>0); PutbackRMByte(m_dst); break; + case 0x18: do { RORC_BYTE(); c--; } while (c>0); PutbackRMByte(m_dst); break; + case 0x30: + case 0x20: SHL_BYTE(c); break; + case 0x28: SHR_BYTE(c); break; + case 0x38: SHRA_BYTE(c); break; + } + } + } + break; + + case 0xd3: // i_rotshft_wcl + { + UINT8 c; + + m_modrm = fetch(); + m_src = GetRMWord(); + m_dst = m_src; + c = m_regs.b[CL]; + CLKM(ROT_REG_BASE,ROT_M16_BASE); + m_icount -= m_timing[ROT_REG_BIT] * c; + if (c) + { + switch ( m_modrm & 0x38 ) + { + case 0x00: do { ROL_WORD(); c--; } while (c>0); PutbackRMWord(m_dst); break; + case 0x08: do { ROR_WORD(); c--; } while (c>0); PutbackRMWord(m_dst); break; + case 0x10: do { ROLC_WORD(); c--; } while (c>0); PutbackRMWord(m_dst); break; + case 0x18: do { RORC_WORD(); c--; } while (c>0); PutbackRMWord(m_dst); break; + case 0x30: + case 0x20: SHL_WORD(c); break; + case 0x28: SHR_WORD(c); break; + case 0x38: SHRA_WORD(c); break; + } + } + } + break; + + default: + if(!common_op(op)) + { + m_icount -= 10; + logerror("%s: %06x: Invalid Opcode %02x\n", tag(), pc(), op); + break; + } + break; + } + } +} + +void i8086_cpu_device::device_start() +{ + i8086_common_cpu_device::device_start(); + state_add( I8086_ES, "ES", m_sregs[ES] ).callimport().callexport().formatstr("%04X"); + state_add( I8086_CS, "CS", m_sregs[CS] ).callimport().callexport().formatstr("%04X"); + state_add( I8086_SS, "SS", m_sregs[SS] ).callimport().callexport().formatstr("%04X"); + state_add( I8086_DS, "DS", m_sregs[DS] ).callimport().callexport().formatstr("%04X"); + state_add( I8086_VECTOR, "V", m_int_vector).callimport().callexport().formatstr("%02X"); + + state_add(STATE_GENPC, "curpc", m_pc).callimport().callexport().formatstr("%05X"); +} + +i8086_common_cpu_device::i8086_common_cpu_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : cpu_device(mconfig, type, name, tag, owner, clock, shortname, source) + , m_ip(0) + , m_TF(0) + , m_int_vector(0) + , m_pending_irq(0) + , m_nmi_state(0) + , m_irq_state(0) + , m_test_state(1) + , m_pc(0) + , m_lock(false) + , m_lock_handler(*this) +{ + static const BREGS reg_name[8]={ AL, CL, DL, BL, AH, CH, DH, BH }; + + /* Set up parity lookup table. */ + for (UINT16 i = 0;i < 256; i++) + { + UINT16 c = 0; + for (UINT16 j = i; j > 0; j >>= 1) + { + if (j & 1) c++; + } + m_parity_table[i] = !(c & 1); + } + + for (UINT16 i = 0; i < 256; i++) + { + m_Mod_RM.reg.b[i] = reg_name[(i & 0x38) >> 3]; + m_Mod_RM.reg.w[i] = (WREGS) ( (i & 0x38) >> 3) ; + } + + for (UINT16 i = 0xc0; i < 0x100; i++) + { + m_Mod_RM.RM.w[i] = (WREGS)( i & 7 ); + m_Mod_RM.RM.b[i] = (BREGS)reg_name[i & 7]; + } + + memset(&m_regs, 0x00, sizeof(m_regs)); + memset(m_sregs, 0x00, sizeof(m_sregs)); +} + +void i8086_common_cpu_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + switch (entry.index()) + { + case STATE_GENPC: + strprintf(str, "%08X", pc()); + break; + + case STATE_GENFLAGS: + { + UINT16 flags = CompressFlags(); + strprintf(str, "%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c", + flags & 0x8000 ? '1':'.', + flags & 0x4000 ? '1':'.', + flags & 0x2000 ? '1':'.', + flags & 0x1000 ? '1':'.', + flags & 0x0800 ? 'O':'.', + flags & 0x0400 ? 'D':'.', + flags & 0x0200 ? 'I':'.', + flags & 0x0100 ? 'T':'.', + flags & 0x0080 ? 'S':'.', + flags & 0x0040 ? 'Z':'.', + flags & 0x0020 ? '0':'.', + flags & 0x0010 ? 'A':'.', + flags & 0x0008 ? '0':'.', + flags & 0x0004 ? 'P':'.', + flags & 0x0002 ? '1':'.', + flags & 0x0001 ? 'C':'.'); + } + break; + } +} + +void i8086_common_cpu_device::device_start() +{ + m_program = &space(AS_PROGRAM); + m_direct = &m_program->direct(); + m_io = &space(AS_IO); + + save_item(NAME(m_regs.w)); + save_item(NAME(m_sregs)); + save_item(NAME(m_ip)); + save_item(NAME(m_prev_ip)); + save_item(NAME(m_TF)); + save_item(NAME(m_IF)); + save_item(NAME(m_DF)); + save_item(NAME(m_MF)); + save_item(NAME(m_NT)); + save_item(NAME(m_IOPL)); + save_item(NAME(m_SignVal)); + save_item(NAME(m_int_vector)); + save_item(NAME(m_pending_irq)); + save_item(NAME(m_nmi_state)); + save_item(NAME(m_irq_state)); + save_item(NAME(m_AuxVal)); + save_item(NAME(m_OverVal)); + save_item(NAME(m_ZeroVal)); + save_item(NAME(m_CarryVal)); + save_item(NAME(m_ParityVal)); + save_item(NAME(m_seg_prefix)); + save_item(NAME(m_seg_prefix_next)); + save_item(NAME(m_prefix_seg)); + save_item(NAME(m_halt)); + + // Register state for debugger +// state_add( I8086_PC, "PC", m_PC ).callimport().callexport().formatstr("%04X"); + state_add( I8086_IP, "IP", m_ip ).callimport().callexport().formatstr("%04X"); + state_add( I8086_AX, "AX", m_regs.w[AX] ).callimport().callexport().formatstr("%04X"); + state_add( I8086_CX, "CX", m_regs.w[CS] ).callimport().callexport().formatstr("%04X"); + state_add( I8086_DX, "DX", m_regs.w[DX] ).callimport().callexport().formatstr("%04X"); + state_add( I8086_BX, "BX", m_regs.w[BX] ).callimport().callexport().formatstr("%04X"); + state_add( I8086_SP, "SP", m_regs.w[SP] ).callimport().callexport().formatstr("%04X"); + state_add( I8086_BP, "BP", m_regs.w[BP] ).callimport().callexport().formatstr("%04X"); + state_add( I8086_SI, "SI", m_regs.w[SI] ).callimport().callexport().formatstr("%04X"); + state_add( I8086_DI, "DI", m_regs.w[DI] ).callimport().callexport().formatstr("%04X"); + + state_add(STATE_GENFLAGS, "GENFLAGS", m_TF).callimport().callexport().formatstr("%16s").noshow(); + + m_icountptr = &m_icount; + + m_lock_handler.resolve_safe(); +} + + +void i8086_common_cpu_device::device_reset() +{ + m_ZeroVal = 1; + m_ParityVal = 1; + m_regs.w[AX] = 0; + m_regs.w[CX] = 0; + m_regs.w[DX] = 0; + m_regs.w[BX] = 0; + m_regs.w[SP] = 0; + m_regs.w[BP] = 0; + m_regs.w[SI] = 0; + m_regs.w[DI] = 0; + m_sregs[ES] = 0; + m_sregs[CS] = 0xffff; + m_sregs[SS] = 0; + m_sregs[DS] = 0; + m_ip = 0; + m_prev_ip = 0; + m_SignVal = 0; + m_AuxVal = 0; + m_OverVal = 0; + m_CarryVal = 0; + m_TF = 0; + m_IF = 0; + m_DF = 0; + m_IOPL = 3; // 8086 IOPL always 3 + m_NT = 1; // 8086 NT always 1 + m_MF = 1; // 8086 MF always 1, 80286 always 0 + m_int_vector = 0; + m_pending_irq = 0; + m_nmi_state = 0; + m_irq_state = 0; + m_no_interrupt = 0; + m_fire_trap = 0; + m_prefix_seg = 0; + m_seg_prefix = false; + m_seg_prefix_next = false; + m_ea = 0; + m_eo = 0; + m_e16 = 0; + m_modrm = 0; + m_dst = 0; + m_src = 0; + m_halt = false; + m_lock = false; +} + + + +void i8086_common_cpu_device::interrupt(int int_num, int trap) +{ + PUSH( CompressFlags() ); + m_TF = m_IF = 0; + + if (int_num == -1) + { + int_num = standard_irq_callback(0); + + m_irq_state = CLEAR_LINE; + m_pending_irq &= ~INT_IRQ; + } + + UINT16 dest_off = read_word( int_num * 4 + 0 ); + UINT16 dest_seg = read_word( int_num * 4 + 2 ); + + PUSH(m_sregs[CS]); + PUSH(m_ip); + m_ip = dest_off; + m_sregs[CS] = dest_seg; +} + + +void i8086_common_cpu_device::execute_set_input( int inptnum, int state ) +{ + if (inptnum == INPUT_LINE_NMI) + { + if ( m_nmi_state == state ) + { + return; + } + m_nmi_state = state; + if (state != CLEAR_LINE) + { + m_pending_irq |= NMI_IRQ; + } + } + else if (inptnum == INPUT_LINE_TEST) + { + m_test_state = state; + } + else + { + m_irq_state = state; + if (state == CLEAR_LINE) + { + m_pending_irq &= ~INT_IRQ; + } + else + { + m_pending_irq |= INT_IRQ; + } + } +} + +offs_t i8086_common_cpu_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern int i386_dasm_one(char *buffer, offs_t eip, const UINT8 *oprom, int mode); + return i386_dasm_one(buffer, pc, oprom, 1); +} + +UINT8 i8086_common_cpu_device::read_port_byte(UINT16 port) +{ + return m_io->read_byte(port); +} + +UINT16 i8086_common_cpu_device::read_port_word(UINT16 port) +{ + return m_io->read_word_unaligned(port); +} + +void i8086_common_cpu_device::write_port_byte(UINT16 port, UINT8 data) +{ + m_io->write_byte(port, data); +} + +void i8086_common_cpu_device::write_port_word(UINT16 port, UINT16 data) +{ + m_io->write_word_unaligned(port, data); +} + +UINT32 i8086_common_cpu_device::calc_addr(int seg, UINT16 offset, int size, int op, bool override) +{ + if ( m_seg_prefix && (seg==DS || seg==SS) && override ) + { + return (m_sregs[m_prefix_seg] << 4) + offset; + } + else + { + return (m_sregs[seg] << 4) + offset; + } +} + +bool i8086_common_cpu_device::common_op(UINT8 op) +{ + switch(op) + { + case 0x00: // i_add_br8 + DEF_br8(); + set_CFB(ADDB()); + PutbackRMByte(m_dst); + CLKM(ALU_RR8,ALU_MR8); + break; + + case 0x01: // i_add_wr16 + DEF_wr16(); + set_CFW(ADDX()); + PutbackRMWord(m_dst); + CLKM(ALU_RR16,ALU_MR16); + break; + + case 0x02: // i_add_r8b + DEF_r8b(); + set_CFB(ADDB()); + RegByte(m_dst); + CLKM(ALU_RR8,ALU_RM8); + break; + + case 0x03: // i_add_r16w + DEF_r16w(); + set_CFW(ADDX()); + RegWord(m_dst); + CLKM(ALU_RR16,ALU_RM16); + break; + + case 0x04: // i_add_ald8 + DEF_ald8(); + set_CFB(ADDB()); + m_regs.b[AL] = m_dst; + CLK(ALU_RI8); + break; + + case 0x05: // i_add_axd16 + DEF_axd16(); + set_CFW(ADDX()); + m_regs.w[AX] = m_dst; + CLK(ALU_RI16); + break; + + case 0x06: // i_push_es + PUSH(m_sregs[ES]); + CLK(PUSH_SEG); + break; + + case 0x07: // i_pop_es + m_sregs[ES] = POP(); + CLK(POP_SEG); + break; + + case 0x08: // i_or_br8 + DEF_br8(); + ORB(); + PutbackRMByte(m_dst); + CLKM(ALU_RR8,ALU_MR8); + break; + + case 0x09: // i_or_wr16 + DEF_wr16(); + ORW(); + PutbackRMWord(m_dst); + CLKM(ALU_RR16,ALU_MR16); + break; + + case 0x0a: // i_or_r8b + DEF_r8b(); + ORB(); + RegByte(m_dst); + CLKM(ALU_RR8,ALU_RM8); + break; + + case 0x0b: // i_or_r16w + DEF_r16w(); + ORW(); + RegWord(m_dst); + CLKM(ALU_RR16,ALU_RM16); + break; + + case 0x0c: // i_or_ald8 + DEF_ald8(); + ORB(); + m_regs.b[AL] = m_dst; + CLK(ALU_RI8); + break; + + case 0x0d: // i_or_axd16 + DEF_axd16(); + ORW(); + m_regs.w[AX] = m_dst; + CLK(ALU_RI16); + break; + + case 0x0e: // i_push_cs + PUSH(m_sregs[CS]); + CLK(PUSH_SEG); + break; + + case 0x10: // i_adc_br8 + { + DEF_br8(); + m_src += CF ? 1 : 0; + UINT32 tmpcf = ADDB(); + PutbackRMByte(m_dst); + set_CFB(tmpcf); + CLKM(ALU_RR8,ALU_MR8); + break; + } + case 0x11: // i_adc_wr16 + { + DEF_wr16(); + m_src += CF ? 1 : 0; + UINT32 tmpcf = ADDX(); + PutbackRMWord(m_dst); + set_CFW(tmpcf); + CLKM(ALU_RR16,ALU_MR16); + break; + } + + case 0x12: // i_adc_r8b + DEF_r8b(); + m_src += CF ? 1 : 0; + set_CFB(ADDB()); + RegByte(m_dst); + CLKM(ALU_RR8,ALU_RM8); + break; + + case 0x13: // i_adc_r16w + DEF_r16w(); + m_src += CF ? 1 : 0; + set_CFW(ADDX()); + RegWord(m_dst); + CLKM(ALU_RR16,ALU_RM16); + break; + + case 0x14: // i_adc_ald8 + DEF_ald8(); + m_src += CF ? 1 : 0; + set_CFB(ADDB()); + m_regs.b[AL] = m_dst; + CLK(ALU_RI8); + break; + + case 0x15: // i_adc_axd16 + DEF_axd16(); + m_src += CF ? 1 : 0; + set_CFW(ADDX()); + m_regs.w[AX] = m_dst; + CLK(ALU_RI16); + break; + + case 0x16: // i_push_ss + PUSH(m_sregs[SS]); + CLK(PUSH_SEG); + break; + + case 0x17: // i_pop_ss + m_sregs[SS] = POP(); + CLK(POP_SEG); + m_no_interrupt = 1; + break; + + case 0x18: // i_sbb_br8 + { + UINT32 tmpcf; + DEF_br8(); + m_src += CF ? 1 : 0; + tmpcf = SUBB(); + PutbackRMByte(m_dst); + set_CFB(tmpcf); + CLKM(ALU_RR8,ALU_MR8); + break; + } + + case 0x19: // i_sbb_wr16 + { + UINT32 tmpcf; + DEF_wr16(); + m_src += CF ? 1 : 0; + tmpcf = SUBX(); + PutbackRMWord(m_dst); + set_CFW(tmpcf); + CLKM(ALU_RR16,ALU_MR16); + break; + } + + case 0x1a: // i_sbb_r8b + DEF_r8b(); + m_src += CF ? 1 : 0; + set_CFB(SUBB()); + RegByte(m_dst); + CLKM(ALU_RR8,ALU_RM8); + break; + + case 0x1b: // i_sbb_r16w + DEF_r16w(); + m_src += CF ? 1 : 0; + set_CFW(SUBX()); + RegWord(m_dst); + CLKM(ALU_RR16,ALU_RM16); + break; + + case 0x1c: // i_sbb_ald8 + DEF_ald8(); + m_src += CF ? 1 : 0; + set_CFB(SUBB()); + m_regs.b[AL] = m_dst; + CLK(ALU_RI8); + break; + + case 0x1d: // i_sbb_axd16 + DEF_axd16(); + m_src += CF ? 1 : 0; + set_CFW(SUBX()); + m_regs.w[AX] = m_dst; + CLK(ALU_RI16); + break; + + case 0x1e: // i_push_ds + PUSH(m_sregs[DS]); + CLK(PUSH_SEG); + break; + + case 0x1f: // i_pop_ds + m_sregs[DS] = POP(); + CLK(POP_SEG); + break; + + + case 0x20: // i_and_br8 + DEF_br8(); + ANDB(); + PutbackRMByte(m_dst); + CLKM(ALU_RR8,ALU_MR8); + break; + + case 0x21: // i_and_wr16 + DEF_wr16(); + ANDX(); + PutbackRMWord(m_dst); + CLKM(ALU_RR16,ALU_MR16); + break; + + case 0x22: // i_and_r8b + DEF_r8b(); + ANDB(); + RegByte(m_dst); + CLKM(ALU_RR8,ALU_RM8); + break; + + case 0x23: // i_and_r16w + DEF_r16w(); + ANDX(); + RegWord(m_dst); + CLKM(ALU_RR16,ALU_RM16); + break; + + case 0x24: // i_and_ald8 + DEF_ald8(); + ANDB(); + m_regs.b[AL] = m_dst; + CLK(ALU_RI8); + break; + + case 0x25: // i_and_axd16 + DEF_axd16(); + ANDX(); + m_regs.w[AX] = m_dst; + CLK(ALU_RI16); + break; + + case 0x26: // i_es + m_seg_prefix_next = true; + m_prefix_seg = ES; + CLK(OVERRIDE); + break; + + case 0x27: // i_daa + ADJ4(6,0x60); + CLK(DAA); + break; + + + case 0x28: // i_sub_br8 + DEF_br8(); + set_CFB(SUBB()); + PutbackRMByte(m_dst); + CLKM(ALU_RR8,ALU_MR8); + break; + + case 0x29: // i_sub_wr16 + DEF_wr16(); + set_CFW(SUBX()); + PutbackRMWord(m_dst); + CLKM(ALU_RR16,ALU_MR16); + break; + + case 0x2a: // i_sub_r8b + DEF_r8b(); + set_CFB(SUBB()); + RegByte(m_dst); + CLKM(ALU_RR8,ALU_RM8); + break; + + case 0x2b: // i_sub_r16w + DEF_r16w(); + set_CFW(SUBX()); + RegWord(m_dst); + CLKM(ALU_RR16,ALU_RM16); + break; + + case 0x2c: // i_sub_ald8 + DEF_ald8(); + set_CFB(SUBB()); + m_regs.b[AL] = m_dst; + CLK(ALU_RI8); + break; + + case 0x2d: // i_sub_axd16 + DEF_axd16(); + set_CFW(SUBX()); + m_regs.w[AX] = m_dst; + CLK(ALU_RI16); + break; + + case 0x2e: // i_cs + m_seg_prefix_next = true; + m_prefix_seg = CS; + CLK(OVERRIDE); + break; + + case 0x2f: // i_das + ADJ4(-6,-0x60); + CLK(DAS); + break; + + + case 0x30: // i_xor_br8 + DEF_br8(); + XORB(); + PutbackRMByte(m_dst); + CLKM(ALU_RR8,ALU_MR8); + break; + + case 0x31: // i_xor_wr16 + DEF_wr16(); + XORW(); + PutbackRMWord(m_dst); + CLKM(ALU_RR16,ALU_RM16); + break; + + case 0x32: // i_xor_r8b + DEF_r8b(); + XORB(); + RegByte(m_dst); + CLKM(ALU_RR8,ALU_RM8); + break; + + case 0x33: // i_xor_r16w + DEF_r16w(); + XORW(); + RegWord(m_dst); + CLKM(ALU_RR16,ALU_RM16); + break; + + case 0x34: // i_xor_ald8 + DEF_ald8(); + XORB(); + m_regs.b[AL] = m_dst; + CLK(ALU_RI8); + break; + + case 0x35: // i_xor_axd16 + DEF_axd16(); + XORW(); + m_regs.w[AX] = m_dst; + CLK(ALU_RI16); + break; + + case 0x36: // i_ss + m_seg_prefix_next = true; + m_prefix_seg = SS; + CLK(OVERRIDE); + break; + + case 0x37: // i_aaa + ADJB(6, (m_regs.b[AL] > 0xf9) ? 2 : 1); + CLK(AAA); + break; + + + case 0x38: // i_cmp_br8 + DEF_br8(); + set_CFB(SUBB()); + CLKM(ALU_RR8,ALU_RM8); + break; + + case 0x39: // i_cmp_wr16 + DEF_wr16(); + set_CFW(SUBX()); + CLKM(ALU_RR16,ALU_RM16); + break; + + case 0x3a: // i_cmp_r8b + DEF_r8b(); + set_CFB(SUBB()); + CLKM(ALU_RR8,ALU_RM8); + break; + + case 0x3b: // i_cmp_r16w + DEF_r16w(); + set_CFW(SUBX()); + CLKM(ALU_RR16,ALU_RM16); + break; + + case 0x3c: // i_cmp_ald8 + DEF_ald8(); + set_CFB(SUBB()); + CLK(ALU_RI8); + break; + + case 0x3d: // i_cmp_axd16 + DEF_axd16(); + set_CFW(SUBX()); + CLK(ALU_RI16); + break; + + case 0x3e: // i_ds + m_seg_prefix_next = true; + m_prefix_seg = DS; + CLK(OVERRIDE); + break; + + case 0x3f: // i_aas + ADJB(-6, (m_regs.b[AL] < 6) ? -2 : -1); + CLK(AAS); + break; + + + case 0x40: // i_inc_ax + IncWordReg(AX); + CLK(INCDEC_R16); + break; + + case 0x41: // i_inc_cx + IncWordReg(CX); + CLK(INCDEC_R16); + break; + + case 0x42: // i_inc_dx + IncWordReg(DX); + CLK(INCDEC_R16); + break; + + case 0x43: // i_inc_bx + IncWordReg(BX); + CLK(INCDEC_R16); + break; + + case 0x44: // i_inc_sp + IncWordReg(SP); + CLK(INCDEC_R16); + break; + + case 0x45: // i_inc_bp + IncWordReg(BP); + CLK(INCDEC_R16); + break; + + case 0x46: // i_inc_si + IncWordReg(SI); + CLK(INCDEC_R16); + break; + + case 0x47: // i_inc_di + IncWordReg(DI); + CLK(INCDEC_R16); + break; + + + case 0x48: // i_dec_ax + DecWordReg(AX); + CLK(INCDEC_R16); + break; + + case 0x49: // i_dec_cx + DecWordReg(CX); + CLK(INCDEC_R16); + break; + + case 0x4a: // i_dec_dx + DecWordReg(DX); + CLK(INCDEC_R16); + break; + + case 0x4b: // i_dec_bx + DecWordReg(BX); + CLK(INCDEC_R16); + break; + + case 0x4c: // i_dec_sp + DecWordReg(SP); + CLK(INCDEC_R16); + break; + + case 0x4d: // i_dec_bp + DecWordReg(BP); + CLK(INCDEC_R16); + break; + + case 0x4e: // i_dec_si + DecWordReg(SI); + CLK(INCDEC_R16); + break; + + case 0x4f: // i_dec_di + DecWordReg(DI); + CLK(INCDEC_R16); + break; + + + case 0x50: // i_push_ax + PUSH(m_regs.w[AX]); + CLK(PUSH_R16); + break; + + case 0x51: // i_push_cx + PUSH(m_regs.w[CX]); + CLK(PUSH_R16); + break; + + case 0x52: // i_push_dx + PUSH(m_regs.w[DX]); + CLK(PUSH_R16); + break; + + case 0x53: // i_push_bx + PUSH(m_regs.w[BX]); + CLK(PUSH_R16); + break; + + case 0x54: // i_push_sp + PUSH(m_regs.w[SP]-2); + CLK(PUSH_R16); + break; + + case 0x55: // i_push_bp + PUSH(m_regs.w[BP]); + CLK(PUSH_R16); + break; + + case 0x56: // i_push_si + PUSH(m_regs.w[SI]); + CLK(PUSH_R16); + break; + + case 0x57: // i_push_di + PUSH(m_regs.w[DI]); + CLK(PUSH_R16); + break; + + + case 0x58: // i_pop_ax + m_regs.w[AX] = POP(); + CLK(POP_R16); + break; + + case 0x59: // i_pop_cx + m_regs.w[CX] = POP(); + CLK(POP_R16); + break; + + case 0x5a: // i_pop_dx + m_regs.w[DX] = POP(); + CLK(POP_R16); + break; + + case 0x5b: // i_pop_bx + m_regs.w[BX] = POP(); + CLK(POP_R16); + break; + + case 0x5c: // i_pop_sp + m_regs.w[SP] = POP(); + CLK(POP_R16); + break; + + case 0x5d: // i_pop_bp + m_regs.w[BP] = POP(); + CLK(POP_R16); + break; + + case 0x5e: // i_pop_si + m_regs.w[SI] = POP(); + CLK(POP_R16); + break; + + case 0x5f: // i_pop_di + m_regs.w[DI] = POP(); + CLK(POP_R16); + break; + +// 8086 'invalid opcodes', as documented at http://www.os2museum.com/wp/?p=2147 +// - 0x60 - 0x6f are an alias to 0x70 - 0x7f. +// - 0xc0, 0xc1, 0xc8, 0xc9 are also aliases where the CPU ignores BIT 1 (*). +// +// Instructions are used in the boot sector for some versions of +// MS-DOS (e.g. the DEC Rainbow-100 version of DOS 2.x) + case 0x60: + case 0x70: // i_jo + JMP( OF); + break; + + case 0x61: + case 0x71: // i_jno + JMP(!OF); + break; + + case 0x62: + case 0x72: // i_jc + JMP( CF); + break; + + case 0x63: + case 0x73: // i_jnc + JMP(!CF); + break; + + case 0x64: + case 0x74: // i_jz + JMP( ZF); + break; + + case 0x65: + case 0x75: // i_jnz + JMP(!ZF); + break; + + case 0x66: + case 0x76: // i_jce + JMP(CF || ZF); + break; + + case 0x67: + case 0x77: // i_jnce + JMP(!(CF || ZF)); + break; + + case 0x68: + case 0x78: // i_js + JMP( SF); + break; + + case 0x69: + case 0x79: // i_jns + JMP(!SF); + break; + + case 0x6a: + case 0x7a: // i_jp + JMP( PF); + break; + + case 0x6b: + case 0x7b: // i_jnp + JMP(!PF); + break; + + case 0x6c: + case 0x7c: // i_jl + JMP((SF!=OF)&&(!ZF)); + break; + + case 0x6d: + case 0x7d: // i_jnl + JMP((ZF)||(SF==OF)); + break; + + case 0x6e: + case 0x7e: // i_jle + JMP((ZF)||(SF!=OF)); + break; + + case 0x6f: + case 0x7f: // i_jnle + JMP((SF==OF)&&(!ZF)); + break; + + + case 0x80: // i_80pre + { + UINT32 tmpcf; + m_modrm = fetch(); + m_dst = GetRMByte(); + m_src = fetch(); + if (m_modrm >=0xc0 ) { CLK(ALU_RI8); } + else if ((m_modrm & 0x38)==0x38) { CLK(ALU_MI8_RO); } + else { CLK(ALU_MI8); } + switch (m_modrm & 0x38) + { + case 0x00: set_CFB(ADDB()); PutbackRMByte(m_dst); break; + case 0x08: ORB(); PutbackRMByte(m_dst); break; + case 0x10: m_src += CF ? 1 : 0; tmpcf = ADDB(); PutbackRMByte(m_dst); set_CFB(tmpcf); break; + case 0x18: m_src += CF ? 1 : 0; tmpcf = SUBB(); PutbackRMByte(m_dst); set_CFB(tmpcf); break; + case 0x20: ANDB(); PutbackRMByte(m_dst); break; + case 0x28: set_CFB(SUBB()); PutbackRMByte(m_dst); break; + case 0x30: XORB(); PutbackRMByte(m_dst); break; + case 0x38: set_CFB(SUBB()); break; /* CMP */ + } + break; + } + + + case 0x81: // i_81pre + { + UINT32 tmpcf; + m_modrm = fetch(); + m_dst = GetRMWord(); + m_src = fetch_word(); + if (m_modrm >=0xc0 ) { CLK(ALU_RI16); } + else if ((m_modrm & 0x38)==0x38) { CLK(ALU_MI16_RO); } + else { CLK(ALU_MI16); } + switch (m_modrm & 0x38) + { + case 0x00: set_CFW(ADDX()); PutbackRMWord(m_dst); break; + case 0x08: ORW(); PutbackRMWord(m_dst); break; + case 0x10: m_src += CF ? 1 : 0; tmpcf = ADDX(); PutbackRMWord(m_dst); set_CFW(tmpcf); break; + case 0x18: m_src += CF ? 1 : 0; tmpcf = SUBX(); PutbackRMWord(m_dst); set_CFW(tmpcf); break; + case 0x20: ANDX(); PutbackRMWord(m_dst); break; + case 0x28: set_CFW(SUBX()); PutbackRMWord(m_dst); break; + case 0x30: XORW(); PutbackRMWord(m_dst); break; + case 0x38: set_CFW(SUBX()); break; /* CMP */ + } + break; + } + + + case 0x82: // i_82pre + { + UINT32 tmpcf; + m_modrm = fetch(); + m_dst = GetRMByte(); + m_src = (INT8)fetch(); + if (m_modrm >=0xc0 ) { CLK(ALU_RI8); } + else if ((m_modrm & 0x38)==0x38) { CLK(ALU_MI8_RO); } + else { CLK(ALU_MI8); } + switch (m_modrm & 0x38) + { + case 0x00: set_CFB(ADDB()); PutbackRMByte(m_dst); break; + case 0x08: ORB(); PutbackRMByte(m_dst); break; + case 0x10: m_src += CF ? 1 : 0; tmpcf = ADDB(); PutbackRMByte(m_dst); set_CFB(tmpcf); break; + case 0x18: m_src += CF ? 1 : 0; tmpcf = SUBB(); PutbackRMByte(m_dst); set_CFB(tmpcf); break; + case 0x20: ANDB(); PutbackRMByte(m_dst); break; + case 0x28: set_CFB(SUBB()); PutbackRMByte(m_dst); break; + case 0x30: XORB(); PutbackRMByte(m_dst); break; + case 0x38: set_CFB(SUBB()); break; /* CMP */ + } + break; + } + + + case 0x83: // i_83pre + { + UINT32 tmpcf; + m_modrm = fetch(); + m_dst = GetRMWord(); + m_src = (UINT16)((INT16)((INT8)fetch())); + if (m_modrm >=0xc0 ) { CLK(ALU_R16I8); } + else if ((m_modrm & 0x38)==0x38) { CLK(ALU_M16I8_RO); } + else { CLK(ALU_M16I8); } + switch (m_modrm & 0x38) + { + case 0x00: set_CFW(ADDX()); PutbackRMWord(m_dst); break; + case 0x08: ORW(); PutbackRMWord(m_dst); break; + case 0x10: m_src += CF ? 1 : 0; tmpcf = ADDX(); PutbackRMWord(m_dst); set_CFW(tmpcf); break; + case 0x18: m_src += CF ? 1 : 0; tmpcf = SUBX(); PutbackRMWord(m_dst); set_CFW(tmpcf); break; + case 0x20: ANDX(); PutbackRMWord(m_dst); break; + case 0x28: set_CFW(SUBX()); PutbackRMWord(m_dst); break; + case 0x30: XORW(); PutbackRMWord(m_dst); break; + case 0x38: set_CFW(SUBX()); break; /* CMP */ + } + break; + } + + + case 0x84: // i_test_br8 + DEF_br8(); + ANDB(); + CLKM(ALU_RR8,ALU_RM8); + break; + + case 0x85: // i_test_wr16 + DEF_wr16(); + ANDX(); + CLKM(ALU_RR16,ALU_RM16); + break; + + case 0x86: // i_xchg_br8 + DEF_br8(); + RegByte(m_dst); + PutbackRMByte(m_src); + CLKM(XCHG_RR8,XCHG_RM8); + break; + + case 0x87: // i_xchg_wr16 + DEF_wr16(); + RegWord(m_dst); + PutbackRMWord(m_src); + CLKM(XCHG_RR16,XCHG_RM16); + break; + + + case 0x88: // i_mov_br8 + m_modrm = fetch(); + m_src = RegByte(); + PutRMByte(m_src); + CLKM(ALU_RR8,ALU_MR8); + break; + + case 0x89: // i_mov_wr16 + m_modrm = fetch(); + m_src = RegWord(); + PutRMWord(m_src); + CLKM(ALU_RR16,ALU_MR16); + break; + + case 0x8a: // i_mov_r8b + m_modrm = fetch(); + m_src = GetRMByte(); + RegByte(m_src); + CLKM(ALU_RR8,ALU_RM8); + break; + + case 0x8b: // i_mov_r16w + m_modrm = fetch(); + m_src = GetRMWord(); + RegWord(m_src); + CLKM(ALU_RR16,ALU_RM16); + break; + + case 0x8c: // i_mov_wsreg + m_modrm = fetch(); + PutRMWord(m_sregs[(m_modrm & 0x18) >> 3]); // confirmed on hw: modrm bit 5 ignored + CLKM(MOV_RS,MOV_MS); + break; + + case 0x8d: // i_lea + m_modrm = fetch(); + get_ea(0, I8086_NONE); + RegWord(m_eo); + CLK(LEA); + break; + + case 0x8e: // i_mov_sregw + m_modrm = fetch(); + m_src = GetRMWord(); + m_sregs[(m_modrm & 0x18) >> 3] = m_src; // confirmed on hw: modrm bit 5 ignored + CLKM(MOV_SR,MOV_SM); + break; + + case 0x8f: // i_popw + m_modrm = fetch(); + PutRMWord( POP() ); + CLKM(POP_R16,POP_M16); + break; + + case 0x90: // i_nop + CLK(NOP); + break; + + case 0x91: // i_xchg_axcx + XchgAXReg(CX); + CLK(XCHG_AR16); + break; + + case 0x92: // i_xchg_axdx + XchgAXReg(DX); + CLK(XCHG_AR16); + break; + + case 0x93: // i_xchg_axbx + XchgAXReg(BX); + CLK(XCHG_AR16); + break; + + case 0x94: // i_xchg_axsp + XchgAXReg(SP); + CLK(XCHG_AR16); + break; + + case 0x95: // i_xchg_axbp + XchgAXReg(BP); + CLK(XCHG_AR16); + break; + + case 0x96: // i_xchg_axsi + XchgAXReg(SI); + CLK(XCHG_AR16); + break; + + case 0x97: // i_xchg_axdi + XchgAXReg(DI); + CLK(XCHG_AR16); + break; + + + case 0x98: // i_cbw + m_regs.b[AH] = (m_regs.b[AL] & 0x80) ? 0xff : 0; + CLK(CBW); + break; + + case 0x99: // i_cwd + m_regs.w[DX] = (m_regs.b[AH] & 0x80) ? 0xffff : 0; + CLK(CWD); + break; + + case 0x9a: // i_call_far + { + UINT16 tmp = fetch_word(); + UINT16 tmp2 = fetch_word(); + PUSH(m_sregs[CS]); + PUSH(m_ip); + m_ip = tmp; + m_sregs[CS] = tmp2; + CLK(CALL_FAR); + } + break; + + case 0x9b: // i_wait + // Wait for assertion of /TEST + if (m_test_state == 0) + { + m_icount = 0; + m_ip--; + } + else + CLK(WAIT); + break; + + case 0x9c: // i_pushf + PUSH( CompressFlags() ); + CLK(PUSHF); + break; + + case 0x9d: // i_popf + i_popf(); + break; + + case 0x9e: // i_sahf + { + UINT32 tmp = (CompressFlags() & 0xff00) | (m_regs.b[AH] & 0xd5); + ExpandFlags(tmp); + CLK(SAHF); + } + break; + + case 0x9f: // i_lahf + m_regs.b[AH] = CompressFlags(); + CLK(LAHF); + break; + + + case 0xa0: // i_mov_aldisp + { + UINT32 addr = fetch_word(); + m_regs.b[AL] = GetMemB(DS, addr); + CLK(MOV_AM8); + } + break; + + case 0xa1: // i_mov_axdisp + { + UINT32 addr = fetch_word(); + m_regs.w[AX] = GetMemW(DS, addr); + CLK(MOV_AM16); + } + break; + + case 0xa2: // i_mov_dispal + { + UINT32 addr = fetch_word(); + PutMemB(DS, addr, m_regs.b[AL]); + CLK(MOV_MA8); + } + break; + + case 0xa3: // i_mov_dispax + { + UINT32 addr = fetch_word(); + PutMemW(DS, addr, m_regs.w[AX]); + CLK(MOV_MA16); + } + break; + + case 0xa4: // i_movsb + i_movsb(); + break; + + case 0xa5: // i_movsw + i_movsw(); + break; + + case 0xa6: // i_cmpsb + i_cmpsb(); + break; + + case 0xa7: // i_cmpsw + i_cmpsw(); + break; + + + case 0xa8: // i_test_ald8 + DEF_ald8(); + ANDB(); + CLK(ALU_RI8); + break; + + case 0xa9: // i_test_axd16 + DEF_axd16(); + ANDX(); + CLK(ALU_RI16); + break; + + case 0xaa: // i_stosb + i_stosb(); + break; + + case 0xab: // i_stosw + i_stosw(); + break; + + case 0xac: // i_lodsb + i_lodsb(); + break; + + case 0xad: // i_lodsw + i_lodsw(); + break; + + case 0xae: // i_scasb + i_scasb(); + break; + + case 0xaf: // i_scasw + i_scasw(); + break; + + + case 0xb0: // i_mov_ald8 + m_regs.b[AL] = fetch(); + CLK(MOV_RI8); + break; + + case 0xb1: // i_mov_cld8 + m_regs.b[CL] = fetch(); + CLK(MOV_RI8); + break; + + case 0xb2: // i_mov_dld8 + m_regs.b[DL] = fetch(); + CLK(MOV_RI8); + break; + + case 0xb3: // i_mov_bld8 + m_regs.b[BL] = fetch(); + CLK(MOV_RI8); + break; + + case 0xb4: // i_mov_ahd8 + m_regs.b[AH] = fetch(); + CLK(MOV_RI8); + break; + + case 0xb5: // i_mov_chd8 + m_regs.b[CH] = fetch(); + CLK(MOV_RI8); + break; + + case 0xb6: // i_mov_dhd8 + m_regs.b[DH] = fetch(); + CLK(MOV_RI8); + break; + + case 0xb7: // i_mov_bhd8 + m_regs.b[BH] = fetch(); + CLK(MOV_RI8); + break; + + + case 0xb8: // i_mov_axd16 + m_regs.b[AL] = fetch(); + m_regs.b[AH] = fetch(); + CLK(MOV_RI16); + break; + + case 0xb9: // i_mov_cxd16 + m_regs.b[CL] = fetch(); + m_regs.b[CH] = fetch(); + CLK(MOV_RI16); + break; + + case 0xba: // i_mov_dxd16 + m_regs.b[DL] = fetch(); + m_regs.b[DH] = fetch(); + CLK(MOV_RI16); + break; + + case 0xbb: // i_mov_bxd16 + m_regs.b[BL] = fetch(); + m_regs.b[BH] = fetch(); + CLK(MOV_RI16); + break; + + case 0xbc: // i_mov_spd16 + m_regs.b[SPL] = fetch(); + m_regs.b[SPH] = fetch(); + CLK(MOV_RI16); + break; + + case 0xbd: // i_mov_bpd16 + m_regs.b[BPL] = fetch(); + m_regs.b[BPH] = fetch(); + CLK(MOV_RI16); + break; + + case 0xbe: // i_mov_sid16 + m_regs.b[SIL] = fetch(); + m_regs.b[SIH] = fetch(); + CLK(MOV_RI16); + break; + + case 0xbf: // i_mov_did16 + m_regs.b[DIL] = fetch(); + m_regs.b[DIH] = fetch(); + CLK(MOV_RI16); + break; + + case 0xc0: // 0xc0 is 0xc2 - see (*) + case 0xc2: // i_ret_d16 + { + UINT32 count = fetch_word(); + m_ip = POP(); + m_regs.w[SP] += count; + CLK(RET_NEAR_IMM); + } + break; + + case 0xc1: // 0xc1 is 0xc3 - see (*) + case 0xc3: // i_ret + m_ip = POP(); + CLK(RET_NEAR); + break; + + case 0xc4: // i_les_dw + m_modrm = fetch(); + RegWord( GetRMWord() ); + m_sregs[ES] = GetnextRMWord(); + CLK(LOAD_PTR); + break; + + case 0xc5: // i_lds_dw + m_modrm = fetch(); + RegWord( GetRMWord() ); + m_sregs[DS] = GetnextRMWord(); + CLK(LOAD_PTR); + break; + + case 0xc6: // i_mov_bd8 + m_modrm = fetch(); + PutImmRMByte(); + CLKM(MOV_RI8,MOV_MI8); + break; + + case 0xc7: // i_mov_wd16 + m_modrm = fetch(); + PutImmRMWord(); + CLKM(MOV_RI16,MOV_MI16); + break; + + case 0xc8: // 0xc8 = 0xca - see (*) + case 0xca: // i_retf_d16 + { + UINT32 count = fetch_word(); + m_ip = POP(); + m_sregs[CS] = POP(); + m_regs.w[SP] += count; + CLK(RET_FAR_IMM); + } + break; + + case 0xc9: // 0xc9 = 0xcb - see (*) + case 0xcb: // i_retf + m_ip = POP(); + m_sregs[CS] = POP(); + CLK(RET_FAR); + break; + + case 0xcc: // i_int3 + interrupt(3, 0); + CLK(INT3); + break; + + case 0xcd: // i_int + interrupt(fetch(), 0); + CLK(INT_IMM); + break; + + case 0xce: // i_into + if (OF) + { + interrupt(4, 0); + CLK(INTO_T); + } + else + CLK(INTO_NT); + break; + + case 0xcf: // i_iret + m_ip = POP(); + m_sregs[CS] = POP(); + i_popf(); + CLK(IRET); + break; + + case 0xd0: // i_rotshft_b + m_modrm = fetch(); + m_src = GetRMByte(); + m_dst = m_src; + CLKM(ROT_REG_1,ROT_M8_1); + switch ( m_modrm & 0x38 ) + { + case 0x00: ROL_BYTE(); PutbackRMByte(m_dst); m_OverVal = (m_src ^ m_dst) & 0x80; break; + case 0x08: ROR_BYTE(); PutbackRMByte(m_dst); m_OverVal = (m_src ^ m_dst) & 0x80; break; + case 0x10: ROLC_BYTE(); PutbackRMByte(m_dst); m_OverVal = (m_src ^ m_dst) & 0x80; break; + case 0x18: RORC_BYTE(); PutbackRMByte(m_dst); m_OverVal = (m_src ^ m_dst) & 0x80; break; + case 0x30: + case 0x20: SHL_BYTE(1); m_OverVal = (m_src ^ m_dst) & 0x80; break; + case 0x28: SHR_BYTE(1); m_OverVal = (m_src ^ m_dst) & 0x80; break; + case 0x38: SHRA_BYTE(1); m_OverVal = 0; break; + } + break; + + case 0xd1: // i_rotshft_w + m_modrm = fetch(); + m_src = GetRMWord(); + m_dst = m_src; + CLKM(ROT_REG_1,ROT_M8_1); + switch ( m_modrm & 0x38 ) + { + case 0x00: ROL_WORD(); PutbackRMWord(m_dst); m_OverVal = (m_src ^ m_dst) & 0x8000; break; + case 0x08: ROR_WORD(); PutbackRMWord(m_dst); m_OverVal = (m_src ^ m_dst) & 0x8000; break; + case 0x10: ROLC_WORD(); PutbackRMWord(m_dst); m_OverVal = (m_src ^ m_dst) & 0x8000; break; + case 0x18: RORC_WORD(); PutbackRMWord(m_dst); m_OverVal = (m_src ^ m_dst) & 0x8000; break; + case 0x30: + case 0x20: SHL_WORD(1); m_OverVal = (m_src ^ m_dst) & 0x8000; break; + case 0x28: SHR_WORD(1); m_OverVal = (m_src ^ m_dst) & 0x8000; break; + case 0x38: SHRA_WORD(1); m_OverVal = 0; break; + } + break; + + case 0xd4: // i_aam + { + UINT8 base = fetch(); + if(!base) + { + interrupt(0); + break; + } + m_regs.b[AH] = m_regs.b[AL] / base; + m_regs.b[AL] %= base; + set_SZPF_Word(m_regs.w[AX]); + CLK(AAM); + break; + } + + case 0xd5: // i_aad + { + UINT8 base = fetch(); + m_regs.b[AL] = m_regs.b[AH] * base + m_regs.b[AL]; + m_regs.b[AH] = 0; + set_SZPF_Byte(m_regs.b[AL]); + CLK(AAD); + break; + } + + case 0xd6: // i_salc + m_regs.b[AL] = (CF ? 0xff : 0); + CLK(ALU_RR8); // is sbb al,al + break; + + case 0xd7: // i_trans + m_regs.b[AL] = GetMemB( DS, m_regs.w[BX] + m_regs.b[AL] ); + CLK(XLAT); + break; + + case 0xd8: // i_esc + case 0xd9: + case 0xda: + case 0xdb: + case 0xdc: + case 0xdd: + case 0xde: + case 0xdf: + m_modrm = fetch(); + GetRMByte(); + CLK(NOP); + logerror("%s: %06x: Unimplemented floating point escape %02x%02x\n", tag(), pc(), op, m_modrm); + break; + + + case 0xe0: // i_loopne + { + INT8 disp = (INT8)fetch(); + + m_regs.w[CX]--; + if (!ZF && m_regs.w[CX]) + { + m_ip = m_ip + disp; + CLK(LOOP_T); + } + else + CLK(LOOP_NT); + } + break; + + case 0xe1: // i_loope + { + INT8 disp = (INT8)fetch(); + + m_regs.w[CX]--; + if (ZF && m_regs.w[CX]) + { + m_ip = m_ip + disp; + CLK(LOOPE_T); + } + else + CLK(LOOPE_NT); + } + break; + + case 0xe2: // i_loop + { + INT8 disp = (INT8)fetch(); + + m_regs.w[CX]--; + if (m_regs.w[CX]) + { + m_ip = m_ip + disp; + CLK(LOOP_T); + } + else + CLK(LOOP_NT); + } + break; + + case 0xe3: // i_jcxz + { + INT8 disp = (INT8)fetch(); + + if (m_regs.w[CX] == 0) + { + m_ip = m_ip + disp; + CLK(JCXZ_T); + } + else + CLK(JCXZ_NT); + } + break; + + case 0xe4: // i_inal + if (m_lock) m_lock_handler(1); + m_regs.b[AL] = read_port_byte( fetch() ); + if (m_lock) { m_lock_handler(0); m_lock = false; } + CLK(IN_IMM8); + break; + + case 0xe5: // i_inax + { + UINT8 port = fetch(); + + m_regs.w[AX] = read_port_word(port); + CLK(IN_IMM16); + } + break; + + case 0xe6: // i_outal + write_port_byte( fetch(), m_regs.b[AL]); + CLK(OUT_IMM8); + break; + + case 0xe7: // i_outax + { + UINT8 port = fetch(); + + write_port_word(port, m_regs.w[AX]); + CLK(OUT_IMM16); + } + break; + + + case 0xe8: // i_call_d16 + { + INT16 tmp = (INT16)fetch_word(); + + PUSH(m_ip); + m_ip = m_ip + tmp; + CLK(CALL_NEAR); + } + break; + + case 0xe9: // i_jmp_d16 + { + INT16 offset = (INT16)fetch_word(); + m_ip += offset; + CLK(JMP_NEAR); + } + break; + + case 0xea: // i_jmp_far + { + UINT16 tmp = fetch_word(); + UINT16 tmp1 = fetch_word(); + + m_sregs[CS] = tmp1; + m_ip = tmp; + CLK(JMP_FAR); + } + break; + + case 0xeb: // i_jmp_d8 + { + int tmp = (int)((INT8)fetch()); + + CLK(JMP_SHORT); + if (tmp==-2 && m_no_interrupt==0 && (m_pending_irq==0) && m_icount>0) + { + m_icount%=12; /* cycle skip */ + } + m_ip = (UINT16)(m_ip+tmp); + } + break; + + case 0xec: // i_inaldx + m_regs.b[AL] = read_port_byte(m_regs.w[DX]); + CLK(IN_DX8); + break; + + case 0xed: // i_inaxdx + { + UINT32 port = m_regs.w[DX]; + + m_regs.w[AX] = read_port_word(port); + CLK(IN_DX16); + } + break; + + case 0xee: // i_outdxal + write_port_byte(m_regs.w[DX], m_regs.b[AL]); + CLK(OUT_DX8); + break; + + case 0xef: // i_outdxax + { + UINT32 port = m_regs.w[DX]; + + write_port_word(port, m_regs.w[AX]); + CLK(OUT_DX16); + } + break; + + + case 0xf0: // i_lock + logerror("%s: %06x: Warning - BUSLOCK\n", tag(), pc()); + m_lock = true; + m_no_interrupt = 1; + CLK(NOP); + break; + + case 0xf2: // i_repne + { + bool invalid = false; + UINT8 next = repx_op(); + UINT16 c = m_regs.w[CX]; + + switch (next) + { + case 0xa4: CLK(OVERRIDE); if (c) do { i_movsb(); c--; } while (c>0 && m_icount>0); m_regs.w[CX]=c; m_seg_prefix = false; m_seg_prefix_next = false; break; + case 0xa5: CLK(OVERRIDE); if (c) do { i_movsw(); c--; } while (c>0 && m_icount>0); m_regs.w[CX]=c; m_seg_prefix = false; m_seg_prefix_next = false; break; + case 0xa6: CLK(OVERRIDE); if (c) do { i_cmpsb(); c--; } while (c>0 && !ZF && m_icount>0); m_regs.w[CX]=c; m_seg_prefix = false; m_seg_prefix_next = false; break; + case 0xa7: CLK(OVERRIDE); if (c) do { i_cmpsw(); c--; } while (c>0 && !ZF && m_icount>0); m_regs.w[CX]=c; m_seg_prefix = false; m_seg_prefix_next = false; break; + case 0xaa: CLK(OVERRIDE); if (c) do { i_stosb(); c--; } while (c>0 && m_icount>0); m_regs.w[CX]=c; m_seg_prefix = false; m_seg_prefix_next = false; break; + case 0xab: CLK(OVERRIDE); if (c) do { i_stosw(); c--; } while (c>0 && m_icount>0); m_regs.w[CX]=c; m_seg_prefix = false; m_seg_prefix_next = false; break; + case 0xac: CLK(OVERRIDE); if (c) do { i_lodsb(); c--; } while (c>0 && m_icount>0); m_regs.w[CX]=c; m_seg_prefix = false; m_seg_prefix_next = false; break; + case 0xad: CLK(OVERRIDE); if (c) do { i_lodsw(); c--; } while (c>0 && m_icount>0); m_regs.w[CX]=c; m_seg_prefix = false; m_seg_prefix_next = false; break; + case 0xae: CLK(OVERRIDE); if (c) do { i_scasb(); c--; } while (c>0 && !ZF && m_icount>0); m_regs.w[CX]=c; m_seg_prefix = false; m_seg_prefix_next = false; break; + case 0xaf: CLK(OVERRIDE); if (c) do { i_scasw(); c--; } while (c>0 && !ZF && m_icount>0); m_regs.w[CX]=c; m_seg_prefix = false; m_seg_prefix_next = false; break; + default: + logerror("%s: %06x: REPNE invalid\n", tag(), pc()); + // Decrement IP so the normal instruction will be executed next + m_ip--; + invalid = true; + break; + } + if(c && !invalid) + { + if(!(ZF && ((next & 6) == 6))) + m_ip = m_prev_ip; + } + } + break; + + case 0xf3: // i_repe + { + bool invalid = false; + UINT8 next = repx_op(); + UINT16 c = m_regs.w[CX]; + + switch (next) + { + case 0xa4: CLK(OVERRIDE); if (c) do { i_movsb(); c--; } while (c>0 && m_icount>0); m_regs.w[CX]=c; m_seg_prefix = false; m_seg_prefix_next = false; break; + case 0xa5: CLK(OVERRIDE); if (c) do { i_movsw(); c--; } while (c>0 && m_icount>0); m_regs.w[CX]=c; m_seg_prefix = false; m_seg_prefix_next = false; break; + case 0xa6: CLK(OVERRIDE); if (c) do { i_cmpsb(); c--; } while (c>0 && ZF && m_icount>0); m_regs.w[CX]=c; m_seg_prefix = false; m_seg_prefix_next = false; break; + case 0xa7: CLK(OVERRIDE); if (c) do { i_cmpsw(); c--; } while (c>0 && ZF && m_icount>0); m_regs.w[CX]=c; m_seg_prefix = false; m_seg_prefix_next = false; break; + case 0xaa: CLK(OVERRIDE); if (c) do { i_stosb(); c--; } while (c>0 && m_icount>0); m_regs.w[CX]=c; m_seg_prefix = false; m_seg_prefix_next = false; break; + case 0xab: CLK(OVERRIDE); if (c) do { i_stosw(); c--; } while (c>0 && m_icount>0); m_regs.w[CX]=c; m_seg_prefix = false; m_seg_prefix_next = false; break; + case 0xac: CLK(OVERRIDE); if (c) do { i_lodsb(); c--; } while (c>0 && m_icount>0); m_regs.w[CX]=c; m_seg_prefix = false; m_seg_prefix_next = false; break; + case 0xad: CLK(OVERRIDE); if (c) do { i_lodsw(); c--; } while (c>0 && m_icount>0); m_regs.w[CX]=c; m_seg_prefix = false; m_seg_prefix_next = false; break; + case 0xae: CLK(OVERRIDE); if (c) do { i_scasb(); c--; } while (c>0 && ZF && m_icount>0); m_regs.w[CX]=c; m_seg_prefix = false; m_seg_prefix_next = false; break; + case 0xaf: CLK(OVERRIDE); if (c) do { i_scasw(); c--; } while (c>0 && ZF && m_icount>0); m_regs.w[CX]=c; m_seg_prefix = false; m_seg_prefix_next = false; break; + default: + logerror("%s: %06x: REPE invalid\n", tag(), pc()); + // Decrement IP so the normal instruction will be executed next + m_ip--; + invalid = true; + break; + } + if(c && !invalid) + { + if(!(!ZF && ((next & 6) == 6))) + m_ip = m_prev_ip; + } + } + break; + + case 0xf4: // i_hlt + //logerror("%s: %06x: HALT\n", tag(), pc()); + m_icount = 0; + m_halt = true; + break; + + case 0xf5: // i_cmc + m_CarryVal = !m_CarryVal; + CLK(FLAG_OPS); + break; + + case 0xf6: // i_f6pre + { + UINT32 tmp; + UINT32 uresult,uresult2; + INT32 result,result2; + + m_modrm = fetch(); + tmp = GetRMByte(); + switch ( m_modrm & 0x38 ) + { + case 0x00: /* TEST */ + case 0x08: /* TEST (alias) */ + tmp &= fetch(); + m_CarryVal = m_OverVal = 0; + set_SZPF_Byte(tmp); + CLKM(ALU_RI8,ALU_MI8_RO); + break; + case 0x10: /* NOT */ + PutbackRMByte(~tmp); + CLKM(NEGNOT_R8,NEGNOT_M8); + break; + case 0x18: /* NEG */ + m_CarryVal = (tmp!=0) ? 1 : 0; + tmp = (~tmp)+1; + set_SZPF_Byte(tmp); + PutbackRMByte(tmp&0xff); + CLKM(NEGNOT_R8,NEGNOT_M8); + break; + case 0x20: /* MUL */ + uresult = m_regs.b[AL] * tmp; + m_regs.w[AX] = (UINT16)uresult; + m_CarryVal = m_OverVal = (m_regs.b[AH]!=0) ? 1 : 0; + set_ZF(m_regs.w[AX]); + CLKM(MUL_R8,MUL_M8); + break; + case 0x28: /* IMUL */ + result = (INT16)((INT8)m_regs.b[AL])*(INT16)((INT8)tmp); + m_regs.w[AX] = (UINT16)result; + m_CarryVal = m_OverVal = (m_regs.b[AH]!=0) ? 1 : 0; + set_ZF(m_regs.w[AX]); + CLKM(IMUL_R8,IMUL_M8); + break; + case 0x30: /* DIV */ + if (tmp) + { + uresult = m_regs.w[AX]; + uresult2 = uresult % tmp; + if ((uresult /= tmp) > 0xff) + { + interrupt(0); + } + else + { + m_regs.b[AL] = uresult; + m_regs.b[AH] = uresult2; + } + } + else + { + interrupt(0); + } + CLKM(DIV_R8,DIV_M8); + break; + case 0x38: /* IDIV */ + if (tmp) + { + result = (INT16)m_regs.w[AX]; + result2 = result % (INT16)((INT8)tmp); + if ((result /= (INT16)((INT8)tmp)) > 0xff) + { + interrupt(0); + } + else + { + m_regs.b[AL] = result; + m_regs.b[AH] = result2; + } + } + else + { + interrupt(0); + } + CLKM(IDIV_R8,IDIV_M8); + break; + } + } + break; + + + case 0xf7: // i_f7pre + { + UINT32 tmp,tmp2; + UINT32 uresult,uresult2; + INT32 result,result2; + + m_modrm = fetch(); + tmp = GetRMWord(); + switch ( m_modrm & 0x38 ) + { + case 0x00: /* TEST */ + case 0x08: /* TEST (alias) */ + tmp2 = fetch_word(); + tmp &= tmp2; + m_CarryVal = m_OverVal = 0; + set_SZPF_Word(tmp); + CLKM(ALU_RI16,ALU_MI16_RO); + break; + case 0x10: /* NOT */ + PutbackRMWord(~tmp); + CLKM(NEGNOT_R16,NEGNOT_M16); + break; + case 0x18: /* NEG */ + m_CarryVal = (tmp!=0) ? 1 : 0; + tmp = (~tmp) + 1; + set_SZPF_Word(tmp); + PutbackRMWord(tmp); + CLKM(NEGNOT_R16,NEGNOT_M16); + break; + case 0x20: /* MUL */ + uresult = m_regs.w[AX]*tmp; + m_regs.w[AX] = uresult & 0xffff; + m_regs.w[DX] = ((UINT32)uresult)>>16; + m_CarryVal = m_OverVal = (m_regs.w[DX] != 0) ? 1 : 0; + set_ZF(m_regs.w[AX] | m_regs.w[DX]); + CLKM(MUL_R16,MUL_M16); + break; + case 0x28: /* IMUL */ + result = (INT32)((INT16)m_regs.w[AX]) * (INT32)((INT16)tmp); + m_regs.w[AX] = result & 0xffff; + m_regs.w[DX] = result >> 16; + m_CarryVal = m_OverVal = (m_regs.w[DX] != 0) ? 1 : 0; + set_ZF(m_regs.w[AX] | m_regs.w[DX]); + CLKM(IMUL_R16,IMUL_M16); + break; + case 0x30: /* DIV */ + if (tmp) + { + uresult = (((UINT32)m_regs.w[DX]) << 16) | m_regs.w[AX]; + uresult2 = uresult % tmp; + if ((uresult /= tmp) > 0xffff) + { + interrupt(0); + } + else + { + m_regs.w[AX] = uresult; + m_regs.w[DX] = uresult2; + } + } + else + { + interrupt(0); + } + CLKM(DIV_R16,DIV_M16); + break; + case 0x38: /* IDIV */ + if (tmp) + { + result = ((UINT32)m_regs.w[DX] << 16) + m_regs.w[AX]; + result2 = result % (INT32)((INT16)tmp); + if ((result /= (INT32)((INT16)tmp)) > 0xffff) + { + interrupt(0); + } + else + { + m_regs.w[AX] = result; + m_regs.w[DX] = result2; + } + } + else + { + interrupt(0); + } + CLKM(IDIV_R16,IDIV_M16); + break; + } + } + break; + + + case 0xf8: // i_clc + m_CarryVal = 0; + CLK(FLAG_OPS); + break; + + case 0xf9: // i_stc + m_CarryVal = 1; + CLK(FLAG_OPS); + break; + + case 0xfa: // i_cli + m_IF = 0; + CLK(FLAG_OPS); + break; + + case 0xfb: // i_sti + m_IF = 1; + CLK(FLAG_OPS); + break; + + case 0xfc: // i_cld + m_DF = 0; + CLK(FLAG_OPS); + break; + + case 0xfd: // i_std + m_DF = 1; + CLK(FLAG_OPS); + break; + + case 0xfe: // i_fepre + { + UINT32 tmp, tmp1; + m_modrm = fetch(); + tmp = GetRMByte(); + switch ( m_modrm & 0x38 ) + { + case 0x00: /* INC */ + tmp1 = tmp+1; + m_OverVal = (tmp==0x7f); + set_AF(tmp1,tmp,1); + set_SZPF_Byte(tmp1); + PutbackRMByte(tmp1); + CLKM(INCDEC_R8,INCDEC_M8); + break; + case 0x08: /* DEC */ + tmp1 = tmp-1; + m_OverVal = (tmp==0x80); + set_AF(tmp1,tmp,1); + set_SZPF_Byte(tmp1); + PutbackRMByte(tmp1); + CLKM(INCDEC_R8,INCDEC_M8); + break; + default: + logerror("%s: %06x: FE Pre with unimplemented mod\n", tag(), pc()); + break; + } + } + break; + + case 0xff: // i_ffpre + { + UINT32 tmp, tmp1; + m_modrm = fetch(); + tmp = GetRMWord(); + switch ( m_modrm & 0x38 ) + { + case 0x00: /* INC */ + tmp1 = tmp+1; + m_OverVal = (tmp==0x7fff); + set_AF(tmp1,tmp,1); + set_SZPF_Word(tmp1); + PutbackRMWord(tmp1); + CLKM(INCDEC_R16,INCDEC_M16); + break; + case 0x08: /* DEC */ + tmp1 = tmp-1; + m_OverVal = (tmp==0x8000); + set_AF(tmp1,tmp,1); + set_SZPF_Word(tmp1); + PutbackRMWord(tmp1); + CLKM(INCDEC_R16,INCDEC_M16); + break; + case 0x10: /* CALL */ + PUSH(m_ip); + m_ip = tmp; + CLKM(CALL_R16,CALL_M16); + break; + case 0x18: /* CALL FAR */ + tmp1 = m_sregs[CS]; + m_sregs[CS] = GetnextRMWord(); + PUSH(tmp1); + PUSH(m_ip); + m_ip = tmp; + CLK(CALL_M32); + break; + case 0x20: /* JMP */ + m_ip = tmp; + CLKM(JMP_R16,JMP_M16); + break; + case 0x28: /* JMP FAR */ + m_ip = tmp; + m_sregs[CS] = GetnextRMWord(); + CLK(JMP_M32); + break; + case 0x30: + PUSH(tmp); + CLKM(PUSH_R16,PUSH_M16); + break; + default: + logerror("%s: %06x: FF Pre with unimplemented mod\n", tag(), pc()); + break; + } + } + break; + default: + return false; + } + return true; +} diff --git a/src/devices/cpu/i86/i86.h b/src/devices/cpu/i86/i86.h new file mode 100644 index 00000000000..6e48fecd71e --- /dev/null +++ b/src/devices/cpu/i86/i86.h @@ -0,0 +1,371 @@ +// license:BSD-3-Clause +// copyright-holders:Carl +#ifndef __I8086_H__ +#define __I8086_H__ + +#include "emu.h" + +///////////////////////////////////////////////////////////////// + +extern const device_type I8086; +extern const device_type I8088; + +#define INPUT_LINE_INT0 INPUT_LINE_IRQ0 +#define INPUT_LINE_TEST 20 + + +#define MCFG_I8086_LOCK_HANDLER(_write) \ + devcb = &i8086_common_cpu_device::set_lock_handler(*device, DEVCB_##_write); + + +enum +{ + I8086_PC=0, + I8086_IP, I8086_AX, I8086_CX, I8086_DX, I8086_BX, I8086_SP, I8086_BP, I8086_SI, I8086_DI, + I8086_FLAGS, I8086_ES, I8086_CS, I8086_SS, I8086_DS, + I8086_VECTOR, I8086_PENDING +}; + + +class i8086_common_cpu_device : public cpu_device +{ +public: + // construction/destruction + i8086_common_cpu_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + template static devcb_base &set_lock_handler(device_t &device, _Object object) + { return downcast(device).m_lock_handler.set_callback(object); } + +protected: + enum + { + EXCEPTION, IRET, /* EXCEPTION, iret */ + INT3, INT_IMM, INTO_NT, INTO_T, /* intS */ + OVERRIDE, /* SEGMENT OVERRIDES */ + FLAG_OPS, LAHF, SAHF, /* FLAG OPERATIONS */ + AAA, AAS, AAM, AAD, /* ARITHMETIC ADJUSTS */ + DAA, DAS, /* DECIMAL ADJUSTS */ + CBW, CWD, /* SIGN EXTENSION */ + HLT, LOAD_PTR, LEA, NOP, WAIT, XLAT, /* MISC */ + + JMP_SHORT, JMP_NEAR, JMP_FAR, /* DIRECT jmpS */ + JMP_R16, JMP_M16, JMP_M32, /* INDIRECT jmpS */ + CALL_NEAR, CALL_FAR, /* DIRECT callS */ + CALL_R16, CALL_M16, CALL_M32, /* INDIRECT callS */ + RET_NEAR, RET_FAR, RET_NEAR_IMM, RET_FAR_IMM, /* RETURNS */ + JCC_NT, JCC_T, JCXZ_NT, JCXZ_T, /* CONDITIONAL jmpS */ + LOOP_NT, LOOP_T, LOOPE_NT, LOOPE_T, /* LOOPS */ + + IN_IMM8, IN_IMM16, IN_DX8, IN_DX16, /* PORT READS */ + OUT_IMM8, OUT_IMM16, OUT_DX8, OUT_DX16, /* PORT WRITES */ + + MOV_RR8, MOV_RM8, MOV_MR8, /* MOVE, 8-BIT */ + MOV_RI8, MOV_MI8, /* MOVE, 8-BIT IMMEDIATE */ + MOV_RR16, MOV_RM16, MOV_MR16, /* MOVE, 16-BIT */ + MOV_RI16, MOV_MI16, /* MOVE, 16-BIT IMMEDIATE */ + MOV_AM8, MOV_AM16, MOV_MA8, MOV_MA16, /* MOVE, al/ax MEMORY */ + MOV_SR, MOV_SM, MOV_RS, MOV_MS, /* MOVE, SEGMENT REGISTERS */ + XCHG_RR8, XCHG_RM8, /* EXCHANGE, 8-BIT */ + XCHG_RR16, XCHG_RM16, XCHG_AR16, /* EXCHANGE, 16-BIT */ + + PUSH_R16, PUSH_M16, PUSH_SEG, PUSHF, /* PUSHES */ + POP_R16, POP_M16, POP_SEG, POPF, /* POPS */ + + ALU_RR8, ALU_RM8, ALU_MR8, /* alu OPS, 8-BIT */ + ALU_RI8, ALU_MI8, ALU_MI8_RO, /* alu OPS, 8-BIT IMMEDIATE */ + ALU_RR16, ALU_RM16, ALU_MR16, /* alu OPS, 16-BIT */ + ALU_RI16, ALU_MI16, ALU_MI16_RO, /* alu OPS, 16-BIT IMMEDIATE */ + ALU_R16I8, ALU_M16I8, ALU_M16I8_RO, /* alu OPS, 16-BIT W/8-BIT IMMEDIATE */ + MUL_R8, MUL_R16, MUL_M8, MUL_M16, /* mul */ + IMUL_R8, IMUL_R16, IMUL_M8, IMUL_M16, /* imul */ + DIV_R8, DIV_R16, DIV_M8, DIV_M16, /* div */ + IDIV_R8, IDIV_R16, IDIV_M8, IDIV_M16, /* idiv */ + INCDEC_R8, INCDEC_R16, INCDEC_M8, INCDEC_M16, /* inc/dec */ + NEGNOT_R8, NEGNOT_R16, NEGNOT_M8, NEGNOT_M16, /* neg/not */ + + ROT_REG_1, ROT_REG_BASE, ROT_REG_BIT, /* REG SHIFT/ROTATE */ + ROT_M8_1, ROT_M8_BASE, ROT_M8_BIT, /* M8 SHIFT/ROTATE */ + ROT_M16_1, ROT_M16_BASE, ROT_M16_BIT, /* M16 SHIFT/ROTATE */ + + CMPS8, REP_CMPS8_BASE, REP_CMPS8_COUNT, /* cmps 8-BIT */ + CMPS16, REP_CMPS16_BASE, REP_CMPS16_COUNT, /* cmps 16-BIT */ + SCAS8, REP_SCAS8_BASE, REP_SCAS8_COUNT, /* scas 8-BIT */ + SCAS16, REP_SCAS16_BASE, REP_SCAS16_COUNT, /* scas 16-BIT */ + LODS8, REP_LODS8_BASE, REP_LODS8_COUNT, /* lods 8-BIT */ + LODS16, REP_LODS16_BASE, REP_LODS16_COUNT, /* lods 16-BIT */ + STOS8, REP_STOS8_BASE, REP_STOS8_COUNT, /* stos 8-BIT */ + STOS16, REP_STOS16_BASE, REP_STOS16_COUNT, /* stos 16-BIT */ + MOVS8, REP_MOVS8_BASE, REP_MOVS8_COUNT, /* movs 8-BIT */ + MOVS16, REP_MOVS16_BASE, REP_MOVS16_COUNT, /* movs 16-BIT */ + + INS8, REP_INS8_BASE, REP_INS8_COUNT, /* (80186) ins 8-BIT */ + INS16, REP_INS16_BASE, REP_INS16_COUNT, /* (80186) ins 16-BIT */ + OUTS8, REP_OUTS8_BASE, REP_OUTS8_COUNT, /* (80186) outs 8-BIT */ + OUTS16, REP_OUTS16_BASE, REP_OUTS16_COUNT, /* (80186) outs 16-BIT */ + PUSH_IMM, PUSHA, POPA, /* (80186) push IMMEDIATE, pusha/popa */ + IMUL_RRI8, IMUL_RMI8, /* (80186) imul IMMEDIATE 8-BIT */ + IMUL_RRI16, IMUL_RMI16, /* (80186) imul IMMEDIATE 16-BIT */ + ENTER0, ENTER1, ENTER_BASE, ENTER_COUNT, LEAVE, /* (80186) enter/leave */ + BOUND /* (80186) bound */ + }; + + enum SREGS { ES=0, CS, SS, DS }; + enum WREGS { AX=0, CX, DX, BX, SP, BP, SI, DI }; + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_execute_interface overrides + virtual UINT32 execute_min_cycles() const { return 1; } + virtual UINT32 execute_max_cycles() const { return 50; } + virtual void execute_set_input(int inputnum, int state); + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const { return 1; } + virtual UINT32 disasm_max_opcode_bytes() const { return 8; } + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + + // device_state_interface overrides + virtual void state_string_export(const device_state_entry &entry, std::string &str); + + virtual void interrupt(int int_num, int trap = 1); + bool common_op(UINT8 op); + + // Accessing memory and io + inline UINT8 read_byte(UINT32 addr); + inline UINT16 read_word(UINT32 addr); + inline void write_byte(UINT32 addr, UINT8 data); + inline void write_word(UINT32 addr, UINT16 data); + virtual UINT8 read_port_byte(UINT16 port); + virtual UINT16 read_port_word(UINT16 port); + virtual void write_port_byte(UINT16 port, UINT8 data); + virtual void write_port_word(UINT16 port, UINT16 data); + + // Executing instructions + virtual UINT8 fetch_op() = 0; + virtual UINT8 fetch() = 0; + inline UINT16 fetch_word(); + inline UINT8 repx_op(); + + // Cycles passed while executing instructions + inline void CLK(UINT8 op); + inline void CLKM(UINT8 op_reg, UINT8 op_mem); + + // Memory handling while executing instructions + virtual UINT32 calc_addr(int seg, UINT16 offset, int size, int op, bool override = true); + inline UINT32 get_ea(int size, int op); + inline void PutbackRMByte(UINT8 data); + inline void PutbackRMWord(UINT16 data); + inline void RegByte(UINT8 data); + inline void RegWord(UINT16 data); + inline UINT8 RegByte(); + inline UINT16 RegWord(); + inline UINT16 GetRMWord(); + inline UINT16 GetnextRMWord(); + inline UINT8 GetRMByte(); + inline void PutMemB(int seg, UINT16 offset, UINT8 data); + inline void PutMemW(int seg, UINT16 offset, UINT16 data); + inline UINT8 GetMemB(int seg, UINT16 offset); + inline UINT16 GetMemW(int seg, UINT16 offset); + inline void PutImmRMWord(); + inline void PutRMWord(UINT16 val); + inline void PutRMByte(UINT8 val); + inline void PutImmRMByte(); + inline void DEF_br8(); + inline void DEF_wr16(); + inline void DEF_r8b(); + inline void DEF_r16w(); + inline void DEF_ald8(); + inline void DEF_axd16(); + + // Flags + inline void set_CFB(UINT32 x); + inline void set_CFW(UINT32 x); + inline void set_AF(UINT32 x,UINT32 y,UINT32 z); + inline void set_SF(UINT32 x); + inline void set_ZF(UINT32 x); + inline void set_PF(UINT32 x); + inline void set_SZPF_Byte(UINT32 x); + inline void set_SZPF_Word(UINT32 x); + inline void set_OFW_Add(UINT32 x,UINT32 y,UINT32 z); + inline void set_OFB_Add(UINT32 x,UINT32 y,UINT32 z); + inline void set_OFW_Sub(UINT32 x,UINT32 y,UINT32 z); + inline void set_OFB_Sub(UINT32 x,UINT32 y,UINT32 z); + inline UINT16 CompressFlags(); + inline void ExpandFlags(UINT16 f); + + // rep instructions + inline void i_insb(); + inline void i_insw(); + inline void i_outsb(); + inline void i_outsw(); + inline void i_movsb(); + inline void i_movsw(); + inline void i_cmpsb(); + inline void i_cmpsw(); + inline void i_stosb(); + inline void i_stosw(); + inline void i_lodsb(); + inline void i_lodsw(); + inline void i_scasb(); + inline void i_scasw(); + inline void i_popf(); + + // sub implementations + inline UINT32 ADDB(); + inline UINT32 ADDX(); + inline UINT32 SUBB(); + inline UINT32 SUBX(); + inline void ORB(); + inline void ORW(); + inline void ANDB(); + inline void ANDX(); + inline void XORB(); + inline void XORW(); + inline void ROL_BYTE(); + inline void ROL_WORD(); + inline void ROR_BYTE(); + inline void ROR_WORD(); + inline void ROLC_BYTE(); + inline void ROLC_WORD(); + inline void RORC_BYTE(); + inline void RORC_WORD(); + inline void SHL_BYTE(UINT8 c); + inline void SHL_WORD(UINT8 c); + inline void SHR_BYTE(UINT8 c); + inline void SHR_WORD(UINT8 c); + inline void SHRA_BYTE(UINT8 c); + inline void SHRA_WORD(UINT8 c); + inline void XchgAXReg(UINT8 reg); + inline void IncWordReg(UINT8 reg); + inline void DecWordReg(UINT8 reg); + inline void PUSH(UINT16 data); + inline UINT16 POP(); + inline void JMP(bool cond); + inline void ADJ4(INT8 param1, INT8 param2); + inline void ADJB(INT8 param1, INT8 param2); + +protected: + + union + { /* eight general registers */ + UINT16 w[8]; /* viewed as 16 bits registers */ + UINT8 b[16]; /* or as 8 bit registers */ + } m_regs; + + enum BREGS { + AL = NATIVE_ENDIAN_VALUE_LE_BE(0x0, 0x1), + AH = NATIVE_ENDIAN_VALUE_LE_BE(0x1, 0x0), + CL = NATIVE_ENDIAN_VALUE_LE_BE(0x2, 0x3), + CH = NATIVE_ENDIAN_VALUE_LE_BE(0x3, 0x2), + DL = NATIVE_ENDIAN_VALUE_LE_BE(0x4, 0x5), + DH = NATIVE_ENDIAN_VALUE_LE_BE(0x5, 0x4), + BL = NATIVE_ENDIAN_VALUE_LE_BE(0x6, 0x7), + BH = NATIVE_ENDIAN_VALUE_LE_BE(0x7, 0x6), + SPL = NATIVE_ENDIAN_VALUE_LE_BE(0x8, 0x9), + SPH = NATIVE_ENDIAN_VALUE_LE_BE(0x9, 0x8), + BPL = NATIVE_ENDIAN_VALUE_LE_BE(0xa, 0xb), + BPH = NATIVE_ENDIAN_VALUE_LE_BE(0xb, 0xa), + SIL = NATIVE_ENDIAN_VALUE_LE_BE(0xc, 0xd), + SIH = NATIVE_ENDIAN_VALUE_LE_BE(0xd, 0xc), + DIL = NATIVE_ENDIAN_VALUE_LE_BE(0xe, 0xf), + DIH = NATIVE_ENDIAN_VALUE_LE_BE(0xf, 0xe) + }; + + enum { + I8086_READ, + I8086_WRITE, + I8086_FETCH, + I8086_NONE + }; + + UINT16 m_sregs[4]; + + UINT16 m_ip; + UINT16 m_prev_ip; + + INT32 m_SignVal; + UINT32 m_AuxVal, m_OverVal, m_ZeroVal, m_CarryVal, m_ParityVal; /* 0 or non-0 valued flags */ + UINT8 m_TF, m_IF, m_DF; /* 0 or 1 valued flags */ + UINT8 m_IOPL, m_NT, m_MF; + UINT32 m_int_vector; + UINT32 m_pending_irq; + UINT32 m_nmi_state; + UINT32 m_irq_state; + UINT8 m_no_interrupt; + UINT8 m_fire_trap; + UINT8 m_test_state; + + address_space *m_program; + direct_read_data *m_direct; + address_space *m_io; + offs_t m_fetch_xor; + int m_icount; + + UINT32 m_prefix_seg; /* the latest prefix segment */ + bool m_seg_prefix; /* prefix segment indicator */ + bool m_seg_prefix_next; /* prefix segment for next instruction */ + + UINT32 m_ea; + UINT16 m_eo; + UINT16 m_e16; + + // Used during execution of instructions + UINT8 m_modrm; + UINT32 m_dst; + UINT32 m_src; + UINT32 m_pc; + + // Lookup tables + UINT8 m_parity_table[256]; + struct { + struct { + int w[256]; + int b[256]; + } reg; + struct { + int w[256]; + int b[256]; + } RM; + } m_Mod_RM; + + UINT8 m_timing[200]; + bool m_halt; + + bool m_lock; + devcb_write_line m_lock_handler; +}; + +class i8086_cpu_device : public i8086_common_cpu_device +{ +public: + // construction/destruction + i8086_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + i8086_cpu_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source, int data_bus_size); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const { return (spacenum == AS_PROGRAM) ? &m_program_config : ( (spacenum == AS_IO) ? &m_io_config : NULL ); } + +protected: + virtual void execute_run(); + virtual void device_start(); + virtual UINT32 execute_input_lines() const { return 1; } + virtual UINT8 fetch_op(); + virtual UINT8 fetch(); + UINT32 pc() { return m_pc = (m_sregs[CS] << 4) + m_ip; } + + address_space_config m_program_config; + address_space_config m_io_config; + static const UINT8 m_i8086_timing[200]; +}; + +class i8088_cpu_device : public i8086_cpu_device +{ +public: + // construction/destruction + i8088_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +#endif /* __I8086_H__ */ diff --git a/src/devices/cpu/i86/i86.txt b/src/devices/cpu/i86/i86.txt new file mode 100644 index 00000000000..39b54d6a8d0 --- /dev/null +++ b/src/devices/cpu/i86/i86.txt @@ -0,0 +1,111 @@ +intel 8086 and compatibles +-------------------------- + +this info is here, +to list and give some remarks on all 8086 compatible processors + +excellent info in Hamarsoft's 86BUGS list +(also distributed in ralf browns interrupt list) + +8086/8088 +--------- +20 bit address bus, 16 bit data bus and registers +many 8080 assembler sources should be compilable/reusable + +8086 +---- +6 bytes prefetch queue + +8088 +---- +8086 with 8 bit data bus, +prefetch queue only 4 byte, and refilled when 1 byte empty + +early 8086/8088 revisions bug +----------------------------- +(copyright 1978 on package) +mov sreg, doesnot disable until next operation is executed + +8086/8088 +--------- +"mov cs, " causes unconditional jump! + +80C86/80C88 +----------- +"mov cs, " ignored + +80186/80188 +----------- +integrated pic8259, pit8253, dma8253 (but not at standard pc addresses) +additional instructions +"mov cs, " ? +shift count anded with 0x1f + +80188 +----- +8bit data bus + +NEC series +---------- +80186 instruction set, additional nec instructions +although it is based on 80186 instruction set, some behaviours follow 8086 +8080 emulation mode +"mov cs, " ignored +shift count not anded (acts like 8086) + +NEC 70116 (V30) +--------------- +8086 pin compatible + +NEC 70108 (V20) +--------------- +8088 pinout + +NEC V30MX +--------- +on die ems hardware +24 bit address but for ems memory!? +no 8080 emulation mode + +NEC V40 +------- +pinout, integrated peripherals as 80186 + +NEC V50 +------- +pinout, integrated peripherals as 80188 + +NEC V33? +-------- +speed optimized V30? + +NEC V25/V35? +------------ + +NEC V25+/V35+? +-------------- + +NEC V60/V70 +----------- +risc (misc/delux) like instruction set +v30? emulation mode (without 8080 emulation mode) + +80286 +----- +80186 with additional instructions +24 bit address bus, +protected mode + +80386 and later +--------------- +not covered here + +8087/80287/80387/80387sx +------------------------ +mathematical coprocessors + +weitek, iit variants + +in 80486 coprocessor integrated +(except 80486sx and several clones) +80487: 80486 with other pinout diff --git a/src/devices/cpu/i86/i86inline.h b/src/devices/cpu/i86/i86inline.h new file mode 100644 index 00000000000..d848e336e35 --- /dev/null +++ b/src/devices/cpu/i86/i86inline.h @@ -0,0 +1,980 @@ +// license:BSD-3-Clause +// copyright-holders:Carl +#include "i86.h" + +#define CF (m_CarryVal!=0) +#define SF (m_SignVal<0) +#define ZF (m_ZeroVal==0) +#define PF m_parity_table[(UINT8)m_ParityVal] +#define AF (m_AuxVal!=0) +#define OF (m_OverVal!=0) + +/* The interrupt number of a pending external interrupt pending NMI is 2. */ +/* For INTR interrupts, the level is caught on the bus during an INTA cycle */ + +#define INT_IRQ 0x01 +#define NMI_IRQ 0x02 + +UINT8 i8086_common_cpu_device::read_byte(UINT32 addr) +{ + return m_program->read_byte(addr); +} + +UINT16 i8086_common_cpu_device::read_word(UINT32 addr) +{ + return m_program->read_word_unaligned(addr); +} + +void i8086_common_cpu_device::write_byte(UINT32 addr, UINT8 data) +{ + m_program->write_byte(addr, data); +} + + +void i8086_common_cpu_device::write_word(UINT32 addr, UINT16 data) +{ + m_program->write_word_unaligned(addr, data); +} + +inline UINT16 i8086_common_cpu_device::fetch_word() +{ + UINT16 data = fetch(); + data |= ( fetch() << 8 ); + return data; +} + +inline UINT8 i8086_common_cpu_device::repx_op() +{ + UINT8 next = fetch_op(); + bool seg_prefix = false; + int seg = 0; + + switch (next) + { + case 0x26: + seg_prefix = true; + seg = ES; + break; + case 0x2e: + seg_prefix = true; + seg = CS; + break; + case 0x36: + seg_prefix = true; + seg = SS; + break; + case 0x3e: + seg_prefix = true; + seg = DS; + break; + } + + if ( seg_prefix ) + { + m_seg_prefix = true; + m_seg_prefix_next = true; + m_prefix_seg = seg; + next = fetch_op(); + CLK(OVERRIDE); + } + + return next; +} + + +inline void i8086_common_cpu_device::CLK(UINT8 op) +{ + m_icount -= m_timing[op]; +} + + +inline void i8086_common_cpu_device::CLKM(UINT8 op_reg, UINT8 op_mem) +{ + m_icount -= ( m_modrm >= 0xc0 ) ? m_timing[op_reg] : m_timing[op_mem]; +} + + +inline UINT32 i8086_common_cpu_device::get_ea(int size, int op) +{ + switch( m_modrm & 0xc7 ) + { + case 0x00: + m_icount -= 7; + m_eo = m_regs.w[BX] + m_regs.w[SI]; + m_ea = calc_addr(DS, m_eo, size, op); + break; + case 0x01: + m_icount -= 8; + m_eo = m_regs.w[BX] + m_regs.w[DI]; + m_ea = calc_addr(DS, m_eo, size, op); + break; + case 0x02: + m_icount -= 8; + m_eo = m_regs.w[BP] + m_regs.w[SI]; + m_ea = calc_addr(SS, m_eo, size, op); + break; + case 0x03: + m_icount -= 7; + m_eo = m_regs.w[BP] + m_regs.w[DI]; + m_ea = calc_addr(SS, m_eo, size, op); + break; + case 0x04: + m_icount -= 5; + m_eo = m_regs.w[SI]; + m_ea = calc_addr(DS, m_eo, size, op); + break; + case 0x05: + m_icount -= 5; + m_eo = m_regs.w[DI]; + m_ea = calc_addr(DS, m_eo, size, op); + break; + case 0x06: + m_icount -= 6; + m_eo = fetch_word(); + m_ea = calc_addr(DS, m_eo, size, op); + break; + case 0x07: + m_icount -= 5; + m_eo = m_regs.w[BX]; + m_ea = calc_addr(DS, m_eo, size, op); + break; + + case 0x40: + m_icount -= 11; + m_eo = m_regs.w[BX] + m_regs.w[SI] + (INT8)fetch(); + m_ea = calc_addr(DS, m_eo, size, op); + break; + case 0x41: + m_icount -= 12; + m_eo = m_regs.w[BX] + m_regs.w[DI] + (INT8)fetch(); + m_ea = calc_addr(DS, m_eo, size, op); + break; + case 0x42: + m_icount -= 12; + m_eo = m_regs.w[BP] + m_regs.w[SI] + (INT8)fetch(); + m_ea = calc_addr(SS, m_eo, size, op); + break; + case 0x43: + m_icount -= 11; + m_eo = m_regs.w[BP] + m_regs.w[DI] + (INT8)fetch(); + m_ea = calc_addr(SS, m_eo, size, op); + break; + case 0x44: + m_icount -= 9; + m_eo = m_regs.w[SI] + (INT8)fetch(); + m_ea = calc_addr(DS, m_eo, size, op); + break; + case 0x45: + m_icount -= 9; + m_eo = m_regs.w[DI] + (INT8)fetch(); + m_ea = calc_addr(DS, m_eo, size, op); + break; + case 0x46: + m_icount -= 9; + m_eo = m_regs.w[BP] + (INT8)fetch(); + m_ea = calc_addr(SS, m_eo, size, op); + break; + case 0x47: + m_icount -= 9; + m_eo = m_regs.w[BX] + (INT8)fetch(); + m_ea = calc_addr(DS, m_eo, size, op); + break; + + case 0x80: + m_icount -= 11; + m_e16 = fetch_word(); + m_eo = m_regs.w[BX] + m_regs.w[SI] + (INT16)m_e16; + m_ea = calc_addr(DS, m_eo, size, op); + break; + case 0x81: + m_icount -= 12; + m_e16 = fetch_word(); + m_eo = m_regs.w[BX] + m_regs.w[DI] + (INT16)m_e16; + m_ea = calc_addr(DS, m_eo, size, op); + break; + case 0x82: + m_icount -= 11; + m_e16 = fetch_word(); + m_eo = m_regs.w[BP] + m_regs.w[SI] + (INT16)m_e16; + m_ea = calc_addr(SS, m_eo, size, op); + break; + case 0x83: + m_icount -= 11; + m_e16 = fetch_word(); + m_eo = m_regs.w[BP] + m_regs.w[DI] + (INT16)m_e16; + m_ea = calc_addr(SS, m_eo, size, op); + break; + case 0x84: + m_icount -= 9; + m_e16 = fetch_word(); + m_eo = m_regs.w[SI] + (INT16)m_e16; + m_ea = calc_addr(DS, m_eo, size, op); + break; + case 0x85: + m_icount -= 9; + m_e16 = fetch_word(); + m_eo = m_regs.w[DI] + (INT16)m_e16; + m_ea = calc_addr(DS, m_eo, size, op); + break; + case 0x86: + m_icount -= 9; + m_e16 = fetch_word(); + m_eo = m_regs.w[BP] + (INT16)m_e16; + m_ea = calc_addr(SS, m_eo, size, op); + break; + case 0x87: + m_icount -= 9; + m_e16 = fetch_word(); + m_eo = m_regs.w[BX] + (INT16)m_e16; + m_ea = calc_addr(DS, m_eo, size, op); + break; + } + + return m_ea; +} + + +inline void i8086_common_cpu_device::PutbackRMByte(UINT8 data) +{ + if ( m_modrm >= 0xc0 ) + { + m_regs.b[ m_Mod_RM.RM.b[ m_modrm ] ] = data; + } + else + { + write_byte( m_ea, data ); + } +} + + +inline void i8086_common_cpu_device::PutbackRMWord(UINT16 data) +{ + if ( m_modrm >= 0xc0 ) + { + m_regs.w[ m_Mod_RM.RM.w[ m_modrm ] ] = data; + } + else + { + write_word( m_ea, data ); + } +} + +inline void i8086_common_cpu_device::PutImmRMWord() +{ + if ( m_modrm >= 0xc0 ) + { + m_regs.w[ m_Mod_RM.RM.w[ m_modrm ] ] = fetch_word(); + } + else + { + UINT32 addr = get_ea(2, I8086_WRITE); + write_word( addr, fetch_word() ); + } +} + +inline void i8086_common_cpu_device::PutRMWord(UINT16 val) +{ + if ( m_modrm >= 0xc0 ) + { + m_regs.w[ m_Mod_RM.RM.w[ m_modrm ] ] = val; + } + else + { + write_word( get_ea(2, I8086_WRITE), val ); + } +} + + +inline void i8086_common_cpu_device::PutRMByte(UINT8 val) +{ + if ( m_modrm >= 0xc0 ) + { + m_regs.b[ m_Mod_RM.RM.b[ m_modrm ] ] = val; + } + else + { + write_byte( get_ea(1, I8086_WRITE), val ); + } +} + + +inline void i8086_common_cpu_device::PutImmRMByte() +{ + if ( m_modrm >= 0xc0 ) + { + m_regs.b[ m_Mod_RM.RM.b[ m_modrm ] ] = fetch(); + } + else + { + UINT32 addr = get_ea(1, I8086_WRITE); + write_byte( addr, fetch() ); + } +} + + +inline void i8086_common_cpu_device::DEF_br8() +{ + m_modrm = fetch(); + m_src = RegByte(); + m_dst = GetRMByte(); +} + + +inline void i8086_common_cpu_device::DEF_wr16() +{ + m_modrm = fetch(); + m_src = RegWord(); + m_dst = GetRMWord(); +} + + +inline void i8086_common_cpu_device::DEF_r8b() +{ + m_modrm = fetch(); + m_dst = RegByte(); + m_src = GetRMByte(); +} + + +inline void i8086_common_cpu_device::DEF_r16w() +{ + m_modrm = fetch(); + m_dst = RegWord(); + m_src = GetRMWord(); +} + + +inline void i8086_common_cpu_device::DEF_ald8() +{ + m_src = fetch(); + m_dst = m_regs.b[AL]; +} + + +inline void i8086_common_cpu_device::DEF_axd16() +{ + m_src = fetch_word(); + m_dst = m_regs.w[AX]; +} + + + +inline void i8086_common_cpu_device::RegByte(UINT8 data) +{ + m_regs.b[ m_Mod_RM.reg.b[ m_modrm ] ] = data; +} + + +inline void i8086_common_cpu_device::RegWord(UINT16 data) +{ + m_regs.w[ m_Mod_RM.reg.w[ m_modrm ] ] = data; +} + + +inline UINT8 i8086_common_cpu_device::RegByte() +{ + return m_regs.b[ m_Mod_RM.reg.b[ m_modrm ] ]; +} + + +inline UINT16 i8086_common_cpu_device::RegWord() +{ + return m_regs.w[ m_Mod_RM.reg.w[ m_modrm ] ]; +} + + +inline UINT16 i8086_common_cpu_device::GetRMWord() +{ + if ( m_modrm >= 0xc0 ) + { + return m_regs.w[ m_Mod_RM.RM.w[ m_modrm ] ]; + } + else + { + return read_word( get_ea(2, I8086_READ) ); + } +} + + +inline UINT16 i8086_common_cpu_device::GetnextRMWord() +{ + UINT32 addr = ( m_ea & ~0xffff ) | ( ( m_ea + 2 ) & 0xffff ); + + return read_word( addr ); +} + + +inline UINT8 i8086_common_cpu_device::GetRMByte() +{ + if ( m_modrm >= 0xc0 ) + { + return m_regs.b[ m_Mod_RM.RM.b[ m_modrm ] ]; + } + else + { + return read_byte( get_ea(1, I8086_READ) ); + } +} + + +inline void i8086_common_cpu_device::PutMemB(int seg, UINT16 offset, UINT8 data) +{ + write_byte( calc_addr(seg, offset, 1, I8086_WRITE), data); +} + + +inline void i8086_common_cpu_device::PutMemW(int seg, UINT16 offset, UINT16 data) +{ + write_word( calc_addr( seg, offset, 2, I8086_WRITE), data); +} + + +inline UINT8 i8086_common_cpu_device::GetMemB(int seg, UINT16 offset) +{ + return read_byte( calc_addr(seg, offset, 1, I8086_READ) ); +} + + +inline UINT16 i8086_common_cpu_device::GetMemW(int seg, UINT16 offset) +{ + return read_word( calc_addr(seg, offset, 2, I8086_READ) ); +} + + +// Setting flags + +inline void i8086_common_cpu_device::set_CFB(UINT32 x) +{ + m_CarryVal = x & 0x100; +} + +inline void i8086_common_cpu_device::set_CFW(UINT32 x) +{ + m_CarryVal = x & 0x10000; +} + +inline void i8086_common_cpu_device::set_AF(UINT32 x,UINT32 y,UINT32 z) +{ + m_AuxVal = (x ^ (y ^ z)) & 0x10; +} + +inline void i8086_common_cpu_device::set_SF(UINT32 x) +{ + m_SignVal = x; +} + +inline void i8086_common_cpu_device::set_ZF(UINT32 x) +{ + m_ZeroVal = x; +} + +inline void i8086_common_cpu_device::set_PF(UINT32 x) +{ + m_ParityVal = x; +} + +inline void i8086_common_cpu_device::set_SZPF_Byte(UINT32 x) +{ + m_SignVal = m_ZeroVal = m_ParityVal = (INT8)x; +} + +inline void i8086_common_cpu_device::set_SZPF_Word(UINT32 x) +{ + m_SignVal = m_ZeroVal = m_ParityVal = (INT16)x; +} + +inline void i8086_common_cpu_device::set_OFW_Add(UINT32 x,UINT32 y,UINT32 z) +{ + m_OverVal = (x ^ y) & (x ^ z) & 0x8000; +} + +inline void i8086_common_cpu_device::set_OFB_Add(UINT32 x,UINT32 y,UINT32 z) +{ + m_OverVal = (x ^ y) & (x ^ z) & 0x80; +} + +inline void i8086_common_cpu_device::set_OFW_Sub(UINT32 x,UINT32 y,UINT32 z) +{ + m_OverVal = (z ^ y) & (z ^ x) & 0x8000; +} + +inline void i8086_common_cpu_device::set_OFB_Sub(UINT32 x,UINT32 y,UINT32 z) +{ + m_OverVal = (z ^ y) & (z ^ x) & 0x80; +} + + +inline UINT16 i8086_common_cpu_device::CompressFlags() +{ + return (CF ? 1 : 0) + | (1 << 1) + | (PF ? 4 : 0) + | (AF ? 0x10 : 0) + | (ZF ? 0x40 : 0) + | (SF ? 0x80 : 0) + | (m_TF << 8) + | (m_IF << 9) + | (m_DF << 10) + | (OF << 11) + | (m_IOPL << 12) + | (m_NT << 14) + | (m_MF << 15); +} + +inline void i8086_common_cpu_device::ExpandFlags(UINT16 f) +{ + m_CarryVal = (f) & 1; + m_ParityVal = !((f) & 4); + m_AuxVal = (f) & 16; + m_ZeroVal = !((f) & 64); + m_SignVal = (f) & 128 ? -1 : 0; + m_TF = ((f) & 256) == 256; + m_IF = ((f) & 512) == 512; + m_DF = ((f) & 1024) == 1024; + m_OverVal = (f) & 2048; + m_IOPL = (f >> 12) & 3; + m_NT = ((f) & 0x4000) == 0x4000; + m_MF = ((f) & 0x8000) == 0x8000; +} + +inline void i8086_common_cpu_device::i_insb() +{ + UINT32 ea = calc_addr(ES, m_regs.w[DI], 1, I8086_WRITE); + write_byte(ea, read_port_byte(m_regs.w[DX])); + m_regs.w[DI] += -2 * m_DF + 1; + CLK(IN_IMM8); +} + +inline void i8086_common_cpu_device::i_insw() +{ + UINT32 ea = calc_addr(ES, m_regs.w[DI], 2, I8086_WRITE); + write_word(ea, read_port_word(m_regs.w[DX])); + m_regs.w[DI] += -4 * m_DF + 2; + CLK(IN_IMM16); +} + +inline void i8086_common_cpu_device::i_outsb() +{ + write_port_byte(m_regs.w[DX], GetMemB(DS, m_regs.w[SI])); + m_regs.w[SI] += -2 * m_DF + 1; + CLK(OUT_IMM8); +} + +inline void i8086_common_cpu_device::i_outsw() +{ + write_port_word(m_regs.w[DX], GetMemW(DS, m_regs.w[SI])); + m_regs.w[SI] += -4 * m_DF + 2; + CLK(OUT_IMM16); +} + +inline void i8086_common_cpu_device::i_movsb() +{ + UINT8 tmp = GetMemB( DS, m_regs.w[SI] ); + PutMemB( ES, m_regs.w[DI], tmp); + m_regs.w[DI] += -2 * m_DF + 1; + m_regs.w[SI] += -2 * m_DF + 1; + CLK(MOVS8); +} + +inline void i8086_common_cpu_device::i_movsw() +{ + UINT16 tmp = GetMemW( DS, m_regs.w[SI] ); + PutMemW( ES, m_regs.w[DI], tmp ); + m_regs.w[DI] += -4 * m_DF + 2; + m_regs.w[SI] += -4 * m_DF + 2; + CLK(MOVS16); +} + +inline void i8086_common_cpu_device::i_cmpsb() +{ + m_src = GetMemB( ES, m_regs.w[DI] ); + m_dst = GetMemB( DS, m_regs.w[SI] ); + set_CFB(SUBB()); + m_regs.w[DI] += -2 * m_DF + 1; + m_regs.w[SI] += -2 * m_DF + 1; + CLK(CMPS8); +} + +inline void i8086_common_cpu_device::i_cmpsw() +{ + m_src = GetMemW( ES, m_regs.w[DI] ); + m_dst = GetMemW( DS, m_regs.w[SI] ); + set_CFW(SUBX()); + m_regs.w[DI] += -4 * m_DF + 2; + m_regs.w[SI] += -4 * m_DF + 2; + CLK(CMPS16); +} + +inline void i8086_common_cpu_device::i_stosb() +{ + PutMemB( ES, m_regs.w[DI], m_regs.b[AL] ); + m_regs.w[DI] += -2 * m_DF + 1; + CLK(STOS8); +} + +inline void i8086_common_cpu_device::i_stosw() +{ + PutMemW( ES, m_regs.w[DI], m_regs.w[AX] ); + m_regs.w[DI] += -4 * m_DF + 2; + CLK(STOS16); +} + +inline void i8086_common_cpu_device::i_lodsb() +{ + m_regs.b[AL] = GetMemB( DS, m_regs.w[SI] ); + m_regs.w[SI] += -2 * m_DF + 1; + CLK(LODS8); +} + +inline void i8086_common_cpu_device::i_lodsw() +{ + m_regs.w[AX] = GetMemW( DS, m_regs.w[SI] ); + m_regs.w[SI] += -4 * m_DF + 2; + CLK(LODS16); +} + +inline void i8086_common_cpu_device::i_scasb() +{ + m_src = GetMemB( ES, m_regs.w[DI] ); + m_dst = m_regs.b[AL]; + set_CFB(SUBB()); + m_regs.w[DI] += -2 * m_DF + 1; + CLK(SCAS8); +} + +inline void i8086_common_cpu_device::i_scasw() +{ + m_src = GetMemW( ES, m_regs.w[DI] ); + m_dst = m_regs.w[AX]; + set_CFW(SUBX()); + m_regs.w[DI] += -4 * m_DF + 2; + CLK(SCAS16); +} + + +inline void i8086_common_cpu_device::i_popf() +{ + UINT32 tmp = POP(); + + ExpandFlags(tmp | 0xf000); + CLK(POPF); + if (m_TF) + { + m_fire_trap = 1; + } +} + + +inline UINT32 i8086_common_cpu_device::ADDB() +{ + UINT32 res = m_dst + m_src; + + set_OFB_Add(res,m_src,m_dst); + set_AF(res,m_src,m_dst); + set_SZPF_Byte(res); + m_dst = res & 0xff; + return res; +} + + +inline UINT32 i8086_common_cpu_device::ADDX() +{ + UINT32 res = m_dst + m_src; + + set_OFW_Add(res,m_src,m_dst); + set_AF(res,m_src,m_dst); + set_SZPF_Word(res); + m_dst = res & 0xffff; + return res; +} + + +inline UINT32 i8086_common_cpu_device::SUBB() +{ + UINT32 res = m_dst - m_src; + + set_OFB_Sub(res,m_src,m_dst); + set_AF(res,m_src,m_dst); + set_SZPF_Byte(res); + m_dst = res & 0xff; + return res; +} + + +inline UINT32 i8086_common_cpu_device::SUBX() +{ + UINT32 res = m_dst - m_src; + + set_OFW_Sub(res,m_src,m_dst); + set_AF(res,m_src,m_dst); + set_SZPF_Word(res); + m_dst = res & 0xffff; + return res; +} + + +inline void i8086_common_cpu_device::ORB() +{ + m_dst |= m_src; + m_CarryVal = m_OverVal = m_AuxVal = 0; + set_SZPF_Byte(m_dst); +} + + +inline void i8086_common_cpu_device::ORW() +{ + m_dst |= m_src; + m_CarryVal = m_OverVal = m_AuxVal = 0; + set_SZPF_Word(m_dst); +} + + +inline void i8086_common_cpu_device::ANDB() +{ + m_dst &= m_src; + m_CarryVal = m_OverVal = m_AuxVal = 0; + set_SZPF_Byte(m_dst); +} + + +inline void i8086_common_cpu_device::ANDX() +{ + m_dst &= m_src; + m_CarryVal = m_OverVal = m_AuxVal = 0; + set_SZPF_Word(m_dst); +} + + +inline void i8086_common_cpu_device::XORB() +{ + m_dst ^= m_src; + m_CarryVal = m_OverVal = m_AuxVal = 0; + set_SZPF_Byte(m_dst); +} + + +inline void i8086_common_cpu_device::XORW() +{ + m_dst ^= m_src; + m_CarryVal = m_OverVal = m_AuxVal = 0; + set_SZPF_Word(m_dst); +} + + +inline void i8086_common_cpu_device::ROL_BYTE() +{ + m_CarryVal = m_dst & 0x80; + m_dst = (m_dst << 1) | ( CF ? 1 : 0 ); +} + +inline void i8086_common_cpu_device::ROL_WORD() +{ + m_CarryVal = m_dst & 0x8000; + m_dst = (m_dst << 1) | ( CF ? 1 : 0 ); +} + +inline void i8086_common_cpu_device::ROR_BYTE() +{ + m_CarryVal = m_dst & 0x1; + m_dst = (m_dst >> 1) | (CF ? 0x80 : 0x00); +} + +inline void i8086_common_cpu_device::ROR_WORD() +{ + m_CarryVal = m_dst & 0x1; + m_dst = (m_dst >> 1) + (CF ? 0x8000 : 0x0000); +} + +inline void i8086_common_cpu_device::ROLC_BYTE() +{ + m_dst = (m_dst << 1) | ( CF ? 1 : 0 ); + set_CFB(m_dst); +} + +inline void i8086_common_cpu_device::ROLC_WORD() +{ + m_dst = (m_dst << 1) | ( CF ? 1 : 0 ); + set_CFW(m_dst); +} + +inline void i8086_common_cpu_device::RORC_BYTE() +{ + m_dst |= ( CF ? 0x100 : 0x00); + m_CarryVal = m_dst & 0x01; + m_dst >>= 1; +} + +inline void i8086_common_cpu_device::RORC_WORD() +{ + m_dst |= ( CF ? 0x10000 : 0); + m_CarryVal = m_dst & 0x01; + m_dst >>= 1; +} + +inline void i8086_common_cpu_device::SHL_BYTE(UINT8 c) +{ + while (c--) + m_dst <<= 1; + + set_CFB(m_dst); + set_SZPF_Byte(m_dst); + PutbackRMByte(m_dst); +} + +inline void i8086_common_cpu_device::SHL_WORD(UINT8 c) +{ + while (c--) + m_dst <<= 1; + + set_CFW(m_dst); + set_SZPF_Word(m_dst); + PutbackRMWord(m_dst); +} + +inline void i8086_common_cpu_device::SHR_BYTE(UINT8 c) +{ + while (c--) + { + m_CarryVal = m_dst & 0x01; + m_dst >>= 1; + } + + set_SZPF_Byte(m_dst); + PutbackRMByte(m_dst); +} + +inline void i8086_common_cpu_device::SHR_WORD(UINT8 c) +{ + while (c--) + { + m_CarryVal = m_dst & 0x01; + m_dst >>= 1; + } + + set_SZPF_Word(m_dst); + PutbackRMWord(m_dst); +} + +inline void i8086_common_cpu_device::SHRA_BYTE(UINT8 c) +{ + while (c--) + { + m_CarryVal = m_dst & 0x01; + m_dst = ((INT8) m_dst) >> 1; + } + + set_SZPF_Byte(m_dst); + PutbackRMByte(m_dst); +} + +inline void i8086_common_cpu_device::SHRA_WORD(UINT8 c) +{ + while (c--) + { + m_CarryVal = m_dst & 0x01; + m_dst = ((INT16) m_dst) >> 1; + } + + set_SZPF_Word(m_dst); + PutbackRMWord(m_dst); +} + + +inline void i8086_common_cpu_device::XchgAXReg(UINT8 reg) +{ + UINT16 tmp = m_regs.w[reg]; + + m_regs.w[reg] = m_regs.w[AX]; + m_regs.w[AX] = tmp; +} + + +inline void i8086_common_cpu_device::IncWordReg(UINT8 reg) +{ + UINT32 tmp = m_regs.w[reg]; + UINT32 tmp1 = tmp+1; + + m_OverVal = (tmp == 0x7fff); + set_AF(tmp1,tmp,1); + set_SZPF_Word(tmp1); + m_regs.w[reg] = tmp1; +} + + +inline void i8086_common_cpu_device::DecWordReg(UINT8 reg) +{ + UINT32 tmp = m_regs.w[reg]; + UINT32 tmp1 = tmp-1; + + m_OverVal = (tmp == 0x8000); + set_AF(tmp1,tmp,1); + set_SZPF_Word(tmp1); + m_regs.w[reg] = tmp1; +} + + +inline void i8086_common_cpu_device::PUSH(UINT16 data) +{ + write_word(calc_addr(SS, m_regs.w[SP] - 2, 2, I8086_WRITE, false), data); + m_regs.w[SP] -= 2; +} + + +inline UINT16 i8086_common_cpu_device::POP() +{ + UINT16 data = read_word(calc_addr(SS, m_regs.w[SP], 2, I8086_READ, false)); + + m_regs.w[SP] += 2; + return data; +} + + +inline void i8086_common_cpu_device::JMP(bool cond) +{ + int rel = (int)((INT8)fetch()); + + if (cond) + { + m_ip += rel; + CLK(JCC_T); + } + else + CLK(JCC_NT); +} + + +inline void i8086_common_cpu_device::ADJ4(INT8 param1,INT8 param2) +{ + if (AF || ((m_regs.b[AL] & 0xf) > 9)) + { + UINT16 tmp; + tmp = m_regs.b[AL] + param1; + m_regs.b[AL] = tmp; + m_AuxVal = 1; + m_CarryVal |= tmp & 0x100; + } + if (CF || (m_regs.b[AL]>0x9f)) + { + m_regs.b[AL] += param2; + m_CarryVal = 1; + } + set_SZPF_Byte(m_regs.b[AL]); +} + + +inline void i8086_common_cpu_device::ADJB(INT8 param1, INT8 param2) +{ + if (AF || ((m_regs.b[AL] & 0xf) > 9)) + { + m_regs.b[AL] += param1; + m_regs.b[AH] += param2; + m_AuxVal = 1; + m_CarryVal = 1; + } + else + { + m_AuxVal = 0; + m_CarryVal = 0; + } + m_regs.b[AL] &= 0x0F; +} diff --git a/src/devices/cpu/i860/i860.c b/src/devices/cpu/i860/i860.c new file mode 100644 index 00000000000..5023fa65c60 --- /dev/null +++ b/src/devices/cpu/i860/i860.c @@ -0,0 +1,237 @@ +// license:BSD-3-Clause +// copyright-holders:Jason Eckhardt +/*************************************************************************** + + i860.c + + Interface file for the Intel i860 emulator. + + Copyright (C) 1995-present Jason Eckhardt (jle@rice.edu) + +***************************************************************************/ + +/* +TODO: Separate out i860XR and i860XP (make different types, etc). + Hook IRQ lines into MAME core (they're custom functions atm). +*/ + +#include "emu.h" +#include "debugger.h" +#include "i860.h" + + +/* Control register numbers. */ +enum { + CR_FIR = 0, + CR_PSR = 1, + CR_DIRBASE = 2, + CR_DB = 3, + CR_FSR = 4, + CR_EPSR = 5 +}; + + +const device_type I860 = &device_creator; + + +i860_cpu_device::i860_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : cpu_device(mconfig, I860, "i860XR", tag, owner, clock, "i860xr", __FILE__) + , m_program_config("program", ENDIANNESS_LITTLE, 64, 32, 0) +{ +} + + +void i860_cpu_device::device_start() +{ + m_program = &space(AS_PROGRAM); + reset_i860(); + i860_set_pin(DEC_PIN_BUS_HOLD, 0); + i860_set_pin(DEC_PIN_RESET, 0); + m_single_stepping = 0; + + save_item(NAME(m_iregs)); + save_item(NAME(m_cregs)); + save_item(NAME(m_frg)); + save_item(NAME(m_pc)); + + state_add( I860_PC, "PC", m_pc).formatstr("%08X"); + state_add( I860_FIR, "FIR", m_cregs[CR_FIR]).formatstr("%08X"); + state_add( I860_PSR, "PSR", m_cregs[CR_PSR]).formatstr("%08X"); + state_add( I860_DIRBASE, "DIRBASE", m_cregs[CR_DIRBASE]).formatstr("%08X"); + state_add( I860_DB, "DB", m_cregs[CR_DB]).formatstr("%08X"); + state_add( I860_FSR, "FSR", m_cregs[CR_FSR]).formatstr("%08X"); + state_add( I860_EPSR, "EPSR", m_cregs[CR_EPSR]).formatstr("%08X"); + state_add( I860_R0, "R0", m_iregs[0]).formatstr("%08X"); + state_add( I860_R1, "R1", m_iregs[1]).formatstr("%08X"); + state_add( I860_R2, "R2", m_iregs[2]).formatstr("%08X"); + state_add( I860_R3, "R3", m_iregs[3]).formatstr("%08X"); + state_add( I860_R4, "R4", m_iregs[4]).formatstr("%08X"); + state_add( I860_R5, "R5", m_iregs[5]).formatstr("%08X"); + state_add( I860_R6, "R6", m_iregs[6]).formatstr("%08X"); + state_add( I860_R7, "R7", m_iregs[7]).formatstr("%08X"); + state_add( I860_R8, "R8", m_iregs[8]).formatstr("%08X"); + state_add( I860_R9, "R9", m_iregs[9]).formatstr("%08X"); + state_add( I860_R10, "R10", m_iregs[10]).formatstr("%08X"); + state_add( I860_R11, "R11", m_iregs[11]).formatstr("%08X"); + state_add( I860_R12, "R12", m_iregs[12]).formatstr("%08X"); + state_add( I860_R13, "R13", m_iregs[13]).formatstr("%08X"); + state_add( I860_R14, "R14", m_iregs[14]).formatstr("%08X"); + state_add( I860_R15, "R15", m_iregs[15]).formatstr("%08X"); + state_add( I860_R16, "R16", m_iregs[16]).formatstr("%08X"); + state_add( I860_R17, "R17", m_iregs[17]).formatstr("%08X"); + state_add( I860_R18, "R18", m_iregs[18]).formatstr("%08X"); + state_add( I860_R19, "R19", m_iregs[19]).formatstr("%08X"); + state_add( I860_R20, "R20", m_iregs[20]).formatstr("%08X"); + state_add( I860_R21, "R21", m_iregs[21]).formatstr("%08X"); + state_add( I860_R22, "R22", m_iregs[22]).formatstr("%08X"); + state_add( I860_R23, "R23", m_iregs[23]).formatstr("%08X"); + state_add( I860_R24, "R24", m_iregs[24]).formatstr("%08X"); + state_add( I860_R25, "R25", m_iregs[25]).formatstr("%08X"); + state_add( I860_R26, "R26", m_iregs[26]).formatstr("%08X"); + state_add( I860_R27, "R27", m_iregs[27]).formatstr("%08X"); + state_add( I860_R28, "R28", m_iregs[28]).formatstr("%08X"); + state_add( I860_R29, "R29", m_iregs[29]).formatstr("%08X"); + state_add( I860_R30, "R30", m_iregs[30]).formatstr("%08X"); + state_add( I860_R31, "R31", m_iregs[31]).formatstr("%08X"); + + state_add( I860_F0, "F0", m_freg[0]).callimport().callexport().formatstr("%08X"); + state_add( I860_F1, "F1", m_freg[1]).callimport().callexport().formatstr("%08X"); + state_add( I860_F2, "F2", m_freg[2]).callimport().callexport().formatstr("%08X"); + state_add( I860_F3, "F3", m_freg[3]).callimport().callexport().formatstr("%08X"); + state_add( I860_F4, "F4", m_freg[4]).callimport().callexport().formatstr("%08X"); + state_add( I860_F5, "F5", m_freg[5]).callimport().callexport().formatstr("%08X"); + state_add( I860_F6, "F6", m_freg[6]).callimport().callexport().formatstr("%08X"); + state_add( I860_F7, "F7", m_freg[7]).callimport().callexport().formatstr("%08X"); + state_add( I860_F8, "F8", m_freg[8]).callimport().callexport().formatstr("%08X"); + state_add( I860_F9, "F9", m_freg[9]).callimport().callexport().formatstr("%08X"); + state_add( I860_F10, "F10", m_freg[10]).callimport().callexport().formatstr("%08X"); + state_add( I860_F11, "F11", m_freg[11]).callimport().callexport().formatstr("%08X"); + state_add( I860_F12, "F12", m_freg[12]).callimport().callexport().formatstr("%08X"); + state_add( I860_F13, "F13", m_freg[13]).callimport().callexport().formatstr("%08X"); + state_add( I860_F14, "F14", m_freg[14]).callimport().callexport().formatstr("%08X"); + state_add( I860_F15, "F15", m_freg[15]).callimport().callexport().formatstr("%08X"); + state_add( I860_F16, "F16", m_freg[16]).callimport().callexport().formatstr("%08X"); + state_add( I860_F17, "F17", m_freg[17]).callimport().callexport().formatstr("%08X"); + state_add( I860_F18, "F18", m_freg[18]).callimport().callexport().formatstr("%08X"); + state_add( I860_F19, "F19", m_freg[19]).callimport().callexport().formatstr("%08X"); + state_add( I860_F20, "F20", m_freg[20]).callimport().callexport().formatstr("%08X"); + state_add( I860_F21, "F21", m_freg[21]).callimport().callexport().formatstr("%08X"); + state_add( I860_F22, "F22", m_freg[22]).callimport().callexport().formatstr("%08X"); + state_add( I860_F23, "F23", m_freg[23]).callimport().callexport().formatstr("%08X"); + state_add( I860_F24, "F24", m_freg[24]).callimport().callexport().formatstr("%08X"); + state_add( I860_F25, "F25", m_freg[25]).callimport().callexport().formatstr("%08X"); + state_add( I860_F26, "F26", m_freg[26]).callimport().callexport().formatstr("%08X"); + state_add( I860_F27, "F27", m_freg[27]).callimport().callexport().formatstr("%08X"); + state_add( I860_F28, "F28", m_freg[28]).callimport().callexport().formatstr("%08X"); + state_add( I860_F29, "F29", m_freg[29]).callimport().callexport().formatstr("%08X"); + state_add( I860_F30, "F30", m_freg[30]).callimport().callexport().formatstr("%08X"); + state_add( I860_F31, "F31", m_freg[31]).callimport().callexport().formatstr("%08X"); + + state_add(STATE_GENPC, "curpc", m_pc).noshow(); + + m_icountptr = &m_icount; +} + + +void i860_cpu_device::state_import(const device_state_entry &entry) +{ +#define I860_SET_INFO_F(fnum) m_frg[0+(4*fnum)] = (m_freg[fnum] & 0x000000ff); \ + m_frg[1+(4*fnum)] = (m_freg[fnum] & 0x0000ff00) >> 8; \ + m_frg[2+(4*fnum)] = (m_freg[fnum] & 0x00ff0000) >> 16; \ + m_frg[3+(4*fnum)] = (m_freg[fnum] & 0xff000000) >> 24; + + switch (entry.index()) + { + case I860_F0: I860_SET_INFO_F(0); break; + case I860_F1: I860_SET_INFO_F(1); break; + case I860_F2: I860_SET_INFO_F(2); break; + case I860_F3: I860_SET_INFO_F(3); break; + case I860_F4: I860_SET_INFO_F(4); break; + case I860_F5: I860_SET_INFO_F(5); break; + case I860_F6: I860_SET_INFO_F(6); break; + case I860_F7: I860_SET_INFO_F(7); break; + case I860_F8: I860_SET_INFO_F(8); break; + case I860_F9: I860_SET_INFO_F(9); break; + case I860_F10: I860_SET_INFO_F(10); break; + case I860_F11: I860_SET_INFO_F(11); break; + case I860_F12: I860_SET_INFO_F(12); break; + case I860_F13: I860_SET_INFO_F(13); break; + case I860_F14: I860_SET_INFO_F(14); break; + case I860_F15: I860_SET_INFO_F(15); break; + case I860_F16: I860_SET_INFO_F(16); break; + case I860_F17: I860_SET_INFO_F(17); break; + case I860_F18: I860_SET_INFO_F(18); break; + case I860_F19: I860_SET_INFO_F(19); break; + case I860_F20: I860_SET_INFO_F(20); break; + case I860_F21: I860_SET_INFO_F(21); break; + case I860_F22: I860_SET_INFO_F(22); break; + case I860_F23: I860_SET_INFO_F(23); break; + case I860_F24: I860_SET_INFO_F(24); break; + case I860_F25: I860_SET_INFO_F(25); break; + case I860_F26: I860_SET_INFO_F(26); break; + case I860_F27: I860_SET_INFO_F(27); break; + case I860_F28: I860_SET_INFO_F(28); break; + case I860_F29: I860_SET_INFO_F(29); break; + case I860_F30: I860_SET_INFO_F(30); break; + case I860_F31: I860_SET_INFO_F(31); break; + } +} + +void i860_cpu_device::state_export(const device_state_entry &entry) +{ +#define I860_GET_INFO_F(fnum) m_freg[fnum] = m_frg[0+(4*fnum)] | ( m_frg[1+(4*fnum)] << 8 ) | ( m_frg[2+(4*fnum)] << 16 ) | ( m_frg[3+(4*fnum)] << 24) + + switch (entry.index()) + { + case I860_F0: I860_GET_INFO_F(0); break; + case I860_F1: I860_GET_INFO_F(1); break; + case I860_F2: I860_GET_INFO_F(2); break; + case I860_F3: I860_GET_INFO_F(3); break; + case I860_F4: I860_GET_INFO_F(4); break; + case I860_F5: I860_GET_INFO_F(5); break; + case I860_F6: I860_GET_INFO_F(6); break; + case I860_F7: I860_GET_INFO_F(7); break; + case I860_F8: I860_GET_INFO_F(8); break; + case I860_F9: I860_GET_INFO_F(9); break; + case I860_F10: I860_GET_INFO_F(10); break; + case I860_F11: I860_GET_INFO_F(11); break; + case I860_F12: I860_GET_INFO_F(12); break; + case I860_F13: I860_GET_INFO_F(13); break; + case I860_F14: I860_GET_INFO_F(14); break; + case I860_F15: I860_GET_INFO_F(15); break; + case I860_F16: I860_GET_INFO_F(16); break; + case I860_F17: I860_GET_INFO_F(17); break; + case I860_F18: I860_GET_INFO_F(18); break; + case I860_F19: I860_GET_INFO_F(19); break; + case I860_F20: I860_GET_INFO_F(20); break; + case I860_F21: I860_GET_INFO_F(21); break; + case I860_F22: I860_GET_INFO_F(22); break; + case I860_F23: I860_GET_INFO_F(23); break; + case I860_F24: I860_GET_INFO_F(24); break; + case I860_F25: I860_GET_INFO_F(25); break; + case I860_F26: I860_GET_INFO_F(26); break; + case I860_F27: I860_GET_INFO_F(27); break; + case I860_F28: I860_GET_INFO_F(28); break; + case I860_F29: I860_GET_INFO_F(29); break; + case I860_F30: I860_GET_INFO_F(30); break; + case I860_F31: I860_GET_INFO_F(31); break; + } +} + +void i860_cpu_device::device_reset() +{ + reset_i860(); +} + + +offs_t i860_cpu_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( i860 ); + return CPU_DISASSEMBLE_NAME(i860)(this, buffer, pc, oprom, opram, options); +} + + +/************************************************************************** + * The actual decode and execute code. + **************************************************************************/ +#include "i860dec.inc" diff --git a/src/devices/cpu/i860/i860.h b/src/devices/cpu/i860/i860.h new file mode 100644 index 00000000000..1079d46b479 --- /dev/null +++ b/src/devices/cpu/i860/i860.h @@ -0,0 +1,318 @@ +// license:BSD-3-Clause +// copyright-holders:Jason Eckhardt +/*************************************************************************** + + i860.h + + Interface file for the Intel i860 emulator. + + Copyright (C) 1995-present Jason Eckhardt (jle@rice.edu) + +***************************************************************************/ + +#pragma once + +#ifndef __I860_H__ +#define __I860_H__ + + +/*************************************************************************** + REGISTER ENUMERATION +***************************************************************************/ + +enum +{ + I860_PC = 1, + + I860_FIR, + I860_PSR, + I860_DIRBASE, + I860_DB, + I860_FSR, + I860_EPSR, + + I860_R0, I860_R1, I860_R2, I860_R3, I860_R4, I860_R5, I860_R6, I860_R7, I860_R8, I860_R9, + I860_R10, I860_R11, I860_R12, I860_R13, I860_R14, I860_R15, I860_R16, I860_R17, I860_R18, I860_R19, + I860_R20, I860_R21, I860_R22, I860_R23, I860_R24, I860_R25, I860_R26, I860_R27, I860_R28, I860_R29, + I860_R30, I860_R31, + + I860_F0, I860_F1, I860_F2, I860_F3, I860_F4, I860_F5, I860_F6, I860_F7, I860_F8, I860_F9, + I860_F10, I860_F11, I860_F12, I860_F13, I860_F14, I860_F15, I860_F16, I860_F17, I860_F18, I860_F19, + I860_F20, I860_F21, I860_F22, I860_F23, I860_F24, I860_F25, I860_F26, I860_F27, I860_F28, I860_F29, + I860_F30, I860_F31 + +}; + + +class i860_cpu_device : public cpu_device +{ +public: + // construction/destruction + i860_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + /* This is the external interface for asserting an external interrupt + to the i860. */ + void i860_gen_interrupt(); + + /* This is the external interface for asserting/deasserting a pin on + the i860. */ + void i860_set_pin(int, int); + + /* Hard or soft reset. */ + void reset_i860(); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_execute_interface overrides + virtual UINT32 execute_min_cycles() const { return 1; } + virtual UINT32 execute_max_cycles() const { return 8; } + virtual UINT32 execute_input_lines() const { return 0; } + virtual void execute_run(); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const { return (spacenum == AS_PROGRAM) ? &m_program_config : NULL; } + + // device_state_interface overrides + void state_export(const device_state_entry &entry); + void state_import(const device_state_entry &entry); + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const { return 4; } + virtual UINT32 disasm_max_opcode_bytes() const { return 4; } + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + +private: + address_space_config m_program_config; + + /* Integer registers (32 x 32-bits). */ + UINT32 m_iregs[32]; + + /* Floating point registers (32 x 32-bits, 16 x 64 bits, or 8 x 128 bits). + When referenced as pairs or quads, the higher numbered registers + are the upper bits. E.g., double precision f0 is f1:f0. */ + UINT8 m_frg[32 * 4]; + + /* Control registers (6 x 32-bits). */ + UINT32 m_cregs[6]; + + /* Program counter (1 x 32-bits). Reset starts at pc=0xffffff00. */ + UINT32 m_pc; + + /* Special registers (4 x 64-bits). */ + union + { + float s; + double d; + } m_KR, m_KI, m_T; + UINT64 m_merge; + + /* The adder pipeline, always 3 stages. */ + struct + { + /* The stage contents. */ + union { + float s; + double d; + } val; + + /* The stage status bits. */ + struct { + /* Adder result precision (1 = dbl, 0 = sgl). */ + char arp; + } stat; + } m_A[3]; + + /* The multiplier pipeline. 3 stages for single precision, 2 stages + for double precision, and confusing for mixed precision. */ + struct { + /* The stage contents. */ + union { + float s; + double d; + } val; + + /* The stage status bits. */ + struct { + /* Multiplier result precision (1 = dbl, 0 = sgl). */ + char mrp; + } stat; + } m_M[3]; + + /* The load pipeline, always 3 stages. */ + struct { + /* The stage contents. */ + union { + float s; + double d; + } val; + + /* The stage status bits. */ + struct { + /* Load result precision (1 = dbl, 0 = sgl). */ + char lrp; + } stat; + } m_L[3]; + + /* The graphics/integer pipeline, always 1 stage. */ + struct { + /* The stage contents. */ + union { + float s; + double d; + } val; + + /* The stage status bits. */ + struct { + /* Integer/graphics result precision (1 = dbl, 0 = sgl). */ + char irp; + } stat; + } m_G; + + /* Pins. */ + int m_pin_bus_hold; + int m_pin_reset; + + /* + * Other emulator state. + */ + int m_exiting_readmem; + int m_exiting_ifetch; + + /* Indicate a control-flow instruction, so we know the PC is updated. */ + int m_pc_updated; + + /* Indicate an instruction just generated a trap, so we know the PC + needs to go to the trap address. */ + int m_pending_trap; + + /* This is 1 if the next fir load gets the trap address, otherwise + it is 0 to get the ld.c address. This is set to 1 only when a + non-reset trap occurs. */ + int m_fir_gets_trap_addr; + + /* Single stepping flag for internal use. */ + int m_single_stepping; + + /* + * MAME-specific stuff. + */ + address_space *m_program; + UINT32 m_ppc; + int m_icount; + // For debugger + UINT32 m_freg[32]; + + void writememi_emu (UINT32 addr, int size, UINT32 data); + void fp_readmem_emu (UINT32 addr, int size, UINT8 *dest); + void fp_writemem_emu (UINT32 addr, int size, UINT8 *data, UINT32 wmask); + void dump_pipe (int type); + void dump_state (); + void unrecog_opcode (UINT32 pc, UINT32 insn); + void insn_ld_ctrl (UINT32 insn); + void insn_st_ctrl (UINT32 insn); + void insn_ldx (UINT32 insn); + void insn_stx (UINT32 insn); + void insn_fsty (UINT32 insn); + void insn_fldy (UINT32 insn); + void insn_pstd (UINT32 insn); + void insn_ixfr (UINT32 insn); + void insn_addu (UINT32 insn); + void insn_addu_imm (UINT32 insn); + void insn_adds (UINT32 insn); + void insn_adds_imm (UINT32 insn); + void insn_subu (UINT32 insn); + void insn_subu_imm (UINT32 insn); + void insn_subs (UINT32 insn); + void insn_subs_imm (UINT32 insn); + void insn_shl (UINT32 insn); + void insn_shl_imm (UINT32 insn); + void insn_shr (UINT32 insn); + void insn_shr_imm (UINT32 insn); + void insn_shra (UINT32 insn); + void insn_shra_imm (UINT32 insn); + void insn_shrd (UINT32 insn); + void insn_and (UINT32 insn); + void insn_and_imm (UINT32 insn); + void insn_andh_imm (UINT32 insn); + void insn_andnot (UINT32 insn); + void insn_andnot_imm (UINT32 insn); + void insn_andnoth_imm (UINT32 insn); + void insn_or (UINT32 insn); + void insn_or_imm (UINT32 insn); + void insn_orh_imm (UINT32 insn); + void insn_xor (UINT32 insn); + void insn_xor_imm (UINT32 insn); + void insn_xorh_imm (UINT32 insn); + void insn_trap (UINT32 insn); + void insn_intovr (UINT32 insn); + void insn_bte (UINT32 insn); + void insn_bte_imm (UINT32 insn); + void insn_btne (UINT32 insn); + void insn_btne_imm (UINT32 insn); + void insn_bc (UINT32 insn); + void insn_bnc (UINT32 insn); + void insn_bct (UINT32 insn); + void insn_bnct (UINT32 insn); + void insn_call (UINT32 insn); + void insn_br (UINT32 insn); + void insn_bri (UINT32 insn); + void insn_calli (UINT32 insn); + void insn_bla (UINT32 insn); + void insn_flush (UINT32 insn); + void insn_fmul (UINT32 insn); + void insn_fmlow (UINT32 insn); + void insn_fadd_sub (UINT32 insn); + void insn_dualop (UINT32 insn); + void insn_frcp (UINT32 insn); + void insn_frsqr (UINT32 insn); + void insn_fxfr (UINT32 insn); + void insn_ftrunc (UINT32 insn); + void insn_famov (UINT32 insn); + void insn_fiadd_sub (UINT32 insn); + void insn_fcmp (UINT32 insn); + void insn_fzchk (UINT32 insn); + void insn_form (UINT32 insn); + void insn_faddp (UINT32 insn); + void insn_faddz (UINT32 insn); + void decode_exec (UINT32 insn, UINT32 non_shadow); + void disasm (UINT32 addr, int len); + void dbg_db (UINT32 addr, int len); + float get_fregval_s (int fr); + double get_fregval_d (int fr); + void set_fregval_s (int fr, float s); + void set_fregval_d (int fr, double d); + int has_delay_slot(UINT32 insn); + UINT32 ifetch (UINT32 pc); + UINT32 get_address_translation (UINT32 vaddr, int is_dataref, int is_write); + UINT32 readmemi_emu (UINT32 addr, int size); + float get_fval_from_optype_s (UINT32 insn, int optype); + double get_fval_from_optype_d (UINT32 insn, int optype); + + typedef void (i860_cpu_device::*insn_func)(UINT32); + struct decode_tbl_t + { + /* Execute function for this opcode. */ + insn_func insn_exec; + /* Flags for this opcode. */ + char flags; + }; + static const decode_tbl_t decode_tbl[64]; + static const decode_tbl_t core_esc_decode_tbl[8]; + static const decode_tbl_t fp_decode_tbl[128]; +}; + + +/* i860 pins. */ +enum { + DEC_PIN_BUS_HOLD, /* Bus HOLD pin. */ + DEC_PIN_RESET /* System reset pin. */ +}; + + +extern const device_type I860; + + +#endif /* __I860_H__ */ diff --git a/src/devices/cpu/i860/i860dasm.c b/src/devices/cpu/i860/i860dasm.c new file mode 100644 index 00000000000..60c83a5fec0 --- /dev/null +++ b/src/devices/cpu/i860/i860dasm.c @@ -0,0 +1,378 @@ +// license:BSD-3-Clause +// copyright-holders:Jason Eckhardt +#include "i860.h" + +/* Sub-group decoders */ +static void i860_dasm_core_dasm(const UINT32 op, char* buffer); +static void i860_dasm_floating_point_dasm(const UINT32 op, char* buffer); +static void i860_dasm_CTRL_dasm(const UINT32 op, char* buffer); + +/* REG-Format Opcodes*/ +static void i860_dasm_ldx(const UINT32 op, char* buffer); +static void i860_dasm_stx(const UINT32 op, char* buffer); +static void i860_dasm_ixfr(const UINT32 op, char* buffer); +static void i860_dasm_fid_fst(const UINT32 op, char* buffer); +static void i860_dasm_flush(const UINT32 op, char* buffer); +static void i860_dasm_pstd(const UINT32 op, char* buffer); +static void i860_dasm_ldc_sdc(const UINT32 op, char* buffer); +static void i860_dasm_bri(const UINT32 op, char* buffer); +static void i860_dasm_trap(const UINT32 op, char* buffer); +static void i860_dasm_bte_btne(const UINT32 op, char* buffer); +static void i860_dasm_pfidy(const UINT32 op, char* buffer); +static void i860_dasm_addu_subu(const UINT32 op, char* buffer); +static void i860_dasm_shl_shr(const UINT32 op, char* buffer); +static void i860_dasm_shrd(const UINT32 op, char* buffer); +static void i860_dasm_bla(const UINT32 op, char* buffer); +static void i860_dasm_shra(const UINT32 op, char* buffer); +static void i860_dasm_and_andh(const UINT32 op, char* buffer); +static void i860_dasm_andnot_andnoth(const UINT32 op, char* buffer); +static void i860_dasm_or_orh(const UINT32 op, char* buffer); +static void i860_dasm_xor_xorh(const UINT32 op, char* buffer); + +/* CORE Escape Opcodes */ +static void i860_dasm_CORE_lock(const UINT32 op, char* buffer); +static void i860_dasm_CORE_calli(const UINT32 op, char* buffer); +static void i860_dasm_CORE_intovr(const UINT32 op, char* buffer); +static void i860_dasm_CORE_unlock(const UINT32 op, char* buffer); + +/* CTRL-Format Opcodes */ +static void i860_dasm_CTRL_br(const UINT32 op, char* buffer); +static void i860_dasm_CTRL_call(const UINT32 op, char* buffer); +static void i860_dasm_CTRL_bc_bct(const UINT32 op, char* buffer); +static void i860_dasm_CTRL_bnc_bnct(const UINT32 op, char* buffer); + +/* Floating-Point Instructions */ + + +CPU_DISASSEMBLE( i860 ) +{ + char tempB[1024] = ""; + + /* Little Endian */ + const UINT32 op = (oprom[3] << 24) | (oprom[2] << 16) | (oprom[1] << 8) | (oprom[0] << 0); + //const UINT32 op = (oprom[2] << 24) | (oprom[3] << 16) | (oprom[0] << 8) | (oprom[1] << 0); /* Mixed Endian */ + //const UINT32 op = (oprom[0] << 24) | (oprom[1] << 16) | (oprom[2] << 8) | (oprom[3] << 0); /* Big Endian */ + //const UINT32 op = (oprom[1] << 24) | (oprom[0] << 16) | (oprom[3] << 8) | (oprom[2] << 0); /* Mixed Endian */ + + /* The opcode is the top 6 bits */ + UINT8 opcode = (op >> 26) & 0x3f; + + /* DEBUG - print this out if you feel things are going a bit wonky */ + // sprintf(buffer, "%08x : oo %02x", op, opcode); + + /* Main decode */ + switch (opcode) + { + case 0x00: + case 0x01: + case 0x04: + case 0x05: i860_dasm_ldx(op, tempB); break; + + case 0x03: + case 0x07: i860_dasm_stx(op, tempB); break; + + case 0x02: i860_dasm_ixfr(op, tempB); break; + + case 0x06: sprintf(tempB, "(reserved)"); break; + + case 0x08: + case 0x09: + case 0x0a: + case 0x0b: i860_dasm_fid_fst(op, tempB); break; + + case 0x0d: i860_dasm_flush(op, tempB); break; + + case 0x0f: i860_dasm_pstd(op, tempB); break; + + case 0x0c: + case 0x0e: i860_dasm_ldc_sdc(op, tempB); break; + + case 0x10: i860_dasm_bri(op, tempB); break; + + case 0x11: i860_dasm_trap(op, tempB); break; + + case 0x12: i860_dasm_floating_point_dasm(op, tempB); break; /* Floating point operation sub-group */ + + case 0x13: i860_dasm_core_dasm(op, tempB); break; /* Core operation sub-group */ + + case 0x14: + case 0x15: + case 0x16: + case 0x17: i860_dasm_bte_btne(op, tempB); break; + + case 0x18: + case 0x19: i860_dasm_pfidy(op, tempB); break; + + case 0x1a: + case 0x1b: + case 0x1c: + case 0x1d: + case 0x1e: + case 0x1f: i860_dasm_CTRL_dasm(op, tempB); break; /* CTRL operation sub-group */ + + case 0x20: + case 0x21: + case 0x22: + case 0x23: + case 0x24: + case 0x25: + case 0x26: + case 0x27: i860_dasm_addu_subu(op, tempB); break; + + case 0x28: + case 0x29: + case 0x2a: + case 0x2b: i860_dasm_shl_shr(op, tempB); break; + + case 0x2c: i860_dasm_shrd(op, tempB); break; + + case 0x2d: i860_dasm_bla(op, tempB); break; + + case 0x2e: + case 0x2f: i860_dasm_shra(op, tempB); break; + + case 0x30: + case 0x31: + case 0x32: + case 0x33: i860_dasm_and_andh(op, tempB); break; + + case 0x34: + case 0x35: + case 0x36: + case 0x37: i860_dasm_andnot_andnoth(op, tempB); break; + + case 0x38: + case 0x39: + case 0x3a: + case 0x3b: i860_dasm_or_orh(op, tempB); break; + + case 0x3c: + case 0x3d: + case 0x3e: + case 0x3f: i860_dasm_xor_xorh(op, tempB); break; + + default: sprintf(tempB, "(reserved)"); break; + } + + /* More Debug */ + //strcat(buffer, " : "); + //strcat(buffer, tempB); + sprintf(buffer, "%s", tempB); + + /* All opcodes are 32 bits */ + return (4 | DASMFLAG_SUPPORTED); +} + + +// BIT HELPER +// 31 27 23 19 15 11 7 3 +// 0000 0011 1111 1111 0000 0111 1110 0000 + + +/**********************/ +/* Sub-group decoders */ +/**********************/ +static void i860_dasm_core_dasm(const UINT32 op, char* buffer) +{ + //UINT8 src1 = (op >> 11) & 0x0000001f; + + /* Reserved bits must be set to 0 */ + if ( (op & 0x000007e0) || (op & 0x03ff0000) ) + { + //logerror("[i860] Reserved CORE bits must be set to 0."); + printf("CORE baddie\n"); + } + + switch(op & 0x0000001f) + { + case 0x01: i860_dasm_CORE_lock(op, buffer); break; + case 0x02: i860_dasm_CORE_calli(op, buffer); break; + case 0x04: i860_dasm_CORE_intovr(op, buffer); break; + case 0x07: i860_dasm_CORE_unlock(op, buffer); break; + + default: sprintf(buffer, "(reserved)"); break; + } +} + +static void i860_dasm_floating_point_dasm(const UINT32 op, char* buffer) +{ + sprintf(buffer, "[[F-P unit]]"); +} + +static void i860_dasm_CTRL_dasm(const UINT32 op, char* buffer) +{ + UINT8 opc = (op >> 26) & 0x07; + + switch(opc) + { + case 0x02: i860_dasm_CTRL_br(op, buffer); break; + case 0x03: i860_dasm_CTRL_call(op, buffer); break; + case 0x04: case 0x05: i860_dasm_CTRL_bc_bct(op, buffer); break; + case 0x06: case 0x07: i860_dasm_CTRL_bnc_bnct(op, buffer); break; + + default: sprintf(buffer, "(reserved)"); break; + } +} + + +/*********************/ +/* REG-Format Opcodes*/ +/*********************/ +static void i860_dasm_ldx(const UINT32 op, char* buffer) +{ + sprintf(buffer, "ldx"); +} + +static void i860_dasm_stx(const UINT32 op, char* buffer) +{ + sprintf(buffer, "stx"); +} + +static void i860_dasm_ixfr(const UINT32 op, char* buffer) +{ +// UINT16 val = op & 0x7ff; +// UINT8 opc = (op >> 26) & 0x3f; +// UINT8 src2 = (op >> 21) & 0x1f; +// UINT8 dest = (op >> 16) & 0x1f; +// UINT8 src1 = (op >> 11) & 0x1f; + + sprintf(buffer, "ixfr"); +} + +static void i860_dasm_fid_fst(const UINT32 op, char* buffer) +{ + sprintf(buffer, "fst"); +} + +static void i860_dasm_flush(const UINT32 op, char* buffer) +{ + sprintf(buffer, "flush"); +} + +static void i860_dasm_pstd(const UINT32 op, char* buffer) +{ + sprintf(buffer, "pstd"); +} + +static void i860_dasm_ldc_sdc(const UINT32 op, char* buffer) +{ + sprintf(buffer, "ldc, sdc"); +} + +static void i860_dasm_bri(const UINT32 op, char* buffer) +{ + sprintf(buffer, "bri"); +} + +static void i860_dasm_trap(const UINT32 op, char* buffer) +{ + sprintf(buffer, "trap"); +} + +static void i860_dasm_bte_btne(const UINT32 op, char* buffer) +{ + sprintf(buffer, "bte, btne"); +} + +static void i860_dasm_pfidy(const UINT32 op, char* buffer) +{ + sprintf(buffer, "pfidy"); +} + +static void i860_dasm_addu_subu(const UINT32 op, char* buffer) +{ + sprintf(buffer, "addu, subu"); +} + +static void i860_dasm_shl_shr(const UINT32 op, char* buffer) +{ + sprintf(buffer, "shl, shr"); +} + +static void i860_dasm_shrd(const UINT32 op, char* buffer) +{ + sprintf(buffer, "shrd"); +} + +static void i860_dasm_bla(const UINT32 op, char* buffer) +{ + sprintf(buffer, "bla"); +} + +static void i860_dasm_shra(const UINT32 op, char* buffer) +{ + sprintf(buffer, "shra"); +} + +static void i860_dasm_and_andh(const UINT32 op, char* buffer) +{ + sprintf(buffer, "and, andh"); +} + +static void i860_dasm_andnot_andnoth(const UINT32 op, char* buffer) +{ + sprintf(buffer, "andnot, andnoth"); +} + +static void i860_dasm_or_orh(const UINT32 op, char* buffer) +{ + sprintf(buffer, "or, orh"); +} + +static void i860_dasm_xor_xorh(const UINT32 op, char* buffer) +{ + sprintf(buffer, "xor, xorh"); +} + + +/***********************/ +/* CORE Escape Opcodes */ +/***********************/ +static void i860_dasm_CORE_lock(const UINT32 op, char* buffer) +{ + sprintf(buffer, "lock"); +} + +static void i860_dasm_CORE_calli(const UINT32 op, char* buffer) +{ + sprintf(buffer, "calli"); +} + +static void i860_dasm_CORE_intovr(const UINT32 op, char* buffer) +{ + sprintf(buffer, "intovr"); +} + +static void i860_dasm_CORE_unlock(const UINT32 op, char* buffer) +{ + sprintf(buffer, "unlock"); +} + + +/***********************/ +/* CTRL-Format Opcodes */ +/***********************/ +static void i860_dasm_CTRL_br(const UINT32 op, char* buffer) +{ + sprintf(buffer, "br"); +} + +static void i860_dasm_CTRL_call(const UINT32 op, char* buffer) +{ + sprintf(buffer, "call"); +} + +static void i860_dasm_CTRL_bc_bct(const UINT32 op, char* buffer) +{ + sprintf(buffer, "bct"); +} + +static void i860_dasm_CTRL_bnc_bnct(const UINT32 op, char* buffer) +{ + sprintf(buffer, "bnct"); +} + + +/*******************************/ +/* Floating-Point Instructions */ +/*******************************/ diff --git a/src/devices/cpu/i860/i860dec.inc b/src/devices/cpu/i860/i860dec.inc new file mode 100644 index 00000000000..d0943c9e5a6 --- /dev/null +++ b/src/devices/cpu/i860/i860dec.inc @@ -0,0 +1,4687 @@ +// license:BSD-3-Clause +// copyright-holders:Jason Eckhardt +/*************************************************************************** + + i860dec.inc + + Execution engine for the Intel i860 emulator. + + Copyright (C) 1995-present Jason Eckhardt (jle@rice.edu) + +***************************************************************************/ + +/* + * References: + * `i860 Microprocessor Programmer's Reference Manual', Intel, 1990. + * + * This code was originally written by Jason Eckhardt as part of an + * emulator for some i860-based Unix workstations (early 1990's) such + * as the Stardent Vistra 800 series and the OkiStation/i860 7300 series. + * The code you are reading now is the i860 CPU portion only, which has + * been adapted to (and simplified for) MAME. + * MAME-specific notes: + * - i860XR emulation only (i860XP unnecessary for MAME). + * - No emulation of data and instruction caches (unnecessary for MAME version). + * - No emulation of DIM mode or CS8 mode (unnecessary for MAME version). + * - No BL/IL/locked sequences (unnecessary for MAME). + * - Emulate only the i860's LSB-first mode (BE = 0). + * Generic notes: + * - There is some amount of code duplication (e.g., see the + * various insn_* routines for the branches and FP routines) that + * could be eliminated. + * - The host's floating point types are used to emulate the i860's + * floating point. Should probably be made machine independent by + * using an IEEE FP emulation library. On the other hand, most machines + * today also use IEEE FP. + * + */ +#include "i860.h" +#include + + +#undef HOST_MSB + +#undef TRACE_RDWR_MEM +#undef TRACE_ADDR_TRANSLATION +#undef TRACE_PAGE_FAULT +#define TRACE_UNDEFINED_I860 +#undef TRACE_EXT_INT +#define TRACE_UNALIGNED_MEM + + +/* Defines for pending_trap. */ +enum { + TRAP_NORMAL = 0x01, + TRAP_IN_DELAY_SLOT = 0x02, + TRAP_WAS_EXTERNAL = 0x04 +}; + + +/* TODO: THESE WILL BE REPLACED BY MAME FUNCTIONS +#define BYTE_REV32(t) \ + do { \ + (t) = ((UINT32)(t) >> 16) | ((UINT32)(t) << 16); \ + (t) = (((UINT32)(t) >> 8) & 0x00ff00ff) | (((UINT32)(t) << 8) & 0xff00ff00); \ + } while (0); + +#define BYTE_REV16(t) \ + do { \ + (t) = (((UINT16)(t) >> 8) & 0x00ff) | (((UINT16)(t) << 8) & 0xff00); \ + } while (0); +#endif +*/ + + +/* Get/set general register value -- watch for r0 on writes. */ +#define get_iregval(gr) (m_iregs[(gr)]) +#define set_iregval(gr, val) (m_iregs[(gr)] = ((gr) == 0 ? 0 : (val))) + +float i860_cpu_device::get_fregval_s (int fr) +{ + float f; + UINT32 x; + UINT8 *tp; + fr = 31 - fr; + tp = (UINT8 *)(&m_frg[fr * 4]); + x = ((UINT32)tp[0] << 24) | ((UINT32)tp[1] << 16) | + ((UINT32)tp[2] << 8) | ((UINT32)tp[3]); + f = *(float *)(&x); + return f; +} + +double i860_cpu_device::get_fregval_d (int fr) +{ + double d; + UINT64 x; + UINT8 *tp; + fr = 31 - (fr + 1); + tp = (UINT8 *)(&m_frg[fr * 4]); + x = ((UINT64)tp[0] << 56) | ((UINT64)tp[1] << 48) | + ((UINT64)tp[2] << 40) | ((UINT64)tp[3] << 32) | + ((UINT64)tp[4] << 24) | ((UINT64)tp[5] << 16) | + ((UINT64)tp[6] << 8) | ((UINT64)tp[7]); + d = *(double *)(&x); + return d; +} + +void i860_cpu_device::set_fregval_s (int fr, float s) +{ + UINT8 *f = (UINT8 *)&s; + UINT8 *tp; + int newfr = 31 - fr; + float jj = s; + tp = (UINT8 *)(&m_frg[newfr * 4]); + + f = (UINT8 *)(&jj); + if (fr == 0 || fr == 1) + { + tp[0] = 0; tp[1] = 0; tp[2] = 0; tp[3] = 0; + } + else + { +#ifndef HOST_MSB + tp[0] = f[3]; tp[1] = f[2]; tp[2] = f[1]; tp[3] = f[0]; +#else + tp[0] = f[0]; tp[1] = f[1]; tp[2] = f[2]; tp[3] = f[3]; +#endif + } +} + +void i860_cpu_device::set_fregval_d (int fr, double d) +{ + UINT8 *f = (UINT8 *)&d; + UINT8 *tp; + int newfr = 31 - (fr + 1); + double jj = d; + tp = (UINT8 *)(&m_frg[newfr * 4]); + + f = (UINT8 *)(&jj); + + if (fr == 0) + { + tp[0] = 0; tp[1] = 0; tp[2] = 0; tp[3] = 0; + tp[4] = 0; tp[5] = 0; tp[6] = 0; tp[7] = 0; + } + else + { +#ifndef HOST_MSB + tp[0] = f[7]; tp[1] = f[6]; tp[2] = f[5]; tp[3] = f[4]; + tp[4] = f[3]; tp[5] = f[2]; tp[6] = f[1]; tp[7] = f[0]; +#else + tp[0] = f[0]; tp[1] = f[1]; tp[2] = f[2]; tp[3] = f[3]; + tp[4] = f[4]; tp[5] = f[5]; tp[6] = f[6]; tp[7] = f[7]; +#endif + } +} + + +/* Macros for accessing register fields in instruction word. */ +#define get_isrc1(bits) (((bits) >> 11) & 0x1f) +#define get_isrc2(bits) (((bits) >> 21) & 0x1f) +#define get_idest(bits) (((bits) >> 16) & 0x1f) +#define get_fsrc1(bits) (((bits) >> 11) & 0x1f) +#define get_fsrc2(bits) (((bits) >> 21) & 0x1f) +#define get_fdest(bits) (((bits) >> 16) & 0x1f) +#define get_creg(bits) (((bits) >> 21) & 0x7) + +/* Macros for accessing immediate fields. */ +/* 16-bit immediate. */ +#define get_imm16(insn) ((insn) & 0xffff) + +/* A mask for all the trap bits of the PSR (FT, DAT, IAT, IN, IT, or + bits [12..8]). */ +#define PSR_ALL_TRAP_BITS_MASK 0x00001f00 + +/* A mask for PSR bits which can only be changed from supervisor level. */ +#define PSR_SUPERVISOR_ONLY_MASK 0x0000fff3 + + +/* PSR: BR flag (PSR[0]): set/get. */ +#define GET_PSR_BR() ((m_cregs[CR_PSR] >> 0) & 1) +#define SET_PSR_BR(val) (m_cregs[CR_PSR] = (m_cregs[CR_PSR] & ~(1 << 0)) | (((val) & 1) << 0)) + +/* PSR: BW flag (PSR[1]): set/get. */ +#define GET_PSR_BW() ((m_cregs[CR_PSR] >> 1) & 1) +#define SET_PSR_BW(val) (m_cregs[CR_PSR] = (m_cregs[CR_PSR] & ~(1 << 1)) | (((val) & 1) << 1)) + +/* PSR: Shift count (PSR[21..17]): set/get. */ +#define GET_PSR_SC() ((m_cregs[CR_PSR] >> 17) & 0x1f) +#define SET_PSR_SC(val) (m_cregs[CR_PSR] = (m_cregs[CR_PSR] & ~0x003e0000) | (((val) & 0x1f) << 17)) + +/* PSR: CC flag (PSR[2]): set/get. */ +#define GET_PSR_CC() ((m_cregs[CR_PSR] >> 2) & 1) +#define SET_PSR_CC(val) (m_cregs[CR_PSR] = (m_cregs[CR_PSR] & ~(1 << 2)) | (((val) & 1) << 2)) + +/* PSR: IT flag (PSR[8]): set/get. */ +#define GET_PSR_IT() ((m_cregs[CR_PSR] >> 8) & 1) +#define SET_PSR_IT(val) (m_cregs[CR_PSR] = (m_cregs[CR_PSR] & ~(1 << 8)) | (((val) & 1) << 8)) + +/* PSR: IN flag (PSR[9]): set/get. */ +#define GET_PSR_IN() ((m_cregs[CR_PSR] >> 9) & 1) +#define SET_PSR_IN(val) (m_cregs[CR_PSR] = (m_cregs[CR_PSR] & ~(1 << 9)) | (((val) & 1) << 9)) + +/* PSR: IAT flag (PSR[10]): set/get. */ +#define GET_PSR_IAT() ((m_cregs[CR_PSR] >> 10) & 1) +#define SET_PSR_IAT(val) (m_cregs[CR_PSR] = (m_cregs[CR_PSR] & ~(1 << 10)) | (((val) & 1) << 10)) + +/* PSR: DAT flag (PSR[11]): set/get. */ +#define GET_PSR_DAT() ((m_cregs[CR_PSR] >> 11) & 1) +#define SET_PSR_DAT(val) (m_cregs[CR_PSR] = (m_cregs[CR_PSR] & ~(1 << 11)) | (((val) & 1) << 11)) + +/* PSR: FT flag (PSR[12]): set/get. */ +#define GET_PSR_FT() ((m_cregs[CR_PSR] >> 12) & 1) +#define SET_PSR_FT(val) (m_cregs[CR_PSR] = (m_cregs[CR_PSR] & ~(1 << 12)) | (((val) & 1) << 12)) + +/* PSR: DS flag (PSR[13]): set/get. */ +#define GET_PSR_DS() ((m_cregs[CR_PSR] >> 13) & 1) +#define SET_PSR_DS(val) (m_cregs[CR_PSR] = (m_cregs[CR_PSR] & ~(1 << 13)) | (((val) & 1) << 13)) + +/* PSR: DIM flag (PSR[14]): set/get. */ +#define GET_PSR_DIM() ((m_cregs[CR_PSR] >> 14) & 1) +#define SET_PSR_DIM(val) (m_cregs[CR_PSR] = (m_cregs[CR_PSR] & ~(1 << 14)) | (((val) & 1) << 14)) + +/* PSR: LCC (PSR[3]): set/get. */ +#define GET_PSR_LCC() ((m_cregs[CR_PSR] >> 3) & 1) +#define SET_PSR_LCC(val) (m_cregs[CR_PSR] = (m_cregs[CR_PSR] & ~(1 << 3)) | (((val) & 1) << 3)) + +/* PSR: IM (PSR[4]): set/get. */ +#define GET_PSR_IM() ((m_cregs[CR_PSR] >> 4) & 1) +#define SET_PSR_IM(val) (m_cregs[CR_PSR] = (m_cregs[CR_PSR] & ~(1 << 4)) | (((val) & 1) << 4)) + +/* PSR: PIM (PSR[5]): set/get. */ +#define GET_PSR_PIM() ((m_cregs[CR_PSR] >> 5) & 1) +#define SET_PSR_PIM(val) (m_cregs[CR_PSR] = (m_cregs[CR_PSR] & ~(1 << 5)) | (((val) & 1) << 5)) + +/* PSR: U (PSR[6]): set/get. */ +#define GET_PSR_U() ((m_cregs[CR_PSR] >> 6) & 1) +#define SET_PSR_U(val) (m_cregs[CR_PSR] = (m_cregs[CR_PSR] & ~(1 << 6)) | (((val) & 1) << 6)) + +/* PSR: PU (PSR[7]): set/get. */ +#define GET_PSR_PU() ((m_cregs[CR_PSR] >> 7) & 1) +#define SET_PSR_PU(val) (m_cregs[CR_PSR] = (m_cregs[CR_PSR] & ~(1 << 7)) | (((val) & 1) << 7)) + +/* PSR: Pixel size (PSR[23..22]): set/get. */ +#define GET_PSR_PS() ((m_cregs[CR_PSR] >> 22) & 0x3) +#define SET_PSR_PS(val) (m_cregs[CR_PSR] = (m_cregs[CR_PSR] & ~0x00c00000) | (((val) & 0x3) << 22)) + +/* PSR: Pixel mask (PSR[31..24]): set/get. */ +#define GET_PSR_PM() ((m_cregs[CR_PSR] >> 24) & 0xff) +#define SET_PSR_PM(val) (m_cregs[CR_PSR] = (m_cregs[CR_PSR] & ~0xff000000) | (((val) & 0xff) << 24)) + +/* EPSR: WP bit (EPSR[14]): set/get. */ +#define GET_EPSR_WP() ((m_cregs[CR_EPSR] >> 14) & 1) +#define SET_EPSR_WP(val) (m_cregs[CR_EPSR] = (m_cregs[CR_EPSR] & ~(1 << 14)) | (((val) & 1) << 14)) + +/* EPSR: INT bit (EPSR[17]): set/get. */ +#define GET_EPSR_INT() ((m_cregs[CR_EPSR] >> 17) & 1) +#define SET_EPSR_INT(val) (m_cregs[CR_EPSR] = (m_cregs[CR_EPSR] & ~(1 << 17)) | (((val) & 1) << 17)) + + +/* EPSR: OF flag (EPSR[24]): set/get. */ +#define GET_EPSR_OF() ((m_cregs[CR_EPSR] >> 24) & 1) +#define SET_EPSR_OF(val) (m_cregs[CR_EPSR] = (m_cregs[CR_EPSR] & ~(1 << 24)) | (((val) & 1) << 24)) + +/* EPSR: BE flag (EPSR[23]): set/get. */ +#define GET_EPSR_BE() ((m_cregs[CR_EPSR] >> 23) & 1) +#define SET_EPSR_BE(val) (m_cregs[CR_EPSR] = (m_cregs[CR_EPSR] & ~(1 << 23)) | (((val) & 1) << 23)) + +/* DIRBASE: ATE bit (DIRBASE[0]): get. */ +#define GET_DIRBASE_ATE() (m_cregs[CR_DIRBASE] & 1) + +/* DIRBASE: CS8 bit (DIRBASE[7]): get. */ +#define GET_DIRBASE_CS8() ((m_cregs[CR_DIRBASE] >> 7) & 1) + +/* FSR: FTE bit (FSR[5]): set/get. */ +#define GET_FSR_FTE() ((m_cregs[CR_FSR] >> 5) & 1) +#define SET_FSR_FTE(val) (m_cregs[CR_FSR] = (m_cregs[CR_FSR] & ~(1 << 5)) | (((val) & 1) << 5)) + +/* FSR: SE bit (FSR[8]): set/get. */ +#define GET_FSR_SE() ((m_cregs[CR_FSR] >> 8) & 1) +#define SET_FSR_SE(val) (m_cregs[CR_FSR] = (m_cregs[CR_FSR] & ~(1 << 8)) | (((val) & 1) << 8)) + + +int i860_cpu_device::has_delay_slot(UINT32 insn) +{ + int opc = (insn >> 26) & 0x3f; + if (opc == 0x10 || opc == 0x1a || opc == 0x1b || opc == 0x1d || + opc == 0x1f || opc == 0x2d || (opc == 0x13 && (insn & 3) == 2)) + return 1; + return 0; +} + +/* This is the external interface for asserting/deasserting pins on + the i860. */ +void i860_cpu_device::i860_set_pin (int pin, int val) +{ + if (pin == DEC_PIN_BUS_HOLD) + m_pin_bus_hold = val; + else if (pin == DEC_PIN_RESET) + m_pin_reset = val; + else + assert (0); +} + + +/* This is the external interface for indicating an external interrupt + to the i860. */ +void i860_cpu_device::i860_gen_interrupt() +{ + /* If interrupts are enabled, then set PSR.IN and prepare for trap. + Otherwise, the external interrupt is ignored. We also set + bit EPSR.INT (which tracks the INT pin). */ + if (GET_PSR_IM ()) + { + SET_PSR_IN (1); + SET_EPSR_INT (1); + m_pending_trap = TRAP_WAS_EXTERNAL; + } + +#ifdef TRACE_EXT_INT + fprintf (stderr, "i860_gen_interrupt: External interrupt received "); + if (GET_PSR_IM ()) + fprintf (stderr, "[PSR.IN set, preparing to trap]\n"); + else + fprintf (stderr, "[ignored (interrupts disabled)]\n"); +#endif +} + + +/* Fetch instructions from instruction cache. + Note: The instruction cache is not implemented for MAME version, + this just fetches and returns 1 instruction from memory. */ +UINT32 i860_cpu_device::ifetch (UINT32 pc) +{ + UINT32 phys_pc = 0; + UINT32 w1 = 0; + + /* If virtual mode, get translation. */ + if (GET_DIRBASE_ATE ()) + { + phys_pc = get_address_translation (pc, 0 /* is_dataref */, 0 /* is_write */); + m_exiting_ifetch = 0; + if (m_pending_trap && (GET_PSR_DAT () || GET_PSR_IAT ())) + { + m_exiting_ifetch = 1; + return 0xffeeffee; + } + } + else + phys_pc = pc; + + /* Since i860 instructions are always stored LSB first (regardless of + the BE bit), we need to adjust the instruction below on MSB hosts. */ + w1 = m_program->read_dword(phys_pc); +#ifdef HOST_MSB + BYTE_REV32 (w1); +#endif /* HOST_MSB. */ + return w1; +} + + +/* Given a virtual address, perform the i860 address translation and + return the corresponding physical address. + vaddr: virtual address + is_dataref: 1 = load/store, 0 = instruction fetch. + is_write: 1 = writing to vaddr, 0 = reading from vaddr + The last two arguments are only used to determine what types + of traps should be taken. + + Page tables must always be in memory (not cached). So the routine + here only accesses memory. */ +UINT32 i860_cpu_device::get_address_translation (UINT32 vaddr, int is_dataref, int is_write) +{ + UINT32 vdir = (vaddr >> 22) & 0x3ff; + UINT32 vpage = (vaddr >> 12) & 0x3ff; + UINT32 voffset = vaddr & 0xfff; + UINT32 dtb = (m_cregs[CR_DIRBASE]) & 0xfffff000; + UINT32 pg_dir_entry_a = 0; + UINT32 pg_dir_entry = 0; + UINT32 pg_tbl_entry_a = 0; + UINT32 pg_tbl_entry = 0; + UINT32 pfa1 = 0; + UINT32 pfa2 = 0; + UINT32 ret = 0; + UINT32 ttpde = 0; + UINT32 ttpte = 0; + + assert (GET_DIRBASE_ATE ()); + + /* Get page directory entry at DTB:DIR:00. */ + pg_dir_entry_a = dtb | (vdir << 2); + pg_dir_entry = m_program->read_dword(pg_dir_entry_a); +#ifdef HOST_MSB + BYTE_REV32 (pg_dir_entry); +#endif + + /* Check for non-present PDE. */ + if (!(pg_dir_entry & 1)) + { + /* PDE is not present, generate DAT or IAT. */ + if (is_dataref) + SET_PSR_DAT (1); + else + SET_PSR_IAT (1); + m_pending_trap = 1; + + /* Dummy return. */ + return 0; + } + + /* PDE Check for write protection violations. */ + if (is_write && is_dataref + && !(pg_dir_entry & 2) /* W = 0. */ + && (GET_PSR_U () || GET_EPSR_WP ())) /* PSR_U = 1 or EPSR_WP = 1. */ + { + SET_PSR_DAT (1); + m_pending_trap = 1; + /* Dummy return. */ + return 0; + } + + /* PDE Check for user-mode access to supervisor pages. */ + if (GET_PSR_U () + && !(pg_dir_entry & 4)) /* U = 0. */ + { + if (is_dataref) + SET_PSR_DAT (1); + else + SET_PSR_IAT (1); + m_pending_trap = 1; + /* Dummy return. */ + return 0; + } + + /* FIXME: How exactly to handle A check/update?. */ + + /* Get page table entry at PFA1:PAGE:00. */ + pfa1 = pg_dir_entry & 0xfffff000; + pg_tbl_entry_a = pfa1 | (vpage << 2); + pg_tbl_entry = m_program->read_dword(pg_tbl_entry_a); +#ifdef HOST_MSB + BYTE_REV32 (pg_tbl_entry); +#endif + + /* Check for non-present PTE. */ + if (!(pg_tbl_entry & 1)) + { + /* PTE is not present, generate DAT or IAT. */ + if (is_dataref) + SET_PSR_DAT (1); + else + SET_PSR_IAT (1); + m_pending_trap = 1; + + /* Dummy return. */ + return 0; + } + + /* PTE Check for write protection violations. */ + if (is_write && is_dataref + && !(pg_tbl_entry & 2) /* W = 0. */ + && (GET_PSR_U () || GET_EPSR_WP ())) /* PSR_U = 1 or EPSR_WP = 1. */ + { + SET_PSR_DAT (1); + m_pending_trap = 1; + /* Dummy return. */ + return 0; + } + + /* PTE Check for user-mode access to supervisor pages. */ + if (GET_PSR_U () + && !(pg_tbl_entry & 4)) /* U = 0. */ + { + if (is_dataref) + SET_PSR_DAT (1); + else + SET_PSR_IAT (1); + m_pending_trap = 1; + /* Dummy return. */ + return 0; + } + + /* Update A bit and check D bit. */ + ttpde = pg_dir_entry | 0x20; + ttpte = pg_tbl_entry | 0x20; +#ifdef HOST_MSB + BYTE_REV32 (ttpde); + BYTE_REV32 (ttpte); +#endif + m_program->write_dword(pg_dir_entry_a, ttpde); + m_program->write_dword(pg_tbl_entry_a, ttpte); + + if (is_write && is_dataref && (pg_tbl_entry & 0x40) == 0) + { + /* fprintf(stderr, "DAT trap on write without dirty bit v0x%08x/p0x%08x\n", + vaddr, (pg_tbl_entry & ~0xfff)|voffset); */ + SET_PSR_DAT (1); + m_pending_trap = 1; + /* Dummy return. */ + return 0; + } + + pfa2 = (pg_tbl_entry & 0xfffff000); + ret = pfa2 | voffset; + +#ifdef TRACE_ADDR_TRANSLATION + fprintf (stderr, "get_address_translation: virt(0x%08x) -> phys(0x%08x)\n", + vaddr, ret); +#endif + + return ret; +} + + +/* Read memory emulation. + addr = address to read. + size = size of read in bytes. */ +UINT32 i860_cpu_device::readmemi_emu (UINT32 addr, int size) +{ +#ifdef TRACE_RDWR_MEM + fprintf (stderr, "readmemi_emu: (ATE=%d) addr = 0x%08x, size = %d\n", + GET_DIRBASE_ATE (), addr, size); +#endif + + /* If virtual mode, do translation. */ + if (GET_DIRBASE_ATE ()) + { + UINT32 phys = get_address_translation (addr, 1 /* is_dataref */, 0 /* is_write */); + if (m_pending_trap && (GET_PSR_IAT () || GET_PSR_DAT ())) + { +#ifdef TRACE_PAGE_FAULT + fprintf (stderr, "0x%08x: ## Page fault (readmemi_emu).\n", + m_pc); +#endif + m_exiting_readmem = 1; + return 0; + } + addr = phys; + } + + /* First check for match to db register (before read). */ + if (((addr & ~(size - 1)) == m_cregs[CR_DB]) && GET_PSR_BR ()) + { + SET_PSR_DAT (1); + m_pending_trap = 1; + return 0; + } + + /* Now do the actual read. */ + if (size == 1) + { + UINT32 ret = m_program->read_byte(addr); + return ret & 0xff; + } + else if (size == 2) + { + UINT32 ret = m_program->read_word(addr); +#ifdef HOST_MSB + BYTE_REV16 (ret); +#endif + return ret & 0xffff; + } + else if (size == 4) + { + UINT32 ret = m_program->read_dword(addr); +#ifdef HOST_MSB + BYTE_REV32 (ret); +#endif + return ret; + } + else + assert (0); + + return 0; +} + + +/* Write memory emulation. + addr = address to write. + size = size of write in bytes. + data = data to write. */ +void i860_cpu_device::writememi_emu (UINT32 addr, int size, UINT32 data) +{ +#ifdef TRACE_RDWR_MEM + fprintf (stderr, "writememi_emu: (ATE=%d) addr = 0x%08x, size = %d, data = 0x%08x\n", + GET_DIRBASE_ATE (), addr, size, data); +#endif + + /* If virtual mode, do translation. */ + if (GET_DIRBASE_ATE ()) + { + UINT32 phys = get_address_translation (addr, 1 /* is_dataref */, 1 /* is_write */); + if (m_pending_trap && (GET_PSR_IAT () || GET_PSR_DAT ())) + { +#ifdef TRACE_PAGE_FAULT + fprintf (stderr, "0x%08x: ## Page fault (writememi_emu).\n", + m_pc); +#endif + m_exiting_readmem = 2; + return; + } + addr = phys; + } + + /* First check for match to db register (before write). */ + if (((addr & ~(size - 1)) == m_cregs[CR_DB]) && GET_PSR_BW ()) + { + SET_PSR_DAT (1); + m_pending_trap = 1; + return; + } + + /* Now do the actual write. */ + if (size == 1) + m_program->write_byte(addr, data); + else if (size == 2) + { +#ifdef HOST_MSB + BYTE_REV16 (data); +#endif + m_program->write_word(addr, data); + } + else if (size == 4) + { +#ifdef HOST_MSB + BYTE_REV32 (data); +#endif + m_program->write_dword(addr, data); + } + else + assert (0); +} + + +/* Floating-point read mem routine. + addr = address to read. + size = size of read in bytes. + dest = memory to put read data. */ +void i860_cpu_device::fp_readmem_emu (UINT32 addr, int size, UINT8 *dest) +{ +#ifdef TRACE_RDWR_MEM + fprintf (stderr, "fp_readmem_emu: (ATE=%d) addr = 0x%08x, size = %d\n", + GET_DIRBASE_ATE (), addr, size); +#endif + + assert (size == 4 || size == 8 || size == 16); + + /* If virtual mode, do translation. */ + if (GET_DIRBASE_ATE ()) + { + UINT32 phys = get_address_translation (addr, 1 /* is_dataref */, 0 /* is_write */); + if (m_pending_trap && (GET_PSR_IAT () || GET_PSR_DAT ())) + { +#ifdef TRACE_PAGE_FAULT + fprintf (stderr, "0x%08x: ## Page fault (fp_readmem_emu).\n", + m_pc); +#endif + m_exiting_readmem = 3; + return; + } + addr = phys; + } + + /* First check for match to db register (before read). */ + if (((addr & ~(size - 1)) == m_cregs[CR_DB]) && GET_PSR_BR ()) + { + SET_PSR_DAT (1); + m_pending_trap = 1; + return; + } + + if (size == 4) + { + dest[0] = m_program->read_byte(addr+3); + dest[1] = m_program->read_byte(addr+2); + dest[2] = m_program->read_byte(addr+1); + dest[3] = m_program->read_byte(addr+0); + } + else if (size == 8) + { + dest[0] = m_program->read_byte(addr+7); + dest[1] = m_program->read_byte(addr+6); + dest[2] = m_program->read_byte(addr+5); + dest[3] = m_program->read_byte(addr+4); + dest[4] = m_program->read_byte(addr+3); + dest[5] = m_program->read_byte(addr+2); + dest[6] = m_program->read_byte(addr+1); + dest[7] = m_program->read_byte(addr+0); + } + else if (size == 16) + { + int i; + for (i = 0; i < 16; i++) + { + dest[i] = m_program->read_byte(addr+15-i); + } + } +} + + +/* Floating-point write mem routine. + addr = address to read. + size = size of read in bytes. + data = pointer to the data. + wmask = bit mask of bytes to write (only for pst.d). */ +void i860_cpu_device::fp_writemem_emu (UINT32 addr, int size, UINT8 *data, UINT32 wmask) +{ +#ifdef TRACE_RDWR_MEM + fprintf (stderr, "fp_writemem_emu: (ATE=%d) addr = 0x%08x, size = %d\n", + GET_DIRBASE_ATE (), addr, size); +#endif + + assert (size == 4 || size == 8 || size == 16); + + /* If virtual mode, do translation. */ + if (GET_DIRBASE_ATE ()) + { + UINT32 phys = get_address_translation (addr, 1 /* is_dataref */, 1 /* is_write */); + if (m_pending_trap && GET_PSR_DAT ()) + { +#ifdef TRACE_PAGE_FAULT + fprintf (stderr, "0x%08x: ## Page fault (fp_writememi_emu).\n", + m_pc); +#endif + m_exiting_readmem = 4; + return; + } + addr = phys; + } + + /* First check for match to db register (before read). */ + if (((addr & ~(size - 1)) == m_cregs[CR_DB]) && GET_PSR_BW ()) + { + SET_PSR_DAT (1); + m_pending_trap = 1; + return; + } + + if (size == 4) + { +#if 1 + m_program->write_byte(addr+3, data[0]); + m_program->write_byte(addr+2, data[1]); + m_program->write_byte(addr+1, data[2]); + m_program->write_byte(addr+0, data[3]); +#else + UINT32 ddd = (data[3]) | (data[2] << 8) | (data[1] << 16) |(data[0] << 24); + m_program->write_dword(addr+0, ddd); +#endif + } + else if (size == 8) + { + /* Special: watch for wmask != 0xff, which means we're doing pst.d. */ + if (wmask == 0xff) + { + m_program->write_byte(addr+7, data[0]); + m_program->write_byte(addr+6, data[1]); + m_program->write_byte(addr+5, data[2]); + m_program->write_byte(addr+4, data[3]); + m_program->write_byte(addr+3, data[4]); + m_program->write_byte(addr+2, data[5]); + m_program->write_byte(addr+1, data[6]); + m_program->write_byte(addr+0, data[7]); + } + else + { + if (wmask & 0x80) m_program->write_byte(addr+7, data[0]); + if (wmask & 0x40) m_program->write_byte(addr+6, data[1]); + if (wmask & 0x20) m_program->write_byte(addr+5, data[2]); + if (wmask & 0x10) m_program->write_byte(addr+4, data[3]); + if (wmask & 0x08) m_program->write_byte(addr+3, data[4]); + if (wmask & 0x04) m_program->write_byte(addr+2, data[5]); + if (wmask & 0x02) m_program->write_byte(addr+1, data[6]); + if (wmask & 0x01) m_program->write_byte(addr+0, data[7]); + } + } + else if (size == 16) + { + int i; + for (i = 0; i < 16; i++) + { + m_program->write_byte(addr+15-i, data[i]); + } + } + +} + + +#if 0 +/* Do a pipeline dump. + type: 0 (all), 1 (add), 2 (mul), 3 (load), 4 (graphics). */ +void i860_cpu_device::dump_pipe (int type) +{ + int i = 0; + + fprintf (stderr, "pipeline state:\n"); + /* Dump the adder pipeline, if requested. */ + if (type == 0 || type == 1) + { + fprintf (stderr, " A: "); + for (i = 0; i < 3; i++) + { + if (m_A[i].stat.arp) + fprintf (stderr, "[%dd] 0x%016llx ", i + 1, + *(UINT64 *)(&m_A[i].val.d)); + else + fprintf (stderr, "[%ds] 0x%08x ", i + 1, + *(UINT32 *)(&m_A[i].val.s)); + } + fprintf (stderr, "\n"); + } + + + /* Dump the multiplier pipeline, if requested. */ + if (type == 0 || type == 2) + { + fprintf (stderr, " M: "); + for (i = 0; i < 3; i++) + { + if (m_M[i].stat.mrp) + fprintf (stderr, "[%dd] 0x%016llx ", i + 1, + *(UINT64 *)(&m_M[i].val.d)); + else + fprintf (stderr, "[%ds] 0x%08x ", i + 1, + *(UINT32 *)(&m_M[i].val.s)); + } + fprintf (stderr, "\n"); + } + + /* Dump the load pipeline, if requested. */ + if (type == 0 || type == 3) + { + fprintf (stderr, " L: "); + for (i = 0; i < 3; i++) + { + if (m_L[i].stat.lrp) + fprintf (stderr, "[%dd] 0x%016llx ", i + 1, + *(UINT64 *)(&m_L[i].val.d)); + else + fprintf (stderr, "[%ds] 0x%08x ", i + 1, + *(UINT32 *)(&m_L[i].val.s)); + } + fprintf (stderr, "\n"); + } + + /* Dump the graphics pipeline, if requested. */ + if (type == 0 || type == 4) + { + fprintf (stderr, " I: "); + if (m_G.stat.irp) + fprintf (stderr, "[1d] 0x%016llx\n", + *(UINT64 *)(&m_G.val.d)); + else + fprintf (stderr, "[1s] 0x%08x\n", + *(UINT32 *)(&m_G.val.s)); + } +} + + +/* Do a register/state dump. */ +void i860_cpu_device::dump_state (i860s *cpustate) +{ + int rn; + + /* GR's first, 4 per line. */ + for (rn = 0; rn < 32; rn++) + { + if ((rn % 4) == 0) + fprintf (stderr, "\n"); + fprintf (stderr, "%%r%-3d: 0x%08x ", rn, get_iregval (rn)); + } + fprintf (stderr, "\n"); + + /* FR's (as 32-bits), 4 per line. */ + for (rn = 0; rn < 32; rn++) + { + float ff = get_fregval_s (rn); + if ((rn % 4) == 0) + fprintf (stderr, "\n"); + fprintf (stderr, "%%f%-3d: 0x%08x ", rn, *(UINT32 *)&ff); + } + fprintf (stderr, "\n"); + + fprintf (stderr, " psr: CC = %d, LCC = %d, SC = %d, IM = %d, U = %d\n", + GET_PSR_CC (), GET_PSR_LCC (), GET_PSR_SC (), GET_PSR_IM (), + GET_PSR_U ()); + fprintf (stderr, " IT/FT/IAT/DAT/IN = %d/%d/%d/%d/%d\n", + GET_PSR_IT (), GET_PSR_FT (), GET_PSR_IAT (), + GET_PSR_DAT (), GET_PSR_IN ()); + fprintf (stderr, "epsr: INT = %d, OF = %d, BE = %d\n", + GET_EPSR_INT (), GET_EPSR_OF (), GET_EPSR_BE ()); + fprintf (stderr, " fir: 0x%08x dirbase: 0x%08x fsr: 0x%08x\n", + m_cregs[CR_FIR], m_cregs[CR_DIRBASE], + m_cregs[CR_FSR]); + fprintf (stderr, " pc: 0x%08x\n", m_pc); +} +#endif + +/* Sign extend N-bit number. */ +INLINE INT32 sign_ext (UINT32 x, int n) +{ + INT32 t; + t = x >> (n - 1); + t = ((-t) << n) | x; + return t; +} + + +void i860_cpu_device::unrecog_opcode (UINT32 pc, UINT32 insn) +{ + fprintf (stderr, "0x%08x: 0x%08x (unrecognized opcode)\n", pc, insn); +} + + +/* Execute "ld.c csrc2,idest" instruction. */ +void i860_cpu_device::insn_ld_ctrl (UINT32 insn) +{ + UINT32 csrc2 = get_creg (insn); + UINT32 idest = get_idest (insn); + +#ifdef TRACE_UNDEFINED_I860 + if (csrc2 > 5) + { + /* Control register not between 0..5. Undefined i860XR behavior. */ + fprintf (stderr, "WARNING: insn_ld_from_ctrl (pc=0x%08x): bad creg in ld.c (ignored)\n", m_pc); + return; + } +#endif + + /* If this is a load of the fir, then there are two cases: + 1. First load of fir after a trap = usual value. + 2. Not first load of fir after a trap = address of the ld.c insn. */ + if (csrc2 == CR_FIR) + { + if (m_fir_gets_trap_addr) + set_iregval (idest, m_cregs[csrc2]); + else + { + m_cregs[csrc2] = m_pc; + set_iregval (idest, m_cregs[csrc2]); + } + m_fir_gets_trap_addr = 0; + } + else + set_iregval (idest, m_cregs[csrc2]); +} + + +/* Execute "st.c isrc1,csrc2" instruction. */ +void i860_cpu_device::insn_st_ctrl (UINT32 insn) +{ + UINT32 csrc2 = get_creg (insn); + UINT32 isrc1 = get_isrc1 (insn); + +#ifdef TRACE_UNDEFINED_I860 + if (csrc2 > 5) + { + /* Control register not between 0..5. Undefined i860XR behavior. */ + fprintf (stderr, "WARNING: insn_st_to_ctrl (pc=0x%08x): bad creg in st.c (ignored)\n", m_pc); + return; + } +#endif + + /* Look for ITI bit turned on (but it never actually is written -- + it always appears to be 0). */ + if (csrc2 == CR_DIRBASE && (get_iregval (isrc1) & 0x20)) + { + /* NOTE: The actual icache and TLB flush are unimplemented for + the MAME version. */ + + /* Make sure ITI isn't actually written. */ + set_iregval (isrc1, (get_iregval (isrc1) & ~0x20)); + } + + if (csrc2 == CR_DIRBASE && (get_iregval (isrc1) & 1) + && GET_DIRBASE_ATE () == 0) + { + fprintf (stderr, "0x%08x: ** ATE going high!\n", m_pc); + } + + /* Update the register -- unless it is fir which cannot be updated. */ + if (csrc2 == CR_EPSR) + { + UINT32 enew = 0, tmp = 0; + /* Make sure unchangeable EPSR bits stay unchanged (DCS, stepping, + and type). Also, some bits are only writeable in supervisor + mode. */ + if (GET_PSR_U ()) + { + enew = get_iregval (isrc1) & ~(0x003e1fff | 0x00c06000); + tmp = m_cregs[CR_EPSR] & (0x003e1fff | 0x00c06000); + } + else + { + enew = get_iregval (isrc1) & ~0x003e1fff; + tmp = m_cregs[CR_EPSR] & 0x003e1fff; + } + m_cregs[CR_EPSR] = enew | tmp; + } + else if (csrc2 == CR_PSR) + { + /* Some PSR bits are only writeable in supervisor mode. */ + if (GET_PSR_U ()) + { + UINT32 enew = get_iregval (isrc1) & ~PSR_SUPERVISOR_ONLY_MASK; + UINT32 tmp = m_cregs[CR_PSR] & PSR_SUPERVISOR_ONLY_MASK; + m_cregs[CR_PSR] = enew | tmp; + } + else + m_cregs[CR_PSR] = get_iregval (isrc1); + } + else if (csrc2 == CR_FSR) + { + /* I believe that only 21..17, 8..5, and 3..0 should be updated. */ + UINT32 enew = get_iregval (isrc1) & 0x003e01ef; + UINT32 tmp = m_cregs[CR_FSR] & ~0x003e01ef; + m_cregs[CR_FSR] = enew | tmp; + } + else if (csrc2 != CR_FIR) + m_cregs[csrc2] = get_iregval (isrc1); +} + + +/* Execute "ld.{s,b,l} isrc1(isrc2),idest" or + "ld.{s,b,l} #const(isrc2),idest". */ +void i860_cpu_device::insn_ldx (UINT32 insn) +{ + UINT32 isrc1 = get_isrc1 (insn); + INT32 immsrc1 = sign_ext (get_imm16 (insn), 16); + UINT32 isrc2 = get_isrc2 (insn); + UINT32 idest = get_idest (insn); + UINT32 eff = 0; + /* Operand size, in bytes. */ + int sizes[4] = { 1, 1, 2, 4}; + int size = 0; + int form_disp_reg = 0; + + /* Bits 28 and 0 determine the operand size. */ + size = sizes[((insn >> 27) & 2) | (insn & 1)]; + + /* Bit 26 determines the addressing mode (reg+reg or disp+reg). */ + form_disp_reg = (insn & 0x04000000); + + /* Get effective address depending on disp+reg or reg+reg form. */ + if (form_disp_reg) + { + /* Chop off lower bits of displacement. */ + immsrc1 &= ~(size - 1); + eff = (UINT32)(immsrc1 + (INT32)(get_iregval (isrc2))); + } + else + eff = get_iregval (isrc1) + get_iregval (isrc2); + +#ifdef TRACE_UNALIGNED_MEM + if (eff & (size - 1)) + { + fprintf (stderr, "0x%08x: Unaligned access detected (0x%08x).\n", + m_pc, eff); + SET_PSR_DAT (1); + m_pending_trap = 1; + return; + } +#endif + + /* The i860 sign-extends 8- or 16-bit integer loads. + + Below, the readmemi_emu() needs to happen outside of the + set_iregval macro (otherwise the readmem won't occur if r0 + is the target register). */ + if (size < 4) + { + UINT32 readval = sign_ext (readmemi_emu (eff, size), size * 8); + /* Do not update register on page fault. */ + if (m_exiting_readmem) + { + return; + } + set_iregval (idest, readval); + } + else + { + UINT32 readval = readmemi_emu (eff, size); + /* Do not update register on page fault. */ + if (m_exiting_readmem) + { + return; + } + set_iregval (idest, readval); + } +} + + +/* Execute "st.x isrc1ni,#const(isrc2)" instruction (there is no + (reg + reg form). Store uses the split immediate, not the normal + 16-bit immediate as in ld.x. */ +void i860_cpu_device::insn_stx (UINT32 insn) +{ + INT32 immsrc = sign_ext ((((insn >> 5) & 0xf800) | (insn & 0x07ff)), 16); + UINT32 isrc1 = get_isrc1 (insn); + UINT32 isrc2 = get_isrc2 (insn); + UINT32 eff = 0; + /* Operand size, in bytes. */ + int sizes[4] = { 1, 1, 2, 4}; + int size = 0; + + /* Bits 28 and 0 determine the operand size. */ + size = sizes[((insn >> 27) & 2) | (insn & 1)]; + + /* FIXME: Do any necessary traps. */ + + /* Get effective address. Chop off lower bits of displacement. */ + immsrc &= ~(size - 1); + eff = (UINT32)(immsrc + (INT32)get_iregval (isrc2)); + + /* Write data (value of reg isrc1) to memory at eff. */ + writememi_emu (eff, size, get_iregval (isrc1)); + if (m_exiting_readmem) + return; +} + + +/* Execute "fst.y fdest,isrc1(isrc2)", "fst.y fdest,isrc1(isrc2)++", + "fst.y fdest,#const(isrc2)" or "fst.y fdest,#const(isrc2)++" + instruction. */ +void i860_cpu_device::insn_fsty (UINT32 insn) +{ + UINT32 isrc1 = get_isrc1 (insn); + INT32 immsrc1 = sign_ext (get_imm16 (insn), 16); + UINT32 isrc2 = get_isrc2 (insn); + UINT32 fdest = get_fdest (insn); + UINT32 eff = 0; + /* Operand size, in bytes. */ + int sizes[4] = { 8, 4, 16, 4}; + int size = 0; + int form_disp_reg = 0; + int auto_inc = (insn & 1); + + /* Bits 2 and 1 determine the operand size. */ + size = sizes[((insn >> 1) & 3)]; + + /* Bit 26 determines the addressing mode (reg+reg or disp+reg). */ + form_disp_reg = (insn & 0x04000000); + + /* FIXME: Check for undefined behavior, non-even or non-quad + register operands for fst.d and fst.q respectively. */ + + /* Get effective address depending on disp+reg or reg+reg form. */ + if (form_disp_reg) + { + /* Chop off lower bits of displacement. */ + immsrc1 &= ~(size - 1); + eff = (UINT32)(immsrc1 + (INT32)(get_iregval (isrc2))); + } + else + eff = get_iregval (isrc1) + get_iregval (isrc2); + +#ifdef TRACE_UNALIGNED_MEM + if (eff & (size - 1)) + { + fprintf (stderr, "0x%08x: Unaligned access detected (0x%08x).\n", + m_pc, eff); + SET_PSR_DAT (1); + m_pending_trap = 1; + return; + } +#endif + + /* Do (post) auto-increment. */ + if (auto_inc) + { + set_iregval (isrc2, eff); +#ifdef TRACE_UNDEFINED_I860 + /* When auto-inc, isrc1 and isrc2 regs can't be the same. */ + if (isrc1 == isrc2) + { + /* Undefined i860XR behavior. */ + fprintf (stderr, "WARNING: insn_fsty (pc=0x%08x): isrc1 = isrc2 in fst with auto-inc (ignored)\n", m_pc); + return; + } +#endif + } + + /* Write data (value of freg fdest) to memory at eff. */ + if (size == 4) + fp_writemem_emu (eff, size, (UINT8 *)(&m_frg[4 * (31 - fdest)]), 0xff); + else if (size == 8) + fp_writemem_emu (eff, size, (UINT8 *)(&m_frg[4 * (31 - (fdest + 1))]), 0xff); + else + fp_writemem_emu (eff, size, (UINT8 *)(&m_frg[4 * (31 - (fdest + 3))]), 0xff); + +} + + +/* Execute "fld.y isrc1(isrc2),fdest", "fld.y isrc1(isrc2)++,idest", + "fld.y #const(isrc2),fdest" or "fld.y #const(isrc2)++,idest". + Where y = {l,d,q}. Note, there is no pfld.q, though. */ +void i860_cpu_device::insn_fldy (UINT32 insn) +{ + UINT32 isrc1 = get_isrc1 (insn); + INT32 immsrc1 = sign_ext (get_imm16 (insn), 16); + UINT32 isrc2 = get_isrc2 (insn); + UINT32 fdest = get_fdest (insn); + UINT32 eff = 0; + /* Operand size, in bytes. */ + int sizes[4] = { 8, 4, 16, 4}; + int size = 0; + int form_disp_reg = 0; + int auto_inc = (insn & 1); + int piped = (insn & 0x40000000); + + /* Bits 2 and 1 determine the operand size. */ + size = sizes[((insn >> 1) & 3)]; + + /* Bit 26 determines the addressing mode (reg+reg or disp+reg). */ + form_disp_reg = (insn & 0x04000000); + + /* There is no pipelined load quad. */ + if (piped && size == 16) + { + unrecog_opcode (m_pc, insn); + return; + } + + /* FIXME: Check for undefined behavior, non-even or non-quad + register operands for fld.d and fld.q respectively. */ + + /* Get effective address depending on disp+reg or reg+reg form. */ + if (form_disp_reg) + { + /* Chop off lower bits of displacement. */ + immsrc1 &= ~(size - 1); + eff = (UINT32)(immsrc1 + (INT32)(get_iregval (isrc2))); + } + else + eff = get_iregval (isrc1) + get_iregval (isrc2); + + /* Do (post) auto-increment. */ + if (auto_inc) + { + set_iregval (isrc2, eff); +#ifdef TRACE_UNDEFINED_I860 + /* When auto-inc, isrc1 and isrc2 regs can't be the same. */ + if (isrc1 == isrc2) + { + /* Undefined i860XR behavior. */ + fprintf (stderr, "WARNING: insn_fldy (pc=0x%08x): isrc1 = isrc2 in fst with auto-inc (ignored)\n", m_pc); + return; + } +#endif + } + +#ifdef TRACE_UNALIGNED_MEM + if (eff & (size - 1)) + { + fprintf (stderr, "0x%08x: Unaligned access detected (0x%08x).\n", + m_pc, eff); + SET_PSR_DAT (1); + m_pending_trap = 1; + return; + } +#endif + + /* Update the load pipe if necessary. */ + /* FIXME: Copy result-status bits to fsr from last stage. */ + if (!piped) + { + /* Scalar version writes the current result to fdest. */ + /* Read data at 'eff' into freg 'fdest' (reads to f0 or f1 are + thrown away). */ + if (fdest > 1) + { + if (size == 4) + fp_readmem_emu (eff, size, (UINT8 *)&(m_frg[4 * (31 - fdest)])); + else if (size == 8) + fp_readmem_emu (eff, size, (UINT8 *)&(m_frg[4 * (31 - (fdest + 1))])); + else if (size == 16) + fp_readmem_emu (eff, size, (UINT8 *)&(m_frg[4 * (31 - (fdest + 3))])); + } + } + else + { + /* Read the data into a temp space first. This way we can test + for any traps before updating the pipeline. The pipeline must + stay unaffected after a trap so that the instruction can be + properly restarted. */ + UINT8 bebuf[8]; + fp_readmem_emu (eff, size, bebuf); + if (m_pending_trap && m_exiting_readmem) + goto ab_op; + + /* Pipelined version writes fdest with the result from the last + stage of the pipeline, with precision specified by the LRP + bit of the stage's result-status bits. */ +#if 1 /* FIXME: WIP on FSR update. This may not be correct. */ + /* Copy 3rd stage LRP to FSR. */ + if (m_L[1 /* 2 */].stat.lrp) + m_cregs[CR_FSR] |= 0x04000000; + else + m_cregs[CR_FSR] &= ~0x04000000; +#endif + if (m_L[2].stat.lrp) /* 3rd (last) stage. */ + set_fregval_d (fdest, m_L[2].val.d); + else + set_fregval_s (fdest, m_L[2].val.s); + + /* Now advance pipeline and write loaded data to first stage. */ + m_L[2] = m_L[1]; + m_L[1] = m_L[0]; + if (size == 8) + { + UINT8 *t = (UINT8 *)&(m_L[0].val.d); +#ifndef HOST_MSB + t[7] = bebuf[0]; t[6] = bebuf[1]; t[5] = bebuf[2]; t[4] = bebuf[3]; + t[3] = bebuf[4]; t[2] = bebuf[5]; t[1] = bebuf[6]; t[0] = bebuf[7]; +#else + t[0] = bebuf[0]; t[1] = bebuf[1]; t[2] = bebuf[2]; t[3] = bebuf[3]; + t[4] = bebuf[4]; t[5] = bebuf[5]; t[6] = bebuf[6]; t[7] = bebuf[7]; +#endif + m_L[0].stat.lrp = 1; + } + else + { + UINT8 *t = (UINT8 *)&(m_L[0].val.s); +#ifndef HOST_MSB + t[3] = bebuf[0]; t[2] = bebuf[1]; t[1] = bebuf[2]; t[0] = bebuf[3]; +#else + t[0] = bebuf[0]; t[1] = bebuf[1]; t[2] = bebuf[2]; t[3] = bebuf[3]; +#endif + m_L[0].stat.lrp = 0; + } + } + + ab_op:; +} + + +/* Execute "pst.d fdest,#const(isrc2)" or "fst.d fdest,#const(isrc2)++" + instruction. */ +void i860_cpu_device::insn_pstd (UINT32 insn) +{ + INT32 immsrc1 = sign_ext (get_imm16 (insn), 16); + UINT32 isrc2 = get_isrc2 (insn); + UINT32 fdest = get_fdest (insn); + UINT32 eff = 0; + int auto_inc = (insn & 1); + UINT8 *bebuf = 0; + int pm = GET_PSR_PM (); + int i; + UINT32 wmask; + int orig_pm = pm; + + /* Get the pixel size, where: + PS: 0 = 8 bits, 1 = 16 bits, 2 = 32-bits. */ + int ps = GET_PSR_PS (); + +#ifdef TRACE_UNDEFINED_I860 + if (!(ps == 0 || ps == 1 || ps == 2)) + fprintf (stderr, "insn_pstd: Undefined i860XR behavior, invalid value %d for pixel size.\n", ps); +#endif + +#ifdef TRACE_UNDEFINED_I860 + /* Bits 2 and 1 determine the operand size, which must always be + zero (indicating a 64-bit operand). */ + if (insn & 0x6) + { + /* Undefined i860XR behavior. */ + fprintf (stderr, "WARNING: insn_pstd (pc=0x%08x): bad operand size specifier\n", m_pc); + } +#endif + + /* FIXME: Check for undefined behavior, non-even register operands. */ + + /* Get effective address. Chop off lower bits of displacement. */ + immsrc1 &= ~(8 - 1); + eff = (UINT32)(immsrc1 + (INT32)(get_iregval (isrc2))); + +#ifdef TRACE_UNALIGNED_MEM + if (eff & (8 - 1)) + { + fprintf (stderr, "0x%08x: Unaligned access detected (0x%08x).\n", + m_pc, eff); + SET_PSR_DAT (1); + m_pending_trap = 1; + return; + } +#endif + + /* Do (post) auto-increment. */ + if (auto_inc) + set_iregval (isrc2, eff); + + /* Update the pixel mask depending on the pixel size. Shift PM + right by 8/2^ps bits. */ + if (ps == 0) + pm = (pm >> 8) & 0x00; + else if (ps == 1) + pm = (pm >> 4) & 0x0f; + else if (ps == 2) + pm = (pm >> 2) & 0x3f; + SET_PSR_PM (pm); + + /* Write data (value of freg fdest) to memory at eff-- but only those + bytes that are enabled by the bits in PSR.PM. Bit 0 of PM selects + the pixel at the lowest address. */ + wmask = 0; + for (i = 0; i < 8; ) + { + if (ps == 0) + { + if (orig_pm & 0x80) + wmask |= 1 << (7-i); + i += 1; + } + else if (ps == 1) + { + if (orig_pm & 0x08) + wmask |= 0x3 << (6-i); + i += 2; + } + else if (ps == 2) + { + if (orig_pm & 0x02) + wmask |= 0xf << (4-i); + i += 4; + } + else + { + wmask = 0xff; + break; + } + orig_pm <<= 1; + } + bebuf = (UINT8 *)(&m_frg[4 * (31 - (fdest + 1))]); + fp_writemem_emu (eff, 8, bebuf, wmask); +} + + +/* Execute "ixfr isrc1ni,fdest" instruction. */ +void i860_cpu_device::insn_ixfr (UINT32 insn) +{ + UINT32 isrc1 = get_isrc1 (insn); + UINT32 fdest = get_fdest (insn); + UINT32 iv = 0; + + /* This is a bit-pattern transfer, not a conversion. */ + iv = get_iregval (isrc1); + set_fregval_s (fdest, *(float *)&iv); +} + + +/* Execute "addu isrc1,isrc2,idest". */ +void i860_cpu_device::insn_addu (UINT32 insn) +{ + UINT32 src1val; + UINT32 isrc2 = get_isrc2 (insn); + UINT32 idest = get_idest (insn); + UINT32 tmp_dest_val = 0; + UINT64 tmp = 0; + + src1val = get_iregval (get_isrc1 (insn)); + + /* We don't update the actual idest register now because below we + need to test the original src1 and src2 if either happens to + be the destination register. */ + tmp_dest_val = src1val + get_iregval (isrc2); + + /* Set OF and CC flags. + For unsigned: + OF = bit 31 carry + CC = bit 31 carry. + */ + tmp = (UINT64)src1val + (UINT64)(get_iregval (isrc2)); + if ((tmp >> 32) & 1) + { + SET_PSR_CC (1); + SET_EPSR_OF (1); + } + else + { + SET_PSR_CC (0); + SET_EPSR_OF (0); + } + + /* Now update the destination register. */ + set_iregval (idest, tmp_dest_val); +} + + +/* Execute "addu #const,isrc2,idest". */ +void i860_cpu_device::insn_addu_imm (UINT32 insn) +{ + UINT32 src1val; + UINT32 isrc2 = get_isrc2 (insn); + UINT32 idest = get_idest (insn); + UINT32 tmp_dest_val = 0; + UINT64 tmp = 0; + + src1val = sign_ext (get_imm16 (insn), 16); + + /* We don't update the actual idest register now because below we + need to test the original src1 and src2 if either happens to + be the destination register. */ + tmp_dest_val = src1val + get_iregval (isrc2); + + /* Set OF and CC flags. + For unsigned: + OF = bit 31 carry + CC = bit 31 carry. + */ + tmp = (UINT64)src1val + (UINT64)(get_iregval (isrc2)); + if ((tmp >> 32) & 1) + { + SET_PSR_CC (1); + SET_EPSR_OF (1); + } + else + { + SET_PSR_CC (0); + SET_EPSR_OF (0); + } + + /* Now update the destination register. */ + set_iregval (idest, tmp_dest_val); +} + + +/* Execute "adds isrc1,isrc2,idest". */ +void i860_cpu_device::insn_adds (UINT32 insn) +{ + UINT32 src1val; + UINT32 isrc2 = get_isrc2 (insn); + UINT32 idest = get_idest (insn); + UINT32 tmp_dest_val = 0; + int sa, sb, sres; + + src1val = get_iregval (get_isrc1 (insn)); + + /* We don't update the actual idest register now because below we + need to test the original src1 and src2 if either happens to + be the destination register. */ + tmp_dest_val = src1val + get_iregval (isrc2); + + /* Set OF and CC flags. + For signed: + OF = standard signed overflow. + CC set if isrc2 < -isrc1 + CC clear if isrc2 >= -isrc1 + */ + sa = src1val & 0x80000000; + sb = get_iregval (isrc2) & 0x80000000; + sres = tmp_dest_val & 0x80000000; + if (sa != sb && sa != sres) + SET_EPSR_OF (1); + else + SET_EPSR_OF (0); + + if ((INT32)get_iregval (isrc2) < -(INT32)(src1val)) + SET_PSR_CC (1); + else + SET_PSR_CC (0); + + /* Now update the destination register. */ + set_iregval (idest, tmp_dest_val); +} + + +/* Execute "adds #const,isrc2,idest". */ +void i860_cpu_device::insn_adds_imm (UINT32 insn) +{ + UINT32 src1val; + UINT32 isrc2 = get_isrc2 (insn); + UINT32 idest = get_idest (insn); + UINT32 tmp_dest_val = 0; + int sa, sb, sres; + + src1val = sign_ext (get_imm16 (insn), 16); + + /* We don't update the actual idest register now because below we + need to test the original src1 and src2 if either happens to + be the destination register. */ + tmp_dest_val = src1val + get_iregval (isrc2); + + /* Set OF and CC flags. + For signed: + OF = standard signed overflow. + CC set if isrc2 < -isrc1 + CC clear if isrc2 >= -isrc1 + */ + sa = src1val & 0x80000000; + sb = get_iregval (isrc2) & 0x80000000; + sres = tmp_dest_val & 0x80000000; + if (sa != sb && sa != sres) + SET_EPSR_OF (1); + else + SET_EPSR_OF (0); + + if ((INT32)get_iregval (isrc2) < -(INT32)(src1val)) + SET_PSR_CC (1); + else + SET_PSR_CC (0); + + /* Now update the destination register. */ + set_iregval (idest, tmp_dest_val); +} + + +/* Execute "subu isrc1,isrc2,idest". */ +void i860_cpu_device::insn_subu (UINT32 insn) +{ + UINT32 src1val; + UINT32 isrc2 = get_isrc2 (insn); + UINT32 idest = get_idest (insn); + UINT32 tmp_dest_val = 0; + + src1val = get_iregval (get_isrc1 (insn)); + + /* We don't update the actual idest register now because below we + need to test the original src1 and src2 if either happens to + be the destination register. */ + tmp_dest_val = src1val - get_iregval (isrc2); + + /* Set OF and CC flags. + For unsigned: + OF = NOT(bit 31 carry) + CC = bit 31 carry. + (i.e. CC set if isrc2 <= isrc1 + CC clear if isrc2 > isrc1 + */ + if ((UINT32)get_iregval (isrc2) <= (UINT32)src1val) + { + SET_PSR_CC (1); + SET_EPSR_OF (0); + } + else + { + SET_PSR_CC (0); + SET_EPSR_OF (1); + } + + /* Now update the destination register. */ + set_iregval (idest, tmp_dest_val); +} + + +/* Execute "subu #const,isrc2,idest". */ +void i860_cpu_device::insn_subu_imm (UINT32 insn) +{ + UINT32 src1val; + UINT32 isrc2 = get_isrc2 (insn); + UINT32 idest = get_idest (insn); + UINT32 tmp_dest_val = 0; + + src1val = sign_ext (get_imm16 (insn), 16); + + /* We don't update the actual idest register now because below we + need to test the original src1 and src2 if either happens to + be the destination register. */ + tmp_dest_val = src1val - get_iregval (isrc2); + + /* Set OF and CC flags. + For unsigned: + OF = NOT(bit 31 carry) + CC = bit 31 carry. + (i.e. CC set if isrc2 <= isrc1 + CC clear if isrc2 > isrc1 + */ + if ((UINT32)get_iregval (isrc2) <= (UINT32)src1val) + { + SET_PSR_CC (1); + SET_EPSR_OF (0); + } + else + { + SET_PSR_CC (0); + SET_EPSR_OF (1); + } + + /* Now update the destination register. */ + set_iregval (idest, tmp_dest_val); +} + + +/* Execute "subs isrc1,isrc2,idest". */ +void i860_cpu_device::insn_subs (UINT32 insn) +{ + UINT32 src1val; + UINT32 isrc2 = get_isrc2 (insn); + UINT32 idest = get_idest (insn); + UINT32 tmp_dest_val = 0; + int sa, sb, sres; + + src1val = get_iregval (get_isrc1 (insn)); + + /* We don't update the actual idest register now because below we + need to test the original src1 and src2 if either happens to + be the destination register. */ + tmp_dest_val = src1val - get_iregval (isrc2); + + /* Set OF and CC flags. + For signed: + OF = standard signed overflow. + CC set if isrc2 > isrc1 + CC clear if isrc2 <= isrc1 + */ + sa = src1val & 0x80000000; + sb = get_iregval (isrc2) & 0x80000000; + sres = tmp_dest_val & 0x80000000; + if (sa != sb && sa != sres) + SET_EPSR_OF (1); + else + SET_EPSR_OF (0); + + if ((INT32)get_iregval (isrc2) > (INT32)(src1val)) + SET_PSR_CC (1); + else + SET_PSR_CC (0); + + /* Now update the destination register. */ + set_iregval (idest, tmp_dest_val); +} + + +/* Execute "subs #const,isrc2,idest". */ +void i860_cpu_device::insn_subs_imm (UINT32 insn) +{ + UINT32 src1val; + UINT32 isrc2 = get_isrc2 (insn); + UINT32 idest = get_idest (insn); + UINT32 tmp_dest_val = 0; + int sa, sb, sres; + + src1val = sign_ext (get_imm16 (insn), 16); + + /* We don't update the actual idest register now because below we + need to test the original src1 and src2 if either happens to + be the destination register. */ + tmp_dest_val = src1val - get_iregval (isrc2); + + /* Set OF and CC flags. + For signed: + OF = standard signed overflow. + CC set if isrc2 > isrc1 + CC clear if isrc2 <= isrc1 + */ + sa = src1val & 0x80000000; + sb = get_iregval (isrc2) & 0x80000000; + sres = tmp_dest_val & 0x80000000; + if (sa != sb && sa != sres) + SET_EPSR_OF (1); + else + SET_EPSR_OF (0); + + if ((INT32)get_iregval (isrc2) > (INT32)(src1val)) + SET_PSR_CC (1); + else + SET_PSR_CC (0); + + /* Now update the destination register. */ + set_iregval (idest, tmp_dest_val); +} + + +/* Execute "shl isrc1,isrc2,idest". */ +void i860_cpu_device::insn_shl (UINT32 insn) +{ + UINT32 src1val = 0; + UINT32 isrc2 = get_isrc2 (insn); + UINT32 idest = get_idest (insn); + + src1val = get_iregval (get_isrc1 (insn)); + set_iregval (idest, get_iregval (isrc2) << src1val); +} + + +/* Execute "shl #const,isrc2,idest". */ +void i860_cpu_device::insn_shl_imm (UINT32 insn) +{ + UINT32 src1val = 0; + UINT32 isrc2 = get_isrc2 (insn); + UINT32 idest = get_idest (insn); + + src1val = sign_ext (get_imm16 (insn), 16); + set_iregval (idest, get_iregval (isrc2) << src1val); +} + + +/* Execute "shr isrc1,isrc2,idest". */ +void i860_cpu_device::insn_shr (UINT32 insn) +{ + UINT32 src1val = 0; + UINT32 isrc2 = get_isrc2 (insn); + UINT32 idest = get_idest (insn); + + src1val = get_iregval (get_isrc1 (insn)); + + /* The iregs array is UINT32, so this is a logical shift. */ + set_iregval (idest, get_iregval (isrc2) >> src1val); + + /* shr also sets the SC in psr (shift count). */ + SET_PSR_SC (src1val); +} + + +/* Execute "shr #const,isrc2,idest". */ +void i860_cpu_device::insn_shr_imm (UINT32 insn) +{ + UINT32 src1val = 0; + UINT32 isrc2 = get_isrc2 (insn); + UINT32 idest = get_idest (insn); + + src1val = sign_ext (get_imm16 (insn), 16); + + /* The iregs array is UINT32, so this is a logical shift. */ + set_iregval (idest, get_iregval (isrc2) >> src1val); + + /* shr also sets the SC in psr (shift count). */ + SET_PSR_SC (src1val); +} + + +/* Execute "shra isrc1,isrc2,idest". */ +void i860_cpu_device::insn_shra (UINT32 insn) +{ + UINT32 src1val = 0; + UINT32 isrc2 = get_isrc2 (insn); + UINT32 idest = get_idest (insn); + + src1val = get_iregval (get_isrc1 (insn)); + + /* The iregs array is UINT32, so cast isrc2 to get arithmetic shift. */ + set_iregval (idest, (INT32)get_iregval (isrc2) >> src1val); +} + + +/* Execute "shra #const,isrc2,idest". */ +void i860_cpu_device::insn_shra_imm (UINT32 insn) +{ + UINT32 src1val = 0; + UINT32 isrc2 = get_isrc2 (insn); + UINT32 idest = get_idest (insn); + + src1val = sign_ext (get_imm16 (insn), 16); + + /* The iregs array is UINT32, so cast isrc2 to get arithmetic shift. */ + set_iregval (idest, (INT32)get_iregval (isrc2) >> src1val); +} + + +/* Execute "shrd isrc1ni,isrc2,idest" instruction. */ +void i860_cpu_device::insn_shrd (UINT32 insn) +{ + UINT32 isrc1 = get_isrc1 (insn); + UINT32 isrc2 = get_isrc2 (insn); + UINT32 idest = get_idest (insn); + UINT32 sc = GET_PSR_SC (); + UINT32 tmp; + + /* Do the operation: + idest = low_32(isrc1ni:isrc2 >> sc). */ + if (sc == 0) + tmp = get_iregval (isrc2); + else + { + tmp = get_iregval (isrc1) << (32 - sc); + tmp |= (get_iregval (isrc2) >> sc); + } + set_iregval (idest, tmp); +} + + +/* Execute "and isrc1,isrc2,idest". */ +void i860_cpu_device::insn_and (UINT32 insn) +{ + UINT32 isrc1 = get_isrc1 (insn); + UINT32 isrc2 = get_isrc2 (insn); + UINT32 idest = get_idest (insn); + UINT32 res = 0; + + /* Do the operation. */ + res = get_iregval (isrc1) & get_iregval (isrc2); + + /* Set flags. */ + if (res == 0) + SET_PSR_CC (1); + else + SET_PSR_CC (0); + + set_iregval (idest, res); +} + + +/* Execute "and #const,isrc2,idest". */ +void i860_cpu_device::insn_and_imm (UINT32 insn) +{ + UINT32 src1val = 0; + UINT32 isrc2 = get_isrc2 (insn); + UINT32 idest = get_idest (insn); + UINT32 res = 0; + + /* Do the operation. */ + src1val = get_imm16 (insn); + res = src1val & get_iregval (isrc2); + + /* Set flags. */ + if (res == 0) + SET_PSR_CC (1); + else + SET_PSR_CC (0); + + set_iregval (idest, res); +} + + +/* Execute "andh #const,isrc2,idest". */ +void i860_cpu_device::insn_andh_imm (UINT32 insn) +{ + UINT32 src1val = 0; + UINT32 isrc2 = get_isrc2 (insn); + UINT32 idest = get_idest (insn); + UINT32 res = 0; + + /* Do the operation. */ + src1val = get_imm16 (insn); + res = (src1val << 16) & get_iregval (isrc2); + + /* Set flags. */ + if (res == 0) + SET_PSR_CC (1); + else + SET_PSR_CC (0); + + set_iregval (idest, res); +} + + +/* Execute "andnot isrc1,isrc2,idest". */ +void i860_cpu_device::insn_andnot (UINT32 insn) +{ + UINT32 isrc1 = get_isrc1 (insn); + UINT32 isrc2 = get_isrc2 (insn); + UINT32 idest = get_idest (insn); + UINT32 res = 0; + + /* Do the operation. */ + res = (~get_iregval (isrc1)) & get_iregval (isrc2); + + /* Set flags. */ + if (res == 0) + SET_PSR_CC (1); + else + SET_PSR_CC (0); + + set_iregval (idest, res); +} + + +/* Execute "andnot #const,isrc2,idest". */ +void i860_cpu_device::insn_andnot_imm (UINT32 insn) +{ + UINT32 src1val = 0; + UINT32 isrc2 = get_isrc2 (insn); + UINT32 idest = get_idest (insn); + UINT32 res = 0; + + /* Do the operation. */ + src1val = get_imm16 (insn); + res = (~src1val) & get_iregval (isrc2); + + /* Set flags. */ + if (res == 0) + SET_PSR_CC (1); + else + SET_PSR_CC (0); + + set_iregval (idest, res); +} + + +/* Execute "andnoth #const,isrc2,idest". */ +void i860_cpu_device::insn_andnoth_imm (UINT32 insn) +{ + UINT32 src1val = 0; + UINT32 isrc2 = get_isrc2 (insn); + UINT32 idest = get_idest (insn); + UINT32 res = 0; + + /* Do the operation. */ + src1val = get_imm16 (insn); + res = (~(src1val << 16)) & get_iregval (isrc2); + + /* Set flags. */ + if (res == 0) + SET_PSR_CC (1); + else + SET_PSR_CC (0); + + set_iregval (idest, res); +} + + +/* Execute "or isrc1,isrc2,idest". */ +void i860_cpu_device::insn_or (UINT32 insn) +{ + UINT32 isrc1 = get_isrc1 (insn); + UINT32 isrc2 = get_isrc2 (insn); + UINT32 idest = get_idest (insn); + UINT32 res = 0; + + /* Do the operation. */ + res = get_iregval (isrc1) | get_iregval (isrc2); + + /* Set flags. */ + if (res == 0) + SET_PSR_CC (1); + else + SET_PSR_CC (0); + + set_iregval (idest, res); +} + + +/* Execute "or #const,isrc2,idest". */ +void i860_cpu_device::insn_or_imm (UINT32 insn) +{ + UINT32 src1val = 0; + UINT32 isrc2 = get_isrc2 (insn); + UINT32 idest = get_idest (insn); + UINT32 res = 0; + + /* Do the operation. */ + src1val = get_imm16 (insn); + res = src1val | get_iregval (isrc2); + + /* Set flags. */ + if (res == 0) + SET_PSR_CC (1); + else + SET_PSR_CC (0); + + set_iregval (idest, res); +} + + +/* Execute "orh #const,isrc2,idest". */ +void i860_cpu_device::insn_orh_imm (UINT32 insn) +{ + UINT32 src1val = 0; + UINT32 isrc2 = get_isrc2 (insn); + UINT32 idest = get_idest (insn); + UINT32 res = 0; + + /* Do the operation. */ + src1val = get_imm16 (insn); + res = (src1val << 16) | get_iregval (isrc2); + + /* Set flags. */ + if (res == 0) + SET_PSR_CC (1); + else + SET_PSR_CC (0); + + set_iregval (idest, res); +} + + +/* Execute "xor isrc1,isrc2,idest". */ +void i860_cpu_device::insn_xor (UINT32 insn) +{ + UINT32 isrc1 = get_isrc1 (insn); + UINT32 isrc2 = get_isrc2 (insn); + UINT32 idest = get_idest (insn); + UINT32 res = 0; + + /* Do the operation. */ + res = get_iregval (isrc1) ^ get_iregval (isrc2); + + /* Set flags. */ + if (res == 0) + SET_PSR_CC (1); + else + SET_PSR_CC (0); + + set_iregval (idest, res); +} + + +/* Execute "xor #const,isrc2,idest". */ +void i860_cpu_device::insn_xor_imm (UINT32 insn) +{ + UINT32 src1val = 0; + UINT32 isrc2 = get_isrc2 (insn); + UINT32 idest = get_idest (insn); + UINT32 res = 0; + + /* Do the operation. */ + src1val = get_imm16 (insn); + res = src1val ^ get_iregval (isrc2); + + /* Set flags. */ + if (res == 0) + SET_PSR_CC (1); + else + SET_PSR_CC (0); + + set_iregval (idest, res); +} + + +/* Execute "xorh #const,isrc2,idest". */ +void i860_cpu_device::insn_xorh_imm (UINT32 insn) +{ + UINT32 src1val = 0; + UINT32 isrc2 = get_isrc2 (insn); + UINT32 idest = get_idest (insn); + UINT32 res = 0; + + /* Do the operation. */ + src1val = get_imm16 (insn); + res = (src1val << 16) ^ get_iregval (isrc2); + + /* Set flags. */ + if (res == 0) + SET_PSR_CC (1); + else + SET_PSR_CC (0); + + set_iregval (idest, res); +} + + +/* Execute "trap isrc1ni,isrc2,idest" instruction. */ +void i860_cpu_device::insn_trap (UINT32 insn) +{ + SET_PSR_IT (1); + m_pending_trap = 1; +} + + +/* Execute "intovr" instruction. */ +void i860_cpu_device::insn_intovr (UINT32 insn) +{ + if (GET_EPSR_OF ()) + { + SET_PSR_IT (1); + m_pending_trap = 1; + } +} + + +/* Execute "bte isrc1,isrc2,sbroff". */ +void i860_cpu_device::insn_bte (UINT32 insn) +{ + UINT32 src1val = 0; + UINT32 isrc2 = get_isrc2 (insn); + UINT32 target_addr = 0; + INT32 sbroff = 0; + int res = 0; + + src1val = get_iregval (get_isrc1 (insn)); + + /* Compute the target address from the sbroff field. */ + sbroff = sign_ext ((((insn >> 5) & 0xf800) | (insn & 0x07ff)), 16); + target_addr = (INT32)m_pc + 4 + (sbroff << 2); + + /* Determine comparison result. */ + res = (src1val == get_iregval (isrc2)); + + /* Branch routines always update the PC. */ + if (res) + m_pc = target_addr; + else + m_pc += 4; + + m_pc_updated = 1; +} + + +/* Execute "bte #const5,isrc2,sbroff". */ +void i860_cpu_device::insn_bte_imm (UINT32 insn) +{ + UINT32 src1val = 0; + UINT32 isrc2 = get_isrc2 (insn); + UINT32 target_addr = 0; + INT32 sbroff = 0; + int res = 0; + + src1val = (insn >> 11) & 0x1f; /* 5-bit field, zero-extended. */ + + /* Compute the target address from the sbroff field. */ + sbroff = sign_ext ((((insn >> 5) & 0xf800) | (insn & 0x07ff)), 16); + target_addr = (INT32)m_pc + 4 + (sbroff << 2); + + /* Determine comparison result. */ + res = (src1val == get_iregval (isrc2)); + + /* Branch routines always update the PC. */ + if (res) + m_pc = target_addr; + else + m_pc += 4; + + m_pc_updated = 1; +} + + +/* Execute "btne isrc1,isrc2,sbroff". */ +void i860_cpu_device::insn_btne (UINT32 insn) +{ + UINT32 src1val = 0; + UINT32 isrc2 = get_isrc2 (insn); + UINT32 target_addr = 0; + INT32 sbroff = 0; + int res = 0; + + src1val = get_iregval (get_isrc1 (insn)); + + /* Compute the target address from the sbroff field. */ + sbroff = sign_ext ((((insn >> 5) & 0xf800) | (insn & 0x07ff)), 16); + target_addr = (INT32)m_pc + 4 + (sbroff << 2); + + /* Determine comparison result. */ + res = (src1val != get_iregval (isrc2)); + + /* Branch routines always update the PC. */ + if (res) + m_pc = target_addr; + else + m_pc += 4; + + m_pc_updated = 1; +} + + +/* Execute "btne #const5,isrc2,sbroff". */ +void i860_cpu_device::insn_btne_imm (UINT32 insn) +{ + UINT32 src1val = 0; + UINT32 isrc2 = get_isrc2 (insn); + UINT32 target_addr = 0; + INT32 sbroff = 0; + int res = 0; + + src1val = (insn >> 11) & 0x1f; /* 5-bit field, zero-extended. */ + + /* Compute the target address from the sbroff field. */ + sbroff = sign_ext ((((insn >> 5) & 0xf800) | (insn & 0x07ff)), 16); + target_addr = (INT32)m_pc + 4 + (sbroff << 2); + + /* Determine comparison result. */ + res = (src1val != get_iregval (isrc2)); + + /* Branch routines always update the PC. */ + if (res) + m_pc = target_addr; + else + m_pc += 4; + + m_pc_updated = 1; +} + + +/* Execute "bc lbroff" instruction. */ +void i860_cpu_device::insn_bc (UINT32 insn) +{ + UINT32 target_addr = 0; + INT32 lbroff = 0; + int res = 0; + + /* Compute the target address from the lbroff field. */ + lbroff = sign_ext ((insn & 0x03ffffff), 26); + target_addr = (INT32)m_pc + 4 + (lbroff << 2); + + /* Determine comparison result. */ + res = (GET_PSR_CC () == 1); + + /* Branch routines always update the PC. */ + if (res) + m_pc = target_addr; + else + m_pc += 4; + + m_pc_updated = 1; +} + + +/* Execute "bnc lbroff" instruction. */ +void i860_cpu_device::insn_bnc (UINT32 insn) +{ + UINT32 target_addr = 0; + INT32 lbroff = 0; + int res = 0; + + /* Compute the target address from the lbroff field. */ + lbroff = sign_ext ((insn & 0x03ffffff), 26); + target_addr = (INT32)m_pc + 4 + (lbroff << 2); + + /* Determine comparison result. */ + res = (GET_PSR_CC () == 0); + + /* Branch routines always update the PC, since pc_updated is set + in the decode routine. */ + if (res) + m_pc = target_addr; + else + m_pc += 4; + + m_pc_updated = 1; +} + + +/* Execute "bc.t lbroff" instruction. */ +void i860_cpu_device::insn_bct (UINT32 insn) +{ + UINT32 target_addr = 0; + INT32 lbroff = 0; + int res = 0; + UINT32 orig_pc = m_pc; + + /* Compute the target address from the lbroff field. */ + lbroff = sign_ext ((insn & 0x03ffffff), 26); + target_addr = (INT32)m_pc + 4 + (lbroff << 2); + + /* Determine comparison result. */ + res = (GET_PSR_CC () == 1); + + /* Careful. Unlike bla, the delay slot instruction is only executed + if the branch is taken. */ + if (res) + { + /* Execute delay slot instruction. */ + m_pc += 4; + decode_exec (ifetch (orig_pc + 4), 0); + m_pc = orig_pc; + if (m_pending_trap) + { + m_pending_trap |= TRAP_IN_DELAY_SLOT; + goto ab_op; + } + } + + /* Since this branch is delayed, we must jump 2 instructions if + if isn't taken. */ + if (res) + m_pc = target_addr; + else + m_pc += 8; + + m_pc_updated = 1; + + ab_op: + ; +} + + +/* Execute "bnc.t lbroff" instruction. */ +void i860_cpu_device::insn_bnct (UINT32 insn) +{ + UINT32 target_addr = 0; + INT32 lbroff = 0; + int res = 0; + UINT32 orig_pc = m_pc; + + /* Compute the target address from the lbroff field. */ + lbroff = sign_ext ((insn & 0x03ffffff), 26); + target_addr = (INT32)m_pc + 4 + (lbroff << 2); + + /* Determine comparison result. */ + res = (GET_PSR_CC () == 0); + + /* Careful. Unlike bla, the delay slot instruction is only executed + if the branch is taken. */ + if (res) + { + /* Execute delay slot instruction. */ + m_pc += 4; + decode_exec (ifetch (orig_pc + 4), 0); + m_pc = orig_pc; + if (m_pending_trap) + { + m_pending_trap |= TRAP_IN_DELAY_SLOT; + goto ab_op; + } + } + + /* Since this branch is delayed, we must jump 2 instructions if + if isn't taken. */ + if (res) + m_pc = target_addr; + else + m_pc += 8; + + m_pc_updated = 1; + + ab_op: + ; +} + + +/* Execute "call lbroff" instruction. */ +void i860_cpu_device::insn_call (UINT32 insn) +{ + UINT32 target_addr = 0; + INT32 lbroff = 0; + UINT32 orig_pc = m_pc; + + /* Compute the target address from the lbroff field. */ + lbroff = sign_ext ((insn & 0x03ffffff), 26); + target_addr = (INT32)m_pc + 4 + (lbroff << 2); + + /* Execute the delay slot instruction. */ + m_pc += 4; + decode_exec (ifetch (orig_pc + 4), 0); + m_pc = orig_pc; + if (m_pending_trap) + { + m_pending_trap |= TRAP_IN_DELAY_SLOT; + goto ab_op; + } + + /* Sets the return pointer (r1). */ + set_iregval (1, orig_pc + 8); + + /* New target. */ + m_pc = target_addr; + m_pc_updated = 1; + + ab_op:; +} + + +/* Execute "br lbroff". */ +void i860_cpu_device::insn_br (UINT32 insn) +{ + UINT32 target_addr = 0; + INT32 lbroff = 0; + UINT32 orig_pc = m_pc; + + /* Compute the target address from the lbroff field. */ + lbroff = sign_ext ((insn & 0x03ffffff), 26); + target_addr = (INT32)m_pc + 4 + (lbroff << 2); + + /* Execute the delay slot instruction. */ + m_pc += 4; + decode_exec (ifetch (orig_pc + 4), 0); + m_pc = orig_pc; + if (m_pending_trap) + { + m_pending_trap |= TRAP_IN_DELAY_SLOT; + goto ab_op; + } + + /* New target. */ + m_pc = target_addr; + m_pc_updated = 1; + + ab_op:; +} + + +/* Execute "bri isrc1ni" instruction. + Note: I didn't merge this code with calli because bri must do + a lot of flag manipulation if any trap bits are set. */ +void i860_cpu_device::insn_bri (UINT32 insn) +{ + UINT32 isrc1 = get_isrc1 (insn); + UINT32 orig_pc = m_pc; + UINT32 orig_psr = m_cregs[CR_PSR]; + UINT32 orig_src1_val = get_iregval (isrc1); + +#if 1 /* TURBO. */ + m_cregs[CR_PSR] &= ~PSR_ALL_TRAP_BITS_MASK; +#endif + + /* Execute the delay slot instruction. */ + m_pc += 4; + decode_exec (ifetch (orig_pc + 4), 0); + m_pc = orig_pc; + + /* Delay slot insn caused a trap, abort operation. */ + if (m_pending_trap) + { + m_pending_trap |= TRAP_IN_DELAY_SLOT; + goto ab_op; + } + + /* If any trap bits are set, we need to do the return from + trap work. Note, we must use the PSR value that existed + before the delay slot instruction was executed since the + delay slot instruction might itself cause a trap bit to + be set. */ + if (orig_psr & PSR_ALL_TRAP_BITS_MASK) + { + /* Restore U and IM from their previous copies. */ + SET_PSR_U (GET_PSR_PU ()); + SET_PSR_IM (GET_PSR_PIM ()); + + m_fir_gets_trap_addr = 0; + } + + /* Update PC. */ + m_pc = orig_src1_val; + + m_pc_updated = 1; + ab_op:; +} + +/* Execute "calli isrc1ni" instruction. */ +void i860_cpu_device::insn_calli (UINT32 insn) +{ + UINT32 isrc1 = get_isrc1 (insn); + UINT32 orig_pc = m_pc; + UINT32 orig_src1_val = get_iregval (isrc1); + +#ifdef TRACE_UNDEFINED_I860 + /* Check for undefined behavior. */ + if (isrc1 == 1) + { + /* Src1 must not be r1. */ + fprintf (stderr, "WARNING: insn_calli (pc=0x%08x): isrc1 = r1 on a calli\n", m_pc); + } +#endif + + /* Set return pointer before executing delay slot instruction. */ + set_iregval (1, m_pc + 8); + + /* Execute the delay slot instruction. */ + m_pc += 4; + decode_exec (ifetch (orig_pc + 4), 0); + m_pc = orig_pc; + if (m_pending_trap) + { + set_iregval (1, orig_src1_val); + m_pending_trap |= TRAP_IN_DELAY_SLOT; + goto ab_op; + } + + /* Set new PC. */ + m_pc = orig_src1_val; + m_pc_updated = 1; + + ab_op:; +} + + +/* Execute "bla isrc1ni,isrc2,sbroff" instruction. */ +void i860_cpu_device::insn_bla (UINT32 insn) +{ + UINT32 isrc1 = get_isrc1 (insn); + UINT32 isrc2 = get_isrc2 (insn); + UINT32 target_addr = 0; + INT32 sbroff = 0; + int lcc_tmp = 0; + UINT32 orig_pc = m_pc; + UINT32 orig_isrc2val = get_iregval (isrc2); + +#ifdef TRACE_UNDEFINED_I860 + /* Check for undefined behavior. */ + if (isrc1 == isrc2) + { + /* Src1 and src2 the same is undefined i860XR behavior. */ + fprintf (stderr, "WARNING: insn_bla (pc=0x%08x): isrc1 and isrc2 are the same (ignored)\n", m_pc); + return; + } +#endif + + /* Compute the target address from the sbroff field. */ + sbroff = sign_ext ((((insn >> 5) & 0xf800) | (insn & 0x07ff)), 16); + target_addr = (INT32)m_pc + 4 + (sbroff << 2); + + /* Determine comparison result based on opcode. */ + lcc_tmp = ((INT32)get_iregval (isrc2) >= -(INT32)get_iregval (isrc1)); + + set_iregval (isrc2, get_iregval (isrc1) + orig_isrc2val); + + /* Execute the delay slot instruction. */ + m_pc += 4; + decode_exec (ifetch (orig_pc + 4), 0); + m_pc = orig_pc; + if (m_pending_trap) + { + m_pending_trap |= TRAP_IN_DELAY_SLOT; + goto ab_op; + } + + if (GET_PSR_LCC ()) + m_pc = target_addr; + else + { + /* Since this branch is delayed, we must jump 2 instructions if + if isn't taken. */ + m_pc += 8; + } + SET_PSR_LCC (lcc_tmp); + + m_pc_updated = 1; + ab_op:; +} + + +/* Execute "flush #const(isrc2)" or "flush #const(isrc2)++" instruction. */ +void i860_cpu_device::insn_flush (UINT32 insn) +{ + UINT32 src1val = sign_ext (get_imm16 (insn), 16); + UINT32 isrc2 = get_isrc2 (insn); + int auto_inc = (insn & 1); + UINT32 eff = 0; + + /* Technically, idest should be encoded as r0 because idest + is undefined after the instruction. We don't currently + check for this. + + Flush D$ block at address #const+isrc2. Block is undefined + after. The effective address must be 16-byte aligned. + + FIXME: Need to examine RB and RC and do this right. + */ + + /* Chop off lower bits of displacement to 16-byte alignment. */ + src1val &= ~(16-1); + eff = src1val + get_iregval (isrc2); + if (auto_inc) + set_iregval (isrc2, eff); + + /* In user mode, the flush is ignored. */ + if (GET_PSR_U () == 0) + { + /* If line is dirty, write it to memory and invalidate. + NOTE: The actual dirty write is unimplemented in the MAME version + as we don't emulate the dcache. */ + } +} + + +/* Execute "[p]fmul.{ss,sd,dd} fsrc1,fsrc2,fdest" instruction or + pfmul3.dd fsrc1,fsrc2,fdest. + + The pfmul3.dd differs from pfmul.dd in that it treats the pipeline + as 3 stages, even though it is a double precision multiply. */ +void i860_cpu_device::insn_fmul (UINT32 insn) +{ + UINT32 fsrc1 = get_fsrc1 (insn); + UINT32 fsrc2 = get_fsrc2 (insn); + UINT32 fdest = get_fdest (insn); + int src_prec = insn & 0x100; /* 1 = double, 0 = single. */ + int res_prec = insn & 0x080; /* 1 = double, 0 = single. */ + int piped = insn & 0x400; /* 1 = pipelined, 0 = scalar. */ + double dbl_tmp_dest = 0.0; + float sgl_tmp_dest = 0.0; + double dbl_last_stage_contents = 0.0; + float sgl_last_stage_contents = 0.0; + int is_pfmul3 = insn & 0x4; + int num_stages = (src_prec && !is_pfmul3) ? 2 : 3; + + /* Only .dd is valid for pfmul. */ + if (is_pfmul3 && (insn & 0x180) != 0x180) + { + unrecog_opcode (m_pc, insn); + return; + } + + /* Check for invalid .ds combination. */ + if ((insn & 0x180) == 0x100) + { + unrecog_opcode (m_pc, insn); + return; + } + + /* For pipelined version, retrieve the contents of the last stage + of the pipeline, whose precision is specified by the MRP bit + of the stage's result-status bits. Note for pfmul, the number + of stages is determined by the source precision of the current + operation. */ + if (piped) + { + if (m_M[num_stages - 1].stat.mrp) + dbl_last_stage_contents = m_M[num_stages - 1].val.d; + else + sgl_last_stage_contents = m_M[num_stages - 1].val.s; + } + + /* Do the operation, being careful about source and result + precision. */ + if (src_prec) + { + double v1 = get_fregval_d (fsrc1); + double v2 = get_fregval_d (fsrc2); + + /* For pipelined mul, if fsrc2 is the same as fdest, then the last + stage is bypassed to fsrc2 (rather than using the value in fsrc2). + This bypass is not available for fsrc1, and is undefined behavior. */ + if (0 && piped && fdest != 0 && fsrc1 == fdest) + v1 = dbl_last_stage_contents; + if (piped && fdest != 0 && fsrc2 == fdest) + v2 = dbl_last_stage_contents; + + if (res_prec) + dbl_tmp_dest = v1 * v2; + else + sgl_tmp_dest = (float)(v1 * v2); + } + else + { + float v1 = get_fregval_s (fsrc1); + float v2 = get_fregval_s (fsrc2); + + /* For pipelined mul, if fsrc2 is the same as fdest, then the last + stage is bypassed to fsrc2 (rather than using the value in fsrc2). + This bypass is not available for fsrc1, and is undefined behavior. */ + if (0 && piped && fdest != 0 && fsrc1 == fdest) + v1 = sgl_last_stage_contents; + if (piped && fdest != 0 && fsrc2 == fdest) + v2 = sgl_last_stage_contents; + + if (res_prec) + dbl_tmp_dest = (double)(v1 * v2); + else + sgl_tmp_dest = v1 * v2; + } + + /* FIXME: Set result-status bits besides MRP. And copy to fsr from + last stage. */ + /* FIXME: Scalar version flows through all stages. */ + /* FIXME: Mixed precision (only weird for pfmul). */ + if (!piped) + { + /* Scalar version writes the current calculation to the fdest + register, with precision specified by the R bit. */ + if (res_prec) + set_fregval_d (fdest, dbl_tmp_dest); + else + set_fregval_s (fdest, sgl_tmp_dest); + } + else + { + /* Pipelined version writes fdest with the result from the last + stage of the pipeline. */ +#if 1 /* FIXME: WIP on FSR update. This may not be correct. */ + /* Copy 3rd stage MRP to FSR. */ + if (m_M[num_stages - 2 /* 1 */].stat.mrp) + m_cregs[CR_FSR] |= 0x10000000; + else + m_cregs[CR_FSR] &= ~0x10000000; +#endif + + if (m_M[num_stages - 1].stat.mrp) + set_fregval_d (fdest, dbl_last_stage_contents); + else + set_fregval_s (fdest, sgl_last_stage_contents); + + /* Now advance pipeline and write current calculation to + first stage. */ + if (num_stages == 3) + { + m_M[2] = m_M[1]; + m_M[1] = m_M[0]; + } + else + m_M[1] = m_M[0]; + + if (res_prec) + { + m_M[0].val.d = dbl_tmp_dest; + m_M[0].stat.mrp = 1; + } + else + { + m_M[0].val.s = sgl_tmp_dest; + m_M[0].stat.mrp = 0; + } + } +} + + +/* Execute "fmlow.dd fsrc1,fsrc2,fdest" instruction. */ +void i860_cpu_device::insn_fmlow (UINT32 insn) +{ + UINT32 fsrc1 = get_fsrc1 (insn); + UINT32 fsrc2 = get_fsrc2 (insn); + UINT32 fdest = get_fdest (insn); + + double v1 = get_fregval_d (fsrc1); + double v2 = get_fregval_d (fsrc2); + INT64 i1 = *(UINT64 *)&v1; + INT64 i2 = *(UINT64 *)&v2; + INT64 tmp = 0; + + /* Only .dd is valid for fmlow. */ + if ((insn & 0x180) != 0x180) + { + unrecog_opcode (m_pc, insn); + return; + } + + /* The lower 32-bits are obvious. What exactly goes in the upper + bits? + Technically, the upper-most 10 bits are undefined, but i'd like + to be undefined in the same way as the real i860 if possible. */ + + /* Keep lower 53 bits of multiply. */ + tmp = i1 * i2; + tmp &= 0x001fffffffffffffULL; + tmp |= (i1 & 0x8000000000000000LL) ^ (i2 & 0x8000000000000000LL); + set_fregval_d (fdest, *(double *)&tmp); +} + + +/* Execute [p]fadd.{ss,sd,dd} fsrc1,fsrc2,fdest (.ds disallowed above). */ +void i860_cpu_device::insn_fadd_sub (UINT32 insn) +{ + UINT32 fsrc1 = get_fsrc1 (insn); + UINT32 fsrc2 = get_fsrc2 (insn); + UINT32 fdest = get_fdest (insn); + int src_prec = insn & 0x100; /* 1 = double, 0 = single. */ + int res_prec = insn & 0x080; /* 1 = double, 0 = single. */ + int piped = insn & 0x400; /* 1 = pipelined, 0 = scalar. */ + int is_sub = insn & 1; /* 1 = sub, 0 = add. */ + double dbl_tmp_dest = 0.0; + float sgl_tmp_dest = 0.0; + double dbl_last_stage_contents = 0.0; + float sgl_last_stage_contents = 0.0; + + /* Check for invalid .ds combination. */ + if ((insn & 0x180) == 0x100) + { + unrecog_opcode (m_pc, insn); + return; + } + + /* For pipelined version, retrieve the contents of the last stage + of the pipeline, whose precision is specified by the ARP bit + of the stage's result-status bits. There are always three stages + for pfadd/pfsub. */ + if (piped) + { + if (m_A[2].stat.arp) + dbl_last_stage_contents = m_A[2].val.d; + else + sgl_last_stage_contents = m_A[2].val.s; + } + + /* Do the operation, being careful about source and result + precision. */ + if (src_prec) + { + double v1 = get_fregval_d (fsrc1); + double v2 = get_fregval_d (fsrc2); + + /* For pipelined add/sub, if fsrc1 is the same as fdest, then the last + stage is bypassed to fsrc1 (rather than using the value in fsrc1). + Likewise for fsrc2. */ + if (piped && fdest != 0 && fsrc1 == fdest) + v1 = dbl_last_stage_contents; + if (piped && fdest != 0 && fsrc2 == fdest) + v2 = dbl_last_stage_contents; + + if (res_prec) + dbl_tmp_dest = is_sub ? v1 - v2 : v1 + v2; + else + sgl_tmp_dest = is_sub ? (float)(v1 - v2) : (float)(v1 + v2); + } + else + { + float v1 = get_fregval_s (fsrc1); + float v2 = get_fregval_s (fsrc2); + + /* For pipelined add/sub, if fsrc1 is the same as fdest, then the last + stage is bypassed to fsrc1 (rather than using the value in fsrc1). + Likewise for fsrc2. */ + if (piped && fdest != 0 && fsrc1 == fdest) + v1 = sgl_last_stage_contents; + if (piped && fdest != 0 && fsrc2 == fdest) + v2 = sgl_last_stage_contents; + + if (res_prec) + dbl_tmp_dest = is_sub ? (double)(v1 - v2) : (double)(v1 + v2); + else + sgl_tmp_dest = is_sub ? v1 - v2 : v1 + v2; + } + + /* FIXME: Set result-status bits besides ARP. And copy to fsr from + last stage. */ + /* FIXME: Scalar version flows through all stages. */ + if (!piped) + { + /* Scalar version writes the current calculation to the fdest + register, with precision specified by the R bit. */ + if (res_prec) + set_fregval_d (fdest, dbl_tmp_dest); + else + set_fregval_s (fdest, sgl_tmp_dest); + } + else + { + /* Pipelined version writes fdest with the result from the last + stage of the pipeline, with precision specified by the ARP + bit of the stage's result-status bits. */ +#if 1 /* FIXME: WIP on FSR update. This may not be correct. */ + /* Copy 3rd stage ARP to FSR. */ + if (m_A[1 /* 2 */].stat.arp) + m_cregs[CR_FSR] |= 0x20000000; + else + m_cregs[CR_FSR] &= ~0x20000000; +#endif + if (m_A[2].stat.arp) /* 3rd (last) stage. */ + set_fregval_d (fdest, dbl_last_stage_contents); + else + set_fregval_s (fdest, sgl_last_stage_contents); + + /* Now advance pipeline and write current calculation to + first stage. */ + m_A[2] = m_A[1]; + m_A[1] = m_A[0]; + if (res_prec) + { + m_A[0].val.d = dbl_tmp_dest; + m_A[0].stat.arp = 1; + } + else + { + m_A[0].val.s = sgl_tmp_dest; + m_A[0].stat.arp = 0; + } + } +} + + +/* Operand types for PFAM/PFMAM routine below. */ +enum { + OP_SRC1 = 0, + OP_SRC2 = 1, + OP_KI = 2, + OP_KR = 4, + OP_T = 8, + OP_MPIPE = 16, + OP_APIPE = 32, + FLAGM = 64 /* Indicates PFMAM uses M rather than A pipe result. */ +}; + +/* A table to map DPC value to source operands. + + The PFAM and PFMAM tables are nearly identical, and the only differences + are that every time PFAM uses the A pipe, PFMAM uses the M pipe instead. + So we only represent the PFAM table and use a special flag on any entry + where the PFMAM table would use the M pipe rather than the A pipe. + Also, entry 16 is not valid for PFMAM. */ +static const struct +{ + int M_unit_op1; + int M_unit_op2; + int A_unit_op1; + int A_unit_op2; + int T_loaded; + int K_loaded; +} src_opers[] = { + /* 0000 */ { OP_KR, OP_SRC2, OP_SRC1, OP_MPIPE, 0, 0}, + /* 0001 */ { OP_KR, OP_SRC2, OP_T, OP_MPIPE, 0, 1}, + /* 0010 */ { OP_KR, OP_SRC2, OP_SRC1, OP_APIPE|FLAGM, 1, 0}, + /* 0011 */ { OP_KR, OP_SRC2, OP_T, OP_APIPE|FLAGM, 1, 1}, + /* 0100 */ { OP_KI, OP_SRC2, OP_SRC1, OP_MPIPE, 0, 0}, + /* 0101 */ { OP_KI, OP_SRC2, OP_T, OP_MPIPE, 0, 1}, + /* 0110 */ { OP_KI, OP_SRC2, OP_SRC1, OP_APIPE|FLAGM, 1, 0}, + /* 0111 */ { OP_KI, OP_SRC2, OP_T, OP_APIPE|FLAGM, 1, 1}, + /* 1000 */ { OP_KR, OP_APIPE|FLAGM, OP_SRC1, OP_SRC2, 1, 0}, + /* 1001 */ { OP_SRC1, OP_SRC2, OP_APIPE|FLAGM, OP_MPIPE, 0, 0}, + /* 1010 */ { OP_KR, OP_APIPE|FLAGM, OP_SRC1, OP_SRC2, 0, 0}, + /* 1011 */ { OP_SRC1, OP_SRC2, OP_T, OP_APIPE|FLAGM, 1, 0}, + /* 1100 */ { OP_KI, OP_APIPE|FLAGM, OP_SRC1, OP_SRC2, 1, 0}, + /* 1101 */ { OP_SRC1, OP_SRC2, OP_T, OP_MPIPE, 0, 0}, + /* 1110 */ { OP_KI, OP_APIPE|FLAGM, OP_SRC1, OP_SRC2, 0, 0}, + /* 1111 */ { OP_SRC1, OP_SRC2, OP_T, OP_APIPE|FLAGM, 0, 0} +}; + +float i860_cpu_device::get_fval_from_optype_s (UINT32 insn, int optype) +{ + float retval = 0.0; + UINT32 fsrc1 = get_fsrc1 (insn); + UINT32 fsrc2 = get_fsrc2 (insn); + + optype &= ~FLAGM; + switch (optype) + { + case OP_SRC1: + retval = get_fregval_s (fsrc1); + break; + case OP_SRC2: + retval = get_fregval_s (fsrc2); + break; + case OP_KI: + retval = m_KI.s; + break; + case OP_KR: + retval = m_KR.s; + break; + case OP_T: + retval = m_T.s; + break; + case OP_MPIPE: + /* Last stage is 3rd stage for single precision input. */ + retval = m_M[2].val.s; + break; + case OP_APIPE: + retval = m_A[2].val.s; + break; + default: + assert (0); + } + + return retval; +} + + +double i860_cpu_device::get_fval_from_optype_d (UINT32 insn, int optype) +{ + double retval = 0.0; + UINT32 fsrc1 = get_fsrc1 (insn); + UINT32 fsrc2 = get_fsrc2 (insn); + + optype &= ~FLAGM; + switch (optype) + { + case OP_SRC1: + retval = get_fregval_d (fsrc1); + break; + case OP_SRC2: + retval = get_fregval_d (fsrc2); + break; + case OP_KI: + retval = m_KI.d; + break; + case OP_KR: + retval = m_KR.d; + break; + case OP_T: + retval = m_T.d; + break; + case OP_MPIPE: + /* Last stage is 2nd stage for double precision input. */ + retval = m_M[1].val.d; + break; + case OP_APIPE: + retval = m_A[2].val.d; + break; + default: + assert (0); + } + + return retval; +} + + +/* Execute pf[m]{a,s}m.{ss,sd,dd} fsrc1,fsrc2,fdest (FP dual ops). + + Since these are always pipelined, the P bit is used to distinguish + family pfam (P=1) from family pfmam (P=0), and the lower 4 bits + of the extended opcode is the DPC. + + Note also that the S and R bits are slightly different than normal + floating point operations. The S bit denotes the precision of the + multiplication source, while the R bit denotes the precision of + the addition source as well as precision of all results. */ +void i860_cpu_device::insn_dualop (UINT32 insn) +{ + UINT32 fsrc1 = get_fsrc1 (insn); + UINT32 fsrc2 = get_fsrc2 (insn); + UINT32 fdest = get_fdest (insn); + int src_prec = insn & 0x100; /* 1 = double, 0 = single. */ + int res_prec = insn & 0x080; /* 1 = double, 0 = single. */ + int is_pfam = insn & 0x400; /* 1 = pfam, 0 = pfmam. */ + int is_sub = insn & 0x10; /* 1 = pf[m]sm, 0 = pf[m]am. */ + double dbl_tmp_dest_mul = 0.0; + float sgl_tmp_dest_mul = 0.0; + double dbl_tmp_dest_add = 0.0; + float sgl_tmp_dest_add = 0.0; + double dbl_last_Mstage_contents = 0.0; + float sgl_last_Mstage_contents = 0.0; + double dbl_last_Astage_contents = 0.0; + float sgl_last_Astage_contents = 0.0; + int num_mul_stages = src_prec ? 2 : 3; + + int dpc = insn & 0xf; + int M_unit_op1 = src_opers[dpc].M_unit_op1; + int M_unit_op2 = src_opers[dpc].M_unit_op2; + int A_unit_op1 = src_opers[dpc].A_unit_op1; + int A_unit_op2 = src_opers[dpc].A_unit_op2; + int T_loaded = src_opers[dpc].T_loaded; + int K_loaded = src_opers[dpc].K_loaded; + + /* Check for invalid .ds combination. */ + if ((insn & 0x180) == 0x100) + { + unrecog_opcode (m_pc, insn); + return; + } + + if (is_pfam == 0) + { + /* Check for invalid DPC combination 16 for PFMAM. */ + if (dpc == 16) + { + unrecog_opcode (m_pc, insn); + return; + } + + /* PFMAM table adjustments (M_unit_op1 is never a pipe stage, + so no adjustment made for it). */ + M_unit_op2 = (M_unit_op2 & FLAGM) ? OP_MPIPE : M_unit_op2; + A_unit_op1 = (A_unit_op1 & FLAGM) ? OP_MPIPE : A_unit_op1; + A_unit_op2 = (A_unit_op2 & FLAGM) ? OP_MPIPE : A_unit_op2; + } + + /* FIXME: Check for fsrc1/fdest overlap for some mul DPC combinations. */ + + /* Retrieve the contents of the last stage of the multiplier pipeline, + whose precision is specified by the MRP bit of the stage's result- + status bits. Note for multiply, the number of stages is determined + by the source precision of the current operation. */ + if (m_M[num_mul_stages - 1].stat.mrp) + dbl_last_Mstage_contents = m_M[num_mul_stages - 1].val.d; + else + sgl_last_Mstage_contents = m_M[num_mul_stages - 1].val.s; + + /* Similarly, retrieve the last stage of the adder pipe. */ + if (m_A[2].stat.arp) + dbl_last_Astage_contents = m_A[2].val.d; + else + sgl_last_Astage_contents = m_A[2].val.s; + + /* Do the mul operation, being careful about source and result + precision. */ + if (src_prec) + { + double v1 = get_fval_from_optype_d (insn, M_unit_op1); + double v2 = get_fval_from_optype_d (insn, M_unit_op2); + + /* For mul, if fsrc2 is the same as fdest, then the last stage + is bypassed to fsrc2 (rather than using the value in fsrc2). + This bypass is not available for fsrc1, and is undefined behavior. */ + if (0 && M_unit_op1 == OP_SRC1 && fdest != 0 && fsrc1 == fdest) + v1 = is_pfam ? dbl_last_Astage_contents : dbl_last_Mstage_contents; + if (M_unit_op2 == OP_SRC2 && fdest != 0 && fsrc2 == fdest) + v2 = is_pfam ? dbl_last_Astage_contents : dbl_last_Mstage_contents; + + if (res_prec) + dbl_tmp_dest_mul = v1 * v2; + else + sgl_tmp_dest_mul = (float)(v1 * v2); + } + else + { + float v1 = get_fval_from_optype_s (insn, M_unit_op1); + float v2 = get_fval_from_optype_s (insn, M_unit_op2); + + /* For mul, if fsrc2 is the same as fdest, then the last stage + is bypassed to fsrc2 (rather than using the value in fsrc2). + This bypass is not available for fsrc1, and is undefined behavior. */ + if (0 && M_unit_op1 == OP_SRC1 && fdest != 0 && fsrc1 == fdest) + v1 = is_pfam ? sgl_last_Astage_contents : sgl_last_Mstage_contents; + if (M_unit_op2 == OP_SRC2 && fdest != 0 && fsrc2 == fdest) + v2 = is_pfam ? sgl_last_Astage_contents : sgl_last_Mstage_contents; + + if (res_prec) + dbl_tmp_dest_mul = (double)(v1 * v2); + else + sgl_tmp_dest_mul = v1 * v2; + } + + /* Do the add operation, being careful about source and result + precision. Remember, the R bit indicates source and result precision + here. */ + if (res_prec) + { + double v1 = get_fval_from_optype_d (insn, A_unit_op1); + double v2 = get_fval_from_optype_d (insn, A_unit_op2); + + /* For add/sub, if fsrc1 is the same as fdest, then the last stage + is bypassed to fsrc1 (rather than using the value in fsrc1). + Likewise for fsrc2. */ + if (A_unit_op1 == OP_SRC1 && fdest != 0 && fsrc1 == fdest) + v1 = is_pfam ? dbl_last_Astage_contents : dbl_last_Mstage_contents; + if (A_unit_op2 == OP_SRC2 && fdest != 0 && fsrc2 == fdest) + v2 = is_pfam ? dbl_last_Astage_contents : dbl_last_Mstage_contents; + + if (res_prec) + dbl_tmp_dest_add = is_sub ? v1 - v2 : v1 + v2; + else + sgl_tmp_dest_add = is_sub ? (float)(v1 - v2) : (float)(v1 + v2); + } + else + { + float v1 = get_fval_from_optype_s (insn, A_unit_op1); + float v2 = get_fval_from_optype_s (insn, A_unit_op2); + + /* For add/sub, if fsrc1 is the same as fdest, then the last stage + is bypassed to fsrc1 (rather than using the value in fsrc1). + Likewise for fsrc2. */ + if (A_unit_op1 == OP_SRC1 && fdest != 0 && fsrc1 == fdest) + v1 = is_pfam ? sgl_last_Astage_contents : sgl_last_Mstage_contents; + if (A_unit_op2 == OP_SRC2 && fdest != 0 && fsrc2 == fdest) + v2 = is_pfam ? sgl_last_Astage_contents : sgl_last_Mstage_contents; + + if (res_prec) + dbl_tmp_dest_add = is_sub ? (double)(v1 - v2) : (double)(v1 + v2); + else + sgl_tmp_dest_add = is_sub ? v1 - v2 : v1 + v2; + } + + /* If necessary, load T. */ + if (T_loaded) + { + /* T is loaded from the result of the last stage of the multiplier. */ + if (m_M[num_mul_stages - 1].stat.mrp) + m_T.d = dbl_last_Mstage_contents; + else + m_T.s = sgl_last_Mstage_contents; + } + + /* If necessary, load KR or KI. */ + if (K_loaded) + { + /* KI or KR is loaded from the first register input. */ + if (M_unit_op1 == OP_KI) + { + if (src_prec) + m_KI.d = get_fregval_d (fsrc1); + else + m_KI.s = get_fregval_s (fsrc1); + } + else if (M_unit_op1 == OP_KR) + { + if (src_prec) + m_KR.d = get_fregval_d (fsrc1); + else + m_KR.s = get_fregval_s (fsrc1); + } + else + assert (0); + } + + /* Now update fdest (either from adder pipe or multiplier pipe, + depending on whether the instruction is pfam or pfmam). */ + if (is_pfam) + { + /* Update fdest with the result from the last stage of the + adder pipeline, with precision specified by the ARP + bit of the stage's result-status bits. */ + if (m_A[2].stat.arp) + set_fregval_d (fdest, dbl_last_Astage_contents); + else + set_fregval_s (fdest, sgl_last_Astage_contents); + } + else + { + /* Update fdest with the result from the last stage of the + multiplier pipeline, with precision specified by the MRP + bit of the stage's result-status bits. */ + if (m_M[num_mul_stages - 1].stat.mrp) + set_fregval_d (fdest, dbl_last_Mstage_contents); + else + set_fregval_s (fdest, sgl_last_Mstage_contents); + } + + /* FIXME: Set result-status bits besides MRP. And copy to fsr from + last stage. */ + /* FIXME: Mixed precision (only weird for pfmul). */ +#if 1 /* FIXME: WIP on FSR update. This may not be correct. */ + /* Copy 3rd stage MRP to FSR. */ + if (m_M[num_mul_stages - 2 /* 1 */].stat.mrp) + m_cregs[CR_FSR] |= 0x10000000; + else + m_cregs[CR_FSR] &= ~0x10000000; +#endif + + /* Now advance multiplier pipeline and write current calculation to + first stage. */ + if (num_mul_stages == 3) + { + m_M[2] = m_M[1]; + m_M[1] = m_M[0]; + } + else + m_M[1] = m_M[0]; + + if (res_prec) + { + m_M[0].val.d = dbl_tmp_dest_mul; + m_M[0].stat.mrp = 1; + } + else + { + m_M[0].val.s = sgl_tmp_dest_mul; + m_M[0].stat.mrp = 0; + } + + /* FIXME: Set result-status bits besides ARP. And copy to fsr from + last stage. */ +#if 1 /* FIXME: WIP on FSR update. This may not be correct. */ + /* Copy 3rd stage ARP to FSR. */ + if (m_A[1 /* 2 */].stat.arp) + m_cregs[CR_FSR] |= 0x20000000; + else + m_cregs[CR_FSR] &= ~0x20000000; +#endif + + /* Now advance adder pipeline and write current calculation to + first stage. */ + m_A[2] = m_A[1]; + m_A[1] = m_A[0]; + if (res_prec) + { + m_A[0].val.d = dbl_tmp_dest_add; + m_A[0].stat.arp = 1; + } + else + { + m_A[0].val.s = sgl_tmp_dest_add; + m_A[0].stat.arp = 0; + } +} + + +/* Execute frcp.{ss,sd,dd} fsrc2,fdest (.ds disallowed above). */ +void i860_cpu_device::insn_frcp (UINT32 insn) +{ + UINT32 fsrc2 = get_fsrc2 (insn); + UINT32 fdest = get_fdest (insn); + int src_prec = insn & 0x100; /* 1 = double, 0 = single. */ + int res_prec = insn & 0x080; /* 1 = double, 0 = single. */ + + /* Do the operation, being careful about source and result + precision. */ + if (src_prec) + { + double v = get_fregval_d (fsrc2); + double res; + if (v == (double)0.0) + { + /* Generate source-exception trap if fsrc2 is 0. */ + if (0 /* && GET_FSR_FTE () */) + { + SET_PSR_FT (1); + SET_FSR_SE (1); + m_pending_trap = GET_FSR_FTE (); + } + /* Set fdest to INF or some other exceptional value here? */ + } + else + { + /* Real i860 isn't a precise as a real divide, but this should + be okay. */ + SET_FSR_SE (0); + *((UINT64 *)&v) &= 0xfffff00000000000ULL; + res = (double)1.0/v; + *((UINT64 *)&res) &= 0xfffff00000000000ULL; + if (res_prec) + set_fregval_d (fdest, res); + else + set_fregval_s (fdest, (float)res); + } + } + else + { + float v = get_fregval_s (fsrc2); + float res; + if (v == 0.0f) + { + /* Generate source-exception trap if fsrc2 is 0. */ + if (0 /* GET_FSR_FTE () */) + { + SET_PSR_FT (1); + SET_FSR_SE (1); + m_pending_trap = GET_FSR_FTE (); + } + /* Set fdest to INF or some other exceptional value here? */ + } + else + { + /* Real i860 isn't a precise as a real divide, but this should + be okay. */ + SET_FSR_SE (0); + *((UINT32 *)&v) &= 0xffff8000; + res = (float)1.0/v; + *((UINT32 *)&res) &= 0xffff8000; + if (res_prec) + set_fregval_d (fdest, (double)res); + else + set_fregval_s (fdest, res); + } + } +} + + +/* Execute frsqr.{ss,sd,dd} fsrc2,fdest (.ds disallowed above). */ +void i860_cpu_device::insn_frsqr (UINT32 insn) +{ + UINT32 fsrc2 = get_fsrc2 (insn); + UINT32 fdest = get_fdest (insn); + int src_prec = insn & 0x100; /* 1 = double, 0 = single. */ + int res_prec = insn & 0x080; /* 1 = double, 0 = single. */ + + /* Check for invalid .ds combination. */ + if ((insn & 0x180) == 0x100) + { + unrecog_opcode (m_pc, insn); + return; + } + + /* Check for invalid .ds combination. */ + if ((insn & 0x180) == 0x100) + { + unrecog_opcode (m_pc, insn); + return; + } + + /* Do the operation, being careful about source and result + precision. */ + if (src_prec) + { + double v = get_fregval_d (fsrc2); + double res; + if (v == 0.0 || v < 0.0) + { + /* Generate source-exception trap if fsrc2 is 0 or negative. */ + if (0 /* GET_FSR_FTE () */) + { + SET_PSR_FT (1); + SET_FSR_SE (1); + m_pending_trap = GET_FSR_FTE (); + } + /* Set fdest to INF or some other exceptional value here? */ + } + else + { + SET_FSR_SE (0); + *((UINT64 *)&v) &= 0xfffff00000000000ULL; + res = (double)1.0/sqrt (v); + *((UINT64 *)&res) &= 0xfffff00000000000ULL; + if (res_prec) + set_fregval_d (fdest, res); + else + set_fregval_s (fdest, (float)res); + } + } + else + { + float v = get_fregval_s (fsrc2); + float res; + if (v == 0.0f || v < 0.0f) + { + /* Generate source-exception trap if fsrc2 is 0 or negative. */ + if (0 /* GET_FSR_FTE () */) + { + SET_PSR_FT (1); + SET_FSR_SE (1); + m_pending_trap = GET_FSR_FTE (); + } + /* Set fdest to INF or some other exceptional value here? */ + } + else + { + SET_FSR_SE (0); + *((UINT32 *)&v) &= 0xffff8000; + // FIXME: shouldn't this be 1.0f / sqrtf(v) ? + res = (float) (1.0/sqrt (v)); + *((UINT32 *)&res) &= 0xffff8000; + if (res_prec) + set_fregval_d (fdest, (double)res); + else + set_fregval_s (fdest, res); + } + } +} + + +/* Execute fxfr fsrc1,idest. */ +void i860_cpu_device::insn_fxfr (UINT32 insn) +{ + UINT32 fsrc1 = get_fsrc1 (insn); + UINT32 idest = get_idest (insn); + float fv = 0; + + /* This is a bit-pattern transfer, not a conversion. */ + fv = get_fregval_s (fsrc1); + set_iregval (idest, *(UINT32 *)&fv); +} + + +/* Execute [p]ftrunc.{ss,sd,dd} fsrc1,idest. */ +/* FIXME: Is .ss really a valid combination? On the one hand, + the programmer's reference (1990) lists ftrunc.p where .p + is any of {ss,sd,dd}. On the other hand, a paragraph on the + same page states that [p]ftrunc must specify double-precision + results. Inconsistent. + Update: The vendor SVR4 assembler does not accept .ss combination, + so the latter sentence above appears to be the correct way. */ +void i860_cpu_device::insn_ftrunc (UINT32 insn) +{ + UINT32 fsrc1 = get_fsrc1 (insn); + UINT32 fdest = get_fdest (insn); + int src_prec = insn & 0x100; /* 1 = double, 0 = single. */ + int res_prec = insn & 0x080; /* 1 = double, 0 = single. */ + int piped = insn & 0x400; /* 1 = pipelined, 0 = scalar. */ + + /* Check for invalid .ds or .ss combinations. */ + if ((insn & 0x080) == 0) + { + unrecog_opcode (m_pc, insn); + return; + } + + /* Do the operation, being careful about source and result + precision. Operation: fdest = integer part of fsrc1 in + lower 32-bits. */ + if (src_prec) + { + double v1 = get_fregval_d (fsrc1); + INT32 iv = (INT32)v1; + /* We always write a single, since the lower 32-bits of fdest + get the result (and the even numbered reg is the lower). */ + set_fregval_s (fdest, *(float *)&iv); + } + else + { + float v1 = get_fregval_s (fsrc1); + INT32 iv = (INT32)v1; + /* We always write a single, since the lower 32-bits of fdest + get the result (and the even numbered reg is the lower). */ + set_fregval_s (fdest, *(float *)&iv); + } + + /* FIXME: Handle updating of pipestages for pftrunc. */ + /* Includes looking at ARP (add result precision.) */ + if (piped) + { + fprintf (stderr, "insn_ftrunc: FIXME: pipelined not functional yet.\n"); + if (res_prec) + set_fregval_d (fdest, 0.0); + else + set_fregval_s (fdest, 0.0); + } +} + + +/* Execute [p]famov.{ss,sd,ds,dd} fsrc1,fdest. */ +void i860_cpu_device::insn_famov (UINT32 insn) +{ + UINT32 fsrc1 = get_fsrc1 (insn); + UINT32 fdest = get_fdest (insn); + int src_prec = insn & 0x100; /* 1 = double, 0 = single. */ + int res_prec = insn & 0x080; /* 1 = double, 0 = single. */ + int piped = insn & 0x400; /* 1 = pipelined, 0 = scalar. */ + double dbl_tmp_dest = 0.0; + double sgl_tmp_dest = 0.0; + + /* Do the operation, being careful about source and result + precision. */ + if (src_prec) + { + double v1 = get_fregval_d (fsrc1); + if (res_prec) + dbl_tmp_dest = v1; + else + sgl_tmp_dest = (float)v1; + } + else + { + float v1 = get_fregval_s (fsrc1); + if (res_prec) + dbl_tmp_dest = (double)v1; + else + sgl_tmp_dest = v1; + } + + /* FIXME: Set result-status bits besides ARP. And copy to fsr from + last stage. */ + /* FIXME: Scalar version flows through all stages. */ + if (!piped) + { + /* Scalar version writes the current calculation to the fdest + register, with precision specified by the R bit. */ + if (res_prec) + set_fregval_d (fdest, dbl_tmp_dest); + else + set_fregval_s (fdest, sgl_tmp_dest); + } + else + { + /* Pipelined version writes fdest with the result from the last + stage of the pipeline, with precision specified by the ARP + bit of the stage's result-status bits. */ +#if 1 /* FIXME: WIP on FSR update. This may not be correct. */ + /* Copy 3rd stage ARP to FSR. */ + if (m_A[1 /* 2 */].stat.arp) + m_cregs[CR_FSR] |= 0x20000000; + else + m_cregs[CR_FSR] &= ~0x20000000; +#endif + if (m_A[2].stat.arp) /* 3rd (last) stage. */ + set_fregval_d (fdest, m_A[2].val.d); + else + set_fregval_s (fdest, m_A[2].val.s); + + /* Now advance pipeline and write current calculation to + first stage. */ + m_A[2] = m_A[1]; + m_A[1] = m_A[0]; + if (res_prec) + { + m_A[0].val.d = dbl_tmp_dest; + m_A[0].stat.arp = 1; + } + else + { + m_A[0].val.s = sgl_tmp_dest; + m_A[0].stat.arp = 0; + } + } +} + + +/* Execute [p]fiadd/sub.{ss,dd} fsrc1,fsrc2,fdest. */ +void i860_cpu_device::insn_fiadd_sub (UINT32 insn) +{ + UINT32 fsrc1 = get_fsrc1 (insn); + UINT32 fsrc2 = get_fsrc2 (insn); + UINT32 fdest = get_fdest (insn); + int src_prec = insn & 0x100; /* 1 = double, 0 = single. */ + int res_prec = insn & 0x080; /* 1 = double, 0 = single. */ + int piped = insn & 0x400; /* 1 = pipelined, 0 = scalar. */ + int is_sub = insn & 0x4; /* 1 = sub, 0 = add. */ + double dbl_tmp_dest = 0.0; + float sgl_tmp_dest = 0.0; + + /* Check for invalid .ds and .sd combinations. */ + if ((insn & 0x180) == 0x100 + || (insn & 0x180) == 0x080) + { + unrecog_opcode (m_pc, insn); + return; + } + + /* Do the operation, being careful about source and result + precision. */ + if (src_prec) + { + double v1 = get_fregval_d (fsrc1); + double v2 = get_fregval_d (fsrc2); + UINT64 iv1 = *(UINT64 *)&v1; + UINT64 iv2 = *(UINT64 *)&v2; + UINT64 r; + if (is_sub) + r = iv1 - iv2; + else + r = iv1 + iv2; + if (res_prec) + dbl_tmp_dest = *(double *)&r; + else + assert (0); /* .ds not allowed. */ + } + else + { + float v1 = get_fregval_s (fsrc1); + float v2 = get_fregval_s (fsrc2); + UINT64 iv1 = (UINT64)(*(UINT32 *)&v1); + UINT64 iv2 = (UINT64)(*(UINT32 *)&v2); + UINT32 r; + if (is_sub) + r = (UINT32)(iv1 - iv2); + else + r = (UINT32)(iv1 + iv2); + if (res_prec) + assert (0); /* .sd not allowed. */ + else + sgl_tmp_dest = *(float *)&r; + } + + /* FIXME: Copy result-status bit IRP to fsr from last stage. */ + /* FIXME: Scalar version flows through all stages. */ + if (!piped) + { + /* Scalar version writes the current calculation to the fdest + register, with precision specified by the R bit. */ + if (res_prec) + set_fregval_d (fdest, dbl_tmp_dest); + else + set_fregval_s (fdest, sgl_tmp_dest); + } + else + { + /* Pipelined version writes fdest with the result from the last + stage of the pipeline, with precision specified by the IRP + bit of the stage's result-status bits. */ +#if 1 /* FIXME: WIP on FSR update. This may not be correct. */ + /* Copy stage IRP to FSR. */ + if (res_prec) + m_cregs[CR_FSR] |= 0x08000000; + else + m_cregs[CR_FSR] &= ~0x08000000; +#endif + if (m_G.stat.irp) /* 1st (and last) stage. */ + set_fregval_d (fdest, m_G.val.d); + else + set_fregval_s (fdest, m_G.val.s); + + /* Now write current calculation to first and only stage. */ + if (res_prec) + { + m_G.val.d = dbl_tmp_dest; + m_G.stat.irp = 1; + } + else + { + m_G.val.s = sgl_tmp_dest; + m_G.stat.irp = 0; + } + } +} + + +/* Execute pf{gt,le,eq}.{ss,dd} fsrc1,fsrc2,fdest. + Opcode pfgt has R bit cleared; pfle has R bit set. */ +void i860_cpu_device::insn_fcmp (UINT32 insn) +{ + UINT32 fsrc1 = get_fsrc1 (insn); + UINT32 fsrc2 = get_fsrc2 (insn); + UINT32 fdest = get_fdest (insn); + int src_prec = insn & 0x100; /* 1 = double, 0 = single. */ + double dbl_tmp_dest = 0.0; + double sgl_tmp_dest = 0.0; + /* int is_eq = insn & 1; */ + int is_gt = ((insn & 0x81) == 0x00); + int is_le = ((insn & 0x81) == 0x80); + + /* Do the operation. Source and result precision must be the same. + pfgt: CC set if fsrc1 > fsrc2, else cleared. + pfle: CC cleared if fsrc1 <= fsrc2, else set. + pfeq: CC set if fsrc1 = fsrc2, else cleared. + + Note that the compares write an undefined (but non-exceptional) + result into the first stage of the adder pipeline. We'll model + this by just pushing in dbl_ or sgl_tmp_dest which equal 0.0. */ + if (src_prec) + { + double v1 = get_fregval_d (fsrc1); + double v2 = get_fregval_d (fsrc2); + if (is_gt) /* gt. */ + SET_PSR_CC (v1 > v2 ? 1 : 0); + else if (is_le) /* le. */ + SET_PSR_CC (v1 <= v2 ? 0 : 1); + else /* eq. */ + SET_PSR_CC (v1 == v2 ? 1 : 0); + } + else + { + float v1 = get_fregval_s (fsrc1); + float v2 = get_fregval_s (fsrc2); + if (is_gt) /* gt. */ + SET_PSR_CC (v1 > v2 ? 1 : 0); + else if (is_le) /* le. */ + SET_PSR_CC (v1 <= v2 ? 0 : 1); + else /* eq. */ + SET_PSR_CC (v1 == v2 ? 1 : 0); + } + + /* FIXME: Set result-status bits besides ARP. And copy to fsr from + last stage. */ + /* These write fdest with the result from the last + stage of the pipeline, with precision specified by the ARP + bit of the stage's result-status bits. */ +#if 1 /* FIXME: WIP on FSR update. This may not be correct. */ + /* Copy 3rd stage ARP to FSR. */ + if (m_A[1 /* 2 */].stat.arp) + m_cregs[CR_FSR] |= 0x20000000; + else + m_cregs[CR_FSR] &= ~0x20000000; +#endif + if (m_A[2].stat.arp) /* 3rd (last) stage. */ + set_fregval_d (fdest, m_A[2].val.d); + else + set_fregval_s (fdest, m_A[2].val.s); + + /* Now advance pipeline and write current calculation to + first stage. */ + m_A[2] = m_A[1]; + m_A[1] = m_A[0]; + if (src_prec) + { + m_A[0].val.d = dbl_tmp_dest; + m_A[0].stat.arp = 1; + } + else + { + m_A[0].val.s = sgl_tmp_dest; + m_A[0].stat.arp = 0; + } +} + + +/* Execute [p]fzchk{l,s} fsrc1,fsrc2,fdest. + The fzchk instructions have S and R bits set. */ +void i860_cpu_device::insn_fzchk (UINT32 insn) +{ + UINT32 fsrc1 = get_fsrc1 (insn); + UINT32 fsrc2 = get_fsrc2 (insn); + UINT32 fdest = get_fdest (insn); + int piped = insn & 0x400; /* 1 = pipelined, 0 = scalar. */ + int is_fzchks = insn & 8; /* 1 = fzchks, 0 = fzchkl. */ + double dbl_tmp_dest = 0.0; + int i; + double v1 = get_fregval_d (fsrc1); + double v2 = get_fregval_d (fsrc2); + UINT64 iv1 = *(UINT64 *)&v1; + UINT64 iv2 = *(UINT64 *)&v2; + UINT64 r = 0; + char pm = GET_PSR_PM (); + + /* Check for S and R bits set. */ + if ((insn & 0x180) != 0x180) + { + unrecog_opcode (m_pc, insn); + return; + } + + /* Do the operation. The fzchks version operates in parallel on + four 16-bit pixels, while the fzchkl operates on two 32-bit + pixels (pixels are unsigned ordinals in this context). */ + if (is_fzchks) + { + pm = (pm >> 4) & 0x0f; + for (i = 3; i >= 0; i--) + { + UINT16 ps1 = (iv1 >> (i * 16)) & 0xffff; + UINT16 ps2 = (iv2 >> (i * 16)) & 0xffff; + if (ps2 <= ps1) + { + r |= ((UINT64)ps2 << (i * 16)); + pm |= (1 << (7 - (3 - i))); + } + else + { + r |= ((UINT64)ps1 << (i * 16)); + pm &= ~(1 << (7 - (3 - i))); + } + } + } + else + { + pm = (pm >> 2) & 0x3f; + for (i = 1; i >= 0; i--) + { + UINT32 ps1 = (iv1 >> (i * 32)) & 0xffffffff; + UINT32 ps2 = (iv2 >> (i * 32)) & 0xffffffff; + if (ps2 <= ps1) + { + r |= ((UINT64)ps2 << (i * 32)); + pm |= (1 << (7 - (1 - i))); + } + else + { + r |= ((UINT64)ps1 << (i * 32)); + pm &= ~(1 << (7 - (1 - i))); + } + } + } + + dbl_tmp_dest = *(double *)&r; + SET_PSR_PM (pm); + m_merge = 0; + + /* FIXME: Copy result-status bit IRP to fsr from last stage. */ + /* FIXME: Scalar version flows through all stages. */ + if (!piped) + { + /* Scalar version writes the current calculation to the fdest + register, always with double precision. */ + set_fregval_d (fdest, dbl_tmp_dest); + } + else + { + /* Pipelined version writes fdest with the result from the last + stage of the pipeline, with precision specified by the IRP + bit of the stage's result-status bits. */ + if (m_G.stat.irp) /* 1st (and last) stage. */ + set_fregval_d (fdest, m_G.val.d); + else + set_fregval_s (fdest, m_G.val.s); + + /* Now write current calculation to first and only stage. */ + m_G.val.d = dbl_tmp_dest; + m_G.stat.irp = 1; + } +} + + +/* Execute [p]form.dd fsrc1,fdest. + The form.dd instructions have S and R bits set. */ +void i860_cpu_device::insn_form (UINT32 insn) +{ + UINT32 fsrc1 = get_fsrc1 (insn); + UINT32 fdest = get_fdest (insn); + int piped = insn & 0x400; /* 1 = pipelined, 0 = scalar. */ + double dbl_tmp_dest = 0.0; + double v1 = get_fregval_d (fsrc1); + UINT64 iv1 = *(UINT64 *)&v1; + + /* Check for S and R bits set. */ + if ((insn & 0x180) != 0x180) + { + unrecog_opcode (m_pc, insn); + return; + } + + iv1 |= m_merge; + dbl_tmp_dest = *(double *)&iv1; + m_merge = 0; + + /* FIXME: Copy result-status bit IRP to fsr from last stage. */ + /* FIXME: Scalar version flows through all stages. */ + if (!piped) + { + /* Scalar version writes the current calculation to the fdest + register, always with double precision. */ + set_fregval_d (fdest, dbl_tmp_dest); + } + else + { + /* Pipelined version writes fdest with the result from the last + stage of the pipeline, with precision specified by the IRP + bit of the stage's result-status bits. */ + if (m_G.stat.irp) /* 1st (and last) stage. */ + set_fregval_d (fdest, m_G.val.d); + else + set_fregval_s (fdest, m_G.val.s); + + /* Now write current calculation to first and only stage. */ + m_G.val.d = dbl_tmp_dest; + m_G.stat.irp = 1; + } +} + + +/* Execute [p]faddp fsrc1,fsrc2,fdest. */ +void i860_cpu_device::insn_faddp (UINT32 insn) +{ + UINT32 fsrc1 = get_fsrc1 (insn); + UINT32 fsrc2 = get_fsrc2 (insn); + UINT32 fdest = get_fdest (insn); + int piped = insn & 0x400; /* 1 = pipelined, 0 = scalar. */ + double dbl_tmp_dest = 0.0; + double v1 = get_fregval_d (fsrc1); + double v2 = get_fregval_d (fsrc2); + UINT64 iv1 = *(UINT64 *)&v1; + UINT64 iv2 = *(UINT64 *)&v2; + UINT64 r = 0; + int ps = GET_PSR_PS (); + + r = iv1 + iv2; + dbl_tmp_dest = *(double *)&r; + + /* Update the merge register depending on the pixel size. + PS: 0 = 8 bits, 1 = 16 bits, 2 = 32-bits. */ + if (ps == 0) + { + m_merge = ((m_merge >> 8) & ~0xff00ff00ff00ff00ULL); + m_merge |= (r & 0xff00ff00ff00ff00ULL); + } + else if (ps == 1) + { + m_merge = ((m_merge >> 6) & ~0xfc00fc00fc00fc00ULL); + m_merge |= (r & 0xfc00fc00fc00fc00ULL); + } + else if (ps == 2) + { + m_merge = ((m_merge >> 8) & ~0xff000000ff000000ULL); + m_merge |= (r & 0xff000000ff000000ULL); + } +#ifdef TRACE_UNDEFINED_I860 + else + fprintf (stderr, "insn_faddp: Undefined i860XR behavior, invalid value %d for pixel size.\n", ps); +#endif + + /* FIXME: Copy result-status bit IRP to fsr from last stage. */ + /* FIXME: Scalar version flows through all stages. */ + if (!piped) + { + /* Scalar version writes the current calculation to the fdest + register, always with double precision. */ + set_fregval_d (fdest, dbl_tmp_dest); + } + else + { + /* Pipelined version writes fdest with the result from the last + stage of the pipeline, with precision specified by the IRP + bit of the stage's result-status bits. */ + if (m_G.stat.irp) /* 1st (and last) stage. */ + set_fregval_d (fdest, m_G.val.d); + else + set_fregval_s (fdest, m_G.val.s); + + /* Now write current calculation to first and only stage. */ + m_G.val.d = dbl_tmp_dest; + m_G.stat.irp = 1; + } +} + + +/* Execute [p]faddz fsrc1,fsrc2,fdest. */ +void i860_cpu_device::insn_faddz (UINT32 insn) +{ + UINT32 fsrc1 = get_fsrc1 (insn); + UINT32 fsrc2 = get_fsrc2 (insn); + UINT32 fdest = get_fdest (insn); + int piped = insn & 0x400; /* 1 = pipelined, 0 = scalar. */ + double dbl_tmp_dest = 0.0; + double v1 = get_fregval_d (fsrc1); + double v2 = get_fregval_d (fsrc2); + UINT64 iv1 = *(UINT64 *)&v1; + UINT64 iv2 = *(UINT64 *)&v2; + UINT64 r = 0; + + r = iv1 + iv2; + dbl_tmp_dest = *(double *)&r; + + /* Update the merge register depending on the pixel size. */ + m_merge = ((m_merge >> 16) & ~0xffff0000ffff0000ULL); + m_merge |= (r & 0xffff0000ffff0000ULL); + + /* FIXME: Copy result-status bit IRP to fsr from last stage. */ + /* FIXME: Scalar version flows through all stages. */ + if (!piped) + { + /* Scalar version writes the current calculation to the fdest + register, always with double precision. */ + set_fregval_d (fdest, dbl_tmp_dest); + } + else + { + /* Pipelined version writes fdest with the result from the last + stage of the pipeline, with precision specified by the IRP + bit of the stage's result-status bits. */ + if (m_G.stat.irp) /* 1st (and last) stage. */ + set_fregval_d (fdest, m_G.val.d); + else + set_fregval_s (fdest, m_G.val.s); + + /* Now write current calculation to first and only stage. */ + m_G.val.d = dbl_tmp_dest; + m_G.stat.irp = 1; + } +} + + +/* Flags for the decode table. */ +enum { + DEC_MORE = 1, /* More decoding necessary. */ + DEC_DECODED = 2 /* Fully decoded, go. */ +}; + + +/* First-level decode table (i.e., for the 6 primary opcode bits). */ +const i860_cpu_device::decode_tbl_t i860_cpu_device::decode_tbl[64] = { + /* A slight bit of decoding for loads and stores is done in the + execution routines (operand size and addressing mode), which + is why their respective entries are identical. */ + { &i860_cpu_device::insn_ldx, DEC_DECODED}, /* ld.b isrc1(isrc2),idest. */ + { &i860_cpu_device::insn_ldx, DEC_DECODED}, /* ld.b #const(isrc2),idest. */ + { &i860_cpu_device::insn_ixfr, DEC_DECODED}, /* ixfr isrc1ni,fdest. */ + { &i860_cpu_device::insn_stx, DEC_DECODED}, /* st.b isrc1ni,#const(isrc2). */ + { &i860_cpu_device::insn_ldx, DEC_DECODED}, /* ld.{s,l} isrc1(isrc2),idest. */ + { &i860_cpu_device::insn_ldx, DEC_DECODED}, /* ld.{s,l} #const(isrc2),idest. */ + { 0, 0}, + { &i860_cpu_device::insn_stx, DEC_DECODED}, /* st.{s,l} isrc1ni,#const(isrc2),idest.*/ + { &i860_cpu_device::insn_fldy, DEC_DECODED}, /* fld.{l,d,q} isrc1(isrc2)[++],fdest. */ + { &i860_cpu_device::insn_fldy, DEC_DECODED}, /* fld.{l,d,q} #const(isrc2)[++],fdest. */ + { &i860_cpu_device::insn_fsty, DEC_DECODED}, /* fst.{l,d,q} fdest,isrc1(isrc2)[++] */ + { &i860_cpu_device::insn_fsty, DEC_DECODED}, /* fst.{l,d,q} fdest,#const(isrc2)[++] */ + { &i860_cpu_device::insn_ld_ctrl, DEC_DECODED}, /* ld.c csrc2,idest. */ + { &i860_cpu_device::insn_flush, DEC_DECODED}, /* flush #const(isrc2) (or autoinc). */ + { &i860_cpu_device::insn_st_ctrl, DEC_DECODED}, /* st.c isrc1,csrc2. */ + { &i860_cpu_device::insn_pstd, DEC_DECODED}, /* pst.d fdest,#const(isrc2)[++]. */ + { &i860_cpu_device::insn_bri, DEC_DECODED}, /* bri isrc1ni. */ + { &i860_cpu_device::insn_trap, DEC_DECODED}, /* trap isrc1ni,isrc2,idest. */ + { 0, DEC_MORE}, /* FP ESCAPE FORMAT, more decode. */ + { 0, DEC_MORE}, /* CORE ESCAPE FORMAT, more decode. */ + { &i860_cpu_device::insn_btne, DEC_DECODED}, /* btne isrc1,isrc2,sbroff. */ + { &i860_cpu_device::insn_btne_imm, DEC_DECODED}, /* btne #const,isrc2,sbroff. */ + { &i860_cpu_device::insn_bte, DEC_DECODED}, /* bte isrc1,isrc2,sbroff. */ + { &i860_cpu_device::insn_bte_imm, DEC_DECODED}, /* bte #const5,isrc2,idest. */ + { &i860_cpu_device::insn_fldy, DEC_DECODED}, /* pfld.{l,d,q} isrc1(isrc2)[++],fdest.*/ + { &i860_cpu_device::insn_fldy, DEC_DECODED}, /* pfld.{l,d,q} #const(isrc2)[++],fdest.*/ + { &i860_cpu_device::insn_br, DEC_DECODED}, /* br lbroff. */ + { &i860_cpu_device::insn_call, DEC_DECODED}, /* call lbroff . */ + { &i860_cpu_device::insn_bc, DEC_DECODED}, /* bc lbroff. */ + { &i860_cpu_device::insn_bct, DEC_DECODED}, /* bc.t lbroff. */ + { &i860_cpu_device::insn_bnc, DEC_DECODED}, /* bnc lbroff. */ + { &i860_cpu_device::insn_bnct, DEC_DECODED}, /* bnc.t lbroff. */ + { &i860_cpu_device::insn_addu, DEC_DECODED}, /* addu isrc1,isrc2,idest. */ + { &i860_cpu_device::insn_addu_imm, DEC_DECODED}, /* addu #const,isrc2,idest. */ + { &i860_cpu_device::insn_subu, DEC_DECODED}, /* subu isrc1,isrc2,idest. */ + { &i860_cpu_device::insn_subu_imm, DEC_DECODED}, /* subu #const,isrc2,idest. */ + { &i860_cpu_device::insn_adds, DEC_DECODED}, /* adds isrc1,isrc2,idest. */ + { &i860_cpu_device::insn_adds_imm, DEC_DECODED}, /* adds #const,isrc2,idest. */ + { &i860_cpu_device::insn_subs, DEC_DECODED}, /* subs isrc1,isrc2,idest. */ + { &i860_cpu_device::insn_subs_imm, DEC_DECODED}, /* subs #const,isrc2,idest. */ + { &i860_cpu_device::insn_shl, DEC_DECODED}, /* shl isrc1,isrc2,idest. */ + { &i860_cpu_device::insn_shl_imm, DEC_DECODED}, /* shl #const,isrc2,idest. */ + { &i860_cpu_device::insn_shr, DEC_DECODED}, /* shr isrc1,isrc2,idest. */ + { &i860_cpu_device::insn_shr_imm, DEC_DECODED}, /* shr #const,isrc2,idest. */ + { &i860_cpu_device::insn_shrd, DEC_DECODED}, /* shrd isrc1ni,isrc2,idest. */ + { &i860_cpu_device::insn_bla, DEC_DECODED}, /* bla isrc1ni,isrc2,sbroff. */ + { &i860_cpu_device::insn_shra, DEC_DECODED}, /* shra isrc1,isrc2,idest. */ + { &i860_cpu_device::insn_shra_imm, DEC_DECODED}, /* shra #const,isrc2,idest. */ + { &i860_cpu_device::insn_and, DEC_DECODED}, /* and isrc1,isrc2,idest. */ + { &i860_cpu_device::insn_and_imm, DEC_DECODED}, /* and #const,isrc2,idest. */ + { 0, 0}, + { &i860_cpu_device::insn_andh_imm, DEC_DECODED}, /* andh #const,isrc2,idest. */ + { &i860_cpu_device::insn_andnot, DEC_DECODED}, /* andnot isrc1,isrc2,idest. */ + { &i860_cpu_device::insn_andnot_imm, DEC_DECODED}, /* andnot #const,isrc2,idest. */ + { 0, 0}, + { &i860_cpu_device::insn_andnoth_imm, DEC_DECODED}, /* andnoth #const,isrc2,idest. */ + { &i860_cpu_device::insn_or, DEC_DECODED}, /* or isrc1,isrc2,idest. */ + { &i860_cpu_device::insn_or_imm, DEC_DECODED}, /* or #const,isrc2,idest. */ + { 0, 0}, + { &i860_cpu_device::insn_orh_imm, DEC_DECODED}, /* orh #const,isrc2,idest. */ + { &i860_cpu_device::insn_xor, DEC_DECODED}, /* xor isrc1,isrc2,idest. */ + { &i860_cpu_device::insn_xor_imm, DEC_DECODED}, /* xor #const,isrc2,idest. */ + { 0, 0}, + { &i860_cpu_device::insn_xorh_imm, DEC_DECODED}, /* xorh #const,isrc2,idest. */ +}; + + +/* Second-level decode table (i.e., for the 3 core escape opcode bits). */ +const i860_cpu_device::decode_tbl_t i860_cpu_device::core_esc_decode_tbl[8] = { + { 0, 0}, + { 0, 0}, /* lock (FIXME: unimplemented). */ + { &i860_cpu_device::insn_calli, DEC_DECODED}, /* calli isrc1ni. */ + { 0, 0}, + { &i860_cpu_device::insn_intovr, DEC_DECODED}, /* intovr. */ + { 0, 0}, + { 0, 0}, + { 0, 0}, /* unlock (FIXME: unimplemented). */ +}; + + +/* Second-level decode table (i.e., for the 7 FP extended opcode bits). */ +const i860_cpu_device::decode_tbl_t i860_cpu_device::fp_decode_tbl[128] = { + /* Floating point instructions. The least significant 7 bits are + the (extended) opcode and bits 10:7 are P,D,S,R respectively + ([p]ipelined, [d]ual, [s]ource prec., [r]esult prec.). + For some operations, I defer decoding the P,S,R bits to the + emulation routine for them. */ + { &i860_cpu_device::insn_dualop, DEC_DECODED}, /* 0x00 pf[m]am */ + { &i860_cpu_device::insn_dualop, DEC_DECODED}, /* 0x01 pf[m]am */ + { &i860_cpu_device::insn_dualop, DEC_DECODED}, /* 0x02 pf[m]am */ + { &i860_cpu_device::insn_dualop, DEC_DECODED}, /* 0x03 pf[m]am */ + { &i860_cpu_device::insn_dualop, DEC_DECODED}, /* 0x04 pf[m]am */ + { &i860_cpu_device::insn_dualop, DEC_DECODED}, /* 0x05 pf[m]am */ + { &i860_cpu_device::insn_dualop, DEC_DECODED}, /* 0x06 pf[m]am */ + { &i860_cpu_device::insn_dualop, DEC_DECODED}, /* 0x07 pf[m]am */ + { &i860_cpu_device::insn_dualop, DEC_DECODED}, /* 0x08 pf[m]am */ + { &i860_cpu_device::insn_dualop, DEC_DECODED}, /* 0x09 pf[m]am */ + { &i860_cpu_device::insn_dualop, DEC_DECODED}, /* 0x0A pf[m]am */ + { &i860_cpu_device::insn_dualop, DEC_DECODED}, /* 0x0B pf[m]am */ + { &i860_cpu_device::insn_dualop, DEC_DECODED}, /* 0x0C pf[m]am */ + { &i860_cpu_device::insn_dualop, DEC_DECODED}, /* 0x0D pf[m]am */ + { &i860_cpu_device::insn_dualop, DEC_DECODED}, /* 0x0E pf[m]am */ + { &i860_cpu_device::insn_dualop, DEC_DECODED}, /* 0x0F pf[m]am */ + { &i860_cpu_device::insn_dualop, DEC_DECODED}, /* 0x10 pf[m]sm */ + { &i860_cpu_device::insn_dualop, DEC_DECODED}, /* 0x11 pf[m]sm */ + { &i860_cpu_device::insn_dualop, DEC_DECODED}, /* 0x12 pf[m]sm */ + { &i860_cpu_device::insn_dualop, DEC_DECODED}, /* 0x13 pf[m]sm */ + { &i860_cpu_device::insn_dualop, DEC_DECODED}, /* 0x14 pf[m]sm */ + { &i860_cpu_device::insn_dualop, DEC_DECODED}, /* 0x15 pf[m]sm */ + { &i860_cpu_device::insn_dualop, DEC_DECODED}, /* 0x16 pf[m]sm */ + { &i860_cpu_device::insn_dualop, DEC_DECODED}, /* 0x17 pf[m]sm */ + { &i860_cpu_device::insn_dualop, DEC_DECODED}, /* 0x18 pf[m]sm */ + { &i860_cpu_device::insn_dualop, DEC_DECODED}, /* 0x19 pf[m]sm */ + { &i860_cpu_device::insn_dualop, DEC_DECODED}, /* 0x1A pf[m]sm */ + { &i860_cpu_device::insn_dualop, DEC_DECODED}, /* 0x1B pf[m]sm */ + { &i860_cpu_device::insn_dualop, DEC_DECODED}, /* 0x1C pf[m]sm */ + { &i860_cpu_device::insn_dualop, DEC_DECODED}, /* 0x1D pf[m]sm */ + { &i860_cpu_device::insn_dualop, DEC_DECODED}, /* 0x1E pf[m]sm */ + { &i860_cpu_device::insn_dualop, DEC_DECODED}, /* 0x1F pf[m]sm */ + { &i860_cpu_device::insn_fmul, DEC_DECODED}, /* 0x20 [p]fmul */ + { &i860_cpu_device::insn_fmlow, DEC_DECODED}, /* 0x21 fmlow.dd */ + { &i860_cpu_device::insn_frcp, DEC_DECODED}, /* 0x22 frcp.{ss,sd,dd} */ + { &i860_cpu_device::insn_frsqr, DEC_DECODED}, /* 0x23 frsqr.{ss,sd,dd} */ + { &i860_cpu_device::insn_fmul, DEC_DECODED}, /* 0x24 pfmul3.dd */ + { 0, 0}, /* 0x25 */ + { 0, 0}, /* 0x26 */ + { 0, 0}, /* 0x27 */ + { 0, 0}, /* 0x28 */ + { 0, 0}, /* 0x29 */ + { 0, 0}, /* 0x2A */ + { 0, 0}, /* 0x2B */ + { 0, 0}, /* 0x2C */ + { 0, 0}, /* 0x2D */ + { 0, 0}, /* 0x2E */ + { 0, 0}, /* 0x2F */ + { &i860_cpu_device::insn_fadd_sub, DEC_DECODED}, /* 0x30, [p]fadd.{ss,sd,dd} */ + { &i860_cpu_device::insn_fadd_sub, DEC_DECODED}, /* 0x31, [p]fsub.{ss,sd,dd} */ + { 0, 0}, /* 0x32, [p]fix.{ss,sd,dd} FIXME: nyi. */ + { &i860_cpu_device::insn_famov, DEC_DECODED}, /* 0x33, [p]famov.{ss,sd,ds,dd} */ + { &i860_cpu_device::insn_fcmp, DEC_DECODED}, /* 0x34, pf{gt,le}.{ss,dd} */ + { &i860_cpu_device::insn_fcmp, DEC_DECODED}, /* 0x35, pfeq.{ss,dd} */ + { 0, 0}, /* 0x36 */ + { 0, 0}, /* 0x37 */ + { 0, 0}, /* 0x38 */ + { 0, 0}, /* 0x39 */ + { &i860_cpu_device::insn_ftrunc, DEC_DECODED}, /* 0x3A, [p]ftrunc.{ss,sd,dd} */ + { 0, 0}, /* 0x3B */ + { 0, 0}, /* 0x3C */ + { 0, 0}, /* 0x3D */ + { 0, 0}, /* 0x3E */ + { 0, 0}, /* 0x3F */ + { &i860_cpu_device::insn_fxfr, DEC_DECODED}, /* 0x40, fxfr */ + { 0, 0}, /* 0x41 */ + { 0, 0}, /* 0x42 */ + { 0, 0}, /* 0x43 */ + { 0, 0}, /* 0x44 */ + { 0, 0}, /* 0x45 */ + { 0, 0}, /* 0x46 */ + { 0, 0}, /* 0x47 */ + { 0, 0}, /* 0x48 */ + { &i860_cpu_device::insn_fiadd_sub, DEC_DECODED}, /* 0x49, [p]fiadd.{ss,dd} */ + { 0, 0}, /* 0x4A */ + { 0, 0}, /* 0x4B */ + { 0, 0}, /* 0x4C */ + { &i860_cpu_device::insn_fiadd_sub, DEC_DECODED}, /* 0x4D, [p]fisub.{ss,dd} */ + { 0, 0}, /* 0x4E */ + { 0, 0}, /* 0x4F */ + { &i860_cpu_device::insn_faddp, DEC_DECODED}, /* 0x50, [p]faddp */ + { &i860_cpu_device::insn_faddz, DEC_DECODED}, /* 0x51, [p]faddz */ + { 0, 0}, /* 0x52 */ + { 0, 0}, /* 0x53 */ + { 0, 0}, /* 0x54 */ + { 0, 0}, /* 0x55 */ + { 0, 0}, /* 0x56 */ + { &i860_cpu_device::insn_fzchk, DEC_DECODED}, /* 0x57, [p]fzchkl */ + { 0, 0}, /* 0x58 */ + { 0, 0}, /* 0x59 */ + { &i860_cpu_device::insn_form, DEC_DECODED}, /* 0x5A, [p]form.dd */ + { 0, 0}, /* 0x5B */ + { 0, 0}, /* 0x5C */ + { 0, 0}, /* 0x5D */ + { 0, 0}, /* 0x5E */ + { &i860_cpu_device::insn_fzchk, DEC_DECODED}, /* 0x5F, [p]fzchks */ + { 0, 0}, /* 0x60 */ + { 0, 0}, /* 0x61 */ + { 0, 0}, /* 0x62 */ + { 0, 0}, /* 0x63 */ + { 0, 0}, /* 0x64 */ + { 0, 0}, /* 0x65 */ + { 0, 0}, /* 0x66 */ + { 0, 0}, /* 0x67 */ + { 0, 0}, /* 0x68 */ + { 0, 0}, /* 0x69 */ + { 0, 0}, /* 0x6A */ + { 0, 0}, /* 0x6B */ + { 0, 0}, /* 0x6C */ + { 0, 0}, /* 0x6D */ + { 0, 0}, /* 0x6E */ + { 0, 0}, /* 0x6F */ + { 0, 0}, /* 0x70 */ + { 0, 0}, /* 0x71 */ + { 0, 0}, /* 0x72 */ + { 0, 0}, /* 0x73 */ + { 0, 0}, /* 0x74 */ + { 0, 0}, /* 0x75 */ + { 0, 0}, /* 0x76 */ + { 0, 0}, /* 0x77 */ + { 0, 0}, /* 0x78 */ + { 0, 0}, /* 0x79 */ + { 0, 0}, /* 0x7A */ + { 0, 0}, /* 0x7B */ + { 0, 0}, /* 0x7C */ + { 0, 0}, /* 0x7D */ + { 0, 0}, /* 0x7E */ + { 0, 0}, /* 0x7F */ +}; + + +/* + * Main decoder driver. + * insn = instruction at the current PC to execute. + * non_shadow = This insn is not in the shadow of a delayed branch). + */ +void i860_cpu_device::decode_exec (UINT32 insn, UINT32 non_shadow) +{ + int upper_6bits = (insn >> 26) & 0x3f; + char flags = 0; + int unrecognized = 1; + + if (m_exiting_ifetch) + return; + + if ((upper_6bits == 0x12 || upper_6bits == 0x2c) && insn & 0x0200) + logerror("D-bit seen.\n"); + if (GET_EPSR_BE ()) + logerror("BE-bit high.\n"); + if (GET_DIRBASE_CS8 ()) + logerror("CS8-bit high.\n"); + + flags = decode_tbl[upper_6bits].flags; + if (flags & DEC_DECODED) + { + (this->*decode_tbl[upper_6bits].insn_exec)(insn); + unrecognized = 0; + } + else if (flags & DEC_MORE) + { + if (upper_6bits == 0x12) + { + /* FP instruction format handled here. */ + char fp_flags = fp_decode_tbl[insn & 0x7f].flags; + if (fp_flags & DEC_DECODED) + { + (this->*fp_decode_tbl[insn & 0x7f].insn_exec)(insn); + unrecognized = 0; + } + } + else if (upper_6bits == 0x13) + { + /* Core escape instruction format handled here. */ + char esc_flags = core_esc_decode_tbl[insn & 0x3].flags; + if (esc_flags & DEC_DECODED) + { + (this->*core_esc_decode_tbl[insn & 0x3].insn_exec)(insn); + unrecognized = 0; + } + } + } + + if (unrecognized) + unrecog_opcode (m_pc, insn); + + /* For now, just treat every instruction as taking the same number of + clocks-- a major oversimplification. */ + m_icount -= 9; +} + + +/* Set-up all the default power-on/reset values. */ +void i860_cpu_device::reset_i860 () +{ + int i; + /* On power-up/reset, i860 has values: + PC = 0xffffff00. + Integer registers: r0 = 0, others = undefined. + FP registers: f0:f1 = 0, others undefined. + psr: U = IM = BR = BW = 0; others = undefined. + epsr: IL = WP = PBM = BE = 0; processor type, stepping, and + DCS are proper and read-only; others = undefined. + db: undefined. + dirbase: DPS, BL, ATE = 0 + fir, fsr, KR, KI, MERGE: undefined. (what about T?) + + I$: flushed. + D$: undefined (all modified bits = 0). + TLB: flushed. + + Note that any undefined values are set to 0x55aa55aa patterns to + try to detect defective i860 software. */ + + /* PC is at trap address after reset. */ + m_pc = 0xffffff00; + + /* Set grs and frs to undefined/nonsense values, except r0. */ + for (i = 0; i < 32; i++) + { + set_iregval (i, 0x55aa55aa); + set_fregval_s (i, 0.0); + } + set_iregval (0, 0); + set_fregval_s (0, 0.0); + set_fregval_s (1, 0.0); + + /* Set whole psr to 0. This sets the proper bits to 0 as specified + above, and zeroes the undefined bits. */ + m_cregs[CR_PSR] = 0; + + /* Set most of the epsr bits to 0 (as specified above), leaving + undefined as zero as well. Then properly set processor type, + step, and DCS. Type = EPSR[7..0], step = EPSR[12..8], + DCS = EPSR[21..18] (2^[12+dcs] = cache size). + We'll pretend to be stepping D0, since it has the fewest bugs + (and I don't want to emulate the many defects in the earlier + steppings). + Proc type: 1 = XR, 2 = XP (XR has 8KB data cache -> DCS = 1). + Steppings (XR): 3,4,5,6,7 = (B2, C0, B3, C1, D0 respectively). + Steppings (XP): 0, 2, 3, 4 = (A0, B0, B1, B2) (any others?). */ + m_cregs[CR_EPSR] = 0x00040701; + + /* Set DPS, BL, ATE = 0 and the undefined parts also to 0. */ + m_cregs[CR_DIRBASE] = 0x00000000; + + /* Set fir, fsr, KR, KI, MERGE, T to undefined. */ + m_cregs[CR_FIR] = 0xaa55aa55; + m_cregs[CR_FSR] = /* 0xaa55aa55; */ 0; + m_KR.d = 0.0; + m_KI.d = 0.0; + m_T.d = 0.0; + m_merge = 0xaa55aa55; + + m_fir_gets_trap_addr = 0; +} + + + + +/*=================================================================*/ +/* MAME execution hook for i860 emulator. */ +/*=================================================================*/ + +void i860_cpu_device::execute_run() +{ + /* Check if the data bus is held by another device, and bail if so. + Also check for reset. */ + if (m_pin_reset) + reset_i860 (); + if (m_pin_bus_hold) + { + m_icount = 0; + return; + } + + m_exiting_readmem = 0; + m_exiting_ifetch = 0; + + /* Decode and execute loop. */ + while (m_icount > 0) + { + UINT32 savepc = m_pc; + m_pc_updated = 0; + m_pending_trap = 0; + +#if 1 /* Delete me soon, for debugging VC inter-processor synch. */ + if (m_pc == 0xfffc0370 || + m_pc == 0xfffc03a4) + { + fprintf(stderr, "(%s) 0x%08x: snag 0x20000000\n", tag(), m_pc); + m_single_stepping = 0; + } + else if (m_pc == 0xfffc0384 || + m_pc == 0xfffc03b8) + { + fprintf(stderr, "(%s) 0x%08x: passed 0x20000000\n", tag(), m_pc); + m_single_stepping = 0; + } +#endif + + savepc = m_pc; + debugger_instruction_hook(this, m_pc); + decode_exec (ifetch (m_pc), 1); + + m_exiting_ifetch = 0; + m_exiting_readmem = 0; + + if (m_pending_trap) + { + /* If we need to trap, change PC to trap address. + Also set supervisor mode, copy U and IM to their + previous versions, clear IM. */ + if ((m_pending_trap & TRAP_WAS_EXTERNAL) || (GET_EPSR_INT () && GET_PSR_IN ())) + { + if (!m_pc_updated) + m_cregs[CR_FIR] = savepc + 4; + else + m_cregs[CR_FIR] = m_pc; + } + else if (m_pending_trap & TRAP_IN_DELAY_SLOT) + { + m_cregs[CR_FIR] = savepc + 4; + } + else + m_cregs[CR_FIR] = savepc; + + m_fir_gets_trap_addr = 1; + SET_PSR_PU (GET_PSR_U ()); + SET_PSR_PIM (GET_PSR_IM ()); + SET_PSR_U (0); + SET_PSR_IM (0); + SET_PSR_DIM (0); + SET_PSR_DS (0); + m_pc = 0xffffff00; + m_pending_trap = 0; + } + else if (!m_pc_updated) + { + /* If the PC wasn't updated by a control flow instruction, just + bump to next sequential instruction. */ + m_pc += 4; + } + + /*if (m_single_stepping) + debugger (cpustate); */ + } +} +/*=================================================================*/ + + + + +#if 0 +/*=================================================================*/ +/* Internal debugger-related stuff. */ + +extern unsigned disasm_i860 (char *buf, unsigned int pc, unsigned int insn); + + +/* Disassemble `len' instructions starting at `addr'. */ +void i860_cpu_device::disasm (UINT32 addr, int len) +{ + UINT32 insn; + int j; + for (j = 0; j < len; j++) + { + char buf[256]; + UINT32 phys_addr = addr; + if (GET_DIRBASE_ATE ()) + phys_addr = get_address_translation (addr, 1 /* is_dataref */, 0 /* is_write */); + + /* Note that we print the incoming (possibly virtual) address as the + PC rather than the translated address. */ + fprintf (stderr, " (%s) 0x%08x: ", m_device->tag(), addr); + insn = m_program->read_dword(phys_addr); +#ifdef HOST_MSB + BYTE_REV32 (insn); +#endif /* HOST_MSB. */ + disasm_i860 (buf, addr, insn); fprintf (stderr, "%s", buf); + fprintf (stderr, "\n"); + addr += 4; +#if 1 + if (m_single_stepping == 1 && has_delay_slot (insn)) + len += 1; +#endif + } +} + + +/* Dump `len' bytes starting at `addr'. */ +void i860_cpu_device::dbg_db (UINT32 addr, int len) +{ + UINT8 b[16]; + int i; + /* This will always dump a multiple of 16 bytes, even if 'len' isn't. */ + while (len > 0) + { + /* Note that we print the incoming (possibly virtual) address + rather than the translated address. */ + fprintf (stderr, "0x%08x: ", addr); + for (i = 0; i < 16; i++) + { + UINT32 phys_addr = addr; + if (GET_DIRBASE_ATE ()) + phys_addr = get_address_translation (addr, 1 /* is_dataref */, 0 /* is_write */); + + b[i] = m_program->read_byte(phys_addr); + fprintf (stderr, "%02x ", b[i]); + addr++; + } + fprintf (stderr, "| "); + for (i = 0; i < 16; i++) + { + if (isprint (b[i])) + fprintf (stderr, "%c", b[i]); + else + fprintf (stderr, "."); + } + fprintf (stderr, "\n"); + len -= 16; + } +} + + +/* A simple internal debugger. */ +void debugger (i860s *cpustate) +{ + char buf[256]; + UINT32 curr_disasm = m_pc; + UINT32 curr_dumpdb = 0; + int c = 0; + + if (m_single_stepping > 1 && m_single_stepping != m_pc) + return; + + buf[0] = 0; + + /* Always disassemble the upcoming instruction when single-stepping. */ + if (m_single_stepping) + { + disasm (m_pc, 1); + if (has_delay_slot (2)) + disasm (m_pc + 4, 1); + } + else + fprintf (stderr, "\nEmulator: internal debugger started (? for help).\n"); + + fflush (stdin); + + m_single_stepping = 0; + while (!m_single_stepping) + { + fprintf (stderr, "- "); +#if 0 /* Doesn't work on MacOSX BSD flavor. */ + fscanf (stdin, "%s", buf); +#else + while (1) + { + char it = 0; + if (read(STDIN_FILENO, &it, 1) == 1) + { + if (it == '\n') + { + buf[c] = 0; + c = 0; + break; + } + buf[c++] = it; + } + } +#endif + if (buf[0] == 'g') + { + if (buf[1] == '0') + sscanf (buf + 1, "%x", &m_single_stepping); + else + break; + buf[1] = 0; + fprintf (stderr, "go until pc = 0x%08x.\n", + m_single_stepping); + m_single_stepping = 0; /* HACK */ + } + else if (buf[0] == 'r') + dump_state (cpustate); + else if (buf[0] == 'u') + { + if (buf[1] == '0') + sscanf (buf + 1, "%x", &curr_disasm); + disasm (curr_disasm, 10); + curr_disasm += 10 * 4; + buf[1] = 0; + } + else if (buf[0] == 'p') + { + if (buf[1] >= '0' && buf[1] <= '4') + dump_pipe (buf[1] - 0x30); + buf[1] = 0; + } + else if (buf[0] == 's') + m_single_stepping = 1; + else if (buf[0] == 'l') + ; //m_pc = elf_load(buf + 1); + else if (buf[0] == 'd' && buf[1] == 'b') + { + if (buf[2] == '0') + sscanf (buf + 2, "%x", &curr_dumpdb); + dbg_db (curr_dumpdb, 32); + curr_dumpdb += 32; + } + else if (buf[0] == 'x' && buf[1] == '0') + { + UINT32 v; + sscanf (buf + 1, "%x", &v); + if (GET_DIRBASE_ATE ()) + fprintf (stderr, "vma 0x%08x ==> phys 0x%08x\n", v, + get_address_translation (v, 1, 0)); + else + fprintf (stderr, "not in virtual address mode.\n"); + } + else if (buf[0] == 'B') + { + ;//m_pc = elf_load("bins/bsd"); + break; + } + else if (buf[0] == '?') + { + fprintf (stderr, " db: dump bytes (db[0xaddress])\n r: dump registers\n s: single-step\n g: go back to emulator (g[0xaddress])\n u: disassemble (u[0xaddress])\n p: dump pipelines (p{0-4} for all, add, mul, load, graphics)\n l: load an ELF binary (lpath)\n x: give virt->phys translation (x{0xaddress})\n"); + } + else + fprintf (stderr, "Bad command '%s'.\n", buf); + } + + /* Less noise when single-stepping. */ + if (m_single_stepping != 1) + fprintf (stderr, "Debugger done, continuing emulation.\n"); +} + +#endif diff --git a/src/devices/cpu/i860/i860dis.c b/src/devices/cpu/i860/i860dis.c new file mode 100644 index 00000000000..1c72a9f474d --- /dev/null +++ b/src/devices/cpu/i860/i860dis.c @@ -0,0 +1,697 @@ +// license:BSD-3-Clause +// copyright-holders:Jason Eckhardt +/*************************************************************************** + + i860dis.c + + Disassembler for the Intel i860 emulator. + + Copyright (C) 1995-present Jason Eckhardt (jle@rice.edu) + +***************************************************************************/ + +#include "emu.h" +#include "i860.h" + +/* Macros for accessing register fields in instruction word. */ +#define get_isrc1(bits) (((bits) >> 11) & 0x1f) +#define get_isrc2(bits) (((bits) >> 21) & 0x1f) +#define get_idest(bits) (((bits) >> 16) & 0x1f) +#define get_fsrc1(bits) (((bits) >> 11) & 0x1f) +#define get_fsrc2(bits) (((bits) >> 21) & 0x1f) +#define get_fdest(bits) (((bits) >> 16) & 0x1f) +#define get_creg(bits) (((bits) >> 21) & 0x7) + +/* Macros for accessing immediate fields. */ +/* 16-bit immediate. */ +#define get_imm16(insn) ((insn) & 0xffff) + + +/* Control register names. */ +static const char *const cr2str[] = + {"fir", "psr", "dirbase", "db", "fsr", "epsr", "!", "!"}; + + +/* Sign extend N-bit number. */ +static INT32 sign_ext(UINT32 x, int n) +{ + INT32 t; + t = x >> (n - 1); + t = ((-t) << n) | x; + return t; +} + + +/* Basic integer 3-address register format: + * mnemonic %rs1,%rs2,%rd */ +static void int_12d(char *buf, char *mnemonic, UINT32 pc, UINT32 insn) +{ + /* Possibly prefix shrd with 'd.' */ + if (((insn & 0xfc000000) == 0xb0000000) && (insn & 0x200)) + sprintf(buf, "d.%s\t%%r%d,%%r%d,%%r%d", mnemonic, + get_isrc1 (insn), get_isrc2 (insn), get_idest (insn)); + else + sprintf(buf, "%s\t%%r%d,%%r%d,%%r%d", mnemonic, + get_isrc1 (insn), get_isrc2 (insn), get_idest (insn)); +} + + +/* Basic integer 3-address imm16 format: + * mnemonic #imm16,%rs2,%rd */ +static void int_i2d(char *buf, char *mnemonic, UINT32 pc, UINT32 insn) +{ + /* Sign extend the 16-bit immediate. + Print as hex for the bitwise operations. */ + int upper_6bits = (insn >> 26) & 0x3f; + if (upper_6bits >= 0x30 && upper_6bits <= 0x3f) + sprintf(buf, "%s\t0x%04x,%%r%d,%%r%d", mnemonic, + (UINT32)(get_imm16 (insn)), get_isrc2 (insn), get_idest (insn)); + else + sprintf(buf, "%s\t%d,%%r%d,%%r%d", mnemonic, + sign_ext(get_imm16 (insn), 16), get_isrc2 (insn), get_idest (insn)); +} + + +/* Integer (mixed) 2-address isrc1ni,fdest. */ +static void int_1d(char *buf, char *mnemonic, UINT32 pc, UINT32 insn) +{ + sprintf(buf, "%s\t%%r%d,%%f%d", mnemonic, get_isrc1 (insn), get_fdest (insn)); +} + + +/* Integer (mixed) 2-address csrc2,idest. */ +static void int_cd(char *buf, char *mnemonic, UINT32 pc, UINT32 insn) +{ + sprintf(buf, "%s\t%%%s,%%r%d", mnemonic, cr2str[get_creg (insn)], get_idest (insn)); +} + + +/* Integer (mixed) 2-address isrc1,csrc2. */ +static void int_1c(char *buf, char *mnemonic, UINT32 pc, UINT32 insn) +{ + sprintf(buf, "%s\t%%r%d,%%%s", mnemonic, get_isrc1(insn), cr2str[get_creg (insn)]); +} + + +/* Integer 1-address register format: + * mnemonic %rs1 */ +static void int_1(char *buf, char *mnemonic, UINT32 pc, UINT32 insn) +{ + sprintf(buf, "%s\t%%r%d", mnemonic, get_isrc1 (insn)); +} + + +/* Integer no-address register format: + * mnemonic */ +static void int_0(char *buf, char *mnemonic, UINT32 pc, UINT32 insn) +{ + sprintf(buf, "%s", mnemonic); +} + + +/* Basic floating-point 3-address register format: + * mnemonic %fs1,%fs2,%fd */ +static void flop_12d(char *buf, char *mnemonic, UINT32 pc, UINT32 insn) +{ + const char *const suffix[4] = { "ss", "sd", "ds", "dd" }; + const char *prefix_d, *prefix_p; + prefix_p = (insn & 0x400) ? "p" : ""; + prefix_d = (insn & 0x200) ? "d." : ""; + + /* Special case: pf[m]am and pf[m]sm families are always pipelined, so they + do not have a prefix. Also, for the pfmam and pfmsm families, replace + any 'a' in the mnemonic with 'm' and prepend an 'm'. */ + if ((insn & 0x7f) < 0x20) + { + int is_pfam = insn & 0x400; + if (!is_pfam) + { + char newname[256]; + char *op = mnemonic; + char *np = newname + 1; + newname[0] = 'm'; + while (*op) + { + if (*op == 'a') + *np = 'm'; + else + *np = *op; + np++; + op++; + } + *np = 0; + mnemonic = newname; + } + prefix_p = ""; + } + + /* Special case: pfgt/pfle-- R-bit distinguishes the two. */ + if ((insn & 0x7f) == 0x34) + { + const char *const mn[2] = { "fgt.", "fle." }; + int r = (insn & 0x080) >> 7; + int s = (insn & 0x100) ? 3 : 0; + sprintf(buf, "%s%s%s%s\t%%f%d,%%f%d,%%f%d", prefix_d, prefix_p, mn[r], + suffix[s], get_fsrc1 (insn), get_fsrc2 (insn), get_fdest (insn)); + } + else + { + int s = (insn & 0x180) >> 7; + sprintf(buf, "%s%s%s%s\t%%f%d,%%f%d,%%f%d", prefix_d, prefix_p, mnemonic, + suffix[s], get_fsrc1 (insn), get_fsrc2 (insn), get_fdest (insn)); + } +} + + +/* Floating-point 2-address register format: + * mnemonic %fs1,%fd */ +static void flop_1d(char *buf, char *mnemonic, UINT32 pc, UINT32 insn) +{ + const char *const suffix[4] = { "ss", "sd", "ds", "dd" }; + const char *prefix_d, *prefix_p; + int s = (insn & 0x180) >> 7; + prefix_p = (insn & 0x400) ? "p" : ""; + prefix_d = (insn & 0x200) ? "d." : ""; + sprintf(buf, "%s%s%s%s\t%%f%d,%%f%d", prefix_d, prefix_p, mnemonic, + suffix[s], get_fsrc1 (insn), get_fdest (insn)); +} + + +/* Floating-point 2-address register format: + * mnemonic %fs2,%fd */ +static void flop_2d(char *buf, char *mnemonic, UINT32 pc, UINT32 insn) +{ + const char *const suffix[4] = { "ss", "sd", "ds", "dd" }; + const char *prefix_d; + int s = (insn & 0x180) >> 7; + prefix_d = (insn & 0x200) ? "d." : ""; + sprintf(buf, "%s%s%s\t%%f%d,%%f%d", prefix_d, mnemonic, suffix[s], + get_fsrc2 (insn), get_fdest (insn)); +} + + +/* Floating-point (mixed) 2-address register format: + * fxfr fsrc1,idest. */ +static void flop_fxfr(char *buf, char *mnemonic, UINT32 pc, UINT32 insn) +{ + const char *prefix_d = (insn & 0x200) ? "d." : ""; + sprintf(buf, "%s%s\t%%f%d,%%r%d", prefix_d, mnemonic, get_fsrc1 (insn), + get_idest (insn)); +} + + +/* Branch with reg,reg,sbroff format: + * mnemonic %rs1,%rs2,sbroff */ +static void int_12S(char *buf, char *mnemonic, UINT32 pc, UINT32 insn) +{ + INT32 sbroff = sign_ext ((((insn >> 5) & 0xf800) | (insn & 0x07ff)), 16); + INT32 rel = (INT32)pc + (sbroff << 2) + 4; + + sprintf(buf, "%s\t%%r%d,%%r%d,0x%08x", mnemonic, get_isrc1 (insn), + get_isrc2 (insn), (UINT32)rel); +} + + +/* Branch with #const5,reg,sbroff format: + * mnemonic #const5,%rs2,sbroff */ +static void int_i2S(char *buf, char *mnemonic, UINT32 pc, UINT32 insn) +{ + INT32 sbroff = sign_ext ((((insn >> 5) & 0xf800) | (insn & 0x07ff)), 16); + INT32 rel = (INT32)pc + (sbroff << 2) + 4; + + sprintf(buf, "%s\t%d,%%r%d,0x%08x", mnemonic, ((insn >> 11) & 0x1f), + get_isrc2 (insn), (UINT32)rel); +} + + +/* Branch with lbroff format: + * mnemonic lbroff */ +static void int_L(char *buf, char *mnemonic, UINT32 pc, UINT32 insn) +{ + INT32 lbroff = sign_ext ((insn & 0x03ffffff), 26); + INT32 rel = (INT32)pc + (lbroff << 2) + 4; + + sprintf(buf, "%s\t0x%08x", mnemonic, (UINT32)rel); +} + + +/* Integer load. + * ld.{b,s,l} isrc1(isrc2),idest + * ld.{b,s,l} #const(isrc2),idest */ +static void int_ldx(char *buf, char *mnemonic, UINT32 pc, UINT32 insn) +{ + /* Operand size, in bytes. */ + int sizes[4] = { 1, 1, 2, 4 }; + const char *const suffix[4] = { "b", "b", "s", "l" }; + UINT32 idx = 0; + + /* Bits 28 and 0 determine the operand size. */ + idx = ((insn >> 27) & 2) | (insn & 1); + + /* Bit 26 determines the addressing mode (reg+reg or disp+reg). */ + if (insn & 0x04000000) + { + /* Chop off lower bits of displacement. */ + INT32 immsrc1 = sign_ext (get_imm16 (insn), 16); + int size = sizes[idx]; + immsrc1 &= ~(size - 1); + sprintf(buf, "%s%s\t%d(%%r%d),%%r%d", mnemonic, suffix[idx], + immsrc1, get_isrc2 (insn), get_idest (insn)); + } + else + sprintf(buf, "%s%s\t%%r%d(%%r%d),%%r%d", mnemonic, suffix[idx], + get_isrc1 (insn), get_isrc2 (insn), get_idest (insn)); +} + + +/* Integer store: st.b isrc1ni,#const(isrc2) */ +static void int_stx(char *buf, char *mnemonic, UINT32 pc, UINT32 insn) +{ + /* Operand size, in bytes. */ + int sizes[4] = { 1, 1, 2, 4 }; + const char *const suffix[4] = { "b", "b", "s", "l" }; + int idx = 0; + int size; + INT32 immsrc = sign_ext ((((insn >> 5) & 0xf800) | (insn & 0x07ff)), 16); + + /* Bits 28 and 0 determine the operand size. */ + idx = ((insn >> 27) & 2) | (insn & 1); + + /* Chop off lower bits of displacement. */ + size = sizes[idx]; + immsrc &= ~(size - 1); + sprintf(buf, "%s%s\t%%r%d,%d(%%r%d)", mnemonic, suffix[idx], + get_isrc1 (insn), immsrc, get_isrc2 (insn)); +} + + +/* Disassemble: + * "[p]fld.y isrc1(isrc2),fdest", "[p]fld.y isrc1(isrc2)++,idest", + * "[p]fld.y #const(isrc2),fdest" or "[p]fld.y #const(isrc2)++,idest". + * "fst.y fdest,isrc1(isrc2)", "fst.y fdest,isrc1(isrc2)++", + * "fst.y fdest,#const(isrc2)" or "fst.y fdest,#const(isrc2)++" + * Where y = {l,d,q}. Note, there is no pfld.q, though. */ +static void int_fldst(char *buf, char *mnemonic, UINT32 pc, UINT32 insn) +{ + INT32 immsrc1 = sign_ext (get_imm16 (insn), 16); + /* Operand size, in bytes. */ + int sizes[4] = { 8, 4, 16, 4 }; + const char *const suffix[4] = { "d", "l", "q", "l" }; + int idx = 0; + int size = 0; + int auto_inc = (insn & 1); + const char *const auto_suff[2] = { "", "++" }; + int piped = (insn & 0x40000000) >> 29; + const char *const piped_suff[2] = { "", "p" }; + int upper_6bits = (insn >> 26) & 0x3f; + int is_load = (upper_6bits == 8 || upper_6bits == 9 || upper_6bits == 24 + || upper_6bits == 25); + + /* Bits 2 and 1 determine the operand size. */ + idx = ((insn >> 1) & 3); + size = sizes[idx]; + + /* There is no pipelined load quad on XR. */ + if (piped && size == 16) + { + sprintf (buf, ".long\t%#08x; *", insn); + return; + } + + /* There is only a 64-bit pixel store. */ + if ((upper_6bits == 15) && size != 8) + { + sprintf (buf, ".long\t%#08x", insn); + return; + } + + /* Bit 26 determines the addressing mode (reg+reg or disp+reg). */ + if (insn & 0x04000000) + { + /* Chop off lower bits of displacement. */ + immsrc1 &= ~(size - 1); + if (is_load) + sprintf(buf, "%s%s%s\t%d(%%r%d)%s,%%f%d", piped_suff[piped], mnemonic, + suffix[idx], immsrc1, get_isrc2 (insn), auto_suff[auto_inc], + get_fdest (insn)); + else + sprintf(buf, "%s%s\t%%f%d,%d(%%r%d)%s", mnemonic, suffix[idx], + get_fdest (insn), immsrc1, get_isrc2 (insn), auto_suff[auto_inc]); + } + else + { + if (is_load) + sprintf(buf, "%s%s%s\t%%r%d(%%r%d)%s,%%f%d", piped_suff[piped], + mnemonic, suffix[idx], get_isrc1 (insn), get_isrc2 (insn), + auto_suff[auto_inc], get_fdest (insn)); + else + sprintf(buf, "%s%s\t%%f%d,%%r%d(%%r%d)%s", mnemonic, suffix[idx], + get_fdest (insn), get_isrc1 (insn), get_isrc2 (insn), + auto_suff[auto_inc]); + } +} + + +/* flush #const(isrc2)[++]. */ +static void int_flush(char *buf, char *mnemonic, UINT32 pc, UINT32 insn) +{ + const char *const auto_suff[2] = { "", "++" }; + INT32 immsrc = sign_ext (get_imm16 (insn), 16); + immsrc &= ~(16-1); + sprintf(buf, "%s\t%d(%%r%d)%s", mnemonic, immsrc, get_isrc2 (insn), + auto_suff[(insn & 1)]); +} + + +/* Flags for the decode table. */ +enum +{ + DEC_MORE = 1, /* More decoding necessary. */ + DEC_DECODED = 2 /* Fully decoded, go. */ +}; + + +struct decode_tbl_t +{ + /* Disassembly function for this opcode. + Call with buffer, mnemonic, pc, insn. */ + void (*insn_dis)(char *, char *, UINT32, UINT32); + + /* Flags for this opcode. */ + char flags; + + /* Mnemonic of this opcode (sometimes partial when more decode is + done in disassembly routines-- e.g., loads and stores). */ + const char *mnemonic; +}; + + +/* First-level decode table (i.e., for the 6 primary opcode bits). */ +static const decode_tbl_t decode_tbl[64] = +{ + /* A slight bit of decoding for loads and stores is done in the + execution routines (operand size and addressing mode), which + is why their respective entries are identical. */ + { int_ldx, DEC_DECODED, "ld." }, /* ld.b isrc1(isrc2),idest. */ + { int_ldx, DEC_DECODED, "ld." }, /* ld.b #const(isrc2),idest. */ + { int_1d, DEC_DECODED, "ixfr" }, /* ixfr isrc1ni,fdest. */ + { int_stx, DEC_DECODED, "st." }, /* st.b isrc1ni,#const(isrc2). */ + { int_ldx, DEC_DECODED, "ld." }, /* ld.{s,l} isrc1(isrc2),idest. */ + { int_ldx, DEC_DECODED, "ld." }, /* ld.{s,l} #const(isrc2),idest. */ + { 0, 0 , 0 }, + { int_stx, DEC_DECODED, "st." }, /* st.{s,l} isrc1ni,#const(isrc2),idest.*/ + { int_fldst, DEC_DECODED, "fld." }, /* fld.{l,d,q} isrc1(isrc2)[++],fdest. */ + { int_fldst, DEC_DECODED, "fld." }, /* fld.{l,d,q} #const(isrc2)[++],fdest. */ + { int_fldst, DEC_DECODED, "fst." }, /* fst.{l,d,q} fdest,isrc1(isrc2)[++] */ + { int_fldst, DEC_DECODED, "fst." }, /* fst.{l,d,q} fdest,#const(isrc2)[++] */ + { int_cd, DEC_DECODED, "ld.c" }, /* ld.c csrc2,idest. */ + { int_flush, DEC_DECODED, "flush" }, /* flush #const(isrc2) (or autoinc). */ + { int_1c, DEC_DECODED, "st.c" }, /* st.c isrc1,csrc2. */ + { int_fldst, DEC_DECODED, "pstd." }, /* pst.d fdest,#const(isrc2)[++]. */ + { int_1, DEC_DECODED, "bri" }, /* bri isrc1ni. */ + { int_12d, DEC_DECODED, "trap" }, /* trap isrc1ni,isrc2,idest. */ + { 0, DEC_MORE, 0 }, /* FP ESCAPE FORMAT, more decode. */ + { 0, DEC_MORE, 0 }, /* CORE ESCAPE FORMAT, more decode. */ + { int_12S, DEC_DECODED, "btne" }, /* btne isrc1,isrc2,sbroff. */ + { int_i2S, DEC_DECODED, "btne" }, /* btne #const,isrc2,sbroff. */ + { int_12S, DEC_DECODED, "bte" }, /* bte isrc1,isrc2,sbroff. */ + { int_i2S, DEC_DECODED, "bte" }, /* bte #const5,isrc2,idest. */ + { int_fldst, DEC_DECODED, "pfld." }, /* pfld.{l,d,q} isrc1(isrc2)[++],fdest. */ + { int_fldst, DEC_DECODED, "pfld." }, /* pfld.{l,d,q} #const(isrc2)[++],fdest.*/ + { int_L, DEC_DECODED, "br" }, /* br lbroff. */ + { int_L, DEC_DECODED, "call" }, /* call lbroff . */ + { int_L, DEC_DECODED, "bc" }, /* bc lbroff. */ + { int_L, DEC_DECODED, "bc.t" }, /* bc.t lbroff. */ + { int_L, DEC_DECODED, "bnc" }, /* bnc lbroff. */ + { int_L, DEC_DECODED, "bnc.t" }, /* bnc.t lbroff. */ + { int_12d, DEC_DECODED, "addu" }, /* addu isrc1,isrc2,idest. */ + { int_i2d, DEC_DECODED, "addu" }, /* addu #const,isrc2,idest. */ + { int_12d, DEC_DECODED, "subu" }, /* subu isrc1,isrc2,idest. */ + { int_i2d, DEC_DECODED, "subu" }, /* subu #const,isrc2,idest. */ + { int_12d, DEC_DECODED, "adds" }, /* adds isrc1,isrc2,idest. */ + { int_i2d, DEC_DECODED, "adds" }, /* adds #const,isrc2,idest. */ + { int_12d, DEC_DECODED, "subs" }, /* subs isrc1,isrc2,idest. */ + { int_i2d, DEC_DECODED, "subs" }, /* subs #const,isrc2,idest. */ + { int_12d, DEC_DECODED, "shl" }, /* shl isrc1,isrc2,idest. */ + { int_i2d, DEC_DECODED, "shl" }, /* shl #const,isrc2,idest. */ + { int_12d, DEC_DECODED, "shr" }, /* shr isrc1,isrc2,idest. */ + { int_i2d, DEC_DECODED, "shr" }, /* shr #const,isrc2,idest. */ + { int_12d, DEC_DECODED, "shrd" }, /* shrd isrc1ni,isrc2,idest. */ + { int_12S, DEC_DECODED, "bla" }, /* bla isrc1ni,isrc2,sbroff. */ + { int_12d, DEC_DECODED, "shra" }, /* shra isrc1,isrc2,idest. */ + { int_i2d, DEC_DECODED, "shra" }, /* shra #const,isrc2,idest. */ + { int_12d, DEC_DECODED, "and" }, /* and isrc1,isrc2,idest. */ + { int_i2d, DEC_DECODED, "and" }, /* and #const,isrc2,idest. */ + { 0, 0 , 0 }, + { int_i2d, DEC_DECODED, "andh" }, /* andh #const,isrc2,idest. */ + { int_12d, DEC_DECODED, "andnot" }, /* andnot isrc1,isrc2,idest. */ + { int_i2d, DEC_DECODED, "andnot" }, /* andnot #const,isrc2,idest. */ + { 0, 0 , 0 }, + { int_i2d, DEC_DECODED, "andnoth" }, /* andnoth #const,isrc2,idest.*/ + { int_12d, DEC_DECODED, "or" }, /* or isrc1,isrc2,idest. */ + { int_i2d, DEC_DECODED, "or" }, /* or #const,isrc2,idest. */ + { 0, 0 , 0 }, + { int_i2d, DEC_DECODED, "orh" }, /* orh #const,isrc2,idest. */ + { int_12d, DEC_DECODED, "xor" }, /* xor isrc1,isrc2,idest. */ + { int_i2d, DEC_DECODED, "xor" }, /* xor #const,isrc2,idest. */ + { 0, 0 , 0 }, + { int_i2d, DEC_DECODED, "xorh" }, /* xorh #const,isrc2,idest. */ +}; + + +/* Second-level decode table (i.e., for the 3 core escape opcode bits). */ +static const decode_tbl_t core_esc_decode_tbl[8] = +{ + { 0, 0 , 0 }, + { int_0, DEC_DECODED, "lock" }, /* lock. */ + { int_1, DEC_DECODED, "calli" }, /* calli isrc1ni. */ + { 0, 0 , 0 }, + { int_0, DEC_DECODED, "intovr" }, /* intovr. */ + { 0, 0 , 0 }, + { 0, 0 , 0 }, + { int_0, DEC_DECODED, "unlock" }, /* unlock. */ +}; + + +/* Second-level decode table (i.e., for the 7 FP extended opcode bits). */ +static const decode_tbl_t fp_decode_tbl[128] = +{ + /* Floating point instructions. The least significant 7 bits are + the (extended) opcode and bits 10:7 are P,D,S,R respectively + ([p]ipelined, [d]ual, [s]ource prec., [r]esult prec.). + For some operations, I defer decoding the P,S,R bits to the + emulation routine for them. */ + { flop_12d, DEC_DECODED, "r2p1." }, /* 0x00 pf[m]am */ + { flop_12d, DEC_DECODED, "r2pt." }, /* 0x01 pf[m]am */ + { flop_12d, DEC_DECODED, "r2ap1." }, /* 0x02 pf[m]am */ + { flop_12d, DEC_DECODED, "r2apt." }, /* 0x03 pf[m]am */ + { flop_12d, DEC_DECODED, "i2p1." }, /* 0x04 pf[m]am */ + { flop_12d, DEC_DECODED, "i2pt." }, /* 0x05 pf[m]am */ + { flop_12d, DEC_DECODED, "i2ap1." }, /* 0x06 pf[m]am */ + { flop_12d, DEC_DECODED, "i2apt." }, /* 0x07 pf[m]am */ + { flop_12d, DEC_DECODED, "rat1p2." }, /* 0x08 pf[m]am */ + { flop_12d, DEC_DECODED, "m12apm." }, /* 0x09 pf[m]am */ + { flop_12d, DEC_DECODED, "ra1p2." }, /* 0x0A pf[m]am */ + { flop_12d, DEC_DECODED, "m12ttpa." }, /* 0x0B pf[m]am */ + { flop_12d, DEC_DECODED, "iat1p2." }, /* 0x0C pf[m]am */ + { flop_12d, DEC_DECODED, "m12tpm." }, /* 0x0D pf[m]am */ + { flop_12d, DEC_DECODED, "ia1p2." }, /* 0x0E pf[m]am */ + { flop_12d, DEC_DECODED, "m12tpa." }, /* 0x0F pf[m]am */ + { flop_12d, DEC_DECODED, "r2s1." }, /* 0x10 pf[m]sm */ + { flop_12d, DEC_DECODED, "r2st." }, /* 0x11 pf[m]sm */ + { flop_12d, DEC_DECODED, "r2as1." }, /* 0x12 pf[m]sm */ + { flop_12d, DEC_DECODED, "r2ast." }, /* 0x13 pf[m]sm */ + { flop_12d, DEC_DECODED, "i2s1." }, /* 0x14 pf[m]sm */ + { flop_12d, DEC_DECODED, "i2st." }, /* 0x15 pf[m]sm */ + { flop_12d, DEC_DECODED, "i2as1." }, /* 0x16 pf[m]sm */ + { flop_12d, DEC_DECODED, "i2ast." }, /* 0x17 pf[m]sm */ + { flop_12d, DEC_DECODED, "rat1s2." }, /* 0x18 pf[m]sm */ + { flop_12d, DEC_DECODED, "m12asm." }, /* 0x19 pf[m]sm */ + { flop_12d, DEC_DECODED, "ra1s2." }, /* 0x1A pf[m]sm */ + { flop_12d, DEC_DECODED, "m12ttsa." }, /* 0x1B pf[m]sm */ + { flop_12d, DEC_DECODED, "iat1s2." }, /* 0x1C pf[m]sm */ + { flop_12d, DEC_DECODED, "m12tsm." }, /* 0x1D pf[m]sm */ + { flop_12d, DEC_DECODED, "ia1s2." }, /* 0x1E pf[m]sm */ + { flop_12d, DEC_DECODED, "m12tsa." }, /* 0x1F pf[m]sm */ + { flop_12d, DEC_DECODED, "fmul." }, /* 0x20 [p]fmul */ + { flop_12d, DEC_DECODED, "fmlow." }, /* 0x21 fmlow.dd */ + { flop_2d, DEC_DECODED, "frcp." }, /* 0x22 frcp.{ss,sd,dd} */ + { flop_2d, DEC_DECODED, "frsqr." }, /* 0x23 frsqr.{ss,sd,dd} */ + { flop_12d, DEC_DECODED, "pfmul3.dd" }, /* 0x24 pfmul3.dd */ + { 0, 0 , 0 }, /* 0x25 */ + { 0, 0 , 0 }, /* 0x26 */ + { 0, 0 , 0 }, /* 0x27 */ + { 0, 0 , 0 }, /* 0x28 */ + { 0, 0 , 0 }, /* 0x29 */ + { 0, 0 , 0 }, /* 0x2A */ + { 0, 0 , 0 }, /* 0x2B */ + { 0, 0 , 0 }, /* 0x2C */ + { 0, 0 , 0 }, /* 0x2D */ + { 0, 0 , 0 }, /* 0x2E */ + { 0, 0 , 0 }, /* 0x2F */ + { flop_12d, DEC_DECODED, "fadd." }, /* 0x30, [p]fadd.{ss,sd,dd} */ + { flop_12d, DEC_DECODED, "fsub." }, /* 0x31, [p]fsub.{ss,sd,dd} */ + { flop_1d, DEC_DECODED, "fix." }, /* 0x32, [p]fix.{ss,sd,dd} */ + { flop_1d, DEC_DECODED, "famov." }, /* 0x33, [p]famov.{ss,sd,ds,dd} */ + { flop_12d, DEC_DECODED, "f{gt,le}" }, /* 0x34, pf{gt,le}.{ss,dd} */ + { flop_12d, DEC_DECODED, "feq." }, /* 0x35, pfeq.{ss,dd} */ + { 0, 0 , 0 }, /* 0x36 */ + { 0, 0 , 0 }, /* 0x37 */ + { 0, 0 , 0 }, /* 0x38 */ + { 0, 0 , 0 }, /* 0x39 */ + { flop_1d, DEC_DECODED, "ftrunc." }, /* 0x3A, [p]ftrunc.{ss,sd,dd} */ + { 0, 0 , 0 }, /* 0x3B */ + { 0, 0 , 0 }, /* 0x3C */ + { 0, 0 , 0 }, /* 0x3D */ + { 0, 0 , 0 }, /* 0x3E */ + { 0, 0 , 0 }, /* 0x3F */ + { flop_fxfr, DEC_DECODED, "fxfr" }, /* 0x40, fxfr fsrc1,idest. */ + { 0, 0 , 0 }, /* 0x41 */ + { 0, 0 , 0 }, /* 0x42 */ + { 0, 0 , 0 }, /* 0x43 */ + { 0, 0 , 0 }, /* 0x44 */ + { 0, 0 , 0 }, /* 0x45 */ + { 0, 0 , 0 }, /* 0x46 */ + { 0, 0 , 0 }, /* 0x47 */ + { 0, 0 , 0 }, /* 0x48 */ + { flop_12d, DEC_DECODED, "fiadd." }, /* 0x49, [p]fiadd.{ss,dd} */ + { 0, 0 , 0 }, /* 0x4A */ + { 0, 0 , 0 }, /* 0x4B */ + { 0, 0 , 0 }, /* 0x4C */ + { flop_12d, DEC_DECODED, "fisub." }, /* 0x4D, [p]fisub.{ss,dd} */ + { 0, 0 , 0 }, /* 0x4E */ + { 0, 0 , 0 }, /* 0x4F */ + { flop_12d, DEC_DECODED, "faddp" }, /* 0x50, [p]faddp */ + { flop_12d, DEC_DECODED, "faddz" }, /* 0x51, [p]faddz */ + { 0, 0 , 0 }, /* 0x52 */ + { 0, 0 , 0 }, /* 0x53 */ + { 0, 0 , 0 }, /* 0x54 */ + { 0, 0 , 0 }, /* 0x55 */ + { 0, 0 , 0 }, /* 0x56 */ + { flop_12d, DEC_DECODED, "fzchkl" }, /* 0x57, [p]fzchkl */ + { 0, 0 , 0 }, /* 0x58 */ + { 0, 0 , 0 }, /* 0x59 */ + { flop_1d, DEC_DECODED, "form" }, /* 0x5A, [p]form.dd */ + { 0, 0 , 0 }, /* 0x5B */ + { 0, 0 , 0 }, /* 0x5C */ + { 0, 0 , 0 }, /* 0x5D */ + { 0, 0 , 0 }, /* 0x5E */ + { flop_12d, DEC_DECODED, "fzchks" }, /* 0x5F, [p]fzchks */ + { 0, 0 , 0 }, /* 0x60 */ + { 0, 0 , 0 }, /* 0x61 */ + { 0, 0 , 0 }, /* 0x62 */ + { 0, 0 , 0 }, /* 0x63 */ + { 0, 0 , 0 }, /* 0x64 */ + { 0, 0 , 0 }, /* 0x65 */ + { 0, 0 , 0 }, /* 0x66 */ + { 0, 0 , 0 }, /* 0x67 */ + { 0, 0 , 0 }, /* 0x68 */ + { 0, 0 , 0 }, /* 0x69 */ + { 0, 0 , 0 }, /* 0x6A */ + { 0, 0 , 0 }, /* 0x6B */ + { 0, 0 , 0 }, /* 0x6C */ + { 0, 0 , 0 }, /* 0x6D */ + { 0, 0 , 0 }, /* 0x6E */ + { 0, 0 , 0 }, /* 0x6F */ + { 0, 0 , 0 }, /* 0x70 */ + { 0, 0 , 0 }, /* 0x71 */ + { 0, 0 , 0 }, /* 0x72 */ + { 0, 0 , 0 }, /* 0x73 */ + { 0, 0 , 0 }, /* 0x74 */ + { 0, 0 , 0 }, /* 0x75 */ + { 0, 0 , 0 }, /* 0x76 */ + { 0, 0 , 0 }, /* 0x77 */ + { 0, 0 , 0 }, /* 0x78 */ + { 0, 0 , 0 }, /* 0x79 */ + { 0, 0 , 0 }, /* 0x7A */ + { 0, 0 , 0 }, /* 0x7B */ + { 0, 0 , 0 }, /* 0x7C */ + { 0, 0 , 0 }, /* 0x7D */ + { 0, 0 , 0 }, /* 0x7E */ + { 0, 0 , 0 }, /* 0x7F */ +}; + + +/* Replaces tabs with spaces. */ +static void i860_dasm_tab_replacer(char* buf, int tab_size) +{ + int i = 0; + int tab_count = 0; + char tab_buf[1024]; + memset(tab_buf, 0, 1024); + + while (i != strlen(buf)) + { + if (buf[i] != '\t') + { + tab_buf[tab_count] = buf[i]; + tab_count++; + } + else + { + while (tab_count % tab_size != 0) + { + strcat(tab_buf, " "); + tab_count++; + } + } + i++; + } + + tab_buf[tab_count] = 0x00; + strcpy(buf, tab_buf); +} + + +CPU_DISASSEMBLE( i860 ) +{ + UINT32 insn = (oprom[0] << 0) | + (oprom[1] << 8) | + (oprom[2] << 16) | + (oprom[3] << 24); + + int unrecognized_op = 1; + int upper_6bits = (insn >> 26) & 0x3f; + char flags = decode_tbl[upper_6bits].flags; + if (flags & DEC_DECODED) + { + const char *s = decode_tbl[upper_6bits].mnemonic; + decode_tbl[upper_6bits].insn_dis (buffer, (char *)s, pc, insn); + unrecognized_op = 0; + } + else if (flags & DEC_MORE) + { + if (upper_6bits == 0x12) + { + /* FP instruction format handled here. */ + char fp_flags = fp_decode_tbl[insn & 0x7f].flags; + const char *s = fp_decode_tbl[insn & 0x7f].mnemonic; + if (fp_flags & DEC_DECODED) + { + fp_decode_tbl[insn & 0x7f].insn_dis (buffer, (char *)s, pc, insn); + unrecognized_op = 0; + } + } + else if (upper_6bits == 0x13) + { + /* Core escape instruction format handled here. */ + char esc_flags = core_esc_decode_tbl[insn & 0x3].flags; + const char *s = core_esc_decode_tbl[insn & 0x3].mnemonic; + if (esc_flags & DEC_DECODED) + { + core_esc_decode_tbl[insn & 0x3].insn_dis (buffer, (char *)s, pc, insn); + unrecognized_op = 0; + } + } + } + + if (unrecognized_op) + sprintf (buffer, ".long\t%#08x", insn); + + /* Replace tabs with spaces */ + i860_dasm_tab_replacer(buffer, 10); + + /* Return number of bytes disassembled. */ + /* MAME dasm flags haven't been added yet */ + return (4); +} diff --git a/src/devices/cpu/i960/i960.c b/src/devices/cpu/i960/i960.c new file mode 100644 index 00000000000..8b00a58d4c6 --- /dev/null +++ b/src/devices/cpu/i960/i960.c @@ -0,0 +1,2122 @@ +// license:BSD-3-Clause +// copyright-holders:Farfetch'd, R. Belmont +#include "emu.h" +#include "debugger.h" +#include "i960.h" + +CPU_DISASSEMBLE( i960 ); + +#ifdef _MSC_VER +/* logb prototype is different for MS Visual C */ +#include +#define logb _logb +#endif + + +const device_type I960 = &device_creator; + + +i960_cpu_device::i960_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : cpu_device(mconfig, I960, "i960kb", tag, owner, clock, "i960kb", __FILE__) + , m_program_config("program", ENDIANNESS_LITTLE, 32, 32, 0) +{ +} + + +UINT32 i960_cpu_device::i960_read_dword_unaligned(UINT32 address) +{ + if (address & 3) + return m_program->read_byte(address) | m_program->read_byte(address+1)<<8 | m_program->read_byte(address+2)<<16 | m_program->read_byte(address+3)<<24; + else + return m_program->read_dword(address); +} + +UINT16 i960_cpu_device::i960_read_word_unaligned(UINT32 address) +{ + if (address & 1) + return m_program->read_byte(address) | m_program->read_byte(address+1)<<8; + else + return m_program->read_word(address); +} + +void i960_cpu_device::i960_write_dword_unaligned(UINT32 address, UINT32 data) +{ + if (address & 3) + { + m_program->write_byte(address, data & 0xff); + m_program->write_byte(address+1, (data>>8)&0xff); + m_program->write_byte(address+2, (data>>16)&0xff); + m_program->write_byte(address+3, (data>>24)&0xff); + } + else + { + m_program->write_dword(address, data); + } +} + +void i960_cpu_device::i960_write_word_unaligned(UINT32 address, UINT16 data) +{ + if (address & 1) + { + m_program->write_byte(address, data & 0xff); + m_program->write_byte(address+1, (data>>8)&0xff); + } + else + { + m_program->write_word(address, data); + } +} + +void i960_cpu_device::send_iac(UINT32 adr) +{ + UINT32 iac[4]; + iac[0] = m_program->read_dword(adr); + iac[1] = m_program->read_dword(adr+4); + iac[2] = m_program->read_dword(adr+8); + iac[3] = m_program->read_dword(adr+12); + + switch(iac[0]>>24) { + case 0x93: // reinit + m_SAT = iac[1]; + m_PRCB = iac[2]; + m_IP = iac[3]; + break; + default: + fatalerror("I960: %x: IAC %08x %08x %08x %08x\n", m_PIP, iac[0], iac[1], iac[2], iac[3]); + } +} + +UINT32 i960_cpu_device::get_ea(UINT32 opcode) +{ + int abase = (opcode >> 14) & 0x1f; + if(!(opcode & 0x00001000)) { // MEMA + UINT32 offset = opcode & 0x1fff; + if(!(opcode & 0x2000)) + return offset; + else + return m_r[abase]+offset; + } else { // MEMB + int index = opcode & 0x1f; + int scale = (opcode >> 7) & 0x7; + int mode = (opcode >> 10) & 0xf; + UINT32 ret; + + switch(mode) { + case 0x4: + return m_r[abase]; + + case 0x7: + return m_r[abase] + (m_r[index] << scale); + + case 0xc: + ret = m_direct->read_dword(m_IP); + m_IP += 4; + return ret; + + case 0xd: + ret = m_direct->read_dword(m_IP) + m_r[abase]; + m_IP += 4; + return ret; + + case 0xe: + ret = m_direct->read_dword(m_IP) + (m_r[index] << scale); + m_IP += 4; + return ret; + + case 0xf: + ret = m_direct->read_dword(m_IP) + m_r[abase] + (m_r[index] << scale); + m_IP += 4; + return ret; + + default: + fatalerror("I960: %x: unhandled MEMB mode %x\n", m_PIP, mode); + } + } +} + +UINT32 i960_cpu_device::get_1_ri(UINT32 opcode) +{ + if(!(opcode & 0x00000800)) + return m_r[opcode & 0x1f]; + else + return opcode & 0x1f; +} + +UINT32 i960_cpu_device::get_2_ri(UINT32 opcode) +{ + if(!(opcode & 0x00001000)) + return m_r[(opcode>>14) & 0x1f]; + else + return (opcode>>14) & 0x1f; +} + +UINT64 i960_cpu_device::get_2_ri64(UINT32 opcode) +{ + if(!(opcode & 0x00001000)) + return m_r[(opcode>>14) & 0x1f] | ((UINT64)m_r[((opcode>>14) & 0x1f)+1]<<32); + else + return (opcode>>14) & 0x1f; +} + +void i960_cpu_device::set_ri(UINT32 opcode, UINT32 val) +{ + if(!(opcode & 0x00002000)) + m_r[(opcode>>19) & 0x1f] = val; + else { + fatalerror("I960: %x: set_ri on literal?\n", m_PIP); + } +} + +void i960_cpu_device::set_ri2(UINT32 opcode, UINT32 val, UINT32 val2) +{ + if(!(opcode & 0x00002000)) + { + m_r[(opcode>>19) & 0x1f] = val; + m_r[((opcode>>19) & 0x1f)+1] = val2; + } + else { + fatalerror("I960: %x: set_ri2 on literal?\n", m_PIP); + } +} + +void i960_cpu_device::set_ri64(UINT32 opcode, UINT64 val) +{ + if(!(opcode & 0x00002000)) { + m_r[(opcode>>19) & 0x1f] = val; + m_r[((opcode>>19) & 0x1f)+1] = val >> 32; + } else + fatalerror("I960: %x: set_ri64 on literal?\n", m_PIP); +} + +double i960_cpu_device::get_1_rif(UINT32 opcode) +{ + if(!(opcode & 0x00000800)) + return u2f(m_r[opcode & 0x1f]); + else { + int idx = opcode & 0x1f; + if(idx < 4) + return m_fp[idx]; + if(idx == 0x16) + return 1.0; + return 0.0; + } +} + +double i960_cpu_device::get_2_rif(UINT32 opcode) +{ + if(!(opcode & 0x00001000)) + return u2f(m_r[(opcode>>14) & 0x1f]); + else { + int idx = (opcode>>14) & 0x1f; + if(idx < 4) + return m_fp[idx]; + if(idx == 0x16) + return 1.0; + return 0.0; + } +} + +void i960_cpu_device::set_rif(UINT32 opcode, double val) +{ + if(!(opcode & 0x00002000)) + m_r[(opcode>>19) & 0x1f] = f2u(val); + else if(!(opcode & 0x00e00000)) + m_fp[(opcode>>19) & 3] = val; + else + fatalerror("I960: %x: set_rif on literal?\n", m_PIP); +} + +double i960_cpu_device::get_1_rifl(UINT32 opcode) +{ + if(!(opcode & 0x00000800)) { + UINT64 v = m_r[opcode & 0x1e]; + v |= ((UINT64)(m_r[(opcode & 0x1e)+1]))<<32; + return u2d(v); + } else { + int idx = opcode & 0x1f; + if(idx < 4) + return m_fp[idx]; + if(idx == 0x16) + return 1.0; + return 0.0; + } +} + +double i960_cpu_device::get_2_rifl(UINT32 opcode) +{ + if(!(opcode & 0x00001000)) { + UINT64 v = m_r[(opcode >> 14) & 0x1e]; + v |= ((UINT64)(m_r[((opcode>>14) & 0x1e)+1]))<<32; + return u2d(v); + } else { + int idx = (opcode>>14) & 0x1f; + if(idx < 4) + return m_fp[idx]; + if(idx == 0x16) + return 1.0; + return 0.0; + } +} + +void i960_cpu_device::set_rifl(UINT32 opcode, double val) +{ + if(!(opcode & 0x00002000)) { + UINT64 v = d2u(val); + m_r[(opcode>>19) & 0x1e] = v; + m_r[((opcode>>19) & 0x1e)+1] = v>>32; + } else if(!(opcode & 0x00e00000)) + m_fp[(opcode>>19) & 3] = val; + else + fatalerror("I960: %x: set_rifl on literal?\n", m_PIP); +} + +UINT32 i960_cpu_device::get_1_ci(UINT32 opcode) +{ + if(!(opcode & 0x00002000)) + return m_r[(opcode >> 19) & 0x1f]; + else + return (opcode >> 19) & 0x1f; +} + +UINT32 i960_cpu_device::get_2_ci(UINT32 opcode) +{ + return m_r[(opcode >> 14) & 0x1f]; +} + +UINT32 i960_cpu_device::get_disp(UINT32 opcode) +{ + UINT32 disp; + disp = opcode & 0xffffff; + if(disp & 0x00800000) + disp |= 0xff000000; + return disp-4; +} + +UINT32 i960_cpu_device::get_disp_s(UINT32 opcode) +{ + UINT32 disp; + disp = opcode & 0x1fff; + if(disp & 0x00001000) + disp |= 0xffffe000; + return disp-4; +} + +void i960_cpu_device::cmp_s(INT32 v1, INT32 v2) +{ + m_AC &= ~7; + if(v1 v2) + m_AC |= 1; +} + +void i960_cpu_device::bxx(UINT32 opcode, int mask) +{ + if(m_AC & mask) { + m_IP += get_disp(opcode); + } +} + +void i960_cpu_device::bxx_s(UINT32 opcode, int mask) +{ + if(m_AC & mask) { + m_IP += get_disp_s(opcode); + } +} + +void i960_cpu_device::test(UINT32 opcode, int mask) +{ + if(m_AC & mask) + m_r[(opcode>>19) & 0x1f] = 1; + else + m_r[(opcode>>19) & 0x1f] = 0; +} + + +// interrupt dispatch +void i960_cpu_device::take_interrupt(int vector, int lvl) +{ + int int_tab = m_program->read_dword(m_PRCB+20); // interrupt table + int int_SP = m_program->read_dword(m_PRCB+24); // interrupt stack + int SP; + UINT32 IRQV; + + IRQV = m_program->read_dword(int_tab + 36 + (vector-8)*4); + + // start the process + if(!(m_PC & 0x2000)) // if this is a nested interrupt, don't re-get int_SP + { + SP = int_SP; + } + else + { + SP = m_r[I960_SP]; + } + + SP = (SP + 63) & ~63; + SP += 128; // emulate ElSemi's core, this fixes the crash in sonic the fighters + + do_call(IRQV, 7, SP); + + // save the processor state + m_program->write_dword(m_r[I960_FP]-16, m_PC); + m_program->write_dword(m_r[I960_FP]-12, m_AC); + // store the vector + m_program->write_dword(m_r[I960_FP]-8, vector-8); + + m_PC &= ~0x1f00; // clear priority, state, trace-fault pending, and trace enable + m_PC |= (lvl<<16); // set CPU level to current IRQ level + m_PC |= 0x2002; // set supervisor mode & interrupt flag +} + +void i960_cpu_device::check_irqs() +{ + int int_tab = m_program->read_dword(m_PRCB+20); // interrupt table + int cpu_pri = (m_PC>>16)&0x1f; + int pending_pri; + int lvl, irq, take = -1; + int vword; + static const UINT32 lvlmask[4] = { 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000 }; + + pending_pri = m_program->read_dword(int_tab); // read pending priorities + + if ((m_immediate_irq) && ((cpu_pri < m_immediate_pri) || (m_immediate_pri == 31))) + { + take_interrupt(m_immediate_vector, m_immediate_pri); + m_immediate_irq = 0; + } + else + { + for(lvl = 31; lvl >= 0; lvl--) { + if((pending_pri & (1 << lvl)) && ((cpu_pri < lvl) || (lvl == 31))) { + int word, wordl, wordh; + + // figure out which word contains this level's priorities + word = ((lvl / 4) * 4) + 4; // (lvl/4) = word address, *4 for byte address, +4 to skip pending priorities + wordl = (lvl % 4) * 8; + wordh = (wordl + 8) - 1; + + vword = m_program->read_dword(int_tab + word); + + // take the first vector we find for this level + for (irq = wordh; irq >= wordl; irq--) { + if(vword & (1 << irq)) { + // clear pending bit + vword &= ~(1 << irq); + m_program->write_dword(int_tab + word, vword); + take = irq; + break; + } + } + + // if no vectors were found at our level, it's an error + if(take == -1) { + logerror("i960: ERROR! no vector found for pending level %d\n", lvl); + + // try to recover... + pending_pri &= ~(1 << lvl); + m_program->write_dword(int_tab, pending_pri); + return; + } + + // if no vectors are waiting for this level, clear the level bit + if(!(vword & lvlmask[lvl % 4])) { + pending_pri &= ~(1 << lvl); + m_program->write_dword(int_tab, pending_pri); + } + + take += ((lvl/4) * 32); + + take_interrupt(take, lvl); + return; + } + } + } +} + +void i960_cpu_device::do_call(UINT32 adr, int type, UINT32 stack) +{ + int i; + UINT32 FP; + + // call and callx take 9 cycles base + m_icount -= 9; + + // set the new RIP + m_r[I960_RIP] = m_IP; +// osd_printf_debug("CALL (type %d): FP %x, %x => %x, stack %x, rcache_pos %d\n", type, m_r[I960_FP], m_r[I960_RIP], adr, stack, m_rcache_pos); + + // are we out of cache entries? + if (m_rcache_pos >= I960_RCACHE_SIZE) { + // flush the current register set to the current frame + FP = m_r[I960_FP] & ~0x3f; + for (i = 0; i < 16; i++) { + m_program->write_dword(FP + (i*4), m_r[i]); + } + } + else // a cache entry is available, use it + { + memcpy(&m_rcache[m_rcache_pos][0], m_r, 0x10 * sizeof(UINT32)); + m_rcache_frame_addr[m_rcache_pos] = m_r[I960_FP] & ~0x3f; + } + m_rcache_pos++; + + m_IP = adr; + m_r[I960_PFP] = m_r[I960_FP] & ~7; + m_r[I960_PFP] |= type; + + if(type == 7) { // interrupts need special handling + // set the stack to the passed-in value to properly handle nested interrupts + // (can't set it externally or the original program's SP will be lost) + m_r[I960_SP] = stack; + } + + m_r[I960_FP] = (m_r[I960_SP] + 63) & ~63; + m_r[I960_SP] = m_r[I960_FP] + 64; +} + +void i960_cpu_device::do_ret_0() +{ +// int type = m_r[I960_PFP] & 7; + + m_r[I960_FP] = m_r[I960_PFP] & ~0x3f; + + m_rcache_pos--; + + // normal situation: if we're still above rcache size, we're not in cache. + // abnormal situation (after the app does a FLUSHREG): rcache_pos will be 0 + // coming in, but we must still treat it as a not-in-cache situation. + if ((m_rcache_pos >= I960_RCACHE_SIZE) || (m_rcache_pos < 0)) + { + int i; + for(i=0; i<0x10; i++) + m_r[i] = m_program->read_dword(m_r[I960_FP]+4*i); + + if (m_rcache_pos < 0) + { + m_rcache_pos = 0; + } + } + else + { + memcpy(m_r, m_rcache[m_rcache_pos], 0x10*sizeof(UINT32)); + } + +// osd_printf_debug("RET (type %d): FP %x, %x => %x, rcache_pos %d\n", type, m_r[I960_FP], m_IP, m_r[I960_RIP], m_rcache_pos); + m_IP = m_r[I960_RIP]; +} + +void i960_cpu_device::do_ret() +{ + UINT32 x, y; + m_icount -= 7; + switch(m_r[I960_PFP] & 7) { + case 0: + do_ret_0(); + break; + + case 7: + x = m_program->read_dword(m_r[I960_FP]-16); + y = m_program->read_dword(m_r[I960_FP]-12); + do_ret_0(); + m_AC = y; + // #### test supervisor + m_PC = x; + + // check for another IRQ now that we're back + check_irqs(); + break; + + default: + fatalerror("I960: %x: Unsupported return mode %d\n", m_PIP, m_r[I960_PFP] & 7); + } +} + +void i960_cpu_device::execute_op(UINT32 opcode) +{ + UINT32 t1, t2; + double t1f, t2f; + + switch(opcode >> 24) { + case 0x08: // b + m_icount--; + m_IP += get_disp(opcode); + break; + + case 0x09: // call + do_call(m_IP+get_disp(opcode), 0, m_r[I960_SP]); + break; + + case 0x0a: // ret + do_ret(); + break; + + case 0x0b: // bal + m_icount -= 5; + m_r[0x1e] = m_IP; + m_IP += get_disp(opcode); + break; + + case 0x10: // bno + m_icount--; + if(!(m_AC & 7)) { + m_IP += get_disp(opcode); + } + break; + + case 0x11: // bg + m_icount--; + bxx(opcode, 1); + break; + + case 0x12: // be + m_icount--; + bxx(opcode, 2); + break; + + case 0x13: // bge + m_icount--; + bxx(opcode, 3); + break; + + case 0x14: // bl + m_icount--; + bxx(opcode, 4); + break; + + case 0x15: // bne + m_icount--; + bxx(opcode, 5); + break; + + case 0x16: // ble + m_icount--; + bxx(opcode, 6); + break; + + case 0x17: // bo + m_icount--; + bxx(opcode, 7); + break; + + case 0x20: // testno + m_icount--; + if(!(m_AC & 7)) + m_r[(opcode>>19) & 0x1f] = 1; + else + m_r[(opcode>>19) & 0x1f] = 0; + break; + + case 0x21: // testg + m_icount--; + test(opcode, 1); + break; + + case 0x22: // teste + m_icount--; + test(opcode, 2); + break; + + case 0x23: // testge + m_icount--; + test(opcode, 3); + break; + + case 0x24: // testl + m_icount--; + test(opcode, 4); + break; + + case 0x25: // testne + m_icount--; + test(opcode, 5); + break; + + case 0x26: // testle + m_icount--; + test(opcode, 6); + break; + + case 0x27: // testo + m_icount--; + test(opcode, 7); + break; + + case 0x30: // bbc + m_icount -= 4; + t1 = get_1_ci(opcode) & 0x1f; + t2 = get_2_ci(opcode); + if(!(t2 & (1<> 7) & 0xf) { + case 0x0: // notbit + m_icount -= 2; + t1 = get_1_ri(opcode); + t2 = get_2_ri(opcode); + set_ri(opcode, t2 ^ (1<<(t1 & 31))); + break; + + case 0x1: // and + m_icount--; + t1 = get_1_ri(opcode); + t2 = get_2_ri(opcode); + set_ri(opcode, t2 & t1); + break; + + case 0x2: // andnot + m_icount--; + t1 = get_1_ri(opcode); + t2 = get_2_ri(opcode); + set_ri(opcode, t2 & ~t1); + break; + + case 0x3: // setbit + m_icount -= 2; + t1 = get_1_ri(opcode); + t2 = get_2_ri(opcode); + set_ri(opcode, t2 | (1<<(t1 & 31))); + break; + + case 0x4: // notand + m_icount--; + t1 = get_1_ri(opcode); + t2 = get_2_ri(opcode); + set_ri(opcode, (~t2) & t1); + break; + + case 0x6: // xor + m_icount--; + t1 = get_1_ri(opcode); + t2 = get_2_ri(opcode); + set_ri(opcode, t2 ^ t1); + break; + + case 0x7: // or + m_icount--; + t1 = get_1_ri(opcode); + t2 = get_2_ri(opcode); + set_ri(opcode, t2 | t1); + break; + + case 0x8: // nor + m_icount--; + t1 = get_1_ri(opcode); + t2 = get_2_ri(opcode); + set_ri(opcode, ((~t2) & (~t1))); + break; + + case 0x9: // xnor + m_icount--; + t1 = get_1_ri(opcode); + t2 = get_2_ri(opcode); + set_ri(opcode, ~(t2 ^ t1)); + break; + + case 0xa: // not + m_icount--; + t1 = get_1_ri(opcode); + set_ri(opcode, ~t1); + break; + + case 0xb: // ornot + m_icount--; + t1 = get_1_ri(opcode); + t2 = get_2_ri(opcode); + set_ri(opcode, t2 | ~t1); + break; + + case 0xc: // clrbit + m_icount -= 2; + t1 = get_1_ri(opcode); + t2 = get_2_ri(opcode); + set_ri(opcode, t2 & ~(1<<(t1 & 31))); + break; + + case 0xd: // notor + m_icount--; + t1 = get_1_ri(opcode); + t2 = get_2_ri(opcode); + set_ri(opcode, (~t2) | t1); + break; + + case 0xe: // nand + m_icount -= 2; + t1 = get_1_ri(opcode); + t2 = get_2_ri(opcode); + set_ri(opcode, ~t2 | ~t1); + break; + + case 0xf: // alterbit + m_icount -= 2; + t1 = get_1_ri(opcode); + t2 = get_2_ri(opcode); + if(m_AC & 2) + set_ri(opcode, t2 | (1<<(t1 & 31))); + else + set_ri(opcode, t2 & ~(1<<(t1 & 31))); + break; + + default: + fatalerror("I960: %x: Unhandled 58.%x\n", m_PIP, (opcode >> 7) & 0xf); + } + break; + + case 0x59: + switch((opcode >> 7) & 0xf) { + case 0x0: // addo + m_icount--; + t1 = get_1_ri(opcode); + t2 = get_2_ri(opcode); + set_ri(opcode, t2+t1); + break; + + case 0x1: // addi + // #### overflow + m_icount--; + t1 = get_1_ri(opcode); + t2 = get_2_ri(opcode); + set_ri(opcode, t2+t1); + break; + + case 0x2: // subo + m_icount--; + t1 = get_1_ri(opcode); + t2 = get_2_ri(opcode); + set_ri(opcode, t2-t1); + break; + + case 0x3: // subi + // #### overflow + m_icount--; + t1 = get_1_ri(opcode); + t2 = get_2_ri(opcode); + set_ri(opcode, t2-t1); + break; + + case 0x8: // shro + m_icount--; + t1 = get_1_ri(opcode); + t2 = get_2_ri(opcode); + set_ri(opcode, t2>>t1); + break; + + case 0xa: // shrdi + m_icount--; + t1 = get_1_ri(opcode); + t2 = get_2_ri(opcode); + if(((INT32)t2) < 0) { + if(t2 & ((1<>t1)+1); + else + set_ri(opcode, ((INT32)t2)>>t1); + } else + set_ri(opcode, t2>>t1); + break; + + case 0xb: // shri + m_icount--; + t1 = get_1_ri(opcode); + t2 = get_2_ri(opcode); + set_ri(opcode, ((INT32)t2)>>t1); + break; + + case 0xc: // shlo + m_icount--; + t1 = get_1_ri(opcode); + t2 = get_2_ri(opcode); + set_ri(opcode, t2<>(32-t1))); + break; + + case 0xe: // shli + // missing overflow + m_icount--; + t1 = get_1_ri(opcode); + t2 = get_2_ri(opcode); + set_ri(opcode, t2<> 7) & 0xf); + } + break; + + case 0x5a: + switch((opcode >> 7) & 0xf) { + case 0x0: // cmpo + m_icount--; + t1 = get_1_ri(opcode); + t2 = get_2_ri(opcode); + cmp_u(t1, t2); + break; + + case 0x1: // cmpi + m_icount--; + t1 = get_1_ri(opcode); + t2 = get_2_ri(opcode); + cmp_s(t1, t2); + break; + + case 0x2: // concmpo + m_icount--; + if(!(m_AC & 0x4)) { + t1 = get_1_ri(opcode); + t2 = get_2_ri(opcode); + concmp_u(t1, t2); + } + break; + + case 0x3: // concmpi + m_icount--; + if(!(m_AC & 0x4)) { + t1 = get_1_ri(opcode); + t2 = get_2_ri(opcode); + concmp_s(t1, t2); + } + break; + + case 0x4: // cmpinco + m_icount -= 2; + t1 = get_1_ri(opcode); + t2 = get_2_ri(opcode); + cmp_u(t1, t2); + set_ri(opcode, t2+1); + break; + + case 0x5: // cmpinci + m_icount -= 2; + t1 = get_1_ri(opcode); + t2 = get_2_ri(opcode); + cmp_s(t1, t2); + set_ri(opcode, t2+1); + break; + + case 0x6: // cmpdeco + m_icount -= 2; + t1 = get_1_ri(opcode); + t2 = get_2_ri(opcode); + cmp_u(t1, t2); + set_ri(opcode, t2-1); + break; + + case 0x7: // cmpdeci + m_icount -= 2; + t1 = get_1_ri(opcode); + t2 = get_2_ri(opcode); + cmp_s(t1, t2); + set_ri(opcode, t2-1); + break; + + case 0xe: // chkbit + m_icount -= 2; + t1 = get_1_ri(opcode) & 0x1f; + t2 = get_2_ri(opcode); + if(t2 & (1<> 7) & 0xf); + } + break; + + case 0x5b: + switch((opcode >> 7) & 0xf) { + case 0x0: // addc + { + UINT64 res; + + m_icount -= 2; + t1 = get_1_ri(opcode); + t2 = get_2_ri(opcode); + res = t2+(t1+((m_AC>>1)&1)); + set_ri(opcode, res&0xffffffff); + + m_AC &= ~0x3; // clear C and V + // set carry + m_AC |= ((res) & (((UINT64)1) << 32)) ? 0x2 : 0; + // set overflow + m_AC |= (((res) ^ (t1)) & ((res) ^ (t2)) & 0x80000000) ? 1: 0; + } + break; + + case 0x2: // subc + { + UINT64 res; + + m_icount -= 2; + t1 = get_1_ri(opcode); + t2 = get_2_ri(opcode); + res = t2-(t1+((m_AC>>1)&1)); + set_ri(opcode, res&0xffffffff); + + m_AC &= ~0x3; // clear C and V + // set carry + m_AC |= ((res) & (((UINT64)1) << 32)) ? 0x2 : 0; + // set overflow + m_AC |= (((t2) ^ (t1)) & ((t2) ^ (res)) & 0x80000000) ? 1 : 0; + } + break; + + default: + fatalerror("I960: %x: Unhandled 5b.%x\n", m_PIP, (opcode >> 7) & 0xf); + } + break; + + case 0x5c: + switch((opcode >> 7) & 0xf) { + case 0xc: // mov + m_icount -= 2; + t1 = get_1_ri(opcode); + set_ri(opcode, t1); + break; + + default: + fatalerror("I960: %x: Unhandled 5c.%x\n", m_PIP, (opcode >> 7) & 0xf); + } + break; + + case 0x5d: + switch((opcode >> 7) & 0xf) { + case 0xc: // movl + m_icount -= 2; + t2 = (opcode>>19) & 0x1e; + if(opcode & 0x00000800) { // litteral + t1 = opcode & 0x1f; + m_r[t2] = m_r[t2+1] = t1; + } else + memcpy(m_r+t2, m_r+(opcode & 0x1f), 2*sizeof(UINT32)); + break; + + default: + fatalerror("I960: %x: Unhandled 5d.%x\n", m_PIP, (opcode >> 7) & 0xf); + } + break; + + case 0x5e: + switch((opcode >> 7) & 0xf) { + case 0xc: // movt + m_icount -= 3; + t2 = (opcode>>19) & 0x1c; + if(opcode & 0x00000800) { // litteral + t1 = opcode & 0x1f; + m_r[t2] = m_r[t2+1] = m_r[t2+2]= t1; + } else + memcpy(m_r+t2, m_r+(opcode & 0x1f), 3*sizeof(UINT32)); + break; + + default: + fatalerror("I960: %x: Unhandled 5e.%x\n", m_PIP, (opcode >> 7) & 0xf); + } + break; + + case 0x5f: + switch((opcode >> 7) & 0xf) { + case 0xc: // movq + m_icount -= 4; + t2 = (opcode>>19) & 0x1c; + if(opcode & 0x00000800) { // litteral + t1 = opcode & 0x1f; + m_r[t2] = m_r[t2+1] = m_r[t2+2] = m_r[t2+3] = t1; + } else + memcpy(m_r+t2, m_r+(opcode & 0x1f), 4*sizeof(UINT32)); + break; + + default: + fatalerror("I960: %x: Unhandled 5f.%x\n", m_PIP, (opcode >> 7) & 0xf); + } + break; + + case 0x60: + switch((opcode >> 7) & 0xf) { + case 0x0: // synmov + m_icount -= 6; + t1 = get_1_ri(opcode); + t2 = get_2_ri(opcode); + // interrupt control register + if(t1 == 0xff000004) + m_ICR = m_program->read_dword(t2); + else + m_program->write_dword(t1, m_program->read_dword(t2)); + m_AC = (m_AC & ~7) | 2; + break; + + case 0x2: // synmovq + m_icount -= 12; + t1 = get_1_ri(opcode); + t2 = get_2_ri(opcode); + if(t1 == 0xff000010) + send_iac(t2); + else { + m_program->write_dword(t1, m_program->read_dword(t2)); + m_program->write_dword(t1+4, m_program->read_dword(t2+4)); + m_program->write_dword(t1+8, m_program->read_dword(t2+8)); + m_program->write_dword(t1+12, m_program->read_dword(t2+12)); + } + m_AC = (m_AC & ~7) | 2; + break; + + default: + fatalerror("I960: %x: Unhandled 60.%x\n", m_PIP, (opcode >> 7) & 0xf); + } + break; + + case 0x64: + switch((opcode >> 7) & 0xf) { + case 0x0: // spanbit + { + UINT32 res = 0xffffffff; + int i; + + m_icount -= 10; + + t1 = get_1_ri(opcode); + m_AC &= ~7; + + for (i = 31; i >= 0; i--) + { + if (!(t1 & (1<= 0; i--) + { + if (t1 & (1<> 7) & 0xf); + } + break; + + case 0x65: + switch((opcode >> 7) & 0xf) { + case 0x5: // modpc + m_icount -= 10; + t1 = m_PC; + t2 = get_2_ri(opcode); + m_PC = (m_PC & ~t2) | (m_r[(opcode>>19) & 0x1f] & t2); + set_ri(opcode, t1); + break; + + default: + fatalerror("I960: %x: Unhandled 65.%x\n", m_PIP, (opcode >> 7) & 0xf); + } + break; + + case 0x66: + switch((opcode >> 7) & 0xf) { + case 0xd: // flushreg + if (m_rcache_pos > 4) + { + m_rcache_pos = 4; + } + for(t1=0; t1 < m_rcache_pos; t1++) + { + int i; + + for (i = 0; i < 0x10; i++) + { + m_program->write_dword(m_rcache_frame_addr[t1] + (i * sizeof(UINT32)), m_rcache[t1][i]); + } + } + m_rcache_pos = 0; + break; + + default: + fatalerror("I960: %x: Unhandled 66.%x\n", m_PIP, (opcode >> 7) & 0xf); + } + break; + + case 0x67: + switch((opcode >> 7) & 0xf) { + case 0x0: // emul + m_icount -= 37; + t1 = get_1_ri(opcode); + t2 = get_2_ri(opcode); + + set_ri64(opcode, (INT64)t1 * (INT64)t2); + break; + + case 0x1: // ediv + m_icount -= 37; + { + UINT64 src1, src2; + + src1 = get_1_ri(opcode); + src2 = get_2_ri64(opcode); + + set_ri2(opcode, src2 % src1, src2 / src1); + } + break; + + case 0x4: // cvtir + m_icount -= 30; + t1 = get_1_ri(opcode); + set_rif(opcode, (double)(INT32)t1); + break; + + case 0x5: // cvtilr + m_icount -= 30; + t1 = get_1_ri(opcode); + set_rifl(opcode, (double)(INT32)t1); + break; + + case 0x6: // scalerl + m_icount -= 30; + t1 = get_1_ri(opcode); + t2f = get_2_rifl(opcode); + set_rifl(opcode, t2f * pow(2.0, (double)(INT32)t1)); + break; + + case 0x7: // scaler + m_icount -= 30; + t1 = get_1_ri(opcode); + t2f = get_2_rif(opcode); + set_rif(opcode, t2f * pow(2.0, (double)(INT32)t1)); + break; + + default: + fatalerror("I960: %x: Unhandled 67.%x\n", m_PIP, (opcode >> 7) & 0xf); + } + break; + + case 0x68: + switch((opcode >> 7) & 0xf) { + case 0x0: // atanr + m_icount -= 267; + t1f = get_1_rif(opcode); + t2f = get_2_rif(opcode); + set_rif(opcode, atan2(t2f, t1f)); + break; + + case 0x1: // logepr + m_icount -= 400; + t1f = get_1_rif(opcode); + t2f = get_2_rif(opcode); + set_rif(opcode, t2f*log(t1f+1.0)/log(2.0)); + break; + + case 0x3: // remr + m_icount -= 67; // (67 to 75878 depending on opcodes!!!) + t1f = get_1_rif(opcode); + t2f = get_2_rif(opcode); + set_rif(opcode, fmod(t2f, t1f)); + break; + + case 0x5: // cmpr + m_icount -= 10; + t1f = get_1_rif(opcode); + t2f = get_2_rif(opcode); + cmp_d(t1f, t2f); + break; + + case 0x8: // sqrtr + m_icount -= 104; + t1f = get_1_rif(opcode); + set_rif(opcode, sqrt(t1f)); + break; + + case 0xa: // logbnr + m_icount -= 37; + t1f = get_1_rif(opcode); + set_rif(opcode, logb(t1f)); + break; + + case 0xb: // roundr + { + INT32 st1 = get_1_rif(opcode); + m_icount -= 69; + set_rif(opcode, (double)st1); + } + break; + + case 0xc: // sinr + m_icount -= 406; + t1f = get_1_rif(opcode); + set_rif(opcode, sin(t1f)); + break; + + case 0xd: // cosr + m_icount -= 406; + t1f = get_1_rif(opcode); + set_rif(opcode, cos(t1f)); + break; + + case 0xe: // tanr + m_icount -= 293; + t1f = get_1_rif(opcode); + set_rif(opcode, tan(t1f)); + break; + + default: + fatalerror("I960: %x: Unhandled 68.%x\n", m_PIP, (opcode >> 7) & 0xf); + } + break; + + case 0x69: + switch((opcode >> 7) & 0xf) { + case 0x0: // atanrl + m_icount -= 350; + t1f = get_1_rifl(opcode); + t2f = get_2_rifl(opcode); + set_rifl(opcode, atan2(t2f, t1f)); + break; + + case 0x2: // logrl + m_icount -= 438; + t1f = get_1_rifl(opcode); + set_rifl(opcode, log(t1f)); + break; + + case 0x5: // cmprl + m_icount -= 12; + t1f = get_1_rifl(opcode); + t2f = get_2_rifl(opcode); + cmp_d(t1f, t2f); + break; + + case 0x8: // sqrtrl + m_icount -= 104; + t1f = get_1_rifl(opcode); + set_rifl(opcode, sqrt(t1f)); + break; + + case 0x9: // exprl + m_icount -= 334; + t1f = get_1_rifl(opcode); + set_rifl(opcode, pow(2.0, t1f)-1.0); + break; + + case 0xa: // logbnrl + m_icount -= 37; + t1f = get_1_rifl(opcode); + set_rifl(opcode, logb(t1f)); + break; + + case 0xb: // roundrl + { + INT32 st1 = get_1_rifl(opcode); + m_icount -= 70; + set_rifl(opcode, (double)st1); + } + break; + + case 0xc: // sinrl + m_icount -= 441; + t1f = get_1_rifl(opcode); + set_rifl(opcode, sin(t1f)); + break; + + case 0xd: // cosrl + m_icount -= 441; + t1f = get_1_rifl(opcode); + set_rifl(opcode, cos(t1f)); + break; + + case 0xe: // tanrl + m_icount -= 323; + t1f = get_1_rifl(opcode); + set_rifl(opcode, tan(t1f)); + break; + + default: + fatalerror("I960: %x: Unhandled 69.%x\n", m_PIP, (opcode >> 7) & 0xf); + } + break; + + case 0x6c: + switch((opcode >> 7) & 0xf) { + case 0x0: // cvtri + m_icount -= 33; + t1f = get_1_rif(opcode); + // apply rounding mode + // we do this a little indirectly to avoid some odd GCC warnings + t2f = 0.0; + switch((m_AC>>30)&3) + { + case 0: t2f = floor(t1f+0.5); break; + case 1: t2f = floor(t1f); break; + case 2: t2f = ceil(t1f); break; + case 3: t2f = t1f; break; + } + set_ri(opcode, (INT32)t2f); + break; + + case 0x2: // cvtzri + m_icount -= 43; + t1f = get_1_rif(opcode); + set_ri(opcode, (INT32)t1f); + break; + + case 0x3: // cvtzril + m_icount -= 44; + t1f = get_1_rif(opcode); + set_ri64(opcode, (INT64)t1f); + break; + + case 0x9: // movr + m_icount -= 5; + t1f = get_1_rif(opcode); + set_rif(opcode, t1f); + break; + + default: + fatalerror("I960: %x: Unhandled 6c.%x\n", m_PIP, (opcode >> 7) & 0xf); + } + break; + + case 0x6d: + switch((opcode >> 7) & 0xf) { + case 0x9: // movrl + m_icount -= 6; + t1f = get_1_rifl(opcode); + set_rifl(opcode, t1f); + break; + + default: + fatalerror("I960: %x: Unhandled 6d.%x\n", m_PIP, (opcode >> 7) & 0xf); + } + break; + + case 0x6e: + switch((opcode >> 7) & 0xf) { + case 0x1: // movre + { + UINT32 *src=0, *dst=0; + + m_icount -= 8; + + if(!(opcode & 0x00000800)) { + src = (UINT32 *)&m_r[opcode & 0x1e]; + } else { + int idx = opcode & 0x1f; + if(idx < 4) + src = (UINT32 *)&m_fp[idx]; + } + + if(!(opcode & 0x00002000)) { + dst = (UINT32 *)&m_r[(opcode>>19) & 0x1e]; + } else if(!(opcode & 0x00e00000)) + dst = (UINT32 *)&m_fp[(opcode>>19) & 3]; + + dst[0] = src[0]; + dst[1] = src[1]; + dst[2] = src[2]&0xffff; + } + break; + case 0x2: // cpysre + m_icount -= 8; + t1f = get_1_rifl(opcode); + t2f = get_2_rifl(opcode); + + if (t2f >= 0.0) + set_rifl(opcode, fabs(t1f)); + else + set_rifl(opcode, -fabs(t1f)); + break; + default: + fatalerror("I960: %x: Unhandled 6e.%x\n", m_PIP, (opcode >> 7) & 0xf); + } + break; + + case 0x70: + switch((opcode >> 7) & 0xf) { + case 0x1: // mulo + m_icount -= 18; + t1 = get_1_ri(opcode); + t2 = get_2_ri(opcode); + set_ri(opcode, t2*t1); + break; + + case 0x8: // remo + m_icount -= 37; + t1 = get_1_ri(opcode); + t2 = get_2_ri(opcode); + set_ri(opcode, t2%t1); + break; + + case 0xb: // divo + m_icount -= 37; + t1 = get_1_ri(opcode); + t2 = get_2_ri(opcode); + if (t1 == 0) // HACK! + set_ri(opcode, 0); + else + set_ri(opcode, t2/t1); + break; + + default: + fatalerror("I960: %x: Unhandled 70.%x\n", m_PIP, (opcode >> 7) & 0xf); + } + break; + + case 0x74: + switch((opcode >> 7) & 0xf) { + case 0x1: // muli + m_icount -= 18; + t1 = get_1_ri(opcode); + t2 = get_2_ri(opcode); + set_ri(opcode, ((INT32)t2)*((INT32)t1)); + break; + + case 0x8: // remi + m_icount -= 37; + t1 = get_1_ri(opcode); + t2 = get_2_ri(opcode); + set_ri(opcode, ((INT32)t2)%((INT32)t1)); + break; + + case 0x9:{// modi + INT32 src1, src2, dst; + m_icount -= 37; + src1 = (INT32)get_1_ri(opcode); + src2 = (INT32)get_2_ri(opcode); + dst = src2 - ((src2/src1)*src1); + if(((src2*src1) < 0) && (dst != 0)) + dst += src1; + set_ri(opcode, dst); + break; + } + + case 0xb: // divi + m_icount -= 37; + t1 = get_1_ri(opcode); + t2 = get_2_ri(opcode); + set_ri(opcode, ((INT32)t2)/((INT32)t1)); + break; + + default: + fatalerror("I960: %x: Unhandled 74.%x\n", m_PIP, (opcode >> 7) & 0xf); + } + break; + + case 0x78: + switch((opcode >> 7) & 0xf) { + case 0xb: // divr + m_icount -= 35; + t1f = get_1_rif(opcode); + t2f = get_2_rif(opcode); + set_rif(opcode, t2f/t1f); + break; + + case 0xc: // mulr + m_icount -= 18; + t1f = get_1_rif(opcode); + t2f = get_2_rif(opcode); + set_rif(opcode, t2f*t1f); + break; + + case 0xd: // subr + m_icount -= 10; + t1f = get_1_rif(opcode); + t2f = get_2_rif(opcode); + set_rif(opcode, t2f-t1f); + break; + + case 0xf: // addr + m_icount -= 10; + t1f = get_1_rif(opcode); + t2f = get_2_rif(opcode); + set_rif(opcode, t2f+t1f); + break; + + default: + fatalerror("I960: %x: Unhandled 78.%x\n", m_PIP, (opcode >> 7) & 0xf); + } + break; + + case 0x79: + switch((opcode >> 7) & 0xf) { + case 0xb: // divrl + m_icount -= 77; + t1f = get_1_rifl(opcode); + t2f = get_2_rifl(opcode); + set_rifl(opcode, t2f/t1f); + break; + + case 0xc: // mulrl + m_icount -= 36; + t1f = get_1_rifl(opcode); + t2f = get_2_rifl(opcode); + set_rifl(opcode, t2f*t1f); + break; + + case 0xd: // subrl + m_icount -= 13; + t1f = get_1_rifl(opcode); + t2f = get_2_rifl(opcode); + set_rifl(opcode, t2f-t1f); + break; + + case 0xf: // addrl + m_icount -= 13; + t1f = get_1_rifl(opcode); + t2f = get_2_rifl(opcode); + set_rifl(opcode, t2f+t1f); + break; + + default: + fatalerror("I960: %x: Unhandled 79.%x\n", m_PIP, (opcode >> 7) & 0xf); + } + break; + + case 0x80: // ldob + m_icount -= 4; + m_r[(opcode>>19)&0x1f] = m_program->read_byte(get_ea(opcode)); + break; + + case 0x82: // stob + m_icount -= 2; + m_program->write_byte(get_ea(opcode), m_r[(opcode>>19)&0x1f]); + break; + + case 0x84: // bx + m_icount -= 3; + m_IP = get_ea(opcode); + break; + + case 0x85: // balx + m_icount -= 5; + t1 = get_ea(opcode); + m_r[(opcode>>19)&0x1f] = m_IP; + m_IP = t1; + break; + + case 0x86: // callx + t1 = get_ea(opcode); + do_call(t1, 0, m_r[I960_SP]); + break; + + case 0x88: // ldos + m_icount -= 4; + m_r[(opcode>>19)&0x1f] = i960_read_word_unaligned(get_ea(opcode)); + break; + + case 0x8a: // stos + m_icount -= 2; + i960_write_word_unaligned(get_ea(opcode), m_r[(opcode>>19)&0x1f]); + break; + + case 0x8c: // lda + m_icount--; + m_r[(opcode>>19)&0x1f] = get_ea(opcode); + break; + + case 0x90: // ld + m_icount -= 4; + m_r[(opcode>>19)&0x1f] = i960_read_dword_unaligned(get_ea(opcode)); + break; + + case 0x92: // st + m_icount -= 2; + i960_write_dword_unaligned(get_ea(opcode), m_r[(opcode>>19)&0x1f]); + break; + + case 0x98:{// ldl + int i; + m_icount -= 5; + t1 = get_ea(opcode); + t2 = (opcode>>19)&0x1e; + m_bursting = 1; + for(i=0; i<2; i++) { + m_r[t2+i] = i960_read_dword_unaligned(t1); + if(m_bursting) + t1 += 4; + } + break; + } + + case 0x9a:{// stl + int i; + m_icount -= 3; + t1 = get_ea(opcode); + t2 = (opcode>>19)&0x1e; + m_bursting = 1; + for(i=0; i<2; i++) { + i960_write_dword_unaligned(t1, m_r[t2+i]); + if(m_bursting) + t1 += 4; + } + break; + } + + case 0xa0:{// ldt + int i; + m_icount -= 6; + t1 = get_ea(opcode); + t2 = (opcode>>19)&0x1c; + m_bursting = 1; + for(i=0; i<3; i++) { + m_r[t2+i] = i960_read_dword_unaligned(t1); + if(m_bursting) + t1 += 4; + } + break; + } + + case 0xa2:{// stt + int i; + m_icount -= 4; + t1 = get_ea(opcode); + t2 = (opcode>>19)&0x1c; + m_bursting = 1; + for(i=0; i<3; i++) { + i960_write_dword_unaligned(t1, m_r[t2+i]); + if(m_bursting) + t1 += 4; + } + break; + } + + case 0xb0:{// ldq + int i; + m_icount -= 7; + t1 = get_ea(opcode); + t2 = (opcode>>19)&0x1c; + m_bursting = 1; + for(i=0; i<4; i++) { + m_r[t2+i] = i960_read_dword_unaligned(t1); + if(m_bursting) + t1 += 4; + } + break; + } + + case 0xb2:{// stq + int i; + m_icount -= 5; + t1 = get_ea(opcode); + t2 = (opcode>>19)&0x1c; + m_bursting = 1; + for(i=0; i<4; i++) { + i960_write_dword_unaligned(t1, m_r[t2+i]); + if(m_bursting) + t1 += 4; + } + break; + } + + case 0xc0: // ldib + m_icount -= 4; + m_r[(opcode>>19)&0x1f] = (INT8)m_program->read_byte(get_ea(opcode)); + break; + + case 0xc2: // stib + m_icount -= 2; + m_program->write_byte(get_ea(opcode), m_r[(opcode>>19)&0x1f]); + break; + + case 0xc8: // ldis + m_icount -= 4; + m_r[(opcode>>19)&0x1f] = (INT16)i960_read_word_unaligned(get_ea(opcode)); + break; + + case 0xca: // stis + m_icount -= 2; + i960_write_word_unaligned(get_ea(opcode), m_r[(opcode>>19)&0x1f]); + break; + + default: + fatalerror("I960: %x: Unhandled %02x\n", m_PIP, opcode >> 24); + } + +} + +void i960_cpu_device::execute_run() +{ + UINT32 opcode; + + check_irqs(); + while(m_icount > 0) { + m_PIP = m_IP; + debugger_instruction_hook(this, m_IP); + + m_bursting = 0; + + opcode = m_direct->read_dword(m_IP); + m_IP += 4; + + execute_op(opcode); + } +} + +void i960_cpu_device::execute_set_input(int irqline, int state) +{ + int int_tab = m_program->read_dword(m_PRCB+20); // interrupt table + int cpu_pri = (m_PC>>16)&0x1f; + int vector =0; + int priority; + UINT32 pend, word, wordofs; + + // We support the 4 external IRQ lines in "normal" mode only. + // The i960's interrupt support is a bit more complete than that, + // but Namco and Sega both went for the cheapest solution. + + switch (irqline) + { + case I960_IRQ0: + vector = m_ICR & 0xff; + break; + + case I960_IRQ1: + vector = (m_ICR>>8)&0xff; + break; + + case I960_IRQ2: + vector = (m_ICR>>16)&0xff; + break; + + case I960_IRQ3: + vector = (m_ICR>>24)&0xff; + break; + } + + if(!vector) + { + logerror("i960: interrupt line %d in IAC mode, unsupported!\n", irqline); + return; + } + + + priority = vector / 8; + + if(state) { + // check if we can take this "right now" + if (((cpu_pri < priority) || (priority == 31)) && (m_immediate_irq == 0)) + { + m_immediate_irq = 1; + m_immediate_vector = vector; + m_immediate_pri = priority; + } + else + { + // store the interrupt in the "pending" table + pend = m_program->read_dword(int_tab); + pend |= (1 << priority); + m_program->write_dword(int_tab, pend); + + // now bitfield-ize the vector + word = ((vector / 32) * 4) + 4; + wordofs = vector % 32; + pend = m_program->read_dword(int_tab + word); + pend |= (1 << wordofs); + m_program->write_dword(int_tab + word, pend); + } + + // and ack it to the core now that it's queued + standard_irq_callback(irqline); + } +} + + +void i960_cpu_device::device_start() +{ + m_program = &space(AS_PROGRAM); + m_direct = &m_program->direct(); + + save_item(NAME(m_IP)); + save_item(NAME(m_PIP)); + save_item(NAME(m_SAT)); + save_item(NAME(m_PRCB)); + save_item(NAME(m_PC)); + save_item(NAME(m_AC)); + save_item(NAME(m_ICR)); + save_item(NAME(m_r)); + save_item(NAME(m_fp)); + save_item(NAME(m_rcache)); + save_item(NAME(m_rcache_frame_addr)); + save_item(NAME(m_rcache_pos)); + save_item(NAME(m_immediate_irq)); + save_item(NAME(m_immediate_vector)); + save_item(NAME(m_immediate_pri)); + + state_add( I960_SAT, "sat", m_SAT).formatstr("%08X"); + state_add( I960_PRCB, "prcb", m_PRCB).formatstr("%08X"); + state_add( I960_PC, "pc", m_PC).formatstr("%08X"); + state_add( I960_AC, "ac", m_AC).formatstr("%08X"); + state_add( I960_IP, "ip", m_IP).formatstr("%08X"); + state_add( I960_PIP, "pip", m_PIP).formatstr("%08X"); + state_add( I960_R0, "pfp", m_r[ 0]).formatstr("%08X"); + state_add( I960_R1, "sp", m_r[ 1]).formatstr("%08X"); + state_add( I960_R2, "rip", m_r[ 2]).formatstr("%08X"); + state_add( I960_R3, "r3", m_r[ 3]).formatstr("%08X"); + state_add( I960_R4, "r4", m_r[ 4]).formatstr("%08X"); + state_add( I960_R5, "r5", m_r[ 5]).formatstr("%08X"); + state_add( I960_R6, "r6", m_r[ 6]).formatstr("%08X"); + state_add( I960_R7, "r7", m_r[ 7]).formatstr("%08X"); + state_add( I960_R8, "r8", m_r[ 8]).formatstr("%08X"); + state_add( I960_R9, "r9", m_r[ 9]).formatstr("%08X"); + state_add( I960_R10, "r10", m_r[10]).formatstr("%08X"); + state_add( I960_R11, "r11", m_r[11]).formatstr("%08X"); + state_add( I960_R12, "r12", m_r[12]).formatstr("%08X"); + state_add( I960_R13, "r13", m_r[13]).formatstr("%08X"); + state_add( I960_R14, "r14", m_r[14]).formatstr("%08X"); + state_add( I960_R15, "r15", m_r[15]).formatstr("%08X"); + state_add( I960_G0, "g0", m_r[16]).formatstr("%08X"); + state_add( I960_G1, "g1", m_r[17]).formatstr("%08X"); + state_add( I960_G2, "g2", m_r[18]).formatstr("%08X"); + state_add( I960_G3, "g3", m_r[19]).formatstr("%08X"); + state_add( I960_G4, "g4", m_r[20]).formatstr("%08X"); + state_add( I960_G5, "g5", m_r[21]).formatstr("%08X"); + state_add( I960_G6, "g6", m_r[22]).formatstr("%08X"); + state_add( I960_G7, "g7", m_r[23]).formatstr("%08X"); + state_add( I960_G8, "g8", m_r[24]).formatstr("%08X"); + state_add( I960_G9, "g9", m_r[25]).formatstr("%08X"); + state_add( I960_G10, "g10", m_r[26]).formatstr("%08X"); + state_add( I960_G11, "g11", m_r[27]).formatstr("%08X"); + state_add( I960_G12, "g12", m_r[28]).formatstr("%08X"); + state_add( I960_G13, "g13", m_r[29]).formatstr("%08X"); + state_add( I960_G14, "g14", m_r[30]).formatstr("%08X"); + state_add( I960_G15, "fp", m_r[31]).formatstr("%08X"); + + state_add( STATE_GENPC, "GENPC", m_IP).noshow(); + state_add( STATE_GENFLAGS, "GENFLAGS", m_AC).noshow().formatstr("%2s"); + + m_immediate_vector = 0; + m_immediate_pri = 0; + memset(m_rcache_frame_addr, 0, sizeof(m_rcache_frame_addr)); + memset(m_fp, 0, sizeof(m_fp)); + m_PIP = 0; + + m_icountptr = &m_icount; +} + +void i960_cpu_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + static const char *const conditions[8] = + { + "no", "g", "e", "ge", "l", "ne", "le", "o" + }; + + switch (entry.index()) + { + case STATE_GENFLAGS: + strprintf(str, "%s", conditions[m_AC & 7]); + break; + } +} + +void i960_cpu_device::device_reset() +{ + m_SAT = m_program->read_dword(0); + m_PRCB = m_program->read_dword(4); + m_IP = m_program->read_dword(12); + m_PC = 0x001f2002; + m_AC = 0; + m_ICR = 0xff000000; + m_bursting = 0; + m_immediate_irq = 0; + + memset(m_r, 0, sizeof(m_r)); + memset(m_rcache, 0, sizeof(m_rcache)); + + m_r[I960_FP] = m_program->read_dword(m_PRCB+24); + m_r[I960_SP] = m_r[I960_FP] + 64; + m_rcache_pos = 0; +} + + +offs_t i960_cpu_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( i960 ); + return CPU_DISASSEMBLE_NAME(i960)(this, buffer, pc, oprom, opram, options); +} diff --git a/src/devices/cpu/i960/i960.h b/src/devices/cpu/i960/i960.h new file mode 100644 index 00000000000..7251a091fd0 --- /dev/null +++ b/src/devices/cpu/i960/i960.h @@ -0,0 +1,177 @@ +// license:BSD-3-Clause +// copyright-holders:Farfetch'd, R. Belmont +#pragma once + +#ifndef __I960_H__ +#define __I960_H__ + + +enum +{ + I960_PFP = 0, + I960_SP = 1, + I960_RIP = 2, + I960_FP = 31, + + I960_R0 = 0, + I960_R1 = 1, + I960_R2 = 2, + I960_R3 = 3, + I960_R4 = 4, + I960_R5 = 5, + I960_R6 = 6, + I960_R7 = 7, + I960_R8 = 8, + I960_R9 = 9, + I960_R10 = 10, + I960_R11 = 11, + I960_R12 = 12, + I960_R13 = 13, + I960_R14 = 14, + I960_R15 = 15, + I960_G0 = 16, + I960_G1 = 17, + I960_G2 = 18, + I960_G3 = 19, + I960_G4 = 20, + I960_G5 = 21, + I960_G6 = 22, + I960_G7 = 23, + I960_G8 = 24, + I960_G9 = 25, + I960_G10 = 26, + I960_G11 = 27, + I960_G12 = 28, + I960_G13 = 29, + I960_G14 = 30, + I960_G15 = 31, + + I960_SAT = 32, + I960_PRCB = 33, + I960_PC = 34, + I960_AC = 35, + I960_IP = 36, + I960_PIP = 37 +}; + +enum +{ + I960_IRQ0 = 0, + I960_IRQ1 = 1, + I960_IRQ2 = 2, + I960_IRQ3 = 3 +}; + + +enum { I960_RCACHE_SIZE = 4 }; + + +class i960_cpu_device : public cpu_device +{ +public: + // construction/destruction + i960_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // call from any read/write handler for a memory area that can't be bursted + // on the real hardware (e.g. Model 2's interrupt control registers) + void i960_noburst() { m_bursting = 0; } + + void i960_stall() { m_IP = m_PIP; } + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_execute_interface overrides + virtual UINT32 execute_min_cycles() const { return 1; } /* ???? TODO: Exact timing unknown */ + virtual UINT32 execute_max_cycles() const { return 1; } /* ???? TODO: Exact timing unknown */ + virtual UINT32 execute_input_lines() const { return 4; } + virtual UINT32 execute_default_irq_vector() const { return 0xffffffff; } + virtual void execute_run(); + virtual void execute_set_input(int inputnum, int state); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const { return (spacenum == AS_PROGRAM) ? &m_program_config : NULL; } + + // device_state_interface overrides + void state_string_export(const device_state_entry &entry, std::string &str); + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const { return 4; } + virtual UINT32 disasm_max_opcode_bytes() const { return 8; } + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + +private: + address_space_config m_program_config; + + UINT32 m_r[0x20]; + UINT32 m_rcache[I960_RCACHE_SIZE][0x10]; + UINT32 m_rcache_frame_addr[I960_RCACHE_SIZE]; + // rcache_pos = how deep in the stack we are. 0-(I960_RCACHE_SIZE-1) means in-cache. + // I960_RCACHE_SIZE or greater means out of cache, must save to memory. + INT32 m_rcache_pos; + + double m_fp[4]; + + UINT32 m_SAT; + UINT32 m_PRCB; + UINT32 m_PC; + UINT32 m_AC; + UINT32 m_IP; + UINT32 m_PIP; + UINT32 m_ICR; + int m_bursting; + + int m_immediate_irq; + int m_immediate_vector; + int m_immediate_pri; + + address_space *m_program; + direct_read_data *m_direct; + + int m_icount; + + UINT32 i960_read_dword_unaligned(UINT32 address); + UINT16 i960_read_word_unaligned(UINT32 address); + void i960_write_dword_unaligned(UINT32 address, UINT32 data); + void i960_write_word_unaligned(UINT32 address, UINT16 data); + void send_iac(UINT32 adr); + UINT32 get_ea(UINT32 opcode); + UINT32 get_1_ri(UINT32 opcode); + UINT32 get_2_ri(UINT32 opcode); + UINT64 get_2_ri64(UINT32 opcode); + void set_ri(UINT32 opcode, UINT32 val); + void set_ri2(UINT32 opcode, UINT32 val, UINT32 val2); + void set_ri64(UINT32 opcode, UINT64 val); + double get_1_rif(UINT32 opcode); + double get_2_rif(UINT32 opcode); + void set_rif(UINT32 opcode, double val); + double get_1_rifl(UINT32 opcode); + double get_2_rifl(UINT32 opcode); + void set_rifl(UINT32 opcode, double val); + UINT32 get_1_ci(UINT32 opcode); + UINT32 get_2_ci(UINT32 opcode); + UINT32 get_disp(UINT32 opcode); + UINT32 get_disp_s(UINT32 opcode); + void cmp_s(INT32 v1, INT32 v2); + void cmp_u(UINT32 v1, UINT32 v2); + void concmp_s(INT32 v1, INT32 v2); + void concmp_u(UINT32 v1, UINT32 v2); + void cmp_d(double v1, double v2); + void bxx(UINT32 opcode, int mask); + void bxx_s(UINT32 opcode, int mask); + void test(UINT32 opcode, int mask); + void execute_op(UINT32 opcode); + void take_interrupt(int vector, int lvl); + void check_irqs(); + void do_call(UINT32 adr, int type, UINT32 stack); + void do_ret_0(); + void do_ret(); +}; + + +extern const device_type I960; + + +#endif /* __I960_H__ */ diff --git a/src/devices/cpu/i960/i960dis.c b/src/devices/cpu/i960/i960dis.c new file mode 100644 index 00000000000..8e1a4c00431 --- /dev/null +++ b/src/devices/cpu/i960/i960dis.c @@ -0,0 +1,306 @@ +// license:BSD-3-Clause +// copyright-holders:Farfetch'd, R. Belmont +/* + Intel i960 disassembler + + By Farfetch'd and R. Belmont +*/ + +#include "emu.h" +#include "i960.h" +#include "i960dis.h" + +struct mnemonic_t +{ + const char *mnem; + unsigned short type; +}; + + +static const mnemonic_t mnemonic[256] = { + { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, // 00 + { "b", 8 }, { "call", 8 }, { "ret", 9 }, { "bal", 8 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, + + { "bno", 8 }, { "bg", 8 }, { "be", 8 }, { "bge", 8 }, { "bl", 8 }, { "bne", 8 }, { "ble", 8 }, { "bo", 8 }, // 10 + { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, + + { "testno", 10 }, { "testg", 10 }, { "teste", 10 }, { "testge", 10 }, { "testl", 10 }, { "testne", 10 }, { "testle", 10 }, { "testo", 10 }, // 20 + { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, + + { "bbc", 6 }, { "cmpobg", 7 }, { "cmpobe", 7 }, { "cmpobge", 7 }, { "cmpobl", 7 }, { "cmpobne", 7 }, { "cmpoble", 7 }, { "bbs", 6 }, // 30 + { "cmpibno", 7 }, { "cmpibg", 7 }, { "cmpibe", 7 }, { "cmpibge", 7 }, { "cmpibl", 7 }, { "cmpibne", 7 }, { "cmpible", 7 }, { "cmpibo", 7 }, + + { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, // 40 + { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, + + { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, // 50 + { "58", 3 }, { "59", 3 }, { "5A", 3 }, { "5B", 3 }, { "5C", 2 }, { "5D", 3 }, { "?", 0 }, { "5F", 3 }, + + { "synmov", 1 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "64", 3 }, { "65", 3 }, { "calls", 0 }, { "67", 3 }, // 60 + { "68", 3 }, { "69", 3 }, { "?", 0 }, { "?", 0 }, { "6C", 3 }, { "6D", 3 }, { "6E", 3 }, { "?", 0 }, + + { "70", 3 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "74", 3 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, // 70 + { "78", 3 }, { "79", 3 }, { "7A", 3 }, { "7B", 3 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, + + { "ldob", 1 }, { "?", 0 }, { "stob", 1 }, { "?", 0 }, { "bx", 1 }, { "balx", 1 }, { "callx", 1 }, { "?", 0 }, // 80 + { "ldos", 1 }, { "?", 0 }, { "stos", 1 }, { "?", 0 }, { "lda", 1 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, + + { "ld", 1 }, { "?", 0 }, { "st", 1 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, // 90 + { "ldl", 1 }, { "?", 0 }, { "stl", 1 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, + + { "ldt", 1 }, { "?", 0 }, { "stt", 1 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, // a0 + { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, + + { "ldq", 1 }, { "?", 0 }, { "stq", 1 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, // b0 + { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, + + { "ldib", 1 }, { "?", 0 }, { "stib", 1 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, // c0 + { "ldis", 1 }, { "?", 0 }, { "stis", 1 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, + + { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, // d0 + { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, + + { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, // e0 + { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, + + { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, // f0 + { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 }, { "?", 0 } +}; + +static const mnemonic_t mnem_reg[100] = +{ + { "notbit", 0x580 }, { "and", 0x581 }, { "andnot", 0x582 }, { "setbit", 0x583 }, { "notand",0x584 }, + { "xor", 0x586 }, { "or", 0x587 }, { "nor", 0x588 }, { "xnor",0x589 }, { "not",0x58a }, + { "clrbit", 0x58c }, + { "addo", 0x590 }, { "addi",0x591 }, { "subo",0x592 }, { "subi",0x593 }, { "cmpob",0x594 }, { "shro",0x598 }, { "shrdi",0x59a }, { "shri",0x59b }, { "shlo",0x59c }, { "rotate",0x59d }, { "shli",0x59e }, + { "cmpo",0x5a0 }, { "cmpi",0x5a1 }, { "concmpo",0x5a2 }, { "concmpi",0x5a3 }, { "cmpinco",0x5a4 }, { "cmpinci",0x5a5 }, { "cmpdeco",0x5a6 }, { "cmpdeci",0x5a7 }, { "scanbyte",0x5ac }, { "bswap",0x5ad }, { "chkbit",0x5ae }, + { "addc",0x5b0 }, { "subc",0x5b2 }, + { "mov", 0x5cc }, + { "movl",0x5dc }, + { "movq",0x5fc }, + { "scanbit", 0x641 }, { "daddc", 0x642 }, { "dsubc", 0x643 }, { "dmovt", 0x644 }, { "modac",0x645 }, + { "modify",0x650 }, { "extract",0x651 }, { "modtc",0x654 }, { "modpc",0x655 }, + { "emul",0x670 }, { "ediv",0x671 }, { "cvtir", 0x674 }, { "cvtilr", 0x675 }, { "scalerl", 0x676 }, { "scaler", 0x677 }, + { "atanr",0x680 }, { "logepr", 0x681 }, { "logr", 0x682 }, { "remr", 0x683 }, { "cmpor", 0x684 }, { "cmpr", 0x685 }, { "sqrtr", 0x688 }, + { "expr", 0x689 }, { "logbnr", 0x68a }, { "roundr", 0x68b }, { "sinr", 0x68c }, { "cosr", 0x68d }, { "tanr", 0x68e }, { "classr", 0x68f }, + { "atanrl",0x690 }, { "logeprl", 0x691 }, { "logrl", 0x692 }, { "remrl", 0x693 }, { "cmporl", 0x694 }, { "cmprl", 0x695 }, { "sqrtrl", 0x698 }, + { "exprl", 0x699 }, { "logbnrl", 0x69a }, { "roundrl", 0x69b }, { "sinrl", 0x69c }, { "cosrl", 0x69d }, { "tanrl", 0x69e }, { "classrl", 0x69f }, + { "cvtri", 0x6c0 }, { "cvtril", 0x6c1 }, { "cvtzri", 0x6c2 }, { "cvtzril", 0x6c3 }, { "movr", 0x6c9 }, + { "movrl", 0x6d9 }, + { "movre", 0x6e1 }, { "cpysre", 0x6e2 }, { "cpyrsre", 0x6e3 }, + { "mulo", 0x701 }, { "remo",0x708 }, { "divo",0x70b }, + { "muli",0x741 }, { "remi",0x748 }, { "modi",0x749 }, { "divi",0x74b }, + { "ending_code",0 } +}; + +static const char *const constnames[32] = +{ + "0x0", "0x1", "0x2", "0x3", "0x4", "0x5", "0x6", "0x7", "0x8", "0x9", "0xa", "0xb", "0xc", "0xd", "0xe", "0xf", + "0x10", "0x11", "0x12", "0x13", "0x14", "0x15", "0x16", "0x17", "0x18", "0x19", "0x1a", "0x1b", "0x1c", "0x1d", "0x1e", "0x1f" +}; + +static const char *const regnames[32] = +{ + "pfp","sp","rip","r3", "r4","r5","r6","r7", "r8","r9","r10","r11", "r12","r13","r14","r15", + "g0","g1","g2","g3", "g4","g5","g6","g7", "g8","g9","g10","g11", "g12","g13","g14","fp", +}; + +#define REG_DST regnames[dst] +#define REG_ABASE regnames[abase] +#define REG_REG2 regnames[reg2] +#define REG_COBR_SRC1 ((iCode & 0x2000) ? constnames[COBRSRC1] : regnames[COBRSRC1]) +#define REG_COBR_SRC2 regnames[COBRSRC2] +#define NEM mnemonic[op].mnem + +// REG format +#define SRC1 (iCode & 0x1f) +#define S1 ((iCode >> 5) & 0x1) +#define S2 ((iCode >> 6) & 0x1) +#define OP2 ((iCode >> 7) & 0xf) +#define M1 ((iCode >> 11) & 0x1) +#define M2 ((iCode >> 12) & 0x1) +#define M3 ((iCode >> 13) & 0x1) +#define SRC2 ((iCode >> 14) & 0x1f) +#define DST ((iCode >> 19) & 0x1f) +#define OP ((iCode >> 24) & 0xff) + +// COBR format +#define COBRSRC1 ((iCode >> 19) & 0x1f) +#define COBRSRC2 ((iCode >> 14) & 0x1f) + +static char *dis_decode_reg(unsigned long iCode, char* tmpStr,unsigned char cnt) +{ + char src1[10]; + char src2[10]; + char dst[10]; + + if (S1) src1[0] = 0; + else + { + if(M1) sprintf(src1,"0x%lx",SRC1); + else sprintf(src1,"%s",regnames[SRC1]); + } + if (S2) sprintf(src2,"reserved"); + else + { + if(M2) sprintf(src2,"0x%lx,",SRC2); + else sprintf(src2,"%s,",regnames[SRC2]); + } + if(M3) dst[0] = 0; + else sprintf(dst,"%s,",regnames[DST]); + if (cnt == 1) + sprintf(tmpStr,"%s%s",dst,src1); + else + sprintf(tmpStr,"%s%s%s",dst,src2,src1); + return tmpStr; +} + +#define READ32(dis,offs) ((dis)->oprom[(offs) + 0] | ((dis)->oprom[(offs) + 1] << 8) | ((dis)->oprom[(offs) + 2] << 16) | ((dis)->oprom[(offs) + 3] << 24)) + +static char *i960_disassemble(disassemble_t *diss) +{ + unsigned char op,op2; + unsigned char /*mode,*/ modeh, model; + unsigned char dst,abase,reg2; + unsigned short opc; + unsigned long iCode; + char tmpStr[256]; + long i; + + iCode = READ32(diss,0); + op = (unsigned char) (iCode >> 24); + op2 = (unsigned char) (iCode >> 7)&0xf; + + model = (unsigned char) (iCode >> 10) &0x3; + modeh = (unsigned char) (iCode >> 12) &0x3; + //mode = (unsigned char) (iCode >> 10) &0x7; + dst = (unsigned char) (iCode >> 19) &0x1f; + abase = (unsigned char) (iCode>>14)&0x1f; + reg2 = (unsigned char) (iCode)&0x1f; + + sprintf(diss->buffer,"???"); + diss->IPinc = 4; + diss->disflags = 0; + + if (op == 0x09 || op == 0x0b || op == 0x66 || op == 0x85 || op == 0x86) + diss->disflags = DASMFLAG_STEP_OVER; + else if (op == 0x0a) + diss->disflags = DASMFLAG_STEP_OUT; + + switch(mnemonic[op].type) + { + case 0: // not yet implemented + sprintf(diss->buffer,"%s %02x:%01x %08lx %1x %1x",mnemonic[op].mnem,op,op2,iCode, modeh, model); + break; + case 1: // memory access + switch(modeh) + { + case 0: + sprintf(diss->buffer, "%-8s%s,0x%lx",NEM,REG_DST, iCode&0xfff); + break; + case 1: + switch (model) + { + case 0: + sprintf(diss->buffer, "%-8s%s,(%s)",NEM,REG_DST, REG_ABASE); + break; + case 3: + sprintf(diss->buffer, "%-8s%s,(%s)[%s*%ld]",NEM,REG_DST, REG_ABASE,REG_REG2,(iCode>>7)&0x7); + break; + default: + sprintf(diss->buffer,"%s %02x:%01x %08lx %1x %1x",mnemonic[op].mnem,op,op2,iCode, modeh, model); + break; + } + break; + case 2: + sprintf(diss->buffer, "%-8s%s,0x%lx(%s)",NEM,REG_DST, iCode&0xfff,REG_ABASE); + break; + case 3: + switch (model) + { + case 0: + sprintf(diss->buffer, "%-8s%s,0x%x",NEM,REG_DST, READ32(diss,4)); + diss->IPinc = 8; + break; + case 1: + sprintf(diss->buffer, "%-8s%s,0x%x(%s)",NEM,REG_DST, READ32(diss,4),REG_ABASE); + diss->IPinc = 8; + break; + case 2: + sprintf(diss->buffer, "%-8s%s,0x%x[%s*%ld]",NEM,REG_DST, READ32(diss,4),REG_REG2,(iCode>>7)&0x7); + diss->IPinc = 8; + break; + case 3: + sprintf(diss->buffer, "%-8s%s,0x%x(%s)[%s*%ld]",NEM,REG_DST, READ32(diss,4),REG_ABASE,REG_REG2,(iCode>>7)&0x7); + diss->IPinc = 8; + break; + default: + sprintf(diss->buffer,"%s %02x:%01x %08lx %1x %1x",mnemonic[op].mnem,op,op2,iCode, modeh, model); + break; + } + break; + default: + sprintf(diss->buffer,"%s %02x:%01x %08lx %1x %1x",mnemonic[op].mnem,op,op2,iCode, modeh, model); + break; + } + break; + case 2: + i = 0; + opc = op<<4|op2; + + while(mnem_reg[i].type != 0) + { + if (mnem_reg[i].type == opc) break; + i++; + } + + if (mnem_reg[i].type == opc) sprintf(diss->buffer, "%-8s%s", mnem_reg[i].mnem,dis_decode_reg(iCode,tmpStr,1)); + else sprintf(diss->buffer,"%s %02x:%01x %08lx %1x %1x",mnemonic[op].mnem,op,op2,iCode, modeh, model); + break; + case 3: + i = 0; + opc = op<<4|op2; + + while(mnem_reg[i].type != 0) + { + if (mnem_reg[i].type == opc) break; + i++; + } + + if (mnem_reg[i].type == opc) sprintf(diss->buffer, "%-8s%s", mnem_reg[i].mnem,dis_decode_reg(iCode,tmpStr,0)); + else sprintf(diss->buffer,"%s %02x:%01x %08lx %1x %1x",mnemonic[op].mnem,op,op2,iCode, modeh, model); + break; + + case 6: // bitpos and branch type + sprintf(diss->buffer, "%-8s%ld,%s,0x%lx",NEM, COBRSRC1, REG_COBR_SRC2,((((long)iCode&0x00fffffc)<<19)>>19) + (diss->IP)); + break; + case 7: // compare and branch type + sprintf(diss->buffer, "%-8s%s,%s,0x%lx",NEM,REG_COBR_SRC1,REG_COBR_SRC2,((((long)iCode&0x00fffffc)<<19)>>19) + (diss->IP)); + break; + case 8: // target type + sprintf(diss->buffer, "%-8s%08lx",NEM,((((long)iCode&0x00fffffc)<<8)>>8) + (diss->IP)); + break; + case 9: // no operands + sprintf(diss->buffer, "%s",NEM); + break; + case 10: // TEST type: register only + sprintf(diss->buffer, "%s %s", NEM, REG_DST); + break; + } + return diss->buffer; +} + + + +CPU_DISASSEMBLE( i960 ) +{ + disassemble_t dis; + + dis.IP = pc; + dis.buffer = buffer; + dis.oprom = oprom; + + i960_disassemble(&dis); + + return dis.IPinc | dis.disflags | DASMFLAG_SUPPORTED; +} diff --git a/src/devices/cpu/i960/i960dis.h b/src/devices/cpu/i960/i960dis.h new file mode 100644 index 00000000000..6ad878ee119 --- /dev/null +++ b/src/devices/cpu/i960/i960dis.h @@ -0,0 +1,15 @@ +// license:BSD-3-Clause +// copyright-holders:Farfetch'd, R. Belmont +#ifndef __I960DIS_H__ +#define __I960DIS_H__ + +struct disassemble_t +{ + char *buffer; // output buffer + unsigned long IP; + unsigned long IPinc; + const UINT8 *oprom; + UINT32 disflags; +}; + +#endif /* __I960DIS_H__ */ diff --git a/src/devices/cpu/ie15/ie15.c b/src/devices/cpu/ie15/ie15.c new file mode 100644 index 00000000000..cae9bc8db1d --- /dev/null +++ b/src/devices/cpu/ie15/ie15.c @@ -0,0 +1,469 @@ +// license:BSD-3-Clause +// copyright-holders:Sergey Svishchev +#include "emu.h" +#include "debugger.h" +#include "ie15.h" + +//************************************************************************** +// MACROS +//************************************************************************** + +#define SKIP_OP(x) do { \ + x = rop() & 0xf0; \ + if (x == 0x10 || x == 0x20 || x == 0x30) \ + m_PC.w.l = m_PC.w.l + 1; \ + } while(0) + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +// device type definition +const device_type IE15 = &device_creator; + +//************************************************************************** +// DEVICE INTERFACE +//************************************************************************** + +//------------------------------------------------- +// ie15_device - constructor +//------------------------------------------------- +ie15_device::ie15_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : cpu_device(mconfig, IE15, "ie15", tag, owner, clock, "ie15_cpu", __FILE__), + m_program_config("program", ENDIANNESS_LITTLE, 8, 14), + m_io_config("io", ENDIANNESS_LITTLE, 8, 8), + m_program(0), + m_direct(0) +{ + // set our instruction counter + m_icountptr = &m_icount; +} + +//------------------------------------------------- +// device_start - start up the device +//------------------------------------------------- + +void ie15_device::device_start() +{ + // find address spaces + m_program = &space(AS_PROGRAM); + m_direct = &m_program->direct(); + m_io = &space(AS_IO); + + // save state + save_item(NAME(m_PC)); + save_item(NAME(m_A)); + save_item(NAME(m_CF)); + save_item(NAME(m_ZF)); + save_item(NAME(m_RF)); + // XXX save registers + + // register our state for the debugger + state_add(IE15_PC, "PC", m_PC.w.l).mask(0x0fff); + state_add(STATE_GENPC, "GENPC", m_PC.w.l).mask(0x0fff).noshow(); + state_add(STATE_GENFLAGS,"GENFLAGS", m_flags).mask(0x0f).callimport().callexport().noshow().formatstr("%4s"); + state_add(IE15_A, "A", m_A); + + std::string tempstring; + for (int ireg = 0; ireg < 32; ireg++) + state_add(IE15_R0 + ireg, strformat(tempstring, "R%d", ireg).c_str(), m_REGS[ireg]); +} + +//------------------------------------------------- +// device_reset - reset the device +//------------------------------------------------- + +void ie15_device::device_reset() +{ + m_CF = m_ZF = m_RF = 0; + m_A = 0; + m_PC.d = 0; + memset(m_REGS,0,sizeof(m_REGS)); +} + +//------------------------------------------------- +// memory_space_config - return the configuration +// of the specified address space, or NULL if +// the space doesn't exist +//------------------------------------------------- + +const address_space_config *ie15_device::memory_space_config(address_spacenum spacenum) const +{ + return (spacenum == AS_PROGRAM) ? &m_program_config : + (spacenum == AS_IO) ? &m_io_config : + NULL; +} + +//------------------------------------------------- +// state_import - import state into the device, +// after it has been set +//------------------------------------------------- + +void ie15_device::state_import(const device_state_entry &entry) +{ + switch (entry.index()) + { + case STATE_GENFLAGS: + m_CF = (m_flags >> 3) & 1; + m_ZF = (m_flags >> 2) & 1; + m_RF = (m_flags >> 1) & 1; + break; + } +} + +//------------------------------------------------- +// state_export - export state from the device, +// to a known location where it can be read +//------------------------------------------------- + +void ie15_device::state_export(const device_state_entry &entry) +{ + switch (entry.index()) + { + case STATE_GENFLAGS: + m_flags = (m_CF ? 0x08 : 0x00) | + (m_ZF ? 0x04 : 0x00) | + (m_RF ? 0x02 : 0x00); + break; + } +} + +//------------------------------------------------- +// state_string_export - export state as a string +// for the debugger +//------------------------------------------------- + +void ie15_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + switch (entry.index()) + { + case STATE_GENFLAGS: + strprintf(str, "%c%c%c", + m_CF ? 'C':'.', + m_ZF ? 'Z':'.', + m_RF ? 'R':'.'); + break; + } +} + +//------------------------------------------------- +// disasm_min_opcode_bytes - return the length +// of the shortest instruction, in bytes +//------------------------------------------------- + +UINT32 ie15_device::disasm_min_opcode_bytes() const +{ + return 1; +} + +//------------------------------------------------- +// disasm_max_opcode_bytes - return the length +// of the longest instruction, in bytes +//------------------------------------------------- + +UINT32 ie15_device::disasm_max_opcode_bytes() const +{ + return 2; +} + +//------------------------------------------------- +// disasm_disassemble - call the disassembly +// helper function +//------------------------------------------------- + +offs_t ie15_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( ie15 ); + return CPU_DISASSEMBLE_NAME(ie15)(NULL, buffer, pc, oprom, opram, 0); +} + +//************************************************************************** +// EXECUTION +//************************************************************************** + +//------------------------------------------------- +// execute_min_cycles - return minimum number of +// cycles it takes for one instruction to execute +//------------------------------------------------- + +UINT32 ie15_device::execute_min_cycles() const +{ + return 1; +} + +//------------------------------------------------- +// execute_max_cycles - return maximum number of +// cycles it takes for one instruction to execute +//------------------------------------------------- + +UINT32 ie15_device::execute_max_cycles() const +{ + return 1; +} + +//------------------------------------------------- +// execute_run - execute until our icount expires +//------------------------------------------------- + +void ie15_device::execute_run() +{ + do + { + debugger_instruction_hook(this, m_PC.d); + execute_one(rop()); + } while (m_icount > 0); +} + +inline void ie15_device::illegal(UINT8 opcode) +{ + if ((machine().debug_flags & DEBUG_FLAG_ENABLED) != 0) + { + logerror("IE15 illegal instruction %04X $%02X\n", m_PC.w.l, opcode); + } +} + +// XXX verify that m_ZF and m_CF are set and handled right +// XXX 'ota' apparently writes the ALU buffer register, not accumulator +// XXX what if ldc was at 0x_ff? +inline void ie15_device::execute_one(int opcode) +{ + UINT16 tmp; + + m_icount -= 1; + + switch (opcode & 0xf0) + { + case 0x00: // add + tmp = m_A + get_reg_lo(opcode & 15); + m_A = tmp & 255; + update_flags(m_A); + m_CF = BIT(tmp, 8); + break; + case 0x10: // jmp + m_PC.w.l = get_addr(opcode); +// m_CF = 0; + break; + case 0x20: // ldc + set_reg(opcode & 15, arg() | (m_PC.w.l & 0xf00)); + m_PC.w.l = m_PC.w.l + 1; +// m_CF = 0; + break; + case 0x40: // dsr + tmp = get_reg_lo(opcode & 15) - 1; +// m_CF = BIT(tmp, 8); + tmp &= 255; + set_reg(opcode & 15, tmp); + update_flags(tmp); + if (m_ZF) { + SKIP_OP(tmp); + } + break; + case 0x30: + switch (opcode) + { + case 0x30: // lca + m_A = arg(); + update_flags(m_A); + m_PC.w.l = m_PC.w.l + 1; + break; + case 0x33: // ral + tmp = m_A; + m_A = (m_A << 1) | BIT(tmp,7); + update_flags(m_A); + break; + case 0x35: // rar + tmp = m_A; + m_A = (m_A >> 1) | (BIT(tmp,0) ? 0x80 : 0x00); + update_flags(m_A); + break; + default: + illegal(opcode); + break; + }; + break; + case 0x50: + switch (opcode) + { + case 0x51: // inc + case 0x50: // isn + case 0x58: // ise + tmp = m_A + 1; + m_A = tmp & 255; + update_flags(m_A); + m_CF = BIT(tmp, 8); + if (opcode == 0x50 && m_ZF) + SKIP_OP(tmp); + if (opcode == 0x58 && !m_ZF) + SKIP_OP(tmp); + break; + case 0x5b: // dec + case 0x52: // dsn + case 0x5a: // dse + tmp = m_A - 1; + m_A = tmp & 255; + update_flags(m_A); + m_CF = BIT(tmp, 8); + if (opcode == 0x52 && m_ZF) + SKIP_OP(tmp); + if (opcode == 0x5a && !m_ZF) + SKIP_OP(tmp); + break; + case 0x5d: // com + m_A ^= 255; + update_flags(m_A); + break; + case 0x5f: // clr + m_A = 0; + update_flags(m_A); + break; + default: + illegal(opcode); + break; + }; + break; + case 0x70: // jmi +// m_CF = 0; + m_PC.w.l = get_reg(opcode & 15); + break; + case 0x60: // lla + // special case -- port 7 + if (opcode == 0x67) + m_A = 255; + else + m_A = m_io->read_byte(opcode & 15); + update_flags(m_A); + break; + case 0xf0: // ota + // special case -- ports 016, 017 + if (opcode == 0xfe) + m_RF = 1; + else if (opcode == 0xff) + m_RF = 0; + else + m_io->write_byte(opcode & 15, m_A); +// m_CF = 0; + break; + case 0xc0: // cfl, sfl + switch (opcode) + { + // special case -- accessing control flag 05 resets CF + case 0xc5: + case 0xcd: + m_CF = 0; + break; + default: + m_io->write_byte(020 | (opcode & 7), BIT(opcode, 3)); + break; + } + break; + case 0x80: // sfc, skp, sfs, nop + tmp = opcode & 7; + switch (tmp) + { + case 5: + tmp = BIT(m_A, 7); + break; + case 6: + tmp = m_CF; + break; + case 7: + tmp = 0; + break; + default: + tmp = m_io->read_byte(020 | tmp); + break; + + } + if (!BIT(opcode, 3) && !tmp) + SKIP_OP(tmp); + if (BIT(opcode, 3) && tmp) + SKIP_OP(tmp); + break; + case 0xb0: // cs +// m_CF = 0; + if (m_A == get_reg_lo(opcode & 15)) { + m_ZF = 1; + SKIP_OP(tmp); + } + break; + case 0x90: // and + m_A &= get_reg_lo(opcode & 15); + update_flags(m_A); + break; + case 0xa0: // xor + m_A ^= get_reg_lo(opcode & 15); + update_flags(m_A); + break; + case 0xd0: // lda + m_A = get_reg_lo(opcode & 15); + update_flags(m_A); + break; + case 0xe0: // sta + set_reg(opcode & 15, m_A | (m_PC.w.l & 0xf00)); +// m_CF = 0; + break; + default: + illegal(opcode); + break; + } +} + +/*************************************************************************** + INLINE FUNCTIONS +***************************************************************************/ + +inline UINT8 ie15_device::rop() +{ + UINT8 retVal = m_direct->read_byte(m_PC.w.l); + m_PC.w.l = (m_PC.w.l + 1) & 0x0fff; + return retVal; +} + +inline UINT8 ie15_device::arg() +{ + UINT8 retVal = m_direct->read_byte(m_PC.w.l); + return retVal; +} + +inline UINT8 ie15_device::get_reg_lo(UINT8 reg) +{ + UINT16 tmp = m_RF ? m_REGS[16 + reg] : m_REGS[reg]; + return tmp & 255; +} + +inline UINT16 ie15_device::get_reg(UINT8 reg) +{ + return m_RF ? m_REGS[16 + reg] : m_REGS[reg]; +} + +inline void ie15_device::set_reg(UINT8 reg, UINT16 val) +{ + (m_RF ? m_REGS[16 + reg] : m_REGS[reg]) = val; + +} + +inline void ie15_device::update_flags(UINT8 val) +{ + m_ZF = (val == 0xff) ? 1 : 0; +} + +inline UINT8 ie15_device::do_condition(UINT8 val) +{ + UINT8 v = (val >> 5) & 1; + UINT8 cond = 0; + switch((val>> 3) & 0x03) { + case 0 : + if (m_CF==v) cond = 1; + break; + case 1 : + if (m_ZF==v) cond = 1; + break; + } + return cond; +} + +inline UINT16 ie15_device::get_addr(UINT8 val) +{ + UINT8 lo = arg(); + return ((val & 0x0f) << 8) + lo + 1; +} diff --git a/src/devices/cpu/ie15/ie15.h b/src/devices/cpu/ie15/ie15.h new file mode 100644 index 00000000000..8aaaa5a81ab --- /dev/null +++ b/src/devices/cpu/ie15/ie15.h @@ -0,0 +1,92 @@ +// license:BSD-3-Clause +// copyright-holders:Sergey Svishchev +#ifndef __IE15_H__ +#define __IE15_H__ + +//************************************************************************** +// ENUMERATIONS +//************************************************************************** + +enum +{ + IE15_PC, + IE15_A, + IE15_R0, IE15_R1, IE15_R2, IE15_R3, IE15_R4, IE15_R5, IE15_R6, IE15_R7, + IE15_R8, IE15_R9, IE15_R10, IE15_R11, IE15_R12, IE15_R13, IE15_R14, IE15_R15, + IE15_R16, IE15_R17, IE15_R18, IE15_R19, IE15_R20, IE15_R21, IE15_R22, IE15_R23, + IE15_R24, IE15_R25, IE15_R26, IE15_R27, IE15_R28, IE15_R29, IE15_R30, IE15_R31, + + IE15_GENPC = STATE_GENPC, + IE15_GENPCBASE = STATE_GENPCBASE +}; + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class ie15_device; + +class ie15_device : public cpu_device +{ +public: + // construction/destruction + ie15_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_execute_interface overrides + virtual UINT32 execute_min_cycles() const; + virtual UINT32 execute_max_cycles() const; + virtual void execute_run(); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const; + + // device_state_interface overrides + virtual void state_import(const device_state_entry &entry); + virtual void state_export(const device_state_entry &entry); + virtual void state_string_export(const device_state_entry &entry, std::string &str); + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const; + virtual UINT32 disasm_max_opcode_bytes() const; + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + + virtual void execute_one(int opcode); + + UINT8 rop(); + UINT8 get_reg_lo(UINT8 reg); + UINT16 get_reg(UINT8 reg); + void set_reg(UINT8 reg, UINT16 val); + UINT8 arg(); + void update_flags(UINT8 val); + UINT8 do_condition(UINT8 val); + UINT16 get_addr(UINT8 val); + void illegal(UINT8 opcode); + + int m_icount; + + // configuration + const address_space_config m_program_config; + const address_space_config m_io_config; + + UINT8 m_A; + PAIR m_PC; + UINT16 m_REGS[32]; // General registers (2 pages of 16) + UINT8 m_CF; // Carry flag + UINT8 m_ZF; // Zero flag + UINT8 m_RF; // Current register page + UINT8 m_flags; // temporary I/O only + + address_space *m_program; + address_space *m_io; + direct_read_data *m_direct; +}; + +// device type definition +extern const device_type IE15; + +#endif diff --git a/src/devices/cpu/ie15/ie15dasm.c b/src/devices/cpu/ie15/ie15dasm.c new file mode 100644 index 00000000000..3f21fb977e0 --- /dev/null +++ b/src/devices/cpu/ie15/ie15dasm.c @@ -0,0 +1,126 @@ +// license:BSD-3-Clause +// copyright-holders:Sergey Svishchev +#include "emu.h" + +#define OP(A) oprom[(A) - PC] +#define ARG(A) opram[(A) - PC] + +CPU_DISASSEMBLE( ie15 ) +{ + UINT32 flags = 0; + UINT8 op; + unsigned PC = pc; + + op = OP(pc++); + switch (op & 0xf0) + { + case 0x00: + sprintf (buffer,"add r%d", op & 0x0f); + break; + case 0x10: + sprintf (buffer,"jmp $%04x", (((op & 0x0f) << 8) | ARG(pc)) + 1); + pc+=1; + break; + case 0x20: + sprintf (buffer,"ldc r%d, #$%02x", (op & 0x0f), ARG(pc)); + pc+=1; + break; + case 0x30: switch (op) + { + case 0x30: + sprintf (buffer,"lca #$%02x", ARG(pc)); + pc+=1; + break; + case 0x33: + sprintf (buffer,"ral"); + break; + case 0x35: + sprintf (buffer,"rar"); + break; + default: + sprintf (buffer,"illegal"); + break; + }; + break; + case 0x40: + sprintf (buffer,"dsr r%d", op & 0x0f); + break; + case 0x50: switch (op) + { + case 0x50: + sprintf (buffer,"isn"); + break; + case 0x51: + sprintf (buffer,"inc"); + break; + case 0x52: + sprintf (buffer,"dsn"); + break; + case 0x58: + sprintf (buffer,"ise"); + break; + case 0x5a: + sprintf (buffer,"dse"); + break; + case 0x5b: + sprintf (buffer,"dec"); + break; + case 0x5d: + sprintf (buffer,"com"); + break; + case 0x5f: + sprintf (buffer,"clr"); + break; + default: + sprintf (buffer,"illegal"); + break; + }; + break; + case 0x60: + sprintf (buffer,"lla #$%02x", op & 0x0f); + break; + case 0x70: + sprintf (buffer,"jmi r%d", op & 0x0f); + break; + case 0x80: switch (op) + { + case 0x80: case 0x81: case 0x82: case 0x83: + case 0x84: case 0x85: case 0x86: + sprintf (buffer,"sfc #%d", op & 0x07); + break; + case 0x87: + sprintf (buffer,"skp"); + break; + case 0x88: case 0x89: case 0x8a: case 0x8b: + case 0x8c: case 0x8d: case 0x8e: + sprintf (buffer,"sfs #%d", op & 0x07); + break; + case 0x8f: + sprintf (buffer,"nop"); + break; + }; + break; + case 0x90: + sprintf (buffer,"and r%d", op & 0x0f); + break; + case 0xa0: + sprintf (buffer,"xor r%d", op & 0x0f); + break; + case 0xb0: + sprintf (buffer,"cs r%d", op & 0x0f); + break; + case 0xc0: + sprintf (buffer,"%s #%d", BIT(op, 3) ? "sfl" : "cfl", op & 0x07); + break; + case 0xd0: + sprintf (buffer,"lda r%d", op & 0x0f); + break; + case 0xe0: + sprintf (buffer,"sta r%d", op & 0x0f); + break; + case 0xf0: + sprintf (buffer,"ota #$%02x", op & 0x0f); + break; + } + return (pc - PC) | flags | DASMFLAG_SUPPORTED; +} diff --git a/src/devices/cpu/jaguar/jagdasm.c b/src/devices/cpu/jaguar/jagdasm.c new file mode 100644 index 00000000000..e5e9cd70882 --- /dev/null +++ b/src/devices/cpu/jaguar/jagdasm.c @@ -0,0 +1,196 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + jagdasm.c + Disassembler for the portable Jaguar DSP emulator. + Written by Aaron Giles + +***************************************************************************/ + +#include "emu.h" +#include "jaguar.h" + + +/*************************************************************************** + MEMORY ACCESSORS +***************************************************************************/ + +#define ROPCODE(offs) ((oprom[offs] << 8) | oprom[(offs) + 1]) + + +/*************************************************************************** + STATIC VARIABLES +***************************************************************************/ + +static const UINT8 convert_zero[32] = +{ 32,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31 }; + +static const char *const condition[32] = +{ + "", + "nz,", + "z,", + "???,", + "nc,", + "nc nz,", + "nc z,", + "???,", + "c,", + "c nz,", + "c z,", + "???,", + "???,", + "???,", + "???,", + "???,", + + "???,", + "???,", + "???,", + "???,", + "nn,", + "nn nz,", + "nn z,", + "???,", + "n,", + "n nz,", + "n z,", + "???,", + "???,", + "???,", + "???,", + "never," +}; + + + +/*************************************************************************** + CODE CODE +***************************************************************************/ + +INLINE char *signed_16bit(INT16 val) +{ + static char temp[10]; + if (val < 0) + sprintf(temp, "-$%x", -val); + else + sprintf(temp, "$%x", val); + return temp; +} + +static unsigned dasmjag(int variant, char *buffer, unsigned pc, const UINT8 *oprom) +{ + UINT32 flags = 0; + int op = ROPCODE(0); + int reg1 = (op >> 5) & 31; + int reg2 = op & 31; + int size = 2; + + pc += 2; + switch (op >> 10) + { + case 0: sprintf(buffer, "add r%d,r%d", reg1, reg2); break; + case 1: sprintf(buffer, "addc r%d,r%d", reg1, reg2); break; + case 2: sprintf(buffer, "addq $%x,r%d", convert_zero[reg1], reg2); break; + case 3: sprintf(buffer, "addqt $%x,r%d", convert_zero[reg1], reg2); break; + case 4: sprintf(buffer, "sub r%d,r%d", reg1, reg2); break; + case 5: sprintf(buffer, "subc r%d,r%d", reg1, reg2); break; + case 6: sprintf(buffer, "subq $%x,r%d", convert_zero[reg1], reg2); break; + case 7: sprintf(buffer, "subqt $%x,r%d", convert_zero[reg1], reg2); break; + case 8: sprintf(buffer, "neg r%d", reg2); break; + case 9: sprintf(buffer, "and r%d,r%d", reg1, reg2); break; + case 10: sprintf(buffer, "or r%d,r%d", reg1, reg2); break; + case 11: sprintf(buffer, "xor r%d,r%d", reg1, reg2); break; + case 12: sprintf(buffer, "not r%d", reg2); break; + case 13: sprintf(buffer, "btst $%x,r%d", reg1, reg2); break; + case 14: sprintf(buffer, "bset $%x,r%d", reg1, reg2); break; + case 15: sprintf(buffer, "bclr $%x,r%d", reg1, reg2); break; + case 16: sprintf(buffer, "mult r%d,r%d", reg1, reg2); break; + case 17: sprintf(buffer, "imult r%d,r%d", reg1, reg2); break; + case 18: sprintf(buffer, "imultn r%d,r%d", reg1, reg2); break; + case 19: sprintf(buffer, "resmac r%d", reg2); break; + case 20: sprintf(buffer, "imacn r%d,r%d", reg1, reg2); break; + case 21: sprintf(buffer, "div r%d,r%d", reg1, reg2); break; + case 22: sprintf(buffer, "abs r%d", reg2); break; + case 23: sprintf(buffer, "sh r%d,r%d", reg1, reg2); break; + case 24: sprintf(buffer, "shlq $%x,r%d", 32 - convert_zero[reg1], reg2); break; + case 25: sprintf(buffer, "shrq $%x,r%d", convert_zero[reg1], reg2); break; + case 26: sprintf(buffer, "sha r%d,r%d", reg1, reg2); break; + case 27: sprintf(buffer, "sharq $%x,r%d", convert_zero[reg1], reg2); break; + case 28: sprintf(buffer, "ror r%d,r%d", reg1, reg2); break; + case 29: sprintf(buffer, "rorq $%x,r%d", convert_zero[reg1], reg2); break; + case 30: sprintf(buffer, "cmp r%d,r%d", reg1, reg2); break; + case 31: sprintf(buffer, "cmpq %s,r%d", signed_16bit((INT16)(reg1 << 11) >> 11), reg2);break; + case 32: if (variant == JAGUAR_VARIANT_GPU) + sprintf(buffer, "sat8 r%d", reg2); + else + sprintf(buffer, "subqmod $%x,r%d", convert_zero[reg1], reg2); + break; + case 33: if (variant == JAGUAR_VARIANT_GPU) + sprintf(buffer, "sat16 r%d", reg2); + else + sprintf(buffer, "sat16s r%d", reg2); + break; + case 34: sprintf(buffer, "move r%d,r%d", reg1, reg2); break; + case 35: sprintf(buffer, "moveq %d,r%d", reg1, reg2); break; + case 36: sprintf(buffer, "moveta r%d,r%d", reg1, reg2); break; + case 37: sprintf(buffer, "movefa r%d,r%d", reg1, reg2); break; + case 38: sprintf(buffer, "movei $%x,r%d", ROPCODE(2) | (ROPCODE(4)<<16), reg2); size = 6; break; + case 39: sprintf(buffer, "loadb (r%d),r%d", reg1, reg2); break; + case 40: sprintf(buffer, "loadw (r%d),r%d", reg1, reg2); break; + case 41: sprintf(buffer, "load (r%d),r%d", reg1, reg2); break; + case 42: if (variant == JAGUAR_VARIANT_GPU) + sprintf(buffer, "loadp (r%d),r%d", reg1, reg2); + else + sprintf(buffer, "sat32s r%d", reg2); + break; + case 43: sprintf(buffer, "load (r14+$%x),r%d", convert_zero[reg1]*4, reg2);break; + case 44: sprintf(buffer, "load (r15+$%x),r%d", convert_zero[reg1]*4, reg2);break; + case 45: sprintf(buffer, "storeb r%d,(r%d)", reg2, reg1); break; + case 46: sprintf(buffer, "storew r%d,(r%d)", reg2, reg1); break; + case 47: sprintf(buffer, "store r%d,(r%d)", reg2, reg1); break; + case 48: if (variant == JAGUAR_VARIANT_GPU) + sprintf(buffer, "storep r%d,(r%d)", reg2, reg1); + else + sprintf(buffer, "mirror r%d", reg2); + break; + case 49: sprintf(buffer, "store r%d,(r14+$%x)", reg2, convert_zero[reg1]*4);break; + case 50: sprintf(buffer, "store r%d,(r15+$%x)", reg2, convert_zero[reg1]*4);break; + case 51: sprintf(buffer, "move pc,r%d", reg2); break; + case 52: sprintf(buffer, "jump %s(r%d)", condition[reg2], reg1); break; + case 53: sprintf(buffer, "jr %s%08X", condition[reg2], pc + ((INT8)(reg1 << 3) >> 2)); break; + case 54: sprintf(buffer, "mmult r%d,r%d", reg1, reg2); break; + case 55: sprintf(buffer, "mtoi r%d,r%d", reg1, reg2); break; + case 56: sprintf(buffer, "normi r%d,r%d", reg1, reg2); break; + case 57: sprintf(buffer, "nop"); break; + case 58: sprintf(buffer, "load (r14+r%d),r%d", reg1, reg2); break; + case 59: sprintf(buffer, "load (r15+r%d),r%d", reg1, reg2); break; + case 60: sprintf(buffer, "store r%d,(r14+r%d)", reg2, reg1); break; + case 61: sprintf(buffer, "store r%d,(r15+r%d)", reg2, reg1); break; + case 62: if (variant == JAGUAR_VARIANT_GPU) + sprintf(buffer, "sat24 r%d", reg2); + else + sprintf(buffer, "illegal"); + break; + case 63: if (variant == JAGUAR_VARIANT_GPU) + sprintf(buffer, reg1 ? + "unpack r%d" : + "pack r%d", reg2); + else + sprintf(buffer, "addqmod $%x,r%d", convert_zero[reg1], reg2); + break; + } + return size | flags | DASMFLAG_SUPPORTED; +} + + +CPU_DISASSEMBLE( jaguargpu ) +{ + return dasmjag(JAGUAR_VARIANT_GPU, buffer, pc, oprom); +} + +CPU_DISASSEMBLE( jaguardsp ) +{ + return dasmjag(JAGUAR_VARIANT_DSP, buffer, pc, oprom); +} diff --git a/src/devices/cpu/jaguar/jaguar.c b/src/devices/cpu/jaguar/jaguar.c new file mode 100644 index 00000000000..976ab4f5983 --- /dev/null +++ b/src/devices/cpu/jaguar/jaguar.c @@ -0,0 +1,1452 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + jaguar.c + Core implementation for the portable Jaguar DSP emulator. + Written by Aaron Giles + +***************************************************************************/ + +#include "emu.h" +#include "debugger.h" +#include "jaguar.h" + + +#define LOG_GPU_IO 0 +#define LOG_DSP_IO 0 + + +/*************************************************************************** + CONSTANTS +***************************************************************************/ + +#define ZFLAG 0x00001 +#define CFLAG 0x00002 +#define NFLAG 0x00004 +#define IFLAG 0x00008 +#define EINT0FLAG 0x00010 +#define EINT1FLAG 0x00020 +#define EINT2FLAG 0x00040 +#define EINT3FLAG 0x00080 +#define EINT4FLAG 0x00100 +#define EINT04FLAGS (EINT0FLAG | EINT1FLAG | EINT2FLAG | EINT3FLAG | EINT4FLAG) +#define CINT0FLAG 0x00200 +#define CINT1FLAG 0x00400 +#define CINT2FLAG 0x00800 +#define CINT3FLAG 0x01000 +#define CINT4FLAG 0x02000 +#define CINT04FLAGS (CINT0FLAG | CINT1FLAG | CINT2FLAG | CINT3FLAG | CINT4FLAG) +#define RPAGEFLAG 0x04000 +#define DMAFLAG 0x08000 +#define EINT5FLAG 0x10000 /* DSP only */ +#define CINT5FLAG 0x20000 /* DSP only */ + +#define CLR_Z() (FLAGS &= ~ZFLAG) +#define CLR_ZN() (FLAGS &= ~(ZFLAG | NFLAG)) +#define CLR_ZNC() (FLAGS &= ~(CFLAG | ZFLAG | NFLAG)) +#define SET_Z(r) (FLAGS |= ((r) == 0)) +#define SET_C_ADD(a,b) (FLAGS |= ((UINT32)(b) > (UINT32)(~(a))) << 1) +#define SET_C_SUB(a,b) (FLAGS |= ((UINT32)(b) > (UINT32)(a)) << 1) +#define SET_N(r) (FLAGS |= (((UINT32)(r) >> 29) & 4)) +#define SET_ZN(r) SET_N(r); SET_Z(r) +#define SET_ZNC_ADD(a,b,r) SET_N(r); SET_Z(r); SET_C_ADD(a,b) +#define SET_ZNC_SUB(a,b,r) SET_N(r); SET_Z(r); SET_C_SUB(a,b) + + + +/*************************************************************************** + MACROS +***************************************************************************/ + +#define PC m_ctrl[G_PC] +#define FLAGS m_ctrl[G_FLAGS] + +#define CONDITION(x) condition_table[(x) + ((FLAGS & 7) << 5)] + +#define READBYTE(a) m_program->read_byte(a) +#define READWORD(a) m_program->read_word(a) +#define READLONG(a) m_program->read_dword(a) + +#define WRITEBYTE(a,v) m_program->write_byte(a, v) +#define WRITEWORD(a,v) m_program->write_word(a, v) +#define WRITELONG(a,v) m_program->write_dword(a, v) + + + +/*************************************************************************** + PRIVATE GLOBAL VARIABLES +***************************************************************************/ + +static UINT32 table_refcount = 0; +static UINT16 * mirror_table; +static UINT8 * condition_table; + +const UINT32 jaguar_cpu_device::convert_zero[32] = +{ 32,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31 }; + + + +/*************************************************************************** + FUNCTION TABLES +***************************************************************************/ + +const jaguar_cpu_device::op_func jaguar_cpu_device::gpu_op_table[64] = +{ + /* 00-03 */ &jaguar_cpu_device::add_rn_rn, &jaguar_cpu_device::addc_rn_rn, &jaguar_cpu_device::addq_n_rn, &jaguar_cpu_device::addqt_n_rn, + /* 04-07 */ &jaguar_cpu_device::sub_rn_rn, &jaguar_cpu_device::subc_rn_rn, &jaguar_cpu_device::subq_n_rn, &jaguar_cpu_device::subqt_n_rn, + /* 08-11 */ &jaguar_cpu_device::neg_rn, &jaguar_cpu_device::and_rn_rn, &jaguar_cpu_device::or_rn_rn, &jaguar_cpu_device::xor_rn_rn, + /* 12-15 */ &jaguar_cpu_device::not_rn, &jaguar_cpu_device::btst_n_rn, &jaguar_cpu_device::bset_n_rn, &jaguar_cpu_device::bclr_n_rn, + /* 16-19 */ &jaguar_cpu_device::mult_rn_rn, &jaguar_cpu_device::imult_rn_rn, &jaguar_cpu_device::imultn_rn_rn, &jaguar_cpu_device::resmac_rn, + /* 20-23 */ &jaguar_cpu_device::imacn_rn_rn, &jaguar_cpu_device::div_rn_rn, &jaguar_cpu_device::abs_rn, &jaguar_cpu_device::sh_rn_rn, + /* 24-27 */ &jaguar_cpu_device::shlq_n_rn, &jaguar_cpu_device::shrq_n_rn, &jaguar_cpu_device::sha_rn_rn, &jaguar_cpu_device::sharq_n_rn, + /* 28-31 */ &jaguar_cpu_device::ror_rn_rn, &jaguar_cpu_device::rorq_n_rn, &jaguar_cpu_device::cmp_rn_rn, &jaguar_cpu_device::cmpq_n_rn, + /* 32-35 */ &jaguar_cpu_device::sat8_rn, &jaguar_cpu_device::sat16_rn, &jaguar_cpu_device::move_rn_rn, &jaguar_cpu_device::moveq_n_rn, + /* 36-39 */ &jaguar_cpu_device::moveta_rn_rn, &jaguar_cpu_device::movefa_rn_rn, &jaguar_cpu_device::movei_n_rn, &jaguar_cpu_device::loadb_rn_rn, + /* 40-43 */ &jaguar_cpu_device::loadw_rn_rn, &jaguar_cpu_device::load_rn_rn, &jaguar_cpu_device::loadp_rn_rn, &jaguar_cpu_device::load_r14n_rn, + /* 44-47 */ &jaguar_cpu_device::load_r15n_rn, &jaguar_cpu_device::storeb_rn_rn, &jaguar_cpu_device::storew_rn_rn, &jaguar_cpu_device::store_rn_rn, + /* 48-51 */ &jaguar_cpu_device::storep_rn_rn, &jaguar_cpu_device::store_rn_r14n, &jaguar_cpu_device::store_rn_r15n, &jaguar_cpu_device::move_pc_rn, + /* 52-55 */ &jaguar_cpu_device::jump_cc_rn, &jaguar_cpu_device::jr_cc_n, &jaguar_cpu_device::mmult_rn_rn, &jaguar_cpu_device::mtoi_rn_rn, + /* 56-59 */ &jaguar_cpu_device::normi_rn_rn, &jaguar_cpu_device::nop, &jaguar_cpu_device::load_r14rn_rn, &jaguar_cpu_device::load_r15rn_rn, + /* 60-63 */ &jaguar_cpu_device::store_rn_r14rn, &jaguar_cpu_device::store_rn_r15rn, &jaguar_cpu_device::sat24_rn, &jaguar_cpu_device::pack_rn +}; + +const jaguar_cpu_device::op_func jaguar_cpu_device::dsp_op_table[64] = +{ + /* 00-03 */ &jaguar_cpu_device::add_rn_rn, &jaguar_cpu_device::addc_rn_rn, &jaguar_cpu_device::addq_n_rn, &jaguar_cpu_device::addqt_n_rn, + /* 04-07 */ &jaguar_cpu_device::sub_rn_rn, &jaguar_cpu_device::subc_rn_rn, &jaguar_cpu_device::subq_n_rn, &jaguar_cpu_device::subqt_n_rn, + /* 08-11 */ &jaguar_cpu_device::neg_rn, &jaguar_cpu_device::and_rn_rn, &jaguar_cpu_device::or_rn_rn, &jaguar_cpu_device::xor_rn_rn, + /* 12-15 */ &jaguar_cpu_device::not_rn, &jaguar_cpu_device::btst_n_rn, &jaguar_cpu_device::bset_n_rn, &jaguar_cpu_device::bclr_n_rn, + /* 16-19 */ &jaguar_cpu_device::mult_rn_rn, &jaguar_cpu_device::imult_rn_rn, &jaguar_cpu_device::imultn_rn_rn, &jaguar_cpu_device::resmac_rn, + /* 20-23 */ &jaguar_cpu_device::imacn_rn_rn, &jaguar_cpu_device::div_rn_rn, &jaguar_cpu_device::abs_rn, &jaguar_cpu_device::sh_rn_rn, + /* 24-27 */ &jaguar_cpu_device::shlq_n_rn, &jaguar_cpu_device::shrq_n_rn, &jaguar_cpu_device::sha_rn_rn, &jaguar_cpu_device::sharq_n_rn, + /* 28-31 */ &jaguar_cpu_device::ror_rn_rn, &jaguar_cpu_device::rorq_n_rn, &jaguar_cpu_device::cmp_rn_rn, &jaguar_cpu_device::cmpq_n_rn, + /* 32-35 */ &jaguar_cpu_device::subqmod_n_rn, &jaguar_cpu_device::sat16s_rn, &jaguar_cpu_device::move_rn_rn, &jaguar_cpu_device::moveq_n_rn, + /* 36-39 */ &jaguar_cpu_device::moveta_rn_rn, &jaguar_cpu_device::movefa_rn_rn, &jaguar_cpu_device::movei_n_rn, &jaguar_cpu_device::loadb_rn_rn, + /* 40-43 */ &jaguar_cpu_device::loadw_rn_rn, &jaguar_cpu_device::load_rn_rn, &jaguar_cpu_device::sat32s_rn, &jaguar_cpu_device::load_r14n_rn, + /* 44-47 */ &jaguar_cpu_device::load_r15n_rn, &jaguar_cpu_device::storeb_rn_rn, &jaguar_cpu_device::storew_rn_rn, &jaguar_cpu_device::store_rn_rn, + /* 48-51 */ &jaguar_cpu_device::mirror_rn, &jaguar_cpu_device::store_rn_r14n, &jaguar_cpu_device::store_rn_r15n, &jaguar_cpu_device::move_pc_rn, + /* 52-55 */ &jaguar_cpu_device::jump_cc_rn, &jaguar_cpu_device::jr_cc_n, &jaguar_cpu_device::mmult_rn_rn, &jaguar_cpu_device::mtoi_rn_rn, + /* 56-59 */ &jaguar_cpu_device::normi_rn_rn, &jaguar_cpu_device::nop, &jaguar_cpu_device::load_r14rn_rn, &jaguar_cpu_device::load_r15rn_rn, + /* 60-63 */ &jaguar_cpu_device::store_rn_r14rn, &jaguar_cpu_device::store_rn_r15rn, &jaguar_cpu_device::illegal, &jaguar_cpu_device::addqmod_n_rn +}; + + + +/*************************************************************************** + MEMORY ACCESSORS +***************************************************************************/ + +#define ROPCODE(pc) (m_direct->read_word(pc, WORD_XOR_BE(0))) + + +const device_type JAGUARGPU = &device_creator; +const device_type JAGUARDSP = &device_creator; + + +jaguar_cpu_device::jaguar_cpu_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source, bool isdsp) + : cpu_device(mconfig, type, name, tag, owner, clock, shortname, source) + , m_program_config("program", ENDIANNESS_BIG, 32, 24, 0) + , m_isdsp(isdsp) + , m_cpu_interrupt(*this) + , m_tables_referenced(false) + , m_table(isdsp ? dsp_op_table : gpu_op_table) +{ + if (isdsp) + { + m_internal_ram_start = 0xf1b000; + m_internal_ram_end = 0xf1cfff; + } + else + { + m_internal_ram_start = 0xf03000; + m_internal_ram_end = 0xf03fff; + } +} + + +jaguargpu_cpu_device::jaguargpu_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : jaguar_cpu_device(mconfig, JAGUARGPU, "Jaguar GPU", tag, owner, clock, "jaguargpu", __FILE__, false) +{ +} + + +jaguardsp_cpu_device::jaguardsp_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : jaguar_cpu_device(mconfig, JAGUARDSP, "Jaguar DSP", tag, owner, clock, "jaguardsp", __FILE__, true) +{ +} + + +void jaguar_cpu_device::update_register_banks() +{ + UINT32 temp; + int i, bank; + + /* pick the bank */ + bank = FLAGS & RPAGEFLAG; + if (FLAGS & IFLAG) bank = 0; + + /* do we need to swap? */ + if ((bank == 0 && m_b0 != m_r) || (bank != 0 && m_b1 != m_r)) + { + /* remember the icount of the instruction after we swap */ + m_bankswitch_icount = m_icount - 1; + + /* exchange the contents */ + for (i = 0; i < 32; i++) + temp = m_r[i], m_r[i] = m_a[i], m_a[i] = temp; + + /* swap the bank pointers */ + if (bank == 0) + { + m_b0 = m_r; + m_b1 = m_a; + } + else + { + m_b0 = m_a; + m_b1 = m_r; + } + } +} + + + +/*************************************************************************** + IRQ HANDLING +***************************************************************************/ + +void jaguar_cpu_device::check_irqs() +{ + int bits, mask, which = 0; + + /* if the IMASK is set, bail */ + if (FLAGS & IFLAG) + return; + + /* get the active interrupt bits */ + bits = (m_ctrl[G_CTRL] >> 6) & 0x1f; + bits |= (m_ctrl[G_CTRL] >> 10) & 0x20; + + /* get the interrupt mask */ + mask = (FLAGS >> 4) & 0x1f; + mask |= (FLAGS >> 11) & 0x20; + + /* bail if nothing is available */ + bits &= mask; + if (bits == 0) + return; + + /* determine which interrupt */ + if (bits & 0x01) which = 0; + if (bits & 0x02) which = 1; + if (bits & 0x04) which = 2; + if (bits & 0x08) which = 3; + if (bits & 0x10) which = 4; + if (bits & 0x20) which = 5; + + /* set the interrupt flag */ + FLAGS |= IFLAG; + update_register_banks(); + + /* push the PC-2 on the stack */ + m_r[31] -= 4; + WRITELONG(m_r[31], PC - 2); + + /* dispatch */ + PC = (m_isdsp) ? 0xf1b000 : 0xf03000; + PC += which * 0x10; +} + + +void jaguar_cpu_device::execute_set_input(int irqline, int state) +{ + int mask = (irqline < 5) ? (0x40 << irqline) : 0x10000; + m_ctrl[G_CTRL] &= ~mask; + if (state != CLEAR_LINE) + { + m_ctrl[G_CTRL] |= mask; + check_irqs(); + } +} + + + +/*************************************************************************** + INITIALIZATION AND SHUTDOWN +***************************************************************************/ + +void jaguar_cpu_device::init_tables() +{ + int i, j; + + m_tables_referenced = true; + + /* if we're not the first, skip */ + if (table_refcount++ != 0) + { + assert(mirror_table != NULL); + assert(condition_table != NULL); + return; + } + + /* fill in the mirror table */ + mirror_table = global_alloc_array(UINT16, 65536); + for (i = 0; i < 65536; i++) + mirror_table[i] = ((i >> 15) & 0x0001) | ((i >> 13) & 0x0002) | + ((i >> 11) & 0x0004) | ((i >> 9) & 0x0008) | + ((i >> 7) & 0x0010) | ((i >> 5) & 0x0020) | + ((i >> 3) & 0x0040) | ((i >> 1) & 0x0080) | + ((i << 1) & 0x0100) | ((i << 3) & 0x0200) | + ((i << 5) & 0x0400) | ((i << 7) & 0x0800) | + ((i << 9) & 0x1000) | ((i << 11) & 0x2000) | + ((i << 13) & 0x4000) | ((i << 15) & 0x8000); + + /* fill in the condition table */ + condition_table = global_alloc_array(UINT8, 32 * 8); + for (i = 0; i < 8; i++) + for (j = 0; j < 32; j++) + { + int result = 1; + if (j & 1) + if (i & ZFLAG) result = 0; + if (j & 2) + if (!(i & ZFLAG)) result = 0; + if (j & 4) + if (i & (CFLAG << (j >> 4))) result = 0; + if (j & 8) + if (!(i & (CFLAG << (j >> 4)))) result = 0; + condition_table[i * 32 + j] = result; + } +} + + +void jaguar_cpu_device::jaguar_postload() +{ + update_register_banks(); + check_irqs(); +} + + +void jaguar_cpu_device::device_start() +{ + init_tables(); + + m_program = &space(AS_PROGRAM); + m_direct = &m_program->direct(); + m_cpu_interrupt.resolve_safe(); + + save_item(NAME(m_r)); + save_item(NAME(m_a)); + save_item(NAME(m_ctrl)); + save_item(NAME(m_ppc)); + machine().save().register_postload(save_prepost_delegate(FUNC(jaguar_cpu_device::jaguar_postload), this)); + + if (m_isdsp) + { + m_internal_ram_start = 0xf1b000; + m_internal_ram_end = 0xf1cfff; + } + else + { + m_internal_ram_start = 0xf03000; + m_internal_ram_end = 0xf03fff; + } + + memset(m_r, 0, sizeof(m_r)); + memset(m_a, 0, sizeof(m_a)); + memset(m_ctrl, 0, sizeof(m_ctrl)); + m_ppc = 0; + m_accum = 0; + m_bankswitch_icount = 0; + + state_add( JAGUAR_PC, "PC", PC).formatstr("%08X"); + state_add( JAGUAR_FLAGS, "FLAGS", FLAGS).formatstr("%08X"); + state_add( JAGUAR_R0, "R0", m_r[0]).formatstr("%08X"); + state_add( JAGUAR_R1, "R1", m_r[1]).formatstr("%08X"); + state_add( JAGUAR_R2, "R2", m_r[2]).formatstr("%08X"); + state_add( JAGUAR_R3, "R3", m_r[3]).formatstr("%08X"); + state_add( JAGUAR_R4, "R4", m_r[4]).formatstr("%08X"); + state_add( JAGUAR_R5, "R5", m_r[5]).formatstr("%08X"); + state_add( JAGUAR_R6, "R6", m_r[6]).formatstr("%08X"); + state_add( JAGUAR_R7, "R7", m_r[7]).formatstr("%08X"); + state_add( JAGUAR_R8, "R8", m_r[8]).formatstr("%08X"); + state_add( JAGUAR_R9, "R9", m_r[9]).formatstr("%08X"); + state_add( JAGUAR_R10, "R10", m_r[10]).formatstr("%08X"); + state_add( JAGUAR_R11, "R11", m_r[11]).formatstr("%08X"); + state_add( JAGUAR_R12, "R12", m_r[12]).formatstr("%08X"); + state_add( JAGUAR_R13, "R13", m_r[13]).formatstr("%08X"); + state_add( JAGUAR_R14, "R14", m_r[14]).formatstr("%08X"); + state_add( JAGUAR_R15, "R15", m_r[15]).formatstr("%08X"); + state_add( JAGUAR_R16, "R16", m_r[16]).formatstr("%08X"); + state_add( JAGUAR_R17, "R17", m_r[17]).formatstr("%08X"); + state_add( JAGUAR_R18, "R18", m_r[18]).formatstr("%08X"); + state_add( JAGUAR_R19, "R19", m_r[19]).formatstr("%08X"); + state_add( JAGUAR_R20, "R20", m_r[20]).formatstr("%08X"); + state_add( JAGUAR_R21, "R21", m_r[21]).formatstr("%08X"); + state_add( JAGUAR_R22, "R22", m_r[22]).formatstr("%08X"); + state_add( JAGUAR_R23, "R23", m_r[23]).formatstr("%08X"); + state_add( JAGUAR_R24, "R24", m_r[24]).formatstr("%08X"); + state_add( JAGUAR_R25, "R25", m_r[25]).formatstr("%08X"); + state_add( JAGUAR_R26, "R26", m_r[26]).formatstr("%08X"); + state_add( JAGUAR_R27, "R27", m_r[27]).formatstr("%08X"); + state_add( JAGUAR_R28, "R28", m_r[28]).formatstr("%08X"); + state_add( JAGUAR_R29, "R29", m_r[29]).formatstr("%08X"); + state_add( JAGUAR_R30, "R30", m_r[30]).formatstr("%08X"); + state_add( JAGUAR_R31, "R31", m_r[31]).formatstr("%08X"); + + state_add( STATE_GENPC, "GENPC", PC).noshow(); + state_add( STATE_GENPCBASE, "GENPCBASE", m_ppc).noshow(); + state_add( STATE_GENFLAGS, "GENFLAGS", FLAGS).formatstr("%11s").noshow(); + + m_icountptr = &m_icount; +} + + +void jaguar_cpu_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + switch (entry.index()) + { + case STATE_GENFLAGS: + strprintf(str, "%c%c%c%c%c%c%c%c%c%c%c", + FLAGS & 0x8000 ? 'D':'.', + FLAGS & 0x4000 ? 'A':'.', + FLAGS & 0x0100 ? '4':'.', + FLAGS & 0x0080 ? '3':'.', + FLAGS & 0x0040 ? '2':'.', + FLAGS & 0x0020 ? '1':'.', + FLAGS & 0x0010 ? '0':'.', + FLAGS & 0x0008 ? 'I':'.', + FLAGS & 0x0004 ? 'N':'.', + FLAGS & 0x0002 ? 'C':'.', + FLAGS & 0x0001 ? 'Z':'.'); + break; + } +} + + +void jaguar_cpu_device::device_reset() +{ + m_b0 = m_r; + m_b1 = m_a; +} + + +jaguar_cpu_device::~jaguar_cpu_device() +{ + if ( !m_tables_referenced ) + return; + + if (--table_refcount != 0) + return; + + if (mirror_table != NULL) + global_free_array(mirror_table); + mirror_table = NULL; + + if (condition_table != NULL) + global_free_array(condition_table); + condition_table = NULL; +} + + + +/*************************************************************************** + CORE EXECUTION LOOP +***************************************************************************/ + +void jaguargpu_cpu_device::execute_run() +{ + /* if we're halted, we shouldn't be here */ + if (!(m_ctrl[G_CTRL] & 1)) + { + //device->execute().set_input_line(INPUT_LINE_HALT, ASSERT_LINE); + m_icount = 0; + return; + } + + /* check for IRQs */ + check_irqs(); + + /* count cycles and interrupt cycles */ + m_bankswitch_icount = -1000; + + /* core execution loop */ + do + { + UINT32 op; + + /* debugging */ + //if (PC < 0xf03000 || PC > 0xf04000) { fatalerror("GPU: PC = %06X (ppc = %06X)\n", PC, m_ppc); } + m_ppc = PC; + debugger_instruction_hook(this, PC); + + /* instruction fetch */ + op = ROPCODE(PC); + PC += 2; + + /* parse the instruction */ + (this->*gpu_op_table[op >> 10])(op); + m_icount--; + + } while (m_icount > 0 || m_icount == m_bankswitch_icount); +} + +void jaguardsp_cpu_device::execute_run() +{ + /* if we're halted, we shouldn't be here */ + if (!(m_ctrl[G_CTRL] & 1)) + { + //device->execute().set_input_line(INPUT_LINE_HALT, ASSERT_LINE); + m_icount = 0; + return; + } + + /* check for IRQs */ + check_irqs(); + + /* count cycles and interrupt cycles */ + m_bankswitch_icount = -1000; + + /* core execution loop */ + do + { + UINT32 op; + + /* debugging */ + //if (PC < 0xf1b000 || PC > 0xf1d000) { fatalerror(stderr, "DSP: PC = %06X\n", PC); } + m_ppc = PC; + debugger_instruction_hook(this, PC); + + /* instruction fetch */ + op = ROPCODE(PC); + PC += 2; + + /* parse the instruction */ + (this->*dsp_op_table[op >> 10])(op); + m_icount--; + + } while (m_icount > 0 || m_icount == m_bankswitch_icount); +} + + + +/*************************************************************************** + OPCODES +***************************************************************************/ + +void jaguar_cpu_device::abs_rn(UINT16 op) +{ + int dreg = op & 31; + UINT32 res = m_r[dreg]; + CLR_ZNC(); + if (res & 0x80000000) + { + m_r[dreg] = res = -res; + FLAGS |= CFLAG; + } + SET_Z(res); +} + +void jaguar_cpu_device::add_rn_rn(UINT16 op) +{ + int dreg = op & 31; + UINT32 r1 = m_r[(op >> 5) & 31]; + UINT32 r2 = m_r[dreg]; + UINT32 res = r2 + r1; + m_r[dreg] = res; + CLR_ZNC(); SET_ZNC_ADD(r2, r1, res); +} + +void jaguar_cpu_device::addc_rn_rn(UINT16 op) +{ + int dreg = op & 31; + UINT32 r1 = m_r[(op >> 5) & 31]; + UINT32 r2 = m_r[dreg]; + UINT32 c = ((FLAGS >> 1) & 1); + UINT32 res = r2 + r1 + c; + m_r[dreg] = res; + CLR_ZNC(); SET_ZNC_ADD(r2, r1 + c, res); +} + +void jaguar_cpu_device::addq_n_rn(UINT16 op) +{ + int dreg = op & 31; + UINT32 r1 = convert_zero[(op >> 5) & 31]; + UINT32 r2 = m_r[dreg]; + UINT32 res = r2 + r1; + m_r[dreg] = res; + CLR_ZNC(); SET_ZNC_ADD(r2, r1, res); +} + +void jaguar_cpu_device::addqmod_n_rn(UINT16 op) /* DSP only */ +{ + int dreg = op & 31; + UINT32 r1 = convert_zero[(op >> 5) & 31]; + UINT32 r2 = m_r[dreg]; + UINT32 res = r2 + r1; + res = (res & ~m_ctrl[D_MOD]) | (r2 & ~m_ctrl[D_MOD]); + m_r[dreg] = res; + CLR_ZNC(); SET_ZNC_ADD(r2, r1, res); +} + +void jaguar_cpu_device::addqt_n_rn(UINT16 op) +{ + int dreg = op & 31; + UINT32 r1 = convert_zero[(op >> 5) & 31]; + UINT32 r2 = m_r[dreg]; + UINT32 res = r2 + r1; + m_r[dreg] = res; +} + +void jaguar_cpu_device::and_rn_rn(UINT16 op) +{ + int dreg = op & 31; + UINT32 r1 = m_r[(op >> 5) & 31]; + UINT32 r2 = m_r[dreg]; + UINT32 res = r2 & r1; + m_r[dreg] = res; + CLR_ZN(); SET_ZN(res); +} + +void jaguar_cpu_device::bclr_n_rn(UINT16 op) +{ + int dreg = op & 31; + UINT32 r1 = (op >> 5) & 31; + UINT32 r2 = m_r[dreg]; + UINT32 res = r2 & ~(1 << r1); + m_r[dreg] = res; + CLR_ZN(); SET_ZN(res); +} + +void jaguar_cpu_device::bset_n_rn(UINT16 op) +{ + int dreg = op & 31; + UINT32 r1 = (op >> 5) & 31; + UINT32 r2 = m_r[dreg]; + UINT32 res = r2 | (1 << r1); + m_r[dreg] = res; + CLR_ZN(); SET_ZN(res); +} + +void jaguar_cpu_device::btst_n_rn(UINT16 op) +{ + UINT32 r1 = (op >> 5) & 31; + UINT32 r2 = m_r[op & 31]; + CLR_Z(); FLAGS |= (~r2 >> r1) & 1; +} + +void jaguar_cpu_device::cmp_rn_rn(UINT16 op) +{ + UINT32 r1 = m_r[(op >> 5) & 31]; + UINT32 r2 = m_r[op & 31]; + UINT32 res = r2 - r1; + CLR_ZNC(); SET_ZNC_SUB(r2, r1, res); +} + +void jaguar_cpu_device::cmpq_n_rn(UINT16 op) +{ + UINT32 r1 = (INT8)(op >> 2) >> 3; + UINT32 r2 = m_r[op & 31]; + UINT32 res = r2 - r1; + CLR_ZNC(); SET_ZNC_SUB(r2, r1, res); +} + +void jaguar_cpu_device::div_rn_rn(UINT16 op) +{ + int dreg = op & 31; + UINT32 r1 = m_r[(op >> 5) & 31]; + UINT32 r2 = m_r[dreg]; + if (r1) + { + if (m_ctrl[D_DIVCTRL] & 1) + { + m_r[dreg] = ((UINT64)r2 << 16) / r1; + m_ctrl[D_REMAINDER] = ((UINT64)r2 << 16) % r1; + } + else + { + m_r[dreg] = r2 / r1; + m_ctrl[D_REMAINDER] = r2 % r1; + } + } + else + m_r[dreg] = 0xffffffff; +} + +void jaguar_cpu_device::illegal(UINT16 op) +{ +} + +void jaguar_cpu_device::imacn_rn_rn(UINT16 op) +{ + UINT32 r1 = m_r[(op >> 5) & 31]; + UINT32 r2 = m_r[op & 31]; + m_accum += (INT64)((INT16)r1 * (INT16)r2); + logerror("Unexpected IMACN instruction!\n"); +} + +void jaguar_cpu_device::imult_rn_rn(UINT16 op) +{ + int dreg = op & 31; + UINT32 r1 = m_r[(op >> 5) & 31]; + UINT32 r2 = m_r[dreg]; + UINT32 res = (INT16)r1 * (INT16)r2; + m_r[dreg] = res; + CLR_ZN(); SET_ZN(res); +} + +void jaguar_cpu_device::imultn_rn_rn(UINT16 op) +{ + int dreg = op & 31; + UINT32 r1 = m_r[(op >> 5) & 31]; + UINT32 r2 = m_r[dreg]; + UINT32 res = (INT16)r1 * (INT16)r2; + m_accum = (INT32)res; + CLR_ZN(); SET_ZN(res); + + op = ROPCODE(PC); + while ((op >> 10) == 20) + { + r1 = m_r[(op >> 5) & 31]; + r2 = m_r[op & 31]; + m_accum += (INT64)((INT16)r1 * (INT16)r2); + PC += 2; + op = ROPCODE(PC); + } + if ((op >> 10) == 19) + { + PC += 2; + m_r[op & 31] = (UINT32)m_accum; + } +} + +void jaguar_cpu_device::jr_cc_n(UINT16 op) +{ + if (CONDITION(op & 31)) + { + INT32 r1 = (INT8)((op >> 2) & 0xf8) >> 2; + UINT32 newpc = PC + r1; + debugger_instruction_hook(this, PC); + op = ROPCODE(PC); + PC = newpc; + (this->*m_table[op >> 10])(op); + + m_icount -= 3; /* 3 wait states guaranteed */ + } +} + +void jaguar_cpu_device::jump_cc_rn(UINT16 op) +{ + if (CONDITION(op & 31)) + { + UINT8 reg = (op >> 5) & 31; + + /* special kludge for risky code in the cojag DSP interrupt handlers */ + UINT32 newpc = (m_icount == m_bankswitch_icount) ? m_a[reg] : m_r[reg]; + debugger_instruction_hook(this, PC); + op = ROPCODE(PC); + PC = newpc; + (this->*m_table[op >> 10])(op); + + m_icount -= 3; /* 3 wait states guaranteed */ + } +} + +void jaguar_cpu_device::load_rn_rn(UINT16 op) +{ + UINT32 r1 = m_r[(op >> 5) & 31]; + m_r[op & 31] = READLONG(r1); +} + +void jaguar_cpu_device::load_r14n_rn(UINT16 op) +{ + UINT32 r1 = convert_zero[(op >> 5) & 31]; + m_r[op & 31] = READLONG(m_r[14] + 4 * r1); +} + +void jaguar_cpu_device::load_r15n_rn(UINT16 op) +{ + UINT32 r1 = convert_zero[(op >> 5) & 31]; + m_r[op & 31] = READLONG(m_r[15] + 4 * r1); +} + +void jaguar_cpu_device::load_r14rn_rn(UINT16 op) +{ + UINT32 r1 = m_r[(op >> 5) & 31]; + m_r[op & 31] = READLONG(m_r[14] + r1); +} + +void jaguar_cpu_device::load_r15rn_rn(UINT16 op) +{ + UINT32 r1 = m_r[(op >> 5) & 31]; + m_r[op & 31] = READLONG(m_r[15] + r1); +} + +void jaguar_cpu_device::loadb_rn_rn(UINT16 op) +{ + UINT32 r1 = m_r[(op >> 5) & 31]; + if (r1 >= m_internal_ram_start && r1 <= m_internal_ram_end) + { + m_r[op & 31] = READLONG(r1 & ~3); + } + else + { + m_r[op & 31] = READBYTE(r1); + } +} + +void jaguar_cpu_device::loadw_rn_rn(UINT16 op) +{ + UINT32 r1 = m_r[(op >> 5) & 31]; + if (r1 >= m_internal_ram_start && r1 <= m_internal_ram_end) + { + m_r[op & 31] = READLONG(r1 & ~3); + } + else + { + m_r[op & 31] = READWORD(r1); + } +} + +void jaguar_cpu_device::loadp_rn_rn(UINT16 op) /* GPU only */ +{ + UINT32 r1 = m_r[(op >> 5) & 31]; + if (r1 >= m_internal_ram_start && r1 <= m_internal_ram_end) + { + m_r[op & 31] = READLONG(r1 & ~3); + } + else + { + m_ctrl[G_HIDATA] = READLONG(r1); + m_r[op & 31] = READLONG(r1+4); + } +} + +void jaguar_cpu_device::mirror_rn(UINT16 op) /* DSP only */ +{ + int dreg = op & 31; + UINT32 r1 = m_r[dreg]; + UINT32 res = (mirror_table[r1 & 0xffff] << 16) | mirror_table[r1 >> 16]; + m_r[dreg] = res; + CLR_ZN(); SET_ZN(res); +} + +void jaguar_cpu_device::mmult_rn_rn(UINT16 op) +{ + int count = m_ctrl[G_MTXC] & 15, i; + int sreg = (op >> 5) & 31; + int dreg = op & 31; + UINT32 addr = m_ctrl[G_MTXA]; + INT64 accum = 0; + UINT32 res; + + if (!(m_ctrl[G_MTXC] & 0x10)) + { + for (i = 0; i < count; i++) + { + accum += (INT16)(m_b1[sreg + i/2] >> (16 * ((i & 1) ^ 1))) * (INT16)READWORD(addr); + addr += 2; + } + } + else + { + for (i = 0; i < count; i++) + { + accum += (INT16)(m_b1[sreg + i/2] >> (16 * ((i & 1) ^ 1))) * (INT16)READWORD(addr); + addr += 2 * count; + } + } + m_r[dreg] = res = (UINT32)accum; + CLR_ZN(); SET_ZN(res); +} + +void jaguar_cpu_device::move_rn_rn(UINT16 op) +{ + m_r[op & 31] = m_r[(op >> 5) & 31]; +} + +void jaguar_cpu_device::move_pc_rn(UINT16 op) +{ + m_r[op & 31] = m_ppc; +} + +void jaguar_cpu_device::movefa_rn_rn(UINT16 op) +{ + m_r[op & 31] = m_a[(op >> 5) & 31]; +} + +void jaguar_cpu_device::movei_n_rn(UINT16 op) +{ + UINT32 res = ROPCODE(PC) | (ROPCODE(PC + 2) << 16); + PC += 4; + m_r[op & 31] = res; +} + +void jaguar_cpu_device::moveq_n_rn(UINT16 op) +{ + m_r[op & 31] = (op >> 5) & 31; +} + +void jaguar_cpu_device::moveta_rn_rn(UINT16 op) +{ + m_a[op & 31] = m_r[(op >> 5) & 31]; +} + +void jaguar_cpu_device::mtoi_rn_rn(UINT16 op) +{ + UINT32 r1 = m_r[(op >> 5) & 31]; + m_r[op & 31] = (((INT32)r1 >> 8) & 0xff800000) | (r1 & 0x007fffff); +} + +void jaguar_cpu_device::mult_rn_rn(UINT16 op) +{ + int dreg = op & 31; + UINT32 r1 = m_r[(op >> 5) & 31]; + UINT32 r2 = m_r[dreg]; + UINT32 res = (UINT16)r1 * (UINT16)r2; + m_r[dreg] = res; + CLR_ZN(); SET_ZN(res); +} + +void jaguar_cpu_device::neg_rn(UINT16 op) +{ + int dreg = op & 31; + UINT32 r2 = m_r[dreg]; + UINT32 res = -r2; + m_r[dreg] = res; + CLR_ZNC(); SET_ZNC_SUB(0, r2, res); +} + +void jaguar_cpu_device::nop(UINT16 op) +{ +} + +void jaguar_cpu_device::normi_rn_rn(UINT16 op) +{ + UINT32 r1 = m_r[(op >> 5) & 31]; + UINT32 res = 0; + if (r1 != 0) + { + while ((r1 & 0xffc00000) == 0) + { + r1 <<= 1; + res--; + } + while ((r1 & 0xff800000) != 0) + { + r1 >>= 1; + res++; + } + } + m_r[op & 31] = res; + CLR_ZN(); SET_ZN(res); +} + +void jaguar_cpu_device::not_rn(UINT16 op) +{ + int dreg = op & 31; + UINT32 res = ~m_r[dreg]; + m_r[dreg] = res; + CLR_ZN(); SET_ZN(res); +} + +void jaguar_cpu_device::or_rn_rn(UINT16 op) +{ + int dreg = op & 31; + UINT32 r1 = m_r[(op >> 5) & 31]; + UINT32 r2 = m_r[dreg]; + UINT32 res = r1 | r2; + m_r[dreg] = res; + CLR_ZN(); SET_ZN(res); +} + +void jaguar_cpu_device::pack_rn(UINT16 op) /* GPU only */ +{ + int dreg = op & 31; + int pack = (op >> 5) & 31; + UINT32 r2 = m_r[dreg]; + UINT32 res; + if (pack == 0) /* PACK */ + res = ((r2 >> 10) & 0xf000) | ((r2 >> 5) & 0x0f00) | (r2 & 0xff); + else /* UNPACK */ + res = ((r2 & 0xf000) << 10) | ((r2 & 0x0f00) << 5) | (r2 & 0xff); + m_r[dreg] = res; +} + +void jaguar_cpu_device::resmac_rn(UINT16 op) +{ + m_r[op & 31] = (UINT32)m_accum; +} + +void jaguar_cpu_device::ror_rn_rn(UINT16 op) +{ + int dreg = op & 31; + UINT32 r1 = m_r[(op >> 5) & 31] & 31; + UINT32 r2 = m_r[dreg]; + UINT32 res = (r2 >> r1) | (r2 << (32 - r1)); + m_r[dreg] = res; + CLR_ZNC(); SET_ZN(res); FLAGS |= (r2 >> 30) & 2; +} + +void jaguar_cpu_device::rorq_n_rn(UINT16 op) +{ + int dreg = op & 31; + UINT32 r1 = convert_zero[(op >> 5) & 31]; + UINT32 r2 = m_r[dreg]; + UINT32 res = (r2 >> r1) | (r2 << (32 - r1)); + m_r[dreg] = res; + CLR_ZNC(); SET_ZN(res); FLAGS |= (r2 >> 30) & 2; +} + +void jaguar_cpu_device::sat8_rn(UINT16 op) /* GPU only */ +{ + int dreg = op & 31; + INT32 r2 = m_r[dreg]; + UINT32 res = (r2 < 0) ? 0 : (r2 > 255) ? 255 : r2; + m_r[dreg] = res; + CLR_ZN(); SET_ZN(res); +} + +void jaguar_cpu_device::sat16_rn(UINT16 op) /* GPU only */ +{ + int dreg = op & 31; + INT32 r2 = m_r[dreg]; + UINT32 res = (r2 < 0) ? 0 : (r2 > 65535) ? 65535 : r2; + m_r[dreg] = res; + CLR_ZN(); SET_ZN(res); +} + +void jaguar_cpu_device::sat16s_rn(UINT16 op) /* DSP only */ +{ + int dreg = op & 31; + INT32 r2 = m_r[dreg]; + UINT32 res = (r2 < -32768) ? -32768 : (r2 > 32767) ? 32767 : r2; + m_r[dreg] = res; + CLR_ZN(); SET_ZN(res); +} + +void jaguar_cpu_device::sat24_rn(UINT16 op) /* GPU only */ +{ + int dreg = op & 31; + INT32 r2 = m_r[dreg]; + UINT32 res = (r2 < 0) ? 0 : (r2 > 16777215) ? 16777215 : r2; + m_r[dreg] = res; + CLR_ZN(); SET_ZN(res); +} + +void jaguar_cpu_device::sat32s_rn(UINT16 op) /* DSP only */ +{ + int dreg = op & 31; + INT32 r2 = (UINT32)m_r[dreg]; + INT32 temp = m_accum >> 32; + UINT32 res = (temp < -1) ? (INT32)0x80000000 : (temp > 0) ? (INT32)0x7fffffff : r2; + m_r[dreg] = res; + CLR_ZN(); SET_ZN(res); +} + +void jaguar_cpu_device::sh_rn_rn(UINT16 op) +{ + int dreg = op & 31; + INT32 r1 = (INT32)m_r[(op >> 5) & 31]; + UINT32 r2 = m_r[dreg]; + UINT32 res; + + CLR_ZNC(); + if (r1 < 0) + { + res = (r1 <= -32) ? 0 : (r2 << -r1); + FLAGS |= (r2 >> 30) & 2; + } + else + { + res = (r1 >= 32) ? 0 : (r2 >> r1); + FLAGS |= (r2 << 1) & 2; + } + m_r[dreg] = res; + SET_ZN(res); +} + +void jaguar_cpu_device::sha_rn_rn(UINT16 op) +{ + int dreg = op & 31; + INT32 r1 = (INT32)m_r[(op >> 5) & 31]; + UINT32 r2 = m_r[dreg]; + UINT32 res; + + CLR_ZNC(); + if (r1 < 0) + { + res = (r1 <= -32) ? 0 : (r2 << -r1); + FLAGS |= (r2 >> 30) & 2; + } + else + { + res = (r1 >= 32) ? ((INT32)r2 >> 31) : ((INT32)r2 >> r1); + FLAGS |= (r2 << 1) & 2; + } + m_r[dreg] = res; + SET_ZN(res); +} + +void jaguar_cpu_device::sharq_n_rn(UINT16 op) +{ + int dreg = op & 31; + INT32 r1 = convert_zero[(op >> 5) & 31]; + UINT32 r2 = m_r[dreg]; + UINT32 res = (INT32)r2 >> r1; + m_r[dreg] = res; + CLR_ZNC(); SET_ZN(res); FLAGS |= (r2 << 1) & 2; +} + +void jaguar_cpu_device::shlq_n_rn(UINT16 op) +{ + int dreg = op & 31; + INT32 r1 = convert_zero[(op >> 5) & 31]; + UINT32 r2 = m_r[dreg]; + UINT32 res = r2 << (32 - r1); + m_r[dreg] = res; + CLR_ZNC(); SET_ZN(res); FLAGS |= (r2 >> 30) & 2; +} + +void jaguar_cpu_device::shrq_n_rn(UINT16 op) +{ + int dreg = op & 31; + INT32 r1 = convert_zero[(op >> 5) & 31]; + UINT32 r2 = m_r[dreg]; + UINT32 res = r2 >> r1; + m_r[dreg] = res; + CLR_ZNC(); SET_ZN(res); FLAGS |= (r2 << 1) & 2; +} + +void jaguar_cpu_device::store_rn_rn(UINT16 op) +{ + UINT32 r1 = m_r[(op >> 5) & 31]; + WRITELONG(r1, m_r[op & 31]); +} + +void jaguar_cpu_device::store_rn_r14n(UINT16 op) +{ + UINT32 r1 = convert_zero[(op >> 5) & 31]; + WRITELONG(m_r[14] + r1 * 4, m_r[op & 31]); +} + +void jaguar_cpu_device::store_rn_r15n(UINT16 op) +{ + UINT32 r1 = convert_zero[(op >> 5) & 31]; + WRITELONG(m_r[15] + r1 * 4, m_r[op & 31]); +} + +void jaguar_cpu_device::store_rn_r14rn(UINT16 op) +{ + UINT32 r1 = m_r[(op >> 5) & 31]; + WRITELONG(m_r[14] + r1, m_r[op & 31]); +} + +void jaguar_cpu_device::store_rn_r15rn(UINT16 op) +{ + UINT32 r1 = m_r[(op >> 5) & 31]; + WRITELONG(m_r[15] + r1, m_r[op & 31]); +} + +void jaguar_cpu_device::storeb_rn_rn(UINT16 op) +{ + UINT32 r1 = m_r[(op >> 5) & 31]; + if (r1 >= m_internal_ram_start && r1 <= m_internal_ram_end) + { + WRITELONG(r1 & ~3, m_r[op & 31]); + } + else + { + WRITEBYTE(r1, m_r[op & 31]); + } +} + +void jaguar_cpu_device::storew_rn_rn(UINT16 op) +{ + UINT32 r1 = m_r[(op >> 5) & 31]; + if (r1 >= m_internal_ram_start && r1 <= m_internal_ram_end) + { + WRITELONG(r1 & ~3, m_r[op & 31]); + } + else + { + WRITEWORD(r1, m_r[op & 31]); + } +} + +void jaguar_cpu_device::storep_rn_rn(UINT16 op) /* GPU only */ +{ + UINT32 r1 = m_r[(op >> 5) & 31]; + if (r1 >= m_internal_ram_start && r1 <= m_internal_ram_end) + { + WRITELONG(r1 & ~3, m_r[op & 31]); + } + else + { + WRITELONG(r1, m_ctrl[G_HIDATA]); + WRITELONG(r1+4, m_r[op & 31]); + } +} + +void jaguar_cpu_device::sub_rn_rn(UINT16 op) +{ + int dreg = op & 31; + UINT32 r1 = m_r[(op >> 5) & 31]; + UINT32 r2 = m_r[dreg]; + UINT32 res = r2 - r1; + m_r[dreg] = res; + CLR_ZNC(); SET_ZNC_SUB(r2, r1, res); +} + +void jaguar_cpu_device::subc_rn_rn(UINT16 op) +{ + int dreg = op & 31; + UINT32 r1 = m_r[(op >> 5) & 31]; + UINT32 r2 = m_r[dreg]; + UINT32 c = ((FLAGS >> 1) & 1); + UINT32 res = r2 - r1 - c; + m_r[dreg] = res; + CLR_ZNC(); SET_ZNC_SUB(r2, r1 + c, res); +} + +void jaguar_cpu_device::subq_n_rn(UINT16 op) +{ + int dreg = op & 31; + UINT32 r1 = convert_zero[(op >> 5) & 31]; + UINT32 r2 = m_r[dreg]; + UINT32 res = r2 - r1; + m_r[dreg] = res; + CLR_ZNC(); SET_ZNC_SUB(r2, r1, res); +} + +void jaguar_cpu_device::subqmod_n_rn(UINT16 op) /* DSP only */ +{ + int dreg = op & 31; + UINT32 r1 = convert_zero[(op >> 5) & 31]; + UINT32 r2 = m_r[dreg]; + UINT32 res = r2 - r1; + res = (res & ~m_ctrl[D_MOD]) | (r2 & ~m_ctrl[D_MOD]); + m_r[dreg] = res; + CLR_ZNC(); SET_ZNC_SUB(r2, r1, res); +} + +void jaguar_cpu_device::subqt_n_rn(UINT16 op) +{ + int dreg = op & 31; + UINT32 r1 = convert_zero[(op >> 5) & 31]; + UINT32 r2 = m_r[dreg]; + UINT32 res = r2 - r1; + m_r[dreg] = res; +} + +void jaguar_cpu_device::xor_rn_rn(UINT16 op) +{ + int dreg = op & 31; + UINT32 r1 = m_r[(op >> 5) & 31]; + UINT32 r2 = m_r[dreg]; + UINT32 res = r1 ^ r2; + m_r[dreg] = res; + CLR_ZN(); SET_ZN(res); +} + + + +/*************************************************************************** + I/O HANDLING +***************************************************************************/ + +READ32_MEMBER( jaguargpu_cpu_device::ctrl_r ) +{ + if (LOG_GPU_IO) logerror("GPU read register @ F021%02X\n", offset * 4); + + return m_ctrl[offset]; +} + + +WRITE32_MEMBER( jaguargpu_cpu_device::ctrl_w ) +{ + UINT32 oldval, newval; + + if (LOG_GPU_IO && offset != G_HIDATA) + logerror("GPU write register @ F021%02X = %08X\n", offset * 4, data); + + /* remember the old and set the new */ + oldval = m_ctrl[offset]; + newval = oldval; + COMBINE_DATA(&newval); + + /* handle the various registers */ + switch (offset) + { + case G_FLAGS: + + /* combine the data properly */ + m_ctrl[offset] = newval & (ZFLAG | CFLAG | NFLAG | EINT04FLAGS | RPAGEFLAG); + if (newval & IFLAG) + m_ctrl[offset] |= oldval & IFLAG; + + /* clear interrupts */ + m_ctrl[G_CTRL] &= ~((newval & CINT04FLAGS) >> 3); + + /* determine which register bank should be active */ + update_register_banks(); + + /* update IRQs */ + check_irqs(); + break; + + case G_MTXC: + case G_MTXA: + m_ctrl[offset] = newval; + break; + + case G_END: + m_ctrl[offset] = newval; + if ((newval & 7) != 7) + logerror("GPU to set to little-endian!\n"); + break; + + case G_PC: + PC = newval & 0xffffff; + break; + + case G_CTRL: + m_ctrl[offset] = newval; + if ((oldval ^ newval) & 0x01) + { + set_input_line(INPUT_LINE_HALT, (newval & 1) ? CLEAR_LINE : ASSERT_LINE); + yield(); + } + if (newval & 0x02) + { + m_cpu_interrupt(ASSERT_LINE); + m_ctrl[offset] &= ~0x02; + } + if (newval & 0x04) + { + m_ctrl[G_CTRL] |= 1 << 6; + m_ctrl[offset] &= ~0x04; + check_irqs(); + } + if (newval & 0x18) + { + logerror("GPU single stepping was enabled!\n"); + } + break; + + case G_HIDATA: + case G_DIVCTRL: + m_ctrl[offset] = newval; + break; + } +} + + + +/*************************************************************************** + I/O HANDLING +***************************************************************************/ + +READ32_MEMBER( jaguardsp_cpu_device::ctrl_r ) +{ + if (LOG_DSP_IO && offset != D_FLAGS) + logerror("DSP read register @ F1A1%02X\n", offset * 4); + + /* switch to the target context */ + return m_ctrl[offset]; +} + + +WRITE32_MEMBER( jaguardsp_cpu_device::ctrl_w ) +{ + UINT32 oldval, newval; + + if (LOG_DSP_IO && offset != D_FLAGS) + logerror("DSP write register @ F1A1%02X = %08X\n", offset * 4, data); + + /* remember the old and set the new */ + oldval = m_ctrl[offset]; + newval = oldval; + COMBINE_DATA(&newval); + + /* handle the various registers */ + switch (offset) + { + case D_FLAGS: + + /* combine the data properly */ + m_ctrl[offset] = newval & (ZFLAG | CFLAG | NFLAG | EINT04FLAGS | EINT5FLAG | RPAGEFLAG); + if (newval & IFLAG) + m_ctrl[offset] |= oldval & IFLAG; + + /* clear interrupts */ + m_ctrl[D_CTRL] &= ~((newval & CINT04FLAGS) >> 3); + m_ctrl[D_CTRL] &= ~((newval & CINT5FLAG) >> 1); + + /* determine which register bank should be active */ + update_register_banks(); + + /* update IRQs */ + check_irqs(); + break; + + case D_MTXC: + case D_MTXA: + m_ctrl[offset] = newval; + break; + + case D_END: + m_ctrl[offset] = newval; + if ((newval & 7) != 7) + logerror("DSP to set to little-endian!\n"); + break; + + case D_PC: + PC = newval & 0xffffff; + break; + + case D_CTRL: + m_ctrl[offset] = newval; + if ((oldval ^ newval) & 0x01) + { + set_input_line(INPUT_LINE_HALT, (newval & 1) ? CLEAR_LINE : ASSERT_LINE); + yield(); + } + if (newval & 0x02) + { + m_cpu_interrupt(ASSERT_LINE); + m_ctrl[offset] &= ~0x02; + } + if (newval & 0x04) + { + m_ctrl[D_CTRL] |= 1 << 6; + m_ctrl[offset] &= ~0x04; + check_irqs(); + } + if (newval & 0x18) + { + logerror("DSP single stepping was enabled!\n"); + } + break; + + case D_MOD: + case D_DIVCTRL: + m_ctrl[offset] = newval; + break; + } +} + + +offs_t jaguargpu_cpu_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( jaguargpu ); + return CPU_DISASSEMBLE_NAME(jaguargpu)(this, buffer, pc, oprom, opram, options); +} + + +offs_t jaguardsp_cpu_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( jaguardsp ); + return CPU_DISASSEMBLE_NAME(jaguardsp)(this, buffer, pc, oprom, opram, options); +} diff --git a/src/devices/cpu/jaguar/jaguar.h b/src/devices/cpu/jaguar/jaguar.h new file mode 100644 index 00000000000..5139158861b --- /dev/null +++ b/src/devices/cpu/jaguar/jaguar.h @@ -0,0 +1,278 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + jaguar.h + Interface file for the portable Jaguar DSP emulator. + Written by Aaron Giles + +***************************************************************************/ + +#pragma once + +#ifndef __JAGUAR_H__ +#define __JAGUAR_H__ + + + +/*************************************************************************** + GLOBAL CONSTANTS +***************************************************************************/ + +#define JAGUAR_VARIANT_GPU 0 +#define JAGUAR_VARIANT_DSP 1 + + + +/*************************************************************************** + REGISTER ENUMERATION +***************************************************************************/ + +enum +{ + JAGUAR_PC=1,JAGUAR_FLAGS, + JAGUAR_R0,JAGUAR_R1,JAGUAR_R2,JAGUAR_R3,JAGUAR_R4,JAGUAR_R5,JAGUAR_R6,JAGUAR_R7, + JAGUAR_R8,JAGUAR_R9,JAGUAR_R10,JAGUAR_R11,JAGUAR_R12,JAGUAR_R13,JAGUAR_R14,JAGUAR_R15, + JAGUAR_R16,JAGUAR_R17,JAGUAR_R18,JAGUAR_R19,JAGUAR_R20,JAGUAR_R21,JAGUAR_R22,JAGUAR_R23, + JAGUAR_R24,JAGUAR_R25,JAGUAR_R26,JAGUAR_R27,JAGUAR_R28,JAGUAR_R29,JAGUAR_R30,JAGUAR_R31 +}; + +enum +{ + G_FLAGS = 0, + G_MTXC, + G_MTXA, + G_END, + G_PC, + G_CTRL, + G_HIDATA, + G_DIVCTRL, + G_DUMMY, + G_REMAINDER, + G_CTRLMAX +}; + +enum +{ + D_FLAGS = 0, + D_MTXC, + D_MTXA, + D_END, + D_PC, + D_CTRL, + D_MOD, + D_DIVCTRL, + D_MACHI, + D_REMAINDER, + D_CTRLMAX +}; + + + +/*************************************************************************** + CONFIGURATION +***************************************************************************/ + +#define MCFG_JAGUAR_IRQ_HANDLER(_devcb) \ + devcb = &jaguar_cpu_device::set_int_func(*device, DEVCB_##_devcb); + + +/*************************************************************************** + INTERRUPT CONSTANTS +***************************************************************************/ + +#define JAGUAR_IRQ0 0 /* IRQ0 */ +#define JAGUAR_IRQ1 1 /* IRQ1 */ +#define JAGUAR_IRQ2 2 /* IRQ2 */ +#define JAGUAR_IRQ3 3 /* IRQ3 */ +#define JAGUAR_IRQ4 4 /* IRQ4 */ +#define JAGUAR_IRQ5 5 /* IRQ5 */ + + + +/*************************************************************************** + PUBLIC FUNCTIONS +***************************************************************************/ + + +extern const device_type JAGUARGPU; +extern const device_type JAGUARDSP; + + +class jaguar_cpu_device : public cpu_device +{ +public: + // construction/destruction + jaguar_cpu_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source, bool isdsp); + ~jaguar_cpu_device(); + + // static configuration helpers + template static devcb_base &set_int_func(device_t &device, _Object object) { return downcast(device).m_cpu_interrupt.set_callback(object); } + + virtual DECLARE_WRITE32_MEMBER(ctrl_w) { assert(0); } + virtual DECLARE_READ32_MEMBER(ctrl_r) { assert(0); return 0; } + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_execute_interface overrides + virtual UINT32 execute_min_cycles() const { return 1; } + virtual UINT32 execute_max_cycles() const { return 1; } + virtual UINT32 execute_input_lines() const { return 5; } + virtual void execute_set_input(int inputnum, int state); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const { return (spacenum == AS_PROGRAM) ? &m_program_config : NULL; } + + // device_state_interface overrides + void state_string_export(const device_state_entry &entry, std::string &str); + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const { return 2; } + virtual UINT32 disasm_max_opcode_bytes() const { return 6; } + + address_space_config m_program_config; + + /* core registers */ + UINT32 m_r[32]; + UINT32 m_a[32]; + UINT32 * m_b0; + UINT32 * m_b1; + + /* control registers */ + UINT32 m_ctrl[G_CTRLMAX]; + UINT32 m_ppc; + UINT64 m_accum; + + /* internal stuff */ + bool m_isdsp; + int m_icount; + int m_bankswitch_icount; + devcb_write_line m_cpu_interrupt; + address_space *m_program; + direct_read_data *m_direct; + + UINT32 m_internal_ram_start; + UINT32 m_internal_ram_end; + + typedef void (jaguar_cpu_device::*op_func)(UINT16 op); + + static const op_func gpu_op_table[64]; + static const op_func dsp_op_table[64]; + static const UINT32 convert_zero[32]; + bool m_tables_referenced; + + const op_func *m_table; + + void abs_rn(UINT16 op); + void add_rn_rn(UINT16 op); + void addc_rn_rn(UINT16 op); + void addq_n_rn(UINT16 op); + void addqmod_n_rn(UINT16 op); /* DSP only */ + void addqt_n_rn(UINT16 op); + void and_rn_rn(UINT16 op); + void bclr_n_rn(UINT16 op); + void bset_n_rn(UINT16 op); + void btst_n_rn(UINT16 op); + void cmp_rn_rn(UINT16 op); + void cmpq_n_rn(UINT16 op); + void div_rn_rn(UINT16 op); + void illegal(UINT16 op); + void imacn_rn_rn(UINT16 op); + void imult_rn_rn(UINT16 op); + void imultn_rn_rn(UINT16 op); + void jr_cc_n(UINT16 op); + void jump_cc_rn(UINT16 op); + void load_rn_rn(UINT16 op); + void load_r14n_rn(UINT16 op); + void load_r15n_rn(UINT16 op); + void load_r14rn_rn(UINT16 op); + void load_r15rn_rn(UINT16 op); + void loadb_rn_rn(UINT16 op); + void loadw_rn_rn(UINT16 op); + void loadp_rn_rn(UINT16 op); /* GPU only */ + void mirror_rn(UINT16 op); /* DSP only */ + void mmult_rn_rn(UINT16 op); + void move_rn_rn(UINT16 op); + void move_pc_rn(UINT16 op); + void movefa_rn_rn(UINT16 op); + void movei_n_rn(UINT16 op); + void moveq_n_rn(UINT16 op); + void moveta_rn_rn(UINT16 op); + void mtoi_rn_rn(UINT16 op); + void mult_rn_rn(UINT16 op); + void neg_rn(UINT16 op); + void nop(UINT16 op); + void normi_rn_rn(UINT16 op); + void not_rn(UINT16 op); + void or_rn_rn(UINT16 op); + void pack_rn(UINT16 op); /* GPU only */ + void resmac_rn(UINT16 op); + void ror_rn_rn(UINT16 op); + void rorq_n_rn(UINT16 op); + void sat8_rn(UINT16 op); /* GPU only */ + void sat16_rn(UINT16 op); /* GPU only */ + void sat16s_rn(UINT16 op); /* DSP only */ + void sat24_rn(UINT16 op); /* GPU only */ + void sat32s_rn(UINT16 op); /* DSP only */ + void sh_rn_rn(UINT16 op); + void sha_rn_rn(UINT16 op); + void sharq_n_rn(UINT16 op); + void shlq_n_rn(UINT16 op); + void shrq_n_rn(UINT16 op); + void store_rn_rn(UINT16 op); + void store_rn_r14n(UINT16 op); + void store_rn_r15n(UINT16 op); + void store_rn_r14rn(UINT16 op); + void store_rn_r15rn(UINT16 op); + void storeb_rn_rn(UINT16 op); + void storew_rn_rn(UINT16 op); + void storep_rn_rn(UINT16 op); /* GPU only */ + void sub_rn_rn(UINT16 op); + void subc_rn_rn(UINT16 op); + void subq_n_rn(UINT16 op); + void subqmod_n_rn(UINT16 op); /* DSP only */ + void subqt_n_rn(UINT16 op); + void xor_rn_rn(UINT16 op); + void update_register_banks(); + void check_irqs(); + void init_tables(); + void jaguar_postload(); +}; + + +class jaguargpu_cpu_device : public jaguar_cpu_device +{ +public: + // construction/destruction + jaguargpu_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + DECLARE_WRITE32_MEMBER(ctrl_w); + DECLARE_READ32_MEMBER(ctrl_r); + +protected: + virtual void execute_run(); + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); +}; + + +class jaguardsp_cpu_device : public jaguar_cpu_device +{ +public: + // construction/destruction + jaguardsp_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + DECLARE_WRITE32_MEMBER(ctrl_w); + DECLARE_READ32_MEMBER(ctrl_r); + +protected: + virtual UINT32 execute_input_lines() const { return 6; } + virtual void execute_run(); + + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); +}; + + +#endif /* __JAGUAR_H__ */ diff --git a/src/devices/cpu/lc8670/lc8670.c b/src/devices/cpu/lc8670/lc8670.c new file mode 100644 index 00000000000..96bcfaa0348 --- /dev/null +++ b/src/devices/cpu/lc8670/lc8670.c @@ -0,0 +1,1777 @@ +// license:BSD-3-Clause +// copyright-holders:Sandro Ronco +/****************************************************************************** + + Sanyo LC8670 "Potato" CPU core + by Sandro Ronco + + Based on: + - Sega VMU hardware manual + - Sanyo LC86104C datasheet + + TODO: + - SIO + - HOLD state + +******************************************************************************/ + +#include "emu.h" +#include "debugger.h" +#include "lc8670.h" + +//*************************************************************************** +// DEBUGGING +//*************************************************************************** + +#define LOG_TIMERS 0 +#define LOG_IRQ 0 + + +//************************************************************************** +// CONSTANTS +//************************************************************************** + +const device_type LC8670 = &device_creator; + + +//************************************************************************** +// MACROS +//************************************************************************** + +// registers +#define REG_A m_sfr[0x00] +#define REG_PSW m_sfr[0x01] +#define REG_B m_sfr[0x02] +#define REG_C m_sfr[0x03] +#define REG_TRL m_sfr[0x04] +#define REG_TRH m_sfr[0x05] +#define REG_SP m_sfr[0x06] +#define REG_PCON m_sfr[0x07] +#define REG_IE m_sfr[0x08] +#define REG_IP m_sfr[0x09] +#define REG_EXT m_sfr[0x0d] +#define REG_OCR m_sfr[0x0e] +#define REG_T0CNT m_sfr[0x10] +#define REG_T0PRR m_sfr[0x11] +#define REG_T0LR m_sfr[0x13] +#define REG_T0HR m_sfr[0x15] +#define REG_T1CNT m_sfr[0x18] +#define REG_T1LC m_sfr[0x1a] +#define REG_T1LR m_sfr[0x1b] +#define REG_T1HC m_sfr[0x1c] +#define REG_T1HR m_sfr[0x1d] +#define REG_MCR m_sfr[0x20] +#define REG_STAD m_sfr[0x22] +#define REG_CNR m_sfr[0x23] +#define REG_TDR m_sfr[0x24] +#define REG_XBNK m_sfr[0x25] +#define REG_VCCR m_sfr[0x27] +#define REG_SCON0 m_sfr[0x30] +#define REG_SBUF0 m_sfr[0x31] +#define REG_SBR m_sfr[0x32] +#define REG_SCON1 m_sfr[0x34] +#define REG_SBUF1 m_sfr[0x35] +#define REG_P1 m_sfr[0x44] +#define REG_P1DDR m_sfr[0x45] +#define REG_P1FCR m_sfr[0x46] +#define REG_P3 m_sfr[0x4c] +#define REG_P3DDR m_sfr[0x4d] +#define REG_P3INT m_sfr[0x4e] +#define REG_FPR m_sfr[0x54] +#define REG_I01CR m_sfr[0x5d] +#define REG_I23CR m_sfr[0x5e] +#define REG_ISL m_sfr[0x5f] +#define REG_VSEL m_sfr[0x63] +#define REG_VRMAD1 m_sfr[0x64] +#define REG_VRMAD2 m_sfr[0x65] +#define REG_BTCR m_sfr[0x7f] + +// addressing modes +#define GET_D9 (((m_op & 0x01)<<8) | fetch()) +#define GET_D9B3 (((m_op & 0x10)<<4) | fetch()) +#define GET_I8 fetch() +#define GET_R8 fetch() +#define GET_RI (m_op & 0x03) +#define GET_B3 (m_op & 0x07) +#define GET_A12 (((m_op & 0x10)<<7) | ((m_op & 0x07)<<8) | fetch()) +#define SIGNED(v) ((v) - (BIT(v,7) ? 0x100 : 0)) + +// flags +#define FLAG_CY 0x80 +#define FLAG_AC 0x40 +#define FLAG_OV 0x04 +#define FLAG_P 0x01 +#define GET_CY BIT(REG_PSW,7) +#define GET_AC BIT(REG_PSW,6) +#define GET_OV BIT(REG_PSW,2) +#define GET_P BIT(REG_PSW,0) +#define SET_CY(v) { if (v) REG_PSW |= FLAG_CY; else REG_PSW &= ~FLAG_CY; } while(0) +#define SET_AC(v) { if (v) REG_PSW |= FLAG_AC; else REG_PSW &= ~FLAG_AC; } while(0) +#define SET_OV(v) { if (v) REG_PSW |= FLAG_OV; else REG_PSW &= ~FLAG_OV; } while(0) +#define CHECK_P() check_p_flag() + +// CPU state +#define HALT_MODE 0x01 +#define HOLD_MODE 0x02 + + +//************************************************************************** +// Opcodes Table +//************************************************************************** + +const lc8670_cpu_device::op_handler lc8670_cpu_device::s_opcode_table[] = +{ + &lc8670_cpu_device::op_nop , &lc8670_cpu_device::op_br , &lc8670_cpu_device::op_ld , &lc8670_cpu_device::op_ld , &lc8670_cpu_device::op_call, // 0x0* + &lc8670_cpu_device::op_callr, &lc8670_cpu_device::op_brf , &lc8670_cpu_device::op_st , &lc8670_cpu_device::op_st , &lc8670_cpu_device::op_call, // 0x1* + &lc8670_cpu_device::op_callf, &lc8670_cpu_device::op_jmpf, &lc8670_cpu_device::op_mov , &lc8670_cpu_device::op_mov , &lc8670_cpu_device::op_jmp, // 0x2* + &lc8670_cpu_device::op_mul , &lc8670_cpu_device::op_be , &lc8670_cpu_device::op_be , &lc8670_cpu_device::op_be_ri, &lc8670_cpu_device::op_jmp, // 0x3* + &lc8670_cpu_device::op_div , &lc8670_cpu_device::op_bne , &lc8670_cpu_device::op_bne , &lc8670_cpu_device::op_bne_ri, &lc8670_cpu_device::op_bpc, // 0x4* + &lc8670_cpu_device::op_ldf , &lc8670_cpu_device::op_stf , &lc8670_cpu_device::op_dbnz, &lc8670_cpu_device::op_dbnz, &lc8670_cpu_device::op_bpc, // 0x5* + &lc8670_cpu_device::op_push , &lc8670_cpu_device::op_push, &lc8670_cpu_device::op_inc , &lc8670_cpu_device::op_inc , &lc8670_cpu_device::op_bp, // 0x6* + &lc8670_cpu_device::op_pop , &lc8670_cpu_device::op_pop , &lc8670_cpu_device::op_dec , &lc8670_cpu_device::op_dec , &lc8670_cpu_device::op_bp, // 0x7* + &lc8670_cpu_device::op_bz , &lc8670_cpu_device::op_add , &lc8670_cpu_device::op_add , &lc8670_cpu_device::op_add , &lc8670_cpu_device::op_bn, // 0x8* + &lc8670_cpu_device::op_bnz , &lc8670_cpu_device::op_addc, &lc8670_cpu_device::op_addc, &lc8670_cpu_device::op_addc, &lc8670_cpu_device::op_bn, // 0x9* + &lc8670_cpu_device::op_ret , &lc8670_cpu_device::op_sub , &lc8670_cpu_device::op_sub , &lc8670_cpu_device::op_sub , &lc8670_cpu_device::op_not1, // 0xa* + &lc8670_cpu_device::op_reti , &lc8670_cpu_device::op_subc, &lc8670_cpu_device::op_subc, &lc8670_cpu_device::op_subc, &lc8670_cpu_device::op_not1, // 0xb* + &lc8670_cpu_device::op_ror , &lc8670_cpu_device::op_ldc , &lc8670_cpu_device::op_xch , &lc8670_cpu_device::op_xch , &lc8670_cpu_device::op_clr1, // 0xc* + &lc8670_cpu_device::op_rorc , &lc8670_cpu_device::op_or , &lc8670_cpu_device::op_or , &lc8670_cpu_device::op_or , &lc8670_cpu_device::op_clr1, // 0xd* + &lc8670_cpu_device::op_rol , &lc8670_cpu_device::op_and , &lc8670_cpu_device::op_and , &lc8670_cpu_device::op_and , &lc8670_cpu_device::op_set1, // 0xe* + &lc8670_cpu_device::op_rolc , &lc8670_cpu_device::op_xor , &lc8670_cpu_device::op_xor , &lc8670_cpu_device::op_xor , &lc8670_cpu_device::op_set1, // 0xf* +}; + + +//************************************************************************** +// IRQ vectors +//************************************************************************** + +const UINT16 lc8670_cpu_device::s_irq_vectors[] = +{ + 0x0000, 0x0003, 0x000b, 0x0013, 0x001b, 0x0023, 0x002b, 0x0033, + 0x003b, 0x0043, 0x004b, 0x004f, 0x0052, 0x0055, 0x005a, 0x005d +}; + + +//************************************************************************** +// Internal memory map +//************************************************************************** + +static ADDRESS_MAP_START( lc8670_internal_map, AS_DATA, 8, lc8670_cpu_device ) + AM_RANGE(0x000, 0x0ff) AM_READWRITE(mram_r, mram_w) + AM_RANGE(0x100, 0x17f) AM_READWRITE(regs_r, regs_w) + AM_RANGE(0x180, 0x1ff) AM_READWRITE(xram_r, xram_w) +ADDRESS_MAP_END + + +//************************************************************************** +// LC8670 DEVICE +//************************************************************************** + +//------------------------------------------------- +// lc8670_cpu_device - constructor +//------------------------------------------------- + +lc8670_cpu_device::lc8670_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : cpu_device(mconfig, LC8670, "Sanyo LC8670", tag, owner, clock, "lc8670", __FILE__), + m_program_config("program", ENDIANNESS_BIG, 8, 16, 0), + m_data_config("data", ENDIANNESS_BIG, 8, 9, 0, ADDRESS_MAP_NAME(lc8670_internal_map)), + m_io_config("io", ENDIANNESS_BIG, 8, 8, 0), + m_pc(0), + m_ppc(0), + m_bankswitch_func(*this) +{ + memset(m_sfr, 0x00, sizeof(m_sfr)); + memset(m_timer0, 0x00, sizeof(m_timer0)); + memset(m_timer1, 0x00, sizeof(m_timer1)); +} + +//------------------------------------------------- +// device_start - start up the device +//------------------------------------------------- + +void lc8670_cpu_device::device_start() +{ + // find address spaces + m_program = &space(AS_PROGRAM); + m_data = &space(AS_DATA); + m_io = &space(AS_IO); + m_direct = &m_program->direct(); + + // set our instruction counter + m_icountptr = &m_icount; + + // resolve callbacks + m_bankswitch_func.resolve(); + + // setup timers + m_basetimer = timer_alloc(BASE_TIMER); + m_basetimer->adjust(attotime::from_hz(m_clocks[LC8670_SUB_CLOCK]), 0, attotime::from_hz(m_clocks[LC8670_SUB_CLOCK])); + m_clocktimer = timer_alloc(CLOCK_TIMER); + + // register state for debugger + state_add(LC8670_PC , "PC" , m_pc).callimport().callexport().formatstr("%04X"); + state_add(LC8670_SFR + 0x00, "A" , REG_A ).callimport().callexport().formatstr("%02X"); + state_add(LC8670_SFR + 0x02, "B" , REG_B ).callimport().callexport().formatstr("%02X"); + state_add(LC8670_SFR + 0x03, "C" , REG_C ).callimport().callexport().formatstr("%02X"); + state_add(LC8670_SFR + 0x06, "SP" , REG_SP ).callimport().callexport().formatstr("%02X"); + state_add(LC8670_SFR + 0x01, "PSW" , REG_PSW ).callimport().callexport().formatstr("%02X"); + state_add(LC8670_SFR + 0x04, "TRL" , REG_TRL ).callimport().callexport().formatstr("%02X"); + state_add(LC8670_SFR + 0x05, "TRH" , REG_TRH ).callimport().callexport().formatstr("%02X"); + state_add(LC8670_SFR + 0x07, "PCON" , REG_PCON ).callimport().callexport().formatstr("%02X"); + state_add(LC8670_SFR + 0x08, "IE" , REG_IE ).callimport().callexport().formatstr("%02X"); + state_add(LC8670_SFR + 0x09, "IP" , REG_IP ).callimport().callexport().formatstr("%02X"); + state_add(LC8670_SFR + 0x0d, "EXT" , REG_EXT ).callimport().callexport().formatstr("%02X"); + state_add(LC8670_SFR + 0x0e, "OCR" , REG_OCR ).callimport().callexport().formatstr("%02X"); + state_add(LC8670_SFR + 0x10, "T0CNT" , REG_T0CNT ).callimport().callexport().formatstr("%02X"); + state_add(LC8670_SFR + 0x11, "T0PRR" , REG_T0PRR ).callimport().callexport().formatstr("%02X"); + state_add(LC8670_SFR + 0x12, "T0L" , m_timer0[0]).callimport().callexport().formatstr("%02X"); + state_add(LC8670_SFR + 0x13, "T0LR" , REG_T0LR ).callimport().callexport().formatstr("%02X"); + state_add(LC8670_SFR + 0x14, "T0H" , m_timer0[1]).callimport().callexport().formatstr("%02X"); + state_add(LC8670_SFR + 0x15, "T0HR" , REG_T0HR ).callimport().callexport().formatstr("%02X"); + state_add(LC8670_SFR + 0x18, "T1CNT" , REG_T1CNT ).callimport().callexport().formatstr("%02X"); + state_add(LC8670_SFR + 0x80, "T1L" , m_timer1[0]).callimport().callexport().formatstr("%02X"); + state_add(LC8670_SFR + 0x1a, "T1LC" , REG_T1LC ).callimport().callexport().formatstr("%02X"); + state_add(LC8670_SFR + 0x1b, "T1LR" , REG_T1LR ).callimport().callexport().formatstr("%02X"); + state_add(LC8670_SFR + 0x81, "T1H" , m_timer1[1]).callimport().callexport().formatstr("%02X"); + state_add(LC8670_SFR + 0x1c, "T1HC" , REG_T1HC ).callimport().callexport().formatstr("%02X"); + state_add(LC8670_SFR + 0x1d, "T1HR" , REG_T1HR ).callimport().callexport().formatstr("%02X"); + state_add(LC8670_SFR + 0x20, "MCR" , REG_MCR ).callimport().callexport().formatstr("%02X"); + state_add(LC8670_SFR + 0x22, "STAD" , REG_STAD ).callimport().callexport().formatstr("%02X"); + state_add(LC8670_SFR + 0x23, "CNR" , REG_CNR ).callimport().callexport().formatstr("%02X"); + state_add(LC8670_SFR + 0x24, "TDR" , REG_TDR ).callimport().callexport().formatstr("%02X"); + state_add(LC8670_SFR + 0x25, "XBNK" , REG_XBNK ).callimport().callexport().formatstr("%02X"); + state_add(LC8670_SFR + 0x27, "VCCR" , REG_VCCR ).callimport().callexport().formatstr("%02X"); + state_add(LC8670_SFR + 0x30, "SCON0" , REG_SCON0 ).callimport().callexport().formatstr("%02X"); + state_add(LC8670_SFR + 0x31, "SBUF0" , REG_SBUF0 ).callimport().callexport().formatstr("%02X"); + state_add(LC8670_SFR + 0x32, "SBR" , REG_SBR ).callimport().callexport().formatstr("%02X"); + state_add(LC8670_SFR + 0x34, "SCON1" , REG_SCON1 ).callimport().callexport().formatstr("%02X"); + state_add(LC8670_SFR + 0x35, "SBUF1" , REG_SBUF1 ).callimport().callexport().formatstr("%02X"); + state_add(LC8670_SFR + 0x44, "P1" , REG_P1 ).callimport().callexport().formatstr("%02X"); + state_add(LC8670_SFR + 0x45, "P1DDR" , REG_P1DDR ).callimport().callexport().formatstr("%02X"); + state_add(LC8670_SFR + 0x46, "P1FCR" , REG_P1FCR ).callimport().callexport().formatstr("%02X"); + state_add(LC8670_SFR + 0x4c, "P3" , REG_P3 ).callimport().callexport().formatstr("%02X"); + state_add(LC8670_SFR + 0x4d, "P3DDR" , REG_P3DDR ).callimport().callexport().formatstr("%02X"); + state_add(LC8670_SFR + 0x4e, "P3INT" , REG_P3INT ).callimport().callexport().formatstr("%02X"); + state_add(LC8670_SFR + 0x54, "FPR" , REG_FPR ).callimport().callexport().formatstr("%02X"); + state_add(LC8670_SFR + 0x5d, "I01CR" , REG_I01CR ).callimport().callexport().formatstr("%02X"); + state_add(LC8670_SFR + 0x5e, "I23CR" , REG_I23CR ).callimport().callexport().formatstr("%02X"); + state_add(LC8670_SFR + 0x5f, "ISL" , REG_ISL ).callimport().callexport().formatstr("%02X"); + state_add(LC8670_SFR + 0x63, "VSEL" , REG_VSEL ).callimport().callexport().formatstr("%02X"); + state_add(LC8670_SFR + 0x64, "VRMAD1", REG_VRMAD1).callimport().callexport().formatstr("%02X"); + state_add(LC8670_SFR + 0x65, "VRMAD2", REG_VRMAD2).callimport().callexport().formatstr("%02X"); + state_add(LC8670_SFR + 0x7f, "BTCR" , REG_BTCR ).callimport().callexport().formatstr("%02X"); + + state_add(STATE_GENPC, "curpc", m_pc).callimport().callexport().formatstr("%04X").noshow(); + state_add(STATE_GENPCBASE, "curpcbase", m_ppc).callimport().callexport().formatstr("%4X").noshow(); + state_add(STATE_GENFLAGS, "GENFLAGS", REG_PSW).mask(0xff).formatstr("%7s").noshow(); + + // save state + save_pointer(NAME(m_sfr), 0x80); + save_pointer(NAME(m_mram), 0x200); + save_pointer(NAME(m_xram), 0xc6); + save_pointer(NAME(m_vtrbf), 0x200); + save_item(NAME(m_pc)); + save_item(NAME(m_ppc)); + save_item(NAME(m_op)); + save_item(NAME(m_irq_flag)); + save_item(NAME(m_irq_lev)); + save_item(NAME(m_after_reti)); + save_item(NAME(m_p1_data)); + save_item(NAME(m_timer0_prescaler)); + save_item(NAME(m_timer0)); + save_item(NAME(m_timer1)); + save_item(NAME(m_timer1_comparator)); + save_item(NAME(m_base_timer)); + save_item(NAME(m_clock_changed)); + save_item(NAME(m_input_lines)); +} + + +//------------------------------------------------- +// device_reset - reset up the device +//------------------------------------------------- + +void lc8670_cpu_device::device_reset() +{ + m_pc = s_irq_vectors[0]; + m_ppc = m_pc; + m_op = 0; + m_icount = 0; + m_irq_flag = 0; + m_irq_lev = 0; + m_after_reti = false; + m_p1_data = 0; + m_timer0_prescaler = 0; + m_timer0[0] = m_timer0[1] = 0; + m_timer1[0] = m_timer1[1] = 0; + m_timer1_comparator[0] = m_timer1_comparator[1] = 0; + m_base_timer[0] = m_base_timer[1] = 0; + m_clock_changed = false; + memset(m_sfr, 0, 0x80); + memset(m_mram, 0, 0x200); + memset(m_xram, 0, 0xc6); + memset(m_vtrbf, 0, 0x200); + + // default values from VMU hardware manual + REG_P1FCR = 0xbf; + REG_P3INT = 0xfd; + REG_ISL = 0xc0; + REG_VSEL = 0xfc; + REG_BTCR = 0x41; + + // reset bankswitch and clock source + m_bankswitch_func(0); + change_clock_source(); +} + + +//------------------------------------------------- +// device_timer - handler timer events +//------------------------------------------------- + +void lc8670_cpu_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch(id) + { + case BASE_TIMER: + if (!(REG_ISL & 0x10)) + base_timer_tick(); + break; + + case CLOCK_TIMER: + timer0_prescaler_tick(); + timer1_tick(); + + if ((REG_ISL & 0x30) == 0x10) + base_timer_tick(); + break; + } +} + + +//------------------------------------------------- +// state_import - import state into the device, +// after it has been set +//------------------------------------------------- + +void lc8670_cpu_device::state_import(const device_state_entry &entry) +{ + switch (entry.index()) + { + case STATE_GENPC: + set_pc(m_pc); + break; + } +} + + +//------------------------------------------------- +// state_string_export - export state as a string +// for the debugger +//------------------------------------------------- + +void lc8670_cpu_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + switch (entry.index()) + { + case STATE_GENFLAGS: + strprintf(str, "%s%s%s%s", + GET_CY ? "CY" : "..", + GET_AC ? "AC" : "..", + GET_OV ? "OV" : "..", + GET_P ? "P" : "." + ); + break; + } +} + + +//------------------------------------------------- +// memory_space_config - return the configuration +// of the specified address space, or NULL if +// the space doesn't exist +//------------------------------------------------- + +const address_space_config * lc8670_cpu_device::memory_space_config(address_spacenum spacenum) const +{ + return (spacenum == AS_PROGRAM) ? &m_program_config : + (spacenum == AS_DATA) ? &m_data_config : + (spacenum == AS_IO) ? &m_io_config : + NULL; +} + +//------------------------------------------------- +// execute - execute for the provided number of +// countcles +//------------------------------------------------- + +void lc8670_cpu_device::execute_run() +{ + if (m_clock_changed) + { + change_clock_source(); + return; + } + + do + { + check_irqs(); + + debugger_instruction_hook(this, m_pc); + + int cycles = 0; + m_ppc = m_pc; + + if (REG_PCON & HALT_MODE) + { + // in HALT state the timers are still updated + cycles = 1; + } + else + { + // instruction fetch + m_op = fetch(); + int op_idx = decode_op(m_op); + + // execute the instruction + cycles = (this->*s_opcode_table[op_idx])(); + } + + // update the instruction counter + m_icount -= cycles; + } + while (m_icount > 0 && !m_clock_changed); +} + + +//------------------------------------------------- +// execute_set_input +//------------------------------------------------- + +void lc8670_cpu_device::execute_set_input(int inputnum, int state) +{ + switch(inputnum) + { + case LC8670_EXT_INT0: + if ((REG_I01CR & 0x0c) == 0x00 && m_input_lines[inputnum] && !state) // falling edge + { + REG_I01CR |= 0x02; + if (REG_I01CR & 0x01) + set_irq_flag(1); + } + else if ((REG_I01CR & 0x0c) == 0x04 && !state) // low level + { + REG_I01CR |= 0x02; + if (REG_I01CR & 0x01) + set_irq_flag(1); + } + else if ((REG_I01CR & 0x0c) == 0x08 && !m_input_lines[inputnum] && state) // rising edge + { + REG_I01CR |= 0x02; + if (REG_I01CR & 0x01) + set_irq_flag(1); + } + else if ((REG_I01CR & 0x0c) == 0x0c && state) // high level + { + REG_I01CR |= 0x02; + if (REG_I01CR & 0x01) + set_irq_flag(1); + } + break; + case LC8670_EXT_INT1: + if ((REG_I01CR & 0xc0) == 0x00 && m_input_lines[inputnum] && !state) // falling edge + { + REG_I01CR |= 0x20; + if (REG_I01CR & 0x10) + set_irq_flag(2); + } + else if ((REG_I01CR & 0xc0) == 0x40 && !state) // low level + { + REG_I01CR |= 0x20; + if (REG_I01CR & 0x10) + set_irq_flag(2); + } + else if ((REG_I01CR & 0xc0) == 0x80 && !m_input_lines[inputnum] && state) // rising edge + { + REG_I01CR |= 0x20; + if (REG_I01CR & 0x10) + set_irq_flag(2); + } + else if ((REG_I01CR & 0xc0) == 0xc0 && state) // high level + { + REG_I01CR |= 0x20; + if (REG_I01CR & 0x10) + set_irq_flag(2); + } + break; + case LC8670_EXT_INT2: + if ((REG_I23CR & 0x04) && m_input_lines[inputnum] && !state) // falling edge + { + if (!(REG_ISL & 0x01)) + timer0_tick(true); + + REG_I23CR |= 0x02; + if (REG_I23CR & 0x01) + set_irq_flag(3); + } + if ((REG_I23CR & 0x08) && !m_input_lines[inputnum] && state) // rising edge + { + if (!(REG_ISL & 0x01)) + timer0_tick(true); + + REG_I23CR |= 0x02; + if (REG_I23CR & 0x01) + set_irq_flag(3); + } + break; + case LC8670_EXT_INT3: + if ((REG_I23CR & 0x40) && m_input_lines[inputnum] && !state) // falling edge + { + if (REG_ISL & 0x01) + timer0_tick(true); + + REG_I23CR |= 0x20; + if (REG_I23CR & 0x10) + set_irq_flag(4); + } + if ((REG_I23CR & 0x80) && !m_input_lines[inputnum] && state) // rising edge + { + if (REG_ISL & 0x01) + timer0_tick(true); + + REG_I23CR |= 0x20; + if (REG_I23CR & 0x10) + set_irq_flag(4); + } + break; + } + + m_input_lines[inputnum] = state; +} + + +//------------------------------------------------- +// screen_update - handle updating the screen +//------------------------------------------------- + +UINT32 lc8670_cpu_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) +{ + if (m_lcd_update_func) + return m_lcd_update_func(*this, bitmap, cliprect, m_xram, (REG_MCR & 0x08) && (REG_VCCR & 0x80), REG_STAD); + + return 0; +} + + +//------------------------------------------------- +// check_irqs - check for interrupts request +//------------------------------------------------- + +void lc8670_cpu_device::check_irqs() +{ + // update P3 interrupt + check_p3int(); + + if (m_irq_flag && !m_after_reti) + { + int irq = 0; + UINT8 priority = 0; + + // highest priority IRQ + if (!(REG_IE & 0x01) && (m_irq_flag & 0x02)) + { + irq = 0x01; + priority = 2; + } + else if (!(REG_IE & 0x02) && (m_irq_flag & 0x04)) + { + irq = 0x02; + priority = 2; + } + + // high priority IRQ + else if ((REG_IE & 0x80) && ((REG_IP<<3) & m_irq_flag)) + { + for(int i=3; i<=10; i++) + if ((m_irq_flag & (REG_IP<<3)) & (1<>0) & 0xff); + push((m_pc>>8) & 0xff); + + set_pc(s_irq_vectors[irq]); + + REG_PCON &= ~HALT_MODE; // interrupts resume from HALT state + + // clear the IRQ flag + m_irq_flag &= ~(1<>0) & 0xff; + m_timer0[1] = (timer0>>8) & 0xff; + } + } + } + else + { + // 8-bit timer/counter mode + if ((REG_T0CNT & 0x40) && (((REG_T0CNT & 0x10) && ext_line) || (!(REG_T0CNT & 0x10) && !ext_line))) + { + UINT16 timer0l = m_timer0[0] + 1; + + if (timer0l & 0x100) + { + if (LOG_TIMERS) logerror("%s: timer0 low overflow, IRQ: %d\n", tag(), BIT(REG_T0CNT,0)); + m_timer0[0] = REG_T0LR; + REG_T0CNT |= 0x02; + if (REG_T0CNT & 0x01) + set_irq_flag(3); + } + else + { + m_timer0[0] = timer0l & 0xff; + } + } + if ((REG_T0CNT & 0x80) && !ext_line) + { + UINT16 timer0h = m_timer0[1] + 1; + if (timer0h & 0x100) + { + if (LOG_TIMERS) logerror("%s: timer0 high overflow, IRQ: %d\n", tag(), BIT(REG_T0CNT,3)); + m_timer0[1] = REG_T0HR; + REG_T0CNT |= 0x08; + if (REG_T0CNT & 0x04) + set_irq_flag(5); + } + else + { + m_timer0[1] = timer0h & 0xff; + } + } + } + } +} + +//------------------------------------------------- +// timer1_tick - update timer 1 +//------------------------------------------------- + +void lc8670_cpu_device::timer1_tick() +{ + if (REG_T1CNT & 0xc0) + { + if (REG_T1CNT & 0x20) + { + if (REG_T1CNT & 0x40) + { + // 16-bit timer mode + UINT16 timer1l = m_timer1[0] + (REG_T1CNT & 0x80 ? 1 : 2); + if (timer1l & 0x100) + { + UINT16 timer1h = m_timer1[1] + 1; + m_timer1[0] = REG_T1LR; + REG_T1CNT |= 0x04; + + if (timer1h & 0x100) + { + if (LOG_TIMERS) logerror("%s: timer1 long overflow, IRQ: %d\n", tag(), BIT(REG_T1CNT,3)); + m_timer1[1] = REG_T1HR; + REG_T1CNT |= 0x08; + if (REG_T1CNT & 0x05) + set_irq_flag(6); + } + else + { + m_timer1[1] = timer1h & 0xff; + } + } + else + { + m_timer1[0] = timer1l & 0xff; + } + } + } + else + { + // 8-bit timer/pulse generator mode + if (REG_T1CNT & 0x40) + { + UINT16 timer1l = m_timer1[0] + 1; + + if (timer1l == m_timer1_comparator[0]) + update_port1(m_p1_data | 0x80); + + if (timer1l & 0x100) + { + if (LOG_TIMERS) logerror("%s: timer1 low overflow, IRQ: %d\n", tag(), BIT(REG_T1CNT,0)); + m_timer1[0] = REG_T1LR; + update_port1(m_p1_data & 0x7f); + REG_T1CNT |= 0x02; + if (REG_T1CNT & 0x01) + set_irq_flag(6); + } + else + { + m_timer1[0] = timer1l & 0xff; + } + } + if (REG_T1CNT & 0x80) + { + UINT16 timer1h = m_timer1[1] + 1; + + if (timer1h & 0x100) + { + if (LOG_TIMERS) logerror("%s: timer1 high overflow, IRQ: %d\n", tag(), BIT(REG_T1CNT,3)); + m_timer1[1] = REG_T1HR; + REG_T1CNT |= 0x08; + if (REG_T1CNT & 0x04) + set_irq_flag(6); + } + else + { + m_timer1[1] = timer1h & 0xff; + } + } + } + } +} + + +//************************************************************************** +// internal map handlers +//************************************************************************** + +READ8_MEMBER(lc8670_cpu_device::mram_r) +{ + return m_mram[BIT(REG_PSW,1)*0x100 + offset]; +} + +WRITE8_MEMBER(lc8670_cpu_device::mram_w) +{ + m_mram[BIT(REG_PSW,1)*0x100 + offset] = data; +} + +READ8_MEMBER(lc8670_cpu_device::xram_r) +{ + if (!(REG_VCCR & 0x40) || space.debugger_access()) // XRAM access enabled + { + UINT8 * xram_bank = m_xram + (REG_XBNK & 0x03) * 0x60; + + switch(REG_XBNK & 0x03) + { + case 0: + case 1: + if ((offset & 0x0f) < 0x0c) + return xram_bank[(offset>>4) * 0x0c + (offset & 0x0f)]; + break; + case 2: + if (offset < 0x06) + return xram_bank[offset]; + break; + } + } + + return 0xff; +} + +WRITE8_MEMBER(lc8670_cpu_device::xram_w) +{ + if (!(REG_VCCR & 0x40) || space.debugger_access()) // XRAM access enabled + { + UINT8 * xram_bank = m_xram + (REG_XBNK & 0x03) * 0x60; + + switch(REG_XBNK & 0x03) + { + case 0: + case 1: + if ((offset & 0x0f) < 0x0c) + xram_bank[(offset>>4) * 0x0c + (offset & 0x0f)] = data; + break; + case 2: + if (offset < 0x06) + xram_bank[offset] = data; + break; + } + } +} + +READ8_MEMBER(lc8670_cpu_device::regs_r) +{ + switch(offset) + { + case 0x12: + return m_timer0[0]; + case 0x14: + return m_timer0[1]; + case 0x1b: + return m_timer1[0]; + case 0x1d: + return m_timer1[1]; + case 0x44: + return (REG_P1 & REG_P1DDR) | (m_io->read_byte(LC8670_PORT1) & (REG_P1DDR ^ 0xff)); + case 0x4c: + return (REG_P3 & REG_P3DDR) | (m_io->read_byte(LC8670_PORT3) & (REG_P3DDR ^ 0xff)); + case 0x5c: + return m_io->read_byte(LC8670_PORT7) | 0xf0; // 4-bit read-only port + case 0x66: + { + UINT8 data = m_vtrbf[((REG_VRMAD2<<8) | REG_VRMAD1) & 0x1ff]; + if (!space.debugger_access() && (REG_VSEL & 0x10)) + { + UINT16 vrmad = (REG_VRMAD1 | (REG_VRMAD2<<8)) + 1; + REG_VRMAD1 = vrmad & 0xff; + REG_VRMAD2 = (vrmad >> 8) & 0x01; + } + return data; + } + + // write-only registers + case 0x20: case 0x23: case 0x24: case 0x27: + case 0x45: case 0x46: case 0x4d: + if(!space.debugger_access()) logerror("%s: read write-only SFR %04x\n", machine().describe_context(), offset); + return 0xff; + } + return m_sfr[offset]; +} + +WRITE8_MEMBER(lc8670_cpu_device::regs_w) +{ + switch(offset) + { + case 0x00: + REG_A = data; + CHECK_P(); + break; + case 0x07: + if (data & HOLD_MODE) + fatalerror("%s: unemulated HOLD mode\n", machine().describe_context()); + break; + case 0x10: + if (!(data & 0x80)) + m_timer0[1] = REG_T0HR; + if (!(data & 0x40)) + m_timer0[0] = REG_T0LR; + break; + case 0x18: + if ((data & 0x10) && !(REG_T1CNT & 0x10)) + { + m_timer1_comparator[0] = REG_T1LC; + m_timer1_comparator[1] = REG_T1HC; + } + if (!(data & 0x80)) + m_timer1[1] = REG_T1HR; + if (!(data & 0x40)) + m_timer1[0] = REG_T1LR; + break; + case 0x1a: + if ((REG_T1CNT & 0x10) || !(REG_T1CNT & 0x40)) + m_timer1_comparator[0] = data; + break; + case 0x1c: + if ((REG_T1CNT & 0x10) || !(REG_T1CNT & 0x80)) + m_timer1_comparator[1] = data; + break; + case 0x0e: + if ((data ^ REG_OCR) & 0xb0) + m_clock_changed = true; + break; + case 0x44: + m_io->write_byte(LC8670_PORT1, ((data | (m_p1_data & REG_P1FCR)) & REG_P1DDR) | (m_io->read_byte(LC8670_PORT1) & (REG_P1DDR ^ 0xff))); + break; + case 0x4c: + m_io->write_byte(LC8670_PORT3, (data & REG_P3DDR) | (m_io->read_byte(LC8670_PORT3) & (REG_P3DDR ^ 0xff))); + break; + case 0x66: + m_vtrbf[((REG_VRMAD2<<8) | REG_VRMAD1) & 0x1ff] = data; + if (!space.debugger_access() && (REG_VSEL & 0x10)) + { + UINT16 vrmad = (REG_VRMAD1 | (REG_VRMAD2<<8)) + 1; + REG_VRMAD1 = vrmad & 0xff; + REG_VRMAD2 = (vrmad >> 8) & 0x01; + } + break; + case 0x7f: + if (!(data & 0x40)) + m_base_timer[0] = m_base_timer[1] = 0; // stop the timer clear the counter + break; + + // read-only registers + case 0x12: case 0x14: case 0x5c: + if(!space.debugger_access()) logerror("%s: write read-only SFR %04x = %02x\n", machine().describe_context(), offset, data); + return; + } + + m_sfr[offset] = data; +} + + +//************************************************************************** +// HELPERS +//************************************************************************** + +inline UINT8 lc8670_cpu_device::fetch() +{ + UINT8 data = m_direct->read_byte(m_pc); + + set_pc(m_pc + 1); + + return data; +} + +inline UINT8 lc8670_cpu_device::read_data(UINT16 offset) +{ + return m_data->read_byte(offset); +} + +inline void lc8670_cpu_device::write_data(UINT16 offset, UINT8 data) +{ + m_data->write_byte(offset, data); +} + +inline UINT8 lc8670_cpu_device::read_data_latch(UINT16 offset) +{ + if (offset == 0x144) + return REG_P1; + else if (offset == 0x14c) + return REG_P3; + else + return read_data(offset); +} + +inline void lc8670_cpu_device::write_data_latch(UINT16 offset, UINT8 data) +{ + if (offset == 0x144) + REG_P1 = data; + else if (offset == 0x14c) + REG_P3 = data; + else + write_data(offset, data); +} + +inline void lc8670_cpu_device::update_port1(UINT8 data) +{ + m_p1_data = data; + m_io->write_byte(LC8670_PORT1, ((REG_P1 | (m_p1_data & REG_P1FCR)) & REG_P1DDR) | (m_io->read_byte(LC8670_PORT1) & (REG_P1DDR ^ 0xff))); +} + +inline void lc8670_cpu_device::set_pc(UINT16 new_pc) +{ + m_pc = new_pc; +} + +inline void lc8670_cpu_device::push(UINT8 data) +{ + REG_SP++; + m_mram[REG_SP] = data; +} + +inline UINT8 lc8670_cpu_device::pop() +{ + UINT8 data = m_mram[REG_SP]; + REG_SP--; + return data; +} + +inline UINT16 lc8670_cpu_device::get_addr() +{ + int mode = m_op & 0x0f; + UINT16 addr = 0; + + if (mode > 0x01 && mode <= 0x03) + addr = GET_D9; + else if (mode > 0x03 && mode <= 0x07) + addr = read_data(GET_RI | ((REG_PSW>>1) & 0x0c)) | ((GET_RI & 0x02) ? 0x100 : 0x00); + else + fatalerror("%s: invalid get_addr in mode %x\n", machine().describe_context(), mode); + + return addr; +} + +inline UINT8 lc8670_cpu_device::get_data() +{ + int mode = m_op & 0x0f; + UINT8 data = 0; + + if (mode == 0x01) + data = GET_I8; + else + data = read_data(get_addr()); + + return data; +} + +inline void lc8670_cpu_device::change_clock_source() +{ + UINT32 new_clock = 0; + + switch(REG_OCR & 0x30) + { + case 0x00: + new_clock = m_clocks[LC8670_RC_CLOCK]; + break; + case 0x20: + new_clock = m_clocks[LC8670_SUB_CLOCK]; + break; + case 0x10: + case 0x30: + new_clock = m_clocks[LC8670_CF_CLOCK]; + break; + } + + set_unscaled_clock(new_clock); + set_clock_scale(1.0 / (REG_OCR & 0x80 ? 6.0 : 12.0)); + m_clocktimer->adjust(attotime::from_hz(clock()), 0, attotime::from_hz(clock())); + m_clock_changed = false; +} + +inline void lc8670_cpu_device::check_p_flag() +{ + UINT8 p_plag = 0; + for(int i=0; i<8; i++) + p_plag ^= BIT(REG_A, i); + + if (p_plag) + REG_PSW |= FLAG_P; + else + REG_PSW &= ~FLAG_P; +} + +inline void lc8670_cpu_device::check_p3int() +{ + if (REG_P3INT & 0x04) + { + if ((m_io->read_byte(LC8670_PORT3) ^ 0xff) & (REG_P3DDR ^ 0xff) & REG_P3) + { + REG_P3INT |= 0x02; + if (REG_P3INT & 0x01) + set_irq_flag(10); + } + } +} + +inline void lc8670_cpu_device::set_irq_flag(int source) +{ + if (LOG_IRQ) logerror("%s: set interrupt flag: %d\n", tag(), source); + m_irq_flag |= 1<>4) & 0x0f) * 5 + idx; +} + +//************************************************************************** +// Opcodes +//************************************************************************** + +int lc8670_cpu_device::op_nop() +{ + return 1; +} + +int lc8670_cpu_device::op_br() +{ + UINT8 r8 = GET_R8; + set_pc(m_pc + SIGNED(r8)); + + return 2; +} + +int lc8670_cpu_device::op_ld() +{ + REG_A = get_data(); + CHECK_P(); + + return 1; +} + +int lc8670_cpu_device::op_call() +{ + UINT16 new_pc = GET_A12; + + push((m_pc>>0) & 0xff); + push((m_pc>>8) & 0xff); + + set_pc((m_pc & 0xf000) | new_pc); + + return 2; +} + + +int lc8670_cpu_device::op_callr() +{ + UINT16 r16 = fetch(); + r16 |= fetch()<<8; + + push((m_pc>>0) & 0xff); + push((m_pc>>8) & 0xff); + set_pc(m_pc - 1 + r16); + + return 4; +} + +int lc8670_cpu_device::op_brf() +{ + UINT16 r16 = fetch(); + r16 |= fetch()<<8; + set_pc(m_pc - 1 + r16); + + return 4; +} + +int lc8670_cpu_device::op_st() +{ + write_data(get_addr(), REG_A); + + return 1; +} + +int lc8670_cpu_device::op_callf() +{ + UINT16 a16 = fetch()<<8; + a16 |= fetch(); + + push((m_pc>>0) & 0xff); + push((m_pc>>8) & 0xff); + set_pc(a16); + + return 2; +} + +int lc8670_cpu_device::op_jmpf() +{ + UINT16 a16 = fetch()<<8; + a16 |= fetch(); + set_pc(a16); + + m_bankswitch_func(((REG_EXT & 0x01) ? 1 : (REG_EXT & 0x08) ? 0 : 2)); + + return 2; +} + +int lc8670_cpu_device::op_mov() +{ + UINT16 addr = get_addr(); + UINT8 i8 = GET_I8; + write_data(addr, i8); + + return 1; +} + +int lc8670_cpu_device::op_jmp() +{ + UINT16 new_pc = GET_A12; + set_pc((m_pc & 0xf000) | new_pc); + + return 2; +} + +int lc8670_cpu_device::op_mul() +{ + UINT32 res = REG_B * ((REG_A<<8) | REG_C); + + REG_A = (res>>8) & 0xff; + REG_B = (res>>16) & 0xff; + REG_C = (res>>0) & 0xff; + + SET_OV(REG_B != 0 ? 1 : 0); + SET_CY(0); + CHECK_P(); + + return 7; +} + +int lc8670_cpu_device::op_be() +{ + UINT8 data = get_data(); + UINT8 r8 = GET_R8; + + if (REG_A == data) + set_pc(m_pc + SIGNED(r8)); + + SET_CY((REG_A < data) ? 1 : 0); + + return 2; +} + +int lc8670_cpu_device::op_be_ri() +{ + UINT8 data = get_data(); + UINT8 i8 = GET_I8; + UINT8 r8 = GET_R8; + + if (i8 == data) + set_pc(m_pc + SIGNED(r8)); + + SET_CY((data < i8) ? 1 : 0); + + return 2; +} + + +int lc8670_cpu_device::op_div() +{ + UINT32 res, mod; + + if (REG_B != 0) + { + UINT16 v = ((REG_A<<8) | REG_C); + res = v / REG_B; + mod = v % REG_B; + + REG_A = (res>>8) & 0xff; + REG_C = (res>>0) & 0xff; + REG_B = mod & 0xff; + SET_OV(0); + } + else + { + REG_A = 0xff; + SET_OV(1); + } + + SET_CY(0); + CHECK_P(); + + return 7; +} + +int lc8670_cpu_device::op_bne() +{ + UINT8 data = get_data(); + UINT8 r8 = GET_R8; + + if (REG_A != data) + set_pc(m_pc + SIGNED(r8)); + + SET_CY((REG_A < data) ? 1 : 0); + + return 2; +} + +int lc8670_cpu_device::op_bne_ri() +{ + UINT8 data = get_data(); + UINT8 i8 = GET_I8; + UINT8 r8 = GET_R8; + + if (i8 != data) + set_pc(m_pc + SIGNED(r8)); + + SET_CY((data < i8) ? 1 : 0); + + return 2; +} + +int lc8670_cpu_device::op_ldf() +{ + UINT16 addr = REG_TRL | (REG_TRH<<8); + + m_bankswitch_func(REG_FPR & 0x01 ? 2 : 1); + REG_A = m_program->read_byte(addr); + CHECK_P(); + m_bankswitch_func(((REG_EXT & 0x01) ? 1 : (REG_EXT & 0x08) ? 0 : 2)); + + return 2; +} + +int lc8670_cpu_device::op_stf() +{ + UINT16 addr = REG_TRL | (REG_TRH<<8); + + m_bankswitch_func(REG_FPR & 0x01 ? 2 : 1); + m_program->write_byte(addr, REG_A); + m_bankswitch_func(((REG_EXT & 0x01) ? 1 : (REG_EXT & 0x08) ? 0 : 2)); + + return 2; +} + +int lc8670_cpu_device::op_dbnz() +{ + UINT16 addr = get_addr(); + UINT8 r8 = GET_R8; + UINT8 data = read_data_latch(addr) - 1; + + write_data_latch(addr, data); + + if (data != 0) + set_pc(m_pc + SIGNED(r8)); + + return 2; +} + +int lc8670_cpu_device::op_bpc() +{ + UINT8 b3 = GET_B3; + UINT16 d9 = GET_D9B3; + UINT8 r8 = GET_R8; + UINT8 data = read_data_latch(d9); + + if (data & (1< 0xff ? 1 : 0); + SET_AC(((REG_A & 0x0f) + (data & 0x0f)) > 0x0f ? 1 : 0); + SET_OV((REG_A & data) & (data ^ res) & 0x80 ? 1 : 0); + + REG_A = res & 0xff; + CHECK_P(); + + return 1; +} + +int lc8670_cpu_device::op_bn() +{ + UINT8 b3 = GET_B3; + UINT16 d9 = GET_D9B3; + UINT8 r8 = GET_R8; + + if (!(read_data(d9) & (1< 0xff ? 1 : 0); + SET_AC(((REG_A & 0x0f) + (data & 0x0f) + GET_CY) > 0x0f ? 1 : 0); + SET_OV(((REG_A+GET_CY) & data) & (data ^ res) & 0x80 ? 1 : 0); + + REG_A = res & 0xff; + CHECK_P(); + + return 1; +} + +int lc8670_cpu_device::op_ret() +{ + UINT16 new_pc = pop()<<8; + new_pc |= pop(); + set_pc(new_pc); + + return 2; +} + +int lc8670_cpu_device::op_sub() +{ + UINT8 data = get_data(); + INT32 res = (REG_A - data); + + SET_CY(res < 0x00 ? 1 : 0); + SET_AC(((REG_A & 0x0f) - (data & 0x0f)) < 0x00 ? 1 : 0); + SET_OV((REG_A ^ data) & (data & res) & 0x80 ? 1 : 0); + + REG_A = res & 0xff; + CHECK_P(); + + return 1; +} + +int lc8670_cpu_device::op_not1() +{ + UINT16 d9 = GET_D9B3; + UINT8 data = read_data_latch(d9); + + data ^= (1<=0; i--) + if (m_irq_lev & (1<>1); + CHECK_P(); + + return 1; +} + +int lc8670_cpu_device::op_ldc() +{ + REG_A = m_program->read_byte(((REG_TRH<<8) | REG_TRL) + REG_A); + CHECK_P(); + + return 2; +} + +int lc8670_cpu_device::op_xch() +{ + UINT16 addr = get_addr(); + UINT8 data = read_data(addr); + + write_data(addr, REG_A); + REG_A = data; + CHECK_P(); + + return 1; +} + +int lc8670_cpu_device::op_clr1() +{ + UINT16 d9 = GET_D9B3; + UINT8 data = read_data_latch(d9); + + data &= ~(1<>1) | (GET_CY ? 0x80 : 0x00); + + SET_CY(BIT(REG_A,0)); + REG_A = a; + CHECK_P(); + + return 1; +} + +int lc8670_cpu_device::op_or() +{ + REG_A = REG_A | get_data(); + CHECK_P(); + + return 1; +} + +int lc8670_cpu_device::op_rol() +{ + REG_A = ((REG_A & 0x80) >> 7) | (REG_A<<1); + CHECK_P(); + + return 1; +} + +int lc8670_cpu_device::op_and() +{ + REG_A = REG_A & get_data(); + CHECK_P(); + + return 1; +} + +int lc8670_cpu_device::op_set1() +{ + UINT16 d9 = GET_D9B3; + UINT8 data = read_data_latch(d9); + + data |= (1< lc8670_cpu_device + +class lc8670_cpu_device : public cpu_device +{ +public: + // construction/destruction + lc8670_cpu_device(const machine_config &mconfig, const char *_tag, device_t *_owner, UINT32 _clock); + + // public interfaces + UINT32 screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); + + // internal map handlers + DECLARE_READ8_MEMBER(regs_r); + DECLARE_WRITE8_MEMBER(regs_w); + DECLARE_READ8_MEMBER(mram_r); + DECLARE_WRITE8_MEMBER(mram_w); + DECLARE_READ8_MEMBER(xram_r); + DECLARE_WRITE8_MEMBER(xram_w); + + // static configuration helpers + static void static_set_cpu_clock(device_t &device, int _source, UINT32 _clock) { downcast(device).m_clocks[_source] = _clock; } + static void static_set_lcd_update_cb(device_t &device, lc8670_lcd_update _cb) { downcast(device).m_lcd_update_func = _cb; } + template static devcb_base & static_set_bankswitch_cb(device_t &device, _Object object) { return downcast(device).m_bankswitch_func.set_callback(object); } + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + // device_execute_interface overrides + virtual UINT32 execute_min_cycles() const { return 1; } + virtual UINT32 execute_max_cycles() const { return 7; } + virtual UINT32 execute_input_lines() const { return 4; } + virtual void execute_run(); + virtual void execute_set_input(int inputnum, int state); + + // device_state_interface overrides + virtual void state_import(const device_state_entry &entry); + void state_string_export(const device_state_entry &entry, std::string &str); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const; + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const { return 1; } + virtual UINT32 disasm_max_opcode_bytes() const { return 4; } + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + +private: + // helpers + inline UINT8 fetch(); + inline void push(UINT8 data); + inline UINT8 pop(); + inline UINT8 read_data(UINT16 offset); + inline void write_data(UINT16 offset, UINT8 data); + inline UINT8 read_data_latch(UINT16 offset); + inline void write_data_latch(UINT16 offset, UINT8 data); + inline void update_port1(UINT8 data); + inline void set_pc(UINT16 new_pc); + inline UINT8 get_data(); + inline UINT16 get_addr(); + inline void change_clock_source(); + inline void check_p_flag(); + inline void check_p3int(); + inline void set_irq_flag(int source); + int decode_op(UINT8 op); + void check_irqs(); + void timer0_prescaler_tick(); + void timer0_tick(bool ext_line = false); + void timer1_tick(); + void base_timer_tick(); + void dasm_arg(UINT8 op, char *buffer, offs_t pc, int arg, const UINT8 *oprom, int &pos); + + // opcodes handlers + int op_nop(); + int op_br(); + int op_ld(); + int op_call(); + int op_callr(); + int op_brf(); + int op_st(); + int op_callf(); + int op_jmpf(); + int op_mov(); + int op_jmp(); + int op_mul(); + int op_be(); + int op_be_ri(); + int op_div(); + int op_bne(); + int op_bne_ri(); + int op_ldf(); + int op_stf(); + int op_dbnz(); + int op_bpc(); + int op_push(); + int op_inc(); + int op_bp(); + int op_pop(); + int op_dec(); + int op_bz(); + int op_add(); + int op_bn(); + int op_bnz(); + int op_addc(); + int op_ret(); + int op_sub(); + int op_not1(); + int op_reti(); + int op_subc(); + int op_ror(); + int op_ldc(); + int op_xch(); + int op_clr1(); + int op_rorc(); + int op_or(); + int op_rol(); + int op_and(); + int op_set1(); + int op_rolc(); + int op_xor(); + +private: + address_space_config m_program_config; + address_space_config m_data_config; + address_space_config m_io_config; + + address_space * m_program; // program space (ROM or flash) + address_space * m_data; // internal RAM/register + address_space * m_io; // I/O ports + direct_read_data * m_direct; + + // timers + static const device_timer_id BASE_TIMER = 1; + static const device_timer_id CLOCK_TIMER = 2; + emu_timer * m_basetimer; + emu_timer * m_clocktimer; + + // internal state + int m_icount; + UINT16 m_pc; + UINT16 m_ppc; + UINT8 m_op; + UINT8 m_sfr[0x80]; // special function registers + UINT8 m_mram[0x200]; // main RAM + UINT8 m_xram[0xc6]; // XRAM + UINT8 m_vtrbf[0x200]; // work RAM + UINT16 m_irq_flag; + UINT8 m_irq_lev; + bool m_after_reti; + UINT8 m_p1_data; + UINT8 m_timer0_prescaler; + UINT8 m_timer0[2]; + UINT8 m_timer1[2]; + UINT8 m_timer1_comparator[2]; + UINT8 m_base_timer[2]; + bool m_clock_changed; + int m_input_lines[4]; + + // configuration + UINT32 m_clocks[3]; // clock sources + devcb_write8 m_bankswitch_func; // bankswitch CB + lc8670_lcd_update m_lcd_update_func; // LCD update CB + + // interrupts vectors + static const UINT16 s_irq_vectors[16]; + + // opcodes table + typedef int (lc8670_cpu_device::*op_handler)(); + static const op_handler s_opcode_table[80]; + + // disassembler + enum + { + OP_NULL, + OP_R8, + OP_R8RI, + OP_R16, + OP_RI, + OP_A12, + OP_A16, + OP_I8, + OP_B3, + OP_D9, + OP_D9B3, + OP_RII8 + }; + + // disasm table + struct dasm_entry + { + const char *str; + UINT8 arg1; + UINT8 arg2; + bool inv; + }; + static const dasm_entry s_dasm_table[80]; +}; + +extern const device_type LC8670; + +#endif /* __LC8670_H__ */ diff --git a/src/devices/cpu/lc8670/lc8670dsm.c b/src/devices/cpu/lc8670/lc8670dsm.c new file mode 100644 index 00000000000..45985ea6e5f --- /dev/null +++ b/src/devices/cpu/lc8670/lc8670dsm.c @@ -0,0 +1,178 @@ +// license:BSD-3-Clause +// copyright-holders:Sandro Ronco +/****************************************************************************** + + Sanyo LC8670 disassembler + +******************************************************************************/ + +#include "emu.h" +#include "debugger.h" +#include "lc8670.h" + +const lc8670_cpu_device::dasm_entry lc8670_cpu_device::s_dasm_table[] = +{ + { "NOP" , OP_NULL, OP_NULL, 0 }, // 0x0* + { "BR" , OP_R8 , OP_NULL, 0 }, + { "LD" , OP_D9 , OP_NULL, 0 }, + { "LD" , OP_RI , OP_NULL, 0 }, + { "CALL", OP_A12 , OP_NULL, 0 }, + { "CALLR", OP_R16 , OP_NULL, 0 }, // 0x1* + { "BRF" , OP_R16 , OP_NULL, 0 }, + { "ST" , OP_D9 , OP_NULL, 0 }, + { "ST" , OP_RI , OP_NULL, 0 }, + { "CALL", OP_A12 , OP_NULL, 0 }, + { "CALLF", OP_A16 , OP_NULL, 0 }, // 0x2* + { "JMPF", OP_A16 , OP_NULL, 0 }, + { "MOV" , OP_D9 , OP_I8 , 1 }, + { "MOV" , OP_RI , OP_I8 , 1 }, + { "JMP" , OP_A12 , OP_NULL, 0 }, + { "MUL" , OP_NULL, OP_NULL, 0 }, // 0x3* + { "BE" , OP_I8 , OP_R8 , 0 }, + { "BE" , OP_D9 , OP_R8 , 0 }, + { "BE" , OP_RII8, OP_R8 , 0 }, + { "JMP" , OP_A12 , OP_NULL, 0 }, + { "DIV" , OP_NULL, OP_NULL, 0 }, // 0x4* + { "BNE" , OP_I8 , OP_R8 , 0 }, + { "BNE" , OP_D9 , OP_R8 , 0 }, + { "BNE" , OP_RII8, OP_R8 , 0 }, + { "BPC" , OP_D9B3, OP_R8 , 0 }, + { "LDF" , OP_NULL, OP_NULL, 0 }, // 0x5* + { "STF" , OP_NULL, OP_NULL, 0 }, + { "DBNZ", OP_D9 , OP_R8 , 0 }, + { "DBNZ", OP_RI , OP_R8RI, 0 }, + { "BPC" , OP_D9B3, OP_R8 , 0 }, + { "PUSH", OP_D9 , OP_NULL, 0 }, // 0x6* + { "PUSH", OP_D9 , OP_NULL, 0 }, + { "INC" , OP_D9 , OP_NULL, 0 }, + { "INC" , OP_RI , OP_NULL, 0 }, + { "BP" , OP_D9B3, OP_R8 , 0 }, + { "POP" , OP_D9 , OP_NULL, 0 }, // 0x7* + { "POP" , OP_D9 , OP_NULL, 0 }, + { "DEC" , OP_D9 , OP_NULL, 0 }, + { "DEC" , OP_RI , OP_NULL, 0 }, + { "BP" , OP_D9B3, OP_R8 , 0 }, + { "BZ" , OP_R8 , OP_NULL, 0 }, // 0x8* + { "ADD" , OP_I8 , OP_NULL, 0 }, + { "ADD" , OP_D9 , OP_NULL, 0 }, + { "ADD" , OP_RI , OP_NULL, 0 }, + { "BN" , OP_D9B3, OP_R8 , 0 }, + { "BNZ" , OP_R8 , OP_NULL, 0 }, // 0x9* + { "ADDC", OP_I8 , OP_NULL, 0 }, + { "ADDC", OP_D9 , OP_NULL, 0 }, + { "ADDC", OP_RI , OP_NULL, 0 }, + { "BN" , OP_D9B3, OP_R8 , 0 }, + { "RET" , OP_NULL, OP_NULL, 0 }, // 0xa* + { "SUB" , OP_I8 , OP_NULL, 0 }, + { "SUB" , OP_D9 , OP_NULL, 0 }, + { "SUB" , OP_RI , OP_NULL, 0 }, + { "NOT1", OP_D9B3, OP_NULL, 0 }, + { "RETI", OP_NULL, OP_NULL, 0 }, // 0xb* + { "SUBC", OP_I8 , OP_NULL, 0 }, + { "SUBC", OP_D9 , OP_NULL, 0 }, + { "SUBC", OP_RI , OP_NULL, 0 }, + { "NOT1", OP_D9B3, OP_NULL, 0 }, + { "ROR" , OP_NULL, OP_NULL, 0 }, // 0xc* + { "LDC" , OP_NULL, OP_NULL, 0 }, + { "XCH" , OP_D9 , OP_NULL, 0 }, + { "XCH" , OP_RI , OP_NULL, 0 }, + { "CLR1", OP_D9B3, OP_NULL, 0 }, + { "RORC", OP_NULL, OP_NULL, 0 }, // 0xd* + { "OR" , OP_I8 , OP_NULL, 0 }, + { "OR" , OP_D9 , OP_NULL, 0 }, + { "OR" , OP_RI , OP_NULL, 0 }, + { "CLR1", OP_D9B3, OP_NULL, 0 }, + { "ROL" , OP_NULL, OP_NULL, 0 }, // 0xe* + { "AND" , OP_I8 , OP_NULL, 0 }, + { "AND" , OP_D9 , OP_NULL, 0 }, + { "AND" , OP_RI , OP_NULL, 0 }, + { "SET1", OP_D9B3, OP_NULL, 0 }, + { "ROLC", OP_NULL, OP_NULL, 0 }, // 0xf* + { "XOR" , OP_I8 , OP_NULL, 0 }, + { "XOR" , OP_D9 , OP_NULL, 0 }, + { "XOR" , OP_RI , OP_NULL, 0 }, + { "SET1", OP_D9B3, OP_NULL, 0 }, +}; + +void lc8670_cpu_device::dasm_arg(UINT8 op, char *buffer, offs_t pc, int arg, const UINT8 *oprom, int &pos) +{ + switch( arg ) + { + case OP_NULL: + buffer[0] = '\0'; + break; + case OP_R8: + pc++; + // fall through + case OP_R8RI: + buffer += sprintf(buffer, "%04x", (pc + 1 + oprom[pos] - (oprom[pos]&0x80 ? 0x100 : 0)) & 0xffff); + pos++; + break; + case OP_R16: + buffer += sprintf(buffer, "%04x", (pc + 2 + ((oprom[pos+1]<<8) | oprom[pos])) & 0xffff); + pos += 2; + break; + case OP_RI: + buffer += sprintf(buffer, "@%x", op & 0x03); + break; + case OP_A12: + buffer += sprintf(buffer, "%04x", ((pc + 2) & 0xf000) | ((op & 0x10)<<7) | ((op & 0x07)<<8) | oprom[pos]); + pos++; + break; + case OP_A16: + buffer += sprintf(buffer, "%04x", (oprom[pos]<<8) | oprom[pos+1]); + pos += 2; + break; + case OP_I8: + buffer += sprintf(buffer, "#$%02x", oprom[pos++]); + break; + case OP_B3: + buffer += sprintf(buffer, "%x", op & 0x07); + break; + case OP_D9: + buffer += sprintf(buffer, "($%03x)", ((op & 0x01)<<8) | oprom[pos]); + pos++; + break; + case OP_D9B3: + buffer += sprintf(buffer, "($%03x)", ((op & 0x10)<<4) | oprom[pos]); + buffer += sprintf(buffer, ",%x", op & 0x07); + pos++; + break; + case OP_RII8: + buffer += sprintf(buffer, "@%x", op & 0x03); + buffer += sprintf(buffer, ",#$%02x", oprom[pos]); + pos++; + break; + } +} + +//------------------------------------------------- +// disasm_disassemble - call the disassembly +// helper function +//------------------------------------------------- + +offs_t lc8670_cpu_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + int pos = 0; + char arg1[16], arg2[16]; + + UINT8 op = oprom[pos++]; + + int op_idx = decode_op(op); + const dasm_entry *inst = &s_dasm_table[op_idx]; + + buffer += sprintf(buffer,"%-8s", inst->str); + + dasm_arg(op, inst->inv ? arg2 : arg1, pc+0, inst->arg1, oprom, pos); + dasm_arg(op, inst->inv ? arg1 : arg2, pc+1, inst->arg2, oprom, pos); + + strcat(buffer, arg1); + + if (inst->arg2 != OP_NULL) + { + strcat(buffer, ","); + strcat(buffer, arg2); + } + + return pos; +} diff --git a/src/devices/cpu/lh5801/5801dasm.c b/src/devices/cpu/lh5801/5801dasm.c new file mode 100644 index 00000000000..b622bda9de6 --- /dev/null +++ b/src/devices/cpu/lh5801/5801dasm.c @@ -0,0 +1,725 @@ +// license:BSD-3-Clause +// copyright-holders:Peter Trauner +/***************************************************************************** + * + * disasm.c + * portable lh5801 emulator interface + * + * + *****************************************************************************/ + +#include "emu.h" +#include "debugger.h" + +#include "lh5801.h" + +enum Adr +{ + Imp, + Reg, + Vec, // imm byte (vector at 0xffxx) + Vej, + Imm, + RegImm, + Imm16, + RegImm16, + ME0, + ME0Imm, + Abs, + AbsImm, + ME1, + ME1Imm, + ME1Abs, + ME1AbsImm, + RelP, + RelM +}; + +enum Regs +{ + RegNone, + A, + XL, XH, X, + YL, YH, Y, + UL, UH, U, + P, S +}; + +static const char *const RegNames[]= { + 0, "A", "XL", "XH", "X", "YL", "YH", "Y", "UL", "UH", "U", "P", "S" +}; + +#if defined(SEC) +#undef SEC +#endif + +enum Ins +{ + ILL, ILL2, PREFD, NOP, + + LDA, STA, LDI, LDX, STX, + LDE, SDE, LIN, SIN, + TIN, // (x++)->(y++) + ADC, ADI, ADR, SBC, SBI, + DCA, DCS, // bcd add and sub + CPA, CPI, CIN, // A compared with (x++) + AND, ANI, ORA, ORI, EOR, EAI, BIT, BII, + INC, DEC, + DRL, DRR, // digit rotates + ROL, ROR, + SHL, SHR, + AEX, // A nibble swap + + BCR, BCS, BHR, BHS, BZR, BZS, BVR, BVS, + BCH, LOP, // loop with ul + JMP, SJP, RTN, RTI, HLT, + VCR, VCS, VHR, VHS, VVS, VZR, VZS, + VMJ, VEJ, + PSH, POP, ATT, TTA, + REC, SEC, RIE, SIE, + + AM0, AM1, // load timer reg + ITA, // reads input port + ATP, // akku send to data bus + CDV, // clears internal divider + OFF, // clears bf flip flop + RDP, SDP,// reset display flip flop + RPU, SPU,// flip flop pu off + RPV, SPV // flip flop pv off +}; + +static const char *const InsNames[]={ + "ILL", "ILL", 0, "NOP", + "LDA", "STA", "LDI", "LDX", "STX", + "LDE", "SDE", "LIN", "SIN", + "TIN", + "ADC", "ADI", "ADR", "SBC", "SBI", + "DCA", "DCS", + "CPA", "CPI", "CIN", + "AND", "ANI", "ORA", "ORI", "EOR", "EAI", "BIT", "BII", + "INC", "DEC", + "DRL", "DRR", + "ROL", "ROR", + "SHL", "SHR", + "AEX", + "BCR", "BCS", "BHR", "BHS", "BZR", "BZS", "BVR", "BVS", + "BCH", "LOP", + "JMP", "SJP", "RTN", "RTI", "HLT", + "VCR", "VCS", "VHR", "VHS", "VVS", "VZR", "VZS", + "VMJ", "VEJ", + "PSH", "POP", "ATT", "TTA", + "REC", "SEC", "RIE", "SIE", + + "AM0", "AM1", + "ITA", + "ATP", + "CDV", + "OFF", + "RDP", "SDP", + "RPU", "SPU", + "RPV", "SPV", +}; + +struct Entry { Ins ins; Adr adr; Regs reg; }; + +static const Entry table[0x100]={ + { SBC, Reg, XL }, // 0 + { SBC, ME0, X }, + { ADC, Reg, XL }, + { ADC, ME0, X }, + { LDA, Reg, XL }, + { LDA, ME0, X }, + { CPA, Reg, XL }, + { CPA, ME0, X }, + { STA, Reg, XH }, + { AND, ME0, X }, + { STA, Reg, XL }, + { ORA, ME0, X }, + { DCS, ME0, X }, + { EOR, ME0, X }, + { STA, ME0, X }, + { BIT, ME0, X }, + { SBC, Reg, YL }, // 0x10 + { SBC, ME0, Y }, + { ADC, Reg, YL }, + { ADC, ME0, Y }, + { LDA, Reg, YL }, + { LDA, ME0, Y }, + { CPA, Reg, YL }, + { CPA, ME0, Y }, + { STA, Reg, YH }, + { AND, ME0, Y }, + { STA, Reg, YL }, + { ORA, ME0, Y }, + { DCS, ME0, Y }, + { EOR, ME0, Y }, + { STA, ME0, Y }, + { BIT, ME0, Y }, + { SBC, Reg, UL }, // 0x20 + { SBC, ME0, U }, + { ADC, Reg, UL }, + { ADC, ME0, U }, + { LDA, Reg, UL }, + { LDA, ME0, U }, + { CPA, Reg, UL }, + { CPA, ME0, U }, + { STA, Reg, UH }, + { AND, ME0, U }, + { STA, Reg, UL }, + { ORA, ME0, U }, + { DCS, ME0, U }, + { EOR, ME0, U }, + { STA, ME0, U }, + { BIT, ME0, U }, + { ILL }, // 0x30 + { ILL }, + { ILL }, + { ILL }, + { ILL }, + { ILL }, + { ILL }, + { ILL }, + { NOP, Imp }, + { ILL }, + { ILL }, + { ILL }, + { ILL }, + { ILL }, + { ILL }, + { ILL }, + { INC, Reg, XL }, //0x40 + { SIN, Reg, X }, + { DEC, Reg, XL }, + { SDE, Reg, X }, + { INC, Reg, X }, + { LIN, Reg, X }, + { DEC, Reg, X }, + { LDE, Reg, X }, + { LDI, RegImm, XH }, + { ANI, ME0Imm, X }, + { LDI, RegImm, XL }, + { ORI, ME0Imm, X }, + { CPI, RegImm, XH }, + { BII, ME0Imm, X }, + { CPI, RegImm, XL }, + { ADI, ME0Imm, X }, + { INC, Reg, YL }, //0x50 + { SIN, Reg, Y }, + { DEC, Reg, YL }, + { SDE, Reg, Y }, + { INC, Reg, Y }, + { LIN, Reg, Y }, + { DEC, Reg, Y }, + { LDE, Reg, Y }, + { LDI, RegImm, YH }, + { ANI, ME0Imm, Y }, + { LDI, RegImm, YL }, + { ORI, ME0Imm, Y }, + { CPI, RegImm, YH }, + { BII, ME0Imm, Y }, + { CPI, RegImm, YL }, + { ADI, ME0Imm, Y }, + { INC, Reg, UL }, //0x60 + { SIN, Reg, U }, + { DEC, Reg, UL }, + { SDE, Reg, U }, + { INC, Reg, U }, + { LIN, Reg, U }, + { DEC, Reg, U }, + { LDE, Reg, U }, + { LDI, RegImm, UH }, + { ANI, ME0Imm, U }, + { LDI, RegImm, UL }, + { ORI, ME0Imm, U }, + { CPI, RegImm, UH }, + { BII, ME0Imm, U }, + { CPI, RegImm, UL }, + { ADI, ME0Imm, U }, + { ILL }, // 0X70 + { ILL }, + { ILL }, + { ILL }, + { ILL }, + { ILL }, + { ILL }, + { ILL }, + { ILL }, + { ILL }, + { ILL }, + { ILL }, + { ILL }, + { ILL }, + { ILL }, + { ILL }, + { SBC, Reg, XH }, // 0x80 + { BCR, RelP }, + { ADC, Reg, XH }, + { BCS, RelP }, + { LDA, Reg, XH }, + { BHR, RelP }, + { CPA, Reg, XH }, + { BHS, RelP }, + { LOP, RelM }, + { BZR, RelP }, + { RTI, Imp }, + { BZS, RelP }, + { DCA, ME0, X }, + { BVR, RelP }, + { BCH, RelP }, + { BVS, RelP }, + { SBC, Reg, YH }, // 0x90 + { BCR, RelM }, + { ADC, Reg, YH }, + { BCS, RelM }, + { LDA, Reg, YH }, + { BHR, RelM }, + { CPA, Reg, YH }, + { BHS, RelM }, + { ILL }, + { BZR, RelM }, + { RTN, Imp }, + { BZS, RelM }, + { DCA, ME0, Y }, + { BVR, RelM }, + { BCH, RelM }, + { BVS, RelM }, + { SBC, Reg, UH }, // 0xa0 + { SBC, Abs }, + { ADC, Reg, UH }, + { ADC, Abs }, + { LDA, Reg, UH }, + { LDA, Abs }, + { CPA, Reg, UH }, + { CPA, Abs }, + { SPV, Imp }, + { AND, Abs }, + { LDI, RegImm16, S }, + { ORA, Abs }, + { DCA, ME0, U }, + { EOR, Abs }, + { STA, Abs }, + { BIT, Abs }, + { ILL }, //0xb0 + { SBI }, + { ILL }, + { ADI, RegImm, A }, + { ILL }, + { LDI, RegImm, A }, + { ILL }, + { CPI, RegImm, A }, + { RPV, Imp }, + { ANI, RegImm, A }, + { JMP, Imm16 }, + { ORI, RegImm, A }, + { ILL }, + { EAI, Imm }, + { SJP, Imm16 }, + { BII, RegImm, A }, + { VEJ, Vej }, // 0xc0 + { VCR, Vec }, + { VEJ, Vej }, + { VCS, Vec }, + { VEJ, Vej }, + { VHR, Vec }, + { VEJ, Vej }, + { VHS, Vec }, + { VEJ, Vej }, + { VZR, Vec }, + { VEJ, Vej }, + { VZS, Vec }, + { VEJ, Vej }, + { VMJ, Vec }, + { VEJ, Vej }, + { VVS, Vec }, + { VEJ, Vej }, // 0xd0 + { ROR, Imp }, + { VEJ, Vej }, + { DRR, Imp }, + { VEJ, Vej }, + { SHR, Imp }, + { VEJ, Vej }, + { DRL, Imp }, + { VEJ, Vej }, + { SHL, Imp }, + { VEJ, Vej }, + { ROL, Imp }, + { VEJ, Vej }, + { INC, Reg, A }, + { VEJ, Vej }, + { DEC, Reg, A }, + { VEJ, Vej }, //0xe0 + { SPU, Imp }, + { VEJ, Vej }, + { RPU, Imp }, + { VEJ, Vej }, + { ILL }, + { VEJ, Vej }, + { ILL }, + { VEJ, Vej }, + { ANI, AbsImm }, + { VEJ, Vej }, + { ORI, AbsImm }, + { VEJ, Vej }, + { BII, AbsImm }, + { VEJ, Vej }, + { ADI, AbsImm }, + { VEJ, Vej }, //0xf0 + { AEX, Imp }, + { VEJ, Vej }, + { ILL }, + { VEJ, Vej }, + { TIN, Imp }, + { VEJ, Vej }, + { CIN, Imp }, + { ILL }, + { REC, Imp }, + { ILL }, + { SEC, Imp }, + { ILL }, + { PREFD }, + { ILL }, + { ILL } +}; +static const Entry table_fd[0x100]={ + { ILL2 }, // 0x00 + { SBC, ME1, X }, + { ILL2 }, + { ADC, ME1, X }, + { ILL2 }, + { LDA, ME1, X }, + { ILL2 }, + { CPA, ME1, X }, + { LDX, Reg, X }, + { AND, ME1, X }, + { POP, Reg, X }, + { ORA, ME1, X }, + { DCS, ME1, X }, + { EOR, ME1, X }, + { STA, ME1, X }, + { BIT, ME1, X }, + { ILL2 }, // 0x10 + { SBC, ME1, Y }, + { ILL2 }, + { ADC, ME1, Y }, + { ILL2 }, + { LDA, ME1, Y }, + { ILL2 }, + { CPA, ME1, Y }, + { LDX, Reg, Y }, + { AND, ME1, Y }, + { POP, Reg, Y }, + { ORA, ME1, Y }, + { DCS, ME1, Y }, + { EOR, ME1, Y }, + { STA, ME1, Y }, + { BIT, ME1, Y }, + { ILL2 }, // 0x20 + { SBC, ME1, U }, + { ILL2 }, + { ADC, ME1, U }, + { ILL2 }, + { LDA, ME1, U }, + { ILL2 }, + { CPA, ME1, U }, + { LDX, Reg, U }, + { AND, ME1, U }, + { POP, Reg, U }, + { ORA, ME1, U }, + { DCS, ME1, U }, + { EOR, ME1, U }, + { STA, ME1, U }, + { BIT, ME1, U }, + { ILL2 }, // 0x30 + { ILL2 }, + { ILL2 }, + { ILL2 }, + { ILL2 }, + { ILL2 }, + { ILL2 }, + { ILL2 }, + { ILL2 }, + { ILL2 }, + { ILL2 }, + { ILL2 }, + { ILL2 }, + { ILL2 }, + { ILL2 }, + { ILL2 }, + { INC, Reg, XH }, // 0x40 + { ILL2 }, + { DEC, Reg, XH }, //46 in other part of manual + { ILL2 }, + { ILL2 }, + { ILL2 }, + { ILL2 }, + { ILL2 }, + { LDX, Reg, S }, + { ANI, ME1Imm, X }, + { STX, Reg, X }, + { ORI, ME1Imm, X }, + { OFF, Imp }, + { BII, ME1Imm, X }, + { STX, Reg, S }, + { ADI, ME1Imm, X }, + { INC, Reg, YH }, // 0x50 + { ILL2 }, + { DEC, Reg, YH }, // 56 in other part of manual + { ILL2 }, + { ILL2 }, + { ILL2 }, + { ILL2 }, + { ILL2 }, + { LDX, Reg, P }, + { ANI, ME1Imm, Y }, + { STX, Reg, Y }, + { ORI, ME1Imm, Y }, + { ILL2 }, + { BII, ME1Imm, Y }, + { STX, Reg, P }, + { ADI, ME1Imm, Y }, + { INC, Reg, UH }, // 0x60 + { ILL2 }, + { DEC, Reg, UH }, // 66 in other part of manual + { ILL2 }, + { ILL2 }, + { ILL2 }, + { ILL2 }, + { ILL2 }, + { ILL2 }, + { ANI, ME1Imm, U }, + { STX, Reg, U }, + { ORI, ME1Imm, U }, + { ILL2 }, + { BII, ME1Imm, U }, + { ILL }, + { ADI, ME1Imm, U }, + { ILL2 }, // 0x70 + { ILL2 }, + { ILL2 }, + { ILL2 }, + { ILL2 }, + { ILL2 }, + { ILL2 }, + { ILL2 }, + { ILL2 }, + { ILL2 }, + { ILL2 }, + { ILL2 }, + { ILL2 }, + { ILL2 }, + { ILL2 }, + { ILL2 }, + { ILL2 }, // 0x80 + { SIE, Imp }, + { ILL2 }, + { ILL2 }, + { ILL2 }, + { ILL2 }, + { ILL2 }, + { ILL2 }, + { PSH, Reg, X }, + { ILL2 }, + { POP, Reg, A }, + { ILL2 }, + { DCA, ME1, X }, + { ILL2 }, + { CDV, Imp }, + { ILL2 }, + { ILL2 }, // 0x90 + { ILL2 }, + { ILL2 }, + { ILL2 }, + { ILL2 }, + { ILL2 }, + { ILL2 }, + { ILL2 }, + { PSH, Reg, Y }, + { ILL2 }, + { ILL2 }, + { ILL2 }, + { DCA, ME1, Y }, + { ILL2 }, + { ILL2 }, + { ILL2 }, + { ILL2 }, // 0xa0 + { SBC, ME1Abs }, + { ILL2 }, + { ADC, ME1Abs }, + { ILL2 }, + { LDA, ME1Abs }, + { ILL2 }, + { CPA, ME1Abs }, + { PSH, Reg, U }, + { AND, ME1Abs }, + { TTA, Imp }, + { ORA, ME1Abs }, + { DCA, ME1, U }, + { EOR, ME1Abs }, + { STA, ME1Abs }, + { BIT, ME1Abs }, + { ILL2 }, // 0xb0 + { HLT, Imp }, + { ILL2 }, + { ILL2 }, + { ILL2 }, + { ILL2 }, + { ILL2 }, + { ILL2 }, + { ILL2 }, + { ILL2 }, + { ITA, Imp }, + { ILL2 }, + { ILL2 }, + { ILL2 }, + { RIE, Imp }, + { ILL2 }, + { RDP, Imp }, // 0xc0 + { SDP, Imp }, + { ILL2 }, + { ILL2 }, + { ILL2 }, + { ILL2 }, + { ILL2 }, + { ILL2 }, + { PSH, Reg, A }, + { ILL2 }, + { ADR, Reg, X }, + { ILL2 }, + { ATP, Imp }, + { ILL2 }, + { AM0, Imp }, + { ILL2 }, + { ILL2 }, // 0xd0 + { ILL2 }, + { ILL2 }, + { DRR, ME1, X }, + { ILL2 }, + { ILL2 }, + { ILL2 }, + { DRL, ME1, X }, + { ILL2 }, + { ILL2 }, + { ADR, Reg, Y }, + { ILL2 }, + { ILL2 }, + { ILL2 }, + { AM1, Imp }, + { ILL2 }, + { ILL2 }, // 0xe0 + { ILL2 }, + { ILL2 }, + { ILL2 }, + { ILL2 }, + { ILL2 }, + { ILL2 }, + { ILL2 }, + { ILL2 }, + { ANI, ME1AbsImm }, + { ADR, Reg, U }, + { ORI, ME1AbsImm }, + { ATT, Imp }, + { BII, ME1AbsImm }, + { ILL2 }, + { ADI, ME1AbsImm }, + { ILL2 }, // 0xf0 + { ILL2 }, + { ILL2 }, + { ILL2 }, + { ILL2 }, + { ILL2 }, + { ILL2 }, + { ILL2 }, + { ILL2 }, + { ILL2 }, + { ILL2 }, + { ILL2 }, + { ILL2 }, + { ILL2 }, + { ILL2 }, + { ILL2 } +}; + +CPU_DISASSEMBLE( lh5801 ) +{ + int pos = 0; + int oper; + UINT16 absolut; + const Entry *entry; + int temp; + + oper=oprom[pos++]; + entry=table+oper; + + if (table[oper].ins==PREFD) { + oper=oprom[pos++]; + entry=table_fd+oper; + } + switch (entry->ins) { + case ILL: + sprintf(buffer,"%s %.2x", InsNames[entry->ins], oper);break; + case ILL2: + sprintf(buffer,"%s fd%.2x", InsNames[entry->ins], oper);break; + default: + switch(entry->adr) { + case Imp: + sprintf(buffer,"%s", InsNames[entry->ins]);break; + case Reg: + sprintf(buffer,"%s %s", InsNames[entry->ins],RegNames[entry->reg]);break; + case RegImm: + sprintf(buffer,"%s %s,%.2x", InsNames[entry->ins], + RegNames[entry->reg], oprom[pos++]); + break; + case RegImm16: + absolut=oprom[pos++]<<8; + absolut|=oprom[pos++]; + sprintf(buffer,"%s %s,%.4x", InsNames[entry->ins],RegNames[entry->reg],absolut ); + break; + case Vec: + sprintf(buffer,"%s (ff%.2x)", InsNames[entry->ins],oprom[pos++]);break; + case Vej: + sprintf(buffer,"%s (ff%.2x)", InsNames[entry->ins], oper);break; + case Imm: + sprintf(buffer,"%s %.2x", InsNames[entry->ins],oprom[pos++]);break; + case Imm16: + absolut=oprom[pos++]<<8; + absolut|=oprom[pos++]; + sprintf(buffer,"%s %.4x", InsNames[entry->ins],absolut );break; + case RelP: + temp=oprom[pos++]; + sprintf(buffer,"%s %.4x", InsNames[entry->ins],pc+pos+temp );break; + case RelM: + temp=oprom[pos++]; + sprintf(buffer,"%s %.4x", InsNames[entry->ins],pc+pos-temp );break; + case Abs: + absolut=oprom[pos++]<<8; + absolut|=oprom[pos++]; + sprintf(buffer,"%s (%.4x)", InsNames[entry->ins],absolut );break; + case ME1Abs: + absolut=oprom[pos++]<<8; + absolut|=oprom[pos++]; + sprintf(buffer,"%s #(%.4x)", InsNames[entry->ins],absolut );break; + case AbsImm: + absolut=oprom[pos++]<<8; + absolut|=oprom[pos++]; + sprintf(buffer,"%s (%.4x),%.2x", InsNames[entry->ins],absolut, + oprom[pos++]);break; + case ME1AbsImm: + absolut=oprom[pos++]<<8; + absolut|=oprom[pos++]; + sprintf(buffer,"%s #(%.4x),%.2x", InsNames[entry->ins],absolut, + oprom[pos++]);break; + case ME0: + sprintf(buffer,"%s (%s)", InsNames[entry->ins],RegNames[entry->reg] );break; + case ME0Imm: + sprintf(buffer,"%s (%s),%.2x", InsNames[entry->ins],RegNames[entry->reg],oprom[pos++] ); + break; + case ME1: + sprintf(buffer,"%s #(%s)", InsNames[entry->ins],RegNames[entry->reg] );break; + case ME1Imm: + sprintf(buffer,"%s #(%s),%.2x", InsNames[entry->ins],RegNames[entry->reg],oprom[pos++] ); + break; + } + } + + return pos; +} diff --git a/src/devices/cpu/lh5801/5801tbl.inc b/src/devices/cpu/lh5801/5801tbl.inc new file mode 100644 index 00000000000..98a8d7b1d02 --- /dev/null +++ b/src/devices/cpu/lh5801/5801tbl.inc @@ -0,0 +1,689 @@ +// license:BSD-3-Clause +// copyright-holders:Peter Trauner +/* assumed + res=left+right+c + sbc is like adc with inverted carry and right side + (decrement, compare the same) + (like in the m6502 processors) +*/ +UINT8 lh5801_cpu_device::lh5801_add_generic(int left, int right, int carry) +{ + int res=left+right+carry; + int v,c; + + m_t&=~(H|V|Z|C); + + if (!(res&0xff)) m_t|=Z; + c=res&0x100; + if (c) m_t|=C; + if (((left&0xf)+(right&0xf)+carry)&0x10) m_t|=H; + v=((left&0x7f)+(right&0x7f)+carry)&0x80; + if ( (c&&!v)||(!c&&v) ) m_t|=V; + + return res; +} + +UINT16 lh5801_cpu_device::lh5801_readop_word() +{ + UINT16 r; + r=m_direct->read_byte(P++)<<8; + r|=m_direct->read_byte(P++); + return r; +} + + +void lh5801_cpu_device::lh5801_adc(UINT8 data) +{ + m_a=lh5801_add_generic(m_a,data,m_t&C); +} + +void lh5801_cpu_device::lh5801_add_mem(address_space &space, int addr, UINT8 data) +{ + int v=lh5801_add_generic(space.read_byte(addr),data,0); + space.write_byte(addr,v); +} + +void lh5801_cpu_device::lh5801_adr(PAIR *reg) +{ + reg->b.l=lh5801_add_generic(reg->b.l,m_a,0); + if (m_t&C) { + reg->b.h++; + } +} + +void lh5801_cpu_device::lh5801_sbc(UINT8 data) +{ + m_a=lh5801_add_generic(m_a,data^0xff,m_t&C); +} + +void lh5801_cpu_device::lh5801_cpa(UINT8 a, UINT8 b) +{ + lh5801_add_generic(a, b^0xff, 1); +} + +UINT8 lh5801_cpu_device::lh5801_decimaladd_generic(int left, int right, int carry) +{ + int res=lh5801_add_generic(left, right, carry); + UINT8 da; + + //DA values taken from official documentation + if (!(m_t&C) && !(m_t&H)) + da = 0x9a; + else if (!(m_t&C) && (m_t&H)) + da = 0xa0; + else if ((m_t&C) && !(m_t&H)) + da = 0xfa; + else //if ((m_t&C) && (m_t&H)) + da = 0x00; + + return res + da; +} + +void lh5801_cpu_device::lh5801_dca(UINT8 data) +{ + m_a += 0x66; //taken from official documentation + m_a=lh5801_decimaladd_generic(m_a, data, m_t&C); +} + +void lh5801_cpu_device::lh5801_dcs(UINT8 data) +{ + m_a=lh5801_decimaladd_generic(m_a, data^0xff, m_t&C); +} + +void lh5801_cpu_device::lh5801_and(UINT8 data) +{ + m_a&=data; + m_t&=~Z; + if (!m_a) m_t|=Z; +} + +void lh5801_cpu_device::lh5801_and_mem(address_space &space, int addr, UINT8 data) +{ + data&=space.read_byte(addr); + m_t&=~Z; + if (!data) m_t|=Z; + space.write_byte(addr,data); +} + +void lh5801_cpu_device::lh5801_bit(UINT8 a, UINT8 b) +{ + m_t&=~Z; + if (!(a&b)) m_t|=Z; +} + +void lh5801_cpu_device::lh5801_eor(UINT8 data) +{ + m_a^=data; + m_t&=~Z; + if (!m_a) m_t|=Z; +} + +void lh5801_cpu_device::lh5801_ora(UINT8 data) +{ + m_a|=data; + m_t&=~Z; + if (!m_a) m_t|=Z; +} + +void lh5801_cpu_device::lh5801_ora_mem(address_space &space, int addr, UINT8 data) +{ + data|=space.read_byte(addr); + m_t&=~Z; + if (!data) m_t|=Z; + space.write_byte(addr,data); +} + +void lh5801_cpu_device::lh5801_lda(UINT8 data) +{ + m_a=data; + m_t&=~Z; + if (!m_a) m_t|=Z; +} + +void lh5801_cpu_device::lh5801_lde(PAIR *reg) +{ + // or z flag depends on reg + m_a=m_program->read_byte(reg->w.l--); + m_t&=~Z; + if (!m_a) m_t|=Z; +} + +void lh5801_cpu_device::lh5801_sde(PAIR *reg) +{ + m_program->write_byte(reg->w.l--, m_a); +} + +void lh5801_cpu_device::lh5801_lin(PAIR *reg) +{ + // or z flag depends on reg + m_a=m_program->read_byte(reg->w.l++); + m_t&=~Z; + if (!m_a) m_t|=Z; +} + +void lh5801_cpu_device::lh5801_sin(PAIR *reg) +{ + m_program->write_byte(reg->w.l++, m_a); +} + +void lh5801_cpu_device::lh5801_dec(UINT8 *adr) +{ + *adr=lh5801_add_generic(*adr,0xff,0); +} + +void lh5801_cpu_device::lh5801_inc(UINT8 *adr) +{ + *adr=lh5801_add_generic(*adr,1,0); +} + +void lh5801_cpu_device::lh5801_pop() +{ + m_a=m_program->read_byte(++S); + m_t&=~Z; + if (!m_a) m_t|=Z; +} + +void lh5801_cpu_device::lh5801_pop_word(PAIR *reg) +{ + reg->b.h=m_program->read_byte(++S); + reg->b.l=m_program->read_byte(++S); + // z flag? +} + +void lh5801_cpu_device::lh5801_rtn() +{ + P=m_program->read_byte(++S)<<8; + P|=m_program->read_byte(++S); +} + +void lh5801_cpu_device::lh5801_rti() +{ + P=m_program->read_byte(++S)<<8; + P|=m_program->read_byte(++S); + m_t=m_program->read_byte(++S); +} + +void lh5801_cpu_device::lh5801_push(UINT8 data) +{ + m_program->write_byte(S--, data); +} + +void lh5801_cpu_device::lh5801_push_word(UINT16 data) +{ + m_program->write_byte(S--, data&0xff); + m_program->write_byte(S--, data>>8); +} + +void lh5801_cpu_device::lh5801_jmp(UINT16 adr) +{ + P=adr; +} + +void lh5801_cpu_device::lh5801_branch_plus(int doit) +{ + UINT8 t=m_direct->read_byte(P++); + if (doit) { + m_icount-=3; + P+=t; + } +} + +void lh5801_cpu_device::lh5801_branch_minus(int doit) +{ + UINT8 t=m_direct->read_byte(P++); + if (doit) { + m_icount-=3; + P-=t; + } +} + +void lh5801_cpu_device::lh5801_lop() +{ + UINT8 t=m_direct->read_byte(P++); + m_icount-=8; + if (UL--) { + m_icount-=3; + P-=t; + } +} + +void lh5801_cpu_device::lh5801_sjp() +{ + UINT16 n=lh5801_readop_word(); + lh5801_push_word(P); + P=n; +} + +void lh5801_cpu_device::lh5801_vector(int doit, int nr) +{ + if (doit) { + lh5801_push_word(P); + P=m_program->read_byte(0xff00+nr)<<8; + P|=m_program->read_byte(0xff00+nr+1); + m_icount-=21-8; + } + m_t&=~Z; // after the jump!? +} + +void lh5801_cpu_device::lh5801_aex() +{ + UINT8 t=m_a; + m_a=(t<<4)|(t>>4); + // flags? +} + +void lh5801_cpu_device::lh5801_drl(address_space &space, int adr) +{ + UINT16 t=m_a|(space.read_byte(adr)<<8); + + m_a=t>>8; + space.write_byte(adr,t>>4); +} + +void lh5801_cpu_device::lh5801_drr(address_space &space, int adr) +{ + UINT16 t=space.read_byte(adr)|(m_a<<8); + + m_a=t; + space.write_byte(adr,t>>4); +} + +void lh5801_cpu_device::lh5801_rol() +{ + // maybe use of the adder + int n = m_a; + m_a = (n<<1) | (m_t&C); + // flags cvhz + m_t&=~(H|V|Z|C); + if (n&0x80) m_t|=C; + if (!m_a) m_t|=Z; + if (m_a & 0x10) m_t|=H; + if ((BIT(n,6) && !BIT(n,7)) || (!BIT(n,6) && BIT(n,7))) m_t|=V; +} + +void lh5801_cpu_device::lh5801_ror() +{ + int n = m_a; + m_a=(n | ((m_t&C)<<8))>>1; + // flags cvhz + m_t&=~(H|V|Z|C); + if (n&0x01) m_t|=C; + if (!m_a) m_t|=Z; + if (m_a & 0x08) m_t|=H; + if ((BIT(n,0) && BIT(m_a,1)) || (BIT(m_a,0) && BIT(n,1))) m_t|=V; +} + +void lh5801_cpu_device::lh5801_shl() +{ + int n = m_a; + m_a<<=1; + // flags cvhz + m_t&=~(H|V|Z|C); + if (n&0x80) m_t|=C; + if (!m_a) m_t|=Z; + if (m_a & 0x10) m_t|=H; + if ((BIT(n,6) && !BIT(n,7)) || (!BIT(n,6) && BIT(n,7))) m_t|=V; +} + +void lh5801_cpu_device::lh5801_shr() +{ + int n = m_a; + m_a>>=1; + // flags cvhz + m_t&=~(H|V|Z|C); + if (n & 0x01) m_t|=C; + if (!m_a) m_t|=Z; + if (m_a & 0x08) m_t|=H; + if ((BIT(n,0) && BIT(m_a,1)) || (BIT(m_a,0) && BIT(n,1))) m_t|=V; +} + +void lh5801_cpu_device::lh5801_am(int value) +{ + m_tm=value; + // jfkas?jfkl?jkd? +} + +void lh5801_cpu_device::lh5801_ita() +{ + m_a=m_in_func(); + m_t&=~Z; + if (!m_a) m_t|=Z; +} + +void lh5801_cpu_device::lh5801_instruction_fd() +{ + int oper; + int adr; + + oper=m_direct->read_byte(P++); + switch (oper) { + case 0x01: lh5801_sbc(m_io->read_byte(X)); m_icount-=11;break; + case 0x03: lh5801_adc(m_io->read_byte(X)); m_icount-=11;break; + case 0x05: lh5801_lda(m_io->read_byte(X)); m_icount-=10;break; + case 0x07: lh5801_cpa(m_a, m_io->read_byte(X)); m_icount-=11;break; + case 0x08: X=X;m_icount-=11;break; //!!! + case 0x09: lh5801_and(m_io->read_byte(X)); m_icount-=11;break; + case 0x0a: lh5801_pop_word(&m_x); m_icount-=15;break; + case 0x0b: lh5801_ora(m_io->read_byte(X)); m_icount-=11;break; + case 0x0c: lh5801_dcs(m_io->read_byte(X)); m_icount-=17; break; + case 0x0d: lh5801_eor(m_io->read_byte(X)); m_icount-=11;break; + case 0x0e: m_io->write_byte(X,m_a); m_icount-=10;break; + case 0x0f: lh5801_bit(m_io->read_byte(X),m_a); m_icount-=11;break; + case 0x11: lh5801_sbc(m_io->read_byte(Y)); m_icount-=11;break; + case 0x13: lh5801_adc(m_io->read_byte(Y)); m_icount-=11;break; + case 0x15: lh5801_lda(m_io->read_byte(Y)); m_icount-=10;break; + case 0x17: lh5801_cpa(m_a, m_io->read_byte(Y)); m_icount-=11;break; + case 0x18: X=Y;m_icount-=11;break; + case 0x19: lh5801_and(m_io->read_byte(Y)); m_icount-=11;break; + case 0x1a: lh5801_pop_word(&m_y); m_icount-=15;break; + case 0x1b: lh5801_ora(m_io->read_byte(Y)); m_icount-=11;break; + case 0x1c: lh5801_dcs(m_io->read_byte(Y)); m_icount-=17; break; + case 0x1d: lh5801_eor(m_io->read_byte(Y)); m_icount-=11;break; + case 0x1e: m_io->write_byte(Y,m_a); m_icount-=10;break; + case 0x1f: lh5801_bit(m_io->read_byte(Y),m_a); m_icount-=11;break; + case 0x21: lh5801_sbc(m_io->read_byte(U)); m_icount-=11;break; + case 0x23: lh5801_adc(m_io->read_byte(U)); m_icount-=11;break; + case 0x25: lh5801_lda(m_io->read_byte(U)); m_icount-=10;break; + case 0x27: lh5801_cpa(m_a, m_io->read_byte(U)); m_icount-=11;break; + case 0x28: X=U;m_icount-=11;break; + case 0x29: lh5801_and(m_io->read_byte(U)); m_icount-=11;break; + case 0x2a: lh5801_pop_word(&m_u); m_icount-=15;break; + case 0x2b: lh5801_ora(m_io->read_byte(U)); m_icount-=11;break; + case 0x2c: lh5801_dcs(m_io->read_byte(U)); m_icount-=17; break; + case 0x2d: lh5801_eor(m_io->read_byte(U)); m_icount-=11;break; + case 0x2e: m_io->write_byte(U,m_a); m_icount-=10;break; + case 0x2f: lh5801_bit(m_io->read_byte(U),m_a); m_icount-=11;break; + case 0x40: lh5801_inc(&XH);m_icount-=9;break; + case 0x42: lh5801_dec(&XH);m_icount-=9;break; + case 0x48: X=S;m_icount-=11;break; + case 0x49: lh5801_and_mem(*m_io, X, m_direct->read_byte(P++)); m_icount-=17;break; + case 0x4a: X=X;m_icount-=11;break; //!!! + case 0x4b: lh5801_ora_mem(*m_io, X, m_direct->read_byte(P++)); m_icount-=17;break; + case 0x4c: m_bf=0;/*off !*/ m_icount-=8;break; + case 0x4d: lh5801_bit(m_io->read_byte(X), m_direct->read_byte(P++));m_icount-=14;break; + case 0x4e: S=X;m_icount-=11;break; + case 0x4f: lh5801_add_mem(*m_io, X, m_direct->read_byte(P++)); m_icount-=17;break; + case 0x50: lh5801_inc(&YH);m_icount-=9;break; + case 0x52: lh5801_dec(&YH);m_icount-=9;break; + case 0x58: X=P;m_icount-=11;break; + case 0x59: lh5801_and_mem(*m_io, Y, m_direct->read_byte(P++)); m_icount-=17;break; + case 0x5a: Y=X;m_icount-=11;break; + case 0x5b: lh5801_ora_mem(*m_io, Y, m_direct->read_byte(P++)); m_icount-=17;break; + case 0x5d: lh5801_bit(m_io->read_byte(Y), m_direct->read_byte(P++));m_icount-=14;break; + case 0x5e: lh5801_jmp(X);m_icount-=11;break; // P=X + case 0x5f: lh5801_add_mem(*m_io, Y, m_direct->read_byte(P++)); m_icount-=17;break; + case 0x60: lh5801_inc(&UH);m_icount-=9;break; + case 0x62: lh5801_dec(&UH);m_icount-=9;break; + case 0x69: lh5801_and_mem(*m_io, U, m_direct->read_byte(P++)); m_icount-=17;break; + case 0x6a: U=X;m_icount-=11;break; + case 0x6b: lh5801_ora_mem(*m_io, U, m_direct->read_byte(P++)); m_icount-=17;break; + case 0x6d: lh5801_bit(m_io->read_byte(X), m_direct->read_byte(P++));m_icount-=14;break; + case 0x6f: lh5801_add_mem(*m_io, U, m_direct->read_byte(P++)); m_icount-=17;break; + case 0x81: m_t|=IE; /*sie !*/m_icount-=8;break; + case 0x88: lh5801_push_word(X); m_icount-=14;break; + case 0x8a: lh5801_pop(); m_icount-=12; break; + case 0x8c: lh5801_dca(m_io->read_byte(X)); m_icount-=19; break; + case 0x8e: /*cdv clears internal devider*/m_icount-=8;break; + case 0x98: lh5801_push_word(Y); m_icount-=14;break; + case 0x9c: lh5801_dca(m_io->read_byte(Y)); m_icount-=19; break; + case 0xa1: lh5801_sbc(m_io->read_byte(lh5801_readop_word())); m_icount-=17;break; + case 0xa3: lh5801_adc(m_io->read_byte(lh5801_readop_word())); m_icount-=17;break; + case 0xa5: lh5801_lda(m_io->read_byte(lh5801_readop_word())); m_icount-=16;break; + case 0xa7: lh5801_cpa(m_a, m_io->read_byte(lh5801_readop_word())); m_icount-=17;break; + case 0xa8: lh5801_push_word(U); m_icount-=14;break; + case 0xa9: lh5801_and(m_io->read_byte(lh5801_readop_word())); m_icount-=17;break; + case 0xaa: lh5801_lda(m_t); m_icount-=9;break; + case 0xab: lh5801_ora(m_io->read_byte(lh5801_readop_word())); m_icount-=17;break; + case 0xac: lh5801_dca(m_io->read_byte(U)); m_icount-=19; break; + case 0xad: lh5801_eor(m_io->read_byte(lh5801_readop_word())); m_icount-=17;break; + case 0xae: m_io->write_byte(lh5801_readop_word(),m_a); m_icount-=16;break; + case 0xaf: lh5801_bit(m_io->read_byte(lh5801_readop_word()),m_a); m_icount-=17;break; + case 0xb1: /*hlt*/m_icount-=8;break; + case 0xba: lh5801_ita();m_icount-=9;break; + case 0xbe: m_t&=~IE; /*rie !*/m_icount-=8;break; + case 0xc0: m_dp=0; /*rdp !*/m_icount-=8;break; + case 0xc1: m_dp=1; /*sdp !*/m_icount-=8;break; + case 0xc8: lh5801_push(m_a); m_icount-=11;break; + case 0xca: lh5801_adr(&m_x);m_icount-=11;break; + case 0xcc: /*atp sends a to data bus*/m_icount-=9;break; + case 0xce: lh5801_am(m_a); m_icount-=9; break; + case 0xd3: lh5801_drr(*m_io, X); m_icount-=16; break; + case 0xd7: lh5801_drl(*m_io, X); m_icount-=16; break; + case 0xda: lh5801_adr(&m_y);m_icount-=11;break; + case 0xde: lh5801_am(m_a|0x100); m_icount-=9; break; + case 0xea: lh5801_adr(&m_u);m_icount-=11;break; + case 0xe9: + adr=lh5801_readop_word(); + lh5801_and_mem(*m_io, adr, m_direct->read_byte(P++)); m_icount-=23; + break; + case 0xeb: + adr=lh5801_readop_word(); + lh5801_ora_mem(*m_io, adr, m_direct->read_byte(P++)); m_icount-=23; + break; + case 0xec: m_t=m_a; m_icount-=9;break; + case 0xed: + adr=lh5801_readop_word(); + lh5801_bit(m_io->read_byte(adr), m_direct->read_byte(P++)); + m_icount-=20;break; + case 0xef: + adr=lh5801_readop_word(); + lh5801_add_mem(*m_io, adr, m_direct->read_byte(P++)); m_icount-=23; + break; + + default: + logerror("lh5801 illegal opcode at %.4x fd%.2x\n",P-2, oper); + } +} + +void lh5801_cpu_device::lh5801_instruction() +{ + int oper; + int adr; + + oper=m_direct->read_byte(P++); + switch (oper) { + case 0x00: lh5801_sbc(XL); m_icount-=6;break; + case 0x01: lh5801_sbc(m_program->read_byte(X)); m_icount-=7;break; + case 0x02: lh5801_adc(XL); m_icount-=6;break; + case 0x03: lh5801_adc(m_program->read_byte(X)); m_icount-=7;break; + case 0x04: lh5801_lda(XL); m_icount-=5;break; + case 0x05: lh5801_lda(m_program->read_byte(X)); m_icount-=6;break; + case 0x06: lh5801_cpa(m_a, XL); m_icount-=6;break; + case 0x07: lh5801_cpa(m_a, m_program->read_byte(X)); m_icount-=7;break; + case 0x08: XH=m_a; m_icount-=5; break; + case 0x09: lh5801_and(m_program->read_byte(X)); m_icount-=7;break; + case 0x0a: XL=m_a; m_icount-=5; break; + case 0x0b: lh5801_ora(m_program->read_byte(X)); m_icount-=7;break; + case 0x0c: lh5801_dcs(m_program->read_byte(X)); m_icount-=13; break; + case 0x0d: lh5801_eor(m_program->read_byte(X)); m_icount-=7;break; + case 0x0e: m_program->write_byte(X,m_a); m_icount-=6;break; + case 0x0f: lh5801_bit(m_program->read_byte(X),m_a); m_icount-=7;break; + case 0x10: lh5801_sbc(YL); m_icount-=6;break; + case 0x11: lh5801_sbc(m_program->read_byte(Y)); m_icount-=7;break; + case 0x12: lh5801_adc(YL); m_icount-=6;break; + case 0x13: lh5801_adc(m_program->read_byte(Y)); m_icount-=7;break; + case 0x14: lh5801_lda(YL); m_icount-=5;break; + case 0x15: lh5801_lda(m_program->read_byte(Y)); m_icount-=6;break; + case 0x16: lh5801_cpa(m_a, YL); m_icount-=6;break; + case 0x17: lh5801_cpa(m_a, m_program->read_byte(Y)); m_icount-=7;break; + case 0x18: YH=m_a; m_icount-=5; break; + case 0x19: lh5801_and(m_program->read_byte(Y)); m_icount-=7;break; + case 0x1a: YL=m_a; m_icount-=5; break; + case 0x1b: lh5801_ora(m_program->read_byte(Y)); m_icount-=7;break; + case 0x1c: lh5801_dcs(m_program->read_byte(Y)); m_icount-=13; break; + case 0x1d: lh5801_eor(m_program->read_byte(Y)); m_icount-=7;break; + case 0x1e: m_program->write_byte(Y,m_a); m_icount-=6;break; + case 0x1f: lh5801_bit(m_program->read_byte(Y),m_a); m_icount-=7;break; + case 0x20: lh5801_sbc(UL); m_icount-=6;break; + case 0x21: lh5801_sbc(m_program->read_byte(U)); m_icount-=7;break; + case 0x22: lh5801_adc(UL); m_icount-=6;break; + case 0x23: lh5801_adc(m_program->read_byte(U)); m_icount-=7;break; + case 0x24: lh5801_lda(UL); m_icount-=5;break; + case 0x25: lh5801_lda(m_program->read_byte(U)); m_icount-=6;break; + case 0x26: lh5801_cpa(m_a, UL); m_icount-=6;break; + case 0x27: lh5801_cpa(m_a, m_program->read_byte(U)); m_icount-=7;break; + case 0x28: UH=m_a; m_icount-=5; break; + case 0x29: lh5801_and(m_program->read_byte(U)); m_icount-=7;break; + case 0x2a: UL=m_a; m_icount-=5; break; + case 0x2b: lh5801_ora(m_program->read_byte(U)); m_icount-=7;break; + case 0x2c: lh5801_dcs(m_program->read_byte(U)); m_icount-=13; break; + case 0x2d: lh5801_eor(m_program->read_byte(U)); m_icount-=7;break; + case 0x2e: m_program->write_byte(U,m_a); m_icount-=6;break; + case 0x2f: lh5801_bit(m_program->read_byte(U),m_a); m_icount-=7;break; + case 0x38: /*nop*/m_icount-=5;break; + case 0x40: lh5801_inc(&XL);m_icount-=5;break; + case 0x41: lh5801_sin(&m_x); m_icount-=6;break; + case 0x42: lh5801_dec(&XL);m_icount-=5;break; + case 0x43: lh5801_sde(&m_x); m_icount-=6;break; + case 0x44: X++;m_icount-=5;break; + case 0x45: lh5801_lin(&m_x);m_icount-=6;break; + case 0x46: X--;m_icount-=5;break; + case 0x47: lh5801_lde(&m_x);m_icount-=6;break; + case 0x48: XH=m_direct->read_byte(P++);m_icount-=6;break; + case 0x49: lh5801_and_mem(*m_program, X, m_direct->read_byte(P++)); m_icount-=13;break; + case 0x4a: XL=m_direct->read_byte(P++);m_icount-=6;break; + case 0x4b: lh5801_ora_mem(*m_program, X, m_direct->read_byte(P++)); m_icount-=13;break; + case 0x4c: lh5801_cpa(XH, m_direct->read_byte(P++)); m_icount-=7;break; + case 0x4d: lh5801_bit(m_program->read_byte(X), m_direct->read_byte(P++));m_icount-=10;break; + case 0x4e: lh5801_cpa(XL, m_direct->read_byte(P++)); m_icount-=7;break; + case 0x4f: lh5801_add_mem(*m_program, X, m_direct->read_byte(P++)); m_icount-=13;break; + case 0x50: lh5801_inc(&YL);m_icount-=5;break; + case 0x51: lh5801_sin(&m_y); m_icount-=6;break; + case 0x52: lh5801_dec(&YL);m_icount-=5;break; + case 0x53: lh5801_sde(&m_y); m_icount-=6;break; + case 0x54: Y++;m_icount-=5;break; + case 0x55: lh5801_lin(&m_y);m_icount-=6;break; + case 0x56: Y--;m_icount-=5;break; + case 0x57: lh5801_lde(&m_y);m_icount-=6;break; + case 0x58: YH=m_direct->read_byte(P++);m_icount-=6;break; + case 0x59: lh5801_and_mem(*m_program, Y, m_direct->read_byte(P++)); m_icount-=13;break; + case 0x5a: YL=m_direct->read_byte(P++);m_icount-=6;break; + case 0x5b: lh5801_ora_mem(*m_program, Y, m_direct->read_byte(P++)); m_icount-=13;break; + case 0x5c: lh5801_cpa(YH, m_direct->read_byte(P++)); m_icount-=7;break; + case 0x5d: lh5801_bit(m_program->read_byte(Y), m_direct->read_byte(P++));m_icount-=10;break; + case 0x5e: lh5801_cpa(YL, m_direct->read_byte(P++)); m_icount-=7;break; + case 0x5f: lh5801_add_mem(*m_program, Y, m_direct->read_byte(P++)); m_icount-=13;break; + case 0x60: lh5801_inc(&UL);m_icount-=5;break; + case 0x61: lh5801_sin(&m_u); m_icount-=6;break; + case 0x62: lh5801_dec(&UL);m_icount-=5;break; + case 0x63: lh5801_sde(&m_u); m_icount-=6;break; + case 0x64: U++;m_icount-=5;break; + case 0x65: lh5801_lin(&m_u);m_icount-=6;break; + case 0x66: U--;m_icount-=5;break; + case 0x67: lh5801_lde(&m_u);m_icount-=6;break; + case 0x68: UH=m_direct->read_byte(P++);m_icount-=6;break; + case 0x69: lh5801_and_mem(*m_program, U, m_direct->read_byte(P++)); m_icount-=13;break; + case 0x6a: UL=m_direct->read_byte(P++);m_icount-=6;break; + case 0x6b: lh5801_ora_mem(*m_program, U, m_direct->read_byte(P++)); m_icount-=13;break; + case 0x6c: lh5801_cpa(UH, m_direct->read_byte(P++)); m_icount-=7;break; + case 0x6d: lh5801_bit(m_program->read_byte(U), m_direct->read_byte(P++));m_icount-=10;break; + case 0x6e: lh5801_cpa(UL, m_direct->read_byte(P++)); m_icount-=7;break; + case 0x6f: lh5801_add_mem(*m_program, U, m_direct->read_byte(P++)); m_icount-=13;break; + case 0x80: lh5801_sbc(XH); m_icount-=6;break; + case 0x81: lh5801_branch_plus(!(m_t&C)); m_icount-=8; break; + case 0x82: lh5801_adc(XH); m_icount-=6;break; + case 0x83: lh5801_branch_plus(m_t&C); m_icount-=8; break; + case 0x84: lh5801_lda(XH); m_icount-=5;break; + case 0x85: lh5801_branch_plus(!(m_t&H)); m_icount-=8; break; + case 0x86: lh5801_cpa(m_a, XH); m_icount-=6;break; + case 0x87: lh5801_branch_plus(m_t&H); m_icount-=8; break; + case 0x88: lh5801_lop(); break; + case 0x89: lh5801_branch_plus(!(m_t&Z)); m_icount-=8; break; + case 0x8a: lh5801_rti(); m_icount-=14; break; + case 0x8b: lh5801_branch_plus(m_t&Z); m_icount-=8; break; + case 0x8c: lh5801_dca(m_program->read_byte(X)); m_icount-=15; break; + case 0x8d: lh5801_branch_plus(!(m_t&V)); m_icount-=8; break; + case 0x8e: lh5801_branch_plus(1); m_icount-=5; break; + case 0x8f: lh5801_branch_plus(m_t&V); m_icount-=8; break; + case 0x90: lh5801_sbc(YH); m_icount-=6;break; + case 0x91: lh5801_branch_minus(!(m_t&C)); m_icount-=8; break; + case 0x92: lh5801_adc(YH); m_icount-=6;break; + case 0x93: lh5801_branch_minus(m_t&C); m_icount-=8; break; + case 0x94: lh5801_lda(YH); m_icount-=5;break; + case 0x95: lh5801_branch_minus(!(m_t&H)); m_icount-=8; break; + case 0x96: lh5801_cpa(m_a, YH); m_icount-=6;break; + case 0x97: lh5801_branch_minus(m_t&H); m_icount-=8; break; + case 0x99: lh5801_branch_minus(!(m_t&Z)); m_icount-=8; break; + case 0x9a: lh5801_rtn(); m_icount-=11; break; + case 0x9b: lh5801_branch_minus(m_t&Z); m_icount-=8; break; + case 0x9c: lh5801_dca(m_program->read_byte(Y)); m_icount-=15; break; + case 0x9d: lh5801_branch_minus(!(m_t&V)); m_icount-=8; break; + case 0x9e: lh5801_branch_minus(1); m_icount-=6; break; + case 0x9f: lh5801_branch_minus(m_t&V); m_icount-=8; break; + case 0xa0: lh5801_sbc(UH); m_icount-=6;break; + case 0xa2: lh5801_adc(UH); m_icount-=6;break; + case 0xa1: lh5801_sbc(m_program->read_byte(lh5801_readop_word())); m_icount-=13;break; + case 0xa3: lh5801_adc(m_program->read_byte(lh5801_readop_word())); m_icount-=13;break; + case 0xa4: lh5801_lda(UH); m_icount-=5;break; + case 0xa5: lh5801_lda(m_program->read_byte(lh5801_readop_word())); m_icount-=12;break; + case 0xa6: lh5801_cpa(m_a, UH); m_icount-=6;break; + case 0xa7: lh5801_cpa(m_a, m_program->read_byte(lh5801_readop_word())); m_icount-=13;break; + case 0xa8: m_pv=1;/*spv!*/ m_icount-=4; break; + case 0xa9: lh5801_and(m_program->read_byte(lh5801_readop_word())); m_icount-=13;break; + case 0xaa: S=lh5801_readop_word();m_icount-=6;break; + case 0xab: lh5801_ora(m_program->read_byte(lh5801_readop_word())); m_icount-=13;break; + case 0xac: lh5801_dca(m_program->read_byte(U)); m_icount-=15; break; + case 0xad: lh5801_eor(m_program->read_byte(lh5801_readop_word())); m_icount-=13;break; + case 0xae: m_program->write_byte(lh5801_readop_word(),m_a); m_icount-=12;break; + case 0xaf: lh5801_bit(m_program->read_byte(lh5801_readop_word()),m_a); m_icount-=13;break; + case 0xb1: lh5801_sbc(m_direct->read_byte(P++)); m_icount-=7;break; + case 0xb3: lh5801_adc(m_direct->read_byte(P++)); m_icount-=7;break; + case 0xb5: lh5801_lda(m_direct->read_byte(P++)); m_icount-=6;break; + case 0xb7: lh5801_cpa(m_a, m_direct->read_byte(P++)); m_icount-=7;break; + case 0xb8: m_pv=0;/*rpv!*/ m_icount-=4; break; + case 0xb9: lh5801_and(m_direct->read_byte(P++)); m_icount-=7;break; + case 0xba: lh5801_jmp(lh5801_readop_word()); m_icount-=12;break; + case 0xbb: lh5801_ora(m_direct->read_byte(P++)); m_icount-=7;break; + case 0xbd: lh5801_eor(m_direct->read_byte(P++)); m_icount-=7;break; + case 0xbe: lh5801_sjp(); m_icount-=19; break; + case 0xbf: lh5801_bit(m_a, m_direct->read_byte(P++));m_icount-=7;break; + case 0xc1: lh5801_vector(!(m_t&C), m_direct->read_byte(P++)); m_icount-=8;break; + case 0xc3: lh5801_vector(m_t&C, m_direct->read_byte(P++)); m_icount-=8;break; + case 0xc5: lh5801_vector(!(m_t&H), m_direct->read_byte(P++)); m_icount-=8;break; + case 0xc7: lh5801_vector(m_t&H, m_direct->read_byte(P++)); m_icount-=8;break; + case 0xc9: lh5801_vector(!(m_t&Z), m_direct->read_byte(P++)); m_icount-=8;break; + case 0xcb: lh5801_vector(m_t&Z, m_direct->read_byte(P++)); m_icount-=8;break; + case 0xcd: lh5801_vector(1, m_direct->read_byte(P++)); m_icount-=7;break; + case 0xcf: lh5801_vector(m_t&V, m_direct->read_byte(P++)); m_icount-=8;break; + case 0xd1: lh5801_ror(); m_icount-=6; break; + case 0xd3: lh5801_drr(*m_program, X); m_icount-=12; break; + case 0xd5: lh5801_shr(); m_icount-=6; break; + case 0xd7: lh5801_drl(*m_program, X); m_icount-=12; break; + case 0xd9: lh5801_shl(); m_icount-=6; break; + case 0xdb: lh5801_rol(); m_icount-=6; break; + case 0xdd: lh5801_inc(&m_a);m_icount-=5;break; + case 0xdf: lh5801_dec(&m_a);m_icount-=5;break; + case 0xe1: m_pu=1;/*spu!*/ m_icount-=4; break; + case 0xe3: m_pu=0;/*rpu!*/ m_icount-=4; break; + case 0xe9: + adr=lh5801_readop_word();lh5801_and_mem(*m_program, adr, m_direct->read_byte(P++)); + m_icount-=19;break; + case 0xeb: + adr=lh5801_readop_word();lh5801_ora_mem(*m_program, adr, m_direct->read_byte(P++)); + m_icount-=19;break; + case 0xed: + adr=lh5801_readop_word();lh5801_bit(m_program->read_byte(adr), m_direct->read_byte(P++)); + m_icount-=16;break; + case 0xef: + adr=lh5801_readop_word(); + lh5801_add_mem(*m_program, adr, m_direct->read_byte(P++)); m_icount-=19; + break; + case 0xf1: lh5801_aex(); m_icount-=6; break; + case 0xf5: m_program->write_byte(Y++, m_program->read_byte(X++)); m_icount-=7; break; //tin + case 0xf7: lh5801_cpa(m_a, m_program->read_byte(X++));m_icount-=7; break; //cin + case 0xf9: m_t&=~C;m_icount-=4;break; + case 0xfb: m_t|=C;m_icount-=4;break; + case 0xfd: lh5801_instruction_fd();break; + case 0xc0: case 0xc2: case 0xc4: case 0xc6: + case 0xc8: case 0xca: case 0xcc: case 0xce: + case 0xd0: case 0xd2: case 0xd4: case 0xd6: + case 0xd8: case 0xda: case 0xdc: case 0xde: + case 0xe0: case 0xe2: case 0xe4: case 0xe6: + case 0xe8: case 0xea: case 0xec: case 0xee: + case 0xf0: case 0xf2: case 0xf4: case 0xf6: + lh5801_vector(1, oper);m_icount-=4;break; + default: + logerror("lh5801 illegal opcode at %.4x %.2x\n",P-1, oper); + } + +} diff --git a/src/devices/cpu/lh5801/lh5801.c b/src/devices/cpu/lh5801/lh5801.c new file mode 100644 index 00000000000..0287e0d0859 --- /dev/null +++ b/src/devices/cpu/lh5801/lh5801.c @@ -0,0 +1,254 @@ +// license:BSD-3-Clause +// copyright-holders:Peter Trauner +/***************************************************************************** + * + * + * 02/2011 (Sandro Ronco) + * - Added IO_SPACE and updated all access in ME1 memory for use it. + * - Implemented interrupts. + * - Fixed the flags in the ROL/ROR/SHL/SHR opcodes. + * - Fixed decimal add/sub opcodes. + * + * based on info found on an artikel for the tandy trs80 pc2 + * and on "PC1500 Technical reference manual" + * + *****************************************************************************/ + +#include "emu.h" +#include "debugger.h" + +#include "lh5801.h" + +#define VERBOSE 0 + +#define LOG(x) do { if (VERBOSE) logerror x; } while (0) + +enum +{ + LH5801_T=1, + LH5801_P, + LH5801_S, + LH5801_U, + LH5801_X, + LH5801_Y, + LH5801_A, + + LH5801_TM, + LH5801_IN, + LH5801_BF, + LH5801_PU, + LH5801_PV, + LH5801_DP, + LH5801_IRQ_STATE +}; + + +#define P m_p.w.l +#define S m_s.w.l +#define U m_u.w.l +#define UL m_u.b.l +#define UH m_u.b.h +#define X m_x.w.l +#define XL m_x.b.l +#define XH m_x.b.h +#define Y m_y.w.l +#define YL m_y.b.l +#define YH m_y.b.h + +#define C 0x01 +#define IE 0x02 +#define Z 0x04 +#define V 0x08 +#define H 0x10 + + +const device_type LH5801 = &device_creator; + + +lh5801_cpu_device::lh5801_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : cpu_device(mconfig, LH5801, "LH5801", tag, owner, clock, "lh5801", __FILE__) + , m_program_config("program", ENDIANNESS_LITTLE, 8, 16, 0) + , m_io_config("io", ENDIANNESS_LITTLE, 8, 16, 0) + , m_in_func(*this) +{ +} + + +/*************************************************************** + * include the opcode macros, functions and tables + ***************************************************************/ +#include "5801tbl.inc" + +void lh5801_cpu_device::device_start() +{ + m_program = &space(AS_PROGRAM); + m_io = &space(AS_IO); + m_direct = &m_program->direct(); + + m_in_func.resolve_safe(0); + + m_s.w.l = 0; + m_p.w.l = 0; + m_u.w.l = 0; + m_x.w.l = 0; + m_y.w.l = 0; + m_tm = 0; + m_t = 0; + m_a = 0; + m_bf = 0; + m_dp = 0; + m_pu = 0; + m_pv = 0; + m_oldpc = 0; + m_irq_state = 0; + memset(m_ir_flipflop, 0, sizeof(m_ir_flipflop)); + memset(m_lines_status, 0, sizeof(m_lines_status)); + m_idle = 0; + + save_item(NAME(m_s.w.l)); + save_item(NAME(m_p.w.l)); + save_item(NAME(m_u.w.l)); + save_item(NAME(m_x.w.l)); + save_item(NAME(m_y.w.l)); + save_item(NAME(m_tm)); + save_item(NAME(m_t)); + save_item(NAME(m_a)); + save_item(NAME(m_bf)); + save_item(NAME(m_dp)); + save_item(NAME(m_pu)); + save_item(NAME(m_pv)); + save_item(NAME(m_oldpc)); + save_item(NAME(m_irq_state)); + save_item(NAME(m_ir_flipflop)); + save_item(NAME(m_lines_status)); + save_item(NAME(m_idle)); + + state_add( LH5801_P, "P", m_p.w.l ).formatstr("%04X"); + state_add( LH5801_S, "S", m_s.w.l ).formatstr("%04X"); + state_add( LH5801_U, "U", m_u.w.l ).formatstr("%04X"); + state_add( LH5801_X, "X", m_x.w.l ).formatstr("%04X"); + state_add( LH5801_Y, "Y", m_y.w.l ).formatstr("%04X"); + state_add( LH5801_T, "T", m_t ).formatstr("%02X"); + state_add( LH5801_A, "A", m_a ).formatstr("%02X"); + state_add( LH5801_TM, "TM", m_tm ).formatstr("%03X"); + state_add( LH5801_PV, "PV", m_pv ).formatstr("%04X"); + state_add( LH5801_PU, "PU", m_pu ).formatstr("%04X"); + state_add( LH5801_BF, "BF", m_bf ).formatstr("%04X"); + state_add( LH5801_DP, "DP", m_dp ).formatstr("%04X"); + + state_add(STATE_GENPC, "GENPC", m_p.w.l).noshow(); + state_add(STATE_GENFLAGS, "GENFLAGS", m_t).noshow().formatstr("%8s"); + + m_icountptr = &m_icount; +} + +void lh5801_cpu_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + switch (entry.index()) + { + case STATE_GENFLAGS: + strprintf(str, "%c%c%c%c%c%c%c%c", + m_t&0x80?'1':'0', + m_t&0x40?'1':'0', + m_t&0x20?'1':'0', + m_t&0x10?'H':'.', + m_t&0x08?'V':'.', + m_t&0x04?'Z':'.', + m_t&0x02?'I':'.', + m_t&0x01?'C':'.'); + break; + } +} + +void lh5801_cpu_device::device_reset() +{ + P = (m_program->read_byte(0xfffe)<<8) | m_program->read_byte(0xffff); + + m_idle=0; + + memset(m_ir_flipflop, 0, sizeof(m_ir_flipflop)); + memset(m_lines_status, 0, sizeof(m_lines_status)); +} + + +void lh5801_cpu_device::check_irq() +{ + if (m_ir_flipflop[0]) + { + //NMI interrupt + m_ir_flipflop[0] = 0; + lh5801_push(m_t); + m_t&=~IE; + lh5801_push_word(P); + P = (m_program->read_byte(0xfffc)<<8) | m_program->read_byte(0xfffd); + } + else if (m_ir_flipflop[1] && (m_t & IE)) + { + //counter interrupt (counter not yet implemented) + m_ir_flipflop[1] = 0; + lh5801_push(m_t); + m_t&=~IE; + lh5801_push_word(P); + P = (m_program->read_byte(0xfffa)<<8) | m_program->read_byte(0xfffb); + } + else if (m_ir_flipflop[2] && (m_t & IE)) + { + //MI interrupt + m_ir_flipflop[2] = 0; + lh5801_push(m_t); + m_t&=~IE; + lh5801_push_word(P); + P = (m_program->read_byte(0xfff8)<<8) | m_program->read_byte(0xfff9); + } +} + + +void lh5801_cpu_device::execute_run() +{ + do + { + check_irq(); + + if (m_idle) + m_icount = 0; + else + { + m_oldpc = P; + + debugger_instruction_hook(this, P); + lh5801_instruction(); + } + + } while (m_icount > 0); +} + +void lh5801_cpu_device::execute_set_input(int irqline, int state) +{ + switch( irqline) + { + case LH5801_LINE_MI: + if (m_lines_status[0] == CLEAR_LINE && state == ASSERT_LINE) + { + m_idle = 0; + m_ir_flipflop[2] = 1; + } + + m_lines_status[0] = state; + break; + case INPUT_LINE_NMI: + if (m_lines_status[1] == CLEAR_LINE && state == ASSERT_LINE) + { + m_idle = 0; + m_ir_flipflop[0] = 1; + } + + m_lines_status[1] = state; + break; + } +} + +offs_t lh5801_cpu_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( lh5801 ); + return CPU_DISASSEMBLE_NAME(lh5801)(this, buffer, pc, oprom, opram, options); +} diff --git a/src/devices/cpu/lh5801/lh5801.h b/src/devices/cpu/lh5801/lh5801.h new file mode 100644 index 00000000000..e5c6aa74690 --- /dev/null +++ b/src/devices/cpu/lh5801/lh5801.h @@ -0,0 +1,188 @@ +// license:BSD-3-Clause +// copyright-holders:Peter Trauner +/***************************************************************************** + * + * cpustate->h + * portable lh5801 emulator interface + * + * + *****************************************************************************/ +#pragma once + +#ifndef __LH5801_H__ +#define __LH5801_H__ + +/* +lh5801 + +little endian + +ph, pl p +sh, sl s + +xh, xl x +yh, yl y +uh, ul u + +a A + +0 0 0 H V Z IE C + +TM 9bit polynominal? + +pu pv disp flipflops + +bf flipflop (break key connected) + + me0, me1 chip select for 2 64kb memory blocks + +in0-in7 input pins + + mi maskable interrupt input (fff8/9) + timer fffa/b + nmi non .. (fffc/d) + reset fffe/f +e ? + + + +lh5811 chip +pa 8bit io +pb 8bit io +pc 8bit +*/ + + +// input lines +enum +{ + LH5801_LINE_MI //maskable interrupt +}; + + +#define MCFG_LH5801_IN(_devcb) \ + lh5801_cpu_device::set_in_func(*device, DEVCB_##_devcb); + + +class lh5801_cpu_device : public cpu_device +{ +public: + // construction/destruction + lh5801_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // static configuration helpers + template static devcb_base &set_in_func(device_t &device, _Object object) { return downcast(device).m_in_func.set_callback(object); } + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_execute_interface overrides + virtual UINT32 execute_min_cycles() const { return 2; } + virtual UINT32 execute_max_cycles() const { return 19; } + virtual UINT32 execute_input_lines() const { return 2; } + virtual UINT32 execute_default_irq_vector() const { return 0; } + virtual void execute_run(); + virtual void execute_set_input(int inputnum, int state); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const { return (spacenum == AS_PROGRAM) ? &m_program_config : ( (spacenum == AS_IO) ? &m_io_config : NULL ); } + + // device_state_interface overrides + void state_string_export(const device_state_entry &entry, std::string &str); + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const { return 1; } + virtual UINT32 disasm_max_opcode_bytes() const { return 5; } + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + +private: + address_space_config m_program_config; + address_space_config m_io_config; + + devcb_read8 m_in_func; + + address_space *m_program; //ME0 + address_space *m_io; //ME1 + direct_read_data *m_direct; + + PAIR m_s; + PAIR m_p; + PAIR m_u; + PAIR m_x; + PAIR m_y; + int m_tm; //9 bit + + UINT8 m_t, m_a; + + int m_bf; + int m_dp; + int m_pu; + int m_pv; + + UINT16 m_oldpc; + + int m_irq_state; + + UINT8 m_ir_flipflop[3]; //interrupt request flipflop: IR0, IR1, IR2 + int m_lines_status[2]; //MI and NMI lines status + + int m_idle; + int m_icount; + + void check_irq(); + void lh5801_instruction_fd(); + void lh5801_instruction(); + UINT8 lh5801_add_generic(int left, int right, int carry); + UINT16 lh5801_readop_word(); + void lh5801_adc(UINT8 data); + void lh5801_add_mem(address_space &space, int addr, UINT8 data); + void lh5801_adr(PAIR *reg); + void lh5801_sbc(UINT8 data); + void lh5801_cpa(UINT8 a, UINT8 b); + UINT8 lh5801_decimaladd_generic(int left, int right, int carry); + void lh5801_dca(UINT8 data); + void lh5801_dcs(UINT8 data); + void lh5801_and(UINT8 data); + void lh5801_and_mem(address_space &space, int addr, UINT8 data); + void lh5801_bit(UINT8 a, UINT8 b); + void lh5801_eor(UINT8 data); + void lh5801_ora(UINT8 data); + void lh5801_ora_mem(address_space &space, int addr, UINT8 data); + void lh5801_lda(UINT8 data); + void lh5801_lde(PAIR *reg); + void lh5801_sde(PAIR *reg); + void lh5801_lin(PAIR *reg); + void lh5801_sin(PAIR *reg); + void lh5801_dec(UINT8 *adr); + void lh5801_inc(UINT8 *adr); + void lh5801_pop(); + void lh5801_pop_word(PAIR *reg); + void lh5801_rtn(); + void lh5801_rti(); + void lh5801_push(UINT8 data); + void lh5801_push_word(UINT16 data); + void lh5801_jmp(UINT16 adr); + void lh5801_branch_plus(int doit); + void lh5801_branch_minus(int doit); + void lh5801_lop(); + void lh5801_sjp(); + void lh5801_vector(int doit, int nr); + void lh5801_aex(); + void lh5801_drl(address_space &space, int adr); + void lh5801_drr(address_space &space, int adr); + void lh5801_rol(); + void lh5801_ror(); + void lh5801_shl(); + void lh5801_shr(); + void lh5801_am(int value); + void lh5801_ita(); + +}; + + +extern const device_type LH5801; + + +#endif /* __LH5801_H__ */ diff --git a/src/devices/cpu/lr35902/lr35902.c b/src/devices/cpu/lr35902/lr35902.c new file mode 100644 index 00000000000..02cb785e1ff --- /dev/null +++ b/src/devices/cpu/lr35902/lr35902.c @@ -0,0 +1,354 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +/*************************************************************/ +/** **/ +/** lr35902.c **/ +/** **/ +/** This file contains implementation for the GameBoy CPU. **/ +/** See lr35902.h for the relevant definitions. Please, note**/ +/** that this code can not be used to emulate a generic Z80 **/ +/** because the GameBoy version of it differs from Z80 in **/ +/** many ways. **/ +/** **/ +/** Orginal cpu code (PlayBoy) Carsten Sorensen 1998 **/ +/** MESS modifications Hans de Goede 1998 **/ +/** Adapted to new cpuintrf Juergen Buchmueller 2000 **/ +/** Adapted to new cpuintrf Anthony Kruize 2002 **/ +/** Changed reset function to **/ +/** reset all registers instead **/ +/** of just AF. Wilbert Pol 2004 **/ +/** **/ +/** 1.1: **/ +/** Removed dependency on the mess gameboy driver **/ +/** **/ +/** 1.2: **/ +/** Fixed cycle count for taking an interrupt **/ +/** Fixed cycle count for BIT X,(HL) instructions **/ +/** Fixed flags in RRCA instruction **/ +/** Fixed DAA instruction **/ +/** Fixed flags in ADD SP,n8 instruction **/ +/** Fixed flags in LD HL,SP+n8 instruction **/ +/** **/ +/** 1.3: **/ +/** Improved triggering of the HALT bug **/ +/** Added 4 cycle penalty when leaving HALT state for **/ +/** newer versions of the cpu core **/ +/** **/ +/** 1.4: **/ +/** Split fetch and execute cycles. **/ +/** **/ +/*************************************************************/ + +#include "emu.h" +#include "debugger.h" +#include "lr35902.h" + +/* Flag bit definitions */ +enum lr35902_flag +{ + FLAG_C = 0x10, + FLAG_H = 0x20, + FLAG_N = 0x40, + FLAG_Z = 0x80 +}; + +#define IME 0x01 +#define HALTED 0x02 + + +//************************************************************************** +// LR35902 DEVICE +//************************************************************************** + +const device_type LR35902 = &device_creator; + + +lr35902_cpu_device::lr35902_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : cpu_device(mconfig, LR35902, "LR35902", tag, owner, clock, "lr35902", __FILE__) + , m_program_config("program", ENDIANNESS_LITTLE, 8, 16, 0) + , m_A(0) + , m_F(0) + , m_B(0) + , m_C(0) + , m_D(0) + , m_E(0) + , m_H(0) + , m_L(0) + , m_SP(0) + , m_PC(0) + , m_IE(0) + , m_IF(0) + , m_enable(0) + , m_has_halt_bug(false) + , m_timer_func(*this) + , m_incdec16_func(*this) +{ +} + + +/****************************************************************************/ +/* Memory functions */ +/****************************************************************************/ + +inline void lr35902_cpu_device::cycles_passed(UINT8 cycles) +{ + m_icount -= cycles / m_gb_speed; + m_timer_func( cycles ); +} + + +inline UINT8 lr35902_cpu_device::mem_read_byte( UINT16 addr ) +{ + UINT8 data = m_program->read_byte( addr ); + cycles_passed( 4 ); + return data; +} + + +inline void lr35902_cpu_device::mem_write_byte( UINT16 addr, UINT8 data ) +{ + m_program->write_byte( addr, data ); + cycles_passed( 4 ); +} + + +inline UINT16 lr35902_cpu_device::mem_read_word( UINT16 addr ) +{ + UINT16 data = mem_read_byte( addr ); + data |= ( mem_read_byte( addr + 1 ) << 8 ); + return data; +} + + +inline void lr35902_cpu_device::mem_write_word( UINT16 addr, UINT16 data ) +{ + mem_write_byte( addr, data & 0xFF ); + mem_write_byte( addr + 1, data >> 8 ); +} + + +void lr35902_cpu_device::device_start() +{ + m_device = this; + m_program = &space(AS_PROGRAM); + + // resolve callbacks + m_timer_func.resolve_safe(); + m_incdec16_func.resolve_safe(); + + // register for save states + save_item(NAME(m_A)); + save_item(NAME(m_F)); + save_item(NAME(m_B)); + save_item(NAME(m_C)); + save_item(NAME(m_D)); + save_item(NAME(m_E)); + save_item(NAME(m_H)); + save_item(NAME(m_L)); + save_item(NAME(m_PC)); + save_item(NAME(m_SP)); + save_item(NAME(m_IE)); + save_item(NAME(m_IF)); + save_item(NAME(m_irq_state)); + save_item(NAME(m_handle_ei_delay)); + save_item(NAME(m_execution_state)); + save_item(NAME(m_op)); + save_item(NAME(m_gb_speed)); + save_item(NAME(m_gb_speed_change_pending)); + save_item(NAME(m_enable)); + save_item(NAME(m_handle_halt_bug)); + + // Register state for debugger + state_add( LR35902_PC, "PC", m_PC ).callimport().callexport().formatstr("%04X"); + state_add( LR35902_SP, "SP", m_SP ).callimport().callexport().formatstr("%04X"); + state_add( LR35902_A, "A", m_A ).callimport().callexport().formatstr("%02X"); + state_add( LR35902_F, "F", m_F ).callimport().callexport().formatstr("%02X"); + state_add( LR35902_B, "B", m_B ).callimport().callexport().formatstr("%02X"); + state_add( LR35902_C, "C", m_C ).callimport().callexport().formatstr("%02X"); + state_add( LR35902_D, "D", m_D ).callimport().callexport().formatstr("%02X"); + state_add( LR35902_E, "E", m_E ).callimport().callexport().formatstr("%02X"); + state_add( LR35902_H, "H", m_H ).callimport().callexport().formatstr("%02X"); + state_add( LR35902_L, "L", m_L ).callimport().callexport().formatstr("%02X"); + state_add( LR35902_IRQ_STATE, "IRQ", m_enable ).callimport().callexport().formatstr("%02X"); + state_add( LR35902_IE, "IE", m_IE ).callimport().callexport().formatstr("%02X"); + state_add( LR35902_IF, "IF", m_IF ).callimport().callexport().formatstr("%02X"); + + state_add(STATE_GENPC, "curpc", m_PC).callimport().callexport().formatstr("%8s").noshow(); + state_add(STATE_GENFLAGS, "GENFLAGS", m_F).mask(0xf0).formatstr("%8s").noshow(); + + m_icountptr = &m_icount; +} + + +void lr35902_cpu_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + switch (entry.index()) + { + case LR35902_SPEED: + strprintf(str, "%02X", 0x7E | ((m_gb_speed - 1) << 7) | m_gb_speed_change_pending); + break; + + case STATE_GENFLAGS: + strprintf(str, "%c%c%c%c", + m_F & FLAG_Z ? 'Z' : '.', + m_F & FLAG_N ? 'N' : '.', + m_F & FLAG_H ? 'H' : '.', + m_F & FLAG_C ? 'C' : '.' + ); + break; + } +} + +void lr35902_cpu_device::device_reset() +{ + m_A = 0x00; + m_F = 0x00; + m_B = 0x00; + m_C = 0x00; + m_D = 0x00; + m_E = 0x00; + m_H = 0x00; + m_L = 0x00; + m_SP = 0x0000; + m_PC = 0x0000; + + m_enable = 0; + m_IE = 0; + m_IF = 0; + + m_execution_state = 0; + m_handle_halt_bug = false; + m_handle_ei_delay = false; + m_gb_speed_change_pending = 0; + m_gb_speed = 1; +} + + +offs_t lr35902_cpu_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( lr35902 ); + return CPU_DISASSEMBLE_NAME(lr35902)(this, buffer, pc, oprom, opram, options); +} + + +void lr35902_cpu_device::check_interrupts() +{ + UINT8 irq = m_IE & m_IF; + + /* Interrupts should be taken after the first instruction after an EI instruction */ + if (m_handle_ei_delay) { + m_handle_ei_delay = false; + return; + } + + /* + logerror("Attempting to process LR35902 Interrupt IRQ $%02X\n", irq); + logerror("Attempting to process LR35902 Interrupt IE $%02X\n", m_IE); + logerror("Attempting to process LR35902 Interrupt IF $%02X\n", m_IF); + */ + if (irq) + { + int irqline = 0; + /* + logerror("LR35902 Interrupt IRQ $%02X\n", irq); + */ + + for( ; irqline < 5; irqline++ ) + { + if( irq & (1< 0); +} + + +void lr35902_cpu_device::execute_set_input( int inptnum, int state ) +{ + m_irq_state = state; + if( state == ASSERT_LINE ) + { + m_IF |= (0x01 << inptnum); + } + else + { + m_IF &= ~(0x01 << inptnum); + } +} + + +UINT8 lr35902_cpu_device::get_speed() +{ + return 0x7E | ( ( m_gb_speed - 1 ) << 7 ) | m_gb_speed_change_pending; +} + + +void lr35902_cpu_device::set_speed( UINT8 speed_request ) +{ + m_gb_speed_change_pending = speed_request & 0x01; +} diff --git a/src/devices/cpu/lr35902/lr35902.h b/src/devices/cpu/lr35902/lr35902.h new file mode 100644 index 00000000000..509f06e77f5 --- /dev/null +++ b/src/devices/cpu/lr35902/lr35902.h @@ -0,0 +1,128 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +#pragma once + +#ifndef __LR35902_H__ +#define __LR35902_H__ + + +#define MCFG_LR35902_TIMER_CB(_devcb) \ + lr35902_cpu_device::set_timer_cb(*device, DEVCB_##_devcb); + +// The first release of this CPU has a bug where the programcounter +// is not incremented properly after an interrupt after the halt opcode. +// This was fixed in a newer revision. +#define MCFG_LR35902_HALT_BUG \ + lr35902_cpu_device::set_halt_bug(*device); + +// The GameBoy has a bug where OAM data gets corrupted if you inc/dec +// a 16-bit register in the $fe** region. +// note: oldval is in hiword, newval is in loword +#define MCFG_LR35902_INCDEC16_CB(_devcb) \ + lr35902_cpu_device::set_incdec16_cb(*device, DEVCB_##_devcb); + + +enum +{ + LR35902_PC=1, LR35902_SP, LR35902_A, LR35902_F, LR35902_B, LR35902_C, LR35902_D, LR35902_E, LR35902_H, LR35902_L, + LR35902_IRQ_STATE, + /* Pseudo registers to keep track of the interrupt statuses */ + LR35902_IE, LR35902_IF, + /* Pseudo register to change and check the cpu operating speed */ + LR35902_SPEED +}; + + +class lr35902_cpu_device : public cpu_device +{ +public: + // construction/destruction + lr35902_cpu_device(const machine_config &mconfig, const char *_tag, device_t *_owner, UINT32 _clock); + + // static configuration helpers + template static devcb_base &set_timer_cb(device_t &device, _Object object) { return downcast(device).m_timer_func.set_callback(object); } + template static devcb_base &set_incdec16_cb(device_t &device, _Object object) { return downcast(device).m_incdec16_func.set_callback(object); } + static void set_halt_bug(device_t &device) { downcast(device).m_has_halt_bug = true; } + + UINT8 get_speed(); + void set_speed( UINT8 speed_request ); + + UINT8 get_ie() { return m_IE; } + void set_ie( UINT8 data ) { m_IE = data; } + + UINT8 get_if() { return m_IF; } + void set_if( UINT8 data ) { m_IF = data; } + +protected: + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_execute_interface overrides + virtual UINT32 execute_min_cycles() const { return 1; } + virtual UINT32 execute_max_cycles() const { return 16; } + virtual UINT32 execute_input_lines() const { return 5; } + virtual void execute_run(); + virtual void execute_set_input(int inputnum, int state); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const { return (spacenum == AS_PROGRAM) ? &m_program_config : NULL; } + + // device_state_interface overrides + void state_string_export(const device_state_entry &entry, std::string &str); + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const { return 1; } + virtual UINT32 disasm_max_opcode_bytes() const { return 4; } + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + + inline void cycles_passed(UINT8 cycles); + inline UINT8 mem_read_byte(UINT16 addr); + inline void mem_write_byte(UINT16 addr, UINT8 data); + inline UINT16 mem_read_word(UINT16 addr); + inline void mem_write_word(UINT16 addr, UINT16 data); + inline void check_interrupts(); + + address_space_config m_program_config; + + UINT8 m_A; + UINT8 m_F; + UINT8 m_B; + UINT8 m_C; + UINT8 m_D; + UINT8 m_E; + UINT8 m_H; + UINT8 m_L; + + UINT16 m_SP; + UINT16 m_PC; + + /* Interrupt related */ + UINT8 m_IE; + UINT8 m_IF; + int m_irq_state; + bool m_handle_ei_delay; + lr35902_cpu_device *m_device; + address_space *m_program; + int m_icount; + + /* Fetch & execute related */ + int m_execution_state; + UINT8 m_op; + + /* Others */ + int m_gb_speed; + int m_gb_speed_change_pending; + int m_enable; + bool m_handle_halt_bug; + bool m_has_halt_bug; + + /* Callbacks */ + devcb_write8 m_timer_func; + devcb_write32 m_incdec16_func; +}; + +extern const device_type LR35902; + +#endif /* __LR35902_H__ */ diff --git a/src/devices/cpu/lr35902/lr35902d.c b/src/devices/cpu/lr35902/lr35902d.c new file mode 100644 index 00000000000..cf6d61bd7d6 --- /dev/null +++ b/src/devices/cpu/lr35902/lr35902d.c @@ -0,0 +1,277 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +/***************************************************************************** + * + * lr35902d.c + * Portable Sharp LR35902 disassembler + * + *****************************************************************************/ + +#include "emu.h" +#include "debugger.h" +#include "lr35902.h" + +enum e_mnemonics +{ + zADC, zADD, zAND, zBIT, zCALL, zCCF, zCP, + zCPL, zDAA, zDB, zDEC, zDI, zEI, zHLT, + zIN, zINC, zJP, zJR, zLD, zNOP, zOR, + zPOP, zPUSH, zRES, zRET, zRETI, zRL, zRLA, + zRLC, zRLCA, zRR, zRRA, zRRC, zRRCA, zRST, + zSBC, zSCF, zSET, zSLA, zSLL, zSRA, zSRL, + zSTOP, zSUB, zXOR, zSWAP +}; + +static const char *const s_mnemonic[] = +{ + "adc", "add", "and", "bit", "call","ccf", "cp", + "cpl", "daa", "db", "dec", "di", "ei", "halt", + "in", "inc", "jp", "jr", "ld", "nop", "or", + "pop", "push","res", "ret", "reti","rl", "rla", + "rlc", "rlca","rr", "rra", "rrc", "rrca","rst", + "sbc", "scf", "set", "sla", "sll", "sra", "srl", + "stop","sub", "xor", "swap" +}; + +#define _OVER DASMFLAG_STEP_OVER +#define _OUT DASMFLAG_STEP_OUT + +static const UINT32 s_flags[] = { + 0 ,0 ,0 ,0 ,_OVER,0 ,0 , + 0 ,0 ,0 ,0 ,0 ,0 ,_OVER, + 0 ,0 ,0 ,0 ,0 ,0 ,0 , + 0 ,0 ,0 ,_OUT ,_OUT ,0 ,0 , + 0 ,0 ,0 ,0 ,0 ,0 ,_OVER, + 0 ,0 ,0 ,0 ,0 ,0 ,0 , + _OVER,0 ,0 ,0 +}; + +struct lr35902dasm +{ + UINT8 mnemonic; + const char *arguments; +}; + +static const lr35902dasm mnemonic_cb[256] = { + {zRLC,"b"}, {zRLC,"c"}, {zRLC,"d"}, {zRLC,"e"}, + {zRLC,"h"}, {zRLC,"l"}, {zRLC,"(hl)"}, {zRLC,"a"}, + {zRRC,"b"}, {zRRC,"c"}, {zRRC,"d"}, {zRRC,"e"}, + {zRRC,"h"}, {zRRC,"l"}, {zRRC,"(hl)"}, {zRRC,"a"}, + {zRL,"b"}, {zRL,"c"}, {zRL,"d"}, {zRL,"e"}, + {zRL,"h"}, {zRL,"l"}, {zRL,"(hl)"}, {zRL,"a"}, + {zRR,"b"}, {zRR,"c"}, {zRR,"d"}, {zRR,"e"}, + {zRR,"h"}, {zRR,"l"}, {zRR,"(hl)"}, {zRR,"a"}, + {zSLA,"b"}, {zSLA,"c"}, {zSLA,"d"}, {zSLA,"e"}, + {zSLA,"h"}, {zSLA,"l"}, {zSLA,"(hl)"}, {zSLA,"a"}, + {zSRA,"b"}, {zSRA,"c"}, {zSRA,"d"}, {zSRA,"e"}, + {zSRA,"h"}, {zSRA,"l"}, {zSRA,"(hl)"}, {zSRA,"a"}, + {zSWAP,"b"}, {zSWAP,"c"}, {zSWAP,"d"}, {zSWAP,"e"}, + {zSWAP,"h"}, {zSWAP,"l"}, {zSWAP,"(hl)"}, {zSWAP,"a"}, + {zSRL,"b"}, {zSRL,"c"}, {zSRL,"d"}, {zSRL,"e"}, + {zSRL,"h"}, {zSRL,"l"}, {zSRL,"(hl)"}, {zSRL,"a"}, + {zBIT,"0,b"}, {zBIT,"0,c"}, {zBIT,"0,d"}, {zBIT,"0,e"}, + {zBIT,"0,h"}, {zBIT,"0,l"}, {zBIT,"0,(hl)"},{zBIT,"0,a"}, + {zBIT,"1,b"}, {zBIT,"1,c"}, {zBIT,"1,d"}, {zBIT,"1,e"}, + {zBIT,"1,h"}, {zBIT,"1,l"}, {zBIT,"1,(hl)"},{zBIT,"1,a"}, + {zBIT,"2,b"}, {zBIT,"2,c"}, {zBIT,"2,d"}, {zBIT,"2,e"}, + {zBIT,"2,h"}, {zBIT,"2,l"}, {zBIT,"2,(hl)"},{zBIT,"2,a"}, + {zBIT,"3,b"}, {zBIT,"3,c"}, {zBIT,"3,d"}, {zBIT,"3,e"}, + {zBIT,"3,h"}, {zBIT,"3,l"}, {zBIT,"3,(hl)"},{zBIT,"3,a"}, + {zBIT,"4,b"}, {zBIT,"4,c"}, {zBIT,"4,d"}, {zBIT,"4,e"}, + {zBIT,"4,h"}, {zBIT,"4,l"}, {zBIT,"4,(hl)"},{zBIT,"4,a"}, + {zBIT,"5,b"}, {zBIT,"5,c"}, {zBIT,"5,d"}, {zBIT,"5,e"}, + {zBIT,"5,h"}, {zBIT,"5,l"}, {zBIT,"5,(hl)"},{zBIT,"5,a"}, + {zBIT,"6,b"}, {zBIT,"6,c"}, {zBIT,"6,d"}, {zBIT,"6,e"}, + {zBIT,"6,h"}, {zBIT,"6,l"}, {zBIT,"6,(hl)"},{zBIT,"6,a"}, + {zBIT,"7,b"}, {zBIT,"7,c"}, {zBIT,"7,d"}, {zBIT,"7,e"}, + {zBIT,"7,h"}, {zBIT,"7,l"}, {zBIT,"7,(hl)"},{zBIT,"7,a"}, + {zRES,"0,b"}, {zRES,"0,c"}, {zRES,"0,d"}, {zRES,"0,e"}, + {zRES,"0,h"}, {zRES,"0,l"}, {zRES,"0,(hl)"},{zRES,"0,a"}, + {zRES,"1,b"}, {zRES,"1,c"}, {zRES,"1,d"}, {zRES,"1,e"}, + {zRES,"1,h"}, {zRES,"1,l"}, {zRES,"1,(hl)"},{zRES,"1,a"}, + {zRES,"2,b"}, {zRES,"2,c"}, {zRES,"2,d"}, {zRES,"2,e"}, + {zRES,"2,h"}, {zRES,"2,l"}, {zRES,"2,(hl)"},{zRES,"2,a"}, + {zRES,"3,b"}, {zRES,"3,c"}, {zRES,"3,d"}, {zRES,"3,e"}, + {zRES,"3,h"}, {zRES,"3,l"}, {zRES,"3,(hl)"},{zRES,"3,a"}, + {zRES,"4,b"}, {zRES,"4,c"}, {zRES,"4,d"}, {zRES,"4,e"}, + {zRES,"4,h"}, {zRES,"4,l"}, {zRES,"4,(hl)"},{zRES,"4,a"}, + {zRES,"5,b"}, {zRES,"5,c"}, {zRES,"5,d"}, {zRES,"5,e"}, + {zRES,"5,h"}, {zRES,"5,l"}, {zRES,"5,(hl)"},{zRES,"5,a"}, + {zRES,"6,b"}, {zRES,"6,c"}, {zRES,"6,d"}, {zRES,"6,e"}, + {zRES,"6,h"}, {zRES,"6,l"}, {zRES,"6,(hl)"},{zRES,"6,a"}, + {zRES,"7,b"}, {zRES,"7,c"}, {zRES,"7,d"}, {zRES,"7,e"}, + {zRES,"7,h"}, {zRES,"7,l"}, {zRES,"7,(hl)"},{zRES,"7,a"}, + {zSET,"0,b"}, {zSET,"0,c"}, {zSET,"0,d"}, {zSET,"0,e"}, + {zSET,"0,h"}, {zSET,"0,l"}, {zSET,"0,(hl)"},{zSET,"0,a"}, + {zSET,"1,b"}, {zSET,"1,c"}, {zSET,"1,d"}, {zSET,"1,e"}, + {zSET,"1,h"}, {zSET,"1,l"}, {zSET,"1,(hl)"},{zSET,"1,a"}, + {zSET,"2,b"}, {zSET,"2,c"}, {zSET,"2,d"}, {zSET,"2,e"}, + {zSET,"2,h"}, {zSET,"2,l"}, {zSET,"2,(hl)"},{zSET,"2,a"}, + {zSET,"3,b"}, {zSET,"3,c"}, {zSET,"3,d"}, {zSET,"3,e"}, + {zSET,"3,h"}, {zSET,"3,l"}, {zSET,"3,(hl)"},{zSET,"3,a"}, + {zSET,"4,b"}, {zSET,"4,c"}, {zSET,"4,d"}, {zSET,"4,e"}, + {zSET,"4,h"}, {zSET,"4,l"}, {zSET,"4,(hl)"},{zSET,"4,a"}, + {zSET,"5,b"}, {zSET,"5,c"}, {zSET,"5,d"}, {zSET,"5,e"}, + {zSET,"5,h"}, {zSET,"5,l"}, {zSET,"5,(hl)"},{zSET,"5,a"}, + {zSET,"6,b"}, {zSET,"6,c"}, {zSET,"6,d"}, {zSET,"6,e"}, + {zSET,"6,h"}, {zSET,"6,l"}, {zSET,"6,(hl)"},{zSET,"6,a"}, + {zSET,"7,b"}, {zSET,"7,c"}, {zSET,"7,d"}, {zSET,"7,e"}, + {zSET,"7,h"}, {zSET,"7,l"}, {zSET,"7,(hl)"},{zSET,"7,a"} +}; + +static const lr35902dasm mnemonic_main[256]= { + {zNOP,0}, {zLD,"bc,N"}, {zLD,"(bc),a"}, {zINC,"bc"}, + {zINC,"b"}, {zDEC,"b"}, {zLD,"b,B"}, {zRLCA,0}, + {zLD,"(W),sp"}, {zADD,"hl,bc"}, {zLD,"a,(bc)"}, {zDEC,"bc"}, + {zINC,"c"}, {zDEC,"c"}, {zLD,"c,B"}, {zRRCA,0}, + {zSTOP,0}, {zLD,"de,N"}, {zLD,"(de),a"}, {zINC,"de"}, + {zINC,"d"}, {zDEC,"d"}, {zLD,"d,B"}, {zRLA,0}, + {zJR,"O"}, {zADD,"hl,de"}, {zLD,"a,(de)"}, {zDEC,"de"}, + {zINC,"e"}, {zDEC,"e"}, {zLD,"e,B"}, {zRRA,0}, + {zJR,"nz,O"}, {zLD,"hl,N"}, {zLD,"(hl+),a"},{zINC,"hl"}, + {zINC,"h"}, {zDEC,"h"}, {zLD,"h,B"}, {zDAA,0}, + {zJR,"z,O"}, {zADD,"hl,hl"}, {zLD,"a,(hl+)"},{zDEC,"hl"}, + {zINC,"l"}, {zDEC,"l"}, {zLD,"l,B"}, {zCPL,0}, + {zJR,"nc,O"}, {zLD,"sp,N"}, {zLD,"(hl-),a"},{zINC,"sp"}, + {zINC,"(hl)"}, {zDEC,"(hl)"}, {zLD,"(hl),B"}, {zSCF,0}, + {zJR,"c,O"}, {zADD,"hl,sp"}, {zLD,"a,(hl-)"},{zDEC,"sp"}, + {zINC,"a"}, {zDEC,"a"}, {zLD,"a,B"}, {zCCF,0}, + {zLD,"b,b"}, {zLD,"b,c"}, {zLD,"b,d"}, {zLD,"b,e"}, + {zLD,"b,h"}, {zLD,"b,l"}, {zLD,"b,(hl)"}, {zLD,"b,a"}, + {zLD,"c,b"}, {zLD,"c,c"}, {zLD,"c,d"}, {zLD,"c,e"}, + {zLD,"c,h"}, {zLD,"c,l"}, {zLD,"c,(hl)"}, {zLD,"c,a"}, + {zLD,"d,b"}, {zLD,"d,c"}, {zLD,"d,d"}, {zLD,"d,e"}, + {zLD,"d,h"}, {zLD,"d,l"}, {zLD,"d,(hl)"}, {zLD,"d,a"}, + {zLD,"e,b"}, {zLD,"e,c"}, {zLD,"e,d"}, {zLD,"e,e"}, + {zLD,"e,h"}, {zLD,"e,l"}, {zLD,"e,(hl)"}, {zLD,"e,a"}, + {zLD,"h,b"}, {zLD,"h,c"}, {zLD,"h,d"}, {zLD,"h,e"}, + {zLD,"h,h"}, {zLD,"h,l"}, {zLD,"h,(hl)"}, {zLD,"h,a"}, + {zLD,"l,b"}, {zLD,"l,c"}, {zLD,"l,d"}, {zLD,"l,e"}, + {zLD,"l,h"}, {zLD,"l,l"}, {zLD,"l,(hl)"}, {zLD,"l,a"}, + {zLD,"(hl),b"}, {zLD,"(hl),c"}, {zLD,"(hl),d"}, {zLD,"(hl),e"}, + {zLD,"(hl),h"}, {zLD,"(hl),l"}, {zHLT,0}, {zLD,"(hl),a"}, + {zLD,"a,b"}, {zLD,"a,c"}, {zLD,"a,d"}, {zLD,"a,e"}, + {zLD,"a,h"}, {zLD,"a,l"}, {zLD,"a,(hl)"}, {zLD,"a,a"}, + {zADD,"a,b"}, {zADD,"a,c"}, {zADD,"a,d"}, {zADD,"a,e"}, + {zADD,"a,h"}, {zADD,"a,l"}, {zADD,"a,(hl)"},{zADD,"a,a"}, + {zADC,"a,b"}, {zADC,"a,c"}, {zADC,"a,d"}, {zADC,"a,e"}, + {zADC,"a,h"}, {zADC,"a,l"}, {zADC,"a,(hl)"},{zADC,"a,a"}, + {zSUB,"b"}, {zSUB,"c"}, {zSUB,"d"}, {zSUB,"e"}, + {zSUB,"h"}, {zSUB,"l"}, {zSUB,"(hl)"}, {zSUB,"a"}, + {zSBC,"a,b"}, {zSBC,"a,c"}, {zSBC,"a,d"}, {zSBC,"a,e"}, + {zSBC,"a,h"}, {zSBC,"a,l"}, {zSBC,"a,(hl)"},{zSBC,"a,a"}, + {zAND,"b"}, {zAND,"c"}, {zAND,"d"}, {zAND,"e"}, + {zAND,"h"}, {zAND,"l"}, {zAND,"(hl)"}, {zAND,"a"}, + {zXOR,"b"}, {zXOR,"c"}, {zXOR,"d"}, {zXOR,"e"}, + {zXOR,"h"}, {zXOR,"l"}, {zXOR,"(hl)"}, {zXOR,"a"}, + {zOR,"b"}, {zOR,"c"}, {zOR,"d"}, {zOR,"e"}, + {zOR,"h"}, {zOR,"l"}, {zOR,"(hl)"}, {zOR,"a"}, + {zCP,"b"}, {zCP,"c"}, {zCP,"d"}, {zCP,"e"}, + {zCP,"h"}, {zCP,"l"}, {zCP,"(hl)"}, {zCP,"a"}, + {zRET,"nz"}, {zPOP,"bc"}, {zJP,"nz,A"}, {zJP,"A"}, + {zCALL,"nz,A"}, {zPUSH,"bc"}, {zADD,"a,B"}, {zRST,"V"}, + {zRET,"z"}, {zRET,0}, {zJP,"z,A"}, {zDB,"cb"}, + {zCALL,"z,A"}, {zCALL,"A"}, {zADC,"a,B"}, {zRST,"V"}, + {zRET,"nc"}, {zPOP,"de"}, {zJP,"nc,A"}, {zDB,"d3"}, + {zCALL,"nc,A"}, {zPUSH,"de"}, {zSUB,"B"}, {zRST,"V"}, + {zRET,"c"}, {zRETI,0}, {zJP,"c,A"}, {zDB,"db"}, + {zCALL,"c,A"}, {zDB,"dd"}, {zSBC,"a,B"}, {zRST,"V"}, + {zLD,"(F),a"}, {zPOP,"hl"}, {zLD,"(C),a"}, {zDB,"e3"}, + {zDB,"e4"}, {zPUSH,"hl"}, {zAND,"B"}, {zRST,"V"}, + {zADD,"SP,B"}, {zJP,"(hl)"}, {zLD,"(W),a"}, {zDB,"eb"}, + {zDB,"ec"}, {zDB,"ed"}, {zXOR,"B"}, {zRST,"V"}, + {zLD,"a,(F)"}, {zPOP,"af"}, {zLD,"a,(C)"}, {zDI,0}, + {zDB,"f4"}, {zPUSH,"af"}, {zOR,"B"}, {zRST,"V"}, + {zLD,"hl,sp+B"},{zLD,"sp,hl"}, {zLD,"a,(W)"}, {zEI,0}, + {zDB,"fc"}, {zDB,"fd"}, {zCP,"B"}, {zRST,"V"} +}; + +/**************************************************************************** + * Disassemble opcode at PC and return number of bytes it takes + ****************************************************************************/ + +CPU_DISASSEMBLE( lr35902 ) +{ + const lr35902dasm *d; + const char /* *symbol,*/ *src; + char *dst; + INT8 offset = 0; + UINT8 op, op1; + UINT16 ea = 0; + int pos = 0; + + dst = buffer; + //symbol = NULL; + + op = oprom[pos++]; + op1 = 0; /* keep GCC happy */ + + if( op == 0xcb ) { + op = oprom[pos++]; + d = &mnemonic_cb[op]; + } else { + d = &mnemonic_main[op]; + } + + if( d->arguments ) { + dst += sprintf(dst, "%-4s ", s_mnemonic[d->mnemonic]); + src = d->arguments; + while( *src ) { + switch( *src ) { + case '?': /* illegal opcode */ + dst += sprintf( dst, "$%02X,$%02X", op, op1); + break; + case 'A': + ea = opram[pos] + ( opram[pos+1] << 8); + pos += 2; + dst += sprintf( dst, "$%04X", ea ); + break; + case 'B': /* Byte op arg */ + ea = opram[pos++]; + dst += sprintf( dst, "$%02X", ea ); + break; + case '(': /* Memory byte at (...) */ + *dst++ = *src; + if( !strncmp( src, "(bc)", 4) ) { + } else if( !strncmp( src, "(de)", 4) ) { + } else if( !strncmp( src, "(hl)", 4) ) { + } else if( !strncmp( src, "(sp)", 4) ) { + } else if( !strncmp( src, "(F)", 3) ) { + ea = 0xFF00 + opram[pos++]; + dst += sprintf( dst, "$%02X", ea ); + src++; + } else if( !strncmp( src, "(C)", 3) ) { + dst += sprintf( dst, "$FF00+c" ); + src++; + } + break; + case 'N': /* Immediate 16 bit */ + ea = opram[pos] + ( opram[pos+1] << 8 ); + pos += 2; + dst += sprintf( dst, "$%04X", ea ); + break; + case 'O': /* Offset relative to PC */ + offset = (INT8) opram[pos++]; + dst += sprintf( dst, "$%04X", pc + offset + 2 ); + break; + case 'V': /* Restart vector */ + ea = op & 0x38; + dst += sprintf( dst, "$%02X", ea ); + break; + case 'W': /* Memory address word */ + ea = opram[pos] + ( opram[pos+1] << 8 ); + pos += 2; + dst += sprintf( dst, "$%04X", ea ); + break; + default: + *dst++ = *src; + } + src++; + } + *dst = '\0'; + } else { + dst += sprintf(dst, "%s", s_mnemonic[d->mnemonic]); + } + + return pos | s_flags[d->mnemonic] | DASMFLAG_SUPPORTED; +} diff --git a/src/devices/cpu/lr35902/opc_cb.inc b/src/devices/cpu/lr35902/opc_cb.inc new file mode 100644 index 00000000000..ace58d019e7 --- /dev/null +++ b/src/devices/cpu/lr35902/opc_cb.inc @@ -0,0 +1,1539 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +#define RLC_8BIT(x) \ +{ \ + register UINT8 f; \ + (x)=(UINT8)(((x)<<1)|((x)>>7)); \ + if( (x)&1 ) \ + f=FLAG_C; \ + else \ + f=0; \ + if( (x)==0 ) \ + f|=FLAG_Z; \ + m_F=f; \ +} + +#define RL_8BIT(x) \ +{ \ + register UINT8 r; \ + r=((x)&0x80)?FLAG_C:0; \ + (x)=(UINT8)(((x)<<1)|((m_F&FLAG_C)?1:0)); \ + if( (x)==0 ) \ + r|=FLAG_Z; \ + m_F=r; \ +} + +#define RRC_8BIT(x) \ +{ \ + register UINT8 f; \ + (x)=(UINT8)(((x)>>1)|((x)<<7)); \ + if( (x)&0x80 ) \ + f=FLAG_C; \ + else \ + f=0; \ + if( (x)==0 ) \ + f|=FLAG_Z; \ + m_F=f; \ +} + +#define RR_8BIT(x) \ +{ \ + register UINT8 r; \ + r=((x)&1)?FLAG_C:0; \ + (x)=(UINT8)(((x)>>1)|((m_F&FLAG_C)?0x80:0)); \ + if( (x)==0 ) \ + r|=FLAG_Z; \ + m_F=r; \ +} + +#define SLA_8BIT(x) \ +{ \ + register UINT8 f; \ + if( (x)&0x80 ) \ + f=FLAG_C; \ + else \ + f=0; \ + (x)<<=1; \ + if( (x)==0 ) \ + f|=FLAG_Z; \ + m_F=f; \ +} + +#define SRA_8BIT(x) \ +{ \ + register UINT8 f; \ + if( (x)&1 ) \ + f=FLAG_C; \ + else \ + f=0; \ + (x)=(UINT8)(((char)(x))>>1); \ + if( (x)==0 ) \ + f|=FLAG_Z; \ + m_F=f; \ +} + +#define SWAP_8BIT(x) \ + (x)=(UINT8)(((x)>>4)|((x)<<4)); \ + if( (x)==0 ) \ + m_F=FLAG_Z; \ + else \ + m_F=0; + + +#define SRL_8BIT(x) \ +{ \ + register UINT8 f; \ + if( (x)&1 ) \ + f=FLAG_C; \ + else \ + f=0; \ + (x)>>=1; \ + if( (x)==0 ) \ + f|=FLAG_Z; \ + m_F=f; \ +} + +#define BIT_8BIT(n,x) \ + if( (x)&(1<<(n)) ) \ + m_F=(UINT8)(FLAG_H|(m_F&FLAG_C)); \ + else \ + m_F=(UINT8)(FLAG_Z|FLAG_H|(m_F&FLAG_C)); + +#define RES_8BIT(n,x) (x)&=~(1<<(n)); + +#define SET_8BIT(n,x) (x)|=(1<<(n)); + +/**********************************************************/ + +case 0x00: + /* RLC B */ + + RLC_8BIT (m_B) + break; +case 0x01: + /* RLC C */ + + RLC_8BIT (m_C) + break; +case 0x02: + /* RLC D */ + + RLC_8BIT (m_D) + break; +case 0x03: + /* RLC E */ + + RLC_8BIT (m_E) + break; +case 0x04: + /* RLC H */ + + RLC_8BIT (m_H) + break; +case 0x05: + /* RLC L */ + + RLC_8BIT (m_L) + break; +case 0x06: + /* RLC (HL) */ + { + UINT16 addr = ( m_H << 8 ) | m_L; + + x = mem_read_byte( addr ); + RLC_8BIT (x) + mem_write_byte( addr, x ); + } + break; +case 0x07: + /* RLC A */ + + RLC_8BIT (m_A) + break; +case 0x08: + /* RRC B */ + + RRC_8BIT (m_B) + break; +case 0x09: + /* RRC C */ + + RRC_8BIT (m_C) + break; +case 0x0A: + /* RRC D */ + + RRC_8BIT (m_D) + break; +case 0x0B: + /* RRC E */ + + RRC_8BIT (m_E) + break; +case 0x0C: + /* RRC H */ + + RRC_8BIT (m_H) + break; +case 0x0D: + /* RRC L */ + + RRC_8BIT (m_L) + break; +case 0x0E: + /* RRC (HL) */ + { + UINT16 addr = ( m_H << 8 ) | m_L; + + x = mem_read_byte( addr); + RRC_8BIT (x) + mem_write_byte( addr, x); + } + break; +case 0x0F: + /* RRC A */ + + RRC_8BIT (m_A) + break; +case 0x10: + /* RL B */ + + RL_8BIT (m_B) + break; +case 0x11: + /* RL C */ + + RL_8BIT (m_C) + break; +case 0x12: + /* RL D */ + + RL_8BIT (m_D) + break; +case 0x13: + /* RL E */ + + RL_8BIT (m_E) + break; +case 0x14: + /* RL H */ + + RL_8BIT (m_H) + break; +case 0x15: + /* RL L */ + + RL_8BIT (m_L) + break; +case 0x16: + /* RL (HL) */ + { + UINT16 addr = ( m_H << 8 ) | m_L; + + x = mem_read_byte( addr); + RL_8BIT (x) + mem_write_byte( addr, x); + } + break; +case 0x17: + /* RL A */ + + RL_8BIT (m_A) + break; +case 0x18: + /* RR B */ + + RR_8BIT (m_B) + break; +case 0x19: + /* RR C */ + + RR_8BIT (m_C) + break; +case 0x1A: + /* RR D */ + + RR_8BIT (m_D) + break; +case 0x1B: + /* RR E */ + + RR_8BIT (m_E) + break; +case 0x1C: + /* RR H */ + + RR_8BIT (m_H) + break; +case 0x1D: + /* RR L */ + + RR_8BIT (m_L) + break; +case 0x1E: + /* RR (HL) */ + { + UINT16 addr = ( m_H << 8 ) | m_L; + + x = mem_read_byte( addr); + RR_8BIT (x) + mem_write_byte( addr, x); + } + break; +case 0x1F: + /* RR A */ + + RR_8BIT (m_A) + break; +case 0x20: + /* SLA B */ + + SLA_8BIT (m_B) + break; +case 0x21: + /* SLA C */ + + SLA_8BIT (m_C) + break; +case 0x22: + /* SLA D */ + + SLA_8BIT (m_D) + break; +case 0x23: + /* SLA E */ + + SLA_8BIT (m_E) + break; +case 0x24: + /* SLA H */ + + SLA_8BIT (m_H) + break; +case 0x25: + /* SLA L */ + + SLA_8BIT (m_L) + break; +case 0x26: + /* SLA (HL) */ + { + UINT16 addr = ( m_H << 8 ) | m_L; + + x = mem_read_byte( addr); + SLA_8BIT (x) + mem_write_byte( addr, x); + } + break; +case 0x27: + /* SLA A */ + + SLA_8BIT (m_A) + break; +case 0x28: + /* SRA B */ + + SRA_8BIT (m_B) + break; +case 0x29: + /* SRA C */ + + SRA_8BIT (m_C) + break; +case 0x2A: + /* SRA D */ + + SRA_8BIT (m_D) + break; +case 0x2B: + /* SRA E */ + + SRA_8BIT (m_E) + break; +case 0x2C: + /* SRA H */ + + SRA_8BIT (m_H) + break; +case 0x2D: + /* SRA L */ + + SRA_8BIT (m_L) + break; +case 0x2E: + /* SRA (HL) */ + { + UINT16 addr = ( m_H << 8 ) | m_L; + + x = mem_read_byte( addr); + SRA_8BIT (x) + mem_write_byte( addr, x); + } + break; +case 0x2F: + /* SRA A */ + + SRA_8BIT (m_A) + break; +case 0x30: + /* SWAP B */ + + SWAP_8BIT (m_B) + break; +case 0x31: + /* SWAP C */ + + SWAP_8BIT (m_C) + break; +case 0x32: + /* SWAP D */ + + SWAP_8BIT (m_D) + break; +case 0x33: + /* SWAP E */ + + SWAP_8BIT (m_E) + break; +case 0x34: + /* SWAP H */ + + SWAP_8BIT (m_H) + break; +case 0x35: + /* SWAP L */ + + SWAP_8BIT (m_L) + break; +case 0x36: + /* SWAP (HL) */ + { + UINT16 addr = ( m_H << 8 ) | m_L; + + x = mem_read_byte( addr); + SWAP_8BIT (x) + mem_write_byte( addr, x); + } + break; +case 0x37: + /* SWAP A */ + + SWAP_8BIT (m_A) + break; +case 0x38: + /* SRL B */ + + SRL_8BIT (m_B) + break; +case 0x39: + /* SRL C */ + + SRL_8BIT (m_C) + break; +case 0x3A: + /* SRL D */ + + SRL_8BIT (m_D) + break; +case 0x3B: + /* SRL E */ + + SRL_8BIT (m_E) + break; +case 0x3C: + /* SRL H */ + + SRL_8BIT (m_H) + break; +case 0x3D: + /* SRL L */ + + SRL_8BIT (m_L) + break; +case 0x3E: + /* SRL (HL) */ + { + UINT16 addr = ( m_H << 8 ) | m_L; + + x = mem_read_byte( addr); + SRL_8BIT (x) + mem_write_byte( addr, x); + } + break; +case 0x3F: + /* SRL A */ + + SRL_8BIT (m_A) + break; +case 0x40: + /* BIT 0,B */ + + BIT_8BIT (0, m_B) + break; +case 0x41: + /* BIT 0,C */ + + BIT_8BIT (0, m_C) + break; +case 0x42: + /* BIT 0,D */ + + BIT_8BIT (0, m_D) + break; +case 0x43: + /* BIT 0,E */ + + BIT_8BIT (0, m_E) + break; +case 0x44: + /* BIT 0,H */ + + BIT_8BIT (0, m_H) + break; +case 0x45: + /* BIT 0,L */ + + BIT_8BIT (0, m_L) + break; +case 0x46: + /* BIT 0,(HL) */ + { + UINT16 addr = ( m_H << 8 ) | m_L; + + x = mem_read_byte( addr); + BIT_8BIT (0, x) + } + break; +case 0x47: + /* BIT 0,A */ + + BIT_8BIT (0, m_A) + break; +case 0x48: + /* BIT 1,B */ + + BIT_8BIT (1, m_B) + break; +case 0x49: + /* BIT 1,C */ + + BIT_8BIT (1, m_C) + break; +case 0x4A: + /* BIT 1,D */ + + BIT_8BIT (1, m_D) + break; +case 0x4B: + /* BIT 1,E */ + + BIT_8BIT (1, m_E) + break; +case 0x4C: + /* BIT 1,H */ + + BIT_8BIT (1, m_H) + break; +case 0x4D: + /* BIT 1,L */ + + BIT_8BIT (1, m_L) + break; +case 0x4E: + /* BIT 1,(HL) */ + { + UINT16 addr = ( m_H << 8 ) | m_L; + + x = mem_read_byte( addr); + BIT_8BIT (1, x) + } + break; +case 0x4F: + /* BIT 1,A */ + + BIT_8BIT (1, m_A) + break; +case 0x50: + /* BIT 2,B */ + + BIT_8BIT (2, m_B) + break; +case 0x51: + /* BIT 2,C */ + + BIT_8BIT (2, m_C) + break; +case 0x52: + /* BIT 2,D */ + + BIT_8BIT (2, m_D) + break; +case 0x53: + /* BIT 2,E */ + + BIT_8BIT (2, m_E) + break; +case 0x54: + /* BIT 2,H */ + + BIT_8BIT (2, m_H) + break; +case 0x55: + /* BIT 2,L */ + + BIT_8BIT (2, m_L) + break; +case 0x56: + /* BIT 2,(HL) */ + { + UINT16 addr = ( m_H << 8 ) | m_L; + + x = mem_read_byte( addr); + BIT_8BIT (2, x) + } + break; +case 0x57: + /* BIT 2,A */ + + BIT_8BIT (2, m_A) + break; +case 0x58: + /* BIT 3,B */ + + BIT_8BIT (3, m_B) + break; +case 0x59: + /* BIT 3,C */ + + BIT_8BIT (3, m_C) + break; +case 0x5A: + /* BIT 3,D */ + + BIT_8BIT (3, m_D) + break; +case 0x5B: + /* BIT 3,E */ + + BIT_8BIT (3, m_E) + break; +case 0x5C: + /* BIT 3,H */ + + BIT_8BIT (3, m_H) + break; +case 0x5D: + /* BIT 3,L */ + + BIT_8BIT (3, m_L) + break; +case 0x5E: + /* BIT 3,(HL) */ + { + UINT16 addr = ( m_H << 8 ) | m_L; + + x = mem_read_byte( addr); + BIT_8BIT (3, x) + } + break; +case 0x5F: + /* BIT 3,A */ + + BIT_8BIT (3, m_A) + break; +case 0x60: + /* BIT 4,B */ + + BIT_8BIT (4, m_B) + break; +case 0x61: + /* BIT 4,C */ + + BIT_8BIT (4, m_C) + break; +case 0x62: + /* BIT 4,D */ + + BIT_8BIT (4, m_D) + break; +case 0x63: + /* BIT 4,E */ + + BIT_8BIT (4, m_E) + break; +case 0x64: + /* BIT 4,H */ + + BIT_8BIT (4, m_H) + break; +case 0x65: + /* BIT 4,L */ + + BIT_8BIT (4, m_L) + break; +case 0x66: + /* BIT 4,(HL) */ + { + UINT16 addr = ( m_H << 8 ) | m_L; + + x = mem_read_byte( addr); + BIT_8BIT (4, x) + } + break; +case 0x67: + /* BIT 4,A */ + + BIT_8BIT (4, m_A) + break; +case 0x68: + /* BIT 5,B */ + + BIT_8BIT (5, m_B) + break; +case 0x69: + /* BIT 5,C */ + + BIT_8BIT (5, m_C) + break; +case 0x6A: + /* BIT 5,D */ + + BIT_8BIT (5, m_D) + break; +case 0x6B: + /* BIT 5,E */ + + BIT_8BIT (5, m_E) + break; +case 0x6C: + /* BIT 5,H */ + + BIT_8BIT (5, m_H) + break; +case 0x6D: + /* BIT 5,L */ + + BIT_8BIT (5, m_L) + break; +case 0x6E: + /* BIT 5,(HL) */ + { + UINT16 addr = ( m_H << 8 ) | m_L; + + x = mem_read_byte( addr); + BIT_8BIT (5, x) + } + break; +case 0x6F: + /* BIT 5,A */ + + BIT_8BIT (5, m_A) + break; +case 0x70: + /* BIT 6,B */ + + BIT_8BIT (6, m_B) + break; +case 0x71: + /* BIT 6,C */ + + BIT_8BIT (6, m_C) + break; +case 0x72: + /* BIT 6,D */ + + BIT_8BIT (6, m_D) + break; +case 0x73: + /* BIT 6,E */ + + BIT_8BIT (6, m_E) + break; +case 0x74: + /* BIT 6,H */ + + BIT_8BIT (6, m_H) + break; +case 0x75: + /* BIT 6,L */ + + BIT_8BIT (6, m_L) + break; +case 0x76: + /* BIT 6,(HL) */ + { + UINT16 addr = ( m_H << 8 ) | m_L; + + x = mem_read_byte( addr); + BIT_8BIT (6, x) + } + break; +case 0x77: + /* BIT 6,A */ + + BIT_8BIT (6, m_A) + break; +case 0x78: + /* BIT 7,B */ + + BIT_8BIT (7, m_B) + break; +case 0x79: + /* BIT 7,C */ + + BIT_8BIT (7, m_C) + break; +case 0x7A: + /* BIT 7,D */ + + BIT_8BIT (7, m_D) + break; +case 0x7B: + /* BIT 7,E */ + + BIT_8BIT (7, m_E) + break; +case 0x7C: + /* BIT 7,H */ + + BIT_8BIT (7, m_H) + break; +case 0x7D: + /* BIT 7,L */ + + BIT_8BIT (7, m_L) + break; +case 0x7E: + /* BIT 7,(HL) */ + { + UINT16 addr = ( m_H << 8 ) | m_L; + + x = mem_read_byte( addr); + BIT_8BIT (7, x) + } + break; +case 0x7F: + /* BIT 7,A */ + + BIT_8BIT (7, m_A) + break; +case 0x80: + /* RES 0,B */ + + RES_8BIT (0, m_B) + break; +case 0x81: + /* RES 0,C */ + + RES_8BIT (0, m_C) + break; +case 0x82: + /* RES 0,D */ + + RES_8BIT (0, m_D) + break; +case 0x83: + /* RES 0,E */ + + RES_8BIT (0, m_E) + break; +case 0x84: + /* RES 0,H */ + + RES_8BIT (0, m_H) + break; +case 0x85: + /* RES 0,L */ + + RES_8BIT (0, m_L) + break; +case 0x86: + /* RES 0,(HL) */ + { + UINT16 addr = ( m_H << 8 ) | m_L; + + x = mem_read_byte( addr); + RES_8BIT (0, x) + mem_write_byte( addr, x); + } + break; +case 0x87: + /* RES 0,A */ + + RES_8BIT (0, m_A) + break; +case 0x88: + /* RES 1,B */ + + RES_8BIT (1, m_B) + break; +case 0x89: + /* RES 1,C */ + + RES_8BIT (1, m_C) + break; +case 0x8A: + /* RES 1,D */ + + RES_8BIT (1, m_D) + break; +case 0x8B: + /* RES 1,E */ + + RES_8BIT (1, m_E) + break; +case 0x8C: + /* RES 1,H */ + + RES_8BIT (1, m_H) + break; +case 0x8D: + /* RES 1,L */ + + RES_8BIT (1, m_L) + break; +case 0x8E: + /* RES 1,(HL) */ + { + UINT16 addr = ( m_H << 8 ) | m_L; + + x = mem_read_byte( addr); + RES_8BIT (1, x) + mem_write_byte( addr, x); + } + break; +case 0x8F: + /* RES 1,A */ + + RES_8BIT (1, m_A) + break; +case 0x90: + /* RES 2,B */ + + RES_8BIT (2, m_B) + break; +case 0x91: + /* RES 2,C */ + + RES_8BIT (2, m_C) + break; +case 0x92: + /* RES 2,D */ + + RES_8BIT (2, m_D) + break; +case 0x93: + /* RES 2,E */ + + RES_8BIT (2, m_E) + break; +case 0x94: + /* RES 2,H */ + + RES_8BIT (2, m_H) + break; +case 0x95: + /* RES 2,L */ + + RES_8BIT (2, m_L) + break; +case 0x96: + /* RES 2,(HL) */ + { + UINT16 addr = ( m_H << 8 ) | m_L; + + x = mem_read_byte( addr); + RES_8BIT (2, x) + mem_write_byte( addr, x); + } + break; +case 0x97: + /* RES 2,A */ + + RES_8BIT (2, m_A) + break; +case 0x98: + /* RES 3,B */ + + RES_8BIT (3, m_B) + break; +case 0x99: + /* RES 3,C */ + + RES_8BIT (3, m_C) + break; +case 0x9A: + /* RES 3,D */ + + RES_8BIT (3, m_D) + break; +case 0x9B: + /* RES 3,E */ + + RES_8BIT (3, m_E) + break; +case 0x9C: + /* RES 3,H */ + + RES_8BIT (3, m_H) + break; +case 0x9D: + /* RES 3,L */ + + RES_8BIT (3, m_L) + break; +case 0x9E: + /* RES 3,(HL) */ + { + UINT16 addr = ( m_H << 8 ) | m_L; + + x = mem_read_byte( addr); + RES_8BIT (3, x) + mem_write_byte( addr, x); + } + break; +case 0x9F: + /* RES 3,A */ + + RES_8BIT (3, m_A) + break; +case 0xA0: + /* RES 4,B */ + + RES_8BIT (4, m_B) + break; +case 0xA1: + /* RES 4,C */ + + RES_8BIT (4, m_C) + break; +case 0xA2: + /* RES 4,D */ + + RES_8BIT (4, m_D) + break; +case 0xA3: + /* RES 4,E */ + + RES_8BIT (4, m_E) + break; +case 0xA4: + /* RES 4,H */ + + RES_8BIT (4, m_H) + break; +case 0xA5: + /* RES 4,L */ + + RES_8BIT (4, m_L) + break; +case 0xA6: + /* RES 4,(HL) */ + { + UINT16 addr = ( m_H << 8 ) | m_L; + + x = mem_read_byte( addr); + RES_8BIT (4, x) + mem_write_byte( addr, x); + } + break; +case 0xA7: + /* RES 4,A */ + + RES_8BIT (4, m_A) + break; +case 0xA8: + /* RES 5,B */ + + RES_8BIT (5, m_B) + break; +case 0xA9: + /* RES 5,C */ + + RES_8BIT (5, m_C) + break; +case 0xAA: + /* RES 5,D */ + + RES_8BIT (5, m_D) + break; +case 0xAB: + /* RES 5,E */ + + RES_8BIT (5, m_E) + break; +case 0xAC: + /* RES 5,H */ + + RES_8BIT (5, m_H) + break; +case 0xAD: + /* RES 5,L */ + + RES_8BIT (5, m_L) + break; +case 0xAE: + /* RES 5,(HL) */ + { + UINT16 addr = ( m_H << 8 ) | m_L; + + x = mem_read_byte( addr); + RES_8BIT (5, x) + mem_write_byte( addr, x); + } + break; +case 0xAF: + /* RES 5,A */ + + RES_8BIT (5, m_A) + break; +case 0xB0: + /* RES 6,B */ + + RES_8BIT (6, m_B) + break; +case 0xB1: + /* RES 6,C */ + + RES_8BIT (6, m_C) + break; +case 0xB2: + /* RES 6,D */ + + RES_8BIT (6, m_D) + break; +case 0xB3: + /* RES 6,E */ + + RES_8BIT (6, m_E) + break; +case 0xB4: + /* RES 6,H */ + + RES_8BIT (6, m_H) + break; +case 0xB5: + /* RES 6,L */ + + RES_8BIT (6, m_L) + break; +case 0xB6: + /* RES 6,(HL) */ + { + UINT16 addr = ( m_H << 8 ) | m_L; + + x = mem_read_byte( addr); + RES_8BIT (6, x) + mem_write_byte( addr, x); + } + break; +case 0xB7: + /* RES 6,A */ + + RES_8BIT (6, m_A) + break; +case 0xB8: + /* RES 7,B */ + + RES_8BIT (7, m_B) + break; +case 0xB9: + /* RES 7,C */ + + RES_8BIT (7, m_C) + break; +case 0xBA: + /* RES 7,D */ + + RES_8BIT (7, m_D) + break; +case 0xBB: + /* RES 7,E */ + + RES_8BIT (7, m_E) + break; +case 0xBC: + /* RES 7,H */ + + RES_8BIT (7, m_H) + break; +case 0xBD: + /* RES 7,L */ + + RES_8BIT (7, m_L) + break; +case 0xBE: + /* RES 7,(HL) */ + { + UINT16 addr = ( m_H << 8 ) | m_L; + + x = mem_read_byte( addr); + RES_8BIT (7, x) + mem_write_byte( addr, x); + } + break; +case 0xBF: + /* RES 7,A */ + + RES_8BIT (7, m_A) + break; +case 0xC0: + /* SET 0,B */ + + SET_8BIT (0, m_B) + break; +case 0xC1: + /* SET 0,C */ + + SET_8BIT (0, m_C) + break; +case 0xC2: + /* SET 0,D */ + + SET_8BIT (0, m_D) + break; +case 0xC3: + /* SET 0,E */ + + SET_8BIT (0, m_E) + break; +case 0xC4: + /* SET 0,H */ + + SET_8BIT (0, m_H) + break; +case 0xC5: + /* SET 0,L */ + + SET_8BIT (0, m_L) + break; +case 0xC6: + /* SET 0,(HL) */ + { + UINT16 addr = ( m_H << 8 ) | m_L; + + x = mem_read_byte( addr); + SET_8BIT (0, x) + mem_write_byte( addr, x); + } + break; +case 0xC7: + /* SET 0,A */ + + SET_8BIT (0, m_A) + break; +case 0xC8: + /* SET 1,B */ + + SET_8BIT (1, m_B) + break; +case 0xC9: + /* SET 1,C */ + + SET_8BIT (1, m_C) + break; +case 0xCA: + /* SET 1,D */ + + SET_8BIT (1, m_D) + break; +case 0xCB: + /* SET 1,E */ + + SET_8BIT (1, m_E) + break; +case 0xCC: + /* SET 1,H */ + + SET_8BIT (1, m_H) + break; +case 0xCD: + /* SET 1,L */ + + SET_8BIT (1, m_L) + break; +case 0xCE: + /* SET 1,(HL) */ + { + UINT16 addr = ( m_H << 8 ) | m_L; + + x = mem_read_byte( addr); + SET_8BIT (1, x) + mem_write_byte( addr, x); + } + break; +case 0xCF: + /* SET 1,A */ + + SET_8BIT (1, m_A) + break; +case 0xD0: + /* SET 2,B */ + + SET_8BIT (2, m_B) + break; +case 0xD1: + /* SET 2,C */ + + SET_8BIT (2, m_C) + break; +case 0xD2: + /* SET 2,D */ + + SET_8BIT (2, m_D) + break; +case 0xD3: + /* SET 2,E */ + + SET_8BIT (2, m_E) + break; +case 0xD4: + /* SET 2,H */ + + SET_8BIT (2, m_H) + break; +case 0xD5: + /* SET 2,L */ + + SET_8BIT (2, m_L) + break; +case 0xD6: + /* SET 2,(HL) */ + { + UINT16 addr = ( m_H << 8 ) | m_L; + + x = mem_read_byte( addr); + SET_8BIT (2, x) + mem_write_byte( addr, x); + } + break; +case 0xD7: + /* SET 2,A */ + + SET_8BIT (2, m_A) + break; +case 0xD8: + /* SET 3,B */ + + SET_8BIT (3, m_B) + break; +case 0xD9: + /* SET 3,C */ + + SET_8BIT (3, m_C) + break; +case 0xDA: + /* SET 3,D */ + + SET_8BIT (3, m_D) + break; +case 0xDB: + /* SET 3,E */ + + SET_8BIT (3, m_E) + break; +case 0xDC: + /* SET 3,H */ + + SET_8BIT (3, m_H) + break; +case 0xDD: + /* SET 3,L */ + + SET_8BIT (3, m_L) + break; +case 0xDE: + /* SET 3,(HL) */ + { + UINT16 addr = ( m_H << 8 ) | m_L; + + x = mem_read_byte( addr); + SET_8BIT (3, x) + mem_write_byte( addr, x); + } + break; +case 0xDF: + /* SET 3,A */ + + SET_8BIT (3, m_A) + break; +case 0xE0: + /* SET 4,B */ + + SET_8BIT (4, m_B) + break; +case 0xE1: + /* SET 4,C */ + + SET_8BIT (4, m_C) + break; +case 0xE2: + /* SET 4,D */ + + SET_8BIT (4, m_D) + break; +case 0xE3: + /* SET 4,E */ + + SET_8BIT (4, m_E) + break; +case 0xE4: + /* SET 4,H */ + + SET_8BIT (4, m_H) + break; +case 0xE5: + /* SET 4,L */ + + SET_8BIT (4, m_L) + break; +case 0xE6: + /* SET 4,(HL) */ + { + UINT16 addr = ( m_H << 8 ) | m_L; + + x = mem_read_byte( addr); + SET_8BIT (4, x) + mem_write_byte( addr, x); + } + break; +case 0xE7: + /* SET 4,A */ + + SET_8BIT (4, m_A) + break; +case 0xE8: + /* SET 5,B */ + + SET_8BIT (5, m_B) + break; +case 0xE9: + /* SET 5,C */ + + SET_8BIT (5, m_C) + break; +case 0xEA: + /* SET 5,D */ + + SET_8BIT (5, m_D) + break; +case 0xEB: + /* SET 5,E */ + + SET_8BIT (5, m_E) + break; +case 0xEC: + /* SET 5,H */ + + SET_8BIT (5, m_H) + break; +case 0xED: + /* SET 5,L */ + + SET_8BIT (5, m_L) + break; +case 0xEE: + /* SET 5,(HL) */ + { + UINT16 addr = ( m_H << 8 ) | m_L; + + x = mem_read_byte( addr); + SET_8BIT (5, x) + mem_write_byte( addr, x); + } + break; +case 0xEF: + /* SET 5,A */ + + SET_8BIT (5, m_A) + break; +case 0xF0: + /* SET 6,B */ + + SET_8BIT (6, m_B) + break; +case 0xF1: + /* SET 6,C */ + + SET_8BIT (6, m_C) + break; +case 0xF2: + /* SET 6,D */ + + SET_8BIT (6, m_D) + break; +case 0xF3: + /* SET 6,E */ + + SET_8BIT (6, m_E) + break; +case 0xF4: + /* SET 6,H */ + + SET_8BIT (6, m_H) + break; +case 0xF5: + /* SET 6,L */ + + SET_8BIT (6, m_L) + break; +case 0xF6: + /* SET 6,(HL) */ + { + UINT16 addr = ( m_H << 8 ) | m_L; + + x = mem_read_byte( addr); + SET_8BIT (6, x) + mem_write_byte( addr, x); + } + break; +case 0xF7: + /* SET 6,A */ + + SET_8BIT (6, m_A) + break; +case 0xF8: + /* SET 7,B */ + + SET_8BIT (7, m_B) + break; +case 0xF9: + /* SET 7,C */ + + SET_8BIT (7, m_C) + break; +case 0xFA: + /* SET 7,D */ + + SET_8BIT (7, m_D) + break; +case 0xFB: + /* SET 7,E */ + + SET_8BIT (7, m_E) + break; +case 0xFC: + /* SET 7,H */ + + SET_8BIT (7, m_H) + break; +case 0xFD: + /* SET 7,L */ + + SET_8BIT (7, m_L) + break; +case 0xFE: + /* SET 7,(HL) */ + { + UINT16 addr = ( m_H << 8 ) | m_L; + + x = mem_read_byte( addr); + SET_8BIT (7, x) + mem_write_byte( addr, x); + } + break; +case 0xFF: + /* SET 7,A */ + + SET_8BIT (7, m_A) + break; diff --git a/src/devices/cpu/lr35902/opc_main.inc b/src/devices/cpu/lr35902/opc_main.inc new file mode 100644 index 00000000000..c551bb3d351 --- /dev/null +++ b/src/devices/cpu/lr35902/opc_main.inc @@ -0,0 +1,1429 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +#define INC_8BIT(x) \ +{ \ + register UINT8 r,f; \ + x++; \ + r=(x); \ + f=(UINT8)(m_F&FLAG_C); \ + if( r==0 ) f|=FLAG_Z; \ + if( (r&0xF)==0 ) f|=FLAG_H; \ + m_F=f; \ +} + +#define DEC_8BIT(x) \ +{ \ + register UINT8 r,f; \ + x--; \ + r=(x); \ + f=(UINT8)((m_F&FLAG_C)|FLAG_N); \ + if( r==0 ) f|=FLAG_Z; \ + if( (r&0xF)==0xF ) f|=FLAG_H; \ + m_F=f; \ +} + +#define INC_16BIT(x,y) \ +{ \ + register UINT16 r = x << 8 | y; \ + if (++y == 0) x++; \ + m_incdec16_func(r << 16 | x << 8 | y); \ +} + +#define DEC_16BIT(x,y) \ +{ \ + register UINT16 r = x << 8 | y; \ + if (--y == 0xff) x--; \ + m_incdec16_func(r << 16 | x << 8 | y); \ +} + +#define ADD_HL_RR(x) \ +{ \ + register UINT32 r1,r2; \ + register UINT8 f; \ + r1=((m_H<<8)|m_L)+(x); \ + r2=(((m_H<<8)|m_L)&0xFFF)+((x)&0xFFF); \ + f=(UINT8)(m_F&FLAG_Z); \ + if( r1>0xFFFF ) f|=FLAG_C; \ + if( r2>0x0FFF ) f|=FLAG_H; \ + m_L = r1; \ + m_H = r1 >> 8; \ + m_F=f; \ +} + +#define ADD_A_X(x) \ +{ \ + register UINT16 r1,r2; \ + register UINT8 f; \ + r1=(UINT16)((m_A&0xF)+((x)&0xF)); \ + r2=(UINT16)(m_A+(x)); \ + m_A=(UINT8)r2; \ + if( ((UINT8)r2)==0 ) f=FLAG_Z; \ + else f=0; \ + if( r2>0xFF ) f|=FLAG_C; \ + if( r1>0xF ) f|=FLAG_H; \ + m_F=f; \ +} + +#define SUB_A_X(x) \ +{ \ + register UINT16 r1,r2; \ + register UINT8 f; \ + r1=(UINT16)((m_A&0xF)-((x)&0xF)); \ + r2=(UINT16)(m_A-(x)); \ + m_A=(UINT8)r2; \ + if( ((UINT8)r2)==0 ) f=FLAG_N|FLAG_Z; \ + else f=FLAG_N; \ + if( r2>0xFF ) f|=FLAG_C; \ + if( r1>0xF ) f|=FLAG_H; \ + m_F=f; \ +} + +#define CP_A_X(x) \ +{ \ + register UINT16 r1,r2; \ + register UINT8 f; \ + r1=(UINT16)((m_A&0xF)-((x)&0xF)); \ + r2=(UINT16)(m_A-(x)); \ + if( ((UINT8)r2)==0 ) f=FLAG_N|FLAG_Z; \ + else f=FLAG_N; \ + if( r2>0xFF ) f|=FLAG_C; \ + if( r1>0xF ) f|=FLAG_H; \ + m_F=f; \ +} + +#define SBC_A_X(x) \ +{ \ + register UINT16 r1,r2; \ + register UINT8 f; \ + r1=(UINT16)((m_A&0xF)-((x)&0xF)-((m_F&FLAG_C)?1:0)); \ + r2=(UINT16)(m_A-(x)-((m_F&FLAG_C)?1:0)); \ + m_A=(UINT8)r2; \ + if( ((UINT8)r2)==0 ) f=FLAG_N|FLAG_Z; \ + else f=FLAG_N; \ + if( r2>0xFF ) f|=FLAG_C; \ + if( r1>0xF ) f|=FLAG_H; \ + m_F=f; \ +} + +#define ADC_A_X(x) \ +{ \ + register UINT16 r1,r2; \ + register UINT8 f; \ + r1=(UINT16)((m_A&0xF)+((x)&0xF)+((m_F&FLAG_C)?1:0)); \ + r2=(UINT16)(m_A+(x)+((m_F&FLAG_C)?1:0)); \ + if( (m_A=(UINT8)r2)==0 ) f=FLAG_Z; \ + else f=0; \ + if( r2>0xFF ) f|=FLAG_C; \ + if( r1>0xF ) f|=FLAG_H; \ + m_F=f; \ +} + +#define AND_A_X(x) \ + if( (m_A&=(x))==0 ) \ + m_F=FLAG_H|FLAG_Z; \ + else \ + m_F=FLAG_H; + +#define XOR_A_X(x) \ + if( (m_A^=(x))==0 ) \ + m_F=FLAG_Z; \ + else \ + m_F=0; + +#define OR_A_X(x) \ + if( (m_A|=(x))==0 ) \ + m_F=FLAG_Z; \ + else \ + m_F=0; + +#define POP(x,y) \ + y = mem_read_byte( m_SP++ ); \ + x = mem_read_byte( m_SP++ ); + +#define PUSH(x,y) \ + m_SP--; \ + mem_write_byte( m_SP, x ); \ + m_SP--; \ + mem_write_byte( m_SP, y ); + +/**********************************************************/ + +case 0x00: /* NOP */ + break; + +case 0x01: /* LD BC,n16 */ + m_C = mem_read_byte( m_PC++ ); + m_B = mem_read_byte( m_PC++ ); + break; + +case 0x02: /* LD (BC),A */ + mem_write_byte( ( m_B << 8 ) | m_C, m_A ); + break; + +case 0x03: /* INC BC */ + INC_16BIT(m_B, m_C); + cycles_passed( 4 ); + break; + +case 0x04: /* INC B */ + INC_8BIT (m_B) + break; + +case 0x05: /* DEC B */ + DEC_8BIT (m_B) + break; + +case 0x06: /* LD B,n8 */ + m_B = mem_read_byte( m_PC++ ); + break; + +case 0x07: /* RLCA */ + + m_A = (UINT8) ((m_A << 1) | (m_A >> 7)); + if (m_A & 1) + { + m_F = FLAG_C; + } + else + { + m_F = 0; + } + break; + +case 0x08: /* LD (n16),SP */ + mem_write_word (mem_read_word (m_PC), m_SP); + m_PC += 2; + break; + +case 0x09: /* ADD HL,BC */ + ADD_HL_RR ((m_B<<8)|m_C) + cycles_passed( 4 ); + break; +case 0x0A: /* LD A,(BC) */ + + m_A = mem_read_byte ( (m_B<<8)|m_C ); + break; +case 0x0B: /* DEC BC */ + DEC_16BIT(m_B, m_C); + cycles_passed( 4 ); + break; +case 0x0C: /* INC C */ + + INC_8BIT (m_C) + break; +case 0x0D: /* DEC C */ + + DEC_8BIT (m_C) + break; +case 0x0E: /* LD C,n8 */ + + m_C = mem_read_byte ( m_PC++ ); + break; +case 0x0F: /* RRCA */ + + m_A = (UINT8) ((m_A >> 1) | (m_A << 7)); + m_F = 0; + if (m_A & 0x80) + { + m_F |= FLAG_C; + } + break; +case 0x10: /* STOP */ + if ( m_gb_speed_change_pending ) { + m_gb_speed = ( m_gb_speed == 1 ) ? 2 : 1; + } + m_gb_speed_change_pending = 0; + break; +case 0x11: /* LD DE,n16 */ + m_E = mem_read_byte( m_PC++ ); + m_D = mem_read_byte( m_PC++ ); + break; +case 0x12: /* LD (DE),A */ + mem_write_byte( ( m_D << 8 ) | m_E, m_A ); + break; +case 0x13: /* INC DE */ + INC_16BIT(m_D, m_E); + cycles_passed( 4 ); + break; +case 0x14: /* INC D */ + + INC_8BIT (m_D) + break; +case 0x15: /* DEC D */ + + DEC_8BIT (m_D) + break; +case 0x16: /* LD D,n8 */ + + m_D = mem_read_byte ( m_PC++ ); + break; +case 0x17: /* RLA */ + + x = (m_A & 0x80) ? FLAG_C : 0; + + m_A = (UINT8) ((m_A << 1) | ((m_F & FLAG_C) ? 1 : 0)); + m_F = x; + break; +case 0x18: /* JR n8 */ + { + INT8 offset; + + offset = mem_read_byte( m_PC++ ); + m_PC += offset; + cycles_passed( 4 ); + } + break; +case 0x19: /* ADD HL,DE */ + ADD_HL_RR (( m_D << 8 ) | m_E) + cycles_passed( 4 ); + break; +case 0x1A: /* LD A,(DE) */ + + m_A = mem_read_byte( ( m_D << 8 ) | m_E ); + break; +case 0x1B: /* DEC DE */ + DEC_16BIT(m_D, m_E); + cycles_passed( 4 ); + break; +case 0x1C: /* INC E */ + + INC_8BIT (m_E) + break; +case 0x1D: /* DEC E */ + + DEC_8BIT (m_E) + break; +case 0x1E: /* LD E,n8 */ + + m_E = mem_read_byte( m_PC++ ); + break; +case 0x1F: /* RRA */ + + x = (m_A & 1) ? FLAG_C : 0; + + m_A = (UINT8) ((m_A >> 1) | ((m_F & FLAG_C) ? 0x80 : 0)); + m_F = x; + break; +case 0x20: /* JR NZ,n8 */ + { + INT8 offset = mem_read_byte( m_PC++ ); + if (! (m_F & FLAG_Z) ) + { + m_PC += offset; + cycles_passed( 4 ); + } + } + break; +case 0x21: /* LD HL,n16 */ + m_L = mem_read_byte( m_PC++ ); + m_H = mem_read_byte( m_PC++ ); + break; +case 0x22: /* LD (HL+),A */ + mem_write_byte( (m_H << 8 ) | m_L, m_A ); + INC_16BIT(m_H, m_L); + break; +case 0x23: /* INC HL */ + INC_16BIT(m_H, m_L); + cycles_passed( 4 ); + break; +case 0x24: /* INC H */ + + INC_8BIT (m_H); + break; +case 0x25: /* DEC H */ + + DEC_8BIT (m_H); + break; +case 0x26: /* LD H,n8 */ + + m_H = mem_read_byte( m_PC++ ); + break; +case 0x27: /* DAA */ + { + int tmp = m_A; + + if ( ! ( m_F & FLAG_N ) ) { + if ( ( m_F & FLAG_H ) || ( tmp & 0x0F ) > 9 ) + tmp += 6; + if ( ( m_F & FLAG_C ) || tmp > 0x9F ) + tmp += 0x60; + } else { + if ( m_F & FLAG_H ) { + tmp -= 6; + if ( ! ( m_F & FLAG_C ) ) + tmp &= 0xFF; + } + if ( m_F & FLAG_C ) + tmp -= 0x60; + } + m_F &= ~ ( FLAG_H | FLAG_Z ); + if ( tmp & 0x100 ) + m_F |= FLAG_C; + m_A = tmp & 0xFF; + if ( ! m_A ) + m_F |= FLAG_Z; + } + break; +case 0x28: /* JR Z,n8 */ + { + INT8 offset = mem_read_byte( m_PC++ ); + + if (m_F & FLAG_Z) + { + m_PC += offset; + cycles_passed( 4 ); + } + } + break; +case 0x29: /* ADD HL,HL */ + ADD_HL_RR ((m_H << 8 ) | m_L) + cycles_passed( 4 ); + break; +case 0x2A: /* LD A,(HL+) */ + m_A = mem_read_byte( ( m_H << 8 ) | m_L ); + INC_16BIT(m_H, m_L); + break; +case 0x2B: /* DEC HL */ + DEC_16BIT(m_H, m_L); + cycles_passed( 4 ); + break; +case 0x2C: /* INC L */ + + INC_8BIT (m_L); + break; +case 0x2D: /* DEC L */ + + DEC_8BIT (m_L); + break; +case 0x2E: /* LD L,n8 */ + + m_L = mem_read_byte( m_PC++ ); + break; +case 0x2F: /* CPL */ + + m_A = ~m_A; + m_F |= FLAG_N | FLAG_H; + break; +case 0x30: /* JR NC,n8 */ + { + INT8 offset = mem_read_byte( m_PC++ ); + + if ( ! (m_F & FLAG_C) ) + { + m_PC += offset; + cycles_passed( 4 ); + } + } + break; +case 0x31: /* LD SP,n16 */ + + m_SP = mem_read_word( m_PC ); + m_PC += 2; + break; +case 0x32: /* LD (HL-),A */ + mem_write_byte( ( m_H << 8 ) | m_L, m_A ); + DEC_16BIT(m_H, m_L); + break; +case 0x33: /* INC SP */ + m_SP += 1; + cycles_passed( 4 ); + break; +case 0x34: /* INC (HL) */ + { + UINT16 addr = ( m_H << 8 ) | m_L; + register UINT8 r, f; + + f = (UINT8) (m_F & FLAG_C); + r = mem_read_byte( addr ); + r += 1; + mem_write_byte( addr, r ); + + if (r == 0) + f |= FLAG_Z; + + if ((r & 0xF) == 0) + f |= FLAG_H; + + m_F = f; + } + break; +case 0x35: /* DEC (HL) */ + { + UINT16 addr = ( m_H << 8 ) | m_L; + register UINT8 r, f; + + f = (UINT8) ((m_F & FLAG_C) | FLAG_N); + r = mem_read_byte( addr ); + r -= 1; + mem_write_byte( addr, r ); + + if (r == 0) + f |= FLAG_Z; + + if ((r & 0xF) == 0xF) + f |= FLAG_H; + + m_F = f; + } + break; +case 0x36: /* LD (HL),n8 */ + { + UINT8 v = mem_read_byte( m_PC++ ); + mem_write_byte( ( m_H << 8 ) | m_L, v ); + } + break; +case 0x37: /* SCF */ + + m_F = (UINT8) ((m_F & FLAG_Z) | FLAG_C); + break; +case 0x38: /* JR C,n8 */ + { + INT8 offset = mem_read_byte( m_PC++ ); + + if (m_F & FLAG_C) + { + m_PC += offset; + cycles_passed( 4 ); + } + } + break; +case 0x39: /* ADD HL,SP */ + ADD_HL_RR (m_SP) + cycles_passed( 4 ); + break; +case 0x3A: /* LD A,(HL-) */ + m_A = mem_read_byte( ( m_H << 8 ) | m_L ); + DEC_16BIT(m_H, m_L); + break; +case 0x3B: /* DEC SP */ + m_SP -= 1; + cycles_passed( 4 ); + break; +case 0x3C: /* INC A */ + + INC_8BIT (m_A); + break; +case 0x3D: /* DEC A */ + + DEC_8BIT (m_A); + break; +case 0x3E: /* LD A,n8 */ + + m_A = mem_read_byte( m_PC++ ); + break; +case 0x3F: /* CCF */ + + m_F = (UINT8) ((m_F & FLAG_Z) | ((m_F & FLAG_C) ? 0 : FLAG_C)); + break; +case 0x40: /* LD B,B */ + break; +case 0x41: /* LD B,C */ + + m_B = m_C; + break; +case 0x42: /* LD B,D */ + + m_B = m_D; + break; +case 0x43: /* LD B,E */ + + m_B = m_E; + break; +case 0x44: /* LD B,H */ + + m_B = m_H; + break; +case 0x45: /* LD B,L */ + + m_B = m_L; + break; +case 0x46: /* LD B,(HL) */ + m_B = mem_read_byte( ( m_H << 8 ) | m_L) ; + break; + +case 0x47: /* LD B,A */ + + m_B = m_A; + break; +case 0x48: /* LD C,B */ + + m_C = m_B; + break; +case 0x49: /* LD C,C */ + break; +case 0x4A: /* LD C,D */ + + m_C = m_D; + break; +case 0x4B: /* LD C,E */ + + m_C = m_E; + break; +case 0x4C: /* LD C,H */ + + m_C = m_H; + break; +case 0x4D: /* LD C,L */ + + m_C = m_L; + break; + +case 0x4E: /* LD C,(HL) */ + m_C = mem_read_byte( ( m_H << 8 ) | m_L ); + break; + +case 0x4F: /* LD C,A */ + + m_C = m_A; + break; +case 0x50: /* LD D,B */ + + m_D = m_B; + break; +case 0x51: /* LD D,C */ + + m_D = m_C; + break; +case 0x52: /* LD D,D */ + break; +case 0x53: /* LD D,E */ + + m_D = m_E; + break; +case 0x54: /* LD D,H */ + + m_D = m_H; + break; +case 0x55: /* LD D,L */ + + m_D = m_L; + break; +case 0x56: /* LD D,(HL) */ + + m_D = mem_read_byte( ( m_H << 8 ) | m_L ); + break; +case 0x57: /* LD D,A */ + + m_D = m_A; + break; +case 0x58: /* LD E,B */ + + m_E = m_B; + break; +case 0x59: /* LD E,C */ + + m_E = m_C; + break; +case 0x5A: /* LD E,D */ + + m_E = m_D; + break; +case 0x5B: /* LD E,E */ + break; +case 0x5C: /* LD E,H */ + + m_E = m_H; + break; +case 0x5D: /* LD E,L */ + + m_E = m_L; + break; +case 0x5E: /* LD E,(HL) */ + + m_E = mem_read_byte( ( m_H << 8 ) | m_L ); + break; +case 0x5F: /* LD E,A */ + + m_E = m_A; + break; +case 0x60: /* LD H,B */ + + m_H = m_B; + break; +case 0x61: /* LD H,C */ + + m_H = m_C; + break; +case 0x62: /* LD H,D */ + + m_H = m_D; + break; +case 0x63: /* LD H,E */ + + m_H = m_E; + break; +case 0x64: /* LD H,H */ + break; +case 0x65: /* LD H,L */ + + m_H = m_L; + break; +case 0x66: /* LD H,(HL) */ + + m_H = mem_read_byte( ( m_H << 8 ) | m_L ); + break; +case 0x67: /* LD H,A */ + + m_H = m_A; + break; +case 0x68: /* LD L,B */ + + m_L = m_B; + break; +case 0x69: /* LD L,C */ + + m_L = m_C; + break; +case 0x6A: /* LD L,D */ + m_L = m_D; + break; +case 0x6B: /* LD L,E */ + + m_L = m_E; + break; +case 0x6C: /* LD L,H */ + + m_L = m_H; + break; +case 0x6D: /* LD L,L */ + break; +case 0x6E: /* LD L,(HL) */ + + m_L = mem_read_byte( ( m_H << 8 ) | m_L ); + break; +case 0x6F: /* LD L,A */ + + m_L = m_A; + break; + +case 0x70: /* LD (HL),B */ + mem_write_byte( ( m_H << 8 ) | m_L, m_B ); + break; + +case 0x71: /* LD (HL),C */ + mem_write_byte( ( m_H << 8 ) | m_L, m_C ); + break; +case 0x72: /* LD (HL),D */ + mem_write_byte( ( m_H << 8 ) | m_L, m_D ); + break; +case 0x73: /* LD (HL),E */ + mem_write_byte( ( m_H << 8 ) | m_L, m_E ); + break; +case 0x74: /* LD (HL),H */ + mem_write_byte( ( m_H << 8 ) | m_L, m_H ); + break; +case 0x75: /* LD (HL),L */ + mem_write_byte( ( m_H << 8 ) | m_L, m_L ); + break; +case 0x76: /* HALT */ + m_enable |= HALTED; + m_PC--; + break; +case 0x77: /* LD (HL),A */ + mem_write_byte( ( m_H << 8 ) | m_L, m_A ); + break; +case 0x78: /* LD A,B */ + + m_A = m_B; + break; +case 0x79: /* LD A,C */ + + m_A = m_C; + break; +case 0x7A: /* LD A,D */ + + m_A = m_D; + break; +case 0x7B: /* LD A,E */ + + m_A = m_E; + break; +case 0x7C: /* LD A,H */ + + m_A = m_H; + break; +case 0x7D: /* LD A,L */ + + m_A = m_L; + break; +case 0x7E: /* LD A,(HL) */ + + m_A = mem_read_byte( ( m_H << 8 ) | m_L ); + break; +case 0x7F: /* LD A,A */ + break; +case 0x80: /* ADD A,B */ + + ADD_A_X (m_B) + break; +case 0x81: /* ADD A,C */ + + ADD_A_X (m_C) + break; +case 0x82: /* ADD A,D */ + + ADD_A_X (m_D) + break; +case 0x83: /* ADD A,E */ + + ADD_A_X (m_E) + break; +case 0x84: /* ADD A,H */ + + ADD_A_X (m_H) + break; +case 0x85: /* ADD A,L */ + + ADD_A_X (m_L) + break; +case 0x86: /* ADD A,(HL) */ + + x = mem_read_byte( ( m_H << 8 ) | m_L ); + + ADD_A_X (x) + break; +case 0x87: /* ADD A,A */ + + ADD_A_X (m_A) + break; +case 0x88: /* ADC A,B */ + + ADC_A_X (m_B) + break; +case 0x89: /* ADC A,C */ + + ADC_A_X (m_C) + break; +case 0x8A: /* ADC A,D */ + + ADC_A_X (m_D) + break; +case 0x8B: /* ADC A,E */ + + ADC_A_X (m_E) + break; +case 0x8C: /* ADC A,H */ + + ADC_A_X (m_H) + break; +case 0x8D: /* ADC A,L */ + + ADC_A_X (m_L) + break; +case 0x8E: /* ADC A,(HL) */ + + x = mem_read_byte( ( m_H << 8 ) | m_L ); + + ADC_A_X (x) + break; +case 0x8F: /* ADC A,A */ + + ADC_A_X (m_A) + break; +case 0x90: /* SUB A,B */ + + SUB_A_X (m_B) + break; +case 0x91: /* SUB A,C */ + + SUB_A_X (m_C) + break; +case 0x92: /* SUB A,D */ + + SUB_A_X (m_D) + break; +case 0x93: /* SUB A,E */ + + SUB_A_X (m_E) + break; +case 0x94: /* SUB A,H */ + + SUB_A_X (m_H) + break; +case 0x95: /* SUB A,L */ + + SUB_A_X (m_L) + break; +case 0x96: /* SUB A,(HL) */ + + + x = mem_read_byte( ( m_H << 8 ) | m_L ); + + SUB_A_X (x) + break; +case 0x97: /* SUB A,A */ + + SUB_A_X (m_A) + break; +case 0x98: /* SBC A,B */ + + SBC_A_X (m_B) + break; +case 0x99: /* SBC A,C */ + + SBC_A_X (m_C) + break; +case 0x9A: /* SBC A,D */ + + SBC_A_X (m_D) + break; +case 0x9B: /* SBC A,E */ + + SBC_A_X (m_E) + break; +case 0x9C: /* SBC A,H */ + + SBC_A_X (m_H) + break; +case 0x9D: /* SBC A,L */ + + SBC_A_X (m_L) + break; +case 0x9E: /* SBC A,(HL) */ + + x = mem_read_byte( ( m_H << 8 ) | m_L ); + + SBC_A_X (x) + break; +case 0x9F: /* SBC A,A */ + + SBC_A_X (m_A) + break; +case 0xA0: /* AND A,B */ + + AND_A_X (m_B) + break; +case 0xA1: /* AND A,C */ + + AND_A_X (m_C) + break; +case 0xA2: /* AND A,D */ + + AND_A_X (m_D) + break; +case 0xA3: /* AND A,E */ + + AND_A_X (m_E) + break; +case 0xA4: /* AND A,H */ + + AND_A_X (m_H) + break; +case 0xA5: /* AND A,L */ + + AND_A_X (m_L) + break; +case 0xA6: /* AND A,(HL) */ + + x = mem_read_byte( ( m_H << 8 ) | m_L ); + + AND_A_X (x) + break; +case 0xA7: /* AND A,A */ + + m_F = (m_A == 0) ? (FLAG_H | FLAG_Z) : FLAG_H; + break; +case 0xA8: /* XOR A,B */ + + XOR_A_X (m_B) + break; +case 0xA9: /* XOR A,C */ + + XOR_A_X (m_C) + break; +case 0xAA: /* XOR A,D */ + + XOR_A_X (m_D) + break; +case 0xAB: /* XOR A,E */ + + XOR_A_X (m_E) + break; +case 0xAC: /* XOR A,H */ + + XOR_A_X (m_H) + break; +case 0xAD: /* XOR A,L */ + + XOR_A_X (m_L) + break; +case 0xAE: /* XOR A,(HL) */ + + x = mem_read_byte( ( m_H << 8 ) | m_L ); + + XOR_A_X (x) + break; +case 0xAF: /* XOR A,A */ + + XOR_A_X (m_A) + break; +case 0xB0: /* OR A,B */ + + OR_A_X (m_B) + break; +case 0xB1: /* OR A,C */ + + OR_A_X (m_C) + break; +case 0xB2: /* OR A,D */ + + OR_A_X (m_D) + break; +case 0xB3: /* OR A,E */ + + OR_A_X (m_E) + break; +case 0xB4: /* OR A,H */ + + OR_A_X (m_H) + break; +case 0xB5: /* OR A,L */ + + OR_A_X (m_L) + break; +case 0xB6: /* OR A,(HL) */ + + x = mem_read_byte( ( m_H << 8 ) | m_L ); + + OR_A_X (x) + break; +case 0xB7: /* OR A,A */ + + OR_A_X (m_A) + break; +case 0xB8: /* CP A,B */ + + CP_A_X (m_B) + break; +case 0xB9: /* CP A,C */ + + CP_A_X (m_C) + break; +case 0xBA: /* CP A,D */ + + CP_A_X (m_D) + break; +case 0xBB: /* CP A,E */ + + CP_A_X (m_E) + break; +case 0xBC: /* CP A,H */ + + CP_A_X (m_H) + break; +case 0xBD: /* CP A,L */ + + CP_A_X (m_L) + break; +case 0xBE: /* CP A,(HL) */ + + x = mem_read_byte( ( m_H << 8 ) | m_L ); + + CP_A_X (x) + break; +case 0xBF: /* CP A,A */ + + CP_A_X (m_A) + break; +case 0xC0: /* RET NZ */ + cycles_passed( 4 ); + if (!(m_F & FLAG_Z)) + { + m_PC = mem_read_word( m_SP ); + m_SP += 2; + cycles_passed( 4 ); + } + break; +case 0xC1: /* POP BC */ + POP( m_B, m_C ); + break; +case 0xC2: /* JP NZ,n16 */ + { + UINT16 addr = mem_read_word( m_PC ); + m_PC += 2; + + if ( ! (m_F & FLAG_Z) ) + { + m_PC = addr; + cycles_passed( 4 ); + } + } + break; +case 0xC3: /* JP n16 */ + m_PC = mem_read_word( m_PC ); + cycles_passed( 4 ); + break; +case 0xC4: /* CALL NZ,n16 */ + { + UINT16 addr = mem_read_word( m_PC ); + m_PC += 2; + + if ( ! (m_F & FLAG_Z) ) + { + m_SP -= 2; + mem_write_word( m_SP, m_PC ); + m_PC = addr; + cycles_passed( 4 ); + } + } + break; +case 0xC5: /* PUSH BC */ + PUSH( m_B, m_C ); + cycles_passed( 4 ); + break; +case 0xC6: /* ADD A,n8 */ + + x = mem_read_byte( m_PC++ ); + ADD_A_X (x) + break; +case 0xC7: /* RST 0 */ + m_SP -= 2; + mem_write_word( m_SP, m_PC ); + m_PC = 0; + cycles_passed( 4 ); + break; +case 0xC8: /* RET Z */ + cycles_passed( 4 ); + if (m_F & FLAG_Z) + { + m_PC = mem_read_word( m_SP ); + m_SP += 2; + cycles_passed( 4 ); + } + break; +case 0xC9: /* RET */ + m_PC = mem_read_word( m_SP ); + m_SP += 2; + cycles_passed( 4 ); + break; +case 0xCA: /* JP Z,n16 */ + { + UINT16 addr = mem_read_word( m_PC ); + m_PC += 2; + + if (m_F & FLAG_Z) + { + m_PC = addr; + cycles_passed( 4 ); + } + } + break; +case 0xCB: /* PREFIX! */ + x = mem_read_byte( m_PC++ ); + switch (x) + { + #include "opc_cb.inc" + } + break; +case 0xCC: /* CALL Z,n16 */ + { + UINT16 addr = mem_read_word( m_PC ); + m_PC += 2; + + if (m_F & FLAG_Z) + { + m_SP -= 2; + mem_write_word( m_SP, m_PC ); + m_PC = addr; + cycles_passed( 4 ); + } + } + break; +case 0xCD: /* CALL n16 */ + { + UINT16 addr = mem_read_word( m_PC ); + m_PC += 2; + + m_SP -= 2; + mem_write_word( m_SP, m_PC ); + m_PC = addr; + cycles_passed( 4 ); + } + break; +case 0xCE: /* ADC A,n8 */ + + x = mem_read_byte( m_PC++ ); + ADC_A_X (x) + break; +case 0xCF: /* RST 8 */ + m_SP -= 2; + mem_write_word( m_SP, m_PC ); + m_PC = 8; + cycles_passed( 4 ); + break; +case 0xD0: /* RET NC */ + cycles_passed( 4 ); + if (!(m_F & FLAG_C)) + { + m_PC = mem_read_word( m_SP ); + m_SP += 2; + cycles_passed( 4 ); + } + break; +case 0xD1: /* POP DE */ + POP( m_D, m_E ); + break; +case 0xD2: /* JP NC,n16 */ + { + UINT16 addr = mem_read_word( m_PC ); + m_PC += 2; + + if ( ! (m_F & FLAG_C) ) + { + m_PC = addr; + cycles_passed( 4 ); + } + } + break; +case 0xD4: /* CALL NC,n16 */ + { + UINT16 addr = mem_read_word( m_PC ); + m_PC += 2; + + if ( ! (m_F & FLAG_C) ) + { + m_SP -= 2; + mem_write_word( m_SP, m_PC ); + m_PC = addr; + cycles_passed( 4 ); + } + } + break; +case 0xD5: /* PUSH DE */ + PUSH( m_D, m_E ); + cycles_passed( 4 ); + break; +case 0xD6: /* SUB A,n8 */ + + x = mem_read_byte( m_PC++ ); + SUB_A_X (x) + break; +case 0xD7: /* RST $10 */ + m_SP -= 2; + mem_write_word( m_SP, m_PC ); + m_PC = 0x10; + cycles_passed( 4 ); + break; +case 0xD8: /* RET C */ + cycles_passed( 4 ); + if (m_F & FLAG_C) + { + m_PC = mem_read_word( m_SP ); + m_SP += 2; + cycles_passed( 4 ); + } + break; +case 0xD9: /* RETI */ + m_PC = mem_read_word( m_SP ); + m_SP += 2; + m_enable |= IME; + cycles_passed( 4 ); + break; +case 0xDA: /* JP C,n16 */ + { + UINT16 addr = mem_read_word( m_PC ); + m_PC += 2; + + if (m_F & FLAG_C) + { + m_PC = addr; + cycles_passed( 4 ); + } + } + break; +case 0xDC: /* CALL C,n16 */ + { + UINT16 addr = mem_read_word( m_PC ); + m_PC += 2; + + if (m_F & FLAG_C) + { + m_SP -= 2; + mem_write_word( m_SP, m_PC ); + m_PC = addr; + cycles_passed( 4 ); + } + } + break; +case 0xDE: /* SBC A,n8 */ + + x = mem_read_byte( m_PC++ ); + SBC_A_X (x) + break; +case 0xDF: /* RST $18 */ + m_SP -= 2; + mem_write_word( m_SP, m_PC ); + m_PC = 0x18; + cycles_passed( 4 ); + break; +case 0xE0: /* LD ($FF00+n8),A */ + { + UINT8 v = mem_read_byte( m_PC++ ); + mem_write_byte( 0xFF00 + v, m_A ); + } + break; +case 0xE1: /* POP HL */ + POP( m_H, m_L ); + break; +case 0xE2: /* LD ($FF00+C),A */ + + mem_write_byte( 0xFF00 + m_C, m_A ); + break; +case 0xE5: /* PUSH HL */ + PUSH( m_H, m_L ); + cycles_passed( 4 ); + break; +case 0xE6: /* AND A,n8 */ + + x = mem_read_byte( m_PC++ ); + AND_A_X (x) + break; +case 0xE7: /* RST $20 */ + m_SP -= 2; + mem_write_word( m_SP, m_PC ); + m_PC = 0x20; + cycles_passed( 4 ); + break; +case 0xE8: /* ADD SP,n8 */ +/* + * Z - Reset. + * N - Reset. + * H - Set or reset according to operation. + * C - Set or reset according to operation. + */ + + { + register INT32 n; + + n = (INT8) mem_read_byte( m_PC++ ); + + if ( ( m_SP & 0xFF ) + (UINT8)(n & 0xFF) > 0xFF ) + { + m_F = FLAG_C; + } + else + { + m_F = 0; + } + + if ( ( m_SP & 0x0F ) + ( n & 0x0F ) > 0x0F ) + { + m_F |= FLAG_H; + } + + m_SP = (UINT16) ( m_SP + n ); + } + cycles_passed( 8 ); + break; +case 0xE9: /* JP (HL) */ + m_PC = ( m_H << 8 ) | m_L; + break; +case 0xEA: /* LD (n16),A */ + + mem_write_byte( mem_read_word( m_PC ), m_A ); + m_PC += 2; + break; +case 0xEE: /* XOR A,n8 */ + + x = mem_read_byte( m_PC++ ); + XOR_A_X (x) + break; +case 0xEF: /* RST $28 */ + m_SP -= 2; + mem_write_word( m_SP, m_PC ); + m_PC = 0x28; + cycles_passed( 4 ); + break; +case 0xF0: /* LD A,($FF00+n8) */ + { + UINT8 v = mem_read_byte( m_PC++ ); + m_A = mem_read_byte( 0xFF00 + v ); + } + break; +case 0xF1: /* POP AF */ + POP( m_A, m_F ); + m_F &= 0xF0; + break; +case 0xF2: /* LD A,($FF00+C) */ + + m_A = mem_read_byte( 0xFF00 + m_C ); + break; +case 0xF3: /* DI */ + m_handle_ei_delay = false; + m_enable &= ~IME; + break; +case 0xF5: /* PUSH AF */ + m_F &= 0xF0; + PUSH( m_A, m_F ); + cycles_passed( 4 ); + break; +case 0xF6: /* OR A,n8 */ + + x = mem_read_byte( m_PC++ ); + OR_A_X (x) + break; +case 0xF7: /* RST $30 */ + m_SP -= 2; + mem_write_word( m_SP, m_PC ); + m_PC = 0x30; + cycles_passed( 4 ); + break; +case 0xF8: /* LD HL,SP+n8 */ +/* + * n = one UINT8 signed immediate value. + * Flags affected: + * Z - Reset. + * N - Reset. + * H - Set or reset according to operation. + * C - Set or reset according to operation. + * + */ + + { + register INT32 n; + + n = (INT8) mem_read_byte( m_PC++ ); + + if ( ( m_SP & 0xFF ) + (UINT8)(n & 0xFF) > 0xFF ) + { + m_F = FLAG_C; + } + else + { + m_F = 0; + } + + if ( ( m_SP & 0x0F ) + ( n & 0x0F ) > 0x0F ) + { + m_F |= FLAG_H; + } + + UINT16 res = m_SP + n; + + m_L = res & 0xFF; + m_H = res >> 8; + } + cycles_passed( 4 ); + break; +case 0xF9: /* LD SP,HL */ + m_SP = ( m_H << 8 ) | m_L; + cycles_passed( 4 ); + break; +case 0xFA: /* LD A,(n16) */ + m_A = mem_read_byte( mem_read_word( m_PC ) ); + m_PC += 2; + break; +case 0xFB: /* EI */ + m_enable |= IME; + m_handle_ei_delay = true; + break; +case 0xFE: /* CP A,n8 */ + x = mem_read_byte( m_PC++ ); + CP_A_X (x) + break; +case 0xFF: /* RST $38 */ + m_SP -= 2; + mem_write_word( m_SP, m_PC ); + m_PC = 0x38; + cycles_passed( 4 ); + break; diff --git a/src/devices/cpu/m37710/m37710.c b/src/devices/cpu/m37710/m37710.c new file mode 100644 index 00000000000..26a2accfe76 --- /dev/null +++ b/src/devices/cpu/m37710/m37710.c @@ -0,0 +1,1215 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont, Karl Stenerud, hap +/* + Mitsubishi M37702/37710 CPU Emulator + + The 7700 series is based on the WDC 65C816 core, with the following + notable changes: + + - Second accumulator called "B" (on the 65816, "A" and "B" were the + two 8-bit halves of the 16-bit "C" accumulator). + - 6502 emulation mode and XCE instruction are not present. + - No NMI line. BRK and the watchdog interrupt are non-maskable, but there + is no provision for the traditional 6502/65816 NMI line. + - 3-bit interrupt priority levels like the 68000. Interrupts in general + are very different from the 65816. + - New single-instruction immediate-to-memory move instructions (LDM) + replaces STZ. + - CLM and SEM (clear and set "M" status bit) replace CLD/SED. Decimal + mode is still available via REP/SEP instructions. + - INC and DEC (0x1A and 0x3A) switch places for no particular reason. + - The microcode bug that caused MVN/NVP to take 2 extra cycles per byte + on the 65816 seems to have been fixed. + - The WDM (0x42) and BIT immediate (0x89) instructions are now prefixes. + 0x42 when used before an instruction involving the A accumulator makes + it use the B accumulator instead. 0x89 adds multiply and divide + opcodes, which the real 65816 doesn't have. + - The 65C816 preserves the upper 8 bits of A when in 8-bit M mode, but + not the upper 8 bits of X or Y when in 8-bit X. The 7700 preserves + the top bits of all registers in all modes (code in the C74 BIOS + starting at d881 requires this!). + + The various 7700 series models differ primarily by their on board + peripherals. The 7750 and later models do include some additional + instructions, vs. the 770x/1x/2x, notably signed multiply/divide and + sign extension opcodes. + + Peripherals common across the 7700 series include: programmable timers, + digital I/O ports, and analog to digital converters. + + Reference: 7700 Family Software User's Manual (instruction set) + 7702/7703 Family User's Manual (on-board peripherals) + 7720 Family User's Manual + + Emulator by R. Belmont. + Based on G65816 Emulator by Karl Stenrud. + + History: + - v1.0 RB First version, basic operation OK, timers not complete + - v1.1 RB Data bus is 16-bit, dozens of bugfixes to IRQs, opcodes, + and opcode mapping. New opcodes added, internal timers added. + - v1.2 RB Fixed execution outside of bank 0, fixed LDM outside of bank 0, + fixed so top 8 bits of X & Y are preserved while in 8-bit mode, + added save state support. +*/ + +#include "emu.h" +#include "debugger.h" +#include "m37710.h" +#include "m37710cm.h" +#include "m37710il.h" + +#define M37710_DEBUG (0) // enables verbose logging for peripherals, etc. + + +const device_type M37702M2 = &device_creator; +const device_type M37702S1 = &device_creator; +const device_type M37710S4 = &device_creator; + + +// On-board RAM, ROM, and peripherals + +// M37702M2: 512 bytes internal RAM, 16K internal mask ROM +// (M37702E2: same with EPROM instead of mask ROM) +DEVICE_ADDRESS_MAP_START( map, 16, m37702m2_device ) + AM_RANGE(0x000000, 0x00007f) AM_READWRITE(m37710_internal_word_r, m37710_internal_word_w) + AM_RANGE(0x000080, 0x00027f) AM_RAM + AM_RANGE(0x00c000, 0x00ffff) AM_ROM AM_REGION(M37710_INTERNAL_ROM_REGION, 0) +ADDRESS_MAP_END + + +// M37702S1: 512 bytes internal RAM, no internal ROM +DEVICE_ADDRESS_MAP_START( map, 16, m37702s1_device ) + AM_RANGE(0x000000, 0x00007f) AM_READWRITE(m37710_internal_word_r, m37710_internal_word_w) + AM_RANGE(0x000080, 0x00027f) AM_RAM +ADDRESS_MAP_END + + +// M37710S4: 2048 bytes internal RAM, no internal ROM +DEVICE_ADDRESS_MAP_START( map, 16, m37710s4_device ) + AM_RANGE(0x000000, 0x00007f) AM_READWRITE(m37710_internal_word_r, m37710_internal_word_w) + AM_RANGE(0x000080, 0x00087f) AM_RAM +ADDRESS_MAP_END + +// many other combinations of RAM and ROM size exist + + +m37710_cpu_device::m37710_cpu_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source, address_map_delegate map_delegate) + : cpu_device(mconfig, type, name, tag, owner, clock, shortname, source) + , m_program_config("program", ENDIANNESS_LITTLE, 16, 24, 0, map_delegate) + , m_io_config("io", ENDIANNESS_LITTLE, 8, 16, 0) +{ +} + + +m37702m2_device::m37702m2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : m37710_cpu_device(mconfig, M37702M2, "M37702M2", tag, owner, clock, "m37702m2", __FILE__, address_map_delegate(FUNC(m37702m2_device::map), this)) +{ +} + + +m37702m2_device::m37702m2_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : m37710_cpu_device(mconfig, type, name, tag, owner, clock, shortname, source, address_map_delegate(FUNC(m37702m2_device::map), this)) +{ +} + + +m37702s1_device::m37702s1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : m37710_cpu_device(mconfig, M37702S1, "M37702S1", tag, owner, clock, "m37702s1", __FILE__, address_map_delegate(FUNC(m37702s1_device::map), this)) +{ +} + + +m37710s4_device::m37710s4_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : m37710_cpu_device(mconfig, M37710S4, "M37710S4", tag, owner, clock, "m37710s4", __FILE__, address_map_delegate(FUNC(m37710s4_device::map), this)) +{ +} + + +/* interrupt control mapping */ + +const int m37710_cpu_device::m37710_irq_levels[M37710_LINE_MAX] = +{ + // maskable + 0x70, // ADC 0 + 0x73, // UART 1 XMIT 1 + 0x74, // UART 1 RECV 2 + 0x71, // UART 0 XMIT 3 + 0x72, // UART 0 RECV 4 + 0x7c, // Timer B2 5 + 0x7b, // Timer B1 6 + 0x7a, // Timer B0 7 + 0x79, // Timer A4 8 + 0x78, // Timer A3 9 + 0x77, // Timer A2 10 + 0x76, // Timer A1 11 + 0x75, // Timer A0 12 + 0x7f, // IRQ 2 13 + 0x7e, // IRQ 1 14 + 0x7d, // IRQ 0 15 + + // non-maskable + 0, // watchdog + 0, // debugger control + 0, // BRK + 0, // divide by zero + 0, // reset +}; + +const int m37710_cpu_device::m37710_irq_vectors[M37710_LINE_MAX] = +{ + // maskable + 0xffd6, // A-D converter + 0xffd8, // UART1 transmit + 0xffda, // UART1 receive + 0xffdc, // UART0 transmit + 0xffde, // UART0 receive + 0xffe0, // Timer B2 + 0xffe2, // Timer B1 + 0xffe4, // Timer B0 + 0xffe6, // Timer A4 + 0xffe8, // Timer A3 + 0xffea, // Timer A2 + 0xffec, // Timer A1 + 0xffee, // Timer A0 + 0xfff0, // external INT2 pin + 0xfff2, // external INT1 pin + 0xfff4, // external INT0 pin + + // non-maskable + 0xfff6, // watchdog timer + 0xfff8, // debugger control (not used in shipping ICs?) + 0xfffa, // BRK + 0xfffc, // divide by zero + 0xfffe, // RESET +}; + +// M37710 internal peripherals + +const char *const m37710_cpu_device::m37710_rnames[128] = +{ + "", + "", + "Port P0 reg", + "Port P1 reg", + "Port P0 dir reg", + "Port P1 dir reg", + "Port P2 reg", + "Port P3 reg", + "Port P2 dir reg", + "Port P3 dir reg", + "Port P4 reg", + "Port P5 reg", + "Port P4 dir reg", + "Port P5 dir reg", + "Port P6 reg", + "Port P7 reg", + "Port P6 dir reg", // 16 (0x10) + "Port P7 dir reg", + "Port P8 reg", + "", + "Port P8 dir reg", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "A/D control reg", + "A/D sweep pin select", + "A/D 0", // 32 (0x20) + "", + "A/D 1", + "", + "A/D 2", + "", + "A/D 3", + "", + "A/D 4", + "", + "A/D 5", + "", + "A/D 6", + "", + "A/D 7", + "", + "UART0 transmit/recv mode", // 48 (0x30) + "UART0 baud rate", // 0x31 + "UART0 transmit buf L", // 0x32 + "UART0 transmit buf H", // 0x33 + "UART0 transmit/recv ctrl 0", // 0x34 + "UART0 transmit/recv ctrl 1", // 0x35 + "UART0 recv buf L", // 0x36 + "UART0 recv buf H", // 0x37 + "UART1 transmit/recv mode", // 0x38 + "UART1 baud rate", + "UART1 transmit buf L", + "UART1 transmit buf H", + "UART1 transmit/recv ctrl 0", + "UART1 transmit/recv ctrl 1", + "UART1 recv buf L", + "UART1 recv buf H", + "Count start", // 0x40 + "", + "One-shot start", + "", + "Up-down register", + "", + "Timer A0 L", // 0x46 + "Timer A0 H", + "Timer A1 L", + "Timer A1 H", + "Timer A2 L", + "Timer A2 H", + "Timer A3 L", + "Timer A3 H", + "Timer A4 L", + "Timer A4 H", + "Timer B0 L", + "Timer B0 H", // 0x50 + "Timer B1 L", + "Timer B1 H", + "Timer B2 L", + "Timer B2 H", + "Timer A0 mode", + "Timer A1 mode", + "Timer A2 mode", + "Timer A3 mode", + "Timer A4 mode", + "Timer B0 mode", + "Timer B1 mode", + "Timer B2 mode", + "Processor mode", + "", + "Watchdog reset", // 0x60 + "Watchdog frequency", // 0x61 + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "A/D IRQ ctrl", + "UART0 xmit IRQ ctrl", // 0x70 + "UART0 recv IRQ ctrl", + "UART1 xmit IRQ ctrl", + "UART1 recv IRQ ctrl", + "Timer A0 IRQ ctrl", // 0x74 + "Timer A1 IRQ ctrl", // 0x75 + "Timer A2 IRQ ctrl", // 0x76 + "Timer A3 IRQ ctrl", + "Timer A4 IRQ ctrl", // 0x78 + "Timer B0 IRQ ctrl", + "Timer B1 IRQ ctrl", + "Timer B2 IRQ ctrl", + "INT0 IRQ ctrl", + "INT1 IRQ ctrl", + "INT2 IRQ ctrl", +}; + +const char *const m37710_cpu_device::m37710_tnames[8] = +{ + "A0", "A1", "A2", "A3", "A4", "B0", "B1", "B2" +}; + +TIMER_CALLBACK_MEMBER( m37710_cpu_device::m37710_timer_cb ) +{ + int which = param; + int curirq = M37710_LINE_TIMERA0 - which; + + m_timers[which]->adjust(m_reload[which], param); + + m37710_set_irq_line(curirq, HOLD_LINE); + signal_interrupt_trigger(); +} + +void m37710_cpu_device::m37710_external_tick(int timer, int state) +{ + // we only care if the state is "on" + if (!state) + { + return; + } + + // check if enabled + if (m_m37710_regs[0x40] & (1<>6]; + time *= (tval + 1); + + #if M37710_DEBUG + logerror("Timer %d in timer mode, %f Hz\n", timer, 1.0 / time.as_double()); + #endif + + m_timers[timer]->adjust(time, timer); + m_reload[timer] = time; + break; + + case 1: // event counter mode + #if M37710_DEBUG + logerror("Timer %d in event counter mode\n", timer); + #endif + break; + + case 2: // one-shot pulse mode + #if M37710_DEBUG + logerror("Timer %d in one-shot mode\n", timer); + #endif + break; + + case 3: // PWM mode + #if M37710_DEBUG + logerror("Timer %d in PWM mode\n", timer); + #endif + break; + } + } + else + { + switch (m_m37710_regs[0x56+timer] & 0x3) + { + case 0: // timer mode + time = attotime::from_hz(unscaled_clock()) * tscales[m_m37710_regs[0x56+timer]>>6]; + time *= (tval + 1); + + #if M37710_DEBUG + logerror("Timer %d in timer mode, %f Hz\n", timer, 1.0 / time.as_double()); + #endif + + m_timers[timer]->adjust(time, timer); + m_reload[timer] = time; + break; + + case 1: // event counter mode + #if M37710_DEBUG + logerror("Timer %d in event counter mode\n", timer); + #endif + break; + + case 2: // pulse period/pulse width measurement mode + #if M37710_DEBUG + logerror("Timer %d in pulse period/width measurement mode\n", timer); + #endif + break; + + case 3: + #if M37710_DEBUG + logerror("Timer %d in unknown mode!\n", timer); + #endif + break; + } + } + } +} + +UINT8 m37710_cpu_device::m37710_internal_r(int offset) +{ + UINT8 d; + + #if M37710_DEBUG + if (offset > 1) + logerror("m37710_internal_r from %02x: %s (PC=%x)\n", (int)offset, m37710_rnames[(int)offset], REG_PB<<16 | REG_PC); + #endif + + switch (offset) + { + // ports + case 0x02: // p0 + d = m_m37710_regs[0x04]; + if (d != 0xff) + return (m_io->read_byte(M37710_PORT0)&~d) | (m_m37710_regs[offset]&d); + break; + case 0x03: // p1 + d = m_m37710_regs[0x05]; + if (d != 0xff) + return (m_io->read_byte(M37710_PORT1)&~d) | (m_m37710_regs[offset]&d); + break; + case 0x06: // p2 + d = m_m37710_regs[0x08]; + if (d != 0xff) + return (m_io->read_byte(M37710_PORT2)&~d) | (m_m37710_regs[offset]&d); + break; + case 0x07: // p3 + d = m_m37710_regs[0x09]; + if (d != 0xff) + return (m_io->read_byte(M37710_PORT3)&~d) | (m_m37710_regs[offset]&d); + break; + case 0x0a: // p4 + d = m_m37710_regs[0x0c]; + if (d != 0xff) + return (m_io->read_byte(M37710_PORT4)&~d) | (m_m37710_regs[offset]&d); + break; + case 0x0b: // p5 + d = m_m37710_regs[0x0d]; + if (d != 0xff) + return (m_io->read_byte(M37710_PORT5)&~d) | (m_m37710_regs[offset]&d); + break; + case 0x0e: // p6 + d = m_m37710_regs[0x10]; + if (d != 0xff) + return (m_io->read_byte(M37710_PORT6)&~d) | (m_m37710_regs[offset]&d); + break; + case 0x0f: // p7 + d = m_m37710_regs[0x11]; + if (d != 0xff) + return (m_io->read_byte(M37710_PORT7)&~d) | (m_m37710_regs[offset]&d); + break; + case 0x12: // p8 + d = m_m37710_regs[0x14]; + if (d != 0xff) + return (m_io->read_byte(M37710_PORT8)&~d) | (m_m37710_regs[offset]&d); + break; + + // A-D regs + case 0x20: + return m_io->read_byte(M37710_ADC0_L); + case 0x21: + return m_io->read_byte(M37710_ADC0_H); + case 0x22: + return m_io->read_byte(M37710_ADC1_L); + case 0x23: + return m_io->read_byte(M37710_ADC1_H); + case 0x24: + return m_io->read_byte(M37710_ADC2_L); + case 0x25: + return m_io->read_byte(M37710_ADC2_H); + case 0x26: + return m_io->read_byte(M37710_ADC3_L); + case 0x27: + return m_io->read_byte(M37710_ADC3_H); + case 0x28: + return m_io->read_byte(M37710_ADC4_L); + case 0x29: + return m_io->read_byte(M37710_ADC4_H); + case 0x2a: + return m_io->read_byte(M37710_ADC5_L); + case 0x2b: + return m_io->read_byte(M37710_ADC5_H); + case 0x2c: + return m_io->read_byte(M37710_ADC6_L); + case 0x2d: + return m_io->read_byte(M37710_ADC6_H); + case 0x2e: + return m_io->read_byte(M37710_ADC7_L); + case 0x2f: + return m_io->read_byte(M37710_ADC7_H); + + // UART control (not hooked up yet) + case 0x34: case 0x3c: + return 0x08; + case 0x35: case 0x3d: + return 0xff; + + // A-D IRQ control (also not properly hooked up yet) + case 0x70: + return m_m37710_regs[offset] | 8; + + default: + return m_m37710_regs[offset]; + } + + return m_m37710_regs[offset]; +} + +void m37710_cpu_device::m37710_internal_w(int offset, UINT8 data) +{ + int i; + UINT8 prevdata; + UINT8 d; + + #if M37710_DEBUG + if (offset != 0x60) // filter out watchdog + logerror("m37710_internal_w %x to %02x: %s = %x\n", data, (int)offset, m37710_rnames[(int)offset], m_m37710_regs[offset]); + #endif + + prevdata = m_m37710_regs[offset]; + m_m37710_regs[offset] = data; + + switch(offset) + { + // ports + case 0x02: // p0 + d = m_m37710_regs[0x04]; + if (d != 0) + m_io->write_byte(M37710_PORT0, data&d); + break; + case 0x03: // p1 + d = m_m37710_regs[0x05]; + if (d != 0) + m_io->write_byte(M37710_PORT1, data&d); + break; + case 0x06: // p2 + d = m_m37710_regs[0x08]; + if (d != 0) + m_io->write_byte(M37710_PORT2, data&d); + break; + case 0x07: // p3 + d = m_m37710_regs[0x09]; + if (d != 0) + m_io->write_byte(M37710_PORT3, data&d); + break; + case 0x0a: // p4 + d = m_m37710_regs[0x0c]; + if (d != 0) + m_io->write_byte(M37710_PORT4, data&d); + break; + case 0x0b: // p5 + d = m_m37710_regs[0x0d]; + if (d != 0) + m_io->write_byte(M37710_PORT5, data&d); + break; + case 0x0e: // p6 + d = m_m37710_regs[0x10]; + if (d != 0) + m_io->write_byte(M37710_PORT6, data&d); + break; + case 0x0f: // p7 + d = m_m37710_regs[0x11]; + if (d != 0) + m_io->write_byte(M37710_PORT7, data&d); + break; + case 0x12: // p8 + d = m_m37710_regs[0x14]; + if (d != 0) + m_io->write_byte(M37710_PORT8, data&d); + break; + + case 0x40: // count start + for (i = 0; i < 8; i++) + { + if ((data & (1<>8); +} + + +const m37710_cpu_device::opcode_func *m37710_cpu_device::m37710i_opcodes[4] = +{ + m37710i_opcodes_M0X0, + m37710i_opcodes_M0X1, + m37710i_opcodes_M1X0, + m37710i_opcodes_M1X1, +}; + +const m37710_cpu_device::opcode_func *m37710_cpu_device::m37710i_opcodes2[4] = +{ + m37710i_opcodes42_M0X0, + m37710i_opcodes42_M0X1, + m37710i_opcodes42_M1X0, + m37710i_opcodes42_M1X1, +}; + +const m37710_cpu_device::opcode_func *m37710_cpu_device::m37710i_opcodes3[4] = +{ + m37710i_opcodes89_M0X0, + m37710i_opcodes89_M0X1, + m37710i_opcodes89_M1X0, + m37710i_opcodes89_M1X1, +}; + +const m37710_cpu_device::get_reg_func m37710_cpu_device::m37710i_get_reg[4] = +{ + &m37710_cpu_device::m37710i_get_reg_M0X0, + &m37710_cpu_device::m37710i_get_reg_M0X1, + &m37710_cpu_device::m37710i_get_reg_M1X0, + &m37710_cpu_device::m37710i_get_reg_M1X1, +}; + +const m37710_cpu_device::set_reg_func m37710_cpu_device::m37710i_set_reg[4] = +{ + &m37710_cpu_device::m37710i_set_reg_M0X0, + &m37710_cpu_device::m37710i_set_reg_M0X1, + &m37710_cpu_device::m37710i_set_reg_M1X0, + &m37710_cpu_device::m37710i_set_reg_M1X1, +}; + +const m37710_cpu_device::set_line_func m37710_cpu_device::m37710i_set_line[4] = +{ + &m37710_cpu_device::m37710i_set_line_M0X0, + &m37710_cpu_device::m37710i_set_line_M0X1, + &m37710_cpu_device::m37710i_set_line_M1X0, + &m37710_cpu_device::m37710i_set_line_M1X1, +}; + +const m37710_cpu_device::execute_func m37710_cpu_device::m37710i_execute[4] = +{ + &m37710_cpu_device::m37710i_execute_M0X0, + &m37710_cpu_device::m37710i_execute_M0X1, + &m37710_cpu_device::m37710i_execute_M1X0, + &m37710_cpu_device::m37710i_execute_M1X1, +}; + +/* internal functions */ + +void m37710_cpu_device::m37710i_update_irqs() +{ + int curirq, pending = LINE_IRQ; + int wantedIRQ = -1; + int curpri = 0; + + for (curirq = M37710_LINE_MAX - 1; curirq >= 0; curirq--) + { + if ((pending & (1 << curirq))) + { + // this IRQ is set + if (m37710_irq_levels[curirq]) + { + int control = m_m37710_regs[m37710_irq_levels[curirq]]; + int thispri = control & 7; + // logerror("line %d set, level %x curpri %x IPL %x\n", curirq, thispri, curpri, m_ipl); + // it's maskable, check if the level works, also make sure it's acceptable for the current CPU level + if (!FLAG_I && thispri > curpri && thispri > m_ipl) + { + // mark us as the best candidate + wantedIRQ = curirq; + curpri = thispri; + } + } + else + { + // non-maskable + wantedIRQ = curirq; + curpri = 7; + break; // no more processing, NMIs always win + } + } + } + + if (wantedIRQ != -1) + { + standard_irq_callback(wantedIRQ); + + // make sure we're running to service the interrupt + CPU_STOPPED &= ~STOP_LEVEL_WAI; + + // auto-clear line + m37710_set_irq_line(wantedIRQ, CLEAR_LINE); + + // let's do it... + // push PB, then PC, then status + CLK(13); +// osd_printf_debug("taking IRQ %d: PC = %06x, SP = %04x, IPL %d\n", wantedIRQ, REG_PB | REG_PC, REG_S, m_ipl); + m37710i_push_8(REG_PB>>16); + m37710i_push_16(REG_PC); + m37710i_push_8(m_ipl); + m37710i_push_8(m37710i_get_reg_p()); + + // set I to 1, set IPL to the interrupt we're taking + FLAG_I = IFLAG_SET; + m_ipl = curpri; + // then PB=0, PC=(vector) + REG_PB = 0; + REG_PC = m37710_read_16(m37710_irq_vectors[wantedIRQ]); +// logerror("IRQ @ %06x\n", REG_PB | REG_PC); + } +} + +/* external functions */ + +void m37710_cpu_device::device_reset() +{ + int i; + + /* Reset MAME timers */ + for (i = 0; i < 8; i++) + { + m_timers[i]->reset(); + m_reload[i] = attotime::zero; + } + + /* Start the CPU */ + CPU_STOPPED = 0; + + /* Reset internal registers */ + // port direction + m_m37710_regs[0x04] = 0; + m_m37710_regs[0x05] = 0; + m_m37710_regs[0x08] = 0; + m_m37710_regs[0x09] = 0; + m_m37710_regs[0x0c] = 0; + m_m37710_regs[0x0d] = 0; + m_m37710_regs[0x10] = 0; + m_m37710_regs[0x11] = 0; + m_m37710_regs[0x14] = 0; + + m_m37710_regs[0x1e] &= 7; // A-D control + m_m37710_regs[0x1f] |= 3; // A-D sweep + + // UART + m_m37710_regs[0x30] = 0; + m_m37710_regs[0x38] = 0; + m_m37710_regs[0x34] = (m_m37710_regs[0x34] & 0xf0) | 8; + m_m37710_regs[0x3c] = (m_m37710_regs[0x3c] & 0xf0) | 8; + m_m37710_regs[0x35] = 2; + m_m37710_regs[0x3d] = 2; + m_m37710_regs[0x37]&= 1; + m_m37710_regs[0x3f]&= 1; + + // timer + m_m37710_regs[0x40] = 0; + m_m37710_regs[0x42]&= 0x1f; + m_m37710_regs[0x44] = 0; + for (i = 0x56; i < 0x5e; i++) + m_m37710_regs[i] = 0; + + m_m37710_regs[0x5e] = 0; // processor mode + m_m37710_regs[0x61]&= 1; // watchdog frequency + + // interrupt control + m_m37710_regs[0x7d] &= 0x3f; + m_m37710_regs[0x7e] &= 0x3f; + m_m37710_regs[0x7f] &= 0x3f; + for (i = 0x70; i < 0x7d; i++) + m_m37710_regs[i] &= 0xf; + + /* Clear IPL, m, x, D and set I */ + m_ipl = 0; + FLAG_M = MFLAG_CLEAR; + FLAG_X = XFLAG_CLEAR; + FLAG_D = DFLAG_CLEAR; + FLAG_I = IFLAG_SET; + + /* Clear all pending interrupts (should we really do this?) */ + LINE_IRQ = 0; + IRQ_DELAY = 0; + + /* 37710 boots in full native mode */ + REG_D = 0; + REG_PB = 0; + REG_DB = 0; + REG_S = (REG_S & 0xff) | 0x100; + REG_XH = REG_X & 0xff00; REG_X &= 0xff; + REG_YH = REG_Y & 0xff00; REG_Y &= 0xff; + REG_B = REG_A & 0xff00; REG_A &= 0xff; + REG_BB = REG_BA & 0xff00; REG_BA &= 0xff; + + /* Set the function tables to emulation mode */ + m37710i_set_execution_mode(EXECUTION_MODE_M0X0); + + /* Fetch the reset vector */ + REG_PC = m37710_read_16(0xfffe); +} + +/* Execute some instructions */ +void m37710_cpu_device::execute_run() +{ + m37710i_update_irqs(); + + int clocks = m_ICount; + m_ICount = clocks - (this->*m_execute)(m_ICount); +} + + +/* Set the Program Counter */ +void m37710_cpu_device::m37710_set_pc(unsigned val) +{ + REG_PC = MAKE_UINT_16(val); +} + +/* Get the current Stack Pointer */ +unsigned m37710_cpu_device::m37710_get_sp() +{ + return REG_S; +} + +/* Set the Stack Pointer */ +void m37710_cpu_device::m37710_set_sp(unsigned val) +{ + REG_S = MAKE_UINT_16(val); +} + +/* Get a register */ +unsigned m37710_cpu_device::m37710_get_reg(int regnum) +{ + return (this->*m_get_reg)(regnum); +} + +/* Set a register */ +void m37710_cpu_device::m37710_set_reg(int regnum, unsigned value) +{ + (this->*m_set_reg)(regnum, value); +} + +/* Set an interrupt line */ +void m37710_cpu_device::m37710_set_irq_line(int line, int state) +{ + (this->*m_set_line)(line, state); +} + +/* Disassemble an instruction */ +#include "m7700ds.h" + + +CPU_DISASSEMBLE( m37710 ) +{ + return m7700_disassemble(buffer, (pc&0xffff), pc>>16, oprom, 0, 0); +} + + +offs_t m37710_cpu_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + return m7700_disassemble(buffer, (pc&0xffff), pc>>16, oprom, FLAG_M, FLAG_X); +} + + +void m37710_cpu_device::m37710_restore_state() +{ + // restore proper function pointers + m37710i_set_execution_mode((FLAG_M>>4) | (FLAG_X>>4)); +} + +void m37710_cpu_device::device_start() +{ + m_a = 0; + m_b = 0; + m_ba = 0; + m_bb = 0; + m_x = 0; + m_y = 0; + m_xh = 0; + m_yh = 0; + m_s = 0; + m_pc = 0; + m_ppc = 0; + m_pb = 0; + m_db = 0; + m_d = 0; + m_flag_e = 0; + m_flag_m = 0; + m_flag_x = 0; + m_flag_n = 0; + m_flag_v = 0; + m_flag_d = 0; + m_flag_i = 0; + m_flag_z = 0; + m_flag_c = 0; + m_line_irq = 0; + m_ipl = 0; + m_ir = 0; + m_im = 0; + m_im2 = 0; + m_im3 = 0; + m_im4 = 0; + m_irq_delay = 0; + m_irq_level = 0; + m_stopped = 0; + memset(m_m37710_regs, 0, sizeof(m_m37710_regs)); + + m_program = &space(AS_PROGRAM); + m_direct = &m_program->direct(); + m_io = &space(AS_IO); + + m_ICount = 0; + + m_source = 0; + m_destination = 0; + + for (int i = 0; i < 8; i++) + { + m_timers[i] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(m37710_cpu_device::m37710_timer_cb), this)); + m_reload[i] = attotime::never; + } + + save_item(NAME(m_a)); + save_item(NAME(m_b)); + save_item(NAME(m_ba)); + save_item(NAME(m_bb)); + save_item(NAME(m_x)); + save_item(NAME(m_y)); + save_item(NAME(m_xh)); + save_item(NAME(m_yh)); + save_item(NAME(m_s)); + save_item(NAME(m_pc)); + save_item(NAME(m_ppc)); + save_item(NAME(m_pb)); + save_item(NAME(m_db)); + save_item(NAME(m_d)); + save_item(NAME(m_flag_e)); + save_item(NAME(m_flag_m)); + save_item(NAME(m_flag_x)); + save_item(NAME(m_flag_n)); + save_item(NAME(m_flag_v)); + save_item(NAME(m_flag_d)); + save_item(NAME(m_flag_i)); + save_item(NAME(m_flag_z)); + save_item(NAME(m_flag_c)); + save_item(NAME(m_line_irq)); + save_item(NAME(m_ipl)); + save_item(NAME(m_ir)); + save_item(NAME(m_im)); + save_item(NAME(m_im2)); + save_item(NAME(m_im3)); + save_item(NAME(m_im4)); + save_item(NAME(m_irq_delay)); + save_item(NAME(m_irq_level)); + save_item(NAME(m_stopped)); + save_item(NAME(m_m37710_regs)); + save_item(NAME(m_reload[0])); + save_item(NAME(m_reload[1])); + save_item(NAME(m_reload[2])); + save_item(NAME(m_reload[3])); + save_item(NAME(m_reload[4])); + save_item(NAME(m_reload[5])); + save_item(NAME(m_reload[6])); + save_item(NAME(m_reload[7])); + + machine().save().register_postload(save_prepost_delegate(save_prepost_delegate(FUNC(m37710_cpu_device::m37710_restore_state), this))); + + state_add( M37710_PC, "PC", m_pc).formatstr("%04X"); + state_add( M37710_PB, "PB", m_debugger_pb).callimport().callexport().formatstr("%02X"); + state_add( M37710_DB, "DB", m_debugger_db).callimport().callexport().formatstr("%02X"); + state_add( M37710_D, "D", m_d).formatstr("%04X"); + state_add( M37710_S, "S", m_s).formatstr("%04X"); + state_add( M37710_P, "P", m_debugger_p).callimport().callexport().formatstr("%04X"); + state_add( M37710_E, "E", m_flag_e).formatstr("%01X"); + state_add( M37710_A, "A", m_debugger_a).callimport().callexport().formatstr("%04X"); + state_add( M37710_B, "B", m_debugger_b).callimport().callexport().formatstr("%04X"); + state_add( M37710_X, "X", m_x).formatstr("%04X"); + state_add( M37710_Y, "Y", m_y).formatstr("%04X"); + state_add( M37710_IRQ_STATE, "IRQ", m_line_irq).formatstr("%01X"); + + state_add( STATE_GENPC, "GENPC", m_debugger_pc ).callimport().callexport().noshow(); + state_add( STATE_GENFLAGS, "GENFLAGS", m_debugger_p ).formatstr("%8s").noshow(); + + m_icountptr = &m_ICount; +} + + +void m37710_cpu_device::state_import(const device_state_entry &entry) +{ + switch (entry.index()) + { + case M37710_PB: + m37710_set_reg(M37710_PB, m_debugger_pb); + break; + + case M37710_DB: + m37710_set_reg(M37710_DB, m_debugger_db); + break; + + case M37710_P: + m37710_set_reg(M37710_P, m_debugger_p&0xff); + m_ipl = (m_debugger_p>>8)&0xff; + break; + + case M37710_A: + m37710_set_reg(M37710_A, m_debugger_a); + break; + + case M37710_B: + m37710_set_reg(M37710_B, m_debugger_b); + break; + + case STATE_GENPC: + REG_PB = m_debugger_pc & 0xff0000; + m37710_set_pc(m_debugger_pc & 0xffff); + break; + } +} + + +void m37710_cpu_device::state_export(const device_state_entry &entry) +{ + switch (entry.index()) + { + case M37710_PB: + m_debugger_pb = m_pb >> 16; + break; + + case M37710_DB: + m_debugger_db = m_db >> 16; + break; + + case M37710_P: + m_debugger_p = (m_flag_n&0x80) | ((m_flag_v>>1)&0x40) | m_flag_m | m_flag_x | m_flag_d | m_flag_i | ((!m_flag_z)<<1) | ((m_flag_c>>8)&1) | (m_ipl<<8); + break; + + case M37710_A: + m_debugger_a = m_a | m_b; + break; + + case M37710_B: + m_debugger_b = m_ba | m_bb; + break; + + case STATE_GENPC: + m_debugger_pc = (REG_PB | REG_PC); + break; + } +} + + +void m37710_cpu_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + switch (entry.index()) + { + case STATE_GENFLAGS: + strprintf(str, "%c%c%c%c%c%c%c%c", + m_flag_n & NFLAG_SET ? 'N':'.', + m_flag_v & VFLAG_SET ? 'V':'.', + m_flag_m & MFLAG_SET ? 'M':'.', + m_flag_x & XFLAG_SET ? 'X':'.', + m_flag_d & DFLAG_SET ? 'D':'.', + m_flag_i & IFLAG_SET ? 'I':'.', + m_flag_z == 0 ? 'Z':'.', + m_flag_c & CFLAG_SET ? 'C':'.'); + break; + } +} + + +void m37710_cpu_device::execute_set_input(int inputnum, int state) +{ + switch( inputnum ) + { + case M37710_LINE_ADC: + case M37710_LINE_IRQ0: + case M37710_LINE_IRQ1: + case M37710_LINE_IRQ2: + m37710_set_irq_line(inputnum, state); + break; + + case M37710_LINE_TIMERA0TICK: + case M37710_LINE_TIMERA1TICK: + case M37710_LINE_TIMERA2TICK: + case M37710_LINE_TIMERA3TICK: + case M37710_LINE_TIMERA4TICK: + case M37710_LINE_TIMERB0TICK: + case M37710_LINE_TIMERB1TICK: + case M37710_LINE_TIMERB2TICK: + m37710_external_tick(inputnum - M37710_LINE_TIMERA0TICK, state); + break; + } +} + + +void m37710_cpu_device::m37710i_set_execution_mode(UINT32 mode) +{ + m_opcodes = m37710i_opcodes[mode]; + m_opcodes42 = m37710i_opcodes2[mode]; + m_opcodes89 = m37710i_opcodes3[mode]; + FTABLE_GET_REG = m37710i_get_reg[mode]; + FTABLE_SET_REG = m37710i_set_reg[mode]; + FTABLE_SET_LINE = m37710i_set_line[mode]; + m_execute = m37710i_execute[mode]; +} + + +/* ======================================================================== */ +/* =============================== INTERRUPTS ============================= */ +/* ======================================================================== */ + +void m37710_cpu_device::m37710i_interrupt_software(UINT32 vector) +{ + CLK(13); + m37710i_push_8(REG_PB>>16); + m37710i_push_16(REG_PC); + m37710i_push_8(m_ipl); + m37710i_push_8(m37710i_get_reg_p()); + FLAG_I = IFLAG_SET; + REG_PB = 0; + REG_PC = m37710_read_16(vector); +} + + + +/* ======================================================================== */ +/* ============================== END OF FILE ============================= */ +/* ======================================================================== */ diff --git a/src/devices/cpu/m37710/m37710.h b/src/devices/cpu/m37710/m37710.h new file mode 100644 index 00000000000..3bcc57ae68d --- /dev/null +++ b/src/devices/cpu/m37710/m37710.h @@ -0,0 +1,2051 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont, Karl Stenerud, hap +#ifndef __M37710_H__ +#define __M37710_H__ + +/* ======================================================================== */ +/* =============================== COPYRIGHT ============================== */ +/* ======================================================================== */ +/* + +M37710 CPU Emulator v0.1 + +*/ + +/* ======================================================================== */ +/* =============================== DEFINES ================================ */ +/* ======================================================================== */ +/* + Input lines - used with cpunum_set_input_line() and the like. + WARNING: these are in the same order as the vector table for simplicity. + Do not alter this order! +*/ + +enum +{ + // these interrupts are maskable + M37710_LINE_ADC = 0, + M37710_LINE_UART1XMIT, + M37710_LINE_UART1RECV, + M37710_LINE_UART0XMIT, + M37710_LINE_UART0RECV, + M37710_LINE_TIMERB2, + M37710_LINE_TIMERB1, + M37710_LINE_TIMERB0, + M37710_LINE_TIMERA4, + M37710_LINE_TIMERA3, + M37710_LINE_TIMERA2, + M37710_LINE_TIMERA1, + M37710_LINE_TIMERA0, + M37710_LINE_IRQ2, + M37710_LINE_IRQ1, + M37710_LINE_IRQ0, + // these interrupts are non-maskable + M37710_LINE_WATCHDOG, + M37710_LINE_DEBUG, + M37710_LINE_BRK, + M37710_LINE_ZERODIV, + M37710_LINE_RESET, + + // these are not interrupts, they're signals external hardware can send + M37710_LINE_TIMERA0TICK, + M37710_LINE_TIMERA1TICK, + M37710_LINE_TIMERA2TICK, + M37710_LINE_TIMERA3TICK, + M37710_LINE_TIMERA4TICK, + M37710_LINE_TIMERB0TICK, + M37710_LINE_TIMERB1TICK, + M37710_LINE_TIMERB2TICK, + + M37710_LINE_MAX +}; + +/* Registers - used by m37710_set_reg() and m37710_get_reg() */ +enum +{ + M37710_PC=1, M37710_S, M37710_P, M37710_A, M37710_B, M37710_X, M37710_Y, + M37710_PB, M37710_DB, M37710_D, M37710_E, + M37710_NMI_STATE, M37710_IRQ_STATE +}; + + +/* I/O ports */ +enum +{ + M37710_PORT0 = 0, + M37710_PORT1, M37710_PORT2, M37710_PORT3, M37710_PORT4, + M37710_PORT5, M37710_PORT6, M37710_PORT7, M37710_PORT8, + + M37710_ADC0_L = 0x10, M37710_ADC0_H, + M37710_ADC1_L, M37710_ADC1_H, M37710_ADC2_L, M37710_ADC2_H, M37710_ADC3_L, M37710_ADC3_H, + M37710_ADC4_L, M37710_ADC4_H, M37710_ADC5_L, M37710_ADC5_H, M37710_ADC6_L, M37710_ADC6_H, + M37710_ADC7_L, M37710_ADC7_H, + + M37710_SER0_REC = 0x20, + M37710_SER0_XMIT, M37710_SER1_REC, M37710_SER1_XMIT +}; + + +// internal ROM region +#define M37710_INTERNAL_ROM_REGION "internal" +#define M37710_INTERNAL_ROM(_tag) (_tag ":" M37710_INTERNAL_ROM_REGION) + +class m37710_cpu_device : public cpu_device +{ +public: + // construction/destruction + m37710_cpu_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source, address_map_delegate map_delegate); + + DECLARE_READ16_MEMBER( m37710_internal_word_r ); + DECLARE_WRITE16_MEMBER( m37710_internal_word_w ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_execute_interface overrides + virtual UINT32 execute_min_cycles() const { return 1; } + virtual UINT32 execute_max_cycles() const { return 20; /* rough guess */ } + virtual UINT32 execute_input_lines() const { return M37710_LINE_MAX; } + virtual void execute_run(); + virtual void execute_set_input(int inputnum, int state); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const { return (spacenum == AS_PROGRAM) ? &m_program_config : ( (spacenum == AS_IO) ? &m_io_config : NULL ); } + + // device_state_interface overrides + virtual void state_import(const device_state_entry &entry); + virtual void state_export(const device_state_entry &entry); + void state_string_export(const device_state_entry &entry, std::string &str); + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const { return 1; } + virtual UINT32 disasm_max_opcode_bytes() const { return 6; } + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + +private: + address_space_config m_program_config; + address_space_config m_io_config; + + UINT32 m_a; /* Accumulator */ + UINT32 m_b; /* holds high byte of accumulator */ + UINT32 m_ba; /* Secondary Accumulator */ + UINT32 m_bb; /* holds high byte of secondary accumulator */ + UINT32 m_x; /* Index Register X */ + UINT32 m_y; /* Index Register Y */ + UINT32 m_xh; /* holds high byte of x */ + UINT32 m_yh; /* holds high byte of y */ + UINT32 m_s; /* Stack Pointer */ + UINT32 m_pc; /* Program Counter */ + UINT32 m_ppc; /* Previous Program Counter */ + UINT32 m_pb; /* Program Bank (shifted left 16) */ + UINT32 m_db; /* Data Bank (shifted left 16) */ + UINT32 m_d; /* Direct Register */ + UINT32 m_flag_e; /* Emulation Mode Flag */ + UINT32 m_flag_m; /* Memory/Accumulator Select Flag */ + UINT32 m_flag_x; /* Index Select Flag */ + UINT32 m_flag_n; /* Negative Flag */ + UINT32 m_flag_v; /* Overflow Flag */ + UINT32 m_flag_d; /* Decimal Mode Flag */ + UINT32 m_flag_i; /* Interrupt Mask Flag */ + UINT32 m_flag_z; /* Zero Flag (inverted) */ + UINT32 m_flag_c; /* Carry Flag */ + UINT32 m_line_irq; /* Bitmask of pending IRQs */ + UINT32 m_ipl; /* Interrupt priority level (top of PSW) */ + UINT32 m_ir; /* Instruction Register */ + UINT32 m_im; /* Immediate load value */ + UINT32 m_im2; /* Immediate load target */ + UINT32 m_im3; /* Immediate load target */ + UINT32 m_im4; /* Immediate load target */ + UINT32 m_irq_delay; /* delay 1 instruction before checking irq */ + UINT32 m_irq_level; /* irq level */ + int m_ICount; /* cycle count */ + UINT32 m_source; /* temp register */ + UINT32 m_destination; /* temp register */ + address_space *m_program; + direct_read_data *m_direct; + address_space *m_io; + UINT32 m_stopped; /* Sets how the CPU is stopped */ + + // on-board peripheral stuff + UINT8 m_m37710_regs[128]; + attotime m_reload[8]; + emu_timer *m_timers[8]; + + // for debugger + UINT32 m_debugger_pc; + UINT32 m_debugger_pb; + UINT32 m_debugger_db; + UINT32 m_debugger_p; + UINT32 m_debugger_a; + UINT32 m_debugger_b; + + // Statics + typedef void (m37710_cpu_device::*opcode_func)(); + typedef UINT32 (m37710_cpu_device::*get_reg_func)(int regnum); + typedef void (m37710_cpu_device::*set_reg_func)(int regnum, UINT32 val); + typedef void (m37710_cpu_device::*set_line_func)(int line, int state); + typedef int (m37710_cpu_device::*execute_func)(int cycles); + + static const int m37710_irq_levels[M37710_LINE_MAX]; + static const int m37710_irq_vectors[M37710_LINE_MAX]; + static const char *const m37710_rnames[128]; + static const char *const m37710_tnames[8]; + static const opcode_func *m37710i_opcodes[4]; + static const opcode_func *m37710i_opcodes2[4]; + static const opcode_func *m37710i_opcodes3[4]; + static const get_reg_func m37710i_get_reg[4]; + static const set_reg_func m37710i_set_reg[4]; + static const set_line_func m37710i_set_line[4]; + static const execute_func m37710i_execute[4]; + static const opcode_func m37710i_opcodes_M0X0[]; + static const opcode_func m37710i_opcodes_M0X1[]; + static const opcode_func m37710i_opcodes_M1X0[]; + static const opcode_func m37710i_opcodes_M1X1[]; + static const opcode_func m37710i_opcodes42_M0X0[]; + static const opcode_func m37710i_opcodes42_M0X1[]; + static const opcode_func m37710i_opcodes42_M1X0[]; + static const opcode_func m37710i_opcodes42_M1X1[]; + static const opcode_func m37710i_opcodes89_M0X0[]; + static const opcode_func m37710i_opcodes89_M0X1[]; + static const opcode_func m37710i_opcodes89_M1X0[]; + static const opcode_func m37710i_opcodes89_M1X1[]; + + const opcode_func *m_opcodes; /* opcodes with no prefix */ + const opcode_func *m_opcodes42; /* opcodes with 0x42 prefix */ + const opcode_func *m_opcodes89; /* opcodes with 0x89 prefix */ + get_reg_func m_get_reg; + set_reg_func m_set_reg; + set_line_func m_set_line; + execute_func m_execute; + + // Implementation + void m37710i_set_execution_mode(UINT32 mode); + TIMER_CALLBACK_MEMBER( m37710_timer_cb ); + void m37710_external_tick(int timer, int state); + void m37710_recalc_timer(int timer); + UINT8 m37710_internal_r(int offset); + void m37710_internal_w(int offset, UINT8 data); + UINT32 m37710i_get_reg_M0X0(int regnum); + UINT32 m37710i_get_reg_M0X1(int regnum); + UINT32 m37710i_get_reg_M1X0(int regnum); + UINT32 m37710i_get_reg_M1X1(int regnum); + void m37710i_set_reg_M0X0(int regnum, UINT32 val); + void m37710i_set_reg_M0X1(int regnum, UINT32 val); + void m37710i_set_reg_M1X0(int regnum, UINT32 val); + void m37710i_set_reg_M1X1(int regnum, UINT32 val); + void m37710i_set_line_M0X0(int line, int state); + void m37710i_set_line_M0X1(int line, int state); + void m37710i_set_line_M1X0(int line, int state); + void m37710i_set_line_M1X1(int line, int state); + int m37710i_execute_M0X0(int cycles); + int m37710i_execute_M0X1(int cycles); + int m37710i_execute_M1X0(int cycles); + int m37710i_execute_M1X1(int cycles); + void m37710i_update_irqs(); + void m37710_set_pc(unsigned val); + unsigned m37710_get_sp(); + void m37710_set_sp(unsigned val); + unsigned m37710_get_reg(int regnum); + void m37710_set_reg(int regnum, unsigned value); + void m37710_set_irq_line(int line, int state); + void m37710_restore_state(); + UINT32 m37710i_read_8_normal(UINT32 address); + UINT32 m37710i_read_8_immediate(UINT32 address); + UINT32 m37710i_read_8_direct(UINT32 address); + void m37710i_write_8_normal(UINT32 address, UINT32 value); + void m37710i_write_8_direct(UINT32 address, UINT32 value); + UINT32 m37710i_read_16_normal(UINT32 address); + UINT32 m37710i_read_16_immediate(UINT32 address); + UINT32 m37710i_read_16_direct(UINT32 address); + void m37710i_write_16_normal(UINT32 address, UINT32 value); + void m37710i_write_16_direct(UINT32 address, UINT32 value); + UINT32 m37710i_read_24_normal(UINT32 address); + UINT32 m37710i_read_24_immediate(UINT32 address); + UINT32 m37710i_read_24_direct(UINT32 address); + void m37710i_push_8(UINT32 value); + UINT32 m37710i_pull_8(); + void m37710i_push_16(UINT32 value); + UINT32 m37710i_pull_16(); + void m37710i_push_24(UINT32 value); + UINT32 m37710i_pull_24(); + void m37710i_jump_16(UINT32 address); + void m37710i_jump_24(UINT32 address); + void m37710i_branch_8(UINT32 offset); + void m37710i_branch_16(UINT32 offset); + UINT32 m37710i_get_reg_p(); + void m37710i_set_reg_ipl(UINT32 value); + void m37710i_interrupt_software(UINT32 vector); + void m37710i_set_flag_m0x0(UINT32 value); + void m37710i_set_flag_m0x1(UINT32 value); + void m37710i_set_flag_m1x0(UINT32 value); + void m37710i_set_flag_m1x1(UINT32 value); + void m37710i_set_reg_p_m0x0(UINT32 value); + void m37710i_set_reg_p_m0x1(UINT32 value); + void m37710i_set_reg_p_m1x0(UINT32 value); + void m37710i_set_reg_p_m1x1(UINT32 value); + UINT32 EA_IMM8(); + UINT32 EA_IMM16(); + UINT32 EA_IMM24(); + UINT32 EA_D(); + UINT32 EA_A(); + UINT32 EA_AL(); + UINT32 EA_DX(); + UINT32 EA_DY(); + UINT32 EA_AX(); + UINT32 EA_ALX(); + UINT32 EA_AY(); + UINT32 EA_DI(); + UINT32 EA_DLI(); + UINT32 EA_AI(); + UINT32 EA_ALI(); + UINT32 EA_DXI(); + UINT32 EA_DIY(); + UINT32 EA_DLIY(); + UINT32 EA_AXI(); + UINT32 EA_S(); + UINT32 EA_SIY(); + void m37710i_00_M0X0(); + void m37710i_01_M0X0(); + void m37710i_02_M0X0(); + void m37710i_03_M0X0(); + void m37710i_04_M0X0(); + void m37710i_05_M0X0(); + void m37710i_06_M0X0(); + void m37710i_07_M0X0(); + void m37710i_08_M0X0(); + void m37710i_09_M0X0(); + void m37710i_0a_M0X0(); + void m37710i_0b_M0X0(); + void m37710i_0c_M0X0(); + void m37710i_0d_M0X0(); + void m37710i_0e_M0X0(); + void m37710i_0f_M0X0(); + void m37710i_10_M0X0(); + void m37710i_11_M0X0(); + void m37710i_12_M0X0(); + void m37710i_13_M0X0(); + void m37710i_14_M0X0(); + void m37710i_15_M0X0(); + void m37710i_16_M0X0(); + void m37710i_17_M0X0(); + void m37710i_18_M0X0(); + void m37710i_19_M0X0(); + void m37710i_1a_M0X0(); + void m37710i_1b_M0X0(); + void m37710i_1c_M0X0(); + void m37710i_1d_M0X0(); + void m37710i_1e_M0X0(); + void m37710i_1f_M0X0(); + void m37710i_20_M0X0(); + void m37710i_21_M0X0(); + void m37710i_22_M0X0(); + void m37710i_23_M0X0(); + void m37710i_24_M0X0(); + void m37710i_25_M0X0(); + void m37710i_26_M0X0(); + void m37710i_27_M0X0(); + void m37710i_28_M0X0(); + void m37710i_29_M0X0(); + void m37710i_2a_M0X0(); + void m37710i_2b_M0X0(); + void m37710i_2c_M0X0(); + void m37710i_2d_M0X0(); + void m37710i_2e_M0X0(); + void m37710i_2f_M0X0(); + void m37710i_30_M0X0(); + void m37710i_31_M0X0(); + void m37710i_32_M0X0(); + void m37710i_33_M0X0(); + void m37710i_34_M0X0(); + void m37710i_35_M0X0(); + void m37710i_36_M0X0(); + void m37710i_37_M0X0(); + void m37710i_38_M0X0(); + void m37710i_39_M0X0(); + void m37710i_3a_M0X0(); + void m37710i_3b_M0X0(); + void m37710i_3c_M0X0(); + void m37710i_3d_M0X0(); + void m37710i_3e_M0X0(); + void m37710i_3f_M0X0(); + void m37710i_40_M0X0(); + void m37710i_41_M0X0(); + void m37710i_42_M0X0(); + void m37710i_43_M0X0(); + void m37710i_44_M0X0(); + void m37710i_45_M0X0(); + void m37710i_46_M0X0(); + void m37710i_47_M0X0(); + void m37710i_48_M0X0(); + void m37710i_49_M0X0(); + void m37710i_4a_M0X0(); + void m37710i_4b_M0X0(); + void m37710i_4c_M0X0(); + void m37710i_4d_M0X0(); + void m37710i_4e_M0X0(); + void m37710i_4f_M0X0(); + void m37710i_50_M0X0(); + void m37710i_51_M0X0(); + void m37710i_52_M0X0(); + void m37710i_53_M0X0(); + void m37710i_54_M0X0(); + void m37710i_55_M0X0(); + void m37710i_56_M0X0(); + void m37710i_57_M0X0(); + void m37710i_58_M0X0(); + void m37710i_59_M0X0(); + void m37710i_5a_M0X0(); + void m37710i_5b_M0X0(); + void m37710i_5c_M0X0(); + void m37710i_5d_M0X0(); + void m37710i_5e_M0X0(); + void m37710i_5f_M0X0(); + void m37710i_60_M0X0(); + void m37710i_61_M0X0(); + void m37710i_62_M0X0(); + void m37710i_63_M0X0(); + void m37710i_64_M0X0(); + void m37710i_65_M0X0(); + void m37710i_66_M0X0(); + void m37710i_67_M0X0(); + void m37710i_68_M0X0(); + void m37710i_69_M0X0(); + void m37710i_6a_M0X0(); + void m37710i_6b_M0X0(); + void m37710i_6c_M0X0(); + void m37710i_6d_M0X0(); + void m37710i_6e_M0X0(); + void m37710i_6f_M0X0(); + void m37710i_70_M0X0(); + void m37710i_71_M0X0(); + void m37710i_72_M0X0(); + void m37710i_73_M0X0(); + void m37710i_74_M0X0(); + void m37710i_75_M0X0(); + void m37710i_76_M0X0(); + void m37710i_77_M0X0(); + void m37710i_78_M0X0(); + void m37710i_79_M0X0(); + void m37710i_7a_M0X0(); + void m37710i_7b_M0X0(); + void m37710i_7c_M0X0(); + void m37710i_7d_M0X0(); + void m37710i_7e_M0X0(); + void m37710i_7f_M0X0(); + void m37710i_80_M0X0(); + void m37710i_81_M0X0(); + void m37710i_82_M0X0(); + void m37710i_83_M0X0(); + void m37710i_84_M0X0(); + void m37710i_85_M0X0(); + void m37710i_86_M0X0(); + void m37710i_87_M0X0(); + void m37710i_88_M0X0(); + void m37710i_89_M0X0(); + void m37710i_8a_M0X0(); + void m37710i_8b_M0X0(); + void m37710i_8c_M0X0(); + void m37710i_8d_M0X0(); + void m37710i_8e_M0X0(); + void m37710i_8f_M0X0(); + void m37710i_90_M0X0(); + void m37710i_91_M0X0(); + void m37710i_92_M0X0(); + void m37710i_93_M0X0(); + void m37710i_94_M0X0(); + void m37710i_95_M0X0(); + void m37710i_96_M0X0(); + void m37710i_97_M0X0(); + void m37710i_98_M0X0(); + void m37710i_99_M0X0(); + void m37710i_9a_M0X0(); + void m37710i_9b_M0X0(); + void m37710i_9c_M0X0(); + void m37710i_9d_M0X0(); + void m37710i_9e_M0X0(); + void m37710i_9f_M0X0(); + void m37710i_a0_M0X0(); + void m37710i_a1_M0X0(); + void m37710i_a2_M0X0(); + void m37710i_a3_M0X0(); + void m37710i_a4_M0X0(); + void m37710i_a5_M0X0(); + void m37710i_a6_M0X0(); + void m37710i_a7_M0X0(); + void m37710i_a8_M0X0(); + void m37710i_a9_M0X0(); + void m37710i_aa_M0X0(); + void m37710i_ab_M0X0(); + void m37710i_ac_M0X0(); + void m37710i_ad_M0X0(); + void m37710i_ae_M0X0(); + void m37710i_af_M0X0(); + void m37710i_b0_M0X0(); + void m37710i_b1_M0X0(); + void m37710i_b2_M0X0(); + void m37710i_b3_M0X0(); + void m37710i_b4_M0X0(); + void m37710i_b5_M0X0(); + void m37710i_b6_M0X0(); + void m37710i_b7_M0X0(); + void m37710i_b8_M0X0(); + void m37710i_b9_M0X0(); + void m37710i_ba_M0X0(); + void m37710i_bb_M0X0(); + void m37710i_bc_M0X0(); + void m37710i_bd_M0X0(); + void m37710i_be_M0X0(); + void m37710i_bf_M0X0(); + void m37710i_c0_M0X0(); + void m37710i_c1_M0X0(); + void m37710i_c2_M0X0(); + void m37710i_c3_M0X0(); + void m37710i_c4_M0X0(); + void m37710i_c5_M0X0(); + void m37710i_c6_M0X0(); + void m37710i_c7_M0X0(); + void m37710i_c8_M0X0(); + void m37710i_c9_M0X0(); + void m37710i_ca_M0X0(); + void m37710i_cb_M0X0(); + void m37710i_cc_M0X0(); + void m37710i_cd_M0X0(); + void m37710i_ce_M0X0(); + void m37710i_cf_M0X0(); + void m37710i_d0_M0X0(); + void m37710i_d1_M0X0(); + void m37710i_d2_M0X0(); + void m37710i_d3_M0X0(); + void m37710i_d4_M0X0(); + void m37710i_d5_M0X0(); + void m37710i_d6_M0X0(); + void m37710i_d7_M0X0(); + void m37710i_d8_M0X0(); + void m37710i_d9_M0X0(); + void m37710i_da_M0X0(); + void m37710i_db_M0X0(); + void m37710i_dc_M0X0(); + void m37710i_dd_M0X0(); + void m37710i_de_M0X0(); + void m37710i_df_M0X0(); + void m37710i_e0_M0X0(); + void m37710i_e1_M0X0(); + void m37710i_e2_M0X0(); + void m37710i_e3_M0X0(); + void m37710i_e4_M0X0(); + void m37710i_e5_M0X0(); + void m37710i_e6_M0X0(); + void m37710i_e7_M0X0(); + void m37710i_e8_M0X0(); + void m37710i_e9_M0X0(); + void m37710i_ea_M0X0(); + void m37710i_eb_M0X0(); + void m37710i_ec_M0X0(); + void m37710i_ed_M0X0(); + void m37710i_ee_M0X0(); + void m37710i_ef_M0X0(); + void m37710i_f0_M0X0(); + void m37710i_f1_M0X0(); + void m37710i_f2_M0X0(); + void m37710i_f3_M0X0(); + void m37710i_f4_M0X0(); + void m37710i_f5_M0X0(); + void m37710i_f6_M0X0(); + void m37710i_f7_M0X0(); + void m37710i_f8_M0X0(); + void m37710i_f9_M0X0(); + void m37710i_fa_M0X0(); + void m37710i_fb_M0X0(); + void m37710i_fc_M0X0(); + void m37710i_fd_M0X0(); + void m37710i_fe_M0X0(); + void m37710i_ff_M0X0(); + void m37710i_101_M0X0(); + void m37710i_103_M0X0(); + void m37710i_105_M0X0(); + void m37710i_107_M0X0(); + void m37710i_109_M0X0(); + void m37710i_10a_M0X0(); + void m37710i_10d_M0X0(); + void m37710i_10f_M0X0(); + void m37710i_111_M0X0(); + void m37710i_112_M0X0(); + void m37710i_113_M0X0(); + void m37710i_115_M0X0(); + void m37710i_117_M0X0(); + void m37710i_119_M0X0(); + void m37710i_11a_M0X0(); + void m37710i_11b_M0X0(); + void m37710i_11d_M0X0(); + void m37710i_11f_M0X0(); + void m37710i_121_M0X0(); + void m37710i_123_M0X0(); + void m37710i_125_M0X0(); + void m37710i_127_M0X0(); + void m37710i_129_M0X0(); + void m37710i_12a_M0X0(); + void m37710i_12d_M0X0(); + void m37710i_12f_M0X0(); + void m37710i_131_M0X0(); + void m37710i_132_M0X0(); + void m37710i_133_M0X0(); + void m37710i_135_M0X0(); + void m37710i_137_M0X0(); + void m37710i_139_M0X0(); + void m37710i_13a_M0X0(); + void m37710i_13b_M0X0(); + void m37710i_13d_M0X0(); + void m37710i_13f_M0X0(); + void m37710i_141_M0X0(); + void m37710i_143_M0X0(); + void m37710i_145_M0X0(); + void m37710i_147_M0X0(); + void m37710i_148_M0X0(); + void m37710i_149_M0X0(); + void m37710i_14a_M0X0(); + void m37710i_14d_M0X0(); + void m37710i_14f_M0X0(); + void m37710i_151_M0X0(); + void m37710i_152_M0X0(); + void m37710i_153_M0X0(); + void m37710i_155_M0X0(); + void m37710i_157_M0X0(); + void m37710i_159_M0X0(); + void m37710i_15b_M0X0(); + void m37710i_15d_M0X0(); + void m37710i_15f_M0X0(); + void m37710i_161_M0X0(); + void m37710i_163_M0X0(); + void m37710i_165_M0X0(); + void m37710i_167_M0X0(); + void m37710i_168_M0X0(); + void m37710i_169_M0X0(); + void m37710i_16a_M0X0(); + void m37710i_16d_M0X0(); + void m37710i_16f_M0X0(); + void m37710i_171_M0X0(); + void m37710i_172_M0X0(); + void m37710i_173_M0X0(); + void m37710i_175_M0X0(); + void m37710i_177_M0X0(); + void m37710i_179_M0X0(); + void m37710i_17b_M0X0(); + void m37710i_17d_M0X0(); + void m37710i_17f_M0X0(); + void m37710i_181_M0X0(); + void m37710i_183_M0X0(); + void m37710i_185_M0X0(); + void m37710i_187_M0X0(); + void m37710i_18a_M0X0(); + void m37710i_18d_M0X0(); + void m37710i_18f_M0X0(); + void m37710i_191_M0X0(); + void m37710i_192_M0X0(); + void m37710i_193_M0X0(); + void m37710i_195_M0X0(); + void m37710i_197_M0X0(); + void m37710i_198_M0X0(); + void m37710i_199_M0X0(); + void m37710i_19d_M0X0(); + void m37710i_19f_M0X0(); + void m37710i_1a1_M0X0(); + void m37710i_1a3_M0X0(); + void m37710i_1a5_M0X0(); + void m37710i_1a7_M0X0(); + void m37710i_1a8_M0X0(); + void m37710i_1a9_M0X0(); + void m37710i_1aa_M0X0(); + void m37710i_1ad_M0X0(); + void m37710i_1af_M0X0(); + void m37710i_1b1_M0X0(); + void m37710i_1b2_M0X0(); + void m37710i_1b3_M0X0(); + void m37710i_1b5_M0X0(); + void m37710i_1b7_M0X0(); + void m37710i_1b9_M0X0(); + void m37710i_1bd_M0X0(); + void m37710i_1bf_M0X0(); + void m37710i_1c1_M0X0(); + void m37710i_1c3_M0X0(); + void m37710i_1c5_M0X0(); + void m37710i_1c7_M0X0(); + void m37710i_1c9_M0X0(); + void m37710i_1cd_M0X0(); + void m37710i_1cf_M0X0(); + void m37710i_1d1_M0X0(); + void m37710i_1d2_M0X0(); + void m37710i_1d3_M0X0(); + void m37710i_1d5_M0X0(); + void m37710i_1d7_M0X0(); + void m37710i_1d9_M0X0(); + void m37710i_1dd_M0X0(); + void m37710i_1df_M0X0(); + void m37710i_1e1_M0X0(); + void m37710i_1e3_M0X0(); + void m37710i_1e5_M0X0(); + void m37710i_1e7_M0X0(); + void m37710i_1e9_M0X0(); + void m37710i_1ed_M0X0(); + void m37710i_1ef_M0X0(); + void m37710i_1f1_M0X0(); + void m37710i_1f2_M0X0(); + void m37710i_1f3_M0X0(); + void m37710i_1f5_M0X0(); + void m37710i_1f7_M0X0(); + void m37710i_1f9_M0X0(); + void m37710i_1fd_M0X0(); + void m37710i_1ff_M0X0(); + void m37710i_200_M0X0(); + void m37710i_201_M0X0(); + void m37710i_203_M0X0(); + void m37710i_205_M0X0(); + void m37710i_207_M0X0(); + void m37710i_209_M0X0(); + void m37710i_20d_M0X0(); + void m37710i_20f_M0X0(); + void m37710i_211_M0X0(); + void m37710i_212_M0X0(); + void m37710i_213_M0X0(); + void m37710i_215_M0X0(); + void m37710i_217_M0X0(); + void m37710i_219_M0X0(); + void m37710i_21d_M0X0(); + void m37710i_21f_M0X0(); + void m37710i_221_M0X0(); + void m37710i_223_M0X0(); + void m37710i_225_M0X0(); + void m37710i_227_M0X0(); + void m37710i_228_M0X0(); + void m37710i_229_M0X0(); + void m37710i_22d_M0X0(); + void m37710i_22f_M0X0(); + void m37710i_231_M0X0(); + void m37710i_232_M0X0(); + void m37710i_233_M0X0(); + void m37710i_235_M0X0(); + void m37710i_237_M0X0(); + void m37710i_239_M0X0(); + void m37710i_23d_M0X0(); + void m37710i_23f_M0X0(); + void m37710i_249_M0X0(); + void m37710i_2c2_M0X0(); + void m37710i_00_M0X1(); + void m37710i_01_M0X1(); + void m37710i_02_M0X1(); + void m37710i_03_M0X1(); + void m37710i_04_M0X1(); + void m37710i_05_M0X1(); + void m37710i_06_M0X1(); + void m37710i_07_M0X1(); + void m37710i_08_M0X1(); + void m37710i_09_M0X1(); + void m37710i_0a_M0X1(); + void m37710i_0b_M0X1(); + void m37710i_0c_M0X1(); + void m37710i_0d_M0X1(); + void m37710i_0e_M0X1(); + void m37710i_0f_M0X1(); + void m37710i_10_M0X1(); + void m37710i_11_M0X1(); + void m37710i_12_M0X1(); + void m37710i_13_M0X1(); + void m37710i_14_M0X1(); + void m37710i_15_M0X1(); + void m37710i_16_M0X1(); + void m37710i_17_M0X1(); + void m37710i_18_M0X1(); + void m37710i_19_M0X1(); + void m37710i_1a_M0X1(); + void m37710i_1b_M0X1(); + void m37710i_1c_M0X1(); + void m37710i_1d_M0X1(); + void m37710i_1e_M0X1(); + void m37710i_1f_M0X1(); + void m37710i_20_M0X1(); + void m37710i_21_M0X1(); + void m37710i_22_M0X1(); + void m37710i_23_M0X1(); + void m37710i_24_M0X1(); + void m37710i_25_M0X1(); + void m37710i_26_M0X1(); + void m37710i_27_M0X1(); + void m37710i_28_M0X1(); + void m37710i_29_M0X1(); + void m37710i_2a_M0X1(); + void m37710i_2b_M0X1(); + void m37710i_2c_M0X1(); + void m37710i_2d_M0X1(); + void m37710i_2e_M0X1(); + void m37710i_2f_M0X1(); + void m37710i_30_M0X1(); + void m37710i_31_M0X1(); + void m37710i_32_M0X1(); + void m37710i_33_M0X1(); + void m37710i_34_M0X1(); + void m37710i_35_M0X1(); + void m37710i_36_M0X1(); + void m37710i_37_M0X1(); + void m37710i_38_M0X1(); + void m37710i_39_M0X1(); + void m37710i_3a_M0X1(); + void m37710i_3b_M0X1(); + void m37710i_3c_M0X1(); + void m37710i_3d_M0X1(); + void m37710i_3e_M0X1(); + void m37710i_3f_M0X1(); + void m37710i_40_M0X1(); + void m37710i_41_M0X1(); + void m37710i_42_M0X1(); + void m37710i_43_M0X1(); + void m37710i_44_M0X1(); + void m37710i_45_M0X1(); + void m37710i_46_M0X1(); + void m37710i_47_M0X1(); + void m37710i_48_M0X1(); + void m37710i_49_M0X1(); + void m37710i_4a_M0X1(); + void m37710i_4b_M0X1(); + void m37710i_4c_M0X1(); + void m37710i_4d_M0X1(); + void m37710i_4e_M0X1(); + void m37710i_4f_M0X1(); + void m37710i_50_M0X1(); + void m37710i_51_M0X1(); + void m37710i_52_M0X1(); + void m37710i_53_M0X1(); + void m37710i_54_M0X1(); + void m37710i_55_M0X1(); + void m37710i_56_M0X1(); + void m37710i_57_M0X1(); + void m37710i_58_M0X1(); + void m37710i_59_M0X1(); + void m37710i_5a_M0X1(); + void m37710i_5b_M0X1(); + void m37710i_5c_M0X1(); + void m37710i_5d_M0X1(); + void m37710i_5e_M0X1(); + void m37710i_5f_M0X1(); + void m37710i_60_M0X1(); + void m37710i_61_M0X1(); + void m37710i_62_M0X1(); + void m37710i_63_M0X1(); + void m37710i_64_M0X1(); + void m37710i_65_M0X1(); + void m37710i_66_M0X1(); + void m37710i_67_M0X1(); + void m37710i_68_M0X1(); + void m37710i_69_M0X1(); + void m37710i_6a_M0X1(); + void m37710i_6b_M0X1(); + void m37710i_6c_M0X1(); + void m37710i_6d_M0X1(); + void m37710i_6e_M0X1(); + void m37710i_6f_M0X1(); + void m37710i_70_M0X1(); + void m37710i_71_M0X1(); + void m37710i_72_M0X1(); + void m37710i_73_M0X1(); + void m37710i_74_M0X1(); + void m37710i_75_M0X1(); + void m37710i_76_M0X1(); + void m37710i_77_M0X1(); + void m37710i_78_M0X1(); + void m37710i_79_M0X1(); + void m37710i_7a_M0X1(); + void m37710i_7b_M0X1(); + void m37710i_7c_M0X1(); + void m37710i_7d_M0X1(); + void m37710i_7e_M0X1(); + void m37710i_7f_M0X1(); + void m37710i_80_M0X1(); + void m37710i_81_M0X1(); + void m37710i_82_M0X1(); + void m37710i_83_M0X1(); + void m37710i_84_M0X1(); + void m37710i_85_M0X1(); + void m37710i_86_M0X1(); + void m37710i_87_M0X1(); + void m37710i_88_M0X1(); + void m37710i_89_M0X1(); + void m37710i_8a_M0X1(); + void m37710i_8b_M0X1(); + void m37710i_8c_M0X1(); + void m37710i_8d_M0X1(); + void m37710i_8e_M0X1(); + void m37710i_8f_M0X1(); + void m37710i_90_M0X1(); + void m37710i_91_M0X1(); + void m37710i_92_M0X1(); + void m37710i_93_M0X1(); + void m37710i_94_M0X1(); + void m37710i_95_M0X1(); + void m37710i_96_M0X1(); + void m37710i_97_M0X1(); + void m37710i_98_M0X1(); + void m37710i_99_M0X1(); + void m37710i_9a_M0X1(); + void m37710i_9b_M0X1(); + void m37710i_9c_M0X1(); + void m37710i_9d_M0X1(); + void m37710i_9e_M0X1(); + void m37710i_9f_M0X1(); + void m37710i_a0_M0X1(); + void m37710i_a1_M0X1(); + void m37710i_a2_M0X1(); + void m37710i_a3_M0X1(); + void m37710i_a4_M0X1(); + void m37710i_a5_M0X1(); + void m37710i_a6_M0X1(); + void m37710i_a7_M0X1(); + void m37710i_a8_M0X1(); + void m37710i_a9_M0X1(); + void m37710i_aa_M0X1(); + void m37710i_ab_M0X1(); + void m37710i_ac_M0X1(); + void m37710i_ad_M0X1(); + void m37710i_ae_M0X1(); + void m37710i_af_M0X1(); + void m37710i_b0_M0X1(); + void m37710i_b1_M0X1(); + void m37710i_b2_M0X1(); + void m37710i_b3_M0X1(); + void m37710i_b4_M0X1(); + void m37710i_b5_M0X1(); + void m37710i_b6_M0X1(); + void m37710i_b7_M0X1(); + void m37710i_b8_M0X1(); + void m37710i_b9_M0X1(); + void m37710i_ba_M0X1(); + void m37710i_bb_M0X1(); + void m37710i_bc_M0X1(); + void m37710i_bd_M0X1(); + void m37710i_be_M0X1(); + void m37710i_bf_M0X1(); + void m37710i_c0_M0X1(); + void m37710i_c1_M0X1(); + void m37710i_c2_M0X1(); + void m37710i_c3_M0X1(); + void m37710i_c4_M0X1(); + void m37710i_c5_M0X1(); + void m37710i_c6_M0X1(); + void m37710i_c7_M0X1(); + void m37710i_c8_M0X1(); + void m37710i_c9_M0X1(); + void m37710i_ca_M0X1(); + void m37710i_cb_M0X1(); + void m37710i_cc_M0X1(); + void m37710i_cd_M0X1(); + void m37710i_ce_M0X1(); + void m37710i_cf_M0X1(); + void m37710i_d0_M0X1(); + void m37710i_d1_M0X1(); + void m37710i_d2_M0X1(); + void m37710i_d3_M0X1(); + void m37710i_d4_M0X1(); + void m37710i_d5_M0X1(); + void m37710i_d6_M0X1(); + void m37710i_d7_M0X1(); + void m37710i_d8_M0X1(); + void m37710i_d9_M0X1(); + void m37710i_da_M0X1(); + void m37710i_db_M0X1(); + void m37710i_dc_M0X1(); + void m37710i_dd_M0X1(); + void m37710i_de_M0X1(); + void m37710i_df_M0X1(); + void m37710i_e0_M0X1(); + void m37710i_e1_M0X1(); + void m37710i_e2_M0X1(); + void m37710i_e3_M0X1(); + void m37710i_e4_M0X1(); + void m37710i_e5_M0X1(); + void m37710i_e6_M0X1(); + void m37710i_e7_M0X1(); + void m37710i_e8_M0X1(); + void m37710i_e9_M0X1(); + void m37710i_ea_M0X1(); + void m37710i_eb_M0X1(); + void m37710i_ec_M0X1(); + void m37710i_ed_M0X1(); + void m37710i_ee_M0X1(); + void m37710i_ef_M0X1(); + void m37710i_f0_M0X1(); + void m37710i_f1_M0X1(); + void m37710i_f2_M0X1(); + void m37710i_f3_M0X1(); + void m37710i_f4_M0X1(); + void m37710i_f5_M0X1(); + void m37710i_f6_M0X1(); + void m37710i_f7_M0X1(); + void m37710i_f8_M0X1(); + void m37710i_f9_M0X1(); + void m37710i_fa_M0X1(); + void m37710i_fb_M0X1(); + void m37710i_fc_M0X1(); + void m37710i_fd_M0X1(); + void m37710i_fe_M0X1(); + void m37710i_ff_M0X1(); + void m37710i_101_M0X1(); + void m37710i_103_M0X1(); + void m37710i_105_M0X1(); + void m37710i_107_M0X1(); + void m37710i_109_M0X1(); + void m37710i_10a_M0X1(); + void m37710i_10d_M0X1(); + void m37710i_10f_M0X1(); + void m37710i_111_M0X1(); + void m37710i_112_M0X1(); + void m37710i_113_M0X1(); + void m37710i_115_M0X1(); + void m37710i_117_M0X1(); + void m37710i_119_M0X1(); + void m37710i_11a_M0X1(); + void m37710i_11b_M0X1(); + void m37710i_11d_M0X1(); + void m37710i_11f_M0X1(); + void m37710i_121_M0X1(); + void m37710i_123_M0X1(); + void m37710i_125_M0X1(); + void m37710i_127_M0X1(); + void m37710i_129_M0X1(); + void m37710i_12a_M0X1(); + void m37710i_12d_M0X1(); + void m37710i_12f_M0X1(); + void m37710i_131_M0X1(); + void m37710i_132_M0X1(); + void m37710i_133_M0X1(); + void m37710i_135_M0X1(); + void m37710i_137_M0X1(); + void m37710i_139_M0X1(); + void m37710i_13a_M0X1(); + void m37710i_13b_M0X1(); + void m37710i_13d_M0X1(); + void m37710i_13f_M0X1(); + void m37710i_141_M0X1(); + void m37710i_143_M0X1(); + void m37710i_145_M0X1(); + void m37710i_147_M0X1(); + void m37710i_148_M0X1(); + void m37710i_149_M0X1(); + void m37710i_14a_M0X1(); + void m37710i_14d_M0X1(); + void m37710i_14f_M0X1(); + void m37710i_151_M0X1(); + void m37710i_152_M0X1(); + void m37710i_153_M0X1(); + void m37710i_155_M0X1(); + void m37710i_157_M0X1(); + void m37710i_159_M0X1(); + void m37710i_15b_M0X1(); + void m37710i_15d_M0X1(); + void m37710i_15f_M0X1(); + void m37710i_161_M0X1(); + void m37710i_163_M0X1(); + void m37710i_165_M0X1(); + void m37710i_167_M0X1(); + void m37710i_168_M0X1(); + void m37710i_169_M0X1(); + void m37710i_16a_M0X1(); + void m37710i_16d_M0X1(); + void m37710i_16f_M0X1(); + void m37710i_171_M0X1(); + void m37710i_172_M0X1(); + void m37710i_173_M0X1(); + void m37710i_175_M0X1(); + void m37710i_177_M0X1(); + void m37710i_179_M0X1(); + void m37710i_17b_M0X1(); + void m37710i_17d_M0X1(); + void m37710i_17f_M0X1(); + void m37710i_181_M0X1(); + void m37710i_183_M0X1(); + void m37710i_185_M0X1(); + void m37710i_187_M0X1(); + void m37710i_18a_M0X1(); + void m37710i_18d_M0X1(); + void m37710i_18f_M0X1(); + void m37710i_191_M0X1(); + void m37710i_192_M0X1(); + void m37710i_193_M0X1(); + void m37710i_195_M0X1(); + void m37710i_197_M0X1(); + void m37710i_198_M0X1(); + void m37710i_199_M0X1(); + void m37710i_19d_M0X1(); + void m37710i_19f_M0X1(); + void m37710i_1a1_M0X1(); + void m37710i_1a3_M0X1(); + void m37710i_1a5_M0X1(); + void m37710i_1a7_M0X1(); + void m37710i_1a8_M0X1(); + void m37710i_1a9_M0X1(); + void m37710i_1aa_M0X1(); + void m37710i_1ad_M0X1(); + void m37710i_1af_M0X1(); + void m37710i_1b1_M0X1(); + void m37710i_1b2_M0X1(); + void m37710i_1b3_M0X1(); + void m37710i_1b5_M0X1(); + void m37710i_1b7_M0X1(); + void m37710i_1b9_M0X1(); + void m37710i_1bd_M0X1(); + void m37710i_1bf_M0X1(); + void m37710i_1c1_M0X1(); + void m37710i_1c3_M0X1(); + void m37710i_1c5_M0X1(); + void m37710i_1c7_M0X1(); + void m37710i_1c9_M0X1(); + void m37710i_1cd_M0X1(); + void m37710i_1cf_M0X1(); + void m37710i_1d1_M0X1(); + void m37710i_1d2_M0X1(); + void m37710i_1d3_M0X1(); + void m37710i_1d5_M0X1(); + void m37710i_1d7_M0X1(); + void m37710i_1d9_M0X1(); + void m37710i_1dd_M0X1(); + void m37710i_1df_M0X1(); + void m37710i_1e1_M0X1(); + void m37710i_1e3_M0X1(); + void m37710i_1e5_M0X1(); + void m37710i_1e7_M0X1(); + void m37710i_1e9_M0X1(); + void m37710i_1ed_M0X1(); + void m37710i_1ef_M0X1(); + void m37710i_1f1_M0X1(); + void m37710i_1f2_M0X1(); + void m37710i_1f3_M0X1(); + void m37710i_1f5_M0X1(); + void m37710i_1f7_M0X1(); + void m37710i_1f9_M0X1(); + void m37710i_1fd_M0X1(); + void m37710i_1ff_M0X1(); + void m37710i_200_M0X1(); + void m37710i_201_M0X1(); + void m37710i_203_M0X1(); + void m37710i_205_M0X1(); + void m37710i_207_M0X1(); + void m37710i_209_M0X1(); + void m37710i_20d_M0X1(); + void m37710i_20f_M0X1(); + void m37710i_211_M0X1(); + void m37710i_212_M0X1(); + void m37710i_213_M0X1(); + void m37710i_215_M0X1(); + void m37710i_217_M0X1(); + void m37710i_219_M0X1(); + void m37710i_21d_M0X1(); + void m37710i_21f_M0X1(); + void m37710i_221_M0X1(); + void m37710i_223_M0X1(); + void m37710i_225_M0X1(); + void m37710i_227_M0X1(); + void m37710i_228_M0X1(); + void m37710i_229_M0X1(); + void m37710i_22d_M0X1(); + void m37710i_22f_M0X1(); + void m37710i_231_M0X1(); + void m37710i_232_M0X1(); + void m37710i_233_M0X1(); + void m37710i_235_M0X1(); + void m37710i_237_M0X1(); + void m37710i_239_M0X1(); + void m37710i_23d_M0X1(); + void m37710i_23f_M0X1(); + void m37710i_249_M0X1(); + void m37710i_2c2_M0X1(); + void m37710i_00_M1X0(); + void m37710i_01_M1X0(); + void m37710i_02_M1X0(); + void m37710i_03_M1X0(); + void m37710i_04_M1X0(); + void m37710i_05_M1X0(); + void m37710i_06_M1X0(); + void m37710i_07_M1X0(); + void m37710i_08_M1X0(); + void m37710i_09_M1X0(); + void m37710i_0a_M1X0(); + void m37710i_0b_M1X0(); + void m37710i_0c_M1X0(); + void m37710i_0d_M1X0(); + void m37710i_0e_M1X0(); + void m37710i_0f_M1X0(); + void m37710i_10_M1X0(); + void m37710i_11_M1X0(); + void m37710i_12_M1X0(); + void m37710i_13_M1X0(); + void m37710i_14_M1X0(); + void m37710i_15_M1X0(); + void m37710i_16_M1X0(); + void m37710i_17_M1X0(); + void m37710i_18_M1X0(); + void m37710i_19_M1X0(); + void m37710i_1a_M1X0(); + void m37710i_1b_M1X0(); + void m37710i_1c_M1X0(); + void m37710i_1d_M1X0(); + void m37710i_1e_M1X0(); + void m37710i_1f_M1X0(); + void m37710i_20_M1X0(); + void m37710i_21_M1X0(); + void m37710i_22_M1X0(); + void m37710i_23_M1X0(); + void m37710i_24_M1X0(); + void m37710i_25_M1X0(); + void m37710i_26_M1X0(); + void m37710i_27_M1X0(); + void m37710i_28_M1X0(); + void m37710i_29_M1X0(); + void m37710i_2a_M1X0(); + void m37710i_2b_M1X0(); + void m37710i_2c_M1X0(); + void m37710i_2d_M1X0(); + void m37710i_2e_M1X0(); + void m37710i_2f_M1X0(); + void m37710i_30_M1X0(); + void m37710i_31_M1X0(); + void m37710i_32_M1X0(); + void m37710i_33_M1X0(); + void m37710i_34_M1X0(); + void m37710i_35_M1X0(); + void m37710i_36_M1X0(); + void m37710i_37_M1X0(); + void m37710i_38_M1X0(); + void m37710i_39_M1X0(); + void m37710i_3a_M1X0(); + void m37710i_3b_M1X0(); + void m37710i_3c_M1X0(); + void m37710i_3d_M1X0(); + void m37710i_3e_M1X0(); + void m37710i_3f_M1X0(); + void m37710i_40_M1X0(); + void m37710i_41_M1X0(); + void m37710i_42_M1X0(); + void m37710i_43_M1X0(); + void m37710i_44_M1X0(); + void m37710i_45_M1X0(); + void m37710i_46_M1X0(); + void m37710i_47_M1X0(); + void m37710i_48_M1X0(); + void m37710i_49_M1X0(); + void m37710i_4a_M1X0(); + void m37710i_4b_M1X0(); + void m37710i_4c_M1X0(); + void m37710i_4d_M1X0(); + void m37710i_4e_M1X0(); + void m37710i_4f_M1X0(); + void m37710i_50_M1X0(); + void m37710i_51_M1X0(); + void m37710i_52_M1X0(); + void m37710i_53_M1X0(); + void m37710i_54_M1X0(); + void m37710i_55_M1X0(); + void m37710i_56_M1X0(); + void m37710i_57_M1X0(); + void m37710i_58_M1X0(); + void m37710i_59_M1X0(); + void m37710i_5a_M1X0(); + void m37710i_5b_M1X0(); + void m37710i_5c_M1X0(); + void m37710i_5d_M1X0(); + void m37710i_5e_M1X0(); + void m37710i_5f_M1X0(); + void m37710i_60_M1X0(); + void m37710i_61_M1X0(); + void m37710i_62_M1X0(); + void m37710i_63_M1X0(); + void m37710i_64_M1X0(); + void m37710i_65_M1X0(); + void m37710i_66_M1X0(); + void m37710i_67_M1X0(); + void m37710i_68_M1X0(); + void m37710i_69_M1X0(); + void m37710i_6a_M1X0(); + void m37710i_6b_M1X0(); + void m37710i_6c_M1X0(); + void m37710i_6d_M1X0(); + void m37710i_6e_M1X0(); + void m37710i_6f_M1X0(); + void m37710i_70_M1X0(); + void m37710i_71_M1X0(); + void m37710i_72_M1X0(); + void m37710i_73_M1X0(); + void m37710i_74_M1X0(); + void m37710i_75_M1X0(); + void m37710i_76_M1X0(); + void m37710i_77_M1X0(); + void m37710i_78_M1X0(); + void m37710i_79_M1X0(); + void m37710i_7a_M1X0(); + void m37710i_7b_M1X0(); + void m37710i_7c_M1X0(); + void m37710i_7d_M1X0(); + void m37710i_7e_M1X0(); + void m37710i_7f_M1X0(); + void m37710i_80_M1X0(); + void m37710i_81_M1X0(); + void m37710i_82_M1X0(); + void m37710i_83_M1X0(); + void m37710i_84_M1X0(); + void m37710i_85_M1X0(); + void m37710i_86_M1X0(); + void m37710i_87_M1X0(); + void m37710i_88_M1X0(); + void m37710i_89_M1X0(); + void m37710i_8a_M1X0(); + void m37710i_8b_M1X0(); + void m37710i_8c_M1X0(); + void m37710i_8d_M1X0(); + void m37710i_8e_M1X0(); + void m37710i_8f_M1X0(); + void m37710i_90_M1X0(); + void m37710i_91_M1X0(); + void m37710i_92_M1X0(); + void m37710i_93_M1X0(); + void m37710i_94_M1X0(); + void m37710i_95_M1X0(); + void m37710i_96_M1X0(); + void m37710i_97_M1X0(); + void m37710i_98_M1X0(); + void m37710i_99_M1X0(); + void m37710i_9a_M1X0(); + void m37710i_9b_M1X0(); + void m37710i_9c_M1X0(); + void m37710i_9d_M1X0(); + void m37710i_9e_M1X0(); + void m37710i_9f_M1X0(); + void m37710i_a0_M1X0(); + void m37710i_a1_M1X0(); + void m37710i_a2_M1X0(); + void m37710i_a3_M1X0(); + void m37710i_a4_M1X0(); + void m37710i_a5_M1X0(); + void m37710i_a6_M1X0(); + void m37710i_a7_M1X0(); + void m37710i_a8_M1X0(); + void m37710i_a9_M1X0(); + void m37710i_aa_M1X0(); + void m37710i_ab_M1X0(); + void m37710i_ac_M1X0(); + void m37710i_ad_M1X0(); + void m37710i_ae_M1X0(); + void m37710i_af_M1X0(); + void m37710i_b0_M1X0(); + void m37710i_b1_M1X0(); + void m37710i_b2_M1X0(); + void m37710i_b3_M1X0(); + void m37710i_b4_M1X0(); + void m37710i_b5_M1X0(); + void m37710i_b6_M1X0(); + void m37710i_b7_M1X0(); + void m37710i_b8_M1X0(); + void m37710i_b9_M1X0(); + void m37710i_ba_M1X0(); + void m37710i_bb_M1X0(); + void m37710i_bc_M1X0(); + void m37710i_bd_M1X0(); + void m37710i_be_M1X0(); + void m37710i_bf_M1X0(); + void m37710i_c0_M1X0(); + void m37710i_c1_M1X0(); + void m37710i_c2_M1X0(); + void m37710i_c3_M1X0(); + void m37710i_c4_M1X0(); + void m37710i_c5_M1X0(); + void m37710i_c6_M1X0(); + void m37710i_c7_M1X0(); + void m37710i_c8_M1X0(); + void m37710i_c9_M1X0(); + void m37710i_ca_M1X0(); + void m37710i_cb_M1X0(); + void m37710i_cc_M1X0(); + void m37710i_cd_M1X0(); + void m37710i_ce_M1X0(); + void m37710i_cf_M1X0(); + void m37710i_d0_M1X0(); + void m37710i_d1_M1X0(); + void m37710i_d2_M1X0(); + void m37710i_d3_M1X0(); + void m37710i_d4_M1X0(); + void m37710i_d5_M1X0(); + void m37710i_d6_M1X0(); + void m37710i_d7_M1X0(); + void m37710i_d8_M1X0(); + void m37710i_d9_M1X0(); + void m37710i_da_M1X0(); + void m37710i_db_M1X0(); + void m37710i_dc_M1X0(); + void m37710i_dd_M1X0(); + void m37710i_de_M1X0(); + void m37710i_df_M1X0(); + void m37710i_e0_M1X0(); + void m37710i_e1_M1X0(); + void m37710i_e2_M1X0(); + void m37710i_e3_M1X0(); + void m37710i_e4_M1X0(); + void m37710i_e5_M1X0(); + void m37710i_e6_M1X0(); + void m37710i_e7_M1X0(); + void m37710i_e8_M1X0(); + void m37710i_e9_M1X0(); + void m37710i_ea_M1X0(); + void m37710i_eb_M1X0(); + void m37710i_ec_M1X0(); + void m37710i_ed_M1X0(); + void m37710i_ee_M1X0(); + void m37710i_ef_M1X0(); + void m37710i_f0_M1X0(); + void m37710i_f1_M1X0(); + void m37710i_f2_M1X0(); + void m37710i_f3_M1X0(); + void m37710i_f4_M1X0(); + void m37710i_f5_M1X0(); + void m37710i_f6_M1X0(); + void m37710i_f7_M1X0(); + void m37710i_f8_M1X0(); + void m37710i_f9_M1X0(); + void m37710i_fa_M1X0(); + void m37710i_fb_M1X0(); + void m37710i_fc_M1X0(); + void m37710i_fd_M1X0(); + void m37710i_fe_M1X0(); + void m37710i_ff_M1X0(); + void m37710i_101_M1X0(); + void m37710i_103_M1X0(); + void m37710i_105_M1X0(); + void m37710i_107_M1X0(); + void m37710i_109_M1X0(); + void m37710i_10a_M1X0(); + void m37710i_10d_M1X0(); + void m37710i_10f_M1X0(); + void m37710i_111_M1X0(); + void m37710i_112_M1X0(); + void m37710i_113_M1X0(); + void m37710i_115_M1X0(); + void m37710i_117_M1X0(); + void m37710i_119_M1X0(); + void m37710i_11a_M1X0(); + void m37710i_11b_M1X0(); + void m37710i_11d_M1X0(); + void m37710i_11f_M1X0(); + void m37710i_121_M1X0(); + void m37710i_123_M1X0(); + void m37710i_125_M1X0(); + void m37710i_127_M1X0(); + void m37710i_129_M1X0(); + void m37710i_12a_M1X0(); + void m37710i_12d_M1X0(); + void m37710i_12f_M1X0(); + void m37710i_131_M1X0(); + void m37710i_132_M1X0(); + void m37710i_133_M1X0(); + void m37710i_135_M1X0(); + void m37710i_137_M1X0(); + void m37710i_139_M1X0(); + void m37710i_13a_M1X0(); + void m37710i_13b_M1X0(); + void m37710i_13d_M1X0(); + void m37710i_13f_M1X0(); + void m37710i_141_M1X0(); + void m37710i_143_M1X0(); + void m37710i_145_M1X0(); + void m37710i_147_M1X0(); + void m37710i_148_M1X0(); + void m37710i_149_M1X0(); + void m37710i_14a_M1X0(); + void m37710i_14d_M1X0(); + void m37710i_14f_M1X0(); + void m37710i_151_M1X0(); + void m37710i_152_M1X0(); + void m37710i_153_M1X0(); + void m37710i_155_M1X0(); + void m37710i_157_M1X0(); + void m37710i_159_M1X0(); + void m37710i_15b_M1X0(); + void m37710i_15d_M1X0(); + void m37710i_15f_M1X0(); + void m37710i_161_M1X0(); + void m37710i_163_M1X0(); + void m37710i_165_M1X0(); + void m37710i_167_M1X0(); + void m37710i_168_M1X0(); + void m37710i_169_M1X0(); + void m37710i_16a_M1X0(); + void m37710i_16d_M1X0(); + void m37710i_16f_M1X0(); + void m37710i_171_M1X0(); + void m37710i_172_M1X0(); + void m37710i_173_M1X0(); + void m37710i_175_M1X0(); + void m37710i_177_M1X0(); + void m37710i_179_M1X0(); + void m37710i_17b_M1X0(); + void m37710i_17d_M1X0(); + void m37710i_17f_M1X0(); + void m37710i_181_M1X0(); + void m37710i_183_M1X0(); + void m37710i_185_M1X0(); + void m37710i_187_M1X0(); + void m37710i_18a_M1X0(); + void m37710i_18d_M1X0(); + void m37710i_18f_M1X0(); + void m37710i_191_M1X0(); + void m37710i_192_M1X0(); + void m37710i_193_M1X0(); + void m37710i_195_M1X0(); + void m37710i_197_M1X0(); + void m37710i_198_M1X0(); + void m37710i_199_M1X0(); + void m37710i_19d_M1X0(); + void m37710i_19f_M1X0(); + void m37710i_1a1_M1X0(); + void m37710i_1a3_M1X0(); + void m37710i_1a5_M1X0(); + void m37710i_1a7_M1X0(); + void m37710i_1a8_M1X0(); + void m37710i_1a9_M1X0(); + void m37710i_1aa_M1X0(); + void m37710i_1ad_M1X0(); + void m37710i_1af_M1X0(); + void m37710i_1b1_M1X0(); + void m37710i_1b2_M1X0(); + void m37710i_1b3_M1X0(); + void m37710i_1b5_M1X0(); + void m37710i_1b7_M1X0(); + void m37710i_1b9_M1X0(); + void m37710i_1bd_M1X0(); + void m37710i_1bf_M1X0(); + void m37710i_1c1_M1X0(); + void m37710i_1c3_M1X0(); + void m37710i_1c5_M1X0(); + void m37710i_1c7_M1X0(); + void m37710i_1c9_M1X0(); + void m37710i_1cd_M1X0(); + void m37710i_1cf_M1X0(); + void m37710i_1d1_M1X0(); + void m37710i_1d2_M1X0(); + void m37710i_1d3_M1X0(); + void m37710i_1d5_M1X0(); + void m37710i_1d7_M1X0(); + void m37710i_1d9_M1X0(); + void m37710i_1dd_M1X0(); + void m37710i_1df_M1X0(); + void m37710i_1e1_M1X0(); + void m37710i_1e3_M1X0(); + void m37710i_1e5_M1X0(); + void m37710i_1e7_M1X0(); + void m37710i_1e9_M1X0(); + void m37710i_1ed_M1X0(); + void m37710i_1ef_M1X0(); + void m37710i_1f1_M1X0(); + void m37710i_1f2_M1X0(); + void m37710i_1f3_M1X0(); + void m37710i_1f5_M1X0(); + void m37710i_1f7_M1X0(); + void m37710i_1f9_M1X0(); + void m37710i_1fd_M1X0(); + void m37710i_1ff_M1X0(); + void m37710i_200_M1X0(); + void m37710i_201_M1X0(); + void m37710i_203_M1X0(); + void m37710i_205_M1X0(); + void m37710i_207_M1X0(); + void m37710i_209_M1X0(); + void m37710i_20d_M1X0(); + void m37710i_20f_M1X0(); + void m37710i_211_M1X0(); + void m37710i_212_M1X0(); + void m37710i_213_M1X0(); + void m37710i_215_M1X0(); + void m37710i_217_M1X0(); + void m37710i_219_M1X0(); + void m37710i_21d_M1X0(); + void m37710i_21f_M1X0(); + void m37710i_221_M1X0(); + void m37710i_223_M1X0(); + void m37710i_225_M1X0(); + void m37710i_227_M1X0(); + void m37710i_228_M1X0(); + void m37710i_229_M1X0(); + void m37710i_22d_M1X0(); + void m37710i_22f_M1X0(); + void m37710i_231_M1X0(); + void m37710i_232_M1X0(); + void m37710i_233_M1X0(); + void m37710i_235_M1X0(); + void m37710i_237_M1X0(); + void m37710i_239_M1X0(); + void m37710i_23d_M1X0(); + void m37710i_23f_M1X0(); + void m37710i_249_M1X0(); + void m37710i_2c2_M1X0(); + void m37710i_00_M1X1(); + void m37710i_01_M1X1(); + void m37710i_02_M1X1(); + void m37710i_03_M1X1(); + void m37710i_04_M1X1(); + void m37710i_05_M1X1(); + void m37710i_06_M1X1(); + void m37710i_07_M1X1(); + void m37710i_08_M1X1(); + void m37710i_09_M1X1(); + void m37710i_0a_M1X1(); + void m37710i_0b_M1X1(); + void m37710i_0c_M1X1(); + void m37710i_0d_M1X1(); + void m37710i_0e_M1X1(); + void m37710i_0f_M1X1(); + void m37710i_10_M1X1(); + void m37710i_11_M1X1(); + void m37710i_12_M1X1(); + void m37710i_13_M1X1(); + void m37710i_14_M1X1(); + void m37710i_15_M1X1(); + void m37710i_16_M1X1(); + void m37710i_17_M1X1(); + void m37710i_18_M1X1(); + void m37710i_19_M1X1(); + void m37710i_1a_M1X1(); + void m37710i_1b_M1X1(); + void m37710i_1c_M1X1(); + void m37710i_1d_M1X1(); + void m37710i_1e_M1X1(); + void m37710i_1f_M1X1(); + void m37710i_20_M1X1(); + void m37710i_21_M1X1(); + void m37710i_22_M1X1(); + void m37710i_23_M1X1(); + void m37710i_24_M1X1(); + void m37710i_25_M1X1(); + void m37710i_26_M1X1(); + void m37710i_27_M1X1(); + void m37710i_28_M1X1(); + void m37710i_29_M1X1(); + void m37710i_2a_M1X1(); + void m37710i_2b_M1X1(); + void m37710i_2c_M1X1(); + void m37710i_2d_M1X1(); + void m37710i_2e_M1X1(); + void m37710i_2f_M1X1(); + void m37710i_30_M1X1(); + void m37710i_31_M1X1(); + void m37710i_32_M1X1(); + void m37710i_33_M1X1(); + void m37710i_34_M1X1(); + void m37710i_35_M1X1(); + void m37710i_36_M1X1(); + void m37710i_37_M1X1(); + void m37710i_38_M1X1(); + void m37710i_39_M1X1(); + void m37710i_3a_M1X1(); + void m37710i_3b_M1X1(); + void m37710i_3c_M1X1(); + void m37710i_3d_M1X1(); + void m37710i_3e_M1X1(); + void m37710i_3f_M1X1(); + void m37710i_40_M1X1(); + void m37710i_41_M1X1(); + void m37710i_42_M1X1(); + void m37710i_43_M1X1(); + void m37710i_44_M1X1(); + void m37710i_45_M1X1(); + void m37710i_46_M1X1(); + void m37710i_47_M1X1(); + void m37710i_48_M1X1(); + void m37710i_49_M1X1(); + void m37710i_4a_M1X1(); + void m37710i_4b_M1X1(); + void m37710i_4c_M1X1(); + void m37710i_4d_M1X1(); + void m37710i_4e_M1X1(); + void m37710i_4f_M1X1(); + void m37710i_50_M1X1(); + void m37710i_51_M1X1(); + void m37710i_52_M1X1(); + void m37710i_53_M1X1(); + void m37710i_54_M1X1(); + void m37710i_55_M1X1(); + void m37710i_56_M1X1(); + void m37710i_57_M1X1(); + void m37710i_58_M1X1(); + void m37710i_59_M1X1(); + void m37710i_5a_M1X1(); + void m37710i_5b_M1X1(); + void m37710i_5c_M1X1(); + void m37710i_5d_M1X1(); + void m37710i_5e_M1X1(); + void m37710i_5f_M1X1(); + void m37710i_60_M1X1(); + void m37710i_61_M1X1(); + void m37710i_62_M1X1(); + void m37710i_63_M1X1(); + void m37710i_64_M1X1(); + void m37710i_65_M1X1(); + void m37710i_66_M1X1(); + void m37710i_67_M1X1(); + void m37710i_68_M1X1(); + void m37710i_69_M1X1(); + void m37710i_6a_M1X1(); + void m37710i_6b_M1X1(); + void m37710i_6c_M1X1(); + void m37710i_6d_M1X1(); + void m37710i_6e_M1X1(); + void m37710i_6f_M1X1(); + void m37710i_70_M1X1(); + void m37710i_71_M1X1(); + void m37710i_72_M1X1(); + void m37710i_73_M1X1(); + void m37710i_74_M1X1(); + void m37710i_75_M1X1(); + void m37710i_76_M1X1(); + void m37710i_77_M1X1(); + void m37710i_78_M1X1(); + void m37710i_79_M1X1(); + void m37710i_7a_M1X1(); + void m37710i_7b_M1X1(); + void m37710i_7c_M1X1(); + void m37710i_7d_M1X1(); + void m37710i_7e_M1X1(); + void m37710i_7f_M1X1(); + void m37710i_80_M1X1(); + void m37710i_81_M1X1(); + void m37710i_82_M1X1(); + void m37710i_83_M1X1(); + void m37710i_84_M1X1(); + void m37710i_85_M1X1(); + void m37710i_86_M1X1(); + void m37710i_87_M1X1(); + void m37710i_88_M1X1(); + void m37710i_89_M1X1(); + void m37710i_8a_M1X1(); + void m37710i_8b_M1X1(); + void m37710i_8c_M1X1(); + void m37710i_8d_M1X1(); + void m37710i_8e_M1X1(); + void m37710i_8f_M1X1(); + void m37710i_90_M1X1(); + void m37710i_91_M1X1(); + void m37710i_92_M1X1(); + void m37710i_93_M1X1(); + void m37710i_94_M1X1(); + void m37710i_95_M1X1(); + void m37710i_96_M1X1(); + void m37710i_97_M1X1(); + void m37710i_98_M1X1(); + void m37710i_99_M1X1(); + void m37710i_9a_M1X1(); + void m37710i_9b_M1X1(); + void m37710i_9c_M1X1(); + void m37710i_9d_M1X1(); + void m37710i_9e_M1X1(); + void m37710i_9f_M1X1(); + void m37710i_a0_M1X1(); + void m37710i_a1_M1X1(); + void m37710i_a2_M1X1(); + void m37710i_a3_M1X1(); + void m37710i_a4_M1X1(); + void m37710i_a5_M1X1(); + void m37710i_a6_M1X1(); + void m37710i_a7_M1X1(); + void m37710i_a8_M1X1(); + void m37710i_a9_M1X1(); + void m37710i_aa_M1X1(); + void m37710i_ab_M1X1(); + void m37710i_ac_M1X1(); + void m37710i_ad_M1X1(); + void m37710i_ae_M1X1(); + void m37710i_af_M1X1(); + void m37710i_b0_M1X1(); + void m37710i_b1_M1X1(); + void m37710i_b2_M1X1(); + void m37710i_b3_M1X1(); + void m37710i_b4_M1X1(); + void m37710i_b5_M1X1(); + void m37710i_b6_M1X1(); + void m37710i_b7_M1X1(); + void m37710i_b8_M1X1(); + void m37710i_b9_M1X1(); + void m37710i_ba_M1X1(); + void m37710i_bb_M1X1(); + void m37710i_bc_M1X1(); + void m37710i_bd_M1X1(); + void m37710i_be_M1X1(); + void m37710i_bf_M1X1(); + void m37710i_c0_M1X1(); + void m37710i_c1_M1X1(); + void m37710i_c2_M1X1(); + void m37710i_c3_M1X1(); + void m37710i_c4_M1X1(); + void m37710i_c5_M1X1(); + void m37710i_c6_M1X1(); + void m37710i_c7_M1X1(); + void m37710i_c8_M1X1(); + void m37710i_c9_M1X1(); + void m37710i_ca_M1X1(); + void m37710i_cb_M1X1(); + void m37710i_cc_M1X1(); + void m37710i_cd_M1X1(); + void m37710i_ce_M1X1(); + void m37710i_cf_M1X1(); + void m37710i_d0_M1X1(); + void m37710i_d1_M1X1(); + void m37710i_d2_M1X1(); + void m37710i_d3_M1X1(); + void m37710i_d4_M1X1(); + void m37710i_d5_M1X1(); + void m37710i_d6_M1X1(); + void m37710i_d7_M1X1(); + void m37710i_d8_M1X1(); + void m37710i_d9_M1X1(); + void m37710i_da_M1X1(); + void m37710i_db_M1X1(); + void m37710i_dc_M1X1(); + void m37710i_dd_M1X1(); + void m37710i_de_M1X1(); + void m37710i_df_M1X1(); + void m37710i_e0_M1X1(); + void m37710i_e1_M1X1(); + void m37710i_e2_M1X1(); + void m37710i_e3_M1X1(); + void m37710i_e4_M1X1(); + void m37710i_e5_M1X1(); + void m37710i_e6_M1X1(); + void m37710i_e7_M1X1(); + void m37710i_e8_M1X1(); + void m37710i_e9_M1X1(); + void m37710i_ea_M1X1(); + void m37710i_eb_M1X1(); + void m37710i_ec_M1X1(); + void m37710i_ed_M1X1(); + void m37710i_ee_M1X1(); + void m37710i_ef_M1X1(); + void m37710i_f0_M1X1(); + void m37710i_f1_M1X1(); + void m37710i_f2_M1X1(); + void m37710i_f3_M1X1(); + void m37710i_f4_M1X1(); + void m37710i_f5_M1X1(); + void m37710i_f6_M1X1(); + void m37710i_f7_M1X1(); + void m37710i_f8_M1X1(); + void m37710i_f9_M1X1(); + void m37710i_fa_M1X1(); + void m37710i_fb_M1X1(); + void m37710i_fc_M1X1(); + void m37710i_fd_M1X1(); + void m37710i_fe_M1X1(); + void m37710i_ff_M1X1(); + void m37710i_101_M1X1(); + void m37710i_103_M1X1(); + void m37710i_105_M1X1(); + void m37710i_107_M1X1(); + void m37710i_109_M1X1(); + void m37710i_10a_M1X1(); + void m37710i_10d_M1X1(); + void m37710i_10f_M1X1(); + void m37710i_111_M1X1(); + void m37710i_112_M1X1(); + void m37710i_113_M1X1(); + void m37710i_115_M1X1(); + void m37710i_117_M1X1(); + void m37710i_119_M1X1(); + void m37710i_11a_M1X1(); + void m37710i_11b_M1X1(); + void m37710i_11d_M1X1(); + void m37710i_11f_M1X1(); + void m37710i_121_M1X1(); + void m37710i_123_M1X1(); + void m37710i_125_M1X1(); + void m37710i_127_M1X1(); + void m37710i_129_M1X1(); + void m37710i_12a_M1X1(); + void m37710i_12d_M1X1(); + void m37710i_12f_M1X1(); + void m37710i_131_M1X1(); + void m37710i_132_M1X1(); + void m37710i_133_M1X1(); + void m37710i_135_M1X1(); + void m37710i_137_M1X1(); + void m37710i_139_M1X1(); + void m37710i_13a_M1X1(); + void m37710i_13b_M1X1(); + void m37710i_13d_M1X1(); + void m37710i_13f_M1X1(); + void m37710i_141_M1X1(); + void m37710i_143_M1X1(); + void m37710i_145_M1X1(); + void m37710i_147_M1X1(); + void m37710i_148_M1X1(); + void m37710i_149_M1X1(); + void m37710i_14a_M1X1(); + void m37710i_14d_M1X1(); + void m37710i_14f_M1X1(); + void m37710i_151_M1X1(); + void m37710i_152_M1X1(); + void m37710i_153_M1X1(); + void m37710i_155_M1X1(); + void m37710i_157_M1X1(); + void m37710i_159_M1X1(); + void m37710i_15b_M1X1(); + void m37710i_15d_M1X1(); + void m37710i_15f_M1X1(); + void m37710i_161_M1X1(); + void m37710i_163_M1X1(); + void m37710i_165_M1X1(); + void m37710i_167_M1X1(); + void m37710i_168_M1X1(); + void m37710i_169_M1X1(); + void m37710i_16a_M1X1(); + void m37710i_16d_M1X1(); + void m37710i_16f_M1X1(); + void m37710i_171_M1X1(); + void m37710i_172_M1X1(); + void m37710i_173_M1X1(); + void m37710i_175_M1X1(); + void m37710i_177_M1X1(); + void m37710i_179_M1X1(); + void m37710i_17b_M1X1(); + void m37710i_17d_M1X1(); + void m37710i_17f_M1X1(); + void m37710i_181_M1X1(); + void m37710i_183_M1X1(); + void m37710i_185_M1X1(); + void m37710i_187_M1X1(); + void m37710i_18a_M1X1(); + void m37710i_18d_M1X1(); + void m37710i_18f_M1X1(); + void m37710i_191_M1X1(); + void m37710i_192_M1X1(); + void m37710i_193_M1X1(); + void m37710i_195_M1X1(); + void m37710i_197_M1X1(); + void m37710i_198_M1X1(); + void m37710i_199_M1X1(); + void m37710i_19d_M1X1(); + void m37710i_19f_M1X1(); + void m37710i_1a1_M1X1(); + void m37710i_1a3_M1X1(); + void m37710i_1a5_M1X1(); + void m37710i_1a7_M1X1(); + void m37710i_1a8_M1X1(); + void m37710i_1a9_M1X1(); + void m37710i_1aa_M1X1(); + void m37710i_1ad_M1X1(); + void m37710i_1af_M1X1(); + void m37710i_1b1_M1X1(); + void m37710i_1b2_M1X1(); + void m37710i_1b3_M1X1(); + void m37710i_1b5_M1X1(); + void m37710i_1b7_M1X1(); + void m37710i_1b9_M1X1(); + void m37710i_1bd_M1X1(); + void m37710i_1bf_M1X1(); + void m37710i_1c1_M1X1(); + void m37710i_1c3_M1X1(); + void m37710i_1c5_M1X1(); + void m37710i_1c7_M1X1(); + void m37710i_1c9_M1X1(); + void m37710i_1cd_M1X1(); + void m37710i_1cf_M1X1(); + void m37710i_1d1_M1X1(); + void m37710i_1d2_M1X1(); + void m37710i_1d3_M1X1(); + void m37710i_1d5_M1X1(); + void m37710i_1d7_M1X1(); + void m37710i_1d9_M1X1(); + void m37710i_1dd_M1X1(); + void m37710i_1df_M1X1(); + void m37710i_1e1_M1X1(); + void m37710i_1e3_M1X1(); + void m37710i_1e5_M1X1(); + void m37710i_1e7_M1X1(); + void m37710i_1e9_M1X1(); + void m37710i_1ed_M1X1(); + void m37710i_1ef_M1X1(); + void m37710i_1f1_M1X1(); + void m37710i_1f2_M1X1(); + void m37710i_1f3_M1X1(); + void m37710i_1f5_M1X1(); + void m37710i_1f7_M1X1(); + void m37710i_1f9_M1X1(); + void m37710i_1fd_M1X1(); + void m37710i_1ff_M1X1(); + void m37710i_200_M1X1(); + void m37710i_201_M1X1(); + void m37710i_203_M1X1(); + void m37710i_205_M1X1(); + void m37710i_207_M1X1(); + void m37710i_209_M1X1(); + void m37710i_20d_M1X1(); + void m37710i_20f_M1X1(); + void m37710i_211_M1X1(); + void m37710i_212_M1X1(); + void m37710i_213_M1X1(); + void m37710i_215_M1X1(); + void m37710i_217_M1X1(); + void m37710i_219_M1X1(); + void m37710i_21d_M1X1(); + void m37710i_21f_M1X1(); + void m37710i_221_M1X1(); + void m37710i_223_M1X1(); + void m37710i_225_M1X1(); + void m37710i_227_M1X1(); + void m37710i_228_M1X1(); + void m37710i_229_M1X1(); + void m37710i_22d_M1X1(); + void m37710i_22f_M1X1(); + void m37710i_231_M1X1(); + void m37710i_232_M1X1(); + void m37710i_233_M1X1(); + void m37710i_235_M1X1(); + void m37710i_237_M1X1(); + void m37710i_239_M1X1(); + void m37710i_23d_M1X1(); + void m37710i_23f_M1X1(); + void m37710i_249_M1X1(); + void m37710i_2c2_M1X1(); + +}; + + +class m37702s1_device : public m37710_cpu_device +{ +public: + // construction/destruction + m37702s1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +protected: + DECLARE_ADDRESS_MAP(map, 16); +}; + +class m37702m2_device : public m37710_cpu_device +{ +public: + // construction/destruction + m37702m2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + m37702m2_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); +protected: + DECLARE_ADDRESS_MAP(map, 16); +}; + +class m37710s4_device : public m37710_cpu_device +{ +public: + // construction/destruction + m37710s4_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +protected: + DECLARE_ADDRESS_MAP(map, 16); +}; + + +extern const device_type M37702M2; +extern const device_type M37702S1; +extern const device_type M37710S4; + + +/* ======================================================================== */ +/* ============================== END OF FILE ============================= */ +/* ======================================================================== */ + +#endif /* __M37710_H__ */ diff --git a/src/devices/cpu/m37710/m37710cm.h b/src/devices/cpu/m37710/m37710cm.h new file mode 100644 index 00000000000..aa691b2e9aa --- /dev/null +++ b/src/devices/cpu/m37710/m37710cm.h @@ -0,0 +1,410 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont, Karl Stenerud, hap +#pragma once + +#ifndef __M37710CM_H__ +#define __M37710CM_H__ + + +/* ======================================================================== */ +/* ================================ INCLUDES ============================== */ +/* ======================================================================== */ + +#include +#include "m37710.h" + + +/* ======================================================================== */ +/* ================================= MAME ================================= */ +/* ======================================================================== */ + +#undef M37710_CALL_DEBUGGER + +#define M37710_CALL_DEBUGGER(x) debugger_instruction_hook(this, x) +#define m37710_read_8(addr) m_program->read_byte(addr) +#define m37710_write_8(addr,data) m_program->write_byte(addr,data) +#define m37710_read_8_immediate(A) m_direct->read_byte(A, BYTE_XOR_LE(0)) +#define m37710_read_16(addr) m_program->read_word_unaligned(addr) +#define m37710_write_16(addr,data) m_program->write_word_unaligned(addr,data) +#define m37710_read_16_immediate(A) m_direct->read_word(A) + + +/* ======================================================================== */ +/* ================================ GENERAL =============================== */ +/* ======================================================================== */ + +#undef int8 + +/* Allow for architectures that don't have 8-bit sizes */ +#if UCHAR_MAX == 0xff +#define int8 char +#define MAKE_INT_8(A) (int8)((A)&0xff) +#else +#define int8 int +INLINE int MAKE_INT_8(int A) {return (A & 0x80) ? A | ~0xff : A & 0xff;} +#endif /* UCHAR_MAX == 0xff */ + +#define MAKE_UINT_8(A) ((A)&0xff) +#define MAKE_UINT_16(A) ((A)&0xffff) +#define MAKE_UINT_24(A) ((A)&0xffffff) + +/* Bits */ +#define BIT_0 0x01 +#define BIT_1 0x02 +#define BIT_2 0x04 +#define BIT_3 0x08 +#define BIT_4 0x10 +#define BIT_5 0x20 +#define BIT_6 0x40 +#define BIT_7 0x80 + +/* ======================================================================== */ +/* ================================== CPU ================================= */ +/* ======================================================================== */ + +#define REG_A m_a /* Accumulator */ +#define REG_B m_b /* Accumulator hi byte */ +#define REG_BA m_ba /* Secondary Accumulator */ +#define REG_BB m_bb /* Secondary Accumulator hi byte */ +#define REG_X m_x /* Index X Register */ +#define REG_Y m_y /* Index Y Register */ +#define REG_XH m_xh /* X high byte */ +#define REG_YH m_yh /* Y high byte */ +#define REG_S m_s /* Stack Pointer */ +#define REG_PC m_pc /* Program Counter */ +#define REG_PPC m_ppc /* Previous Program Counter */ +#define REG_PB m_pb /* Program Bank */ +#define REG_DB m_db /* Data Bank */ +#define REG_D m_d /* Direct Register */ +#define FLAG_M m_flag_m /* Memory/Accumulator Select Flag */ +#define FLAG_X m_flag_x /* Index Select Flag */ +#define FLAG_N m_flag_n /* Negative Flag */ +#define FLAG_V m_flag_v /* Overflow Flag */ +#define FLAG_D m_flag_d /* Decimal Mode Flag */ +#define FLAG_I m_flag_i /* Interrupt Mask Flag */ +#define FLAG_Z m_flag_z /* Zero Flag (inverted) */ +#define FLAG_C m_flag_c /* Carry Flag */ +#define LINE_IRQ m_line_irq /* Status of the IRQ line */ +#define REG_IR m_ir /* Instruction Register */ +#define REG_IM m_im /* Immediate load value */ +#define REG_IM2 m_im2 /* Immediate load target */ +#define REG_IM3 m_im3 /* Immediate load target */ +#define REG_IM4 m_im4 /* Immediate load target */ +#define INT_ACK m_int_ack /* Interrupt Acknowledge function pointer */ +#define CLOCKS m_ICount /* Clock cycles remaining */ +#define IRQ_DELAY m_irq_delay /* Delay 1 instruction before checking IRQ */ +#define CPU_STOPPED m_stopped /* Stopped status of the CPU */ + +#define FTABLE_GET_REG m_get_reg +#define FTABLE_SET_REG m_set_reg +#define FTABLE_SET_LINE m_set_line + +#define SRC m_source /* Source Operand */ +#define DST m_destination /* Destination Operand */ + +#define STOP_LEVEL_WAI 1 +#define STOP_LEVEL_STOP 2 + +#define EXECUTION_MODE_M0X0 0 +#define EXECUTION_MODE_M0X1 1 +#define EXECUTION_MODE_M1X0 2 +#define EXECUTION_MODE_M1X1 3 + + +/* ======================================================================== */ +/* ================================= CLOCK ================================ */ +/* ======================================================================== */ + +#define CLK_OP 1 +#define CLK_R8 1 +#define CLK_R16 2 +#define CLK_R24 3 +#define CLK_W8 1 +#define CLK_W16 2 +#define CLK_W24 3 +#define CLK_RMW8 3 +#define CLK_RMW16 5 + +#define CLK_IMPLIED 1 +#define CLK_IMPLIED 1 +#define CLK_RELATIVE_8 1 +#define CLK_RELATIVE_16 2 +#define CLK_IMM 0 +#define CLK_AI 4 +#define CLK_AXI 4 +#define CLK_A 2 +#define CLK_AL 3 +#define CLK_ALX 3 +#define CLK_AX 2 +#define CLK_AY 2 +#define CLK_D 1 +#define CLK_DI 3 +#define CLK_DIY 3 +#define CLK_DLI 4 +#define CLK_DLIY 4 +#define CLK_DX 2 +#define CLK_DXI 4 +#define CLK_DY 2 +#define CLK_S 2 +#define CLK_SIY 5 + +/* AX and AY addressing modes take 1 extra cycle when writing */ +#define CLK_W_IMM 0 +#define CLK_W_AI 4 +#define CLK_W_AXI 4 +#define CLK_W_A 2 +#define CLK_W_AL 3 +#define CLK_W_ALX 3 +#define CLK_W_AX 3 +#define CLK_W_AY 3 +#define CLK_W_D 1 +#define CLK_W_DI 3 +#define CLK_W_DIY 3 +#define CLK_W_DLI 4 +#define CLK_W_DLIY 4 +#define CLK_W_DX 2 +#define CLK_W_DXI 4 +#define CLK_W_DY 2 +#define CLK_W_S 2 +#define CLK_W_SIY 5 + +#define CLK(A) CLOCKS -= (A) +#define USE_ALL_CLKS() CLOCKS = 0 + + +/* ======================================================================== */ +/* ============================ STATUS REGISTER =========================== */ +/* ======================================================================== */ + +/* Flag positions in Processor Status Register */ +/* common */ +#define FLAGPOS_N BIT_7 /* Negative */ +#define FLAGPOS_V BIT_6 /* Overflow */ +#define FLAGPOS_D BIT_3 /* Decimal Mode */ +#define FLAGPOS_I BIT_2 /* Interrupt Mask */ +#define FLAGPOS_Z BIT_1 /* Zero */ +#define FLAGPOS_C BIT_0 /* Carry */ +/* emulation */ +#define FLAGPOS_R BIT_5 /* Reserved */ +#define FLAGPOS_B BIT_4 /* BRK Instruction */ +/* native */ +#define FLAGPOS_M BIT_5 /* Mem/Reg Select */ +#define FLAGPOS_X BIT_4 /* Index Select */ + +#define EFLAG_SET 1 +#define EFLAG_CLEAR 0 +#define MFLAG_SET FLAGPOS_M +#define MFLAG_CLEAR 0 +#define XFLAG_SET FLAGPOS_X +#define XFLAG_CLEAR 0 +#define NFLAG_SET 0x80 +#define NFLAG_CLEAR 0 +#define VFLAG_SET 0x80 +#define VFLAG_CLEAR 0 +#define DFLAG_SET FLAGPOS_D +#define DFLAG_CLEAR 0 +#define IFLAG_SET FLAGPOS_I +#define IFLAG_CLEAR 0 +#define BFLAG_SET FLAGPOS_B +#define BFLAG_CLEAR 0 +#define ZFLAG_SET 0 +#define ZFLAG_CLEAR 1 +#define CFLAG_SET 0x100 +#define CFLAG_CLEAR 0 + +/* Codition code tests */ +#define COND_CC() (!(FLAG_C&0x100)) /* Carry Clear */ +#define COND_CS() (FLAG_C&0x100) /* Carry Set */ +#define COND_EQ() (!FLAG_Z) /* Equal */ +#define COND_NE() FLAG_Z /* Not Equal */ +#define COND_MI() (FLAG_N&0x80) /* Minus */ +#define COND_PL() (!(FLAG_N&0x80)) /* Plus */ +#define COND_VC() (!(FLAG_V&0x80)) /* Overflow Clear */ +#define COND_VS() (FLAG_V&0x80) /* Overflow Set */ + +/* Set Overflow flag in math operations */ +#define VFLAG_ADD_8(S, D, R) ((S^R) & (D^R)) +#define VFLAG_ADD_16(S, D, R) (((S^R) & (D^R))>>8) +#define VFLAG_SUB_8(S, D, R) ((S^D) & (R^D)) +#define VFLAG_SUB_16(S, D, R) (((S^D) & (R^D))>>8) + +#define CFLAG_8(A) (A) +#define CFLAG_16(A) ((A)>>8) +#define NFLAG_8(A) (A) +#define NFLAG_16(A) ((A)>>8) + +#define CFLAG_AS_1() ((FLAG_C>>8)&1) + +/* ======================================================================== */ +/* ========================== EFFECTIVE ADDRESSES ========================= */ +/* ======================================================================== */ + +/* Effective-address based memory access macros */ +#define read_8_NORM(A) m37710i_read_8_normal(A) +#define read_8_IMM(A) m37710i_read_8_immediate(A) +#define read_8_D(A) m37710i_read_8_direct(A) +#define read_8_A(A) m37710i_read_8_normal(A) +#define read_8_AL(A) m37710i_read_8_normal(A) +#define read_8_DX(A) m37710i_read_8_direct(A) +#define read_8_DY(A) m37710i_read_8_direct(A) +#define read_8_AX(A) m37710i_read_8_normal(A) +#define read_8_ALX(A) m37710i_read_8_normal(A) +#define read_8_AY(A) m37710i_read_8_normal(A) +#define read_8_DI(A) m37710i_read_8_normal(A) +#define read_8_DLI(A) m37710i_read_8_normal(A) +#define read_8_AI(A) m37710i_read_8_normal(A) +#define read_8_ALI(A) m37710i_read_8_normal(A) +#define read_8_DXI(A) m37710i_read_8_normal(A) +#define read_8_DIY(A) m37710i_read_8_normal(A) +#define read_8_DLIY(A) m37710i_read_8_normal(A) +#define read_8_AXI(A) m37710i_read_8_normal(A) +#define read_8_S(A) m37710i_read_8_normal(A) +#define read_8_SIY(A) m37710i_read_8_normal(A) + +#define read_16_NORM(A) m37710i_read_16_normal(A) +#define read_16_IMM(A) m37710i_read_16_immediate(A) +#define read_16_D(A) m37710i_read_16_direct(A) +#define read_16_A(A) m37710i_read_16_normal(A) +#define read_16_AL(A) m37710i_read_16_normal(A) +#define read_16_DX(A) m37710i_read_16_direct(A) +#define read_16_DY(A) m37710i_read_16_direct(A) +#define read_16_AX(A) m37710i_read_16_normal(A) +#define read_16_ALX(A) m37710i_read_16_normal(A) +#define read_16_AY(A) m37710i_read_16_normal(A) +#define read_16_DI(A) m37710i_read_16_normal(A) +#define read_16_DLI(A) m37710i_read_16_normal(A) +#define read_16_AI(A) m37710i_read_16_normal(A) +#define read_16_ALI(A) m37710i_read_16_normal(A) +#define read_16_DXI(A) m37710i_read_16_normal(A) +#define read_16_DIY(A) m37710i_read_16_normal(A) +#define read_16_DLIY(A) m37710i_read_16_normal(A) +#define read_16_AXI(A) m37710i_read_16_normal(A) +#define read_16_S(A) m37710i_read_16_normal(A) +#define read_16_SIY(A) m37710i_read_16_normal(A) + +#define read_24_NORM(A) m37710i_read_24_normal(A) +#define read_24_IMM(A) m37710i_read_24_immediate(A) +#define read_24_D(A) m37710i_read_24_direct(A) +#define read_24_A(A) m37710i_read_24_normal(A) +#define read_24_AL(A) m37710i_read_24_normal(A) +#define read_24_DX(A) m37710i_read_24_direct(A) +#define read_24_DY(A) m37710i_read_24_direct(A) +#define read_24_AX(A) m37710i_read_24_normal(A) +#define read_24_ALX(A) m37710i_read_24_normal(A) +#define read_24_AY(A) m37710i_read_24_normal(A) +#define read_24_DI(A) m37710i_read_24_normal(A) +#define read_24_DLI(A) m37710i_read_24_normal(A) +#define read_24_AI(A) m37710i_read_24_normal(A) +#define read_24_ALI(A) m37710i_read_24_normal(A) +#define read_24_DXI(A) m37710i_read_24_normal(A) +#define read_24_DIY(A) m37710i_read_24_normal(A) +#define read_24_DLIY(A) m37710i_read_24_normal(A) +#define read_24_AXI(A) m37710i_read_24_normal(A) +#define read_24_S(A) m37710i_read_24_normal(A) +#define read_24_SIY(A) m37710i_read_24_normal(A) + +#define write_8_NORM(A, V) m37710i_write_8_normal(A, V) +#define write_8_D(A, V) m37710i_write_8_direct(A, V) +#define write_8_A(A, V) m37710i_write_8_normal(A, V) +#define write_8_AL(A, V) m37710i_write_8_normal(A, V) +#define write_8_DX(A, V) m37710i_write_8_direct(A, V) +#define write_8_DY(A, V) m37710i_write_8_direct(A, V) +#define write_8_AX(A, V) m37710i_write_8_normal(A, V) +#define write_8_ALX(A, V) m37710i_write_8_normal(A, V) +#define write_8_AY(A, V) m37710i_write_8_normal(A, V) +#define write_8_DI(A, V) m37710i_write_8_normal(A, V) +#define write_8_DLI(A, V) m37710i_write_8_normal(A, V) +#define write_8_AI(A, V) m37710i_write_8_normal(A, V) +#define write_8_ALI(A, V) m37710i_write_8_normal(A, V) +#define write_8_DXI(A, V) m37710i_write_8_normal(A, V) +#define write_8_DIY(A, V) m37710i_write_8_normal(A, V) +#define write_8_DLIY(A, V) m37710i_write_8_normal(A, V) +#define write_8_AXI(A, V) m37710i_write_8_normal(A, V) +#define write_8_S(A, V) m37710i_write_8_normal(A, V) +#define write_8_SIY(A, V) m37710i_write_8_normal(A, V) + +#define write_16_NORM(A, V) m37710i_write_16_normal(A, V) +#define write_16_D(A, V) m37710i_write_16_direct(A, V) +#define write_16_A(A, V) m37710i_write_16_normal(A, V) +#define write_16_AL(A, V) m37710i_write_16_normal(A, V) +#define write_16_DX(A, V) m37710i_write_16_direct(A, V) +#define write_16_DY(A, V) m37710i_write_16_direct(A, V) +#define write_16_AX(A, V) m37710i_write_16_normal(A, V) +#define write_16_ALX(A, V) m37710i_write_16_normal(A, V) +#define write_16_AY(A, V) m37710i_write_16_normal(A, V) +#define write_16_DI(A, V) m37710i_write_16_normal(A, V) +#define write_16_DLI(A, V) m37710i_write_16_normal(A, V) +#define write_16_AI(A, V) m37710i_write_16_normal(A, V) +#define write_16_ALI(A, V) m37710i_write_16_normal(A, V) +#define write_16_DXI(A, V) m37710i_write_16_normal(A, V) +#define write_16_DIY(A, V) m37710i_write_16_normal(A, V) +#define write_16_DLIY(A, V) m37710i_write_16_normal(A, V) +#define write_16_AXI(A, V) m37710i_write_16_normal(A, V) +#define write_16_S(A, V) m37710i_write_16_normal(A, V) +#define write_16_SIY(A, V) m37710i_write_16_normal(A, V) + + +#define OPER_8_IMM() read_8_IMM(EA_IMM8()) +#define OPER_8_D() read_8_D(EA_D()) +#define OPER_8_A() read_8_A(EA_A()) +#define OPER_8_AL() read_8_AL(EA_AL()) +#define OPER_8_DX() read_8_DX(EA_DX()) +#define OPER_8_DY() read_8_DY(EA_DY()) +#define OPER_8_AX() read_8_AX(EA_AX()) +#define OPER_8_ALX() read_8_ALX(EA_ALX()) +#define OPER_8_AY() read_8_AY(EA_AY()) +#define OPER_8_DI() read_8_DI(EA_DI()) +#define OPER_8_DLI() read_8_DLI(EA_DLI()) +#define OPER_8_AI() read_8_AI(EA_AI()) +#define OPER_8_ALI() read_8_ALI(EA_ALI()) +#define OPER_8_DXI() read_8_DXI(EA_DXI()) +#define OPER_8_DIY() read_8_DIY(EA_DIY()) +#define OPER_8_DLIY() read_8_DLIY(EA_DLIY()) +#define OPER_8_AXI() read_8_AXI(EA_AXI()) +#define OPER_8_S() read_8_S(EA_S()) +#define OPER_8_SIY() read_8_SIY(EA_SIY()) + +#define OPER_16_IMM() read_16_IMM(EA_IMM16()) +#define OPER_16_D() read_16_D(EA_D()) +#define OPER_16_A() read_16_A(EA_A()) +#define OPER_16_AL() read_16_AL(EA_AL()) +#define OPER_16_DX() read_16_DX(EA_DX()) +#define OPER_16_DY() read_16_DY(EA_DY()) +#define OPER_16_AX() read_16_AX(EA_AX()) +#define OPER_16_ALX() read_16_ALX(EA_ALX()) +#define OPER_16_AY() read_16_AY(EA_AY()) +#define OPER_16_DI() read_16_DI(EA_DI()) +#define OPER_16_DLI() read_16_DLI(EA_DLI()) +#define OPER_16_AI() read_16_AI(EA_AI()) +#define OPER_16_ALI() read_16_ALI(EA_ALI()) +#define OPER_16_DXI() read_16_DXI(EA_DXI()) +#define OPER_16_DIY() read_16_DIY(EA_DIY()) +#define OPER_16_DLIY() read_16_DLIY(EA_DLIY()) +#define OPER_16_AXI() read_16_AXI(EA_AXI()) +#define OPER_16_S() read_16_S(EA_S()) +#define OPER_16_SIY() read_16_SIY(EA_SIY()) + +#define OPER_24_IMM() read_24_IMM(EA_IMM24()) +#define OPER_24_D() read_24_D(EA_D()) +#define OPER_24_A() read_24_A(EA_A()) +#define OPER_24_AL() read_24_AL(EA_AL()) +#define OPER_24_DX() read_24_DX(EA_DX()) +#define OPER_24_DY() read_24_DY(EA_DY()) +#define OPER_24_AX() read_24_AX(EA_AX()) +#define OPER_24_ALX() read_24_ALX(EA_ALX()) +#define OPER_24_AY() read_24_AY(EA_AY()) +#define OPER_24_DI() read_24_DI(EA_DI()) +#define OPER_24_DLI() read_24_DLI(EA_DLI()) +#define OPER_24_AI() read_24_AI(EA_AI()) +#define OPER_24_ALI() read_24_ALI(EA_ALI()) +#define OPER_24_DXI() read_24_DXI(EA_DXI()) +#define OPER_24_DIY() read_24_DIY(EA_DIY()) +#define OPER_24_DLIY() read_24_DLIY(EA_DLIY()) +#define OPER_24_AXI() read_24_AXI(EA_AXI()) +#define OPER_24_S() read_24_S(EA_S()) +#define OPER_24_SIY() read_24_SIY(EA_SIY()) + +/* ======================================================================== */ +/* ================================== CPU ================================= */ +/* ======================================================================== */ +#endif /* __M37710CM_H__ */ diff --git a/src/devices/cpu/m37710/m37710il.h b/src/devices/cpu/m37710/m37710il.h new file mode 100644 index 00000000000..ffc1aed0a7a --- /dev/null +++ b/src/devices/cpu/m37710/m37710il.h @@ -0,0 +1,208 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont, Karl Stenerud, hap +#pragma once + +#ifndef __M37710IL_H__ +#define __M37710IL_H__ + + +/* ======================================================================== */ +/* ================================= MEMORY =============================== */ +/* ======================================================================== */ + +inline UINT32 m37710_cpu_device::m37710i_read_8_normal(UINT32 address) +{ + return m37710_read_8(address); +} + +inline UINT32 m37710_cpu_device::m37710i_read_8_immediate(UINT32 address) +{ + return m37710_read_8_immediate(address); +} + +inline UINT32 m37710_cpu_device::m37710i_read_8_direct(UINT32 address) +{ + return m37710_read_8(address); +} + +inline void m37710_cpu_device::m37710i_write_8_normal(UINT32 address, UINT32 value) +{ + m37710_write_8(address, value); +} + +inline void m37710_cpu_device::m37710i_write_8_direct(UINT32 address, UINT32 value) +{ + m37710_write_8(address, value); +} + +inline UINT32 m37710_cpu_device::m37710i_read_16_normal(UINT32 address) +{ + return m37710_read_16(address); +} + +inline UINT32 m37710_cpu_device::m37710i_read_16_immediate(UINT32 address) +{ + if (address & 1) + return m37710_read_8_immediate(address) | (m37710_read_8_immediate(address+1)<<8); + else + return m37710_read_16_immediate(address); +} + +inline UINT32 m37710_cpu_device::m37710i_read_16_direct(UINT32 address) +{ + return m37710_read_16(address); +} + +inline void m37710_cpu_device::m37710i_write_16_normal(UINT32 address, UINT32 value) +{ + m37710_write_16(address, value); +} + +inline void m37710_cpu_device::m37710i_write_16_direct(UINT32 address, UINT32 value) +{ + m37710_write_16(address, value); +} + +inline UINT32 m37710_cpu_device::m37710i_read_24_normal(UINT32 address) +{ + if (address & 1) + return m37710_read_8(address) | (m37710_read_16(address+1)<<8); + else + return m37710_read_16(address) | (m37710_read_8(address+2)<<16); +} + +inline UINT32 m37710_cpu_device::m37710i_read_24_immediate(UINT32 address) +{ + if (address & 1) + return m37710_read_8_immediate(address) | (m37710_read_16_immediate(address+1)<<8); + else + return m37710_read_16_immediate(address) | (m37710_read_8_immediate(address+2)<<16); +} + +inline UINT32 m37710_cpu_device::m37710i_read_24_direct(UINT32 address) +{ + if (address & 1) + return m37710_read_8(address) | (m37710_read_16(address+1)<<8); + else + return m37710_read_16(address) | (m37710_read_8(address+2)<<16); +} + + +/* ======================================================================== */ +/* ================================= STACK ================================ */ +/* ======================================================================== */ + +inline void m37710_cpu_device::m37710i_push_8(UINT32 value) +{ + m37710_write_8(REG_S, value); + REG_S = MAKE_UINT_16(REG_S-1); +} + +inline UINT32 m37710_cpu_device::m37710i_pull_8() +{ + REG_S = MAKE_UINT_16(REG_S+1); + return m37710_read_8(REG_S); +} + +inline void m37710_cpu_device::m37710i_push_16(UINT32 value) +{ + m37710i_push_8(value>>8); + m37710i_push_8(value); +} + +inline UINT32 m37710_cpu_device::m37710i_pull_16() +{ + UINT32 res = m37710i_pull_8(); + return res | (m37710i_pull_8() << 8); +} + +inline void m37710_cpu_device::m37710i_push_24(UINT32 value) +{ + m37710i_push_8(value>>16); + m37710i_push_8((value>>8)); + m37710i_push_8(value); +} + +inline UINT32 m37710_cpu_device::m37710i_pull_24() +{ + UINT32 res = m37710i_pull_8(); + res |= m37710i_pull_8() << 8; + return res | (m37710i_pull_8() << 16); +} + + +/* ======================================================================== */ +/* ============================ PROGRAM COUNTER =========================== */ +/* ======================================================================== */ + +inline void m37710_cpu_device::m37710i_jump_16(UINT32 address) +{ + REG_PC = MAKE_UINT_16(address); +} + +inline void m37710_cpu_device::m37710i_jump_24(UINT32 address) +{ + REG_PB = address&0xff0000; + REG_PC = MAKE_UINT_16(address); +} + +inline void m37710_cpu_device::m37710i_branch_8(UINT32 offset) +{ + REG_PC = MAKE_UINT_16(REG_PC + MAKE_INT_8(offset)); +} + +inline void m37710_cpu_device::m37710i_branch_16(UINT32 offset) +{ + REG_PC = MAKE_UINT_16(REG_PC + offset); +} + + +/* ======================================================================== */ +/* ============================ STATUS REGISTER =========================== */ +/* ======================================================================== */ + +inline UINT32 m37710_cpu_device::m37710i_get_reg_p() +{ + return (FLAG_N&0x80) | + ((FLAG_V>>1)&0x40) | + FLAG_M | + FLAG_X | + FLAG_D | + FLAG_I | + ((!FLAG_Z)<<1) | + ((FLAG_C>>8)&1); +} + +inline void m37710_cpu_device::m37710i_set_reg_ipl(UINT32 value) +{ + m_ipl = value & 7; +} + + +/* ======================================================================== */ +/* ============================= ADDRESS MODES ============================ */ +/* ======================================================================== */ + +inline UINT32 m37710_cpu_device::EA_IMM8() {REG_PC += 1; return REG_PB | MAKE_UINT_16(REG_PC-1);} +inline UINT32 m37710_cpu_device::EA_IMM16() {REG_PC += 2; return REG_PB | MAKE_UINT_16(REG_PC-2);} +inline UINT32 m37710_cpu_device::EA_IMM24() {REG_PC += 3; return REG_PB | MAKE_UINT_16(REG_PC-3);} +inline UINT32 m37710_cpu_device::EA_D() {if(MAKE_UINT_8(REG_D)) CLK(1); return MAKE_UINT_16(REG_D + OPER_8_IMM());} +inline UINT32 m37710_cpu_device::EA_A() {return REG_DB | OPER_16_IMM();} +inline UINT32 m37710_cpu_device::EA_AL() {return OPER_24_IMM();} +inline UINT32 m37710_cpu_device::EA_DX() {return MAKE_UINT_16(REG_D + OPER_8_IMM() + REG_X);} +inline UINT32 m37710_cpu_device::EA_DY() {return MAKE_UINT_16(REG_D + OPER_8_IMM() + REG_Y);} +inline UINT32 m37710_cpu_device::EA_AX() {UINT32 tmp = EA_A(); if((tmp^(tmp+REG_X))&0xff00) CLK(1); return tmp + REG_X;} +inline UINT32 m37710_cpu_device::EA_ALX() {return EA_AL() + REG_X;} +inline UINT32 m37710_cpu_device::EA_AY() {UINT32 tmp = EA_A(); if((tmp^(tmp+REG_X))&0xff00) CLK(1); return tmp + REG_Y;} +inline UINT32 m37710_cpu_device::EA_DI() {return REG_DB | OPER_16_D();} +inline UINT32 m37710_cpu_device::EA_DLI() {return OPER_24_D();} +inline UINT32 m37710_cpu_device::EA_AI() {return read_16_A(OPER_16_IMM());} +inline UINT32 m37710_cpu_device::EA_ALI() {return OPER_24_A();} +inline UINT32 m37710_cpu_device::EA_DXI() {return REG_DB | OPER_16_DX();} +inline UINT32 m37710_cpu_device::EA_DIY() {UINT32 tmp = REG_DB | OPER_16_D(); if((tmp^(tmp+REG_X))&0xff00) CLK(1); return tmp + REG_Y;} +inline UINT32 m37710_cpu_device::EA_DLIY() {return OPER_24_D() + REG_Y;} +inline UINT32 m37710_cpu_device::EA_AXI() {return read_16_AXI(MAKE_UINT_16(OPER_16_IMM() + REG_X));} +inline UINT32 m37710_cpu_device::EA_S() {return MAKE_UINT_16(REG_S + OPER_8_IMM());} +inline UINT32 m37710_cpu_device::EA_SIY() {return MAKE_UINT_16(read_16_SIY(REG_S + OPER_8_IMM()) + REG_Y) | REG_DB;} + +#endif /* __M37710IL_H__ */ diff --git a/src/devices/cpu/m37710/m37710o0.c b/src/devices/cpu/m37710/m37710o0.c new file mode 100644 index 00000000000..6fdd9b2a01f --- /dev/null +++ b/src/devices/cpu/m37710/m37710o0.c @@ -0,0 +1,8 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont, Karl Stenerud, hap +#include "emu.h" +#include "debugger.h" +#include "m37710cm.h" +#include "m37710il.h" +#define EXECUTION_MODE EXECUTION_MODE_M0X0 +#include "m37710op.h" diff --git a/src/devices/cpu/m37710/m37710o1.c b/src/devices/cpu/m37710/m37710o1.c new file mode 100644 index 00000000000..d8de494a6ce --- /dev/null +++ b/src/devices/cpu/m37710/m37710o1.c @@ -0,0 +1,8 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont, Karl Stenerud, hap +#include "emu.h" +#include "debugger.h" +#include "m37710cm.h" +#include "m37710il.h" +#define EXECUTION_MODE EXECUTION_MODE_M0X1 +#include "m37710op.h" diff --git a/src/devices/cpu/m37710/m37710o2.c b/src/devices/cpu/m37710/m37710o2.c new file mode 100644 index 00000000000..d92556b3207 --- /dev/null +++ b/src/devices/cpu/m37710/m37710o2.c @@ -0,0 +1,8 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont, Karl Stenerud, hap +#include "emu.h" +#include "debugger.h" +#include "m37710cm.h" +#include "m37710il.h" +#define EXECUTION_MODE EXECUTION_MODE_M1X0 +#include "m37710op.h" diff --git a/src/devices/cpu/m37710/m37710o3.c b/src/devices/cpu/m37710/m37710o3.c new file mode 100644 index 00000000000..16e2084ec4a --- /dev/null +++ b/src/devices/cpu/m37710/m37710o3.c @@ -0,0 +1,8 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont, Karl Stenerud, hap +#include "emu.h" +#include "debugger.h" +#include "m37710cm.h" +#include "m37710il.h" +#define EXECUTION_MODE EXECUTION_MODE_M1X1 +#include "m37710op.h" diff --git a/src/devices/cpu/m37710/m37710op.h b/src/devices/cpu/m37710/m37710op.h new file mode 100644 index 00000000000..03e29580323 --- /dev/null +++ b/src/devices/cpu/m37710/m37710op.h @@ -0,0 +1,2608 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont, Karl Stenerud, hap +/* ======================================================================== */ +/* ============================= CONFIGURATION ============================ */ +/* ======================================================================== */ + +#undef FLAG_SET_M +#undef FLAG_SET_X +#undef m37710i_set_flag_mx +#undef m37710i_set_reg_p + +#if EXECUTION_MODE == EXECUTION_MODE_M0X0 +#define FLAG_SET_M 0 +#define FLAG_SET_X 0 +#define m37710i_set_flag_mx m37710i_set_flag_m0x0 +#define m37710i_set_reg_p m37710i_set_reg_p_m0x0 +#elif EXECUTION_MODE == EXECUTION_MODE_M0X1 +#define FLAG_SET_M 0 +#define FLAG_SET_X 1 +#define m37710i_set_flag_mx m37710i_set_flag_m0x1 +#define m37710i_set_reg_p m37710i_set_reg_p_m0x1 +#elif EXECUTION_MODE == EXECUTION_MODE_M1X0 +#define FLAG_SET_M 1 +#define FLAG_SET_X 0 +#define m37710i_set_flag_mx m37710i_set_flag_m1x0 +#define m37710i_set_reg_p m37710i_set_reg_p_m1x0 +#elif EXECUTION_MODE == EXECUTION_MODE_M1X1 +#define FLAG_SET_M 1 +#define FLAG_SET_X 1 +#define m37710i_set_flag_mx m37710i_set_flag_m1x1 +#define m37710i_set_reg_p m37710i_set_reg_p_m1x1 +#endif + +/* ======================================================================== */ +/* ============================ STATUS REGISTER =========================== */ +/* ======================================================================== */ + +/* note: difference from 65816. when switching to 8-bit X/Y, X and Y are *not* truncated + to 8 bits! */ + +void m37710_cpu_device::m37710i_set_flag_mx(UINT32 value) +{ +#if FLAG_SET_M + if(!(value & FLAGPOS_M)) + { + REG_A |= REG_B; + REG_B = 0; + REG_BA |= REG_BB; + REG_BB = 0; + FLAG_M = MFLAG_CLEAR; + } +#else + if(value & FLAGPOS_M) + { + REG_B = REG_A & 0xff00; + REG_A = MAKE_UINT_8(REG_A); + REG_BB = REG_BA & 0xff00; + REG_BA = MAKE_UINT_8(REG_BA); + FLAG_M = MFLAG_SET; + } +#endif +#if FLAG_SET_X + if(!(value & FLAGPOS_X)) + { + REG_X |= REG_XH; + REG_XH = 0; + REG_Y |= REG_YH; + REG_YH = 0; + FLAG_X = XFLAG_CLEAR; + } +#else + if(value & FLAGPOS_X) + { + REG_XH = REG_X & 0xff00; + REG_X = MAKE_UINT_8(REG_X); + REG_YH = REG_Y & 0xff00; + REG_Y = MAKE_UINT_8(REG_Y); + FLAG_X = XFLAG_SET; + } +#endif + m37710i_set_execution_mode((FLAG_M>>4) | (FLAG_X>>4)); +} + + +void m37710_cpu_device::m37710i_set_reg_p(UINT32 value) +{ + FLAG_N = value; + FLAG_V = value << 1; + FLAG_D = value & FLAGPOS_D; + FLAG_Z = !(value & FLAGPOS_Z); + FLAG_C = value << 8; + m37710i_set_flag_mx(value); + FLAG_I = value & FLAGPOS_I; +} + + +/* ======================================================================== */ +/* =========================== OPERATION MACROS =========================== */ +/* ======================================================================== */ + +/* M37710 Push all */ +#undef OP_PSH + +#if FLAG_SET_M +#if FLAG_SET_X +#define OP_PSH(MODE) \ + SRC = OPER_8_##MODE(); \ + CLK(12); \ + if (SRC&0x1) \ + { m37710i_push_8(REG_A); CLK(2); } \ + if (SRC&0x2) \ + { m37710i_push_8(REG_BA); CLK(2); } \ + if (SRC&0x4) \ + { m37710i_push_8(REG_X); CLK(2); } \ + if (SRC&0x8) \ + { m37710i_push_8(REG_Y); CLK(2); } \ + if (SRC&0x10) \ + { m37710i_push_16(REG_D); CLK(2); } \ + if (SRC&0x20) \ + { m37710i_push_8(REG_DB>>16); CLK(1); } \ + if (SRC&0x40) \ + { m37710i_push_8(REG_PB>>16); CLK(1); } \ + if (SRC&0x80) \ + { m37710i_push_8(m_ipl); m37710i_push_8(m37710i_get_reg_p()); CLK(2); } +#else // FLAG_SET_X +#define OP_PSH(MODE) \ + SRC = OPER_8_##MODE(); \ + CLK(12); \ + if (SRC&0x1) \ + { m37710i_push_8(REG_A); CLK(2); } \ + if (SRC&0x2) \ + { m37710i_push_8(REG_BA); CLK(2); } \ + if (SRC&0x4) \ + { m37710i_push_16(REG_X); CLK(2); } \ + if (SRC&0x8) \ + { m37710i_push_16(REG_Y); CLK(2); } \ + if (SRC&0x10) \ + { m37710i_push_16(REG_D); CLK(2); } \ + if (SRC&0x20) \ + { m37710i_push_8(REG_DB>>16); CLK(1); } \ + if (SRC&0x40) \ + { m37710i_push_8(REG_PB>>16); CLK(1); } \ + if (SRC&0x80) \ + { m37710i_push_8(m_ipl); m37710i_push_8(m37710i_get_reg_p()); CLK(2); } +#endif // FLAG_SET_X +#else // FLAG_SET_M +#if FLAG_SET_X +#define OP_PSH(MODE) \ + SRC = OPER_8_##MODE(); \ + CLK(12); \ + if (SRC&0x1) \ + { m37710i_push_16(REG_A); CLK(2); } \ + if (SRC&0x2) \ + { m37710i_push_16(REG_BA); CLK(2); } \ + if (SRC&0x4) \ + { m37710i_push_8(REG_X); CLK(2); } \ + if (SRC&0x8) \ + { m37710i_push_8(REG_Y); CLK(2); } \ + if (SRC&0x10) \ + { m37710i_push_16(REG_D); CLK(2); } \ + if (SRC&0x20) \ + { m37710i_push_8(REG_DB>>16); CLK(1); } \ + if (SRC&0x40) \ + { m37710i_push_8(REG_PB>>16); CLK(1); } \ + if (SRC&0x80) \ + { m37710i_push_8(m_ipl); m37710i_push_8(m37710i_get_reg_p()); CLK(2); } +#else // FLAG_SET_X +#define OP_PSH(MODE) \ + SRC = OPER_8_##MODE(); \ + CLK(12); \ + if (SRC&0x1) \ + { m37710i_push_16(REG_A); CLK(2); } \ + if (SRC&0x2) \ + { m37710i_push_16(REG_BA); CLK(2);} \ + if (SRC&0x4) \ + { m37710i_push_16(REG_X); CLK(2); } \ + if (SRC&0x8) \ + { m37710i_push_16(REG_Y); CLK(2); } \ + if (SRC&0x10) \ + { m37710i_push_16(REG_D); CLK(2); } \ + if (SRC&0x20) \ + { m37710i_push_8(REG_DB>>16); CLK(1); } \ + if (SRC&0x40) \ + { m37710i_push_8(REG_PB>>16); CLK(1); } \ + if (SRC&0x80) \ + { m37710i_push_8(m_ipl); m37710i_push_8(m37710i_get_reg_p()); CLK(2); } +#endif // FLAG_SET_X +#endif // FLAG_SET_M + +/* M37710 Pull all */ +/* Unusual behavior: bit 6 has no effect */ +#undef OP_PUL +#define OP_PUL(MODE) \ + SRC = OPER_8_##MODE(); \ + CLK(14); \ + if (SRC&0x80) \ + { m37710i_set_reg_p(m37710i_pull_8()); m37710i_set_reg_ipl(m37710i_pull_8()); CLK(3); } \ + if (SRC&0x20) \ + { REG_DB = m37710i_pull_8() << 16; CLK(3); } \ + if (SRC&0x10) \ + { REG_D = m37710i_pull_16(); CLK(4); } \ + if (m37710i_get_reg_p() & XFLAG_SET) \ + { \ + if (SRC&0x8) \ + { REG_Y = m37710i_pull_8(); CLK(3); } \ + if (SRC&0x4) \ + { REG_X = m37710i_pull_8(); CLK(3); } \ + } \ + else \ + { \ + if (SRC&0x8) \ + { REG_Y = m37710i_pull_16(); CLK(3); } \ + if (SRC&0x4) \ + { REG_X = m37710i_pull_16(); CLK(3); } \ + } \ + if (m37710i_get_reg_p() & MFLAG_SET) \ + { \ + if (SRC&0x2) \ + { REG_BA = m37710i_pull_8(); CLK(3); } \ + if (SRC&0x1) \ + { REG_A = m37710i_pull_8(); CLK(3); } \ + } \ + else \ + { \ + if (SRC&0x2) \ + { REG_BA = m37710i_pull_16(); CLK(3); } \ + if (SRC&0x1) \ + { REG_A = m37710i_pull_16(); CLK(3); } \ + } \ + m37710i_update_irqs() + +/* M37710 Multiply */ +#undef OP_MPY +#if FLAG_SET_M +#define OP_MPY(MODE) \ + CLK(CLK_OP + CLK_R8 + CLK_##MODE + 14); \ + SRC = OPER_8_##MODE(); \ + { UINT16 temp = SRC * (REG_A&0xff); REG_A = temp & 0xff; REG_BA = (temp>>8)&0xff; FLAG_Z = temp; FLAG_N = (temp & 0x8000) ? 1 : 0; FLAG_C = 0; } +#else +#define OP_MPY(MODE) \ + CLK(CLK_OP + CLK_R16 + CLK_##MODE + 14+8); \ + SRC = OPER_16_##MODE(); \ + { UINT32 temp = SRC * REG_A; REG_A = temp & 0xffff; REG_BA = (temp>>16)&0xffff; FLAG_Z = temp; FLAG_N = (temp & 0x80000000) ? 1 : 0; FLAG_C = 0; } +#endif + +/* M37710 Divide */ +#undef OP_DIV +#if FLAG_SET_M +#define OP_DIV(MODE) \ + CLK(CLK_OP + CLK_R8 + CLK_##MODE + 17); \ + SRC = (REG_BA&0xff)<<8 | (REG_A & 0xff); \ + DST = OPER_8_##MODE(); \ + if (DST != 0) \ + { \ + UINT16 tempa = SRC / DST; UINT16 tempb = SRC % DST; \ + FLAG_V = ((tempa | tempb) & 0xff00) ? VFLAG_SET : 0; \ + FLAG_C = FLAG_V ? CFLAG_SET : 0; \ + if (!FLAG_V) { FLAG_N = (tempa & 0x80) ? 1 : 0; } \ + FLAG_Z = REG_A = tempa & 0xff; REG_BA = tempb & 0xff; \ + CLK(8); \ + } else m37710i_interrupt_software(0xfffc) +#else +#define OP_DIV(MODE) \ + CLK(CLK_OP + CLK_R16 + CLK_##MODE + 17); \ + SRC = (REG_BA<<16) | REG_A; \ + DST = OPER_16_##MODE(); \ + if (DST != 0) \ + { \ + UINT32 tempa = SRC / DST; UINT32 tempb = SRC % DST; \ + FLAG_V = ((tempa | tempb) & 0xffff0000) ? VFLAG_SET : 0; \ + FLAG_C = FLAG_V ? CFLAG_SET : 0; \ + if (!FLAG_V) { FLAG_N = (tempa & 0x8000) ? 1 : 0; } \ + FLAG_Z = REG_A = tempa & 0xffff; REG_BA = tempb & 0xffff; \ + CLK(8+15); \ + } else m37710i_interrupt_software(0xfffc) +#endif + +/* M37710 Add With Carry */ +#undef OP_ADC +#if FLAG_SET_M +#define OP_ADC(MODE) \ + CLK(CLK_OP + CLK_R8 + CLK_##MODE); \ + SRC = OPER_8_##MODE(); \ + FLAG_C = REG_A + SRC + CFLAG_AS_1(); \ + if(FLAG_D) \ + { \ + if((FLAG_C & 0xf) > 9) \ + FLAG_C+=6; \ + if((FLAG_C & 0xf0) > 0x90) \ + FLAG_C+=0x60; \ + } \ + FLAG_V = VFLAG_ADD_8(SRC, REG_A, FLAG_C); \ + FLAG_N = FLAG_Z = REG_A = MAKE_UINT_8(FLAG_C) +#else +#define OP_ADC(MODE) \ + CLK(CLK_OP + CLK_R16 + CLK_##MODE); \ + SRC = OPER_16_##MODE(); \ + if(!FLAG_D) \ + { \ + FLAG_C = REG_A + SRC + CFLAG_AS_1(); \ + FLAG_V = VFLAG_ADD_16(SRC, REG_A, FLAG_C); \ + FLAG_Z = REG_A = MAKE_UINT_16(FLAG_C); \ + FLAG_N = NFLAG_16(REG_A); \ + FLAG_C = CFLAG_16(FLAG_C); \ + BREAKOUT; \ + } \ + FLAG_C = MAKE_UINT_8(REG_A) + MAKE_UINT_8(SRC) + CFLAG_AS_1(); \ + if((FLAG_C & 0xf) > 9) \ + FLAG_C+=6; \ + if((FLAG_C & 0xf0) > 0x90) \ + FLAG_C+=0x60; \ + FLAG_Z = MAKE_UINT_8(FLAG_C); \ + \ + FLAG_C = MAKE_UINT_8(REG_A>>8) + MAKE_UINT_8(SRC>>8) + CFLAG_AS_1(); \ + if((FLAG_C & 0xf) > 9) \ + FLAG_C+=6; \ + if((FLAG_C & 0xf0) > 0x90) \ + FLAG_C+=0x60; \ + FLAG_Z |= MAKE_UINT_8(FLAG_C) << 8; \ + FLAG_N = NFLAG_16(FLAG_Z); \ + FLAG_V = VFLAG_ADD_16(SRC, REG_A, FLAG_C); \ + REG_A = FLAG_Z +#endif + +/* M37710 Add With Carry - B accumulator*/ +#undef OP_ADCB +#if FLAG_SET_M +#define OP_ADCB(MODE) \ + CLK(CLK_OP + CLK_R8 + CLK_##MODE); \ + SRC = OPER_8_##MODE(); \ + FLAG_C = REG_BA + SRC + CFLAG_AS_1(); \ + if(FLAG_D) \ + { \ + if((FLAG_C & 0xf) > 9) \ + FLAG_C+=6; \ + if((FLAG_C & 0xf0) > 0x90) \ + FLAG_C+=0x60; \ + } \ + FLAG_V = VFLAG_ADD_8(SRC, REG_BA, FLAG_C); \ + FLAG_N = FLAG_Z = REG_BA = MAKE_UINT_8(FLAG_C) +#else +#define OP_ADCB(MODE) \ + CLK(CLK_OP + CLK_R16 + CLK_##MODE); \ + SRC = OPER_16_##MODE(); \ + if(!FLAG_D) \ + { \ + FLAG_C = REG_BA + SRC + CFLAG_AS_1(); \ + FLAG_V = VFLAG_ADD_16(SRC, REG_BA, FLAG_C); \ + FLAG_Z = REG_BA = MAKE_UINT_16(FLAG_C); \ + FLAG_N = NFLAG_16(REG_BA); \ + FLAG_C = CFLAG_16(FLAG_C); \ + BREAKOUT; \ + } \ + FLAG_C = MAKE_UINT_8(REG_BA) + MAKE_UINT_8(SRC) + CFLAG_AS_1(); \ + if((FLAG_C & 0xf) > 9) \ + FLAG_C+=6; \ + if((FLAG_C & 0xf0) > 0x90) \ + FLAG_C+=0x60; \ + FLAG_Z = MAKE_UINT_8(FLAG_C); \ + \ + FLAG_C = MAKE_UINT_8(REG_BA>>8) + MAKE_UINT_8(SRC>>8) + CFLAG_AS_1(); \ + if((FLAG_C & 0xf) > 9) \ + FLAG_C+=6; \ + if((FLAG_C & 0xf0) > 0x90) \ + FLAG_C+=0x60; \ + FLAG_Z |= MAKE_UINT_8(FLAG_C) << 8; \ + FLAG_N = NFLAG_16(FLAG_Z); \ + FLAG_V = VFLAG_ADD_16(SRC, REG_BA, FLAG_C); \ + REG_BA = FLAG_Z +#endif + +/* M37710 Logical AND with accumulator */ +#undef OP_AND +#if FLAG_SET_M +#define OP_AND(MODE) \ + CLK(CLK_OP + CLK_R8 + CLK_##MODE); \ + FLAG_N = FLAG_Z = REG_A &= OPER_8_##MODE() +#else +#define OP_AND(MODE) \ + CLK(CLK_OP + CLK_R16 + CLK_##MODE); \ + FLAG_Z = REG_A &= OPER_16_##MODE(); \ + FLAG_N = NFLAG_16(REG_A) +#endif + +/* M37710 Logical AND with B accumulator */ +#undef OP_ANDB +#if FLAG_SET_M +#define OP_ANDB(MODE) \ + CLK(CLK_OP + CLK_R8 + CLK_##MODE); \ + FLAG_N = FLAG_Z = REG_BA &= OPER_8_##MODE() +#else +#define OP_ANDB(MODE) \ + CLK(CLK_OP + CLK_R16 + CLK_##MODE); \ + FLAG_Z = REG_BA &= OPER_16_##MODE(); \ + FLAG_N = NFLAG_16(REG_BA) +#endif + +/* M37710 Arithmetic Shift Left accumulator */ +#undef OP_ASL +#if FLAG_SET_M +#define OP_ASL() \ + CLK(CLK_OP + CLK_IMPLIED); \ + FLAG_C = REG_A << 1; \ + FLAG_N = FLAG_Z = REG_A = MAKE_UINT_8(FLAG_C) +#else +#define OP_ASL() \ + CLK(CLK_OP + CLK_IMPLIED); \ + FLAG_C = REG_A << 1; \ + FLAG_Z = REG_A = MAKE_UINT_16(FLAG_C); \ + FLAG_N = NFLAG_16(FLAG_C); \ + FLAG_C = CFLAG_16(FLAG_C) +#endif + +/* M37710 Arithmetic Shift Left B accumulator */ +#undef OP_BSL +#if FLAG_SET_M +#define OP_BSL() \ + CLK(CLK_OP + CLK_IMPLIED); \ + FLAG_C = REG_BA << 1; \ + FLAG_N = FLAG_Z = REG_BA = MAKE_UINT_8(FLAG_C) +#else +#define OP_BSL() \ + CLK(CLK_OP + CLK_IMPLIED); \ + FLAG_C = REG_BA << 1; \ + FLAG_Z = REG_BA = MAKE_UINT_16(FLAG_C); \ + FLAG_N = NFLAG_16(FLAG_C); \ + FLAG_C = CFLAG_16(FLAG_C) +#endif + +/* M37710 Arithmetic Shift Left operand */ +#undef OP_ASLM +#if FLAG_SET_M +#define OP_ASLM(MODE) \ + CLK(CLK_OP + CLK_RMW8 + CLK_W_##MODE); \ + DST = EA_##MODE(); \ + FLAG_C = read_8_##MODE(DST) << 1; \ + FLAG_N = FLAG_Z = MAKE_UINT_8(FLAG_C); \ + write_8_##MODE(DST, FLAG_Z) +#else +#define OP_ASLM(MODE) \ + CLK(CLK_OP + CLK_RMW16 + CLK_W_##MODE); \ + DST = EA_##MODE(); \ + FLAG_C = read_16_##MODE(DST) << 1; \ + FLAG_Z = MAKE_UINT_16(FLAG_C); \ + FLAG_N = NFLAG_16(FLAG_C); \ + FLAG_C = CFLAG_16(FLAG_C); \ + write_16_##MODE(DST, FLAG_Z) +#endif + +/* M37710 Branch on Condition Code */ +#undef OP_BCC +#define OP_BCC(COND) \ + DST = OPER_8_IMM(); \ + if(COND) \ + { \ + CLK(CLK_OP + CLK_RELATIVE_8 + 1); \ + m37710i_branch_8(DST); \ + BREAKOUT; \ + } \ + CLK(CLK_OP + CLK_RELATIVE_8); +/* M37710 Cause a Break interrupt */ +#undef OP_BRK +#define OP_BRK() \ + REG_PC++; CLK(CLK_OP + CLK_R8 + CLK_IMM); \ + logerror("error M37710: BRK at PC=%06x\n", REG_PB|REG_PC); \ + m37710i_interrupt_software(0xfffa) + +/* M37710 Branch Always */ +#undef OP_BRA +#define OP_BRA() \ + CLK(CLK_OP + CLK_IMPLIED + CLK_RELATIVE_8); \ + m37710i_branch_8(OPER_8_IMM()) + +/* M37710 Branch Always Long */ +#undef OP_BRL +#define OP_BRL() \ + CLK(CLK_OP + CLK_IMPLIED + CLK_RELATIVE_16); \ + m37710i_branch_16(OPER_16_IMM()) + +/* M37710 Clear Carry flag */ +#undef OP_CLC +#define OP_CLC() \ + CLK(CLK_OP + CLK_IMPLIED); \ + FLAG_C = CFLAG_CLEAR + +/* M37710 Clear Interrupt Mask flag */ +#undef OP_CLI +#define OP_CLI() \ + CLK(CLK_OP + CLK_IMPLIED); \ + FLAG_I = IFLAG_CLEAR; \ + m37710i_update_irqs() + +/* M37710 Clear oVerflow flag */ +#undef OP_CLV +#define OP_CLV() \ + CLK(CLK_OP + CLK_IMPLIED); \ + FLAG_V = VFLAG_CLEAR + +/* M37710 Compare operand to accumulator */ +/* Unusual behavior: C flag is inverted */ +#undef OP_CMP +#if FLAG_SET_M +#define OP_CMP(MODE) \ + CLK(CLK_OP + CLK_R8 + CLK_##MODE); \ + FLAG_C = REG_A - OPER_8_##MODE(); \ + FLAG_N = FLAG_Z = MAKE_UINT_8(FLAG_C); \ + FLAG_C ^= CFLAG_SET +#else +#define OP_CMP(MODE) \ + CLK(CLK_OP + CLK_R16 + CLK_##MODE); \ + FLAG_C = REG_A - OPER_16_##MODE(); \ + FLAG_Z = MAKE_UINT_16(FLAG_C); \ + FLAG_N = NFLAG_16(FLAG_C); \ + FLAG_C = ~CFLAG_16(FLAG_C) +#endif + +/* M37710 Compare operand to B accumulator */ +/* Unusual behavior: C flag is inverted */ +#undef OP_CMPB +#if FLAG_SET_M +#define OP_CMPB(MODE) \ + CLK(CLK_OP + CLK_R8 + CLK_##MODE); \ + FLAG_C = REG_BA - OPER_8_##MODE(); \ + FLAG_N = FLAG_Z = MAKE_UINT_8(FLAG_C); \ + FLAG_C ^= CFLAG_SET +#else +#define OP_CMPB(MODE) \ + CLK(CLK_OP + CLK_R16 + CLK_##MODE); \ + FLAG_C = REG_BA - OPER_16_##MODE(); \ + FLAG_Z = MAKE_UINT_16(FLAG_C); \ + FLAG_N = NFLAG_16(FLAG_C); \ + FLAG_C = ~CFLAG_16(FLAG_C) +#endif + +/* M37710 Compare operand to index register */ +/* Unusual behavior: C flag is inverted */ +#undef OP_CMPX +#if FLAG_SET_X +#define OP_CMPX(REG, MODE) \ + CLK(CLK_OP + CLK_R8 + CLK_##MODE); \ + FLAG_C = REG - OPER_8_##MODE(); \ + FLAG_N = FLAG_Z = MAKE_UINT_8(FLAG_C); \ + FLAG_C ^= CFLAG_SET +#else +#define OP_CMPX(REG, MODE) \ + CLK(CLK_OP + CLK_R16 + CLK_##MODE); \ + FLAG_C = REG - OPER_16_##MODE(); \ + FLAG_Z = MAKE_UINT_16(FLAG_C); \ + FLAG_N = NFLAG_16(FLAG_C); \ + FLAG_C = ~CFLAG_16(FLAG_C) +#endif + +/* M37710 Decrement accumulator */ +#undef OP_DEC +#if FLAG_SET_M +#define OP_DEC() \ + CLK(CLK_OP + CLK_IMPLIED); \ + FLAG_N = FLAG_Z = REG_A = MAKE_UINT_8(REG_A - 1) +#else +#define OP_DEC() \ + CLK(CLK_OP + CLK_IMPLIED); \ + FLAG_Z = REG_A = MAKE_UINT_16(REG_A - 1); \ + FLAG_N = NFLAG_16(REG_A) +#endif + +/* M37710 Decrement B accumulator */ +#undef OP_DECB +#if FLAG_SET_M +#define OP_DECB() \ + CLK(CLK_OP + CLK_IMPLIED); \ + FLAG_N = FLAG_Z = REG_BA = MAKE_UINT_8(REG_BA - 1) +#else +#define OP_DECB() \ + CLK(CLK_OP + CLK_IMPLIED); \ + FLAG_Z = REG_BA = MAKE_UINT_16(REG_BA - 1); \ + FLAG_N = NFLAG_16(REG_BA) +#endif + +/* M37710 Decrement operand */ +#undef OP_DECM +#if FLAG_SET_M +#define OP_DECM(MODE) \ + CLK(CLK_OP + CLK_RMW8 + CLK_W_##MODE); \ + DST = EA_##MODE(); \ + FLAG_N = FLAG_Z = MAKE_UINT_8(read_8_##MODE(DST) - 1); \ + write_8_##MODE(DST, FLAG_Z) +#else +#define OP_DECM(MODE) \ + CLK(CLK_OP + CLK_RMW16 + CLK_W_##MODE); \ + DST = EA_##MODE(); \ + FLAG_Z = MAKE_UINT_16(read_16_##MODE(DST) - 1); \ + FLAG_N = NFLAG_16(FLAG_Z); \ + write_16_##MODE(DST, FLAG_Z) +#endif + +/* M37710 Decrement index register */ +#undef OP_DECX +#if FLAG_SET_X +#define OP_DECX(REG) \ + CLK(CLK_OP + CLK_IMPLIED); \ + FLAG_N = FLAG_Z = REG = MAKE_UINT_8(REG - 1) +#else +#define OP_DECX(REG) \ + CLK(CLK_OP + CLK_IMPLIED); \ + FLAG_Z = REG = MAKE_UINT_16(REG - 1); \ + FLAG_N = NFLAG_16(REG) +#endif + +/* M37710 Exclusive Or operand to accumulator */ +#undef OP_EOR +#if FLAG_SET_M +#define OP_EOR(MODE) \ + CLK(CLK_OP + CLK_R8 + CLK_##MODE); \ + FLAG_N = FLAG_Z = REG_A ^= OPER_8_##MODE() +#else +#define OP_EOR(MODE) \ + CLK(CLK_OP + CLK_R16 + CLK_##MODE); \ + FLAG_Z = REG_A ^= OPER_16_##MODE(); \ + FLAG_N = NFLAG_16(REG_A) +#endif + +/* M37710 Exclusive Or operand to accumulator B */ +#undef OP_EORB +#if FLAG_SET_M +#define OP_EORB(MODE) \ + CLK(CLK_OP + CLK_R8 + CLK_##MODE); \ + FLAG_N = FLAG_Z = REG_BA ^= OPER_8_##MODE() +#else +#define OP_EORB(MODE) \ + CLK(CLK_OP + CLK_R16 + CLK_##MODE); \ + FLAG_Z = REG_BA ^= OPER_16_##MODE(); \ + FLAG_N = NFLAG_16(REG_BA) +#endif + +/* M37710 Increment accumulator */ +#undef OP_INC +#if FLAG_SET_M +#define OP_INC() \ + CLK(CLK_OP + CLK_IMPLIED); \ + FLAG_N = FLAG_Z = REG_A = MAKE_UINT_8(REG_A + 1) +#else +#define OP_INC() \ + CLK(CLK_OP + CLK_IMPLIED); \ + FLAG_Z = REG_A = MAKE_UINT_16(REG_A + 1); \ + FLAG_N = NFLAG_16(REG_A) +#endif + +/* M37710 Increment B accumulator */ +#undef OP_INCB +#if FLAG_SET_M +#define OP_INCB() \ + CLK(CLK_OP + CLK_IMPLIED); \ + FLAG_N = FLAG_Z = REG_BA = MAKE_UINT_8(REG_BA + 1) +#else +#define OP_INCB() \ + CLK(CLK_OP + CLK_IMPLIED); \ + FLAG_Z = REG_BA = MAKE_UINT_16(REG_BA + 1); \ + FLAG_N = NFLAG_16(REG_BA) +#endif + +/* M37710 Increment operand */ +#undef OP_INCM +#if FLAG_SET_M +#define OP_INCM(MODE) \ + CLK(CLK_OP + CLK_RMW8 + CLK_W_##MODE); \ + DST = EA_##MODE(); \ + FLAG_N = FLAG_Z = MAKE_UINT_8(read_8_##MODE(DST) + 1); \ + write_8_##MODE(DST, FLAG_Z) +#else +#define OP_INCM(MODE) \ + CLK(CLK_OP + CLK_RMW16 + CLK_W_##MODE); \ + DST = EA_##MODE(); \ + FLAG_Z = MAKE_UINT_16(read_16_##MODE(DST) + 1); \ + FLAG_N = NFLAG_16(FLAG_Z); \ + write_16_##MODE(DST, FLAG_Z) +#endif + +/* M37710 Increment index register */ +#undef OP_INCX +#if FLAG_SET_X +#define OP_INCX(REG) \ + CLK(CLK_OP + CLK_IMPLIED); \ + FLAG_N = FLAG_Z = REG = MAKE_UINT_8(REG + 1) +#else +#define OP_INCX(REG) \ + CLK(CLK_OP + CLK_IMPLIED); \ + FLAG_Z = REG = MAKE_UINT_16(REG + 1); \ + FLAG_N = NFLAG_16(REG) +#endif + +/* M37710 Jump Long */ +#undef OP_JMLAI +#define OP_JMLAI() \ + CLK(CLK_OP + CLK_AI + 1); \ + m37710i_jump_24(read_24_A(OPER_16_IMM())) + +/* M37710 Jump */ +#undef OP_JMP +#define OP_JMP(MODE) \ + CLK(CLK_OP + CLK_##MODE); \ + m37710i_jump_16(EA_##MODE()) + +/* M37710 Jump absolute indexed indirect */ +#undef OP_JMPAXI +#define OP_JMPAXI() \ + CLK(CLK_OP + CLK_AXI); \ + m37710i_jump_16(read_16_AXI(REG_PB | (MAKE_UINT_16(OPER_16_IMM() + REG_X)))) + +/* M37710 Jump absolute long */ +#undef OP_JMPAL +#define OP_JMPAL() \ + CLK(CLK_OP + CLK_AL); \ + m37710i_jump_24(EA_AL()) + +/* M37710 Jump to Subroutine Long */ +#undef OP_JSL +#define OP_JSL(MODE) \ + CLK(CLK_OP + CLK_W24 + CLK_##MODE + 1); \ + DST = EA_##MODE(); \ + m37710i_push_8(REG_PB>>16); \ + m37710i_push_16(REG_PC); \ + m37710i_jump_24(DST) + +/* M37710 Jump to Subroutine */ +#undef OP_JSR +#define OP_JSR(MODE) \ + CLK(CLK_OP + CLK_W16 + CLK_##MODE); \ + DST = EA_##MODE(); \ + m37710i_push_16(REG_PC); \ + m37710i_jump_16(DST) + +/* M37710 Jump to Subroutine */ +#undef OP_JSRAXI +#define OP_JSRAXI() \ + CLK(CLK_OP + CLK_W16 + CLK_AXI); \ + DST = read_16_AXI(REG_PB | (MAKE_UINT_16(OPER_16_IMM() + REG_X))); \ + m37710i_push_16(REG_PC); \ + m37710i_jump_16(DST) + +/* M37710 Load accumulator with operand */ +#undef OP_LDA +#if FLAG_SET_M +#define OP_LDA(MODE) \ + CLK(CLK_OP + CLK_R8 + CLK_##MODE); \ + FLAG_N = FLAG_Z = REG_A = OPER_8_##MODE() +#else +#define OP_LDA(MODE) \ + CLK(CLK_OP + CLK_R16 + CLK_##MODE); \ + FLAG_Z = REG_A = OPER_16_##MODE(); \ + FLAG_N = NFLAG_16(REG_A) +#endif + +/* M37710 Load B accumulator with operand */ +#undef OP_LDB +#if FLAG_SET_M +#define OP_LDB(MODE) \ + CLK(CLK_OP + CLK_R8 + CLK_##MODE); \ + FLAG_N = FLAG_Z = REG_BA = OPER_8_##MODE() +#else +#define OP_LDB(MODE) \ + CLK(CLK_OP + CLK_R16 + CLK_##MODE); \ + FLAG_Z = REG_BA = OPER_16_##MODE(); \ + FLAG_N = NFLAG_16(REG_BA) +#endif + +/* M37710 Load memory with operand */ +#undef OP_LDM +#if FLAG_SET_M +#define OP_LDM(MODE) \ + CLK(CLK_OP + CLK_R8 + CLK_##MODE); \ + REG_IM2 = EA_##MODE(); \ + REG_IM = read_8_IMM(REG_PB | REG_PC); \ + REG_PC++; \ + write_8_##MODE(REG_IM2, REG_IM) +#else +#define OP_LDM(MODE) \ + CLK(CLK_OP + CLK_R16 + CLK_##MODE); \ + REG_IM2 = EA_##MODE(); \ + REG_IM = read_16_IMM(REG_PB | REG_PC); \ + REG_PC+=2; \ + write_16_##MODE(REG_IM2, REG_IM) +#endif + +/* M37710 Branch if bits set */ +#undef OP_BBS +#if FLAG_SET_M +#define OP_BBS(MODE) \ + CLK(CLK_OP + CLK_R8 + CLK_##MODE); \ + REG_IM2 = read_8_NORM(EA_##MODE()); \ + REG_IM = read_8_IMM(REG_PB | REG_PC); \ + REG_PC++; \ + DST = OPER_8_IMM(); \ + if ((REG_IM2 & REG_IM) == REG_IM) \ + { \ + CLK(CLK_OP + CLK_RELATIVE_8 + 1); \ + m37710i_branch_8(DST); \ + BREAKOUT; \ + } +#else +#define OP_BBS(MODE) \ + CLK(CLK_OP + CLK_R16 + CLK_##MODE); \ + REG_IM2 = read_16_NORM(EA_##MODE()); \ + REG_IM = read_16_IMM(REG_PB | REG_PC); \ + REG_PC++; \ + REG_PC++; \ + DST = OPER_8_IMM(); \ + if ((REG_IM2 & REG_IM) == REG_IM) \ + { \ + CLK(CLK_OP + CLK_RELATIVE_8 + 1); \ + m37710i_branch_8(DST); \ + BREAKOUT; \ + } +#endif + +/* M37710 Branch if bits clear */ +#undef OP_BBC +#if FLAG_SET_M +#define OP_BBC(MODE) \ + CLK(CLK_OP + CLK_R8 + CLK_##MODE); \ + REG_IM2 = read_8_NORM(EA_##MODE()); \ + REG_IM = read_8_IMM(REG_PB | REG_PC); \ + REG_PC++; \ + DST = OPER_8_IMM(); \ + if ((REG_IM2 & REG_IM) == 0) \ + { \ + CLK(CLK_OP + CLK_RELATIVE_8 + 1); \ + m37710i_branch_8(DST); \ + BREAKOUT; \ + } +#else +#define OP_BBC(MODE) \ + CLK(CLK_OP + CLK_R16 + CLK_##MODE); \ + REG_IM2 = read_16_NORM(EA_##MODE()); \ + REG_IM = read_16_IMM(REG_PB | REG_PC); \ + REG_PC++; \ + REG_PC++; \ + DST = OPER_8_IMM(); \ + if ((REG_IM2 & REG_IM) == 0) \ + { \ + CLK(CLK_OP + CLK_RELATIVE_8 + 1); \ + m37710i_branch_8(DST); \ + BREAKOUT; \ + } +#endif + +/* M37710 Swap accumulators */ +#undef OP_XAB +#if FLAG_SET_M +#define OP_XAB() \ + CLK(6); \ + DST = REG_A; \ + FLAG_N = FLAG_Z = REG_A = REG_BA; \ + REG_BA = DST; +#else +#define OP_XAB() \ + CLK(6); \ + DST = REG_A; \ + FLAG_Z = REG_A = REG_BA; \ + FLAG_N = NFLAG_16(REG_A); \ + REG_BA = DST; +#endif + +/* M37710 Load index register with operand */ +#undef OP_LDX +#if FLAG_SET_X +#define OP_LDX(REG, MODE) \ + CLK(CLK_OP + CLK_R8 + CLK_##MODE); \ + FLAG_N = FLAG_Z = REG = OPER_8_##MODE() +#else +#define OP_LDX(REG, MODE) \ + CLK(CLK_OP + CLK_R16 + CLK_##MODE); \ + FLAG_Z = REG = OPER_16_##MODE(); \ + FLAG_N = NFLAG_16(REG) +#endif + +/* M37710 Logical Shift Right accumulator */ +#undef OP_LSR +#if FLAG_SET_M +#define OP_LSR() \ + CLK(CLK_OP + CLK_IMPLIED); \ + FLAG_N = 0; \ + FLAG_C = REG_A << 8; \ + FLAG_Z = REG_A >>= 1 +#else +#define OP_LSR() \ + CLK(CLK_OP + CLK_IMPLIED); \ + FLAG_N = 0; \ + FLAG_C = REG_A << 8; \ + FLAG_Z = REG_A >>= 1 +#endif + +/* M37710 Logical Shift Right B accumulator */ +#undef OP_LSRB +#if FLAG_SET_M +#define OP_LSRB() \ + CLK(CLK_OP + CLK_IMPLIED); \ + FLAG_N = 0; \ + FLAG_C = REG_BA << 8; \ + FLAG_Z = REG_BA >>= 1 +#else +#define OP_LSRB() \ + CLK(CLK_OP + CLK_IMPLIED); \ + FLAG_N = 0; \ + FLAG_C = REG_BA << 8; \ + FLAG_Z = REG_BA >>= 1 +#endif + +/* M37710 Logical Shift Right operand */ +#undef OP_LSRM +#if FLAG_SET_M +#define OP_LSRM(MODE) \ + CLK(CLK_OP + CLK_RMW8 + CLK_W_##MODE); \ + DST = EA_##MODE(); \ + FLAG_N = 0; \ + FLAG_Z = read_8_##MODE(DST); \ + FLAG_C = FLAG_Z << 8; \ + FLAG_Z >>= 1; \ + write_8_##MODE(DST, FLAG_Z) +#else +#define OP_LSRM(MODE) \ + CLK(CLK_OP + CLK_RMW16 + CLK_W_##MODE); \ + DST = EA_##MODE(); \ + FLAG_N = 0; \ + FLAG_Z = read_16_##MODE(DST); \ + FLAG_C = FLAG_Z << 8; \ + FLAG_Z >>= 1; \ + write_16_##MODE(DST, FLAG_Z) +#endif + +/* M37710 Move Block Negative */ +#undef OP_MVN +#if FLAG_SET_X +#define OP_MVN() \ + DST = OPER_8_IMM()<<16; \ + SRC = OPER_8_IMM()<<16; \ + REG_DB = DST; \ + REG_A |= REG_B; \ + CLK(7); \ + if (REG_A > 0) \ + { \ + write_8_NORM(DST | REG_Y, read_8_NORM(SRC | REG_X)); \ + REG_X = MAKE_UINT_8(REG_X+1); \ + REG_Y = MAKE_UINT_8(REG_Y+1); \ + REG_A--; \ + if ((REG_A&0xffff) != 0) \ + {\ + REG_PC -= 3; \ + }\ + else \ + { \ + if (FLAG_M) \ + { \ + REG_A = 0xff; \ + REG_B = 0xff00; \ + } \ + else \ + { \ + REG_A = 0xffff; \ + } \ + } \ + } +#else +#define OP_MVN() \ + DST = OPER_8_IMM()<<16; \ + SRC = OPER_8_IMM()<<16; \ + REG_DB = DST; \ + REG_A |= REG_B; \ + CLK(7); \ + if (REG_A > 0) \ + { \ + write_8_NORM(DST | REG_Y, read_8_NORM(SRC | REG_X)); \ + REG_X = MAKE_UINT_16(REG_X+1); \ + REG_Y = MAKE_UINT_16(REG_Y+1); \ + REG_A--; \ + if ((REG_A&0xffff) != 0) \ + {\ + REG_PC -= 3; \ + }\ + else \ + { \ + if (FLAG_M) \ + { \ + REG_A = 0xff; \ + REG_B = 0xff00; \ + } \ + else \ + { \ + REG_A = 0xffff; \ + } \ + } \ + } +#endif + +/* M37710 Move Block Positive */ +#undef OP_MVP +#if FLAG_SET_X +#define OP_MVP() \ + DST = OPER_8_IMM()<<16; \ + SRC = OPER_8_IMM()<<16; \ + REG_DB = DST; \ + REG_A |= REG_B; \ + CLK(7); \ + if (REG_A > 0) \ + { \ + write_8_NORM(DST | REG_Y, read_8_NORM(SRC | REG_X)); \ + REG_X = MAKE_UINT_8(REG_X-1); \ + REG_Y = MAKE_UINT_8(REG_Y-1); \ + REG_A--; \ + if ((REG_A&0xffff) != 0) \ + {\ + REG_PC -= 3; \ + }\ + else \ + { \ + if (FLAG_M) \ + { \ + REG_A = 0xff; \ + REG_B = 0xff00; \ + } \ + else \ + { \ + REG_A = 0xffff; \ + } \ + } \ + } +#else +#define OP_MVP() \ + DST = OPER_8_IMM()<<16; \ + SRC = OPER_8_IMM()<<16; \ + REG_DB = DST; \ + REG_A |= REG_B; \ + CLK(7); \ + if (REG_A > 0) \ + { \ + write_8_NORM(DST | REG_Y, read_8_NORM(SRC | REG_X)); \ + REG_X = MAKE_UINT_16(REG_X-1); \ + REG_Y = MAKE_UINT_16(REG_Y-1); \ + REG_A--; \ + if ((REG_A&0xffff) != 0) \ + {\ + REG_PC -= 3; \ + }\ + else \ + { \ + if (FLAG_M) \ + { \ + REG_A = 0xff; \ + REG_B = 0xff00; \ + } \ + else \ + { \ + REG_A = 0xffff; \ + } \ + } \ + } +#endif + +/* M37710 No Operation */ +#undef OP_NOP +#define OP_NOP() \ + CLK(CLK_OP + CLK_IMPLIED) + +/* M37710 Logical OR operand to accumulator */ +#undef OP_ORA +#if FLAG_SET_M +#define OP_ORA(MODE) \ + CLK(CLK_OP + CLK_R8 + CLK_##MODE); \ + FLAG_N = FLAG_Z = REG_A |= OPER_8_ ## MODE() +#else +#define OP_ORA(MODE) \ + CLK(CLK_OP + CLK_R16 + CLK_##MODE); \ + FLAG_Z = REG_A |= OPER_16_##MODE(); \ + FLAG_N = NFLAG_16(REG_A) +#endif + +/* M37710 Logical OR operand to B accumulator */ +#undef OP_ORB +#if FLAG_SET_M +#define OP_ORB(MODE) \ + CLK(CLK_OP + CLK_R8 + CLK_##MODE); \ + FLAG_N = FLAG_Z = REG_BA |= OPER_8_ ## MODE() +#else +#define OP_ORB(MODE) \ + CLK(CLK_OP + CLK_R16 + CLK_##MODE); \ + FLAG_Z = REG_BA |= OPER_16_##MODE(); \ + FLAG_N = NFLAG_16(REG_BA) +#endif + +/* M37710 Push Effective Address */ +#undef OP_PEA +#define OP_PEA() \ + CLK(CLK_OP + CLK_R16 + CLK_W16); \ + m37710i_push_16(OPER_16_IMM()) + +/* M37710 Push Effective Indirect Address */ +#undef OP_PEI +#define OP_PEI() \ + CLK(CLK_OP + CLK_R16 + CLK_W16 + CLK_D); \ + m37710i_push_16(EA_DI()) + +/* M37710 Push Effective PC-Relative Address */ +#undef OP_PER +#define OP_PER() \ + CLK(CLK_OP + CLK_R16 + CLK_W16 + 1); \ + SRC = OPER_16_IMM(); \ + m37710i_push_16(REG_PC + SRC) + +/* M37710 Push accumulator to the stack */ +#undef OP_PHA +#if FLAG_SET_M +#define OP_PHA() \ + CLK(CLK_OP + CLK_W8 + 1); \ + m37710i_push_8(REG_A) +#else +#define OP_PHA() \ + CLK(CLK_OP + CLK_W16 + 1); \ + m37710i_push_16(REG_A) +#endif + +/* M37710 Push B accumulator to the stack */ +#undef OP_PHAB +#if FLAG_SET_M +#define OP_PHAB() \ + CLK(CLK_OP + CLK_W8 + 1); \ + m37710i_push_8(REG_BA) +#else +#define OP_PHAB() \ + CLK(CLK_OP + CLK_W16 + 1); \ + m37710i_push_16(REG_BA) +#endif + +/* M37710 Push index register to the stack */ +#undef OP_PHX +#if FLAG_SET_X +#define OP_PHX(REG) \ + CLK(CLK_OP + CLK_W8 + 1); \ + m37710i_push_8(REG) +#else +#define OP_PHX(REG) \ + CLK(CLK_OP + CLK_W16 + 1); \ + m37710i_push_16(REG) +#endif + +/* M37710 Push data bank register */ +#undef OP_PHT +#define OP_PHT() \ + CLK(CLK_OP + CLK_W8 + 1); \ + m37710i_push_8(REG_DB>>16) + +/* M37710 Push direct register */ +#undef OP_PHD +#define OP_PHD() \ + CLK(CLK_OP + CLK_W16 + 1); \ + m37710i_push_16(REG_D) + +/* M37710 Push program bank register */ +#undef OP_PHK +#define OP_PHK() \ + CLK(CLK_OP + CLK_W8 + 1); \ + m37710i_push_8(REG_PB>>16) + +/* M37710 Push the Processor Status Register to the stack */ +#undef OP_PHP +#define OP_PHP() \ + CLK(CLK_OP + CLK_W8 + 1); \ + m37710i_push_8(m_ipl); \ + m37710i_push_8(m37710i_get_reg_p()) + +/* M37710 Pull accumulator from the stack */ +#undef OP_PLA +#if FLAG_SET_M +#define OP_PLA() \ + CLK(CLK_OP + CLK_R8 + 2); \ + FLAG_N = FLAG_Z = REG_A = m37710i_pull_8() +#else +#define OP_PLA() \ + CLK(CLK_OP + CLK_R16 + 2); \ + FLAG_Z = REG_A = m37710i_pull_16(); \ + FLAG_N = NFLAG_16(FLAG_Z) +#endif + +/* M37710 Pull B accumulator from the stack */ +#undef OP_PLAB +#if FLAG_SET_M +#define OP_PLAB() \ + CLK(CLK_OP + CLK_R8 + 2); \ + FLAG_N = FLAG_Z = REG_BA = m37710i_pull_8() +#else +#define OP_PLAB() \ + CLK(CLK_OP + CLK_R16 + 2); \ + FLAG_Z = REG_BA = m37710i_pull_16(); \ + FLAG_N = NFLAG_16(FLAG_Z) +#endif + +/* M37710 Pull index register from the stack */ +#undef OP_PLX +#if FLAG_SET_X +#define OP_PLX(REG) \ + CLK(CLK_OP + CLK_R8 + 2); \ + FLAG_N = FLAG_Z = REG = m37710i_pull_8() +#else +#define OP_PLX(REG) \ + CLK(CLK_OP + CLK_R16 + 2); \ + FLAG_Z = REG = m37710i_pull_16(); \ + FLAG_N = NFLAG_16(FLAG_Z) +#endif + +/* M37710 Pull data bank register */ +#undef OP_PLT +#define OP_PLT() \ + CLK(CLK_OP + CLK_R8 + 2); \ + FLAG_N = FLAG_Z = m37710i_pull_8(); \ + REG_DB = FLAG_Z << 16 + +/* M37710 Pull direct register */ +#undef OP_PLD +#define OP_PLD() \ + CLK(CLK_OP + CLK_R16 + 2); \ + REG_D = m37710i_pull_16() + +/* M37710 Pull the Processor Status Register from the stack */ +#undef OP_PLP +#define OP_PLP() \ + CLK(CLK_OP + CLK_R8 + 2); \ + m37710i_set_reg_p(m37710i_pull_8()); \ + m37710i_set_reg_ipl(m37710i_pull_8()); \ + m37710i_update_irqs() + +/* M37710 Reset Program status word */ +#undef OP_REP +#define OP_REP() \ + CLK(CLK_OP + CLK_R8 + 1); \ + m37710i_set_reg_p(m37710i_get_reg_p() & ~OPER_8_IMM()); \ + m37710i_update_irqs() + +/* M37710 Clear "M" status bit */ +#undef OP_CLM +#define OP_CLM() \ + CLK(CLK_OP + CLK_R8 + 1); \ + m37710i_set_reg_p(m37710i_get_reg_p() & ~FLAGPOS_M) + +/* M37710 Rotate Left the accumulator */ +#undef OP_ROL +#if FLAG_SET_M +#define OP_ROL() \ + CLK(CLK_OP + CLK_IMPLIED); \ + FLAG_C = (REG_A<<1) | CFLAG_AS_1(); \ + FLAG_N = FLAG_Z = REG_A = MAKE_UINT_8(FLAG_C) +#else +#define OP_ROL() \ + CLK(CLK_OP + CLK_IMPLIED); \ + FLAG_C = (REG_A<<1) | CFLAG_AS_1(); \ + FLAG_Z = REG_A = MAKE_UINT_16(FLAG_C); \ + FLAG_N = NFLAG_16(FLAG_C); \ + FLAG_C = CFLAG_16(FLAG_C) +#endif + +/* M37710 Rotate Left the B accumulator */ +#undef OP_ROLB +#if FLAG_SET_M +#define OP_ROLB() \ + CLK(CLK_OP + CLK_IMPLIED); \ + FLAG_C = (REG_BA<<1) | CFLAG_AS_1(); \ + FLAG_N = FLAG_Z = REG_BA = MAKE_UINT_8(FLAG_C) +#else +#define OP_ROLB() \ + CLK(CLK_OP + CLK_IMPLIED); \ + FLAG_C = (REG_BA<<1) | CFLAG_AS_1(); \ + FLAG_Z = REG_BA = MAKE_UINT_16(FLAG_C); \ + FLAG_N = NFLAG_16(FLAG_C); \ + FLAG_C = CFLAG_16(FLAG_C) +#endif + +/* M37710 Rotate Left the accumulator by a specified amount */ +#undef OP_RLA +#if FLAG_SET_M +#define OP_RLA(MODE) \ + { int cnt = OPER_8_##MODE(); while (cnt > 0) { CLK(6); REG_A=((REG_A<<1)|(REG_A>>7&1))&0xff; cnt--; } } +#else +#define OP_RLA(MODE) \ + { int cnt = OPER_16_##MODE(); while (cnt > 0) { CLK(6); REG_A=((REG_A<<1)|(REG_A>>15&1))&0xffff; cnt--; } } +#endif + +/* M37710 Rotate Left an operand */ +#undef OP_ROLM +#if FLAG_SET_M +#define OP_ROLM(MODE) \ + CLK(CLK_OP + CLK_RMW8 + CLK_W_##MODE); \ + DST = EA_##MODE(); \ + FLAG_C = (read_8_##MODE(DST)<<1) | CFLAG_AS_1(); \ + FLAG_N = FLAG_Z = MAKE_UINT_8(FLAG_C); \ + write_8_##MODE(DST, FLAG_Z) +#else +#define OP_ROLM(MODE) \ + CLK(CLK_OP + CLK_RMW16 + CLK_W_##MODE); \ + DST = EA_##MODE(); \ + FLAG_C = (read_16_##MODE(DST)<<1) | CFLAG_AS_1(); \ + FLAG_Z = MAKE_UINT_16(FLAG_C); \ + FLAG_N = NFLAG_16(FLAG_C); \ + FLAG_C = CFLAG_16(FLAG_C); \ + write_16_##MODE(DST, FLAG_Z) +#endif + +/* M37710 Rotate Right the accumulator */ +#undef OP_ROR +#if FLAG_SET_M +#define OP_ROR() \ + CLK(CLK_OP + CLK_IMPLIED); \ + REG_A |= FLAG_C & 0x100; \ + FLAG_C = REG_A << 8; \ + FLAG_N = FLAG_Z = REG_A >>= 1 +#else +#define OP_ROR() \ + CLK(CLK_OP + CLK_IMPLIED); \ + REG_A |= (FLAG_C<<8) & 0x10000; \ + FLAG_C = REG_A << 8; \ + FLAG_Z = REG_A >>= 1; \ + FLAG_N = NFLAG_16(REG_A) +#endif + +/* M37710 Rotate Right the B accumulator */ +#undef OP_RORB +#if FLAG_SET_M +#define OP_RORB() \ + CLK(CLK_OP + CLK_IMPLIED); \ + REG_BA |= FLAG_C & 0x100; \ + FLAG_C = REG_BA << 8; \ + FLAG_N = FLAG_Z = REG_BA >>= 1 +#else +#define OP_RORB() \ + CLK(CLK_OP + CLK_IMPLIED); \ + REG_BA |= (FLAG_C<<8) & 0x10000; \ + FLAG_C = REG_BA << 8; \ + FLAG_Z = REG_BA >>= 1; \ + FLAG_N = NFLAG_16(REG_BA) +#endif + +/* M37710 Rotate Right an operand */ +#undef OP_RORM +#if FLAG_SET_M +#define OP_RORM(MODE) \ + CLK(CLK_OP + CLK_RMW8 + CLK_W_##MODE); \ + DST = EA_##MODE(); \ + FLAG_Z = read_8_##MODE(DST) | (FLAG_C & 0x100); \ + FLAG_C = FLAG_Z << 8; \ + FLAG_N = FLAG_Z >>= 1; \ + write_8_##MODE(DST, FLAG_Z) +#else +#define OP_RORM(MODE) \ + CLK(CLK_OP + CLK_RMW16 + CLK_W_##MODE); \ + DST = EA_##MODE(); \ + FLAG_Z = read_16_##MODE(DST) | ((FLAG_C<<8) & 0x10000); \ + FLAG_C = FLAG_Z << 8; \ + FLAG_Z >>= 1; \ + FLAG_N = NFLAG_16(FLAG_Z); \ + write_16_##MODE(DST, FLAG_Z) +#endif + +/* M37710 Return from Interrupt */ +#undef OP_RTI +#define OP_RTI() \ + CLK(8); \ + m37710i_set_reg_p(m37710i_pull_8()); \ + m37710i_set_reg_ipl(m37710i_pull_8()); \ + m37710i_jump_16(m37710i_pull_16()); \ + REG_PB = m37710i_pull_8() << 16; \ + m37710i_update_irqs() + +/* M37710 Return from Subroutine Long */ +#undef OP_RTL +#define OP_RTL() \ + CLK(6); \ + m37710i_jump_24(m37710i_pull_24()) + +/* M37710 Return from Subroutine */ +#undef OP_RTS +#define OP_RTS() \ + CLK(6); \ + DST = m37710i_pull_16(); \ + m37710i_jump_16(DST) + +/* M37710 Subtract with Carry */ +/* Unusual behavior: C flag is inverted */ +#undef OP_SBC +#if FLAG_SET_M +#define OP_SBC(MODE) \ + CLK(CLK_OP + CLK_R8 + CLK_##MODE); \ + SRC = OPER_8_##MODE(); \ + FLAG_C = ~FLAG_C; \ + if(!FLAG_D) \ + { \ + FLAG_C = REG_A - SRC - CFLAG_AS_1(); \ + FLAG_V = VFLAG_SUB_8(SRC, REG_A, FLAG_C); \ + FLAG_N = FLAG_Z = REG_A = MAKE_UINT_8(FLAG_C); \ + FLAG_C = ~FLAG_C; \ + BREAKOUT; \ + } \ + DST = CFLAG_AS_1(); \ + FLAG_C = REG_A - SRC - DST; \ + FLAG_V = VFLAG_SUB_8(SRC, REG_A, FLAG_C); \ + if((FLAG_C & 0xf) > 9) \ + FLAG_C-=6; \ + if((FLAG_C & 0xf0) > 0x90) \ + FLAG_C-=0x60; \ + FLAG_N = FLAG_Z = REG_A = MAKE_UINT_8(FLAG_C); \ + FLAG_C = ~FLAG_C +#else +#define OP_SBC(MODE) \ + CLK(CLK_OP + CLK_R16 + CLK_##MODE); \ + SRC = OPER_16_##MODE(); \ + FLAG_C = ~FLAG_C; \ + if(!FLAG_D) \ + { \ + FLAG_C = REG_A - SRC - CFLAG_AS_1(); \ + FLAG_V = VFLAG_SUB_16(SRC, REG_A, FLAG_C); \ + FLAG_Z = REG_A = MAKE_UINT_16(FLAG_C); \ + FLAG_N = NFLAG_16(REG_A); \ + FLAG_C = ~CFLAG_16(FLAG_C); \ + BREAKOUT; \ + } \ + DST = CFLAG_AS_1(); \ + FLAG_C = MAKE_UINT_8(REG_A) - MAKE_UINT_8(SRC) - DST; \ + if((FLAG_C & 0xf) > 9) \ + FLAG_C-=6; \ + if((FLAG_C & 0xf0) > 0x90) \ + FLAG_C-=0x60; \ + FLAG_Z = MAKE_UINT_8(FLAG_C); \ + DST = CFLAG_AS_1(); \ + FLAG_C = MAKE_UINT_8(REG_A>>8) - MAKE_UINT_8(SRC>>8) - DST; \ + if((FLAG_C & 0xf) > 9) \ + FLAG_C-=6; \ + if((FLAG_C & 0xf0) > 0x90) \ + FLAG_C-=0x60; \ + FLAG_Z |= MAKE_UINT_8(FLAG_C) << 8; \ + FLAG_N = NFLAG_16(FLAG_Z); \ + FLAG_V = VFLAG_SUB_16(SRC, REG_A, FLAG_Z); \ + REG_A = FLAG_Z; \ + FLAG_C = ~FLAG_C +#endif + +/* M37710 Subtract with Carry - B accumulator */ +/* Unusual behavior: C flag is inverted */ +#undef OP_SBCB +#if FLAG_SET_M +#define OP_SBCB(MODE) \ + CLK(CLK_OP + CLK_R8 + CLK_##MODE); \ + SRC = OPER_8_##MODE(); \ + FLAG_C = ~FLAG_C; \ + if(!FLAG_D) \ + { \ + FLAG_C = REG_BA - SRC - CFLAG_AS_1(); \ + FLAG_V = VFLAG_SUB_8(SRC, REG_BA, FLAG_C); \ + FLAG_N = FLAG_Z = REG_BA = MAKE_UINT_8(FLAG_C); \ + FLAG_C = ~FLAG_C; \ + BREAKOUT; \ + } \ + DST = CFLAG_AS_1(); \ + FLAG_C = REG_BA - SRC - DST; \ + FLAG_V = VFLAG_SUB_8(SRC, REG_BA, FLAG_C); \ + if((FLAG_C & 0xf) > 9) \ + FLAG_C-=6; \ + if((FLAG_C & 0xf0) > 0x90) \ + FLAG_C-=0x60; \ + FLAG_N = FLAG_Z = REG_BA = MAKE_UINT_8(FLAG_C); \ + FLAG_C = ~FLAG_C +#else +#define OP_SBCB(MODE) \ + CLK(CLK_OP + CLK_R16 + CLK_##MODE); \ + SRC = OPER_16_##MODE(); \ + FLAG_C = ~FLAG_C; \ + if(!FLAG_D) \ + { \ + FLAG_C = REG_BA - SRC - CFLAG_AS_1(); \ + FLAG_V = VFLAG_SUB_16(SRC, REG_BA, FLAG_C); \ + FLAG_Z = REG_BA = MAKE_UINT_16(FLAG_C); \ + FLAG_N = NFLAG_16(REG_BA); \ + FLAG_C = ~CFLAG_16(FLAG_C); \ + BREAKOUT; \ + } \ + DST = CFLAG_AS_1(); \ + FLAG_C = MAKE_UINT_8(REG_BA) - MAKE_UINT_8(SRC) - DST; \ + if((FLAG_C & 0xf) > 9) \ + FLAG_C-=6; \ + if((FLAG_C & 0xf0) > 0x90) \ + FLAG_C-=0x60; \ + FLAG_Z = MAKE_UINT_8(FLAG_C); \ + DST = CFLAG_AS_1(); \ + FLAG_C = MAKE_UINT_8(REG_A>>8) - MAKE_UINT_8(SRC>>8) - DST; \ + if((FLAG_C & 0xf) > 9) \ + FLAG_C-=6; \ + if((FLAG_C & 0xf0) > 0x90) \ + FLAG_C-=0x60; \ + FLAG_Z |= MAKE_UINT_8(FLAG_C) << 8; \ + FLAG_N = NFLAG_16(FLAG_Z); \ + FLAG_V = VFLAG_SUB_16(SRC, REG_BA, FLAG_Z); \ + REG_BA = FLAG_Z; \ + FLAG_C = ~FLAG_C +#endif + +/* M37710 Set Carry flag */ +#undef OP_SEC +#define OP_SEC() \ + CLK(CLK_OP + CLK_IMPLIED); \ + FLAG_C = CFLAG_SET + +/* M37710 Set Interrupt Mask flag */ +#undef OP_SEI +#define OP_SEI() \ + CLK(CLK_OP + CLK_IMPLIED); \ + FLAG_I = IFLAG_SET + +/* M37710 Set Program status word */ +#undef OP_SEP +#define OP_SEP() \ + CLK(CLK_OP + CLK_R8 + 1); \ + m37710i_set_reg_p(m37710i_get_reg_p() | OPER_8_IMM()) + +/* M37710 Set "M" status bit */ +#undef OP_SEM +#define OP_SEM() \ + CLK(CLK_OP + CLK_R8 + 1); \ + m37710i_set_reg_p(m37710i_get_reg_p() | FLAGPOS_M) + +/* M37710 Store accumulator to memory */ +#undef OP_STA +#if FLAG_SET_M +#define OP_STA(MODE) \ + CLK(CLK_OP + CLK_W8 + CLK_W_##MODE); \ + write_8_##MODE(EA_##MODE(), REG_A) +#else +#define OP_STA(MODE) \ + CLK(CLK_OP + CLK_W16 + CLK_W_##MODE); \ + write_16_##MODE(EA_##MODE(), REG_A) +#endif + +/* M37710 Store B accumulator to memory */ +#undef OP_STB +#if FLAG_SET_M +#define OP_STB(MODE) \ + CLK(CLK_OP + CLK_W8 + CLK_W_##MODE); \ + write_8_##MODE(EA_##MODE(), REG_BA) +#else +#define OP_STB(MODE) \ + CLK(CLK_OP + CLK_W16 + CLK_W_##MODE); \ + write_16_##MODE(EA_##MODE(), REG_BA) +#endif + +/* M37710 Store index register to memory */ +#undef OP_STX +#if FLAG_SET_X +#define OP_STX(REG, MODE) \ + CLK(CLK_OP + CLK_W8 + CLK_W_##MODE); \ + write_8_##MODE(EA_##MODE(), REG) +#else +#define OP_STX(REG, MODE) \ + CLK(CLK_OP + CLK_W16 + CLK_W_##MODE); \ + write_16_##MODE(EA_##MODE(), REG) +#endif + +/* M37710 Stop the clock */ +#undef OP_STP +#define OP_STP() \ + USE_ALL_CLKS(); \ + CPU_STOPPED |= STOP_LEVEL_STOP + +/* M37710 Transfer accumulator to index */ +#undef OP_TAX +#if FLAG_SET_M +#if FLAG_SET_X +#define OP_TAX(REG) \ + CLK(CLK_OP + CLK_IMPLIED); \ + FLAG_Z = REG = REG_A; \ + FLAG_N = NFLAG_8(FLAG_Z) +#else /* FLAG_SET_X */ +#define OP_TAX(REG) \ + CLK(CLK_OP + CLK_IMPLIED); \ + FLAG_Z = REG = REG_B | REG_A; \ + FLAG_N = NFLAG_16(FLAG_Z) +#endif /* FLAG_SET_X */ +#else /* FLAG_SET_M */ +#if FLAG_SET_X +#define OP_TAX(REG) \ + CLK(CLK_OP + CLK_IMPLIED); \ + FLAG_Z = REG = MAKE_UINT_8(REG_A); \ + FLAG_N = NFLAG_8(FLAG_Z) +#else /* FLAG_SET_X */ +#define OP_TAX(REG) \ + CLK(CLK_OP + CLK_IMPLIED); \ + FLAG_Z = REG = REG_A; \ + FLAG_N = NFLAG_16(FLAG_Z) +#endif /* FLAG_SET_X */ +#endif /* FLAG_SET_M */ + + +/* M37710 Transfer accumulator B to index */ +#undef OP_TBX +#if FLAG_SET_M +#if FLAG_SET_X +#define OP_TBX(REG) \ + CLK(CLK_OP + CLK_IMPLIED); \ + FLAG_Z = REG = REG_BA; \ + FLAG_N = NFLAG_8(FLAG_Z) +#else /* FLAG_SET_X */ +#define OP_TBX(REG) \ + CLK(CLK_OP + CLK_IMPLIED); \ + FLAG_Z = REG = REG_BB | REG_BA; \ + FLAG_N = NFLAG_16(FLAG_Z) +#endif /* FLAG_SET_X */ +#else /* FLAG_SET_M */ +#if FLAG_SET_X +#define OP_TBX(REG) \ + CLK(CLK_OP + CLK_IMPLIED); \ + FLAG_Z = REG = MAKE_UINT_8(REG_BA); \ + FLAG_N = NFLAG_8(FLAG_Z) +#else /* FLAG_SET_X */ +#define OP_TBX(REG) \ + CLK(CLK_OP + CLK_IMPLIED); \ + FLAG_Z = REG = REG_BA; \ + FLAG_N = NFLAG_16(FLAG_Z) +#endif /* FLAG_SET_X */ +#endif /* FLAG_SET_M */ + +/* M37710 Transfer index to accumulator */ +#undef OP_TXA +#if FLAG_SET_M +#define OP_TXA(REG) \ + CLK(CLK_OP + CLK_IMPLIED); \ + FLAG_Z = REG_A = MAKE_UINT_8(REG); \ + FLAG_N = NFLAG_8(FLAG_Z) +#else +#define OP_TXA(REG) \ + CLK(CLK_OP + CLK_IMPLIED); \ + FLAG_Z = REG_A = REG; \ + FLAG_N = NFLAG_16(FLAG_Z) +#endif + +/* M37710 Transfer index to accumulator B */ +#undef OP_TXB +#if FLAG_SET_M +#define OP_TXB(REG) \ + CLK(CLK_OP + CLK_IMPLIED); \ + FLAG_Z = REG_BA = MAKE_UINT_8(REG); \ + FLAG_N = NFLAG_8(FLAG_Z) +#else +#define OP_TXB(REG) \ + CLK(CLK_OP + CLK_IMPLIED); \ + FLAG_Z = REG_BA = REG; \ + FLAG_N = NFLAG_16(FLAG_Z) +#endif + +/* M37710 Transfer accumulator to direct register */ +#undef OP_TAD +#if FLAG_SET_M +#define OP_TAD() \ + CLK(CLK_OP + CLK_IMPLIED); \ + REG_D = REG_A | REG_B +#else +#define OP_TAD() \ + CLK(CLK_OP + CLK_IMPLIED); \ + REG_D = REG_A +#endif + +/* M37710 Transfer accumulator B to direct register */ +#undef OP_TBD +#if FLAG_SET_M +#define OP_TBD() \ + CLK(CLK_OP + CLK_IMPLIED); \ + REG_D = REG_BA | REG_BB +#else +#define OP_TBD() \ + CLK(CLK_OP + CLK_IMPLIED); \ + REG_D = REG_BA +#endif + +/* M37710 Transfer direct register to accumulator */ +#undef OP_TDA +#if FLAG_SET_M +#define OP_TDA() \ + CLK(CLK_OP + CLK_IMPLIED); \ + FLAG_Z = REG_D; \ + FLAG_N = NFLAG_16(FLAG_Z); \ + REG_A = MAKE_UINT_8(REG_D); \ + REG_B = REG_D & 0xff00 +#else +#define OP_TDA() \ + CLK(CLK_OP + CLK_IMPLIED); \ + FLAG_Z = REG_A = REG_D; \ + FLAG_N = NFLAG_16(FLAG_Z) +#endif + +/* M37710 Transfer direct register to accumulator B */ +#undef OP_TDB +#if FLAG_SET_M +#define OP_TDB() \ + CLK(CLK_OP + CLK_IMPLIED); \ + FLAG_Z = REG_D; \ + FLAG_N = NFLAG_16(FLAG_Z); \ + REG_BA = MAKE_UINT_8(REG_D); \ + REG_BB = REG_D & 0xff00 +#else +#define OP_TDB() \ + CLK(CLK_OP + CLK_IMPLIED); \ + FLAG_Z = REG_BA = REG_D; \ + FLAG_N = NFLAG_16(FLAG_Z) +#endif + +/* M37710 Transfer accumulator to stack pointer */ +#undef OP_TAS +#if FLAG_SET_M +#define OP_TAS() \ + CLK(CLK_OP + CLK_IMPLIED); \ + REG_S = REG_A | REG_B +#else +#define OP_TAS() \ + CLK(CLK_OP + CLK_IMPLIED); \ + REG_S = REG_A +#endif + +/* M37710 Transfer accumulator B to stack pointer */ +#undef OP_TBS +#if FLAG_SET_M +#define OP_TBS() \ + CLK(CLK_OP + CLK_IMPLIED); \ + REG_S = REG_BA | REG_BB +#else +#define OP_TBS() \ + CLK(CLK_OP + CLK_IMPLIED); \ + REG_S = REG_BA +#endif + +/* M37710 Transfer stack pointer to accumulator */ +#undef OP_TSA +#if FLAG_SET_M +#define OP_TSA() \ + CLK(CLK_OP + CLK_IMPLIED); \ + FLAG_Z = REG_S; \ + FLAG_N = NFLAG_16(FLAG_Z); \ + REG_A = MAKE_UINT_8(REG_S); \ + REG_B = REG_S & 0xff00 +#else +#define OP_TSA() \ + CLK(CLK_OP + CLK_IMPLIED); \ + FLAG_Z = REG_A = REG_S; \ + FLAG_N = NFLAG_16(FLAG_Z) +#endif + +/* M37710 Transfer stack pointer to accumulator B */ +#undef OP_TSB +#if FLAG_SET_M +#define OP_TSB() \ + CLK(CLK_OP + CLK_IMPLIED); \ + FLAG_Z = REG_S; \ + FLAG_N = NFLAG_16(FLAG_Z); \ + REG_BA = MAKE_UINT_8(REG_S); \ + REG_BB = REG_S & 0xff00 +#else +#define OP_TSB() \ + CLK(CLK_OP + CLK_IMPLIED); \ + FLAG_Z = REG_BA = REG_S; \ + FLAG_N = NFLAG_16(FLAG_Z) +#endif + +/* M37710 Transfer stack pointer to X */ +#undef OP_TSX +#if FLAG_SET_X +#define OP_TSX() \ + CLK(CLK_OP + CLK_IMPLIED); \ + FLAG_Z = REG_X = MAKE_UINT_8(REG_S); \ + FLAG_N = NFLAG_8(FLAG_Z) +#else +#define OP_TSX() \ + CLK(CLK_OP + CLK_IMPLIED); \ + FLAG_Z = REG_X = REG_S; \ + FLAG_N = NFLAG_16(FLAG_Z) +#endif + +/* M37710 Transfer X to stack pointer */ +#undef OP_TXS +#if FLAG_SET_X +#define OP_TXS() \ + CLK(CLK_OP + CLK_IMPLIED); \ + REG_S = MAKE_UINT_8(REG_X) +#else +#define OP_TXS() \ + CLK(CLK_OP + CLK_IMPLIED); \ + REG_S = REG_X +#endif + +/* M37710 Transfer X to Y */ +#undef OP_TXY +#if FLAG_SET_X +#define OP_TXY() \ + CLK(CLK_OP + CLK_IMPLIED); \ + FLAG_Z = REG_Y = REG_X; \ + FLAG_N = NFLAG_8(FLAG_Z) +#else +#define OP_TXY() \ + CLK(CLK_OP + CLK_IMPLIED); \ + FLAG_Z = REG_Y = REG_X; \ + FLAG_N = NFLAG_16(FLAG_Z) +#endif + +/* M37710 Transfer Y to X */ +#undef OP_TYX +#if FLAG_SET_X +#define OP_TYX() \ + CLK(CLK_OP + CLK_IMPLIED); \ + FLAG_Z = REG_X = REG_Y; \ + FLAG_N = NFLAG_8(FLAG_Z) +#else +#define OP_TYX() \ + CLK(CLK_OP + CLK_IMPLIED); \ + FLAG_Z = REG_X = REG_Y; \ + FLAG_N = NFLAG_16(FLAG_Z) +#endif + +/* M37710 clear bit */ +#undef OP_CLB +#if FLAG_SET_M +#define OP_CLB(MODE) \ + CLK(CLK_OP + CLK_RMW8 + CLK_W_##MODE); \ + DST = EA_##MODE(); \ + REG_IM = read_8_##MODE(DST); \ + REG_IM2 = read_8_IMM(REG_PB | REG_PC); \ + REG_PC++; \ + write_8_##MODE(DST, REG_IM & ~REG_IM2); +#else +#define OP_CLB(MODE) \ + CLK(CLK_OP + CLK_RMW16 + CLK_W_##MODE); \ + DST = EA_##MODE(); \ + REG_IM = read_16_##MODE(DST); \ + REG_IM2 = read_16_IMM(REG_PB | REG_PC); \ + REG_PC+=2; \ + write_16_##MODE(DST, REG_IM & ~REG_IM2); +#endif + +/* M37710 set bit */ +#undef OP_SEB +#if FLAG_SET_M +#define OP_SEB(MODE) \ + CLK(CLK_OP + CLK_RMW8 + CLK_W_##MODE); \ + DST = EA_##MODE(); \ + REG_IM = read_8_##MODE(DST); \ + REG_IM2 = read_8_IMM(REG_PB | REG_PC); \ + REG_PC++; \ + write_8_##MODE(DST, REG_IM | REG_IM2); +#else +#define OP_SEB(MODE) \ + CLK(CLK_OP + CLK_RMW16 + CLK_W_##MODE); \ + DST = EA_##MODE(); \ + REG_IM = read_16_##MODE(DST); \ + REG_IM2 = read_16_IMM(REG_PB | REG_PC); \ + REG_PC+=2; \ + write_16_##MODE(DST, REG_IM | REG_IM2); +#endif + +/* M37710 Wait for interrupt */ +#undef OP_WAI +#define OP_WAI() \ + USE_ALL_CLKS(); \ + CPU_STOPPED |= STOP_LEVEL_WAI + +/* M37710 load data bank register */ +#undef OP_LDT +#define OP_LDT(MODE) \ + CLK(CLK_OP + CLK_R8 + CLK_##MODE); \ + REG_DB = OPER_8_##MODE()<<16; + + +/* M37710 prefix for B accumulator (0x42) */ +/* There is a 2 cycle penalty for all instructions using this prefix */ +#undef OP_PFB +#define OP_PFB() \ + CLK(2); \ + REG_IR = read_8_IMM(REG_PB | REG_PC); \ + REG_PC++; \ + (this->*m_opcodes42[REG_IR])(); + + +/* M37710 prefix for multiply / divide instructions (0x89) */ +#undef OP_PFXM +#define OP_PFXM() \ + REG_IR = read_8_IMM(REG_PB | REG_PC); \ + REG_PC++; \ + (this->*m_opcodes89[REG_IR])(); + + +/* M37710 unimplemented opcode */ +#undef OP_UNIMP +#define OP_UNIMP() \ + logerror("error M37710: UNIMPLEMENTED OPCODE! K=%x PC=%x\n", REG_PB, REG_PPC); + +/* ======================================================================== */ +/* ======================== OPCODE & FUNCTION TABLES ====================== */ +/* ======================================================================== */ + +#undef OP +#undef O +#undef TABLE_OPCODES +#undef TABLE_FUNCTION + +#if !FLAG_SET_M && !FLAG_SET_X +#define OP(CODE, OPERATION) void m37710_cpu_device::m37710i_ ## CODE ## _M0X0() {OPERATION;} +#define O(CODE) &m37710_cpu_device::m37710i_ ## CODE ## _M0X0 +#define TABLE_OPCODES const m37710_cpu_device::opcode_func m37710_cpu_device::m37710i_opcodes_M0X0[256] +#define TABLE_OPCODES2 const m37710_cpu_device::opcode_func m37710_cpu_device::m37710i_opcodes42_M0X0[256] +#define TABLE_OPCODES3 const m37710_cpu_device::opcode_func m37710_cpu_device::m37710i_opcodes89_M0X0[256] +#define TABLE_FUNCTION(RTYPE, NAME, ARGS) RTYPE m37710_cpu_device::m37710i_ ## NAME ## _M0X0 ARGS + +#elif !FLAG_SET_M && FLAG_SET_X + +#define OP(CODE, OPERATION) void m37710_cpu_device::m37710i_ ## CODE ## _M0X1() {OPERATION;} +#define O(CODE) &m37710_cpu_device::m37710i_ ## CODE ## _M0X1 +#define TABLE_OPCODES const m37710_cpu_device::opcode_func m37710_cpu_device::m37710i_opcodes_M0X1[256] +#define TABLE_OPCODES2 const m37710_cpu_device::opcode_func m37710_cpu_device::m37710i_opcodes42_M0X1[256] +#define TABLE_OPCODES3 const m37710_cpu_device::opcode_func m37710_cpu_device::m37710i_opcodes89_M0X1[256] +#define TABLE_FUNCTION(RTYPE, NAME, ARGS) RTYPE m37710_cpu_device::m37710i_ ## NAME ## _M0X1 ARGS + +#elif FLAG_SET_M && !FLAG_SET_X + +#define OP(CODE, OPERATION) void m37710_cpu_device::m37710i_ ## CODE ## _M1X0() {OPERATION;} +#define O(CODE) &m37710_cpu_device::m37710i_ ## CODE ## _M1X0 +#define TABLE_OPCODES const m37710_cpu_device::opcode_func m37710_cpu_device::m37710i_opcodes_M1X0[256] +#define TABLE_OPCODES2 const m37710_cpu_device::opcode_func m37710_cpu_device::m37710i_opcodes42_M1X0[256] +#define TABLE_OPCODES3 const m37710_cpu_device::opcode_func m37710_cpu_device::m37710i_opcodes89_M1X0[256] +#define TABLE_FUNCTION(RTYPE, NAME, ARGS) RTYPE m37710_cpu_device::m37710i_ ## NAME ## _M1X0 ARGS + +#elif FLAG_SET_M && FLAG_SET_X + +#define OP(CODE, OPERATION) void m37710_cpu_device::m37710i_ ## CODE ## _M1X1() {OPERATION;} +#define O(CODE) &m37710_cpu_device::m37710i_ ## CODE ## _M1X1 +#define TABLE_OPCODES const m37710_cpu_device::opcode_func m37710_cpu_device::m37710i_opcodes_M1X1[256] +#define TABLE_OPCODES2 const m37710_cpu_device::opcode_func m37710_cpu_device::m37710i_opcodes42_M1X1[256] +#define TABLE_OPCODES3 const m37710_cpu_device::opcode_func m37710_cpu_device::m37710i_opcodes89_M1X1[256] +#define TABLE_FUNCTION(RTYPE, NAME, ARGS) RTYPE m37710_cpu_device::m37710i_ ## NAME ## _M1X1 ARGS + +#endif + +#define BREAKOUT return + +/* OP FUNCTION Comment */ +OP(00, OP_BRK ( ) ) /* BRK */ +OP(01, OP_ORA ( DXI ) ) /* ORA dxi */ +OP(02, OP_NOP ( ) ) /* unused */ +OP(03, OP_ORA ( S ) ) /* ORA s (G) */ +OP(04, OP_SEB ( D ) ) /* SEB d (C) */ +OP(05, OP_ORA ( D ) ) /* ORA d */ +OP(06, OP_ASLM ( D ) ) /* ASL d */ +OP(07, OP_ORA ( DLI ) ) /* ORA dli (G) */ +OP(08, OP_PHP ( ) ) /* PHP */ +OP(09, OP_ORA ( IMM ) ) /* ORA imm */ +OP(0a, OP_ASL ( ) ) /* ASL acc */ +OP(0b, OP_PHD ( ) ) /* PHD (G) */ +OP(0c, OP_SEB ( A ) ) /* SEB a (C) */ +OP(0d, OP_ORA ( A ) ) /* ORA a */ +OP(0e, OP_ASLM ( A ) ) /* ASL a */ +OP(0f, OP_ORA ( AL ) ) /* ORA al (G) */ +OP(10, OP_BCC ( COND_PL() ) ) /* BPL */ +OP(11, OP_ORA ( DIY ) ) /* ORA diy */ +OP(12, OP_ORA ( DI ) ) /* ORA di (C) */ +OP(13, OP_ORA ( SIY ) ) /* ORA siy (G) */ +OP(14, OP_CLB ( D ) ) /* CLB d (C) */ +OP(15, OP_ORA ( DX ) ) /* ORA dx */ +OP(16, OP_ASLM ( DX ) ) /* ASL dx */ +OP(17, OP_ORA ( DLIY ) ) /* ORA dliy(C) */ +OP(18, OP_CLC ( ) ) /* CLC */ +OP(19, OP_ORA ( AY ) ) /* ORA ay */ +OP(1a, OP_DEC ( ) ) /* DEA (C) */ +OP(1b, OP_TAS ( ) ) /* TAS (G) */ +OP(1c, OP_CLB ( A ) ) /* CLB a (C) */ +OP(1d, OP_ORA ( AX ) ) /* ORA ax */ +OP(1e, OP_ASLM ( AX ) ) /* ASL ax */ +OP(1f, OP_ORA ( ALX ) ) /* ORA alx (G) */ +OP(20, OP_JSR ( A ) ) /* JSR a */ +OP(21, OP_AND ( DXI ) ) /* AND dxi */ +OP(22, OP_JSL ( AL ) ) /* JSL al (G) */ +OP(23, OP_AND ( S ) ) /* AND s (G) */ +OP(24, OP_BBS ( D ) ) /* BBS d */ +OP(25, OP_AND ( D ) ) /* AND d */ +OP(26, OP_ROLM ( D ) ) /* ROL d */ +OP(27, OP_AND ( DLI ) ) /* AND dli (G) */ +OP(28, OP_PLP ( ) ) /* PLP */ +OP(29, OP_AND ( IMM ) ) /* AND imm */ +OP(2a, OP_ROL ( ) ) /* ROL acc */ +OP(2b, OP_PLD ( ) ) /* PLD (G) */ +OP(2c, OP_BBS ( A ) ) /* BBS a */ +OP(2d, OP_AND ( A ) ) /* AND a */ +OP(2e, OP_ROLM ( A ) ) /* ROL a */ +OP(2f, OP_AND ( AL ) ) /* AND al (G) */ +OP(30, OP_BCC ( COND_MI() ) ) /* BMI */ +OP(31, OP_AND ( DIY ) ) /* AND diy */ +OP(32, OP_AND ( DI ) ) /* AND di (C) */ +OP(33, OP_AND ( SIY ) ) /* AND siy */ +OP(34, OP_BBC ( D ) ) /* BBC d */ +OP(35, OP_AND ( DX ) ) /* AND dx */ +OP(36, OP_ROLM ( DX ) ) /* ROL dx */ +OP(37, OP_AND ( DLIY ) ) /* AND dliy(G) */ +OP(38, OP_SEC ( ) ) /* SEC */ +OP(39, OP_AND ( AY ) ) /* AND ay */ +OP(3a, OP_INC ( ) ) /* INA (C) */ +OP(3b, OP_TSA ( ) ) /* TSA (G) */ +OP(3c, OP_BBC ( A ) ) /* BBC a */ +OP(3d, OP_AND ( AX ) ) /* AND ax */ +OP(3e, OP_ROLM ( AX ) ) /* ROL ax */ +OP(3f, OP_AND ( ALX ) ) /* AND alx (G) */ +OP(40, OP_RTI ( ) ) /* RTI */ +OP(41, OP_EOR ( DXI ) ) /* EOR dxi */ +OP(42, OP_PFB ( ) ) /* prefix for "B" accumulator */ +OP(43, OP_EOR ( S ) ) /* EOR s (G) */ +OP(44, OP_MVP ( ) ) /* MVP (G) */ +OP(45, OP_EOR ( D ) ) /* EOR d */ +OP(46, OP_LSRM ( D ) ) /* LSR d */ +OP(47, OP_EOR ( DLI ) ) /* EOR dli (G) */ +OP(48, OP_PHA ( ) ) /* PHA */ +OP(49, OP_EOR ( IMM ) ) /* EOR imm */ +OP(4a, OP_LSR ( ) ) /* LSR acc */ +OP(4b, OP_PHK ( ) ) /* PHK (G) */ +OP(4c, OP_JMP ( A ) ) /* JMP a */ +OP(4d, OP_EOR ( A ) ) /* EOR a */ +OP(4e, OP_LSRM ( A ) ) /* LSR a */ +OP(4f, OP_EOR ( AL ) ) /* EOR al (G) */ +OP(50, OP_BCC ( COND_VC() ) ) /* BVC */ +OP(51, OP_EOR ( DIY ) ) /* EOR diy */ +OP(52, OP_EOR ( DI ) ) /* EOR di (C) */ +OP(53, OP_EOR ( SIY ) ) /* EOR siy (G) */ +OP(54, OP_MVN ( ) ) /* MVN (G) */ +OP(55, OP_EOR ( DX ) ) /* EOR dx */ +OP(56, OP_LSRM ( DX ) ) /* LSR dx */ +OP(57, OP_EOR ( DLIY ) ) /* EOR dliy(G) */ +OP(58, OP_CLI ( ) ) /* CLI */ +OP(59, OP_EOR ( AY ) ) /* EOR ay */ +OP(5a, OP_PHX ( REG_Y ) ) /* PHY (C) */ +OP(5b, OP_TAD ( ) ) /* TAD (G) */ +OP(5c, OP_JMPAL( ) ) /* JMP al (G) */ +OP(5d, OP_EOR ( AX ) ) /* EOR ax */ +OP(5e, OP_LSRM ( AX ) ) /* LSR ax */ +OP(5f, OP_EOR ( ALX ) ) /* EOR alx (G) */ +OP(60, OP_RTS ( ) ) /* RTS */ +OP(61, OP_ADC ( DXI ) ) /* ADC dxi */ +OP(62, OP_PER ( ) ) /* PER (G) */ +OP(63, OP_ADC ( S ) ) /* ADC s (G) */ +OP(64, OP_LDM ( D ) ) /* LDM d (C) */ +OP(65, OP_ADC ( D ) ) /* ADC d */ +OP(66, OP_RORM ( D ) ) /* ROR d */ +OP(67, OP_ADC ( DLI ) ) /* ADC dli (G) */ +OP(68, OP_PLA ( ) ) /* PLA */ +OP(69, OP_ADC ( IMM ) ) /* ADC imm */ +OP(6a, OP_ROR ( ) ) /* ROR acc */ +OP(6b, OP_RTL ( ) ) /* RTL (G) */ +OP(6c, OP_JMP ( AI ) ) /* JMP ai */ +OP(6d, OP_ADC ( A ) ) /* ADC a */ +OP(6e, OP_RORM ( A ) ) /* ROR a */ +OP(6f, OP_ADC ( AL ) ) /* ADC al (G) */ +OP(70, OP_BCC ( COND_VS() ) ) /* BVS */ +OP(71, OP_ADC ( DIY ) ) /* ADC diy */ +OP(72, OP_ADC ( DI ) ) /* ADC di (G) */ +OP(73, OP_ADC ( SIY ) ) /* ADC siy (G) */ +OP(74, OP_LDM ( DX ) ) /* LDM dx (C) */ +OP(75, OP_ADC ( DX ) ) /* ADC dx */ +OP(76, OP_RORM ( DX ) ) /* ROR dx */ +OP(77, OP_ADC ( DLIY ) ) /* ADC dliy(G) */ +OP(78, OP_SEI ( ) ) /* SEI */ +OP(79, OP_ADC ( AY ) ) /* ADC ay */ +OP(7a, OP_PLX ( REG_Y ) ) /* PLY (C) */ +OP(7b, OP_TDA ( ) ) /* TDA (G) */ +OP(7c, OP_JMPAXI( ) ) /* JMP axi (C) */ +OP(7d, OP_ADC ( AX ) ) /* ADC ax */ +OP(7e, OP_RORM ( AX ) ) /* ROR ax */ +OP(7f, OP_ADC ( ALX ) ) /* ADC alx (G) */ +OP(80, OP_BRA ( ) ) /* BRA (C) */ +OP(81, OP_STA ( DXI ) ) /* STA dxi */ +OP(82, OP_BRL ( ) ) /* BRL (G) */ +OP(83, OP_STA ( S ) ) /* STA s (G) */ +OP(84, OP_STX ( REG_Y, D ) ) /* STY d */ +OP(85, OP_STA ( D ) ) /* STA d */ +OP(86, OP_STX ( REG_X, D ) ) /* STX d */ +OP(87, OP_STA ( DLI ) ) /* STA dli (G) */ +OP(88, OP_DECX ( REG_Y ) ) /* DEY */ +OP(89, OP_PFXM ( ) ) /* prefix for mul/div insns */ +OP(8a, OP_TXA ( REG_X ) ) /* TXA */ +OP(8b, OP_PHT ( ) ) /* PHT (G) */ +OP(8c, OP_STX ( REG_Y, A ) ) /* STY a */ +OP(8d, OP_STA ( A ) ) /* STA a */ +OP(8e, OP_STX ( REG_X, A ) ) /* STX a */ +OP(8f, OP_STA ( AL ) ) /* STA al (G) */ +OP(90, OP_BCC ( COND_CC() ) ) /* BCC */ +OP(91, OP_STA ( DIY ) ) /* STA diy */ +OP(92, OP_STA ( DI ) ) /* STA di (C) */ +OP(93, OP_STA ( SIY ) ) /* STA siy (G) */ +OP(94, OP_STX ( REG_Y, DX ) ) /* STY dx */ +OP(95, OP_STA ( DX ) ) /* STA dx */ +OP(96, OP_STX ( REG_X, DY ) ) /* STX dy */ +OP(97, OP_STA ( DLIY ) ) /* STA dliy(G) */ +OP(98, OP_TXA ( REG_Y ) ) /* TYA */ +OP(99, OP_STA ( AY ) ) /* STA ay */ +OP(9a, OP_TXS ( ) ) /* TXS */ +OP(9b, OP_TXY ( ) ) /* TXY (G) */ +OP(9c, OP_LDM ( A ) ) /* LDM a (C) */ +OP(9d, OP_STA ( AX ) ) /* STA ax */ +OP(9e, OP_LDM ( AX ) ) /* LDM ax (C) */ +OP(9f, OP_STA ( ALX ) ) /* STA alx (G) */ +OP(a0, OP_LDX ( REG_Y, IMM ) ) /* LDY imm */ +OP(a1, OP_LDA ( DXI ) ) /* LDA dxi */ +OP(a2, OP_LDX ( REG_X, IMM ) ) /* LDX imm */ +OP(a3, OP_LDA ( S ) ) /* LDA s (G) */ +OP(a4, OP_LDX ( REG_Y, D ) ) /* LDY d */ +OP(a5, OP_LDA ( D ) ) /* LDA d */ +OP(a6, OP_LDX ( REG_X, D ) ) /* LDX d */ +OP(a7, OP_LDA ( DLI ) ) /* LDA dli (G) */ +OP(a8, OP_TAX ( REG_Y ) ) /* TAY */ +OP(a9, OP_LDA ( IMM ) ) /* LDA imm */ +OP(aa, OP_TAX ( REG_X ) ) /* TAX */ +OP(ab, OP_PLT ( ) ) /* PLT (G) */ +OP(ac, OP_LDX ( REG_Y, A ) ) /* LDY a */ +OP(ad, OP_LDA ( A ) ) /* LDA a */ +OP(ae, OP_LDX ( REG_X, A ) ) /* LDX a */ +OP(af, OP_LDA ( AL ) ) /* LDA al (G) */ +OP(b0, OP_BCC ( COND_CS() ) ) /* BCS */ +OP(b1, OP_LDA ( DIY ) ) /* LDA diy */ +OP(b2, OP_LDA ( DI ) ) /* LDA di (C) */ +OP(b3, OP_LDA ( SIY ) ) /* LDA siy (G) */ +OP(b4, OP_LDX ( REG_Y, DX ) ) /* LDY dx */ +OP(b5, OP_LDA ( DX ) ) /* LDA dx */ +OP(b6, OP_LDX ( REG_X, DY ) ) /* LDX dy */ +OP(b7, OP_LDA ( DLIY ) ) /* LDA dliy(G) */ +OP(b8, OP_CLV ( ) ) /* CLV */ +OP(b9, OP_LDA ( AY ) ) /* LDA ay */ +OP(ba, OP_TSX ( ) ) /* TSX */ +OP(bb, OP_TYX ( ) ) /* TYX (G) */ +OP(bc, OP_LDX ( REG_Y, AX ) ) /* LDY ax */ +OP(bd, OP_LDA ( AX ) ) /* LDA ax */ +OP(be, OP_LDX ( REG_X, AY ) ) /* LDX ay */ +OP(bf, OP_LDA ( ALX ) ) /* LDA alx (G) */ +OP(c0, OP_CMPX ( REG_Y, IMM ) ) /* CPY imm */ +OP(c1, OP_CMP ( DXI ) ) /* CMP dxi */ +OP(c2, OP_REP ( ) ) /* REP (G) */ +OP(c3, OP_CMP ( S ) ) /* CMP s (G) */ +OP(c4, OP_CMPX ( REG_Y, D ) ) /* CPY d */ +OP(c5, OP_CMP ( D ) ) /* CMP d */ +OP(c6, OP_DECM ( D ) ) /* DEC d */ +OP(c7, OP_CMP ( DLI ) ) /* CMP dli (G) */ +OP(c8, OP_INCX ( REG_Y ) ) /* INY */ +OP(c9, OP_CMP ( IMM ) ) /* CMP imm */ +OP(ca, OP_DECX ( REG_X ) ) /* DEX */ +OP(cb, OP_WAI ( ) ) /* WAI (G) */ +OP(cc, OP_CMPX ( REG_Y, A ) ) /* CPY a */ +OP(cd, OP_CMP ( A ) ) /* CMP a */ +OP(ce, OP_DECM ( A ) ) /* DEC a */ +OP(cf, OP_CMP ( AL ) ) /* CMP al (G) */ +OP(d0, OP_BCC ( COND_NE() ) ) /* BNE */ +OP(d1, OP_CMP ( DIY ) ) /* CMP diy */ +OP(d2, OP_CMP ( DI ) ) /* CMP di (C) */ +OP(d3, OP_CMP ( SIY ) ) /* CMP siy (G) */ +OP(d4, OP_PEI ( ) ) /* PEI (G) */ +OP(d5, OP_CMP ( DX ) ) /* CMP dx */ +OP(d6, OP_DECM ( DX ) ) /* DEC dx */ +OP(d7, OP_CMP ( DLIY ) ) /* CMP dliy(G) */ +OP(d8, OP_CLM ( ) ) /* CLM */ +OP(d9, OP_CMP ( AY ) ) /* CMP ay */ +OP(da, OP_PHX ( REG_X ) ) /* PHX (C) */ +OP(db, OP_STP ( ) ) /* STP (G) */ +OP(dc, OP_JMLAI( ) ) /* JML ai (G) */ +OP(dd, OP_CMP ( AX ) ) /* CMP ax */ +OP(de, OP_DECM ( AX ) ) /* DEC ax */ +OP(df, OP_CMP ( ALX ) ) /* CMP alx (G) */ +OP(e0, OP_CMPX ( REG_X, IMM ) ) /* CPX imm */ +OP(e1, OP_SBC ( DXI ) ) /* SBC dxi */ +OP(e2, OP_SEP ( ) ) /* SEP imm (G) */ +OP(e3, OP_SBC ( S ) ) /* SBC s (G) */ +OP(e4, OP_CMPX ( REG_X, D ) ) /* CPX d */ +OP(e5, OP_SBC ( D ) ) /* SBC d */ +OP(e6, OP_INCM ( D ) ) /* INC d */ +OP(e7, OP_SBC ( DLI ) ) /* SBC dli (G) */ +OP(e8, OP_INCX ( REG_X ) ) /* INX */ +OP(e9, OP_SBC ( IMM ) ) /* SBC imm */ +OP(ea, OP_NOP ( ) ) /* NOP */ +OP(eb, OP_PSH ( IMM ) ) /* PSH imm */ +OP(ec, OP_CMPX ( REG_X, A ) ) /* CPX a */ +OP(ed, OP_SBC ( A ) ) /* SBC a */ +OP(ee, OP_INCM ( A ) ) /* INC a */ +OP(ef, OP_SBC ( AL ) ) /* SBC al (G) */ +OP(f0, OP_BCC ( COND_EQ() ) ) /* BEQ */ +OP(f1, OP_SBC ( DIY ) ) /* SBC diy */ +OP(f2, OP_SBC ( DI ) ) /* SBC di (C) */ +OP(f3, OP_SBC ( SIY ) ) /* SBC siy (G) */ +OP(f4, OP_PEA ( ) ) /* PEA (G) */ +OP(f5, OP_SBC ( DX ) ) /* SBC dx */ +OP(f6, OP_INCM ( DX ) ) /* INC dx */ +OP(f7, OP_SBC ( DLIY ) ) /* SBC dliy(G) */ +OP(f8, OP_SEM ( ) ) /* SEM */ +OP(f9, OP_SBC ( AY ) ) /* SBC ay */ +OP(fa, OP_PLX ( REG_X ) ) /* PLX (C) */ +OP(fb, OP_PUL ( IMM ) ) /* PUL imm */ +OP(fc, OP_JSRAXI( ) ) /* JSR axi (G) */ +OP(fd, OP_SBC ( AX ) ) /* SBC ax */ +OP(fe, OP_INCM ( AX ) ) /* INC ax */ +OP(ff, OP_SBC ( ALX ) ) /* SBC alx (G) */ + +/* B accumulator */ +OP(101,OP_ORB ( DXI ) ) /* ORB dxi */ +OP(103,OP_ORB ( S ) ) /* ORB s */ +OP(105,OP_ORB ( D ) ) /* ORB d */ +OP(107,OP_ORB ( DLI ) ) /* ORB dli */ +OP(109,OP_ORB ( IMM ) ) /* ORB imm */ +OP(10a,OP_BSL ( ) ) /* BSL acc */ +OP(10d,OP_ORB ( A ) ) /* ORB a */ +OP(10f,OP_ORB ( AL ) ) /* ORB al */ +OP(111,OP_ORB ( DIY ) ) /* ORB diy */ +OP(112,OP_ORB ( DI ) ) /* ORB di */ +OP(113,OP_ORB ( SIY ) ) /* ORB siy */ +OP(115,OP_ORB ( DX ) ) /* ORB dx */ +OP(117,OP_ORB ( DLIY ) ) /* ORB dliy */ +OP(119,OP_ORB ( AY ) ) /* ORB ay */ +OP(11a,OP_DECB ( ) ) /* DEB */ +OP(11b,OP_TBS ( ) ) /* TBS */ +OP(11d,OP_ORB ( AX ) ) /* ORB ax */ +OP(11f,OP_ORB ( ALX ) ) /* ORB alx */ +OP(121,OP_ANDB ( DXI ) ) /* ANDB dxi */ +OP(123,OP_ANDB ( S ) ) /* ANDB s */ +OP(125,OP_ANDB ( D ) ) /* ANDB d */ +OP(127,OP_ANDB ( DLI ) ) /* ANDB dli */ +OP(129,OP_ANDB ( IMM ) ) /* ANDB imm */ +OP(12a,OP_ROLB ( ) ) /* ROL Bacc */ +OP(12d,OP_ANDB ( A ) ) /* ANDB a */ +OP(12f,OP_ANDB ( AL ) ) /* ANDB al */ +OP(131,OP_ANDB ( DIY ) ) /* ANDB diy */ +OP(132,OP_ANDB ( DI ) ) /* ANDB di */ +OP(133,OP_ANDB ( SIY ) ) /* ANDB siy */ +OP(135,OP_ANDB ( DX ) ) /* ANDB dx */ +OP(137,OP_ANDB ( DLIY ) ) /* ANDB dliy */ +OP(139,OP_ANDB ( AY ) ) /* ANDB ay */ +OP(13a,OP_INCB ( ) ) /* INB */ +OP(13b,OP_TSB ( ) ) /* TSB */ +OP(13d,OP_ANDB ( AX ) ) /* ANDB ax */ +OP(13f,OP_ANDB ( ALX ) ) /* ANDB alx */ +OP(141,OP_EORB ( DXI ) ) /* EORB dxi */ +OP(143,OP_EORB ( S ) ) /* EORB s */ +OP(145,OP_EORB ( D ) ) /* EORB d */ +OP(147,OP_EORB ( DLI ) ) /* EORB dli */ +OP(148,OP_PHAB ( ) ) /* PHB */ +OP(149,OP_EORB ( IMM ) ) /* EORB imm */ +OP(14a,OP_LSRB ( ) ) /* LSRB acc */ +OP(14d,OP_EORB ( A ) ) /* EORB a */ +OP(14f,OP_EORB ( AL ) ) /* EORB al */ +OP(151,OP_EORB ( DIY ) ) /* EORB diy */ +OP(152,OP_EORB ( DI ) ) /* EORB di */ +OP(153,OP_EORB ( SIY ) ) /* EORB siy */ +OP(155,OP_EORB ( DX ) ) /* EORB dx */ +OP(157,OP_EORB ( DLIY ) ) /* EORB dliy */ +OP(159,OP_EORB ( AY ) ) /* EORB ay */ +OP(15b,OP_TBD ( ) ) /* TBD */ +OP(15d,OP_EORB ( AX ) ) /* EORB ax */ +OP(15f,OP_EORB ( ALX ) ) /* EORB alx */ +OP(161,OP_ADCB ( DXI ) ) /* ADCB dxi */ +OP(163,OP_ADCB ( S ) ) /* ADCB s */ +OP(165,OP_ADCB ( D ) ) /* ADCB d */ +OP(167,OP_ADCB ( DLI ) ) /* ADCB dli */ +OP(168,OP_PLAB ( ) ) /* PLB */ +OP(169,OP_ADCB ( IMM ) ) /* ADCB imm */ +OP(16a,OP_RORB ( ) ) /* ROR Bacc */ +OP(16d,OP_ADCB ( A ) ) /* ADCB a */ +OP(16f,OP_ADCB ( AL ) ) /* ADCB al */ +OP(171,OP_ADCB ( DIY ) ) /* ADCB diy */ +OP(172,OP_ADCB ( DI ) ) /* ADCB di */ +OP(173,OP_ADCB ( SIY ) ) /* ADCB siy */ +OP(175,OP_ADCB ( DX ) ) /* ADCB dx */ +OP(177,OP_ADCB ( DLIY ) ) /* ADCB dliy */ +OP(179,OP_ADCB ( AY ) ) /* ADCB ay */ +OP(17b,OP_TDB ( ) ) /* TDB */ +OP(17d,OP_ADCB ( AX ) ) /* ADCB ax */ +OP(17f,OP_ADCB ( ALX ) ) /* ADCB alx */ +OP(181,OP_STB ( DXI ) ) /* STB dxi */ +OP(183,OP_STB ( S ) ) /* STB s */ +OP(185,OP_STB ( D ) ) /* STB d */ +OP(187,OP_STB ( DLI ) ) /* STB dli */ +OP(18a,OP_TXB ( REG_X ) ) /* TXB */ +OP(18d,OP_STB ( A ) ) /* STB a */ +OP(18f,OP_STB ( AL ) ) /* STB al */ +OP(191,OP_STB ( DIY ) ) /* STB diy */ +OP(192,OP_STB ( DI ) ) /* STB di */ +OP(193,OP_STB ( SIY ) ) /* STB siy */ +OP(195,OP_STB ( DX ) ) /* STB dx */ +OP(197,OP_STB ( DLIY ) ) /* STB dliy */ +OP(198,OP_TXB ( REG_Y ) ) /* TYB */ +OP(199,OP_STB ( AY ) ) /* STB ay */ +OP(19d,OP_STB ( AX ) ) /* STB ax */ +OP(19f,OP_STB ( ALX ) ) /* STB alx */ +OP(1a1,OP_LDB ( DXI ) ) /* LDB dxi */ +OP(1a3,OP_LDB ( S ) ) /* LDB s */ +OP(1a5,OP_LDB ( D ) ) /* LDB d */ +OP(1a7,OP_LDB ( DLI ) ) /* LDB dli */ +OP(1a8,OP_TBX ( REG_Y ) ) /* TBY */ +OP(1a9,OP_LDB ( IMM ) ) /* LDB imm */ +OP(1aa,OP_TBX ( REG_X ) ) /* TBX */ +OP(1ad,OP_LDB ( A ) ) /* LDB a */ +OP(1af,OP_LDB ( AL ) ) /* LDB al */ +OP(1b1,OP_LDB ( DIY ) ) /* LDB diy */ +OP(1b2,OP_LDB ( DI ) ) /* LDB di */ +OP(1b3,OP_LDB ( SIY ) ) /* LDB siy */ +OP(1b5,OP_LDB ( DX ) ) /* LDB dx */ +OP(1b7,OP_LDB ( DLIY ) ) /* LDB dliy */ +OP(1b9,OP_LDB ( AY ) ) /* LDB ay */ +OP(1bd,OP_LDB ( AX ) ) /* LDB ax */ +OP(1bf,OP_LDB ( ALX ) ) /* LDB alx */ +OP(1c1,OP_CMPB ( DXI ) ) /* CMPB dxi */ +OP(1c3,OP_CMPB ( S ) ) /* CMPB s */ +OP(1c5,OP_CMPB ( D ) ) /* CMPB d */ +OP(1c7,OP_CMPB ( DLI ) ) /* CMPB dli */ +OP(1c9,OP_CMPB ( IMM ) ) /* CMPB imm */ +OP(1cd,OP_CMPB ( A ) ) /* CMPB a */ +OP(1cf,OP_CMPB ( AL ) ) /* CMPB al */ +OP(1d1,OP_CMPB ( DIY ) ) /* CMPB diy */ +OP(1d2,OP_CMPB ( DI ) ) /* CMPB di */ +OP(1d3,OP_CMPB ( SIY ) ) /* CMPB siy */ +OP(1d5,OP_CMPB ( DX ) ) /* CMPB dx */ +OP(1d7,OP_CMPB ( DLIY ) ) /* CMPB dliy */ +OP(1d9,OP_CMPB ( AY ) ) /* CMPB ay */ +OP(1dd,OP_CMPB ( AX ) ) /* CMPB ax */ +OP(1df,OP_CMPB ( ALX ) ) /* CMPB alx */ +OP(1e1,OP_SBCB ( DXI ) ) /* SBCB dxi */ +OP(1e3,OP_SBCB ( S ) ) /* SBCB s */ +OP(1e5,OP_SBCB ( D ) ) /* SBCB d */ +OP(1e7,OP_SBCB ( DLI ) ) /* SBCB dli */ +OP(1e9,OP_SBCB ( IMM ) ) /* SBCB imm */ +OP(1ed,OP_SBCB ( A ) ) /* SBCB a */ +OP(1ef,OP_SBCB ( AL ) ) /* SBCB al */ +OP(1f1,OP_SBCB ( DIY ) ) /* SBCB diy */ +OP(1f2,OP_SBCB ( DI ) ) /* SBCB di */ +OP(1f3,OP_SBCB ( SIY ) ) /* SBCB siy */ +OP(1f5,OP_SBCB ( DX ) ) /* SBCB dx */ +OP(1f7,OP_SBCB ( DLIY ) ) /* SBCB dliy */ +OP(1f9,OP_SBCB ( AY ) ) /* SBCB ay */ +OP(1fd,OP_SBCB ( AX ) ) /* SBCB ax */ +OP(1ff,OP_SBCB ( ALX ) ) /* SBCB alx */ + +OP(200,OP_UNIMP( ) ) /* unimplemented */ + +/* multiply/divide */ +OP(201,OP_MPY ( DXI ) ) /* MPY dxi */ +OP(203,OP_MPY ( S ) ) /* MPY s */ +OP(205,OP_MPY ( D ) ) /* MPY d */ +OP(207,OP_MPY ( DLI ) ) /* MPY dli */ +OP(209,OP_MPY ( IMM ) ) /* MPY imm */ +OP(20d,OP_MPY ( A ) ) /* MPY a */ +OP(20f,OP_MPY ( AL ) ) /* MPY al */ +OP(211,OP_MPY ( DIY ) ) /* MPY diy */ +OP(212,OP_MPY ( DI ) ) /* MPY di */ +OP(213,OP_MPY ( SIY ) ) /* MPY siy */ +OP(215,OP_MPY ( DX ) ) /* MPY dx */ +OP(217,OP_MPY ( DLIY ) ) /* MPY dliy */ +OP(219,OP_MPY ( AY ) ) /* MPY ay */ +OP(21d,OP_MPY ( AX ) ) /* MPY ax */ +OP(21f,OP_MPY ( ALX ) ) /* MPY alx */ +OP(221,OP_DIV ( DXI ) ) /* DIV dxi */ +OP(223,OP_DIV ( S ) ) /* DIV s */ +OP(225,OP_DIV ( D ) ) /* DIV d */ +OP(227,OP_DIV ( DLI ) ) /* DIV dli */ +OP(228,OP_XAB ( ) ) /* XAB */ +OP(229,OP_DIV ( IMM ) ) /* DIV imm */ +OP(22d,OP_DIV ( A ) ) /* DIV a */ +OP(22f,OP_DIV ( AL ) ) /* DIV al */ +OP(231,OP_DIV ( DIY ) ) /* DIV diy */ +OP(232,OP_DIV ( DI ) ) /* DIV di */ +OP(233,OP_DIV ( SIY ) ) /* DIV siy */ +OP(235,OP_DIV ( DX ) ) /* DIV dx */ +OP(237,OP_DIV ( DLIY ) ) /* DIV dliy */ +OP(239,OP_DIV ( AY ) ) /* DIV ay */ +OP(23d,OP_DIV ( AX ) ) /* DIV ax */ +OP(23f,OP_DIV ( ALX ) ) /* DIV alx */ +OP(249,OP_RLA ( IMM ) ) /* RLA imm */ +OP(2c2,OP_LDT ( IMM ) ) /* LDT imm */ +// note: block 28x-2bx is for 7750 opcodes, not implemented yet + +TABLE_OPCODES = +// 00 01 02 03 04 05 06 07 +// 08 09 0a 0b 0c 0d 0e 0f +{ + O(00), O(01), O(02), O(03), O(04), O(05), O(06), O(07), // 00 + O(08), O(09), O(0a), O(0b), O(0c), O(0d), O(0e), O(0f), + O(10), O(11), O(12), O(13), O(14), O(15), O(16), O(17), // 10 + O(18), O(19), O(1a), O(1b), O(1c), O(1d), O(1e), O(1f), + O(20), O(21), O(22), O(23), O(24), O(25), O(26), O(27), // 20 + O(28), O(29), O(2a), O(2b), O(2c), O(2d), O(2e), O(2f), + O(30), O(31), O(32), O(33), O(34), O(35), O(36), O(37), // 30 + O(38), O(39), O(3a), O(3b), O(3c), O(3d), O(3e), O(3f), + O(40), O(41), O(42), O(43), O(44), O(45), O(46), O(47), // 40 + O(48), O(49), O(4a), O(4b), O(4c), O(4d), O(4e), O(4f), + O(50), O(51), O(52), O(53), O(54), O(55), O(56), O(57), // 50 + O(58), O(59), O(5a), O(5b), O(5c), O(5d), O(5e), O(5f), + O(60), O(61), O(62), O(63), O(64), O(65), O(66), O(67), // 60 + O(68), O(69), O(6a), O(6b), O(6c), O(6d), O(6e), O(6f), + O(70), O(71), O(72), O(73), O(74), O(75), O(76), O(77), // 70 + O(78), O(79), O(7a), O(7b), O(7c), O(7d), O(7e), O(7f), + O(80), O(81), O(82), O(83), O(84), O(85), O(86), O(87), // 80 + O(88), O(89), O(8a), O(8b), O(8c), O(8d), O(8e), O(8f), + O(90), O(91), O(92), O(93), O(94), O(95), O(96), O(97), // 90 + O(98), O(99), O(9a), O(9b), O(9c), O(9d), O(9e), O(9f), + O(a0), O(a1), O(a2), O(a3), O(a4), O(a5), O(a6), O(a7), // a0 + O(a8), O(a9), O(aa), O(ab), O(ac), O(ad), O(ae), O(af), + O(b0), O(b1), O(b2), O(b3), O(b4), O(b5), O(b6), O(b7), // b0 + O(b8), O(b9), O(ba), O(bb), O(bc), O(bd), O(be), O(bf), + O(c0), O(c1), O(c2), O(c3), O(c4), O(c5), O(c6), O(c7), // c0 + O(c8), O(c9), O(ca), O(cb), O(cc), O(cd), O(ce), O(cf), + O(d0), O(d1), O(d2), O(d3), O(d4), O(d5), O(d6), O(d7), // d0 + O(d8), O(d9), O(da), O(db), O(dc), O(dd), O(de), O(df), + O(e0), O(e1), O(e2), O(e3), O(e4), O(e5), O(e6), O(e7), // e0 + O(e8), O(e9), O(ea), O(eb), O(ec), O(ed), O(ee), O(ef), + O(f0), O(f1), O(f2), O(f3), O(f4), O(f5), O(f6), O(f7), // f0 + O(f8), O(f9), O(fa), O(fb), O(fc), O(fd), O(fe), O(ff) +}; + +TABLE_OPCODES2 = +// 00 01 02 03 04 05 06 07 +// 08 09 0a 0b 0c 0d 0e 0f +{ + O(200),O(101),O(200),O(103),O(200),O(105),O(200),O(107), // 00 + O(200),O(109),O(10a),O(200),O(200),O(10d),O(200),O(10f), + O(200),O(111),O(112),O(113),O(200),O(115),O(200),O(117), // 10 + O(200),O(119),O(11a),O(11b),O(200),O(11d),O(200),O(11f), + O(200),O(121),O(200),O(123),O(200),O(125),O(200),O(127), // 20 + O(200),O(129),O(12a),O(200),O(200),O(12d),O(200),O(12f), + O(200),O(131),O(132),O(133),O(200),O(135),O(200),O(137), // 30 + O(200),O(139),O(13a),O(13b),O(200),O(13d),O(200),O(13f), + O(200),O(141),O(200),O(143),O(200),O(145),O(200),O(147), // 40 + O(148),O(149),O(14a),O(200),O(200),O(14d),O(200),O(14f), + O(200),O(151),O(152),O(153),O(200),O(155),O(200),O(157), // 50 + O(200),O(159),O(200),O(15b),O(200),O(15d),O(200),O(15f), + O(200),O(161),O(200),O(163),O(200),O(165),O(200),O(167), // 60 + O(168),O(169),O(16a),O(200),O(200),O(16d),O(200),O(16f), + O(200),O(171),O(172),O(173),O(200),O(175),O(200),O(177), // 70 + O(200),O(179),O(200),O(17b),O(200),O(17d),O(200),O(17f), + O(200),O(181),O(200),O(183),O(200),O(185),O(200),O(187), // 80 + O(200),O(200),O(18a),O(200),O(200),O(18d),O(200),O(18f), + O(200),O(191),O(192),O(193),O(200),O(195),O(200),O(197), // 90 + O(198),O(199),O(200),O(200),O(200),O(19d),O(200),O(19f), + O(200),O(1a1),O(200),O(1a3),O(200),O(1a5),O(200),O(1a7), // a0 + O(1a8),O(1a9),O(1aa),O(200),O(200),O(1ad),O(200),O(1af), + O(200),O(1b1),O(1b2),O(1b3),O(200),O(1b5),O(200),O(1b7), // b0 + O(200),O(1b9),O(200),O(200),O(200),O(1bd),O(200),O(1bf), + O(200),O(1c1),O(200),O(1c3),O(200),O(1c5),O(200),O(1c7), // c0 + O(200),O(1c9),O(200),O(200),O(200),O(1cd),O(200),O(1cf), + O(200),O(1d1),O(1d2),O(1d3),O(200),O(1d5),O(200),O(1d7), // d0 + O(200),O(1d9),O(200),O(200),O(200),O(1dd),O(200),O(1df), + O(200),O(1e1),O(200),O(1e3),O(200),O(1e5),O(200),O(1e7), // e0 + O(200),O(1e9),O(200),O(200),O(200),O(1ed),O(200),O(1ef), + O(200),O(1f1),O(1f2),O(1f3),O(200),O(1f5),O(200),O(1f7), // f0 + O(200),O(1f9),O(200),O(200),O(200),O(1fd),O(200),O(1ff) +}; + +TABLE_OPCODES3 = +// 00 01 02 03 04 05 06 07 +// 08 09 0a 0b 0c 0d 0e 0f +{ + O(200),O(201),O(200),O(203),O(200),O(205),O(200),O(207), // 00 + O(200),O(209),O(200),O(200),O(200),O(20d),O(200),O(20f), + O(200),O(211),O(212),O(213),O(200),O(215),O(200),O(217), // 10 + O(200),O(219),O(200),O(200),O(200),O(21d),O(200),O(21f), + O(200),O(221),O(200),O(223),O(200),O(225),O(200),O(227), // 20 + O(228),O(229),O(200),O(200),O(200),O(22d),O(200),O(22f), + O(200),O(231),O(232),O(233),O(200),O(235),O(200),O(237), // 30 + O(200),O(239),O(200),O(200),O(200),O(23d),O(200),O(23f), + O(200),O(200),O(200),O(200),O(200),O(200),O(200),O(200), // 40 + O(200),O(249),O(200),O(200),O(200),O(200),O(200),O(200), + O(200),O(200),O(200),O(200),O(200),O(200),O(200),O(200), // 50 + O(200),O(200),O(200),O(200),O(200),O(200),O(200),O(200), + O(200),O(200),O(200),O(200),O(200),O(200),O(200),O(200), // 60 + O(200),O(200),O(200),O(200),O(200),O(200),O(200),O(200), + O(200),O(200),O(200),O(200),O(200),O(200),O(200),O(200), // 70 + O(200),O(200),O(200),O(200),O(200),O(200),O(200),O(200), + O(200),O(200),O(200),O(200),O(200),O(200),O(200),O(200), // 80 + O(200),O(200),O(200),O(200),O(200),O(200),O(200),O(200), + O(200),O(200),O(200),O(200),O(200),O(200),O(200),O(200), // 90 + O(200),O(200),O(200),O(200),O(200),O(200),O(200),O(200), + O(200),O(200),O(200),O(200),O(200),O(200),O(200),O(200), // a0 + O(200),O(200),O(200),O(200),O(200),O(200),O(200),O(200), + O(200),O(200),O(200),O(200),O(200),O(200),O(200),O(200), // b0 + O(200),O(200),O(200),O(200),O(200),O(200),O(200),O(200), + O(200),O(200),O(2c2),O(200),O(200),O(200),O(200),O(200), // c0 + O(200),O(200),O(200),O(200),O(200),O(200),O(200),O(200), + O(200),O(200),O(200),O(200),O(200),O(200),O(200),O(200), // d0 + O(200),O(200),O(200),O(200),O(200),O(200),O(200),O(200), + O(200),O(200),O(200),O(200),O(200),O(200),O(200),O(200), // e0 + O(200),O(200),O(200),O(200),O(200),O(200),O(200),O(200), + O(200),O(200),O(200),O(200),O(200),O(200),O(200),O(200), // f0 + O(200),O(200),O(200),O(200),O(200),O(200),O(200),O(200) +}; + + +/* Assert or clear a line on the CPU */ +TABLE_FUNCTION(void, set_line, (int line, int state)) +{ + switch(line) + { + // maskable interrupts + case M37710_LINE_ADC: + case M37710_LINE_UART1XMIT: + case M37710_LINE_UART1RECV: + case M37710_LINE_UART0XMIT: + case M37710_LINE_UART0RECV: + case M37710_LINE_TIMERB2: + case M37710_LINE_TIMERB1: + case M37710_LINE_TIMERB0: + case M37710_LINE_TIMERA4: + case M37710_LINE_TIMERA3: + case M37710_LINE_TIMERA2: + case M37710_LINE_TIMERA1: + case M37710_LINE_TIMERA0: + case M37710_LINE_IRQ2: + case M37710_LINE_IRQ1: + case M37710_LINE_IRQ0: + switch(state) + { + case CLEAR_LINE: + LINE_IRQ &= ~(1 << line); + if (m37710_irq_levels[line]) + { + m_m37710_regs[m37710_irq_levels[line]] &= ~8; + } + break; + + case ASSERT_LINE: + case PULSE_LINE: + case HOLD_LINE: + LINE_IRQ |= (1 << line); + if (m37710_irq_levels[line]) + { + m_m37710_regs[m37710_irq_levels[line]] |= 8; + } + break; + + default: break; + } + break; + + default: break; + } +} + + + +/* Get a register from the CPU core */ +TABLE_FUNCTION(UINT32, get_reg, (int regnum)) +{ + switch(regnum) + { + case M37710_A: return REG_B | REG_A; + case M37710_B: return REG_BB | REG_BA; + case M37710_X: return REG_X; + case M37710_Y: return REG_Y; + case M37710_S: return REG_S; + case M37710_PC: return REG_PC; + case M37710_PB: return REG_PB >> 16; + case M37710_DB: return REG_DB >> 16; + case M37710_D: return REG_D; + case M37710_P: return m37710i_get_reg_p(); + case M37710_IRQ_STATE: return LINE_IRQ; + case STATE_GENPCBASE: return REG_PPC; + } + return 0; +} + +TABLE_FUNCTION(void, set_reg, (int regnum, UINT32 val)) +{ + switch(regnum) + { + case M37710_PC: REG_PC = MAKE_UINT_16(val); break; + case M37710_S: REG_S = MAKE_UINT_16(val); break; + case M37710_P: m37710i_set_reg_p(val); break; +#if FLAG_SET_M + case M37710_A: REG_A = MAKE_UINT_8(val); REG_B = val&0xff00; break; + case M37710_B: REG_BA = MAKE_UINT_8(val); REG_BB = val&0xff00; break; +#else + case M37710_A: REG_A = MAKE_UINT_16(val); break; + case M37710_B: REG_BA = MAKE_UINT_16(val); break; +#endif +#if FLAG_SET_X + case M37710_X: REG_X = MAKE_UINT_8(val); break; + case M37710_Y: REG_Y = MAKE_UINT_8(val); break; +#else + case M37710_X: REG_X = MAKE_UINT_16(val); break; + case M37710_Y: REG_Y = MAKE_UINT_16(val); break; +#endif + case M37710_IRQ_STATE: (this->*FTABLE_SET_LINE)(M37710_LINE_IRQ0, val == 0 ? CLEAR_LINE : ASSERT_LINE); break; + } +} + +TABLE_FUNCTION(int, execute, (int clocks)) +{ + if(!CPU_STOPPED) + { + CLOCKS = clocks; + do + { + REG_PPC = REG_PC; + M37710_CALL_DEBUGGER(REG_PB | REG_PC); + REG_PC++; + REG_IR = read_8_IMM(REG_PB | REG_PPC); + (this->*m_opcodes[REG_IR])(); + } while(CLOCKS > 0); + return clocks - CLOCKS; + } + return clocks; +} + + +/* ======================================================================== */ +/* ================================== EOF ================================= */ +/* ======================================================================== */ diff --git a/src/devices/cpu/m37710/m7700ds.c b/src/devices/cpu/m37710/m7700ds.c new file mode 100644 index 00000000000..f6b77932b1e --- /dev/null +++ b/src/devices/cpu/m37710/m7700ds.c @@ -0,0 +1,617 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont, Karl Stenerud +/* + +Mitsubishi 7700 Series CPU disassembler v1.1 + +By R. Belmont +Based on G65C816 CPU Emulator by Karl Stenerud + +*/ + +#include "emu.h" +#include "m7700ds.h" + +#ifdef SEC +#undef SEC +#endif + +#define ADDRESS_24BIT(A) ((A)&0xffffff) + +struct m7700_opcode_struct +{ + unsigned char name; + unsigned char flag; + unsigned char ea; +}; + +enum +{ + IMP , ACC , RELB, RELW, IMM , A , AI , AL , ALX , AX , AXI , + AY , D , DI , DIY , DLI , DLIY, DX , DXI , DY , S , SIY , + SIG /*, MVN , MVP , PEA , PEI , PER */, LDM4, LDM5, LDM4X, LDM5X, + BBCD, BBCA, ACCB +}; + +enum +{ + I, /* ignore */ + M, /* check m bit */ + X /* check x bit */ +}; + +enum +{ + ADC , AND , ASL , BCC , BCS , BEQ , BIT , BMI , BNE , BPL , BRA , + BRK , BRL , BVC , BVS , CLC , CLD , CLI , CLV , CMP , COP , CPX , + CPY , DEA , DEC , DEX , DEY , EOR , INA , INC , INX , INY , JML , + JMP , JSL , JSR , LDA , LDX , LDY , LSR , MVN , MVP , NOP , ORA , + PEA , PEI , PER , PHA , PHT , PHD , PHK , PHP , PHX , PHY , PLA , + PLB , PLD , PLP , PLX , PLY , CLP , ROL , ROR , RTI , RTL , RTS , + SBC , SEC , SED , SEI , SEP , STA , STP , STX , STY , STZ , TAX , + TAY , TCS , TCD , TDC , TRB , TSB , TSC , TSX , TXA , TXS , TXY , + TYA , TYX , WAI , WDM , XBA , XCE , MPY , DIV , MPYS, DIVS, RLA , + EXTS, EXTZ , LDT , LDM , UNK , SEB , SEM , CLM , STB , LDB , ADCB , + SBCB, EORB , TBX , CMPB, INB , DEB , TXB , TYB , LSRB, ORB , CLB , + BBC, BBS, TBY, ANDB, PUL , PSH , PLAB, XAB , PHB +}; + +static const char *const g_opnames[] = +{ + "ADC", "AND", "ASL", "BCC", "BCS", "BEQ", "BIT", "BMI", "BNE", "BPL", "BRA", + "BRK", "BRL", "BVC", "BVS", "CLC", "CLD", "CLI", "CLV", "CMP", "COP", "CPX", + "CPY", "DEA", "DEC", "DEX", "DEY", "EOR", "INA", "INC", "INX", "INY", "JML", + "JMP", "JSL", "JSR", "LDA", "LDX", "LDY", "LSR", "MVN", "MVP", "NOP", "ORA", + "PEA", "PEI", "PER", "PHA", "PHT", "PHD", "PHK", "PHP", "PHX", "PHY", "PLA", + "PLT", "PLD", "PLP", "PLX", "PLY", "CLP", "ROL", "ROR", "RTI", "RTL", "RTS", + "SBC", "SEC", "SED", "SEI", "SEP", "STA", "STP", "STX", "STY", "STZ", "TAX", + "TAY", "TCS", "TCD", "TDC", "TRB", "TSB", "TSC", "TSX", "TXA", "TXS", "TXY", + "TYA", "TYX", "WAI", "WDM", "XBA", "XCE", "MPY", "DIV", "MPYS", "DIVS", "RLA", + "EXTS","EXTZ","LDT", "LDM", "UNK", "SEB", "SEM", "CLM", "STB", "LDB", "ADCB", + "SBCB","EORB","TBX", "CMPB","INB", "DEB", "TXB", "TYB", "LSRB", "ORB", "CLB", + "BBC", "BBS", "TBY", "ANDB","PUL", "PSH", "PLB", "XAB", "PHB", +}; + +static const m7700_opcode_struct g_opcodes[256] = +{ + {BRK, I, SIG }, {ORA, M, DXI }, {UNK, I, SIG }, {ORA, M, S }, + {SEB, M, LDM4 }, {ORA, M, D }, {ASL, M, D }, {ORA, M, DLI }, + {PHP, I, IMP }, {ORA, M, IMM }, {ASL, M, ACC }, {PHD, I, IMP }, + {SEB, M, LDM5 }, {ORA, M, A }, {ASL, M, A }, {ORA, M, AL }, +// 0x10 + {BPL, I, RELB}, {ORA, M, DIY }, {ORA, M, DI }, {ORA, M, SIY }, + {CLB, M, LDM4}, {ORA, M, DX }, {ASL, M, DX }, {ORA, M, DLIY}, + {CLC, I, IMP }, {ORA, M, AY }, {DEA, I, IMP }, {TCS, I, IMP }, + {CLB, M, LDM5}, {ORA, M, AX }, {ASL, M, AX }, {ORA, M, ALX }, +// 0x20 + {JSR, I, A }, {AND, M, DXI }, {JSL, I, AL }, {AND, M, S }, + {BBS, M, BBCD}, {AND, M, D }, {ROL, M, D }, {AND, M, DLI }, + {PLP, I, IMP }, {AND, M, IMM }, {ROL, M, ACC }, {PLD, I, IMP }, + {BBS, M, BBCA}, {AND, M, A }, {ROL, M, A }, {AND, M, AL }, +// 0x30 + {BMI, I, RELB}, {AND, M, DIY }, {AND, M, DI }, {AND, M, SIY }, + {BBC, M, BBCD}, {AND, M, DX }, {ROL, M, DX }, {AND, M, DLIY}, + {SEC, I, IMP }, {AND, M, AY }, {INA, I, IMP }, {TSC, I, IMP }, + {BBC, M, BBCA}, {AND, M, AX }, {ROL, M, AX }, {AND, M, ALX }, +// 0x40 + {RTI, I, IMP }, {EOR, M, DXI }, {WDM, I, IMP }, {EOR, M, S }, + {MVP, I, MVP }, {EOR, M, D }, {LSR, M, D }, {EOR, M, DLI }, + {PHA, I, IMP }, {EOR, M, IMM }, {LSR, M, ACC }, {PHK, I, IMP }, + {JMP, I, A }, {EOR, M, A }, {LSR, M, A }, {EOR, M, AL }, +// 0x50 + {BVC, I, RELB}, {EOR, M, DIY }, {EOR, M, DI }, {EOR, M, SIY }, + {MVN, I, MVN }, {EOR, M, DX }, {LSR, M, DX }, {EOR, M, DLIY}, + {CLI, I, IMP }, {EOR, M, AY }, {PHY, I, IMP }, {TCD, I, IMP }, + {JMP, I, AL }, {EOR, M, AX }, {LSR, M, AX }, {EOR, M, ALX }, +// 0x60 + {RTS, I, IMP }, {ADC, M, DXI }, {PER, I, PER }, {ADC, M, S }, + {LDM, M, LDM4 }, {ADC, M, D }, {ROR, M, D }, {ADC, M, DLI }, + {PLA, I, IMP }, {ADC, M, IMM }, {ROR, M, ACC }, {RTL, I, IMP }, + {JMP, I, AI }, {ADC, M, A }, {ROR, M, A }, {ADC, M, AL }, +// 0x70 + {BVS, I, RELB}, {ADC, M, DIY }, {ADC, M, DI }, {ADC, M, SIY }, + {LDM, M, LDM4X }, {ADC, M, DX }, {ROR, M, DX }, {ADC, M, DLIY}, + {SEI, I, IMP }, {ADC, M, AY }, {PLY, I, IMP }, {TDC, I, IMP }, + {JMP, I, AXI }, {ADC, M, AX }, {ROR, M, AX }, {ADC, M, ALX }, +// 0x80 + {BRA, I, RELB}, {STA, M, DXI }, {BRL, I, RELW}, {STA, M, S }, + {STY, X, D }, {STA, M, D }, {STX, X, D }, {STA, M, DLI }, + {DEY, I, IMP }, {BIT, M, IMM }, {TXA, I, IMP }, {PHT, I, IMP }, + {STY, X, A }, {STA, M, A }, {STX, X, A }, {STA, M, AL }, +// 0x90 + {BCC, I, RELB}, {STA, M, DIY }, {STA, M, DI }, {STA, M, SIY }, + {STY, X, DX }, {STA, M, DX }, {STX, X, DY }, {STA, M, DLIY}, + {TYA, I, IMP }, {STA, M, AY }, {TXS, I, IMP }, {TXY, I, IMP }, + {LDM, M, LDM5 }, {STA, M, AX }, {LDM, M, LDM5X }, {STA, M, ALX }, +// 0xA0 + {LDY, X, IMM }, {LDA, M, DXI }, {LDX, X, IMM }, {LDA, M, S }, + {LDY, X, D }, {LDA, M, D }, {LDX, X, D }, {LDA, M, DLI }, + {TAY, I, IMP }, {LDA, M, IMM }, {TAX, I, IMP }, {PLB, I, IMP }, + {LDY, X, A }, {LDA, M, A }, {LDX, X, A }, {LDA, M, AL }, +// 0xB0 + {BCS, I, RELB}, {LDA, M, DIY }, {LDA, M, DI }, {LDA, M, SIY }, + {LDY, X, DX }, {LDA, M, DX }, {LDX, X, DY }, {LDA, M, DLIY}, + {CLV, I, IMP }, {LDA, M, AY }, {TSX, I, IMP }, {TYX, I, IMP }, + {LDY, X, AX }, {LDA, M, AX }, {LDX, X, AY }, {LDA, M, ALX }, +// 0xC0 + {CPY, X, IMM }, {CMP, M, DXI }, {CLP, I, IMM }, {CMP, M, S }, + {CPY, X, D }, {CMP, M, D }, {DEC, M, D }, {CMP, M, DLI }, + {INY, I, IMP }, {CMP, M, IMM }, {DEX, I, IMP }, {WAI, I, IMP }, + {CPY, X, A }, {CMP, M, A }, {DEC, M, A }, {CMP, M, AL }, +// 0xD0 + {BNE, I, RELB}, {CMP, M, DIY }, {CMP, M, DI }, {CMP, M, SIY }, + {PEI, I, PEI }, {CMP, M, DX }, {DEC, M, DX }, {CMP, M, DLIY}, + {CLM, I, IMP }, {CMP, M, AY }, {PHX, I, IMP }, {STP, I, IMP }, + {JML, I, AI }, {CMP, M, AX }, {DEC, M, AX }, {CMP, M, ALX }, +// 0xE0 + {CPX, X, IMM }, {SBC, M, DXI }, {SEP, I, IMM }, {SBC, M, S }, + {CPX, X, D }, {SBC, M, D }, {INC, M, D }, {SBC, M, DLI }, + {INX, M, IMP }, {SBC, M, IMM }, {NOP, I, IMP }, {PSH, I, IMM }, + {CPX, X, A }, {SBC, M, A }, {INC, M, A }, {SBC, M, AL }, +// 0xF0 + {BEQ, I, RELB}, {SBC, M, DIY }, {SBC, M, DI }, {SBC, M, SIY }, + {PEA, I, PEA }, {SBC, M, DX }, {INC, M, DX }, {SBC, M, DLIY}, + {SEM, I, IMP }, {SBC, M, AY }, {PLX, I, IMP }, {PUL, I, IMM }, + {JSR, I, AXI }, {SBC, M, AX }, {INC, M, AX }, {SBC, M, ALX } +}; + +static const m7700_opcode_struct g_opcodes_prefix42[256] = +{ + {BRK, I, SIG }, {ORB, M, DXI }, {COP, I, SIG }, {ORB, M, S }, + {TSB, M, D }, {ORB, M, D }, {ASL, M, D }, {ORB, M, DLI }, + {PHP, I, IMP }, {ORB, M, IMM }, {ASL, M, ACCB }, {PHD, I, IMP }, + {TSB, M, A }, {ORB, M, A }, {ASL, M, A }, {ORB, M, AL }, +// 0x10 + {BPL, I, RELB}, {ORB, M, DIY }, {ORB, M, DI }, {ORB, M, SIY }, + {TRB, M, D }, {ORB, M, DX }, {ASL, M, DX }, {ORB, M, DLIY}, + {CLC, I, IMP }, {ORB, M, AY }, {DEB, I, IMP }, {TCS, I, IMP }, + {TRB, M, A }, {ORB, M, AX }, {ASL, M, AX }, {ORB, M, ALX }, +// 0x20 + {JSR, I, A }, {ANDB, M, DXI }, {JSL, I, AL }, {ANDB, M, S }, + {BIT, M, D }, {ANDB, M, D }, {ROL, M, D }, {ANDB, M, DLI }, + {PLP, I, IMP }, {ANDB, M, IMM }, {ROL, M, ACCB }, {PLD, I, IMP }, + {BIT, M, A }, {ANDB, M, A }, {ROL, M, A }, {ANDB, M, AL }, +// 0x30 + {BMI, I, RELB}, {AND, M, DIY }, {AND, M, DI }, {AND, M, SIY }, + {BIT, M, DX }, {AND, M, DX }, {ROL, M, DX }, {AND, M, DLIY}, + {SEC, I, IMP }, {AND, M, AY }, {INB, I, IMP }, {TSC, I, IMP }, + {BIT, M, AX }, {AND, M, AX }, {ROL, M, AX }, {AND, M, ALX }, +// 0x40 + {RTI, I, IMP }, {EORB, M, DXI }, {WDM, I, IMP }, {EORB, M, S }, + {MVP, I, MVP }, {EORB, M, D }, {LSRB, M, D }, {EORB, M, DLI }, + {PHB, I, IMP }, {EORB, M, IMM }, {LSRB, M, ACC }, {PHK, I, IMP }, + {JMP, I, A }, {EORB, M, A }, {LSRB, M, A }, {EORB, M, AL }, +// 0x50 + {BVC, I, RELB}, {EORB, M, DIY }, {EORB, M, DI }, {EORB, M, SIY }, + {MVN, I, MVN }, {EORB, M, DX }, {LSRB, M, DX }, {EORB, M, DLIY}, + {CLI, I, IMP }, {EORB, M, AY }, {PHY, I, IMP }, {TCD, I, IMP }, + {JMP, I, AL }, {EORB, M, AX }, {LSRB, M, AX }, {EORB, M, ALX }, +// 0x60 + {RTS, I, IMP }, {ADCB, M, DXI }, {PER, I, PER }, {ADCB, M, S }, + {STZ, M, D }, {ADCB, M, D }, {ROR, M, D }, {ADCB, M, DLI }, + {PLAB,I, IMP }, {ADCB, M, IMM }, {ROR, M, ACC }, {RTL, I, IMP }, + {JMP, I, AI }, {ADCB, M, A }, {ROR, M, A }, {ADCB, M, AL }, +// 0x70 + {BVS, I, RELB}, {ADCB, M, DIY }, {ADCB, M, DI }, {ADCB, M, SIY }, + {STZ, M, DX }, {ADCB, M, DX }, {ROR, M, DX }, {ADCB, M, DLIY}, + {SEI, I, IMP }, {ADCB, M, AY }, {PLY, I, IMP }, {TDC, I, IMP }, + {JMP, I, AXI }, {ADCB, M, AX }, {ROR, M, AX }, {ADCB, M, ALX }, +// 0x80 + {BRA, I, RELB}, {STB, M, DXI }, {BRL, I, RELW}, {STB, M, S }, + {STY, X, D }, {STB, M, D }, {STX, X, D }, {STB, M, DLI }, + {DEY, I, IMP }, {BIT, M, IMM }, {TXB, I, IMP }, {PHB, I, IMP }, + {STY, X, A }, {STB, M, A }, {STX, X, A }, {STB, M, AL }, +// 0x90 + {BCC, I, RELB}, {STB, M, DIY }, {STB, M, DI }, {STB, M, SIY }, + {STY, X, DX }, {STB, M, DX }, {STX, X, DY }, {STB, M, DLIY}, + {TYB, I, IMP }, {STB, M, AY }, {TXS, I, IMP }, {TXY, I, IMP }, + {STZ, M, A }, {STB, M, AX }, {STZ, M, AX }, {STB, M, ALX }, +// 0xA0 + {LDY, X, IMM }, {LDB, M, DXI }, {LDX, X, IMM }, {LDB, M, S }, + {LDY, X, D }, {LDB, M, D }, {LDX, X, D }, {LDB, M, DLI }, + {TBY, I, IMP }, {LDB, M, IMM }, {TBX, I, IMP }, {PLB, I, IMP }, + {LDY, X, A }, {LDB, M, A }, {LDX, X, A }, {LDB, M, AL }, +// 0xB0 + {BCS, I, RELB}, {LDB, M, DIY }, {LDB, M, DI }, {LDB, M, SIY }, + {LDY, X, DX }, {LDB, M, DX }, {LDX, X, DY }, {LDB, M, DLIY}, + {CLV, I, IMP }, {LDB, M, AY }, {TSX, I, IMP }, {TYX, I, IMP }, + {LDY, X, AX }, {LDB, M, AX }, {LDX, X, AY }, {LDB, M, ALX }, +// 0xC0 + {CPY, X, IMM }, {CMPB, M, DXI }, {CLP, I, IMM }, {CMPB, M, S }, + {CPY, X, D }, {CMPB, M, D }, {DEC, M, D }, {CMPB, M, DLI }, + {INY, I, IMP }, {CMPB, M, IMM }, {DEX, I, IMP }, {WAI, I, IMP }, + {CPY, X, A }, {CMPB, M, A }, {DEC, M, A }, {CMPB, M, AL }, +// 0xD0 + {BNE, I, RELB}, {CMPB, M, DIY }, {CMPB, M, DI }, {CMPB, M, SIY }, + {PEI, I, PEI }, {CMPB, M, DX }, {DEC, M, DX }, {CMPB, M, DLIY}, + {CLD, I, IMP }, {CMPB, M, AY }, {PHX, I, IMP }, {STP, I, IMP }, + {JML, I, AI }, {CMPB, M, AX }, {DEC, M, AX }, {CMPB, M, ALX }, +// 0xE0 + {CPX, X, IMM }, {SBCB, M, DXI }, {SEP, I, IMM }, {SBCB, M, S }, + {CPX, X, D }, {SBCB, M, D }, {INC, M, D }, {SBCB, M, DLI }, + {INX, M, IMP }, {SBCB, M, IMM }, {NOP, I, IMP }, {XBA, I, IMP }, + {CPX, X, A }, {SBCB, M, A }, {INC, M, A }, {SBCB, M, AL }, +// 0xF0 + {BEQ, I, RELB}, {SBCB, M, DIY }, {SBCB, M, DI }, {SBCB, M, SIY }, + {PEA, I, PEA }, {SBCB, M, DX }, {INC, M, DX }, {SBCB, M, DLIY}, + {SED, I, IMP }, {SBCB, M, AY }, {PLX, I, IMP }, {XCE, I, IMP }, + {JSR, I, AXI }, {SBCB, M, AX }, {INC, M, AX }, {SBCB, M, ALX } +}; + +static const m7700_opcode_struct g_opcodes_prefix89[256] = +{ + {BRK, I, SIG }, {MPY, M, DXI }, {COP, I, SIG }, {MPY, M, S }, + {TSB, M, D }, {MPY, M, D }, {ASL, M, D }, {MPY, M, DLI }, + {PHP, I, IMP }, {MPY, M, IMM }, {ASL, M, ACC }, {PHD, I, IMP }, + {TSB, M, A }, {MPY, M, A }, {ASL, M, A }, {MPY, M, AL }, +// 0x10 + {BPL, I, RELB}, {ORA, M, DIY }, {ORA, M, DI }, {ORA, M, SIY }, + {TRB, M, D }, {MPY, M, DX }, {ASL, M, DX }, {ORA, M, DLIY}, + {CLC, I, IMP }, {MPY, M, AY }, {INA, I, IMP }, {TCS, I, IMP }, + {TRB, M, A }, {ORA, M, AX }, {ASL, M, AX }, {ORA, M, ALX }, +// 0x20 + {JSR, I, A }, {AND, M, DXI }, {JSL, I, AL }, {AND, M, S }, + {BIT, M, D }, {AND, M, D }, {ROL, M, D }, {AND, M, DLI }, + {XAB, I, IMP }, {AND, M, IMM }, {ROL, M, ACC }, {PLD, I, IMP }, + {BIT, M, A }, {AND, M, A }, {ROL, M, A }, {AND, M, AL }, +// 0x30 + {BMI, I, RELB}, {AND, M, DIY }, {AND, M, DI }, {AND, M, SIY }, + {BIT, M, DX }, {AND, M, DX }, {ROL, M, DX }, {AND, M, DLIY}, + {SEC, I, IMP }, {AND, M, AY }, {DEA, I, IMP }, {TSC, I, IMP }, + {BIT, M, AX }, {AND, M, AX }, {ROL, M, AX }, {AND, M, ALX }, +// 0x40 + {RTI, I, IMP }, {EOR, M, DXI }, {WDM, I, IMP }, {EOR, M, S }, + {MVP, I, MVP }, {EOR, M, D }, {LSR, M, D }, {EOR, M, DLI }, + {PHA, I, IMP }, {RLA, M, IMM }, {LSR, M, ACC }, {PHK, I, IMP }, + {JMP, I, A }, {EOR, M, A }, {LSR, M, A }, {EOR, M, AL }, +// 0x50 + {BVC, I, RELB}, {EOR, M, DIY }, {EOR, M, DI }, {EOR, M, SIY }, + {MVN, I, MVN }, {EOR, M, DX }, {LSR, M, DX }, {EOR, M, DLIY}, + {CLI, I, IMP }, {EOR, M, AY }, {PHY, I, IMP }, {TCD, I, IMP }, + {JMP, I, AL }, {EOR, M, AX }, {LSR, M, AX }, {EOR, M, ALX }, +// 0x60 + {RTS, I, IMP }, {ADC, M, DXI }, {PER, I, PER }, {ADC, M, S }, + {STZ, M, D }, {ADC, M, D }, {ROR, M, D }, {ADC, M, DLI }, + {PLA, I, IMP }, {ADC, M, IMM }, {ROR, M, ACC }, {RTL, I, IMP }, + {JMP, I, AI }, {ADC, M, A }, {ROR, M, A }, {ADC, M, AL }, +// 0x70 + {BVS, I, RELB}, {ADC, M, DIY }, {ADC, M, DI }, {ADC, M, SIY }, + {STZ, M, DX }, {ADC, M, DX }, {ROR, M, DX }, {ADC, M, DLIY}, + {SEI, I, IMP }, {ADC, M, AY }, {PLY, I, IMP }, {TDC, I, IMP }, + {JMP, I, AXI }, {ADC, M, AX }, {ROR, M, AX }, {ADC, M, ALX }, +// 0x80 + {BRA, I, RELB}, {STA, M, DXI }, {BRL, I, RELW}, {STA, M, S }, + {STY, X, D }, {STA, M, D }, {STX, X, D }, {STA, M, DLI }, + {DEY, I, IMP }, {BIT, M, IMM }, {TXA, I, IMP }, {PHB, I, IMP }, + {STY, X, A }, {STA, M, A }, {STX, X, A }, {STA, M, AL }, +// 0x90 + {BCC, I, RELB}, {STA, M, DIY }, {STA, M, DI }, {STA, M, SIY }, + {STY, X, DX }, {STA, M, DX }, {STX, X, DY }, {STA, M, DLIY}, + {TYA, I, IMP }, {STA, M, AY }, {TXS, I, IMP }, {TXY, I, IMP }, + {STZ, M, A }, {STA, M, AX }, {STZ, M, AX }, {STA, M, ALX }, +// 0xA0 + {LDY, X, IMM }, {LDA, M, DXI }, {LDX, X, IMM }, {LDA, M, S }, + {LDY, X, D }, {LDA, M, D }, {LDX, X, D }, {LDA, M, DLI }, + {TAY, I, IMP }, {LDA, M, IMM }, {TAX, I, IMP }, {PLB, I, IMP }, + {LDY, X, A }, {LDA, M, A }, {LDX, X, A }, {LDA, M, AL }, +// 0xB0 + {BCS, I, RELB}, {LDA, M, DIY }, {LDA, M, DI }, {LDA, M, SIY }, + {LDY, X, DX }, {LDA, M, DX }, {LDX, X, DY }, {LDA, M, DLIY}, + {CLV, I, IMP }, {LDA, M, AY }, {TSX, I, IMP }, {TYX, I, IMP }, + {LDY, X, AX }, {LDA, M, AX }, {LDX, X, AY }, {LDA, M, ALX }, +// 0xC0 + {CPY, X, IMM }, {CMP, M, DXI }, {LDT, I, IMM }, {CMP, M, S }, + {CPY, X, D }, {CMP, M, D }, {DEC, M, D }, {CMP, M, DLI }, + {INY, I, IMP }, {CMP, M, IMM }, {DEX, I, IMP }, {WAI, I, IMP }, + {CPY, X, A }, {CMP, M, A }, {DEC, M, A }, {CMP, M, AL }, +// 0xD0 + {BNE, I, RELB}, {CMP, M, DIY }, {CMP, M, DI }, {CMP, M, SIY }, + {PEI, I, PEI }, {CMP, M, DX }, {DEC, M, DX }, {CMP, M, DLIY}, + {CLD, I, IMP }, {CMP, M, AY }, {PHX, I, IMP }, {STP, I, IMP }, + {JML, I, AI }, {CMP, M, AX }, {DEC, M, AX }, {CMP, M, ALX }, +// 0xE0 + {CPX, X, IMM }, {SBC, M, DXI }, {SEP, I, IMM }, {SBC, M, S }, + {CPX, X, D }, {SBC, M, D }, {INC, M, D }, {SBC, M, DLI }, + {INX, M, IMP }, {SBC, M, IMM }, {NOP, I, IMP }, {XBA, I, IMP }, + {CPX, X, A }, {SBC, M, A }, {INC, M, A }, {SBC, M, AL }, +// 0xF0 + {BEQ, I, RELB}, {SBC, M, DIY }, {SBC, M, DI }, {SBC, M, SIY }, + {PEA, I, PEA }, {SBC, M, DX }, {INC, M, DX }, {SBC, M, DLIY}, + {SEM, I, IMP }, {SBC, M, AY }, {PLX, I, IMP }, {XCE, I, IMP }, + {JSR, I, AXI }, {SBC, M, AX }, {INC, M, AX }, {SBC, M, ALX } +}; + +INLINE unsigned int read_8(const UINT8 *oprom, unsigned int offset) +{ + return oprom[offset]; +} + +INLINE unsigned int read_16(const UINT8 *oprom, unsigned int offset) +{ + unsigned int val = read_8(oprom, offset); + return val | (read_8(oprom, offset+1)<<8); +} + +INLINE unsigned int read_24(const UINT8 *oprom, unsigned int offset) +{ + unsigned int val = read_8(oprom, offset); + val |= (read_8(oprom, offset+1)<<8); + return val | (read_8(oprom, offset+2)<<16); +} + +INLINE char* int_8_str(unsigned int val) +{ + static char str[20]; + + val &= 0xff; + + if(val & 0x80) + sprintf(str, "-$%x", (0-val) & 0x7f); + else + sprintf(str, "$%x", val & 0x7f); + + return str; +} + +INLINE char* int_16_str(unsigned int val) +{ + static char str[20]; + + val &= 0xffff; + + if(val & 0x8000) + sprintf(str, "-$%x", (0-val) & 0x7fff); + else + sprintf(str, "$%x", val & 0x7fff); + + return str; +} + + +int m7700_disassemble(char* buff, unsigned int pc, unsigned int pb, const UINT8 *oprom, int m_flag, int x_flag) +{ + unsigned int instruction; + const m7700_opcode_struct *opcode; + char* ptr; + int var; + signed char varS; + int length = 1; + unsigned int address; + //unsigned int start; + UINT32 flags = 0; + + pb <<= 16; + address = pc | pb; + //start = address; + + instruction = read_8(oprom,0); + + // check for prefixes + switch (instruction) + { + case 0x42: + address++; + length++; + oprom++; + instruction = read_8(oprom,0); + opcode = g_opcodes_prefix42 + instruction; + break; + + case 0x89: + address++; + length++; + oprom++; + instruction = read_8(oprom,0); + opcode = g_opcodes_prefix89 + instruction; + break; + + default: + opcode = g_opcodes + instruction; + break; + } + + if (opcode->name == JSR) + flags = DASMFLAG_STEP_OVER; + else if (opcode->name == RTS || opcode->name == RTI) + flags = DASMFLAG_STEP_OUT; + + sprintf(buff, "%s", g_opnames[opcode->name]); + ptr = buff + strlen(buff); + + switch(opcode->ea) + { + case IMP : + break; + case ACC : + sprintf(ptr, " A"); + break; + case ACCB : + sprintf(ptr, " B"); + break; + case RELB: + varS = read_8(oprom,1); + length++; + sprintf(ptr, " %06x (%s)", pb | ((pc + length + varS)&0xffff), int_8_str(varS)); + break; + case RELW: + case PER : + var = read_16(oprom,1); + length += 2; + sprintf(ptr, " %06x (%s)", pb | ((pc + length + var)&0xffff), int_16_str(var)); + break; + case IMM : + if((opcode->flag == M && !m_flag) || (opcode->flag == X && !x_flag)) + { + sprintf(ptr, " #$%04x", read_16(oprom,1)); + length += 2; + } + else + { + sprintf(ptr, " #$%02x", read_8(oprom,1)); + length++; + } + break; + case BBCD: + if((opcode->flag == M && !m_flag) || (opcode->flag == X && !x_flag)) + { + varS = read_8(oprom,4); + length += 4; + sprintf(ptr, " #$%04x, $%02x, %06x (%s)", read_16(oprom,2), read_8(oprom,1), pb | ((pc + length + varS)&0xffff), int_8_str(varS)); + } + else + { + varS = read_8(oprom,3); + length += 3; + sprintf(ptr, " #$%02x, $%02x, %06x (%s)", read_8(oprom,2), read_8(oprom,1), pb | ((pc + length + varS)&0xffff), int_8_str(varS)); + } + break; + case BBCA: + if((opcode->flag == M && !m_flag) || (opcode->flag == X && !x_flag)) + { + length += 5; + varS = read_8(oprom,5); + sprintf(ptr, " #$%04x, $%04x, %06x (%s)", read_16(oprom,3), read_16(oprom,1), pb | ((pc + length + varS)&0xffff), int_8_str(varS)); + } + else + { + length += 4; + varS = read_8(oprom,4); + sprintf(ptr, " #$%02x, $%04x, %06x (%s)", read_8(oprom,3), read_16(oprom,1), pb | ((pc + length + varS)&0xffff), int_8_str(varS)); + } + break; + case LDM4: + if((opcode->flag == M && !m_flag) || (opcode->flag == X && !x_flag)) + { + sprintf(ptr, " #$%04x, $%02x", read_16(oprom,2), read_8(oprom,1)); + length += 3; + } + else + { + sprintf(ptr, " #$%02x, $%02x", read_8(oprom,2), read_8(oprom,1)); + length += 2; + } + break; + case LDM5: + if((opcode->flag == M && !m_flag) || (opcode->flag == X && !x_flag)) + { + sprintf(ptr, " #$%04x, $%04x", read_16(oprom,3), read_16(oprom,1)); + length += 4; + } + else + { + sprintf(ptr, " #$%02x, $%04x", read_8(oprom,3), read_16(oprom,1)); + length += 3; + } + break; + case LDM4X: + if((opcode->flag == M && !m_flag) || (opcode->flag == X && !x_flag)) + { + sprintf(ptr, " #$%04x, $%02x, X", read_16(oprom,2), read_8(oprom,1)); + length += 3; + } + else + { + sprintf(ptr, " #$%02x, $%02x, X", read_8(oprom,2), read_8(oprom,1)); + length += 2; + } + break; + case LDM5X: + if((opcode->flag == M && !m_flag) || (opcode->flag == X && !x_flag)) + { + sprintf(ptr, " #$%04x, $%04x, X", read_16(oprom,3), read_16(oprom,1)); + length += 4; + } + else + { + sprintf(ptr, " #$%02x, $%04x, X", read_8(oprom,3), read_16(oprom,1)); + length += 3; + } + break; + case A : + case PEA : + sprintf(ptr, " $%04x", read_16(oprom,1)); + length += 2; + break; + case AI : + sprintf(ptr, " ($%04x)", read_16(oprom,1)); + length += 2; + break; + case AL : + sprintf(ptr, " $%06x", read_24(oprom,1)); + length += 3; + break; + case ALX : + sprintf(ptr, " $%06x,X", read_24(oprom,1)); + length += 3; + break; + case AX : + sprintf(ptr, " $%04x,X", read_16(oprom,1)); + length += 2; + break; + case AXI : + sprintf(ptr, " ($%04x,X)", read_16(oprom,1)); + length += 2; + break; + case AY : + sprintf(ptr, " $%04x,Y", read_16(oprom,1)); + length += 2; + break; + case D : + sprintf(ptr, " $%02x", read_8(oprom,1)); + length++; + break; + case DI : + case PEI : + sprintf(ptr, " ($%02x)", read_8(oprom,1)); + length++; + break; + case DIY : + sprintf(ptr, " ($%02x),Y", read_8(oprom,1)); + length++; + break; + case DLI : + sprintf(ptr, " [$%02x]", read_8(oprom,1)); + length++; + break; + case DLIY: + sprintf(ptr, " [$%02x],Y", read_8(oprom,1)); + length++; + break; + case DX : + sprintf(ptr, " $%02x,X", read_8(oprom,1)); + length++; + break; + case DXI : + sprintf(ptr, " ($%02x,X)", read_8(oprom,1)); + length++; + break; + case DY : + sprintf(ptr, " $%02x,Y", read_8(oprom,1)); + length++; + break; + case S : + sprintf(ptr, " %s,S", int_8_str(read_8(oprom,1))); + length++; + break; + case SIY : + sprintf(ptr, " (%s,S),Y", int_8_str(read_8(oprom,1))); + length++; + break; + case SIG : + sprintf(ptr, " #$%02x", read_8(oprom,1)); + length++; + break; + case MVN : + case MVP : + sprintf(ptr, " $%02x, $%02x", read_8(oprom,2), read_8(oprom,1)); + length += 2; + break; + } + + return length | flags | DASMFLAG_SUPPORTED; +} + +CPU_DISASSEMBLE( m37710_generic ) +{ + return m7700_disassemble(buffer, (pc&0xffff), pc>>16, oprom, 0, 0); +} diff --git a/src/devices/cpu/m37710/m7700ds.h b/src/devices/cpu/m37710/m7700ds.h new file mode 100644 index 00000000000..c0af0846b72 --- /dev/null +++ b/src/devices/cpu/m37710/m7700ds.h @@ -0,0 +1,23 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont, Karl Stenerud +#pragma once + +#ifndef __M7700DS_H__ +#define __M7700DS_H__ + +/* + +Mitsubishi 7700 CPU Emulator v0.10 +By R. Belmont + +Based on: +G65C816 CPU Emulator V0.92 + +Copyright Karl Stenerud +All rights reserved. + +*/ + +int m7700_disassemble(char* buff, unsigned int pc, unsigned int pb, const UINT8 *oprom, int m_flag, int x_flag); + +#endif /* __M7700DS_H__ */ diff --git a/src/devices/cpu/m6502/ddeco16.lst b/src/devices/cpu/m6502/ddeco16.lst new file mode 100644 index 00000000000..b57f2614cf0 --- /dev/null +++ b/src/devices/cpu/m6502/ddeco16.lst @@ -0,0 +1,18 @@ +# deco16 - deco variant +brk_16_imp ora_idx ill_non ill_non ill_non ora_zpg asl_zpg ill_non php_imp ora_imm asl_acc u0B_zpg ill_non ora_aba asl_aba ill_non +bpl_rel ora_idy ill_non u13_zpg ill_non ora_zpx asl_zpx ill_non clc_imp ora_aby ill_non ill_non ill_non ora_abx asl_abx ill_non +jsr_adr and_idx ill_non u23_zpg bit_zpg and_zpg rol_zpg ill_non plp_imp and_imm rol_acc ill_non bit_aba and_aba rol_aba ill_non +bmi_rel and_idy ill_non ill_non ill_non and_zpx rol_zpx ill_non sec_imp and_aby ill_non ill_non ill_non and_abx rol_abx u3F_zpg +rti_imp eor_idx ill_non ill_non ill_non eor_zpg lsr_zpg ill_non pha_imp eor_imm lsr_acc u4B_zpg jmp_adr eor_aba lsr_aba ill_non +bvc_rel eor_idy ill_non ill_non ill_non eor_zpx lsr_zpx ill_non cli_imp eor_aby ill_non ill_non ill_non eor_abx lsr_abx ill_non +rts_imp adc_idx ill_non ill_non ill_non adc_zpg ror_zpg vbl_zpg pla_imp adc_imm ror_acc ill_non jmp_ind adc_aba ror_aba ill_non +bvs_rel adc_idy ill_non ill_non ill_non adc_zpx ror_zpx ill_non sei_imp adc_aby ill_non ill_non ill_non adc_abx ror_abx ill_non +ill_non sta_idx ill_non ill_non sty_zpg sta_zpg stx_zpg u87_zpg dey_imp ill_non txa_imp ill_non sty_aba sta_aba stx_aba u8F_zpg +bcc_rel sta_idy ill_non ill_non sty_zpx sta_zpx stx_zpy ill_non tya_imp sta_aby txs_imp ill_non ill_non sta_abx ill_non ill_non +ldy_imm lda_idx ldx_imm uA3_zpg ldy_zpg lda_zpg ldx_zpg ill_non tay_imp lda_imm tax_imp ill_non ldy_aba lda_aba ldx_aba ill_non +bcs_rel lda_idy ill_non ill_non ldy_zpx lda_zpx ldx_zpy ill_non clv_imp lda_aby tsx_imp uBB_zpg ldy_abx lda_abx ldx_aby ill_non +cpy_imm cmp_idx ill_non ill_non cpy_zpg cmp_zpg dec_zpg ill_non iny_imp cmp_imm dex_imp ill_non cpy_aba cmp_aba dec_aba ill_non +bne_rel cmp_idy ill_non ill_non ill_non cmp_zpx dec_zpx ill_non cld_imp cmp_aby ill_non ill_non ill_non cmp_abx dec_abx ill_non +cpx_imm sbc_idx ill_non ill_non cpx_zpg sbc_zpg inc_zpg ill_non inx_imp sbc_imm nop_imp ill_non cpx_aba sbc_aba inc_aba ill_non +beq_rel sbc_idy ill_non ill_non ill_non sbc_zpx inc_zpx ill_non sed_imp sbc_aby ill_non ill_non ill_non sbc_abx inc_abx ill_non +reset_16 diff --git a/src/devices/cpu/m6502/deco16.c b/src/devices/cpu/m6502/deco16.c new file mode 100644 index 00000000000..a500b287d7a --- /dev/null +++ b/src/devices/cpu/m6502/deco16.c @@ -0,0 +1,53 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +/*************************************************************************** + + deco16.c + + 6502, reverse-engineered DECO variant + +***************************************************************************/ + +#include "emu.h" +#include "deco16.h" + +#define DECO16_VERBOSE 1 + +const device_type DECO16 = &device_creator; + +deco16_device::deco16_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + m6502_device(mconfig, DECO16, "DECO16", tag, owner, clock, "deco16", __FILE__), + io_config("io", ENDIANNESS_LITTLE, 8, 16) +{ +} + +offs_t deco16_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + return disassemble_generic(buffer, pc, oprom, opram, options, disasm_entries); +} + + +void deco16_device::device_start() +{ + if(direct_disabled) + mintf = new mi_default_nd; + else + mintf = new mi_default_normal; + + init(); + + io = &space(AS_IO); +} + +const address_space_config *deco16_device::memory_space_config(address_spacenum spacenum) const +{ + switch(spacenum) + { + case AS_PROGRAM: return &program_config; + case AS_IO: return &io_config; + case AS_DECRYPTED_OPCODES: return has_configured_map(AS_DECRYPTED_OPCODES) ? &sprogram_config : NULL; + default: return NULL; + } +} + +#include "cpu/m6502/deco16.inc" diff --git a/src/devices/cpu/m6502/deco16.h b/src/devices/cpu/m6502/deco16.h new file mode 100644 index 00000000000..d82087477f7 --- /dev/null +++ b/src/devices/cpu/m6502/deco16.h @@ -0,0 +1,62 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +/*************************************************************************** + + deco16.h + + 6502, reverse-engineered DECO variant + +***************************************************************************/ + +#ifndef __DECO16_H__ +#define __DECO16_H__ + +#include "m6502.h" + +class deco16_device : public m6502_device { +public: + deco16_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + static const disasm_entry disasm_entries[0x100]; + + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + virtual void do_exec_full(); + virtual void do_exec_partial(); + +protected: + address_space *io; + address_space_config io_config; + + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const; + virtual void device_start(); + +#define O(o) void o ## _full(); void o ## _partial() + + O(brk_16_imp); + O(ill_non); + O(u0B_zpg); + O(u13_zpg); + O(u23_zpg); + O(u3F_zpg); + O(u4B_zpg); + O(u87_zpg); + O(u8F_zpg); + O(uA3_zpg); + O(uAB_zpg); + O(uBB_zpg); + O(vbl_zpg); + + O(reset_16); + +#undef O +}; + +enum { + DECO16_IRQ_LINE = m6502_device::IRQ_LINE, + DECO16_NMI_LINE = m6502_device::NMI_LINE, + DECO16_SET_OVERFLOW = m6502_device::V_LINE +}; + +extern const device_type DECO16; + +#endif diff --git a/src/devices/cpu/m6502/dm4510.lst b/src/devices/cpu/m6502/dm4510.lst new file mode 100644 index 00000000000..6de7627ebc7 --- /dev/null +++ b/src/devices/cpu/m6502/dm4510.lst @@ -0,0 +1,18 @@ +# m4510 - 65ce02 with a mmu +brk_ce_imp ora_ce_idx cle_imp see_imp tsb_ce_zpg ora_ce_zpg asl_ce_zpg rmb_ce_bzp php_ce_imp ora_imm asl_ce_acc tsy_imp tsb_ce_aba ora_aba asl_ce_aba bbr_ce_zpb +bpl_ce_rel ora_ce_idy ora_idz bpl_rw2 trb_ce_zpg ora_ce_zpx asl_ce_zpx rmb_ce_bzp clc_ce_imp ora_ce_aby inc_ce_acc inz_imp trb_ce_aba ora_ce_abx asl_ce_abx bbr_ce_zpb +jsr_ce_adr and_ce_idx jsr_ind jsr_iax bit_ce_zpg and_ce_zpg rol_ce_zpg rmb_ce_bzp plp_ce_imp and_imm rol_ce_acc tys_imp bit_aba and_aba rol_ce_aba bbr_ce_zpb +bmi_ce_rel and_ce_idy and_idz bmi_rw2 bit_ce_zpx and_ce_zpx rol_ce_zpx rmb_ce_bzp sec_ce_imp and_ce_aby dec_ce_acc dez_imp bit_ce_abx and_ce_abx rol_ce_abx bbr_ce_zpb +rti_ce_imp eor_ce_idx neg_acc asr_acc asr_zpg eor_ce_zpg lsr_ce_zpg rmb_ce_bzp pha_ce_imp eor_imm lsr_ce_acc taz_imp jmp_adr eor_aba lsr_ce_aba bbr_ce_zpb +bvc_ce_rel eor_ce_idy eor_idz bvc_rw2 asr_zpx eor_ce_zpx lsr_ce_zpx rmb_ce_bzp cli_ce_imp eor_ce_aby phy_ce_imp tab_imp map_imp eor_ce_abx lsr_ce_abx bbr_ce_zpb +rts_ce_imp adc_ce_idx rtn_imm bsr_rw2 stz_ce_zpg adc_ce_zpg ror_ce_zpg rmb_ce_bzp pla_ce_imp adc_ce_imm ror_ce_acc tza_imp jmp_ce_ind adc_ce_aba ror_ce_aba bbr_ce_zpb +bvs_ce_rel adc_ce_idy adc_idz bvs_rw2 stz_ce_zpx adc_ce_zpx ror_ce_zpx rmb_ce_bzp sei_ce_imp adc_ce_aby ply_ce_imp tba_imp jmp_ce_iax adc_ce_abx ror_ce_abx bbr_ce_zpb +bra_ce_rel sta_ce_idx sta_isy bra_rw2 sty_ce_zpg sta_ce_zpg stx_ce_zpg smb_ce_bzp dey_ce_imp bit_ce_imm txa_ce_imp sty_abx sty_aba sta_aba stx_aba bbs_ce_zpb +bcc_ce_rel sta_ce_idy sta_idz bcc_rw2 sty_ce_zpx sta_ce_zpx stx_ce_zpy smb_ce_bzp tya_ce_imp sta_ce_aby txs_ce_imp stx_aby stz_ce_aba sta_ce_abx stz_ce_abx bbs_ce_zpb +ldy_imm lda_ce_idx ldx_imm ldz_imm ldy_ce_zpg lda_ce_zpg ldx_ce_zpg smb_ce_bzp tay_ce_imp lda_imm tax_ce_imp ldz_aba ldy_aba lda_aba ldx_aba bbs_ce_zpb +bcs_ce_rel lda_ce_idy lda_idz bcs_rw2 ldy_ce_zpx lda_ce_zpx ldx_ce_zpy smb_ce_bzp clv_ce_imp lda_ce_aby tsx_ce_imp ldz_abx ldy_ce_abx lda_ce_abx ldx_ce_aby bbs_ce_zpb +cpy_imm cmp_ce_idx cpz_imm dew_zpg cpy_ce_zpg cmp_ce_zpg dec_ce_zpg smb_ce_bzp iny_ce_imp cmp_imm dex_ce_imp asw_aba cpy_aba cmp_aba dec_ce_aba bbs_ce_zpb +bne_ce_rel cmp_ce_idy cmp_idz bne_rw2 cpz_zpg cmp_ce_zpx dec_ce_zpx smb_ce_bzp cld_ce_imp cmp_ce_aby phx_ce_imp phz_imp cpz_aba cmp_ce_abx dec_ce_abx bbs_ce_zpb +cpx_imm sbc_ce_idx lda_isy inw_zpg cpx_ce_zpg sbc_ce_zpg inc_ce_zpg smb_ce_bzp inx_ce_imp sbc_ce_imm eom_imp row_aba cpx_aba sbc_ce_aba inc_ce_aba bbs_ce_zpb +beq_ce_rel sbc_ce_idy sbc_idz beq_rw2 phw_iw2 sbc_ce_zpx inc_ce_zpx smb_ce_bzp sed_ce_imp sbc_ce_aby plx_ce_imp plz_imp phw_aba sbc_ce_abx inc_ce_abx bbs_ce_zpb +reset diff --git a/src/devices/cpu/m6502/dm6502.lst b/src/devices/cpu/m6502/dm6502.lst new file mode 100644 index 00000000000..335cae3d2e7 --- /dev/null +++ b/src/devices/cpu/m6502/dm6502.lst @@ -0,0 +1,18 @@ +# m6502_family_device - 6502, 6504 +brk_imp ora_idx kil_non slo_idx nop_zpg ora_zpg asl_zpg slo_zpg php_imp ora_imm asl_acc anc_imm nop_aba ora_aba asl_aba slo_aba +bpl_rel ora_idy kil_non slo_idy nop_zpx ora_zpx asl_zpx slo_zpx clc_imp ora_aby nop_imp slo_aby nop_abx ora_abx asl_abx slo_abx +jsr_adr and_idx kil_non rla_idx bit_zpg and_zpg rol_zpg rla_zpg plp_imp and_imm rol_acc anc_imm bit_aba and_aba rol_aba rla_aba +bmi_rel and_idy kil_non rla_idy nop_zpx and_zpx rol_zpx rla_zpx sec_imp and_aby nop_imp rla_aby nop_abx and_abx rol_abx rla_abx +rti_imp eor_idx kil_non sre_idx nop_zpg eor_zpg lsr_zpg sre_zpg pha_imp eor_imm lsr_acc asr_imm jmp_adr eor_aba lsr_aba sre_aba +bvc_rel eor_idy kil_non sre_idy nop_zpx eor_zpx lsr_zpx sre_zpx cli_imp eor_aby nop_imp sre_aby nop_abx eor_abx lsr_abx sre_abx +rts_imp adc_idx kil_non rra_idx nop_zpg adc_zpg ror_zpg rra_zpg pla_imp adc_imm ror_acc arr_imm jmp_ind adc_aba ror_aba rra_aba +bvs_rel adc_idy kil_non rra_idy nop_zpx adc_zpx ror_zpx rra_zpx sei_imp adc_aby nop_imp rra_aby nop_abx adc_abx ror_abx rra_abx +nop_imm sta_idx nop_imm sax_idx sty_zpg sta_zpg stx_zpg sax_zpg dey_imp nop_imm txa_imp ane_imm sty_aba sta_aba stx_aba sax_aba +bcc_rel sta_idy kil_non sha_idy sty_zpx sta_zpx stx_zpy sax_zpy tya_imp sta_aby txs_imp shs_aby shy_abx sta_abx shx_aby sha_aby +ldy_imm lda_idx ldx_imm lax_idx ldy_zpg lda_zpg ldx_zpg lax_zpg tay_imp lda_imm tax_imp lxa_imm ldy_aba lda_aba ldx_aba lax_aba +bcs_rel lda_idy kil_non lax_idy ldy_zpx lda_zpx ldx_zpy lax_zpy clv_imp lda_aby tsx_imp las_aby ldy_abx lda_abx ldx_aby lax_aby +cpy_imm cmp_idx nop_imm dcp_idx cpy_zpg cmp_zpg dec_zpg dcp_zpg iny_imp cmp_imm dex_imp sbx_imm cpy_aba cmp_aba dec_aba dcp_aba +bne_rel cmp_idy kil_non dcp_idy nop_zpx cmp_zpx dec_zpx dcp_zpx cld_imp cmp_aby nop_imp dcp_aby nop_abx cmp_abx dec_abx dcp_abx +cpx_imm sbc_idx nop_imm isb_idx cpx_zpg sbc_zpg inc_zpg isb_zpg inx_imp sbc_imm nop_imp sbc_imm cpx_aba sbc_aba inc_aba isb_aba +beq_rel sbc_idy kil_non isb_idy nop_zpx sbc_zpx inc_zpx isb_zpx sed_imp sbc_aby nop_imp isb_aby nop_abx sbc_abx inc_abx isb_abx +reset diff --git a/src/devices/cpu/m6502/dm6509.lst b/src/devices/cpu/m6502/dm6509.lst new file mode 100644 index 00000000000..644aa6c79d6 --- /dev/null +++ b/src/devices/cpu/m6502/dm6509.lst @@ -0,0 +1,18 @@ +# m6509 - special banking on two specific instructions, and banking in general +brk_imp ora_idx kil_non slo_idx nop_zpg ora_zpg asl_zpg slo_zpg php_imp ora_imm asl_acc anc_imm nop_aba ora_aba asl_aba slo_aba +bpl_rel ora_idy kil_non slo_idy nop_zpx ora_zpx asl_zpx slo_zpx clc_imp ora_aby nop_imp slo_aby nop_abx ora_abx asl_abx slo_abx +jsr_adr and_idx kil_non rla_idx bit_zpg and_zpg rol_zpg rla_zpg plp_imp and_imm rol_acc anc_imm bit_aba and_aba rol_aba rla_aba +bmi_rel and_idy kil_non rla_idy nop_zpx and_zpx rol_zpx rla_zpx sec_imp and_aby nop_imp rla_aby nop_abx and_abx rol_abx rla_abx +rti_imp eor_idx kil_non sre_idx nop_zpg eor_zpg lsr_zpg sre_zpg pha_imp eor_imm lsr_acc asr_imm jmp_adr eor_aba lsr_aba sre_aba +bvc_rel eor_idy kil_non sre_idy nop_zpx eor_zpx lsr_zpx sre_zpx cli_imp eor_aby nop_imp sre_aby nop_abx eor_abx lsr_abx sre_abx +rts_imp adc_idx kil_non rra_idx nop_zpg adc_zpg ror_zpg rra_zpg pla_imp adc_imm ror_acc arr_imm jmp_ind adc_aba ror_aba rra_aba +bvs_rel adc_idy kil_non rra_idy nop_zpx adc_zpx ror_zpx rra_zpx sei_imp adc_aby nop_imp rra_aby nop_abx adc_abx ror_abx rra_abx +nop_imm sta_idx nop_imm sax_idx sty_zpg sta_zpg stx_zpg sax_zpg dey_imp nop_imm txa_imp ane_imm sty_aba sta_aba stx_aba sax_aba +bcc_rel sta_9_idy kil_non sha_idy sty_zpx sta_zpx stx_zpy sax_zpy tya_imp sta_aby txs_imp shs_aby shy_abx sta_abx shx_aby sha_aby +ldy_imm lda_idx ldx_imm lax_idx ldy_zpg lda_zpg ldx_zpg lax_zpg tay_imp lda_imm tax_imp lxa_imm ldy_aba lda_aba ldx_aba lax_aba +bcs_rel lda_9_idy kil_non lax_idy ldy_zpx lda_zpx ldx_zpy lax_zpy clv_imp lda_aby tsx_imp las_aby ldy_abx lda_abx ldx_aby lax_aby +cpy_imm cmp_idx nop_imm dcp_idx cpy_zpg cmp_zpg dec_zpg dcp_zpg iny_imp cmp_imm dex_imp sbx_imm cpy_aba cmp_aba dec_aba dcp_aba +bne_rel cmp_idy kil_non dcp_idy nop_zpx cmp_zpx dec_zpx dcp_zpx cld_imp cmp_aby nop_imp dcp_aby nop_abx cmp_abx dec_abx dcp_abx +cpx_imm sbc_idx nop_imm isb_idx cpx_zpg sbc_zpg inc_zpg isb_zpg inx_imp sbc_imm nop_imp sbc_imm cpx_aba sbc_aba inc_aba isb_aba +beq_rel sbc_idy kil_non isb_idy nop_zpx sbc_zpx inc_zpx isb_zpx sed_imp sbc_aby nop_imp isb_aby nop_abx sbc_abx inc_abx isb_abx +reset diff --git a/src/devices/cpu/m6502/dm6510.lst b/src/devices/cpu/m6502/dm6510.lst new file mode 100644 index 00000000000..dbc8bd88d57 --- /dev/null +++ b/src/devices/cpu/m6502/dm6510.lst @@ -0,0 +1,18 @@ +# m6510_family - identical to 6502, except for some undocumented instructions that have to be handled specifically +brk_imp ora_idx kil_non slo_idx nop_zpg ora_zpg asl_zpg slo_zpg php_imp ora_imm asl_acc anc_10_imm nop_aba ora_aba asl_aba slo_aba +bpl_rel ora_idy kil_non slo_idy nop_zpx ora_zpx asl_zpx slo_zpx clc_imp ora_aby nop_imp slo_aby nop_abx ora_abx asl_abx slo_abx +jsr_adr and_idx kil_non rla_idx bit_zpg and_zpg rol_zpg rla_zpg plp_imp and_imm rol_acc anc_10_imm bit_aba and_aba rol_aba rla_aba +bmi_rel and_idy kil_non rla_idy nop_zpx and_zpx rol_zpx rla_zpx sec_imp and_aby nop_imp rla_aby nop_abx and_abx rol_abx rla_abx +rti_imp eor_idx kil_non sre_idx nop_zpg eor_zpg lsr_zpg sre_zpg pha_imp eor_imm lsr_acc asr_10_imm jmp_adr eor_aba lsr_aba sre_aba +bvc_rel eor_idy kil_non sre_idy nop_zpx eor_zpx lsr_zpx sre_zpx cli_imp eor_aby nop_imp sre_aby nop_abx eor_abx lsr_abx sre_abx +rts_imp adc_idx kil_non rra_idx nop_zpg adc_zpg ror_zpg rra_zpg pla_imp adc_imm ror_acc arr_10_imm jmp_ind adc_aba ror_aba rra_aba +bvs_rel adc_idy kil_non rra_idy nop_zpx adc_zpx ror_zpx rra_zpx sei_imp adc_aby nop_imp rra_aby nop_abx adc_abx ror_abx rra_abx +nop_imm sta_idx nop_imm sax_idx sty_zpg sta_zpg stx_zpg sax_zpg dey_imp nop_imm txa_imp ane_10_imm sty_aba sta_aba stx_aba sax_aba +bcc_rel sta_idy kil_non sha_idy sty_zpx sta_zpx stx_zpy sax_zpy tya_imp sta_aby txs_imp shs_aby shy_abx sta_abx shx_aby sha_aby +ldy_imm lda_idx ldx_imm lax_idx ldy_zpg lda_zpg ldx_zpg lax_zpg tay_imp lda_imm tax_imp lxa_10_imm ldy_aba lda_aba ldx_aba lax_aba +bcs_rel lda_idy kil_non lax_idy ldy_zpx lda_zpx ldx_zpy lax_zpy clv_imp lda_aby tsx_imp las_10_aby ldy_abx lda_abx ldx_aby lax_aby +cpy_imm cmp_idx nop_imm dcp_idx cpy_zpg cmp_zpg dec_zpg dcp_zpg iny_imp cmp_imm dex_imp sbx_imm cpy_aba cmp_aba dec_aba dcp_aba +bne_rel cmp_idy kil_non dcp_idy nop_zpx cmp_zpx dec_zpx dcp_zpx cld_imp cmp_aby nop_imp dcp_aby nop_abx cmp_abx dec_abx dcp_abx +cpx_imm sbc_idx nop_imm isb_idx cpx_zpg sbc_zpg inc_zpg isb_zpg inx_imp sbc_imm nop_imp sbc_imm cpx_aba sbc_aba inc_aba isb_aba +beq_rel sbc_idy kil_non isb_idy nop_zpx sbc_zpx inc_zpx isb_zpx sed_imp sbc_aby nop_imp isb_aby nop_abx sbc_abx inc_abx isb_abx +reset diff --git a/src/devices/cpu/m6502/dm65c02.lst b/src/devices/cpu/m6502/dm65c02.lst new file mode 100644 index 00000000000..4b0cd1f2db4 --- /dev/null +++ b/src/devices/cpu/m6502/dm65c02.lst @@ -0,0 +1,18 @@ +# m65c02 +brk_c_imp ora_idx nop_imm nop_c_imp tsb_zpg ora_zpg asl_zpg nop_c_imp php_imp ora_imm asl_acc nop_c_imp tsb_aba ora_aba asl_aba nop_c_imp +bpl_rel ora_idy ora_zpi nop_c_imp trb_zpg ora_zpx asl_zpx nop_c_imp clc_imp ora_aby inc_acc nop_c_imp trb_aba ora_abx asl_c_abx nop_c_imp +jsr_adr and_idx nop_imm nop_c_imp bit_zpg and_zpg rol_zpg nop_c_imp plp_imp and_imm rol_acc nop_c_imp bit_aba and_aba rol_aba nop_c_imp +bmi_rel and_idy and_zpi nop_c_imp bit_zpx and_zpx rol_zpx nop_c_imp sec_imp and_aby dec_acc nop_c_imp bit_abx and_abx rol_c_abx nop_c_imp +rti_imp eor_idx nop_imm nop_c_imp nop_zpg eor_zpg lsr_zpg nop_c_imp pha_imp eor_imm lsr_acc nop_c_imp jmp_adr eor_aba lsr_aba nop_c_imp +bvc_rel eor_idy eor_zpi nop_c_imp nop_zpx eor_zpx lsr_zpx nop_c_imp cli_imp eor_aby phy_imp nop_c_imp nop_c_aba eor_abx lsr_c_abx nop_c_imp +rts_imp adc_c_idx nop_imm nop_c_imp stz_zpg adc_c_zpg ror_zpg nop_c_imp pla_imp adc_c_imm ror_acc nop_c_imp jmp_c_ind adc_c_aba ror_aba nop_c_imp +bvs_rel adc_c_idy adc_c_zpi nop_c_imp stz_zpx adc_c_zpx ror_zpx nop_c_imp sei_imp adc_c_aby ply_imp nop_c_imp jmp_iax adc_c_abx ror_c_abx nop_c_imp +bra_rel sta_idx nop_imm nop_c_imp sty_zpg sta_zpg stx_zpg nop_c_imp dey_imp bit_imm txa_imp nop_c_imp sty_aba sta_aba stx_aba nop_c_imp +bcc_rel sta_idy sta_zpi nop_c_imp sty_zpx sta_zpx stx_zpy nop_c_imp tya_imp sta_aby txs_imp nop_c_imp stz_aba sta_abx stz_abx nop_c_imp +ldy_imm lda_idx ldx_imm nop_c_imp ldy_zpg lda_zpg ldx_zpg nop_c_imp tay_imp lda_imm tax_imp nop_c_imp ldy_aba lda_aba ldx_aba nop_c_imp +bcs_rel lda_idy lda_zpi nop_c_imp ldy_zpx lda_zpx ldx_zpy nop_c_imp clv_imp lda_aby tsx_imp nop_c_imp ldy_abx lda_abx ldx_aby nop_c_imp +cpy_imm cmp_idx nop_imm nop_c_imp cpy_zpg cmp_zpg dec_zpg nop_c_imp iny_imp cmp_imm dex_imp nop_c_imp cpy_aba cmp_aba dec_aba nop_c_imp +bne_rel cmp_idy cmp_zpi nop_c_imp nop_zpx cmp_zpx dec_zpx nop_c_imp cld_imp cmp_aby phx_imp nop_c_imp nop_c_abx cmp_abx dec_abx nop_c_imp +cpx_imm sbc_c_idx nop_imm nop_c_imp cpx_zpg sbc_c_zpg inc_zpg nop_c_imp inx_imp sbc_c_imm nop_imp nop_c_imp cpx_aba sbc_c_aba inc_aba nop_c_imp +beq_rel sbc_c_idy sbc_c_zpi nop_c_imp nop_zpx sbc_c_zpx inc_zpx nop_c_imp sed_imp sbc_c_aby plx_imp nop_c_imp nop_c_abx sbc_c_abx inc_abx nop_c_imp +reset diff --git a/src/devices/cpu/m6502/dm65ce02.lst b/src/devices/cpu/m6502/dm65ce02.lst new file mode 100644 index 00000000000..b2fafe67203 --- /dev/null +++ b/src/devices/cpu/m6502/dm65ce02.lst @@ -0,0 +1,18 @@ +# m65ce02 - Adds the B and Z registers to the r65c02, a bunch of instructions, and changes most of the timings +brk_ce_imp ora_ce_idx cle_imp see_imp tsb_ce_zpg ora_ce_zpg asl_ce_zpg rmb_ce_bzp php_ce_imp ora_imm asl_ce_acc tsy_imp tsb_ce_aba ora_aba asl_ce_aba bbr_ce_zpb +bpl_ce_rel ora_ce_idy ora_idz bpl_rw2 trb_ce_zpg ora_ce_zpx asl_ce_zpx rmb_ce_bzp clc_ce_imp ora_ce_aby inc_ce_acc inz_imp trb_ce_aba ora_ce_abx asl_ce_abx bbr_ce_zpb +jsr_ce_adr and_ce_idx jsr_ind jsr_iax bit_ce_zpg and_ce_zpg rol_ce_zpg rmb_ce_bzp plp_ce_imp and_imm rol_ce_acc tys_imp bit_aba and_aba rol_ce_aba bbr_ce_zpb +bmi_ce_rel and_ce_idy and_idz bmi_rw2 bit_ce_zpx and_ce_zpx rol_ce_zpx rmb_ce_bzp sec_ce_imp and_ce_aby dec_ce_acc dez_imp bit_ce_abx and_ce_abx rol_ce_abx bbr_ce_zpb +rti_ce_imp eor_ce_idx neg_acc asr_acc asr_zpg eor_ce_zpg lsr_ce_zpg rmb_ce_bzp pha_ce_imp eor_imm lsr_ce_acc taz_imp jmp_adr eor_aba lsr_ce_aba bbr_ce_zpb +bvc_ce_rel eor_ce_idy eor_idz bvc_rw2 asr_zpx eor_ce_zpx lsr_ce_zpx rmb_ce_bzp cli_ce_imp eor_ce_aby phy_ce_imp tab_imp aug_iw3 eor_ce_abx lsr_ce_abx bbr_ce_zpb +rts_ce_imp adc_ce_idx rtn_imm bsr_rw2 stz_ce_zpg adc_ce_zpg ror_ce_zpg rmb_ce_bzp pla_ce_imp adc_ce_imm ror_ce_acc tza_imp jmp_ce_ind adc_ce_aba ror_ce_aba bbr_ce_zpb +bvs_ce_rel adc_ce_idy adc_idz bvs_rw2 stz_ce_zpx adc_ce_zpx ror_ce_zpx rmb_ce_bzp sei_ce_imp adc_ce_aby ply_ce_imp tba_imp jmp_ce_iax adc_ce_abx ror_ce_abx bbr_ce_zpb +bra_ce_rel sta_ce_idx sta_isy bra_rw2 sty_ce_zpg sta_ce_zpg stx_ce_zpg smb_ce_bzp dey_ce_imp bit_ce_imm txa_ce_imp sty_abx sty_aba sta_aba stx_aba bbs_ce_zpb +bcc_ce_rel sta_ce_idy sta_idz bcc_rw2 sty_ce_zpx sta_ce_zpx stx_ce_zpy smb_ce_bzp tya_ce_imp sta_ce_aby txs_ce_imp stx_aby stz_ce_aba sta_ce_abx stz_ce_abx bbs_ce_zpb +ldy_imm lda_ce_idx ldx_imm ldz_imm ldy_ce_zpg lda_ce_zpg ldx_ce_zpg smb_ce_bzp tay_ce_imp lda_imm tax_ce_imp ldz_aba ldy_aba lda_aba ldx_aba bbs_ce_zpb +bcs_ce_rel lda_ce_idy lda_idz bcs_rw2 ldy_ce_zpx lda_ce_zpx ldx_ce_zpy smb_ce_bzp clv_ce_imp lda_ce_aby tsx_ce_imp ldz_abx ldy_ce_abx lda_ce_abx ldx_ce_aby bbs_ce_zpb +cpy_imm cmp_ce_idx cpz_imm dew_zpg cpy_ce_zpg cmp_ce_zpg dec_ce_zpg smb_ce_bzp iny_ce_imp cmp_imm dex_ce_imp asw_aba cpy_aba cmp_aba dec_ce_aba bbs_ce_zpb +bne_ce_rel cmp_ce_idy cmp_idz bne_rw2 cpz_zpg cmp_ce_zpx dec_ce_zpx smb_ce_bzp cld_ce_imp cmp_ce_aby phx_ce_imp phz_imp cpz_aba cmp_ce_abx dec_ce_abx bbs_ce_zpb +cpx_imm sbc_ce_idx lda_isy inw_zpg cpx_ce_zpg sbc_ce_zpg inc_ce_zpg smb_ce_bzp inx_ce_imp sbc_ce_imm nop_c_imp row_aba cpx_aba sbc_ce_aba inc_ce_aba bbs_ce_zpb +beq_ce_rel sbc_ce_idy sbc_idz beq_rw2 phw_iw2 sbc_ce_zpx inc_ce_zpx smb_ce_bzp sed_ce_imp sbc_ce_aby plx_ce_imp plz_imp phw_aba sbc_ce_abx inc_ce_abx bbs_ce_zpb +reset diff --git a/src/devices/cpu/m6502/dm740.lst b/src/devices/cpu/m6502/dm740.lst new file mode 100644 index 00000000000..c11f0826cd5 --- /dev/null +++ b/src/devices/cpu/m6502/dm740.lst @@ -0,0 +1,34 @@ +# m740 device +brk740_imp ora_idx kil_non bbs_bar nop_zpg ora_zpg asl_zpg bbs_bzr php_imp ora_imm asl_acc seb_bac nop_aba ora_aba asl_aba seb_biz +bpl_rel ora_idy clt_imp bbc_bar nop_zpx ora_zpx asl_zpx bbc_bzr clc_imp ora_aby dec_acc clb_bac nop_abx ora_abx asl_abx clb_biz +jsr_adr and_idx jsr_spg bbs_bar bit_zpg and_zpg rol_zpg bbs_bzr plp_imp and_imm rol_acc seb_bac bit_aba and_aba rol_aba seb_biz +bmi_rel and_idy set_imp bbc_bar nop_zpx and_zpx rol_zpx bbc_bzr sec_imp and_aby inc_acc clb_bac ldm_imz and_abx rol_abx clb_biz +rti_imp eor_idx kil_non bbs_bar com_zpg eor_zpg lsr_zpg bbs_bzr pha_imp eor_imm lsr_acc seb_bac jmp_adr eor_aba lsr_aba seb_biz +bvc_rel eor_idy kil_non bbc_bar nop_zpx eor_zpx lsr_zpx bbc_bzr cli_imp eor_aby nop_imp clb_bac nop_abx eor_abx lsr_abx clb_biz +rts_imp adc_idx kil_non bbs_bar nop_zpg adc_zpg ror_zpg bbs_bzr pla_imp adc_imm ror_acc seb_bac jmp_ind adc_aba ror_aba seb_biz +bvs_rel adc_idy kil_non bbc_bar nop_zpx adc_zpx ror_zpx bbc_bzr sei_imp adc_aby nop_imp clb_bac nop_abx adc_abx ror_abx clb_biz +bra_rel sta_idx rrf_zpg bbs_bar sty_zpg sta_zpg stx_zpg bbs_bzr dey_imp nop_imm txa_imp seb_bac sty_aba sta_aba stx_aba seb_biz +bcc_rel sta_idy kil_non bbc_bar sty_zpx sta_zpx stx_zpy bbc_bzr tya_imp sta_aby txs_imp clb_bac shy_abx sta_abx shx_aby clb_biz +ldy_imm lda_idx ldx_imm bbs_bar ldy_zpg lda_zpg ldx_zpg bbs_bzr tay_imp lda_imm tax_imp seb_bac ldy_aba lda_aba ldx_aba seb_biz +bcs_rel lda_idy jmp_zpi bbc_bar ldy_zpx lda_zpx ldx_zpy bbc_bzr clv_imp lda_aby tsx_imp clb_bac ldy_abx lda_abx ldx_aby clb_biz +cpy_imm cmp_idx nop_imm bbs_bar cpy_zpg cmp_zpg dec_zpg bbs_bzr iny_imp cmp_imm dex_imp seb_bac cpy_aba cmp_aba dec_aba seb_biz +bne_rel cmp_idy kil_non bbc_bar nop_zpx cmp_zpx dec_zpx bbc_bzr cld_imp cmp_aby nop_imp clb_bac nop_abx cmp_abx dec_abx clb_biz +cpx_imm sbc_idx nop_imm bbs_bar cpx_zpg sbc_zpg inc_zpg bbs_bzr inx_imp sbc_imm nop_imp seb_bac cpx_aba sbc_aba inc_aba seb_biz +beq_rel sbc_idy kil_non bbc_bar nop_zpx sbc_zpx inc_zpx bbc_bzr sed_imp sbc_aby nop_imp clb_bac nop_abx sbc_abx inc_abx clb_biz +brk740_imp ort_idx kil_non bbs_bar nop_zpg ort_zpg asl_zpg bbs_bzr php_imp ort_imm asl_acc seb_bac nop_aba ort_aba asl_aba seb_biz +bpl_rel ort_idy clt_imp bbc_bar nop_zpx ort_zpx asl_zpx bbc_bzr clc_imp ort_aby dect_acc clb_bac nop_abx ort_abx asl_abx clb_biz +jsr_adr andt_idx jsr_spg bbs_bar bit_zpg andt_zpg rol_zpg bbs_bzr plp_imp andt_imm rol_acc seb_bac bit_aba andt_aba rol_aba seb_biz +bmi_rel andt_idy set_imp bbc_bar nop_zpx andt_zpx rol_zpx bbc_bzr sec_imp andt_aby inct_acc clb_bac ldm_imz andt_abx rol_abx clb_biz +rti_imp eort_idx kil_non bbs_bar com_zpg eort_zpg lsr_zpg bbs_bzr pha_imp eort_imm lsr_acc seb_bac jmp_adr eort_aba lsr_aba seb_biz +bvc_rel eort_idy kil_non bbc_bar nop_zpx eort_zpx lsr_zpx bbc_bzr cli_imp eort_aby nop_imp clb_bac nop_abx eort_abx lsr_abx clb_biz +rts_imp adct_idx kil_non bbs_bar nop_zpg adct_zpg ror_zpg bbs_bzr pla_imp adct_imm ror_acc seb_bac jmp_ind adct_aba ror_aba seb_biz +bvs_rel adct_idy kil_non bbc_bar nop_zpx adct_zpx ror_zpx bbc_bzr sei_imp adct_aby nop_imp clb_bac nop_abx adct_abx ror_abx clb_biz +bra_rel sta_idx rrf_zpg bbs_bar sty_zpg sta_zpg stx_zpg bbs_bzr dey_imp nop_imm txa_imp seb_bac sty_aba sta_aba stx_aba seb_biz +bcc_rel sta_idy kil_non bbc_bar sty_zpx sta_zpx stx_zpy bbc_bzr tya_imp sta_aby txs_imp clb_bac shy_abx sta_abx shx_aby clb_biz +ldy_imm ldt_idx ldx_imm bbs_bar ldy_zpg ldt_zpg ldx_zpg bbs_bzr tay_imp ldt_imm tax_imp seb_bac ldy_aba ldt_aba ldx_aba seb_biz +bcs_rel ldt_idy jmp_zpi bbc_bar ldy_zpx ldt_zpx ldx_zpy bbc_bzr clv_imp ldt_aby tsx_imp clb_bac ldy_abx ldt_abx ldx_aby clb_biz +cpy_imm cmp_idx nop_imm bbs_bar cpy_zpg cmpt_zpg dec_zpg bbs_bzr iny_imp cmpt_imm dex_imp seb_bac cpy_aba cmpt_aba dec_aba seb_biz +bne_rel cmp_idy kil_non bbc_bar nop_zpx cmpt_zpx dec_zpx bbc_bzr cld_imp cmpt_aby nop_imp clb_bac nop_abx cmpt_abx dec_abx clb_biz +cpx_imm sbct_idx nop_imm bbs_bar cpx_zpg sbct_zpg inc_zpg bbs_bzr inx_imp sbc_imm nop_imp seb_bac cpx_aba sbct_aba inc_aba seb_biz +beq_rel sbct_idy kil_non bbc_bar nop_zpx sbct_zpx inc_zpx bbc_bzr sed_imp sbc_aby nop_imp clb_bac nop_abx sbct_abx inc_abx clb_biz +reset740 diff --git a/src/devices/cpu/m6502/dn2a03.lst b/src/devices/cpu/m6502/dn2a03.lst new file mode 100644 index 00000000000..7f0a5d4a9cb --- /dev/null +++ b/src/devices/cpu/m6502/dn2a03.lst @@ -0,0 +1,18 @@ +# n2a03 - D flag is disabled but present in the P register +brk_imp ora_idx kil_non slo_idx nop_zpg ora_zpg asl_zpg slo_zpg php_imp ora_imm asl_acc anc_imm nop_aba ora_aba asl_aba slo_aba +bpl_rel ora_idy kil_non slo_idy nop_zpx ora_zpx asl_zpx slo_zpx clc_imp ora_aby nop_imp slo_aby nop_abx ora_abx asl_abx slo_abx +jsr_adr and_idx kil_non rla_idx bit_zpg and_zpg rol_zpg rla_zpg plp_imp and_imm rol_acc anc_imm bit_aba and_aba rol_aba rla_aba +bmi_rel and_idy kil_non rla_idy nop_zpx and_zpx rol_zpx rla_zpx sec_imp and_aby nop_imp rla_aby nop_abx and_abx rol_abx rla_abx +rti_imp eor_idx kil_non sre_idx nop_zpg eor_zpg lsr_zpg sre_zpg pha_imp eor_imm lsr_acc asr_imm jmp_adr eor_aba lsr_aba sre_aba +bvc_rel eor_idy kil_non sre_idy nop_zpx eor_zpx lsr_zpx sre_zpx cli_imp eor_aby nop_imp sre_aby nop_abx eor_abx lsr_abx sre_abx +rts_imp adc_nd_idx kil_non rra_nd_idx nop_zpg adc_nd_zpg ror_zpg rra_nd_zpg pla_imp adc_nd_imm ror_acc arr_nd_imm jmp_ind adc_nd_aba ror_aba rra_nd_aba +bvs_rel adc_nd_idy kil_non rra_nd_idy nop_zpx adc_nd_zpx ror_zpx rra_nd_zpx sei_imp adc_nd_aby nop_imp rra_nd_aby nop_abx adc_nd_abx ror_abx rra_nd_abx +nop_imm sta_idx nop_imm sax_idx sty_zpg sta_zpg stx_zpg sax_zpg dey_imp nop_imm txa_imp ane_imm sty_aba sta_aba stx_aba sax_aba +bcc_rel sta_idy kil_non sha_idy sty_zpx sta_zpx stx_zpy sax_zpy tya_imp sta_aby txs_imp shs_aby shy_abx sta_abx shx_aby sha_aby +ldy_imm lda_idx ldx_imm lax_idx ldy_zpg lda_zpg ldx_zpg lax_zpg tay_imp lda_imm tax_imp lxa_imm ldy_aba lda_aba ldx_aba lax_aba +bcs_rel lda_idy kil_non lax_idy ldy_zpx lda_zpx ldx_zpy lax_zpy clv_imp lda_aby tsx_imp las_aby ldy_abx lda_abx ldx_aby lax_aby +cpy_imm cmp_idx nop_imm dcp_idx cpy_zpg cmp_zpg dec_zpg dcp_zpg iny_imp cmp_imm dex_imp sbx_imm cpy_aba cmp_aba dec_aba dcp_aba +bne_rel cmp_idy kil_non dcp_idy nop_zpx cmp_zpx dec_zpx dcp_zpx cld_imp cmp_aby nop_imp dcp_aby nop_abx cmp_abx dec_abx dcp_abx +cpx_imm sbc_nd_idx nop_imm isb_nd_idx cpx_zpg sbc_nd_zpg inc_zpg isb_nd_zpg inx_imp sbc_nd_imm nop_imp sbc_nd_imm cpx_aba sbc_nd_aba inc_aba isb_nd_aba +beq_rel sbc_nd_idy kil_non isb_nd_idy nop_zpx sbc_nd_zpx inc_zpx isb_nd_zpx sed_imp sbc_nd_aby nop_imp isb_nd_aby nop_abx sbc_nd_abx inc_abx isb_nd_abx +reset diff --git a/src/devices/cpu/m6502/dr65c02.lst b/src/devices/cpu/m6502/dr65c02.lst new file mode 100644 index 00000000000..fa4a97bda56 --- /dev/null +++ b/src/devices/cpu/m6502/dr65c02.lst @@ -0,0 +1,18 @@ +# r65c02 - rockwell variant, with the bitwise instructions and stp/wai +brk_c_imp ora_idx nop_imm nop_c_imp tsb_zpg ora_zpg asl_zpg rmb_bzp php_imp ora_imm asl_acc nop_c_imp tsb_aba ora_aba asl_aba bbr_zpb +bpl_rel ora_idy ora_zpi nop_c_imp trb_zpg ora_zpx asl_zpx rmb_bzp clc_imp ora_aby inc_acc nop_c_imp trb_aba ora_abx asl_c_abx bbr_zpb +jsr_adr and_idx nop_imm nop_c_imp bit_zpg and_zpg rol_zpg rmb_bzp plp_imp and_imm rol_acc nop_c_imp bit_aba and_aba rol_aba bbr_zpb +bmi_rel and_idy and_zpi nop_c_imp bit_zpx and_zpx rol_zpx rmb_bzp sec_imp and_aby dec_acc nop_c_imp bit_abx and_abx rol_c_abx bbr_zpb +rti_imp eor_idx nop_imm nop_c_imp nop_zpg eor_zpg lsr_zpg rmb_bzp pha_imp eor_imm lsr_acc nop_c_imp jmp_adr eor_aba lsr_aba bbr_zpb +bvc_rel eor_idy eor_zpi nop_c_imp nop_zpx eor_zpx lsr_zpx rmb_bzp cli_imp eor_aby phy_imp nop_c_imp nop_c_aba eor_abx lsr_c_abx bbr_zpb +rts_imp adc_c_idx nop_imm nop_c_imp stz_zpg adc_c_zpg ror_zpg rmb_bzp pla_imp adc_c_imm ror_acc nop_c_imp jmp_c_ind adc_c_aba ror_aba bbr_zpb +bvs_rel adc_c_idy adc_c_zpi nop_c_imp stz_zpx adc_c_zpx ror_zpx rmb_bzp sei_imp adc_c_aby ply_imp nop_c_imp jmp_iax adc_c_abx ror_c_abx bbr_zpb +bra_rel sta_idx nop_imm nop_c_imp sty_zpg sta_zpg stx_zpg smb_bzp dey_imp bit_imm txa_imp nop_c_imp sty_aba sta_aba stx_aba bbs_zpb +bcc_rel sta_idy sta_zpi nop_c_imp sty_zpx sta_zpx stx_zpy smb_bzp tya_imp sta_aby txs_imp nop_c_imp stz_aba sta_abx stz_abx bbs_zpb +ldy_imm lda_idx ldx_imm nop_c_imp ldy_zpg lda_zpg ldx_zpg smb_bzp tay_imp lda_imm tax_imp nop_c_imp ldy_aba lda_aba ldx_aba bbs_zpb +bcs_rel lda_idy lda_zpi nop_c_imp ldy_zpx lda_zpx ldx_zpy smb_bzp clv_imp lda_aby tsx_imp nop_c_imp ldy_abx lda_abx ldx_aby bbs_zpb +cpy_imm cmp_idx nop_imm nop_c_imp cpy_zpg cmp_zpg dec_zpg smb_bzp iny_imp cmp_imm dex_imp wai_imp cpy_aba cmp_aba dec_aba bbs_zpb +bne_rel cmp_idy cmp_zpi nop_c_imp nop_zpx cmp_zpx dec_zpx smb_bzp cld_imp cmp_aby phx_imp stp_imp nop_c_abx cmp_abx dec_abx bbs_zpb +cpx_imm sbc_c_idx nop_imm nop_c_imp cpx_zpg sbc_c_zpg inc_zpg smb_bzp inx_imp sbc_c_imm nop_imp nop_c_imp cpx_aba sbc_c_aba inc_aba bbs_zpb +beq_rel sbc_c_idy sbc_c_zpi nop_c_imp nop_zpx sbc_c_zpx inc_zpx smb_bzp sed_imp sbc_c_aby plx_imp nop_c_imp nop_c_abx sbc_c_abx inc_abx bbs_zpb +reset diff --git a/src/devices/cpu/m6502/m3745x.c b/src/devices/cpu/m6502/m3745x.c new file mode 100644 index 00000000000..79aa2a95a83 --- /dev/null +++ b/src/devices/cpu/m6502/m3745x.c @@ -0,0 +1,503 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont, Olivier Galibert +/* + Mitsubishi M3745x 8-bit microcontroller family +*/ + +#include "emu.h" +#include "m3745x.h" + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +// Interrupt control bits (interpolated from C68 program; need 7450 Group manual badly) + +#define IRQ1_INT1 (0x04) +#define IRQ1_INT2 (0x08) // guess, not used in C68 +#define IRQ1_INT3 (0x10) // guess, not used in C68 + +#define IRQ2_SERIALRX (0x08) +#define IRQ2_SERIALTX (0x10) +#define IRQ2_ADC (0x20) + +#define ADCTRL_CH_MASK (0x07) // AD ctrl reg. channel mask +#define ADCTRL_COMPLETE (0x08) // AD ctrl "start"/"complete" bit + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type M37450 = &device_creator; + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// m3745x_device - constructor +//------------------------------------------------- +m3745x_device::m3745x_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, address_map_constructor internal_map, const char *shortname, const char *source) : + m740_device(mconfig, type, name, tag, owner, clock, "m3745x", source), + m_program_config("program", ENDIANNESS_LITTLE, 8, 16, 0, internal_map), + read_p3(*this), + read_p4(*this), + read_p5(*this), + read_p6(*this), + write_p3(*this), + write_p4(*this), + write_p5(*this), + write_p6(*this), + read_ad_0(*this), + read_ad_1(*this), + read_ad_2(*this), + read_ad_3(*this), + read_ad_4(*this), + read_ad_5(*this), + read_ad_6(*this), + read_ad_7(*this) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void m3745x_device::device_start() +{ + read_p3.resolve_safe(0); + read_p4.resolve_safe(0); + read_p5.resolve_safe(0); + read_p6.resolve_safe(0); + write_p3.resolve_safe(); + write_p4.resolve_safe(); + write_p5.resolve_safe(); + write_p6.resolve_safe(); + read_ad_0.resolve_safe(0); + read_ad_1.resolve_safe(0); + read_ad_2.resolve_safe(0); + read_ad_3.resolve_safe(0); + read_ad_4.resolve_safe(0); + read_ad_5.resolve_safe(0); + read_ad_6.resolve_safe(0); + read_ad_7.resolve_safe(0); + + for (int i = 0; i < NUM_TIMERS; i++) + { + m_timers[i] = timer_alloc(i, NULL); + } + + m740_device::device_start(); + + save_item(NAME(m_ports)); + save_item(NAME(m_ddrs)); + save_item(NAME(m_intreq1)); + save_item(NAME(m_intreq2)); + save_item(NAME(m_intctrl1)); + save_item(NAME(m_intctrl2)); + save_item(NAME(m_adctrl)); + save_item(NAME(m_last_all_ints)); + + // all ports reset to input on startup + memset(m_ddrs, 0, sizeof(m_ddrs)); + memset(m_ports, 0, sizeof(m_ports)); + m_intreq1 = m_intreq2 = m_intctrl1 = m_intctrl2 = 0; + m_adctrl = 0; + m_last_all_ints = 0; +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void m3745x_device::device_reset() +{ + m740_device::device_reset(); + + SP = 0x01ff; // we have the "traditional" stack in page 1, not 0 like some M740 derivatives + + for (int i = 0; i < NUM_TIMERS; i++) + { + m_timers[i]->adjust(attotime::never); + } + + // all ports reset to input on startup + memset(m_ddrs, 0, sizeof(m_ddrs)); + memset(m_ports, 0, sizeof(m_ports)); + m_intreq1 = m_intreq2 = m_intctrl1 = m_intctrl2 = 0; + m_adctrl = 0; + m_last_all_ints = 0; +} + +void m3745x_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch (id) + { + case TIMER_ADC: + m_timers[TIMER_ADC]->adjust(attotime::never); + + m_adctrl |= ADCTRL_COMPLETE; + m_intreq2 |= IRQ2_ADC; + recalc_irqs(); + break; + + default: + printf("M3775x: unknown timer expire %d\n", id); + break; + } +} + +void m3745x_device::execute_set_input(int inputnum, int state) +{ + switch (inputnum) + { + case M3745X_INT1_LINE: + if (state == ASSERT_LINE) + { + m_intreq1 |= IRQ1_INT1; + } + else + { + m_intreq1 &= ~IRQ1_INT1; + } + break; + + case M3745X_INT2_LINE: + if (state == ASSERT_LINE) + { + m_intreq1 |= IRQ1_INT2; + } + else + { + m_intreq1 &= ~IRQ1_INT2; + } + break; + + case M3745X_INT3_LINE: + if (state == ASSERT_LINE) + { + m_intreq1 |= IRQ1_INT3; + } + else + { + m_intreq1 &= ~IRQ1_INT3; + } + break; + + case M3745X_SET_OVERFLOW: // the base 740 class can handle this + m740_device::execute_set_input(M740_SET_OVERFLOW, state); + break; + } + + recalc_irqs(); +} + +void m3745x_device::recalc_irqs() +{ + UINT16 all_ints = 0; + int static const irq_lines[16] = + { + -1, -1, -1, M740_INT11_LINE, M740_INT12_LINE, M740_INT13_LINE, -1, -1, + -1, -1, M740_INT2_LINE, M740_INT3_LINE, M740_INT4_LINE, -1, -1, -1 + }; + + all_ints = (m_intreq1 & m_intctrl1) << 8; + all_ints |= (m_intreq2 & m_intctrl2); + +// printf("recalc_irqs: last_all_ints = %04x last_ints = %04x (req1 %02x ctrl1 %02x req2 %02x ctrl2 %02x)\n", all_ints, m_last_all_ints, m_intreq1, m_intctrl1, m_intreq2, m_intctrl2); + + // check all 16 IRQ bits for changes + for (int i = 0; i < 16; i++) + { + // if bit is set now + if (all_ints & (1 << i)) + { + // and wasn't last time + if (!(m_last_all_ints & (1 << i))) + { +// printf(" asserting irq %d (%d)\n", i, irq_lines[i]); + if (irq_lines[i] != -1) + { + m740_device::execute_set_input(irq_lines[i], ASSERT_LINE); + } + } + } + else // bit is clear now + { + // ...and wasn't clear last time + if (m_last_all_ints & (1 << i)) + { +// printf(" clearing irq %d (%d)\n", i, irq_lines[i]); + if (irq_lines[i] != -1) + { + m740_device::execute_set_input(irq_lines[i], CLEAR_LINE); + } + } + } + } + + m_last_all_ints = all_ints; +} + +void m3745x_device::send_port(address_space &space, UINT8 offset, UINT8 data) +{ + switch (offset) + { + case 0: + write_p3(data); + break; + + case 1: + write_p4(data); + break; + + case 2: + write_p5(data); + break; + + case 3: + write_p6(data); + break; + } +} + +UINT8 m3745x_device::read_port(UINT8 offset) +{ + UINT8 incoming = 0; + + switch (offset) + { + case 0: + incoming = read_p3(); + break; + + case 1: + incoming = read_p4(); + break; + + case 2: + incoming = read_p5(); + break; + + case 3: + incoming = read_p6(); + break; + } + + // apply data direction registers + incoming &= (m_ddrs[offset] ^ 0xff); + // OR in ddr-masked version of port writes + incoming |= (m_ports[offset] & m_ddrs[offset]); + + return incoming; +} + +READ8_MEMBER(m3745x_device::ports_r) +{ + switch (offset) + { + case 0: + return read_port(0); + + case 1: + return m_ddrs[0]; + + case 2: + return read_port(1); + + case 4: + return read_port(2); + + case 5: + return m_ddrs[2]; + + case 6: + return read_port(3); + + case 7: + return m_ddrs[3]; + } + + return 0xff; +} + +WRITE8_MEMBER(m3745x_device::ports_w) +{ + switch (offset) + { + case 0: // p3 + send_port(space, 0, data & m_ddrs[0]); + m_ports[0] = data; + break; + + case 1: // p3 ddr + send_port(space, 0, m_ports[0] & data); + m_ddrs[0] = data; + break; + + case 2: // p4 + send_port(space, 1, data & m_ddrs[1]); + m_ports[1] = data; + break; + + case 4: // p5 + send_port(space, 2, data & m_ddrs[2]); + m_ports[2] = data; + break; + + case 5: // p5 ddr + send_port(space, 2, m_ports[2] & data); + m_ddrs[2] = data; + break; + + case 6: // p6 + send_port(space, 3, data & m_ddrs[3]); + m_ports[3] = data; + break; + + case 7: // p6 ddr + send_port(space, 3, m_ports[3] & data); + m_ddrs[3] = data; + break; + } +} + +READ8_MEMBER(m3745x_device::intregs_r) +{ + switch (offset) + { + case 0: + return m_intreq1; + + case 1: + return m_intreq2; + + case 2: + return m_intctrl1; + + case 3: + return m_intctrl2; + } + + // this should never happen + assert(0); + return 0; +} + +WRITE8_MEMBER(m3745x_device::intregs_w) +{ + switch (offset) + { + case 0: + m_intreq1 = data; + break; + + case 1: + m_intreq2 = data; + break; + + case 2: + m_intctrl1 = data; + break; + + case 3: + m_intctrl2 = data; + break; + } + + recalc_irqs(); +} + +READ8_MEMBER(m3745x_device::adc_r) +{ + UINT8 rv = 0; + + switch (offset) + { + case 0: + m_intreq2 &= ~IRQ2_ADC; + recalc_irqs(); + + switch (m_adctrl & 7) + { + case 0: + rv = read_ad_0(); + break; + + case 1: + rv = read_ad_1(); + break; + + case 2: + rv = read_ad_2(); + break; + + case 3: + rv = read_ad_3(); + break; + + case 4: + rv = read_ad_4(); + break; + + case 5: + rv = read_ad_5(); + break; + + case 6: + rv = read_ad_6(); + break; + + case 7: + rv = read_ad_7(); + break; + } + return rv; + + case 1: + return m_adctrl; + } + + return 0; +} + +WRITE8_MEMBER(m3745x_device::adc_w) +{ + switch (offset) + { + case 0: + printf("M3745x: Write %02x to ADC output?!\n", data); + break; + + case 1: + m_adctrl = data; + + // starting a conversion? this takes 50 cycles. + if (!(m_adctrl & ADCTRL_COMPLETE)) + { + double hz = (double)clock() / 50.0; + m_timers[TIMER_ADC]->adjust(attotime::from_hz(hz)); + } + break; + } +} + +/* M37450 - baseline for this familiy */ +static ADDRESS_MAP_START( m37450_map, AS_PROGRAM, 8, m37450_device ) + AM_RANGE(0x0000, 0x00bf) AM_RAM + AM_RANGE(0x00d6, 0x00dd) AM_READWRITE(ports_r, ports_w) + AM_RANGE(0x00e2, 0x00e3) AM_READWRITE(adc_r, adc_w) + AM_RANGE(0x00fc, 0x00ff) AM_READWRITE(intregs_r, intregs_w) + AM_RANGE(0x0100, 0x01ff) AM_RAM +ADDRESS_MAP_END + +m37450_device::m37450_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + m3745x_device(mconfig, M37450, "Mitsubishi M37450", tag, owner, clock, ADDRESS_MAP_NAME(m37450_map), "m3745x", __FILE__) +{ +} + +m37450_device::m37450_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + m3745x_device(mconfig, type, name, tag, owner, clock, ADDRESS_MAP_NAME(m37450_map), shortname, source) +{ +} diff --git a/src/devices/cpu/m6502/m3745x.h b/src/devices/cpu/m6502/m3745x.h new file mode 100644 index 00000000000..d7d24c80880 --- /dev/null +++ b/src/devices/cpu/m6502/m3745x.h @@ -0,0 +1,157 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +#pragma once + +#ifndef __M3745X_H__ +#define __M3745X_H__ + +#include "m740.h" + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_M3745X_ADC14_CALLBACKS(_ad0, _ad1, _ad2, _ad3) \ + downcast(device)->set_ad14_callbacks(DEVCB_##_ad0, DEVCB_##_ad1, DEVCB_##_ad2, DEVCB_##_ad3); + +#define MCFG_M3745X_ADC58_CALLBACKS(_ad0, _ad1, _ad2, _ad3) \ + downcast(device)->set_ad58_callbacks(DEVCB_##_ad0, DEVCB_##_ad1, DEVCB_##_ad2, DEVCB_##_ad3); + +#define MCFG_M3745X_PORT3_CALLBACKS(_read, _write) \ + downcast(device)->set_p3_callbacks(DEVCB_##_read, DEVCB_##_write); + +#define MCFG_M3745X_PORT4_CALLBACKS(_read, _write) \ + downcast(device)->set_p4_callbacks(DEVCB_##_read, DEVCB_##_write); + +#define MCFG_M3745X_PORT5_CALLBACKS(_read, _write) \ + downcast(device)->set_p5_callbacks(DEVCB_##_read, DEVCB_##_write); + +#define MCFG_M3745X_PORT6_CALLBACKS(_read, _write) \ + downcast(device)->set_p6_callbacks(DEVCB_##_read, DEVCB_##_write); + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> m3745x_device + +class m3745x_device : public m740_device +{ + friend class m37450_device; + + enum + { + TIMER_1 = 0, + TIMER_2, + TIMER_3, + + TIMER_ADC, + + NUM_TIMERS + }; + +public: + enum + { + M3745X_INT1_LINE = INPUT_LINE_IRQ0, + M3745X_INT2_LINE, + M3745X_INT3_LINE, + + M3745X_SET_OVERFLOW = M740_SET_OVERFLOW + }; + + // construction/destruction + m3745x_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, address_map_constructor internal_map, const char *shortname, const char *source); + + const address_space_config m_program_config; + + template void set_p3_callbacks(_read rd, _write wr) + { + read_p3.set_callback(rd); + write_p3.set_callback(wr); + } + + template void set_p4_callbacks(_read rd, _write wr) + { + read_p4.set_callback(rd); + write_p4.set_callback(wr); + } + + template void set_p5_callbacks(_read rd, _write wr) + { + read_p5.set_callback(rd); + write_p5.set_callback(wr); + } + + template void set_p6_callbacks(_read rd, _write wr) + { + read_p6.set_callback(rd); + write_p6.set_callback(wr); + } + + template void set_ad14_callbacks(_read rd, _read2 rd2, _read3 rd3, _read4 rd4) + { + read_ad_0.set_callback(rd); + read_ad_1.set_callback(rd2); + read_ad_2.set_callback(rd3); + read_ad_3.set_callback(rd4); + } + + template void set_ad58_callbacks(_read rd, _read2 rd2, _read3 rd3, _read4 rd4) + { + read_ad_4.set_callback(rd); + read_ad_5.set_callback(rd2); + read_ad_6.set_callback(rd3); + read_ad_7.set_callback(rd4); + } + + devcb_read8 read_p3, read_p4, read_p5, read_p6; + devcb_write8 write_p3, write_p4, write_p5, write_p6; + devcb_read8 read_ad_0, read_ad_1, read_ad_2, read_ad_3; + devcb_read8 read_ad_4, read_ad_5, read_ad_6, read_ad_7; + + DECLARE_READ8_MEMBER(ports_r); + DECLARE_WRITE8_MEMBER(ports_w); + DECLARE_READ8_MEMBER(adc_r); + DECLARE_WRITE8_MEMBER(adc_w); + DECLARE_READ8_MEMBER(intregs_r); + DECLARE_WRITE8_MEMBER(intregs_w); + + bool are_port_bits_output(UINT8 port, UINT8 mask) { return ((m_ddrs[port] & mask) == mask) ? true : false; } + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + virtual void execute_set_input(int inputnum, int state); + virtual const address_space_config *memory_space_config(address_spacenum spacenum) const { return (spacenum == AS_PROGRAM) ? &m_program_config : NULL; } + + void send_port(address_space &space, UINT8 offset, UINT8 data); + UINT8 read_port(UINT8 offset); + + void recalc_irqs(); + + UINT8 m_ports[6], m_ddrs[6]; + UINT8 m_intreq1, m_intreq2, m_intctrl1, m_intctrl2; + UINT8 m_adctrl; + UINT16 m_last_all_ints; + +private: + emu_timer *m_timers[NUM_TIMERS]; +}; + +class m37450_device : public m3745x_device +{ +public: + m37450_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + m37450_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + +protected: + +private: +}; + +extern const device_type M37450; + +#endif diff --git a/src/devices/cpu/m6502/m4510.c b/src/devices/cpu/m6502/m4510.c new file mode 100644 index 00000000000..2a7eb10ee1e --- /dev/null +++ b/src/devices/cpu/m6502/m4510.c @@ -0,0 +1,106 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +/*************************************************************************** + + m4510.c + + 65ce02 with a mmu and a cia integrated + +***************************************************************************/ + +#include "emu.h" +#include "m4510.h" + +const device_type M4510 = &device_creator; + +m4510_device::m4510_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + m65ce02_device(mconfig, M4510, "M4510", tag, owner, clock, "m4510", __FILE__) +{ + program_config.m_addrbus_width = 20; + program_config.m_logaddr_width = 16; + program_config.m_page_shift = 13; + sprogram_config.m_addrbus_width = 20; + sprogram_config.m_logaddr_width = 16; + sprogram_config.m_page_shift = 13; +} + +offs_t m4510_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + return disassemble_generic(buffer, pc, oprom, opram, options, disasm_entries); +} + +void m4510_device::device_start() +{ + if(direct_disabled) + mintf = new mi_4510_nd(this); + else + mintf = new mi_4510_normal(this); + + m65ce02_device::init(); + + save_item(NAME(map_offset)); + save_item(NAME(map_enable)); +} + +void m4510_device::device_reset() +{ + map_offset[0] = map_offset[1] = 0; + map_enable = 0; + nomap = true; + + // Wild guess, this setting makes the cpu start executing some code in the c65 driver + //map_offset[1] = 0x2e000; + //map_enable = 0x80; + m65ce02_device::device_reset(); +} + +bool m4510_device::memory_translate(address_spacenum spacenum, int intention, offs_t &address) +{ + if (spacenum == AS_PROGRAM) + { + address = map(address); + } + + return true; +} + +m4510_device::mi_4510_normal::mi_4510_normal(m4510_device *_base) +{ + base = _base; +} + +UINT8 m4510_device::mi_4510_normal::read(UINT16 adr) +{ + return program->read_byte(base->map(adr)); +} + +UINT8 m4510_device::mi_4510_normal::read_sync(UINT16 adr) +{ + return sdirect->read_byte(base->map(adr)); +} + +UINT8 m4510_device::mi_4510_normal::read_arg(UINT16 adr) +{ + return direct->read_byte(base->map(adr)); +} + +void m4510_device::mi_4510_normal::write(UINT16 adr, UINT8 val) +{ + program->write_byte(base->map(adr), val); +} + +m4510_device::mi_4510_nd::mi_4510_nd(m4510_device *_base) : mi_4510_normal(_base) +{ +} + +UINT8 m4510_device::mi_4510_nd::read_sync(UINT16 adr) +{ + return sprogram->read_byte(base->map(adr)); +} + +UINT8 m4510_device::mi_4510_nd::read_arg(UINT16 adr) +{ + return program->read_byte(base->map(adr)); +} + +#include "cpu/m6502/m4510.inc" diff --git a/src/devices/cpu/m6502/m4510.h b/src/devices/cpu/m6502/m4510.h new file mode 100644 index 00000000000..492572fddb6 --- /dev/null +++ b/src/devices/cpu/m6502/m4510.h @@ -0,0 +1,82 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +/*************************************************************************** + + m4510.h + + 65ce02 with a mmu and a port + +***************************************************************************/ + +#ifndef __M4510_H__ +#define __M4510_H__ + +#include "m65ce02.h" + +class m4510_device : public m65ce02_device { +public: + m4510_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + static const disasm_entry disasm_entries[0x100]; + + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + virtual void do_exec_full(); + virtual void do_exec_partial(); + + bool get_nomap() const { return nomap; } + +protected: + UINT32 map_offset[2]; + UINT8 map_enable; + bool nomap; + + class mi_4510_normal : public memory_interface { + public: + m4510_device *base; + + mi_4510_normal(m4510_device *base); + virtual ~mi_4510_normal() {} + virtual UINT8 read(UINT16 adr); + virtual UINT8 read_sync(UINT16 adr); + virtual UINT8 read_arg(UINT16 adr); + virtual void write(UINT16 adr, UINT8 val); + }; + + class mi_4510_nd : public mi_4510_normal { + public: + mi_4510_nd(m4510_device *base); + virtual ~mi_4510_nd() {} + virtual UINT8 read_sync(UINT16 adr); + virtual UINT8 read_arg(UINT16 adr); + }; + + virtual void device_start(); + virtual void device_reset(); + virtual bool memory_translate(address_spacenum spacenum, int intention, offs_t &address); + + inline UINT32 map(UINT16 adr) { + if(map_enable & (1 << (adr >> 13))) { + nomap = false; + return adr + map_offset[adr >> 15]; + } + nomap = true; + return adr; + } + +#define O(o) void o ## _full(); void o ## _partial() + + // 4510 opcodes + O(eom_imp); + O(map_imp); + +#undef O +}; + +enum { + M4510_IRQ_LINE = m6502_device::IRQ_LINE, + M4510_NMI_LINE = m6502_device::NMI_LINE +}; + +extern const device_type M4510; + +#endif diff --git a/src/devices/cpu/m6502/m5074x.c b/src/devices/cpu/m6502/m5074x.c new file mode 100644 index 00000000000..dc499b912c0 --- /dev/null +++ b/src/devices/cpu/m6502/m5074x.c @@ -0,0 +1,507 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont, Olivier Galibert +/* + Mitsubishi M5074x 8-bit microcontroller family +*/ + +#include "emu.h" +#include "m5074x.h" + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define IRQ_CNTRREQ (0x80) +#define IRQ_CNTRENA (0x40) +#define IRQ_TMR1REQ (0x20) +#define IRQ_TMR1ENA (0x10) +#define IRQ_TMR2REQ (0x08) +#define IRQ_TMR2ENA (0x04) +#define IRQ_INTREQ (0x02) +#define IRQ_INTENA (0x01) + +#define TMRC_TMRXREQ (0x80) +#define TMRC_TMRXENA (0x40) +#define TMRC_TMRXHLT (0x20) +#define TMRC_TMRXMDE (0x0c) + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type M50740 = &device_creator; +const device_type M50741 = &device_creator; + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// m5074x_device - constructor +//------------------------------------------------- +m5074x_device::m5074x_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, address_map_constructor internal_map, const char *shortname, const char *source) : + m740_device(mconfig, type, name, tag, owner, clock, shortname, source), + m_program_config("program", ENDIANNESS_LITTLE, 8, 13, 0, internal_map), + read_p0(*this), + read_p1(*this), + read_p2(*this), + read_p3(*this), + write_p0(*this), + write_p1(*this), + write_p2(*this), + write_p3(*this) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void m5074x_device::device_start() +{ + read_p0.resolve_safe(0); + read_p1.resolve_safe(0); + read_p2.resolve_safe(0); + read_p3.resolve_safe(0); + write_p0.resolve_safe(); + write_p1.resolve_safe(); + write_p2.resolve_safe(); + write_p3.resolve_safe(); + + for (int i = 0; i < NUM_TIMERS; i++) + { + m_timers[i] = timer_alloc(i, NULL); + } + + m740_device::device_start(); + + save_item(NAME(m_ports)); + save_item(NAME(m_ddrs)); + save_item(NAME(m_intctrl)); + save_item(NAME(m_tmrctrl)); + save_item(NAME(m_tmr12pre)); + save_item(NAME(m_tmr1)); + save_item(NAME(m_tmr2)); + save_item(NAME(m_tmrxpre)); + save_item(NAME(m_tmrx)); + save_item(NAME(m_tmr1latch)); + save_item(NAME(m_tmr2latch)); + save_item(NAME(m_tmrxlatch)); + save_item(NAME(m_last_all_ints)); + + memset(m_ports, 0, sizeof(m_ports)); + memset(m_ddrs, 0, sizeof(m_ddrs)); + m_intctrl = m_tmrctrl = 0; + m_tmr12pre = m_tmrxpre = 0; + m_tmr1 = m_tmr2 = m_tmrx = 0; + m_last_all_ints = 0; +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void m5074x_device::device_reset() +{ + m740_device::device_reset(); + + // all ports reset to input on startup + memset(m_ports, 0, sizeof(m_ports)); + memset(m_ddrs, 0, sizeof(m_ddrs)); + m_intctrl = m_tmrctrl = 0; + m_tmr12pre = m_tmrxpre = 0; + m_tmr1 = m_tmr2 = m_tmrx = 0; +} + +void m5074x_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch (id) + { + case TIMER_1: + m_tmr1--; + + if (m_tmr1 <= 0) + { + m_intctrl |= IRQ_TMR1REQ; + m_tmr1 = m_tmr1latch; + recalc_irqs(); + } + break; + + case TIMER_2: + m_tmr2--; + + if (m_tmr2 <= 0) + { + m_intctrl |= IRQ_TMR2REQ; + m_tmr2 = m_tmr2latch; + recalc_irqs(); + } + break; + + case TIMER_X: + m_tmrx--; + + if (m_tmrx <= 0) + { + m_tmrctrl |= TMRC_TMRXREQ; + m_tmrx = m_tmrxlatch; + recalc_irqs(); + } + break; + } +} + +void m5074x_device::execute_set_input(int inputnum, int state) +{ + switch (inputnum) + { + case M5074X_INT1_LINE: + if (state == ASSERT_LINE) + { + m_intctrl |= IRQ_INTREQ; + } + else + { + m_intctrl &= ~IRQ_INTREQ; + } + break; + + case M5074X_SET_OVERFLOW: // the base 740 class can handle this + m740_device::execute_set_input(M740_SET_OVERFLOW, state); + break; + } + + recalc_irqs(); +} + +void m5074x_device::recalc_irqs() +{ + UINT8 all_ints = 0; + + if ((m_intctrl & (IRQ_CNTRREQ|IRQ_CNTRENA)) == (IRQ_CNTRREQ|IRQ_CNTRENA)) + { + all_ints |= 0x01; + } + if ((m_tmrctrl & (TMRC_TMRXREQ|TMRC_TMRXENA)) == (TMRC_TMRXREQ|TMRC_TMRXENA)) + { + all_ints |= 0x02; + } + if ((m_intctrl & (IRQ_TMR1REQ|IRQ_TMR1ENA)) == (IRQ_TMR1REQ|IRQ_TMR1ENA)) + { + all_ints |= 0x04; + } + if ((m_intctrl & (IRQ_TMR2REQ|IRQ_TMR2ENA)) == (IRQ_TMR2REQ|IRQ_TMR2ENA)) + { + all_ints |= 0x08; + } + if ((m_intctrl & (IRQ_INTREQ|IRQ_INTENA)) == (IRQ_INTREQ|IRQ_INTENA)) + { + all_ints |= 0x10; + } + + // check all 5 IRQ bits for changes + for (int i = 0; i < 5; i++) + { + // if bit is set now + if (all_ints & (1 << i)) + { + // and wasn't last time + if (!(m_last_all_ints & (1 << i))) + { + m740_device::execute_set_input(M740_INT0_LINE + i, ASSERT_LINE); + } + } + else // bit is clear now + { + // ...and wasn't clear last time + if (m_last_all_ints & (1 << i)) + { + m740_device::execute_set_input(M740_INT0_LINE + i, CLEAR_LINE); + } + } + } + + m_last_all_ints = all_ints; +} + +void m5074x_device::recalc_timer(int timer) +{ + int hz; + + switch (timer) + { + case 0: + hz = clock() / 16; + hz /= (m_tmr12pre + 2); + m_timers[TIMER_1]->adjust(attotime::from_hz(hz), 0, attotime::from_hz(hz)); + break; + + case 1: + hz = clock() / 16; + hz /= (m_tmr12pre + 2); + m_timers[TIMER_2]->adjust(attotime::from_hz(hz), 0, attotime::from_hz(hz)); + break; + + case 2: + // Timer X modes: 00 = free run countdown, 01 = invert CNTR pin each time expires, + // 10 = count each time CNTR pin inverts, 11 = count when CNTR pin low + if ((m_tmrctrl & TMRC_TMRXMDE) == 0) + { + // stop bit? + if (m_tmrctrl & TMRC_TMRXHLT) + { + m_timers[TIMER_X]->adjust(attotime::never, 0, attotime::never); + } + else + { + hz = clock() / 16; + hz /= (m_tmrxpre + 2); + m_timers[TIMER_X]->adjust(attotime::from_hz(hz), 0, attotime::from_hz(hz)); + } + } + else + { + fatalerror("M5074x: Unhandled timer X mode %d\n", (m_tmrctrl&TMRC_TMRXMDE)>>2); + } + break; + } +} + +void m5074x_device::send_port(address_space &space, UINT8 offset, UINT8 data) +{ + switch (offset) + { + case 0: + write_p0(data); + break; + + case 1: + write_p1(data); + break; + + case 2: + write_p2(data); + break; + + case 3: + write_p3(data); + break; + } +} + +UINT8 m5074x_device::read_port(UINT8 offset) +{ + UINT8 incoming = 0; + + switch (offset) + { + case 0: + incoming = read_p0(); + break; + + case 1: + incoming = read_p1(); + break; + + case 2: + incoming = read_p2(); + break; + + case 3: + incoming = read_p3(); + break; + } + + // apply data direction registers + incoming &= (m_ddrs[offset] ^ 0xff); + // OR in ddr-masked version of port writes + incoming |= (m_ports[offset] & m_ddrs[offset]); + + return incoming; +} + +READ8_MEMBER(m5074x_device::ports_r) +{ + switch (offset) + { + case 0: + return read_port(0); + + case 1: + return m_ddrs[0]; + + case 2: + return read_port(1); + + case 3: + return m_ddrs[1]; + + case 4: + return read_port(2); + + case 5: + return m_ddrs[2]; + + case 8: + return read_port(3); + + case 9: + return m_ddrs[3]; + } + + return 0xff; +} + +WRITE8_MEMBER(m5074x_device::ports_w) +{ + switch (offset) + { + case 0: // p0 + send_port(space, 0, data & m_ddrs[0]); + m_ports[0] = data; + break; + + case 1: // p0 ddr + send_port(space, 0, m_ports[0] & data); + m_ddrs[0] = data; + break; + + case 2: // p1 + send_port(space, 1, data & m_ddrs[1]); + m_ports[1] = data; + break; + + case 3: // p1 ddr + send_port(space, 1, m_ports[1] & data); + m_ddrs[1] = data; + break; + + case 4: // p2 + send_port(space, 2, data & m_ddrs[2]); + m_ports[2] = data; + break; + + case 5: // p2 ddr + send_port(space, 2, m_ports[2] & data); + m_ddrs[2] = data; + break; + + case 8: // p3 + send_port(space, 3, data & m_ddrs[3]); + m_ports[3] = data; + break; + + case 9: // p3 ddr + send_port(space, 3, m_ports[3] & data); + m_ddrs[3] = data; + break; + } +} + +READ8_MEMBER(m5074x_device::tmrirq_r) +{ + switch (offset) + { + case 0: + return m_tmr12pre; + + case 1: + return m_tmr1; + + case 2: + return m_tmr2; + + case 3: + return m_tmrxpre; + + case 4: + return m_tmrx; + + case 5: + return m_intctrl; + + case 6: + return m_tmrctrl; + } + + return 0xff; +} + +WRITE8_MEMBER(m5074x_device::tmrirq_w) +{ +// printf("%02x to tmrirq @ %d\n", data, offset); + + switch (offset) + { + case 0: + m_tmr12pre = data; + recalc_timer(0); + recalc_timer(1); + break; + + case 1: + m_tmr1 = m_tmr1latch = data; + break; + + case 2: + m_tmr2 = m_tmr2latch = data; + break; + + case 3: + m_tmrxpre = m_tmrxlatch = data; + recalc_timer(2); + break; + + case 4: + m_tmrx = data; + break; + + case 5: + m_intctrl = data; + recalc_irqs(); + break; + + case 6: + m_tmrctrl = data; + recalc_irqs(); + break; + } +} + +/* M50740 - baseline for this familiy */ +static ADDRESS_MAP_START( m50740_map, AS_PROGRAM, 8, m50740_device ) + AM_RANGE(0x0000, 0x005f) AM_RAM + AM_RANGE(0x00e0, 0x00e9) AM_READWRITE(ports_r, ports_w) + AM_RANGE(0x00f9, 0x00ff) AM_READWRITE(tmrirq_r, tmrirq_w) + AM_RANGE(0x1400, 0x1fff) AM_ROM AM_REGION(M5074X_INTERNAL_ROM_REGION, 0) +ADDRESS_MAP_END + +m50740_device::m50740_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + m5074x_device(mconfig, M50740, "Mitsubishi M50740", tag, owner, clock, ADDRESS_MAP_NAME(m50740_map), "m50740", __FILE__) +{ +} + +m50740_device::m50740_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + m5074x_device(mconfig, type, name, tag, owner, clock, ADDRESS_MAP_NAME(m50740_map), shortname, source) +{ +} + +/* M50741 - 50740 with a larger internal ROM */ +static ADDRESS_MAP_START( m50741_map, AS_PROGRAM, 8, m50741_device ) + AM_RANGE(0x0000, 0x005f) AM_RAM + AM_RANGE(0x00e0, 0x00e9) AM_READWRITE(ports_r, ports_w) + AM_RANGE(0x00f9, 0x00ff) AM_READWRITE(tmrirq_r, tmrirq_w) + AM_RANGE(0x1000, 0x1fff) AM_ROM AM_REGION("internal", 0) +ADDRESS_MAP_END + +m50741_device::m50741_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + m5074x_device(mconfig, M50740, "Mitsubishi M50741", tag, owner, clock, ADDRESS_MAP_NAME(m50741_map), "m50741", __FILE__) +{ +} + +m50741_device::m50741_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + m5074x_device(mconfig, type, name, tag, owner, clock, ADDRESS_MAP_NAME(m50741_map), shortname, source) +{ +} diff --git a/src/devices/cpu/m6502/m5074x.h b/src/devices/cpu/m6502/m5074x.h new file mode 100644 index 00000000000..10f0aa06df5 --- /dev/null +++ b/src/devices/cpu/m6502/m5074x.h @@ -0,0 +1,147 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +#pragma once + +#ifndef __M5074X_H__ +#define __M5074X_H__ + +#include "m740.h" + +//************************************************************************** +// CONSTANTS +//************************************************************************** + +// internal ROM region +#define M5074X_INTERNAL_ROM_REGION "internal" +#define M5074X_INTERNAL_ROM(_tag) (_tag ":" M5074X_INTERNAL_ROM_REGION) + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_M5074X_PORT0_READ_CALLBACK(_read) \ + devcb = &m5074x_device::set_p0_rd_callback(*device, DEVCB_##_read); + +#define MCFG_M5074X_PORT1_READ_CALLBACK(_read) \ + devcb = &m5074x_device::set_p1_rd_callback(*device, DEVCB_##_read); + +#define MCFG_M5074X_PORT2_READ_CALLBACK(_read) \ + devcb = &m5074x_device::set_p2_rd_callback(*device, DEVCB_##_read); + +#define MCFG_M5074X_PORT3_READ_CALLBACK(_read) \ + devcb = &m5074x_device::set_p3_rd_callback(*device, DEVCB_##_read); + +#define MCFG_M5074X_PORT0_WRITE_CALLBACK(_write) \ + devcb = &m5074x_device::set_p0_wr_callback(*device, DEVCB_##_write); + +#define MCFG_M5074X_PORT1_WRITE_CALLBACK(_write) \ + devcb = &m5074x_device::set_p1_wr_callback(*device, DEVCB_##_write); + +#define MCFG_M5074X_PORT2_WRITE_CALLBACK(_write) \ + devcb = &m5074x_device::set_p2_wr_callback(*device, DEVCB_##_write); + +#define MCFG_M5074X_PORT3_WRITE_CALLBACK(_write) \ + devcb = &m5074x_device::set_p3_wr_callback(*device, DEVCB_##_write); + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> m5074x_device + +class m5074x_device : public m740_device +{ + friend class m50740_device; + friend class m50741_device; + + enum + { + M5074X_INT1_LINE = INPUT_LINE_IRQ0, + + M5074X_SET_OVERFLOW = M740_SET_OVERFLOW + }; + + enum + { + TIMER_1 = 0, + TIMER_2, + TIMER_X, + + NUM_TIMERS + }; + +public: + // construction/destruction + m5074x_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, address_map_constructor internal_map, const char *shortname, const char *source); + + const address_space_config m_program_config; + + template static devcb_base &set_p0_rd_callback(device_t &device, _Object object) { return downcast(device).read_p0.set_callback(object); } + template static devcb_base &set_p1_rd_callback(device_t &device, _Object object) { return downcast(device).read_p1.set_callback(object); } + template static devcb_base &set_p2_rd_callback(device_t &device, _Object object) { return downcast(device).read_p2.set_callback(object); } + template static devcb_base &set_p3_rd_callback(device_t &device, _Object object) { return downcast(device).read_p3.set_callback(object); } + template static devcb_base &set_p0_wr_callback(device_t &device, _Object object) { return downcast(device).write_p0.set_callback(object); } + template static devcb_base &set_p1_wr_callback(device_t &device, _Object object) { return downcast(device).write_p1.set_callback(object); } + template static devcb_base &set_p2_wr_callback(device_t &device, _Object object) { return downcast(device).write_p2.set_callback(object); } + template static devcb_base &set_p3_wr_callback(device_t &device, _Object object) { return downcast(device).write_p3.set_callback(object); } + + devcb_read8 read_p0, read_p1, read_p2, read_p3; + devcb_write8 write_p0, write_p1, write_p2, write_p3; + + DECLARE_READ8_MEMBER(ports_r); + DECLARE_WRITE8_MEMBER(ports_w); + DECLARE_READ8_MEMBER(tmrirq_r); + DECLARE_WRITE8_MEMBER(tmrirq_w); + + bool are_port_bits_output(UINT8 port, UINT8 mask) { return ((m_ddrs[port] & mask) == mask) ? true : false; } + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + virtual void execute_set_input(int inputnum, int state); + virtual const address_space_config *memory_space_config(address_spacenum spacenum) const { return (spacenum == AS_PROGRAM) ? &m_program_config : NULL; } + + void send_port(address_space &space, UINT8 offset, UINT8 data); + UINT8 read_port(UINT8 offset); + + void recalc_irqs(); + void recalc_timer(int timer); + + UINT8 m_ports[6], m_ddrs[6]; + UINT8 m_intctrl, m_tmrctrl; + UINT8 m_tmr12pre, m_tmr1, m_tmr2, m_tmrxpre, m_tmrx; + UINT8 m_tmr1latch, m_tmr2latch, m_tmrxlatch; + UINT8 m_last_all_ints; + +private: + emu_timer *m_timers[NUM_TIMERS]; +}; + +class m50740_device : public m5074x_device +{ +public: + m50740_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + m50740_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + +protected: + +private: +}; + +class m50741_device : public m5074x_device +{ +public: + m50741_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + m50741_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + +protected: + +private: +}; + +extern const device_type M50740; +extern const device_type M50741; + +#endif diff --git a/src/devices/cpu/m6502/m6502.c b/src/devices/cpu/m6502/m6502.c new file mode 100644 index 00000000000..01b2b8f0f98 --- /dev/null +++ b/src/devices/cpu/m6502/m6502.c @@ -0,0 +1,724 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +/*************************************************************************** + + m6502.c + + Mostek 6502, original NMOS variant + +***************************************************************************/ + +#include "emu.h" +#include "debugger.h" +#include "m6502.h" + +const device_type M6502 = &device_creator; + +m6502_device::m6502_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + cpu_device(mconfig, M6502, "M6502", tag, owner, clock, "m6502", __FILE__), + sync_w(*this), + program_config("program", ENDIANNESS_LITTLE, 8, 16), + sprogram_config("decrypted_opcodes", ENDIANNESS_LITTLE, 8, 16) +{ + direct_disabled = false; +} + +m6502_device::m6502_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + cpu_device(mconfig, type, name, tag, owner, clock, shortname, source), + sync_w(*this), + program_config("program", ENDIANNESS_LITTLE, 8, 16), + sprogram_config("decrypted_opcodes", ENDIANNESS_LITTLE, 8, 16) +{ + direct_disabled = false; +} + +void m6502_device::device_start() +{ + if(direct_disabled) + mintf = new mi_default_nd; + else + mintf = new mi_default_normal; + + init(); +} + +void m6502_device::init() +{ + mintf->program = &space(AS_PROGRAM); + mintf->sprogram = has_space(AS_DECRYPTED_OPCODES) ? &space(AS_DECRYPTED_OPCODES) : mintf->program; + + mintf->direct = &mintf->program->direct(); + mintf->sdirect = &mintf->sprogram->direct(); + + sync_w.resolve_safe(); + + state_add(STATE_GENPC, "GENPC", NPC).noshow(); + state_add(STATE_GENPCBASE, "GENPCBASE", PPC).noshow(); + state_add(STATE_GENSP, "GENSP", SP).noshow(); + state_add(STATE_GENFLAGS, "GENFLAGS", P).callimport().formatstr("%6s").noshow(); + state_add(M6502_PC, "PC", NPC).callimport(); + state_add(M6502_A, "A", A); + state_add(M6502_X, "X", X); + state_add(M6502_Y, "Y", Y); + state_add(M6502_P, "P", P).callimport(); + state_add(M6502_S, "SP", SP); + state_add(M6502_IR, "IR", IR); + + save_item(NAME(PC)); + save_item(NAME(NPC)); + save_item(NAME(A)); + save_item(NAME(X)); + save_item(NAME(Y)); + save_item(NAME(P)); + save_item(NAME(SP)); + save_item(NAME(TMP)); + save_item(NAME(TMP2)); + save_item(NAME(IR)); + save_item(NAME(nmi_state)); + save_item(NAME(irq_state)); + save_item(NAME(apu_irq_state)); + save_item(NAME(v_state)); + save_item(NAME(inst_state)); + save_item(NAME(inst_substate)); + save_item(NAME(inst_state_base)); + save_item(NAME(irq_taken)); + save_item(NAME(inhibit_interrupts)); + + m_icountptr = &icount; + + PC = 0x0000; + NPC = 0x0000; + A = 0x00; + X = 0x80; + Y = 0x00; + P = 0x36; + SP = 0x01bd; + TMP = 0x0000; + TMP2 = 0x00; + IR = 0x00; + nmi_state = false; + irq_state = false; + apu_irq_state = false; + irq_taken = false; + v_state = false; + inst_state = STATE_RESET; + inst_substate = 0; + inst_state_base = 0; + sync = false; + inhibit_interrupts = false; +} + +void m6502_device::device_reset() +{ + inst_state = STATE_RESET; + inst_substate = 0; + inst_state_base = 0; + nmi_state = false; + irq_state = false; + apu_irq_state = false; + irq_taken = false; + v_state = false; + sync = false; + sync_w(CLEAR_LINE); + inhibit_interrupts = false; +} + + +UINT32 m6502_device::execute_min_cycles() const +{ + return 1; +} + +UINT32 m6502_device::execute_max_cycles() const +{ + return 10; +} + +UINT32 m6502_device::execute_input_lines() const +{ + return NMI_LINE+1; +} + +void m6502_device::do_adc_d(UINT8 val) +{ + UINT8 c = P & F_C ? 1 : 0; + P &= ~(F_N|F_V|F_Z|F_C); + UINT8 al = (A & 15) + (val & 15) + c; + if(al > 9) + al += 6; + UINT8 ah = (A >> 4) + (val >> 4) + (al > 15); + if(!UINT8(A + val + c)) + P |= F_Z; + else if(ah & 8) + P |= F_N; + if(~(A^val) & (A^(ah << 4)) & 0x80) + P |= F_V; + if(ah > 9) + ah += 6; + if(ah > 15) + P |= F_C; + A = (ah << 4) | (al & 15); +} + +void m6502_device::do_adc_nd(UINT8 val) +{ + UINT16 sum; + sum = A + val + (P & F_C ? 1 : 0); + P &= ~(F_N|F_V|F_Z|F_C); + if(!UINT8(sum)) + P |= F_Z; + else if(INT8(sum) < 0) + P |= F_N; + if(~(A^val) & (A^sum) & 0x80) + P |= F_V; + if(sum & 0xff00) + P |= F_C; + A = sum; +} + +void m6502_device::do_adc(UINT8 val) +{ + if(P & F_D) + do_adc_d(val); + else + do_adc_nd(val); +} + +void m6502_device::do_arr_nd() +{ + bool c = P & F_C; + P &= ~(F_N|F_Z|F_C|F_V); + A >>= 1; + if(c) + A |= 0x80; + if(!A) + P |= F_Z; + else if(INT8(A)<0) + P |= F_N; + if(A & 0x40) + P |= F_V|F_C; + if(A & 0x20) + P ^= F_V; +} + +void m6502_device::do_arr_d() +{ + // The adc/ror interaction gives an extremely weird result + bool c = P & F_C; + P &= ~(F_N|F_Z|F_C|F_V); + UINT8 a = A >> 1; + if(c) + a |= 0x80; + if(!a) + P |= F_Z; + else if(INT8(a) < 0) + P |= F_N; + if((a ^ A) & 0x40) + P |= F_V; + + if((A & 0x0f) >= 0x05) + a = ((a + 6) & 0x0f) | (a & 0xf0); + + if((A & 0xf0) >= 0x50) { + a += 0x60; + P |= F_C; + } + A = a; +} + +void m6502_device::do_arr() +{ + if(P & F_D) + do_arr_d(); + else + do_arr_nd(); +} + +void m6502_device::do_cmp(UINT8 val1, UINT8 val2) +{ + P &= ~(F_N|F_Z|F_C); + UINT16 r = val1-val2; + if(!r) + P |= F_Z; + else if(INT8(r) < 0) + P |= F_N; + if(!(r & 0xff00)) + P |= F_C; +} + +void m6502_device::do_sbc_d(UINT8 val) +{ + UINT8 c = P & F_C ? 0 : 1; + P &= ~(F_N|F_V|F_Z|F_C); + UINT16 diff = A - val - c; + UINT8 al = (A & 15) - (val & 15) - c; + if(INT8(al) < 0) + al -= 6; + UINT8 ah = (A >> 4) - (val >> 4) - (INT8(al) < 0); + if(!UINT8(diff)) + P |= F_Z; + else if(diff & 0x80) + P |= F_N; + if((A^val) & (A^diff) & 0x80) + P |= F_V; + if(!(diff & 0xff00)) + P |= F_C; + if(INT8(ah) < 0) + ah -= 6; + A = (ah << 4) | (al & 15); +} + +void m6502_device::do_sbc_nd(UINT8 val) +{ + UINT16 diff = A - val - (P & F_C ? 0 : 1); + P &= ~(F_N|F_V|F_Z|F_C); + if(!UINT8(diff)) + P |= F_Z; + else if(INT8(diff) < 0) + P |= F_N; + if((A^val) & (A^diff) & 0x80) + P |= F_V; + if(!(diff & 0xff00)) + P |= F_C; + A = diff; +} + +void m6502_device::do_sbc(UINT8 val) +{ + if(P & F_D) + do_sbc_d(val); + else + do_sbc_nd(val); +} + +void m6502_device::do_bit(UINT8 val) +{ + P &= ~(F_N|F_Z|F_V); + UINT8 r = A & val; + if(!r) + P |= F_Z; + if(val & 0x80) + P |= F_N; + if(val & 0x40) + P |= F_V; +} + +UINT8 m6502_device::do_asl(UINT8 v) +{ + P &= ~(F_N|F_Z|F_C); + UINT8 r = v<<1; + if(!r) + P |= F_Z; + else if(INT8(r) < 0) + P |= F_N; + if(v & 0x80) + P |= F_C; + return r; +} + +UINT8 m6502_device::do_lsr(UINT8 v) +{ + P &= ~(F_N|F_Z|F_C); + if(v & 1) + P |= F_C; + v >>= 1; + if(!v) + P |= F_Z; + return v; +} + +UINT8 m6502_device::do_ror(UINT8 v) +{ + bool c = P & F_C; + P &= ~(F_N|F_Z|F_C); + if(v & 1) + P |= F_C; + v >>= 1; + if(c) + v |= 0x80; + if(!v) + P |= F_Z; + else if(INT8(v)<0) + P |= F_N; + return v; +} + +UINT8 m6502_device::do_rol(UINT8 v) +{ + bool c = P & F_C; + P &= ~(F_N|F_Z|F_C); + if(v & 0x80) + P |= F_C; + v <<= 1; + if(c) + v |= 0x01; + if(!v) + P |= F_Z; + else if(INT8(v)<0) + P |= F_N; + return v; +} + +UINT8 m6502_device::do_asr(UINT8 v) +{ + P &= ~(F_N|F_Z|F_C); + if(v & 1) + P |= F_C; + v >>= 1; + if(!v) + P |= F_Z; + else if(v & 0x40) { + P |= F_N; + v |= 0x80; + } + return v; +} + +void m6502_device::execute_run() +{ + if(inst_substate) + do_exec_partial(); + + while(icount > 0) { + if(inst_state < 0xff00) { + PPC = NPC; + inst_state = IR | inst_state_base; + if(machine().debug_flags & DEBUG_FLAG_ENABLED) + debugger_instruction_hook(this, NPC); + } + do_exec_full(); + } +} + +void m6502_device::execute_set_input(int inputnum, int state) +{ + switch(inputnum) { + case IRQ_LINE: irq_state = state == ASSERT_LINE; break; + case APU_IRQ_LINE: apu_irq_state = state == ASSERT_LINE; break; + case NMI_LINE: nmi_state = nmi_state || (state == ASSERT_LINE); break; + case V_LINE: + if(!v_state && state == ASSERT_LINE) + P |= F_V; + v_state = state == ASSERT_LINE; + break; + } +} + + +const address_space_config *m6502_device::memory_space_config(address_spacenum spacenum) const +{ + switch(spacenum) + { + case AS_PROGRAM: return &program_config; + case AS_DECRYPTED_OPCODES: return has_configured_map(AS_DECRYPTED_OPCODES) ? &sprogram_config : NULL; + default: return NULL; + } +} + + +void m6502_device::state_import(const device_state_entry &entry) +{ + switch(entry.index()) { + case STATE_GENFLAGS: + case M6502_P: + P = P | (F_B|F_E); + break; + case M6502_PC: + PC = NPC; + irq_taken = false; + prefetch(); + PPC = NPC; + inst_state = IR | inst_state_base; + break; + } +} + +void m6502_device::state_export(const device_state_entry &entry) +{ +} + +void m6502_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + switch(entry.index()) { + case STATE_GENFLAGS: + case M6502_P: + strprintf(str, "%c%c%c%c%c%c", + P & F_N ? 'N' : '.', + P & F_V ? 'V' : '.', + P & F_D ? 'D' : '.', + P & F_I ? 'I' : '.', + P & F_Z ? 'Z' : '.', + P & F_C ? 'C' : '.'); + break; + } +} + + +UINT32 m6502_device::disasm_min_opcode_bytes() const +{ + return 1; +} + +UINT32 m6502_device::disasm_max_opcode_bytes() const +{ + return 4; +} + +offs_t m6502_device::disassemble_generic(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options, const disasm_entry *table) +{ + const disasm_entry &e = table[oprom[0] | inst_state_base]; + UINT32 flags = e.flags | DASMFLAG_SUPPORTED; + buffer += sprintf(buffer, "%s", e.opcode); + + switch(e.mode) { + case DASM_non: + flags |= 1; + break; + + case DASM_aba: + sprintf(buffer, " $%02x%02x", opram[2], opram[1]); + flags |= 3; + break; + + case DASM_abx: + sprintf(buffer, " $%02x%02x, x", opram[2], opram[1]); + flags |= 3; + break; + + case DASM_aby: + sprintf(buffer, " $%02x%02x, y", opram[2], opram[1]); + flags |= 3; + break; + + case DASM_acc: + sprintf(buffer, " a"); + flags |= 1; + break; + + case DASM_adr: + sprintf(buffer, " $%02x%02x", opram[2], opram[1]); + flags |= 3; + break; + + case DASM_bzp: + sprintf(buffer, "%d $%02x", (oprom[0] >> 4) & 7, opram[1]); + flags |= 2; + break; + + case DASM_iax: + sprintf(buffer, " ($%02x%02x, x)", opram[2], opram[1]); + flags |= 3; + break; + + case DASM_idx: + sprintf(buffer, " ($%02x, x)", opram[1]); + flags |= 2; + break; + + case DASM_idy: + sprintf(buffer, " ($%02x), y", opram[1]); + flags |= 2; + break; + + case DASM_idz: + sprintf(buffer, " ($%02x), z", opram[1]); + flags |= 2; + break; + + case DASM_imm: + sprintf(buffer, " #$%02x", opram[1]); + flags |= 2; + break; + + case DASM_imp: + flags |= 1; + break; + + case DASM_ind: + sprintf(buffer, " ($%02x%02x)", opram[2], opram[1]); + flags |= 3; + break; + + case DASM_isy: + sprintf(buffer, " ($%02x, s), y", opram[1]); + flags |= 2; + break; + + case DASM_iw2: + sprintf(buffer, " #$%02x%02x", opram[2], opram[1]); + flags |= 3; + break; + + case DASM_iw3: + sprintf(buffer, " #$%02x%02x%02x", opram[3], opram[2], opram[1]); + flags |= 4; + break; + + case DASM_rel: + sprintf(buffer, " $%04x", (pc & 0xf0000) | UINT16(pc + 2 + INT8(opram[1]))); + flags |= 2; + break; + + case DASM_rw2: + sprintf(buffer, " $%04x", (pc & 0xf0000) | UINT16(pc + 2 + INT16((opram[2] << 8) | opram[1]))); + flags |= 3; + break; + + case DASM_zpb: + sprintf(buffer, "%d $%02x, $%04x", (oprom[0] >> 4) & 7, opram[1], (pc & 0xf0000) | UINT16(pc + 3 + INT8(opram[2]))); + flags |= 3; + break; + + case DASM_zpg: + sprintf(buffer, " $%02x", opram[1]); + flags |= 2; + break; + + case DASM_zpi: + sprintf(buffer, " ($%02x)", opram[1]); + flags |= 2; + break; + + case DASM_zpx: + sprintf(buffer, " $%02x, x", opram[1]); + flags |= 2; + break; + + case DASM_zpy: + sprintf(buffer, " $%02x, y", opram[1]); + flags |= 2; + break; + + case DASM_imz: + sprintf(buffer, " #$%02x, $%02x", opram[1], opram[2]); + flags |= 3; + break; + + case DASM_spg: + sprintf(buffer, " \\$%02x", opram[1]); + flags |= 2; + break; + + case DASM_biz: + sprintf(buffer, " %d, $%02x", (opram[0] >> 5) & 7, opram[1]); + flags |= 2; + break; + + case DASM_bzr: + sprintf(buffer, " %d, $%02x, $%04x", (opram[0] >> 5) & 7, opram[1], (pc & 0xf0000) | UINT16(pc + 3 + INT8(opram[2]))); + flags |= 3; + break; + + case DASM_bar: + sprintf(buffer, " %d, a, $%04x", (opram[0] >> 5) & 7, (pc & 0xf0000) | UINT16(pc + 3 + INT8(opram[1]))); + flags |= 2; + break; + + case DASM_bac: + sprintf(buffer, " %d, a", (opram[0] >> 5) & 7); + flags |= 1; + break; + + default: + fprintf(stderr, "Unhandled dasm mode %d\n", e.mode); + abort(); + } + return flags; +} + +void m6502_device::prefetch() +{ + sync = true; + sync_w(ASSERT_LINE); + NPC = PC; + IR = mintf->read_sync(PC); + sync = false; + sync_w(CLEAR_LINE); + + if((nmi_state || ((irq_state || apu_irq_state) && !(P & F_I))) && !inhibit_interrupts) { + irq_taken = true; + IR = 0x00; + } else + PC++; +} + +void m6502_device::prefetch_noirq() +{ + sync = true; + sync_w(ASSERT_LINE); + NPC = PC; + IR = mintf->read_sync(PC); + sync = false; + sync_w(CLEAR_LINE); + PC++; +} + +void m6502_device::set_nz(UINT8 v) +{ + P &= ~(F_Z|F_N); + if(v & 0x80) + P |= F_N; + if(!v) + P |= F_Z; +} + +offs_t m6502_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + return disassemble_generic(buffer, pc, oprom, opram, options, disasm_entries); +} + + +UINT8 m6502_device::memory_interface::read_9(UINT16 adr) +{ + return read(adr); +} + +void m6502_device::memory_interface::write_9(UINT16 adr, UINT8 val) +{ + write(adr, val); +} + + +UINT8 m6502_device::mi_default_normal::read(UINT16 adr) +{ + return program->read_byte(adr); +} + +UINT8 m6502_device::mi_default_normal::read_sync(UINT16 adr) +{ + return sdirect->read_byte(adr); +} + +UINT8 m6502_device::mi_default_normal::read_arg(UINT16 adr) +{ + return direct->read_byte(adr); +} + + +void m6502_device::mi_default_normal::write(UINT16 adr, UINT8 val) +{ + program->write_byte(adr, val); +} + +UINT8 m6502_device::mi_default_nd::read_sync(UINT16 adr) +{ + return sprogram->read_byte(adr); +} + +UINT8 m6502_device::mi_default_nd::read_arg(UINT16 adr) +{ + return program->read_byte(adr); +} + + +WRITE_LINE_MEMBER( m6502_device::irq_line ) +{ + set_input_line( M6502_IRQ_LINE, state ); +} + +WRITE_LINE_MEMBER( m6502_device::nmi_line ) +{ + set_input_line( M6502_NMI_LINE, state ); +} + +#include "cpu/m6502/m6502.inc" diff --git a/src/devices/cpu/m6502/m6502.h b/src/devices/cpu/m6502/m6502.h new file mode 100644 index 00000000000..33b13f3afb6 --- /dev/null +++ b/src/devices/cpu/m6502/m6502.h @@ -0,0 +1,335 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +/*************************************************************************** + + m6502.h + + Mostek 6502, original NMOS variant + +***************************************************************************/ + +#ifndef __M6502FAM_H__ +#define __M6502FAM_H__ + +#define MCFG_M6502_DISABLE_DIRECT() \ + downcast(device)->disable_direct(); + +#define MCFG_M6502_SYNC_CALLBACK(_cb) \ + devcb = &m6502_device::set_sync_callback(*device, DEVCB_##_cb); + +class m6502_device : public cpu_device { +public: + enum { + IRQ_LINE = INPUT_LINE_IRQ0, + APU_IRQ_LINE = INPUT_LINE_IRQ1, + NMI_LINE = INPUT_LINE_NMI, + V_LINE = INPUT_LINE_IRQ0 + 16 + }; + + m6502_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + m6502_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + DECLARE_WRITE_LINE_MEMBER( irq_line ); + DECLARE_WRITE_LINE_MEMBER( nmi_line ); + + bool get_sync() const { return sync; } + void disable_direct() { direct_disabled = true; } + + template static devcb_base &set_sync_callback(device_t &device, _Object object) { return downcast(device).sync_w.set_callback(object); } + + devcb_write_line sync_w; + +protected: + class memory_interface { + public: + address_space *program, *sprogram; + direct_read_data *direct, *sdirect; + + virtual ~memory_interface() {} + virtual UINT8 read(UINT16 adr) = 0; + virtual UINT8 read_9(UINT16 adr); + virtual UINT8 read_sync(UINT16 adr) = 0; + virtual UINT8 read_arg(UINT16 adr) = 0; + virtual void write(UINT16 adr, UINT8 val) = 0; + virtual void write_9(UINT16 adr, UINT8 val); + }; + + class mi_default_normal : public memory_interface { + public: + virtual ~mi_default_normal() {} + virtual UINT8 read(UINT16 adr); + virtual UINT8 read_sync(UINT16 adr); + virtual UINT8 read_arg(UINT16 adr); + virtual void write(UINT16 adr, UINT8 val); + }; + + class mi_default_nd : public mi_default_normal { + public: + virtual ~mi_default_nd() {} + virtual UINT8 read_sync(UINT16 adr); + virtual UINT8 read_arg(UINT16 adr); + }; + + struct disasm_entry { + const char *opcode; + int mode; + offs_t flags; + }; + + enum { + STATE_RESET = 0xff00 + }; + + enum { + DASM_non, /* no additional arguments */ + DASM_aba, /* absolute */ + DASM_abx, /* absolute + X */ + DASM_aby, /* absolute + Y */ + DASM_acc, /* accumulator */ + DASM_adr, /* absolute address (jmp,jsr) */ + DASM_bzp, /* zero page with bit selection */ + DASM_iax, /* indirect + X (65c02 jmp) */ + DASM_idx, /* zero page pre indexed */ + DASM_idy, /* zero page post indexed */ + DASM_idz, /* zero page post indexed (65ce02) */ + DASM_imm, /* immediate */ + DASM_imp, /* implicit */ + DASM_ind, /* indirect (jmp) */ + DASM_isy, /* zero page pre indexed sp and post indexed Y (65ce02) */ + DASM_iw2, /* immediate word (65ce02) */ + DASM_iw3, /* augment (65ce02) */ + DASM_rel, /* relative */ + DASM_rw2, /* relative word (65cs02, 65ce02) */ + DASM_zpb, /* zero page and branch (65c02 bbr, bbs) */ + DASM_zpg, /* zero page */ + DASM_zpi, /* zero page indirect (65c02) */ + DASM_zpx, /* zero page + X */ + DASM_zpy, /* zero page + Y */ + DASM_imz, /* load immediate byte, store to zero page address (M740) */ + DASM_spg, /* "special page": implied FF00 OR immediate value (M740)*/ + DASM_biz, /* bit, zero page (M740) */ + DASM_bzr, /* bit, zero page, relative offset (M740) */ + DASM_bar, /* bit, accumulator, relative offset (M740) */ + DASM_bac /* bit, accumulator (M740) */ + }; + + enum { + F_N = 0x80, + F_V = 0x40, + F_E = 0x20, // 65ce02 + F_T = 0x20, // M740: replaces A with $00,X in some opcodes when set + F_B = 0x10, + F_D = 0x08, + F_I = 0x04, + F_Z = 0x02, + F_C = 0x01 + }; + + virtual void init(); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_execute_interface overrides + virtual UINT32 execute_min_cycles() const; + virtual UINT32 execute_max_cycles() const; + virtual UINT32 execute_input_lines() const; + virtual void execute_run(); + virtual void execute_set_input(int inputnum, int state); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const; + + // device_state_interface overrides + virtual void state_import(const device_state_entry &entry); + virtual void state_export(const device_state_entry &entry); + virtual void state_string_export(const device_state_entry &entry, std::string &str); + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const; + virtual UINT32 disasm_max_opcode_bytes() const; + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + + address_space_config program_config, sprogram_config; + + UINT16 PPC; /* previous program counter */ + UINT16 NPC; /* next start-of-instruction program counter */ + UINT16 PC; /* program counter */ + UINT16 SP; /* stack pointer (always 100 - 1FF) */ + UINT16 TMP; /* temporary internal values */ + UINT8 TMP2; /* another temporary internal value, 8 bits this time */ + UINT8 A; /* Accumulator */ + UINT8 X; /* X index register */ + UINT8 Y; /* Y index register */ + UINT8 P; /* Processor status */ + UINT8 IR; /* Prefetched instruction register */ + int inst_state_base; /* Current instruction bank */ + + memory_interface *mintf; + int inst_state, inst_substate; + int icount; + bool nmi_state, irq_state, apu_irq_state, v_state; + bool irq_taken, sync, direct_disabled, inhibit_interrupts; + + static const disasm_entry disasm_entries[0x100]; + + offs_t disassemble_generic(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options, const disasm_entry *table); + UINT8 read(UINT16 adr) { return mintf->read(adr); } + UINT8 read_9(UINT16 adr) { return mintf->read_9(adr); } + void write(UINT16 adr, UINT8 val) { mintf->write(adr, val); } + void write_9(UINT16 adr, UINT8 val) { mintf->write_9(adr, val); } + UINT8 read_arg(UINT16 adr) { return mintf->read_arg(adr); } + UINT8 read_pc() { return mintf->read_arg(PC++); } + UINT8 read_pc_noinc() { return mintf->read_arg(PC); } + void prefetch(); + void prefetch_noirq(); + void set_nz(UINT8 v); + + virtual void do_exec_full(); + virtual void do_exec_partial(); + + // inline helpers + static inline bool page_changing(UINT16 base, int delta) { return ((base + delta) ^ base) & 0xff00; } + static inline UINT16 set_l(UINT16 base, UINT8 val) { return (base & 0xff00) | val; } + static inline UINT16 set_h(UINT16 base, UINT8 val) { return (base & 0x00ff) | (val << 8); } + + inline void dec_SP() { SP = set_l(SP, SP-1); } + inline void inc_SP() { SP = set_l(SP, SP+1); } + + void do_adc_d(UINT8 val); + void do_adc_nd(UINT8 val); + void do_sbc_d(UINT8 val); + void do_sbc_nd(UINT8 val); + void do_arr_d(); + void do_arr_nd(); + + void do_adc(UINT8 val); + void do_cmp(UINT8 val1, UINT8 val2); + void do_sbc(UINT8 val); + void do_bit(UINT8 val); + void do_arr(); + UINT8 do_asl(UINT8 v); + UINT8 do_lsr(UINT8 v); + UINT8 do_ror(UINT8 v); + UINT8 do_rol(UINT8 v); + UINT8 do_asr(UINT8 v); + +#define O(o) void o ## _full(); void o ## _partial() + + // NMOS 6502 opcodes + // documented opcodes + O(adc_aba); O(adc_abx); O(adc_aby); O(adc_idx); O(adc_idy); O(adc_imm); O(adc_zpg); O(adc_zpx); + O(and_aba); O(and_abx); O(and_aby); O(and_imm); O(and_idx); O(and_idy); O(and_zpg); O(and_zpx); + O(asl_aba); O(asl_abx); O(asl_acc); O(asl_zpg); O(asl_zpx); + O(bcc_rel); + O(bcs_rel); + O(beq_rel); + O(bit_aba); O(bit_zpg); + O(bmi_rel); + O(bne_rel); + O(bpl_rel); + O(brk_imp); + O(bvc_rel); + O(bvs_rel); + O(clc_imp); + O(cld_imp); + O(cli_imp); + O(clv_imp); + O(cmp_aba); O(cmp_abx); O(cmp_aby); O(cmp_idx); O(cmp_idy); O(cmp_imm); O(cmp_zpg); O(cmp_zpx); + O(cpx_aba); O(cpx_imm); O(cpx_zpg); + O(cpy_aba); O(cpy_imm); O(cpy_zpg); + O(dec_aba); O(dec_abx); O(dec_zpg); O(dec_zpx); + O(dex_imp); + O(dey_imp); + O(eor_aba); O(eor_abx); O(eor_aby); O(eor_idx); O(eor_idy); O(eor_imm); O(eor_zpg); O(eor_zpx); + O(inc_aba); O(inc_abx); O(inc_zpg); O(inc_zpx); + O(inx_imp); + O(iny_imp); + O(jmp_adr); O(jmp_ind); + O(jsr_adr); + O(lda_aba); O(lda_abx); O(lda_aby); O(lda_idx); O(lda_idy); O(lda_imm); O(lda_zpg); O(lda_zpx); + O(ldx_aba); O(ldx_aby); O(ldx_imm); O(ldx_zpg); O(ldx_zpy); + O(ldy_aba); O(ldy_abx); O(ldy_imm); O(ldy_zpg); O(ldy_zpx); + O(lsr_aba); O(lsr_abx); O(lsr_acc); O(lsr_zpg); O(lsr_zpx); + O(nop_imp); + O(ora_aba); O(ora_abx); O(ora_aby); O(ora_imm); O(ora_idx); O(ora_idy); O(ora_zpg); O(ora_zpx); + O(pha_imp); + O(php_imp); + O(pla_imp); + O(plp_imp); + O(rol_aba); O(rol_abx); O(rol_acc); O(rol_zpg); O(rol_zpx); + O(ror_aba); O(ror_abx); O(ror_acc); O(ror_zpg); O(ror_zpx); + O(rti_imp); + O(rts_imp); + O(sbc_aba); O(sbc_abx); O(sbc_aby); O(sbc_idx); O(sbc_idy); O(sbc_imm); O(sbc_zpg); O(sbc_zpx); + O(sec_imp); + O(sed_imp); + O(sei_imp); + O(sta_aba); O(sta_abx); O(sta_aby); O(sta_idx); O(sta_idy); O(sta_zpg); O(sta_zpx); + O(stx_aba); O(stx_zpg); O(stx_zpy); + O(sty_aba); O(sty_zpg); O(sty_zpx); + O(tax_imp); + O(tay_imp); + O(tsx_imp); + O(txa_imp); + O(txs_imp); + O(tya_imp); + + // exceptions + O(reset); + + // undocumented reliable instructions + O(dcp_aba); O(dcp_abx); O(dcp_aby); O(dcp_idx); O(dcp_idy); O(dcp_zpg); O(dcp_zpx); + O(isb_aba); O(isb_abx); O(isb_aby); O(isb_idx); O(isb_idy); O(isb_zpg); O(isb_zpx); + O(lax_aba); O(lax_aby); O(lax_idx); O(lax_idy); O(lax_zpg); O(lax_zpy); + O(rla_aba); O(rla_abx); O(rla_aby); O(rla_idx); O(rla_idy); O(rla_zpg); O(rla_zpx); + O(rra_aba); O(rra_abx); O(rra_aby); O(rra_idx); O(rra_idy); O(rra_zpg); O(rra_zpx); + O(sax_aba); O(sax_idx); O(sax_zpg); O(sax_zpy); + O(sbx_imm); + O(sha_aby); O(sha_idy); + O(shs_aby); + O(shx_aby); + O(shy_abx); + O(slo_aba); O(slo_abx); O(slo_aby); O(slo_idx); O(slo_idy); O(slo_zpg); O(slo_zpx); + O(sre_aba); O(sre_abx); O(sre_aby); O(sre_idx); O(sre_idy); O(sre_zpg); O(sre_zpx); + + // undocumented unreliable instructions + // behaviour differs between visual6502 and online docs, which + // is a clear sign reliability is not to be expected + // implemented version follows visual6502 + O(anc_imm); + O(ane_imm); + O(arr_imm); + O(asr_imm); + O(las_aby); + O(lxa_imm); + + // nop variants + O(nop_imm); O(nop_aba); O(nop_abx); O(nop_zpg); O(nop_zpx); + + // system killers + O(kil_non); + +#undef O +}; + +enum { + M6502_PC = 1, + M6502_A, + M6502_X, + M6502_Y, + M6502_P, + M6502_S, + M6502_IR +}; + +enum { + M6502_IRQ_LINE = m6502_device::IRQ_LINE, + M6502_NMI_LINE = m6502_device::NMI_LINE, + M6502_SET_OVERFLOW = m6502_device::V_LINE +}; + +extern const device_type M6502; + +#endif diff --git a/src/devices/cpu/m6502/m6502.txt b/src/devices/cpu/m6502/m6502.txt new file mode 100644 index 00000000000..d92af7ec146 --- /dev/null +++ b/src/devices/cpu/m6502/m6502.txt @@ -0,0 +1,163 @@ +mos metal oxid semiconductor +bought by cbm + +license to produce chips + rockwell + +transistor, logic gate designs: +NMOS (M65xx) +CMOS (M65Cxx) +HMOS (M75xx) hyper? MOS, used in early c16/plus4 series +H2MOS (M85xx) hyper2 MOS, used in C128, later c16/plus4, late C64 +?SCMOS (M65SCxx) Super? CMOS +?CE (M65CExx, M45xx) CMOS Enhanced?, used in not released C65 + +HMOS, H2MOS CPUs have the same core as the NMOS series + +6500 / 6501 +mask programable microcontroller +32 io ports (2 interruptable) +timer +64 byte ram +8 kbyte rom + +6502 (used in many designs) +b-flag always 1! (only pushed as 0 when break executed!) +memory changing opcodes accesses memory: read, write data, write modified data + +6504 +only 12 address pins a11..a0 + +6508 +8 io pins (p0 bis p7) + +6509 +1 megabyte memory management +(lda,sta (zeropage),y modified, uses 2nd address extension register) + +6510/8500 (used in some designs) +6 io pins (p0 bis p5) + +6510T/8503? (used in commodore C1551 floppy) +8 io pins +integrated clock generation? + +7501/8501 (c16, c116, c232, c264, plus4, c364) +7 io pins (no p5) +no nmi + +8502 (c128) +7 io pins (no p7) + +the above series is opcode compatible (including illegal opcodes) + + +n2a03 (some arcades, NES) +------------------------- +(nintendo variant) +NMOS based! +illegal opcodes +$6c jump indirect low byte overrun problem as in 6502 +no decimal mode +integrated sound hardware + + +65c02 (used in some designs) +---------------------------- +fixed jmp ind opcode +memory changing opcodes accesses memory: read, read, write +no illegal opcodes from the above series +so not full compatible to 6502 series +b flag always 1 as in NMOS Series is not known? +additional commands + +several other CMOS variants + + +65sc02 (where used?) +-------------------- +65c02 compatible +additional commands + +atari lynx bastian schicks bll +integrated m65sc02 cpu core +no bbr bbs instructions, else m65c02 compatible + +watara supervision +integrated m65c02 cpu core (or m65sc02 or m65ce02?) + + +gte65816 (nintendo snes) +------------------------ +65802 upgrade cpu (c64 and c128 upgrade cpu) +16 bit wide registers +24 bit address space +65c02? compatible mode +additional commands + + +spc700 +------ +(snes sound processor) +same register layout? +same addressing modes? +heavily modified opcodes +YA could be combined for 16 bit operations? + + +huc6280 (nec pcengine) +---------------------- +65sc02 compatible? +8 memory registers +(highest 3 bits select memory register, these build a22..a13) +(so 2 Megabyte address room!) +additional commands? +several additional integrated features + + +65ce02 (c65 prototype) +---------------------- +(scan of documentation available, also use +c65 m4510 documentation) +(cpu core to be used in asics) +65sc02 compatible +z register +(65c02 zeropage indexed addressing is now (zeropage),z) +b bank register, highbyte of all zerozape addressing +register for stack high byte +additional command (some from the 65816) + + +m4510 (Commodore C65 CPU) +------------------------- +(scan of documentation (in c65 documentation) available) +65ce02 compatible +integrated 20 bit memory management (map) +(aug opcode changed to map opcode) +2 cia6526 integrated +1 uart integrated + + +mitsubishi 740 series +--------------------- +(data book in electronic form available) +(M507xx, M509xx, M374xx, M38xxx, M375xx) +NMOS based +additional operation mode +(arithmetic instruction not performing on akku (a=a operation addressing mode) +but on zeropage ([x]=[x] operation addressing mode)) +additional instructions LDM, MUL, DIV, TST, COM, RRF, CLT, SET, WIT, STP, CLP +BRK 1 byte only? +BRA CMOS compatible +BBC, BBR different opcode as CMOS, and also akku addressing +different TRB, TSB +no CMOS STZ, JMP ind,x +STP not in all variants +MUL, DIV not in all variants + + +Set Overflow Pin +---------------- +in 6502 and pin compatibles (65C02 65SC02 65SC802 65CE02), M6509 +no SO pin 6510/7501/8500/8501/8502/65sc816 +6510T ? diff --git a/src/devices/cpu/m6502/m6502make.py b/src/devices/cpu/m6502/m6502make.py new file mode 100755 index 00000000000..4ac62e90ce9 --- /dev/null +++ b/src/devices/cpu/m6502/m6502make.py @@ -0,0 +1,280 @@ +#!/usr/bin/python + +from __future__ import print_function + +USAGE = """ +Usage: +%s device_name {opc.lst|-} disp.lst device.inc +""" +import sys +import logging + +MAX_STATES = 0 + +def load_opcodes(fname): + """Load opcodes from .lst file""" + opcodes = [] + logging.info("load_opcodes: %s", fname) + try: + f = open(fname, "rU") + except Exception: + err = sys.exc_info()[1] + logging.error("cannot read opcodes file %s [%s]", fname, err) + sys.exit(1) + + for line in f: + if line.startswith("#"): continue + line = line.rstrip() + if not line: continue + if line.startswith(" ") or line.startswith("\t"): + # append instruction to last opcode + opcodes[-1][1].append(line) + else: + # add new opcode + opcodes.append((line, [])) + return opcodes + + +def load_disp(fname): + logging.info("load_disp: %s", fname) + states = [] + try: + f = open(fname, "rU") + except Exception: + err = sys.exc_info()[1] + logging.error("cannot read display file %s [%s]", fname, err) + sys.exit(1) + for line in f: + if line.startswith("#"): continue + line = line.strip() + if not line: continue + tokens = line.split() + states += tokens + return states + +def emit(f, text): + """write string to file""" + print(text, file=f) + +FULL_PROLOG="""\ +void %(device)s::%(opcode)s_full() +{ +""" + +FULL_EPILOG="""\ +} +""" + +FULL_EAT_ALL="""\ +\ticount=0; inst_substate = %(substate)s; return; +""" + +FULL_MEMORY="""\ +\tif(icount == 0) { inst_substate = %(substate)s; return; } +%(ins)s +\ticount--; +""" + +FULL_NONE="""\ +%(ins)s +""" + +PARTIAL_PROLOG="""\ +void %(device)s::%(opcode)s_partial() +{ +switch(inst_substate) { +case 0: +""" + +PARTIAL_EPILOG="""\ +} +\tinst_substate = 0; +} + +""" + +PARTIAL_EAT_ALL="""\ +\ticount=0; inst_substate = %(substate)s; return; +case %(substate)s:; +""" + +PARTIAL_MEMORY="""\ +\tif(icount == 0) { inst_substate = %(substate)s; return; } +case %(substate)s: +%(ins)s +\ticount--; +""" + +PARTIAL_NONE="""\ +%(ins)s +""" +def identify_line_type(ins): + if "eat-all-cycles" in ins: return "EAT" + for s in ["read", "write", "prefetch(", "prefetch_noirq("]: + if s in ins: + return "MEMORY" + return "NONE" + + +def save_opcodes(f, device, opcodes): + for name, instructions in opcodes: + d = { "device": device, + "opcode": name, + } + + emit(f, FULL_PROLOG % d) + substate = 1 + for ins in instructions: + d["substate"] = str(substate) + d["ins"] = ins + line_type = identify_line_type(ins) + if line_type == "EAT": + emit(f, FULL_EAT_ALL % d) + substate += 1 + elif line_type == "MEMORY": + emit(f, FULL_MEMORY % d) + substate += 1 + else: + emit(f, FULL_NONE %d) + emit(f, FULL_EPILOG % d) + + emit(f, PARTIAL_PROLOG % d) + substate = 1 + for ins in instructions: + d["substate"] = str(substate) + d["ins"] = ins + line_type = identify_line_type(ins) + if line_type == "EAT": + emit(f, PARTIAL_EAT_ALL % d) + substate += 1 + elif line_type == "MEMORY": + emit(f, PARTIAL_MEMORY % d) + substate += 1 + else: + emit(f, PARTIAL_NONE %d) + emit(f, PARTIAL_EPILOG % d) + + +DO_EXEC_FULL_PROLOG="""\ +void %(device)s::do_exec_full() +{ +\tswitch(inst_state) { +""" + +DO_EXEC_FULL_EPILOG="""\ +\t} +} +""" + +DO_EXEC_PARTIAL_PROLOG="""\ +void %(device)s::do_exec_partial() +{ +\tswitch(inst_state) { +""" + +DO_EXEC_PARTIAL_EPILOG="""\ +\t} +} +""" + +DISASM_PROLOG="""\ +const %(device)s::disasm_entry %(device)s::disasm_entries[0x%(disasm_count)x] = { +""" + +DISASM_EPILOG="""\ +}; +""" + +def save_tables(f, device, states): + total_states = len(states) + + d = { "device": device, + "disasm_count": total_states-1 + } + + + emit(f, DO_EXEC_FULL_PROLOG % d) + for n, state in enumerate(states): + if state == ".": continue + if n < total_states - 1: + emit(f, "\tcase 0x%02x: %s_full(); break;\n" % (n, state)) + else: + emit(f, "\tcase %s: %s_full(); break;\n" % ("STATE_RESET", state)) + emit(f, DO_EXEC_FULL_EPILOG % d) + + emit(f, DO_EXEC_PARTIAL_PROLOG % d) + for n, state in enumerate(states): + if state == ".": continue + if n < total_states - 1: + emit(f, "\tcase 0x%02x: %s_partial(); break;\n" % (n, state)) + else: + emit(f, "\tcase %s: %s_partial(); break;\n" % ("STATE_RESET", state)) + emit(f, DO_EXEC_PARTIAL_EPILOG % d) + + emit(f, DISASM_PROLOG % d ) + for n, state in enumerate(states): + if state == ".": continue + if n == total_states - 1: break + tokens = state.split("_") + opc = tokens[0] + mode = tokens[-1] + extra = "0" + if opc in ["jsr", "bsr"]: + extra = "DASMFLAG_STEP_OVER" + elif opc in ["rts", "rti", "rtn"]: + extra = "DASMFLAG_STEP_OUT" + emit(f, '\t{ "%s", DASM_%s, %s },\n' % (opc, mode, extra)) + emit(f, DISASM_EPILOG % d) + +def save(fname, device, opcodes, states): + logging.info("saving: %s", fname) + try: + f = open(fname, "w") + except Exception: + err = sys.exc_info()[1] + logging.error("cannot write file %s [%s]", fname, err) + sys.exit(1) + save_opcodes(f,device, opcodes) + emit(f, "\n") + save_tables(f, device, states) + f.close() + + +def main(argv): + debug = False + logformat=("%(levelname)s:" + "%(module)s:" + "%(lineno)d:" + "%(threadName)s:" + "%(message)s") + if debug: + logging.basicConfig(level=logging.INFO, format=logformat) + else: + logging.basicConfig(level=logging.WARNING, format=logformat) + + + if len(argv) != 5: + print(USAGE % argv[0]) + return 1 + + device_name = argv[1] + + opcodes = [] + if argv[2] != "-": + opcodes = load_opcodes(argv[2]) + logging.info("found %d opcodes", len(opcodes)) + else: + logging.info("skipping opcode reading") + + + states = load_disp(argv[3]) + logging.info("loaded %s states", len(states)) + + assert (len(states) & 0xff) == 1 + save(argv[4], device_name, opcodes, states) + + +# ====================================================================== +if __name__ == "__main__": + sys.exit(main(sys.argv)) + diff --git a/src/devices/cpu/m6502/m6504.c b/src/devices/cpu/m6502/m6504.c new file mode 100644 index 00000000000..f2ae2c4b6d9 --- /dev/null +++ b/src/devices/cpu/m6502/m6504.c @@ -0,0 +1,61 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +/*************************************************************************** + + m6504.c + + Mostek 6502, NMOS variant with reduced address bus + +***************************************************************************/ + +#include "emu.h" +#include "m6504.h" + +const device_type M6504 = &device_creator; + +m6504_device::m6504_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + m6502_device(mconfig, M6504, "M6504", tag, owner, clock, "m6504", __FILE__) +{ + program_config.m_addrbus_width = 13; + sprogram_config.m_addrbus_width = 13; +} + +void m6504_device::device_start() +{ + if(direct_disabled) + mintf = new mi_6504_nd; + else + mintf = new mi_6504_normal; + + init(); +} + +UINT8 m6504_device::mi_6504_normal::read(UINT16 adr) +{ + return program->read_byte(adr & 0x1fff); +} + +UINT8 m6504_device::mi_6504_normal::read_sync(UINT16 adr) +{ + return sdirect->read_byte(adr & 0x1fff); +} + +UINT8 m6504_device::mi_6504_normal::read_arg(UINT16 adr) +{ + return direct->read_byte(adr & 0x1fff); +} + +void m6504_device::mi_6504_normal::write(UINT16 adr, UINT8 val) +{ + program->write_byte(adr & 0x1fff, val); +} + +UINT8 m6504_device::mi_6504_nd::read_sync(UINT16 adr) +{ + return sprogram->read_byte(adr & 0x1fff); +} + +UINT8 m6504_device::mi_6504_nd::read_arg(UINT16 adr) +{ + return program->read_byte(adr & 0x1fff); +} diff --git a/src/devices/cpu/m6502/m6504.h b/src/devices/cpu/m6502/m6504.h new file mode 100644 index 00000000000..f272b059333 --- /dev/null +++ b/src/devices/cpu/m6502/m6504.h @@ -0,0 +1,49 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +/*************************************************************************** + + m6504.h + + Mostek 6502, NMOS variant with reduced address bus + +***************************************************************************/ + +#ifndef __M6504_H__ +#define __M6504_H__ + +#include "m6502.h" + +class m6504_device : public m6502_device { +public: + m6504_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + class mi_6504_normal : public memory_interface { + public: + virtual ~mi_6504_normal() {} + virtual UINT8 read(UINT16 adr); + virtual UINT8 read_sync(UINT16 adr); + virtual UINT8 read_arg(UINT16 adr); + virtual void write(UINT16 adr, UINT8 val); + }; + + class mi_6504_nd : public mi_6504_normal { + public: + virtual ~mi_6504_nd() {} + virtual UINT8 read_sync(UINT16 adr); + virtual UINT8 read_arg(UINT16 adr); + }; + + virtual void device_start(); +}; + + +enum { + M6504_IRQ_LINE = m6502_device::IRQ_LINE, + M6504_NMI_LINE = m6502_device::NMI_LINE, + M6504_SET_OVERFLOW = m6502_device::V_LINE +}; + +extern const device_type M6504; + +#endif diff --git a/src/devices/cpu/m6502/m6509.c b/src/devices/cpu/m6502/m6509.c new file mode 100644 index 00000000000..77af9e8f1f7 --- /dev/null +++ b/src/devices/cpu/m6502/m6509.c @@ -0,0 +1,148 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +/*************************************************************************** + + m6509.c + + 6502 with banking and extended address bus + +***************************************************************************/ + +#include "emu.h" +#include "m6509.h" + +const device_type M6509 = &device_creator; + +m6509_device::m6509_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + m6502_device(mconfig, M6509, "M6509", tag, owner, clock, "m6509", __FILE__) +{ + program_config.m_addrbus_width = 20; + program_config.m_logaddr_width = 20; + sprogram_config.m_addrbus_width = 20; + sprogram_config.m_logaddr_width = 20; +} + +void m6509_device::device_start() +{ + if(direct_disabled) + mintf = new mi_6509_nd(this); + else + mintf = new mi_6509_normal(this); + + init(); + + state_add(STATE_GENPC, "GENPC", XPC).callexport().noshow(); + state_add(M6509_BI, "BI", bank_i); + state_add(M6509_BY, "BY", bank_y); +} + +void m6509_device::device_reset() +{ + m6502_device::device_reset(); + bank_i = 0x0f; + bank_y = 0x0f; +} + +void m6509_device::state_export(const device_state_entry &entry) +{ + switch(entry.index()) { + case STATE_GENPC: + XPC = adr_in_bank_i(NPC); + break; + } +} + +offs_t m6509_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + return disassemble_generic(buffer, pc, oprom, opram, options, disasm_entries); +} + + +m6509_device::mi_6509_normal::mi_6509_normal(m6509_device *_base) +{ + base = _base; +} + +UINT8 m6509_device::mi_6509_normal::read(UINT16 adr) +{ + UINT8 res = program->read_byte(base->adr_in_bank_i(adr)); + if(adr == 0x0000) + res = base->bank_i_r(); + else if(adr == 0x0001) + res = base->bank_y_r(); + return res; +} + +UINT8 m6509_device::mi_6509_normal::read_sync(UINT16 adr) +{ + UINT8 res = sdirect->read_byte(base->adr_in_bank_i(adr)); + if(adr == 0x0000) + res = base->bank_i_r(); + else if(adr == 0x0001) + res = base->bank_y_r(); + return res; +} + +UINT8 m6509_device::mi_6509_normal::read_arg(UINT16 adr) +{ + UINT8 res = direct->read_byte(base->adr_in_bank_i(adr)); + if(adr == 0x0000) + res = base->bank_i_r(); + else if(adr == 0x0001) + res = base->bank_y_r(); + return res; +} + +UINT8 m6509_device::mi_6509_normal::read_9(UINT16 adr) +{ + UINT8 res = program->read_byte(base->adr_in_bank_y(adr)); + if(adr == 0x0000) + res = base->bank_i_r(); + else if(adr == 0x0001) + res = base->bank_y_r(); + return res; +} + +void m6509_device::mi_6509_normal::write(UINT16 adr, UINT8 val) +{ + program->write_byte(base->adr_in_bank_i(adr), val); + if(adr == 0x0000) + base->bank_i_w(val); + else if(adr == 0x0001) + base->bank_y_w(val); +} + +void m6509_device::mi_6509_normal::write_9(UINT16 adr, UINT8 val) +{ + program->write_byte(base->adr_in_bank_y(adr), val); + if(adr == 0x0000) + base->bank_i_w(val); + else if(adr == 0x0001) + base->bank_y_w(val); +} + +m6509_device::mi_6509_nd::mi_6509_nd(m6509_device *_base) : mi_6509_normal(_base) +{ +} + +UINT8 m6509_device::mi_6509_nd::read_sync(UINT16 adr) +{ + UINT8 res = sprogram->read_byte(base->adr_in_bank_i(adr)); + if(adr == 0x0000) + res = base->bank_i_r(); + else if(adr == 0x0001) + res = base->bank_y_r(); + return res; +} + +UINT8 m6509_device::mi_6509_nd::read_arg(UINT16 adr) +{ + UINT8 res = program->read_byte(base->adr_in_bank_i(adr)); + if(adr == 0x0000) + res = base->bank_i_r(); + else if(adr == 0x0001) + res = base->bank_y_r(); + return res; +} + +#include "cpu/m6502/m6509.inc" diff --git a/src/devices/cpu/m6502/m6509.h b/src/devices/cpu/m6502/m6509.h new file mode 100644 index 00000000000..2bfee01981a --- /dev/null +++ b/src/devices/cpu/m6502/m6509.h @@ -0,0 +1,87 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +/*************************************************************************** + + m6509.h + + 6502 with banking and extended address bus + +***************************************************************************/ + +#ifndef __M6509_H__ +#define __M6509_H__ + +#include "m6502.h" + +class m6509_device : public m6502_device { +public: + m6509_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + static const disasm_entry disasm_entries[0x100]; + + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + virtual void do_exec_full(); + virtual void do_exec_partial(); + +protected: + class mi_6509_normal : public memory_interface { + public: + m6509_device *base; + + mi_6509_normal(m6509_device *base); + virtual ~mi_6509_normal() {} + virtual UINT8 read(UINT16 adr); + virtual UINT8 read_9(UINT16 adr); + virtual UINT8 read_sync(UINT16 adr); + virtual UINT8 read_arg(UINT16 adr); + virtual void write(UINT16 adr, UINT8 val); + virtual void write_9(UINT16 adr, UINT8 val); + }; + + class mi_6509_nd : public mi_6509_normal { + public: + mi_6509_nd(m6509_device *base); + virtual ~mi_6509_nd() {} + virtual UINT8 read_sync(UINT16 adr); + virtual UINT8 read_arg(UINT16 adr); + }; + + virtual void device_start(); + virtual void device_reset(); + virtual void state_export(const device_state_entry &entry); + + UINT32 XPC; + + UINT8 bank_i, bank_y; + + UINT8 bank_i_r() { return bank_i; } + UINT8 bank_y_r() { return bank_y; } + void bank_i_w(UINT8 data) { bank_i = data; } + void bank_y_w(UINT8 data) { bank_y = data; } + + UINT32 adr_in_bank_i(UINT16 adr) { return adr | ((bank_i & 0xf) << 16); } + UINT32 adr_in_bank_y(UINT16 adr) { return adr | ((bank_y & 0xf) << 16); } + +#define O(o) void o ## _full(); void o ## _partial() + + // 6509 opcodes + O(lda_9_idy); + O(sta_9_idy); + +#undef O +}; + +enum { + M6509_IRQ_LINE = m6502_device::IRQ_LINE, + M6509_NMI_LINE = m6502_device::NMI_LINE, + M6509_SET_OVERFLOW = m6502_device::V_LINE +}; + +enum { + M6509_BI = M6502_IR+1, + M6509_BY +}; + +extern const device_type M6509; + +#endif diff --git a/src/devices/cpu/m6502/m6510.c b/src/devices/cpu/m6502/m6510.c new file mode 100644 index 00000000000..10e57fb27b8 --- /dev/null +++ b/src/devices/cpu/m6502/m6510.c @@ -0,0 +1,175 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +/*************************************************************************** + + m6510.c + + 6502 with 6 i/o pins, also known as 8500 + +***************************************************************************/ + +#include "emu.h" +#include "m6510.h" + +const device_type M6510 = &device_creator; + +m6510_device::m6510_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + m6502_device(mconfig, M6510, "M6510", tag, owner, clock, "m6510", __FILE__), + read_port(*this), + write_port(*this) +{ + pullup = 0x00; + floating = 0x00; +} + +m6510_device::m6510_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + m6502_device(mconfig, type, name, tag, owner, clock, shortname, source), + read_port(*this), + write_port(*this) +{ + pullup = 0x00; + floating = 0x00; +} + +void m6510_device::set_pulls(UINT8 _pullup, UINT8 _floating) +{ + pullup = _pullup; + floating = _floating; +} + +offs_t m6510_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + return disassemble_generic(buffer, pc, oprom, opram, options, disasm_entries); +} + +void m6510_device::device_start() +{ + read_port.resolve_safe(0); + write_port.resolve_safe(); + + if(direct_disabled) + mintf = new mi_6510_nd(this); + else + mintf = new mi_6510_normal(this); + + init(); + + save_item(NAME(pullup)); + save_item(NAME(floating)); + save_item(NAME(dir)); + save_item(NAME(port)); + save_item(NAME(drive)); +} + +void m6510_device::device_reset() +{ + m6502_device::device_reset(); + dir = 0x00; + port = 0x00; + drive = 0x00; + update_port(); +} + +void m6510_device::update_port() +{ + drive = (port & dir) | (drive & ~dir); + write_port((port & dir) | (pullup & ~dir)); +} + +UINT8 m6510_device::get_port() +{ + return (port & dir) | (pullup & ~dir); +} + +UINT8 m6510_device::dir_r() +{ + return dir; +} + +UINT8 m6510_device::port_r() +{ + return ((read_port() | (floating & drive)) & ~dir) | (port & dir); +} + +void m6510_device::dir_w(UINT8 data) +{ + dir = data; + update_port(); +} + +void m6510_device::port_w(UINT8 data) +{ + port = data; + update_port(); +} + + +m6510_device::mi_6510_normal::mi_6510_normal(m6510_device *_base) +{ + base = _base; +} + +UINT8 m6510_device::mi_6510_normal::read(UINT16 adr) +{ + UINT8 res = program->read_byte(adr); + if(adr == 0x0000) + res = base->dir_r(); + else if(adr == 0x0001) + res = base->port_r(); + return res; +} + +UINT8 m6510_device::mi_6510_normal::read_sync(UINT16 adr) +{ + UINT8 res = sdirect->read_byte(adr); + if(adr == 0x0000) + res = base->dir_r(); + else if(adr == 0x0001) + res = base->port_r(); + return res; +} + +UINT8 m6510_device::mi_6510_normal::read_arg(UINT16 adr) +{ + UINT8 res = direct->read_byte(adr); + if(adr == 0x0000) + res = base->dir_r(); + else if(adr == 0x0001) + res = base->port_r(); + return res; +} + +void m6510_device::mi_6510_normal::write(UINT16 adr, UINT8 val) +{ + program->write_byte(adr, val); + if(adr == 0x0000) + base->dir_w(val); + else if(adr == 0x0001) + base->port_w(val); +} + +m6510_device::mi_6510_nd::mi_6510_nd(m6510_device *_base) : mi_6510_normal(_base) +{ +} + +UINT8 m6510_device::mi_6510_nd::read_sync(UINT16 adr) +{ + UINT8 res = sprogram->read_byte(adr); + if(adr == 0x0000) + res = base->dir_r(); + else if(adr == 0x0001) + res = base->port_r(); + return res; +} + +UINT8 m6510_device::mi_6510_nd::read_arg(UINT16 adr) +{ + UINT8 res = program->read_byte(adr); + if(adr == 0x0000) + res = base->dir_r(); + else if(adr == 0x0001) + res = base->port_r(); + return res; +} + +#include "cpu/m6502/m6510.inc" diff --git a/src/devices/cpu/m6502/m6510.h b/src/devices/cpu/m6502/m6510.h new file mode 100644 index 00000000000..86aaa60ffaa --- /dev/null +++ b/src/devices/cpu/m6502/m6510.h @@ -0,0 +1,99 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +/*************************************************************************** + + m6510.h + + 6502 with 6 i/o pins, also known as 8500 + +***************************************************************************/ + +#ifndef __M6510FAM_H__ +#define __M6510FAM_H__ + +#include "m6502.h" + +#define MCFG_M6510_PORT_CALLBACKS(_read, _write) \ + downcast(device)->set_callbacks(DEVCB_##_read, DEVCB_##_write); + +#define MCFG_M6510_PORT_PULLS(_up, _down) \ + downcast(device)->set_pulls(_up, _down); + +class m6510_device : public m6502_device { +public: + m6510_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + m6510_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + UINT8 get_port(); + void set_port(UINT8 val); + void set_pulls(UINT8 pullup, UINT8 pulldown); + + template void set_callbacks(_read rd, _write wr) { + read_port.set_callback(rd); + write_port.set_callback(wr); + } + + static const disasm_entry disasm_entries[0x100]; + + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + virtual void do_exec_full(); + virtual void do_exec_partial(); + +protected: + class mi_6510_normal : public memory_interface { + public: + m6510_device *base; + + mi_6510_normal(m6510_device *base); + virtual ~mi_6510_normal() {} + virtual UINT8 read(UINT16 adr); + virtual UINT8 read_sync(UINT16 adr); + virtual UINT8 read_arg(UINT16 adr); + virtual void write(UINT16 adr, UINT8 val); + }; + + class mi_6510_nd : public mi_6510_normal { + public: + mi_6510_nd(m6510_device *base); + virtual ~mi_6510_nd() {} + virtual UINT8 read_sync(UINT16 adr); + virtual UINT8 read_arg(UINT16 adr); + }; + + devcb_read8 read_port; + devcb_write8 write_port; + + UINT8 pullup, floating, dir, port, drive; + + virtual void device_start(); + virtual void device_reset(); + + UINT8 dir_r(); + void dir_w(UINT8 data); + UINT8 port_r(); + void port_w(UINT8 data); + + void update_port(); + +#define O(o) void o ## _full(); void o ## _partial() + + // 6510 undocumented instructions in a C64 context + // implementation follows what the test suites expect (usually an extra and) + O(anc_10_imm); + O(ane_10_imm); + O(arr_10_imm); + O(asr_10_imm); + O(las_10_aby); + O(lxa_10_imm); + +#undef O +}; + +enum { + M6510_IRQ_LINE = m6502_device::IRQ_LINE, + M6510_NMI_LINE = m6502_device::NMI_LINE +}; + +extern const device_type M6510; + +#endif diff --git a/src/devices/cpu/m6502/m6510t.c b/src/devices/cpu/m6502/m6510t.c new file mode 100644 index 00000000000..7e8a34c6f20 --- /dev/null +++ b/src/devices/cpu/m6502/m6510t.c @@ -0,0 +1,19 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +/*************************************************************************** + + m6510t.c + + 6510 with the full 8 i/o pins at the expense of the NMI and RDY lines. + +***************************************************************************/ + +#include "emu.h" +#include "m6510t.h" + +const device_type M6510T = &device_creator; + +m6510t_device::m6510t_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + m6510_device(mconfig, M6510T, "M6510T", tag, owner, clock, "m6510t", __FILE__) +{ +} diff --git a/src/devices/cpu/m6502/m6510t.h b/src/devices/cpu/m6502/m6510t.h new file mode 100644 index 00000000000..f580ed6aef3 --- /dev/null +++ b/src/devices/cpu/m6502/m6510t.h @@ -0,0 +1,34 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +/*************************************************************************** + + m6510t.h + + 6510 with the full 8 i/o pins at the expense of the NMI and RDY lines. + +***************************************************************************/ + +#ifndef __M6510T_H__ +#define __M6510T_H__ + +#include "m6510.h" + +#define MCFG_M6510T_PORT_CALLBACKS(_read, _write) \ + downcast(device)->set_callbacks(DEVCB_##_read, DEVCB_##_write); + +#define MCFG_M6510T_PORT_PULLS(_up, _down) \ + downcast(device)->set_pulls(_up, _down); + +class m6510t_device : public m6510_device { +public: + m6510t_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +enum { + M6510T_IRQ_LINE = m6502_device::IRQ_LINE, + M6510T_SET_OVERFLOW = m6502_device::V_LINE +}; + +extern const device_type M6510T; + +#endif diff --git a/src/devices/cpu/m6502/m65c02.c b/src/devices/cpu/m6502/m65c02.c new file mode 100644 index 00000000000..4f02de6471c --- /dev/null +++ b/src/devices/cpu/m6502/m65c02.c @@ -0,0 +1,32 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +/*************************************************************************** + + m65c02.c + + Mostek 6502, CMOS variant with some additional instructions (but + not the bitwise ones) + +***************************************************************************/ + +#include "emu.h" +#include "m65c02.h" + +const device_type M65C02 = &device_creator; + +m65c02_device::m65c02_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + m6502_device(mconfig, M65C02, "M65C02", tag, owner, clock, "mc65c02", __FILE__) +{ +} + +m65c02_device::m65c02_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + m6502_device(mconfig, type, name, tag, owner, clock, shortname, source) +{ +} + +offs_t m65c02_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + return disassemble_generic(buffer, pc, oprom, opram, options, disasm_entries); +} + +#include "cpu/m6502/m65c02.inc" diff --git a/src/devices/cpu/m6502/m65c02.h b/src/devices/cpu/m6502/m65c02.h new file mode 100644 index 00000000000..5eda5593fee --- /dev/null +++ b/src/devices/cpu/m6502/m65c02.h @@ -0,0 +1,76 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +/*************************************************************************** + + m65c02.h + + Mostek 6502, CMOS variant with some additional instructions (but + not the bitwise ones) + +***************************************************************************/ + +#ifndef __M65C02_H__ +#define __M65C02_H__ + +#include "m6502.h" + +class m65c02_device : public m6502_device { +public: + m65c02_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + m65c02_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + static const disasm_entry disasm_entries[0x100]; + + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + virtual void do_exec_full(); + virtual void do_exec_partial(); + +protected: +#define O(o) void o ## _full(); void o ## _partial() + + // 65c02 opcodes + O(adc_c_aba); O(adc_c_abx); O(adc_c_aby); O(adc_c_idx); O(adc_c_idy); O(adc_c_imm); O(adc_c_zpg); O(adc_c_zpi); O(adc_c_zpx); + O(and_zpi); + O(asl_c_abx); + O(bbr_zpb); + O(bbs_zpb); + O(bit_abx); O(bit_imm); O(bit_zpx); + O(bra_rel); + O(brk_c_imp); + O(cmp_zpi); + O(dec_acc); + O(eor_zpi); + O(inc_acc); + O(jmp_c_ind); O(jmp_iax); + O(lda_zpi); + O(lsr_c_abx); + O(nop_c_aba); O(nop_c_abx); O(nop_c_imp); + O(ora_zpi); + O(phx_imp); + O(phy_imp); + O(plx_imp); + O(ply_imp); + O(rmb_bzp); + O(rol_c_abx); + O(ror_c_abx); + O(sbc_c_aba); O(sbc_c_abx); O(sbc_c_aby); O(sbc_c_idx); O(sbc_c_idy); O(sbc_c_imm); O(sbc_c_zpg); O(sbc_c_zpi); O(sbc_c_zpx); + O(smb_bzp); + O(stp_imp); + O(sta_zpi); + O(stz_aba); O(stz_abx); O(stz_zpg); O(stz_zpx); + O(trb_aba); O(trb_zpg); + O(tsb_aba); O(tsb_zpg); + O(wai_imp); + +#undef O +}; + +enum { + M65C02_IRQ_LINE = m6502_device::IRQ_LINE, + M65C02_NMI_LINE = m6502_device::NMI_LINE, + M65C02_SET_OVERFLOW = m6502_device::V_LINE +}; + +extern const device_type M65C02; + +#endif diff --git a/src/devices/cpu/m6502/m65ce02.c b/src/devices/cpu/m6502/m65ce02.c new file mode 100644 index 00000000000..97ad2c4b535 --- /dev/null +++ b/src/devices/cpu/m6502/m65ce02.c @@ -0,0 +1,98 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +/*************************************************************************** + + m65ce02.c + + 6502 with Z register and some more stuff + +***************************************************************************/ + +#include "emu.h" +#include "m65ce02.h" + +const device_type M65CE02 = &device_creator; + +m65ce02_device::m65ce02_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + m65c02_device(mconfig, M65CE02, "M65CE02", tag, owner, clock, "m65ce02", __FILE__) +{ +} + +m65ce02_device::m65ce02_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + m65c02_device(mconfig, type, name, tag, owner, clock, shortname, source) +{ +} + +offs_t m65ce02_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + return disassemble_generic(buffer, pc, oprom, opram, options, disasm_entries); +} + +void m65ce02_device::init() +{ + m65c02_device::init(); + state_add(M65CE02_Z, "Z", Z); + state_add(M65CE02_B, "B", B).callimport().formatstr("%2s"); + save_item(NAME(B)); + save_item(NAME(Z)); + save_item(NAME(TMP3)); + Z = 0x00; + B = 0x0000; + TMP3 = 0x0000; +} + +void m65ce02_device::device_start() +{ + if(direct_disabled) + mintf = new mi_default_nd; + else + mintf = new mi_default_normal; + + init(); +} + +void m65ce02_device::device_reset() +{ + m65c02_device::device_reset(); + Z = 0x00; + B = 0x0000; +} + +void m65ce02_device::state_import(const device_state_entry &entry) +{ + switch(entry.index()) { + case STATE_GENFLAGS: + case M6502_P: + P = P | F_B; + break; + case M65CE02_B: + B <<= 8; + break; + } +} + +void m65ce02_device::state_export(const device_state_entry &entry) +{ +} + +void m65ce02_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + switch(entry.index()) { + case STATE_GENFLAGS: + case M6502_P: + strprintf(str, "%c%c%c%c%c%c%c", + P & F_N ? 'N' : '.', + P & F_V ? 'V' : '.', + P & F_E ? 'E' : '.', + P & F_D ? 'D' : '.', + P & F_I ? 'I' : '.', + P & F_Z ? 'Z' : '.', + P & F_C ? 'C' : '.'); + break; + case M65CE02_B: + strprintf(str, "%02x", B >> 8); + break; + } +} + +#include "cpu/m6502/m65ce02.inc" diff --git a/src/devices/cpu/m6502/m65ce02.h b/src/devices/cpu/m6502/m65ce02.h new file mode 100644 index 00000000000..f8e03867d82 --- /dev/null +++ b/src/devices/cpu/m6502/m65ce02.h @@ -0,0 +1,153 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +/*************************************************************************** + + m65ce02.h + + 6502 with Z register and some more stuff + +***************************************************************************/ + +#ifndef __M65CE02_H__ +#define __M65CE02_H__ + +#include "m65c02.h" + +class m65ce02_device : public m65c02_device { +public: + m65ce02_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + m65ce02_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + static const disasm_entry disasm_entries[0x100]; + + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + virtual void do_exec_full(); + virtual void do_exec_partial(); + +protected: + UINT16 TMP3; /* temporary internal values */ + UINT8 Z; /* Z index register */ + UINT16 B; /* Zero page base address (always xx00) */ + + virtual void init(); + virtual void device_start(); + virtual void device_reset(); + virtual void state_import(const device_state_entry &entry); + virtual void state_export(const device_state_entry &entry); + virtual void state_string_export(const device_state_entry &entry, std::string &str); + + inline void dec_SP_ce() { if(P & F_E) SP = set_l(SP, SP-1); else SP--; } + inline void inc_SP_ce() { if(P & F_E) SP = set_l(SP, SP+1); else SP++; } + +#define O(o) void o ## _full(); void o ## _partial() + + // 65ce02 opcodes + O(adc_ce_aba); O(adc_ce_abx); O(adc_ce_aby); O(adc_ce_idx); O(adc_ce_idy); O(adc_idz); O(adc_ce_imm); O(adc_ce_zpg); O(adc_ce_zpx); + O(and_ce_abx); O(and_ce_aby); O(and_ce_idx); O(and_ce_idy); O(and_idz); O(and_ce_zpg); O(and_ce_zpx); + O(asl_ce_aba); O(asl_ce_abx); O(asl_ce_acc); O(asl_ce_zpg); O(asl_ce_zpx); + O(asr_acc); O(asr_zpg); O(asr_zpx); + O(asw_aba); + O(aug_iw3); + O(bbr_ce_zpb); + O(bbs_ce_zpb); + O(bcc_ce_rel); O(bcc_rw2); + O(bcs_ce_rel); O(bcs_rw2); + O(beq_ce_rel); O(beq_rw2); + O(bit_ce_abx); O(bit_ce_imm); O(bit_ce_zpg); O(bit_ce_zpx); + O(bmi_ce_rel); O(bmi_rw2); + O(bne_ce_rel); O(bne_rw2); + O(bpl_ce_rel); O(bpl_rw2); + O(bra_ce_rel); O(bra_rw2); + O(brk_ce_imp); + O(bsr_rw2); + O(bvc_ce_rel); O(bvc_rw2); + O(bvs_ce_rel); O(bvs_rw2); + O(clc_ce_imp); + O(cld_ce_imp); + O(cle_imp); + O(cli_ce_imp); + O(clv_ce_imp); + O(cmp_ce_abx); O(cmp_ce_aby); O(cmp_ce_idx); O(cmp_ce_idy); O(cmp_idz); O(cmp_ce_zpg); O(cmp_ce_zpx); + O(cpx_ce_zpg); + O(cpy_ce_zpg); + O(cpz_aba); O(cpz_imm); O(cpz_zpg); + O(dec_ce_aba); O(dec_ce_abx); O(dec_ce_acc); O(dec_ce_zpg); O(dec_ce_zpx); + O(dew_zpg); + O(dex_ce_imp); + O(dey_ce_imp); + O(dez_imp); + O(eor_ce_abx); O(eor_ce_aby); O(eor_ce_idx); O(eor_ce_idy); O(eor_idz); O(eor_ce_zpg); O(eor_ce_zpx); + O(inc_ce_aba); O(inc_ce_abx); O(inc_ce_acc); O(inc_ce_zpg); O(inc_ce_zpx); + O(inw_zpg); + O(inx_ce_imp); + O(iny_ce_imp); + O(inz_imp); + O(jmp_ce_iax); O(jmp_ce_ind); + O(jsr_ce_adr); O(jsr_ind); O(jsr_iax); + O(lda_ce_abx); O(lda_ce_aby); O(lda_ce_idx); O(lda_ce_idy); O(lda_idz); O(lda_isy); O(lda_ce_zpg); O(lda_ce_zpx); + O(ldx_ce_aby); O(ldx_ce_zpg); O(ldx_ce_zpy); + O(ldy_ce_abx); O(ldy_ce_zpg); O(ldy_ce_zpx); + O(ldz_aba); O(ldz_abx); O(ldz_imm); + O(lsr_ce_aba); O(lsr_ce_abx); O(lsr_ce_acc); O(lsr_ce_zpg); O(lsr_ce_zpx); + O(neg_acc); + O(ora_ce_abx); O(ora_ce_aby); O(ora_ce_idx); O(ora_ce_idy); O(ora_idz); O(ora_ce_zpg); O(ora_ce_zpx); + O(pha_ce_imp); + O(php_ce_imp); + O(phw_aba); O(phw_iw2); + O(phx_ce_imp); + O(phy_ce_imp); + O(phz_imp); + O(pla_ce_imp); + O(plp_ce_imp); + O(plx_ce_imp); + O(ply_ce_imp); + O(plz_imp); + O(rmb_ce_bzp); + O(rol_ce_aba); O(rol_ce_abx); O(rol_ce_acc); O(rol_ce_zpg); O(rol_ce_zpx); + O(ror_ce_aba); O(ror_ce_abx); O(ror_ce_acc); O(ror_ce_zpg); O(ror_ce_zpx); + O(row_aba); + O(rti_ce_imp); + O(rtn_imm); + O(rts_ce_imp); + O(sbc_ce_aba); O(sbc_ce_abx); O(sbc_ce_aby); O(sbc_ce_idx); O(sbc_ce_idy); O(sbc_idz); O(sbc_ce_imm); O(sbc_ce_zpg); O(sbc_ce_zpx); + O(sec_ce_imp); + O(sed_ce_imp); + O(see_imp); + O(sei_ce_imp); + O(smb_ce_bzp); + O(sta_ce_abx); O(sta_ce_aby); O(sta_ce_idx); O(sta_ce_idy); O(sta_idz); O(sta_isy); O(sta_ce_zpg); O(sta_ce_zpx); + O(stx_aby); O(stx_ce_zpg); O(stx_ce_zpy); + O(sty_abx); O(sty_ce_zpg); O(sty_ce_zpx); + O(stz_ce_aba); O(stz_ce_abx); O(stz_ce_zpg); O(stz_ce_zpx); + O(tab_imp); + O(tax_ce_imp); + O(tay_ce_imp); + O(taz_imp); + O(tba_imp); + O(trb_ce_aba); O(trb_ce_zpg); + O(tsb_ce_aba); O(tsb_ce_zpg); + O(tsx_ce_imp); + O(tsy_imp); + O(txa_ce_imp); + O(txs_ce_imp); + O(tys_imp); + O(tya_ce_imp); + O(tza_imp); + +#undef O +}; + +enum { + M65CE02_IRQ_LINE = m6502_device::IRQ_LINE, + M65CE02_NMI_LINE = m6502_device::NMI_LINE +}; + + +enum { + M65CE02_Z = M6502_IR+1, + M65CE02_B +}; + +extern const device_type M65CE02; + +#endif diff --git a/src/devices/cpu/m6502/m65sc02.c b/src/devices/cpu/m6502/m65sc02.c new file mode 100644 index 00000000000..f61bc63cf7f --- /dev/null +++ b/src/devices/cpu/m6502/m65sc02.c @@ -0,0 +1,19 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +/*************************************************************************** + + m65sc02.c + + Rockwell-class 65c02 with internal static registers, making clock stoppable? + +***************************************************************************/ + +#include "emu.h" +#include "m65sc02.h" + +const device_type M65SC02 = &device_creator; + +m65sc02_device::m65sc02_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + r65c02_device(mconfig, M65SC02, "M65SC02", tag, owner, clock, "m65sc02", __FILE__) +{ +} diff --git a/src/devices/cpu/m6502/m65sc02.h b/src/devices/cpu/m6502/m65sc02.h new file mode 100644 index 00000000000..f754fc3de89 --- /dev/null +++ b/src/devices/cpu/m6502/m65sc02.h @@ -0,0 +1,29 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +/*************************************************************************** + + m65sc02.h + + Rockwell-class 65c02 with internal static registers, making clock stoppable? + +***************************************************************************/ + +#ifndef __M65SC02_H__ +#define __M65SC02_H__ + +#include "r65c02.h" + +class m65sc02_device : public r65c02_device { +public: + m65sc02_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +enum { + M65SC02_IRQ_LINE = m6502_device::IRQ_LINE, + M65SC02_NMI_LINE = m6502_device::NMI_LINE, + M65SC02_SET_OVERFLOW = m6502_device::V_LINE +}; + +extern const device_type M65SC02; + +#endif diff --git a/src/devices/cpu/m6502/m740.c b/src/devices/cpu/m6502/m740.c new file mode 100644 index 00000000000..5e011ba3561 --- /dev/null +++ b/src/devices/cpu/m6502/m740.c @@ -0,0 +1,243 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +/*************************************************************************** + + m740.c + + Mitsubishi M740 series (M507xx/M509xx) + +***************************************************************************/ + +#include "emu.h" +#include "m740.h" + +const device_type M740 = &device_creator; + +m740_device::m740_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + m6502_device(mconfig, M740, "M740", tag, owner, clock, "m740", __FILE__) +{ +} + +m740_device::m740_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + m6502_device(mconfig, type, name, tag, owner, clock, shortname, source) +{ +} + +offs_t m740_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + return disassemble_generic(buffer, pc, oprom, opram, options, disasm_entries); +} + +void m740_device::device_start() +{ + m6502_device::device_start(); + + save_item(NAME(m_irq_multiplex)); + save_item(NAME(m_irq_vector)); +} + +void m740_device::device_reset() +{ + inst_state_base = 0; + inst_state = STATE_RESET; + inst_substate = 0; + nmi_state = false; + irq_state = false; + m_irq_multiplex = 0; + m_irq_vector = 0xfffc; + apu_irq_state = false; + irq_taken = false; + v_state = false; + sync = false; + inhibit_interrupts = false; + SP = 0x00ff; +} + +void m740_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + switch(entry.index()) { + case STATE_GENFLAGS: + case M6502_P: + strprintf(str, "%c%c%c%c%c%c%c", + P & F_N ? 'N' : '.', + P & F_V ? 'V' : '.', + P & F_T ? 'T' : '.', + P & F_D ? 'D' : '.', + P & F_I ? 'I' : '.', + P & F_Z ? 'Z' : '.', + P & F_C ? 'C' : '.'); + break; + } +} + +UINT8 m740_device::do_clb(UINT8 in, UINT8 bit) +{ + return in & ~(1<>4); +} + +void m740_device::do_sbc_dt(UINT8 val) +{ + UINT8 c = P & F_C ? 0 : 1; + P &= ~(F_N|F_V|F_Z|F_C); + UINT16 diff = TMP2 - val - c; + UINT8 al = (TMP2 & 15) - (val & 15) - c; + if(INT8(al) < 0) + al -= 6; + UINT8 ah = (TMP2 >> 4) - (val >> 4) - (INT8(al) < 0); + if(!UINT8(diff)) + P |= F_Z; + else if(diff & 0x80) + P |= F_N; + if((TMP2^val) & (TMP2^diff) & 0x80) + P |= F_V; + if(!(diff & 0xff00)) + P |= F_C; + if(INT8(ah) < 0) + ah -= 6; + TMP2 = (ah << 4) | (al & 15); +} + +void m740_device::do_sbc_ndt(UINT8 val) +{ + UINT16 diff = TMP2 - val - (P & F_C ? 0 : 1); + P &= ~(F_N|F_V|F_Z|F_C); + if(!UINT8(diff)) + P |= F_Z; + else if(INT8(diff) < 0) + P |= F_N; + if((TMP2^val) & (TMP2^diff) & 0x80) + P |= F_V; + if(!(diff & 0xff00)) + P |= F_C; + TMP2 = diff; +} + +void m740_device::do_sbct(UINT8 val) +{ + if(P & F_D) + do_sbc_dt(val); + else + do_sbc_ndt(val); +} + +void m740_device::do_adc_dt(UINT8 val) +{ + UINT8 c = P & F_C ? 1 : 0; + P &= ~(F_N|F_V|F_Z|F_C); + UINT8 al = (TMP2 & 15) + (val & 15) + c; + if(al > 9) + al += 6; + UINT8 ah = (TMP2 >> 4) + (val >> 4) + (al > 15); + if(!UINT8(TMP2 + val + c)) + P |= F_Z; + else if(ah & 8) + P |= F_N; + if(~(TMP2^val) & (TMP2^(ah << 4)) & 0x80) + P |= F_V; + if(ah > 9) + ah += 6; + if(ah > 15) + P |= F_C; + TMP2 = (ah << 4) | (al & 15); +} + +void m740_device::do_adc_ndt(UINT8 val) +{ + UINT16 sum; + sum = TMP2 + val + (P & F_C ? 1 : 0); + P &= ~(F_N|F_V|F_Z|F_C); + if(!UINT8(sum)) + P |= F_Z; + else if(INT8(sum) < 0) + P |= F_N; + if(~(TMP2^val) & (TMP2^sum) & 0x80) + P |= F_V; + if(sum & 0xff00) + P |= F_C; + TMP2 = sum; +} + +void m740_device::do_adct(UINT8 val) +{ + if(P & F_D) + do_adc_dt(val); + else + do_adc_ndt(val); +} + +void m740_device::execute_set_input(int inputnum, int state) +{ + switch(inputnum) + { + case M740_INT0_LINE: + case M740_INT1_LINE: + case M740_INT2_LINE: + case M740_INT3_LINE: + case M740_INT4_LINE: + case M740_INT5_LINE: + case M740_INT6_LINE: + case M740_INT7_LINE: + case M740_INT8_LINE: + case M740_INT9_LINE: + case M740_INT10_LINE: + case M740_INT11_LINE: + case M740_INT12_LINE: + case M740_INT13_LINE: + case M740_INT14_LINE: // 37450 has 15 IRQ lines, no other known variant has that many + set_irq_line(inputnum - M740_INT0_LINE, state); + break; + + case V_LINE: + if(!v_state && state == ASSERT_LINE) + { + P |= F_V; + } + v_state = state == ASSERT_LINE; + break; + } +} + +void m740_device::set_irq_line(int line, int state) +{ + assert(line > 0); + assert(line <= M740_MAX_INT_LINE); + + if (state == ASSERT_LINE) + { + m_irq_multiplex |= (1<; + +m7501_device::m7501_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + m6510_device(mconfig, M7501, "M7501", tag, owner, clock, "m7501", __FILE__) +{ +} diff --git a/src/devices/cpu/m6502/m7501.h b/src/devices/cpu/m6502/m7501.h new file mode 100644 index 00000000000..7ded4caffe2 --- /dev/null +++ b/src/devices/cpu/m6502/m7501.h @@ -0,0 +1,34 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +/*************************************************************************** + + m7501.h + + 6510 derivative, essentially identical. Also known as the 8501. + +***************************************************************************/ + +#ifndef __M7501_H__ +#define __M7501_H__ + +#include "m6510.h" + +#define MCFG_M7501_PORT_CALLBACKS(_read, _write) \ + downcast(device)->set_callbacks(DEVCB_##_read, DEVCB_##_write); + +#define MCFG_M7501_PORT_PULLS(_up, _down) \ + downcast(device)->set_pulls(_up, _down); + +class m7501_device : public m6510_device { +public: + m7501_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +enum { + M7501_IRQ_LINE = m6502_device::IRQ_LINE, + M7501_NMI_LINE = m6502_device::NMI_LINE +}; + +extern const device_type M7501; + +#endif diff --git a/src/devices/cpu/m6502/m8502.c b/src/devices/cpu/m6502/m8502.c new file mode 100644 index 00000000000..a967d03d74c --- /dev/null +++ b/src/devices/cpu/m6502/m8502.c @@ -0,0 +1,19 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +/*************************************************************************** + + m8502.c + + 6510 derivative, capable of running at 2MHz. + +***************************************************************************/ + +#include "emu.h" +#include "m8502.h" + +const device_type M8502 = &device_creator; + +m8502_device::m8502_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + m6510_device(mconfig, M8502, "M8502", tag, owner, clock, "m8502", __FILE__) +{ +} diff --git a/src/devices/cpu/m6502/m8502.h b/src/devices/cpu/m6502/m8502.h new file mode 100644 index 00000000000..1969ba6ffad --- /dev/null +++ b/src/devices/cpu/m6502/m8502.h @@ -0,0 +1,34 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +/*************************************************************************** + + m8502.h + + 6510 derivative, capable of running at 2MHz. + +***************************************************************************/ + +#ifndef __M8502_H__ +#define __M8502_H__ + +#include "m6510.h" + +#define MCFG_M8502_PORT_CALLBACKS(_read, _write) \ + downcast(device)->set_callbacks(DEVCB_##_read, DEVCB_##_write); + +#define MCFG_M8502_PORT_PULLS(_up, _down) \ + downcast(device)->set_pulls(_up, _down); + +class m8502_device : public m6510_device { +public: + m8502_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +enum { + M8502_IRQ_LINE = m6502_device::IRQ_LINE, + M8502_NMI_LINE = m6502_device::NMI_LINE +}; + +extern const device_type M8502; + +#endif diff --git a/src/devices/cpu/m6502/n2a03.c b/src/devices/cpu/m6502/n2a03.c new file mode 100644 index 00000000000..b3b2cb31808 --- /dev/null +++ b/src/devices/cpu/m6502/n2a03.c @@ -0,0 +1,76 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +/*************************************************************************** + + m6502.c + + 6502, NES variant + +***************************************************************************/ + +#include "emu.h" +#include "n2a03.h" + +const device_type N2A03 = &device_creator; + +n2a03_device::n2a03_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + m6502_device(mconfig, N2A03, "N2A03", tag, owner, clock, "n2a03", __FILE__) +{ +} + +offs_t n2a03_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + return disassemble_generic(buffer, pc, oprom, opram, options, disasm_entries); +} + +void n2a03_device::device_start() +{ + if(direct_disabled) + mintf = new mi_2a03_nd; + else + mintf = new mi_2a03_normal; + + init(); +} + +UINT8 n2a03_device::mi_2a03_normal::read(UINT16 adr) +{ + return program->read_byte(adr); +} + +UINT8 n2a03_device::mi_2a03_normal::read_sync(UINT16 adr) +{ + return sdirect->read_byte(adr); +} + +UINT8 n2a03_device::mi_2a03_normal::read_arg(UINT16 adr) +{ + return direct->read_byte(adr); +} + +void n2a03_device::mi_2a03_normal::write(UINT16 adr, UINT8 val) +{ + program->write_byte(adr, val); +} + +UINT8 n2a03_device::mi_2a03_nd::read(UINT16 adr) +{ + return program->read_byte(adr); +} + +UINT8 n2a03_device::mi_2a03_nd::read_sync(UINT16 adr) +{ + return sprogram->read_byte(adr); +} + +UINT8 n2a03_device::mi_2a03_nd::read_arg(UINT16 adr) +{ + return program->read_byte(adr); +} + +void n2a03_device::mi_2a03_nd::write(UINT16 adr, UINT8 val) +{ + program->write_byte(adr, val); +} + +#include "cpu/m6502/n2a03.inc" diff --git a/src/devices/cpu/m6502/n2a03.h b/src/devices/cpu/m6502/n2a03.h new file mode 100644 index 00000000000..6d56a42e9b7 --- /dev/null +++ b/src/devices/cpu/m6502/n2a03.h @@ -0,0 +1,70 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +/*************************************************************************** + + n2a03.h + + 6502, NES variant + +***************************************************************************/ + +#ifndef __N2A03_H__ +#define __N2A03_H__ + +#include "m6502.h" + +class n2a03_device : public m6502_device { +public: + n2a03_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + static const disasm_entry disasm_entries[0x100]; + + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + virtual void do_exec_full(); + virtual void do_exec_partial(); + +protected: + class mi_2a03_normal : public memory_interface { + public: + virtual ~mi_2a03_normal() {} + virtual UINT8 read(UINT16 adr); + virtual UINT8 read_sync(UINT16 adr); + virtual UINT8 read_arg(UINT16 adr); + virtual void write(UINT16 adr, UINT8 val); + }; + + class mi_2a03_nd : public memory_interface { + public: + virtual ~mi_2a03_nd() {} + virtual UINT8 read(UINT16 adr); + virtual UINT8 read_sync(UINT16 adr); + virtual UINT8 read_arg(UINT16 adr); + virtual void write(UINT16 adr, UINT8 val); + }; + + virtual void device_start(); + +#define O(o) void o ## _full(); void o ## _partial() + + // n2a03 opcodes - same as 6502 with D disabled + O(adc_nd_aba); O(adc_nd_abx); O(adc_nd_aby); O(adc_nd_idx); O(adc_nd_idy); O(adc_nd_imm); O(adc_nd_zpg); O(adc_nd_zpx); + O(arr_nd_imm); + O(isb_nd_aba); O(isb_nd_abx); O(isb_nd_aby); O(isb_nd_idx); O(isb_nd_idy); O(isb_nd_zpg); O(isb_nd_zpx); + O(rra_nd_aba); O(rra_nd_abx); O(rra_nd_aby); O(rra_nd_idx); O(rra_nd_idy); O(rra_nd_zpg); O(rra_nd_zpx); + O(sbc_nd_aba); O(sbc_nd_abx); O(sbc_nd_aby); O(sbc_nd_idx); O(sbc_nd_idy); O(sbc_nd_imm); O(sbc_nd_zpg); O(sbc_nd_zpx); + +#undef O +}; + +#define N2A03_DEFAULTCLOCK (21477272.724 / 12) + +enum { + N2A03_IRQ_LINE = m6502_device::IRQ_LINE, + N2A03_APU_IRQ_LINE = m6502_device::APU_IRQ_LINE, + N2A03_NMI_LINE = m6502_device::NMI_LINE, + N2A03_SET_OVERFLOW = m6502_device::V_LINE +}; + +extern const device_type N2A03; + +#endif diff --git a/src/devices/cpu/m6502/odeco16.lst b/src/devices/cpu/m6502/odeco16.lst new file mode 100644 index 00000000000..6cea2fa7282 --- /dev/null +++ b/src/devices/cpu/m6502/odeco16.lst @@ -0,0 +1,101 @@ +# deco 16 opcodes +brk_16_imp + // The 6502 bug when a nmi occurs in a brk is reproduced (case !irq_taken && nmi_state) + if(irq_taken) { + read_pc_noinc(); + } else { + read_pc(); + } + write(SP, PC >> 8); + dec_SP(); + write(SP, PC); + dec_SP(); + write(SP, irq_taken ? P & ~F_B : P); + dec_SP(); + if(nmi_state) { + PC = read_arg(0xfff7); + PC = set_h(PC, read_arg(0xfff6)); + nmi_state = false; + standard_irq_callback(NMI_LINE); + } else { + PC = read_arg(0xfff3); + PC = set_h(PC, read_arg(0xfff2)); + if(irq_taken) + standard_irq_callback(IRQ_LINE); + } + irq_taken = false; + P |= F_I; // Do *not* move after the prefetch + prefetch(); + inst_state = -1; + +ill_non + logerror("%s: Unimplemented instruction %02x\n", tag(), inst_state); + prefetch(); + +u0B_zpg + TMP2 = read_pc(); + if(DECO16_VERBOSE) + logerror("%s: OP0B %02x (%04x)\n", tag(), NPC, TMP2); + prefetch(); + +u13_zpg + TMP2 = read_pc(); + if(DECO16_VERBOSE) + logerror("%s: OP13 %02x (%04x)\n", tag(), NPC, TMP2); + prefetch(); + +u23_zpg + TMP2 = read_pc(); + if(DECO16_VERBOSE) + logerror("%s: OP23 %02x (%04x)\n", tag(), NPC, TMP2); + prefetch(); + +u3F_zpg + TMP2 = read_pc(); + if(DECO16_VERBOSE) + logerror("%s: OPBB %02x (%04x)\n", tag(), NPC, TMP2); + prefetch(); + +u4B_zpg + TMP2 = read_pc(); + A = io->read_byte(1); + prefetch(); + +u87_zpg + TMP2 = read_pc(); + if(DECO16_VERBOSE) + logerror("%s: OP87 %02x (%04x)\n", tag(), NPC, TMP2); + prefetch(); + +u8F_zpg + TMP2 = read_pc(); + if(DECO16_VERBOSE) + logerror("%s: OP8F (BANK) %02x (%04x)\n", tag(), NPC, TMP2); + io->write_byte(0, TMP2); + prefetch(); + +uA3_zpg + TMP2 = read_pc(); + if(DECO16_VERBOSE) + logerror("%s: OPA3 %02x (%04x)\n", tag(), NPC, TMP2); + prefetch(); + +uBB_zpg + TMP2 = read_pc(); + if(DECO16_VERBOSE) + logerror("%s: OPBB %02x (%04x)\n", tag(), NPC, TMP2); + prefetch(); + +vbl_zpg + TMP2 = read_pc(); + A = io->read_byte(0); + if(DECO16_VERBOSE) + logerror("%s: VBL %02x (%04x)\n", tag(), NPC, TMP2); + prefetch(); + +# exceptions +reset_16 + PC = read_arg(0xfff1); + PC = set_h(PC, read_arg(0xfff0)); + prefetch(); + inst_state = -1; diff --git a/src/devices/cpu/m6502/om4510.lst b/src/devices/cpu/m6502/om4510.lst new file mode 100644 index 00000000000..fbe49491fac --- /dev/null +++ b/src/devices/cpu/m6502/om4510.lst @@ -0,0 +1,21 @@ +# 4510 opcodes + +eom_imp + inhibit_interrupts = false; // before or after prefetch? + prefetch(); + +map_imp + inhibit_interrupts = true; + map_offset[0] = (A<<8) | ((X & 0xf) << 16); + map_offset[1] = (Y<<8) | ((Z & 0xf) << 16); + map_enable = ((X & 0xf0) >> 4) | (Z & 0xf0); + logerror("MAP execute\n"); + logerror("0x0000 - 0x1fff = %08x\n",map_enable & 1 ? map_offset[0]+0x0000 : 0x0000); + logerror("0x2000 - 0x3fff = %08x\n",map_enable & 2 ? map_offset[0]+0x2000 : 0x2000); + logerror("0x4000 - 0x5fff = %08x\n",map_enable & 4 ? map_offset[0]+0x4000 : 0x4000); + logerror("0x6000 - 0x7fff = %08x\n",map_enable & 8 ? map_offset[0]+0x6000 : 0x6000); + logerror("0x8000 - 0x9fff = %08x\n",map_enable & 16 ? map_offset[1]+0x8000 : 0x8000); + logerror("0xa000 - 0xbfff = %08x\n",map_enable & 32 ? map_offset[1]+0xa000 : 0xa000); + logerror("0xc000 - 0xdfff = %08x\n",map_enable & 64 ? map_offset[1]+0xc000 : 0xc000); + logerror("0xe000 - 0xffff = %08x\n",map_enable & 128 ? map_offset[1]+0xe000 : 0xe000); + prefetch(); diff --git a/src/devices/cpu/m6502/om6502.lst b/src/devices/cpu/m6502/om6502.lst new file mode 100644 index 00000000000..24c560c02fa --- /dev/null +++ b/src/devices/cpu/m6502/om6502.lst @@ -0,0 +1,1964 @@ +# NMOS 6502 opcodes +# Verified with visual6502 +# documented opcodes + +adc_aba + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + TMP = read(TMP); + do_adc(TMP); + prefetch(); + +adc_abx + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + if(page_changing(TMP, X)) { + read(set_l(TMP, TMP+X)); + } + TMP += X; + TMP = read(TMP); + do_adc(TMP); + prefetch(); + +adc_aby + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + if(page_changing(TMP, Y)) { + read(set_l(TMP, TMP+Y)); + } + TMP += Y; + TMP = read(TMP); + do_adc(TMP); + prefetch(); + +adc_idx + TMP2 = read_pc(); + read(TMP2); + TMP2 += X; + TMP = read(TMP2 & 0xff); + TMP = set_h(TMP, read((TMP2+1) & 0xff)); + do_adc(read(TMP)); + prefetch(); + +adc_idy + TMP2 = read_pc(); + TMP = read(TMP2); + TMP = set_h(TMP, read((TMP2+1) & 0xff)); + if(page_changing(TMP, Y)) { + read(set_l(TMP, TMP+Y)); + } + do_adc(read(TMP+Y)); + prefetch(); + +adc_imm + TMP = read_pc(); + do_adc(TMP); + prefetch(); + +adc_zpg + TMP = read_pc(); + TMP = read(TMP); + do_adc(TMP); + prefetch(); + +adc_zpx + TMP = read_pc(); + read(TMP); + TMP = read(UINT8(TMP+X)); + do_adc(TMP); + prefetch(); + +and_aba + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + A &= read(TMP); + set_nz(A); + prefetch(); + +and_abx + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + if(page_changing(TMP, X)) { + read(set_l(TMP, TMP+X)); + } + TMP += X; + A &= read(TMP); + set_nz(A); + prefetch(); + +and_aby + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + if(page_changing(TMP, Y)) { + read(set_l(TMP, TMP+Y)); + } + TMP += Y; + A &= read(TMP); + set_nz(A); + prefetch(); + +and_imm + A &= read_pc(); + set_nz(A); + prefetch(); + +and_idx + TMP2 = read_pc(); + read(TMP2); + TMP2 += X; + TMP = read(TMP2 & 0xff); + TMP = set_h(TMP, read((TMP2+1) & 0xff)); + A &= read(TMP); + set_nz(A); + prefetch(); + +and_idy + TMP2 = read_pc(); + TMP = read(TMP2); + TMP = set_h(TMP, read((TMP2+1) & 0xff)); + if(page_changing(TMP, Y)) { + read(set_l(TMP, TMP+Y)); + } + A &= read(TMP+Y); + set_nz(A); + prefetch(); + +and_zpg + TMP = read_pc(); + A &= read(TMP); + set_nz(A); + prefetch(); + +and_zpx + TMP = read_pc(); + read(TMP); + A &= read(UINT8(TMP+X)); + set_nz(A); + prefetch(); + +asl_aba + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + TMP2 = read(TMP); + write(TMP, TMP2); + TMP2 = do_asl(TMP2); + write(TMP, TMP2); + prefetch(); + +asl_abx + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + read(set_l(TMP, TMP+X)); + TMP += X; + TMP2 = read(TMP); + write(TMP, TMP2); + TMP2 = do_asl(TMP2); + write(TMP, TMP2); + prefetch(); + +asl_acc + read_pc_noinc(); + A = do_asl(A); + prefetch(); + +asl_zpg + TMP = read_pc(); + TMP2 = read(TMP); + write(TMP, TMP2); + TMP2 = do_asl(TMP2); + write(TMP, TMP2); + prefetch(); + +asl_zpx + TMP = read_pc(); + read(TMP); + TMP = UINT8(TMP+X); + TMP2 = read(TMP); + write(TMP, TMP2); + TMP2 = do_asl(TMP2); + write(TMP, TMP2); + prefetch(); + +bcc_rel + TMP = read_pc(); + if(!(P & F_C)) { + read_pc_noinc(); + if(page_changing(PC, INT8(TMP))) { + read_arg(set_l(PC, PC+INT8(TMP))); + } + PC += INT8(TMP); + } + prefetch(); + +bcs_rel + TMP = read_pc(); + if(P & F_C) { + read_pc_noinc(); + if(page_changing(PC, INT8(TMP))) { + read_arg(set_l(PC, PC+INT8(TMP))); + } + PC += INT8(TMP); + } + prefetch(); + +beq_rel + TMP = read_pc(); + if(P & F_Z) { + read_pc_noinc(); + if(page_changing(PC, INT8(TMP))) { + read_arg(set_l(PC, PC+INT8(TMP))); + } + PC += INT8(TMP); + } + prefetch(); + +bit_aba + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + do_bit(read(TMP)); + prefetch(); + +bit_zpg + TMP = read_pc(); + do_bit(read(TMP)); + prefetch(); + +bmi_rel + TMP = read_pc(); + if(P & F_N) { + read_pc_noinc(); + if(page_changing(PC, INT8(TMP))) { + read_arg(set_l(PC, PC+INT8(TMP))); + } + PC += INT8(TMP); + } + prefetch(); + +bne_rel + TMP = read_pc(); + if(!(P & F_Z)) { + read_pc_noinc(); + if(page_changing(PC, INT8(TMP))) { + read_arg(set_l(PC, PC+INT8(TMP))); + } + PC += INT8(TMP); + } + prefetch(); + +bpl_rel + TMP = read_pc(); + if(!(P & F_N)) { + read_pc_noinc(); + if(page_changing(PC, INT8(TMP))) { + read_arg(set_l(PC, PC+INT8(TMP))); + } + PC += INT8(TMP); + } + prefetch(); + +brk_imp + // The 6502 bug when a nmi occurs in a brk is reproduced (case !irq_taken && nmi_state) + if(irq_taken) { + read_pc_noinc(); + } else { + read_pc(); + } + write(SP, PC >> 8); + dec_SP(); + write(SP, PC); + dec_SP(); + write(SP, irq_taken ? P & ~F_B : P); + dec_SP(); + if(nmi_state) { + PC = read_arg(0xfffa); + PC = set_h(PC, read_arg(0xfffb)); + nmi_state = false; + standard_irq_callback(NMI_LINE); + } else { + PC = read_arg(0xfffe); + PC = set_h(PC, read_arg(0xffff)); + if(irq_taken) + standard_irq_callback(IRQ_LINE); + } + irq_taken = false; + P |= F_I; // Do *not* move after the prefetch + prefetch(); + inst_state = -1; + +bvc_rel + TMP = read_pc(); + if(!(P & F_V)) { + read_pc_noinc(); + if(page_changing(PC, INT8(TMP))) { + read_arg(set_l(PC, PC+INT8(TMP))); + } + PC += INT8(TMP); + } + prefetch(); + +bvs_rel + TMP = read_pc(); + if(P & F_V) { + read_pc_noinc(); + if(page_changing(PC, INT8(TMP))) { + read_arg(set_l(PC, PC+INT8(TMP))); + } + PC += INT8(TMP); + } + prefetch(); + +clc_imp + read_pc_noinc(); + P &= ~F_C; + prefetch(); + +cld_imp + read_pc_noinc(); + P &= ~F_D; + prefetch(); + +cli_imp + read_pc_noinc(); + prefetch(); + P &= ~F_I; // Do *not* move it before the prefetch + +clv_imp + read_pc_noinc(); + P &= ~F_V; + prefetch(); + +cmp_aba + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + TMP = read(TMP); + do_cmp(A, TMP); + prefetch(); + +cmp_abx + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + if(page_changing(TMP, X)) { + read(set_l(TMP, TMP+X)); + } + TMP += X; + TMP = read(TMP); + do_cmp(A, TMP); + prefetch(); + +cmp_aby + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + if(page_changing(TMP, Y)) { + read(set_l(TMP, TMP+Y)); + } + TMP += Y; + TMP = read(TMP); + do_cmp(A, TMP); + prefetch(); + +cmp_idx + TMP2 = read_pc(); + read(TMP2); + TMP2 += X; + TMP = read(TMP2 & 0xff); + TMP = set_h(TMP, read((TMP2+1) & 0xff)); + do_cmp(A, read(TMP)); + prefetch(); + +cmp_idy + TMP2 = read_pc(); + TMP = read(TMP2); + TMP = set_h(TMP, read((TMP2+1) & 0xff)); + if(page_changing(TMP, Y)) { + read(set_l(TMP, TMP+Y)); + } + do_cmp(A, read(TMP+Y)); + prefetch(); + +cmp_imm + TMP = read_pc(); + do_cmp(A, TMP); + prefetch(); + +cmp_zpg + TMP = read_pc(); + TMP = read(TMP); + do_cmp(A, TMP); + prefetch(); + +cmp_zpx + TMP = read_pc(); + read(TMP); + TMP = read(UINT8(TMP+X)); + do_cmp(A, TMP); + prefetch(); + +cpx_aba + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + TMP = read(TMP); + do_cmp(X, TMP); + prefetch(); + +cpx_imm + TMP = read_pc(); + do_cmp(X, TMP); + prefetch(); + +cpx_zpg + TMP = read_pc(); + TMP = read(TMP); + do_cmp(X, TMP); + prefetch(); + +cpy_aba + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + TMP = read(TMP); + do_cmp(Y, TMP); + prefetch(); + +cpy_imm + TMP = read_pc(); + do_cmp(Y, TMP); + prefetch(); + +cpy_zpg + TMP = read_pc(); + TMP = read(TMP); + do_cmp(Y, TMP); + prefetch(); + +dec_aba + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + TMP2 = read(TMP); + write(TMP, TMP2); + TMP2--; + set_nz(TMP2); + write(TMP, TMP2); + prefetch(); + +dec_abx + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + read(set_l(TMP, TMP+X)); + TMP += X; + TMP2 = read(TMP); + write(TMP, TMP2); + TMP2--; + set_nz(TMP2); + write(TMP, TMP2); + prefetch(); + +dec_zpg + TMP = read_pc(); + TMP2 = read(TMP); + write(TMP, TMP2); + TMP2--; + set_nz(TMP2); + write(TMP, TMP2); + prefetch(); + +dec_zpx + TMP = read_pc(); + read(TMP); + TMP = UINT8(TMP+X); + TMP2 = read(TMP); + write(TMP, TMP2); + TMP2--; + set_nz(TMP2); + write(TMP, TMP2); + prefetch(); + +dex_imp + read_pc_noinc(); + X--; + set_nz(X); + prefetch(); + +dey_imp + read_pc_noinc(); + Y--; + set_nz(Y); + prefetch(); + +eor_aba + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + A ^= read(TMP); + set_nz(A); + prefetch(); + +eor_abx + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + if(page_changing(TMP, X)) { + read(set_l(TMP, TMP+X)); + } + TMP += X; + A ^= read(TMP); + set_nz(A); + prefetch(); + +eor_aby + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + if(page_changing(TMP, Y)) { + read(set_l(TMP, TMP+Y)); + } + TMP += Y; + A ^= read(TMP); + set_nz(A); + prefetch(); + +eor_idx + TMP2 = read_pc(); + read(TMP2); + TMP2 += X; + TMP = read(TMP2 & 0xff); + TMP = set_h(TMP, read((TMP2+1) & 0xff)); + A ^= read(TMP); + set_nz(A); + prefetch(); + +eor_idy + TMP2 = read_pc(); + TMP = read(TMP2); + TMP = set_h(TMP, read((TMP2+1) & 0xff)); + if(page_changing(TMP, Y)) { + read(set_l(TMP, TMP+Y)); + } + A ^= read(TMP+Y); + set_nz(A); + prefetch(); + +eor_imm + A ^= read_pc(); + set_nz(A); + prefetch(); + +eor_zpg + TMP = read_pc(); + A ^= read(TMP); + set_nz(A); + prefetch(); + +eor_zpx + TMP = read_pc(); + read(TMP); + A ^= read(UINT8(TMP+X)); + set_nz(A); + prefetch(); + +inc_aba + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + TMP2 = read(TMP); + write(TMP, TMP2); + TMP2++; + set_nz(TMP2); + write(TMP, TMP2); + prefetch(); + +inc_abx + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + read(set_l(TMP, TMP+X)); + TMP += X; + TMP2 = read(TMP); + write(TMP, TMP2); + TMP2++; + set_nz(TMP2); + write(TMP, TMP2); + prefetch(); + +inc_zpg + TMP = read_pc(); + TMP2 = read(TMP); + write(TMP, TMP2); + TMP2++; + set_nz(TMP2); + write(TMP, TMP2); + prefetch(); + +inc_zpx + TMP = read_pc(); + read(TMP); + TMP = UINT8(TMP+X); + TMP2 = read(TMP); + write(TMP, TMP2); + TMP2++; + set_nz(TMP2); + write(TMP, TMP2); + prefetch(); + +inx_imp + read_pc_noinc(); + X++; + set_nz(X); + prefetch(); + +iny_imp + read_pc_noinc(); + Y++; + set_nz(Y); + prefetch(); + +jmp_adr + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + PC = TMP; + prefetch(); + +jmp_ind + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + PC = read(TMP); + PC = set_h(PC, read(set_l(TMP, TMP+1))); + prefetch(); + +jsr_adr + TMP = read_pc(); + read(SP); + write(SP, PC>>8); + dec_SP(); + write(SP, PC); + dec_SP(); + TMP = set_h(TMP, read_pc()); + PC = TMP; + prefetch(); + +lda_aba + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + A = read(TMP); + set_nz(A); + prefetch(); + +lda_abx + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + if(page_changing(TMP, X)) { + read(set_l(TMP, TMP+X)); + } + A = read(TMP + X); + set_nz(A); + prefetch(); + +lda_aby + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + if(page_changing(TMP, Y)) { + read(set_l(TMP, TMP+Y)); + } + A = read(TMP + Y); + set_nz(A); + prefetch(); + +lda_idx + TMP2 = read_pc(); + read(TMP2); + TMP2 += X; + TMP = read(TMP2 & 0xff); + TMP = set_h(TMP, read((TMP2+1) & 0xff)); + A = read(TMP); + set_nz(A); + prefetch(); + +lda_idy + TMP2 = read_pc(); + TMP = read(TMP2); + TMP = set_h(TMP, read((TMP2+1) & 0xff)); + if(page_changing(TMP, Y)) { + read(set_l(TMP, TMP+Y)); + } + A = read(TMP+Y); + set_nz(A); + prefetch(); + +lda_imm + A = read_pc(); + set_nz(A); + prefetch(); + +lda_zpg + TMP = read_pc(); + A = read(TMP); + set_nz(A); + prefetch(); + +lda_zpx + TMP = read_pc(); + read(TMP); + A = read(UINT8(TMP+X)); + set_nz(A); + prefetch(); + +ldx_aba + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + X = read(TMP); + set_nz(X); + prefetch(); + +ldx_aby + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + if(page_changing(TMP, Y)) { + read(set_l(TMP, TMP+Y)); + } + X = read(TMP + Y); + set_nz(X); + prefetch(); + +ldx_imm + X = read_pc(); + set_nz(X); + prefetch(); + +ldx_zpg + TMP = read_pc(); + X = read(TMP); + set_nz(X); + prefetch(); + +ldx_zpy + TMP = read_pc(); + read(TMP); + X = read(UINT8(TMP+Y)); + set_nz(X); + prefetch(); + +ldy_aba + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + Y = read(TMP); + set_nz(Y); + prefetch(); + +ldy_abx + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + if(page_changing(TMP, X)) { + read(set_l(TMP, TMP+X)); + } + TMP += X; + Y = read(TMP); + set_nz(Y); + prefetch(); + +ldy_imm + Y = read_pc(); + set_nz(Y); + prefetch(); + +ldy_zpg + TMP = read_pc(); + Y = read(TMP); + set_nz(Y); + prefetch(); + +ldy_zpx + TMP = read_pc(); + read(TMP); + Y = read(UINT8(TMP+X)); + set_nz(Y); + prefetch(); + +lsr_aba + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + TMP2 = read(TMP); + write(TMP, TMP2); + TMP2 = do_lsr(TMP2); + write(TMP, TMP2); + prefetch(); + +lsr_abx + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + read(set_l(TMP, TMP+X)); + TMP += X; + TMP2 = read(TMP); + write(TMP, TMP2); + TMP2 = do_lsr(TMP2); + write(TMP, TMP2); + prefetch(); + +lsr_acc + read_pc_noinc(); + A = do_lsr(A); + prefetch(); + +lsr_zpg + TMP = read_pc(); + TMP2 = read(TMP); + write(TMP, TMP2); + TMP2 = do_lsr(TMP2); + write(TMP, TMP2); + prefetch(); + +lsr_zpx + TMP = read_pc(); + read(TMP); + TMP = UINT8(TMP+X); + TMP2 = read(TMP); + write(TMP, TMP2); + TMP2 = do_lsr(TMP2); + write(TMP, TMP2); + prefetch(); + +nop_imp + read_pc_noinc(); + prefetch(); + +ora_aba + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + A |= read(TMP); + set_nz(A); + prefetch(); + +ora_abx + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + if(page_changing(TMP, X)) { + read(set_l(TMP, TMP+X)); + } + TMP += X; + A |= read(TMP); + set_nz(A); + prefetch(); + +ora_aby + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + if(page_changing(TMP, Y)) { + read(set_l(TMP, TMP+Y)); + } + TMP += Y; + A |= read(TMP); + set_nz(A); + prefetch(); + +ora_imm + A |= read_pc(); + set_nz(A); + prefetch(); + +ora_idx + TMP2 = read_pc(); + read(TMP2); + TMP2 += X; + TMP = read(TMP2 & 0xff); + TMP = set_h(TMP, read((TMP2+1) & 0xff)); + A |= read(TMP); + set_nz(A); + prefetch(); + +ora_idy + TMP2 = read_pc(); + TMP = read(TMP2); + TMP = set_h(TMP, read((TMP2+1) & 0xff)); + if(page_changing(TMP, Y)) { + read(set_l(TMP, TMP+Y)); + } + A |= read(TMP+Y); + set_nz(A); + prefetch(); + +ora_zpg + TMP = read_pc(); + A |= read(TMP); + set_nz(A); + prefetch(); + +ora_zpx + TMP = read_pc(); + read(TMP); + A |= read(UINT8(TMP+X)); + set_nz(A); + prefetch(); + +pha_imp + read_pc_noinc(); + write(SP, A); + dec_SP(); + prefetch(); + +php_imp + read_pc_noinc(); + write(SP, P); + dec_SP(); + prefetch(); + +pla_imp + read_pc_noinc(); + read(SP); + inc_SP(); + A = read(SP); + set_nz(A); + prefetch(); + +plp_imp + read_pc_noinc(); + read(SP); + inc_SP(); + TMP = read(SP) | (F_B|F_E); + prefetch(); + P = TMP; // Do *not* move it before the prefetch + +rol_aba + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + TMP2 = read(TMP); + write(TMP, TMP2); + TMP2 = do_rol(TMP2); + write(TMP, TMP2); + prefetch(); + +rol_abx + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + read(set_l(TMP, TMP+X)); + TMP += X; + TMP2 = read(TMP); + write(TMP, TMP2); + TMP2 = do_rol(TMP2); + write(TMP, TMP2); + prefetch(); + +rol_acc + read_pc_noinc(); + A = do_rol(A); + prefetch(); + +rol_zpg + TMP = read_pc(); + TMP2 = read(TMP); + write(TMP, TMP2); + TMP2 = do_rol(TMP2); + write(TMP, TMP2); + prefetch(); + +rol_zpx + TMP = read_pc(); + read(TMP); + TMP = UINT8(TMP+X); + TMP2 = read(TMP); + write(TMP, TMP2); + TMP2 = do_rol(TMP2); + write(TMP, TMP2); + prefetch(); + +ror_aba + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + TMP2 = read(TMP); + write(TMP, TMP2); + TMP2 = do_ror(TMP2); + write(TMP, TMP2); + prefetch(); + +ror_abx + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + read(set_l(TMP, TMP+X)); + TMP += X; + TMP2 = read(TMP); + write(TMP, TMP2); + TMP2 = do_ror(TMP2); + write(TMP, TMP2); + prefetch(); + +ror_acc + read_pc_noinc(); + A = do_ror(A); + prefetch(); + +ror_zpg + TMP = read_pc(); + TMP2 = read(TMP); + write(TMP, TMP2); + TMP2 = do_ror(TMP2); + write(TMP, TMP2); + prefetch(); + +ror_zpx + TMP = read_pc(); + read(TMP); + TMP = UINT8(TMP+X); + TMP2 = read(TMP); + write(TMP, TMP2); + TMP2 = do_ror(TMP2); + write(TMP, TMP2); + prefetch(); + +rti_imp + read_pc_noinc(); + read(SP); + inc_SP(); + P = read(SP) | (F_B|F_E); + inc_SP(); + PC = read(SP); + inc_SP(); + PC = set_h(PC, read(SP)); + prefetch(); + +rts_imp + read_pc_noinc(); + read(SP); + inc_SP(); + PC = read(SP); + inc_SP(); + PC = set_h(PC, read(SP)); + read_pc(); + prefetch(); + +sbc_aba + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + TMP = read(TMP); + do_sbc(TMP); + prefetch(); + +sbc_abx + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + if(page_changing(TMP, X)) { + read(set_l(TMP, TMP+X)); + } + TMP += X; + TMP = read(TMP); + do_sbc(TMP); + prefetch(); + +sbc_aby + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + if(page_changing(TMP, Y)) { + read(set_l(TMP, TMP+Y)); + } + TMP += Y; + TMP = read(TMP); + do_sbc(TMP); + prefetch(); + +sbc_idx + TMP2 = read_pc(); + read(TMP2); + TMP2 += X; + TMP = read(TMP2 & 0xff); + TMP = set_h(TMP, read((TMP2+1) & 0xff)); + do_sbc(read(TMP)); + prefetch(); + +sbc_idy + TMP2 = read_pc(); + TMP = read(TMP2); + TMP = set_h(TMP, read((TMP2+1) & 0xff)); + if(page_changing(TMP, Y)) { + read(set_l(TMP, TMP+Y)); + } + do_sbc(read(TMP+Y)); + prefetch(); + +sbc_imm + TMP = read_pc(); + do_sbc(TMP); + prefetch(); + +sbc_zpg + TMP = read_pc(); + TMP = read(TMP); + do_sbc(TMP); + prefetch(); + +sbc_zpx + TMP = read_pc(); + read(TMP); + TMP = read(UINT8(TMP+X)); + do_sbc(TMP); + prefetch(); + +sec_imp + read_pc_noinc(); + P |= F_C; + prefetch(); + +sed_imp + read_pc_noinc(); + P |= F_D; + prefetch(); + +sei_imp + read_pc_noinc(); + prefetch(); + P |= F_I; // Do *not* move it before the prefetch + +sta_aba + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + write(TMP, A); + prefetch(); + +sta_abx + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + read(set_l(TMP, TMP+X)); + write(TMP+X, A); + prefetch(); + +sta_aby + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + read(set_l(TMP, TMP+Y)); + write(TMP+Y, A); + prefetch(); + +sta_idx + TMP2 = read_pc(); + read(TMP2); + TMP2 += X; + TMP = read(TMP2 & 0xff); + TMP = set_h(TMP, read((TMP2+1) & 0xff)); + write(TMP, A); + prefetch(); + +sta_idy + TMP2 = read_pc(); + TMP = read(TMP2); + TMP = set_h(TMP, read((TMP2+1) & 0xff)); + read(set_l(TMP, TMP+Y)); + write(TMP+Y, A); + prefetch(); + +sta_zpg + TMP = read_pc(); + write(TMP, A); + prefetch(); + +sta_zpx + TMP = read_pc(); + read(TMP); + write(UINT8(TMP+X), A); + prefetch(); + +stx_aba + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + write(TMP, X); + prefetch(); + +stx_zpg + TMP = read_pc(); + write(TMP, X); + prefetch(); + +stx_zpy + TMP = read_pc(); + read(TMP); + write(UINT8(TMP+Y), X); + prefetch(); + +sty_aba + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + write(TMP, Y); + prefetch(); + +sty_zpg + TMP = read_pc(); + write(TMP, Y); + prefetch(); + +sty_zpx + TMP = read_pc(); + read(TMP); + write(UINT8(TMP+X), Y); + prefetch(); + +tax_imp + read_pc_noinc(); + X = A; + set_nz(X); + prefetch(); + +tay_imp + read_pc_noinc(); + Y = A; + set_nz(Y); + prefetch(); + +tsx_imp + read_pc_noinc(); + X = SP; + set_nz(X); + prefetch(); + +txa_imp + read_pc_noinc(); + A = X; + set_nz(A); + prefetch(); + +txs_imp + read_pc_noinc(); + SP = set_l(SP, X); + prefetch(); + +tya_imp + read_pc_noinc(); + A = Y; + set_nz(A); + prefetch(); + +# exceptions +reset + PC = read_arg(0xfffc); + PC = set_h(PC, read_arg(0xfffd)); + prefetch(); + inst_state = -1; + + +# undocumented reliable instructions +dcp_aba + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + TMP2 = read(TMP); + write(TMP, TMP2); + TMP2--; + write(TMP, TMP2); + do_cmp(A, TMP2); + prefetch(); + +dcp_abx + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + read(set_l(TMP, TMP+X)); + TMP += X; + TMP2 = read(TMP); + write(TMP, TMP2); + TMP2--; + write(TMP, TMP2); + do_cmp(A, TMP2); + prefetch(); + +dcp_aby + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + read(set_l(TMP, TMP+Y)); + TMP += Y; + TMP2 = read(TMP); + write(TMP, TMP2); + TMP2--; + write(TMP, TMP2); + do_cmp(A, TMP2); + prefetch(); + +dcp_idx + TMP2 = read_pc(); + read(TMP2); + TMP2 += X; + TMP = read(TMP2 & 0xff); + TMP = set_h(TMP, read((TMP2+1) & 0xff)); + TMP2 = read(TMP); + write(TMP, TMP2); + TMP2--; + write(TMP, TMP2); + do_cmp(A, TMP2); + prefetch(); + +dcp_idy + TMP2 = read_pc(); + TMP = read(TMP2); + TMP = set_h(TMP, read((TMP2+1) & 0xff)); + read(set_l(TMP, TMP+Y)); + TMP += Y; + TMP2 = read(TMP); + write(TMP, TMP2); + TMP2--; + write(TMP, TMP2); + do_cmp(A, TMP2); + prefetch(); + +dcp_zpg + TMP = read_pc(); + TMP2 = read(TMP); + write(TMP, TMP2); + TMP2--; + write(TMP, TMP2); + do_cmp(A, TMP2); + prefetch(); + +dcp_zpx + TMP = read_pc(); + read(TMP); + TMP = UINT8(TMP+X); + TMP2 = read(TMP); + write(TMP, TMP2); + TMP2--; + write(TMP, TMP2); + do_cmp(A, TMP2); + prefetch(); + +isb_aba + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + TMP2 = read(TMP); + write(TMP, TMP2); + TMP2++; + write(TMP, TMP2); + do_sbc(TMP2); + prefetch(); + +isb_abx + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + read(set_l(TMP, TMP+X)); + TMP += X; + TMP2 = read(TMP); + write(TMP, TMP2); + TMP2++; + write(TMP, TMP2); + do_sbc(TMP2); + prefetch(); + +isb_aby + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + read(set_l(TMP, TMP+Y)); + TMP += Y; + TMP2 = read(TMP); + write(TMP, TMP2); + TMP2++; + write(TMP, TMP2); + do_sbc(TMP2); + prefetch(); + +isb_idx + TMP2 = read_pc(); + read(TMP2); + TMP2 += X; + TMP = read(TMP2 & 0xff); + TMP = set_h(TMP, read((TMP2+1) & 0xff)); + TMP2 = read(TMP); + write(TMP, TMP2); + TMP2++; + write(TMP, TMP2); + do_sbc(TMP2); + prefetch(); + +isb_idy + TMP2 = read_pc(); + TMP = read(TMP2); + TMP = set_h(TMP, read((TMP2+1) & 0xff)); + read(set_l(TMP, TMP+Y)); + TMP += Y; + TMP2 = read(TMP); + write(TMP, TMP2); + TMP2++; + write(TMP, TMP2); + do_sbc(TMP2); + prefetch(); + +isb_zpg + TMP = read_pc(); + TMP2 = read(TMP); + write(TMP, TMP2); + TMP2++; + write(TMP, TMP2); + do_sbc(TMP2); + prefetch(); + +isb_zpx + TMP = read_pc(); + read(TMP); + TMP = UINT8(TMP+X); + TMP2 = read(TMP); + write(TMP, TMP2); + TMP2++; + write(TMP, TMP2); + do_sbc(TMP2); + prefetch(); + +lax_aba + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + A = X = read(TMP); + set_nz(A); + prefetch(); + +lax_aby + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + read(set_l(TMP, TMP+Y)); + TMP += Y; + A = X = read(TMP); + set_nz(A); + prefetch(); + +lax_idx + TMP2 = read_pc(); + read(TMP2); + TMP2 += X; + TMP = read(TMP2 & 0xff); + TMP = set_h(TMP, read((TMP2+1) & 0xff)); + A = X = read(TMP); + set_nz(A); + prefetch(); + +lax_idy + TMP2 = read_pc(); + TMP = read(TMP2); + TMP = set_h(TMP, read((TMP2+1) & 0xff)); + if(page_changing(TMP, Y)) { + read(set_l(TMP, TMP+Y)); + } + A = X = read(TMP+Y); + set_nz(A); + prefetch(); + +lax_zpg + TMP = read_pc(); + A = X = read(TMP); + set_nz(A); + prefetch(); + +lax_zpy + TMP = read_pc(); + read(TMP); + TMP = UINT8(TMP+Y); + A = X = read(TMP); + set_nz(A); + prefetch(); + +rla_aba + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + TMP2 = read(TMP); + write(TMP, TMP2); + TMP2 = do_rol(TMP2); + write(TMP, TMP2); + A &= TMP2; + set_nz(A); + prefetch(); + +rla_abx + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + read(set_l(TMP, TMP+X)); + TMP += X; + TMP2 = read(TMP); + write(TMP, TMP2); + TMP2 = do_rol(TMP2); + write(TMP, TMP2); + A &= TMP2; + set_nz(A); + prefetch(); + +rla_aby + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + read(set_l(TMP, TMP+Y)); + TMP += Y; + TMP2 = read(TMP); + write(TMP, TMP2); + TMP2 = do_rol(TMP2); + write(TMP, TMP2); + A &= TMP2; + set_nz(A); + prefetch(); + +rla_idx + TMP2 = read_pc(); + read(TMP2); + TMP2 += X; + TMP = read(TMP2 & 0xff); + TMP = set_h(TMP, read((TMP2+1) & 0xff)); + TMP2 = read(TMP); + write(TMP, TMP2); + TMP2 = do_rol(TMP2); + write(TMP, TMP2); + A &= TMP2; + set_nz(A); + prefetch(); + +rla_idy + TMP2 = read_pc(); + TMP = read(TMP2); + TMP = set_h(TMP, read((TMP2+1) & 0xff)); + read(set_l(TMP, TMP+Y)); + TMP += Y; + TMP2 = read(TMP); + write(TMP, TMP2); + TMP2 = do_rol(TMP2); + write(TMP, TMP2); + A &= TMP2; + set_nz(A); + prefetch(); + +rla_zpg + TMP = read_pc(); + TMP2 = read(TMP); + write(TMP, TMP2); + TMP2 = do_rol(TMP2); + write(TMP, TMP2); + A &= TMP2; + set_nz(A); + prefetch(); + +rla_zpx + TMP = read_pc(); + read(TMP); + TMP = UINT8(TMP+X); + TMP2 = read(TMP); + write(TMP, TMP2); + TMP2 = do_rol(TMP2); + write(TMP, TMP2); + A &= TMP2; + set_nz(A); + prefetch(); + +rra_aba + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + TMP2 = read(TMP); + write(TMP, TMP2); + TMP2 = do_ror(TMP2); + write(TMP, TMP2); + do_adc(TMP2); + prefetch(); + +rra_abx + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + read(set_l(TMP, TMP+X)); + TMP += X; + TMP2 = read(TMP); + write(TMP, TMP2); + TMP2 = do_ror(TMP2); + write(TMP, TMP2); + do_adc(TMP2); + prefetch(); + +rra_aby + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + read(set_l(TMP, TMP+Y)); + TMP += Y; + TMP2 = read(TMP); + write(TMP, TMP2); + TMP2 = do_ror(TMP2); + write(TMP, TMP2); + do_adc(TMP2); + prefetch(); + +rra_idx + TMP2 = read_pc(); + read(TMP2); + TMP2 += X; + TMP = read(TMP2 & 0xff); + TMP = set_h(TMP, read((TMP2+1) & 0xff)); + TMP2 = read(TMP); + write(TMP, TMP2); + TMP2 = do_ror(TMP2); + write(TMP, TMP2); + do_adc(TMP2); + prefetch(); + +rra_idy + TMP2 = read_pc(); + TMP = read(TMP2); + TMP = set_h(TMP, read((TMP2+1) & 0xff)); + read(set_l(TMP, TMP+Y)); + TMP += Y; + TMP2 = read(TMP); + write(TMP, TMP2); + TMP2 = do_ror(TMP2); + write(TMP, TMP2); + do_adc(TMP2); + prefetch(); + +rra_zpg + TMP = read_pc(); + TMP2 = read(TMP); + write(TMP, TMP2); + TMP2 = do_ror(TMP2); + write(TMP, TMP2); + do_adc(TMP2); + prefetch(); + +rra_zpx + TMP = read_pc(); + read(TMP); + TMP = UINT8(TMP+X); + TMP2 = read(TMP); + write(TMP, TMP2); + TMP2 = do_ror(TMP2); + write(TMP, TMP2); + do_adc(TMP2); + prefetch(); + +sax_aba + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + TMP2 = A & X; + write(TMP, TMP2); + prefetch(); + +sax_idx + TMP2 = read_pc(); + read(TMP2); + TMP2 += X; + TMP = read(TMP2 & 0xff); + TMP = set_h(TMP, read((TMP2+1) & 0xff)); + TMP2 = A & X; + write(TMP, TMP2); + prefetch(); + +sax_zpg + TMP = read_pc(); + TMP2 = A & X; + write(TMP, TMP2); + prefetch(); + +sax_zpy + TMP = read_pc(); + read(TMP); + TMP = UINT8(TMP+Y); + TMP2 = A & X; + write(TMP, TMP2); + prefetch(); + +sbx_imm + TMP2 = read_pc(); + X &= A; + if(X < TMP2) + P &= ~F_C; + else + P |= F_C; + X -= TMP2; + set_nz(X); + prefetch(); + +sha_aby + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + read(set_l(TMP, TMP+Y)); + TMP2 = A & X & ((TMP >> 8)+1); + if(page_changing(TMP, Y)) + TMP = set_h(TMP+Y, TMP2); + else + TMP += Y; + write(TMP, TMP2); + prefetch(); + +sha_idy + TMP2 = read_pc(); + TMP = read(TMP2); + TMP = set_h(TMP, read((TMP2+1) & 0xff)); + read(set_l(TMP, TMP+Y)); + TMP2 = A & X & ((TMP >> 8)+1); + if(page_changing(TMP, Y)) + TMP = set_h(TMP+Y, TMP2); + else + TMP += Y; + write(TMP, TMP2); + prefetch(); + +shs_aby + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + read(set_l(TMP, TMP+Y)); + SP = set_l(SP, A & X); + TMP2 = A & X & ((TMP >> 8)+1); + if(page_changing(TMP, Y)) + TMP = set_h(TMP+Y, TMP2); + else + TMP += Y; + write(TMP, TMP2); + prefetch(); + +shx_aby + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + read(set_l(TMP, TMP+Y)); + TMP2 = X & ((TMP >> 8)+1); + if(page_changing(TMP, Y)) + TMP = set_h(TMP+Y, TMP2); + else + TMP += Y; + write(TMP, TMP2); + prefetch(); + +shy_abx + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + read(set_l(TMP, TMP+X)); + TMP2 = Y & ((TMP >> 8)+1); + if(page_changing(TMP, X)) + TMP = set_h(TMP+X, TMP2); + else + TMP += X; + write(TMP, TMP2); + prefetch(); + +slo_aba + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + TMP2 = read(TMP); + write(TMP, TMP2); + TMP2 = do_asl(TMP2); + write(TMP, TMP2); + A |= TMP2; + set_nz(A); + prefetch(); + +slo_abx + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + read(set_l(TMP, TMP+X)); + TMP += X; + TMP2 = read(TMP); + write(TMP, TMP2); + TMP2 = do_asl(TMP2); + write(TMP, TMP2); + A |= TMP2; + set_nz(A); + prefetch(); + +slo_aby + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + read(set_l(TMP, TMP+Y)); + TMP += Y; + TMP2 = read(TMP); + write(TMP, TMP2); + TMP2 = do_asl(TMP2); + write(TMP, TMP2); + A |= TMP2; + set_nz(A); + prefetch(); + +slo_idx + TMP2 = read_pc(); + read(TMP2); + TMP2 += X; + TMP = read(TMP2 & 0xff); + TMP = set_h(TMP, read((TMP2+1) & 0xff)); + TMP2 = read(TMP); + write(TMP, TMP2); + TMP2 = do_asl(TMP2); + write(TMP, TMP2); + A |= TMP2; + set_nz(A); + prefetch(); + +slo_idy + TMP2 = read_pc(); + TMP = read(TMP2); + TMP = set_h(TMP, read((TMP2+1) & 0xff)); + read(set_l(TMP, TMP+Y)); + TMP += Y; + TMP2 = read(TMP); + write(TMP, TMP2); + TMP2 = do_asl(TMP2); + write(TMP, TMP2); + A |= TMP2; + set_nz(A); + prefetch(); + +slo_zpg + TMP = read_pc(); + TMP2 = read(TMP); + write(TMP, TMP2); + TMP2 = do_asl(TMP2); + write(TMP, TMP2); + A |= TMP2; + set_nz(A); + prefetch(); + +slo_zpx + TMP = read_pc(); + read(TMP); + TMP = UINT8(TMP+X); + TMP2 = read(TMP); + write(TMP, TMP2); + TMP2 = do_asl(TMP2); + write(TMP, TMP2); + A |= TMP2; + set_nz(A); + prefetch(); + +sre_aba + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + TMP2 = read(TMP); + write(TMP, TMP2); + TMP2 = do_lsr(TMP2); + write(TMP, TMP2); + A ^= TMP2; + set_nz(A); + prefetch(); + +sre_abx + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + read(set_l(TMP, TMP+X)); + TMP += X; + TMP2 = read(TMP); + write(TMP, TMP2); + TMP2 = do_lsr(TMP2); + write(TMP, TMP2); + A ^= TMP2; + set_nz(A); + prefetch(); + +sre_aby + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + read(set_l(TMP, TMP+Y)); + TMP += Y; + TMP2 = read(TMP); + write(TMP, TMP2); + TMP2 = do_lsr(TMP2); + write(TMP, TMP2); + A ^= TMP2; + set_nz(A); + prefetch(); + +sre_idx + TMP2 = read_pc(); + read(TMP2); + TMP2 += X; + TMP = read(TMP2 & 0xff); + TMP = set_h(TMP, read((TMP2+1) & 0xff)); + TMP2 = read(TMP); + write(TMP, TMP2); + TMP2 = do_lsr(TMP2); + write(TMP, TMP2); + A ^= TMP2; + set_nz(A); + prefetch(); + +sre_idy + TMP2 = read_pc(); + TMP = read(TMP2); + TMP = set_h(TMP, read((TMP2+1) & 0xff)); + read(set_l(TMP, TMP+Y)); + TMP += Y; + TMP2 = read(TMP); + write(TMP, TMP2); + TMP2 = do_lsr(TMP2); + write(TMP, TMP2); + A ^= TMP2; + set_nz(A); + prefetch(); + +sre_zpg + TMP = read_pc(); + TMP2 = read(TMP); + write(TMP, TMP2); + TMP2 = do_lsr(TMP2); + write(TMP, TMP2); + A ^= TMP2; + set_nz(A); + prefetch(); + +sre_zpx + TMP = read_pc(); + read(TMP); + TMP = UINT8(TMP+X); + TMP2 = read(TMP); + write(TMP, TMP2); + TMP2 = do_lsr(TMP2); + write(TMP, TMP2); + A ^= TMP2; + set_nz(A); + prefetch(); + +# undocumented unreliable instructions +anc_imm + A &= read_pc(); + set_nz(A); + if(A & 0x80) + P |= F_C; + else + P &= ~F_C; + prefetch(); + +ane_imm + TMP2 = read_pc(); + A &= TMP2 & X; + set_nz(A); + prefetch(); + +asr_imm + A &= read_pc(); + A = do_lsr(A); + prefetch(); + +arr_imm + A &= read_pc(); + do_arr(); + prefetch(); + +las_aby + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + if(page_changing(TMP, Y)) { + read(set_l(TMP, TMP+Y)); + } + TMP2 = read(TMP+Y); + A = TMP2 | 0x51; + X = 0xff; + set_nz(TMP2); + prefetch(); + +lxa_imm + A = X = read_pc(); + set_nz(A); + prefetch(); + +# nop variants +nop_aba + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + read(TMP); + prefetch(); + +nop_abx + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + if(page_changing(TMP, X)) { + read(set_l(TMP, TMP+X)); + } + read(TMP + X); + prefetch(); + +nop_imm + read_pc(); + prefetch(); + +nop_zpg + TMP = read_pc(); + read(TMP); + prefetch(); + +nop_zpx + TMP = read_pc(); + read(TMP); + read(UINT8(TMP+X)); + prefetch(); + +# system killers +kil_non + read_pc(); + read(0xffff); + read(0xfffe); + read(0xfffe); + for(;;) { + read(0xffff); + } diff --git a/src/devices/cpu/m6502/om6509.lst b/src/devices/cpu/m6502/om6509.lst new file mode 100644 index 00000000000..4595827b1d7 --- /dev/null +++ b/src/devices/cpu/m6502/om6509.lst @@ -0,0 +1,20 @@ +# 6509 opcodes + +lda_9_idy + TMP2 = read_pc(); + TMP = read(TMP2); + TMP = set_h(TMP, read((TMP2+1) & 0xff)); + if(page_changing(TMP, Y)) { + read_9(set_l(TMP, TMP+Y)); + } + A = read_9(TMP+Y); + set_nz(A); + prefetch(); + +sta_9_idy + TMP2 = read_pc(); + TMP = read(TMP2); + TMP = set_h(TMP, read((TMP2+1) & 0xff)); + read_9(set_l(TMP, TMP+Y)); + write_9(TMP+Y, A); + prefetch(); diff --git a/src/devices/cpu/m6502/om6510.lst b/src/devices/cpu/m6502/om6510.lst new file mode 100644 index 00000000000..e08a5229111 --- /dev/null +++ b/src/devices/cpu/m6502/om6510.lst @@ -0,0 +1,46 @@ +# 6510 undocumented instructions in a C64 context +anc_10_imm + TMP2 = read_pc(); + A &= TMP2; + set_nz(A); + if(A & 0x80) + P |= F_C; + else + P &= ~F_C; + prefetch(); + +ane_10_imm + TMP2 = read_pc(); + A = (A | 0xee) & TMP2 & X; + set_nz(A); + prefetch(); + +asr_10_imm + TMP2 = read_pc(); + A = do_lsr(A & TMP2); + set_nz(A); + prefetch(); + +arr_10_imm + TMP2 = read_pc(); + A &= TMP2; + do_arr(); + prefetch(); + +las_10_aby + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + if(page_changing(TMP, Y)) { + read(set_l(TMP, TMP+Y)); + } + TMP2 = read(TMP+Y); + A = X = TMP2 & SP; + SP = set_l(SP, A); + set_nz(A); + prefetch(); + +lxa_10_imm + TMP2 = read_pc(); + A = X = (A | 0xee) & TMP2; + set_nz(A); + prefetch(); diff --git a/src/devices/cpu/m6502/om65c02.lst b/src/devices/cpu/m6502/om65c02.lst new file mode 100644 index 00000000000..d64ddcdc409 --- /dev/null +++ b/src/devices/cpu/m6502/om65c02.lst @@ -0,0 +1,584 @@ +# m65c02 opcodes + +adc_c_aba + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + TMP = read(TMP); + do_adc(TMP); + if(P & F_D) { + read_pc_noinc(); + set_nz(A); + } + prefetch(); + +adc_c_abx + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + if(page_changing(TMP, X)) { + read(set_l(TMP, TMP+X)); + } + TMP += X; + TMP = read(TMP); + do_adc(TMP); + if(P & F_D) { + read_pc_noinc(); + set_nz(A); + } + prefetch(); + +adc_c_aby + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + if(page_changing(TMP, Y)) { + read(set_l(TMP, TMP+Y)); + } + TMP += Y; + TMP = read(TMP); + do_adc(TMP); + if(P & F_D) { + read_pc_noinc(); + set_nz(A); + } + prefetch(); + +adc_c_idx + TMP2 = read_pc(); + read(TMP2); + TMP2 += X; + TMP = read(TMP2 & 0xff); + TMP = set_h(TMP, read((TMP2+1) & 0xff)); + do_adc(read(TMP)); + if(P & F_D) { + read_pc_noinc(); + set_nz(A); + } + prefetch(); + +adc_c_idy + TMP2 = read_pc(); + TMP = read(TMP2); + TMP = set_h(TMP, read((TMP2+1) & 0xff)); + if(page_changing(TMP, Y)) { + read(set_l(TMP, TMP+Y)); + } + do_adc(read(TMP+Y)); + if(P & F_D) { + read_pc_noinc(); + set_nz(A); + } + prefetch(); + +adc_c_imm + TMP = read_pc(); + do_adc(TMP); + if(P & F_D) { + read_pc_noinc(); + set_nz(A); + } + prefetch(); + +adc_c_zpg + TMP = read_pc(); + TMP = read(TMP); + do_adc(TMP); + if(P & F_D) { + read_pc_noinc(); + set_nz(A); + } + prefetch(); + +adc_c_zpi + TMP2 = read_pc(); + TMP = read(TMP2 & 0xff); + TMP = set_h(TMP, read((TMP2+1) & 0xff)); + do_adc(read(TMP)); + if(P & F_D) { + read_pc_noinc(); + set_nz(A); + } + prefetch(); + +adc_c_zpx + TMP = read_pc(); + read(TMP); + TMP = read(UINT8(TMP+X)); + do_adc(TMP); + if(P & F_D) { + read_pc_noinc(); + set_nz(A); + } + prefetch(); + +and_zpi + TMP2 = read_pc(); + TMP = read(TMP2 & 0xff); + TMP = set_h(TMP, read((TMP2+1) & 0xff)); + A &= read(TMP); + set_nz(A); + prefetch(); + +asl_c_abx + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + if(page_changing(TMP, X)) { + read(set_l(TMP, TMP+X)); + } + TMP += X; + TMP2 = read(TMP); + write(TMP, TMP2); + TMP2 = do_asl(TMP2); + write(TMP, TMP2); + prefetch(); + +bbr_zpb + // Access pattern uncertain + TMP = read_pc(); + TMP2 = read(TMP); + TMP = read_pc(); + read_pc_noinc(); + if(!(TMP2 & (1 << ((inst_state >> 4) & 7)))) { + PC += INT8(TMP); + } + prefetch(); + +bbs_zpb + // Access pattern uncertain + TMP = read_pc(); + TMP2 = read(TMP); + TMP = read_pc(); + read_pc_noinc(); + if(TMP2 & (1 << ((inst_state >> 4) & 7))) { + PC += INT8(TMP); + } + prefetch(); + +bit_abx + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + if(page_changing(TMP, X)) { + read(set_l(TMP, TMP+X)); + } + TMP += X; + do_bit(read(TMP)); + prefetch(); + +bit_imm + TMP = read_pc(); + if(A & TMP) + P &= ~F_Z; + else + P |= F_Z; + prefetch(); + +bit_zpx + TMP = read_pc(); + read(TMP); + TMP = read(UINT8(TMP+X)); + do_bit(TMP); + prefetch(); + +bra_rel + TMP = read_pc(); + read_pc_noinc(); + if(page_changing(PC, INT8(TMP))) { + read_arg(set_l(PC, PC+INT8(TMP))); + } + PC += INT8(TMP); + prefetch(); + +brk_c_imp + if(irq_taken || nmi_state) { + read_pc_noinc(); + } else { + read_pc(); + } + write(SP, PC >> 8); + dec_SP(); + write(SP, PC); + dec_SP(); + write(SP, irq_taken || nmi_state ? P & ~F_B : P); + dec_SP(); + if(irq_taken && nmi_state) { + PC = read_arg(0xfffa); + PC = set_h(PC, read_arg(0xfffb)); + nmi_state = false; + standard_irq_callback(NMI_LINE); + } else { + PC = read_arg(0xfffe); + PC = set_h(PC, read_arg(0xffff)); + if(irq_taken) + standard_irq_callback(IRQ_LINE); + } + irq_taken = false; + P = (P | F_I) & ~F_D; // Do *not* move after the prefetch + prefetch(); + inst_state = -1; + +cmp_zpi + TMP2 = read_pc(); + TMP = read(TMP2 & 0xff); + TMP = set_h(TMP, read((TMP2+1) & 0xff)); + do_cmp(A, read(TMP)); + prefetch(); + +dec_acc + read_pc_noinc(); + A--; + set_nz(A); + prefetch(); + +eor_zpi + TMP2 = read_pc(); + TMP = read(TMP2 & 0xff); + TMP = set_h(TMP, read((TMP2+1) & 0xff)); + A ^= read(TMP); + set_nz(A); + prefetch(); + +inc_acc + read_pc_noinc(); + A++; + set_nz(A); + prefetch(); + +jmp_iax + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + read(set_l(TMP, TMP+X)); + TMP += X; + PC = read(TMP); + PC = set_h(PC, read(TMP+1)); + prefetch(); + +jmp_c_ind + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + PC = read(TMP); + read(set_l(TMP, TMP+1)); + PC = set_h(PC, read(TMP+1)); + prefetch(); + +lda_zpi + TMP2 = read_pc(); + TMP = read(TMP2 & 0xff); + TMP = set_h(TMP, read((TMP2+1) & 0xff)); + A = read(TMP); + set_nz(A); + prefetch(); + + +lsr_c_abx + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + if(page_changing(TMP, X)) { + read(set_l(TMP, TMP+X)); + } + TMP += X; + TMP2 = read(TMP); + write(TMP, TMP2); + TMP2 = do_lsr(TMP2); + write(TMP, TMP2); + prefetch(); + +nop_c_imp + prefetch(); + +nop_c_aba + read_pc(); + read_pc(); + read_pc_noinc(); + read_pc_noinc(); + read_pc_noinc(); + read_pc_noinc(); + read_pc_noinc(); + prefetch(); + +nop_c_abx + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + read(set_l(TMP, TMP+X)); + prefetch(); + +ora_zpi + TMP2 = read_pc(); + TMP = read(TMP2 & 0xff); + TMP = set_h(TMP, read((TMP2+1) & 0xff)); + A |= read(TMP); + set_nz(A); + prefetch(); + +phx_imp + read_pc_noinc(); + write(SP, X); + dec_SP(); + prefetch(); + +phy_imp + read_pc_noinc(); + write(SP, Y); + dec_SP(); + prefetch(); + +plx_imp + read_pc_noinc(); + read(SP); + inc_SP(); + X = read(SP); + set_nz(X); + prefetch(); + +ply_imp + read_pc_noinc(); + read(SP); + inc_SP(); + Y = read(SP); + set_nz(Y); + prefetch(); + +rmb_bzp + // Access pattern unknown but probable (built upon inc_zpg) + TMP = read_pc(); + TMP2 = read(TMP); + write(TMP, TMP2); + TMP2 &= ~(1 << ((inst_state >> 4) & 7)); + write(TMP, TMP2); + prefetch(); + +rol_c_abx + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + if(page_changing(TMP, X)) { + read(set_l(TMP, TMP+X)); + } + TMP += X; + TMP2 = read(TMP); + write(TMP, TMP2); + TMP2 = do_rol(TMP2); + write(TMP, TMP2); + prefetch(); + + +ror_c_abx + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + if(page_changing(TMP, X)) { + read(set_l(TMP, TMP+X)); + } + TMP += X; + TMP2 = read(TMP); + write(TMP, TMP2); + TMP2 = do_ror(TMP2); + write(TMP, TMP2); + prefetch(); + +sbc_c_aba + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + TMP = read(TMP); + do_sbc(TMP); + if(P & F_D) { + read_pc_noinc(); + set_nz(A); + } + prefetch(); + +sbc_c_abx + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + if(page_changing(TMP, X)) { + read(set_l(TMP, TMP+X)); + } + TMP += X; + TMP = read(TMP); + do_sbc(TMP); + if(P & F_D) { + read_pc_noinc(); + set_nz(A); + } + prefetch(); + +sbc_c_aby + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + if(page_changing(TMP, Y)) { + read(set_l(TMP, TMP+Y)); + } + TMP += Y; + TMP = read(TMP); + do_sbc(TMP); + if(P & F_D) { + read_pc_noinc(); + set_nz(A); + } + prefetch(); + +sbc_c_idx + TMP2 = read_pc(); + read(TMP2); + TMP2 += X; + TMP = read(TMP2 & 0xff); + TMP = set_h(TMP, read((TMP2+1) & 0xff)); + do_sbc(read(TMP)); + if(P & F_D) { + read_pc_noinc(); + set_nz(A); + } + prefetch(); + +sbc_c_idy + TMP2 = read_pc(); + TMP = read(TMP2); + TMP = set_h(TMP, read((TMP2+1) & 0xff)); + if(page_changing(TMP, Y)) { + read(set_l(TMP, TMP+Y)); + } + do_sbc(read(TMP+Y)); + if(P & F_D) { + read_pc_noinc(); + set_nz(A); + } + prefetch(); + +sbc_c_imm + TMP = read_pc(); + do_sbc(TMP); + if(P & F_D) { + read_pc_noinc(); + set_nz(A); + } + prefetch(); + +sbc_c_zpg + TMP = read_pc(); + TMP = read(TMP); + do_sbc(TMP); + if(P & F_D) { + read_pc_noinc(); + set_nz(A); + } + prefetch(); + +sbc_c_zpi + TMP2 = read_pc(); + TMP = read(TMP2 & 0xff); + TMP = set_h(TMP, read((TMP2+1) & 0xff)); + do_sbc(read(TMP)); + if(P & F_D) { + read_pc_noinc(); + set_nz(A); + } + prefetch(); + +sbc_c_zpx + TMP = read_pc(); + read(TMP); + TMP = read(UINT8(TMP+X)); + do_sbc(TMP); + if(P & F_D) { + read_pc_noinc(); + set_nz(A); + } + prefetch(); + +smb_bzp + // Access pattern unknown but probable (built upon inc_zpg) + TMP = read_pc(); + TMP2 = read(TMP); + write(TMP, TMP2); + TMP2 |= 1 << ((inst_state >> 4) & 7); + write(TMP, TMP2); + prefetch(); + +sta_zpi + TMP2 = read_pc(); + TMP = read(TMP2 & 0xff); + TMP = set_h(TMP, read((TMP2+1) & 0xff)); + write(TMP, A); + prefetch(); + +stp_imp + for(;;) { + eat-all-cycles; + } + +stz_aba + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + write(TMP, 0x00); + prefetch(); + +stz_abx + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + read(set_l(TMP, TMP+X)); + write(TMP+X, 0x00); + prefetch(); + +stz_zpg + TMP = read_pc(); + write(TMP, 0x00); + prefetch(); + +stz_zpx + TMP = read_pc(); + read(TMP); + write(UINT8(TMP+X), 0x00); + prefetch(); + +trb_aba + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + TMP2 = read(TMP); + write(TMP, TMP2); + if(A & TMP2) + P &= ~F_Z; + else + P |= F_Z; + TMP2 &= ~A; + write(TMP, TMP2); + prefetch(); + +trb_zpg + TMP = read_pc(); + TMP2 = read(TMP); + write(TMP, TMP2); + if(A & TMP2) + P &= ~F_Z; + else + P |= F_Z; + TMP2 &= ~A; + write(TMP, TMP2); + prefetch(); + +tsb_aba + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + TMP2 = read(TMP); + write(TMP, TMP2); + if(A & TMP2) + P &= ~F_Z; + else + P |= F_Z; + TMP2 |= A; + write(TMP, TMP2); + prefetch(); + +tsb_zpg + TMP = read_pc(); + TMP2 = read(TMP); + write(TMP, TMP2); + if(A & TMP2) + P &= ~F_Z; + else + P |= F_Z; + TMP2 |= A; + write(TMP, TMP2); + prefetch(); + +wai_imp + read_pc_noinc(); + read_pc_noinc(); + while(!nmi_state && !irq_state) { + eat-all-cycles; + } + prefetch(); diff --git a/src/devices/cpu/m6502/om65ce02.lst b/src/devices/cpu/m6502/om65ce02.lst new file mode 100644 index 00000000000..049097fded8 --- /dev/null +++ b/src/devices/cpu/m6502/om65ce02.lst @@ -0,0 +1,1533 @@ +# 65ce02 opcodes, a lot only remove dummy read/write cycles, some are new, some use the B register + +adc_ce_aba + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + TMP = read(TMP); + do_adc(TMP); + if(P & F_D) + set_nz(A); + prefetch(); + +adc_ce_abx + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + TMP += X; + TMP = read(TMP); + do_adc(TMP); + if(P & F_D) + set_nz(A); + prefetch(); + +adc_ce_aby + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + TMP += Y; + TMP = read(TMP); + do_adc(TMP); + if(P & F_D) + set_nz(A); + prefetch(); + +adc_ce_idx + TMP2 = read_pc(); + TMP2 += X; + TMP = read(B|TMP2); + TMP2++; + TMP = set_h(TMP, read(B|TMP2)); + do_adc(read(TMP)); + if(P & F_D) + set_nz(A); + prefetch(); + +adc_ce_idy + TMP2 = read_pc(); + TMP = read(B|TMP2); + TMP2++; + TMP = set_h(TMP, read(B|TMP2)); + do_adc(read(TMP+Y)); + if(P & F_D) + set_nz(A); + prefetch(); + +adc_idz + TMP2 = read_pc(); + TMP = read(B|TMP2); + TMP2++; + TMP = set_h(TMP, read(B|TMP2)); + do_adc(read(TMP+Z)); + if(P & F_D) + set_nz(A); + prefetch(); + +adc_ce_imm + TMP = read_pc(); + do_adc(TMP); + if(P & F_D) + set_nz(A); + prefetch(); + +adc_ce_zpg + TMP = read_pc(); + TMP = read(B|TMP); + do_adc(TMP); + if(P & F_D) + set_nz(A); + prefetch(); + +adc_ce_zpx + TMP = read_pc(); + TMP = read(B|UINT8(TMP+X)); + do_adc(TMP); + if(P & F_D) + set_nz(A); + prefetch(); + +and_ce_abx + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + TMP += X; + A &= read(TMP); + set_nz(A); + prefetch(); + +and_ce_aby + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + TMP += Y; + A &= read(TMP); + set_nz(A); + prefetch(); + +and_ce_idx + TMP2 = read_pc(); + TMP2 += X; + TMP = read(B|TMP2); + TMP2++; + TMP = set_h(TMP, read(B|TMP2)); + A &= read(TMP); + set_nz(A); + prefetch(); + +and_ce_idy + TMP2 = read_pc(); + TMP = read(B|TMP2); + TMP2++; + TMP = set_h(TMP, read(B|TMP2)); + A &= read(TMP+Y); + set_nz(A); + prefetch(); + +and_idz + TMP2 = read_pc(); + TMP = read(B|TMP2); + TMP2++; + TMP = set_h(TMP, read(B|TMP2)); + A &= read(TMP+Z); + set_nz(A); + prefetch(); + +and_ce_zpg + TMP = read_pc(); + A &= read(B|TMP); + set_nz(A); + prefetch(); + +and_ce_zpx + TMP = read_pc(); + A &= read(B|UINT8(TMP+X)); + set_nz(A); + prefetch(); + +asl_ce_aba + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + TMP2 = read(TMP); + TMP2 = do_asl(TMP2); + write(TMP, TMP2); + prefetch(); + +asl_ce_abx + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + TMP += X; + TMP2 = read(TMP); + TMP2 = do_asl(TMP2); + write(TMP, TMP2); + prefetch(); + +asl_ce_acc + A = do_asl(A); + prefetch(); + +asl_ce_zpg + TMP = B|read_pc(); + TMP2 = read(TMP); + TMP2 = do_asl(TMP2); + write(TMP, TMP2); + prefetch(); + +asl_ce_zpx + TMP = read_pc(); + TMP = B|UINT8(TMP+X); + TMP2 = read(TMP); + TMP2 = do_asl(TMP2); + write(TMP, TMP2); + prefetch(); + +asr_acc + A = do_asr(A); + prefetch(); + +asr_zpg + TMP = B|read_pc(); + TMP2 = read(TMP); + TMP2 = do_asr(TMP2); + write(TMP, TMP2); + prefetch(); + +asr_zpx + TMP = read_pc(); + TMP = B|UINT8(TMP+X); + TMP2 = read(TMP); + TMP2 = do_asr(TMP2); + write(TMP, TMP2); + prefetch(); + +asw_aba + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + TMP3 = read(TMP); + TMP3 = set_h(TMP3, read(TMP+1)); + P &= ~(F_C|F_N|F_Z); + if(TMP3 & 0x8000) + P |= F_C; + TMP3 <<= 1; + if(!TMP3) + P |= F_Z; + else if(TMP3 & 0x8000) + P |= F_N; + write(TMP, TMP3); + write(TMP, TMP3 >> 8); + prefetch(); + +aug_iw3 + read_pc(); + read_pc(); + read_pc(); + prefetch(); + +bbr_ce_zpb + // Access pattern uncertain + TMP = read_pc(); + TMP2 = read(TMP); + TMP = read_pc(); + if(!(TMP2 & (1 << ((inst_state >> 4) & 7)))) + PC += INT8(TMP); + prefetch(); + +bbs_ce_zpb + // Access pattern uncertain + TMP = read_pc(); + TMP2 = read(TMP); + TMP = read_pc(); + if(TMP2 & (1 << ((inst_state >> 4) & 7))) + PC += INT8(TMP); + prefetch(); + +bcc_ce_rel + TMP = read_pc(); + if(!(P & F_C)) + PC += INT8(TMP); + prefetch(); + +bcc_rw2 + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + if(!(P & F_C)) + PC += TMP-1; + prefetch(); + +bcs_ce_rel + TMP = read_pc(); + if(P & F_C) + PC += INT8(TMP); + prefetch(); + +bcs_rw2 + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + if(P & F_C) + PC += TMP-1; + prefetch(); + +beq_ce_rel + TMP = read_pc(); + if(P & F_Z) + PC += INT8(TMP); + prefetch(); + +beq_rw2 + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + if(P & F_Z) + PC += TMP-1; + prefetch(); + +bit_ce_abx + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + TMP += X; + do_bit(read(TMP)); + prefetch(); + +bit_ce_imm + TMP = read_pc(); + do_bit(TMP); + prefetch(); + +bit_ce_zpg + TMP = B|read_pc(); + do_bit(read(TMP)); + prefetch(); + +bit_ce_zpx + TMP = read_pc(); + TMP = read(B|UINT8(TMP+X)); + do_bit(TMP); + prefetch(); + +bmi_ce_rel + TMP = read_pc(); + if(P & F_N) + PC += INT8(TMP); + prefetch(); + +bmi_rw2 + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + if(P & F_N) + PC += TMP-1; + prefetch(); + +bne_ce_rel + TMP = read_pc(); + if(!(P & F_Z)) + PC += INT8(TMP); + prefetch(); + +bne_rw2 + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + if(!(P & F_Z)) + PC += TMP-1; + prefetch(); + +bpl_ce_rel + TMP = read_pc(); + if(!(P & F_N)) + PC += INT8(TMP); + prefetch(); + +bpl_rw2 + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + if(!(P & F_N)) + PC += TMP-1; + prefetch(); + +bra_ce_rel + TMP = read_pc(); + PC += INT8(TMP); + prefetch(); + +bra_rw2 + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + PC += TMP - 1; + prefetch(); + +brk_ce_imp + if(irq_taken) { + read_pc_noinc(); + } else { + read_pc(); + } + write(SP, PC >> 8); + dec_SP_ce(); + write(SP, PC); + dec_SP_ce(); + write(SP, irq_taken || nmi_state ? P & ~F_B : P); + dec_SP_ce(); + if(nmi_state) { + PC = read_arg(0xfffa); + PC = set_h(PC, read_arg(0xfffb)); + nmi_state = false; + } else { + PC = read_arg(0xfffe); + PC = set_h(PC, read_arg(0xffff)); + } + irq_taken = false; + P = (P | F_I) & ~F_D; // Do *not* move after the prefetch + prefetch(); + inst_state = -1; + +bsr_rw2 + TMP = read_pc(); + write(SP, PC>>8); + dec_SP_ce(); + write(SP, PC); + dec_SP_ce(); + TMP = set_h(TMP, read_pc()); + PC += TMP-1; + prefetch(); + +bvc_ce_rel + TMP = read_pc(); + if(!(P & F_V)) + PC += INT8(TMP); + prefetch(); + +bvc_rw2 + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + if(!(P & F_V)) + PC += TMP-1; + prefetch(); + +bvs_ce_rel + TMP = read_pc(); + if(P & F_V) + PC += INT8(TMP); + prefetch(); + +bvs_rw2 + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + if(P & F_V) + PC += TMP-1; + prefetch(); + +clc_ce_imp + P &= ~F_C; + prefetch(); + +cld_ce_imp + P &= ~F_D; + prefetch(); + +cle_imp + read_pc_noinc(); + P &= ~F_E; + logerror("CLE\n"); + prefetch(); + +cli_ce_imp + prefetch(); + P &= ~F_I; // Do *not* move it before the prefetch + +clv_ce_imp + P &= ~F_V; + prefetch(); + +cmp_ce_abx + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + TMP += X; + TMP = read(TMP); + do_cmp(A, TMP); + prefetch(); + +cmp_ce_aby + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + TMP += Y; + TMP = read(TMP); + do_cmp(A, TMP); + prefetch(); + +cmp_ce_idx + TMP2 = read_pc(); + TMP2 += X; + TMP = read(B|TMP2); + TMP2++; + TMP = set_h(TMP, read(B|TMP2)); + do_cmp(A, read(TMP)); + prefetch(); + +cmp_ce_idy + TMP2 = read_pc(); + TMP = read(B|TMP2); + TMP2++; + TMP = set_h(TMP, read(B|TMP2)); + do_cmp(A, read(TMP+Y)); + prefetch(); + +cmp_idz + TMP2 = read_pc(); + TMP = read(B|TMP2); + TMP2++; + TMP = set_h(TMP, read(B|TMP2)); + do_cmp(A, read(TMP+Z)); + prefetch(); + +cmp_ce_zpg + TMP = read_pc(); + TMP = read(B|TMP); + do_cmp(A, TMP); + prefetch(); + +cmp_ce_zpx + TMP = read_pc(); + read(TMP); + TMP = read(B|UINT8(TMP+X)); + do_cmp(A, TMP); + prefetch(); + +cpx_ce_zpg + TMP = read_pc(); + TMP = read(B|TMP); + do_cmp(X, TMP); + prefetch(); + +cpy_ce_zpg + TMP = read_pc(); + TMP = read(B|TMP); + do_cmp(Y, TMP); + prefetch(); + +cpz_aba + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + TMP = read(TMP); + do_cmp(Z, TMP); + prefetch(); + +cpz_imm + TMP = read_pc(); + do_cmp(Z, TMP); + prefetch(); + +cpz_zpg + TMP = read_pc(); + TMP = read(B|TMP); + do_cmp(Z, TMP); + prefetch(); + +dec_ce_aba + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + TMP2 = read(TMP); + TMP2--; + set_nz(TMP2); + write(TMP, TMP2); + prefetch(); + +dec_ce_abx + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + TMP += X; + TMP2 = read(TMP); + TMP2--; + set_nz(TMP2); + write(TMP, TMP2); + prefetch(); + +dec_ce_acc + A--; + set_nz(A); + prefetch(); + +dec_ce_zpg + TMP = B|read_pc(); + TMP2 = read(TMP); + TMP2--; + set_nz(TMP2); + write(TMP, TMP2); + prefetch(); + +dec_ce_zpx + TMP = read_pc(); + TMP = B|UINT8(TMP+X); + TMP2 = read(TMP); + TMP2--; + set_nz(TMP2); + write(TMP, TMP2); + prefetch(); + +dew_zpg + TMP2 = read_pc(); + TMP = read(B|TMP2); + TMP2++; + TMP = set_h(TMP, read(B|TMP2)); + P &= ~(F_N|F_Z); + TMP++; + if(!TMP) + P |= F_Z; + else if(TMP & 0x8000) + P |= F_N; + TMP2++; + write(B|TMP2, TMP); + TMP2++; + write(B|TMP2, TMP >> 8); + prefetch(); + +dex_ce_imp + X--; + set_nz(X); + prefetch(); + +dey_ce_imp + Y--; + set_nz(Y); + prefetch(); + +dez_imp + Z--; + set_nz(Z); + prefetch(); + +eor_ce_abx + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + TMP += X; + A ^= read(TMP); + set_nz(A); + prefetch(); + +eor_ce_aby + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + TMP += Y; + A ^= read(TMP); + set_nz(A); + prefetch(); + +eor_ce_idx + TMP2 = read_pc(); + TMP2 += X; + TMP = read(B|TMP2); + TMP2++; + TMP = set_h(TMP, read(B|TMP2)); + A ^= read(TMP); + set_nz(A); + prefetch(); + +eor_ce_idy + TMP2 = read_pc(); + TMP = read(B|TMP2); + TMP2++; + TMP = set_h(TMP, read(B|TMP2)); + A ^= read(TMP+Y); + set_nz(A); + prefetch(); + +eor_idz + TMP2 = read_pc(); + TMP = read(B|TMP2); + TMP2++; + TMP = set_h(TMP, read(B|TMP2)); + A ^= read(TMP+Z); + set_nz(A); + prefetch(); + +eor_ce_zpg + TMP = read_pc(); + A ^= read(B|TMP); + set_nz(A); + prefetch(); + +eor_ce_zpx + TMP = read_pc(); + A ^= read(B|UINT8(TMP+X)); + set_nz(A); + prefetch(); + +inc_ce_aba + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + TMP2 = read(TMP); + TMP2++; + set_nz(TMP2); + write(TMP, TMP2); + prefetch(); + +inc_ce_abx + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + TMP += X; + TMP2 = read(TMP); + TMP2++; + set_nz(TMP2); + write(TMP, TMP2); + prefetch(); + +inc_ce_acc + A++; + set_nz(A); + prefetch(); + +inc_ce_zpg + TMP = B|read_pc(); + TMP2 = read(TMP); + TMP2++; + set_nz(TMP2); + write(TMP, TMP2); + prefetch(); + +inc_ce_zpx + TMP = read_pc(); + TMP = B|UINT8(TMP+X); + TMP2 = read(TMP); + TMP2++; + set_nz(TMP2); + write(TMP, TMP2); + prefetch(); + +inw_zpg + TMP2 = read_pc(); + TMP = read(B|TMP2); + TMP2++; + TMP = set_h(TMP, read(B|TMP2)); + P &= ~(F_N|F_Z); + TMP++; + if(!TMP) + P |= F_Z; + else if(TMP & 0x8000) + P |= F_N; + TMP2--; + write(B|TMP2, TMP); + TMP2++; + write(B|TMP2, TMP >> 8); + prefetch(); + +inx_ce_imp + X++; + set_nz(X); + prefetch(); + +iny_ce_imp + Y++; + set_nz(Y); + prefetch(); + +inz_imp + Z++; + set_nz(Z); + prefetch(); + +jmp_ce_iax + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + TMP += X; + PC = read(TMP); + PC = set_h(PC, read(TMP+1)); + prefetch(); + +jmp_ce_ind + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + PC = read(TMP); + PC = set_h(PC, read(TMP+1)); + prefetch(); + +jsr_ce_adr + TMP = read_pc(); + write(SP, PC>>8); + dec_SP_ce(); + write(SP, PC); + dec_SP_ce(); + TMP = set_h(TMP, read_pc()); + PC = TMP; + prefetch(); + +jsr_iax + TMP = read_pc(); + write(SP, PC>>8); + dec_SP_ce(); + write(SP, PC); + dec_SP_ce(); + TMP = set_h(TMP, read_pc()); + PC = read(TMP); + PC = set_h(PC, read(TMP+1)); + PC += X; + prefetch(); + +jsr_ind + TMP = read_pc(); + write(SP, PC>>8); + dec_SP_ce(); + write(SP, PC); + dec_SP_ce(); + TMP = set_h(TMP, read_pc()); + PC = read(TMP); + PC = set_h(PC, read(TMP+1)); + prefetch(); + +lda_ce_abx + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + A = read(TMP + X); + set_nz(A); + prefetch(); + +lda_ce_aby + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + A = read(TMP + Y); + set_nz(A); + prefetch(); + +lda_ce_idx + TMP2 = read_pc(); + TMP2 += X; + TMP = read(B|TMP2); + TMP2++; + TMP = set_h(TMP, read(B|TMP2)); + A = read(TMP); + set_nz(A); + prefetch(); + +lda_ce_idy + TMP2 = read_pc(); + TMP = read(B|TMP2); + TMP2++; + TMP = set_h(TMP, read(B|TMP2)); + A = read(TMP+Y); + set_nz(A); + prefetch(); + +lda_idz + TMP2 = read_pc(); + TMP = read(B|TMP2); + TMP2++; + TMP = set_h(TMP, read(B|TMP2)); + A = read(TMP+Z); + set_nz(A); + prefetch(); + +lda_isy + read_pc_noinc(); + TMP = read_pc(); + if(P & F_E) + TMP = set_l(SP, SP+TMP); + else + TMP = SP + TMP; + TMP2 = read(TMP); + TMP++; + TMP = TMP2 | (read(TMP) << 8); + A = read(TMP+Y); + set_nz(A); + prefetch(); + +lda_ce_zpg + TMP = read_pc(); + A = read(B|TMP); + set_nz(A); + prefetch(); + +lda_ce_zpx + TMP = read_pc(); + A = read(B|UINT8(TMP+X)); + set_nz(A); + prefetch(); + +ldx_ce_aby + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + X = read(TMP + Y); + set_nz(X); + prefetch(); + +ldx_ce_zpg + TMP = read_pc(); + X = read(B|TMP); + set_nz(X); + prefetch(); + +ldx_ce_zpy + TMP = read_pc(); + X = read(B|UINT8(TMP+Y)); + set_nz(X); + prefetch(); + +ldy_ce_abx + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + TMP += X; + Y = read(TMP); + set_nz(Y); + prefetch(); + +ldy_ce_zpg + TMP = read_pc(); + Y = read(B|TMP); + set_nz(Y); + prefetch(); + +ldy_ce_zpx + TMP = read_pc(); + Y = read(B|UINT8(TMP+X)); + set_nz(Y); + prefetch(); + +ldz_aba + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + Z = read(TMP); + set_nz(Z); + prefetch(); + +ldz_abx + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + Z = read(TMP + X); + set_nz(Z); + prefetch(); + +ldz_imm + Z = read_pc(); + set_nz(Z); + prefetch(); + +lsr_ce_aba + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + TMP2 = read(TMP); + TMP2 = do_lsr(TMP2); + write(TMP, TMP2); + prefetch(); + +lsr_ce_abx + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + read(set_l(TMP, TMP+X)); + TMP += X; + TMP2 = read(TMP); + TMP2 = do_lsr(TMP2); + write(TMP, TMP2); + prefetch(); + +lsr_ce_acc + A = do_lsr(A); + prefetch(); + +lsr_ce_zpg + TMP = B|read_pc(); + TMP2 = read(TMP); + TMP2 = do_lsr(TMP2); + write(TMP, TMP2); + prefetch(); + +lsr_ce_zpx + TMP = read_pc(); + TMP = B|UINT8(TMP+X); + TMP2 = read(TMP); + TMP2 = do_lsr(TMP2); + write(TMP, TMP2); + prefetch(); + +neg_acc + read_pc_noinc(); + A = -A; + set_nz(A); + prefetch(); + +ora_ce_abx + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + TMP += X; + A |= read(TMP); + set_nz(A); + prefetch(); + +ora_ce_aby + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + TMP += Y; + A |= read(TMP); + set_nz(A); + prefetch(); + +ora_ce_idx + TMP2 = read_pc(); + TMP2 += X; + TMP = read(B|TMP2); + TMP2++; + TMP = set_h(TMP, read(B|TMP2)); + A |= read(TMP); + set_nz(A); + prefetch(); + +ora_ce_idy + TMP2 = read_pc(); + TMP = read(B|TMP2); + TMP2++; + TMP = set_h(TMP, read(B|TMP2)); + A |= read(TMP+Y); + set_nz(A); + prefetch(); + +ora_idz + TMP2 = read_pc(); + TMP = read(B|TMP2); + TMP2++; + TMP = set_h(TMP, read(B|TMP2)); + A |= read(TMP+Z); + set_nz(A); + prefetch(); + +ora_ce_zpg + TMP = read_pc(); + A |= read(B|TMP); + set_nz(A); + prefetch(); + +ora_ce_zpx + TMP = read_pc(); + A |= read(B|UINT8(TMP+X)); + set_nz(A); + prefetch(); + +# push/pop instructions and rti/rtn/rts are not fully streamlined +pha_ce_imp + read_pc_noinc(); + write(SP, A); + dec_SP_ce(); + prefetch(); + +php_ce_imp + read_pc_noinc(); + write(SP, P); + dec_SP_ce(); + prefetch(); + +phw_aba + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + TMP3 = read(TMP); + TMP3 = set_h(TMP3, read(TMP+1)); + dec_SP_ce(); + write(SP, TMP3); + dec_SP_ce(); + write(SP, TMP3 >> 8); + prefetch(); + +phw_iw2 + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + dec_SP_ce(); + write(SP, TMP); + dec_SP_ce(); + write(SP, TMP >> 8); + prefetch(); + +phx_ce_imp + read_pc_noinc(); + write(SP, X); + dec_SP_ce(); + prefetch(); + +phy_ce_imp + read_pc_noinc(); + write(SP, Y); + dec_SP_ce(); + prefetch(); + +phz_imp + read_pc_noinc(); + write(SP, Z); + dec_SP_ce(); + prefetch(); + +pla_ce_imp + read_pc_noinc(); + inc_SP_ce(); + A = read(SP); + set_nz(A); + prefetch(); + +plp_ce_imp + read_pc_noinc(); + inc_SP_ce(); + TMP = read(SP) | F_B; + prefetch(); + P = TMP; // Do *not* move it before the prefetch + +plx_ce_imp + read_pc_noinc(); + inc_SP_ce(); + X = read(SP); + set_nz(X); + prefetch(); + +ply_ce_imp + read_pc_noinc(); + inc_SP_ce(); + Y = read(SP); + set_nz(Y); + prefetch(); + +plz_imp + read_pc_noinc(); + inc_SP_ce(); + Z = read(SP); + set_nz(Z); + prefetch(); + +rmb_ce_bzp + TMP = read_pc(); + TMP2 = read(TMP); + TMP2 &= ~(1 << ((inst_state >> 4) & 7)); + write(TMP, TMP2); + prefetch(); + +rol_ce_aba + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + TMP2 = read(TMP); + TMP2 = do_rol(TMP2); + write(TMP, TMP2); + prefetch(); + +rol_ce_abx + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + TMP += X; + TMP2 = read(TMP); + TMP2 = do_rol(TMP2); + write(TMP, TMP2); + prefetch(); + +rol_ce_acc + A = do_rol(A); + prefetch(); + +rol_ce_zpg + TMP = B|read_pc(); + TMP2 = read(TMP); + TMP2 = do_rol(TMP2); + write(TMP, TMP2); + prefetch(); + +rol_ce_zpx + TMP = read_pc(); + TMP = B|UINT8(TMP+X); + TMP2 = read(TMP); + TMP2 = do_rol(TMP2); + write(TMP, TMP2); + prefetch(); + +ror_ce_aba + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + TMP2 = read(TMP); + TMP2 = do_ror(TMP2); + write(TMP, TMP2); + prefetch(); + +ror_ce_abx + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + TMP += X; + TMP2 = read(TMP); + TMP2 = do_ror(TMP2); + write(TMP, TMP2); + prefetch(); + +ror_ce_acc + A = do_ror(A); + prefetch(); + +ror_ce_zpg + TMP = B|read_pc(); + TMP2 = read(TMP); + TMP2 = do_ror(TMP2); + write(TMP, TMP2); + prefetch(); + +ror_ce_zpx + TMP = read_pc(); + TMP = B|UINT8(TMP+X); + TMP2 = read(TMP); + TMP2 = do_ror(TMP2); + write(TMP, TMP2); + prefetch(); + +row_aba + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + TMP3 = read(TMP); + TMP3 = set_h(TMP3, read(TMP+1)); + TMP2 = P; + P &= ~(F_C|F_N|F_Z); + if(TMP3 & 0x8000) + P |= F_C; + TMP3 <<= 1; + if(TMP2 & F_C) + TMP3 |= 0x0001; + if(!TMP3) + P |= F_Z; + else if(TMP3 & 0x8000) + P |= F_N; + write(TMP, TMP3); + write(TMP, TMP3 >> 8); + prefetch(); + +rti_ce_imp + read_pc_noinc(); + inc_SP_ce(); + P = read(SP) | F_B; + inc_SP_ce(); + PC = read(SP); + inc_SP_ce(); + PC = set_h(PC, read(SP)); + prefetch(); + +rtn_imm + TMP = read_pc(); + if(P & F_E) + SP = set_l(SP, SP+TMP); + else + SP += TMP; + read_pc_noinc(); + read(SP); + inc_SP(); + PC = read(SP); + inc_SP(); + PC = set_h(PC, read(SP)); + read_pc(); + prefetch(); + +rts_ce_imp + inc_SP_ce(); + PC = read(SP); + inc_SP_ce(); + PC = set_h(PC, read(SP)); + read_pc(); + prefetch(); + +sbc_ce_aba + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + TMP = read(TMP); + do_sbc(TMP); + if(P & F_D) + set_nz(A); + prefetch(); + +sbc_ce_abx + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + TMP += X; + TMP = read(TMP); + do_sbc(TMP); + if(P & F_D) + set_nz(A); + prefetch(); + +sbc_ce_aby + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + TMP += Y; + TMP = read(TMP); + do_sbc(TMP); + if(P & F_D) + set_nz(A); + prefetch(); + +sbc_ce_idx + TMP2 = read_pc(); + TMP2 += X; + TMP = read(B|TMP2); + TMP2++; + TMP = set_h(TMP, read(B|TMP2)); + do_sbc(read(TMP)); + if(P & F_D) + set_nz(A); + prefetch(); + +sbc_ce_idy + TMP2 = read_pc(); + TMP = read(B|TMP2); + TMP2++; + TMP = set_h(TMP, read(B|TMP2)); + do_sbc(read(TMP+Y)); + if(P & F_D) + set_nz(A); + prefetch(); + +sbc_idz + TMP2 = read_pc(); + TMP = read(B|TMP2); + TMP2++; + TMP = set_h(TMP, read(B|TMP2)); + do_sbc(read(TMP+Z)); + if(P & F_D) + set_nz(A); + prefetch(); + +sbc_ce_imm + TMP = read_pc(); + do_sbc(TMP); + if(P & F_D) + set_nz(A); + prefetch(); + +sbc_ce_zpg + TMP = read_pc(); + TMP = read(B|TMP); + do_sbc(TMP); + if(P & F_D) + set_nz(A); + prefetch(); + +sbc_ce_zpx + TMP = read_pc(); + read(TMP); + TMP = read(B|UINT8(TMP+X)); + do_sbc(TMP); + if(P & F_D) + set_nz(A); + prefetch(); + +sec_ce_imp + P |= F_C; + prefetch(); + +sed_ce_imp + P |= F_D; + prefetch(); + +see_imp + read_pc_noinc(); + P |= F_E; + prefetch(); + +sei_ce_imp + prefetch(); + P |= F_I; // Do *not* move it before the prefetch + +smb_ce_bzp + TMP = read_pc(); + TMP2 = read(TMP); + TMP2 |= 1 << ((inst_state >> 4) & 7); + write(TMP, TMP2); + prefetch(); + +sta_ce_abx + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + write(TMP+X, A); + prefetch(); + +sta_ce_aby + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + write(TMP+Y, A); + prefetch(); + +sta_ce_idx + TMP2 = read_pc(); + TMP2 += X; + TMP = read(B|TMP2); + TMP2++; + TMP = set_h(TMP, read(B|TMP2)); + write(TMP, A); + prefetch(); + +sta_ce_idy + TMP2 = read_pc(); + TMP = read(B|TMP2); + TMP2++; + TMP = set_h(TMP, read(B|TMP2)); + write(TMP+Y, A); + prefetch(); + +sta_idz + TMP2 = read_pc(); + TMP = read(B|TMP2); + TMP2++; + TMP = set_h(TMP, read(B|TMP2)); + write(TMP+Z, A); + prefetch(); + +sta_isy + read_pc_noinc(); + TMP = read_pc(); + if(P & F_E) + TMP = set_l(SP, SP+TMP); + else + TMP = SP + TMP; + TMP2 = read(TMP); + TMP++; + TMP = TMP2 | (read(TMP) << 8); + write(TMP+Y, A); + prefetch(); + +sta_ce_zpg + TMP = read_pc(); + write(B|TMP, A); + prefetch(); + +sta_ce_zpx + TMP = read_pc(); + write(B|UINT8(TMP+X), A); + prefetch(); + +stx_aby + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + write(TMP+Y, X); + prefetch(); + +stx_ce_zpg + TMP = read_pc(); + write(B|TMP, X); + prefetch(); + +stx_ce_zpy + TMP = read_pc(); + write(B|UINT8(TMP+Y), X); + prefetch(); + +sty_abx + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + write(TMP+X, Y); + prefetch(); + +sty_ce_zpg + TMP = read_pc(); + write(B|TMP, Y); + prefetch(); + +sty_ce_zpx + TMP = read_pc(); + write(B|UINT8(TMP+X), Y); + prefetch(); + +stz_ce_aba + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + write(TMP, A); + prefetch(); + +stz_ce_abx + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + write(TMP+X, A); + prefetch(); + +stz_ce_zpg + TMP = read_pc(); + write(B|TMP, Z); + prefetch(); + +stz_ce_zpx + TMP = read_pc(); + write(B|UINT8(TMP+X), Z); + prefetch(); + +tab_imp + B = A << 8; + prefetch(); + +tax_ce_imp + X = A; + set_nz(X); + prefetch(); + +tay_ce_imp + Y = A; + set_nz(Y); + prefetch(); + +taz_imp + Z = A; + set_nz(Z); + prefetch(); + +tba_imp + A = B >> 8; + set_nz(A); + prefetch(); + +trb_ce_aba + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + TMP2 = read(TMP); + if(A & TMP2) + P &= ~F_Z; + else + P |= F_Z; + TMP2 &= ~A; + write(TMP, TMP2); + prefetch(); + +trb_ce_zpg + TMP = read_pc(); + TMP2 = read(TMP); + if(A & TMP2) + P &= ~F_Z; + else + P |= F_Z; + TMP2 &= ~A; + write(TMP, TMP2); + prefetch(); + +tsb_ce_aba + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + TMP2 = read(TMP); + if(A & TMP2) + P &= ~F_Z; + else + P |= F_Z; + TMP2 |= A; + write(TMP, TMP2); + prefetch(); + +tsb_ce_zpg + TMP = read_pc(); + TMP2 = read(TMP); + if(A & TMP2) + P &= ~F_Z; + else + P |= F_Z; + TMP2 |= A; + write(TMP, TMP2); + prefetch(); + +tsx_ce_imp + X = SP; + set_nz(X); + prefetch(); + +tsy_imp + Y = SP >> 8; + set_nz(Y); + prefetch(); + +txa_ce_imp + A = X; + set_nz(A); + prefetch(); + +txs_ce_imp + SP = set_l(SP, X); + prefetch_noirq(); + +tys_imp + SP = set_h(SP, Y); + prefetch(); + +tya_ce_imp + A = Y; + set_nz(A); + prefetch(); + +tza_imp + A = Z; + set_nz(A); + prefetch(); diff --git a/src/devices/cpu/m6502/om740.lst b/src/devices/cpu/m6502/om740.lst new file mode 100644 index 00000000000..9f17dc639bf --- /dev/null +++ b/src/devices/cpu/m6502/om740.lst @@ -0,0 +1,749 @@ +# m740 opcodes +set_imp + read_pc_noinc(); + P |= F_T; + inst_state_base = 0x100; + prefetch(); + +clt_imp + read_pc_noinc(); + P &= ~F_T; + inst_state_base = 0; + prefetch(); + +ldm_imz + TMP = read_pc(); + TMP2 = read_pc(); + write(TMP2, TMP); + prefetch(); + +jsr_spg + TMP = read_pc_noinc(); + read(SP); + write(SP, PC>>8); + dec_SP(); + write(SP, PC); + dec_SP(); + TMP = set_h(TMP, 0xff); + PC = TMP; + prefetch(); + +clb_bac + read_pc_noinc(); + A = do_clb(A, (IR>>5) & 7); + prefetch(); + +seb_bac + read_pc_noinc(); + A = do_seb(A, (IR>>5) & 7); + prefetch(); + +clb_biz + TMP = read_pc(); + TMP2 = read(TMP); + TMP2 = do_clb(TMP2, (IR>>5) & 7); + write(TMP, TMP2); + prefetch(); + +seb_biz + TMP = read_pc(); + TMP2 = read(TMP); + TMP2 = do_seb(TMP2, (IR>>5) & 7); + write(TMP, TMP2); + prefetch(); + +bbc_bzr + TMP = read_pc(); + TMP2 = read(TMP); + TMP = read_pc(); + read_pc_noinc(); + if(!(TMP2 & (1 << ((IR>>5) & 7)))) { + PC += INT8(TMP); + } + prefetch(); + +bbs_bzr + TMP = read_pc(); + TMP2 = read(TMP); + TMP = read_pc(); + read_pc_noinc(); + if(TMP2 & (1 << ((IR>>5) & 7))) { + PC += INT8(TMP); + } + prefetch(); + +bbc_bar + TMP = read_pc(); + read_pc_noinc(); + if(!(A & (1 << ((IR>>5) & 7)))) { + PC += INT8(TMP); + } + prefetch(); + +bbs_bar + TMP = read_pc(); + read_pc_noinc(); + if(A & (1 << ((IR>>5) & 7))) { + PC += INT8(TMP); + } + prefetch(); + +rrf_zpg + TMP = read_pc(); + TMP2 = read(TMP); + TMP2 = do_rrf(TMP2); + write(TMP, TMP2); + prefetch(); + +bra_rel + TMP = read_pc(); + read_pc_noinc(); + if(page_changing(PC, INT8(TMP))) { + read_arg(set_l(PC, PC+INT8(TMP))); + } + PC += INT8(TMP); + prefetch(); + +jmp_zpi + TMP2 = read_pc(); + TMP = read(TMP2 & 0xff); + TMP = set_h(TMP, read((TMP2+1) & 0xff)); + PC = TMP; + prefetch(); + +reset740 + PC = read_arg(0xfffe); + PC = set_h(PC, read_arg(0xffff)); + prefetch(); + inst_state = -1; + +brk740_imp + // The 6502 bug when a nmi occurs in a brk is reproduced (case !irq_taken && nmi_state) + if(irq_taken) { + read_pc_noinc(); + } else { + read_pc(); + } + write(SP, PC >> 8); + dec_SP(); + write(SP, PC); + dec_SP(); + write(SP, irq_taken ? P & ~F_B : P); + dec_SP(); + if(nmi_state) { + PC = read_arg(0xfffa); + PC = set_h(PC, read_arg(0xfffb)); + nmi_state = false; + standard_irq_callback(NMI_LINE); + } else { + PC = read_arg(m_irq_vector); + PC = set_h(PC, read_arg(m_irq_vector+1)); + if(irq_taken) + standard_irq_callback(IRQ_LINE); + } + irq_taken = false; + P |= F_I; // Do *not* move after the prefetch + prefetch(); + inst_state = -1; + +# T=1 opcodes + +adct_aba + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + TMP = read(TMP); + TMP2 = read(X); + do_adct(TMP); + write(X, TMP2); + prefetch(); + +adct_abx + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + if(page_changing(TMP, X)) { + read(set_l(TMP, TMP+X)); + } + TMP += X; + TMP = read(TMP); + TMP2 = read(X); + do_adct(TMP); + write(X, TMP2); + prefetch(); + +adct_aby + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + if(page_changing(TMP, Y)) { + read(set_l(TMP, TMP+Y)); + } + TMP += Y; + TMP = read(TMP); + TMP2 = read(X); + do_adct(TMP); + write(X, TMP2); + prefetch(); + +adct_idx + TMP2 = read_pc(); + read(TMP2); + TMP2 += X; + TMP = read(TMP2 & 0xff); + TMP = set_h(TMP, read((TMP2+1) & 0xff)); + TMP2 = read(X); + do_adct(read(TMP)); + write(X, TMP2); + prefetch(); + +adct_idy + TMP2 = read_pc(); + TMP = read(TMP2); + TMP = set_h(TMP, read((TMP2+1) & 0xff)); + if(page_changing(TMP, Y)) { + read(set_l(TMP, TMP+Y)); + } + TMP2 = read(X); + do_adct(read(TMP+Y)); + write(X, TMP2); + prefetch(); + +adct_imm + TMP = read_pc(); + TMP2 = read(X); + do_adct(TMP); + write(X, TMP2); + prefetch(); + +adct_zpg + TMP = read_pc(); + TMP = read(TMP); + TMP2 = read(X); + do_adct(TMP); + write(X, TMP2); + prefetch(); + +adct_zpx + TMP = read_pc(); + read(TMP); + TMP = read(UINT8(TMP+X)); + TMP2 = read(X); + do_adct(TMP); + write(X, TMP2); + prefetch(); + +andt_aba + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + TMP2 = read(X); + TMP2 &= read(TMP); + set_nz(TMP2); + write(X, TMP2); + prefetch(); + +andt_abx + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + if(page_changing(TMP, X)) { + read(set_l(TMP, TMP+X)); + } + TMP += X; + TMP2 = read(X); + TMP2 &= read(TMP); + set_nz(TMP2); + write(X, TMP2); + prefetch(); + +andt_aby + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + if(page_changing(TMP, Y)) { + read(set_l(TMP, TMP+Y)); + } + TMP += Y; + TMP2 = read(X); + TMP2 &= read(TMP); + set_nz(TMP2); + write(X, TMP2); + prefetch(); + +andt_imm + TMP2 = read(X); + TMP2 &= read_pc(); + set_nz(TMP2); + write(X, TMP2); + prefetch(); + +andt_idx + TMP2 = read_pc(); + read(TMP2); + TMP2 += X; + TMP = read(TMP2 & 0xff); + TMP = set_h(TMP, read((TMP2+1) & 0xff)); + TMP2 = read(X); + TMP2 &= read(TMP); + set_nz(TMP2); + write(X, TMP2); + prefetch(); + +andt_idy + TMP2 = read_pc(); + TMP = read(TMP2); + TMP = set_h(TMP, read((TMP2+1) & 0xff)); + if(page_changing(TMP, Y)) { + read(set_l(TMP, TMP+Y)); + } + TMP2 = read(X); + TMP2 &= read(TMP+Y); + set_nz(TMP2); + write(X, TMP2); + prefetch(); + +andt_zpg + TMP = read_pc(); + TMP2 = read(X); + TMP2 &= read(TMP); + set_nz(TMP2); + write(X, TMP2); + prefetch(); + +andt_zpx + TMP = read_pc(); + read(TMP); + TMP2 = read(X); + TMP2 &= read(UINT8(TMP+X)); + set_nz(TMP2); + write(X, TMP2); + prefetch(); + +com_zpg + TMP = read_pc(); + TMP2 = read(TMP); + TMP2 ^= 0xff; + set_nz(TMP2); + write(TMP, TMP2); + prefetch(); + +cmpt_aba + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + TMP = read(TMP); + TMP2 = read(X); + do_cmp(TMP2, TMP); + prefetch(); + +cmpt_abx + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + if(page_changing(TMP, X)) { + read(set_l(TMP, TMP+X)); + } + TMP += X; + TMP = read(TMP); + TMP2 = read(X); + do_cmp(TMP2, TMP); + prefetch(); + +cmpt_aby + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + if(page_changing(TMP, Y)) { + read(set_l(TMP, TMP+Y)); + } + TMP += Y; + TMP = read(TMP); + TMP2 = read(X); + do_cmp(TMP2, TMP); + prefetch(); + +cmpt_idx + TMP2 = read_pc(); + read(TMP2); + TMP2 += X; + TMP = read(TMP2 & 0xff); + TMP = set_h(TMP, read((TMP2+1) & 0xff)); + TMP2 = read(X); + do_cmp(TMP2, read(TMP)); + prefetch(); + +cmpt_idy + TMP2 = read_pc(); + TMP = read(TMP2); + TMP = set_h(TMP, read((TMP2+1) & 0xff)); + if(page_changing(TMP, Y)) { + read(set_l(TMP, TMP+Y)); + } + TMP2 = read(X); + do_cmp(TMP2, read(TMP+Y)); + prefetch(); + +cmpt_imm + TMP = read_pc(); + TMP2 = read(X); + do_cmp(TMP2, TMP); + prefetch(); + +cmpt_zpg + TMP = read_pc(); + TMP = read(TMP); + TMP2 = read(X); + do_cmp(TMP2, TMP); + prefetch(); + +cmpt_zpx + TMP = read_pc(); + read(TMP); + TMP = read(UINT8(TMP+X)); + TMP2 = read(X); + do_cmp(TMP2, TMP); + prefetch(); + +dec_acc + read_pc_noinc(); + A--; + set_nz(A); + prefetch(); + +dect_acc + read_pc_noinc(); + TMP2 = read(X); + TMP2--; + set_nz(TMP2); + write(X, TMP2); + prefetch(); + +eort_aba + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + TMP2 = read(X); + TMP2 ^= read(TMP); + set_nz(TMP2); + write(X, TMP2); + prefetch(); + +eort_abx + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + if(page_changing(TMP, X)) { + read(set_l(TMP, TMP+X)); + } + TMP += X; + TMP2 = read(X); + TMP2 ^= read(TMP); + set_nz(TMP2); + write(X, TMP2); + prefetch(); + +eort_aby + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + if(page_changing(TMP, Y)) { + read(set_l(TMP, TMP+Y)); + } + TMP += Y; + TMP2 = read(X); + TMP2 ^= read(TMP); + set_nz(TMP2); + write(X, TMP2); + prefetch(); + +eort_idx + TMP2 = read_pc(); + read(TMP2); + TMP2 += X; + TMP = read(TMP2 & 0xff); + TMP = set_h(TMP, read((TMP2+1) & 0xff)); + TMP2 = read(X); + TMP2 ^= read(TMP); + set_nz(TMP2); + write(X, TMP2); + prefetch(); + +eort_idy + TMP2 = read_pc(); + TMP = read(TMP2); + TMP = set_h(TMP, read((TMP2+1) & 0xff)); + if(page_changing(TMP, Y)) { + read(set_l(TMP, TMP+Y)); + } + TMP2 = read(X); + TMP2 ^= read(TMP+Y); + set_nz(TMP2); + write(X, TMP2); + prefetch(); + +eort_imm + TMP2 = read(X); + TMP2 ^= read_pc(); + set_nz(TMP2); + write(X, TMP2); + prefetch(); + +eort_zpg + TMP = read_pc(); + TMP2 = read(X); + TMP2 ^= read(TMP+Y); + set_nz(TMP2); + write(X, TMP2); + prefetch(); + +eort_zpx + TMP = read_pc(); + read(TMP); + TMP2 = read(X); + TMP2 ^= read(UINT8(TMP+X)); + set_nz(TMP2); + write(X, TMP2); + prefetch(); + +inc_acc + read_pc_noinc(); + A++; + set_nz(A); + prefetch(); + +inct_acc + read_pc_noinc(); + TMP2 = read(X); + TMP2++; + set_nz(TMP2); + write(X, TMP2); + prefetch(); + +ldt_aba + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + TMP2 = read(TMP); + set_nz(TMP2); + write(X, TMP2); + prefetch(); + +ldt_abx + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + if(page_changing(TMP, X)) { + read(set_l(TMP, TMP+X)); + } + TMP2 = read(TMP + X); + set_nz(TMP2); + write(X, TMP2); + prefetch(); + +ldt_aby + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + if(page_changing(TMP, Y)) { + read(set_l(TMP, TMP+Y)); + } + TMP2 = read(TMP + Y); + set_nz(TMP2); + write(X, TMP2); + prefetch(); + +ldt_idx + TMP2 = read_pc(); + read(TMP2); + TMP2 += X; + TMP = read(TMP2 & 0xff); + TMP = set_h(TMP, read((TMP2+1) & 0xff)); + TMP2 = read(TMP); + set_nz(TMP2); + write(X, TMP2); + prefetch(); + +ldt_idy + TMP2 = read_pc(); + TMP = read(TMP2); + TMP = set_h(TMP, read((TMP2+1) & 0xff)); + if(page_changing(TMP, Y)) { + read(set_l(TMP, TMP+Y)); + } + TMP2 = read(TMP+Y); + set_nz(TMP2); + write(X, TMP2); + prefetch(); + +ldt_imm + TMP2 = read_pc(); + set_nz(TMP2); + write(X, TMP2); + prefetch(); + +ldt_zpg + TMP = read_pc(); + TMP2 = read(TMP); + set_nz(TMP2); + write(X, TMP2); + prefetch(); + +ldt_zpx + TMP = read_pc(); + read(TMP); + TMP2 = read(UINT8(TMP+X)); + set_nz(TMP2); + write(X, TMP2); + prefetch(); + +ort_aba + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + TMP2 = read(X); + TMP2 |= read(TMP); + set_nz(TMP2); + write(X, TMP2); + prefetch(); + +ort_abx + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + if(page_changing(TMP, X)) { + read(set_l(TMP, TMP+X)); + } + TMP += X; + TMP2 = read(X); + TMP2 |= read(TMP); + set_nz(TMP2); + write(X, TMP2); + prefetch(); + +ort_aby + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + if(page_changing(TMP, Y)) { + read(set_l(TMP, TMP+Y)); + } + TMP += Y; + TMP2 = read(X); + TMP2 |= read(TMP); + set_nz(TMP2); + write(X, TMP2); + prefetch(); + +ort_imm + TMP2 = read(X); + TMP2 |= read_pc(); + set_nz(TMP2); + write(X, TMP2); + prefetch(); + +ort_idx + TMP2 = read_pc(); + read(TMP2); + TMP2 += X; + TMP = read(TMP2 & 0xff); + TMP = set_h(TMP, read((TMP2+1) & 0xff)); + TMP2 = read(X); + TMP2 |= read(TMP); + set_nz(TMP2); + write(X, TMP2); + prefetch(); + +ort_idy + TMP2 = read_pc(); + TMP = read(TMP2); + TMP = set_h(TMP, read((TMP2+1) & 0xff)); + if(page_changing(TMP, Y)) { + read(set_l(TMP, TMP+Y)); + } + TMP2 = read(X); + TMP2 |= read(TMP+Y); + set_nz(TMP2); + write(X, TMP2); + prefetch(); + +ort_zpg + TMP = read_pc(); + TMP2 = read(X); + TMP2 |= read(TMP); + set_nz(TMP2); + write(X, TMP2); + prefetch(); + +ort_zpx + TMP = read_pc(); + read(TMP); + TMP2 = read(X); + TMP2 |= read(UINT8(TMP+X)); + set_nz(TMP2); + write(X, TMP2); + prefetch(); + +sbct_aba + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + TMP = read(TMP); + TMP2 = read(X); + do_sbct(TMP); + write(X, TMP2); + prefetch(); + +sbct_abx + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + if(page_changing(TMP, X)) { + read(set_l(TMP, TMP+X)); + } + TMP += X; + TMP = read(TMP); + TMP2 = read(X); + do_sbct(TMP); + write(X, TMP2); + prefetch(); + +sbct_aby + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + if(page_changing(TMP, Y)) { + read(set_l(TMP, TMP+Y)); + } + TMP += Y; + TMP = read(TMP); + TMP2 = read(X); + do_sbct(TMP); + write(X, TMP2); + prefetch(); + +sbct_idx + TMP2 = read_pc(); + read(TMP2); + TMP2 += X; + TMP = read(TMP2 & 0xff); + TMP = set_h(TMP, read((TMP2+1) & 0xff)); + TMP2 = read(X); + do_sbct(read(TMP)); + write(X, TMP2); + prefetch(); + +sbct_idy + TMP2 = read_pc(); + TMP = read(TMP2); + TMP = set_h(TMP, read((TMP2+1) & 0xff)); + if(page_changing(TMP, Y)) { + read(set_l(TMP, TMP+Y)); + } + TMP2 = read(X); + do_sbct(read(TMP+Y)); + write(X, TMP2); + prefetch(); + +sbct_imm + TMP = read_pc(); + TMP2 = read(X); + do_sbct(TMP); + write(X, TMP2); + prefetch(); + +sbct_zpg + TMP = read_pc(); + TMP = read(TMP); + TMP2 = read(X); + do_sbct(TMP); + write(X, TMP2); + prefetch(); + +sbct_zpx + TMP = read_pc(); + read(TMP); + TMP = read(UINT8(TMP+X)); + TMP2 = read(X); + do_sbct(TMP); + write(X, TMP2); + prefetch(); diff --git a/src/devices/cpu/m6502/on2a03.lst b/src/devices/cpu/m6502/on2a03.lst new file mode 100644 index 00000000000..7d8a72c8d62 --- /dev/null +++ b/src/devices/cpu/m6502/on2a03.lst @@ -0,0 +1,297 @@ +# n2a03 opcodes - same as 6502 but with d disabled +adc_nd_aba + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + TMP = read(TMP); + do_adc_nd(TMP); + prefetch(); + +adc_nd_abx + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + if(page_changing(TMP, X)) { + read(set_l(TMP, TMP+X)); + } + TMP += X; + TMP = read(TMP); + do_adc_nd(TMP); + prefetch(); + +adc_nd_aby + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + if(page_changing(TMP, Y)) { + read(set_l(TMP, TMP+Y)); + } + TMP += Y; + TMP = read(TMP); + do_adc_nd(TMP); + prefetch(); + +adc_nd_idx + TMP2 = read_pc(); + read(TMP2); + TMP2 += X; + TMP = read(TMP2 & 0xff); + TMP = set_h(TMP, read((TMP2+1) & 0xff)); + do_adc_nd(read(TMP)); + prefetch(); + +adc_nd_idy + TMP2 = read_pc(); + TMP = read(TMP2); + TMP = set_h(TMP, read((TMP2+1) & 0xff)); + if(page_changing(TMP, Y)) { + read(set_l(TMP, TMP+Y)); + } + do_adc_nd(read(TMP+Y)); + prefetch(); + +adc_nd_imm + TMP = read_pc(); + do_adc_nd(TMP); + prefetch(); + +adc_nd_zpg + TMP = read_pc(); + TMP = read(TMP); + do_adc_nd(TMP); + prefetch(); + +adc_nd_zpx + TMP = read_pc(); + read(TMP); + TMP = read(UINT8(TMP+X)); + do_adc_nd(TMP); + prefetch(); + +arr_nd_imm + A &= read_pc(); + do_arr_nd(); + prefetch(); + +rra_nd_aba + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + TMP2 = read(TMP); + write(TMP, TMP2); + TMP2 = do_ror(TMP2); + write(TMP, TMP2); + do_adc_nd(TMP2); + prefetch(); + +rra_nd_abx + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + read(set_l(TMP, TMP+X)); + TMP += X; + TMP2 = read(TMP); + write(TMP, TMP2); + TMP2 = do_ror(TMP2); + write(TMP, TMP2); + do_adc_nd(TMP2); + prefetch(); + +rra_nd_aby + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + read(set_l(TMP, TMP+Y)); + TMP += Y; + TMP2 = read(TMP); + write(TMP, TMP2); + TMP2 = do_ror(TMP2); + write(TMP, TMP2); + do_adc_nd(TMP2); + prefetch(); + +rra_nd_idx + TMP2 = read_pc(); + read(TMP2); + TMP2 += X; + TMP = read(TMP2 & 0xff); + TMP = set_h(TMP, read((TMP2+1) & 0xff)); + TMP2 = read(TMP); + write(TMP, TMP2); + TMP2 = do_ror(TMP2); + write(TMP, TMP2); + do_adc_nd(TMP2); + prefetch(); + +rra_nd_idy + TMP2 = read_pc(); + TMP = read(TMP2); + TMP = set_h(TMP, read((TMP2+1) & 0xff)); + read(set_l(TMP, TMP+Y)); + TMP += Y; + TMP2 = read(TMP); + write(TMP, TMP2); + TMP2 = do_ror(TMP2); + write(TMP, TMP2); + do_adc_nd(TMP2); + prefetch(); + +rra_nd_zpg + TMP = read_pc(); + TMP2 = read(TMP); + write(TMP, TMP2); + TMP2 = do_ror(TMP2); + write(TMP, TMP2); + do_adc_nd(TMP2); + prefetch(); + +rra_nd_zpx + TMP = read_pc(); + read(TMP); + TMP = UINT8(TMP+X); + TMP2 = read(TMP); + write(TMP, TMP2); + TMP2 = do_ror(TMP2); + write(TMP, TMP2); + do_adc_nd(TMP2); + prefetch(); + +sbc_nd_aba + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + TMP = read(TMP); + do_sbc_nd(TMP); + prefetch(); + +sbc_nd_abx + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + if(page_changing(TMP, X)) { + read(set_l(TMP, TMP+X)); + } + TMP += X; + TMP = read(TMP); + do_sbc_nd(TMP); + prefetch(); + +sbc_nd_aby + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + if(page_changing(TMP, Y)) { + read(set_l(TMP, TMP+Y)); + } + TMP += Y; + TMP = read(TMP); + do_sbc_nd(TMP); + prefetch(); + +sbc_nd_idx + TMP2 = read_pc(); + read(TMP2); + TMP2 += X; + TMP = read(TMP2 & 0xff); + TMP = set_h(TMP, read((TMP2+1) & 0xff)); + do_sbc_nd(read(TMP)); + prefetch(); + +sbc_nd_idy + TMP2 = read_pc(); + TMP = read(TMP2); + TMP = set_h(TMP, read((TMP2+1) & 0xff)); + if(page_changing(TMP, Y)) { + read(set_l(TMP, TMP+Y)); + } + do_sbc_nd(read(TMP+Y)); + prefetch(); + +sbc_nd_imm + TMP = read_pc(); + do_sbc_nd(TMP); + prefetch(); + +sbc_nd_zpg + TMP = read_pc(); + TMP = read(TMP); + do_sbc_nd(TMP); + prefetch(); + +sbc_nd_zpx + TMP = read_pc(); + read(TMP); + TMP = read(UINT8(TMP+X)); + do_sbc_nd(TMP); + prefetch(); + +isb_nd_aba + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + TMP2 = read(TMP); + write(TMP, TMP2); + TMP2++; + write(TMP, TMP2); + do_sbc_nd(TMP2); + prefetch(); + +isb_nd_abx + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + read(set_l(TMP, TMP+X)); + TMP += X; + TMP2 = read(TMP); + write(TMP, TMP2); + TMP2++; + write(TMP, TMP2); + do_sbc_nd(TMP2); + prefetch(); + +isb_nd_aby + TMP = read_pc(); + TMP = set_h(TMP, read_pc()); + read(set_l(TMP, TMP+Y)); + TMP += Y; + TMP2 = read(TMP); + write(TMP, TMP2); + TMP2++; + write(TMP, TMP2); + do_sbc_nd(TMP2); + prefetch(); + +isb_nd_idx + TMP2 = read_pc(); + read(TMP2); + TMP2 += X; + TMP = read(TMP2 & 0xff); + TMP = set_h(TMP, read((TMP2+1) & 0xff)); + TMP2 = read(TMP); + write(TMP, TMP2); + TMP2++; + write(TMP, TMP2); + do_sbc_nd(TMP2); + prefetch(); + +isb_nd_idy + TMP2 = read_pc(); + TMP = read(TMP2); + TMP = set_h(TMP, read((TMP2+1) & 0xff)); + read(set_l(TMP, TMP+Y)); + TMP += Y; + TMP2 = read(TMP); + write(TMP, TMP2); + TMP2++; + write(TMP, TMP2); + do_sbc_nd(TMP2); + prefetch(); + +isb_nd_zpg + TMP = read_pc(); + TMP2 = read(TMP); + write(TMP, TMP2); + TMP2++; + write(TMP, TMP2); + do_sbc_nd(TMP2); + prefetch(); + +isb_nd_zpx + TMP = read_pc(); + read(TMP); + TMP = UINT8(TMP+X); + TMP2 = read(TMP); + write(TMP, TMP2); + TMP2++; + write(TMP, TMP2); + do_sbc_nd(TMP2); + prefetch(); diff --git a/src/devices/cpu/m6502/r65c02.c b/src/devices/cpu/m6502/r65c02.c new file mode 100644 index 00000000000..3101ffd0341 --- /dev/null +++ b/src/devices/cpu/m6502/r65c02.c @@ -0,0 +1,31 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +/*************************************************************************** + + r65c02.c + + Rockwell 65c02, CMOS variant with bitwise instructions + +***************************************************************************/ + +#include "emu.h" +#include "r65c02.h" + +const device_type R65C02 = &device_creator; + +r65c02_device::r65c02_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + m65c02_device(mconfig, R65C02, "R65C02", tag, owner, clock, "r65c02", __FILE__) +{ +} + +r65c02_device::r65c02_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + m65c02_device(mconfig, type, name, tag, owner, clock, shortname, source) +{ +} + +offs_t r65c02_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + return disassemble_generic(buffer, pc, oprom, opram, options, disasm_entries); +} + +#include "cpu/m6502/r65c02.inc" diff --git a/src/devices/cpu/m6502/r65c02.h b/src/devices/cpu/m6502/r65c02.h new file mode 100644 index 00000000000..ed3f65f40ad --- /dev/null +++ b/src/devices/cpu/m6502/r65c02.h @@ -0,0 +1,36 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +/*************************************************************************** + + r65c02.h + + Rockwell 65c02, CMOS variant with bitwise instructions + +***************************************************************************/ + +#ifndef __R65C02_H__ +#define __R65C02_H__ + +#include "m65c02.h" + +class r65c02_device : public m65c02_device { +public: + r65c02_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + r65c02_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + static const disasm_entry disasm_entries[0x100]; + + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + virtual void do_exec_full(); + virtual void do_exec_partial(); +}; + +enum { + R65C02_IRQ_LINE = m6502_device::IRQ_LINE, + R65C02_NMI_LINE = m6502_device::NMI_LINE, + R65C02_SET_OVERFLOW = m6502_device::V_LINE +}; + +extern const device_type R65C02; + +#endif diff --git a/src/devices/cpu/m6800/6800dasm.c b/src/devices/cpu/m6800/6800dasm.c new file mode 100644 index 00000000000..49f908013cd --- /dev/null +++ b/src/devices/cpu/m6800/6800dasm.c @@ -0,0 +1,282 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/* + * A quick-hack 6803/6808 disassembler + * + * Note: this is not the good and proper way to disassemble anything, but it works + * + * I'm afraid to put my name on it, but I feel obligated: + * This code written by Aaron Giles (agiles@sirius.com) for the MAME project + * + * History: + * 990314 HJB + * The disassembler knows about valid opcodes for M6800/1/2/3/8 and HD63701. + * 990302 HJB + * Changed the string array into a table of opcode names (or tokens) and + * argument types. This second try should give somewhat better results. + * Named the undocumented HD63701YO opcodes $12 and $13 'asx1' and 'asx2', + * since 'add contents of stack to x register' is what they do. + * + */ + +#include "emu.h" +#include "debugger.h" +#include "m6800.h" + +enum addr_mode { + inh, /* inherent */ + rel, /* relative */ + imb, /* immediate (byte) */ + imw, /* immediate (word) */ + dir, /* direct address */ + imd, /* HD63701YO: immediate, direct address */ + ext, /* extended address */ + idx, /* x + byte offset */ + imx, /* HD63701YO: immediate, x + byte offset */ + sx1 /* HD63701YO: undocumented opcodes: byte from (s+1) */ +}; + +enum op_names { + aba=0, abx, adca, adcb, adda, addb, addd, aim, + anda, andb, asl, asla, aslb, asld, asr, asra, + asrb, bcc, bcs, beq, bge, bgt, bhi, bita, + bitb, ble, bls, blt, bmi, bne, bpl, bra, + brn, bsr, bvc, bvs, cba, clc, cli, clr, + clra, clrb, clv, cmpa, cmpb, cmpx, com, coma, + comb, daa, dec, deca, decb, des, dex, eim, + eora, eorb, ill, inc, inca, incb, ins, inx, + jmp, jsr, lda, ldb, ldd, lds, ldx, lsr, + lsra, lsrb, lsrd, mul, neg, nega, negb, nop, + oim, ora, orb, psha, pshb, pshx, pula, pulb, + pulx, rol, rola, rolb, ror, rora, rorb, rti, + rts, sba, sbca, sbcb, sec, sev, sta, stb, + _std, sei, sts, stx, suba, subb, subd, swi, + wai, tab, tap, tba, tim, tpa, tst, tsta, + tstb, tsx, txs, asx1, asx2, xgdx, addx, adcx +}; + +static const char *const op_name_str[] = { + "aba", "abx", "adca", "adcb", "adda", "addb", "addd", "aim", + "anda", "andb", "asl", "asla", "aslb", "asld", "asr", "asra", + "asrb", "bcc", "bcs", "beq", "bge", "bgt", "bhi", "bita", + "bitb", "ble", "bls", "blt", "bmi", "bne", "bpl", "bra", + "brn", "bsr", "bvc", "bvs", "cba", "clc", "cli", "clr", + "clra", "clrb", "clv", "cmpa", "cmpb", "cmpx", "com", "coma", + "comb", "daa", "dec", "deca", "decb", "des", "dex", "eim", + "eora", "eorb", "illegal","inc", "inca", "incb", "ins", "inx", + "jmp", "jsr", "lda", "ldb", "ldd", "lds", "ldx", "lsr", + "lsra", "lsrb", "lsrd", "mul", "neg", "nega", "negb", "nop", + "oim", "ora", "orb", "psha", "pshb", "pshx", "pula", "pulb", + "pulx", "rol", "rola", "rolb", "ror", "rora", "rorb", "rti", + "rts", "sba", "sbca", "sbcb", "sec", "sev", "sta", "stb", + "std", "sei", "sts", "stx", "suba", "subb", "subd", "swi", + "wai", "tab", "tap", "tba", "tim", "tpa", "tst", "tsta", + "tstb", "tsx", "txs", "asx1", "asx2", "xgdx", "addx", "adcx" +}; + +/* + * This table defines the opcodes: + * byte meaning + * 0 token (menmonic) + * 1 addressing mode + * 2 invalid opcode for 1:6800/6802/6808, 2:6801/6803, 4:HD63701 + */ + +static const UINT8 table[0x102][3] = { + {ill, inh,7},{nop, inh,0},{ill, inh,7},{ill, inh,7},/* 00 */ + {lsrd,inh,1},{asld,inh,1},{tap, inh,0},{tpa, inh,0}, + {inx, inh,0},{dex, inh,0},{clv, inh,0},{sev, inh,0}, + {clc, inh,0},{sec, inh,0},{cli, inh,0},{sei, inh,0}, + {sba, inh,0},{cba, inh,0},{asx1,sx1,0},{asx2,sx1,0},/* 10 */ + {ill, inh,7},{ill, inh,7},{tab, inh,0},{tba, inh,0}, + {xgdx,inh,3},{daa, inh,0},{ill, inh,7},{aba, inh,0}, + {ill, inh,7},{ill, inh,7},{ill, inh,7},{ill, inh,7}, + {bra, rel,0},{brn, rel,0},{bhi, rel,0},{bls, rel,0},/* 20 */ + {bcc, rel,0},{bcs, rel,0},{bne, rel,0},{beq, rel,0}, + {bvc, rel,0},{bvs, rel,0},{bpl, rel,0},{bmi, rel,0}, + {bge, rel,0},{blt, rel,0},{bgt, rel,0},{ble, rel,0}, + {tsx, inh,0},{ins, inh,0},{pula,inh,0},{pulb,inh,0},/* 30 */ + {des, inh,0},{txs, inh,0},{psha,inh,0},{pshb,inh,0}, + {pulx,inh,1},{rts, inh,0},{abx, inh,1},{rti, inh,0}, + {pshx,inh,1},{mul, inh,1},{wai, inh,0},{swi, inh,0}, + {nega,inh,0},{ill, inh,7},{ill, inh,7},{coma,inh,0},/* 40 */ + {lsra,inh,0},{ill, inh,7},{rora,inh,0},{asra,inh,0}, + {asla,inh,0},{rola,inh,0},{deca,inh,0},{ill, inh,7}, + {inca,inh,0},{tsta,inh,0},{ill, inh,7},{clra,inh,0}, + {negb,inh,0},{ill, inh,7},{ill, inh,7},{comb,inh,0},/* 50 */ + {lsrb,inh,0},{ill, inh,7},{rorb,inh,0},{asrb,inh,0}, + {aslb,inh,0},{rolb,inh,0},{decb,inh,0},{ill, inh,7}, + {incb,inh,0},{tstb,inh,0},{ill, inh,7},{clrb,inh,0}, + {neg, idx,0},{aim, imx,3},{oim, imx,3},{com, idx,0},/* 60 */ + {lsr, idx,0},{eim, imx,3},{ror, idx,0},{asr, idx,0}, + {asl, idx,0},{rol, idx,0},{dec, idx,0},{tim, imx,3}, + {inc, idx,0},{tst, idx,0},{jmp, idx,0},{clr, idx,0}, + {neg, ext,0},{aim, imd,3},{oim, imd,3},{com, ext,0},/* 70 */ + {lsr, ext,0},{eim, imd,3},{ror, ext,0},{asr, ext,0}, + {asl, ext,0},{rol, ext,0},{dec, ext,0},{tim, imd,3}, + {inc, ext,0},{tst, ext,0},{jmp, ext,0},{clr, ext,0}, + {suba,imb,0},{cmpa,imb,0},{sbca,imb,0},{subd,imw,1},/* 80 */ + {anda,imb,0},{bita,imb,0},{lda, imb,0},{sta, imb,0}, + {eora,imb,0},{adca,imb,0},{ora, imb,0},{adda,imb,0}, + {cmpx,imw,0},{bsr, rel,0},{lds, imw,0},{sts, imw,0}, + {suba,dir,0},{cmpa,dir,0},{sbca,dir,0},{subd,dir,1},/* 90 */ + {anda,dir,0},{bita,dir,0},{lda, dir,0},{sta, dir,0}, + {eora,dir,0},{adca,dir,0},{ora, dir,0},{adda,dir,0}, + {cmpx,dir,0},{jsr, dir,0},{lds, dir,0},{sts, dir,0}, + {suba,idx,0},{cmpa,idx,0},{sbca,idx,0},{subd,idx,1},/* a0 */ + {anda,idx,0},{bita,idx,0},{lda, idx,0},{sta, idx,0}, + {eora,idx,0},{adca,idx,0},{ora, idx,0},{adda,idx,0}, + {cmpx,idx,0},{jsr, idx,0},{lds, idx,0},{sts, idx,0}, + {suba,ext,0},{cmpa,ext,0},{sbca,ext,0},{subd,ext,1},/* b0 */ + {anda,ext,0},{bita,ext,0},{lda, ext,0},{sta, ext,0}, + {eora,ext,0},{adca,ext,0},{ora, ext,0},{adda,ext,0}, + {cmpx,ext,0},{jsr, ext,0},{lds, ext,0},{sts, ext,0}, + {subb,imb,0},{cmpb,imb,0},{sbcb,imb,0},{addd,imw,1},/* c0 */ + {andb,imb,0},{bitb,imb,0},{ldb, imb,0},{stb, imb,0}, + {eorb,imb,0},{adcb,imb,0},{orb, imb,0},{addb,imb,0}, + {ldd, imw,1},{_std,imw,1},{ldx, imw,0},{stx, imw,0}, + {subb,dir,0},{cmpb,dir,0},{sbcb,dir,0},{addd,dir,1},/* d0 */ + {andb,dir,0},{bitb,dir,0},{ldb, dir,0},{stb, dir,0}, + {eorb,dir,0},{adcb,dir,0},{orb, dir,0},{addb,dir,0}, + {ldd, dir,1},{_std,dir,1},{ldx, dir,0},{stx, dir,0}, + {subb,idx,0},{cmpb,idx,0},{sbcb,idx,0},{addd,idx,1},/* e0 */ + {andb,idx,0},{bitb,idx,0},{ldb, idx,0},{stb, idx,0}, + {eorb,idx,0},{adcb,idx,0},{orb, idx,0},{addb,idx,0}, + {ldd, idx,1},{_std,idx,1},{ldx, idx,0},{stx, idx,0}, + {subb,ext,0},{cmpb,ext,0},{sbcb,ext,0},{addd,ext,1},/* f0 */ + {andb,ext,0},{bitb,ext,0},{ldb, ext,0},{stb, ext,0}, + {eorb,ext,0},{adcb,ext,0},{orb, ext,0},{addb,ext,0}, + {ldd, ext,1},{_std,ext,1},{ldx, ext,0},{stx, ext,0}, + + /* extra instruction $fc for NSC-8105 */ + {addx,ext,0}, + /* extra instruction $ec for NSC-8105 */ + {adcx,imb,0} +}; + +/* some macros to keep things short */ +#define OP oprom[0] +#define ARG1 opram[1] +#define ARG2 opram[2] +#define ARGW (opram[1]<<8) + opram[2] + +static unsigned Dasm680x (int subtype, char *buf, unsigned pc, const UINT8 *oprom, const UINT8 *opram) +{ + UINT32 flags = 0; + int invalid_mask; + int code = OP; + UINT8 opcode, args, invalid; + + switch( subtype ) + { + case 6800: case 6802: case 6808: case 8105: + invalid_mask = 1; + break; + case 6801: case 6803: + invalid_mask = 2; + break; + default: + invalid_mask = 4; + } + + /* NSC-8105 is a special case */ + if (subtype == 8105) + { + /* swap bits */ + code = (code & 0x3c) | ((code & 0x41) << 1) | ((code & 0x82) >> 1); + + /* and check for extra instruction */ + if (code == 0xfc) code = 0x0100; + if (code == 0xec) code = 0x0101; + } + + opcode = table[code][0]; + args = table[code][1]; + invalid = table[code][2]; + + if (opcode == bsr || opcode == jsr) + flags = DASMFLAG_STEP_OVER; + else if (opcode == rti || opcode == rts) + flags = DASMFLAG_STEP_OUT; + + if ( invalid & invalid_mask ) /* invalid for this cpu type ? */ + { + strcpy(buf, "illegal"); + return 1 | flags | DASMFLAG_SUPPORTED; + } + + buf += sprintf(buf, "%-5s", op_name_str[opcode]); + + switch( args ) + { + case rel: /* relative */ + sprintf (buf, "$%04X", pc + (INT8)ARG1 + 2); + return 2 | flags | DASMFLAG_SUPPORTED; + case imb: /* immediate (byte) */ + sprintf (buf, "#$%02X", ARG1); + return 2 | flags | DASMFLAG_SUPPORTED; + case imw: /* immediate (word) */ + sprintf (buf, "#$%04X", ARGW); + return 3 | flags | DASMFLAG_SUPPORTED; + case idx: /* indexed + byte offset */ + sprintf (buf, "(x+$%02X)", ARG1 ); + return 2 | flags | DASMFLAG_SUPPORTED; + case imx: /* immediate, indexed + byte offset */ + sprintf (buf, "#$%02X,(x+$%02x)", ARG1, ARG2 ); + return 3 | flags | DASMFLAG_SUPPORTED; + case dir: /* direct address */ + sprintf (buf, "$%02X", ARG1 ); + return 2 | flags | DASMFLAG_SUPPORTED; + case imd: /* immediate, direct address */ + sprintf (buf, "#$%02X,$%02X", ARG1, ARG2); + return 3 | flags | DASMFLAG_SUPPORTED; + case ext: /* extended address */ + sprintf (buf, "$%04X", ARGW); + return 3 | flags | DASMFLAG_SUPPORTED; + case sx1: /* byte from address (s + 1) */ + sprintf (buf, "(s+1)"); + return 1 | flags | DASMFLAG_SUPPORTED; + default: + return 1 | flags | DASMFLAG_SUPPORTED; + } +} + +CPU_DISASSEMBLE( m6800 ) +{ + return Dasm680x(6800,buffer,pc,oprom,opram); +} + +CPU_DISASSEMBLE( m6801 ) +{ + return Dasm680x(6801,buffer,pc,oprom,opram); +} + +CPU_DISASSEMBLE( m6802 ) +{ + return Dasm680x(6802,buffer,pc,oprom,opram); +} + +CPU_DISASSEMBLE( m6803 ) +{ + return Dasm680x(6803,buffer,pc,oprom,opram); +} + +CPU_DISASSEMBLE( m6808 ) +{ + return Dasm680x(6808,buffer,pc,oprom,opram); +} + +CPU_DISASSEMBLE( hd6301 ) +{ + return Dasm680x(6301,buffer,pc,oprom,opram); +} + +CPU_DISASSEMBLE( hd63701 ) +{ + return Dasm680x(63701,buffer,pc,oprom,opram); +} + +CPU_DISASSEMBLE( nsc8105 ) +{ + return Dasm680x(8105,buffer,pc,oprom,opram); +} diff --git a/src/devices/cpu/m6800/6800ops.inc b/src/devices/cpu/m6800/6800ops.inc new file mode 100644 index 00000000000..cf0360c7538 --- /dev/null +++ b/src/devices/cpu/m6800/6800ops.inc @@ -0,0 +1,2284 @@ + +/* + +HNZVC + +? = undefined +* = affected +- = unaffected +0 = cleared +1 = set +# = ccr directly affected by instruction +@ = special - carry set if bit 7 is set + +*/ + +#define OP_HANDLER(_name) void m6800_cpu_device::_name () + +//OP_HANDLER( illegal ) +OP_HANDLER( illegal ) +{ + logerror("m6800: illegal opcode: address %04X, op %02X\n",PC-1,(int) M_RDOP_ARG(PC-1)&0xFF); +} + +/* HD63701 only */ +//OP_HANDLER( trap ) +OP_HANDLER( trap ) +{ + logerror("m6800: illegal opcode: address %04X, op %02X\n",PC-1,(int) M_RDOP_ARG(PC-1)&0xFF); + TAKE_TRAP; +} + +/* $00 ILLEGAL */ + +/* $01 NOP */ +OP_HANDLER( nop ) +{ +} + +/* $02 ILLEGAL */ + +/* $03 ILLEGAL */ + +/* $04 LSRD inherent -0*-* */ +OP_HANDLER( lsrd ) +{ + UINT16 t; + CLR_NZC; t = D; CC|=(t&0x0001); + t>>=1; SET_Z16(t); D=t; +} + +/* $05 ASLD inherent ?**** */ +OP_HANDLER( asld ) +{ + int r; + UINT16 t; + t = D; r=t<<1; + CLR_NZVC; SET_FLAGS16(t,t,r); + D=r; +} + +/* $06 TAP inherent ##### */ +OP_HANDLER( tap ) +{ + CC=A; + ONE_MORE_INSN(); + CHECK_IRQ_LINES(); /* HJB 990417 */ +} + +/* $07 TPA inherent ----- */ +OP_HANDLER( tpa ) +{ + A=CC; +} + +/* $08 INX inherent --*-- */ +OP_HANDLER( inx ) +{ + ++X; + CLR_Z; SET_Z16(X); +} + +/* $09 DEX inherent --*-- */ +OP_HANDLER( dex ) +{ + --X; + CLR_Z; SET_Z16(X); +} + +/* $0a CLV */ +OP_HANDLER( clv ) +{ + CLV; +} + +/* $0b SEV */ +OP_HANDLER( sev ) +{ + SEV; +} + +/* $0c CLC */ +OP_HANDLER( clc ) +{ + CLC; +} + +/* $0d SEC */ +OP_HANDLER( sec ) +{ + SEC; +} + +/* $0e CLI */ +OP_HANDLER( cli ) +{ + CLI; + ONE_MORE_INSN(); + CHECK_IRQ_LINES(); /* HJB 990417 */ +} + +/* $0f SEI */ +OP_HANDLER( sei ) +{ + SEI; + ONE_MORE_INSN(); + CHECK_IRQ_LINES(); /* HJB 990417 */ +} + +/* $10 SBA inherent -**** */ +OP_HANDLER( sba ) +{ + UINT16 t; + t=A-B; + CLR_NZVC; SET_FLAGS8(A,B,t); + A=t; +} + +/* $11 CBA inherent -**** */ +OP_HANDLER( cba ) +{ + UINT16 t; + t=A-B; + CLR_NZVC; SET_FLAGS8(A,B,t); +} + +/* $12 ILLEGAL */ +OP_HANDLER( undoc1 ) +{ + X += RM( S + 1 ); +} + +/* $13 ILLEGAL */ +OP_HANDLER( undoc2 ) +{ + X += RM( S + 1 ); +} + + +/* $14 ILLEGAL */ + +/* $15 ILLEGAL */ + +/* $16 TAB inherent -**0- */ +OP_HANDLER( tab ) +{ + B=A; + CLR_NZV; SET_NZ8(B); +} + +/* $17 TBA inherent -**0- */ +OP_HANDLER( tba ) +{ + A=B; + CLR_NZV; SET_NZ8(A); +} + +/* $18 XGDX inherent ----- */ /* HD63701YO only */ +OP_HANDLER( xgdx ) +{ + UINT16 t = X; + X = D; + D=t; +} + +/* $19 DAA inherent (A) -**0* */ +OP_HANDLER( daa ) +{ + UINT8 msn, lsn; + UINT16 t, cf = 0; + msn=A & 0xf0; lsn=A & 0x0f; + if( lsn>0x09 || CC&0x20 ) cf |= 0x06; + if( msn>0x80 && lsn>0x09 ) cf |= 0x60; + if( msn>0x90 || CC&0x01 ) cf |= 0x60; + t = cf + A; + CLR_NZV; /* keep carry from previous operation */ + SET_NZ8((UINT8)t); SET_C8(t); + A = t; +} + +/* $1a ILLEGAL */ + +/* $1a SLP */ /* HD63701YO only */ +OP_HANDLER( slp ) +{ + /* wait for next IRQ (same as waiting of wai) */ + m_wai_state |= M6800_SLP; + EAT_CYCLES; +} + +/* $1b ABA inherent ***** */ +OP_HANDLER( aba ) +{ + UINT16 t; + t=A+B; + CLR_HNZVC; SET_FLAGS8(A,B,t); SET_H(A,B,t); + A=t; +} + +/* $1c ILLEGAL */ + +/* $1d ILLEGAL */ + +/* $1e ILLEGAL */ + +/* $1f ILLEGAL */ + +/* $20 BRA relative ----- */ +OP_HANDLER( bra ) +{ + UINT8 t; + IMMBYTE(t); + PC+=SIGNED(t); +} + +/* $21 BRN relative ----- */ +static UINT8 m6800_brn_t; // hack around GCC 4.6 error because we need the side effects of IMMBYTE +OP_HANDLER( brn ) +{ + IMMBYTE(m6800_brn_t); +} + +/* $22 BHI relative ----- */ +OP_HANDLER( bhi ) +{ + UINT8 t; + BRANCH(!(CC&0x05)); +} + +/* $23 BLS relative ----- */ +OP_HANDLER( bls ) +{ + UINT8 t; + BRANCH(CC&0x05); +} + +/* $24 BCC relative ----- */ +OP_HANDLER( bcc ) +{ + UINT8 t; + BRANCH(!(CC&0x01)); +} + +/* $25 BCS relative ----- */ +OP_HANDLER( bcs ) +{ + UINT8 t; + BRANCH(CC&0x01); +} + +/* $26 BNE relative ----- */ +OP_HANDLER( bne ) +{ + UINT8 t; + BRANCH(!(CC&0x04)); +} + +/* $27 BEQ relative ----- */ +OP_HANDLER( beq ) +{ + UINT8 t; + BRANCH(CC&0x04); +} + +/* $28 BVC relative ----- */ +OP_HANDLER( bvc ) +{ + UINT8 t; + BRANCH(!(CC&0x02)); +} + +/* $29 BVS relative ----- */ +OP_HANDLER( bvs ) +{ + UINT8 t; + BRANCH(CC&0x02); +} + +/* $2a BPL relative ----- */ +OP_HANDLER( bpl ) +{ + UINT8 t; + BRANCH(!(CC&0x08)); +} + +/* $2b BMI relative ----- */ +OP_HANDLER( bmi ) +{ + UINT8 t; + BRANCH(CC&0x08); +} + +/* $2c BGE relative ----- */ +OP_HANDLER( bge ) +{ + UINT8 t; + BRANCH(!NXORV); +} + +/* $2d BLT relative ----- */ +OP_HANDLER( blt ) +{ + UINT8 t; + BRANCH(NXORV); +} + +/* $2e BGT relative ----- */ +OP_HANDLER( bgt ) +{ + UINT8 t; + BRANCH(!(NXORV||CC&0x04)); +} + +/* $2f BLE relative ----- */ +OP_HANDLER( ble ) +{ + UINT8 t; + BRANCH(NXORV||CC&0x04); +} + +/* $30 TSX inherent ----- */ +OP_HANDLER( tsx ) +{ + X = ( S + 1 ); +} + +/* $31 INS inherent ----- */ +OP_HANDLER( ins ) +{ + ++S; +} + +/* $32 PULA inherent ----- */ +OP_HANDLER( pula ) +{ + PULLBYTE(m_d.b.h); +} + +/* $33 PULB inherent ----- */ +OP_HANDLER( pulb ) +{ + PULLBYTE(m_d.b.l); +} + +/* $34 DES inherent ----- */ +OP_HANDLER( des ) +{ + --S; +} + +/* $35 TXS inherent ----- */ +OP_HANDLER( txs ) +{ + S = ( X - 1 ); +} + +/* $36 PSHA inherent ----- */ +OP_HANDLER( psha ) +{ + PUSHBYTE(m_d.b.h); +} + +/* $37 PSHB inherent ----- */ +OP_HANDLER( pshb ) +{ + PUSHBYTE(m_d.b.l); +} + +/* $38 PULX inherent ----- */ +OP_HANDLER( pulx ) +{ + PULLWORD(pX); +} + +/* $39 RTS inherent ----- */ +OP_HANDLER( rts ) +{ + PULLWORD(pPC); +} + +/* $3a ABX inherent ----- */ +OP_HANDLER( abx ) +{ + X += B; +} + +/* $3b RTI inherent ##### */ +OP_HANDLER( rti ) +{ + PULLBYTE(CC); + PULLBYTE(B); + PULLBYTE(A); + PULLWORD(pX); + PULLWORD(pPC); + CHECK_IRQ_LINES(); /* HJB 990417 */ +} + +/* $3c PSHX inherent ----- */ +OP_HANDLER( pshx ) +{ + PUSHWORD(pX); +} + +/* $3d MUL inherent --*-@ */ +OP_HANDLER( mul ) +{ + UINT16 t; + t=A*B; + CLR_C; + if(t&0x80) SEC; + D=t; +} + +/* $3e WAI inherent ----- */ +OP_HANDLER( wai ) +{ + /* + * WAI stacks the entire machine state on the + * hardware stack, then waits for an interrupt. + */ + m_wai_state |= M6800_WAI; + PUSHWORD(pPC); + PUSHWORD(pX); + PUSHBYTE(A); + PUSHBYTE(B); + PUSHBYTE(CC); + CHECK_IRQ_LINES(); + if (m_wai_state & M6800_WAI) EAT_CYCLES; +} + +/* $3f SWI absolute indirect ----- */ +OP_HANDLER( swi ) +{ + PUSHWORD(pPC); + PUSHWORD(pX); + PUSHBYTE(A); + PUSHBYTE(B); + PUSHBYTE(CC); + SEI; + PCD = RM16(0xfffa); +} + +/* $40 NEGA inherent ?**** */ +OP_HANDLER( nega ) +{ + UINT16 r; + r=-A; + CLR_NZVC; SET_FLAGS8(0,A,r); + A=r; +} + +/* $41 ILLEGAL */ + +/* $42 ILLEGAL */ + +/* $43 COMA inherent -**01 */ +OP_HANDLER( coma ) +{ + A = ~A; + CLR_NZV; SET_NZ8(A); SEC; +} + +/* $44 LSRA inherent -0*-* */ +OP_HANDLER( lsra ) +{ + CLR_NZC; CC|=(A&0x01); + A>>=1; SET_Z8(A); +} + +/* $45 ILLEGAL */ + +/* $46 RORA inherent -**-* */ +OP_HANDLER( rora ) +{ + UINT8 r; + r=(CC&0x01)<<7; + CLR_NZC; CC|=(A&0x01); + r |= A>>1; SET_NZ8(r); + A=r; +} + +/* $47 ASRA inherent ?**-* */ +OP_HANDLER( asra ) +{ + CLR_NZC; CC|=(A&0x01); + A>>=1; A|=((A&0x40)<<1); + SET_NZ8(A); +} + +/* $48 ASLA inherent ?**** */ +OP_HANDLER( asla ) +{ + UINT16 r; + r=A<<1; + CLR_NZVC; SET_FLAGS8(A,A,r); + A=r; +} + +/* $49 ROLA inherent -**** */ +OP_HANDLER( rola ) +{ + UINT16 t,r; + t = A; r = CC&0x01; r |= t<<1; + CLR_NZVC; SET_FLAGS8(t,t,r); + A=r; +} + +/* $4a DECA inherent -***- */ +OP_HANDLER( deca ) +{ + --A; + CLR_NZV; SET_FLAGS8D(A); +} + +/* $4b ILLEGAL */ + +/* $4c INCA inherent -***- */ +OP_HANDLER( inca ) +{ + ++A; + CLR_NZV; SET_FLAGS8I(A); +} + +/* $4d TSTA inherent -**0- */ +OP_HANDLER( tsta ) +{ + CLR_NZVC; SET_NZ8(A); +} + +/* $4e ILLEGAL */ + +/* $4f CLRA inherent -0100 */ +OP_HANDLER( clra ) +{ + A=0; + CLR_NZVC; SEZ; +} + +/* $50 NEGB inherent ?**** */ +OP_HANDLER( negb ) +{ + UINT16 r; + r=-B; + CLR_NZVC; SET_FLAGS8(0,B,r); + B=r; +} + +/* $51 ILLEGAL */ + +/* $52 ILLEGAL */ + +/* $53 COMB inherent -**01 */ +OP_HANDLER( comb ) +{ + B = ~B; + CLR_NZV; SET_NZ8(B); SEC; +} + +/* $54 LSRB inherent -0*-* */ +OP_HANDLER( lsrb ) +{ + CLR_NZC; CC|=(B&0x01); + B>>=1; SET_Z8(B); +} + +/* $55 ILLEGAL */ + +/* $56 RORB inherent -**-* */ +OP_HANDLER( rorb ) +{ + UINT8 r; + r=(CC&0x01)<<7; + CLR_NZC; CC|=(B&0x01); + r |= B>>1; SET_NZ8(r); + B=r; +} + +/* $57 ASRB inherent ?**-* */ +OP_HANDLER( asrb ) +{ + CLR_NZC; CC|=(B&0x01); + B>>=1; B|=((B&0x40)<<1); + SET_NZ8(B); +} + +/* $58 ASLB inherent ?**** */ +OP_HANDLER( aslb ) +{ + UINT16 r; + r=B<<1; + CLR_NZVC; SET_FLAGS8(B,B,r); + B=r; +} + +/* $59 ROLB inherent -**** */ +OP_HANDLER( rolb ) +{ + UINT16 t,r; + t = B; r = CC&0x01; r |= t<<1; + CLR_NZVC; SET_FLAGS8(t,t,r); + B=r; +} + +/* $5a DECB inherent -***- */ +OP_HANDLER( decb ) +{ + --B; + CLR_NZV; SET_FLAGS8D(B); +} + +/* $5b ILLEGAL */ + +/* $5c INCB inherent -***- */ +OP_HANDLER( incb ) +{ + ++B; + CLR_NZV; SET_FLAGS8I(B); +} + +/* $5d TSTB inherent -**0- */ +OP_HANDLER( tstb ) +{ + CLR_NZVC; SET_NZ8(B); +} + +/* $5e ILLEGAL */ + +/* $5f CLRB inherent -0100 */ +OP_HANDLER( clrb ) +{ + B=0; + CLR_NZVC; SEZ; +} + +/* $60 NEG indexed ?**** */ +OP_HANDLER( neg_ix ) +{ + UINT16 r,t; + IDXBYTE(t); r=-t; + CLR_NZVC; SET_FLAGS8(0,t,r); + WM(EAD,r); +} + +/* $61 AIM --**0- */ /* HD63701YO only */ +OP_HANDLER( aim_ix ) +{ + UINT8 t, r; + IMMBYTE(t); + IDXBYTE(r); + r &= t; + CLR_NZV; SET_NZ8(r); + WM(EAD,r); +} + +/* $62 OIM --**0- */ /* HD63701YO only */ +OP_HANDLER( oim_ix ) +{ + UINT8 t, r; + IMMBYTE(t); + IDXBYTE(r); + r |= t; + CLR_NZV; SET_NZ8(r); + WM(EAD,r); +} + +/* $63 COM indexed -**01 */ +OP_HANDLER( com_ix ) +{ + UINT8 t; + IDXBYTE(t); t = ~t; + CLR_NZV; SET_NZ8(t); SEC; + WM(EAD,t); +} + +/* $64 LSR indexed -0*-* */ +OP_HANDLER( lsr_ix ) +{ + UINT8 t; + IDXBYTE(t); CLR_NZC; CC|=(t&0x01); + t>>=1; SET_Z8(t); + WM(EAD,t); +} + +/* $65 EIM --**0- */ /* HD63701YO only */ +OP_HANDLER( eim_ix ) +{ + UINT8 t, r; + IMMBYTE(t); + IDXBYTE(r); + r ^= t; + CLR_NZV; SET_NZ8(r); + WM(EAD,r); +} + +/* $66 ROR indexed -**-* */ +OP_HANDLER( ror_ix ) +{ + UINT8 t,r; + IDXBYTE(t); r=(CC&0x01)<<7; + CLR_NZC; CC|=(t&0x01); + r |= t>>1; SET_NZ8(r); + WM(EAD,r); +} + +/* $67 ASR indexed ?**-* */ +OP_HANDLER( asr_ix ) +{ + UINT8 t; + IDXBYTE(t); CLR_NZC; CC|=(t&0x01); + t>>=1; t|=((t&0x40)<<1); + SET_NZ8(t); + WM(EAD,t); +} + +/* $68 ASL indexed ?**** */ +OP_HANDLER( asl_ix ) +{ + UINT16 t,r; + IDXBYTE(t); r=t<<1; + CLR_NZVC; SET_FLAGS8(t,t,r); + WM(EAD,r); +} + +/* $69 ROL indexed -**** */ +OP_HANDLER( rol_ix ) +{ + UINT16 t,r; + IDXBYTE(t); r = CC&0x01; r |= t<<1; + CLR_NZVC; SET_FLAGS8(t,t,r); + WM(EAD,r); +} + +/* $6a DEC indexed -***- */ +OP_HANDLER( dec_ix ) +{ + UINT8 t; + IDXBYTE(t); --t; + CLR_NZV; SET_FLAGS8D(t); + WM(EAD,t); +} + +/* $6b TIM --**0- */ /* HD63701YO only */ +OP_HANDLER( tim_ix ) +{ + UINT8 t, r; + IMMBYTE(t); + IDXBYTE(r); + r &= t; + CLR_NZV; SET_NZ8(r); +} + +/* $6c INC indexed -***- */ +OP_HANDLER( inc_ix ) +{ + UINT8 t; + IDXBYTE(t); ++t; + CLR_NZV; SET_FLAGS8I(t); + WM(EAD,t); +} + +/* $6d TST indexed -**0- */ +OP_HANDLER( tst_ix ) +{ + UINT8 t; + IDXBYTE(t); CLR_NZVC; SET_NZ8(t); +} + +/* $6e JMP indexed ----- */ +OP_HANDLER( jmp_ix ) +{ + INDEXED; PC=EA; +} + +/* $6f CLR indexed -0100 */ +OP_HANDLER( clr_ix ) +{ + INDEXED; WM(EAD,0); + CLR_NZVC; SEZ; +} + +/* $70 NEG extended ?**** */ +OP_HANDLER( neg_ex ) +{ + UINT16 r,t; + EXTBYTE(t); r=-t; + CLR_NZVC; SET_FLAGS8(0,t,r); + WM(EAD,r); +} + +/* $71 AIM --**0- */ /* HD63701YO only */ +OP_HANDLER( aim_di ) +{ + UINT8 t, r; + IMMBYTE(t); + DIRBYTE(r); + r &= t; + CLR_NZV; SET_NZ8(r); + WM(EAD,r); +} + +/* $72 OIM --**0- */ /* HD63701YO only */ +OP_HANDLER( oim_di ) +{ + UINT8 t, r; + IMMBYTE(t); + DIRBYTE(r); + r |= t; + CLR_NZV; SET_NZ8(r); + WM(EAD,r); +} + +/* $73 COM extended -**01 */ +OP_HANDLER( com_ex ) +{ + UINT8 t; + EXTBYTE(t); t = ~t; + CLR_NZV; SET_NZ8(t); SEC; + WM(EAD,t); +} + +/* $74 LSR extended -0*-* */ +OP_HANDLER( lsr_ex ) +{ + UINT8 t; + EXTBYTE(t); + CLR_NZC; + CC|=(t&0x01); + t>>=1; + SET_Z8(t); + WM(EAD,t); +} + +/* $75 EIM --**0- */ /* HD63701YO only */ +OP_HANDLER( eim_di ) +{ + UINT8 t, r; + IMMBYTE(t); + DIRBYTE(r); + r ^= t; + CLR_NZV; SET_NZ8(r); + WM(EAD,r); +} + +/* $76 ROR extended -**-* */ +OP_HANDLER( ror_ex ) +{ + UINT8 t,r; + EXTBYTE(t); r=(CC&0x01)<<7; + CLR_NZC; CC|=(t&0x01); + r |= t>>1; SET_NZ8(r); + WM(EAD,r); +} + +/* $77 ASR extended ?**-* */ +OP_HANDLER( asr_ex ) +{ + UINT8 t; + EXTBYTE(t); CLR_NZC; CC|=(t&0x01); + t>>=1; t|=((t&0x40)<<1); + SET_NZ8(t); + WM(EAD,t); +} + +/* $78 ASL extended ?**** */ +OP_HANDLER( asl_ex ) +{ + UINT16 t,r; + EXTBYTE(t); r=t<<1; + CLR_NZVC; SET_FLAGS8(t,t,r); + WM(EAD,r); +} + +/* $79 ROL extended -**** */ +OP_HANDLER( rol_ex ) +{ + UINT16 t,r; + EXTBYTE(t); r = CC&0x01; r |= t<<1; + CLR_NZVC; SET_FLAGS8(t,t,r); + WM(EAD,r); +} + +/* $7a DEC extended -***- */ +OP_HANDLER( dec_ex ) +{ + UINT8 t; + EXTBYTE(t); --t; + CLR_NZV; SET_FLAGS8D(t); + WM(EAD,t); +} + +/* $7b TIM --**0- */ /* HD63701YO only */ +OP_HANDLER( tim_di ) +{ + UINT8 t, r; + IMMBYTE(t); + DIRBYTE(r); + r &= t; + CLR_NZV; SET_NZ8(r); +} + +/* $7c INC extended -***- */ +OP_HANDLER( inc_ex ) +{ + UINT8 t; + EXTBYTE(t); ++t; + CLR_NZV; SET_FLAGS8I(t); + WM(EAD,t); +} + +/* $7d TST extended -**0- */ +OP_HANDLER( tst_ex ) +{ + UINT8 t; + EXTBYTE(t); CLR_NZVC; SET_NZ8(t); +} + +/* $7e JMP extended ----- */ +OP_HANDLER( jmp_ex ) +{ + EXTENDED; PC=EA; +} + +/* $7f CLR extended -0100 */ +OP_HANDLER( clr_ex ) +{ + EXTENDED; WM(EAD,0); + CLR_NZVC; SEZ; +} + +/* $80 SUBA immediate ?**** */ +OP_HANDLER( suba_im ) +{ + UINT16 t,r; + IMMBYTE(t); r = A-t; + CLR_NZVC; SET_FLAGS8(A,t,r); + A = r; +} + +/* $81 CMPA immediate ?**** */ +OP_HANDLER( cmpa_im ) +{ + UINT16 t,r; + IMMBYTE(t); r = A-t; + CLR_NZVC; SET_FLAGS8(A,t,r); +} + +/* $82 SBCA immediate ?**** */ +OP_HANDLER( sbca_im ) +{ + UINT16 t,r; + IMMBYTE(t); r = A-t-(CC&0x01); + CLR_NZVC; SET_FLAGS8(A,t,r); + A = r; +} + +/* $83 SUBD immediate -**** */ +OP_HANDLER( subd_im ) +{ + UINT32 r,d; + PAIR b; + IMMWORD(b); + d = D; + r = d - b.d; + CLR_NZVC; + SET_FLAGS16(d,b.d,r); + D = r; +} + +/* $84 ANDA immediate -**0- */ +OP_HANDLER( anda_im ) +{ + UINT8 t; + IMMBYTE(t); A &= t; + CLR_NZV; SET_NZ8(A); +} + +/* $85 BITA immediate -**0- */ +OP_HANDLER( bita_im ) +{ + UINT8 t,r; + IMMBYTE(t); r = A&t; + CLR_NZV; SET_NZ8(r); +} + +/* $86 LDA immediate -**0- */ +OP_HANDLER( lda_im ) +{ + IMMBYTE(A); + CLR_NZV; SET_NZ8(A); +} + +/* is this a legal instruction? */ +/* $87 STA immediate -**0- */ +OP_HANDLER( sta_im ) +{ + CLR_NZV; SET_NZ8(A); + IMM8; WM(EAD,A); +} + +/* $88 EORA immediate -**0- */ +OP_HANDLER( eora_im ) +{ + UINT8 t; + IMMBYTE(t); A ^= t; + CLR_NZV; SET_NZ8(A); +} + +/* $89 ADCA immediate ***** */ +OP_HANDLER( adca_im ) +{ + UINT16 t,r; + IMMBYTE(t); r = A+t+(CC&0x01); + CLR_HNZVC; SET_FLAGS8(A,t,r); SET_H(A,t,r); + A = r; +} + +/* $8a ORA immediate -**0- */ +OP_HANDLER( ora_im ) +{ + UINT8 t; + IMMBYTE(t); A |= t; + CLR_NZV; SET_NZ8(A); +} + +/* $8b ADDA immediate ***** */ +OP_HANDLER( adda_im ) +{ + UINT16 t,r; + IMMBYTE(t); r = A+t; + CLR_HNZVC; SET_FLAGS8(A,t,r); SET_H(A,t,r); + A = r; +} + +/* $8c CMPX immediate -***- */ +OP_HANDLER( cmpx_im ) +{ + UINT32 r,d; + PAIR b; + IMMWORD(b); + d = X; + r = d - b.d; + CLR_NZV; + SET_NZ16(r); SET_V16(d,b.d,r); +} + +/* $8c CPX immediate -**** (6803) */ +OP_HANDLER( cpx_im ) +{ + UINT32 r,d; + PAIR b; + IMMWORD(b); + d = X; + r = d - b.d; + CLR_NZVC; SET_FLAGS16(d,b.d,r); +} + + +/* $8d BSR ----- */ +OP_HANDLER( bsr ) +{ + UINT8 t; + IMMBYTE(t); + PUSHWORD(pPC); + PC += SIGNED(t); +} + +/* $8e LDS immediate -**0- */ +OP_HANDLER( lds_im ) +{ + IMMWORD(m_s); + CLR_NZV; + SET_NZ16(S); +} + +/* $8f STS immediate -**0- */ +OP_HANDLER( sts_im ) +{ + CLR_NZV; + SET_NZ16(S); + IMM16; + WM16(EAD,&m_s); +} + +/* $90 SUBA direct ?**** */ +OP_HANDLER( suba_di ) +{ + UINT16 t,r; + DIRBYTE(t); r = A-t; + CLR_NZVC; SET_FLAGS8(A,t,r); + A = r; +} + +/* $91 CMPA direct ?**** */ +OP_HANDLER( cmpa_di ) +{ + UINT16 t,r; + DIRBYTE(t); r = A-t; + CLR_NZVC; SET_FLAGS8(A,t,r); +} + +/* $92 SBCA direct ?**** */ +OP_HANDLER( sbca_di ) +{ + UINT16 t,r; + DIRBYTE(t); r = A-t-(CC&0x01); + CLR_NZVC; SET_FLAGS8(A,t,r); + A = r; +} + +/* $93 SUBD direct -**** */ +OP_HANDLER( subd_di ) +{ + UINT32 r,d; + PAIR b; + DIRWORD(b); + d = D; + r = d - b.d; + CLR_NZVC; + SET_FLAGS16(d,b.d,r); + D=r; +} + +/* $94 ANDA direct -**0- */ +OP_HANDLER( anda_di ) +{ + UINT8 t; + DIRBYTE(t); A &= t; + CLR_NZV; SET_NZ8(A); +} + +/* $95 BITA direct -**0- */ +OP_HANDLER( bita_di ) +{ + UINT8 t,r; + DIRBYTE(t); r = A&t; + CLR_NZV; SET_NZ8(r); +} + +/* $96 LDA direct -**0- */ +OP_HANDLER( lda_di ) +{ + DIRBYTE(A); + CLR_NZV; + SET_NZ8(A); +} + +/* $97 STA direct -**0- */ +OP_HANDLER( sta_di ) +{ + CLR_NZV; + SET_NZ8(A); + DIRECT; + WM(EAD,A); +} + +/* $98 EORA direct -**0- */ +OP_HANDLER( eora_di ) +{ + UINT8 t; + DIRBYTE(t); + A ^= t; + CLR_NZV; + SET_NZ8(A); +} + +/* $99 ADCA direct ***** */ +OP_HANDLER( adca_di ) +{ + UINT16 t,r; + DIRBYTE(t); + r = A+t+(CC&0x01); + CLR_HNZVC; + SET_FLAGS8(A,t,r); + SET_H(A,t,r); + A = r; +} + +/* $9a ORA direct -**0- */ +OP_HANDLER( ora_di ) +{ + UINT8 t; + DIRBYTE(t); + A |= t; + CLR_NZV; + SET_NZ8(A); +} + +/* $9b ADDA direct ***** */ +OP_HANDLER( adda_di ) +{ + UINT16 t,r; + DIRBYTE(t); + r = A + t; + CLR_HNZVC; + SET_FLAGS8(A,t,r); + SET_H(A,t,r); + A = r; +} + +/* $9c CMPX direct -***- */ +OP_HANDLER( cmpx_di ) +{ + UINT32 r,d; + PAIR b; + DIRWORD(b); + d = X; + r = d - b.d; + CLR_NZV; + SET_NZ16(r); + SET_V16(d,b.d,r); +} + +/* $9c CPX direct -**** (6803) */ +OP_HANDLER( cpx_di ) +{ + UINT32 r,d; + PAIR b; + DIRWORD(b); + d = X; + r = d - b.d; + CLR_NZVC; + SET_FLAGS16(d,b.d,r); +} + +/* $9d JSR direct ----- */ +OP_HANDLER( jsr_di ) +{ + DIRECT; + PUSHWORD(pPC); + PC = EA; +} + +/* $9e LDS direct -**0- */ +OP_HANDLER( lds_di ) +{ + DIRWORD(m_s); + CLR_NZV; + SET_NZ16(S); +} + +/* $9f STS direct -**0- */ +OP_HANDLER( sts_di ) +{ + CLR_NZV; + SET_NZ16(S); + DIRECT; + WM16(EAD,&m_s); +} + +/* $a0 SUBA indexed ?**** */ +OP_HANDLER( suba_ix ) +{ + UINT16 t,r; + IDXBYTE(t); + r = A - t; + CLR_NZVC; + SET_FLAGS8(A,t,r); + A = r; +} + +/* $a1 CMPA indexed ?**** */ +OP_HANDLER( cmpa_ix ) +{ + UINT16 t,r; + IDXBYTE(t); + r = A - t; + CLR_NZVC; + SET_FLAGS8(A,t,r); +} + +/* $a2 SBCA indexed ?**** */ +OP_HANDLER( sbca_ix ) +{ + UINT16 t,r; + IDXBYTE(t); + r = A - t - (CC&0x01); + CLR_NZVC; + SET_FLAGS8(A,t,r); + A = r; +} + +/* $a3 SUBD indexed -**** */ +OP_HANDLER( subd_ix ) +{ + UINT32 r,d; + PAIR b; + IDXWORD(b); + d = D; + r = d - b.d; + CLR_NZVC; + SET_FLAGS16(d,b.d,r); + D = r; +} + +/* $a4 ANDA indexed -**0- */ +OP_HANDLER( anda_ix ) +{ + UINT8 t; + IDXBYTE(t); A &= t; + CLR_NZV; + SET_NZ8(A); +} + +/* $a5 BITA indexed -**0- */ +OP_HANDLER( bita_ix ) +{ + UINT8 t,r; + IDXBYTE(t); r = A&t; + CLR_NZV; + SET_NZ8(r); +} + +/* $a6 LDA indexed -**0- */ +OP_HANDLER( lda_ix ) +{ + IDXBYTE(A); + CLR_NZV; + SET_NZ8(A); +} + +/* $a7 STA indexed -**0- */ +OP_HANDLER( sta_ix ) +{ + CLR_NZV; + SET_NZ8(A); + INDEXED; + WM(EAD,A); +} + +/* $a8 EORA indexed -**0- */ +OP_HANDLER( eora_ix ) +{ + UINT8 t; + IDXBYTE(t); + A ^= t; + CLR_NZV; + SET_NZ8(A); +} + +/* $a9 ADCA indexed ***** */ +OP_HANDLER( adca_ix ) +{ + UINT16 t,r; + IDXBYTE(t); + r = A + t + (CC&0x01); + CLR_HNZVC; + SET_FLAGS8(A,t,r); + SET_H(A,t,r); + A = r; +} + +/* $aa ORA indexed -**0- */ +OP_HANDLER( ora_ix ) +{ + UINT8 t; + IDXBYTE(t); + A |= t; + CLR_NZV; + SET_NZ8(A); +} + +/* $ab ADDA indexed ***** */ +OP_HANDLER( adda_ix ) +{ + UINT16 t,r; + IDXBYTE(t); + r = A+t; + CLR_HNZVC; + SET_FLAGS8(A,t,r); + SET_H(A,t,r); + A = r; +} + +/* $ac CMPX indexed -***- */ +OP_HANDLER( cmpx_ix ) +{ + UINT32 r,d; + PAIR b; + IDXWORD(b); + d = X; + r = d - b.d; + CLR_NZV; + SET_NZ16(r); + SET_V16(d,b.d,r); +} + +/* $ac CPX indexed -**** (6803)*/ +OP_HANDLER( cpx_ix ) +{ + UINT32 r,d; + PAIR b; + IDXWORD(b); + d = X; + r = d - b.d; + CLR_NZVC; + SET_FLAGS16(d,b.d,r); +} + +/* $ad JSR indexed ----- */ +OP_HANDLER( jsr_ix ) +{ + INDEXED; + PUSHWORD(pPC); + PC = EA; +} + +/* $ae LDS indexed -**0- */ +OP_HANDLER( lds_ix ) +{ + IDXWORD(m_s); + CLR_NZV; + SET_NZ16(S); +} + +/* $af STS indexed -**0- */ +OP_HANDLER( sts_ix ) +{ + CLR_NZV; + SET_NZ16(S); + INDEXED; + WM16(EAD,&m_s); +} + +/* $b0 SUBA extended ?**** */ +OP_HANDLER( suba_ex ) +{ + UINT16 t,r; + EXTBYTE(t); + r = A - t; + CLR_NZVC; + SET_FLAGS8(A,t,r); + A = r; +} + +/* $b1 CMPA extended ?**** */ +OP_HANDLER( cmpa_ex ) +{ + UINT16 t,r; + EXTBYTE(t); + r = A-t; + CLR_NZVC; + SET_FLAGS8(A,t,r); +} + +/* $b2 SBCA extended ?**** */ +OP_HANDLER( sbca_ex ) +{ + UINT16 t,r; + EXTBYTE(t); + r = A-t-(CC&0x01); + CLR_NZVC; + SET_FLAGS8(A,t,r); + A = r; +} + +/* $b3 SUBD extended -**** */ +OP_HANDLER( subd_ex ) +{ + UINT32 r,d; + PAIR b; + EXTWORD(b); + d = D; + r = d - b.d; + CLR_NZVC; + SET_FLAGS16(d,b.d,r); + D=r; +} + +/* $b4 ANDA extended -**0- */ +OP_HANDLER( anda_ex ) +{ + UINT8 t; + EXTBYTE(t); + A &= t; + CLR_NZV; + SET_NZ8(A); +} + +/* $b5 BITA extended -**0- */ +OP_HANDLER( bita_ex ) +{ + UINT8 t,r; + EXTBYTE(t); + r = A&t; + CLR_NZV; + SET_NZ8(r); +} + +/* $b6 LDA extended -**0- */ +OP_HANDLER( lda_ex ) +{ + EXTBYTE(A); + CLR_NZV; + SET_NZ8(A); +} + +/* $b7 STA extended -**0- */ +OP_HANDLER( sta_ex ) +{ + CLR_NZV; + SET_NZ8(A); + EXTENDED; + WM(EAD,A); +} + +/* $b8 EORA extended -**0- */ +OP_HANDLER( eora_ex ) +{ + UINT8 t; + EXTBYTE(t); + A ^= t; + CLR_NZV; + SET_NZ8(A); +} + +/* $b9 ADCA extended ***** */ +OP_HANDLER( adca_ex ) +{ + UINT16 t,r; + EXTBYTE(t); + r = A+t+(CC&0x01); + CLR_HNZVC; + SET_FLAGS8(A,t,r); + SET_H(A,t,r); + A = r; +} + +/* $ba ORA extended -**0- */ +OP_HANDLER( ora_ex ) +{ + UINT8 t; + EXTBYTE(t); + A |= t; + CLR_NZV; + SET_NZ8(A); +} + +/* $bb ADDA extended ***** */ +OP_HANDLER( adda_ex ) +{ + UINT16 t,r; + EXTBYTE(t); + r = A+t; + CLR_HNZVC; + SET_FLAGS8(A,t,r); + SET_H(A,t,r); + A = r; +} + +/* $bc CMPX extended -***- */ +OP_HANDLER( cmpx_ex ) +{ + UINT32 r,d; + PAIR b; + EXTWORD(b); + d = X; + r = d - b.d; + CLR_NZV; + SET_NZ16(r); + SET_V16(d,b.d,r); +} + +/* $bc CPX extended -**** (6803) */ +OP_HANDLER( cpx_ex ) +{ + UINT32 r,d; + PAIR b; + EXTWORD(b); + d = X; + r = d - b.d; + CLR_NZVC; + SET_FLAGS16(d,b.d,r); +} + +/* $bd JSR extended ----- */ +OP_HANDLER( jsr_ex ) +{ + EXTENDED; + PUSHWORD(pPC); + PC = EA; +} + +/* $be LDS extended -**0- */ +OP_HANDLER( lds_ex ) +{ + EXTWORD(m_s); + CLR_NZV; + SET_NZ16(S); +} + +/* $bf STS extended -**0- */ +OP_HANDLER( sts_ex ) +{ + CLR_NZV; + SET_NZ16(S); + EXTENDED; + WM16(EAD,&m_s); +} + +/* $c0 SUBB immediate ?**** */ +OP_HANDLER( subb_im ) +{ + UINT16 t,r; + IMMBYTE(t); + r = B-t; + CLR_NZVC; + SET_FLAGS8(B,t,r); + B = r; +} + +/* $c1 CMPB immediate ?**** */ +OP_HANDLER( cmpb_im ) +{ + UINT16 t,r; + IMMBYTE(t); + r = B-t; + CLR_NZVC; + SET_FLAGS8(B,t,r); +} + +/* $c2 SBCB immediate ?**** */ +OP_HANDLER( sbcb_im ) +{ + UINT16 t,r; + IMMBYTE(t); + r = B-t-(CC&0x01); + CLR_NZVC; + SET_FLAGS8(B,t,r); + B = r; +} + +/* $c3 ADDD immediate -**** */ +OP_HANDLER( addd_im ) +{ + UINT32 r,d; + PAIR b; + IMMWORD(b); + d = D; + r = d + b.d; + CLR_NZVC; + SET_FLAGS16(d,b.d,r); + D = r; +} + +/* $c4 ANDB immediate -**0- */ +OP_HANDLER( andb_im ) +{ + UINT8 t; + IMMBYTE(t); + B &= t; + CLR_NZV; + SET_NZ8(B); +} + +/* $c5 BITB immediate -**0- */ +OP_HANDLER( bitb_im ) +{ + UINT8 t,r; + IMMBYTE(t); + r = B&t; + CLR_NZV; + SET_NZ8(r); +} + +/* $c6 LDB immediate -**0- */ +OP_HANDLER( ldb_im ) +{ + IMMBYTE(B); + CLR_NZV; + SET_NZ8(B); +} + +/* is this a legal instruction? */ +/* $c7 STB immediate -**0- */ +OP_HANDLER( stb_im ) +{ + CLR_NZV; + SET_NZ8(B); + IMM8; + WM(EAD,B); +} + +/* $c8 EORB immediate -**0- */ +OP_HANDLER( eorb_im ) +{ + UINT8 t; + IMMBYTE(t); + B ^= t; + CLR_NZV; + SET_NZ8(B); +} + +/* $c9 ADCB immediate ***** */ +OP_HANDLER( adcb_im ) +{ + UINT16 t,r; + IMMBYTE(t); + r = B+t+(CC&0x01); + CLR_HNZVC; + SET_FLAGS8(B,t,r); + SET_H(B,t,r); + B = r; +} + +/* $ca ORB immediate -**0- */ +OP_HANDLER( orb_im ) +{ + UINT8 t; + IMMBYTE(t); + B |= t; + CLR_NZV; + SET_NZ8(B); +} + +/* $cb ADDB immediate ***** */ +OP_HANDLER( addb_im ) +{ + UINT16 t,r; + IMMBYTE(t); + r = B+t; + CLR_HNZVC; + SET_FLAGS8(B,t,r); + SET_H(B,t,r); + B = r; +} + +/* $CC LDD immediate -**0- */ +OP_HANDLER( ldd_im ) +{ + IMMWORD(m_d); + CLR_NZV; + SET_NZ16(D); +} + +/* is this a legal instruction? */ +/* $cd STD immediate -**0- */ +OP_HANDLER( std_im ) +{ + IMM16; + CLR_NZV; + SET_NZ16(D); + WM16(EAD,&m_d); +} + +/* $ce LDX immediate -**0- */ +OP_HANDLER( ldx_im ) +{ + IMMWORD(m_x); + CLR_NZV; + SET_NZ16(X); +} + +/* $cf STX immediate -**0- */ +OP_HANDLER( stx_im ) +{ + CLR_NZV; + SET_NZ16(X); + IMM16; + WM16(EAD,&m_x); +} + +/* $d0 SUBB direct ?**** */ +OP_HANDLER( subb_di ) +{ + UINT16 t,r; + DIRBYTE(t); + r = B-t; + CLR_NZVC; + SET_FLAGS8(B,t,r); + B = r; +} + +/* $d1 CMPB direct ?**** */ +OP_HANDLER( cmpb_di ) +{ + UINT16 t,r; + DIRBYTE(t); + r = B-t; + CLR_NZVC; + SET_FLAGS8(B,t,r); +} + +/* $d2 SBCB direct ?**** */ +OP_HANDLER( sbcb_di ) +{ + UINT16 t,r; + DIRBYTE(t); + r = B-t-(CC&0x01); + CLR_NZVC; + SET_FLAGS8(B,t,r); + B = r; +} + +/* $d3 ADDD direct -**** */ +OP_HANDLER( addd_di ) +{ + UINT32 r,d; + PAIR b; + DIRWORD(b); + d = D; + r = d + b.d; + CLR_NZVC; + SET_FLAGS16(d,b.d,r); + D = r; +} + +/* $d4 ANDB direct -**0- */ +OP_HANDLER( andb_di ) +{ + UINT8 t; + DIRBYTE(t); + B &= t; + CLR_NZV; + SET_NZ8(B); +} + +/* $d5 BITB direct -**0- */ +OP_HANDLER( bitb_di ) +{ + UINT8 t,r; + DIRBYTE(t); + r = B&t; + CLR_NZV; + SET_NZ8(r); +} + +/* $d6 LDB direct -**0- */ +OP_HANDLER( ldb_di ) +{ + DIRBYTE(B); + CLR_NZV; + SET_NZ8(B); +} + +/* $d7 STB direct -**0- */ +OP_HANDLER( stb_di ) +{ + CLR_NZV; + SET_NZ8(B); + DIRECT; + WM(EAD,B); +} + +/* $d8 EORB direct -**0- */ +OP_HANDLER( eorb_di ) +{ + UINT8 t; + DIRBYTE(t); + B ^= t; + CLR_NZV; + SET_NZ8(B); +} + +/* $d9 ADCB direct ***** */ +OP_HANDLER( adcb_di ) +{ + UINT16 t,r; + DIRBYTE(t); + r = B+t+(CC&0x01); + CLR_HNZVC; + SET_FLAGS8(B,t,r); + SET_H(B,t,r); + B = r; +} + +/* $da ORB direct -**0- */ +OP_HANDLER( orb_di ) +{ + UINT8 t; + DIRBYTE(t); + B |= t; + CLR_NZV; + SET_NZ8(B); +} + +/* $db ADDB direct ***** */ +OP_HANDLER( addb_di ) +{ + UINT16 t,r; + DIRBYTE(t); + r = B+t; + CLR_HNZVC; + SET_FLAGS8(B,t,r); + SET_H(B,t,r); + B = r; +} + +/* $dc LDD direct -**0- */ +OP_HANDLER( ldd_di ) +{ + DIRWORD(m_d); + CLR_NZV; + SET_NZ16(D); +} + +/* $dd STD direct -**0- */ +OP_HANDLER( std_di ) +{ + DIRECT; + CLR_NZV; + SET_NZ16(D); + WM16(EAD,&m_d); +} + +/* $de LDX direct -**0- */ +OP_HANDLER( ldx_di ) +{ + DIRWORD(m_x); + CLR_NZV; + SET_NZ16(X); +} + +/* $dF STX direct -**0- */ +OP_HANDLER( stx_di ) +{ + CLR_NZV; + SET_NZ16(X); + DIRECT; + WM16(EAD,&m_x); +} + +/* $e0 SUBB indexed ?**** */ +OP_HANDLER( subb_ix ) +{ + UINT16 t,r; + IDXBYTE(t); + r = B-t; + CLR_NZVC; + SET_FLAGS8(B,t,r); + B = r; +} + +/* $e1 CMPB indexed ?**** */ +OP_HANDLER( cmpb_ix ) +{ + UINT16 t,r; + IDXBYTE(t); + r = B-t; + CLR_NZVC; + SET_FLAGS8(B,t,r); +} + +/* $e2 SBCB indexed ?**** */ +OP_HANDLER( sbcb_ix ) +{ + UINT16 t,r; + IDXBYTE(t); + r = B-t-(CC&0x01); + CLR_NZVC; + SET_FLAGS8(B,t,r); + B = r; +} + +/* $e3 ADDD indexed -**** */ +OP_HANDLER( addd_ix ) +{ + UINT32 r,d; + PAIR b; + IDXWORD(b); + d = D; + r = d + b.d; + CLR_NZVC; + SET_FLAGS16(d,b.d,r); + D = r; +} + +/* $e4 ANDB indexed -**0- */ +OP_HANDLER( andb_ix ) +{ + UINT8 t; + IDXBYTE(t); + B &= t; + CLR_NZV; + SET_NZ8(B); +} + +/* $e5 BITB indexed -**0- */ +OP_HANDLER( bitb_ix ) +{ + UINT8 t,r; + IDXBYTE(t); + r = B&t; + CLR_NZV; + SET_NZ8(r); +} + +/* $e6 LDB indexed -**0- */ +OP_HANDLER( ldb_ix ) +{ + IDXBYTE(B); + CLR_NZV; + SET_NZ8(B); +} + +/* $e7 STB indexed -**0- */ +OP_HANDLER( stb_ix ) +{ + CLR_NZV; + SET_NZ8(B); + INDEXED; + WM(EAD,B); +} + +/* $e8 EORB indexed -**0- */ +OP_HANDLER( eorb_ix ) +{ + UINT8 t; + IDXBYTE(t); + B ^= t; + CLR_NZV; + SET_NZ8(B); +} + +/* $e9 ADCB indexed ***** */ +OP_HANDLER( adcb_ix ) +{ + UINT16 t,r; + IDXBYTE(t); + r = B+t+(CC&0x01); + CLR_HNZVC; + SET_FLAGS8(B,t,r); + SET_H(B,t,r); + B = r; +} + +/* $ea ORB indexed -**0- */ +OP_HANDLER( orb_ix ) +{ + UINT8 t; + IDXBYTE(t); + B |= t; + CLR_NZV; + SET_NZ8(B); +} + +/* $eb ADDB indexed ***** */ +OP_HANDLER( addb_ix ) +{ + UINT16 t,r; + IDXBYTE(t); + r = B+t; + CLR_HNZVC; + SET_FLAGS8(B,t,r); + SET_H(B,t,r); + B = r; +} + +/* $ec LDD indexed -**0- */ +OP_HANDLER( ldd_ix ) +{ + IDXWORD(m_d); + CLR_NZV; + SET_NZ16(D); +} + +/* $ec ADCX immediate -**** NSC8105 only. Flags are a guess - copied from addb_im() */ +OP_HANDLER( adcx_im ) +{ + UINT16 t,r; + IMMBYTE(t); + r = X+t+(CC&0x01); + CLR_HNZVC; + SET_FLAGS8(X,t,r); + SET_H(X,t,r); + X = r; +} + +/* $ed STD indexed -**0- */ +OP_HANDLER( std_ix ) +{ + INDEXED; + CLR_NZV; + SET_NZ16(D); + WM16(EAD,&m_d); +} + +/* $ee LDX indexed -**0- */ +OP_HANDLER( ldx_ix ) +{ + IDXWORD(m_x); + CLR_NZV; + SET_NZ16(X); +} + +/* $ef STX indexed -**0- */ +OP_HANDLER( stx_ix ) +{ + CLR_NZV; + SET_NZ16(X); + INDEXED; + WM16(EAD,&m_x); +} + +/* $f0 SUBB extended ?**** */ +OP_HANDLER( subb_ex ) +{ + UINT16 t,r; + EXTBYTE(t); + r = B-t; + CLR_NZVC; + SET_FLAGS8(B,t,r); + B = r; +} + +/* $f1 CMPB extended ?**** */ +OP_HANDLER( cmpb_ex ) +{ + UINT16 t,r; + EXTBYTE(t); + r = B-t; + CLR_NZVC; + SET_FLAGS8(B,t,r); +} + +/* $f2 SBCB extended ?**** */ +OP_HANDLER( sbcb_ex ) +{ + UINT16 t,r; + EXTBYTE(t); + r = B-t-(CC&0x01); + CLR_NZVC; + SET_FLAGS8(B,t,r); + B = r; +} + +/* $f3 ADDD extended -**** */ +OP_HANDLER( addd_ex ) +{ + UINT32 r,d; + PAIR b; + EXTWORD(b); + d = D; + r = d + b.d; + CLR_NZVC; + SET_FLAGS16(d,b.d,r); + D = r; +} + +/* $f4 ANDB extended -**0- */ +OP_HANDLER( andb_ex ) +{ + UINT8 t; + EXTBYTE(t); + B &= t; + CLR_NZV; + SET_NZ8(B); +} + +/* $f5 BITB extended -**0- */ +OP_HANDLER( bitb_ex ) +{ + UINT8 t,r; + EXTBYTE(t); + r = B & t; + CLR_NZV; + SET_NZ8(r); +} + +/* $f6 LDB extended -**0- */ +OP_HANDLER( ldb_ex ) +{ + EXTBYTE(B); + CLR_NZV; + SET_NZ8(B); +} + +/* $f7 STB extended -**0- */ +OP_HANDLER( stb_ex ) +{ + CLR_NZV; + SET_NZ8(B); + EXTENDED; + WM(EAD,B); +} + +/* $f8 EORB extended -**0- */ +OP_HANDLER( eorb_ex ) +{ + UINT8 t; + EXTBYTE(t); + B ^= t; + CLR_NZV; + SET_NZ8(B); +} + +/* $f9 ADCB extended ***** */ +OP_HANDLER( adcb_ex ) +{ + UINT16 t,r; + EXTBYTE(t); + r = B+t+(CC&0x01); + CLR_HNZVC; + SET_FLAGS8(B,t,r); + SET_H(B,t,r); + B = r; +} + +/* $fa ORB extended -**0- */ +OP_HANDLER( orb_ex ) +{ + UINT8 t; + EXTBYTE(t); + B |= t; + CLR_NZV; + SET_NZ8(B); +} + +/* $fb ADDB extended ***** */ +OP_HANDLER( addb_ex ) +{ + UINT16 t,r; + EXTBYTE(t); + r = B+t; + CLR_HNZVC; + SET_FLAGS8(B,t,r); + SET_H(B,t,r); + B = r; +} + +/* $fc LDD extended -**0- */ +OP_HANDLER( ldd_ex ) +{ + EXTWORD(m_d); + CLR_NZV; + SET_NZ16(D); +} + +/* $fc ADDX extended -**** NSC8105 only. Flags are a guess */ +OP_HANDLER( addx_ex ) +{ + UINT32 r,d; + PAIR b; + EXTWORD(b); + d = X; + r = d + b.d; + CLR_NZVC; + SET_FLAGS16(d,b.d,r); + X = r; +} + +/* $fd STD extended -**0- */ +OP_HANDLER( std_ex ) +{ + EXTENDED; + CLR_NZV; + SET_NZ16(D); + WM16(EAD,&m_d); +} + +/* $fe LDX extended -**0- */ +OP_HANDLER( ldx_ex ) +{ + EXTWORD(m_x); + CLR_NZV; + SET_NZ16(X); +} + +/* $ff STX extended -**0- */ +OP_HANDLER( stx_ex ) +{ + CLR_NZV; + SET_NZ16(X); + EXTENDED; + WM16(EAD,&m_x); +} diff --git a/src/devices/cpu/m6800/6800tbl.inc b/src/devices/cpu/m6800/6800tbl.inc new file mode 100644 index 00000000000..38376dadd59 --- /dev/null +++ b/src/devices/cpu/m6800/6800tbl.inc @@ -0,0 +1,140 @@ + +const m6800_cpu_device::op_func m6800_cpu_device::m6800_insn[0x100] = { +&m6800_cpu_device::illegal,&m6800_cpu_device::nop, &m6800_cpu_device::illegal,&m6800_cpu_device::illegal,&m6800_cpu_device::illegal,&m6800_cpu_device::illegal,&m6800_cpu_device::tap, &m6800_cpu_device::tpa, +&m6800_cpu_device::inx, &m6800_cpu_device::dex, &m6800_cpu_device::clv, &m6800_cpu_device::sev, &m6800_cpu_device::clc, &m6800_cpu_device::sec, &m6800_cpu_device::cli, &m6800_cpu_device::sei, +&m6800_cpu_device::sba, &m6800_cpu_device::cba, &m6800_cpu_device::illegal,&m6800_cpu_device::illegal,&m6800_cpu_device::illegal,&m6800_cpu_device::illegal,&m6800_cpu_device::tab, &m6800_cpu_device::tba, +&m6800_cpu_device::illegal,&m6800_cpu_device::daa, &m6800_cpu_device::illegal,&m6800_cpu_device::aba, &m6800_cpu_device::illegal,&m6800_cpu_device::illegal,&m6800_cpu_device::illegal,&m6800_cpu_device::illegal, +&m6800_cpu_device::bra, &m6800_cpu_device::brn, &m6800_cpu_device::bhi, &m6800_cpu_device::bls, &m6800_cpu_device::bcc, &m6800_cpu_device::bcs, &m6800_cpu_device::bne, &m6800_cpu_device::beq, +&m6800_cpu_device::bvc, &m6800_cpu_device::bvs, &m6800_cpu_device::bpl, &m6800_cpu_device::bmi, &m6800_cpu_device::bge, &m6800_cpu_device::blt, &m6800_cpu_device::bgt, &m6800_cpu_device::ble, +&m6800_cpu_device::tsx, &m6800_cpu_device::ins, &m6800_cpu_device::pula, &m6800_cpu_device::pulb, &m6800_cpu_device::des, &m6800_cpu_device::txs, &m6800_cpu_device::psha, &m6800_cpu_device::pshb, +&m6800_cpu_device::illegal,&m6800_cpu_device::rts, &m6800_cpu_device::illegal,&m6800_cpu_device::rti, &m6800_cpu_device::illegal,&m6800_cpu_device::illegal,&m6800_cpu_device::wai, &m6800_cpu_device::swi, +&m6800_cpu_device::nega, &m6800_cpu_device::illegal,&m6800_cpu_device::illegal,&m6800_cpu_device::coma, &m6800_cpu_device::lsra, &m6800_cpu_device::illegal,&m6800_cpu_device::rora, &m6800_cpu_device::asra, +&m6800_cpu_device::asla, &m6800_cpu_device::rola, &m6800_cpu_device::deca, &m6800_cpu_device::illegal,&m6800_cpu_device::inca, &m6800_cpu_device::tsta, &m6800_cpu_device::illegal,&m6800_cpu_device::clra, +&m6800_cpu_device::negb, &m6800_cpu_device::illegal,&m6800_cpu_device::illegal,&m6800_cpu_device::comb, &m6800_cpu_device::lsrb, &m6800_cpu_device::illegal,&m6800_cpu_device::rorb, &m6800_cpu_device::asrb, +&m6800_cpu_device::aslb, &m6800_cpu_device::rolb, &m6800_cpu_device::decb, &m6800_cpu_device::illegal,&m6800_cpu_device::incb, &m6800_cpu_device::tstb, &m6800_cpu_device::illegal,&m6800_cpu_device::clrb, +&m6800_cpu_device::neg_ix, &m6800_cpu_device::illegal,&m6800_cpu_device::illegal,&m6800_cpu_device::com_ix, &m6800_cpu_device::lsr_ix, &m6800_cpu_device::illegal,&m6800_cpu_device::ror_ix, &m6800_cpu_device::asr_ix, +&m6800_cpu_device::asl_ix, &m6800_cpu_device::rol_ix, &m6800_cpu_device::dec_ix, &m6800_cpu_device::illegal,&m6800_cpu_device::inc_ix, &m6800_cpu_device::tst_ix, &m6800_cpu_device::jmp_ix, &m6800_cpu_device::clr_ix, +&m6800_cpu_device::neg_ex, &m6800_cpu_device::illegal,&m6800_cpu_device::illegal,&m6800_cpu_device::com_ex, &m6800_cpu_device::lsr_ex, &m6800_cpu_device::illegal,&m6800_cpu_device::ror_ex, &m6800_cpu_device::asr_ex, +&m6800_cpu_device::asl_ex, &m6800_cpu_device::rol_ex, &m6800_cpu_device::dec_ex, &m6800_cpu_device::illegal,&m6800_cpu_device::inc_ex, &m6800_cpu_device::tst_ex, &m6800_cpu_device::jmp_ex, &m6800_cpu_device::clr_ex, +&m6800_cpu_device::suba_im,&m6800_cpu_device::cmpa_im,&m6800_cpu_device::sbca_im,&m6800_cpu_device::illegal,&m6800_cpu_device::anda_im,&m6800_cpu_device::bita_im,&m6800_cpu_device::lda_im, &m6800_cpu_device::sta_im, +&m6800_cpu_device::eora_im,&m6800_cpu_device::adca_im,&m6800_cpu_device::ora_im, &m6800_cpu_device::adda_im,&m6800_cpu_device::cmpx_im,&m6800_cpu_device::bsr, &m6800_cpu_device::lds_im, &m6800_cpu_device::sts_im, +&m6800_cpu_device::suba_di,&m6800_cpu_device::cmpa_di,&m6800_cpu_device::sbca_di,&m6800_cpu_device::illegal,&m6800_cpu_device::anda_di,&m6800_cpu_device::bita_di,&m6800_cpu_device::lda_di, &m6800_cpu_device::sta_di, +&m6800_cpu_device::eora_di,&m6800_cpu_device::adca_di,&m6800_cpu_device::ora_di, &m6800_cpu_device::adda_di,&m6800_cpu_device::cmpx_di,&m6800_cpu_device::jsr_di, &m6800_cpu_device::lds_di, &m6800_cpu_device::sts_di, +&m6800_cpu_device::suba_ix,&m6800_cpu_device::cmpa_ix,&m6800_cpu_device::sbca_ix,&m6800_cpu_device::illegal,&m6800_cpu_device::anda_ix,&m6800_cpu_device::bita_ix,&m6800_cpu_device::lda_ix, &m6800_cpu_device::sta_ix, +&m6800_cpu_device::eora_ix,&m6800_cpu_device::adca_ix,&m6800_cpu_device::ora_ix, &m6800_cpu_device::adda_ix,&m6800_cpu_device::cmpx_ix,&m6800_cpu_device::jsr_ix, &m6800_cpu_device::lds_ix, &m6800_cpu_device::sts_ix, +&m6800_cpu_device::suba_ex,&m6800_cpu_device::cmpa_ex,&m6800_cpu_device::sbca_ex,&m6800_cpu_device::illegal,&m6800_cpu_device::anda_ex,&m6800_cpu_device::bita_ex,&m6800_cpu_device::lda_ex, &m6800_cpu_device::sta_ex, +&m6800_cpu_device::eora_ex,&m6800_cpu_device::adca_ex,&m6800_cpu_device::ora_ex, &m6800_cpu_device::adda_ex,&m6800_cpu_device::cmpx_ex,&m6800_cpu_device::jsr_ex, &m6800_cpu_device::lds_ex, &m6800_cpu_device::sts_ex, +&m6800_cpu_device::subb_im,&m6800_cpu_device::cmpb_im,&m6800_cpu_device::sbcb_im,&m6800_cpu_device::illegal,&m6800_cpu_device::andb_im,&m6800_cpu_device::bitb_im,&m6800_cpu_device::ldb_im, &m6800_cpu_device::stb_im, +&m6800_cpu_device::eorb_im,&m6800_cpu_device::adcb_im,&m6800_cpu_device::orb_im, &m6800_cpu_device::addb_im,&m6800_cpu_device::illegal,&m6800_cpu_device::illegal,&m6800_cpu_device::ldx_im, &m6800_cpu_device::stx_im, +&m6800_cpu_device::subb_di,&m6800_cpu_device::cmpb_di,&m6800_cpu_device::sbcb_di,&m6800_cpu_device::illegal,&m6800_cpu_device::andb_di,&m6800_cpu_device::bitb_di,&m6800_cpu_device::ldb_di, &m6800_cpu_device::stb_di, +&m6800_cpu_device::eorb_di,&m6800_cpu_device::adcb_di,&m6800_cpu_device::orb_di, &m6800_cpu_device::addb_di,&m6800_cpu_device::illegal,&m6800_cpu_device::illegal,&m6800_cpu_device::ldx_di, &m6800_cpu_device::stx_di, +&m6800_cpu_device::subb_ix,&m6800_cpu_device::cmpb_ix,&m6800_cpu_device::sbcb_ix,&m6800_cpu_device::illegal,&m6800_cpu_device::andb_ix,&m6800_cpu_device::bitb_ix,&m6800_cpu_device::ldb_ix, &m6800_cpu_device::stb_ix, +&m6800_cpu_device::eorb_ix,&m6800_cpu_device::adcb_ix,&m6800_cpu_device::orb_ix, &m6800_cpu_device::addb_ix,&m6800_cpu_device::illegal,&m6800_cpu_device::illegal,&m6800_cpu_device::ldx_ix, &m6800_cpu_device::stx_ix, +&m6800_cpu_device::subb_ex,&m6800_cpu_device::cmpb_ex,&m6800_cpu_device::sbcb_ex,&m6800_cpu_device::illegal,&m6800_cpu_device::andb_ex,&m6800_cpu_device::bitb_ex,&m6800_cpu_device::ldb_ex, &m6800_cpu_device::stb_ex, +&m6800_cpu_device::eorb_ex,&m6800_cpu_device::adcb_ex,&m6800_cpu_device::orb_ex, &m6800_cpu_device::addb_ex,&m6800_cpu_device::illegal,&m6800_cpu_device::illegal,&m6800_cpu_device::ldx_ex, &m6800_cpu_device::stx_ex +}; + +const m6800_cpu_device::op_func m6800_cpu_device::m6803_insn[0x100] = { +&m6800_cpu_device::illegal,&m6800_cpu_device::nop, &m6800_cpu_device::illegal,&m6800_cpu_device::illegal,&m6800_cpu_device::lsrd, &m6800_cpu_device::asld, &m6800_cpu_device::tap, &m6800_cpu_device::tpa, +&m6800_cpu_device::inx, &m6800_cpu_device::dex, &m6800_cpu_device::clv, &m6800_cpu_device::sev, &m6800_cpu_device::clc, &m6800_cpu_device::sec, &m6800_cpu_device::cli, &m6800_cpu_device::sei, +&m6800_cpu_device::sba, &m6800_cpu_device::cba, &m6800_cpu_device::illegal,&m6800_cpu_device::illegal,&m6800_cpu_device::illegal,&m6800_cpu_device::illegal,&m6800_cpu_device::tab, &m6800_cpu_device::tba, +&m6800_cpu_device::illegal,&m6800_cpu_device::daa, &m6800_cpu_device::illegal,&m6800_cpu_device::aba, &m6800_cpu_device::illegal,&m6800_cpu_device::illegal,&m6800_cpu_device::illegal,&m6800_cpu_device::illegal, +&m6800_cpu_device::bra, &m6800_cpu_device::brn, &m6800_cpu_device::bhi, &m6800_cpu_device::bls, &m6800_cpu_device::bcc, &m6800_cpu_device::bcs, &m6800_cpu_device::bne, &m6800_cpu_device::beq, +&m6800_cpu_device::bvc, &m6800_cpu_device::bvs, &m6800_cpu_device::bpl, &m6800_cpu_device::bmi, &m6800_cpu_device::bge, &m6800_cpu_device::blt, &m6800_cpu_device::bgt, &m6800_cpu_device::ble, +&m6800_cpu_device::tsx, &m6800_cpu_device::ins, &m6800_cpu_device::pula, &m6800_cpu_device::pulb, &m6800_cpu_device::des, &m6800_cpu_device::txs, &m6800_cpu_device::psha, &m6800_cpu_device::pshb, +&m6800_cpu_device::pulx, &m6800_cpu_device::rts, &m6800_cpu_device::abx, &m6800_cpu_device::rti, &m6800_cpu_device::pshx, &m6800_cpu_device::mul, &m6800_cpu_device::wai, &m6800_cpu_device::swi, +&m6800_cpu_device::nega, &m6800_cpu_device::illegal,&m6800_cpu_device::illegal,&m6800_cpu_device::coma, &m6800_cpu_device::lsra, &m6800_cpu_device::illegal,&m6800_cpu_device::rora, &m6800_cpu_device::asra, +&m6800_cpu_device::asla, &m6800_cpu_device::rola, &m6800_cpu_device::deca, &m6800_cpu_device::illegal,&m6800_cpu_device::inca, &m6800_cpu_device::tsta, &m6800_cpu_device::illegal,&m6800_cpu_device::clra, +&m6800_cpu_device::negb, &m6800_cpu_device::illegal,&m6800_cpu_device::illegal,&m6800_cpu_device::comb, &m6800_cpu_device::lsrb, &m6800_cpu_device::illegal,&m6800_cpu_device::rorb, &m6800_cpu_device::asrb, +&m6800_cpu_device::aslb, &m6800_cpu_device::rolb, &m6800_cpu_device::decb, &m6800_cpu_device::illegal,&m6800_cpu_device::incb, &m6800_cpu_device::tstb, &m6800_cpu_device::illegal,&m6800_cpu_device::clrb, +&m6800_cpu_device::neg_ix, &m6800_cpu_device::illegal,&m6800_cpu_device::illegal,&m6800_cpu_device::com_ix, &m6800_cpu_device::lsr_ix, &m6800_cpu_device::illegal,&m6800_cpu_device::ror_ix, &m6800_cpu_device::asr_ix, +&m6800_cpu_device::asl_ix, &m6800_cpu_device::rol_ix, &m6800_cpu_device::dec_ix, &m6800_cpu_device::illegal,&m6800_cpu_device::inc_ix, &m6800_cpu_device::tst_ix, &m6800_cpu_device::jmp_ix, &m6800_cpu_device::clr_ix, +&m6800_cpu_device::neg_ex, &m6800_cpu_device::illegal,&m6800_cpu_device::illegal,&m6800_cpu_device::com_ex, &m6800_cpu_device::lsr_ex, &m6800_cpu_device::illegal,&m6800_cpu_device::ror_ex, &m6800_cpu_device::asr_ex, +&m6800_cpu_device::asl_ex, &m6800_cpu_device::rol_ex, &m6800_cpu_device::dec_ex, &m6800_cpu_device::illegal,&m6800_cpu_device::inc_ex, &m6800_cpu_device::tst_ex, &m6800_cpu_device::jmp_ex, &m6800_cpu_device::clr_ex, +&m6800_cpu_device::suba_im,&m6800_cpu_device::cmpa_im,&m6800_cpu_device::sbca_im,&m6800_cpu_device::subd_im,&m6800_cpu_device::anda_im,&m6800_cpu_device::bita_im,&m6800_cpu_device::lda_im, &m6800_cpu_device::sta_im, +&m6800_cpu_device::eora_im,&m6800_cpu_device::adca_im,&m6800_cpu_device::ora_im, &m6800_cpu_device::adda_im,&m6800_cpu_device::cpx_im ,&m6800_cpu_device::bsr, &m6800_cpu_device::lds_im, &m6800_cpu_device::sts_im, +&m6800_cpu_device::suba_di,&m6800_cpu_device::cmpa_di,&m6800_cpu_device::sbca_di,&m6800_cpu_device::subd_di,&m6800_cpu_device::anda_di,&m6800_cpu_device::bita_di,&m6800_cpu_device::lda_di, &m6800_cpu_device::sta_di, +&m6800_cpu_device::eora_di,&m6800_cpu_device::adca_di,&m6800_cpu_device::ora_di, &m6800_cpu_device::adda_di,&m6800_cpu_device::cpx_di ,&m6800_cpu_device::jsr_di, &m6800_cpu_device::lds_di, &m6800_cpu_device::sts_di, +&m6800_cpu_device::suba_ix,&m6800_cpu_device::cmpa_ix,&m6800_cpu_device::sbca_ix,&m6800_cpu_device::subd_ix,&m6800_cpu_device::anda_ix,&m6800_cpu_device::bita_ix,&m6800_cpu_device::lda_ix, &m6800_cpu_device::sta_ix, +&m6800_cpu_device::eora_ix,&m6800_cpu_device::adca_ix,&m6800_cpu_device::ora_ix, &m6800_cpu_device::adda_ix,&m6800_cpu_device::cpx_ix ,&m6800_cpu_device::jsr_ix, &m6800_cpu_device::lds_ix, &m6800_cpu_device::sts_ix, +&m6800_cpu_device::suba_ex,&m6800_cpu_device::cmpa_ex,&m6800_cpu_device::sbca_ex,&m6800_cpu_device::subd_ex,&m6800_cpu_device::anda_ex,&m6800_cpu_device::bita_ex,&m6800_cpu_device::lda_ex, &m6800_cpu_device::sta_ex, +&m6800_cpu_device::eora_ex,&m6800_cpu_device::adca_ex,&m6800_cpu_device::ora_ex, &m6800_cpu_device::adda_ex,&m6800_cpu_device::cpx_ex ,&m6800_cpu_device::jsr_ex, &m6800_cpu_device::lds_ex, &m6800_cpu_device::sts_ex, +&m6800_cpu_device::subb_im,&m6800_cpu_device::cmpb_im,&m6800_cpu_device::sbcb_im,&m6800_cpu_device::addd_im,&m6800_cpu_device::andb_im,&m6800_cpu_device::bitb_im,&m6800_cpu_device::ldb_im, &m6800_cpu_device::stb_im, +&m6800_cpu_device::eorb_im,&m6800_cpu_device::adcb_im,&m6800_cpu_device::orb_im, &m6800_cpu_device::addb_im,&m6800_cpu_device::ldd_im, &m6800_cpu_device::std_im, &m6800_cpu_device::ldx_im, &m6800_cpu_device::stx_im, +&m6800_cpu_device::subb_di,&m6800_cpu_device::cmpb_di,&m6800_cpu_device::sbcb_di,&m6800_cpu_device::addd_di,&m6800_cpu_device::andb_di,&m6800_cpu_device::bitb_di,&m6800_cpu_device::ldb_di, &m6800_cpu_device::stb_di, +&m6800_cpu_device::eorb_di,&m6800_cpu_device::adcb_di,&m6800_cpu_device::orb_di, &m6800_cpu_device::addb_di,&m6800_cpu_device::ldd_di, &m6800_cpu_device::std_di, &m6800_cpu_device::ldx_di, &m6800_cpu_device::stx_di, +&m6800_cpu_device::subb_ix,&m6800_cpu_device::cmpb_ix,&m6800_cpu_device::sbcb_ix,&m6800_cpu_device::addd_ix,&m6800_cpu_device::andb_ix,&m6800_cpu_device::bitb_ix,&m6800_cpu_device::ldb_ix, &m6800_cpu_device::stb_ix, +&m6800_cpu_device::eorb_ix,&m6800_cpu_device::adcb_ix,&m6800_cpu_device::orb_ix, &m6800_cpu_device::addb_ix,&m6800_cpu_device::ldd_ix, &m6800_cpu_device::std_ix, &m6800_cpu_device::ldx_ix, &m6800_cpu_device::stx_ix, +&m6800_cpu_device::subb_ex,&m6800_cpu_device::cmpb_ex,&m6800_cpu_device::sbcb_ex,&m6800_cpu_device::addd_ex,&m6800_cpu_device::andb_ex,&m6800_cpu_device::bitb_ex,&m6800_cpu_device::ldb_ex, &m6800_cpu_device::stb_ex, +&m6800_cpu_device::eorb_ex,&m6800_cpu_device::adcb_ex,&m6800_cpu_device::orb_ex, &m6800_cpu_device::addb_ex,&m6800_cpu_device::ldd_ex, &m6800_cpu_device::std_ex, &m6800_cpu_device::ldx_ex, &m6800_cpu_device::stx_ex +}; + +const m6800_cpu_device::op_func m6800_cpu_device::hd63701_insn[0x100] = { +&m6800_cpu_device::trap, &m6800_cpu_device::nop, &m6800_cpu_device::trap, &m6800_cpu_device::trap, &m6800_cpu_device::lsrd, &m6800_cpu_device::asld, &m6800_cpu_device::tap, &m6800_cpu_device::tpa, +&m6800_cpu_device::inx, &m6800_cpu_device::dex, &m6800_cpu_device::clv, &m6800_cpu_device::sev, &m6800_cpu_device::clc, &m6800_cpu_device::sec, &m6800_cpu_device::cli, &m6800_cpu_device::sei, +&m6800_cpu_device::sba, &m6800_cpu_device::cba, &m6800_cpu_device::undoc1, &m6800_cpu_device::undoc2, &m6800_cpu_device::trap, &m6800_cpu_device::trap, &m6800_cpu_device::tab, &m6800_cpu_device::tba, +&m6800_cpu_device::xgdx, &m6800_cpu_device::daa, &m6800_cpu_device::slp, &m6800_cpu_device::aba, &m6800_cpu_device::trap, &m6800_cpu_device::trap, &m6800_cpu_device::trap, &m6800_cpu_device::trap, +&m6800_cpu_device::bra, &m6800_cpu_device::brn, &m6800_cpu_device::bhi, &m6800_cpu_device::bls, &m6800_cpu_device::bcc, &m6800_cpu_device::bcs, &m6800_cpu_device::bne, &m6800_cpu_device::beq, +&m6800_cpu_device::bvc, &m6800_cpu_device::bvs, &m6800_cpu_device::bpl, &m6800_cpu_device::bmi, &m6800_cpu_device::bge, &m6800_cpu_device::blt, &m6800_cpu_device::bgt, &m6800_cpu_device::ble, +&m6800_cpu_device::tsx, &m6800_cpu_device::ins, &m6800_cpu_device::pula, &m6800_cpu_device::pulb, &m6800_cpu_device::des, &m6800_cpu_device::txs, &m6800_cpu_device::psha, &m6800_cpu_device::pshb, +&m6800_cpu_device::pulx, &m6800_cpu_device::rts, &m6800_cpu_device::abx, &m6800_cpu_device::rti, &m6800_cpu_device::pshx, &m6800_cpu_device::mul, &m6800_cpu_device::wai, &m6800_cpu_device::swi, +&m6800_cpu_device::nega, &m6800_cpu_device::trap, &m6800_cpu_device::trap, &m6800_cpu_device::coma, &m6800_cpu_device::lsra, &m6800_cpu_device::trap, &m6800_cpu_device::rora, &m6800_cpu_device::asra, +&m6800_cpu_device::asla, &m6800_cpu_device::rola, &m6800_cpu_device::deca, &m6800_cpu_device::trap, &m6800_cpu_device::inca, &m6800_cpu_device::tsta, &m6800_cpu_device::trap, &m6800_cpu_device::clra, +&m6800_cpu_device::negb, &m6800_cpu_device::trap, &m6800_cpu_device::trap, &m6800_cpu_device::comb, &m6800_cpu_device::lsrb, &m6800_cpu_device::trap, &m6800_cpu_device::rorb, &m6800_cpu_device::asrb, +&m6800_cpu_device::aslb, &m6800_cpu_device::rolb, &m6800_cpu_device::decb, &m6800_cpu_device::trap, &m6800_cpu_device::incb, &m6800_cpu_device::tstb, &m6800_cpu_device::trap, &m6800_cpu_device::clrb, +&m6800_cpu_device::neg_ix, &m6800_cpu_device::aim_ix, &m6800_cpu_device::oim_ix, &m6800_cpu_device::com_ix, &m6800_cpu_device::lsr_ix, &m6800_cpu_device::eim_ix, &m6800_cpu_device::ror_ix, &m6800_cpu_device::asr_ix, +&m6800_cpu_device::asl_ix, &m6800_cpu_device::rol_ix, &m6800_cpu_device::dec_ix, &m6800_cpu_device::tim_ix, &m6800_cpu_device::inc_ix, &m6800_cpu_device::tst_ix, &m6800_cpu_device::jmp_ix, &m6800_cpu_device::clr_ix, +&m6800_cpu_device::neg_ex, &m6800_cpu_device::aim_di, &m6800_cpu_device::oim_di, &m6800_cpu_device::com_ex, &m6800_cpu_device::lsr_ex, &m6800_cpu_device::eim_di, &m6800_cpu_device::ror_ex, &m6800_cpu_device::asr_ex, +&m6800_cpu_device::asl_ex, &m6800_cpu_device::rol_ex, &m6800_cpu_device::dec_ex, &m6800_cpu_device::tim_di, &m6800_cpu_device::inc_ex, &m6800_cpu_device::tst_ex, &m6800_cpu_device::jmp_ex, &m6800_cpu_device::clr_ex, +&m6800_cpu_device::suba_im,&m6800_cpu_device::cmpa_im,&m6800_cpu_device::sbca_im,&m6800_cpu_device::subd_im,&m6800_cpu_device::anda_im,&m6800_cpu_device::bita_im,&m6800_cpu_device::lda_im, &m6800_cpu_device::sta_im, +&m6800_cpu_device::eora_im,&m6800_cpu_device::adca_im,&m6800_cpu_device::ora_im, &m6800_cpu_device::adda_im,&m6800_cpu_device::cpx_im ,&m6800_cpu_device::bsr, &m6800_cpu_device::lds_im, &m6800_cpu_device::sts_im, +&m6800_cpu_device::suba_di,&m6800_cpu_device::cmpa_di,&m6800_cpu_device::sbca_di,&m6800_cpu_device::subd_di,&m6800_cpu_device::anda_di,&m6800_cpu_device::bita_di,&m6800_cpu_device::lda_di, &m6800_cpu_device::sta_di, +&m6800_cpu_device::eora_di,&m6800_cpu_device::adca_di,&m6800_cpu_device::ora_di, &m6800_cpu_device::adda_di,&m6800_cpu_device::cpx_di ,&m6800_cpu_device::jsr_di, &m6800_cpu_device::lds_di, &m6800_cpu_device::sts_di, +&m6800_cpu_device::suba_ix,&m6800_cpu_device::cmpa_ix,&m6800_cpu_device::sbca_ix,&m6800_cpu_device::subd_ix,&m6800_cpu_device::anda_ix,&m6800_cpu_device::bita_ix,&m6800_cpu_device::lda_ix, &m6800_cpu_device::sta_ix, +&m6800_cpu_device::eora_ix,&m6800_cpu_device::adca_ix,&m6800_cpu_device::ora_ix, &m6800_cpu_device::adda_ix,&m6800_cpu_device::cpx_ix ,&m6800_cpu_device::jsr_ix, &m6800_cpu_device::lds_ix, &m6800_cpu_device::sts_ix, +&m6800_cpu_device::suba_ex,&m6800_cpu_device::cmpa_ex,&m6800_cpu_device::sbca_ex,&m6800_cpu_device::subd_ex,&m6800_cpu_device::anda_ex,&m6800_cpu_device::bita_ex,&m6800_cpu_device::lda_ex, &m6800_cpu_device::sta_ex, +&m6800_cpu_device::eora_ex,&m6800_cpu_device::adca_ex,&m6800_cpu_device::ora_ex, &m6800_cpu_device::adda_ex,&m6800_cpu_device::cpx_ex ,&m6800_cpu_device::jsr_ex, &m6800_cpu_device::lds_ex, &m6800_cpu_device::sts_ex, +&m6800_cpu_device::subb_im,&m6800_cpu_device::cmpb_im,&m6800_cpu_device::sbcb_im,&m6800_cpu_device::addd_im,&m6800_cpu_device::andb_im,&m6800_cpu_device::bitb_im,&m6800_cpu_device::ldb_im, &m6800_cpu_device::stb_im, +&m6800_cpu_device::eorb_im,&m6800_cpu_device::adcb_im,&m6800_cpu_device::orb_im, &m6800_cpu_device::addb_im,&m6800_cpu_device::ldd_im, &m6800_cpu_device::std_im, &m6800_cpu_device::ldx_im, &m6800_cpu_device::stx_im, +&m6800_cpu_device::subb_di,&m6800_cpu_device::cmpb_di,&m6800_cpu_device::sbcb_di,&m6800_cpu_device::addd_di,&m6800_cpu_device::andb_di,&m6800_cpu_device::bitb_di,&m6800_cpu_device::ldb_di, &m6800_cpu_device::stb_di, +&m6800_cpu_device::eorb_di,&m6800_cpu_device::adcb_di,&m6800_cpu_device::orb_di, &m6800_cpu_device::addb_di,&m6800_cpu_device::ldd_di, &m6800_cpu_device::std_di, &m6800_cpu_device::ldx_di, &m6800_cpu_device::stx_di, +&m6800_cpu_device::subb_ix,&m6800_cpu_device::cmpb_ix,&m6800_cpu_device::sbcb_ix,&m6800_cpu_device::addd_ix,&m6800_cpu_device::andb_ix,&m6800_cpu_device::bitb_ix,&m6800_cpu_device::ldb_ix, &m6800_cpu_device::stb_ix, +&m6800_cpu_device::eorb_ix,&m6800_cpu_device::adcb_ix,&m6800_cpu_device::orb_ix, &m6800_cpu_device::addb_ix,&m6800_cpu_device::ldd_ix, &m6800_cpu_device::std_ix, &m6800_cpu_device::ldx_ix, &m6800_cpu_device::stx_ix, +&m6800_cpu_device::subb_ex,&m6800_cpu_device::cmpb_ex,&m6800_cpu_device::sbcb_ex,&m6800_cpu_device::addd_ex,&m6800_cpu_device::andb_ex,&m6800_cpu_device::bitb_ex,&m6800_cpu_device::ldb_ex, &m6800_cpu_device::stb_ex, +&m6800_cpu_device::eorb_ex,&m6800_cpu_device::adcb_ex,&m6800_cpu_device::orb_ex, &m6800_cpu_device::addb_ex,&m6800_cpu_device::ldd_ex, &m6800_cpu_device::std_ex, &m6800_cpu_device::ldx_ex, &m6800_cpu_device::stx_ex +}; + +const m6800_cpu_device::op_func m6800_cpu_device::nsc8105_insn[0x100] = { +&m6800_cpu_device::illegal,&m6800_cpu_device::illegal,&m6800_cpu_device::nop, &m6800_cpu_device::illegal,&m6800_cpu_device::illegal,&m6800_cpu_device::tap, &m6800_cpu_device::illegal,&m6800_cpu_device::tpa, +&m6800_cpu_device::inx, &m6800_cpu_device::clv, &m6800_cpu_device::dex, &m6800_cpu_device::sev, &m6800_cpu_device::clc, &m6800_cpu_device::cli, &m6800_cpu_device::sec, &m6800_cpu_device::sei, +&m6800_cpu_device::sba, &m6800_cpu_device::illegal,&m6800_cpu_device::cba, &m6800_cpu_device::illegal,&m6800_cpu_device::illegal,&m6800_cpu_device::tab, &m6800_cpu_device::illegal,&m6800_cpu_device::tba, +&m6800_cpu_device::illegal,&m6800_cpu_device::illegal,&m6800_cpu_device::daa, &m6800_cpu_device::aba, &m6800_cpu_device::illegal,&m6800_cpu_device::illegal,&m6800_cpu_device::illegal,&m6800_cpu_device::illegal, +&m6800_cpu_device::bra, &m6800_cpu_device::bhi, &m6800_cpu_device::brn, &m6800_cpu_device::bls, &m6800_cpu_device::bcc, &m6800_cpu_device::bne, &m6800_cpu_device::bcs, &m6800_cpu_device::beq, +&m6800_cpu_device::bvc, &m6800_cpu_device::bpl, &m6800_cpu_device::bvs, &m6800_cpu_device::bmi, &m6800_cpu_device::bge, &m6800_cpu_device::bgt, &m6800_cpu_device::blt, &m6800_cpu_device::ble, +&m6800_cpu_device::tsx, &m6800_cpu_device::pula, &m6800_cpu_device::ins, &m6800_cpu_device::pulb, &m6800_cpu_device::des, &m6800_cpu_device::psha, &m6800_cpu_device::txs, &m6800_cpu_device::pshb, +&m6800_cpu_device::illegal,&m6800_cpu_device::illegal,&m6800_cpu_device::rts, &m6800_cpu_device::rti, &m6800_cpu_device::illegal,&m6800_cpu_device::wai, &m6800_cpu_device::illegal,&m6800_cpu_device::swi, +&m6800_cpu_device::suba_im,&m6800_cpu_device::sbca_im,&m6800_cpu_device::cmpa_im,&m6800_cpu_device::illegal,&m6800_cpu_device::anda_im,&m6800_cpu_device::lda_im, &m6800_cpu_device::bita_im,&m6800_cpu_device::sta_im, +&m6800_cpu_device::eora_im,&m6800_cpu_device::ora_im, &m6800_cpu_device::adca_im,&m6800_cpu_device::adda_im,&m6800_cpu_device::cmpx_im,&m6800_cpu_device::lds_im, &m6800_cpu_device::bsr, &m6800_cpu_device::sts_im, +&m6800_cpu_device::suba_di,&m6800_cpu_device::sbca_di,&m6800_cpu_device::cmpa_di,&m6800_cpu_device::illegal,&m6800_cpu_device::anda_di,&m6800_cpu_device::lda_di, &m6800_cpu_device::bita_di,&m6800_cpu_device::sta_di, +&m6800_cpu_device::eora_di,&m6800_cpu_device::ora_di, &m6800_cpu_device::adca_di,&m6800_cpu_device::adda_di,&m6800_cpu_device::cmpx_di,&m6800_cpu_device::lds_di, &m6800_cpu_device::jsr_di, &m6800_cpu_device::sts_di, +&m6800_cpu_device::suba_ix,&m6800_cpu_device::sbca_ix,&m6800_cpu_device::cmpa_ix,&m6800_cpu_device::illegal,&m6800_cpu_device::anda_ix,&m6800_cpu_device::lda_ix, &m6800_cpu_device::bita_ix,&m6800_cpu_device::sta_ix, +&m6800_cpu_device::eora_ix,&m6800_cpu_device::ora_ix, &m6800_cpu_device::adca_ix,&m6800_cpu_device::adda_ix,&m6800_cpu_device::cmpx_ix,&m6800_cpu_device::lds_ix, &m6800_cpu_device::jsr_ix, &m6800_cpu_device::sts_ix, +&m6800_cpu_device::suba_ex,&m6800_cpu_device::sbca_ex,&m6800_cpu_device::cmpa_ex,&m6800_cpu_device::illegal,&m6800_cpu_device::anda_ex,&m6800_cpu_device::lda_ex, &m6800_cpu_device::bita_ex,&m6800_cpu_device::sta_ex, +&m6800_cpu_device::eora_ex,&m6800_cpu_device::ora_ex, &m6800_cpu_device::adca_ex,&m6800_cpu_device::adda_ex,&m6800_cpu_device::cmpx_ex,&m6800_cpu_device::lds_ex, &m6800_cpu_device::jsr_ex, &m6800_cpu_device::sts_ex, +&m6800_cpu_device::nega, &m6800_cpu_device::illegal,&m6800_cpu_device::illegal,&m6800_cpu_device::coma, &m6800_cpu_device::lsra, &m6800_cpu_device::rora, &m6800_cpu_device::illegal,&m6800_cpu_device::asra, +&m6800_cpu_device::asla, &m6800_cpu_device::deca, &m6800_cpu_device::rola, &m6800_cpu_device::illegal,&m6800_cpu_device::inca, &m6800_cpu_device::illegal,&m6800_cpu_device::tsta, &m6800_cpu_device::clra, +&m6800_cpu_device::negb, &m6800_cpu_device::illegal,&m6800_cpu_device::illegal,&m6800_cpu_device::comb, &m6800_cpu_device::lsrb, &m6800_cpu_device::rorb, &m6800_cpu_device::illegal,&m6800_cpu_device::asrb, +&m6800_cpu_device::aslb, &m6800_cpu_device::decb, &m6800_cpu_device::rolb, &m6800_cpu_device::illegal,&m6800_cpu_device::incb, &m6800_cpu_device::illegal,&m6800_cpu_device::tstb, &m6800_cpu_device::clrb, +&m6800_cpu_device::neg_ix, &m6800_cpu_device::illegal,&m6800_cpu_device::illegal,&m6800_cpu_device::com_ix, &m6800_cpu_device::lsr_ix, &m6800_cpu_device::ror_ix, &m6800_cpu_device::illegal,&m6800_cpu_device::asr_ix, +&m6800_cpu_device::asl_ix, &m6800_cpu_device::dec_ix, &m6800_cpu_device::rol_ix, &m6800_cpu_device::illegal,&m6800_cpu_device::inc_ix, &m6800_cpu_device::jmp_ix, &m6800_cpu_device::tst_ix, &m6800_cpu_device::clr_ix, +&m6800_cpu_device::neg_ex, &m6800_cpu_device::illegal,&m6800_cpu_device::illegal,&m6800_cpu_device::com_ex, &m6800_cpu_device::lsr_ex, &m6800_cpu_device::ror_ex, &m6800_cpu_device::illegal,&m6800_cpu_device::asr_ex, +&m6800_cpu_device::asl_ex, &m6800_cpu_device::dec_ex, &m6800_cpu_device::rol_ex, &m6800_cpu_device::illegal,&m6800_cpu_device::inc_ex, &m6800_cpu_device::jmp_ex, &m6800_cpu_device::tst_ex, &m6800_cpu_device::clr_ex, +&m6800_cpu_device::subb_im,&m6800_cpu_device::sbcb_im,&m6800_cpu_device::cmpb_im,&m6800_cpu_device::illegal,&m6800_cpu_device::andb_im,&m6800_cpu_device::ldb_im, &m6800_cpu_device::bitb_im,&m6800_cpu_device::stb_im, +&m6800_cpu_device::eorb_im,&m6800_cpu_device::orb_im, &m6800_cpu_device::adcb_im,&m6800_cpu_device::addb_im,&m6800_cpu_device::illegal,&m6800_cpu_device::ldx_im, &m6800_cpu_device::illegal,&m6800_cpu_device::stx_im, +&m6800_cpu_device::subb_di,&m6800_cpu_device::sbcb_di,&m6800_cpu_device::cmpb_di,&m6800_cpu_device::illegal,&m6800_cpu_device::andb_di,&m6800_cpu_device::ldb_di, &m6800_cpu_device::bitb_di,&m6800_cpu_device::stb_di, +&m6800_cpu_device::eorb_di,&m6800_cpu_device::orb_di, &m6800_cpu_device::adcb_di,&m6800_cpu_device::addb_di,&m6800_cpu_device::illegal,&m6800_cpu_device::ldx_di, &m6800_cpu_device::illegal,&m6800_cpu_device::stx_di, +&m6800_cpu_device::subb_ix,&m6800_cpu_device::sbcb_ix,&m6800_cpu_device::cmpb_ix,&m6800_cpu_device::illegal,&m6800_cpu_device::andb_ix,&m6800_cpu_device::ldb_ix, &m6800_cpu_device::bitb_ix,&m6800_cpu_device::stb_ix, +&m6800_cpu_device::eorb_ix,&m6800_cpu_device::orb_ix, &m6800_cpu_device::adcb_ix,&m6800_cpu_device::addb_ix,&m6800_cpu_device::adcx_im,&m6800_cpu_device::ldx_ix, &m6800_cpu_device::illegal,&m6800_cpu_device::stx_ix, +&m6800_cpu_device::subb_ex,&m6800_cpu_device::sbcb_ex,&m6800_cpu_device::cmpb_ex,&m6800_cpu_device::illegal,&m6800_cpu_device::andb_ex,&m6800_cpu_device::ldb_ex, &m6800_cpu_device::bitb_ex,&m6800_cpu_device::stb_ex, +&m6800_cpu_device::eorb_ex,&m6800_cpu_device::orb_ex, &m6800_cpu_device::adcb_ex,&m6800_cpu_device::addb_ex,&m6800_cpu_device::addx_ex,&m6800_cpu_device::ldx_ex, &m6800_cpu_device::illegal,&m6800_cpu_device::stx_ex +}; diff --git a/src/devices/cpu/m6800/m6800.c b/src/devices/cpu/m6800/m6800.c new file mode 100644 index 00000000000..46a7cc4a99a --- /dev/null +++ b/src/devices/cpu/m6800/m6800.c @@ -0,0 +1,1817 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*** m6800: Portable 6800 class emulator ************************************* + + m68xx.c + + References: + + 6809 Simulator V09, By L.C. Benschop, Eindhoven The Netherlands. + + m6809: Portable 6809 emulator, DS (6809 code in MAME, derived from + the 6809 Simulator V09) + + 6809 Microcomputer Programming & Interfacing with Experiments" + by Andrew C. Staugaard, Jr.; Howard W. Sams & Co., Inc. + + System dependencies: UINT16 must be 16 bit unsigned int + UINT8 must be 8 bit unsigned int + UINT32 must be more than 16 bits + arrays up to 65536 bytes must be supported + machine must be twos complement + +History +991031 ZV + Added NSC-8105 support + +990319 HJB + Fixed wrong LSB/MSB order for push/pull word. + Subtract .extra_cycles at the beginning/end of the exectuion loops. + +990316 HJB + Renamed to 6800, since that's the basic CPU. + Added different cycle count tables for M6800/2/8, M6801/3 and m68xx. + +990314 HJB + Also added the M6800 subtype. + +990311 HJB + Added _info functions. Now uses static m6808_Regs struct instead + of single statics. Changed the 16 bit registers to use the generic + PAIR union. Registers defined using macros. Split the core into + four execution loops for M6802, M6803, M6808 and HD63701. + TST, TSTA and TSTB opcodes reset carry flag. +TODO: + Verify invalid opcodes for the different CPU types. + Add proper credits to _info functions. + Integrate m6808_Flags into the registers (multiple m6808 type CPUs?) + +990301 HJB + Modified the interrupt handling. No more pending interrupt checks. + WAI opcode saves state, when an interrupt is taken (IRQ or OCI), + the state is only saved if not already done by WAI. + +*****************************************************************************/ + +/* + + Chip RAM NVRAM ROM SCI r15-f ports + ----------------------------------------------------------------- + MC6800 - - - no no 4 + MC6802 128 32 - no no 4 + MC6802NS 128 - - no no 4 + MC6808 - - - no no 4 + + MC6801 128 64 2K yes no 4 + MC68701 128 64 - yes no 4 + MC6803 128 64 - yes no 4 + + MC6801U4 192 32 4K yes yes 4 + MC6803U4 192 32 - yes yes 4 + + HD6801 128 64 2K yes no 4 + HD6301V 128 - 4K yes no 4 + HD63701V 192 - 4K yes no 4 + HD6303R 128 - - yes no 4 + + HD6301X 192 - 4K yes yes 6 + HD6301Y 256 - 16K yes yes 6 + HD6303X 192 - - yes yes 6 + HD6303Y 256 - - yes yes 6 + + NSC8105 + MS2010-A + +*/ + +#include "emu.h" +#include "debugger.h" +#include "m6800.h" + +#define VERBOSE 0 + +#define LOG(x) do { if (VERBOSE) logerror x; } while (0) + +#if 0 +/* CPU subtypes, needed for extra insn after TAP/CLI/SEI */ +enum +{ + SUBTYPE_M6800, + SUBTYPE_M6801, + SUBTYPE_M6802, + SUBTYPE_M6803, + SUBTYPE_M6808, + SUBTYPE_HD6301, + SUBTYPE_HD63701, + SUBTYPE_NSC8105 +}; +#endif + + +#if 0 +static void hd63701_trap_pc(); +#endif + +#define pPPC m_ppc +#define pPC m_pc +#define pS m_s +#define pX m_x +#define pD m_d + +#define PC m_pc.w.l +#define PCD m_pc.d +#define S m_s.w.l +#define SD m_s.d +#define X m_x.w.l +#define D m_d.w.l +#define A m_d.b.h +#define B m_d.b.l +#define CC m_cc + +#define CT m_counter.w.l +#define CTH m_counter.w.h +#define CTD m_counter.d +#define OC m_output_compare.w.l +#define OCH m_output_compare.w.h +#define OCD m_output_compare.d +#define TOH m_timer_over.w.l +#define TOD m_timer_over.d + +#define EAD m_ea.d +#define EA m_ea.w.l + +/* point of next timer event */ +static UINT32 timer_next; + +/* memory interface */ + +/****************************************************************************/ +/* Read a byte from given memory location */ +/****************************************************************************/ +#define RM(Addr) ((unsigned)m_program->read_byte(Addr)) + +/****************************************************************************/ +/* Write a byte to given memory location */ +/****************************************************************************/ +#define WM(Addr,Value) (m_program->write_byte(Addr,Value)) + +/****************************************************************************/ +/* M6800_RDOP() is identical to M6800_RDMEM() except it is used for reading */ +/* opcodes. In case of system with memory mapped I/O, this function can be */ +/* used to greatly speed up emulation */ +/****************************************************************************/ +#define M_RDOP(Addr) ((unsigned)m_decrypted_opcodes_direct->read_byte(Addr)) + +/****************************************************************************/ +/* M6800_RDOP_ARG() is identical to M6800_RDOP() but it's used for reading */ +/* opcode arguments. This difference can be used to support systems that */ +/* use different encoding mechanisms for opcodes and opcode arguments */ +/****************************************************************************/ +#define M_RDOP_ARG(Addr) ((unsigned)m_direct->read_byte(Addr)) + +/* macros to access memory */ +#define IMMBYTE(b) b = M_RDOP_ARG(PCD); PC++ +#define IMMWORD(w) w.d = (M_RDOP_ARG(PCD)<<8) | M_RDOP_ARG((PCD+1)&0xffff); PC+=2 + +#define PUSHBYTE(b) WM(SD,b); --S +#define PUSHWORD(w) WM(SD,w.b.l); --S; WM(SD,w.b.h); --S +#define PULLBYTE(b) S++; b = RM(SD) +#define PULLWORD(w) S++; w.d = RM(SD)<<8; S++; w.d |= RM(SD) + +#define MODIFIED_tcsr { \ + m_irq2 = (m_tcsr&(m_tcsr<<3))&(TCSR_ICF|TCSR_OCF|TCSR_TOF); \ +} + +#define SET_TIMER_EVENT { \ + timer_next = (OCD - CTD < TOD - CTD) ? OCD : TOD; \ +} + +/* cleanup high-word of counters */ +#define CLEANUP_COUNTERS() { \ + OCH -= CTH; \ + TOH -= CTH; \ + CTH = 0; \ + SET_TIMER_EVENT; \ +} + +/* when change freerunningcounter or outputcapture */ +#define MODIFIED_counters { \ + OCH = (OC >= CT) ? CTH : CTH+1; \ + SET_TIMER_EVENT; \ +} + +// I/O registers + +enum +{ + IO_P1DDR = 0, + IO_P2DDR, + IO_P1DATA, + IO_P2DATA, + IO_P3DDR, + IO_P4DDR, + IO_P3DATA, + IO_P4DATA, + IO_TCSR, + IO_CH, + IO_CL, + IO_OCRH, + IO_OCRL, + IO_ICRH, + IO_ICRL, + IO_P3CSR, + IO_RMCR, + IO_TRCSR, + IO_RDR, + IO_TDR, + IO_RCR, + IO_CAAH, + IO_CAAL, + IO_TCR1, + IO_TCR2, + IO_TSR, + IO_OCR2H, + IO_OCR2L, + IO_OCR3H, + IO_OCR3L, + IO_ICR2H, + IO_ICR2L +}; + +// serial I/O + +#define M6800_RMCR_SS_MASK 0x03 // Speed Select +#define M6800_RMCR_SS_4096 0x03 // E / 4096 +#define M6800_RMCR_SS_1024 0x02 // E / 1024 +#define M6800_RMCR_SS_128 0x01 // E / 128 +#define M6800_RMCR_SS_16 0x00 // E / 16 +#define M6800_RMCR_CC_MASK 0x0c // Clock Control/Format Select + +#define M6800_TRCSR_RDRF 0x80 // Receive Data Register Full +#define M6800_TRCSR_ORFE 0x40 // Over Run Framing Error +#define M6800_TRCSR_TDRE 0x20 // Transmit Data Register Empty +#define M6800_TRCSR_RIE 0x10 // Receive Interrupt Enable +#define M6800_TRCSR_RE 0x08 // Receive Enable +#define M6800_TRCSR_TIE 0x04 // Transmit Interrupt Enable +#define M6800_TRCSR_TE 0x02 // Transmit Enable +#define M6800_TRCSR_WU 0x01 // Wake Up + +#define M6800_PORT2_IO4 0x10 +#define M6800_PORT2_IO3 0x08 + +#define M6801_P3CSR_LE 0x08 +#define M6801_P3CSR_OSS 0x10 +#define M6801_P3CSR_IS3_ENABLE 0x40 +#define M6801_P3CSR_IS3_FLAG 0x80 + +static const int M6800_RMCR_SS[] = { 16, 128, 1024, 4096 }; + +#define M6800_SERIAL_START 0 +#define M6800_SERIAL_STOP 9 + +enum +{ + M6800_TX_STATE_INIT = 0, + M6800_TX_STATE_READY +}; + +/* take interrupt */ +#define TAKE_ICI enter_interrupt("M6800 '%s' take ICI\n",0xfff6) +#define TAKE_OCI enter_interrupt("M6800 '%s' take OCI\n",0xfff4) +#define TAKE_TOI enter_interrupt("M6800 '%s' take TOI\n",0xfff2) +#define TAKE_SCI enter_interrupt("M6800 '%s' take SCI\n",0xfff0) +#define TAKE_TRAP enter_interrupt("M6800 '%s' take TRAP\n",0xffee) + +/* operate one instruction for */ +#define ONE_MORE_INSN() { \ + UINT8 ireg; \ + pPPC = pPC; \ + debugger_instruction_hook(this, PCD); \ + ireg=M_RDOP(PCD); \ + PC++; \ + (this->*m_insn[ireg])(); \ + increment_counter(m_cycles[ireg]); \ +} + +/* CC masks HI NZVC + 7654 3210 */ +#define CLR_HNZVC CC&=0xd0 +#define CLR_NZV CC&=0xf1 +#define CLR_HNZC CC&=0xd2 +#define CLR_NZVC CC&=0xf0 +#define CLR_Z CC&=0xfb +#define CLR_NZC CC&=0xf2 +#define CLR_ZC CC&=0xfa +#define CLR_C CC&=0xfe + +/* macros for CC -- CC bits affected should be reset before calling */ +#define SET_Z(a) if(!(a))SEZ +#define SET_Z8(a) SET_Z((UINT8)(a)) +#define SET_Z16(a) SET_Z((UINT16)(a)) +#define SET_N8(a) CC|=(((a)&0x80)>>4) +#define SET_N16(a) CC|=(((a)&0x8000)>>12) +#define SET_H(a,b,r) CC|=((((a)^(b)^(r))&0x10)<<1) +#define SET_C8(a) CC|=(((a)&0x100)>>8) +#define SET_C16(a) CC|=(((a)&0x10000)>>16) +#define SET_V8(a,b,r) CC|=((((a)^(b)^(r)^((r)>>1))&0x80)>>6) +#define SET_V16(a,b,r) CC|=((((a)^(b)^(r)^((r)>>1))&0x8000)>>14) + +const UINT8 m6800_cpu_device::flags8i[256]= /* increment */ +{ +0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x0a,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08, +0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08, +0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08, +0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08, +0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08, +0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08, +0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08, +0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08 +}; + + +const UINT8 m6800_cpu_device::flags8d[256]= /* decrement */ +{ +0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02, +0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08, +0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08, +0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08, +0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08, +0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08, +0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08, +0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08, +0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08 +}; + +#define SET_FLAGS8I(a) {CC|=flags8i[(a)&0xff];} +#define SET_FLAGS8D(a) {CC|=flags8d[(a)&0xff];} + +/* combos */ +#define SET_NZ8(a) {SET_N8(a);SET_Z8(a);} +#define SET_NZ16(a) {SET_N16(a);SET_Z16(a);} +#define SET_FLAGS8(a,b,r) {SET_N8(r);SET_Z8(r);SET_V8(a,b,r);SET_C8(r);} +#define SET_FLAGS16(a,b,r) {SET_N16(r);SET_Z16(r);SET_V16(a,b,r);SET_C16(r);} + +/* for treating an UINT8 as a signed INT16 */ +#define SIGNED(b) ((INT16)(b&0x80?b|0xff00:b)) + +/* Macros for addressing modes */ +#define DIRECT IMMBYTE(EAD) +#define IMM8 EA=PC++ +#define IMM16 {EA=PC;PC+=2;} +#define EXTENDED IMMWORD(m_ea) +#define INDEXED {EA=X+(UINT8)M_RDOP_ARG(PCD);PC++;} + +/* macros to set status flags */ +#if defined(SEC) +#undef SEC +#endif +#define SEC CC|=0x01 +#define CLC CC&=0xfe +#define SEZ CC|=0x04 +#define CLZ CC&=0xfb +#define SEN CC|=0x08 +#define CLN CC&=0xf7 +#define SEV CC|=0x02 +#define CLV CC&=0xfd +#define SEH CC|=0x20 +#define CLH CC&=0xdf +#define SEI CC|=0x10 +#define CLI CC&=~0x10 + +/* mnemonicos for the Timer Control and Status Register bits */ +#define TCSR_OLVL 0x01 +#define TCSR_IEDG 0x02 +#define TCSR_ETOI 0x04 +#define TCSR_EOCI 0x08 +#define TCSR_EICI 0x10 +#define TCSR_TOF 0x20 +#define TCSR_OCF 0x40 +#define TCSR_ICF 0x80 + +/* macros for convenience */ +#define DIRBYTE(b) {DIRECT;b=RM(EAD);} +#define DIRWORD(w) {DIRECT;w.d=RM16(EAD);} +#define EXTBYTE(b) {EXTENDED;b=RM(EAD);} +#define EXTWORD(w) {EXTENDED;w.d=RM16(EAD);} + +#define IDXBYTE(b) {INDEXED;b=RM(EAD);} +#define IDXWORD(w) {INDEXED;w.d=RM16(EAD);} + +/* Macros for branch instructions */ +#define BRANCH(f) {IMMBYTE(t);if(f){PC+=SIGNED(t);}} +#define NXORV ((CC&0x08)^((CC&0x02)<<2)) + +#define M6800_WAI 8 /* set when WAI is waiting for an interrupt */ +#define M6800_SLP 0x10 /* HD63701 only */ + +/* Note: don't use 0 cycles here for invalid opcodes so that we don't */ +/* hang in an infinite loop if we hit one */ +#define XX 5 // invalid opcode unknown cc +const UINT8 m6800_cpu_device::cycles_6800[256] = +{ + /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ + /*0*/ XX, 2,XX,XX,XX,XX, 2, 2, 4, 4, 2, 2, 2, 2, 2, 2, + /*1*/ 2, 2,XX,XX,XX,XX, 2, 2,XX, 2,XX, 2,XX,XX,XX,XX, + /*2*/ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + /*3*/ 4, 4, 4, 4, 4, 4, 4, 4,XX, 5,XX,10,XX,XX, 9,12, + /*4*/ 2,XX,XX, 2, 2,XX, 2, 2, 2, 2, 2,XX, 2, 2,XX, 2, + /*5*/ 2,XX,XX, 2, 2,XX, 2, 2, 2, 2, 2,XX, 2, 2,XX, 2, + /*6*/ 7,XX,XX, 7, 7,XX, 7, 7, 7, 7, 7,XX, 7, 7, 4, 7, + /*7*/ 6,XX,XX, 6, 6,XX, 6, 6, 6, 6, 6,XX, 6, 6, 3, 6, + /*8*/ 2, 2, 2,XX, 2, 2, 2, 3, 2, 2, 2, 2, 3, 8, 3, 4, + /*9*/ 3, 3, 3,XX, 3, 3, 3, 4, 3, 3, 3, 3, 4, 6, 4, 5, + /*A*/ 5, 5, 5,XX, 5, 5, 5, 6, 5, 5, 5, 5, 6, 8, 6, 7, + /*B*/ 4, 4, 4,XX, 4, 4, 4, 5, 4, 4, 4, 4, 5, 9, 5, 6, + /*C*/ 2, 2, 2,XX, 2, 2, 2, 3, 2, 2, 2, 2,XX,XX, 3, 4, + /*D*/ 3, 3, 3,XX, 3, 3, 3, 4, 3, 3, 3, 3,XX,XX, 4, 5, + /*E*/ 5, 5, 5,XX, 5, 5, 5, 6, 5, 5, 5, 5,XX,XX, 6, 7, + /*F*/ 4, 4, 4,XX, 4, 4, 4, 5, 4, 4, 4, 4,XX,XX, 5, 6 +}; + +const UINT8 m6800_cpu_device::cycles_6803[256] = +{ + /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ + /*0*/ XX, 2,XX,XX, 3, 3, 2, 2, 3, 3, 2, 2, 2, 2, 2, 2, + /*1*/ 2, 2,XX,XX,XX,XX, 2, 2,XX, 2,XX, 2,XX,XX,XX,XX, + /*2*/ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + /*3*/ 3, 3, 4, 4, 3, 3, 3, 3, 5, 5, 3,10, 4,10, 9,12, + /*4*/ 2,XX,XX, 2, 2,XX, 2, 2, 2, 2, 2,XX, 2, 2,XX, 2, + /*5*/ 2,XX,XX, 2, 2,XX, 2, 2, 2, 2, 2,XX, 2, 2,XX, 2, + /*6*/ 6,XX,XX, 6, 6,XX, 6, 6, 6, 6, 6,XX, 6, 6, 3, 6, + /*7*/ 6,XX,XX, 6, 6,XX, 6, 6, 6, 6, 6,XX, 6, 6, 3, 6, + /*8*/ 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 2, 4, 6, 3, 3, + /*9*/ 3, 3, 3, 5, 3, 3, 3, 3, 3, 3, 3, 3, 5, 5, 4, 4, + /*A*/ 4, 4, 4, 6, 4, 4, 4, 4, 4, 4, 4, 4, 6, 6, 5, 5, + /*B*/ 4, 4, 4, 6, 4, 4, 4, 4, 4, 4, 4, 4, 6, 6, 5, 5, + /*C*/ 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 2, 3,XX, 3, 3, + /*D*/ 3, 3, 3, 5, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, + /*E*/ 4, 4, 4, 6, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, + /*F*/ 4, 4, 4, 6, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5 +}; + +const UINT8 m6800_cpu_device::cycles_63701[256] = +{ + /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ + /*0*/ XX, 1,XX,XX, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + /*1*/ 1, 1,XX,XX,XX,XX, 1, 1, 2, 2, 4, 1,XX,XX,XX,XX, + /*2*/ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + /*3*/ 1, 1, 3, 3, 1, 1, 4, 4, 4, 5, 1,10, 5, 7, 9,12, + /*4*/ 1,XX,XX, 1, 1,XX, 1, 1, 1, 1, 1,XX, 1, 1,XX, 1, + /*5*/ 1,XX,XX, 1, 1,XX, 1, 1, 1, 1, 1,XX, 1, 1,XX, 1, + /*6*/ 6, 7, 7, 6, 6, 7, 6, 6, 6, 6, 6, 5, 6, 4, 3, 5, + /*7*/ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 4, 6, 4, 3, 5, + /*8*/ 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 3, 5, 3, 3, + /*9*/ 3, 3, 3, 4, 3, 3, 3, 3, 3, 3, 3, 3, 4, 5, 4, 4, + /*A*/ 4, 4, 4, 5, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, + /*B*/ 4, 4, 4, 5, 4, 4, 4, 4, 4, 4, 4, 4, 5, 6, 5, 5, + /*C*/ 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 3,XX, 3, 3, + /*D*/ 3, 3, 3, 4, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, + /*E*/ 4, 4, 4, 5, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, + /*F*/ 4, 4, 4, 5, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5 +}; + +const UINT8 m6800_cpu_device::cycles_nsc8105[256] = +{ + /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ + /*0*/ XX,XX, 2,XX,XX, 2,XX, 2, 4, 2, 4, 2, 2, 2, 2, 2, + /*1*/ 2,XX, 2,XX,XX, 2,XX, 2,XX,XX, 2, 2,XX,XX,XX,XX, + /*2*/ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + /*3*/ 4, 4, 4, 4, 4, 4, 4, 4,XX,XX, 5,10,XX, 9,XX,12, + /*4*/ 2, 2, 2,XX, 2, 2, 2, 3, 2, 2, 2, 2, 3, 3, 8, 4, + /*5*/ 3, 3, 3,XX, 3, 3, 3, 4, 3, 3, 3, 3, 4, 4, 6, 5, + /*6*/ 5, 5, 5,XX, 5, 5, 5, 6, 5, 5, 5, 5, 6, 6, 8, 7, + /*7*/ 4, 4, 4,XX, 4, 4, 4, 5, 4, 4, 4, 4, 5, 5, 9, 6, + /*8*/ 2,XX,XX, 2, 2, 2,XX, 2, 2, 2, 2,XX, 2,XX, 2, 2, + /*9*/ 2,XX,XX, 2, 2, 2,XX, 2, 2, 2, 2,XX, 2,XX, 2, 2, + /*A*/ 7,XX,XX, 7, 7, 7,XX, 7, 7, 7, 7,XX, 7, 4, 7, 7, + /*B*/ 6,XX,XX, 6, 6, 6,XX, 6, 6, 6, 6,XX, 6, 3, 6, 6, + /*C*/ 2, 2, 2,XX, 2, 2, 2, 3, 2, 2, 2, 2,XX, 3,XX, 4, + /*D*/ 3, 3, 3,XX, 3, 3, 3, 4, 3, 3, 3, 3,XX, 4,XX, 5, + /*E*/ 5, 5, 5,XX, 5, 5, 5, 6, 5, 5, 5, 5, 5, 6,XX, 7, + /*F*/ 4, 4, 4,XX, 4, 4, 4, 5, 4, 4, 4, 4, 4, 5,XX, 6 +}; +#undef XX // /invalid opcode unknown cc + +#define EAT_CYCLES \ +{ \ + int cycles_to_eat; \ + \ + cycles_to_eat = timer_next - CTD; \ + if( cycles_to_eat > m_icount) cycles_to_eat = m_icount; \ + if (cycles_to_eat > 0) \ + { \ + increment_counter(cycles_to_eat); \ + } \ +} + + +const device_type M6800 = &device_creator; +const device_type M6801 = &device_creator; +const device_type M6802 = &device_creator; +const device_type M6803 = &device_creator; +const device_type M6808 = &device_creator; +const device_type HD6301 = &device_creator; +const device_type HD63701 = &device_creator; +const device_type NSC8105 = &device_creator; +const device_type HD6303R = &device_creator; +const device_type HD6303Y = &device_creator; + + +m6800_cpu_device::m6800_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : cpu_device(mconfig, M6800, "M6800", tag, owner, clock, "m6800", __FILE__) + , m_program_config("program", ENDIANNESS_BIG, 8, 16, 0) + , m_decrypted_opcodes_config("program", ENDIANNESS_BIG, 8, 16, 0) + , m_io_config("io", ENDIANNESS_BIG, 8, 9, 0) + , m_has_io(false) + , m_out_sc2_func(*this) + , m_out_sertx_func(*this) + , m_insn(m6800_insn) + , m_cycles(cycles_6800) +{ + m_clock_divider = 1; +} + +m6800_cpu_device::m6800_cpu_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source, bool has_io, int clock_divider, const op_func *insn, const UINT8 *cycles, address_map_constructor internal) + : cpu_device(mconfig, type, name, tag, owner, clock, shortname, source) + , m_program_config("program", ENDIANNESS_BIG, 8, 16, 0, internal) + , m_decrypted_opcodes_config("program", ENDIANNESS_BIG, 8, 16, 0) + , m_io_config("io", ENDIANNESS_BIG, 8, 9, 0) + , m_has_io(has_io) + , m_out_sc2_func(*this) + , m_out_sertx_func(*this) + , m_insn(insn) + , m_cycles(cycles) +{ + m_clock_divider = clock_divider; +} + +m6801_cpu_device::m6801_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : m6800_cpu_device(mconfig, M6801, "M6801", tag, owner, clock, "m6801", __FILE__, true, 4, m6803_insn, cycles_6803) +{ +} + +m6801_cpu_device::m6801_cpu_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source, const op_func *insn, const UINT8 *cycles, address_map_constructor internal) + : m6800_cpu_device(mconfig, type, name, tag, owner, clock, shortname, source, true, 4, insn, cycles, internal) +{ +} + +m6802_cpu_device::m6802_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : m6800_cpu_device(mconfig, M6802, "M6802", tag, owner, clock, "m6802", __FILE__, false, 4, m6800_insn, cycles_6800) +{ +} + +m6802_cpu_device::m6802_cpu_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source, const op_func *insn, const UINT8 *cycles) + : m6800_cpu_device(mconfig, type, name, tag, owner, clock, shortname, source, false, 4, insn, cycles) +{ +} + +static ADDRESS_MAP_START(m6803_mem, AS_PROGRAM, 8, m6800_cpu_device) + AM_RANGE(0x0000, 0x001f) AM_READWRITE(m6801_io_r, m6801_io_w) + AM_RANGE(0x0020, 0x007f) AM_NOP /* unused */ + AM_RANGE(0x0080, 0x00ff) AM_RAM /* 6803 internal RAM */ +ADDRESS_MAP_END + + +m6803_cpu_device::m6803_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : m6801_cpu_device(mconfig, M6803, "M6803", tag, owner, clock, "m6803", __FILE__, m6803_insn, cycles_6803, ADDRESS_MAP_NAME(m6803_mem)) +{ +} + +m6808_cpu_device::m6808_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : m6802_cpu_device(mconfig, M6808, "M6808", tag, owner, clock, "m6808", __FILE__, m6800_insn, cycles_6800) +{ +} + +hd6301_cpu_device::hd6301_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : m6801_cpu_device(mconfig, HD6301, "HD6301", tag, owner, clock, "hd6301", __FILE__, hd63701_insn, cycles_63701) +{ +} + +hd6301_cpu_device::hd6301_cpu_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : m6801_cpu_device(mconfig, type, name, tag, owner, clock, shortname, source, hd63701_insn, cycles_63701) +{ +} + +hd63701_cpu_device::hd63701_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : m6801_cpu_device(mconfig, HD63701, "HD63701", tag, owner, clock, "hd63701", __FILE__, hd63701_insn, cycles_63701) +{ +} + +nsc8105_cpu_device::nsc8105_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : m6802_cpu_device(mconfig, NSC8105, "NSC8105", tag, owner, clock, "nsc8105", __FILE__, nsc8105_insn, cycles_nsc8105) +{ +} + +hd6303r_cpu_device::hd6303r_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : hd6301_cpu_device(mconfig, HD6303R, "HD6303R", tag, owner, clock, "hd6303r", __FILE__) +{ +} + +hd6303y_cpu_device::hd6303y_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : hd6301_cpu_device(mconfig, HD6303Y, "HD6303Y", tag, owner, clock, "hd6303y", __FILE__) +{ +} + +const address_space_config *m6800_cpu_device::memory_space_config(address_spacenum spacenum) const +{ + switch(spacenum) + { + case AS_PROGRAM: return &m_program_config; + case AS_IO: return m_has_io ? &m_io_config : NULL; + case AS_DECRYPTED_OPCODES: return has_configured_map(AS_DECRYPTED_OPCODES) ? &m_decrypted_opcodes_config : NULL; + default: return NULL; + } +} + + +UINT32 m6800_cpu_device::RM16(UINT32 Addr ) +{ + UINT32 result = RM(Addr) << 8; + return result | RM((Addr+1)&0xffff); +} + +void m6800_cpu_device::WM16(UINT32 Addr, PAIR *p ) +{ + WM( Addr, p->b.h ); + WM( (Addr+1)&0xffff, p->b.l ); +} + +/* IRQ enter */ +void m6800_cpu_device::enter_interrupt(const char *message,UINT16 irq_vector) +{ + LOG((message, tag())); + if( m_wai_state & (M6800_WAI|M6800_SLP) ) + { + if( m_wai_state & M6800_WAI ) + m_icount -= 4; + m_wai_state &= ~(M6800_WAI|M6800_SLP); + } + else + { + PUSHWORD(pPC); + PUSHWORD(pX); + PUSHBYTE(A); + PUSHBYTE(B); + PUSHBYTE(CC); + m_icount -= 12; + } + SEI; + PCD = RM16( irq_vector ); +} + + + +void m6800_cpu_device::m6800_check_irq2() +{ + if ((m_tcsr & (TCSR_EICI|TCSR_ICF)) == (TCSR_EICI|TCSR_ICF)) + { + TAKE_ICI; + standard_irq_callback(M6801_TIN_LINE); + } + else if ((m_tcsr & (TCSR_EOCI|TCSR_OCF)) == (TCSR_EOCI|TCSR_OCF)) + { + TAKE_OCI; + } + else if ((m_tcsr & (TCSR_ETOI|TCSR_TOF)) == (TCSR_ETOI|TCSR_TOF)) + { + TAKE_TOI; + } + else if (((m_trcsr & (M6800_TRCSR_RIE|M6800_TRCSR_RDRF)) == (M6800_TRCSR_RIE|M6800_TRCSR_RDRF)) || + ((m_trcsr & (M6800_TRCSR_RIE|M6800_TRCSR_ORFE)) == (M6800_TRCSR_RIE|M6800_TRCSR_ORFE)) || + ((m_trcsr & (M6800_TRCSR_TIE|M6800_TRCSR_TDRE)) == (M6800_TRCSR_TIE|M6800_TRCSR_TDRE))) + { + //logerror("M6800 '%s' SCI interrupt\n", tag()); + TAKE_SCI; + } +} + + +/* check the IRQ lines for pending interrupts */ +void m6800_cpu_device::CHECK_IRQ_LINES() +{ + // TODO: IS3 interrupt + + if (m_nmi_pending) + { + if(m_wai_state & M6800_SLP) + m_wai_state &= ~M6800_SLP; + + m_nmi_pending = FALSE; + enter_interrupt("M6800 '%s' take NMI\n",0xfffc); + } + else + { + if( m_irq_state[M6800_IRQ_LINE] != CLEAR_LINE ) + { /* standard IRQ */ + if(m_wai_state & M6800_SLP) + m_wai_state &= ~M6800_SLP; + + if( !(CC & 0x10) ) + { + enter_interrupt("M6800 '%s' take IRQ1\n",0xfff8); + standard_irq_callback(M6800_IRQ_LINE); + } + } + else + if( !(CC & 0x10) ) + m6800_check_irq2(); + } +} + +/* check OCI or TOI */ +void m6800_cpu_device::check_timer_event() +{ + /* OCI */ + if( CTD >= OCD) + { + OCH++; // next IRQ point + m_tcsr |= TCSR_OCF; + m_pending_tcsr |= TCSR_OCF; + MODIFIED_tcsr; + if((m_tcsr & TCSR_EOCI) && m_wai_state & M6800_SLP) + m_wai_state &= ~M6800_SLP; + if ( !(CC & 0x10) && (m_tcsr & TCSR_EOCI)) + TAKE_OCI; + + // if output on P21 is enabled, let's do it + if (m_port2_ddr & 2) + { + m_port2_data &= ~2; + m_port2_data |= (m_tcsr & TCSR_OLVL) << 1; + m_port2_written = 1; + write_port2(); + } + } + /* TOI */ + if( CTD >= TOD) + { + TOH++; // next IRQ point +#if 0 + CLEANUP_COUNTERS(); +#endif + m_tcsr |= TCSR_TOF; + m_pending_tcsr |= TCSR_TOF; + MODIFIED_tcsr; + if((m_tcsr & TCSR_ETOI) && m_wai_state & M6800_SLP) + m_wai_state &= ~M6800_SLP; + if ( !(CC & 0x10) && (m_tcsr & TCSR_ETOI)) + TAKE_TOI; + } + /* set next event */ + SET_TIMER_EVENT; +} + +void m6800_cpu_device::increment_counter(int amount) +{ + m_icount -= amount; + CTD += amount; + if( CTD >= timer_next) + check_timer_event(); +} + +void m6800_cpu_device::set_rmcr(UINT8 data) +{ + if (m_rmcr == data) return; + + m_rmcr = data; + + switch ((m_rmcr & M6800_RMCR_CC_MASK) >> 2) + { + case 0: + m_sci_timer->enable(false); + m_use_ext_serclock = false; + break; + + case 3: // external clock + m_use_ext_serclock = true; + m_sci_timer->enable(false); + break; + + case 1: + case 2: + { + int divisor = M6800_RMCR_SS[m_rmcr & M6800_RMCR_SS_MASK]; + int clock = m_clock / m_clock_divider; + + m_sci_timer->adjust(attotime::from_hz(clock / divisor), 0, attotime::from_hz(clock / divisor)); + m_use_ext_serclock = false; + } + break; + } +} + +void m6800_cpu_device::write_port2() +{ + if (!m_port2_written) return; + + UINT8 data = m_port2_data; + UINT8 ddr = m_port2_ddr & 0x1f; + + if ((ddr != 0x1f) && ddr) + { + data = (m_port2_data & ddr) | (ddr ^ 0xff); + } + + if (m_trcsr & M6800_TRCSR_TE) + { + data = (data & 0xef) | (m_tx << 4); + } + + data &= 0x1f; + + m_io->write_byte(M6801_PORT2, data); +} + +/* include the opcode prototypes and function pointer tables */ +#include "6800tbl.inc" + +/* include the opcode functions */ +#include "6800ops.inc" + +int m6800_cpu_device::m6800_rx() +{ + return (m_io->read_byte(M6801_PORT2) & M6800_PORT2_IO3) >> 3; +} + +void m6800_cpu_device::serial_transmit() +{ + //logerror("M6800 '%s' Tx Tick\n", tag()); + + if (m_trcsr & M6800_TRCSR_TE) + { + // force Port 2 bit 4 as output + m_port2_ddr |= M6800_PORT2_IO4; + + switch (m_txstate) + { + case M6800_TX_STATE_INIT: + m_tx = 1; + m_txbits++; + + if (m_txbits == 10) + { + m_txstate = M6800_TX_STATE_READY; + m_txbits = M6800_SERIAL_START; + } + break; + + case M6800_TX_STATE_READY: + switch (m_txbits) + { + case M6800_SERIAL_START: + if (m_trcsr & M6800_TRCSR_TDRE) + { + // transmit buffer is empty, send nothing + return; + } + else + { + // transmit buffer is full, send data + + // load TDR to shift register + m_tsr = m_tdr; + + // transmit buffer is empty, set TDRE flag + m_trcsr |= M6800_TRCSR_TDRE; + + // send start bit '0' + m_tx = 0; + + m_txbits++; + + //logerror("M6800 '%s' Transmit START Data %02x\n", tag(), m_tsr); + } + break; + + case M6800_SERIAL_STOP: + // send stop bit '1' + m_tx = 1; + + CHECK_IRQ_LINES(); + + m_txbits = M6800_SERIAL_START; + + //logerror("M6800 '%s' Transmit STOP\n", tag()); + break; + + default: + // send data bit '0' or '1' + m_tx = m_tsr & 0x01; + + // shift transmit register + m_tsr >>= 1; + + //logerror("M6800 '%s' Transmit Bit %u: %u\n", tag(), m_txbits, m_tx); + + m_txbits++; + break; + } + break; + } + + m_out_sertx_func((m_tx == 1) ? ASSERT_LINE : CLEAR_LINE); + m_port2_written = 1; + write_port2(); + } +} + +void m6800_cpu_device::serial_receive() +{ + //logerror("M6800 '%s' Rx Tick TRCSR %02x bits %u check %02x\n", tag(), m_trcsr, m_rxbits, m_trcsr & M6800_TRCSR_RE); + + if (m_trcsr & M6800_TRCSR_RE) + { + if (m_trcsr & M6800_TRCSR_WU) + { + // wait for 10 bits of '1' + if (m6800_rx() == 1) + { + m_rxbits++; + + //logerror("M6800 '%s' Received WAKE UP bit %u\n", tag(), m_rxbits); + + if (m_rxbits == 10) + { + //logerror("M6800 '%s' Receiver Wake Up\n", tag()); + + m_trcsr &= ~M6800_TRCSR_WU; + m_rxbits = M6800_SERIAL_START; + } + } + else + { + //logerror("M6800 '%s' Receiver Wake Up interrupted\n", tag()); + + m_rxbits = M6800_SERIAL_START; + } + } + else + { + // receive data + switch (m_rxbits) + { + case M6800_SERIAL_START: + if (m6800_rx() == 0) + { + // start bit found + m_rxbits++; + + //logerror("M6800 '%s' Received START bit\n", tag()); + } + break; + + case M6800_SERIAL_STOP: + if (m6800_rx() == 1) + { + //logerror("M6800 '%s' Received STOP bit\n", tag()); + + if (m_trcsr & M6800_TRCSR_RDRF) + { + // overrun error + m_trcsr |= M6800_TRCSR_ORFE; + + //logerror("M6800 '%s' Receive Overrun Error\n", tag()); + + CHECK_IRQ_LINES(); + } + else + { + if (!(m_trcsr & M6800_TRCSR_ORFE)) + { + // transfer data into receive register + m_rdr = m_rsr; + + //logerror("M6800 '%s' Receive Data Register: %02x\n", tag(), m_rdr); + + // set RDRF flag + m_trcsr |= M6800_TRCSR_RDRF; + + CHECK_IRQ_LINES(); + } + } + } + else + { + // framing error + if (!(m_trcsr & M6800_TRCSR_ORFE)) + { + // transfer unframed data into receive register + m_rdr = m_rsr; + } + + m_trcsr |= M6800_TRCSR_ORFE; + m_trcsr &= ~M6800_TRCSR_RDRF; + + //logerror("M6800 '%s' Receive Framing Error\n", tag()); + + CHECK_IRQ_LINES(); + } + + m_rxbits = M6800_SERIAL_START; + break; + + default: + // shift receive register + m_rsr >>= 1; + + // receive bit into register + m_rsr |= (m6800_rx() << 7); + + //logerror("M6800 '%s' Received DATA bit %u: %u\n", tag(), m_rxbits, BIT(m_rsr, 7)); + + m_rxbits++; + break; + } + } + } +} + +TIMER_CALLBACK_MEMBER( m6800_cpu_device::sci_tick ) +{ + serial_transmit(); + serial_receive(); +} + + +void m6800_cpu_device::device_start() +{ + m_program = &space(AS_PROGRAM); + m_direct = &m_program->direct(); + m_decrypted_opcodes = has_space(AS_DECRYPTED_OPCODES) ? &space(AS_DECRYPTED_OPCODES) : m_program; + m_decrypted_opcodes_direct = &m_decrypted_opcodes->direct(); + if ( m_has_io ) + m_io = &space(AS_IO); + + m_out_sc2_func.resolve_safe(); + m_out_sertx_func.resolve_safe(); + m_sci_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(m6800_cpu_device::sci_tick),this)); + + m_port4_ddr = 0; + m_port4_data = 0; + m_input_capture = 0; + m_rdr = 0; + m_tdr = 0; + m_rmcr = 0; + m_ram_ctrl = 0; + + m_pc.d = 0; + m_s.d = 0; + m_x.d = 0; + m_d.d = 0; + m_cc = 0; + m_wai_state = 0; + m_irq_state[0] = m_irq_state[1] = m_irq_state[2] = 0; + + save_item(NAME(m_ppc.w.l)); + save_item(NAME(m_pc.w.l)); + save_item(NAME(m_s.w.l)); + save_item(NAME(m_x.w.l)); + save_item(NAME(m_d.w.l)); + save_item(NAME(m_cc)); + save_item(NAME(m_wai_state)); + save_item(NAME(m_nmi_state)); + save_item(NAME(m_nmi_pending)); + save_item(NAME(m_irq_state)); + save_item(NAME(m_ic_eddge)); + + save_item(NAME(m_port1_ddr)); + save_item(NAME(m_port2_ddr)); + save_item(NAME(m_port3_ddr)); + save_item(NAME(m_port4_ddr)); + save_item(NAME(m_port1_data)); + save_item(NAME(m_port2_data)); + save_item(NAME(m_port3_data)); + save_item(NAME(m_port4_data)); + save_item(NAME(m_port2_written)); + save_item(NAME(m_port3_latched)); + save_item(NAME(m_p3csr)); + save_item(NAME(m_p3csr_is3_flag_read)); + save_item(NAME(m_tcsr)); + save_item(NAME(m_pending_tcsr)); + save_item(NAME(m_irq2)); + save_item(NAME(m_ram_ctrl)); + + save_item(NAME(m_counter.d)); + save_item(NAME(m_output_compare.d)); + save_item(NAME(m_input_capture)); + save_item(NAME(m_timer_over.d)); + + save_item(NAME(m_clock_divider)); + save_item(NAME(m_trcsr)); + save_item(NAME(m_rmcr)); + save_item(NAME(m_rdr)); + save_item(NAME(m_tdr)); + save_item(NAME(m_rsr)); + save_item(NAME(m_tsr)); + save_item(NAME(m_rxbits)); + save_item(NAME(m_txbits)); + save_item(NAME(m_txstate)); + save_item(NAME(m_trcsr_read_tdre)); + save_item(NAME(m_trcsr_read_orfe)); + save_item(NAME(m_trcsr_read_rdrf)); + save_item(NAME(m_tx)); + + state_add( M6800_A, "A", m_d.b.h).formatstr("%02X"); + state_add( M6800_B, "B", m_d.b.l).formatstr("%02X"); + state_add( M6800_PC, "PC", m_pc.w.l).formatstr("%04X"); + state_add( M6800_S, "S", m_s.w.l).formatstr("%04X"); + state_add( M6800_X, "X", m_x.w.l).formatstr("%04X"); + state_add( M6800_CC, "CC", m_cc).formatstr("%02X"); + state_add( M6800_WAI_STATE, "WAI", m_wai_state).formatstr("%01X"); + + state_add( STATE_GENPC, "GENPC", m_pc.w.l).noshow(); + state_add( STATE_GENFLAGS, "GENFLAGS", m_cc).formatstr("%8s").noshow(); + + m_icountptr = &m_icount; +} + +void m6800_cpu_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + switch (entry.index()) + { + case STATE_GENFLAGS: + strprintf(str, "%c%c%c%c%c%c%c%c", + m_cc & 0x80 ? '?':'.', + m_cc & 0x40 ? '?':'.', + m_cc & 0x20 ? 'H':'.', + m_cc & 0x10 ? 'I':'.', + m_cc & 0x08 ? 'N':'.', + m_cc & 0x04 ? 'Z':'.', + m_cc & 0x02 ? 'V':'.', + m_cc & 0x01 ? 'C':'.'); + break; + } +} + +void m6800_cpu_device::device_reset() +{ + m_cc = 0xc0; + SEI; /* IRQ disabled */ + PCD = RM16( 0xfffe ); + + m_wai_state = 0; + m_nmi_state = 0; + m_nmi_pending = 0; + m_sc1_state = 0; + m_irq_state[M6800_IRQ_LINE] = 0; + m_irq_state[M6801_TIN_LINE] = 0; + m_ic_eddge = 0; + + m_port1_ddr = 0x00; + m_port2_ddr = 0x00; + m_port3_ddr = 0x00; + m_port1_data = 0; + m_p3csr = 0x00; + m_p3csr_is3_flag_read = 0; + m_port2_written = 0; + m_port3_latched = 0; + /* TODO: on reset port 2 should be read to determine the operating mode (bits 0-2) */ + m_tcsr = 0x00; + m_pending_tcsr = 0x00; + m_irq2 = 0; + CTD = 0x0000; + OCD = 0xffff; + TOD = 0xffff; + m_ram_ctrl |= 0x40; + m_latch09 = 0; + + m_trcsr = M6800_TRCSR_TDRE; + + m_txstate = M6800_TX_STATE_INIT; + m_txbits = m_rxbits = 0; + m_tx = 1; + m_trcsr_read_tdre = 0; + m_trcsr_read_orfe = 0; + m_trcsr_read_rdrf = 0; + m_ext_serclock = 0; + m_use_ext_serclock = false; + + set_rmcr(0); +} + + +void m6800_cpu_device::execute_set_input(int irqline, int state) +{ + switch (irqline) + { + case INPUT_LINE_NMI: + if (!m_nmi_state && state != CLEAR_LINE) + m_nmi_pending = TRUE; + m_nmi_state = state; + break; + + case M6801_SC1_LINE: + if (!m_port3_latched && (m_p3csr & M6801_P3CSR_LE)) + { + if (!m_sc1_state && state) + { + // latch input data to port 3 + m_port3_data = (m_io->read_byte(M6801_PORT3) & (m_port3_ddr ^ 0xff)) | (m_port3_data & m_port3_ddr); + m_port3_latched = 1; + //logerror("M6801 '%s' Latched Port 3 Data: %02x\n", tag(), m_port3_data); + + // set IS3 flag bit + m_p3csr |= M6801_P3CSR_IS3_FLAG; + } + } + m_sc1_state = state; + break; + + default: + LOG(("M6800 '%s' set_irq_line %d,%d\n", tag(), irqline, state)); + m_irq_state[irqline] = state; + + if (irqline == M6801_TIN_LINE && state != m_irq_state[irqline]) + { + //eddge = (state == CLEAR_LINE ) ? 2 : 0; + if( ((m_tcsr&TCSR_IEDG) ^ (state==CLEAR_LINE ? TCSR_IEDG : 0))==0 ) + return; + /* active edge in */ + m_tcsr |= TCSR_ICF; + m_pending_tcsr |= TCSR_ICF; + m_input_capture = CT; + MODIFIED_tcsr; + } + } +} + +/**************************************************************************** + * Execute cycles CPU cycles. Return number of cycles really executed + ****************************************************************************/ +void m6800_cpu_device::execute_run() +{ + UINT8 ireg; + + CHECK_IRQ_LINES(); /* HJB 990417 */ + + CLEANUP_COUNTERS(); + + do + { + if( m_wai_state & (M6800_WAI|M6800_SLP) ) + { + EAT_CYCLES; + } + else + { + pPPC = pPC; + debugger_instruction_hook(this, PCD); + ireg=M_RDOP(PCD); + PC++; + (this->*m_insn[ireg])(); + increment_counter(m_cycles[ireg]); + } + } while( m_icount>0 ); +} + + +/* + if change_pc() direccted these areas ,Call hd63701_trap_pc(). + 'mode' is selected by the sense of p2.0,p2.1,and p2.3 at reset timming. + mode 0,1,2,4,6 : $0000-$001f + mode 5 : $0000-$001f,$0200-$efff + mode 7 : $0000-$001f,$0100-$efff +*/ +#if 0 +void m6800_cpu_device::hd63701_trap_pc() +{ + TAKE_TRAP; +} +#endif + +void m6800_cpu_device::set_os3(int state) +{ + //logerror("M6801 '%s' OS3: %u\n", tag(), state); + + m_out_sc2_func(state); +} + +READ8_MEMBER( m6800_cpu_device::m6801_io_r ) +{ + UINT8 data = 0; + + switch (offset) + { + case IO_P1DDR: + data = m_port1_ddr; + break; + + case IO_P2DDR: + data = m_port2_ddr; + break; + + case IO_P1DATA: + if(m_port1_ddr == 0xff) + data = m_port1_data; + else + data = (m_io->read_byte(M6801_PORT1) & (m_port1_ddr ^ 0xff)) + | (m_port1_data & m_port1_ddr); + break; + + case IO_P2DATA: + if(m_port2_ddr == 0xff) + data = m_port2_data; + else + data = (m_io->read_byte(M6801_PORT2) & (m_port2_ddr ^ 0xff)) + | (m_port2_data & m_port2_ddr); + break; + + case IO_P3DDR: + logerror("M6801 '%s' Port 3 DDR is a write-only register\n", space.device().tag()); + break; + + case IO_P4DDR: + data = m_port4_ddr; + break; + + case IO_P3DATA: + if (!space.debugger_access()) + { + if (m_p3csr_is3_flag_read) + { + //logerror("M6801 '%s' Cleared IS3\n", space.device().tag()); + m_p3csr &= ~M6801_P3CSR_IS3_FLAG; + m_p3csr_is3_flag_read = 0; + } + + if (!(m_p3csr & M6801_P3CSR_OSS)) + { + set_os3(ASSERT_LINE); + } + } + + if ((m_p3csr & M6801_P3CSR_LE) || (m_port3_ddr == 0xff)) + data = m_port3_data; + else + data = (m_io->read_byte(M6801_PORT3) & (m_port3_ddr ^ 0xff)) + | (m_port3_data & m_port3_ddr); + + if (!space.debugger_access()) + { + m_port3_latched = 0; + + if (!(m_p3csr & M6801_P3CSR_OSS)) + { + set_os3(CLEAR_LINE); + } + } + break; + + case IO_P4DATA: + if(m_port4_ddr == 0xff) + data = m_port4_data; + else + data = (m_io->read_byte(M6801_PORT4) & (m_port4_ddr ^ 0xff)) + | (m_port4_data & m_port4_ddr); + break; + + case IO_TCSR: + m_pending_tcsr = 0; + data = m_tcsr; + break; + + case IO_CH: + if(!(m_pending_tcsr&TCSR_TOF) && !space.debugger_access()) + { + m_tcsr &= ~TCSR_TOF; + MODIFIED_tcsr; + } + data = m_counter.b.h; + break; + + case IO_CL: + data = m_counter.b.l; + // HACK there should be a break here, but Coleco Adam won't boot with it present, proper fix required to the free-running counter + + case IO_OCRH: + if(!(m_pending_tcsr&TCSR_OCF) && !space.debugger_access()) + { + m_tcsr &= ~TCSR_OCF; + MODIFIED_tcsr; + } + data = m_output_compare.b.h; + break; + + case IO_OCRL: + if(!(m_pending_tcsr&TCSR_OCF) && !space.debugger_access()) + { + m_tcsr &= ~TCSR_OCF; + MODIFIED_tcsr; + } + data = m_output_compare.b.l; + break; + + case IO_ICRH: + if(!(m_pending_tcsr&TCSR_ICF) && !space.debugger_access()) + { + m_tcsr &= ~TCSR_ICF; + MODIFIED_tcsr; + } + data = (m_input_capture >> 0) & 0xff; + break; + + case IO_ICRL: + data = (m_input_capture >> 8) & 0xff; + break; + + case IO_P3CSR: + if ((m_p3csr & M6801_P3CSR_IS3_FLAG) && !space.debugger_access()) + { + m_p3csr_is3_flag_read = 1; + } + + data = m_p3csr; + break; + + case IO_RMCR: + data = m_rmcr; + break; + + case IO_TRCSR: + if (!space.debugger_access()) + { + if (m_trcsr & M6800_TRCSR_TDRE) + { + m_trcsr_read_tdre = 1; + } + + if (m_trcsr & M6800_TRCSR_ORFE) + { + m_trcsr_read_orfe = 1; + } + + if (m_trcsr & M6800_TRCSR_RDRF) + { + m_trcsr_read_rdrf = 1; + } + } + + data = m_trcsr; + break; + + case IO_RDR: + if (!space.debugger_access()) + { + if (m_trcsr_read_orfe) + { + //logerror("M6801 '%s' Cleared ORFE\n", space.device().tag()); + m_trcsr_read_orfe = 0; + m_trcsr &= ~M6800_TRCSR_ORFE; + } + + if (m_trcsr_read_rdrf) + { + //logerror("M6801 '%s' Cleared RDRF\n", space.device().tag()); + m_trcsr_read_rdrf = 0; + m_trcsr &= ~M6800_TRCSR_RDRF; + } + } + + data = m_rdr; + break; + + case IO_TDR: + data = m_tdr; + break; + + case IO_RCR: + data = m_ram_ctrl; + break; + + case IO_CAAH: + case IO_CAAL: + case IO_TCR1: + case IO_TCR2: + case IO_TSR: + case IO_OCR2H: + case IO_OCR2L: + case IO_OCR3H: + case IO_OCR3L: + case IO_ICR2H: + case IO_ICR2L: + default: + logerror("M6801 '%s' PC %04x: warning - read from reserved internal register %02x\n",space.device().tag(),space.device().safe_pc(),offset); + } + + return data; +} + +WRITE8_MEMBER( m6800_cpu_device::m6801_io_w ) +{ + switch (offset) + { + case IO_P1DDR: + //logerror("M6801 '%s' Port 1 Data Direction Register: %02x\n", space.device().tag(), data); + + if (m_port1_ddr != data) + { + m_port1_ddr = data; + if(m_port1_ddr == 0xff) + m_io->write_byte(M6801_PORT1,m_port1_data); + else + m_io->write_byte(M6801_PORT1,(m_port1_data & m_port1_ddr) | (m_port1_ddr ^ 0xff)); + } + break; + + case IO_P2DDR: + //logerror("M6801 '%s' Port 2 Data Direction Register: %02x\n", space.device().tag(), data); + + if (m_port2_ddr != data) + { + m_port2_ddr = data; + write_port2(); + } + break; + + case IO_P1DATA: + //logerror("M6801 '%s' Port 1 Data Register: %02x\n", space.device().tag(), data); + + m_port1_data = data; + if(m_port1_ddr == 0xff) + m_io->write_byte(M6801_PORT1,m_port1_data); + else + m_io->write_byte(M6801_PORT1,(m_port1_data & m_port1_ddr) | (m_port1_ddr ^ 0xff)); + break; + + case IO_P2DATA: + //logerror("M6801 '%s' Port 2 Data Register: %02x\n", space.device().tag(), data); + + m_port2_data = data; + m_port2_written = 1; + write_port2(); + break; + + case IO_P3DDR: + //logerror("M6801 '%s' Port 3 Data Direction Register: %02x\n", space.device().tag(), data); + + if (m_port3_ddr != data) + { + m_port3_ddr = data; + if(m_port3_ddr == 0xff) + m_io->write_byte(M6801_PORT3,m_port3_data); + else + m_io->write_byte(M6801_PORT3,(m_port3_data & m_port3_ddr) | (m_port3_ddr ^ 0xff)); + } + break; + + case IO_P4DDR: + //logerror("M6801 '%s' Port 4 Data Direction Register: %02x\n", space.device().tag(), data); + + if (m_port4_ddr != data) + { + m_port4_ddr = data; + if(m_port4_ddr == 0xff) + m_io->write_byte(M6801_PORT4,m_port4_data); + else + m_io->write_byte(M6801_PORT4,(m_port4_data & m_port4_ddr) | (m_port4_ddr ^ 0xff)); + } + break; + + case IO_P3DATA: + //logerror("M6801 '%s' Port 3 Data Register: %02x\n", space.device().tag(), data); + + if (m_p3csr_is3_flag_read) + { + //logerror("M6801 '%s' Cleared IS3\n", space.device().tag()); + m_p3csr &= ~M6801_P3CSR_IS3_FLAG; + m_p3csr_is3_flag_read = 0; + } + + if (m_p3csr & M6801_P3CSR_OSS) + { + set_os3(ASSERT_LINE); + } + + m_port3_data = data; + if(m_port3_ddr == 0xff) + m_io->write_byte(M6801_PORT3,m_port3_data); + else + m_io->write_byte(M6801_PORT3,(m_port3_data & m_port3_ddr) | (m_port3_ddr ^ 0xff)); + + if (m_p3csr & M6801_P3CSR_OSS) + { + set_os3(CLEAR_LINE); + } + break; + + case IO_P4DATA: + //logerror("M6801 '%s' Port 4 Data Register: %02x\n", space.device().tag(), data); + + m_port4_data = data; + if(m_port4_ddr == 0xff) + m_io->write_byte(M6801_PORT4,m_port4_data); + else + m_io->write_byte(M6801_PORT4,(m_port4_data & m_port4_ddr) | (m_port4_ddr ^ 0xff)); + break; + + case IO_TCSR: + //logerror("M6801 '%s' Timer Control and Status Register: %02x\n", space.device().tag(), data); + + m_tcsr = data; + m_pending_tcsr &= m_tcsr; + MODIFIED_tcsr; + if( !(CC & 0x10) ) + m6800_check_irq2(); + break; + + case IO_CH: + //logerror("M6801 '%s' Counter High Register: %02x\n", space.device().tag(), data); + + m_latch09 = data & 0xff; /* 6301 only */ + CT = 0xfff8; + TOH = CTH; + MODIFIED_counters; + break; + + case IO_CL: /* 6301 only */ + //logerror("M6801 '%s' Counter Low Register: %02x\n", space.device().tag(), data); + + CT = (m_latch09 << 8) | (data & 0xff); + TOH = CTH; + MODIFIED_counters; + break; + + case IO_OCRH: + //logerror("M6801 '%s' Output Compare High Register: %02x\n", space.device().tag(), data); + + if( m_output_compare.b.h != data) + { + m_output_compare.b.h = data; + MODIFIED_counters; + } + break; + + case IO_OCRL: + //logerror("M6801 '%s' Output Compare Low Register: %02x\n", space.device().tag(), data); + + if( m_output_compare.b.l != data) + { + m_output_compare.b.l = data; + MODIFIED_counters; + } + break; + + case IO_ICRH: + case IO_ICRL: + case IO_RDR: + //logerror("CPU '%s' PC %04x: warning - write %02x to read only internal register %02x\n",space.device().tag(),space.device().safe_pc(),data,offset); + break; + + case IO_P3CSR: + //logerror("M6801 '%s' Port 3 Control and Status Register: %02x\n", space.device().tag(), data); + + m_p3csr = data; + break; + + case IO_RMCR: + //logerror("M6801 '%s' Rate and Mode Control Register: %02x\n", space.device().tag(), data); + + set_rmcr(data); + break; + + case IO_TRCSR: + //logerror("M6801 '%s' Transmit/Receive Control and Status Register: %02x\n", space.device().tag(), data); + + if ((data & M6800_TRCSR_TE) && !(m_trcsr & M6800_TRCSR_TE)) + { + m_txstate = M6800_TX_STATE_INIT; + m_txbits = 0; + m_tx = 1; + } + + if ((data & M6800_TRCSR_RE) && !(m_trcsr & M6800_TRCSR_RE)) + { + m_rxbits = 0; + } + + m_trcsr = (m_trcsr & 0xe0) | (data & 0x1f); + break; + + case IO_TDR: + //logerror("M6800 '%s' Transmit Data Register: %02x\n", space.device().tag(), data); + + if (m_trcsr_read_tdre) + { + m_trcsr_read_tdre = 0; + m_trcsr &= ~M6800_TRCSR_TDRE; + } + m_tdr = data; + break; + + case IO_RCR: + //logerror("M6801 '%s' RAM Control Register: %02x\n", space.device().tag(), data); + + m_ram_ctrl = data; + break; + + case IO_CAAH: + case IO_CAAL: + case IO_TCR1: + case IO_TCR2: + case IO_TSR: + case IO_OCR2H: + case IO_OCR2L: + case IO_OCR3H: + case IO_OCR3L: + case IO_ICR2H: + case IO_ICR2L: + default: + logerror("M6801 '%s' PC %04x: warning - write %02x to reserved internal register %02x\n",space.device().tag(),space.device().safe_pc(),data,offset); + break; + } +} + +void m6801_cpu_device::m6801_clock_serial() +{ + if (m_use_ext_serclock) + { + m_ext_serclock++; + + if (m_ext_serclock >= 8) + { + m_ext_serclock = 0; + serial_transmit(); + serial_receive(); + } + } +} + +offs_t m6800_cpu_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( m6800 ); + return CPU_DISASSEMBLE_NAME(m6800)(this, buffer, pc, oprom, opram, options); +} + + +offs_t m6801_cpu_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( m6801 ); + return CPU_DISASSEMBLE_NAME(m6801)(this, buffer, pc, oprom, opram, options); +} + + +offs_t m6802_cpu_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( m6802 ); + return CPU_DISASSEMBLE_NAME(m6802)(this, buffer, pc, oprom, opram, options); +} + + +offs_t m6803_cpu_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( m6803 ); + return CPU_DISASSEMBLE_NAME(m6803)(this, buffer, pc, oprom, opram, options); +} + + +offs_t m6808_cpu_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( m6808 ); + return CPU_DISASSEMBLE_NAME(m6808)(this, buffer, pc, oprom, opram, options); +} + + +offs_t hd6301_cpu_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( hd6301 ); + return CPU_DISASSEMBLE_NAME(hd6301)(this, buffer, pc, oprom, opram, options); +} + + +offs_t hd63701_cpu_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( hd63701 ); + return CPU_DISASSEMBLE_NAME(hd63701)(this, buffer, pc, oprom, opram, options); +} + + +offs_t nsc8105_cpu_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( nsc8105 ); + return CPU_DISASSEMBLE_NAME(nsc8105)(this, buffer, pc, oprom, opram, options); +} + +WRITE_LINE_MEMBER( m6800_cpu_device::irq_line ) +{ + set_input_line( M6800_IRQ_LINE, state ); +} + +WRITE_LINE_MEMBER( m6800_cpu_device::nmi_line ) +{ + set_input_line( INPUT_LINE_NMI, state ); +} diff --git a/src/devices/cpu/m6800/m6800.h b/src/devices/cpu/m6800/m6800.h new file mode 100644 index 00000000000..af02be492d8 --- /dev/null +++ b/src/devices/cpu/m6800/m6800.h @@ -0,0 +1,545 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*** m6800: Portable 6800 class emulator *************************************/ + +#pragma once + +#ifndef __M6800_H__ +#define __M6800_H__ + + +enum +{ + M6800_PC=1, M6800_S, M6800_A, M6800_B, M6800_X, M6800_CC, + M6800_WAI_STATE +}; + +enum +{ + M6800_IRQ_LINE = 0, /* IRQ line number */ + M6801_TIN_LINE, /* P20/Tin Input Capture line (eddge sense) */ + /* Active eddge is selecrable by internal reg. */ + /* raise eddge : CLEAR_LINE -> ASSERT_LINE */ + /* fall eddge : ASSERT_LINE -> CLEAR_LINE */ + /* it is usuali to use PULSE_LINE state */ + M6801_SC1_LINE +}; + +enum +{ + M6801_MODE_0 = 0, + M6801_MODE_1, + M6801_MODE_2, + M6801_MODE_3, + M6801_MODE_4, + M6801_MODE_5, + M6801_MODE_6, + M6801_MODE_7 +}; + +enum +{ + M6801_PORT1 = 0x100, + M6801_PORT2, + M6801_PORT3, + M6801_PORT4 +}; + + +#define MCFG_M6801_SC2(_devcb) \ + m6800_cpu_device::set_out_sc2_func(*device, DEVCB_##_devcb); +#define MCFG_M6801_SER_TX(_devcb) \ + m6800_cpu_device::set_out_sertx_func(*device, DEVCB_##_devcb); + +class m6800_cpu_device : public cpu_device +{ +public: + typedef void (m6800_cpu_device::*op_func)(); + + // construction/destruction + m6800_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + m6800_cpu_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source, bool has_io, int clock_divider, const m6800_cpu_device::op_func *insn, const UINT8 *cycles, address_map_constructor internal = NULL); + + // static configuration helpers + template static devcb_base &set_out_sc2_func(device_t &device, _Object object) { return downcast(device).m_out_sc2_func.set_callback(object); } + template static devcb_base &set_out_sertx_func(device_t &device, _Object object) { return downcast(device).m_out_sertx_func.set_callback(object); } + + DECLARE_READ8_MEMBER( m6801_io_r ); + DECLARE_WRITE8_MEMBER( m6801_io_w ); + + DECLARE_WRITE_LINE_MEMBER( irq_line ); + DECLARE_WRITE_LINE_MEMBER( nmi_line ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_execute_interface overrides + virtual UINT32 execute_min_cycles() const { return 1; } + virtual UINT32 execute_max_cycles() const { return 12; } + virtual UINT32 execute_input_lines() const { return 2; } + virtual UINT32 execute_default_irq_vector() const { return 0; } + virtual void execute_run(); + virtual void execute_set_input(int inputnum, int state); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const; + + // device_state_interface overrides + void state_string_export(const device_state_entry &entry, std::string &str); + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const { return 1; } + virtual UINT32 disasm_max_opcode_bytes() const { return 4; } + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + + address_space_config m_program_config; + address_space_config m_decrypted_opcodes_config; + address_space_config m_io_config; + bool m_has_io; + + devcb_write_line m_out_sc2_func; + devcb_write_line m_out_sertx_func; + + PAIR m_ppc; /* Previous program counter */ + PAIR m_pc; /* Program counter */ + PAIR m_s; /* Stack pointer */ + PAIR m_x; /* Index register */ + PAIR m_d; /* Accumulators */ + UINT8 m_cc; /* Condition codes */ + UINT8 m_wai_state; /* WAI opcode state ,(or sleep opcode state) */ + UINT8 m_nmi_state; /* NMI line state */ + UINT8 m_nmi_pending; /* NMI pending */ + UINT8 m_irq_state[3]; /* IRQ line state [IRQ1,TIN,SC1] */ + UINT8 m_ic_eddge; /* InputCapture eddge , b.0=fall,b.1=raise */ + int m_sc1_state; + + /* Memory spaces */ + address_space *m_program, *m_decrypted_opcodes; + direct_read_data *m_direct, *m_decrypted_opcodes_direct; + address_space *m_io; + + const op_func *m_insn; + const UINT8 *m_cycles; /* clock cycle of instruction table */ + /* internal registers */ + UINT8 m_port1_ddr; + UINT8 m_port2_ddr; + UINT8 m_port3_ddr; + UINT8 m_port4_ddr; + UINT8 m_port1_data; + UINT8 m_port2_data; + UINT8 m_port3_data; + UINT8 m_port4_data; + UINT8 m_p3csr; // Port 3 Control/Status Register + UINT8 m_tcsr; /* Timer Control and Status Register */ + UINT8 m_pending_tcsr; /* pending IRQ flag for clear IRQflag process */ + UINT8 m_irq2; /* IRQ2 flags */ + UINT8 m_ram_ctrl; + PAIR m_counter; /* free running counter */ + PAIR m_output_compare; /* output compare */ + UINT16 m_input_capture; /* input capture */ + int m_p3csr_is3_flag_read; + int m_port3_latched; + + int m_clock_divider; + UINT8 m_trcsr, m_rmcr, m_rdr, m_tdr, m_rsr, m_tsr; + int m_rxbits, m_txbits, m_txstate, m_trcsr_read_tdre, m_trcsr_read_orfe, m_trcsr_read_rdrf, m_tx, m_ext_serclock; + bool m_use_ext_serclock; + int m_port2_written; + + int m_icount; + int m_latch09; + + PAIR m_timer_over; + emu_timer *m_sci_timer; + PAIR m_ea; /* effective address */ + + static const UINT8 flags8i[256]; + static const UINT8 flags8d[256]; + static const UINT8 cycles_6800[256]; + static const UINT8 cycles_6803[256]; + static const UINT8 cycles_63701[256]; + static const UINT8 cycles_nsc8105[256]; + static const op_func m6800_insn[256]; + static const op_func m6803_insn[256]; + static const op_func hd63701_insn[256]; + static const op_func nsc8105_insn[256]; + + UINT32 RM16(UINT32 Addr ); + void WM16(UINT32 Addr, PAIR *p ); + void enter_interrupt(const char *message,UINT16 irq_vector); + void m6800_check_irq2(); + void CHECK_IRQ_LINES(); + void check_timer_event(); + void increment_counter(int amount); + void set_rmcr(UINT8 data); + void write_port2(); + int m6800_rx(); + void serial_transmit(); + void serial_receive(); + TIMER_CALLBACK_MEMBER( sci_tick ); + void set_os3(int state); + + void aba(); + void abx(); + void adca_di(); + void adca_ex(); + void adca_im(); + void adca_ix(); + void adcb_di(); + void adcb_ex(); + void adcb_im(); + void adcb_ix(); + void adcx_im(); + void adda_di(); + void adda_ex(); + void adda_im(); + void adda_ix(); + void addb_di(); + void addb_ex(); + void addb_im(); + void addb_ix(); + void addd_di(); + void addd_ex(); + void addx_ex(); + void addd_im(); + void addd_ix(); + void aim_di(); + void aim_ix(); + void anda_di(); + void anda_ex(); + void anda_im(); + void anda_ix(); + void andb_di(); + void andb_ex(); + void andb_im(); + void andb_ix(); + void asl_ex(); + void asl_ix(); + void asla(); + void aslb(); + void asld(); + void asr_ex(); + void asr_ix(); + void asra(); + void asrb(); + void bcc(); + void bcs(); + void beq(); + void bge(); + void bgt(); + void bhi(); + void bita_di(); + void bita_ex(); + void bita_im(); + void bita_ix(); + void bitb_di(); + void bitb_ex(); + void bitb_im(); + void bitb_ix(); + void ble(); + void bls(); + void blt(); + void bmi(); + void bne(); + void bpl(); + void bra(); + void brn(); + void bsr(); + void bvc(); + void bvs(); + void cba(); + void clc(); + void cli(); + void clr_ex(); + void clr_ix(); + void clra(); + void clrb(); + void clv(); + void cmpa_di(); + void cmpa_ex(); + void cmpa_im(); + void cmpa_ix(); + void cmpb_di(); + void cmpb_ex(); + void cmpb_im(); + void cmpb_ix(); + void cmpx_di(); + void cmpx_ex(); + void cmpx_im(); + void cmpx_ix(); + void com_ex(); + void com_ix(); + void coma(); + void comb(); + void daa(); + void dec_ex(); + void dec_ix(); + void deca(); + void decb(); + void des(); + void dex(); + void eim_di(); + void eim_ix(); + void eora_di(); + void eora_ex(); + void eora_im(); + void eora_ix(); + void eorb_di(); + void eorb_ex(); + void eorb_im(); + void eorb_ix(); + void illegal(); + void inc_ex(); + void inc_ix(); + void inca(); + void incb(); + void ins(); + void inx(); + void jmp_ex(); + void jmp_ix(); + void jsr_di(); + void jsr_ex(); + void jsr_ix(); + void lda_di(); + void lda_ex(); + void lda_im(); + void lda_ix(); + void ldb_di(); + void ldb_ex(); + void ldb_im(); + void ldb_ix(); + void ldd_di(); + void ldd_ex(); + void ldd_im(); + void ldd_ix(); + void lds_di(); + void lds_ex(); + void lds_im(); + void lds_ix(); + void ldx_di(); + void ldx_ex(); + void ldx_im(); + void ldx_ix(); + void lsr_ex(); + void lsr_ix(); + void lsra(); + void lsrb(); + void lsrd(); + void mul(); + void neg_ex(); + void neg_ix(); + void nega(); + void negb(); + void nop(); + void oim_di(); + void oim_ix(); + void ora_di(); + void ora_ex(); + void ora_im(); + void ora_ix(); + void orb_di(); + void orb_ex(); + void orb_im(); + void orb_ix(); + void psha(); + void pshb(); + void pshx(); + void pula(); + void pulb(); + void pulx(); + void rol_ex(); + void rol_ix(); + void rola(); + void rolb(); + void ror_ex(); + void ror_ix(); + void rora(); + void rorb(); + void rti(); + void rts(); + void sba(); + void sbca_di(); + void sbca_ex(); + void sbca_im(); + void sbca_ix(); + void sbcb_di(); + void sbcb_ex(); + void sbcb_im(); + void sbcb_ix(); + void sec(); + void sei(); + void sev(); + void slp(); + void sta_di(); + void sta_ex(); + void sta_im(); + void sta_ix(); + void stb_di(); + void stb_ex(); + void stb_im(); + void stb_ix(); + void std_di(); + void std_ex(); + void std_im(); + void std_ix(); + void sts_di(); + void sts_ex(); + void sts_im(); + void sts_ix(); + void stx_di(); + void stx_ex(); + void stx_im(); + void stx_ix(); + void suba_di(); + void suba_ex(); + void suba_im(); + void suba_ix(); + void subb_di(); + void subb_ex(); + void subb_im(); + void subb_ix(); + void subd_di(); + void subd_ex(); + void subd_im(); + void subd_ix(); + void swi(); + void tab(); + void tap(); + void tba(); + void tim_di(); + void tim_ix(); + void tpa(); + void tst_ex(); + void tst_ix(); + void tsta(); + void tstb(); + void tsx(); + void txs(); + void undoc1(); + void undoc2(); + void wai(); + void xgdx(); + void cpx_di(); + void cpx_ex(); + void cpx_im(); + void cpx_ix(); + void trap(); +}; + + +class m6801_cpu_device : public m6800_cpu_device +{ +public: + m6801_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + m6801_cpu_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source, const m6800_cpu_device::op_func *insn, const UINT8 *cycles, address_map_constructor internal = NULL); + + void m6801_clock_serial(); + +protected: + virtual UINT64 execute_clocks_to_cycles(UINT64 clocks) const { return (clocks + 4 - 1) / 4; } + virtual UINT64 execute_cycles_to_clocks(UINT64 cycles) const { return (cycles * 4); } + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); +}; + + +class m6802_cpu_device : public m6800_cpu_device +{ +public: + m6802_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + m6802_cpu_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source, const m6800_cpu_device::op_func *insn, const UINT8 *cycles); + +protected: + virtual UINT64 execute_clocks_to_cycles(UINT64 clocks) const { return (clocks + 4 - 1) / 4; } + virtual UINT64 execute_cycles_to_clocks(UINT64 cycles) const { return (cycles * 4); } + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); +}; + + +class m6803_cpu_device : public m6801_cpu_device +{ +public: + m6803_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); +}; + + +class m6808_cpu_device : public m6802_cpu_device +{ +public: + m6808_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); +}; + + +class hd6301_cpu_device : public m6801_cpu_device +{ +public: + hd6301_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + hd6301_cpu_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + +protected: + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); +}; + + +class hd63701_cpu_device : public m6801_cpu_device +{ +public: + hd63701_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); +}; + + +class nsc8105_cpu_device : public m6802_cpu_device +{ +public: + nsc8105_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); +}; + + +// DP-40 package: HD6303RP, HD63A03RP, HD63B03RP, +// FP-54 package: HD6303RF, HD63A03RF, HD63B03RF, +// CG-40 package: HD6303RCG, HD63A03RCG, HD63B03RCG, +// Not fully emulated yet +class hd6303r_cpu_device : public hd6301_cpu_device +{ +public: + hd6303r_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +// DP-64S package: HD6303YP, HD63A03YP, HD63B03YP, HD63C03YP +// FP-64 package: HD6303YF, HD63A03YF, HD63B03YF, HD63C03YF +// FP-64A package: HD6303YH, HD63A03YH, HD63B03YH, HD63C03YH +// CP-68 package: HD6303YCP, HD63A03YCP, HD63B03YCP, HD63C03YCP +// Not fully emulated yet +class hd6303y_cpu_device : public hd6301_cpu_device +{ +public: + hd6303y_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +extern const device_type M6800; +extern const device_type M6801; +extern const device_type M6802; +extern const device_type M6803; +extern const device_type M6808; +extern const device_type HD6301; +extern const device_type HD63701; +extern const device_type NSC8105; +extern const device_type HD6303R; +extern const device_type HD6303Y; + +#endif /* __M6800_H__ */ diff --git a/src/devices/cpu/m68000/m68000.h b/src/devices/cpu/m68000/m68000.h new file mode 100644 index 00000000000..5279ad655ec --- /dev/null +++ b/src/devices/cpu/m68000/m68000.h @@ -0,0 +1,808 @@ +// license:BSD-3-Clause +// copyright-holders:Karl Stenerud +#pragma once + +#ifndef __M68000_H__ +#define __M68000_H__ + + + + +#include "softfloat/milieu.h" +#include "softfloat/softfloat.h" + + +/* MMU constants */ +#define MMU_ATC_ENTRIES (22) // 68851 has 64, 030 has 22 + +/* instruction cache constants */ +#define M68K_IC_SIZE 128 + + + + +#define m68ki_check_address_error(m68k, ADDR, WRITE_MODE, FC) \ + if((ADDR)&1) \ + { \ + m68k->aerr_address = ADDR; \ + m68k->aerr_write_mode = WRITE_MODE; \ + m68k->aerr_fc = FC; \ + throw 10; \ + } + + + +/* There are 7 levels of interrupt to the 68K. + * A transition from < 7 to 7 will cause a non-maskable interrupt (NMI). + */ +#define M68K_IRQ_NONE 0 +#define M68K_IRQ_1 1 +#define M68K_IRQ_2 2 +#define M68K_IRQ_3 3 +#define M68K_IRQ_4 4 +#define M68K_IRQ_5 5 +#define M68K_IRQ_6 6 +#define M68K_IRQ_7 7 + +// special input lines +#define M68K_LINE_BUSERROR 16 + +/* CPU types for use in m68k_set_cpu_type() */ +enum +{ + M68K_CPU_TYPE_INVALID, + M68K_CPU_TYPE_68000, + M68K_CPU_TYPE_68008, + M68K_CPU_TYPE_68010, + M68K_CPU_TYPE_68EC020, + M68K_CPU_TYPE_68020, + M68K_CPU_TYPE_68EC030, + M68K_CPU_TYPE_68030, + M68K_CPU_TYPE_68EC040, + M68K_CPU_TYPE_68LC040, + M68K_CPU_TYPE_68040, + M68K_CPU_TYPE_SCC68070, + M68K_CPU_TYPE_FSCPU32, + M68K_CPU_TYPE_COLDFIRE +}; + +// function codes +enum +{ + M68K_FC_USER_DATA = 1, + M68K_FC_USER_PROGRAM = 2, + M68K_FC_SUPERVISOR_DATA = 5, + M68K_FC_SUPERVISOR_PROGRAM = 6, + M68K_FC_INTERRUPT = 7 +}; + +/* HMMU enable types for use with m68k_set_hmmu_enable() */ +#define M68K_HMMU_DISABLE 0 /* no translation */ +#define M68K_HMMU_ENABLE_II 1 /* Mac II style fixed translation */ +#define M68K_HMMU_ENABLE_LC 2 /* Mac LC style fixed translation */ + +/* Special interrupt acknowledge values. + * Use these as special returns from the interrupt acknowledge callback + * (specified later in this header). + */ + +/* Causes an interrupt autovector (0x18 + interrupt level) to be taken. + * This happens in a real 68K if VPA or AVEC is asserted during an interrupt + * acknowledge cycle instead of DTACK. + */ +#define M68K_INT_ACK_AUTOVECTOR 0xffffffff + +/* Causes the spurious interrupt vector (0x18) to be taken + * This happens in a real 68K if BERR is asserted during the interrupt + * acknowledge cycle (i.e. no devices responded to the acknowledge). + */ +#define M68K_INT_ACK_SPURIOUS 0xfffffffe + +enum +{ + /* NOTE: M68K_SP fetches the current SP, be it USP, ISP, or MSP */ + M68K_PC, M68K_SP, M68K_ISP, M68K_USP, M68K_MSP, M68K_SR, M68K_VBR, + M68K_SFC, M68K_DFC, M68K_CACR, M68K_CAAR, M68K_PREF_ADDR, M68K_PREF_DATA, + M68K_D0, M68K_D1, M68K_D2, M68K_D3, M68K_D4, M68K_D5, M68K_D6, M68K_D7, + M68K_A0, M68K_A1, M68K_A2, M68K_A3, M68K_A4, M68K_A5, M68K_A6, M68K_A7, + M68K_FP0, M68K_FP1, M68K_FP2, M68K_FP3, M68K_FP4, M68K_FP5, M68K_FP6, M68K_FP7, + M68K_FPSR, M68K_FPCR, + + M68K_GENPC = STATE_GENPC, + M68K_GENSP = STATE_GENSP, + M68K_GENPCBASE = STATE_GENPCBASE +}; + +unsigned int m68k_disassemble_raw(char* str_buff, unsigned int pc, const unsigned char* opdata, const unsigned char* argdata, unsigned int cpu_type); + +class m68000_base_device; + + +extern const device_type M68K; + +class m68000_base_device : public cpu_device +{ +public: + + // construction/destruction + m68000_base_device(const machine_config &mconfig, const char *name, const char *tag, device_t *owner, UINT32 clock, + const device_type type, UINT32 prg_data_width, UINT32 prg_address_bits, const char *shortname, const char *source); + + m68000_base_device(const machine_config &mconfig, const char *name, const char *tag, device_t *owner, UINT32 clock, + const device_type type, UINT32 prg_data_width, UINT32 prg_address_bits, address_map_constructor internal_map, const char *shortname, const char *source); + + m68000_base_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + DECLARE_WRITE_LINE_MEMBER( write_irq1 ); + DECLARE_WRITE_LINE_MEMBER( write_irq2 ); + DECLARE_WRITE_LINE_MEMBER( write_irq3 ); + DECLARE_WRITE_LINE_MEMBER( write_irq4 ); + DECLARE_WRITE_LINE_MEMBER( write_irq5 ); + DECLARE_WRITE_LINE_MEMBER( write_irq6 ); + DECLARE_WRITE_LINE_MEMBER( write_irq7 ); + + void clear_all(void); + + virtual UINT32 disasm_min_opcode_bytes() const { return 2; }; + virtual UINT32 disasm_max_opcode_bytes() const { return 10; }; + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + + + + + // device_execute_interface overrides + virtual UINT32 execute_min_cycles() const { return 4; }; + virtual UINT32 execute_max_cycles() const { return 158; }; + virtual UINT32 execute_input_lines() const { return 8; }; // number of input lines + virtual void execute_run(); + virtual void execute_set_input(int inputnum, int state); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_stop(); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const; + + // address spaces + const address_space_config m_program_config, m_oprogram_config; + + void define_state(void); + + void set_reset_callback(write_line_delegate callback); + void set_cmpild_callback(write32_delegate callback); + void set_rte_callback(write_line_delegate callback); + void set_tas_write_callback(write8_delegate callback); + UINT16 get_fc(); + void set_hmmu_enable(int enable); + void set_instruction_hook(read32_delegate ihook); + void set_buserror_details(UINT32 fault_addr, UINT8 rw, UINT8 fc); + +public: + + + UINT32 cpu_type; /* CPU Type: 68000, 68008, 68010, 68EC020, 68020, 68EC030, 68030, 68EC040, or 68040 */ +// UINT32 dasm_type; /* disassembly type */ + UINT32 dar[16]; /* Data and Address Registers */ + UINT32 ppc; /* Previous program counter */ + UINT32 pc; /* Program Counter */ + UINT32 sp[7]; /* User, Interrupt, and Master Stack Pointers */ + UINT32 vbr; /* Vector Base Register (m68010+) */ + UINT32 sfc; /* Source Function Code Register (m68010+) */ + UINT32 dfc; /* Destination Function Code Register (m68010+) */ + UINT32 cacr; /* Cache Control Register (m68020, unemulated) */ + UINT32 caar; /* Cache Address Register (m68020, unemulated) */ + UINT32 ir; /* Instruction Register */ + floatx80 fpr[8]; /* FPU Data Register (m68030/040) */ + UINT32 fpiar; /* FPU Instruction Address Register (m68040) */ + UINT32 fpsr; /* FPU Status Register (m68040) */ + UINT32 fpcr; /* FPU Control Register (m68040) */ + UINT32 t1_flag; /* Trace 1 */ + UINT32 t0_flag; /* Trace 0 */ + UINT32 s_flag; /* Supervisor */ + UINT32 m_flag; /* Master/Interrupt state */ + UINT32 x_flag; /* Extend */ + UINT32 n_flag; /* Negative */ + UINT32 not_z_flag; /* Zero, inverted for speedups */ + UINT32 v_flag; /* Overflow */ + UINT32 c_flag; /* Carry */ + UINT32 int_mask; /* I0-I2 */ + UINT32 int_level; /* State of interrupt pins IPL0-IPL2 -- ASG: changed from ints_pending */ + UINT32 stopped; /* Stopped state */ + UINT32 pref_addr; /* Last prefetch address */ + UINT32 pref_data; /* Data in the prefetch queue */ + UINT32 sr_mask; /* Implemented status register bits */ + UINT32 instr_mode; /* Stores whether we are in instruction mode or group 0/1 exception mode */ + UINT32 run_mode; /* Stores whether we are processing a reset, bus error, address error, or something else */ + int has_pmmu; /* Indicates if a PMMU available (yes on 030, 040, no on EC030) */ + int has_hmmu; /* Indicates if an Apple HMMU is available in place of the 68851 (020 only) */ + int pmmu_enabled; /* Indicates if the PMMU is enabled */ + int hmmu_enabled; /* Indicates if the HMMU is enabled */ + int has_fpu; /* Indicates if a FPU is available (yes on 030, 040, may be on 020) */ + int fpu_just_reset; /* Indicates the FPU was just reset */ + + /* Clocks required for instructions / exceptions */ + UINT32 cyc_bcc_notake_b; + UINT32 cyc_bcc_notake_w; + UINT32 cyc_dbcc_f_noexp; + UINT32 cyc_dbcc_f_exp; + UINT32 cyc_scc_r_true; + UINT32 cyc_movem_w; + UINT32 cyc_movem_l; + UINT32 cyc_shift; + UINT32 cyc_reset; + + int initial_cycles; + int remaining_cycles; /* Number of clocks remaining */ + int reset_cycles; + UINT32 tracing; + + int m_address_error; + + UINT32 aerr_address; + UINT32 aerr_write_mode; + UINT32 aerr_fc; + + /* Virtual IRQ lines state */ + UINT32 virq_state; + UINT32 nmi_pending; + + void (**jump_table)(m68000_base_device *m68k); + const UINT8* cyc_instruction; + const UINT8* cyc_exception; + + /* Callbacks to host */ + device_irq_acknowledge_delegate int_ack_callback; /* Interrupt Acknowledge */ + write32_delegate bkpt_ack_callback; /* Breakpoint Acknowledge */ + write_line_delegate reset_instr_callback; /* Called when a RESET instruction is encountered */ + write32_delegate cmpild_instr_callback; /* Called when a CMPI.L #v, Dn instruction is encountered */ + write_line_delegate rte_instr_callback; /* Called when a RTE instruction is encountered */ + write8_delegate tas_write_callback; /* Called instead of normal write8 by the TAS instruction, + allowing writeback to be disabled globally or selectively + or other side effects to be implemented */ + + address_space *program, *oprogram; + + /* Redirect memory calls */ + + typedef delegate m68k_read8_delegate; + typedef delegate m68k_readimm16_delegate; + typedef delegate m68k_read16_delegate; + typedef delegate m68k_read32_delegate; + typedef delegate m68k_write8_delegate; + typedef delegate m68k_write16_delegate; + typedef delegate m68k_write32_delegate; + +// class m68k_memory_interface +// { + public: + void init8(address_space &space, address_space &ospace); + void init16(address_space &space, address_space &ospace); + void init32(address_space &space, address_space &ospace); + void init32mmu(address_space &space, address_space &ospace); + void init32hmmu(address_space &space, address_space &ospace); + + offs_t opcode_xor; // Address Calculation + m68k_readimm16_delegate readimm16; // Immediate read 16 bit + m68k_read8_delegate read8; + m68k_read16_delegate read16; + m68k_read32_delegate read32; + m68k_write8_delegate write8; + m68k_write16_delegate write16; + m68k_write32_delegate write32; + + private: + UINT16 m68008_read_immediate_16(offs_t address); + UINT16 read_immediate_16(offs_t address); + UINT16 simple_read_immediate_16(offs_t address); + + void m68000_write_byte(offs_t address, UINT8 data); + + UINT8 read_byte_32_mmu(offs_t address); + void write_byte_32_mmu(offs_t address, UINT8 data); + UINT16 read_immediate_16_mmu(offs_t address); + UINT16 readword_d32_mmu(offs_t address); + void writeword_d32_mmu(offs_t address, UINT16 data); + UINT32 readlong_d32_mmu(offs_t address); + void writelong_d32_mmu(offs_t address, UINT32 data); + + UINT8 read_byte_32_hmmu(offs_t address); + void write_byte_32_hmmu(offs_t address, UINT8 data); + UINT16 read_immediate_16_hmmu(offs_t address); + UINT16 readword_d32_hmmu(offs_t address); + void writeword_d32_hmmu(offs_t address, UINT16 data); + UINT32 readlong_d32_hmmu(offs_t address); + void writelong_d32_hmmu(offs_t address, UINT32 data); + +// m68000_base_device *m_cpustate; +// }; + + public: +// m68k_memory_interface memory; + + address_space *m_space, *m_ospace; + direct_read_data *m_direct, *m_odirect; + + UINT32 iotemp; + + /* save state data */ + UINT16 save_sr; + UINT8 save_stopped; + UINT8 save_halted; + + /* PMMU registers */ + UINT32 mmu_crp_aptr, mmu_crp_limit; + UINT32 mmu_srp_aptr, mmu_srp_limit; + UINT32 mmu_urp_aptr; /* 040 only */ + UINT32 mmu_tc; + UINT16 mmu_sr; + UINT32 mmu_sr_040; + UINT32 mmu_atc_tag[MMU_ATC_ENTRIES], mmu_atc_data[MMU_ATC_ENTRIES]; + UINT32 mmu_atc_rr; + UINT32 mmu_tt0, mmu_tt1; + UINT32 mmu_itt0, mmu_itt1, mmu_dtt0, mmu_dtt1; + UINT32 mmu_acr0, mmu_acr1, mmu_acr2, mmu_acr3; + UINT32 mmu_last_page_entry, mmu_last_page_entry_addr; + + UINT16 mmu_tmp_sr; /* temporary hack: status code for ptest and to handle write protection */ + UINT16 mmu_tmp_fc; /* temporary hack: function code for the mmu (moves) */ + UINT16 mmu_tmp_rw; /* temporary hack: read/write (1/0) for the mmu */ + UINT32 mmu_tmp_buserror_address; /* temporary hack: (first) bus error address */ + UINT16 mmu_tmp_buserror_occurred; /* temporary hack: flag that bus error has occurred from mmu */ + UINT16 mmu_tmp_buserror_fc; /* temporary hack: (first) bus error fc */ + UINT16 mmu_tmp_buserror_rw; /* temporary hack: (first) bus error rw */ + + UINT32 ic_address[M68K_IC_SIZE]; /* instruction cache address data */ + UINT32 ic_data[M68K_IC_SIZE]; /* instruction cache content data */ + bool ic_valid[M68K_IC_SIZE]; /* instruction cache valid flags */ + + + + /* 68307 / 68340 internal address map */ + address_space *internal; + + + + /* external instruction hook (does not depend on debug mode) */ + read32_delegate instruction_hook; + + + + void init_cpu_common(void); + void init_cpu_m68000(void); + void init_cpu_m68008(void); + void init_cpu_m68010(void); + void init_cpu_m68020(void); + void init_cpu_m68020fpu(void); + void init_cpu_m68020pmmu(void); + void init_cpu_m68020hmmu(void); + void init_cpu_m68ec020(void); + void init_cpu_m68030(void); + void init_cpu_m68ec030(void); + void init_cpu_m68040(void); + void init_cpu_m68ec040(void); + void init_cpu_m68lc040(void); + void init_cpu_fscpu32(void); + void init_cpu_scc68070(void); + void init_cpu_coldfire(void); + + + void m68ki_exception_interrupt(m68000_base_device *m68k, UINT32 int_level); + + void reset_cpu(void); + inline void cpu_execute(void); + + // device_state_interface overrides + virtual void state_import(const device_state_entry &entry); + virtual void state_export(const device_state_entry &entry); + virtual void state_string_export(const device_state_entry &entry, std::string &str); + + // device_memory_interface overrides + virtual bool memory_translate(address_spacenum space, int intention, offs_t &address); +}; + + + +class m68000_device : public m68000_base_device +{ +public: + // construction/destruction + m68000_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + m68000_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + m68000_device(const machine_config &mconfig, const char *name, const char *tag, device_t *owner, UINT32 clock, + const device_type type, UINT32 prg_data_width, UINT32 prg_address_bits, address_map_constructor internal_map, const char *shortname, const char *source); + + + + virtual UINT32 disasm_min_opcode_bytes() const { return 2; }; + virtual UINT32 disasm_max_opcode_bytes() const { return 10; }; + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + + virtual UINT32 execute_min_cycles() const { return 4; }; + virtual UINT32 execute_max_cycles() const { return 158; }; + + virtual UINT32 execute_default_irq_vector() const { return -1; }; + + // device-level overrides + virtual void device_start(); +protected: +}; + +class m68301_device : public m68000_base_device +{ +public: + // construction/destruction + m68301_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual UINT32 disasm_min_opcode_bytes() const { return 2; }; + virtual UINT32 disasm_max_opcode_bytes() const { return 10; }; + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + + virtual UINT32 execute_min_cycles() const { return 4; }; + virtual UINT32 execute_max_cycles() const { return 158; }; + + virtual UINT32 execute_default_irq_vector() const { return -1; }; + + // device-level overrides + virtual void device_start(); +protected: +}; + + + + +class m68008_device : public m68000_base_device +{ +public: + // construction/destruction + m68008_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual UINT32 disasm_min_opcode_bytes() const { return 2; }; + virtual UINT32 disasm_max_opcode_bytes() const { return 10; }; + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + + virtual UINT32 execute_min_cycles() const { return 4; }; + virtual UINT32 execute_max_cycles() const { return 158; }; + + virtual UINT32 execute_default_irq_vector() const { return -1; }; + + // device-level overrides + virtual void device_start(); +protected: +}; + +class m68008plcc_device : public m68000_base_device +{ +public: + // construction/destruction + m68008plcc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual UINT32 disasm_min_opcode_bytes() const { return 2; }; + virtual UINT32 disasm_max_opcode_bytes() const { return 10; }; + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + + virtual UINT32 execute_min_cycles() const { return 4; }; + virtual UINT32 execute_max_cycles() const { return 158; }; + + virtual UINT32 execute_default_irq_vector() const { return -1; }; + + // device-level overrides + virtual void device_start(); +protected: +}; + +class m68010_device : public m68000_base_device +{ +public: + // construction/destruction + m68010_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual UINT32 disasm_min_opcode_bytes() const { return 2; }; + virtual UINT32 disasm_max_opcode_bytes() const { return 10; }; + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + + virtual UINT32 execute_min_cycles() const { return 4; }; + virtual UINT32 execute_max_cycles() const { return 158; }; + + virtual UINT32 execute_default_irq_vector() const { return -1; }; + + // device-level overrides + virtual void device_start(); +protected: +}; + +class m68ec020_device : public m68000_base_device +{ +public: + // construction/destruction + m68ec020_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual UINT32 disasm_min_opcode_bytes() const { return 2; }; + virtual UINT32 disasm_max_opcode_bytes() const { return 20; }; + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + + virtual UINT32 execute_min_cycles() const { return 2; }; + virtual UINT32 execute_max_cycles() const { return 158; }; + + virtual UINT32 execute_default_irq_vector() const { return -1; }; + + // device-level overrides + virtual void device_start(); +protected: +}; + +class m68020_device : public m68000_base_device +{ +public: + // construction/destruction + m68020_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual UINT32 disasm_min_opcode_bytes() const { return 2; }; + virtual UINT32 disasm_max_opcode_bytes() const { return 20; }; + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + + virtual UINT32 execute_min_cycles() const { return 2; }; + virtual UINT32 execute_max_cycles() const { return 158; }; + + virtual UINT32 execute_default_irq_vector() const { return -1; }; + + // device-level overrides + virtual void device_start(); +protected: +}; + +class m68020fpu_device : public m68000_base_device +{ +public: + // construction/destruction + m68020fpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual UINT32 disasm_min_opcode_bytes() const { return 2; }; + virtual UINT32 disasm_max_opcode_bytes() const { return 20; }; + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + + virtual UINT32 execute_min_cycles() const { return 2; }; + virtual UINT32 execute_max_cycles() const { return 158; }; + + virtual UINT32 execute_default_irq_vector() const { return -1; }; + + // device-level overrides + virtual void device_start(); +protected: +}; + +class m68020pmmu_device : public m68000_base_device +{ +public: + // construction/destruction + m68020pmmu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual UINT32 disasm_min_opcode_bytes() const { return 2; }; + virtual UINT32 disasm_max_opcode_bytes() const { return 20; }; + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + + virtual UINT32 execute_min_cycles() const { return 2; }; + virtual UINT32 execute_max_cycles() const { return 158; }; + + virtual UINT32 execute_default_irq_vector() const { return -1; }; + + // device-level overrides + virtual void device_start(); +protected: +}; + +class m68020hmmu_device : public m68000_base_device +{ +public: + // construction/destruction + m68020hmmu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual UINT32 disasm_min_opcode_bytes() const { return 2; }; + virtual UINT32 disasm_max_opcode_bytes() const { return 20; }; + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + + virtual UINT32 execute_min_cycles() const { return 2; }; + virtual UINT32 execute_max_cycles() const { return 158; }; + + virtual UINT32 execute_default_irq_vector() const { return -1; }; + + virtual bool memory_translate(address_spacenum space, int intention, offs_t &address); + + // device-level overrides + virtual void device_start(); +protected: +}; + +class m68ec030_device : public m68000_base_device +{ +public: + // construction/destruction + m68ec030_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual UINT32 disasm_min_opcode_bytes() const { return 2; }; + virtual UINT32 disasm_max_opcode_bytes() const { return 20; }; + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + + virtual UINT32 execute_min_cycles() const { return 2; }; + virtual UINT32 execute_max_cycles() const { return 158; }; + + virtual UINT32 execute_default_irq_vector() const { return -1; }; + + // device-level overrides + virtual void device_start(); +protected: +}; + +class m68030_device : public m68000_base_device +{ +public: + // construction/destruction + m68030_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual UINT32 disasm_min_opcode_bytes() const { return 2; }; + virtual UINT32 disasm_max_opcode_bytes() const { return 20; }; + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + + virtual UINT32 execute_min_cycles() const { return 2; }; + virtual UINT32 execute_max_cycles() const { return 158; }; + + virtual UINT32 execute_default_irq_vector() const { return -1; }; + + // device-level overrides + virtual void device_start(); +protected: +}; + +class m68ec040_device : public m68000_base_device +{ +public: + // construction/destruction + m68ec040_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual UINT32 disasm_min_opcode_bytes() const { return 2; }; + virtual UINT32 disasm_max_opcode_bytes() const { return 20; }; + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + + virtual UINT32 execute_min_cycles() const { return 2; }; + virtual UINT32 execute_max_cycles() const { return 158; }; + + virtual UINT32 execute_default_irq_vector() const { return -1; }; + + // device-level overrides + virtual void device_start(); +protected: +}; + +class m68lc040_device : public m68000_base_device +{ +public: + // construction/destruction + m68lc040_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual UINT32 disasm_min_opcode_bytes() const { return 2; }; + virtual UINT32 disasm_max_opcode_bytes() const { return 20; }; + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + + virtual UINT32 execute_min_cycles() const { return 2; }; + virtual UINT32 execute_max_cycles() const { return 158; }; + + virtual UINT32 execute_default_irq_vector() const { return -1; }; + + // device-level overrides + virtual void device_start(); +protected: +}; + +class m68040_device : public m68000_base_device +{ +public: + // construction/destruction + m68040_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual UINT32 disasm_min_opcode_bytes() const { return 2; }; + virtual UINT32 disasm_max_opcode_bytes() const { return 20; }; + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + + virtual UINT32 execute_min_cycles() const { return 2; }; + virtual UINT32 execute_max_cycles() const { return 158; }; + + virtual UINT32 execute_default_irq_vector() const { return -1; }; + + // device-level overrides + virtual void device_start(); +protected: +}; + +class scc68070_device : public m68000_base_device +{ +public: + // construction/destruction + scc68070_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual UINT32 disasm_min_opcode_bytes() const { return 2; }; + virtual UINT32 disasm_max_opcode_bytes() const { return 10; }; + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + + virtual UINT32 execute_min_cycles() const { return 4; }; + virtual UINT32 execute_max_cycles() const { return 158; }; + + virtual UINT32 execute_default_irq_vector() const { return -1; }; + + // device-level overrides + virtual void device_start(); +protected: +}; + + + + +class fscpu32_device : public m68000_base_device +{ +public: + // construction/destruction + fscpu32_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + fscpu32_device(const machine_config &mconfig, const char *name, const char *tag, device_t *owner, UINT32 clock, + const device_type type, UINT32 prg_data_width, UINT32 prg_address_bits, address_map_constructor internal_map, const char *shortname, const char *source); + + virtual UINT32 disasm_min_opcode_bytes() const { return 2; }; + virtual UINT32 disasm_max_opcode_bytes() const { return 20; }; + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + + virtual UINT32 execute_min_cycles() const { return 2; }; + virtual UINT32 execute_max_cycles() const { return 158; }; + + virtual UINT32 execute_default_irq_vector() const { return -1; }; + + // device-level overrides + virtual void device_start(); +protected: +}; + + + +class mcf5206e_device : public m68000_base_device +{ +public: + // construction/destruction + mcf5206e_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual UINT32 disasm_min_opcode_bytes() const { return 2; }; + virtual UINT32 disasm_max_opcode_bytes() const { return 20; }; + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + + virtual UINT32 execute_min_cycles() const { return 2; }; + virtual UINT32 execute_max_cycles() const { return 158; }; + + virtual UINT32 execute_default_irq_vector() const { return -1; }; + + + // device-level overrides + virtual void device_start(); +protected: +}; + + +extern const device_type M68000; +extern const device_type M68301; +extern const device_type M68008; +extern const device_type M68008PLCC; +extern const device_type M68010; +extern const device_type M68EC020; +extern const device_type M68020; +extern const device_type M68020FPU; +extern const device_type M68020PMMU; +extern const device_type M68020HMMU; +extern const device_type M68EC030; +extern const device_type M68030; +extern const device_type M68EC040; +extern const device_type M68LC040; +extern const device_type M68040; +extern const device_type SCC68070; +extern const device_type FSCPU32; +extern const device_type MCF5206E; + + +#endif /* __M68000_H__ */ diff --git a/src/devices/cpu/m68000/m68k_in.c b/src/devices/cpu/m68000/m68k_in.c new file mode 100644 index 00000000000..74b136a0012 --- /dev/null +++ b/src/devices/cpu/m68000/m68k_in.c @@ -0,0 +1,10546 @@ +// license:BSD-3-Clause +// copyright-holders:Karl Stenerud +/* +must fix: + callm + chk +*/ +/* ======================================================================== */ +/* ========================= LICENSING & COPYRIGHT ======================== */ +/* ======================================================================== */ +/* + * MUSASHI + * Version 4.90 + * + * A portable Motorola M68xxx processor emulation engine. + * Copyright Karl Stenerud. All rights reserved. + * + */ + +/* Special thanks to Bart Trzynadlowski for his insight into the + * undocumented features of this chip: + * + * http://dynarec.com/~bart/files/68knotes.txt + */ + + +/* Input file for m68kmake + * ----------------------- + * + * All sections begin with 80 X's in a row followed by an end-of-line + * sequence. + * After this, m68kmake will expect to find one of the following section + * identifiers: + * M68KMAKE_PROTOTYPE_HEADER - header for opcode handler prototypes + * M68KMAKE_PROTOTYPE_FOOTER - footer for opcode handler prototypes + * M68KMAKE_TABLE_HEADER - header for opcode handler jumptable + * M68KMAKE_TABLE_FOOTER - footer for opcode handler jumptable + * M68KMAKE_TABLE_BODY - the table itself + * M68KMAKE_OPCODE_HANDLER_HEADER - header for opcode handler implementation + * M68KMAKE_OPCODE_HANDLER_FOOTER - footer for opcode handler implementation + * M68KMAKE_OPCODE_HANDLER_BODY - body section for opcode handler implementation + * + * NOTE: M68KMAKE_OPCODE_HANDLER_BODY must be last in the file and + * M68KMAKE_TABLE_BODY must be second last in the file. + * + * The M68KMAKE_OPHANDLER_BODY section contains the opcode handler + * primitives themselves. Each opcode handler begins with: + * M68KMAKE_OP(A, B, C, D) + * + * where A is the opcode handler name, B is the size of the operation, + * C denotes any special processing mode, and D denotes a specific + * addressing mode. + * For C and D where nothing is specified, use "." + * + * Example: + * M68KMAKE_OP(abcd, 8, rr, .) abcd, size 8, register to register, default EA + * M68KMAKE_OP(abcd, 8, mm, ax7) abcd, size 8, memory to memory, register X is A7 + * M68KMAKE_OP(tst, 16, ., pcix) tst, size 16, PCIX addressing + * + * All opcode handler primitives end with a closing curly brace "}" at column 1 + * + * NOTE: Do not place a M68KMAKE_OP() directive inside the opcode handler, + * and do not put a closing curly brace at column 1 unless it is + * marking the end of the handler! + * + * Inside the handler, m68kmake will recognize M68KMAKE_GET_OPER_xx_xx, + * M68KMAKE_GET_EA_xx_xx, and M68KMAKE_CC directives, and create multiple + * opcode handlers to handle variations in the opcode handler. + * Note: M68KMAKE_CC will only be interpreted in condition code opcodes. + * As well, M68KMAKE_GET_EA_xx_xx and M68KMAKE_GET_OPER_xx_xx will only + * be interpreted on instructions where the corresponding table entry + * specifies multiple effective addressing modes. + * Example: + * clr 32 . . 0100001010...... A+-DXWL... U U U 12 6 4 + * + * This table entry says that the clr.l opcde has 7 variations (A+-DXWL). + * It is run in user or supervisor mode for all CPUs, and uses 12 cycles for + * 68000, 6 cycles for 68010, and 4 cycles for 68020. + */ + +XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +M68KMAKE_PROTOTYPE_HEADER + + +/* ======================================================================== */ +/* ============================ OPCODE HANDLERS =========================== */ +/* ======================================================================== */ + + + +XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +M68KMAKE_PROTOTYPE_FOOTER + + +/* Build the opcode handler table */ +void m68ki_build_opcode_table(void); + +extern void (*m68ki_instruction_jump_table[][0x10000])(m68000_base_device *m68k); /* opcode handler jump table */ +extern unsigned char m68ki_cycles[][0x10000]; + + +/* ======================================================================== */ +/* ============================== END OF FILE ============================= */ +/* ======================================================================== */ + + + + +XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +M68KMAKE_TABLE_HEADER + +/* ======================================================================== */ +/* ========================= OPCODE TABLE BUILDER ========================= */ +/* ======================================================================== */ + +#include "m68kops.h" + +#define NUM_CPU_TYPES 7 + +void (*m68ki_instruction_jump_table[NUM_CPU_TYPES][0x10000])(m68000_base_device *m68k); /* opcode handler jump table */ +unsigned char m68ki_cycles[NUM_CPU_TYPES][0x10000]; /* Cycles used by CPU type */ + +/* This is used to generate the opcode handler jump table */ +struct opcode_handler_struct +{ + void (*opcode_handler)(m68000_base_device *m68k); /* handler function */ + unsigned int mask; /* mask on opcode */ + unsigned int match; /* what to match after masking */ + unsigned char cycles[NUM_CPU_TYPES]; /* cycles each cpu type takes */ +}; + + +/* Opcode handler table */ +static const opcode_handler_struct m68k_opcode_handler_table[] = +{ +/* function mask match 000 010 020 040 */ + + + +XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +M68KMAKE_TABLE_FOOTER + + {0, 0, 0, {0, 0, 0, 0, 0}} +}; + + +/* Build the opcode handler jump table */ + +static void m68ki_set_one(unsigned short opcode, const opcode_handler_struct *s) +{ + for(int i=0; icycles[i] != 0xff) { + m68ki_cycles[i][opcode] = s->cycles[i]; + m68ki_instruction_jump_table[i][opcode] = s->opcode_handler; + } +} + +void m68ki_build_opcode_table(void) +{ + const opcode_handler_struct *ostruct; + int i; + int j; + int k; + + for(i = 0; i < 0x10000; i++) + { + /* default to illegal */ + for(k=0;kmask != 0xff00) + { + for(i = 0;i < 0x10000;i++) + { + if((i & ostruct->mask) == ostruct->match) + m68ki_set_one(i, ostruct); + } + ostruct++; + } + while(ostruct->mask == 0xff00) + { + for(i = 0;i <= 0xff;i++) + m68ki_set_one(ostruct->match | i, ostruct); + ostruct++; + } + while(ostruct->mask == 0xff20) + { + for(i = 0;i < 4;i++) + { + for(j = 0;j < 32;j++) + { + m68ki_set_one(ostruct->match | (i << 6) | j, ostruct); + } + } + ostruct++; + } + while(ostruct->mask == 0xf1f8) + { + for(i = 0;i < 8;i++) + { + for(j = 0;j < 8;j++) + m68ki_set_one(ostruct->match | (i << 9) | j, ostruct); + } + ostruct++; + } + while(ostruct->mask == 0xffd8) + { + for(i = 0;i < 2;i++) + { + for(j = 0;j < 8;j++) + { + m68ki_set_one(ostruct->match | (i << 5) | j, ostruct); + } + } + ostruct++; + } + while(ostruct->mask == 0xfff0) + { + for(i = 0;i <= 0x0f;i++) + m68ki_set_one(ostruct->match | i, ostruct); + ostruct++; + } + while(ostruct->mask == 0xf1ff) + { + for(i = 0;i <= 0x07;i++) + m68ki_set_one(ostruct->match | (i << 9), ostruct); + ostruct++; + } + while(ostruct->mask == 0xfff8) + { + for(i = 0;i <= 0x07;i++) + m68ki_set_one(ostruct->match | i, ostruct); + ostruct++; + } + while(ostruct->mask == 0xffff) + { + m68ki_set_one(ostruct->match, ostruct); + ostruct++; + } + + // if we fell all the way through with a non-zero mask, the opcode table wasn't built properly + if (ostruct->mask != 0) + { + fatalerror("m68ki_build_opcode_table: unhandled opcode mask %x (match %x), m68k core will not function!\n", ostruct->mask, ostruct->match); + } +} + + +/* ======================================================================== */ +/* ============================== END OF FILE ============================= */ +/* ======================================================================== */ + + + +XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +M68KMAKE_OPCODE_HANDLER_HEADER + +#include "emu.h" +#include "m68kcpu.h" +extern void m68040_fpu_op0(m68000_base_device *m68k); +extern void m68040_fpu_op1(m68000_base_device *m68k); +extern void m68881_mmu_ops(m68000_base_device *m68k); +extern void m68881_ftrap(m68000_base_device *m68k); + +/* ======================================================================== */ +/* ========================= INSTRUCTION HANDLERS ========================= */ +/* ======================================================================== */ + + + +XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +M68KMAKE_OPCODE_HANDLER_FOOTER + +/* ======================================================================== */ +/* ============================== END OF FILE ============================= */ +/* ======================================================================== */ + + + +XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +M68KMAKE_TABLE_BODY +/* +The following table is arranged as follows: + +name: Opcode mnemonic + +size: Operation size + +spec proc: Special processing mode: + .: normal + s: static operand + r: register operand + rr: register to register + mm: memory to memory + er: effective address to register + re: register to effective address + dd: data register to data register + da: data register to address register + aa: address register to address register + cr: control register to register + rc: register to control register + toc: to condition code register + tos: to status register + tou: to user stack pointer + frc: from condition code register + frs: from status register + fru: from user stack pointer + * for move.x, the special processing mode is a specific + destination effective addressing mode. + +spec ea: Specific effective addressing mode: + .: normal + i: immediate + d: data register + a: address register + ai: address register indirect + pi: address register indirect with postincrement + pd: address register indirect with predecrement + di: address register indirect with displacement + ix: address register indirect with index + aw: absolute word address + al: absolute long address + pcdi: program counter relative with displacement + pcix: program counter relative with index + a7: register specified in instruction is A7 + ax7: register field X of instruction is A7 + ay7: register field Y of instruction is A7 + axy7: register fields X and Y of instruction are A7 + +bit pattern: Pattern to recognize this opcode. "." means don't care. + +allowed ea: List of allowed addressing modes: + .: not present + A: address register indirect + +: ARI (address register indirect) with postincrement + -: ARI with predecrement + D: ARI with displacement + X: ARI with index + W: absolute word address + L: absolute long address + d: program counter indirect with displacement + x: program counter indirect with index + I: immediate +mode: CPU operating mode for each cpu type. U = user or supervisor, + S = supervisor only, "." = opcode not present. + +cpu cycles: Base number of cycles required to execute this opcode on the + specified CPU type. + Use "." if CPU does not have this opcode. +*/ + + + spec spec allowed ea mode 3 C cpu cycles +name size proc ea bit pattern A+-DXWLdxI 0 1 2 3 4 2 F 000 010 020 030 040 340 CLF comments +====== ==== ==== ==== ================ ========== = = = = = = = === === === === === === === ========== +M68KMAKE_TABLE_START +1010 0 . . 1010............ .......... U U U U U U U 4 4 4 4 4 4 4 +1111 0 . . 1111............ .......... U U U U U U U 4 4 4 4 4 4 4 +040fpu0 32 . . 11110010........ .......... . . U U U U . . . 0 0 0 0 . +040fpu1 32 . . 11110011........ .......... . . U U U U . . . 0 0 0 0 . +abcd 8 rr . 1100...100000... .......... U U U U U U U 6 6 4 4 4 4 4 +abcd 8 mm ax7 1100111100001... .......... U U U U U U U 18 18 16 16 16 16 16 +abcd 8 mm ay7 1100...100001111 .......... U U U U U U U 18 18 16 16 16 16 16 +abcd 8 mm axy7 1100111100001111 .......... U U U U U U U 18 18 16 16 16 16 16 +abcd 8 mm . 1100...100001... .......... U U U U U U U 18 18 16 16 16 16 16 +add 8 er d 1101...000000... .......... U U U U U U U 4 4 2 2 2 2 2 +add 8 er . 1101...000...... A+-DXWLdxI U U U U U U U 4 4 2 2 2 2 2 +add 16 er d 1101...001000... .......... U U U U U U U 4 4 2 2 2 2 2 +add 16 er a 1101...001001... .......... U U U U U U U 4 4 2 2 2 2 2 +add 16 er . 1101...001...... A+-DXWLdxI U U U U U U U 4 4 2 2 2 2 2 +add 32 er d 1101...010000... .......... U U U U U U U 6 6 2 2 2 2 2 +add 32 er a 1101...010001... .......... U U U U U U U 6 6 2 2 2 2 2 +add 32 er . 1101...010...... A+-DXWLdxI U U U U U U U 6 6 2 2 2 2 2 +add 8 re . 1101...100...... A+-DXWL... U U U U U U U 8 8 4 4 4 4 4 +add 16 re . 1101...101...... A+-DXWL... U U U U U U U 8 8 4 4 4 4 4 +add 32 re . 1101...110...... A+-DXWL... U U U U U U U 12 12 4 4 4 4 4 +adda 16 . d 1101...011000... .......... U U U U U U U 8 8 2 2 2 2 2 +adda 16 . a 1101...011001... .......... U U U U U U U 8 8 2 2 2 2 2 +adda 16 . . 1101...011...... A+-DXWLdxI U U U U U U U 8 8 2 2 2 2 2 +adda 32 . d 1101...111000... .......... U U U U U U U 6 6 2 2 2 2 2 +adda 32 . a 1101...111001... .......... U U U U U U U 6 6 2 2 2 2 2 +adda 32 . . 1101...111...... A+-DXWLdxI U U U U U U U 6 6 2 2 2 2 2 +addi 8 . d 0000011000000... .......... U U U U U U U 8 8 2 2 2 2 2 +addi 8 . . 0000011000...... A+-DXWL... U U U U U U U 12 12 4 4 4 4 4 +addi 16 . d 0000011001000... .......... U U U U U U U 8 8 2 2 2 2 2 +addi 16 . . 0000011001...... A+-DXWL... U U U U U U U 12 12 4 4 4 4 4 +addi 32 . d 0000011010000... .......... U U U U U U U 16 14 2 2 2 2 2 +addi 32 . . 0000011010...... A+-DXWL... U U U U U U U 20 20 4 4 4 4 4 +addq 8 . d 0101...000000... .......... U U U U U U U 4 4 2 2 2 2 2 +addq 8 . . 0101...000...... A+-DXWL... U U U U U U U 8 8 4 4 4 4 4 +addq 16 . d 0101...001000... .......... U U U U U U U 4 4 2 2 2 2 2 +addq 16 . a 0101...001001... .......... U U U U U U U 4 4 2 2 2 2 2 +addq 16 . . 0101...001...... A+-DXWL... U U U U U U U 8 8 4 4 4 4 4 +addq 32 . d 0101...010000... .......... U U U U U U U 8 8 2 2 2 2 2 +addq 32 . a 0101...010001... .......... U U U U U U U 8 8 2 2 2 2 2 +addq 32 . . 0101...010...... A+-DXWL... U U U U U U U 12 12 4 4 4 4 4 +addx 8 rr . 1101...100000... .......... U U U U U U U 4 4 2 2 2 2 2 +addx 16 rr . 1101...101000... .......... U U U U U U U 4 4 2 2 2 2 2 +addx 32 rr . 1101...110000... .......... U U U U U U U 8 6 2 2 2 2 2 +addx 8 mm ax7 1101111100001... .......... U U U U U U U 18 18 12 12 12 12 12 +addx 8 mm ay7 1101...100001111 .......... U U U U U U U 18 18 12 12 12 12 12 +addx 8 mm axy7 1101111100001111 .......... U U U U U U U 18 18 12 12 12 12 12 +addx 8 mm . 1101...100001... .......... U U U U U U U 18 18 12 12 12 12 12 +addx 16 mm . 1101...101001... .......... U U U U U U U 18 18 12 12 12 12 12 +addx 32 mm . 1101...110001... .......... U U U U U U U 30 30 12 12 12 12 12 +and 8 er d 1100...000000... .......... U U U U U U U 4 4 2 2 2 2 2 +and 8 er . 1100...000...... A+-DXWLdxI U U U U U U U 4 4 2 2 2 2 2 +and 16 er d 1100...001000... .......... U U U U U U U 4 4 2 2 2 2 2 +and 16 er . 1100...001...... A+-DXWLdxI U U U U U U U 4 4 2 2 2 2 2 +and 32 er d 1100...010000... .......... U U U U U U U 6 6 2 2 2 2 2 +and 32 er . 1100...010...... A+-DXWLdxI U U U U U U U 6 6 2 2 2 2 2 +and 8 re . 1100...100...... A+-DXWL... U U U U U U U 8 8 4 4 4 4 4 +and 16 re . 1100...101...... A+-DXWL... U U U U U U U 8 8 4 4 4 4 4 +and 32 re . 1100...110...... A+-DXWL... U U U U U U U 12 12 4 4 4 4 4 +andi 16 toc . 0000001000111100 .......... U U U U U U U 20 16 12 12 12 12 12 +andi 16 tos . 0000001001111100 .......... S S S S S S S 20 16 12 12 12 12 12 +andi 8 . d 0000001000000... .......... U U U U U U U 8 8 2 2 2 2 2 +andi 8 . . 0000001000...... A+-DXWL... U U U U U U U 12 12 4 4 4 4 4 +andi 16 . d 0000001001000... .......... U U U U U U U 8 8 2 2 2 2 2 +andi 16 . . 0000001001...... A+-DXWL... U U U U U U U 12 12 4 4 4 4 4 +andi 32 . d 0000001010000... .......... U U U U U U U 14 14 2 2 2 2 2 +andi 32 . . 0000001010...... A+-DXWL... U U U U U U U 20 20 4 4 4 4 4 +asr 8 s . 1110...000000... .......... U U U U U U U 6 6 6 6 6 6 6 +asr 16 s . 1110...001000... .......... U U U U U U U 6 6 6 6 6 6 6 +asr 32 s . 1110...010000... .......... U U U U U U U 8 8 6 6 6 6 6 +asr 8 r . 1110...000100... .......... U U U U U U U 6 6 6 6 6 6 6 +asr 16 r . 1110...001100... .......... U U U U U U U 6 6 6 6 6 6 6 +asr 32 r . 1110...010100... .......... U U U U U U U 8 8 6 6 6 6 6 +asr 16 . . 1110000011...... A+-DXWL... U U U U U U U 8 8 5 5 5 5 5 +asl 8 s . 1110...100000... .......... U U U U U U U 6 6 8 8 8 8 8 +asl 16 s . 1110...101000... .......... U U U U U U U 6 6 8 8 8 8 8 +asl 32 s . 1110...110000... .......... U U U U U U U 8 8 8 8 8 8 8 +asl 8 r . 1110...100100... .......... U U U U U U U 6 6 8 8 8 8 8 +asl 16 r . 1110...101100... .......... U U U U U U U 6 6 8 8 8 8 8 +asl 32 r . 1110...110100... .......... U U U U U U U 8 8 8 8 8 8 8 +asl 16 . . 1110000111...... A+-DXWL... U U U U U U U 8 8 6 6 6 6 6 +bcc 8 . . 0110............ .......... U U U U U U U 10 10 6 6 6 6 6 +bcc 16 . . 0110....00000000 .......... U U U U U U U 10 10 6 6 6 6 6 +bcc 32 . . 0110....11111111 .......... U U U U U U U 10 10 6 6 6 6 6 +bchg 8 r . 0000...101...... A+-DXWL... U U U U U U U 8 8 4 4 4 4 4 +bchg 32 r d 0000...101000... .......... U U U U U U U 8 8 4 4 4 4 4 +bchg 8 s . 0000100001...... A+-DXWL... U U U U U U U 12 12 4 4 4 4 4 +bchg 32 s d 0000100001000... .......... U U U U U U U 12 12 4 4 4 4 4 +bclr 8 r . 0000...110...... A+-DXWL... U U U U U U U 8 10 4 4 4 4 4 +bclr 32 r d 0000...110000... .......... U U U U U U U 10 10 4 4 4 4 4 +bclr 8 s . 0000100010...... A+-DXWL... U U U U U U U 12 12 4 4 4 4 4 +bclr 32 s d 0000100010000... .......... U U U U U U U 14 14 4 4 4 4 4 +bfchg 32 . d 1110101011000... .......... . . U U U U U . . 12 12 12 12 12 timing not quite correct +bfchg 32 . . 1110101011...... A..DXWL... . . U U U U U . . 20 20 20 20 20 +bfclr 32 . d 1110110011000... .......... . . U U U U U . . 12 12 12 12 12 +bfclr 32 . . 1110110011...... A..DXWL... . . U U U U U . . 20 20 20 20 20 +bfexts 32 . d 1110101111000... .......... . . U U U U U . . 8 8 8 8 8 +bfexts 32 . . 1110101111...... A..DXWLdx. . . U U U U U . . 15 15 15 15 15 +bfextu 32 . d 1110100111000... .......... . . U U U U U . . 8 8 8 8 8 +bfextu 32 . . 1110100111...... A..DXWLdx. . . U U U U U . . 15 15 15 15 15 +bfffo 32 . d 1110110111000... .......... . . U U U U U . . 18 18 18 18 18 +bfffo 32 . . 1110110111...... A..DXWLdx. . . U U U U U . . 28 28 28 28 28 +bfins 32 . d 1110111111000... .......... . . U U U U U . . 10 10 10 10 10 +bfins 32 . . 1110111111...... A..DXWL... . . U U U U U . . 17 17 17 17 17 +bfset 32 . d 1110111011000... .......... . . U U U U U . . 12 12 12 12 12 +bfset 32 . . 1110111011...... A..DXWL... . . U U U U U . . 20 20 20 20 20 +bftst 32 . d 1110100011000... .......... . . U U U U U . . 6 6 6 6 6 +bftst 32 . . 1110100011...... A..DXWLdx. . . U U U U U . . 13 13 13 13 13 +bkpt 0 . . 0100100001001... .......... . U U U U U U . 10 10 10 10 10 10 +bra 8 . . 01100000........ .......... U U U U U U U 10 10 10 10 10 10 10 +bra 16 . . 0110000000000000 .......... U U U U U U U 10 10 10 10 10 10 10 +bra 32 . . 0110000011111111 .......... U U U U U U U 10 10 10 10 10 10 10 +bset 32 r d 0000...111000... .......... U U U U U U U 8 8 4 4 4 4 4 +bset 8 r . 0000...111...... A+-DXWL... U U U U U U U 8 8 4 4 4 4 4 +bset 8 s . 0000100011...... A+-DXWL... U U U U U U U 12 12 4 4 4 4 4 +bset 32 s d 0000100011000... .......... U U U U U U U 12 12 4 4 4 4 4 +bsr 8 . . 01100001........ .......... U U U U U U U 18 18 7 7 7 7 7 +bsr 16 . . 0110000100000000 .......... U U U U U U U 18 18 7 7 7 7 7 +bsr 32 . . 0110000111111111 .......... U U U U U U U 18 18 7 7 7 7 7 +btst 8 r . 0000...100...... A+-DXWLdxI U U U U U U U 4 4 4 4 4 4 4 +btst 32 r d 0000...100000... .......... U U U U U U U 6 6 4 4 4 4 4 +btst 8 s . 0000100000...... A+-DXWLdx. U U U U U U U 8 8 4 4 4 4 4 +btst 32 s d 0000100000000... .......... U U U U U U U 10 10 4 4 4 4 4 +callm 32 . . 0000011011...... A..DXWLdx. . . U U U U U . . 60 60 60 60 60 not properly emulated +cas 8 . . 0000101011...... A+-DXWL... . . U U U U U . . 12 12 12 12 12 +cas 16 . . 0000110011...... A+-DXWL... . . U U U U U . . 12 12 12 12 12 +cas 32 . . 0000111011...... A+-DXWL... . . U U U U U . . 12 12 12 12 12 +cas2 16 . . 0000110011111100 .......... . . U U U U U . . 12 12 12 12 12 +cas2 32 . . 0000111011111100 .......... . . U U U U U . . 12 12 12 12 12 +chk 16 . d 0100...110000... .......... U U U U U U U 10 8 8 8 8 8 8 +chk 16 . . 0100...110...... A+-DXWLdxI U U U U U U U 10 8 8 8 8 8 8 +chk 32 . d 0100...100000... .......... . . U U U U U . . 8 8 8 8 8 +chk 32 . . 0100...100...... A+-DXWLdxI . . U U U U U . . 8 8 8 8 8 +chk2cmp2 8 . pcdi 0000000011111010 .......... . . U U U U U . . 23 23 23 23 23 +chk2cmp2 8 . pcix 0000000011111011 .......... . . U U U U U . . 23 23 23 23 23 +chk2cmp2 8 . . 0000000011...... A..DXWL... . . U U U U U . . 18 18 18 18 18 +chk2cmp2 16 . pcdi 0000001011111010 .......... . . U U U U U . . 23 23 23 23 23 +chk2cmp2 16 . pcix 0000001011111011 .......... . . U U U U U . . 23 23 23 23 23 +chk2cmp2 16 . . 0000001011...... A..DXWL... . . U U U U U . . 18 18 18 18 18 +chk2cmp2 32 . pcdi 0000010011111010 .......... . . U U U U U . . 23 23 23 23 23 +chk2cmp2 32 . pcix 0000010011111011 .......... . . U U U U U . . 23 23 23 23 23 +chk2cmp2 32 . . 0000010011...... A..DXWL... . . U U U U U . . 18 18 18 18 18 +clr 8 . d 0100001000000... .......... U U U U U U U 4 4 2 2 2 2 2 +clr 8 . . 0100001000...... A+-DXWL... U U U U U U U 8 4 4 4 4 4 4 +clr 16 . d 0100001001000... .......... U U U U U U U 4 4 2 2 2 2 2 +clr 16 . . 0100001001...... A+-DXWL... U U U U U U U 8 4 4 4 4 4 4 +clr 32 . d 0100001010000... .......... U U U U U U U 6 6 2 2 2 2 2 +clr 32 . . 0100001010...... A+-DXWL... U U U U U U U 12 6 4 4 4 4 4 +cmp 8 . d 1011...000000... .......... U U U U U U U 4 4 2 2 2 2 2 +cmp 8 . . 1011...000...... A+-DXWLdxI U U U U U U U 4 4 2 2 2 2 2 +cmp 16 . d 1011...001000... .......... U U U U U U U 4 4 2 2 2 2 2 +cmp 16 . a 1011...001001... .......... U U U U U U U 4 4 2 2 2 2 2 +cmp 16 . . 1011...001...... A+-DXWLdxI U U U U U U U 4 4 2 2 2 2 2 +cmp 32 . d 1011...010000... .......... U U U U U U U 6 6 2 2 2 2 2 +cmp 32 . a 1011...010001... .......... U U U U U U U 6 6 2 2 2 2 2 +cmp 32 . . 1011...010...... A+-DXWLdxI U U U U U U U 6 6 2 2 2 2 2 +cmpa 16 . d 1011...011000... .......... U U U U U U U 6 6 4 4 4 4 4 +cmpa 16 . a 1011...011001... .......... U U U U U U U 6 6 4 4 4 4 4 +cmpa 16 . . 1011...011...... A+-DXWLdxI U U U U U U U 6 6 4 4 4 4 4 +cmpa 32 . d 1011...111000... .......... U U U U U U U 6 6 4 4 4 4 4 +cmpa 32 . a 1011...111001... .......... U U U U U U U 6 6 4 4 4 4 4 +cmpa 32 . . 1011...111...... A+-DXWLdxI U U U U U U U 6 6 4 4 4 4 4 +cmpi 8 . d 0000110000000... .......... U U U U U U U 8 8 2 2 2 2 2 +cmpi 8 . . 0000110000...... A+-DXWL... U U U U U U U 8 8 2 2 2 2 2 +cmpi 8 . pcdi 0000110000111010 .......... . . U U U U U . . 7 7 7 7 7 +cmpi 8 . pcix 0000110000111011 .......... . . U U U U U . . 9 9 9 9 9 +cmpi 16 . d 0000110001000... .......... U U U U U U U 8 8 2 2 2 2 2 +cmpi 16 . . 0000110001...... A+-DXWL... U U U U U U U 8 8 2 2 2 2 2 +cmpi 16 . pcdi 0000110001111010 .......... . . U U U U U . . 7 7 7 7 7 +cmpi 16 . pcix 0000110001111011 .......... . . U U U U U . . 9 9 9 9 9 +cmpi 32 . d 0000110010000... .......... U U U U U U U 14 12 2 2 2 2 2 +cmpi 32 . . 0000110010...... A+-DXWL... U U U U U U U 12 12 2 2 2 2 2 +cmpi 32 . pcdi 0000110010111010 .......... . . U U U U U . . 7 7 7 7 7 +cmpi 32 . pcix 0000110010111011 .......... . . U U U U U . . 9 9 9 9 9 +cmpm 8 . ax7 1011111100001... .......... U U U U U U U 12 12 9 9 9 9 9 +cmpm 8 . ay7 1011...100001111 .......... U U U U U U U 12 12 9 9 9 9 9 +cmpm 8 . axy7 1011111100001111 .......... U U U U U U U 12 12 9 9 9 9 9 +cmpm 8 . . 1011...100001... .......... U U U U U U U 12 12 9 9 9 9 9 +cmpm 16 . . 1011...101001... .......... U U U U U U U 12 12 9 9 9 9 9 +cmpm 32 . . 1011...110001... .......... U U U U U U U 20 20 9 9 9 9 9 +cinv 32 . . 11110100..0..... .......... . . . . U . . . . . . 16 . . 040 only +cpush 32 . . 11110100..1..... .......... . . . . U . . . . . . 16 . . 040 only +cpbcc 32 . . 1111...01....... .......... . . U U . . U . . 4 4 . . . cpXXX only for 020/030, not on 040! +cpdbcc 32 . . 1111...001001... .......... . . U U . . U . . 4 4 . . . +cpgen 32 . . 1111...000...... .......... . . U U . . U . . 4 4 . . . +cpscc 32 . . 1111...001...... .......... . . U U . . U . . 4 4 . . . +cptrapcc 32 . . 1111...001111... .......... . . U U . . U . . 4 4 . . . +ftrapcc 32 . . 1111001001111... .......... . . U U . . U . . 4 4 . . . +dbt 16 . . 0101000011001... .......... U U U U U U U 12 12 6 6 6 6 6 +dbf 16 . . 0101000111001... .......... U U U U U U U 12 12 6 4 4 4 4 +dbcc 16 . . 0101....11001... .......... U U U U U U U 12 12 6 6 6 6 6 +divs 16 . d 1000...111000... .......... U U U U U U U 158 122 56 56 56 56 56 +divs 16 . . 1000...111...... A+-DXWLdxI U U U U U U U 158 122 56 56 56 56 56 +divu 16 . d 1000...011000... .......... U U U U U U U 140 108 44 44 44 44 44 +divu 16 . . 1000...011...... A+-DXWLdxI U U U U U U U 140 108 44 44 44 44 44 +divl 32 . d 0100110001000... .......... . . U U U U U . . 84 84 84 84 84 +divl 32 . . 0100110001...... A+-DXWLdxI . . U U U U U . . 84 84 84 84 84 +eor 8 . d 1011...100000... .......... U U U U U U U 4 4 2 2 2 2 2 +eor 8 . . 1011...100...... A+-DXWL... U U U U U U U 8 8 4 4 4 4 4 +eor 16 . d 1011...101000... .......... U U U U U U U 4 4 2 2 2 2 2 +eor 16 . . 1011...101...... A+-DXWL... U U U U U U U 8 8 4 4 4 4 4 +eor 32 . d 1011...110000... .......... U U U U U U U 8 6 2 2 2 2 2 +eor 32 . . 1011...110...... A+-DXWL... U U U U U U U 12 12 4 4 4 4 4 +eori 16 toc . 0000101000111100 .......... U U U U U U U 20 16 12 12 12 12 12 +eori 16 tos . 0000101001111100 .......... S S S S S S S 20 16 12 12 12 12 12 +eori 8 . d 0000101000000... .......... U U U U U U U 8 8 2 2 2 2 2 +eori 8 . . 0000101000...... A+-DXWL... U U U U U U U 12 12 4 4 4 4 4 +eori 16 . d 0000101001000... .......... U U U U U U U 8 8 2 2 2 2 2 +eori 16 . . 0000101001...... A+-DXWL... U U U U U U U 12 12 4 4 4 4 4 +eori 32 . d 0000101010000... .......... U U U U U U U 16 14 2 2 2 2 2 +eori 32 . . 0000101010...... A+-DXWL... U U U U U U U 20 20 4 4 4 4 4 +exg 32 dd . 1100...101000... .......... U U U U U U U 6 6 2 2 2 2 2 +exg 32 aa . 1100...101001... .......... U U U U U U U 6 6 2 2 2 2 2 +exg 32 da . 1100...110001... .......... U U U U U U U 6 6 2 2 2 2 2 +ext 16 . . 0100100010000... .......... U U U U U U U 4 4 4 4 4 4 4 +ext 32 . . 0100100011000... .......... U U U U U U U 4 4 4 4 4 4 4 +extb 32 . . 0100100111000... .......... . . U U U U U . . 4 4 4 4 4 +illegal 0 . . 0100101011111100 .......... U U U U U U U 4 4 4 4 4 4 4 +jmp 32 . . 0100111011...... A..DXWLdx. U U U U U U U 4 4 0 0 0 0 0 +jsr 32 . . 0100111010...... A..DXWLdx. U U U U U U U 12 12 0 0 0 0 0 +lea 32 . . 0100...111...... A..DXWLdx. U U U U U U U 0 0 2 2 2 2 2 +link 16 . a7 0100111001010111 .......... U U U U U U U 16 16 5 5 5 5 5 +link 16 . . 0100111001010... .......... U U U U U U U 16 16 5 5 5 5 5 +link 32 . a7 0100100000001111 .......... . . U U U U U . . 6 6 6 6 6 +link 32 . . 0100100000001... .......... . . U U U U U . . 6 6 6 6 6 +lsr 8 s . 1110...000001... .......... U U U U U U U 6 6 4 4 4 4 4 +lsr 16 s . 1110...001001... .......... U U U U U U U 6 6 4 4 4 4 4 +lsr 32 s . 1110...010001... .......... U U U U U U U 8 8 4 4 4 4 4 +lsr 8 r . 1110...000101... .......... U U U U U U U 6 6 6 6 6 6 6 +lsr 16 r . 1110...001101... .......... U U U U U U U 6 6 6 6 6 6 6 +lsr 32 r . 1110...010101... .......... U U U U U U U 8 8 6 6 6 6 6 +lsr 16 . . 1110001011...... A+-DXWL... U U U U U U U 8 8 5 5 5 5 5 +lsl 8 s . 1110...100001... .......... U U U U U U U 6 6 4 4 4 4 4 +lsl 16 s . 1110...101001... .......... U U U U U U U 6 6 4 4 4 4 4 +lsl 32 s . 1110...110001... .......... U U U U U U U 8 8 4 4 4 4 4 +lsl 8 r . 1110...100101... .......... U U U U U U U 6 6 6 6 6 6 6 +lsl 16 r . 1110...101101... .......... U U U U U U U 6 6 6 6 6 6 6 +lsl 32 r . 1110...110101... .......... U U U U U U U 8 8 6 6 6 6 6 +lsl 16 . . 1110001111...... A+-DXWL... U U U U U U U 8 8 5 5 5 5 5 +move 8 d d 0001...000000... .......... U U U U U U U 4 4 2 2 2 2 2 +move 8 d . 0001...000...... A+-DXWLdxI U U U U U U U 4 4 2 2 2 2 2 +move 8 ai d 0001...010000... .......... U U U U U U U 8 8 4 4 4 4 4 +move 8 ai . 0001...010...... A+-DXWLdxI U U U U U U U 8 8 4 4 4 4 4 +move 8 pi d 0001...011000... .......... U U U U U U U 8 8 4 4 4 4 4 +move 8 pi . 0001...011...... A+-DXWLdxI U U U U U U U 8 8 4 4 4 4 4 +move 8 pi7 d 0001111011000... .......... U U U U U U U 8 8 4 4 4 4 4 +move 8 pi7 . 0001111011...... A+-DXWLdxI U U U U U U U 8 8 4 4 4 4 4 +move 8 pd d 0001...100000... .......... U U U U U U U 8 8 5 5 5 5 5 +move 8 pd . 0001...100...... A+-DXWLdxI U U U U U U U 8 8 5 5 5 5 5 +move 8 pd7 d 0001111100000... .......... U U U U U U U 8 8 5 5 5 5 5 +move 8 pd7 . 0001111100...... A+-DXWLdxI U U U U U U U 8 8 5 5 5 5 5 +move 8 di d 0001...101000... .......... U U U U U U U 12 12 5 5 5 5 5 +move 8 di . 0001...101...... A+-DXWLdxI U U U U U U U 12 12 5 5 5 5 5 +move 8 ix d 0001...110000... .......... U U U U U U U 14 14 7 7 7 7 7 +move 8 ix . 0001...110...... A+-DXWLdxI U U U U U U U 14 14 7 7 7 7 7 +move 8 aw d 0001000111000... .......... U U U U U U U 12 12 4 4 4 4 4 +move 8 aw . 0001000111...... A+-DXWLdxI U U U U U U U 12 12 4 4 4 4 4 +move 8 al d 0001001111000... .......... U U U U U U U 16 16 6 6 6 6 6 +move 8 al . 0001001111...... A+-DXWLdxI U U U U U U U 16 16 6 6 6 6 6 +move 16 d d 0011...000000... .......... U U U U U U U 4 4 2 2 2 2 2 +move 16 d a 0011...000001... .......... U U U U U U U 4 4 2 2 2 2 2 +move 16 d . 0011...000...... A+-DXWLdxI U U U U U U U 4 4 2 2 2 2 2 +move 16 ai d 0011...010000... .......... U U U U U U U 8 8 4 4 4 4 4 +move 16 ai a 0011...010001... .......... U U U U U U U 8 8 4 4 4 4 4 +move 16 ai . 0011...010...... A+-DXWLdxI U U U U U U U 8 8 4 4 4 4 4 +move 16 pi d 0011...011000... .......... U U U U U U U 8 8 4 4 4 4 4 +move 16 pi a 0011...011001... .......... U U U U U U U 8 8 4 4 4 4 4 +move 16 pi . 0011...011...... A+-DXWLdxI U U U U U U U 8 8 4 4 4 4 4 +move 16 pd d 0011...100000... .......... U U U U U U U 8 8 5 5 5 5 5 +move 16 pd a 0011...100001... .......... U U U U U U U 8 8 5 5 5 5 5 +move 16 pd . 0011...100...... A+-DXWLdxI U U U U U U U 8 8 5 5 5 5 5 +move 16 di d 0011...101000... .......... U U U U U U U 12 12 5 5 5 5 5 +move 16 di a 0011...101001... .......... U U U U U U U 12 12 5 5 5 5 5 +move 16 di . 0011...101...... A+-DXWLdxI U U U U U U U 12 12 5 5 5 5 5 +move 16 ix d 0011...110000... .......... U U U U U U U 14 14 7 7 7 7 7 +move 16 ix a 0011...110001... .......... U U U U U U U 14 14 7 7 7 7 7 +move 16 ix . 0011...110...... A+-DXWLdxI U U U U U U U 14 14 7 7 7 7 7 +move 16 aw d 0011000111000... .......... U U U U U U U 12 12 4 4 4 4 4 +move 16 aw a 0011000111001... .......... U U U U U U U 12 12 4 4 4 4 4 +move 16 aw . 0011000111...... A+-DXWLdxI U U U U U U U 12 12 4 4 4 4 4 +move 16 al d 0011001111000... .......... U U U U U U U 16 16 6 6 6 6 6 +move 16 al a 0011001111001... .......... U U U U U U U 16 16 6 6 6 6 6 +move 16 al . 0011001111...... A+-DXWLdxI U U U U U U U 16 16 6 6 6 6 6 +move 32 d d 0010...000000... .......... U U U U U U U 4 4 2 2 2 2 2 +move 32 d a 0010...000001... .......... U U U U U U U 4 4 2 2 2 2 2 +move 32 d . 0010...000...... A+-DXWLdxI U U U U U U U 4 4 2 2 2 2 2 +move 32 ai d 0010...010000... .......... U U U U U U U 12 12 4 4 4 4 4 +move 32 ai a 0010...010001... .......... U U U U U U U 12 12 4 4 4 4 4 +move 32 ai . 0010...010...... A+-DXWLdxI U U U U U U U 12 12 4 4 4 4 4 +move 32 pi d 0010...011000... .......... U U U U U U U 12 12 4 4 4 4 4 +move 32 pi a 0010...011001... .......... U U U U U U U 12 12 4 4 4 4 4 +move 32 pi . 0010...011...... A+-DXWLdxI U U U U U U U 12 12 4 4 4 4 4 +move 32 pd d 0010...100000... .......... U U U U U U U 12 14 5 5 5 5 5 +move 32 pd a 0010...100001... .......... U U U U U U U 12 14 5 5 5 5 5 +move 32 pd . 0010...100...... A+-DXWLdxI U U U U U U U 12 14 5 5 5 5 5 +move 32 di d 0010...101000... .......... U U U U U U U 16 16 5 5 5 5 5 +move 32 di a 0010...101001... .......... U U U U U U U 16 16 5 5 5 5 5 +move 32 di . 0010...101...... A+-DXWLdxI U U U U U U U 16 16 5 5 5 5 5 +move 32 ix d 0010...110000... .......... U U U U U U U 18 18 7 7 7 7 7 +move 32 ix a 0010...110001... .......... U U U U U U U 18 18 7 7 7 7 7 +move 32 ix . 0010...110...... A+-DXWLdxI U U U U U U U 18 18 7 7 7 7 7 +move 32 aw d 0010000111000... .......... U U U U U U U 16 16 4 4 4 4 4 +move 32 aw a 0010000111001... .......... U U U U U U U 16 16 4 4 4 4 4 +move 32 aw . 0010000111...... A+-DXWLdxI U U U U U U U 16 16 4 4 4 4 4 +move 32 al d 0010001111000... .......... U U U U U U U 20 20 6 6 6 6 6 +move 32 al a 0010001111001... .......... U U U U U U U 20 20 6 6 6 6 6 +move 32 al . 0010001111...... A+-DXWLdxI U U U U U U U 20 20 6 6 6 6 6 +movea 16 . d 0011...001000... .......... U U U U U U U 4 4 2 2 2 2 2 +movea 16 . a 0011...001001... .......... U U U U U U U 4 4 2 2 2 2 2 +movea 16 . . 0011...001...... A+-DXWLdxI U U U U U U U 4 4 2 2 2 2 2 +movea 32 . d 0010...001000... .......... U U U U U U U 4 4 2 2 2 2 2 +movea 32 . a 0010...001001... .......... U U U U U U U 4 4 2 2 2 2 2 +movea 32 . . 0010...001...... A+-DXWLdxI U U U U U U U 4 4 2 2 2 2 2 +move 16 frc d 0100001011000... .......... . U U U U U U . 4 4 4 4 4 4 +move 16 frc . 0100001011...... A+-DXWL... . U U U U U U . 8 4 4 4 4 4 +move 16 toc d 0100010011000... .......... U U U U U U U 12 12 4 4 4 4 4 +move 16 toc . 0100010011...... A+-DXWLdxI U U U U U U U 12 12 4 4 4 4 4 +move 16 frs d 0100000011000... .......... U S S S S S S 6 4 8 8 8 8 8 U only for 000 +move 16 frs . 0100000011...... A+-DXWL... U S S S S S S 8 8 8 8 8 8 8 U only for 000 +move 16 tos d 0100011011000... .......... S S S S S S S 12 12 8 8 8 8 8 +move 16 tos . 0100011011...... A+-DXWLdxI S S S S S S S 12 12 8 8 8 8 8 +move 32 fru . 0100111001101... .......... S S S S S S S 4 6 2 2 2 2 2 +move 32 tou . 0100111001100... .......... S S S S S S S 4 6 2 2 2 2 2 +movec 32 cr . 0100111001111010 .......... . S S S S S S . 12 6 6 6 6 6 +movec 32 rc . 0100111001111011 .......... . S S S S S S . 10 12 12 12 12 12 +movem 16 re pd 0100100010100... .......... U U U U U U U 8 8 4 4 4 4 4 +movem 16 re . 0100100010...... A..DXWL... U U U U U U U 8 8 4 4 4 4 4 +movem 32 re pd 0100100011100... .......... U U U U U U U 8 8 4 4 4 4 4 +movem 32 re . 0100100011...... A..DXWL... U U U U U U U 8 8 4 4 4 4 4 +movem 16 er pi 0100110010011... .......... U U U U U U U 12 12 8 8 8 8 8 +movem 16 er pcdi 0100110010111010 .......... U U U U U U U 16 16 9 9 9 9 9 +movem 16 er pcix 0100110010111011 .......... U U U U U U U 18 18 11 11 11 11 11 +movem 16 er . 0100110010...... A..DXWL... U U U U U U U 12 12 8 8 8 8 8 +movem 32 er pi 0100110011011... .......... U U U U U U U 12 12 8 8 8 8 8 +movem 32 er pcdi 0100110011111010 .......... U U U U U U U 16 16 9 9 9 9 9 +movem 32 er pcix 0100110011111011 .......... U U U U U U U 18 18 11 11 11 11 11 +movem 32 er . 0100110011...... A..DXWL... U U U U U U U 12 12 8 8 8 8 8 +movep 16 er . 0000...100001... .......... U U U U U U U 16 16 12 12 12 12 12 +movep 32 er . 0000...101001... .......... U U U U U U U 24 24 18 18 18 18 18 +movep 16 re . 0000...110001... .......... U U U U U U U 16 16 11 11 11 11 11 +movep 32 re . 0000...111001... .......... U U U U U U U 24 24 17 17 17 17 17 +moveq 32 . . 0111...0........ .......... U U U U U U U 4 4 2 2 2 2 2 +moves 8 . . 0000111000...... A+-DXWL... . S S S S S S . 14 5 5 5 5 5 +moves 16 . . 0000111001...... A+-DXWL... . S S S S S S . 14 5 5 5 5 5 +moves 32 . . 0000111010...... A+-DXWL... . S S S S S S . 16 5 5 5 5 5 +move16 32 . . 1111011000100... .......... . . . . U U . . . . . 4 4 4 TODO: correct timing +muls 16 . d 1100...111000... .......... U U U U U U U 54 32 27 27 27 27 27 +muls 16 . . 1100...111...... A+-DXWLdxI U U U U U U U 54 32 27 27 27 27 27 +mulu 16 . d 1100...011000... .......... U U U U U U U 54 30 27 27 27 27 27 +mulu 16 . . 1100...011...... A+-DXWLdxI U U U U U U U 54 30 27 27 27 27 27 +mull 32 . d 0100110000000... .......... . . U U U U U . . 43 43 43 43 43 +mull 32 . . 0100110000...... A+-DXWLdxI . . U U U U U . . 43 43 43 43 43 +nbcd 8 . d 0100100000000... .......... U U U U U U U 6 6 6 6 6 6 6 +nbcd 8 . . 0100100000...... A+-DXWL... U U U U U U U 8 8 6 6 6 6 6 +neg 8 . d 0100010000000... .......... U U U U U U U 4 4 2 2 2 2 2 +neg 8 . . 0100010000...... A+-DXWL... U U U U U U U 8 8 4 4 4 4 4 +neg 16 . d 0100010001000... .......... U U U U U U U 4 4 2 2 2 2 2 +neg 16 . . 0100010001...... A+-DXWL... U U U U U U U 8 8 4 4 4 4 4 +neg 32 . d 0100010010000... .......... U U U U U U U 6 6 2 2 2 2 2 +neg 32 . . 0100010010...... A+-DXWL... U U U U U U U 12 12 4 4 4 4 4 +negx 8 . d 0100000000000... .......... U U U U U U U 4 4 2 2 2 2 2 +negx 8 . . 0100000000...... A+-DXWL... U U U U U U U 8 8 4 4 4 4 4 +negx 16 . d 0100000001000... .......... U U U U U U U 4 4 2 2 2 2 2 +negx 16 . . 0100000001...... A+-DXWL... U U U U U U U 8 8 4 4 4 4 4 +negx 32 . d 0100000010000... .......... U U U U U U U 6 6 2 2 2 2 2 +negx 32 . . 0100000010...... A+-DXWL... U U U U U U U 12 12 4 4 4 4 4 +nop 0 . . 0100111001110001 .......... U U U U U U U 4 4 2 2 2 2 2 +not 8 . d 0100011000000... .......... U U U U U U U 4 4 2 2 2 2 2 +not 8 . . 0100011000...... A+-DXWL... U U U U U U U 8 8 4 4 4 4 4 +not 16 . d 0100011001000... .......... U U U U U U U 4 4 2 2 2 2 2 +not 16 . . 0100011001...... A+-DXWL... U U U U U U U 8 8 4 4 4 4 4 +not 32 . d 0100011010000... .......... U U U U U U U 6 6 2 2 2 2 2 +not 32 . . 0100011010...... A+-DXWL... U U U U U U U 12 12 4 4 4 4 4 +or 8 er d 1000...000000... .......... U U U U U U U 4 4 2 2 2 2 2 +or 8 er . 1000...000...... A+-DXWLdxI U U U U U U U 4 4 2 2 2 2 2 +or 16 er d 1000...001000... .......... U U U U U U U 4 4 2 2 2 2 2 +or 16 er . 1000...001...... A+-DXWLdxI U U U U U U U 4 4 2 2 2 2 2 +or 32 er d 1000...010000... .......... U U U U U U U 6 6 2 2 2 2 2 +or 32 er . 1000...010...... A+-DXWLdxI U U U U U U U 6 6 2 2 2 2 2 +or 8 re . 1000...100...... A+-DXWL... U U U U U U U 8 8 4 4 4 4 4 +or 16 re . 1000...101...... A+-DXWL... U U U U U U U 8 8 4 4 4 4 4 +or 32 re . 1000...110...... A+-DXWL... U U U U U U U 12 12 4 4 4 4 4 +ori 16 toc . 0000000000111100 .......... U U U U U U U 20 16 12 12 12 12 12 +ori 16 tos . 0000000001111100 .......... S S S S S S S 20 16 12 12 12 12 12 +ori 8 . d 0000000000000... .......... U U U U U U U 8 8 2 2 2 2 2 +ori 8 . . 0000000000...... A+-DXWL... U U U U U U U 12 12 4 4 4 4 4 +ori 16 . d 0000000001000... .......... U U U U U U U 8 8 2 2 2 2 2 +ori 16 . . 0000000001...... A+-DXWL... U U U U U U U 12 12 4 4 4 4 4 +ori 32 . d 0000000010000... .......... U U U U U U U 16 14 2 2 2 2 2 +ori 32 . . 0000000010...... A+-DXWL... U U U U U U U 20 20 4 4 4 4 4 +pack 16 rr . 1000...101000... .......... . . U U U U U . . 6 6 6 6 6 +pack 16 mm ax7 1000111101001... .......... . . U U U U U . . 13 13 13 13 13 +pack 16 mm ay7 1000...101001111 .......... . . U U U U U . . 13 13 13 13 13 +pack 16 mm axy7 1000111101001111 .......... . . U U U U U . . 13 13 13 13 13 +pack 16 mm . 1000...101001... .......... . . U U U U U . . 13 13 13 13 13 +pea 32 . . 0100100001...... A..DXWLdx. U U U U U U U 6 6 5 5 5 5 5 +pflusha 32 . . 1111010100011... .......... . . . . S S . . . . . 4 4 4 TODO: correct timing +pflushan 32 . . 1111010100010... .......... . . . . S S . . . . . 4 4 4 TODO: correct timing +pmmu 32 . . 1111000......... .......... . . S S S S S . . 8 8 8 8 8 +ptest 32 . . 1111010101.01... .......... . . . . S . . . . . . 8 . . +reset 0 . . 0100111001110000 .......... S S S S S S S 0 0 0 0 0 0 0 +ror 8 s . 1110...000011... .......... U U U U U U U 6 6 8 8 8 8 8 +ror 16 s . 1110...001011... .......... U U U U U U U 6 6 8 8 8 8 8 +ror 32 s . 1110...010011... .......... U U U U U U U 8 8 8 8 8 8 8 +ror 8 r . 1110...000111... .......... U U U U U U U 6 6 8 8 8 8 8 +ror 16 r . 1110...001111... .......... U U U U U U U 6 6 8 8 8 8 8 +ror 32 r . 1110...010111... .......... U U U U U U U 8 8 8 8 8 8 8 +ror 16 . . 1110011011...... A+-DXWL... U U U U U U U 8 8 7 7 7 7 7 +rol 8 s . 1110...100011... .......... U U U U U U U 6 6 8 8 8 8 8 +rol 16 s . 1110...101011... .......... U U U U U U U 6 6 8 8 8 8 8 +rol 32 s . 1110...110011... .......... U U U U U U U 8 8 8 8 8 8 8 +rol 8 r . 1110...100111... .......... U U U U U U U 6 6 8 8 8 8 8 +rol 16 r . 1110...101111... .......... U U U U U U U 6 6 8 8 8 8 8 +rol 32 r . 1110...110111... .......... U U U U U U U 8 8 8 8 8 8 8 +rol 16 . . 1110011111...... A+-DXWL... U U U U U U U 8 8 7 7 7 7 7 +roxr 8 s . 1110...000010... .......... U U U U U U U 6 6 12 12 12 12 12 +roxr 16 s . 1110...001010... .......... U U U U U U U 6 6 12 12 12 12 12 +roxr 32 s . 1110...010010... .......... U U U U U U U 8 8 12 12 12 12 12 +roxr 8 r . 1110...000110... .......... U U U U U U U 6 6 12 12 12 12 12 +roxr 16 r . 1110...001110... .......... U U U U U U U 6 6 12 12 12 12 12 +roxr 32 r . 1110...010110... .......... U U U U U U U 8 8 12 12 12 12 12 +roxr 16 . . 1110010011...... A+-DXWL... U U U U U U U 8 8 5 5 5 5 5 +roxl 8 s . 1110...100010... .......... U U U U U U U 6 6 12 12 12 12 12 +roxl 16 s . 1110...101010... .......... U U U U U U U 6 6 12 12 12 12 12 +roxl 32 s . 1110...110010... .......... U U U U U U U 8 8 12 12 12 12 12 +roxl 8 r . 1110...100110... .......... U U U U U U U 6 6 12 12 12 12 12 +roxl 16 r . 1110...101110... .......... U U U U U U U 6 6 12 12 12 12 12 +roxl 32 r . 1110...110110... .......... U U U U U U U 8 8 12 12 12 12 12 +roxl 16 . . 1110010111...... A+-DXWL... U U U U U U U 8 8 5 5 5 5 5 +rtd 32 . . 0100111001110100 .......... . U U U U U U . 16 10 10 10 10 10 +rte 32 . . 0100111001110011 .......... S S S S S S S 20 24 20 20 20 20 20 bus fault not emulated +rtm 32 . . 000001101100.... .......... . . U U U U U . . 19 19 19 19 19 not properly emulated +rtr 32 . . 0100111001110111 .......... U U U U U U U 20 20 14 14 14 14 14 +rts 32 . . 0100111001110101 .......... U U U U U U U 16 16 10 10 10 10 10 +sbcd 8 rr . 1000...100000... .......... U U U U U U U 6 6 4 4 4 4 4 +sbcd 8 mm ax7 1000111100001... .......... U U U U U U U 18 18 16 16 16 16 16 +sbcd 8 mm ay7 1000...100001111 .......... U U U U U U U 18 18 16 16 16 16 16 +sbcd 8 mm axy7 1000111100001111 .......... U U U U U U U 18 18 16 16 16 16 16 +sbcd 8 mm . 1000...100001... .......... U U U U U U U 18 18 16 16 16 16 16 +st 8 . d 0101000011000... .......... U U U U U U U 6 4 4 4 4 4 4 +st 8 . . 0101000011...... A+-DXWL... U U U U U U U 8 8 6 6 6 6 6 +sf 8 . d 0101000111000... .......... U U U U U U U 4 4 4 4 4 4 4 +sf 8 . . 0101000111...... A+-DXWL... U U U U U U U 8 8 6 6 6 6 6 +scc 8 . d 0101....11000... .......... U U U U U U U 4 4 4 4 4 4 4 +scc 8 . . 0101....11...... A+-DXWL... U U U U U U U 8 8 6 6 6 6 6 +stop 0 . . 0100111001110010 .......... S S S S S S S 4 4 8 8 8 8 8 +sub 8 er d 1001...000000... .......... U U U U U U U 4 4 2 2 2 2 2 +sub 8 er . 1001...000...... A+-DXWLdxI U U U U U U U 4 4 2 2 2 2 2 +sub 16 er d 1001...001000... .......... U U U U U U U 4 4 2 2 2 2 2 +sub 16 er a 1001...001001... .......... U U U U U U U 4 4 2 2 2 2 2 +sub 16 er . 1001...001...... A+-DXWLdxI U U U U U U U 4 4 2 2 2 2 2 +sub 32 er d 1001...010000... .......... U U U U U U U 6 6 2 2 2 2 2 +sub 32 er a 1001...010001... .......... U U U U U U U 6 6 2 2 2 2 2 +sub 32 er . 1001...010...... A+-DXWLdxI U U U U U U U 6 6 2 2 2 2 2 +sub 8 re . 1001...100...... A+-DXWL... U U U U U U U 8 8 4 4 4 4 4 +sub 16 re . 1001...101...... A+-DXWL... U U U U U U U 8 8 4 4 4 4 4 +sub 32 re . 1001...110...... A+-DXWL... U U U U U U U 12 12 4 4 4 4 4 +suba 16 . d 1001...011000... .......... U U U U U U U 8 8 2 2 2 2 2 +suba 16 . a 1001...011001... .......... U U U U U U U 8 8 2 2 2 2 2 +suba 16 . . 1001...011...... A+-DXWLdxI U U U U U U U 8 8 2 2 2 2 2 +suba 32 . d 1001...111000... .......... U U U U U U U 6 6 2 2 2 2 2 +suba 32 . a 1001...111001... .......... U U U U U U U 6 6 2 2 2 2 2 +suba 32 . . 1001...111...... A+-DXWLdxI U U U U U U U 6 6 2 2 2 2 2 +subi 8 . d 0000010000000... .......... U U U U U U U 8 8 2 2 2 2 2 +subi 8 . . 0000010000...... A+-DXWL... U U U U U U U 12 12 4 4 4 4 4 +subi 16 . d 0000010001000... .......... U U U U U U U 8 8 2 2 2 2 2 +subi 16 . . 0000010001...... A+-DXWL... U U U U U U U 12 12 4 4 4 4 4 +subi 32 . d 0000010010000... .......... U U U U U U U 16 14 2 2 2 2 2 +subi 32 . . 0000010010...... A+-DXWL... U U U U U U U 20 20 4 4 4 4 4 +subq 8 . d 0101...100000... .......... U U U U U U U 4 4 2 2 2 2 2 +subq 8 . . 0101...100...... A+-DXWL... U U U U U U U 8 8 4 4 4 4 4 +subq 16 . d 0101...101000... .......... U U U U U U U 4 4 2 2 2 2 2 +subq 16 . a 0101...101001... .......... U U U U U U U 8 4 2 2 2 2 2 +subq 16 . . 0101...101...... A+-DXWL... U U U U U U U 8 8 4 4 4 4 4 +subq 32 . d 0101...110000... .......... U U U U U U U 8 8 2 2 2 2 2 +subq 32 . a 0101...110001... .......... U U U U U U U 8 8 2 2 2 2 2 +subq 32 . . 0101...110...... A+-DXWL... U U U U U U U 12 12 4 4 4 4 4 +subx 8 rr . 1001...100000... .......... U U U U U U U 4 4 2 2 2 2 2 +subx 16 rr . 1001...101000... .......... U U U U U U U 4 4 2 2 2 2 2 +subx 32 rr . 1001...110000... .......... U U U U U U U 8 6 2 2 2 2 2 +subx 8 mm ax7 1001111100001... .......... U U U U U U U 18 18 12 12 12 12 12 +subx 8 mm ay7 1001...100001111 .......... U U U U U U U 18 18 12 12 12 12 12 +subx 8 mm axy7 1001111100001111 .......... U U U U U U U 18 18 12 12 12 12 12 +subx 8 mm . 1001...100001... .......... U U U U U U U 18 18 12 12 12 12 12 +subx 16 mm . 1001...101001... .......... U U U U U U U 18 18 12 12 12 12 12 +subx 32 mm . 1001...110001... .......... U U U U U U U 30 30 12 12 12 12 12 +swap 32 . . 0100100001000... .......... U U U U U U U 4 4 4 4 4 4 4 +tas 8 . d 0100101011000... .......... U U U U U U U 4 4 4 4 4 4 4 +tas 8 . . 0100101011...... A+-DXWL... U U U U U U U 14 14 12 12 12 12 12 +trap 0 . . 010011100100.... .......... U U U U U U U 4 4 4 4 4 4 4 +trapt 0 . . 0101000011111100 .......... . . U U U U U . . 4 4 4 4 4 +trapt 16 . . 0101000011111010 .......... . . U U U U U . . 6 6 6 6 6 +trapt 32 . . 0101000011111011 .......... . . U U U U U . . 8 8 8 8 8 +trapf 0 . . 0101000111111100 .......... . . U U U U U . . 4 4 4 4 4 +trapf 16 . . 0101000111111010 .......... . . U U U U U . . 6 6 6 6 6 +trapf 32 . . 0101000111111011 .......... . . U U U U U . . 8 8 8 8 8 +trapcc 0 . . 0101....11111100 .......... . . U U U U U . . 4 4 4 4 4 +trapcc 16 . . 0101....11111010 .......... . . U U U U U . . 6 6 6 6 6 +trapcc 32 . . 0101....11111011 .......... . . U U U U U . . 8 8 8 8 8 +trapv 0 . . 0100111001110110 .......... U U U U U U U 4 4 4 4 4 4 4 +tst 8 . d 0100101000000... .......... U U U U U U U 4 4 2 2 2 2 2 +tst 8 . . 0100101000...... A+-DXWL... U U U U U U U 4 4 2 2 2 2 2 +tst 8 . pcdi 0100101000111010 .......... . . U U U U U . . 7 7 7 7 7 +tst 8 . pcix 0100101000111011 .......... . . U U U U U . . 9 9 9 9 9 +tst 8 . i 0100101000111100 .......... . . U U U U U . . 6 6 6 6 6 +tst 16 . d 0100101001000... .......... U U U U U U U 4 4 2 2 2 2 2 +tst 16 . a 0100101001001... .......... . . U U U U U . . 2 2 2 2 2 +tst 16 . . 0100101001...... A+-DXWL... U U U U U U U 4 4 2 2 2 2 2 +tst 16 . pcdi 0100101001111010 .......... . . U U U U U . . 7 7 7 7 7 +tst 16 . pcix 0100101001111011 .......... . . U U U U U . . 9 9 9 9 9 +tst 16 . i 0100101001111100 .......... . . U U U U U . . 6 6 6 6 6 +tst 32 . d 0100101010000... .......... U U U U U U U 4 4 2 2 2 2 2 +tst 32 . a 0100101010001... .......... . . U U U U U . . 2 2 2 2 2 +tst 32 . . 0100101010...... A+-DXWL... U U U U U U U 4 4 2 2 2 2 2 +tst 32 . pcdi 0100101010111010 .......... . . U U U U U . . 7 7 7 7 7 +tst 32 . pcix 0100101010111011 .......... . . U U U U U . . 9 9 9 9 9 +tst 32 . i 0100101010111100 .......... . . U U U U U . . 6 6 6 6 6 +unlk 32 . a7 0100111001011111 .......... U U U U U U U 12 12 6 6 6 6 6 +unlk 32 . . 0100111001011... .......... U U U U U U U 12 12 6 6 6 6 6 +unpk 16 rr . 1000...110000... .......... . . U U U U U . . 8 8 8 8 8 +unpk 16 mm ax7 1000111110001... .......... . . U U U U U . . 13 13 13 13 13 +unpk 16 mm ay7 1000...110001111 .......... . . U U U U U . . 13 13 13 13 13 +unpk 16 mm axy7 1000111110001111 .......... . . U U U U U . . 13 13 13 13 13 +unpk 16 mm . 1000...110001... .......... . . U U U U U . . 13 13 13 13 13 + + + +XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +M68KMAKE_OPCODE_HANDLER_BODY + +M68KMAKE_OP(1010, 0, ., .) +{ + m68ki_exception_1010(mc68kcpu); +} + + +M68KMAKE_OP(1111, 0, ., .) +{ + m68ki_exception_1111(mc68kcpu); +} + + +M68KMAKE_OP(040fpu0, 32, ., .) +{ + if((mc68kcpu)->has_fpu) + { + m68040_fpu_op0(mc68kcpu); + return; + } + m68ki_exception_1111(mc68kcpu); +} + + +M68KMAKE_OP(040fpu1, 32, ., .) +{ + if((mc68kcpu)->has_fpu) + { + m68040_fpu_op1(mc68kcpu); + return; + } + m68ki_exception_1111(mc68kcpu); +} + + + +M68KMAKE_OP(abcd, 8, rr, .) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = DY(mc68kcpu); + UINT32 dst = *r_dst; + UINT32 res = LOW_NIBBLE(src) + LOW_NIBBLE(dst) + XFLAG_AS_1(mc68kcpu); + + (mc68kcpu)->v_flag = ~res; /* Undefined V behavior */ + + if(res > 9) + res += 6; + res += HIGH_NIBBLE(src) + HIGH_NIBBLE(dst); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = (res > 0x99) << 8; + if((mc68kcpu)->c_flag) + res -= 0xa0; + + (mc68kcpu)->v_flag &= res; /* Undefined V behavior part II */ + (mc68kcpu)->n_flag = NFLAG_8(res); /* Undefined N behavior */ + + res = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->not_z_flag |= res; + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; +} + + +M68KMAKE_OP(abcd, 8, mm, ax7) +{ + UINT32 src = OPER_AY_PD_8(mc68kcpu); + UINT32 ea = EA_A7_PD_8(mc68kcpu); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + UINT32 res = LOW_NIBBLE(src) + LOW_NIBBLE(dst) + XFLAG_AS_1(mc68kcpu); + + (mc68kcpu)->v_flag = ~res; /* Undefined V behavior */ + + if(res > 9) + res += 6; + res += HIGH_NIBBLE(src) + HIGH_NIBBLE(dst); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = (res > 0x99) << 8; + if((mc68kcpu)->c_flag) + res -= 0xa0; + + (mc68kcpu)->v_flag &= res; /* Undefined V behavior part II */ + (mc68kcpu)->n_flag = NFLAG_8(res); /* Undefined N behavior */ + + res = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->not_z_flag |= res; + + m68ki_write_8((mc68kcpu), ea, res); +} + + +M68KMAKE_OP(abcd, 8, mm, ay7) +{ + UINT32 src = OPER_A7_PD_8(mc68kcpu); + UINT32 ea = EA_AX_PD_8(mc68kcpu); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + UINT32 res = LOW_NIBBLE(src) + LOW_NIBBLE(dst) + XFLAG_AS_1(mc68kcpu); + + (mc68kcpu)->v_flag = ~res; /* Undefined V behavior */ + + if(res > 9) + res += 6; + res += HIGH_NIBBLE(src) + HIGH_NIBBLE(dst); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = (res > 0x99) << 8; + if((mc68kcpu)->c_flag) + res -= 0xa0; + + (mc68kcpu)->v_flag &= res; /* Undefined V behavior part II */ + (mc68kcpu)->n_flag = NFLAG_8(res); /* Undefined N behavior */ + + res = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->not_z_flag |= res; + + m68ki_write_8((mc68kcpu), ea, res); +} + + +M68KMAKE_OP(abcd, 8, mm, axy7) +{ + UINT32 src = OPER_A7_PD_8(mc68kcpu); + UINT32 ea = EA_A7_PD_8(mc68kcpu); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + UINT32 res = LOW_NIBBLE(src) + LOW_NIBBLE(dst) + XFLAG_AS_1(mc68kcpu); + + (mc68kcpu)->v_flag = ~res; /* Undefined V behavior */ + + if(res > 9) + res += 6; + res += HIGH_NIBBLE(src) + HIGH_NIBBLE(dst); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = (res > 0x99) << 8; + if((mc68kcpu)->c_flag) + res -= 0xa0; + + (mc68kcpu)->v_flag &= res; /* Undefined V behavior part II */ + (mc68kcpu)->n_flag = NFLAG_8(res); /* Undefined N behavior */ + + res = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->not_z_flag |= res; + + m68ki_write_8((mc68kcpu), ea, res); +} + + +M68KMAKE_OP(abcd, 8, mm, .) +{ + UINT32 src = OPER_AY_PD_8(mc68kcpu); + UINT32 ea = EA_AX_PD_8(mc68kcpu); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + UINT32 res = LOW_NIBBLE(src) + LOW_NIBBLE(dst) + XFLAG_AS_1(mc68kcpu); + + (mc68kcpu)->v_flag = ~res; /* Undefined V behavior */ + + if(res > 9) + res += 6; + res += HIGH_NIBBLE(src) + HIGH_NIBBLE(dst); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = (res > 0x99) << 8; + if((mc68kcpu)->c_flag) + res -= 0xa0; + + (mc68kcpu)->v_flag &= res; /* Undefined V behavior part II */ + (mc68kcpu)->n_flag = NFLAG_8(res); /* Undefined N behavior */ + + res = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->not_z_flag |= res; + + m68ki_write_8((mc68kcpu), ea, res); +} + + +M68KMAKE_OP(add, 8, er, d) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = MASK_OUT_ABOVE_8(DY(mc68kcpu)); + UINT32 dst = MASK_OUT_ABOVE_8(*r_dst); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_ADD_8(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | (mc68kcpu)->not_z_flag; +} + + +M68KMAKE_OP(add, 8, er, .) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = M68KMAKE_GET_OPER_AY_8; + UINT32 dst = MASK_OUT_ABOVE_8(*r_dst); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_ADD_8(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | (mc68kcpu)->not_z_flag; +} + + +M68KMAKE_OP(add, 16, er, d) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = MASK_OUT_ABOVE_16(DY(mc68kcpu)); + UINT32 dst = MASK_OUT_ABOVE_16(*r_dst); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->v_flag = VFLAG_ADD_16(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | (mc68kcpu)->not_z_flag; +} + + +M68KMAKE_OP(add, 16, er, a) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = MASK_OUT_ABOVE_16(AY(mc68kcpu)); + UINT32 dst = MASK_OUT_ABOVE_16(*r_dst); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->v_flag = VFLAG_ADD_16(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | (mc68kcpu)->not_z_flag; +} + + +M68KMAKE_OP(add, 16, er, .) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = M68KMAKE_GET_OPER_AY_16; + UINT32 dst = MASK_OUT_ABOVE_16(*r_dst); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->v_flag = VFLAG_ADD_16(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | (mc68kcpu)->not_z_flag; +} + + +M68KMAKE_OP(add, 32, er, d) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = DY(mc68kcpu); + UINT32 dst = *r_dst; + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->v_flag = VFLAG_ADD_32(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_ADD_32(src, dst, res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + + *r_dst = (mc68kcpu)->not_z_flag; +} + + +M68KMAKE_OP(add, 32, er, a) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = AY(mc68kcpu); + UINT32 dst = *r_dst; + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->v_flag = VFLAG_ADD_32(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_ADD_32(src, dst, res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + + *r_dst = (mc68kcpu)->not_z_flag; +} + + +M68KMAKE_OP(add, 32, er, .) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = M68KMAKE_GET_OPER_AY_32; + UINT32 dst = *r_dst; + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->v_flag = VFLAG_ADD_32(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_ADD_32(src, dst, res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + + *r_dst = (mc68kcpu)->not_z_flag; +} + + +M68KMAKE_OP(add, 8, re, .) +{ + UINT32 ea = M68KMAKE_GET_EA_AY_8; + UINT32 src = MASK_OUT_ABOVE_8(DX(mc68kcpu)); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_ADD_8(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + + m68ki_write_8((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +M68KMAKE_OP(add, 16, re, .) +{ + UINT32 ea = M68KMAKE_GET_EA_AY_16; + UINT32 src = MASK_OUT_ABOVE_16(DX(mc68kcpu)); + UINT32 dst = m68ki_read_16((mc68kcpu), ea); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->v_flag = VFLAG_ADD_16(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + + m68ki_write_16((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +M68KMAKE_OP(add, 32, re, .) +{ + UINT32 ea = M68KMAKE_GET_EA_AY_32; + UINT32 src = DX(mc68kcpu); + UINT32 dst = m68ki_read_32((mc68kcpu), ea); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->v_flag = VFLAG_ADD_32(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_ADD_32(src, dst, res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + + m68ki_write_32((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +M68KMAKE_OP(adda, 16, ., d) +{ + UINT32* r_dst = &AX(mc68kcpu); + + *r_dst = MASK_OUT_ABOVE_32(*r_dst + MAKE_INT_16(DY(mc68kcpu))); +} + + +M68KMAKE_OP(adda, 16, ., a) +{ + UINT32* r_dst = &AX(mc68kcpu); + + *r_dst = MASK_OUT_ABOVE_32(*r_dst + MAKE_INT_16(AY(mc68kcpu))); +} + + +M68KMAKE_OP(adda, 16, ., .) +{ + UINT32* r_dst = &AX(mc68kcpu); + UINT32 src = MAKE_INT_16(M68KMAKE_GET_OPER_AY_16); + + *r_dst = MASK_OUT_ABOVE_32(*r_dst + src); +} + + +M68KMAKE_OP(adda, 32, ., d) +{ + UINT32* r_dst = &AX(mc68kcpu); + + *r_dst = MASK_OUT_ABOVE_32(*r_dst + DY(mc68kcpu)); +} + + +M68KMAKE_OP(adda, 32, ., a) +{ + UINT32* r_dst = &AX(mc68kcpu); + + *r_dst = MASK_OUT_ABOVE_32(*r_dst + AY(mc68kcpu)); +} + + +M68KMAKE_OP(adda, 32, ., .) +{ + UINT32* r_dst = &AX(mc68kcpu); + UINT32 src = M68KMAKE_GET_OPER_AY_32; + + *r_dst = MASK_OUT_ABOVE_32(*r_dst + src); +} + + +M68KMAKE_OP(addi, 8, ., d) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 src = OPER_I_8(mc68kcpu); + UINT32 dst = MASK_OUT_ABOVE_8(*r_dst); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_ADD_8(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | (mc68kcpu)->not_z_flag; +} + + +M68KMAKE_OP(addi, 8, ., .) +{ + UINT32 src = OPER_I_8(mc68kcpu); + UINT32 ea = M68KMAKE_GET_EA_AY_8; + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_ADD_8(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + + m68ki_write_8((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +M68KMAKE_OP(addi, 16, ., d) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 src = OPER_I_16(mc68kcpu); + UINT32 dst = MASK_OUT_ABOVE_16(*r_dst); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->v_flag = VFLAG_ADD_16(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | (mc68kcpu)->not_z_flag; +} + + +M68KMAKE_OP(addi, 16, ., .) +{ + UINT32 src = OPER_I_16(mc68kcpu); + UINT32 ea = M68KMAKE_GET_EA_AY_16; + UINT32 dst = m68ki_read_16((mc68kcpu), ea); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->v_flag = VFLAG_ADD_16(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + + m68ki_write_16((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +M68KMAKE_OP(addi, 32, ., d) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 src = OPER_I_32(mc68kcpu); + UINT32 dst = *r_dst; + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->v_flag = VFLAG_ADD_32(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_ADD_32(src, dst, res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + + *r_dst = (mc68kcpu)->not_z_flag; +} + + +M68KMAKE_OP(addi, 32, ., .) +{ + UINT32 src = OPER_I_32(mc68kcpu); + UINT32 ea = M68KMAKE_GET_EA_AY_32; + UINT32 dst = m68ki_read_32((mc68kcpu), ea); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->v_flag = VFLAG_ADD_32(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_ADD_32(src, dst, res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + + m68ki_write_32((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +M68KMAKE_OP(addq, 8, ., d) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 src = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT32 dst = MASK_OUT_ABOVE_8(*r_dst); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_ADD_8(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | (mc68kcpu)->not_z_flag; +} + + +M68KMAKE_OP(addq, 8, ., .) +{ + UINT32 src = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT32 ea = M68KMAKE_GET_EA_AY_8; + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_ADD_8(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + + m68ki_write_8((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +M68KMAKE_OP(addq, 16, ., d) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 src = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT32 dst = MASK_OUT_ABOVE_16(*r_dst); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->v_flag = VFLAG_ADD_16(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | (mc68kcpu)->not_z_flag; +} + + +M68KMAKE_OP(addq, 16, ., a) +{ + UINT32* r_dst = &AY(mc68kcpu); + + *r_dst = MASK_OUT_ABOVE_32(*r_dst + ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1); +} + + +M68KMAKE_OP(addq, 16, ., .) +{ + UINT32 src = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT32 ea = M68KMAKE_GET_EA_AY_16; + UINT32 dst = m68ki_read_16((mc68kcpu), ea); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->v_flag = VFLAG_ADD_16(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + + m68ki_write_16((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +M68KMAKE_OP(addq, 32, ., d) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 src = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT32 dst = *r_dst; + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->v_flag = VFLAG_ADD_32(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_ADD_32(src, dst, res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + + *r_dst = (mc68kcpu)->not_z_flag; +} + + +M68KMAKE_OP(addq, 32, ., a) +{ + UINT32* r_dst = &AY(mc68kcpu); + + *r_dst = MASK_OUT_ABOVE_32(*r_dst + ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1); +} + + +M68KMAKE_OP(addq, 32, ., .) +{ + UINT32 src = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT32 ea = M68KMAKE_GET_EA_AY_32; + UINT32 dst = m68ki_read_32((mc68kcpu), ea); + UINT32 res = src + dst; + + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->v_flag = VFLAG_ADD_32(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_ADD_32(src, dst, res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + + m68ki_write_32((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +M68KMAKE_OP(addx, 8, rr, .) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = MASK_OUT_ABOVE_8(DY(mc68kcpu)); + UINT32 dst = MASK_OUT_ABOVE_8(*r_dst); + UINT32 res = src + dst + XFLAG_AS_1(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_ADD_8(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + + res = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->not_z_flag |= res; + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; +} + + +M68KMAKE_OP(addx, 16, rr, .) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = MASK_OUT_ABOVE_16(DY(mc68kcpu)); + UINT32 dst = MASK_OUT_ABOVE_16(*r_dst); + UINT32 res = src + dst + XFLAG_AS_1(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->v_flag = VFLAG_ADD_16(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_16(res); + + res = MASK_OUT_ABOVE_16(res); + (mc68kcpu)->not_z_flag |= res; + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; +} + + +M68KMAKE_OP(addx, 32, rr, .) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = DY(mc68kcpu); + UINT32 dst = *r_dst; + UINT32 res = src + dst + XFLAG_AS_1(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->v_flag = VFLAG_ADD_32(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_ADD_32(src, dst, res); + + res = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->not_z_flag |= res; + + *r_dst = res; +} + + +M68KMAKE_OP(addx, 8, mm, ax7) +{ + UINT32 src = OPER_AY_PD_8(mc68kcpu); + UINT32 ea = EA_A7_PD_8(mc68kcpu); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + UINT32 res = src + dst + XFLAG_AS_1(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_ADD_8(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + + res = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->not_z_flag |= res; + + m68ki_write_8((mc68kcpu), ea, res); +} + + +M68KMAKE_OP(addx, 8, mm, ay7) +{ + UINT32 src = OPER_A7_PD_8(mc68kcpu); + UINT32 ea = EA_AX_PD_8(mc68kcpu); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + UINT32 res = src + dst + XFLAG_AS_1(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_ADD_8(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + + res = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->not_z_flag |= res; + + m68ki_write_8((mc68kcpu), ea, res); +} + + +M68KMAKE_OP(addx, 8, mm, axy7) +{ + UINT32 src = OPER_A7_PD_8(mc68kcpu); + UINT32 ea = EA_A7_PD_8(mc68kcpu); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + UINT32 res = src + dst + XFLAG_AS_1(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_ADD_8(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + + res = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->not_z_flag |= res; + + m68ki_write_8((mc68kcpu), ea, res); +} + + +M68KMAKE_OP(addx, 8, mm, .) +{ + UINT32 src = OPER_AY_PD_8(mc68kcpu); + UINT32 ea = EA_AX_PD_8(mc68kcpu); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + UINT32 res = src + dst + XFLAG_AS_1(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_ADD_8(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + + res = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->not_z_flag |= res; + + m68ki_write_8((mc68kcpu), ea, res); +} + + +M68KMAKE_OP(addx, 16, mm, .) +{ + UINT32 src = OPER_AY_PD_16(mc68kcpu); + UINT32 ea = EA_AX_PD_16(mc68kcpu); + UINT32 dst = m68ki_read_16((mc68kcpu), ea); + UINT32 res = src + dst + XFLAG_AS_1(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->v_flag = VFLAG_ADD_16(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_16(res); + + res = MASK_OUT_ABOVE_16(res); + (mc68kcpu)->not_z_flag |= res; + + m68ki_write_16((mc68kcpu), ea, res); +} + + +M68KMAKE_OP(addx, 32, mm, .) +{ + UINT32 src = OPER_AY_PD_32(mc68kcpu); + UINT32 ea = EA_AX_PD_32(mc68kcpu); + UINT32 dst = m68ki_read_32((mc68kcpu), ea); + UINT32 res = src + dst + XFLAG_AS_1(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->v_flag = VFLAG_ADD_32(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_ADD_32(src, dst, res); + + res = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->not_z_flag |= res; + + m68ki_write_32((mc68kcpu), ea, res); +} + + +M68KMAKE_OP(and, 8, er, d) +{ + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(DX(mc68kcpu) &= (DY(mc68kcpu) | 0xffffff00)); + + (mc68kcpu)->n_flag = NFLAG_8((mc68kcpu)->not_z_flag); + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +M68KMAKE_OP(and, 8, er, .) +{ + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(DX(mc68kcpu) &= (M68KMAKE_GET_OPER_AY_8 | 0xffffff00)); + + (mc68kcpu)->n_flag = NFLAG_8((mc68kcpu)->not_z_flag); + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +M68KMAKE_OP(and, 16, er, d) +{ + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(DX(mc68kcpu) &= (DY(mc68kcpu) | 0xffff0000)); + + (mc68kcpu)->n_flag = NFLAG_16((mc68kcpu)->not_z_flag); + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +M68KMAKE_OP(and, 16, er, .) +{ + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(DX(mc68kcpu) &= (M68KMAKE_GET_OPER_AY_16 | 0xffff0000)); + + (mc68kcpu)->n_flag = NFLAG_16((mc68kcpu)->not_z_flag); + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +M68KMAKE_OP(and, 32, er, d) +{ + (mc68kcpu)->not_z_flag = DX(mc68kcpu) &= DY(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_32((mc68kcpu)->not_z_flag); + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +M68KMAKE_OP(and, 32, er, .) +{ + (mc68kcpu)->not_z_flag = DX(mc68kcpu) &= M68KMAKE_GET_OPER_AY_32; + + (mc68kcpu)->n_flag = NFLAG_32((mc68kcpu)->not_z_flag); + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +M68KMAKE_OP(and, 8, re, .) +{ + UINT32 ea = M68KMAKE_GET_EA_AY_8; + UINT32 res = DX(mc68kcpu) & m68ki_read_8((mc68kcpu), ea); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + + m68ki_write_8((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +M68KMAKE_OP(and, 16, re, .) +{ + UINT32 ea = M68KMAKE_GET_EA_AY_16; + UINT32 res = DX(mc68kcpu) & m68ki_read_16((mc68kcpu), ea); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + + m68ki_write_16((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +M68KMAKE_OP(and, 32, re, .) +{ + UINT32 ea = M68KMAKE_GET_EA_AY_32; + UINT32 res = DX(mc68kcpu) & m68ki_read_32((mc68kcpu), ea); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + + m68ki_write_32((mc68kcpu), ea, res); +} + + +M68KMAKE_OP(andi, 8, ., d) +{ + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(DY(mc68kcpu) &= (OPER_I_8(mc68kcpu) | 0xffffff00)); + + (mc68kcpu)->n_flag = NFLAG_8((mc68kcpu)->not_z_flag); + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +M68KMAKE_OP(andi, 8, ., .) +{ + UINT32 src = OPER_I_8(mc68kcpu); + UINT32 ea = M68KMAKE_GET_EA_AY_8; + UINT32 res = src & m68ki_read_8((mc68kcpu), ea); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + + m68ki_write_8((mc68kcpu), ea, res); +} + + +M68KMAKE_OP(andi, 16, ., d) +{ + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(DY(mc68kcpu) &= (OPER_I_16(mc68kcpu) | 0xffff0000)); + + (mc68kcpu)->n_flag = NFLAG_16((mc68kcpu)->not_z_flag); + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +M68KMAKE_OP(andi, 16, ., .) +{ + UINT32 src = OPER_I_16(mc68kcpu); + UINT32 ea = M68KMAKE_GET_EA_AY_16; + UINT32 res = src & m68ki_read_16((mc68kcpu), ea); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + + m68ki_write_16((mc68kcpu), ea, res); +} + + +M68KMAKE_OP(andi, 32, ., d) +{ + (mc68kcpu)->not_z_flag = DY(mc68kcpu) &= (OPER_I_32(mc68kcpu)); + + (mc68kcpu)->n_flag = NFLAG_32((mc68kcpu)->not_z_flag); + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +M68KMAKE_OP(andi, 32, ., .) +{ + UINT32 src = OPER_I_32(mc68kcpu); + UINT32 ea = M68KMAKE_GET_EA_AY_32; + UINT32 res = src & m68ki_read_32((mc68kcpu), ea); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + + m68ki_write_32((mc68kcpu), ea, res); +} + + +M68KMAKE_OP(andi, 16, toc, .) +{ + m68ki_set_ccr((mc68kcpu), m68ki_get_ccr(mc68kcpu) & OPER_I_16(mc68kcpu)); +} + + +M68KMAKE_OP(andi, 16, tos, .) +{ + if((mc68kcpu)->s_flag) + { + UINT32 src = OPER_I_16(mc68kcpu); + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_set_sr((mc68kcpu), m68ki_get_sr(mc68kcpu) & src); + return; + } + m68ki_exception_privilege_violation(mc68kcpu); +} + + +M68KMAKE_OP(asr, 8, s, .) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 shift = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT32 src = MASK_OUT_ABOVE_8(*r_dst); + UINT32 res = src >> shift; + + if(shift != 0) + (mc68kcpu)->remaining_cycles -= shift<<(mc68kcpu)->cyc_shift; + + if(GET_MSB_8(src)) + res |= m68ki_shift_8_table[shift]; + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = src << (9-shift); +} + + +M68KMAKE_OP(asr, 16, s, .) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 shift = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT32 src = MASK_OUT_ABOVE_16(*r_dst); + UINT32 res = src >> shift; + + if(shift != 0) + (mc68kcpu)->remaining_cycles -= shift<<(mc68kcpu)->cyc_shift; + + if(GET_MSB_16(src)) + res |= m68ki_shift_16_table[shift]; + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = src << (9-shift); +} + + +M68KMAKE_OP(asr, 32, s, .) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 shift = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT32 src = *r_dst; + UINT32 res = src >> shift; + + if(shift != 0) + (mc68kcpu)->remaining_cycles -= shift<<(mc68kcpu)->cyc_shift; + + if(GET_MSB_32(src)) + res |= m68ki_shift_32_table[shift]; + + *r_dst = res; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = src << (9-shift); +} + + +M68KMAKE_OP(asr, 8, r, .) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 shift = DX(mc68kcpu) & 0x3f; + UINT32 src = MASK_OUT_ABOVE_8(*r_dst); + UINT32 res = src >> shift; + + if(shift != 0) + { + (mc68kcpu)->remaining_cycles -= shift<<(mc68kcpu)->cyc_shift; + + if(shift < 8) + { + if(GET_MSB_8(src)) + res |= m68ki_shift_8_table[shift]; + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; + + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = src << (9-shift); + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + return; + } + + if(GET_MSB_8(src)) + { + *r_dst |= 0xff; + (mc68kcpu)->c_flag = CFLAG_SET; + (mc68kcpu)->x_flag = XFLAG_SET; + (mc68kcpu)->n_flag = NFLAG_SET; + (mc68kcpu)->not_z_flag = ZFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + return; + } + + *r_dst &= 0xffffff00; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->x_flag = XFLAG_CLEAR; + (mc68kcpu)->n_flag = NFLAG_CLEAR; + (mc68kcpu)->not_z_flag = ZFLAG_SET; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + return; + } + + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->n_flag = NFLAG_8(src); + (mc68kcpu)->not_z_flag = src; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +M68KMAKE_OP(asr, 16, r, .) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 shift = DX(mc68kcpu) & 0x3f; + UINT32 src = MASK_OUT_ABOVE_16(*r_dst); + UINT32 res = src >> shift; + + if(shift != 0) + { + (mc68kcpu)->remaining_cycles -= shift<<(mc68kcpu)->cyc_shift; + + if(shift < 16) + { + if(GET_MSB_16(src)) + res |= m68ki_shift_16_table[shift]; + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag = (src >> (shift - 1))<<8; + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + return; + } + + if(GET_MSB_16(src)) + { + *r_dst |= 0xffff; + (mc68kcpu)->c_flag = CFLAG_SET; + (mc68kcpu)->x_flag = XFLAG_SET; + (mc68kcpu)->n_flag = NFLAG_SET; + (mc68kcpu)->not_z_flag = ZFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + return; + } + + *r_dst &= 0xffff0000; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->x_flag = XFLAG_CLEAR; + (mc68kcpu)->n_flag = NFLAG_CLEAR; + (mc68kcpu)->not_z_flag = ZFLAG_SET; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + return; + } + + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->n_flag = NFLAG_16(src); + (mc68kcpu)->not_z_flag = src; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +M68KMAKE_OP(asr, 32, r, .) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 shift = DX(mc68kcpu) & 0x3f; + UINT32 src = *r_dst; + UINT32 res = src >> shift; + + if(shift != 0) + { + (mc68kcpu)->remaining_cycles -= shift<<(mc68kcpu)->cyc_shift; + + if(shift < 32) + { + if(GET_MSB_32(src)) + res |= m68ki_shift_32_table[shift]; + + *r_dst = res; + + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag = (src >> (shift - 1))<<8; + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + return; + } + + if(GET_MSB_32(src)) + { + *r_dst = 0xffffffff; + (mc68kcpu)->c_flag = CFLAG_SET; + (mc68kcpu)->x_flag = XFLAG_SET; + (mc68kcpu)->n_flag = NFLAG_SET; + (mc68kcpu)->not_z_flag = ZFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + return; + } + + *r_dst = 0; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->x_flag = XFLAG_CLEAR; + (mc68kcpu)->n_flag = NFLAG_CLEAR; + (mc68kcpu)->not_z_flag = ZFLAG_SET; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + return; + } + + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->n_flag = NFLAG_32(src); + (mc68kcpu)->not_z_flag = src; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +M68KMAKE_OP(asr, 16, ., .) +{ + UINT32 ea = M68KMAKE_GET_EA_AY_16; + UINT32 src = m68ki_read_16((mc68kcpu), ea); + UINT32 res = src >> 1; + + if(GET_MSB_16(src)) + res |= 0x8000; + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag = src << 8; +} + + +M68KMAKE_OP(asl, 8, s, .) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 shift = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT32 src = MASK_OUT_ABOVE_8(*r_dst); + UINT32 res = MASK_OUT_ABOVE_8(src << shift); + + if(shift != 0) + (mc68kcpu)->remaining_cycles -= shift<<(mc68kcpu)->cyc_shift; + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; + + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = src << shift; + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + src &= m68ki_shift_8_table[shift + 1]; + (mc68kcpu)->v_flag = (!(src == 0 || (src == m68ki_shift_8_table[shift + 1] && shift < 8)))<<7; +} + + +M68KMAKE_OP(asl, 16, s, .) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 shift = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT32 src = MASK_OUT_ABOVE_16(*r_dst); + UINT32 res = MASK_OUT_ABOVE_16(src << shift); + + if(shift != 0) + (mc68kcpu)->remaining_cycles -= shift<<(mc68kcpu)->cyc_shift; + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = src >> (8-shift); + src &= m68ki_shift_16_table[shift + 1]; + (mc68kcpu)->v_flag = (!(src == 0 || src == m68ki_shift_16_table[shift + 1]))<<7; +} + + +M68KMAKE_OP(asl, 32, s, .) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 shift = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT32 src = *r_dst; + UINT32 res = MASK_OUT_ABOVE_32(src << shift); + + if(shift != 0) + (mc68kcpu)->remaining_cycles -= shift<<(mc68kcpu)->cyc_shift; + + *r_dst = res; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = src >> (24-shift); + src &= m68ki_shift_32_table[shift + 1]; + (mc68kcpu)->v_flag = (!(src == 0 || src == m68ki_shift_32_table[shift + 1]))<<7; +} + + +M68KMAKE_OP(asl, 8, r, .) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 shift = DX(mc68kcpu) & 0x3f; + UINT32 src = MASK_OUT_ABOVE_8(*r_dst); + UINT32 res = MASK_OUT_ABOVE_8(src << shift); + + if(shift != 0) + { + (mc68kcpu)->remaining_cycles -= shift<<(mc68kcpu)->cyc_shift; + + if(shift < 8) + { + *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = src << shift; + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + src &= m68ki_shift_8_table[shift + 1]; + (mc68kcpu)->v_flag = (!(src == 0 || src == m68ki_shift_8_table[shift + 1]))<<7; + return; + } + + *r_dst &= 0xffffff00; + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = ((shift == 8 ? src & 1 : 0))<<8; + (mc68kcpu)->n_flag = NFLAG_CLEAR; + (mc68kcpu)->not_z_flag = ZFLAG_SET; + (mc68kcpu)->v_flag = (!(src == 0))<<7; + return; + } + + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->n_flag = NFLAG_8(src); + (mc68kcpu)->not_z_flag = src; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +M68KMAKE_OP(asl, 16, r, .) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 shift = DX(mc68kcpu) & 0x3f; + UINT32 src = MASK_OUT_ABOVE_16(*r_dst); + UINT32 res = MASK_OUT_ABOVE_16(src << shift); + + if(shift != 0) + { + (mc68kcpu)->remaining_cycles -= shift<<(mc68kcpu)->cyc_shift; + + if(shift < 16) + { + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = (src << shift) >> 8; + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + src &= m68ki_shift_16_table[shift + 1]; + (mc68kcpu)->v_flag = (!(src == 0 || src == m68ki_shift_16_table[shift + 1]))<<7; + return; + } + + *r_dst &= 0xffff0000; + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = ((shift == 16 ? src & 1 : 0))<<8; + (mc68kcpu)->n_flag = NFLAG_CLEAR; + (mc68kcpu)->not_z_flag = ZFLAG_SET; + (mc68kcpu)->v_flag = (!(src == 0))<<7; + return; + } + + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->n_flag = NFLAG_16(src); + (mc68kcpu)->not_z_flag = src; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +M68KMAKE_OP(asl, 32, r, .) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 shift = DX(mc68kcpu) & 0x3f; + UINT32 src = *r_dst; + UINT32 res = MASK_OUT_ABOVE_32(src << shift); + + if(shift != 0) + { + (mc68kcpu)->remaining_cycles -= shift<<(mc68kcpu)->cyc_shift; + + if(shift < 32) + { + *r_dst = res; + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = (src >> (32 - shift)) << 8; + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + src &= m68ki_shift_32_table[shift + 1]; + (mc68kcpu)->v_flag = (!(src == 0 || src == m68ki_shift_32_table[shift + 1]))<<7; + return; + } + + *r_dst = 0; + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = ((shift == 32 ? src & 1 : 0))<<8; + (mc68kcpu)->n_flag = NFLAG_CLEAR; + (mc68kcpu)->not_z_flag = ZFLAG_SET; + (mc68kcpu)->v_flag = (!(src == 0))<<7; + return; + } + + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->n_flag = NFLAG_32(src); + (mc68kcpu)->not_z_flag = src; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +M68KMAKE_OP(asl, 16, ., .) +{ + UINT32 ea = M68KMAKE_GET_EA_AY_16; + UINT32 src = m68ki_read_16((mc68kcpu), ea); + UINT32 res = MASK_OUT_ABOVE_16(src << 1); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = src >> 7; + src &= 0xc000; + (mc68kcpu)->v_flag = (!(src == 0 || src == 0xc000))<<7; +} + + +M68KMAKE_OP(bcc, 8, ., .) +{ + if(M68KMAKE_CC) + { + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_8((mc68kcpu), MASK_OUT_ABOVE_8((mc68kcpu)->ir)); + return; + } + (mc68kcpu)->remaining_cycles -= (mc68kcpu)->cyc_bcc_notake_b; +} + + +M68KMAKE_OP(bcc, 16, ., .) +{ + if(M68KMAKE_CC) + { + UINT32 offset = OPER_I_16(mc68kcpu); + REG_PC(mc68kcpu) -= 2; + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_16((mc68kcpu), offset); + return; + } + REG_PC(mc68kcpu) += 2; + (mc68kcpu)->remaining_cycles -= (mc68kcpu)->cyc_bcc_notake_w; +} + + +M68KMAKE_OP(bcc, 32, ., .) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + if(M68KMAKE_CC) + { + UINT32 offset = OPER_I_32(mc68kcpu); + REG_PC(mc68kcpu) -= 4; + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_32((mc68kcpu), offset); + return; + } + REG_PC(mc68kcpu) += 4; + return; + } + else + { + if(M68KMAKE_CC) + { + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_8((mc68kcpu), MASK_OUT_ABOVE_8((mc68kcpu)->ir)); + return; + } + (mc68kcpu)->remaining_cycles -= (mc68kcpu)->cyc_bcc_notake_b; + } +} + + +M68KMAKE_OP(bchg, 32, r, d) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 mask = 1 << (DX(mc68kcpu) & 0x1f); + + (mc68kcpu)->not_z_flag = *r_dst & mask; + *r_dst ^= mask; +} + + +M68KMAKE_OP(bchg, 8, r, .) +{ + UINT32 ea = M68KMAKE_GET_EA_AY_8; + UINT32 src = m68ki_read_8((mc68kcpu), ea); + UINT32 mask = 1 << (DX(mc68kcpu) & 7); + + (mc68kcpu)->not_z_flag = src & mask; + m68ki_write_8((mc68kcpu), ea, src ^ mask); +} + + +M68KMAKE_OP(bchg, 32, s, d) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 mask = 1 << (OPER_I_8(mc68kcpu) & 0x1f); + + (mc68kcpu)->not_z_flag = *r_dst & mask; + *r_dst ^= mask; +} + + +M68KMAKE_OP(bchg, 8, s, .) +{ + UINT32 mask = 1 << (OPER_I_8(mc68kcpu) & 7); + UINT32 ea = M68KMAKE_GET_EA_AY_8; + UINT32 src = m68ki_read_8((mc68kcpu), ea); + + (mc68kcpu)->not_z_flag = src & mask; + m68ki_write_8((mc68kcpu), ea, src ^ mask); +} + + +M68KMAKE_OP(bclr, 32, r, d) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 mask = 1 << (DX(mc68kcpu) & 0x1f); + + (mc68kcpu)->not_z_flag = *r_dst & mask; + *r_dst &= ~mask; +} + + +M68KMAKE_OP(bclr, 8, r, .) +{ + UINT32 ea = M68KMAKE_GET_EA_AY_8; + UINT32 src = m68ki_read_8((mc68kcpu), ea); + UINT32 mask = 1 << (DX(mc68kcpu) & 7); + + (mc68kcpu)->not_z_flag = src & mask; + m68ki_write_8((mc68kcpu), ea, src & ~mask); +} + + +M68KMAKE_OP(bclr, 32, s, d) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 mask = 1 << (OPER_I_8(mc68kcpu) & 0x1f); + + (mc68kcpu)->not_z_flag = *r_dst & mask; + *r_dst &= ~mask; +} + + +M68KMAKE_OP(bclr, 8, s, .) +{ + UINT32 mask = 1 << (OPER_I_8(mc68kcpu) & 7); + UINT32 ea = M68KMAKE_GET_EA_AY_8; + UINT32 src = m68ki_read_8((mc68kcpu), ea); + + (mc68kcpu)->not_z_flag = src & mask; + m68ki_write_8((mc68kcpu), ea, src & ~mask); +} + + +M68KMAKE_OP(bfchg, 32, ., d) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT32 offset = (word2>>6)&31; + UINT32 width = word2; + UINT32* data = &DY(mc68kcpu); + UINT64 mask; + + + if(BIT_B(word2)) + offset = REG_D(mc68kcpu)[offset&7]; + if(BIT_5(word2)) + width = REG_D(mc68kcpu)[width&7]; + + offset &= 31; + width = ((width-1) & 31) + 1; + + mask = MASK_OUT_ABOVE_32(0xffffffff << (32 - width)); + mask = ROR_32(mask, offset); + + (mc68kcpu)->n_flag = NFLAG_32(*data<not_z_flag = *data & mask; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + + *data ^= mask; + + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +M68KMAKE_OP(bfchg, 32, ., .) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + INT32 offset = (word2>>6)&31; + UINT32 width = word2; + UINT32 mask_base; + UINT32 data_long; + UINT32 mask_long; + UINT32 data_byte = 0; + UINT32 mask_byte = 0; + UINT32 ea = M68KMAKE_GET_EA_AY_8; + + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D(mc68kcpu)[offset&7]); + if(BIT_5(word2)) + width = REG_D(mc68kcpu)[width&7]; + + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + offset %= 8; + if(offset < 0) + { + offset += 8; + ea--; + } + width = ((width-1) & 31) + 1; + + mask_base = MASK_OUT_ABOVE_32(0xffffffff << (32 - width)); + mask_long = mask_base >> offset; + + data_long = m68ki_read_32((mc68kcpu), ea); + (mc68kcpu)->n_flag = NFLAG_32(data_long << offset); + (mc68kcpu)->not_z_flag = data_long & mask_long; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + + m68ki_write_32((mc68kcpu), ea, data_long ^ mask_long); + + if((width + offset) > 32) + { + mask_byte = MASK_OUT_ABOVE_8(mask_base); + data_byte = m68ki_read_8((mc68kcpu), ea+4); + (mc68kcpu)->not_z_flag |= (data_byte & mask_byte); + m68ki_write_8((mc68kcpu), ea+4, data_byte ^ mask_byte); + } + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +M68KMAKE_OP(bfclr, 32, ., d) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT32 offset = (word2>>6)&31; + UINT32 width = word2; + UINT32* data = &DY(mc68kcpu); + UINT64 mask; + + + if(BIT_B(word2)) + offset = REG_D(mc68kcpu)[offset&7]; + if(BIT_5(word2)) + width = REG_D(mc68kcpu)[width&7]; + + + offset &= 31; + width = ((width-1) & 31) + 1; + + + mask = MASK_OUT_ABOVE_32(0xffffffff << (32 - width)); + mask = ROR_32(mask, offset); + + (mc68kcpu)->n_flag = NFLAG_32(*data<not_z_flag = *data & mask; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + + *data &= ~mask; + + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +M68KMAKE_OP(bfclr, 32, ., .) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + INT32 offset = (word2>>6)&31; + UINT32 width = word2; + UINT32 mask_base; + UINT32 data_long; + UINT32 mask_long; + UINT32 data_byte = 0; + UINT32 mask_byte = 0; + UINT32 ea = M68KMAKE_GET_EA_AY_8; + + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D(mc68kcpu)[offset&7]); + if(BIT_5(word2)) + width = REG_D(mc68kcpu)[width&7]; + + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + offset %= 8; + if(offset < 0) + { + offset += 8; + ea--; + } + width = ((width-1) & 31) + 1; + + mask_base = MASK_OUT_ABOVE_32(0xffffffff << (32 - width)); + mask_long = mask_base >> offset; + + data_long = m68ki_read_32((mc68kcpu), ea); + (mc68kcpu)->n_flag = NFLAG_32(data_long << offset); + (mc68kcpu)->not_z_flag = data_long & mask_long; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + + m68ki_write_32((mc68kcpu), ea, data_long & ~mask_long); + + if((width + offset) > 32) + { + mask_byte = MASK_OUT_ABOVE_8(mask_base); + data_byte = m68ki_read_8((mc68kcpu), ea+4); + (mc68kcpu)->not_z_flag |= (data_byte & mask_byte); + m68ki_write_8((mc68kcpu), ea+4, data_byte & ~mask_byte); + } + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +M68KMAKE_OP(bfexts, 32, ., d) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT32 offset = (word2>>6)&31; + UINT32 width = word2; + UINT64 data = DY(mc68kcpu); + + + if(BIT_B(word2)) + offset = REG_D(mc68kcpu)[offset&7]; + if(BIT_5(word2)) + width = REG_D(mc68kcpu)[width&7]; + + offset &= 31; + width = ((width-1) & 31) + 1; + + data = ROL_32(data, offset); + (mc68kcpu)->n_flag = NFLAG_32(data); + data = MAKE_INT_32(data) >> (32 - width); + + (mc68kcpu)->not_z_flag = data; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + + REG_D(mc68kcpu)[(word2>>12)&7] = data; + + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +M68KMAKE_OP(bfexts, 32, ., .) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + INT32 offset = (word2>>6)&31; + UINT32 width = word2; + UINT32 data; + UINT32 ea = M68KMAKE_GET_EA_AY_8; + + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D(mc68kcpu)[offset&7]); + if(BIT_5(word2)) + width = REG_D(mc68kcpu)[width&7]; + + if(BIT_B(word2)) + { + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + offset %= 8; + if(offset < 0) + { + offset += 8; + ea--; + } + } + width = ((width-1) & 31) + 1; + + data = (offset+width) < 8 ? (m68ki_read_8((mc68kcpu), ea) << 24) : + (offset+width) < 16 ? (m68ki_read_16((mc68kcpu), ea) << 16) : m68ki_read_32((mc68kcpu), ea); + + data = MASK_OUT_ABOVE_32(data< 32) + data |= (m68ki_read_8((mc68kcpu), ea+4) << offset) >> 8; + + (mc68kcpu)->n_flag = NFLAG_32(data); + data = MAKE_INT_32(data) >> (32 - width); + + (mc68kcpu)->not_z_flag = data; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + + REG_D(mc68kcpu)[(word2 >> 12) & 7] = data; + + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +M68KMAKE_OP(bfextu, 32, ., d) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT32 offset = (word2>>6)&31; + UINT32 width = word2; + UINT64 data = DY(mc68kcpu); + + + if(BIT_B(word2)) + offset = REG_D(mc68kcpu)[offset&7]; + if(BIT_5(word2)) + width = REG_D(mc68kcpu)[width&7]; + + offset &= 31; + width = ((width-1) & 31) + 1; + + data = ROL_32(data, offset); + (mc68kcpu)->n_flag = NFLAG_32(data); + data >>= 32 - width; + + (mc68kcpu)->not_z_flag = data; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + + REG_D(mc68kcpu)[(word2>>12)&7] = data; + + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +M68KMAKE_OP(bfextu, 32, ., .) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + INT32 offset = (word2>>6)&31; + UINT32 width = word2; + UINT32 data; + UINT32 ea = M68KMAKE_GET_EA_AY_8; + + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D(mc68kcpu)[offset&7]); + if(BIT_5(word2)) + width = REG_D(mc68kcpu)[width&7]; + + if(BIT_B(word2)) + { + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + offset %= 8; + if(offset < 0) + { + offset += 8; + ea--; + } + } + width = ((width-1) & 31) + 1; + + data = (offset+width) < 8 ? (m68ki_read_8((mc68kcpu), ea) << 24) : + (offset+width) < 16 ? (m68ki_read_16((mc68kcpu), ea) << 16) : m68ki_read_32((mc68kcpu), ea); + data = MASK_OUT_ABOVE_32(data< 32) + data |= (m68ki_read_8((mc68kcpu), ea+4) << offset) >> 8; + + (mc68kcpu)->n_flag = NFLAG_32(data); + data >>= (32 - width); + + (mc68kcpu)->not_z_flag = data; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + + REG_D(mc68kcpu)[(word2 >> 12) & 7] = data; + + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +M68KMAKE_OP(bfffo, 32, ., d) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT32 offset = (word2>>6)&31; + UINT32 width = word2; + UINT64 data = DY(mc68kcpu); + UINT32 bit; + + + if(BIT_B(word2)) + offset = REG_D(mc68kcpu)[offset&7]; + if(BIT_5(word2)) + width = REG_D(mc68kcpu)[width&7]; + + offset &= 31; + width = ((width-1) & 31) + 1; + + data = ROL_32(data, offset); + (mc68kcpu)->n_flag = NFLAG_32(data); + data >>= 32 - width; + + (mc68kcpu)->not_z_flag = data; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + + for(bit = 1<<(width-1);bit && !(data & bit);bit>>= 1) + offset++; + + REG_D(mc68kcpu)[(word2>>12)&7] = offset; + + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +M68KMAKE_OP(bfffo, 32, ., .) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + INT32 offset = (word2>>6)&31; + INT32 local_offset; + UINT32 width = word2; + UINT32 data; + UINT32 bit; + UINT32 ea = M68KMAKE_GET_EA_AY_8; + + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D(mc68kcpu)[offset&7]); + if(BIT_5(word2)) + width = REG_D(mc68kcpu)[width&7]; + + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + local_offset = offset % 8; + if(local_offset < 0) + { + local_offset += 8; + ea--; + } + width = ((width-1) & 31) + 1; + + data = (offset+width) < 16 ? (m68ki_read_16((mc68kcpu), ea) << 16) : m68ki_read_32((mc68kcpu), ea); + data = MASK_OUT_ABOVE_32(data< 32) + data |= (m68ki_read_8((mc68kcpu), ea+4) << local_offset) >> 8; + + (mc68kcpu)->n_flag = NFLAG_32(data); + data >>= (32 - width); + + (mc68kcpu)->not_z_flag = data; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + + for(bit = 1<<(width-1);bit && !(data & bit);bit>>= 1) + offset++; + + REG_D(mc68kcpu)[(word2>>12)&7] = offset; + + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +M68KMAKE_OP(bfins, 32, ., d) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT32 offset = (word2>>6)&31; + UINT32 width = word2; + UINT32* data = &DY(mc68kcpu); + UINT64 mask; + UINT64 insert = REG_D(mc68kcpu)[(word2>>12)&7]; + + + if(BIT_B(word2)) + offset = REG_D(mc68kcpu)[offset&7]; + if(BIT_5(word2)) + width = REG_D(mc68kcpu)[width&7]; + + + offset &= 31; + width = ((width-1) & 31) + 1; + + + mask = MASK_OUT_ABOVE_32(0xffffffff << (32 - width)); + mask = ROR_32(mask, offset); + + insert = MASK_OUT_ABOVE_32(insert << (32 - width)); + (mc68kcpu)->n_flag = NFLAG_32(insert); + (mc68kcpu)->not_z_flag = insert; + insert = ROR_32(insert, offset); + + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + + *data &= ~mask; + *data |= insert; + + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +M68KMAKE_OP(bfins, 32, ., .) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + INT32 offset = (word2>>6)&31; + UINT32 width = word2; + UINT32 insert_base = REG_D(mc68kcpu)[(word2>>12)&7]; + UINT32 insert_long; + UINT32 insert_byte; + UINT32 mask_base; + UINT32 data_long; + UINT32 mask_long; + UINT32 data_byte = 0; + UINT32 mask_byte = 0; + UINT32 ea = M68KMAKE_GET_EA_AY_8; + + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D(mc68kcpu)[offset&7]); + if(BIT_5(word2)) + width = REG_D(mc68kcpu)[width&7]; + + if(BIT_B(word2)) + { + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + offset %= 8; + if(offset < 0) + { + offset += 8; + ea--; + } + } + width = ((width-1) & 31) + 1; + + mask_base = MASK_OUT_ABOVE_32(0xffffffff << (32 - width)); + mask_long = mask_base >> offset; + + insert_base = MASK_OUT_ABOVE_32(insert_base << (32 - width)); + (mc68kcpu)->n_flag = NFLAG_32(insert_base); + (mc68kcpu)->not_z_flag = insert_base; + insert_long = insert_base >> offset; + + data_long = (offset+width) < 8 ? (m68ki_read_8((mc68kcpu), ea) << 24) : + (offset+width) < 16 ? (m68ki_read_16((mc68kcpu), ea) << 16) : m68ki_read_32((mc68kcpu), ea); + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + + if((width + offset) < 8) + { + m68ki_write_8((mc68kcpu), ea, ((data_long & ~mask_long) | insert_long) >> 24); + } + else if((width + offset) < 16) + { + m68ki_write_16((mc68kcpu), ea, ((data_long & ~mask_long) | insert_long) >> 16); + } + else + { + m68ki_write_32((mc68kcpu), ea, (data_long & ~mask_long) | insert_long); + } + + if((width + offset) > 32) + { + mask_byte = MASK_OUT_ABOVE_8(mask_base); + insert_byte = MASK_OUT_ABOVE_8(insert_base); + data_byte = m68ki_read_8((mc68kcpu), ea+4); + (mc68kcpu)->not_z_flag |= (data_byte & mask_byte); + m68ki_write_8((mc68kcpu), ea+4, (data_byte & ~mask_byte) | insert_byte); + } + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +M68KMAKE_OP(bfset, 32, ., d) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT32 offset = (word2>>6)&31; + UINT32 width = word2; + UINT32* data = &DY(mc68kcpu); + UINT64 mask; + + + if(BIT_B(word2)) + offset = REG_D(mc68kcpu)[offset&7]; + if(BIT_5(word2)) + width = REG_D(mc68kcpu)[width&7]; + + + offset &= 31; + width = ((width-1) & 31) + 1; + + + mask = MASK_OUT_ABOVE_32(0xffffffff << (32 - width)); + mask = ROR_32(mask, offset); + + (mc68kcpu)->n_flag = NFLAG_32(*data<not_z_flag = *data & mask; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + + *data |= mask; + + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +M68KMAKE_OP(bfset, 32, ., .) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + INT32 offset = (word2>>6)&31; + UINT32 width = word2; + UINT32 mask_base; + UINT32 data_long; + UINT32 mask_long; + UINT32 data_byte = 0; + UINT32 mask_byte = 0; + UINT32 ea = M68KMAKE_GET_EA_AY_8; + + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D(mc68kcpu)[offset&7]); + if(BIT_5(word2)) + width = REG_D(mc68kcpu)[width&7]; + + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + offset %= 8; + if(offset < 0) + { + offset += 8; + ea--; + } + width = ((width-1) & 31) + 1; + + + mask_base = MASK_OUT_ABOVE_32(0xffffffff << (32 - width)); + mask_long = mask_base >> offset; + + data_long = m68ki_read_32((mc68kcpu), ea); + (mc68kcpu)->n_flag = NFLAG_32(data_long << offset); + (mc68kcpu)->not_z_flag = data_long & mask_long; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + + m68ki_write_32((mc68kcpu), ea, data_long | mask_long); + + if((width + offset) > 32) + { + mask_byte = MASK_OUT_ABOVE_8(mask_base); + data_byte = m68ki_read_8((mc68kcpu), ea+4); + (mc68kcpu)->not_z_flag |= (data_byte & mask_byte); + m68ki_write_8((mc68kcpu), ea+4, data_byte | mask_byte); + } + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +M68KMAKE_OP(bftst, 32, ., d) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT32 offset = (word2>>6)&31; + UINT32 width = word2; + UINT32* data = &DY(mc68kcpu); + UINT64 mask; + + + if(BIT_B(word2)) + offset = REG_D(mc68kcpu)[offset&7]; + if(BIT_5(word2)) + width = REG_D(mc68kcpu)[width&7]; + + + offset &= 31; + width = ((width-1) & 31) + 1; + + + mask = MASK_OUT_ABOVE_32(0xffffffff << (32 - width)); + mask = ROR_32(mask, offset); + + (mc68kcpu)->n_flag = NFLAG_32(*data<not_z_flag = *data & mask; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +M68KMAKE_OP(bftst, 32, ., .) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + INT32 offset = (word2>>6)&31; + UINT32 width = word2; + UINT32 mask_base; + UINT32 data_long; + UINT32 mask_long; + UINT32 data_byte = 0; + UINT32 mask_byte = 0; + UINT32 ea = M68KMAKE_GET_EA_AY_8; + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D(mc68kcpu)[offset&7]); + if(BIT_5(word2)) + width = REG_D(mc68kcpu)[width&7]; + + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + offset %= 8; + if(offset < 0) + { + offset += 8; + ea--; + } + width = ((width-1) & 31) + 1; + + + mask_base = MASK_OUT_ABOVE_32(0xffffffff << (32 - width)); + mask_long = mask_base >> offset; + + data_long = m68ki_read_32((mc68kcpu), ea); + (mc68kcpu)->n_flag = ((data_long & (0x80000000 >> offset))<>24; + (mc68kcpu)->not_z_flag = data_long & mask_long; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + + if((width + offset) > 32) + { + mask_byte = MASK_OUT_ABOVE_8(mask_base); + data_byte = m68ki_read_8((mc68kcpu), ea+4); + (mc68kcpu)->not_z_flag |= (data_byte & mask_byte); + } + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +M68KMAKE_OP(bkpt, 0, ., .) +{ + if(CPU_TYPE_IS_010_PLUS((mc68kcpu)->cpu_type)) + { + if (!(mc68kcpu)->bkpt_ack_callback.isnull()) + ((mc68kcpu)->bkpt_ack_callback)((*mc68kcpu->program), 0, CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type) ? (mc68kcpu)->ir & 7 : 0, 0xffffffff); + } + m68ki_exception_illegal(mc68kcpu); +} + + +M68KMAKE_OP(bra, 8, ., .) +{ + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_8((mc68kcpu), MASK_OUT_ABOVE_8((mc68kcpu)->ir)); + if(REG_PC(mc68kcpu) == REG_PPC(mc68kcpu) && (mc68kcpu)->remaining_cycles > 0) + (mc68kcpu)->remaining_cycles = 0; +} + + +M68KMAKE_OP(bra, 16, ., .) +{ + UINT32 offset = OPER_I_16(mc68kcpu); + REG_PC(mc68kcpu) -= 2; + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_16((mc68kcpu), offset); + if(REG_PC(mc68kcpu) == REG_PPC(mc68kcpu) && (mc68kcpu)->remaining_cycles > 0) + (mc68kcpu)->remaining_cycles = 0; +} + + +M68KMAKE_OP(bra, 32, ., .) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 offset = OPER_I_32(mc68kcpu); + REG_PC(mc68kcpu) -= 4; + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_32((mc68kcpu), offset); + if(REG_PC(mc68kcpu) == REG_PPC(mc68kcpu) && (mc68kcpu)->remaining_cycles > 0) + (mc68kcpu)->remaining_cycles = 0; + return; + } + else + { + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_8((mc68kcpu), MASK_OUT_ABOVE_8((mc68kcpu)->ir)); + if(REG_PC(mc68kcpu) == REG_PPC(mc68kcpu) && (mc68kcpu)->remaining_cycles > 0) + (mc68kcpu)->remaining_cycles = 0; + } +} + + +M68KMAKE_OP(bset, 32, r, d) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 mask = 1 << (DX(mc68kcpu) & 0x1f); + + (mc68kcpu)->not_z_flag = *r_dst & mask; + *r_dst |= mask; +} + + +M68KMAKE_OP(bset, 8, r, .) +{ + UINT32 ea = M68KMAKE_GET_EA_AY_8; + UINT32 src = m68ki_read_8((mc68kcpu), ea); + UINT32 mask = 1 << (DX(mc68kcpu) & 7); + + (mc68kcpu)->not_z_flag = src & mask; + m68ki_write_8((mc68kcpu), ea, src | mask); +} + + +M68KMAKE_OP(bset, 32, s, d) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 mask = 1 << (OPER_I_8(mc68kcpu) & 0x1f); + + (mc68kcpu)->not_z_flag = *r_dst & mask; + *r_dst |= mask; +} + + +M68KMAKE_OP(bset, 8, s, .) +{ + UINT32 mask = 1 << (OPER_I_8(mc68kcpu) & 7); + UINT32 ea = M68KMAKE_GET_EA_AY_8; + UINT32 src = m68ki_read_8((mc68kcpu), ea); + + (mc68kcpu)->not_z_flag = src & mask; + m68ki_write_8((mc68kcpu), ea, src | mask); +} + + +M68KMAKE_OP(bsr, 8, ., .) +{ + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_push_32((mc68kcpu), REG_PC(mc68kcpu)); + m68ki_branch_8((mc68kcpu), MASK_OUT_ABOVE_8((mc68kcpu)->ir)); +} + + +M68KMAKE_OP(bsr, 16, ., .) +{ + UINT32 offset = OPER_I_16(mc68kcpu); + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_push_32((mc68kcpu), REG_PC(mc68kcpu)); + REG_PC(mc68kcpu) -= 2; + m68ki_branch_16((mc68kcpu), offset); +} + + +M68KMAKE_OP(bsr, 32, ., .) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 offset = OPER_I_32(mc68kcpu); + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_push_32((mc68kcpu), REG_PC(mc68kcpu)); + REG_PC(mc68kcpu) -= 4; + m68ki_branch_32((mc68kcpu), offset); + return; + } + else + { + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_push_32((mc68kcpu), REG_PC(mc68kcpu)); + m68ki_branch_8((mc68kcpu), MASK_OUT_ABOVE_8((mc68kcpu)->ir)); + } +} + + +M68KMAKE_OP(btst, 32, r, d) +{ + (mc68kcpu)->not_z_flag = DY(mc68kcpu) & (1 << (DX(mc68kcpu) & 0x1f)); +} + + +M68KMAKE_OP(btst, 8, r, .) +{ + (mc68kcpu)->not_z_flag = M68KMAKE_GET_OPER_AY_8 & (1 << (DX(mc68kcpu) & 7)); +} + + +M68KMAKE_OP(btst, 32, s, d) +{ + (mc68kcpu)->not_z_flag = DY(mc68kcpu) & (1 << (OPER_I_8(mc68kcpu) & 0x1f)); +} + + +M68KMAKE_OP(btst, 8, s, .) +{ + UINT32 bit = OPER_I_8(mc68kcpu) & 7; + + (mc68kcpu)->not_z_flag = M68KMAKE_GET_OPER_AY_8 & (1 << bit); +} + + +M68KMAKE_OP(callm, 32, ., .) +{ + /* note: watch out for pcrelative modes */ + if(CPU_TYPE_IS_020_VARIANT((mc68kcpu)->cpu_type)) + { + UINT32 ea = M68KMAKE_GET_EA_AY_32; + + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + REG_PC(mc68kcpu) += 2; +(void)ea; /* just to avoid an 'unused variable' warning */ + logerror("%s at %08x: called unimplemented instruction %04x (callm)\n", + (mc68kcpu)->tag(), REG_PC(mc68kcpu) - 2, (mc68kcpu)->ir); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +M68KMAKE_OP(cas, 8, ., .) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT32 ea = M68KMAKE_GET_EA_AY_8; + UINT32 dest = m68ki_read_8((mc68kcpu), ea); + UINT32* compare = ®_D(mc68kcpu)[word2 & 7]; + UINT32 res = dest - MASK_OUT_ABOVE_8(*compare); + + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(*compare, dest, res); + (mc68kcpu)->c_flag = CFLAG_8(res); + + if(COND_NE(mc68kcpu)) + *compare = MASK_OUT_BELOW_8(*compare) | dest; + else + { + (mc68kcpu)->remaining_cycles -= 3; + m68ki_write_8((mc68kcpu), ea, MASK_OUT_ABOVE_8(REG_D(mc68kcpu)[(word2 >> 6) & 7])); + } + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +M68KMAKE_OP(cas, 16, ., .) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT32 ea = M68KMAKE_GET_EA_AY_16; + UINT32 dest = m68ki_read_16((mc68kcpu), ea); + UINT32* compare = ®_D(mc68kcpu)[word2 & 7]; + UINT32 res = dest - MASK_OUT_ABOVE_16(*compare); + + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + (mc68kcpu)->v_flag = VFLAG_SUB_16(*compare, dest, res); + (mc68kcpu)->c_flag = CFLAG_16(res); + + if(COND_NE(mc68kcpu)) + *compare = MASK_OUT_BELOW_16(*compare) | dest; + else + { + (mc68kcpu)->remaining_cycles -= 3; + m68ki_write_16((mc68kcpu), ea, MASK_OUT_ABOVE_16(REG_D(mc68kcpu)[(word2 >> 6) & 7])); + } + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +M68KMAKE_OP(cas, 32, ., .) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT32 ea = M68KMAKE_GET_EA_AY_32; + UINT32 dest = m68ki_read_32((mc68kcpu), ea); + UINT32* compare = ®_D(mc68kcpu)[word2 & 7]; + UINT32 res = dest - *compare; + + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(*compare, dest, res); + (mc68kcpu)->c_flag = CFLAG_SUB_32(*compare, dest, res); + + if(COND_NE(mc68kcpu)) + *compare = dest; + else + { + (mc68kcpu)->remaining_cycles -= 3; + m68ki_write_32((mc68kcpu), ea, REG_D(mc68kcpu)[(word2 >> 6) & 7]); + } + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +M68KMAKE_OP(cas2, 16, ., .) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_32(mc68kcpu); + UINT32* compare1 = ®_D(mc68kcpu)[(word2 >> 16) & 7]; + UINT32 ea1 = REG_DA(mc68kcpu)[(word2 >> 28) & 15]; + UINT32 dest1 = m68ki_read_16((mc68kcpu), ea1); + UINT32 res1 = dest1 - MASK_OUT_ABOVE_16(*compare1); + UINT32* compare2 = ®_D(mc68kcpu)[word2 & 7]; + UINT32 ea2 = REG_DA(mc68kcpu)[(word2 >> 12) & 15]; + UINT32 dest2 = m68ki_read_16((mc68kcpu), ea2); + UINT32 res2; + + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + (mc68kcpu)->n_flag = NFLAG_16(res1); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res1); + (mc68kcpu)->v_flag = VFLAG_SUB_16(*compare1, dest1, res1); + (mc68kcpu)->c_flag = CFLAG_16(res1); + + if(COND_EQ(mc68kcpu)) + { + res2 = dest2 - MASK_OUT_ABOVE_16(*compare2); + + (mc68kcpu)->n_flag = NFLAG_16(res2); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res2); + (mc68kcpu)->v_flag = VFLAG_SUB_16(*compare2, dest2, res2); + (mc68kcpu)->c_flag = CFLAG_16(res2); + + if(COND_EQ(mc68kcpu)) + { + (mc68kcpu)->remaining_cycles -= 3; + m68ki_write_16((mc68kcpu), ea1, REG_D(mc68kcpu)[(word2 >> 22) & 7]); + m68ki_write_16((mc68kcpu), ea2, REG_D(mc68kcpu)[(word2 >> 6) & 7]); + return; + } + } + *compare1 = BIT_1F(word2) ? MAKE_INT_16(dest1) : MASK_OUT_BELOW_16(*compare1) | dest1; + *compare2 = BIT_F(word2) ? MAKE_INT_16(dest2) : MASK_OUT_BELOW_16(*compare2) | dest2; + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +M68KMAKE_OP(cas2, 32, ., .) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_32(mc68kcpu); + UINT32* compare1 = ®_D(mc68kcpu)[(word2 >> 16) & 7]; + UINT32 ea1 = REG_DA(mc68kcpu)[(word2 >> 28) & 15]; + UINT32 dest1 = m68ki_read_32((mc68kcpu), ea1); + UINT32 res1 = dest1 - *compare1; + UINT32* compare2 = ®_D(mc68kcpu)[word2 & 7]; + UINT32 ea2 = REG_DA(mc68kcpu)[(word2 >> 12) & 15]; + UINT32 dest2 = m68ki_read_32((mc68kcpu), ea2); + UINT32 res2; + + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + (mc68kcpu)->n_flag = NFLAG_32(res1); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res1); + (mc68kcpu)->v_flag = VFLAG_SUB_32(*compare1, dest1, res1); + (mc68kcpu)->c_flag = CFLAG_SUB_32(*compare1, dest1, res1); + + if(COND_EQ(mc68kcpu)) + { + res2 = dest2 - *compare2; + + (mc68kcpu)->n_flag = NFLAG_32(res2); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res2); + (mc68kcpu)->v_flag = VFLAG_SUB_32(*compare2, dest2, res2); + (mc68kcpu)->c_flag = CFLAG_SUB_32(*compare2, dest2, res2); + + if(COND_EQ(mc68kcpu)) + { + (mc68kcpu)->remaining_cycles -= 3; + m68ki_write_32((mc68kcpu), ea1, REG_D(mc68kcpu)[(word2 >> 22) & 7]); + m68ki_write_32((mc68kcpu), ea2, REG_D(mc68kcpu)[(word2 >> 6) & 7]); + return; + } + } + *compare1 = dest1; + *compare2 = dest2; + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +M68KMAKE_OP(chk, 16, ., d) +{ + INT32 src = MAKE_INT_16(DX(mc68kcpu)); + INT32 bound = MAKE_INT_16(DY(mc68kcpu)); + + (mc68kcpu)->not_z_flag = ZFLAG_16(src); /* Undocumented */ + (mc68kcpu)->v_flag = VFLAG_CLEAR; /* Undocumented */ + (mc68kcpu)->c_flag = CFLAG_CLEAR; /* Undocumented */ + + if(src >= 0 && src <= bound) + { + return; + } + (mc68kcpu)->n_flag = (src < 0)<<7; + m68ki_exception_trap((mc68kcpu), EXCEPTION_CHK); +} + + +M68KMAKE_OP(chk, 16, ., .) +{ + INT32 src = MAKE_INT_16(DX(mc68kcpu)); + INT32 bound = MAKE_INT_16(M68KMAKE_GET_OPER_AY_16); + + (mc68kcpu)->not_z_flag = ZFLAG_16(src); /* Undocumented */ + (mc68kcpu)->v_flag = VFLAG_CLEAR; /* Undocumented */ + (mc68kcpu)->c_flag = CFLAG_CLEAR; /* Undocumented */ + + if(src >= 0 && src <= bound) + { + return; + } + (mc68kcpu)->n_flag = (src < 0)<<7; + m68ki_exception_trap((mc68kcpu), EXCEPTION_CHK); +} + + +M68KMAKE_OP(chk, 32, ., d) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + INT32 src = MAKE_INT_32(DX(mc68kcpu)); + INT32 bound = MAKE_INT_32(DY(mc68kcpu)); + + (mc68kcpu)->not_z_flag = ZFLAG_32(src); /* Undocumented */ + (mc68kcpu)->v_flag = VFLAG_CLEAR; /* Undocumented */ + (mc68kcpu)->c_flag = CFLAG_CLEAR; /* Undocumented */ + + if(src >= 0 && src <= bound) + { + return; + } + (mc68kcpu)->n_flag = (src < 0)<<7; + m68ki_exception_trap((mc68kcpu), EXCEPTION_CHK); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +M68KMAKE_OP(chk, 32, ., .) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + INT32 src = MAKE_INT_32(DX(mc68kcpu)); + INT32 bound = MAKE_INT_32(M68KMAKE_GET_OPER_AY_32); + + (mc68kcpu)->not_z_flag = ZFLAG_32(src); /* Undocumented */ + (mc68kcpu)->v_flag = VFLAG_CLEAR; /* Undocumented */ + (mc68kcpu)->c_flag = CFLAG_CLEAR; /* Undocumented */ + + if(src >= 0 && src <= bound) + { + return; + } + (mc68kcpu)->n_flag = (src < 0)<<7; + m68ki_exception_trap((mc68kcpu), EXCEPTION_CHK); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +M68KMAKE_OP(chk2cmp2, 8, ., pcdi) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT32 compare = REG_DA(mc68kcpu)[(word2 >> 12) & 15]&0xff; + UINT32 ea = EA_PCDI_8(mc68kcpu); + UINT32 lower_bound = m68ki_read_pcrel_8((mc68kcpu), ea); + UINT32 upper_bound = m68ki_read_pcrel_8((mc68kcpu), ea + 1); + + if(!BIT_F(word2)) + (mc68kcpu)->c_flag = MAKE_INT_8(compare) - MAKE_INT_8(lower_bound); + else + (mc68kcpu)->c_flag = compare - lower_bound; + (mc68kcpu)->not_z_flag = !((upper_bound==compare) | (lower_bound==compare)); + if(COND_CS(mc68kcpu)) + { + if(BIT_B(word2)) + m68ki_exception_trap((mc68kcpu), EXCEPTION_CHK); + return; + } + + (mc68kcpu)->c_flag = upper_bound - compare; + if(COND_CS(mc68kcpu) && BIT_B(word2)) + m68ki_exception_trap((mc68kcpu), EXCEPTION_CHK); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +M68KMAKE_OP(chk2cmp2, 8, ., pcix) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT32 compare = REG_DA(mc68kcpu)[(word2 >> 12) & 15]&0xff; + UINT32 ea = EA_PCIX_8(mc68kcpu); + UINT32 lower_bound = m68ki_read_pcrel_8((mc68kcpu), ea); + UINT32 upper_bound = m68ki_read_pcrel_8((mc68kcpu), ea + 1); + + if(!BIT_F(word2)) + (mc68kcpu)->c_flag = MAKE_INT_8(compare) - MAKE_INT_8(lower_bound); + else + (mc68kcpu)->c_flag = compare - lower_bound; + (mc68kcpu)->not_z_flag = !((upper_bound==compare) | (lower_bound==compare)); + if(COND_CS(mc68kcpu)) + { + if(BIT_B(word2)) + m68ki_exception_trap((mc68kcpu), EXCEPTION_CHK); + return; + } + + (mc68kcpu)->c_flag = upper_bound - compare; + if(COND_CS(mc68kcpu) && BIT_B(word2)) + m68ki_exception_trap((mc68kcpu), EXCEPTION_CHK); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +M68KMAKE_OP(chk2cmp2, 8, ., .) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT32 compare = REG_DA(mc68kcpu)[(word2 >> 12) & 15]&0xff; + UINT32 ea = M68KMAKE_GET_EA_AY_8; + UINT32 lower_bound = m68ki_read_8((mc68kcpu), ea); + UINT32 upper_bound = m68ki_read_8((mc68kcpu), ea + 1); + + if(!BIT_F(word2)) + (mc68kcpu)->c_flag = MAKE_INT_8(compare) - MAKE_INT_8(lower_bound); + else + (mc68kcpu)->c_flag = compare - lower_bound; + (mc68kcpu)->not_z_flag = !((upper_bound==compare) | (lower_bound==compare)); + if(COND_CS(mc68kcpu)) + { + if(BIT_B(word2)) + m68ki_exception_trap((mc68kcpu), EXCEPTION_CHK); + return; + } + + (mc68kcpu)->c_flag = upper_bound - compare; + if(COND_CS(mc68kcpu) && BIT_B(word2)) + m68ki_exception_trap((mc68kcpu), EXCEPTION_CHK); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +M68KMAKE_OP(chk2cmp2, 16, ., pcdi) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT32 compare = REG_DA(mc68kcpu)[(word2 >> 12) & 15]&0xffff; + UINT32 ea = EA_PCDI_16(mc68kcpu); + UINT32 lower_bound = m68ki_read_pcrel_16((mc68kcpu), ea); + UINT32 upper_bound = m68ki_read_pcrel_16((mc68kcpu), ea + 2); + + if(!BIT_F(word2)) + (mc68kcpu)->c_flag = MAKE_INT_16(compare) - MAKE_INT_16(lower_bound); + else + (mc68kcpu)->c_flag = compare - lower_bound; + (mc68kcpu)->not_z_flag = !((upper_bound==compare) | (lower_bound==compare)); + (mc68kcpu)->c_flag = CFLAG_16((mc68kcpu)->c_flag); + if(COND_CS(mc68kcpu)) + { + if(BIT_B(word2)) + m68ki_exception_trap((mc68kcpu), EXCEPTION_CHK); + return; + } + + if(!BIT_F(word2)) + (mc68kcpu)->c_flag = MAKE_INT_16(upper_bound) - MAKE_INT_16(compare); + else + (mc68kcpu)->c_flag = upper_bound - compare; + (mc68kcpu)->c_flag = CFLAG_16((mc68kcpu)->c_flag); + if(COND_CS(mc68kcpu) && BIT_B(word2)) + m68ki_exception_trap((mc68kcpu), EXCEPTION_CHK); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +M68KMAKE_OP(chk2cmp2, 16, ., pcix) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT32 compare = REG_DA(mc68kcpu)[(word2 >> 12) & 15]&0xffff; + UINT32 ea = EA_PCIX_16(mc68kcpu); + UINT32 lower_bound = m68ki_read_pcrel_16((mc68kcpu), ea); + UINT32 upper_bound = m68ki_read_pcrel_16((mc68kcpu), ea + 2); + + if(!BIT_F(word2)) + (mc68kcpu)->c_flag = MAKE_INT_16(compare) - MAKE_INT_16(lower_bound); + else + (mc68kcpu)->c_flag = compare - lower_bound; + (mc68kcpu)->not_z_flag = !((upper_bound==compare) | (lower_bound==compare)); + (mc68kcpu)->c_flag = CFLAG_16((mc68kcpu)->c_flag); + if(COND_CS(mc68kcpu)) + { + if(BIT_B(word2)) + m68ki_exception_trap((mc68kcpu), EXCEPTION_CHK); + return; + } + + if(!BIT_F(word2)) + (mc68kcpu)->c_flag = MAKE_INT_16(upper_bound) - MAKE_INT_16(compare); + else + (mc68kcpu)->c_flag = upper_bound - compare; + (mc68kcpu)->c_flag = CFLAG_16((mc68kcpu)->c_flag); + if(COND_CS(mc68kcpu) && BIT_B(word2)) + m68ki_exception_trap((mc68kcpu), EXCEPTION_CHK); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +M68KMAKE_OP(chk2cmp2, 16, ., .) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT32 compare = REG_DA(mc68kcpu)[(word2 >> 12) & 15]&0xffff; + UINT32 ea = M68KMAKE_GET_EA_AY_16; + UINT32 lower_bound = m68ki_read_16((mc68kcpu), ea); + UINT32 upper_bound = m68ki_read_16((mc68kcpu), ea + 2); + + if(!BIT_F(word2)) + (mc68kcpu)->c_flag = MAKE_INT_16(compare) - MAKE_INT_16(lower_bound); + else + (mc68kcpu)->c_flag = compare - lower_bound; + + (mc68kcpu)->not_z_flag = !((upper_bound==compare) | (lower_bound==compare)); + (mc68kcpu)->c_flag = CFLAG_16((mc68kcpu)->c_flag); + if(COND_CS(mc68kcpu)) + { + if(BIT_B(word2)) + m68ki_exception_trap((mc68kcpu), EXCEPTION_CHK); + return; + } + if(!BIT_F(word2)) + (mc68kcpu)->c_flag = MAKE_INT_16(upper_bound) - MAKE_INT_16(compare); + else + (mc68kcpu)->c_flag = upper_bound - compare; + + (mc68kcpu)->c_flag = CFLAG_16((mc68kcpu)->c_flag); + if(COND_CS(mc68kcpu) && BIT_B(word2)) + m68ki_exception_trap((mc68kcpu), EXCEPTION_CHK); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +M68KMAKE_OP(chk2cmp2, 32, ., pcdi) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT32 compare = REG_DA(mc68kcpu)[(word2 >> 12) & 15]; + UINT32 ea = EA_PCDI_32(mc68kcpu); + UINT32 lower_bound = m68ki_read_pcrel_32((mc68kcpu), ea); + UINT32 upper_bound = m68ki_read_pcrel_32((mc68kcpu), ea + 4); + + (mc68kcpu)->c_flag = compare - lower_bound; + (mc68kcpu)->not_z_flag = !((upper_bound==compare) | (lower_bound==compare)); + (mc68kcpu)->c_flag = CFLAG_SUB_32(lower_bound, compare, (mc68kcpu)->c_flag); + if(COND_CS(mc68kcpu)) + { + if(BIT_B(word2)) + m68ki_exception_trap((mc68kcpu), EXCEPTION_CHK); + return; + } + + (mc68kcpu)->c_flag = upper_bound - compare; + (mc68kcpu)->c_flag = CFLAG_SUB_32(compare, upper_bound, (mc68kcpu)->c_flag); + if(COND_CS(mc68kcpu) && BIT_B(word2)) + m68ki_exception_trap((mc68kcpu), EXCEPTION_CHK); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +M68KMAKE_OP(chk2cmp2, 32, ., pcix) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT32 compare = REG_DA(mc68kcpu)[(word2 >> 12) & 15]; + UINT32 ea = EA_PCIX_32(mc68kcpu); + UINT32 lower_bound = m68ki_read_pcrel_32((mc68kcpu), ea); + UINT32 upper_bound = m68ki_read_pcrel_32((mc68kcpu), ea + 4); + + (mc68kcpu)->c_flag = compare - lower_bound; + (mc68kcpu)->not_z_flag = !((upper_bound==compare) | (lower_bound==compare)); + (mc68kcpu)->c_flag = CFLAG_SUB_32(lower_bound, compare, (mc68kcpu)->c_flag); + if(COND_CS(mc68kcpu)) + { + if(BIT_B(word2)) + m68ki_exception_trap((mc68kcpu), EXCEPTION_CHK); + return; + } + + (mc68kcpu)->c_flag = upper_bound - compare; + (mc68kcpu)->c_flag = CFLAG_SUB_32(compare, upper_bound, (mc68kcpu)->c_flag); + if(COND_CS(mc68kcpu) && BIT_B(word2)) + m68ki_exception_trap((mc68kcpu), EXCEPTION_CHK); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +M68KMAKE_OP(chk2cmp2, 32, ., .) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT32 compare = REG_DA(mc68kcpu)[(word2 >> 12) & 15]; + UINT32 ea = M68KMAKE_GET_EA_AY_32; + UINT32 lower_bound = m68ki_read_32((mc68kcpu), ea); + UINT32 upper_bound = m68ki_read_32((mc68kcpu), ea + 4); + + (mc68kcpu)->c_flag = compare - lower_bound; + (mc68kcpu)->not_z_flag = !((upper_bound==compare) | (lower_bound==compare)); + (mc68kcpu)->c_flag = CFLAG_SUB_32(lower_bound, compare, (mc68kcpu)->c_flag); + if(COND_CS(mc68kcpu)) + { + if(BIT_B(word2)) + m68ki_exception_trap((mc68kcpu), EXCEPTION_CHK); + return; + } + + (mc68kcpu)->c_flag = upper_bound - compare; + (mc68kcpu)->c_flag = CFLAG_SUB_32(compare, upper_bound, (mc68kcpu)->c_flag); + if(COND_CS(mc68kcpu) && BIT_B(word2)) + m68ki_exception_trap((mc68kcpu), EXCEPTION_CHK); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +M68KMAKE_OP(clr, 8, ., d) +{ + DY(mc68kcpu) &= 0xffffff00; + + (mc68kcpu)->n_flag = NFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->not_z_flag = ZFLAG_SET; +} + + +M68KMAKE_OP(clr, 8, ., .) +{ + UINT32 ea = M68KMAKE_GET_EA_AY_8; + + if(CPU_TYPE_IS_000((mc68kcpu)->cpu_type)) + { + m68ki_read_8((mc68kcpu), ea); /* the 68000 does a dummy read, the value is discarded */ + } + + m68ki_write_8((mc68kcpu), ea, 0); + + (mc68kcpu)->n_flag = NFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->not_z_flag = ZFLAG_SET; +} + + +M68KMAKE_OP(clr, 16, ., d) +{ + DY(mc68kcpu) &= 0xffff0000; + + (mc68kcpu)->n_flag = NFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->not_z_flag = ZFLAG_SET; +} + + +M68KMAKE_OP(clr, 16, ., .) +{ + UINT32 ea = M68KMAKE_GET_EA_AY_16; + + if(CPU_TYPE_IS_000((mc68kcpu)->cpu_type)) + { + m68ki_read_16((mc68kcpu), ea); /* the 68000 does a dummy read, the value is discarded */ + } + + m68ki_write_16((mc68kcpu), ea, 0); + + (mc68kcpu)->n_flag = NFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->not_z_flag = ZFLAG_SET; +} + + +M68KMAKE_OP(clr, 32, ., d) +{ + DY(mc68kcpu) = 0; + + (mc68kcpu)->n_flag = NFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->not_z_flag = ZFLAG_SET; +} + + +M68KMAKE_OP(clr, 32, ., .) +{ + UINT32 ea = M68KMAKE_GET_EA_AY_32; + + if(CPU_TYPE_IS_000((mc68kcpu)->cpu_type)) + { + m68ki_read_32((mc68kcpu), ea); /* the 68000 does a dummy read, the value is discarded */ + } + + m68ki_write_32((mc68kcpu), ea, 0); + + (mc68kcpu)->n_flag = NFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->not_z_flag = ZFLAG_SET; +} + + +M68KMAKE_OP(cmp, 8, ., d) +{ + UINT32 src = MASK_OUT_ABOVE_8(DY(mc68kcpu)); + UINT32 dst = MASK_OUT_ABOVE_8(DX(mc68kcpu)); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_8(res); +} + + +M68KMAKE_OP(cmp, 8, ., .) +{ + UINT32 src = M68KMAKE_GET_OPER_AY_8; + UINT32 dst = MASK_OUT_ABOVE_8(DX(mc68kcpu)); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_8(res); +} + + +M68KMAKE_OP(cmp, 16, ., d) +{ + UINT32 src = MASK_OUT_ABOVE_16(DY(mc68kcpu)); + UINT32 dst = MASK_OUT_ABOVE_16(DX(mc68kcpu)); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + (mc68kcpu)->v_flag = VFLAG_SUB_16(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_16(res); +} + + +M68KMAKE_OP(cmp, 16, ., a) +{ + UINT32 src = MASK_OUT_ABOVE_16(AY(mc68kcpu)); + UINT32 dst = MASK_OUT_ABOVE_16(DX(mc68kcpu)); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + (mc68kcpu)->v_flag = VFLAG_SUB_16(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_16(res); +} + + +M68KMAKE_OP(cmp, 16, ., .) +{ + UINT32 src = M68KMAKE_GET_OPER_AY_16; + UINT32 dst = MASK_OUT_ABOVE_16(DX(mc68kcpu)); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + (mc68kcpu)->v_flag = VFLAG_SUB_16(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_16(res); +} + + +M68KMAKE_OP(cmp, 32, ., d) +{ + UINT32 src = DY(mc68kcpu); + UINT32 dst = DX(mc68kcpu); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); +} + + +M68KMAKE_OP(cmp, 32, ., a) +{ + UINT32 src = AY(mc68kcpu); + UINT32 dst = DX(mc68kcpu); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); +} + + +M68KMAKE_OP(cmp, 32, ., .) +{ + UINT32 src = M68KMAKE_GET_OPER_AY_32; + UINT32 dst = DX(mc68kcpu); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); +} + + +M68KMAKE_OP(cmpa, 16, ., d) +{ + UINT32 src = MAKE_INT_16(DY(mc68kcpu)); + UINT32 dst = AX(mc68kcpu); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); +} + + +M68KMAKE_OP(cmpa, 16, ., a) +{ + UINT32 src = MAKE_INT_16(AY(mc68kcpu)); + UINT32 dst = AX(mc68kcpu); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); +} + + +M68KMAKE_OP(cmpa, 16, ., .) +{ + UINT32 src = MAKE_INT_16(M68KMAKE_GET_OPER_AY_16); + UINT32 dst = AX(mc68kcpu); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); +} + + +M68KMAKE_OP(cmpa, 32, ., d) +{ + UINT32 src = DY(mc68kcpu); + UINT32 dst = AX(mc68kcpu); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); +} + + +M68KMAKE_OP(cmpa, 32, ., a) +{ + UINT32 src = AY(mc68kcpu); + UINT32 dst = AX(mc68kcpu); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); +} + + +M68KMAKE_OP(cmpa, 32, ., .) +{ + UINT32 src = M68KMAKE_GET_OPER_AY_32; + UINT32 dst = AX(mc68kcpu); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); +} + + +M68KMAKE_OP(cmpi, 8, ., d) +{ + UINT32 src = OPER_I_8(mc68kcpu); + UINT32 dst = MASK_OUT_ABOVE_8(DY(mc68kcpu)); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_8(res); +} + + +M68KMAKE_OP(cmpi, 8, ., .) +{ + UINT32 src = OPER_I_8(mc68kcpu); + UINT32 dst = M68KMAKE_GET_OPER_AY_8; + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_8(res); +} + + +M68KMAKE_OP(cmpi, 8, ., pcdi) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 src = OPER_I_8(mc68kcpu); + UINT32 dst = OPER_PCDI_8(mc68kcpu); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_8(res); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +M68KMAKE_OP(cmpi, 8, ., pcix) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 src = OPER_I_8(mc68kcpu); + UINT32 dst = OPER_PCIX_8(mc68kcpu); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_8(res); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +M68KMAKE_OP(cmpi, 16, ., d) +{ + UINT32 src = OPER_I_16(mc68kcpu); + UINT32 dst = MASK_OUT_ABOVE_16(DY(mc68kcpu)); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + (mc68kcpu)->v_flag = VFLAG_SUB_16(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_16(res); +} + + +M68KMAKE_OP(cmpi, 16, ., .) +{ + UINT32 src = OPER_I_16(mc68kcpu); + UINT32 dst = M68KMAKE_GET_OPER_AY_16; + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + (mc68kcpu)->v_flag = VFLAG_SUB_16(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_16(res); +} + + +M68KMAKE_OP(cmpi, 16, ., pcdi) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 src = OPER_I_16(mc68kcpu); + UINT32 dst = OPER_PCDI_16(mc68kcpu); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + (mc68kcpu)->v_flag = VFLAG_SUB_16(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_16(res); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +M68KMAKE_OP(cmpi, 16, ., pcix) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 src = OPER_I_16(mc68kcpu); + UINT32 dst = OPER_PCIX_16(mc68kcpu); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + (mc68kcpu)->v_flag = VFLAG_SUB_16(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_16(res); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +M68KMAKE_OP(cmpi, 32, ., d) +{ + UINT32 src = OPER_I_32(mc68kcpu); + UINT32 dst = DY(mc68kcpu); + UINT32 res = dst - src; + + if (!(mc68kcpu)->cmpild_instr_callback.isnull()) + ((mc68kcpu)->cmpild_instr_callback)(*(mc68kcpu)->program, (mc68kcpu)->ir & 7, src, 0xffffffff); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); +} + + +M68KMAKE_OP(cmpi, 32, ., .) +{ + UINT32 src = OPER_I_32(mc68kcpu); + UINT32 dst = M68KMAKE_GET_OPER_AY_32; + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); +} + + +M68KMAKE_OP(cmpi, 32, ., pcdi) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 src = OPER_I_32(mc68kcpu); + UINT32 dst = OPER_PCDI_32(mc68kcpu); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +M68KMAKE_OP(cmpi, 32, ., pcix) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 src = OPER_I_32(mc68kcpu); + UINT32 dst = OPER_PCIX_32(mc68kcpu); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +M68KMAKE_OP(cmpm, 8, ., ax7) +{ + UINT32 src = OPER_AY_PI_8(mc68kcpu); + UINT32 dst = OPER_A7_PI_8(mc68kcpu); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_8(res); +} + + +M68KMAKE_OP(cmpm, 8, ., ay7) +{ + UINT32 src = OPER_A7_PI_8(mc68kcpu); + UINT32 dst = OPER_AX_PI_8(mc68kcpu); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_8(res); +} + + +M68KMAKE_OP(cmpm, 8, ., axy7) +{ + UINT32 src = OPER_A7_PI_8(mc68kcpu); + UINT32 dst = OPER_A7_PI_8(mc68kcpu); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_8(res); +} + + +M68KMAKE_OP(cmpm, 8, ., .) +{ + UINT32 src = OPER_AY_PI_8(mc68kcpu); + UINT32 dst = OPER_AX_PI_8(mc68kcpu); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_8(res); +} + + +M68KMAKE_OP(cmpm, 16, ., .) +{ + UINT32 src = OPER_AY_PI_16(mc68kcpu); + UINT32 dst = OPER_AX_PI_16(mc68kcpu); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + (mc68kcpu)->v_flag = VFLAG_SUB_16(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_16(res); +} + + +M68KMAKE_OP(cmpm, 32, ., .) +{ + UINT32 src = OPER_AY_PI_32(mc68kcpu); + UINT32 dst = OPER_AX_PI_32(mc68kcpu); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); +} + + +M68KMAKE_OP(cpbcc, 32, ., .) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + logerror("%s at %08x: called unimplemented instruction %04x (cpbcc)\n", + (mc68kcpu)->tag(), REG_PC(mc68kcpu) - 2, (mc68kcpu)->ir); + return; + } + m68ki_exception_1111(mc68kcpu); +} + + +M68KMAKE_OP(cpdbcc, 32, ., .) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + logerror("%s at %08x: called unimplemented instruction %04x (cpdbcc)\n", + (mc68kcpu)->tag(), REG_PC(mc68kcpu) - 2, (mc68kcpu)->ir); + return; + } + m68ki_exception_1111(mc68kcpu); +} + + +M68KMAKE_OP(cpgen, 32, ., .) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type) && (mc68kcpu->has_fpu || mc68kcpu->has_pmmu)) + { + logerror("%s at %08x: called unimplemented instruction %04x (cpgen)\n", + (mc68kcpu)->tag(), REG_PC(mc68kcpu) - 2, (mc68kcpu)->ir); + return; + } + m68ki_exception_1111(mc68kcpu); +} + + +M68KMAKE_OP(cpscc, 32, ., .) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + logerror("%s at %08x: called unimplemented instruction %04x (cpscc)\n", + (mc68kcpu)->tag(), REG_PC(mc68kcpu) - 2, (mc68kcpu)->ir); + return; + } + m68ki_exception_1111(mc68kcpu); +} + + +M68KMAKE_OP(cptrapcc, 32, ., .) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + logerror("%s at %08x: called unimplemented instruction %04x (cptrapcc)\n", + (mc68kcpu)->tag(), REG_PC(mc68kcpu) - 2, (mc68kcpu)->ir); + return; + } + m68ki_exception_1111(mc68kcpu); +} + +M68KMAKE_OP(ftrapcc, 32, ., .) +{ + if((mc68kcpu)->has_fpu) + { + m68881_ftrap(mc68kcpu); + return; + } + m68ki_exception_1111(mc68kcpu); +} + +M68KMAKE_OP(dbt, 16, ., .) +{ + REG_PC(mc68kcpu) += 2; +} + + +M68KMAKE_OP(dbf, 16, ., .) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_16(*r_dst - 1); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + if(res != 0xffff) + { + UINT32 offset = OPER_I_16(mc68kcpu); + REG_PC(mc68kcpu) -= 2; + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_16((mc68kcpu), offset); + (mc68kcpu)->remaining_cycles -= (mc68kcpu)->cyc_dbcc_f_noexp; + return; + } + REG_PC(mc68kcpu) += 2; + (mc68kcpu)->remaining_cycles -= (mc68kcpu)->cyc_dbcc_f_exp; +} + + +M68KMAKE_OP(dbcc, 16, ., .) +{ + if(M68KMAKE_NOT_CC) + { + UINT32* r_dst = &DY(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_16(*r_dst - 1); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + if(res != 0xffff) + { + UINT32 offset = OPER_I_16(mc68kcpu); + REG_PC(mc68kcpu) -= 2; + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_16((mc68kcpu), offset); + (mc68kcpu)->remaining_cycles -= (mc68kcpu)->cyc_dbcc_f_noexp; + return; + } + REG_PC(mc68kcpu) += 2; + (mc68kcpu)->remaining_cycles -= (mc68kcpu)->cyc_dbcc_f_exp; + return; + } + REG_PC(mc68kcpu) += 2; +} + + +M68KMAKE_OP(divs, 16, ., d) +{ + UINT32* r_dst = &DX(mc68kcpu); + INT32 src = MAKE_INT_16(DY(mc68kcpu)); + INT32 quotient; + INT32 remainder; + + if(src != 0) + { + if((UINT32)*r_dst == 0x80000000 && src == -1) + { + (mc68kcpu)->not_z_flag = 0; + (mc68kcpu)->n_flag = NFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + *r_dst = 0; + return; + } + + quotient = MAKE_INT_32(*r_dst) / src; + remainder = MAKE_INT_32(*r_dst) % src; + + if(quotient == MAKE_INT_16(quotient)) + { + (mc68kcpu)->not_z_flag = quotient; + (mc68kcpu)->n_flag = NFLAG_16(quotient); + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + *r_dst = MASK_OUT_ABOVE_32(MASK_OUT_ABOVE_16(quotient) | (remainder << 16)); + return; + } + (mc68kcpu)->v_flag = VFLAG_SET; + return; + } + m68ki_exception_trap((mc68kcpu), EXCEPTION_ZERO_DIVIDE); +} + + +M68KMAKE_OP(divs, 16, ., .) +{ + UINT32* r_dst = &DX(mc68kcpu); + INT32 src = MAKE_INT_16(M68KMAKE_GET_OPER_AY_16); + INT32 quotient; + INT32 remainder; + + if(src != 0) + { + if((UINT32)*r_dst == 0x80000000 && src == -1) + { + (mc68kcpu)->not_z_flag = 0; + (mc68kcpu)->n_flag = NFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + *r_dst = 0; + return; + } + + quotient = MAKE_INT_32(*r_dst) / src; + remainder = MAKE_INT_32(*r_dst) % src; + + if(quotient == MAKE_INT_16(quotient)) + { + (mc68kcpu)->not_z_flag = quotient; + (mc68kcpu)->n_flag = NFLAG_16(quotient); + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + *r_dst = MASK_OUT_ABOVE_32(MASK_OUT_ABOVE_16(quotient) | (remainder << 16)); + return; + } + (mc68kcpu)->v_flag = VFLAG_SET; + return; + } + m68ki_exception_trap((mc68kcpu), EXCEPTION_ZERO_DIVIDE); +} + + +M68KMAKE_OP(divu, 16, ., d) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = MASK_OUT_ABOVE_16(DY(mc68kcpu)); + + if(src != 0) + { + UINT32 quotient = *r_dst / src; + UINT32 remainder = *r_dst % src; + + if(quotient < 0x10000) + { + (mc68kcpu)->not_z_flag = quotient; + (mc68kcpu)->n_flag = NFLAG_16(quotient); + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + *r_dst = MASK_OUT_ABOVE_32(MASK_OUT_ABOVE_16(quotient) | (remainder << 16)); + return; + } + (mc68kcpu)->v_flag = VFLAG_SET; + return; + } + m68ki_exception_trap((mc68kcpu), EXCEPTION_ZERO_DIVIDE); +} + + +M68KMAKE_OP(divu, 16, ., .) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = M68KMAKE_GET_OPER_AY_16; + + if(src != 0) + { + UINT32 quotient = *r_dst / src; + UINT32 remainder = *r_dst % src; + + if(quotient < 0x10000) + { + (mc68kcpu)->not_z_flag = quotient; + (mc68kcpu)->n_flag = NFLAG_16(quotient); + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + *r_dst = MASK_OUT_ABOVE_32(MASK_OUT_ABOVE_16(quotient) | (remainder << 16)); + return; + } + (mc68kcpu)->v_flag = VFLAG_SET; + return; + } + m68ki_exception_trap((mc68kcpu), EXCEPTION_ZERO_DIVIDE); +} + + +M68KMAKE_OP(divl, 32, ., d) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT64 divisor = DY(mc68kcpu); + UINT64 dividend = 0; + UINT64 quotient = 0; + UINT64 remainder = 0; + + if(divisor != 0) + { + if(BIT_A(word2)) /* 64 bit */ + { + dividend = REG_D(mc68kcpu)[word2 & 7]; + dividend <<= 32; + dividend |= REG_D(mc68kcpu)[(word2 >> 12) & 7]; + + if(BIT_B(word2)) /* signed */ + { + quotient = (UINT64)((INT64)dividend / (INT64)((INT32)divisor)); + remainder = (UINT64)((INT64)dividend % (INT64)((INT32)divisor)); + if((INT64)quotient != (INT64)((INT32)quotient)) + { + (mc68kcpu)->v_flag = VFLAG_SET; + return; + } + } + else /* unsigned */ + { + quotient = dividend / divisor; + if(quotient > 0xffffffff) + { + (mc68kcpu)->v_flag = VFLAG_SET; + return; + } + remainder = dividend % divisor; + } + } + else /* 32 bit */ + { + dividend = REG_D(mc68kcpu)[(word2 >> 12) & 7]; + if(BIT_B(word2)) /* signed */ + { + quotient = (UINT64)((INT64)((INT32)dividend) / (INT64)((INT32)divisor)); + remainder = (UINT64)((INT64)((INT32)dividend) % (INT64)((INT32)divisor)); + } + else /* unsigned */ + { + quotient = dividend / divisor; + remainder = dividend % divisor; + } + } + + REG_D(mc68kcpu)[word2 & 7] = remainder; + REG_D(mc68kcpu)[(word2 >> 12) & 7] = quotient; + + (mc68kcpu)->n_flag = NFLAG_32(quotient); + (mc68kcpu)->not_z_flag = quotient; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + return; + } + m68ki_exception_trap((mc68kcpu), EXCEPTION_ZERO_DIVIDE); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +M68KMAKE_OP(divl, 32, ., .) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT64 divisor = M68KMAKE_GET_OPER_AY_32; + UINT64 dividend = 0; + UINT64 quotient = 0; + UINT64 remainder = 0; + + if(divisor != 0) + { + if(BIT_A(word2)) /* 64 bit */ + { + dividend = REG_D(mc68kcpu)[word2 & 7]; + dividend <<= 32; + dividend |= REG_D(mc68kcpu)[(word2 >> 12) & 7]; + + if(BIT_B(word2)) /* signed */ + { + quotient = (UINT64)((INT64)dividend / (INT64)((INT32)divisor)); + remainder = (UINT64)((INT64)dividend % (INT64)((INT32)divisor)); + if((INT64)quotient != (INT64)((INT32)quotient)) + { + (mc68kcpu)->v_flag = VFLAG_SET; + return; + } + } + else /* unsigned */ + { + quotient = dividend / divisor; + if(quotient > 0xffffffff) + { + (mc68kcpu)->v_flag = VFLAG_SET; + return; + } + remainder = dividend % divisor; + } + } + else /* 32 bit */ + { + dividend = REG_D(mc68kcpu)[(word2 >> 12) & 7]; + if(BIT_B(word2)) /* signed */ + { + quotient = (UINT64)((INT64)((INT32)dividend) / (INT64)((INT32)divisor)); + remainder = (UINT64)((INT64)((INT32)dividend) % (INT64)((INT32)divisor)); + } + else /* unsigned */ + { + quotient = dividend / divisor; + remainder = dividend % divisor; + } + } + + REG_D(mc68kcpu)[word2 & 7] = remainder; + REG_D(mc68kcpu)[(word2 >> 12) & 7] = quotient; + + (mc68kcpu)->n_flag = NFLAG_32(quotient); + (mc68kcpu)->not_z_flag = quotient; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + return; + } + m68ki_exception_trap((mc68kcpu), EXCEPTION_ZERO_DIVIDE); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +M68KMAKE_OP(eor, 8, ., d) +{ + UINT32 res = MASK_OUT_ABOVE_8(DY(mc68kcpu) ^= MASK_OUT_ABOVE_8(DX(mc68kcpu))); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +M68KMAKE_OP(eor, 8, ., .) +{ + UINT32 ea = M68KMAKE_GET_EA_AY_8; + UINT32 res = MASK_OUT_ABOVE_8(DX(mc68kcpu) ^ m68ki_read_8((mc68kcpu), ea)); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +M68KMAKE_OP(eor, 16, ., d) +{ + UINT32 res = MASK_OUT_ABOVE_16(DY(mc68kcpu) ^= MASK_OUT_ABOVE_16(DX(mc68kcpu))); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +M68KMAKE_OP(eor, 16, ., .) +{ + UINT32 ea = M68KMAKE_GET_EA_AY_16; + UINT32 res = MASK_OUT_ABOVE_16(DX(mc68kcpu) ^ m68ki_read_16((mc68kcpu), ea)); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +M68KMAKE_OP(eor, 32, ., d) +{ + UINT32 res = DY(mc68kcpu) ^= DX(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +M68KMAKE_OP(eor, 32, ., .) +{ + UINT32 ea = M68KMAKE_GET_EA_AY_32; + UINT32 res = DX(mc68kcpu) ^ m68ki_read_32((mc68kcpu), ea); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +M68KMAKE_OP(eori, 8, ., d) +{ + UINT32 res = MASK_OUT_ABOVE_8(DY(mc68kcpu) ^= OPER_I_8(mc68kcpu)); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +M68KMAKE_OP(eori, 8, ., .) +{ + UINT32 src = OPER_I_8(mc68kcpu); + UINT32 ea = M68KMAKE_GET_EA_AY_8; + UINT32 res = src ^ m68ki_read_8((mc68kcpu), ea); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +M68KMAKE_OP(eori, 16, ., d) +{ + UINT32 res = MASK_OUT_ABOVE_16(DY(mc68kcpu) ^= OPER_I_16(mc68kcpu)); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +M68KMAKE_OP(eori, 16, ., .) +{ + UINT32 src = OPER_I_16(mc68kcpu); + UINT32 ea = M68KMAKE_GET_EA_AY_16; + UINT32 res = src ^ m68ki_read_16((mc68kcpu), ea); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +M68KMAKE_OP(eori, 32, ., d) +{ + UINT32 res = DY(mc68kcpu) ^= OPER_I_32(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +M68KMAKE_OP(eori, 32, ., .) +{ + UINT32 src = OPER_I_32(mc68kcpu); + UINT32 ea = M68KMAKE_GET_EA_AY_32; + UINT32 res = src ^ m68ki_read_32((mc68kcpu), ea); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +M68KMAKE_OP(eori, 16, toc, .) +{ + m68ki_set_ccr((mc68kcpu), m68ki_get_ccr(mc68kcpu) ^ OPER_I_16(mc68kcpu)); +} + + +M68KMAKE_OP(eori, 16, tos, .) +{ + if((mc68kcpu)->s_flag) + { + UINT32 src = OPER_I_16(mc68kcpu); + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_set_sr((mc68kcpu), m68ki_get_sr(mc68kcpu) ^ src); + return; + } + m68ki_exception_privilege_violation(mc68kcpu); +} + + +M68KMAKE_OP(exg, 32, dd, .) +{ + UINT32* reg_a = &DX(mc68kcpu); + UINT32* reg_b = &DY(mc68kcpu); + UINT32 tmp = *reg_a; + *reg_a = *reg_b; + *reg_b = tmp; +} + + +M68KMAKE_OP(exg, 32, aa, .) +{ + UINT32* reg_a = &AX(mc68kcpu); + UINT32* reg_b = &AY(mc68kcpu); + UINT32 tmp = *reg_a; + *reg_a = *reg_b; + *reg_b = tmp; +} + + +M68KMAKE_OP(exg, 32, da, .) +{ + UINT32* reg_a = &DX(mc68kcpu); + UINT32* reg_b = &AY(mc68kcpu); + UINT32 tmp = *reg_a; + *reg_a = *reg_b; + *reg_b = tmp; +} + + +M68KMAKE_OP(ext, 16, ., .) +{ + UINT32* r_dst = &DY(mc68kcpu); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | MASK_OUT_ABOVE_8(*r_dst) | (GET_MSB_8(*r_dst) ? 0xff00 : 0); + + (mc68kcpu)->n_flag = NFLAG_16(*r_dst); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(*r_dst); + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +M68KMAKE_OP(ext, 32, ., .) +{ + UINT32* r_dst = &DY(mc68kcpu); + + *r_dst = MASK_OUT_ABOVE_16(*r_dst) | (GET_MSB_16(*r_dst) ? 0xffff0000 : 0); + + (mc68kcpu)->n_flag = NFLAG_32(*r_dst); + (mc68kcpu)->not_z_flag = *r_dst; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +M68KMAKE_OP(extb, 32, ., .) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32* r_dst = &DY(mc68kcpu); + + *r_dst = MASK_OUT_ABOVE_8(*r_dst) | (GET_MSB_8(*r_dst) ? 0xffffff00 : 0); + + (mc68kcpu)->n_flag = NFLAG_32(*r_dst); + (mc68kcpu)->not_z_flag = *r_dst; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +M68KMAKE_OP(illegal, 0, ., .) +{ + m68ki_exception_illegal(mc68kcpu); +} + +M68KMAKE_OP(jmp, 32, ., .) +{ + m68ki_jump((mc68kcpu), M68KMAKE_GET_EA_AY_32); + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + if(REG_PC(mc68kcpu) == REG_PPC(mc68kcpu) && (mc68kcpu)->remaining_cycles > 0) + (mc68kcpu)->remaining_cycles = 0; +} + + +M68KMAKE_OP(jsr, 32, ., .) +{ + UINT32 ea = M68KMAKE_GET_EA_AY_32; + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_push_32((mc68kcpu), REG_PC(mc68kcpu)); + m68ki_jump((mc68kcpu), ea); +} + + +M68KMAKE_OP(lea, 32, ., .) +{ + AX(mc68kcpu) = M68KMAKE_GET_EA_AY_32; +} + + +M68KMAKE_OP(link, 16, ., a7) +{ + REG_A(mc68kcpu)[7] -= 4; + m68ki_write_32((mc68kcpu), REG_A(mc68kcpu)[7], REG_A(mc68kcpu)[7]); + REG_A(mc68kcpu)[7] = MASK_OUT_ABOVE_32(REG_A(mc68kcpu)[7] + MAKE_INT_16(OPER_I_16(mc68kcpu))); +} + + +M68KMAKE_OP(link, 16, ., .) +{ + UINT32* r_dst = &AY(mc68kcpu); + + m68ki_push_32((mc68kcpu), *r_dst); + *r_dst = REG_A(mc68kcpu)[7]; + REG_A(mc68kcpu)[7] = MASK_OUT_ABOVE_32(REG_A(mc68kcpu)[7] + MAKE_INT_16(OPER_I_16(mc68kcpu))); +} + + +M68KMAKE_OP(link, 32, ., a7) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + REG_A(mc68kcpu)[7] -= 4; + m68ki_write_32((mc68kcpu), REG_A(mc68kcpu)[7], REG_A(mc68kcpu)[7]); + REG_A(mc68kcpu)[7] = MASK_OUT_ABOVE_32(REG_A(mc68kcpu)[7] + OPER_I_32(mc68kcpu)); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +M68KMAKE_OP(link, 32, ., .) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32* r_dst = &AY(mc68kcpu); + + m68ki_push_32((mc68kcpu), *r_dst); + *r_dst = REG_A(mc68kcpu)[7]; + REG_A(mc68kcpu)[7] = MASK_OUT_ABOVE_32(REG_A(mc68kcpu)[7] + OPER_I_32(mc68kcpu)); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +M68KMAKE_OP(lsr, 8, s, .) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 shift = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT32 src = MASK_OUT_ABOVE_8(*r_dst); + UINT32 res = src >> shift; + + if(shift != 0) + (mc68kcpu)->remaining_cycles -= shift<<(mc68kcpu)->cyc_shift; + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; + + (mc68kcpu)->n_flag = NFLAG_CLEAR; + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = src << (9-shift); + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +M68KMAKE_OP(lsr, 16, s, .) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 shift = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT32 src = MASK_OUT_ABOVE_16(*r_dst); + UINT32 res = src >> shift; + + if(shift != 0) + (mc68kcpu)->remaining_cycles -= shift<<(mc68kcpu)->cyc_shift; + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + + (mc68kcpu)->n_flag = NFLAG_CLEAR; + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = src << (9-shift); + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +M68KMAKE_OP(lsr, 32, s, .) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 shift = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT32 src = *r_dst; + UINT32 res = src >> shift; + + if(shift != 0) + (mc68kcpu)->remaining_cycles -= shift<<(mc68kcpu)->cyc_shift; + + *r_dst = res; + + (mc68kcpu)->n_flag = NFLAG_CLEAR; + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = src << (9-shift); + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +M68KMAKE_OP(lsr, 8, r, .) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 shift = DX(mc68kcpu) & 0x3f; + UINT32 src = MASK_OUT_ABOVE_8(*r_dst); + UINT32 res = src >> shift; + + if(shift != 0) + { + (mc68kcpu)->remaining_cycles -= shift<<(mc68kcpu)->cyc_shift; + + if(shift <= 8) + { + *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = src << (9-shift); + (mc68kcpu)->n_flag = NFLAG_CLEAR; + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + return; + } + + *r_dst &= 0xffffff00; + (mc68kcpu)->x_flag = XFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->n_flag = NFLAG_CLEAR; + (mc68kcpu)->not_z_flag = ZFLAG_SET; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + return; + } + + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->n_flag = NFLAG_8(src); + (mc68kcpu)->not_z_flag = src; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +M68KMAKE_OP(lsr, 16, r, .) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 shift = DX(mc68kcpu) & 0x3f; + UINT32 src = MASK_OUT_ABOVE_16(*r_dst); + UINT32 res = src >> shift; + + if(shift != 0) + { + (mc68kcpu)->remaining_cycles -= shift<<(mc68kcpu)->cyc_shift; + + if(shift <= 16) + { + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag = (src >> (shift - 1))<<8; + (mc68kcpu)->n_flag = NFLAG_CLEAR; + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + return; + } + + *r_dst &= 0xffff0000; + (mc68kcpu)->x_flag = XFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->n_flag = NFLAG_CLEAR; + (mc68kcpu)->not_z_flag = ZFLAG_SET; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + return; + } + + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->n_flag = NFLAG_16(src); + (mc68kcpu)->not_z_flag = src; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +M68KMAKE_OP(lsr, 32, r, .) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 shift = DX(mc68kcpu) & 0x3f; + UINT32 src = *r_dst; + UINT32 res = src >> shift; + + if(shift != 0) + { + (mc68kcpu)->remaining_cycles -= shift<<(mc68kcpu)->cyc_shift; + + if(shift < 32) + { + *r_dst = res; + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag = (src >> (shift - 1))<<8; + (mc68kcpu)->n_flag = NFLAG_CLEAR; + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + return; + } + + *r_dst = 0; + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = (shift == 32 ? GET_MSB_32(src)>>23 : 0); + (mc68kcpu)->n_flag = NFLAG_CLEAR; + (mc68kcpu)->not_z_flag = ZFLAG_SET; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + return; + } + + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->n_flag = NFLAG_32(src); + (mc68kcpu)->not_z_flag = src; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +M68KMAKE_OP(lsr, 16, ., .) +{ + UINT32 ea = M68KMAKE_GET_EA_AY_16; + UINT32 src = m68ki_read_16((mc68kcpu), ea); + UINT32 res = src >> 1; + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_CLEAR; + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag = src << 8; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +M68KMAKE_OP(lsl, 8, s, .) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 shift = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT32 src = MASK_OUT_ABOVE_8(*r_dst); + UINT32 res = MASK_OUT_ABOVE_8(src << shift); + + if(shift != 0) + (mc68kcpu)->remaining_cycles -= shift<<(mc68kcpu)->cyc_shift; + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = src << shift; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +M68KMAKE_OP(lsl, 16, s, .) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 shift = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT32 src = MASK_OUT_ABOVE_16(*r_dst); + UINT32 res = MASK_OUT_ABOVE_16(src << shift); + + if(shift != 0) + (mc68kcpu)->remaining_cycles -= shift<<(mc68kcpu)->cyc_shift; + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = src >> (8-shift); + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +M68KMAKE_OP(lsl, 32, s, .) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 shift = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT32 src = *r_dst; + UINT32 res = MASK_OUT_ABOVE_32(src << shift); + + if(shift != 0) + (mc68kcpu)->remaining_cycles -= shift<<(mc68kcpu)->cyc_shift; + + *r_dst = res; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = src >> (24-shift); + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +M68KMAKE_OP(lsl, 8, r, .) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 shift = DX(mc68kcpu) & 0x3f; + UINT32 src = MASK_OUT_ABOVE_8(*r_dst); + UINT32 res = MASK_OUT_ABOVE_8(src << shift); + + if(shift != 0) + { + (mc68kcpu)->remaining_cycles -= shift<<(mc68kcpu)->cyc_shift; + + if(shift <= 8) + { + *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = src << shift; + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + return; + } + + *r_dst &= 0xffffff00; + (mc68kcpu)->x_flag = XFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->n_flag = NFLAG_CLEAR; + (mc68kcpu)->not_z_flag = ZFLAG_SET; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + return; + } + + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->n_flag = NFLAG_8(src); + (mc68kcpu)->not_z_flag = src; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +M68KMAKE_OP(lsl, 16, r, .) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 shift = DX(mc68kcpu) & 0x3f; + UINT32 src = MASK_OUT_ABOVE_16(*r_dst); + UINT32 res = MASK_OUT_ABOVE_16(src << shift); + + if(shift != 0) + { + (mc68kcpu)->remaining_cycles -= shift<<(mc68kcpu)->cyc_shift; + + if(shift <= 16) + { + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = (src << shift) >> 8; + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + return; + } + + *r_dst &= 0xffff0000; + (mc68kcpu)->x_flag = XFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->n_flag = NFLAG_CLEAR; + (mc68kcpu)->not_z_flag = ZFLAG_SET; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + return; + } + + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->n_flag = NFLAG_16(src); + (mc68kcpu)->not_z_flag = src; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +M68KMAKE_OP(lsl, 32, r, .) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 shift = DX(mc68kcpu) & 0x3f; + UINT32 src = *r_dst; + UINT32 res = MASK_OUT_ABOVE_32(src << shift); + + if(shift != 0) + { + (mc68kcpu)->remaining_cycles -= shift<<(mc68kcpu)->cyc_shift; + + if(shift < 32) + { + *r_dst = res; + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = (src >> (32 - shift)) << 8; + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + return; + } + + *r_dst = 0; + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = ((shift == 32 ? src & 1 : 0))<<8; + (mc68kcpu)->n_flag = NFLAG_CLEAR; + (mc68kcpu)->not_z_flag = ZFLAG_SET; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + return; + } + + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->n_flag = NFLAG_32(src); + (mc68kcpu)->not_z_flag = src; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +M68KMAKE_OP(lsl, 16, ., .) +{ + UINT32 ea = M68KMAKE_GET_EA_AY_16; + UINT32 src = m68ki_read_16((mc68kcpu), ea); + UINT32 res = MASK_OUT_ABOVE_16(src << 1); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = src >> 7; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 8, d, d) +{ + UINT32 res = MASK_OUT_ABOVE_8(DY(mc68kcpu)); + UINT32* r_dst = &DX(mc68kcpu); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 8, d, .) +{ + UINT32 res = M68KMAKE_GET_OPER_AY_8; + UINT32* r_dst = &DX(mc68kcpu); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 8, ai, d) +{ + UINT32 res = MASK_OUT_ABOVE_8(DY(mc68kcpu)); + UINT32 ea = EA_AX_AI_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 8, ai, .) +{ + UINT32 res = M68KMAKE_GET_OPER_AY_8; + UINT32 ea = EA_AX_AI_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 8, pi7, d) +{ + UINT32 res = MASK_OUT_ABOVE_8(DY(mc68kcpu)); + UINT32 ea = EA_A7_PI_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 8, pi, d) +{ + UINT32 res = MASK_OUT_ABOVE_8(DY(mc68kcpu)); + UINT32 ea = EA_AX_PI_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 8, pi7, .) +{ + UINT32 res = M68KMAKE_GET_OPER_AY_8; + UINT32 ea = EA_A7_PI_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 8, pi, .) +{ + UINT32 res = M68KMAKE_GET_OPER_AY_8; + UINT32 ea = EA_AX_PI_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 8, pd7, d) +{ + UINT32 res = MASK_OUT_ABOVE_8(DY(mc68kcpu)); + UINT32 ea = EA_A7_PD_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 8, pd, d) +{ + UINT32 res = MASK_OUT_ABOVE_8(DY(mc68kcpu)); + UINT32 ea = EA_AX_PD_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 8, pd7, .) +{ + UINT32 res = M68KMAKE_GET_OPER_AY_8; + UINT32 ea = EA_A7_PD_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 8, pd, .) +{ + UINT32 res = M68KMAKE_GET_OPER_AY_8; + UINT32 ea = EA_AX_PD_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 8, di, d) +{ + UINT32 res = MASK_OUT_ABOVE_8(DY(mc68kcpu)); + UINT32 ea = EA_AX_DI_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 8, di, .) +{ + UINT32 res = M68KMAKE_GET_OPER_AY_8; + UINT32 ea = EA_AX_DI_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 8, ix, d) +{ + UINT32 res = MASK_OUT_ABOVE_8(DY(mc68kcpu)); + UINT32 ea = EA_AX_IX_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 8, ix, .) +{ + UINT32 res = M68KMAKE_GET_OPER_AY_8; + UINT32 ea = EA_AX_IX_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 8, aw, d) +{ + UINT32 res = MASK_OUT_ABOVE_8(DY(mc68kcpu)); + UINT32 ea = EA_AW_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 8, aw, .) +{ + UINT32 res = M68KMAKE_GET_OPER_AY_8; + UINT32 ea = EA_AW_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 8, al, d) +{ + UINT32 res = MASK_OUT_ABOVE_8(DY(mc68kcpu)); + UINT32 ea = EA_AL_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 8, al, .) +{ + UINT32 res = M68KMAKE_GET_OPER_AY_8; + UINT32 ea = EA_AL_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 16, d, d) +{ + UINT32 res = MASK_OUT_ABOVE_16(DY(mc68kcpu)); + UINT32* r_dst = &DX(mc68kcpu); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 16, d, a) +{ + UINT32 res = MASK_OUT_ABOVE_16(AY(mc68kcpu)); + UINT32* r_dst = &DX(mc68kcpu); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 16, d, .) +{ + UINT32 res = M68KMAKE_GET_OPER_AY_16; + UINT32* r_dst = &DX(mc68kcpu); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 16, ai, d) +{ + UINT32 res = MASK_OUT_ABOVE_16(DY(mc68kcpu)); + UINT32 ea = EA_AX_AI_16(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 16, ai, a) +{ + UINT32 res = MASK_OUT_ABOVE_16(AY(mc68kcpu)); + UINT32 ea = EA_AX_AI_16(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 16, ai, .) +{ + UINT32 res = M68KMAKE_GET_OPER_AY_16; + UINT32 ea = EA_AX_AI_16(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 16, pi, d) +{ + UINT32 res = MASK_OUT_ABOVE_16(DY(mc68kcpu)); + UINT32 ea = EA_AX_PI_16(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 16, pi, a) +{ + UINT32 res = MASK_OUT_ABOVE_16(AY(mc68kcpu)); + UINT32 ea = EA_AX_PI_16(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 16, pi, .) +{ + UINT32 res = M68KMAKE_GET_OPER_AY_16; + UINT32 ea = EA_AX_PI_16(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 16, pd, d) +{ + UINT32 res = MASK_OUT_ABOVE_16(DY(mc68kcpu)); + UINT32 ea = EA_AX_PD_16(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 16, pd, a) +{ + UINT32 res = MASK_OUT_ABOVE_16(AY(mc68kcpu)); + UINT32 ea = EA_AX_PD_16(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 16, pd, .) +{ + UINT32 res = M68KMAKE_GET_OPER_AY_16; + UINT32 ea = EA_AX_PD_16(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 16, di, d) +{ + UINT32 res = MASK_OUT_ABOVE_16(DY(mc68kcpu)); + UINT32 ea = EA_AX_DI_16(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 16, di, a) +{ + UINT32 res = MASK_OUT_ABOVE_16(AY(mc68kcpu)); + UINT32 ea = EA_AX_DI_16(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 16, di, .) +{ + UINT32 res = M68KMAKE_GET_OPER_AY_16; + UINT32 ea = EA_AX_DI_16(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 16, ix, d) +{ + UINT32 res = MASK_OUT_ABOVE_16(DY(mc68kcpu)); + UINT32 ea = EA_AX_IX_16(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 16, ix, a) +{ + UINT32 res = MASK_OUT_ABOVE_16(AY(mc68kcpu)); + UINT32 ea = EA_AX_IX_16(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 16, ix, .) +{ + UINT32 res = M68KMAKE_GET_OPER_AY_16; + UINT32 ea = EA_AX_IX_16(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 16, aw, d) +{ + UINT32 res = MASK_OUT_ABOVE_16(DY(mc68kcpu)); + UINT32 ea = EA_AW_16(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 16, aw, a) +{ + UINT32 res = MASK_OUT_ABOVE_16(AY(mc68kcpu)); + UINT32 ea = EA_AW_16(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 16, aw, .) +{ + UINT32 res = M68KMAKE_GET_OPER_AY_16; + UINT32 ea = EA_AW_16(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 16, al, d) +{ + UINT32 res = MASK_OUT_ABOVE_16(DY(mc68kcpu)); + UINT32 ea = EA_AL_16(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 16, al, a) +{ + UINT32 res = MASK_OUT_ABOVE_16(AY(mc68kcpu)); + UINT32 ea = EA_AL_16(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 16, al, .) +{ + UINT32 res = M68KMAKE_GET_OPER_AY_16; + UINT32 ea = EA_AL_16(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 32, d, d) +{ + UINT32 res = DY(mc68kcpu); + UINT32* r_dst = &DX(mc68kcpu); + + *r_dst = res; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 32, d, a) +{ + UINT32 res = AY(mc68kcpu); + UINT32* r_dst = &DX(mc68kcpu); + + *r_dst = res; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 32, d, .) +{ + UINT32 res = M68KMAKE_GET_OPER_AY_32; + UINT32* r_dst = &DX(mc68kcpu); + + *r_dst = res; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 32, ai, d) +{ + UINT32 res = DY(mc68kcpu); + UINT32 ea = EA_AX_AI_32(mc68kcpu); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 32, ai, a) +{ + UINT32 res = AY(mc68kcpu); + UINT32 ea = EA_AX_AI_32(mc68kcpu); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 32, ai, .) +{ + UINT32 res = M68KMAKE_GET_OPER_AY_32; + UINT32 ea = EA_AX_AI_32(mc68kcpu); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 32, pi, d) +{ + UINT32 res = DY(mc68kcpu); + UINT32 ea = EA_AX_PI_32(mc68kcpu); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 32, pi, a) +{ + UINT32 res = AY(mc68kcpu); + UINT32 ea = EA_AX_PI_32(mc68kcpu); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 32, pi, .) +{ + UINT32 res = M68KMAKE_GET_OPER_AY_32; + UINT32 ea = EA_AX_PI_32(mc68kcpu); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 32, pd, d) +{ + UINT32 res = DY(mc68kcpu); + UINT32 ea = EA_AX_PD_32(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea+2, res & 0xFFFF ); + m68ki_write_16((mc68kcpu), ea, (res >> 16) & 0xFFFF ); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 32, pd, a) +{ + UINT32 res = AY(mc68kcpu); + UINT32 ea = EA_AX_PD_32(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea+2, res & 0xFFFF ); + m68ki_write_16((mc68kcpu), ea, (res >> 16) & 0xFFFF ); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 32, pd, .) +{ + UINT32 res = M68KMAKE_GET_OPER_AY_32; + UINT32 ea = EA_AX_PD_32(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea+2, res & 0xFFFF ); + m68ki_write_16((mc68kcpu), ea, (res >> 16) & 0xFFFF ); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 32, di, d) +{ + UINT32 res = DY(mc68kcpu); + UINT32 ea = EA_AX_DI_32(mc68kcpu); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 32, di, a) +{ + UINT32 res = AY(mc68kcpu); + UINT32 ea = EA_AX_DI_32(mc68kcpu); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 32, di, .) +{ + UINT32 res = M68KMAKE_GET_OPER_AY_32; + UINT32 ea = EA_AX_DI_32(mc68kcpu); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 32, ix, d) +{ + UINT32 res = DY(mc68kcpu); + UINT32 ea = EA_AX_IX_32(mc68kcpu); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 32, ix, a) +{ + UINT32 res = AY(mc68kcpu); + UINT32 ea = EA_AX_IX_32(mc68kcpu); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 32, ix, .) +{ + UINT32 res = M68KMAKE_GET_OPER_AY_32; + UINT32 ea = EA_AX_IX_32(mc68kcpu); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 32, aw, d) +{ + UINT32 res = DY(mc68kcpu); + UINT32 ea = EA_AW_32(mc68kcpu); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 32, aw, a) +{ + UINT32 res = AY(mc68kcpu); + UINT32 ea = EA_AW_32(mc68kcpu); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 32, aw, .) +{ + UINT32 res = M68KMAKE_GET_OPER_AY_32; + UINT32 ea = EA_AW_32(mc68kcpu); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 32, al, d) +{ + UINT32 res = DY(mc68kcpu); + UINT32 ea = EA_AL_32(mc68kcpu); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 32, al, a) +{ + UINT32 res = AY(mc68kcpu); + UINT32 ea = EA_AL_32(mc68kcpu); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move, 32, al, .) +{ + UINT32 res = M68KMAKE_GET_OPER_AY_32; + UINT32 ea = EA_AL_32(mc68kcpu); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +M68KMAKE_OP(movea, 16, ., d) +{ + AX(mc68kcpu) = MAKE_INT_16(DY(mc68kcpu)); +} + + +M68KMAKE_OP(movea, 16, ., a) +{ + AX(mc68kcpu) = MAKE_INT_16(AY(mc68kcpu)); +} + + +M68KMAKE_OP(movea, 16, ., .) +{ + AX(mc68kcpu) = MAKE_INT_16(M68KMAKE_GET_OPER_AY_16); +} + + +M68KMAKE_OP(movea, 32, ., d) +{ + AX(mc68kcpu) = DY(mc68kcpu); +} + + +M68KMAKE_OP(movea, 32, ., a) +{ + AX(mc68kcpu) = AY(mc68kcpu); +} + + +M68KMAKE_OP(movea, 32, ., .) +{ + AX(mc68kcpu) = M68KMAKE_GET_OPER_AY_32; +} + + +M68KMAKE_OP(move, 16, frc, d) +{ + if(CPU_TYPE_IS_010_PLUS((mc68kcpu)->cpu_type)) + { + DY(mc68kcpu) = MASK_OUT_BELOW_16(DY(mc68kcpu)) | m68ki_get_ccr(mc68kcpu); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +M68KMAKE_OP(move, 16, frc, .) +{ + if(CPU_TYPE_IS_010_PLUS((mc68kcpu)->cpu_type)) + { + m68ki_write_16((mc68kcpu), M68KMAKE_GET_EA_AY_16, m68ki_get_ccr(mc68kcpu)); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +M68KMAKE_OP(move, 16, toc, d) +{ + m68ki_set_ccr((mc68kcpu), DY(mc68kcpu)); +} + + +M68KMAKE_OP(move, 16, toc, .) +{ + m68ki_set_ccr((mc68kcpu), M68KMAKE_GET_OPER_AY_16); +} + + +M68KMAKE_OP(move, 16, frs, d) +{ + if(CPU_TYPE_IS_000((mc68kcpu)->cpu_type) || (mc68kcpu)->s_flag) /* NS990408 */ + { + DY(mc68kcpu) = MASK_OUT_BELOW_16(DY(mc68kcpu)) | m68ki_get_sr(mc68kcpu); + return; + } + m68ki_exception_privilege_violation(mc68kcpu); +} + + +M68KMAKE_OP(move, 16, frs, .) +{ + if(CPU_TYPE_IS_000((mc68kcpu)->cpu_type) || (mc68kcpu)->s_flag) /* NS990408 */ + { + UINT32 ea = M68KMAKE_GET_EA_AY_16; + m68ki_write_16((mc68kcpu), ea, m68ki_get_sr(mc68kcpu)); + return; + } + m68ki_exception_privilege_violation(mc68kcpu); +} + + +M68KMAKE_OP(move, 16, tos, d) +{ + if((mc68kcpu)->s_flag) + { + m68ki_set_sr((mc68kcpu), DY(mc68kcpu)); + return; + } + m68ki_exception_privilege_violation(mc68kcpu); +} + + +M68KMAKE_OP(move, 16, tos, .) +{ + if((mc68kcpu)->s_flag) + { + UINT32 new_sr = M68KMAKE_GET_OPER_AY_16; + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_set_sr((mc68kcpu), new_sr); + return; + } + m68ki_exception_privilege_violation(mc68kcpu); +} + + +M68KMAKE_OP(move, 32, fru, .) +{ + if((mc68kcpu)->s_flag) + { + AY(mc68kcpu) = REG_USP(mc68kcpu); + return; + } + m68ki_exception_privilege_violation(mc68kcpu); +} + + +M68KMAKE_OP(move, 32, tou, .) +{ + if((mc68kcpu)->s_flag) + { + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + REG_USP(mc68kcpu) = AY(mc68kcpu); + return; + } + m68ki_exception_privilege_violation(mc68kcpu); +} + + +M68KMAKE_OP(movec, 32, cr, .) +{ + if(CPU_TYPE_IS_010_PLUS((mc68kcpu)->cpu_type)) + { + if((mc68kcpu)->s_flag) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + switch (word2 & 0xfff) + { + case 0x000: /* SFC */ + REG_DA(mc68kcpu)[(word2 >> 12) & 15] = (mc68kcpu)->sfc; + return; + case 0x001: /* DFC */ + REG_DA(mc68kcpu)[(word2 >> 12) & 15] = (mc68kcpu)->dfc; + return; + case 0x002: /* CACR */ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + REG_DA(mc68kcpu)[(word2 >> 12) & 15] = (mc68kcpu)->cacr; + return; + } + return; + case 0x800: /* USP */ + REG_DA(mc68kcpu)[(word2 >> 12) & 15] = REG_USP(mc68kcpu); + return; + case 0x801: /* VBR */ + REG_DA(mc68kcpu)[(word2 >> 12) & 15] = (mc68kcpu)->vbr; + return; + case 0x802: /* CAAR */ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + REG_DA(mc68kcpu)[(word2 >> 12) & 15] = (mc68kcpu)->caar; + return; + } + m68ki_exception_illegal(mc68kcpu); + break; + case 0x803: /* MSP */ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + REG_DA(mc68kcpu)[(word2 >> 12) & 15] = (mc68kcpu)->m_flag ? REG_SP(mc68kcpu) : REG_MSP(mc68kcpu); + return; + } + m68ki_exception_illegal(mc68kcpu); + return; + case 0x804: /* ISP */ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + REG_DA(mc68kcpu)[(word2 >> 12) & 15] = (mc68kcpu)->m_flag ? REG_ISP(mc68kcpu) : REG_SP(mc68kcpu); + return; + } + m68ki_exception_illegal(mc68kcpu); + return; + case 0x003: /* TC */ + if(CPU_TYPE_IS_040_PLUS((mc68kcpu)->cpu_type)) + { + REG_DA(mc68kcpu)[(word2 >> 12) & 15] = mc68kcpu->mmu_tc; + return; + } + m68ki_exception_illegal(mc68kcpu); + return; + case 0x004: /* ITT0 (040+, ACR0 on ColdFire) */ + if(CPU_TYPE_IS_040_PLUS((mc68kcpu)->cpu_type)) + { + REG_DA(mc68kcpu)[(word2 >> 12) & 15] = mc68kcpu->mmu_itt0; + return; + } + else if(CPU_TYPE_IS_COLDFIRE((mc68kcpu)->cpu_type)) + { + REG_DA(mc68kcpu)[(word2 >> 12) & 15] = mc68kcpu->mmu_acr0; + return; + } + m68ki_exception_illegal(mc68kcpu); + return; + case 0x005: /* ITT1 (040+, ACR1 on ColdFire) */ + if(CPU_TYPE_IS_040_PLUS((mc68kcpu)->cpu_type)) + { + REG_DA(mc68kcpu)[(word2 >> 12) & 15] = mc68kcpu->mmu_itt1; + return; + } + else if(CPU_TYPE_IS_COLDFIRE((mc68kcpu)->cpu_type)) + { + REG_DA(mc68kcpu)[(word2 >> 12) & 15] = mc68kcpu->mmu_acr1; + return; + } + m68ki_exception_illegal(mc68kcpu); + return; + case 0x006: /* DTT0 */ + if(CPU_TYPE_IS_040_PLUS((mc68kcpu)->cpu_type)) + { + REG_DA(mc68kcpu)[(word2 >> 12) & 15] = mc68kcpu->mmu_dtt0; + return; + } + else if(CPU_TYPE_IS_COLDFIRE((mc68kcpu)->cpu_type)) + { + REG_DA(mc68kcpu)[(word2 >> 12) & 15] = mc68kcpu->mmu_acr2; + return; + } + m68ki_exception_illegal(mc68kcpu); + return; + case 0x007: /* DTT1 */ + if(CPU_TYPE_IS_040_PLUS((mc68kcpu)->cpu_type)) + { + REG_DA(mc68kcpu)[(word2 >> 12) & 15] = mc68kcpu->mmu_dtt1; + return; + } + else if(CPU_TYPE_IS_COLDFIRE((mc68kcpu)->cpu_type)) + { + REG_DA(mc68kcpu)[(word2 >> 12) & 15] = mc68kcpu->mmu_acr3; + return; + } + m68ki_exception_illegal(mc68kcpu); + return; + case 0x805: /* MMUSR */ + if(CPU_TYPE_IS_040_PLUS((mc68kcpu)->cpu_type)) + { + REG_DA(mc68kcpu)[(word2 >> 12) & 15] = mc68kcpu->mmu_sr_040; + return; + } + m68ki_exception_illegal(mc68kcpu); + return; + case 0x806: /* URP */ + if(CPU_TYPE_IS_040_PLUS((mc68kcpu)->cpu_type)) + { + REG_DA(mc68kcpu)[(word2 >> 12) & 15] = mc68kcpu->mmu_urp_aptr; + return; + } + m68ki_exception_illegal(mc68kcpu); + return; + case 0x807: /* SRP */ + if(CPU_TYPE_IS_040_PLUS((mc68kcpu)->cpu_type)) + { + REG_DA(mc68kcpu)[(word2 >> 12) & 15] = mc68kcpu->mmu_srp_aptr; + return; + } + m68ki_exception_illegal(mc68kcpu); + return; + case 0xc00: // ROMBAR0 + if(CPU_TYPE_IS_COLDFIRE((mc68kcpu)->cpu_type)) + { + /* TODO */ + return; + } + m68ki_exception_illegal(mc68kcpu); + return; + case 0xc01: // ROMBAR1 + if(CPU_TYPE_IS_COLDFIRE((mc68kcpu)->cpu_type)) + { + /* TODO */ + return; + } + m68ki_exception_illegal(mc68kcpu); + return; + case 0xc04: // RAMBAR0 + if(CPU_TYPE_IS_COLDFIRE((mc68kcpu)->cpu_type)) + { + /* TODO */ + return; + } + m68ki_exception_illegal(mc68kcpu); + return; + case 0xc05: // RAMBAR1 + if(CPU_TYPE_IS_COLDFIRE((mc68kcpu)->cpu_type)) + { + /* TODO */ + return; + } + m68ki_exception_illegal(mc68kcpu); + return; + case 0xc0c: // MPCR + if(CPU_TYPE_IS_COLDFIRE((mc68kcpu)->cpu_type)) + { + /* TODO */ + return; + } + m68ki_exception_illegal(mc68kcpu); + return; + case 0xc0d: // EDRAMBAR + if(CPU_TYPE_IS_COLDFIRE((mc68kcpu)->cpu_type)) + { + /* TODO */ + return; + } + m68ki_exception_illegal(mc68kcpu); + return; + case 0xc0e: // SECMBAR + if(CPU_TYPE_IS_COLDFIRE((mc68kcpu)->cpu_type)) + { + /* TODO */ + return; + } + m68ki_exception_illegal(mc68kcpu); + return; + case 0xc0f: // MBAR + if(CPU_TYPE_IS_COLDFIRE((mc68kcpu)->cpu_type)) + { + /* TODO */ + return; + } + m68ki_exception_illegal(mc68kcpu); + return; + default: + m68ki_exception_illegal(mc68kcpu); + return; + } + } + m68ki_exception_privilege_violation(mc68kcpu); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +M68KMAKE_OP(movec, 32, rc, .) +{ + if(CPU_TYPE_IS_010_PLUS((mc68kcpu)->cpu_type)) + { + if((mc68kcpu)->s_flag) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + switch (word2 & 0xfff) + { + case 0x000: /* SFC */ + (mc68kcpu)->sfc = REG_DA(mc68kcpu)[(word2 >> 12) & 15] & 7; + return; + case 0x001: /* DFC */ + (mc68kcpu)->dfc = REG_DA(mc68kcpu)[(word2 >> 12) & 15] & 7; + return; + case 0x002: /* CACR */ + /* Only EC020 and later have CACR */ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + /* 68030 can write all bits except 5-7, 040 can write all */ + if (CPU_TYPE_IS_040_PLUS((mc68kcpu)->cpu_type)) + { + (mc68kcpu)->cacr = REG_DA(mc68kcpu)[(word2 >> 12) & 15]; + } + else if (CPU_TYPE_IS_030_PLUS((mc68kcpu)->cpu_type)) + { + (mc68kcpu)->cacr = REG_DA(mc68kcpu)[(word2 >> 12) & 15] & 0xff1f; + } + else + { + (mc68kcpu)->cacr = REG_DA(mc68kcpu)[(word2 >> 12) & 15] & 0x0f; + } + +// logerror("movec to cacr=%04x\n", (mc68kcpu)->cacr); + if ((mc68kcpu)->cacr & (M68K_CACR_CI | M68K_CACR_CEI)) + { + m68ki_ic_clear(mc68kcpu); + } + return; + } + m68ki_exception_illegal(mc68kcpu); + return; + case 0x800: /* USP */ + REG_USP(mc68kcpu) = REG_DA(mc68kcpu)[(word2 >> 12) & 15]; + return; + case 0x801: /* VBR */ + (mc68kcpu)->vbr = REG_DA(mc68kcpu)[(word2 >> 12) & 15]; + return; + case 0x802: /* CAAR */ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + (mc68kcpu)->caar = REG_DA(mc68kcpu)[(word2 >> 12) & 15]; + return; + } + m68ki_exception_illegal(mc68kcpu); + return; + case 0x803: /* MSP */ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + /* we are in supervisor mode so just check for M flag */ + if(!(mc68kcpu)->m_flag) + { + REG_MSP(mc68kcpu) = REG_DA(mc68kcpu)[(word2 >> 12) & 15]; + return; + } + REG_SP(mc68kcpu) = REG_DA(mc68kcpu)[(word2 >> 12) & 15]; + return; + } + m68ki_exception_illegal(mc68kcpu); + return; + case 0x804: /* ISP */ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + if(!(mc68kcpu)->m_flag) + { + REG_SP(mc68kcpu) = REG_DA(mc68kcpu)[(word2 >> 12) & 15]; + return; + } + REG_ISP(mc68kcpu) = REG_DA(mc68kcpu)[(word2 >> 12) & 15]; + return; + } + m68ki_exception_illegal(mc68kcpu); + return; + case 0x003: /* TC */ + if (CPU_TYPE_IS_040_PLUS((mc68kcpu)->cpu_type)) + { + mc68kcpu->mmu_tc = REG_DA(mc68kcpu)[(word2 >> 12) & 15]; + + if (mc68kcpu->mmu_tc & 0x8000) + { + mc68kcpu->pmmu_enabled = 1; + } + else + { + mc68kcpu->pmmu_enabled = 0; + } + return; + } + m68ki_exception_illegal(mc68kcpu); + return; + case 0x004: /* ITT0 */ + if (CPU_TYPE_IS_040_PLUS((mc68kcpu)->cpu_type)) + { + mc68kcpu->mmu_itt0 = REG_DA(mc68kcpu)[(word2 >> 12) & 15]; + return; + } + else if(CPU_TYPE_IS_COLDFIRE((mc68kcpu)->cpu_type)) + { + mc68kcpu->mmu_acr0 = REG_DA(mc68kcpu)[(word2 >> 12) & 15]; + return; + } + m68ki_exception_illegal(mc68kcpu); + return; + case 0x005: /* ITT1 */ + if (CPU_TYPE_IS_040_PLUS((mc68kcpu)->cpu_type)) + { + mc68kcpu->mmu_itt1 = REG_DA(mc68kcpu)[(word2 >> 12) & 15]; + return; + } + else if(CPU_TYPE_IS_COLDFIRE((mc68kcpu)->cpu_type)) + { + mc68kcpu->mmu_acr1 = REG_DA(mc68kcpu)[(word2 >> 12) & 15]; + return; + } + m68ki_exception_illegal(mc68kcpu); + return; + case 0x006: /* DTT0 */ + if (CPU_TYPE_IS_040_PLUS((mc68kcpu)->cpu_type)) + { + mc68kcpu->mmu_dtt0 = REG_DA(mc68kcpu)[(word2 >> 12) & 15]; + return; + } + else if(CPU_TYPE_IS_COLDFIRE((mc68kcpu)->cpu_type)) + { + mc68kcpu->mmu_acr2 = REG_DA(mc68kcpu)[(word2 >> 12) & 15]; + return; + } + m68ki_exception_illegal(mc68kcpu); + return; + case 0x007: /* DTT1 */ + if (CPU_TYPE_IS_040_PLUS((mc68kcpu)->cpu_type)) + { + mc68kcpu->mmu_dtt1 = REG_DA(mc68kcpu)[(word2 >> 12) & 15]; + return; + } + else if(CPU_TYPE_IS_COLDFIRE((mc68kcpu)->cpu_type)) + { + mc68kcpu->mmu_acr3 = REG_DA(mc68kcpu)[(word2 >> 12) & 15]; + return; + } + m68ki_exception_illegal(mc68kcpu); + return; + case 0x805: /* MMUSR */ + if (CPU_TYPE_IS_040_PLUS((mc68kcpu)->cpu_type)) + { + mc68kcpu->mmu_sr_040 = REG_DA(mc68kcpu)[(word2 >> 12) & 15]; + return; + } + m68ki_exception_illegal(mc68kcpu); + return; + case 0x806: /* URP */ + if (CPU_TYPE_IS_040_PLUS((mc68kcpu)->cpu_type)) + { + mc68kcpu->mmu_urp_aptr = REG_DA(mc68kcpu)[(word2 >> 12) & 15]; + return; + } + m68ki_exception_illegal(mc68kcpu); + return; + case 0x807: /* SRP */ + if (CPU_TYPE_IS_040_PLUS((mc68kcpu)->cpu_type)) + { + mc68kcpu->mmu_srp_aptr = REG_DA(mc68kcpu)[(word2 >> 12) & 15]; + return; + } + m68ki_exception_illegal(mc68kcpu); + return; + case 0xc00: // ROMBAR0 + if(CPU_TYPE_IS_COLDFIRE((mc68kcpu)->cpu_type)) + { + /* TODO */ + return; + } + m68ki_exception_illegal(mc68kcpu); + return; + case 0xc01: // ROMBAR1 + if(CPU_TYPE_IS_COLDFIRE((mc68kcpu)->cpu_type)) + { + /* TODO */ + return; + } + m68ki_exception_illegal(mc68kcpu); + return; + case 0xc04: // RAMBAR0 + if(CPU_TYPE_IS_COLDFIRE((mc68kcpu)->cpu_type)) + { + /* TODO */ + return; + } + m68ki_exception_illegal(mc68kcpu); + return; + case 0xc05: // RAMBAR1 + if(CPU_TYPE_IS_COLDFIRE((mc68kcpu)->cpu_type)) + { + /* TODO */ + return; + } + m68ki_exception_illegal(mc68kcpu); + return; + case 0xc0c: // MPCR + if(CPU_TYPE_IS_COLDFIRE((mc68kcpu)->cpu_type)) + { + /* TODO */ + return; + } + m68ki_exception_illegal(mc68kcpu); + return; + case 0xc0d: // EDRAMBAR + if(CPU_TYPE_IS_COLDFIRE((mc68kcpu)->cpu_type)) + { + /* TODO */ + return; + } + m68ki_exception_illegal(mc68kcpu); + return; + case 0xc0e: // SECMBAR + if(CPU_TYPE_IS_COLDFIRE((mc68kcpu)->cpu_type)) + { + /* TODO */ + return; + } + m68ki_exception_illegal(mc68kcpu); + return; + case 0xc0f: // MBAR + if(CPU_TYPE_IS_COLDFIRE((mc68kcpu)->cpu_type)) + { + /* TODO */ + return; + } + m68ki_exception_illegal(mc68kcpu); + return; + default: + m68ki_exception_illegal(mc68kcpu); + return; + } + } + m68ki_exception_privilege_violation(mc68kcpu); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +M68KMAKE_OP(movem, 16, re, pd) +{ + UINT32 i = 0; + UINT32 register_list = OPER_I_16(mc68kcpu); + UINT32 ea = AY(mc68kcpu); + UINT32 count = 0; + + for(; i < 16; i++) + if(register_list & (1 << i)) + { + ea -= 2; + m68ki_write_16((mc68kcpu), ea, MASK_OUT_ABOVE_16(REG_DA(mc68kcpu)[15-i])); + count++; + } + AY(mc68kcpu) = ea; + + (mc68kcpu)->remaining_cycles -= count<<(mc68kcpu)->cyc_movem_w; +} + + +M68KMAKE_OP(movem, 16, re, .) +{ + UINT32 i = 0; + UINT32 register_list = OPER_I_16(mc68kcpu); + UINT32 ea = M68KMAKE_GET_EA_AY_16; + UINT32 count = 0; + + for(; i < 16; i++) + if(register_list & (1 << i)) + { + m68ki_write_16((mc68kcpu), ea, MASK_OUT_ABOVE_16(REG_DA(mc68kcpu)[i])); + ea += 2; + count++; + } + + (mc68kcpu)->remaining_cycles -= count<<(mc68kcpu)->cyc_movem_w; +} + + +M68KMAKE_OP(movem, 32, re, pd) +{ + UINT32 i = 0; + UINT32 register_list = OPER_I_16(mc68kcpu); + UINT32 ea = AY(mc68kcpu); + UINT32 count = 0; + + for(; i < 16; i++) + if(register_list & (1 << i)) + { + ea -= 4; + m68ki_write_16((mc68kcpu), ea+2, REG_DA(mc68kcpu)[15-i] & 0xFFFF ); + m68ki_write_16((mc68kcpu), ea, (REG_DA(mc68kcpu)[15-i] >> 16) & 0xFFFF ); + count++; + } + AY(mc68kcpu) = ea; + + (mc68kcpu)->remaining_cycles -= count<<(mc68kcpu)->cyc_movem_l; +} + + +M68KMAKE_OP(movem, 32, re, .) +{ + UINT32 i = 0; + UINT32 register_list = OPER_I_16(mc68kcpu); + UINT32 ea = M68KMAKE_GET_EA_AY_32; + UINT32 count = 0; + + for(; i < 16; i++) + if(register_list & (1 << i)) + { + m68ki_write_32((mc68kcpu), ea, REG_DA(mc68kcpu)[i]); + ea += 4; + count++; + } + + (mc68kcpu)->remaining_cycles -= count<<(mc68kcpu)->cyc_movem_l; +} + + +M68KMAKE_OP(movem, 16, er, pi) +{ + UINT32 i = 0; + UINT32 register_list = OPER_I_16(mc68kcpu); + UINT32 ea = AY(mc68kcpu); + UINT32 count = 0; + + for(; i < 16; i++) + if(register_list & (1 << i)) + { + REG_DA(mc68kcpu)[i] = MAKE_INT_16(MASK_OUT_ABOVE_16(m68ki_read_16((mc68kcpu), ea))); + ea += 2; + count++; + } + AY(mc68kcpu) = ea; + + (mc68kcpu)->remaining_cycles -= count<<(mc68kcpu)->cyc_movem_w; +} + + +M68KMAKE_OP(movem, 16, er, pcdi) +{ + UINT32 i = 0; + UINT32 register_list = OPER_I_16(mc68kcpu); + UINT32 ea = EA_PCDI_16(mc68kcpu); + UINT32 count = 0; + + for(; i < 16; i++) + if(register_list & (1 << i)) + { + REG_DA(mc68kcpu)[i] = MAKE_INT_16(MASK_OUT_ABOVE_16(m68ki_read_pcrel_16((mc68kcpu), ea))); + ea += 2; + count++; + } + + (mc68kcpu)->remaining_cycles -= count<<(mc68kcpu)->cyc_movem_w; +} + + +M68KMAKE_OP(movem, 16, er, pcix) +{ + UINT32 i = 0; + UINT32 register_list = OPER_I_16(mc68kcpu); + UINT32 ea = EA_PCIX_16(mc68kcpu); + UINT32 count = 0; + + for(; i < 16; i++) + if(register_list & (1 << i)) + { + REG_DA(mc68kcpu)[i] = MAKE_INT_16(MASK_OUT_ABOVE_16(m68ki_read_pcrel_16((mc68kcpu), ea))); + ea += 2; + count++; + } + + (mc68kcpu)->remaining_cycles -= count<<(mc68kcpu)->cyc_movem_w; +} + + +M68KMAKE_OP(movem, 16, er, .) +{ + UINT32 i = 0; + UINT32 register_list = OPER_I_16(mc68kcpu); + UINT32 ea = M68KMAKE_GET_EA_AY_16; + UINT32 count = 0; + + for(; i < 16; i++) + if(register_list & (1 << i)) + { + REG_DA(mc68kcpu)[i] = MAKE_INT_16(MASK_OUT_ABOVE_16(m68ki_read_16((mc68kcpu), ea))); + ea += 2; + count++; + } + + (mc68kcpu)->remaining_cycles -= count<<(mc68kcpu)->cyc_movem_w; +} + + +M68KMAKE_OP(movem, 32, er, pi) +{ + UINT32 i = 0; + UINT32 register_list = OPER_I_16(mc68kcpu); + UINT32 ea = AY(mc68kcpu); + UINT32 count = 0; + + for(; i < 16; i++) + if(register_list & (1 << i)) + { + REG_DA(mc68kcpu)[i] = m68ki_read_32((mc68kcpu), ea); + ea += 4; + count++; + } + AY(mc68kcpu) = ea; + + (mc68kcpu)->remaining_cycles -= count<<(mc68kcpu)->cyc_movem_l; +} + + +M68KMAKE_OP(movem, 32, er, pcdi) +{ + UINT32 i = 0; + UINT32 register_list = OPER_I_16(mc68kcpu); + UINT32 ea = EA_PCDI_32(mc68kcpu); + UINT32 count = 0; + + for(; i < 16; i++) + if(register_list & (1 << i)) + { + REG_DA(mc68kcpu)[i] = m68ki_read_pcrel_32((mc68kcpu), ea); + ea += 4; + count++; + } + + (mc68kcpu)->remaining_cycles -= count<<(mc68kcpu)->cyc_movem_l; +} + + +M68KMAKE_OP(movem, 32, er, pcix) +{ + UINT32 i = 0; + UINT32 register_list = OPER_I_16(mc68kcpu); + UINT32 ea = EA_PCIX_32(mc68kcpu); + UINT32 count = 0; + + for(; i < 16; i++) + if(register_list & (1 << i)) + { + REG_DA(mc68kcpu)[i] = m68ki_read_pcrel_32((mc68kcpu), ea); + ea += 4; + count++; + } + + (mc68kcpu)->remaining_cycles -= count<<(mc68kcpu)->cyc_movem_l; +} + + +M68KMAKE_OP(movem, 32, er, .) +{ + UINT32 i = 0; + UINT32 register_list = OPER_I_16(mc68kcpu); + UINT32 ea = M68KMAKE_GET_EA_AY_32; + UINT32 count = 0; + + for(; i < 16; i++) + if(register_list & (1 << i)) + { + REG_DA(mc68kcpu)[i] = m68ki_read_32((mc68kcpu), ea); + ea += 4; + count++; + } + + (mc68kcpu)->remaining_cycles -= count<<(mc68kcpu)->cyc_movem_l; +} + + +M68KMAKE_OP(movep, 16, re, .) +{ + UINT32 ea = EA_AY_DI_16(mc68kcpu); + UINT32 src = DX(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, MASK_OUT_ABOVE_8(src >> 8)); + m68ki_write_8((mc68kcpu), ea += 2, MASK_OUT_ABOVE_8(src)); +} + + +M68KMAKE_OP(movep, 32, re, .) +{ + UINT32 ea = EA_AY_DI_32(mc68kcpu); + UINT32 src = DX(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, MASK_OUT_ABOVE_8(src >> 24)); + m68ki_write_8((mc68kcpu), ea += 2, MASK_OUT_ABOVE_8(src >> 16)); + m68ki_write_8((mc68kcpu), ea += 2, MASK_OUT_ABOVE_8(src >> 8)); + m68ki_write_8((mc68kcpu), ea += 2, MASK_OUT_ABOVE_8(src)); +} + + +M68KMAKE_OP(movep, 16, er, .) +{ + UINT32 ea = EA_AY_DI_16(mc68kcpu); + UINT32* r_dst = &DX(mc68kcpu); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | ((m68ki_read_8((mc68kcpu), ea) << 8) + m68ki_read_8((mc68kcpu), ea + 2)); +} + + +M68KMAKE_OP(movep, 32, er, .) +{ + UINT32 ea = EA_AY_DI_32(mc68kcpu); + + DX(mc68kcpu) = (m68ki_read_8((mc68kcpu), ea) << 24) + (m68ki_read_8((mc68kcpu), ea + 2) << 16) + + (m68ki_read_8((mc68kcpu), ea + 4) << 8) + m68ki_read_8((mc68kcpu), ea + 6); +} + + +M68KMAKE_OP(moves, 8, ., .) +{ + if(CPU_TYPE_IS_010_PLUS((mc68kcpu)->cpu_type)) + { + if((mc68kcpu)->s_flag) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT32 ea = M68KMAKE_GET_EA_AY_8; + + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + if(BIT_B(word2)) /* Register to memory */ + { + m68ki_write_8_fc((mc68kcpu), ea, (mc68kcpu)->dfc, MASK_OUT_ABOVE_8(REG_DA(mc68kcpu)[(word2 >> 12) & 15])); + return; + } + if(BIT_F(word2)) /* Memory to address register */ + { + REG_A(mc68kcpu)[(word2 >> 12) & 7] = MAKE_INT_8(m68ki_read_8_fc((mc68kcpu), ea, (mc68kcpu)->sfc)); + if(CPU_TYPE_IS_020_VARIANT((mc68kcpu)->cpu_type)) + (mc68kcpu)->remaining_cycles -= 2; + return; + } + /* Memory to data register */ + REG_D(mc68kcpu)[(word2 >> 12) & 7] = MASK_OUT_BELOW_8(REG_D(mc68kcpu)[(word2 >> 12) & 7]) | m68ki_read_8_fc((mc68kcpu), ea, (mc68kcpu)->sfc); + if(CPU_TYPE_IS_020_VARIANT((mc68kcpu)->cpu_type)) + (mc68kcpu)->remaining_cycles -= 2; + return; + } + m68ki_exception_privilege_violation(mc68kcpu); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +M68KMAKE_OP(moves, 16, ., .) +{ + if(CPU_TYPE_IS_010_PLUS((mc68kcpu)->cpu_type)) + { + if((mc68kcpu)->s_flag) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT32 ea = M68KMAKE_GET_EA_AY_16; + + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + if(BIT_B(word2)) /* Register to memory */ + { + m68ki_write_16_fc((mc68kcpu), ea, (mc68kcpu)->dfc, MASK_OUT_ABOVE_16(REG_DA(mc68kcpu)[(word2 >> 12) & 15])); + return; + } + if(BIT_F(word2)) /* Memory to address register */ + { + REG_A(mc68kcpu)[(word2 >> 12) & 7] = MAKE_INT_16(m68ki_read_16_fc((mc68kcpu), ea, (mc68kcpu)->sfc)); + if(CPU_TYPE_IS_020_VARIANT((mc68kcpu)->cpu_type)) + (mc68kcpu)->remaining_cycles -= 2; + return; + } + /* Memory to data register */ + REG_D(mc68kcpu)[(word2 >> 12) & 7] = MASK_OUT_BELOW_16(REG_D(mc68kcpu)[(word2 >> 12) & 7]) | m68ki_read_16_fc((mc68kcpu), ea, (mc68kcpu)->sfc); + if(CPU_TYPE_IS_020_VARIANT((mc68kcpu)->cpu_type)) + (mc68kcpu)->remaining_cycles -= 2; + return; + } + m68ki_exception_privilege_violation(mc68kcpu); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +M68KMAKE_OP(moves, 32, ., .) +{ + if(CPU_TYPE_IS_010_PLUS((mc68kcpu)->cpu_type)) + { + if((mc68kcpu)->s_flag) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT32 ea = M68KMAKE_GET_EA_AY_32; + + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + if(BIT_B(word2)) /* Register to memory */ + { + m68ki_write_32_fc((mc68kcpu), ea, (mc68kcpu)->dfc, REG_DA(mc68kcpu)[(word2 >> 12) & 15]); + if(CPU_TYPE_IS_020_VARIANT((mc68kcpu)->cpu_type)) + (mc68kcpu)->remaining_cycles -= 2; + return; + } + /* Memory to register */ + REG_DA(mc68kcpu)[(word2 >> 12) & 15] = m68ki_read_32_fc((mc68kcpu), ea, (mc68kcpu)->sfc); + if(CPU_TYPE_IS_020_VARIANT((mc68kcpu)->cpu_type)) + (mc68kcpu)->remaining_cycles -= 2; + return; + } + m68ki_exception_privilege_violation(mc68kcpu); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +M68KMAKE_OP(moveq, 32, ., .) +{ + UINT32 res = DX(mc68kcpu) = MAKE_INT_8(MASK_OUT_ABOVE_8((mc68kcpu)->ir)); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +M68KMAKE_OP(move16, 32, ., .) +{ + UINT16 w2 = OPER_I_16(mc68kcpu); + int ax = (mc68kcpu)->ir & 7; + int ay = (w2 >> 12) & 7; + m68ki_write_32((mc68kcpu), REG_A(mc68kcpu)[ay], m68ki_read_32((mc68kcpu), REG_A(mc68kcpu)[ax])); + m68ki_write_32((mc68kcpu), REG_A(mc68kcpu)[ay]+4, m68ki_read_32((mc68kcpu), REG_A(mc68kcpu)[ax]+4)); + m68ki_write_32((mc68kcpu), REG_A(mc68kcpu)[ay]+8, m68ki_read_32((mc68kcpu), REG_A(mc68kcpu)[ax]+8)); + m68ki_write_32((mc68kcpu), REG_A(mc68kcpu)[ay]+12, m68ki_read_32((mc68kcpu), REG_A(mc68kcpu)[ax]+12)); + + REG_A(mc68kcpu)[ax] += 16; + REG_A(mc68kcpu)[ay] += 16; +} + + +M68KMAKE_OP(muls, 16, ., d) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_32(MAKE_INT_16(DY(mc68kcpu)) * MAKE_INT_16(MASK_OUT_ABOVE_16(*r_dst))); + + *r_dst = res; + + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +M68KMAKE_OP(muls, 16, ., .) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_32(MAKE_INT_16(M68KMAKE_GET_OPER_AY_16) * MAKE_INT_16(MASK_OUT_ABOVE_16(*r_dst))); + + *r_dst = res; + + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +M68KMAKE_OP(mulu, 16, ., d) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_16(DY(mc68kcpu)) * MASK_OUT_ABOVE_16(*r_dst); + + *r_dst = res; + + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +M68KMAKE_OP(mulu, 16, ., .) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 res = M68KMAKE_GET_OPER_AY_16 * MASK_OUT_ABOVE_16(*r_dst); + + *r_dst = res; + + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +M68KMAKE_OP(mull, 32, ., d) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT64 src = DY(mc68kcpu); + UINT64 dst = REG_D(mc68kcpu)[(word2 >> 12) & 7]; + UINT64 res; + + (mc68kcpu)->c_flag = CFLAG_CLEAR; + + if(BIT_B(word2)) /* signed */ + { + res = (INT64)((INT32)src) * (INT64)((INT32)dst); + if(!BIT_A(word2)) + { + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->v_flag = ((INT64)res != (INT32)res)<<7; + REG_D(mc68kcpu)[(word2 >> 12) & 7] = (mc68kcpu)->not_z_flag; + return; + } + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res) | (res>>32); + (mc68kcpu)->n_flag = NFLAG_64(res); + (mc68kcpu)->v_flag = VFLAG_CLEAR; + REG_D(mc68kcpu)[word2 & 7] = (res >> 32); + REG_D(mc68kcpu)[(word2 >> 12) & 7] = MASK_OUT_ABOVE_32(res); + return; + } + + res = src * dst; + if(!BIT_A(word2)) + { + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->v_flag = (res > 0xffffffff)<<7; + REG_D(mc68kcpu)[(word2 >> 12) & 7] = (mc68kcpu)->not_z_flag; + return; + } + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res) | (res>>32); + (mc68kcpu)->n_flag = NFLAG_64(res); + (mc68kcpu)->v_flag = VFLAG_CLEAR; + REG_D(mc68kcpu)[word2 & 7] = (res >> 32); + REG_D(mc68kcpu)[(word2 >> 12) & 7] = MASK_OUT_ABOVE_32(res); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +M68KMAKE_OP(mull, 32, ., .) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT64 src = M68KMAKE_GET_OPER_AY_32; + UINT64 dst = REG_D(mc68kcpu)[(word2 >> 12) & 7]; + UINT64 res; + + (mc68kcpu)->c_flag = CFLAG_CLEAR; + + if(BIT_B(word2)) /* signed */ + { + res = (INT64)((INT32)src) * (INT64)((INT32)dst); + if(!BIT_A(word2)) + { + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->v_flag = ((INT64)res != (INT32)res)<<7; + REG_D(mc68kcpu)[(word2 >> 12) & 7] = (mc68kcpu)->not_z_flag; + return; + } + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res) | (res>>32); + (mc68kcpu)->n_flag = NFLAG_64(res); + (mc68kcpu)->v_flag = VFLAG_CLEAR; + REG_D(mc68kcpu)[word2 & 7] = (res >> 32); + REG_D(mc68kcpu)[(word2 >> 12) & 7] = MASK_OUT_ABOVE_32(res); + return; + } + + res = src * dst; + if(!BIT_A(word2)) + { + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->v_flag = (res > 0xffffffff)<<7; + REG_D(mc68kcpu)[(word2 >> 12) & 7] = (mc68kcpu)->not_z_flag; + return; + } + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res) | (res>>32); + (mc68kcpu)->n_flag = NFLAG_64(res); + (mc68kcpu)->v_flag = VFLAG_CLEAR; + REG_D(mc68kcpu)[word2 & 7] = (res >> 32); + REG_D(mc68kcpu)[(word2 >> 12) & 7] = MASK_OUT_ABOVE_32(res); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +M68KMAKE_OP(nbcd, 8, ., d) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 dst = *r_dst; + UINT32 res = MASK_OUT_ABOVE_8(0x9a - dst - XFLAG_AS_1(mc68kcpu)); + + if(res != 0x9a) + { + (mc68kcpu)->v_flag = ~res; /* Undefined V behavior */ + + if((res & 0x0f) == 0xa) + res = (res & 0xf0) + 0x10; + + res = MASK_OUT_ABOVE_8(res); + + (mc68kcpu)->v_flag &= res; /* Undefined V behavior part II */ + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; + + (mc68kcpu)->not_z_flag |= res; + (mc68kcpu)->c_flag = CFLAG_SET; + (mc68kcpu)->x_flag = XFLAG_SET; + } + else + { + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->x_flag = XFLAG_CLEAR; + } + (mc68kcpu)->n_flag = NFLAG_8(res); /* Undefined N behavior */ +} + + +M68KMAKE_OP(nbcd, 8, ., .) +{ + UINT32 ea = M68KMAKE_GET_EA_AY_8; + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + UINT32 res = MASK_OUT_ABOVE_8(0x9a - dst - XFLAG_AS_1(mc68kcpu)); + + if(res != 0x9a) + { + (mc68kcpu)->v_flag = ~res; /* Undefined V behavior */ + + if((res & 0x0f) == 0xa) + res = (res & 0xf0) + 0x10; + + res = MASK_OUT_ABOVE_8(res); + + (mc68kcpu)->v_flag &= res; /* Undefined V behavior part II */ + + m68ki_write_8((mc68kcpu), ea, MASK_OUT_ABOVE_8(res)); + + (mc68kcpu)->not_z_flag |= res; + (mc68kcpu)->c_flag = CFLAG_SET; + (mc68kcpu)->x_flag = XFLAG_SET; + } + else + { + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->x_flag = XFLAG_CLEAR; + } + (mc68kcpu)->n_flag = NFLAG_8(res); /* Undefined N behavior */ +} + + +M68KMAKE_OP(neg, 8, ., d) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 res = 0 - MASK_OUT_ABOVE_8(*r_dst); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag = CFLAG_8(res); + (mc68kcpu)->v_flag = *r_dst & res; + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | (mc68kcpu)->not_z_flag; +} + + +M68KMAKE_OP(neg, 8, ., .) +{ + UINT32 ea = M68KMAKE_GET_EA_AY_8; + UINT32 src = m68ki_read_8((mc68kcpu), ea); + UINT32 res = 0 - src; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag = CFLAG_8(res); + (mc68kcpu)->v_flag = src & res; + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + + m68ki_write_8((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +M68KMAKE_OP(neg, 16, ., d) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 res = 0 - MASK_OUT_ABOVE_16(*r_dst); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag = CFLAG_16(res); + (mc68kcpu)->v_flag = (*r_dst & res)>>8; + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | (mc68kcpu)->not_z_flag; +} + + +M68KMAKE_OP(neg, 16, ., .) +{ + UINT32 ea = M68KMAKE_GET_EA_AY_16; + UINT32 src = m68ki_read_16((mc68kcpu), ea); + UINT32 res = 0 - src; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag = CFLAG_16(res); + (mc68kcpu)->v_flag = (src & res)>>8; + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + + m68ki_write_16((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +M68KMAKE_OP(neg, 32, ., d) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 res = 0 - *r_dst; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag = CFLAG_SUB_32(*r_dst, 0, res); + (mc68kcpu)->v_flag = (*r_dst & res)>>24; + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + + *r_dst = (mc68kcpu)->not_z_flag; +} + + +M68KMAKE_OP(neg, 32, ., .) +{ + UINT32 ea = M68KMAKE_GET_EA_AY_32; + UINT32 src = m68ki_read_32((mc68kcpu), ea); + UINT32 res = 0 - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag = CFLAG_SUB_32(src, 0, res); + (mc68kcpu)->v_flag = (src & res)>>24; + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + + m68ki_write_32((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +M68KMAKE_OP(negx, 8, ., d) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 res = 0 - MASK_OUT_ABOVE_8(*r_dst) - XFLAG_AS_1(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->v_flag = *r_dst & res; + + res = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->not_z_flag |= res; + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; +} + + +M68KMAKE_OP(negx, 8, ., .) +{ + UINT32 ea = M68KMAKE_GET_EA_AY_8; + UINT32 src = m68ki_read_8((mc68kcpu), ea); + UINT32 res = 0 - src - XFLAG_AS_1(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->v_flag = src & res; + + res = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->not_z_flag |= res; + + m68ki_write_8((mc68kcpu), ea, res); +} + + +M68KMAKE_OP(negx, 16, ., d) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 res = 0 - MASK_OUT_ABOVE_16(*r_dst) - XFLAG_AS_1(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_16(res); + (mc68kcpu)->v_flag = (*r_dst & res)>>8; + + res = MASK_OUT_ABOVE_16(res); + (mc68kcpu)->not_z_flag |= res; + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; +} + + +M68KMAKE_OP(negx, 16, ., .) +{ + UINT32 ea = M68KMAKE_GET_EA_AY_16; + UINT32 src = m68ki_read_16((mc68kcpu), ea); + UINT32 res = 0 - MASK_OUT_ABOVE_16(src) - XFLAG_AS_1(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_16(res); + (mc68kcpu)->v_flag = (src & res)>>8; + + res = MASK_OUT_ABOVE_16(res); + (mc68kcpu)->not_z_flag |= res; + + m68ki_write_16((mc68kcpu), ea, res); +} + + +M68KMAKE_OP(negx, 32, ., d) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 res = 0 - MASK_OUT_ABOVE_32(*r_dst) - XFLAG_AS_1(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_SUB_32(*r_dst, 0, res); + (mc68kcpu)->v_flag = (*r_dst & res)>>24; + + res = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->not_z_flag |= res; + + *r_dst = res; +} + + +M68KMAKE_OP(negx, 32, ., .) +{ + UINT32 ea = M68KMAKE_GET_EA_AY_32; + UINT32 src = m68ki_read_32((mc68kcpu), ea); + UINT32 res = 0 - MASK_OUT_ABOVE_32(src) - XFLAG_AS_1(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_SUB_32(src, 0, res); + (mc68kcpu)->v_flag = (src & res)>>24; + + res = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->not_z_flag |= res; + + m68ki_write_32((mc68kcpu), ea, res); +} + + +M68KMAKE_OP(nop, 0, ., .) +{ + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ +} + + +M68KMAKE_OP(not, 8, ., d) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_8(~*r_dst); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +M68KMAKE_OP(not, 8, ., .) +{ + UINT32 ea = M68KMAKE_GET_EA_AY_8; + UINT32 res = MASK_OUT_ABOVE_8(~m68ki_read_8((mc68kcpu), ea)); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +M68KMAKE_OP(not, 16, ., d) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_16(~*r_dst); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +M68KMAKE_OP(not, 16, ., .) +{ + UINT32 ea = M68KMAKE_GET_EA_AY_16; + UINT32 res = MASK_OUT_ABOVE_16(~m68ki_read_16((mc68kcpu), ea)); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +M68KMAKE_OP(not, 32, ., d) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 res = *r_dst = MASK_OUT_ABOVE_32(~*r_dst); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +M68KMAKE_OP(not, 32, ., .) +{ + UINT32 ea = M68KMAKE_GET_EA_AY_32; + UINT32 res = MASK_OUT_ABOVE_32(~m68ki_read_32((mc68kcpu), ea)); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +M68KMAKE_OP(or, 8, er, d) +{ + UINT32 res = MASK_OUT_ABOVE_8((DX(mc68kcpu) |= MASK_OUT_ABOVE_8(DY(mc68kcpu)))); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +M68KMAKE_OP(or, 8, er, .) +{ + UINT32 res = MASK_OUT_ABOVE_8((DX(mc68kcpu) |= M68KMAKE_GET_OPER_AY_8)); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +M68KMAKE_OP(or, 16, er, d) +{ + UINT32 res = MASK_OUT_ABOVE_16((DX(mc68kcpu) |= MASK_OUT_ABOVE_16(DY(mc68kcpu)))); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +M68KMAKE_OP(or, 16, er, .) +{ + UINT32 res = MASK_OUT_ABOVE_16((DX(mc68kcpu) |= M68KMAKE_GET_OPER_AY_16)); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +M68KMAKE_OP(or, 32, er, d) +{ + UINT32 res = DX(mc68kcpu) |= DY(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +M68KMAKE_OP(or, 32, er, .) +{ + UINT32 res = DX(mc68kcpu) |= M68KMAKE_GET_OPER_AY_32; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +M68KMAKE_OP(or, 8, re, .) +{ + UINT32 ea = M68KMAKE_GET_EA_AY_8; + UINT32 res = MASK_OUT_ABOVE_8(DX(mc68kcpu) | m68ki_read_8((mc68kcpu), ea)); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +M68KMAKE_OP(or, 16, re, .) +{ + UINT32 ea = M68KMAKE_GET_EA_AY_16; + UINT32 res = MASK_OUT_ABOVE_16(DX(mc68kcpu) | m68ki_read_16((mc68kcpu), ea)); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +M68KMAKE_OP(or, 32, re, .) +{ + UINT32 ea = M68KMAKE_GET_EA_AY_32; + UINT32 res = DX(mc68kcpu) | m68ki_read_32((mc68kcpu), ea); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +M68KMAKE_OP(ori, 8, ., d) +{ + UINT32 res = MASK_OUT_ABOVE_8((DY(mc68kcpu) |= OPER_I_8(mc68kcpu))); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +M68KMAKE_OP(ori, 8, ., .) +{ + UINT32 src = OPER_I_8(mc68kcpu); + UINT32 ea = M68KMAKE_GET_EA_AY_8; + UINT32 res = MASK_OUT_ABOVE_8(src | m68ki_read_8((mc68kcpu), ea)); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +M68KMAKE_OP(ori, 16, ., d) +{ + UINT32 res = MASK_OUT_ABOVE_16(DY(mc68kcpu) |= OPER_I_16(mc68kcpu)); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +M68KMAKE_OP(ori, 16, ., .) +{ + UINT32 src = OPER_I_16(mc68kcpu); + UINT32 ea = M68KMAKE_GET_EA_AY_16; + UINT32 res = MASK_OUT_ABOVE_16(src | m68ki_read_16((mc68kcpu), ea)); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +M68KMAKE_OP(ori, 32, ., d) +{ + UINT32 res = DY(mc68kcpu) |= OPER_I_32(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +M68KMAKE_OP(ori, 32, ., .) +{ + UINT32 src = OPER_I_32(mc68kcpu); + UINT32 ea = M68KMAKE_GET_EA_AY_32; + UINT32 res = src | m68ki_read_32((mc68kcpu), ea); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +M68KMAKE_OP(ori, 16, toc, .) +{ + m68ki_set_ccr((mc68kcpu), m68ki_get_ccr(mc68kcpu) | OPER_I_16(mc68kcpu)); +} + + +M68KMAKE_OP(ori, 16, tos, .) +{ + if((mc68kcpu)->s_flag) + { + UINT32 src = OPER_I_16(mc68kcpu); + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_set_sr((mc68kcpu), m68ki_get_sr(mc68kcpu) | src); + return; + } + m68ki_exception_privilege_violation(mc68kcpu); +} + + +M68KMAKE_OP(pack, 16, rr, .) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + /* Note: DX(mc68kcpu) and DY(mc68kcpu) are reversed in Motorola's docs */ + UINT32 src = DY(mc68kcpu) + OPER_I_16(mc68kcpu); + UINT32* r_dst = &DX(mc68kcpu); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | ((src >> 4) & 0x00f0) | (src & 0x000f); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +M68KMAKE_OP(pack, 16, mm, ax7) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + /* Note: AX and AY are reversed in Motorola's docs */ + UINT32 ea_src = EA_AY_PD_8(mc68kcpu); + UINT32 src = m68ki_read_8((mc68kcpu), ea_src); + ea_src = EA_AY_PD_8(mc68kcpu); + src = ((src << 8) | m68ki_read_8((mc68kcpu), ea_src)) + OPER_I_16(mc68kcpu); + + m68ki_write_8((mc68kcpu), EA_A7_PD_8(mc68kcpu), ((src >> 4) & 0x00f0) | (src & 0x000f)); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +M68KMAKE_OP(pack, 16, mm, ay7) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + /* Note: AX and AY are reversed in Motorola's docs */ + UINT32 ea_src = EA_A7_PD_8(mc68kcpu); + UINT32 src = m68ki_read_8((mc68kcpu), ea_src); + ea_src = EA_A7_PD_8(mc68kcpu); + src = ((src << 8) | m68ki_read_8((mc68kcpu), ea_src)) + OPER_I_16(mc68kcpu); + + m68ki_write_8((mc68kcpu), EA_AX_PD_8(mc68kcpu), ((src >> 4) & 0x00f0) | (src & 0x000f)); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +M68KMAKE_OP(pack, 16, mm, axy7) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 ea_src = EA_A7_PD_8(mc68kcpu); + UINT32 src = m68ki_read_8((mc68kcpu), ea_src); + ea_src = EA_A7_PD_8(mc68kcpu); + src = ((src << 8) | m68ki_read_8((mc68kcpu), ea_src)) + OPER_I_16(mc68kcpu); + + m68ki_write_8((mc68kcpu), EA_A7_PD_8(mc68kcpu), ((src >> 4) & 0x00f0) | (src & 0x000f)); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +M68KMAKE_OP(pack, 16, mm, .) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + /* Note: AX and AY are reversed in Motorola's docs */ + UINT32 ea_src = EA_AY_PD_8(mc68kcpu); + UINT32 src = m68ki_read_8((mc68kcpu), ea_src); + ea_src = EA_AY_PD_8(mc68kcpu); + src = ((src << 8) | m68ki_read_8((mc68kcpu), ea_src)) + OPER_I_16(mc68kcpu); + + m68ki_write_8((mc68kcpu), EA_AX_PD_8(mc68kcpu), ((src >> 4) & 0x00f0) | (src & 0x000f)); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +M68KMAKE_OP(pea, 32, ., .) +{ + UINT32 ea = M68KMAKE_GET_EA_AY_32; + + m68ki_push_32((mc68kcpu), ea); +} + +M68KMAKE_OP(pflusha, 32, ., .) +{ + if ((CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) && ((mc68kcpu)->has_pmmu)) + { + logerror("68040: unhandled PFLUSHA (ir=%04x)\n", mc68kcpu->ir); + return; + } + m68ki_exception_1111(mc68kcpu); +} + +M68KMAKE_OP(pflushan, 32, ., .) +{ + if ((CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) && ((mc68kcpu)->has_pmmu)) + { + logerror("68040: unhandled PFLUSHAN (ir=%04x)\n", mc68kcpu->ir); + return; + } + m68ki_exception_1111(mc68kcpu); +} + +M68KMAKE_OP(pmmu, 32, ., .) +{ + if ((CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) && ((mc68kcpu)->has_pmmu)) + { + m68881_mmu_ops(mc68kcpu); + } + else + { + m68ki_exception_1111(mc68kcpu); + } +} + +M68KMAKE_OP(ptest, 32, ., .) +{ + if ((CPU_TYPE_IS_040_PLUS((mc68kcpu)->cpu_type)) && ((mc68kcpu)->has_pmmu)) + { + logerror("68040: unhandled PTEST\n"); + return; + } + else + { + m68ki_exception_1111(mc68kcpu); + } +} + +M68KMAKE_OP(reset, 0, ., .) +{ + if((mc68kcpu)->s_flag) + { + if (!(mc68kcpu)->reset_instr_callback.isnull()) + ((mc68kcpu)->reset_instr_callback)(1); + (mc68kcpu)->remaining_cycles -= (mc68kcpu)->cyc_reset; + return; + } + m68ki_exception_privilege_violation(mc68kcpu); +} + + +M68KMAKE_OP(ror, 8, s, .) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 orig_shift = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT32 shift = orig_shift & 7; + UINT32 src = MASK_OUT_ABOVE_8(*r_dst); + UINT32 res = ROR_8(src, shift); + + if(orig_shift != 0) + (mc68kcpu)->remaining_cycles -= orig_shift<<(mc68kcpu)->cyc_shift; + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = src << (9-orig_shift); + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +M68KMAKE_OP(ror, 16, s, .) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 shift = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT32 src = MASK_OUT_ABOVE_16(*r_dst); + UINT32 res = ROR_16(src, shift); + + if(shift != 0) + (mc68kcpu)->remaining_cycles -= shift<<(mc68kcpu)->cyc_shift; + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = src << (9-shift); + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +M68KMAKE_OP(ror, 32, s, .) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 shift = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT64 src = *r_dst; + UINT32 res = ROR_32(src, shift); + + if(shift != 0) + (mc68kcpu)->remaining_cycles -= shift<<(mc68kcpu)->cyc_shift; + + *r_dst = res; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = src << (9-shift); + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +M68KMAKE_OP(ror, 8, r, .) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 orig_shift = DX(mc68kcpu) & 0x3f; + UINT32 shift = orig_shift & 7; + UINT32 src = MASK_OUT_ABOVE_8(*r_dst); + UINT32 res = ROR_8(src, shift); + + if(orig_shift != 0) + { + (mc68kcpu)->remaining_cycles -= orig_shift<<(mc68kcpu)->cyc_shift; + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; + (mc68kcpu)->c_flag = src << (8-((shift-1)&7)); + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + return; + } + + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->n_flag = NFLAG_8(src); + (mc68kcpu)->not_z_flag = src; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +M68KMAKE_OP(ror, 16, r, .) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 orig_shift = DX(mc68kcpu) & 0x3f; + UINT32 shift = orig_shift & 15; + UINT32 src = MASK_OUT_ABOVE_16(*r_dst); + UINT32 res = ROR_16(src, shift); + + if(orig_shift != 0) + { + (mc68kcpu)->remaining_cycles -= orig_shift<<(mc68kcpu)->cyc_shift; + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + (mc68kcpu)->c_flag = (src >> ((shift - 1) & 15)) << 8; + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + return; + } + + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->n_flag = NFLAG_16(src); + (mc68kcpu)->not_z_flag = src; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +M68KMAKE_OP(ror, 32, r, .) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 orig_shift = DX(mc68kcpu) & 0x3f; + UINT32 shift = orig_shift & 31; + UINT64 src = *r_dst; + UINT32 res = ROR_32(src, shift); + + if(orig_shift != 0) + { + (mc68kcpu)->remaining_cycles -= orig_shift<<(mc68kcpu)->cyc_shift; + + *r_dst = res; + (mc68kcpu)->c_flag = (src >> ((shift - 1) & 31)) << 8; + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + return; + } + + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->n_flag = NFLAG_32(src); + (mc68kcpu)->not_z_flag = src; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +M68KMAKE_OP(ror, 16, ., .) +{ + UINT32 ea = M68KMAKE_GET_EA_AY_16; + UINT32 src = m68ki_read_16((mc68kcpu), ea); + UINT32 res = ROR_16(src, 1); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = src << 8; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +M68KMAKE_OP(rol, 8, s, .) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 orig_shift = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT32 shift = orig_shift & 7; + UINT32 src = MASK_OUT_ABOVE_8(*r_dst); + UINT32 res = ROL_8(src, shift); + + if(orig_shift != 0) + (mc68kcpu)->remaining_cycles -= orig_shift<<(mc68kcpu)->cyc_shift; + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = src << orig_shift; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +M68KMAKE_OP(rol, 16, s, .) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 shift = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT32 src = MASK_OUT_ABOVE_16(*r_dst); + UINT32 res = ROL_16(src, shift); + + if(shift != 0) + (mc68kcpu)->remaining_cycles -= shift<<(mc68kcpu)->cyc_shift; + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = src >> (8-shift); + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +M68KMAKE_OP(rol, 32, s, .) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 shift = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT64 src = *r_dst; + UINT32 res = ROL_32(src, shift); + + if(shift != 0) + (mc68kcpu)->remaining_cycles -= shift<<(mc68kcpu)->cyc_shift; + + *r_dst = res; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = src >> (24-shift); + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +M68KMAKE_OP(rol, 8, r, .) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 orig_shift = DX(mc68kcpu) & 0x3f; + UINT32 shift = orig_shift & 7; + UINT32 src = MASK_OUT_ABOVE_8(*r_dst); + UINT32 res = ROL_8(src, shift); + + if(orig_shift != 0) + { + (mc68kcpu)->remaining_cycles -= orig_shift<<(mc68kcpu)->cyc_shift; + + if(shift != 0) + { + *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; + (mc68kcpu)->c_flag = src << shift; + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + return; + } + (mc68kcpu)->c_flag = (src & 1)<<8; + (mc68kcpu)->n_flag = NFLAG_8(src); + (mc68kcpu)->not_z_flag = src; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + return; + } + + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->n_flag = NFLAG_8(src); + (mc68kcpu)->not_z_flag = src; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +M68KMAKE_OP(rol, 16, r, .) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 orig_shift = DX(mc68kcpu) & 0x3f; + UINT32 shift = orig_shift & 15; + UINT32 src = MASK_OUT_ABOVE_16(*r_dst); + UINT32 res = MASK_OUT_ABOVE_16(ROL_16(src, shift)); + + if(orig_shift != 0) + { + (mc68kcpu)->remaining_cycles -= orig_shift<<(mc68kcpu)->cyc_shift; + + if(shift != 0) + { + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + (mc68kcpu)->c_flag = (src << shift) >> 8; + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + return; + } + (mc68kcpu)->c_flag = (src & 1)<<8; + (mc68kcpu)->n_flag = NFLAG_16(src); + (mc68kcpu)->not_z_flag = src; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + return; + } + + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->n_flag = NFLAG_16(src); + (mc68kcpu)->not_z_flag = src; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +M68KMAKE_OP(rol, 32, r, .) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 orig_shift = DX(mc68kcpu) & 0x3f; + UINT32 shift = orig_shift & 31; + UINT64 src = *r_dst; + UINT32 res = ROL_32(src, shift); + + if(orig_shift != 0) + { + (mc68kcpu)->remaining_cycles -= orig_shift<<(mc68kcpu)->cyc_shift; + + *r_dst = res; + + (mc68kcpu)->c_flag = (src >> ((32 - shift) & 0x1f)) << 8; + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + return; + } + + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->n_flag = NFLAG_32(src); + (mc68kcpu)->not_z_flag = src; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +M68KMAKE_OP(rol, 16, ., .) +{ + UINT32 ea = M68KMAKE_GET_EA_AY_16; + UINT32 src = m68ki_read_16((mc68kcpu), ea); + UINT32 res = MASK_OUT_ABOVE_16(ROL_16(src, 1)); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = src >> 7; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +M68KMAKE_OP(roxr, 8, s, .) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 shift = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT32 src = MASK_OUT_ABOVE_8(*r_dst); + UINT32 res = ROR_9(src | (XFLAG_AS_1(mc68kcpu) << 8), shift); + + if(shift != 0) + (mc68kcpu)->remaining_cycles -= shift<<(mc68kcpu)->cyc_shift; + + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag = res; + res = MASK_OUT_ABOVE_8(res); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +M68KMAKE_OP(roxr, 16, s, .) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 shift = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT32 src = MASK_OUT_ABOVE_16(*r_dst); + UINT32 res = ROR_17(src | (XFLAG_AS_1(mc68kcpu) << 16), shift); + + if(shift != 0) + (mc68kcpu)->remaining_cycles -= shift<<(mc68kcpu)->cyc_shift; + + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag = res >> 8; + res = MASK_OUT_ABOVE_16(res); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +M68KMAKE_OP(roxr, 32, s, .) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 shift = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT64 src = *r_dst; + UINT64 res = src | (((UINT64)XFLAG_AS_1(mc68kcpu)) << 32); + + if(shift != 0) + (mc68kcpu)->remaining_cycles -= shift<<(mc68kcpu)->cyc_shift; + + res = ROR_33_64(res, shift); + + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag = res >> 24; + res = MASK_OUT_ABOVE_32(res); + + *r_dst = res; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +M68KMAKE_OP(roxr, 8, r, .) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 orig_shift = DX(mc68kcpu) & 0x3f; + + if(orig_shift != 0) + { + UINT32 shift = orig_shift % 9; + UINT32 src = MASK_OUT_ABOVE_8(*r_dst); + UINT32 res = ROR_9(src | (XFLAG_AS_1(mc68kcpu) << 8), shift); + + (mc68kcpu)->remaining_cycles -= orig_shift<<(mc68kcpu)->cyc_shift; + + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag = res; + res = MASK_OUT_ABOVE_8(res); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + return; + } + + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag; + (mc68kcpu)->n_flag = NFLAG_8(*r_dst); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(*r_dst); + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +M68KMAKE_OP(roxr, 16, r, .) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 orig_shift = DX(mc68kcpu) & 0x3f; + + if(orig_shift != 0) + { + UINT32 shift = orig_shift % 17; + UINT32 src = MASK_OUT_ABOVE_16(*r_dst); + UINT32 res = ROR_17(src | (XFLAG_AS_1(mc68kcpu) << 16), shift); + + (mc68kcpu)->remaining_cycles -= orig_shift<<(mc68kcpu)->cyc_shift; + + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag = res >> 8; + res = MASK_OUT_ABOVE_16(res); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + return; + } + + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag; + (mc68kcpu)->n_flag = NFLAG_16(*r_dst); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(*r_dst); + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +M68KMAKE_OP(roxr, 32, r, .) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 orig_shift = DX(mc68kcpu) & 0x3f; + + if(orig_shift != 0) + { + UINT32 shift = orig_shift % 33; + UINT64 src = *r_dst; + UINT64 res = src | (((UINT64)XFLAG_AS_1(mc68kcpu)) << 32); + + res = ROR_33_64(res, shift); + + (mc68kcpu)->remaining_cycles -= orig_shift<<(mc68kcpu)->cyc_shift; + + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag = res >> 24; + res = MASK_OUT_ABOVE_32(res); + + *r_dst = res; + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + return; + } + + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag; + (mc68kcpu)->n_flag = NFLAG_32(*r_dst); + (mc68kcpu)->not_z_flag = *r_dst; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +M68KMAKE_OP(roxr, 16, ., .) +{ + UINT32 ea = M68KMAKE_GET_EA_AY_16; + UINT32 src = m68ki_read_16((mc68kcpu), ea); + UINT32 res = ROR_17(src | (XFLAG_AS_1(mc68kcpu) << 16), 1); + + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag = res >> 8; + res = MASK_OUT_ABOVE_16(res); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +M68KMAKE_OP(roxl, 8, s, .) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 shift = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT32 src = MASK_OUT_ABOVE_8(*r_dst); + UINT32 res = ROL_9(src | (XFLAG_AS_1(mc68kcpu) << 8), shift); + + if(shift != 0) + (mc68kcpu)->remaining_cycles -= shift<<(mc68kcpu)->cyc_shift; + + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag = res; + res = MASK_OUT_ABOVE_8(res); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +M68KMAKE_OP(roxl, 16, s, .) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 shift = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT32 src = MASK_OUT_ABOVE_16(*r_dst); + UINT32 res = ROL_17(src | (XFLAG_AS_1(mc68kcpu) << 16), shift); + + if(shift != 0) + (mc68kcpu)->remaining_cycles -= shift<<(mc68kcpu)->cyc_shift; + + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag = res >> 8; + res = MASK_OUT_ABOVE_16(res); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +M68KMAKE_OP(roxl, 32, s, .) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 shift = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT64 src = *r_dst; + UINT64 res = src | (((UINT64)XFLAG_AS_1(mc68kcpu)) << 32); + + if(shift != 0) + (mc68kcpu)->remaining_cycles -= shift<<(mc68kcpu)->cyc_shift; + + res = ROL_33_64(res, shift); + + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag = res >> 24; + res = MASK_OUT_ABOVE_32(res); + + *r_dst = res; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +M68KMAKE_OP(roxl, 8, r, .) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 orig_shift = DX(mc68kcpu) & 0x3f; + + + if(orig_shift != 0) + { + UINT32 shift = orig_shift % 9; + UINT32 src = MASK_OUT_ABOVE_8(*r_dst); + UINT32 res = ROL_9(src | (XFLAG_AS_1(mc68kcpu) << 8), shift); + + (mc68kcpu)->remaining_cycles -= orig_shift<<(mc68kcpu)->cyc_shift; + + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag = res; + res = MASK_OUT_ABOVE_8(res); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + return; + } + + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag; + (mc68kcpu)->n_flag = NFLAG_8(*r_dst); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(*r_dst); + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +M68KMAKE_OP(roxl, 16, r, .) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 orig_shift = DX(mc68kcpu) & 0x3f; + + if(orig_shift != 0) + { + UINT32 shift = orig_shift % 17; + UINT32 src = MASK_OUT_ABOVE_16(*r_dst); + UINT32 res = ROL_17(src | (XFLAG_AS_1(mc68kcpu) << 16), shift); + + (mc68kcpu)->remaining_cycles -= orig_shift<<(mc68kcpu)->cyc_shift; + + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag = res >> 8; + res = MASK_OUT_ABOVE_16(res); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + return; + } + + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag; + (mc68kcpu)->n_flag = NFLAG_16(*r_dst); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(*r_dst); + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +M68KMAKE_OP(roxl, 32, r, .) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 orig_shift = DX(mc68kcpu) & 0x3f; + + if(orig_shift != 0) + { + UINT32 shift = orig_shift % 33; + UINT64 src = *r_dst; + UINT64 res = src | (((UINT64)XFLAG_AS_1(mc68kcpu)) << 32); + + res = ROL_33_64(res, shift); + + (mc68kcpu)->remaining_cycles -= orig_shift<<(mc68kcpu)->cyc_shift; + + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag = res >> 24; + res = MASK_OUT_ABOVE_32(res); + + *r_dst = res; + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + return; + } + + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag; + (mc68kcpu)->n_flag = NFLAG_32(*r_dst); + (mc68kcpu)->not_z_flag = *r_dst; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +M68KMAKE_OP(roxl, 16, ., .) +{ + UINT32 ea = M68KMAKE_GET_EA_AY_16; + UINT32 src = m68ki_read_16((mc68kcpu), ea); + UINT32 res = ROL_17(src | (XFLAG_AS_1(mc68kcpu) << 16), 1); + + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag = res >> 8; + res = MASK_OUT_ABOVE_16(res); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +M68KMAKE_OP(rtd, 32, ., .) +{ + if(CPU_TYPE_IS_010_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 new_pc = m68ki_pull_32(mc68kcpu); + + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + REG_A(mc68kcpu)[7] = MASK_OUT_ABOVE_32(REG_A(mc68kcpu)[7] + MAKE_INT_16(OPER_I_16(mc68kcpu))); + m68ki_jump((mc68kcpu), new_pc); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +M68KMAKE_OP(rte, 32, ., .) +{ + if((mc68kcpu)->s_flag) + { + UINT32 new_sr; + UINT32 new_pc; + UINT32 format_word; + + if (!(mc68kcpu)->rte_instr_callback.isnull()) + ((mc68kcpu)->rte_instr_callback)(1); + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + + if(CPU_TYPE_IS_000((mc68kcpu)->cpu_type)) + { + new_sr = m68ki_pull_16(mc68kcpu); + new_pc = m68ki_pull_32(mc68kcpu); + m68ki_jump((mc68kcpu), new_pc); + m68ki_set_sr((mc68kcpu), new_sr); + + (mc68kcpu)->instr_mode = INSTRUCTION_YES; + (mc68kcpu)->run_mode = RUN_MODE_NORMAL; + + return; + } + + if(CPU_TYPE_IS_010((mc68kcpu)->cpu_type)) + { + format_word = m68ki_read_16((mc68kcpu), REG_A(mc68kcpu)[7]+6) >> 12; + if(format_word == 0) + { + new_sr = m68ki_pull_16(mc68kcpu); + new_pc = m68ki_pull_32(mc68kcpu); + m68ki_fake_pull_16(mc68kcpu); /* format word */ + m68ki_jump((mc68kcpu), new_pc); + m68ki_set_sr((mc68kcpu), new_sr); + (mc68kcpu)->instr_mode = INSTRUCTION_YES; + (mc68kcpu)->run_mode = RUN_MODE_NORMAL; + return; + } + (mc68kcpu)->instr_mode = INSTRUCTION_YES; + (mc68kcpu)->run_mode = RUN_MODE_NORMAL; + /* Not handling bus fault (9) */ + m68ki_exception_format_error(mc68kcpu); + return; + } + + /* Otherwise it's 020 */ +rte_loop: + format_word = m68ki_read_16((mc68kcpu), REG_A(mc68kcpu)[7]+6) >> 12; + switch(format_word) + { + case 0: /* Normal */ + new_sr = m68ki_pull_16(mc68kcpu); + new_pc = m68ki_pull_32(mc68kcpu); + m68ki_fake_pull_16(mc68kcpu); /* format word */ + m68ki_jump((mc68kcpu), new_pc); + m68ki_set_sr((mc68kcpu), new_sr); + (mc68kcpu)->instr_mode = INSTRUCTION_YES; + (mc68kcpu)->run_mode = RUN_MODE_NORMAL; + return; + case 1: /* Throwaway */ + new_sr = m68ki_pull_16(mc68kcpu); + m68ki_fake_pull_32(mc68kcpu); /* program counter */ + m68ki_fake_pull_16(mc68kcpu); /* format word */ + m68ki_set_sr_noint((mc68kcpu), new_sr); + goto rte_loop; + case 2: /* Trap */ + new_sr = m68ki_pull_16(mc68kcpu); + new_pc = m68ki_pull_32(mc68kcpu); + m68ki_fake_pull_16(mc68kcpu); /* format word */ + m68ki_fake_pull_32(mc68kcpu); /* address */ + m68ki_jump((mc68kcpu), new_pc); + m68ki_set_sr((mc68kcpu), new_sr); + (mc68kcpu)->instr_mode = INSTRUCTION_YES; + (mc68kcpu)->run_mode = RUN_MODE_NORMAL; + return; + case 7: /* 68040 access error */ + new_sr = m68ki_pull_16(mc68kcpu); + new_pc = m68ki_pull_32(mc68kcpu); + m68ki_fake_pull_16(mc68kcpu); /* $06: format word */ + m68ki_fake_pull_32(mc68kcpu); /* $08: effective address */ + m68ki_fake_pull_16(mc68kcpu); /* $0c: special status word */ + m68ki_fake_pull_16(mc68kcpu); /* $0e: wb3s */ + m68ki_fake_pull_16(mc68kcpu); /* $10: wb2s */ + m68ki_fake_pull_16(mc68kcpu); /* $12: wb1s */ + m68ki_fake_pull_32(mc68kcpu); /* $14: data fault address */ + m68ki_fake_pull_32(mc68kcpu); /* $18: wb3a */ + m68ki_fake_pull_32(mc68kcpu); /* $1c: wb3d */ + m68ki_fake_pull_32(mc68kcpu); /* $20: wb2a */ + m68ki_fake_pull_32(mc68kcpu); /* $24: wb2d */ + m68ki_fake_pull_32(mc68kcpu); /* $28: wb1a */ + m68ki_fake_pull_32(mc68kcpu); /* $2c: wb1d/pd0 */ + m68ki_fake_pull_32(mc68kcpu); /* $30: pd1 */ + m68ki_fake_pull_32(mc68kcpu); /* $34: pd2 */ + m68ki_fake_pull_32(mc68kcpu); /* $38: pd3 */ + m68ki_jump((mc68kcpu), new_pc); + m68ki_set_sr((mc68kcpu), new_sr); + (mc68kcpu)->instr_mode = INSTRUCTION_YES; + (mc68kcpu)->run_mode = RUN_MODE_NORMAL; + return; + + case 0x0a: /* Bus Error at instruction boundary */ + new_sr = m68ki_pull_16(mc68kcpu); + new_pc = m68ki_pull_32(mc68kcpu); + m68ki_fake_pull_16(mc68kcpu); /* $06: format word */ + m68ki_fake_pull_16(mc68kcpu); /* $08: internal register */ + m68ki_fake_pull_16(mc68kcpu); /* $0a: special status word */ + m68ki_fake_pull_16(mc68kcpu); /* $0c: instruction pipe stage c */ + m68ki_fake_pull_16(mc68kcpu); /* $0e: instruction pipe stage b */ + m68ki_fake_pull_32(mc68kcpu); /* $10: data fault address */ + m68ki_fake_pull_32(mc68kcpu); /* $14: internal registers */ + m68ki_fake_pull_32(mc68kcpu); /* $18: data output buffer */ + m68ki_fake_pull_32(mc68kcpu); /* $1c: internal registers */ + + m68ki_jump((mc68kcpu), new_pc); + m68ki_set_sr((mc68kcpu), new_sr); + (mc68kcpu)->instr_mode = INSTRUCTION_YES; + (mc68kcpu)->run_mode = RUN_MODE_NORMAL; + return; + case 0x0b: /* Bus Error - Instruction Execution in Progress */ + new_sr = m68ki_pull_16(mc68kcpu); + new_pc = m68ki_pull_32(mc68kcpu); + m68ki_fake_pull_16(mc68kcpu); /* $06: format word */ + m68ki_fake_pull_16(mc68kcpu); /* $08: internal register */ + m68ki_fake_pull_16(mc68kcpu); /* $0a: special status word */ + m68ki_fake_pull_16(mc68kcpu); /* $0c: instruction pipe stage c */ + m68ki_fake_pull_16(mc68kcpu); /* $0e: instruction pipe stage b */ + m68ki_fake_pull_32(mc68kcpu); /* $10: data fault address */ + m68ki_fake_pull_32(mc68kcpu); /* $14: internal registers */ + m68ki_fake_pull_32(mc68kcpu); /* $18: data output buffer */ + m68ki_fake_pull_32(mc68kcpu); /* $1c: internal registers */ + m68ki_fake_pull_32(mc68kcpu); /* $20: */ + m68ki_fake_pull_32(mc68kcpu); /* $24: stage B address */ + m68ki_fake_pull_32(mc68kcpu); /* $28: */ + m68ki_fake_pull_32(mc68kcpu); /* $2c: data input buffer */ + m68ki_fake_pull_32(mc68kcpu); /* $30: */ + m68ki_fake_pull_16(mc68kcpu); /* $34: */ + m68ki_fake_pull_16(mc68kcpu); /* $36: version #, internal information */ + m68ki_fake_pull_32(mc68kcpu); /* $38: */ + m68ki_fake_pull_32(mc68kcpu); /* $3c: */ + m68ki_fake_pull_32(mc68kcpu); /* $40: */ + m68ki_fake_pull_32(mc68kcpu); /* $44: */ + m68ki_fake_pull_32(mc68kcpu); /* $48: */ + m68ki_fake_pull_32(mc68kcpu); /* $4c: */ + m68ki_fake_pull_32(mc68kcpu); /* $50: */ + m68ki_fake_pull_32(mc68kcpu); /* $54: */ + m68ki_fake_pull_32(mc68kcpu); /* $58: */ + + m68ki_jump((mc68kcpu), new_pc); + m68ki_set_sr((mc68kcpu), new_sr); + (mc68kcpu)->instr_mode = INSTRUCTION_YES; + (mc68kcpu)->run_mode = RUN_MODE_NORMAL; + return; + } + /* Not handling long or short bus fault */ + (mc68kcpu)->instr_mode = INSTRUCTION_YES; + (mc68kcpu)->run_mode = RUN_MODE_NORMAL; + m68ki_exception_format_error(mc68kcpu); + return; + } + m68ki_exception_privilege_violation(mc68kcpu); +} + + +M68KMAKE_OP(rtm, 32, ., .) +{ + if(CPU_TYPE_IS_020_VARIANT((mc68kcpu)->cpu_type)) + { + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + logerror("%s at %08x: called unimplemented instruction %04x (rtm)\n", + (mc68kcpu)->tag(), REG_PC(mc68kcpu) - 2, (mc68kcpu)->ir); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +M68KMAKE_OP(rtr, 32, ., .) +{ + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_set_ccr((mc68kcpu), m68ki_pull_16(mc68kcpu)); + m68ki_jump((mc68kcpu), m68ki_pull_32(mc68kcpu)); +} + + +M68KMAKE_OP(rts, 32, ., .) +{ + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_jump((mc68kcpu), m68ki_pull_32(mc68kcpu)); +} + + +M68KMAKE_OP(sbcd, 8, rr, .) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = DY(mc68kcpu); + UINT32 dst = *r_dst; + UINT32 res = LOW_NIBBLE(dst) - LOW_NIBBLE(src) - XFLAG_AS_1(mc68kcpu); + +// (mc68kcpu)->v_flag = ~res; /* Undefined V behavior */ + (mc68kcpu)->v_flag = VFLAG_CLEAR; /* Undefined in Motorola's M68000PM/AD rev.1 and safer to assume cleared. */ + + if(res > 9) + res -= 6; + res += HIGH_NIBBLE(dst) - HIGH_NIBBLE(src); + if(res > 0x99) + { + res += 0xa0; + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_SET; + (mc68kcpu)->n_flag = NFLAG_SET; /* Undefined in Motorola's M68000PM/AD rev.1 and safer to follow carry. */ + } + else + (mc68kcpu)->n_flag = (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = 0; + + res = MASK_OUT_ABOVE_8(res); + +// (mc68kcpu)->v_flag &= res; /* Undefined V behavior part II */ +// (mc68kcpu)->n_flag = NFLAG_8(res); /* Undefined N behavior */ + (mc68kcpu)->not_z_flag |= res; + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; +} + + +M68KMAKE_OP(sbcd, 8, mm, ax7) +{ + UINT32 src = OPER_AY_PD_8(mc68kcpu); + UINT32 ea = EA_A7_PD_8(mc68kcpu); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + UINT32 res = LOW_NIBBLE(dst) - LOW_NIBBLE(src) - XFLAG_AS_1(mc68kcpu); + +// (mc68kcpu)->v_flag = ~res; /* Undefined V behavior */ + (mc68kcpu)->v_flag = VFLAG_CLEAR; /* Undefined in Motorola's M68000PM/AD rev.1 and safer to return zero. */ + + if(res > 9) + res -= 6; + res += HIGH_NIBBLE(dst) - HIGH_NIBBLE(src); + if(res > 0x99) + { + res += 0xa0; + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_SET; + (mc68kcpu)->n_flag = NFLAG_SET; /* Undefined in Motorola's M68000PM/AD rev.1 and safer to follow carry. */ + } + else + (mc68kcpu)->n_flag = (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = 0; + + res = MASK_OUT_ABOVE_8(res); + +// (mc68kcpu)->v_flag &= res; /* Undefined V behavior part II */ +// (mc68kcpu)->n_flag = NFLAG_8(res); /* Undefined N behavior */ + (mc68kcpu)->not_z_flag |= res; + + m68ki_write_8((mc68kcpu), ea, res); +} + + +M68KMAKE_OP(sbcd, 8, mm, ay7) +{ + UINT32 src = OPER_A7_PD_8(mc68kcpu); + UINT32 ea = EA_AX_PD_8(mc68kcpu); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + UINT32 res = LOW_NIBBLE(dst) - LOW_NIBBLE(src) - XFLAG_AS_1(mc68kcpu); + +// (mc68kcpu)->v_flag = ~res; /* Undefined V behavior */ + (mc68kcpu)->v_flag = VFLAG_CLEAR; /* Undefined in Motorola's M68000PM/AD rev.1 and safer to return zero. */ + + if(res > 9) + res -= 6; + res += HIGH_NIBBLE(dst) - HIGH_NIBBLE(src); + if(res > 0x99) + { + res += 0xa0; + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_SET; + (mc68kcpu)->n_flag = NFLAG_SET; /* Undefined in Motorola's M68000PM/AD rev.1 and safer to follow carry. */ + } + else + (mc68kcpu)->n_flag = (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = 0; + + res = MASK_OUT_ABOVE_8(res); + +// (mc68kcpu)->v_flag &= res; /* Undefined V behavior part II */ +// (mc68kcpu)->n_flag = NFLAG_8(res); /* Undefined N behavior */ + (mc68kcpu)->not_z_flag |= res; + + m68ki_write_8((mc68kcpu), ea, res); +} + + +M68KMAKE_OP(sbcd, 8, mm, axy7) +{ + UINT32 src = OPER_A7_PD_8(mc68kcpu); + UINT32 ea = EA_A7_PD_8(mc68kcpu); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + UINT32 res = LOW_NIBBLE(dst) - LOW_NIBBLE(src) - XFLAG_AS_1(mc68kcpu); + +// (mc68kcpu)->v_flag = ~res; /* Undefined V behavior */ + (mc68kcpu)->v_flag = VFLAG_CLEAR; /* Undefined in Motorola's M68000PM/AD rev.1 and safer to return zero. */ + + if(res > 9) + res -= 6; + res += HIGH_NIBBLE(dst) - HIGH_NIBBLE(src); + if(res > 0x99) + { + res += 0xa0; + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_SET; + (mc68kcpu)->n_flag = NFLAG_SET; /* Undefined in Motorola's M68000PM/AD rev.1 and safer to follow carry. */ + } + else + (mc68kcpu)->n_flag = (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = 0; + + res = MASK_OUT_ABOVE_8(res); + +// (mc68kcpu)->v_flag &= res; /* Undefined V behavior part II */ +// (mc68kcpu)->n_flag = NFLAG_8(res); /* Undefined N behavior */ + (mc68kcpu)->not_z_flag |= res; + + m68ki_write_8((mc68kcpu), ea, res); +} + + +M68KMAKE_OP(sbcd, 8, mm, .) +{ + UINT32 src = OPER_AY_PD_8(mc68kcpu); + UINT32 ea = EA_AX_PD_8(mc68kcpu); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + UINT32 res = LOW_NIBBLE(dst) - LOW_NIBBLE(src) - XFLAG_AS_1(mc68kcpu); + +// (mc68kcpu)->v_flag = ~res; /* Undefined V behavior */ + (mc68kcpu)->v_flag = VFLAG_CLEAR; /* Undefined in Motorola's M68000PM/AD rev.1 and safer to return zero. */ + + if(res > 9) + res -= 6; + res += HIGH_NIBBLE(dst) - HIGH_NIBBLE(src); + if(res > 0x99) + { + res += 0xa0; + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_SET; + (mc68kcpu)->n_flag = NFLAG_SET; /* Undefined in Motorola's M68000PM/AD rev.1 and safer to follow carry. */ + } + else + (mc68kcpu)->n_flag = (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = 0; + + res = MASK_OUT_ABOVE_8(res); + +// (mc68kcpu)->v_flag &= res; /* Undefined V behavior part II */ +// (mc68kcpu)->n_flag = NFLAG_8(res); /* Undefined N behavior */ + (mc68kcpu)->not_z_flag |= res; + + m68ki_write_8((mc68kcpu), ea, res); +} + + +M68KMAKE_OP(st, 8, ., d) +{ + DY(mc68kcpu) |= 0xff; +} + + +M68KMAKE_OP(st, 8, ., .) +{ + m68ki_write_8((mc68kcpu), M68KMAKE_GET_EA_AY_8, 0xff); +} + + +M68KMAKE_OP(sf, 8, ., d) +{ + DY(mc68kcpu) &= 0xffffff00; +} + + +M68KMAKE_OP(sf, 8, ., .) +{ + m68ki_write_8((mc68kcpu), M68KMAKE_GET_EA_AY_8, 0); +} + + +M68KMAKE_OP(scc, 8, ., d) +{ + if(M68KMAKE_CC) + { + DY(mc68kcpu) |= 0xff; + (mc68kcpu)->remaining_cycles -= (mc68kcpu)->cyc_scc_r_true; + return; + } + DY(mc68kcpu) &= 0xffffff00; +} + + +M68KMAKE_OP(scc, 8, ., .) +{ + m68ki_write_8((mc68kcpu), M68KMAKE_GET_EA_AY_8, M68KMAKE_CC ? 0xff : 0); +} + + +M68KMAKE_OP(stop, 0, ., .) +{ + if((mc68kcpu)->s_flag) + { + UINT32 new_sr = OPER_I_16(mc68kcpu); + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + (mc68kcpu)->stopped |= STOP_LEVEL_STOP; + m68ki_set_sr((mc68kcpu), new_sr); + (mc68kcpu)->remaining_cycles = 0; + return; + } + m68ki_exception_privilege_violation(mc68kcpu); +} + + +M68KMAKE_OP(sub, 8, er, d) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = MASK_OUT_ABOVE_8(DY(mc68kcpu)); + UINT32 dst = MASK_OUT_ABOVE_8(*r_dst); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(src, dst, res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | (mc68kcpu)->not_z_flag; +} + + +M68KMAKE_OP(sub, 8, er, .) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = M68KMAKE_GET_OPER_AY_8; + UINT32 dst = MASK_OUT_ABOVE_8(*r_dst); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(src, dst, res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | (mc68kcpu)->not_z_flag; +} + + +M68KMAKE_OP(sub, 16, er, d) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = MASK_OUT_ABOVE_16(DY(mc68kcpu)); + UINT32 dst = MASK_OUT_ABOVE_16(*r_dst); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_16(res); + (mc68kcpu)->v_flag = VFLAG_SUB_16(src, dst, res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | (mc68kcpu)->not_z_flag; +} + + +M68KMAKE_OP(sub, 16, er, a) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = MASK_OUT_ABOVE_16(AY(mc68kcpu)); + UINT32 dst = MASK_OUT_ABOVE_16(*r_dst); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_16(res); + (mc68kcpu)->v_flag = VFLAG_SUB_16(src, dst, res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | (mc68kcpu)->not_z_flag; +} + + +M68KMAKE_OP(sub, 16, er, .) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = M68KMAKE_GET_OPER_AY_16; + UINT32 dst = MASK_OUT_ABOVE_16(*r_dst); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_16(res); + (mc68kcpu)->v_flag = VFLAG_SUB_16(src, dst, res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | (mc68kcpu)->not_z_flag; +} + + +M68KMAKE_OP(sub, 32, er, d) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = DY(mc68kcpu); + UINT32 dst = *r_dst; + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + + *r_dst = (mc68kcpu)->not_z_flag; +} + + +M68KMAKE_OP(sub, 32, er, a) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = AY(mc68kcpu); + UINT32 dst = *r_dst; + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + + *r_dst = (mc68kcpu)->not_z_flag; +} + + +M68KMAKE_OP(sub, 32, er, .) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = M68KMAKE_GET_OPER_AY_32; + UINT32 dst = *r_dst; + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + + *r_dst = (mc68kcpu)->not_z_flag; +} + + +M68KMAKE_OP(sub, 8, re, .) +{ + UINT32 ea = M68KMAKE_GET_EA_AY_8; + UINT32 src = MASK_OUT_ABOVE_8(DX(mc68kcpu)); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(src, dst, res); + + m68ki_write_8((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +M68KMAKE_OP(sub, 16, re, .) +{ + UINT32 ea = M68KMAKE_GET_EA_AY_16; + UINT32 src = MASK_OUT_ABOVE_16(DX(mc68kcpu)); + UINT32 dst = m68ki_read_16((mc68kcpu), ea); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_16(res); + (mc68kcpu)->v_flag = VFLAG_SUB_16(src, dst, res); + + m68ki_write_16((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +M68KMAKE_OP(sub, 32, re, .) +{ + UINT32 ea = M68KMAKE_GET_EA_AY_32; + UINT32 src = DX(mc68kcpu); + UINT32 dst = m68ki_read_32((mc68kcpu), ea); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + + m68ki_write_32((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +M68KMAKE_OP(suba, 16, ., d) +{ + UINT32* r_dst = &AX(mc68kcpu); + + *r_dst = MASK_OUT_ABOVE_32(*r_dst - MAKE_INT_16(DY(mc68kcpu))); +} + + +M68KMAKE_OP(suba, 16, ., a) +{ + UINT32* r_dst = &AX(mc68kcpu); + + *r_dst = MASK_OUT_ABOVE_32(*r_dst - MAKE_INT_16(AY(mc68kcpu))); +} + + +M68KMAKE_OP(suba, 16, ., .) +{ + UINT32* r_dst = &AX(mc68kcpu); + UINT32 src = MAKE_INT_16(M68KMAKE_GET_OPER_AY_16); + + *r_dst = MASK_OUT_ABOVE_32(*r_dst - src); +} + + +M68KMAKE_OP(suba, 32, ., d) +{ + UINT32* r_dst = &AX(mc68kcpu); + + *r_dst = MASK_OUT_ABOVE_32(*r_dst - DY(mc68kcpu)); +} + + +M68KMAKE_OP(suba, 32, ., a) +{ + UINT32* r_dst = &AX(mc68kcpu); + + *r_dst = MASK_OUT_ABOVE_32(*r_dst - AY(mc68kcpu)); +} + + +M68KMAKE_OP(suba, 32, ., .) +{ + UINT32* r_dst = &AX(mc68kcpu); + UINT32 src = M68KMAKE_GET_OPER_AY_32; + + *r_dst = MASK_OUT_ABOVE_32(*r_dst - src); +} + + +M68KMAKE_OP(subi, 8, ., d) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 src = OPER_I_8(mc68kcpu); + UINT32 dst = MASK_OUT_ABOVE_8(*r_dst); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(src, dst, res); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | (mc68kcpu)->not_z_flag; +} + + +M68KMAKE_OP(subi, 8, ., .) +{ + UINT32 src = OPER_I_8(mc68kcpu); + UINT32 ea = M68KMAKE_GET_EA_AY_8; + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(src, dst, res); + + m68ki_write_8((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +M68KMAKE_OP(subi, 16, ., d) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 src = OPER_I_16(mc68kcpu); + UINT32 dst = MASK_OUT_ABOVE_16(*r_dst); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_16(res); + (mc68kcpu)->v_flag = VFLAG_SUB_16(src, dst, res); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | (mc68kcpu)->not_z_flag; +} + + +M68KMAKE_OP(subi, 16, ., .) +{ + UINT32 src = OPER_I_16(mc68kcpu); + UINT32 ea = M68KMAKE_GET_EA_AY_16; + UINT32 dst = m68ki_read_16((mc68kcpu), ea); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_16(res); + (mc68kcpu)->v_flag = VFLAG_SUB_16(src, dst, res); + + m68ki_write_16((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +M68KMAKE_OP(subi, 32, ., d) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 src = OPER_I_32(mc68kcpu); + UINT32 dst = *r_dst; + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + + *r_dst = (mc68kcpu)->not_z_flag; +} + + +M68KMAKE_OP(subi, 32, ., .) +{ + UINT32 src = OPER_I_32(mc68kcpu); + UINT32 ea = M68KMAKE_GET_EA_AY_32; + UINT32 dst = m68ki_read_32((mc68kcpu), ea); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + + m68ki_write_32((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +M68KMAKE_OP(subq, 8, ., d) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 src = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT32 dst = MASK_OUT_ABOVE_8(*r_dst); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(src, dst, res); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | (mc68kcpu)->not_z_flag; +} + + +M68KMAKE_OP(subq, 8, ., .) +{ + UINT32 src = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT32 ea = M68KMAKE_GET_EA_AY_8; + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(src, dst, res); + + m68ki_write_8((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +M68KMAKE_OP(subq, 16, ., d) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 src = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT32 dst = MASK_OUT_ABOVE_16(*r_dst); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_16(res); + (mc68kcpu)->v_flag = VFLAG_SUB_16(src, dst, res); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | (mc68kcpu)->not_z_flag; +} + + +M68KMAKE_OP(subq, 16, ., a) +{ + UINT32* r_dst = &AY(mc68kcpu); + + *r_dst = MASK_OUT_ABOVE_32(*r_dst - (((((mc68kcpu)->ir >> 9) - 1) & 7) + 1)); +} + + +M68KMAKE_OP(subq, 16, ., .) +{ + UINT32 src = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT32 ea = M68KMAKE_GET_EA_AY_16; + UINT32 dst = m68ki_read_16((mc68kcpu), ea); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_16(res); + (mc68kcpu)->v_flag = VFLAG_SUB_16(src, dst, res); + + m68ki_write_16((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +M68KMAKE_OP(subq, 32, ., d) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 src = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT32 dst = *r_dst; + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + + *r_dst = (mc68kcpu)->not_z_flag; +} + + +M68KMAKE_OP(subq, 32, ., a) +{ + UINT32* r_dst = &AY(mc68kcpu); + + *r_dst = MASK_OUT_ABOVE_32(*r_dst - (((((mc68kcpu)->ir >> 9) - 1) & 7) + 1)); +} + + +M68KMAKE_OP(subq, 32, ., .) +{ + UINT32 src = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT32 ea = M68KMAKE_GET_EA_AY_32; + UINT32 dst = m68ki_read_32((mc68kcpu), ea); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + + m68ki_write_32((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +M68KMAKE_OP(subx, 8, rr, .) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = MASK_OUT_ABOVE_8(DY(mc68kcpu)); + UINT32 dst = MASK_OUT_ABOVE_8(*r_dst); + UINT32 res = dst - src - XFLAG_AS_1(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(src, dst, res); + + res = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->not_z_flag |= res; + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; +} + + +M68KMAKE_OP(subx, 16, rr, .) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = MASK_OUT_ABOVE_16(DY(mc68kcpu)); + UINT32 dst = MASK_OUT_ABOVE_16(*r_dst); + UINT32 res = dst - src - XFLAG_AS_1(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_16(res); + (mc68kcpu)->v_flag = VFLAG_SUB_16(src, dst, res); + + res = MASK_OUT_ABOVE_16(res); + (mc68kcpu)->not_z_flag |= res; + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; +} + + +M68KMAKE_OP(subx, 32, rr, .) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = DY(mc68kcpu); + UINT32 dst = *r_dst; + UINT32 res = dst - src - XFLAG_AS_1(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + + res = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->not_z_flag |= res; + + *r_dst = res; +} + + +M68KMAKE_OP(subx, 8, mm, ax7) +{ + UINT32 src = OPER_AY_PD_8(mc68kcpu); + UINT32 ea = EA_A7_PD_8(mc68kcpu); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + UINT32 res = dst - src - XFLAG_AS_1(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(src, dst, res); + + res = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->not_z_flag |= res; + + m68ki_write_8((mc68kcpu), ea, res); +} + + +M68KMAKE_OP(subx, 8, mm, ay7) +{ + UINT32 src = OPER_A7_PD_8(mc68kcpu); + UINT32 ea = EA_AX_PD_8(mc68kcpu); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + UINT32 res = dst - src - XFLAG_AS_1(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(src, dst, res); + + res = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->not_z_flag |= res; + + m68ki_write_8((mc68kcpu), ea, res); +} + + +M68KMAKE_OP(subx, 8, mm, axy7) +{ + UINT32 src = OPER_A7_PD_8(mc68kcpu); + UINT32 ea = EA_A7_PD_8(mc68kcpu); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + UINT32 res = dst - src - XFLAG_AS_1(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(src, dst, res); + + res = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->not_z_flag |= res; + + m68ki_write_8((mc68kcpu), ea, res); +} + + +M68KMAKE_OP(subx, 8, mm, .) +{ + UINT32 src = OPER_AY_PD_8(mc68kcpu); + UINT32 ea = EA_AX_PD_8(mc68kcpu); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + UINT32 res = dst - src - XFLAG_AS_1(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(src, dst, res); + + res = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->not_z_flag |= res; + + m68ki_write_8((mc68kcpu), ea, res); +} + + +M68KMAKE_OP(subx, 16, mm, .) +{ + UINT32 src = OPER_AY_PD_16(mc68kcpu); + UINT32 ea = EA_AX_PD_16(mc68kcpu); + UINT32 dst = m68ki_read_16((mc68kcpu), ea); + UINT32 res = dst - src - XFLAG_AS_1(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_16(res); + (mc68kcpu)->v_flag = VFLAG_SUB_16(src, dst, res); + + res = MASK_OUT_ABOVE_16(res); + (mc68kcpu)->not_z_flag |= res; + + m68ki_write_16((mc68kcpu), ea, res); +} + + +M68KMAKE_OP(subx, 32, mm, .) +{ + UINT32 src = OPER_AY_PD_32(mc68kcpu); + UINT32 ea = EA_AX_PD_32(mc68kcpu); + UINT32 dst = m68ki_read_32((mc68kcpu), ea); + UINT32 res = dst - src - XFLAG_AS_1(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + + res = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->not_z_flag |= res; + + m68ki_write_32((mc68kcpu), ea, res); +} + + +M68KMAKE_OP(swap, 32, ., .) +{ + UINT32* r_dst = &DY(mc68kcpu); + + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(*r_dst<<16); + *r_dst = (*r_dst>>16) | (mc68kcpu)->not_z_flag; + + (mc68kcpu)->not_z_flag = *r_dst; + (mc68kcpu)->n_flag = NFLAG_32(*r_dst); + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +M68KMAKE_OP(tas, 8, ., d) +{ + UINT32* r_dst = &DY(mc68kcpu); + + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(*r_dst); + (mc68kcpu)->n_flag = NFLAG_8(*r_dst); + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + *r_dst |= 0x80; +} + + +M68KMAKE_OP(tas, 8, ., .) +{ + UINT32 ea = M68KMAKE_GET_EA_AY_8; + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + + (mc68kcpu)->not_z_flag = dst; + (mc68kcpu)->n_flag = NFLAG_8(dst); + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + + /* On the 68000 and 68010, the TAS instruction uses a unique bus cycle that may have + side effects (e.g. delaying DMA) or may fail to write back at all depending on the + bus implementation. + In particular, the Genesis/Megadrive games Gargoyles and Ex-Mutants need the TAS + to fail to write back in order to function properly. */ + if (CPU_TYPE_IS_010_LESS((mc68kcpu)->cpu_type) && !(mc68kcpu)->tas_write_callback.isnull()) + ((mc68kcpu)->tas_write_callback)(*(mc68kcpu)->program, ea, dst | 0x80, 0xff); + else + m68ki_write_8((mc68kcpu), ea, dst | 0x80); +} + + +M68KMAKE_OP(trap, 0, ., .) +{ + /* Trap#n stacks exception frame type 0 */ + m68ki_exception_trapN((mc68kcpu), EXCEPTION_TRAP_BASE + ((mc68kcpu)->ir & 0xf)); /* HJB 990403 */ +} + + +M68KMAKE_OP(trapt, 0, ., .) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + m68ki_exception_trap((mc68kcpu), EXCEPTION_TRAPV); /* HJB 990403 */ + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +M68KMAKE_OP(trapt, 16, ., .) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + m68ki_exception_trap((mc68kcpu), EXCEPTION_TRAPV); /* HJB 990403 */ + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +M68KMAKE_OP(trapt, 32, ., .) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + m68ki_exception_trap((mc68kcpu), EXCEPTION_TRAPV); /* HJB 990403 */ + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +M68KMAKE_OP(trapf, 0, ., .) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +M68KMAKE_OP(trapf, 16, ., .) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + REG_PC(mc68kcpu) += 2; + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +M68KMAKE_OP(trapf, 32, ., .) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + REG_PC(mc68kcpu) += 4; + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +M68KMAKE_OP(trapcc, 0, ., .) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + if(M68KMAKE_CC) + m68ki_exception_trap((mc68kcpu), EXCEPTION_TRAPV); /* HJB 990403 */ + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +M68KMAKE_OP(trapcc, 16, ., .) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + if(M68KMAKE_CC) + { + m68ki_exception_trap((mc68kcpu), EXCEPTION_TRAPV); /* HJB 990403 */ + return; + } + REG_PC(mc68kcpu) += 2; + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +M68KMAKE_OP(trapcc, 32, ., .) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + if(M68KMAKE_CC) + { + m68ki_exception_trap((mc68kcpu), EXCEPTION_TRAPV); /* HJB 990403 */ + return; + } + REG_PC(mc68kcpu) += 4; + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +M68KMAKE_OP(trapv, 0, ., .) +{ + if(COND_VC(mc68kcpu)) + { + return; + } + m68ki_exception_trap((mc68kcpu), EXCEPTION_TRAPV); /* HJB 990403 */ +} + + +M68KMAKE_OP(tst, 8, ., d) +{ + UINT32 res = MASK_OUT_ABOVE_8(DY(mc68kcpu)); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +M68KMAKE_OP(tst, 8, ., .) +{ + UINT32 res = M68KMAKE_GET_OPER_AY_8; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +M68KMAKE_OP(tst, 8, ., pcdi) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 res = OPER_PCDI_8(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +M68KMAKE_OP(tst, 8, ., pcix) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 res = OPER_PCIX_8(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +M68KMAKE_OP(tst, 8, ., i) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 res = OPER_I_8(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +M68KMAKE_OP(tst, 16, ., d) +{ + UINT32 res = MASK_OUT_ABOVE_16(DY(mc68kcpu)); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +M68KMAKE_OP(tst, 16, ., a) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 res = MAKE_INT_16(AY(mc68kcpu)); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +M68KMAKE_OP(tst, 16, ., .) +{ + UINT32 res = M68KMAKE_GET_OPER_AY_16; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +M68KMAKE_OP(tst, 16, ., pcdi) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 res = OPER_PCDI_16(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +M68KMAKE_OP(tst, 16, ., pcix) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 res = OPER_PCIX_16(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +M68KMAKE_OP(tst, 16, ., i) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 res = OPER_I_16(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +M68KMAKE_OP(tst, 32, ., d) +{ + UINT32 res = DY(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +M68KMAKE_OP(tst, 32, ., a) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 res = AY(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +M68KMAKE_OP(tst, 32, ., .) +{ + UINT32 res = M68KMAKE_GET_OPER_AY_32; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +M68KMAKE_OP(tst, 32, ., pcdi) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 res = OPER_PCDI_32(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +M68KMAKE_OP(tst, 32, ., pcix) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 res = OPER_PCIX_32(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +M68KMAKE_OP(tst, 32, ., i) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 res = OPER_I_32(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +M68KMAKE_OP(unlk, 32, ., a7) +{ + REG_A(mc68kcpu)[7] = m68ki_read_32((mc68kcpu), REG_A(mc68kcpu)[7]); +} + + +M68KMAKE_OP(unlk, 32, ., .) +{ + UINT32* r_dst = &AY(mc68kcpu); + + REG_A(mc68kcpu)[7] = *r_dst; + *r_dst = m68ki_pull_32(mc68kcpu); +} + + +M68KMAKE_OP(unpk, 16, rr, .) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + /* Note: DX(mc68kcpu) and DY(mc68kcpu) are reversed in Motorola's docs */ + UINT32 src = DY(mc68kcpu); + UINT32* r_dst = &DX(mc68kcpu); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | (((((src << 4) & 0x0f00) | (src & 0x000f)) + OPER_I_16(mc68kcpu)) & 0xffff); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +M68KMAKE_OP(unpk, 16, mm, ax7) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + /* Note: AX and AY are reversed in Motorola's docs */ + UINT32 src = OPER_AY_PD_8(mc68kcpu); + UINT32 ea_dst; + + src = (((src << 4) & 0x0f00) | (src & 0x000f)) + OPER_I_16(mc68kcpu); + ea_dst = EA_A7_PD_8(mc68kcpu); + m68ki_write_8((mc68kcpu), ea_dst, (src >> 8) & 0xff); + ea_dst = EA_A7_PD_8(mc68kcpu); + m68ki_write_8((mc68kcpu), ea_dst, src & 0xff); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +M68KMAKE_OP(unpk, 16, mm, ay7) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + /* Note: AX and AY are reversed in Motorola's docs */ + UINT32 src = OPER_A7_PD_8(mc68kcpu); + UINT32 ea_dst; + + src = (((src << 4) & 0x0f00) | (src & 0x000f)) + OPER_I_16(mc68kcpu); + ea_dst = EA_AX_PD_8(mc68kcpu); + m68ki_write_8((mc68kcpu), ea_dst, (src >> 8) & 0xff); + ea_dst = EA_AX_PD_8(mc68kcpu); + m68ki_write_8((mc68kcpu), ea_dst, src & 0xff); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +M68KMAKE_OP(unpk, 16, mm, axy7) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 src = OPER_A7_PD_8(mc68kcpu); + UINT32 ea_dst; + + src = (((src << 4) & 0x0f00) | (src & 0x000f)) + OPER_I_16(mc68kcpu); + ea_dst = EA_A7_PD_8(mc68kcpu); + m68ki_write_8((mc68kcpu), ea_dst, (src >> 8) & 0xff); + ea_dst = EA_A7_PD_8(mc68kcpu); + m68ki_write_8((mc68kcpu), ea_dst, src & 0xff); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +M68KMAKE_OP(unpk, 16, mm, .) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + /* Note: AX and AY are reversed in Motorola's docs */ + UINT32 src = OPER_AY_PD_8(mc68kcpu); + UINT32 ea_dst; + + src = (((src << 4) & 0x0f00) | (src & 0x000f)) + OPER_I_16(mc68kcpu); + ea_dst = EA_AX_PD_8(mc68kcpu); + m68ki_write_8((mc68kcpu), ea_dst, (src >> 8) & 0xff); + ea_dst = EA_AX_PD_8(mc68kcpu); + m68ki_write_8((mc68kcpu), ea_dst, src & 0xff); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +M68KMAKE_OP(cinv, 32, ., .) +{ + if(CPU_TYPE_IS_040_PLUS((mc68kcpu)->cpu_type)) + { + UINT16 ir = mc68kcpu->ir; + UINT8 cache = (ir >> 6) & 3; +// UINT8 scope = (ir >> 3) & 3; +// logerror("68040 %s: pc=%08x ir=%04x cache=%d scope=%d register=%d\n", ir & 0x0020 ? "cpush" : "cinv", REG_PPC(mc68kcpu), ir, cache, scope, ir & 7); + switch (cache) + { + case 2: + case 3: + // we invalidate/push the whole instruction cache + m68ki_ic_clear(mc68kcpu); + } + return; + } + m68ki_exception_1111(mc68kcpu); +} + +M68KMAKE_OP(cpush, 32, ., .) +{ + if(CPU_TYPE_IS_040_PLUS((mc68kcpu)->cpu_type)) + { + logerror("%s at %08x: called unimplemented instruction %04x (cpush)\n", + (mc68kcpu)->tag(), REG_PC(mc68kcpu) - 2, (mc68kcpu)->ir); + return; + } + m68ki_exception_1111(mc68kcpu); +} + +XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +M68KMAKE_END diff --git a/src/devices/cpu/m68000/m68kcpu.c b/src/devices/cpu/m68000/m68kcpu.c new file mode 100644 index 00000000000..bc5e7bc9b3d --- /dev/null +++ b/src/devices/cpu/m68000/m68kcpu.c @@ -0,0 +1,2815 @@ +// license:BSD-3-Clause +// copyright-holders:Karl Stenerud +/* ======================================================================== */ +/* ========================= LICENSING & COPYRIGHT ======================== */ +/* ======================================================================== */ + +#if 0 +static const char copyright_notice[] = +"MUSASHI\n" +"Version 4.95 (2012-02-19)\n" +"A portable Motorola M68xxx/CPU32/ColdFire processor emulation engine.\n" +"Copyright Karl Stenerud. All rights reserved.\n" +; +#endif + + +/* ======================================================================== */ +/* ================================= NOTES ================================ */ +/* ======================================================================== */ + + + +/* ======================================================================== */ +/* ================================ INCLUDES ============================== */ +/* ======================================================================== */ + +#include "emu.h" +#include "debugger.h" +#include "m68kcpu.h" +#include "m68kops.h" + +#include "m68kfpu.inc" +#include "m68kmmu.h" + +extern void m68040_fpu_op0(m68000_base_device *m68k); +extern void m68040_fpu_op1(m68000_base_device *m68k); +extern void m68881_mmu_ops(m68000_base_device *m68k); + +/* ======================================================================== */ +/* ================================= DATA ================================= */ +/* ======================================================================== */ + +/* Used by shift & rotate instructions */ +const UINT8 m68ki_shift_8_table[65] = +{ + 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff +}; +const UINT16 m68ki_shift_16_table[65] = +{ + 0x0000, 0x8000, 0xc000, 0xe000, 0xf000, 0xf800, 0xfc00, 0xfe00, 0xff00, + 0xff80, 0xffc0, 0xffe0, 0xfff0, 0xfff8, 0xfffc, 0xfffe, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff +}; +const UINT32 m68ki_shift_32_table[65] = +{ + 0x00000000, 0x80000000, 0xc0000000, 0xe0000000, 0xf0000000, 0xf8000000, + 0xfc000000, 0xfe000000, 0xff000000, 0xff800000, 0xffc00000, 0xffe00000, + 0xfff00000, 0xfff80000, 0xfffc0000, 0xfffe0000, 0xffff0000, 0xffff8000, + 0xffffc000, 0xffffe000, 0xfffff000, 0xfffff800, 0xfffffc00, 0xfffffe00, + 0xffffff00, 0xffffff80, 0xffffffc0, 0xffffffe0, 0xfffffff0, 0xfffffff8, + 0xfffffffc, 0xfffffffe, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff +}; + + +/* Number of clock cycles to use for exception processing. + * I used 4 for any vectors that are undocumented for processing times. + */ +const UINT8 m68ki_exception_cycle_table[7][256] = +{ + { /* 000 */ + 40, /* 0: Reset - Initial Stack Pointer */ + 4, /* 1: Reset - Initial Program Counter */ + 50, /* 2: Bus Error (unemulated) */ + 50, /* 3: Address Error (unemulated) */ + 34, /* 4: Illegal Instruction */ + 38, /* 5: Divide by Zero */ + 40, /* 6: CHK */ + 34, /* 7: TRAPV */ + 34, /* 8: Privilege Violation */ + 34, /* 9: Trace */ + 4, /* 10: 1010 */ + 4, /* 11: 1111 */ + 4, /* 12: RESERVED */ + 4, /* 13: Coprocessor Protocol Violation (unemulated) */ + 4, /* 14: Format Error */ + 44, /* 15: Uninitialized Interrupt */ + 4, /* 16: RESERVED */ + 4, /* 17: RESERVED */ + 4, /* 18: RESERVED */ + 4, /* 19: RESERVED */ + 4, /* 20: RESERVED */ + 4, /* 21: RESERVED */ + 4, /* 22: RESERVED */ + 4, /* 23: RESERVED */ + 44, /* 24: Spurious Interrupt */ + 44, /* 25: Level 1 Interrupt Autovector */ + 44, /* 26: Level 2 Interrupt Autovector */ + 44, /* 27: Level 3 Interrupt Autovector */ + 44, /* 28: Level 4 Interrupt Autovector */ + 44, /* 29: Level 5 Interrupt Autovector */ + 44, /* 30: Level 6 Interrupt Autovector */ + 44, /* 31: Level 7 Interrupt Autovector */ + 34, /* 32: TRAP #0 */ + 34, /* 33: TRAP #1 */ + 34, /* 34: TRAP #2 */ + 34, /* 35: TRAP #3 */ + 34, /* 36: TRAP #4 */ + 34, /* 37: TRAP #5 */ + 34, /* 38: TRAP #6 */ + 34, /* 39: TRAP #7 */ + 34, /* 40: TRAP #8 */ + 34, /* 41: TRAP #9 */ + 34, /* 42: TRAP #10 */ + 34, /* 43: TRAP #11 */ + 34, /* 44: TRAP #12 */ + 34, /* 45: TRAP #13 */ + 34, /* 46: TRAP #14 */ + 34, /* 47: TRAP #15 */ + 4, /* 48: FP Branch or Set on Unknown Condition (unemulated) */ + 4, /* 49: FP Inexact Result (unemulated) */ + 4, /* 50: FP Divide by Zero (unemulated) */ + 4, /* 51: FP Underflow (unemulated) */ + 4, /* 52: FP Operand Error (unemulated) */ + 4, /* 53: FP Overflow (unemulated) */ + 4, /* 54: FP Signaling NAN (unemulated) */ + 4, /* 55: FP Unimplemented Data Type (unemulated) */ + 4, /* 56: MMU Configuration Error (unemulated) */ + 4, /* 57: MMU Illegal Operation Error (unemulated) */ + 4, /* 58: MMU Access Level Violation Error (unemulated) */ + 4, /* 59: RESERVED */ + 4, /* 60: RESERVED */ + 4, /* 61: RESERVED */ + 4, /* 62: RESERVED */ + 4, /* 63: RESERVED */ + /* 64-255: User Defined */ + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4 + }, + { /* 010 */ + 40, /* 0: Reset - Initial Stack Pointer */ + 4, /* 1: Reset - Initial Program Counter */ + 126, /* 2: Bus Error (unemulated) */ + 126, /* 3: Address Error (unemulated) */ + 38, /* 4: Illegal Instruction */ + 44, /* 5: Divide by Zero */ + 44, /* 6: CHK */ + 34, /* 7: TRAPV */ + 38, /* 8: Privilege Violation */ + 38, /* 9: Trace */ + 4, /* 10: 1010 */ + 4, /* 11: 1111 */ + 4, /* 12: RESERVED */ + 4, /* 13: Coprocessor Protocol Violation (unemulated) */ + 4, /* 14: Format Error */ + 44, /* 15: Uninitialized Interrupt */ + 4, /* 16: RESERVED */ + 4, /* 17: RESERVED */ + 4, /* 18: RESERVED */ + 4, /* 19: RESERVED */ + 4, /* 20: RESERVED */ + 4, /* 21: RESERVED */ + 4, /* 22: RESERVED */ + 4, /* 23: RESERVED */ + 46, /* 24: Spurious Interrupt */ + 46, /* 25: Level 1 Interrupt Autovector */ + 46, /* 26: Level 2 Interrupt Autovector */ + 46, /* 27: Level 3 Interrupt Autovector */ + 46, /* 28: Level 4 Interrupt Autovector */ + 46, /* 29: Level 5 Interrupt Autovector */ + 46, /* 30: Level 6 Interrupt Autovector */ + 46, /* 31: Level 7 Interrupt Autovector */ + 38, /* 32: TRAP #0 */ + 38, /* 33: TRAP #1 */ + 38, /* 34: TRAP #2 */ + 38, /* 35: TRAP #3 */ + 38, /* 36: TRAP #4 */ + 38, /* 37: TRAP #5 */ + 38, /* 38: TRAP #6 */ + 38, /* 39: TRAP #7 */ + 38, /* 40: TRAP #8 */ + 38, /* 41: TRAP #9 */ + 38, /* 42: TRAP #10 */ + 38, /* 43: TRAP #11 */ + 38, /* 44: TRAP #12 */ + 38, /* 45: TRAP #13 */ + 38, /* 46: TRAP #14 */ + 38, /* 47: TRAP #15 */ + 4, /* 48: FP Branch or Set on Unknown Condition (unemulated) */ + 4, /* 49: FP Inexact Result (unemulated) */ + 4, /* 50: FP Divide by Zero (unemulated) */ + 4, /* 51: FP Underflow (unemulated) */ + 4, /* 52: FP Operand Error (unemulated) */ + 4, /* 53: FP Overflow (unemulated) */ + 4, /* 54: FP Signaling NAN (unemulated) */ + 4, /* 55: FP Unimplemented Data Type (unemulated) */ + 4, /* 56: MMU Configuration Error (unemulated) */ + 4, /* 57: MMU Illegal Operation Error (unemulated) */ + 4, /* 58: MMU Access Level Violation Error (unemulated) */ + 4, /* 59: RESERVED */ + 4, /* 60: RESERVED */ + 4, /* 61: RESERVED */ + 4, /* 62: RESERVED */ + 4, /* 63: RESERVED */ + /* 64-255: User Defined */ + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4 + }, + { /* 020 */ + 4, /* 0: Reset - Initial Stack Pointer */ + 4, /* 1: Reset - Initial Program Counter */ + 50, /* 2: Bus Error (unemulated) */ + 50, /* 3: Address Error (unemulated) */ + 20, /* 4: Illegal Instruction */ + 38, /* 5: Divide by Zero */ + 40, /* 6: CHK */ + 20, /* 7: TRAPV */ + 34, /* 8: Privilege Violation */ + 25, /* 9: Trace */ + 20, /* 10: 1010 */ + 20, /* 11: 1111 */ + 4, /* 12: RESERVED */ + 4, /* 13: Coprocessor Protocol Violation (unemulated) */ + 4, /* 14: Format Error */ + 30, /* 15: Uninitialized Interrupt */ + 4, /* 16: RESERVED */ + 4, /* 17: RESERVED */ + 4, /* 18: RESERVED */ + 4, /* 19: RESERVED */ + 4, /* 20: RESERVED */ + 4, /* 21: RESERVED */ + 4, /* 22: RESERVED */ + 4, /* 23: RESERVED */ + 30, /* 24: Spurious Interrupt */ + 30, /* 25: Level 1 Interrupt Autovector */ + 30, /* 26: Level 2 Interrupt Autovector */ + 30, /* 27: Level 3 Interrupt Autovector */ + 30, /* 28: Level 4 Interrupt Autovector */ + 30, /* 29: Level 5 Interrupt Autovector */ + 30, /* 30: Level 6 Interrupt Autovector */ + 30, /* 31: Level 7 Interrupt Autovector */ + 20, /* 32: TRAP #0 */ + 20, /* 33: TRAP #1 */ + 20, /* 34: TRAP #2 */ + 20, /* 35: TRAP #3 */ + 20, /* 36: TRAP #4 */ + 20, /* 37: TRAP #5 */ + 20, /* 38: TRAP #6 */ + 20, /* 39: TRAP #7 */ + 20, /* 40: TRAP #8 */ + 20, /* 41: TRAP #9 */ + 20, /* 42: TRAP #10 */ + 20, /* 43: TRAP #11 */ + 20, /* 44: TRAP #12 */ + 20, /* 45: TRAP #13 */ + 20, /* 46: TRAP #14 */ + 20, /* 47: TRAP #15 */ + 4, /* 48: FP Branch or Set on Unknown Condition (unemulated) */ + 4, /* 49: FP Inexact Result (unemulated) */ + 4, /* 50: FP Divide by Zero (unemulated) */ + 4, /* 51: FP Underflow (unemulated) */ + 4, /* 52: FP Operand Error (unemulated) */ + 4, /* 53: FP Overflow (unemulated) */ + 4, /* 54: FP Signaling NAN (unemulated) */ + 4, /* 55: FP Unimplemented Data Type (unemulated) */ + 4, /* 56: MMU Configuration Error (unemulated) */ + 4, /* 57: MMU Illegal Operation Error (unemulated) */ + 4, /* 58: MMU Access Level Violation Error (unemulated) */ + 4, /* 59: RESERVED */ + 4, /* 60: RESERVED */ + 4, /* 61: RESERVED */ + 4, /* 62: RESERVED */ + 4, /* 63: RESERVED */ + /* 64-255: User Defined */ + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4 + }, + { /* 030 - not correct */ + 4, /* 0: Reset - Initial Stack Pointer */ + 4, /* 1: Reset - Initial Program Counter */ + 50, /* 2: Bus Error (unemulated) */ + 50, /* 3: Address Error (unemulated) */ + 20, /* 4: Illegal Instruction */ + 38, /* 5: Divide by Zero */ + 40, /* 6: CHK */ + 20, /* 7: TRAPV */ + 34, /* 8: Privilege Violation */ + 25, /* 9: Trace */ + 20, /* 10: 1010 */ + 20, /* 11: 1111 */ + 4, /* 12: RESERVED */ + 4, /* 13: Coprocessor Protocol Violation (unemulated) */ + 4, /* 14: Format Error */ + 30, /* 15: Uninitialized Interrupt */ + 4, /* 16: RESERVED */ + 4, /* 17: RESERVED */ + 4, /* 18: RESERVED */ + 4, /* 19: RESERVED */ + 4, /* 20: RESERVED */ + 4, /* 21: RESERVED */ + 4, /* 22: RESERVED */ + 4, /* 23: RESERVED */ + 30, /* 24: Spurious Interrupt */ + 30, /* 25: Level 1 Interrupt Autovector */ + 30, /* 26: Level 2 Interrupt Autovector */ + 30, /* 27: Level 3 Interrupt Autovector */ + 30, /* 28: Level 4 Interrupt Autovector */ + 30, /* 29: Level 5 Interrupt Autovector */ + 30, /* 30: Level 6 Interrupt Autovector */ + 30, /* 31: Level 7 Interrupt Autovector */ + 20, /* 32: TRAP #0 */ + 20, /* 33: TRAP #1 */ + 20, /* 34: TRAP #2 */ + 20, /* 35: TRAP #3 */ + 20, /* 36: TRAP #4 */ + 20, /* 37: TRAP #5 */ + 20, /* 38: TRAP #6 */ + 20, /* 39: TRAP #7 */ + 20, /* 40: TRAP #8 */ + 20, /* 41: TRAP #9 */ + 20, /* 42: TRAP #10 */ + 20, /* 43: TRAP #11 */ + 20, /* 44: TRAP #12 */ + 20, /* 45: TRAP #13 */ + 20, /* 46: TRAP #14 */ + 20, /* 47: TRAP #15 */ + 4, /* 48: FP Branch or Set on Unknown Condition (unemulated) */ + 4, /* 49: FP Inexact Result (unemulated) */ + 4, /* 50: FP Divide by Zero (unemulated) */ + 4, /* 51: FP Underflow (unemulated) */ + 4, /* 52: FP Operand Error (unemulated) */ + 4, /* 53: FP Overflow (unemulated) */ + 4, /* 54: FP Signaling NAN (unemulated) */ + 4, /* 55: FP Unimplemented Data Type (unemulated) */ + 4, /* 56: MMU Configuration Error (unemulated) */ + 4, /* 57: MMU Illegal Operation Error (unemulated) */ + 4, /* 58: MMU Access Level Violation Error (unemulated) */ + 4, /* 59: RESERVED */ + 4, /* 60: RESERVED */ + 4, /* 61: RESERVED */ + 4, /* 62: RESERVED */ + 4, /* 63: RESERVED */ + /* 64-255: User Defined */ + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4 + }, + { /* 040 */ // TODO: these values are not correct + 4, /* 0: Reset - Initial Stack Pointer */ + 4, /* 1: Reset - Initial Program Counter */ + 50, /* 2: Bus Error (unemulated) */ + 50, /* 3: Address Error (unemulated) */ + 20, /* 4: Illegal Instruction */ + 38, /* 5: Divide by Zero */ + 40, /* 6: CHK */ + 20, /* 7: TRAPV */ + 34, /* 8: Privilege Violation */ + 25, /* 9: Trace */ + 20, /* 10: 1010 */ + 20, /* 11: 1111 */ + 4, /* 12: RESERVED */ + 4, /* 13: Coprocessor Protocol Violation (unemulated) */ + 4, /* 14: Format Error */ + 30, /* 15: Uninitialized Interrupt */ + 4, /* 16: RESERVED */ + 4, /* 17: RESERVED */ + 4, /* 18: RESERVED */ + 4, /* 19: RESERVED */ + 4, /* 20: RESERVED */ + 4, /* 21: RESERVED */ + 4, /* 22: RESERVED */ + 4, /* 23: RESERVED */ + 30, /* 24: Spurious Interrupt */ + 30, /* 25: Level 1 Interrupt Autovector */ + 30, /* 26: Level 2 Interrupt Autovector */ + 30, /* 27: Level 3 Interrupt Autovector */ + 30, /* 28: Level 4 Interrupt Autovector */ + 30, /* 29: Level 5 Interrupt Autovector */ + 30, /* 30: Level 6 Interrupt Autovector */ + 30, /* 31: Level 7 Interrupt Autovector */ + 20, /* 32: TRAP #0 */ + 20, /* 33: TRAP #1 */ + 20, /* 34: TRAP #2 */ + 20, /* 35: TRAP #3 */ + 20, /* 36: TRAP #4 */ + 20, /* 37: TRAP #5 */ + 20, /* 38: TRAP #6 */ + 20, /* 39: TRAP #7 */ + 20, /* 40: TRAP #8 */ + 20, /* 41: TRAP #9 */ + 20, /* 42: TRAP #10 */ + 20, /* 43: TRAP #11 */ + 20, /* 44: TRAP #12 */ + 20, /* 45: TRAP #13 */ + 20, /* 46: TRAP #14 */ + 20, /* 47: TRAP #15 */ + 4, /* 48: FP Branch or Set on Unknown Condition (unemulated) */ + 4, /* 49: FP Inexact Result (unemulated) */ + 4, /* 50: FP Divide by Zero (unemulated) */ + 4, /* 51: FP Underflow (unemulated) */ + 4, /* 52: FP Operand Error (unemulated) */ + 4, /* 53: FP Overflow (unemulated) */ + 4, /* 54: FP Signaling NAN (unemulated) */ + 4, /* 55: FP Unimplemented Data Type (unemulated) */ + 4, /* 56: MMU Configuration Error (unemulated) */ + 4, /* 57: MMU Illegal Operation Error (unemulated) */ + 4, /* 58: MMU Access Level Violation Error (unemulated) */ + 4, /* 59: RESERVED */ + 4, /* 60: RESERVED */ + 4, /* 61: RESERVED */ + 4, /* 62: RESERVED */ + 4, /* 63: RESERVED */ + /* 64-255: User Defined */ + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4 + }, + { /* CPU32 */ + 4, /* 0: Reset - Initial Stack Pointer */ + 4, /* 1: Reset - Initial Program Counter */ + 50, /* 2: Bus Error (unemulated) */ + 50, /* 3: Address Error (unemulated) */ + 20, /* 4: Illegal Instruction */ + 38, /* 5: Divide by Zero */ + 40, /* 6: CHK */ + 20, /* 7: TRAPV */ + 34, /* 8: Privilege Violation */ + 25, /* 9: Trace */ + 20, /* 10: 1010 */ + 20, /* 11: 1111 */ + 4, /* 12: RESERVED */ + 4, /* 13: Coprocessor Protocol Violation (unemulated) */ + 4, /* 14: Format Error */ + 30, /* 15: Uninitialized Interrupt */ + 4, /* 16: RESERVED */ + 4, /* 17: RESERVED */ + 4, /* 18: RESERVED */ + 4, /* 19: RESERVED */ + 4, /* 20: RESERVED */ + 4, /* 21: RESERVED */ + 4, /* 22: RESERVED */ + 4, /* 23: RESERVED */ + 30, /* 24: Spurious Interrupt */ + 30, /* 25: Level 1 Interrupt Autovector */ + 30, /* 26: Level 2 Interrupt Autovector */ + 30, /* 27: Level 3 Interrupt Autovector */ + 30, /* 28: Level 4 Interrupt Autovector */ + 30, /* 29: Level 5 Interrupt Autovector */ + 30, /* 30: Level 6 Interrupt Autovector */ + 30, /* 31: Level 7 Interrupt Autovector */ + 20, /* 32: TRAP #0 */ + 20, /* 33: TRAP #1 */ + 20, /* 34: TRAP #2 */ + 20, /* 35: TRAP #3 */ + 20, /* 36: TRAP #4 */ + 20, /* 37: TRAP #5 */ + 20, /* 38: TRAP #6 */ + 20, /* 39: TRAP #7 */ + 20, /* 40: TRAP #8 */ + 20, /* 41: TRAP #9 */ + 20, /* 42: TRAP #10 */ + 20, /* 43: TRAP #11 */ + 20, /* 44: TRAP #12 */ + 20, /* 45: TRAP #13 */ + 20, /* 46: TRAP #14 */ + 20, /* 47: TRAP #15 */ + 4, /* 48: FP Branch or Set on Unknown Condition (unemulated) */ + 4, /* 49: FP Inexact Result (unemulated) */ + 4, /* 50: FP Divide by Zero (unemulated) */ + 4, /* 51: FP Underflow (unemulated) */ + 4, /* 52: FP Operand Error (unemulated) */ + 4, /* 53: FP Overflow (unemulated) */ + 4, /* 54: FP Signaling NAN (unemulated) */ + 4, /* 55: FP Unimplemented Data Type (unemulated) */ + 4, /* 56: MMU Configuration Error (unemulated) */ + 4, /* 57: MMU Illegal Operation Error (unemulated) */ + 4, /* 58: MMU Access Level Violation Error (unemulated) */ + 4, /* 59: RESERVED */ + 4, /* 60: RESERVED */ + 4, /* 61: RESERVED */ + 4, /* 62: RESERVED */ + 4, /* 63: RESERVED */ + /* 64-255: User Defined */ + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4 + }, + { /* ColdFire - not correct */ + 4, /* 0: Reset - Initial Stack Pointer */ + 4, /* 1: Reset - Initial Program Counter */ + 50, /* 2: Bus Error (unemulated) */ + 50, /* 3: Address Error (unemulated) */ + 20, /* 4: Illegal Instruction */ + 38, /* 5: Divide by Zero */ + 40, /* 6: CHK */ + 20, /* 7: TRAPV */ + 34, /* 8: Privilege Violation */ + 25, /* 9: Trace */ + 20, /* 10: 1010 */ + 20, /* 11: 1111 */ + 4, /* 12: RESERVED */ + 4, /* 13: Coprocessor Protocol Violation (unemulated) */ + 4, /* 14: Format Error */ + 30, /* 15: Uninitialized Interrupt */ + 4, /* 16: RESERVED */ + 4, /* 17: RESERVED */ + 4, /* 18: RESERVED */ + 4, /* 19: RESERVED */ + 4, /* 20: RESERVED */ + 4, /* 21: RESERVED */ + 4, /* 22: RESERVED */ + 4, /* 23: RESERVED */ + 30, /* 24: Spurious Interrupt */ + 30, /* 25: Level 1 Interrupt Autovector */ + 30, /* 26: Level 2 Interrupt Autovector */ + 30, /* 27: Level 3 Interrupt Autovector */ + 30, /* 28: Level 4 Interrupt Autovector */ + 30, /* 29: Level 5 Interrupt Autovector */ + 30, /* 30: Level 6 Interrupt Autovector */ + 30, /* 31: Level 7 Interrupt Autovector */ + 20, /* 32: TRAP #0 */ + 20, /* 33: TRAP #1 */ + 20, /* 34: TRAP #2 */ + 20, /* 35: TRAP #3 */ + 20, /* 36: TRAP #4 */ + 20, /* 37: TRAP #5 */ + 20, /* 38: TRAP #6 */ + 20, /* 39: TRAP #7 */ + 20, /* 40: TRAP #8 */ + 20, /* 41: TRAP #9 */ + 20, /* 42: TRAP #10 */ + 20, /* 43: TRAP #11 */ + 20, /* 44: TRAP #12 */ + 20, /* 45: TRAP #13 */ + 20, /* 46: TRAP #14 */ + 20, /* 47: TRAP #15 */ + 4, /* 48: FP Branch or Set on Unknown Condition (unemulated) */ + 4, /* 49: FP Inexact Result (unemulated) */ + 4, /* 50: FP Divide by Zero (unemulated) */ + 4, /* 51: FP Underflow (unemulated) */ + 4, /* 52: FP Operand Error (unemulated) */ + 4, /* 53: FP Overflow (unemulated) */ + 4, /* 54: FP Signaling NAN (unemulated) */ + 4, /* 55: FP Unimplemented Data Type (unemulated) */ + 4, /* 56: MMU Configuration Error (unemulated) */ + 4, /* 57: MMU Illegal Operation Error (unemulated) */ + 4, /* 58: MMU Access Level Violation Error (unemulated) */ + 4, /* 59: RESERVED */ + 4, /* 60: RESERVED */ + 4, /* 61: RESERVED */ + 4, /* 62: RESERVED */ + 4, /* 63: RESERVED */ + /* 64-255: User Defined */ + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4 + }, +}; + +const UINT8 m68ki_ea_idx_cycle_table[64] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, /* ..01.000 no memory indirect, base NULL */ + 5, /* ..01..01 memory indirect, base NULL, outer NULL */ + 7, /* ..01..10 memory indirect, base NULL, outer 16 */ + 7, /* ..01..11 memory indirect, base NULL, outer 32 */ + 0, 5, 7, 7, 0, 5, 7, 7, 0, 5, 7, 7, + 2, /* ..10.000 no memory indirect, base 16 */ + 7, /* ..10..01 memory indirect, base 16, outer NULL */ + 9, /* ..10..10 memory indirect, base 16, outer 16 */ + 9, /* ..10..11 memory indirect, base 16, outer 32 */ + 0, 7, 9, 9, 0, 7, 9, 9, 0, 7, 9, 9, + 6, /* ..11.000 no memory indirect, base 32 */ + 11, /* ..11..01 memory indirect, base 32, outer NULL */ + 13, /* ..11..10 memory indirect, base 32, outer 16 */ + 13, /* ..11..11 memory indirect, base 32, outer 32 */ + 0, 11, 13, 13, 0, 11, 13, 13, 0, 11, 13, 13 +}; + + + +/*************************************************************************** + CPU STATE DESCRIPTION +***************************************************************************/ + +#define MASK_ALL (CPU_TYPE_000 | CPU_TYPE_008 | CPU_TYPE_010 | CPU_TYPE_EC020 | CPU_TYPE_020 | CPU_TYPE_EC030 | CPU_TYPE_030 | CPU_TYPE_EC040 | CPU_TYPE_040 | CPU_TYPE_FSCPU32 ) +#define MASK_24BIT_SPACE (CPU_TYPE_000 | CPU_TYPE_008 | CPU_TYPE_010 | CPU_TYPE_EC020) +#define MASK_32BIT_SPACE (CPU_TYPE_020 | CPU_TYPE_EC030 | CPU_TYPE_030 | CPU_TYPE_EC040 | CPU_TYPE_040 | CPU_TYPE_FSCPU32 ) +#define MASK_010_OR_LATER (CPU_TYPE_010 | CPU_TYPE_EC020 | CPU_TYPE_020 | CPU_TYPE_030 | CPU_TYPE_EC030 | CPU_TYPE_040 | CPU_TYPE_EC040 | CPU_TYPE_FSCPU32 ) +#define MASK_020_OR_LATER (CPU_TYPE_EC020 | CPU_TYPE_020 | CPU_TYPE_EC030 | CPU_TYPE_030 | CPU_TYPE_EC040 | CPU_TYPE_040 | CPU_TYPE_FSCPU32 ) +#define MASK_030_OR_LATER (CPU_TYPE_030 | CPU_TYPE_EC030 | CPU_TYPE_040 | CPU_TYPE_EC040) +#define MASK_040_OR_LATER (CPU_TYPE_040 | CPU_TYPE_EC040) + + + +/* ======================================================================== */ +/* ================================= API ================================== */ +/* ======================================================================== */ + +static void set_irq_line(m68000_base_device *m68k, int irqline, int state) +{ + UINT32 old_level = m68k->int_level; + UINT32 vstate = m68k->virq_state; + UINT32 blevel; + + if(state == ASSERT_LINE) + vstate |= 1 << irqline; + else + vstate &= ~(1 << irqline); + m68k->virq_state = vstate; + + for(blevel = 7; blevel > 0; blevel--) + if(vstate & (1 << blevel)) + break; + + m68k->int_level = blevel << 8; + + /* A transition from < 7 to 7 always interrupts (NMI) */ + /* Note: Level 7 can also level trigger like a normal IRQ */ + if(old_level != 0x0700 && m68k->int_level == 0x0700) + m68k->nmi_pending = TRUE; +} + +static void m68k_presave(m68000_base_device *m68k) +{ + m68k->save_sr = m68ki_get_sr(m68k); + m68k->save_stopped = (m68k->stopped & STOP_LEVEL_STOP) != 0; + m68k->save_halted = (m68k->stopped & STOP_LEVEL_HALT) != 0; +} + +static void m68k_postload(m68000_base_device *m68k) +{ + m68ki_set_sr_noint_nosp(m68k, m68k->save_sr); + //fprintf(stderr, "Reloaded, pc=%x\n", REG_PC(m68k)); + m68k->stopped = (m68k->save_stopped ? STOP_LEVEL_STOP : 0) | (m68k->save_halted ? STOP_LEVEL_HALT : 0); + m68ki_jump(m68k, REG_PC(m68k)); +} + +static void m68k_cause_bus_error(m68000_base_device *m68k) +{ + UINT32 sr; + + sr = m68ki_init_exception(m68k); + + m68k->run_mode = RUN_MODE_BERR_AERR_RESET; + + if (!CPU_TYPE_IS_010_PLUS(m68k->cpu_type)) + { + /* Note: This is implemented for 68000 only! */ + m68ki_stack_frame_buserr(m68k, sr); + } + else if (CPU_TYPE_IS_010(m68k->cpu_type)) + { + /* only the 68010 throws this unique type-1000 frame */ + m68ki_stack_frame_1000(m68k, REG_PPC(m68k), sr, EXCEPTION_BUS_ERROR); + } + else if (m68k->mmu_tmp_buserror_address == REG_PPC(m68k)) + { + m68ki_stack_frame_1010(m68k, sr, EXCEPTION_BUS_ERROR, REG_PPC(m68k), m68k->mmu_tmp_buserror_address); + } + else + { + m68ki_stack_frame_1011(m68k, sr, EXCEPTION_BUS_ERROR, REG_PPC(m68k), m68k->mmu_tmp_buserror_address); + } + + m68ki_jump_vector(m68k, EXCEPTION_BUS_ERROR); +} + +WRITE_LINE_MEMBER( m68000_base_device::write_irq1 ) +{ + set_input_line( M68K_IRQ_1, state ); +} + +WRITE_LINE_MEMBER( m68000_base_device::write_irq2 ) +{ + set_input_line( M68K_IRQ_2, state ); +} + +WRITE_LINE_MEMBER( m68000_base_device::write_irq3 ) +{ + set_input_line( M68K_IRQ_3, state ); +} + +WRITE_LINE_MEMBER( m68000_base_device::write_irq4 ) +{ + set_input_line( M68K_IRQ_4, state ); +} + +WRITE_LINE_MEMBER( m68000_base_device::write_irq5 ) +{ + set_input_line( M68K_IRQ_5, state ); +} + +WRITE_LINE_MEMBER( m68000_base_device::write_irq6 ) +{ + set_input_line( M68K_IRQ_6, state ); +} + +WRITE_LINE_MEMBER( m68000_base_device::write_irq7 ) +{ + set_input_line( M68K_IRQ_7, state ); +} + +bool m68000_base_device::memory_translate(address_spacenum space, int intention, offs_t &address) +{ + /* only applies to the program address space and only does something if the MMU's enabled */ + if (this) + { + /* 68040 needs to call the MMU even when disabled so transparent translation works */ + if ((space == AS_PROGRAM) && ((pmmu_enabled) || (CPU_TYPE_IS_040_PLUS(cpu_type)))) + { + // FIXME: mmu_tmp_sr will be overwritten in pmmu_translate_addr_with_fc + UINT16 temp_mmu_tmp_sr = mmu_tmp_sr; + int mode = s_flag ? FUNCTION_CODE_SUPERVISOR_PROGRAM : FUNCTION_CODE_USER_PROGRAM; +// UINT32 va=address; + + if (CPU_TYPE_IS_040_PLUS(cpu_type)) + { + address = pmmu_translate_addr_with_fc_040(this, address, mode, 1); + } + else + { + address = pmmu_translate_addr_with_fc(this, address, mode, 1); + } + + if ((mmu_tmp_sr & M68K_MMU_SR_INVALID) != 0) { +// logerror("cpu_translate_m68k failed with mmu_sr=%04x va=%08x pa=%08x\n",mmu_tmp_sr,va ,address); + address = 0; + } + + mmu_tmp_sr = temp_mmu_tmp_sr; + } + } + return TRUE; +} + + + + + + + + + +inline void m68000_base_device::cpu_execute(void) +{ + initial_cycles = remaining_cycles; + + /* eat up any reset cycles */ + if (reset_cycles) { + int rc = reset_cycles; + reset_cycles = 0; + remaining_cycles -= rc; + + if (remaining_cycles <= 0) return; + } + + /* See if interrupts came in */ + m68ki_check_interrupts(this); + + /* Make sure we're not stopped */ + if(!stopped) + { + /* Return point if we had an address error */ + check_address_error: + if (m_address_error==1) + { + m_address_error = 0; + try { + m68ki_exception_address_error(this); + } + catch(int error) + { + if (error==10) + { + m_address_error = 1; + REG_PPC(this) = REG_PC(this); + goto check_address_error; + } + else + throw; + } + if(stopped) + { + if (remaining_cycles > 0) + remaining_cycles = 0; + return; + } + } + + + /* Main loop. Keep going until we run out of clock cycles */ + while (remaining_cycles > 0) + { + /* Set tracing accodring to T1. (T0 is done inside instruction) */ + m68ki_trace_t1(this); /* auto-disable (see m68kcpu.h) */ + + /* Call external hook to peek at CPU */ + debugger_instruction_hook(this, REG_PC(this)); + + /* call external instruction hook (independent of debug mode) */ + if (!instruction_hook.isnull()) + instruction_hook(*program, REG_PC(this), 0xffffffff); + + /* Record previous program counter */ + REG_PPC(this) = REG_PC(this); + + try + { + if (!pmmu_enabled) + { + run_mode = RUN_MODE_NORMAL; + /* Read an instruction and call its handler */ + ir = m68ki_read_imm_16(this); + jump_table[ir](this); + remaining_cycles -= cyc_instruction[ir]; + } + else + { + run_mode = RUN_MODE_NORMAL; + // save CPU address registers values at start of instruction + int i; + UINT32 tmp_dar[16]; + + for (i = 15; i >= 0; i--) + { + tmp_dar[i] = REG_DA(this)[i]; + } + + mmu_tmp_buserror_occurred = 0; + + /* Read an instruction and call its handler */ + ir = m68ki_read_imm_16(this); + + if (!mmu_tmp_buserror_occurred) + { + jump_table[ir](this); + remaining_cycles -= cyc_instruction[ir]; + } + + if (mmu_tmp_buserror_occurred) + { + UINT32 sr; + + mmu_tmp_buserror_occurred = 0; + + // restore cpu address registers to value at start of instruction + for (i = 15; i >= 0; i--) + { + if (REG_DA(this)[i] != tmp_dar[i]) + { +// logerror("PMMU: pc=%08x sp=%08x bus error: fixed %s[%d]: %08x -> %08x\n", +// REG_PPC(this), REG_A(this)[7], i < 8 ? "D" : "A", i & 7, REG_DA(this)[i], tmp_dar[i]); + REG_DA(this)[i] = tmp_dar[i]; + } + } + + sr = m68ki_init_exception(this); + + run_mode = RUN_MODE_BERR_AERR_RESET; + + if (!CPU_TYPE_IS_020_PLUS(cpu_type)) + { + /* Note: This is implemented for 68000 only! */ + m68ki_stack_frame_buserr(this, sr); + } + else if(!CPU_TYPE_IS_040_PLUS(cpu_type)) { + if (mmu_tmp_buserror_address == REG_PPC(this)) + { + m68ki_stack_frame_1010(this, sr, EXCEPTION_BUS_ERROR, REG_PPC(this), mmu_tmp_buserror_address); + } + else + { + m68ki_stack_frame_1011(this, sr, EXCEPTION_BUS_ERROR, REG_PPC(this), mmu_tmp_buserror_address); + } + } + else + { + m68ki_stack_frame_0111(this, sr, EXCEPTION_BUS_ERROR, REG_PPC(this), mmu_tmp_buserror_address, true); + } + + m68ki_jump_vector(this, EXCEPTION_BUS_ERROR); + + // TODO: + /* Use up some clock cycles and undo the instruction's cycles */ + // remaining_cycles -= cyc_exception[EXCEPTION_BUS_ERROR] - cyc_instruction[ir]; + } + } + } + catch (int error) + { + if (error==10) + { + m_address_error = 1; + goto check_address_error; + } + else + throw; + } + + + /* Trace m68k_exception, if necessary */ + m68ki_exception_if_trace(this); /* auto-disable (see m68kcpu.h) */ + } + + /* set previous PC to current PC for the next entry into the loop */ + REG_PPC(this) = REG_PC(this); + } + else if (remaining_cycles > 0) + remaining_cycles = 0; +} + + + +void m68000_base_device::init_cpu_common(void) +{ + static UINT32 emulation_initialized = 0; + + //this = device;//deviceparam; + program = &space(AS_PROGRAM); + oprogram = has_space(AS_DECRYPTED_OPCODES) ? &space(AS_DECRYPTED_OPCODES) : program; + int_ack_callback = device_irq_acknowledge_delegate(FUNC(m68000_base_device::standard_irq_callback_member), this); + + /* disable all MMUs */ + has_pmmu = 0; + has_hmmu = 0; + pmmu_enabled = 0; + hmmu_enabled = 0; + + /* The first call to this function initializes the opcode handler jump table */ + if(!emulation_initialized) + { + m68ki_build_opcode_table(); + emulation_initialized = 1; + } + + /* Note, D covers A because the dar array is common, REG_A(m68k)=REG_D(m68k)+8 */ + save_item(NAME(REG_D(this))); + save_item(NAME(REG_PPC(this))); + save_item(NAME(REG_PC(this))); + save_item(NAME(REG_USP(this))); + save_item(NAME(REG_ISP(this))); + save_item(NAME(REG_MSP(this))); + save_item(NAME(vbr)); + save_item(NAME(sfc)); + save_item(NAME(dfc)); + save_item(NAME(cacr)); + save_item(NAME(caar)); + save_item(NAME(save_sr)); + save_item(NAME(int_level)); + save_item(NAME(save_stopped)); + save_item(NAME(save_halted)); + save_item(NAME(pref_addr)); + save_item(NAME(pref_data)); + save_item(NAME(reset_cycles)); + save_item(NAME(virq_state)); + save_item(NAME(nmi_pending)); + save_item(NAME(has_pmmu)); + save_item(NAME(has_hmmu)); + save_item(NAME(pmmu_enabled)); + save_item(NAME(hmmu_enabled)); + + save_item(NAME(mmu_crp_aptr)); + save_item(NAME(mmu_crp_limit)); + save_item(NAME(mmu_srp_aptr)); + save_item(NAME(mmu_srp_limit)); + save_item(NAME(mmu_urp_aptr)); + save_item(NAME(mmu_tc)); + save_item(NAME(mmu_sr)); + save_item(NAME(mmu_sr_040)); + save_item(NAME(mmu_atc_rr)); + save_item(NAME(mmu_tt0)); + save_item(NAME(mmu_tt1)); + save_item(NAME(mmu_itt0)); + save_item(NAME(mmu_itt1)); + save_item(NAME(mmu_dtt0)); + save_item(NAME(mmu_dtt1)); + save_item(NAME(mmu_acr0)); + save_item(NAME(mmu_acr1)); + save_item(NAME(mmu_acr2)); + save_item(NAME(mmu_acr3)); + save_item(NAME(mmu_last_page_entry)); + save_item(NAME(mmu_last_page_entry_addr)); + + for (int i=0; i 0) + remaining_cycles = 0; + + run_mode = RUN_MODE_BERR_AERR_RESET; + + /* Turn off tracing */ + t1_flag = t0_flag = 0; + m68ki_clear_trace(this); + /* Interrupt mask to level 7 */ + int_mask = 0x0700; + int_level = 0; + virq_state = 0; + /* Reset VBR */ + vbr = 0; + /* Go to supervisor mode */ + m68ki_set_sm_flag(this, SFLAG_SET | MFLAG_CLEAR); + + /* Invalidate the prefetch queue */ + /* Set to arbitrary number since our first fetch is from 0 */ + pref_addr = 0x1000; + + /* Read the initial stack pointer and program counter */ + m68ki_jump(this, 0); + REG_SP(this) = m68ki_read_imm_32(this); + REG_PC(this) = m68ki_read_imm_32(this); + m68ki_jump(this, REG_PC(this)); + + run_mode = RUN_MODE_NORMAL; + + reset_cycles = cyc_exception[EXCEPTION_RESET]; + + /* flush the MMU's cache */ + pmmu_atc_flush(this); + + if(CPU_TYPE_IS_EC020_PLUS(cpu_type)) + { + // clear instruction cache + m68ki_ic_clear(this); + } +} + + + +/************************************************************************** + * STATE IMPORT/EXPORT + **************************************************************************/ + +void m68000_base_device::state_import(const device_state_entry &entry) +{ + switch (entry.index()) + { + case M68K_SR: + case STATE_GENFLAGS: + m68ki_set_sr(this, iotemp); + break; + + case M68K_ISP: + if (s_flag && !m_flag) + REG_SP(this) = iotemp; + else + REG_ISP(this) = iotemp; + break; + + case M68K_USP: + if (!s_flag) + REG_SP(this) = iotemp; + else + REG_USP(this) = iotemp; + break; + + case M68K_MSP: + if (s_flag && m_flag) + REG_SP(this) = iotemp; + else + REG_MSP(this) = iotemp; + break; + + default: + fatalerror("CPU_IMPORT_STATE(this) called for unexpected value\n"); + } + +} + + + +void m68000_base_device::state_export(const device_state_entry &entry) +{ + switch (entry.index()) + { + case M68K_SR: + case STATE_GENFLAGS: + iotemp = m68ki_get_sr(this); + break; + + case M68K_ISP: + iotemp = (s_flag && !m_flag) ? REG_SP(this) : REG_ISP(this); + break; + + case M68K_USP: + iotemp = (!s_flag) ? REG_SP(this) : REG_USP(this); + break; + + case M68K_MSP: + iotemp = (s_flag && m_flag) ? REG_SP(this) : REG_MSP(this); + break; + + case M68K_FP0: + case M68K_FP1: + case M68K_FP2: + case M68K_FP3: + case M68K_FP4: + case M68K_FP5: + case M68K_FP6: + case M68K_FP7: + break; + + default: + fatalerror("CPU_EXPORT_STATE(this) called for unexpected value\n"); + } +} + +void m68000_base_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + UINT16 sr; + + switch (entry.index()) + { + case M68K_FP0: + strprintf(str,"%f", fx80_to_double(REG_FP(this)[0])); + break; + + case M68K_FP1: + strprintf(str,"%f", fx80_to_double(REG_FP(this)[1])); + break; + + case M68K_FP2: + strprintf(str,"%f", fx80_to_double(REG_FP(this)[2])); + break; + + case M68K_FP3: + strprintf(str,"%f", fx80_to_double(REG_FP(this)[3])); + break; + + case M68K_FP4: + strprintf(str,"%f", fx80_to_double(REG_FP(this)[4])); + break; + + case M68K_FP5: + strprintf(str,"%f", fx80_to_double(REG_FP(this)[5])); + break; + + case M68K_FP6: + strprintf(str,"%f", fx80_to_double(REG_FP(this)[6])); + break; + + case M68K_FP7: + strprintf(str,"%f", fx80_to_double(REG_FP(this)[7])); + break; + + case STATE_GENFLAGS: + sr = m68ki_get_sr(this); + strprintf(str,"%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c", + sr & 0x8000 ? 'T':'.', + sr & 0x4000 ? 't':'.', + sr & 0x2000 ? 'S':'.', + sr & 0x1000 ? 'M':'.', + sr & 0x0800 ? '?':'.', + sr & 0x0400 ? 'I':'.', + sr & 0x0200 ? 'I':'.', + sr & 0x0100 ? 'I':'.', + sr & 0x0080 ? '?':'.', + sr & 0x0040 ? '?':'.', + sr & 0x0020 ? '?':'.', + sr & 0x0010 ? 'X':'.', + sr & 0x0008 ? 'N':'.', + sr & 0x0004 ? 'Z':'.', + sr & 0x0002 ? 'V':'.', + sr & 0x0001 ? 'C':'.'); + break; + } + +} + + +/* global access */ + +void m68000_base_device::set_hmmu_enable(int enable) +{ + hmmu_enabled = enable; +} + +void m68000_base_device::set_instruction_hook(read32_delegate ihook) +{ + instruction_hook = ihook; +} + +/**************************************************************************** + * 8-bit data memory interface + ****************************************************************************/ + +UINT16 m68000_base_device::m68008_read_immediate_16(offs_t address) +{ + return (m_odirect->read_byte(address) << 8) | (m_odirect->read_byte(address + 1)); +} + +void m68000_base_device::init8(address_space &space, address_space &ospace) +{ + m_space = &space; + m_direct = &space.direct(); + m_ospace = &ospace; + m_odirect = &ospace.direct(); +// m_cpustate = this; + opcode_xor = 0; + + readimm16 = m68k_readimm16_delegate(FUNC(m68000_base_device::m68008_read_immediate_16), this); + read8 = m68k_read8_delegate(FUNC(address_space::read_byte), &space); + read16 = m68k_read16_delegate(FUNC(address_space::read_word), &space); + read32 = m68k_read32_delegate(FUNC(address_space::read_dword), &space); + write8 = m68k_write8_delegate(FUNC(address_space::write_byte), &space); + write16 = m68k_write16_delegate(FUNC(address_space::write_word), &space); + write32 = m68k_write32_delegate(FUNC(address_space::write_dword), &space); +} + +/**************************************************************************** + * 16-bit data memory interface + ****************************************************************************/ + +UINT16 m68000_base_device::read_immediate_16(offs_t address) +{ + return m_odirect->read_word((address), opcode_xor); +} + +UINT16 m68000_base_device::simple_read_immediate_16(offs_t address) +{ + return m_odirect->read_word(address); +} + +void m68000_base_device::m68000_write_byte(offs_t address, UINT8 data) +{ + static const UINT16 masks[] = {0xff00, 0x00ff}; + + m_space->write_word(address & ~1, data | (data << 8), masks[address & 1]); +} + +void m68000_base_device::init16(address_space &space, address_space &ospace) +{ + m_space = &space; + m_direct = &space.direct(); + m_ospace = &ospace; + m_odirect = &ospace.direct(); + + opcode_xor = 0; + + readimm16 = m68k_readimm16_delegate(FUNC(m68000_base_device::simple_read_immediate_16), this); + read8 = m68k_read8_delegate(FUNC(address_space::read_byte), &space); + read16 = m68k_read16_delegate(FUNC(address_space::read_word), &space); + read32 = m68k_read32_delegate(FUNC(address_space::read_dword), &space); + write8 = m68k_write8_delegate(FUNC(m68000_base_device::m68000_write_byte), this); + write16 = m68k_write16_delegate(FUNC(address_space::write_word), &space); + write32 = m68k_write32_delegate(FUNC(address_space::write_dword), &space); +} + + + + + +/**************************************************************************** + * 32-bit data memory interface + ****************************************************************************/ + +/* interface for 32-bit data bus (68EC020, 68020) */ +void m68000_base_device::init32(address_space &space, address_space &ospace) +{ + m_space = &space; + m_direct = &space.direct(); + m_ospace = &ospace; + m_odirect = &ospace.direct(); + opcode_xor = WORD_XOR_BE(0); + + readimm16 = m68k_readimm16_delegate(FUNC(m68000_base_device::read_immediate_16), this); + read8 = m68k_read8_delegate(FUNC(address_space::read_byte), &space); + read16 = m68k_read16_delegate(FUNC(address_space::read_word_unaligned), &space); + read32 = m68k_read32_delegate(FUNC(address_space::read_dword_unaligned), &space); + write8 = m68k_write8_delegate(FUNC(address_space::write_byte), &space); + write16 = m68k_write16_delegate(FUNC(address_space::write_word_unaligned), &space); + write32 = m68k_write32_delegate(FUNC(address_space::write_dword_unaligned), &space); +} + +/* interface for 32-bit data bus with PMMU (68EC020, 68020) */ +UINT8 m68000_base_device::read_byte_32_mmu(offs_t address) +{ + if (pmmu_enabled) + { + address = pmmu_translate_addr(this, address); + if (mmu_tmp_buserror_occurred) { + return ~0; + } + } + + return m_space->read_byte(address); +} + +void m68000_base_device::write_byte_32_mmu(offs_t address, UINT8 data) +{ + if (pmmu_enabled) + { + address = pmmu_translate_addr(this, address); + if (mmu_tmp_buserror_occurred) { + return; + } + } + + m_space->write_byte(address, data); +} + +UINT16 m68000_base_device::read_immediate_16_mmu(offs_t address) +{ + if (pmmu_enabled) + { + address = pmmu_translate_addr(this, address); + if (mmu_tmp_buserror_occurred) { + return ~0; + } + } + + return m_odirect->read_word((address), opcode_xor); +} + +/* potentially misaligned 16-bit reads with a 32-bit data bus (and 24-bit address bus) */ +UINT16 m68000_base_device::readword_d32_mmu(offs_t address) +{ + UINT16 result; + + if (pmmu_enabled) + { + UINT32 address0 = pmmu_translate_addr(this, address); + if (mmu_tmp_buserror_occurred) { + return ~0; + } else if (!(address & 1)) { + return m_space->read_word(address0); + } else { + UINT32 address1 = pmmu_translate_addr(this, address + 1); + if (mmu_tmp_buserror_occurred) { + return ~0; + } else { + result = m_space->read_byte(address0) << 8; + return result | m_space->read_byte(address1); + } + } + } + + if (!(address & 1)) + return m_space->read_word(address); + result = m_space->read_byte(address) << 8; + return result | m_space->read_byte(address + 1); +} + +/* potentially misaligned 16-bit writes with a 32-bit data bus (and 24-bit address bus) */ +void m68000_base_device::writeword_d32_mmu(offs_t address, UINT16 data) +{ + if (pmmu_enabled) + { + UINT32 address0 = pmmu_translate_addr(this, address); + if (mmu_tmp_buserror_occurred) { + return; + } else if (!(address & 1)) { + m_space->write_word(address0, data); + return; + } else { + UINT32 address1 = pmmu_translate_addr(this, address + 1); + if (mmu_tmp_buserror_occurred) { + return; + } else { + m_space->write_byte(address0, data >> 8); + m_space->write_byte(address1, data); + return; + } + } + } + + if (!(address & 1)) + { + m_space->write_word(address, data); + return; + } + m_space->write_byte(address, data >> 8); + m_space->write_byte(address + 1, data); +} + +/* potentially misaligned 32-bit reads with a 32-bit data bus (and 24-bit address bus) */ +UINT32 m68000_base_device::readlong_d32_mmu(offs_t address) +{ + UINT32 result; + + if (pmmu_enabled) + { + UINT32 address0 = pmmu_translate_addr(this, address); + if (mmu_tmp_buserror_occurred) { + return ~0; + } else if ((address +3) & 0xfc) { + // not at page boundary; use default code + address = address0; + } else if (!(address & 3)) { // 0 + return m_space->read_dword(address0); + } else { + UINT32 address2 = pmmu_translate_addr(this, address+2); + if (mmu_tmp_buserror_occurred) { + return ~0; + } else if (!(address & 1)) { // 2 + result = m_space->read_word(address0) << 16; + return result | m_space->read_word(address2); + } else { + UINT32 address1 = pmmu_translate_addr(this, address+1); + UINT32 address3 = pmmu_translate_addr(this, address+3); + if (mmu_tmp_buserror_occurred) { + return ~0; + } else { + result = m_space->read_byte(address0) << 24; + result |= m_space->read_word(address1) << 8; + return result | m_space->read_byte(address3); + } + } + } + } + + if (!(address & 3)) + return m_space->read_dword(address); + else if (!(address & 1)) + { + result = m_space->read_word(address) << 16; + return result | m_space->read_word(address + 2); + } + result = m_space->read_byte(address) << 24; + result |= m_space->read_word(address + 1) << 8; + return result | m_space->read_byte(address + 3); +} + +/* potentially misaligned 32-bit writes with a 32-bit data bus (and 24-bit address bus) */ +void m68000_base_device::writelong_d32_mmu(offs_t address, UINT32 data) +{ + if (pmmu_enabled) + { + UINT32 address0 = pmmu_translate_addr(this, address); + if (mmu_tmp_buserror_occurred) { + return; + } else if ((address +3) & 0xfc) { + // not at page boundary; use default code + address = address0; + } else if (!(address & 3)) { // 0 + m_space->write_dword(address0, data); + return; + } else { + UINT32 address2 = pmmu_translate_addr(this, address+2); + if (mmu_tmp_buserror_occurred) { + return; + } else if (!(address & 1)) { // 2 + m_space->write_word(address0, data >> 16); + m_space->write_word(address2, data); + return; + } else { + UINT32 address1 = pmmu_translate_addr(this, address+1); + UINT32 address3 = pmmu_translate_addr(this, address+3); + if (mmu_tmp_buserror_occurred) { + return; + } else { + m_space->write_byte(address0, data >> 24); + m_space->write_word(address1, data >> 8); + m_space->write_byte(address3, data); + return; + } + } + } + } + + if (!(address & 3)) + { + m_space->write_dword(address, data); + return; + } + else if (!(address & 1)) + { + m_space->write_word(address, data >> 16); + m_space->write_word(address + 2, data); + return; + } + m_space->write_byte(address, data >> 24); + m_space->write_word(address + 1, data >> 8); + m_space->write_byte(address + 3, data); +} + +void m68000_base_device::init32mmu(address_space &space, address_space &ospace) +{ + m_space = &space; + m_direct = &space.direct(); + m_ospace = &ospace; + m_odirect = &ospace.direct(); + opcode_xor = WORD_XOR_BE(0); + + readimm16 = m68k_readimm16_delegate(FUNC(m68000_base_device::read_immediate_16_mmu), this); + read8 = m68k_read8_delegate(FUNC(m68000_base_device::read_byte_32_mmu), this); + read16 = m68k_read16_delegate(FUNC(m68000_base_device::readword_d32_mmu), this); + read32 = m68k_read32_delegate(FUNC(m68000_base_device::readlong_d32_mmu), this); + write8 = m68k_write8_delegate(FUNC(m68000_base_device::write_byte_32_mmu), this); + write16 = m68k_write16_delegate(FUNC(m68000_base_device::writeword_d32_mmu), this); + write32 = m68k_write32_delegate(FUNC(m68000_base_device::writelong_d32_mmu), this); +} + + +/* interface for 32-bit data bus with PMMU (68EC020, 68020) */ +UINT8 m68000_base_device::read_byte_32_hmmu(offs_t address) +{ + if (hmmu_enabled) + { + address = hmmu_translate_addr(this, address); + } + + return m_space->read_byte(address); +} + +void m68000_base_device::write_byte_32_hmmu(offs_t address, UINT8 data) +{ + if (hmmu_enabled) + { + address = hmmu_translate_addr(this, address); + } + + m_space->write_byte(address, data); +} + +UINT16 m68000_base_device::read_immediate_16_hmmu(offs_t address) +{ + if (hmmu_enabled) + { + address = hmmu_translate_addr(this, address); + } + + return m_odirect->read_word((address), opcode_xor); +} + +/* potentially misaligned 16-bit reads with a 32-bit data bus (and 24-bit address bus) */ +UINT16 m68000_base_device::readword_d32_hmmu(offs_t address) +{ + UINT16 result; + + if (hmmu_enabled) + { + address = hmmu_translate_addr(this, address); + } + + if (!(address & 1)) + return m_space->read_word(address); + result = m_space->read_byte(address) << 8; + return result | m_space->read_byte(address + 1); +} + +/* potentially misaligned 16-bit writes with a 32-bit data bus (and 24-bit address bus) */ +void m68000_base_device::writeword_d32_hmmu(offs_t address, UINT16 data) +{ + if (hmmu_enabled) + { + address = hmmu_translate_addr(this, address); + } + + if (!(address & 1)) + { + m_space->write_word(address, data); + return; + } + m_space->write_byte(address, data >> 8); + m_space->write_byte(address + 1, data); +} + +/* potentially misaligned 32-bit reads with a 32-bit data bus (and 24-bit address bus) */ +UINT32 m68000_base_device::readlong_d32_hmmu(offs_t address) +{ + UINT32 result; + + if (hmmu_enabled) + { + address = hmmu_translate_addr(this, address); + } + + if (!(address & 3)) + return m_space->read_dword(address); + else if (!(address & 1)) + { + result = m_space->read_word(address) << 16; + return result | m_space->read_word(address + 2); + } + result = m_space->read_byte(address) << 24; + result |= m_space->read_word(address + 1) << 8; + return result | m_space->read_byte(address + 3); +} + +/* potentially misaligned 32-bit writes with a 32-bit data bus (and 24-bit address bus) */ +void m68000_base_device::writelong_d32_hmmu(offs_t address, UINT32 data) +{ + if (hmmu_enabled) + { + address = hmmu_translate_addr(this, address); + } + + if (!(address & 3)) + { + m_space->write_dword(address, data); + return; + } + else if (!(address & 1)) + { + m_space->write_word(address, data >> 16); + m_space->write_word(address + 2, data); + return; + } + m_space->write_byte(address, data >> 24); + m_space->write_word(address + 1, data >> 8); + m_space->write_byte(address + 3, data); +} + +void m68000_base_device::init32hmmu(address_space &space, address_space &ospace) +{ + m_space = &space; + m_direct = &space.direct(); + m_ospace = &ospace; + m_odirect = &ospace.direct(); + opcode_xor = WORD_XOR_BE(0); + + readimm16 = m68k_readimm16_delegate(FUNC(m68000_base_device::read_immediate_16_hmmu), this); + read8 = m68k_read8_delegate(FUNC(m68000_base_device::read_byte_32_hmmu), this); + read16 = m68k_read16_delegate(FUNC(m68000_base_device::readword_d32_hmmu), this); + read32 = m68k_read32_delegate(FUNC(m68000_base_device::readlong_d32_hmmu), this); + write8 = m68k_write8_delegate(FUNC(m68000_base_device::write_byte_32_hmmu), this); + write16 = m68k_write16_delegate(FUNC(m68000_base_device::writeword_d32_hmmu), this); + write32 = m68k_write32_delegate(FUNC(m68000_base_device::writelong_d32_hmmu), this); +} + +void m68000_base_device::set_reset_callback(write_line_delegate callback) +{ + reset_instr_callback = callback; +} + +// fault_addr = address to indicate fault at +// rw = 0 for read, 1 for write +// fc = 3-bit function code of access (usually you'd just put what m68k_get_fc() returns here) +void m68000_base_device::set_buserror_details(UINT32 fault_addr, UINT8 rw, UINT8 fc) +{ + aerr_address = fault_addr; + aerr_write_mode = rw; + aerr_fc = fc; +} + +void m68000_base_device::set_cmpild_callback(write32_delegate callback) +{ + cmpild_instr_callback = callback; +} + +void m68000_base_device::set_rte_callback(write_line_delegate callback) +{ + rte_instr_callback = callback; +} + +void m68000_base_device::set_tas_write_callback(write8_delegate callback) +{ + tas_write_callback = callback; +} + +UINT16 m68000_base_device::get_fc() +{ + return mmu_tmp_fc; +} + +/**************************************************************************** + * State definition + ****************************************************************************/ + +void m68000_base_device::define_state(void) +{ + UINT32 addrmask = (cpu_type & MASK_24BIT_SPACE) ? 0xffffff : 0xffffffff; + + state_add(M68K_PC, "PC", pc).mask(addrmask); + state_add(STATE_GENPC, "GENPC", pc).mask(addrmask).noshow(); + state_add(STATE_GENPCBASE, "GENPCBASE", ppc).mask(addrmask).noshow(); + state_add(M68K_SP, "SP", dar[15]); + state_add(STATE_GENSP, "GENSP", dar[15]).noshow(); + state_add(STATE_GENFLAGS, "GENFLAGS", iotemp).noshow().callimport().callexport().formatstr("%16s"); + state_add(M68K_ISP, "ISP", iotemp).callimport().callexport(); + state_add(M68K_USP, "USP", iotemp).callimport().callexport(); + if (cpu_type & MASK_020_OR_LATER) + state_add(M68K_MSP, "MSP", iotemp).callimport().callexport(); + state_add(M68K_ISP, "ISP", iotemp).callimport().callexport(); + + std::string tempstr; + for (int regnum = 0; regnum < 8; regnum++) { + strprintf(tempstr,"D%d", regnum); + state_add(M68K_D0 + regnum, tempstr.c_str(), dar[regnum]); + } + for (int regnum = 0; regnum < 8; regnum++) { + strprintf(tempstr,"A%d", regnum); + state_add(M68K_A0 + regnum, tempstr.c_str(), dar[8 + regnum]); + } + + state_add(M68K_PREF_ADDR, "PREF_ADDR", pref_addr).mask(addrmask); + state_add(M68K_PREF_DATA, "PREF_DATA", pref_data); + + if (cpu_type & MASK_010_OR_LATER) + { + state_add(M68K_SFC, "SFC", sfc).mask(0x7); + state_add(M68K_DFC, "DFC", dfc).mask(0x7); + state_add(M68K_VBR, "VBR", vbr); + } + + if (cpu_type & MASK_020_OR_LATER) + { + state_add(M68K_CACR, "CACR", cacr); + state_add(M68K_CAAR, "CAAR", caar); + } + + if (cpu_type & MASK_030_OR_LATER) + { + for (int regnum = 0; regnum < 8; regnum++) { + strprintf(tempstr,"FP%d", regnum); + state_add(M68K_FP0 + regnum, tempstr.c_str(), iotemp).callimport().callexport().formatstr("%10s"); + } + state_add(M68K_FPSR, "FPSR", fpsr); + state_add(M68K_FPCR, "FPCR", fpcr); + } +} + + + +/**************** + CPU Inits +****************/ + + +void m68000_base_device::init_cpu_m68000(void) +{ + init_cpu_common(); + + cpu_type = CPU_TYPE_000; +// dasm_type = M68K_CPU_TYPE_68000; + + init16(*program, *oprogram); + sr_mask = 0xa71f; /* T1 -- S -- -- I2 I1 I0 -- -- -- X N Z V C */ + jump_table = m68ki_instruction_jump_table[0]; + cyc_instruction = m68ki_cycles[0]; + cyc_exception = m68ki_exception_cycle_table[0]; + cyc_bcc_notake_b = -2; + cyc_bcc_notake_w = 2; + cyc_dbcc_f_noexp = -2; + cyc_dbcc_f_exp = 2; + cyc_scc_r_true = 2; + cyc_movem_w = 2; + cyc_movem_l = 3; + cyc_shift = 1; + cyc_reset = 132; + has_pmmu = 0; + has_hmmu = 0; + has_fpu = 0; + + define_state(); + +} + + +void m68000_base_device::init_cpu_m68008(void) +{ + init_cpu_common(); + + cpu_type = CPU_TYPE_008; +// dasm_type = M68K_CPU_TYPE_68008; + + init8(*program, *oprogram); + sr_mask = 0xa71f; /* T1 -- S -- -- I2 I1 I0 -- -- -- X N Z V C */ + jump_table = m68ki_instruction_jump_table[0]; + cyc_instruction = m68ki_cycles[0]; + cyc_exception = m68ki_exception_cycle_table[0]; + cyc_bcc_notake_b = -2; + cyc_bcc_notake_w = 2; + cyc_dbcc_f_noexp = -2; + cyc_dbcc_f_exp = 2; + cyc_scc_r_true = 2; + cyc_movem_w = 2; + cyc_movem_l = 3; + cyc_shift = 1; + cyc_reset = 132; + has_pmmu = 0; + has_fpu = 0; + + define_state(); + +} + + +void m68000_base_device::init_cpu_m68010(void) +{ + init_cpu_common(); + cpu_type = CPU_TYPE_010; +// dasm_type = M68K_CPU_TYPE_68010; + + init16(*program, *oprogram); + sr_mask = 0xa71f; /* T1 -- S -- -- I2 I1 I0 -- -- -- X N Z V C */ + jump_table = m68ki_instruction_jump_table[1]; + cyc_instruction = m68ki_cycles[1]; + cyc_exception = m68ki_exception_cycle_table[1]; + cyc_bcc_notake_b = -4; + cyc_bcc_notake_w = 0; + cyc_dbcc_f_noexp = 0; + cyc_dbcc_f_exp = 6; + cyc_scc_r_true = 0; + cyc_movem_w = 2; + cyc_movem_l = 3; + cyc_shift = 1; + cyc_reset = 130; + has_pmmu = 0; + has_fpu = 0; + + define_state(); +} + + +void m68000_base_device::init_cpu_m68020(void) +{ + init_cpu_common(); + cpu_type = CPU_TYPE_020; +// dasm_type = M68K_CPU_TYPE_68020; + + init32(*program, *oprogram); + sr_mask = 0xf71f; /* T1 T0 S M -- I2 I1 I0 -- -- -- X N Z V C */ + jump_table = m68ki_instruction_jump_table[2]; + cyc_instruction = m68ki_cycles[2]; + cyc_exception = m68ki_exception_cycle_table[2]; + cyc_bcc_notake_b = -2; + cyc_bcc_notake_w = 0; + cyc_dbcc_f_noexp = 0; + cyc_dbcc_f_exp = 4; + cyc_scc_r_true = 0; + cyc_movem_w = 2; + cyc_movem_l = 2; + cyc_shift = 0; + cyc_reset = 518; + + define_state(); +} + +void m68000_base_device::init_cpu_m68020fpu(void) +{ + init_cpu_m68020(); + + has_fpu = 1; +} + +void m68000_base_device::init_cpu_m68020pmmu(void) +{ + init_cpu_m68020(); + + has_pmmu = 1; + has_fpu = 1; + + + init32mmu(*program, *oprogram); +} + + + +void m68000_base_device::init_cpu_m68020hmmu(void) +{ + init_cpu_m68020(); + + has_hmmu = 1; + has_fpu = 1; + + + init32hmmu(*program, *oprogram); +} + +void m68000_base_device::init_cpu_m68ec020(void) +{ + init_cpu_common(); + + cpu_type = CPU_TYPE_EC020; +// dasm_type = M68K_CPU_TYPE_68EC020; + + + init32(*program, *oprogram); + sr_mask = 0xf71f; /* T1 T0 S M -- I2 I1 I0 -- -- -- X N Z V C */ + jump_table = m68ki_instruction_jump_table[2]; + cyc_instruction = m68ki_cycles[2]; + cyc_exception = m68ki_exception_cycle_table[2]; + cyc_bcc_notake_b = -2; + cyc_bcc_notake_w = 0; + cyc_dbcc_f_noexp = 0; + cyc_dbcc_f_exp = 4; + cyc_scc_r_true = 0; + cyc_movem_w = 2; + cyc_movem_l = 2; + cyc_shift = 0; + cyc_reset = 518; + has_pmmu = 0; + has_fpu = 0; + + define_state(); +} + + +void m68000_base_device::init_cpu_m68030(void) +{ + init_cpu_common(); + + cpu_type = CPU_TYPE_030; +// dasm_type = M68K_CPU_TYPE_68030; + + + init32mmu(*program, *oprogram); + sr_mask = 0xf71f; /* T1 T0 S M -- I2 I1 I0 -- -- -- X N Z V C */ + jump_table = m68ki_instruction_jump_table[3]; + cyc_instruction = m68ki_cycles[3]; + cyc_exception = m68ki_exception_cycle_table[3]; + cyc_bcc_notake_b = -2; + cyc_bcc_notake_w = 0; + cyc_dbcc_f_noexp = 0; + cyc_dbcc_f_exp = 4; + cyc_scc_r_true = 0; + cyc_movem_w = 2; + cyc_movem_l = 2; + cyc_shift = 0; + cyc_reset = 518; + has_pmmu = 1; + has_fpu = 1; + + define_state(); +} + + + +void m68000_base_device::init_cpu_m68ec030(void) +{ + init_cpu_common(); + + cpu_type = CPU_TYPE_EC030; +// dasm_type = M68K_CPU_TYPE_68EC030; + + + init32(*program, *oprogram); + sr_mask = 0xf71f; /* T1 T0 S M -- I2 I1 I0 -- -- -- X N Z V C */ + jump_table = m68ki_instruction_jump_table[3]; + cyc_instruction = m68ki_cycles[3]; + cyc_exception = m68ki_exception_cycle_table[3]; + cyc_bcc_notake_b = -2; + cyc_bcc_notake_w = 0; + cyc_dbcc_f_noexp = 0; + cyc_dbcc_f_exp = 4; + cyc_scc_r_true = 0; + cyc_movem_w = 2; + cyc_movem_l = 2; + cyc_shift = 0; + cyc_reset = 518; + has_pmmu = 0; /* EC030 lacks the PMMU and is effectively a die-shrink 68020 */ + has_fpu = 1; + + define_state(); +} + + + +void m68000_base_device::init_cpu_m68040(void) +{ + init_cpu_common(); + + cpu_type = CPU_TYPE_040; +// dasm_type = M68K_CPU_TYPE_68040; + + + init32mmu(*program, *oprogram); + sr_mask = 0xf71f; /* T1 T0 S M -- I2 I1 I0 -- -- -- X N Z V C */ + jump_table = m68ki_instruction_jump_table[4]; + cyc_instruction = m68ki_cycles[4]; + cyc_exception = m68ki_exception_cycle_table[4]; + cyc_bcc_notake_b = -2; + cyc_bcc_notake_w = 0; + cyc_dbcc_f_noexp = 0; + cyc_dbcc_f_exp = 4; + cyc_scc_r_true = 0; + cyc_movem_w = 2; + cyc_movem_l = 2; + cyc_shift = 0; + cyc_reset = 518; + has_pmmu = 1; + has_fpu = 1; + + define_state(); +} + + +void m68000_base_device::init_cpu_m68ec040(void) +{ + init_cpu_common(); + + cpu_type = CPU_TYPE_EC040; +// dasm_type = M68K_CPU_TYPE_68EC040; + + + init32(*program, *oprogram); + sr_mask = 0xf71f; /* T1 T0 S M -- I2 I1 I0 -- -- -- X N Z V C */ + jump_table = m68ki_instruction_jump_table[4]; + cyc_instruction = m68ki_cycles[4]; + cyc_exception = m68ki_exception_cycle_table[4]; + cyc_bcc_notake_b = -2; + cyc_bcc_notake_w = 0; + cyc_dbcc_f_noexp = 0; + cyc_dbcc_f_exp = 4; + cyc_scc_r_true = 0; + cyc_movem_w = 2; + cyc_movem_l = 2; + cyc_shift = 0; + cyc_reset = 518; + has_pmmu = 0; + has_fpu = 0; + + define_state(); +} + + +void m68000_base_device::init_cpu_m68lc040(void) +{ + init_cpu_common(); + + cpu_type = CPU_TYPE_LC040; +// dasm_type = M68K_CPU_TYPE_68LC040; + + + init32mmu(*program, *oprogram); + sr_mask = 0xf71f; /* T1 T0 S M -- I2 I1 I0 -- -- -- X N Z V C */ + jump_table = m68ki_instruction_jump_table[4]; + cyc_instruction = m68ki_cycles[4]; + cyc_exception = m68ki_exception_cycle_table[4]; + cyc_bcc_notake_b = -2; + cyc_bcc_notake_w = 0; + cyc_dbcc_f_noexp = 0; + cyc_dbcc_f_exp = 4; + cyc_scc_r_true = 0; + cyc_movem_w = 2; + cyc_movem_l = 2; + cyc_shift = 0; + cyc_reset = 518; + has_pmmu = 1; + has_fpu = 0; + + define_state(); +} + + +void m68000_base_device::init_cpu_scc68070(void) +{ + init_cpu_m68010(); + cpu_type = CPU_TYPE_SCC070; +} + + +void m68000_base_device::init_cpu_fscpu32(void) +{ + init_cpu_common(); + + cpu_type = CPU_TYPE_FSCPU32; +// dasm_type = M68K_CPU_TYPE_FSCPU32; + + + init32(*program, *oprogram); + sr_mask = 0xf71f; /* T1 T0 S M -- I2 I1 I0 -- -- -- X N Z V C */ + jump_table = m68ki_instruction_jump_table[5]; + cyc_instruction = m68ki_cycles[5]; + cyc_exception = m68ki_exception_cycle_table[5]; + cyc_bcc_notake_b = -2; + cyc_bcc_notake_w = 0; + cyc_dbcc_f_noexp = 0; + cyc_dbcc_f_exp = 4; + cyc_scc_r_true = 0; + cyc_movem_w = 2; + cyc_movem_l = 2; + cyc_shift = 0; + cyc_reset = 518; + + define_state(); +} + + + +void m68000_base_device::init_cpu_coldfire(void) +{ + init_cpu_common(); + + cpu_type = CPU_TYPE_COLDFIRE; +// dasm_type = M68K_CPU_TYPE_COLDFIRE; + + + init32(*program, *oprogram); + sr_mask = 0xf71f; /* T1 T0 S M -- I2 I1 I0 -- -- -- X N Z V C */ + jump_table = m68ki_instruction_jump_table[6]; + cyc_instruction = m68ki_cycles[6]; + cyc_exception = m68ki_exception_cycle_table[6]; + cyc_bcc_notake_b = -2; + cyc_bcc_notake_w = 0; + cyc_dbcc_f_noexp = 0; + cyc_dbcc_f_exp = 4; + cyc_scc_r_true = 0; + cyc_movem_w = 2; + cyc_movem_l = 2; + cyc_shift = 0; + cyc_reset = 518; + + define_state(); +} + + + + + + +/* + case CPUINFO_INT_CLOCK_MULTIPLIER: info->i = 1; break; + case CPUINFO_INT_CLOCK_DIVIDER: info->i = 1; break; + + case CPUINFO_INT_ADDRBUS_WIDTH + AS_PROGRAM: info->i = 24; break; + case CPUINFO_INT_ADDRBUS_SHIFT + AS_PROGRAM: info->i = 0; break; + + case CPUINFO_INT_INPUT_STATE + 0: info->i = 0; // there is no level 0 + case CPUINFO_INT_INPUT_STATE + 1: info->i = (m68k->virq_state >> 1) & 1; break; + case CPUINFO_INT_INPUT_STATE + 2: info->i = (m68k->virq_state >> 2) & 1; break; + case CPUINFO_INT_INPUT_STATE + 3: info->i = (m68k->virq_state >> 3) & 1; break; + case CPUINFO_INT_INPUT_STATE + 4: info->i = (m68k->virq_state >> 4) & 1; break; + case CPUINFO_INT_INPUT_STATE + 5: info->i = (m68k->virq_state >> 5) & 1; break; + case CPUINFO_INT_INPUT_STATE + 6: info->i = (m68k->virq_state >> 6) & 1; break; + case CPUINFO_INT_INPUT_STATE + 7: info->i = (m68k->virq_state >> 7) & 1; break; + + case CPUINFO_STR_FAMILY: strcpy(info->s, "Motorola 68K"); break; + case CPUINFO_STR_VERSION: strcpy(info->s, "4.95"); break; + case CPUINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break; + case CPUINFO_STR_CREDITS: strcpy(info->s, "Copyright Karl Stenerud. All rights reserved. (2.1 fixes HJB, FPU+MMU by RB+HO+OG)"); break; + + +*/ + + + + + +CPU_DISASSEMBLE( dasm_m68000 ) +{ + return m68k_disassemble_raw(buffer, pc, oprom, opram, M68K_CPU_TYPE_68000); +} + +CPU_DISASSEMBLE( dasm_m68008 ) +{ + return m68k_disassemble_raw(buffer, pc, oprom, opram, M68K_CPU_TYPE_68008); +} + +CPU_DISASSEMBLE( dasm_m68010 ) +{ + return m68k_disassemble_raw(buffer, pc, oprom, opram, M68K_CPU_TYPE_68010); +} + +CPU_DISASSEMBLE( dasm_m68020 ) +{ + return m68k_disassemble_raw(buffer, pc, oprom, opram, M68K_CPU_TYPE_68020); +} + +CPU_DISASSEMBLE( dasm_m68030 ) +{ + return m68k_disassemble_raw(buffer, pc, oprom, opram, M68K_CPU_TYPE_68030); +} + +CPU_DISASSEMBLE( dasm_m68ec030 ) +{ + return m68k_disassemble_raw(buffer, pc, oprom, opram, M68K_CPU_TYPE_68EC030); +} + +CPU_DISASSEMBLE( dasm_m68040 ) +{ + return m68k_disassemble_raw(buffer, pc, oprom, opram, M68K_CPU_TYPE_68040); +} + +CPU_DISASSEMBLE( dasm_m68ec040 ) +{ + return m68k_disassemble_raw(buffer, pc, oprom, opram, M68K_CPU_TYPE_68EC040); +} + +CPU_DISASSEMBLE( dasm_m68lc040 ) +{ + return m68k_disassemble_raw(buffer, pc, oprom, opram, M68K_CPU_TYPE_68LC040); +} + +CPU_DISASSEMBLE( dasm_fscpu32 ) +{ + return m68k_disassemble_raw(buffer, pc, oprom, opram, M68K_CPU_TYPE_FSCPU32); +} + +CPU_DISASSEMBLE( dasm_coldfire ) +{ + return m68k_disassemble_raw(buffer, pc, oprom, opram, M68K_CPU_TYPE_COLDFIRE); +} + +offs_t m68000_base_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) { return CPU_DISASSEMBLE_NAME(dasm_m68000)(this, buffer, pc, oprom, opram, options); } +offs_t m68000_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) { return CPU_DISASSEMBLE_NAME(dasm_m68000)(this, buffer, pc, oprom, opram, options); } +offs_t m68301_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) { return CPU_DISASSEMBLE_NAME(dasm_m68000)(this, buffer, pc, oprom, opram, options); } +offs_t m68008_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) { return CPU_DISASSEMBLE_NAME(dasm_m68008)(this, buffer, pc, oprom, opram, options); } +offs_t m68008plcc_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) { return CPU_DISASSEMBLE_NAME(dasm_m68008)(this, buffer, pc, oprom, opram, options); } +offs_t m68010_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) { return CPU_DISASSEMBLE_NAME(dasm_m68010)(this, buffer, pc, oprom, opram, options); } +offs_t m68ec020_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) { return CPU_DISASSEMBLE_NAME(dasm_m68020)(this, buffer, pc, oprom, opram, options); } +offs_t m68020_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) { return CPU_DISASSEMBLE_NAME(dasm_m68020)(this, buffer, pc, oprom, opram, options); } +offs_t m68020fpu_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) { return CPU_DISASSEMBLE_NAME(dasm_m68020)(this, buffer, pc, oprom, opram, options); } +offs_t m68020pmmu_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) { return CPU_DISASSEMBLE_NAME(dasm_m68020)(this, buffer, pc, oprom, opram, options); } +offs_t m68020hmmu_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) { return CPU_DISASSEMBLE_NAME(dasm_m68020)(this, buffer, pc, oprom, opram, options); } +offs_t m68ec030_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) { return CPU_DISASSEMBLE_NAME(dasm_m68ec030)(this, buffer, pc, oprom, opram, options); } +offs_t m68030_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) { return CPU_DISASSEMBLE_NAME(dasm_m68030)(this, buffer, pc, oprom, opram, options); } +offs_t m68ec040_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) { return CPU_DISASSEMBLE_NAME(dasm_m68ec040)(this, buffer, pc, oprom, opram, options); } +offs_t m68lc040_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) { return CPU_DISASSEMBLE_NAME(dasm_m68lc040)(this, buffer, pc, oprom, opram, options); } +offs_t m68040_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) { return CPU_DISASSEMBLE_NAME(dasm_m68040)(this, buffer, pc, oprom, opram, options); } +offs_t scc68070_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) { return CPU_DISASSEMBLE_NAME(dasm_m68000)(this, buffer, pc, oprom, opram, options); } +offs_t fscpu32_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) { return CPU_DISASSEMBLE_NAME(dasm_fscpu32)(this, buffer, pc, oprom, opram, options); } +offs_t mcf5206e_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) { return CPU_DISASSEMBLE_NAME(dasm_coldfire)(this, buffer, pc, oprom, opram, options); } + + +/* Service an interrupt request and start exception processing */ +void m68000_base_device::m68ki_exception_interrupt(m68000_base_device *m68k, UINT32 int_level) +{ + UINT32 vector; + UINT32 sr; + UINT32 new_pc; + + if(CPU_TYPE_IS_000(cpu_type)) + { + instr_mode = INSTRUCTION_NO; + } + + /* Turn off the stopped state */ + stopped &= ~STOP_LEVEL_STOP; + + /* If we are halted, don't do anything */ + if(stopped) + return; + + /* Acknowledge the interrupt */ + vector = int_ack_callback(*this, int_level); + + /* Get the interrupt vector */ + if(vector == M68K_INT_ACK_AUTOVECTOR) + /* Use the autovectors. This is the most commonly used implementation */ + vector = EXCEPTION_INTERRUPT_AUTOVECTOR+int_level; + else if(vector == M68K_INT_ACK_SPURIOUS) + /* Called if no devices respond to the interrupt acknowledge */ + vector = EXCEPTION_SPURIOUS_INTERRUPT; + else if(vector > 255) + return; + + /* Start exception processing */ + sr = m68ki_init_exception(m68k); + + /* Set the interrupt mask to the level of the one being serviced */ + int_mask = int_level<<8; + + /* Get the new PC */ + new_pc = m68ki_read_data_32(this, (vector<<2) + vbr); + + /* If vector is uninitialized, call the uninitialized interrupt vector */ + if(new_pc == 0) + new_pc = m68ki_read_data_32(this, (EXCEPTION_UNINITIALIZED_INTERRUPT<<2) + vbr); + + /* Generate a stack frame */ + m68ki_stack_frame_0000(this, REG_PC(m68k), sr, vector); + if(m_flag && CPU_TYPE_IS_EC020_PLUS(cpu_type)) + { + /* Create throwaway frame */ + m68ki_set_sm_flag(this, s_flag); /* clear M */ + sr |= 0x2000; /* Same as SR in master stack frame except S is forced high */ + m68ki_stack_frame_0001(this, REG_PC(m68k), sr, vector); + } + + m68ki_jump(this, new_pc); + + /* Defer cycle counting until later */ + remaining_cycles -= cyc_exception[vector]; +} + + +const device_type M68K = &device_creator; + +//------------------------------------------------- +// h6280_device - constructor +//------------------------------------------------- + +m68000_base_device::m68000_base_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : cpu_device(mconfig, M68K, "M68K", tag, owner, clock, "m68k", __FILE__), + m_program_config("program", ENDIANNESS_BIG, 16, 24), + m_oprogram_config("decrypted_opcodes", ENDIANNESS_BIG, 16, 24) +{ + clear_all(); +} + + + + +m68000_base_device::m68000_base_device(const machine_config &mconfig, const char *name, const char *tag, device_t *owner, UINT32 clock, + const device_type type, UINT32 prg_data_width, UINT32 prg_address_bits, address_map_constructor internal_map, const char *shortname, const char *source) + : cpu_device(mconfig, type, name, tag, owner, clock, shortname, source), + m_program_config("program", ENDIANNESS_BIG, prg_data_width, prg_address_bits, 0, internal_map), + m_oprogram_config("decrypted_opcodes", ENDIANNESS_BIG, prg_data_width, prg_address_bits, 0, internal_map) +{ + clear_all(); +} + + +m68000_base_device::m68000_base_device(const machine_config &mconfig, const char *name, const char *tag, device_t *owner, UINT32 clock, + const device_type type, UINT32 prg_data_width, UINT32 prg_address_bits, const char *shortname, const char *source) + : cpu_device(mconfig, type, name, tag, owner, clock, shortname, source), + m_program_config("program", ENDIANNESS_BIG, prg_data_width, prg_address_bits), + m_oprogram_config("decrypted_opcodes", ENDIANNESS_BIG, prg_data_width, prg_address_bits) +{ + clear_all(); +} + +void m68000_base_device::clear_all() +{ + cpu_type= 0; +// dasm_type= 0; + for (int i=0;i<16;i++) + dar[i]= 0; + ppc= 0; + pc= 0; + for (int i=0;i<7;i++) + sp[i]= 0; + vbr= 0; + sfc= 0; + dfc= 0; + cacr= 0; + caar= 0; + ir= 0; +// for (int i=0;i<8;i++) +// fpr[i]= 0; + fpiar= 0; + fpsr= 0; + fpcr= 0; + t1_flag= 0; + t0_flag= 0; + s_flag= 0; + m_flag= 0; + x_flag= 0; + n_flag= 0; + not_z_flag= 0; + v_flag= 0; + c_flag= 0; + int_mask= 0; + int_level= 0; + stopped= 0; + pref_addr= 0; + pref_data= 0; + sr_mask= 0; + instr_mode= 0; + run_mode= 0; + has_pmmu= 0; + has_hmmu= 0; + pmmu_enabled= 0; + hmmu_enabled= 0; + has_fpu= 0; + fpu_just_reset= 0; + + cyc_bcc_notake_b = 0; + cyc_bcc_notake_w = 0; + cyc_dbcc_f_noexp = 0; + cyc_dbcc_f_exp = 0; + cyc_scc_r_true = 0; + cyc_movem_w = 0; + cyc_movem_l = 0; + cyc_shift = 0; + cyc_reset = 0; + + initial_cycles = 0; + remaining_cycles = 0; + reset_cycles = 0; + tracing = 0; + + m_address_error = 0; + + aerr_address = 0; + aerr_write_mode = 0; + aerr_fc = 0; + + virq_state = 0; + nmi_pending = 0; + + cyc_instruction = 0; + cyc_exception = 0; + + int_ack_callback = device_irq_acknowledge_delegate(); + program = 0; + + opcode_xor = 0; +// readimm16 = 0; +// read8 = 0; +// read16 = 0; +// read32 = 0; +// write8 = 0; +// write16 = 0; +// write32 = 0; + + m_space = 0; + m_direct = 0; + + + iotemp = 0; + + save_sr = 0; + save_stopped = 0; + save_halted = 0; + + + mmu_crp_aptr = mmu_crp_limit = 0; + mmu_srp_aptr = mmu_srp_limit = 0; + mmu_urp_aptr = 0; + mmu_tc = 0; + mmu_sr = 0; + mmu_sr_040 = 0; + + for (int i=0; i; +const device_type M68301 = &device_creator; +const device_type M68008 = &device_creator; +const device_type M68008PLCC = &device_creator; +const device_type M68010 = &device_creator; +const device_type M68EC020 = &device_creator; +const device_type M68020 = &device_creator; +const device_type M68020FPU = &device_creator; +const device_type M68020PMMU = &device_creator; +const device_type M68020HMMU = &device_creator; +const device_type M68EC030 = &device_creator; +const device_type M68030 = &device_creator; +const device_type M68EC040 = &device_creator; +const device_type M68LC040 = &device_creator; +const device_type M68040 = &device_creator; +const device_type SCC68070 = &device_creator; +const device_type FSCPU32 = &device_creator; +const device_type MCF5206E = &device_creator; + +m68000_device::m68000_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : m68000_base_device(mconfig, "M68000", tag, owner, clock, M68000, 16,24, "m68000", __FILE__) +{ +} + +m68000_device::m68000_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : m68000_base_device(mconfig, "M68000", tag, owner, clock, M68000, 16,24, shortname, source) +{ +} + +void m68000_device::device_start() +{ + init_cpu_m68000(); +} + +m68000_device::m68000_device(const machine_config &mconfig, const char *name, const char *tag, device_t *owner, UINT32 clock, + const device_type type, UINT32 prg_data_width, UINT32 prg_address_bits, address_map_constructor internal_map, const char *shortname, const char *source) + : m68000_base_device(mconfig, name, tag, owner, clock, type, prg_data_width, prg_address_bits, internal_map, shortname, source) +{ +} + + + + + +m68301_device::m68301_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : m68000_base_device(mconfig, "M68301", tag, owner, clock, M68301, 16,24, "m68301", __FILE__) +{ +} + + +void m68301_device::device_start() +{ + init_cpu_m68000(); +} + + + + + + +/* m68008_device */ + +m68008_device::m68008_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : m68000_base_device(mconfig, "M68008", tag, owner, clock, M68008, 8,20, "m68008", __FILE__) +{ +} + +void m68008_device::device_start() +{ + init_cpu_m68008(); +} + + +m68008plcc_device::m68008plcc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : m68000_base_device(mconfig, "M68008PLCC", tag, owner, clock, M68008, 8,22, "m68008plcc", __FILE__) +{ +} + +void m68008plcc_device::device_start() +{ + init_cpu_m68008(); +} + + + +m68010_device::m68010_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : m68000_base_device(mconfig, "M68010", tag, owner, clock, M68010, 16,24, "m68010", __FILE__) +{ +} + +void m68010_device::device_start() +{ + init_cpu_m68010(); +} + + + +m68020_device::m68020_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : m68000_base_device(mconfig, "M68020", tag, owner, clock, M68020, 32,32, "m68020", __FILE__) +{ +} + +void m68020_device::device_start() +{ + init_cpu_m68020(); +} + + +m68020fpu_device::m68020fpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : m68000_base_device(mconfig, "M68020FPU", tag, owner, clock, M68020, 32,32, "m68020fpu", __FILE__) +{ +} + +void m68020fpu_device::device_start() +{ + init_cpu_m68020fpu(); +} + +// 68020 with 68851 PMMU +m68020pmmu_device::m68020pmmu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : m68000_base_device(mconfig, "M68020PMMU", tag, owner, clock, M68020PMMU, 32,32, "m68020pmmu", __FILE__) +{ +} + +void m68020pmmu_device::device_start() +{ + init_cpu_m68020pmmu(); +} + +bool m68020hmmu_device::memory_translate(address_spacenum space, int intention, offs_t &address) +{ + /* only applies to the program address space and only does something if the MMU's enabled */ + if (this) + { + if ((space == AS_PROGRAM) && (hmmu_enabled)) + { + address = hmmu_translate_addr(this, address); + } + } + return TRUE; +} + + +// 68020 with Apple HMMU & 68881 FPU +// case CPUINFO_FCT_TRANSLATE: info->translate = CPU_TRANSLATE_NAME(m68khmmu); break; +m68020hmmu_device::m68020hmmu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : m68000_base_device(mconfig, "M68020HMMU", tag, owner, clock, M68020HMMU, 32,32, "m68020hmmu", __FILE__) +{ +} + +void m68020hmmu_device::device_start() +{ + init_cpu_m68020hmmu(); +} + + +m68ec020_device::m68ec020_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : m68000_base_device(mconfig, "M68EC020", tag, owner, clock, M68EC020, 32,24, "m68ec020", __FILE__) +{ +} + +void m68ec020_device::device_start() +{ + init_cpu_m68ec020(); +} + +m68030_device::m68030_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : m68000_base_device(mconfig, "M68030", tag, owner, clock, M68030, 32,32, "m68030", __FILE__) +{ +} + +void m68030_device::device_start() +{ + init_cpu_m68030(); +} + +m68ec030_device::m68ec030_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : m68000_base_device(mconfig, "M68EC030", tag, owner, clock, M68EC030, 32,32, "m68ec030", __FILE__) +{ +} + +void m68ec030_device::device_start() +{ + init_cpu_m68ec030(); +} + +m68040_device::m68040_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : m68000_base_device(mconfig, "M68040", tag, owner, clock, M68040, 32,32, "m68040", __FILE__) +{ +} + + +void m68040_device::device_start() +{ + init_cpu_m68040(); +} + + + +m68ec040_device::m68ec040_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : m68000_base_device(mconfig, "M68EC040", tag, owner, clock, M68EC040, 32,32, "m68ec040", __FILE__) +{ +} + +void m68ec040_device::device_start() +{ + init_cpu_m68ec040(); +} + + + +m68lc040_device::m68lc040_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : m68000_base_device(mconfig, "M68LC040", tag, owner, clock, M68LC040, 32,32, "m68lc040", __FILE__) +{ +} + +void m68lc040_device::device_start() +{ + init_cpu_m68lc040(); +} + + +scc68070_device::scc68070_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : m68000_base_device(mconfig, "SCC68070", tag, owner, clock, SCC68070, 16,32, "scc68070", __FILE__) +{ +} + +void scc68070_device::device_start() +{ + init_cpu_scc68070(); +} + + +fscpu32_device::fscpu32_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : m68000_base_device(mconfig, "Freescale CPU32 Core", tag, owner, clock, FSCPU32, 32,32, "fscpu32", __FILE__) +{ +} + +fscpu32_device::fscpu32_device(const machine_config &mconfig, const char *name, const char *tag, device_t *owner, UINT32 clock, + const device_type type, UINT32 prg_data_width, UINT32 prg_address_bits, address_map_constructor internal_map, const char *shortname, const char *source) + : m68000_base_device(mconfig, name, tag, owner, clock, type, prg_data_width, prg_address_bits, internal_map, shortname, source) +{ +} + + +void fscpu32_device::device_start() +{ + init_cpu_fscpu32(); +} + + + +mcf5206e_device::mcf5206e_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : m68000_base_device(mconfig, "MCF5206E", tag, owner, clock, MCF5206E, 32,32, "mcf5206e", __FILE__) +{ +} + +void mcf5206e_device::device_start() +{ + init_cpu_coldfire(); +} diff --git a/src/devices/cpu/m68000/m68kcpu.h b/src/devices/cpu/m68000/m68kcpu.h new file mode 100644 index 00000000000..2c30bf78a98 --- /dev/null +++ b/src/devices/cpu/m68000/m68kcpu.h @@ -0,0 +1,1698 @@ +// license:BSD-3-Clause +// copyright-holders:Karl Stenerud +/* ======================================================================== */ +/* ========================= LICENSING & COPYRIGHT ======================== */ +/* ======================================================================== */ +/* + * MUSASHI + * Version 4.50 + * + * A portable Motorola M680x0 processor emulation engine. + * Copyright Karl Stenerud. All rights reserved. + * + */ + + +#pragma once + +#ifndef __M68KCPU_H__ +#define __M68KCPU_H__ + +class m68000_base_device; + +#include "m68000.h" + + +#include + +#if defined(__sun__) && defined(__svr4__) +#undef REG_SP +#undef REG_PC +#undef REG_FP +#endif + +/* ======================================================================== */ +/* ==================== ARCHITECTURE-DEPENDANT DEFINES ==================== */ +/* ======================================================================== */ + +/* Check for > 32bit sizes */ +#define MAKE_INT_8(A) (INT8)(A) +#define MAKE_INT_16(A) (INT16)(A) +#define MAKE_INT_32(A) (INT32)(A) + + +/* ======================================================================== */ +/* ============================ GENERAL DEFINES =========================== */ +/* ======================================================================== */ + +/* Exception Vectors handled by emulation */ +#define EXCEPTION_RESET 0 +#define EXCEPTION_BUS_ERROR 2 /* This one is not emulated! */ +#define EXCEPTION_ADDRESS_ERROR 3 /* This one is partially emulated (doesn't stack a proper frame yet) */ +#define EXCEPTION_ILLEGAL_INSTRUCTION 4 +#define EXCEPTION_ZERO_DIVIDE 5 +#define EXCEPTION_CHK 6 +#define EXCEPTION_TRAPV 7 +#define EXCEPTION_PRIVILEGE_VIOLATION 8 +#define EXCEPTION_TRACE 9 +#define EXCEPTION_1010 10 +#define EXCEPTION_1111 11 +#define EXCEPTION_FORMAT_ERROR 14 +#define EXCEPTION_UNINITIALIZED_INTERRUPT 15 +#define EXCEPTION_SPURIOUS_INTERRUPT 24 +#define EXCEPTION_INTERRUPT_AUTOVECTOR 24 +#define EXCEPTION_TRAP_BASE 32 + +/* Function codes set by CPU during data/address bus activity */ +#define FUNCTION_CODE_USER_DATA 1 +#define FUNCTION_CODE_USER_PROGRAM 2 +#define FUNCTION_CODE_SUPERVISOR_DATA 5 +#define FUNCTION_CODE_SUPERVISOR_PROGRAM 6 +#define FUNCTION_CODE_CPU_SPACE 7 + +/* CPU types for deciding what to emulate */ +#define CPU_TYPE_000 (0x00000001) +#define CPU_TYPE_008 (0x00000002) +#define CPU_TYPE_010 (0x00000004) +#define CPU_TYPE_EC020 (0x00000008) +#define CPU_TYPE_020 (0x00000010) +#define CPU_TYPE_EC030 (0x00000020) +#define CPU_TYPE_030 (0x00000040) +#define CPU_TYPE_EC040 (0x00000080) +#define CPU_TYPE_LC040 (0x00000100) +#define CPU_TYPE_040 (0x00000200) +#define CPU_TYPE_SCC070 (0x00000400) +#define CPU_TYPE_FSCPU32 (0x00000800) +#define CPU_TYPE_COLDFIRE (0x00001000) + +/* Different ways to stop the CPU */ +#define STOP_LEVEL_STOP 1 +#define STOP_LEVEL_HALT 2 + +/* Used for 68000 address error processing */ +#define INSTRUCTION_YES 0 +#define INSTRUCTION_NO 0x08 +#define MODE_READ 0x10 +#define MODE_WRITE 0 + +#define RUN_MODE_NORMAL 0 +#define RUN_MODE_BERR_AERR_RESET 1 + + + +#define M68K_CACR_IBE 0x10 // Instruction Burst Enable +#define M68K_CACR_CI 0x08 // Clear Instruction Cache +#define M68K_CACR_CEI 0x04 // Clear Entry in Instruction Cache +#define M68K_CACR_FI 0x02 // Freeze Instruction Cache +#define M68K_CACR_EI 0x01 // Enable Instruction Cache + +/* ======================================================================== */ +/* ================================ MACROS ================================ */ +/* ======================================================================== */ + + +/* ---------------------------- General Macros ---------------------------- */ + +/* Bit Isolation Macros */ +#define BIT_0(A) ((A) & 0x00000001) +#define BIT_1(A) ((A) & 0x00000002) +#define BIT_2(A) ((A) & 0x00000004) +#define BIT_3(A) ((A) & 0x00000008) +#define BIT_4(A) ((A) & 0x00000010) +#define BIT_5(A) ((A) & 0x00000020) +#define BIT_6(A) ((A) & 0x00000040) +#define BIT_7(A) ((A) & 0x00000080) +#define BIT_8(A) ((A) & 0x00000100) +#define BIT_9(A) ((A) & 0x00000200) +#define BIT_A(A) ((A) & 0x00000400) +#define BIT_B(A) ((A) & 0x00000800) +#define BIT_C(A) ((A) & 0x00001000) +#define BIT_D(A) ((A) & 0x00002000) +#define BIT_E(A) ((A) & 0x00004000) +#define BIT_F(A) ((A) & 0x00008000) +#define BIT_10(A) ((A) & 0x00010000) +#define BIT_11(A) ((A) & 0x00020000) +#define BIT_12(A) ((A) & 0x00040000) +#define BIT_13(A) ((A) & 0x00080000) +#define BIT_14(A) ((A) & 0x00100000) +#define BIT_15(A) ((A) & 0x00200000) +#define BIT_16(A) ((A) & 0x00400000) +#define BIT_17(A) ((A) & 0x00800000) +#define BIT_18(A) ((A) & 0x01000000) +#define BIT_19(A) ((A) & 0x02000000) +#define BIT_1A(A) ((A) & 0x04000000) +#define BIT_1B(A) ((A) & 0x08000000) +#define BIT_1C(A) ((A) & 0x10000000) +#define BIT_1D(A) ((A) & 0x20000000) +#define BIT_1E(A) ((A) & 0x40000000) +#define BIT_1F(A) ((A) & 0x80000000) + +/* Get the most significant bit for specific sizes */ +#define GET_MSB_8(A) ((A) & 0x80) +#define GET_MSB_9(A) ((A) & 0x100) +#define GET_MSB_16(A) ((A) & 0x8000) +#define GET_MSB_17(A) ((A) & 0x10000) +#define GET_MSB_32(A) ((A) & 0x80000000) +#define GET_MSB_33(A) ((A) & U64(0x100000000)) + +/* Isolate nibbles */ +#define LOW_NIBBLE(A) ((A) & 0x0f) +#define HIGH_NIBBLE(A) ((A) & 0xf0) + +/* These are used to isolate 8, 16, and 32 bit sizes */ +#define MASK_OUT_ABOVE_2(A) ((A) & 3) +#define MASK_OUT_ABOVE_8(A) ((A) & 0xff) +#define MASK_OUT_ABOVE_16(A) ((A) & 0xffff) +#define MASK_OUT_BELOW_2(A) ((A) & ~3) +#define MASK_OUT_BELOW_8(A) ((A) & ~0xff) +#define MASK_OUT_BELOW_16(A) ((A) & ~0xffff) + +/* No need to mask if we are 32 bit */ +#define MASK_OUT_ABOVE_32(A) ((A) & U64(0xffffffff)) +#define MASK_OUT_BELOW_32(A) ((A) & ~U64(0xffffffff)) + +/* Shift & Rotate Macros. */ +#define LSL(A, C) ((A) << (C)) +#define LSR(A, C) ((A) >> (C)) + +/* We have to do this because the morons at ANSI decided that shifts +* by >= data size are undefined. +*/ +#define LSR_32(A, C) ((C) < 32 ? (A) >> (C) : 0) +#define LSL_32(A, C) ((C) < 32 ? (A) << (C) : 0) + +#define LSL_32_64(A, C) ((A) << (C)) +#define LSR_32_64(A, C) ((A) >> (C)) +#define ROL_33_64(A, C) (LSL_32_64(A, C) | LSR_32_64(A, 33-(C))) +#define ROR_33_64(A, C) (LSR_32_64(A, C) | LSL_32_64(A, 33-(C))) + +#define ROL_8(A, C) MASK_OUT_ABOVE_8(LSL(A, C) | LSR(A, 8-(C))) +#define ROL_9(A, C) (LSL(A, C) | LSR(A, 9-(C))) +#define ROL_16(A, C) MASK_OUT_ABOVE_16(LSL(A, C) | LSR(A, 16-(C))) +#define ROL_17(A, C) (LSL(A, C) | LSR(A, 17-(C))) +#define ROL_32(A, C) MASK_OUT_ABOVE_32(LSL_32(A, C) | LSR_32(A, 32-(C))) +#define ROL_33(A, C) (LSL_32(A, C) | LSR_32(A, 33-(C))) + +#define ROR_8(A, C) MASK_OUT_ABOVE_8(LSR(A, C) | LSL(A, 8-(C))) +#define ROR_9(A, C) (LSR(A, C) | LSL(A, 9-(C))) +#define ROR_16(A, C) MASK_OUT_ABOVE_16(LSR(A, C) | LSL(A, 16-(C))) +#define ROR_17(A, C) (LSR(A, C) | LSL(A, 17-(C))) +#define ROR_32(A, C) MASK_OUT_ABOVE_32(LSR_32(A, C) | LSL_32(A, 32-(C))) +#define ROR_33(A, C) (LSR_32(A, C) | LSL_32(A, 33-(C))) + + + +/* ------------------------------ CPU Access ------------------------------ */ + +/* Access the CPU registers */ +#define REG_DA(M) (M)->dar /* easy access to data and address regs */ +#define REG_D(M) (M)->dar +#define REG_A(M) ((M)->dar+8) +#define REG_PPC(M) (M)->ppc +#define REG_PC(M) (M)->pc +#define REG_SP_BASE(M) (M)->sp +#define REG_USP(M) (M)->sp[0] +#define REG_ISP(M) (M)->sp[4] +#define REG_MSP(M) (M)->sp[6] +#define REG_SP(M) (M)->dar[15] + +#define REG_FP(M) (M)->fpr +#define REG_FPCR(M) (M)->fpcr +#define REG_FPSR(M) (M)->fpsr +#define REG_FPIAR(M) (M)->fpiar + + +/* ----------------------------- Configuration ---------------------------- */ + +/* These defines are dependant on the configuration defines in m68kconf.h */ + +/* Disable certain comparisons if we're not using all CPU types */ +#define CPU_TYPE_IS_COLDFIRE(A) ((A) & (CPU_TYPE_COLDFIRE)) + +#define CPU_TYPE_IS_040_PLUS(A) ((A) & (CPU_TYPE_040 | CPU_TYPE_EC040)) +#define CPU_TYPE_IS_040_LESS(A) 1 + +#define CPU_TYPE_IS_030_PLUS(A) ((A) & (CPU_TYPE_030 | CPU_TYPE_EC030 | CPU_TYPE_040 | CPU_TYPE_EC040)) +#define CPU_TYPE_IS_030_LESS(A) 1 + +#define CPU_TYPE_IS_020_PLUS(A) ((A) & (CPU_TYPE_020 | CPU_TYPE_030 | CPU_TYPE_EC030 | CPU_TYPE_040 | CPU_TYPE_EC040 | CPU_TYPE_FSCPU32 | CPU_TYPE_COLDFIRE)) +#define CPU_TYPE_IS_020_LESS(A) 1 + +#define CPU_TYPE_IS_020_VARIANT(A) ((A) & (CPU_TYPE_EC020 | CPU_TYPE_020 | CPU_TYPE_FSCPU32)) + +#define CPU_TYPE_IS_EC020_PLUS(A) ((A) & (CPU_TYPE_EC020 | CPU_TYPE_020 | CPU_TYPE_030 | CPU_TYPE_EC030 | CPU_TYPE_040 | CPU_TYPE_EC040 | CPU_TYPE_FSCPU32 | CPU_TYPE_COLDFIRE)) +#define CPU_TYPE_IS_EC020_LESS(A) ((A) & (CPU_TYPE_000 | CPU_TYPE_008 | CPU_TYPE_010 | CPU_TYPE_EC020)) + +#define CPU_TYPE_IS_010(A) ((A) == CPU_TYPE_010) +#define CPU_TYPE_IS_010_PLUS(A) ((A) & (CPU_TYPE_010 | CPU_TYPE_EC020 | CPU_TYPE_020 | CPU_TYPE_EC030 | CPU_TYPE_030 | CPU_TYPE_040 | CPU_TYPE_EC040 | CPU_TYPE_FSCPU32 | CPU_TYPE_COLDFIRE)) +#define CPU_TYPE_IS_010_LESS(A) ((A) & (CPU_TYPE_000 | CPU_TYPE_008 | CPU_TYPE_010)) + +#define CPU_TYPE_IS_000(A) ((A) == CPU_TYPE_000 || (A) == CPU_TYPE_008) + + +/* Initiates trace checking before each instruction (t1) */ +#define m68ki_trace_t1(m68k) m68k->tracing = m68k->t1_flag +/* adds t0 to trace checking if we encounter change of flow */ +#define m68ki_trace_t0(m68k) m68k->tracing |= m68k->t0_flag +/* Clear all tracing */ +#define m68ki_clear_trace(m68k) m68k->tracing = 0 +/* Cause a trace exception if we are tracing */ +#define m68ki_exception_if_trace(m68k) if(m68k->tracing) m68ki_exception_trace(m68k) + +/* -------------------------- EA / Operand Access ------------------------- */ + +/* + * The general instruction format follows this pattern: + * .... XXX. .... .YYY + * where XXX is register X and YYY is register Y + */ +/* Data Register Isolation */ +#define DX(M) (REG_D(M)[((M)->ir >> 9) & 7]) +#define DY(M) (REG_D(M)[(M)->ir & 7]) +/* Address Register Isolation */ +#define AX(M) (REG_A(M)[((M)->ir >> 9) & 7]) +#define AY(M) (REG_A(M)[(M)->ir & 7]) + + +/* Effective Address Calculations */ +#define EA_AY_AI_8(M) AY(M) /* address register indirect */ +#define EA_AY_AI_16(M) EA_AY_AI_8(M) +#define EA_AY_AI_32(M) EA_AY_AI_8(M) +#define EA_AY_PI_8(M) (AY(M)++) /* postincrement (size = byte) */ +#define EA_AY_PI_16(M) ((AY(M)+=2)-2) /* postincrement (size = word) */ +#define EA_AY_PI_32(M) ((AY(M)+=4)-4) /* postincrement (size = long) */ +#define EA_AY_PD_8(M) (--AY(M)) /* predecrement (size = byte) */ +#define EA_AY_PD_16(M) (AY(M)-=2) /* predecrement (size = word) */ +#define EA_AY_PD_32(M) (AY(M)-=4) /* predecrement (size = long) */ +#define EA_AY_DI_8(M) (AY(M)+MAKE_INT_16(m68ki_read_imm_16(M))) /* displacement */ +#define EA_AY_DI_16(M) EA_AY_DI_8(M) +#define EA_AY_DI_32(M) EA_AY_DI_8(M) +#define EA_AY_IX_8(M) m68ki_get_ea_ix(M, AY(M)) /* indirect + index */ +#define EA_AY_IX_16(M) EA_AY_IX_8(M) +#define EA_AY_IX_32(M) EA_AY_IX_8(M) + +#define EA_AX_AI_8(M) AX(M) +#define EA_AX_AI_16(M) EA_AX_AI_8(M) +#define EA_AX_AI_32(M) EA_AX_AI_8(M) +#define EA_AX_PI_8(M) (AX(M)++) +#define EA_AX_PI_16(M) ((AX(M)+=2)-2) +#define EA_AX_PI_32(M) ((AX(M)+=4)-4) +#define EA_AX_PD_8(M) (--AX(M)) +#define EA_AX_PD_16(M) (AX(M)-=2) +#define EA_AX_PD_32(M) (AX(M)-=4) +#define EA_AX_DI_8(M) (AX(M)+MAKE_INT_16(m68ki_read_imm_16(M))) +#define EA_AX_DI_16(M) EA_AX_DI_8(M) +#define EA_AX_DI_32(M) EA_AX_DI_8(M) +#define EA_AX_IX_8(M) m68ki_get_ea_ix(M, AX(M)) +#define EA_AX_IX_16(M) EA_AX_IX_8(M) +#define EA_AX_IX_32(M) EA_AX_IX_8(M) + +#define EA_A7_PI_8(m68k) ((REG_A(m68k)[7]+=2)-2) +#define EA_A7_PD_8(m68k) (REG_A(m68k)[7]-=2) + +#define EA_AW_8(m68k) MAKE_INT_16(m68ki_read_imm_16(m68k)) /* absolute word */ +#define EA_AW_16(m68k) EA_AW_8(m68k) +#define EA_AW_32(m68k) EA_AW_8(m68k) +#define EA_AL_8(m68k) m68ki_read_imm_32(m68k) /* absolute long */ +#define EA_AL_16(m68k) EA_AL_8(m68k) +#define EA_AL_32(m68k) EA_AL_8(m68k) +#define EA_PCDI_8(m68k) m68ki_get_ea_pcdi(m68k) /* pc indirect + displacement */ +#define EA_PCDI_16(m68k) EA_PCDI_8(m68k) +#define EA_PCDI_32(m68k) EA_PCDI_8(m68k) +#define EA_PCIX_8(m68k) m68ki_get_ea_pcix(m68k) /* pc indirect + index */ +#define EA_PCIX_16(m68k) EA_PCIX_8(m68k) +#define EA_PCIX_32(m68k) EA_PCIX_8(m68k) + + +#define OPER_I_8(m68k) m68ki_read_imm_8(m68k) +#define OPER_I_16(m68k) m68ki_read_imm_16(m68k) +#define OPER_I_32(m68k) m68ki_read_imm_32(m68k) + + + +/* --------------------------- Status Register ---------------------------- */ + +/* Flag Calculation Macros */ +#define CFLAG_8(A) (A) +#define CFLAG_16(A) ((A)>>8) + +#define CFLAG_ADD_32(S, D, R) (((S & D) | (~R & (S | D)))>>23) +#define CFLAG_SUB_32(S, D, R) (((S & R) | (~D & (S | R)))>>23) + +#define VFLAG_ADD_8(S, D, R) ((S^R) & (D^R)) +#define VFLAG_ADD_16(S, D, R) (((S^R) & (D^R))>>8) +#define VFLAG_ADD_32(S, D, R) (((S^R) & (D^R))>>24) + +#define VFLAG_SUB_8(S, D, R) ((S^D) & (R^D)) +#define VFLAG_SUB_16(S, D, R) (((S^D) & (R^D))>>8) +#define VFLAG_SUB_32(S, D, R) (((S^D) & (R^D))>>24) + +#define NFLAG_8(A) (A) +#define NFLAG_16(A) ((A)>>8) +#define NFLAG_32(A) ((A)>>24) +#define NFLAG_64(A) ((A)>>56) + +#define ZFLAG_8(A) MASK_OUT_ABOVE_8(A) +#define ZFLAG_16(A) MASK_OUT_ABOVE_16(A) +#define ZFLAG_32(A) MASK_OUT_ABOVE_32(A) + + +/* Flag values */ +#define NFLAG_SET 0x80 +#define NFLAG_CLEAR 0 +#define CFLAG_SET 0x100 +#define CFLAG_CLEAR 0 +#define XFLAG_SET 0x100 +#define XFLAG_CLEAR 0 +#define VFLAG_SET 0x80 +#define VFLAG_CLEAR 0 +#define ZFLAG_SET 0 +#define ZFLAG_CLEAR 0xffffffff + +#define SFLAG_SET 4 +#define SFLAG_CLEAR 0 +#define MFLAG_SET 2 +#define MFLAG_CLEAR 0 + +/* Turn flag values into 1 or 0 */ +#define XFLAG_AS_1(M) (((M)->x_flag>>8)&1) +#define NFLAG_AS_1(M) (((M)->n_flag>>7)&1) +#define VFLAG_AS_1(M) (((M)->v_flag>>7)&1) +#define ZFLAG_AS_1(M) (!(M)->not_z_flag) +#define CFLAG_AS_1(M) (((M)->c_flag>>8)&1) + + +/* Conditions */ +#define COND_CS(M) ((M)->c_flag&0x100) +#define COND_CC(M) (!COND_CS(M)) +#define COND_VS(M) ((M)->v_flag&0x80) +#define COND_VC(M) (!COND_VS(M)) +#define COND_NE(M) (M)->not_z_flag +#define COND_EQ(M) (!COND_NE(M)) +#define COND_MI(M) ((M)->n_flag&0x80) +#define COND_PL(M) (!COND_MI(M)) +#define COND_LT(M) (((M)->n_flag^(M)->v_flag)&0x80) +#define COND_GE(M) (!COND_LT(M)) +#define COND_HI(M) (COND_CC(M) && COND_NE(M)) +#define COND_LS(M) (COND_CS(M) || COND_EQ(M)) +#define COND_GT(M) (COND_GE(M) && COND_NE(M)) +#define COND_LE(M) (COND_LT(M) || COND_EQ(M)) + +/* Reversed conditions */ +#define COND_NOT_CS(M) COND_CC(M) +#define COND_NOT_CC(M) COND_CS(M) +#define COND_NOT_VS(M) COND_VC(M) +#define COND_NOT_VC(M) COND_VS(M) +#define COND_NOT_NE(M) COND_EQ(M) +#define COND_NOT_EQ(M) COND_NE(M) +#define COND_NOT_MI(M) COND_PL(M) +#define COND_NOT_PL(M) COND_MI(M) +#define COND_NOT_LT(M) COND_GE(M) +#define COND_NOT_GE(M) COND_LT(M) +#define COND_NOT_HI(M) COND_LS(M) +#define COND_NOT_LS(M) COND_HI(M) +#define COND_NOT_GT(M) COND_LE(M) +#define COND_NOT_LE(M) COND_GT(M) + +/* Not real conditions, but here for convenience */ +#define COND_XS(M) ((M)->x_flag&0x100) +#define COND_XC(M) (!COND_XS) + + +/* Get the condition code register */ +#define m68ki_get_ccr(M) ((COND_XS(M) >> 4) | \ + (COND_MI(M) >> 4) | \ + (COND_EQ(M) << 2) | \ + (COND_VS(M) >> 6) | \ + (COND_CS(M) >> 8)) + +/* Get the status register */ +#define m68ki_get_sr(M) ((M)->t1_flag | \ + (M)->t0_flag | \ + ((M)->s_flag << 11) | \ + ((M)->m_flag << 11) | \ + (M)->int_mask | \ + m68ki_get_ccr(M)) + + + +/* ----------------------------- Read / Write ----------------------------- */ + +/* Read from the current address space */ +#define m68ki_read_8(M, A) m68ki_read_8_fc (M, A, (M)->s_flag | FUNCTION_CODE_USER_DATA) +#define m68ki_read_16(M, A) m68ki_read_16_fc(M, A, (M)->s_flag | FUNCTION_CODE_USER_DATA) +#define m68ki_read_32(M, A) m68ki_read_32_fc(M, A, (M)->s_flag | FUNCTION_CODE_USER_DATA) + +/* Write to the current data space */ +#define m68ki_write_8(M, A, V) m68ki_write_8_fc (M, A, (M)->s_flag | FUNCTION_CODE_USER_DATA, V) +#define m68ki_write_16(M, A, V) m68ki_write_16_fc(M, A, (M)->s_flag | FUNCTION_CODE_USER_DATA, V) +#define m68ki_write_32(M, A, V) m68ki_write_32_fc(M, A, (M)->s_flag | FUNCTION_CODE_USER_DATA, V) +#define m68ki_write_32_pd(M, A, V) m68ki_write_32_pd_fc(M, A, (M)->s_flag | FUNCTION_CODE_USER_DATA, V) + +/* map read immediate 8 to read immediate 16 */ +#define m68ki_read_imm_8(M) MASK_OUT_ABOVE_8(m68ki_read_imm_16(M)) + +/* Map PC-relative reads */ +#define m68ki_read_pcrel_8(M, A) m68k_read_pcrelative_8(M, A) +#define m68ki_read_pcrel_16(M, A) m68k_read_pcrelative_16(M, A) +#define m68ki_read_pcrel_32(M, A) m68k_read_pcrelative_32(M, A) + +/* Read from the program space */ +#define m68ki_read_program_8(M, A) m68ki_read_8_fc(M, A, (M)->s_flag | FUNCTION_CODE_USER_PROGRAM) +#define m68ki_read_program_16(M, A) m68ki_read_16_fc(M, A, (M)->s_flag | FUNCTION_CODE_USER_PROGRAM) +#define m68ki_read_program_32(M, A) m68ki_read_32_fc(M, A, (M)->s_flag | FUNCTION_CODE_USER_PROGRAM) + +/* Read from the data space */ +#define m68ki_read_data_8(M, A) m68ki_read_8_fc(M, A, (M)->s_flag | FUNCTION_CODE_USER_DATA) +#define m68ki_read_data_16(M, A) m68ki_read_16_fc(M, A, (M)->s_flag | FUNCTION_CODE_USER_DATA) +#define m68ki_read_data_32(M, A) m68ki_read_32_fc(M, A, (M)->s_flag | FUNCTION_CODE_USER_DATA) + + + +/* ======================================================================== */ +/* =============================== PROTOTYPES ============================= */ +/* ======================================================================== */ + +union fp_reg +{ + UINT64 i; + double f; +}; + +class m68000_base_device_ops +{ +public: + #define OPCODE_PROTOTYPES + #include "m68kops.h" + #undef OPCODE_PROTOTYPES +}; + + + +extern const UINT8 m68ki_shift_8_table[]; +extern const UINT16 m68ki_shift_16_table[]; +extern const UINT32 m68ki_shift_32_table[]; +extern const UINT8 m68ki_exception_cycle_table[][256]; +extern const UINT8 m68ki_ea_idx_cycle_table[]; + +/* Read data immediately after the program counter */ +INLINE UINT32 m68ki_read_imm_16(m68000_base_device *m68k); +INLINE UINT32 m68ki_read_imm_32(m68000_base_device *m68k); + +/* Read data with specific function code */ +INLINE UINT32 m68ki_read_8_fc (m68000_base_device *m68k, UINT32 address, UINT32 fc); +INLINE UINT32 m68ki_read_16_fc (m68000_base_device *m68k, UINT32 address, UINT32 fc); +INLINE UINT32 m68ki_read_32_fc (m68000_base_device *m68k, UINT32 address, UINT32 fc); + +/* Write data with specific function code */ +INLINE void m68ki_write_8_fc (m68000_base_device *m68k, UINT32 address, UINT32 fc, UINT32 value); +INLINE void m68ki_write_16_fc(m68000_base_device *m68k, UINT32 address, UINT32 fc, UINT32 value); +INLINE void m68ki_write_32_fc(m68000_base_device *m68k, UINT32 address, UINT32 fc, UINT32 value); +INLINE void m68ki_write_32_pd_fc(m68000_base_device *m68k, UINT32 address, UINT32 fc, UINT32 value); + +/* Indexed and PC-relative ea fetching */ +INLINE UINT32 m68ki_get_ea_pcdi(m68000_base_device *m68k); +INLINE UINT32 m68ki_get_ea_pcix(m68000_base_device *m68k); +INLINE UINT32 m68ki_get_ea_ix(m68000_base_device *m68k, UINT32 An); + +/* Operand fetching */ +INLINE UINT32 OPER_AY_AI_8(m68000_base_device *m68k); +INLINE UINT32 OPER_AY_AI_16(m68000_base_device *m68k); +INLINE UINT32 OPER_AY_AI_32(m68000_base_device *m68k); +INLINE UINT32 OPER_AY_PI_8(m68000_base_device *m68k); +INLINE UINT32 OPER_AY_PI_16(m68000_base_device *m68k); +INLINE UINT32 OPER_AY_PI_32(m68000_base_device *m68k); +INLINE UINT32 OPER_AY_PD_8(m68000_base_device *m68k); +INLINE UINT32 OPER_AY_PD_16(m68000_base_device *m68k); +INLINE UINT32 OPER_AY_PD_32(m68000_base_device *m68k); +INLINE UINT32 OPER_AY_DI_8(m68000_base_device *m68k); +INLINE UINT32 OPER_AY_DI_16(m68000_base_device *m68k); +INLINE UINT32 OPER_AY_DI_32(m68000_base_device *m68k); +INLINE UINT32 OPER_AY_IX_8(m68000_base_device *m68k); +INLINE UINT32 OPER_AY_IX_16(m68000_base_device *m68k); +INLINE UINT32 OPER_AY_IX_32(m68000_base_device *m68k); + +INLINE UINT32 OPER_AX_AI_8(m68000_base_device *m68k); +INLINE UINT32 OPER_AX_AI_16(m68000_base_device *m68k); +INLINE UINT32 OPER_AX_AI_32(m68000_base_device *m68k); +INLINE UINT32 OPER_AX_PI_8(m68000_base_device *m68k); +INLINE UINT32 OPER_AX_PI_16(m68000_base_device *m68k); +INLINE UINT32 OPER_AX_PI_32(m68000_base_device *m68k); +INLINE UINT32 OPER_AX_PD_8(m68000_base_device *m68k); +INLINE UINT32 OPER_AX_PD_16(m68000_base_device *m68k); +INLINE UINT32 OPER_AX_PD_32(m68000_base_device *m68k); +INLINE UINT32 OPER_AX_DI_8(m68000_base_device *m68k); +INLINE UINT32 OPER_AX_DI_16(m68000_base_device *m68k); +INLINE UINT32 OPER_AX_DI_32(m68000_base_device *m68k); +INLINE UINT32 OPER_AX_IX_8(m68000_base_device *m68k); +INLINE UINT32 OPER_AX_IX_16(m68000_base_device *m68k); +INLINE UINT32 OPER_AX_IX_32(m68000_base_device *m68k); + +INLINE UINT32 OPER_A7_PI_8(m68000_base_device *m68k); +INLINE UINT32 OPER_A7_PD_8(m68000_base_device *m68k); + +INLINE UINT32 OPER_AW_8(m68000_base_device *m68k); +INLINE UINT32 OPER_AW_16(m68000_base_device *m68k); +INLINE UINT32 OPER_AW_32(m68000_base_device *m68k); +INLINE UINT32 OPER_AL_8(m68000_base_device *m68k); +INLINE UINT32 OPER_AL_16(m68000_base_device *m68k); +INLINE UINT32 OPER_AL_32(m68000_base_device *m68k); +INLINE UINT32 OPER_PCDI_8(m68000_base_device *m68k); +INLINE UINT32 OPER_PCDI_16(m68000_base_device *m68k); +INLINE UINT32 OPER_PCDI_32(m68000_base_device *m68k); +INLINE UINT32 OPER_PCIX_8(m68000_base_device *m68k); +INLINE UINT32 OPER_PCIX_16(m68000_base_device *m68k); +INLINE UINT32 OPER_PCIX_32(m68000_base_device *m68k); + +/* Stack operations */ +INLINE void m68ki_push_16(m68000_base_device *m68k, UINT32 value); +INLINE void m68ki_push_32(m68000_base_device *m68k, UINT32 value); +INLINE UINT32 m68ki_pull_16(m68000_base_device *m68k); +INLINE UINT32 m68ki_pull_32(m68000_base_device *m68k); + +/* Program flow operations */ +INLINE void m68ki_jump(m68000_base_device *m68k, UINT32 new_pc); +INLINE void m68ki_jump_vector(m68000_base_device *m68k, UINT32 vector); +INLINE void m68ki_branch_8(m68000_base_device *m68k, UINT32 offset); +INLINE void m68ki_branch_16(m68000_base_device *m68k, UINT32 offset); +INLINE void m68ki_branch_32(m68000_base_device *m68k, UINT32 offset); + +/* Status register operations. */ +INLINE void m68ki_set_s_flag(m68000_base_device *m68k, UINT32 value); /* Only bit 2 of value should be set (i.e. 4 or 0) */ +INLINE void m68ki_set_sm_flag(m68000_base_device *m68k, UINT32 value); /* only bits 1 and 2 of value should be set */ +INLINE void m68ki_set_ccr(m68000_base_device *m68k, UINT32 value); /* set the condition code register */ +INLINE void m68ki_set_sr(m68000_base_device *m68k, UINT32 value); /* set the status register */ +INLINE void m68ki_set_sr_noint(m68000_base_device *m68k, UINT32 value); /* set the status register */ + +/* Exception processing */ +INLINE UINT32 m68ki_init_exception(m68000_base_device *m68k); /* Initial exception processing */ + +INLINE void m68ki_stack_frame_3word(m68000_base_device *m68k, UINT32 pc, UINT32 sr); /* Stack various frame types */ +INLINE void m68ki_stack_frame_buserr(m68000_base_device *m68k, UINT32 sr); + +INLINE void m68ki_stack_frame_0000(m68000_base_device *m68k, UINT32 pc, UINT32 sr, UINT32 vector); +INLINE void m68ki_stack_frame_0001(m68000_base_device *m68k, UINT32 pc, UINT32 sr, UINT32 vector); +INLINE void m68ki_stack_frame_0010(m68000_base_device *m68k, UINT32 sr, UINT32 vector); +INLINE void m68ki_stack_frame_1000(m68000_base_device *m68k, UINT32 pc, UINT32 sr, UINT32 vector); +INLINE void m68ki_stack_frame_1010(m68000_base_device *m68k, UINT32 sr, UINT32 vector, UINT32 pc, UINT32 fault_address); +INLINE void m68ki_stack_frame_1011(m68000_base_device *m68k, UINT32 sr, UINT32 vector, UINT32 pc, UINT32 fault_address); +INLINE void m68ki_stack_frame_0111(m68000_base_device *m68k, UINT32 sr, UINT32 vector, UINT32 pc, UINT32 fault_address, bool in_mmu); + +INLINE void m68ki_exception_trap(m68000_base_device *m68k, UINT32 vector); +INLINE void m68ki_exception_trapN(m68000_base_device *m68k, UINT32 vector); +INLINE void m68ki_exception_trace(m68000_base_device *m68k); +INLINE void m68ki_exception_privilege_violation(m68000_base_device *m68k); +INLINE void m68ki_exception_1010(m68000_base_device *m68k); +INLINE void m68ki_exception_1111(m68000_base_device *m68k); +INLINE void m68ki_exception_illegal(m68000_base_device *m68k); +INLINE void m68ki_exception_format_error(m68000_base_device *m68k); +INLINE void m68ki_exception_address_error(m68000_base_device *m68k); + +INLINE void m68ki_check_interrupts(m68000_base_device *m68k); /* ASG: check for interrupts */ + +/* quick disassembly (used for logging) */ +char* m68ki_disassemble_quick(unsigned int pc, unsigned int cpu_type); + + +/* ======================================================================== */ +/* =========================== UTILITY FUNCTIONS ========================== */ +/* ======================================================================== */ + + +INLINE unsigned int m68k_read_pcrelative_8(m68000_base_device *m68k, unsigned int address) +{ + return ((m68k->readimm16(address&~1)>>(8*(1-(address & 1))))&0xff); +} + +INLINE unsigned int m68k_read_pcrelative_16(m68000_base_device *m68k, unsigned int address) +{ + if(address & 1) + return + (m68k->readimm16(address-1) << 8) | + (m68k->readimm16(address+1) >> 8); + + else + return + (m68k->readimm16(address ) ); +} + +INLINE unsigned int m68k_read_pcrelative_32(m68000_base_device *m68k, unsigned int address) +{ + if(address & 1) + return + (m68k->readimm16(address-1) << 24) | + (m68k->readimm16(address+1) << 8) | + (m68k->readimm16(address+3) >> 8); + + else + return + (m68k->readimm16(address ) << 16) | + (m68k->readimm16(address+2) ); +} + + +/* Special call to simulate undocumented 68k behavior when move.l with a + * predecrement destination mode is executed. + * A real 68k first writes the high word to [address+2], and then writes the + * low word to [address]. + */ +INLINE void m68kx_write_memory_32_pd(m68000_base_device *m68k, unsigned int address, unsigned int value) +{ + m68k->/*memory.*/write16(address+2, value>>16); + m68k->/*memory.*/write16(address, value&0xffff); +} + + +/* ---------------------------- Read Immediate ---------------------------- */ + +// clear the instruction cache +INLINE void m68ki_ic_clear(m68000_base_device *m68k) +{ + int i; + for (i=0; i< M68K_IC_SIZE; i++) { + m68k->ic_address[i] = ~0; + } +} + +// read immediate word using the instruction cache + +INLINE UINT32 m68ki_ic_readimm16(m68000_base_device *m68k, UINT32 address) +{ + if (m68k->cacr & M68K_CACR_EI) + { + // 68020 series I-cache (MC68020 User's Manual, Section 4 - On-Chip Cache Memory) + if (m68k->cpu_type & (CPU_TYPE_EC020 | CPU_TYPE_020)) + { + UINT32 tag = (address >> 8) | (m68k->s_flag ? 0x1000000 : 0); + int idx = (address >> 2) & 0x3f; // 1-of-64 select + + // do a cache fill if the line is invalid or the tags don't match + if ((!m68k->ic_valid[idx]) || (m68k->ic_address[idx] != tag)) + { + UINT32 data = m68k->read32(address & ~3); + +// printf("m68k: doing cache fill at %08x (tag %08x idx %d)\n", address, tag, idx); + + // if no buserror occurred, validate the tag + if (!m68k->mmu_tmp_buserror_occurred) + { + m68k->ic_address[idx] = tag; + m68k->ic_data[idx] = data; + m68k->ic_valid[idx] = true; + } + else + { + return m68k->readimm16(address); + } + } + + // at this point, the cache is guaranteed to be valid, either as + // a hit or because we just filled it. + if (address & 2) + { + return m68k->ic_data[idx] & 0xffff; + } + else + { + return m68k->ic_data[idx] >> 16; + } + } + } + + return m68k->readimm16(address); +} + +/* Handles all immediate reads, does address error check, function code setting, + * and prefetching if they are enabled in m68kconf.h + */ +INLINE UINT32 m68ki_read_imm_16(m68000_base_device *m68k) +{ + UINT32 result; + + m68k->mmu_tmp_fc = m68k->s_flag | FUNCTION_CODE_USER_PROGRAM; + m68k->mmu_tmp_rw = 1; + + m68ki_check_address_error(m68k, REG_PC(m68k), MODE_READ, m68k->s_flag | FUNCTION_CODE_USER_PROGRAM); /* auto-disable (see m68kcpu.h) */ + + if(REG_PC(m68k) != m68k->pref_addr) + { + m68k->pref_data = m68ki_ic_readimm16(m68k, REG_PC(m68k)); + m68k->pref_addr = m68k->mmu_tmp_buserror_occurred ? ~0 : REG_PC(m68k); + } + result = MASK_OUT_ABOVE_16(m68k->pref_data); + REG_PC(m68k) += 2; + if (!m68k->mmu_tmp_buserror_occurred) { + // prefetch only if no bus error occurred in opcode fetch + m68k->pref_data = m68ki_ic_readimm16(m68k, REG_PC(m68k)); + m68k->pref_addr = m68k->mmu_tmp_buserror_occurred ? ~0 : REG_PC(m68k); + // ignore bus error on prefetch + m68k->mmu_tmp_buserror_occurred = 0; + } + + return result; +} + +INLINE UINT32 m68ki_read_imm_32(m68000_base_device *m68k) +{ + UINT32 temp_val; + + m68k->mmu_tmp_fc = m68k->s_flag | FUNCTION_CODE_USER_PROGRAM; + m68k->mmu_tmp_rw = 1; + + m68ki_check_address_error(m68k, REG_PC(m68k), MODE_READ, m68k->s_flag | FUNCTION_CODE_USER_PROGRAM); /* auto-disable (see m68kcpu.h) */ + + if(REG_PC(m68k) != m68k->pref_addr) + { + m68k->pref_addr = REG_PC(m68k); + m68k->pref_data = m68ki_ic_readimm16(m68k, m68k->pref_addr); + } + temp_val = MASK_OUT_ABOVE_16(m68k->pref_data); + REG_PC(m68k) += 2; + m68k->pref_addr = REG_PC(m68k); + m68k->pref_data = m68ki_ic_readimm16(m68k, m68k->pref_addr); + + temp_val = MASK_OUT_ABOVE_32((temp_val << 16) | MASK_OUT_ABOVE_16(m68k->pref_data)); + REG_PC(m68k) += 2; + m68k->pref_data = m68ki_ic_readimm16(m68k, REG_PC(m68k)); + m68k->pref_addr = m68k->mmu_tmp_buserror_occurred ? ~0 : REG_PC(m68k); + + return temp_val; +} + + + +/* ------------------------- Top level read/write ------------------------- */ + +/* Handles all memory accesses (except for immediate reads if they are + * configured to use separate functions in m68kconf.h). + * All memory accesses must go through these top level functions. + * These functions will also check for address error and set the function + * code if they are enabled in m68kconf.h. + */ +INLINE UINT32 m68ki_read_8_fc(m68000_base_device *m68k, UINT32 address, UINT32 fc) +{ + m68k->mmu_tmp_fc = fc; + m68k->mmu_tmp_rw = 1; + return m68k->/*memory.*/read8(address); +} +INLINE UINT32 m68ki_read_16_fc(m68000_base_device *m68k, UINT32 address, UINT32 fc) +{ + if (CPU_TYPE_IS_010_LESS(m68k->cpu_type)) + { + m68ki_check_address_error(m68k, address, MODE_READ, fc); + } + m68k->mmu_tmp_fc = fc; + m68k->mmu_tmp_rw = 1; + return m68k->/*memory.*/read16(address); +} +INLINE UINT32 m68ki_read_32_fc(m68000_base_device *m68k, UINT32 address, UINT32 fc) +{ + if (CPU_TYPE_IS_010_LESS(m68k->cpu_type)) + { + m68ki_check_address_error(m68k, address, MODE_READ, fc); + } + m68k->mmu_tmp_fc = fc; + m68k->mmu_tmp_rw = 1; + return m68k->/*memory.*/read32(address); +} + +INLINE void m68ki_write_8_fc(m68000_base_device *m68k, UINT32 address, UINT32 fc, UINT32 value) +{ + m68k->mmu_tmp_fc = fc; + m68k->mmu_tmp_rw = 0; + m68k->/*memory.*/write8(address, value); +} +INLINE void m68ki_write_16_fc(m68000_base_device *m68k, UINT32 address, UINT32 fc, UINT32 value) +{ + if (CPU_TYPE_IS_010_LESS(m68k->cpu_type)) + { + m68ki_check_address_error(m68k, address, MODE_WRITE, fc); + } + m68k->mmu_tmp_fc = fc; + m68k->mmu_tmp_rw = 0; + m68k->/*memory.*/write16(address, value); +} +INLINE void m68ki_write_32_fc(m68000_base_device *m68k, UINT32 address, UINT32 fc, UINT32 value) +{ + if (CPU_TYPE_IS_010_LESS(m68k->cpu_type)) + { + m68ki_check_address_error(m68k, address, MODE_WRITE, fc); + } + m68k->mmu_tmp_fc = fc; + m68k->mmu_tmp_rw = 0; + m68k->/*memory.*/write32(address, value); +} + +/* Special call to simulate undocumented 68k behavior when move.l with a + * predecrement destination mode is executed. + * A real 68k first writes the high word to [address+2], and then writes the + * low word to [address]. + */ +INLINE void m68ki_write_32_pd_fc(m68000_base_device *m68k, UINT32 address, UINT32 fc, UINT32 value) +{ + if (CPU_TYPE_IS_010_LESS(m68k->cpu_type)) + { + m68ki_check_address_error(m68k, address, MODE_WRITE, fc); + } + m68k->mmu_tmp_fc = fc; + m68k->mmu_tmp_rw = 0; + m68k->/*memory.*/write16(address+2, value>>16); + m68k->/*memory.*/write16(address, value&0xffff); +} + + +/* --------------------- Effective Address Calculation -------------------- */ + +/* The program counter relative addressing modes cause operands to be + * retrieved from program space, not data space. + */ +INLINE UINT32 m68ki_get_ea_pcdi(m68000_base_device *m68k) +{ + UINT32 old_pc = REG_PC(m68k); + return old_pc + MAKE_INT_16(m68ki_read_imm_16(m68k)); +} + + +INLINE UINT32 m68ki_get_ea_pcix(m68000_base_device *m68k) +{ + return m68ki_get_ea_ix(m68k, REG_PC(m68k)); +} + +/* Indexed addressing modes are encoded as follows: + * + * Base instruction format: + * F E D C B A 9 8 7 6 | 5 4 3 | 2 1 0 + * x x x x x x x x x x | 1 1 0 | BASE REGISTER (An) + * + * Base instruction format for destination EA in move instructions: + * F E D C | B A 9 | 8 7 6 | 5 4 3 2 1 0 + * x x x x | BASE REG | 1 1 0 | X X X X X X (An) + * + * Brief extension format: + * F | E D C | B | A 9 | 8 | 7 6 5 4 3 2 1 0 + * D/A | REGISTER | W/L | SCALE | 0 | DISPLACEMENT + * + * Full extension format: + * F E D C B A 9 8 7 6 5 4 3 2 1 0 + * D/A | REGISTER | W/L | SCALE | 1 | BS | IS | BD SIZE | 0 | I/IS + * BASE DISPLACEMENT (0, 16, 32 bit) (bd) + * OUTER DISPLACEMENT (0, 16, 32 bit) (od) + * + * D/A: 0 = Dn, 1 = An (Xn) + * W/L: 0 = W (sign extend), 1 = L (.SIZE) + * SCALE: 00=1, 01=2, 10=4, 11=8 (*SCALE) + * BS: 0=add base reg, 1=suppress base reg (An suppressed) + * IS: 0=add index, 1=suppress index (Xn suppressed) + * BD SIZE: 00=reserved, 01=NULL, 10=Word, 11=Long (size of bd) + * + * IS I/IS Operation + * 0 000 No Memory Indirect + * 0 001 indir prex with null outer + * 0 010 indir prex with word outer + * 0 011 indir prex with long outer + * 0 100 reserved + * 0 101 indir postx with null outer + * 0 110 indir postx with word outer + * 0 111 indir postx with long outer + * 1 000 no memory indirect + * 1 001 mem indir with null outer + * 1 010 mem indir with word outer + * 1 011 mem indir with long outer + * 1 100-111 reserved + */ +INLINE UINT32 m68ki_get_ea_ix(m68000_base_device *m68k, UINT32 An) +{ + /* An = base register */ + UINT32 extension = m68ki_read_imm_16(m68k); + UINT32 Xn = 0; /* Index register */ + UINT32 bd = 0; /* Base Displacement */ + UINT32 od = 0; /* Outer Displacement */ + + if(CPU_TYPE_IS_010_LESS(m68k->cpu_type)) + { + /* Calculate index */ + Xn = REG_DA(m68k)[extension>>12]; /* Xn */ + if(!BIT_B(extension)) /* W/L */ + Xn = MAKE_INT_16(Xn); + + /* Add base register and displacement and return */ + return An + Xn + MAKE_INT_8(extension); + } + + /* Brief extension format */ + if(!BIT_8(extension)) + { + /* Calculate index */ + Xn = REG_DA(m68k)[extension>>12]; /* Xn */ + if(!BIT_B(extension)) /* W/L */ + Xn = MAKE_INT_16(Xn); + /* Add scale if proper CPU type */ + if(CPU_TYPE_IS_EC020_PLUS(m68k->cpu_type)) + Xn <<= (extension>>9) & 3; /* SCALE */ + + /* Add base register and displacement and return */ + return An + Xn + MAKE_INT_8(extension); + } + + /* Full extension format */ + + m68k->remaining_cycles -= m68ki_ea_idx_cycle_table[extension&0x3f]; + + /* Check if base register is present */ + if(BIT_7(extension)) /* BS */ + An = 0; /* An */ + + /* Check if index is present */ + if(!BIT_6(extension)) /* IS */ + { + Xn = REG_DA(m68k)[extension>>12]; /* Xn */ + if(!BIT_B(extension)) /* W/L */ + Xn = MAKE_INT_16(Xn); + Xn <<= (extension>>9) & 3; /* SCALE */ + } + + /* Check if base displacement is present */ + if(BIT_5(extension)) /* BD SIZE */ + bd = BIT_4(extension) ? m68ki_read_imm_32(m68k) : MAKE_INT_16(m68ki_read_imm_16(m68k)); + + /* If no indirect action, we are done */ + if(!(extension&7)) /* No Memory Indirect */ + return An + bd + Xn; + + /* Check if outer displacement is present */ + if(BIT_1(extension)) /* I/IS: od */ + od = BIT_0(extension) ? m68ki_read_imm_32(m68k) : MAKE_INT_16(m68ki_read_imm_16(m68k)); + + /* Postindex */ + if(BIT_2(extension)) /* I/IS: 0 = preindex, 1 = postindex */ + return m68ki_read_32(m68k, An + bd) + Xn + od; + + /* Preindex */ + return m68ki_read_32(m68k, An + bd + Xn) + od; +} + + +/* Fetch operands */ +INLINE UINT32 OPER_AY_AI_8(m68000_base_device *m68k) {UINT32 ea = EA_AY_AI_8(m68k); return m68ki_read_8(m68k, ea); } +INLINE UINT32 OPER_AY_AI_16(m68000_base_device *m68k) {UINT32 ea = EA_AY_AI_16(m68k); return m68ki_read_16(m68k, ea);} +INLINE UINT32 OPER_AY_AI_32(m68000_base_device *m68k) {UINT32 ea = EA_AY_AI_32(m68k); return m68ki_read_32(m68k, ea);} +INLINE UINT32 OPER_AY_PI_8(m68000_base_device *m68k) {UINT32 ea = EA_AY_PI_8(m68k); return m68ki_read_8(m68k, ea); } +INLINE UINT32 OPER_AY_PI_16(m68000_base_device *m68k) {UINT32 ea = EA_AY_PI_16(m68k); return m68ki_read_16(m68k, ea);} +INLINE UINT32 OPER_AY_PI_32(m68000_base_device *m68k) {UINT32 ea = EA_AY_PI_32(m68k); return m68ki_read_32(m68k, ea);} +INLINE UINT32 OPER_AY_PD_8(m68000_base_device *m68k) {UINT32 ea = EA_AY_PD_8(m68k); return m68ki_read_8(m68k, ea); } +INLINE UINT32 OPER_AY_PD_16(m68000_base_device *m68k) {UINT32 ea = EA_AY_PD_16(m68k); return m68ki_read_16(m68k, ea);} +INLINE UINT32 OPER_AY_PD_32(m68000_base_device *m68k) {UINT32 ea = EA_AY_PD_32(m68k); return m68ki_read_32(m68k, ea);} +INLINE UINT32 OPER_AY_DI_8(m68000_base_device *m68k) {UINT32 ea = EA_AY_DI_8(m68k); return m68ki_read_8(m68k, ea); } +INLINE UINT32 OPER_AY_DI_16(m68000_base_device *m68k) {UINT32 ea = EA_AY_DI_16(m68k); return m68ki_read_16(m68k, ea);} +INLINE UINT32 OPER_AY_DI_32(m68000_base_device *m68k) {UINT32 ea = EA_AY_DI_32(m68k); return m68ki_read_32(m68k, ea);} +INLINE UINT32 OPER_AY_IX_8(m68000_base_device *m68k) {UINT32 ea = EA_AY_IX_8(m68k); return m68ki_read_8(m68k, ea); } +INLINE UINT32 OPER_AY_IX_16(m68000_base_device *m68k) {UINT32 ea = EA_AY_IX_16(m68k); return m68ki_read_16(m68k, ea);} +INLINE UINT32 OPER_AY_IX_32(m68000_base_device *m68k) {UINT32 ea = EA_AY_IX_32(m68k); return m68ki_read_32(m68k, ea);} + +INLINE UINT32 OPER_AX_AI_8(m68000_base_device *m68k) {UINT32 ea = EA_AX_AI_8(m68k); return m68ki_read_8(m68k, ea); } +INLINE UINT32 OPER_AX_AI_16(m68000_base_device *m68k) {UINT32 ea = EA_AX_AI_16(m68k); return m68ki_read_16(m68k, ea);} +INLINE UINT32 OPER_AX_AI_32(m68000_base_device *m68k) {UINT32 ea = EA_AX_AI_32(m68k); return m68ki_read_32(m68k, ea);} +INLINE UINT32 OPER_AX_PI_8(m68000_base_device *m68k) {UINT32 ea = EA_AX_PI_8(m68k); return m68ki_read_8(m68k, ea); } +INLINE UINT32 OPER_AX_PI_16(m68000_base_device *m68k) {UINT32 ea = EA_AX_PI_16(m68k); return m68ki_read_16(m68k, ea);} +INLINE UINT32 OPER_AX_PI_32(m68000_base_device *m68k) {UINT32 ea = EA_AX_PI_32(m68k); return m68ki_read_32(m68k, ea);} +INLINE UINT32 OPER_AX_PD_8(m68000_base_device *m68k) {UINT32 ea = EA_AX_PD_8(m68k); return m68ki_read_8(m68k, ea); } +INLINE UINT32 OPER_AX_PD_16(m68000_base_device *m68k) {UINT32 ea = EA_AX_PD_16(m68k); return m68ki_read_16(m68k, ea);} +INLINE UINT32 OPER_AX_PD_32(m68000_base_device *m68k) {UINT32 ea = EA_AX_PD_32(m68k); return m68ki_read_32(m68k, ea);} +INLINE UINT32 OPER_AX_DI_8(m68000_base_device *m68k) {UINT32 ea = EA_AX_DI_8(m68k); return m68ki_read_8(m68k, ea); } +INLINE UINT32 OPER_AX_DI_16(m68000_base_device *m68k) {UINT32 ea = EA_AX_DI_16(m68k); return m68ki_read_16(m68k, ea);} +INLINE UINT32 OPER_AX_DI_32(m68000_base_device *m68k) {UINT32 ea = EA_AX_DI_32(m68k); return m68ki_read_32(m68k, ea);} +INLINE UINT32 OPER_AX_IX_8(m68000_base_device *m68k) {UINT32 ea = EA_AX_IX_8(m68k); return m68ki_read_8(m68k, ea); } +INLINE UINT32 OPER_AX_IX_16(m68000_base_device *m68k) {UINT32 ea = EA_AX_IX_16(m68k); return m68ki_read_16(m68k, ea);} +INLINE UINT32 OPER_AX_IX_32(m68000_base_device *m68k) {UINT32 ea = EA_AX_IX_32(m68k); return m68ki_read_32(m68k, ea);} + +INLINE UINT32 OPER_A7_PI_8(m68000_base_device *m68k) {UINT32 ea = EA_A7_PI_8(m68k); return m68ki_read_8(m68k, ea); } +INLINE UINT32 OPER_A7_PD_8(m68000_base_device *m68k) {UINT32 ea = EA_A7_PD_8(m68k); return m68ki_read_8(m68k, ea); } + +INLINE UINT32 OPER_AW_8(m68000_base_device *m68k) {UINT32 ea = EA_AW_8(m68k); return m68ki_read_8(m68k, ea); } +INLINE UINT32 OPER_AW_16(m68000_base_device *m68k) {UINT32 ea = EA_AW_16(m68k); return m68ki_read_16(m68k, ea);} +INLINE UINT32 OPER_AW_32(m68000_base_device *m68k) {UINT32 ea = EA_AW_32(m68k); return m68ki_read_32(m68k, ea);} +INLINE UINT32 OPER_AL_8(m68000_base_device *m68k) {UINT32 ea = EA_AL_8(m68k); return m68ki_read_8(m68k, ea); } +INLINE UINT32 OPER_AL_16(m68000_base_device *m68k) {UINT32 ea = EA_AL_16(m68k); return m68ki_read_16(m68k, ea);} +INLINE UINT32 OPER_AL_32(m68000_base_device *m68k) {UINT32 ea = EA_AL_32(m68k); return m68ki_read_32(m68k, ea);} +INLINE UINT32 OPER_PCDI_8(m68000_base_device *m68k) {UINT32 ea = EA_PCDI_8(m68k); return m68ki_read_pcrel_8(m68k, ea); } +INLINE UINT32 OPER_PCDI_16(m68000_base_device *m68k) {UINT32 ea = EA_PCDI_16(m68k); return m68ki_read_pcrel_16(m68k, ea);} +INLINE UINT32 OPER_PCDI_32(m68000_base_device *m68k) {UINT32 ea = EA_PCDI_32(m68k); return m68ki_read_pcrel_32(m68k, ea);} +INLINE UINT32 OPER_PCIX_8(m68000_base_device *m68k) {UINT32 ea = EA_PCIX_8(m68k); return m68ki_read_pcrel_8(m68k, ea); } +INLINE UINT32 OPER_PCIX_16(m68000_base_device *m68k) {UINT32 ea = EA_PCIX_16(m68k); return m68ki_read_pcrel_16(m68k, ea);} +INLINE UINT32 OPER_PCIX_32(m68000_base_device *m68k) {UINT32 ea = EA_PCIX_32(m68k); return m68ki_read_pcrel_32(m68k, ea);} + + + +/* ---------------------------- Stack Functions --------------------------- */ + +/* Push/pull data from the stack */ +INLINE void m68ki_push_16(m68000_base_device *m68k, UINT32 value) +{ + REG_SP(m68k) = MASK_OUT_ABOVE_32(REG_SP(m68k) - 2); + m68ki_write_16(m68k, REG_SP(m68k), value); +} + +INLINE void m68ki_push_32(m68000_base_device *m68k, UINT32 value) +{ + REG_SP(m68k) = MASK_OUT_ABOVE_32(REG_SP(m68k) - 4); + m68ki_write_32(m68k, REG_SP(m68k), value); +} + +INLINE UINT32 m68ki_pull_16(m68000_base_device *m68k) +{ + REG_SP(m68k) = MASK_OUT_ABOVE_32(REG_SP(m68k) + 2); + return m68ki_read_16(m68k, REG_SP(m68k)-2); +} + +INLINE UINT32 m68ki_pull_32(m68000_base_device *m68k) +{ + REG_SP(m68k) = MASK_OUT_ABOVE_32(REG_SP(m68k) + 4); + return m68ki_read_32(m68k, REG_SP(m68k)-4); +} + + +/* Increment/decrement the stack as if doing a push/pull but + * don't do any memory access. + */ +INLINE void m68ki_fake_push_16(m68000_base_device *m68k) +{ + REG_SP(m68k) = MASK_OUT_ABOVE_32(REG_SP(m68k) - 2); +} + +INLINE void m68ki_fake_push_32(m68000_base_device *m68k) +{ + REG_SP(m68k) = MASK_OUT_ABOVE_32(REG_SP(m68k) - 4); +} + +INLINE void m68ki_fake_pull_16(m68000_base_device *m68k) +{ + REG_SP(m68k) = MASK_OUT_ABOVE_32(REG_SP(m68k) + 2); +} + +INLINE void m68ki_fake_pull_32(m68000_base_device *m68k) +{ + REG_SP(m68k) = MASK_OUT_ABOVE_32(REG_SP(m68k) + 4); +} + + +/* ----------------------------- Program Flow ----------------------------- */ + +/* Jump to a new program location or vector. + * These functions will also call the pc_changed callback if it was enabled + * in m68kconf.h. + */ +INLINE void m68ki_jump(m68000_base_device *m68k, UINT32 new_pc) +{ + REG_PC(m68k) = new_pc; +} + +INLINE void m68ki_jump_vector(m68000_base_device *m68k, UINT32 vector) +{ + REG_PC(m68k) = (vector<<2) + m68k->vbr; + REG_PC(m68k) = m68ki_read_data_32(m68k, REG_PC(m68k)); +} + + +/* Branch to a new memory location. + * The 32-bit branch will call pc_changed if it was enabled in m68kconf.h. + * So far I've found no problems with not calling pc_changed for 8 or 16 + * bit branches. + */ +INLINE void m68ki_branch_8(m68000_base_device *m68k, UINT32 offset) +{ + REG_PC(m68k) += MAKE_INT_8(offset); +} + +INLINE void m68ki_branch_16(m68000_base_device *m68k, UINT32 offset) +{ + REG_PC(m68k) += MAKE_INT_16(offset); +} + +INLINE void m68ki_branch_32(m68000_base_device *m68k, UINT32 offset) +{ + REG_PC(m68k) += offset; +} + + + +/* ---------------------------- Status Register --------------------------- */ + +/* Set the S flag and change the active stack pointer. + * Note that value MUST be 4 or 0. + */ +INLINE void m68ki_set_s_flag(m68000_base_device *m68k, UINT32 value) +{ + /* Backup the old stack pointer */ + REG_SP_BASE(m68k)[m68k->s_flag | ((m68k->s_flag>>1) & m68k->m_flag)] = REG_SP(m68k); + /* Set the S flag */ + m68k->s_flag = value; + /* Set the new stack pointer */ + REG_SP(m68k) = REG_SP_BASE(m68k)[m68k->s_flag | ((m68k->s_flag>>1) & m68k->m_flag)]; +} + +/* Set the S and M flags and change the active stack pointer. + * Note that value MUST be 0, 2, 4, or 6 (bit2 = S, bit1 = M). + */ +INLINE void m68ki_set_sm_flag(m68000_base_device *m68k, UINT32 value) +{ + /* Backup the old stack pointer */ + REG_SP_BASE(m68k)[m68k->s_flag | ((m68k->s_flag>>1) & m68k->m_flag)] = REG_SP(m68k); + /* Set the S and M flags */ + m68k->s_flag = value & SFLAG_SET; + m68k->m_flag = value & MFLAG_SET; + /* Set the new stack pointer */ + REG_SP(m68k) = REG_SP_BASE(m68k)[m68k->s_flag | ((m68k->s_flag>>1) & m68k->m_flag)]; +} + +/* Set the S and M flags. Don't touch the stack pointer. */ +INLINE void m68ki_set_sm_flag_nosp(m68000_base_device *m68k, UINT32 value) +{ + /* Set the S and M flags */ + m68k->s_flag = value & SFLAG_SET; + m68k->m_flag = value & MFLAG_SET; +} + + +/* Set the condition code register */ +INLINE void m68ki_set_ccr(m68000_base_device *m68k, UINT32 value) +{ + m68k->x_flag = BIT_4(value) << 4; + m68k->n_flag = BIT_3(value) << 4; + m68k->not_z_flag = !BIT_2(value); + m68k->v_flag = BIT_1(value) << 6; + m68k->c_flag = BIT_0(value) << 8; +} + +/* Set the status register but don't check for interrupts */ +INLINE void m68ki_set_sr_noint(m68000_base_device *m68k, UINT32 value) +{ + /* Mask out the "unimplemented" bits */ + value &= m68k->sr_mask; + + /* Now set the status register */ + m68k->t1_flag = BIT_F(value); + m68k->t0_flag = BIT_E(value); + m68k->int_mask = value & 0x0700; + m68ki_set_ccr(m68k, value); + m68ki_set_sm_flag(m68k, (value >> 11) & 6); +} + +/* Set the status register but don't check for interrupts nor + * change the stack pointer + */ +INLINE void m68ki_set_sr_noint_nosp(m68000_base_device *m68k, UINT32 value) +{ + /* Mask out the "unimplemented" bits */ + value &= m68k->sr_mask; + + /* Now set the status register */ + m68k->t1_flag = BIT_F(value); + m68k->t0_flag = BIT_E(value); + m68k->int_mask = value & 0x0700; + m68ki_set_ccr(m68k, value); + m68ki_set_sm_flag_nosp(m68k, (value >> 11) & 6); +} + +/* Set the status register and check for interrupts */ +INLINE void m68ki_set_sr(m68000_base_device *m68k, UINT32 value) +{ + m68ki_set_sr_noint(m68k, value); + m68ki_check_interrupts(m68k); +} + + +/* ------------------------- Exception Processing ------------------------- */ + +/* Initiate exception processing */ +INLINE UINT32 m68ki_init_exception(m68000_base_device *m68k) +{ + /* Save the old status register */ + UINT32 sr = m68ki_get_sr(m68k); + + /* Turn off trace flag, clear pending traces */ + m68k->t1_flag = m68k->t0_flag = 0; + m68ki_clear_trace(m68k); + /* Enter supervisor mode */ + m68ki_set_s_flag(m68k, SFLAG_SET); + + return sr; +} + +/* 3 word stack frame (68000 only) */ +INLINE void m68ki_stack_frame_3word(m68000_base_device *m68k, UINT32 pc, UINT32 sr) +{ + m68ki_push_32(m68k, pc); + m68ki_push_16(m68k, sr); +} + +/* Format 0 stack frame. + * This is the standard stack frame for 68010+. + */ +INLINE void m68ki_stack_frame_0000(m68000_base_device *m68k, UINT32 pc, UINT32 sr, UINT32 vector) +{ + /* Stack a 3-word frame if we are 68000 */ + if(m68k->cpu_type == CPU_TYPE_000 || m68k->cpu_type == CPU_TYPE_008) + { + m68ki_stack_frame_3word(m68k, pc, sr); + return; + } + m68ki_push_16(m68k, vector<<2); + m68ki_push_32(m68k, pc); + m68ki_push_16(m68k, sr); +} + +/* Format 1 stack frame (68020). + * For 68020, this is the 4 word throwaway frame. + */ +INLINE void m68ki_stack_frame_0001(m68000_base_device *m68k, UINT32 pc, UINT32 sr, UINT32 vector) +{ + m68ki_push_16(m68k, 0x1000 | (vector<<2)); + m68ki_push_32(m68k, pc); + m68ki_push_16(m68k, sr); +} + +/* Format 2 stack frame. + * This is used only by 68020 for trap exceptions. + */ +INLINE void m68ki_stack_frame_0010(m68000_base_device *m68k, UINT32 sr, UINT32 vector) +{ + m68ki_push_32(m68k, REG_PPC(m68k)); + m68ki_push_16(m68k, 0x2000 | (vector<<2)); + m68ki_push_32(m68k, REG_PC(m68k)); + m68ki_push_16(m68k, sr); +} + + +/* Bus error stack frame (68000 only). + */ +INLINE void m68ki_stack_frame_buserr(m68000_base_device *m68k, UINT32 sr) +{ + m68ki_push_32(m68k, REG_PC(m68k)); + m68ki_push_16(m68k, sr); + m68ki_push_16(m68k, m68k->ir); + m68ki_push_32(m68k, m68k->aerr_address); /* access address */ + /* 0 0 0 0 0 0 0 0 0 0 0 R/W I/N FC + * R/W 0 = write, 1 = read + * I/N 0 = instruction, 1 = not + * FC 3-bit function code + */ + m68ki_push_16(m68k, m68k->aerr_write_mode | m68k->instr_mode | m68k->aerr_fc); +} + +/* Format 8 stack frame (68010). + * 68010 only. This is the 29 word bus/address error frame. + */ +INLINE void m68ki_stack_frame_1000(m68000_base_device *m68k, UINT32 pc, UINT32 sr, UINT32 vector) +{ + /* VERSION + * NUMBER + * INTERNAL INFORMATION, 16 WORDS + */ + m68ki_fake_push_32(m68k); + m68ki_fake_push_32(m68k); + m68ki_fake_push_32(m68k); + m68ki_fake_push_32(m68k); + m68ki_fake_push_32(m68k); + m68ki_fake_push_32(m68k); + m68ki_fake_push_32(m68k); + m68ki_fake_push_32(m68k); + + /* INSTRUCTION INPUT BUFFER */ + m68ki_push_16(m68k, 0); + + /* UNUSED, RESERVED (not written) */ + m68ki_fake_push_16(m68k); + + /* DATA INPUT BUFFER */ + m68ki_push_16(m68k, 0); + + /* UNUSED, RESERVED (not written) */ + m68ki_fake_push_16(m68k); + + /* DATA OUTPUT BUFFER */ + m68ki_push_16(m68k, 0); + + /* UNUSED, RESERVED (not written) */ + m68ki_fake_push_16(m68k); + + /* FAULT ADDRESS */ + m68ki_push_32(m68k, 0); + + /* SPECIAL STATUS WORD */ + m68ki_push_16(m68k, 0); + + /* 1000, VECTOR OFFSET */ + m68ki_push_16(m68k, 0x8000 | (vector<<2)); + + /* PROGRAM COUNTER */ + m68ki_push_32(m68k, pc); + + /* STATUS REGISTER */ + m68ki_push_16(m68k, sr); +} + +/* Format A stack frame (short bus fault). + * This is used only by 68020 for bus fault and address error + * if the error happens at an instruction boundary. + * PC stacked is address of next instruction. + */ +INLINE void m68ki_stack_frame_1010(m68000_base_device *m68k, UINT32 sr, UINT32 vector, UINT32 pc, UINT32 fault_address) +{ + int orig_rw = m68k->mmu_tmp_buserror_rw; // this gets splatted by the following pushes, so save it now + int orig_fc = m68k->mmu_tmp_buserror_fc; + + /* INTERNAL REGISTER */ + m68ki_push_16(m68k, 0); + + /* INTERNAL REGISTER */ + m68ki_push_16(m68k, 0); + + /* DATA OUTPUT BUFFER (2 words) */ + m68ki_push_32(m68k, 0); + + /* INTERNAL REGISTER */ + m68ki_push_16(m68k, 0); + + /* INTERNAL REGISTER */ + m68ki_push_16(m68k, 0); + + /* DATA CYCLE FAULT ADDRESS (2 words) */ + m68ki_push_32(m68k, fault_address); + + /* INSTRUCTION PIPE STAGE B */ + m68ki_push_16(m68k, 0); + + /* INSTRUCTION PIPE STAGE C */ + m68ki_push_16(m68k, 0); + + /* SPECIAL STATUS REGISTER */ + // set bit for: Rerun Faulted bus Cycle, or run pending prefetch + // set FC + m68ki_push_16(m68k, 0x0100 | orig_fc | orig_rw<<6); + + /* INTERNAL REGISTER */ + m68ki_push_16(m68k, 0); + + /* 1010, VECTOR OFFSET */ + m68ki_push_16(m68k, 0xa000 | (vector<<2)); + + /* PROGRAM COUNTER */ + m68ki_push_32(m68k, pc); + + /* STATUS REGISTER */ + m68ki_push_16(m68k, sr); +} + +/* Format B stack frame (long bus fault). + * This is used only by 68020 for bus fault and address error + * if the error happens during instruction execution. + * PC stacked is address of instruction in progress. + */ +INLINE void m68ki_stack_frame_1011(m68000_base_device *m68k, UINT32 sr, UINT32 vector, UINT32 pc, UINT32 fault_address) +{ + int orig_rw = m68k->mmu_tmp_buserror_rw; // this gets splatted by the following pushes, so save it now + int orig_fc = m68k->mmu_tmp_buserror_fc; + + /* INTERNAL REGISTERS (18 words) */ + m68ki_push_32(m68k, 0); + m68ki_push_32(m68k, 0); + m68ki_push_32(m68k, 0); + m68ki_push_32(m68k, 0); + m68ki_push_32(m68k, 0); + m68ki_push_32(m68k, 0); + m68ki_push_32(m68k, 0); + m68ki_push_32(m68k, 0); + m68ki_push_32(m68k, 0); + + /* VERSION# (4 bits), INTERNAL INFORMATION */ + m68ki_push_16(m68k, 0); + + /* INTERNAL REGISTERS (3 words) */ + m68ki_push_32(m68k, 0); + m68ki_push_16(m68k, 0); + + /* DATA INTPUT BUFFER (2 words) */ + m68ki_push_32(m68k, 0); + + /* INTERNAL REGISTERS (2 words) */ + m68ki_push_32(m68k, 0); + + /* STAGE B ADDRESS (2 words) */ + m68ki_push_32(m68k, 0); + + /* INTERNAL REGISTER (4 words) */ + m68ki_push_32(m68k, 0); + m68ki_push_32(m68k, 0); + + /* DATA OUTPUT BUFFER (2 words) */ + m68ki_push_32(m68k, 0); + + /* INTERNAL REGISTER */ + m68ki_push_16(m68k, 0); + + /* INTERNAL REGISTER */ + m68ki_push_16(m68k, 0); + + /* DATA CYCLE FAULT ADDRESS (2 words) */ + m68ki_push_32(m68k, fault_address); + + /* INSTRUCTION PIPE STAGE B */ + m68ki_push_16(m68k, 0); + + /* INSTRUCTION PIPE STAGE C */ + m68ki_push_16(m68k, 0); + + /* SPECIAL STATUS REGISTER */ + m68ki_push_16(m68k, 0x0100 | orig_fc | orig_rw<<6); + + /* INTERNAL REGISTER */ + m68ki_push_16(m68k, 0); + + /* 1011, VECTOR OFFSET */ + m68ki_push_16(m68k, 0xb000 | (vector<<2)); + + /* PROGRAM COUNTER */ + m68ki_push_32(m68k, pc); + + /* STATUS REGISTER */ + m68ki_push_16(m68k, sr); +} + +/* Type 7 stack frame (access fault). + * This is used by the 68040 for bus fault and mmu trap + * 30 words + */ +INLINE void m68ki_stack_frame_0111(m68000_base_device *m68k, UINT32 sr, UINT32 vector, UINT32 pc, UINT32 fault_address, bool in_mmu) +{ + int orig_rw = m68k->mmu_tmp_buserror_rw; // this gets splatted by the following pushes, so save it now + int orig_fc = m68k->mmu_tmp_buserror_fc; + + /* INTERNAL REGISTERS (18 words) */ + m68ki_push_32(m68k, 0); + m68ki_push_32(m68k, 0); + m68ki_push_32(m68k, 0); + m68ki_push_32(m68k, 0); + m68ki_push_32(m68k, 0); + m68ki_push_32(m68k, 0); + m68ki_push_32(m68k, 0); + m68ki_push_32(m68k, 0); + m68ki_push_32(m68k, 0); + + /* FAULT ADDRESS (2 words) */ + m68ki_push_32(m68k, fault_address); + + /* INTERNAL REGISTERS (3 words) */ + m68ki_push_32(m68k, 0); + m68ki_push_16(m68k, 0); + + /* SPECIAL STATUS REGISTER (1 word) */ + m68ki_push_16(m68k, (in_mmu ? 0x400 : 0) | orig_fc | (orig_rw<<8)); + + /* EFFECTIVE ADDRESS (2 words) */ + m68ki_push_32(m68k, fault_address); + + /* 0111, VECTOR OFFSET (1 word) */ + m68ki_push_16(m68k, 0x7000 | (vector<<2)); + + /* PROGRAM COUNTER (2 words) */ + m68ki_push_32(m68k, pc); + + /* STATUS REGISTER (1 word) */ + m68ki_push_16(m68k, sr); +} + + +/* Used for Group 2 exceptions. + * These stack a type 2 frame on the 020. + */ +INLINE void m68ki_exception_trap(m68000_base_device *m68k, UINT32 vector) +{ + UINT32 sr = m68ki_init_exception(m68k); + + if(CPU_TYPE_IS_010_LESS(m68k->cpu_type)) + m68ki_stack_frame_0000(m68k, REG_PC(m68k), sr, vector); + else + m68ki_stack_frame_0010(m68k, sr, vector); + + m68ki_jump_vector(m68k, vector); + + /* Use up some clock cycles */ + m68k->remaining_cycles -= m68k->cyc_exception[vector]; +} + +/* Trap#n stacks a 0 frame but behaves like group2 otherwise */ +INLINE void m68ki_exception_trapN(m68000_base_device *m68k, UINT32 vector) +{ + UINT32 sr = m68ki_init_exception(m68k); + m68ki_stack_frame_0000(m68k, REG_PC(m68k), sr, vector); + m68ki_jump_vector(m68k, vector); + + /* Use up some clock cycles */ + m68k->remaining_cycles -= m68k->cyc_exception[vector]; +} + +/* Exception for trace mode */ +INLINE void m68ki_exception_trace(m68000_base_device *m68k) +{ + UINT32 sr = m68ki_init_exception(m68k); + + if(CPU_TYPE_IS_010_LESS(m68k->cpu_type)) + { + if(CPU_TYPE_IS_000(m68k->cpu_type)) + { + m68k->instr_mode = INSTRUCTION_NO; + } + m68ki_stack_frame_0000(m68k, REG_PC(m68k), sr, EXCEPTION_TRACE); + } + else + m68ki_stack_frame_0010(m68k, sr, EXCEPTION_TRACE); + + m68ki_jump_vector(m68k, EXCEPTION_TRACE); + + /* Trace nullifies a STOP instruction */ + m68k->stopped &= ~STOP_LEVEL_STOP; + + /* Use up some clock cycles */ + m68k->remaining_cycles -= m68k->cyc_exception[EXCEPTION_TRACE]; +} + +/* Exception for privilege violation */ +INLINE void m68ki_exception_privilege_violation(m68000_base_device *m68k) +{ + UINT32 sr = m68ki_init_exception(m68k); + + if(CPU_TYPE_IS_000(m68k->cpu_type)) + { + m68k->instr_mode = INSTRUCTION_NO; + } + + m68ki_stack_frame_0000(m68k, REG_PPC(m68k), sr, EXCEPTION_PRIVILEGE_VIOLATION); + m68ki_jump_vector(m68k, EXCEPTION_PRIVILEGE_VIOLATION); + + /* Use up some clock cycles and undo the instruction's cycles */ + m68k->remaining_cycles -= m68k->cyc_exception[EXCEPTION_PRIVILEGE_VIOLATION] - m68k->cyc_instruction[m68k->ir]; +} + +/* Exception for A-Line instructions */ +INLINE void m68ki_exception_1010(m68000_base_device *m68k) +{ + UINT32 sr; + + sr = m68ki_init_exception(m68k); + m68ki_stack_frame_0000(m68k, REG_PPC(m68k), sr, EXCEPTION_1010); + m68ki_jump_vector(m68k, EXCEPTION_1010); + + /* Use up some clock cycles and undo the instruction's cycles */ + m68k->remaining_cycles -= m68k->cyc_exception[EXCEPTION_1010] - m68k->cyc_instruction[m68k->ir]; +} + +/* Exception for F-Line instructions */ +INLINE void m68ki_exception_1111(m68000_base_device *m68k) +{ + UINT32 sr; + + sr = m68ki_init_exception(m68k); + m68ki_stack_frame_0000(m68k, REG_PPC(m68k), sr, EXCEPTION_1111); + m68ki_jump_vector(m68k, EXCEPTION_1111); + + /* Use up some clock cycles and undo the instruction's cycles */ + m68k->remaining_cycles -= m68k->cyc_exception[EXCEPTION_1111] - m68k->cyc_instruction[m68k->ir]; +} + +/* Exception for illegal instructions */ +INLINE void m68ki_exception_illegal(m68000_base_device *m68k) +{ + UINT32 sr; + + sr = m68ki_init_exception(m68k); + + if(CPU_TYPE_IS_000(m68k->cpu_type)) + { + m68k->instr_mode = INSTRUCTION_NO; + } + + m68ki_stack_frame_0000(m68k, REG_PPC(m68k), sr, EXCEPTION_ILLEGAL_INSTRUCTION); + m68ki_jump_vector(m68k, EXCEPTION_ILLEGAL_INSTRUCTION); + + /* Use up some clock cycles and undo the instruction's cycles */ + m68k->remaining_cycles -= m68k->cyc_exception[EXCEPTION_ILLEGAL_INSTRUCTION] - m68k->cyc_instruction[m68k->ir]; +} + +/* Exception for format errror in RTE */ +INLINE void m68ki_exception_format_error(m68000_base_device *m68k) +{ + UINT32 sr = m68ki_init_exception(m68k); + m68ki_stack_frame_0000(m68k, REG_PC(m68k), sr, EXCEPTION_FORMAT_ERROR); + m68ki_jump_vector(m68k, EXCEPTION_FORMAT_ERROR); + + /* Use up some clock cycles and undo the instruction's cycles */ + m68k->remaining_cycles -= m68k->cyc_exception[EXCEPTION_FORMAT_ERROR] - m68k->cyc_instruction[m68k->ir]; +} + +/* Exception for address error */ +INLINE void m68ki_exception_address_error(m68000_base_device *m68k) +{ + UINT32 sr = m68ki_init_exception(m68k); + + /* If we were processing a bus error, address error, or reset, + * this is a catastrophic failure. + * Halt the CPU + */ + if(m68k->run_mode == RUN_MODE_BERR_AERR_RESET) + { + m68k->/*memory.*/read8(0x00ffff01); + m68k->stopped = STOP_LEVEL_HALT; + return; + } + m68k->run_mode = RUN_MODE_BERR_AERR_RESET; + + /* Note: This is implemented for 68000 only! */ + m68ki_stack_frame_buserr(m68k, sr); + + m68ki_jump_vector(m68k, EXCEPTION_ADDRESS_ERROR); + + /* Use up some clock cycles and undo the instruction's cycles */ + m68k->remaining_cycles -= m68k->cyc_exception[EXCEPTION_ADDRESS_ERROR] - m68k->cyc_instruction[m68k->ir]; +} + + + +/* ASG: Check for interrupts */ +INLINE void m68ki_check_interrupts(m68000_base_device *m68k) +{ + if(m68k->nmi_pending) + { + m68k->nmi_pending = FALSE; + m68k->m68ki_exception_interrupt(m68k, 7); + } + else if(m68k->int_level > m68k->int_mask) + m68k->m68ki_exception_interrupt(m68k, m68k->int_level>>8); +} + + + +/* ======================================================================== */ +/* ============================== END OF FILE ============================= */ +/* ======================================================================== */ + +#endif /* __M68KCPU_H__ */ diff --git a/src/devices/cpu/m68000/m68kdasm.c b/src/devices/cpu/m68000/m68kdasm.c new file mode 100644 index 00000000000..e82d5c7111a --- /dev/null +++ b/src/devices/cpu/m68000/m68kdasm.c @@ -0,0 +1,4157 @@ +// license:BSD-3-Clause +// copyright-holders:Karl Stenerud +/* ======================================================================== */ +/* ========================= LICENSING & COPYRIGHT ======================== */ +/* ======================================================================== */ +/* + * MUSASHI + * Version 3.32 + * + * A portable Motorola M680x0 processor emulation engine. + * Copyright Karl Stenerud. All rights reserved. + * + */ + + + +/* ======================================================================== */ +/* ================================ INCLUDES ============================== */ +/* ======================================================================== */ + +#define m68ki_cpu_core void +#include "emu.h" +#include "m68000.h" + +#ifndef DECL_SPEC +#define DECL_SPEC +#endif + +/* ======================================================================== */ +/* ============================ GENERAL DEFINES =========================== */ +/* ======================================================================== */ + +/* unsigned int and int must be at least 32 bits wide */ +#undef UINT32 +#define UINT32 unsigned int + +/* Bit Isolation Functions */ +#define BIT_0(A) ((A) & 0x00000001) +#define BIT_1(A) ((A) & 0x00000002) +#define BIT_2(A) ((A) & 0x00000004) +#define BIT_3(A) ((A) & 0x00000008) +#define BIT_4(A) ((A) & 0x00000010) +#define BIT_5(A) ((A) & 0x00000020) +#define BIT_6(A) ((A) & 0x00000040) +#define BIT_7(A) ((A) & 0x00000080) +#define BIT_8(A) ((A) & 0x00000100) +#define BIT_9(A) ((A) & 0x00000200) +#define BIT_A(A) ((A) & 0x00000400) +#define BIT_B(A) ((A) & 0x00000800) +#define BIT_C(A) ((A) & 0x00001000) +#define BIT_D(A) ((A) & 0x00002000) +#define BIT_E(A) ((A) & 0x00004000) +#define BIT_F(A) ((A) & 0x00008000) +#define BIT_10(A) ((A) & 0x00010000) +#define BIT_11(A) ((A) & 0x00020000) +#define BIT_12(A) ((A) & 0x00040000) +#define BIT_13(A) ((A) & 0x00080000) +#define BIT_14(A) ((A) & 0x00100000) +#define BIT_15(A) ((A) & 0x00200000) +#define BIT_16(A) ((A) & 0x00400000) +#define BIT_17(A) ((A) & 0x00800000) +#define BIT_18(A) ((A) & 0x01000000) +#define BIT_19(A) ((A) & 0x02000000) +#define BIT_1A(A) ((A) & 0x04000000) +#define BIT_1B(A) ((A) & 0x08000000) +#define BIT_1C(A) ((A) & 0x10000000) +#define BIT_1D(A) ((A) & 0x20000000) +#define BIT_1E(A) ((A) & 0x40000000) +#define BIT_1F(A) ((A) & 0x80000000) + +/* These are the CPU types understood by this disassembler */ +#define TYPE_68000 1 +#define TYPE_68008 2 +#define TYPE_68010 4 +#define TYPE_68020 8 +#define TYPE_68030 16 +#define TYPE_68040 32 +#define TYPE_68340 64 // (CPU32) +#define TYPE_COLDFIRE 128 + +#define M68000_ONLY (TYPE_68000 | TYPE_68008) + +#define M68010_ONLY TYPE_68010 +#define M68010_LESS (TYPE_68000 | TYPE_68008 | TYPE_68010) +#define M68010_PLUS (TYPE_68010 | TYPE_68020 | TYPE_68030 | TYPE_68040 | TYPE_68340 | TYPE_COLDFIRE) + +#define M68020_ONLY (TYPE_68020 | TYPE_68340) +#define M68020_LESS (TYPE_68010 | TYPE_68020 | TYPE_68340) +#define M68020_PLUS (TYPE_68020 | TYPE_68030 | TYPE_68040 | TYPE_68340 | TYPE_COLDFIRE) + +#define M68030_ONLY TYPE_68030 +#define M68030_LESS (TYPE_68010 | TYPE_68020 | TYPE_68030 | TYPE_68340 ) +#define M68030_PLUS (TYPE_68030 | TYPE_68040) + +#define M68040_PLUS TYPE_68040 + +#define COLDFIRE TYPE_COLDFIRE + +/* Extension word formats */ +#define EXT_8BIT_DISPLACEMENT(A) ((A)&0xff) +#define EXT_FULL(A) BIT_8(A) +#define EXT_EFFECTIVE_ZERO(A) (((A)&0xe4) == 0xc4 || ((A)&0xe2) == 0xc0) +#define EXT_BASE_REGISTER_PRESENT(A) (!BIT_7(A)) +#define EXT_INDEX_REGISTER_PRESENT(A) (!BIT_6(A)) +#define EXT_INDEX_REGISTER(A) (((A)>>12)&7) +#define EXT_INDEX_PRE_POST(A) (EXT_INDEX_PRESENT(A) && (A)&3) +#define EXT_INDEX_PRE(A) (EXT_INDEX_PRESENT(A) && ((A)&7) < 4 && ((A)&7) != 0) +#define EXT_INDEX_POST(A) (EXT_INDEX_PRESENT(A) && ((A)&7) > 4) +#define EXT_INDEX_SCALE(A) (((A)>>9)&3) +#define EXT_INDEX_LONG(A) BIT_B(A) +#define EXT_INDEX_AR(A) BIT_F(A) +#define EXT_BASE_DISPLACEMENT_PRESENT(A) (((A)&0x30) > 0x10) +#define EXT_BASE_DISPLACEMENT_WORD(A) (((A)&0x30) == 0x20) +#define EXT_BASE_DISPLACEMENT_LONG(A) (((A)&0x30) == 0x30) +#define EXT_OUTER_DISPLACEMENT_PRESENT(A) (((A)&3) > 1 && ((A)&0x47) < 0x44) +#define EXT_OUTER_DISPLACEMENT_WORD(A) (((A)&3) == 2 && ((A)&0x47) < 0x44) +#define EXT_OUTER_DISPLACEMENT_LONG(A) (((A)&3) == 3 && ((A)&0x47) < 0x44) + + +/* Opcode flags */ +#define SET_OPCODE_FLAGS(x) g_opcode_type = x; +#define COMBINE_OPCODE_FLAGS(x) ((x) | g_opcode_type | DASMFLAG_SUPPORTED) + + +/* ======================================================================== */ +/* =============================== PROTOTYPES ============================= */ +/* ======================================================================== */ + +/* Read data at the PC and increment PC */ +UINT32 read_imm_8(void); +UINT32 read_imm_16(void); +UINT32 read_imm_32(void); + +/* Read data at the PC but don't imcrement the PC */ +UINT32 peek_imm_8(void); +UINT32 peek_imm_16(void); +UINT32 peek_imm_32(void); + +/* make signed integers 100% portably */ +static int make_int_8(int value); +static int make_int_16(int value); +static int make_int_32(int value); + +/* make a string of a hex value */ +static char* make_signed_hex_str_8(UINT32 val); +static char* make_signed_hex_str_16(UINT32 val); +static char* make_signed_hex_str_32(UINT32 val); + +/* make string of ea mode */ +static char* get_ea_mode_str(UINT32 instruction, UINT32 size); + +char* get_ea_mode_str_8(UINT32 instruction); +char* get_ea_mode_str_16(UINT32 instruction); +char* get_ea_mode_str_32(UINT32 instruction); + +/* make string of immediate value */ +static char* get_imm_str_s(UINT32 size); +static char* get_imm_str_u(UINT32 size); + +char* get_imm_str_s8(void); +char* get_imm_str_s16(void); +char* get_imm_str_s32(void); + +/* Stuff to build the opcode handler jump table */ +static void build_opcode_table(void); +static int valid_ea(UINT32 opcode, UINT32 mask); +static int DECL_SPEC compare_nof_true_bits(const void *aptr, const void *bptr); + +/* used to build opcode handler jump table */ +struct opcode_struct +{ + void (*opcode_handler)(void); /* handler function */ + UINT32 mask; /* mask on opcode */ + UINT32 match; /* what to match after masking */ + UINT32 ea_mask; /* what ea modes are allowed */ +}; + + + +/* ======================================================================== */ +/* ================================= DATA ================================= */ +/* ======================================================================== */ + +/* Opcode handler jump table */ +static void (*g_instruction_table[0x10000])(void); +/* Flag if disassembler initialized */ +static int g_initialized = 0; + +static char g_dasm_str[100]; /* string to hold disassembly */ +static char g_helper_str[100]; /* string to hold helpful info */ +static UINT32 g_cpu_pc; /* program counter */ +static UINT32 g_cpu_ir; /* instruction register */ +static UINT32 g_cpu_type; +static UINT32 g_opcode_type; +static const unsigned char* g_rawop; +static UINT32 g_rawbasepc; + +/* used by ops like asr, ror, addq, etc */ +static const UINT32 g_3bit_qdata_table[8] = {8, 1, 2, 3, 4, 5, 6, 7}; + +static const UINT32 g_5bit_data_table[32] = +{ + 32, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31 +}; + +static const char *const g_cc[16] = +{"t", "f", "hi", "ls", "cc", "cs", "ne", "eq", "vc", "vs", "pl", "mi", "ge", "lt", "gt", "le"}; + +static const char *const g_cpcc[64] = +{/* 000 001 010 011 100 101 110 111 */ + "f", "eq", "ogt", "oge", "olt", "ole", "ogl", "or", /* 000 */ + "un", "ueq", "ugt", "uge", "ult", "ule", "ne", "t", /* 001 */ + "sf", "seq", "gt", "ge", "lt", "le", "gl" "gle", /* 010 */ + "ngle", "ngl", "nle", "nlt", "nge", "ngt", "sne", "st", /* 011 */ + "?", "?", "?", "?", "?", "?", "?", "?", /* 100 */ + "?", "?", "?", "?", "?", "?", "?", "?", /* 101 */ + "?", "?", "?", "?", "?", "?", "?", "?", /* 110 */ + "?", "?", "?", "?", "?", "?", "?", "?" /* 111 */ +}; + +static const char *const g_mmuregs[8] = +{ + "tc", "drp", "srp", "crp", "cal", "val", "sccr", "acr" +}; + +static const char *const g_mmucond[16] = +{ + "bs", "bc", "ls", "lc", "ss", "sc", "as", "ac", + "ws", "wc", "is", "ic", "gs", "gc", "cs", "cc" +}; + +/* ======================================================================== */ +/* =========================== UTILITY FUNCTIONS ========================== */ +/* ======================================================================== */ + +#define LIMIT_CPU_TYPES(ALLOWED_CPU_TYPES) \ + if(!(g_cpu_type & ALLOWED_CPU_TYPES)) \ + { \ + if((g_cpu_ir & 0xf000) == 0xf000) \ + d68000_1111(); \ + else d68000_illegal(); \ + return; \ + } + +static UINT32 dasm_read_imm_8(UINT32 advance) +{ + UINT32 result; + result = g_rawop[g_cpu_pc + 1 - g_rawbasepc]; + g_cpu_pc += advance; + return result; +} + +static UINT32 dasm_read_imm_16(UINT32 advance) +{ + UINT32 result; + result = (g_rawop[g_cpu_pc + 0 - g_rawbasepc] << 8) | + g_rawop[g_cpu_pc + 1 - g_rawbasepc]; + g_cpu_pc += advance; + return result; +} + +static UINT32 dasm_read_imm_32(UINT32 advance) +{ + UINT32 result; + result = (g_rawop[g_cpu_pc + 0 - g_rawbasepc] << 24) | + (g_rawop[g_cpu_pc + 1 - g_rawbasepc] << 16) | + (g_rawop[g_cpu_pc + 2 - g_rawbasepc] << 8) | + g_rawop[g_cpu_pc + 3 - g_rawbasepc]; + g_cpu_pc += advance; + return result; +} + +#define read_imm_8() dasm_read_imm_8(2) +#define read_imm_16() dasm_read_imm_16(2) +#define read_imm_32() dasm_read_imm_32(4) + +#define peek_imm_8() dasm_read_imm_8(0) +#define peek_imm_16() dasm_read_imm_16(0) +#define peek_imm_32() dasm_read_imm_32(0) + +/* Fake a split interface */ +#define get_ea_mode_str_8(instruction) get_ea_mode_str(instruction, 0) +#define get_ea_mode_str_16(instruction) get_ea_mode_str(instruction, 1) +#define get_ea_mode_str_32(instruction) get_ea_mode_str(instruction, 2) + +#define get_imm_str_s8() get_imm_str_s(0) +#define get_imm_str_s16() get_imm_str_s(1) +#define get_imm_str_s32() get_imm_str_s(2) + +#define get_imm_str_u8() get_imm_str_u(0) +#define get_imm_str_u16() get_imm_str_u(1) +#define get_imm_str_u32() get_imm_str_u(2) + +static int sext_7bit_int(int value) +{ + return (value & 0x40) ? (value | 0xffffff80) : (value & 0x7f); +} + + +/* 100% portable signed int generators */ +static int make_int_8(int value) +{ + return (value & 0x80) ? value | ~0xff : value & 0xff; +} + +static int make_int_16(int value) +{ + return (value & 0x8000) ? value | ~0xffff : value & 0xffff; +} + +static int make_int_32(int value) +{ + return (value & 0x80000000) ? value | ~0xffffffff : value & 0xffffffff; +} + +/* Get string representation of hex values */ +static char* make_signed_hex_str_8(UINT32 val) +{ + static char str[20]; + + val &= 0xff; + + if(val == 0x80) + sprintf(str, "-$80"); + else if(val & 0x80) + sprintf(str, "-$%x", (0-val) & 0x7f); + else + sprintf(str, "$%x", val & 0x7f); + + return str; +} + +static char* make_signed_hex_str_16(UINT32 val) +{ + static char str[20]; + + val &= 0xffff; + + if(val == 0x8000) + sprintf(str, "-$8000"); + else if(val & 0x8000) + sprintf(str, "-$%x", (0-val) & 0x7fff); + else + sprintf(str, "$%x", val & 0x7fff); + + return str; +} + +static char* make_signed_hex_str_32(UINT32 val) +{ + static char str[20]; + + val &= 0xffffffff; + + if(val == 0x80000000) + sprintf(str, "-$80000000"); + else if(val & 0x80000000) + sprintf(str, "-$%x", (0-val) & 0x7fffffff); + else + sprintf(str, "$%x", val & 0x7fffffff); + + return str; +} + + +/* make string of immediate value */ +static char* get_imm_str_s(UINT32 size) +{ + static char str[15]; + if(size == 0) + sprintf(str, "#%s", make_signed_hex_str_8(read_imm_8())); + else if(size == 1) + sprintf(str, "#%s", make_signed_hex_str_16(read_imm_16())); + else + sprintf(str, "#%s", make_signed_hex_str_32(read_imm_32())); + return str; +} + +static char* get_imm_str_u(UINT32 size) +{ + static char str[15]; + if(size == 0) + sprintf(str, "#$%x", read_imm_8() & 0xff); + else if(size == 1) + sprintf(str, "#$%x", read_imm_16() & 0xffff); + else + sprintf(str, "#$%x", read_imm_32() & 0xffffffff); + return str; +} + +/* Make string of effective address mode */ +static char* get_ea_mode_str(UINT32 instruction, UINT32 size) +{ + static char b1[64]; + static char b2[64]; + static char* mode = b2; + UINT32 extension; + UINT32 base; + UINT32 outer; + char base_reg[4]; + char index_reg[8]; + UINT32 preindex; + UINT32 postindex; + UINT32 comma = 0; + UINT32 temp_value; + char invalid_mode = 0; + + /* Switch buffers so we don't clobber on a double-call to this function */ + mode = mode == b1 ? b2 : b1; + + switch(instruction & 0x3f) + { + case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: + /* data register direct */ + sprintf(mode, "D%d", instruction&7); + break; + case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f: + /* address register direct */ + sprintf(mode, "A%d", instruction&7); + break; + case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17: + /* address register indirect */ + sprintf(mode, "(A%d)", instruction&7); + break; + case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f: + /* address register indirect with postincrement */ + sprintf(mode, "(A%d)+", instruction&7); + break; + case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27: + /* address register indirect with predecrement */ + sprintf(mode, "-(A%d)", instruction&7); + break; + case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: case 0x2f: + /* address register indirect with displacement*/ + sprintf(mode, "(%s,A%d)", make_signed_hex_str_16(read_imm_16()), instruction&7); + break; + case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37: + /* address register indirect with index */ + extension = read_imm_16(); + + if((g_cpu_type & M68010_LESS) && EXT_INDEX_SCALE(extension)) + { + invalid_mode = 1; + break; + } + + if(EXT_FULL(extension)) + { + if(g_cpu_type & M68010_LESS) + { + invalid_mode = 1; + break; + } + + if(EXT_EFFECTIVE_ZERO(extension)) + { + strcpy(mode, "0"); + break; + } + + base = EXT_BASE_DISPLACEMENT_PRESENT(extension) ? (EXT_BASE_DISPLACEMENT_LONG(extension) ? read_imm_32() : read_imm_16()) : 0; + outer = EXT_OUTER_DISPLACEMENT_PRESENT(extension) ? (EXT_OUTER_DISPLACEMENT_LONG(extension) ? read_imm_32() : read_imm_16()) : 0; + if(EXT_BASE_REGISTER_PRESENT(extension)) + sprintf(base_reg, "A%d", instruction&7); + else + *base_reg = 0; + if(EXT_INDEX_REGISTER_PRESENT(extension)) + { + sprintf(index_reg, "%c%d.%c", EXT_INDEX_AR(extension) ? 'A' : 'D', EXT_INDEX_REGISTER(extension), EXT_INDEX_LONG(extension) ? 'l' : 'w'); + if(EXT_INDEX_SCALE(extension)) + sprintf(index_reg+strlen(index_reg), "*%d", 1 << EXT_INDEX_SCALE(extension)); + } + else + *index_reg = 0; + preindex = (extension&7) > 0 && (extension&7) < 4; + postindex = (extension&7) > 4; + + strcpy(mode, "("); + if(preindex || postindex) + strcat(mode, "["); + if(base) + { + if (EXT_BASE_DISPLACEMENT_LONG(extension)) + { + strcat(mode, make_signed_hex_str_32(base)); + } + else + { + strcat(mode, make_signed_hex_str_16(base)); + } + comma = 1; + } + if(*base_reg) + { + if(comma) + strcat(mode, ","); + strcat(mode, base_reg); + comma = 1; + } + if(postindex) + { + strcat(mode, "]"); + comma = 1; + } + if(*index_reg) + { + if(comma) + strcat(mode, ","); + strcat(mode, index_reg); + comma = 1; + } + if(preindex) + { + strcat(mode, "]"); + comma = 1; + } + if(outer) + { + if(comma) + strcat(mode, ","); + strcat(mode, make_signed_hex_str_16(outer)); + } + strcat(mode, ")"); + break; + } + + if(EXT_8BIT_DISPLACEMENT(extension) == 0) + sprintf(mode, "(A%d,%c%d.%c", instruction&7, EXT_INDEX_AR(extension) ? 'A' : 'D', EXT_INDEX_REGISTER(extension), EXT_INDEX_LONG(extension) ? 'l' : 'w'); + else + sprintf(mode, "(%s,A%d,%c%d.%c", make_signed_hex_str_8(extension), instruction&7, EXT_INDEX_AR(extension) ? 'A' : 'D', EXT_INDEX_REGISTER(extension), EXT_INDEX_LONG(extension) ? 'l' : 'w'); + if(EXT_INDEX_SCALE(extension)) + sprintf(mode+strlen(mode), "*%d", 1 << EXT_INDEX_SCALE(extension)); + strcat(mode, ")"); + break; + case 0x38: + /* absolute short address */ + sprintf(mode, "$%x.w", read_imm_16()); + break; + case 0x39: + /* absolute long address */ + sprintf(mode, "$%x.l", read_imm_32()); + break; + case 0x3a: + /* program counter with displacement */ + temp_value = read_imm_16(); + sprintf(mode, "(%s,PC)", make_signed_hex_str_16(temp_value)); + sprintf(g_helper_str, "; ($%x)", (make_int_16(temp_value) + g_cpu_pc-2) & 0xffffffff); + break; + case 0x3b: + /* program counter with index */ + extension = read_imm_16(); + + if((g_cpu_type & M68010_LESS) && EXT_INDEX_SCALE(extension)) + { + invalid_mode = 1; + break; + } + + if(EXT_FULL(extension)) + { + if(g_cpu_type & M68010_LESS) + { + invalid_mode = 1; + break; + } + + if(EXT_EFFECTIVE_ZERO(extension)) + { + strcpy(mode, "0"); + break; + } + base = EXT_BASE_DISPLACEMENT_PRESENT(extension) ? (EXT_BASE_DISPLACEMENT_LONG(extension) ? read_imm_32() : read_imm_16()) : 0; + outer = EXT_OUTER_DISPLACEMENT_PRESENT(extension) ? (EXT_OUTER_DISPLACEMENT_LONG(extension) ? read_imm_32() : read_imm_16()) : 0; + if(EXT_BASE_REGISTER_PRESENT(extension)) + strcpy(base_reg, "PC"); + else + *base_reg = 0; + if(EXT_INDEX_REGISTER_PRESENT(extension)) + { + sprintf(index_reg, "%c%d.%c", EXT_INDEX_AR(extension) ? 'A' : 'D', EXT_INDEX_REGISTER(extension), EXT_INDEX_LONG(extension) ? 'l' : 'w'); + if(EXT_INDEX_SCALE(extension)) + sprintf(index_reg+strlen(index_reg), "*%d", 1 << EXT_INDEX_SCALE(extension)); + } + else + *index_reg = 0; + preindex = (extension&7) > 0 && (extension&7) < 4; + postindex = (extension&7) > 4; + + strcpy(mode, "("); + if(preindex || postindex) + strcat(mode, "["); + if(base) + { + strcat(mode, make_signed_hex_str_16(base)); + comma = 1; + } + if(*base_reg) + { + if(comma) + strcat(mode, ","); + strcat(mode, base_reg); + comma = 1; + } + if(postindex) + { + strcat(mode, "]"); + comma = 1; + } + if(*index_reg) + { + if(comma) + strcat(mode, ","); + strcat(mode, index_reg); + comma = 1; + } + if(preindex) + { + strcat(mode, "]"); + comma = 1; + } + if(outer) + { + if(comma) + strcat(mode, ","); + strcat(mode, make_signed_hex_str_16(outer)); + } + strcat(mode, ")"); + break; + } + + if(EXT_8BIT_DISPLACEMENT(extension) == 0) + sprintf(mode, "(PC,%c%d.%c", EXT_INDEX_AR(extension) ? 'A' : 'D', EXT_INDEX_REGISTER(extension), EXT_INDEX_LONG(extension) ? 'l' : 'w'); + else + sprintf(mode, "(%s,PC,%c%d.%c", make_signed_hex_str_8(extension), EXT_INDEX_AR(extension) ? 'A' : 'D', EXT_INDEX_REGISTER(extension), EXT_INDEX_LONG(extension) ? 'l' : 'w'); + if(EXT_INDEX_SCALE(extension)) + sprintf(mode+strlen(mode), "*%d", 1 << EXT_INDEX_SCALE(extension)); + strcat(mode, ")"); + break; + case 0x3c: + /* Immediate */ + sprintf(mode, "%s", get_imm_str_u(size)); + break; + default: + invalid_mode = 1; + } + + if(invalid_mode) + sprintf(mode, "INVALID %x", instruction & 0x3f); + + return mode; +} + + + +/* ======================================================================== */ +/* ========================= INSTRUCTION HANDLERS ========================= */ +/* ======================================================================== */ +/* Instruction handler function names follow this convention: + * + * d68000_NAME_EXTENSIONS(void) + * where NAME is the name of the opcode it handles and EXTENSIONS are any + * extensions for special instances of that opcode. + * + * Examples: + * d68000_add_er_8(): add opcode, from effective address to register, + * size = byte + * + * d68000_asr_s_8(): arithmetic shift right, static count, size = byte + * + * + * Common extensions: + * 8 : size = byte + * 16 : size = word + * 32 : size = long + * rr : register to register + * mm : memory to memory + * r : register + * s : static + * er : effective address -> register + * re : register -> effective address + * ea : using effective address mode of operation + * d : data register direct + * a : address register direct + * ai : address register indirect + * pi : address register indirect with postincrement + * pd : address register indirect with predecrement + * di : address register indirect with displacement + * ix : address register indirect with index + * aw : absolute word + * al : absolute long + */ + +static void d68000_illegal(void) +{ + sprintf(g_dasm_str, "dc.w $%04x; ILLEGAL", g_cpu_ir); +} + +static void d68000_1010(void) +{ + sprintf(g_dasm_str, "dc.w $%04x; opcode 1010", g_cpu_ir); +} + + +static void d68000_1111(void) +{ + sprintf(g_dasm_str, "dc.w $%04x; opcode 1111", g_cpu_ir); +} + + +static void d68000_abcd_rr(void) +{ + sprintf(g_dasm_str, "abcd D%d, D%d", g_cpu_ir&7, (g_cpu_ir>>9)&7); +} + + +static void d68000_abcd_mm(void) +{ + sprintf(g_dasm_str, "abcd -(A%d), -(A%d)", g_cpu_ir&7, (g_cpu_ir>>9)&7); +} + +static void d68000_add_er_8(void) +{ + sprintf(g_dasm_str, "add.b %s, D%d", get_ea_mode_str_8(g_cpu_ir), (g_cpu_ir>>9)&7); +} + + +static void d68000_add_er_16(void) +{ + sprintf(g_dasm_str, "add.w %s, D%d", get_ea_mode_str_16(g_cpu_ir), (g_cpu_ir>>9)&7); +} + +static void d68000_add_er_32(void) +{ + sprintf(g_dasm_str, "add.l %s, D%d", get_ea_mode_str_32(g_cpu_ir), (g_cpu_ir>>9)&7); +} + +static void d68000_add_re_8(void) +{ + sprintf(g_dasm_str, "add.b D%d, %s", (g_cpu_ir>>9)&7, get_ea_mode_str_8(g_cpu_ir)); +} + +static void d68000_add_re_16(void) +{ + sprintf(g_dasm_str, "add.w D%d, %s", (g_cpu_ir>>9)&7, get_ea_mode_str_16(g_cpu_ir)); +} + +static void d68000_add_re_32(void) +{ + sprintf(g_dasm_str, "add.l D%d, %s", (g_cpu_ir>>9)&7, get_ea_mode_str_32(g_cpu_ir)); +} + +static void d68000_adda_16(void) +{ + sprintf(g_dasm_str, "adda.w %s, A%d", get_ea_mode_str_16(g_cpu_ir), (g_cpu_ir>>9)&7); +} + +static void d68000_adda_32(void) +{ + sprintf(g_dasm_str, "adda.l %s, A%d", get_ea_mode_str_32(g_cpu_ir), (g_cpu_ir>>9)&7); +} + +static void d68000_addi_8(void) +{ + char* str = get_imm_str_s8(); + sprintf(g_dasm_str, "addi.b %s, %s", str, get_ea_mode_str_8(g_cpu_ir)); +} + +static void d68000_addi_16(void) +{ + char* str = get_imm_str_s16(); + sprintf(g_dasm_str, "addi.w %s, %s", str, get_ea_mode_str_16(g_cpu_ir)); +} + +static void d68000_addi_32(void) +{ + char* str = get_imm_str_s32(); + sprintf(g_dasm_str, "addi.l %s, %s", str, get_ea_mode_str_32(g_cpu_ir)); +} + +static void d68000_addq_8(void) +{ + sprintf(g_dasm_str, "addq.b #%d, %s", g_3bit_qdata_table[(g_cpu_ir>>9)&7], get_ea_mode_str_8(g_cpu_ir)); +} + +static void d68000_addq_16(void) +{ + sprintf(g_dasm_str, "addq.w #%d, %s", g_3bit_qdata_table[(g_cpu_ir>>9)&7], get_ea_mode_str_16(g_cpu_ir)); +} + +static void d68000_addq_32(void) +{ + sprintf(g_dasm_str, "addq.l #%d, %s", g_3bit_qdata_table[(g_cpu_ir>>9)&7], get_ea_mode_str_32(g_cpu_ir)); +} + +static void d68000_addx_rr_8(void) +{ + sprintf(g_dasm_str, "addx.b D%d, D%d", g_cpu_ir&7, (g_cpu_ir>>9)&7); +} + +static void d68000_addx_rr_16(void) +{ + sprintf(g_dasm_str, "addx.w D%d, D%d", g_cpu_ir&7, (g_cpu_ir>>9)&7); +} + +static void d68000_addx_rr_32(void) +{ + sprintf(g_dasm_str, "addx.l D%d, D%d", g_cpu_ir&7, (g_cpu_ir>>9)&7); +} + +static void d68000_addx_mm_8(void) +{ + sprintf(g_dasm_str, "addx.b -(A%d), -(A%d)", g_cpu_ir&7, (g_cpu_ir>>9)&7); +} + +static void d68000_addx_mm_16(void) +{ + sprintf(g_dasm_str, "addx.w -(A%d), -(A%d)", g_cpu_ir&7, (g_cpu_ir>>9)&7); +} + +static void d68000_addx_mm_32(void) +{ + sprintf(g_dasm_str, "addx.l -(A%d), -(A%d)", g_cpu_ir&7, (g_cpu_ir>>9)&7); +} + +static void d68000_and_er_8(void) +{ + sprintf(g_dasm_str, "and.b %s, D%d", get_ea_mode_str_8(g_cpu_ir), (g_cpu_ir>>9)&7); +} + +static void d68000_and_er_16(void) +{ + sprintf(g_dasm_str, "and.w %s, D%d", get_ea_mode_str_16(g_cpu_ir), (g_cpu_ir>>9)&7); +} + +static void d68000_and_er_32(void) +{ + sprintf(g_dasm_str, "and.l %s, D%d", get_ea_mode_str_32(g_cpu_ir), (g_cpu_ir>>9)&7); +} + +static void d68000_and_re_8(void) +{ + sprintf(g_dasm_str, "and.b D%d, %s", (g_cpu_ir>>9)&7, get_ea_mode_str_8(g_cpu_ir)); +} + +static void d68000_and_re_16(void) +{ + sprintf(g_dasm_str, "and.w D%d, %s", (g_cpu_ir>>9)&7, get_ea_mode_str_16(g_cpu_ir)); +} + +static void d68000_and_re_32(void) +{ + sprintf(g_dasm_str, "and.l D%d, %s", (g_cpu_ir>>9)&7, get_ea_mode_str_32(g_cpu_ir)); +} + +static void d68000_andi_8(void) +{ + char* str = get_imm_str_u8(); + sprintf(g_dasm_str, "andi.b %s, %s", str, get_ea_mode_str_8(g_cpu_ir)); +} + +static void d68000_andi_16(void) +{ + char* str = get_imm_str_u16(); + sprintf(g_dasm_str, "andi.w %s, %s", str, get_ea_mode_str_16(g_cpu_ir)); +} + +static void d68000_andi_32(void) +{ + char* str = get_imm_str_u32(); + sprintf(g_dasm_str, "andi.l %s, %s", str, get_ea_mode_str_32(g_cpu_ir)); +} + +static void d68000_andi_to_ccr(void) +{ + sprintf(g_dasm_str, "andi %s, CCR", get_imm_str_u8()); +} + +static void d68000_andi_to_sr(void) +{ + sprintf(g_dasm_str, "andi %s, SR", get_imm_str_u16()); +} + +static void d68000_asr_s_8(void) +{ + sprintf(g_dasm_str, "asr.b #%d, D%d", g_3bit_qdata_table[(g_cpu_ir>>9)&7], g_cpu_ir&7); +} + +static void d68000_asr_s_16(void) +{ + sprintf(g_dasm_str, "asr.w #%d, D%d", g_3bit_qdata_table[(g_cpu_ir>>9)&7], g_cpu_ir&7); +} + +static void d68000_asr_s_32(void) +{ + sprintf(g_dasm_str, "asr.l #%d, D%d", g_3bit_qdata_table[(g_cpu_ir>>9)&7], g_cpu_ir&7); +} + +static void d68000_asr_r_8(void) +{ + sprintf(g_dasm_str, "asr.b D%d, D%d", (g_cpu_ir>>9)&7, g_cpu_ir&7); +} + +static void d68000_asr_r_16(void) +{ + sprintf(g_dasm_str, "asr.w D%d, D%d", (g_cpu_ir>>9)&7, g_cpu_ir&7); +} + +static void d68000_asr_r_32(void) +{ + sprintf(g_dasm_str, "asr.l D%d, D%d", (g_cpu_ir>>9)&7, g_cpu_ir&7); +} + +static void d68000_asr_ea(void) +{ + sprintf(g_dasm_str, "asr.w %s", get_ea_mode_str_16(g_cpu_ir)); +} + +static void d68000_asl_s_8(void) +{ + sprintf(g_dasm_str, "asl.b #%d, D%d", g_3bit_qdata_table[(g_cpu_ir>>9)&7], g_cpu_ir&7); +} + +static void d68000_asl_s_16(void) +{ + sprintf(g_dasm_str, "asl.w #%d, D%d", g_3bit_qdata_table[(g_cpu_ir>>9)&7], g_cpu_ir&7); +} + +static void d68000_asl_s_32(void) +{ + sprintf(g_dasm_str, "asl.l #%d, D%d", g_3bit_qdata_table[(g_cpu_ir>>9)&7], g_cpu_ir&7); +} + +static void d68000_asl_r_8(void) +{ + sprintf(g_dasm_str, "asl.b D%d, D%d", (g_cpu_ir>>9)&7, g_cpu_ir&7); +} + +static void d68000_asl_r_16(void) +{ + sprintf(g_dasm_str, "asl.w D%d, D%d", (g_cpu_ir>>9)&7, g_cpu_ir&7); +} + +static void d68000_asl_r_32(void) +{ + sprintf(g_dasm_str, "asl.l D%d, D%d", (g_cpu_ir>>9)&7, g_cpu_ir&7); +} + +static void d68000_asl_ea(void) +{ + sprintf(g_dasm_str, "asl.w %s", get_ea_mode_str_16(g_cpu_ir)); +} + +static void d68000_bcc_8(void) +{ + UINT32 temp_pc = g_cpu_pc; + sprintf(g_dasm_str, "b%-2s $%x", g_cc[(g_cpu_ir>>8)&0xf], temp_pc + make_int_8(g_cpu_ir)); +} + +static void d68000_bcc_16(void) +{ + UINT32 temp_pc = g_cpu_pc; + sprintf(g_dasm_str, "b%-2s $%x", g_cc[(g_cpu_ir>>8)&0xf], temp_pc + make_int_16(read_imm_16())); +} + +static void d68020_bcc_32(void) +{ + UINT32 temp_pc = g_cpu_pc; + LIMIT_CPU_TYPES(M68020_PLUS); + sprintf(g_dasm_str, "b%-2s $%x; (2+)", g_cc[(g_cpu_ir>>8)&0xf], temp_pc + read_imm_32()); +} + +static void d68000_bchg_r(void) +{ + sprintf(g_dasm_str, "bchg D%d, %s", (g_cpu_ir>>9)&7, get_ea_mode_str_8(g_cpu_ir)); +} + +static void d68000_bchg_s(void) +{ + char* str = get_imm_str_u8(); + sprintf(g_dasm_str, "bchg %s, %s", str, get_ea_mode_str_8(g_cpu_ir)); +} + +static void d68000_bclr_r(void) +{ + sprintf(g_dasm_str, "bclr D%d, %s", (g_cpu_ir>>9)&7, get_ea_mode_str_8(g_cpu_ir)); +} + +static void d68000_bclr_s(void) +{ + char* str = get_imm_str_u8(); + sprintf(g_dasm_str, "bclr %s, %s", str, get_ea_mode_str_8(g_cpu_ir)); +} + +static void d68010_bkpt(void) +{ + LIMIT_CPU_TYPES(M68010_PLUS); + sprintf(g_dasm_str, "bkpt #%d; (1+)", g_cpu_ir&7); +} + +static void d68020_bfchg(void) +{ + UINT32 extension; + char offset[3]; + char width[3]; + + LIMIT_CPU_TYPES(M68020_PLUS); + + extension = read_imm_16(); + + if(BIT_B(extension)) + sprintf(offset, "D%d", (extension>>6)&7); + else + sprintf(offset, "%d", (extension>>6)&31); + if(BIT_5(extension)) + sprintf(width, "D%d", extension&7); + else + sprintf(width, "%d", g_5bit_data_table[extension&31]); + sprintf(g_dasm_str, "bfchg %s {%s:%s}; (2+)", get_ea_mode_str_8(g_cpu_ir), offset, width); +} + +static void d68020_bfclr(void) +{ + UINT32 extension; + char offset[3]; + char width[3]; + + LIMIT_CPU_TYPES(M68020_PLUS); + + extension = read_imm_16(); + + if(BIT_B(extension)) + sprintf(offset, "D%d", (extension>>6)&7); + else + sprintf(offset, "%d", (extension>>6)&31); + if(BIT_5(extension)) + sprintf(width, "D%d", extension&7); + else + sprintf(width, "%d", g_5bit_data_table[extension&31]); + sprintf(g_dasm_str, "bfclr %s {%s:%s}; (2+)", get_ea_mode_str_8(g_cpu_ir), offset, width); +} + +static void d68020_bfexts(void) +{ + UINT32 extension; + char offset[3]; + char width[3]; + + LIMIT_CPU_TYPES(M68020_PLUS); + + extension = read_imm_16(); + + if(BIT_B(extension)) + sprintf(offset, "D%d", (extension>>6)&7); + else + sprintf(offset, "%d", (extension>>6)&31); + if(BIT_5(extension)) + sprintf(width, "D%d", extension&7); + else + sprintf(width, "%d", g_5bit_data_table[extension&31]); + sprintf(g_dasm_str, "bfexts D%d, %s {%s:%s}; (2+)", (extension>>12)&7, get_ea_mode_str_8(g_cpu_ir), offset, width); +} + +static void d68020_bfextu(void) +{ + UINT32 extension; + char offset[3]; + char width[3]; + + LIMIT_CPU_TYPES(M68020_PLUS); + + extension = read_imm_16(); + + if(BIT_B(extension)) + sprintf(offset, "D%d", (extension>>6)&7); + else + sprintf(offset, "%d", (extension>>6)&31); + if(BIT_5(extension)) + sprintf(width, "D%d", extension&7); + else + sprintf(width, "%d", g_5bit_data_table[extension&31]); + sprintf(g_dasm_str, "bfextu D%d, %s {%s:%s}; (2+)", (extension>>12)&7, get_ea_mode_str_8(g_cpu_ir), offset, width); +} + +static void d68020_bfffo(void) +{ + UINT32 extension; + char offset[3]; + char width[3]; + + LIMIT_CPU_TYPES(M68020_PLUS); + + extension = read_imm_16(); + + if(BIT_B(extension)) + sprintf(offset, "D%d", (extension>>6)&7); + else + sprintf(offset, "%d", (extension>>6)&31); + if(BIT_5(extension)) + sprintf(width, "D%d", extension&7); + else + sprintf(width, "%d", g_5bit_data_table[extension&31]); + sprintf(g_dasm_str, "bfffo D%d, %s {%s:%s}; (2+)", (extension>>12)&7, get_ea_mode_str_8(g_cpu_ir), offset, width); +} + +static void d68020_bfins(void) +{ + UINT32 extension; + char offset[3]; + char width[3]; + + LIMIT_CPU_TYPES(M68020_PLUS); + + extension = read_imm_16(); + + if(BIT_B(extension)) + sprintf(offset, "D%d", (extension>>6)&7); + else + sprintf(offset, "%d", (extension>>6)&31); + if(BIT_5(extension)) + sprintf(width, "D%d", extension&7); + else + sprintf(width, "%d", g_5bit_data_table[extension&31]); + sprintf(g_dasm_str, "bfins D%d, %s {%s:%s}; (2+)", (extension>>12)&7, get_ea_mode_str_8(g_cpu_ir), offset, width); +} + +static void d68020_bfset(void) +{ + UINT32 extension; + char offset[3]; + char width[3]; + + LIMIT_CPU_TYPES(M68020_PLUS); + + extension = read_imm_16(); + + if(BIT_B(extension)) + sprintf(offset, "D%d", (extension>>6)&7); + else + sprintf(offset, "%d", (extension>>6)&31); + if(BIT_5(extension)) + sprintf(width, "D%d", extension&7); + else + sprintf(width, "%d", g_5bit_data_table[extension&31]); + sprintf(g_dasm_str, "bfset %s {%s:%s}; (2+)", get_ea_mode_str_8(g_cpu_ir), offset, width); +} + +static void d68020_bftst(void) +{ + UINT32 extension; + char offset[3]; + char width[3]; + + LIMIT_CPU_TYPES(M68020_PLUS); + + extension = read_imm_16(); + + if(BIT_B(extension)) + sprintf(offset, "D%d", (extension>>6)&7); + else + sprintf(offset, "%d", (extension>>6)&31); + if(BIT_5(extension)) + sprintf(width, "D%d", extension&7); + else + sprintf(width, "%d", g_5bit_data_table[extension&31]); + sprintf(g_dasm_str, "bftst %s {%s:%s}; (2+)", get_ea_mode_str_8(g_cpu_ir), offset, width); +} + +static void d68000_bra_8(void) +{ + UINT32 temp_pc = g_cpu_pc; + sprintf(g_dasm_str, "bra $%x", temp_pc + make_int_8(g_cpu_ir)); +} + +static void d68000_bra_16(void) +{ + UINT32 temp_pc = g_cpu_pc; + sprintf(g_dasm_str, "bra $%x", temp_pc + make_int_16(read_imm_16())); +} + +static void d68020_bra_32(void) +{ + UINT32 temp_pc = g_cpu_pc; + LIMIT_CPU_TYPES(M68020_PLUS); + sprintf(g_dasm_str, "bra $%x; (2+)", temp_pc + read_imm_32()); +} + +static void d68000_bset_r(void) +{ + sprintf(g_dasm_str, "bset D%d, %s", (g_cpu_ir>>9)&7, get_ea_mode_str_8(g_cpu_ir)); +} + +static void d68000_bset_s(void) +{ + char* str = get_imm_str_u8(); + sprintf(g_dasm_str, "bset %s, %s", str, get_ea_mode_str_8(g_cpu_ir)); +} + +static void d68000_bsr_8(void) +{ + UINT32 temp_pc = g_cpu_pc; + sprintf(g_dasm_str, "bsr $%x", temp_pc + make_int_8(g_cpu_ir)); + SET_OPCODE_FLAGS(DASMFLAG_STEP_OVER); +} + +static void d68000_bsr_16(void) +{ + UINT32 temp_pc = g_cpu_pc; + sprintf(g_dasm_str, "bsr $%x", temp_pc + make_int_16(read_imm_16())); + SET_OPCODE_FLAGS(DASMFLAG_STEP_OVER); +} + +static void d68020_bsr_32(void) +{ + UINT32 temp_pc = g_cpu_pc; + LIMIT_CPU_TYPES(M68020_PLUS); + sprintf(g_dasm_str, "bsr $%x; (2+)", temp_pc + read_imm_32()); + SET_OPCODE_FLAGS(DASMFLAG_STEP_OVER); +} + +static void d68000_btst_r(void) +{ + sprintf(g_dasm_str, "btst D%d, %s", (g_cpu_ir>>9)&7, get_ea_mode_str_8(g_cpu_ir)); +} + +static void d68000_btst_s(void) +{ + char* str = get_imm_str_u8(); + sprintf(g_dasm_str, "btst %s, %s", str, get_ea_mode_str_8(g_cpu_ir)); +} + +static void d68020_callm(void) +{ + char* str; + LIMIT_CPU_TYPES(M68020_ONLY); + str = get_imm_str_u8(); + + sprintf(g_dasm_str, "callm %s, %s; (2)", str, get_ea_mode_str_8(g_cpu_ir)); +} + +static void d68020_cas_8(void) +{ + UINT32 extension; + LIMIT_CPU_TYPES(M68020_PLUS); + extension = read_imm_16(); + sprintf(g_dasm_str, "cas.b D%d, D%d, %s; (2+)", extension&7, (extension>>8)&7, get_ea_mode_str_8(g_cpu_ir)); +} + +static void d68020_cas_16(void) +{ + UINT32 extension; + LIMIT_CPU_TYPES(M68020_PLUS); + extension = read_imm_16(); + sprintf(g_dasm_str, "cas.w D%d, D%d, %s; (2+)", extension&7, (extension>>8)&7, get_ea_mode_str_16(g_cpu_ir)); +} + +static void d68020_cas_32(void) +{ + UINT32 extension; + LIMIT_CPU_TYPES(M68020_PLUS); + extension = read_imm_16(); + sprintf(g_dasm_str, "cas.l D%d, D%d, %s; (2+)", extension&7, (extension>>8)&7, get_ea_mode_str_32(g_cpu_ir)); +} + +static void d68020_cas2_16(void) +{ +/* CAS2 Dc1:Dc2,Du1:Dc2:(Rn1):(Rn2) +f e d c b a 9 8 7 6 5 4 3 2 1 0 + DARn1 0 0 0 Du1 0 0 0 Dc1 + DARn2 0 0 0 Du2 0 0 0 Dc2 +*/ + + UINT32 extension; + LIMIT_CPU_TYPES(M68020_PLUS); + extension = read_imm_32(); + sprintf(g_dasm_str, "cas2.w D%d:D%d:D%d:D%d, (%c%d):(%c%d); (2+)", + (extension>>16)&7, extension&7, (extension>>22)&7, (extension>>6)&7, + BIT_1F(extension) ? 'A' : 'D', (extension>>28)&7, + BIT_F(extension) ? 'A' : 'D', (extension>>12)&7); +} + +static void d68020_cas2_32(void) +{ + UINT32 extension; + LIMIT_CPU_TYPES(M68020_PLUS); + extension = read_imm_32(); + sprintf(g_dasm_str, "cas2.l D%d:D%d:D%d:D%d, (%c%d):(%c%d); (2+)", + (extension>>16)&7, extension&7, (extension>>22)&7, (extension>>6)&7, + BIT_1F(extension) ? 'A' : 'D', (extension>>28)&7, + BIT_F(extension) ? 'A' : 'D', (extension>>12)&7); +} + +static void d68000_chk_16(void) +{ + sprintf(g_dasm_str, "chk.w %s, D%d", get_ea_mode_str_16(g_cpu_ir), (g_cpu_ir>>9)&7); + SET_OPCODE_FLAGS(DASMFLAG_STEP_OVER); +} + +static void d68020_chk_32(void) +{ + LIMIT_CPU_TYPES(M68020_PLUS); + sprintf(g_dasm_str, "chk.l %s, D%d; (2+)", get_ea_mode_str_32(g_cpu_ir), (g_cpu_ir>>9)&7); + SET_OPCODE_FLAGS(DASMFLAG_STEP_OVER); +} + +static void d68020_chk2_cmp2_8(void) +{ + UINT32 extension; + LIMIT_CPU_TYPES(M68020_PLUS); + extension = read_imm_16(); + sprintf(g_dasm_str, "%s.b %s, %c%d; (2+)", BIT_B(extension) ? "chk2" : "cmp2", get_ea_mode_str_8(g_cpu_ir), BIT_F(extension) ? 'A' : 'D', (extension>>12)&7); +} + +static void d68020_chk2_cmp2_16(void) +{ + UINT32 extension; + LIMIT_CPU_TYPES(M68020_PLUS); + extension = read_imm_16(); + sprintf(g_dasm_str, "%s.w %s, %c%d; (2+)", BIT_B(extension) ? "chk2" : "cmp2", get_ea_mode_str_16(g_cpu_ir), BIT_F(extension) ? 'A' : 'D', (extension>>12)&7); +} + +static void d68020_chk2_cmp2_32(void) +{ + UINT32 extension; + LIMIT_CPU_TYPES(M68020_PLUS); + extension = read_imm_16(); + sprintf(g_dasm_str, "%s.l %s, %c%d; (2+)", BIT_B(extension) ? "chk2" : "cmp2", get_ea_mode_str_32(g_cpu_ir), BIT_F(extension) ? 'A' : 'D', (extension>>12)&7); +} + +static void d68040_cinv(void) +{ + LIMIT_CPU_TYPES(M68040_PLUS); + + static const char *cachetype[4] = { "nop", "data", "inst", "both" }; + + switch((g_cpu_ir>>3)&3) + { + case 0: + sprintf(g_dasm_str, "cinv (illegal scope); (4)"); + break; + case 1: + sprintf(g_dasm_str, "cinvl %s, (A%d); (4)", cachetype[(g_cpu_ir>>6)&3], g_cpu_ir&7); + break; + case 2: + sprintf(g_dasm_str, "cinvp %s, (A%d); (4)", cachetype[(g_cpu_ir>>6)&3], g_cpu_ir&7); + break; + case 3: + sprintf(g_dasm_str, "cinva %s; (4)", cachetype[(g_cpu_ir>>6)&3]); + break; + } +} + +static void d68000_clr_8(void) +{ + sprintf(g_dasm_str, "clr.b %s", get_ea_mode_str_8(g_cpu_ir)); +} + +static void d68000_clr_16(void) +{ + sprintf(g_dasm_str, "clr.w %s", get_ea_mode_str_16(g_cpu_ir)); +} + +static void d68000_clr_32(void) +{ + sprintf(g_dasm_str, "clr.l %s", get_ea_mode_str_32(g_cpu_ir)); +} + +static void d68000_cmp_8(void) +{ + sprintf(g_dasm_str, "cmp.b %s, D%d", get_ea_mode_str_8(g_cpu_ir), (g_cpu_ir>>9)&7); +} + +static void d68000_cmp_16(void) +{ + sprintf(g_dasm_str, "cmp.w %s, D%d", get_ea_mode_str_16(g_cpu_ir), (g_cpu_ir>>9)&7); +} + +static void d68000_cmp_32(void) +{ + sprintf(g_dasm_str, "cmp.l %s, D%d", get_ea_mode_str_32(g_cpu_ir), (g_cpu_ir>>9)&7); +} + +static void d68000_cmpa_16(void) +{ + sprintf(g_dasm_str, "cmpa.w %s, A%d", get_ea_mode_str_16(g_cpu_ir), (g_cpu_ir>>9)&7); +} + +static void d68000_cmpa_32(void) +{ + sprintf(g_dasm_str, "cmpa.l %s, A%d", get_ea_mode_str_32(g_cpu_ir), (g_cpu_ir>>9)&7); +} + +static void d68000_cmpi_8(void) +{ + char* str = get_imm_str_s8(); + sprintf(g_dasm_str, "cmpi.b %s, %s", str, get_ea_mode_str_8(g_cpu_ir)); +} + +static void d68020_cmpi_pcdi_8(void) +{ + char* str; + LIMIT_CPU_TYPES(M68010_PLUS); + str = get_imm_str_s8(); + sprintf(g_dasm_str, "cmpi.b %s, %s; (2+)", str, get_ea_mode_str_8(g_cpu_ir)); +} + +static void d68020_cmpi_pcix_8(void) +{ + char* str; + LIMIT_CPU_TYPES(M68010_PLUS); + str = get_imm_str_s8(); + sprintf(g_dasm_str, "cmpi.b %s, %s; (2+)", str, get_ea_mode_str_8(g_cpu_ir)); +} + +static void d68000_cmpi_16(void) +{ + char* str; + str = get_imm_str_s16(); + sprintf(g_dasm_str, "cmpi.w %s, %s", str, get_ea_mode_str_16(g_cpu_ir)); +} + +static void d68020_cmpi_pcdi_16(void) +{ + char* str; + LIMIT_CPU_TYPES(M68010_PLUS); + str = get_imm_str_s16(); + sprintf(g_dasm_str, "cmpi.w %s, %s; (2+)", str, get_ea_mode_str_16(g_cpu_ir)); +} + +static void d68020_cmpi_pcix_16(void) +{ + char* str; + LIMIT_CPU_TYPES(M68010_PLUS); + str = get_imm_str_s16(); + sprintf(g_dasm_str, "cmpi.w %s, %s; (2+)", str, get_ea_mode_str_16(g_cpu_ir)); +} + +static void d68000_cmpi_32(void) +{ + char* str; + str = get_imm_str_s32(); + sprintf(g_dasm_str, "cmpi.l %s, %s", str, get_ea_mode_str_32(g_cpu_ir)); +} + +static void d68020_cmpi_pcdi_32(void) +{ + char* str; + LIMIT_CPU_TYPES(M68010_PLUS); + str = get_imm_str_s32(); + sprintf(g_dasm_str, "cmpi.l %s, %s; (2+)", str, get_ea_mode_str_32(g_cpu_ir)); +} + +static void d68020_cmpi_pcix_32(void) +{ + char* str; + LIMIT_CPU_TYPES(M68010_PLUS); + str = get_imm_str_s32(); + sprintf(g_dasm_str, "cmpi.l %s, %s; (2+)", str, get_ea_mode_str_32(g_cpu_ir)); +} + +static void d68000_cmpm_8(void) +{ + sprintf(g_dasm_str, "cmpm.b (A%d)+, (A%d)+", g_cpu_ir&7, (g_cpu_ir>>9)&7); +} + +static void d68000_cmpm_16(void) +{ + sprintf(g_dasm_str, "cmpm.w (A%d)+, (A%d)+", g_cpu_ir&7, (g_cpu_ir>>9)&7); +} + +static void d68000_cmpm_32(void) +{ + sprintf(g_dasm_str, "cmpm.l (A%d)+, (A%d)+", g_cpu_ir&7, (g_cpu_ir>>9)&7); +} + +static void d68020_cpbcc_16(void) +{ + UINT32 extension; + UINT32 new_pc = g_cpu_pc; + LIMIT_CPU_TYPES(M68020_PLUS); + extension = read_imm_16(); + new_pc += make_int_16(read_imm_16()); + sprintf(g_dasm_str, "%db%-4s %s; %x (extension = %x) (2-3)", (g_cpu_ir>>9)&7, g_cpcc[g_cpu_ir&0x3f], get_imm_str_s16(), new_pc, extension); +} + +static void d68020_cpbcc_32(void) +{ + UINT32 extension; + UINT32 new_pc = g_cpu_pc; + LIMIT_CPU_TYPES(M68020_PLUS); + extension = read_imm_16(); + new_pc += read_imm_32(); + sprintf(g_dasm_str, "%db%-4s %s; %x (extension = %x) (2-3)", (g_cpu_ir>>9)&7, g_cpcc[g_cpu_ir&0x3f], get_imm_str_s16(), new_pc, extension); +} + +static void d68020_cpdbcc(void) +{ + UINT32 extension1; + UINT32 extension2; + UINT32 new_pc = g_cpu_pc; + LIMIT_CPU_TYPES(M68020_PLUS); + extension1 = read_imm_16(); + extension2 = read_imm_16(); + new_pc += make_int_16(read_imm_16()); + sprintf(g_dasm_str, "%ddb%-4s D%d,%s; %x (extension = %x) (2-3)", (g_cpu_ir>>9)&7, g_cpcc[extension1&0x3f], g_cpu_ir&7, get_imm_str_s16(), new_pc, extension2); +} + +static void d68020_cpgen(void) +{ + LIMIT_CPU_TYPES(M68020_PLUS); + sprintf(g_dasm_str, "%dgen %s; (2-3)", (g_cpu_ir>>9)&7, get_imm_str_u32()); +} + +static void d68020_cprestore(void) +{ + LIMIT_CPU_TYPES(M68020_PLUS); + if (((g_cpu_ir>>9)&7) == 1) + { + sprintf(g_dasm_str, "frestore %s", get_ea_mode_str_8(g_cpu_ir)); + } + else + { + sprintf(g_dasm_str, "%drestore %s; (2-3)", (g_cpu_ir>>9)&7, get_ea_mode_str_8(g_cpu_ir)); + } +} + +static void d68020_cpsave(void) +{ + LIMIT_CPU_TYPES(M68020_PLUS); + if (((g_cpu_ir>>9)&7) == 1) + { + sprintf(g_dasm_str, "fsave %s", get_ea_mode_str_8(g_cpu_ir)); + } + else + { + sprintf(g_dasm_str, "%dsave %s; (2-3)", (g_cpu_ir>>9)&7, get_ea_mode_str_8(g_cpu_ir)); + } +} + +static void d68020_cpscc(void) +{ + UINT32 extension1; + UINT32 extension2; + LIMIT_CPU_TYPES(M68020_PLUS); + extension1 = read_imm_16(); + extension2 = read_imm_16(); + sprintf(g_dasm_str, "%ds%-4s %s; (extension = %x) (2-3)", (g_cpu_ir>>9)&7, g_cpcc[extension1&0x3f], get_ea_mode_str_8(g_cpu_ir), extension2); +} + +static void d68020_cptrapcc_0(void) +{ + UINT32 extension1; + UINT32 extension2; + LIMIT_CPU_TYPES(M68020_PLUS); + extension1 = read_imm_16(); + extension2 = read_imm_16(); + sprintf(g_dasm_str, "%dtrap%-4s; (extension = %x) (2-3)", (g_cpu_ir>>9)&7, g_cpcc[extension1&0x3f], extension2); +} + +static void d68020_cptrapcc_16(void) +{ + UINT32 extension1; + UINT32 extension2; + LIMIT_CPU_TYPES(M68020_PLUS); + extension1 = read_imm_16(); + extension2 = read_imm_16(); + sprintf(g_dasm_str, "%dtrap%-4s %s; (extension = %x) (2-3)", (g_cpu_ir>>9)&7, g_cpcc[extension1&0x3f], get_imm_str_u16(), extension2); +} + +static void d68020_cptrapcc_32(void) +{ + UINT32 extension1; + UINT32 extension2; + LIMIT_CPU_TYPES(M68020_PLUS); + extension1 = read_imm_16(); + extension2 = read_imm_16(); + sprintf(g_dasm_str, "%dtrap%-4s %s; (extension = %x) (2-3)", (g_cpu_ir>>9)&7, g_cpcc[extension1&0x3f], get_imm_str_u32(), extension2); +} + +static void d68040_cpush(void) +{ + static const char *cachetype[4] = { "nop", "data", "inst", "both" }; + + LIMIT_CPU_TYPES(M68040_PLUS); + switch((g_cpu_ir>>3)&3) + { + case 0: + sprintf(g_dasm_str, "cpush (illegal scope); (4)"); + break; + case 1: + sprintf(g_dasm_str, "cpushl %s, (A%d); (4)", cachetype[(g_cpu_ir>>6)&3], g_cpu_ir&7); + break; + case 2: + sprintf(g_dasm_str, "cpushp %s, (A%d); (4)", cachetype[(g_cpu_ir>>6)&3], g_cpu_ir&7); + break; + case 3: + sprintf(g_dasm_str, "cpusha %s; (4)", cachetype[(g_cpu_ir>>6)&3]); + break; + } +} + +static void d68000_dbra(void) +{ + UINT32 temp_pc = g_cpu_pc; + sprintf(g_dasm_str, "dbra D%d, $%x", g_cpu_ir & 7, temp_pc + make_int_16(read_imm_16())); + SET_OPCODE_FLAGS(DASMFLAG_STEP_OVER); +} + +static void d68000_dbcc(void) +{ + UINT32 temp_pc = g_cpu_pc; + sprintf(g_dasm_str, "db%-2s D%d, $%x", g_cc[(g_cpu_ir>>8)&0xf], g_cpu_ir & 7, temp_pc + make_int_16(read_imm_16())); + SET_OPCODE_FLAGS(DASMFLAG_STEP_OVER); +} + +static void d68000_divs(void) +{ + sprintf(g_dasm_str, "divs.w %s, D%d", get_ea_mode_str_16(g_cpu_ir), (g_cpu_ir>>9)&7); +} + +static void d68000_divu(void) +{ + sprintf(g_dasm_str, "divu.w %s, D%d", get_ea_mode_str_16(g_cpu_ir), (g_cpu_ir>>9)&7); +} + +static void d68020_divl(void) +{ + UINT32 extension; + LIMIT_CPU_TYPES(M68020_PLUS); + extension = read_imm_16(); + + if(BIT_A(extension)) + sprintf(g_dasm_str, "div%c.l %s, D%d:D%d; (2+)", BIT_B(extension) ? 's' : 'u', get_ea_mode_str_32(g_cpu_ir), extension&7, (extension>>12)&7); + else if((extension&7) == ((extension>>12)&7)) + sprintf(g_dasm_str, "div%c.l %s, D%d; (2+)", BIT_B(extension) ? 's' : 'u', get_ea_mode_str_32(g_cpu_ir), (extension>>12)&7); + else + sprintf(g_dasm_str, "div%cl.l %s, D%d:D%d; (2+)", BIT_B(extension) ? 's' : 'u', get_ea_mode_str_32(g_cpu_ir), extension&7, (extension>>12)&7); +} + +static void d68000_eor_8(void) +{ + sprintf(g_dasm_str, "eor.b D%d, %s", (g_cpu_ir>>9)&7, get_ea_mode_str_8(g_cpu_ir)); +} + +static void d68000_eor_16(void) +{ + sprintf(g_dasm_str, "eor.w D%d, %s", (g_cpu_ir>>9)&7, get_ea_mode_str_16(g_cpu_ir)); +} + +static void d68000_eor_32(void) +{ + sprintf(g_dasm_str, "eor.l D%d, %s", (g_cpu_ir>>9)&7, get_ea_mode_str_32(g_cpu_ir)); +} + +static void d68000_eori_8(void) +{ + char* str = get_imm_str_u8(); + sprintf(g_dasm_str, "eori.b %s, %s", str, get_ea_mode_str_8(g_cpu_ir)); +} + +static void d68000_eori_16(void) +{ + char* str = get_imm_str_u16(); + sprintf(g_dasm_str, "eori.w %s, %s", str, get_ea_mode_str_16(g_cpu_ir)); +} + +static void d68000_eori_32(void) +{ + char* str = get_imm_str_u32(); + sprintf(g_dasm_str, "eori.l %s, %s", str, get_ea_mode_str_32(g_cpu_ir)); +} + +static void d68000_eori_to_ccr(void) +{ + sprintf(g_dasm_str, "eori %s, CCR", get_imm_str_u8()); +} + +static void d68000_eori_to_sr(void) +{ + sprintf(g_dasm_str, "eori %s, SR", get_imm_str_u16()); +} + +static void d68000_exg_dd(void) +{ + sprintf(g_dasm_str, "exg D%d, D%d", (g_cpu_ir>>9)&7, g_cpu_ir&7); +} + +static void d68000_exg_aa(void) +{ + sprintf(g_dasm_str, "exg A%d, A%d", (g_cpu_ir>>9)&7, g_cpu_ir&7); +} + +static void d68000_exg_da(void) +{ + sprintf(g_dasm_str, "exg D%d, A%d", (g_cpu_ir>>9)&7, g_cpu_ir&7); +} + +static void d68000_ext_16(void) +{ + sprintf(g_dasm_str, "ext.w D%d", g_cpu_ir&7); +} + +static void d68000_ext_32(void) +{ + sprintf(g_dasm_str, "ext.l D%d", g_cpu_ir&7); +} + +static void d68020_extb_32(void) +{ + LIMIT_CPU_TYPES(M68020_PLUS); + sprintf(g_dasm_str, "extb.l D%d; (2+)", g_cpu_ir&7); +} + +static void d68881_ftrap(void) +{ + UINT16 w2, w3; + UINT32 l2; + + LIMIT_CPU_TYPES(M68020_PLUS); + w2 = read_imm_16(); + + switch (g_cpu_ir & 0x7) + { + case 2: // word operand + w3 = read_imm_16(); + sprintf(g_dasm_str, "ftrap%s.w $%04x", g_cpcc[w2 & 0x3f], w3); + break; + + case 3: // long word operand + l2 = read_imm_32(); + sprintf(g_dasm_str, "ftrap%s.l $%08x", g_cpcc[w2 & 0x3f], l2); + break; + + case 4: // no operand + sprintf(g_dasm_str, "ftrap%s", g_cpcc[w2 & 0x3f]); + break; + } +} + +static void d68040_fpu(void) +{ + char float_data_format[8][3] = + { + ".l", ".s", ".x", ".p", ".w", ".d", ".b", ".p" + }; + + char mnemonic[40]; + UINT32 w2, src, dst_reg; + LIMIT_CPU_TYPES(M68020_PLUS); + w2 = read_imm_16(); + + src = (w2 >> 10) & 0x7; + dst_reg = (w2 >> 7) & 0x7; + + // special override for FMOVECR + if ((((w2 >> 13) & 0x7) == 2) && (((w2>>10)&0x7) == 7)) + { + sprintf(g_dasm_str, "fmovecr #$%0x, fp%d", (w2&0x7f), dst_reg); + return; + } + + switch ((w2 >> 13) & 0x7) + { + case 0x0: + case 0x2: + { + switch(w2 & 0x7f) + { + case 0x00: sprintf(mnemonic, "fmove"); break; + case 0x01: sprintf(mnemonic, "fint"); break; + case 0x02: sprintf(mnemonic, "fsinh"); break; + case 0x03: sprintf(mnemonic, "fintrz"); break; + case 0x04: sprintf(mnemonic, "fsqrt"); break; + case 0x06: sprintf(mnemonic, "flognp1"); break; + case 0x08: sprintf(mnemonic, "fetoxm1"); break; + case 0x09: sprintf(mnemonic, "ftanh1"); break; + case 0x0a: sprintf(mnemonic, "fatan"); break; + case 0x0c: sprintf(mnemonic, "fasin"); break; + case 0x0d: sprintf(mnemonic, "fatanh"); break; + case 0x0e: sprintf(mnemonic, "fsin"); break; + case 0x0f: sprintf(mnemonic, "ftan"); break; + case 0x10: sprintf(mnemonic, "fetox"); break; + case 0x11: sprintf(mnemonic, "ftwotox"); break; + case 0x12: sprintf(mnemonic, "ftentox"); break; + case 0x14: sprintf(mnemonic, "flogn"); break; + case 0x15: sprintf(mnemonic, "flog10"); break; + case 0x16: sprintf(mnemonic, "flog2"); break; + case 0x18: sprintf(mnemonic, "fabs"); break; + case 0x19: sprintf(mnemonic, "fcosh"); break; + case 0x1a: sprintf(mnemonic, "fneg"); break; + case 0x1c: sprintf(mnemonic, "facos"); break; + case 0x1d: sprintf(mnemonic, "fcos"); break; + case 0x1e: sprintf(mnemonic, "fgetexp"); break; + case 0x1f: sprintf(mnemonic, "fgetman"); break; + case 0x20: sprintf(mnemonic, "fdiv"); break; + case 0x21: sprintf(mnemonic, "fmod"); break; + case 0x22: sprintf(mnemonic, "fadd"); break; + case 0x23: sprintf(mnemonic, "fmul"); break; + case 0x24: sprintf(mnemonic, "fsgldiv"); break; + case 0x25: sprintf(mnemonic, "frem"); break; + case 0x26: sprintf(mnemonic, "fscale"); break; + case 0x27: sprintf(mnemonic, "fsglmul"); break; + case 0x28: sprintf(mnemonic, "fsub"); break; + case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37: + sprintf(mnemonic, "fsincos"); break; + case 0x38: sprintf(mnemonic, "fcmp"); break; + case 0x3a: sprintf(mnemonic, "ftst"); break; + case 0x41: sprintf(mnemonic, "fssqrt"); break; + case 0x45: sprintf(mnemonic, "fdsqrt"); break; + case 0x58: sprintf(mnemonic, "fsabs"); break; + case 0x5a: sprintf(mnemonic, "fsneg"); break; + case 0x5c: sprintf(mnemonic, "fdabs"); break; + case 0x5e: sprintf(mnemonic, "fdneg"); break; + case 0x60: sprintf(mnemonic, "fsdiv"); break; + case 0x62: sprintf(mnemonic, "fsadd"); break; + case 0x63: sprintf(mnemonic, "fsmul"); break; + case 0x64: sprintf(mnemonic, "fddiv"); break; + case 0x66: sprintf(mnemonic, "fdadd"); break; + case 0x67: sprintf(mnemonic, "fdmul"); break; + case 0x68: sprintf(mnemonic, "fssub"); break; + case 0x6c: sprintf(mnemonic, "fdsub"); break; + + default: sprintf(mnemonic, "FPU (?)"); break; + } + + if (w2 & 0x4000) + { + sprintf(g_dasm_str, "%s%s %s, FP%d", mnemonic, float_data_format[src], get_ea_mode_str_32(g_cpu_ir), dst_reg); + } + else + { + sprintf(g_dasm_str, "%s.x FP%d, FP%d", mnemonic, src, dst_reg); + } + break; + } + + case 0x3: + { + switch ((w2>>10)&7) + { + case 3: // packed decimal w/fixed k-factor + sprintf(g_dasm_str, "fmove%s FP%d, %s {#%d}", float_data_format[(w2>>10)&7], dst_reg, get_ea_mode_str_32(g_cpu_ir), sext_7bit_int(w2&0x7f)); + break; + + case 7: // packed decimal w/dynamic k-factor (register) + sprintf(g_dasm_str, "fmove%s FP%d, %s {D%d}", float_data_format[(w2>>10)&7], dst_reg, get_ea_mode_str_32(g_cpu_ir), (w2>>4)&7); + break; + + default: + sprintf(g_dasm_str, "fmove%s FP%d, %s", float_data_format[(w2>>10)&7], dst_reg, get_ea_mode_str_32(g_cpu_ir)); + break; + } + break; + } + + case 0x4: // ea to control + { + sprintf(g_dasm_str, "fmovem.l %s, ", get_ea_mode_str_32(g_cpu_ir)); + if (w2 & 0x1000) strcat(g_dasm_str, "fpcr"); + if (w2 & 0x0800) strcat(g_dasm_str, "/fpsr"); + if (w2 & 0x0400) strcat(g_dasm_str, "/fpiar"); + break; + } + + case 0x5: // control to ea + { + strcpy(g_dasm_str, "fmovem.l "); + if (w2 & 0x1000) strcat(g_dasm_str, "fpcr"); + if (w2 & 0x0800) strcat(g_dasm_str, "/fpsr"); + if (w2 & 0x0400) strcat(g_dasm_str, "/fpiar"); + strcat(g_dasm_str, ", "); + strcat(g_dasm_str, get_ea_mode_str_32(g_cpu_ir)); + break; + } + + case 0x6: // memory to FPU, list + { + char temp[32]; + + if ((w2>>11) & 1) // dynamic register list + { + sprintf(g_dasm_str, "fmovem.x %s, D%d", get_ea_mode_str_32(g_cpu_ir), (w2>>4)&7); + } + else // static register list + { + int i; + + sprintf(g_dasm_str, "fmovem.x %s, ", get_ea_mode_str_32(g_cpu_ir)); + + for (i = 0; i < 8; i++) + { + if (w2 & (1<>12) & 1) // postincrement or control + { + sprintf(temp, "FP%d ", 7-i); + } + else // predecrement + { + sprintf(temp, "FP%d ", i); + } + strcat(g_dasm_str, temp); + } + } + } + break; + } + + case 0x7: // FPU to memory, list + { + char temp[32]; + + if ((w2>>11) & 1) // dynamic register list + { + sprintf(g_dasm_str, "fmovem.x D%d, %s", (w2>>4)&7, get_ea_mode_str_32(g_cpu_ir)); + } + else // static register list + { + int i; + + sprintf(g_dasm_str, "fmovem.x "); + + for (i = 0; i < 8; i++) + { + if (w2 & (1<>12) & 1) // postincrement or control + { + sprintf(temp, "FP%d ", 7-i); + } + else // predecrement + { + sprintf(temp, "FP%d ", i); + } + strcat(g_dasm_str, temp); + } + } + + strcat(g_dasm_str, ", "); + strcat(g_dasm_str, get_ea_mode_str_32(g_cpu_ir)); + } + break; + } + + default: + { + sprintf(g_dasm_str, "FPU (?) "); + break; + } + } +} + +static void d68000_jmp(void) +{ + sprintf(g_dasm_str, "jmp %s", get_ea_mode_str_32(g_cpu_ir)); +} + +static void d68000_jsr(void) +{ + sprintf(g_dasm_str, "jsr %s", get_ea_mode_str_32(g_cpu_ir)); + SET_OPCODE_FLAGS(DASMFLAG_STEP_OVER); +} + +static void d68000_lea(void) +{ + sprintf(g_dasm_str, "lea %s, A%d", get_ea_mode_str_32(g_cpu_ir), (g_cpu_ir>>9)&7); +} + +static void d68000_link_16(void) +{ + sprintf(g_dasm_str, "link A%d, %s", g_cpu_ir&7, get_imm_str_s16()); +} + +static void d68020_link_32(void) +{ + LIMIT_CPU_TYPES(M68020_PLUS); + sprintf(g_dasm_str, "link A%d, %s; (2+)", g_cpu_ir&7, get_imm_str_s32()); +} + +static void d68000_lsr_s_8(void) +{ + sprintf(g_dasm_str, "lsr.b #%d, D%d", g_3bit_qdata_table[(g_cpu_ir>>9)&7], g_cpu_ir&7); +} + +static void d68000_lsr_s_16(void) +{ + sprintf(g_dasm_str, "lsr.w #%d, D%d", g_3bit_qdata_table[(g_cpu_ir>>9)&7], g_cpu_ir&7); +} + +static void d68000_lsr_s_32(void) +{ + sprintf(g_dasm_str, "lsr.l #%d, D%d", g_3bit_qdata_table[(g_cpu_ir>>9)&7], g_cpu_ir&7); +} + +static void d68000_lsr_r_8(void) +{ + sprintf(g_dasm_str, "lsr.b D%d, D%d", (g_cpu_ir>>9)&7, g_cpu_ir&7); +} + +static void d68000_lsr_r_16(void) +{ + sprintf(g_dasm_str, "lsr.w D%d, D%d", (g_cpu_ir>>9)&7, g_cpu_ir&7); +} + +static void d68000_lsr_r_32(void) +{ + sprintf(g_dasm_str, "lsr.l D%d, D%d", (g_cpu_ir>>9)&7, g_cpu_ir&7); +} + +static void d68000_lsr_ea(void) +{ + sprintf(g_dasm_str, "lsr.w %s", get_ea_mode_str_32(g_cpu_ir)); +} + +static void d68000_lsl_s_8(void) +{ + sprintf(g_dasm_str, "lsl.b #%d, D%d", g_3bit_qdata_table[(g_cpu_ir>>9)&7], g_cpu_ir&7); +} + +static void d68000_lsl_s_16(void) +{ + sprintf(g_dasm_str, "lsl.w #%d, D%d", g_3bit_qdata_table[(g_cpu_ir>>9)&7], g_cpu_ir&7); +} + +static void d68000_lsl_s_32(void) +{ + sprintf(g_dasm_str, "lsl.l #%d, D%d", g_3bit_qdata_table[(g_cpu_ir>>9)&7], g_cpu_ir&7); +} + +static void d68000_lsl_r_8(void) +{ + sprintf(g_dasm_str, "lsl.b D%d, D%d", (g_cpu_ir>>9)&7, g_cpu_ir&7); +} + +static void d68000_lsl_r_16(void) +{ + sprintf(g_dasm_str, "lsl.w D%d, D%d", (g_cpu_ir>>9)&7, g_cpu_ir&7); +} + +static void d68000_lsl_r_32(void) +{ + sprintf(g_dasm_str, "lsl.l D%d, D%d", (g_cpu_ir>>9)&7, g_cpu_ir&7); +} + +static void d68000_lsl_ea(void) +{ + sprintf(g_dasm_str, "lsl.w %s", get_ea_mode_str_32(g_cpu_ir)); +} + +static void d68000_move_8(void) +{ + char* str = get_ea_mode_str_8(g_cpu_ir); + sprintf(g_dasm_str, "move.b %s, %s", str, get_ea_mode_str_8(((g_cpu_ir>>9) & 7) | ((g_cpu_ir>>3) & 0x38))); +} + +static void d68000_move_16(void) +{ + char* str = get_ea_mode_str_16(g_cpu_ir); + sprintf(g_dasm_str, "move.w %s, %s", str, get_ea_mode_str_16(((g_cpu_ir>>9) & 7) | ((g_cpu_ir>>3) & 0x38))); +} + +static void d68000_move_32(void) +{ + char* str = get_ea_mode_str_32(g_cpu_ir); + sprintf(g_dasm_str, "move.l %s, %s", str, get_ea_mode_str_32(((g_cpu_ir>>9) & 7) | ((g_cpu_ir>>3) & 0x38))); +} + +static void d68000_movea_16(void) +{ + sprintf(g_dasm_str, "movea.w %s, A%d", get_ea_mode_str_16(g_cpu_ir), (g_cpu_ir>>9)&7); +} + +static void d68000_movea_32(void) +{ + sprintf(g_dasm_str, "movea.l %s, A%d", get_ea_mode_str_32(g_cpu_ir), (g_cpu_ir>>9)&7); +} + +static void d68000_move_to_ccr(void) +{ + sprintf(g_dasm_str, "move %s, CCR", get_ea_mode_str_8(g_cpu_ir)); +} + +static void d68010_move_fr_ccr(void) +{ + LIMIT_CPU_TYPES(M68010_PLUS); + sprintf(g_dasm_str, "move CCR, %s; (1+)", get_ea_mode_str_8(g_cpu_ir)); +} + +static void d68000_move_fr_sr(void) +{ + sprintf(g_dasm_str, "move SR, %s", get_ea_mode_str_16(g_cpu_ir)); +} + +static void d68000_move_to_sr(void) +{ + sprintf(g_dasm_str, "move %s, SR", get_ea_mode_str_16(g_cpu_ir)); +} + +static void d68000_move_fr_usp(void) +{ + sprintf(g_dasm_str, "move USP, A%d", g_cpu_ir&7); +} + +static void d68000_move_to_usp(void) +{ + sprintf(g_dasm_str, "move A%d, USP", g_cpu_ir&7); +} + +static void d68010_movec(void) +{ + UINT32 extension; + const char* reg_name; + const char* processor; + LIMIT_CPU_TYPES(M68010_PLUS); + extension = read_imm_16(); + + switch(extension & 0xfff) + { + case 0x000: + reg_name = "SFC"; + processor = "1+"; + break; + case 0x001: + reg_name = "DFC"; + processor = "1+"; + break; + case 0x800: + reg_name = "USP"; + processor = "1+"; + break; + case 0x801: + reg_name = "VBR"; + processor = "1+"; + break; + case 0x002: + reg_name = "CACR"; + processor = "2+"; + break; + case 0x802: + reg_name = "CAAR"; + processor = "2,3"; + break; + case 0x803: + reg_name = "MSP"; + processor = "2+"; + break; + case 0x804: + reg_name = "ISP"; + processor = "2+"; + break; + case 0x003: + reg_name = "TC"; + processor = "4+"; + break; + case 0x004: + if(g_cpu_type & COLDFIRE) + { + reg_name = "ACR0"; + processor = "CF"; + } + else + { + reg_name = "ITT0"; + processor = "4+"; + } + break; + case 0x005: + if(g_cpu_type & COLDFIRE) + { + reg_name = "ACR1"; + processor = "CF"; + } + else + { + reg_name = "ITT1"; + processor = "4+"; + } + break; + case 0x006: + if(g_cpu_type & COLDFIRE) + { + reg_name = "ACR2"; + processor = "CF"; + } + else + { + reg_name = "DTT0"; + processor = "4+"; + } + break; + case 0x007: + if(g_cpu_type & COLDFIRE) + { + reg_name = "ACR3"; + processor = "CF"; + } + else + { + reg_name = "DTT1"; + processor = "4+"; + } + break; + case 0x805: + reg_name = "MMUSR"; + processor = "4+"; + break; + case 0x806: + reg_name = "URP"; + processor = "4+"; + break; + case 0x807: + reg_name = "SRP"; + processor = "4+"; + break; + case 0xc00: + reg_name = "ROMBAR0"; + processor = "CF"; + break; + case 0xc01: + reg_name = "ROMBAR1"; + processor = "CF"; + break; + case 0xc04: + reg_name = "RAMBAR0"; + processor = "CF"; + break; + case 0xc05: + reg_name = "RAMBAR1"; + processor = "CF"; + break; + case 0xc0c: + reg_name = "MPCR"; + processor = "CF"; + break; + case 0xc0d: + reg_name = "EDRAMBAR"; + processor = "CF"; + break; + case 0xc0e: + reg_name = "SECMBAR"; + processor = "CF"; + break; + case 0xc0f: + reg_name = "MBAR"; + processor = "CF"; + break; + default: + reg_name = make_signed_hex_str_16(extension & 0xfff); + processor = "?"; + } + + if(BIT_0(g_cpu_ir)) + sprintf(g_dasm_str, "movec %c%d, %s; (%s)", BIT_F(extension) ? 'A' : 'D', (extension>>12)&7, reg_name, processor); + else + sprintf(g_dasm_str, "movec %s, %c%d; (%s)", reg_name, BIT_F(extension) ? 'A' : 'D', (extension>>12)&7, processor); +} + +static void d68000_movem_pd_16(void) +{ + UINT32 data = read_imm_16(); + char buffer[40]; + UINT32 first; + UINT32 run_length; + UINT32 i; + + buffer[0] = 0; + for(i=0;i<8;i++) + { + if(data&(1<<(15-i))) + { + first = i; + run_length = 0; + while(i<7 && (data&(1<<(15-(i+1))))) + { + i++; + run_length++; + } + if(buffer[0] != 0) + strcat(buffer, "/"); + sprintf(buffer+strlen(buffer), "D%d", first); + if(run_length > 0) + sprintf(buffer+strlen(buffer), "-D%d", first + run_length); + } + } + for(i=0;i<8;i++) + { + if(data&(1<<(7-i))) + { + first = i; + run_length = 0; + while(i<7 && (data&(1<<(7-(i+1))))) + { + i++; + run_length++; + } + if(buffer[0] != 0) + strcat(buffer, "/"); + sprintf(buffer+strlen(buffer), "A%d", first); + if(run_length > 0) + sprintf(buffer+strlen(buffer), "-A%d", first + run_length); + } + } + sprintf(g_dasm_str, "movem.w %s, %s", buffer, get_ea_mode_str_16(g_cpu_ir)); +} + +static void d68000_movem_pd_32(void) +{ + UINT32 data = read_imm_16(); + char buffer[40]; + UINT32 first; + UINT32 run_length; + UINT32 i; + + buffer[0] = 0; + for(i=0;i<8;i++) + { + if(data&(1<<(15-i))) + { + first = i; + run_length = 0; + while(i<7 && (data&(1<<(15-(i+1))))) + { + i++; + run_length++; + } + if(buffer[0] != 0) + strcat(buffer, "/"); + sprintf(buffer+strlen(buffer), "D%d", first); + if(run_length > 0) + sprintf(buffer+strlen(buffer), "-D%d", first + run_length); + } + } + for(i=0;i<8;i++) + { + if(data&(1<<(7-i))) + { + first = i; + run_length = 0; + while(i<7 && (data&(1<<(7-(i+1))))) + { + i++; + run_length++; + } + if(buffer[0] != 0) + strcat(buffer, "/"); + sprintf(buffer+strlen(buffer), "A%d", first); + if(run_length > 0) + sprintf(buffer+strlen(buffer), "-A%d", first + run_length); + } + } + sprintf(g_dasm_str, "movem.l %s, %s", buffer, get_ea_mode_str_32(g_cpu_ir)); +} + +static void d68000_movem_er_16(void) +{ + UINT32 data = read_imm_16(); + char buffer[40]; + UINT32 first; + UINT32 run_length; + UINT32 i; + + buffer[0] = 0; + for(i=0;i<8;i++) + { + if(data&(1< 0) + sprintf(buffer+strlen(buffer), "-D%d", first + run_length); + } + } + for(i=0;i<8;i++) + { + if(data&(1<<(i+8))) + { + first = i; + run_length = 0; + while(i<7 && (data&(1<<(i+8+1)))) + { + i++; + run_length++; + } + if(buffer[0] != 0) + strcat(buffer, "/"); + sprintf(buffer+strlen(buffer), "A%d", first); + if(run_length > 0) + sprintf(buffer+strlen(buffer), "-A%d", first + run_length); + } + } + sprintf(g_dasm_str, "movem.w %s, %s", get_ea_mode_str_16(g_cpu_ir), buffer); +} + +static void d68000_movem_er_32(void) +{ + UINT32 data = read_imm_16(); + char buffer[40]; + UINT32 first; + UINT32 run_length; + UINT32 i; + + buffer[0] = 0; + for(i=0;i<8;i++) + { + if(data&(1< 0) + sprintf(buffer+strlen(buffer), "-D%d", first + run_length); + } + } + for(i=0;i<8;i++) + { + if(data&(1<<(i+8))) + { + first = i; + run_length = 0; + while(i<7 && (data&(1<<(i+8+1)))) + { + i++; + run_length++; + } + if(buffer[0] != 0) + strcat(buffer, "/"); + sprintf(buffer+strlen(buffer), "A%d", first); + if(run_length > 0) + sprintf(buffer+strlen(buffer), "-A%d", first + run_length); + } + } + sprintf(g_dasm_str, "movem.l %s, %s", get_ea_mode_str_32(g_cpu_ir), buffer); +} + +static void d68000_movem_re_16(void) +{ + UINT32 data = read_imm_16(); + char buffer[40]; + UINT32 first; + UINT32 run_length; + UINT32 i; + + buffer[0] = 0; + for(i=0;i<8;i++) + { + if(data&(1< 0) + sprintf(buffer+strlen(buffer), "-D%d", first + run_length); + } + } + for(i=0;i<8;i++) + { + if(data&(1<<(i+8))) + { + first = i; + run_length = 0; + while(i<7 && (data&(1<<(i+8+1)))) + { + i++; + run_length++; + } + if(buffer[0] != 0) + strcat(buffer, "/"); + sprintf(buffer+strlen(buffer), "A%d", first); + if(run_length > 0) + sprintf(buffer+strlen(buffer), "-A%d", first + run_length); + } + } + sprintf(g_dasm_str, "movem.w %s, %s", buffer, get_ea_mode_str_16(g_cpu_ir)); +} + +static void d68000_movem_re_32(void) +{ + UINT32 data = read_imm_16(); + char buffer[40]; + UINT32 first; + UINT32 run_length; + UINT32 i; + + buffer[0] = 0; + for(i=0;i<8;i++) + { + if(data&(1< 0) + sprintf(buffer+strlen(buffer), "-D%d", first + run_length); + } + } + for(i=0;i<8;i++) + { + if(data&(1<<(i+8))) + { + first = i; + run_length = 0; + while(i<7 && (data&(1<<(i+8+1)))) + { + i++; + run_length++; + } + if(buffer[0] != 0) + strcat(buffer, "/"); + sprintf(buffer+strlen(buffer), "A%d", first); + if(run_length > 0) + sprintf(buffer+strlen(buffer), "-A%d", first + run_length); + } + } + sprintf(g_dasm_str, "movem.l %s, %s", buffer, get_ea_mode_str_32(g_cpu_ir)); +} + +static void d68000_movep_re_16(void) +{ + sprintf(g_dasm_str, "movep.w D%d, ($%x,A%d)", (g_cpu_ir>>9)&7, read_imm_16(), g_cpu_ir&7); +} + +static void d68000_movep_re_32(void) +{ + sprintf(g_dasm_str, "movep.l D%d, ($%x,A%d)", (g_cpu_ir>>9)&7, read_imm_16(), g_cpu_ir&7); +} + +static void d68000_movep_er_16(void) +{ + sprintf(g_dasm_str, "movep.w ($%x,A%d), D%d", read_imm_16(), g_cpu_ir&7, (g_cpu_ir>>9)&7); +} + +static void d68000_movep_er_32(void) +{ + sprintf(g_dasm_str, "movep.l ($%x,A%d), D%d", read_imm_16(), g_cpu_ir&7, (g_cpu_ir>>9)&7); +} + +static void d68010_moves_8(void) +{ + UINT32 extension; + LIMIT_CPU_TYPES(M68010_PLUS); + extension = read_imm_16(); + if(BIT_B(extension)) + sprintf(g_dasm_str, "moves.b %c%d, %s; (1+)", BIT_F(extension) ? 'A' : 'D', (extension>>12)&7, get_ea_mode_str_8(g_cpu_ir)); + else + sprintf(g_dasm_str, "moves.b %s, %c%d; (1+)", get_ea_mode_str_8(g_cpu_ir), BIT_F(extension) ? 'A' : 'D', (extension>>12)&7); +} + +static void d68010_moves_16(void) +{ + UINT32 extension; + LIMIT_CPU_TYPES(M68010_PLUS); + extension = read_imm_16(); + if(BIT_B(extension)) + sprintf(g_dasm_str, "moves.w %c%d, %s; (1+)", BIT_F(extension) ? 'A' : 'D', (extension>>12)&7, get_ea_mode_str_16(g_cpu_ir)); + else + sprintf(g_dasm_str, "moves.w %s, %c%d; (1+)", get_ea_mode_str_16(g_cpu_ir), BIT_F(extension) ? 'A' : 'D', (extension>>12)&7); +} + +static void d68010_moves_32(void) +{ + UINT32 extension; + LIMIT_CPU_TYPES(M68010_PLUS); + extension = read_imm_16(); + if(BIT_B(extension)) + sprintf(g_dasm_str, "moves.l %c%d, %s; (1+)", BIT_F(extension) ? 'A' : 'D', (extension>>12)&7, get_ea_mode_str_32(g_cpu_ir)); + else + sprintf(g_dasm_str, "moves.l %s, %c%d; (1+)", get_ea_mode_str_32(g_cpu_ir), BIT_F(extension) ? 'A' : 'D', (extension>>12)&7); +} + +static void d68000_moveq(void) +{ + sprintf(g_dasm_str, "moveq #%s, D%d", make_signed_hex_str_8(g_cpu_ir), (g_cpu_ir>>9)&7); +} + +static void d68040_move16_pi_pi(void) +{ + LIMIT_CPU_TYPES(M68040_PLUS); + sprintf(g_dasm_str, "move16 (A%d)+, (A%d)+; (4)", g_cpu_ir&7, (read_imm_16()>>12)&7); +} + +static void d68040_move16_pi_al(void) +{ + LIMIT_CPU_TYPES(M68040_PLUS); + sprintf(g_dasm_str, "move16 (A%d)+, %s; (4)", g_cpu_ir&7, get_imm_str_u32()); +} + +static void d68040_move16_al_pi(void) +{ + LIMIT_CPU_TYPES(M68040_PLUS); + sprintf(g_dasm_str, "move16 %s, (A%d)+; (4)", get_imm_str_u32(), g_cpu_ir&7); +} + +static void d68040_move16_ai_al(void) +{ + LIMIT_CPU_TYPES(M68040_PLUS); + sprintf(g_dasm_str, "move16 (A%d), %s; (4)", g_cpu_ir&7, get_imm_str_u32()); +} + +static void d68040_move16_al_ai(void) +{ + LIMIT_CPU_TYPES(M68040_PLUS); + sprintf(g_dasm_str, "move16 %s, (A%d); (4)", get_imm_str_u32(), g_cpu_ir&7); +} + +static void d68000_muls(void) +{ + sprintf(g_dasm_str, "muls.w %s, D%d", get_ea_mode_str_16(g_cpu_ir), (g_cpu_ir>>9)&7); +} + +static void d68000_mulu(void) +{ + sprintf(g_dasm_str, "mulu.w %s, D%d", get_ea_mode_str_16(g_cpu_ir), (g_cpu_ir>>9)&7); +} + +static void d68020_mull(void) +{ + UINT32 extension; + LIMIT_CPU_TYPES(M68020_PLUS); + extension = read_imm_16(); + + if(BIT_A(extension)) + sprintf(g_dasm_str, "mul%c.l %s, D%d-D%d; (2+)", BIT_B(extension) ? 's' : 'u', get_ea_mode_str_32(g_cpu_ir), extension&7, (extension>>12)&7); + else + sprintf(g_dasm_str, "mul%c.l %s, D%d; (2+)", BIT_B(extension) ? 's' : 'u', get_ea_mode_str_32(g_cpu_ir), (extension>>12)&7); +} + +static void d68000_nbcd(void) +{ + sprintf(g_dasm_str, "nbcd %s", get_ea_mode_str_8(g_cpu_ir)); +} + +static void d68000_neg_8(void) +{ + sprintf(g_dasm_str, "neg.b %s", get_ea_mode_str_8(g_cpu_ir)); +} + +static void d68000_neg_16(void) +{ + sprintf(g_dasm_str, "neg.w %s", get_ea_mode_str_16(g_cpu_ir)); +} + +static void d68000_neg_32(void) +{ + sprintf(g_dasm_str, "neg.l %s", get_ea_mode_str_32(g_cpu_ir)); +} + +static void d68000_negx_8(void) +{ + sprintf(g_dasm_str, "negx.b %s", get_ea_mode_str_8(g_cpu_ir)); +} + +static void d68000_negx_16(void) +{ + sprintf(g_dasm_str, "negx.w %s", get_ea_mode_str_16(g_cpu_ir)); +} + +static void d68000_negx_32(void) +{ + sprintf(g_dasm_str, "negx.l %s", get_ea_mode_str_32(g_cpu_ir)); +} + +static void d68000_nop(void) +{ + sprintf(g_dasm_str, "nop"); +} + +static void d68000_not_8(void) +{ + sprintf(g_dasm_str, "not.b %s", get_ea_mode_str_8(g_cpu_ir)); +} + +static void d68000_not_16(void) +{ + sprintf(g_dasm_str, "not.w %s", get_ea_mode_str_16(g_cpu_ir)); +} + +static void d68000_not_32(void) +{ + sprintf(g_dasm_str, "not.l %s", get_ea_mode_str_32(g_cpu_ir)); +} + +static void d68000_or_er_8(void) +{ + sprintf(g_dasm_str, "or.b %s, D%d", get_ea_mode_str_8(g_cpu_ir), (g_cpu_ir>>9)&7); +} + +static void d68000_or_er_16(void) +{ + sprintf(g_dasm_str, "or.w %s, D%d", get_ea_mode_str_16(g_cpu_ir), (g_cpu_ir>>9)&7); +} + +static void d68000_or_er_32(void) +{ + sprintf(g_dasm_str, "or.l %s, D%d", get_ea_mode_str_32(g_cpu_ir), (g_cpu_ir>>9)&7); +} + +static void d68000_or_re_8(void) +{ + sprintf(g_dasm_str, "or.b D%d, %s", (g_cpu_ir>>9)&7, get_ea_mode_str_8(g_cpu_ir)); +} + +static void d68000_or_re_16(void) +{ + sprintf(g_dasm_str, "or.w D%d, %s", (g_cpu_ir>>9)&7, get_ea_mode_str_16(g_cpu_ir)); +} + +static void d68000_or_re_32(void) +{ + sprintf(g_dasm_str, "or.l D%d, %s", (g_cpu_ir>>9)&7, get_ea_mode_str_32(g_cpu_ir)); +} + +static void d68000_ori_8(void) +{ + char* str = get_imm_str_u8(); + sprintf(g_dasm_str, "ori.b %s, %s", str, get_ea_mode_str_8(g_cpu_ir)); +} + +static void d68000_ori_16(void) +{ + char* str = get_imm_str_u16(); + sprintf(g_dasm_str, "ori.w %s, %s", str, get_ea_mode_str_16(g_cpu_ir)); +} + +static void d68000_ori_32(void) +{ + char* str = get_imm_str_u32(); + sprintf(g_dasm_str, "ori.l %s, %s", str, get_ea_mode_str_32(g_cpu_ir)); +} + +static void d68000_ori_to_ccr(void) +{ + sprintf(g_dasm_str, "ori %s, CCR", get_imm_str_u8()); +} + +static void d68000_ori_to_sr(void) +{ + sprintf(g_dasm_str, "ori %s, SR", get_imm_str_u16()); +} + +static void d68020_pack_rr(void) +{ + LIMIT_CPU_TYPES(M68020_PLUS); + sprintf(g_dasm_str, "pack D%d, D%d, %s; (2+)", g_cpu_ir&7, (g_cpu_ir>>9)&7, get_imm_str_u16()); +} + +static void d68020_pack_mm(void) +{ + LIMIT_CPU_TYPES(M68020_PLUS); + sprintf(g_dasm_str, "pack -(A%d), -(A%d), %s; (2+)", g_cpu_ir&7, (g_cpu_ir>>9)&7, get_imm_str_u16()); +} + +static void d68000_pea(void) +{ + sprintf(g_dasm_str, "pea %s", get_ea_mode_str_32(g_cpu_ir)); +} + +// this is a 68040-specific form of PFLUSH +static void d68040_pflush(void) +{ + LIMIT_CPU_TYPES(M68040_PLUS); + + if (g_cpu_ir & 0x10) + { + sprintf(g_dasm_str, "pflusha%s", (g_cpu_ir & 8) ? "" : "n"); + } + else + { + sprintf(g_dasm_str, "pflush%s(A%d)", (g_cpu_ir & 8) ? "" : "n", g_cpu_ir & 7); + } +} + +static void d68000_reset(void) +{ + sprintf(g_dasm_str, "reset"); +} + +static void d68000_ror_s_8(void) +{ + sprintf(g_dasm_str, "ror.b #%d, D%d", g_3bit_qdata_table[(g_cpu_ir>>9)&7], g_cpu_ir&7); +} + +static void d68000_ror_s_16(void) +{ + sprintf(g_dasm_str, "ror.w #%d, D%d", g_3bit_qdata_table[(g_cpu_ir>>9)&7],g_cpu_ir&7); +} + +static void d68000_ror_s_32(void) +{ + sprintf(g_dasm_str, "ror.l #%d, D%d", g_3bit_qdata_table[(g_cpu_ir>>9)&7], g_cpu_ir&7); +} + +static void d68000_ror_r_8(void) +{ + sprintf(g_dasm_str, "ror.b D%d, D%d", (g_cpu_ir>>9)&7, g_cpu_ir&7); +} + +static void d68000_ror_r_16(void) +{ + sprintf(g_dasm_str, "ror.w D%d, D%d", (g_cpu_ir>>9)&7, g_cpu_ir&7); +} + +static void d68000_ror_r_32(void) +{ + sprintf(g_dasm_str, "ror.l D%d, D%d", (g_cpu_ir>>9)&7, g_cpu_ir&7); +} + +static void d68000_ror_ea(void) +{ + sprintf(g_dasm_str, "ror.w %s", get_ea_mode_str_32(g_cpu_ir)); +} + +static void d68000_rol_s_8(void) +{ + sprintf(g_dasm_str, "rol.b #%d, D%d", g_3bit_qdata_table[(g_cpu_ir>>9)&7], g_cpu_ir&7); +} + +static void d68000_rol_s_16(void) +{ + sprintf(g_dasm_str, "rol.w #%d, D%d", g_3bit_qdata_table[(g_cpu_ir>>9)&7], g_cpu_ir&7); +} + +static void d68000_rol_s_32(void) +{ + sprintf(g_dasm_str, "rol.l #%d, D%d", g_3bit_qdata_table[(g_cpu_ir>>9)&7], g_cpu_ir&7); +} + +static void d68000_rol_r_8(void) +{ + sprintf(g_dasm_str, "rol.b D%d, D%d", (g_cpu_ir>>9)&7, g_cpu_ir&7); +} + +static void d68000_rol_r_16(void) +{ + sprintf(g_dasm_str, "rol.w D%d, D%d", (g_cpu_ir>>9)&7, g_cpu_ir&7); +} + +static void d68000_rol_r_32(void) +{ + sprintf(g_dasm_str, "rol.l D%d, D%d", (g_cpu_ir>>9)&7, g_cpu_ir&7); +} + +static void d68000_rol_ea(void) +{ + sprintf(g_dasm_str, "rol.w %s", get_ea_mode_str_32(g_cpu_ir)); +} + +static void d68000_roxr_s_8(void) +{ + sprintf(g_dasm_str, "roxr.b #%d, D%d", g_3bit_qdata_table[(g_cpu_ir>>9)&7], g_cpu_ir&7); +} + +static void d68000_roxr_s_16(void) +{ + sprintf(g_dasm_str, "roxr.w #%d, D%d", g_3bit_qdata_table[(g_cpu_ir>>9)&7], g_cpu_ir&7); +} + + +static void d68000_roxr_s_32(void) +{ + sprintf(g_dasm_str, "roxr.l #%d, D%d", g_3bit_qdata_table[(g_cpu_ir>>9)&7], g_cpu_ir&7); +} + +static void d68000_roxr_r_8(void) +{ + sprintf(g_dasm_str, "roxr.b D%d, D%d", (g_cpu_ir>>9)&7, g_cpu_ir&7); +} + +static void d68000_roxr_r_16(void) +{ + sprintf(g_dasm_str, "roxr.w D%d, D%d", (g_cpu_ir>>9)&7, g_cpu_ir&7); +} + +static void d68000_roxr_r_32(void) +{ + sprintf(g_dasm_str, "roxr.l D%d, D%d", (g_cpu_ir>>9)&7, g_cpu_ir&7); +} + +static void d68000_roxr_ea(void) +{ + sprintf(g_dasm_str, "roxr.w %s", get_ea_mode_str_32(g_cpu_ir)); +} + +static void d68000_roxl_s_8(void) +{ + sprintf(g_dasm_str, "roxl.b #%d, D%d", g_3bit_qdata_table[(g_cpu_ir>>9)&7], g_cpu_ir&7); +} + +static void d68000_roxl_s_16(void) +{ + sprintf(g_dasm_str, "roxl.w #%d, D%d", g_3bit_qdata_table[(g_cpu_ir>>9)&7], g_cpu_ir&7); +} + +static void d68000_roxl_s_32(void) +{ + sprintf(g_dasm_str, "roxl.l #%d, D%d", g_3bit_qdata_table[(g_cpu_ir>>9)&7], g_cpu_ir&7); +} + +static void d68000_roxl_r_8(void) +{ + sprintf(g_dasm_str, "roxl.b D%d, D%d", (g_cpu_ir>>9)&7, g_cpu_ir&7); +} + +static void d68000_roxl_r_16(void) +{ + sprintf(g_dasm_str, "roxl.w D%d, D%d", (g_cpu_ir>>9)&7, g_cpu_ir&7); +} + +static void d68000_roxl_r_32(void) +{ + sprintf(g_dasm_str, "roxl.l D%d, D%d", (g_cpu_ir>>9)&7, g_cpu_ir&7); +} + +static void d68000_roxl_ea(void) +{ + sprintf(g_dasm_str, "roxl.w %s", get_ea_mode_str_32(g_cpu_ir)); +} + +static void d68010_rtd(void) +{ + LIMIT_CPU_TYPES(M68010_PLUS); + sprintf(g_dasm_str, "rtd %s; (1+)", get_imm_str_s16()); + SET_OPCODE_FLAGS(DASMFLAG_STEP_OUT); +} + +static void d68000_rte(void) +{ + sprintf(g_dasm_str, "rte"); + SET_OPCODE_FLAGS(DASMFLAG_STEP_OUT); +} + +static void d68020_rtm(void) +{ + LIMIT_CPU_TYPES(M68020_ONLY); + sprintf(g_dasm_str, "rtm %c%d; (2+)", BIT_3(g_cpu_ir) ? 'A' : 'D', g_cpu_ir&7); + SET_OPCODE_FLAGS(DASMFLAG_STEP_OUT); +} + +static void d68000_rtr(void) +{ + sprintf(g_dasm_str, "rtr"); + SET_OPCODE_FLAGS(DASMFLAG_STEP_OUT); +} + +static void d68000_rts(void) +{ + sprintf(g_dasm_str, "rts"); + SET_OPCODE_FLAGS(DASMFLAG_STEP_OUT); +} + +static void d68000_sbcd_rr(void) +{ + sprintf(g_dasm_str, "sbcd D%d, D%d", g_cpu_ir&7, (g_cpu_ir>>9)&7); +} + +static void d68000_sbcd_mm(void) +{ + sprintf(g_dasm_str, "sbcd -(A%d), -(A%d)", g_cpu_ir&7, (g_cpu_ir>>9)&7); +} + +static void d68000_scc(void) +{ + sprintf(g_dasm_str, "s%-2s %s", g_cc[(g_cpu_ir>>8)&0xf], get_ea_mode_str_8(g_cpu_ir)); +} + +static void d68000_stop(void) +{ + sprintf(g_dasm_str, "stop %s", get_imm_str_s16()); +} + +static void d68000_sub_er_8(void) +{ + sprintf(g_dasm_str, "sub.b %s, D%d", get_ea_mode_str_8(g_cpu_ir), (g_cpu_ir>>9)&7); +} + +static void d68000_sub_er_16(void) +{ + sprintf(g_dasm_str, "sub.w %s, D%d", get_ea_mode_str_16(g_cpu_ir), (g_cpu_ir>>9)&7); +} + +static void d68000_sub_er_32(void) +{ + sprintf(g_dasm_str, "sub.l %s, D%d", get_ea_mode_str_32(g_cpu_ir), (g_cpu_ir>>9)&7); +} + +static void d68000_sub_re_8(void) +{ + sprintf(g_dasm_str, "sub.b D%d, %s", (g_cpu_ir>>9)&7, get_ea_mode_str_8(g_cpu_ir)); +} + +static void d68000_sub_re_16(void) +{ + sprintf(g_dasm_str, "sub.w D%d, %s", (g_cpu_ir>>9)&7, get_ea_mode_str_16(g_cpu_ir)); +} + +static void d68000_sub_re_32(void) +{ + sprintf(g_dasm_str, "sub.l D%d, %s", (g_cpu_ir>>9)&7, get_ea_mode_str_32(g_cpu_ir)); +} + +static void d68000_suba_16(void) +{ + sprintf(g_dasm_str, "suba.w %s, A%d", get_ea_mode_str_16(g_cpu_ir), (g_cpu_ir>>9)&7); +} + +static void d68000_suba_32(void) +{ + sprintf(g_dasm_str, "suba.l %s, A%d", get_ea_mode_str_32(g_cpu_ir), (g_cpu_ir>>9)&7); +} + +static void d68000_subi_8(void) +{ + char* str = get_imm_str_s8(); + sprintf(g_dasm_str, "subi.b %s, %s", str, get_ea_mode_str_8(g_cpu_ir)); +} + +static void d68000_subi_16(void) +{ + char* str = get_imm_str_s16(); + sprintf(g_dasm_str, "subi.w %s, %s", str, get_ea_mode_str_16(g_cpu_ir)); +} + +static void d68000_subi_32(void) +{ + char* str = get_imm_str_s32(); + sprintf(g_dasm_str, "subi.l %s, %s", str, get_ea_mode_str_32(g_cpu_ir)); +} + +static void d68000_subq_8(void) +{ + sprintf(g_dasm_str, "subq.b #%d, %s", g_3bit_qdata_table[(g_cpu_ir>>9)&7], get_ea_mode_str_8(g_cpu_ir)); +} + +static void d68000_subq_16(void) +{ + sprintf(g_dasm_str, "subq.w #%d, %s", g_3bit_qdata_table[(g_cpu_ir>>9)&7], get_ea_mode_str_16(g_cpu_ir)); +} + +static void d68000_subq_32(void) +{ + sprintf(g_dasm_str, "subq.l #%d, %s", g_3bit_qdata_table[(g_cpu_ir>>9)&7], get_ea_mode_str_32(g_cpu_ir)); +} + +static void d68000_subx_rr_8(void) +{ + sprintf(g_dasm_str, "subx.b D%d, D%d", g_cpu_ir&7, (g_cpu_ir>>9)&7); +} + +static void d68000_subx_rr_16(void) +{ + sprintf(g_dasm_str, "subx.w D%d, D%d", g_cpu_ir&7, (g_cpu_ir>>9)&7); +} + +static void d68000_subx_rr_32(void) +{ + sprintf(g_dasm_str, "subx.l D%d, D%d", g_cpu_ir&7, (g_cpu_ir>>9)&7); +} + +static void d68000_subx_mm_8(void) +{ + sprintf(g_dasm_str, "subx.b -(A%d), -(A%d)", g_cpu_ir&7, (g_cpu_ir>>9)&7); +} + +static void d68000_subx_mm_16(void) +{ + sprintf(g_dasm_str, "subx.w -(A%d), -(A%d)", g_cpu_ir&7, (g_cpu_ir>>9)&7); +} + +static void d68000_subx_mm_32(void) +{ + sprintf(g_dasm_str, "subx.l -(A%d), -(A%d)", g_cpu_ir&7, (g_cpu_ir>>9)&7); +} + +static void d68000_swap(void) +{ + sprintf(g_dasm_str, "swap D%d", g_cpu_ir&7); +} + +static void d68000_tas(void) +{ + sprintf(g_dasm_str, "tas %s", get_ea_mode_str_8(g_cpu_ir)); +} + +static void d68000_trap(void) +{ + sprintf(g_dasm_str, "trap #$%x", g_cpu_ir&0xf); +} + +static void d68020_trapcc_0(void) +{ + LIMIT_CPU_TYPES(M68020_PLUS); + sprintf(g_dasm_str, "trap%-2s; (2+)", g_cc[(g_cpu_ir>>8)&0xf]); + SET_OPCODE_FLAGS(DASMFLAG_STEP_OVER); +} + +static void d68020_trapcc_16(void) +{ + LIMIT_CPU_TYPES(M68020_PLUS); + sprintf(g_dasm_str, "trap%-2s %s; (2+)", g_cc[(g_cpu_ir>>8)&0xf], get_imm_str_u16()); + SET_OPCODE_FLAGS(DASMFLAG_STEP_OVER); +} + +static void d68020_trapcc_32(void) +{ + LIMIT_CPU_TYPES(M68020_PLUS); + sprintf(g_dasm_str, "trap%-2s %s; (2+)", g_cc[(g_cpu_ir>>8)&0xf], get_imm_str_u32()); + SET_OPCODE_FLAGS(DASMFLAG_STEP_OVER); +} + +static void d68000_trapv(void) +{ + sprintf(g_dasm_str, "trapv"); + SET_OPCODE_FLAGS(DASMFLAG_STEP_OVER); +} + +static void d68000_tst_8(void) +{ + sprintf(g_dasm_str, "tst.b %s", get_ea_mode_str_8(g_cpu_ir)); +} + +static void d68020_tst_pcdi_8(void) +{ + LIMIT_CPU_TYPES(M68020_PLUS); + sprintf(g_dasm_str, "tst.b %s; (2+)", get_ea_mode_str_8(g_cpu_ir)); +} + +static void d68020_tst_pcix_8(void) +{ + LIMIT_CPU_TYPES(M68020_PLUS); + sprintf(g_dasm_str, "tst.b %s; (2+)", get_ea_mode_str_8(g_cpu_ir)); +} + +static void d68020_tst_i_8(void) +{ + LIMIT_CPU_TYPES(M68020_PLUS); + sprintf(g_dasm_str, "tst.b %s; (2+)", get_ea_mode_str_8(g_cpu_ir)); +} + +static void d68000_tst_16(void) +{ + sprintf(g_dasm_str, "tst.w %s", get_ea_mode_str_16(g_cpu_ir)); +} + +static void d68020_tst_a_16(void) +{ + LIMIT_CPU_TYPES(M68020_PLUS); + sprintf(g_dasm_str, "tst.w %s; (2+)", get_ea_mode_str_16(g_cpu_ir)); +} + +static void d68020_tst_pcdi_16(void) +{ + LIMIT_CPU_TYPES(M68020_PLUS); + sprintf(g_dasm_str, "tst.w %s; (2+)", get_ea_mode_str_16(g_cpu_ir)); +} + +static void d68020_tst_pcix_16(void) +{ + LIMIT_CPU_TYPES(M68020_PLUS); + sprintf(g_dasm_str, "tst.w %s; (2+)", get_ea_mode_str_16(g_cpu_ir)); +} + +static void d68020_tst_i_16(void) +{ + LIMIT_CPU_TYPES(M68020_PLUS); + sprintf(g_dasm_str, "tst.w %s; (2+)", get_ea_mode_str_16(g_cpu_ir)); +} + +static void d68000_tst_32(void) +{ + sprintf(g_dasm_str, "tst.l %s", get_ea_mode_str_32(g_cpu_ir)); +} + +static void d68020_tst_a_32(void) +{ + LIMIT_CPU_TYPES(M68020_PLUS); + sprintf(g_dasm_str, "tst.l %s; (2+)", get_ea_mode_str_32(g_cpu_ir)); +} + +static void d68020_tst_pcdi_32(void) +{ + LIMIT_CPU_TYPES(M68020_PLUS); + sprintf(g_dasm_str, "tst.l %s; (2+)", get_ea_mode_str_32(g_cpu_ir)); +} + +static void d68020_tst_pcix_32(void) +{ + LIMIT_CPU_TYPES(M68020_PLUS); + sprintf(g_dasm_str, "tst.l %s; (2+)", get_ea_mode_str_32(g_cpu_ir)); +} + +static void d68020_tst_i_32(void) +{ + LIMIT_CPU_TYPES(M68020_PLUS); + sprintf(g_dasm_str, "tst.l %s; (2+)", get_ea_mode_str_32(g_cpu_ir)); +} + +static void d68000_unlk(void) +{ + sprintf(g_dasm_str, "unlk A%d", g_cpu_ir&7); +} + +static void d68020_unpk_rr(void) +{ + LIMIT_CPU_TYPES(M68020_PLUS); + sprintf(g_dasm_str, "unpk D%d, D%d, %s; (2+)", g_cpu_ir&7, (g_cpu_ir>>9)&7, get_imm_str_u16()); +} + +static void d68020_unpk_mm(void) +{ + LIMIT_CPU_TYPES(M68020_PLUS); + sprintf(g_dasm_str, "unpk -(A%d), -(A%d), %s; (2+)", g_cpu_ir&7, (g_cpu_ir>>9)&7, get_imm_str_u16()); +} + + +// PFLUSH: 001xxx0xxxxxxxxx +// PLOAD: 001000x0000xxxxx +// PVALID1: 0010100000000000 +// PVALID2: 0010110000000xxx +// PMOVE 1: 010xxxx000000000 +// PMOVE 2: 011xxxx0000xxx00 +// PMOVE 3: 011xxxx000000000 +// PTEST: 100xxxxxxxxxxxxx +// PFLUSHR: 1010000000000000 +static void d68851_p000(void) +{ + char* str; + UINT16 modes = read_imm_16(); + + // do this after fetching the second PMOVE word so we properly get the 3rd if necessary + str = get_ea_mode_str_32(g_cpu_ir); + + if ((modes & 0xfde0) == 0x2000) // PLOAD + { + if (modes & 0x0200) + { + sprintf(g_dasm_str, "pload #%d, %s", (modes>>10)&7, str); + } + else + { + sprintf(g_dasm_str, "pload %s, #%d", str, (modes>>10)&7); + } + return; + } + + if ((modes & 0xe200) == 0x2000) // PFLUSH + { + sprintf(g_dasm_str, "pflushr %x, %x, %s", modes & 0x1f, (modes>>5)&0xf, str); + return; + } + + if (modes == 0xa000) // PFLUSHR + { + sprintf(g_dasm_str, "pflushr %s", str); + } + + if (modes == 0x2800) // PVALID (FORMAT 1) + { + sprintf(g_dasm_str, "pvalid VAL, %s", str); + return; + } + + if ((modes & 0xfff8) == 0x2c00) // PVALID (FORMAT 2) + { + sprintf(g_dasm_str, "pvalid A%d, %s", modes & 0xf, str); + return; + } + + if ((modes & 0xe000) == 0x8000) // PTEST + { + sprintf(g_dasm_str, "ptest #%d, %s", modes & 0x1f, str); + return; + } + + switch ((modes>>13) & 0x7) + { + case 0: // MC68030/040 form with FD bit + case 2: // MC68881 form, FD never set + if (modes & 0x0100) + { + if (modes & 0x0200) + { + sprintf(g_dasm_str, "pmovefd %s, %s", g_mmuregs[(modes>>10)&7], str); + } + else + { + sprintf(g_dasm_str, "pmovefd %s, %s", str, g_mmuregs[(modes>>10)&7]); + } + } + else + { + if (modes & 0x0200) + { + sprintf(g_dasm_str, "pmove %s, %s", g_mmuregs[(modes>>10)&7], str); + } + else + { + sprintf(g_dasm_str, "pmove %s, %s", str, g_mmuregs[(modes>>10)&7]); + } + } + break; + + case 3: // MC68030 to/from status reg + if (modes & 0x0200) + { + sprintf(g_dasm_str, "pmove mmusr, %s", str); + } + else + { + sprintf(g_dasm_str, "pmove %s, mmusr", str); + } + break; + + default: + sprintf(g_dasm_str, "pmove [unknown form] %s", str); + break; + } +} + +static void d68851_pbcc16(void) +{ + UINT32 temp_pc = g_cpu_pc; + + sprintf(g_dasm_str, "pb%s %x", g_mmucond[g_cpu_ir&0xf], temp_pc + make_int_16(read_imm_16())); +} + +static void d68851_pbcc32(void) +{ + UINT32 temp_pc = g_cpu_pc; + + sprintf(g_dasm_str, "pb%s %x", g_mmucond[g_cpu_ir&0xf], temp_pc + make_int_32(read_imm_32())); +} + +static void d68851_pdbcc(void) +{ + UINT32 temp_pc = g_cpu_pc; + UINT16 modes = read_imm_16(); + + sprintf(g_dasm_str, "pb%s %x", g_mmucond[modes&0xf], temp_pc + make_int_16(read_imm_16())); +} + +// PScc: 0000000000xxxxxx +static void d68851_p001(void) +{ + sprintf(g_dasm_str, "MMU 001 group"); +} + +// fbcc is 68040 and 68881 +static void d68040_fbcc_16() +{ + LIMIT_CPU_TYPES(M68030_PLUS); + UINT32 temp_pc = g_cpu_pc; + INT16 disp = make_int_16(read_imm_16()); + sprintf(g_dasm_str, "fb%-s $%x", g_cpcc[g_cpu_ir & 0x3f], temp_pc + disp); +} + +static void d68040_fbcc_32() +{ + LIMIT_CPU_TYPES(M68030_PLUS); + UINT32 temp_pc = g_cpu_pc; + UINT32 disp = read_imm_32(); + sprintf(g_dasm_str, "fb%-s $%x", g_cpcc[g_cpu_ir & 0x3f], temp_pc + disp); +} + +/* ======================================================================== */ +/* ======================= INSTRUCTION TABLE BUILDER ====================== */ +/* ======================================================================== */ + +/* EA Masks: +800 = data register direct +400 = address register direct +200 = address register indirect +100 = ARI postincrement + 80 = ARI pre-decrement + 40 = ARI displacement + 20 = ARI index + 10 = absolute short + 8 = absolute long + 4 = immediate / sr + 2 = pc displacement + 1 = pc idx +*/ + +static const opcode_struct g_opcode_info[] = +{ +/* opcode handler mask match ea mask */ + {d68000_1010 , 0xf000, 0xa000, 0x000}, + {d68000_1111 , 0xf000, 0xf000, 0x000}, + {d68000_abcd_rr , 0xf1f8, 0xc100, 0x000}, + {d68000_abcd_mm , 0xf1f8, 0xc108, 0x000}, + {d68000_add_er_8 , 0xf1c0, 0xd000, 0xbff}, + {d68000_add_er_16 , 0xf1c0, 0xd040, 0xfff}, + {d68000_add_er_32 , 0xf1c0, 0xd080, 0xfff}, + {d68000_add_re_8 , 0xf1c0, 0xd100, 0x3f8}, + {d68000_add_re_16 , 0xf1c0, 0xd140, 0x3f8}, + {d68000_add_re_32 , 0xf1c0, 0xd180, 0x3f8}, + {d68000_adda_16 , 0xf1c0, 0xd0c0, 0xfff}, + {d68000_adda_32 , 0xf1c0, 0xd1c0, 0xfff}, + {d68000_addi_8 , 0xffc0, 0x0600, 0xbf8}, + {d68000_addi_16 , 0xffc0, 0x0640, 0xbf8}, + {d68000_addi_32 , 0xffc0, 0x0680, 0xbf8}, + {d68000_addq_8 , 0xf1c0, 0x5000, 0xbf8}, + {d68000_addq_16 , 0xf1c0, 0x5040, 0xff8}, + {d68000_addq_32 , 0xf1c0, 0x5080, 0xff8}, + {d68000_addx_rr_8 , 0xf1f8, 0xd100, 0x000}, + {d68000_addx_rr_16 , 0xf1f8, 0xd140, 0x000}, + {d68000_addx_rr_32 , 0xf1f8, 0xd180, 0x000}, + {d68000_addx_mm_8 , 0xf1f8, 0xd108, 0x000}, + {d68000_addx_mm_16 , 0xf1f8, 0xd148, 0x000}, + {d68000_addx_mm_32 , 0xf1f8, 0xd188, 0x000}, + {d68000_and_er_8 , 0xf1c0, 0xc000, 0xbff}, + {d68000_and_er_16 , 0xf1c0, 0xc040, 0xbff}, + {d68000_and_er_32 , 0xf1c0, 0xc080, 0xbff}, + {d68000_and_re_8 , 0xf1c0, 0xc100, 0x3f8}, + {d68000_and_re_16 , 0xf1c0, 0xc140, 0x3f8}, + {d68000_and_re_32 , 0xf1c0, 0xc180, 0x3f8}, + {d68000_andi_to_ccr , 0xffff, 0x023c, 0x000}, + {d68000_andi_to_sr , 0xffff, 0x027c, 0x000}, + {d68000_andi_8 , 0xffc0, 0x0200, 0xbf8}, + {d68000_andi_16 , 0xffc0, 0x0240, 0xbf8}, + {d68000_andi_32 , 0xffc0, 0x0280, 0xbf8}, + {d68000_asr_s_8 , 0xf1f8, 0xe000, 0x000}, + {d68000_asr_s_16 , 0xf1f8, 0xe040, 0x000}, + {d68000_asr_s_32 , 0xf1f8, 0xe080, 0x000}, + {d68000_asr_r_8 , 0xf1f8, 0xe020, 0x000}, + {d68000_asr_r_16 , 0xf1f8, 0xe060, 0x000}, + {d68000_asr_r_32 , 0xf1f8, 0xe0a0, 0x000}, + {d68000_asr_ea , 0xffc0, 0xe0c0, 0x3f8}, + {d68000_asl_s_8 , 0xf1f8, 0xe100, 0x000}, + {d68000_asl_s_16 , 0xf1f8, 0xe140, 0x000}, + {d68000_asl_s_32 , 0xf1f8, 0xe180, 0x000}, + {d68000_asl_r_8 , 0xf1f8, 0xe120, 0x000}, + {d68000_asl_r_16 , 0xf1f8, 0xe160, 0x000}, + {d68000_asl_r_32 , 0xf1f8, 0xe1a0, 0x000}, + {d68000_asl_ea , 0xffc0, 0xe1c0, 0x3f8}, + {d68000_bcc_8 , 0xf000, 0x6000, 0x000}, + {d68000_bcc_16 , 0xf0ff, 0x6000, 0x000}, + {d68020_bcc_32 , 0xf0ff, 0x60ff, 0x000}, + {d68000_bchg_r , 0xf1c0, 0x0140, 0xbf8}, + {d68000_bchg_s , 0xffc0, 0x0840, 0xbf8}, + {d68000_bclr_r , 0xf1c0, 0x0180, 0xbf8}, + {d68000_bclr_s , 0xffc0, 0x0880, 0xbf8}, + {d68020_bfchg , 0xffc0, 0xeac0, 0xa78}, + {d68020_bfclr , 0xffc0, 0xecc0, 0xa78}, + {d68020_bfexts , 0xffc0, 0xebc0, 0xa7b}, + {d68020_bfextu , 0xffc0, 0xe9c0, 0xa7b}, + {d68020_bfffo , 0xffc0, 0xedc0, 0xa7b}, + {d68020_bfins , 0xffc0, 0xefc0, 0xa78}, + {d68020_bfset , 0xffc0, 0xeec0, 0xa78}, + {d68020_bftst , 0xffc0, 0xe8c0, 0xa7b}, + {d68881_ftrap , 0xfff8, 0xf278, 0x000}, + {d68010_bkpt , 0xfff8, 0x4848, 0x000}, + {d68000_bra_8 , 0xff00, 0x6000, 0x000}, + {d68000_bra_16 , 0xffff, 0x6000, 0x000}, + {d68020_bra_32 , 0xffff, 0x60ff, 0x000}, + {d68000_bset_r , 0xf1c0, 0x01c0, 0xbf8}, + {d68000_bset_s , 0xffc0, 0x08c0, 0xbf8}, + {d68000_bsr_8 , 0xff00, 0x6100, 0x000}, + {d68000_bsr_16 , 0xffff, 0x6100, 0x000}, + {d68020_bsr_32 , 0xffff, 0x61ff, 0x000}, + {d68000_btst_r , 0xf1c0, 0x0100, 0xbff}, + {d68000_btst_s , 0xffc0, 0x0800, 0xbfb}, + {d68020_callm , 0xffc0, 0x06c0, 0x27b}, + {d68020_cas_8 , 0xffc0, 0x0ac0, 0x3f8}, + {d68020_cas_16 , 0xffc0, 0x0cc0, 0x3f8}, + {d68020_cas_32 , 0xffc0, 0x0ec0, 0x3f8}, + {d68020_cas2_16 , 0xffff, 0x0cfc, 0x000}, + {d68020_cas2_32 , 0xffff, 0x0efc, 0x000}, + {d68000_chk_16 , 0xf1c0, 0x4180, 0xbff}, + {d68020_chk_32 , 0xf1c0, 0x4100, 0xbff}, + {d68020_chk2_cmp2_8 , 0xffc0, 0x00c0, 0x27b}, + {d68020_chk2_cmp2_16 , 0xffc0, 0x02c0, 0x27b}, + {d68020_chk2_cmp2_32 , 0xffc0, 0x04c0, 0x27b}, + {d68040_cinv , 0xff20, 0xf400, 0x000}, + {d68000_clr_8 , 0xffc0, 0x4200, 0xbf8}, + {d68000_clr_16 , 0xffc0, 0x4240, 0xbf8}, + {d68000_clr_32 , 0xffc0, 0x4280, 0xbf8}, + {d68000_cmp_8 , 0xf1c0, 0xb000, 0xbff}, + {d68000_cmp_16 , 0xf1c0, 0xb040, 0xfff}, + {d68000_cmp_32 , 0xf1c0, 0xb080, 0xfff}, + {d68000_cmpa_16 , 0xf1c0, 0xb0c0, 0xfff}, + {d68000_cmpa_32 , 0xf1c0, 0xb1c0, 0xfff}, + {d68000_cmpi_8 , 0xffc0, 0x0c00, 0xbf8}, + {d68020_cmpi_pcdi_8 , 0xffff, 0x0c3a, 0x000}, + {d68020_cmpi_pcix_8 , 0xffff, 0x0c3b, 0x000}, + {d68000_cmpi_16 , 0xffc0, 0x0c40, 0xbf8}, + {d68020_cmpi_pcdi_16 , 0xffff, 0x0c7a, 0x000}, + {d68020_cmpi_pcix_16 , 0xffff, 0x0c7b, 0x000}, + {d68000_cmpi_32 , 0xffc0, 0x0c80, 0xbf8}, + {d68020_cmpi_pcdi_32 , 0xffff, 0x0cba, 0x000}, + {d68020_cmpi_pcix_32 , 0xffff, 0x0cbb, 0x000}, + {d68000_cmpm_8 , 0xf1f8, 0xb108, 0x000}, + {d68000_cmpm_16 , 0xf1f8, 0xb148, 0x000}, + {d68000_cmpm_32 , 0xf1f8, 0xb188, 0x000}, + {d68020_cpbcc_16 , 0xf1c0, 0xf080, 0x000}, + {d68020_cpbcc_32 , 0xf1c0, 0xf0c0, 0x000}, + {d68020_cpdbcc , 0xf1f8, 0xf048, 0x000}, + {d68020_cpgen , 0xf1c0, 0xf000, 0x000}, + {d68020_cprestore , 0xf1c0, 0xf140, 0x37f}, + {d68020_cpsave , 0xf1c0, 0xf100, 0x2f8}, + {d68020_cpscc , 0xf1c0, 0xf040, 0xbf8}, + {d68020_cptrapcc_0 , 0xf1ff, 0xf07c, 0x000}, + {d68020_cptrapcc_16 , 0xf1ff, 0xf07a, 0x000}, + {d68020_cptrapcc_32 , 0xf1ff, 0xf07b, 0x000}, + {d68040_cpush , 0xff20, 0xf420, 0x000}, + {d68000_dbcc , 0xf0f8, 0x50c8, 0x000}, + {d68000_dbra , 0xfff8, 0x51c8, 0x000}, + {d68000_divs , 0xf1c0, 0x81c0, 0xbff}, + {d68000_divu , 0xf1c0, 0x80c0, 0xbff}, + {d68020_divl , 0xffc0, 0x4c40, 0xbff}, + {d68000_eor_8 , 0xf1c0, 0xb100, 0xbf8}, + {d68000_eor_16 , 0xf1c0, 0xb140, 0xbf8}, + {d68000_eor_32 , 0xf1c0, 0xb180, 0xbf8}, + {d68000_eori_to_ccr , 0xffff, 0x0a3c, 0x000}, + {d68000_eori_to_sr , 0xffff, 0x0a7c, 0x000}, + {d68000_eori_8 , 0xffc0, 0x0a00, 0xbf8}, + {d68000_eori_16 , 0xffc0, 0x0a40, 0xbf8}, + {d68000_eori_32 , 0xffc0, 0x0a80, 0xbf8}, + {d68000_exg_dd , 0xf1f8, 0xc140, 0x000}, + {d68000_exg_aa , 0xf1f8, 0xc148, 0x000}, + {d68000_exg_da , 0xf1f8, 0xc188, 0x000}, + {d68020_extb_32 , 0xfff8, 0x49c0, 0x000}, + {d68000_ext_16 , 0xfff8, 0x4880, 0x000}, + {d68000_ext_32 , 0xfff8, 0x48c0, 0x000}, + {d68040_fpu , 0xffc0, 0xf200, 0x000}, + {d68000_illegal , 0xffff, 0x4afc, 0x000}, + {d68000_jmp , 0xffc0, 0x4ec0, 0x27b}, + {d68000_jsr , 0xffc0, 0x4e80, 0x27b}, + {d68000_lea , 0xf1c0, 0x41c0, 0x27b}, + {d68000_link_16 , 0xfff8, 0x4e50, 0x000}, + {d68020_link_32 , 0xfff8, 0x4808, 0x000}, + {d68000_lsr_s_8 , 0xf1f8, 0xe008, 0x000}, + {d68000_lsr_s_16 , 0xf1f8, 0xe048, 0x000}, + {d68000_lsr_s_32 , 0xf1f8, 0xe088, 0x000}, + {d68000_lsr_r_8 , 0xf1f8, 0xe028, 0x000}, + {d68000_lsr_r_16 , 0xf1f8, 0xe068, 0x000}, + {d68000_lsr_r_32 , 0xf1f8, 0xe0a8, 0x000}, + {d68000_lsr_ea , 0xffc0, 0xe2c0, 0x3f8}, + {d68000_lsl_s_8 , 0xf1f8, 0xe108, 0x000}, + {d68000_lsl_s_16 , 0xf1f8, 0xe148, 0x000}, + {d68000_lsl_s_32 , 0xf1f8, 0xe188, 0x000}, + {d68000_lsl_r_8 , 0xf1f8, 0xe128, 0x000}, + {d68000_lsl_r_16 , 0xf1f8, 0xe168, 0x000}, + {d68000_lsl_r_32 , 0xf1f8, 0xe1a8, 0x000}, + {d68000_lsl_ea , 0xffc0, 0xe3c0, 0x3f8}, + {d68000_move_8 , 0xf000, 0x1000, 0xbff}, + {d68000_move_16 , 0xf000, 0x3000, 0xfff}, + {d68000_move_32 , 0xf000, 0x2000, 0xfff}, + {d68000_movea_16 , 0xf1c0, 0x3040, 0xfff}, + {d68000_movea_32 , 0xf1c0, 0x2040, 0xfff}, + {d68000_move_to_ccr , 0xffc0, 0x44c0, 0xbff}, + {d68010_move_fr_ccr , 0xffc0, 0x42c0, 0xbf8}, + {d68000_move_to_sr , 0xffc0, 0x46c0, 0xbff}, + {d68000_move_fr_sr , 0xffc0, 0x40c0, 0xbf8}, + {d68000_move_to_usp , 0xfff8, 0x4e60, 0x000}, + {d68000_move_fr_usp , 0xfff8, 0x4e68, 0x000}, + {d68010_movec , 0xfffe, 0x4e7a, 0x000}, + {d68000_movem_pd_16 , 0xfff8, 0x48a0, 0x000}, + {d68000_movem_pd_32 , 0xfff8, 0x48e0, 0x000}, + {d68000_movem_re_16 , 0xffc0, 0x4880, 0x2f8}, + {d68000_movem_re_32 , 0xffc0, 0x48c0, 0x2f8}, + {d68000_movem_er_16 , 0xffc0, 0x4c80, 0x37b}, + {d68000_movem_er_32 , 0xffc0, 0x4cc0, 0x37b}, + {d68000_movep_er_16 , 0xf1f8, 0x0108, 0x000}, + {d68000_movep_er_32 , 0xf1f8, 0x0148, 0x000}, + {d68000_movep_re_16 , 0xf1f8, 0x0188, 0x000}, + {d68000_movep_re_32 , 0xf1f8, 0x01c8, 0x000}, + {d68010_moves_8 , 0xffc0, 0x0e00, 0x3f8}, + {d68010_moves_16 , 0xffc0, 0x0e40, 0x3f8}, + {d68010_moves_32 , 0xffc0, 0x0e80, 0x3f8}, + {d68000_moveq , 0xf100, 0x7000, 0x000}, + {d68040_move16_pi_pi , 0xfff8, 0xf620, 0x000}, + {d68040_move16_pi_al , 0xfff8, 0xf600, 0x000}, + {d68040_move16_al_pi , 0xfff8, 0xf608, 0x000}, + {d68040_move16_ai_al , 0xfff8, 0xf610, 0x000}, + {d68040_move16_al_ai , 0xfff8, 0xf618, 0x000}, + {d68000_muls , 0xf1c0, 0xc1c0, 0xbff}, + {d68000_mulu , 0xf1c0, 0xc0c0, 0xbff}, + {d68020_mull , 0xffc0, 0x4c00, 0xbff}, + {d68000_nbcd , 0xffc0, 0x4800, 0xbf8}, + {d68000_neg_8 , 0xffc0, 0x4400, 0xbf8}, + {d68000_neg_16 , 0xffc0, 0x4440, 0xbf8}, + {d68000_neg_32 , 0xffc0, 0x4480, 0xbf8}, + {d68000_negx_8 , 0xffc0, 0x4000, 0xbf8}, + {d68000_negx_16 , 0xffc0, 0x4040, 0xbf8}, + {d68000_negx_32 , 0xffc0, 0x4080, 0xbf8}, + {d68000_nop , 0xffff, 0x4e71, 0x000}, + {d68000_not_8 , 0xffc0, 0x4600, 0xbf8}, + {d68000_not_16 , 0xffc0, 0x4640, 0xbf8}, + {d68000_not_32 , 0xffc0, 0x4680, 0xbf8}, + {d68000_or_er_8 , 0xf1c0, 0x8000, 0xbff}, + {d68000_or_er_16 , 0xf1c0, 0x8040, 0xbff}, + {d68000_or_er_32 , 0xf1c0, 0x8080, 0xbff}, + {d68000_or_re_8 , 0xf1c0, 0x8100, 0x3f8}, + {d68000_or_re_16 , 0xf1c0, 0x8140, 0x3f8}, + {d68000_or_re_32 , 0xf1c0, 0x8180, 0x3f8}, + {d68000_ori_to_ccr , 0xffff, 0x003c, 0x000}, + {d68000_ori_to_sr , 0xffff, 0x007c, 0x000}, + {d68000_ori_8 , 0xffc0, 0x0000, 0xbf8}, + {d68000_ori_16 , 0xffc0, 0x0040, 0xbf8}, + {d68000_ori_32 , 0xffc0, 0x0080, 0xbf8}, + {d68020_pack_rr , 0xf1f8, 0x8140, 0x000}, + {d68020_pack_mm , 0xf1f8, 0x8148, 0x000}, + {d68000_pea , 0xffc0, 0x4840, 0x27b}, + {d68040_pflush , 0xffe0, 0xf500, 0x000}, + {d68000_reset , 0xffff, 0x4e70, 0x000}, + {d68000_ror_s_8 , 0xf1f8, 0xe018, 0x000}, + {d68000_ror_s_16 , 0xf1f8, 0xe058, 0x000}, + {d68000_ror_s_32 , 0xf1f8, 0xe098, 0x000}, + {d68000_ror_r_8 , 0xf1f8, 0xe038, 0x000}, + {d68000_ror_r_16 , 0xf1f8, 0xe078, 0x000}, + {d68000_ror_r_32 , 0xf1f8, 0xe0b8, 0x000}, + {d68000_ror_ea , 0xffc0, 0xe6c0, 0x3f8}, + {d68000_rol_s_8 , 0xf1f8, 0xe118, 0x000}, + {d68000_rol_s_16 , 0xf1f8, 0xe158, 0x000}, + {d68000_rol_s_32 , 0xf1f8, 0xe198, 0x000}, + {d68000_rol_r_8 , 0xf1f8, 0xe138, 0x000}, + {d68000_rol_r_16 , 0xf1f8, 0xe178, 0x000}, + {d68000_rol_r_32 , 0xf1f8, 0xe1b8, 0x000}, + {d68000_rol_ea , 0xffc0, 0xe7c0, 0x3f8}, + {d68000_roxr_s_8 , 0xf1f8, 0xe010, 0x000}, + {d68000_roxr_s_16 , 0xf1f8, 0xe050, 0x000}, + {d68000_roxr_s_32 , 0xf1f8, 0xe090, 0x000}, + {d68000_roxr_r_8 , 0xf1f8, 0xe030, 0x000}, + {d68000_roxr_r_16 , 0xf1f8, 0xe070, 0x000}, + {d68000_roxr_r_32 , 0xf1f8, 0xe0b0, 0x000}, + {d68000_roxr_ea , 0xffc0, 0xe4c0, 0x3f8}, + {d68000_roxl_s_8 , 0xf1f8, 0xe110, 0x000}, + {d68000_roxl_s_16 , 0xf1f8, 0xe150, 0x000}, + {d68000_roxl_s_32 , 0xf1f8, 0xe190, 0x000}, + {d68000_roxl_r_8 , 0xf1f8, 0xe130, 0x000}, + {d68000_roxl_r_16 , 0xf1f8, 0xe170, 0x000}, + {d68000_roxl_r_32 , 0xf1f8, 0xe1b0, 0x000}, + {d68000_roxl_ea , 0xffc0, 0xe5c0, 0x3f8}, + {d68010_rtd , 0xffff, 0x4e74, 0x000}, + {d68000_rte , 0xffff, 0x4e73, 0x000}, + {d68020_rtm , 0xfff0, 0x06c0, 0x000}, + {d68000_rtr , 0xffff, 0x4e77, 0x000}, + {d68000_rts , 0xffff, 0x4e75, 0x000}, + {d68000_sbcd_rr , 0xf1f8, 0x8100, 0x000}, + {d68000_sbcd_mm , 0xf1f8, 0x8108, 0x000}, + {d68000_scc , 0xf0c0, 0x50c0, 0xbf8}, + {d68000_stop , 0xffff, 0x4e72, 0x000}, + {d68000_sub_er_8 , 0xf1c0, 0x9000, 0xbff}, + {d68000_sub_er_16 , 0xf1c0, 0x9040, 0xfff}, + {d68000_sub_er_32 , 0xf1c0, 0x9080, 0xfff}, + {d68000_sub_re_8 , 0xf1c0, 0x9100, 0x3f8}, + {d68000_sub_re_16 , 0xf1c0, 0x9140, 0x3f8}, + {d68000_sub_re_32 , 0xf1c0, 0x9180, 0x3f8}, + {d68000_suba_16 , 0xf1c0, 0x90c0, 0xfff}, + {d68000_suba_32 , 0xf1c0, 0x91c0, 0xfff}, + {d68000_subi_8 , 0xffc0, 0x0400, 0xbf8}, + {d68000_subi_16 , 0xffc0, 0x0440, 0xbf8}, + {d68000_subi_32 , 0xffc0, 0x0480, 0xbf8}, + {d68000_subq_8 , 0xf1c0, 0x5100, 0xbf8}, + {d68000_subq_16 , 0xf1c0, 0x5140, 0xff8}, + {d68000_subq_32 , 0xf1c0, 0x5180, 0xff8}, + {d68000_subx_rr_8 , 0xf1f8, 0x9100, 0x000}, + {d68000_subx_rr_16 , 0xf1f8, 0x9140, 0x000}, + {d68000_subx_rr_32 , 0xf1f8, 0x9180, 0x000}, + {d68000_subx_mm_8 , 0xf1f8, 0x9108, 0x000}, + {d68000_subx_mm_16 , 0xf1f8, 0x9148, 0x000}, + {d68000_subx_mm_32 , 0xf1f8, 0x9188, 0x000}, + {d68000_swap , 0xfff8, 0x4840, 0x000}, + {d68000_tas , 0xffc0, 0x4ac0, 0xbf8}, + {d68000_trap , 0xfff0, 0x4e40, 0x000}, + {d68020_trapcc_0 , 0xf0ff, 0x50fc, 0x000}, + {d68020_trapcc_16 , 0xf0ff, 0x50fa, 0x000}, + {d68020_trapcc_32 , 0xf0ff, 0x50fb, 0x000}, + {d68000_trapv , 0xffff, 0x4e76, 0x000}, + {d68000_tst_8 , 0xffc0, 0x4a00, 0xbf8}, + {d68020_tst_pcdi_8 , 0xffff, 0x4a3a, 0x000}, + {d68020_tst_pcix_8 , 0xffff, 0x4a3b, 0x000}, + {d68020_tst_i_8 , 0xffff, 0x4a3c, 0x000}, + {d68000_tst_16 , 0xffc0, 0x4a40, 0xbf8}, + {d68020_tst_a_16 , 0xfff8, 0x4a48, 0x000}, + {d68020_tst_pcdi_16 , 0xffff, 0x4a7a, 0x000}, + {d68020_tst_pcix_16 , 0xffff, 0x4a7b, 0x000}, + {d68020_tst_i_16 , 0xffff, 0x4a7c, 0x000}, + {d68000_tst_32 , 0xffc0, 0x4a80, 0xbf8}, + {d68020_tst_a_32 , 0xfff8, 0x4a88, 0x000}, + {d68020_tst_pcdi_32 , 0xffff, 0x4aba, 0x000}, + {d68020_tst_pcix_32 , 0xffff, 0x4abb, 0x000}, + {d68020_tst_i_32 , 0xffff, 0x4abc, 0x000}, + {d68000_unlk , 0xfff8, 0x4e58, 0x000}, + {d68020_unpk_rr , 0xf1f8, 0x8180, 0x000}, + {d68020_unpk_mm , 0xf1f8, 0x8188, 0x000}, + {d68851_p000 , 0xffc0, 0xf000, 0x000}, + {d68851_pbcc16 , 0xffc0, 0xf080, 0x000}, + {d68851_pbcc32 , 0xffc0, 0xf0c0, 0x000}, + {d68851_pdbcc , 0xfff8, 0xf048, 0x000}, + {d68851_p001 , 0xffc0, 0xf040, 0x000}, + {d68040_fbcc_16 , 0xffc0, 0xf280, 0x000}, + {d68040_fbcc_32 , 0xffc0, 0xf2c0, 0x000}, + {0, 0, 0, 0} +}; + +/* Check if opcode is using a valid ea mode */ +static int valid_ea(UINT32 opcode, UINT32 mask) +{ + if(mask == 0) + return 1; + + switch(opcode & 0x3f) + { + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x04: case 0x05: case 0x06: case 0x07: + return (mask & 0x800) != 0; + case 0x08: case 0x09: case 0x0a: case 0x0b: + case 0x0c: case 0x0d: case 0x0e: case 0x0f: + return (mask & 0x400) != 0; + case 0x10: case 0x11: case 0x12: case 0x13: + case 0x14: case 0x15: case 0x16: case 0x17: + return (mask & 0x200) != 0; + case 0x18: case 0x19: case 0x1a: case 0x1b: + case 0x1c: case 0x1d: case 0x1e: case 0x1f: + return (mask & 0x100) != 0; + case 0x20: case 0x21: case 0x22: case 0x23: + case 0x24: case 0x25: case 0x26: case 0x27: + return (mask & 0x080) != 0; + case 0x28: case 0x29: case 0x2a: case 0x2b: + case 0x2c: case 0x2d: case 0x2e: case 0x2f: + return (mask & 0x040) != 0; + case 0x30: case 0x31: case 0x32: case 0x33: + case 0x34: case 0x35: case 0x36: case 0x37: + return (mask & 0x020) != 0; + case 0x38: + return (mask & 0x010) != 0; + case 0x39: + return (mask & 0x008) != 0; + case 0x3a: + return (mask & 0x002) != 0; + case 0x3b: + return (mask & 0x001) != 0; + case 0x3c: + return (mask & 0x004) != 0; + } + return 0; + +} + +/* Used by qsort */ +static int DECL_SPEC compare_nof_true_bits(const void *aptr, const void *bptr) +{ + UINT32 a = ((const opcode_struct*)aptr)->mask; + UINT32 b = ((const opcode_struct*)bptr)->mask; + + a = ((a & 0xAAAA) >> 1) + (a & 0x5555); + a = ((a & 0xCCCC) >> 2) + (a & 0x3333); + a = ((a & 0xF0F0) >> 4) + (a & 0x0F0F); + a = ((a & 0xFF00) >> 8) + (a & 0x00FF); + + b = ((b & 0xAAAA) >> 1) + (b & 0x5555); + b = ((b & 0xCCCC) >> 2) + (b & 0x3333); + b = ((b & 0xF0F0) >> 4) + (b & 0x0F0F); + b = ((b & 0xFF00) >> 8) + (b & 0x00FF); + + return b - a; /* reversed to get greatest to least sorting */ +} + +/* build the opcode handler jump table */ +static void build_opcode_table(void) +{ + UINT32 i; + UINT32 opcode; + opcode_struct* ostruct; + opcode_struct opcode_info[ARRAY_LENGTH(g_opcode_info)]; + + memcpy(opcode_info, g_opcode_info, sizeof(g_opcode_info)); + qsort((void *)opcode_info, ARRAY_LENGTH(opcode_info)-1, sizeof(opcode_info[0]), compare_nof_true_bits); + + for(i=0;i<0x10000;i++) + { + g_instruction_table[i] = d68000_illegal; /* default to illegal */ + opcode = i; + /* search through opcode info for a match */ + for(ostruct = opcode_info;ostruct->opcode_handler != 0;ostruct++) + { + /* match opcode mask and allowed ea modes */ + if((opcode & ostruct->mask) == ostruct->match) + { + /* Handle destination ea for move instructions */ + if((ostruct->opcode_handler == d68000_move_8 || + ostruct->opcode_handler == d68000_move_16 || + ostruct->opcode_handler == d68000_move_32) && + !valid_ea(((opcode>>9)&7) | ((opcode>>3)&0x38), 0xbf8)) + continue; + if(valid_ea(opcode, ostruct->ea_mask)) + { + g_instruction_table[i] = ostruct->opcode_handler; + break; + } + } + } + } +} + + + +/* ======================================================================== */ +/* ================================= API ================================== */ +/* ======================================================================== */ + +/* Disasemble one instruction at pc and store in str_buff */ +static unsigned int m68k_disassemble(char* str_buff, unsigned int pc, unsigned int cpu_type) +{ + if(!g_initialized) + { + build_opcode_table(); + g_initialized = 1; + } + switch(cpu_type) + { + case M68K_CPU_TYPE_68000: + g_cpu_type = TYPE_68000; + break; + case M68K_CPU_TYPE_68008: + g_cpu_type = TYPE_68008; + break; + case M68K_CPU_TYPE_68010: + g_cpu_type = TYPE_68010; + break; + case M68K_CPU_TYPE_68EC020: + case M68K_CPU_TYPE_68020: + g_cpu_type = TYPE_68020; + break; + case M68K_CPU_TYPE_68EC030: + case M68K_CPU_TYPE_68030: + g_cpu_type = TYPE_68030; + break; + case M68K_CPU_TYPE_68040: + case M68K_CPU_TYPE_68EC040: + case M68K_CPU_TYPE_68LC040: + g_cpu_type = TYPE_68040; + break; + case M68K_CPU_TYPE_FSCPU32: + g_cpu_type = TYPE_68340; + break; + case M68K_CPU_TYPE_COLDFIRE: + g_cpu_type = TYPE_COLDFIRE; + break; + default: + return 0; + } + + g_cpu_pc = pc; + g_helper_str[0] = 0; + g_cpu_ir = read_imm_16(); + g_opcode_type = 0; + g_instruction_table[g_cpu_ir](); + sprintf(str_buff, "%s%s", g_dasm_str, g_helper_str); + return COMBINE_OPCODE_FLAGS(g_cpu_pc - pc); +} + +#ifdef UNUSED_FUNCTION +char* m68ki_disassemble_quick(unsigned int pc, unsigned int cpu_type) +{ + static char buff[100]; + buff[0] = 0; + m68k_disassemble(buff, pc, cpu_type); + return buff; +} +#endif + +unsigned int m68k_disassemble_raw(char* str_buff, unsigned int pc, const unsigned char* opdata, const unsigned char* argdata, unsigned int cpu_type) +{ + unsigned int result; + + g_rawop = opdata; + g_rawbasepc = pc; + result = m68k_disassemble(str_buff, pc, cpu_type); + g_rawop = NULL; + return result; +} + +#ifdef UNUSED_FUNCTION +/* Check if the instruction is a valid one */ +unsigned int m68k_is_valid_instruction(unsigned int instruction, unsigned int cpu_type) +{ + if(!g_initialized) + { + build_opcode_table(); + g_initialized = 1; + } + + instruction &= 0xffff; + if(g_instruction_table[instruction] == d68000_illegal) + return 0; + + switch(cpu_type) + { + case M68K_CPU_TYPE_68000: + case M68K_CPU_TYPE_68008: + if(g_instruction_table[instruction] == d68010_bkpt) + return 0; + if(g_instruction_table[instruction] == d68010_move_fr_ccr) + return 0; + if(g_instruction_table[instruction] == d68010_movec) + return 0; + if(g_instruction_table[instruction] == d68010_moves_8) + return 0; + if(g_instruction_table[instruction] == d68010_moves_16) + return 0; + if(g_instruction_table[instruction] == d68010_moves_32) + return 0; + if(g_instruction_table[instruction] == d68010_rtd) + return 0; + case M68K_CPU_TYPE_68010: + if(g_instruction_table[instruction] == d68020_bcc_32) + return 0; + if(g_instruction_table[instruction] == d68020_bfchg) + return 0; + if(g_instruction_table[instruction] == d68020_bfclr) + return 0; + if(g_instruction_table[instruction] == d68020_bfexts) + return 0; + if(g_instruction_table[instruction] == d68020_bfextu) + return 0; + if(g_instruction_table[instruction] == d68020_bfffo) + return 0; + if(g_instruction_table[instruction] == d68020_bfins) + return 0; + if(g_instruction_table[instruction] == d68020_bfset) + return 0; + if(g_instruction_table[instruction] == d68020_bftst) + return 0; + if(g_instruction_table[instruction] == d68020_bra_32) + return 0; + if(g_instruction_table[instruction] == d68020_bsr_32) + return 0; + if(g_instruction_table[instruction] == d68020_callm) + return 0; + if(g_instruction_table[instruction] == d68020_cas_8) + return 0; + if(g_instruction_table[instruction] == d68020_cas_16) + return 0; + if(g_instruction_table[instruction] == d68020_cas_32) + return 0; + if(g_instruction_table[instruction] == d68020_cas2_16) + return 0; + if(g_instruction_table[instruction] == d68020_cas2_32) + return 0; + if(g_instruction_table[instruction] == d68020_chk_32) + return 0; + if(g_instruction_table[instruction] == d68020_chk2_cmp2_8) + return 0; + if(g_instruction_table[instruction] == d68020_chk2_cmp2_16) + return 0; + if(g_instruction_table[instruction] == d68020_chk2_cmp2_32) + return 0; + if(g_instruction_table[instruction] == d68020_cmpi_pcdi_8) + return 0; + if(g_instruction_table[instruction] == d68020_cmpi_pcix_8) + return 0; + if(g_instruction_table[instruction] == d68020_cmpi_pcdi_16) + return 0; + if(g_instruction_table[instruction] == d68020_cmpi_pcix_16) + return 0; + if(g_instruction_table[instruction] == d68020_cmpi_pcdi_32) + return 0; + if(g_instruction_table[instruction] == d68020_cmpi_pcix_32) + return 0; + if(g_instruction_table[instruction] == d68020_cpbcc_16) + return 0; + if(g_instruction_table[instruction] == d68020_cpbcc_32) + return 0; + if(g_instruction_table[instruction] == d68020_cpdbcc) + return 0; + if(g_instruction_table[instruction] == d68020_cpgen) + return 0; + if(g_instruction_table[instruction] == d68020_cprestore) + return 0; + if(g_instruction_table[instruction] == d68020_cpsave) + return 0; + if(g_instruction_table[instruction] == d68020_cpscc) + return 0; + if(g_instruction_table[instruction] == d68020_cptrapcc_0) + return 0; + if(g_instruction_table[instruction] == d68020_cptrapcc_16) + return 0; + if(g_instruction_table[instruction] == d68020_cptrapcc_32) + return 0; + if(g_instruction_table[instruction] == d68020_divl) + return 0; + if(g_instruction_table[instruction] == d68020_extb_32) + return 0; + if(g_instruction_table[instruction] == d68020_link_32) + return 0; + if(g_instruction_table[instruction] == d68020_mull) + return 0; + if(g_instruction_table[instruction] == d68020_pack_rr) + return 0; + if(g_instruction_table[instruction] == d68020_pack_mm) + return 0; + if(g_instruction_table[instruction] == d68020_rtm) + return 0; + if(g_instruction_table[instruction] == d68020_trapcc_0) + return 0; + if(g_instruction_table[instruction] == d68020_trapcc_16) + return 0; + if(g_instruction_table[instruction] == d68020_trapcc_32) + return 0; + if(g_instruction_table[instruction] == d68020_tst_pcdi_8) + return 0; + if(g_instruction_table[instruction] == d68020_tst_pcix_8) + return 0; + if(g_instruction_table[instruction] == d68020_tst_i_8) + return 0; + if(g_instruction_table[instruction] == d68020_tst_a_16) + return 0; + if(g_instruction_table[instruction] == d68020_tst_pcdi_16) + return 0; + if(g_instruction_table[instruction] == d68020_tst_pcix_16) + return 0; + if(g_instruction_table[instruction] == d68020_tst_i_16) + return 0; + if(g_instruction_table[instruction] == d68020_tst_a_32) + return 0; + if(g_instruction_table[instruction] == d68020_tst_pcdi_32) + return 0; + if(g_instruction_table[instruction] == d68020_tst_pcix_32) + return 0; + if(g_instruction_table[instruction] == d68020_tst_i_32) + return 0; + if(g_instruction_table[instruction] == d68020_unpk_rr) + return 0; + if(g_instruction_table[instruction] == d68020_unpk_mm) + return 0; + if(g_instruction_table[instruction] == d68040_fbcc_16) + return 0; + if(g_instruction_table[instruction] == d68040_fbcc_32) + return 0; + case M68K_CPU_TYPE_68EC020: + case M68K_CPU_TYPE_68020: + case M68K_CPU_TYPE_68030: + case M68K_CPU_TYPE_68EC030: + case M68K_CPU_TYPE_FSCPU32: + case M68K_CPU_TYPE_COLDFIRE: + if(g_instruction_table[instruction] == d68040_cinv) + return 0; + if(g_instruction_table[instruction] == d68040_cpush) + return 0; + if(g_instruction_table[instruction] == d68040_move16_pi_pi) + return 0; + if(g_instruction_table[instruction] == d68040_move16_pi_al) + return 0; + if(g_instruction_table[instruction] == d68040_move16_al_pi) + return 0; + if(g_instruction_table[instruction] == d68040_move16_ai_al) + return 0; + if(g_instruction_table[instruction] == d68040_move16_al_ai) + return 0; + case M68K_CPU_TYPE_68040: + case M68K_CPU_TYPE_68EC040: + case M68K_CPU_TYPE_68LC040: + if(g_instruction_table[instruction] == d68020_cpbcc_16) + return 0; + if(g_instruction_table[instruction] == d68020_cpbcc_32) + return 0; + if(g_instruction_table[instruction] == d68020_cpdbcc) + return 0; + if(g_instruction_table[instruction] == d68020_cpgen) + return 0; + if(g_instruction_table[instruction] == d68020_cprestore) + return 0; + if(g_instruction_table[instruction] == d68020_cpsave) + return 0; + if(g_instruction_table[instruction] == d68020_cpscc) + return 0; + if(g_instruction_table[instruction] == d68020_cptrapcc_0) + return 0; + if(g_instruction_table[instruction] == d68020_cptrapcc_16) + return 0; + if(g_instruction_table[instruction] == d68020_cptrapcc_32) + return 0; + if(g_instruction_table[instruction] == d68040_pflush) + return 0; + } + if(cpu_type != M68K_CPU_TYPE_68020 && cpu_type != M68K_CPU_TYPE_68EC020 && + (g_instruction_table[instruction] == d68020_callm || + g_instruction_table[instruction] == d68020_rtm)) + return 0; + + return 1; +} +#endif + +CPU_DISASSEMBLE( m68000 ) +{ + return m68k_disassemble_raw(buffer, pc, oprom, opram, M68K_CPU_TYPE_68000); +} + +CPU_DISASSEMBLE( m68008 ) +{ + return m68k_disassemble_raw(buffer, pc, oprom, opram, M68K_CPU_TYPE_68008); +} + +CPU_DISASSEMBLE( m68010 ) +{ + return m68k_disassemble_raw(buffer, pc, oprom, opram, M68K_CPU_TYPE_68010); +} + +CPU_DISASSEMBLE( m68020 ) +{ + return m68k_disassemble_raw(buffer, pc, oprom, opram, M68K_CPU_TYPE_68020); +} + +CPU_DISASSEMBLE( m68030 ) +{ + return m68k_disassemble_raw(buffer, pc, oprom, opram, M68K_CPU_TYPE_68030); +} + +CPU_DISASSEMBLE( m68040 ) +{ + return m68k_disassemble_raw(buffer, pc, oprom, opram, M68K_CPU_TYPE_68040); +} + +CPU_DISASSEMBLE( m68340 ) +{ + return m68k_disassemble_raw(buffer, pc, oprom, opram, M68K_CPU_TYPE_FSCPU32); +} + +CPU_DISASSEMBLE( coldfire ) +{ + return m68k_disassemble_raw(buffer, pc, oprom, opram, M68K_CPU_TYPE_COLDFIRE); +} + +/* ======================================================================== */ +/* ============================== END OF FILE ============================= */ +/* ======================================================================== */ diff --git a/src/devices/cpu/m68000/m68kfpu.inc b/src/devices/cpu/m68000/m68kfpu.inc new file mode 100644 index 00000000000..32d0179e6c2 --- /dev/null +++ b/src/devices/cpu/m68000/m68kfpu.inc @@ -0,0 +1,2204 @@ +// license:BSD-3-Clause +// copyright-holders:Karl Stenerud +#include + +#define FPCC_N 0x08000000 +#define FPCC_Z 0x04000000 +#define FPCC_I 0x02000000 +#define FPCC_NAN 0x01000000 + +#define FPES_OE 0x00002000 +#define FPAE_IOP 0x00000080 + +#define DOUBLE_INFINITY U64(0x7ff0000000000000) +#define DOUBLE_EXPONENT U64(0x7ff0000000000000) +#define DOUBLE_MANTISSA U64(0x000fffffffffffff) + +extern flag floatx80_is_nan( floatx80 a ); + +// masks for packed dwords, positive k-factor +static const UINT32 pkmask2[18] = +{ + 0xffffffff, 0, 0xf0000000, 0xff000000, 0xfff00000, 0xffff0000, + 0xfffff000, 0xffffff00, 0xfffffff0, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff +}; + +static const UINT32 pkmask3[18] = +{ + 0xffffffff, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0xf0000000, 0xff000000, 0xfff00000, 0xffff0000, + 0xfffff000, 0xffffff00, 0xfffffff0, 0xffffffff, +}; + +INLINE double fx80_to_double(floatx80 fx) +{ + UINT64 d; + double *foo; + + foo = (double *)&d; + + d = floatx80_to_float64(fx); + + return *foo; +} + +INLINE floatx80 double_to_fx80(double in) +{ + UINT64 *d; + + d = (UINT64 *)∈ + + return float64_to_floatx80(*d); +} + +INLINE floatx80 load_extended_float80(m68000_base_device *m68k, UINT32 ea) +{ + UINT32 d1,d2; + UINT16 d3; + floatx80 fp; + + d3 = m68ki_read_16(m68k, ea); + d1 = m68ki_read_32(m68k, ea+4); + d2 = m68ki_read_32(m68k, ea+8); + + fp.high = d3; + fp.low = ((UINT64)d1<<32) | (d2 & 0xffffffff); + + return fp; +} + +INLINE void store_extended_float80(m68000_base_device *m68k, UINT32 ea, floatx80 fpr) +{ + m68ki_write_16(m68k, ea+0, fpr.high); + m68ki_write_16(m68k, ea+2, 0); + m68ki_write_32(m68k, ea+4, (fpr.low>>32)&0xffffffff); + m68ki_write_32(m68k, ea+8, fpr.low&0xffffffff); +} + +INLINE floatx80 load_pack_float80(m68000_base_device *m68k, UINT32 ea) +{ + UINT32 dw1, dw2, dw3; + floatx80 result; + double tmp; + char str[128], *ch; + + dw1 = m68ki_read_32(m68k, ea); + dw2 = m68ki_read_32(m68k, ea+4); + dw3 = m68ki_read_32(m68k, ea+8); + + ch = &str[0]; + if (dw1 & 0x80000000) // mantissa sign + { + *ch++ = '-'; + } + *ch++ = (char)((dw1 & 0xf) + '0'); + *ch++ = '.'; + *ch++ = (char)(((dw2 >> 28) & 0xf) + '0'); + *ch++ = (char)(((dw2 >> 24) & 0xf) + '0'); + *ch++ = (char)(((dw2 >> 20) & 0xf) + '0'); + *ch++ = (char)(((dw2 >> 16) & 0xf) + '0'); + *ch++ = (char)(((dw2 >> 12) & 0xf) + '0'); + *ch++ = (char)(((dw2 >> 8) & 0xf) + '0'); + *ch++ = (char)(((dw2 >> 4) & 0xf) + '0'); + *ch++ = (char)(((dw2 >> 0) & 0xf) + '0'); + *ch++ = (char)(((dw3 >> 28) & 0xf) + '0'); + *ch++ = (char)(((dw3 >> 24) & 0xf) + '0'); + *ch++ = (char)(((dw3 >> 20) & 0xf) + '0'); + *ch++ = (char)(((dw3 >> 16) & 0xf) + '0'); + *ch++ = (char)(((dw3 >> 12) & 0xf) + '0'); + *ch++ = (char)(((dw3 >> 8) & 0xf) + '0'); + *ch++ = (char)(((dw3 >> 4) & 0xf) + '0'); + *ch++ = (char)(((dw3 >> 0) & 0xf) + '0'); + *ch++ = 'E'; + if (dw1 & 0x40000000) // exponent sign + { + *ch++ = '-'; + } + *ch++ = (char)(((dw1 >> 24) & 0xf) + '0'); + *ch++ = (char)(((dw1 >> 20) & 0xf) + '0'); + *ch++ = (char)(((dw1 >> 16) & 0xf) + '0'); + *ch = '\0'; + + sscanf(str, "%le", &tmp); + + result = double_to_fx80(tmp); + + return result; +} + +INLINE void store_pack_float80(m68000_base_device *m68k, UINT32 ea, int k, floatx80 fpr) +{ + UINT32 dw1, dw2, dw3; + char str[128], *ch; + int i, j, exp; + + dw1 = dw2 = dw3 = 0; + ch = &str[0]; + + sprintf(str, "%.16e", fx80_to_double(fpr)); + + if (*ch == '-') + { + ch++; + dw1 = 0x80000000; + } + + if (*ch == '+') + { + ch++; + } + + dw1 |= (*ch++ - '0'); + + if (*ch == '.') + { + ch++; + } + + // handle negative k-factor here + if ((k <= 0) && (k >= -13)) + { + exp = 0; + for (i = 0; i < 3; i++) + { + if (ch[18+i] >= '0' && ch[18+i] <= '9') + { + exp = (exp << 4) | (ch[18+i] - '0'); + } + } + + if (ch[17] == '-') + { + exp = -exp; + } + + k = -k; + // last digit is (k + exponent - 1) + k += (exp - 1); + + // round up the last significant mantissa digit + if (ch[k+1] >= '5') + { + ch[k]++; + } + + // zero out the rest of the mantissa digits + for (j = (k+1); j < 16; j++) + { + ch[j] = '0'; + } + + // now zero out K to avoid tripping the positive K detection below + k = 0; + } + + // crack 8 digits of the mantissa + for (i = 0; i < 8; i++) + { + dw2 <<= 4; + if (*ch >= '0' && *ch <= '9') + { + dw2 |= *ch++ - '0'; + } + } + + // next 8 digits of the mantissa + for (i = 0; i < 8; i++) + { + dw3 <<= 4; + if (*ch >= '0' && *ch <= '9') + dw3 |= *ch++ - '0'; + } + + // handle masking if k is positive + if (k >= 1) + { + if (k <= 17) + { + dw2 &= pkmask2[k]; + dw3 &= pkmask3[k]; + } + else + { + dw2 &= pkmask2[17]; + dw3 &= pkmask3[17]; +// m68k->fpcr |= (need to set OPERR bit) + } + } + + // finally, crack the exponent + if (*ch == 'e' || *ch == 'E') + { + ch++; + if (*ch == '-') + { + ch++; + dw1 |= 0x40000000; + } + + if (*ch == '+') + { + ch++; + } + + j = 0; + for (i = 0; i < 3; i++) + { + if (*ch >= '0' && *ch <= '9') + { + j = (j << 4) | (*ch++ - '0'); + } + } + + dw1 |= (j << 16); + } + + m68ki_write_32(m68k, ea, dw1); + m68ki_write_32(m68k, ea+4, dw2); + m68ki_write_32(m68k, ea+8, dw3); +} + +INLINE void SET_CONDITION_CODES(m68000_base_device *m68k, floatx80 reg) +{ +// UINT64 *regi; + +// regi = (UINT64 *)® + + REG_FPSR(m68k) &= ~(FPCC_N|FPCC_Z|FPCC_I|FPCC_NAN); + + // sign flag + if (reg.high & 0x8000) + { + REG_FPSR(m68k) |= FPCC_N; + } + + // zero flag + if (((reg.high & 0x7fff) == 0) && ((reg.low<<1) == 0)) + { + REG_FPSR(m68k) |= FPCC_Z; + } + + // infinity flag + if (((reg.high & 0x7fff) == 0x7fff) && ((reg.low<<1) == 0)) + { + REG_FPSR(m68k) |= FPCC_I; + } + + // NaN flag + if (floatx80_is_nan(reg)) + { + REG_FPSR(m68k) |= FPCC_NAN; + } +} + +INLINE int TEST_CONDITION(m68000_base_device *m68k, int condition) +{ + int n = (REG_FPSR(m68k) & FPCC_N) != 0; + int z = (REG_FPSR(m68k) & FPCC_Z) != 0; + int nan = (REG_FPSR(m68k) & FPCC_NAN) != 0; + int r = 0; + switch (condition) + { + case 0x10: + case 0x00: return 0; // False + + case 0x11: + case 0x01: return (z); // Equal + + case 0x12: + case 0x02: return (!(nan || z || n)); // Greater Than + + case 0x13: + case 0x03: return (z || !(nan || n)); // Greater or Equal + + case 0x14: + case 0x04: return (n && !(nan || z)); // Less Than + + case 0x15: + case 0x05: return (z || (n && !nan)); // Less Than or Equal + + case 0x16: + case 0x06: return !nan && !z; + + case 0x17: + case 0x07: return !nan; + + case 0x18: + case 0x08: return nan; + + case 0x19: + case 0x09: return nan || z; + + case 0x1a: + case 0x0a: return (nan || !(n || z)); // Not Less Than or Equal + + case 0x1b: + case 0x0b: return (nan || z || !n); // Not Less Than + + case 0x1c: + case 0x0c: return (nan || (n && !z)); // Not Greater or Equal Than + + case 0x1d: + case 0x0d: return (nan || z || n); // Not Greater Than + + case 0x1e: + case 0x0e: return (!z); // Not Equal + + case 0x1f: + case 0x0f: return 1; // True + + default: fatalerror("M68kFPU: test_condition: unhandled condition %02X\n", condition); + } + + return r; +} + +static UINT8 READ_EA_8(m68000_base_device *m68k, int ea) +{ + int mode = (ea >> 3) & 0x7; + int reg = (ea & 0x7); + + switch (mode) + { + case 0: // Dn + { + return REG_D(m68k)[reg]; + } + case 2: // (An) + { + UINT32 ea = REG_A(m68k)[reg]; + return m68ki_read_8(m68k, ea); + } + case 3: // (An)+ + { + UINT32 ea = EA_AY_PI_8(m68k); + return m68ki_read_8(m68k, ea); + } + case 4: // -(An) + { + UINT32 ea = EA_AY_PD_8(m68k); + return m68ki_read_8(m68k, ea); + } + case 5: // (d16, An) + { + UINT32 ea = EA_AY_DI_8(m68k); + return m68ki_read_8(m68k, ea); + } + case 6: // (An) + (Xn) + d8 + { + UINT32 ea = EA_AY_IX_8(m68k); + return m68ki_read_8(m68k, ea); + } + case 7: + { + switch (reg) + { + case 0: // (xxx).W + { + UINT32 ea = (UINT32)OPER_I_16(m68k); + return m68ki_read_8(m68k, ea); + } + case 1: // (xxx).L + { + UINT32 d1 = OPER_I_16(m68k); + UINT32 d2 = OPER_I_16(m68k); + UINT32 ea = (d1 << 16) | d2; + return m68ki_read_8(m68k, ea); + } + case 2: // (d16, PC) + { + UINT32 ea = EA_PCDI_8(m68k); + return m68ki_read_8(m68k, ea); + } + case 3: // (PC) + (Xn) + d8 + { + UINT32 ea = EA_PCIX_8(m68k); + return m68ki_read_8(m68k, ea); + } + case 4: // # + { + return OPER_I_8(m68k); + } + default: fatalerror("M68kFPU: READ_EA_8: unhandled mode %d, reg %d at %08X\n", mode, reg, REG_PC(m68k)); + } + break; + } + default: fatalerror("M68kFPU: READ_EA_8: unhandled mode %d, reg %d at %08X\n", mode, reg, REG_PC(m68k)); + } + + return 0; +} + +static UINT16 READ_EA_16(m68000_base_device *m68k, int ea) +{ + int mode = (ea >> 3) & 0x7; + int reg = (ea & 0x7); + + switch (mode) + { + case 0: // Dn + { + return (UINT16)(REG_D(m68k)[reg]); + } + case 2: // (An) + { + UINT32 ea = REG_A(m68k)[reg]; + return m68ki_read_16(m68k, ea); + } + case 3: // (An)+ + { + UINT32 ea = EA_AY_PI_16(m68k); + return m68ki_read_16(m68k, ea); + } + case 4: // -(An) + { + UINT32 ea = EA_AY_PD_16(m68k); + return m68ki_read_16(m68k, ea); + } + case 5: // (d16, An) + { + UINT32 ea = EA_AY_DI_16(m68k); + return m68ki_read_16(m68k, ea); + } + case 6: // (An) + (Xn) + d8 + { + UINT32 ea = EA_AY_IX_16(m68k); + return m68ki_read_16(m68k, ea); + } + case 7: + { + switch (reg) + { + case 0: // (xxx).W + { + UINT32 ea = (UINT32)OPER_I_16(m68k); + return m68ki_read_16(m68k, ea); + } + case 1: // (xxx).L + { + UINT32 d1 = OPER_I_16(m68k); + UINT32 d2 = OPER_I_16(m68k); + UINT32 ea = (d1 << 16) | d2; + return m68ki_read_16(m68k, ea); + } + case 2: // (d16, PC) + { + UINT32 ea = EA_PCDI_16(m68k); + return m68ki_read_16(m68k, ea); + } + case 3: // (PC) + (Xn) + d8 + { + UINT32 ea = EA_PCIX_16(m68k); + return m68ki_read_16(m68k, ea); + } + case 4: // # + { + return OPER_I_16(m68k); + } + + default: fatalerror("M68kFPU: READ_EA_16: unhandled mode %d, reg %d at %08X\n", mode, reg, REG_PC(m68k)); + } + break; + } + default: fatalerror("M68kFPU: READ_EA_16: unhandled mode %d, reg %d at %08X\n", mode, reg, REG_PC(m68k)); + } + + return 0; +} + +static UINT32 READ_EA_32(m68000_base_device *m68k, int ea) +{ + int mode = (ea >> 3) & 0x7; + int reg = (ea & 0x7); + + switch (mode) + { + case 0: // Dn + { + return REG_D(m68k)[reg]; + } + case 2: // (An) + { + UINT32 ea = REG_A(m68k)[reg]; + return m68ki_read_32(m68k, ea); + } + case 3: // (An)+ + { + UINT32 ea = EA_AY_PI_32(m68k); + return m68ki_read_32(m68k, ea); + } + case 4: // -(An) + { + UINT32 ea = EA_AY_PD_32(m68k); + return m68ki_read_32(m68k, ea); + } + case 5: // (d16, An) + { + UINT32 ea = EA_AY_DI_32(m68k); + return m68ki_read_32(m68k, ea); + } + case 6: // (An) + (Xn) + d8 + { + UINT32 ea = EA_AY_IX_32(m68k); + return m68ki_read_32(m68k, ea); + } + case 7: + { + switch (reg) + { + case 0: // (xxx).W + { + UINT32 ea = (UINT32)OPER_I_16(m68k); + return m68ki_read_32(m68k, ea); + } + case 1: // (xxx).L + { + UINT32 d1 = OPER_I_16(m68k); + UINT32 d2 = OPER_I_16(m68k); + UINT32 ea = (d1 << 16) | d2; + return m68ki_read_32(m68k, ea); + } + case 2: // (d16, PC) + { + UINT32 ea = EA_PCDI_32(m68k); + return m68ki_read_32(m68k, ea); + } + case 3: // (PC) + (Xn) + d8 + { + UINT32 ea = EA_PCIX_32(m68k); + return m68ki_read_32(m68k, ea); + } + case 4: // # + { + return OPER_I_32(m68k); + } + default: fatalerror("M68kFPU: READ_EA_32: unhandled mode %d, reg %d at %08X\n", mode, reg, REG_PC(m68k)); + } + break; + } + default: fatalerror("M68kFPU: READ_EA_32: unhandled mode %d, reg %d at %08X\n", mode, reg, REG_PC(m68k)); + } + return 0; +} + +static UINT64 READ_EA_64(m68000_base_device *m68k, int ea) +{ + int mode = (ea >> 3) & 0x7; + int reg = (ea & 0x7); + UINT32 h1, h2; + + switch (mode) + { + case 2: // (An) + { + UINT32 ea = REG_A(m68k)[reg]; + h1 = m68ki_read_32(m68k, ea+0); + h2 = m68ki_read_32(m68k, ea+4); + return (UINT64)(h1) << 32 | (UINT64)(h2); + } + case 3: // (An)+ + { + UINT32 ea = REG_A(m68k)[reg]; + REG_A(m68k)[reg] += 8; + h1 = m68ki_read_32(m68k, ea+0); + h2 = m68ki_read_32(m68k, ea+4); + return (UINT64)(h1) << 32 | (UINT64)(h2); + } + case 4: // -(An) + { + UINT32 ea = REG_A(m68k)[reg]-8; + REG_A(m68k)[reg] -= 8; + h1 = m68ki_read_32(m68k, ea+0); + h2 = m68ki_read_32(m68k, ea+4); + return (UINT64)(h1) << 32 | (UINT64)(h2); + } + case 5: // (d16, An) + { + UINT32 ea = EA_AY_DI_32(m68k); + h1 = m68ki_read_32(m68k, ea+0); + h2 = m68ki_read_32(m68k, ea+4); + return (UINT64)(h1) << 32 | (UINT64)(h2); + } + case 6: // (An) + (Xn) + d8 + { + UINT32 ea = EA_AY_IX_32(m68k); + h1 = m68ki_read_32(m68k, ea+0); + h2 = m68ki_read_32(m68k, ea+4); + return (UINT64)(h1) << 32 | (UINT64)(h2); + } + case 7: + { + switch (reg) + { + case 1: // (xxx).L + { + UINT32 d1 = OPER_I_16(m68k); + UINT32 d2 = OPER_I_16(m68k); + UINT32 ea = (d1 << 16) | d2; + return (UINT64)(m68ki_read_32(m68k, ea)) << 32 | (UINT64)(m68ki_read_32(m68k, ea+4)); + } + case 3: // (PC) + (Xn) + d8 + { + UINT32 ea = EA_PCIX_32(m68k); + h1 = m68ki_read_32(m68k, ea+0); + h2 = m68ki_read_32(m68k, ea+4); + return (UINT64)(h1) << 32 | (UINT64)(h2); + } + case 4: // # + { + h1 = OPER_I_32(m68k); + h2 = OPER_I_32(m68k); + return (UINT64)(h1) << 32 | (UINT64)(h2); + } + case 2: // (d16, PC) + { + UINT32 ea = EA_PCDI_32(m68k); + h1 = m68ki_read_32(m68k, ea+0); + h2 = m68ki_read_32(m68k, ea+4); + return (UINT64)(h1) << 32 | (UINT64)(h2); + } + default: fatalerror("M68kFPU: READ_EA_64: unhandled mode %d, reg %d at %08X\n", mode, reg, REG_PC(m68k)); + } + break; + } + default: fatalerror("M68kFPU: READ_EA_64: unhandled mode %d, reg %d at %08X\n", mode, reg, REG_PC(m68k)); + } + + return 0; +} + + +static floatx80 READ_EA_FPE(m68000_base_device *m68k, int ea) +{ + floatx80 fpr; + int mode = (ea >> 3) & 0x7; + int reg = (ea & 0x7); + + switch (mode) + { + case 2: // (An) + { + UINT32 ea = REG_A(m68k)[reg]; + fpr = load_extended_float80(m68k, ea); + break; + } + + case 3: // (An)+ + { + UINT32 ea = REG_A(m68k)[reg]; + REG_A(m68k)[reg] += 12; + fpr = load_extended_float80(m68k, ea); + break; + } + case 4: // -(An) + { + UINT32 ea = REG_A(m68k)[reg]-12; + REG_A(m68k)[reg] -= 12; + fpr = load_extended_float80(m68k, ea); + break; + } + case 5: // (d16, An) + { + // FIXME: will fail for fmovem + UINT32 ea = EA_AY_DI_32(m68k); + fpr = load_extended_float80(m68k, ea); + break; + } + case 6: // (An) + (Xn) + d8 + { + // FIXME: will fail for fmovem + UINT32 ea = EA_AY_IX_32(m68k); + fpr = load_extended_float80(m68k, ea); + break; + } + + case 7: // extended modes + { + switch (reg) + { + case 1: // (xxx) + { + UINT32 d1 = OPER_I_16(m68k); + UINT32 d2 = OPER_I_16(m68k); + UINT32 ea = (d1 << 16) | d2; + fpr = load_extended_float80(m68k, ea); + } + break; + + case 2: // (d16, PC) + { + UINT32 ea = EA_PCDI_32(m68k); + fpr = load_extended_float80(m68k, ea); + } + break; + + case 3: // (d16,PC,Dx.w) + { + UINT32 ea = EA_PCIX_32(m68k); + fpr = load_extended_float80(m68k, ea); + } + break; + + default: + fatalerror("M68kFPU: READ_EA_FPE: unhandled mode %d, reg %d, at %08X\n", mode, reg, REG_PC(m68k)); + break; + } + } + break; + + default: fatalerror("M68kFPU: READ_EA_FPE: unhandled mode %d, reg %d, at %08X\n", mode, reg, REG_PC(m68k)); break; + } + + return fpr; +} + +static floatx80 READ_EA_PACK(m68000_base_device *m68k, int ea) +{ + floatx80 fpr; + int mode = (ea >> 3) & 0x7; + int reg = (ea & 0x7); + + switch (mode) + { + case 2: // (An) + { + UINT32 ea = REG_A(m68k)[reg]; + fpr = load_pack_float80(m68k, ea); + break; + } + + case 3: // (An)+ + { + UINT32 ea = REG_A(m68k)[reg]; + REG_A(m68k)[reg] += 12; + fpr = load_pack_float80(m68k, ea); + break; + } + + case 7: // extended modes + { + switch (reg) + { + case 3: // (d16,PC,Dx.w) + { + UINT32 ea = EA_PCIX_32(m68k); + fpr = load_pack_float80(m68k, ea); + } + break; + + default: + fatalerror("M68kFPU: READ_EA_PACK: unhandled mode %d, reg %d, at %08X\n", mode, reg, REG_PC(m68k)); + break; + } + } + break; + + default: fatalerror("M68kFPU: READ_EA_PACK: unhandled mode %d, reg %d, at %08X\n", mode, reg, REG_PC(m68k)); break; + } + + return fpr; +} + +static void WRITE_EA_8(m68000_base_device *m68k, int ea, UINT8 data) +{ + int mode = (ea >> 3) & 0x7; + int reg = (ea & 0x7); + + switch (mode) + { + case 0: // Dn + { + REG_D(m68k)[reg] = data; + break; + } + case 2: // (An) + { + UINT32 ea = REG_A(m68k)[reg]; + m68ki_write_8(m68k, ea, data); + break; + } + case 3: // (An)+ + { + UINT32 ea = EA_AY_PI_8(m68k); + m68ki_write_8(m68k, ea, data); + break; + } + case 4: // -(An) + { + UINT32 ea = EA_AY_PD_8(m68k); + m68ki_write_8(m68k, ea, data); + break; + } + case 5: // (d16, An) + { + UINT32 ea = EA_AY_DI_8(m68k); + m68ki_write_8(m68k, ea, data); + break; + } + case 6: // (An) + (Xn) + d8 + { + UINT32 ea = EA_AY_IX_8(m68k); + m68ki_write_8(m68k, ea, data); + break; + } + case 7: + { + switch (reg) + { + case 1: // (xxx).B + { + UINT32 d1 = OPER_I_16(m68k); + UINT32 d2 = OPER_I_16(m68k); + UINT32 ea = (d1 << 16) | d2; + m68ki_write_8(m68k, ea, data); + break; + } + case 2: // (d16, PC) + { + UINT32 ea = EA_PCDI_16(m68k); + m68ki_write_8(m68k, ea, data); + break; + } + default: fatalerror("M68kFPU: WRITE_EA_8: unhandled mode %d, reg %d at %08X\n", mode, reg, REG_PC(m68k)); + } + break; + } + default: fatalerror("M68kFPU: WRITE_EA_8: unhandled mode %d, reg %d, data %08X at %08X\n", mode, reg, data, REG_PC(m68k)); + } +} + +static void WRITE_EA_16(m68000_base_device *m68k, int ea, UINT16 data) +{ + int mode = (ea >> 3) & 0x7; + int reg = (ea & 0x7); + + switch (mode) + { + case 0: // Dn + { + REG_D(m68k)[reg] = data; + break; + } + case 2: // (An) + { + UINT32 ea = REG_A(m68k)[reg]; + m68ki_write_16(m68k, ea, data); + break; + } + case 3: // (An)+ + { + UINT32 ea = EA_AY_PI_16(m68k); + m68ki_write_16(m68k, ea, data); + break; + } + case 4: // -(An) + { + UINT32 ea = EA_AY_PD_16(m68k); + m68ki_write_16(m68k, ea, data); + break; + } + case 5: // (d16, An) + { + UINT32 ea = EA_AY_DI_16(m68k); + m68ki_write_16(m68k, ea, data); + break; + } + case 6: // (An) + (Xn) + d8 + { + UINT32 ea = EA_AY_IX_16(m68k); + m68ki_write_16(m68k, ea, data); + break; + } + case 7: + { + switch (reg) + { + case 1: // (xxx).W + { + UINT32 d1 = OPER_I_16(m68k); + UINT32 d2 = OPER_I_16(m68k); + UINT32 ea = (d1 << 16) | d2; + m68ki_write_16(m68k, ea, data); + break; + } + case 2: // (d16, PC) + { + UINT32 ea = EA_PCDI_16(m68k); + m68ki_write_16(m68k, ea, data); + break; + } + default: fatalerror("M68kFPU: WRITE_EA_16: unhandled mode %d, reg %d at %08X\n", mode, reg, REG_PC(m68k)); + } + break; + } + default: fatalerror("M68kFPU: WRITE_EA_16: unhandled mode %d, reg %d, data %08X at %08X\n", mode, reg, data, REG_PC(m68k)); + } +} + +static void WRITE_EA_32(m68000_base_device *m68k, int ea, UINT32 data) +{ + int mode = (ea >> 3) & 0x7; + int reg = (ea & 0x7); + + switch (mode) + { + case 0: // Dn + { + REG_D(m68k)[reg] = data; + break; + } + case 1: // An + { + REG_A(m68k)[reg] = data; + break; + } + case 2: // (An) + { + UINT32 ea = REG_A(m68k)[reg]; + m68ki_write_32(m68k, ea, data); + break; + } + case 3: // (An)+ + { + UINT32 ea = EA_AY_PI_32(m68k); + m68ki_write_32(m68k, ea, data); + break; + } + case 4: // -(An) + { + UINT32 ea = EA_AY_PD_32(m68k); + m68ki_write_32(m68k, ea, data); + break; + } + case 5: // (d16, An) + { + UINT32 ea = EA_AY_DI_32(m68k); + m68ki_write_32(m68k, ea, data); + break; + } + case 6: // (An) + (Xn) + d8 + { + UINT32 ea = EA_AY_IX_32(m68k); + m68ki_write_32(m68k, ea, data); + break; + } + case 7: + { + switch (reg) + { + case 0: // (xxx).W + { + UINT32 ea = OPER_I_16(m68k); + m68ki_write_32(m68k, ea, data); + break; + } + case 1: // (xxx).L + { + UINT32 d1 = OPER_I_16(m68k); + UINT32 d2 = OPER_I_16(m68k); + UINT32 ea = (d1 << 16) | d2; + m68ki_write_32(m68k, ea, data); + break; + } + case 2: // (d16, PC) + { + UINT32 ea = EA_PCDI_32(m68k); + m68ki_write_32(m68k, ea, data); + break; + } + default: fatalerror("M68kFPU: WRITE_EA_32: unhandled mode %d, reg %d at %08X\n", mode, reg, REG_PC(m68k)); + } + break; + } + default: fatalerror("M68kFPU: WRITE_EA_32: unhandled mode %d, reg %d, data %08X at %08X\n", mode, reg, data, REG_PC(m68k)); + } +} + +static void WRITE_EA_64(m68000_base_device *m68k, int ea, UINT64 data) +{ + int mode = (ea >> 3) & 0x7; + int reg = (ea & 0x7); + + switch (mode) + { + case 2: // (An) + { + UINT32 ea = REG_A(m68k)[reg]; + m68ki_write_32(m68k, ea, (UINT32)(data >> 32)); + m68ki_write_32(m68k, ea+4, (UINT32)(data)); + break; + } + case 3: // (An)+ + { + UINT32 ea = REG_A(m68k)[reg]; + REG_A(m68k)[reg] += 8; + m68ki_write_32(m68k, ea+0, (UINT32)(data >> 32)); + m68ki_write_32(m68k, ea+4, (UINT32)(data)); + break; + } + case 4: // -(An) + { + UINT32 ea; + REG_A(m68k)[reg] -= 8; + ea = REG_A(m68k)[reg]; + m68ki_write_32(m68k, ea+0, (UINT32)(data >> 32)); + m68ki_write_32(m68k, ea+4, (UINT32)(data)); + break; + } + case 5: // (d16, An) + { + UINT32 ea = EA_AY_DI_32(m68k); + m68ki_write_32(m68k, ea+0, (UINT32)(data >> 32)); + m68ki_write_32(m68k, ea+4, (UINT32)(data)); + break; + } + case 6: // (An) + (Xn) + d8 + { + UINT32 ea = EA_AY_IX_32(m68k); + m68ki_write_32(m68k, ea+0, (UINT32)(data >> 32)); + m68ki_write_32(m68k, ea+4, (UINT32)(data)); + break; + } + case 7: + { + switch (reg) + { + case 1: // (xxx).L + { + UINT32 d1 = OPER_I_16(m68k); + UINT32 d2 = OPER_I_16(m68k); + UINT32 ea = (d1 << 16) | d2; + m68ki_write_32(m68k, ea+0, (UINT32)(data >> 32)); + m68ki_write_32(m68k, ea+4, (UINT32)(data)); + break; + } + case 2: // (d16, PC) + { + UINT32 ea = EA_PCDI_32(m68k); + m68ki_write_32(m68k, ea+0, (UINT32)(data >> 32)); + m68ki_write_32(m68k, ea+4, (UINT32)(data)); + break; + } + default: fatalerror("M68kFPU: WRITE_EA_64: unhandled mode %d, reg %d at %08X\n", mode, reg, REG_PC(m68k)); + } + break; + } + default: fatalerror("M68kFPU: WRITE_EA_64: unhandled mode %d, reg %d, data %08X%08X at %08X\n", mode, reg, (UINT32)(data >> 32), (UINT32)(data), REG_PC(m68k)); + } +} + +static void WRITE_EA_FPE(m68000_base_device *m68k, int ea, floatx80 fpr) +{ + int mode = (ea >> 3) & 0x7; + int reg = (ea & 0x7); + + switch (mode) + { + case 2: // (An) + { + UINT32 ea; + ea = REG_A(m68k)[reg]; + store_extended_float80(m68k, ea, fpr); + break; + } + + case 3: // (An)+ + { + UINT32 ea; + ea = REG_A(m68k)[reg]; + store_extended_float80(m68k, ea, fpr); + REG_A(m68k)[reg] += 12; + break; + } + + case 4: // -(An) + { + UINT32 ea; + REG_A(m68k)[reg] -= 12; + ea = REG_A(m68k)[reg]; + store_extended_float80(m68k, ea, fpr); + break; + } + + case 7: + { + switch (reg) + { + default: fatalerror("M68kFPU: WRITE_EA_FPE: unhandled mode %d, reg %d, at %08X\n", mode, reg, REG_PC(m68k)); + } + } + default: fatalerror("M68kFPU: WRITE_EA_FPE: unhandled mode %d, reg %d, at %08X\n", mode, reg, REG_PC(m68k)); + } +} + +static void WRITE_EA_PACK(m68000_base_device *m68k, int ea, int k, floatx80 fpr) +{ + int mode = (ea >> 3) & 0x7; + int reg = (ea & 0x7); + + switch (mode) + { + case 2: // (An) + { + UINT32 ea; + ea = REG_A(m68k)[reg]; + store_pack_float80(m68k, ea, k, fpr); + break; + } + + case 3: // (An)+ + { + UINT32 ea; + ea = REG_A(m68k)[reg]; + store_pack_float80(m68k, ea, k, fpr); + REG_A(m68k)[reg] += 12; + break; + } + + case 4: // -(An) + { + UINT32 ea; + REG_A(m68k)[reg] -= 12; + ea = REG_A(m68k)[reg]; + store_pack_float80(m68k, ea, k, fpr); + break; + } + + case 7: + { + switch (reg) + { + default: fatalerror("M68kFPU: WRITE_EA_PACK: unhandled mode %d, reg %d, at %08X\n", mode, reg, REG_PC(m68k)); + } + } + default: fatalerror("M68kFPU: WRITE_EA_PACK: unhandled mode %d, reg %d, at %08X\n", mode, reg, REG_PC(m68k)); + } +} + +static void fpgen_rm_reg(m68000_base_device *m68k, UINT16 w2) +{ + int ea = m68k->ir & 0x3f; + int rm = (w2 >> 14) & 0x1; + int src = (w2 >> 10) & 0x7; + int dst = (w2 >> 7) & 0x7; + int opmode = w2 & 0x7f; + floatx80 source; + + // fmovecr #$f, fp0 f200 5c0f + + if (rm) + { + switch (src) + { + case 0: // Long-Word Integer + { + INT32 d = READ_EA_32(m68k, ea); + source = int32_to_floatx80(d); + break; + } + case 1: // Single-precision Real + { + UINT32 d = READ_EA_32(m68k, ea); + source = float32_to_floatx80(d); + break; + } + case 2: // Extended-precision Real + { + source = READ_EA_FPE(m68k, ea); + break; + } + case 3: // Packed-decimal Real + { + source = READ_EA_PACK(m68k, ea); + break; + } + case 4: // Word Integer + { + INT16 d = READ_EA_16(m68k, ea); + source = int32_to_floatx80((INT32)d); + break; + } + case 5: // Double-precision Real + { + UINT64 d = READ_EA_64(m68k, ea); + + source = float64_to_floatx80(d); + break; + } + case 6: // Byte Integer + { + INT8 d = READ_EA_8(m68k, ea); + source = int32_to_floatx80((INT32)d); + break; + } + case 7: // FMOVECR load from constant ROM + { + switch (w2 & 0x7f) + { + case 0x0: // Pi + source.high = 0x4000; + source.low = U64(0xc90fdaa22168c235); + break; + + case 0xb: // log10(2) + source.high = 0x3ffd; + source.low = U64(0x9a209a84fbcff798); + break; + + case 0xc: // e + source.high = 0x4000; + source.low = U64(0xadf85458a2bb4a9b); + break; + + case 0xd: // log2(e) + source.high = 0x3fff; + source.low = U64(0xb8aa3b295c17f0bc); + break; + + case 0xe: // log10(e) + source.high = 0x3ffd; + source.low = U64(0xde5bd8a937287195); + break; + + case 0xf: // 0.0 + source = int32_to_floatx80((INT32)0); + break; + + case 0x30: // ln(2) + source.high = 0x3ffe; + source.low = U64(0xb17217f7d1cf79ac); + break; + + case 0x31: // ln(10) + source.high = 0x4000; + source.low = U64(0x935d8dddaaa8ac17); + break; + + case 0x32: // 1 (or 100? manuals are unclear, but 1 would make more sense) + source = int32_to_floatx80((INT32)1); + break; + + case 0x33: // 10^1 + source = int32_to_floatx80((INT32)10); + break; + + case 0x34: // 10^2 + source = int32_to_floatx80((INT32)10*10); + break; + + case 0x35: // 10^4 + source = int32_to_floatx80((INT32)1000*10); + break; + + case 0x36: // 1.0e8 + source = int32_to_floatx80((INT32)10000000*10); + break; + + case 0x37: // 1.0e16 - can't get the right precision from INT32 so go "direct" with constants from h/w + source.high = 0x4034; + source.low = U64(0x8e1bc9bf04000000); + break; + + case 0x38: // 1.0e32 + source.high = 0x4069; + source.low = U64(0x9dc5ada82b70b59e); + break; + + case 0x39: // 1.0e64 + source.high = 0x40d3; + source.low = U64(0xc2781f49ffcfa6d5); + break; + + case 0x3a: // 1.0e128 + source.high = 0x41a8; + source.low = U64(0x93ba47c980e98ce0); + break; + + case 0x3b: // 1.0e256 + source.high = 0x4351; + source.low = U64(0xaa7eebfb9df9de8e); + break; + + case 0x3c: // 1.0e512 + source.high = 0x46a3; + source.low = U64(0xe319a0aea60e91c7); + break; + + case 0x3d: // 1.0e1024 + source.high = 0x4d48; + source.low = U64(0xc976758681750c17); + break; + + case 0x3e: // 1.0e2048 + source.high = 0x5a92; + source.low = U64(0x9e8b3b5dc53d5de5); + break; + + case 0x3f: // 1.0e4096 + source.high = 0x7525; + source.low = U64(0xc46052028a20979b); + break; + + default: + fatalerror("fmove_rm_reg: unknown constant ROM offset %x at %08x\n", w2&0x7f, REG_PC(m68k)-4); + break; + } + + // handle it right here, the usual opmode bits aren't valid in the FMOVECR case + REG_FP(m68k)[dst] = source; + m68k->remaining_cycles -= 4; + return; + } + default: fatalerror("fmove_rm_reg: invalid source specifier %x at %08X\n", src, REG_PC(m68k)-4); + } + } + else + { + source = REG_FP(m68k)[src]; + } + + + + switch (opmode) + { + case 0x00: // FMOVE + { + REG_FP(m68k)[dst] = source; + SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]); + m68k->remaining_cycles -= 4; + break; + } + case 0x01: // FINT + { + INT32 temp; + temp = floatx80_to_int32(source); + REG_FP(m68k)[dst] = int32_to_floatx80(temp); + break; + } + case 0x03: // FINTRZ + { + INT32 temp; + temp = floatx80_to_int32_round_to_zero(source); + REG_FP(m68k)[dst] = int32_to_floatx80(temp); + break; + } + case 0x04: // FSQRT + { + REG_FP(m68k)[dst] = floatx80_sqrt(source); + SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]); + m68k->remaining_cycles -= 109; + break; + } + case 0x06: // FLOGNP1 + { + REG_FP(m68k)[dst] = floatx80_flognp1 (source); + SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]); + m68k->remaining_cycles -= 594; // for MC68881 + break; + } + case 0x0e: // FSIN + { + REG_FP(m68k)[dst] = source; + floatx80_fsin(REG_FP(m68k)[dst]); + SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]); + m68k->remaining_cycles -= 75; + break; + } + case 0x0f: // FTAN + { + REG_FP(m68k)[dst] = source; + floatx80_ftan(REG_FP(m68k)[dst]); + SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]); + m68k->remaining_cycles -= 75; + break; + } + case 0x14: // FLOGN + { + REG_FP(m68k)[dst] = floatx80_flogn (source); + SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]); + m68k->remaining_cycles -= 548; // for MC68881 + break; + } + case 0x15: // FLOG10 + { + REG_FP(m68k)[dst] = floatx80_flog10 (source); + SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]); + m68k->remaining_cycles -= 604; // for MC68881 + break; + } + case 0x16: // FLOG2 + { + REG_FP(m68k)[dst] = floatx80_flog2 (source); + SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]); + m68k->remaining_cycles -= 604; // for MC68881 + break; + } + case 0x18: // FABS + { + REG_FP(m68k)[dst] = source; + REG_FP(m68k)[dst].high &= 0x7fff; + SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]); + m68k->remaining_cycles -= 3; + break; + } + case 0x1a: // FNEG + { + REG_FP(m68k)[dst] = source; + REG_FP(m68k)[dst].high ^= 0x8000; + SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]); + m68k->remaining_cycles -= 3; + break; + } + case 0x1d: // FCOS + { + REG_FP(m68k)[dst] = source; + floatx80_fcos(REG_FP(m68k)[dst]); + SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]); + m68k->remaining_cycles -= 75; + break; + } + case 0x1e: // FGETEXP + { + INT16 temp2; + + temp2 = source.high; // get the exponent + temp2 -= 0x3fff; // take off the bias + REG_FP(m68k)[dst] = double_to_fx80((double)temp2); + SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]); + m68k->remaining_cycles -= 6; + break; + } + case 0x20: // FDIV + { + REG_FP(m68k)[dst] = floatx80_div(REG_FP(m68k)[dst], source); + m68k->remaining_cycles -= 43; + break; + } + case 0x22: // FADD + { + REG_FP(m68k)[dst] = floatx80_add(REG_FP(m68k)[dst], source); + SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]); + m68k->remaining_cycles -= 9; + break; + } + case 0x23: // FMUL + { + REG_FP(m68k)[dst] = floatx80_mul(REG_FP(m68k)[dst], source); + SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]); + m68k->remaining_cycles -= 11; + break; + } + case 0x24: // FSGLDIV + { + float32 a = floatx80_to_float32( REG_FP(m68k)[dst] ); + float32 b = floatx80_to_float32( source ); + REG_FP(m68k)[dst] = float32_to_floatx80( float32_div(a, b) ); + m68k->remaining_cycles -= 43; // // ? (value is from FDIV) + break; + } + case 0x25: // FREM + { + REG_FP(m68k)[dst] = floatx80_rem(REG_FP(m68k)[dst], source); + SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]); + m68k->remaining_cycles -= 43; // guess + break; + } + case 0x26: // FSCALE + { + REG_FP(m68k)[dst] = floatx80_scale(REG_FP(m68k)[dst], source); + SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]); + m68k->remaining_cycles -= 46; // (better?) guess + break; + } + case 0x27: // FSGLMUL + { + float32 a = floatx80_to_float32( REG_FP(m68k)[dst] ); + float32 b = floatx80_to_float32( source ); + REG_FP(m68k)[dst] = float32_to_floatx80( float32_mul(a, b) ); + SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]); + m68k->remaining_cycles -= 11; // ? (value is from FMUL) + break; + } + case 0x28: // FSUB + { + REG_FP(m68k)[dst] = floatx80_sub(REG_FP(m68k)[dst], source); + SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]); + m68k->remaining_cycles -= 9; + break; + } + case 0x38: // FCMP + { + floatx80 res; + res = floatx80_sub(REG_FP(m68k)[dst], source); + SET_CONDITION_CODES(m68k, res); + m68k->remaining_cycles -= 7; + break; + } + case 0x3a: // FTST + { + floatx80 res; + res = source; + SET_CONDITION_CODES(m68k, res); + m68k->remaining_cycles -= 7; + break; + } + + default: fatalerror("fpgen_rm_reg: unimplemented opmode %02X at %08X\n", opmode, REG_PPC(m68k)); + } +} + +static void fmove_reg_mem(m68000_base_device *m68k, UINT16 w2) +{ + int ea = m68k->ir & 0x3f; + int src = (w2 >> 7) & 0x7; + int dst = (w2 >> 10) & 0x7; + int k = (w2 & 0x7f); + + switch (dst) + { + case 0: // Long-Word Integer + { + INT32 d = (INT32)floatx80_to_int32(REG_FP(m68k)[src]); + WRITE_EA_32(m68k, ea, d); + break; + } + case 1: // Single-precision Real + { + UINT32 d = floatx80_to_float32(REG_FP(m68k)[src]); + WRITE_EA_32(m68k, ea, d); + break; + } + case 2: // Extended-precision Real + { + WRITE_EA_FPE(m68k, ea, REG_FP(m68k)[src]); + break; + } + case 3: // Packed-decimal Real with Static K-factor + { + // sign-extend k + k = (k & 0x40) ? (k | 0xffffff80) : (k & 0x7f); + WRITE_EA_PACK(m68k, ea, k, REG_FP(m68k)[src]); + break; + } + case 4: // Word Integer + { + int32 value = floatx80_to_int32(REG_FP(m68k)[src]); + if (value > 0x7fff || value < -0x8000 ) + { + REG_FPSR(m68k) |= FPES_OE | FPAE_IOP; + } + WRITE_EA_16(m68k, ea, (INT16)value); + break; + } + case 5: // Double-precision Real + { + UINT64 d; + + d = floatx80_to_float64(REG_FP(m68k)[src]); + + WRITE_EA_64(m68k, ea, d); + break; + } + case 6: // Byte Integer + { + int32 value = floatx80_to_int32(REG_FP(m68k)[src]); + if (value > 127 || value < -128) + { + REG_FPSR(m68k) |= FPES_OE | FPAE_IOP; + } + WRITE_EA_8(m68k, ea, (INT8) value); + break; + } + case 7: // Packed-decimal Real with Dynamic K-factor + { + WRITE_EA_PACK(m68k, ea, REG_D(m68k)[k>>4], REG_FP(m68k)[src]); + break; + } + } + + m68k->remaining_cycles -= 12; +} + +static void fmove_fpcr(m68000_base_device *m68k, UINT16 w2) +{ + int ea = m68k->ir & 0x3f; + int dir = (w2 >> 13) & 0x1; + int regsel = (w2 >> 10) & 0x7; + int mode = (ea >> 3) & 0x7; + + if ((mode == 5) || (mode == 6)) + { + UINT32 address = 0xffffffff; // force a bus error if this doesn't get assigned + + if (mode == 5) + { + address = EA_AY_DI_32(m68k); + } + else if (mode == 6) + { + address = EA_AY_IX_32(m68k); + } + + if (dir) // From system control reg to + { + if (regsel & 4) { m68ki_write_32(m68k, address, REG_FPCR(m68k)); address += 4; } + if (regsel & 2) { m68ki_write_32(m68k, address, REG_FPSR(m68k)); address += 4; } + if (regsel & 1) { m68ki_write_32(m68k, address, REG_FPIAR(m68k)); address += 4; } + } + else // From to system control reg + { + if (regsel & 4) { REG_FPCR(m68k) = m68ki_read_32(m68k, address); address += 4; } + if (regsel & 2) { REG_FPSR(m68k) = m68ki_read_32(m68k, address); address += 4; } + if (regsel & 1) { REG_FPIAR(m68k) = m68ki_read_32(m68k, address); address += 4; } + } + } + else + { + if (dir) // From system control reg to + { + if (regsel & 4) WRITE_EA_32(m68k, ea, REG_FPCR(m68k)); + if (regsel & 2) WRITE_EA_32(m68k, ea, REG_FPSR(m68k)); + if (regsel & 1) WRITE_EA_32(m68k, ea, REG_FPIAR(m68k)); + } + else // From to system control reg + { + if (regsel & 4) REG_FPCR(m68k) = READ_EA_32(m68k, ea); + if (regsel & 2) REG_FPSR(m68k) = READ_EA_32(m68k, ea); + if (regsel & 1) REG_FPIAR(m68k) = READ_EA_32(m68k, ea); + } + } + + // FIXME: (2011-12-18 ost) + // rounding_mode and rounding_precision of softfloat.c should be set according to current fpcr + // but: with this code on Apollo the following programs in /systest/fptest will fail: + // 1. Single Precision Whetstone will return wrong results never the less + // 2. Vector Test will fault with 00040004: reference to illegal address + + if ((regsel & 4) && dir == 0) + { + int rnd = (REG_FPCR(m68k) >> 4) & 3; + int prec = (REG_FPCR(m68k) >> 6) & 3; + + logerror("m68k_fpsp:fmove_fpcr fpcr=%04x prec=%d rnd=%d\n", REG_FPCR(m68k), prec, rnd); + +#ifdef FLOATX80 + switch (prec) + { + case 0: // Extend (X) + floatx80_rounding_precision = 80; + break; + case 1: // Single (S) + floatx80_rounding_precision = 32; + break; + case 2: // Double (D) + floatx80_rounding_precision = 64; + break; + case 3: // Undefined + floatx80_rounding_precision = 80; + break; + } +#endif + + switch (rnd) + { + case 0: // To Nearest (RN) + float_rounding_mode = float_round_nearest_even; + break; + case 1: // To Zero (RZ) + float_rounding_mode = float_round_to_zero; + break; + case 2: // To Minus Infinitiy (RM) + float_rounding_mode = float_round_down; + break; + case 3: // To Plus Infinitiy (RP) + float_rounding_mode = float_round_up; + break; + } + } + + m68k->remaining_cycles -= 10; +} + +static void fmovem(m68000_base_device *m68k, UINT16 w2) +{ + int i; + int ea = m68k->ir & 0x3f; + int dir = (w2 >> 13) & 0x1; + int mode = (w2 >> 11) & 0x3; + int reglist = w2 & 0xff; + + UINT32 mem_addr = 0; + switch (ea >> 3) + { + case 5: // (d16, An) + mem_addr= EA_AY_DI_32(m68k); + break; + case 6: // (An) + (Xn) + d8 + mem_addr= EA_AY_IX_32(m68k); + break; + } + + if (dir) // From FP regs to mem + { + switch (mode) + { + case 1: // Dynamic register list, postincrement or control addressing mode. + // FIXME: not really tested, but seems to work + reglist = REG_D(m68k)[(reglist >> 4) & 7]; + + case 0: // Static register list, predecrement or control addressing mode + { + for (i=0; i < 8; i++) + { + if (reglist & (1 << i)) + { + switch (ea >> 3) + { + case 5: // (d16, An) + case 6: // (An) + (Xn) + d8 + store_extended_float80(m68k, mem_addr, REG_FP(m68k)[i]); + mem_addr += 12; + break; + default: + WRITE_EA_FPE(m68k, ea, REG_FP(m68k)[i]); + break; + } + + m68k->remaining_cycles -= 2; + } + } + break; + } + + case 2: // Static register list, postdecrement or control addressing mode + { + for (i=0; i < 8; i++) + { + if (reglist & (1 << i)) + { + switch (ea >> 3) + { + case 5: // (d16, An) + case 6: // (An) + (Xn) + d8 + store_extended_float80(m68k, mem_addr, REG_FP(m68k)[7-i]); + mem_addr += 12; + break; + default: + WRITE_EA_FPE(m68k, ea, REG_FP(m68k)[7-i]); + break; + } + + m68k->remaining_cycles -= 2; + } + } + break; + } + + default: fatalerror("M680x0: FMOVEM: mode %d unimplemented at %08X\n", mode, REG_PC(m68k)-4); + } + } + else // From mem to FP regs + { + switch (mode) + { + case 3: // Dynamic register list, predecrement addressing mode. + // FIXME: not really tested, but seems to work + reglist = REG_D(m68k)[(reglist >> 4) & 7]; + + case 2: // Static register list, postincrement or control addressing mode + { + for (i=0; i < 8; i++) + { + if (reglist & (1 << i)) + { + switch (ea >> 3) + { + case 5: // (d16, An) + case 6: // (An) + (Xn) + d8 + REG_FP(m68k)[7-i] = load_extended_float80(m68k, mem_addr); + mem_addr += 12; + break; + default: + REG_FP(m68k)[7-i] = READ_EA_FPE(m68k, ea); + break; + } + m68k->remaining_cycles -= 2; + } + } + break; + } + + default: fatalerror("M680x0: FMOVEM: mode %d unimplemented at %08X\n", mode, REG_PC(m68k)-4); + } + } +} + +static void fscc(m68000_base_device *m68k) +{ + int ea = m68k->ir & 0x3f; + int condition = (INT16)(OPER_I_16(m68k)); + + WRITE_EA_8(m68k, ea, TEST_CONDITION(m68k, condition) ? 0xff : 0); + m68k->remaining_cycles -= 7; // ??? +} + +static void fbcc16(m68000_base_device *m68k) +{ + INT32 offset; + int condition = m68k->ir & 0x3f; + + offset = (INT16)(OPER_I_16(m68k)); + + // TODO: condition and jump!!! + if (TEST_CONDITION(m68k, condition)) + { + m68ki_trace_t0(m68k); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_16(m68k, offset-2); + } + + m68k->remaining_cycles -= 7; +} + +static void fbcc32(m68000_base_device *m68k) +{ + INT32 offset; + int condition = m68k->ir & 0x3f; + + offset = OPER_I_32(m68k); + + // TODO: condition and jump!!! + if (TEST_CONDITION(m68k, condition)) + { + m68ki_trace_t0(m68k); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_32(m68k, offset-4); + } + + m68k->remaining_cycles -= 7; +} + + +void m68040_fpu_op0(m68000_base_device *m68k) +{ + m68k->fpu_just_reset = 0; + + switch ((m68k->ir >> 6) & 0x3) + { + case 0: + { + UINT16 w2 = OPER_I_16(m68k); + switch ((w2 >> 13) & 0x7) + { + case 0x0: // FPU ALU FP, FP + case 0x2: // FPU ALU ea, FP + { + fpgen_rm_reg(m68k, w2); + break; + } + + case 0x3: // FMOVE FP, ea + { + fmove_reg_mem(m68k, w2); + break; + } + + case 0x4: // FMOVEM ea, FPCR + case 0x5: // FMOVEM FPCR, ea + { + fmove_fpcr(m68k, w2); + break; + } + + case 0x6: // FMOVEM ea, list + case 0x7: // FMOVEM list, ea + { + fmovem(m68k, w2); + break; + } + + default: fatalerror("M68kFPU: unimplemented subop %d at %08X\n", (w2 >> 13) & 0x7, REG_PC(m68k)-4); + } + break; + } + + case 1: // FBcc disp16 + { + switch ((m68k->ir >> 3) & 0x7) { + case 1: // FDBcc + // TODO: + break; + default: // FScc (?) + fscc(m68k); + return; + } + fatalerror("M68kFPU: unimplemented main op %d with mode %d at %08X\n", (m68k->ir >> 6) & 0x3, (m68k->ir >> 3) & 0x7, REG_PPC(m68k)); + } + + case 2: // FBcc disp16 + { + fbcc16(m68k); + break; + } + case 3: // FBcc disp32 + { + fbcc32(m68k); + break; + } + + default: fatalerror("M68kFPU: unimplemented main op %d\n", (m68k->ir >> 6) & 0x3); + } +} + +static int perform_fsave(m68000_base_device *m68k, UINT32 addr, int inc) +{ + if(m68k->cpu_type & CPU_TYPE_040) + { + if(inc) + { + m68ki_write_32(m68k, addr, 0x41000000); + return 4; + } + else + { + m68ki_write_32(m68k, addr-4, 0x41000000); + return -4; + } + } + + if (inc) + { + // 68881 IDLE, version 0x1f + m68ki_write_32(m68k, addr, 0x1f180000); + m68ki_write_32(m68k, addr+4, 0); + m68ki_write_32(m68k, addr+8, 0); + m68ki_write_32(m68k, addr+12, 0); + m68ki_write_32(m68k, addr+16, 0); + m68ki_write_32(m68k, addr+20, 0); + m68ki_write_32(m68k, addr+24, 0x70000000); + return 7*4; + } + else + { + m68ki_write_32(m68k, addr-4, 0x70000000); + m68ki_write_32(m68k, addr-8, 0); + m68ki_write_32(m68k, addr-12, 0); + m68ki_write_32(m68k, addr-16, 0); + m68ki_write_32(m68k, addr-20, 0); + m68ki_write_32(m68k, addr-24, 0); + m68ki_write_32(m68k, addr-28, 0x1f180000); + return -7*4; + } +} + +// FRESTORE on a NULL frame reboots the FPU - all registers to NaN, the 3 status regs to 0 +static void do_frestore_null(m68000_base_device *m68k) +{ + int i; + + REG_FPCR(m68k) = 0; + REG_FPSR(m68k) = 0; + REG_FPIAR(m68k) = 0; + for (i = 0; i < 8; i++) + { + REG_FP(m68k)[i].high = 0x7fff; + REG_FP(m68k)[i].low = U64(0xffffffffffffffff); + } + + // Mac IIci at 408458e6 wants an FSAVE of a just-restored NULL frame to also be NULL + // The PRM says it's possible to generate a NULL frame, but not how/when/why. (need the 68881/68882 manual!) + m68k->fpu_just_reset = 1; +} + +static void m68040_do_fsave(m68000_base_device *m68k, UINT32 addr, int reg, int inc) +{ + if (m68k->fpu_just_reset) + { + m68ki_write_32(m68k, addr, 0); + } + else + { + // we normally generate an IDLE frame + int delta = perform_fsave(m68k, addr, inc); + if(reg != -1) + REG_A(m68k)[reg] += delta; + } +} + +static void m68040_do_frestore(m68000_base_device *m68k, UINT32 addr, int reg) +{ + bool m40 = m68k->cpu_type & CPU_TYPE_040; + UINT32 temp = m68ki_read_32(m68k, addr); + + // check for NULL frame + if (temp & 0xff000000) + { + // we don't handle non-NULL frames + m68k->fpu_just_reset = 0; + + if (reg != -1) + { + // how about an IDLE frame? + if (!m40 && ((temp & 0x00ff0000) == 0x00180000)) + { + REG_A(m68k)[reg] += 7*4; + } + else if (m40 && ((temp & 0xffff0000) == 0x41000000)) + { + REG_A(m68k)[reg] += 4; + } // check UNIMP + else if ((temp & 0x00ff0000) == 0x00380000) + { + REG_A(m68k)[reg] += 14*4; + } // check BUSY + else if ((temp & 0x00ff0000) == 0x00b40000) + { + REG_A(m68k)[reg] += 45*4; + } + } + } + else + { + do_frestore_null(m68k); + } +} + +void m68040_fpu_op1(m68000_base_device *m68k) +{ + int ea = m68k->ir & 0x3f; + int mode = (ea >> 3) & 0x7; + int reg = (ea & 0x7); + UINT32 addr; + + switch ((m68k->ir >> 6) & 0x3) + { + case 0: // FSAVE + { + switch (mode) + { + case 2: // (An) + addr = REG_A(m68k)[reg]; + m68040_do_fsave(m68k, addr, -1, 1); + break; + + case 3: // (An)+ + addr = EA_AY_PI_32(m68k); + m68040_do_fsave(m68k, addr, reg, 1); + break; + + case 4: // -(An) + addr = EA_AY_PD_32(m68k); + m68040_do_fsave(m68k, addr, reg, 0); + break; + + case 5: // (D16, An) + addr = EA_AY_DI_16(m68k); + m68040_do_fsave(m68k, addr, -1, 1); + break; + + case 7: // + switch (reg) + { + case 1: // (abs32) + { + addr = EA_AL_32(m68k); + m68040_do_fsave(m68k, addr, -1, 1); + break; + } + case 2: // (d16, PC) + { + addr = EA_PCDI_16(m68k); + m68040_do_fsave(m68k, addr, -1, 1); + break; + } + default: + fatalerror("M68kFPU: FSAVE unhandled mode %d reg %d at %x\n", mode, reg, REG_PC(m68k)); + } + + break; + + default: + fatalerror("M68kFPU: FSAVE unhandled mode %d reg %d at %x\n", mode, reg, REG_PC(m68k)); + } + break; + } + break; + + case 1: // FRESTORE + { + switch (mode) + { + case 2: // (An) + addr = REG_A(m68k)[reg]; + m68040_do_frestore(m68k, addr, -1); + break; + + case 3: // (An)+ + addr = EA_AY_PI_32(m68k); + m68040_do_frestore(m68k, addr, reg); + break; + + case 5: // (D16, An) + addr = EA_AY_DI_16(m68k); + m68040_do_frestore(m68k, addr, -1); + break; + + case 7: // + switch (reg) + { + case 1: // (abs32) + { + addr = EA_AL_32(m68k); + m68040_do_frestore(m68k, addr, -1); + break; + } + case 2: // (d16, PC) + { + addr = EA_PCDI_16(m68k); + m68040_do_frestore(m68k, addr, -1); + break; + } + default: + fatalerror("M68kFPU: FRESTORE unhandled mode %d reg %d at %x\n", mode, reg, REG_PC(m68k)); + } + + break; + + default: + fatalerror("M68kFPU: FRESTORE unhandled mode %d reg %d at %x\n", mode, reg, REG_PC(m68k)); + } + break; + } + break; + + default: fatalerror("m68040_fpu_op1: unimplemented op %d at %08X\n", (m68k->ir >> 6) & 0x3, REG_PC(m68k)-2); + } +} + +void m68881_ftrap(m68000_base_device *m68k) +{ + UINT16 w2 = OPER_I_16(m68k); + + // now check the condition + if (TEST_CONDITION(m68k, w2 & 0x3f)) + { + // trap here + m68ki_exception_trap(m68k, EXCEPTION_TRAPV); + } + else // fall through, requires eating the operand + { + switch (m68k->ir & 0x7) + { + case 2: // word operand + OPER_I_16(m68k); + break; + + case 3: // long word operand + OPER_I_32(m68k); + break; + + case 4: // no operand + break; + } + } +} diff --git a/src/devices/cpu/m68000/m68kmake.c b/src/devices/cpu/m68000/m68kmake.c new file mode 100644 index 00000000000..6a3642c4b1d --- /dev/null +++ b/src/devices/cpu/m68000/m68kmake.c @@ -0,0 +1,1423 @@ +// license:BSD-3-Clause +// copyright-holders:Karl Stenerud +/* ======================================================================== */ +/* ========================= LICENSING & COPYRIGHT ======================== */ +/* ======================================================================== */ +/* + * MUSASHI + * Version 4.90 + * + * A portable Motorola M680x0 processor emulation engine. + * Copyright Karl Stenerud. All rights reserved. + * + */ + +/* + * 68030 and PMMU by R. Belmont and Hans Ostermeyer + * 68040 and FPU by Ville Linde, R. Belmont, and Hans Ostermeyer + * CPU32 by David Haywood. ColdFire by R. Belmont. + * + */ + + +/* ======================================================================== */ +/* ============================ CODE GENERATOR ============================ */ +/* ======================================================================== */ +/* + * This is the code generator program which will generate the opcode table + * and the final opcode handlers. + * + * It requires an input file to function (default m68k_in.c), but you can + * specify your own like so: + * + * m68kmake + * + * where output path is the path where the output files should be placed, and + * input file is the file to use for input. + * + * If you modify the input file greatly from its released form, you may have + * to tweak the configuration section a bit since I'm using static allocation + * to keep things simple. + * + * + * TODO: - build a better code generator for the move instruction. + * - Add callm and rtm instructions + * - Fix RTE to handle other format words + * - Add address error (and bus error?) handling + */ + + +static const char g_version[] = "4.90"; + +/* ======================================================================== */ +/* =============================== INCLUDES =============================== */ +/* ======================================================================== */ + +#include +#include +#include +#include +#include + + + +/* ======================================================================== */ +/* ============================= CONFIGURATION ============================ */ +/* ======================================================================== */ + +#if defined(__GNUC__) && (__GNUC__ >= 3) +#define ATTR_PRINTF(x,y) __attribute__((format(printf, x, y))) +#define ATTR_NORETURN __attribute__((noreturn)) +#else +#define ATTR_PRINTF(x,y) +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +#define ATTR_NORETURN __declspec(noreturn) +#else +#define ATTR_NORETURN +#endif +#endif + +#define M68K_MAX_PATH 1024 +#define M68K_MAX_DIR 1024 + +#define MAX_LINE_LENGTH 200 /* length of 1 line */ +#define MAX_BODY_LENGTH 300 /* Number of lines in 1 function */ +#define MAX_REPLACE_LENGTH 30 /* Max number of replace strings */ +#define MAX_INSERT_LENGTH 5000 /* Max size of insert piece */ +#define MAX_NAME_LENGTH 96 /* Max length of ophandler name */ +#define MAX_SPEC_PROC_LENGTH 4 /* Max length of special processing str */ +#define MAX_SPEC_EA_LENGTH 5 /* Max length of specified EA str */ +#define EA_ALLOWED_LENGTH 11 /* Max length of ea allowed str */ +#define MAX_OPCODE_INPUT_TABLE_LENGTH 1000 /* Max length of opcode handler tbl */ +#define MAX_OPCODE_OUTPUT_TABLE_LENGTH 3000 /* Max length of opcode handler tbl */ + +/* Default filenames */ +#define FILENAME_INPUT "m68k_in.c" +#define FILENAME_PROTOTYPE "m68kops.h" +#define FILENAME_TABLE "m68kops.c" + + +/* Identifier sequences recognized by this program */ + +#define ID_INPUT_SEPARATOR "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" + +#define ID_BASE "M68KMAKE" +#define ID_PROTOTYPE_HEADER ID_BASE "_PROTOTYPE_HEADER" +#define ID_PROTOTYPE_FOOTER ID_BASE "_PROTOTYPE_FOOTER" +#define ID_TABLE_HEADER ID_BASE "_TABLE_HEADER" +#define ID_TABLE_FOOTER ID_BASE "_TABLE_FOOTER" +#define ID_TABLE_BODY ID_BASE "_TABLE_BODY" +#define ID_TABLE_START ID_BASE "_TABLE_START" +#define ID_OPHANDLER_HEADER ID_BASE "_OPCODE_HANDLER_HEADER" +#define ID_OPHANDLER_FOOTER ID_BASE "_OPCODE_HANDLER_FOOTER" +#define ID_OPHANDLER_BODY ID_BASE "_OPCODE_HANDLER_BODY" +#define ID_END ID_BASE "_END" + +#define ID_OPHANDLER_NAME ID_BASE "_OP" +#define ID_OPHANDLER_EA_AY_8 ID_BASE "_GET_EA_AY_8" +#define ID_OPHANDLER_EA_AY_16 ID_BASE "_GET_EA_AY_16" +#define ID_OPHANDLER_EA_AY_32 ID_BASE "_GET_EA_AY_32" +#define ID_OPHANDLER_OPER_AY_8 ID_BASE "_GET_OPER_AY_8" +#define ID_OPHANDLER_OPER_AY_16 ID_BASE "_GET_OPER_AY_16" +#define ID_OPHANDLER_OPER_AY_32 ID_BASE "_GET_OPER_AY_32" +#define ID_OPHANDLER_CC ID_BASE "_CC" +#define ID_OPHANDLER_NOT_CC ID_BASE "_NOT_CC" + + +#ifndef DECL_SPEC +#define DECL_SPEC +#endif /* DECL_SPEC */ + + + +/* ======================================================================== */ +/* ============================== PROTOTYPES ============================== */ +/* ======================================================================== */ + +enum +{ + CPU_TYPE_000 = 0, // 0 + CPU_TYPE_010, // 1 + CPU_TYPE_020, // 2 + CPU_TYPE_030, // 3 + CPU_TYPE_040, // 4 + CPU_TYPE_FSCPU32, // 5 + CPU_TYPE_COLDFIRE, // 6 + NUM_CPUS +}; + +#define UNSPECIFIED "." +#define UNSPECIFIED_CH '.' + +#define HAS_NO_EA_MODE(A) (strcmp(A, "..........") == 0) +#define HAS_EA_AI(A) ((A)[0] == 'A') +#define HAS_EA_PI(A) ((A)[1] == '+') +#define HAS_EA_PD(A) ((A)[2] == '-') +#define HAS_EA_DI(A) ((A)[3] == 'D') +#define HAS_EA_IX(A) ((A)[4] == 'X') +#define HAS_EA_AW(A) ((A)[5] == 'W') +#define HAS_EA_AL(A) ((A)[6] == 'L') +#define HAS_EA_PCDI(A) ((A)[7] == 'd') +#define HAS_EA_PCIX(A) ((A)[8] == 'x') +#define HAS_EA_I(A) ((A)[9] == 'I') + +enum +{ + EA_MODE_NONE, /* No special addressing mode */ + EA_MODE_AI, /* Address register indirect */ + EA_MODE_PI, /* Address register indirect with postincrement */ + EA_MODE_PI7, /* Address register 7 indirect with postincrement */ + EA_MODE_PD, /* Address register indirect with predecrement */ + EA_MODE_PD7, /* Address register 7 indirect with predecrement */ + EA_MODE_DI, /* Address register indirect with displacement */ + EA_MODE_IX, /* Address register indirect with index */ + EA_MODE_AW, /* Absolute word */ + EA_MODE_AL, /* Absolute long */ + EA_MODE_PCDI, /* Program counter indirect with displacement */ + EA_MODE_PCIX, /* Program counter indirect with index */ + EA_MODE_I /* Immediate */ +}; + + +/* Everything we need to know about an opcode */ +struct opcode_struct +{ + char name[MAX_NAME_LENGTH]; /* opcode handler name */ + unsigned char size; /* Size of operation */ + char spec_proc[MAX_SPEC_PROC_LENGTH]; /* Special processing mode */ + char spec_ea[MAX_SPEC_EA_LENGTH]; /* Specified effective addressing mode */ + unsigned char bits; /* Number of significant bits (used for sorting the table) */ + unsigned short op_mask; /* Mask to apply for matching an opcode to a handler */ + unsigned short op_match; /* Value to match after masking */ + char ea_allowed[EA_ALLOWED_LENGTH]; /* Effective addressing modes allowed */ + char cpu_mode[NUM_CPUS]; /* User or supervisor mode */ + char cpus[NUM_CPUS+1]; /* Allowed CPUs */ + unsigned char cycles[NUM_CPUS]; /* cycles for 000, 010, 020, 030, 040 */ +}; + + +/* All modifications necessary for a specific EA mode of an instruction */ +struct ea_info_struct +{ + const char* fname_add; + const char* ea_add; + unsigned int mask_add; + unsigned int match_add; +}; + + +/* Holds the body of a function */ +struct body_struct +{ + char body[MAX_BODY_LENGTH][MAX_LINE_LENGTH+1]; + int length; +}; + + +/* Holds a sequence of search / replace strings */ +struct replace_struct +{ + char replace[MAX_REPLACE_LENGTH][2][MAX_LINE_LENGTH+1]; + int length; +}; + + +/* Function Prototypes */ +static void ATTR_NORETURN error_exit(const char* fmt, ...) ATTR_PRINTF(1,2); +static void ATTR_NORETURN perror_exit(const char* fmt, ...) ATTR_PRINTF(1,2); +static int check_strsncpy(char* dst, char* src, int maxlength); +static int check_atoi(char* str, int *result); +static int skip_spaces(char* str); +static int num_bits(int value); +//int atoh(char* buff); +static int fgetline(char* buff, int nchars, FILE* file); +static int get_oper_cycles(opcode_struct* op, int ea_mode, int cpu_type); +static opcode_struct* find_opcode(char* name, int size, char* spec_proc, char* spec_ea); +//opcode_struct* find_illegal_opcode(void); +static int extract_opcode_info(char* src, char* name, int* size, char* spec_proc, char* spec_ea); +static void add_replace_string(replace_struct* replace, const char* search_str, const char* replace_str); +static void write_body(FILE* filep, body_struct* body, replace_struct* replace); +static void get_base_name(char* base_name, opcode_struct* op); +static void write_function_name(FILE* filep, char* base_name); +static void add_opcode_output_table_entry(opcode_struct* op, char* name); +static int DECL_SPEC compare_nof_true_bits(const void* aptr, const void* bptr); +static void print_opcode_output_table(FILE* filep); +static void write_table_entry(FILE* filep, opcode_struct* op); +static void set_opcode_struct(opcode_struct* src, opcode_struct* dst, int ea_mode); +static void generate_opcode_handler(FILE* filep, body_struct* body, replace_struct* replace, opcode_struct* opinfo, int ea_mode); +static void generate_opcode_ea_variants(FILE* filep, body_struct* body, replace_struct* replace, opcode_struct* op); +static void generate_opcode_cc_variants(FILE* filep, body_struct* body, replace_struct* replace, opcode_struct* op_in, int offset); +static void process_opcode_handlers(FILE* filep); +static void populate_table(void); +static void read_insert(char* insert); + + + +/* ======================================================================== */ +/* ================================= DATA ================================= */ +/* ======================================================================== */ + +/* Name of the input file */ +static char g_input_filename[M68K_MAX_PATH]; + +/* File handles */ +static FILE* g_input_file = NULL; +static FILE* g_prototype_file = NULL; +static FILE* g_table_file = NULL; + +static int g_num_functions = 0; /* Number of functions processed */ +static int g_num_primitives = 0; /* Number of function primitives read */ +static int g_line_number = 1; /* Current line number */ + +/* Opcode handler table */ +static opcode_struct g_opcode_input_table[MAX_OPCODE_INPUT_TABLE_LENGTH]; + +static opcode_struct g_opcode_output_table[MAX_OPCODE_OUTPUT_TABLE_LENGTH]; +static int g_opcode_output_table_length = 0; + +static const ea_info_struct g_ea_info_table[13] = +{/* fname ea mask match */ + {"", "", 0x00, 0x00}, /* EA_MODE_NONE */ + {"ai", "AY_AI", 0x38, 0x10}, /* EA_MODE_AI */ + {"pi", "AY_PI", 0x38, 0x18}, /* EA_MODE_PI */ + {"pi7", "A7_PI", 0x3f, 0x1f}, /* EA_MODE_PI7 */ + {"pd", "AY_PD", 0x38, 0x20}, /* EA_MODE_PD */ + {"pd7", "A7_PD", 0x3f, 0x27}, /* EA_MODE_PD7 */ + {"di", "AY_DI", 0x38, 0x28}, /* EA_MODE_DI */ + {"ix", "AY_IX", 0x38, 0x30}, /* EA_MODE_IX */ + {"aw", "AW", 0x3f, 0x38}, /* EA_MODE_AW */ + {"al", "AL", 0x3f, 0x39}, /* EA_MODE_AL */ + {"pcdi", "PCDI", 0x3f, 0x3a}, /* EA_MODE_PCDI */ + {"pcix", "PCIX", 0x3f, 0x3b}, /* EA_MODE_PCIX */ + {"i", "I", 0x3f, 0x3c}, /* EA_MODE_I */ +}; + + +static const char *const g_cc_table[16][2] = +{ + { "t", "T"}, /* 0000 */ + { "f", "F"}, /* 0001 */ + {"hi", "HI"}, /* 0010 */ + {"ls", "LS"}, /* 0011 */ + {"cc", "CC"}, /* 0100 */ + {"cs", "CS"}, /* 0101 */ + {"ne", "NE"}, /* 0110 */ + {"eq", "EQ"}, /* 0111 */ + {"vc", "VC"}, /* 1000 */ + {"vs", "VS"}, /* 1001 */ + {"pl", "PL"}, /* 1010 */ + {"mi", "MI"}, /* 1011 */ + {"ge", "GE"}, /* 1100 */ + {"lt", "LT"}, /* 1101 */ + {"gt", "GT"}, /* 1110 */ + {"le", "LE"}, /* 1111 */ +}; + +/* size to index translator (0 -> 0, 8 and 16 -> 1, 32 -> 2) */ +static const int g_size_select_table[33] = +{ + 0, /* unsized */ + 0, 0, 0, 0, 0, 0, 0, 1, /* 8 */ + 0, 0, 0, 0, 0, 0, 0, 1, /* 16 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2 /* 32 */ +}; + +/* Extra cycles required for certain EA modes */ +/* TODO: correct timings for 030, 040 */ +static const int g_ea_cycle_table[13][NUM_CPUS][3] = +{/* 000 010 020 030 040 CPU*/ + {{ 0, 0, 0}, { 0, 0, 0}, { 0, 0, 0}, { 0, 0, 0}, { 0, 0, 0}, { 0, 0, 0}}, /* EA_MODE_NONE */ + {{ 0, 4, 8}, { 0, 4, 8}, { 0, 4, 4}, { 0, 4, 4}, { 0, 4, 4}, { 0, 4, 4}}, /* EA_MODE_AI */ + {{ 0, 4, 8}, { 0, 4, 8}, { 0, 4, 4}, { 0, 4, 4}, { 0, 4, 4}, { 0, 4, 4}}, /* EA_MODE_PI */ + {{ 0, 4, 8}, { 0, 4, 8}, { 0, 4, 4}, { 0, 4, 4}, { 0, 4, 4}, { 0, 4, 4}}, /* EA_MODE_PI7 */ + {{ 0, 6, 10}, { 0, 6, 10}, { 0, 5, 5}, { 0, 5, 5}, { 0, 5, 5}, { 0, 5, 5}}, /* EA_MODE_PD */ + {{ 0, 6, 10}, { 0, 6, 10}, { 0, 5, 5}, { 0, 5, 5}, { 0, 5, 5}, { 0, 5, 5}}, /* EA_MODE_PD7 */ + {{ 0, 8, 12}, { 0, 8, 12}, { 0, 5, 5}, { 0, 5, 5}, { 0, 5, 5}, { 0, 5, 5}}, /* EA_MODE_DI */ + {{ 0, 10, 14}, { 0, 10, 14}, { 0, 7, 7}, { 0, 7, 7}, { 0, 7, 7}, { 0, 7, 7}}, /* EA_MODE_IX */ + {{ 0, 8, 12}, { 0, 8, 12}, { 0, 4, 4}, { 0, 4, 4}, { 0, 4, 4}, { 0, 4, 4}}, /* EA_MODE_AW */ + {{ 0, 12, 16}, { 0, 12, 16}, { 0, 4, 4}, { 0, 4, 4}, { 0, 4, 4}, { 0, 4, 4}}, /* EA_MODE_AL */ + {{ 0, 8, 12}, { 0, 8, 12}, { 0, 5, 5}, { 0, 5, 5}, { 0, 5, 5}, { 0, 5, 5}}, /* EA_MODE_PCDI */ + {{ 0, 10, 14}, { 0, 10, 14}, { 0, 7, 7}, { 0, 7, 7}, { 0, 7, 7}, { 0, 7, 7}}, /* EA_MODE_PCIX */ + {{ 0, 4, 8}, { 0, 4, 8}, { 0, 2, 4}, { 0, 2, 4}, { 0, 2, 4}, { 0, 2, 4}}, /* EA_MODE_I */ +}; + +/* Extra cycles for JMP instruction (000, 010) */ +static const int g_jmp_cycle_table[13] = +{ + 0, /* EA_MODE_NONE */ + 4, /* EA_MODE_AI */ + 0, /* EA_MODE_PI */ + 0, /* EA_MODE_PI7 */ + 0, /* EA_MODE_PD */ + 0, /* EA_MODE_PD7 */ + 6, /* EA_MODE_DI */ + 10, /* EA_MODE_IX */ + 6, /* EA_MODE_AW */ + 8, /* EA_MODE_AL */ + 6, /* EA_MODE_PCDI */ + 10, /* EA_MODE_PCIX */ + 0, /* EA_MODE_I */ +}; + +/* Extra cycles for JSR instruction (000, 010) */ +static const int g_jsr_cycle_table[13] = +{ + 0, /* EA_MODE_NONE */ + 4, /* EA_MODE_AI */ + 0, /* EA_MODE_PI */ + 0, /* EA_MODE_PI7 */ + 0, /* EA_MODE_PD */ + 0, /* EA_MODE_PD7 */ + 6, /* EA_MODE_DI */ + 10, /* EA_MODE_IX */ + 6, /* EA_MODE_AW */ + 8, /* EA_MODE_AL */ + 6, /* EA_MODE_PCDI */ + 10, /* EA_MODE_PCIX */ + 0, /* EA_MODE_I */ +}; + +/* Extra cycles for LEA instruction (000, 010) */ +static const int g_lea_cycle_table[13] = +{ + 0, /* EA_MODE_NONE */ + 4, /* EA_MODE_AI */ + 0, /* EA_MODE_PI */ + 0, /* EA_MODE_PI7 */ + 0, /* EA_MODE_PD */ + 0, /* EA_MODE_PD7 */ + 8, /* EA_MODE_DI */ + 12, /* EA_MODE_IX */ + 8, /* EA_MODE_AW */ + 12, /* EA_MODE_AL */ + 8, /* EA_MODE_PCDI */ + 12, /* EA_MODE_PCIX */ + 0, /* EA_MODE_I */ +}; + +/* Extra cycles for PEA instruction (000, 010) */ +static const int g_pea_cycle_table[13] = +{ + 0, /* EA_MODE_NONE */ + 6, /* EA_MODE_AI */ + 0, /* EA_MODE_PI */ + 0, /* EA_MODE_PI7 */ + 0, /* EA_MODE_PD */ + 0, /* EA_MODE_PD7 */ + 10, /* EA_MODE_DI */ + 14, /* EA_MODE_IX */ + 10, /* EA_MODE_AW */ + 14, /* EA_MODE_AL */ + 10, /* EA_MODE_PCDI */ + 14, /* EA_MODE_PCIX */ + 0, /* EA_MODE_I */ +}; + +/* Extra cycles for MOVEM instruction (000, 010) */ +static const int g_movem_cycle_table[13] = +{ + 0, /* EA_MODE_NONE */ + 0, /* EA_MODE_AI */ + 0, /* EA_MODE_PI */ + 0, /* EA_MODE_PI7 */ + 0, /* EA_MODE_PD */ + 0, /* EA_MODE_PD7 */ + 4, /* EA_MODE_DI */ + 6, /* EA_MODE_IX */ + 4, /* EA_MODE_AW */ + 8, /* EA_MODE_AL */ + 0, /* EA_MODE_PCDI */ + 0, /* EA_MODE_PCIX */ + 0, /* EA_MODE_I */ +}; + +/* Extra cycles for MOVES instruction (010) */ +static const int g_moves_cycle_table[13][3] = +{ + { 0, 0, 0}, /* EA_MODE_NONE */ + { 0, 4, 6}, /* EA_MODE_AI */ + { 0, 4, 6}, /* EA_MODE_PI */ + { 0, 4, 6}, /* EA_MODE_PI7 */ + { 0, 6, 12}, /* EA_MODE_PD */ + { 0, 6, 12}, /* EA_MODE_PD7 */ + { 0, 12, 16}, /* EA_MODE_DI */ + { 0, 16, 20}, /* EA_MODE_IX */ + { 0, 12, 16}, /* EA_MODE_AW */ + { 0, 16, 20}, /* EA_MODE_AL */ + { 0, 0, 0}, /* EA_MODE_PCDI */ + { 0, 0, 0}, /* EA_MODE_PCIX */ + { 0, 0, 0}, /* EA_MODE_I */ +}; + +/* Extra cycles for CLR instruction (010) */ +static const int g_clr_cycle_table[13][3] = +{ + { 0, 0, 0}, /* EA_MODE_NONE */ + { 0, 4, 6}, /* EA_MODE_AI */ + { 0, 4, 6}, /* EA_MODE_PI */ + { 0, 4, 6}, /* EA_MODE_PI7 */ + { 0, 6, 8}, /* EA_MODE_PD */ + { 0, 6, 8}, /* EA_MODE_PD7 */ + { 0, 8, 10}, /* EA_MODE_DI */ + { 0, 10, 14}, /* EA_MODE_IX */ + { 0, 8, 10}, /* EA_MODE_AW */ + { 0, 10, 14}, /* EA_MODE_AL */ + { 0, 0, 0}, /* EA_MODE_PCDI */ + { 0, 0, 0}, /* EA_MODE_PCIX */ + { 0, 0, 0}, /* EA_MODE_I */ +}; + + + +/* ======================================================================== */ +/* =========================== UTILITY FUNCTIONS ========================== */ +/* ======================================================================== */ + +/* Print an error message and exit with status error */ +static void error_exit(const char* fmt, ...) +{ + va_list args; + fprintf(stderr, "In %s, near or on line %d:\n\t", g_input_filename, g_line_number); + va_start(args, fmt); + vfprintf(stderr, fmt, args); + va_end(args); + fprintf(stderr, "\n"); + + if(g_prototype_file) fclose(g_prototype_file); + if(g_table_file) fclose(g_table_file); + if(g_input_file) fclose(g_input_file); + + exit(EXIT_FAILURE); +} + +/* Print an error message, call perror(), and exit with status error */ +static void perror_exit(const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + vfprintf(stderr, fmt, args); + va_end(args); + perror(""); + + if(g_prototype_file) fclose(g_prototype_file); + if(g_table_file) fclose(g_table_file); + if(g_input_file) fclose(g_input_file); + + exit(EXIT_FAILURE); +} + + +/* copy until 0 or space and exit with error if we read too far */ +static int check_strsncpy(char* dst, char* src, int maxlength) +{ + char* p = dst; + while(*src && *src != ' ') + { + *p++ = *src++; + if(p - dst > maxlength) + error_exit("Field too long"); + } + *p = 0; + return p - dst; +} + +/* copy until 0 or specified character and exit with error if we read too far */ +static int check_strcncpy(char* dst, char* src, char delim, int maxlength) +{ + char* p = dst; + while(*src && *src != delim) + { + *p++ = *src++; + if(p - dst > maxlength) + error_exit("Field too long"); + } + *p = 0; + return p - dst; +} + +/* convert ascii to integer and exit with error if we find invalid data */ +static int check_atoi(char* str, int *result) +{ + int accum = 0; + char* p = str; + while(*p >= '0' && *p <= '9') + { + accum *= 10; + accum += *p++ - '0'; + } + if(*p != ' ' && *p != 0) + error_exit("Malformed integer value (%c)", *p); + *result = accum; + return p - str; +} + +/* Skip past spaces in a string */ +static int skip_spaces(char* str) +{ + char* p = str; + + while(*p == ' ') + p++; + + return p - str; +} + +/* Count the number of set bits in a value */ +static int num_bits(int value) +{ + value = ((value & 0xaaaa) >> 1) + (value & 0x5555); + value = ((value & 0xcccc) >> 2) + (value & 0x3333); + value = ((value & 0xf0f0) >> 4) + (value & 0x0f0f); + value = ((value & 0xff00) >> 8) + (value & 0x00ff); + return value; +} + +#ifdef UNUSED_FUNCTION +/* Convert a hex value written in ASCII */ +int atoh(char* buff) +{ + int accum = 0; + + for(;;buff++) + { + if(*buff >= '0' && *buff <= '9') + { + accum <<= 4; + accum += *buff - '0'; + } + else if(*buff >= 'a' && *buff <= 'f') + { + accum <<= 4; + accum += *buff - 'a' + 10; + } + else break; + } + return accum; +} +#endif + +/* Get a line of text from a file, discarding any end-of-line characters */ +static int fgetline(char* buff, int nchars, FILE* file) +{ + int length; + + if(fgets(buff, nchars, file) == NULL) + return -1; + if(buff[0] == '\r') + memmove(buff, buff + 1, nchars - 1); + + length = strlen(buff); + while(length && (buff[length-1] == '\r' || buff[length-1] == '\n')) + length--; + buff[length] = 0; + g_line_number++; + + return length; +} + + + +/* ======================================================================== */ +/* =========================== HELPER FUNCTIONS =========================== */ +/* ======================================================================== */ + +/* Calculate the number of cycles an opcode requires */ +static int get_oper_cycles(opcode_struct* op, int ea_mode, int cpu_type) +{ + int size = g_size_select_table[op->size]; + + if(op->cpus[cpu_type] == '.') + return 255; + + if(cpu_type < CPU_TYPE_020) + { + if(cpu_type == CPU_TYPE_010) + { + if(strcmp(op->name, "moves") == 0) + return op->cycles[cpu_type] + g_moves_cycle_table[ea_mode][size]; + if(strcmp(op->name, "clr") == 0) + return op->cycles[cpu_type] + g_clr_cycle_table[ea_mode][size]; + } + + /* ASG: added these cases -- immediate modes take 2 extra cycles here */ + /* SV: but only when operating on long, and also on register direct mode */ + if(cpu_type == CPU_TYPE_000 && (ea_mode == EA_MODE_I || ea_mode == EA_MODE_NONE) && op->size == 32 && + ((strcmp(op->name, "add") == 0 && strcmp(op->spec_proc, "er") == 0) || + strcmp(op->name, "adda") == 0 || + (strcmp(op->name, "and") == 0 && strcmp(op->spec_proc, "er") == 0) || + (strcmp(op->name, "or") == 0 && strcmp(op->spec_proc, "er") == 0) || + (strcmp(op->name, "sub") == 0 && strcmp(op->spec_proc, "er") == 0) || + strcmp(op->name, "suba") == 0)) + return op->cycles[cpu_type] + g_ea_cycle_table[ea_mode][cpu_type][size] + 2; + + if(strcmp(op->name, "jmp") == 0) + return op->cycles[cpu_type] + g_jmp_cycle_table[ea_mode]; + if(strcmp(op->name, "jsr") == 0) + return op->cycles[cpu_type] + g_jsr_cycle_table[ea_mode]; + if(strcmp(op->name, "lea") == 0) + return op->cycles[cpu_type] + g_lea_cycle_table[ea_mode]; + if(strcmp(op->name, "pea") == 0) + return op->cycles[cpu_type] + g_pea_cycle_table[ea_mode]; + if(strcmp(op->name, "movem") == 0) + return op->cycles[cpu_type] + g_movem_cycle_table[ea_mode]; + } + return op->cycles[cpu_type] + g_ea_cycle_table[ea_mode][cpu_type][size]; +} + +/* Find an opcode in the opcode handler list */ +static opcode_struct* find_opcode(char* name, int size, char* spec_proc, char* spec_ea) +{ + opcode_struct* op; + + + for(op = g_opcode_input_table;op->name != NULL;op++) + { + if( strcmp(name, op->name) == 0 && + (size == op->size) && + strcmp(spec_proc, op->spec_proc) == 0 && + strcmp(spec_ea, op->spec_ea) == 0) + return op; + } + return NULL; +} + +#ifdef UNUSED_FUNCTION +/* Specifically find the illegal opcode in the list */ +opcode_struct* find_illegal_opcode(void) +{ + opcode_struct* op; + + for(op = g_opcode_input_table;op->name != NULL;op++) + { + if(strcmp(op->name, "illegal") == 0) + return op; + } + return NULL; +} +#endif + +/* Parse an opcode handler name */ +static int extract_opcode_info(char* src, char* name, int* size, char* spec_proc, char* spec_ea) +{ + char* ptr = strstr(src, ID_OPHANDLER_NAME); + + if(ptr == NULL) + return 0; + + ptr += strlen(ID_OPHANDLER_NAME) + 1; + + ptr += check_strcncpy(name, ptr, ',', MAX_NAME_LENGTH); + if(*ptr != ',') return 0; + ptr++; + ptr += skip_spaces(ptr); + + *size = atoi(ptr); + ptr = strstr(ptr, ","); + if(ptr == NULL) return 0; + ptr++; + ptr += skip_spaces(ptr); + + ptr += check_strcncpy(spec_proc, ptr, ',', MAX_SPEC_PROC_LENGTH); + if(*ptr != ',') return 0; + ptr++; + ptr += skip_spaces(ptr); + + ptr += check_strcncpy(spec_ea, ptr, ')', MAX_SPEC_EA_LENGTH); + if(*ptr != ')') return 0; + ptr++; + ptr += skip_spaces(ptr); + + return 1; +} + + +/* Add a search/replace pair to a replace structure */ +static void add_replace_string(replace_struct* replace, const char* search_str, const char* replace_str) +{ + if(replace->length >= MAX_REPLACE_LENGTH) + error_exit("overflow in replace structure"); + + strcpy(replace->replace[replace->length][0], search_str); + strcpy(replace->replace[replace->length++][1], replace_str); +} + +/* Write a function body while replacing any selected strings */ +static void write_body(FILE* filep, body_struct* body, replace_struct* replace) +{ + int i; + int j; + char* ptr; + char output[MAX_LINE_LENGTH+1]; + char temp_buff[MAX_LINE_LENGTH+1]; + int found; + + for(i=0;ilength;i++) + { + strcpy(output, body->body[i]); + /* Check for the base directive header */ + if(strstr(output, ID_BASE) != NULL) + { + /* Search for any text we need to replace */ + found = 0; + for(j=0;jlength;j++) + { + ptr = strstr(output, replace->replace[j][0]); + if(ptr) + { + /* We found something to replace */ + found = 1; + strcpy(temp_buff, ptr+strlen(replace->replace[j][0])); + strcpy(ptr, replace->replace[j][1]); + strcat(ptr, temp_buff); + } + } + /* Found a directive with no matching replace string */ + if(!found) + error_exit("Unknown " ID_BASE " directive [%s]", output); + } + fprintf(filep, "%s\n", output); + } + fprintf(filep, "\n\n"); +} + +/* Generate a base function name from an opcode struct */ +static void get_base_name(char* base_name, opcode_struct* op) +{ + sprintf(base_name, "m68k_op_%s", op->name); + if(op->size > 0) + sprintf(base_name+strlen(base_name), "_%d", op->size); + if(strcmp(op->spec_proc, UNSPECIFIED) != 0) + sprintf(base_name+strlen(base_name), "_%s", op->spec_proc); + if(strcmp(op->spec_ea, UNSPECIFIED) != 0) + sprintf(base_name+strlen(base_name), "_%s", op->spec_ea); +} + +/* Write the name of an opcode handler function */ +static void write_function_name(FILE* filep, char* base_name) +{ + fprintf(filep, "void m68000_base_device_ops::%s(m68000_base_device* mc68kcpu)\n", base_name); + fprintf(g_prototype_file, "static void %s(m68000_base_device* mc68kcpu);\n", base_name); +} + +static void add_opcode_output_table_entry(opcode_struct* op, char* name) +{ + opcode_struct* ptr; + if(g_opcode_output_table_length > MAX_OPCODE_OUTPUT_TABLE_LENGTH) + error_exit("Opcode output table overflow"); + + ptr = g_opcode_output_table + g_opcode_output_table_length++; + + *ptr = *op; + + sprintf( ptr->name, "m68000_base_device_ops::%s", name); + ptr->bits = num_bits(ptr->op_mask); +} + +/* + * Comparison function for qsort() + * For entries with an equal number of set bits in + * the mask compare the match values + */ +static int DECL_SPEC compare_nof_true_bits(const void* aptr, const void* bptr) +{ + const opcode_struct *a = (const opcode_struct *)aptr, *b = (const opcode_struct *)bptr; + if(a->bits != b->bits) + return a->bits - b->bits; + if(a->op_mask != b->op_mask) + return a->op_mask - b->op_mask; + return a->op_match - b->op_match; +} + +static void print_opcode_output_table(FILE* filep) +{ + int i; + qsort((void *)g_opcode_output_table, g_opcode_output_table_length, sizeof(g_opcode_output_table[0]), compare_nof_true_bits); + + for(i=0;iname, op->op_mask, op->op_match); + + for(i=0;icycles[i]); + if(i < NUM_CPUS-1) + fprintf(filep, ", "); + } + + fprintf(filep, "}},\n"); +} + +/* Fill out an opcode struct with a specific addressing mode of the source opcode struct */ +static void set_opcode_struct(opcode_struct* src, opcode_struct* dst, int ea_mode) +{ + int i; + + *dst = *src; + + for(i=0;icycles[i] = get_oper_cycles(dst, ea_mode, i); + if(strcmp(dst->spec_ea, UNSPECIFIED) == 0 && ea_mode != EA_MODE_NONE) + sprintf(dst->spec_ea, "%s", g_ea_info_table[ea_mode].fname_add); + dst->op_mask |= g_ea_info_table[ea_mode].mask_add; + dst->op_match |= g_ea_info_table[ea_mode].match_add; +} + + +/* Generate a final opcode handler from the provided data */ +static void generate_opcode_handler(FILE* filep, body_struct* body, replace_struct* replace, opcode_struct* opinfo, int ea_mode) +{ + char str[MAX_LINE_LENGTH+1]; + opcode_struct* op = (opcode_struct *)malloc(sizeof(opcode_struct)); + + /* Set the opcode structure and write the tables, prototypes, etc */ + set_opcode_struct(opinfo, op, ea_mode); + get_base_name(str, op); + add_opcode_output_table_entry(op, str); + write_function_name(filep, str); + + /* Add any replace strings needed */ + if(ea_mode != EA_MODE_NONE) + { + sprintf(str, "EA_%s_8(mc68kcpu)", g_ea_info_table[ea_mode].ea_add); + add_replace_string(replace, ID_OPHANDLER_EA_AY_8, str); + sprintf(str, "EA_%s_16(mc68kcpu)", g_ea_info_table[ea_mode].ea_add); + add_replace_string(replace, ID_OPHANDLER_EA_AY_16, str); + sprintf(str, "EA_%s_32(mc68kcpu)", g_ea_info_table[ea_mode].ea_add); + add_replace_string(replace, ID_OPHANDLER_EA_AY_32, str); + sprintf(str, "OPER_%s_8(mc68kcpu)", g_ea_info_table[ea_mode].ea_add); + add_replace_string(replace, ID_OPHANDLER_OPER_AY_8, str); + sprintf(str, "OPER_%s_16(mc68kcpu)", g_ea_info_table[ea_mode].ea_add); + add_replace_string(replace, ID_OPHANDLER_OPER_AY_16, str); + sprintf(str, "OPER_%s_32(mc68kcpu)", g_ea_info_table[ea_mode].ea_add); + add_replace_string(replace, ID_OPHANDLER_OPER_AY_32, str); + } + + /* Now write the function body with the selected replace strings */ + write_body(filep, body, replace); + g_num_functions++; + free(op); +} + +/* Generate opcode variants based on available addressing modes */ +static void generate_opcode_ea_variants(FILE* filep, body_struct* body, replace_struct* replace, opcode_struct* op) +{ + int old_length = replace->length; + + /* No ea modes available for this opcode */ + if(HAS_NO_EA_MODE(op->ea_allowed)) + { + generate_opcode_handler(filep, body, replace, op, EA_MODE_NONE); + return; + } + + /* Check for and create specific opcodes for each available addressing mode */ + if(HAS_EA_AI(op->ea_allowed)) + generate_opcode_handler(filep, body, replace, op, EA_MODE_AI); + replace->length = old_length; + if(HAS_EA_PI(op->ea_allowed)) + { + generate_opcode_handler(filep, body, replace, op, EA_MODE_PI); + replace->length = old_length; + if(op->size == 8) + generate_opcode_handler(filep, body, replace, op, EA_MODE_PI7); + } + replace->length = old_length; + if(HAS_EA_PD(op->ea_allowed)) + { + generate_opcode_handler(filep, body, replace, op, EA_MODE_PD); + replace->length = old_length; + if(op->size == 8) + generate_opcode_handler(filep, body, replace, op, EA_MODE_PD7); + } + replace->length = old_length; + if(HAS_EA_DI(op->ea_allowed)) + generate_opcode_handler(filep, body, replace, op, EA_MODE_DI); + replace->length = old_length; + if(HAS_EA_IX(op->ea_allowed)) + generate_opcode_handler(filep, body, replace, op, EA_MODE_IX); + replace->length = old_length; + if(HAS_EA_AW(op->ea_allowed)) + generate_opcode_handler(filep, body, replace, op, EA_MODE_AW); + replace->length = old_length; + if(HAS_EA_AL(op->ea_allowed)) + generate_opcode_handler(filep, body, replace, op, EA_MODE_AL); + replace->length = old_length; + if(HAS_EA_PCDI(op->ea_allowed)) + generate_opcode_handler(filep, body, replace, op, EA_MODE_PCDI); + replace->length = old_length; + if(HAS_EA_PCIX(op->ea_allowed)) + generate_opcode_handler(filep, body, replace, op, EA_MODE_PCIX); + replace->length = old_length; + if(HAS_EA_I(op->ea_allowed)) + generate_opcode_handler(filep, body, replace, op, EA_MODE_I); + replace->length = old_length; +} + +/* Generate variants of condition code opcodes */ +static void generate_opcode_cc_variants(FILE* filep, body_struct* body, replace_struct* replace, opcode_struct* op_in, int offset) +{ + char repl[32]; + char replnot[32]; + int i; + int old_length = replace->length; + opcode_struct* op = (opcode_struct *)malloc(sizeof(opcode_struct)); + + *op = *op_in; + + op->op_mask |= 0x0f00; + + /* Do all condition codes except t and f */ + for(i=2;i<16;i++) + { + /* Add replace strings for this condition code */ + sprintf(repl, "COND_%s(mc68kcpu)", g_cc_table[i][1]); + sprintf(replnot, "COND_NOT_%s(mc68kcpu)", g_cc_table[i][1]); + + add_replace_string(replace, ID_OPHANDLER_CC, repl); + add_replace_string(replace, ID_OPHANDLER_NOT_CC, replnot); + + /* Set the new opcode info */ + strcpy(op->name+offset, g_cc_table[i][0]); + + op->op_match = (op->op_match & 0xf0ff) | (i<<8); + + /* Generate all opcode variants for this modified opcode */ + generate_opcode_ea_variants(filep, body, replace, op); + /* Remove the above replace strings */ + replace->length = old_length; + } + free(op); +} + +/* Process the opcode handlers section of the input file */ +static void process_opcode_handlers(FILE* filep) +{ + FILE* input_file = g_input_file; + char func_name[MAX_LINE_LENGTH+1]; + char oper_name[MAX_LINE_LENGTH+1]; + int oper_size = 0; + char oper_spec_proc[MAX_LINE_LENGTH+1]; + char oper_spec_ea[MAX_LINE_LENGTH+1]; + opcode_struct* opinfo; + replace_struct* replace = (replace_struct*)malloc(sizeof(replace_struct)); + body_struct* body = (body_struct*)malloc(sizeof(body_struct)); + + for(;;) + { + /* Find the first line of the function */ + func_name[0] = 0; + while(strstr(func_name, ID_OPHANDLER_NAME) == NULL) + { + if(strcmp(func_name, ID_INPUT_SEPARATOR) == 0) + { + free(replace); + free(body); + return; /* all done */ + } + if(fgetline(func_name, MAX_LINE_LENGTH, input_file) < 0) + error_exit("Premature end of file when getting function name"); + } + /* Get the rest of the function */ + for(body->length=0;;body->length++) + { + if(body->length > MAX_BODY_LENGTH) + error_exit("Function too long"); + + if(fgetline(body->body[body->length], MAX_LINE_LENGTH, input_file) < 0) + error_exit("Premature end of file when getting function body"); + + if(body->body[body->length][0] == '}') + { + body->length++; + break; + } + } + + g_num_primitives++; + + /* Extract the function name information */ + if(!extract_opcode_info(func_name, oper_name, &oper_size, oper_spec_proc, oper_spec_ea)) + error_exit("Invalid " ID_OPHANDLER_NAME " format"); + + /* Find the corresponding table entry */ + opinfo = find_opcode(oper_name, oper_size, oper_spec_proc, oper_spec_ea); + if(opinfo == NULL) + error_exit("Unable to find matching table entry for %s", func_name); + + replace->length = 0; + + /* Generate opcode variants */ + if(strcmp(opinfo->name, "bcc") == 0 || strcmp(opinfo->name, "scc") == 0) + generate_opcode_cc_variants(filep, body, replace, opinfo, 1); + else if(strcmp(opinfo->name, "dbcc") == 0) + generate_opcode_cc_variants(filep, body, replace, opinfo, 2); + else if(strcmp(opinfo->name, "trapcc") == 0) + generate_opcode_cc_variants(filep, body, replace, opinfo, 4); + else + generate_opcode_ea_variants(filep, body, replace, opinfo); + } + + free(replace); + free(body); +} + + +/* Populate the opcode handler table from the input file */ +static void populate_table(void) +{ + char* ptr; + char bitpattern[17]; + opcode_struct* op; + char buff[MAX_LINE_LENGTH]; + int i; + int temp; + + buff[0] = 0; + + /* Find the start of the table */ + while (strncmp(buff, ID_TABLE_START, strlen(ID_TABLE_START)) != 0) + { + if(fgetline(buff, MAX_LINE_LENGTH, g_input_file) < 0) + error_exit("(table_start) Premature EOF while reading table"); + } + + /* Process the entire table */ + for(op = g_opcode_input_table;;op++) + { + if(fgetline(buff, MAX_LINE_LENGTH, g_input_file) < 0) + error_exit("(inline) Premature EOF while reading table"); + if(strlen(buff) == 0) + continue; + /* We finish when we find an input separator */ + if(strcmp(buff, ID_INPUT_SEPARATOR) == 0) + break; + + /* Extract the info from the table */ + ptr = buff; + + + /* Name */ + ptr += skip_spaces(ptr); + ptr += check_strsncpy(op->name, ptr, MAX_NAME_LENGTH); + + /* Size */ + ptr += skip_spaces(ptr); + ptr += check_atoi(ptr, &temp); + op->size = (unsigned char)temp; + + /* Special processing */ + ptr += skip_spaces(ptr); + ptr += check_strsncpy(op->spec_proc, ptr, MAX_SPEC_PROC_LENGTH); + + /* Specified EA Mode */ + ptr += skip_spaces(ptr); + ptr += check_strsncpy(op->spec_ea, ptr, MAX_SPEC_EA_LENGTH); + + /* Bit Pattern (more processing later) */ + ptr += skip_spaces(ptr); + ptr += check_strsncpy(bitpattern, ptr, 17); + + /* Allowed Addressing Mode List */ + ptr += skip_spaces(ptr); + ptr += check_strsncpy(op->ea_allowed, ptr, EA_ALLOWED_LENGTH); + + /* CPU operating mode (U = user or supervisor, S = supervisor only */ + ptr += skip_spaces(ptr); + for(i=0;icpu_mode[i] = *ptr++; + ptr += skip_spaces(ptr); + } + + /* Allowed CPUs for this instruction */ + for(i=0;icpus[i] = UNSPECIFIED_CH; + op->cycles[i] = 0; + ptr++; + } + else + { + op->cpus[i] = '0' + i; + ptr += check_atoi(ptr, &temp); + op->cycles[i] = (unsigned char)temp; + } + } + + /* generate mask and match from bitpattern */ + op->op_mask = 0; + op->op_match = 0; + for(i=0;i<16;i++) + { + op->op_mask |= (bitpattern[i] != '.') << (15-i); + op->op_match |= (bitpattern[i] == '1') << (15-i); + } + } + /* Terminate the list */ + op->name[0] = 0; +} + +/* Read a header or footer insert from the input file */ +static void read_insert(char* insert) +{ + char* ptr = insert; + char* overflow = insert + MAX_INSERT_LENGTH - MAX_LINE_LENGTH; + int length; + char* first_blank = NULL; + + first_blank = NULL; + + /* Skip any leading blank lines */ + for(length = 0;length == 0;length = fgetline(ptr, MAX_LINE_LENGTH, g_input_file)) + if(ptr >= overflow) + error_exit("Buffer overflow reading inserts"); + if(length < 0) + error_exit("Premature EOF while reading inserts"); + + /* Advance and append newline */ + ptr += length; + strcpy(ptr++, "\n"); + + /* Read until next separator */ + for(;;) + { + /* Read a new line */ + if(ptr >= overflow) + error_exit("Buffer overflow reading inserts"); + if((length = fgetline(ptr, MAX_LINE_LENGTH, g_input_file)) < 0) + error_exit("Premature EOF while reading inserts"); + + /* Stop if we read a separator */ + if(strcmp(ptr, ID_INPUT_SEPARATOR) == 0) + break; + + /* keep track in case there are trailing blanks */ + if(length == 0) + { + if(first_blank == NULL) + first_blank = ptr; + } + else + first_blank = NULL; + + /* Advance and append newline */ + ptr += length; + strcpy(ptr++, "\n"); + } + + /* kill any trailing blank lines */ + if(first_blank) + ptr = first_blank; + *ptr++ = 0; +} + + + +/* ======================================================================== */ +/* ============================= MAIN FUNCTION ============================ */ +/* ======================================================================== */ + +int main(int argc, char *argv[]) +{ + /* File stuff */ + char output_path[M68K_MAX_DIR] = ""; + char filename[M68K_MAX_PATH]; + /* Section identifier */ + char section_id[MAX_LINE_LENGTH+1]; + /* Inserts */ + char temp_insert[MAX_INSERT_LENGTH+1]; + char prototype_footer_insert[MAX_INSERT_LENGTH+1]; + char table_header_insert[MAX_INSERT_LENGTH+1]; + char table_footer_insert[MAX_INSERT_LENGTH+1]; + char ophandler_header_insert[MAX_INSERT_LENGTH+1]; + char ophandler_footer_insert[MAX_INSERT_LENGTH+1]; + /* Flags if we've processed certain parts already */ + int prototype_header_read = 0; + int prototype_footer_read = 0; + int table_header_read = 0; + int table_footer_read = 0; + int ophandler_header_read = 0; + int ophandler_footer_read = 0; + int table_body_read = 0; + int ophandler_body_read = 0; + + printf("\n\tMusashi v%s 680x0, CPU32, and ColdFire emulator\n", g_version); + printf("\tCopyright Karl Stenerud and the MAME team.\n\n"); + + /* Check if output path and source for the input file are given */ + if(argc > 1) + { + char *ptr; + strcpy(output_path, argv[1]); + + for(ptr = strchr(output_path, '\\'); ptr; ptr = strchr(ptr, '\\')) + *ptr = '/'; + } + + strcpy(g_input_filename, (argc > 2) ? argv[2] : FILENAME_INPUT); + + /* Open the files we need */ + sprintf(filename, "%s/%s", output_path, FILENAME_PROTOTYPE); + if((g_prototype_file = fopen(filename, "wt")) == NULL) + perror_exit("Unable to create prototype file (%s)\n", filename); + + sprintf(filename, "%s/%s", output_path, FILENAME_TABLE); + if((g_table_file = fopen(filename, "wt")) == NULL) + perror_exit("Unable to create table file (%s)\n", filename); + + if((g_input_file=fopen(g_input_filename, "rt")) == NULL) + perror_exit("can't open %s for input", g_input_filename); + + + /* Get to the first section of the input file */ + section_id[0] = 0; + while(strcmp(section_id, ID_INPUT_SEPARATOR) != 0) + if(fgetline(section_id, MAX_LINE_LENGTH, g_input_file) < 0) + error_exit("Premature EOF while reading input file"); + + /* Now process all sections */ + for(;;) + { + if(fgetline(section_id, MAX_LINE_LENGTH, g_input_file) < 0) + error_exit("Premature EOF while reading input file"); + if(strcmp(section_id, ID_PROTOTYPE_HEADER) == 0) + { + if(prototype_header_read) + error_exit("Duplicate prototype header"); + read_insert(temp_insert); + fprintf(g_prototype_file, "%s\n\n", temp_insert); + prototype_header_read = 1; + } + else if(strcmp(section_id, ID_TABLE_HEADER) == 0) + { + if(table_header_read) + error_exit("Duplicate table header"); + read_insert(table_header_insert); + table_header_read = 1; + } + else if(strcmp(section_id, ID_OPHANDLER_HEADER) == 0) + { + if(ophandler_header_read) + error_exit("Duplicate opcode handler header"); + read_insert(ophandler_header_insert); + ophandler_header_read = 1; + } + else if(strcmp(section_id, ID_PROTOTYPE_FOOTER) == 0) + { + if(prototype_footer_read) + error_exit("Duplicate prototype footer"); + read_insert(prototype_footer_insert); + prototype_footer_read = 1; + } + else if(strcmp(section_id, ID_TABLE_FOOTER) == 0) + { + if(table_footer_read) + error_exit("Duplicate table footer"); + read_insert(table_footer_insert); + table_footer_read = 1; + } + else if(strcmp(section_id, ID_OPHANDLER_FOOTER) == 0) + { + if(ophandler_footer_read) + error_exit("Duplicate opcode handler footer"); + read_insert(ophandler_footer_insert); + ophandler_footer_read = 1; + } + else if(strcmp(section_id, ID_TABLE_BODY) == 0) + { + if(!prototype_header_read) + error_exit("Table body encountered before prototype header"); + if(!table_header_read) + error_exit("Table body encountered before table header"); + if(!ophandler_header_read) + error_exit("Table body encountered before opcode handler header"); + + if(table_body_read) + error_exit("Duplicate table body"); + + populate_table(); + table_body_read = 1; + } + else if(strcmp(section_id, ID_OPHANDLER_BODY) == 0) + { + if(!prototype_header_read) + error_exit("Opcode handlers encountered before prototype header"); + if(!table_header_read) + error_exit("Opcode handlers encountered before table header"); + if(!ophandler_header_read) + error_exit("Opcode handlers encountered before opcode handler header"); + if(!table_body_read) + error_exit("Opcode handlers encountered before table body"); + + if(ophandler_body_read) + error_exit("Duplicate opcode handler section"); + + fprintf(g_table_file, "%s\n\n", ophandler_header_insert); + fprintf(g_prototype_file, "#ifdef OPCODE_PROTOTYPES\n\n"); + process_opcode_handlers(g_table_file); + fprintf(g_prototype_file, "#else\n"); + fprintf(g_table_file, "%s\n\n", ophandler_footer_insert); + + ophandler_body_read = 1; + } + else if(strcmp(section_id, ID_END) == 0) + { + /* End of input file. Do a sanity check and then write footers */ + if(!prototype_header_read) + error_exit("Missing prototype header"); + if(!prototype_footer_read) + error_exit("Missing prototype footer"); + if(!table_header_read) + error_exit("Missing table header"); + if(!table_footer_read) + error_exit("Missing table footer"); + if(!table_body_read) + error_exit("Missing table body"); + if(!ophandler_header_read) + error_exit("Missing opcode handler header"); + if(!ophandler_footer_read) + error_exit("Missing opcode handler footer"); + if(!ophandler_body_read) + error_exit("Missing opcode handler body"); + + fprintf(g_table_file, "%s\n\n", table_header_insert); + print_opcode_output_table(g_table_file); + fprintf(g_table_file, "%s\n\n", table_footer_insert); + + fprintf(g_prototype_file, "%s\n\n", prototype_footer_insert); + fprintf(g_prototype_file, "#endif\n"); + + break; + } + else + { + error_exit("Unknown section identifier: %s", section_id); + } + } + + /* Close all files and exit */ + fclose(g_prototype_file); + fclose(g_table_file); + fclose(g_input_file); + + printf("Generated %d opcode handlers from %d primitives\n", g_num_functions, g_num_primitives); + + return 0; +} + + + +/* ======================================================================== */ +/* ============================== END OF FILE ============================= */ +/* ======================================================================== */ diff --git a/src/devices/cpu/m68000/m68kmmu.h b/src/devices/cpu/m68000/m68kmmu.h new file mode 100644 index 00000000000..342fc8ea981 --- /dev/null +++ b/src/devices/cpu/m68000/m68kmmu.h @@ -0,0 +1,1148 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont, Hans Ostermeyer +/* + m68kmmu.h - PMMU implementation for 68851/68030/68040 + HMMU implementation for 68020 (II and LC variants) + + By R. Belmont and Hans Ostermeyer +*/ + +// MMU status register bit definitions + +#define M68K_MMU_SR_BUS_ERROR 0x8000 +#define M68K_MMU_SR_SUPERVISOR_ONLY 0x2000 +#define M68K_MMU_SR_WRITE_PROTECT 0x0800 +#define M68K_MMU_SR_INVALID 0x0400 +#define M68K_MMU_SR_MODIFIED 0x0200 +#define M68K_MMU_SR_LEVEL_0 0x0000 +#define M68K_MMU_SR_LEVEL_1 0x0001 +#define M68K_MMU_SR_LEVEL_2 0x0002 +#define M68K_MMU_SR_LEVEL_3 0x0003 + +// MMU translation table descriptor field definitions + +#define M68K_MMU_DF_DT 0x0003 +#define M68K_MMU_DF_DT0 0x0000 +#define M68K_MMU_DF_DT1 0x0001 +#define M68K_MMU_DF_DT2 0x0002 +#define M68K_MMU_DF_DT3 0x0003 +#define M68K_MMU_DF_WP 0x0004 +#define M68K_MMU_DF_USED 0x0008 +#define M68K_MMU_DF_MODIFIED 0x0010 +#define M68K_MMU_DF_CI 0x0040 +#define M68K_MMU_DF_SUPERVISOR 0x0100 + +// MMU ATC Fields + +#define M68K_MMU_ATC_BUSERROR 0x08000000 +#define M68K_MMU_ATC_CACHE_IN 0x04000000 +#define M68K_MMU_ATC_WRITE_PR 0x02000000 +#define M68K_MMU_ATC_MODIFIED 0x01000000 +#define M68K_MMU_ATC_MASK 0x00ffffff +#define M68K_MMU_ATC_SHIFT 8 +#define M68K_MMU_ATC_VALID 0x08000000 + +// MMU Translation Control register +#define M68K_MMU_TC_SRE 0x02000000 + +/* decodes the effective address */ +static UINT32 DECODE_EA_32(m68000_base_device *m68k, int ea) +{ + int mode = (ea >> 3) & 0x7; + int reg = (ea & 0x7); + + switch (mode) + { + case 2: // (An) + { + return REG_A(m68k)[reg]; + } + case 3: // (An)+ + { + UINT32 ea = EA_AY_PI_32(m68k); + return ea; + } + case 5: // (d16, An) + { + UINT32 ea = EA_AY_DI_32(m68k); + return ea; + } + case 6: // (An) + (Xn) + d8 + { + UINT32 ea = EA_AY_IX_32(m68k); + return ea; + } + case 7: + { + switch (reg) + { + case 0: // (xxx).W + { + UINT32 ea = (UINT32)OPER_I_16(m68k); + return ea; + } + case 1: // (xxx).L + { + UINT32 d1 = OPER_I_16(m68k); + UINT32 d2 = OPER_I_16(m68k); + UINT32 ea = (d1 << 16) | d2; + return ea; + } + case 2: // (d16, PC) + { + UINT32 ea = EA_PCDI_32(m68k); + return ea; + } + default: fatalerror("m68k: DECODE_EA_32: unhandled mode %d, reg %d at %08X\n", mode, reg, REG_PC(m68k)); + } + break; + } + default: fatalerror("m68k: DECODE_EA_32: unhandled mode %d, reg %d at %08X\n", mode, reg, REG_PC(m68k)); + } + return 0; +} + +/* + pmmu_atc_add: adds this address to the ATC +*/ +void pmmu_atc_add(m68000_base_device *m68k, UINT32 logical, UINT32 physical, int fc) +{ + int i, found; + + // get page size (i.e. # of bits to ignore); is 10 for Apollo + int ps = (m68k->mmu_tc >> 20) & 0xf; + // Note: exact emulation would use (logical >> ps) << (ps-8) + UINT32 atc_tag = M68K_MMU_ATC_VALID | ((fc &7) << 24)| logical >> ps; + + // first see if this is already in the cache + for (i = 0; i < MMU_ATC_ENTRIES; i++) + { + // if tag bits and function code match, don't add + if (m68k->mmu_atc_tag[i] == atc_tag) + { + return; + } + } + + // find an open entry + found = -1; + for (i = 0; i < MMU_ATC_ENTRIES; i++) + { + if (!(m68k->mmu_atc_tag[i] & M68K_MMU_ATC_VALID)) + { + found = i; + break; + } + } + + // did we find an entry? steal one by round-robin then + if (found == -1) + { + found = m68k->mmu_atc_rr++; + + if (m68k->mmu_atc_rr >= MMU_ATC_ENTRIES) + { + m68k->mmu_atc_rr = 0; + } + } + + // add the entry + // printf("ATC[%2d] add: log %08x -> phys %08x (fc=%d)\n", found, (logical>>ps) << ps, (physical >> ps) << ps, fc); + m68k->mmu_atc_tag[found] = atc_tag; + m68k->mmu_atc_data[found] = (physical >> ps) << (ps-8); + + if (m68k->mmu_tmp_sr & M68K_MMU_SR_WRITE_PROTECT) + { + m68k->mmu_atc_data[found] |= M68K_MMU_ATC_WRITE_PR; + } +} + +/* + pmmu_atc_flush: flush entire ATC + + 7fff0003 001ffd10 80f05750 is what should load +*/ +void pmmu_atc_flush(m68000_base_device *m68k) +{ + int i; + // printf("ATC flush: pc=%08x\n", REG_PPC(m68k)); + + for (i = 0; i < MMU_ATC_ENTRIES; i++) + { + m68k->mmu_atc_tag[i] = 0; + } + + m68k->mmu_atc_rr = 0; +} + + +INLINE UINT32 get_dt2_table_entry(m68000_base_device *m68k, UINT32 tptr, UINT8 ptest) +{ + UINT32 tbl_entry = m68k->program->read_dword(tptr); + UINT32 dt = tbl_entry & M68K_MMU_DF_DT; + + m68k->mmu_tmp_sr |= tbl_entry & 0x0004 ? M68K_MMU_SR_WRITE_PROTECT : 0; + + if (!ptest && dt != M68K_MMU_DF_DT0) + { + if (dt == M68K_MMU_DF_DT1 && !m68k->mmu_tmp_rw && !(m68k->mmu_tmp_sr & M68K_MMU_SR_WRITE_PROTECT)) + { + // set used and modified + m68k->program->write_dword( tptr, tbl_entry | M68K_MMU_DF_USED | M68K_MMU_DF_MODIFIED); + } + else if (!(tbl_entry & M68K_MMU_DF_USED)) + { + m68k->program->write_dword( tptr, tbl_entry | M68K_MMU_DF_USED); + } + } + return tbl_entry; +} + +INLINE UINT32 get_dt3_table_entry(m68000_base_device *m68k, UINT32 tptr, UINT8 fc, UINT8 ptest) +{ + UINT32 tbl_entry2 = m68k->program->read_dword(tptr); + UINT32 tbl_entry = m68k->program->read_dword(tptr + 4); + UINT32 dt = tbl_entry2 & M68K_MMU_DF_DT; + + m68k->mmu_tmp_sr |= ((tbl_entry2 & 0x0100) && !(fc & 4)) ? M68K_MMU_SR_SUPERVISOR_ONLY : 0; + m68k->mmu_tmp_sr |= tbl_entry2 & 0x0004 ? M68K_MMU_SR_WRITE_PROTECT : 0; + + if (!ptest && dt != M68K_MMU_DF_DT0) + { + if (dt == M68K_MMU_DF_DT1 && !m68k->mmu_tmp_rw && !(m68k->mmu_tmp_sr & M68K_MMU_SR_WRITE_PROTECT)) + { + // set modified + m68k->program->write_dword( tptr, tbl_entry2 | M68K_MMU_DF_USED | M68K_MMU_DF_MODIFIED); + } + else if (!(tbl_entry2 & M68K_MMU_DF_USED)) + { + m68k->program->write_dword( tptr, tbl_entry2 | M68K_MMU_DF_USED); + } + } + + return (tbl_entry & ~M68K_MMU_DF_DT) | dt; +} + +/* + pmmu_translate_addr_with_fc: perform 68851/68030-style PMMU address translation +*/ +/*INLINE*/ static UINT32 pmmu_translate_addr_with_fc(m68000_base_device *m68k, UINT32 addr_in, UINT8 fc, UINT8 ptest) +{ + UINT32 addr_out, tbl_entry = 0, tamode = 0, tbmode = 0, tcmode = 0; + UINT32 root_aptr, root_limit, tofs, ps, is, abits, bbits, cbits; + UINT32 resolved, tptr, shift, last_entry_ptr; + int i; + UINT32 atc_tag; +// int verbose = 0; + +// static UINT32 pmmu_access_count = 0; +// static UINT32 pmmu_atc_count = 0; + + resolved = 0; + addr_out = addr_in; + m68k->mmu_tmp_sr = 0; + + if (fc == 7) + { + return addr_in; + } + + if (m68k->mmu_tt0 & 0x8000) + { + // transparent translation register 0 enabled + UINT32 address_base = m68k->mmu_tt0 & 0xff000000; + UINT32 address_mask = ((m68k->mmu_tt0 << 8) & 0xff000000) ^ 0xff000000; + if ((addr_in & address_mask) == address_base && (fc & ~m68k->mmu_tt0) == ((m68k->mmu_tt0 >> 4) & 7)) + { +// printf("PMMU: pc=%x TT0 fc=%x addr_in=%08x address_mask=%08x address_base=%08x\n", m68k->ppc, fc, addr_in, address_mask, address_base); + return addr_in; + } + } + + if (m68k->mmu_tt1 & 0x8000) + { + // transparent translation register 1 enabled + UINT32 address_base = m68k->mmu_tt1 & 0xff000000; + UINT32 address_mask = ((m68k->mmu_tt1 << 8) & 0xff000000) ^ 0xff000000; + if ((addr_in & address_mask) == address_base && (fc & ~m68k->mmu_tt1) == ((m68k->mmu_tt1 >> 4) & 7)) + { +// printf("PMMU: pc=%x TT1 fc=%x addr_in=%08x address_mask=%08x address_base=%08x\n", m68k->ppc, fc, addr_in, address_mask, address_base); + return addr_in; + } + } + +// if ((++pmmu_access_count % 10000000) == 0) { +// printf("pmmu_translate_addr_with_fc: atc usage = %d%%\n", pmmu_atc_count*100/pmmu_access_count); +// pmmu_atc_count = pmmu_access_count = 0; +// } + + // get page size (i.e. # of bits to ignore); ps is 10 or 12 for Apollo, 8 otherwise + ps = (m68k->mmu_tc >> 20) & 0xf; + atc_tag = M68K_MMU_ATC_VALID | ((fc &7) << 24) | addr_in >> ps; + + // first see if this is already in the ATC + for (i = 0; i < MMU_ATC_ENTRIES; i++) + { + if (m68k->mmu_atc_tag[i] != atc_tag) + { + // tag bits and function code don't match + } + else if (!m68k->mmu_tmp_rw && (m68k->mmu_atc_data[i] & M68K_MMU_ATC_WRITE_PR)) + { + // write mode, but write protected + } + else if (!m68k->mmu_tmp_rw && !(m68k->mmu_atc_data[i] & M68K_MMU_ATC_MODIFIED)) + { + // first write; must set modified in PMMU tables as well + } + else + { + // read access or write access and not write protected + if (!m68k->mmu_tmp_rw && !ptest) + { + // FIXME: must set modified in PMMU tables as well + m68k->mmu_atc_data[i] |= M68K_MMU_ATC_MODIFIED; + } + else + { + // FIXME: supervisor mode? + m68k->mmu_tmp_sr = M68K_MMU_SR_MODIFIED; + } + addr_out = (m68k->mmu_atc_data[i] << 8) | (addr_in & ~(~0 << ps)); +// printf("ATC[%2d] hit: log %08x -> phys %08x pc=%08x fc=%d\n", i, addr_in, addr_out, REG_PPC(m68k), fc); +// pmmu_atc_count++; + return addr_out; + } + } + + // if SRP is enabled and we're in supervisor mode, use it + if ((m68k->mmu_tc & M68K_MMU_TC_SRE) && (fc & 4)) + { + root_aptr = m68k->mmu_srp_aptr; + root_limit = m68k->mmu_srp_limit; + } + else // else use the CRP + { + root_aptr = m68k->mmu_crp_aptr; + root_limit = m68k->mmu_crp_limit; + } + + // get initial shift (# of top bits to ignore) + is = (m68k->mmu_tc >> 16) & 0xf; + ps = (m68k->mmu_tc >> 20) & 0xf; + abits = (m68k->mmu_tc >> 12) & 0xf; + bbits = (m68k->mmu_tc >> 8) & 0xf; + cbits = (m68k->mmu_tc >> 4) & 0xf; + + // printf("PMMU: tcr %08x limit %08x aptr %08x is %x abits %d bbits %d cbits %d\n", m68k->mmu_tc, root_limit, root_aptr, is, abits, bbits, cbits); + + // get table A offset + tofs = (addr_in<>(32-abits); + tptr = root_aptr & 0xfffffff0; + + // find out what format table A is + switch (root_limit & M68K_MMU_DF_DT) + { + case M68K_MMU_DF_DT0: // invalid, will cause MMU exception + m68k->mmu_tmp_sr |= M68K_MMU_SR_INVALID; + return root_aptr; + + case M68K_MMU_DF_DT1: // page descriptor, will cause direct mapping + addr_out = tptr + addr_in; +// printf("PMMU: PC=%x root mode %d (addr_in %08x -> %08x)\n", m68k->ppc, M68K_MMU_DF_DT1, addr_in, addr_out); + return addr_out; + + case M68K_MMU_DF_DT2: // valid 4 byte descriptors + tofs *= 4; +// if (verbose) printf("PMMU: reading table A entry at %08x\n", tofs + tptr); + tbl_entry = get_dt2_table_entry(m68k, tptr + tofs, ptest); + tamode = tbl_entry & M68K_MMU_DF_DT; +// if (verbose) printf("PMMU: addr %08x entry %08x mode %x tofs %x\n", addr_in, tbl_entry, tamode, tofs); + break; + + case M68K_MMU_DF_DT3: // valid 8 byte descriptors + tofs *= 8; +// if (verbose) printf("PMMU: reading table A entries at %08x\n", tofs + tptr); + tbl_entry = get_dt3_table_entry(m68k, tofs + tptr, fc, ptest); + tamode = tbl_entry & M68K_MMU_DF_DT; +// if (verbose) printf("PMMU: addr %08x entry %08x entry2 %08x mode %x tofs %x\n", addr_in, tbl_entry, tbl_entry2, tamode, tofs); + break; + } + + last_entry_ptr = tptr + tofs; + + // get table B offset and pointer + tofs = (addr_in<<(is+abits))>>(32-bbits); + tptr = tbl_entry & 0xfffffff0; + + // find out what format table B is, if any + switch (tamode) + { + case M68K_MMU_DF_DT0: // invalid, will cause MMU exception (but not for ptest) + m68k->mmu_tmp_sr |= (M68K_MMU_SR_INVALID | M68K_MMU_SR_LEVEL_1); + // last valid pointer (for ptest) + addr_out = last_entry_ptr; + resolved = 1; + break; + + case M68K_MMU_DF_DT2: // 4-byte table B descriptor + tofs *= 4; +// if (verbose) printf("PMMU: reading table B entry at %08x\n", tofs + tptr); + tbl_entry = get_dt2_table_entry(m68k, tptr + tofs, ptest); + tbmode = tbl_entry & M68K_MMU_DF_DT; +// if (verbose) printf("PMMU: addr %08x entry %08x mode %x tofs %x\n", addr_in, tbl_entry, tbmode, tofs); + break; + + case M68K_MMU_DF_DT3: // 8-byte table B descriptor + tofs *= 8; +// if (verbose) printf("PMMU: reading table B entries at %08x\n", tofs + tptr); + tbl_entry = get_dt3_table_entry(m68k, tptr + tofs, fc, ptest); + tbmode = tbl_entry & M68K_MMU_DF_DT; + tbl_entry &= ~M68K_MMU_DF_DT; +// if (verbose) printf("PMMU: addr %08x entry %08x entry2 %08x mode %x tofs %x\n", addr_in, tbl_entry, tbl_entry2, tbmode, tofs); + break; + + case M68K_MMU_DF_DT1: // early termination descriptor + tbl_entry &= (~0 << ps); + + shift = is+abits; + addr_out = ((addr_in<>shift) + tbl_entry; + resolved = 1; + break; + } + + // if table A wasn't early-out, continue to process table B + if (!resolved) + { + last_entry_ptr = tptr + tofs; + + // get table C offset and pointer + tofs = (addr_in<<(is+abits+bbits))>>(32-cbits); + tptr = tbl_entry & 0xfffffff0; + + switch (tbmode) + { + case M68K_MMU_DF_DT0: // invalid, will cause MMU exception (but not for ptest) + m68k->mmu_tmp_sr |= (M68K_MMU_SR_INVALID | M68K_MMU_SR_LEVEL_2); + // last valid pointer (for ptest) + addr_out = last_entry_ptr; + resolved = 1; + break; + + case M68K_MMU_DF_DT2: // 4-byte table C descriptor + tofs *= 4; +// if (verbose) printf("PMMU: reading table C entry at %08x\n", tofs + tptr); + tbl_entry = get_dt2_table_entry(m68k, tptr + tofs, ptest); + tcmode = tbl_entry & M68K_MMU_DF_DT; +// if (verbose) printf("PMMU: addr %08x entry %08x mode %x tofs %x\n", addr_in, tbl_entry, tbmode, tofs); + break; + + case M68K_MMU_DF_DT3: // 8-byte table C descriptor + tofs *= 8; +// if (verbose) printf("PMMU: reading table C entries at %08x\n", tofs + tptr); + tbl_entry = get_dt3_table_entry(m68k, tptr+ tofs, fc, ptest); + tcmode = tbl_entry & M68K_MMU_DF_DT; +// if (verbose) printf("PMMU: addr %08x entry %08x entry2 %08x mode %x tofs %x\n", addr_in, tbl_entry, tbl_entry2, tcmode, tofs); + break; + + case M68K_MMU_DF_DT1: // termination descriptor + tbl_entry &= (~0 << ps); + + shift = is+abits+bbits; + addr_out = ((addr_in<>shift) + tbl_entry; + resolved = 1; + break; + } + } + + if (!resolved) + { + switch (tcmode) + { + case M68K_MMU_DF_DT0: // invalid, will cause MMU exception (unless ptest) + m68k->mmu_tmp_sr |= (M68K_MMU_SR_INVALID | M68K_MMU_SR_LEVEL_3); + addr_out = tptr + tofs; + resolved = 1; + break; + + case M68K_MMU_DF_DT2: // 4-byte (short-form) indirect descriptor + case M68K_MMU_DF_DT3: // 8-byte (long-form) indirect descriptor + fatalerror("PMMU: pc=%08x Unhandled Table C mode %d (addr_in %08x)\n", m68k->ppc, tcmode, addr_in); + break; + + case M68K_MMU_DF_DT1: // termination descriptor + tbl_entry &= (~0 << ps); + + shift = is+abits+bbits+cbits; + addr_out = ((addr_in<>shift) + tbl_entry; + resolved = 1; + break; + } + } + + if (!ptest) + { + if (m68k->mmu_tmp_sr & M68K_MMU_SR_INVALID) + { + if (++m68k->mmu_tmp_buserror_occurred == 1) + { + m68k->mmu_tmp_buserror_address = addr_in; + m68k->mmu_tmp_buserror_rw = m68k->mmu_tmp_rw; + m68k->mmu_tmp_buserror_fc = m68k->mmu_tmp_fc; + } + } + else if (m68k->mmu_tmp_sr & M68K_MMU_SR_SUPERVISOR_ONLY) + { + if (++m68k->mmu_tmp_buserror_occurred == 1) + { + m68k->mmu_tmp_buserror_address = addr_in; + m68k->mmu_tmp_buserror_rw = m68k->mmu_tmp_rw; + m68k->mmu_tmp_buserror_fc = m68k->mmu_tmp_fc; + } + } + else if ((m68k->mmu_tmp_sr & M68K_MMU_SR_WRITE_PROTECT) && !m68k->mmu_tmp_rw) + { + if (++m68k->mmu_tmp_buserror_occurred == 1) + { + m68k->mmu_tmp_buserror_address = addr_in; + m68k->mmu_tmp_buserror_rw = m68k->mmu_tmp_rw; + m68k->mmu_tmp_buserror_fc = m68k->mmu_tmp_fc; + } + } + + if (!m68k->mmu_tmp_buserror_occurred) + { + // we add only valid entries + pmmu_atc_add(m68k, addr_in, addr_out, fc); + } + } + + //printf("PMMU: [%08x] => [%08x]\n", addr_in, addr_out); + + return addr_out; +} + + +// FC bits: 2 = supervisor, 1 = program, 0 = data +// the 68040 is a subset of the 68851 and 68030 PMMUs - the page table sizes are fixed, there is no early termination, etc, etc. +/*INLINE*/ static UINT32 pmmu_translate_addr_with_fc_040(m68000_base_device *m68k, UINT32 addr_in, UINT8 fc, UINT8 ptest) +{ + UINT32 addr_out, tt0, tt1; + + addr_out = addr_in; + m68k->mmu_tmp_sr = 0; + + // transparent translation registers are always in force even if the PMMU itself is disabled + // they don't do much in emulation because we never write out of order, but the write-protect and cache control features + // are emulatable, and apparently transparent translation regions skip the page table lookup. + if (fc & 1) // data, use DTT0/DTT1 + { + tt0 = m68k->mmu_dtt0; + tt1 = m68k->mmu_dtt1; + } + else if (fc & 2) // program, use ITT0/ITT1 + { + tt0 = m68k->mmu_itt0; + tt1 = m68k->mmu_itt1; + } + else + { + fatalerror("68040: function code %d is neither data nor program!\n", fc&7); + } + + if (tt0 & 0x8000) + { + static int fcmask[4] = { 4, 4, 0, 0 }; + static int fcmatch[4] = { 0, 4, 0, 0 }; + UINT32 mask = (tt0>>16) & 0xff; + mask ^= 0xff; + mask <<= 24; + + if ((addr_in & mask) == (tt0 & mask) && (fc & fcmask[(tt0 >> 13) & 3]) == fcmatch[(tt0 >> 13) & 3]) + { + // fprintf(stderr, "TT0 match on address %08x (TT0 = %08x, mask = %08x)\n", addr_in, tt0, mask); + if ((tt0 & 4) && !m68k->mmu_tmp_rw && !ptest) // write protect? + { + if (++m68k->mmu_tmp_buserror_occurred == 1) + { + m68k->mmu_tmp_buserror_address = addr_in; + m68k->mmu_tmp_buserror_rw = m68k->mmu_tmp_rw; + m68k->mmu_tmp_buserror_fc = m68k->mmu_tmp_fc; + } + } + + return addr_in; + } + } + + if (tt1 & 0x8000) + { + static int fcmask[4] = { 4, 4, 0, 0 }; + static int fcmatch[4] = { 0, 4, 0, 0 }; + UINT32 mask = (tt1>>16) & 0xff; + mask ^= 0xff; + mask <<= 24; + + if ((addr_in & mask) == (tt1 & mask) && (fc & fcmask[(tt1 >> 13) & 3]) == fcmatch[(tt1 >> 13) & 3]) + { + // fprintf(stderr, "TT1 match on address %08x (TT0 = %08x, mask = %08x)\n", addr_in, tt1, mask); + if ((tt1 & 4) && !m68k->mmu_tmp_rw && !ptest) // write protect? + { + if (++m68k->mmu_tmp_buserror_occurred == 1) + { + m68k->mmu_tmp_buserror_address = addr_in; + m68k->mmu_tmp_buserror_rw = m68k->mmu_tmp_rw; + m68k->mmu_tmp_buserror_fc = m68k->mmu_tmp_fc; + } + } + + return addr_in; + } + } + + if (m68k->pmmu_enabled) + { + UINT32 root_idx = (addr_in>>25) & 0x7f; + UINT32 ptr_idx = (addr_in>>18) & 0x7f; + UINT32 page_idx, page; + UINT32 root_ptr, pointer_ptr, page_ptr; + UINT32 root_entry, pointer_entry, page_entry; + + // select supervisor or user root pointer + if (fc & 4) + { + root_ptr = m68k->mmu_srp_aptr + (root_idx<<2); + } + else + { + root_ptr = m68k->mmu_urp_aptr + (root_idx<<2); + } + + // get the root entry + root_entry = m68k->program->read_dword(root_ptr); + + // is UDT marked valid? + if (root_entry & 2) + { + // we're accessing through this root entry, so set the U bit + if ((!(root_entry & 0x8)) && (!ptest)) + { + root_entry |= 0x8; + m68k->program->write_dword(root_ptr, root_entry); + } + + // PTEST: any write protect bits set in the search tree will set W in SR + if ((ptest) && (root_entry & 4)) + { + m68k->mmu_tmp_sr |= 4; + } + + pointer_ptr = (root_entry & ~0x1ff) + (ptr_idx<<2); + pointer_entry = m68k->program->read_dword(pointer_ptr); + + // PTEST: any write protect bits set in the search tree will set W in SR + if ((ptest) && (pointer_entry & 4)) + { + m68k->mmu_tmp_sr |= 4; + } + + // update U bit on this pointer entry too + if ((!(pointer_entry & 0x8)) && (!ptest)) + { + pointer_entry |= 0x8; + m68k->program->write_dword(pointer_ptr, pointer_entry); + } + + // logerror("pointer entry = %08x\n", pointer_entry); + + // write protected by the root or pointer entries? + if ((((root_entry & 4) && !m68k->mmu_tmp_rw) || ((pointer_entry & 4) && !m68k->mmu_tmp_rw)) && !ptest) + { + if (++m68k->mmu_tmp_buserror_occurred == 1) + { + m68k->mmu_tmp_buserror_address = addr_in; + m68k->mmu_tmp_buserror_rw = m68k->mmu_tmp_rw; + m68k->mmu_tmp_buserror_fc = m68k->mmu_tmp_fc; + } + + return addr_in; + } + + // is UDT valid on the pointer entry? + if (!(pointer_entry & 2) && !ptest) + { +// fprintf(stderr, "Invalid pointer entry! PC=%x, addr=%x\n", m68k->ppc, addr_in); + if (++m68k->mmu_tmp_buserror_occurred == 1) + { + m68k->mmu_tmp_buserror_address = addr_in; + m68k->mmu_tmp_buserror_rw = m68k->mmu_tmp_rw; + m68k->mmu_tmp_buserror_fc = m68k->mmu_tmp_fc; + } + + return addr_in; + } + + // (fall out of these ifs into the page lookup below) + } + else // throw an error + { +// fprintf(stderr, "Invalid root entry! PC=%x, addr=%x\n", m68k->ppc, addr_in); + + if (!ptest) + { + if (++m68k->mmu_tmp_buserror_occurred == 1) + { + m68k->mmu_tmp_buserror_address = addr_in; + m68k->mmu_tmp_buserror_rw = m68k->mmu_tmp_rw; + m68k->mmu_tmp_buserror_fc = m68k->mmu_tmp_fc; + } + } + + return addr_in; + } + + // now do the page lookup + if (m68k->mmu_tc & 0x4000) // 8k pages? + { + page_idx = (addr_in >> 13) & 0x1f; + page = addr_in & 0x1fff; + pointer_entry &= ~0x7f; + // logerror("8k pages: index %x page %x\n", page_idx, page); + } + else // 4k pages + { + page_idx = (addr_in >> 12) & 0x3f; + page = addr_in & 0xfff; + pointer_entry &= ~0xff; + // logerror("4k pages: index %x page %x\n", page_idx, page); + } + + page_ptr = pointer_entry + (page_idx<<2); + page_entry = m68k->program->read_dword(page_ptr); + m68k->mmu_last_page_entry_addr = page_ptr; + + // logerror("page_entry = %08x\n", page_entry); + + // resolve indirect page pointers + while ((page_entry & 3) == 2) + { + page_entry = m68k->program->read_dword(page_entry & ~0x3); + m68k->mmu_last_page_entry_addr = (page_entry & ~0x3); + } + m68k->mmu_last_page_entry = page_entry; + + // is the page write protected or supervisor protected? + if ((((page_entry & 4) && !m68k->mmu_tmp_rw) || ((page_entry & 0x80) && !(fc&4))) && !ptest) + { + if (++m68k->mmu_tmp_buserror_occurred == 1) + { + m68k->mmu_tmp_buserror_address = addr_in; + m68k->mmu_tmp_buserror_rw = m68k->mmu_tmp_rw; + m68k->mmu_tmp_buserror_fc = m68k->mmu_tmp_fc; + } + + return addr_in; + } + + switch (page_entry & 3) + { + case 0: // invalid +// fprintf(stderr, "Invalid page entry! PC=%x, addr=%x\n", m68k->ppc, addr_in); + if (!ptest) + { + if (++m68k->mmu_tmp_buserror_occurred == 1) + { + m68k->mmu_tmp_buserror_address = addr_in; + m68k->mmu_tmp_buserror_rw = m68k->mmu_tmp_rw; + m68k->mmu_tmp_buserror_fc = m68k->mmu_tmp_fc; + } + } + + return addr_in; + + case 1: + case 3: // normal + if (m68k->mmu_tc & 0x4000) // 8k pages? + { + addr_out = (page_entry & ~0x1fff) | page; + } + else + { + addr_out = (page_entry & ~0xfff) | page; + } + + if (!(ptest)) + { + page_entry |= 0x8; // always set the U bit + + // if we're writing, the M bit comes into play + if (!m68k->mmu_tmp_rw) + { + page_entry |= 0x10; // set Modified + } + + // if these updates resulted in a change, write the entry back where we found it + if (page_entry != m68k->mmu_last_page_entry) + { + m68k->mmu_last_page_entry = page_entry; + m68k->program->write_dword(m68k->mmu_last_page_entry_addr, m68k->mmu_last_page_entry); + } + } + else + { + // page entry: UR G U1 U0 S CM CM M U W PDT + // SR: B G U1 U0 S CM CM M 0 W T R + m68k->mmu_tmp_sr |= ((addr_out & ~0xfff) || (page_entry & 0x7f4)); + } + break; + + case 2: // shouldn't happen + fatalerror("68040: got indirect final page pointer, shouldn't be possible\n"); + break; + } + // if (addr_in != addr_out) fprintf(stderr, "040MMU: [%08x] => [%08x]\n", addr_in, addr_out); + } + + return addr_out; +} + +/* + pmmu_translate_addr: perform 68851/68030-style PMMU address translation +*/ +/*INLINE*/ static UINT32 pmmu_translate_addr(m68000_base_device *m68k, UINT32 addr_in) +{ + UINT32 addr_out; + + if (CPU_TYPE_IS_040_PLUS(m68k->cpu_type)) + { + addr_out = pmmu_translate_addr_with_fc_040(m68k, addr_in, m68k->mmu_tmp_fc, 0); + } + else + { + addr_out = pmmu_translate_addr_with_fc(m68k, addr_in, m68k->mmu_tmp_fc, 0); + } + +// if (m68k->mmu_tmp_buserror_occurred > 0) { +// printf("PMMU: pc=%08x sp=%08x va=%08x pa=%08x - invalid Table mode for level=%d (buserror %d)\n", +// REG_PPC(m68k), REG_A(m68k)[7], addr_in, addr_out, m68k->mmu_tmp_sr & M68K_MMU_SR_LEVEL_3, +// m68k->mmu_tmp_buserror_occurred); +// } + + return addr_out; +} + +/* + m68851_mmu_ops: COP 0 MMU opcode handling +*/ + +void m68881_mmu_ops(m68000_base_device *m68k) +{ + UINT16 modes; + UINT32 ea = m68k->ir & 0x3f; + UINT64 temp64; + + + // catch the 2 "weird" encodings up front (PBcc) + if ((m68k->ir & 0xffc0) == 0xf0c0) + { + printf("680x0: unhandled PBcc\n"); + return; + } + else if ((m68k->ir & 0xffc0) == 0xf080) + { + printf("680x0: unhandled PBcc\n"); + return; + } + else if ((m68k->ir & 0xffe0) == 0xf500) + { +// logerror("68040 pflush: pc=%08x ir=%04x opmode=%d register=%d\n", REG_PPC(m68k), m68k->ir, (m68k->ir >> 3) & 3, m68k->ir & 7); + pmmu_atc_flush(m68k); + } + else // the rest are 1111000xxxXXXXXX where xxx is the instruction family + { + switch ((m68k->ir>>9) & 0x7) + { + case 0: + modes = OPER_I_16(m68k); + + if ((modes & 0xfde0) == 0x2000) // PLOAD + { + UINT32 ltmp = DECODE_EA_32(m68k, ea); + UINT32 ptmp; + + ptmp = ltmp; + if (m68k->pmmu_enabled) + { + if (CPU_TYPE_IS_040_PLUS(m68k->cpu_type)) + { + ptmp = pmmu_translate_addr_with_fc_040(m68k, ltmp, modes & 0x07, 0); + } + else + { + ptmp = pmmu_translate_addr_with_fc(m68k, ltmp, modes & 0x07, 0); + } + } + +// printf("680x0: PLOADing ATC with logical %08x => phys %08x\n", ltmp, ptmp); + // FIXME: rw bit? + pmmu_atc_add(m68k, ltmp, ptmp, modes & 0x07); + return; + } + else if ((modes & 0xe200) == 0x2000) // PFLUSH + { + pmmu_atc_flush(m68k); + return; + } + else if (modes == 0xa000) // PFLUSHR + { + pmmu_atc_flush(m68k); + return; + } + else if (modes == 0x2800) // PVALID (FORMAT 1) + { + printf("680x0: unhandled PVALID1\n"); + return; + } + else if ((modes & 0xfff8) == 0x2c00) // PVALID (FORMAT 2) + { + printf("680x0: unhandled PVALID2\n"); + return; + } + else if ((modes & 0xe000) == 0x8000) // PTEST + { + UINT32 v_addr = DECODE_EA_32(m68k, ea); + UINT32 p_addr; + UINT32 fc = modes & 0x1f; + switch (fc >> 3) { + case 0: + fc = fc == 0 ? m68k->sfc : m68k->dfc; + break; + case 1: + fc = REG_D(m68k)[fc &7] &7; + break; + case 2: + fc &=7; + break; + } + + if (CPU_TYPE_IS_040_PLUS(m68k->cpu_type)) + { + p_addr = pmmu_translate_addr_with_fc_040(m68k, v_addr, fc, 1); + } + else + { + p_addr = pmmu_translate_addr_with_fc(m68k, v_addr, fc, 1); + } + m68k->mmu_sr = m68k->mmu_tmp_sr; + +// printf("PMMU: pc=%08x sp=%08x va=%08x pa=%08x PTEST fc=%x level=%x mmu_sr=%04x\n", +// m68k->ppc, REG_A(m68k)[7], v_addr, p_addr, fc, (modes >> 10) & 0x07, m68k->mmu_sr); + + if (modes & 0x100) + { + int areg = (modes >> 5) & 7; + WRITE_EA_32(m68k, 0x08 | areg, p_addr); + } + return; + } + else + { + switch ((modes>>13) & 0x7) + { + case 0: // MC68030/040 form with FD bit + case 2: // MC68881 form, FD never set + if (modes & 0x200) + { + switch ((modes>>10) & 0x3f) + { + case 0x02: // transparent translation register 0 + WRITE_EA_32(m68k, ea, m68k->mmu_tt0); +// printf("PMMU: pc=%x PMOVE from mmu_tt0=%08x\n", m68k->ppc, m68k->mmu_tt0); + break; + case 0x03: // transparent translation register 1 + WRITE_EA_32(m68k, ea, m68k->mmu_tt1); +// printf("PMMU: pc=%x PMOVE from mmu_tt1=%08x\n", m68k->ppc, m68k->mmu_tt1); + break; + case 0x10: // translation control register + WRITE_EA_32(m68k, ea, m68k->mmu_tc); +// printf("PMMU: pc=%x PMOVE from mmu_tc=%08x\n", m68k->ppc, m68k->mmu_tc); + break; + + case 0x12: // supervisor root pointer + WRITE_EA_64(m68k, ea, (UINT64)m68k->mmu_srp_limit<<32 | (UINT64)m68k->mmu_srp_aptr); +// printf("PMMU: pc=%x PMOVE from SRP limit = %08x, aptr = %08x\n", REG_PPC(m68k), m68k->mmu_srp_limit, m68k->mmu_srp_aptr); + break; + + case 0x13: // CPU root pointer + WRITE_EA_64(m68k, ea, (UINT64)m68k->mmu_crp_limit<<32 | (UINT64)m68k->mmu_crp_aptr); +// printf("PMMU: pc=%x PMOVE from CRP limit = %08x, aptr = %08x\n", REG_PPC(m68k), m68k->mmu_crp_limit, m68k->mmu_crp_aptr); + break; + + default: + printf("680x0: PMOVE from unknown MMU register %x, PC %x\n", (modes>>10) & 7, m68k->pc); + break; + } + + } + else // top 3 bits of modes: 010 for this, 011 for status, 000 for transparent translation regs + { + switch ((modes>>13) & 7) + { + case 0: + { + UINT32 temp = READ_EA_32(m68k, ea); + + if (((modes>>10) & 7) == 2) + { + m68k->mmu_tt0 = temp; + } + else if (((modes>>10) & 7) == 3) + { + m68k->mmu_tt1 = temp; + } + } + break; + + case 1: + printf("680x0: unknown PMOVE case 1, PC %x\n", m68k->pc); + break; + + case 2: + switch ((modes>>10) & 7) + { + case 0: // translation control register + m68k->mmu_tc = READ_EA_32(m68k, ea); +// printf("PMMU: TC = %08x\n", m68k->mmu_tc); + + if (m68k->mmu_tc & 0x80000000) + { + m68k->pmmu_enabled = 1; +// printf("PMMU enabled\n"); + } + else + { + m68k->pmmu_enabled = 0; +// printf("PMMU disabled\n"); + } + + if (!(modes & 0x100)) // flush ATC on moves to TC, SRP, CRP with FD bit clear + { + pmmu_atc_flush(m68k); + } + break; + + case 2: // supervisor root pointer + temp64 = READ_EA_64(m68k, ea); + m68k->mmu_srp_limit = (temp64>>32) & 0xffffffff; + m68k->mmu_srp_aptr = temp64 & 0xffffffff; +// printf("PMMU: SRP limit = %08x aptr = %08x\n", m68k->mmu_srp_limit, m68k->mmu_srp_aptr); + if (!(modes & 0x100)) + { + pmmu_atc_flush(m68k); + } + break; + + case 3: // CPU root pointer + temp64 = READ_EA_64(m68k, ea); + m68k->mmu_crp_limit = (temp64>>32) & 0xffffffff; + m68k->mmu_crp_aptr = temp64 & 0xffffffff; +// printf("PMMU: CRP limit = %08x aptr = %08x\n", m68k->mmu_crp_limit, m68k->mmu_crp_aptr); + if (!(modes & 0x100)) + { + pmmu_atc_flush(m68k); + } + break; + + case 7: // MC68851 Access Control Register + if (m68k->cpu_type == CPU_TYPE_020) + { + // DomainOS on Apollo DN3000 will only reset this to 0 + UINT16 mmu_ac = READ_EA_16(m68k, ea); + if (mmu_ac != 0) + { + printf("680x0 PMMU: pc=%x PMOVE to mmu_ac=%08x\n", + m68k->ppc, mmu_ac); + } + break; + } + // fall through; unknown PMOVE mode unless MC68020 with MC68851 + + default: + printf("680x0: PMOVE to unknown MMU register %x, PC %x\n", (modes>>10) & 7, m68k->pc); + break; + } + break; + + case 3: // MMU status + { + UINT32 temp = READ_EA_32(m68k, ea); + printf("680x0: unsupported PMOVE %x to MMU status, PC %x\n", temp, m68k->pc); + } + break; + } + } + break; + + case 3: // MC68030 to/from status reg + if (modes & 0x200) + { + WRITE_EA_16(m68k, ea, m68k->mmu_sr); + } + else + { + m68k->mmu_sr = READ_EA_16(m68k, ea); + } + break; + + default: + printf("680x0: unknown PMOVE mode %x (modes %04x) (PC %x)\n", (modes>>13) & 0x7, modes, m68k->pc); + break; + + } + } + break; + + default: + printf("680x0: unknown PMMU instruction group %d\n", (m68k->ir>>9) & 0x7); + break; + } + } +} + + +/* Apple HMMU translation is much simpler */ +INLINE UINT32 hmmu_translate_addr(m68000_base_device *m68k, UINT32 addr_in) +{ + UINT32 addr_out; + + addr_out = addr_in; + + // check if LC 24-bit mode is enabled - this simply blanks out A31, the V8 ignores A30-24 always + if (m68k->hmmu_enabled == M68K_HMMU_ENABLE_LC) + { + addr_out = addr_in & 0xffffff; + } + else if (m68k->hmmu_enabled == M68K_HMMU_ENABLE_II) // the original II does a more complex translation + { + addr_out = addr_in & 0xffffff; + + if ((addr_out >= 0x800000) && (addr_out <= 0x8fffff)) + { + addr_out |= 0x40000000; // ROM + } + else if ((addr_out >= 0x900000) && (addr_out <= 0xefffff)) + { + addr_out = 0xf0000000; // NuBus + addr_out |= ((addr_in & 0xf00000)<<4); + addr_out |= (addr_in & 0xfffff); + } + else if (addr_out >= 0xf00000) + { + addr_out |= 0x50000000; // I/O + } + + // (RAM is at 0 and doesn't need special massaging) + } + + return addr_out; +} diff --git a/src/devices/cpu/m68000/m68kops.c b/src/devices/cpu/m68000/m68kops.c new file mode 100644 index 00000000000..f0962a93ef8 --- /dev/null +++ b/src/devices/cpu/m68000/m68kops.c @@ -0,0 +1,34886 @@ +// license:BSD-3-Clause +// copyright-holders:Karl Stenerud +#include "emu.h" +#include "m68kcpu.h" +extern void m68040_fpu_op0(m68000_base_device *m68k); +extern void m68040_fpu_op1(m68000_base_device *m68k); +extern void m68881_mmu_ops(m68000_base_device *m68k); +extern void m68881_ftrap(m68000_base_device *m68k); + +/* ======================================================================== */ +/* ========================= INSTRUCTION HANDLERS ========================= */ +/* ======================================================================== */ + + +void m68000_base_device_ops::m68k_op_1010(m68000_base_device* mc68kcpu) +{ + m68ki_exception_1010(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_1111(m68000_base_device* mc68kcpu) +{ + m68ki_exception_1111(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_040fpu0_32(m68000_base_device* mc68kcpu) +{ + if((mc68kcpu)->has_fpu) + { + m68040_fpu_op0(mc68kcpu); + return; + } + m68ki_exception_1111(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_040fpu1_32(m68000_base_device* mc68kcpu) +{ + if((mc68kcpu)->has_fpu) + { + m68040_fpu_op1(mc68kcpu); + return; + } + m68ki_exception_1111(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_abcd_8_rr(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = DY(mc68kcpu); + UINT32 dst = *r_dst; + UINT32 res = LOW_NIBBLE(src) + LOW_NIBBLE(dst) + XFLAG_AS_1(mc68kcpu); + + (mc68kcpu)->v_flag = ~res; /* Undefined V behavior */ + + if(res > 9) + res += 6; + res += HIGH_NIBBLE(src) + HIGH_NIBBLE(dst); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = (res > 0x99) << 8; + if((mc68kcpu)->c_flag) + res -= 0xa0; + + (mc68kcpu)->v_flag &= res; /* Undefined V behavior part II */ + (mc68kcpu)->n_flag = NFLAG_8(res); /* Undefined N behavior */ + + res = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->not_z_flag |= res; + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; +} + + +void m68000_base_device_ops::m68k_op_abcd_8_mm_ax7(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_AY_PD_8(mc68kcpu); + UINT32 ea = EA_A7_PD_8(mc68kcpu); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + UINT32 res = LOW_NIBBLE(src) + LOW_NIBBLE(dst) + XFLAG_AS_1(mc68kcpu); + + (mc68kcpu)->v_flag = ~res; /* Undefined V behavior */ + + if(res > 9) + res += 6; + res += HIGH_NIBBLE(src) + HIGH_NIBBLE(dst); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = (res > 0x99) << 8; + if((mc68kcpu)->c_flag) + res -= 0xa0; + + (mc68kcpu)->v_flag &= res; /* Undefined V behavior part II */ + (mc68kcpu)->n_flag = NFLAG_8(res); /* Undefined N behavior */ + + res = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->not_z_flag |= res; + + m68ki_write_8((mc68kcpu), ea, res); +} + + +void m68000_base_device_ops::m68k_op_abcd_8_mm_ay7(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_A7_PD_8(mc68kcpu); + UINT32 ea = EA_AX_PD_8(mc68kcpu); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + UINT32 res = LOW_NIBBLE(src) + LOW_NIBBLE(dst) + XFLAG_AS_1(mc68kcpu); + + (mc68kcpu)->v_flag = ~res; /* Undefined V behavior */ + + if(res > 9) + res += 6; + res += HIGH_NIBBLE(src) + HIGH_NIBBLE(dst); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = (res > 0x99) << 8; + if((mc68kcpu)->c_flag) + res -= 0xa0; + + (mc68kcpu)->v_flag &= res; /* Undefined V behavior part II */ + (mc68kcpu)->n_flag = NFLAG_8(res); /* Undefined N behavior */ + + res = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->not_z_flag |= res; + + m68ki_write_8((mc68kcpu), ea, res); +} + + +void m68000_base_device_ops::m68k_op_abcd_8_mm_axy7(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_A7_PD_8(mc68kcpu); + UINT32 ea = EA_A7_PD_8(mc68kcpu); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + UINT32 res = LOW_NIBBLE(src) + LOW_NIBBLE(dst) + XFLAG_AS_1(mc68kcpu); + + (mc68kcpu)->v_flag = ~res; /* Undefined V behavior */ + + if(res > 9) + res += 6; + res += HIGH_NIBBLE(src) + HIGH_NIBBLE(dst); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = (res > 0x99) << 8; + if((mc68kcpu)->c_flag) + res -= 0xa0; + + (mc68kcpu)->v_flag &= res; /* Undefined V behavior part II */ + (mc68kcpu)->n_flag = NFLAG_8(res); /* Undefined N behavior */ + + res = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->not_z_flag |= res; + + m68ki_write_8((mc68kcpu), ea, res); +} + + +void m68000_base_device_ops::m68k_op_abcd_8_mm(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_AY_PD_8(mc68kcpu); + UINT32 ea = EA_AX_PD_8(mc68kcpu); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + UINT32 res = LOW_NIBBLE(src) + LOW_NIBBLE(dst) + XFLAG_AS_1(mc68kcpu); + + (mc68kcpu)->v_flag = ~res; /* Undefined V behavior */ + + if(res > 9) + res += 6; + res += HIGH_NIBBLE(src) + HIGH_NIBBLE(dst); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = (res > 0x99) << 8; + if((mc68kcpu)->c_flag) + res -= 0xa0; + + (mc68kcpu)->v_flag &= res; /* Undefined V behavior part II */ + (mc68kcpu)->n_flag = NFLAG_8(res); /* Undefined N behavior */ + + res = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->not_z_flag |= res; + + m68ki_write_8((mc68kcpu), ea, res); +} + + +void m68000_base_device_ops::m68k_op_add_8_er_d(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = MASK_OUT_ABOVE_8(DY(mc68kcpu)); + UINT32 dst = MASK_OUT_ABOVE_8(*r_dst); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_ADD_8(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | (mc68kcpu)->not_z_flag; +} + + +void m68000_base_device_ops::m68k_op_add_8_er_ai(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = OPER_AY_AI_8(mc68kcpu); + UINT32 dst = MASK_OUT_ABOVE_8(*r_dst); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_ADD_8(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | (mc68kcpu)->not_z_flag; +} + + +void m68000_base_device_ops::m68k_op_add_8_er_pi(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = OPER_AY_PI_8(mc68kcpu); + UINT32 dst = MASK_OUT_ABOVE_8(*r_dst); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_ADD_8(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | (mc68kcpu)->not_z_flag; +} + + +void m68000_base_device_ops::m68k_op_add_8_er_pi7(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = OPER_A7_PI_8(mc68kcpu); + UINT32 dst = MASK_OUT_ABOVE_8(*r_dst); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_ADD_8(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | (mc68kcpu)->not_z_flag; +} + + +void m68000_base_device_ops::m68k_op_add_8_er_pd(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = OPER_AY_PD_8(mc68kcpu); + UINT32 dst = MASK_OUT_ABOVE_8(*r_dst); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_ADD_8(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | (mc68kcpu)->not_z_flag; +} + + +void m68000_base_device_ops::m68k_op_add_8_er_pd7(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = OPER_A7_PD_8(mc68kcpu); + UINT32 dst = MASK_OUT_ABOVE_8(*r_dst); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_ADD_8(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | (mc68kcpu)->not_z_flag; +} + + +void m68000_base_device_ops::m68k_op_add_8_er_di(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = OPER_AY_DI_8(mc68kcpu); + UINT32 dst = MASK_OUT_ABOVE_8(*r_dst); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_ADD_8(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | (mc68kcpu)->not_z_flag; +} + + +void m68000_base_device_ops::m68k_op_add_8_er_ix(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = OPER_AY_IX_8(mc68kcpu); + UINT32 dst = MASK_OUT_ABOVE_8(*r_dst); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_ADD_8(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | (mc68kcpu)->not_z_flag; +} + + +void m68000_base_device_ops::m68k_op_add_8_er_aw(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = OPER_AW_8(mc68kcpu); + UINT32 dst = MASK_OUT_ABOVE_8(*r_dst); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_ADD_8(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | (mc68kcpu)->not_z_flag; +} + + +void m68000_base_device_ops::m68k_op_add_8_er_al(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = OPER_AL_8(mc68kcpu); + UINT32 dst = MASK_OUT_ABOVE_8(*r_dst); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_ADD_8(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | (mc68kcpu)->not_z_flag; +} + + +void m68000_base_device_ops::m68k_op_add_8_er_pcdi(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = OPER_PCDI_8(mc68kcpu); + UINT32 dst = MASK_OUT_ABOVE_8(*r_dst); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_ADD_8(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | (mc68kcpu)->not_z_flag; +} + + +void m68000_base_device_ops::m68k_op_add_8_er_pcix(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = OPER_PCIX_8(mc68kcpu); + UINT32 dst = MASK_OUT_ABOVE_8(*r_dst); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_ADD_8(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | (mc68kcpu)->not_z_flag; +} + + +void m68000_base_device_ops::m68k_op_add_8_er_i(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = OPER_I_8(mc68kcpu); + UINT32 dst = MASK_OUT_ABOVE_8(*r_dst); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_ADD_8(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | (mc68kcpu)->not_z_flag; +} + + +void m68000_base_device_ops::m68k_op_add_16_er_d(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = MASK_OUT_ABOVE_16(DY(mc68kcpu)); + UINT32 dst = MASK_OUT_ABOVE_16(*r_dst); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->v_flag = VFLAG_ADD_16(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | (mc68kcpu)->not_z_flag; +} + + +void m68000_base_device_ops::m68k_op_add_16_er_a(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = MASK_OUT_ABOVE_16(AY(mc68kcpu)); + UINT32 dst = MASK_OUT_ABOVE_16(*r_dst); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->v_flag = VFLAG_ADD_16(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | (mc68kcpu)->not_z_flag; +} + + +void m68000_base_device_ops::m68k_op_add_16_er_ai(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = OPER_AY_AI_16(mc68kcpu); + UINT32 dst = MASK_OUT_ABOVE_16(*r_dst); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->v_flag = VFLAG_ADD_16(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | (mc68kcpu)->not_z_flag; +} + + +void m68000_base_device_ops::m68k_op_add_16_er_pi(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = OPER_AY_PI_16(mc68kcpu); + UINT32 dst = MASK_OUT_ABOVE_16(*r_dst); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->v_flag = VFLAG_ADD_16(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | (mc68kcpu)->not_z_flag; +} + + +void m68000_base_device_ops::m68k_op_add_16_er_pd(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = OPER_AY_PD_16(mc68kcpu); + UINT32 dst = MASK_OUT_ABOVE_16(*r_dst); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->v_flag = VFLAG_ADD_16(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | (mc68kcpu)->not_z_flag; +} + + +void m68000_base_device_ops::m68k_op_add_16_er_di(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = OPER_AY_DI_16(mc68kcpu); + UINT32 dst = MASK_OUT_ABOVE_16(*r_dst); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->v_flag = VFLAG_ADD_16(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | (mc68kcpu)->not_z_flag; +} + + +void m68000_base_device_ops::m68k_op_add_16_er_ix(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = OPER_AY_IX_16(mc68kcpu); + UINT32 dst = MASK_OUT_ABOVE_16(*r_dst); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->v_flag = VFLAG_ADD_16(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | (mc68kcpu)->not_z_flag; +} + + +void m68000_base_device_ops::m68k_op_add_16_er_aw(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = OPER_AW_16(mc68kcpu); + UINT32 dst = MASK_OUT_ABOVE_16(*r_dst); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->v_flag = VFLAG_ADD_16(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | (mc68kcpu)->not_z_flag; +} + + +void m68000_base_device_ops::m68k_op_add_16_er_al(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = OPER_AL_16(mc68kcpu); + UINT32 dst = MASK_OUT_ABOVE_16(*r_dst); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->v_flag = VFLAG_ADD_16(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | (mc68kcpu)->not_z_flag; +} + + +void m68000_base_device_ops::m68k_op_add_16_er_pcdi(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = OPER_PCDI_16(mc68kcpu); + UINT32 dst = MASK_OUT_ABOVE_16(*r_dst); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->v_flag = VFLAG_ADD_16(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | (mc68kcpu)->not_z_flag; +} + + +void m68000_base_device_ops::m68k_op_add_16_er_pcix(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = OPER_PCIX_16(mc68kcpu); + UINT32 dst = MASK_OUT_ABOVE_16(*r_dst); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->v_flag = VFLAG_ADD_16(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | (mc68kcpu)->not_z_flag; +} + + +void m68000_base_device_ops::m68k_op_add_16_er_i(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = OPER_I_16(mc68kcpu); + UINT32 dst = MASK_OUT_ABOVE_16(*r_dst); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->v_flag = VFLAG_ADD_16(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | (mc68kcpu)->not_z_flag; +} + + +void m68000_base_device_ops::m68k_op_add_32_er_d(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = DY(mc68kcpu); + UINT32 dst = *r_dst; + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->v_flag = VFLAG_ADD_32(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_ADD_32(src, dst, res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + + *r_dst = (mc68kcpu)->not_z_flag; +} + + +void m68000_base_device_ops::m68k_op_add_32_er_a(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = AY(mc68kcpu); + UINT32 dst = *r_dst; + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->v_flag = VFLAG_ADD_32(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_ADD_32(src, dst, res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + + *r_dst = (mc68kcpu)->not_z_flag; +} + + +void m68000_base_device_ops::m68k_op_add_32_er_ai(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = OPER_AY_AI_32(mc68kcpu); + UINT32 dst = *r_dst; + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->v_flag = VFLAG_ADD_32(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_ADD_32(src, dst, res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + + *r_dst = (mc68kcpu)->not_z_flag; +} + + +void m68000_base_device_ops::m68k_op_add_32_er_pi(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = OPER_AY_PI_32(mc68kcpu); + UINT32 dst = *r_dst; + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->v_flag = VFLAG_ADD_32(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_ADD_32(src, dst, res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + + *r_dst = (mc68kcpu)->not_z_flag; +} + + +void m68000_base_device_ops::m68k_op_add_32_er_pd(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = OPER_AY_PD_32(mc68kcpu); + UINT32 dst = *r_dst; + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->v_flag = VFLAG_ADD_32(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_ADD_32(src, dst, res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + + *r_dst = (mc68kcpu)->not_z_flag; +} + + +void m68000_base_device_ops::m68k_op_add_32_er_di(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = OPER_AY_DI_32(mc68kcpu); + UINT32 dst = *r_dst; + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->v_flag = VFLAG_ADD_32(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_ADD_32(src, dst, res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + + *r_dst = (mc68kcpu)->not_z_flag; +} + + +void m68000_base_device_ops::m68k_op_add_32_er_ix(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = OPER_AY_IX_32(mc68kcpu); + UINT32 dst = *r_dst; + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->v_flag = VFLAG_ADD_32(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_ADD_32(src, dst, res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + + *r_dst = (mc68kcpu)->not_z_flag; +} + + +void m68000_base_device_ops::m68k_op_add_32_er_aw(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = OPER_AW_32(mc68kcpu); + UINT32 dst = *r_dst; + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->v_flag = VFLAG_ADD_32(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_ADD_32(src, dst, res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + + *r_dst = (mc68kcpu)->not_z_flag; +} + + +void m68000_base_device_ops::m68k_op_add_32_er_al(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = OPER_AL_32(mc68kcpu); + UINT32 dst = *r_dst; + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->v_flag = VFLAG_ADD_32(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_ADD_32(src, dst, res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + + *r_dst = (mc68kcpu)->not_z_flag; +} + + +void m68000_base_device_ops::m68k_op_add_32_er_pcdi(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = OPER_PCDI_32(mc68kcpu); + UINT32 dst = *r_dst; + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->v_flag = VFLAG_ADD_32(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_ADD_32(src, dst, res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + + *r_dst = (mc68kcpu)->not_z_flag; +} + + +void m68000_base_device_ops::m68k_op_add_32_er_pcix(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = OPER_PCIX_32(mc68kcpu); + UINT32 dst = *r_dst; + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->v_flag = VFLAG_ADD_32(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_ADD_32(src, dst, res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + + *r_dst = (mc68kcpu)->not_z_flag; +} + + +void m68000_base_device_ops::m68k_op_add_32_er_i(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = OPER_I_32(mc68kcpu); + UINT32 dst = *r_dst; + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->v_flag = VFLAG_ADD_32(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_ADD_32(src, dst, res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + + *r_dst = (mc68kcpu)->not_z_flag; +} + + +void m68000_base_device_ops::m68k_op_add_8_re_ai(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_AI_8(mc68kcpu); + UINT32 src = MASK_OUT_ABOVE_8(DX(mc68kcpu)); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_ADD_8(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + + m68ki_write_8((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_add_8_re_pi(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_PI_8(mc68kcpu); + UINT32 src = MASK_OUT_ABOVE_8(DX(mc68kcpu)); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_ADD_8(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + + m68ki_write_8((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_add_8_re_pi7(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_A7_PI_8(mc68kcpu); + UINT32 src = MASK_OUT_ABOVE_8(DX(mc68kcpu)); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_ADD_8(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + + m68ki_write_8((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_add_8_re_pd(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_PD_8(mc68kcpu); + UINT32 src = MASK_OUT_ABOVE_8(DX(mc68kcpu)); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_ADD_8(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + + m68ki_write_8((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_add_8_re_pd7(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_A7_PD_8(mc68kcpu); + UINT32 src = MASK_OUT_ABOVE_8(DX(mc68kcpu)); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_ADD_8(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + + m68ki_write_8((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_add_8_re_di(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_DI_8(mc68kcpu); + UINT32 src = MASK_OUT_ABOVE_8(DX(mc68kcpu)); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_ADD_8(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + + m68ki_write_8((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_add_8_re_ix(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_IX_8(mc68kcpu); + UINT32 src = MASK_OUT_ABOVE_8(DX(mc68kcpu)); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_ADD_8(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + + m68ki_write_8((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_add_8_re_aw(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AW_8(mc68kcpu); + UINT32 src = MASK_OUT_ABOVE_8(DX(mc68kcpu)); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_ADD_8(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + + m68ki_write_8((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_add_8_re_al(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AL_8(mc68kcpu); + UINT32 src = MASK_OUT_ABOVE_8(DX(mc68kcpu)); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_ADD_8(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + + m68ki_write_8((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_add_16_re_ai(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_AI_16(mc68kcpu); + UINT32 src = MASK_OUT_ABOVE_16(DX(mc68kcpu)); + UINT32 dst = m68ki_read_16((mc68kcpu), ea); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->v_flag = VFLAG_ADD_16(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + + m68ki_write_16((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_add_16_re_pi(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_PI_16(mc68kcpu); + UINT32 src = MASK_OUT_ABOVE_16(DX(mc68kcpu)); + UINT32 dst = m68ki_read_16((mc68kcpu), ea); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->v_flag = VFLAG_ADD_16(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + + m68ki_write_16((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_add_16_re_pd(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_PD_16(mc68kcpu); + UINT32 src = MASK_OUT_ABOVE_16(DX(mc68kcpu)); + UINT32 dst = m68ki_read_16((mc68kcpu), ea); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->v_flag = VFLAG_ADD_16(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + + m68ki_write_16((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_add_16_re_di(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_DI_16(mc68kcpu); + UINT32 src = MASK_OUT_ABOVE_16(DX(mc68kcpu)); + UINT32 dst = m68ki_read_16((mc68kcpu), ea); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->v_flag = VFLAG_ADD_16(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + + m68ki_write_16((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_add_16_re_ix(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_IX_16(mc68kcpu); + UINT32 src = MASK_OUT_ABOVE_16(DX(mc68kcpu)); + UINT32 dst = m68ki_read_16((mc68kcpu), ea); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->v_flag = VFLAG_ADD_16(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + + m68ki_write_16((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_add_16_re_aw(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AW_16(mc68kcpu); + UINT32 src = MASK_OUT_ABOVE_16(DX(mc68kcpu)); + UINT32 dst = m68ki_read_16((mc68kcpu), ea); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->v_flag = VFLAG_ADD_16(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + + m68ki_write_16((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_add_16_re_al(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AL_16(mc68kcpu); + UINT32 src = MASK_OUT_ABOVE_16(DX(mc68kcpu)); + UINT32 dst = m68ki_read_16((mc68kcpu), ea); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->v_flag = VFLAG_ADD_16(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + + m68ki_write_16((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_add_32_re_ai(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_AI_32(mc68kcpu); + UINT32 src = DX(mc68kcpu); + UINT32 dst = m68ki_read_32((mc68kcpu), ea); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->v_flag = VFLAG_ADD_32(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_ADD_32(src, dst, res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + + m68ki_write_32((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_add_32_re_pi(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_PI_32(mc68kcpu); + UINT32 src = DX(mc68kcpu); + UINT32 dst = m68ki_read_32((mc68kcpu), ea); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->v_flag = VFLAG_ADD_32(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_ADD_32(src, dst, res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + + m68ki_write_32((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_add_32_re_pd(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_PD_32(mc68kcpu); + UINT32 src = DX(mc68kcpu); + UINT32 dst = m68ki_read_32((mc68kcpu), ea); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->v_flag = VFLAG_ADD_32(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_ADD_32(src, dst, res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + + m68ki_write_32((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_add_32_re_di(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_DI_32(mc68kcpu); + UINT32 src = DX(mc68kcpu); + UINT32 dst = m68ki_read_32((mc68kcpu), ea); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->v_flag = VFLAG_ADD_32(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_ADD_32(src, dst, res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + + m68ki_write_32((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_add_32_re_ix(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_IX_32(mc68kcpu); + UINT32 src = DX(mc68kcpu); + UINT32 dst = m68ki_read_32((mc68kcpu), ea); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->v_flag = VFLAG_ADD_32(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_ADD_32(src, dst, res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + + m68ki_write_32((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_add_32_re_aw(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AW_32(mc68kcpu); + UINT32 src = DX(mc68kcpu); + UINT32 dst = m68ki_read_32((mc68kcpu), ea); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->v_flag = VFLAG_ADD_32(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_ADD_32(src, dst, res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + + m68ki_write_32((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_add_32_re_al(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AL_32(mc68kcpu); + UINT32 src = DX(mc68kcpu); + UINT32 dst = m68ki_read_32((mc68kcpu), ea); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->v_flag = VFLAG_ADD_32(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_ADD_32(src, dst, res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + + m68ki_write_32((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_adda_16_d(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &AX(mc68kcpu); + + *r_dst = MASK_OUT_ABOVE_32(*r_dst + MAKE_INT_16(DY(mc68kcpu))); +} + + +void m68000_base_device_ops::m68k_op_adda_16_a(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &AX(mc68kcpu); + + *r_dst = MASK_OUT_ABOVE_32(*r_dst + MAKE_INT_16(AY(mc68kcpu))); +} + + +void m68000_base_device_ops::m68k_op_adda_16_ai(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &AX(mc68kcpu); + UINT32 src = MAKE_INT_16(OPER_AY_AI_16(mc68kcpu)); + + *r_dst = MASK_OUT_ABOVE_32(*r_dst + src); +} + + +void m68000_base_device_ops::m68k_op_adda_16_pi(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &AX(mc68kcpu); + UINT32 src = MAKE_INT_16(OPER_AY_PI_16(mc68kcpu)); + + *r_dst = MASK_OUT_ABOVE_32(*r_dst + src); +} + + +void m68000_base_device_ops::m68k_op_adda_16_pd(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &AX(mc68kcpu); + UINT32 src = MAKE_INT_16(OPER_AY_PD_16(mc68kcpu)); + + *r_dst = MASK_OUT_ABOVE_32(*r_dst + src); +} + + +void m68000_base_device_ops::m68k_op_adda_16_di(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &AX(mc68kcpu); + UINT32 src = MAKE_INT_16(OPER_AY_DI_16(mc68kcpu)); + + *r_dst = MASK_OUT_ABOVE_32(*r_dst + src); +} + + +void m68000_base_device_ops::m68k_op_adda_16_ix(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &AX(mc68kcpu); + UINT32 src = MAKE_INT_16(OPER_AY_IX_16(mc68kcpu)); + + *r_dst = MASK_OUT_ABOVE_32(*r_dst + src); +} + + +void m68000_base_device_ops::m68k_op_adda_16_aw(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &AX(mc68kcpu); + UINT32 src = MAKE_INT_16(OPER_AW_16(mc68kcpu)); + + *r_dst = MASK_OUT_ABOVE_32(*r_dst + src); +} + + +void m68000_base_device_ops::m68k_op_adda_16_al(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &AX(mc68kcpu); + UINT32 src = MAKE_INT_16(OPER_AL_16(mc68kcpu)); + + *r_dst = MASK_OUT_ABOVE_32(*r_dst + src); +} + + +void m68000_base_device_ops::m68k_op_adda_16_pcdi(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &AX(mc68kcpu); + UINT32 src = MAKE_INT_16(OPER_PCDI_16(mc68kcpu)); + + *r_dst = MASK_OUT_ABOVE_32(*r_dst + src); +} + + +void m68000_base_device_ops::m68k_op_adda_16_pcix(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &AX(mc68kcpu); + UINT32 src = MAKE_INT_16(OPER_PCIX_16(mc68kcpu)); + + *r_dst = MASK_OUT_ABOVE_32(*r_dst + src); +} + + +void m68000_base_device_ops::m68k_op_adda_16_i(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &AX(mc68kcpu); + UINT32 src = MAKE_INT_16(OPER_I_16(mc68kcpu)); + + *r_dst = MASK_OUT_ABOVE_32(*r_dst + src); +} + + +void m68000_base_device_ops::m68k_op_adda_32_d(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &AX(mc68kcpu); + + *r_dst = MASK_OUT_ABOVE_32(*r_dst + DY(mc68kcpu)); +} + + +void m68000_base_device_ops::m68k_op_adda_32_a(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &AX(mc68kcpu); + + *r_dst = MASK_OUT_ABOVE_32(*r_dst + AY(mc68kcpu)); +} + + +void m68000_base_device_ops::m68k_op_adda_32_ai(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &AX(mc68kcpu); + UINT32 src = OPER_AY_AI_32(mc68kcpu); + + *r_dst = MASK_OUT_ABOVE_32(*r_dst + src); +} + + +void m68000_base_device_ops::m68k_op_adda_32_pi(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &AX(mc68kcpu); + UINT32 src = OPER_AY_PI_32(mc68kcpu); + + *r_dst = MASK_OUT_ABOVE_32(*r_dst + src); +} + + +void m68000_base_device_ops::m68k_op_adda_32_pd(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &AX(mc68kcpu); + UINT32 src = OPER_AY_PD_32(mc68kcpu); + + *r_dst = MASK_OUT_ABOVE_32(*r_dst + src); +} + + +void m68000_base_device_ops::m68k_op_adda_32_di(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &AX(mc68kcpu); + UINT32 src = OPER_AY_DI_32(mc68kcpu); + + *r_dst = MASK_OUT_ABOVE_32(*r_dst + src); +} + + +void m68000_base_device_ops::m68k_op_adda_32_ix(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &AX(mc68kcpu); + UINT32 src = OPER_AY_IX_32(mc68kcpu); + + *r_dst = MASK_OUT_ABOVE_32(*r_dst + src); +} + + +void m68000_base_device_ops::m68k_op_adda_32_aw(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &AX(mc68kcpu); + UINT32 src = OPER_AW_32(mc68kcpu); + + *r_dst = MASK_OUT_ABOVE_32(*r_dst + src); +} + + +void m68000_base_device_ops::m68k_op_adda_32_al(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &AX(mc68kcpu); + UINT32 src = OPER_AL_32(mc68kcpu); + + *r_dst = MASK_OUT_ABOVE_32(*r_dst + src); +} + + +void m68000_base_device_ops::m68k_op_adda_32_pcdi(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &AX(mc68kcpu); + UINT32 src = OPER_PCDI_32(mc68kcpu); + + *r_dst = MASK_OUT_ABOVE_32(*r_dst + src); +} + + +void m68000_base_device_ops::m68k_op_adda_32_pcix(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &AX(mc68kcpu); + UINT32 src = OPER_PCIX_32(mc68kcpu); + + *r_dst = MASK_OUT_ABOVE_32(*r_dst + src); +} + + +void m68000_base_device_ops::m68k_op_adda_32_i(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &AX(mc68kcpu); + UINT32 src = OPER_I_32(mc68kcpu); + + *r_dst = MASK_OUT_ABOVE_32(*r_dst + src); +} + + +void m68000_base_device_ops::m68k_op_addi_8_d(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 src = OPER_I_8(mc68kcpu); + UINT32 dst = MASK_OUT_ABOVE_8(*r_dst); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_ADD_8(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | (mc68kcpu)->not_z_flag; +} + + +void m68000_base_device_ops::m68k_op_addi_8_ai(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_8(mc68kcpu); + UINT32 ea = EA_AY_AI_8(mc68kcpu); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_ADD_8(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + + m68ki_write_8((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_addi_8_pi(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_8(mc68kcpu); + UINT32 ea = EA_AY_PI_8(mc68kcpu); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_ADD_8(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + + m68ki_write_8((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_addi_8_pi7(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_8(mc68kcpu); + UINT32 ea = EA_A7_PI_8(mc68kcpu); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_ADD_8(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + + m68ki_write_8((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_addi_8_pd(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_8(mc68kcpu); + UINT32 ea = EA_AY_PD_8(mc68kcpu); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_ADD_8(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + + m68ki_write_8((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_addi_8_pd7(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_8(mc68kcpu); + UINT32 ea = EA_A7_PD_8(mc68kcpu); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_ADD_8(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + + m68ki_write_8((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_addi_8_di(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_8(mc68kcpu); + UINT32 ea = EA_AY_DI_8(mc68kcpu); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_ADD_8(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + + m68ki_write_8((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_addi_8_ix(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_8(mc68kcpu); + UINT32 ea = EA_AY_IX_8(mc68kcpu); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_ADD_8(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + + m68ki_write_8((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_addi_8_aw(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_8(mc68kcpu); + UINT32 ea = EA_AW_8(mc68kcpu); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_ADD_8(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + + m68ki_write_8((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_addi_8_al(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_8(mc68kcpu); + UINT32 ea = EA_AL_8(mc68kcpu); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_ADD_8(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + + m68ki_write_8((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_addi_16_d(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 src = OPER_I_16(mc68kcpu); + UINT32 dst = MASK_OUT_ABOVE_16(*r_dst); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->v_flag = VFLAG_ADD_16(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | (mc68kcpu)->not_z_flag; +} + + +void m68000_base_device_ops::m68k_op_addi_16_ai(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_16(mc68kcpu); + UINT32 ea = EA_AY_AI_16(mc68kcpu); + UINT32 dst = m68ki_read_16((mc68kcpu), ea); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->v_flag = VFLAG_ADD_16(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + + m68ki_write_16((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_addi_16_pi(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_16(mc68kcpu); + UINT32 ea = EA_AY_PI_16(mc68kcpu); + UINT32 dst = m68ki_read_16((mc68kcpu), ea); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->v_flag = VFLAG_ADD_16(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + + m68ki_write_16((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_addi_16_pd(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_16(mc68kcpu); + UINT32 ea = EA_AY_PD_16(mc68kcpu); + UINT32 dst = m68ki_read_16((mc68kcpu), ea); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->v_flag = VFLAG_ADD_16(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + + m68ki_write_16((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_addi_16_di(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_16(mc68kcpu); + UINT32 ea = EA_AY_DI_16(mc68kcpu); + UINT32 dst = m68ki_read_16((mc68kcpu), ea); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->v_flag = VFLAG_ADD_16(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + + m68ki_write_16((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_addi_16_ix(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_16(mc68kcpu); + UINT32 ea = EA_AY_IX_16(mc68kcpu); + UINT32 dst = m68ki_read_16((mc68kcpu), ea); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->v_flag = VFLAG_ADD_16(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + + m68ki_write_16((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_addi_16_aw(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_16(mc68kcpu); + UINT32 ea = EA_AW_16(mc68kcpu); + UINT32 dst = m68ki_read_16((mc68kcpu), ea); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->v_flag = VFLAG_ADD_16(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + + m68ki_write_16((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_addi_16_al(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_16(mc68kcpu); + UINT32 ea = EA_AL_16(mc68kcpu); + UINT32 dst = m68ki_read_16((mc68kcpu), ea); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->v_flag = VFLAG_ADD_16(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + + m68ki_write_16((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_addi_32_d(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 src = OPER_I_32(mc68kcpu); + UINT32 dst = *r_dst; + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->v_flag = VFLAG_ADD_32(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_ADD_32(src, dst, res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + + *r_dst = (mc68kcpu)->not_z_flag; +} + + +void m68000_base_device_ops::m68k_op_addi_32_ai(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_32(mc68kcpu); + UINT32 ea = EA_AY_AI_32(mc68kcpu); + UINT32 dst = m68ki_read_32((mc68kcpu), ea); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->v_flag = VFLAG_ADD_32(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_ADD_32(src, dst, res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + + m68ki_write_32((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_addi_32_pi(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_32(mc68kcpu); + UINT32 ea = EA_AY_PI_32(mc68kcpu); + UINT32 dst = m68ki_read_32((mc68kcpu), ea); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->v_flag = VFLAG_ADD_32(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_ADD_32(src, dst, res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + + m68ki_write_32((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_addi_32_pd(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_32(mc68kcpu); + UINT32 ea = EA_AY_PD_32(mc68kcpu); + UINT32 dst = m68ki_read_32((mc68kcpu), ea); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->v_flag = VFLAG_ADD_32(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_ADD_32(src, dst, res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + + m68ki_write_32((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_addi_32_di(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_32(mc68kcpu); + UINT32 ea = EA_AY_DI_32(mc68kcpu); + UINT32 dst = m68ki_read_32((mc68kcpu), ea); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->v_flag = VFLAG_ADD_32(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_ADD_32(src, dst, res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + + m68ki_write_32((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_addi_32_ix(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_32(mc68kcpu); + UINT32 ea = EA_AY_IX_32(mc68kcpu); + UINT32 dst = m68ki_read_32((mc68kcpu), ea); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->v_flag = VFLAG_ADD_32(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_ADD_32(src, dst, res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + + m68ki_write_32((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_addi_32_aw(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_32(mc68kcpu); + UINT32 ea = EA_AW_32(mc68kcpu); + UINT32 dst = m68ki_read_32((mc68kcpu), ea); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->v_flag = VFLAG_ADD_32(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_ADD_32(src, dst, res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + + m68ki_write_32((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_addi_32_al(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_32(mc68kcpu); + UINT32 ea = EA_AL_32(mc68kcpu); + UINT32 dst = m68ki_read_32((mc68kcpu), ea); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->v_flag = VFLAG_ADD_32(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_ADD_32(src, dst, res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + + m68ki_write_32((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_addq_8_d(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 src = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT32 dst = MASK_OUT_ABOVE_8(*r_dst); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_ADD_8(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | (mc68kcpu)->not_z_flag; +} + + +void m68000_base_device_ops::m68k_op_addq_8_ai(m68000_base_device* mc68kcpu) +{ + UINT32 src = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT32 ea = EA_AY_AI_8(mc68kcpu); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_ADD_8(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + + m68ki_write_8((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_addq_8_pi(m68000_base_device* mc68kcpu) +{ + UINT32 src = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT32 ea = EA_AY_PI_8(mc68kcpu); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_ADD_8(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + + m68ki_write_8((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_addq_8_pi7(m68000_base_device* mc68kcpu) +{ + UINT32 src = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT32 ea = EA_A7_PI_8(mc68kcpu); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_ADD_8(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + + m68ki_write_8((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_addq_8_pd(m68000_base_device* mc68kcpu) +{ + UINT32 src = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT32 ea = EA_AY_PD_8(mc68kcpu); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_ADD_8(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + + m68ki_write_8((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_addq_8_pd7(m68000_base_device* mc68kcpu) +{ + UINT32 src = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT32 ea = EA_A7_PD_8(mc68kcpu); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_ADD_8(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + + m68ki_write_8((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_addq_8_di(m68000_base_device* mc68kcpu) +{ + UINT32 src = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT32 ea = EA_AY_DI_8(mc68kcpu); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_ADD_8(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + + m68ki_write_8((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_addq_8_ix(m68000_base_device* mc68kcpu) +{ + UINT32 src = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT32 ea = EA_AY_IX_8(mc68kcpu); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_ADD_8(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + + m68ki_write_8((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_addq_8_aw(m68000_base_device* mc68kcpu) +{ + UINT32 src = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT32 ea = EA_AW_8(mc68kcpu); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_ADD_8(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + + m68ki_write_8((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_addq_8_al(m68000_base_device* mc68kcpu) +{ + UINT32 src = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT32 ea = EA_AL_8(mc68kcpu); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_ADD_8(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + + m68ki_write_8((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_addq_16_d(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 src = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT32 dst = MASK_OUT_ABOVE_16(*r_dst); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->v_flag = VFLAG_ADD_16(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | (mc68kcpu)->not_z_flag; +} + + +void m68000_base_device_ops::m68k_op_addq_16_a(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &AY(mc68kcpu); + + *r_dst = MASK_OUT_ABOVE_32(*r_dst + ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1); +} + + +void m68000_base_device_ops::m68k_op_addq_16_ai(m68000_base_device* mc68kcpu) +{ + UINT32 src = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT32 ea = EA_AY_AI_16(mc68kcpu); + UINT32 dst = m68ki_read_16((mc68kcpu), ea); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->v_flag = VFLAG_ADD_16(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + + m68ki_write_16((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_addq_16_pi(m68000_base_device* mc68kcpu) +{ + UINT32 src = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT32 ea = EA_AY_PI_16(mc68kcpu); + UINT32 dst = m68ki_read_16((mc68kcpu), ea); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->v_flag = VFLAG_ADD_16(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + + m68ki_write_16((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_addq_16_pd(m68000_base_device* mc68kcpu) +{ + UINT32 src = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT32 ea = EA_AY_PD_16(mc68kcpu); + UINT32 dst = m68ki_read_16((mc68kcpu), ea); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->v_flag = VFLAG_ADD_16(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + + m68ki_write_16((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_addq_16_di(m68000_base_device* mc68kcpu) +{ + UINT32 src = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT32 ea = EA_AY_DI_16(mc68kcpu); + UINT32 dst = m68ki_read_16((mc68kcpu), ea); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->v_flag = VFLAG_ADD_16(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + + m68ki_write_16((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_addq_16_ix(m68000_base_device* mc68kcpu) +{ + UINT32 src = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT32 ea = EA_AY_IX_16(mc68kcpu); + UINT32 dst = m68ki_read_16((mc68kcpu), ea); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->v_flag = VFLAG_ADD_16(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + + m68ki_write_16((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_addq_16_aw(m68000_base_device* mc68kcpu) +{ + UINT32 src = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT32 ea = EA_AW_16(mc68kcpu); + UINT32 dst = m68ki_read_16((mc68kcpu), ea); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->v_flag = VFLAG_ADD_16(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + + m68ki_write_16((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_addq_16_al(m68000_base_device* mc68kcpu) +{ + UINT32 src = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT32 ea = EA_AL_16(mc68kcpu); + UINT32 dst = m68ki_read_16((mc68kcpu), ea); + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->v_flag = VFLAG_ADD_16(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + + m68ki_write_16((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_addq_32_d(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 src = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT32 dst = *r_dst; + UINT32 res = src + dst; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->v_flag = VFLAG_ADD_32(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_ADD_32(src, dst, res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + + *r_dst = (mc68kcpu)->not_z_flag; +} + + +void m68000_base_device_ops::m68k_op_addq_32_a(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &AY(mc68kcpu); + + *r_dst = MASK_OUT_ABOVE_32(*r_dst + ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1); +} + + +void m68000_base_device_ops::m68k_op_addq_32_ai(m68000_base_device* mc68kcpu) +{ + UINT32 src = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT32 ea = EA_AY_AI_32(mc68kcpu); + UINT32 dst = m68ki_read_32((mc68kcpu), ea); + UINT32 res = src + dst; + + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->v_flag = VFLAG_ADD_32(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_ADD_32(src, dst, res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + + m68ki_write_32((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_addq_32_pi(m68000_base_device* mc68kcpu) +{ + UINT32 src = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT32 ea = EA_AY_PI_32(mc68kcpu); + UINT32 dst = m68ki_read_32((mc68kcpu), ea); + UINT32 res = src + dst; + + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->v_flag = VFLAG_ADD_32(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_ADD_32(src, dst, res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + + m68ki_write_32((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_addq_32_pd(m68000_base_device* mc68kcpu) +{ + UINT32 src = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT32 ea = EA_AY_PD_32(mc68kcpu); + UINT32 dst = m68ki_read_32((mc68kcpu), ea); + UINT32 res = src + dst; + + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->v_flag = VFLAG_ADD_32(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_ADD_32(src, dst, res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + + m68ki_write_32((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_addq_32_di(m68000_base_device* mc68kcpu) +{ + UINT32 src = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT32 ea = EA_AY_DI_32(mc68kcpu); + UINT32 dst = m68ki_read_32((mc68kcpu), ea); + UINT32 res = src + dst; + + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->v_flag = VFLAG_ADD_32(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_ADD_32(src, dst, res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + + m68ki_write_32((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_addq_32_ix(m68000_base_device* mc68kcpu) +{ + UINT32 src = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT32 ea = EA_AY_IX_32(mc68kcpu); + UINT32 dst = m68ki_read_32((mc68kcpu), ea); + UINT32 res = src + dst; + + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->v_flag = VFLAG_ADD_32(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_ADD_32(src, dst, res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + + m68ki_write_32((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_addq_32_aw(m68000_base_device* mc68kcpu) +{ + UINT32 src = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT32 ea = EA_AW_32(mc68kcpu); + UINT32 dst = m68ki_read_32((mc68kcpu), ea); + UINT32 res = src + dst; + + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->v_flag = VFLAG_ADD_32(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_ADD_32(src, dst, res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + + m68ki_write_32((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_addq_32_al(m68000_base_device* mc68kcpu) +{ + UINT32 src = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT32 ea = EA_AL_32(mc68kcpu); + UINT32 dst = m68ki_read_32((mc68kcpu), ea); + UINT32 res = src + dst; + + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->v_flag = VFLAG_ADD_32(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_ADD_32(src, dst, res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + + m68ki_write_32((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_addx_8_rr(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = MASK_OUT_ABOVE_8(DY(mc68kcpu)); + UINT32 dst = MASK_OUT_ABOVE_8(*r_dst); + UINT32 res = src + dst + XFLAG_AS_1(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_ADD_8(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + + res = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->not_z_flag |= res; + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; +} + + +void m68000_base_device_ops::m68k_op_addx_16_rr(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = MASK_OUT_ABOVE_16(DY(mc68kcpu)); + UINT32 dst = MASK_OUT_ABOVE_16(*r_dst); + UINT32 res = src + dst + XFLAG_AS_1(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->v_flag = VFLAG_ADD_16(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_16(res); + + res = MASK_OUT_ABOVE_16(res); + (mc68kcpu)->not_z_flag |= res; + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; +} + + +void m68000_base_device_ops::m68k_op_addx_32_rr(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = DY(mc68kcpu); + UINT32 dst = *r_dst; + UINT32 res = src + dst + XFLAG_AS_1(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->v_flag = VFLAG_ADD_32(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_ADD_32(src, dst, res); + + res = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->not_z_flag |= res; + + *r_dst = res; +} + + +void m68000_base_device_ops::m68k_op_addx_8_mm_ax7(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_AY_PD_8(mc68kcpu); + UINT32 ea = EA_A7_PD_8(mc68kcpu); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + UINT32 res = src + dst + XFLAG_AS_1(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_ADD_8(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + + res = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->not_z_flag |= res; + + m68ki_write_8((mc68kcpu), ea, res); +} + + +void m68000_base_device_ops::m68k_op_addx_8_mm_ay7(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_A7_PD_8(mc68kcpu); + UINT32 ea = EA_AX_PD_8(mc68kcpu); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + UINT32 res = src + dst + XFLAG_AS_1(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_ADD_8(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + + res = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->not_z_flag |= res; + + m68ki_write_8((mc68kcpu), ea, res); +} + + +void m68000_base_device_ops::m68k_op_addx_8_mm_axy7(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_A7_PD_8(mc68kcpu); + UINT32 ea = EA_A7_PD_8(mc68kcpu); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + UINT32 res = src + dst + XFLAG_AS_1(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_ADD_8(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + + res = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->not_z_flag |= res; + + m68ki_write_8((mc68kcpu), ea, res); +} + + +void m68000_base_device_ops::m68k_op_addx_8_mm(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_AY_PD_8(mc68kcpu); + UINT32 ea = EA_AX_PD_8(mc68kcpu); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + UINT32 res = src + dst + XFLAG_AS_1(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_ADD_8(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + + res = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->not_z_flag |= res; + + m68ki_write_8((mc68kcpu), ea, res); +} + + +void m68000_base_device_ops::m68k_op_addx_16_mm(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_AY_PD_16(mc68kcpu); + UINT32 ea = EA_AX_PD_16(mc68kcpu); + UINT32 dst = m68ki_read_16((mc68kcpu), ea); + UINT32 res = src + dst + XFLAG_AS_1(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->v_flag = VFLAG_ADD_16(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_16(res); + + res = MASK_OUT_ABOVE_16(res); + (mc68kcpu)->not_z_flag |= res; + + m68ki_write_16((mc68kcpu), ea, res); +} + + +void m68000_base_device_ops::m68k_op_addx_32_mm(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_AY_PD_32(mc68kcpu); + UINT32 ea = EA_AX_PD_32(mc68kcpu); + UINT32 dst = m68ki_read_32((mc68kcpu), ea); + UINT32 res = src + dst + XFLAG_AS_1(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->v_flag = VFLAG_ADD_32(src, dst, res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_ADD_32(src, dst, res); + + res = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->not_z_flag |= res; + + m68ki_write_32((mc68kcpu), ea, res); +} + + +void m68000_base_device_ops::m68k_op_and_8_er_d(m68000_base_device* mc68kcpu) +{ + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(DX(mc68kcpu) &= (DY(mc68kcpu) | 0xffffff00)); + + (mc68kcpu)->n_flag = NFLAG_8((mc68kcpu)->not_z_flag); + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_and_8_er_ai(m68000_base_device* mc68kcpu) +{ + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(DX(mc68kcpu) &= (OPER_AY_AI_8(mc68kcpu) | 0xffffff00)); + + (mc68kcpu)->n_flag = NFLAG_8((mc68kcpu)->not_z_flag); + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_and_8_er_pi(m68000_base_device* mc68kcpu) +{ + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(DX(mc68kcpu) &= (OPER_AY_PI_8(mc68kcpu) | 0xffffff00)); + + (mc68kcpu)->n_flag = NFLAG_8((mc68kcpu)->not_z_flag); + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_and_8_er_pi7(m68000_base_device* mc68kcpu) +{ + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(DX(mc68kcpu) &= (OPER_A7_PI_8(mc68kcpu) | 0xffffff00)); + + (mc68kcpu)->n_flag = NFLAG_8((mc68kcpu)->not_z_flag); + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_and_8_er_pd(m68000_base_device* mc68kcpu) +{ + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(DX(mc68kcpu) &= (OPER_AY_PD_8(mc68kcpu) | 0xffffff00)); + + (mc68kcpu)->n_flag = NFLAG_8((mc68kcpu)->not_z_flag); + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_and_8_er_pd7(m68000_base_device* mc68kcpu) +{ + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(DX(mc68kcpu) &= (OPER_A7_PD_8(mc68kcpu) | 0xffffff00)); + + (mc68kcpu)->n_flag = NFLAG_8((mc68kcpu)->not_z_flag); + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_and_8_er_di(m68000_base_device* mc68kcpu) +{ + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(DX(mc68kcpu) &= (OPER_AY_DI_8(mc68kcpu) | 0xffffff00)); + + (mc68kcpu)->n_flag = NFLAG_8((mc68kcpu)->not_z_flag); + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_and_8_er_ix(m68000_base_device* mc68kcpu) +{ + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(DX(mc68kcpu) &= (OPER_AY_IX_8(mc68kcpu) | 0xffffff00)); + + (mc68kcpu)->n_flag = NFLAG_8((mc68kcpu)->not_z_flag); + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_and_8_er_aw(m68000_base_device* mc68kcpu) +{ + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(DX(mc68kcpu) &= (OPER_AW_8(mc68kcpu) | 0xffffff00)); + + (mc68kcpu)->n_flag = NFLAG_8((mc68kcpu)->not_z_flag); + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_and_8_er_al(m68000_base_device* mc68kcpu) +{ + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(DX(mc68kcpu) &= (OPER_AL_8(mc68kcpu) | 0xffffff00)); + + (mc68kcpu)->n_flag = NFLAG_8((mc68kcpu)->not_z_flag); + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_and_8_er_pcdi(m68000_base_device* mc68kcpu) +{ + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(DX(mc68kcpu) &= (OPER_PCDI_8(mc68kcpu) | 0xffffff00)); + + (mc68kcpu)->n_flag = NFLAG_8((mc68kcpu)->not_z_flag); + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_and_8_er_pcix(m68000_base_device* mc68kcpu) +{ + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(DX(mc68kcpu) &= (OPER_PCIX_8(mc68kcpu) | 0xffffff00)); + + (mc68kcpu)->n_flag = NFLAG_8((mc68kcpu)->not_z_flag); + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_and_8_er_i(m68000_base_device* mc68kcpu) +{ + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(DX(mc68kcpu) &= (OPER_I_8(mc68kcpu) | 0xffffff00)); + + (mc68kcpu)->n_flag = NFLAG_8((mc68kcpu)->not_z_flag); + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_and_16_er_d(m68000_base_device* mc68kcpu) +{ + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(DX(mc68kcpu) &= (DY(mc68kcpu) | 0xffff0000)); + + (mc68kcpu)->n_flag = NFLAG_16((mc68kcpu)->not_z_flag); + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_and_16_er_ai(m68000_base_device* mc68kcpu) +{ + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(DX(mc68kcpu) &= (OPER_AY_AI_16(mc68kcpu) | 0xffff0000)); + + (mc68kcpu)->n_flag = NFLAG_16((mc68kcpu)->not_z_flag); + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_and_16_er_pi(m68000_base_device* mc68kcpu) +{ + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(DX(mc68kcpu) &= (OPER_AY_PI_16(mc68kcpu) | 0xffff0000)); + + (mc68kcpu)->n_flag = NFLAG_16((mc68kcpu)->not_z_flag); + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_and_16_er_pd(m68000_base_device* mc68kcpu) +{ + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(DX(mc68kcpu) &= (OPER_AY_PD_16(mc68kcpu) | 0xffff0000)); + + (mc68kcpu)->n_flag = NFLAG_16((mc68kcpu)->not_z_flag); + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_and_16_er_di(m68000_base_device* mc68kcpu) +{ + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(DX(mc68kcpu) &= (OPER_AY_DI_16(mc68kcpu) | 0xffff0000)); + + (mc68kcpu)->n_flag = NFLAG_16((mc68kcpu)->not_z_flag); + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_and_16_er_ix(m68000_base_device* mc68kcpu) +{ + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(DX(mc68kcpu) &= (OPER_AY_IX_16(mc68kcpu) | 0xffff0000)); + + (mc68kcpu)->n_flag = NFLAG_16((mc68kcpu)->not_z_flag); + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_and_16_er_aw(m68000_base_device* mc68kcpu) +{ + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(DX(mc68kcpu) &= (OPER_AW_16(mc68kcpu) | 0xffff0000)); + + (mc68kcpu)->n_flag = NFLAG_16((mc68kcpu)->not_z_flag); + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_and_16_er_al(m68000_base_device* mc68kcpu) +{ + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(DX(mc68kcpu) &= (OPER_AL_16(mc68kcpu) | 0xffff0000)); + + (mc68kcpu)->n_flag = NFLAG_16((mc68kcpu)->not_z_flag); + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_and_16_er_pcdi(m68000_base_device* mc68kcpu) +{ + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(DX(mc68kcpu) &= (OPER_PCDI_16(mc68kcpu) | 0xffff0000)); + + (mc68kcpu)->n_flag = NFLAG_16((mc68kcpu)->not_z_flag); + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_and_16_er_pcix(m68000_base_device* mc68kcpu) +{ + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(DX(mc68kcpu) &= (OPER_PCIX_16(mc68kcpu) | 0xffff0000)); + + (mc68kcpu)->n_flag = NFLAG_16((mc68kcpu)->not_z_flag); + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_and_16_er_i(m68000_base_device* mc68kcpu) +{ + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(DX(mc68kcpu) &= (OPER_I_16(mc68kcpu) | 0xffff0000)); + + (mc68kcpu)->n_flag = NFLAG_16((mc68kcpu)->not_z_flag); + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_and_32_er_d(m68000_base_device* mc68kcpu) +{ + (mc68kcpu)->not_z_flag = DX(mc68kcpu) &= DY(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_32((mc68kcpu)->not_z_flag); + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_and_32_er_ai(m68000_base_device* mc68kcpu) +{ + (mc68kcpu)->not_z_flag = DX(mc68kcpu) &= OPER_AY_AI_32(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_32((mc68kcpu)->not_z_flag); + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_and_32_er_pi(m68000_base_device* mc68kcpu) +{ + (mc68kcpu)->not_z_flag = DX(mc68kcpu) &= OPER_AY_PI_32(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_32((mc68kcpu)->not_z_flag); + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_and_32_er_pd(m68000_base_device* mc68kcpu) +{ + (mc68kcpu)->not_z_flag = DX(mc68kcpu) &= OPER_AY_PD_32(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_32((mc68kcpu)->not_z_flag); + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_and_32_er_di(m68000_base_device* mc68kcpu) +{ + (mc68kcpu)->not_z_flag = DX(mc68kcpu) &= OPER_AY_DI_32(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_32((mc68kcpu)->not_z_flag); + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_and_32_er_ix(m68000_base_device* mc68kcpu) +{ + (mc68kcpu)->not_z_flag = DX(mc68kcpu) &= OPER_AY_IX_32(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_32((mc68kcpu)->not_z_flag); + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_and_32_er_aw(m68000_base_device* mc68kcpu) +{ + (mc68kcpu)->not_z_flag = DX(mc68kcpu) &= OPER_AW_32(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_32((mc68kcpu)->not_z_flag); + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_and_32_er_al(m68000_base_device* mc68kcpu) +{ + (mc68kcpu)->not_z_flag = DX(mc68kcpu) &= OPER_AL_32(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_32((mc68kcpu)->not_z_flag); + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_and_32_er_pcdi(m68000_base_device* mc68kcpu) +{ + (mc68kcpu)->not_z_flag = DX(mc68kcpu) &= OPER_PCDI_32(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_32((mc68kcpu)->not_z_flag); + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_and_32_er_pcix(m68000_base_device* mc68kcpu) +{ + (mc68kcpu)->not_z_flag = DX(mc68kcpu) &= OPER_PCIX_32(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_32((mc68kcpu)->not_z_flag); + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_and_32_er_i(m68000_base_device* mc68kcpu) +{ + (mc68kcpu)->not_z_flag = DX(mc68kcpu) &= OPER_I_32(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_32((mc68kcpu)->not_z_flag); + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_and_8_re_ai(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_AI_8(mc68kcpu); + UINT32 res = DX(mc68kcpu) & m68ki_read_8((mc68kcpu), ea); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + + m68ki_write_8((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_and_8_re_pi(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_PI_8(mc68kcpu); + UINT32 res = DX(mc68kcpu) & m68ki_read_8((mc68kcpu), ea); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + + m68ki_write_8((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_and_8_re_pi7(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_A7_PI_8(mc68kcpu); + UINT32 res = DX(mc68kcpu) & m68ki_read_8((mc68kcpu), ea); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + + m68ki_write_8((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_and_8_re_pd(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_PD_8(mc68kcpu); + UINT32 res = DX(mc68kcpu) & m68ki_read_8((mc68kcpu), ea); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + + m68ki_write_8((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_and_8_re_pd7(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_A7_PD_8(mc68kcpu); + UINT32 res = DX(mc68kcpu) & m68ki_read_8((mc68kcpu), ea); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + + m68ki_write_8((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_and_8_re_di(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_DI_8(mc68kcpu); + UINT32 res = DX(mc68kcpu) & m68ki_read_8((mc68kcpu), ea); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + + m68ki_write_8((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_and_8_re_ix(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_IX_8(mc68kcpu); + UINT32 res = DX(mc68kcpu) & m68ki_read_8((mc68kcpu), ea); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + + m68ki_write_8((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_and_8_re_aw(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AW_8(mc68kcpu); + UINT32 res = DX(mc68kcpu) & m68ki_read_8((mc68kcpu), ea); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + + m68ki_write_8((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_and_8_re_al(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AL_8(mc68kcpu); + UINT32 res = DX(mc68kcpu) & m68ki_read_8((mc68kcpu), ea); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + + m68ki_write_8((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_and_16_re_ai(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_AI_16(mc68kcpu); + UINT32 res = DX(mc68kcpu) & m68ki_read_16((mc68kcpu), ea); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + + m68ki_write_16((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_and_16_re_pi(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_PI_16(mc68kcpu); + UINT32 res = DX(mc68kcpu) & m68ki_read_16((mc68kcpu), ea); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + + m68ki_write_16((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_and_16_re_pd(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_PD_16(mc68kcpu); + UINT32 res = DX(mc68kcpu) & m68ki_read_16((mc68kcpu), ea); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + + m68ki_write_16((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_and_16_re_di(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_DI_16(mc68kcpu); + UINT32 res = DX(mc68kcpu) & m68ki_read_16((mc68kcpu), ea); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + + m68ki_write_16((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_and_16_re_ix(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_IX_16(mc68kcpu); + UINT32 res = DX(mc68kcpu) & m68ki_read_16((mc68kcpu), ea); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + + m68ki_write_16((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_and_16_re_aw(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AW_16(mc68kcpu); + UINT32 res = DX(mc68kcpu) & m68ki_read_16((mc68kcpu), ea); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + + m68ki_write_16((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_and_16_re_al(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AL_16(mc68kcpu); + UINT32 res = DX(mc68kcpu) & m68ki_read_16((mc68kcpu), ea); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + + m68ki_write_16((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_and_32_re_ai(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_AI_32(mc68kcpu); + UINT32 res = DX(mc68kcpu) & m68ki_read_32((mc68kcpu), ea); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + + m68ki_write_32((mc68kcpu), ea, res); +} + + +void m68000_base_device_ops::m68k_op_and_32_re_pi(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_PI_32(mc68kcpu); + UINT32 res = DX(mc68kcpu) & m68ki_read_32((mc68kcpu), ea); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + + m68ki_write_32((mc68kcpu), ea, res); +} + + +void m68000_base_device_ops::m68k_op_and_32_re_pd(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_PD_32(mc68kcpu); + UINT32 res = DX(mc68kcpu) & m68ki_read_32((mc68kcpu), ea); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + + m68ki_write_32((mc68kcpu), ea, res); +} + + +void m68000_base_device_ops::m68k_op_and_32_re_di(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_DI_32(mc68kcpu); + UINT32 res = DX(mc68kcpu) & m68ki_read_32((mc68kcpu), ea); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + + m68ki_write_32((mc68kcpu), ea, res); +} + + +void m68000_base_device_ops::m68k_op_and_32_re_ix(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_IX_32(mc68kcpu); + UINT32 res = DX(mc68kcpu) & m68ki_read_32((mc68kcpu), ea); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + + m68ki_write_32((mc68kcpu), ea, res); +} + + +void m68000_base_device_ops::m68k_op_and_32_re_aw(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AW_32(mc68kcpu); + UINT32 res = DX(mc68kcpu) & m68ki_read_32((mc68kcpu), ea); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + + m68ki_write_32((mc68kcpu), ea, res); +} + + +void m68000_base_device_ops::m68k_op_and_32_re_al(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AL_32(mc68kcpu); + UINT32 res = DX(mc68kcpu) & m68ki_read_32((mc68kcpu), ea); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + + m68ki_write_32((mc68kcpu), ea, res); +} + + +void m68000_base_device_ops::m68k_op_andi_8_d(m68000_base_device* mc68kcpu) +{ + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(DY(mc68kcpu) &= (OPER_I_8(mc68kcpu) | 0xffffff00)); + + (mc68kcpu)->n_flag = NFLAG_8((mc68kcpu)->not_z_flag); + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_andi_8_ai(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_8(mc68kcpu); + UINT32 ea = EA_AY_AI_8(mc68kcpu); + UINT32 res = src & m68ki_read_8((mc68kcpu), ea); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + + m68ki_write_8((mc68kcpu), ea, res); +} + + +void m68000_base_device_ops::m68k_op_andi_8_pi(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_8(mc68kcpu); + UINT32 ea = EA_AY_PI_8(mc68kcpu); + UINT32 res = src & m68ki_read_8((mc68kcpu), ea); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + + m68ki_write_8((mc68kcpu), ea, res); +} + + +void m68000_base_device_ops::m68k_op_andi_8_pi7(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_8(mc68kcpu); + UINT32 ea = EA_A7_PI_8(mc68kcpu); + UINT32 res = src & m68ki_read_8((mc68kcpu), ea); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + + m68ki_write_8((mc68kcpu), ea, res); +} + + +void m68000_base_device_ops::m68k_op_andi_8_pd(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_8(mc68kcpu); + UINT32 ea = EA_AY_PD_8(mc68kcpu); + UINT32 res = src & m68ki_read_8((mc68kcpu), ea); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + + m68ki_write_8((mc68kcpu), ea, res); +} + + +void m68000_base_device_ops::m68k_op_andi_8_pd7(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_8(mc68kcpu); + UINT32 ea = EA_A7_PD_8(mc68kcpu); + UINT32 res = src & m68ki_read_8((mc68kcpu), ea); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + + m68ki_write_8((mc68kcpu), ea, res); +} + + +void m68000_base_device_ops::m68k_op_andi_8_di(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_8(mc68kcpu); + UINT32 ea = EA_AY_DI_8(mc68kcpu); + UINT32 res = src & m68ki_read_8((mc68kcpu), ea); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + + m68ki_write_8((mc68kcpu), ea, res); +} + + +void m68000_base_device_ops::m68k_op_andi_8_ix(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_8(mc68kcpu); + UINT32 ea = EA_AY_IX_8(mc68kcpu); + UINT32 res = src & m68ki_read_8((mc68kcpu), ea); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + + m68ki_write_8((mc68kcpu), ea, res); +} + + +void m68000_base_device_ops::m68k_op_andi_8_aw(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_8(mc68kcpu); + UINT32 ea = EA_AW_8(mc68kcpu); + UINT32 res = src & m68ki_read_8((mc68kcpu), ea); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + + m68ki_write_8((mc68kcpu), ea, res); +} + + +void m68000_base_device_ops::m68k_op_andi_8_al(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_8(mc68kcpu); + UINT32 ea = EA_AL_8(mc68kcpu); + UINT32 res = src & m68ki_read_8((mc68kcpu), ea); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + + m68ki_write_8((mc68kcpu), ea, res); +} + + +void m68000_base_device_ops::m68k_op_andi_16_d(m68000_base_device* mc68kcpu) +{ + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(DY(mc68kcpu) &= (OPER_I_16(mc68kcpu) | 0xffff0000)); + + (mc68kcpu)->n_flag = NFLAG_16((mc68kcpu)->not_z_flag); + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_andi_16_ai(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_16(mc68kcpu); + UINT32 ea = EA_AY_AI_16(mc68kcpu); + UINT32 res = src & m68ki_read_16((mc68kcpu), ea); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + + m68ki_write_16((mc68kcpu), ea, res); +} + + +void m68000_base_device_ops::m68k_op_andi_16_pi(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_16(mc68kcpu); + UINT32 ea = EA_AY_PI_16(mc68kcpu); + UINT32 res = src & m68ki_read_16((mc68kcpu), ea); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + + m68ki_write_16((mc68kcpu), ea, res); +} + + +void m68000_base_device_ops::m68k_op_andi_16_pd(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_16(mc68kcpu); + UINT32 ea = EA_AY_PD_16(mc68kcpu); + UINT32 res = src & m68ki_read_16((mc68kcpu), ea); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + + m68ki_write_16((mc68kcpu), ea, res); +} + + +void m68000_base_device_ops::m68k_op_andi_16_di(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_16(mc68kcpu); + UINT32 ea = EA_AY_DI_16(mc68kcpu); + UINT32 res = src & m68ki_read_16((mc68kcpu), ea); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + + m68ki_write_16((mc68kcpu), ea, res); +} + + +void m68000_base_device_ops::m68k_op_andi_16_ix(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_16(mc68kcpu); + UINT32 ea = EA_AY_IX_16(mc68kcpu); + UINT32 res = src & m68ki_read_16((mc68kcpu), ea); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + + m68ki_write_16((mc68kcpu), ea, res); +} + + +void m68000_base_device_ops::m68k_op_andi_16_aw(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_16(mc68kcpu); + UINT32 ea = EA_AW_16(mc68kcpu); + UINT32 res = src & m68ki_read_16((mc68kcpu), ea); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + + m68ki_write_16((mc68kcpu), ea, res); +} + + +void m68000_base_device_ops::m68k_op_andi_16_al(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_16(mc68kcpu); + UINT32 ea = EA_AL_16(mc68kcpu); + UINT32 res = src & m68ki_read_16((mc68kcpu), ea); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + + m68ki_write_16((mc68kcpu), ea, res); +} + + +void m68000_base_device_ops::m68k_op_andi_32_d(m68000_base_device* mc68kcpu) +{ + (mc68kcpu)->not_z_flag = DY(mc68kcpu) &= (OPER_I_32(mc68kcpu)); + + (mc68kcpu)->n_flag = NFLAG_32((mc68kcpu)->not_z_flag); + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_andi_32_ai(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_32(mc68kcpu); + UINT32 ea = EA_AY_AI_32(mc68kcpu); + UINT32 res = src & m68ki_read_32((mc68kcpu), ea); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + + m68ki_write_32((mc68kcpu), ea, res); +} + + +void m68000_base_device_ops::m68k_op_andi_32_pi(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_32(mc68kcpu); + UINT32 ea = EA_AY_PI_32(mc68kcpu); + UINT32 res = src & m68ki_read_32((mc68kcpu), ea); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + + m68ki_write_32((mc68kcpu), ea, res); +} + + +void m68000_base_device_ops::m68k_op_andi_32_pd(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_32(mc68kcpu); + UINT32 ea = EA_AY_PD_32(mc68kcpu); + UINT32 res = src & m68ki_read_32((mc68kcpu), ea); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + + m68ki_write_32((mc68kcpu), ea, res); +} + + +void m68000_base_device_ops::m68k_op_andi_32_di(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_32(mc68kcpu); + UINT32 ea = EA_AY_DI_32(mc68kcpu); + UINT32 res = src & m68ki_read_32((mc68kcpu), ea); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + + m68ki_write_32((mc68kcpu), ea, res); +} + + +void m68000_base_device_ops::m68k_op_andi_32_ix(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_32(mc68kcpu); + UINT32 ea = EA_AY_IX_32(mc68kcpu); + UINT32 res = src & m68ki_read_32((mc68kcpu), ea); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + + m68ki_write_32((mc68kcpu), ea, res); +} + + +void m68000_base_device_ops::m68k_op_andi_32_aw(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_32(mc68kcpu); + UINT32 ea = EA_AW_32(mc68kcpu); + UINT32 res = src & m68ki_read_32((mc68kcpu), ea); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + + m68ki_write_32((mc68kcpu), ea, res); +} + + +void m68000_base_device_ops::m68k_op_andi_32_al(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_32(mc68kcpu); + UINT32 ea = EA_AL_32(mc68kcpu); + UINT32 res = src & m68ki_read_32((mc68kcpu), ea); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + + m68ki_write_32((mc68kcpu), ea, res); +} + + +void m68000_base_device_ops::m68k_op_andi_16_toc(m68000_base_device* mc68kcpu) +{ + m68ki_set_ccr((mc68kcpu), m68ki_get_ccr(mc68kcpu) & OPER_I_16(mc68kcpu)); +} + + +void m68000_base_device_ops::m68k_op_andi_16_tos(m68000_base_device* mc68kcpu) +{ + if((mc68kcpu)->s_flag) + { + UINT32 src = OPER_I_16(mc68kcpu); + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_set_sr((mc68kcpu), m68ki_get_sr(mc68kcpu) & src); + return; + } + m68ki_exception_privilege_violation(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_asr_8_s(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 shift = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT32 src = MASK_OUT_ABOVE_8(*r_dst); + UINT32 res = src >> shift; + + if(shift != 0) + (mc68kcpu)->remaining_cycles -= shift<<(mc68kcpu)->cyc_shift; + + if(GET_MSB_8(src)) + res |= m68ki_shift_8_table[shift]; + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = src << (9-shift); +} + + +void m68000_base_device_ops::m68k_op_asr_16_s(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 shift = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT32 src = MASK_OUT_ABOVE_16(*r_dst); + UINT32 res = src >> shift; + + if(shift != 0) + (mc68kcpu)->remaining_cycles -= shift<<(mc68kcpu)->cyc_shift; + + if(GET_MSB_16(src)) + res |= m68ki_shift_16_table[shift]; + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = src << (9-shift); +} + + +void m68000_base_device_ops::m68k_op_asr_32_s(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 shift = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT32 src = *r_dst; + UINT32 res = src >> shift; + + if(shift != 0) + (mc68kcpu)->remaining_cycles -= shift<<(mc68kcpu)->cyc_shift; + + if(GET_MSB_32(src)) + res |= m68ki_shift_32_table[shift]; + + *r_dst = res; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = src << (9-shift); +} + + +void m68000_base_device_ops::m68k_op_asr_8_r(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 shift = DX(mc68kcpu) & 0x3f; + UINT32 src = MASK_OUT_ABOVE_8(*r_dst); + UINT32 res = src >> shift; + + if(shift != 0) + { + (mc68kcpu)->remaining_cycles -= shift<<(mc68kcpu)->cyc_shift; + + if(shift < 8) + { + if(GET_MSB_8(src)) + res |= m68ki_shift_8_table[shift]; + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; + + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = src << (9-shift); + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + return; + } + + if(GET_MSB_8(src)) + { + *r_dst |= 0xff; + (mc68kcpu)->c_flag = CFLAG_SET; + (mc68kcpu)->x_flag = XFLAG_SET; + (mc68kcpu)->n_flag = NFLAG_SET; + (mc68kcpu)->not_z_flag = ZFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + return; + } + + *r_dst &= 0xffffff00; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->x_flag = XFLAG_CLEAR; + (mc68kcpu)->n_flag = NFLAG_CLEAR; + (mc68kcpu)->not_z_flag = ZFLAG_SET; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + return; + } + + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->n_flag = NFLAG_8(src); + (mc68kcpu)->not_z_flag = src; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_asr_16_r(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 shift = DX(mc68kcpu) & 0x3f; + UINT32 src = MASK_OUT_ABOVE_16(*r_dst); + UINT32 res = src >> shift; + + if(shift != 0) + { + (mc68kcpu)->remaining_cycles -= shift<<(mc68kcpu)->cyc_shift; + + if(shift < 16) + { + if(GET_MSB_16(src)) + res |= m68ki_shift_16_table[shift]; + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag = (src >> (shift - 1))<<8; + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + return; + } + + if(GET_MSB_16(src)) + { + *r_dst |= 0xffff; + (mc68kcpu)->c_flag = CFLAG_SET; + (mc68kcpu)->x_flag = XFLAG_SET; + (mc68kcpu)->n_flag = NFLAG_SET; + (mc68kcpu)->not_z_flag = ZFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + return; + } + + *r_dst &= 0xffff0000; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->x_flag = XFLAG_CLEAR; + (mc68kcpu)->n_flag = NFLAG_CLEAR; + (mc68kcpu)->not_z_flag = ZFLAG_SET; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + return; + } + + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->n_flag = NFLAG_16(src); + (mc68kcpu)->not_z_flag = src; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_asr_32_r(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 shift = DX(mc68kcpu) & 0x3f; + UINT32 src = *r_dst; + UINT32 res = src >> shift; + + if(shift != 0) + { + (mc68kcpu)->remaining_cycles -= shift<<(mc68kcpu)->cyc_shift; + + if(shift < 32) + { + if(GET_MSB_32(src)) + res |= m68ki_shift_32_table[shift]; + + *r_dst = res; + + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag = (src >> (shift - 1))<<8; + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + return; + } + + if(GET_MSB_32(src)) + { + *r_dst = 0xffffffff; + (mc68kcpu)->c_flag = CFLAG_SET; + (mc68kcpu)->x_flag = XFLAG_SET; + (mc68kcpu)->n_flag = NFLAG_SET; + (mc68kcpu)->not_z_flag = ZFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + return; + } + + *r_dst = 0; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->x_flag = XFLAG_CLEAR; + (mc68kcpu)->n_flag = NFLAG_CLEAR; + (mc68kcpu)->not_z_flag = ZFLAG_SET; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + return; + } + + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->n_flag = NFLAG_32(src); + (mc68kcpu)->not_z_flag = src; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_asr_16_ai(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_AI_16(mc68kcpu); + UINT32 src = m68ki_read_16((mc68kcpu), ea); + UINT32 res = src >> 1; + + if(GET_MSB_16(src)) + res |= 0x8000; + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag = src << 8; +} + + +void m68000_base_device_ops::m68k_op_asr_16_pi(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_PI_16(mc68kcpu); + UINT32 src = m68ki_read_16((mc68kcpu), ea); + UINT32 res = src >> 1; + + if(GET_MSB_16(src)) + res |= 0x8000; + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag = src << 8; +} + + +void m68000_base_device_ops::m68k_op_asr_16_pd(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_PD_16(mc68kcpu); + UINT32 src = m68ki_read_16((mc68kcpu), ea); + UINT32 res = src >> 1; + + if(GET_MSB_16(src)) + res |= 0x8000; + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag = src << 8; +} + + +void m68000_base_device_ops::m68k_op_asr_16_di(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_DI_16(mc68kcpu); + UINT32 src = m68ki_read_16((mc68kcpu), ea); + UINT32 res = src >> 1; + + if(GET_MSB_16(src)) + res |= 0x8000; + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag = src << 8; +} + + +void m68000_base_device_ops::m68k_op_asr_16_ix(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_IX_16(mc68kcpu); + UINT32 src = m68ki_read_16((mc68kcpu), ea); + UINT32 res = src >> 1; + + if(GET_MSB_16(src)) + res |= 0x8000; + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag = src << 8; +} + + +void m68000_base_device_ops::m68k_op_asr_16_aw(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AW_16(mc68kcpu); + UINT32 src = m68ki_read_16((mc68kcpu), ea); + UINT32 res = src >> 1; + + if(GET_MSB_16(src)) + res |= 0x8000; + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag = src << 8; +} + + +void m68000_base_device_ops::m68k_op_asr_16_al(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AL_16(mc68kcpu); + UINT32 src = m68ki_read_16((mc68kcpu), ea); + UINT32 res = src >> 1; + + if(GET_MSB_16(src)) + res |= 0x8000; + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag = src << 8; +} + + +void m68000_base_device_ops::m68k_op_asl_8_s(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 shift = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT32 src = MASK_OUT_ABOVE_8(*r_dst); + UINT32 res = MASK_OUT_ABOVE_8(src << shift); + + if(shift != 0) + (mc68kcpu)->remaining_cycles -= shift<<(mc68kcpu)->cyc_shift; + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; + + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = src << shift; + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + src &= m68ki_shift_8_table[shift + 1]; + (mc68kcpu)->v_flag = (!(src == 0 || (src == m68ki_shift_8_table[shift + 1] && shift < 8)))<<7; +} + + +void m68000_base_device_ops::m68k_op_asl_16_s(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 shift = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT32 src = MASK_OUT_ABOVE_16(*r_dst); + UINT32 res = MASK_OUT_ABOVE_16(src << shift); + + if(shift != 0) + (mc68kcpu)->remaining_cycles -= shift<<(mc68kcpu)->cyc_shift; + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = src >> (8-shift); + src &= m68ki_shift_16_table[shift + 1]; + (mc68kcpu)->v_flag = (!(src == 0 || src == m68ki_shift_16_table[shift + 1]))<<7; +} + + +void m68000_base_device_ops::m68k_op_asl_32_s(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 shift = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT32 src = *r_dst; + UINT32 res = MASK_OUT_ABOVE_32(src << shift); + + if(shift != 0) + (mc68kcpu)->remaining_cycles -= shift<<(mc68kcpu)->cyc_shift; + + *r_dst = res; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = src >> (24-shift); + src &= m68ki_shift_32_table[shift + 1]; + (mc68kcpu)->v_flag = (!(src == 0 || src == m68ki_shift_32_table[shift + 1]))<<7; +} + + +void m68000_base_device_ops::m68k_op_asl_8_r(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 shift = DX(mc68kcpu) & 0x3f; + UINT32 src = MASK_OUT_ABOVE_8(*r_dst); + UINT32 res = MASK_OUT_ABOVE_8(src << shift); + + if(shift != 0) + { + (mc68kcpu)->remaining_cycles -= shift<<(mc68kcpu)->cyc_shift; + + if(shift < 8) + { + *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = src << shift; + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + src &= m68ki_shift_8_table[shift + 1]; + (mc68kcpu)->v_flag = (!(src == 0 || src == m68ki_shift_8_table[shift + 1]))<<7; + return; + } + + *r_dst &= 0xffffff00; + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = ((shift == 8 ? src & 1 : 0))<<8; + (mc68kcpu)->n_flag = NFLAG_CLEAR; + (mc68kcpu)->not_z_flag = ZFLAG_SET; + (mc68kcpu)->v_flag = (!(src == 0))<<7; + return; + } + + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->n_flag = NFLAG_8(src); + (mc68kcpu)->not_z_flag = src; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_asl_16_r(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 shift = DX(mc68kcpu) & 0x3f; + UINT32 src = MASK_OUT_ABOVE_16(*r_dst); + UINT32 res = MASK_OUT_ABOVE_16(src << shift); + + if(shift != 0) + { + (mc68kcpu)->remaining_cycles -= shift<<(mc68kcpu)->cyc_shift; + + if(shift < 16) + { + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = (src << shift) >> 8; + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + src &= m68ki_shift_16_table[shift + 1]; + (mc68kcpu)->v_flag = (!(src == 0 || src == m68ki_shift_16_table[shift + 1]))<<7; + return; + } + + *r_dst &= 0xffff0000; + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = ((shift == 16 ? src & 1 : 0))<<8; + (mc68kcpu)->n_flag = NFLAG_CLEAR; + (mc68kcpu)->not_z_flag = ZFLAG_SET; + (mc68kcpu)->v_flag = (!(src == 0))<<7; + return; + } + + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->n_flag = NFLAG_16(src); + (mc68kcpu)->not_z_flag = src; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_asl_32_r(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 shift = DX(mc68kcpu) & 0x3f; + UINT32 src = *r_dst; + UINT32 res = MASK_OUT_ABOVE_32(src << shift); + + if(shift != 0) + { + (mc68kcpu)->remaining_cycles -= shift<<(mc68kcpu)->cyc_shift; + + if(shift < 32) + { + *r_dst = res; + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = (src >> (32 - shift)) << 8; + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + src &= m68ki_shift_32_table[shift + 1]; + (mc68kcpu)->v_flag = (!(src == 0 || src == m68ki_shift_32_table[shift + 1]))<<7; + return; + } + + *r_dst = 0; + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = ((shift == 32 ? src & 1 : 0))<<8; + (mc68kcpu)->n_flag = NFLAG_CLEAR; + (mc68kcpu)->not_z_flag = ZFLAG_SET; + (mc68kcpu)->v_flag = (!(src == 0))<<7; + return; + } + + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->n_flag = NFLAG_32(src); + (mc68kcpu)->not_z_flag = src; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_asl_16_ai(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_AI_16(mc68kcpu); + UINT32 src = m68ki_read_16((mc68kcpu), ea); + UINT32 res = MASK_OUT_ABOVE_16(src << 1); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = src >> 7; + src &= 0xc000; + (mc68kcpu)->v_flag = (!(src == 0 || src == 0xc000))<<7; +} + + +void m68000_base_device_ops::m68k_op_asl_16_pi(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_PI_16(mc68kcpu); + UINT32 src = m68ki_read_16((mc68kcpu), ea); + UINT32 res = MASK_OUT_ABOVE_16(src << 1); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = src >> 7; + src &= 0xc000; + (mc68kcpu)->v_flag = (!(src == 0 || src == 0xc000))<<7; +} + + +void m68000_base_device_ops::m68k_op_asl_16_pd(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_PD_16(mc68kcpu); + UINT32 src = m68ki_read_16((mc68kcpu), ea); + UINT32 res = MASK_OUT_ABOVE_16(src << 1); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = src >> 7; + src &= 0xc000; + (mc68kcpu)->v_flag = (!(src == 0 || src == 0xc000))<<7; +} + + +void m68000_base_device_ops::m68k_op_asl_16_di(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_DI_16(mc68kcpu); + UINT32 src = m68ki_read_16((mc68kcpu), ea); + UINT32 res = MASK_OUT_ABOVE_16(src << 1); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = src >> 7; + src &= 0xc000; + (mc68kcpu)->v_flag = (!(src == 0 || src == 0xc000))<<7; +} + + +void m68000_base_device_ops::m68k_op_asl_16_ix(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_IX_16(mc68kcpu); + UINT32 src = m68ki_read_16((mc68kcpu), ea); + UINT32 res = MASK_OUT_ABOVE_16(src << 1); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = src >> 7; + src &= 0xc000; + (mc68kcpu)->v_flag = (!(src == 0 || src == 0xc000))<<7; +} + + +void m68000_base_device_ops::m68k_op_asl_16_aw(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AW_16(mc68kcpu); + UINT32 src = m68ki_read_16((mc68kcpu), ea); + UINT32 res = MASK_OUT_ABOVE_16(src << 1); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = src >> 7; + src &= 0xc000; + (mc68kcpu)->v_flag = (!(src == 0 || src == 0xc000))<<7; +} + + +void m68000_base_device_ops::m68k_op_asl_16_al(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AL_16(mc68kcpu); + UINT32 src = m68ki_read_16((mc68kcpu), ea); + UINT32 res = MASK_OUT_ABOVE_16(src << 1); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = src >> 7; + src &= 0xc000; + (mc68kcpu)->v_flag = (!(src == 0 || src == 0xc000))<<7; +} + + +void m68000_base_device_ops::m68k_op_bhi_8(m68000_base_device* mc68kcpu) +{ + if(COND_HI(mc68kcpu)) + { + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_8((mc68kcpu), MASK_OUT_ABOVE_8((mc68kcpu)->ir)); + return; + } + (mc68kcpu)->remaining_cycles -= (mc68kcpu)->cyc_bcc_notake_b; +} + + +void m68000_base_device_ops::m68k_op_bls_8(m68000_base_device* mc68kcpu) +{ + if(COND_LS(mc68kcpu)) + { + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_8((mc68kcpu), MASK_OUT_ABOVE_8((mc68kcpu)->ir)); + return; + } + (mc68kcpu)->remaining_cycles -= (mc68kcpu)->cyc_bcc_notake_b; +} + + +void m68000_base_device_ops::m68k_op_bcc_8(m68000_base_device* mc68kcpu) +{ + if(COND_CC(mc68kcpu)) + { + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_8((mc68kcpu), MASK_OUT_ABOVE_8((mc68kcpu)->ir)); + return; + } + (mc68kcpu)->remaining_cycles -= (mc68kcpu)->cyc_bcc_notake_b; +} + + +void m68000_base_device_ops::m68k_op_bcs_8(m68000_base_device* mc68kcpu) +{ + if(COND_CS(mc68kcpu)) + { + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_8((mc68kcpu), MASK_OUT_ABOVE_8((mc68kcpu)->ir)); + return; + } + (mc68kcpu)->remaining_cycles -= (mc68kcpu)->cyc_bcc_notake_b; +} + + +void m68000_base_device_ops::m68k_op_bne_8(m68000_base_device* mc68kcpu) +{ + if(COND_NE(mc68kcpu)) + { + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_8((mc68kcpu), MASK_OUT_ABOVE_8((mc68kcpu)->ir)); + return; + } + (mc68kcpu)->remaining_cycles -= (mc68kcpu)->cyc_bcc_notake_b; +} + + +void m68000_base_device_ops::m68k_op_beq_8(m68000_base_device* mc68kcpu) +{ + if(COND_EQ(mc68kcpu)) + { + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_8((mc68kcpu), MASK_OUT_ABOVE_8((mc68kcpu)->ir)); + return; + } + (mc68kcpu)->remaining_cycles -= (mc68kcpu)->cyc_bcc_notake_b; +} + + +void m68000_base_device_ops::m68k_op_bvc_8(m68000_base_device* mc68kcpu) +{ + if(COND_VC(mc68kcpu)) + { + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_8((mc68kcpu), MASK_OUT_ABOVE_8((mc68kcpu)->ir)); + return; + } + (mc68kcpu)->remaining_cycles -= (mc68kcpu)->cyc_bcc_notake_b; +} + + +void m68000_base_device_ops::m68k_op_bvs_8(m68000_base_device* mc68kcpu) +{ + if(COND_VS(mc68kcpu)) + { + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_8((mc68kcpu), MASK_OUT_ABOVE_8((mc68kcpu)->ir)); + return; + } + (mc68kcpu)->remaining_cycles -= (mc68kcpu)->cyc_bcc_notake_b; +} + + +void m68000_base_device_ops::m68k_op_bpl_8(m68000_base_device* mc68kcpu) +{ + if(COND_PL(mc68kcpu)) + { + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_8((mc68kcpu), MASK_OUT_ABOVE_8((mc68kcpu)->ir)); + return; + } + (mc68kcpu)->remaining_cycles -= (mc68kcpu)->cyc_bcc_notake_b; +} + + +void m68000_base_device_ops::m68k_op_bmi_8(m68000_base_device* mc68kcpu) +{ + if(COND_MI(mc68kcpu)) + { + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_8((mc68kcpu), MASK_OUT_ABOVE_8((mc68kcpu)->ir)); + return; + } + (mc68kcpu)->remaining_cycles -= (mc68kcpu)->cyc_bcc_notake_b; +} + + +void m68000_base_device_ops::m68k_op_bge_8(m68000_base_device* mc68kcpu) +{ + if(COND_GE(mc68kcpu)) + { + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_8((mc68kcpu), MASK_OUT_ABOVE_8((mc68kcpu)->ir)); + return; + } + (mc68kcpu)->remaining_cycles -= (mc68kcpu)->cyc_bcc_notake_b; +} + + +void m68000_base_device_ops::m68k_op_blt_8(m68000_base_device* mc68kcpu) +{ + if(COND_LT(mc68kcpu)) + { + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_8((mc68kcpu), MASK_OUT_ABOVE_8((mc68kcpu)->ir)); + return; + } + (mc68kcpu)->remaining_cycles -= (mc68kcpu)->cyc_bcc_notake_b; +} + + +void m68000_base_device_ops::m68k_op_bgt_8(m68000_base_device* mc68kcpu) +{ + if(COND_GT(mc68kcpu)) + { + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_8((mc68kcpu), MASK_OUT_ABOVE_8((mc68kcpu)->ir)); + return; + } + (mc68kcpu)->remaining_cycles -= (mc68kcpu)->cyc_bcc_notake_b; +} + + +void m68000_base_device_ops::m68k_op_ble_8(m68000_base_device* mc68kcpu) +{ + if(COND_LE(mc68kcpu)) + { + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_8((mc68kcpu), MASK_OUT_ABOVE_8((mc68kcpu)->ir)); + return; + } + (mc68kcpu)->remaining_cycles -= (mc68kcpu)->cyc_bcc_notake_b; +} + + +void m68000_base_device_ops::m68k_op_bhi_16(m68000_base_device* mc68kcpu) +{ + if(COND_HI(mc68kcpu)) + { + UINT32 offset = OPER_I_16(mc68kcpu); + REG_PC(mc68kcpu) -= 2; + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_16((mc68kcpu), offset); + return; + } + REG_PC(mc68kcpu) += 2; + (mc68kcpu)->remaining_cycles -= (mc68kcpu)->cyc_bcc_notake_w; +} + + +void m68000_base_device_ops::m68k_op_bls_16(m68000_base_device* mc68kcpu) +{ + if(COND_LS(mc68kcpu)) + { + UINT32 offset = OPER_I_16(mc68kcpu); + REG_PC(mc68kcpu) -= 2; + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_16((mc68kcpu), offset); + return; + } + REG_PC(mc68kcpu) += 2; + (mc68kcpu)->remaining_cycles -= (mc68kcpu)->cyc_bcc_notake_w; +} + + +void m68000_base_device_ops::m68k_op_bcc_16(m68000_base_device* mc68kcpu) +{ + if(COND_CC(mc68kcpu)) + { + UINT32 offset = OPER_I_16(mc68kcpu); + REG_PC(mc68kcpu) -= 2; + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_16((mc68kcpu), offset); + return; + } + REG_PC(mc68kcpu) += 2; + (mc68kcpu)->remaining_cycles -= (mc68kcpu)->cyc_bcc_notake_w; +} + + +void m68000_base_device_ops::m68k_op_bcs_16(m68000_base_device* mc68kcpu) +{ + if(COND_CS(mc68kcpu)) + { + UINT32 offset = OPER_I_16(mc68kcpu); + REG_PC(mc68kcpu) -= 2; + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_16((mc68kcpu), offset); + return; + } + REG_PC(mc68kcpu) += 2; + (mc68kcpu)->remaining_cycles -= (mc68kcpu)->cyc_bcc_notake_w; +} + + +void m68000_base_device_ops::m68k_op_bne_16(m68000_base_device* mc68kcpu) +{ + if(COND_NE(mc68kcpu)) + { + UINT32 offset = OPER_I_16(mc68kcpu); + REG_PC(mc68kcpu) -= 2; + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_16((mc68kcpu), offset); + return; + } + REG_PC(mc68kcpu) += 2; + (mc68kcpu)->remaining_cycles -= (mc68kcpu)->cyc_bcc_notake_w; +} + + +void m68000_base_device_ops::m68k_op_beq_16(m68000_base_device* mc68kcpu) +{ + if(COND_EQ(mc68kcpu)) + { + UINT32 offset = OPER_I_16(mc68kcpu); + REG_PC(mc68kcpu) -= 2; + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_16((mc68kcpu), offset); + return; + } + REG_PC(mc68kcpu) += 2; + (mc68kcpu)->remaining_cycles -= (mc68kcpu)->cyc_bcc_notake_w; +} + + +void m68000_base_device_ops::m68k_op_bvc_16(m68000_base_device* mc68kcpu) +{ + if(COND_VC(mc68kcpu)) + { + UINT32 offset = OPER_I_16(mc68kcpu); + REG_PC(mc68kcpu) -= 2; + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_16((mc68kcpu), offset); + return; + } + REG_PC(mc68kcpu) += 2; + (mc68kcpu)->remaining_cycles -= (mc68kcpu)->cyc_bcc_notake_w; +} + + +void m68000_base_device_ops::m68k_op_bvs_16(m68000_base_device* mc68kcpu) +{ + if(COND_VS(mc68kcpu)) + { + UINT32 offset = OPER_I_16(mc68kcpu); + REG_PC(mc68kcpu) -= 2; + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_16((mc68kcpu), offset); + return; + } + REG_PC(mc68kcpu) += 2; + (mc68kcpu)->remaining_cycles -= (mc68kcpu)->cyc_bcc_notake_w; +} + + +void m68000_base_device_ops::m68k_op_bpl_16(m68000_base_device* mc68kcpu) +{ + if(COND_PL(mc68kcpu)) + { + UINT32 offset = OPER_I_16(mc68kcpu); + REG_PC(mc68kcpu) -= 2; + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_16((mc68kcpu), offset); + return; + } + REG_PC(mc68kcpu) += 2; + (mc68kcpu)->remaining_cycles -= (mc68kcpu)->cyc_bcc_notake_w; +} + + +void m68000_base_device_ops::m68k_op_bmi_16(m68000_base_device* mc68kcpu) +{ + if(COND_MI(mc68kcpu)) + { + UINT32 offset = OPER_I_16(mc68kcpu); + REG_PC(mc68kcpu) -= 2; + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_16((mc68kcpu), offset); + return; + } + REG_PC(mc68kcpu) += 2; + (mc68kcpu)->remaining_cycles -= (mc68kcpu)->cyc_bcc_notake_w; +} + + +void m68000_base_device_ops::m68k_op_bge_16(m68000_base_device* mc68kcpu) +{ + if(COND_GE(mc68kcpu)) + { + UINT32 offset = OPER_I_16(mc68kcpu); + REG_PC(mc68kcpu) -= 2; + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_16((mc68kcpu), offset); + return; + } + REG_PC(mc68kcpu) += 2; + (mc68kcpu)->remaining_cycles -= (mc68kcpu)->cyc_bcc_notake_w; +} + + +void m68000_base_device_ops::m68k_op_blt_16(m68000_base_device* mc68kcpu) +{ + if(COND_LT(mc68kcpu)) + { + UINT32 offset = OPER_I_16(mc68kcpu); + REG_PC(mc68kcpu) -= 2; + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_16((mc68kcpu), offset); + return; + } + REG_PC(mc68kcpu) += 2; + (mc68kcpu)->remaining_cycles -= (mc68kcpu)->cyc_bcc_notake_w; +} + + +void m68000_base_device_ops::m68k_op_bgt_16(m68000_base_device* mc68kcpu) +{ + if(COND_GT(mc68kcpu)) + { + UINT32 offset = OPER_I_16(mc68kcpu); + REG_PC(mc68kcpu) -= 2; + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_16((mc68kcpu), offset); + return; + } + REG_PC(mc68kcpu) += 2; + (mc68kcpu)->remaining_cycles -= (mc68kcpu)->cyc_bcc_notake_w; +} + + +void m68000_base_device_ops::m68k_op_ble_16(m68000_base_device* mc68kcpu) +{ + if(COND_LE(mc68kcpu)) + { + UINT32 offset = OPER_I_16(mc68kcpu); + REG_PC(mc68kcpu) -= 2; + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_16((mc68kcpu), offset); + return; + } + REG_PC(mc68kcpu) += 2; + (mc68kcpu)->remaining_cycles -= (mc68kcpu)->cyc_bcc_notake_w; +} + + +void m68000_base_device_ops::m68k_op_bhi_32(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + if(COND_HI(mc68kcpu)) + { + UINT32 offset = OPER_I_32(mc68kcpu); + REG_PC(mc68kcpu) -= 4; + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_32((mc68kcpu), offset); + return; + } + REG_PC(mc68kcpu) += 4; + return; + } + else + { + if(COND_HI(mc68kcpu)) + { + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_8((mc68kcpu), MASK_OUT_ABOVE_8((mc68kcpu)->ir)); + return; + } + (mc68kcpu)->remaining_cycles -= (mc68kcpu)->cyc_bcc_notake_b; + } +} + + +void m68000_base_device_ops::m68k_op_bls_32(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + if(COND_LS(mc68kcpu)) + { + UINT32 offset = OPER_I_32(mc68kcpu); + REG_PC(mc68kcpu) -= 4; + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_32((mc68kcpu), offset); + return; + } + REG_PC(mc68kcpu) += 4; + return; + } + else + { + if(COND_LS(mc68kcpu)) + { + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_8((mc68kcpu), MASK_OUT_ABOVE_8((mc68kcpu)->ir)); + return; + } + (mc68kcpu)->remaining_cycles -= (mc68kcpu)->cyc_bcc_notake_b; + } +} + + +void m68000_base_device_ops::m68k_op_bcc_32(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + if(COND_CC(mc68kcpu)) + { + UINT32 offset = OPER_I_32(mc68kcpu); + REG_PC(mc68kcpu) -= 4; + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_32((mc68kcpu), offset); + return; + } + REG_PC(mc68kcpu) += 4; + return; + } + else + { + if(COND_CC(mc68kcpu)) + { + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_8((mc68kcpu), MASK_OUT_ABOVE_8((mc68kcpu)->ir)); + return; + } + (mc68kcpu)->remaining_cycles -= (mc68kcpu)->cyc_bcc_notake_b; + } +} + + +void m68000_base_device_ops::m68k_op_bcs_32(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + if(COND_CS(mc68kcpu)) + { + UINT32 offset = OPER_I_32(mc68kcpu); + REG_PC(mc68kcpu) -= 4; + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_32((mc68kcpu), offset); + return; + } + REG_PC(mc68kcpu) += 4; + return; + } + else + { + if(COND_CS(mc68kcpu)) + { + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_8((mc68kcpu), MASK_OUT_ABOVE_8((mc68kcpu)->ir)); + return; + } + (mc68kcpu)->remaining_cycles -= (mc68kcpu)->cyc_bcc_notake_b; + } +} + + +void m68000_base_device_ops::m68k_op_bne_32(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + if(COND_NE(mc68kcpu)) + { + UINT32 offset = OPER_I_32(mc68kcpu); + REG_PC(mc68kcpu) -= 4; + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_32((mc68kcpu), offset); + return; + } + REG_PC(mc68kcpu) += 4; + return; + } + else + { + if(COND_NE(mc68kcpu)) + { + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_8((mc68kcpu), MASK_OUT_ABOVE_8((mc68kcpu)->ir)); + return; + } + (mc68kcpu)->remaining_cycles -= (mc68kcpu)->cyc_bcc_notake_b; + } +} + + +void m68000_base_device_ops::m68k_op_beq_32(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + if(COND_EQ(mc68kcpu)) + { + UINT32 offset = OPER_I_32(mc68kcpu); + REG_PC(mc68kcpu) -= 4; + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_32((mc68kcpu), offset); + return; + } + REG_PC(mc68kcpu) += 4; + return; + } + else + { + if(COND_EQ(mc68kcpu)) + { + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_8((mc68kcpu), MASK_OUT_ABOVE_8((mc68kcpu)->ir)); + return; + } + (mc68kcpu)->remaining_cycles -= (mc68kcpu)->cyc_bcc_notake_b; + } +} + + +void m68000_base_device_ops::m68k_op_bvc_32(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + if(COND_VC(mc68kcpu)) + { + UINT32 offset = OPER_I_32(mc68kcpu); + REG_PC(mc68kcpu) -= 4; + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_32((mc68kcpu), offset); + return; + } + REG_PC(mc68kcpu) += 4; + return; + } + else + { + if(COND_VC(mc68kcpu)) + { + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_8((mc68kcpu), MASK_OUT_ABOVE_8((mc68kcpu)->ir)); + return; + } + (mc68kcpu)->remaining_cycles -= (mc68kcpu)->cyc_bcc_notake_b; + } +} + + +void m68000_base_device_ops::m68k_op_bvs_32(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + if(COND_VS(mc68kcpu)) + { + UINT32 offset = OPER_I_32(mc68kcpu); + REG_PC(mc68kcpu) -= 4; + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_32((mc68kcpu), offset); + return; + } + REG_PC(mc68kcpu) += 4; + return; + } + else + { + if(COND_VS(mc68kcpu)) + { + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_8((mc68kcpu), MASK_OUT_ABOVE_8((mc68kcpu)->ir)); + return; + } + (mc68kcpu)->remaining_cycles -= (mc68kcpu)->cyc_bcc_notake_b; + } +} + + +void m68000_base_device_ops::m68k_op_bpl_32(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + if(COND_PL(mc68kcpu)) + { + UINT32 offset = OPER_I_32(mc68kcpu); + REG_PC(mc68kcpu) -= 4; + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_32((mc68kcpu), offset); + return; + } + REG_PC(mc68kcpu) += 4; + return; + } + else + { + if(COND_PL(mc68kcpu)) + { + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_8((mc68kcpu), MASK_OUT_ABOVE_8((mc68kcpu)->ir)); + return; + } + (mc68kcpu)->remaining_cycles -= (mc68kcpu)->cyc_bcc_notake_b; + } +} + + +void m68000_base_device_ops::m68k_op_bmi_32(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + if(COND_MI(mc68kcpu)) + { + UINT32 offset = OPER_I_32(mc68kcpu); + REG_PC(mc68kcpu) -= 4; + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_32((mc68kcpu), offset); + return; + } + REG_PC(mc68kcpu) += 4; + return; + } + else + { + if(COND_MI(mc68kcpu)) + { + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_8((mc68kcpu), MASK_OUT_ABOVE_8((mc68kcpu)->ir)); + return; + } + (mc68kcpu)->remaining_cycles -= (mc68kcpu)->cyc_bcc_notake_b; + } +} + + +void m68000_base_device_ops::m68k_op_bge_32(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + if(COND_GE(mc68kcpu)) + { + UINT32 offset = OPER_I_32(mc68kcpu); + REG_PC(mc68kcpu) -= 4; + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_32((mc68kcpu), offset); + return; + } + REG_PC(mc68kcpu) += 4; + return; + } + else + { + if(COND_GE(mc68kcpu)) + { + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_8((mc68kcpu), MASK_OUT_ABOVE_8((mc68kcpu)->ir)); + return; + } + (mc68kcpu)->remaining_cycles -= (mc68kcpu)->cyc_bcc_notake_b; + } +} + + +void m68000_base_device_ops::m68k_op_blt_32(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + if(COND_LT(mc68kcpu)) + { + UINT32 offset = OPER_I_32(mc68kcpu); + REG_PC(mc68kcpu) -= 4; + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_32((mc68kcpu), offset); + return; + } + REG_PC(mc68kcpu) += 4; + return; + } + else + { + if(COND_LT(mc68kcpu)) + { + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_8((mc68kcpu), MASK_OUT_ABOVE_8((mc68kcpu)->ir)); + return; + } + (mc68kcpu)->remaining_cycles -= (mc68kcpu)->cyc_bcc_notake_b; + } +} + + +void m68000_base_device_ops::m68k_op_bgt_32(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + if(COND_GT(mc68kcpu)) + { + UINT32 offset = OPER_I_32(mc68kcpu); + REG_PC(mc68kcpu) -= 4; + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_32((mc68kcpu), offset); + return; + } + REG_PC(mc68kcpu) += 4; + return; + } + else + { + if(COND_GT(mc68kcpu)) + { + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_8((mc68kcpu), MASK_OUT_ABOVE_8((mc68kcpu)->ir)); + return; + } + (mc68kcpu)->remaining_cycles -= (mc68kcpu)->cyc_bcc_notake_b; + } +} + + +void m68000_base_device_ops::m68k_op_ble_32(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + if(COND_LE(mc68kcpu)) + { + UINT32 offset = OPER_I_32(mc68kcpu); + REG_PC(mc68kcpu) -= 4; + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_32((mc68kcpu), offset); + return; + } + REG_PC(mc68kcpu) += 4; + return; + } + else + { + if(COND_LE(mc68kcpu)) + { + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_8((mc68kcpu), MASK_OUT_ABOVE_8((mc68kcpu)->ir)); + return; + } + (mc68kcpu)->remaining_cycles -= (mc68kcpu)->cyc_bcc_notake_b; + } +} + + +void m68000_base_device_ops::m68k_op_bchg_32_r_d(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 mask = 1 << (DX(mc68kcpu) & 0x1f); + + (mc68kcpu)->not_z_flag = *r_dst & mask; + *r_dst ^= mask; +} + + +void m68000_base_device_ops::m68k_op_bchg_8_r_ai(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_AI_8(mc68kcpu); + UINT32 src = m68ki_read_8((mc68kcpu), ea); + UINT32 mask = 1 << (DX(mc68kcpu) & 7); + + (mc68kcpu)->not_z_flag = src & mask; + m68ki_write_8((mc68kcpu), ea, src ^ mask); +} + + +void m68000_base_device_ops::m68k_op_bchg_8_r_pi(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_PI_8(mc68kcpu); + UINT32 src = m68ki_read_8((mc68kcpu), ea); + UINT32 mask = 1 << (DX(mc68kcpu) & 7); + + (mc68kcpu)->not_z_flag = src & mask; + m68ki_write_8((mc68kcpu), ea, src ^ mask); +} + + +void m68000_base_device_ops::m68k_op_bchg_8_r_pi7(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_A7_PI_8(mc68kcpu); + UINT32 src = m68ki_read_8((mc68kcpu), ea); + UINT32 mask = 1 << (DX(mc68kcpu) & 7); + + (mc68kcpu)->not_z_flag = src & mask; + m68ki_write_8((mc68kcpu), ea, src ^ mask); +} + + +void m68000_base_device_ops::m68k_op_bchg_8_r_pd(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_PD_8(mc68kcpu); + UINT32 src = m68ki_read_8((mc68kcpu), ea); + UINT32 mask = 1 << (DX(mc68kcpu) & 7); + + (mc68kcpu)->not_z_flag = src & mask; + m68ki_write_8((mc68kcpu), ea, src ^ mask); +} + + +void m68000_base_device_ops::m68k_op_bchg_8_r_pd7(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_A7_PD_8(mc68kcpu); + UINT32 src = m68ki_read_8((mc68kcpu), ea); + UINT32 mask = 1 << (DX(mc68kcpu) & 7); + + (mc68kcpu)->not_z_flag = src & mask; + m68ki_write_8((mc68kcpu), ea, src ^ mask); +} + + +void m68000_base_device_ops::m68k_op_bchg_8_r_di(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_DI_8(mc68kcpu); + UINT32 src = m68ki_read_8((mc68kcpu), ea); + UINT32 mask = 1 << (DX(mc68kcpu) & 7); + + (mc68kcpu)->not_z_flag = src & mask; + m68ki_write_8((mc68kcpu), ea, src ^ mask); +} + + +void m68000_base_device_ops::m68k_op_bchg_8_r_ix(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_IX_8(mc68kcpu); + UINT32 src = m68ki_read_8((mc68kcpu), ea); + UINT32 mask = 1 << (DX(mc68kcpu) & 7); + + (mc68kcpu)->not_z_flag = src & mask; + m68ki_write_8((mc68kcpu), ea, src ^ mask); +} + + +void m68000_base_device_ops::m68k_op_bchg_8_r_aw(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AW_8(mc68kcpu); + UINT32 src = m68ki_read_8((mc68kcpu), ea); + UINT32 mask = 1 << (DX(mc68kcpu) & 7); + + (mc68kcpu)->not_z_flag = src & mask; + m68ki_write_8((mc68kcpu), ea, src ^ mask); +} + + +void m68000_base_device_ops::m68k_op_bchg_8_r_al(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AL_8(mc68kcpu); + UINT32 src = m68ki_read_8((mc68kcpu), ea); + UINT32 mask = 1 << (DX(mc68kcpu) & 7); + + (mc68kcpu)->not_z_flag = src & mask; + m68ki_write_8((mc68kcpu), ea, src ^ mask); +} + + +void m68000_base_device_ops::m68k_op_bchg_32_s_d(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 mask = 1 << (OPER_I_8(mc68kcpu) & 0x1f); + + (mc68kcpu)->not_z_flag = *r_dst & mask; + *r_dst ^= mask; +} + + +void m68000_base_device_ops::m68k_op_bchg_8_s_ai(m68000_base_device* mc68kcpu) +{ + UINT32 mask = 1 << (OPER_I_8(mc68kcpu) & 7); + UINT32 ea = EA_AY_AI_8(mc68kcpu); + UINT32 src = m68ki_read_8((mc68kcpu), ea); + + (mc68kcpu)->not_z_flag = src & mask; + m68ki_write_8((mc68kcpu), ea, src ^ mask); +} + + +void m68000_base_device_ops::m68k_op_bchg_8_s_pi(m68000_base_device* mc68kcpu) +{ + UINT32 mask = 1 << (OPER_I_8(mc68kcpu) & 7); + UINT32 ea = EA_AY_PI_8(mc68kcpu); + UINT32 src = m68ki_read_8((mc68kcpu), ea); + + (mc68kcpu)->not_z_flag = src & mask; + m68ki_write_8((mc68kcpu), ea, src ^ mask); +} + + +void m68000_base_device_ops::m68k_op_bchg_8_s_pi7(m68000_base_device* mc68kcpu) +{ + UINT32 mask = 1 << (OPER_I_8(mc68kcpu) & 7); + UINT32 ea = EA_A7_PI_8(mc68kcpu); + UINT32 src = m68ki_read_8((mc68kcpu), ea); + + (mc68kcpu)->not_z_flag = src & mask; + m68ki_write_8((mc68kcpu), ea, src ^ mask); +} + + +void m68000_base_device_ops::m68k_op_bchg_8_s_pd(m68000_base_device* mc68kcpu) +{ + UINT32 mask = 1 << (OPER_I_8(mc68kcpu) & 7); + UINT32 ea = EA_AY_PD_8(mc68kcpu); + UINT32 src = m68ki_read_8((mc68kcpu), ea); + + (mc68kcpu)->not_z_flag = src & mask; + m68ki_write_8((mc68kcpu), ea, src ^ mask); +} + + +void m68000_base_device_ops::m68k_op_bchg_8_s_pd7(m68000_base_device* mc68kcpu) +{ + UINT32 mask = 1 << (OPER_I_8(mc68kcpu) & 7); + UINT32 ea = EA_A7_PD_8(mc68kcpu); + UINT32 src = m68ki_read_8((mc68kcpu), ea); + + (mc68kcpu)->not_z_flag = src & mask; + m68ki_write_8((mc68kcpu), ea, src ^ mask); +} + + +void m68000_base_device_ops::m68k_op_bchg_8_s_di(m68000_base_device* mc68kcpu) +{ + UINT32 mask = 1 << (OPER_I_8(mc68kcpu) & 7); + UINT32 ea = EA_AY_DI_8(mc68kcpu); + UINT32 src = m68ki_read_8((mc68kcpu), ea); + + (mc68kcpu)->not_z_flag = src & mask; + m68ki_write_8((mc68kcpu), ea, src ^ mask); +} + + +void m68000_base_device_ops::m68k_op_bchg_8_s_ix(m68000_base_device* mc68kcpu) +{ + UINT32 mask = 1 << (OPER_I_8(mc68kcpu) & 7); + UINT32 ea = EA_AY_IX_8(mc68kcpu); + UINT32 src = m68ki_read_8((mc68kcpu), ea); + + (mc68kcpu)->not_z_flag = src & mask; + m68ki_write_8((mc68kcpu), ea, src ^ mask); +} + + +void m68000_base_device_ops::m68k_op_bchg_8_s_aw(m68000_base_device* mc68kcpu) +{ + UINT32 mask = 1 << (OPER_I_8(mc68kcpu) & 7); + UINT32 ea = EA_AW_8(mc68kcpu); + UINT32 src = m68ki_read_8((mc68kcpu), ea); + + (mc68kcpu)->not_z_flag = src & mask; + m68ki_write_8((mc68kcpu), ea, src ^ mask); +} + + +void m68000_base_device_ops::m68k_op_bchg_8_s_al(m68000_base_device* mc68kcpu) +{ + UINT32 mask = 1 << (OPER_I_8(mc68kcpu) & 7); + UINT32 ea = EA_AL_8(mc68kcpu); + UINT32 src = m68ki_read_8((mc68kcpu), ea); + + (mc68kcpu)->not_z_flag = src & mask; + m68ki_write_8((mc68kcpu), ea, src ^ mask); +} + + +void m68000_base_device_ops::m68k_op_bclr_32_r_d(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 mask = 1 << (DX(mc68kcpu) & 0x1f); + + (mc68kcpu)->not_z_flag = *r_dst & mask; + *r_dst &= ~mask; +} + + +void m68000_base_device_ops::m68k_op_bclr_8_r_ai(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_AI_8(mc68kcpu); + UINT32 src = m68ki_read_8((mc68kcpu), ea); + UINT32 mask = 1 << (DX(mc68kcpu) & 7); + + (mc68kcpu)->not_z_flag = src & mask; + m68ki_write_8((mc68kcpu), ea, src & ~mask); +} + + +void m68000_base_device_ops::m68k_op_bclr_8_r_pi(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_PI_8(mc68kcpu); + UINT32 src = m68ki_read_8((mc68kcpu), ea); + UINT32 mask = 1 << (DX(mc68kcpu) & 7); + + (mc68kcpu)->not_z_flag = src & mask; + m68ki_write_8((mc68kcpu), ea, src & ~mask); +} + + +void m68000_base_device_ops::m68k_op_bclr_8_r_pi7(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_A7_PI_8(mc68kcpu); + UINT32 src = m68ki_read_8((mc68kcpu), ea); + UINT32 mask = 1 << (DX(mc68kcpu) & 7); + + (mc68kcpu)->not_z_flag = src & mask; + m68ki_write_8((mc68kcpu), ea, src & ~mask); +} + + +void m68000_base_device_ops::m68k_op_bclr_8_r_pd(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_PD_8(mc68kcpu); + UINT32 src = m68ki_read_8((mc68kcpu), ea); + UINT32 mask = 1 << (DX(mc68kcpu) & 7); + + (mc68kcpu)->not_z_flag = src & mask; + m68ki_write_8((mc68kcpu), ea, src & ~mask); +} + + +void m68000_base_device_ops::m68k_op_bclr_8_r_pd7(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_A7_PD_8(mc68kcpu); + UINT32 src = m68ki_read_8((mc68kcpu), ea); + UINT32 mask = 1 << (DX(mc68kcpu) & 7); + + (mc68kcpu)->not_z_flag = src & mask; + m68ki_write_8((mc68kcpu), ea, src & ~mask); +} + + +void m68000_base_device_ops::m68k_op_bclr_8_r_di(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_DI_8(mc68kcpu); + UINT32 src = m68ki_read_8((mc68kcpu), ea); + UINT32 mask = 1 << (DX(mc68kcpu) & 7); + + (mc68kcpu)->not_z_flag = src & mask; + m68ki_write_8((mc68kcpu), ea, src & ~mask); +} + + +void m68000_base_device_ops::m68k_op_bclr_8_r_ix(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_IX_8(mc68kcpu); + UINT32 src = m68ki_read_8((mc68kcpu), ea); + UINT32 mask = 1 << (DX(mc68kcpu) & 7); + + (mc68kcpu)->not_z_flag = src & mask; + m68ki_write_8((mc68kcpu), ea, src & ~mask); +} + + +void m68000_base_device_ops::m68k_op_bclr_8_r_aw(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AW_8(mc68kcpu); + UINT32 src = m68ki_read_8((mc68kcpu), ea); + UINT32 mask = 1 << (DX(mc68kcpu) & 7); + + (mc68kcpu)->not_z_flag = src & mask; + m68ki_write_8((mc68kcpu), ea, src & ~mask); +} + + +void m68000_base_device_ops::m68k_op_bclr_8_r_al(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AL_8(mc68kcpu); + UINT32 src = m68ki_read_8((mc68kcpu), ea); + UINT32 mask = 1 << (DX(mc68kcpu) & 7); + + (mc68kcpu)->not_z_flag = src & mask; + m68ki_write_8((mc68kcpu), ea, src & ~mask); +} + + +void m68000_base_device_ops::m68k_op_bclr_32_s_d(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 mask = 1 << (OPER_I_8(mc68kcpu) & 0x1f); + + (mc68kcpu)->not_z_flag = *r_dst & mask; + *r_dst &= ~mask; +} + + +void m68000_base_device_ops::m68k_op_bclr_8_s_ai(m68000_base_device* mc68kcpu) +{ + UINT32 mask = 1 << (OPER_I_8(mc68kcpu) & 7); + UINT32 ea = EA_AY_AI_8(mc68kcpu); + UINT32 src = m68ki_read_8((mc68kcpu), ea); + + (mc68kcpu)->not_z_flag = src & mask; + m68ki_write_8((mc68kcpu), ea, src & ~mask); +} + + +void m68000_base_device_ops::m68k_op_bclr_8_s_pi(m68000_base_device* mc68kcpu) +{ + UINT32 mask = 1 << (OPER_I_8(mc68kcpu) & 7); + UINT32 ea = EA_AY_PI_8(mc68kcpu); + UINT32 src = m68ki_read_8((mc68kcpu), ea); + + (mc68kcpu)->not_z_flag = src & mask; + m68ki_write_8((mc68kcpu), ea, src & ~mask); +} + + +void m68000_base_device_ops::m68k_op_bclr_8_s_pi7(m68000_base_device* mc68kcpu) +{ + UINT32 mask = 1 << (OPER_I_8(mc68kcpu) & 7); + UINT32 ea = EA_A7_PI_8(mc68kcpu); + UINT32 src = m68ki_read_8((mc68kcpu), ea); + + (mc68kcpu)->not_z_flag = src & mask; + m68ki_write_8((mc68kcpu), ea, src & ~mask); +} + + +void m68000_base_device_ops::m68k_op_bclr_8_s_pd(m68000_base_device* mc68kcpu) +{ + UINT32 mask = 1 << (OPER_I_8(mc68kcpu) & 7); + UINT32 ea = EA_AY_PD_8(mc68kcpu); + UINT32 src = m68ki_read_8((mc68kcpu), ea); + + (mc68kcpu)->not_z_flag = src & mask; + m68ki_write_8((mc68kcpu), ea, src & ~mask); +} + + +void m68000_base_device_ops::m68k_op_bclr_8_s_pd7(m68000_base_device* mc68kcpu) +{ + UINT32 mask = 1 << (OPER_I_8(mc68kcpu) & 7); + UINT32 ea = EA_A7_PD_8(mc68kcpu); + UINT32 src = m68ki_read_8((mc68kcpu), ea); + + (mc68kcpu)->not_z_flag = src & mask; + m68ki_write_8((mc68kcpu), ea, src & ~mask); +} + + +void m68000_base_device_ops::m68k_op_bclr_8_s_di(m68000_base_device* mc68kcpu) +{ + UINT32 mask = 1 << (OPER_I_8(mc68kcpu) & 7); + UINT32 ea = EA_AY_DI_8(mc68kcpu); + UINT32 src = m68ki_read_8((mc68kcpu), ea); + + (mc68kcpu)->not_z_flag = src & mask; + m68ki_write_8((mc68kcpu), ea, src & ~mask); +} + + +void m68000_base_device_ops::m68k_op_bclr_8_s_ix(m68000_base_device* mc68kcpu) +{ + UINT32 mask = 1 << (OPER_I_8(mc68kcpu) & 7); + UINT32 ea = EA_AY_IX_8(mc68kcpu); + UINT32 src = m68ki_read_8((mc68kcpu), ea); + + (mc68kcpu)->not_z_flag = src & mask; + m68ki_write_8((mc68kcpu), ea, src & ~mask); +} + + +void m68000_base_device_ops::m68k_op_bclr_8_s_aw(m68000_base_device* mc68kcpu) +{ + UINT32 mask = 1 << (OPER_I_8(mc68kcpu) & 7); + UINT32 ea = EA_AW_8(mc68kcpu); + UINT32 src = m68ki_read_8((mc68kcpu), ea); + + (mc68kcpu)->not_z_flag = src & mask; + m68ki_write_8((mc68kcpu), ea, src & ~mask); +} + + +void m68000_base_device_ops::m68k_op_bclr_8_s_al(m68000_base_device* mc68kcpu) +{ + UINT32 mask = 1 << (OPER_I_8(mc68kcpu) & 7); + UINT32 ea = EA_AL_8(mc68kcpu); + UINT32 src = m68ki_read_8((mc68kcpu), ea); + + (mc68kcpu)->not_z_flag = src & mask; + m68ki_write_8((mc68kcpu), ea, src & ~mask); +} + + +void m68000_base_device_ops::m68k_op_bfchg_32_d(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT32 offset = (word2>>6)&31; + UINT32 width = word2; + UINT32* data = &DY(mc68kcpu); + UINT64 mask; + + + if(BIT_B(word2)) + offset = REG_D(mc68kcpu)[offset&7]; + if(BIT_5(word2)) + width = REG_D(mc68kcpu)[width&7]; + + offset &= 31; + width = ((width-1) & 31) + 1; + + mask = MASK_OUT_ABOVE_32(0xffffffff << (32 - width)); + mask = ROR_32(mask, offset); + + (mc68kcpu)->n_flag = NFLAG_32(*data<not_z_flag = *data & mask; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + + *data ^= mask; + + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_bfchg_32_ai(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + INT32 offset = (word2>>6)&31; + UINT32 width = word2; + UINT32 mask_base; + UINT32 data_long; + UINT32 mask_long; + UINT32 data_byte = 0; + UINT32 mask_byte = 0; + UINT32 ea = EA_AY_AI_8(mc68kcpu); + + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D(mc68kcpu)[offset&7]); + if(BIT_5(word2)) + width = REG_D(mc68kcpu)[width&7]; + + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + offset %= 8; + if(offset < 0) + { + offset += 8; + ea--; + } + width = ((width-1) & 31) + 1; + + mask_base = MASK_OUT_ABOVE_32(0xffffffff << (32 - width)); + mask_long = mask_base >> offset; + + data_long = m68ki_read_32((mc68kcpu), ea); + (mc68kcpu)->n_flag = NFLAG_32(data_long << offset); + (mc68kcpu)->not_z_flag = data_long & mask_long; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + + m68ki_write_32((mc68kcpu), ea, data_long ^ mask_long); + + if((width + offset) > 32) + { + mask_byte = MASK_OUT_ABOVE_8(mask_base); + data_byte = m68ki_read_8((mc68kcpu), ea+4); + (mc68kcpu)->not_z_flag |= (data_byte & mask_byte); + m68ki_write_8((mc68kcpu), ea+4, data_byte ^ mask_byte); + } + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_bfchg_32_di(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + INT32 offset = (word2>>6)&31; + UINT32 width = word2; + UINT32 mask_base; + UINT32 data_long; + UINT32 mask_long; + UINT32 data_byte = 0; + UINT32 mask_byte = 0; + UINT32 ea = EA_AY_DI_8(mc68kcpu); + + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D(mc68kcpu)[offset&7]); + if(BIT_5(word2)) + width = REG_D(mc68kcpu)[width&7]; + + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + offset %= 8; + if(offset < 0) + { + offset += 8; + ea--; + } + width = ((width-1) & 31) + 1; + + mask_base = MASK_OUT_ABOVE_32(0xffffffff << (32 - width)); + mask_long = mask_base >> offset; + + data_long = m68ki_read_32((mc68kcpu), ea); + (mc68kcpu)->n_flag = NFLAG_32(data_long << offset); + (mc68kcpu)->not_z_flag = data_long & mask_long; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + + m68ki_write_32((mc68kcpu), ea, data_long ^ mask_long); + + if((width + offset) > 32) + { + mask_byte = MASK_OUT_ABOVE_8(mask_base); + data_byte = m68ki_read_8((mc68kcpu), ea+4); + (mc68kcpu)->not_z_flag |= (data_byte & mask_byte); + m68ki_write_8((mc68kcpu), ea+4, data_byte ^ mask_byte); + } + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_bfchg_32_ix(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + INT32 offset = (word2>>6)&31; + UINT32 width = word2; + UINT32 mask_base; + UINT32 data_long; + UINT32 mask_long; + UINT32 data_byte = 0; + UINT32 mask_byte = 0; + UINT32 ea = EA_AY_IX_8(mc68kcpu); + + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D(mc68kcpu)[offset&7]); + if(BIT_5(word2)) + width = REG_D(mc68kcpu)[width&7]; + + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + offset %= 8; + if(offset < 0) + { + offset += 8; + ea--; + } + width = ((width-1) & 31) + 1; + + mask_base = MASK_OUT_ABOVE_32(0xffffffff << (32 - width)); + mask_long = mask_base >> offset; + + data_long = m68ki_read_32((mc68kcpu), ea); + (mc68kcpu)->n_flag = NFLAG_32(data_long << offset); + (mc68kcpu)->not_z_flag = data_long & mask_long; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + + m68ki_write_32((mc68kcpu), ea, data_long ^ mask_long); + + if((width + offset) > 32) + { + mask_byte = MASK_OUT_ABOVE_8(mask_base); + data_byte = m68ki_read_8((mc68kcpu), ea+4); + (mc68kcpu)->not_z_flag |= (data_byte & mask_byte); + m68ki_write_8((mc68kcpu), ea+4, data_byte ^ mask_byte); + } + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_bfchg_32_aw(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + INT32 offset = (word2>>6)&31; + UINT32 width = word2; + UINT32 mask_base; + UINT32 data_long; + UINT32 mask_long; + UINT32 data_byte = 0; + UINT32 mask_byte = 0; + UINT32 ea = EA_AW_8(mc68kcpu); + + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D(mc68kcpu)[offset&7]); + if(BIT_5(word2)) + width = REG_D(mc68kcpu)[width&7]; + + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + offset %= 8; + if(offset < 0) + { + offset += 8; + ea--; + } + width = ((width-1) & 31) + 1; + + mask_base = MASK_OUT_ABOVE_32(0xffffffff << (32 - width)); + mask_long = mask_base >> offset; + + data_long = m68ki_read_32((mc68kcpu), ea); + (mc68kcpu)->n_flag = NFLAG_32(data_long << offset); + (mc68kcpu)->not_z_flag = data_long & mask_long; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + + m68ki_write_32((mc68kcpu), ea, data_long ^ mask_long); + + if((width + offset) > 32) + { + mask_byte = MASK_OUT_ABOVE_8(mask_base); + data_byte = m68ki_read_8((mc68kcpu), ea+4); + (mc68kcpu)->not_z_flag |= (data_byte & mask_byte); + m68ki_write_8((mc68kcpu), ea+4, data_byte ^ mask_byte); + } + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_bfchg_32_al(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + INT32 offset = (word2>>6)&31; + UINT32 width = word2; + UINT32 mask_base; + UINT32 data_long; + UINT32 mask_long; + UINT32 data_byte = 0; + UINT32 mask_byte = 0; + UINT32 ea = EA_AL_8(mc68kcpu); + + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D(mc68kcpu)[offset&7]); + if(BIT_5(word2)) + width = REG_D(mc68kcpu)[width&7]; + + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + offset %= 8; + if(offset < 0) + { + offset += 8; + ea--; + } + width = ((width-1) & 31) + 1; + + mask_base = MASK_OUT_ABOVE_32(0xffffffff << (32 - width)); + mask_long = mask_base >> offset; + + data_long = m68ki_read_32((mc68kcpu), ea); + (mc68kcpu)->n_flag = NFLAG_32(data_long << offset); + (mc68kcpu)->not_z_flag = data_long & mask_long; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + + m68ki_write_32((mc68kcpu), ea, data_long ^ mask_long); + + if((width + offset) > 32) + { + mask_byte = MASK_OUT_ABOVE_8(mask_base); + data_byte = m68ki_read_8((mc68kcpu), ea+4); + (mc68kcpu)->not_z_flag |= (data_byte & mask_byte); + m68ki_write_8((mc68kcpu), ea+4, data_byte ^ mask_byte); + } + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_bfclr_32_d(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT32 offset = (word2>>6)&31; + UINT32 width = word2; + UINT32* data = &DY(mc68kcpu); + UINT64 mask; + + + if(BIT_B(word2)) + offset = REG_D(mc68kcpu)[offset&7]; + if(BIT_5(word2)) + width = REG_D(mc68kcpu)[width&7]; + + + offset &= 31; + width = ((width-1) & 31) + 1; + + + mask = MASK_OUT_ABOVE_32(0xffffffff << (32 - width)); + mask = ROR_32(mask, offset); + + (mc68kcpu)->n_flag = NFLAG_32(*data<not_z_flag = *data & mask; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + + *data &= ~mask; + + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_bfclr_32_ai(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + INT32 offset = (word2>>6)&31; + UINT32 width = word2; + UINT32 mask_base; + UINT32 data_long; + UINT32 mask_long; + UINT32 data_byte = 0; + UINT32 mask_byte = 0; + UINT32 ea = EA_AY_AI_8(mc68kcpu); + + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D(mc68kcpu)[offset&7]); + if(BIT_5(word2)) + width = REG_D(mc68kcpu)[width&7]; + + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + offset %= 8; + if(offset < 0) + { + offset += 8; + ea--; + } + width = ((width-1) & 31) + 1; + + mask_base = MASK_OUT_ABOVE_32(0xffffffff << (32 - width)); + mask_long = mask_base >> offset; + + data_long = m68ki_read_32((mc68kcpu), ea); + (mc68kcpu)->n_flag = NFLAG_32(data_long << offset); + (mc68kcpu)->not_z_flag = data_long & mask_long; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + + m68ki_write_32((mc68kcpu), ea, data_long & ~mask_long); + + if((width + offset) > 32) + { + mask_byte = MASK_OUT_ABOVE_8(mask_base); + data_byte = m68ki_read_8((mc68kcpu), ea+4); + (mc68kcpu)->not_z_flag |= (data_byte & mask_byte); + m68ki_write_8((mc68kcpu), ea+4, data_byte & ~mask_byte); + } + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_bfclr_32_di(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + INT32 offset = (word2>>6)&31; + UINT32 width = word2; + UINT32 mask_base; + UINT32 data_long; + UINT32 mask_long; + UINT32 data_byte = 0; + UINT32 mask_byte = 0; + UINT32 ea = EA_AY_DI_8(mc68kcpu); + + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D(mc68kcpu)[offset&7]); + if(BIT_5(word2)) + width = REG_D(mc68kcpu)[width&7]; + + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + offset %= 8; + if(offset < 0) + { + offset += 8; + ea--; + } + width = ((width-1) & 31) + 1; + + mask_base = MASK_OUT_ABOVE_32(0xffffffff << (32 - width)); + mask_long = mask_base >> offset; + + data_long = m68ki_read_32((mc68kcpu), ea); + (mc68kcpu)->n_flag = NFLAG_32(data_long << offset); + (mc68kcpu)->not_z_flag = data_long & mask_long; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + + m68ki_write_32((mc68kcpu), ea, data_long & ~mask_long); + + if((width + offset) > 32) + { + mask_byte = MASK_OUT_ABOVE_8(mask_base); + data_byte = m68ki_read_8((mc68kcpu), ea+4); + (mc68kcpu)->not_z_flag |= (data_byte & mask_byte); + m68ki_write_8((mc68kcpu), ea+4, data_byte & ~mask_byte); + } + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_bfclr_32_ix(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + INT32 offset = (word2>>6)&31; + UINT32 width = word2; + UINT32 mask_base; + UINT32 data_long; + UINT32 mask_long; + UINT32 data_byte = 0; + UINT32 mask_byte = 0; + UINT32 ea = EA_AY_IX_8(mc68kcpu); + + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D(mc68kcpu)[offset&7]); + if(BIT_5(word2)) + width = REG_D(mc68kcpu)[width&7]; + + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + offset %= 8; + if(offset < 0) + { + offset += 8; + ea--; + } + width = ((width-1) & 31) + 1; + + mask_base = MASK_OUT_ABOVE_32(0xffffffff << (32 - width)); + mask_long = mask_base >> offset; + + data_long = m68ki_read_32((mc68kcpu), ea); + (mc68kcpu)->n_flag = NFLAG_32(data_long << offset); + (mc68kcpu)->not_z_flag = data_long & mask_long; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + + m68ki_write_32((mc68kcpu), ea, data_long & ~mask_long); + + if((width + offset) > 32) + { + mask_byte = MASK_OUT_ABOVE_8(mask_base); + data_byte = m68ki_read_8((mc68kcpu), ea+4); + (mc68kcpu)->not_z_flag |= (data_byte & mask_byte); + m68ki_write_8((mc68kcpu), ea+4, data_byte & ~mask_byte); + } + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_bfclr_32_aw(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + INT32 offset = (word2>>6)&31; + UINT32 width = word2; + UINT32 mask_base; + UINT32 data_long; + UINT32 mask_long; + UINT32 data_byte = 0; + UINT32 mask_byte = 0; + UINT32 ea = EA_AW_8(mc68kcpu); + + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D(mc68kcpu)[offset&7]); + if(BIT_5(word2)) + width = REG_D(mc68kcpu)[width&7]; + + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + offset %= 8; + if(offset < 0) + { + offset += 8; + ea--; + } + width = ((width-1) & 31) + 1; + + mask_base = MASK_OUT_ABOVE_32(0xffffffff << (32 - width)); + mask_long = mask_base >> offset; + + data_long = m68ki_read_32((mc68kcpu), ea); + (mc68kcpu)->n_flag = NFLAG_32(data_long << offset); + (mc68kcpu)->not_z_flag = data_long & mask_long; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + + m68ki_write_32((mc68kcpu), ea, data_long & ~mask_long); + + if((width + offset) > 32) + { + mask_byte = MASK_OUT_ABOVE_8(mask_base); + data_byte = m68ki_read_8((mc68kcpu), ea+4); + (mc68kcpu)->not_z_flag |= (data_byte & mask_byte); + m68ki_write_8((mc68kcpu), ea+4, data_byte & ~mask_byte); + } + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_bfclr_32_al(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + INT32 offset = (word2>>6)&31; + UINT32 width = word2; + UINT32 mask_base; + UINT32 data_long; + UINT32 mask_long; + UINT32 data_byte = 0; + UINT32 mask_byte = 0; + UINT32 ea = EA_AL_8(mc68kcpu); + + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D(mc68kcpu)[offset&7]); + if(BIT_5(word2)) + width = REG_D(mc68kcpu)[width&7]; + + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + offset %= 8; + if(offset < 0) + { + offset += 8; + ea--; + } + width = ((width-1) & 31) + 1; + + mask_base = MASK_OUT_ABOVE_32(0xffffffff << (32 - width)); + mask_long = mask_base >> offset; + + data_long = m68ki_read_32((mc68kcpu), ea); + (mc68kcpu)->n_flag = NFLAG_32(data_long << offset); + (mc68kcpu)->not_z_flag = data_long & mask_long; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + + m68ki_write_32((mc68kcpu), ea, data_long & ~mask_long); + + if((width + offset) > 32) + { + mask_byte = MASK_OUT_ABOVE_8(mask_base); + data_byte = m68ki_read_8((mc68kcpu), ea+4); + (mc68kcpu)->not_z_flag |= (data_byte & mask_byte); + m68ki_write_8((mc68kcpu), ea+4, data_byte & ~mask_byte); + } + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_bfexts_32_d(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT32 offset = (word2>>6)&31; + UINT32 width = word2; + UINT64 data = DY(mc68kcpu); + + + if(BIT_B(word2)) + offset = REG_D(mc68kcpu)[offset&7]; + if(BIT_5(word2)) + width = REG_D(mc68kcpu)[width&7]; + + offset &= 31; + width = ((width-1) & 31) + 1; + + data = ROL_32(data, offset); + (mc68kcpu)->n_flag = NFLAG_32(data); + data = MAKE_INT_32(data) >> (32 - width); + + (mc68kcpu)->not_z_flag = data; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + + REG_D(mc68kcpu)[(word2>>12)&7] = data; + + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_bfexts_32_ai(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + INT32 offset = (word2>>6)&31; + UINT32 width = word2; + UINT32 data; + UINT32 ea = EA_AY_AI_8(mc68kcpu); + + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D(mc68kcpu)[offset&7]); + if(BIT_5(word2)) + width = REG_D(mc68kcpu)[width&7]; + + if(BIT_B(word2)) + { + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + offset %= 8; + if(offset < 0) + { + offset += 8; + ea--; + } + } + width = ((width-1) & 31) + 1; + + data = (offset+width) < 8 ? (m68ki_read_8((mc68kcpu), ea) << 24) : + (offset+width) < 16 ? (m68ki_read_16((mc68kcpu), ea) << 16) : m68ki_read_32((mc68kcpu), ea); + + data = MASK_OUT_ABOVE_32(data< 32) + data |= (m68ki_read_8((mc68kcpu), ea+4) << offset) >> 8; + + (mc68kcpu)->n_flag = NFLAG_32(data); + data = MAKE_INT_32(data) >> (32 - width); + + (mc68kcpu)->not_z_flag = data; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + + REG_D(mc68kcpu)[(word2 >> 12) & 7] = data; + + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_bfexts_32_di(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + INT32 offset = (word2>>6)&31; + UINT32 width = word2; + UINT32 data; + UINT32 ea = EA_AY_DI_8(mc68kcpu); + + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D(mc68kcpu)[offset&7]); + if(BIT_5(word2)) + width = REG_D(mc68kcpu)[width&7]; + + if(BIT_B(word2)) + { + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + offset %= 8; + if(offset < 0) + { + offset += 8; + ea--; + } + } + width = ((width-1) & 31) + 1; + + data = (offset+width) < 8 ? (m68ki_read_8((mc68kcpu), ea) << 24) : + (offset+width) < 16 ? (m68ki_read_16((mc68kcpu), ea) << 16) : m68ki_read_32((mc68kcpu), ea); + + data = MASK_OUT_ABOVE_32(data< 32) + data |= (m68ki_read_8((mc68kcpu), ea+4) << offset) >> 8; + + (mc68kcpu)->n_flag = NFLAG_32(data); + data = MAKE_INT_32(data) >> (32 - width); + + (mc68kcpu)->not_z_flag = data; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + + REG_D(mc68kcpu)[(word2 >> 12) & 7] = data; + + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_bfexts_32_ix(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + INT32 offset = (word2>>6)&31; + UINT32 width = word2; + UINT32 data; + UINT32 ea = EA_AY_IX_8(mc68kcpu); + + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D(mc68kcpu)[offset&7]); + if(BIT_5(word2)) + width = REG_D(mc68kcpu)[width&7]; + + if(BIT_B(word2)) + { + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + offset %= 8; + if(offset < 0) + { + offset += 8; + ea--; + } + } + width = ((width-1) & 31) + 1; + + data = (offset+width) < 8 ? (m68ki_read_8((mc68kcpu), ea) << 24) : + (offset+width) < 16 ? (m68ki_read_16((mc68kcpu), ea) << 16) : m68ki_read_32((mc68kcpu), ea); + + data = MASK_OUT_ABOVE_32(data< 32) + data |= (m68ki_read_8((mc68kcpu), ea+4) << offset) >> 8; + + (mc68kcpu)->n_flag = NFLAG_32(data); + data = MAKE_INT_32(data) >> (32 - width); + + (mc68kcpu)->not_z_flag = data; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + + REG_D(mc68kcpu)[(word2 >> 12) & 7] = data; + + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_bfexts_32_aw(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + INT32 offset = (word2>>6)&31; + UINT32 width = word2; + UINT32 data; + UINT32 ea = EA_AW_8(mc68kcpu); + + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D(mc68kcpu)[offset&7]); + if(BIT_5(word2)) + width = REG_D(mc68kcpu)[width&7]; + + if(BIT_B(word2)) + { + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + offset %= 8; + if(offset < 0) + { + offset += 8; + ea--; + } + } + width = ((width-1) & 31) + 1; + + data = (offset+width) < 8 ? (m68ki_read_8((mc68kcpu), ea) << 24) : + (offset+width) < 16 ? (m68ki_read_16((mc68kcpu), ea) << 16) : m68ki_read_32((mc68kcpu), ea); + + data = MASK_OUT_ABOVE_32(data< 32) + data |= (m68ki_read_8((mc68kcpu), ea+4) << offset) >> 8; + + (mc68kcpu)->n_flag = NFLAG_32(data); + data = MAKE_INT_32(data) >> (32 - width); + + (mc68kcpu)->not_z_flag = data; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + + REG_D(mc68kcpu)[(word2 >> 12) & 7] = data; + + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_bfexts_32_al(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + INT32 offset = (word2>>6)&31; + UINT32 width = word2; + UINT32 data; + UINT32 ea = EA_AL_8(mc68kcpu); + + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D(mc68kcpu)[offset&7]); + if(BIT_5(word2)) + width = REG_D(mc68kcpu)[width&7]; + + if(BIT_B(word2)) + { + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + offset %= 8; + if(offset < 0) + { + offset += 8; + ea--; + } + } + width = ((width-1) & 31) + 1; + + data = (offset+width) < 8 ? (m68ki_read_8((mc68kcpu), ea) << 24) : + (offset+width) < 16 ? (m68ki_read_16((mc68kcpu), ea) << 16) : m68ki_read_32((mc68kcpu), ea); + + data = MASK_OUT_ABOVE_32(data< 32) + data |= (m68ki_read_8((mc68kcpu), ea+4) << offset) >> 8; + + (mc68kcpu)->n_flag = NFLAG_32(data); + data = MAKE_INT_32(data) >> (32 - width); + + (mc68kcpu)->not_z_flag = data; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + + REG_D(mc68kcpu)[(word2 >> 12) & 7] = data; + + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_bfexts_32_pcdi(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + INT32 offset = (word2>>6)&31; + UINT32 width = word2; + UINT32 data; + UINT32 ea = EA_PCDI_8(mc68kcpu); + + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D(mc68kcpu)[offset&7]); + if(BIT_5(word2)) + width = REG_D(mc68kcpu)[width&7]; + + if(BIT_B(word2)) + { + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + offset %= 8; + if(offset < 0) + { + offset += 8; + ea--; + } + } + width = ((width-1) & 31) + 1; + + data = (offset+width) < 8 ? (m68ki_read_8((mc68kcpu), ea) << 24) : + (offset+width) < 16 ? (m68ki_read_16((mc68kcpu), ea) << 16) : m68ki_read_32((mc68kcpu), ea); + + data = MASK_OUT_ABOVE_32(data< 32) + data |= (m68ki_read_8((mc68kcpu), ea+4) << offset) >> 8; + + (mc68kcpu)->n_flag = NFLAG_32(data); + data = MAKE_INT_32(data) >> (32 - width); + + (mc68kcpu)->not_z_flag = data; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + + REG_D(mc68kcpu)[(word2 >> 12) & 7] = data; + + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_bfexts_32_pcix(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + INT32 offset = (word2>>6)&31; + UINT32 width = word2; + UINT32 data; + UINT32 ea = EA_PCIX_8(mc68kcpu); + + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D(mc68kcpu)[offset&7]); + if(BIT_5(word2)) + width = REG_D(mc68kcpu)[width&7]; + + if(BIT_B(word2)) + { + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + offset %= 8; + if(offset < 0) + { + offset += 8; + ea--; + } + } + width = ((width-1) & 31) + 1; + + data = (offset+width) < 8 ? (m68ki_read_8((mc68kcpu), ea) << 24) : + (offset+width) < 16 ? (m68ki_read_16((mc68kcpu), ea) << 16) : m68ki_read_32((mc68kcpu), ea); + + data = MASK_OUT_ABOVE_32(data< 32) + data |= (m68ki_read_8((mc68kcpu), ea+4) << offset) >> 8; + + (mc68kcpu)->n_flag = NFLAG_32(data); + data = MAKE_INT_32(data) >> (32 - width); + + (mc68kcpu)->not_z_flag = data; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + + REG_D(mc68kcpu)[(word2 >> 12) & 7] = data; + + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_bfextu_32_d(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT32 offset = (word2>>6)&31; + UINT32 width = word2; + UINT64 data = DY(mc68kcpu); + + + if(BIT_B(word2)) + offset = REG_D(mc68kcpu)[offset&7]; + if(BIT_5(word2)) + width = REG_D(mc68kcpu)[width&7]; + + offset &= 31; + width = ((width-1) & 31) + 1; + + data = ROL_32(data, offset); + (mc68kcpu)->n_flag = NFLAG_32(data); + data >>= 32 - width; + + (mc68kcpu)->not_z_flag = data; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + + REG_D(mc68kcpu)[(word2>>12)&7] = data; + + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_bfextu_32_ai(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + INT32 offset = (word2>>6)&31; + UINT32 width = word2; + UINT32 data; + UINT32 ea = EA_AY_AI_8(mc68kcpu); + + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D(mc68kcpu)[offset&7]); + if(BIT_5(word2)) + width = REG_D(mc68kcpu)[width&7]; + + if(BIT_B(word2)) + { + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + offset %= 8; + if(offset < 0) + { + offset += 8; + ea--; + } + } + width = ((width-1) & 31) + 1; + + data = (offset+width) < 8 ? (m68ki_read_8((mc68kcpu), ea) << 24) : + (offset+width) < 16 ? (m68ki_read_16((mc68kcpu), ea) << 16) : m68ki_read_32((mc68kcpu), ea); + data = MASK_OUT_ABOVE_32(data< 32) + data |= (m68ki_read_8((mc68kcpu), ea+4) << offset) >> 8; + + (mc68kcpu)->n_flag = NFLAG_32(data); + data >>= (32 - width); + + (mc68kcpu)->not_z_flag = data; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + + REG_D(mc68kcpu)[(word2 >> 12) & 7] = data; + + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_bfextu_32_di(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + INT32 offset = (word2>>6)&31; + UINT32 width = word2; + UINT32 data; + UINT32 ea = EA_AY_DI_8(mc68kcpu); + + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D(mc68kcpu)[offset&7]); + if(BIT_5(word2)) + width = REG_D(mc68kcpu)[width&7]; + + if(BIT_B(word2)) + { + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + offset %= 8; + if(offset < 0) + { + offset += 8; + ea--; + } + } + width = ((width-1) & 31) + 1; + + data = (offset+width) < 8 ? (m68ki_read_8((mc68kcpu), ea) << 24) : + (offset+width) < 16 ? (m68ki_read_16((mc68kcpu), ea) << 16) : m68ki_read_32((mc68kcpu), ea); + data = MASK_OUT_ABOVE_32(data< 32) + data |= (m68ki_read_8((mc68kcpu), ea+4) << offset) >> 8; + + (mc68kcpu)->n_flag = NFLAG_32(data); + data >>= (32 - width); + + (mc68kcpu)->not_z_flag = data; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + + REG_D(mc68kcpu)[(word2 >> 12) & 7] = data; + + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_bfextu_32_ix(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + INT32 offset = (word2>>6)&31; + UINT32 width = word2; + UINT32 data; + UINT32 ea = EA_AY_IX_8(mc68kcpu); + + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D(mc68kcpu)[offset&7]); + if(BIT_5(word2)) + width = REG_D(mc68kcpu)[width&7]; + + if(BIT_B(word2)) + { + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + offset %= 8; + if(offset < 0) + { + offset += 8; + ea--; + } + } + width = ((width-1) & 31) + 1; + + data = (offset+width) < 8 ? (m68ki_read_8((mc68kcpu), ea) << 24) : + (offset+width) < 16 ? (m68ki_read_16((mc68kcpu), ea) << 16) : m68ki_read_32((mc68kcpu), ea); + data = MASK_OUT_ABOVE_32(data< 32) + data |= (m68ki_read_8((mc68kcpu), ea+4) << offset) >> 8; + + (mc68kcpu)->n_flag = NFLAG_32(data); + data >>= (32 - width); + + (mc68kcpu)->not_z_flag = data; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + + REG_D(mc68kcpu)[(word2 >> 12) & 7] = data; + + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_bfextu_32_aw(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + INT32 offset = (word2>>6)&31; + UINT32 width = word2; + UINT32 data; + UINT32 ea = EA_AW_8(mc68kcpu); + + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D(mc68kcpu)[offset&7]); + if(BIT_5(word2)) + width = REG_D(mc68kcpu)[width&7]; + + if(BIT_B(word2)) + { + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + offset %= 8; + if(offset < 0) + { + offset += 8; + ea--; + } + } + width = ((width-1) & 31) + 1; + + data = (offset+width) < 8 ? (m68ki_read_8((mc68kcpu), ea) << 24) : + (offset+width) < 16 ? (m68ki_read_16((mc68kcpu), ea) << 16) : m68ki_read_32((mc68kcpu), ea); + data = MASK_OUT_ABOVE_32(data< 32) + data |= (m68ki_read_8((mc68kcpu), ea+4) << offset) >> 8; + + (mc68kcpu)->n_flag = NFLAG_32(data); + data >>= (32 - width); + + (mc68kcpu)->not_z_flag = data; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + + REG_D(mc68kcpu)[(word2 >> 12) & 7] = data; + + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_bfextu_32_al(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + INT32 offset = (word2>>6)&31; + UINT32 width = word2; + UINT32 data; + UINT32 ea = EA_AL_8(mc68kcpu); + + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D(mc68kcpu)[offset&7]); + if(BIT_5(word2)) + width = REG_D(mc68kcpu)[width&7]; + + if(BIT_B(word2)) + { + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + offset %= 8; + if(offset < 0) + { + offset += 8; + ea--; + } + } + width = ((width-1) & 31) + 1; + + data = (offset+width) < 8 ? (m68ki_read_8((mc68kcpu), ea) << 24) : + (offset+width) < 16 ? (m68ki_read_16((mc68kcpu), ea) << 16) : m68ki_read_32((mc68kcpu), ea); + data = MASK_OUT_ABOVE_32(data< 32) + data |= (m68ki_read_8((mc68kcpu), ea+4) << offset) >> 8; + + (mc68kcpu)->n_flag = NFLAG_32(data); + data >>= (32 - width); + + (mc68kcpu)->not_z_flag = data; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + + REG_D(mc68kcpu)[(word2 >> 12) & 7] = data; + + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_bfextu_32_pcdi(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + INT32 offset = (word2>>6)&31; + UINT32 width = word2; + UINT32 data; + UINT32 ea = EA_PCDI_8(mc68kcpu); + + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D(mc68kcpu)[offset&7]); + if(BIT_5(word2)) + width = REG_D(mc68kcpu)[width&7]; + + if(BIT_B(word2)) + { + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + offset %= 8; + if(offset < 0) + { + offset += 8; + ea--; + } + } + width = ((width-1) & 31) + 1; + + data = (offset+width) < 8 ? (m68ki_read_8((mc68kcpu), ea) << 24) : + (offset+width) < 16 ? (m68ki_read_16((mc68kcpu), ea) << 16) : m68ki_read_32((mc68kcpu), ea); + data = MASK_OUT_ABOVE_32(data< 32) + data |= (m68ki_read_8((mc68kcpu), ea+4) << offset) >> 8; + + (mc68kcpu)->n_flag = NFLAG_32(data); + data >>= (32 - width); + + (mc68kcpu)->not_z_flag = data; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + + REG_D(mc68kcpu)[(word2 >> 12) & 7] = data; + + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_bfextu_32_pcix(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + INT32 offset = (word2>>6)&31; + UINT32 width = word2; + UINT32 data; + UINT32 ea = EA_PCIX_8(mc68kcpu); + + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D(mc68kcpu)[offset&7]); + if(BIT_5(word2)) + width = REG_D(mc68kcpu)[width&7]; + + if(BIT_B(word2)) + { + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + offset %= 8; + if(offset < 0) + { + offset += 8; + ea--; + } + } + width = ((width-1) & 31) + 1; + + data = (offset+width) < 8 ? (m68ki_read_8((mc68kcpu), ea) << 24) : + (offset+width) < 16 ? (m68ki_read_16((mc68kcpu), ea) << 16) : m68ki_read_32((mc68kcpu), ea); + data = MASK_OUT_ABOVE_32(data< 32) + data |= (m68ki_read_8((mc68kcpu), ea+4) << offset) >> 8; + + (mc68kcpu)->n_flag = NFLAG_32(data); + data >>= (32 - width); + + (mc68kcpu)->not_z_flag = data; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + + REG_D(mc68kcpu)[(word2 >> 12) & 7] = data; + + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_bfffo_32_d(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT32 offset = (word2>>6)&31; + UINT32 width = word2; + UINT64 data = DY(mc68kcpu); + UINT32 bit; + + + if(BIT_B(word2)) + offset = REG_D(mc68kcpu)[offset&7]; + if(BIT_5(word2)) + width = REG_D(mc68kcpu)[width&7]; + + offset &= 31; + width = ((width-1) & 31) + 1; + + data = ROL_32(data, offset); + (mc68kcpu)->n_flag = NFLAG_32(data); + data >>= 32 - width; + + (mc68kcpu)->not_z_flag = data; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + + for(bit = 1<<(width-1);bit && !(data & bit);bit>>= 1) + offset++; + + REG_D(mc68kcpu)[(word2>>12)&7] = offset; + + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_bfffo_32_ai(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + INT32 offset = (word2>>6)&31; + INT32 local_offset; + UINT32 width = word2; + UINT32 data; + UINT32 bit; + UINT32 ea = EA_AY_AI_8(mc68kcpu); + + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D(mc68kcpu)[offset&7]); + if(BIT_5(word2)) + width = REG_D(mc68kcpu)[width&7]; + + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + local_offset = offset % 8; + if(local_offset < 0) + { + local_offset += 8; + ea--; + } + width = ((width-1) & 31) + 1; + + data = (offset+width) < 16 ? (m68ki_read_16((mc68kcpu), ea) << 16) : m68ki_read_32((mc68kcpu), ea); + data = MASK_OUT_ABOVE_32(data< 32) + data |= (m68ki_read_8((mc68kcpu), ea+4) << local_offset) >> 8; + + (mc68kcpu)->n_flag = NFLAG_32(data); + data >>= (32 - width); + + (mc68kcpu)->not_z_flag = data; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + + for(bit = 1<<(width-1);bit && !(data & bit);bit>>= 1) + offset++; + + REG_D(mc68kcpu)[(word2>>12)&7] = offset; + + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_bfffo_32_di(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + INT32 offset = (word2>>6)&31; + INT32 local_offset; + UINT32 width = word2; + UINT32 data; + UINT32 bit; + UINT32 ea = EA_AY_DI_8(mc68kcpu); + + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D(mc68kcpu)[offset&7]); + if(BIT_5(word2)) + width = REG_D(mc68kcpu)[width&7]; + + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + local_offset = offset % 8; + if(local_offset < 0) + { + local_offset += 8; + ea--; + } + width = ((width-1) & 31) + 1; + + data = (offset+width) < 16 ? (m68ki_read_16((mc68kcpu), ea) << 16) : m68ki_read_32((mc68kcpu), ea); + data = MASK_OUT_ABOVE_32(data< 32) + data |= (m68ki_read_8((mc68kcpu), ea+4) << local_offset) >> 8; + + (mc68kcpu)->n_flag = NFLAG_32(data); + data >>= (32 - width); + + (mc68kcpu)->not_z_flag = data; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + + for(bit = 1<<(width-1);bit && !(data & bit);bit>>= 1) + offset++; + + REG_D(mc68kcpu)[(word2>>12)&7] = offset; + + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_bfffo_32_ix(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + INT32 offset = (word2>>6)&31; + INT32 local_offset; + UINT32 width = word2; + UINT32 data; + UINT32 bit; + UINT32 ea = EA_AY_IX_8(mc68kcpu); + + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D(mc68kcpu)[offset&7]); + if(BIT_5(word2)) + width = REG_D(mc68kcpu)[width&7]; + + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + local_offset = offset % 8; + if(local_offset < 0) + { + local_offset += 8; + ea--; + } + width = ((width-1) & 31) + 1; + + data = (offset+width) < 16 ? (m68ki_read_16((mc68kcpu), ea) << 16) : m68ki_read_32((mc68kcpu), ea); + data = MASK_OUT_ABOVE_32(data< 32) + data |= (m68ki_read_8((mc68kcpu), ea+4) << local_offset) >> 8; + + (mc68kcpu)->n_flag = NFLAG_32(data); + data >>= (32 - width); + + (mc68kcpu)->not_z_flag = data; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + + for(bit = 1<<(width-1);bit && !(data & bit);bit>>= 1) + offset++; + + REG_D(mc68kcpu)[(word2>>12)&7] = offset; + + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_bfffo_32_aw(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + INT32 offset = (word2>>6)&31; + INT32 local_offset; + UINT32 width = word2; + UINT32 data; + UINT32 bit; + UINT32 ea = EA_AW_8(mc68kcpu); + + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D(mc68kcpu)[offset&7]); + if(BIT_5(word2)) + width = REG_D(mc68kcpu)[width&7]; + + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + local_offset = offset % 8; + if(local_offset < 0) + { + local_offset += 8; + ea--; + } + width = ((width-1) & 31) + 1; + + data = (offset+width) < 16 ? (m68ki_read_16((mc68kcpu), ea) << 16) : m68ki_read_32((mc68kcpu), ea); + data = MASK_OUT_ABOVE_32(data< 32) + data |= (m68ki_read_8((mc68kcpu), ea+4) << local_offset) >> 8; + + (mc68kcpu)->n_flag = NFLAG_32(data); + data >>= (32 - width); + + (mc68kcpu)->not_z_flag = data; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + + for(bit = 1<<(width-1);bit && !(data & bit);bit>>= 1) + offset++; + + REG_D(mc68kcpu)[(word2>>12)&7] = offset; + + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_bfffo_32_al(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + INT32 offset = (word2>>6)&31; + INT32 local_offset; + UINT32 width = word2; + UINT32 data; + UINT32 bit; + UINT32 ea = EA_AL_8(mc68kcpu); + + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D(mc68kcpu)[offset&7]); + if(BIT_5(word2)) + width = REG_D(mc68kcpu)[width&7]; + + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + local_offset = offset % 8; + if(local_offset < 0) + { + local_offset += 8; + ea--; + } + width = ((width-1) & 31) + 1; + + data = (offset+width) < 16 ? (m68ki_read_16((mc68kcpu), ea) << 16) : m68ki_read_32((mc68kcpu), ea); + data = MASK_OUT_ABOVE_32(data< 32) + data |= (m68ki_read_8((mc68kcpu), ea+4) << local_offset) >> 8; + + (mc68kcpu)->n_flag = NFLAG_32(data); + data >>= (32 - width); + + (mc68kcpu)->not_z_flag = data; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + + for(bit = 1<<(width-1);bit && !(data & bit);bit>>= 1) + offset++; + + REG_D(mc68kcpu)[(word2>>12)&7] = offset; + + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_bfffo_32_pcdi(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + INT32 offset = (word2>>6)&31; + INT32 local_offset; + UINT32 width = word2; + UINT32 data; + UINT32 bit; + UINT32 ea = EA_PCDI_8(mc68kcpu); + + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D(mc68kcpu)[offset&7]); + if(BIT_5(word2)) + width = REG_D(mc68kcpu)[width&7]; + + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + local_offset = offset % 8; + if(local_offset < 0) + { + local_offset += 8; + ea--; + } + width = ((width-1) & 31) + 1; + + data = (offset+width) < 16 ? (m68ki_read_16((mc68kcpu), ea) << 16) : m68ki_read_32((mc68kcpu), ea); + data = MASK_OUT_ABOVE_32(data< 32) + data |= (m68ki_read_8((mc68kcpu), ea+4) << local_offset) >> 8; + + (mc68kcpu)->n_flag = NFLAG_32(data); + data >>= (32 - width); + + (mc68kcpu)->not_z_flag = data; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + + for(bit = 1<<(width-1);bit && !(data & bit);bit>>= 1) + offset++; + + REG_D(mc68kcpu)[(word2>>12)&7] = offset; + + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_bfffo_32_pcix(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + INT32 offset = (word2>>6)&31; + INT32 local_offset; + UINT32 width = word2; + UINT32 data; + UINT32 bit; + UINT32 ea = EA_PCIX_8(mc68kcpu); + + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D(mc68kcpu)[offset&7]); + if(BIT_5(word2)) + width = REG_D(mc68kcpu)[width&7]; + + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + local_offset = offset % 8; + if(local_offset < 0) + { + local_offset += 8; + ea--; + } + width = ((width-1) & 31) + 1; + + data = (offset+width) < 16 ? (m68ki_read_16((mc68kcpu), ea) << 16) : m68ki_read_32((mc68kcpu), ea); + data = MASK_OUT_ABOVE_32(data< 32) + data |= (m68ki_read_8((mc68kcpu), ea+4) << local_offset) >> 8; + + (mc68kcpu)->n_flag = NFLAG_32(data); + data >>= (32 - width); + + (mc68kcpu)->not_z_flag = data; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + + for(bit = 1<<(width-1);bit && !(data & bit);bit>>= 1) + offset++; + + REG_D(mc68kcpu)[(word2>>12)&7] = offset; + + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_bfins_32_d(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT32 offset = (word2>>6)&31; + UINT32 width = word2; + UINT32* data = &DY(mc68kcpu); + UINT64 mask; + UINT64 insert = REG_D(mc68kcpu)[(word2>>12)&7]; + + + if(BIT_B(word2)) + offset = REG_D(mc68kcpu)[offset&7]; + if(BIT_5(word2)) + width = REG_D(mc68kcpu)[width&7]; + + + offset &= 31; + width = ((width-1) & 31) + 1; + + + mask = MASK_OUT_ABOVE_32(0xffffffff << (32 - width)); + mask = ROR_32(mask, offset); + + insert = MASK_OUT_ABOVE_32(insert << (32 - width)); + (mc68kcpu)->n_flag = NFLAG_32(insert); + (mc68kcpu)->not_z_flag = insert; + insert = ROR_32(insert, offset); + + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + + *data &= ~mask; + *data |= insert; + + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_bfins_32_ai(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + INT32 offset = (word2>>6)&31; + UINT32 width = word2; + UINT32 insert_base = REG_D(mc68kcpu)[(word2>>12)&7]; + UINT32 insert_long; + UINT32 insert_byte; + UINT32 mask_base; + UINT32 data_long; + UINT32 mask_long; + UINT32 data_byte = 0; + UINT32 mask_byte = 0; + UINT32 ea = EA_AY_AI_8(mc68kcpu); + + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D(mc68kcpu)[offset&7]); + if(BIT_5(word2)) + width = REG_D(mc68kcpu)[width&7]; + + if(BIT_B(word2)) + { + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + offset %= 8; + if(offset < 0) + { + offset += 8; + ea--; + } + } + width = ((width-1) & 31) + 1; + + mask_base = MASK_OUT_ABOVE_32(0xffffffff << (32 - width)); + mask_long = mask_base >> offset; + + insert_base = MASK_OUT_ABOVE_32(insert_base << (32 - width)); + (mc68kcpu)->n_flag = NFLAG_32(insert_base); + (mc68kcpu)->not_z_flag = insert_base; + insert_long = insert_base >> offset; + + data_long = (offset+width) < 8 ? (m68ki_read_8((mc68kcpu), ea) << 24) : + (offset+width) < 16 ? (m68ki_read_16((mc68kcpu), ea) << 16) : m68ki_read_32((mc68kcpu), ea); + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + + if((width + offset) < 8) + { + m68ki_write_8((mc68kcpu), ea, ((data_long & ~mask_long) | insert_long) >> 24); + } + else if((width + offset) < 16) + { + m68ki_write_16((mc68kcpu), ea, ((data_long & ~mask_long) | insert_long) >> 16); + } + else + { + m68ki_write_32((mc68kcpu), ea, (data_long & ~mask_long) | insert_long); + } + + if((width + offset) > 32) + { + mask_byte = MASK_OUT_ABOVE_8(mask_base); + insert_byte = MASK_OUT_ABOVE_8(insert_base); + data_byte = m68ki_read_8((mc68kcpu), ea+4); + (mc68kcpu)->not_z_flag |= (data_byte & mask_byte); + m68ki_write_8((mc68kcpu), ea+4, (data_byte & ~mask_byte) | insert_byte); + } + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_bfins_32_di(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + INT32 offset = (word2>>6)&31; + UINT32 width = word2; + UINT32 insert_base = REG_D(mc68kcpu)[(word2>>12)&7]; + UINT32 insert_long; + UINT32 insert_byte; + UINT32 mask_base; + UINT32 data_long; + UINT32 mask_long; + UINT32 data_byte = 0; + UINT32 mask_byte = 0; + UINT32 ea = EA_AY_DI_8(mc68kcpu); + + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D(mc68kcpu)[offset&7]); + if(BIT_5(word2)) + width = REG_D(mc68kcpu)[width&7]; + + if(BIT_B(word2)) + { + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + offset %= 8; + if(offset < 0) + { + offset += 8; + ea--; + } + } + width = ((width-1) & 31) + 1; + + mask_base = MASK_OUT_ABOVE_32(0xffffffff << (32 - width)); + mask_long = mask_base >> offset; + + insert_base = MASK_OUT_ABOVE_32(insert_base << (32 - width)); + (mc68kcpu)->n_flag = NFLAG_32(insert_base); + (mc68kcpu)->not_z_flag = insert_base; + insert_long = insert_base >> offset; + + data_long = (offset+width) < 8 ? (m68ki_read_8((mc68kcpu), ea) << 24) : + (offset+width) < 16 ? (m68ki_read_16((mc68kcpu), ea) << 16) : m68ki_read_32((mc68kcpu), ea); + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + + if((width + offset) < 8) + { + m68ki_write_8((mc68kcpu), ea, ((data_long & ~mask_long) | insert_long) >> 24); + } + else if((width + offset) < 16) + { + m68ki_write_16((mc68kcpu), ea, ((data_long & ~mask_long) | insert_long) >> 16); + } + else + { + m68ki_write_32((mc68kcpu), ea, (data_long & ~mask_long) | insert_long); + } + + if((width + offset) > 32) + { + mask_byte = MASK_OUT_ABOVE_8(mask_base); + insert_byte = MASK_OUT_ABOVE_8(insert_base); + data_byte = m68ki_read_8((mc68kcpu), ea+4); + (mc68kcpu)->not_z_flag |= (data_byte & mask_byte); + m68ki_write_8((mc68kcpu), ea+4, (data_byte & ~mask_byte) | insert_byte); + } + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_bfins_32_ix(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + INT32 offset = (word2>>6)&31; + UINT32 width = word2; + UINT32 insert_base = REG_D(mc68kcpu)[(word2>>12)&7]; + UINT32 insert_long; + UINT32 insert_byte; + UINT32 mask_base; + UINT32 data_long; + UINT32 mask_long; + UINT32 data_byte = 0; + UINT32 mask_byte = 0; + UINT32 ea = EA_AY_IX_8(mc68kcpu); + + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D(mc68kcpu)[offset&7]); + if(BIT_5(word2)) + width = REG_D(mc68kcpu)[width&7]; + + if(BIT_B(word2)) + { + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + offset %= 8; + if(offset < 0) + { + offset += 8; + ea--; + } + } + width = ((width-1) & 31) + 1; + + mask_base = MASK_OUT_ABOVE_32(0xffffffff << (32 - width)); + mask_long = mask_base >> offset; + + insert_base = MASK_OUT_ABOVE_32(insert_base << (32 - width)); + (mc68kcpu)->n_flag = NFLAG_32(insert_base); + (mc68kcpu)->not_z_flag = insert_base; + insert_long = insert_base >> offset; + + data_long = (offset+width) < 8 ? (m68ki_read_8((mc68kcpu), ea) << 24) : + (offset+width) < 16 ? (m68ki_read_16((mc68kcpu), ea) << 16) : m68ki_read_32((mc68kcpu), ea); + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + + if((width + offset) < 8) + { + m68ki_write_8((mc68kcpu), ea, ((data_long & ~mask_long) | insert_long) >> 24); + } + else if((width + offset) < 16) + { + m68ki_write_16((mc68kcpu), ea, ((data_long & ~mask_long) | insert_long) >> 16); + } + else + { + m68ki_write_32((mc68kcpu), ea, (data_long & ~mask_long) | insert_long); + } + + if((width + offset) > 32) + { + mask_byte = MASK_OUT_ABOVE_8(mask_base); + insert_byte = MASK_OUT_ABOVE_8(insert_base); + data_byte = m68ki_read_8((mc68kcpu), ea+4); + (mc68kcpu)->not_z_flag |= (data_byte & mask_byte); + m68ki_write_8((mc68kcpu), ea+4, (data_byte & ~mask_byte) | insert_byte); + } + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_bfins_32_aw(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + INT32 offset = (word2>>6)&31; + UINT32 width = word2; + UINT32 insert_base = REG_D(mc68kcpu)[(word2>>12)&7]; + UINT32 insert_long; + UINT32 insert_byte; + UINT32 mask_base; + UINT32 data_long; + UINT32 mask_long; + UINT32 data_byte = 0; + UINT32 mask_byte = 0; + UINT32 ea = EA_AW_8(mc68kcpu); + + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D(mc68kcpu)[offset&7]); + if(BIT_5(word2)) + width = REG_D(mc68kcpu)[width&7]; + + if(BIT_B(word2)) + { + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + offset %= 8; + if(offset < 0) + { + offset += 8; + ea--; + } + } + width = ((width-1) & 31) + 1; + + mask_base = MASK_OUT_ABOVE_32(0xffffffff << (32 - width)); + mask_long = mask_base >> offset; + + insert_base = MASK_OUT_ABOVE_32(insert_base << (32 - width)); + (mc68kcpu)->n_flag = NFLAG_32(insert_base); + (mc68kcpu)->not_z_flag = insert_base; + insert_long = insert_base >> offset; + + data_long = (offset+width) < 8 ? (m68ki_read_8((mc68kcpu), ea) << 24) : + (offset+width) < 16 ? (m68ki_read_16((mc68kcpu), ea) << 16) : m68ki_read_32((mc68kcpu), ea); + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + + if((width + offset) < 8) + { + m68ki_write_8((mc68kcpu), ea, ((data_long & ~mask_long) | insert_long) >> 24); + } + else if((width + offset) < 16) + { + m68ki_write_16((mc68kcpu), ea, ((data_long & ~mask_long) | insert_long) >> 16); + } + else + { + m68ki_write_32((mc68kcpu), ea, (data_long & ~mask_long) | insert_long); + } + + if((width + offset) > 32) + { + mask_byte = MASK_OUT_ABOVE_8(mask_base); + insert_byte = MASK_OUT_ABOVE_8(insert_base); + data_byte = m68ki_read_8((mc68kcpu), ea+4); + (mc68kcpu)->not_z_flag |= (data_byte & mask_byte); + m68ki_write_8((mc68kcpu), ea+4, (data_byte & ~mask_byte) | insert_byte); + } + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_bfins_32_al(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + INT32 offset = (word2>>6)&31; + UINT32 width = word2; + UINT32 insert_base = REG_D(mc68kcpu)[(word2>>12)&7]; + UINT32 insert_long; + UINT32 insert_byte; + UINT32 mask_base; + UINT32 data_long; + UINT32 mask_long; + UINT32 data_byte = 0; + UINT32 mask_byte = 0; + UINT32 ea = EA_AL_8(mc68kcpu); + + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D(mc68kcpu)[offset&7]); + if(BIT_5(word2)) + width = REG_D(mc68kcpu)[width&7]; + + if(BIT_B(word2)) + { + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + offset %= 8; + if(offset < 0) + { + offset += 8; + ea--; + } + } + width = ((width-1) & 31) + 1; + + mask_base = MASK_OUT_ABOVE_32(0xffffffff << (32 - width)); + mask_long = mask_base >> offset; + + insert_base = MASK_OUT_ABOVE_32(insert_base << (32 - width)); + (mc68kcpu)->n_flag = NFLAG_32(insert_base); + (mc68kcpu)->not_z_flag = insert_base; + insert_long = insert_base >> offset; + + data_long = (offset+width) < 8 ? (m68ki_read_8((mc68kcpu), ea) << 24) : + (offset+width) < 16 ? (m68ki_read_16((mc68kcpu), ea) << 16) : m68ki_read_32((mc68kcpu), ea); + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + + if((width + offset) < 8) + { + m68ki_write_8((mc68kcpu), ea, ((data_long & ~mask_long) | insert_long) >> 24); + } + else if((width + offset) < 16) + { + m68ki_write_16((mc68kcpu), ea, ((data_long & ~mask_long) | insert_long) >> 16); + } + else + { + m68ki_write_32((mc68kcpu), ea, (data_long & ~mask_long) | insert_long); + } + + if((width + offset) > 32) + { + mask_byte = MASK_OUT_ABOVE_8(mask_base); + insert_byte = MASK_OUT_ABOVE_8(insert_base); + data_byte = m68ki_read_8((mc68kcpu), ea+4); + (mc68kcpu)->not_z_flag |= (data_byte & mask_byte); + m68ki_write_8((mc68kcpu), ea+4, (data_byte & ~mask_byte) | insert_byte); + } + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_bfset_32_d(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT32 offset = (word2>>6)&31; + UINT32 width = word2; + UINT32* data = &DY(mc68kcpu); + UINT64 mask; + + + if(BIT_B(word2)) + offset = REG_D(mc68kcpu)[offset&7]; + if(BIT_5(word2)) + width = REG_D(mc68kcpu)[width&7]; + + + offset &= 31; + width = ((width-1) & 31) + 1; + + + mask = MASK_OUT_ABOVE_32(0xffffffff << (32 - width)); + mask = ROR_32(mask, offset); + + (mc68kcpu)->n_flag = NFLAG_32(*data<not_z_flag = *data & mask; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + + *data |= mask; + + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_bfset_32_ai(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + INT32 offset = (word2>>6)&31; + UINT32 width = word2; + UINT32 mask_base; + UINT32 data_long; + UINT32 mask_long; + UINT32 data_byte = 0; + UINT32 mask_byte = 0; + UINT32 ea = EA_AY_AI_8(mc68kcpu); + + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D(mc68kcpu)[offset&7]); + if(BIT_5(word2)) + width = REG_D(mc68kcpu)[width&7]; + + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + offset %= 8; + if(offset < 0) + { + offset += 8; + ea--; + } + width = ((width-1) & 31) + 1; + + + mask_base = MASK_OUT_ABOVE_32(0xffffffff << (32 - width)); + mask_long = mask_base >> offset; + + data_long = m68ki_read_32((mc68kcpu), ea); + (mc68kcpu)->n_flag = NFLAG_32(data_long << offset); + (mc68kcpu)->not_z_flag = data_long & mask_long; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + + m68ki_write_32((mc68kcpu), ea, data_long | mask_long); + + if((width + offset) > 32) + { + mask_byte = MASK_OUT_ABOVE_8(mask_base); + data_byte = m68ki_read_8((mc68kcpu), ea+4); + (mc68kcpu)->not_z_flag |= (data_byte & mask_byte); + m68ki_write_8((mc68kcpu), ea+4, data_byte | mask_byte); + } + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_bfset_32_di(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + INT32 offset = (word2>>6)&31; + UINT32 width = word2; + UINT32 mask_base; + UINT32 data_long; + UINT32 mask_long; + UINT32 data_byte = 0; + UINT32 mask_byte = 0; + UINT32 ea = EA_AY_DI_8(mc68kcpu); + + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D(mc68kcpu)[offset&7]); + if(BIT_5(word2)) + width = REG_D(mc68kcpu)[width&7]; + + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + offset %= 8; + if(offset < 0) + { + offset += 8; + ea--; + } + width = ((width-1) & 31) + 1; + + + mask_base = MASK_OUT_ABOVE_32(0xffffffff << (32 - width)); + mask_long = mask_base >> offset; + + data_long = m68ki_read_32((mc68kcpu), ea); + (mc68kcpu)->n_flag = NFLAG_32(data_long << offset); + (mc68kcpu)->not_z_flag = data_long & mask_long; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + + m68ki_write_32((mc68kcpu), ea, data_long | mask_long); + + if((width + offset) > 32) + { + mask_byte = MASK_OUT_ABOVE_8(mask_base); + data_byte = m68ki_read_8((mc68kcpu), ea+4); + (mc68kcpu)->not_z_flag |= (data_byte & mask_byte); + m68ki_write_8((mc68kcpu), ea+4, data_byte | mask_byte); + } + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_bfset_32_ix(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + INT32 offset = (word2>>6)&31; + UINT32 width = word2; + UINT32 mask_base; + UINT32 data_long; + UINT32 mask_long; + UINT32 data_byte = 0; + UINT32 mask_byte = 0; + UINT32 ea = EA_AY_IX_8(mc68kcpu); + + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D(mc68kcpu)[offset&7]); + if(BIT_5(word2)) + width = REG_D(mc68kcpu)[width&7]; + + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + offset %= 8; + if(offset < 0) + { + offset += 8; + ea--; + } + width = ((width-1) & 31) + 1; + + + mask_base = MASK_OUT_ABOVE_32(0xffffffff << (32 - width)); + mask_long = mask_base >> offset; + + data_long = m68ki_read_32((mc68kcpu), ea); + (mc68kcpu)->n_flag = NFLAG_32(data_long << offset); + (mc68kcpu)->not_z_flag = data_long & mask_long; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + + m68ki_write_32((mc68kcpu), ea, data_long | mask_long); + + if((width + offset) > 32) + { + mask_byte = MASK_OUT_ABOVE_8(mask_base); + data_byte = m68ki_read_8((mc68kcpu), ea+4); + (mc68kcpu)->not_z_flag |= (data_byte & mask_byte); + m68ki_write_8((mc68kcpu), ea+4, data_byte | mask_byte); + } + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_bfset_32_aw(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + INT32 offset = (word2>>6)&31; + UINT32 width = word2; + UINT32 mask_base; + UINT32 data_long; + UINT32 mask_long; + UINT32 data_byte = 0; + UINT32 mask_byte = 0; + UINT32 ea = EA_AW_8(mc68kcpu); + + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D(mc68kcpu)[offset&7]); + if(BIT_5(word2)) + width = REG_D(mc68kcpu)[width&7]; + + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + offset %= 8; + if(offset < 0) + { + offset += 8; + ea--; + } + width = ((width-1) & 31) + 1; + + + mask_base = MASK_OUT_ABOVE_32(0xffffffff << (32 - width)); + mask_long = mask_base >> offset; + + data_long = m68ki_read_32((mc68kcpu), ea); + (mc68kcpu)->n_flag = NFLAG_32(data_long << offset); + (mc68kcpu)->not_z_flag = data_long & mask_long; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + + m68ki_write_32((mc68kcpu), ea, data_long | mask_long); + + if((width + offset) > 32) + { + mask_byte = MASK_OUT_ABOVE_8(mask_base); + data_byte = m68ki_read_8((mc68kcpu), ea+4); + (mc68kcpu)->not_z_flag |= (data_byte & mask_byte); + m68ki_write_8((mc68kcpu), ea+4, data_byte | mask_byte); + } + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_bfset_32_al(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + INT32 offset = (word2>>6)&31; + UINT32 width = word2; + UINT32 mask_base; + UINT32 data_long; + UINT32 mask_long; + UINT32 data_byte = 0; + UINT32 mask_byte = 0; + UINT32 ea = EA_AL_8(mc68kcpu); + + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D(mc68kcpu)[offset&7]); + if(BIT_5(word2)) + width = REG_D(mc68kcpu)[width&7]; + + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + offset %= 8; + if(offset < 0) + { + offset += 8; + ea--; + } + width = ((width-1) & 31) + 1; + + + mask_base = MASK_OUT_ABOVE_32(0xffffffff << (32 - width)); + mask_long = mask_base >> offset; + + data_long = m68ki_read_32((mc68kcpu), ea); + (mc68kcpu)->n_flag = NFLAG_32(data_long << offset); + (mc68kcpu)->not_z_flag = data_long & mask_long; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + + m68ki_write_32((mc68kcpu), ea, data_long | mask_long); + + if((width + offset) > 32) + { + mask_byte = MASK_OUT_ABOVE_8(mask_base); + data_byte = m68ki_read_8((mc68kcpu), ea+4); + (mc68kcpu)->not_z_flag |= (data_byte & mask_byte); + m68ki_write_8((mc68kcpu), ea+4, data_byte | mask_byte); + } + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_bftst_32_d(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT32 offset = (word2>>6)&31; + UINT32 width = word2; + UINT32* data = &DY(mc68kcpu); + UINT64 mask; + + + if(BIT_B(word2)) + offset = REG_D(mc68kcpu)[offset&7]; + if(BIT_5(word2)) + width = REG_D(mc68kcpu)[width&7]; + + + offset &= 31; + width = ((width-1) & 31) + 1; + + + mask = MASK_OUT_ABOVE_32(0xffffffff << (32 - width)); + mask = ROR_32(mask, offset); + + (mc68kcpu)->n_flag = NFLAG_32(*data<not_z_flag = *data & mask; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_bftst_32_ai(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + INT32 offset = (word2>>6)&31; + UINT32 width = word2; + UINT32 mask_base; + UINT32 data_long; + UINT32 mask_long; + UINT32 data_byte = 0; + UINT32 mask_byte = 0; + UINT32 ea = EA_AY_AI_8(mc68kcpu); + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D(mc68kcpu)[offset&7]); + if(BIT_5(word2)) + width = REG_D(mc68kcpu)[width&7]; + + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + offset %= 8; + if(offset < 0) + { + offset += 8; + ea--; + } + width = ((width-1) & 31) + 1; + + + mask_base = MASK_OUT_ABOVE_32(0xffffffff << (32 - width)); + mask_long = mask_base >> offset; + + data_long = m68ki_read_32((mc68kcpu), ea); + (mc68kcpu)->n_flag = ((data_long & (0x80000000 >> offset))<>24; + (mc68kcpu)->not_z_flag = data_long & mask_long; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + + if((width + offset) > 32) + { + mask_byte = MASK_OUT_ABOVE_8(mask_base); + data_byte = m68ki_read_8((mc68kcpu), ea+4); + (mc68kcpu)->not_z_flag |= (data_byte & mask_byte); + } + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_bftst_32_di(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + INT32 offset = (word2>>6)&31; + UINT32 width = word2; + UINT32 mask_base; + UINT32 data_long; + UINT32 mask_long; + UINT32 data_byte = 0; + UINT32 mask_byte = 0; + UINT32 ea = EA_AY_DI_8(mc68kcpu); + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D(mc68kcpu)[offset&7]); + if(BIT_5(word2)) + width = REG_D(mc68kcpu)[width&7]; + + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + offset %= 8; + if(offset < 0) + { + offset += 8; + ea--; + } + width = ((width-1) & 31) + 1; + + + mask_base = MASK_OUT_ABOVE_32(0xffffffff << (32 - width)); + mask_long = mask_base >> offset; + + data_long = m68ki_read_32((mc68kcpu), ea); + (mc68kcpu)->n_flag = ((data_long & (0x80000000 >> offset))<>24; + (mc68kcpu)->not_z_flag = data_long & mask_long; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + + if((width + offset) > 32) + { + mask_byte = MASK_OUT_ABOVE_8(mask_base); + data_byte = m68ki_read_8((mc68kcpu), ea+4); + (mc68kcpu)->not_z_flag |= (data_byte & mask_byte); + } + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_bftst_32_ix(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + INT32 offset = (word2>>6)&31; + UINT32 width = word2; + UINT32 mask_base; + UINT32 data_long; + UINT32 mask_long; + UINT32 data_byte = 0; + UINT32 mask_byte = 0; + UINT32 ea = EA_AY_IX_8(mc68kcpu); + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D(mc68kcpu)[offset&7]); + if(BIT_5(word2)) + width = REG_D(mc68kcpu)[width&7]; + + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + offset %= 8; + if(offset < 0) + { + offset += 8; + ea--; + } + width = ((width-1) & 31) + 1; + + + mask_base = MASK_OUT_ABOVE_32(0xffffffff << (32 - width)); + mask_long = mask_base >> offset; + + data_long = m68ki_read_32((mc68kcpu), ea); + (mc68kcpu)->n_flag = ((data_long & (0x80000000 >> offset))<>24; + (mc68kcpu)->not_z_flag = data_long & mask_long; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + + if((width + offset) > 32) + { + mask_byte = MASK_OUT_ABOVE_8(mask_base); + data_byte = m68ki_read_8((mc68kcpu), ea+4); + (mc68kcpu)->not_z_flag |= (data_byte & mask_byte); + } + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_bftst_32_aw(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + INT32 offset = (word2>>6)&31; + UINT32 width = word2; + UINT32 mask_base; + UINT32 data_long; + UINT32 mask_long; + UINT32 data_byte = 0; + UINT32 mask_byte = 0; + UINT32 ea = EA_AW_8(mc68kcpu); + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D(mc68kcpu)[offset&7]); + if(BIT_5(word2)) + width = REG_D(mc68kcpu)[width&7]; + + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + offset %= 8; + if(offset < 0) + { + offset += 8; + ea--; + } + width = ((width-1) & 31) + 1; + + + mask_base = MASK_OUT_ABOVE_32(0xffffffff << (32 - width)); + mask_long = mask_base >> offset; + + data_long = m68ki_read_32((mc68kcpu), ea); + (mc68kcpu)->n_flag = ((data_long & (0x80000000 >> offset))<>24; + (mc68kcpu)->not_z_flag = data_long & mask_long; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + + if((width + offset) > 32) + { + mask_byte = MASK_OUT_ABOVE_8(mask_base); + data_byte = m68ki_read_8((mc68kcpu), ea+4); + (mc68kcpu)->not_z_flag |= (data_byte & mask_byte); + } + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_bftst_32_al(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + INT32 offset = (word2>>6)&31; + UINT32 width = word2; + UINT32 mask_base; + UINT32 data_long; + UINT32 mask_long; + UINT32 data_byte = 0; + UINT32 mask_byte = 0; + UINT32 ea = EA_AL_8(mc68kcpu); + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D(mc68kcpu)[offset&7]); + if(BIT_5(word2)) + width = REG_D(mc68kcpu)[width&7]; + + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + offset %= 8; + if(offset < 0) + { + offset += 8; + ea--; + } + width = ((width-1) & 31) + 1; + + + mask_base = MASK_OUT_ABOVE_32(0xffffffff << (32 - width)); + mask_long = mask_base >> offset; + + data_long = m68ki_read_32((mc68kcpu), ea); + (mc68kcpu)->n_flag = ((data_long & (0x80000000 >> offset))<>24; + (mc68kcpu)->not_z_flag = data_long & mask_long; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + + if((width + offset) > 32) + { + mask_byte = MASK_OUT_ABOVE_8(mask_base); + data_byte = m68ki_read_8((mc68kcpu), ea+4); + (mc68kcpu)->not_z_flag |= (data_byte & mask_byte); + } + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_bftst_32_pcdi(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + INT32 offset = (word2>>6)&31; + UINT32 width = word2; + UINT32 mask_base; + UINT32 data_long; + UINT32 mask_long; + UINT32 data_byte = 0; + UINT32 mask_byte = 0; + UINT32 ea = EA_PCDI_8(mc68kcpu); + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D(mc68kcpu)[offset&7]); + if(BIT_5(word2)) + width = REG_D(mc68kcpu)[width&7]; + + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + offset %= 8; + if(offset < 0) + { + offset += 8; + ea--; + } + width = ((width-1) & 31) + 1; + + + mask_base = MASK_OUT_ABOVE_32(0xffffffff << (32 - width)); + mask_long = mask_base >> offset; + + data_long = m68ki_read_32((mc68kcpu), ea); + (mc68kcpu)->n_flag = ((data_long & (0x80000000 >> offset))<>24; + (mc68kcpu)->not_z_flag = data_long & mask_long; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + + if((width + offset) > 32) + { + mask_byte = MASK_OUT_ABOVE_8(mask_base); + data_byte = m68ki_read_8((mc68kcpu), ea+4); + (mc68kcpu)->not_z_flag |= (data_byte & mask_byte); + } + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_bftst_32_pcix(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + INT32 offset = (word2>>6)&31; + UINT32 width = word2; + UINT32 mask_base; + UINT32 data_long; + UINT32 mask_long; + UINT32 data_byte = 0; + UINT32 mask_byte = 0; + UINT32 ea = EA_PCIX_8(mc68kcpu); + + if(BIT_B(word2)) + offset = MAKE_INT_32(REG_D(mc68kcpu)[offset&7]); + if(BIT_5(word2)) + width = REG_D(mc68kcpu)[width&7]; + + /* Offset is signed so we have to use ugly math =( */ + ea += offset / 8; + offset %= 8; + if(offset < 0) + { + offset += 8; + ea--; + } + width = ((width-1) & 31) + 1; + + + mask_base = MASK_OUT_ABOVE_32(0xffffffff << (32 - width)); + mask_long = mask_base >> offset; + + data_long = m68ki_read_32((mc68kcpu), ea); + (mc68kcpu)->n_flag = ((data_long & (0x80000000 >> offset))<>24; + (mc68kcpu)->not_z_flag = data_long & mask_long; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + + if((width + offset) > 32) + { + mask_byte = MASK_OUT_ABOVE_8(mask_base); + data_byte = m68ki_read_8((mc68kcpu), ea+4); + (mc68kcpu)->not_z_flag |= (data_byte & mask_byte); + } + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_bkpt(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_010_PLUS((mc68kcpu)->cpu_type)) + { + if (!(mc68kcpu)->bkpt_ack_callback.isnull()) + ((mc68kcpu)->bkpt_ack_callback)((*mc68kcpu->program), 0, CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type) ? (mc68kcpu)->ir & 7 : 0, 0xffffffff); + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_bra_8(m68000_base_device* mc68kcpu) +{ + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_8((mc68kcpu), MASK_OUT_ABOVE_8((mc68kcpu)->ir)); + if(REG_PC(mc68kcpu) == REG_PPC(mc68kcpu) && (mc68kcpu)->remaining_cycles > 0) + (mc68kcpu)->remaining_cycles = 0; +} + + +void m68000_base_device_ops::m68k_op_bra_16(m68000_base_device* mc68kcpu) +{ + UINT32 offset = OPER_I_16(mc68kcpu); + REG_PC(mc68kcpu) -= 2; + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_16((mc68kcpu), offset); + if(REG_PC(mc68kcpu) == REG_PPC(mc68kcpu) && (mc68kcpu)->remaining_cycles > 0) + (mc68kcpu)->remaining_cycles = 0; +} + + +void m68000_base_device_ops::m68k_op_bra_32(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 offset = OPER_I_32(mc68kcpu); + REG_PC(mc68kcpu) -= 4; + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_32((mc68kcpu), offset); + if(REG_PC(mc68kcpu) == REG_PPC(mc68kcpu) && (mc68kcpu)->remaining_cycles > 0) + (mc68kcpu)->remaining_cycles = 0; + return; + } + else + { + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_8((mc68kcpu), MASK_OUT_ABOVE_8((mc68kcpu)->ir)); + if(REG_PC(mc68kcpu) == REG_PPC(mc68kcpu) && (mc68kcpu)->remaining_cycles > 0) + (mc68kcpu)->remaining_cycles = 0; + } +} + + +void m68000_base_device_ops::m68k_op_bset_32_r_d(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 mask = 1 << (DX(mc68kcpu) & 0x1f); + + (mc68kcpu)->not_z_flag = *r_dst & mask; + *r_dst |= mask; +} + + +void m68000_base_device_ops::m68k_op_bset_8_r_ai(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_AI_8(mc68kcpu); + UINT32 src = m68ki_read_8((mc68kcpu), ea); + UINT32 mask = 1 << (DX(mc68kcpu) & 7); + + (mc68kcpu)->not_z_flag = src & mask; + m68ki_write_8((mc68kcpu), ea, src | mask); +} + + +void m68000_base_device_ops::m68k_op_bset_8_r_pi(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_PI_8(mc68kcpu); + UINT32 src = m68ki_read_8((mc68kcpu), ea); + UINT32 mask = 1 << (DX(mc68kcpu) & 7); + + (mc68kcpu)->not_z_flag = src & mask; + m68ki_write_8((mc68kcpu), ea, src | mask); +} + + +void m68000_base_device_ops::m68k_op_bset_8_r_pi7(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_A7_PI_8(mc68kcpu); + UINT32 src = m68ki_read_8((mc68kcpu), ea); + UINT32 mask = 1 << (DX(mc68kcpu) & 7); + + (mc68kcpu)->not_z_flag = src & mask; + m68ki_write_8((mc68kcpu), ea, src | mask); +} + + +void m68000_base_device_ops::m68k_op_bset_8_r_pd(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_PD_8(mc68kcpu); + UINT32 src = m68ki_read_8((mc68kcpu), ea); + UINT32 mask = 1 << (DX(mc68kcpu) & 7); + + (mc68kcpu)->not_z_flag = src & mask; + m68ki_write_8((mc68kcpu), ea, src | mask); +} + + +void m68000_base_device_ops::m68k_op_bset_8_r_pd7(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_A7_PD_8(mc68kcpu); + UINT32 src = m68ki_read_8((mc68kcpu), ea); + UINT32 mask = 1 << (DX(mc68kcpu) & 7); + + (mc68kcpu)->not_z_flag = src & mask; + m68ki_write_8((mc68kcpu), ea, src | mask); +} + + +void m68000_base_device_ops::m68k_op_bset_8_r_di(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_DI_8(mc68kcpu); + UINT32 src = m68ki_read_8((mc68kcpu), ea); + UINT32 mask = 1 << (DX(mc68kcpu) & 7); + + (mc68kcpu)->not_z_flag = src & mask; + m68ki_write_8((mc68kcpu), ea, src | mask); +} + + +void m68000_base_device_ops::m68k_op_bset_8_r_ix(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_IX_8(mc68kcpu); + UINT32 src = m68ki_read_8((mc68kcpu), ea); + UINT32 mask = 1 << (DX(mc68kcpu) & 7); + + (mc68kcpu)->not_z_flag = src & mask; + m68ki_write_8((mc68kcpu), ea, src | mask); +} + + +void m68000_base_device_ops::m68k_op_bset_8_r_aw(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AW_8(mc68kcpu); + UINT32 src = m68ki_read_8((mc68kcpu), ea); + UINT32 mask = 1 << (DX(mc68kcpu) & 7); + + (mc68kcpu)->not_z_flag = src & mask; + m68ki_write_8((mc68kcpu), ea, src | mask); +} + + +void m68000_base_device_ops::m68k_op_bset_8_r_al(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AL_8(mc68kcpu); + UINT32 src = m68ki_read_8((mc68kcpu), ea); + UINT32 mask = 1 << (DX(mc68kcpu) & 7); + + (mc68kcpu)->not_z_flag = src & mask; + m68ki_write_8((mc68kcpu), ea, src | mask); +} + + +void m68000_base_device_ops::m68k_op_bset_32_s_d(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 mask = 1 << (OPER_I_8(mc68kcpu) & 0x1f); + + (mc68kcpu)->not_z_flag = *r_dst & mask; + *r_dst |= mask; +} + + +void m68000_base_device_ops::m68k_op_bset_8_s_ai(m68000_base_device* mc68kcpu) +{ + UINT32 mask = 1 << (OPER_I_8(mc68kcpu) & 7); + UINT32 ea = EA_AY_AI_8(mc68kcpu); + UINT32 src = m68ki_read_8((mc68kcpu), ea); + + (mc68kcpu)->not_z_flag = src & mask; + m68ki_write_8((mc68kcpu), ea, src | mask); +} + + +void m68000_base_device_ops::m68k_op_bset_8_s_pi(m68000_base_device* mc68kcpu) +{ + UINT32 mask = 1 << (OPER_I_8(mc68kcpu) & 7); + UINT32 ea = EA_AY_PI_8(mc68kcpu); + UINT32 src = m68ki_read_8((mc68kcpu), ea); + + (mc68kcpu)->not_z_flag = src & mask; + m68ki_write_8((mc68kcpu), ea, src | mask); +} + + +void m68000_base_device_ops::m68k_op_bset_8_s_pi7(m68000_base_device* mc68kcpu) +{ + UINT32 mask = 1 << (OPER_I_8(mc68kcpu) & 7); + UINT32 ea = EA_A7_PI_8(mc68kcpu); + UINT32 src = m68ki_read_8((mc68kcpu), ea); + + (mc68kcpu)->not_z_flag = src & mask; + m68ki_write_8((mc68kcpu), ea, src | mask); +} + + +void m68000_base_device_ops::m68k_op_bset_8_s_pd(m68000_base_device* mc68kcpu) +{ + UINT32 mask = 1 << (OPER_I_8(mc68kcpu) & 7); + UINT32 ea = EA_AY_PD_8(mc68kcpu); + UINT32 src = m68ki_read_8((mc68kcpu), ea); + + (mc68kcpu)->not_z_flag = src & mask; + m68ki_write_8((mc68kcpu), ea, src | mask); +} + + +void m68000_base_device_ops::m68k_op_bset_8_s_pd7(m68000_base_device* mc68kcpu) +{ + UINT32 mask = 1 << (OPER_I_8(mc68kcpu) & 7); + UINT32 ea = EA_A7_PD_8(mc68kcpu); + UINT32 src = m68ki_read_8((mc68kcpu), ea); + + (mc68kcpu)->not_z_flag = src & mask; + m68ki_write_8((mc68kcpu), ea, src | mask); +} + + +void m68000_base_device_ops::m68k_op_bset_8_s_di(m68000_base_device* mc68kcpu) +{ + UINT32 mask = 1 << (OPER_I_8(mc68kcpu) & 7); + UINT32 ea = EA_AY_DI_8(mc68kcpu); + UINT32 src = m68ki_read_8((mc68kcpu), ea); + + (mc68kcpu)->not_z_flag = src & mask; + m68ki_write_8((mc68kcpu), ea, src | mask); +} + + +void m68000_base_device_ops::m68k_op_bset_8_s_ix(m68000_base_device* mc68kcpu) +{ + UINT32 mask = 1 << (OPER_I_8(mc68kcpu) & 7); + UINT32 ea = EA_AY_IX_8(mc68kcpu); + UINT32 src = m68ki_read_8((mc68kcpu), ea); + + (mc68kcpu)->not_z_flag = src & mask; + m68ki_write_8((mc68kcpu), ea, src | mask); +} + + +void m68000_base_device_ops::m68k_op_bset_8_s_aw(m68000_base_device* mc68kcpu) +{ + UINT32 mask = 1 << (OPER_I_8(mc68kcpu) & 7); + UINT32 ea = EA_AW_8(mc68kcpu); + UINT32 src = m68ki_read_8((mc68kcpu), ea); + + (mc68kcpu)->not_z_flag = src & mask; + m68ki_write_8((mc68kcpu), ea, src | mask); +} + + +void m68000_base_device_ops::m68k_op_bset_8_s_al(m68000_base_device* mc68kcpu) +{ + UINT32 mask = 1 << (OPER_I_8(mc68kcpu) & 7); + UINT32 ea = EA_AL_8(mc68kcpu); + UINT32 src = m68ki_read_8((mc68kcpu), ea); + + (mc68kcpu)->not_z_flag = src & mask; + m68ki_write_8((mc68kcpu), ea, src | mask); +} + + +void m68000_base_device_ops::m68k_op_bsr_8(m68000_base_device* mc68kcpu) +{ + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_push_32((mc68kcpu), REG_PC(mc68kcpu)); + m68ki_branch_8((mc68kcpu), MASK_OUT_ABOVE_8((mc68kcpu)->ir)); +} + + +void m68000_base_device_ops::m68k_op_bsr_16(m68000_base_device* mc68kcpu) +{ + UINT32 offset = OPER_I_16(mc68kcpu); + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_push_32((mc68kcpu), REG_PC(mc68kcpu)); + REG_PC(mc68kcpu) -= 2; + m68ki_branch_16((mc68kcpu), offset); +} + + +void m68000_base_device_ops::m68k_op_bsr_32(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 offset = OPER_I_32(mc68kcpu); + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_push_32((mc68kcpu), REG_PC(mc68kcpu)); + REG_PC(mc68kcpu) -= 4; + m68ki_branch_32((mc68kcpu), offset); + return; + } + else + { + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_push_32((mc68kcpu), REG_PC(mc68kcpu)); + m68ki_branch_8((mc68kcpu), MASK_OUT_ABOVE_8((mc68kcpu)->ir)); + } +} + + +void m68000_base_device_ops::m68k_op_btst_32_r_d(m68000_base_device* mc68kcpu) +{ + (mc68kcpu)->not_z_flag = DY(mc68kcpu) & (1 << (DX(mc68kcpu) & 0x1f)); +} + + +void m68000_base_device_ops::m68k_op_btst_8_r_ai(m68000_base_device* mc68kcpu) +{ + (mc68kcpu)->not_z_flag = OPER_AY_AI_8(mc68kcpu) & (1 << (DX(mc68kcpu) & 7)); +} + + +void m68000_base_device_ops::m68k_op_btst_8_r_pi(m68000_base_device* mc68kcpu) +{ + (mc68kcpu)->not_z_flag = OPER_AY_PI_8(mc68kcpu) & (1 << (DX(mc68kcpu) & 7)); +} + + +void m68000_base_device_ops::m68k_op_btst_8_r_pi7(m68000_base_device* mc68kcpu) +{ + (mc68kcpu)->not_z_flag = OPER_A7_PI_8(mc68kcpu) & (1 << (DX(mc68kcpu) & 7)); +} + + +void m68000_base_device_ops::m68k_op_btst_8_r_pd(m68000_base_device* mc68kcpu) +{ + (mc68kcpu)->not_z_flag = OPER_AY_PD_8(mc68kcpu) & (1 << (DX(mc68kcpu) & 7)); +} + + +void m68000_base_device_ops::m68k_op_btst_8_r_pd7(m68000_base_device* mc68kcpu) +{ + (mc68kcpu)->not_z_flag = OPER_A7_PD_8(mc68kcpu) & (1 << (DX(mc68kcpu) & 7)); +} + + +void m68000_base_device_ops::m68k_op_btst_8_r_di(m68000_base_device* mc68kcpu) +{ + (mc68kcpu)->not_z_flag = OPER_AY_DI_8(mc68kcpu) & (1 << (DX(mc68kcpu) & 7)); +} + + +void m68000_base_device_ops::m68k_op_btst_8_r_ix(m68000_base_device* mc68kcpu) +{ + (mc68kcpu)->not_z_flag = OPER_AY_IX_8(mc68kcpu) & (1 << (DX(mc68kcpu) & 7)); +} + + +void m68000_base_device_ops::m68k_op_btst_8_r_aw(m68000_base_device* mc68kcpu) +{ + (mc68kcpu)->not_z_flag = OPER_AW_8(mc68kcpu) & (1 << (DX(mc68kcpu) & 7)); +} + + +void m68000_base_device_ops::m68k_op_btst_8_r_al(m68000_base_device* mc68kcpu) +{ + (mc68kcpu)->not_z_flag = OPER_AL_8(mc68kcpu) & (1 << (DX(mc68kcpu) & 7)); +} + + +void m68000_base_device_ops::m68k_op_btst_8_r_pcdi(m68000_base_device* mc68kcpu) +{ + (mc68kcpu)->not_z_flag = OPER_PCDI_8(mc68kcpu) & (1 << (DX(mc68kcpu) & 7)); +} + + +void m68000_base_device_ops::m68k_op_btst_8_r_pcix(m68000_base_device* mc68kcpu) +{ + (mc68kcpu)->not_z_flag = OPER_PCIX_8(mc68kcpu) & (1 << (DX(mc68kcpu) & 7)); +} + + +void m68000_base_device_ops::m68k_op_btst_8_r_i(m68000_base_device* mc68kcpu) +{ + (mc68kcpu)->not_z_flag = OPER_I_8(mc68kcpu) & (1 << (DX(mc68kcpu) & 7)); +} + + +void m68000_base_device_ops::m68k_op_btst_32_s_d(m68000_base_device* mc68kcpu) +{ + (mc68kcpu)->not_z_flag = DY(mc68kcpu) & (1 << (OPER_I_8(mc68kcpu) & 0x1f)); +} + + +void m68000_base_device_ops::m68k_op_btst_8_s_ai(m68000_base_device* mc68kcpu) +{ + UINT32 bit = OPER_I_8(mc68kcpu) & 7; + + (mc68kcpu)->not_z_flag = OPER_AY_AI_8(mc68kcpu) & (1 << bit); +} + + +void m68000_base_device_ops::m68k_op_btst_8_s_pi(m68000_base_device* mc68kcpu) +{ + UINT32 bit = OPER_I_8(mc68kcpu) & 7; + + (mc68kcpu)->not_z_flag = OPER_AY_PI_8(mc68kcpu) & (1 << bit); +} + + +void m68000_base_device_ops::m68k_op_btst_8_s_pi7(m68000_base_device* mc68kcpu) +{ + UINT32 bit = OPER_I_8(mc68kcpu) & 7; + + (mc68kcpu)->not_z_flag = OPER_A7_PI_8(mc68kcpu) & (1 << bit); +} + + +void m68000_base_device_ops::m68k_op_btst_8_s_pd(m68000_base_device* mc68kcpu) +{ + UINT32 bit = OPER_I_8(mc68kcpu) & 7; + + (mc68kcpu)->not_z_flag = OPER_AY_PD_8(mc68kcpu) & (1 << bit); +} + + +void m68000_base_device_ops::m68k_op_btst_8_s_pd7(m68000_base_device* mc68kcpu) +{ + UINT32 bit = OPER_I_8(mc68kcpu) & 7; + + (mc68kcpu)->not_z_flag = OPER_A7_PD_8(mc68kcpu) & (1 << bit); +} + + +void m68000_base_device_ops::m68k_op_btst_8_s_di(m68000_base_device* mc68kcpu) +{ + UINT32 bit = OPER_I_8(mc68kcpu) & 7; + + (mc68kcpu)->not_z_flag = OPER_AY_DI_8(mc68kcpu) & (1 << bit); +} + + +void m68000_base_device_ops::m68k_op_btst_8_s_ix(m68000_base_device* mc68kcpu) +{ + UINT32 bit = OPER_I_8(mc68kcpu) & 7; + + (mc68kcpu)->not_z_flag = OPER_AY_IX_8(mc68kcpu) & (1 << bit); +} + + +void m68000_base_device_ops::m68k_op_btst_8_s_aw(m68000_base_device* mc68kcpu) +{ + UINT32 bit = OPER_I_8(mc68kcpu) & 7; + + (mc68kcpu)->not_z_flag = OPER_AW_8(mc68kcpu) & (1 << bit); +} + + +void m68000_base_device_ops::m68k_op_btst_8_s_al(m68000_base_device* mc68kcpu) +{ + UINT32 bit = OPER_I_8(mc68kcpu) & 7; + + (mc68kcpu)->not_z_flag = OPER_AL_8(mc68kcpu) & (1 << bit); +} + + +void m68000_base_device_ops::m68k_op_btst_8_s_pcdi(m68000_base_device* mc68kcpu) +{ + UINT32 bit = OPER_I_8(mc68kcpu) & 7; + + (mc68kcpu)->not_z_flag = OPER_PCDI_8(mc68kcpu) & (1 << bit); +} + + +void m68000_base_device_ops::m68k_op_btst_8_s_pcix(m68000_base_device* mc68kcpu) +{ + UINT32 bit = OPER_I_8(mc68kcpu) & 7; + + (mc68kcpu)->not_z_flag = OPER_PCIX_8(mc68kcpu) & (1 << bit); +} + + +void m68000_base_device_ops::m68k_op_callm_32_ai(m68000_base_device* mc68kcpu) +{ + /* note: watch out for pcrelative modes */ + if(CPU_TYPE_IS_020_VARIANT((mc68kcpu)->cpu_type)) + { + UINT32 ea = EA_AY_AI_32(mc68kcpu); + + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + REG_PC(mc68kcpu) += 2; +(void)ea; /* just to avoid an 'unused variable' warning */ + logerror("%s at %08x: called unimplemented instruction %04x (callm)\n", + (mc68kcpu)->tag(), REG_PC(mc68kcpu) - 2, (mc68kcpu)->ir); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_callm_32_di(m68000_base_device* mc68kcpu) +{ + /* note: watch out for pcrelative modes */ + if(CPU_TYPE_IS_020_VARIANT((mc68kcpu)->cpu_type)) + { + UINT32 ea = EA_AY_DI_32(mc68kcpu); + + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + REG_PC(mc68kcpu) += 2; +(void)ea; /* just to avoid an 'unused variable' warning */ + logerror("%s at %08x: called unimplemented instruction %04x (callm)\n", + (mc68kcpu)->tag(), REG_PC(mc68kcpu) - 2, (mc68kcpu)->ir); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_callm_32_ix(m68000_base_device* mc68kcpu) +{ + /* note: watch out for pcrelative modes */ + if(CPU_TYPE_IS_020_VARIANT((mc68kcpu)->cpu_type)) + { + UINT32 ea = EA_AY_IX_32(mc68kcpu); + + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + REG_PC(mc68kcpu) += 2; +(void)ea; /* just to avoid an 'unused variable' warning */ + logerror("%s at %08x: called unimplemented instruction %04x (callm)\n", + (mc68kcpu)->tag(), REG_PC(mc68kcpu) - 2, (mc68kcpu)->ir); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_callm_32_aw(m68000_base_device* mc68kcpu) +{ + /* note: watch out for pcrelative modes */ + if(CPU_TYPE_IS_020_VARIANT((mc68kcpu)->cpu_type)) + { + UINT32 ea = EA_AW_32(mc68kcpu); + + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + REG_PC(mc68kcpu) += 2; +(void)ea; /* just to avoid an 'unused variable' warning */ + logerror("%s at %08x: called unimplemented instruction %04x (callm)\n", + (mc68kcpu)->tag(), REG_PC(mc68kcpu) - 2, (mc68kcpu)->ir); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_callm_32_al(m68000_base_device* mc68kcpu) +{ + /* note: watch out for pcrelative modes */ + if(CPU_TYPE_IS_020_VARIANT((mc68kcpu)->cpu_type)) + { + UINT32 ea = EA_AL_32(mc68kcpu); + + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + REG_PC(mc68kcpu) += 2; +(void)ea; /* just to avoid an 'unused variable' warning */ + logerror("%s at %08x: called unimplemented instruction %04x (callm)\n", + (mc68kcpu)->tag(), REG_PC(mc68kcpu) - 2, (mc68kcpu)->ir); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_callm_32_pcdi(m68000_base_device* mc68kcpu) +{ + /* note: watch out for pcrelative modes */ + if(CPU_TYPE_IS_020_VARIANT((mc68kcpu)->cpu_type)) + { + UINT32 ea = EA_PCDI_32(mc68kcpu); + + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + REG_PC(mc68kcpu) += 2; +(void)ea; /* just to avoid an 'unused variable' warning */ + logerror("%s at %08x: called unimplemented instruction %04x (callm)\n", + (mc68kcpu)->tag(), REG_PC(mc68kcpu) - 2, (mc68kcpu)->ir); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_callm_32_pcix(m68000_base_device* mc68kcpu) +{ + /* note: watch out for pcrelative modes */ + if(CPU_TYPE_IS_020_VARIANT((mc68kcpu)->cpu_type)) + { + UINT32 ea = EA_PCIX_32(mc68kcpu); + + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + REG_PC(mc68kcpu) += 2; +(void)ea; /* just to avoid an 'unused variable' warning */ + logerror("%s at %08x: called unimplemented instruction %04x (callm)\n", + (mc68kcpu)->tag(), REG_PC(mc68kcpu) - 2, (mc68kcpu)->ir); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_cas_8_ai(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT32 ea = EA_AY_AI_8(mc68kcpu); + UINT32 dest = m68ki_read_8((mc68kcpu), ea); + UINT32* compare = ®_D(mc68kcpu)[word2 & 7]; + UINT32 res = dest - MASK_OUT_ABOVE_8(*compare); + + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(*compare, dest, res); + (mc68kcpu)->c_flag = CFLAG_8(res); + + if(COND_NE(mc68kcpu)) + *compare = MASK_OUT_BELOW_8(*compare) | dest; + else + { + (mc68kcpu)->remaining_cycles -= 3; + m68ki_write_8((mc68kcpu), ea, MASK_OUT_ABOVE_8(REG_D(mc68kcpu)[(word2 >> 6) & 7])); + } + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_cas_8_pi(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT32 ea = EA_AY_PI_8(mc68kcpu); + UINT32 dest = m68ki_read_8((mc68kcpu), ea); + UINT32* compare = ®_D(mc68kcpu)[word2 & 7]; + UINT32 res = dest - MASK_OUT_ABOVE_8(*compare); + + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(*compare, dest, res); + (mc68kcpu)->c_flag = CFLAG_8(res); + + if(COND_NE(mc68kcpu)) + *compare = MASK_OUT_BELOW_8(*compare) | dest; + else + { + (mc68kcpu)->remaining_cycles -= 3; + m68ki_write_8((mc68kcpu), ea, MASK_OUT_ABOVE_8(REG_D(mc68kcpu)[(word2 >> 6) & 7])); + } + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_cas_8_pi7(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT32 ea = EA_A7_PI_8(mc68kcpu); + UINT32 dest = m68ki_read_8((mc68kcpu), ea); + UINT32* compare = ®_D(mc68kcpu)[word2 & 7]; + UINT32 res = dest - MASK_OUT_ABOVE_8(*compare); + + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(*compare, dest, res); + (mc68kcpu)->c_flag = CFLAG_8(res); + + if(COND_NE(mc68kcpu)) + *compare = MASK_OUT_BELOW_8(*compare) | dest; + else + { + (mc68kcpu)->remaining_cycles -= 3; + m68ki_write_8((mc68kcpu), ea, MASK_OUT_ABOVE_8(REG_D(mc68kcpu)[(word2 >> 6) & 7])); + } + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_cas_8_pd(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT32 ea = EA_AY_PD_8(mc68kcpu); + UINT32 dest = m68ki_read_8((mc68kcpu), ea); + UINT32* compare = ®_D(mc68kcpu)[word2 & 7]; + UINT32 res = dest - MASK_OUT_ABOVE_8(*compare); + + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(*compare, dest, res); + (mc68kcpu)->c_flag = CFLAG_8(res); + + if(COND_NE(mc68kcpu)) + *compare = MASK_OUT_BELOW_8(*compare) | dest; + else + { + (mc68kcpu)->remaining_cycles -= 3; + m68ki_write_8((mc68kcpu), ea, MASK_OUT_ABOVE_8(REG_D(mc68kcpu)[(word2 >> 6) & 7])); + } + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_cas_8_pd7(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT32 ea = EA_A7_PD_8(mc68kcpu); + UINT32 dest = m68ki_read_8((mc68kcpu), ea); + UINT32* compare = ®_D(mc68kcpu)[word2 & 7]; + UINT32 res = dest - MASK_OUT_ABOVE_8(*compare); + + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(*compare, dest, res); + (mc68kcpu)->c_flag = CFLAG_8(res); + + if(COND_NE(mc68kcpu)) + *compare = MASK_OUT_BELOW_8(*compare) | dest; + else + { + (mc68kcpu)->remaining_cycles -= 3; + m68ki_write_8((mc68kcpu), ea, MASK_OUT_ABOVE_8(REG_D(mc68kcpu)[(word2 >> 6) & 7])); + } + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_cas_8_di(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT32 ea = EA_AY_DI_8(mc68kcpu); + UINT32 dest = m68ki_read_8((mc68kcpu), ea); + UINT32* compare = ®_D(mc68kcpu)[word2 & 7]; + UINT32 res = dest - MASK_OUT_ABOVE_8(*compare); + + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(*compare, dest, res); + (mc68kcpu)->c_flag = CFLAG_8(res); + + if(COND_NE(mc68kcpu)) + *compare = MASK_OUT_BELOW_8(*compare) | dest; + else + { + (mc68kcpu)->remaining_cycles -= 3; + m68ki_write_8((mc68kcpu), ea, MASK_OUT_ABOVE_8(REG_D(mc68kcpu)[(word2 >> 6) & 7])); + } + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_cas_8_ix(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT32 ea = EA_AY_IX_8(mc68kcpu); + UINT32 dest = m68ki_read_8((mc68kcpu), ea); + UINT32* compare = ®_D(mc68kcpu)[word2 & 7]; + UINT32 res = dest - MASK_OUT_ABOVE_8(*compare); + + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(*compare, dest, res); + (mc68kcpu)->c_flag = CFLAG_8(res); + + if(COND_NE(mc68kcpu)) + *compare = MASK_OUT_BELOW_8(*compare) | dest; + else + { + (mc68kcpu)->remaining_cycles -= 3; + m68ki_write_8((mc68kcpu), ea, MASK_OUT_ABOVE_8(REG_D(mc68kcpu)[(word2 >> 6) & 7])); + } + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_cas_8_aw(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT32 ea = EA_AW_8(mc68kcpu); + UINT32 dest = m68ki_read_8((mc68kcpu), ea); + UINT32* compare = ®_D(mc68kcpu)[word2 & 7]; + UINT32 res = dest - MASK_OUT_ABOVE_8(*compare); + + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(*compare, dest, res); + (mc68kcpu)->c_flag = CFLAG_8(res); + + if(COND_NE(mc68kcpu)) + *compare = MASK_OUT_BELOW_8(*compare) | dest; + else + { + (mc68kcpu)->remaining_cycles -= 3; + m68ki_write_8((mc68kcpu), ea, MASK_OUT_ABOVE_8(REG_D(mc68kcpu)[(word2 >> 6) & 7])); + } + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_cas_8_al(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT32 ea = EA_AL_8(mc68kcpu); + UINT32 dest = m68ki_read_8((mc68kcpu), ea); + UINT32* compare = ®_D(mc68kcpu)[word2 & 7]; + UINT32 res = dest - MASK_OUT_ABOVE_8(*compare); + + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(*compare, dest, res); + (mc68kcpu)->c_flag = CFLAG_8(res); + + if(COND_NE(mc68kcpu)) + *compare = MASK_OUT_BELOW_8(*compare) | dest; + else + { + (mc68kcpu)->remaining_cycles -= 3; + m68ki_write_8((mc68kcpu), ea, MASK_OUT_ABOVE_8(REG_D(mc68kcpu)[(word2 >> 6) & 7])); + } + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_cas_16_ai(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT32 ea = EA_AY_AI_16(mc68kcpu); + UINT32 dest = m68ki_read_16((mc68kcpu), ea); + UINT32* compare = ®_D(mc68kcpu)[word2 & 7]; + UINT32 res = dest - MASK_OUT_ABOVE_16(*compare); + + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + (mc68kcpu)->v_flag = VFLAG_SUB_16(*compare, dest, res); + (mc68kcpu)->c_flag = CFLAG_16(res); + + if(COND_NE(mc68kcpu)) + *compare = MASK_OUT_BELOW_16(*compare) | dest; + else + { + (mc68kcpu)->remaining_cycles -= 3; + m68ki_write_16((mc68kcpu), ea, MASK_OUT_ABOVE_16(REG_D(mc68kcpu)[(word2 >> 6) & 7])); + } + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_cas_16_pi(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT32 ea = EA_AY_PI_16(mc68kcpu); + UINT32 dest = m68ki_read_16((mc68kcpu), ea); + UINT32* compare = ®_D(mc68kcpu)[word2 & 7]; + UINT32 res = dest - MASK_OUT_ABOVE_16(*compare); + + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + (mc68kcpu)->v_flag = VFLAG_SUB_16(*compare, dest, res); + (mc68kcpu)->c_flag = CFLAG_16(res); + + if(COND_NE(mc68kcpu)) + *compare = MASK_OUT_BELOW_16(*compare) | dest; + else + { + (mc68kcpu)->remaining_cycles -= 3; + m68ki_write_16((mc68kcpu), ea, MASK_OUT_ABOVE_16(REG_D(mc68kcpu)[(word2 >> 6) & 7])); + } + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_cas_16_pd(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT32 ea = EA_AY_PD_16(mc68kcpu); + UINT32 dest = m68ki_read_16((mc68kcpu), ea); + UINT32* compare = ®_D(mc68kcpu)[word2 & 7]; + UINT32 res = dest - MASK_OUT_ABOVE_16(*compare); + + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + (mc68kcpu)->v_flag = VFLAG_SUB_16(*compare, dest, res); + (mc68kcpu)->c_flag = CFLAG_16(res); + + if(COND_NE(mc68kcpu)) + *compare = MASK_OUT_BELOW_16(*compare) | dest; + else + { + (mc68kcpu)->remaining_cycles -= 3; + m68ki_write_16((mc68kcpu), ea, MASK_OUT_ABOVE_16(REG_D(mc68kcpu)[(word2 >> 6) & 7])); + } + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_cas_16_di(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT32 ea = EA_AY_DI_16(mc68kcpu); + UINT32 dest = m68ki_read_16((mc68kcpu), ea); + UINT32* compare = ®_D(mc68kcpu)[word2 & 7]; + UINT32 res = dest - MASK_OUT_ABOVE_16(*compare); + + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + (mc68kcpu)->v_flag = VFLAG_SUB_16(*compare, dest, res); + (mc68kcpu)->c_flag = CFLAG_16(res); + + if(COND_NE(mc68kcpu)) + *compare = MASK_OUT_BELOW_16(*compare) | dest; + else + { + (mc68kcpu)->remaining_cycles -= 3; + m68ki_write_16((mc68kcpu), ea, MASK_OUT_ABOVE_16(REG_D(mc68kcpu)[(word2 >> 6) & 7])); + } + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_cas_16_ix(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT32 ea = EA_AY_IX_16(mc68kcpu); + UINT32 dest = m68ki_read_16((mc68kcpu), ea); + UINT32* compare = ®_D(mc68kcpu)[word2 & 7]; + UINT32 res = dest - MASK_OUT_ABOVE_16(*compare); + + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + (mc68kcpu)->v_flag = VFLAG_SUB_16(*compare, dest, res); + (mc68kcpu)->c_flag = CFLAG_16(res); + + if(COND_NE(mc68kcpu)) + *compare = MASK_OUT_BELOW_16(*compare) | dest; + else + { + (mc68kcpu)->remaining_cycles -= 3; + m68ki_write_16((mc68kcpu), ea, MASK_OUT_ABOVE_16(REG_D(mc68kcpu)[(word2 >> 6) & 7])); + } + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_cas_16_aw(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT32 ea = EA_AW_16(mc68kcpu); + UINT32 dest = m68ki_read_16((mc68kcpu), ea); + UINT32* compare = ®_D(mc68kcpu)[word2 & 7]; + UINT32 res = dest - MASK_OUT_ABOVE_16(*compare); + + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + (mc68kcpu)->v_flag = VFLAG_SUB_16(*compare, dest, res); + (mc68kcpu)->c_flag = CFLAG_16(res); + + if(COND_NE(mc68kcpu)) + *compare = MASK_OUT_BELOW_16(*compare) | dest; + else + { + (mc68kcpu)->remaining_cycles -= 3; + m68ki_write_16((mc68kcpu), ea, MASK_OUT_ABOVE_16(REG_D(mc68kcpu)[(word2 >> 6) & 7])); + } + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_cas_16_al(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT32 ea = EA_AL_16(mc68kcpu); + UINT32 dest = m68ki_read_16((mc68kcpu), ea); + UINT32* compare = ®_D(mc68kcpu)[word2 & 7]; + UINT32 res = dest - MASK_OUT_ABOVE_16(*compare); + + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + (mc68kcpu)->v_flag = VFLAG_SUB_16(*compare, dest, res); + (mc68kcpu)->c_flag = CFLAG_16(res); + + if(COND_NE(mc68kcpu)) + *compare = MASK_OUT_BELOW_16(*compare) | dest; + else + { + (mc68kcpu)->remaining_cycles -= 3; + m68ki_write_16((mc68kcpu), ea, MASK_OUT_ABOVE_16(REG_D(mc68kcpu)[(word2 >> 6) & 7])); + } + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_cas_32_ai(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT32 ea = EA_AY_AI_32(mc68kcpu); + UINT32 dest = m68ki_read_32((mc68kcpu), ea); + UINT32* compare = ®_D(mc68kcpu)[word2 & 7]; + UINT32 res = dest - *compare; + + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(*compare, dest, res); + (mc68kcpu)->c_flag = CFLAG_SUB_32(*compare, dest, res); + + if(COND_NE(mc68kcpu)) + *compare = dest; + else + { + (mc68kcpu)->remaining_cycles -= 3; + m68ki_write_32((mc68kcpu), ea, REG_D(mc68kcpu)[(word2 >> 6) & 7]); + } + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_cas_32_pi(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT32 ea = EA_AY_PI_32(mc68kcpu); + UINT32 dest = m68ki_read_32((mc68kcpu), ea); + UINT32* compare = ®_D(mc68kcpu)[word2 & 7]; + UINT32 res = dest - *compare; + + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(*compare, dest, res); + (mc68kcpu)->c_flag = CFLAG_SUB_32(*compare, dest, res); + + if(COND_NE(mc68kcpu)) + *compare = dest; + else + { + (mc68kcpu)->remaining_cycles -= 3; + m68ki_write_32((mc68kcpu), ea, REG_D(mc68kcpu)[(word2 >> 6) & 7]); + } + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_cas_32_pd(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT32 ea = EA_AY_PD_32(mc68kcpu); + UINT32 dest = m68ki_read_32((mc68kcpu), ea); + UINT32* compare = ®_D(mc68kcpu)[word2 & 7]; + UINT32 res = dest - *compare; + + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(*compare, dest, res); + (mc68kcpu)->c_flag = CFLAG_SUB_32(*compare, dest, res); + + if(COND_NE(mc68kcpu)) + *compare = dest; + else + { + (mc68kcpu)->remaining_cycles -= 3; + m68ki_write_32((mc68kcpu), ea, REG_D(mc68kcpu)[(word2 >> 6) & 7]); + } + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_cas_32_di(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT32 ea = EA_AY_DI_32(mc68kcpu); + UINT32 dest = m68ki_read_32((mc68kcpu), ea); + UINT32* compare = ®_D(mc68kcpu)[word2 & 7]; + UINT32 res = dest - *compare; + + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(*compare, dest, res); + (mc68kcpu)->c_flag = CFLAG_SUB_32(*compare, dest, res); + + if(COND_NE(mc68kcpu)) + *compare = dest; + else + { + (mc68kcpu)->remaining_cycles -= 3; + m68ki_write_32((mc68kcpu), ea, REG_D(mc68kcpu)[(word2 >> 6) & 7]); + } + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_cas_32_ix(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT32 ea = EA_AY_IX_32(mc68kcpu); + UINT32 dest = m68ki_read_32((mc68kcpu), ea); + UINT32* compare = ®_D(mc68kcpu)[word2 & 7]; + UINT32 res = dest - *compare; + + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(*compare, dest, res); + (mc68kcpu)->c_flag = CFLAG_SUB_32(*compare, dest, res); + + if(COND_NE(mc68kcpu)) + *compare = dest; + else + { + (mc68kcpu)->remaining_cycles -= 3; + m68ki_write_32((mc68kcpu), ea, REG_D(mc68kcpu)[(word2 >> 6) & 7]); + } + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_cas_32_aw(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT32 ea = EA_AW_32(mc68kcpu); + UINT32 dest = m68ki_read_32((mc68kcpu), ea); + UINT32* compare = ®_D(mc68kcpu)[word2 & 7]; + UINT32 res = dest - *compare; + + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(*compare, dest, res); + (mc68kcpu)->c_flag = CFLAG_SUB_32(*compare, dest, res); + + if(COND_NE(mc68kcpu)) + *compare = dest; + else + { + (mc68kcpu)->remaining_cycles -= 3; + m68ki_write_32((mc68kcpu), ea, REG_D(mc68kcpu)[(word2 >> 6) & 7]); + } + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_cas_32_al(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT32 ea = EA_AL_32(mc68kcpu); + UINT32 dest = m68ki_read_32((mc68kcpu), ea); + UINT32* compare = ®_D(mc68kcpu)[word2 & 7]; + UINT32 res = dest - *compare; + + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(*compare, dest, res); + (mc68kcpu)->c_flag = CFLAG_SUB_32(*compare, dest, res); + + if(COND_NE(mc68kcpu)) + *compare = dest; + else + { + (mc68kcpu)->remaining_cycles -= 3; + m68ki_write_32((mc68kcpu), ea, REG_D(mc68kcpu)[(word2 >> 6) & 7]); + } + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_cas2_16(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_32(mc68kcpu); + UINT32* compare1 = ®_D(mc68kcpu)[(word2 >> 16) & 7]; + UINT32 ea1 = REG_DA(mc68kcpu)[(word2 >> 28) & 15]; + UINT32 dest1 = m68ki_read_16((mc68kcpu), ea1); + UINT32 res1 = dest1 - MASK_OUT_ABOVE_16(*compare1); + UINT32* compare2 = ®_D(mc68kcpu)[word2 & 7]; + UINT32 ea2 = REG_DA(mc68kcpu)[(word2 >> 12) & 15]; + UINT32 dest2 = m68ki_read_16((mc68kcpu), ea2); + UINT32 res2; + + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + (mc68kcpu)->n_flag = NFLAG_16(res1); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res1); + (mc68kcpu)->v_flag = VFLAG_SUB_16(*compare1, dest1, res1); + (mc68kcpu)->c_flag = CFLAG_16(res1); + + if(COND_EQ(mc68kcpu)) + { + res2 = dest2 - MASK_OUT_ABOVE_16(*compare2); + + (mc68kcpu)->n_flag = NFLAG_16(res2); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res2); + (mc68kcpu)->v_flag = VFLAG_SUB_16(*compare2, dest2, res2); + (mc68kcpu)->c_flag = CFLAG_16(res2); + + if(COND_EQ(mc68kcpu)) + { + (mc68kcpu)->remaining_cycles -= 3; + m68ki_write_16((mc68kcpu), ea1, REG_D(mc68kcpu)[(word2 >> 22) & 7]); + m68ki_write_16((mc68kcpu), ea2, REG_D(mc68kcpu)[(word2 >> 6) & 7]); + return; + } + } + *compare1 = BIT_1F(word2) ? MAKE_INT_16(dest1) : MASK_OUT_BELOW_16(*compare1) | dest1; + *compare2 = BIT_F(word2) ? MAKE_INT_16(dest2) : MASK_OUT_BELOW_16(*compare2) | dest2; + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_cas2_32(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_32(mc68kcpu); + UINT32* compare1 = ®_D(mc68kcpu)[(word2 >> 16) & 7]; + UINT32 ea1 = REG_DA(mc68kcpu)[(word2 >> 28) & 15]; + UINT32 dest1 = m68ki_read_32((mc68kcpu), ea1); + UINT32 res1 = dest1 - *compare1; + UINT32* compare2 = ®_D(mc68kcpu)[word2 & 7]; + UINT32 ea2 = REG_DA(mc68kcpu)[(word2 >> 12) & 15]; + UINT32 dest2 = m68ki_read_32((mc68kcpu), ea2); + UINT32 res2; + + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + (mc68kcpu)->n_flag = NFLAG_32(res1); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res1); + (mc68kcpu)->v_flag = VFLAG_SUB_32(*compare1, dest1, res1); + (mc68kcpu)->c_flag = CFLAG_SUB_32(*compare1, dest1, res1); + + if(COND_EQ(mc68kcpu)) + { + res2 = dest2 - *compare2; + + (mc68kcpu)->n_flag = NFLAG_32(res2); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res2); + (mc68kcpu)->v_flag = VFLAG_SUB_32(*compare2, dest2, res2); + (mc68kcpu)->c_flag = CFLAG_SUB_32(*compare2, dest2, res2); + + if(COND_EQ(mc68kcpu)) + { + (mc68kcpu)->remaining_cycles -= 3; + m68ki_write_32((mc68kcpu), ea1, REG_D(mc68kcpu)[(word2 >> 22) & 7]); + m68ki_write_32((mc68kcpu), ea2, REG_D(mc68kcpu)[(word2 >> 6) & 7]); + return; + } + } + *compare1 = dest1; + *compare2 = dest2; + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_chk_16_d(m68000_base_device* mc68kcpu) +{ + INT32 src = MAKE_INT_16(DX(mc68kcpu)); + INT32 bound = MAKE_INT_16(DY(mc68kcpu)); + + (mc68kcpu)->not_z_flag = ZFLAG_16(src); /* Undocumented */ + (mc68kcpu)->v_flag = VFLAG_CLEAR; /* Undocumented */ + (mc68kcpu)->c_flag = CFLAG_CLEAR; /* Undocumented */ + + if(src >= 0 && src <= bound) + { + return; + } + (mc68kcpu)->n_flag = (src < 0)<<7; + m68ki_exception_trap((mc68kcpu), EXCEPTION_CHK); +} + + +void m68000_base_device_ops::m68k_op_chk_16_ai(m68000_base_device* mc68kcpu) +{ + INT32 src = MAKE_INT_16(DX(mc68kcpu)); + INT32 bound = MAKE_INT_16(OPER_AY_AI_16(mc68kcpu)); + + (mc68kcpu)->not_z_flag = ZFLAG_16(src); /* Undocumented */ + (mc68kcpu)->v_flag = VFLAG_CLEAR; /* Undocumented */ + (mc68kcpu)->c_flag = CFLAG_CLEAR; /* Undocumented */ + + if(src >= 0 && src <= bound) + { + return; + } + (mc68kcpu)->n_flag = (src < 0)<<7; + m68ki_exception_trap((mc68kcpu), EXCEPTION_CHK); +} + + +void m68000_base_device_ops::m68k_op_chk_16_pi(m68000_base_device* mc68kcpu) +{ + INT32 src = MAKE_INT_16(DX(mc68kcpu)); + INT32 bound = MAKE_INT_16(OPER_AY_PI_16(mc68kcpu)); + + (mc68kcpu)->not_z_flag = ZFLAG_16(src); /* Undocumented */ + (mc68kcpu)->v_flag = VFLAG_CLEAR; /* Undocumented */ + (mc68kcpu)->c_flag = CFLAG_CLEAR; /* Undocumented */ + + if(src >= 0 && src <= bound) + { + return; + } + (mc68kcpu)->n_flag = (src < 0)<<7; + m68ki_exception_trap((mc68kcpu), EXCEPTION_CHK); +} + + +void m68000_base_device_ops::m68k_op_chk_16_pd(m68000_base_device* mc68kcpu) +{ + INT32 src = MAKE_INT_16(DX(mc68kcpu)); + INT32 bound = MAKE_INT_16(OPER_AY_PD_16(mc68kcpu)); + + (mc68kcpu)->not_z_flag = ZFLAG_16(src); /* Undocumented */ + (mc68kcpu)->v_flag = VFLAG_CLEAR; /* Undocumented */ + (mc68kcpu)->c_flag = CFLAG_CLEAR; /* Undocumented */ + + if(src >= 0 && src <= bound) + { + return; + } + (mc68kcpu)->n_flag = (src < 0)<<7; + m68ki_exception_trap((mc68kcpu), EXCEPTION_CHK); +} + + +void m68000_base_device_ops::m68k_op_chk_16_di(m68000_base_device* mc68kcpu) +{ + INT32 src = MAKE_INT_16(DX(mc68kcpu)); + INT32 bound = MAKE_INT_16(OPER_AY_DI_16(mc68kcpu)); + + (mc68kcpu)->not_z_flag = ZFLAG_16(src); /* Undocumented */ + (mc68kcpu)->v_flag = VFLAG_CLEAR; /* Undocumented */ + (mc68kcpu)->c_flag = CFLAG_CLEAR; /* Undocumented */ + + if(src >= 0 && src <= bound) + { + return; + } + (mc68kcpu)->n_flag = (src < 0)<<7; + m68ki_exception_trap((mc68kcpu), EXCEPTION_CHK); +} + + +void m68000_base_device_ops::m68k_op_chk_16_ix(m68000_base_device* mc68kcpu) +{ + INT32 src = MAKE_INT_16(DX(mc68kcpu)); + INT32 bound = MAKE_INT_16(OPER_AY_IX_16(mc68kcpu)); + + (mc68kcpu)->not_z_flag = ZFLAG_16(src); /* Undocumented */ + (mc68kcpu)->v_flag = VFLAG_CLEAR; /* Undocumented */ + (mc68kcpu)->c_flag = CFLAG_CLEAR; /* Undocumented */ + + if(src >= 0 && src <= bound) + { + return; + } + (mc68kcpu)->n_flag = (src < 0)<<7; + m68ki_exception_trap((mc68kcpu), EXCEPTION_CHK); +} + + +void m68000_base_device_ops::m68k_op_chk_16_aw(m68000_base_device* mc68kcpu) +{ + INT32 src = MAKE_INT_16(DX(mc68kcpu)); + INT32 bound = MAKE_INT_16(OPER_AW_16(mc68kcpu)); + + (mc68kcpu)->not_z_flag = ZFLAG_16(src); /* Undocumented */ + (mc68kcpu)->v_flag = VFLAG_CLEAR; /* Undocumented */ + (mc68kcpu)->c_flag = CFLAG_CLEAR; /* Undocumented */ + + if(src >= 0 && src <= bound) + { + return; + } + (mc68kcpu)->n_flag = (src < 0)<<7; + m68ki_exception_trap((mc68kcpu), EXCEPTION_CHK); +} + + +void m68000_base_device_ops::m68k_op_chk_16_al(m68000_base_device* mc68kcpu) +{ + INT32 src = MAKE_INT_16(DX(mc68kcpu)); + INT32 bound = MAKE_INT_16(OPER_AL_16(mc68kcpu)); + + (mc68kcpu)->not_z_flag = ZFLAG_16(src); /* Undocumented */ + (mc68kcpu)->v_flag = VFLAG_CLEAR; /* Undocumented */ + (mc68kcpu)->c_flag = CFLAG_CLEAR; /* Undocumented */ + + if(src >= 0 && src <= bound) + { + return; + } + (mc68kcpu)->n_flag = (src < 0)<<7; + m68ki_exception_trap((mc68kcpu), EXCEPTION_CHK); +} + + +void m68000_base_device_ops::m68k_op_chk_16_pcdi(m68000_base_device* mc68kcpu) +{ + INT32 src = MAKE_INT_16(DX(mc68kcpu)); + INT32 bound = MAKE_INT_16(OPER_PCDI_16(mc68kcpu)); + + (mc68kcpu)->not_z_flag = ZFLAG_16(src); /* Undocumented */ + (mc68kcpu)->v_flag = VFLAG_CLEAR; /* Undocumented */ + (mc68kcpu)->c_flag = CFLAG_CLEAR; /* Undocumented */ + + if(src >= 0 && src <= bound) + { + return; + } + (mc68kcpu)->n_flag = (src < 0)<<7; + m68ki_exception_trap((mc68kcpu), EXCEPTION_CHK); +} + + +void m68000_base_device_ops::m68k_op_chk_16_pcix(m68000_base_device* mc68kcpu) +{ + INT32 src = MAKE_INT_16(DX(mc68kcpu)); + INT32 bound = MAKE_INT_16(OPER_PCIX_16(mc68kcpu)); + + (mc68kcpu)->not_z_flag = ZFLAG_16(src); /* Undocumented */ + (mc68kcpu)->v_flag = VFLAG_CLEAR; /* Undocumented */ + (mc68kcpu)->c_flag = CFLAG_CLEAR; /* Undocumented */ + + if(src >= 0 && src <= bound) + { + return; + } + (mc68kcpu)->n_flag = (src < 0)<<7; + m68ki_exception_trap((mc68kcpu), EXCEPTION_CHK); +} + + +void m68000_base_device_ops::m68k_op_chk_16_i(m68000_base_device* mc68kcpu) +{ + INT32 src = MAKE_INT_16(DX(mc68kcpu)); + INT32 bound = MAKE_INT_16(OPER_I_16(mc68kcpu)); + + (mc68kcpu)->not_z_flag = ZFLAG_16(src); /* Undocumented */ + (mc68kcpu)->v_flag = VFLAG_CLEAR; /* Undocumented */ + (mc68kcpu)->c_flag = CFLAG_CLEAR; /* Undocumented */ + + if(src >= 0 && src <= bound) + { + return; + } + (mc68kcpu)->n_flag = (src < 0)<<7; + m68ki_exception_trap((mc68kcpu), EXCEPTION_CHK); +} + + +void m68000_base_device_ops::m68k_op_chk_32_d(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + INT32 src = MAKE_INT_32(DX(mc68kcpu)); + INT32 bound = MAKE_INT_32(DY(mc68kcpu)); + + (mc68kcpu)->not_z_flag = ZFLAG_32(src); /* Undocumented */ + (mc68kcpu)->v_flag = VFLAG_CLEAR; /* Undocumented */ + (mc68kcpu)->c_flag = CFLAG_CLEAR; /* Undocumented */ + + if(src >= 0 && src <= bound) + { + return; + } + (mc68kcpu)->n_flag = (src < 0)<<7; + m68ki_exception_trap((mc68kcpu), EXCEPTION_CHK); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_chk_32_ai(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + INT32 src = MAKE_INT_32(DX(mc68kcpu)); + INT32 bound = MAKE_INT_32(OPER_AY_AI_32(mc68kcpu)); + + (mc68kcpu)->not_z_flag = ZFLAG_32(src); /* Undocumented */ + (mc68kcpu)->v_flag = VFLAG_CLEAR; /* Undocumented */ + (mc68kcpu)->c_flag = CFLAG_CLEAR; /* Undocumented */ + + if(src >= 0 && src <= bound) + { + return; + } + (mc68kcpu)->n_flag = (src < 0)<<7; + m68ki_exception_trap((mc68kcpu), EXCEPTION_CHK); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_chk_32_pi(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + INT32 src = MAKE_INT_32(DX(mc68kcpu)); + INT32 bound = MAKE_INT_32(OPER_AY_PI_32(mc68kcpu)); + + (mc68kcpu)->not_z_flag = ZFLAG_32(src); /* Undocumented */ + (mc68kcpu)->v_flag = VFLAG_CLEAR; /* Undocumented */ + (mc68kcpu)->c_flag = CFLAG_CLEAR; /* Undocumented */ + + if(src >= 0 && src <= bound) + { + return; + } + (mc68kcpu)->n_flag = (src < 0)<<7; + m68ki_exception_trap((mc68kcpu), EXCEPTION_CHK); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_chk_32_pd(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + INT32 src = MAKE_INT_32(DX(mc68kcpu)); + INT32 bound = MAKE_INT_32(OPER_AY_PD_32(mc68kcpu)); + + (mc68kcpu)->not_z_flag = ZFLAG_32(src); /* Undocumented */ + (mc68kcpu)->v_flag = VFLAG_CLEAR; /* Undocumented */ + (mc68kcpu)->c_flag = CFLAG_CLEAR; /* Undocumented */ + + if(src >= 0 && src <= bound) + { + return; + } + (mc68kcpu)->n_flag = (src < 0)<<7; + m68ki_exception_trap((mc68kcpu), EXCEPTION_CHK); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_chk_32_di(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + INT32 src = MAKE_INT_32(DX(mc68kcpu)); + INT32 bound = MAKE_INT_32(OPER_AY_DI_32(mc68kcpu)); + + (mc68kcpu)->not_z_flag = ZFLAG_32(src); /* Undocumented */ + (mc68kcpu)->v_flag = VFLAG_CLEAR; /* Undocumented */ + (mc68kcpu)->c_flag = CFLAG_CLEAR; /* Undocumented */ + + if(src >= 0 && src <= bound) + { + return; + } + (mc68kcpu)->n_flag = (src < 0)<<7; + m68ki_exception_trap((mc68kcpu), EXCEPTION_CHK); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_chk_32_ix(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + INT32 src = MAKE_INT_32(DX(mc68kcpu)); + INT32 bound = MAKE_INT_32(OPER_AY_IX_32(mc68kcpu)); + + (mc68kcpu)->not_z_flag = ZFLAG_32(src); /* Undocumented */ + (mc68kcpu)->v_flag = VFLAG_CLEAR; /* Undocumented */ + (mc68kcpu)->c_flag = CFLAG_CLEAR; /* Undocumented */ + + if(src >= 0 && src <= bound) + { + return; + } + (mc68kcpu)->n_flag = (src < 0)<<7; + m68ki_exception_trap((mc68kcpu), EXCEPTION_CHK); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_chk_32_aw(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + INT32 src = MAKE_INT_32(DX(mc68kcpu)); + INT32 bound = MAKE_INT_32(OPER_AW_32(mc68kcpu)); + + (mc68kcpu)->not_z_flag = ZFLAG_32(src); /* Undocumented */ + (mc68kcpu)->v_flag = VFLAG_CLEAR; /* Undocumented */ + (mc68kcpu)->c_flag = CFLAG_CLEAR; /* Undocumented */ + + if(src >= 0 && src <= bound) + { + return; + } + (mc68kcpu)->n_flag = (src < 0)<<7; + m68ki_exception_trap((mc68kcpu), EXCEPTION_CHK); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_chk_32_al(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + INT32 src = MAKE_INT_32(DX(mc68kcpu)); + INT32 bound = MAKE_INT_32(OPER_AL_32(mc68kcpu)); + + (mc68kcpu)->not_z_flag = ZFLAG_32(src); /* Undocumented */ + (mc68kcpu)->v_flag = VFLAG_CLEAR; /* Undocumented */ + (mc68kcpu)->c_flag = CFLAG_CLEAR; /* Undocumented */ + + if(src >= 0 && src <= bound) + { + return; + } + (mc68kcpu)->n_flag = (src < 0)<<7; + m68ki_exception_trap((mc68kcpu), EXCEPTION_CHK); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_chk_32_pcdi(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + INT32 src = MAKE_INT_32(DX(mc68kcpu)); + INT32 bound = MAKE_INT_32(OPER_PCDI_32(mc68kcpu)); + + (mc68kcpu)->not_z_flag = ZFLAG_32(src); /* Undocumented */ + (mc68kcpu)->v_flag = VFLAG_CLEAR; /* Undocumented */ + (mc68kcpu)->c_flag = CFLAG_CLEAR; /* Undocumented */ + + if(src >= 0 && src <= bound) + { + return; + } + (mc68kcpu)->n_flag = (src < 0)<<7; + m68ki_exception_trap((mc68kcpu), EXCEPTION_CHK); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_chk_32_pcix(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + INT32 src = MAKE_INT_32(DX(mc68kcpu)); + INT32 bound = MAKE_INT_32(OPER_PCIX_32(mc68kcpu)); + + (mc68kcpu)->not_z_flag = ZFLAG_32(src); /* Undocumented */ + (mc68kcpu)->v_flag = VFLAG_CLEAR; /* Undocumented */ + (mc68kcpu)->c_flag = CFLAG_CLEAR; /* Undocumented */ + + if(src >= 0 && src <= bound) + { + return; + } + (mc68kcpu)->n_flag = (src < 0)<<7; + m68ki_exception_trap((mc68kcpu), EXCEPTION_CHK); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_chk_32_i(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + INT32 src = MAKE_INT_32(DX(mc68kcpu)); + INT32 bound = MAKE_INT_32(OPER_I_32(mc68kcpu)); + + (mc68kcpu)->not_z_flag = ZFLAG_32(src); /* Undocumented */ + (mc68kcpu)->v_flag = VFLAG_CLEAR; /* Undocumented */ + (mc68kcpu)->c_flag = CFLAG_CLEAR; /* Undocumented */ + + if(src >= 0 && src <= bound) + { + return; + } + (mc68kcpu)->n_flag = (src < 0)<<7; + m68ki_exception_trap((mc68kcpu), EXCEPTION_CHK); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_chk2cmp2_8_pcdi(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT32 compare = REG_DA(mc68kcpu)[(word2 >> 12) & 15]&0xff; + UINT32 ea = EA_PCDI_8(mc68kcpu); + UINT32 lower_bound = m68ki_read_pcrel_8((mc68kcpu), ea); + UINT32 upper_bound = m68ki_read_pcrel_8((mc68kcpu), ea + 1); + + if(!BIT_F(word2)) + (mc68kcpu)->c_flag = MAKE_INT_8(compare) - MAKE_INT_8(lower_bound); + else + (mc68kcpu)->c_flag = compare - lower_bound; + (mc68kcpu)->not_z_flag = !((upper_bound==compare) | (lower_bound==compare)); + if(COND_CS(mc68kcpu)) + { + if(BIT_B(word2)) + m68ki_exception_trap((mc68kcpu), EXCEPTION_CHK); + return; + } + + (mc68kcpu)->c_flag = upper_bound - compare; + if(COND_CS(mc68kcpu) && BIT_B(word2)) + m68ki_exception_trap((mc68kcpu), EXCEPTION_CHK); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_chk2cmp2_8_pcix(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT32 compare = REG_DA(mc68kcpu)[(word2 >> 12) & 15]&0xff; + UINT32 ea = EA_PCIX_8(mc68kcpu); + UINT32 lower_bound = m68ki_read_pcrel_8((mc68kcpu), ea); + UINT32 upper_bound = m68ki_read_pcrel_8((mc68kcpu), ea + 1); + + if(!BIT_F(word2)) + (mc68kcpu)->c_flag = MAKE_INT_8(compare) - MAKE_INT_8(lower_bound); + else + (mc68kcpu)->c_flag = compare - lower_bound; + (mc68kcpu)->not_z_flag = !((upper_bound==compare) | (lower_bound==compare)); + if(COND_CS(mc68kcpu)) + { + if(BIT_B(word2)) + m68ki_exception_trap((mc68kcpu), EXCEPTION_CHK); + return; + } + + (mc68kcpu)->c_flag = upper_bound - compare; + if(COND_CS(mc68kcpu) && BIT_B(word2)) + m68ki_exception_trap((mc68kcpu), EXCEPTION_CHK); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_chk2cmp2_8_ai(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT32 compare = REG_DA(mc68kcpu)[(word2 >> 12) & 15]&0xff; + UINT32 ea = EA_AY_AI_8(mc68kcpu); + UINT32 lower_bound = m68ki_read_8((mc68kcpu), ea); + UINT32 upper_bound = m68ki_read_8((mc68kcpu), ea + 1); + + if(!BIT_F(word2)) + (mc68kcpu)->c_flag = MAKE_INT_8(compare) - MAKE_INT_8(lower_bound); + else + (mc68kcpu)->c_flag = compare - lower_bound; + (mc68kcpu)->not_z_flag = !((upper_bound==compare) | (lower_bound==compare)); + if(COND_CS(mc68kcpu)) + { + if(BIT_B(word2)) + m68ki_exception_trap((mc68kcpu), EXCEPTION_CHK); + return; + } + + (mc68kcpu)->c_flag = upper_bound - compare; + if(COND_CS(mc68kcpu) && BIT_B(word2)) + m68ki_exception_trap((mc68kcpu), EXCEPTION_CHK); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_chk2cmp2_8_di(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT32 compare = REG_DA(mc68kcpu)[(word2 >> 12) & 15]&0xff; + UINT32 ea = EA_AY_DI_8(mc68kcpu); + UINT32 lower_bound = m68ki_read_8((mc68kcpu), ea); + UINT32 upper_bound = m68ki_read_8((mc68kcpu), ea + 1); + + if(!BIT_F(word2)) + (mc68kcpu)->c_flag = MAKE_INT_8(compare) - MAKE_INT_8(lower_bound); + else + (mc68kcpu)->c_flag = compare - lower_bound; + (mc68kcpu)->not_z_flag = !((upper_bound==compare) | (lower_bound==compare)); + if(COND_CS(mc68kcpu)) + { + if(BIT_B(word2)) + m68ki_exception_trap((mc68kcpu), EXCEPTION_CHK); + return; + } + + (mc68kcpu)->c_flag = upper_bound - compare; + if(COND_CS(mc68kcpu) && BIT_B(word2)) + m68ki_exception_trap((mc68kcpu), EXCEPTION_CHK); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_chk2cmp2_8_ix(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT32 compare = REG_DA(mc68kcpu)[(word2 >> 12) & 15]&0xff; + UINT32 ea = EA_AY_IX_8(mc68kcpu); + UINT32 lower_bound = m68ki_read_8((mc68kcpu), ea); + UINT32 upper_bound = m68ki_read_8((mc68kcpu), ea + 1); + + if(!BIT_F(word2)) + (mc68kcpu)->c_flag = MAKE_INT_8(compare) - MAKE_INT_8(lower_bound); + else + (mc68kcpu)->c_flag = compare - lower_bound; + (mc68kcpu)->not_z_flag = !((upper_bound==compare) | (lower_bound==compare)); + if(COND_CS(mc68kcpu)) + { + if(BIT_B(word2)) + m68ki_exception_trap((mc68kcpu), EXCEPTION_CHK); + return; + } + + (mc68kcpu)->c_flag = upper_bound - compare; + if(COND_CS(mc68kcpu) && BIT_B(word2)) + m68ki_exception_trap((mc68kcpu), EXCEPTION_CHK); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_chk2cmp2_8_aw(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT32 compare = REG_DA(mc68kcpu)[(word2 >> 12) & 15]&0xff; + UINT32 ea = EA_AW_8(mc68kcpu); + UINT32 lower_bound = m68ki_read_8((mc68kcpu), ea); + UINT32 upper_bound = m68ki_read_8((mc68kcpu), ea + 1); + + if(!BIT_F(word2)) + (mc68kcpu)->c_flag = MAKE_INT_8(compare) - MAKE_INT_8(lower_bound); + else + (mc68kcpu)->c_flag = compare - lower_bound; + (mc68kcpu)->not_z_flag = !((upper_bound==compare) | (lower_bound==compare)); + if(COND_CS(mc68kcpu)) + { + if(BIT_B(word2)) + m68ki_exception_trap((mc68kcpu), EXCEPTION_CHK); + return; + } + + (mc68kcpu)->c_flag = upper_bound - compare; + if(COND_CS(mc68kcpu) && BIT_B(word2)) + m68ki_exception_trap((mc68kcpu), EXCEPTION_CHK); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_chk2cmp2_8_al(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT32 compare = REG_DA(mc68kcpu)[(word2 >> 12) & 15]&0xff; + UINT32 ea = EA_AL_8(mc68kcpu); + UINT32 lower_bound = m68ki_read_8((mc68kcpu), ea); + UINT32 upper_bound = m68ki_read_8((mc68kcpu), ea + 1); + + if(!BIT_F(word2)) + (mc68kcpu)->c_flag = MAKE_INT_8(compare) - MAKE_INT_8(lower_bound); + else + (mc68kcpu)->c_flag = compare - lower_bound; + (mc68kcpu)->not_z_flag = !((upper_bound==compare) | (lower_bound==compare)); + if(COND_CS(mc68kcpu)) + { + if(BIT_B(word2)) + m68ki_exception_trap((mc68kcpu), EXCEPTION_CHK); + return; + } + + (mc68kcpu)->c_flag = upper_bound - compare; + if(COND_CS(mc68kcpu) && BIT_B(word2)) + m68ki_exception_trap((mc68kcpu), EXCEPTION_CHK); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_chk2cmp2_16_pcdi(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT32 compare = REG_DA(mc68kcpu)[(word2 >> 12) & 15]&0xffff; + UINT32 ea = EA_PCDI_16(mc68kcpu); + UINT32 lower_bound = m68ki_read_pcrel_16((mc68kcpu), ea); + UINT32 upper_bound = m68ki_read_pcrel_16((mc68kcpu), ea + 2); + + if(!BIT_F(word2)) + (mc68kcpu)->c_flag = MAKE_INT_16(compare) - MAKE_INT_16(lower_bound); + else + (mc68kcpu)->c_flag = compare - lower_bound; + (mc68kcpu)->not_z_flag = !((upper_bound==compare) | (lower_bound==compare)); + (mc68kcpu)->c_flag = CFLAG_16((mc68kcpu)->c_flag); + if(COND_CS(mc68kcpu)) + { + if(BIT_B(word2)) + m68ki_exception_trap((mc68kcpu), EXCEPTION_CHK); + return; + } + + if(!BIT_F(word2)) + (mc68kcpu)->c_flag = MAKE_INT_16(upper_bound) - MAKE_INT_16(compare); + else + (mc68kcpu)->c_flag = upper_bound - compare; + (mc68kcpu)->c_flag = CFLAG_16((mc68kcpu)->c_flag); + if(COND_CS(mc68kcpu) && BIT_B(word2)) + m68ki_exception_trap((mc68kcpu), EXCEPTION_CHK); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_chk2cmp2_16_pcix(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT32 compare = REG_DA(mc68kcpu)[(word2 >> 12) & 15]&0xffff; + UINT32 ea = EA_PCIX_16(mc68kcpu); + UINT32 lower_bound = m68ki_read_pcrel_16((mc68kcpu), ea); + UINT32 upper_bound = m68ki_read_pcrel_16((mc68kcpu), ea + 2); + + if(!BIT_F(word2)) + (mc68kcpu)->c_flag = MAKE_INT_16(compare) - MAKE_INT_16(lower_bound); + else + (mc68kcpu)->c_flag = compare - lower_bound; + (mc68kcpu)->not_z_flag = !((upper_bound==compare) | (lower_bound==compare)); + (mc68kcpu)->c_flag = CFLAG_16((mc68kcpu)->c_flag); + if(COND_CS(mc68kcpu)) + { + if(BIT_B(word2)) + m68ki_exception_trap((mc68kcpu), EXCEPTION_CHK); + return; + } + + if(!BIT_F(word2)) + (mc68kcpu)->c_flag = MAKE_INT_16(upper_bound) - MAKE_INT_16(compare); + else + (mc68kcpu)->c_flag = upper_bound - compare; + (mc68kcpu)->c_flag = CFLAG_16((mc68kcpu)->c_flag); + if(COND_CS(mc68kcpu) && BIT_B(word2)) + m68ki_exception_trap((mc68kcpu), EXCEPTION_CHK); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_chk2cmp2_16_ai(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT32 compare = REG_DA(mc68kcpu)[(word2 >> 12) & 15]&0xffff; + UINT32 ea = EA_AY_AI_16(mc68kcpu); + UINT32 lower_bound = m68ki_read_16((mc68kcpu), ea); + UINT32 upper_bound = m68ki_read_16((mc68kcpu), ea + 2); + + if(!BIT_F(word2)) + (mc68kcpu)->c_flag = MAKE_INT_16(compare) - MAKE_INT_16(lower_bound); + else + (mc68kcpu)->c_flag = compare - lower_bound; + + (mc68kcpu)->not_z_flag = !((upper_bound==compare) | (lower_bound==compare)); + (mc68kcpu)->c_flag = CFLAG_16((mc68kcpu)->c_flag); + if(COND_CS(mc68kcpu)) + { + if(BIT_B(word2)) + m68ki_exception_trap((mc68kcpu), EXCEPTION_CHK); + return; + } + if(!BIT_F(word2)) + (mc68kcpu)->c_flag = MAKE_INT_16(upper_bound) - MAKE_INT_16(compare); + else + (mc68kcpu)->c_flag = upper_bound - compare; + + (mc68kcpu)->c_flag = CFLAG_16((mc68kcpu)->c_flag); + if(COND_CS(mc68kcpu) && BIT_B(word2)) + m68ki_exception_trap((mc68kcpu), EXCEPTION_CHK); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_chk2cmp2_16_di(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT32 compare = REG_DA(mc68kcpu)[(word2 >> 12) & 15]&0xffff; + UINT32 ea = EA_AY_DI_16(mc68kcpu); + UINT32 lower_bound = m68ki_read_16((mc68kcpu), ea); + UINT32 upper_bound = m68ki_read_16((mc68kcpu), ea + 2); + + if(!BIT_F(word2)) + (mc68kcpu)->c_flag = MAKE_INT_16(compare) - MAKE_INT_16(lower_bound); + else + (mc68kcpu)->c_flag = compare - lower_bound; + + (mc68kcpu)->not_z_flag = !((upper_bound==compare) | (lower_bound==compare)); + (mc68kcpu)->c_flag = CFLAG_16((mc68kcpu)->c_flag); + if(COND_CS(mc68kcpu)) + { + if(BIT_B(word2)) + m68ki_exception_trap((mc68kcpu), EXCEPTION_CHK); + return; + } + if(!BIT_F(word2)) + (mc68kcpu)->c_flag = MAKE_INT_16(upper_bound) - MAKE_INT_16(compare); + else + (mc68kcpu)->c_flag = upper_bound - compare; + + (mc68kcpu)->c_flag = CFLAG_16((mc68kcpu)->c_flag); + if(COND_CS(mc68kcpu) && BIT_B(word2)) + m68ki_exception_trap((mc68kcpu), EXCEPTION_CHK); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_chk2cmp2_16_ix(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT32 compare = REG_DA(mc68kcpu)[(word2 >> 12) & 15]&0xffff; + UINT32 ea = EA_AY_IX_16(mc68kcpu); + UINT32 lower_bound = m68ki_read_16((mc68kcpu), ea); + UINT32 upper_bound = m68ki_read_16((mc68kcpu), ea + 2); + + if(!BIT_F(word2)) + (mc68kcpu)->c_flag = MAKE_INT_16(compare) - MAKE_INT_16(lower_bound); + else + (mc68kcpu)->c_flag = compare - lower_bound; + + (mc68kcpu)->not_z_flag = !((upper_bound==compare) | (lower_bound==compare)); + (mc68kcpu)->c_flag = CFLAG_16((mc68kcpu)->c_flag); + if(COND_CS(mc68kcpu)) + { + if(BIT_B(word2)) + m68ki_exception_trap((mc68kcpu), EXCEPTION_CHK); + return; + } + if(!BIT_F(word2)) + (mc68kcpu)->c_flag = MAKE_INT_16(upper_bound) - MAKE_INT_16(compare); + else + (mc68kcpu)->c_flag = upper_bound - compare; + + (mc68kcpu)->c_flag = CFLAG_16((mc68kcpu)->c_flag); + if(COND_CS(mc68kcpu) && BIT_B(word2)) + m68ki_exception_trap((mc68kcpu), EXCEPTION_CHK); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_chk2cmp2_16_aw(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT32 compare = REG_DA(mc68kcpu)[(word2 >> 12) & 15]&0xffff; + UINT32 ea = EA_AW_16(mc68kcpu); + UINT32 lower_bound = m68ki_read_16((mc68kcpu), ea); + UINT32 upper_bound = m68ki_read_16((mc68kcpu), ea + 2); + + if(!BIT_F(word2)) + (mc68kcpu)->c_flag = MAKE_INT_16(compare) - MAKE_INT_16(lower_bound); + else + (mc68kcpu)->c_flag = compare - lower_bound; + + (mc68kcpu)->not_z_flag = !((upper_bound==compare) | (lower_bound==compare)); + (mc68kcpu)->c_flag = CFLAG_16((mc68kcpu)->c_flag); + if(COND_CS(mc68kcpu)) + { + if(BIT_B(word2)) + m68ki_exception_trap((mc68kcpu), EXCEPTION_CHK); + return; + } + if(!BIT_F(word2)) + (mc68kcpu)->c_flag = MAKE_INT_16(upper_bound) - MAKE_INT_16(compare); + else + (mc68kcpu)->c_flag = upper_bound - compare; + + (mc68kcpu)->c_flag = CFLAG_16((mc68kcpu)->c_flag); + if(COND_CS(mc68kcpu) && BIT_B(word2)) + m68ki_exception_trap((mc68kcpu), EXCEPTION_CHK); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_chk2cmp2_16_al(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT32 compare = REG_DA(mc68kcpu)[(word2 >> 12) & 15]&0xffff; + UINT32 ea = EA_AL_16(mc68kcpu); + UINT32 lower_bound = m68ki_read_16((mc68kcpu), ea); + UINT32 upper_bound = m68ki_read_16((mc68kcpu), ea + 2); + + if(!BIT_F(word2)) + (mc68kcpu)->c_flag = MAKE_INT_16(compare) - MAKE_INT_16(lower_bound); + else + (mc68kcpu)->c_flag = compare - lower_bound; + + (mc68kcpu)->not_z_flag = !((upper_bound==compare) | (lower_bound==compare)); + (mc68kcpu)->c_flag = CFLAG_16((mc68kcpu)->c_flag); + if(COND_CS(mc68kcpu)) + { + if(BIT_B(word2)) + m68ki_exception_trap((mc68kcpu), EXCEPTION_CHK); + return; + } + if(!BIT_F(word2)) + (mc68kcpu)->c_flag = MAKE_INT_16(upper_bound) - MAKE_INT_16(compare); + else + (mc68kcpu)->c_flag = upper_bound - compare; + + (mc68kcpu)->c_flag = CFLAG_16((mc68kcpu)->c_flag); + if(COND_CS(mc68kcpu) && BIT_B(word2)) + m68ki_exception_trap((mc68kcpu), EXCEPTION_CHK); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_chk2cmp2_32_pcdi(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT32 compare = REG_DA(mc68kcpu)[(word2 >> 12) & 15]; + UINT32 ea = EA_PCDI_32(mc68kcpu); + UINT32 lower_bound = m68ki_read_pcrel_32((mc68kcpu), ea); + UINT32 upper_bound = m68ki_read_pcrel_32((mc68kcpu), ea + 4); + + (mc68kcpu)->c_flag = compare - lower_bound; + (mc68kcpu)->not_z_flag = !((upper_bound==compare) | (lower_bound==compare)); + (mc68kcpu)->c_flag = CFLAG_SUB_32(lower_bound, compare, (mc68kcpu)->c_flag); + if(COND_CS(mc68kcpu)) + { + if(BIT_B(word2)) + m68ki_exception_trap((mc68kcpu), EXCEPTION_CHK); + return; + } + + (mc68kcpu)->c_flag = upper_bound - compare; + (mc68kcpu)->c_flag = CFLAG_SUB_32(compare, upper_bound, (mc68kcpu)->c_flag); + if(COND_CS(mc68kcpu) && BIT_B(word2)) + m68ki_exception_trap((mc68kcpu), EXCEPTION_CHK); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_chk2cmp2_32_pcix(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT32 compare = REG_DA(mc68kcpu)[(word2 >> 12) & 15]; + UINT32 ea = EA_PCIX_32(mc68kcpu); + UINT32 lower_bound = m68ki_read_pcrel_32((mc68kcpu), ea); + UINT32 upper_bound = m68ki_read_pcrel_32((mc68kcpu), ea + 4); + + (mc68kcpu)->c_flag = compare - lower_bound; + (mc68kcpu)->not_z_flag = !((upper_bound==compare) | (lower_bound==compare)); + (mc68kcpu)->c_flag = CFLAG_SUB_32(lower_bound, compare, (mc68kcpu)->c_flag); + if(COND_CS(mc68kcpu)) + { + if(BIT_B(word2)) + m68ki_exception_trap((mc68kcpu), EXCEPTION_CHK); + return; + } + + (mc68kcpu)->c_flag = upper_bound - compare; + (mc68kcpu)->c_flag = CFLAG_SUB_32(compare, upper_bound, (mc68kcpu)->c_flag); + if(COND_CS(mc68kcpu) && BIT_B(word2)) + m68ki_exception_trap((mc68kcpu), EXCEPTION_CHK); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_chk2cmp2_32_ai(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT32 compare = REG_DA(mc68kcpu)[(word2 >> 12) & 15]; + UINT32 ea = EA_AY_AI_32(mc68kcpu); + UINT32 lower_bound = m68ki_read_32((mc68kcpu), ea); + UINT32 upper_bound = m68ki_read_32((mc68kcpu), ea + 4); + + (mc68kcpu)->c_flag = compare - lower_bound; + (mc68kcpu)->not_z_flag = !((upper_bound==compare) | (lower_bound==compare)); + (mc68kcpu)->c_flag = CFLAG_SUB_32(lower_bound, compare, (mc68kcpu)->c_flag); + if(COND_CS(mc68kcpu)) + { + if(BIT_B(word2)) + m68ki_exception_trap((mc68kcpu), EXCEPTION_CHK); + return; + } + + (mc68kcpu)->c_flag = upper_bound - compare; + (mc68kcpu)->c_flag = CFLAG_SUB_32(compare, upper_bound, (mc68kcpu)->c_flag); + if(COND_CS(mc68kcpu) && BIT_B(word2)) + m68ki_exception_trap((mc68kcpu), EXCEPTION_CHK); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_chk2cmp2_32_di(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT32 compare = REG_DA(mc68kcpu)[(word2 >> 12) & 15]; + UINT32 ea = EA_AY_DI_32(mc68kcpu); + UINT32 lower_bound = m68ki_read_32((mc68kcpu), ea); + UINT32 upper_bound = m68ki_read_32((mc68kcpu), ea + 4); + + (mc68kcpu)->c_flag = compare - lower_bound; + (mc68kcpu)->not_z_flag = !((upper_bound==compare) | (lower_bound==compare)); + (mc68kcpu)->c_flag = CFLAG_SUB_32(lower_bound, compare, (mc68kcpu)->c_flag); + if(COND_CS(mc68kcpu)) + { + if(BIT_B(word2)) + m68ki_exception_trap((mc68kcpu), EXCEPTION_CHK); + return; + } + + (mc68kcpu)->c_flag = upper_bound - compare; + (mc68kcpu)->c_flag = CFLAG_SUB_32(compare, upper_bound, (mc68kcpu)->c_flag); + if(COND_CS(mc68kcpu) && BIT_B(word2)) + m68ki_exception_trap((mc68kcpu), EXCEPTION_CHK); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_chk2cmp2_32_ix(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT32 compare = REG_DA(mc68kcpu)[(word2 >> 12) & 15]; + UINT32 ea = EA_AY_IX_32(mc68kcpu); + UINT32 lower_bound = m68ki_read_32((mc68kcpu), ea); + UINT32 upper_bound = m68ki_read_32((mc68kcpu), ea + 4); + + (mc68kcpu)->c_flag = compare - lower_bound; + (mc68kcpu)->not_z_flag = !((upper_bound==compare) | (lower_bound==compare)); + (mc68kcpu)->c_flag = CFLAG_SUB_32(lower_bound, compare, (mc68kcpu)->c_flag); + if(COND_CS(mc68kcpu)) + { + if(BIT_B(word2)) + m68ki_exception_trap((mc68kcpu), EXCEPTION_CHK); + return; + } + + (mc68kcpu)->c_flag = upper_bound - compare; + (mc68kcpu)->c_flag = CFLAG_SUB_32(compare, upper_bound, (mc68kcpu)->c_flag); + if(COND_CS(mc68kcpu) && BIT_B(word2)) + m68ki_exception_trap((mc68kcpu), EXCEPTION_CHK); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_chk2cmp2_32_aw(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT32 compare = REG_DA(mc68kcpu)[(word2 >> 12) & 15]; + UINT32 ea = EA_AW_32(mc68kcpu); + UINT32 lower_bound = m68ki_read_32((mc68kcpu), ea); + UINT32 upper_bound = m68ki_read_32((mc68kcpu), ea + 4); + + (mc68kcpu)->c_flag = compare - lower_bound; + (mc68kcpu)->not_z_flag = !((upper_bound==compare) | (lower_bound==compare)); + (mc68kcpu)->c_flag = CFLAG_SUB_32(lower_bound, compare, (mc68kcpu)->c_flag); + if(COND_CS(mc68kcpu)) + { + if(BIT_B(word2)) + m68ki_exception_trap((mc68kcpu), EXCEPTION_CHK); + return; + } + + (mc68kcpu)->c_flag = upper_bound - compare; + (mc68kcpu)->c_flag = CFLAG_SUB_32(compare, upper_bound, (mc68kcpu)->c_flag); + if(COND_CS(mc68kcpu) && BIT_B(word2)) + m68ki_exception_trap((mc68kcpu), EXCEPTION_CHK); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_chk2cmp2_32_al(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT32 compare = REG_DA(mc68kcpu)[(word2 >> 12) & 15]; + UINT32 ea = EA_AL_32(mc68kcpu); + UINT32 lower_bound = m68ki_read_32((mc68kcpu), ea); + UINT32 upper_bound = m68ki_read_32((mc68kcpu), ea + 4); + + (mc68kcpu)->c_flag = compare - lower_bound; + (mc68kcpu)->not_z_flag = !((upper_bound==compare) | (lower_bound==compare)); + (mc68kcpu)->c_flag = CFLAG_SUB_32(lower_bound, compare, (mc68kcpu)->c_flag); + if(COND_CS(mc68kcpu)) + { + if(BIT_B(word2)) + m68ki_exception_trap((mc68kcpu), EXCEPTION_CHK); + return; + } + + (mc68kcpu)->c_flag = upper_bound - compare; + (mc68kcpu)->c_flag = CFLAG_SUB_32(compare, upper_bound, (mc68kcpu)->c_flag); + if(COND_CS(mc68kcpu) && BIT_B(word2)) + m68ki_exception_trap((mc68kcpu), EXCEPTION_CHK); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_clr_8_d(m68000_base_device* mc68kcpu) +{ + DY(mc68kcpu) &= 0xffffff00; + + (mc68kcpu)->n_flag = NFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->not_z_flag = ZFLAG_SET; +} + + +void m68000_base_device_ops::m68k_op_clr_8_ai(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_AI_8(mc68kcpu); + + if(CPU_TYPE_IS_000((mc68kcpu)->cpu_type)) + { + m68ki_read_8((mc68kcpu), ea); /* the 68000 does a dummy read, the value is discarded */ + } + + m68ki_write_8((mc68kcpu), ea, 0); + + (mc68kcpu)->n_flag = NFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->not_z_flag = ZFLAG_SET; +} + + +void m68000_base_device_ops::m68k_op_clr_8_pi(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_PI_8(mc68kcpu); + + if(CPU_TYPE_IS_000((mc68kcpu)->cpu_type)) + { + m68ki_read_8((mc68kcpu), ea); /* the 68000 does a dummy read, the value is discarded */ + } + + m68ki_write_8((mc68kcpu), ea, 0); + + (mc68kcpu)->n_flag = NFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->not_z_flag = ZFLAG_SET; +} + + +void m68000_base_device_ops::m68k_op_clr_8_pi7(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_A7_PI_8(mc68kcpu); + + if(CPU_TYPE_IS_000((mc68kcpu)->cpu_type)) + { + m68ki_read_8((mc68kcpu), ea); /* the 68000 does a dummy read, the value is discarded */ + } + + m68ki_write_8((mc68kcpu), ea, 0); + + (mc68kcpu)->n_flag = NFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->not_z_flag = ZFLAG_SET; +} + + +void m68000_base_device_ops::m68k_op_clr_8_pd(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_PD_8(mc68kcpu); + + if(CPU_TYPE_IS_000((mc68kcpu)->cpu_type)) + { + m68ki_read_8((mc68kcpu), ea); /* the 68000 does a dummy read, the value is discarded */ + } + + m68ki_write_8((mc68kcpu), ea, 0); + + (mc68kcpu)->n_flag = NFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->not_z_flag = ZFLAG_SET; +} + + +void m68000_base_device_ops::m68k_op_clr_8_pd7(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_A7_PD_8(mc68kcpu); + + if(CPU_TYPE_IS_000((mc68kcpu)->cpu_type)) + { + m68ki_read_8((mc68kcpu), ea); /* the 68000 does a dummy read, the value is discarded */ + } + + m68ki_write_8((mc68kcpu), ea, 0); + + (mc68kcpu)->n_flag = NFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->not_z_flag = ZFLAG_SET; +} + + +void m68000_base_device_ops::m68k_op_clr_8_di(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_DI_8(mc68kcpu); + + if(CPU_TYPE_IS_000((mc68kcpu)->cpu_type)) + { + m68ki_read_8((mc68kcpu), ea); /* the 68000 does a dummy read, the value is discarded */ + } + + m68ki_write_8((mc68kcpu), ea, 0); + + (mc68kcpu)->n_flag = NFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->not_z_flag = ZFLAG_SET; +} + + +void m68000_base_device_ops::m68k_op_clr_8_ix(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_IX_8(mc68kcpu); + + if(CPU_TYPE_IS_000((mc68kcpu)->cpu_type)) + { + m68ki_read_8((mc68kcpu), ea); /* the 68000 does a dummy read, the value is discarded */ + } + + m68ki_write_8((mc68kcpu), ea, 0); + + (mc68kcpu)->n_flag = NFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->not_z_flag = ZFLAG_SET; +} + + +void m68000_base_device_ops::m68k_op_clr_8_aw(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AW_8(mc68kcpu); + + if(CPU_TYPE_IS_000((mc68kcpu)->cpu_type)) + { + m68ki_read_8((mc68kcpu), ea); /* the 68000 does a dummy read, the value is discarded */ + } + + m68ki_write_8((mc68kcpu), ea, 0); + + (mc68kcpu)->n_flag = NFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->not_z_flag = ZFLAG_SET; +} + + +void m68000_base_device_ops::m68k_op_clr_8_al(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AL_8(mc68kcpu); + + if(CPU_TYPE_IS_000((mc68kcpu)->cpu_type)) + { + m68ki_read_8((mc68kcpu), ea); /* the 68000 does a dummy read, the value is discarded */ + } + + m68ki_write_8((mc68kcpu), ea, 0); + + (mc68kcpu)->n_flag = NFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->not_z_flag = ZFLAG_SET; +} + + +void m68000_base_device_ops::m68k_op_clr_16_d(m68000_base_device* mc68kcpu) +{ + DY(mc68kcpu) &= 0xffff0000; + + (mc68kcpu)->n_flag = NFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->not_z_flag = ZFLAG_SET; +} + + +void m68000_base_device_ops::m68k_op_clr_16_ai(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_AI_16(mc68kcpu); + + if(CPU_TYPE_IS_000((mc68kcpu)->cpu_type)) + { + m68ki_read_16((mc68kcpu), ea); /* the 68000 does a dummy read, the value is discarded */ + } + + m68ki_write_16((mc68kcpu), ea, 0); + + (mc68kcpu)->n_flag = NFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->not_z_flag = ZFLAG_SET; +} + + +void m68000_base_device_ops::m68k_op_clr_16_pi(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_PI_16(mc68kcpu); + + if(CPU_TYPE_IS_000((mc68kcpu)->cpu_type)) + { + m68ki_read_16((mc68kcpu), ea); /* the 68000 does a dummy read, the value is discarded */ + } + + m68ki_write_16((mc68kcpu), ea, 0); + + (mc68kcpu)->n_flag = NFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->not_z_flag = ZFLAG_SET; +} + + +void m68000_base_device_ops::m68k_op_clr_16_pd(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_PD_16(mc68kcpu); + + if(CPU_TYPE_IS_000((mc68kcpu)->cpu_type)) + { + m68ki_read_16((mc68kcpu), ea); /* the 68000 does a dummy read, the value is discarded */ + } + + m68ki_write_16((mc68kcpu), ea, 0); + + (mc68kcpu)->n_flag = NFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->not_z_flag = ZFLAG_SET; +} + + +void m68000_base_device_ops::m68k_op_clr_16_di(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_DI_16(mc68kcpu); + + if(CPU_TYPE_IS_000((mc68kcpu)->cpu_type)) + { + m68ki_read_16((mc68kcpu), ea); /* the 68000 does a dummy read, the value is discarded */ + } + + m68ki_write_16((mc68kcpu), ea, 0); + + (mc68kcpu)->n_flag = NFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->not_z_flag = ZFLAG_SET; +} + + +void m68000_base_device_ops::m68k_op_clr_16_ix(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_IX_16(mc68kcpu); + + if(CPU_TYPE_IS_000((mc68kcpu)->cpu_type)) + { + m68ki_read_16((mc68kcpu), ea); /* the 68000 does a dummy read, the value is discarded */ + } + + m68ki_write_16((mc68kcpu), ea, 0); + + (mc68kcpu)->n_flag = NFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->not_z_flag = ZFLAG_SET; +} + + +void m68000_base_device_ops::m68k_op_clr_16_aw(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AW_16(mc68kcpu); + + if(CPU_TYPE_IS_000((mc68kcpu)->cpu_type)) + { + m68ki_read_16((mc68kcpu), ea); /* the 68000 does a dummy read, the value is discarded */ + } + + m68ki_write_16((mc68kcpu), ea, 0); + + (mc68kcpu)->n_flag = NFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->not_z_flag = ZFLAG_SET; +} + + +void m68000_base_device_ops::m68k_op_clr_16_al(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AL_16(mc68kcpu); + + if(CPU_TYPE_IS_000((mc68kcpu)->cpu_type)) + { + m68ki_read_16((mc68kcpu), ea); /* the 68000 does a dummy read, the value is discarded */ + } + + m68ki_write_16((mc68kcpu), ea, 0); + + (mc68kcpu)->n_flag = NFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->not_z_flag = ZFLAG_SET; +} + + +void m68000_base_device_ops::m68k_op_clr_32_d(m68000_base_device* mc68kcpu) +{ + DY(mc68kcpu) = 0; + + (mc68kcpu)->n_flag = NFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->not_z_flag = ZFLAG_SET; +} + + +void m68000_base_device_ops::m68k_op_clr_32_ai(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_AI_32(mc68kcpu); + + if(CPU_TYPE_IS_000((mc68kcpu)->cpu_type)) + { + m68ki_read_32((mc68kcpu), ea); /* the 68000 does a dummy read, the value is discarded */ + } + + m68ki_write_32((mc68kcpu), ea, 0); + + (mc68kcpu)->n_flag = NFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->not_z_flag = ZFLAG_SET; +} + + +void m68000_base_device_ops::m68k_op_clr_32_pi(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_PI_32(mc68kcpu); + + if(CPU_TYPE_IS_000((mc68kcpu)->cpu_type)) + { + m68ki_read_32((mc68kcpu), ea); /* the 68000 does a dummy read, the value is discarded */ + } + + m68ki_write_32((mc68kcpu), ea, 0); + + (mc68kcpu)->n_flag = NFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->not_z_flag = ZFLAG_SET; +} + + +void m68000_base_device_ops::m68k_op_clr_32_pd(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_PD_32(mc68kcpu); + + if(CPU_TYPE_IS_000((mc68kcpu)->cpu_type)) + { + m68ki_read_32((mc68kcpu), ea); /* the 68000 does a dummy read, the value is discarded */ + } + + m68ki_write_32((mc68kcpu), ea, 0); + + (mc68kcpu)->n_flag = NFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->not_z_flag = ZFLAG_SET; +} + + +void m68000_base_device_ops::m68k_op_clr_32_di(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_DI_32(mc68kcpu); + + if(CPU_TYPE_IS_000((mc68kcpu)->cpu_type)) + { + m68ki_read_32((mc68kcpu), ea); /* the 68000 does a dummy read, the value is discarded */ + } + + m68ki_write_32((mc68kcpu), ea, 0); + + (mc68kcpu)->n_flag = NFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->not_z_flag = ZFLAG_SET; +} + + +void m68000_base_device_ops::m68k_op_clr_32_ix(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_IX_32(mc68kcpu); + + if(CPU_TYPE_IS_000((mc68kcpu)->cpu_type)) + { + m68ki_read_32((mc68kcpu), ea); /* the 68000 does a dummy read, the value is discarded */ + } + + m68ki_write_32((mc68kcpu), ea, 0); + + (mc68kcpu)->n_flag = NFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->not_z_flag = ZFLAG_SET; +} + + +void m68000_base_device_ops::m68k_op_clr_32_aw(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AW_32(mc68kcpu); + + if(CPU_TYPE_IS_000((mc68kcpu)->cpu_type)) + { + m68ki_read_32((mc68kcpu), ea); /* the 68000 does a dummy read, the value is discarded */ + } + + m68ki_write_32((mc68kcpu), ea, 0); + + (mc68kcpu)->n_flag = NFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->not_z_flag = ZFLAG_SET; +} + + +void m68000_base_device_ops::m68k_op_clr_32_al(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AL_32(mc68kcpu); + + if(CPU_TYPE_IS_000((mc68kcpu)->cpu_type)) + { + m68ki_read_32((mc68kcpu), ea); /* the 68000 does a dummy read, the value is discarded */ + } + + m68ki_write_32((mc68kcpu), ea, 0); + + (mc68kcpu)->n_flag = NFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->not_z_flag = ZFLAG_SET; +} + + +void m68000_base_device_ops::m68k_op_cmp_8_d(m68000_base_device* mc68kcpu) +{ + UINT32 src = MASK_OUT_ABOVE_8(DY(mc68kcpu)); + UINT32 dst = MASK_OUT_ABOVE_8(DX(mc68kcpu)); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_8(res); +} + + +void m68000_base_device_ops::m68k_op_cmp_8_ai(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_AY_AI_8(mc68kcpu); + UINT32 dst = MASK_OUT_ABOVE_8(DX(mc68kcpu)); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_8(res); +} + + +void m68000_base_device_ops::m68k_op_cmp_8_pi(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_AY_PI_8(mc68kcpu); + UINT32 dst = MASK_OUT_ABOVE_8(DX(mc68kcpu)); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_8(res); +} + + +void m68000_base_device_ops::m68k_op_cmp_8_pi7(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_A7_PI_8(mc68kcpu); + UINT32 dst = MASK_OUT_ABOVE_8(DX(mc68kcpu)); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_8(res); +} + + +void m68000_base_device_ops::m68k_op_cmp_8_pd(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_AY_PD_8(mc68kcpu); + UINT32 dst = MASK_OUT_ABOVE_8(DX(mc68kcpu)); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_8(res); +} + + +void m68000_base_device_ops::m68k_op_cmp_8_pd7(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_A7_PD_8(mc68kcpu); + UINT32 dst = MASK_OUT_ABOVE_8(DX(mc68kcpu)); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_8(res); +} + + +void m68000_base_device_ops::m68k_op_cmp_8_di(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_AY_DI_8(mc68kcpu); + UINT32 dst = MASK_OUT_ABOVE_8(DX(mc68kcpu)); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_8(res); +} + + +void m68000_base_device_ops::m68k_op_cmp_8_ix(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_AY_IX_8(mc68kcpu); + UINT32 dst = MASK_OUT_ABOVE_8(DX(mc68kcpu)); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_8(res); +} + + +void m68000_base_device_ops::m68k_op_cmp_8_aw(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_AW_8(mc68kcpu); + UINT32 dst = MASK_OUT_ABOVE_8(DX(mc68kcpu)); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_8(res); +} + + +void m68000_base_device_ops::m68k_op_cmp_8_al(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_AL_8(mc68kcpu); + UINT32 dst = MASK_OUT_ABOVE_8(DX(mc68kcpu)); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_8(res); +} + + +void m68000_base_device_ops::m68k_op_cmp_8_pcdi(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_PCDI_8(mc68kcpu); + UINT32 dst = MASK_OUT_ABOVE_8(DX(mc68kcpu)); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_8(res); +} + + +void m68000_base_device_ops::m68k_op_cmp_8_pcix(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_PCIX_8(mc68kcpu); + UINT32 dst = MASK_OUT_ABOVE_8(DX(mc68kcpu)); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_8(res); +} + + +void m68000_base_device_ops::m68k_op_cmp_8_i(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_8(mc68kcpu); + UINT32 dst = MASK_OUT_ABOVE_8(DX(mc68kcpu)); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_8(res); +} + + +void m68000_base_device_ops::m68k_op_cmp_16_d(m68000_base_device* mc68kcpu) +{ + UINT32 src = MASK_OUT_ABOVE_16(DY(mc68kcpu)); + UINT32 dst = MASK_OUT_ABOVE_16(DX(mc68kcpu)); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + (mc68kcpu)->v_flag = VFLAG_SUB_16(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_16(res); +} + + +void m68000_base_device_ops::m68k_op_cmp_16_a(m68000_base_device* mc68kcpu) +{ + UINT32 src = MASK_OUT_ABOVE_16(AY(mc68kcpu)); + UINT32 dst = MASK_OUT_ABOVE_16(DX(mc68kcpu)); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + (mc68kcpu)->v_flag = VFLAG_SUB_16(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_16(res); +} + + +void m68000_base_device_ops::m68k_op_cmp_16_ai(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_AY_AI_16(mc68kcpu); + UINT32 dst = MASK_OUT_ABOVE_16(DX(mc68kcpu)); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + (mc68kcpu)->v_flag = VFLAG_SUB_16(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_16(res); +} + + +void m68000_base_device_ops::m68k_op_cmp_16_pi(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_AY_PI_16(mc68kcpu); + UINT32 dst = MASK_OUT_ABOVE_16(DX(mc68kcpu)); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + (mc68kcpu)->v_flag = VFLAG_SUB_16(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_16(res); +} + + +void m68000_base_device_ops::m68k_op_cmp_16_pd(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_AY_PD_16(mc68kcpu); + UINT32 dst = MASK_OUT_ABOVE_16(DX(mc68kcpu)); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + (mc68kcpu)->v_flag = VFLAG_SUB_16(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_16(res); +} + + +void m68000_base_device_ops::m68k_op_cmp_16_di(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_AY_DI_16(mc68kcpu); + UINT32 dst = MASK_OUT_ABOVE_16(DX(mc68kcpu)); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + (mc68kcpu)->v_flag = VFLAG_SUB_16(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_16(res); +} + + +void m68000_base_device_ops::m68k_op_cmp_16_ix(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_AY_IX_16(mc68kcpu); + UINT32 dst = MASK_OUT_ABOVE_16(DX(mc68kcpu)); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + (mc68kcpu)->v_flag = VFLAG_SUB_16(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_16(res); +} + + +void m68000_base_device_ops::m68k_op_cmp_16_aw(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_AW_16(mc68kcpu); + UINT32 dst = MASK_OUT_ABOVE_16(DX(mc68kcpu)); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + (mc68kcpu)->v_flag = VFLAG_SUB_16(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_16(res); +} + + +void m68000_base_device_ops::m68k_op_cmp_16_al(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_AL_16(mc68kcpu); + UINT32 dst = MASK_OUT_ABOVE_16(DX(mc68kcpu)); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + (mc68kcpu)->v_flag = VFLAG_SUB_16(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_16(res); +} + + +void m68000_base_device_ops::m68k_op_cmp_16_pcdi(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_PCDI_16(mc68kcpu); + UINT32 dst = MASK_OUT_ABOVE_16(DX(mc68kcpu)); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + (mc68kcpu)->v_flag = VFLAG_SUB_16(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_16(res); +} + + +void m68000_base_device_ops::m68k_op_cmp_16_pcix(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_PCIX_16(mc68kcpu); + UINT32 dst = MASK_OUT_ABOVE_16(DX(mc68kcpu)); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + (mc68kcpu)->v_flag = VFLAG_SUB_16(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_16(res); +} + + +void m68000_base_device_ops::m68k_op_cmp_16_i(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_16(mc68kcpu); + UINT32 dst = MASK_OUT_ABOVE_16(DX(mc68kcpu)); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + (mc68kcpu)->v_flag = VFLAG_SUB_16(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_16(res); +} + + +void m68000_base_device_ops::m68k_op_cmp_32_d(m68000_base_device* mc68kcpu) +{ + UINT32 src = DY(mc68kcpu); + UINT32 dst = DX(mc68kcpu); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); +} + + +void m68000_base_device_ops::m68k_op_cmp_32_a(m68000_base_device* mc68kcpu) +{ + UINT32 src = AY(mc68kcpu); + UINT32 dst = DX(mc68kcpu); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); +} + + +void m68000_base_device_ops::m68k_op_cmp_32_ai(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_AY_AI_32(mc68kcpu); + UINT32 dst = DX(mc68kcpu); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); +} + + +void m68000_base_device_ops::m68k_op_cmp_32_pi(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_AY_PI_32(mc68kcpu); + UINT32 dst = DX(mc68kcpu); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); +} + + +void m68000_base_device_ops::m68k_op_cmp_32_pd(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_AY_PD_32(mc68kcpu); + UINT32 dst = DX(mc68kcpu); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); +} + + +void m68000_base_device_ops::m68k_op_cmp_32_di(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_AY_DI_32(mc68kcpu); + UINT32 dst = DX(mc68kcpu); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); +} + + +void m68000_base_device_ops::m68k_op_cmp_32_ix(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_AY_IX_32(mc68kcpu); + UINT32 dst = DX(mc68kcpu); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); +} + + +void m68000_base_device_ops::m68k_op_cmp_32_aw(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_AW_32(mc68kcpu); + UINT32 dst = DX(mc68kcpu); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); +} + + +void m68000_base_device_ops::m68k_op_cmp_32_al(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_AL_32(mc68kcpu); + UINT32 dst = DX(mc68kcpu); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); +} + + +void m68000_base_device_ops::m68k_op_cmp_32_pcdi(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_PCDI_32(mc68kcpu); + UINT32 dst = DX(mc68kcpu); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); +} + + +void m68000_base_device_ops::m68k_op_cmp_32_pcix(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_PCIX_32(mc68kcpu); + UINT32 dst = DX(mc68kcpu); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); +} + + +void m68000_base_device_ops::m68k_op_cmp_32_i(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_32(mc68kcpu); + UINT32 dst = DX(mc68kcpu); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); +} + + +void m68000_base_device_ops::m68k_op_cmpa_16_d(m68000_base_device* mc68kcpu) +{ + UINT32 src = MAKE_INT_16(DY(mc68kcpu)); + UINT32 dst = AX(mc68kcpu); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); +} + + +void m68000_base_device_ops::m68k_op_cmpa_16_a(m68000_base_device* mc68kcpu) +{ + UINT32 src = MAKE_INT_16(AY(mc68kcpu)); + UINT32 dst = AX(mc68kcpu); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); +} + + +void m68000_base_device_ops::m68k_op_cmpa_16_ai(m68000_base_device* mc68kcpu) +{ + UINT32 src = MAKE_INT_16(OPER_AY_AI_16(mc68kcpu)); + UINT32 dst = AX(mc68kcpu); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); +} + + +void m68000_base_device_ops::m68k_op_cmpa_16_pi(m68000_base_device* mc68kcpu) +{ + UINT32 src = MAKE_INT_16(OPER_AY_PI_16(mc68kcpu)); + UINT32 dst = AX(mc68kcpu); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); +} + + +void m68000_base_device_ops::m68k_op_cmpa_16_pd(m68000_base_device* mc68kcpu) +{ + UINT32 src = MAKE_INT_16(OPER_AY_PD_16(mc68kcpu)); + UINT32 dst = AX(mc68kcpu); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); +} + + +void m68000_base_device_ops::m68k_op_cmpa_16_di(m68000_base_device* mc68kcpu) +{ + UINT32 src = MAKE_INT_16(OPER_AY_DI_16(mc68kcpu)); + UINT32 dst = AX(mc68kcpu); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); +} + + +void m68000_base_device_ops::m68k_op_cmpa_16_ix(m68000_base_device* mc68kcpu) +{ + UINT32 src = MAKE_INT_16(OPER_AY_IX_16(mc68kcpu)); + UINT32 dst = AX(mc68kcpu); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); +} + + +void m68000_base_device_ops::m68k_op_cmpa_16_aw(m68000_base_device* mc68kcpu) +{ + UINT32 src = MAKE_INT_16(OPER_AW_16(mc68kcpu)); + UINT32 dst = AX(mc68kcpu); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); +} + + +void m68000_base_device_ops::m68k_op_cmpa_16_al(m68000_base_device* mc68kcpu) +{ + UINT32 src = MAKE_INT_16(OPER_AL_16(mc68kcpu)); + UINT32 dst = AX(mc68kcpu); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); +} + + +void m68000_base_device_ops::m68k_op_cmpa_16_pcdi(m68000_base_device* mc68kcpu) +{ + UINT32 src = MAKE_INT_16(OPER_PCDI_16(mc68kcpu)); + UINT32 dst = AX(mc68kcpu); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); +} + + +void m68000_base_device_ops::m68k_op_cmpa_16_pcix(m68000_base_device* mc68kcpu) +{ + UINT32 src = MAKE_INT_16(OPER_PCIX_16(mc68kcpu)); + UINT32 dst = AX(mc68kcpu); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); +} + + +void m68000_base_device_ops::m68k_op_cmpa_16_i(m68000_base_device* mc68kcpu) +{ + UINT32 src = MAKE_INT_16(OPER_I_16(mc68kcpu)); + UINT32 dst = AX(mc68kcpu); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); +} + + +void m68000_base_device_ops::m68k_op_cmpa_32_d(m68000_base_device* mc68kcpu) +{ + UINT32 src = DY(mc68kcpu); + UINT32 dst = AX(mc68kcpu); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); +} + + +void m68000_base_device_ops::m68k_op_cmpa_32_a(m68000_base_device* mc68kcpu) +{ + UINT32 src = AY(mc68kcpu); + UINT32 dst = AX(mc68kcpu); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); +} + + +void m68000_base_device_ops::m68k_op_cmpa_32_ai(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_AY_AI_32(mc68kcpu); + UINT32 dst = AX(mc68kcpu); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); +} + + +void m68000_base_device_ops::m68k_op_cmpa_32_pi(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_AY_PI_32(mc68kcpu); + UINT32 dst = AX(mc68kcpu); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); +} + + +void m68000_base_device_ops::m68k_op_cmpa_32_pd(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_AY_PD_32(mc68kcpu); + UINT32 dst = AX(mc68kcpu); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); +} + + +void m68000_base_device_ops::m68k_op_cmpa_32_di(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_AY_DI_32(mc68kcpu); + UINT32 dst = AX(mc68kcpu); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); +} + + +void m68000_base_device_ops::m68k_op_cmpa_32_ix(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_AY_IX_32(mc68kcpu); + UINT32 dst = AX(mc68kcpu); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); +} + + +void m68000_base_device_ops::m68k_op_cmpa_32_aw(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_AW_32(mc68kcpu); + UINT32 dst = AX(mc68kcpu); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); +} + + +void m68000_base_device_ops::m68k_op_cmpa_32_al(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_AL_32(mc68kcpu); + UINT32 dst = AX(mc68kcpu); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); +} + + +void m68000_base_device_ops::m68k_op_cmpa_32_pcdi(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_PCDI_32(mc68kcpu); + UINT32 dst = AX(mc68kcpu); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); +} + + +void m68000_base_device_ops::m68k_op_cmpa_32_pcix(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_PCIX_32(mc68kcpu); + UINT32 dst = AX(mc68kcpu); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); +} + + +void m68000_base_device_ops::m68k_op_cmpa_32_i(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_32(mc68kcpu); + UINT32 dst = AX(mc68kcpu); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); +} + + +void m68000_base_device_ops::m68k_op_cmpi_8_d(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_8(mc68kcpu); + UINT32 dst = MASK_OUT_ABOVE_8(DY(mc68kcpu)); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_8(res); +} + + +void m68000_base_device_ops::m68k_op_cmpi_8_ai(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_8(mc68kcpu); + UINT32 dst = OPER_AY_AI_8(mc68kcpu); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_8(res); +} + + +void m68000_base_device_ops::m68k_op_cmpi_8_pi(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_8(mc68kcpu); + UINT32 dst = OPER_AY_PI_8(mc68kcpu); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_8(res); +} + + +void m68000_base_device_ops::m68k_op_cmpi_8_pi7(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_8(mc68kcpu); + UINT32 dst = OPER_A7_PI_8(mc68kcpu); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_8(res); +} + + +void m68000_base_device_ops::m68k_op_cmpi_8_pd(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_8(mc68kcpu); + UINT32 dst = OPER_AY_PD_8(mc68kcpu); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_8(res); +} + + +void m68000_base_device_ops::m68k_op_cmpi_8_pd7(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_8(mc68kcpu); + UINT32 dst = OPER_A7_PD_8(mc68kcpu); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_8(res); +} + + +void m68000_base_device_ops::m68k_op_cmpi_8_di(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_8(mc68kcpu); + UINT32 dst = OPER_AY_DI_8(mc68kcpu); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_8(res); +} + + +void m68000_base_device_ops::m68k_op_cmpi_8_ix(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_8(mc68kcpu); + UINT32 dst = OPER_AY_IX_8(mc68kcpu); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_8(res); +} + + +void m68000_base_device_ops::m68k_op_cmpi_8_aw(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_8(mc68kcpu); + UINT32 dst = OPER_AW_8(mc68kcpu); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_8(res); +} + + +void m68000_base_device_ops::m68k_op_cmpi_8_al(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_8(mc68kcpu); + UINT32 dst = OPER_AL_8(mc68kcpu); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_8(res); +} + + +void m68000_base_device_ops::m68k_op_cmpi_8_pcdi(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 src = OPER_I_8(mc68kcpu); + UINT32 dst = OPER_PCDI_8(mc68kcpu); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_8(res); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_cmpi_8_pcix(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 src = OPER_I_8(mc68kcpu); + UINT32 dst = OPER_PCIX_8(mc68kcpu); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_8(res); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_cmpi_16_d(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_16(mc68kcpu); + UINT32 dst = MASK_OUT_ABOVE_16(DY(mc68kcpu)); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + (mc68kcpu)->v_flag = VFLAG_SUB_16(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_16(res); +} + + +void m68000_base_device_ops::m68k_op_cmpi_16_ai(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_16(mc68kcpu); + UINT32 dst = OPER_AY_AI_16(mc68kcpu); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + (mc68kcpu)->v_flag = VFLAG_SUB_16(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_16(res); +} + + +void m68000_base_device_ops::m68k_op_cmpi_16_pi(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_16(mc68kcpu); + UINT32 dst = OPER_AY_PI_16(mc68kcpu); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + (mc68kcpu)->v_flag = VFLAG_SUB_16(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_16(res); +} + + +void m68000_base_device_ops::m68k_op_cmpi_16_pd(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_16(mc68kcpu); + UINT32 dst = OPER_AY_PD_16(mc68kcpu); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + (mc68kcpu)->v_flag = VFLAG_SUB_16(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_16(res); +} + + +void m68000_base_device_ops::m68k_op_cmpi_16_di(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_16(mc68kcpu); + UINT32 dst = OPER_AY_DI_16(mc68kcpu); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + (mc68kcpu)->v_flag = VFLAG_SUB_16(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_16(res); +} + + +void m68000_base_device_ops::m68k_op_cmpi_16_ix(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_16(mc68kcpu); + UINT32 dst = OPER_AY_IX_16(mc68kcpu); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + (mc68kcpu)->v_flag = VFLAG_SUB_16(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_16(res); +} + + +void m68000_base_device_ops::m68k_op_cmpi_16_aw(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_16(mc68kcpu); + UINT32 dst = OPER_AW_16(mc68kcpu); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + (mc68kcpu)->v_flag = VFLAG_SUB_16(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_16(res); +} + + +void m68000_base_device_ops::m68k_op_cmpi_16_al(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_16(mc68kcpu); + UINT32 dst = OPER_AL_16(mc68kcpu); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + (mc68kcpu)->v_flag = VFLAG_SUB_16(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_16(res); +} + + +void m68000_base_device_ops::m68k_op_cmpi_16_pcdi(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 src = OPER_I_16(mc68kcpu); + UINT32 dst = OPER_PCDI_16(mc68kcpu); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + (mc68kcpu)->v_flag = VFLAG_SUB_16(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_16(res); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_cmpi_16_pcix(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 src = OPER_I_16(mc68kcpu); + UINT32 dst = OPER_PCIX_16(mc68kcpu); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + (mc68kcpu)->v_flag = VFLAG_SUB_16(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_16(res); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_cmpi_32_d(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_32(mc68kcpu); + UINT32 dst = DY(mc68kcpu); + UINT32 res = dst - src; + + if (!(mc68kcpu)->cmpild_instr_callback.isnull()) + ((mc68kcpu)->cmpild_instr_callback)(*(mc68kcpu)->program, (mc68kcpu)->ir & 7, src, 0xffffffff); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); +} + + +void m68000_base_device_ops::m68k_op_cmpi_32_ai(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_32(mc68kcpu); + UINT32 dst = OPER_AY_AI_32(mc68kcpu); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); +} + + +void m68000_base_device_ops::m68k_op_cmpi_32_pi(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_32(mc68kcpu); + UINT32 dst = OPER_AY_PI_32(mc68kcpu); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); +} + + +void m68000_base_device_ops::m68k_op_cmpi_32_pd(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_32(mc68kcpu); + UINT32 dst = OPER_AY_PD_32(mc68kcpu); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); +} + + +void m68000_base_device_ops::m68k_op_cmpi_32_di(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_32(mc68kcpu); + UINT32 dst = OPER_AY_DI_32(mc68kcpu); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); +} + + +void m68000_base_device_ops::m68k_op_cmpi_32_ix(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_32(mc68kcpu); + UINT32 dst = OPER_AY_IX_32(mc68kcpu); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); +} + + +void m68000_base_device_ops::m68k_op_cmpi_32_aw(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_32(mc68kcpu); + UINT32 dst = OPER_AW_32(mc68kcpu); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); +} + + +void m68000_base_device_ops::m68k_op_cmpi_32_al(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_32(mc68kcpu); + UINT32 dst = OPER_AL_32(mc68kcpu); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); +} + + +void m68000_base_device_ops::m68k_op_cmpi_32_pcdi(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 src = OPER_I_32(mc68kcpu); + UINT32 dst = OPER_PCDI_32(mc68kcpu); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_cmpi_32_pcix(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 src = OPER_I_32(mc68kcpu); + UINT32 dst = OPER_PCIX_32(mc68kcpu); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_cmpm_8_ax7(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_AY_PI_8(mc68kcpu); + UINT32 dst = OPER_A7_PI_8(mc68kcpu); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_8(res); +} + + +void m68000_base_device_ops::m68k_op_cmpm_8_ay7(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_A7_PI_8(mc68kcpu); + UINT32 dst = OPER_AX_PI_8(mc68kcpu); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_8(res); +} + + +void m68000_base_device_ops::m68k_op_cmpm_8_axy7(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_A7_PI_8(mc68kcpu); + UINT32 dst = OPER_A7_PI_8(mc68kcpu); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_8(res); +} + + +void m68000_base_device_ops::m68k_op_cmpm_8(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_AY_PI_8(mc68kcpu); + UINT32 dst = OPER_AX_PI_8(mc68kcpu); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_8(res); +} + + +void m68000_base_device_ops::m68k_op_cmpm_16(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_AY_PI_16(mc68kcpu); + UINT32 dst = OPER_AX_PI_16(mc68kcpu); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + (mc68kcpu)->v_flag = VFLAG_SUB_16(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_16(res); +} + + +void m68000_base_device_ops::m68k_op_cmpm_32(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_AY_PI_32(mc68kcpu); + UINT32 dst = OPER_AX_PI_32(mc68kcpu); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); +} + + +void m68000_base_device_ops::m68k_op_cpbcc_32(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + logerror("%s at %08x: called unimplemented instruction %04x (cpbcc)\n", + (mc68kcpu)->tag(), REG_PC(mc68kcpu) - 2, (mc68kcpu)->ir); + return; + } + m68ki_exception_1111(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_cpdbcc_32(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + logerror("%s at %08x: called unimplemented instruction %04x (cpdbcc)\n", + (mc68kcpu)->tag(), REG_PC(mc68kcpu) - 2, (mc68kcpu)->ir); + return; + } + m68ki_exception_1111(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_cpgen_32(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type) && (mc68kcpu->has_fpu || mc68kcpu->has_pmmu)) + { + logerror("%s at %08x: called unimplemented instruction %04x (cpgen)\n", + (mc68kcpu)->tag(), REG_PC(mc68kcpu) - 2, (mc68kcpu)->ir); + return; + } + m68ki_exception_1111(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_cpscc_32(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + logerror("%s at %08x: called unimplemented instruction %04x (cpscc)\n", + (mc68kcpu)->tag(), REG_PC(mc68kcpu) - 2, (mc68kcpu)->ir); + return; + } + m68ki_exception_1111(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_cptrapcc_32(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + logerror("%s at %08x: called unimplemented instruction %04x (cptrapcc)\n", + (mc68kcpu)->tag(), REG_PC(mc68kcpu) - 2, (mc68kcpu)->ir); + return; + } + m68ki_exception_1111(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_ftrapcc_32(m68000_base_device* mc68kcpu) +{ + if((mc68kcpu)->has_fpu) + { + m68881_ftrap(mc68kcpu); + return; + } + m68ki_exception_1111(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_dbt_16(m68000_base_device* mc68kcpu) +{ + REG_PC(mc68kcpu) += 2; +} + + +void m68000_base_device_ops::m68k_op_dbf_16(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_16(*r_dst - 1); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + if(res != 0xffff) + { + UINT32 offset = OPER_I_16(mc68kcpu); + REG_PC(mc68kcpu) -= 2; + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_16((mc68kcpu), offset); + (mc68kcpu)->remaining_cycles -= (mc68kcpu)->cyc_dbcc_f_noexp; + return; + } + REG_PC(mc68kcpu) += 2; + (mc68kcpu)->remaining_cycles -= (mc68kcpu)->cyc_dbcc_f_exp; +} + + +void m68000_base_device_ops::m68k_op_dbhi_16(m68000_base_device* mc68kcpu) +{ + if(COND_NOT_HI(mc68kcpu)) + { + UINT32* r_dst = &DY(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_16(*r_dst - 1); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + if(res != 0xffff) + { + UINT32 offset = OPER_I_16(mc68kcpu); + REG_PC(mc68kcpu) -= 2; + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_16((mc68kcpu), offset); + (mc68kcpu)->remaining_cycles -= (mc68kcpu)->cyc_dbcc_f_noexp; + return; + } + REG_PC(mc68kcpu) += 2; + (mc68kcpu)->remaining_cycles -= (mc68kcpu)->cyc_dbcc_f_exp; + return; + } + REG_PC(mc68kcpu) += 2; +} + + +void m68000_base_device_ops::m68k_op_dbls_16(m68000_base_device* mc68kcpu) +{ + if(COND_NOT_LS(mc68kcpu)) + { + UINT32* r_dst = &DY(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_16(*r_dst - 1); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + if(res != 0xffff) + { + UINT32 offset = OPER_I_16(mc68kcpu); + REG_PC(mc68kcpu) -= 2; + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_16((mc68kcpu), offset); + (mc68kcpu)->remaining_cycles -= (mc68kcpu)->cyc_dbcc_f_noexp; + return; + } + REG_PC(mc68kcpu) += 2; + (mc68kcpu)->remaining_cycles -= (mc68kcpu)->cyc_dbcc_f_exp; + return; + } + REG_PC(mc68kcpu) += 2; +} + + +void m68000_base_device_ops::m68k_op_dbcc_16(m68000_base_device* mc68kcpu) +{ + if(COND_NOT_CC(mc68kcpu)) + { + UINT32* r_dst = &DY(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_16(*r_dst - 1); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + if(res != 0xffff) + { + UINT32 offset = OPER_I_16(mc68kcpu); + REG_PC(mc68kcpu) -= 2; + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_16((mc68kcpu), offset); + (mc68kcpu)->remaining_cycles -= (mc68kcpu)->cyc_dbcc_f_noexp; + return; + } + REG_PC(mc68kcpu) += 2; + (mc68kcpu)->remaining_cycles -= (mc68kcpu)->cyc_dbcc_f_exp; + return; + } + REG_PC(mc68kcpu) += 2; +} + + +void m68000_base_device_ops::m68k_op_dbcs_16(m68000_base_device* mc68kcpu) +{ + if(COND_NOT_CS(mc68kcpu)) + { + UINT32* r_dst = &DY(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_16(*r_dst - 1); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + if(res != 0xffff) + { + UINT32 offset = OPER_I_16(mc68kcpu); + REG_PC(mc68kcpu) -= 2; + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_16((mc68kcpu), offset); + (mc68kcpu)->remaining_cycles -= (mc68kcpu)->cyc_dbcc_f_noexp; + return; + } + REG_PC(mc68kcpu) += 2; + (mc68kcpu)->remaining_cycles -= (mc68kcpu)->cyc_dbcc_f_exp; + return; + } + REG_PC(mc68kcpu) += 2; +} + + +void m68000_base_device_ops::m68k_op_dbne_16(m68000_base_device* mc68kcpu) +{ + if(COND_NOT_NE(mc68kcpu)) + { + UINT32* r_dst = &DY(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_16(*r_dst - 1); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + if(res != 0xffff) + { + UINT32 offset = OPER_I_16(mc68kcpu); + REG_PC(mc68kcpu) -= 2; + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_16((mc68kcpu), offset); + (mc68kcpu)->remaining_cycles -= (mc68kcpu)->cyc_dbcc_f_noexp; + return; + } + REG_PC(mc68kcpu) += 2; + (mc68kcpu)->remaining_cycles -= (mc68kcpu)->cyc_dbcc_f_exp; + return; + } + REG_PC(mc68kcpu) += 2; +} + + +void m68000_base_device_ops::m68k_op_dbeq_16(m68000_base_device* mc68kcpu) +{ + if(COND_NOT_EQ(mc68kcpu)) + { + UINT32* r_dst = &DY(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_16(*r_dst - 1); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + if(res != 0xffff) + { + UINT32 offset = OPER_I_16(mc68kcpu); + REG_PC(mc68kcpu) -= 2; + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_16((mc68kcpu), offset); + (mc68kcpu)->remaining_cycles -= (mc68kcpu)->cyc_dbcc_f_noexp; + return; + } + REG_PC(mc68kcpu) += 2; + (mc68kcpu)->remaining_cycles -= (mc68kcpu)->cyc_dbcc_f_exp; + return; + } + REG_PC(mc68kcpu) += 2; +} + + +void m68000_base_device_ops::m68k_op_dbvc_16(m68000_base_device* mc68kcpu) +{ + if(COND_NOT_VC(mc68kcpu)) + { + UINT32* r_dst = &DY(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_16(*r_dst - 1); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + if(res != 0xffff) + { + UINT32 offset = OPER_I_16(mc68kcpu); + REG_PC(mc68kcpu) -= 2; + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_16((mc68kcpu), offset); + (mc68kcpu)->remaining_cycles -= (mc68kcpu)->cyc_dbcc_f_noexp; + return; + } + REG_PC(mc68kcpu) += 2; + (mc68kcpu)->remaining_cycles -= (mc68kcpu)->cyc_dbcc_f_exp; + return; + } + REG_PC(mc68kcpu) += 2; +} + + +void m68000_base_device_ops::m68k_op_dbvs_16(m68000_base_device* mc68kcpu) +{ + if(COND_NOT_VS(mc68kcpu)) + { + UINT32* r_dst = &DY(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_16(*r_dst - 1); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + if(res != 0xffff) + { + UINT32 offset = OPER_I_16(mc68kcpu); + REG_PC(mc68kcpu) -= 2; + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_16((mc68kcpu), offset); + (mc68kcpu)->remaining_cycles -= (mc68kcpu)->cyc_dbcc_f_noexp; + return; + } + REG_PC(mc68kcpu) += 2; + (mc68kcpu)->remaining_cycles -= (mc68kcpu)->cyc_dbcc_f_exp; + return; + } + REG_PC(mc68kcpu) += 2; +} + + +void m68000_base_device_ops::m68k_op_dbpl_16(m68000_base_device* mc68kcpu) +{ + if(COND_NOT_PL(mc68kcpu)) + { + UINT32* r_dst = &DY(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_16(*r_dst - 1); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + if(res != 0xffff) + { + UINT32 offset = OPER_I_16(mc68kcpu); + REG_PC(mc68kcpu) -= 2; + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_16((mc68kcpu), offset); + (mc68kcpu)->remaining_cycles -= (mc68kcpu)->cyc_dbcc_f_noexp; + return; + } + REG_PC(mc68kcpu) += 2; + (mc68kcpu)->remaining_cycles -= (mc68kcpu)->cyc_dbcc_f_exp; + return; + } + REG_PC(mc68kcpu) += 2; +} + + +void m68000_base_device_ops::m68k_op_dbmi_16(m68000_base_device* mc68kcpu) +{ + if(COND_NOT_MI(mc68kcpu)) + { + UINT32* r_dst = &DY(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_16(*r_dst - 1); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + if(res != 0xffff) + { + UINT32 offset = OPER_I_16(mc68kcpu); + REG_PC(mc68kcpu) -= 2; + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_16((mc68kcpu), offset); + (mc68kcpu)->remaining_cycles -= (mc68kcpu)->cyc_dbcc_f_noexp; + return; + } + REG_PC(mc68kcpu) += 2; + (mc68kcpu)->remaining_cycles -= (mc68kcpu)->cyc_dbcc_f_exp; + return; + } + REG_PC(mc68kcpu) += 2; +} + + +void m68000_base_device_ops::m68k_op_dbge_16(m68000_base_device* mc68kcpu) +{ + if(COND_NOT_GE(mc68kcpu)) + { + UINT32* r_dst = &DY(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_16(*r_dst - 1); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + if(res != 0xffff) + { + UINT32 offset = OPER_I_16(mc68kcpu); + REG_PC(mc68kcpu) -= 2; + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_16((mc68kcpu), offset); + (mc68kcpu)->remaining_cycles -= (mc68kcpu)->cyc_dbcc_f_noexp; + return; + } + REG_PC(mc68kcpu) += 2; + (mc68kcpu)->remaining_cycles -= (mc68kcpu)->cyc_dbcc_f_exp; + return; + } + REG_PC(mc68kcpu) += 2; +} + + +void m68000_base_device_ops::m68k_op_dblt_16(m68000_base_device* mc68kcpu) +{ + if(COND_NOT_LT(mc68kcpu)) + { + UINT32* r_dst = &DY(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_16(*r_dst - 1); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + if(res != 0xffff) + { + UINT32 offset = OPER_I_16(mc68kcpu); + REG_PC(mc68kcpu) -= 2; + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_16((mc68kcpu), offset); + (mc68kcpu)->remaining_cycles -= (mc68kcpu)->cyc_dbcc_f_noexp; + return; + } + REG_PC(mc68kcpu) += 2; + (mc68kcpu)->remaining_cycles -= (mc68kcpu)->cyc_dbcc_f_exp; + return; + } + REG_PC(mc68kcpu) += 2; +} + + +void m68000_base_device_ops::m68k_op_dbgt_16(m68000_base_device* mc68kcpu) +{ + if(COND_NOT_GT(mc68kcpu)) + { + UINT32* r_dst = &DY(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_16(*r_dst - 1); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + if(res != 0xffff) + { + UINT32 offset = OPER_I_16(mc68kcpu); + REG_PC(mc68kcpu) -= 2; + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_16((mc68kcpu), offset); + (mc68kcpu)->remaining_cycles -= (mc68kcpu)->cyc_dbcc_f_noexp; + return; + } + REG_PC(mc68kcpu) += 2; + (mc68kcpu)->remaining_cycles -= (mc68kcpu)->cyc_dbcc_f_exp; + return; + } + REG_PC(mc68kcpu) += 2; +} + + +void m68000_base_device_ops::m68k_op_dble_16(m68000_base_device* mc68kcpu) +{ + if(COND_NOT_LE(mc68kcpu)) + { + UINT32* r_dst = &DY(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_16(*r_dst - 1); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + if(res != 0xffff) + { + UINT32 offset = OPER_I_16(mc68kcpu); + REG_PC(mc68kcpu) -= 2; + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_branch_16((mc68kcpu), offset); + (mc68kcpu)->remaining_cycles -= (mc68kcpu)->cyc_dbcc_f_noexp; + return; + } + REG_PC(mc68kcpu) += 2; + (mc68kcpu)->remaining_cycles -= (mc68kcpu)->cyc_dbcc_f_exp; + return; + } + REG_PC(mc68kcpu) += 2; +} + + +void m68000_base_device_ops::m68k_op_divs_16_d(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + INT32 src = MAKE_INT_16(DY(mc68kcpu)); + INT32 quotient; + INT32 remainder; + + if(src != 0) + { + if((UINT32)*r_dst == 0x80000000 && src == -1) + { + (mc68kcpu)->not_z_flag = 0; + (mc68kcpu)->n_flag = NFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + *r_dst = 0; + return; + } + + quotient = MAKE_INT_32(*r_dst) / src; + remainder = MAKE_INT_32(*r_dst) % src; + + if(quotient == MAKE_INT_16(quotient)) + { + (mc68kcpu)->not_z_flag = quotient; + (mc68kcpu)->n_flag = NFLAG_16(quotient); + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + *r_dst = MASK_OUT_ABOVE_32(MASK_OUT_ABOVE_16(quotient) | (remainder << 16)); + return; + } + (mc68kcpu)->v_flag = VFLAG_SET; + return; + } + m68ki_exception_trap((mc68kcpu), EXCEPTION_ZERO_DIVIDE); +} + + +void m68000_base_device_ops::m68k_op_divs_16_ai(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + INT32 src = MAKE_INT_16(OPER_AY_AI_16(mc68kcpu)); + INT32 quotient; + INT32 remainder; + + if(src != 0) + { + if((UINT32)*r_dst == 0x80000000 && src == -1) + { + (mc68kcpu)->not_z_flag = 0; + (mc68kcpu)->n_flag = NFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + *r_dst = 0; + return; + } + + quotient = MAKE_INT_32(*r_dst) / src; + remainder = MAKE_INT_32(*r_dst) % src; + + if(quotient == MAKE_INT_16(quotient)) + { + (mc68kcpu)->not_z_flag = quotient; + (mc68kcpu)->n_flag = NFLAG_16(quotient); + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + *r_dst = MASK_OUT_ABOVE_32(MASK_OUT_ABOVE_16(quotient) | (remainder << 16)); + return; + } + (mc68kcpu)->v_flag = VFLAG_SET; + return; + } + m68ki_exception_trap((mc68kcpu), EXCEPTION_ZERO_DIVIDE); +} + + +void m68000_base_device_ops::m68k_op_divs_16_pi(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + INT32 src = MAKE_INT_16(OPER_AY_PI_16(mc68kcpu)); + INT32 quotient; + INT32 remainder; + + if(src != 0) + { + if((UINT32)*r_dst == 0x80000000 && src == -1) + { + (mc68kcpu)->not_z_flag = 0; + (mc68kcpu)->n_flag = NFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + *r_dst = 0; + return; + } + + quotient = MAKE_INT_32(*r_dst) / src; + remainder = MAKE_INT_32(*r_dst) % src; + + if(quotient == MAKE_INT_16(quotient)) + { + (mc68kcpu)->not_z_flag = quotient; + (mc68kcpu)->n_flag = NFLAG_16(quotient); + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + *r_dst = MASK_OUT_ABOVE_32(MASK_OUT_ABOVE_16(quotient) | (remainder << 16)); + return; + } + (mc68kcpu)->v_flag = VFLAG_SET; + return; + } + m68ki_exception_trap((mc68kcpu), EXCEPTION_ZERO_DIVIDE); +} + + +void m68000_base_device_ops::m68k_op_divs_16_pd(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + INT32 src = MAKE_INT_16(OPER_AY_PD_16(mc68kcpu)); + INT32 quotient; + INT32 remainder; + + if(src != 0) + { + if((UINT32)*r_dst == 0x80000000 && src == -1) + { + (mc68kcpu)->not_z_flag = 0; + (mc68kcpu)->n_flag = NFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + *r_dst = 0; + return; + } + + quotient = MAKE_INT_32(*r_dst) / src; + remainder = MAKE_INT_32(*r_dst) % src; + + if(quotient == MAKE_INT_16(quotient)) + { + (mc68kcpu)->not_z_flag = quotient; + (mc68kcpu)->n_flag = NFLAG_16(quotient); + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + *r_dst = MASK_OUT_ABOVE_32(MASK_OUT_ABOVE_16(quotient) | (remainder << 16)); + return; + } + (mc68kcpu)->v_flag = VFLAG_SET; + return; + } + m68ki_exception_trap((mc68kcpu), EXCEPTION_ZERO_DIVIDE); +} + + +void m68000_base_device_ops::m68k_op_divs_16_di(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + INT32 src = MAKE_INT_16(OPER_AY_DI_16(mc68kcpu)); + INT32 quotient; + INT32 remainder; + + if(src != 0) + { + if((UINT32)*r_dst == 0x80000000 && src == -1) + { + (mc68kcpu)->not_z_flag = 0; + (mc68kcpu)->n_flag = NFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + *r_dst = 0; + return; + } + + quotient = MAKE_INT_32(*r_dst) / src; + remainder = MAKE_INT_32(*r_dst) % src; + + if(quotient == MAKE_INT_16(quotient)) + { + (mc68kcpu)->not_z_flag = quotient; + (mc68kcpu)->n_flag = NFLAG_16(quotient); + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + *r_dst = MASK_OUT_ABOVE_32(MASK_OUT_ABOVE_16(quotient) | (remainder << 16)); + return; + } + (mc68kcpu)->v_flag = VFLAG_SET; + return; + } + m68ki_exception_trap((mc68kcpu), EXCEPTION_ZERO_DIVIDE); +} + + +void m68000_base_device_ops::m68k_op_divs_16_ix(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + INT32 src = MAKE_INT_16(OPER_AY_IX_16(mc68kcpu)); + INT32 quotient; + INT32 remainder; + + if(src != 0) + { + if((UINT32)*r_dst == 0x80000000 && src == -1) + { + (mc68kcpu)->not_z_flag = 0; + (mc68kcpu)->n_flag = NFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + *r_dst = 0; + return; + } + + quotient = MAKE_INT_32(*r_dst) / src; + remainder = MAKE_INT_32(*r_dst) % src; + + if(quotient == MAKE_INT_16(quotient)) + { + (mc68kcpu)->not_z_flag = quotient; + (mc68kcpu)->n_flag = NFLAG_16(quotient); + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + *r_dst = MASK_OUT_ABOVE_32(MASK_OUT_ABOVE_16(quotient) | (remainder << 16)); + return; + } + (mc68kcpu)->v_flag = VFLAG_SET; + return; + } + m68ki_exception_trap((mc68kcpu), EXCEPTION_ZERO_DIVIDE); +} + + +void m68000_base_device_ops::m68k_op_divs_16_aw(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + INT32 src = MAKE_INT_16(OPER_AW_16(mc68kcpu)); + INT32 quotient; + INT32 remainder; + + if(src != 0) + { + if((UINT32)*r_dst == 0x80000000 && src == -1) + { + (mc68kcpu)->not_z_flag = 0; + (mc68kcpu)->n_flag = NFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + *r_dst = 0; + return; + } + + quotient = MAKE_INT_32(*r_dst) / src; + remainder = MAKE_INT_32(*r_dst) % src; + + if(quotient == MAKE_INT_16(quotient)) + { + (mc68kcpu)->not_z_flag = quotient; + (mc68kcpu)->n_flag = NFLAG_16(quotient); + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + *r_dst = MASK_OUT_ABOVE_32(MASK_OUT_ABOVE_16(quotient) | (remainder << 16)); + return; + } + (mc68kcpu)->v_flag = VFLAG_SET; + return; + } + m68ki_exception_trap((mc68kcpu), EXCEPTION_ZERO_DIVIDE); +} + + +void m68000_base_device_ops::m68k_op_divs_16_al(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + INT32 src = MAKE_INT_16(OPER_AL_16(mc68kcpu)); + INT32 quotient; + INT32 remainder; + + if(src != 0) + { + if((UINT32)*r_dst == 0x80000000 && src == -1) + { + (mc68kcpu)->not_z_flag = 0; + (mc68kcpu)->n_flag = NFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + *r_dst = 0; + return; + } + + quotient = MAKE_INT_32(*r_dst) / src; + remainder = MAKE_INT_32(*r_dst) % src; + + if(quotient == MAKE_INT_16(quotient)) + { + (mc68kcpu)->not_z_flag = quotient; + (mc68kcpu)->n_flag = NFLAG_16(quotient); + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + *r_dst = MASK_OUT_ABOVE_32(MASK_OUT_ABOVE_16(quotient) | (remainder << 16)); + return; + } + (mc68kcpu)->v_flag = VFLAG_SET; + return; + } + m68ki_exception_trap((mc68kcpu), EXCEPTION_ZERO_DIVIDE); +} + + +void m68000_base_device_ops::m68k_op_divs_16_pcdi(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + INT32 src = MAKE_INT_16(OPER_PCDI_16(mc68kcpu)); + INT32 quotient; + INT32 remainder; + + if(src != 0) + { + if((UINT32)*r_dst == 0x80000000 && src == -1) + { + (mc68kcpu)->not_z_flag = 0; + (mc68kcpu)->n_flag = NFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + *r_dst = 0; + return; + } + + quotient = MAKE_INT_32(*r_dst) / src; + remainder = MAKE_INT_32(*r_dst) % src; + + if(quotient == MAKE_INT_16(quotient)) + { + (mc68kcpu)->not_z_flag = quotient; + (mc68kcpu)->n_flag = NFLAG_16(quotient); + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + *r_dst = MASK_OUT_ABOVE_32(MASK_OUT_ABOVE_16(quotient) | (remainder << 16)); + return; + } + (mc68kcpu)->v_flag = VFLAG_SET; + return; + } + m68ki_exception_trap((mc68kcpu), EXCEPTION_ZERO_DIVIDE); +} + + +void m68000_base_device_ops::m68k_op_divs_16_pcix(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + INT32 src = MAKE_INT_16(OPER_PCIX_16(mc68kcpu)); + INT32 quotient; + INT32 remainder; + + if(src != 0) + { + if((UINT32)*r_dst == 0x80000000 && src == -1) + { + (mc68kcpu)->not_z_flag = 0; + (mc68kcpu)->n_flag = NFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + *r_dst = 0; + return; + } + + quotient = MAKE_INT_32(*r_dst) / src; + remainder = MAKE_INT_32(*r_dst) % src; + + if(quotient == MAKE_INT_16(quotient)) + { + (mc68kcpu)->not_z_flag = quotient; + (mc68kcpu)->n_flag = NFLAG_16(quotient); + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + *r_dst = MASK_OUT_ABOVE_32(MASK_OUT_ABOVE_16(quotient) | (remainder << 16)); + return; + } + (mc68kcpu)->v_flag = VFLAG_SET; + return; + } + m68ki_exception_trap((mc68kcpu), EXCEPTION_ZERO_DIVIDE); +} + + +void m68000_base_device_ops::m68k_op_divs_16_i(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + INT32 src = MAKE_INT_16(OPER_I_16(mc68kcpu)); + INT32 quotient; + INT32 remainder; + + if(src != 0) + { + if((UINT32)*r_dst == 0x80000000 && src == -1) + { + (mc68kcpu)->not_z_flag = 0; + (mc68kcpu)->n_flag = NFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + *r_dst = 0; + return; + } + + quotient = MAKE_INT_32(*r_dst) / src; + remainder = MAKE_INT_32(*r_dst) % src; + + if(quotient == MAKE_INT_16(quotient)) + { + (mc68kcpu)->not_z_flag = quotient; + (mc68kcpu)->n_flag = NFLAG_16(quotient); + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + *r_dst = MASK_OUT_ABOVE_32(MASK_OUT_ABOVE_16(quotient) | (remainder << 16)); + return; + } + (mc68kcpu)->v_flag = VFLAG_SET; + return; + } + m68ki_exception_trap((mc68kcpu), EXCEPTION_ZERO_DIVIDE); +} + + +void m68000_base_device_ops::m68k_op_divu_16_d(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = MASK_OUT_ABOVE_16(DY(mc68kcpu)); + + if(src != 0) + { + UINT32 quotient = *r_dst / src; + UINT32 remainder = *r_dst % src; + + if(quotient < 0x10000) + { + (mc68kcpu)->not_z_flag = quotient; + (mc68kcpu)->n_flag = NFLAG_16(quotient); + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + *r_dst = MASK_OUT_ABOVE_32(MASK_OUT_ABOVE_16(quotient) | (remainder << 16)); + return; + } + (mc68kcpu)->v_flag = VFLAG_SET; + return; + } + m68ki_exception_trap((mc68kcpu), EXCEPTION_ZERO_DIVIDE); +} + + +void m68000_base_device_ops::m68k_op_divu_16_ai(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = OPER_AY_AI_16(mc68kcpu); + + if(src != 0) + { + UINT32 quotient = *r_dst / src; + UINT32 remainder = *r_dst % src; + + if(quotient < 0x10000) + { + (mc68kcpu)->not_z_flag = quotient; + (mc68kcpu)->n_flag = NFLAG_16(quotient); + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + *r_dst = MASK_OUT_ABOVE_32(MASK_OUT_ABOVE_16(quotient) | (remainder << 16)); + return; + } + (mc68kcpu)->v_flag = VFLAG_SET; + return; + } + m68ki_exception_trap((mc68kcpu), EXCEPTION_ZERO_DIVIDE); +} + + +void m68000_base_device_ops::m68k_op_divu_16_pi(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = OPER_AY_PI_16(mc68kcpu); + + if(src != 0) + { + UINT32 quotient = *r_dst / src; + UINT32 remainder = *r_dst % src; + + if(quotient < 0x10000) + { + (mc68kcpu)->not_z_flag = quotient; + (mc68kcpu)->n_flag = NFLAG_16(quotient); + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + *r_dst = MASK_OUT_ABOVE_32(MASK_OUT_ABOVE_16(quotient) | (remainder << 16)); + return; + } + (mc68kcpu)->v_flag = VFLAG_SET; + return; + } + m68ki_exception_trap((mc68kcpu), EXCEPTION_ZERO_DIVIDE); +} + + +void m68000_base_device_ops::m68k_op_divu_16_pd(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = OPER_AY_PD_16(mc68kcpu); + + if(src != 0) + { + UINT32 quotient = *r_dst / src; + UINT32 remainder = *r_dst % src; + + if(quotient < 0x10000) + { + (mc68kcpu)->not_z_flag = quotient; + (mc68kcpu)->n_flag = NFLAG_16(quotient); + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + *r_dst = MASK_OUT_ABOVE_32(MASK_OUT_ABOVE_16(quotient) | (remainder << 16)); + return; + } + (mc68kcpu)->v_flag = VFLAG_SET; + return; + } + m68ki_exception_trap((mc68kcpu), EXCEPTION_ZERO_DIVIDE); +} + + +void m68000_base_device_ops::m68k_op_divu_16_di(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = OPER_AY_DI_16(mc68kcpu); + + if(src != 0) + { + UINT32 quotient = *r_dst / src; + UINT32 remainder = *r_dst % src; + + if(quotient < 0x10000) + { + (mc68kcpu)->not_z_flag = quotient; + (mc68kcpu)->n_flag = NFLAG_16(quotient); + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + *r_dst = MASK_OUT_ABOVE_32(MASK_OUT_ABOVE_16(quotient) | (remainder << 16)); + return; + } + (mc68kcpu)->v_flag = VFLAG_SET; + return; + } + m68ki_exception_trap((mc68kcpu), EXCEPTION_ZERO_DIVIDE); +} + + +void m68000_base_device_ops::m68k_op_divu_16_ix(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = OPER_AY_IX_16(mc68kcpu); + + if(src != 0) + { + UINT32 quotient = *r_dst / src; + UINT32 remainder = *r_dst % src; + + if(quotient < 0x10000) + { + (mc68kcpu)->not_z_flag = quotient; + (mc68kcpu)->n_flag = NFLAG_16(quotient); + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + *r_dst = MASK_OUT_ABOVE_32(MASK_OUT_ABOVE_16(quotient) | (remainder << 16)); + return; + } + (mc68kcpu)->v_flag = VFLAG_SET; + return; + } + m68ki_exception_trap((mc68kcpu), EXCEPTION_ZERO_DIVIDE); +} + + +void m68000_base_device_ops::m68k_op_divu_16_aw(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = OPER_AW_16(mc68kcpu); + + if(src != 0) + { + UINT32 quotient = *r_dst / src; + UINT32 remainder = *r_dst % src; + + if(quotient < 0x10000) + { + (mc68kcpu)->not_z_flag = quotient; + (mc68kcpu)->n_flag = NFLAG_16(quotient); + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + *r_dst = MASK_OUT_ABOVE_32(MASK_OUT_ABOVE_16(quotient) | (remainder << 16)); + return; + } + (mc68kcpu)->v_flag = VFLAG_SET; + return; + } + m68ki_exception_trap((mc68kcpu), EXCEPTION_ZERO_DIVIDE); +} + + +void m68000_base_device_ops::m68k_op_divu_16_al(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = OPER_AL_16(mc68kcpu); + + if(src != 0) + { + UINT32 quotient = *r_dst / src; + UINT32 remainder = *r_dst % src; + + if(quotient < 0x10000) + { + (mc68kcpu)->not_z_flag = quotient; + (mc68kcpu)->n_flag = NFLAG_16(quotient); + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + *r_dst = MASK_OUT_ABOVE_32(MASK_OUT_ABOVE_16(quotient) | (remainder << 16)); + return; + } + (mc68kcpu)->v_flag = VFLAG_SET; + return; + } + m68ki_exception_trap((mc68kcpu), EXCEPTION_ZERO_DIVIDE); +} + + +void m68000_base_device_ops::m68k_op_divu_16_pcdi(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = OPER_PCDI_16(mc68kcpu); + + if(src != 0) + { + UINT32 quotient = *r_dst / src; + UINT32 remainder = *r_dst % src; + + if(quotient < 0x10000) + { + (mc68kcpu)->not_z_flag = quotient; + (mc68kcpu)->n_flag = NFLAG_16(quotient); + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + *r_dst = MASK_OUT_ABOVE_32(MASK_OUT_ABOVE_16(quotient) | (remainder << 16)); + return; + } + (mc68kcpu)->v_flag = VFLAG_SET; + return; + } + m68ki_exception_trap((mc68kcpu), EXCEPTION_ZERO_DIVIDE); +} + + +void m68000_base_device_ops::m68k_op_divu_16_pcix(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = OPER_PCIX_16(mc68kcpu); + + if(src != 0) + { + UINT32 quotient = *r_dst / src; + UINT32 remainder = *r_dst % src; + + if(quotient < 0x10000) + { + (mc68kcpu)->not_z_flag = quotient; + (mc68kcpu)->n_flag = NFLAG_16(quotient); + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + *r_dst = MASK_OUT_ABOVE_32(MASK_OUT_ABOVE_16(quotient) | (remainder << 16)); + return; + } + (mc68kcpu)->v_flag = VFLAG_SET; + return; + } + m68ki_exception_trap((mc68kcpu), EXCEPTION_ZERO_DIVIDE); +} + + +void m68000_base_device_ops::m68k_op_divu_16_i(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = OPER_I_16(mc68kcpu); + + if(src != 0) + { + UINT32 quotient = *r_dst / src; + UINT32 remainder = *r_dst % src; + + if(quotient < 0x10000) + { + (mc68kcpu)->not_z_flag = quotient; + (mc68kcpu)->n_flag = NFLAG_16(quotient); + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + *r_dst = MASK_OUT_ABOVE_32(MASK_OUT_ABOVE_16(quotient) | (remainder << 16)); + return; + } + (mc68kcpu)->v_flag = VFLAG_SET; + return; + } + m68ki_exception_trap((mc68kcpu), EXCEPTION_ZERO_DIVIDE); +} + + +void m68000_base_device_ops::m68k_op_divl_32_d(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT64 divisor = DY(mc68kcpu); + UINT64 dividend = 0; + UINT64 quotient = 0; + UINT64 remainder = 0; + + if(divisor != 0) + { + if(BIT_A(word2)) /* 64 bit */ + { + dividend = REG_D(mc68kcpu)[word2 & 7]; + dividend <<= 32; + dividend |= REG_D(mc68kcpu)[(word2 >> 12) & 7]; + + if(BIT_B(word2)) /* signed */ + { + quotient = (UINT64)((INT64)dividend / (INT64)((INT32)divisor)); + remainder = (UINT64)((INT64)dividend % (INT64)((INT32)divisor)); + if((INT64)quotient != (INT64)((INT32)quotient)) + { + (mc68kcpu)->v_flag = VFLAG_SET; + return; + } + } + else /* unsigned */ + { + quotient = dividend / divisor; + if(quotient > 0xffffffff) + { + (mc68kcpu)->v_flag = VFLAG_SET; + return; + } + remainder = dividend % divisor; + } + } + else /* 32 bit */ + { + dividend = REG_D(mc68kcpu)[(word2 >> 12) & 7]; + if(BIT_B(word2)) /* signed */ + { + quotient = (UINT64)((INT64)((INT32)dividend) / (INT64)((INT32)divisor)); + remainder = (UINT64)((INT64)((INT32)dividend) % (INT64)((INT32)divisor)); + } + else /* unsigned */ + { + quotient = dividend / divisor; + remainder = dividend % divisor; + } + } + + REG_D(mc68kcpu)[word2 & 7] = remainder; + REG_D(mc68kcpu)[(word2 >> 12) & 7] = quotient; + + (mc68kcpu)->n_flag = NFLAG_32(quotient); + (mc68kcpu)->not_z_flag = quotient; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + return; + } + m68ki_exception_trap((mc68kcpu), EXCEPTION_ZERO_DIVIDE); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_divl_32_ai(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT64 divisor = OPER_AY_AI_32(mc68kcpu); + UINT64 dividend = 0; + UINT64 quotient = 0; + UINT64 remainder = 0; + + if(divisor != 0) + { + if(BIT_A(word2)) /* 64 bit */ + { + dividend = REG_D(mc68kcpu)[word2 & 7]; + dividend <<= 32; + dividend |= REG_D(mc68kcpu)[(word2 >> 12) & 7]; + + if(BIT_B(word2)) /* signed */ + { + quotient = (UINT64)((INT64)dividend / (INT64)((INT32)divisor)); + remainder = (UINT64)((INT64)dividend % (INT64)((INT32)divisor)); + if((INT64)quotient != (INT64)((INT32)quotient)) + { + (mc68kcpu)->v_flag = VFLAG_SET; + return; + } + } + else /* unsigned */ + { + quotient = dividend / divisor; + if(quotient > 0xffffffff) + { + (mc68kcpu)->v_flag = VFLAG_SET; + return; + } + remainder = dividend % divisor; + } + } + else /* 32 bit */ + { + dividend = REG_D(mc68kcpu)[(word2 >> 12) & 7]; + if(BIT_B(word2)) /* signed */ + { + quotient = (UINT64)((INT64)((INT32)dividend) / (INT64)((INT32)divisor)); + remainder = (UINT64)((INT64)((INT32)dividend) % (INT64)((INT32)divisor)); + } + else /* unsigned */ + { + quotient = dividend / divisor; + remainder = dividend % divisor; + } + } + + REG_D(mc68kcpu)[word2 & 7] = remainder; + REG_D(mc68kcpu)[(word2 >> 12) & 7] = quotient; + + (mc68kcpu)->n_flag = NFLAG_32(quotient); + (mc68kcpu)->not_z_flag = quotient; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + return; + } + m68ki_exception_trap((mc68kcpu), EXCEPTION_ZERO_DIVIDE); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_divl_32_pi(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT64 divisor = OPER_AY_PI_32(mc68kcpu); + UINT64 dividend = 0; + UINT64 quotient = 0; + UINT64 remainder = 0; + + if(divisor != 0) + { + if(BIT_A(word2)) /* 64 bit */ + { + dividend = REG_D(mc68kcpu)[word2 & 7]; + dividend <<= 32; + dividend |= REG_D(mc68kcpu)[(word2 >> 12) & 7]; + + if(BIT_B(word2)) /* signed */ + { + quotient = (UINT64)((INT64)dividend / (INT64)((INT32)divisor)); + remainder = (UINT64)((INT64)dividend % (INT64)((INT32)divisor)); + if((INT64)quotient != (INT64)((INT32)quotient)) + { + (mc68kcpu)->v_flag = VFLAG_SET; + return; + } + } + else /* unsigned */ + { + quotient = dividend / divisor; + if(quotient > 0xffffffff) + { + (mc68kcpu)->v_flag = VFLAG_SET; + return; + } + remainder = dividend % divisor; + } + } + else /* 32 bit */ + { + dividend = REG_D(mc68kcpu)[(word2 >> 12) & 7]; + if(BIT_B(word2)) /* signed */ + { + quotient = (UINT64)((INT64)((INT32)dividend) / (INT64)((INT32)divisor)); + remainder = (UINT64)((INT64)((INT32)dividend) % (INT64)((INT32)divisor)); + } + else /* unsigned */ + { + quotient = dividend / divisor; + remainder = dividend % divisor; + } + } + + REG_D(mc68kcpu)[word2 & 7] = remainder; + REG_D(mc68kcpu)[(word2 >> 12) & 7] = quotient; + + (mc68kcpu)->n_flag = NFLAG_32(quotient); + (mc68kcpu)->not_z_flag = quotient; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + return; + } + m68ki_exception_trap((mc68kcpu), EXCEPTION_ZERO_DIVIDE); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_divl_32_pd(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT64 divisor = OPER_AY_PD_32(mc68kcpu); + UINT64 dividend = 0; + UINT64 quotient = 0; + UINT64 remainder = 0; + + if(divisor != 0) + { + if(BIT_A(word2)) /* 64 bit */ + { + dividend = REG_D(mc68kcpu)[word2 & 7]; + dividend <<= 32; + dividend |= REG_D(mc68kcpu)[(word2 >> 12) & 7]; + + if(BIT_B(word2)) /* signed */ + { + quotient = (UINT64)((INT64)dividend / (INT64)((INT32)divisor)); + remainder = (UINT64)((INT64)dividend % (INT64)((INT32)divisor)); + if((INT64)quotient != (INT64)((INT32)quotient)) + { + (mc68kcpu)->v_flag = VFLAG_SET; + return; + } + } + else /* unsigned */ + { + quotient = dividend / divisor; + if(quotient > 0xffffffff) + { + (mc68kcpu)->v_flag = VFLAG_SET; + return; + } + remainder = dividend % divisor; + } + } + else /* 32 bit */ + { + dividend = REG_D(mc68kcpu)[(word2 >> 12) & 7]; + if(BIT_B(word2)) /* signed */ + { + quotient = (UINT64)((INT64)((INT32)dividend) / (INT64)((INT32)divisor)); + remainder = (UINT64)((INT64)((INT32)dividend) % (INT64)((INT32)divisor)); + } + else /* unsigned */ + { + quotient = dividend / divisor; + remainder = dividend % divisor; + } + } + + REG_D(mc68kcpu)[word2 & 7] = remainder; + REG_D(mc68kcpu)[(word2 >> 12) & 7] = quotient; + + (mc68kcpu)->n_flag = NFLAG_32(quotient); + (mc68kcpu)->not_z_flag = quotient; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + return; + } + m68ki_exception_trap((mc68kcpu), EXCEPTION_ZERO_DIVIDE); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_divl_32_di(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT64 divisor = OPER_AY_DI_32(mc68kcpu); + UINT64 dividend = 0; + UINT64 quotient = 0; + UINT64 remainder = 0; + + if(divisor != 0) + { + if(BIT_A(word2)) /* 64 bit */ + { + dividend = REG_D(mc68kcpu)[word2 & 7]; + dividend <<= 32; + dividend |= REG_D(mc68kcpu)[(word2 >> 12) & 7]; + + if(BIT_B(word2)) /* signed */ + { + quotient = (UINT64)((INT64)dividend / (INT64)((INT32)divisor)); + remainder = (UINT64)((INT64)dividend % (INT64)((INT32)divisor)); + if((INT64)quotient != (INT64)((INT32)quotient)) + { + (mc68kcpu)->v_flag = VFLAG_SET; + return; + } + } + else /* unsigned */ + { + quotient = dividend / divisor; + if(quotient > 0xffffffff) + { + (mc68kcpu)->v_flag = VFLAG_SET; + return; + } + remainder = dividend % divisor; + } + } + else /* 32 bit */ + { + dividend = REG_D(mc68kcpu)[(word2 >> 12) & 7]; + if(BIT_B(word2)) /* signed */ + { + quotient = (UINT64)((INT64)((INT32)dividend) / (INT64)((INT32)divisor)); + remainder = (UINT64)((INT64)((INT32)dividend) % (INT64)((INT32)divisor)); + } + else /* unsigned */ + { + quotient = dividend / divisor; + remainder = dividend % divisor; + } + } + + REG_D(mc68kcpu)[word2 & 7] = remainder; + REG_D(mc68kcpu)[(word2 >> 12) & 7] = quotient; + + (mc68kcpu)->n_flag = NFLAG_32(quotient); + (mc68kcpu)->not_z_flag = quotient; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + return; + } + m68ki_exception_trap((mc68kcpu), EXCEPTION_ZERO_DIVIDE); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_divl_32_ix(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT64 divisor = OPER_AY_IX_32(mc68kcpu); + UINT64 dividend = 0; + UINT64 quotient = 0; + UINT64 remainder = 0; + + if(divisor != 0) + { + if(BIT_A(word2)) /* 64 bit */ + { + dividend = REG_D(mc68kcpu)[word2 & 7]; + dividend <<= 32; + dividend |= REG_D(mc68kcpu)[(word2 >> 12) & 7]; + + if(BIT_B(word2)) /* signed */ + { + quotient = (UINT64)((INT64)dividend / (INT64)((INT32)divisor)); + remainder = (UINT64)((INT64)dividend % (INT64)((INT32)divisor)); + if((INT64)quotient != (INT64)((INT32)quotient)) + { + (mc68kcpu)->v_flag = VFLAG_SET; + return; + } + } + else /* unsigned */ + { + quotient = dividend / divisor; + if(quotient > 0xffffffff) + { + (mc68kcpu)->v_flag = VFLAG_SET; + return; + } + remainder = dividend % divisor; + } + } + else /* 32 bit */ + { + dividend = REG_D(mc68kcpu)[(word2 >> 12) & 7]; + if(BIT_B(word2)) /* signed */ + { + quotient = (UINT64)((INT64)((INT32)dividend) / (INT64)((INT32)divisor)); + remainder = (UINT64)((INT64)((INT32)dividend) % (INT64)((INT32)divisor)); + } + else /* unsigned */ + { + quotient = dividend / divisor; + remainder = dividend % divisor; + } + } + + REG_D(mc68kcpu)[word2 & 7] = remainder; + REG_D(mc68kcpu)[(word2 >> 12) & 7] = quotient; + + (mc68kcpu)->n_flag = NFLAG_32(quotient); + (mc68kcpu)->not_z_flag = quotient; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + return; + } + m68ki_exception_trap((mc68kcpu), EXCEPTION_ZERO_DIVIDE); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_divl_32_aw(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT64 divisor = OPER_AW_32(mc68kcpu); + UINT64 dividend = 0; + UINT64 quotient = 0; + UINT64 remainder = 0; + + if(divisor != 0) + { + if(BIT_A(word2)) /* 64 bit */ + { + dividend = REG_D(mc68kcpu)[word2 & 7]; + dividend <<= 32; + dividend |= REG_D(mc68kcpu)[(word2 >> 12) & 7]; + + if(BIT_B(word2)) /* signed */ + { + quotient = (UINT64)((INT64)dividend / (INT64)((INT32)divisor)); + remainder = (UINT64)((INT64)dividend % (INT64)((INT32)divisor)); + if((INT64)quotient != (INT64)((INT32)quotient)) + { + (mc68kcpu)->v_flag = VFLAG_SET; + return; + } + } + else /* unsigned */ + { + quotient = dividend / divisor; + if(quotient > 0xffffffff) + { + (mc68kcpu)->v_flag = VFLAG_SET; + return; + } + remainder = dividend % divisor; + } + } + else /* 32 bit */ + { + dividend = REG_D(mc68kcpu)[(word2 >> 12) & 7]; + if(BIT_B(word2)) /* signed */ + { + quotient = (UINT64)((INT64)((INT32)dividend) / (INT64)((INT32)divisor)); + remainder = (UINT64)((INT64)((INT32)dividend) % (INT64)((INT32)divisor)); + } + else /* unsigned */ + { + quotient = dividend / divisor; + remainder = dividend % divisor; + } + } + + REG_D(mc68kcpu)[word2 & 7] = remainder; + REG_D(mc68kcpu)[(word2 >> 12) & 7] = quotient; + + (mc68kcpu)->n_flag = NFLAG_32(quotient); + (mc68kcpu)->not_z_flag = quotient; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + return; + } + m68ki_exception_trap((mc68kcpu), EXCEPTION_ZERO_DIVIDE); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_divl_32_al(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT64 divisor = OPER_AL_32(mc68kcpu); + UINT64 dividend = 0; + UINT64 quotient = 0; + UINT64 remainder = 0; + + if(divisor != 0) + { + if(BIT_A(word2)) /* 64 bit */ + { + dividend = REG_D(mc68kcpu)[word2 & 7]; + dividend <<= 32; + dividend |= REG_D(mc68kcpu)[(word2 >> 12) & 7]; + + if(BIT_B(word2)) /* signed */ + { + quotient = (UINT64)((INT64)dividend / (INT64)((INT32)divisor)); + remainder = (UINT64)((INT64)dividend % (INT64)((INT32)divisor)); + if((INT64)quotient != (INT64)((INT32)quotient)) + { + (mc68kcpu)->v_flag = VFLAG_SET; + return; + } + } + else /* unsigned */ + { + quotient = dividend / divisor; + if(quotient > 0xffffffff) + { + (mc68kcpu)->v_flag = VFLAG_SET; + return; + } + remainder = dividend % divisor; + } + } + else /* 32 bit */ + { + dividend = REG_D(mc68kcpu)[(word2 >> 12) & 7]; + if(BIT_B(word2)) /* signed */ + { + quotient = (UINT64)((INT64)((INT32)dividend) / (INT64)((INT32)divisor)); + remainder = (UINT64)((INT64)((INT32)dividend) % (INT64)((INT32)divisor)); + } + else /* unsigned */ + { + quotient = dividend / divisor; + remainder = dividend % divisor; + } + } + + REG_D(mc68kcpu)[word2 & 7] = remainder; + REG_D(mc68kcpu)[(word2 >> 12) & 7] = quotient; + + (mc68kcpu)->n_flag = NFLAG_32(quotient); + (mc68kcpu)->not_z_flag = quotient; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + return; + } + m68ki_exception_trap((mc68kcpu), EXCEPTION_ZERO_DIVIDE); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_divl_32_pcdi(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT64 divisor = OPER_PCDI_32(mc68kcpu); + UINT64 dividend = 0; + UINT64 quotient = 0; + UINT64 remainder = 0; + + if(divisor != 0) + { + if(BIT_A(word2)) /* 64 bit */ + { + dividend = REG_D(mc68kcpu)[word2 & 7]; + dividend <<= 32; + dividend |= REG_D(mc68kcpu)[(word2 >> 12) & 7]; + + if(BIT_B(word2)) /* signed */ + { + quotient = (UINT64)((INT64)dividend / (INT64)((INT32)divisor)); + remainder = (UINT64)((INT64)dividend % (INT64)((INT32)divisor)); + if((INT64)quotient != (INT64)((INT32)quotient)) + { + (mc68kcpu)->v_flag = VFLAG_SET; + return; + } + } + else /* unsigned */ + { + quotient = dividend / divisor; + if(quotient > 0xffffffff) + { + (mc68kcpu)->v_flag = VFLAG_SET; + return; + } + remainder = dividend % divisor; + } + } + else /* 32 bit */ + { + dividend = REG_D(mc68kcpu)[(word2 >> 12) & 7]; + if(BIT_B(word2)) /* signed */ + { + quotient = (UINT64)((INT64)((INT32)dividend) / (INT64)((INT32)divisor)); + remainder = (UINT64)((INT64)((INT32)dividend) % (INT64)((INT32)divisor)); + } + else /* unsigned */ + { + quotient = dividend / divisor; + remainder = dividend % divisor; + } + } + + REG_D(mc68kcpu)[word2 & 7] = remainder; + REG_D(mc68kcpu)[(word2 >> 12) & 7] = quotient; + + (mc68kcpu)->n_flag = NFLAG_32(quotient); + (mc68kcpu)->not_z_flag = quotient; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + return; + } + m68ki_exception_trap((mc68kcpu), EXCEPTION_ZERO_DIVIDE); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_divl_32_pcix(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT64 divisor = OPER_PCIX_32(mc68kcpu); + UINT64 dividend = 0; + UINT64 quotient = 0; + UINT64 remainder = 0; + + if(divisor != 0) + { + if(BIT_A(word2)) /* 64 bit */ + { + dividend = REG_D(mc68kcpu)[word2 & 7]; + dividend <<= 32; + dividend |= REG_D(mc68kcpu)[(word2 >> 12) & 7]; + + if(BIT_B(word2)) /* signed */ + { + quotient = (UINT64)((INT64)dividend / (INT64)((INT32)divisor)); + remainder = (UINT64)((INT64)dividend % (INT64)((INT32)divisor)); + if((INT64)quotient != (INT64)((INT32)quotient)) + { + (mc68kcpu)->v_flag = VFLAG_SET; + return; + } + } + else /* unsigned */ + { + quotient = dividend / divisor; + if(quotient > 0xffffffff) + { + (mc68kcpu)->v_flag = VFLAG_SET; + return; + } + remainder = dividend % divisor; + } + } + else /* 32 bit */ + { + dividend = REG_D(mc68kcpu)[(word2 >> 12) & 7]; + if(BIT_B(word2)) /* signed */ + { + quotient = (UINT64)((INT64)((INT32)dividend) / (INT64)((INT32)divisor)); + remainder = (UINT64)((INT64)((INT32)dividend) % (INT64)((INT32)divisor)); + } + else /* unsigned */ + { + quotient = dividend / divisor; + remainder = dividend % divisor; + } + } + + REG_D(mc68kcpu)[word2 & 7] = remainder; + REG_D(mc68kcpu)[(word2 >> 12) & 7] = quotient; + + (mc68kcpu)->n_flag = NFLAG_32(quotient); + (mc68kcpu)->not_z_flag = quotient; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + return; + } + m68ki_exception_trap((mc68kcpu), EXCEPTION_ZERO_DIVIDE); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_divl_32_i(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT64 divisor = OPER_I_32(mc68kcpu); + UINT64 dividend = 0; + UINT64 quotient = 0; + UINT64 remainder = 0; + + if(divisor != 0) + { + if(BIT_A(word2)) /* 64 bit */ + { + dividend = REG_D(mc68kcpu)[word2 & 7]; + dividend <<= 32; + dividend |= REG_D(mc68kcpu)[(word2 >> 12) & 7]; + + if(BIT_B(word2)) /* signed */ + { + quotient = (UINT64)((INT64)dividend / (INT64)((INT32)divisor)); + remainder = (UINT64)((INT64)dividend % (INT64)((INT32)divisor)); + if((INT64)quotient != (INT64)((INT32)quotient)) + { + (mc68kcpu)->v_flag = VFLAG_SET; + return; + } + } + else /* unsigned */ + { + quotient = dividend / divisor; + if(quotient > 0xffffffff) + { + (mc68kcpu)->v_flag = VFLAG_SET; + return; + } + remainder = dividend % divisor; + } + } + else /* 32 bit */ + { + dividend = REG_D(mc68kcpu)[(word2 >> 12) & 7]; + if(BIT_B(word2)) /* signed */ + { + quotient = (UINT64)((INT64)((INT32)dividend) / (INT64)((INT32)divisor)); + remainder = (UINT64)((INT64)((INT32)dividend) % (INT64)((INT32)divisor)); + } + else /* unsigned */ + { + quotient = dividend / divisor; + remainder = dividend % divisor; + } + } + + REG_D(mc68kcpu)[word2 & 7] = remainder; + REG_D(mc68kcpu)[(word2 >> 12) & 7] = quotient; + + (mc68kcpu)->n_flag = NFLAG_32(quotient); + (mc68kcpu)->not_z_flag = quotient; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + return; + } + m68ki_exception_trap((mc68kcpu), EXCEPTION_ZERO_DIVIDE); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_eor_8_d(m68000_base_device* mc68kcpu) +{ + UINT32 res = MASK_OUT_ABOVE_8(DY(mc68kcpu) ^= MASK_OUT_ABOVE_8(DX(mc68kcpu))); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_eor_8_ai(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_AI_8(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_8(DX(mc68kcpu) ^ m68ki_read_8((mc68kcpu), ea)); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_eor_8_pi(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_PI_8(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_8(DX(mc68kcpu) ^ m68ki_read_8((mc68kcpu), ea)); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_eor_8_pi7(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_A7_PI_8(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_8(DX(mc68kcpu) ^ m68ki_read_8((mc68kcpu), ea)); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_eor_8_pd(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_PD_8(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_8(DX(mc68kcpu) ^ m68ki_read_8((mc68kcpu), ea)); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_eor_8_pd7(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_A7_PD_8(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_8(DX(mc68kcpu) ^ m68ki_read_8((mc68kcpu), ea)); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_eor_8_di(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_DI_8(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_8(DX(mc68kcpu) ^ m68ki_read_8((mc68kcpu), ea)); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_eor_8_ix(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_IX_8(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_8(DX(mc68kcpu) ^ m68ki_read_8((mc68kcpu), ea)); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_eor_8_aw(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AW_8(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_8(DX(mc68kcpu) ^ m68ki_read_8((mc68kcpu), ea)); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_eor_8_al(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AL_8(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_8(DX(mc68kcpu) ^ m68ki_read_8((mc68kcpu), ea)); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_eor_16_d(m68000_base_device* mc68kcpu) +{ + UINT32 res = MASK_OUT_ABOVE_16(DY(mc68kcpu) ^= MASK_OUT_ABOVE_16(DX(mc68kcpu))); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_eor_16_ai(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_AI_16(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_16(DX(mc68kcpu) ^ m68ki_read_16((mc68kcpu), ea)); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_eor_16_pi(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_PI_16(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_16(DX(mc68kcpu) ^ m68ki_read_16((mc68kcpu), ea)); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_eor_16_pd(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_PD_16(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_16(DX(mc68kcpu) ^ m68ki_read_16((mc68kcpu), ea)); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_eor_16_di(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_DI_16(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_16(DX(mc68kcpu) ^ m68ki_read_16((mc68kcpu), ea)); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_eor_16_ix(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_IX_16(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_16(DX(mc68kcpu) ^ m68ki_read_16((mc68kcpu), ea)); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_eor_16_aw(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AW_16(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_16(DX(mc68kcpu) ^ m68ki_read_16((mc68kcpu), ea)); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_eor_16_al(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AL_16(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_16(DX(mc68kcpu) ^ m68ki_read_16((mc68kcpu), ea)); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_eor_32_d(m68000_base_device* mc68kcpu) +{ + UINT32 res = DY(mc68kcpu) ^= DX(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_eor_32_ai(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_AI_32(mc68kcpu); + UINT32 res = DX(mc68kcpu) ^ m68ki_read_32((mc68kcpu), ea); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_eor_32_pi(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_PI_32(mc68kcpu); + UINT32 res = DX(mc68kcpu) ^ m68ki_read_32((mc68kcpu), ea); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_eor_32_pd(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_PD_32(mc68kcpu); + UINT32 res = DX(mc68kcpu) ^ m68ki_read_32((mc68kcpu), ea); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_eor_32_di(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_DI_32(mc68kcpu); + UINT32 res = DX(mc68kcpu) ^ m68ki_read_32((mc68kcpu), ea); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_eor_32_ix(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_IX_32(mc68kcpu); + UINT32 res = DX(mc68kcpu) ^ m68ki_read_32((mc68kcpu), ea); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_eor_32_aw(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AW_32(mc68kcpu); + UINT32 res = DX(mc68kcpu) ^ m68ki_read_32((mc68kcpu), ea); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_eor_32_al(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AL_32(mc68kcpu); + UINT32 res = DX(mc68kcpu) ^ m68ki_read_32((mc68kcpu), ea); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_eori_8_d(m68000_base_device* mc68kcpu) +{ + UINT32 res = MASK_OUT_ABOVE_8(DY(mc68kcpu) ^= OPER_I_8(mc68kcpu)); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_eori_8_ai(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_8(mc68kcpu); + UINT32 ea = EA_AY_AI_8(mc68kcpu); + UINT32 res = src ^ m68ki_read_8((mc68kcpu), ea); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_eori_8_pi(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_8(mc68kcpu); + UINT32 ea = EA_AY_PI_8(mc68kcpu); + UINT32 res = src ^ m68ki_read_8((mc68kcpu), ea); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_eori_8_pi7(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_8(mc68kcpu); + UINT32 ea = EA_A7_PI_8(mc68kcpu); + UINT32 res = src ^ m68ki_read_8((mc68kcpu), ea); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_eori_8_pd(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_8(mc68kcpu); + UINT32 ea = EA_AY_PD_8(mc68kcpu); + UINT32 res = src ^ m68ki_read_8((mc68kcpu), ea); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_eori_8_pd7(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_8(mc68kcpu); + UINT32 ea = EA_A7_PD_8(mc68kcpu); + UINT32 res = src ^ m68ki_read_8((mc68kcpu), ea); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_eori_8_di(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_8(mc68kcpu); + UINT32 ea = EA_AY_DI_8(mc68kcpu); + UINT32 res = src ^ m68ki_read_8((mc68kcpu), ea); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_eori_8_ix(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_8(mc68kcpu); + UINT32 ea = EA_AY_IX_8(mc68kcpu); + UINT32 res = src ^ m68ki_read_8((mc68kcpu), ea); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_eori_8_aw(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_8(mc68kcpu); + UINT32 ea = EA_AW_8(mc68kcpu); + UINT32 res = src ^ m68ki_read_8((mc68kcpu), ea); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_eori_8_al(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_8(mc68kcpu); + UINT32 ea = EA_AL_8(mc68kcpu); + UINT32 res = src ^ m68ki_read_8((mc68kcpu), ea); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_eori_16_d(m68000_base_device* mc68kcpu) +{ + UINT32 res = MASK_OUT_ABOVE_16(DY(mc68kcpu) ^= OPER_I_16(mc68kcpu)); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_eori_16_ai(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_16(mc68kcpu); + UINT32 ea = EA_AY_AI_16(mc68kcpu); + UINT32 res = src ^ m68ki_read_16((mc68kcpu), ea); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_eori_16_pi(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_16(mc68kcpu); + UINT32 ea = EA_AY_PI_16(mc68kcpu); + UINT32 res = src ^ m68ki_read_16((mc68kcpu), ea); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_eori_16_pd(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_16(mc68kcpu); + UINT32 ea = EA_AY_PD_16(mc68kcpu); + UINT32 res = src ^ m68ki_read_16((mc68kcpu), ea); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_eori_16_di(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_16(mc68kcpu); + UINT32 ea = EA_AY_DI_16(mc68kcpu); + UINT32 res = src ^ m68ki_read_16((mc68kcpu), ea); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_eori_16_ix(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_16(mc68kcpu); + UINT32 ea = EA_AY_IX_16(mc68kcpu); + UINT32 res = src ^ m68ki_read_16((mc68kcpu), ea); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_eori_16_aw(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_16(mc68kcpu); + UINT32 ea = EA_AW_16(mc68kcpu); + UINT32 res = src ^ m68ki_read_16((mc68kcpu), ea); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_eori_16_al(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_16(mc68kcpu); + UINT32 ea = EA_AL_16(mc68kcpu); + UINT32 res = src ^ m68ki_read_16((mc68kcpu), ea); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_eori_32_d(m68000_base_device* mc68kcpu) +{ + UINT32 res = DY(mc68kcpu) ^= OPER_I_32(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_eori_32_ai(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_32(mc68kcpu); + UINT32 ea = EA_AY_AI_32(mc68kcpu); + UINT32 res = src ^ m68ki_read_32((mc68kcpu), ea); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_eori_32_pi(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_32(mc68kcpu); + UINT32 ea = EA_AY_PI_32(mc68kcpu); + UINT32 res = src ^ m68ki_read_32((mc68kcpu), ea); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_eori_32_pd(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_32(mc68kcpu); + UINT32 ea = EA_AY_PD_32(mc68kcpu); + UINT32 res = src ^ m68ki_read_32((mc68kcpu), ea); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_eori_32_di(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_32(mc68kcpu); + UINT32 ea = EA_AY_DI_32(mc68kcpu); + UINT32 res = src ^ m68ki_read_32((mc68kcpu), ea); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_eori_32_ix(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_32(mc68kcpu); + UINT32 ea = EA_AY_IX_32(mc68kcpu); + UINT32 res = src ^ m68ki_read_32((mc68kcpu), ea); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_eori_32_aw(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_32(mc68kcpu); + UINT32 ea = EA_AW_32(mc68kcpu); + UINT32 res = src ^ m68ki_read_32((mc68kcpu), ea); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_eori_32_al(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_32(mc68kcpu); + UINT32 ea = EA_AL_32(mc68kcpu); + UINT32 res = src ^ m68ki_read_32((mc68kcpu), ea); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_eori_16_toc(m68000_base_device* mc68kcpu) +{ + m68ki_set_ccr((mc68kcpu), m68ki_get_ccr(mc68kcpu) ^ OPER_I_16(mc68kcpu)); +} + + +void m68000_base_device_ops::m68k_op_eori_16_tos(m68000_base_device* mc68kcpu) +{ + if((mc68kcpu)->s_flag) + { + UINT32 src = OPER_I_16(mc68kcpu); + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_set_sr((mc68kcpu), m68ki_get_sr(mc68kcpu) ^ src); + return; + } + m68ki_exception_privilege_violation(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_exg_32_dd(m68000_base_device* mc68kcpu) +{ + UINT32* reg_a = &DX(mc68kcpu); + UINT32* reg_b = &DY(mc68kcpu); + UINT32 tmp = *reg_a; + *reg_a = *reg_b; + *reg_b = tmp; +} + + +void m68000_base_device_ops::m68k_op_exg_32_aa(m68000_base_device* mc68kcpu) +{ + UINT32* reg_a = &AX(mc68kcpu); + UINT32* reg_b = &AY(mc68kcpu); + UINT32 tmp = *reg_a; + *reg_a = *reg_b; + *reg_b = tmp; +} + + +void m68000_base_device_ops::m68k_op_exg_32_da(m68000_base_device* mc68kcpu) +{ + UINT32* reg_a = &DX(mc68kcpu); + UINT32* reg_b = &AY(mc68kcpu); + UINT32 tmp = *reg_a; + *reg_a = *reg_b; + *reg_b = tmp; +} + + +void m68000_base_device_ops::m68k_op_ext_16(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DY(mc68kcpu); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | MASK_OUT_ABOVE_8(*r_dst) | (GET_MSB_8(*r_dst) ? 0xff00 : 0); + + (mc68kcpu)->n_flag = NFLAG_16(*r_dst); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(*r_dst); + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_ext_32(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DY(mc68kcpu); + + *r_dst = MASK_OUT_ABOVE_16(*r_dst) | (GET_MSB_16(*r_dst) ? 0xffff0000 : 0); + + (mc68kcpu)->n_flag = NFLAG_32(*r_dst); + (mc68kcpu)->not_z_flag = *r_dst; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_extb_32(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32* r_dst = &DY(mc68kcpu); + + *r_dst = MASK_OUT_ABOVE_8(*r_dst) | (GET_MSB_8(*r_dst) ? 0xffffff00 : 0); + + (mc68kcpu)->n_flag = NFLAG_32(*r_dst); + (mc68kcpu)->not_z_flag = *r_dst; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_illegal(m68000_base_device* mc68kcpu) +{ + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_jmp_32_ai(m68000_base_device* mc68kcpu) +{ + m68ki_jump((mc68kcpu), EA_AY_AI_32(mc68kcpu)); + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + if(REG_PC(mc68kcpu) == REG_PPC(mc68kcpu) && (mc68kcpu)->remaining_cycles > 0) + (mc68kcpu)->remaining_cycles = 0; +} + + +void m68000_base_device_ops::m68k_op_jmp_32_di(m68000_base_device* mc68kcpu) +{ + m68ki_jump((mc68kcpu), EA_AY_DI_32(mc68kcpu)); + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + if(REG_PC(mc68kcpu) == REG_PPC(mc68kcpu) && (mc68kcpu)->remaining_cycles > 0) + (mc68kcpu)->remaining_cycles = 0; +} + + +void m68000_base_device_ops::m68k_op_jmp_32_ix(m68000_base_device* mc68kcpu) +{ + m68ki_jump((mc68kcpu), EA_AY_IX_32(mc68kcpu)); + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + if(REG_PC(mc68kcpu) == REG_PPC(mc68kcpu) && (mc68kcpu)->remaining_cycles > 0) + (mc68kcpu)->remaining_cycles = 0; +} + + +void m68000_base_device_ops::m68k_op_jmp_32_aw(m68000_base_device* mc68kcpu) +{ + m68ki_jump((mc68kcpu), EA_AW_32(mc68kcpu)); + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + if(REG_PC(mc68kcpu) == REG_PPC(mc68kcpu) && (mc68kcpu)->remaining_cycles > 0) + (mc68kcpu)->remaining_cycles = 0; +} + + +void m68000_base_device_ops::m68k_op_jmp_32_al(m68000_base_device* mc68kcpu) +{ + m68ki_jump((mc68kcpu), EA_AL_32(mc68kcpu)); + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + if(REG_PC(mc68kcpu) == REG_PPC(mc68kcpu) && (mc68kcpu)->remaining_cycles > 0) + (mc68kcpu)->remaining_cycles = 0; +} + + +void m68000_base_device_ops::m68k_op_jmp_32_pcdi(m68000_base_device* mc68kcpu) +{ + m68ki_jump((mc68kcpu), EA_PCDI_32(mc68kcpu)); + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + if(REG_PC(mc68kcpu) == REG_PPC(mc68kcpu) && (mc68kcpu)->remaining_cycles > 0) + (mc68kcpu)->remaining_cycles = 0; +} + + +void m68000_base_device_ops::m68k_op_jmp_32_pcix(m68000_base_device* mc68kcpu) +{ + m68ki_jump((mc68kcpu), EA_PCIX_32(mc68kcpu)); + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + if(REG_PC(mc68kcpu) == REG_PPC(mc68kcpu) && (mc68kcpu)->remaining_cycles > 0) + (mc68kcpu)->remaining_cycles = 0; +} + + +void m68000_base_device_ops::m68k_op_jsr_32_ai(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_AI_32(mc68kcpu); + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_push_32((mc68kcpu), REG_PC(mc68kcpu)); + m68ki_jump((mc68kcpu), ea); +} + + +void m68000_base_device_ops::m68k_op_jsr_32_di(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_DI_32(mc68kcpu); + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_push_32((mc68kcpu), REG_PC(mc68kcpu)); + m68ki_jump((mc68kcpu), ea); +} + + +void m68000_base_device_ops::m68k_op_jsr_32_ix(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_IX_32(mc68kcpu); + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_push_32((mc68kcpu), REG_PC(mc68kcpu)); + m68ki_jump((mc68kcpu), ea); +} + + +void m68000_base_device_ops::m68k_op_jsr_32_aw(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AW_32(mc68kcpu); + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_push_32((mc68kcpu), REG_PC(mc68kcpu)); + m68ki_jump((mc68kcpu), ea); +} + + +void m68000_base_device_ops::m68k_op_jsr_32_al(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AL_32(mc68kcpu); + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_push_32((mc68kcpu), REG_PC(mc68kcpu)); + m68ki_jump((mc68kcpu), ea); +} + + +void m68000_base_device_ops::m68k_op_jsr_32_pcdi(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_PCDI_32(mc68kcpu); + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_push_32((mc68kcpu), REG_PC(mc68kcpu)); + m68ki_jump((mc68kcpu), ea); +} + + +void m68000_base_device_ops::m68k_op_jsr_32_pcix(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_PCIX_32(mc68kcpu); + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_push_32((mc68kcpu), REG_PC(mc68kcpu)); + m68ki_jump((mc68kcpu), ea); +} + + +void m68000_base_device_ops::m68k_op_lea_32_ai(m68000_base_device* mc68kcpu) +{ + AX(mc68kcpu) = EA_AY_AI_32(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_lea_32_di(m68000_base_device* mc68kcpu) +{ + AX(mc68kcpu) = EA_AY_DI_32(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_lea_32_ix(m68000_base_device* mc68kcpu) +{ + AX(mc68kcpu) = EA_AY_IX_32(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_lea_32_aw(m68000_base_device* mc68kcpu) +{ + AX(mc68kcpu) = EA_AW_32(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_lea_32_al(m68000_base_device* mc68kcpu) +{ + AX(mc68kcpu) = EA_AL_32(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_lea_32_pcdi(m68000_base_device* mc68kcpu) +{ + AX(mc68kcpu) = EA_PCDI_32(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_lea_32_pcix(m68000_base_device* mc68kcpu) +{ + AX(mc68kcpu) = EA_PCIX_32(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_link_16_a7(m68000_base_device* mc68kcpu) +{ + REG_A(mc68kcpu)[7] -= 4; + m68ki_write_32((mc68kcpu), REG_A(mc68kcpu)[7], REG_A(mc68kcpu)[7]); + REG_A(mc68kcpu)[7] = MASK_OUT_ABOVE_32(REG_A(mc68kcpu)[7] + MAKE_INT_16(OPER_I_16(mc68kcpu))); +} + + +void m68000_base_device_ops::m68k_op_link_16(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &AY(mc68kcpu); + + m68ki_push_32((mc68kcpu), *r_dst); + *r_dst = REG_A(mc68kcpu)[7]; + REG_A(mc68kcpu)[7] = MASK_OUT_ABOVE_32(REG_A(mc68kcpu)[7] + MAKE_INT_16(OPER_I_16(mc68kcpu))); +} + + +void m68000_base_device_ops::m68k_op_link_32_a7(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + REG_A(mc68kcpu)[7] -= 4; + m68ki_write_32((mc68kcpu), REG_A(mc68kcpu)[7], REG_A(mc68kcpu)[7]); + REG_A(mc68kcpu)[7] = MASK_OUT_ABOVE_32(REG_A(mc68kcpu)[7] + OPER_I_32(mc68kcpu)); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_link_32(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32* r_dst = &AY(mc68kcpu); + + m68ki_push_32((mc68kcpu), *r_dst); + *r_dst = REG_A(mc68kcpu)[7]; + REG_A(mc68kcpu)[7] = MASK_OUT_ABOVE_32(REG_A(mc68kcpu)[7] + OPER_I_32(mc68kcpu)); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_lsr_8_s(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 shift = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT32 src = MASK_OUT_ABOVE_8(*r_dst); + UINT32 res = src >> shift; + + if(shift != 0) + (mc68kcpu)->remaining_cycles -= shift<<(mc68kcpu)->cyc_shift; + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; + + (mc68kcpu)->n_flag = NFLAG_CLEAR; + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = src << (9-shift); + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_lsr_16_s(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 shift = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT32 src = MASK_OUT_ABOVE_16(*r_dst); + UINT32 res = src >> shift; + + if(shift != 0) + (mc68kcpu)->remaining_cycles -= shift<<(mc68kcpu)->cyc_shift; + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + + (mc68kcpu)->n_flag = NFLAG_CLEAR; + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = src << (9-shift); + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_lsr_32_s(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 shift = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT32 src = *r_dst; + UINT32 res = src >> shift; + + if(shift != 0) + (mc68kcpu)->remaining_cycles -= shift<<(mc68kcpu)->cyc_shift; + + *r_dst = res; + + (mc68kcpu)->n_flag = NFLAG_CLEAR; + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = src << (9-shift); + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_lsr_8_r(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 shift = DX(mc68kcpu) & 0x3f; + UINT32 src = MASK_OUT_ABOVE_8(*r_dst); + UINT32 res = src >> shift; + + if(shift != 0) + { + (mc68kcpu)->remaining_cycles -= shift<<(mc68kcpu)->cyc_shift; + + if(shift <= 8) + { + *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = src << (9-shift); + (mc68kcpu)->n_flag = NFLAG_CLEAR; + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + return; + } + + *r_dst &= 0xffffff00; + (mc68kcpu)->x_flag = XFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->n_flag = NFLAG_CLEAR; + (mc68kcpu)->not_z_flag = ZFLAG_SET; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + return; + } + + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->n_flag = NFLAG_8(src); + (mc68kcpu)->not_z_flag = src; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_lsr_16_r(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 shift = DX(mc68kcpu) & 0x3f; + UINT32 src = MASK_OUT_ABOVE_16(*r_dst); + UINT32 res = src >> shift; + + if(shift != 0) + { + (mc68kcpu)->remaining_cycles -= shift<<(mc68kcpu)->cyc_shift; + + if(shift <= 16) + { + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag = (src >> (shift - 1))<<8; + (mc68kcpu)->n_flag = NFLAG_CLEAR; + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + return; + } + + *r_dst &= 0xffff0000; + (mc68kcpu)->x_flag = XFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->n_flag = NFLAG_CLEAR; + (mc68kcpu)->not_z_flag = ZFLAG_SET; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + return; + } + + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->n_flag = NFLAG_16(src); + (mc68kcpu)->not_z_flag = src; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_lsr_32_r(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 shift = DX(mc68kcpu) & 0x3f; + UINT32 src = *r_dst; + UINT32 res = src >> shift; + + if(shift != 0) + { + (mc68kcpu)->remaining_cycles -= shift<<(mc68kcpu)->cyc_shift; + + if(shift < 32) + { + *r_dst = res; + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag = (src >> (shift - 1))<<8; + (mc68kcpu)->n_flag = NFLAG_CLEAR; + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + return; + } + + *r_dst = 0; + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = (shift == 32 ? GET_MSB_32(src)>>23 : 0); + (mc68kcpu)->n_flag = NFLAG_CLEAR; + (mc68kcpu)->not_z_flag = ZFLAG_SET; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + return; + } + + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->n_flag = NFLAG_32(src); + (mc68kcpu)->not_z_flag = src; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_lsr_16_ai(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_AI_16(mc68kcpu); + UINT32 src = m68ki_read_16((mc68kcpu), ea); + UINT32 res = src >> 1; + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_CLEAR; + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag = src << 8; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_lsr_16_pi(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_PI_16(mc68kcpu); + UINT32 src = m68ki_read_16((mc68kcpu), ea); + UINT32 res = src >> 1; + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_CLEAR; + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag = src << 8; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_lsr_16_pd(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_PD_16(mc68kcpu); + UINT32 src = m68ki_read_16((mc68kcpu), ea); + UINT32 res = src >> 1; + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_CLEAR; + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag = src << 8; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_lsr_16_di(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_DI_16(mc68kcpu); + UINT32 src = m68ki_read_16((mc68kcpu), ea); + UINT32 res = src >> 1; + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_CLEAR; + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag = src << 8; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_lsr_16_ix(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_IX_16(mc68kcpu); + UINT32 src = m68ki_read_16((mc68kcpu), ea); + UINT32 res = src >> 1; + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_CLEAR; + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag = src << 8; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_lsr_16_aw(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AW_16(mc68kcpu); + UINT32 src = m68ki_read_16((mc68kcpu), ea); + UINT32 res = src >> 1; + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_CLEAR; + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag = src << 8; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_lsr_16_al(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AL_16(mc68kcpu); + UINT32 src = m68ki_read_16((mc68kcpu), ea); + UINT32 res = src >> 1; + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_CLEAR; + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag = src << 8; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_lsl_8_s(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 shift = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT32 src = MASK_OUT_ABOVE_8(*r_dst); + UINT32 res = MASK_OUT_ABOVE_8(src << shift); + + if(shift != 0) + (mc68kcpu)->remaining_cycles -= shift<<(mc68kcpu)->cyc_shift; + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = src << shift; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_lsl_16_s(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 shift = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT32 src = MASK_OUT_ABOVE_16(*r_dst); + UINT32 res = MASK_OUT_ABOVE_16(src << shift); + + if(shift != 0) + (mc68kcpu)->remaining_cycles -= shift<<(mc68kcpu)->cyc_shift; + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = src >> (8-shift); + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_lsl_32_s(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 shift = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT32 src = *r_dst; + UINT32 res = MASK_OUT_ABOVE_32(src << shift); + + if(shift != 0) + (mc68kcpu)->remaining_cycles -= shift<<(mc68kcpu)->cyc_shift; + + *r_dst = res; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = src >> (24-shift); + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_lsl_8_r(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 shift = DX(mc68kcpu) & 0x3f; + UINT32 src = MASK_OUT_ABOVE_8(*r_dst); + UINT32 res = MASK_OUT_ABOVE_8(src << shift); + + if(shift != 0) + { + (mc68kcpu)->remaining_cycles -= shift<<(mc68kcpu)->cyc_shift; + + if(shift <= 8) + { + *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = src << shift; + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + return; + } + + *r_dst &= 0xffffff00; + (mc68kcpu)->x_flag = XFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->n_flag = NFLAG_CLEAR; + (mc68kcpu)->not_z_flag = ZFLAG_SET; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + return; + } + + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->n_flag = NFLAG_8(src); + (mc68kcpu)->not_z_flag = src; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_lsl_16_r(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 shift = DX(mc68kcpu) & 0x3f; + UINT32 src = MASK_OUT_ABOVE_16(*r_dst); + UINT32 res = MASK_OUT_ABOVE_16(src << shift); + + if(shift != 0) + { + (mc68kcpu)->remaining_cycles -= shift<<(mc68kcpu)->cyc_shift; + + if(shift <= 16) + { + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = (src << shift) >> 8; + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + return; + } + + *r_dst &= 0xffff0000; + (mc68kcpu)->x_flag = XFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->n_flag = NFLAG_CLEAR; + (mc68kcpu)->not_z_flag = ZFLAG_SET; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + return; + } + + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->n_flag = NFLAG_16(src); + (mc68kcpu)->not_z_flag = src; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_lsl_32_r(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 shift = DX(mc68kcpu) & 0x3f; + UINT32 src = *r_dst; + UINT32 res = MASK_OUT_ABOVE_32(src << shift); + + if(shift != 0) + { + (mc68kcpu)->remaining_cycles -= shift<<(mc68kcpu)->cyc_shift; + + if(shift < 32) + { + *r_dst = res; + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = (src >> (32 - shift)) << 8; + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + return; + } + + *r_dst = 0; + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = ((shift == 32 ? src & 1 : 0))<<8; + (mc68kcpu)->n_flag = NFLAG_CLEAR; + (mc68kcpu)->not_z_flag = ZFLAG_SET; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + return; + } + + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->n_flag = NFLAG_32(src); + (mc68kcpu)->not_z_flag = src; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_lsl_16_ai(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_AI_16(mc68kcpu); + UINT32 src = m68ki_read_16((mc68kcpu), ea); + UINT32 res = MASK_OUT_ABOVE_16(src << 1); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = src >> 7; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_lsl_16_pi(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_PI_16(mc68kcpu); + UINT32 src = m68ki_read_16((mc68kcpu), ea); + UINT32 res = MASK_OUT_ABOVE_16(src << 1); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = src >> 7; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_lsl_16_pd(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_PD_16(mc68kcpu); + UINT32 src = m68ki_read_16((mc68kcpu), ea); + UINT32 res = MASK_OUT_ABOVE_16(src << 1); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = src >> 7; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_lsl_16_di(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_DI_16(mc68kcpu); + UINT32 src = m68ki_read_16((mc68kcpu), ea); + UINT32 res = MASK_OUT_ABOVE_16(src << 1); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = src >> 7; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_lsl_16_ix(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_IX_16(mc68kcpu); + UINT32 src = m68ki_read_16((mc68kcpu), ea); + UINT32 res = MASK_OUT_ABOVE_16(src << 1); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = src >> 7; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_lsl_16_aw(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AW_16(mc68kcpu); + UINT32 src = m68ki_read_16((mc68kcpu), ea); + UINT32 res = MASK_OUT_ABOVE_16(src << 1); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = src >> 7; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_lsl_16_al(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AL_16(mc68kcpu); + UINT32 src = m68ki_read_16((mc68kcpu), ea); + UINT32 res = MASK_OUT_ABOVE_16(src << 1); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = src >> 7; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_d_d(m68000_base_device* mc68kcpu) +{ + UINT32 res = MASK_OUT_ABOVE_8(DY(mc68kcpu)); + UINT32* r_dst = &DX(mc68kcpu); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_d_ai(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_AI_8(mc68kcpu); + UINT32* r_dst = &DX(mc68kcpu); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_d_pi(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_PI_8(mc68kcpu); + UINT32* r_dst = &DX(mc68kcpu); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_d_pi7(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_A7_PI_8(mc68kcpu); + UINT32* r_dst = &DX(mc68kcpu); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_d_pd(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_PD_8(mc68kcpu); + UINT32* r_dst = &DX(mc68kcpu); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_d_pd7(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_A7_PD_8(mc68kcpu); + UINT32* r_dst = &DX(mc68kcpu); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_d_di(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_DI_8(mc68kcpu); + UINT32* r_dst = &DX(mc68kcpu); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_d_ix(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_IX_8(mc68kcpu); + UINT32* r_dst = &DX(mc68kcpu); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_d_aw(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AW_8(mc68kcpu); + UINT32* r_dst = &DX(mc68kcpu); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_d_al(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AL_8(mc68kcpu); + UINT32* r_dst = &DX(mc68kcpu); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_d_pcdi(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_PCDI_8(mc68kcpu); + UINT32* r_dst = &DX(mc68kcpu); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_d_pcix(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_PCIX_8(mc68kcpu); + UINT32* r_dst = &DX(mc68kcpu); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_d_i(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_I_8(mc68kcpu); + UINT32* r_dst = &DX(mc68kcpu); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_ai_d(m68000_base_device* mc68kcpu) +{ + UINT32 res = MASK_OUT_ABOVE_8(DY(mc68kcpu)); + UINT32 ea = EA_AX_AI_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_ai_ai(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_AI_8(mc68kcpu); + UINT32 ea = EA_AX_AI_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_ai_pi(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_PI_8(mc68kcpu); + UINT32 ea = EA_AX_AI_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_ai_pi7(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_A7_PI_8(mc68kcpu); + UINT32 ea = EA_AX_AI_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_ai_pd(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_PD_8(mc68kcpu); + UINT32 ea = EA_AX_AI_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_ai_pd7(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_A7_PD_8(mc68kcpu); + UINT32 ea = EA_AX_AI_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_ai_di(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_DI_8(mc68kcpu); + UINT32 ea = EA_AX_AI_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_ai_ix(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_IX_8(mc68kcpu); + UINT32 ea = EA_AX_AI_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_ai_aw(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AW_8(mc68kcpu); + UINT32 ea = EA_AX_AI_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_ai_al(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AL_8(mc68kcpu); + UINT32 ea = EA_AX_AI_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_ai_pcdi(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_PCDI_8(mc68kcpu); + UINT32 ea = EA_AX_AI_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_ai_pcix(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_PCIX_8(mc68kcpu); + UINT32 ea = EA_AX_AI_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_ai_i(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_I_8(mc68kcpu); + UINT32 ea = EA_AX_AI_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_pi7_d(m68000_base_device* mc68kcpu) +{ + UINT32 res = MASK_OUT_ABOVE_8(DY(mc68kcpu)); + UINT32 ea = EA_A7_PI_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_pi_d(m68000_base_device* mc68kcpu) +{ + UINT32 res = MASK_OUT_ABOVE_8(DY(mc68kcpu)); + UINT32 ea = EA_AX_PI_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_pi7_ai(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_AI_8(mc68kcpu); + UINT32 ea = EA_A7_PI_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_pi7_pi(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_PI_8(mc68kcpu); + UINT32 ea = EA_A7_PI_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_pi7_pi7(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_A7_PI_8(mc68kcpu); + UINT32 ea = EA_A7_PI_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_pi7_pd(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_PD_8(mc68kcpu); + UINT32 ea = EA_A7_PI_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_pi7_pd7(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_A7_PD_8(mc68kcpu); + UINT32 ea = EA_A7_PI_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_pi7_di(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_DI_8(mc68kcpu); + UINT32 ea = EA_A7_PI_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_pi7_ix(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_IX_8(mc68kcpu); + UINT32 ea = EA_A7_PI_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_pi7_aw(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AW_8(mc68kcpu); + UINT32 ea = EA_A7_PI_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_pi7_al(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AL_8(mc68kcpu); + UINT32 ea = EA_A7_PI_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_pi7_pcdi(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_PCDI_8(mc68kcpu); + UINT32 ea = EA_A7_PI_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_pi7_pcix(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_PCIX_8(mc68kcpu); + UINT32 ea = EA_A7_PI_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_pi7_i(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_I_8(mc68kcpu); + UINT32 ea = EA_A7_PI_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_pi_ai(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_AI_8(mc68kcpu); + UINT32 ea = EA_AX_PI_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_pi_pi(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_PI_8(mc68kcpu); + UINT32 ea = EA_AX_PI_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_pi_pi7(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_A7_PI_8(mc68kcpu); + UINT32 ea = EA_AX_PI_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_pi_pd(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_PD_8(mc68kcpu); + UINT32 ea = EA_AX_PI_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_pi_pd7(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_A7_PD_8(mc68kcpu); + UINT32 ea = EA_AX_PI_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_pi_di(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_DI_8(mc68kcpu); + UINT32 ea = EA_AX_PI_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_pi_ix(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_IX_8(mc68kcpu); + UINT32 ea = EA_AX_PI_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_pi_aw(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AW_8(mc68kcpu); + UINT32 ea = EA_AX_PI_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_pi_al(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AL_8(mc68kcpu); + UINT32 ea = EA_AX_PI_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_pi_pcdi(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_PCDI_8(mc68kcpu); + UINT32 ea = EA_AX_PI_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_pi_pcix(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_PCIX_8(mc68kcpu); + UINT32 ea = EA_AX_PI_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_pi_i(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_I_8(mc68kcpu); + UINT32 ea = EA_AX_PI_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_pd7_d(m68000_base_device* mc68kcpu) +{ + UINT32 res = MASK_OUT_ABOVE_8(DY(mc68kcpu)); + UINT32 ea = EA_A7_PD_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_pd_d(m68000_base_device* mc68kcpu) +{ + UINT32 res = MASK_OUT_ABOVE_8(DY(mc68kcpu)); + UINT32 ea = EA_AX_PD_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_pd7_ai(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_AI_8(mc68kcpu); + UINT32 ea = EA_A7_PD_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_pd7_pi(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_PI_8(mc68kcpu); + UINT32 ea = EA_A7_PD_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_pd7_pi7(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_A7_PI_8(mc68kcpu); + UINT32 ea = EA_A7_PD_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_pd7_pd(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_PD_8(mc68kcpu); + UINT32 ea = EA_A7_PD_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_pd7_pd7(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_A7_PD_8(mc68kcpu); + UINT32 ea = EA_A7_PD_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_pd7_di(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_DI_8(mc68kcpu); + UINT32 ea = EA_A7_PD_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_pd7_ix(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_IX_8(mc68kcpu); + UINT32 ea = EA_A7_PD_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_pd7_aw(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AW_8(mc68kcpu); + UINT32 ea = EA_A7_PD_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_pd7_al(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AL_8(mc68kcpu); + UINT32 ea = EA_A7_PD_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_pd7_pcdi(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_PCDI_8(mc68kcpu); + UINT32 ea = EA_A7_PD_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_pd7_pcix(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_PCIX_8(mc68kcpu); + UINT32 ea = EA_A7_PD_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_pd7_i(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_I_8(mc68kcpu); + UINT32 ea = EA_A7_PD_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_pd_ai(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_AI_8(mc68kcpu); + UINT32 ea = EA_AX_PD_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_pd_pi(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_PI_8(mc68kcpu); + UINT32 ea = EA_AX_PD_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_pd_pi7(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_A7_PI_8(mc68kcpu); + UINT32 ea = EA_AX_PD_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_pd_pd(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_PD_8(mc68kcpu); + UINT32 ea = EA_AX_PD_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_pd_pd7(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_A7_PD_8(mc68kcpu); + UINT32 ea = EA_AX_PD_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_pd_di(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_DI_8(mc68kcpu); + UINT32 ea = EA_AX_PD_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_pd_ix(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_IX_8(mc68kcpu); + UINT32 ea = EA_AX_PD_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_pd_aw(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AW_8(mc68kcpu); + UINT32 ea = EA_AX_PD_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_pd_al(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AL_8(mc68kcpu); + UINT32 ea = EA_AX_PD_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_pd_pcdi(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_PCDI_8(mc68kcpu); + UINT32 ea = EA_AX_PD_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_pd_pcix(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_PCIX_8(mc68kcpu); + UINT32 ea = EA_AX_PD_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_pd_i(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_I_8(mc68kcpu); + UINT32 ea = EA_AX_PD_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_di_d(m68000_base_device* mc68kcpu) +{ + UINT32 res = MASK_OUT_ABOVE_8(DY(mc68kcpu)); + UINT32 ea = EA_AX_DI_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_di_ai(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_AI_8(mc68kcpu); + UINT32 ea = EA_AX_DI_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_di_pi(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_PI_8(mc68kcpu); + UINT32 ea = EA_AX_DI_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_di_pi7(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_A7_PI_8(mc68kcpu); + UINT32 ea = EA_AX_DI_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_di_pd(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_PD_8(mc68kcpu); + UINT32 ea = EA_AX_DI_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_di_pd7(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_A7_PD_8(mc68kcpu); + UINT32 ea = EA_AX_DI_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_di_di(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_DI_8(mc68kcpu); + UINT32 ea = EA_AX_DI_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_di_ix(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_IX_8(mc68kcpu); + UINT32 ea = EA_AX_DI_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_di_aw(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AW_8(mc68kcpu); + UINT32 ea = EA_AX_DI_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_di_al(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AL_8(mc68kcpu); + UINT32 ea = EA_AX_DI_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_di_pcdi(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_PCDI_8(mc68kcpu); + UINT32 ea = EA_AX_DI_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_di_pcix(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_PCIX_8(mc68kcpu); + UINT32 ea = EA_AX_DI_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_di_i(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_I_8(mc68kcpu); + UINT32 ea = EA_AX_DI_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_ix_d(m68000_base_device* mc68kcpu) +{ + UINT32 res = MASK_OUT_ABOVE_8(DY(mc68kcpu)); + UINT32 ea = EA_AX_IX_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_ix_ai(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_AI_8(mc68kcpu); + UINT32 ea = EA_AX_IX_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_ix_pi(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_PI_8(mc68kcpu); + UINT32 ea = EA_AX_IX_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_ix_pi7(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_A7_PI_8(mc68kcpu); + UINT32 ea = EA_AX_IX_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_ix_pd(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_PD_8(mc68kcpu); + UINT32 ea = EA_AX_IX_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_ix_pd7(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_A7_PD_8(mc68kcpu); + UINT32 ea = EA_AX_IX_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_ix_di(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_DI_8(mc68kcpu); + UINT32 ea = EA_AX_IX_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_ix_ix(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_IX_8(mc68kcpu); + UINT32 ea = EA_AX_IX_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_ix_aw(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AW_8(mc68kcpu); + UINT32 ea = EA_AX_IX_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_ix_al(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AL_8(mc68kcpu); + UINT32 ea = EA_AX_IX_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_ix_pcdi(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_PCDI_8(mc68kcpu); + UINT32 ea = EA_AX_IX_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_ix_pcix(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_PCIX_8(mc68kcpu); + UINT32 ea = EA_AX_IX_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_ix_i(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_I_8(mc68kcpu); + UINT32 ea = EA_AX_IX_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_aw_d(m68000_base_device* mc68kcpu) +{ + UINT32 res = MASK_OUT_ABOVE_8(DY(mc68kcpu)); + UINT32 ea = EA_AW_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_aw_ai(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_AI_8(mc68kcpu); + UINT32 ea = EA_AW_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_aw_pi(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_PI_8(mc68kcpu); + UINT32 ea = EA_AW_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_aw_pi7(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_A7_PI_8(mc68kcpu); + UINT32 ea = EA_AW_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_aw_pd(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_PD_8(mc68kcpu); + UINT32 ea = EA_AW_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_aw_pd7(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_A7_PD_8(mc68kcpu); + UINT32 ea = EA_AW_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_aw_di(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_DI_8(mc68kcpu); + UINT32 ea = EA_AW_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_aw_ix(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_IX_8(mc68kcpu); + UINT32 ea = EA_AW_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_aw_aw(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AW_8(mc68kcpu); + UINT32 ea = EA_AW_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_aw_al(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AL_8(mc68kcpu); + UINT32 ea = EA_AW_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_aw_pcdi(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_PCDI_8(mc68kcpu); + UINT32 ea = EA_AW_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_aw_pcix(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_PCIX_8(mc68kcpu); + UINT32 ea = EA_AW_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_aw_i(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_I_8(mc68kcpu); + UINT32 ea = EA_AW_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_al_d(m68000_base_device* mc68kcpu) +{ + UINT32 res = MASK_OUT_ABOVE_8(DY(mc68kcpu)); + UINT32 ea = EA_AL_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_al_ai(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_AI_8(mc68kcpu); + UINT32 ea = EA_AL_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_al_pi(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_PI_8(mc68kcpu); + UINT32 ea = EA_AL_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_al_pi7(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_A7_PI_8(mc68kcpu); + UINT32 ea = EA_AL_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_al_pd(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_PD_8(mc68kcpu); + UINT32 ea = EA_AL_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_al_pd7(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_A7_PD_8(mc68kcpu); + UINT32 ea = EA_AL_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_al_di(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_DI_8(mc68kcpu); + UINT32 ea = EA_AL_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_al_ix(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_IX_8(mc68kcpu); + UINT32 ea = EA_AL_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_al_aw(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AW_8(mc68kcpu); + UINT32 ea = EA_AL_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_al_al(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AL_8(mc68kcpu); + UINT32 ea = EA_AL_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_al_pcdi(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_PCDI_8(mc68kcpu); + UINT32 ea = EA_AL_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_al_pcix(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_PCIX_8(mc68kcpu); + UINT32 ea = EA_AL_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_8_al_i(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_I_8(mc68kcpu); + UINT32 ea = EA_AL_8(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_16_d_d(m68000_base_device* mc68kcpu) +{ + UINT32 res = MASK_OUT_ABOVE_16(DY(mc68kcpu)); + UINT32* r_dst = &DX(mc68kcpu); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_16_d_a(m68000_base_device* mc68kcpu) +{ + UINT32 res = MASK_OUT_ABOVE_16(AY(mc68kcpu)); + UINT32* r_dst = &DX(mc68kcpu); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_16_d_ai(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_AI_16(mc68kcpu); + UINT32* r_dst = &DX(mc68kcpu); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_16_d_pi(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_PI_16(mc68kcpu); + UINT32* r_dst = &DX(mc68kcpu); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_16_d_pd(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_PD_16(mc68kcpu); + UINT32* r_dst = &DX(mc68kcpu); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_16_d_di(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_DI_16(mc68kcpu); + UINT32* r_dst = &DX(mc68kcpu); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_16_d_ix(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_IX_16(mc68kcpu); + UINT32* r_dst = &DX(mc68kcpu); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_16_d_aw(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AW_16(mc68kcpu); + UINT32* r_dst = &DX(mc68kcpu); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_16_d_al(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AL_16(mc68kcpu); + UINT32* r_dst = &DX(mc68kcpu); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_16_d_pcdi(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_PCDI_16(mc68kcpu); + UINT32* r_dst = &DX(mc68kcpu); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_16_d_pcix(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_PCIX_16(mc68kcpu); + UINT32* r_dst = &DX(mc68kcpu); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_16_d_i(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_I_16(mc68kcpu); + UINT32* r_dst = &DX(mc68kcpu); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_16_ai_d(m68000_base_device* mc68kcpu) +{ + UINT32 res = MASK_OUT_ABOVE_16(DY(mc68kcpu)); + UINT32 ea = EA_AX_AI_16(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_16_ai_a(m68000_base_device* mc68kcpu) +{ + UINT32 res = MASK_OUT_ABOVE_16(AY(mc68kcpu)); + UINT32 ea = EA_AX_AI_16(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_16_ai_ai(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_AI_16(mc68kcpu); + UINT32 ea = EA_AX_AI_16(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_16_ai_pi(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_PI_16(mc68kcpu); + UINT32 ea = EA_AX_AI_16(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_16_ai_pd(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_PD_16(mc68kcpu); + UINT32 ea = EA_AX_AI_16(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_16_ai_di(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_DI_16(mc68kcpu); + UINT32 ea = EA_AX_AI_16(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_16_ai_ix(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_IX_16(mc68kcpu); + UINT32 ea = EA_AX_AI_16(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_16_ai_aw(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AW_16(mc68kcpu); + UINT32 ea = EA_AX_AI_16(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_16_ai_al(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AL_16(mc68kcpu); + UINT32 ea = EA_AX_AI_16(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_16_ai_pcdi(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_PCDI_16(mc68kcpu); + UINT32 ea = EA_AX_AI_16(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_16_ai_pcix(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_PCIX_16(mc68kcpu); + UINT32 ea = EA_AX_AI_16(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_16_ai_i(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_I_16(mc68kcpu); + UINT32 ea = EA_AX_AI_16(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_16_pi_d(m68000_base_device* mc68kcpu) +{ + UINT32 res = MASK_OUT_ABOVE_16(DY(mc68kcpu)); + UINT32 ea = EA_AX_PI_16(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_16_pi_a(m68000_base_device* mc68kcpu) +{ + UINT32 res = MASK_OUT_ABOVE_16(AY(mc68kcpu)); + UINT32 ea = EA_AX_PI_16(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_16_pi_ai(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_AI_16(mc68kcpu); + UINT32 ea = EA_AX_PI_16(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_16_pi_pi(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_PI_16(mc68kcpu); + UINT32 ea = EA_AX_PI_16(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_16_pi_pd(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_PD_16(mc68kcpu); + UINT32 ea = EA_AX_PI_16(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_16_pi_di(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_DI_16(mc68kcpu); + UINT32 ea = EA_AX_PI_16(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_16_pi_ix(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_IX_16(mc68kcpu); + UINT32 ea = EA_AX_PI_16(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_16_pi_aw(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AW_16(mc68kcpu); + UINT32 ea = EA_AX_PI_16(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_16_pi_al(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AL_16(mc68kcpu); + UINT32 ea = EA_AX_PI_16(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_16_pi_pcdi(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_PCDI_16(mc68kcpu); + UINT32 ea = EA_AX_PI_16(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_16_pi_pcix(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_PCIX_16(mc68kcpu); + UINT32 ea = EA_AX_PI_16(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_16_pi_i(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_I_16(mc68kcpu); + UINT32 ea = EA_AX_PI_16(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_16_pd_d(m68000_base_device* mc68kcpu) +{ + UINT32 res = MASK_OUT_ABOVE_16(DY(mc68kcpu)); + UINT32 ea = EA_AX_PD_16(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_16_pd_a(m68000_base_device* mc68kcpu) +{ + UINT32 res = MASK_OUT_ABOVE_16(AY(mc68kcpu)); + UINT32 ea = EA_AX_PD_16(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_16_pd_ai(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_AI_16(mc68kcpu); + UINT32 ea = EA_AX_PD_16(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_16_pd_pi(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_PI_16(mc68kcpu); + UINT32 ea = EA_AX_PD_16(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_16_pd_pd(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_PD_16(mc68kcpu); + UINT32 ea = EA_AX_PD_16(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_16_pd_di(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_DI_16(mc68kcpu); + UINT32 ea = EA_AX_PD_16(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_16_pd_ix(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_IX_16(mc68kcpu); + UINT32 ea = EA_AX_PD_16(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_16_pd_aw(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AW_16(mc68kcpu); + UINT32 ea = EA_AX_PD_16(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_16_pd_al(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AL_16(mc68kcpu); + UINT32 ea = EA_AX_PD_16(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_16_pd_pcdi(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_PCDI_16(mc68kcpu); + UINT32 ea = EA_AX_PD_16(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_16_pd_pcix(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_PCIX_16(mc68kcpu); + UINT32 ea = EA_AX_PD_16(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_16_pd_i(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_I_16(mc68kcpu); + UINT32 ea = EA_AX_PD_16(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_16_di_d(m68000_base_device* mc68kcpu) +{ + UINT32 res = MASK_OUT_ABOVE_16(DY(mc68kcpu)); + UINT32 ea = EA_AX_DI_16(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_16_di_a(m68000_base_device* mc68kcpu) +{ + UINT32 res = MASK_OUT_ABOVE_16(AY(mc68kcpu)); + UINT32 ea = EA_AX_DI_16(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_16_di_ai(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_AI_16(mc68kcpu); + UINT32 ea = EA_AX_DI_16(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_16_di_pi(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_PI_16(mc68kcpu); + UINT32 ea = EA_AX_DI_16(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_16_di_pd(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_PD_16(mc68kcpu); + UINT32 ea = EA_AX_DI_16(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_16_di_di(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_DI_16(mc68kcpu); + UINT32 ea = EA_AX_DI_16(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_16_di_ix(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_IX_16(mc68kcpu); + UINT32 ea = EA_AX_DI_16(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_16_di_aw(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AW_16(mc68kcpu); + UINT32 ea = EA_AX_DI_16(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_16_di_al(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AL_16(mc68kcpu); + UINT32 ea = EA_AX_DI_16(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_16_di_pcdi(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_PCDI_16(mc68kcpu); + UINT32 ea = EA_AX_DI_16(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_16_di_pcix(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_PCIX_16(mc68kcpu); + UINT32 ea = EA_AX_DI_16(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_16_di_i(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_I_16(mc68kcpu); + UINT32 ea = EA_AX_DI_16(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_16_ix_d(m68000_base_device* mc68kcpu) +{ + UINT32 res = MASK_OUT_ABOVE_16(DY(mc68kcpu)); + UINT32 ea = EA_AX_IX_16(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_16_ix_a(m68000_base_device* mc68kcpu) +{ + UINT32 res = MASK_OUT_ABOVE_16(AY(mc68kcpu)); + UINT32 ea = EA_AX_IX_16(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_16_ix_ai(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_AI_16(mc68kcpu); + UINT32 ea = EA_AX_IX_16(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_16_ix_pi(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_PI_16(mc68kcpu); + UINT32 ea = EA_AX_IX_16(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_16_ix_pd(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_PD_16(mc68kcpu); + UINT32 ea = EA_AX_IX_16(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_16_ix_di(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_DI_16(mc68kcpu); + UINT32 ea = EA_AX_IX_16(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_16_ix_ix(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_IX_16(mc68kcpu); + UINT32 ea = EA_AX_IX_16(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_16_ix_aw(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AW_16(mc68kcpu); + UINT32 ea = EA_AX_IX_16(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_16_ix_al(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AL_16(mc68kcpu); + UINT32 ea = EA_AX_IX_16(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_16_ix_pcdi(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_PCDI_16(mc68kcpu); + UINT32 ea = EA_AX_IX_16(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_16_ix_pcix(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_PCIX_16(mc68kcpu); + UINT32 ea = EA_AX_IX_16(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_16_ix_i(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_I_16(mc68kcpu); + UINT32 ea = EA_AX_IX_16(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_16_aw_d(m68000_base_device* mc68kcpu) +{ + UINT32 res = MASK_OUT_ABOVE_16(DY(mc68kcpu)); + UINT32 ea = EA_AW_16(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_16_aw_a(m68000_base_device* mc68kcpu) +{ + UINT32 res = MASK_OUT_ABOVE_16(AY(mc68kcpu)); + UINT32 ea = EA_AW_16(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_16_aw_ai(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_AI_16(mc68kcpu); + UINT32 ea = EA_AW_16(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_16_aw_pi(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_PI_16(mc68kcpu); + UINT32 ea = EA_AW_16(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_16_aw_pd(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_PD_16(mc68kcpu); + UINT32 ea = EA_AW_16(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_16_aw_di(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_DI_16(mc68kcpu); + UINT32 ea = EA_AW_16(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_16_aw_ix(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_IX_16(mc68kcpu); + UINT32 ea = EA_AW_16(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_16_aw_aw(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AW_16(mc68kcpu); + UINT32 ea = EA_AW_16(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_16_aw_al(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AL_16(mc68kcpu); + UINT32 ea = EA_AW_16(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_16_aw_pcdi(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_PCDI_16(mc68kcpu); + UINT32 ea = EA_AW_16(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_16_aw_pcix(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_PCIX_16(mc68kcpu); + UINT32 ea = EA_AW_16(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_16_aw_i(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_I_16(mc68kcpu); + UINT32 ea = EA_AW_16(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_16_al_d(m68000_base_device* mc68kcpu) +{ + UINT32 res = MASK_OUT_ABOVE_16(DY(mc68kcpu)); + UINT32 ea = EA_AL_16(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_16_al_a(m68000_base_device* mc68kcpu) +{ + UINT32 res = MASK_OUT_ABOVE_16(AY(mc68kcpu)); + UINT32 ea = EA_AL_16(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_16_al_ai(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_AI_16(mc68kcpu); + UINT32 ea = EA_AL_16(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_16_al_pi(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_PI_16(mc68kcpu); + UINT32 ea = EA_AL_16(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_16_al_pd(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_PD_16(mc68kcpu); + UINT32 ea = EA_AL_16(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_16_al_di(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_DI_16(mc68kcpu); + UINT32 ea = EA_AL_16(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_16_al_ix(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_IX_16(mc68kcpu); + UINT32 ea = EA_AL_16(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_16_al_aw(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AW_16(mc68kcpu); + UINT32 ea = EA_AL_16(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_16_al_al(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AL_16(mc68kcpu); + UINT32 ea = EA_AL_16(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_16_al_pcdi(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_PCDI_16(mc68kcpu); + UINT32 ea = EA_AL_16(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_16_al_pcix(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_PCIX_16(mc68kcpu); + UINT32 ea = EA_AL_16(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_16_al_i(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_I_16(mc68kcpu); + UINT32 ea = EA_AL_16(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_32_d_d(m68000_base_device* mc68kcpu) +{ + UINT32 res = DY(mc68kcpu); + UINT32* r_dst = &DX(mc68kcpu); + + *r_dst = res; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_32_d_a(m68000_base_device* mc68kcpu) +{ + UINT32 res = AY(mc68kcpu); + UINT32* r_dst = &DX(mc68kcpu); + + *r_dst = res; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_32_d_ai(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_AI_32(mc68kcpu); + UINT32* r_dst = &DX(mc68kcpu); + + *r_dst = res; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_32_d_pi(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_PI_32(mc68kcpu); + UINT32* r_dst = &DX(mc68kcpu); + + *r_dst = res; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_32_d_pd(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_PD_32(mc68kcpu); + UINT32* r_dst = &DX(mc68kcpu); + + *r_dst = res; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_32_d_di(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_DI_32(mc68kcpu); + UINT32* r_dst = &DX(mc68kcpu); + + *r_dst = res; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_32_d_ix(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_IX_32(mc68kcpu); + UINT32* r_dst = &DX(mc68kcpu); + + *r_dst = res; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_32_d_aw(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AW_32(mc68kcpu); + UINT32* r_dst = &DX(mc68kcpu); + + *r_dst = res; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_32_d_al(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AL_32(mc68kcpu); + UINT32* r_dst = &DX(mc68kcpu); + + *r_dst = res; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_32_d_pcdi(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_PCDI_32(mc68kcpu); + UINT32* r_dst = &DX(mc68kcpu); + + *r_dst = res; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_32_d_pcix(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_PCIX_32(mc68kcpu); + UINT32* r_dst = &DX(mc68kcpu); + + *r_dst = res; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_32_d_i(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_I_32(mc68kcpu); + UINT32* r_dst = &DX(mc68kcpu); + + *r_dst = res; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_32_ai_d(m68000_base_device* mc68kcpu) +{ + UINT32 res = DY(mc68kcpu); + UINT32 ea = EA_AX_AI_32(mc68kcpu); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_32_ai_a(m68000_base_device* mc68kcpu) +{ + UINT32 res = AY(mc68kcpu); + UINT32 ea = EA_AX_AI_32(mc68kcpu); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_32_ai_ai(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_AI_32(mc68kcpu); + UINT32 ea = EA_AX_AI_32(mc68kcpu); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_32_ai_pi(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_PI_32(mc68kcpu); + UINT32 ea = EA_AX_AI_32(mc68kcpu); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_32_ai_pd(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_PD_32(mc68kcpu); + UINT32 ea = EA_AX_AI_32(mc68kcpu); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_32_ai_di(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_DI_32(mc68kcpu); + UINT32 ea = EA_AX_AI_32(mc68kcpu); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_32_ai_ix(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_IX_32(mc68kcpu); + UINT32 ea = EA_AX_AI_32(mc68kcpu); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_32_ai_aw(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AW_32(mc68kcpu); + UINT32 ea = EA_AX_AI_32(mc68kcpu); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_32_ai_al(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AL_32(mc68kcpu); + UINT32 ea = EA_AX_AI_32(mc68kcpu); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_32_ai_pcdi(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_PCDI_32(mc68kcpu); + UINT32 ea = EA_AX_AI_32(mc68kcpu); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_32_ai_pcix(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_PCIX_32(mc68kcpu); + UINT32 ea = EA_AX_AI_32(mc68kcpu); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_32_ai_i(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_I_32(mc68kcpu); + UINT32 ea = EA_AX_AI_32(mc68kcpu); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_32_pi_d(m68000_base_device* mc68kcpu) +{ + UINT32 res = DY(mc68kcpu); + UINT32 ea = EA_AX_PI_32(mc68kcpu); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_32_pi_a(m68000_base_device* mc68kcpu) +{ + UINT32 res = AY(mc68kcpu); + UINT32 ea = EA_AX_PI_32(mc68kcpu); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_32_pi_ai(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_AI_32(mc68kcpu); + UINT32 ea = EA_AX_PI_32(mc68kcpu); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_32_pi_pi(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_PI_32(mc68kcpu); + UINT32 ea = EA_AX_PI_32(mc68kcpu); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_32_pi_pd(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_PD_32(mc68kcpu); + UINT32 ea = EA_AX_PI_32(mc68kcpu); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_32_pi_di(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_DI_32(mc68kcpu); + UINT32 ea = EA_AX_PI_32(mc68kcpu); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_32_pi_ix(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_IX_32(mc68kcpu); + UINT32 ea = EA_AX_PI_32(mc68kcpu); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_32_pi_aw(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AW_32(mc68kcpu); + UINT32 ea = EA_AX_PI_32(mc68kcpu); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_32_pi_al(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AL_32(mc68kcpu); + UINT32 ea = EA_AX_PI_32(mc68kcpu); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_32_pi_pcdi(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_PCDI_32(mc68kcpu); + UINT32 ea = EA_AX_PI_32(mc68kcpu); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_32_pi_pcix(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_PCIX_32(mc68kcpu); + UINT32 ea = EA_AX_PI_32(mc68kcpu); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_32_pi_i(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_I_32(mc68kcpu); + UINT32 ea = EA_AX_PI_32(mc68kcpu); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_32_pd_d(m68000_base_device* mc68kcpu) +{ + UINT32 res = DY(mc68kcpu); + UINT32 ea = EA_AX_PD_32(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea+2, res & 0xFFFF ); + m68ki_write_16((mc68kcpu), ea, (res >> 16) & 0xFFFF ); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_32_pd_a(m68000_base_device* mc68kcpu) +{ + UINT32 res = AY(mc68kcpu); + UINT32 ea = EA_AX_PD_32(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea+2, res & 0xFFFF ); + m68ki_write_16((mc68kcpu), ea, (res >> 16) & 0xFFFF ); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_32_pd_ai(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_AI_32(mc68kcpu); + UINT32 ea = EA_AX_PD_32(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea+2, res & 0xFFFF ); + m68ki_write_16((mc68kcpu), ea, (res >> 16) & 0xFFFF ); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_32_pd_pi(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_PI_32(mc68kcpu); + UINT32 ea = EA_AX_PD_32(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea+2, res & 0xFFFF ); + m68ki_write_16((mc68kcpu), ea, (res >> 16) & 0xFFFF ); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_32_pd_pd(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_PD_32(mc68kcpu); + UINT32 ea = EA_AX_PD_32(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea+2, res & 0xFFFF ); + m68ki_write_16((mc68kcpu), ea, (res >> 16) & 0xFFFF ); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_32_pd_di(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_DI_32(mc68kcpu); + UINT32 ea = EA_AX_PD_32(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea+2, res & 0xFFFF ); + m68ki_write_16((mc68kcpu), ea, (res >> 16) & 0xFFFF ); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_32_pd_ix(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_IX_32(mc68kcpu); + UINT32 ea = EA_AX_PD_32(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea+2, res & 0xFFFF ); + m68ki_write_16((mc68kcpu), ea, (res >> 16) & 0xFFFF ); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_32_pd_aw(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AW_32(mc68kcpu); + UINT32 ea = EA_AX_PD_32(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea+2, res & 0xFFFF ); + m68ki_write_16((mc68kcpu), ea, (res >> 16) & 0xFFFF ); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_32_pd_al(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AL_32(mc68kcpu); + UINT32 ea = EA_AX_PD_32(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea+2, res & 0xFFFF ); + m68ki_write_16((mc68kcpu), ea, (res >> 16) & 0xFFFF ); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_32_pd_pcdi(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_PCDI_32(mc68kcpu); + UINT32 ea = EA_AX_PD_32(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea+2, res & 0xFFFF ); + m68ki_write_16((mc68kcpu), ea, (res >> 16) & 0xFFFF ); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_32_pd_pcix(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_PCIX_32(mc68kcpu); + UINT32 ea = EA_AX_PD_32(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea+2, res & 0xFFFF ); + m68ki_write_16((mc68kcpu), ea, (res >> 16) & 0xFFFF ); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_32_pd_i(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_I_32(mc68kcpu); + UINT32 ea = EA_AX_PD_32(mc68kcpu); + + m68ki_write_16((mc68kcpu), ea+2, res & 0xFFFF ); + m68ki_write_16((mc68kcpu), ea, (res >> 16) & 0xFFFF ); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_32_di_d(m68000_base_device* mc68kcpu) +{ + UINT32 res = DY(mc68kcpu); + UINT32 ea = EA_AX_DI_32(mc68kcpu); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_32_di_a(m68000_base_device* mc68kcpu) +{ + UINT32 res = AY(mc68kcpu); + UINT32 ea = EA_AX_DI_32(mc68kcpu); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_32_di_ai(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_AI_32(mc68kcpu); + UINT32 ea = EA_AX_DI_32(mc68kcpu); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_32_di_pi(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_PI_32(mc68kcpu); + UINT32 ea = EA_AX_DI_32(mc68kcpu); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_32_di_pd(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_PD_32(mc68kcpu); + UINT32 ea = EA_AX_DI_32(mc68kcpu); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_32_di_di(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_DI_32(mc68kcpu); + UINT32 ea = EA_AX_DI_32(mc68kcpu); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_32_di_ix(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_IX_32(mc68kcpu); + UINT32 ea = EA_AX_DI_32(mc68kcpu); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_32_di_aw(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AW_32(mc68kcpu); + UINT32 ea = EA_AX_DI_32(mc68kcpu); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_32_di_al(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AL_32(mc68kcpu); + UINT32 ea = EA_AX_DI_32(mc68kcpu); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_32_di_pcdi(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_PCDI_32(mc68kcpu); + UINT32 ea = EA_AX_DI_32(mc68kcpu); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_32_di_pcix(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_PCIX_32(mc68kcpu); + UINT32 ea = EA_AX_DI_32(mc68kcpu); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_32_di_i(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_I_32(mc68kcpu); + UINT32 ea = EA_AX_DI_32(mc68kcpu); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_32_ix_d(m68000_base_device* mc68kcpu) +{ + UINT32 res = DY(mc68kcpu); + UINT32 ea = EA_AX_IX_32(mc68kcpu); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_32_ix_a(m68000_base_device* mc68kcpu) +{ + UINT32 res = AY(mc68kcpu); + UINT32 ea = EA_AX_IX_32(mc68kcpu); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_32_ix_ai(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_AI_32(mc68kcpu); + UINT32 ea = EA_AX_IX_32(mc68kcpu); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_32_ix_pi(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_PI_32(mc68kcpu); + UINT32 ea = EA_AX_IX_32(mc68kcpu); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_32_ix_pd(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_PD_32(mc68kcpu); + UINT32 ea = EA_AX_IX_32(mc68kcpu); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_32_ix_di(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_DI_32(mc68kcpu); + UINT32 ea = EA_AX_IX_32(mc68kcpu); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_32_ix_ix(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_IX_32(mc68kcpu); + UINT32 ea = EA_AX_IX_32(mc68kcpu); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_32_ix_aw(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AW_32(mc68kcpu); + UINT32 ea = EA_AX_IX_32(mc68kcpu); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_32_ix_al(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AL_32(mc68kcpu); + UINT32 ea = EA_AX_IX_32(mc68kcpu); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_32_ix_pcdi(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_PCDI_32(mc68kcpu); + UINT32 ea = EA_AX_IX_32(mc68kcpu); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_32_ix_pcix(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_PCIX_32(mc68kcpu); + UINT32 ea = EA_AX_IX_32(mc68kcpu); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_32_ix_i(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_I_32(mc68kcpu); + UINT32 ea = EA_AX_IX_32(mc68kcpu); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_32_aw_d(m68000_base_device* mc68kcpu) +{ + UINT32 res = DY(mc68kcpu); + UINT32 ea = EA_AW_32(mc68kcpu); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_32_aw_a(m68000_base_device* mc68kcpu) +{ + UINT32 res = AY(mc68kcpu); + UINT32 ea = EA_AW_32(mc68kcpu); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_32_aw_ai(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_AI_32(mc68kcpu); + UINT32 ea = EA_AW_32(mc68kcpu); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_32_aw_pi(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_PI_32(mc68kcpu); + UINT32 ea = EA_AW_32(mc68kcpu); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_32_aw_pd(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_PD_32(mc68kcpu); + UINT32 ea = EA_AW_32(mc68kcpu); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_32_aw_di(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_DI_32(mc68kcpu); + UINT32 ea = EA_AW_32(mc68kcpu); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_32_aw_ix(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_IX_32(mc68kcpu); + UINT32 ea = EA_AW_32(mc68kcpu); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_32_aw_aw(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AW_32(mc68kcpu); + UINT32 ea = EA_AW_32(mc68kcpu); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_32_aw_al(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AL_32(mc68kcpu); + UINT32 ea = EA_AW_32(mc68kcpu); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_32_aw_pcdi(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_PCDI_32(mc68kcpu); + UINT32 ea = EA_AW_32(mc68kcpu); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_32_aw_pcix(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_PCIX_32(mc68kcpu); + UINT32 ea = EA_AW_32(mc68kcpu); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_32_aw_i(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_I_32(mc68kcpu); + UINT32 ea = EA_AW_32(mc68kcpu); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_32_al_d(m68000_base_device* mc68kcpu) +{ + UINT32 res = DY(mc68kcpu); + UINT32 ea = EA_AL_32(mc68kcpu); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_32_al_a(m68000_base_device* mc68kcpu) +{ + UINT32 res = AY(mc68kcpu); + UINT32 ea = EA_AL_32(mc68kcpu); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_32_al_ai(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_AI_32(mc68kcpu); + UINT32 ea = EA_AL_32(mc68kcpu); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_32_al_pi(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_PI_32(mc68kcpu); + UINT32 ea = EA_AL_32(mc68kcpu); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_32_al_pd(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_PD_32(mc68kcpu); + UINT32 ea = EA_AL_32(mc68kcpu); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_32_al_di(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_DI_32(mc68kcpu); + UINT32 ea = EA_AL_32(mc68kcpu); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_32_al_ix(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_IX_32(mc68kcpu); + UINT32 ea = EA_AL_32(mc68kcpu); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_32_al_aw(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AW_32(mc68kcpu); + UINT32 ea = EA_AL_32(mc68kcpu); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_32_al_al(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AL_32(mc68kcpu); + UINT32 ea = EA_AL_32(mc68kcpu); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_32_al_pcdi(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_PCDI_32(mc68kcpu); + UINT32 ea = EA_AL_32(mc68kcpu); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_32_al_pcix(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_PCIX_32(mc68kcpu); + UINT32 ea = EA_AL_32(mc68kcpu); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move_32_al_i(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_I_32(mc68kcpu); + UINT32 ea = EA_AL_32(mc68kcpu); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_movea_16_d(m68000_base_device* mc68kcpu) +{ + AX(mc68kcpu) = MAKE_INT_16(DY(mc68kcpu)); +} + + +void m68000_base_device_ops::m68k_op_movea_16_a(m68000_base_device* mc68kcpu) +{ + AX(mc68kcpu) = MAKE_INT_16(AY(mc68kcpu)); +} + + +void m68000_base_device_ops::m68k_op_movea_16_ai(m68000_base_device* mc68kcpu) +{ + AX(mc68kcpu) = MAKE_INT_16(OPER_AY_AI_16(mc68kcpu)); +} + + +void m68000_base_device_ops::m68k_op_movea_16_pi(m68000_base_device* mc68kcpu) +{ + AX(mc68kcpu) = MAKE_INT_16(OPER_AY_PI_16(mc68kcpu)); +} + + +void m68000_base_device_ops::m68k_op_movea_16_pd(m68000_base_device* mc68kcpu) +{ + AX(mc68kcpu) = MAKE_INT_16(OPER_AY_PD_16(mc68kcpu)); +} + + +void m68000_base_device_ops::m68k_op_movea_16_di(m68000_base_device* mc68kcpu) +{ + AX(mc68kcpu) = MAKE_INT_16(OPER_AY_DI_16(mc68kcpu)); +} + + +void m68000_base_device_ops::m68k_op_movea_16_ix(m68000_base_device* mc68kcpu) +{ + AX(mc68kcpu) = MAKE_INT_16(OPER_AY_IX_16(mc68kcpu)); +} + + +void m68000_base_device_ops::m68k_op_movea_16_aw(m68000_base_device* mc68kcpu) +{ + AX(mc68kcpu) = MAKE_INT_16(OPER_AW_16(mc68kcpu)); +} + + +void m68000_base_device_ops::m68k_op_movea_16_al(m68000_base_device* mc68kcpu) +{ + AX(mc68kcpu) = MAKE_INT_16(OPER_AL_16(mc68kcpu)); +} + + +void m68000_base_device_ops::m68k_op_movea_16_pcdi(m68000_base_device* mc68kcpu) +{ + AX(mc68kcpu) = MAKE_INT_16(OPER_PCDI_16(mc68kcpu)); +} + + +void m68000_base_device_ops::m68k_op_movea_16_pcix(m68000_base_device* mc68kcpu) +{ + AX(mc68kcpu) = MAKE_INT_16(OPER_PCIX_16(mc68kcpu)); +} + + +void m68000_base_device_ops::m68k_op_movea_16_i(m68000_base_device* mc68kcpu) +{ + AX(mc68kcpu) = MAKE_INT_16(OPER_I_16(mc68kcpu)); +} + + +void m68000_base_device_ops::m68k_op_movea_32_d(m68000_base_device* mc68kcpu) +{ + AX(mc68kcpu) = DY(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_movea_32_a(m68000_base_device* mc68kcpu) +{ + AX(mc68kcpu) = AY(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_movea_32_ai(m68000_base_device* mc68kcpu) +{ + AX(mc68kcpu) = OPER_AY_AI_32(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_movea_32_pi(m68000_base_device* mc68kcpu) +{ + AX(mc68kcpu) = OPER_AY_PI_32(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_movea_32_pd(m68000_base_device* mc68kcpu) +{ + AX(mc68kcpu) = OPER_AY_PD_32(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_movea_32_di(m68000_base_device* mc68kcpu) +{ + AX(mc68kcpu) = OPER_AY_DI_32(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_movea_32_ix(m68000_base_device* mc68kcpu) +{ + AX(mc68kcpu) = OPER_AY_IX_32(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_movea_32_aw(m68000_base_device* mc68kcpu) +{ + AX(mc68kcpu) = OPER_AW_32(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_movea_32_al(m68000_base_device* mc68kcpu) +{ + AX(mc68kcpu) = OPER_AL_32(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_movea_32_pcdi(m68000_base_device* mc68kcpu) +{ + AX(mc68kcpu) = OPER_PCDI_32(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_movea_32_pcix(m68000_base_device* mc68kcpu) +{ + AX(mc68kcpu) = OPER_PCIX_32(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_movea_32_i(m68000_base_device* mc68kcpu) +{ + AX(mc68kcpu) = OPER_I_32(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_move_16_frc_d(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_010_PLUS((mc68kcpu)->cpu_type)) + { + DY(mc68kcpu) = MASK_OUT_BELOW_16(DY(mc68kcpu)) | m68ki_get_ccr(mc68kcpu); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_move_16_frc_ai(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_010_PLUS((mc68kcpu)->cpu_type)) + { + m68ki_write_16((mc68kcpu), EA_AY_AI_16(mc68kcpu), m68ki_get_ccr(mc68kcpu)); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_move_16_frc_pi(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_010_PLUS((mc68kcpu)->cpu_type)) + { + m68ki_write_16((mc68kcpu), EA_AY_PI_16(mc68kcpu), m68ki_get_ccr(mc68kcpu)); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_move_16_frc_pd(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_010_PLUS((mc68kcpu)->cpu_type)) + { + m68ki_write_16((mc68kcpu), EA_AY_PD_16(mc68kcpu), m68ki_get_ccr(mc68kcpu)); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_move_16_frc_di(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_010_PLUS((mc68kcpu)->cpu_type)) + { + m68ki_write_16((mc68kcpu), EA_AY_DI_16(mc68kcpu), m68ki_get_ccr(mc68kcpu)); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_move_16_frc_ix(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_010_PLUS((mc68kcpu)->cpu_type)) + { + m68ki_write_16((mc68kcpu), EA_AY_IX_16(mc68kcpu), m68ki_get_ccr(mc68kcpu)); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_move_16_frc_aw(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_010_PLUS((mc68kcpu)->cpu_type)) + { + m68ki_write_16((mc68kcpu), EA_AW_16(mc68kcpu), m68ki_get_ccr(mc68kcpu)); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_move_16_frc_al(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_010_PLUS((mc68kcpu)->cpu_type)) + { + m68ki_write_16((mc68kcpu), EA_AL_16(mc68kcpu), m68ki_get_ccr(mc68kcpu)); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_move_16_toc_d(m68000_base_device* mc68kcpu) +{ + m68ki_set_ccr((mc68kcpu), DY(mc68kcpu)); +} + + +void m68000_base_device_ops::m68k_op_move_16_toc_ai(m68000_base_device* mc68kcpu) +{ + m68ki_set_ccr((mc68kcpu), OPER_AY_AI_16(mc68kcpu)); +} + + +void m68000_base_device_ops::m68k_op_move_16_toc_pi(m68000_base_device* mc68kcpu) +{ + m68ki_set_ccr((mc68kcpu), OPER_AY_PI_16(mc68kcpu)); +} + + +void m68000_base_device_ops::m68k_op_move_16_toc_pd(m68000_base_device* mc68kcpu) +{ + m68ki_set_ccr((mc68kcpu), OPER_AY_PD_16(mc68kcpu)); +} + + +void m68000_base_device_ops::m68k_op_move_16_toc_di(m68000_base_device* mc68kcpu) +{ + m68ki_set_ccr((mc68kcpu), OPER_AY_DI_16(mc68kcpu)); +} + + +void m68000_base_device_ops::m68k_op_move_16_toc_ix(m68000_base_device* mc68kcpu) +{ + m68ki_set_ccr((mc68kcpu), OPER_AY_IX_16(mc68kcpu)); +} + + +void m68000_base_device_ops::m68k_op_move_16_toc_aw(m68000_base_device* mc68kcpu) +{ + m68ki_set_ccr((mc68kcpu), OPER_AW_16(mc68kcpu)); +} + + +void m68000_base_device_ops::m68k_op_move_16_toc_al(m68000_base_device* mc68kcpu) +{ + m68ki_set_ccr((mc68kcpu), OPER_AL_16(mc68kcpu)); +} + + +void m68000_base_device_ops::m68k_op_move_16_toc_pcdi(m68000_base_device* mc68kcpu) +{ + m68ki_set_ccr((mc68kcpu), OPER_PCDI_16(mc68kcpu)); +} + + +void m68000_base_device_ops::m68k_op_move_16_toc_pcix(m68000_base_device* mc68kcpu) +{ + m68ki_set_ccr((mc68kcpu), OPER_PCIX_16(mc68kcpu)); +} + + +void m68000_base_device_ops::m68k_op_move_16_toc_i(m68000_base_device* mc68kcpu) +{ + m68ki_set_ccr((mc68kcpu), OPER_I_16(mc68kcpu)); +} + + +void m68000_base_device_ops::m68k_op_move_16_frs_d(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_000((mc68kcpu)->cpu_type) || (mc68kcpu)->s_flag) /* NS990408 */ + { + DY(mc68kcpu) = MASK_OUT_BELOW_16(DY(mc68kcpu)) | m68ki_get_sr(mc68kcpu); + return; + } + m68ki_exception_privilege_violation(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_move_16_frs_ai(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_000((mc68kcpu)->cpu_type) || (mc68kcpu)->s_flag) /* NS990408 */ + { + UINT32 ea = EA_AY_AI_16(mc68kcpu); + m68ki_write_16((mc68kcpu), ea, m68ki_get_sr(mc68kcpu)); + return; + } + m68ki_exception_privilege_violation(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_move_16_frs_pi(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_000((mc68kcpu)->cpu_type) || (mc68kcpu)->s_flag) /* NS990408 */ + { + UINT32 ea = EA_AY_PI_16(mc68kcpu); + m68ki_write_16((mc68kcpu), ea, m68ki_get_sr(mc68kcpu)); + return; + } + m68ki_exception_privilege_violation(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_move_16_frs_pd(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_000((mc68kcpu)->cpu_type) || (mc68kcpu)->s_flag) /* NS990408 */ + { + UINT32 ea = EA_AY_PD_16(mc68kcpu); + m68ki_write_16((mc68kcpu), ea, m68ki_get_sr(mc68kcpu)); + return; + } + m68ki_exception_privilege_violation(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_move_16_frs_di(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_000((mc68kcpu)->cpu_type) || (mc68kcpu)->s_flag) /* NS990408 */ + { + UINT32 ea = EA_AY_DI_16(mc68kcpu); + m68ki_write_16((mc68kcpu), ea, m68ki_get_sr(mc68kcpu)); + return; + } + m68ki_exception_privilege_violation(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_move_16_frs_ix(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_000((mc68kcpu)->cpu_type) || (mc68kcpu)->s_flag) /* NS990408 */ + { + UINT32 ea = EA_AY_IX_16(mc68kcpu); + m68ki_write_16((mc68kcpu), ea, m68ki_get_sr(mc68kcpu)); + return; + } + m68ki_exception_privilege_violation(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_move_16_frs_aw(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_000((mc68kcpu)->cpu_type) || (mc68kcpu)->s_flag) /* NS990408 */ + { + UINT32 ea = EA_AW_16(mc68kcpu); + m68ki_write_16((mc68kcpu), ea, m68ki_get_sr(mc68kcpu)); + return; + } + m68ki_exception_privilege_violation(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_move_16_frs_al(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_000((mc68kcpu)->cpu_type) || (mc68kcpu)->s_flag) /* NS990408 */ + { + UINT32 ea = EA_AL_16(mc68kcpu); + m68ki_write_16((mc68kcpu), ea, m68ki_get_sr(mc68kcpu)); + return; + } + m68ki_exception_privilege_violation(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_move_16_tos_d(m68000_base_device* mc68kcpu) +{ + if((mc68kcpu)->s_flag) + { + m68ki_set_sr((mc68kcpu), DY(mc68kcpu)); + return; + } + m68ki_exception_privilege_violation(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_move_16_tos_ai(m68000_base_device* mc68kcpu) +{ + if((mc68kcpu)->s_flag) + { + UINT32 new_sr = OPER_AY_AI_16(mc68kcpu); + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_set_sr((mc68kcpu), new_sr); + return; + } + m68ki_exception_privilege_violation(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_move_16_tos_pi(m68000_base_device* mc68kcpu) +{ + if((mc68kcpu)->s_flag) + { + UINT32 new_sr = OPER_AY_PI_16(mc68kcpu); + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_set_sr((mc68kcpu), new_sr); + return; + } + m68ki_exception_privilege_violation(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_move_16_tos_pd(m68000_base_device* mc68kcpu) +{ + if((mc68kcpu)->s_flag) + { + UINT32 new_sr = OPER_AY_PD_16(mc68kcpu); + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_set_sr((mc68kcpu), new_sr); + return; + } + m68ki_exception_privilege_violation(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_move_16_tos_di(m68000_base_device* mc68kcpu) +{ + if((mc68kcpu)->s_flag) + { + UINT32 new_sr = OPER_AY_DI_16(mc68kcpu); + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_set_sr((mc68kcpu), new_sr); + return; + } + m68ki_exception_privilege_violation(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_move_16_tos_ix(m68000_base_device* mc68kcpu) +{ + if((mc68kcpu)->s_flag) + { + UINT32 new_sr = OPER_AY_IX_16(mc68kcpu); + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_set_sr((mc68kcpu), new_sr); + return; + } + m68ki_exception_privilege_violation(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_move_16_tos_aw(m68000_base_device* mc68kcpu) +{ + if((mc68kcpu)->s_flag) + { + UINT32 new_sr = OPER_AW_16(mc68kcpu); + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_set_sr((mc68kcpu), new_sr); + return; + } + m68ki_exception_privilege_violation(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_move_16_tos_al(m68000_base_device* mc68kcpu) +{ + if((mc68kcpu)->s_flag) + { + UINT32 new_sr = OPER_AL_16(mc68kcpu); + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_set_sr((mc68kcpu), new_sr); + return; + } + m68ki_exception_privilege_violation(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_move_16_tos_pcdi(m68000_base_device* mc68kcpu) +{ + if((mc68kcpu)->s_flag) + { + UINT32 new_sr = OPER_PCDI_16(mc68kcpu); + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_set_sr((mc68kcpu), new_sr); + return; + } + m68ki_exception_privilege_violation(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_move_16_tos_pcix(m68000_base_device* mc68kcpu) +{ + if((mc68kcpu)->s_flag) + { + UINT32 new_sr = OPER_PCIX_16(mc68kcpu); + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_set_sr((mc68kcpu), new_sr); + return; + } + m68ki_exception_privilege_violation(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_move_16_tos_i(m68000_base_device* mc68kcpu) +{ + if((mc68kcpu)->s_flag) + { + UINT32 new_sr = OPER_I_16(mc68kcpu); + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_set_sr((mc68kcpu), new_sr); + return; + } + m68ki_exception_privilege_violation(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_move_32_fru(m68000_base_device* mc68kcpu) +{ + if((mc68kcpu)->s_flag) + { + AY(mc68kcpu) = REG_USP(mc68kcpu); + return; + } + m68ki_exception_privilege_violation(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_move_32_tou(m68000_base_device* mc68kcpu) +{ + if((mc68kcpu)->s_flag) + { + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + REG_USP(mc68kcpu) = AY(mc68kcpu); + return; + } + m68ki_exception_privilege_violation(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_movec_32_cr(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_010_PLUS((mc68kcpu)->cpu_type)) + { + if((mc68kcpu)->s_flag) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + switch (word2 & 0xfff) + { + case 0x000: /* SFC */ + REG_DA(mc68kcpu)[(word2 >> 12) & 15] = (mc68kcpu)->sfc; + return; + case 0x001: /* DFC */ + REG_DA(mc68kcpu)[(word2 >> 12) & 15] = (mc68kcpu)->dfc; + return; + case 0x002: /* CACR */ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + REG_DA(mc68kcpu)[(word2 >> 12) & 15] = (mc68kcpu)->cacr; + return; + } + return; + case 0x800: /* USP */ + REG_DA(mc68kcpu)[(word2 >> 12) & 15] = REG_USP(mc68kcpu); + return; + case 0x801: /* VBR */ + REG_DA(mc68kcpu)[(word2 >> 12) & 15] = (mc68kcpu)->vbr; + return; + case 0x802: /* CAAR */ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + REG_DA(mc68kcpu)[(word2 >> 12) & 15] = (mc68kcpu)->caar; + return; + } + m68ki_exception_illegal(mc68kcpu); + break; + case 0x803: /* MSP */ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + REG_DA(mc68kcpu)[(word2 >> 12) & 15] = (mc68kcpu)->m_flag ? REG_SP(mc68kcpu) : REG_MSP(mc68kcpu); + return; + } + m68ki_exception_illegal(mc68kcpu); + return; + case 0x804: /* ISP */ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + REG_DA(mc68kcpu)[(word2 >> 12) & 15] = (mc68kcpu)->m_flag ? REG_ISP(mc68kcpu) : REG_SP(mc68kcpu); + return; + } + m68ki_exception_illegal(mc68kcpu); + return; + case 0x003: /* TC */ + if(CPU_TYPE_IS_040_PLUS((mc68kcpu)->cpu_type)) + { + REG_DA(mc68kcpu)[(word2 >> 12) & 15] = mc68kcpu->mmu_tc; + return; + } + m68ki_exception_illegal(mc68kcpu); + return; + case 0x004: /* ITT0 (040+, ACR0 on ColdFire) */ + if(CPU_TYPE_IS_040_PLUS((mc68kcpu)->cpu_type)) + { + REG_DA(mc68kcpu)[(word2 >> 12) & 15] = mc68kcpu->mmu_itt0; + return; + } + else if(CPU_TYPE_IS_COLDFIRE((mc68kcpu)->cpu_type)) + { + REG_DA(mc68kcpu)[(word2 >> 12) & 15] = mc68kcpu->mmu_acr0; + return; + } + m68ki_exception_illegal(mc68kcpu); + return; + case 0x005: /* ITT1 (040+, ACR1 on ColdFire) */ + if(CPU_TYPE_IS_040_PLUS((mc68kcpu)->cpu_type)) + { + REG_DA(mc68kcpu)[(word2 >> 12) & 15] = mc68kcpu->mmu_itt1; + return; + } + else if(CPU_TYPE_IS_COLDFIRE((mc68kcpu)->cpu_type)) + { + REG_DA(mc68kcpu)[(word2 >> 12) & 15] = mc68kcpu->mmu_acr1; + return; + } + m68ki_exception_illegal(mc68kcpu); + return; + case 0x006: /* DTT0 */ + if(CPU_TYPE_IS_040_PLUS((mc68kcpu)->cpu_type)) + { + REG_DA(mc68kcpu)[(word2 >> 12) & 15] = mc68kcpu->mmu_dtt0; + return; + } + else if(CPU_TYPE_IS_COLDFIRE((mc68kcpu)->cpu_type)) + { + REG_DA(mc68kcpu)[(word2 >> 12) & 15] = mc68kcpu->mmu_acr2; + return; + } + m68ki_exception_illegal(mc68kcpu); + return; + case 0x007: /* DTT1 */ + if(CPU_TYPE_IS_040_PLUS((mc68kcpu)->cpu_type)) + { + REG_DA(mc68kcpu)[(word2 >> 12) & 15] = mc68kcpu->mmu_dtt1; + return; + } + else if(CPU_TYPE_IS_COLDFIRE((mc68kcpu)->cpu_type)) + { + REG_DA(mc68kcpu)[(word2 >> 12) & 15] = mc68kcpu->mmu_acr3; + return; + } + m68ki_exception_illegal(mc68kcpu); + return; + case 0x805: /* MMUSR */ + if(CPU_TYPE_IS_040_PLUS((mc68kcpu)->cpu_type)) + { + REG_DA(mc68kcpu)[(word2 >> 12) & 15] = mc68kcpu->mmu_sr_040; + return; + } + m68ki_exception_illegal(mc68kcpu); + return; + case 0x806: /* URP */ + if(CPU_TYPE_IS_040_PLUS((mc68kcpu)->cpu_type)) + { + REG_DA(mc68kcpu)[(word2 >> 12) & 15] = mc68kcpu->mmu_urp_aptr; + return; + } + m68ki_exception_illegal(mc68kcpu); + return; + case 0x807: /* SRP */ + if(CPU_TYPE_IS_040_PLUS((mc68kcpu)->cpu_type)) + { + REG_DA(mc68kcpu)[(word2 >> 12) & 15] = mc68kcpu->mmu_srp_aptr; + return; + } + m68ki_exception_illegal(mc68kcpu); + return; + case 0xc00: // ROMBAR0 + if(CPU_TYPE_IS_COLDFIRE((mc68kcpu)->cpu_type)) + { + /* TODO */ + return; + } + m68ki_exception_illegal(mc68kcpu); + return; + case 0xc01: // ROMBAR1 + if(CPU_TYPE_IS_COLDFIRE((mc68kcpu)->cpu_type)) + { + /* TODO */ + return; + } + m68ki_exception_illegal(mc68kcpu); + return; + case 0xc04: // RAMBAR0 + if(CPU_TYPE_IS_COLDFIRE((mc68kcpu)->cpu_type)) + { + /* TODO */ + return; + } + m68ki_exception_illegal(mc68kcpu); + return; + case 0xc05: // RAMBAR1 + if(CPU_TYPE_IS_COLDFIRE((mc68kcpu)->cpu_type)) + { + /* TODO */ + return; + } + m68ki_exception_illegal(mc68kcpu); + return; + case 0xc0c: // MPCR + if(CPU_TYPE_IS_COLDFIRE((mc68kcpu)->cpu_type)) + { + /* TODO */ + return; + } + m68ki_exception_illegal(mc68kcpu); + return; + case 0xc0d: // EDRAMBAR + if(CPU_TYPE_IS_COLDFIRE((mc68kcpu)->cpu_type)) + { + /* TODO */ + return; + } + m68ki_exception_illegal(mc68kcpu); + return; + case 0xc0e: // SECMBAR + if(CPU_TYPE_IS_COLDFIRE((mc68kcpu)->cpu_type)) + { + /* TODO */ + return; + } + m68ki_exception_illegal(mc68kcpu); + return; + case 0xc0f: // MBAR + if(CPU_TYPE_IS_COLDFIRE((mc68kcpu)->cpu_type)) + { + /* TODO */ + return; + } + m68ki_exception_illegal(mc68kcpu); + return; + default: + m68ki_exception_illegal(mc68kcpu); + return; + } + } + m68ki_exception_privilege_violation(mc68kcpu); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_movec_32_rc(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_010_PLUS((mc68kcpu)->cpu_type)) + { + if((mc68kcpu)->s_flag) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + switch (word2 & 0xfff) + { + case 0x000: /* SFC */ + (mc68kcpu)->sfc = REG_DA(mc68kcpu)[(word2 >> 12) & 15] & 7; + return; + case 0x001: /* DFC */ + (mc68kcpu)->dfc = REG_DA(mc68kcpu)[(word2 >> 12) & 15] & 7; + return; + case 0x002: /* CACR */ + /* Only EC020 and later have CACR */ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + /* 68030 can write all bits except 5-7, 040 can write all */ + if (CPU_TYPE_IS_040_PLUS((mc68kcpu)->cpu_type)) + { + (mc68kcpu)->cacr = REG_DA(mc68kcpu)[(word2 >> 12) & 15]; + } + else if (CPU_TYPE_IS_030_PLUS((mc68kcpu)->cpu_type)) + { + (mc68kcpu)->cacr = REG_DA(mc68kcpu)[(word2 >> 12) & 15] & 0xff1f; + } + else + { + (mc68kcpu)->cacr = REG_DA(mc68kcpu)[(word2 >> 12) & 15] & 0x0f; + } + +// logerror("movec to cacr=%04x\n", (mc68kcpu)->cacr); + if ((mc68kcpu)->cacr & (M68K_CACR_CI | M68K_CACR_CEI)) + { + m68ki_ic_clear(mc68kcpu); + } + return; + } + m68ki_exception_illegal(mc68kcpu); + return; + case 0x800: /* USP */ + REG_USP(mc68kcpu) = REG_DA(mc68kcpu)[(word2 >> 12) & 15]; + return; + case 0x801: /* VBR */ + (mc68kcpu)->vbr = REG_DA(mc68kcpu)[(word2 >> 12) & 15]; + return; + case 0x802: /* CAAR */ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + (mc68kcpu)->caar = REG_DA(mc68kcpu)[(word2 >> 12) & 15]; + return; + } + m68ki_exception_illegal(mc68kcpu); + return; + case 0x803: /* MSP */ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + /* we are in supervisor mode so just check for M flag */ + if(!(mc68kcpu)->m_flag) + { + REG_MSP(mc68kcpu) = REG_DA(mc68kcpu)[(word2 >> 12) & 15]; + return; + } + REG_SP(mc68kcpu) = REG_DA(mc68kcpu)[(word2 >> 12) & 15]; + return; + } + m68ki_exception_illegal(mc68kcpu); + return; + case 0x804: /* ISP */ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + if(!(mc68kcpu)->m_flag) + { + REG_SP(mc68kcpu) = REG_DA(mc68kcpu)[(word2 >> 12) & 15]; + return; + } + REG_ISP(mc68kcpu) = REG_DA(mc68kcpu)[(word2 >> 12) & 15]; + return; + } + m68ki_exception_illegal(mc68kcpu); + return; + case 0x003: /* TC */ + if (CPU_TYPE_IS_040_PLUS((mc68kcpu)->cpu_type)) + { + mc68kcpu->mmu_tc = REG_DA(mc68kcpu)[(word2 >> 12) & 15]; + + if (mc68kcpu->mmu_tc & 0x8000) + { + mc68kcpu->pmmu_enabled = 1; + } + else + { + mc68kcpu->pmmu_enabled = 0; + } + return; + } + m68ki_exception_illegal(mc68kcpu); + return; + case 0x004: /* ITT0 */ + if (CPU_TYPE_IS_040_PLUS((mc68kcpu)->cpu_type)) + { + mc68kcpu->mmu_itt0 = REG_DA(mc68kcpu)[(word2 >> 12) & 15]; + return; + } + else if(CPU_TYPE_IS_COLDFIRE((mc68kcpu)->cpu_type)) + { + mc68kcpu->mmu_acr0 = REG_DA(mc68kcpu)[(word2 >> 12) & 15]; + return; + } + m68ki_exception_illegal(mc68kcpu); + return; + case 0x005: /* ITT1 */ + if (CPU_TYPE_IS_040_PLUS((mc68kcpu)->cpu_type)) + { + mc68kcpu->mmu_itt1 = REG_DA(mc68kcpu)[(word2 >> 12) & 15]; + return; + } + else if(CPU_TYPE_IS_COLDFIRE((mc68kcpu)->cpu_type)) + { + mc68kcpu->mmu_acr1 = REG_DA(mc68kcpu)[(word2 >> 12) & 15]; + return; + } + m68ki_exception_illegal(mc68kcpu); + return; + case 0x006: /* DTT0 */ + if (CPU_TYPE_IS_040_PLUS((mc68kcpu)->cpu_type)) + { + mc68kcpu->mmu_dtt0 = REG_DA(mc68kcpu)[(word2 >> 12) & 15]; + return; + } + else if(CPU_TYPE_IS_COLDFIRE((mc68kcpu)->cpu_type)) + { + mc68kcpu->mmu_acr2 = REG_DA(mc68kcpu)[(word2 >> 12) & 15]; + return; + } + m68ki_exception_illegal(mc68kcpu); + return; + case 0x007: /* DTT1 */ + if (CPU_TYPE_IS_040_PLUS((mc68kcpu)->cpu_type)) + { + mc68kcpu->mmu_dtt1 = REG_DA(mc68kcpu)[(word2 >> 12) & 15]; + return; + } + else if(CPU_TYPE_IS_COLDFIRE((mc68kcpu)->cpu_type)) + { + mc68kcpu->mmu_acr3 = REG_DA(mc68kcpu)[(word2 >> 12) & 15]; + return; + } + m68ki_exception_illegal(mc68kcpu); + return; + case 0x805: /* MMUSR */ + if (CPU_TYPE_IS_040_PLUS((mc68kcpu)->cpu_type)) + { + mc68kcpu->mmu_sr_040 = REG_DA(mc68kcpu)[(word2 >> 12) & 15]; + return; + } + m68ki_exception_illegal(mc68kcpu); + return; + case 0x806: /* URP */ + if (CPU_TYPE_IS_040_PLUS((mc68kcpu)->cpu_type)) + { + mc68kcpu->mmu_urp_aptr = REG_DA(mc68kcpu)[(word2 >> 12) & 15]; + return; + } + m68ki_exception_illegal(mc68kcpu); + return; + case 0x807: /* SRP */ + if (CPU_TYPE_IS_040_PLUS((mc68kcpu)->cpu_type)) + { + mc68kcpu->mmu_srp_aptr = REG_DA(mc68kcpu)[(word2 >> 12) & 15]; + return; + } + m68ki_exception_illegal(mc68kcpu); + return; + case 0xc00: // ROMBAR0 + if(CPU_TYPE_IS_COLDFIRE((mc68kcpu)->cpu_type)) + { + /* TODO */ + return; + } + m68ki_exception_illegal(mc68kcpu); + return; + case 0xc01: // ROMBAR1 + if(CPU_TYPE_IS_COLDFIRE((mc68kcpu)->cpu_type)) + { + /* TODO */ + return; + } + m68ki_exception_illegal(mc68kcpu); + return; + case 0xc04: // RAMBAR0 + if(CPU_TYPE_IS_COLDFIRE((mc68kcpu)->cpu_type)) + { + /* TODO */ + return; + } + m68ki_exception_illegal(mc68kcpu); + return; + case 0xc05: // RAMBAR1 + if(CPU_TYPE_IS_COLDFIRE((mc68kcpu)->cpu_type)) + { + /* TODO */ + return; + } + m68ki_exception_illegal(mc68kcpu); + return; + case 0xc0c: // MPCR + if(CPU_TYPE_IS_COLDFIRE((mc68kcpu)->cpu_type)) + { + /* TODO */ + return; + } + m68ki_exception_illegal(mc68kcpu); + return; + case 0xc0d: // EDRAMBAR + if(CPU_TYPE_IS_COLDFIRE((mc68kcpu)->cpu_type)) + { + /* TODO */ + return; + } + m68ki_exception_illegal(mc68kcpu); + return; + case 0xc0e: // SECMBAR + if(CPU_TYPE_IS_COLDFIRE((mc68kcpu)->cpu_type)) + { + /* TODO */ + return; + } + m68ki_exception_illegal(mc68kcpu); + return; + case 0xc0f: // MBAR + if(CPU_TYPE_IS_COLDFIRE((mc68kcpu)->cpu_type)) + { + /* TODO */ + return; + } + m68ki_exception_illegal(mc68kcpu); + return; + default: + m68ki_exception_illegal(mc68kcpu); + return; + } + } + m68ki_exception_privilege_violation(mc68kcpu); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_movem_16_re_pd(m68000_base_device* mc68kcpu) +{ + UINT32 i = 0; + UINT32 register_list = OPER_I_16(mc68kcpu); + UINT32 ea = AY(mc68kcpu); + UINT32 count = 0; + + for(; i < 16; i++) + if(register_list & (1 << i)) + { + ea -= 2; + m68ki_write_16((mc68kcpu), ea, MASK_OUT_ABOVE_16(REG_DA(mc68kcpu)[15-i])); + count++; + } + AY(mc68kcpu) = ea; + + (mc68kcpu)->remaining_cycles -= count<<(mc68kcpu)->cyc_movem_w; +} + + +void m68000_base_device_ops::m68k_op_movem_16_re_ai(m68000_base_device* mc68kcpu) +{ + UINT32 i = 0; + UINT32 register_list = OPER_I_16(mc68kcpu); + UINT32 ea = EA_AY_AI_16(mc68kcpu); + UINT32 count = 0; + + for(; i < 16; i++) + if(register_list & (1 << i)) + { + m68ki_write_16((mc68kcpu), ea, MASK_OUT_ABOVE_16(REG_DA(mc68kcpu)[i])); + ea += 2; + count++; + } + + (mc68kcpu)->remaining_cycles -= count<<(mc68kcpu)->cyc_movem_w; +} + + +void m68000_base_device_ops::m68k_op_movem_16_re_di(m68000_base_device* mc68kcpu) +{ + UINT32 i = 0; + UINT32 register_list = OPER_I_16(mc68kcpu); + UINT32 ea = EA_AY_DI_16(mc68kcpu); + UINT32 count = 0; + + for(; i < 16; i++) + if(register_list & (1 << i)) + { + m68ki_write_16((mc68kcpu), ea, MASK_OUT_ABOVE_16(REG_DA(mc68kcpu)[i])); + ea += 2; + count++; + } + + (mc68kcpu)->remaining_cycles -= count<<(mc68kcpu)->cyc_movem_w; +} + + +void m68000_base_device_ops::m68k_op_movem_16_re_ix(m68000_base_device* mc68kcpu) +{ + UINT32 i = 0; + UINT32 register_list = OPER_I_16(mc68kcpu); + UINT32 ea = EA_AY_IX_16(mc68kcpu); + UINT32 count = 0; + + for(; i < 16; i++) + if(register_list & (1 << i)) + { + m68ki_write_16((mc68kcpu), ea, MASK_OUT_ABOVE_16(REG_DA(mc68kcpu)[i])); + ea += 2; + count++; + } + + (mc68kcpu)->remaining_cycles -= count<<(mc68kcpu)->cyc_movem_w; +} + + +void m68000_base_device_ops::m68k_op_movem_16_re_aw(m68000_base_device* mc68kcpu) +{ + UINT32 i = 0; + UINT32 register_list = OPER_I_16(mc68kcpu); + UINT32 ea = EA_AW_16(mc68kcpu); + UINT32 count = 0; + + for(; i < 16; i++) + if(register_list & (1 << i)) + { + m68ki_write_16((mc68kcpu), ea, MASK_OUT_ABOVE_16(REG_DA(mc68kcpu)[i])); + ea += 2; + count++; + } + + (mc68kcpu)->remaining_cycles -= count<<(mc68kcpu)->cyc_movem_w; +} + + +void m68000_base_device_ops::m68k_op_movem_16_re_al(m68000_base_device* mc68kcpu) +{ + UINT32 i = 0; + UINT32 register_list = OPER_I_16(mc68kcpu); + UINT32 ea = EA_AL_16(mc68kcpu); + UINT32 count = 0; + + for(; i < 16; i++) + if(register_list & (1 << i)) + { + m68ki_write_16((mc68kcpu), ea, MASK_OUT_ABOVE_16(REG_DA(mc68kcpu)[i])); + ea += 2; + count++; + } + + (mc68kcpu)->remaining_cycles -= count<<(mc68kcpu)->cyc_movem_w; +} + + +void m68000_base_device_ops::m68k_op_movem_32_re_pd(m68000_base_device* mc68kcpu) +{ + UINT32 i = 0; + UINT32 register_list = OPER_I_16(mc68kcpu); + UINT32 ea = AY(mc68kcpu); + UINT32 count = 0; + + for(; i < 16; i++) + if(register_list & (1 << i)) + { + ea -= 4; + m68ki_write_16((mc68kcpu), ea+2, REG_DA(mc68kcpu)[15-i] & 0xFFFF ); + m68ki_write_16((mc68kcpu), ea, (REG_DA(mc68kcpu)[15-i] >> 16) & 0xFFFF ); + count++; + } + AY(mc68kcpu) = ea; + + (mc68kcpu)->remaining_cycles -= count<<(mc68kcpu)->cyc_movem_l; +} + + +void m68000_base_device_ops::m68k_op_movem_32_re_ai(m68000_base_device* mc68kcpu) +{ + UINT32 i = 0; + UINT32 register_list = OPER_I_16(mc68kcpu); + UINT32 ea = EA_AY_AI_32(mc68kcpu); + UINT32 count = 0; + + for(; i < 16; i++) + if(register_list & (1 << i)) + { + m68ki_write_32((mc68kcpu), ea, REG_DA(mc68kcpu)[i]); + ea += 4; + count++; + } + + (mc68kcpu)->remaining_cycles -= count<<(mc68kcpu)->cyc_movem_l; +} + + +void m68000_base_device_ops::m68k_op_movem_32_re_di(m68000_base_device* mc68kcpu) +{ + UINT32 i = 0; + UINT32 register_list = OPER_I_16(mc68kcpu); + UINT32 ea = EA_AY_DI_32(mc68kcpu); + UINT32 count = 0; + + for(; i < 16; i++) + if(register_list & (1 << i)) + { + m68ki_write_32((mc68kcpu), ea, REG_DA(mc68kcpu)[i]); + ea += 4; + count++; + } + + (mc68kcpu)->remaining_cycles -= count<<(mc68kcpu)->cyc_movem_l; +} + + +void m68000_base_device_ops::m68k_op_movem_32_re_ix(m68000_base_device* mc68kcpu) +{ + UINT32 i = 0; + UINT32 register_list = OPER_I_16(mc68kcpu); + UINT32 ea = EA_AY_IX_32(mc68kcpu); + UINT32 count = 0; + + for(; i < 16; i++) + if(register_list & (1 << i)) + { + m68ki_write_32((mc68kcpu), ea, REG_DA(mc68kcpu)[i]); + ea += 4; + count++; + } + + (mc68kcpu)->remaining_cycles -= count<<(mc68kcpu)->cyc_movem_l; +} + + +void m68000_base_device_ops::m68k_op_movem_32_re_aw(m68000_base_device* mc68kcpu) +{ + UINT32 i = 0; + UINT32 register_list = OPER_I_16(mc68kcpu); + UINT32 ea = EA_AW_32(mc68kcpu); + UINT32 count = 0; + + for(; i < 16; i++) + if(register_list & (1 << i)) + { + m68ki_write_32((mc68kcpu), ea, REG_DA(mc68kcpu)[i]); + ea += 4; + count++; + } + + (mc68kcpu)->remaining_cycles -= count<<(mc68kcpu)->cyc_movem_l; +} + + +void m68000_base_device_ops::m68k_op_movem_32_re_al(m68000_base_device* mc68kcpu) +{ + UINT32 i = 0; + UINT32 register_list = OPER_I_16(mc68kcpu); + UINT32 ea = EA_AL_32(mc68kcpu); + UINT32 count = 0; + + for(; i < 16; i++) + if(register_list & (1 << i)) + { + m68ki_write_32((mc68kcpu), ea, REG_DA(mc68kcpu)[i]); + ea += 4; + count++; + } + + (mc68kcpu)->remaining_cycles -= count<<(mc68kcpu)->cyc_movem_l; +} + + +void m68000_base_device_ops::m68k_op_movem_16_er_pi(m68000_base_device* mc68kcpu) +{ + UINT32 i = 0; + UINT32 register_list = OPER_I_16(mc68kcpu); + UINT32 ea = AY(mc68kcpu); + UINT32 count = 0; + + for(; i < 16; i++) + if(register_list & (1 << i)) + { + REG_DA(mc68kcpu)[i] = MAKE_INT_16(MASK_OUT_ABOVE_16(m68ki_read_16((mc68kcpu), ea))); + ea += 2; + count++; + } + AY(mc68kcpu) = ea; + + (mc68kcpu)->remaining_cycles -= count<<(mc68kcpu)->cyc_movem_w; +} + + +void m68000_base_device_ops::m68k_op_movem_16_er_pcdi(m68000_base_device* mc68kcpu) +{ + UINT32 i = 0; + UINT32 register_list = OPER_I_16(mc68kcpu); + UINT32 ea = EA_PCDI_16(mc68kcpu); + UINT32 count = 0; + + for(; i < 16; i++) + if(register_list & (1 << i)) + { + REG_DA(mc68kcpu)[i] = MAKE_INT_16(MASK_OUT_ABOVE_16(m68ki_read_pcrel_16((mc68kcpu), ea))); + ea += 2; + count++; + } + + (mc68kcpu)->remaining_cycles -= count<<(mc68kcpu)->cyc_movem_w; +} + + +void m68000_base_device_ops::m68k_op_movem_16_er_pcix(m68000_base_device* mc68kcpu) +{ + UINT32 i = 0; + UINT32 register_list = OPER_I_16(mc68kcpu); + UINT32 ea = EA_PCIX_16(mc68kcpu); + UINT32 count = 0; + + for(; i < 16; i++) + if(register_list & (1 << i)) + { + REG_DA(mc68kcpu)[i] = MAKE_INT_16(MASK_OUT_ABOVE_16(m68ki_read_pcrel_16((mc68kcpu), ea))); + ea += 2; + count++; + } + + (mc68kcpu)->remaining_cycles -= count<<(mc68kcpu)->cyc_movem_w; +} + + +void m68000_base_device_ops::m68k_op_movem_16_er_ai(m68000_base_device* mc68kcpu) +{ + UINT32 i = 0; + UINT32 register_list = OPER_I_16(mc68kcpu); + UINT32 ea = EA_AY_AI_16(mc68kcpu); + UINT32 count = 0; + + for(; i < 16; i++) + if(register_list & (1 << i)) + { + REG_DA(mc68kcpu)[i] = MAKE_INT_16(MASK_OUT_ABOVE_16(m68ki_read_16((mc68kcpu), ea))); + ea += 2; + count++; + } + + (mc68kcpu)->remaining_cycles -= count<<(mc68kcpu)->cyc_movem_w; +} + + +void m68000_base_device_ops::m68k_op_movem_16_er_di(m68000_base_device* mc68kcpu) +{ + UINT32 i = 0; + UINT32 register_list = OPER_I_16(mc68kcpu); + UINT32 ea = EA_AY_DI_16(mc68kcpu); + UINT32 count = 0; + + for(; i < 16; i++) + if(register_list & (1 << i)) + { + REG_DA(mc68kcpu)[i] = MAKE_INT_16(MASK_OUT_ABOVE_16(m68ki_read_16((mc68kcpu), ea))); + ea += 2; + count++; + } + + (mc68kcpu)->remaining_cycles -= count<<(mc68kcpu)->cyc_movem_w; +} + + +void m68000_base_device_ops::m68k_op_movem_16_er_ix(m68000_base_device* mc68kcpu) +{ + UINT32 i = 0; + UINT32 register_list = OPER_I_16(mc68kcpu); + UINT32 ea = EA_AY_IX_16(mc68kcpu); + UINT32 count = 0; + + for(; i < 16; i++) + if(register_list & (1 << i)) + { + REG_DA(mc68kcpu)[i] = MAKE_INT_16(MASK_OUT_ABOVE_16(m68ki_read_16((mc68kcpu), ea))); + ea += 2; + count++; + } + + (mc68kcpu)->remaining_cycles -= count<<(mc68kcpu)->cyc_movem_w; +} + + +void m68000_base_device_ops::m68k_op_movem_16_er_aw(m68000_base_device* mc68kcpu) +{ + UINT32 i = 0; + UINT32 register_list = OPER_I_16(mc68kcpu); + UINT32 ea = EA_AW_16(mc68kcpu); + UINT32 count = 0; + + for(; i < 16; i++) + if(register_list & (1 << i)) + { + REG_DA(mc68kcpu)[i] = MAKE_INT_16(MASK_OUT_ABOVE_16(m68ki_read_16((mc68kcpu), ea))); + ea += 2; + count++; + } + + (mc68kcpu)->remaining_cycles -= count<<(mc68kcpu)->cyc_movem_w; +} + + +void m68000_base_device_ops::m68k_op_movem_16_er_al(m68000_base_device* mc68kcpu) +{ + UINT32 i = 0; + UINT32 register_list = OPER_I_16(mc68kcpu); + UINT32 ea = EA_AL_16(mc68kcpu); + UINT32 count = 0; + + for(; i < 16; i++) + if(register_list & (1 << i)) + { + REG_DA(mc68kcpu)[i] = MAKE_INT_16(MASK_OUT_ABOVE_16(m68ki_read_16((mc68kcpu), ea))); + ea += 2; + count++; + } + + (mc68kcpu)->remaining_cycles -= count<<(mc68kcpu)->cyc_movem_w; +} + + +void m68000_base_device_ops::m68k_op_movem_32_er_pi(m68000_base_device* mc68kcpu) +{ + UINT32 i = 0; + UINT32 register_list = OPER_I_16(mc68kcpu); + UINT32 ea = AY(mc68kcpu); + UINT32 count = 0; + + for(; i < 16; i++) + if(register_list & (1 << i)) + { + REG_DA(mc68kcpu)[i] = m68ki_read_32((mc68kcpu), ea); + ea += 4; + count++; + } + AY(mc68kcpu) = ea; + + (mc68kcpu)->remaining_cycles -= count<<(mc68kcpu)->cyc_movem_l; +} + + +void m68000_base_device_ops::m68k_op_movem_32_er_pcdi(m68000_base_device* mc68kcpu) +{ + UINT32 i = 0; + UINT32 register_list = OPER_I_16(mc68kcpu); + UINT32 ea = EA_PCDI_32(mc68kcpu); + UINT32 count = 0; + + for(; i < 16; i++) + if(register_list & (1 << i)) + { + REG_DA(mc68kcpu)[i] = m68ki_read_pcrel_32((mc68kcpu), ea); + ea += 4; + count++; + } + + (mc68kcpu)->remaining_cycles -= count<<(mc68kcpu)->cyc_movem_l; +} + + +void m68000_base_device_ops::m68k_op_movem_32_er_pcix(m68000_base_device* mc68kcpu) +{ + UINT32 i = 0; + UINT32 register_list = OPER_I_16(mc68kcpu); + UINT32 ea = EA_PCIX_32(mc68kcpu); + UINT32 count = 0; + + for(; i < 16; i++) + if(register_list & (1 << i)) + { + REG_DA(mc68kcpu)[i] = m68ki_read_pcrel_32((mc68kcpu), ea); + ea += 4; + count++; + } + + (mc68kcpu)->remaining_cycles -= count<<(mc68kcpu)->cyc_movem_l; +} + + +void m68000_base_device_ops::m68k_op_movem_32_er_ai(m68000_base_device* mc68kcpu) +{ + UINT32 i = 0; + UINT32 register_list = OPER_I_16(mc68kcpu); + UINT32 ea = EA_AY_AI_32(mc68kcpu); + UINT32 count = 0; + + for(; i < 16; i++) + if(register_list & (1 << i)) + { + REG_DA(mc68kcpu)[i] = m68ki_read_32((mc68kcpu), ea); + ea += 4; + count++; + } + + (mc68kcpu)->remaining_cycles -= count<<(mc68kcpu)->cyc_movem_l; +} + + +void m68000_base_device_ops::m68k_op_movem_32_er_di(m68000_base_device* mc68kcpu) +{ + UINT32 i = 0; + UINT32 register_list = OPER_I_16(mc68kcpu); + UINT32 ea = EA_AY_DI_32(mc68kcpu); + UINT32 count = 0; + + for(; i < 16; i++) + if(register_list & (1 << i)) + { + REG_DA(mc68kcpu)[i] = m68ki_read_32((mc68kcpu), ea); + ea += 4; + count++; + } + + (mc68kcpu)->remaining_cycles -= count<<(mc68kcpu)->cyc_movem_l; +} + + +void m68000_base_device_ops::m68k_op_movem_32_er_ix(m68000_base_device* mc68kcpu) +{ + UINT32 i = 0; + UINT32 register_list = OPER_I_16(mc68kcpu); + UINT32 ea = EA_AY_IX_32(mc68kcpu); + UINT32 count = 0; + + for(; i < 16; i++) + if(register_list & (1 << i)) + { + REG_DA(mc68kcpu)[i] = m68ki_read_32((mc68kcpu), ea); + ea += 4; + count++; + } + + (mc68kcpu)->remaining_cycles -= count<<(mc68kcpu)->cyc_movem_l; +} + + +void m68000_base_device_ops::m68k_op_movem_32_er_aw(m68000_base_device* mc68kcpu) +{ + UINT32 i = 0; + UINT32 register_list = OPER_I_16(mc68kcpu); + UINT32 ea = EA_AW_32(mc68kcpu); + UINT32 count = 0; + + for(; i < 16; i++) + if(register_list & (1 << i)) + { + REG_DA(mc68kcpu)[i] = m68ki_read_32((mc68kcpu), ea); + ea += 4; + count++; + } + + (mc68kcpu)->remaining_cycles -= count<<(mc68kcpu)->cyc_movem_l; +} + + +void m68000_base_device_ops::m68k_op_movem_32_er_al(m68000_base_device* mc68kcpu) +{ + UINT32 i = 0; + UINT32 register_list = OPER_I_16(mc68kcpu); + UINT32 ea = EA_AL_32(mc68kcpu); + UINT32 count = 0; + + for(; i < 16; i++) + if(register_list & (1 << i)) + { + REG_DA(mc68kcpu)[i] = m68ki_read_32((mc68kcpu), ea); + ea += 4; + count++; + } + + (mc68kcpu)->remaining_cycles -= count<<(mc68kcpu)->cyc_movem_l; +} + + +void m68000_base_device_ops::m68k_op_movep_16_re(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_DI_16(mc68kcpu); + UINT32 src = DX(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, MASK_OUT_ABOVE_8(src >> 8)); + m68ki_write_8((mc68kcpu), ea += 2, MASK_OUT_ABOVE_8(src)); +} + + +void m68000_base_device_ops::m68k_op_movep_32_re(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_DI_32(mc68kcpu); + UINT32 src = DX(mc68kcpu); + + m68ki_write_8((mc68kcpu), ea, MASK_OUT_ABOVE_8(src >> 24)); + m68ki_write_8((mc68kcpu), ea += 2, MASK_OUT_ABOVE_8(src >> 16)); + m68ki_write_8((mc68kcpu), ea += 2, MASK_OUT_ABOVE_8(src >> 8)); + m68ki_write_8((mc68kcpu), ea += 2, MASK_OUT_ABOVE_8(src)); +} + + +void m68000_base_device_ops::m68k_op_movep_16_er(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_DI_16(mc68kcpu); + UINT32* r_dst = &DX(mc68kcpu); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | ((m68ki_read_8((mc68kcpu), ea) << 8) + m68ki_read_8((mc68kcpu), ea + 2)); +} + + +void m68000_base_device_ops::m68k_op_movep_32_er(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_DI_32(mc68kcpu); + + DX(mc68kcpu) = (m68ki_read_8((mc68kcpu), ea) << 24) + (m68ki_read_8((mc68kcpu), ea + 2) << 16) + + (m68ki_read_8((mc68kcpu), ea + 4) << 8) + m68ki_read_8((mc68kcpu), ea + 6); +} + + +void m68000_base_device_ops::m68k_op_moves_8_ai(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_010_PLUS((mc68kcpu)->cpu_type)) + { + if((mc68kcpu)->s_flag) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT32 ea = EA_AY_AI_8(mc68kcpu); + + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + if(BIT_B(word2)) /* Register to memory */ + { + m68ki_write_8_fc((mc68kcpu), ea, (mc68kcpu)->dfc, MASK_OUT_ABOVE_8(REG_DA(mc68kcpu)[(word2 >> 12) & 15])); + return; + } + if(BIT_F(word2)) /* Memory to address register */ + { + REG_A(mc68kcpu)[(word2 >> 12) & 7] = MAKE_INT_8(m68ki_read_8_fc((mc68kcpu), ea, (mc68kcpu)->sfc)); + if(CPU_TYPE_IS_020_VARIANT((mc68kcpu)->cpu_type)) + (mc68kcpu)->remaining_cycles -= 2; + return; + } + /* Memory to data register */ + REG_D(mc68kcpu)[(word2 >> 12) & 7] = MASK_OUT_BELOW_8(REG_D(mc68kcpu)[(word2 >> 12) & 7]) | m68ki_read_8_fc((mc68kcpu), ea, (mc68kcpu)->sfc); + if(CPU_TYPE_IS_020_VARIANT((mc68kcpu)->cpu_type)) + (mc68kcpu)->remaining_cycles -= 2; + return; + } + m68ki_exception_privilege_violation(mc68kcpu); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_moves_8_pi(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_010_PLUS((mc68kcpu)->cpu_type)) + { + if((mc68kcpu)->s_flag) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT32 ea = EA_AY_PI_8(mc68kcpu); + + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + if(BIT_B(word2)) /* Register to memory */ + { + m68ki_write_8_fc((mc68kcpu), ea, (mc68kcpu)->dfc, MASK_OUT_ABOVE_8(REG_DA(mc68kcpu)[(word2 >> 12) & 15])); + return; + } + if(BIT_F(word2)) /* Memory to address register */ + { + REG_A(mc68kcpu)[(word2 >> 12) & 7] = MAKE_INT_8(m68ki_read_8_fc((mc68kcpu), ea, (mc68kcpu)->sfc)); + if(CPU_TYPE_IS_020_VARIANT((mc68kcpu)->cpu_type)) + (mc68kcpu)->remaining_cycles -= 2; + return; + } + /* Memory to data register */ + REG_D(mc68kcpu)[(word2 >> 12) & 7] = MASK_OUT_BELOW_8(REG_D(mc68kcpu)[(word2 >> 12) & 7]) | m68ki_read_8_fc((mc68kcpu), ea, (mc68kcpu)->sfc); + if(CPU_TYPE_IS_020_VARIANT((mc68kcpu)->cpu_type)) + (mc68kcpu)->remaining_cycles -= 2; + return; + } + m68ki_exception_privilege_violation(mc68kcpu); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_moves_8_pi7(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_010_PLUS((mc68kcpu)->cpu_type)) + { + if((mc68kcpu)->s_flag) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT32 ea = EA_A7_PI_8(mc68kcpu); + + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + if(BIT_B(word2)) /* Register to memory */ + { + m68ki_write_8_fc((mc68kcpu), ea, (mc68kcpu)->dfc, MASK_OUT_ABOVE_8(REG_DA(mc68kcpu)[(word2 >> 12) & 15])); + return; + } + if(BIT_F(word2)) /* Memory to address register */ + { + REG_A(mc68kcpu)[(word2 >> 12) & 7] = MAKE_INT_8(m68ki_read_8_fc((mc68kcpu), ea, (mc68kcpu)->sfc)); + if(CPU_TYPE_IS_020_VARIANT((mc68kcpu)->cpu_type)) + (mc68kcpu)->remaining_cycles -= 2; + return; + } + /* Memory to data register */ + REG_D(mc68kcpu)[(word2 >> 12) & 7] = MASK_OUT_BELOW_8(REG_D(mc68kcpu)[(word2 >> 12) & 7]) | m68ki_read_8_fc((mc68kcpu), ea, (mc68kcpu)->sfc); + if(CPU_TYPE_IS_020_VARIANT((mc68kcpu)->cpu_type)) + (mc68kcpu)->remaining_cycles -= 2; + return; + } + m68ki_exception_privilege_violation(mc68kcpu); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_moves_8_pd(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_010_PLUS((mc68kcpu)->cpu_type)) + { + if((mc68kcpu)->s_flag) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT32 ea = EA_AY_PD_8(mc68kcpu); + + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + if(BIT_B(word2)) /* Register to memory */ + { + m68ki_write_8_fc((mc68kcpu), ea, (mc68kcpu)->dfc, MASK_OUT_ABOVE_8(REG_DA(mc68kcpu)[(word2 >> 12) & 15])); + return; + } + if(BIT_F(word2)) /* Memory to address register */ + { + REG_A(mc68kcpu)[(word2 >> 12) & 7] = MAKE_INT_8(m68ki_read_8_fc((mc68kcpu), ea, (mc68kcpu)->sfc)); + if(CPU_TYPE_IS_020_VARIANT((mc68kcpu)->cpu_type)) + (mc68kcpu)->remaining_cycles -= 2; + return; + } + /* Memory to data register */ + REG_D(mc68kcpu)[(word2 >> 12) & 7] = MASK_OUT_BELOW_8(REG_D(mc68kcpu)[(word2 >> 12) & 7]) | m68ki_read_8_fc((mc68kcpu), ea, (mc68kcpu)->sfc); + if(CPU_TYPE_IS_020_VARIANT((mc68kcpu)->cpu_type)) + (mc68kcpu)->remaining_cycles -= 2; + return; + } + m68ki_exception_privilege_violation(mc68kcpu); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_moves_8_pd7(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_010_PLUS((mc68kcpu)->cpu_type)) + { + if((mc68kcpu)->s_flag) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT32 ea = EA_A7_PD_8(mc68kcpu); + + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + if(BIT_B(word2)) /* Register to memory */ + { + m68ki_write_8_fc((mc68kcpu), ea, (mc68kcpu)->dfc, MASK_OUT_ABOVE_8(REG_DA(mc68kcpu)[(word2 >> 12) & 15])); + return; + } + if(BIT_F(word2)) /* Memory to address register */ + { + REG_A(mc68kcpu)[(word2 >> 12) & 7] = MAKE_INT_8(m68ki_read_8_fc((mc68kcpu), ea, (mc68kcpu)->sfc)); + if(CPU_TYPE_IS_020_VARIANT((mc68kcpu)->cpu_type)) + (mc68kcpu)->remaining_cycles -= 2; + return; + } + /* Memory to data register */ + REG_D(mc68kcpu)[(word2 >> 12) & 7] = MASK_OUT_BELOW_8(REG_D(mc68kcpu)[(word2 >> 12) & 7]) | m68ki_read_8_fc((mc68kcpu), ea, (mc68kcpu)->sfc); + if(CPU_TYPE_IS_020_VARIANT((mc68kcpu)->cpu_type)) + (mc68kcpu)->remaining_cycles -= 2; + return; + } + m68ki_exception_privilege_violation(mc68kcpu); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_moves_8_di(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_010_PLUS((mc68kcpu)->cpu_type)) + { + if((mc68kcpu)->s_flag) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT32 ea = EA_AY_DI_8(mc68kcpu); + + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + if(BIT_B(word2)) /* Register to memory */ + { + m68ki_write_8_fc((mc68kcpu), ea, (mc68kcpu)->dfc, MASK_OUT_ABOVE_8(REG_DA(mc68kcpu)[(word2 >> 12) & 15])); + return; + } + if(BIT_F(word2)) /* Memory to address register */ + { + REG_A(mc68kcpu)[(word2 >> 12) & 7] = MAKE_INT_8(m68ki_read_8_fc((mc68kcpu), ea, (mc68kcpu)->sfc)); + if(CPU_TYPE_IS_020_VARIANT((mc68kcpu)->cpu_type)) + (mc68kcpu)->remaining_cycles -= 2; + return; + } + /* Memory to data register */ + REG_D(mc68kcpu)[(word2 >> 12) & 7] = MASK_OUT_BELOW_8(REG_D(mc68kcpu)[(word2 >> 12) & 7]) | m68ki_read_8_fc((mc68kcpu), ea, (mc68kcpu)->sfc); + if(CPU_TYPE_IS_020_VARIANT((mc68kcpu)->cpu_type)) + (mc68kcpu)->remaining_cycles -= 2; + return; + } + m68ki_exception_privilege_violation(mc68kcpu); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_moves_8_ix(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_010_PLUS((mc68kcpu)->cpu_type)) + { + if((mc68kcpu)->s_flag) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT32 ea = EA_AY_IX_8(mc68kcpu); + + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + if(BIT_B(word2)) /* Register to memory */ + { + m68ki_write_8_fc((mc68kcpu), ea, (mc68kcpu)->dfc, MASK_OUT_ABOVE_8(REG_DA(mc68kcpu)[(word2 >> 12) & 15])); + return; + } + if(BIT_F(word2)) /* Memory to address register */ + { + REG_A(mc68kcpu)[(word2 >> 12) & 7] = MAKE_INT_8(m68ki_read_8_fc((mc68kcpu), ea, (mc68kcpu)->sfc)); + if(CPU_TYPE_IS_020_VARIANT((mc68kcpu)->cpu_type)) + (mc68kcpu)->remaining_cycles -= 2; + return; + } + /* Memory to data register */ + REG_D(mc68kcpu)[(word2 >> 12) & 7] = MASK_OUT_BELOW_8(REG_D(mc68kcpu)[(word2 >> 12) & 7]) | m68ki_read_8_fc((mc68kcpu), ea, (mc68kcpu)->sfc); + if(CPU_TYPE_IS_020_VARIANT((mc68kcpu)->cpu_type)) + (mc68kcpu)->remaining_cycles -= 2; + return; + } + m68ki_exception_privilege_violation(mc68kcpu); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_moves_8_aw(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_010_PLUS((mc68kcpu)->cpu_type)) + { + if((mc68kcpu)->s_flag) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT32 ea = EA_AW_8(mc68kcpu); + + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + if(BIT_B(word2)) /* Register to memory */ + { + m68ki_write_8_fc((mc68kcpu), ea, (mc68kcpu)->dfc, MASK_OUT_ABOVE_8(REG_DA(mc68kcpu)[(word2 >> 12) & 15])); + return; + } + if(BIT_F(word2)) /* Memory to address register */ + { + REG_A(mc68kcpu)[(word2 >> 12) & 7] = MAKE_INT_8(m68ki_read_8_fc((mc68kcpu), ea, (mc68kcpu)->sfc)); + if(CPU_TYPE_IS_020_VARIANT((mc68kcpu)->cpu_type)) + (mc68kcpu)->remaining_cycles -= 2; + return; + } + /* Memory to data register */ + REG_D(mc68kcpu)[(word2 >> 12) & 7] = MASK_OUT_BELOW_8(REG_D(mc68kcpu)[(word2 >> 12) & 7]) | m68ki_read_8_fc((mc68kcpu), ea, (mc68kcpu)->sfc); + if(CPU_TYPE_IS_020_VARIANT((mc68kcpu)->cpu_type)) + (mc68kcpu)->remaining_cycles -= 2; + return; + } + m68ki_exception_privilege_violation(mc68kcpu); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_moves_8_al(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_010_PLUS((mc68kcpu)->cpu_type)) + { + if((mc68kcpu)->s_flag) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT32 ea = EA_AL_8(mc68kcpu); + + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + if(BIT_B(word2)) /* Register to memory */ + { + m68ki_write_8_fc((mc68kcpu), ea, (mc68kcpu)->dfc, MASK_OUT_ABOVE_8(REG_DA(mc68kcpu)[(word2 >> 12) & 15])); + return; + } + if(BIT_F(word2)) /* Memory to address register */ + { + REG_A(mc68kcpu)[(word2 >> 12) & 7] = MAKE_INT_8(m68ki_read_8_fc((mc68kcpu), ea, (mc68kcpu)->sfc)); + if(CPU_TYPE_IS_020_VARIANT((mc68kcpu)->cpu_type)) + (mc68kcpu)->remaining_cycles -= 2; + return; + } + /* Memory to data register */ + REG_D(mc68kcpu)[(word2 >> 12) & 7] = MASK_OUT_BELOW_8(REG_D(mc68kcpu)[(word2 >> 12) & 7]) | m68ki_read_8_fc((mc68kcpu), ea, (mc68kcpu)->sfc); + if(CPU_TYPE_IS_020_VARIANT((mc68kcpu)->cpu_type)) + (mc68kcpu)->remaining_cycles -= 2; + return; + } + m68ki_exception_privilege_violation(mc68kcpu); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_moves_16_ai(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_010_PLUS((mc68kcpu)->cpu_type)) + { + if((mc68kcpu)->s_flag) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT32 ea = EA_AY_AI_16(mc68kcpu); + + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + if(BIT_B(word2)) /* Register to memory */ + { + m68ki_write_16_fc((mc68kcpu), ea, (mc68kcpu)->dfc, MASK_OUT_ABOVE_16(REG_DA(mc68kcpu)[(word2 >> 12) & 15])); + return; + } + if(BIT_F(word2)) /* Memory to address register */ + { + REG_A(mc68kcpu)[(word2 >> 12) & 7] = MAKE_INT_16(m68ki_read_16_fc((mc68kcpu), ea, (mc68kcpu)->sfc)); + if(CPU_TYPE_IS_020_VARIANT((mc68kcpu)->cpu_type)) + (mc68kcpu)->remaining_cycles -= 2; + return; + } + /* Memory to data register */ + REG_D(mc68kcpu)[(word2 >> 12) & 7] = MASK_OUT_BELOW_16(REG_D(mc68kcpu)[(word2 >> 12) & 7]) | m68ki_read_16_fc((mc68kcpu), ea, (mc68kcpu)->sfc); + if(CPU_TYPE_IS_020_VARIANT((mc68kcpu)->cpu_type)) + (mc68kcpu)->remaining_cycles -= 2; + return; + } + m68ki_exception_privilege_violation(mc68kcpu); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_moves_16_pi(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_010_PLUS((mc68kcpu)->cpu_type)) + { + if((mc68kcpu)->s_flag) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT32 ea = EA_AY_PI_16(mc68kcpu); + + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + if(BIT_B(word2)) /* Register to memory */ + { + m68ki_write_16_fc((mc68kcpu), ea, (mc68kcpu)->dfc, MASK_OUT_ABOVE_16(REG_DA(mc68kcpu)[(word2 >> 12) & 15])); + return; + } + if(BIT_F(word2)) /* Memory to address register */ + { + REG_A(mc68kcpu)[(word2 >> 12) & 7] = MAKE_INT_16(m68ki_read_16_fc((mc68kcpu), ea, (mc68kcpu)->sfc)); + if(CPU_TYPE_IS_020_VARIANT((mc68kcpu)->cpu_type)) + (mc68kcpu)->remaining_cycles -= 2; + return; + } + /* Memory to data register */ + REG_D(mc68kcpu)[(word2 >> 12) & 7] = MASK_OUT_BELOW_16(REG_D(mc68kcpu)[(word2 >> 12) & 7]) | m68ki_read_16_fc((mc68kcpu), ea, (mc68kcpu)->sfc); + if(CPU_TYPE_IS_020_VARIANT((mc68kcpu)->cpu_type)) + (mc68kcpu)->remaining_cycles -= 2; + return; + } + m68ki_exception_privilege_violation(mc68kcpu); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_moves_16_pd(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_010_PLUS((mc68kcpu)->cpu_type)) + { + if((mc68kcpu)->s_flag) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT32 ea = EA_AY_PD_16(mc68kcpu); + + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + if(BIT_B(word2)) /* Register to memory */ + { + m68ki_write_16_fc((mc68kcpu), ea, (mc68kcpu)->dfc, MASK_OUT_ABOVE_16(REG_DA(mc68kcpu)[(word2 >> 12) & 15])); + return; + } + if(BIT_F(word2)) /* Memory to address register */ + { + REG_A(mc68kcpu)[(word2 >> 12) & 7] = MAKE_INT_16(m68ki_read_16_fc((mc68kcpu), ea, (mc68kcpu)->sfc)); + if(CPU_TYPE_IS_020_VARIANT((mc68kcpu)->cpu_type)) + (mc68kcpu)->remaining_cycles -= 2; + return; + } + /* Memory to data register */ + REG_D(mc68kcpu)[(word2 >> 12) & 7] = MASK_OUT_BELOW_16(REG_D(mc68kcpu)[(word2 >> 12) & 7]) | m68ki_read_16_fc((mc68kcpu), ea, (mc68kcpu)->sfc); + if(CPU_TYPE_IS_020_VARIANT((mc68kcpu)->cpu_type)) + (mc68kcpu)->remaining_cycles -= 2; + return; + } + m68ki_exception_privilege_violation(mc68kcpu); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_moves_16_di(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_010_PLUS((mc68kcpu)->cpu_type)) + { + if((mc68kcpu)->s_flag) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT32 ea = EA_AY_DI_16(mc68kcpu); + + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + if(BIT_B(word2)) /* Register to memory */ + { + m68ki_write_16_fc((mc68kcpu), ea, (mc68kcpu)->dfc, MASK_OUT_ABOVE_16(REG_DA(mc68kcpu)[(word2 >> 12) & 15])); + return; + } + if(BIT_F(word2)) /* Memory to address register */ + { + REG_A(mc68kcpu)[(word2 >> 12) & 7] = MAKE_INT_16(m68ki_read_16_fc((mc68kcpu), ea, (mc68kcpu)->sfc)); + if(CPU_TYPE_IS_020_VARIANT((mc68kcpu)->cpu_type)) + (mc68kcpu)->remaining_cycles -= 2; + return; + } + /* Memory to data register */ + REG_D(mc68kcpu)[(word2 >> 12) & 7] = MASK_OUT_BELOW_16(REG_D(mc68kcpu)[(word2 >> 12) & 7]) | m68ki_read_16_fc((mc68kcpu), ea, (mc68kcpu)->sfc); + if(CPU_TYPE_IS_020_VARIANT((mc68kcpu)->cpu_type)) + (mc68kcpu)->remaining_cycles -= 2; + return; + } + m68ki_exception_privilege_violation(mc68kcpu); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_moves_16_ix(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_010_PLUS((mc68kcpu)->cpu_type)) + { + if((mc68kcpu)->s_flag) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT32 ea = EA_AY_IX_16(mc68kcpu); + + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + if(BIT_B(word2)) /* Register to memory */ + { + m68ki_write_16_fc((mc68kcpu), ea, (mc68kcpu)->dfc, MASK_OUT_ABOVE_16(REG_DA(mc68kcpu)[(word2 >> 12) & 15])); + return; + } + if(BIT_F(word2)) /* Memory to address register */ + { + REG_A(mc68kcpu)[(word2 >> 12) & 7] = MAKE_INT_16(m68ki_read_16_fc((mc68kcpu), ea, (mc68kcpu)->sfc)); + if(CPU_TYPE_IS_020_VARIANT((mc68kcpu)->cpu_type)) + (mc68kcpu)->remaining_cycles -= 2; + return; + } + /* Memory to data register */ + REG_D(mc68kcpu)[(word2 >> 12) & 7] = MASK_OUT_BELOW_16(REG_D(mc68kcpu)[(word2 >> 12) & 7]) | m68ki_read_16_fc((mc68kcpu), ea, (mc68kcpu)->sfc); + if(CPU_TYPE_IS_020_VARIANT((mc68kcpu)->cpu_type)) + (mc68kcpu)->remaining_cycles -= 2; + return; + } + m68ki_exception_privilege_violation(mc68kcpu); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_moves_16_aw(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_010_PLUS((mc68kcpu)->cpu_type)) + { + if((mc68kcpu)->s_flag) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT32 ea = EA_AW_16(mc68kcpu); + + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + if(BIT_B(word2)) /* Register to memory */ + { + m68ki_write_16_fc((mc68kcpu), ea, (mc68kcpu)->dfc, MASK_OUT_ABOVE_16(REG_DA(mc68kcpu)[(word2 >> 12) & 15])); + return; + } + if(BIT_F(word2)) /* Memory to address register */ + { + REG_A(mc68kcpu)[(word2 >> 12) & 7] = MAKE_INT_16(m68ki_read_16_fc((mc68kcpu), ea, (mc68kcpu)->sfc)); + if(CPU_TYPE_IS_020_VARIANT((mc68kcpu)->cpu_type)) + (mc68kcpu)->remaining_cycles -= 2; + return; + } + /* Memory to data register */ + REG_D(mc68kcpu)[(word2 >> 12) & 7] = MASK_OUT_BELOW_16(REG_D(mc68kcpu)[(word2 >> 12) & 7]) | m68ki_read_16_fc((mc68kcpu), ea, (mc68kcpu)->sfc); + if(CPU_TYPE_IS_020_VARIANT((mc68kcpu)->cpu_type)) + (mc68kcpu)->remaining_cycles -= 2; + return; + } + m68ki_exception_privilege_violation(mc68kcpu); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_moves_16_al(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_010_PLUS((mc68kcpu)->cpu_type)) + { + if((mc68kcpu)->s_flag) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT32 ea = EA_AL_16(mc68kcpu); + + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + if(BIT_B(word2)) /* Register to memory */ + { + m68ki_write_16_fc((mc68kcpu), ea, (mc68kcpu)->dfc, MASK_OUT_ABOVE_16(REG_DA(mc68kcpu)[(word2 >> 12) & 15])); + return; + } + if(BIT_F(word2)) /* Memory to address register */ + { + REG_A(mc68kcpu)[(word2 >> 12) & 7] = MAKE_INT_16(m68ki_read_16_fc((mc68kcpu), ea, (mc68kcpu)->sfc)); + if(CPU_TYPE_IS_020_VARIANT((mc68kcpu)->cpu_type)) + (mc68kcpu)->remaining_cycles -= 2; + return; + } + /* Memory to data register */ + REG_D(mc68kcpu)[(word2 >> 12) & 7] = MASK_OUT_BELOW_16(REG_D(mc68kcpu)[(word2 >> 12) & 7]) | m68ki_read_16_fc((mc68kcpu), ea, (mc68kcpu)->sfc); + if(CPU_TYPE_IS_020_VARIANT((mc68kcpu)->cpu_type)) + (mc68kcpu)->remaining_cycles -= 2; + return; + } + m68ki_exception_privilege_violation(mc68kcpu); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_moves_32_ai(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_010_PLUS((mc68kcpu)->cpu_type)) + { + if((mc68kcpu)->s_flag) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT32 ea = EA_AY_AI_32(mc68kcpu); + + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + if(BIT_B(word2)) /* Register to memory */ + { + m68ki_write_32_fc((mc68kcpu), ea, (mc68kcpu)->dfc, REG_DA(mc68kcpu)[(word2 >> 12) & 15]); + if(CPU_TYPE_IS_020_VARIANT((mc68kcpu)->cpu_type)) + (mc68kcpu)->remaining_cycles -= 2; + return; + } + /* Memory to register */ + REG_DA(mc68kcpu)[(word2 >> 12) & 15] = m68ki_read_32_fc((mc68kcpu), ea, (mc68kcpu)->sfc); + if(CPU_TYPE_IS_020_VARIANT((mc68kcpu)->cpu_type)) + (mc68kcpu)->remaining_cycles -= 2; + return; + } + m68ki_exception_privilege_violation(mc68kcpu); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_moves_32_pi(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_010_PLUS((mc68kcpu)->cpu_type)) + { + if((mc68kcpu)->s_flag) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT32 ea = EA_AY_PI_32(mc68kcpu); + + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + if(BIT_B(word2)) /* Register to memory */ + { + m68ki_write_32_fc((mc68kcpu), ea, (mc68kcpu)->dfc, REG_DA(mc68kcpu)[(word2 >> 12) & 15]); + if(CPU_TYPE_IS_020_VARIANT((mc68kcpu)->cpu_type)) + (mc68kcpu)->remaining_cycles -= 2; + return; + } + /* Memory to register */ + REG_DA(mc68kcpu)[(word2 >> 12) & 15] = m68ki_read_32_fc((mc68kcpu), ea, (mc68kcpu)->sfc); + if(CPU_TYPE_IS_020_VARIANT((mc68kcpu)->cpu_type)) + (mc68kcpu)->remaining_cycles -= 2; + return; + } + m68ki_exception_privilege_violation(mc68kcpu); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_moves_32_pd(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_010_PLUS((mc68kcpu)->cpu_type)) + { + if((mc68kcpu)->s_flag) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT32 ea = EA_AY_PD_32(mc68kcpu); + + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + if(BIT_B(word2)) /* Register to memory */ + { + m68ki_write_32_fc((mc68kcpu), ea, (mc68kcpu)->dfc, REG_DA(mc68kcpu)[(word2 >> 12) & 15]); + if(CPU_TYPE_IS_020_VARIANT((mc68kcpu)->cpu_type)) + (mc68kcpu)->remaining_cycles -= 2; + return; + } + /* Memory to register */ + REG_DA(mc68kcpu)[(word2 >> 12) & 15] = m68ki_read_32_fc((mc68kcpu), ea, (mc68kcpu)->sfc); + if(CPU_TYPE_IS_020_VARIANT((mc68kcpu)->cpu_type)) + (mc68kcpu)->remaining_cycles -= 2; + return; + } + m68ki_exception_privilege_violation(mc68kcpu); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_moves_32_di(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_010_PLUS((mc68kcpu)->cpu_type)) + { + if((mc68kcpu)->s_flag) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT32 ea = EA_AY_DI_32(mc68kcpu); + + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + if(BIT_B(word2)) /* Register to memory */ + { + m68ki_write_32_fc((mc68kcpu), ea, (mc68kcpu)->dfc, REG_DA(mc68kcpu)[(word2 >> 12) & 15]); + if(CPU_TYPE_IS_020_VARIANT((mc68kcpu)->cpu_type)) + (mc68kcpu)->remaining_cycles -= 2; + return; + } + /* Memory to register */ + REG_DA(mc68kcpu)[(word2 >> 12) & 15] = m68ki_read_32_fc((mc68kcpu), ea, (mc68kcpu)->sfc); + if(CPU_TYPE_IS_020_VARIANT((mc68kcpu)->cpu_type)) + (mc68kcpu)->remaining_cycles -= 2; + return; + } + m68ki_exception_privilege_violation(mc68kcpu); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_moves_32_ix(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_010_PLUS((mc68kcpu)->cpu_type)) + { + if((mc68kcpu)->s_flag) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT32 ea = EA_AY_IX_32(mc68kcpu); + + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + if(BIT_B(word2)) /* Register to memory */ + { + m68ki_write_32_fc((mc68kcpu), ea, (mc68kcpu)->dfc, REG_DA(mc68kcpu)[(word2 >> 12) & 15]); + if(CPU_TYPE_IS_020_VARIANT((mc68kcpu)->cpu_type)) + (mc68kcpu)->remaining_cycles -= 2; + return; + } + /* Memory to register */ + REG_DA(mc68kcpu)[(word2 >> 12) & 15] = m68ki_read_32_fc((mc68kcpu), ea, (mc68kcpu)->sfc); + if(CPU_TYPE_IS_020_VARIANT((mc68kcpu)->cpu_type)) + (mc68kcpu)->remaining_cycles -= 2; + return; + } + m68ki_exception_privilege_violation(mc68kcpu); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_moves_32_aw(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_010_PLUS((mc68kcpu)->cpu_type)) + { + if((mc68kcpu)->s_flag) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT32 ea = EA_AW_32(mc68kcpu); + + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + if(BIT_B(word2)) /* Register to memory */ + { + m68ki_write_32_fc((mc68kcpu), ea, (mc68kcpu)->dfc, REG_DA(mc68kcpu)[(word2 >> 12) & 15]); + if(CPU_TYPE_IS_020_VARIANT((mc68kcpu)->cpu_type)) + (mc68kcpu)->remaining_cycles -= 2; + return; + } + /* Memory to register */ + REG_DA(mc68kcpu)[(word2 >> 12) & 15] = m68ki_read_32_fc((mc68kcpu), ea, (mc68kcpu)->sfc); + if(CPU_TYPE_IS_020_VARIANT((mc68kcpu)->cpu_type)) + (mc68kcpu)->remaining_cycles -= 2; + return; + } + m68ki_exception_privilege_violation(mc68kcpu); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_moves_32_al(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_010_PLUS((mc68kcpu)->cpu_type)) + { + if((mc68kcpu)->s_flag) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT32 ea = EA_AL_32(mc68kcpu); + + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + if(BIT_B(word2)) /* Register to memory */ + { + m68ki_write_32_fc((mc68kcpu), ea, (mc68kcpu)->dfc, REG_DA(mc68kcpu)[(word2 >> 12) & 15]); + if(CPU_TYPE_IS_020_VARIANT((mc68kcpu)->cpu_type)) + (mc68kcpu)->remaining_cycles -= 2; + return; + } + /* Memory to register */ + REG_DA(mc68kcpu)[(word2 >> 12) & 15] = m68ki_read_32_fc((mc68kcpu), ea, (mc68kcpu)->sfc); + if(CPU_TYPE_IS_020_VARIANT((mc68kcpu)->cpu_type)) + (mc68kcpu)->remaining_cycles -= 2; + return; + } + m68ki_exception_privilege_violation(mc68kcpu); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_moveq_32(m68000_base_device* mc68kcpu) +{ + UINT32 res = DX(mc68kcpu) = MAKE_INT_8(MASK_OUT_ABOVE_8((mc68kcpu)->ir)); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_move16_32(m68000_base_device* mc68kcpu) +{ + UINT16 w2 = OPER_I_16(mc68kcpu); + int ax = (mc68kcpu)->ir & 7; + int ay = (w2 >> 12) & 7; + m68ki_write_32((mc68kcpu), REG_A(mc68kcpu)[ay], m68ki_read_32((mc68kcpu), REG_A(mc68kcpu)[ax])); + m68ki_write_32((mc68kcpu), REG_A(mc68kcpu)[ay]+4, m68ki_read_32((mc68kcpu), REG_A(mc68kcpu)[ax]+4)); + m68ki_write_32((mc68kcpu), REG_A(mc68kcpu)[ay]+8, m68ki_read_32((mc68kcpu), REG_A(mc68kcpu)[ax]+8)); + m68ki_write_32((mc68kcpu), REG_A(mc68kcpu)[ay]+12, m68ki_read_32((mc68kcpu), REG_A(mc68kcpu)[ax]+12)); + + REG_A(mc68kcpu)[ax] += 16; + REG_A(mc68kcpu)[ay] += 16; +} + + +void m68000_base_device_ops::m68k_op_muls_16_d(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_32(MAKE_INT_16(DY(mc68kcpu)) * MAKE_INT_16(MASK_OUT_ABOVE_16(*r_dst))); + + *r_dst = res; + + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_muls_16_ai(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_32(MAKE_INT_16(OPER_AY_AI_16(mc68kcpu)) * MAKE_INT_16(MASK_OUT_ABOVE_16(*r_dst))); + + *r_dst = res; + + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_muls_16_pi(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_32(MAKE_INT_16(OPER_AY_PI_16(mc68kcpu)) * MAKE_INT_16(MASK_OUT_ABOVE_16(*r_dst))); + + *r_dst = res; + + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_muls_16_pd(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_32(MAKE_INT_16(OPER_AY_PD_16(mc68kcpu)) * MAKE_INT_16(MASK_OUT_ABOVE_16(*r_dst))); + + *r_dst = res; + + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_muls_16_di(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_32(MAKE_INT_16(OPER_AY_DI_16(mc68kcpu)) * MAKE_INT_16(MASK_OUT_ABOVE_16(*r_dst))); + + *r_dst = res; + + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_muls_16_ix(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_32(MAKE_INT_16(OPER_AY_IX_16(mc68kcpu)) * MAKE_INT_16(MASK_OUT_ABOVE_16(*r_dst))); + + *r_dst = res; + + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_muls_16_aw(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_32(MAKE_INT_16(OPER_AW_16(mc68kcpu)) * MAKE_INT_16(MASK_OUT_ABOVE_16(*r_dst))); + + *r_dst = res; + + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_muls_16_al(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_32(MAKE_INT_16(OPER_AL_16(mc68kcpu)) * MAKE_INT_16(MASK_OUT_ABOVE_16(*r_dst))); + + *r_dst = res; + + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_muls_16_pcdi(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_32(MAKE_INT_16(OPER_PCDI_16(mc68kcpu)) * MAKE_INT_16(MASK_OUT_ABOVE_16(*r_dst))); + + *r_dst = res; + + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_muls_16_pcix(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_32(MAKE_INT_16(OPER_PCIX_16(mc68kcpu)) * MAKE_INT_16(MASK_OUT_ABOVE_16(*r_dst))); + + *r_dst = res; + + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_muls_16_i(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_32(MAKE_INT_16(OPER_I_16(mc68kcpu)) * MAKE_INT_16(MASK_OUT_ABOVE_16(*r_dst))); + + *r_dst = res; + + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_mulu_16_d(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_16(DY(mc68kcpu)) * MASK_OUT_ABOVE_16(*r_dst); + + *r_dst = res; + + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_mulu_16_ai(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 res = OPER_AY_AI_16(mc68kcpu) * MASK_OUT_ABOVE_16(*r_dst); + + *r_dst = res; + + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_mulu_16_pi(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 res = OPER_AY_PI_16(mc68kcpu) * MASK_OUT_ABOVE_16(*r_dst); + + *r_dst = res; + + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_mulu_16_pd(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 res = OPER_AY_PD_16(mc68kcpu) * MASK_OUT_ABOVE_16(*r_dst); + + *r_dst = res; + + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_mulu_16_di(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 res = OPER_AY_DI_16(mc68kcpu) * MASK_OUT_ABOVE_16(*r_dst); + + *r_dst = res; + + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_mulu_16_ix(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 res = OPER_AY_IX_16(mc68kcpu) * MASK_OUT_ABOVE_16(*r_dst); + + *r_dst = res; + + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_mulu_16_aw(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 res = OPER_AW_16(mc68kcpu) * MASK_OUT_ABOVE_16(*r_dst); + + *r_dst = res; + + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_mulu_16_al(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 res = OPER_AL_16(mc68kcpu) * MASK_OUT_ABOVE_16(*r_dst); + + *r_dst = res; + + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_mulu_16_pcdi(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 res = OPER_PCDI_16(mc68kcpu) * MASK_OUT_ABOVE_16(*r_dst); + + *r_dst = res; + + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_mulu_16_pcix(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 res = OPER_PCIX_16(mc68kcpu) * MASK_OUT_ABOVE_16(*r_dst); + + *r_dst = res; + + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_mulu_16_i(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 res = OPER_I_16(mc68kcpu) * MASK_OUT_ABOVE_16(*r_dst); + + *r_dst = res; + + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_mull_32_d(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT64 src = DY(mc68kcpu); + UINT64 dst = REG_D(mc68kcpu)[(word2 >> 12) & 7]; + UINT64 res; + + (mc68kcpu)->c_flag = CFLAG_CLEAR; + + if(BIT_B(word2)) /* signed */ + { + res = (INT64)((INT32)src) * (INT64)((INT32)dst); + if(!BIT_A(word2)) + { + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->v_flag = ((INT64)res != (INT32)res)<<7; + REG_D(mc68kcpu)[(word2 >> 12) & 7] = (mc68kcpu)->not_z_flag; + return; + } + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res) | (res>>32); + (mc68kcpu)->n_flag = NFLAG_64(res); + (mc68kcpu)->v_flag = VFLAG_CLEAR; + REG_D(mc68kcpu)[word2 & 7] = (res >> 32); + REG_D(mc68kcpu)[(word2 >> 12) & 7] = MASK_OUT_ABOVE_32(res); + return; + } + + res = src * dst; + if(!BIT_A(word2)) + { + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->v_flag = (res > 0xffffffff)<<7; + REG_D(mc68kcpu)[(word2 >> 12) & 7] = (mc68kcpu)->not_z_flag; + return; + } + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res) | (res>>32); + (mc68kcpu)->n_flag = NFLAG_64(res); + (mc68kcpu)->v_flag = VFLAG_CLEAR; + REG_D(mc68kcpu)[word2 & 7] = (res >> 32); + REG_D(mc68kcpu)[(word2 >> 12) & 7] = MASK_OUT_ABOVE_32(res); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_mull_32_ai(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT64 src = OPER_AY_AI_32(mc68kcpu); + UINT64 dst = REG_D(mc68kcpu)[(word2 >> 12) & 7]; + UINT64 res; + + (mc68kcpu)->c_flag = CFLAG_CLEAR; + + if(BIT_B(word2)) /* signed */ + { + res = (INT64)((INT32)src) * (INT64)((INT32)dst); + if(!BIT_A(word2)) + { + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->v_flag = ((INT64)res != (INT32)res)<<7; + REG_D(mc68kcpu)[(word2 >> 12) & 7] = (mc68kcpu)->not_z_flag; + return; + } + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res) | (res>>32); + (mc68kcpu)->n_flag = NFLAG_64(res); + (mc68kcpu)->v_flag = VFLAG_CLEAR; + REG_D(mc68kcpu)[word2 & 7] = (res >> 32); + REG_D(mc68kcpu)[(word2 >> 12) & 7] = MASK_OUT_ABOVE_32(res); + return; + } + + res = src * dst; + if(!BIT_A(word2)) + { + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->v_flag = (res > 0xffffffff)<<7; + REG_D(mc68kcpu)[(word2 >> 12) & 7] = (mc68kcpu)->not_z_flag; + return; + } + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res) | (res>>32); + (mc68kcpu)->n_flag = NFLAG_64(res); + (mc68kcpu)->v_flag = VFLAG_CLEAR; + REG_D(mc68kcpu)[word2 & 7] = (res >> 32); + REG_D(mc68kcpu)[(word2 >> 12) & 7] = MASK_OUT_ABOVE_32(res); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_mull_32_pi(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT64 src = OPER_AY_PI_32(mc68kcpu); + UINT64 dst = REG_D(mc68kcpu)[(word2 >> 12) & 7]; + UINT64 res; + + (mc68kcpu)->c_flag = CFLAG_CLEAR; + + if(BIT_B(word2)) /* signed */ + { + res = (INT64)((INT32)src) * (INT64)((INT32)dst); + if(!BIT_A(word2)) + { + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->v_flag = ((INT64)res != (INT32)res)<<7; + REG_D(mc68kcpu)[(word2 >> 12) & 7] = (mc68kcpu)->not_z_flag; + return; + } + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res) | (res>>32); + (mc68kcpu)->n_flag = NFLAG_64(res); + (mc68kcpu)->v_flag = VFLAG_CLEAR; + REG_D(mc68kcpu)[word2 & 7] = (res >> 32); + REG_D(mc68kcpu)[(word2 >> 12) & 7] = MASK_OUT_ABOVE_32(res); + return; + } + + res = src * dst; + if(!BIT_A(word2)) + { + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->v_flag = (res > 0xffffffff)<<7; + REG_D(mc68kcpu)[(word2 >> 12) & 7] = (mc68kcpu)->not_z_flag; + return; + } + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res) | (res>>32); + (mc68kcpu)->n_flag = NFLAG_64(res); + (mc68kcpu)->v_flag = VFLAG_CLEAR; + REG_D(mc68kcpu)[word2 & 7] = (res >> 32); + REG_D(mc68kcpu)[(word2 >> 12) & 7] = MASK_OUT_ABOVE_32(res); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_mull_32_pd(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT64 src = OPER_AY_PD_32(mc68kcpu); + UINT64 dst = REG_D(mc68kcpu)[(word2 >> 12) & 7]; + UINT64 res; + + (mc68kcpu)->c_flag = CFLAG_CLEAR; + + if(BIT_B(word2)) /* signed */ + { + res = (INT64)((INT32)src) * (INT64)((INT32)dst); + if(!BIT_A(word2)) + { + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->v_flag = ((INT64)res != (INT32)res)<<7; + REG_D(mc68kcpu)[(word2 >> 12) & 7] = (mc68kcpu)->not_z_flag; + return; + } + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res) | (res>>32); + (mc68kcpu)->n_flag = NFLAG_64(res); + (mc68kcpu)->v_flag = VFLAG_CLEAR; + REG_D(mc68kcpu)[word2 & 7] = (res >> 32); + REG_D(mc68kcpu)[(word2 >> 12) & 7] = MASK_OUT_ABOVE_32(res); + return; + } + + res = src * dst; + if(!BIT_A(word2)) + { + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->v_flag = (res > 0xffffffff)<<7; + REG_D(mc68kcpu)[(word2 >> 12) & 7] = (mc68kcpu)->not_z_flag; + return; + } + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res) | (res>>32); + (mc68kcpu)->n_flag = NFLAG_64(res); + (mc68kcpu)->v_flag = VFLAG_CLEAR; + REG_D(mc68kcpu)[word2 & 7] = (res >> 32); + REG_D(mc68kcpu)[(word2 >> 12) & 7] = MASK_OUT_ABOVE_32(res); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_mull_32_di(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT64 src = OPER_AY_DI_32(mc68kcpu); + UINT64 dst = REG_D(mc68kcpu)[(word2 >> 12) & 7]; + UINT64 res; + + (mc68kcpu)->c_flag = CFLAG_CLEAR; + + if(BIT_B(word2)) /* signed */ + { + res = (INT64)((INT32)src) * (INT64)((INT32)dst); + if(!BIT_A(word2)) + { + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->v_flag = ((INT64)res != (INT32)res)<<7; + REG_D(mc68kcpu)[(word2 >> 12) & 7] = (mc68kcpu)->not_z_flag; + return; + } + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res) | (res>>32); + (mc68kcpu)->n_flag = NFLAG_64(res); + (mc68kcpu)->v_flag = VFLAG_CLEAR; + REG_D(mc68kcpu)[word2 & 7] = (res >> 32); + REG_D(mc68kcpu)[(word2 >> 12) & 7] = MASK_OUT_ABOVE_32(res); + return; + } + + res = src * dst; + if(!BIT_A(word2)) + { + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->v_flag = (res > 0xffffffff)<<7; + REG_D(mc68kcpu)[(word2 >> 12) & 7] = (mc68kcpu)->not_z_flag; + return; + } + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res) | (res>>32); + (mc68kcpu)->n_flag = NFLAG_64(res); + (mc68kcpu)->v_flag = VFLAG_CLEAR; + REG_D(mc68kcpu)[word2 & 7] = (res >> 32); + REG_D(mc68kcpu)[(word2 >> 12) & 7] = MASK_OUT_ABOVE_32(res); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_mull_32_ix(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT64 src = OPER_AY_IX_32(mc68kcpu); + UINT64 dst = REG_D(mc68kcpu)[(word2 >> 12) & 7]; + UINT64 res; + + (mc68kcpu)->c_flag = CFLAG_CLEAR; + + if(BIT_B(word2)) /* signed */ + { + res = (INT64)((INT32)src) * (INT64)((INT32)dst); + if(!BIT_A(word2)) + { + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->v_flag = ((INT64)res != (INT32)res)<<7; + REG_D(mc68kcpu)[(word2 >> 12) & 7] = (mc68kcpu)->not_z_flag; + return; + } + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res) | (res>>32); + (mc68kcpu)->n_flag = NFLAG_64(res); + (mc68kcpu)->v_flag = VFLAG_CLEAR; + REG_D(mc68kcpu)[word2 & 7] = (res >> 32); + REG_D(mc68kcpu)[(word2 >> 12) & 7] = MASK_OUT_ABOVE_32(res); + return; + } + + res = src * dst; + if(!BIT_A(word2)) + { + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->v_flag = (res > 0xffffffff)<<7; + REG_D(mc68kcpu)[(word2 >> 12) & 7] = (mc68kcpu)->not_z_flag; + return; + } + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res) | (res>>32); + (mc68kcpu)->n_flag = NFLAG_64(res); + (mc68kcpu)->v_flag = VFLAG_CLEAR; + REG_D(mc68kcpu)[word2 & 7] = (res >> 32); + REG_D(mc68kcpu)[(word2 >> 12) & 7] = MASK_OUT_ABOVE_32(res); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_mull_32_aw(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT64 src = OPER_AW_32(mc68kcpu); + UINT64 dst = REG_D(mc68kcpu)[(word2 >> 12) & 7]; + UINT64 res; + + (mc68kcpu)->c_flag = CFLAG_CLEAR; + + if(BIT_B(word2)) /* signed */ + { + res = (INT64)((INT32)src) * (INT64)((INT32)dst); + if(!BIT_A(word2)) + { + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->v_flag = ((INT64)res != (INT32)res)<<7; + REG_D(mc68kcpu)[(word2 >> 12) & 7] = (mc68kcpu)->not_z_flag; + return; + } + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res) | (res>>32); + (mc68kcpu)->n_flag = NFLAG_64(res); + (mc68kcpu)->v_flag = VFLAG_CLEAR; + REG_D(mc68kcpu)[word2 & 7] = (res >> 32); + REG_D(mc68kcpu)[(word2 >> 12) & 7] = MASK_OUT_ABOVE_32(res); + return; + } + + res = src * dst; + if(!BIT_A(word2)) + { + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->v_flag = (res > 0xffffffff)<<7; + REG_D(mc68kcpu)[(word2 >> 12) & 7] = (mc68kcpu)->not_z_flag; + return; + } + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res) | (res>>32); + (mc68kcpu)->n_flag = NFLAG_64(res); + (mc68kcpu)->v_flag = VFLAG_CLEAR; + REG_D(mc68kcpu)[word2 & 7] = (res >> 32); + REG_D(mc68kcpu)[(word2 >> 12) & 7] = MASK_OUT_ABOVE_32(res); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_mull_32_al(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT64 src = OPER_AL_32(mc68kcpu); + UINT64 dst = REG_D(mc68kcpu)[(word2 >> 12) & 7]; + UINT64 res; + + (mc68kcpu)->c_flag = CFLAG_CLEAR; + + if(BIT_B(word2)) /* signed */ + { + res = (INT64)((INT32)src) * (INT64)((INT32)dst); + if(!BIT_A(word2)) + { + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->v_flag = ((INT64)res != (INT32)res)<<7; + REG_D(mc68kcpu)[(word2 >> 12) & 7] = (mc68kcpu)->not_z_flag; + return; + } + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res) | (res>>32); + (mc68kcpu)->n_flag = NFLAG_64(res); + (mc68kcpu)->v_flag = VFLAG_CLEAR; + REG_D(mc68kcpu)[word2 & 7] = (res >> 32); + REG_D(mc68kcpu)[(word2 >> 12) & 7] = MASK_OUT_ABOVE_32(res); + return; + } + + res = src * dst; + if(!BIT_A(word2)) + { + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->v_flag = (res > 0xffffffff)<<7; + REG_D(mc68kcpu)[(word2 >> 12) & 7] = (mc68kcpu)->not_z_flag; + return; + } + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res) | (res>>32); + (mc68kcpu)->n_flag = NFLAG_64(res); + (mc68kcpu)->v_flag = VFLAG_CLEAR; + REG_D(mc68kcpu)[word2 & 7] = (res >> 32); + REG_D(mc68kcpu)[(word2 >> 12) & 7] = MASK_OUT_ABOVE_32(res); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_mull_32_pcdi(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT64 src = OPER_PCDI_32(mc68kcpu); + UINT64 dst = REG_D(mc68kcpu)[(word2 >> 12) & 7]; + UINT64 res; + + (mc68kcpu)->c_flag = CFLAG_CLEAR; + + if(BIT_B(word2)) /* signed */ + { + res = (INT64)((INT32)src) * (INT64)((INT32)dst); + if(!BIT_A(word2)) + { + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->v_flag = ((INT64)res != (INT32)res)<<7; + REG_D(mc68kcpu)[(word2 >> 12) & 7] = (mc68kcpu)->not_z_flag; + return; + } + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res) | (res>>32); + (mc68kcpu)->n_flag = NFLAG_64(res); + (mc68kcpu)->v_flag = VFLAG_CLEAR; + REG_D(mc68kcpu)[word2 & 7] = (res >> 32); + REG_D(mc68kcpu)[(word2 >> 12) & 7] = MASK_OUT_ABOVE_32(res); + return; + } + + res = src * dst; + if(!BIT_A(word2)) + { + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->v_flag = (res > 0xffffffff)<<7; + REG_D(mc68kcpu)[(word2 >> 12) & 7] = (mc68kcpu)->not_z_flag; + return; + } + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res) | (res>>32); + (mc68kcpu)->n_flag = NFLAG_64(res); + (mc68kcpu)->v_flag = VFLAG_CLEAR; + REG_D(mc68kcpu)[word2 & 7] = (res >> 32); + REG_D(mc68kcpu)[(word2 >> 12) & 7] = MASK_OUT_ABOVE_32(res); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_mull_32_pcix(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT64 src = OPER_PCIX_32(mc68kcpu); + UINT64 dst = REG_D(mc68kcpu)[(word2 >> 12) & 7]; + UINT64 res; + + (mc68kcpu)->c_flag = CFLAG_CLEAR; + + if(BIT_B(word2)) /* signed */ + { + res = (INT64)((INT32)src) * (INT64)((INT32)dst); + if(!BIT_A(word2)) + { + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->v_flag = ((INT64)res != (INT32)res)<<7; + REG_D(mc68kcpu)[(word2 >> 12) & 7] = (mc68kcpu)->not_z_flag; + return; + } + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res) | (res>>32); + (mc68kcpu)->n_flag = NFLAG_64(res); + (mc68kcpu)->v_flag = VFLAG_CLEAR; + REG_D(mc68kcpu)[word2 & 7] = (res >> 32); + REG_D(mc68kcpu)[(word2 >> 12) & 7] = MASK_OUT_ABOVE_32(res); + return; + } + + res = src * dst; + if(!BIT_A(word2)) + { + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->v_flag = (res > 0xffffffff)<<7; + REG_D(mc68kcpu)[(word2 >> 12) & 7] = (mc68kcpu)->not_z_flag; + return; + } + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res) | (res>>32); + (mc68kcpu)->n_flag = NFLAG_64(res); + (mc68kcpu)->v_flag = VFLAG_CLEAR; + REG_D(mc68kcpu)[word2 & 7] = (res >> 32); + REG_D(mc68kcpu)[(word2 >> 12) & 7] = MASK_OUT_ABOVE_32(res); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_mull_32_i(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 word2 = OPER_I_16(mc68kcpu); + UINT64 src = OPER_I_32(mc68kcpu); + UINT64 dst = REG_D(mc68kcpu)[(word2 >> 12) & 7]; + UINT64 res; + + (mc68kcpu)->c_flag = CFLAG_CLEAR; + + if(BIT_B(word2)) /* signed */ + { + res = (INT64)((INT32)src) * (INT64)((INT32)dst); + if(!BIT_A(word2)) + { + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->v_flag = ((INT64)res != (INT32)res)<<7; + REG_D(mc68kcpu)[(word2 >> 12) & 7] = (mc68kcpu)->not_z_flag; + return; + } + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res) | (res>>32); + (mc68kcpu)->n_flag = NFLAG_64(res); + (mc68kcpu)->v_flag = VFLAG_CLEAR; + REG_D(mc68kcpu)[word2 & 7] = (res >> 32); + REG_D(mc68kcpu)[(word2 >> 12) & 7] = MASK_OUT_ABOVE_32(res); + return; + } + + res = src * dst; + if(!BIT_A(word2)) + { + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->v_flag = (res > 0xffffffff)<<7; + REG_D(mc68kcpu)[(word2 >> 12) & 7] = (mc68kcpu)->not_z_flag; + return; + } + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res) | (res>>32); + (mc68kcpu)->n_flag = NFLAG_64(res); + (mc68kcpu)->v_flag = VFLAG_CLEAR; + REG_D(mc68kcpu)[word2 & 7] = (res >> 32); + REG_D(mc68kcpu)[(word2 >> 12) & 7] = MASK_OUT_ABOVE_32(res); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_nbcd_8_d(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 dst = *r_dst; + UINT32 res = MASK_OUT_ABOVE_8(0x9a - dst - XFLAG_AS_1(mc68kcpu)); + + if(res != 0x9a) + { + (mc68kcpu)->v_flag = ~res; /* Undefined V behavior */ + + if((res & 0x0f) == 0xa) + res = (res & 0xf0) + 0x10; + + res = MASK_OUT_ABOVE_8(res); + + (mc68kcpu)->v_flag &= res; /* Undefined V behavior part II */ + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; + + (mc68kcpu)->not_z_flag |= res; + (mc68kcpu)->c_flag = CFLAG_SET; + (mc68kcpu)->x_flag = XFLAG_SET; + } + else + { + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->x_flag = XFLAG_CLEAR; + } + (mc68kcpu)->n_flag = NFLAG_8(res); /* Undefined N behavior */ +} + + +void m68000_base_device_ops::m68k_op_nbcd_8_ai(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_AI_8(mc68kcpu); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + UINT32 res = MASK_OUT_ABOVE_8(0x9a - dst - XFLAG_AS_1(mc68kcpu)); + + if(res != 0x9a) + { + (mc68kcpu)->v_flag = ~res; /* Undefined V behavior */ + + if((res & 0x0f) == 0xa) + res = (res & 0xf0) + 0x10; + + res = MASK_OUT_ABOVE_8(res); + + (mc68kcpu)->v_flag &= res; /* Undefined V behavior part II */ + + m68ki_write_8((mc68kcpu), ea, MASK_OUT_ABOVE_8(res)); + + (mc68kcpu)->not_z_flag |= res; + (mc68kcpu)->c_flag = CFLAG_SET; + (mc68kcpu)->x_flag = XFLAG_SET; + } + else + { + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->x_flag = XFLAG_CLEAR; + } + (mc68kcpu)->n_flag = NFLAG_8(res); /* Undefined N behavior */ +} + + +void m68000_base_device_ops::m68k_op_nbcd_8_pi(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_PI_8(mc68kcpu); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + UINT32 res = MASK_OUT_ABOVE_8(0x9a - dst - XFLAG_AS_1(mc68kcpu)); + + if(res != 0x9a) + { + (mc68kcpu)->v_flag = ~res; /* Undefined V behavior */ + + if((res & 0x0f) == 0xa) + res = (res & 0xf0) + 0x10; + + res = MASK_OUT_ABOVE_8(res); + + (mc68kcpu)->v_flag &= res; /* Undefined V behavior part II */ + + m68ki_write_8((mc68kcpu), ea, MASK_OUT_ABOVE_8(res)); + + (mc68kcpu)->not_z_flag |= res; + (mc68kcpu)->c_flag = CFLAG_SET; + (mc68kcpu)->x_flag = XFLAG_SET; + } + else + { + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->x_flag = XFLAG_CLEAR; + } + (mc68kcpu)->n_flag = NFLAG_8(res); /* Undefined N behavior */ +} + + +void m68000_base_device_ops::m68k_op_nbcd_8_pi7(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_A7_PI_8(mc68kcpu); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + UINT32 res = MASK_OUT_ABOVE_8(0x9a - dst - XFLAG_AS_1(mc68kcpu)); + + if(res != 0x9a) + { + (mc68kcpu)->v_flag = ~res; /* Undefined V behavior */ + + if((res & 0x0f) == 0xa) + res = (res & 0xf0) + 0x10; + + res = MASK_OUT_ABOVE_8(res); + + (mc68kcpu)->v_flag &= res; /* Undefined V behavior part II */ + + m68ki_write_8((mc68kcpu), ea, MASK_OUT_ABOVE_8(res)); + + (mc68kcpu)->not_z_flag |= res; + (mc68kcpu)->c_flag = CFLAG_SET; + (mc68kcpu)->x_flag = XFLAG_SET; + } + else + { + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->x_flag = XFLAG_CLEAR; + } + (mc68kcpu)->n_flag = NFLAG_8(res); /* Undefined N behavior */ +} + + +void m68000_base_device_ops::m68k_op_nbcd_8_pd(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_PD_8(mc68kcpu); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + UINT32 res = MASK_OUT_ABOVE_8(0x9a - dst - XFLAG_AS_1(mc68kcpu)); + + if(res != 0x9a) + { + (mc68kcpu)->v_flag = ~res; /* Undefined V behavior */ + + if((res & 0x0f) == 0xa) + res = (res & 0xf0) + 0x10; + + res = MASK_OUT_ABOVE_8(res); + + (mc68kcpu)->v_flag &= res; /* Undefined V behavior part II */ + + m68ki_write_8((mc68kcpu), ea, MASK_OUT_ABOVE_8(res)); + + (mc68kcpu)->not_z_flag |= res; + (mc68kcpu)->c_flag = CFLAG_SET; + (mc68kcpu)->x_flag = XFLAG_SET; + } + else + { + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->x_flag = XFLAG_CLEAR; + } + (mc68kcpu)->n_flag = NFLAG_8(res); /* Undefined N behavior */ +} + + +void m68000_base_device_ops::m68k_op_nbcd_8_pd7(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_A7_PD_8(mc68kcpu); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + UINT32 res = MASK_OUT_ABOVE_8(0x9a - dst - XFLAG_AS_1(mc68kcpu)); + + if(res != 0x9a) + { + (mc68kcpu)->v_flag = ~res; /* Undefined V behavior */ + + if((res & 0x0f) == 0xa) + res = (res & 0xf0) + 0x10; + + res = MASK_OUT_ABOVE_8(res); + + (mc68kcpu)->v_flag &= res; /* Undefined V behavior part II */ + + m68ki_write_8((mc68kcpu), ea, MASK_OUT_ABOVE_8(res)); + + (mc68kcpu)->not_z_flag |= res; + (mc68kcpu)->c_flag = CFLAG_SET; + (mc68kcpu)->x_flag = XFLAG_SET; + } + else + { + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->x_flag = XFLAG_CLEAR; + } + (mc68kcpu)->n_flag = NFLAG_8(res); /* Undefined N behavior */ +} + + +void m68000_base_device_ops::m68k_op_nbcd_8_di(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_DI_8(mc68kcpu); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + UINT32 res = MASK_OUT_ABOVE_8(0x9a - dst - XFLAG_AS_1(mc68kcpu)); + + if(res != 0x9a) + { + (mc68kcpu)->v_flag = ~res; /* Undefined V behavior */ + + if((res & 0x0f) == 0xa) + res = (res & 0xf0) + 0x10; + + res = MASK_OUT_ABOVE_8(res); + + (mc68kcpu)->v_flag &= res; /* Undefined V behavior part II */ + + m68ki_write_8((mc68kcpu), ea, MASK_OUT_ABOVE_8(res)); + + (mc68kcpu)->not_z_flag |= res; + (mc68kcpu)->c_flag = CFLAG_SET; + (mc68kcpu)->x_flag = XFLAG_SET; + } + else + { + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->x_flag = XFLAG_CLEAR; + } + (mc68kcpu)->n_flag = NFLAG_8(res); /* Undefined N behavior */ +} + + +void m68000_base_device_ops::m68k_op_nbcd_8_ix(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_IX_8(mc68kcpu); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + UINT32 res = MASK_OUT_ABOVE_8(0x9a - dst - XFLAG_AS_1(mc68kcpu)); + + if(res != 0x9a) + { + (mc68kcpu)->v_flag = ~res; /* Undefined V behavior */ + + if((res & 0x0f) == 0xa) + res = (res & 0xf0) + 0x10; + + res = MASK_OUT_ABOVE_8(res); + + (mc68kcpu)->v_flag &= res; /* Undefined V behavior part II */ + + m68ki_write_8((mc68kcpu), ea, MASK_OUT_ABOVE_8(res)); + + (mc68kcpu)->not_z_flag |= res; + (mc68kcpu)->c_flag = CFLAG_SET; + (mc68kcpu)->x_flag = XFLAG_SET; + } + else + { + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->x_flag = XFLAG_CLEAR; + } + (mc68kcpu)->n_flag = NFLAG_8(res); /* Undefined N behavior */ +} + + +void m68000_base_device_ops::m68k_op_nbcd_8_aw(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AW_8(mc68kcpu); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + UINT32 res = MASK_OUT_ABOVE_8(0x9a - dst - XFLAG_AS_1(mc68kcpu)); + + if(res != 0x9a) + { + (mc68kcpu)->v_flag = ~res; /* Undefined V behavior */ + + if((res & 0x0f) == 0xa) + res = (res & 0xf0) + 0x10; + + res = MASK_OUT_ABOVE_8(res); + + (mc68kcpu)->v_flag &= res; /* Undefined V behavior part II */ + + m68ki_write_8((mc68kcpu), ea, MASK_OUT_ABOVE_8(res)); + + (mc68kcpu)->not_z_flag |= res; + (mc68kcpu)->c_flag = CFLAG_SET; + (mc68kcpu)->x_flag = XFLAG_SET; + } + else + { + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->x_flag = XFLAG_CLEAR; + } + (mc68kcpu)->n_flag = NFLAG_8(res); /* Undefined N behavior */ +} + + +void m68000_base_device_ops::m68k_op_nbcd_8_al(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AL_8(mc68kcpu); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + UINT32 res = MASK_OUT_ABOVE_8(0x9a - dst - XFLAG_AS_1(mc68kcpu)); + + if(res != 0x9a) + { + (mc68kcpu)->v_flag = ~res; /* Undefined V behavior */ + + if((res & 0x0f) == 0xa) + res = (res & 0xf0) + 0x10; + + res = MASK_OUT_ABOVE_8(res); + + (mc68kcpu)->v_flag &= res; /* Undefined V behavior part II */ + + m68ki_write_8((mc68kcpu), ea, MASK_OUT_ABOVE_8(res)); + + (mc68kcpu)->not_z_flag |= res; + (mc68kcpu)->c_flag = CFLAG_SET; + (mc68kcpu)->x_flag = XFLAG_SET; + } + else + { + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->x_flag = XFLAG_CLEAR; + } + (mc68kcpu)->n_flag = NFLAG_8(res); /* Undefined N behavior */ +} + + +void m68000_base_device_ops::m68k_op_neg_8_d(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 res = 0 - MASK_OUT_ABOVE_8(*r_dst); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag = CFLAG_8(res); + (mc68kcpu)->v_flag = *r_dst & res; + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | (mc68kcpu)->not_z_flag; +} + + +void m68000_base_device_ops::m68k_op_neg_8_ai(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_AI_8(mc68kcpu); + UINT32 src = m68ki_read_8((mc68kcpu), ea); + UINT32 res = 0 - src; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag = CFLAG_8(res); + (mc68kcpu)->v_flag = src & res; + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + + m68ki_write_8((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_neg_8_pi(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_PI_8(mc68kcpu); + UINT32 src = m68ki_read_8((mc68kcpu), ea); + UINT32 res = 0 - src; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag = CFLAG_8(res); + (mc68kcpu)->v_flag = src & res; + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + + m68ki_write_8((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_neg_8_pi7(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_A7_PI_8(mc68kcpu); + UINT32 src = m68ki_read_8((mc68kcpu), ea); + UINT32 res = 0 - src; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag = CFLAG_8(res); + (mc68kcpu)->v_flag = src & res; + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + + m68ki_write_8((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_neg_8_pd(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_PD_8(mc68kcpu); + UINT32 src = m68ki_read_8((mc68kcpu), ea); + UINT32 res = 0 - src; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag = CFLAG_8(res); + (mc68kcpu)->v_flag = src & res; + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + + m68ki_write_8((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_neg_8_pd7(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_A7_PD_8(mc68kcpu); + UINT32 src = m68ki_read_8((mc68kcpu), ea); + UINT32 res = 0 - src; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag = CFLAG_8(res); + (mc68kcpu)->v_flag = src & res; + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + + m68ki_write_8((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_neg_8_di(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_DI_8(mc68kcpu); + UINT32 src = m68ki_read_8((mc68kcpu), ea); + UINT32 res = 0 - src; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag = CFLAG_8(res); + (mc68kcpu)->v_flag = src & res; + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + + m68ki_write_8((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_neg_8_ix(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_IX_8(mc68kcpu); + UINT32 src = m68ki_read_8((mc68kcpu), ea); + UINT32 res = 0 - src; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag = CFLAG_8(res); + (mc68kcpu)->v_flag = src & res; + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + + m68ki_write_8((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_neg_8_aw(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AW_8(mc68kcpu); + UINT32 src = m68ki_read_8((mc68kcpu), ea); + UINT32 res = 0 - src; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag = CFLAG_8(res); + (mc68kcpu)->v_flag = src & res; + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + + m68ki_write_8((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_neg_8_al(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AL_8(mc68kcpu); + UINT32 src = m68ki_read_8((mc68kcpu), ea); + UINT32 res = 0 - src; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag = CFLAG_8(res); + (mc68kcpu)->v_flag = src & res; + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + + m68ki_write_8((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_neg_16_d(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 res = 0 - MASK_OUT_ABOVE_16(*r_dst); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag = CFLAG_16(res); + (mc68kcpu)->v_flag = (*r_dst & res)>>8; + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | (mc68kcpu)->not_z_flag; +} + + +void m68000_base_device_ops::m68k_op_neg_16_ai(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_AI_16(mc68kcpu); + UINT32 src = m68ki_read_16((mc68kcpu), ea); + UINT32 res = 0 - src; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag = CFLAG_16(res); + (mc68kcpu)->v_flag = (src & res)>>8; + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + + m68ki_write_16((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_neg_16_pi(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_PI_16(mc68kcpu); + UINT32 src = m68ki_read_16((mc68kcpu), ea); + UINT32 res = 0 - src; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag = CFLAG_16(res); + (mc68kcpu)->v_flag = (src & res)>>8; + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + + m68ki_write_16((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_neg_16_pd(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_PD_16(mc68kcpu); + UINT32 src = m68ki_read_16((mc68kcpu), ea); + UINT32 res = 0 - src; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag = CFLAG_16(res); + (mc68kcpu)->v_flag = (src & res)>>8; + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + + m68ki_write_16((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_neg_16_di(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_DI_16(mc68kcpu); + UINT32 src = m68ki_read_16((mc68kcpu), ea); + UINT32 res = 0 - src; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag = CFLAG_16(res); + (mc68kcpu)->v_flag = (src & res)>>8; + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + + m68ki_write_16((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_neg_16_ix(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_IX_16(mc68kcpu); + UINT32 src = m68ki_read_16((mc68kcpu), ea); + UINT32 res = 0 - src; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag = CFLAG_16(res); + (mc68kcpu)->v_flag = (src & res)>>8; + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + + m68ki_write_16((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_neg_16_aw(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AW_16(mc68kcpu); + UINT32 src = m68ki_read_16((mc68kcpu), ea); + UINT32 res = 0 - src; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag = CFLAG_16(res); + (mc68kcpu)->v_flag = (src & res)>>8; + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + + m68ki_write_16((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_neg_16_al(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AL_16(mc68kcpu); + UINT32 src = m68ki_read_16((mc68kcpu), ea); + UINT32 res = 0 - src; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag = CFLAG_16(res); + (mc68kcpu)->v_flag = (src & res)>>8; + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + + m68ki_write_16((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_neg_32_d(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 res = 0 - *r_dst; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag = CFLAG_SUB_32(*r_dst, 0, res); + (mc68kcpu)->v_flag = (*r_dst & res)>>24; + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + + *r_dst = (mc68kcpu)->not_z_flag; +} + + +void m68000_base_device_ops::m68k_op_neg_32_ai(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_AI_32(mc68kcpu); + UINT32 src = m68ki_read_32((mc68kcpu), ea); + UINT32 res = 0 - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag = CFLAG_SUB_32(src, 0, res); + (mc68kcpu)->v_flag = (src & res)>>24; + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + + m68ki_write_32((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_neg_32_pi(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_PI_32(mc68kcpu); + UINT32 src = m68ki_read_32((mc68kcpu), ea); + UINT32 res = 0 - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag = CFLAG_SUB_32(src, 0, res); + (mc68kcpu)->v_flag = (src & res)>>24; + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + + m68ki_write_32((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_neg_32_pd(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_PD_32(mc68kcpu); + UINT32 src = m68ki_read_32((mc68kcpu), ea); + UINT32 res = 0 - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag = CFLAG_SUB_32(src, 0, res); + (mc68kcpu)->v_flag = (src & res)>>24; + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + + m68ki_write_32((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_neg_32_di(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_DI_32(mc68kcpu); + UINT32 src = m68ki_read_32((mc68kcpu), ea); + UINT32 res = 0 - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag = CFLAG_SUB_32(src, 0, res); + (mc68kcpu)->v_flag = (src & res)>>24; + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + + m68ki_write_32((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_neg_32_ix(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_IX_32(mc68kcpu); + UINT32 src = m68ki_read_32((mc68kcpu), ea); + UINT32 res = 0 - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag = CFLAG_SUB_32(src, 0, res); + (mc68kcpu)->v_flag = (src & res)>>24; + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + + m68ki_write_32((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_neg_32_aw(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AW_32(mc68kcpu); + UINT32 src = m68ki_read_32((mc68kcpu), ea); + UINT32 res = 0 - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag = CFLAG_SUB_32(src, 0, res); + (mc68kcpu)->v_flag = (src & res)>>24; + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + + m68ki_write_32((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_neg_32_al(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AL_32(mc68kcpu); + UINT32 src = m68ki_read_32((mc68kcpu), ea); + UINT32 res = 0 - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag = CFLAG_SUB_32(src, 0, res); + (mc68kcpu)->v_flag = (src & res)>>24; + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + + m68ki_write_32((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_negx_8_d(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 res = 0 - MASK_OUT_ABOVE_8(*r_dst) - XFLAG_AS_1(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->v_flag = *r_dst & res; + + res = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->not_z_flag |= res; + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; +} + + +void m68000_base_device_ops::m68k_op_negx_8_ai(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_AI_8(mc68kcpu); + UINT32 src = m68ki_read_8((mc68kcpu), ea); + UINT32 res = 0 - src - XFLAG_AS_1(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->v_flag = src & res; + + res = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->not_z_flag |= res; + + m68ki_write_8((mc68kcpu), ea, res); +} + + +void m68000_base_device_ops::m68k_op_negx_8_pi(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_PI_8(mc68kcpu); + UINT32 src = m68ki_read_8((mc68kcpu), ea); + UINT32 res = 0 - src - XFLAG_AS_1(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->v_flag = src & res; + + res = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->not_z_flag |= res; + + m68ki_write_8((mc68kcpu), ea, res); +} + + +void m68000_base_device_ops::m68k_op_negx_8_pi7(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_A7_PI_8(mc68kcpu); + UINT32 src = m68ki_read_8((mc68kcpu), ea); + UINT32 res = 0 - src - XFLAG_AS_1(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->v_flag = src & res; + + res = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->not_z_flag |= res; + + m68ki_write_8((mc68kcpu), ea, res); +} + + +void m68000_base_device_ops::m68k_op_negx_8_pd(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_PD_8(mc68kcpu); + UINT32 src = m68ki_read_8((mc68kcpu), ea); + UINT32 res = 0 - src - XFLAG_AS_1(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->v_flag = src & res; + + res = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->not_z_flag |= res; + + m68ki_write_8((mc68kcpu), ea, res); +} + + +void m68000_base_device_ops::m68k_op_negx_8_pd7(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_A7_PD_8(mc68kcpu); + UINT32 src = m68ki_read_8((mc68kcpu), ea); + UINT32 res = 0 - src - XFLAG_AS_1(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->v_flag = src & res; + + res = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->not_z_flag |= res; + + m68ki_write_8((mc68kcpu), ea, res); +} + + +void m68000_base_device_ops::m68k_op_negx_8_di(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_DI_8(mc68kcpu); + UINT32 src = m68ki_read_8((mc68kcpu), ea); + UINT32 res = 0 - src - XFLAG_AS_1(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->v_flag = src & res; + + res = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->not_z_flag |= res; + + m68ki_write_8((mc68kcpu), ea, res); +} + + +void m68000_base_device_ops::m68k_op_negx_8_ix(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_IX_8(mc68kcpu); + UINT32 src = m68ki_read_8((mc68kcpu), ea); + UINT32 res = 0 - src - XFLAG_AS_1(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->v_flag = src & res; + + res = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->not_z_flag |= res; + + m68ki_write_8((mc68kcpu), ea, res); +} + + +void m68000_base_device_ops::m68k_op_negx_8_aw(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AW_8(mc68kcpu); + UINT32 src = m68ki_read_8((mc68kcpu), ea); + UINT32 res = 0 - src - XFLAG_AS_1(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->v_flag = src & res; + + res = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->not_z_flag |= res; + + m68ki_write_8((mc68kcpu), ea, res); +} + + +void m68000_base_device_ops::m68k_op_negx_8_al(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AL_8(mc68kcpu); + UINT32 src = m68ki_read_8((mc68kcpu), ea); + UINT32 res = 0 - src - XFLAG_AS_1(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->v_flag = src & res; + + res = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->not_z_flag |= res; + + m68ki_write_8((mc68kcpu), ea, res); +} + + +void m68000_base_device_ops::m68k_op_negx_16_d(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 res = 0 - MASK_OUT_ABOVE_16(*r_dst) - XFLAG_AS_1(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_16(res); + (mc68kcpu)->v_flag = (*r_dst & res)>>8; + + res = MASK_OUT_ABOVE_16(res); + (mc68kcpu)->not_z_flag |= res; + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; +} + + +void m68000_base_device_ops::m68k_op_negx_16_ai(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_AI_16(mc68kcpu); + UINT32 src = m68ki_read_16((mc68kcpu), ea); + UINT32 res = 0 - MASK_OUT_ABOVE_16(src) - XFLAG_AS_1(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_16(res); + (mc68kcpu)->v_flag = (src & res)>>8; + + res = MASK_OUT_ABOVE_16(res); + (mc68kcpu)->not_z_flag |= res; + + m68ki_write_16((mc68kcpu), ea, res); +} + + +void m68000_base_device_ops::m68k_op_negx_16_pi(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_PI_16(mc68kcpu); + UINT32 src = m68ki_read_16((mc68kcpu), ea); + UINT32 res = 0 - MASK_OUT_ABOVE_16(src) - XFLAG_AS_1(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_16(res); + (mc68kcpu)->v_flag = (src & res)>>8; + + res = MASK_OUT_ABOVE_16(res); + (mc68kcpu)->not_z_flag |= res; + + m68ki_write_16((mc68kcpu), ea, res); +} + + +void m68000_base_device_ops::m68k_op_negx_16_pd(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_PD_16(mc68kcpu); + UINT32 src = m68ki_read_16((mc68kcpu), ea); + UINT32 res = 0 - MASK_OUT_ABOVE_16(src) - XFLAG_AS_1(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_16(res); + (mc68kcpu)->v_flag = (src & res)>>8; + + res = MASK_OUT_ABOVE_16(res); + (mc68kcpu)->not_z_flag |= res; + + m68ki_write_16((mc68kcpu), ea, res); +} + + +void m68000_base_device_ops::m68k_op_negx_16_di(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_DI_16(mc68kcpu); + UINT32 src = m68ki_read_16((mc68kcpu), ea); + UINT32 res = 0 - MASK_OUT_ABOVE_16(src) - XFLAG_AS_1(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_16(res); + (mc68kcpu)->v_flag = (src & res)>>8; + + res = MASK_OUT_ABOVE_16(res); + (mc68kcpu)->not_z_flag |= res; + + m68ki_write_16((mc68kcpu), ea, res); +} + + +void m68000_base_device_ops::m68k_op_negx_16_ix(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_IX_16(mc68kcpu); + UINT32 src = m68ki_read_16((mc68kcpu), ea); + UINT32 res = 0 - MASK_OUT_ABOVE_16(src) - XFLAG_AS_1(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_16(res); + (mc68kcpu)->v_flag = (src & res)>>8; + + res = MASK_OUT_ABOVE_16(res); + (mc68kcpu)->not_z_flag |= res; + + m68ki_write_16((mc68kcpu), ea, res); +} + + +void m68000_base_device_ops::m68k_op_negx_16_aw(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AW_16(mc68kcpu); + UINT32 src = m68ki_read_16((mc68kcpu), ea); + UINT32 res = 0 - MASK_OUT_ABOVE_16(src) - XFLAG_AS_1(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_16(res); + (mc68kcpu)->v_flag = (src & res)>>8; + + res = MASK_OUT_ABOVE_16(res); + (mc68kcpu)->not_z_flag |= res; + + m68ki_write_16((mc68kcpu), ea, res); +} + + +void m68000_base_device_ops::m68k_op_negx_16_al(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AL_16(mc68kcpu); + UINT32 src = m68ki_read_16((mc68kcpu), ea); + UINT32 res = 0 - MASK_OUT_ABOVE_16(src) - XFLAG_AS_1(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_16(res); + (mc68kcpu)->v_flag = (src & res)>>8; + + res = MASK_OUT_ABOVE_16(res); + (mc68kcpu)->not_z_flag |= res; + + m68ki_write_16((mc68kcpu), ea, res); +} + + +void m68000_base_device_ops::m68k_op_negx_32_d(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 res = 0 - MASK_OUT_ABOVE_32(*r_dst) - XFLAG_AS_1(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_SUB_32(*r_dst, 0, res); + (mc68kcpu)->v_flag = (*r_dst & res)>>24; + + res = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->not_z_flag |= res; + + *r_dst = res; +} + + +void m68000_base_device_ops::m68k_op_negx_32_ai(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_AI_32(mc68kcpu); + UINT32 src = m68ki_read_32((mc68kcpu), ea); + UINT32 res = 0 - MASK_OUT_ABOVE_32(src) - XFLAG_AS_1(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_SUB_32(src, 0, res); + (mc68kcpu)->v_flag = (src & res)>>24; + + res = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->not_z_flag |= res; + + m68ki_write_32((mc68kcpu), ea, res); +} + + +void m68000_base_device_ops::m68k_op_negx_32_pi(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_PI_32(mc68kcpu); + UINT32 src = m68ki_read_32((mc68kcpu), ea); + UINT32 res = 0 - MASK_OUT_ABOVE_32(src) - XFLAG_AS_1(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_SUB_32(src, 0, res); + (mc68kcpu)->v_flag = (src & res)>>24; + + res = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->not_z_flag |= res; + + m68ki_write_32((mc68kcpu), ea, res); +} + + +void m68000_base_device_ops::m68k_op_negx_32_pd(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_PD_32(mc68kcpu); + UINT32 src = m68ki_read_32((mc68kcpu), ea); + UINT32 res = 0 - MASK_OUT_ABOVE_32(src) - XFLAG_AS_1(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_SUB_32(src, 0, res); + (mc68kcpu)->v_flag = (src & res)>>24; + + res = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->not_z_flag |= res; + + m68ki_write_32((mc68kcpu), ea, res); +} + + +void m68000_base_device_ops::m68k_op_negx_32_di(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_DI_32(mc68kcpu); + UINT32 src = m68ki_read_32((mc68kcpu), ea); + UINT32 res = 0 - MASK_OUT_ABOVE_32(src) - XFLAG_AS_1(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_SUB_32(src, 0, res); + (mc68kcpu)->v_flag = (src & res)>>24; + + res = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->not_z_flag |= res; + + m68ki_write_32((mc68kcpu), ea, res); +} + + +void m68000_base_device_ops::m68k_op_negx_32_ix(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_IX_32(mc68kcpu); + UINT32 src = m68ki_read_32((mc68kcpu), ea); + UINT32 res = 0 - MASK_OUT_ABOVE_32(src) - XFLAG_AS_1(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_SUB_32(src, 0, res); + (mc68kcpu)->v_flag = (src & res)>>24; + + res = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->not_z_flag |= res; + + m68ki_write_32((mc68kcpu), ea, res); +} + + +void m68000_base_device_ops::m68k_op_negx_32_aw(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AW_32(mc68kcpu); + UINT32 src = m68ki_read_32((mc68kcpu), ea); + UINT32 res = 0 - MASK_OUT_ABOVE_32(src) - XFLAG_AS_1(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_SUB_32(src, 0, res); + (mc68kcpu)->v_flag = (src & res)>>24; + + res = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->not_z_flag |= res; + + m68ki_write_32((mc68kcpu), ea, res); +} + + +void m68000_base_device_ops::m68k_op_negx_32_al(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AL_32(mc68kcpu); + UINT32 src = m68ki_read_32((mc68kcpu), ea); + UINT32 res = 0 - MASK_OUT_ABOVE_32(src) - XFLAG_AS_1(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_SUB_32(src, 0, res); + (mc68kcpu)->v_flag = (src & res)>>24; + + res = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->not_z_flag |= res; + + m68ki_write_32((mc68kcpu), ea, res); +} + + +void m68000_base_device_ops::m68k_op_nop(m68000_base_device* mc68kcpu) +{ + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ +} + + +void m68000_base_device_ops::m68k_op_not_8_d(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_8(~*r_dst); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_not_8_ai(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_AI_8(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_8(~m68ki_read_8((mc68kcpu), ea)); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_not_8_pi(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_PI_8(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_8(~m68ki_read_8((mc68kcpu), ea)); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_not_8_pi7(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_A7_PI_8(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_8(~m68ki_read_8((mc68kcpu), ea)); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_not_8_pd(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_PD_8(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_8(~m68ki_read_8((mc68kcpu), ea)); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_not_8_pd7(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_A7_PD_8(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_8(~m68ki_read_8((mc68kcpu), ea)); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_not_8_di(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_DI_8(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_8(~m68ki_read_8((mc68kcpu), ea)); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_not_8_ix(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_IX_8(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_8(~m68ki_read_8((mc68kcpu), ea)); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_not_8_aw(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AW_8(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_8(~m68ki_read_8((mc68kcpu), ea)); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_not_8_al(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AL_8(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_8(~m68ki_read_8((mc68kcpu), ea)); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_not_16_d(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_16(~*r_dst); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_not_16_ai(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_AI_16(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_16(~m68ki_read_16((mc68kcpu), ea)); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_not_16_pi(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_PI_16(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_16(~m68ki_read_16((mc68kcpu), ea)); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_not_16_pd(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_PD_16(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_16(~m68ki_read_16((mc68kcpu), ea)); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_not_16_di(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_DI_16(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_16(~m68ki_read_16((mc68kcpu), ea)); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_not_16_ix(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_IX_16(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_16(~m68ki_read_16((mc68kcpu), ea)); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_not_16_aw(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AW_16(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_16(~m68ki_read_16((mc68kcpu), ea)); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_not_16_al(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AL_16(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_16(~m68ki_read_16((mc68kcpu), ea)); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_not_32_d(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 res = *r_dst = MASK_OUT_ABOVE_32(~*r_dst); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_not_32_ai(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_AI_32(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_32(~m68ki_read_32((mc68kcpu), ea)); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_not_32_pi(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_PI_32(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_32(~m68ki_read_32((mc68kcpu), ea)); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_not_32_pd(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_PD_32(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_32(~m68ki_read_32((mc68kcpu), ea)); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_not_32_di(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_DI_32(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_32(~m68ki_read_32((mc68kcpu), ea)); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_not_32_ix(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_IX_32(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_32(~m68ki_read_32((mc68kcpu), ea)); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_not_32_aw(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AW_32(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_32(~m68ki_read_32((mc68kcpu), ea)); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_not_32_al(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AL_32(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_32(~m68ki_read_32((mc68kcpu), ea)); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_or_8_er_d(m68000_base_device* mc68kcpu) +{ + UINT32 res = MASK_OUT_ABOVE_8((DX(mc68kcpu) |= MASK_OUT_ABOVE_8(DY(mc68kcpu)))); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_or_8_er_ai(m68000_base_device* mc68kcpu) +{ + UINT32 res = MASK_OUT_ABOVE_8((DX(mc68kcpu) |= OPER_AY_AI_8(mc68kcpu))); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_or_8_er_pi(m68000_base_device* mc68kcpu) +{ + UINT32 res = MASK_OUT_ABOVE_8((DX(mc68kcpu) |= OPER_AY_PI_8(mc68kcpu))); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_or_8_er_pi7(m68000_base_device* mc68kcpu) +{ + UINT32 res = MASK_OUT_ABOVE_8((DX(mc68kcpu) |= OPER_A7_PI_8(mc68kcpu))); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_or_8_er_pd(m68000_base_device* mc68kcpu) +{ + UINT32 res = MASK_OUT_ABOVE_8((DX(mc68kcpu) |= OPER_AY_PD_8(mc68kcpu))); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_or_8_er_pd7(m68000_base_device* mc68kcpu) +{ + UINT32 res = MASK_OUT_ABOVE_8((DX(mc68kcpu) |= OPER_A7_PD_8(mc68kcpu))); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_or_8_er_di(m68000_base_device* mc68kcpu) +{ + UINT32 res = MASK_OUT_ABOVE_8((DX(mc68kcpu) |= OPER_AY_DI_8(mc68kcpu))); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_or_8_er_ix(m68000_base_device* mc68kcpu) +{ + UINT32 res = MASK_OUT_ABOVE_8((DX(mc68kcpu) |= OPER_AY_IX_8(mc68kcpu))); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_or_8_er_aw(m68000_base_device* mc68kcpu) +{ + UINT32 res = MASK_OUT_ABOVE_8((DX(mc68kcpu) |= OPER_AW_8(mc68kcpu))); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_or_8_er_al(m68000_base_device* mc68kcpu) +{ + UINT32 res = MASK_OUT_ABOVE_8((DX(mc68kcpu) |= OPER_AL_8(mc68kcpu))); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_or_8_er_pcdi(m68000_base_device* mc68kcpu) +{ + UINT32 res = MASK_OUT_ABOVE_8((DX(mc68kcpu) |= OPER_PCDI_8(mc68kcpu))); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_or_8_er_pcix(m68000_base_device* mc68kcpu) +{ + UINT32 res = MASK_OUT_ABOVE_8((DX(mc68kcpu) |= OPER_PCIX_8(mc68kcpu))); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_or_8_er_i(m68000_base_device* mc68kcpu) +{ + UINT32 res = MASK_OUT_ABOVE_8((DX(mc68kcpu) |= OPER_I_8(mc68kcpu))); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_or_16_er_d(m68000_base_device* mc68kcpu) +{ + UINT32 res = MASK_OUT_ABOVE_16((DX(mc68kcpu) |= MASK_OUT_ABOVE_16(DY(mc68kcpu)))); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_or_16_er_ai(m68000_base_device* mc68kcpu) +{ + UINT32 res = MASK_OUT_ABOVE_16((DX(mc68kcpu) |= OPER_AY_AI_16(mc68kcpu))); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_or_16_er_pi(m68000_base_device* mc68kcpu) +{ + UINT32 res = MASK_OUT_ABOVE_16((DX(mc68kcpu) |= OPER_AY_PI_16(mc68kcpu))); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_or_16_er_pd(m68000_base_device* mc68kcpu) +{ + UINT32 res = MASK_OUT_ABOVE_16((DX(mc68kcpu) |= OPER_AY_PD_16(mc68kcpu))); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_or_16_er_di(m68000_base_device* mc68kcpu) +{ + UINT32 res = MASK_OUT_ABOVE_16((DX(mc68kcpu) |= OPER_AY_DI_16(mc68kcpu))); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_or_16_er_ix(m68000_base_device* mc68kcpu) +{ + UINT32 res = MASK_OUT_ABOVE_16((DX(mc68kcpu) |= OPER_AY_IX_16(mc68kcpu))); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_or_16_er_aw(m68000_base_device* mc68kcpu) +{ + UINT32 res = MASK_OUT_ABOVE_16((DX(mc68kcpu) |= OPER_AW_16(mc68kcpu))); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_or_16_er_al(m68000_base_device* mc68kcpu) +{ + UINT32 res = MASK_OUT_ABOVE_16((DX(mc68kcpu) |= OPER_AL_16(mc68kcpu))); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_or_16_er_pcdi(m68000_base_device* mc68kcpu) +{ + UINT32 res = MASK_OUT_ABOVE_16((DX(mc68kcpu) |= OPER_PCDI_16(mc68kcpu))); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_or_16_er_pcix(m68000_base_device* mc68kcpu) +{ + UINT32 res = MASK_OUT_ABOVE_16((DX(mc68kcpu) |= OPER_PCIX_16(mc68kcpu))); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_or_16_er_i(m68000_base_device* mc68kcpu) +{ + UINT32 res = MASK_OUT_ABOVE_16((DX(mc68kcpu) |= OPER_I_16(mc68kcpu))); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_or_32_er_d(m68000_base_device* mc68kcpu) +{ + UINT32 res = DX(mc68kcpu) |= DY(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_or_32_er_ai(m68000_base_device* mc68kcpu) +{ + UINT32 res = DX(mc68kcpu) |= OPER_AY_AI_32(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_or_32_er_pi(m68000_base_device* mc68kcpu) +{ + UINT32 res = DX(mc68kcpu) |= OPER_AY_PI_32(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_or_32_er_pd(m68000_base_device* mc68kcpu) +{ + UINT32 res = DX(mc68kcpu) |= OPER_AY_PD_32(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_or_32_er_di(m68000_base_device* mc68kcpu) +{ + UINT32 res = DX(mc68kcpu) |= OPER_AY_DI_32(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_or_32_er_ix(m68000_base_device* mc68kcpu) +{ + UINT32 res = DX(mc68kcpu) |= OPER_AY_IX_32(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_or_32_er_aw(m68000_base_device* mc68kcpu) +{ + UINT32 res = DX(mc68kcpu) |= OPER_AW_32(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_or_32_er_al(m68000_base_device* mc68kcpu) +{ + UINT32 res = DX(mc68kcpu) |= OPER_AL_32(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_or_32_er_pcdi(m68000_base_device* mc68kcpu) +{ + UINT32 res = DX(mc68kcpu) |= OPER_PCDI_32(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_or_32_er_pcix(m68000_base_device* mc68kcpu) +{ + UINT32 res = DX(mc68kcpu) |= OPER_PCIX_32(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_or_32_er_i(m68000_base_device* mc68kcpu) +{ + UINT32 res = DX(mc68kcpu) |= OPER_I_32(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_or_8_re_ai(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_AI_8(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_8(DX(mc68kcpu) | m68ki_read_8((mc68kcpu), ea)); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_or_8_re_pi(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_PI_8(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_8(DX(mc68kcpu) | m68ki_read_8((mc68kcpu), ea)); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_or_8_re_pi7(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_A7_PI_8(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_8(DX(mc68kcpu) | m68ki_read_8((mc68kcpu), ea)); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_or_8_re_pd(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_PD_8(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_8(DX(mc68kcpu) | m68ki_read_8((mc68kcpu), ea)); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_or_8_re_pd7(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_A7_PD_8(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_8(DX(mc68kcpu) | m68ki_read_8((mc68kcpu), ea)); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_or_8_re_di(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_DI_8(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_8(DX(mc68kcpu) | m68ki_read_8((mc68kcpu), ea)); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_or_8_re_ix(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_IX_8(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_8(DX(mc68kcpu) | m68ki_read_8((mc68kcpu), ea)); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_or_8_re_aw(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AW_8(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_8(DX(mc68kcpu) | m68ki_read_8((mc68kcpu), ea)); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_or_8_re_al(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AL_8(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_8(DX(mc68kcpu) | m68ki_read_8((mc68kcpu), ea)); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_or_16_re_ai(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_AI_16(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_16(DX(mc68kcpu) | m68ki_read_16((mc68kcpu), ea)); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_or_16_re_pi(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_PI_16(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_16(DX(mc68kcpu) | m68ki_read_16((mc68kcpu), ea)); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_or_16_re_pd(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_PD_16(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_16(DX(mc68kcpu) | m68ki_read_16((mc68kcpu), ea)); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_or_16_re_di(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_DI_16(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_16(DX(mc68kcpu) | m68ki_read_16((mc68kcpu), ea)); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_or_16_re_ix(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_IX_16(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_16(DX(mc68kcpu) | m68ki_read_16((mc68kcpu), ea)); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_or_16_re_aw(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AW_16(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_16(DX(mc68kcpu) | m68ki_read_16((mc68kcpu), ea)); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_or_16_re_al(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AL_16(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_16(DX(mc68kcpu) | m68ki_read_16((mc68kcpu), ea)); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_or_32_re_ai(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_AI_32(mc68kcpu); + UINT32 res = DX(mc68kcpu) | m68ki_read_32((mc68kcpu), ea); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_or_32_re_pi(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_PI_32(mc68kcpu); + UINT32 res = DX(mc68kcpu) | m68ki_read_32((mc68kcpu), ea); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_or_32_re_pd(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_PD_32(mc68kcpu); + UINT32 res = DX(mc68kcpu) | m68ki_read_32((mc68kcpu), ea); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_or_32_re_di(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_DI_32(mc68kcpu); + UINT32 res = DX(mc68kcpu) | m68ki_read_32((mc68kcpu), ea); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_or_32_re_ix(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_IX_32(mc68kcpu); + UINT32 res = DX(mc68kcpu) | m68ki_read_32((mc68kcpu), ea); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_or_32_re_aw(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AW_32(mc68kcpu); + UINT32 res = DX(mc68kcpu) | m68ki_read_32((mc68kcpu), ea); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_or_32_re_al(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AL_32(mc68kcpu); + UINT32 res = DX(mc68kcpu) | m68ki_read_32((mc68kcpu), ea); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_ori_8_d(m68000_base_device* mc68kcpu) +{ + UINT32 res = MASK_OUT_ABOVE_8((DY(mc68kcpu) |= OPER_I_8(mc68kcpu))); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_ori_8_ai(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_8(mc68kcpu); + UINT32 ea = EA_AY_AI_8(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_8(src | m68ki_read_8((mc68kcpu), ea)); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_ori_8_pi(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_8(mc68kcpu); + UINT32 ea = EA_AY_PI_8(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_8(src | m68ki_read_8((mc68kcpu), ea)); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_ori_8_pi7(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_8(mc68kcpu); + UINT32 ea = EA_A7_PI_8(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_8(src | m68ki_read_8((mc68kcpu), ea)); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_ori_8_pd(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_8(mc68kcpu); + UINT32 ea = EA_AY_PD_8(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_8(src | m68ki_read_8((mc68kcpu), ea)); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_ori_8_pd7(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_8(mc68kcpu); + UINT32 ea = EA_A7_PD_8(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_8(src | m68ki_read_8((mc68kcpu), ea)); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_ori_8_di(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_8(mc68kcpu); + UINT32 ea = EA_AY_DI_8(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_8(src | m68ki_read_8((mc68kcpu), ea)); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_ori_8_ix(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_8(mc68kcpu); + UINT32 ea = EA_AY_IX_8(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_8(src | m68ki_read_8((mc68kcpu), ea)); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_ori_8_aw(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_8(mc68kcpu); + UINT32 ea = EA_AW_8(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_8(src | m68ki_read_8((mc68kcpu), ea)); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_ori_8_al(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_8(mc68kcpu); + UINT32 ea = EA_AL_8(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_8(src | m68ki_read_8((mc68kcpu), ea)); + + m68ki_write_8((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_ori_16_d(m68000_base_device* mc68kcpu) +{ + UINT32 res = MASK_OUT_ABOVE_16(DY(mc68kcpu) |= OPER_I_16(mc68kcpu)); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_ori_16_ai(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_16(mc68kcpu); + UINT32 ea = EA_AY_AI_16(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_16(src | m68ki_read_16((mc68kcpu), ea)); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_ori_16_pi(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_16(mc68kcpu); + UINT32 ea = EA_AY_PI_16(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_16(src | m68ki_read_16((mc68kcpu), ea)); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_ori_16_pd(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_16(mc68kcpu); + UINT32 ea = EA_AY_PD_16(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_16(src | m68ki_read_16((mc68kcpu), ea)); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_ori_16_di(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_16(mc68kcpu); + UINT32 ea = EA_AY_DI_16(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_16(src | m68ki_read_16((mc68kcpu), ea)); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_ori_16_ix(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_16(mc68kcpu); + UINT32 ea = EA_AY_IX_16(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_16(src | m68ki_read_16((mc68kcpu), ea)); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_ori_16_aw(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_16(mc68kcpu); + UINT32 ea = EA_AW_16(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_16(src | m68ki_read_16((mc68kcpu), ea)); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_ori_16_al(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_16(mc68kcpu); + UINT32 ea = EA_AL_16(mc68kcpu); + UINT32 res = MASK_OUT_ABOVE_16(src | m68ki_read_16((mc68kcpu), ea)); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_ori_32_d(m68000_base_device* mc68kcpu) +{ + UINT32 res = DY(mc68kcpu) |= OPER_I_32(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_ori_32_ai(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_32(mc68kcpu); + UINT32 ea = EA_AY_AI_32(mc68kcpu); + UINT32 res = src | m68ki_read_32((mc68kcpu), ea); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_ori_32_pi(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_32(mc68kcpu); + UINT32 ea = EA_AY_PI_32(mc68kcpu); + UINT32 res = src | m68ki_read_32((mc68kcpu), ea); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_ori_32_pd(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_32(mc68kcpu); + UINT32 ea = EA_AY_PD_32(mc68kcpu); + UINT32 res = src | m68ki_read_32((mc68kcpu), ea); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_ori_32_di(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_32(mc68kcpu); + UINT32 ea = EA_AY_DI_32(mc68kcpu); + UINT32 res = src | m68ki_read_32((mc68kcpu), ea); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_ori_32_ix(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_32(mc68kcpu); + UINT32 ea = EA_AY_IX_32(mc68kcpu); + UINT32 res = src | m68ki_read_32((mc68kcpu), ea); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_ori_32_aw(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_32(mc68kcpu); + UINT32 ea = EA_AW_32(mc68kcpu); + UINT32 res = src | m68ki_read_32((mc68kcpu), ea); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_ori_32_al(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_32(mc68kcpu); + UINT32 ea = EA_AL_32(mc68kcpu); + UINT32 res = src | m68ki_read_32((mc68kcpu), ea); + + m68ki_write_32((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_ori_16_toc(m68000_base_device* mc68kcpu) +{ + m68ki_set_ccr((mc68kcpu), m68ki_get_ccr(mc68kcpu) | OPER_I_16(mc68kcpu)); +} + + +void m68000_base_device_ops::m68k_op_ori_16_tos(m68000_base_device* mc68kcpu) +{ + if((mc68kcpu)->s_flag) + { + UINT32 src = OPER_I_16(mc68kcpu); + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_set_sr((mc68kcpu), m68ki_get_sr(mc68kcpu) | src); + return; + } + m68ki_exception_privilege_violation(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_pack_16_rr(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + /* Note: DX(mc68kcpu) and DY(mc68kcpu) are reversed in Motorola's docs */ + UINT32 src = DY(mc68kcpu) + OPER_I_16(mc68kcpu); + UINT32* r_dst = &DX(mc68kcpu); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | ((src >> 4) & 0x00f0) | (src & 0x000f); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_pack_16_mm_ax7(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + /* Note: AX and AY are reversed in Motorola's docs */ + UINT32 ea_src = EA_AY_PD_8(mc68kcpu); + UINT32 src = m68ki_read_8((mc68kcpu), ea_src); + ea_src = EA_AY_PD_8(mc68kcpu); + src = ((src << 8) | m68ki_read_8((mc68kcpu), ea_src)) + OPER_I_16(mc68kcpu); + + m68ki_write_8((mc68kcpu), EA_A7_PD_8(mc68kcpu), ((src >> 4) & 0x00f0) | (src & 0x000f)); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_pack_16_mm_ay7(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + /* Note: AX and AY are reversed in Motorola's docs */ + UINT32 ea_src = EA_A7_PD_8(mc68kcpu); + UINT32 src = m68ki_read_8((mc68kcpu), ea_src); + ea_src = EA_A7_PD_8(mc68kcpu); + src = ((src << 8) | m68ki_read_8((mc68kcpu), ea_src)) + OPER_I_16(mc68kcpu); + + m68ki_write_8((mc68kcpu), EA_AX_PD_8(mc68kcpu), ((src >> 4) & 0x00f0) | (src & 0x000f)); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_pack_16_mm_axy7(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 ea_src = EA_A7_PD_8(mc68kcpu); + UINT32 src = m68ki_read_8((mc68kcpu), ea_src); + ea_src = EA_A7_PD_8(mc68kcpu); + src = ((src << 8) | m68ki_read_8((mc68kcpu), ea_src)) + OPER_I_16(mc68kcpu); + + m68ki_write_8((mc68kcpu), EA_A7_PD_8(mc68kcpu), ((src >> 4) & 0x00f0) | (src & 0x000f)); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_pack_16_mm(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + /* Note: AX and AY are reversed in Motorola's docs */ + UINT32 ea_src = EA_AY_PD_8(mc68kcpu); + UINT32 src = m68ki_read_8((mc68kcpu), ea_src); + ea_src = EA_AY_PD_8(mc68kcpu); + src = ((src << 8) | m68ki_read_8((mc68kcpu), ea_src)) + OPER_I_16(mc68kcpu); + + m68ki_write_8((mc68kcpu), EA_AX_PD_8(mc68kcpu), ((src >> 4) & 0x00f0) | (src & 0x000f)); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_pea_32_ai(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_AI_32(mc68kcpu); + + m68ki_push_32((mc68kcpu), ea); +} + + +void m68000_base_device_ops::m68k_op_pea_32_di(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_DI_32(mc68kcpu); + + m68ki_push_32((mc68kcpu), ea); +} + + +void m68000_base_device_ops::m68k_op_pea_32_ix(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_IX_32(mc68kcpu); + + m68ki_push_32((mc68kcpu), ea); +} + + +void m68000_base_device_ops::m68k_op_pea_32_aw(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AW_32(mc68kcpu); + + m68ki_push_32((mc68kcpu), ea); +} + + +void m68000_base_device_ops::m68k_op_pea_32_al(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AL_32(mc68kcpu); + + m68ki_push_32((mc68kcpu), ea); +} + + +void m68000_base_device_ops::m68k_op_pea_32_pcdi(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_PCDI_32(mc68kcpu); + + m68ki_push_32((mc68kcpu), ea); +} + + +void m68000_base_device_ops::m68k_op_pea_32_pcix(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_PCIX_32(mc68kcpu); + + m68ki_push_32((mc68kcpu), ea); +} + + +void m68000_base_device_ops::m68k_op_pflusha_32(m68000_base_device* mc68kcpu) +{ + if ((CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) && ((mc68kcpu)->has_pmmu)) + { + logerror("68040: unhandled PFLUSHA (ir=%04x)\n", mc68kcpu->ir); + return; + } + m68ki_exception_1111(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_pflushan_32(m68000_base_device* mc68kcpu) +{ + if ((CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) && ((mc68kcpu)->has_pmmu)) + { + logerror("68040: unhandled PFLUSHAN (ir=%04x)\n", mc68kcpu->ir); + return; + } + m68ki_exception_1111(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_pmmu_32(m68000_base_device* mc68kcpu) +{ + if ((CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) && ((mc68kcpu)->has_pmmu)) + { + m68881_mmu_ops(mc68kcpu); + } + else + { + m68ki_exception_1111(mc68kcpu); + } +} + + +void m68000_base_device_ops::m68k_op_ptest_32(m68000_base_device* mc68kcpu) +{ + if ((CPU_TYPE_IS_040_PLUS((mc68kcpu)->cpu_type)) && ((mc68kcpu)->has_pmmu)) + { + logerror("68040: unhandled PTEST\n"); + return; + } + else + { + m68ki_exception_1111(mc68kcpu); + } +} + + +void m68000_base_device_ops::m68k_op_reset(m68000_base_device* mc68kcpu) +{ + if((mc68kcpu)->s_flag) + { + if (!(mc68kcpu)->reset_instr_callback.isnull()) + ((mc68kcpu)->reset_instr_callback)(1); + (mc68kcpu)->remaining_cycles -= (mc68kcpu)->cyc_reset; + return; + } + m68ki_exception_privilege_violation(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_ror_8_s(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 orig_shift = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT32 shift = orig_shift & 7; + UINT32 src = MASK_OUT_ABOVE_8(*r_dst); + UINT32 res = ROR_8(src, shift); + + if(orig_shift != 0) + (mc68kcpu)->remaining_cycles -= orig_shift<<(mc68kcpu)->cyc_shift; + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = src << (9-orig_shift); + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_ror_16_s(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 shift = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT32 src = MASK_OUT_ABOVE_16(*r_dst); + UINT32 res = ROR_16(src, shift); + + if(shift != 0) + (mc68kcpu)->remaining_cycles -= shift<<(mc68kcpu)->cyc_shift; + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = src << (9-shift); + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_ror_32_s(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 shift = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT64 src = *r_dst; + UINT32 res = ROR_32(src, shift); + + if(shift != 0) + (mc68kcpu)->remaining_cycles -= shift<<(mc68kcpu)->cyc_shift; + + *r_dst = res; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = src << (9-shift); + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_ror_8_r(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 orig_shift = DX(mc68kcpu) & 0x3f; + UINT32 shift = orig_shift & 7; + UINT32 src = MASK_OUT_ABOVE_8(*r_dst); + UINT32 res = ROR_8(src, shift); + + if(orig_shift != 0) + { + (mc68kcpu)->remaining_cycles -= orig_shift<<(mc68kcpu)->cyc_shift; + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; + (mc68kcpu)->c_flag = src << (8-((shift-1)&7)); + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + return; + } + + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->n_flag = NFLAG_8(src); + (mc68kcpu)->not_z_flag = src; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_ror_16_r(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 orig_shift = DX(mc68kcpu) & 0x3f; + UINT32 shift = orig_shift & 15; + UINT32 src = MASK_OUT_ABOVE_16(*r_dst); + UINT32 res = ROR_16(src, shift); + + if(orig_shift != 0) + { + (mc68kcpu)->remaining_cycles -= orig_shift<<(mc68kcpu)->cyc_shift; + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + (mc68kcpu)->c_flag = (src >> ((shift - 1) & 15)) << 8; + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + return; + } + + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->n_flag = NFLAG_16(src); + (mc68kcpu)->not_z_flag = src; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_ror_32_r(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 orig_shift = DX(mc68kcpu) & 0x3f; + UINT32 shift = orig_shift & 31; + UINT64 src = *r_dst; + UINT32 res = ROR_32(src, shift); + + if(orig_shift != 0) + { + (mc68kcpu)->remaining_cycles -= orig_shift<<(mc68kcpu)->cyc_shift; + + *r_dst = res; + (mc68kcpu)->c_flag = (src >> ((shift - 1) & 31)) << 8; + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + return; + } + + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->n_flag = NFLAG_32(src); + (mc68kcpu)->not_z_flag = src; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_ror_16_ai(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_AI_16(mc68kcpu); + UINT32 src = m68ki_read_16((mc68kcpu), ea); + UINT32 res = ROR_16(src, 1); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = src << 8; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_ror_16_pi(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_PI_16(mc68kcpu); + UINT32 src = m68ki_read_16((mc68kcpu), ea); + UINT32 res = ROR_16(src, 1); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = src << 8; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_ror_16_pd(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_PD_16(mc68kcpu); + UINT32 src = m68ki_read_16((mc68kcpu), ea); + UINT32 res = ROR_16(src, 1); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = src << 8; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_ror_16_di(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_DI_16(mc68kcpu); + UINT32 src = m68ki_read_16((mc68kcpu), ea); + UINT32 res = ROR_16(src, 1); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = src << 8; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_ror_16_ix(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_IX_16(mc68kcpu); + UINT32 src = m68ki_read_16((mc68kcpu), ea); + UINT32 res = ROR_16(src, 1); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = src << 8; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_ror_16_aw(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AW_16(mc68kcpu); + UINT32 src = m68ki_read_16((mc68kcpu), ea); + UINT32 res = ROR_16(src, 1); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = src << 8; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_ror_16_al(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AL_16(mc68kcpu); + UINT32 src = m68ki_read_16((mc68kcpu), ea); + UINT32 res = ROR_16(src, 1); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = src << 8; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_rol_8_s(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 orig_shift = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT32 shift = orig_shift & 7; + UINT32 src = MASK_OUT_ABOVE_8(*r_dst); + UINT32 res = ROL_8(src, shift); + + if(orig_shift != 0) + (mc68kcpu)->remaining_cycles -= orig_shift<<(mc68kcpu)->cyc_shift; + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = src << orig_shift; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_rol_16_s(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 shift = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT32 src = MASK_OUT_ABOVE_16(*r_dst); + UINT32 res = ROL_16(src, shift); + + if(shift != 0) + (mc68kcpu)->remaining_cycles -= shift<<(mc68kcpu)->cyc_shift; + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = src >> (8-shift); + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_rol_32_s(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 shift = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT64 src = *r_dst; + UINT32 res = ROL_32(src, shift); + + if(shift != 0) + (mc68kcpu)->remaining_cycles -= shift<<(mc68kcpu)->cyc_shift; + + *r_dst = res; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = src >> (24-shift); + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_rol_8_r(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 orig_shift = DX(mc68kcpu) & 0x3f; + UINT32 shift = orig_shift & 7; + UINT32 src = MASK_OUT_ABOVE_8(*r_dst); + UINT32 res = ROL_8(src, shift); + + if(orig_shift != 0) + { + (mc68kcpu)->remaining_cycles -= orig_shift<<(mc68kcpu)->cyc_shift; + + if(shift != 0) + { + *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; + (mc68kcpu)->c_flag = src << shift; + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + return; + } + (mc68kcpu)->c_flag = (src & 1)<<8; + (mc68kcpu)->n_flag = NFLAG_8(src); + (mc68kcpu)->not_z_flag = src; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + return; + } + + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->n_flag = NFLAG_8(src); + (mc68kcpu)->not_z_flag = src; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_rol_16_r(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 orig_shift = DX(mc68kcpu) & 0x3f; + UINT32 shift = orig_shift & 15; + UINT32 src = MASK_OUT_ABOVE_16(*r_dst); + UINT32 res = MASK_OUT_ABOVE_16(ROL_16(src, shift)); + + if(orig_shift != 0) + { + (mc68kcpu)->remaining_cycles -= orig_shift<<(mc68kcpu)->cyc_shift; + + if(shift != 0) + { + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + (mc68kcpu)->c_flag = (src << shift) >> 8; + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + return; + } + (mc68kcpu)->c_flag = (src & 1)<<8; + (mc68kcpu)->n_flag = NFLAG_16(src); + (mc68kcpu)->not_z_flag = src; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + return; + } + + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->n_flag = NFLAG_16(src); + (mc68kcpu)->not_z_flag = src; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_rol_32_r(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 orig_shift = DX(mc68kcpu) & 0x3f; + UINT32 shift = orig_shift & 31; + UINT64 src = *r_dst; + UINT32 res = ROL_32(src, shift); + + if(orig_shift != 0) + { + (mc68kcpu)->remaining_cycles -= orig_shift<<(mc68kcpu)->cyc_shift; + + *r_dst = res; + + (mc68kcpu)->c_flag = (src >> ((32 - shift) & 0x1f)) << 8; + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + return; + } + + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->n_flag = NFLAG_32(src); + (mc68kcpu)->not_z_flag = src; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_rol_16_ai(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_AI_16(mc68kcpu); + UINT32 src = m68ki_read_16((mc68kcpu), ea); + UINT32 res = MASK_OUT_ABOVE_16(ROL_16(src, 1)); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = src >> 7; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_rol_16_pi(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_PI_16(mc68kcpu); + UINT32 src = m68ki_read_16((mc68kcpu), ea); + UINT32 res = MASK_OUT_ABOVE_16(ROL_16(src, 1)); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = src >> 7; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_rol_16_pd(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_PD_16(mc68kcpu); + UINT32 src = m68ki_read_16((mc68kcpu), ea); + UINT32 res = MASK_OUT_ABOVE_16(ROL_16(src, 1)); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = src >> 7; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_rol_16_di(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_DI_16(mc68kcpu); + UINT32 src = m68ki_read_16((mc68kcpu), ea); + UINT32 res = MASK_OUT_ABOVE_16(ROL_16(src, 1)); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = src >> 7; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_rol_16_ix(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_IX_16(mc68kcpu); + UINT32 src = m68ki_read_16((mc68kcpu), ea); + UINT32 res = MASK_OUT_ABOVE_16(ROL_16(src, 1)); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = src >> 7; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_rol_16_aw(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AW_16(mc68kcpu); + UINT32 src = m68ki_read_16((mc68kcpu), ea); + UINT32 res = MASK_OUT_ABOVE_16(ROL_16(src, 1)); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = src >> 7; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_rol_16_al(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AL_16(mc68kcpu); + UINT32 src = m68ki_read_16((mc68kcpu), ea); + UINT32 res = MASK_OUT_ABOVE_16(ROL_16(src, 1)); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->c_flag = src >> 7; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_roxr_8_s(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 shift = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT32 src = MASK_OUT_ABOVE_8(*r_dst); + UINT32 res = ROR_9(src | (XFLAG_AS_1(mc68kcpu) << 8), shift); + + if(shift != 0) + (mc68kcpu)->remaining_cycles -= shift<<(mc68kcpu)->cyc_shift; + + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag = res; + res = MASK_OUT_ABOVE_8(res); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_roxr_16_s(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 shift = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT32 src = MASK_OUT_ABOVE_16(*r_dst); + UINT32 res = ROR_17(src | (XFLAG_AS_1(mc68kcpu) << 16), shift); + + if(shift != 0) + (mc68kcpu)->remaining_cycles -= shift<<(mc68kcpu)->cyc_shift; + + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag = res >> 8; + res = MASK_OUT_ABOVE_16(res); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_roxr_32_s(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 shift = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT64 src = *r_dst; + UINT64 res = src | (((UINT64)XFLAG_AS_1(mc68kcpu)) << 32); + + if(shift != 0) + (mc68kcpu)->remaining_cycles -= shift<<(mc68kcpu)->cyc_shift; + + res = ROR_33_64(res, shift); + + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag = res >> 24; + res = MASK_OUT_ABOVE_32(res); + + *r_dst = res; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_roxr_8_r(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 orig_shift = DX(mc68kcpu) & 0x3f; + + if(orig_shift != 0) + { + UINT32 shift = orig_shift % 9; + UINT32 src = MASK_OUT_ABOVE_8(*r_dst); + UINT32 res = ROR_9(src | (XFLAG_AS_1(mc68kcpu) << 8), shift); + + (mc68kcpu)->remaining_cycles -= orig_shift<<(mc68kcpu)->cyc_shift; + + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag = res; + res = MASK_OUT_ABOVE_8(res); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + return; + } + + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag; + (mc68kcpu)->n_flag = NFLAG_8(*r_dst); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(*r_dst); + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_roxr_16_r(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 orig_shift = DX(mc68kcpu) & 0x3f; + + if(orig_shift != 0) + { + UINT32 shift = orig_shift % 17; + UINT32 src = MASK_OUT_ABOVE_16(*r_dst); + UINT32 res = ROR_17(src | (XFLAG_AS_1(mc68kcpu) << 16), shift); + + (mc68kcpu)->remaining_cycles -= orig_shift<<(mc68kcpu)->cyc_shift; + + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag = res >> 8; + res = MASK_OUT_ABOVE_16(res); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + return; + } + + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag; + (mc68kcpu)->n_flag = NFLAG_16(*r_dst); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(*r_dst); + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_roxr_32_r(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 orig_shift = DX(mc68kcpu) & 0x3f; + + if(orig_shift != 0) + { + UINT32 shift = orig_shift % 33; + UINT64 src = *r_dst; + UINT64 res = src | (((UINT64)XFLAG_AS_1(mc68kcpu)) << 32); + + res = ROR_33_64(res, shift); + + (mc68kcpu)->remaining_cycles -= orig_shift<<(mc68kcpu)->cyc_shift; + + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag = res >> 24; + res = MASK_OUT_ABOVE_32(res); + + *r_dst = res; + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + return; + } + + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag; + (mc68kcpu)->n_flag = NFLAG_32(*r_dst); + (mc68kcpu)->not_z_flag = *r_dst; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_roxr_16_ai(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_AI_16(mc68kcpu); + UINT32 src = m68ki_read_16((mc68kcpu), ea); + UINT32 res = ROR_17(src | (XFLAG_AS_1(mc68kcpu) << 16), 1); + + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag = res >> 8; + res = MASK_OUT_ABOVE_16(res); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_roxr_16_pi(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_PI_16(mc68kcpu); + UINT32 src = m68ki_read_16((mc68kcpu), ea); + UINT32 res = ROR_17(src | (XFLAG_AS_1(mc68kcpu) << 16), 1); + + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag = res >> 8; + res = MASK_OUT_ABOVE_16(res); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_roxr_16_pd(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_PD_16(mc68kcpu); + UINT32 src = m68ki_read_16((mc68kcpu), ea); + UINT32 res = ROR_17(src | (XFLAG_AS_1(mc68kcpu) << 16), 1); + + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag = res >> 8; + res = MASK_OUT_ABOVE_16(res); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_roxr_16_di(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_DI_16(mc68kcpu); + UINT32 src = m68ki_read_16((mc68kcpu), ea); + UINT32 res = ROR_17(src | (XFLAG_AS_1(mc68kcpu) << 16), 1); + + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag = res >> 8; + res = MASK_OUT_ABOVE_16(res); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_roxr_16_ix(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_IX_16(mc68kcpu); + UINT32 src = m68ki_read_16((mc68kcpu), ea); + UINT32 res = ROR_17(src | (XFLAG_AS_1(mc68kcpu) << 16), 1); + + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag = res >> 8; + res = MASK_OUT_ABOVE_16(res); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_roxr_16_aw(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AW_16(mc68kcpu); + UINT32 src = m68ki_read_16((mc68kcpu), ea); + UINT32 res = ROR_17(src | (XFLAG_AS_1(mc68kcpu) << 16), 1); + + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag = res >> 8; + res = MASK_OUT_ABOVE_16(res); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_roxr_16_al(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AL_16(mc68kcpu); + UINT32 src = m68ki_read_16((mc68kcpu), ea); + UINT32 res = ROR_17(src | (XFLAG_AS_1(mc68kcpu) << 16), 1); + + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag = res >> 8; + res = MASK_OUT_ABOVE_16(res); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_roxl_8_s(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 shift = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT32 src = MASK_OUT_ABOVE_8(*r_dst); + UINT32 res = ROL_9(src | (XFLAG_AS_1(mc68kcpu) << 8), shift); + + if(shift != 0) + (mc68kcpu)->remaining_cycles -= shift<<(mc68kcpu)->cyc_shift; + + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag = res; + res = MASK_OUT_ABOVE_8(res); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_roxl_16_s(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 shift = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT32 src = MASK_OUT_ABOVE_16(*r_dst); + UINT32 res = ROL_17(src | (XFLAG_AS_1(mc68kcpu) << 16), shift); + + if(shift != 0) + (mc68kcpu)->remaining_cycles -= shift<<(mc68kcpu)->cyc_shift; + + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag = res >> 8; + res = MASK_OUT_ABOVE_16(res); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_roxl_32_s(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 shift = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT64 src = *r_dst; + UINT64 res = src | (((UINT64)XFLAG_AS_1(mc68kcpu)) << 32); + + if(shift != 0) + (mc68kcpu)->remaining_cycles -= shift<<(mc68kcpu)->cyc_shift; + + res = ROL_33_64(res, shift); + + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag = res >> 24; + res = MASK_OUT_ABOVE_32(res); + + *r_dst = res; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_roxl_8_r(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 orig_shift = DX(mc68kcpu) & 0x3f; + + + if(orig_shift != 0) + { + UINT32 shift = orig_shift % 9; + UINT32 src = MASK_OUT_ABOVE_8(*r_dst); + UINT32 res = ROL_9(src | (XFLAG_AS_1(mc68kcpu) << 8), shift); + + (mc68kcpu)->remaining_cycles -= orig_shift<<(mc68kcpu)->cyc_shift; + + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag = res; + res = MASK_OUT_ABOVE_8(res); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + return; + } + + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag; + (mc68kcpu)->n_flag = NFLAG_8(*r_dst); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(*r_dst); + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_roxl_16_r(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 orig_shift = DX(mc68kcpu) & 0x3f; + + if(orig_shift != 0) + { + UINT32 shift = orig_shift % 17; + UINT32 src = MASK_OUT_ABOVE_16(*r_dst); + UINT32 res = ROL_17(src | (XFLAG_AS_1(mc68kcpu) << 16), shift); + + (mc68kcpu)->remaining_cycles -= orig_shift<<(mc68kcpu)->cyc_shift; + + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag = res >> 8; + res = MASK_OUT_ABOVE_16(res); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + return; + } + + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag; + (mc68kcpu)->n_flag = NFLAG_16(*r_dst); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(*r_dst); + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_roxl_32_r(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 orig_shift = DX(mc68kcpu) & 0x3f; + + if(orig_shift != 0) + { + UINT32 shift = orig_shift % 33; + UINT64 src = *r_dst; + UINT64 res = src | (((UINT64)XFLAG_AS_1(mc68kcpu)) << 32); + + res = ROL_33_64(res, shift); + + (mc68kcpu)->remaining_cycles -= orig_shift<<(mc68kcpu)->cyc_shift; + + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag = res >> 24; + res = MASK_OUT_ABOVE_32(res); + + *r_dst = res; + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + return; + } + + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag; + (mc68kcpu)->n_flag = NFLAG_32(*r_dst); + (mc68kcpu)->not_z_flag = *r_dst; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_roxl_16_ai(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_AI_16(mc68kcpu); + UINT32 src = m68ki_read_16((mc68kcpu), ea); + UINT32 res = ROL_17(src | (XFLAG_AS_1(mc68kcpu) << 16), 1); + + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag = res >> 8; + res = MASK_OUT_ABOVE_16(res); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_roxl_16_pi(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_PI_16(mc68kcpu); + UINT32 src = m68ki_read_16((mc68kcpu), ea); + UINT32 res = ROL_17(src | (XFLAG_AS_1(mc68kcpu) << 16), 1); + + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag = res >> 8; + res = MASK_OUT_ABOVE_16(res); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_roxl_16_pd(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_PD_16(mc68kcpu); + UINT32 src = m68ki_read_16((mc68kcpu), ea); + UINT32 res = ROL_17(src | (XFLAG_AS_1(mc68kcpu) << 16), 1); + + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag = res >> 8; + res = MASK_OUT_ABOVE_16(res); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_roxl_16_di(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_DI_16(mc68kcpu); + UINT32 src = m68ki_read_16((mc68kcpu), ea); + UINT32 res = ROL_17(src | (XFLAG_AS_1(mc68kcpu) << 16), 1); + + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag = res >> 8; + res = MASK_OUT_ABOVE_16(res); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_roxl_16_ix(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_IX_16(mc68kcpu); + UINT32 src = m68ki_read_16((mc68kcpu), ea); + UINT32 res = ROL_17(src | (XFLAG_AS_1(mc68kcpu) << 16), 1); + + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag = res >> 8; + res = MASK_OUT_ABOVE_16(res); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_roxl_16_aw(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AW_16(mc68kcpu); + UINT32 src = m68ki_read_16((mc68kcpu), ea); + UINT32 res = ROL_17(src | (XFLAG_AS_1(mc68kcpu) << 16), 1); + + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag = res >> 8; + res = MASK_OUT_ABOVE_16(res); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_roxl_16_al(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AL_16(mc68kcpu); + UINT32 src = m68ki_read_16((mc68kcpu), ea); + UINT32 res = ROL_17(src | (XFLAG_AS_1(mc68kcpu) << 16), 1); + + (mc68kcpu)->c_flag = (mc68kcpu)->x_flag = res >> 8; + res = MASK_OUT_ABOVE_16(res); + + m68ki_write_16((mc68kcpu), ea, res); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_rtd_32(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_010_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 new_pc = m68ki_pull_32(mc68kcpu); + + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + REG_A(mc68kcpu)[7] = MASK_OUT_ABOVE_32(REG_A(mc68kcpu)[7] + MAKE_INT_16(OPER_I_16(mc68kcpu))); + m68ki_jump((mc68kcpu), new_pc); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_rte_32(m68000_base_device* mc68kcpu) +{ + if((mc68kcpu)->s_flag) + { + UINT32 new_sr; + UINT32 new_pc; + UINT32 format_word; + + if (!(mc68kcpu)->rte_instr_callback.isnull()) + ((mc68kcpu)->rte_instr_callback)(1); + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + + if(CPU_TYPE_IS_000((mc68kcpu)->cpu_type)) + { + new_sr = m68ki_pull_16(mc68kcpu); + new_pc = m68ki_pull_32(mc68kcpu); + m68ki_jump((mc68kcpu), new_pc); + m68ki_set_sr((mc68kcpu), new_sr); + + (mc68kcpu)->instr_mode = INSTRUCTION_YES; + (mc68kcpu)->run_mode = RUN_MODE_NORMAL; + + return; + } + + if(CPU_TYPE_IS_010((mc68kcpu)->cpu_type)) + { + format_word = m68ki_read_16((mc68kcpu), REG_A(mc68kcpu)[7]+6) >> 12; + if(format_word == 0) + { + new_sr = m68ki_pull_16(mc68kcpu); + new_pc = m68ki_pull_32(mc68kcpu); + m68ki_fake_pull_16(mc68kcpu); /* format word */ + m68ki_jump((mc68kcpu), new_pc); + m68ki_set_sr((mc68kcpu), new_sr); + (mc68kcpu)->instr_mode = INSTRUCTION_YES; + (mc68kcpu)->run_mode = RUN_MODE_NORMAL; + return; + } + (mc68kcpu)->instr_mode = INSTRUCTION_YES; + (mc68kcpu)->run_mode = RUN_MODE_NORMAL; + /* Not handling bus fault (9) */ + m68ki_exception_format_error(mc68kcpu); + return; + } + + /* Otherwise it's 020 */ +rte_loop: + format_word = m68ki_read_16((mc68kcpu), REG_A(mc68kcpu)[7]+6) >> 12; + switch(format_word) + { + case 0: /* Normal */ + new_sr = m68ki_pull_16(mc68kcpu); + new_pc = m68ki_pull_32(mc68kcpu); + m68ki_fake_pull_16(mc68kcpu); /* format word */ + m68ki_jump((mc68kcpu), new_pc); + m68ki_set_sr((mc68kcpu), new_sr); + (mc68kcpu)->instr_mode = INSTRUCTION_YES; + (mc68kcpu)->run_mode = RUN_MODE_NORMAL; + return; + case 1: /* Throwaway */ + new_sr = m68ki_pull_16(mc68kcpu); + m68ki_fake_pull_32(mc68kcpu); /* program counter */ + m68ki_fake_pull_16(mc68kcpu); /* format word */ + m68ki_set_sr_noint((mc68kcpu), new_sr); + goto rte_loop; + case 2: /* Trap */ + new_sr = m68ki_pull_16(mc68kcpu); + new_pc = m68ki_pull_32(mc68kcpu); + m68ki_fake_pull_16(mc68kcpu); /* format word */ + m68ki_fake_pull_32(mc68kcpu); /* address */ + m68ki_jump((mc68kcpu), new_pc); + m68ki_set_sr((mc68kcpu), new_sr); + (mc68kcpu)->instr_mode = INSTRUCTION_YES; + (mc68kcpu)->run_mode = RUN_MODE_NORMAL; + return; + case 7: /* 68040 access error */ + new_sr = m68ki_pull_16(mc68kcpu); + new_pc = m68ki_pull_32(mc68kcpu); + m68ki_fake_pull_16(mc68kcpu); /* $06: format word */ + m68ki_fake_pull_32(mc68kcpu); /* $08: effective address */ + m68ki_fake_pull_16(mc68kcpu); /* $0c: special status word */ + m68ki_fake_pull_16(mc68kcpu); /* $0e: wb3s */ + m68ki_fake_pull_16(mc68kcpu); /* $10: wb2s */ + m68ki_fake_pull_16(mc68kcpu); /* $12: wb1s */ + m68ki_fake_pull_32(mc68kcpu); /* $14: data fault address */ + m68ki_fake_pull_32(mc68kcpu); /* $18: wb3a */ + m68ki_fake_pull_32(mc68kcpu); /* $1c: wb3d */ + m68ki_fake_pull_32(mc68kcpu); /* $20: wb2a */ + m68ki_fake_pull_32(mc68kcpu); /* $24: wb2d */ + m68ki_fake_pull_32(mc68kcpu); /* $28: wb1a */ + m68ki_fake_pull_32(mc68kcpu); /* $2c: wb1d/pd0 */ + m68ki_fake_pull_32(mc68kcpu); /* $30: pd1 */ + m68ki_fake_pull_32(mc68kcpu); /* $34: pd2 */ + m68ki_fake_pull_32(mc68kcpu); /* $38: pd3 */ + m68ki_jump((mc68kcpu), new_pc); + m68ki_set_sr((mc68kcpu), new_sr); + (mc68kcpu)->instr_mode = INSTRUCTION_YES; + (mc68kcpu)->run_mode = RUN_MODE_NORMAL; + return; + + case 0x0a: /* Bus Error at instruction boundary */ + new_sr = m68ki_pull_16(mc68kcpu); + new_pc = m68ki_pull_32(mc68kcpu); + m68ki_fake_pull_16(mc68kcpu); /* $06: format word */ + m68ki_fake_pull_16(mc68kcpu); /* $08: internal register */ + m68ki_fake_pull_16(mc68kcpu); /* $0a: special status word */ + m68ki_fake_pull_16(mc68kcpu); /* $0c: instruction pipe stage c */ + m68ki_fake_pull_16(mc68kcpu); /* $0e: instruction pipe stage b */ + m68ki_fake_pull_32(mc68kcpu); /* $10: data fault address */ + m68ki_fake_pull_32(mc68kcpu); /* $14: internal registers */ + m68ki_fake_pull_32(mc68kcpu); /* $18: data output buffer */ + m68ki_fake_pull_32(mc68kcpu); /* $1c: internal registers */ + + m68ki_jump((mc68kcpu), new_pc); + m68ki_set_sr((mc68kcpu), new_sr); + (mc68kcpu)->instr_mode = INSTRUCTION_YES; + (mc68kcpu)->run_mode = RUN_MODE_NORMAL; + return; + case 0x0b: /* Bus Error - Instruction Execution in Progress */ + new_sr = m68ki_pull_16(mc68kcpu); + new_pc = m68ki_pull_32(mc68kcpu); + m68ki_fake_pull_16(mc68kcpu); /* $06: format word */ + m68ki_fake_pull_16(mc68kcpu); /* $08: internal register */ + m68ki_fake_pull_16(mc68kcpu); /* $0a: special status word */ + m68ki_fake_pull_16(mc68kcpu); /* $0c: instruction pipe stage c */ + m68ki_fake_pull_16(mc68kcpu); /* $0e: instruction pipe stage b */ + m68ki_fake_pull_32(mc68kcpu); /* $10: data fault address */ + m68ki_fake_pull_32(mc68kcpu); /* $14: internal registers */ + m68ki_fake_pull_32(mc68kcpu); /* $18: data output buffer */ + m68ki_fake_pull_32(mc68kcpu); /* $1c: internal registers */ + m68ki_fake_pull_32(mc68kcpu); /* $20: */ + m68ki_fake_pull_32(mc68kcpu); /* $24: stage B address */ + m68ki_fake_pull_32(mc68kcpu); /* $28: */ + m68ki_fake_pull_32(mc68kcpu); /* $2c: data input buffer */ + m68ki_fake_pull_32(mc68kcpu); /* $30: */ + m68ki_fake_pull_16(mc68kcpu); /* $34: */ + m68ki_fake_pull_16(mc68kcpu); /* $36: version #, internal information */ + m68ki_fake_pull_32(mc68kcpu); /* $38: */ + m68ki_fake_pull_32(mc68kcpu); /* $3c: */ + m68ki_fake_pull_32(mc68kcpu); /* $40: */ + m68ki_fake_pull_32(mc68kcpu); /* $44: */ + m68ki_fake_pull_32(mc68kcpu); /* $48: */ + m68ki_fake_pull_32(mc68kcpu); /* $4c: */ + m68ki_fake_pull_32(mc68kcpu); /* $50: */ + m68ki_fake_pull_32(mc68kcpu); /* $54: */ + m68ki_fake_pull_32(mc68kcpu); /* $58: */ + + m68ki_jump((mc68kcpu), new_pc); + m68ki_set_sr((mc68kcpu), new_sr); + (mc68kcpu)->instr_mode = INSTRUCTION_YES; + (mc68kcpu)->run_mode = RUN_MODE_NORMAL; + return; + } + /* Not handling long or short bus fault */ + (mc68kcpu)->instr_mode = INSTRUCTION_YES; + (mc68kcpu)->run_mode = RUN_MODE_NORMAL; + m68ki_exception_format_error(mc68kcpu); + return; + } + m68ki_exception_privilege_violation(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_rtm_32(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_020_VARIANT((mc68kcpu)->cpu_type)) + { + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + logerror("%s at %08x: called unimplemented instruction %04x (rtm)\n", + (mc68kcpu)->tag(), REG_PC(mc68kcpu) - 2, (mc68kcpu)->ir); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_rtr_32(m68000_base_device* mc68kcpu) +{ + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_set_ccr((mc68kcpu), m68ki_pull_16(mc68kcpu)); + m68ki_jump((mc68kcpu), m68ki_pull_32(mc68kcpu)); +} + + +void m68000_base_device_ops::m68k_op_rts_32(m68000_base_device* mc68kcpu) +{ + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + m68ki_jump((mc68kcpu), m68ki_pull_32(mc68kcpu)); +} + + +void m68000_base_device_ops::m68k_op_sbcd_8_rr(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = DY(mc68kcpu); + UINT32 dst = *r_dst; + UINT32 res = LOW_NIBBLE(dst) - LOW_NIBBLE(src) - XFLAG_AS_1(mc68kcpu); + +// (mc68kcpu)->v_flag = ~res; /* Undefined V behavior */ + (mc68kcpu)->v_flag = VFLAG_CLEAR; /* Undefined in Motorola's M68000PM/AD rev.1 and safer to assume cleared. */ + + if(res > 9) + res -= 6; + res += HIGH_NIBBLE(dst) - HIGH_NIBBLE(src); + if(res > 0x99) + { + res += 0xa0; + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_SET; + (mc68kcpu)->n_flag = NFLAG_SET; /* Undefined in Motorola's M68000PM/AD rev.1 and safer to follow carry. */ + } + else + (mc68kcpu)->n_flag = (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = 0; + + res = MASK_OUT_ABOVE_8(res); + +// (mc68kcpu)->v_flag &= res; /* Undefined V behavior part II */ +// (mc68kcpu)->n_flag = NFLAG_8(res); /* Undefined N behavior */ + (mc68kcpu)->not_z_flag |= res; + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; +} + + +void m68000_base_device_ops::m68k_op_sbcd_8_mm_ax7(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_AY_PD_8(mc68kcpu); + UINT32 ea = EA_A7_PD_8(mc68kcpu); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + UINT32 res = LOW_NIBBLE(dst) - LOW_NIBBLE(src) - XFLAG_AS_1(mc68kcpu); + +// (mc68kcpu)->v_flag = ~res; /* Undefined V behavior */ + (mc68kcpu)->v_flag = VFLAG_CLEAR; /* Undefined in Motorola's M68000PM/AD rev.1 and safer to return zero. */ + + if(res > 9) + res -= 6; + res += HIGH_NIBBLE(dst) - HIGH_NIBBLE(src); + if(res > 0x99) + { + res += 0xa0; + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_SET; + (mc68kcpu)->n_flag = NFLAG_SET; /* Undefined in Motorola's M68000PM/AD rev.1 and safer to follow carry. */ + } + else + (mc68kcpu)->n_flag = (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = 0; + + res = MASK_OUT_ABOVE_8(res); + +// (mc68kcpu)->v_flag &= res; /* Undefined V behavior part II */ +// (mc68kcpu)->n_flag = NFLAG_8(res); /* Undefined N behavior */ + (mc68kcpu)->not_z_flag |= res; + + m68ki_write_8((mc68kcpu), ea, res); +} + + +void m68000_base_device_ops::m68k_op_sbcd_8_mm_ay7(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_A7_PD_8(mc68kcpu); + UINT32 ea = EA_AX_PD_8(mc68kcpu); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + UINT32 res = LOW_NIBBLE(dst) - LOW_NIBBLE(src) - XFLAG_AS_1(mc68kcpu); + +// (mc68kcpu)->v_flag = ~res; /* Undefined V behavior */ + (mc68kcpu)->v_flag = VFLAG_CLEAR; /* Undefined in Motorola's M68000PM/AD rev.1 and safer to return zero. */ + + if(res > 9) + res -= 6; + res += HIGH_NIBBLE(dst) - HIGH_NIBBLE(src); + if(res > 0x99) + { + res += 0xa0; + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_SET; + (mc68kcpu)->n_flag = NFLAG_SET; /* Undefined in Motorola's M68000PM/AD rev.1 and safer to follow carry. */ + } + else + (mc68kcpu)->n_flag = (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = 0; + + res = MASK_OUT_ABOVE_8(res); + +// (mc68kcpu)->v_flag &= res; /* Undefined V behavior part II */ +// (mc68kcpu)->n_flag = NFLAG_8(res); /* Undefined N behavior */ + (mc68kcpu)->not_z_flag |= res; + + m68ki_write_8((mc68kcpu), ea, res); +} + + +void m68000_base_device_ops::m68k_op_sbcd_8_mm_axy7(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_A7_PD_8(mc68kcpu); + UINT32 ea = EA_A7_PD_8(mc68kcpu); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + UINT32 res = LOW_NIBBLE(dst) - LOW_NIBBLE(src) - XFLAG_AS_1(mc68kcpu); + +// (mc68kcpu)->v_flag = ~res; /* Undefined V behavior */ + (mc68kcpu)->v_flag = VFLAG_CLEAR; /* Undefined in Motorola's M68000PM/AD rev.1 and safer to return zero. */ + + if(res > 9) + res -= 6; + res += HIGH_NIBBLE(dst) - HIGH_NIBBLE(src); + if(res > 0x99) + { + res += 0xa0; + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_SET; + (mc68kcpu)->n_flag = NFLAG_SET; /* Undefined in Motorola's M68000PM/AD rev.1 and safer to follow carry. */ + } + else + (mc68kcpu)->n_flag = (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = 0; + + res = MASK_OUT_ABOVE_8(res); + +// (mc68kcpu)->v_flag &= res; /* Undefined V behavior part II */ +// (mc68kcpu)->n_flag = NFLAG_8(res); /* Undefined N behavior */ + (mc68kcpu)->not_z_flag |= res; + + m68ki_write_8((mc68kcpu), ea, res); +} + + +void m68000_base_device_ops::m68k_op_sbcd_8_mm(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_AY_PD_8(mc68kcpu); + UINT32 ea = EA_AX_PD_8(mc68kcpu); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + UINT32 res = LOW_NIBBLE(dst) - LOW_NIBBLE(src) - XFLAG_AS_1(mc68kcpu); + +// (mc68kcpu)->v_flag = ~res; /* Undefined V behavior */ + (mc68kcpu)->v_flag = VFLAG_CLEAR; /* Undefined in Motorola's M68000PM/AD rev.1 and safer to return zero. */ + + if(res > 9) + res -= 6; + res += HIGH_NIBBLE(dst) - HIGH_NIBBLE(src); + if(res > 0x99) + { + res += 0xa0; + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_SET; + (mc68kcpu)->n_flag = NFLAG_SET; /* Undefined in Motorola's M68000PM/AD rev.1 and safer to follow carry. */ + } + else + (mc68kcpu)->n_flag = (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = 0; + + res = MASK_OUT_ABOVE_8(res); + +// (mc68kcpu)->v_flag &= res; /* Undefined V behavior part II */ +// (mc68kcpu)->n_flag = NFLAG_8(res); /* Undefined N behavior */ + (mc68kcpu)->not_z_flag |= res; + + m68ki_write_8((mc68kcpu), ea, res); +} + + +void m68000_base_device_ops::m68k_op_st_8_d(m68000_base_device* mc68kcpu) +{ + DY(mc68kcpu) |= 0xff; +} + + +void m68000_base_device_ops::m68k_op_st_8_ai(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AY_AI_8(mc68kcpu), 0xff); +} + + +void m68000_base_device_ops::m68k_op_st_8_pi(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AY_PI_8(mc68kcpu), 0xff); +} + + +void m68000_base_device_ops::m68k_op_st_8_pi7(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_A7_PI_8(mc68kcpu), 0xff); +} + + +void m68000_base_device_ops::m68k_op_st_8_pd(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AY_PD_8(mc68kcpu), 0xff); +} + + +void m68000_base_device_ops::m68k_op_st_8_pd7(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_A7_PD_8(mc68kcpu), 0xff); +} + + +void m68000_base_device_ops::m68k_op_st_8_di(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AY_DI_8(mc68kcpu), 0xff); +} + + +void m68000_base_device_ops::m68k_op_st_8_ix(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AY_IX_8(mc68kcpu), 0xff); +} + + +void m68000_base_device_ops::m68k_op_st_8_aw(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AW_8(mc68kcpu), 0xff); +} + + +void m68000_base_device_ops::m68k_op_st_8_al(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AL_8(mc68kcpu), 0xff); +} + + +void m68000_base_device_ops::m68k_op_sf_8_d(m68000_base_device* mc68kcpu) +{ + DY(mc68kcpu) &= 0xffffff00; +} + + +void m68000_base_device_ops::m68k_op_sf_8_ai(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AY_AI_8(mc68kcpu), 0); +} + + +void m68000_base_device_ops::m68k_op_sf_8_pi(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AY_PI_8(mc68kcpu), 0); +} + + +void m68000_base_device_ops::m68k_op_sf_8_pi7(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_A7_PI_8(mc68kcpu), 0); +} + + +void m68000_base_device_ops::m68k_op_sf_8_pd(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AY_PD_8(mc68kcpu), 0); +} + + +void m68000_base_device_ops::m68k_op_sf_8_pd7(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_A7_PD_8(mc68kcpu), 0); +} + + +void m68000_base_device_ops::m68k_op_sf_8_di(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AY_DI_8(mc68kcpu), 0); +} + + +void m68000_base_device_ops::m68k_op_sf_8_ix(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AY_IX_8(mc68kcpu), 0); +} + + +void m68000_base_device_ops::m68k_op_sf_8_aw(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AW_8(mc68kcpu), 0); +} + + +void m68000_base_device_ops::m68k_op_sf_8_al(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AL_8(mc68kcpu), 0); +} + + +void m68000_base_device_ops::m68k_op_shi_8_d(m68000_base_device* mc68kcpu) +{ + if(COND_HI(mc68kcpu)) + { + DY(mc68kcpu) |= 0xff; + (mc68kcpu)->remaining_cycles -= (mc68kcpu)->cyc_scc_r_true; + return; + } + DY(mc68kcpu) &= 0xffffff00; +} + + +void m68000_base_device_ops::m68k_op_sls_8_d(m68000_base_device* mc68kcpu) +{ + if(COND_LS(mc68kcpu)) + { + DY(mc68kcpu) |= 0xff; + (mc68kcpu)->remaining_cycles -= (mc68kcpu)->cyc_scc_r_true; + return; + } + DY(mc68kcpu) &= 0xffffff00; +} + + +void m68000_base_device_ops::m68k_op_scc_8_d(m68000_base_device* mc68kcpu) +{ + if(COND_CC(mc68kcpu)) + { + DY(mc68kcpu) |= 0xff; + (mc68kcpu)->remaining_cycles -= (mc68kcpu)->cyc_scc_r_true; + return; + } + DY(mc68kcpu) &= 0xffffff00; +} + + +void m68000_base_device_ops::m68k_op_scs_8_d(m68000_base_device* mc68kcpu) +{ + if(COND_CS(mc68kcpu)) + { + DY(mc68kcpu) |= 0xff; + (mc68kcpu)->remaining_cycles -= (mc68kcpu)->cyc_scc_r_true; + return; + } + DY(mc68kcpu) &= 0xffffff00; +} + + +void m68000_base_device_ops::m68k_op_sne_8_d(m68000_base_device* mc68kcpu) +{ + if(COND_NE(mc68kcpu)) + { + DY(mc68kcpu) |= 0xff; + (mc68kcpu)->remaining_cycles -= (mc68kcpu)->cyc_scc_r_true; + return; + } + DY(mc68kcpu) &= 0xffffff00; +} + + +void m68000_base_device_ops::m68k_op_seq_8_d(m68000_base_device* mc68kcpu) +{ + if(COND_EQ(mc68kcpu)) + { + DY(mc68kcpu) |= 0xff; + (mc68kcpu)->remaining_cycles -= (mc68kcpu)->cyc_scc_r_true; + return; + } + DY(mc68kcpu) &= 0xffffff00; +} + + +void m68000_base_device_ops::m68k_op_svc_8_d(m68000_base_device* mc68kcpu) +{ + if(COND_VC(mc68kcpu)) + { + DY(mc68kcpu) |= 0xff; + (mc68kcpu)->remaining_cycles -= (mc68kcpu)->cyc_scc_r_true; + return; + } + DY(mc68kcpu) &= 0xffffff00; +} + + +void m68000_base_device_ops::m68k_op_svs_8_d(m68000_base_device* mc68kcpu) +{ + if(COND_VS(mc68kcpu)) + { + DY(mc68kcpu) |= 0xff; + (mc68kcpu)->remaining_cycles -= (mc68kcpu)->cyc_scc_r_true; + return; + } + DY(mc68kcpu) &= 0xffffff00; +} + + +void m68000_base_device_ops::m68k_op_spl_8_d(m68000_base_device* mc68kcpu) +{ + if(COND_PL(mc68kcpu)) + { + DY(mc68kcpu) |= 0xff; + (mc68kcpu)->remaining_cycles -= (mc68kcpu)->cyc_scc_r_true; + return; + } + DY(mc68kcpu) &= 0xffffff00; +} + + +void m68000_base_device_ops::m68k_op_smi_8_d(m68000_base_device* mc68kcpu) +{ + if(COND_MI(mc68kcpu)) + { + DY(mc68kcpu) |= 0xff; + (mc68kcpu)->remaining_cycles -= (mc68kcpu)->cyc_scc_r_true; + return; + } + DY(mc68kcpu) &= 0xffffff00; +} + + +void m68000_base_device_ops::m68k_op_sge_8_d(m68000_base_device* mc68kcpu) +{ + if(COND_GE(mc68kcpu)) + { + DY(mc68kcpu) |= 0xff; + (mc68kcpu)->remaining_cycles -= (mc68kcpu)->cyc_scc_r_true; + return; + } + DY(mc68kcpu) &= 0xffffff00; +} + + +void m68000_base_device_ops::m68k_op_slt_8_d(m68000_base_device* mc68kcpu) +{ + if(COND_LT(mc68kcpu)) + { + DY(mc68kcpu) |= 0xff; + (mc68kcpu)->remaining_cycles -= (mc68kcpu)->cyc_scc_r_true; + return; + } + DY(mc68kcpu) &= 0xffffff00; +} + + +void m68000_base_device_ops::m68k_op_sgt_8_d(m68000_base_device* mc68kcpu) +{ + if(COND_GT(mc68kcpu)) + { + DY(mc68kcpu) |= 0xff; + (mc68kcpu)->remaining_cycles -= (mc68kcpu)->cyc_scc_r_true; + return; + } + DY(mc68kcpu) &= 0xffffff00; +} + + +void m68000_base_device_ops::m68k_op_sle_8_d(m68000_base_device* mc68kcpu) +{ + if(COND_LE(mc68kcpu)) + { + DY(mc68kcpu) |= 0xff; + (mc68kcpu)->remaining_cycles -= (mc68kcpu)->cyc_scc_r_true; + return; + } + DY(mc68kcpu) &= 0xffffff00; +} + + +void m68000_base_device_ops::m68k_op_shi_8_ai(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AY_AI_8(mc68kcpu), COND_HI(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_shi_8_pi(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AY_PI_8(mc68kcpu), COND_HI(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_shi_8_pi7(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_A7_PI_8(mc68kcpu), COND_HI(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_shi_8_pd(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AY_PD_8(mc68kcpu), COND_HI(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_shi_8_pd7(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_A7_PD_8(mc68kcpu), COND_HI(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_shi_8_di(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AY_DI_8(mc68kcpu), COND_HI(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_shi_8_ix(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AY_IX_8(mc68kcpu), COND_HI(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_shi_8_aw(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AW_8(mc68kcpu), COND_HI(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_shi_8_al(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AL_8(mc68kcpu), COND_HI(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_sls_8_ai(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AY_AI_8(mc68kcpu), COND_LS(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_sls_8_pi(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AY_PI_8(mc68kcpu), COND_LS(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_sls_8_pi7(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_A7_PI_8(mc68kcpu), COND_LS(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_sls_8_pd(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AY_PD_8(mc68kcpu), COND_LS(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_sls_8_pd7(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_A7_PD_8(mc68kcpu), COND_LS(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_sls_8_di(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AY_DI_8(mc68kcpu), COND_LS(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_sls_8_ix(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AY_IX_8(mc68kcpu), COND_LS(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_sls_8_aw(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AW_8(mc68kcpu), COND_LS(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_sls_8_al(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AL_8(mc68kcpu), COND_LS(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_scc_8_ai(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AY_AI_8(mc68kcpu), COND_CC(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_scc_8_pi(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AY_PI_8(mc68kcpu), COND_CC(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_scc_8_pi7(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_A7_PI_8(mc68kcpu), COND_CC(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_scc_8_pd(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AY_PD_8(mc68kcpu), COND_CC(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_scc_8_pd7(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_A7_PD_8(mc68kcpu), COND_CC(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_scc_8_di(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AY_DI_8(mc68kcpu), COND_CC(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_scc_8_ix(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AY_IX_8(mc68kcpu), COND_CC(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_scc_8_aw(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AW_8(mc68kcpu), COND_CC(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_scc_8_al(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AL_8(mc68kcpu), COND_CC(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_scs_8_ai(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AY_AI_8(mc68kcpu), COND_CS(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_scs_8_pi(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AY_PI_8(mc68kcpu), COND_CS(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_scs_8_pi7(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_A7_PI_8(mc68kcpu), COND_CS(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_scs_8_pd(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AY_PD_8(mc68kcpu), COND_CS(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_scs_8_pd7(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_A7_PD_8(mc68kcpu), COND_CS(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_scs_8_di(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AY_DI_8(mc68kcpu), COND_CS(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_scs_8_ix(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AY_IX_8(mc68kcpu), COND_CS(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_scs_8_aw(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AW_8(mc68kcpu), COND_CS(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_scs_8_al(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AL_8(mc68kcpu), COND_CS(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_sne_8_ai(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AY_AI_8(mc68kcpu), COND_NE(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_sne_8_pi(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AY_PI_8(mc68kcpu), COND_NE(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_sne_8_pi7(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_A7_PI_8(mc68kcpu), COND_NE(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_sne_8_pd(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AY_PD_8(mc68kcpu), COND_NE(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_sne_8_pd7(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_A7_PD_8(mc68kcpu), COND_NE(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_sne_8_di(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AY_DI_8(mc68kcpu), COND_NE(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_sne_8_ix(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AY_IX_8(mc68kcpu), COND_NE(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_sne_8_aw(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AW_8(mc68kcpu), COND_NE(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_sne_8_al(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AL_8(mc68kcpu), COND_NE(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_seq_8_ai(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AY_AI_8(mc68kcpu), COND_EQ(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_seq_8_pi(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AY_PI_8(mc68kcpu), COND_EQ(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_seq_8_pi7(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_A7_PI_8(mc68kcpu), COND_EQ(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_seq_8_pd(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AY_PD_8(mc68kcpu), COND_EQ(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_seq_8_pd7(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_A7_PD_8(mc68kcpu), COND_EQ(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_seq_8_di(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AY_DI_8(mc68kcpu), COND_EQ(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_seq_8_ix(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AY_IX_8(mc68kcpu), COND_EQ(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_seq_8_aw(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AW_8(mc68kcpu), COND_EQ(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_seq_8_al(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AL_8(mc68kcpu), COND_EQ(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_svc_8_ai(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AY_AI_8(mc68kcpu), COND_VC(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_svc_8_pi(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AY_PI_8(mc68kcpu), COND_VC(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_svc_8_pi7(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_A7_PI_8(mc68kcpu), COND_VC(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_svc_8_pd(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AY_PD_8(mc68kcpu), COND_VC(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_svc_8_pd7(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_A7_PD_8(mc68kcpu), COND_VC(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_svc_8_di(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AY_DI_8(mc68kcpu), COND_VC(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_svc_8_ix(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AY_IX_8(mc68kcpu), COND_VC(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_svc_8_aw(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AW_8(mc68kcpu), COND_VC(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_svc_8_al(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AL_8(mc68kcpu), COND_VC(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_svs_8_ai(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AY_AI_8(mc68kcpu), COND_VS(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_svs_8_pi(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AY_PI_8(mc68kcpu), COND_VS(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_svs_8_pi7(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_A7_PI_8(mc68kcpu), COND_VS(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_svs_8_pd(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AY_PD_8(mc68kcpu), COND_VS(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_svs_8_pd7(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_A7_PD_8(mc68kcpu), COND_VS(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_svs_8_di(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AY_DI_8(mc68kcpu), COND_VS(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_svs_8_ix(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AY_IX_8(mc68kcpu), COND_VS(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_svs_8_aw(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AW_8(mc68kcpu), COND_VS(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_svs_8_al(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AL_8(mc68kcpu), COND_VS(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_spl_8_ai(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AY_AI_8(mc68kcpu), COND_PL(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_spl_8_pi(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AY_PI_8(mc68kcpu), COND_PL(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_spl_8_pi7(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_A7_PI_8(mc68kcpu), COND_PL(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_spl_8_pd(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AY_PD_8(mc68kcpu), COND_PL(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_spl_8_pd7(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_A7_PD_8(mc68kcpu), COND_PL(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_spl_8_di(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AY_DI_8(mc68kcpu), COND_PL(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_spl_8_ix(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AY_IX_8(mc68kcpu), COND_PL(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_spl_8_aw(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AW_8(mc68kcpu), COND_PL(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_spl_8_al(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AL_8(mc68kcpu), COND_PL(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_smi_8_ai(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AY_AI_8(mc68kcpu), COND_MI(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_smi_8_pi(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AY_PI_8(mc68kcpu), COND_MI(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_smi_8_pi7(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_A7_PI_8(mc68kcpu), COND_MI(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_smi_8_pd(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AY_PD_8(mc68kcpu), COND_MI(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_smi_8_pd7(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_A7_PD_8(mc68kcpu), COND_MI(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_smi_8_di(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AY_DI_8(mc68kcpu), COND_MI(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_smi_8_ix(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AY_IX_8(mc68kcpu), COND_MI(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_smi_8_aw(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AW_8(mc68kcpu), COND_MI(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_smi_8_al(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AL_8(mc68kcpu), COND_MI(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_sge_8_ai(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AY_AI_8(mc68kcpu), COND_GE(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_sge_8_pi(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AY_PI_8(mc68kcpu), COND_GE(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_sge_8_pi7(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_A7_PI_8(mc68kcpu), COND_GE(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_sge_8_pd(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AY_PD_8(mc68kcpu), COND_GE(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_sge_8_pd7(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_A7_PD_8(mc68kcpu), COND_GE(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_sge_8_di(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AY_DI_8(mc68kcpu), COND_GE(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_sge_8_ix(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AY_IX_8(mc68kcpu), COND_GE(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_sge_8_aw(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AW_8(mc68kcpu), COND_GE(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_sge_8_al(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AL_8(mc68kcpu), COND_GE(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_slt_8_ai(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AY_AI_8(mc68kcpu), COND_LT(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_slt_8_pi(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AY_PI_8(mc68kcpu), COND_LT(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_slt_8_pi7(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_A7_PI_8(mc68kcpu), COND_LT(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_slt_8_pd(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AY_PD_8(mc68kcpu), COND_LT(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_slt_8_pd7(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_A7_PD_8(mc68kcpu), COND_LT(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_slt_8_di(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AY_DI_8(mc68kcpu), COND_LT(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_slt_8_ix(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AY_IX_8(mc68kcpu), COND_LT(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_slt_8_aw(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AW_8(mc68kcpu), COND_LT(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_slt_8_al(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AL_8(mc68kcpu), COND_LT(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_sgt_8_ai(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AY_AI_8(mc68kcpu), COND_GT(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_sgt_8_pi(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AY_PI_8(mc68kcpu), COND_GT(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_sgt_8_pi7(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_A7_PI_8(mc68kcpu), COND_GT(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_sgt_8_pd(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AY_PD_8(mc68kcpu), COND_GT(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_sgt_8_pd7(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_A7_PD_8(mc68kcpu), COND_GT(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_sgt_8_di(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AY_DI_8(mc68kcpu), COND_GT(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_sgt_8_ix(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AY_IX_8(mc68kcpu), COND_GT(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_sgt_8_aw(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AW_8(mc68kcpu), COND_GT(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_sgt_8_al(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AL_8(mc68kcpu), COND_GT(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_sle_8_ai(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AY_AI_8(mc68kcpu), COND_LE(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_sle_8_pi(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AY_PI_8(mc68kcpu), COND_LE(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_sle_8_pi7(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_A7_PI_8(mc68kcpu), COND_LE(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_sle_8_pd(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AY_PD_8(mc68kcpu), COND_LE(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_sle_8_pd7(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_A7_PD_8(mc68kcpu), COND_LE(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_sle_8_di(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AY_DI_8(mc68kcpu), COND_LE(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_sle_8_ix(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AY_IX_8(mc68kcpu), COND_LE(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_sle_8_aw(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AW_8(mc68kcpu), COND_LE(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_sle_8_al(m68000_base_device* mc68kcpu) +{ + m68ki_write_8((mc68kcpu), EA_AL_8(mc68kcpu), COND_LE(mc68kcpu) ? 0xff : 0); +} + + +void m68000_base_device_ops::m68k_op_stop(m68000_base_device* mc68kcpu) +{ + if((mc68kcpu)->s_flag) + { + UINT32 new_sr = OPER_I_16(mc68kcpu); + m68ki_trace_t0(mc68kcpu); /* auto-disable (see m68kcpu.h) */ + (mc68kcpu)->stopped |= STOP_LEVEL_STOP; + m68ki_set_sr((mc68kcpu), new_sr); + (mc68kcpu)->remaining_cycles = 0; + return; + } + m68ki_exception_privilege_violation(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_sub_8_er_d(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = MASK_OUT_ABOVE_8(DY(mc68kcpu)); + UINT32 dst = MASK_OUT_ABOVE_8(*r_dst); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(src, dst, res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | (mc68kcpu)->not_z_flag; +} + + +void m68000_base_device_ops::m68k_op_sub_8_er_ai(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = OPER_AY_AI_8(mc68kcpu); + UINT32 dst = MASK_OUT_ABOVE_8(*r_dst); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(src, dst, res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | (mc68kcpu)->not_z_flag; +} + + +void m68000_base_device_ops::m68k_op_sub_8_er_pi(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = OPER_AY_PI_8(mc68kcpu); + UINT32 dst = MASK_OUT_ABOVE_8(*r_dst); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(src, dst, res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | (mc68kcpu)->not_z_flag; +} + + +void m68000_base_device_ops::m68k_op_sub_8_er_pi7(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = OPER_A7_PI_8(mc68kcpu); + UINT32 dst = MASK_OUT_ABOVE_8(*r_dst); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(src, dst, res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | (mc68kcpu)->not_z_flag; +} + + +void m68000_base_device_ops::m68k_op_sub_8_er_pd(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = OPER_AY_PD_8(mc68kcpu); + UINT32 dst = MASK_OUT_ABOVE_8(*r_dst); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(src, dst, res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | (mc68kcpu)->not_z_flag; +} + + +void m68000_base_device_ops::m68k_op_sub_8_er_pd7(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = OPER_A7_PD_8(mc68kcpu); + UINT32 dst = MASK_OUT_ABOVE_8(*r_dst); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(src, dst, res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | (mc68kcpu)->not_z_flag; +} + + +void m68000_base_device_ops::m68k_op_sub_8_er_di(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = OPER_AY_DI_8(mc68kcpu); + UINT32 dst = MASK_OUT_ABOVE_8(*r_dst); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(src, dst, res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | (mc68kcpu)->not_z_flag; +} + + +void m68000_base_device_ops::m68k_op_sub_8_er_ix(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = OPER_AY_IX_8(mc68kcpu); + UINT32 dst = MASK_OUT_ABOVE_8(*r_dst); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(src, dst, res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | (mc68kcpu)->not_z_flag; +} + + +void m68000_base_device_ops::m68k_op_sub_8_er_aw(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = OPER_AW_8(mc68kcpu); + UINT32 dst = MASK_OUT_ABOVE_8(*r_dst); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(src, dst, res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | (mc68kcpu)->not_z_flag; +} + + +void m68000_base_device_ops::m68k_op_sub_8_er_al(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = OPER_AL_8(mc68kcpu); + UINT32 dst = MASK_OUT_ABOVE_8(*r_dst); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(src, dst, res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | (mc68kcpu)->not_z_flag; +} + + +void m68000_base_device_ops::m68k_op_sub_8_er_pcdi(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = OPER_PCDI_8(mc68kcpu); + UINT32 dst = MASK_OUT_ABOVE_8(*r_dst); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(src, dst, res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | (mc68kcpu)->not_z_flag; +} + + +void m68000_base_device_ops::m68k_op_sub_8_er_pcix(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = OPER_PCIX_8(mc68kcpu); + UINT32 dst = MASK_OUT_ABOVE_8(*r_dst); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(src, dst, res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | (mc68kcpu)->not_z_flag; +} + + +void m68000_base_device_ops::m68k_op_sub_8_er_i(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = OPER_I_8(mc68kcpu); + UINT32 dst = MASK_OUT_ABOVE_8(*r_dst); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(src, dst, res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | (mc68kcpu)->not_z_flag; +} + + +void m68000_base_device_ops::m68k_op_sub_16_er_d(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = MASK_OUT_ABOVE_16(DY(mc68kcpu)); + UINT32 dst = MASK_OUT_ABOVE_16(*r_dst); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_16(res); + (mc68kcpu)->v_flag = VFLAG_SUB_16(src, dst, res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | (mc68kcpu)->not_z_flag; +} + + +void m68000_base_device_ops::m68k_op_sub_16_er_a(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = MASK_OUT_ABOVE_16(AY(mc68kcpu)); + UINT32 dst = MASK_OUT_ABOVE_16(*r_dst); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_16(res); + (mc68kcpu)->v_flag = VFLAG_SUB_16(src, dst, res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | (mc68kcpu)->not_z_flag; +} + + +void m68000_base_device_ops::m68k_op_sub_16_er_ai(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = OPER_AY_AI_16(mc68kcpu); + UINT32 dst = MASK_OUT_ABOVE_16(*r_dst); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_16(res); + (mc68kcpu)->v_flag = VFLAG_SUB_16(src, dst, res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | (mc68kcpu)->not_z_flag; +} + + +void m68000_base_device_ops::m68k_op_sub_16_er_pi(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = OPER_AY_PI_16(mc68kcpu); + UINT32 dst = MASK_OUT_ABOVE_16(*r_dst); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_16(res); + (mc68kcpu)->v_flag = VFLAG_SUB_16(src, dst, res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | (mc68kcpu)->not_z_flag; +} + + +void m68000_base_device_ops::m68k_op_sub_16_er_pd(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = OPER_AY_PD_16(mc68kcpu); + UINT32 dst = MASK_OUT_ABOVE_16(*r_dst); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_16(res); + (mc68kcpu)->v_flag = VFLAG_SUB_16(src, dst, res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | (mc68kcpu)->not_z_flag; +} + + +void m68000_base_device_ops::m68k_op_sub_16_er_di(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = OPER_AY_DI_16(mc68kcpu); + UINT32 dst = MASK_OUT_ABOVE_16(*r_dst); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_16(res); + (mc68kcpu)->v_flag = VFLAG_SUB_16(src, dst, res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | (mc68kcpu)->not_z_flag; +} + + +void m68000_base_device_ops::m68k_op_sub_16_er_ix(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = OPER_AY_IX_16(mc68kcpu); + UINT32 dst = MASK_OUT_ABOVE_16(*r_dst); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_16(res); + (mc68kcpu)->v_flag = VFLAG_SUB_16(src, dst, res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | (mc68kcpu)->not_z_flag; +} + + +void m68000_base_device_ops::m68k_op_sub_16_er_aw(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = OPER_AW_16(mc68kcpu); + UINT32 dst = MASK_OUT_ABOVE_16(*r_dst); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_16(res); + (mc68kcpu)->v_flag = VFLAG_SUB_16(src, dst, res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | (mc68kcpu)->not_z_flag; +} + + +void m68000_base_device_ops::m68k_op_sub_16_er_al(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = OPER_AL_16(mc68kcpu); + UINT32 dst = MASK_OUT_ABOVE_16(*r_dst); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_16(res); + (mc68kcpu)->v_flag = VFLAG_SUB_16(src, dst, res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | (mc68kcpu)->not_z_flag; +} + + +void m68000_base_device_ops::m68k_op_sub_16_er_pcdi(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = OPER_PCDI_16(mc68kcpu); + UINT32 dst = MASK_OUT_ABOVE_16(*r_dst); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_16(res); + (mc68kcpu)->v_flag = VFLAG_SUB_16(src, dst, res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | (mc68kcpu)->not_z_flag; +} + + +void m68000_base_device_ops::m68k_op_sub_16_er_pcix(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = OPER_PCIX_16(mc68kcpu); + UINT32 dst = MASK_OUT_ABOVE_16(*r_dst); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_16(res); + (mc68kcpu)->v_flag = VFLAG_SUB_16(src, dst, res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | (mc68kcpu)->not_z_flag; +} + + +void m68000_base_device_ops::m68k_op_sub_16_er_i(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = OPER_I_16(mc68kcpu); + UINT32 dst = MASK_OUT_ABOVE_16(*r_dst); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_16(res); + (mc68kcpu)->v_flag = VFLAG_SUB_16(src, dst, res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | (mc68kcpu)->not_z_flag; +} + + +void m68000_base_device_ops::m68k_op_sub_32_er_d(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = DY(mc68kcpu); + UINT32 dst = *r_dst; + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + + *r_dst = (mc68kcpu)->not_z_flag; +} + + +void m68000_base_device_ops::m68k_op_sub_32_er_a(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = AY(mc68kcpu); + UINT32 dst = *r_dst; + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + + *r_dst = (mc68kcpu)->not_z_flag; +} + + +void m68000_base_device_ops::m68k_op_sub_32_er_ai(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = OPER_AY_AI_32(mc68kcpu); + UINT32 dst = *r_dst; + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + + *r_dst = (mc68kcpu)->not_z_flag; +} + + +void m68000_base_device_ops::m68k_op_sub_32_er_pi(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = OPER_AY_PI_32(mc68kcpu); + UINT32 dst = *r_dst; + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + + *r_dst = (mc68kcpu)->not_z_flag; +} + + +void m68000_base_device_ops::m68k_op_sub_32_er_pd(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = OPER_AY_PD_32(mc68kcpu); + UINT32 dst = *r_dst; + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + + *r_dst = (mc68kcpu)->not_z_flag; +} + + +void m68000_base_device_ops::m68k_op_sub_32_er_di(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = OPER_AY_DI_32(mc68kcpu); + UINT32 dst = *r_dst; + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + + *r_dst = (mc68kcpu)->not_z_flag; +} + + +void m68000_base_device_ops::m68k_op_sub_32_er_ix(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = OPER_AY_IX_32(mc68kcpu); + UINT32 dst = *r_dst; + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + + *r_dst = (mc68kcpu)->not_z_flag; +} + + +void m68000_base_device_ops::m68k_op_sub_32_er_aw(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = OPER_AW_32(mc68kcpu); + UINT32 dst = *r_dst; + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + + *r_dst = (mc68kcpu)->not_z_flag; +} + + +void m68000_base_device_ops::m68k_op_sub_32_er_al(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = OPER_AL_32(mc68kcpu); + UINT32 dst = *r_dst; + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + + *r_dst = (mc68kcpu)->not_z_flag; +} + + +void m68000_base_device_ops::m68k_op_sub_32_er_pcdi(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = OPER_PCDI_32(mc68kcpu); + UINT32 dst = *r_dst; + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + + *r_dst = (mc68kcpu)->not_z_flag; +} + + +void m68000_base_device_ops::m68k_op_sub_32_er_pcix(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = OPER_PCIX_32(mc68kcpu); + UINT32 dst = *r_dst; + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + + *r_dst = (mc68kcpu)->not_z_flag; +} + + +void m68000_base_device_ops::m68k_op_sub_32_er_i(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = OPER_I_32(mc68kcpu); + UINT32 dst = *r_dst; + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + + *r_dst = (mc68kcpu)->not_z_flag; +} + + +void m68000_base_device_ops::m68k_op_sub_8_re_ai(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_AI_8(mc68kcpu); + UINT32 src = MASK_OUT_ABOVE_8(DX(mc68kcpu)); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(src, dst, res); + + m68ki_write_8((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_sub_8_re_pi(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_PI_8(mc68kcpu); + UINT32 src = MASK_OUT_ABOVE_8(DX(mc68kcpu)); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(src, dst, res); + + m68ki_write_8((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_sub_8_re_pi7(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_A7_PI_8(mc68kcpu); + UINT32 src = MASK_OUT_ABOVE_8(DX(mc68kcpu)); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(src, dst, res); + + m68ki_write_8((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_sub_8_re_pd(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_PD_8(mc68kcpu); + UINT32 src = MASK_OUT_ABOVE_8(DX(mc68kcpu)); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(src, dst, res); + + m68ki_write_8((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_sub_8_re_pd7(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_A7_PD_8(mc68kcpu); + UINT32 src = MASK_OUT_ABOVE_8(DX(mc68kcpu)); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(src, dst, res); + + m68ki_write_8((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_sub_8_re_di(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_DI_8(mc68kcpu); + UINT32 src = MASK_OUT_ABOVE_8(DX(mc68kcpu)); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(src, dst, res); + + m68ki_write_8((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_sub_8_re_ix(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_IX_8(mc68kcpu); + UINT32 src = MASK_OUT_ABOVE_8(DX(mc68kcpu)); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(src, dst, res); + + m68ki_write_8((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_sub_8_re_aw(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AW_8(mc68kcpu); + UINT32 src = MASK_OUT_ABOVE_8(DX(mc68kcpu)); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(src, dst, res); + + m68ki_write_8((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_sub_8_re_al(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AL_8(mc68kcpu); + UINT32 src = MASK_OUT_ABOVE_8(DX(mc68kcpu)); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(src, dst, res); + + m68ki_write_8((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_sub_16_re_ai(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_AI_16(mc68kcpu); + UINT32 src = MASK_OUT_ABOVE_16(DX(mc68kcpu)); + UINT32 dst = m68ki_read_16((mc68kcpu), ea); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_16(res); + (mc68kcpu)->v_flag = VFLAG_SUB_16(src, dst, res); + + m68ki_write_16((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_sub_16_re_pi(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_PI_16(mc68kcpu); + UINT32 src = MASK_OUT_ABOVE_16(DX(mc68kcpu)); + UINT32 dst = m68ki_read_16((mc68kcpu), ea); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_16(res); + (mc68kcpu)->v_flag = VFLAG_SUB_16(src, dst, res); + + m68ki_write_16((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_sub_16_re_pd(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_PD_16(mc68kcpu); + UINT32 src = MASK_OUT_ABOVE_16(DX(mc68kcpu)); + UINT32 dst = m68ki_read_16((mc68kcpu), ea); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_16(res); + (mc68kcpu)->v_flag = VFLAG_SUB_16(src, dst, res); + + m68ki_write_16((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_sub_16_re_di(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_DI_16(mc68kcpu); + UINT32 src = MASK_OUT_ABOVE_16(DX(mc68kcpu)); + UINT32 dst = m68ki_read_16((mc68kcpu), ea); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_16(res); + (mc68kcpu)->v_flag = VFLAG_SUB_16(src, dst, res); + + m68ki_write_16((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_sub_16_re_ix(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_IX_16(mc68kcpu); + UINT32 src = MASK_OUT_ABOVE_16(DX(mc68kcpu)); + UINT32 dst = m68ki_read_16((mc68kcpu), ea); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_16(res); + (mc68kcpu)->v_flag = VFLAG_SUB_16(src, dst, res); + + m68ki_write_16((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_sub_16_re_aw(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AW_16(mc68kcpu); + UINT32 src = MASK_OUT_ABOVE_16(DX(mc68kcpu)); + UINT32 dst = m68ki_read_16((mc68kcpu), ea); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_16(res); + (mc68kcpu)->v_flag = VFLAG_SUB_16(src, dst, res); + + m68ki_write_16((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_sub_16_re_al(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AL_16(mc68kcpu); + UINT32 src = MASK_OUT_ABOVE_16(DX(mc68kcpu)); + UINT32 dst = m68ki_read_16((mc68kcpu), ea); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_16(res); + (mc68kcpu)->v_flag = VFLAG_SUB_16(src, dst, res); + + m68ki_write_16((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_sub_32_re_ai(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_AI_32(mc68kcpu); + UINT32 src = DX(mc68kcpu); + UINT32 dst = m68ki_read_32((mc68kcpu), ea); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + + m68ki_write_32((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_sub_32_re_pi(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_PI_32(mc68kcpu); + UINT32 src = DX(mc68kcpu); + UINT32 dst = m68ki_read_32((mc68kcpu), ea); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + + m68ki_write_32((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_sub_32_re_pd(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_PD_32(mc68kcpu); + UINT32 src = DX(mc68kcpu); + UINT32 dst = m68ki_read_32((mc68kcpu), ea); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + + m68ki_write_32((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_sub_32_re_di(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_DI_32(mc68kcpu); + UINT32 src = DX(mc68kcpu); + UINT32 dst = m68ki_read_32((mc68kcpu), ea); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + + m68ki_write_32((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_sub_32_re_ix(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_IX_32(mc68kcpu); + UINT32 src = DX(mc68kcpu); + UINT32 dst = m68ki_read_32((mc68kcpu), ea); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + + m68ki_write_32((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_sub_32_re_aw(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AW_32(mc68kcpu); + UINT32 src = DX(mc68kcpu); + UINT32 dst = m68ki_read_32((mc68kcpu), ea); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + + m68ki_write_32((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_sub_32_re_al(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AL_32(mc68kcpu); + UINT32 src = DX(mc68kcpu); + UINT32 dst = m68ki_read_32((mc68kcpu), ea); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + + m68ki_write_32((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_suba_16_d(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &AX(mc68kcpu); + + *r_dst = MASK_OUT_ABOVE_32(*r_dst - MAKE_INT_16(DY(mc68kcpu))); +} + + +void m68000_base_device_ops::m68k_op_suba_16_a(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &AX(mc68kcpu); + + *r_dst = MASK_OUT_ABOVE_32(*r_dst - MAKE_INT_16(AY(mc68kcpu))); +} + + +void m68000_base_device_ops::m68k_op_suba_16_ai(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &AX(mc68kcpu); + UINT32 src = MAKE_INT_16(OPER_AY_AI_16(mc68kcpu)); + + *r_dst = MASK_OUT_ABOVE_32(*r_dst - src); +} + + +void m68000_base_device_ops::m68k_op_suba_16_pi(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &AX(mc68kcpu); + UINT32 src = MAKE_INT_16(OPER_AY_PI_16(mc68kcpu)); + + *r_dst = MASK_OUT_ABOVE_32(*r_dst - src); +} + + +void m68000_base_device_ops::m68k_op_suba_16_pd(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &AX(mc68kcpu); + UINT32 src = MAKE_INT_16(OPER_AY_PD_16(mc68kcpu)); + + *r_dst = MASK_OUT_ABOVE_32(*r_dst - src); +} + + +void m68000_base_device_ops::m68k_op_suba_16_di(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &AX(mc68kcpu); + UINT32 src = MAKE_INT_16(OPER_AY_DI_16(mc68kcpu)); + + *r_dst = MASK_OUT_ABOVE_32(*r_dst - src); +} + + +void m68000_base_device_ops::m68k_op_suba_16_ix(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &AX(mc68kcpu); + UINT32 src = MAKE_INT_16(OPER_AY_IX_16(mc68kcpu)); + + *r_dst = MASK_OUT_ABOVE_32(*r_dst - src); +} + + +void m68000_base_device_ops::m68k_op_suba_16_aw(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &AX(mc68kcpu); + UINT32 src = MAKE_INT_16(OPER_AW_16(mc68kcpu)); + + *r_dst = MASK_OUT_ABOVE_32(*r_dst - src); +} + + +void m68000_base_device_ops::m68k_op_suba_16_al(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &AX(mc68kcpu); + UINT32 src = MAKE_INT_16(OPER_AL_16(mc68kcpu)); + + *r_dst = MASK_OUT_ABOVE_32(*r_dst - src); +} + + +void m68000_base_device_ops::m68k_op_suba_16_pcdi(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &AX(mc68kcpu); + UINT32 src = MAKE_INT_16(OPER_PCDI_16(mc68kcpu)); + + *r_dst = MASK_OUT_ABOVE_32(*r_dst - src); +} + + +void m68000_base_device_ops::m68k_op_suba_16_pcix(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &AX(mc68kcpu); + UINT32 src = MAKE_INT_16(OPER_PCIX_16(mc68kcpu)); + + *r_dst = MASK_OUT_ABOVE_32(*r_dst - src); +} + + +void m68000_base_device_ops::m68k_op_suba_16_i(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &AX(mc68kcpu); + UINT32 src = MAKE_INT_16(OPER_I_16(mc68kcpu)); + + *r_dst = MASK_OUT_ABOVE_32(*r_dst - src); +} + + +void m68000_base_device_ops::m68k_op_suba_32_d(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &AX(mc68kcpu); + + *r_dst = MASK_OUT_ABOVE_32(*r_dst - DY(mc68kcpu)); +} + + +void m68000_base_device_ops::m68k_op_suba_32_a(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &AX(mc68kcpu); + + *r_dst = MASK_OUT_ABOVE_32(*r_dst - AY(mc68kcpu)); +} + + +void m68000_base_device_ops::m68k_op_suba_32_ai(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &AX(mc68kcpu); + UINT32 src = OPER_AY_AI_32(mc68kcpu); + + *r_dst = MASK_OUT_ABOVE_32(*r_dst - src); +} + + +void m68000_base_device_ops::m68k_op_suba_32_pi(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &AX(mc68kcpu); + UINT32 src = OPER_AY_PI_32(mc68kcpu); + + *r_dst = MASK_OUT_ABOVE_32(*r_dst - src); +} + + +void m68000_base_device_ops::m68k_op_suba_32_pd(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &AX(mc68kcpu); + UINT32 src = OPER_AY_PD_32(mc68kcpu); + + *r_dst = MASK_OUT_ABOVE_32(*r_dst - src); +} + + +void m68000_base_device_ops::m68k_op_suba_32_di(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &AX(mc68kcpu); + UINT32 src = OPER_AY_DI_32(mc68kcpu); + + *r_dst = MASK_OUT_ABOVE_32(*r_dst - src); +} + + +void m68000_base_device_ops::m68k_op_suba_32_ix(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &AX(mc68kcpu); + UINT32 src = OPER_AY_IX_32(mc68kcpu); + + *r_dst = MASK_OUT_ABOVE_32(*r_dst - src); +} + + +void m68000_base_device_ops::m68k_op_suba_32_aw(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &AX(mc68kcpu); + UINT32 src = OPER_AW_32(mc68kcpu); + + *r_dst = MASK_OUT_ABOVE_32(*r_dst - src); +} + + +void m68000_base_device_ops::m68k_op_suba_32_al(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &AX(mc68kcpu); + UINT32 src = OPER_AL_32(mc68kcpu); + + *r_dst = MASK_OUT_ABOVE_32(*r_dst - src); +} + + +void m68000_base_device_ops::m68k_op_suba_32_pcdi(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &AX(mc68kcpu); + UINT32 src = OPER_PCDI_32(mc68kcpu); + + *r_dst = MASK_OUT_ABOVE_32(*r_dst - src); +} + + +void m68000_base_device_ops::m68k_op_suba_32_pcix(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &AX(mc68kcpu); + UINT32 src = OPER_PCIX_32(mc68kcpu); + + *r_dst = MASK_OUT_ABOVE_32(*r_dst - src); +} + + +void m68000_base_device_ops::m68k_op_suba_32_i(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &AX(mc68kcpu); + UINT32 src = OPER_I_32(mc68kcpu); + + *r_dst = MASK_OUT_ABOVE_32(*r_dst - src); +} + + +void m68000_base_device_ops::m68k_op_subi_8_d(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 src = OPER_I_8(mc68kcpu); + UINT32 dst = MASK_OUT_ABOVE_8(*r_dst); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(src, dst, res); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | (mc68kcpu)->not_z_flag; +} + + +void m68000_base_device_ops::m68k_op_subi_8_ai(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_8(mc68kcpu); + UINT32 ea = EA_AY_AI_8(mc68kcpu); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(src, dst, res); + + m68ki_write_8((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_subi_8_pi(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_8(mc68kcpu); + UINT32 ea = EA_AY_PI_8(mc68kcpu); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(src, dst, res); + + m68ki_write_8((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_subi_8_pi7(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_8(mc68kcpu); + UINT32 ea = EA_A7_PI_8(mc68kcpu); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(src, dst, res); + + m68ki_write_8((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_subi_8_pd(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_8(mc68kcpu); + UINT32 ea = EA_AY_PD_8(mc68kcpu); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(src, dst, res); + + m68ki_write_8((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_subi_8_pd7(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_8(mc68kcpu); + UINT32 ea = EA_A7_PD_8(mc68kcpu); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(src, dst, res); + + m68ki_write_8((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_subi_8_di(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_8(mc68kcpu); + UINT32 ea = EA_AY_DI_8(mc68kcpu); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(src, dst, res); + + m68ki_write_8((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_subi_8_ix(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_8(mc68kcpu); + UINT32 ea = EA_AY_IX_8(mc68kcpu); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(src, dst, res); + + m68ki_write_8((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_subi_8_aw(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_8(mc68kcpu); + UINT32 ea = EA_AW_8(mc68kcpu); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(src, dst, res); + + m68ki_write_8((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_subi_8_al(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_8(mc68kcpu); + UINT32 ea = EA_AL_8(mc68kcpu); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(src, dst, res); + + m68ki_write_8((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_subi_16_d(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 src = OPER_I_16(mc68kcpu); + UINT32 dst = MASK_OUT_ABOVE_16(*r_dst); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_16(res); + (mc68kcpu)->v_flag = VFLAG_SUB_16(src, dst, res); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | (mc68kcpu)->not_z_flag; +} + + +void m68000_base_device_ops::m68k_op_subi_16_ai(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_16(mc68kcpu); + UINT32 ea = EA_AY_AI_16(mc68kcpu); + UINT32 dst = m68ki_read_16((mc68kcpu), ea); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_16(res); + (mc68kcpu)->v_flag = VFLAG_SUB_16(src, dst, res); + + m68ki_write_16((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_subi_16_pi(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_16(mc68kcpu); + UINT32 ea = EA_AY_PI_16(mc68kcpu); + UINT32 dst = m68ki_read_16((mc68kcpu), ea); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_16(res); + (mc68kcpu)->v_flag = VFLAG_SUB_16(src, dst, res); + + m68ki_write_16((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_subi_16_pd(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_16(mc68kcpu); + UINT32 ea = EA_AY_PD_16(mc68kcpu); + UINT32 dst = m68ki_read_16((mc68kcpu), ea); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_16(res); + (mc68kcpu)->v_flag = VFLAG_SUB_16(src, dst, res); + + m68ki_write_16((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_subi_16_di(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_16(mc68kcpu); + UINT32 ea = EA_AY_DI_16(mc68kcpu); + UINT32 dst = m68ki_read_16((mc68kcpu), ea); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_16(res); + (mc68kcpu)->v_flag = VFLAG_SUB_16(src, dst, res); + + m68ki_write_16((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_subi_16_ix(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_16(mc68kcpu); + UINT32 ea = EA_AY_IX_16(mc68kcpu); + UINT32 dst = m68ki_read_16((mc68kcpu), ea); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_16(res); + (mc68kcpu)->v_flag = VFLAG_SUB_16(src, dst, res); + + m68ki_write_16((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_subi_16_aw(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_16(mc68kcpu); + UINT32 ea = EA_AW_16(mc68kcpu); + UINT32 dst = m68ki_read_16((mc68kcpu), ea); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_16(res); + (mc68kcpu)->v_flag = VFLAG_SUB_16(src, dst, res); + + m68ki_write_16((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_subi_16_al(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_16(mc68kcpu); + UINT32 ea = EA_AL_16(mc68kcpu); + UINT32 dst = m68ki_read_16((mc68kcpu), ea); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_16(res); + (mc68kcpu)->v_flag = VFLAG_SUB_16(src, dst, res); + + m68ki_write_16((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_subi_32_d(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 src = OPER_I_32(mc68kcpu); + UINT32 dst = *r_dst; + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + + *r_dst = (mc68kcpu)->not_z_flag; +} + + +void m68000_base_device_ops::m68k_op_subi_32_ai(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_32(mc68kcpu); + UINT32 ea = EA_AY_AI_32(mc68kcpu); + UINT32 dst = m68ki_read_32((mc68kcpu), ea); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + + m68ki_write_32((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_subi_32_pi(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_32(mc68kcpu); + UINT32 ea = EA_AY_PI_32(mc68kcpu); + UINT32 dst = m68ki_read_32((mc68kcpu), ea); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + + m68ki_write_32((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_subi_32_pd(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_32(mc68kcpu); + UINT32 ea = EA_AY_PD_32(mc68kcpu); + UINT32 dst = m68ki_read_32((mc68kcpu), ea); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + + m68ki_write_32((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_subi_32_di(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_32(mc68kcpu); + UINT32 ea = EA_AY_DI_32(mc68kcpu); + UINT32 dst = m68ki_read_32((mc68kcpu), ea); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + + m68ki_write_32((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_subi_32_ix(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_32(mc68kcpu); + UINT32 ea = EA_AY_IX_32(mc68kcpu); + UINT32 dst = m68ki_read_32((mc68kcpu), ea); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + + m68ki_write_32((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_subi_32_aw(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_32(mc68kcpu); + UINT32 ea = EA_AW_32(mc68kcpu); + UINT32 dst = m68ki_read_32((mc68kcpu), ea); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + + m68ki_write_32((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_subi_32_al(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_I_32(mc68kcpu); + UINT32 ea = EA_AL_32(mc68kcpu); + UINT32 dst = m68ki_read_32((mc68kcpu), ea); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + + m68ki_write_32((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_subq_8_d(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 src = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT32 dst = MASK_OUT_ABOVE_8(*r_dst); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(src, dst, res); + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | (mc68kcpu)->not_z_flag; +} + + +void m68000_base_device_ops::m68k_op_subq_8_ai(m68000_base_device* mc68kcpu) +{ + UINT32 src = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT32 ea = EA_AY_AI_8(mc68kcpu); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(src, dst, res); + + m68ki_write_8((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_subq_8_pi(m68000_base_device* mc68kcpu) +{ + UINT32 src = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT32 ea = EA_AY_PI_8(mc68kcpu); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(src, dst, res); + + m68ki_write_8((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_subq_8_pi7(m68000_base_device* mc68kcpu) +{ + UINT32 src = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT32 ea = EA_A7_PI_8(mc68kcpu); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(src, dst, res); + + m68ki_write_8((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_subq_8_pd(m68000_base_device* mc68kcpu) +{ + UINT32 src = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT32 ea = EA_AY_PD_8(mc68kcpu); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(src, dst, res); + + m68ki_write_8((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_subq_8_pd7(m68000_base_device* mc68kcpu) +{ + UINT32 src = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT32 ea = EA_A7_PD_8(mc68kcpu); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(src, dst, res); + + m68ki_write_8((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_subq_8_di(m68000_base_device* mc68kcpu) +{ + UINT32 src = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT32 ea = EA_AY_DI_8(mc68kcpu); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(src, dst, res); + + m68ki_write_8((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_subq_8_ix(m68000_base_device* mc68kcpu) +{ + UINT32 src = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT32 ea = EA_AY_IX_8(mc68kcpu); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(src, dst, res); + + m68ki_write_8((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_subq_8_aw(m68000_base_device* mc68kcpu) +{ + UINT32 src = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT32 ea = EA_AW_8(mc68kcpu); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(src, dst, res); + + m68ki_write_8((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_subq_8_al(m68000_base_device* mc68kcpu) +{ + UINT32 src = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT32 ea = EA_AL_8(mc68kcpu); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(src, dst, res); + + m68ki_write_8((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_subq_16_d(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 src = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT32 dst = MASK_OUT_ABOVE_16(*r_dst); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_16(res); + (mc68kcpu)->v_flag = VFLAG_SUB_16(src, dst, res); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | (mc68kcpu)->not_z_flag; +} + + +void m68000_base_device_ops::m68k_op_subq_16_a(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &AY(mc68kcpu); + + *r_dst = MASK_OUT_ABOVE_32(*r_dst - (((((mc68kcpu)->ir >> 9) - 1) & 7) + 1)); +} + + +void m68000_base_device_ops::m68k_op_subq_16_ai(m68000_base_device* mc68kcpu) +{ + UINT32 src = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT32 ea = EA_AY_AI_16(mc68kcpu); + UINT32 dst = m68ki_read_16((mc68kcpu), ea); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_16(res); + (mc68kcpu)->v_flag = VFLAG_SUB_16(src, dst, res); + + m68ki_write_16((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_subq_16_pi(m68000_base_device* mc68kcpu) +{ + UINT32 src = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT32 ea = EA_AY_PI_16(mc68kcpu); + UINT32 dst = m68ki_read_16((mc68kcpu), ea); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_16(res); + (mc68kcpu)->v_flag = VFLAG_SUB_16(src, dst, res); + + m68ki_write_16((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_subq_16_pd(m68000_base_device* mc68kcpu) +{ + UINT32 src = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT32 ea = EA_AY_PD_16(mc68kcpu); + UINT32 dst = m68ki_read_16((mc68kcpu), ea); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_16(res); + (mc68kcpu)->v_flag = VFLAG_SUB_16(src, dst, res); + + m68ki_write_16((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_subq_16_di(m68000_base_device* mc68kcpu) +{ + UINT32 src = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT32 ea = EA_AY_DI_16(mc68kcpu); + UINT32 dst = m68ki_read_16((mc68kcpu), ea); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_16(res); + (mc68kcpu)->v_flag = VFLAG_SUB_16(src, dst, res); + + m68ki_write_16((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_subq_16_ix(m68000_base_device* mc68kcpu) +{ + UINT32 src = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT32 ea = EA_AY_IX_16(mc68kcpu); + UINT32 dst = m68ki_read_16((mc68kcpu), ea); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_16(res); + (mc68kcpu)->v_flag = VFLAG_SUB_16(src, dst, res); + + m68ki_write_16((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_subq_16_aw(m68000_base_device* mc68kcpu) +{ + UINT32 src = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT32 ea = EA_AW_16(mc68kcpu); + UINT32 dst = m68ki_read_16((mc68kcpu), ea); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_16(res); + (mc68kcpu)->v_flag = VFLAG_SUB_16(src, dst, res); + + m68ki_write_16((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_subq_16_al(m68000_base_device* mc68kcpu) +{ + UINT32 src = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT32 ea = EA_AL_16(mc68kcpu); + UINT32 dst = m68ki_read_16((mc68kcpu), ea); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_16(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_16(res); + (mc68kcpu)->v_flag = VFLAG_SUB_16(src, dst, res); + + m68ki_write_16((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_subq_32_d(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DY(mc68kcpu); + UINT32 src = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT32 dst = *r_dst; + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + + *r_dst = (mc68kcpu)->not_z_flag; +} + + +void m68000_base_device_ops::m68k_op_subq_32_a(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &AY(mc68kcpu); + + *r_dst = MASK_OUT_ABOVE_32(*r_dst - (((((mc68kcpu)->ir >> 9) - 1) & 7) + 1)); +} + + +void m68000_base_device_ops::m68k_op_subq_32_ai(m68000_base_device* mc68kcpu) +{ + UINT32 src = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT32 ea = EA_AY_AI_32(mc68kcpu); + UINT32 dst = m68ki_read_32((mc68kcpu), ea); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + + m68ki_write_32((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_subq_32_pi(m68000_base_device* mc68kcpu) +{ + UINT32 src = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT32 ea = EA_AY_PI_32(mc68kcpu); + UINT32 dst = m68ki_read_32((mc68kcpu), ea); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + + m68ki_write_32((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_subq_32_pd(m68000_base_device* mc68kcpu) +{ + UINT32 src = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT32 ea = EA_AY_PD_32(mc68kcpu); + UINT32 dst = m68ki_read_32((mc68kcpu), ea); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + + m68ki_write_32((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_subq_32_di(m68000_base_device* mc68kcpu) +{ + UINT32 src = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT32 ea = EA_AY_DI_32(mc68kcpu); + UINT32 dst = m68ki_read_32((mc68kcpu), ea); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + + m68ki_write_32((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_subq_32_ix(m68000_base_device* mc68kcpu) +{ + UINT32 src = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT32 ea = EA_AY_IX_32(mc68kcpu); + UINT32 dst = m68ki_read_32((mc68kcpu), ea); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + + m68ki_write_32((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_subq_32_aw(m68000_base_device* mc68kcpu) +{ + UINT32 src = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT32 ea = EA_AW_32(mc68kcpu); + UINT32 dst = m68ki_read_32((mc68kcpu), ea); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + + m68ki_write_32((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_subq_32_al(m68000_base_device* mc68kcpu) +{ + UINT32 src = ((((mc68kcpu)->ir >> 9) - 1) & 7) + 1; + UINT32 ea = EA_AL_32(mc68kcpu); + UINT32 dst = m68ki_read_32((mc68kcpu), ea); + UINT32 res = dst - src; + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + + m68ki_write_32((mc68kcpu), ea, (mc68kcpu)->not_z_flag); +} + + +void m68000_base_device_ops::m68k_op_subx_8_rr(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = MASK_OUT_ABOVE_8(DY(mc68kcpu)); + UINT32 dst = MASK_OUT_ABOVE_8(*r_dst); + UINT32 res = dst - src - XFLAG_AS_1(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(src, dst, res); + + res = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->not_z_flag |= res; + + *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; +} + + +void m68000_base_device_ops::m68k_op_subx_16_rr(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = MASK_OUT_ABOVE_16(DY(mc68kcpu)); + UINT32 dst = MASK_OUT_ABOVE_16(*r_dst); + UINT32 res = dst - src - XFLAG_AS_1(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_16(res); + (mc68kcpu)->v_flag = VFLAG_SUB_16(src, dst, res); + + res = MASK_OUT_ABOVE_16(res); + (mc68kcpu)->not_z_flag |= res; + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; +} + + +void m68000_base_device_ops::m68k_op_subx_32_rr(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DX(mc68kcpu); + UINT32 src = DY(mc68kcpu); + UINT32 dst = *r_dst; + UINT32 res = dst - src - XFLAG_AS_1(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + + res = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->not_z_flag |= res; + + *r_dst = res; +} + + +void m68000_base_device_ops::m68k_op_subx_8_mm_ax7(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_AY_PD_8(mc68kcpu); + UINT32 ea = EA_A7_PD_8(mc68kcpu); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + UINT32 res = dst - src - XFLAG_AS_1(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(src, dst, res); + + res = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->not_z_flag |= res; + + m68ki_write_8((mc68kcpu), ea, res); +} + + +void m68000_base_device_ops::m68k_op_subx_8_mm_ay7(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_A7_PD_8(mc68kcpu); + UINT32 ea = EA_AX_PD_8(mc68kcpu); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + UINT32 res = dst - src - XFLAG_AS_1(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(src, dst, res); + + res = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->not_z_flag |= res; + + m68ki_write_8((mc68kcpu), ea, res); +} + + +void m68000_base_device_ops::m68k_op_subx_8_mm_axy7(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_A7_PD_8(mc68kcpu); + UINT32 ea = EA_A7_PD_8(mc68kcpu); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + UINT32 res = dst - src - XFLAG_AS_1(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(src, dst, res); + + res = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->not_z_flag |= res; + + m68ki_write_8((mc68kcpu), ea, res); +} + + +void m68000_base_device_ops::m68k_op_subx_8_mm(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_AY_PD_8(mc68kcpu); + UINT32 ea = EA_AX_PD_8(mc68kcpu); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + UINT32 res = dst - src - XFLAG_AS_1(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_8(res); + (mc68kcpu)->v_flag = VFLAG_SUB_8(src, dst, res); + + res = MASK_OUT_ABOVE_8(res); + (mc68kcpu)->not_z_flag |= res; + + m68ki_write_8((mc68kcpu), ea, res); +} + + +void m68000_base_device_ops::m68k_op_subx_16_mm(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_AY_PD_16(mc68kcpu); + UINT32 ea = EA_AX_PD_16(mc68kcpu); + UINT32 dst = m68ki_read_16((mc68kcpu), ea); + UINT32 res = dst - src - XFLAG_AS_1(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_16(res); + (mc68kcpu)->v_flag = VFLAG_SUB_16(src, dst, res); + + res = MASK_OUT_ABOVE_16(res); + (mc68kcpu)->not_z_flag |= res; + + m68ki_write_16((mc68kcpu), ea, res); +} + + +void m68000_base_device_ops::m68k_op_subx_32_mm(m68000_base_device* mc68kcpu) +{ + UINT32 src = OPER_AY_PD_32(mc68kcpu); + UINT32 ea = EA_AX_PD_32(mc68kcpu); + UINT32 dst = m68ki_read_32((mc68kcpu), ea); + UINT32 res = dst - src - XFLAG_AS_1(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->x_flag = (mc68kcpu)->c_flag = CFLAG_SUB_32(src, dst, res); + (mc68kcpu)->v_flag = VFLAG_SUB_32(src, dst, res); + + res = MASK_OUT_ABOVE_32(res); + (mc68kcpu)->not_z_flag |= res; + + m68ki_write_32((mc68kcpu), ea, res); +} + + +void m68000_base_device_ops::m68k_op_swap_32(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DY(mc68kcpu); + + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_32(*r_dst<<16); + *r_dst = (*r_dst>>16) | (mc68kcpu)->not_z_flag; + + (mc68kcpu)->not_z_flag = *r_dst; + (mc68kcpu)->n_flag = NFLAG_32(*r_dst); + (mc68kcpu)->c_flag = CFLAG_CLEAR; + (mc68kcpu)->v_flag = VFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_tas_8_d(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &DY(mc68kcpu); + + (mc68kcpu)->not_z_flag = MASK_OUT_ABOVE_8(*r_dst); + (mc68kcpu)->n_flag = NFLAG_8(*r_dst); + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + *r_dst |= 0x80; +} + + +void m68000_base_device_ops::m68k_op_tas_8_ai(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_AI_8(mc68kcpu); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + + (mc68kcpu)->not_z_flag = dst; + (mc68kcpu)->n_flag = NFLAG_8(dst); + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + + /* On the 68000 and 68010, the TAS instruction uses a unique bus cycle that may have + side effects (e.g. delaying DMA) or may fail to write back at all depending on the + bus implementation. + In particular, the Genesis/Megadrive games Gargoyles and Ex-Mutants need the TAS + to fail to write back in order to function properly. */ + if (CPU_TYPE_IS_010_LESS((mc68kcpu)->cpu_type) && !(mc68kcpu)->tas_write_callback.isnull()) + ((mc68kcpu)->tas_write_callback)(*(mc68kcpu)->program, ea, dst | 0x80, 0xff); + else + m68ki_write_8((mc68kcpu), ea, dst | 0x80); +} + + +void m68000_base_device_ops::m68k_op_tas_8_pi(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_PI_8(mc68kcpu); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + + (mc68kcpu)->not_z_flag = dst; + (mc68kcpu)->n_flag = NFLAG_8(dst); + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + + /* On the 68000 and 68010, the TAS instruction uses a unique bus cycle that may have + side effects (e.g. delaying DMA) or may fail to write back at all depending on the + bus implementation. + In particular, the Genesis/Megadrive games Gargoyles and Ex-Mutants need the TAS + to fail to write back in order to function properly. */ + if (CPU_TYPE_IS_010_LESS((mc68kcpu)->cpu_type) && !(mc68kcpu)->tas_write_callback.isnull()) + ((mc68kcpu)->tas_write_callback)(*(mc68kcpu)->program, ea, dst | 0x80, 0xff); + else + m68ki_write_8((mc68kcpu), ea, dst | 0x80); +} + + +void m68000_base_device_ops::m68k_op_tas_8_pi7(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_A7_PI_8(mc68kcpu); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + + (mc68kcpu)->not_z_flag = dst; + (mc68kcpu)->n_flag = NFLAG_8(dst); + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + + /* On the 68000 and 68010, the TAS instruction uses a unique bus cycle that may have + side effects (e.g. delaying DMA) or may fail to write back at all depending on the + bus implementation. + In particular, the Genesis/Megadrive games Gargoyles and Ex-Mutants need the TAS + to fail to write back in order to function properly. */ + if (CPU_TYPE_IS_010_LESS((mc68kcpu)->cpu_type) && !(mc68kcpu)->tas_write_callback.isnull()) + ((mc68kcpu)->tas_write_callback)(*(mc68kcpu)->program, ea, dst | 0x80, 0xff); + else + m68ki_write_8((mc68kcpu), ea, dst | 0x80); +} + + +void m68000_base_device_ops::m68k_op_tas_8_pd(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_PD_8(mc68kcpu); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + + (mc68kcpu)->not_z_flag = dst; + (mc68kcpu)->n_flag = NFLAG_8(dst); + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + + /* On the 68000 and 68010, the TAS instruction uses a unique bus cycle that may have + side effects (e.g. delaying DMA) or may fail to write back at all depending on the + bus implementation. + In particular, the Genesis/Megadrive games Gargoyles and Ex-Mutants need the TAS + to fail to write back in order to function properly. */ + if (CPU_TYPE_IS_010_LESS((mc68kcpu)->cpu_type) && !(mc68kcpu)->tas_write_callback.isnull()) + ((mc68kcpu)->tas_write_callback)(*(mc68kcpu)->program, ea, dst | 0x80, 0xff); + else + m68ki_write_8((mc68kcpu), ea, dst | 0x80); +} + + +void m68000_base_device_ops::m68k_op_tas_8_pd7(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_A7_PD_8(mc68kcpu); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + + (mc68kcpu)->not_z_flag = dst; + (mc68kcpu)->n_flag = NFLAG_8(dst); + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + + /* On the 68000 and 68010, the TAS instruction uses a unique bus cycle that may have + side effects (e.g. delaying DMA) or may fail to write back at all depending on the + bus implementation. + In particular, the Genesis/Megadrive games Gargoyles and Ex-Mutants need the TAS + to fail to write back in order to function properly. */ + if (CPU_TYPE_IS_010_LESS((mc68kcpu)->cpu_type) && !(mc68kcpu)->tas_write_callback.isnull()) + ((mc68kcpu)->tas_write_callback)(*(mc68kcpu)->program, ea, dst | 0x80, 0xff); + else + m68ki_write_8((mc68kcpu), ea, dst | 0x80); +} + + +void m68000_base_device_ops::m68k_op_tas_8_di(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_DI_8(mc68kcpu); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + + (mc68kcpu)->not_z_flag = dst; + (mc68kcpu)->n_flag = NFLAG_8(dst); + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + + /* On the 68000 and 68010, the TAS instruction uses a unique bus cycle that may have + side effects (e.g. delaying DMA) or may fail to write back at all depending on the + bus implementation. + In particular, the Genesis/Megadrive games Gargoyles and Ex-Mutants need the TAS + to fail to write back in order to function properly. */ + if (CPU_TYPE_IS_010_LESS((mc68kcpu)->cpu_type) && !(mc68kcpu)->tas_write_callback.isnull()) + ((mc68kcpu)->tas_write_callback)(*(mc68kcpu)->program, ea, dst | 0x80, 0xff); + else + m68ki_write_8((mc68kcpu), ea, dst | 0x80); +} + + +void m68000_base_device_ops::m68k_op_tas_8_ix(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AY_IX_8(mc68kcpu); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + + (mc68kcpu)->not_z_flag = dst; + (mc68kcpu)->n_flag = NFLAG_8(dst); + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + + /* On the 68000 and 68010, the TAS instruction uses a unique bus cycle that may have + side effects (e.g. delaying DMA) or may fail to write back at all depending on the + bus implementation. + In particular, the Genesis/Megadrive games Gargoyles and Ex-Mutants need the TAS + to fail to write back in order to function properly. */ + if (CPU_TYPE_IS_010_LESS((mc68kcpu)->cpu_type) && !(mc68kcpu)->tas_write_callback.isnull()) + ((mc68kcpu)->tas_write_callback)(*(mc68kcpu)->program, ea, dst | 0x80, 0xff); + else + m68ki_write_8((mc68kcpu), ea, dst | 0x80); +} + + +void m68000_base_device_ops::m68k_op_tas_8_aw(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AW_8(mc68kcpu); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + + (mc68kcpu)->not_z_flag = dst; + (mc68kcpu)->n_flag = NFLAG_8(dst); + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + + /* On the 68000 and 68010, the TAS instruction uses a unique bus cycle that may have + side effects (e.g. delaying DMA) or may fail to write back at all depending on the + bus implementation. + In particular, the Genesis/Megadrive games Gargoyles and Ex-Mutants need the TAS + to fail to write back in order to function properly. */ + if (CPU_TYPE_IS_010_LESS((mc68kcpu)->cpu_type) && !(mc68kcpu)->tas_write_callback.isnull()) + ((mc68kcpu)->tas_write_callback)(*(mc68kcpu)->program, ea, dst | 0x80, 0xff); + else + m68ki_write_8((mc68kcpu), ea, dst | 0x80); +} + + +void m68000_base_device_ops::m68k_op_tas_8_al(m68000_base_device* mc68kcpu) +{ + UINT32 ea = EA_AL_8(mc68kcpu); + UINT32 dst = m68ki_read_8((mc68kcpu), ea); + + (mc68kcpu)->not_z_flag = dst; + (mc68kcpu)->n_flag = NFLAG_8(dst); + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + + /* On the 68000 and 68010, the TAS instruction uses a unique bus cycle that may have + side effects (e.g. delaying DMA) or may fail to write back at all depending on the + bus implementation. + In particular, the Genesis/Megadrive games Gargoyles and Ex-Mutants need the TAS + to fail to write back in order to function properly. */ + if (CPU_TYPE_IS_010_LESS((mc68kcpu)->cpu_type) && !(mc68kcpu)->tas_write_callback.isnull()) + ((mc68kcpu)->tas_write_callback)(*(mc68kcpu)->program, ea, dst | 0x80, 0xff); + else + m68ki_write_8((mc68kcpu), ea, dst | 0x80); +} + + +void m68000_base_device_ops::m68k_op_trap(m68000_base_device* mc68kcpu) +{ + /* Trap#n stacks exception frame type 0 */ + m68ki_exception_trapN((mc68kcpu), EXCEPTION_TRAP_BASE + ((mc68kcpu)->ir & 0xf)); /* HJB 990403 */ +} + + +void m68000_base_device_ops::m68k_op_trapt(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + m68ki_exception_trap((mc68kcpu), EXCEPTION_TRAPV); /* HJB 990403 */ + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_trapt_16(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + m68ki_exception_trap((mc68kcpu), EXCEPTION_TRAPV); /* HJB 990403 */ + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_trapt_32(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + m68ki_exception_trap((mc68kcpu), EXCEPTION_TRAPV); /* HJB 990403 */ + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_trapf(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_trapf_16(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + REG_PC(mc68kcpu) += 2; + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_trapf_32(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + REG_PC(mc68kcpu) += 4; + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_traphi(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + if(COND_HI(mc68kcpu)) + m68ki_exception_trap((mc68kcpu), EXCEPTION_TRAPV); /* HJB 990403 */ + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_trapls(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + if(COND_LS(mc68kcpu)) + m68ki_exception_trap((mc68kcpu), EXCEPTION_TRAPV); /* HJB 990403 */ + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_trapcc(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + if(COND_CC(mc68kcpu)) + m68ki_exception_trap((mc68kcpu), EXCEPTION_TRAPV); /* HJB 990403 */ + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_trapcs(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + if(COND_CS(mc68kcpu)) + m68ki_exception_trap((mc68kcpu), EXCEPTION_TRAPV); /* HJB 990403 */ + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_trapne(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + if(COND_NE(mc68kcpu)) + m68ki_exception_trap((mc68kcpu), EXCEPTION_TRAPV); /* HJB 990403 */ + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_trapeq(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + if(COND_EQ(mc68kcpu)) + m68ki_exception_trap((mc68kcpu), EXCEPTION_TRAPV); /* HJB 990403 */ + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_trapvc(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + if(COND_VC(mc68kcpu)) + m68ki_exception_trap((mc68kcpu), EXCEPTION_TRAPV); /* HJB 990403 */ + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_trapvs(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + if(COND_VS(mc68kcpu)) + m68ki_exception_trap((mc68kcpu), EXCEPTION_TRAPV); /* HJB 990403 */ + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_trappl(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + if(COND_PL(mc68kcpu)) + m68ki_exception_trap((mc68kcpu), EXCEPTION_TRAPV); /* HJB 990403 */ + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_trapmi(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + if(COND_MI(mc68kcpu)) + m68ki_exception_trap((mc68kcpu), EXCEPTION_TRAPV); /* HJB 990403 */ + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_trapge(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + if(COND_GE(mc68kcpu)) + m68ki_exception_trap((mc68kcpu), EXCEPTION_TRAPV); /* HJB 990403 */ + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_traplt(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + if(COND_LT(mc68kcpu)) + m68ki_exception_trap((mc68kcpu), EXCEPTION_TRAPV); /* HJB 990403 */ + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_trapgt(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + if(COND_GT(mc68kcpu)) + m68ki_exception_trap((mc68kcpu), EXCEPTION_TRAPV); /* HJB 990403 */ + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_traple(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + if(COND_LE(mc68kcpu)) + m68ki_exception_trap((mc68kcpu), EXCEPTION_TRAPV); /* HJB 990403 */ + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_traphi_16(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + if(COND_HI(mc68kcpu)) + { + m68ki_exception_trap((mc68kcpu), EXCEPTION_TRAPV); /* HJB 990403 */ + return; + } + REG_PC(mc68kcpu) += 2; + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_trapls_16(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + if(COND_LS(mc68kcpu)) + { + m68ki_exception_trap((mc68kcpu), EXCEPTION_TRAPV); /* HJB 990403 */ + return; + } + REG_PC(mc68kcpu) += 2; + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_trapcc_16(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + if(COND_CC(mc68kcpu)) + { + m68ki_exception_trap((mc68kcpu), EXCEPTION_TRAPV); /* HJB 990403 */ + return; + } + REG_PC(mc68kcpu) += 2; + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_trapcs_16(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + if(COND_CS(mc68kcpu)) + { + m68ki_exception_trap((mc68kcpu), EXCEPTION_TRAPV); /* HJB 990403 */ + return; + } + REG_PC(mc68kcpu) += 2; + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_trapne_16(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + if(COND_NE(mc68kcpu)) + { + m68ki_exception_trap((mc68kcpu), EXCEPTION_TRAPV); /* HJB 990403 */ + return; + } + REG_PC(mc68kcpu) += 2; + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_trapeq_16(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + if(COND_EQ(mc68kcpu)) + { + m68ki_exception_trap((mc68kcpu), EXCEPTION_TRAPV); /* HJB 990403 */ + return; + } + REG_PC(mc68kcpu) += 2; + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_trapvc_16(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + if(COND_VC(mc68kcpu)) + { + m68ki_exception_trap((mc68kcpu), EXCEPTION_TRAPV); /* HJB 990403 */ + return; + } + REG_PC(mc68kcpu) += 2; + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_trapvs_16(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + if(COND_VS(mc68kcpu)) + { + m68ki_exception_trap((mc68kcpu), EXCEPTION_TRAPV); /* HJB 990403 */ + return; + } + REG_PC(mc68kcpu) += 2; + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_trappl_16(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + if(COND_PL(mc68kcpu)) + { + m68ki_exception_trap((mc68kcpu), EXCEPTION_TRAPV); /* HJB 990403 */ + return; + } + REG_PC(mc68kcpu) += 2; + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_trapmi_16(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + if(COND_MI(mc68kcpu)) + { + m68ki_exception_trap((mc68kcpu), EXCEPTION_TRAPV); /* HJB 990403 */ + return; + } + REG_PC(mc68kcpu) += 2; + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_trapge_16(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + if(COND_GE(mc68kcpu)) + { + m68ki_exception_trap((mc68kcpu), EXCEPTION_TRAPV); /* HJB 990403 */ + return; + } + REG_PC(mc68kcpu) += 2; + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_traplt_16(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + if(COND_LT(mc68kcpu)) + { + m68ki_exception_trap((mc68kcpu), EXCEPTION_TRAPV); /* HJB 990403 */ + return; + } + REG_PC(mc68kcpu) += 2; + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_trapgt_16(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + if(COND_GT(mc68kcpu)) + { + m68ki_exception_trap((mc68kcpu), EXCEPTION_TRAPV); /* HJB 990403 */ + return; + } + REG_PC(mc68kcpu) += 2; + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_traple_16(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + if(COND_LE(mc68kcpu)) + { + m68ki_exception_trap((mc68kcpu), EXCEPTION_TRAPV); /* HJB 990403 */ + return; + } + REG_PC(mc68kcpu) += 2; + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_traphi_32(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + if(COND_HI(mc68kcpu)) + { + m68ki_exception_trap((mc68kcpu), EXCEPTION_TRAPV); /* HJB 990403 */ + return; + } + REG_PC(mc68kcpu) += 4; + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_trapls_32(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + if(COND_LS(mc68kcpu)) + { + m68ki_exception_trap((mc68kcpu), EXCEPTION_TRAPV); /* HJB 990403 */ + return; + } + REG_PC(mc68kcpu) += 4; + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_trapcc_32(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + if(COND_CC(mc68kcpu)) + { + m68ki_exception_trap((mc68kcpu), EXCEPTION_TRAPV); /* HJB 990403 */ + return; + } + REG_PC(mc68kcpu) += 4; + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_trapcs_32(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + if(COND_CS(mc68kcpu)) + { + m68ki_exception_trap((mc68kcpu), EXCEPTION_TRAPV); /* HJB 990403 */ + return; + } + REG_PC(mc68kcpu) += 4; + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_trapne_32(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + if(COND_NE(mc68kcpu)) + { + m68ki_exception_trap((mc68kcpu), EXCEPTION_TRAPV); /* HJB 990403 */ + return; + } + REG_PC(mc68kcpu) += 4; + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_trapeq_32(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + if(COND_EQ(mc68kcpu)) + { + m68ki_exception_trap((mc68kcpu), EXCEPTION_TRAPV); /* HJB 990403 */ + return; + } + REG_PC(mc68kcpu) += 4; + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_trapvc_32(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + if(COND_VC(mc68kcpu)) + { + m68ki_exception_trap((mc68kcpu), EXCEPTION_TRAPV); /* HJB 990403 */ + return; + } + REG_PC(mc68kcpu) += 4; + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_trapvs_32(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + if(COND_VS(mc68kcpu)) + { + m68ki_exception_trap((mc68kcpu), EXCEPTION_TRAPV); /* HJB 990403 */ + return; + } + REG_PC(mc68kcpu) += 4; + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_trappl_32(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + if(COND_PL(mc68kcpu)) + { + m68ki_exception_trap((mc68kcpu), EXCEPTION_TRAPV); /* HJB 990403 */ + return; + } + REG_PC(mc68kcpu) += 4; + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_trapmi_32(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + if(COND_MI(mc68kcpu)) + { + m68ki_exception_trap((mc68kcpu), EXCEPTION_TRAPV); /* HJB 990403 */ + return; + } + REG_PC(mc68kcpu) += 4; + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_trapge_32(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + if(COND_GE(mc68kcpu)) + { + m68ki_exception_trap((mc68kcpu), EXCEPTION_TRAPV); /* HJB 990403 */ + return; + } + REG_PC(mc68kcpu) += 4; + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_traplt_32(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + if(COND_LT(mc68kcpu)) + { + m68ki_exception_trap((mc68kcpu), EXCEPTION_TRAPV); /* HJB 990403 */ + return; + } + REG_PC(mc68kcpu) += 4; + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_trapgt_32(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + if(COND_GT(mc68kcpu)) + { + m68ki_exception_trap((mc68kcpu), EXCEPTION_TRAPV); /* HJB 990403 */ + return; + } + REG_PC(mc68kcpu) += 4; + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_traple_32(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + if(COND_LE(mc68kcpu)) + { + m68ki_exception_trap((mc68kcpu), EXCEPTION_TRAPV); /* HJB 990403 */ + return; + } + REG_PC(mc68kcpu) += 4; + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_trapv(m68000_base_device* mc68kcpu) +{ + if(COND_VC(mc68kcpu)) + { + return; + } + m68ki_exception_trap((mc68kcpu), EXCEPTION_TRAPV); /* HJB 990403 */ +} + + +void m68000_base_device_ops::m68k_op_tst_8_d(m68000_base_device* mc68kcpu) +{ + UINT32 res = MASK_OUT_ABOVE_8(DY(mc68kcpu)); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_tst_8_ai(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_AI_8(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_tst_8_pi(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_PI_8(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_tst_8_pi7(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_A7_PI_8(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_tst_8_pd(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_PD_8(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_tst_8_pd7(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_A7_PD_8(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_tst_8_di(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_DI_8(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_tst_8_ix(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_IX_8(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_tst_8_aw(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AW_8(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_tst_8_al(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AL_8(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_tst_8_pcdi(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 res = OPER_PCDI_8(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_tst_8_pcix(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 res = OPER_PCIX_8(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_tst_8_i(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 res = OPER_I_8(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_8(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_tst_16_d(m68000_base_device* mc68kcpu) +{ + UINT32 res = MASK_OUT_ABOVE_16(DY(mc68kcpu)); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_tst_16_a(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 res = MAKE_INT_16(AY(mc68kcpu)); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_tst_16_ai(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_AI_16(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_tst_16_pi(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_PI_16(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_tst_16_pd(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_PD_16(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_tst_16_di(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_DI_16(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_tst_16_ix(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_IX_16(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_tst_16_aw(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AW_16(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_tst_16_al(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AL_16(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_tst_16_pcdi(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 res = OPER_PCDI_16(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_tst_16_pcix(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 res = OPER_PCIX_16(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_tst_16_i(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 res = OPER_I_16(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_16(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_tst_32_d(m68000_base_device* mc68kcpu) +{ + UINT32 res = DY(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_tst_32_a(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 res = AY(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_tst_32_ai(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_AI_32(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_tst_32_pi(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_PI_32(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_tst_32_pd(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_PD_32(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_tst_32_di(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_DI_32(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_tst_32_ix(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AY_IX_32(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_tst_32_aw(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AW_32(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_tst_32_al(m68000_base_device* mc68kcpu) +{ + UINT32 res = OPER_AL_32(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; +} + + +void m68000_base_device_ops::m68k_op_tst_32_pcdi(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 res = OPER_PCDI_32(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_tst_32_pcix(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 res = OPER_PCIX_32(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_tst_32_i(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 res = OPER_I_32(mc68kcpu); + + (mc68kcpu)->n_flag = NFLAG_32(res); + (mc68kcpu)->not_z_flag = res; + (mc68kcpu)->v_flag = VFLAG_CLEAR; + (mc68kcpu)->c_flag = CFLAG_CLEAR; + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_unlk_32_a7(m68000_base_device* mc68kcpu) +{ + REG_A(mc68kcpu)[7] = m68ki_read_32((mc68kcpu), REG_A(mc68kcpu)[7]); +} + + +void m68000_base_device_ops::m68k_op_unlk_32(m68000_base_device* mc68kcpu) +{ + UINT32* r_dst = &AY(mc68kcpu); + + REG_A(mc68kcpu)[7] = *r_dst; + *r_dst = m68ki_pull_32(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_unpk_16_rr(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + /* Note: DX(mc68kcpu) and DY(mc68kcpu) are reversed in Motorola's docs */ + UINT32 src = DY(mc68kcpu); + UINT32* r_dst = &DX(mc68kcpu); + + *r_dst = MASK_OUT_BELOW_16(*r_dst) | (((((src << 4) & 0x0f00) | (src & 0x000f)) + OPER_I_16(mc68kcpu)) & 0xffff); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_unpk_16_mm_ax7(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + /* Note: AX and AY are reversed in Motorola's docs */ + UINT32 src = OPER_AY_PD_8(mc68kcpu); + UINT32 ea_dst; + + src = (((src << 4) & 0x0f00) | (src & 0x000f)) + OPER_I_16(mc68kcpu); + ea_dst = EA_A7_PD_8(mc68kcpu); + m68ki_write_8((mc68kcpu), ea_dst, (src >> 8) & 0xff); + ea_dst = EA_A7_PD_8(mc68kcpu); + m68ki_write_8((mc68kcpu), ea_dst, src & 0xff); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_unpk_16_mm_ay7(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + /* Note: AX and AY are reversed in Motorola's docs */ + UINT32 src = OPER_A7_PD_8(mc68kcpu); + UINT32 ea_dst; + + src = (((src << 4) & 0x0f00) | (src & 0x000f)) + OPER_I_16(mc68kcpu); + ea_dst = EA_AX_PD_8(mc68kcpu); + m68ki_write_8((mc68kcpu), ea_dst, (src >> 8) & 0xff); + ea_dst = EA_AX_PD_8(mc68kcpu); + m68ki_write_8((mc68kcpu), ea_dst, src & 0xff); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_unpk_16_mm_axy7(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + UINT32 src = OPER_A7_PD_8(mc68kcpu); + UINT32 ea_dst; + + src = (((src << 4) & 0x0f00) | (src & 0x000f)) + OPER_I_16(mc68kcpu); + ea_dst = EA_A7_PD_8(mc68kcpu); + m68ki_write_8((mc68kcpu), ea_dst, (src >> 8) & 0xff); + ea_dst = EA_A7_PD_8(mc68kcpu); + m68ki_write_8((mc68kcpu), ea_dst, src & 0xff); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_unpk_16_mm(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_EC020_PLUS((mc68kcpu)->cpu_type)) + { + /* Note: AX and AY are reversed in Motorola's docs */ + UINT32 src = OPER_AY_PD_8(mc68kcpu); + UINT32 ea_dst; + + src = (((src << 4) & 0x0f00) | (src & 0x000f)) + OPER_I_16(mc68kcpu); + ea_dst = EA_AX_PD_8(mc68kcpu); + m68ki_write_8((mc68kcpu), ea_dst, (src >> 8) & 0xff); + ea_dst = EA_AX_PD_8(mc68kcpu); + m68ki_write_8((mc68kcpu), ea_dst, src & 0xff); + return; + } + m68ki_exception_illegal(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_cinv_32(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_040_PLUS((mc68kcpu)->cpu_type)) + { + UINT16 ir = mc68kcpu->ir; + UINT8 cache = (ir >> 6) & 3; +// UINT8 scope = (ir >> 3) & 3; +// logerror("68040 %s: pc=%08x ir=%04x cache=%d scope=%d register=%d\n", ir & 0x0020 ? "cpush" : "cinv", REG_PPC(mc68kcpu), ir, cache, scope, ir & 7); + switch (cache) + { + case 2: + case 3: + // we invalidate/push the whole instruction cache + m68ki_ic_clear(mc68kcpu); + } + return; + } + m68ki_exception_1111(mc68kcpu); +} + + +void m68000_base_device_ops::m68k_op_cpush_32(m68000_base_device* mc68kcpu) +{ + if(CPU_TYPE_IS_040_PLUS((mc68kcpu)->cpu_type)) + { + logerror("%s at %08x: called unimplemented instruction %04x (cpush)\n", + (mc68kcpu)->tag(), REG_PC(mc68kcpu) - 2, (mc68kcpu)->ir); + return; + } + m68ki_exception_1111(mc68kcpu); +} + + +/* ======================================================================== */ +/* ============================== END OF FILE ============================= */ +/* ======================================================================== */ + + +/* ======================================================================== */ +/* ========================= OPCODE TABLE BUILDER ========================= */ +/* ======================================================================== */ + +#include "m68kops.h" + +#define NUM_CPU_TYPES 7 + +void (*m68ki_instruction_jump_table[NUM_CPU_TYPES][0x10000])(m68000_base_device *m68k); /* opcode handler jump table */ +unsigned char m68ki_cycles[NUM_CPU_TYPES][0x10000]; /* Cycles used by CPU type */ + +/* This is used to generate the opcode handler jump table */ +struct opcode_handler_struct +{ + void (*opcode_handler)(m68000_base_device *m68k); /* handler function */ + unsigned int mask; /* mask on opcode */ + unsigned int match; /* what to match after masking */ + unsigned char cycles[NUM_CPU_TYPES]; /* cycles each cpu type takes */ +}; + + +/* Opcode handler table */ +static const opcode_handler_struct m68k_opcode_handler_table[] = +{ +/* function mask match 000 010 020 040 */ + + + {m68000_base_device_ops::m68k_op_1010, 0xf000, 0xa000, { 4, 4, 4, 4, 4, 4, 4}}, + {m68000_base_device_ops::m68k_op_1111, 0xf000, 0xf000, { 4, 4, 4, 4, 4, 4, 4}}, + {m68000_base_device_ops::m68k_op_moveq_32, 0xf100, 0x7000, { 4, 4, 2, 2, 2, 2, 2}}, + {m68000_base_device_ops::m68k_op_cpbcc_32, 0xf180, 0xf080, {255, 255, 4, 4, 255, 255, 255}}, + {m68000_base_device_ops::m68k_op_cpgen_32, 0xf1c0, 0xf000, {255, 255, 4, 4, 255, 255, 255}}, + {m68000_base_device_ops::m68k_op_cpscc_32, 0xf1c0, 0xf040, {255, 255, 4, 4, 255, 255, 255}}, + {m68000_base_device_ops::m68k_op_pmmu_32, 0xfe00, 0xf000, {255, 255, 8, 8, 8, 8, 8}}, + {m68000_base_device_ops::m68k_op_bra_8, 0xff00, 0x6000, { 10, 10, 10, 10, 10, 10, 10}}, + {m68000_base_device_ops::m68k_op_bsr_8, 0xff00, 0x6100, { 18, 18, 7, 7, 7, 7, 7}}, + {m68000_base_device_ops::m68k_op_bhi_8, 0xff00, 0x6200, { 10, 10, 6, 6, 6, 6, 6}}, + {m68000_base_device_ops::m68k_op_bls_8, 0xff00, 0x6300, { 10, 10, 6, 6, 6, 6, 6}}, + {m68000_base_device_ops::m68k_op_bcc_8, 0xff00, 0x6400, { 10, 10, 6, 6, 6, 6, 6}}, + {m68000_base_device_ops::m68k_op_bcs_8, 0xff00, 0x6500, { 10, 10, 6, 6, 6, 6, 6}}, + {m68000_base_device_ops::m68k_op_bne_8, 0xff00, 0x6600, { 10, 10, 6, 6, 6, 6, 6}}, + {m68000_base_device_ops::m68k_op_beq_8, 0xff00, 0x6700, { 10, 10, 6, 6, 6, 6, 6}}, + {m68000_base_device_ops::m68k_op_bvc_8, 0xff00, 0x6800, { 10, 10, 6, 6, 6, 6, 6}}, + {m68000_base_device_ops::m68k_op_bvs_8, 0xff00, 0x6900, { 10, 10, 6, 6, 6, 6, 6}}, + {m68000_base_device_ops::m68k_op_bpl_8, 0xff00, 0x6a00, { 10, 10, 6, 6, 6, 6, 6}}, + {m68000_base_device_ops::m68k_op_bmi_8, 0xff00, 0x6b00, { 10, 10, 6, 6, 6, 6, 6}}, + {m68000_base_device_ops::m68k_op_bge_8, 0xff00, 0x6c00, { 10, 10, 6, 6, 6, 6, 6}}, + {m68000_base_device_ops::m68k_op_blt_8, 0xff00, 0x6d00, { 10, 10, 6, 6, 6, 6, 6}}, + {m68000_base_device_ops::m68k_op_bgt_8, 0xff00, 0x6e00, { 10, 10, 6, 6, 6, 6, 6}}, + {m68000_base_device_ops::m68k_op_ble_8, 0xff00, 0x6f00, { 10, 10, 6, 6, 6, 6, 6}}, + {m68000_base_device_ops::m68k_op_040fpu0_32, 0xff00, 0xf200, {255, 255, 0, 0, 0, 0, 255}}, + {m68000_base_device_ops::m68k_op_040fpu1_32, 0xff00, 0xf300, {255, 255, 0, 0, 0, 0, 255}}, + {m68000_base_device_ops::m68k_op_cinv_32, 0xff20, 0xf400, {255, 255, 255, 255, 16, 255, 255}}, + {m68000_base_device_ops::m68k_op_cpush_32, 0xff20, 0xf420, {255, 255, 255, 255, 16, 255, 255}}, + {m68000_base_device_ops::m68k_op_btst_32_r_d, 0xf1f8, 0x0100, { 6, 6, 4, 4, 4, 4, 4}}, + {m68000_base_device_ops::m68k_op_movep_16_er, 0xf1f8, 0x0108, { 16, 16, 12, 12, 12, 12, 12}}, + {m68000_base_device_ops::m68k_op_btst_8_r_ai, 0xf1f8, 0x0110, { 8, 8, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_btst_8_r_pi, 0xf1f8, 0x0118, { 8, 8, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_btst_8_r_pd, 0xf1f8, 0x0120, { 10, 10, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_btst_8_r_di, 0xf1f8, 0x0128, { 12, 12, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_btst_8_r_ix, 0xf1f8, 0x0130, { 14, 14, 11, 11, 11, 11, 4}}, + {m68000_base_device_ops::m68k_op_bchg_32_r_d, 0xf1f8, 0x0140, { 8, 8, 4, 4, 4, 4, 4}}, + {m68000_base_device_ops::m68k_op_movep_32_er, 0xf1f8, 0x0148, { 24, 24, 18, 18, 18, 18, 18}}, + {m68000_base_device_ops::m68k_op_bchg_8_r_ai, 0xf1f8, 0x0150, { 12, 12, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_bchg_8_r_pi, 0xf1f8, 0x0158, { 12, 12, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_bchg_8_r_pd, 0xf1f8, 0x0160, { 14, 14, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_bchg_8_r_di, 0xf1f8, 0x0168, { 16, 16, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_bchg_8_r_ix, 0xf1f8, 0x0170, { 18, 18, 11, 11, 11, 11, 4}}, + {m68000_base_device_ops::m68k_op_bclr_32_r_d, 0xf1f8, 0x0180, { 10, 10, 4, 4, 4, 4, 4}}, + {m68000_base_device_ops::m68k_op_movep_16_re, 0xf1f8, 0x0188, { 16, 16, 11, 11, 11, 11, 11}}, + {m68000_base_device_ops::m68k_op_bclr_8_r_ai, 0xf1f8, 0x0190, { 12, 14, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_bclr_8_r_pi, 0xf1f8, 0x0198, { 12, 14, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_bclr_8_r_pd, 0xf1f8, 0x01a0, { 14, 16, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_bclr_8_r_di, 0xf1f8, 0x01a8, { 16, 18, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_bclr_8_r_ix, 0xf1f8, 0x01b0, { 18, 20, 11, 11, 11, 11, 4}}, + {m68000_base_device_ops::m68k_op_bset_32_r_d, 0xf1f8, 0x01c0, { 8, 8, 4, 4, 4, 4, 4}}, + {m68000_base_device_ops::m68k_op_movep_32_re, 0xf1f8, 0x01c8, { 24, 24, 17, 17, 17, 17, 17}}, + {m68000_base_device_ops::m68k_op_bset_8_r_ai, 0xf1f8, 0x01d0, { 12, 12, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_bset_8_r_pi, 0xf1f8, 0x01d8, { 12, 12, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_bset_8_r_pd, 0xf1f8, 0x01e0, { 14, 14, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_bset_8_r_di, 0xf1f8, 0x01e8, { 16, 16, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_bset_8_r_ix, 0xf1f8, 0x01f0, { 18, 18, 11, 11, 11, 11, 4}}, + {m68000_base_device_ops::m68k_op_move_8_d_d, 0xf1f8, 0x1000, { 4, 4, 2, 2, 2, 2, 2}}, + {m68000_base_device_ops::m68k_op_move_8_d_ai, 0xf1f8, 0x1010, { 8, 8, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_move_8_d_pi, 0xf1f8, 0x1018, { 8, 8, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_move_8_d_pd, 0xf1f8, 0x1020, { 10, 10, 7, 7, 7, 7, 2}}, + {m68000_base_device_ops::m68k_op_move_8_d_di, 0xf1f8, 0x1028, { 12, 12, 7, 7, 7, 7, 2}}, + {m68000_base_device_ops::m68k_op_move_8_d_ix, 0xf1f8, 0x1030, { 14, 14, 9, 9, 9, 9, 2}}, + {m68000_base_device_ops::m68k_op_move_8_ai_d, 0xf1f8, 0x1080, { 8, 8, 4, 4, 4, 4, 4}}, + {m68000_base_device_ops::m68k_op_move_8_ai_ai, 0xf1f8, 0x1090, { 12, 12, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_move_8_ai_pi, 0xf1f8, 0x1098, { 12, 12, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_move_8_ai_pd, 0xf1f8, 0x10a0, { 14, 14, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_move_8_ai_di, 0xf1f8, 0x10a8, { 16, 16, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_move_8_ai_ix, 0xf1f8, 0x10b0, { 18, 18, 11, 11, 11, 11, 4}}, + {m68000_base_device_ops::m68k_op_move_8_pi_d, 0xf1f8, 0x10c0, { 8, 8, 4, 4, 4, 4, 4}}, + {m68000_base_device_ops::m68k_op_move_8_pi_ai, 0xf1f8, 0x10d0, { 12, 12, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_move_8_pi_pi, 0xf1f8, 0x10d8, { 12, 12, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_move_8_pi_pd, 0xf1f8, 0x10e0, { 14, 14, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_move_8_pi_di, 0xf1f8, 0x10e8, { 16, 16, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_move_8_pi_ix, 0xf1f8, 0x10f0, { 18, 18, 11, 11, 11, 11, 4}}, + {m68000_base_device_ops::m68k_op_move_8_pd_d, 0xf1f8, 0x1100, { 8, 8, 5, 5, 5, 5, 5}}, + {m68000_base_device_ops::m68k_op_move_8_pd_ai, 0xf1f8, 0x1110, { 12, 12, 9, 9, 9, 9, 5}}, + {m68000_base_device_ops::m68k_op_move_8_pd_pi, 0xf1f8, 0x1118, { 12, 12, 9, 9, 9, 9, 5}}, + {m68000_base_device_ops::m68k_op_move_8_pd_pd, 0xf1f8, 0x1120, { 14, 14, 10, 10, 10, 10, 5}}, + {m68000_base_device_ops::m68k_op_move_8_pd_di, 0xf1f8, 0x1128, { 16, 16, 10, 10, 10, 10, 5}}, + {m68000_base_device_ops::m68k_op_move_8_pd_ix, 0xf1f8, 0x1130, { 18, 18, 12, 12, 12, 12, 5}}, + {m68000_base_device_ops::m68k_op_move_8_di_d, 0xf1f8, 0x1140, { 12, 12, 5, 5, 5, 5, 5}}, + {m68000_base_device_ops::m68k_op_move_8_di_ai, 0xf1f8, 0x1150, { 16, 16, 9, 9, 9, 9, 5}}, + {m68000_base_device_ops::m68k_op_move_8_di_pi, 0xf1f8, 0x1158, { 16, 16, 9, 9, 9, 9, 5}}, + {m68000_base_device_ops::m68k_op_move_8_di_pd, 0xf1f8, 0x1160, { 18, 18, 10, 10, 10, 10, 5}}, + {m68000_base_device_ops::m68k_op_move_8_di_di, 0xf1f8, 0x1168, { 20, 20, 10, 10, 10, 10, 5}}, + {m68000_base_device_ops::m68k_op_move_8_di_ix, 0xf1f8, 0x1170, { 22, 22, 12, 12, 12, 12, 5}}, + {m68000_base_device_ops::m68k_op_move_8_ix_d, 0xf1f8, 0x1180, { 14, 14, 7, 7, 7, 7, 7}}, + {m68000_base_device_ops::m68k_op_move_8_ix_ai, 0xf1f8, 0x1190, { 18, 18, 11, 11, 11, 11, 7}}, + {m68000_base_device_ops::m68k_op_move_8_ix_pi, 0xf1f8, 0x1198, { 18, 18, 11, 11, 11, 11, 7}}, + {m68000_base_device_ops::m68k_op_move_8_ix_pd, 0xf1f8, 0x11a0, { 20, 20, 12, 12, 12, 12, 7}}, + {m68000_base_device_ops::m68k_op_move_8_ix_di, 0xf1f8, 0x11a8, { 22, 22, 12, 12, 12, 12, 7}}, + {m68000_base_device_ops::m68k_op_move_8_ix_ix, 0xf1f8, 0x11b0, { 24, 24, 14, 14, 14, 14, 7}}, + {m68000_base_device_ops::m68k_op_move_32_d_d, 0xf1f8, 0x2000, { 4, 4, 2, 2, 2, 2, 2}}, + {m68000_base_device_ops::m68k_op_move_32_d_a, 0xf1f8, 0x2008, { 4, 4, 2, 2, 2, 2, 2}}, + {m68000_base_device_ops::m68k_op_move_32_d_ai, 0xf1f8, 0x2010, { 12, 12, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_move_32_d_pi, 0xf1f8, 0x2018, { 12, 12, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_move_32_d_pd, 0xf1f8, 0x2020, { 14, 14, 7, 7, 7, 7, 2}}, + {m68000_base_device_ops::m68k_op_move_32_d_di, 0xf1f8, 0x2028, { 16, 16, 7, 7, 7, 7, 2}}, + {m68000_base_device_ops::m68k_op_move_32_d_ix, 0xf1f8, 0x2030, { 18, 18, 9, 9, 9, 9, 2}}, + {m68000_base_device_ops::m68k_op_movea_32_d, 0xf1f8, 0x2040, { 4, 4, 2, 2, 2, 2, 2}}, + {m68000_base_device_ops::m68k_op_movea_32_a, 0xf1f8, 0x2048, { 4, 4, 2, 2, 2, 2, 2}}, + {m68000_base_device_ops::m68k_op_movea_32_ai, 0xf1f8, 0x2050, { 12, 12, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_movea_32_pi, 0xf1f8, 0x2058, { 12, 12, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_movea_32_pd, 0xf1f8, 0x2060, { 14, 14, 7, 7, 7, 7, 2}}, + {m68000_base_device_ops::m68k_op_movea_32_di, 0xf1f8, 0x2068, { 16, 16, 7, 7, 7, 7, 2}}, + {m68000_base_device_ops::m68k_op_movea_32_ix, 0xf1f8, 0x2070, { 18, 18, 9, 9, 9, 9, 2}}, + {m68000_base_device_ops::m68k_op_move_32_ai_d, 0xf1f8, 0x2080, { 12, 12, 4, 4, 4, 4, 4}}, + {m68000_base_device_ops::m68k_op_move_32_ai_a, 0xf1f8, 0x2088, { 12, 12, 4, 4, 4, 4, 4}}, + {m68000_base_device_ops::m68k_op_move_32_ai_ai, 0xf1f8, 0x2090, { 20, 20, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_move_32_ai_pi, 0xf1f8, 0x2098, { 20, 20, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_move_32_ai_pd, 0xf1f8, 0x20a0, { 22, 22, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_move_32_ai_di, 0xf1f8, 0x20a8, { 24, 24, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_move_32_ai_ix, 0xf1f8, 0x20b0, { 26, 26, 11, 11, 11, 11, 4}}, + {m68000_base_device_ops::m68k_op_move_32_pi_d, 0xf1f8, 0x20c0, { 12, 12, 4, 4, 4, 4, 4}}, + {m68000_base_device_ops::m68k_op_move_32_pi_a, 0xf1f8, 0x20c8, { 12, 12, 4, 4, 4, 4, 4}}, + {m68000_base_device_ops::m68k_op_move_32_pi_ai, 0xf1f8, 0x20d0, { 20, 20, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_move_32_pi_pi, 0xf1f8, 0x20d8, { 20, 20, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_move_32_pi_pd, 0xf1f8, 0x20e0, { 22, 22, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_move_32_pi_di, 0xf1f8, 0x20e8, { 24, 24, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_move_32_pi_ix, 0xf1f8, 0x20f0, { 26, 26, 11, 11, 11, 11, 4}}, + {m68000_base_device_ops::m68k_op_move_32_pd_d, 0xf1f8, 0x2100, { 12, 14, 5, 5, 5, 5, 5}}, + {m68000_base_device_ops::m68k_op_move_32_pd_a, 0xf1f8, 0x2108, { 12, 14, 5, 5, 5, 5, 5}}, + {m68000_base_device_ops::m68k_op_move_32_pd_ai, 0xf1f8, 0x2110, { 20, 22, 9, 9, 9, 9, 5}}, + {m68000_base_device_ops::m68k_op_move_32_pd_pi, 0xf1f8, 0x2118, { 20, 22, 9, 9, 9, 9, 5}}, + {m68000_base_device_ops::m68k_op_move_32_pd_pd, 0xf1f8, 0x2120, { 22, 24, 10, 10, 10, 10, 5}}, + {m68000_base_device_ops::m68k_op_move_32_pd_di, 0xf1f8, 0x2128, { 24, 26, 10, 10, 10, 10, 5}}, + {m68000_base_device_ops::m68k_op_move_32_pd_ix, 0xf1f8, 0x2130, { 26, 28, 12, 12, 12, 12, 5}}, + {m68000_base_device_ops::m68k_op_move_32_di_d, 0xf1f8, 0x2140, { 16, 16, 5, 5, 5, 5, 5}}, + {m68000_base_device_ops::m68k_op_move_32_di_a, 0xf1f8, 0x2148, { 16, 16, 5, 5, 5, 5, 5}}, + {m68000_base_device_ops::m68k_op_move_32_di_ai, 0xf1f8, 0x2150, { 24, 24, 9, 9, 9, 9, 5}}, + {m68000_base_device_ops::m68k_op_move_32_di_pi, 0xf1f8, 0x2158, { 24, 24, 9, 9, 9, 9, 5}}, + {m68000_base_device_ops::m68k_op_move_32_di_pd, 0xf1f8, 0x2160, { 26, 26, 10, 10, 10, 10, 5}}, + {m68000_base_device_ops::m68k_op_move_32_di_di, 0xf1f8, 0x2168, { 28, 28, 10, 10, 10, 10, 5}}, + {m68000_base_device_ops::m68k_op_move_32_di_ix, 0xf1f8, 0x2170, { 30, 30, 12, 12, 12, 12, 5}}, + {m68000_base_device_ops::m68k_op_move_32_ix_d, 0xf1f8, 0x2180, { 18, 18, 7, 7, 7, 7, 7}}, + {m68000_base_device_ops::m68k_op_move_32_ix_a, 0xf1f8, 0x2188, { 18, 18, 7, 7, 7, 7, 7}}, + {m68000_base_device_ops::m68k_op_move_32_ix_ai, 0xf1f8, 0x2190, { 26, 26, 11, 11, 11, 11, 7}}, + {m68000_base_device_ops::m68k_op_move_32_ix_pi, 0xf1f8, 0x2198, { 26, 26, 11, 11, 11, 11, 7}}, + {m68000_base_device_ops::m68k_op_move_32_ix_pd, 0xf1f8, 0x21a0, { 28, 28, 12, 12, 12, 12, 7}}, + {m68000_base_device_ops::m68k_op_move_32_ix_di, 0xf1f8, 0x21a8, { 30, 30, 12, 12, 12, 12, 7}}, + {m68000_base_device_ops::m68k_op_move_32_ix_ix, 0xf1f8, 0x21b0, { 32, 32, 14, 14, 14, 14, 7}}, + {m68000_base_device_ops::m68k_op_move_16_d_d, 0xf1f8, 0x3000, { 4, 4, 2, 2, 2, 2, 2}}, + {m68000_base_device_ops::m68k_op_move_16_d_a, 0xf1f8, 0x3008, { 4, 4, 2, 2, 2, 2, 2}}, + {m68000_base_device_ops::m68k_op_move_16_d_ai, 0xf1f8, 0x3010, { 8, 8, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_move_16_d_pi, 0xf1f8, 0x3018, { 8, 8, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_move_16_d_pd, 0xf1f8, 0x3020, { 10, 10, 7, 7, 7, 7, 2}}, + {m68000_base_device_ops::m68k_op_move_16_d_di, 0xf1f8, 0x3028, { 12, 12, 7, 7, 7, 7, 2}}, + {m68000_base_device_ops::m68k_op_move_16_d_ix, 0xf1f8, 0x3030, { 14, 14, 9, 9, 9, 9, 2}}, + {m68000_base_device_ops::m68k_op_movea_16_d, 0xf1f8, 0x3040, { 4, 4, 2, 2, 2, 2, 2}}, + {m68000_base_device_ops::m68k_op_movea_16_a, 0xf1f8, 0x3048, { 4, 4, 2, 2, 2, 2, 2}}, + {m68000_base_device_ops::m68k_op_movea_16_ai, 0xf1f8, 0x3050, { 8, 8, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_movea_16_pi, 0xf1f8, 0x3058, { 8, 8, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_movea_16_pd, 0xf1f8, 0x3060, { 10, 10, 7, 7, 7, 7, 2}}, + {m68000_base_device_ops::m68k_op_movea_16_di, 0xf1f8, 0x3068, { 12, 12, 7, 7, 7, 7, 2}}, + {m68000_base_device_ops::m68k_op_movea_16_ix, 0xf1f8, 0x3070, { 14, 14, 9, 9, 9, 9, 2}}, + {m68000_base_device_ops::m68k_op_move_16_ai_d, 0xf1f8, 0x3080, { 8, 8, 4, 4, 4, 4, 4}}, + {m68000_base_device_ops::m68k_op_move_16_ai_a, 0xf1f8, 0x3088, { 8, 8, 4, 4, 4, 4, 4}}, + {m68000_base_device_ops::m68k_op_move_16_ai_ai, 0xf1f8, 0x3090, { 12, 12, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_move_16_ai_pi, 0xf1f8, 0x3098, { 12, 12, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_move_16_ai_pd, 0xf1f8, 0x30a0, { 14, 14, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_move_16_ai_di, 0xf1f8, 0x30a8, { 16, 16, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_move_16_ai_ix, 0xf1f8, 0x30b0, { 18, 18, 11, 11, 11, 11, 4}}, + {m68000_base_device_ops::m68k_op_move_16_pi_d, 0xf1f8, 0x30c0, { 8, 8, 4, 4, 4, 4, 4}}, + {m68000_base_device_ops::m68k_op_move_16_pi_a, 0xf1f8, 0x30c8, { 8, 8, 4, 4, 4, 4, 4}}, + {m68000_base_device_ops::m68k_op_move_16_pi_ai, 0xf1f8, 0x30d0, { 12, 12, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_move_16_pi_pi, 0xf1f8, 0x30d8, { 12, 12, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_move_16_pi_pd, 0xf1f8, 0x30e0, { 14, 14, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_move_16_pi_di, 0xf1f8, 0x30e8, { 16, 16, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_move_16_pi_ix, 0xf1f8, 0x30f0, { 18, 18, 11, 11, 11, 11, 4}}, + {m68000_base_device_ops::m68k_op_move_16_pd_d, 0xf1f8, 0x3100, { 8, 8, 5, 5, 5, 5, 5}}, + {m68000_base_device_ops::m68k_op_move_16_pd_a, 0xf1f8, 0x3108, { 8, 8, 5, 5, 5, 5, 5}}, + {m68000_base_device_ops::m68k_op_move_16_pd_ai, 0xf1f8, 0x3110, { 12, 12, 9, 9, 9, 9, 5}}, + {m68000_base_device_ops::m68k_op_move_16_pd_pi, 0xf1f8, 0x3118, { 12, 12, 9, 9, 9, 9, 5}}, + {m68000_base_device_ops::m68k_op_move_16_pd_pd, 0xf1f8, 0x3120, { 14, 14, 10, 10, 10, 10, 5}}, + {m68000_base_device_ops::m68k_op_move_16_pd_di, 0xf1f8, 0x3128, { 16, 16, 10, 10, 10, 10, 5}}, + {m68000_base_device_ops::m68k_op_move_16_pd_ix, 0xf1f8, 0x3130, { 18, 18, 12, 12, 12, 12, 5}}, + {m68000_base_device_ops::m68k_op_move_16_di_d, 0xf1f8, 0x3140, { 12, 12, 5, 5, 5, 5, 5}}, + {m68000_base_device_ops::m68k_op_move_16_di_a, 0xf1f8, 0x3148, { 12, 12, 5, 5, 5, 5, 5}}, + {m68000_base_device_ops::m68k_op_move_16_di_ai, 0xf1f8, 0x3150, { 16, 16, 9, 9, 9, 9, 5}}, + {m68000_base_device_ops::m68k_op_move_16_di_pi, 0xf1f8, 0x3158, { 16, 16, 9, 9, 9, 9, 5}}, + {m68000_base_device_ops::m68k_op_move_16_di_pd, 0xf1f8, 0x3160, { 18, 18, 10, 10, 10, 10, 5}}, + {m68000_base_device_ops::m68k_op_move_16_di_di, 0xf1f8, 0x3168, { 20, 20, 10, 10, 10, 10, 5}}, + {m68000_base_device_ops::m68k_op_move_16_di_ix, 0xf1f8, 0x3170, { 22, 22, 12, 12, 12, 12, 5}}, + {m68000_base_device_ops::m68k_op_move_16_ix_d, 0xf1f8, 0x3180, { 14, 14, 7, 7, 7, 7, 7}}, + {m68000_base_device_ops::m68k_op_move_16_ix_a, 0xf1f8, 0x3188, { 14, 14, 7, 7, 7, 7, 7}}, + {m68000_base_device_ops::m68k_op_move_16_ix_ai, 0xf1f8, 0x3190, { 18, 18, 11, 11, 11, 11, 7}}, + {m68000_base_device_ops::m68k_op_move_16_ix_pi, 0xf1f8, 0x3198, { 18, 18, 11, 11, 11, 11, 7}}, + {m68000_base_device_ops::m68k_op_move_16_ix_pd, 0xf1f8, 0x31a0, { 20, 20, 12, 12, 12, 12, 7}}, + {m68000_base_device_ops::m68k_op_move_16_ix_di, 0xf1f8, 0x31a8, { 22, 22, 12, 12, 12, 12, 7}}, + {m68000_base_device_ops::m68k_op_move_16_ix_ix, 0xf1f8, 0x31b0, { 24, 24, 14, 14, 14, 14, 7}}, + {m68000_base_device_ops::m68k_op_chk_32_d, 0xf1f8, 0x4100, {255, 255, 8, 8, 8, 8, 8}}, + {m68000_base_device_ops::m68k_op_chk_32_ai, 0xf1f8, 0x4110, {255, 255, 12, 12, 12, 12, 8}}, + {m68000_base_device_ops::m68k_op_chk_32_pi, 0xf1f8, 0x4118, {255, 255, 12, 12, 12, 12, 8}}, + {m68000_base_device_ops::m68k_op_chk_32_pd, 0xf1f8, 0x4120, {255, 255, 13, 13, 13, 13, 8}}, + {m68000_base_device_ops::m68k_op_chk_32_di, 0xf1f8, 0x4128, {255, 255, 13, 13, 13, 13, 8}}, + {m68000_base_device_ops::m68k_op_chk_32_ix, 0xf1f8, 0x4130, {255, 255, 15, 15, 15, 15, 8}}, + {m68000_base_device_ops::m68k_op_chk_16_d, 0xf1f8, 0x4180, { 10, 8, 8, 8, 8, 8, 8}}, + {m68000_base_device_ops::m68k_op_chk_16_ai, 0xf1f8, 0x4190, { 14, 12, 12, 12, 12, 12, 8}}, + {m68000_base_device_ops::m68k_op_chk_16_pi, 0xf1f8, 0x4198, { 14, 12, 12, 12, 12, 12, 8}}, + {m68000_base_device_ops::m68k_op_chk_16_pd, 0xf1f8, 0x41a0, { 16, 14, 13, 13, 13, 13, 8}}, + {m68000_base_device_ops::m68k_op_chk_16_di, 0xf1f8, 0x41a8, { 18, 16, 13, 13, 13, 13, 8}}, + {m68000_base_device_ops::m68k_op_chk_16_ix, 0xf1f8, 0x41b0, { 20, 18, 15, 15, 15, 15, 8}}, + {m68000_base_device_ops::m68k_op_lea_32_ai, 0xf1f8, 0x41d0, { 4, 4, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_lea_32_di, 0xf1f8, 0x41e8, { 8, 8, 7, 7, 7, 7, 2}}, + {m68000_base_device_ops::m68k_op_lea_32_ix, 0xf1f8, 0x41f0, { 12, 12, 9, 9, 9, 9, 2}}, + {m68000_base_device_ops::m68k_op_addq_8_d, 0xf1f8, 0x5000, { 4, 4, 2, 2, 2, 2, 2}}, + {m68000_base_device_ops::m68k_op_addq_8_ai, 0xf1f8, 0x5010, { 12, 12, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_addq_8_pi, 0xf1f8, 0x5018, { 12, 12, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_addq_8_pd, 0xf1f8, 0x5020, { 14, 14, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_addq_8_di, 0xf1f8, 0x5028, { 16, 16, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_addq_8_ix, 0xf1f8, 0x5030, { 18, 18, 11, 11, 11, 11, 4}}, + {m68000_base_device_ops::m68k_op_addq_16_d, 0xf1f8, 0x5040, { 4, 4, 2, 2, 2, 2, 2}}, + {m68000_base_device_ops::m68k_op_addq_16_a, 0xf1f8, 0x5048, { 4, 4, 2, 2, 2, 2, 2}}, + {m68000_base_device_ops::m68k_op_addq_16_ai, 0xf1f8, 0x5050, { 12, 12, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_addq_16_pi, 0xf1f8, 0x5058, { 12, 12, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_addq_16_pd, 0xf1f8, 0x5060, { 14, 14, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_addq_16_di, 0xf1f8, 0x5068, { 16, 16, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_addq_16_ix, 0xf1f8, 0x5070, { 18, 18, 11, 11, 11, 11, 4}}, + {m68000_base_device_ops::m68k_op_addq_32_d, 0xf1f8, 0x5080, { 8, 8, 2, 2, 2, 2, 2}}, + {m68000_base_device_ops::m68k_op_addq_32_a, 0xf1f8, 0x5088, { 8, 8, 2, 2, 2, 2, 2}}, + {m68000_base_device_ops::m68k_op_addq_32_ai, 0xf1f8, 0x5090, { 20, 20, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_addq_32_pi, 0xf1f8, 0x5098, { 20, 20, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_addq_32_pd, 0xf1f8, 0x50a0, { 22, 22, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_addq_32_di, 0xf1f8, 0x50a8, { 24, 24, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_addq_32_ix, 0xf1f8, 0x50b0, { 26, 26, 11, 11, 11, 11, 4}}, + {m68000_base_device_ops::m68k_op_subq_8_d, 0xf1f8, 0x5100, { 4, 4, 2, 2, 2, 2, 2}}, + {m68000_base_device_ops::m68k_op_subq_8_ai, 0xf1f8, 0x5110, { 12, 12, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_subq_8_pi, 0xf1f8, 0x5118, { 12, 12, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_subq_8_pd, 0xf1f8, 0x5120, { 14, 14, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_subq_8_di, 0xf1f8, 0x5128, { 16, 16, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_subq_8_ix, 0xf1f8, 0x5130, { 18, 18, 11, 11, 11, 11, 4}}, + {m68000_base_device_ops::m68k_op_subq_16_d, 0xf1f8, 0x5140, { 4, 4, 2, 2, 2, 2, 2}}, + {m68000_base_device_ops::m68k_op_subq_16_a, 0xf1f8, 0x5148, { 8, 4, 2, 2, 2, 2, 2}}, + {m68000_base_device_ops::m68k_op_subq_16_ai, 0xf1f8, 0x5150, { 12, 12, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_subq_16_pi, 0xf1f8, 0x5158, { 12, 12, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_subq_16_pd, 0xf1f8, 0x5160, { 14, 14, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_subq_16_di, 0xf1f8, 0x5168, { 16, 16, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_subq_16_ix, 0xf1f8, 0x5170, { 18, 18, 11, 11, 11, 11, 4}}, + {m68000_base_device_ops::m68k_op_subq_32_d, 0xf1f8, 0x5180, { 8, 8, 2, 2, 2, 2, 2}}, + {m68000_base_device_ops::m68k_op_subq_32_a, 0xf1f8, 0x5188, { 8, 8, 2, 2, 2, 2, 2}}, + {m68000_base_device_ops::m68k_op_subq_32_ai, 0xf1f8, 0x5190, { 20, 20, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_subq_32_pi, 0xf1f8, 0x5198, { 20, 20, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_subq_32_pd, 0xf1f8, 0x51a0, { 22, 22, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_subq_32_di, 0xf1f8, 0x51a8, { 24, 24, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_subq_32_ix, 0xf1f8, 0x51b0, { 26, 26, 11, 11, 11, 11, 4}}, + {m68000_base_device_ops::m68k_op_or_8_er_d, 0xf1f8, 0x8000, { 4, 4, 2, 2, 2, 2, 2}}, + {m68000_base_device_ops::m68k_op_or_8_er_ai, 0xf1f8, 0x8010, { 8, 8, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_or_8_er_pi, 0xf1f8, 0x8018, { 8, 8, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_or_8_er_pd, 0xf1f8, 0x8020, { 10, 10, 7, 7, 7, 7, 2}}, + {m68000_base_device_ops::m68k_op_or_8_er_di, 0xf1f8, 0x8028, { 12, 12, 7, 7, 7, 7, 2}}, + {m68000_base_device_ops::m68k_op_or_8_er_ix, 0xf1f8, 0x8030, { 14, 14, 9, 9, 9, 9, 2}}, + {m68000_base_device_ops::m68k_op_or_16_er_d, 0xf1f8, 0x8040, { 4, 4, 2, 2, 2, 2, 2}}, + {m68000_base_device_ops::m68k_op_or_16_er_ai, 0xf1f8, 0x8050, { 8, 8, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_or_16_er_pi, 0xf1f8, 0x8058, { 8, 8, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_or_16_er_pd, 0xf1f8, 0x8060, { 10, 10, 7, 7, 7, 7, 2}}, + {m68000_base_device_ops::m68k_op_or_16_er_di, 0xf1f8, 0x8068, { 12, 12, 7, 7, 7, 7, 2}}, + {m68000_base_device_ops::m68k_op_or_16_er_ix, 0xf1f8, 0x8070, { 14, 14, 9, 9, 9, 9, 2}}, + {m68000_base_device_ops::m68k_op_or_32_er_d, 0xf1f8, 0x8080, { 8, 6, 2, 2, 2, 2, 2}}, + {m68000_base_device_ops::m68k_op_or_32_er_ai, 0xf1f8, 0x8090, { 14, 14, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_or_32_er_pi, 0xf1f8, 0x8098, { 14, 14, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_or_32_er_pd, 0xf1f8, 0x80a0, { 16, 16, 7, 7, 7, 7, 2}}, + {m68000_base_device_ops::m68k_op_or_32_er_di, 0xf1f8, 0x80a8, { 18, 18, 7, 7, 7, 7, 2}}, + {m68000_base_device_ops::m68k_op_or_32_er_ix, 0xf1f8, 0x80b0, { 20, 20, 9, 9, 9, 9, 2}}, + {m68000_base_device_ops::m68k_op_divu_16_d, 0xf1f8, 0x80c0, {140, 108, 44, 44, 44, 44, 44}}, + {m68000_base_device_ops::m68k_op_divu_16_ai, 0xf1f8, 0x80d0, {144, 112, 48, 48, 48, 48, 44}}, + {m68000_base_device_ops::m68k_op_divu_16_pi, 0xf1f8, 0x80d8, {144, 112, 48, 48, 48, 48, 44}}, + {m68000_base_device_ops::m68k_op_divu_16_pd, 0xf1f8, 0x80e0, {146, 114, 49, 49, 49, 49, 44}}, + {m68000_base_device_ops::m68k_op_divu_16_di, 0xf1f8, 0x80e8, {148, 116, 49, 49, 49, 49, 44}}, + {m68000_base_device_ops::m68k_op_divu_16_ix, 0xf1f8, 0x80f0, {150, 118, 51, 51, 51, 51, 44}}, + {m68000_base_device_ops::m68k_op_sbcd_8_rr, 0xf1f8, 0x8100, { 6, 6, 4, 4, 4, 4, 4}}, + {m68000_base_device_ops::m68k_op_sbcd_8_mm, 0xf1f8, 0x8108, { 18, 18, 16, 16, 16, 16, 16}}, + {m68000_base_device_ops::m68k_op_or_8_re_ai, 0xf1f8, 0x8110, { 12, 12, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_or_8_re_pi, 0xf1f8, 0x8118, { 12, 12, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_or_8_re_pd, 0xf1f8, 0x8120, { 14, 14, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_or_8_re_di, 0xf1f8, 0x8128, { 16, 16, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_or_8_re_ix, 0xf1f8, 0x8130, { 18, 18, 11, 11, 11, 11, 4}}, + {m68000_base_device_ops::m68k_op_pack_16_rr, 0xf1f8, 0x8140, {255, 255, 6, 6, 6, 6, 6}}, + {m68000_base_device_ops::m68k_op_pack_16_mm, 0xf1f8, 0x8148, {255, 255, 13, 13, 13, 13, 13}}, + {m68000_base_device_ops::m68k_op_or_16_re_ai, 0xf1f8, 0x8150, { 12, 12, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_or_16_re_pi, 0xf1f8, 0x8158, { 12, 12, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_or_16_re_pd, 0xf1f8, 0x8160, { 14, 14, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_or_16_re_di, 0xf1f8, 0x8168, { 16, 16, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_or_16_re_ix, 0xf1f8, 0x8170, { 18, 18, 11, 11, 11, 11, 4}}, + {m68000_base_device_ops::m68k_op_unpk_16_rr, 0xf1f8, 0x8180, {255, 255, 8, 8, 8, 8, 8}}, + {m68000_base_device_ops::m68k_op_unpk_16_mm, 0xf1f8, 0x8188, {255, 255, 13, 13, 13, 13, 13}}, + {m68000_base_device_ops::m68k_op_or_32_re_ai, 0xf1f8, 0x8190, { 20, 20, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_or_32_re_pi, 0xf1f8, 0x8198, { 20, 20, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_or_32_re_pd, 0xf1f8, 0x81a0, { 22, 22, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_or_32_re_di, 0xf1f8, 0x81a8, { 24, 24, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_or_32_re_ix, 0xf1f8, 0x81b0, { 26, 26, 11, 11, 11, 11, 4}}, + {m68000_base_device_ops::m68k_op_divs_16_d, 0xf1f8, 0x81c0, {158, 122, 56, 56, 56, 56, 56}}, + {m68000_base_device_ops::m68k_op_divs_16_ai, 0xf1f8, 0x81d0, {162, 126, 60, 60, 60, 60, 56}}, + {m68000_base_device_ops::m68k_op_divs_16_pi, 0xf1f8, 0x81d8, {162, 126, 60, 60, 60, 60, 56}}, + {m68000_base_device_ops::m68k_op_divs_16_pd, 0xf1f8, 0x81e0, {164, 128, 61, 61, 61, 61, 56}}, + {m68000_base_device_ops::m68k_op_divs_16_di, 0xf1f8, 0x81e8, {166, 130, 61, 61, 61, 61, 56}}, + {m68000_base_device_ops::m68k_op_divs_16_ix, 0xf1f8, 0x81f0, {168, 132, 63, 63, 63, 63, 56}}, + {m68000_base_device_ops::m68k_op_sub_8_er_d, 0xf1f8, 0x9000, { 4, 4, 2, 2, 2, 2, 2}}, + {m68000_base_device_ops::m68k_op_sub_8_er_ai, 0xf1f8, 0x9010, { 8, 8, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_sub_8_er_pi, 0xf1f8, 0x9018, { 8, 8, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_sub_8_er_pd, 0xf1f8, 0x9020, { 10, 10, 7, 7, 7, 7, 2}}, + {m68000_base_device_ops::m68k_op_sub_8_er_di, 0xf1f8, 0x9028, { 12, 12, 7, 7, 7, 7, 2}}, + {m68000_base_device_ops::m68k_op_sub_8_er_ix, 0xf1f8, 0x9030, { 14, 14, 9, 9, 9, 9, 2}}, + {m68000_base_device_ops::m68k_op_sub_16_er_d, 0xf1f8, 0x9040, { 4, 4, 2, 2, 2, 2, 2}}, + {m68000_base_device_ops::m68k_op_sub_16_er_a, 0xf1f8, 0x9048, { 4, 4, 2, 2, 2, 2, 2}}, + {m68000_base_device_ops::m68k_op_sub_16_er_ai, 0xf1f8, 0x9050, { 8, 8, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_sub_16_er_pi, 0xf1f8, 0x9058, { 8, 8, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_sub_16_er_pd, 0xf1f8, 0x9060, { 10, 10, 7, 7, 7, 7, 2}}, + {m68000_base_device_ops::m68k_op_sub_16_er_di, 0xf1f8, 0x9068, { 12, 12, 7, 7, 7, 7, 2}}, + {m68000_base_device_ops::m68k_op_sub_16_er_ix, 0xf1f8, 0x9070, { 14, 14, 9, 9, 9, 9, 2}}, + {m68000_base_device_ops::m68k_op_sub_32_er_d, 0xf1f8, 0x9080, { 8, 6, 2, 2, 2, 2, 2}}, + {m68000_base_device_ops::m68k_op_sub_32_er_a, 0xf1f8, 0x9088, { 8, 6, 2, 2, 2, 2, 2}}, + {m68000_base_device_ops::m68k_op_sub_32_er_ai, 0xf1f8, 0x9090, { 14, 14, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_sub_32_er_pi, 0xf1f8, 0x9098, { 14, 14, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_sub_32_er_pd, 0xf1f8, 0x90a0, { 16, 16, 7, 7, 7, 7, 2}}, + {m68000_base_device_ops::m68k_op_sub_32_er_di, 0xf1f8, 0x90a8, { 18, 18, 7, 7, 7, 7, 2}}, + {m68000_base_device_ops::m68k_op_sub_32_er_ix, 0xf1f8, 0x90b0, { 20, 20, 9, 9, 9, 9, 2}}, + {m68000_base_device_ops::m68k_op_suba_16_d, 0xf1f8, 0x90c0, { 8, 8, 2, 2, 2, 2, 2}}, + {m68000_base_device_ops::m68k_op_suba_16_a, 0xf1f8, 0x90c8, { 8, 8, 2, 2, 2, 2, 2}}, + {m68000_base_device_ops::m68k_op_suba_16_ai, 0xf1f8, 0x90d0, { 12, 12, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_suba_16_pi, 0xf1f8, 0x90d8, { 12, 12, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_suba_16_pd, 0xf1f8, 0x90e0, { 14, 14, 7, 7, 7, 7, 2}}, + {m68000_base_device_ops::m68k_op_suba_16_di, 0xf1f8, 0x90e8, { 16, 16, 7, 7, 7, 7, 2}}, + {m68000_base_device_ops::m68k_op_suba_16_ix, 0xf1f8, 0x90f0, { 18, 18, 9, 9, 9, 9, 2}}, + {m68000_base_device_ops::m68k_op_subx_8_rr, 0xf1f8, 0x9100, { 4, 4, 2, 2, 2, 2, 2}}, + {m68000_base_device_ops::m68k_op_subx_8_mm, 0xf1f8, 0x9108, { 18, 18, 12, 12, 12, 12, 12}}, + {m68000_base_device_ops::m68k_op_sub_8_re_ai, 0xf1f8, 0x9110, { 12, 12, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_sub_8_re_pi, 0xf1f8, 0x9118, { 12, 12, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_sub_8_re_pd, 0xf1f8, 0x9120, { 14, 14, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_sub_8_re_di, 0xf1f8, 0x9128, { 16, 16, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_sub_8_re_ix, 0xf1f8, 0x9130, { 18, 18, 11, 11, 11, 11, 4}}, + {m68000_base_device_ops::m68k_op_subx_16_rr, 0xf1f8, 0x9140, { 4, 4, 2, 2, 2, 2, 2}}, + {m68000_base_device_ops::m68k_op_subx_16_mm, 0xf1f8, 0x9148, { 18, 18, 12, 12, 12, 12, 12}}, + {m68000_base_device_ops::m68k_op_sub_16_re_ai, 0xf1f8, 0x9150, { 12, 12, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_sub_16_re_pi, 0xf1f8, 0x9158, { 12, 12, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_sub_16_re_pd, 0xf1f8, 0x9160, { 14, 14, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_sub_16_re_di, 0xf1f8, 0x9168, { 16, 16, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_sub_16_re_ix, 0xf1f8, 0x9170, { 18, 18, 11, 11, 11, 11, 4}}, + {m68000_base_device_ops::m68k_op_subx_32_rr, 0xf1f8, 0x9180, { 8, 6, 2, 2, 2, 2, 2}}, + {m68000_base_device_ops::m68k_op_subx_32_mm, 0xf1f8, 0x9188, { 30, 30, 12, 12, 12, 12, 12}}, + {m68000_base_device_ops::m68k_op_sub_32_re_ai, 0xf1f8, 0x9190, { 20, 20, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_sub_32_re_pi, 0xf1f8, 0x9198, { 20, 20, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_sub_32_re_pd, 0xf1f8, 0x91a0, { 22, 22, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_sub_32_re_di, 0xf1f8, 0x91a8, { 24, 24, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_sub_32_re_ix, 0xf1f8, 0x91b0, { 26, 26, 11, 11, 11, 11, 4}}, + {m68000_base_device_ops::m68k_op_suba_32_d, 0xf1f8, 0x91c0, { 8, 6, 2, 2, 2, 2, 2}}, + {m68000_base_device_ops::m68k_op_suba_32_a, 0xf1f8, 0x91c8, { 8, 6, 2, 2, 2, 2, 2}}, + {m68000_base_device_ops::m68k_op_suba_32_ai, 0xf1f8, 0x91d0, { 14, 14, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_suba_32_pi, 0xf1f8, 0x91d8, { 14, 14, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_suba_32_pd, 0xf1f8, 0x91e0, { 16, 16, 7, 7, 7, 7, 2}}, + {m68000_base_device_ops::m68k_op_suba_32_di, 0xf1f8, 0x91e8, { 18, 18, 7, 7, 7, 7, 2}}, + {m68000_base_device_ops::m68k_op_suba_32_ix, 0xf1f8, 0x91f0, { 20, 20, 9, 9, 9, 9, 2}}, + {m68000_base_device_ops::m68k_op_cmp_8_d, 0xf1f8, 0xb000, { 4, 4, 2, 2, 2, 2, 2}}, + {m68000_base_device_ops::m68k_op_cmp_8_ai, 0xf1f8, 0xb010, { 8, 8, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_cmp_8_pi, 0xf1f8, 0xb018, { 8, 8, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_cmp_8_pd, 0xf1f8, 0xb020, { 10, 10, 7, 7, 7, 7, 2}}, + {m68000_base_device_ops::m68k_op_cmp_8_di, 0xf1f8, 0xb028, { 12, 12, 7, 7, 7, 7, 2}}, + {m68000_base_device_ops::m68k_op_cmp_8_ix, 0xf1f8, 0xb030, { 14, 14, 9, 9, 9, 9, 2}}, + {m68000_base_device_ops::m68k_op_cmp_16_d, 0xf1f8, 0xb040, { 4, 4, 2, 2, 2, 2, 2}}, + {m68000_base_device_ops::m68k_op_cmp_16_a, 0xf1f8, 0xb048, { 4, 4, 2, 2, 2, 2, 2}}, + {m68000_base_device_ops::m68k_op_cmp_16_ai, 0xf1f8, 0xb050, { 8, 8, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_cmp_16_pi, 0xf1f8, 0xb058, { 8, 8, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_cmp_16_pd, 0xf1f8, 0xb060, { 10, 10, 7, 7, 7, 7, 2}}, + {m68000_base_device_ops::m68k_op_cmp_16_di, 0xf1f8, 0xb068, { 12, 12, 7, 7, 7, 7, 2}}, + {m68000_base_device_ops::m68k_op_cmp_16_ix, 0xf1f8, 0xb070, { 14, 14, 9, 9, 9, 9, 2}}, + {m68000_base_device_ops::m68k_op_cmp_32_d, 0xf1f8, 0xb080, { 6, 6, 2, 2, 2, 2, 2}}, + {m68000_base_device_ops::m68k_op_cmp_32_a, 0xf1f8, 0xb088, { 6, 6, 2, 2, 2, 2, 2}}, + {m68000_base_device_ops::m68k_op_cmp_32_ai, 0xf1f8, 0xb090, { 14, 14, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_cmp_32_pi, 0xf1f8, 0xb098, { 14, 14, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_cmp_32_pd, 0xf1f8, 0xb0a0, { 16, 16, 7, 7, 7, 7, 2}}, + {m68000_base_device_ops::m68k_op_cmp_32_di, 0xf1f8, 0xb0a8, { 18, 18, 7, 7, 7, 7, 2}}, + {m68000_base_device_ops::m68k_op_cmp_32_ix, 0xf1f8, 0xb0b0, { 20, 20, 9, 9, 9, 9, 2}}, + {m68000_base_device_ops::m68k_op_cmpa_16_d, 0xf1f8, 0xb0c0, { 6, 6, 4, 4, 4, 4, 4}}, + {m68000_base_device_ops::m68k_op_cmpa_16_a, 0xf1f8, 0xb0c8, { 6, 6, 4, 4, 4, 4, 4}}, + {m68000_base_device_ops::m68k_op_cmpa_16_ai, 0xf1f8, 0xb0d0, { 10, 10, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_cmpa_16_pi, 0xf1f8, 0xb0d8, { 10, 10, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_cmpa_16_pd, 0xf1f8, 0xb0e0, { 12, 12, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_cmpa_16_di, 0xf1f8, 0xb0e8, { 14, 14, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_cmpa_16_ix, 0xf1f8, 0xb0f0, { 16, 16, 11, 11, 11, 11, 4}}, + {m68000_base_device_ops::m68k_op_eor_8_d, 0xf1f8, 0xb100, { 4, 4, 2, 2, 2, 2, 2}}, + {m68000_base_device_ops::m68k_op_cmpm_8, 0xf1f8, 0xb108, { 12, 12, 9, 9, 9, 9, 9}}, + {m68000_base_device_ops::m68k_op_eor_8_ai, 0xf1f8, 0xb110, { 12, 12, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_eor_8_pi, 0xf1f8, 0xb118, { 12, 12, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_eor_8_pd, 0xf1f8, 0xb120, { 14, 14, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_eor_8_di, 0xf1f8, 0xb128, { 16, 16, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_eor_8_ix, 0xf1f8, 0xb130, { 18, 18, 11, 11, 11, 11, 4}}, + {m68000_base_device_ops::m68k_op_eor_16_d, 0xf1f8, 0xb140, { 4, 4, 2, 2, 2, 2, 2}}, + {m68000_base_device_ops::m68k_op_cmpm_16, 0xf1f8, 0xb148, { 12, 12, 9, 9, 9, 9, 9}}, + {m68000_base_device_ops::m68k_op_eor_16_ai, 0xf1f8, 0xb150, { 12, 12, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_eor_16_pi, 0xf1f8, 0xb158, { 12, 12, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_eor_16_pd, 0xf1f8, 0xb160, { 14, 14, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_eor_16_di, 0xf1f8, 0xb168, { 16, 16, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_eor_16_ix, 0xf1f8, 0xb170, { 18, 18, 11, 11, 11, 11, 4}}, + {m68000_base_device_ops::m68k_op_eor_32_d, 0xf1f8, 0xb180, { 8, 6, 2, 2, 2, 2, 2}}, + {m68000_base_device_ops::m68k_op_cmpm_32, 0xf1f8, 0xb188, { 20, 20, 9, 9, 9, 9, 9}}, + {m68000_base_device_ops::m68k_op_eor_32_ai, 0xf1f8, 0xb190, { 20, 20, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_eor_32_pi, 0xf1f8, 0xb198, { 20, 20, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_eor_32_pd, 0xf1f8, 0xb1a0, { 22, 22, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_eor_32_di, 0xf1f8, 0xb1a8, { 24, 24, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_eor_32_ix, 0xf1f8, 0xb1b0, { 26, 26, 11, 11, 11, 11, 4}}, + {m68000_base_device_ops::m68k_op_cmpa_32_d, 0xf1f8, 0xb1c0, { 6, 6, 4, 4, 4, 4, 4}}, + {m68000_base_device_ops::m68k_op_cmpa_32_a, 0xf1f8, 0xb1c8, { 6, 6, 4, 4, 4, 4, 4}}, + {m68000_base_device_ops::m68k_op_cmpa_32_ai, 0xf1f8, 0xb1d0, { 14, 14, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_cmpa_32_pi, 0xf1f8, 0xb1d8, { 14, 14, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_cmpa_32_pd, 0xf1f8, 0xb1e0, { 16, 16, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_cmpa_32_di, 0xf1f8, 0xb1e8, { 18, 18, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_cmpa_32_ix, 0xf1f8, 0xb1f0, { 20, 20, 11, 11, 11, 11, 4}}, + {m68000_base_device_ops::m68k_op_and_8_er_d, 0xf1f8, 0xc000, { 4, 4, 2, 2, 2, 2, 2}}, + {m68000_base_device_ops::m68k_op_and_8_er_ai, 0xf1f8, 0xc010, { 8, 8, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_and_8_er_pi, 0xf1f8, 0xc018, { 8, 8, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_and_8_er_pd, 0xf1f8, 0xc020, { 10, 10, 7, 7, 7, 7, 2}}, + {m68000_base_device_ops::m68k_op_and_8_er_di, 0xf1f8, 0xc028, { 12, 12, 7, 7, 7, 7, 2}}, + {m68000_base_device_ops::m68k_op_and_8_er_ix, 0xf1f8, 0xc030, { 14, 14, 9, 9, 9, 9, 2}}, + {m68000_base_device_ops::m68k_op_and_16_er_d, 0xf1f8, 0xc040, { 4, 4, 2, 2, 2, 2, 2}}, + {m68000_base_device_ops::m68k_op_and_16_er_ai, 0xf1f8, 0xc050, { 8, 8, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_and_16_er_pi, 0xf1f8, 0xc058, { 8, 8, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_and_16_er_pd, 0xf1f8, 0xc060, { 10, 10, 7, 7, 7, 7, 2}}, + {m68000_base_device_ops::m68k_op_and_16_er_di, 0xf1f8, 0xc068, { 12, 12, 7, 7, 7, 7, 2}}, + {m68000_base_device_ops::m68k_op_and_16_er_ix, 0xf1f8, 0xc070, { 14, 14, 9, 9, 9, 9, 2}}, + {m68000_base_device_ops::m68k_op_and_32_er_d, 0xf1f8, 0xc080, { 8, 6, 2, 2, 2, 2, 2}}, + {m68000_base_device_ops::m68k_op_and_32_er_ai, 0xf1f8, 0xc090, { 14, 14, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_and_32_er_pi, 0xf1f8, 0xc098, { 14, 14, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_and_32_er_pd, 0xf1f8, 0xc0a0, { 16, 16, 7, 7, 7, 7, 2}}, + {m68000_base_device_ops::m68k_op_and_32_er_di, 0xf1f8, 0xc0a8, { 18, 18, 7, 7, 7, 7, 2}}, + {m68000_base_device_ops::m68k_op_and_32_er_ix, 0xf1f8, 0xc0b0, { 20, 20, 9, 9, 9, 9, 2}}, + {m68000_base_device_ops::m68k_op_mulu_16_d, 0xf1f8, 0xc0c0, { 54, 30, 27, 27, 27, 27, 27}}, + {m68000_base_device_ops::m68k_op_mulu_16_ai, 0xf1f8, 0xc0d0, { 58, 34, 31, 31, 31, 31, 27}}, + {m68000_base_device_ops::m68k_op_mulu_16_pi, 0xf1f8, 0xc0d8, { 58, 34, 31, 31, 31, 31, 27}}, + {m68000_base_device_ops::m68k_op_mulu_16_pd, 0xf1f8, 0xc0e0, { 60, 36, 32, 32, 32, 32, 27}}, + {m68000_base_device_ops::m68k_op_mulu_16_di, 0xf1f8, 0xc0e8, { 62, 38, 32, 32, 32, 32, 27}}, + {m68000_base_device_ops::m68k_op_mulu_16_ix, 0xf1f8, 0xc0f0, { 64, 40, 34, 34, 34, 34, 27}}, + {m68000_base_device_ops::m68k_op_abcd_8_rr, 0xf1f8, 0xc100, { 6, 6, 4, 4, 4, 4, 4}}, + {m68000_base_device_ops::m68k_op_abcd_8_mm, 0xf1f8, 0xc108, { 18, 18, 16, 16, 16, 16, 16}}, + {m68000_base_device_ops::m68k_op_and_8_re_ai, 0xf1f8, 0xc110, { 12, 12, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_and_8_re_pi, 0xf1f8, 0xc118, { 12, 12, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_and_8_re_pd, 0xf1f8, 0xc120, { 14, 14, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_and_8_re_di, 0xf1f8, 0xc128, { 16, 16, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_and_8_re_ix, 0xf1f8, 0xc130, { 18, 18, 11, 11, 11, 11, 4}}, + {m68000_base_device_ops::m68k_op_exg_32_dd, 0xf1f8, 0xc140, { 6, 6, 2, 2, 2, 2, 2}}, + {m68000_base_device_ops::m68k_op_exg_32_aa, 0xf1f8, 0xc148, { 6, 6, 2, 2, 2, 2, 2}}, + {m68000_base_device_ops::m68k_op_and_16_re_ai, 0xf1f8, 0xc150, { 12, 12, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_and_16_re_pi, 0xf1f8, 0xc158, { 12, 12, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_and_16_re_pd, 0xf1f8, 0xc160, { 14, 14, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_and_16_re_di, 0xf1f8, 0xc168, { 16, 16, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_and_16_re_ix, 0xf1f8, 0xc170, { 18, 18, 11, 11, 11, 11, 4}}, + {m68000_base_device_ops::m68k_op_exg_32_da, 0xf1f8, 0xc188, { 6, 6, 2, 2, 2, 2, 2}}, + {m68000_base_device_ops::m68k_op_and_32_re_ai, 0xf1f8, 0xc190, { 20, 20, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_and_32_re_pi, 0xf1f8, 0xc198, { 20, 20, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_and_32_re_pd, 0xf1f8, 0xc1a0, { 22, 22, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_and_32_re_di, 0xf1f8, 0xc1a8, { 24, 24, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_and_32_re_ix, 0xf1f8, 0xc1b0, { 26, 26, 11, 11, 11, 11, 4}}, + {m68000_base_device_ops::m68k_op_muls_16_d, 0xf1f8, 0xc1c0, { 54, 32, 27, 27, 27, 27, 27}}, + {m68000_base_device_ops::m68k_op_muls_16_ai, 0xf1f8, 0xc1d0, { 58, 36, 31, 31, 31, 31, 27}}, + {m68000_base_device_ops::m68k_op_muls_16_pi, 0xf1f8, 0xc1d8, { 58, 36, 31, 31, 31, 31, 27}}, + {m68000_base_device_ops::m68k_op_muls_16_pd, 0xf1f8, 0xc1e0, { 60, 38, 32, 32, 32, 32, 27}}, + {m68000_base_device_ops::m68k_op_muls_16_di, 0xf1f8, 0xc1e8, { 62, 40, 32, 32, 32, 32, 27}}, + {m68000_base_device_ops::m68k_op_muls_16_ix, 0xf1f8, 0xc1f0, { 64, 42, 34, 34, 34, 34, 27}}, + {m68000_base_device_ops::m68k_op_add_8_er_d, 0xf1f8, 0xd000, { 4, 4, 2, 2, 2, 2, 2}}, + {m68000_base_device_ops::m68k_op_add_8_er_ai, 0xf1f8, 0xd010, { 8, 8, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_add_8_er_pi, 0xf1f8, 0xd018, { 8, 8, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_add_8_er_pd, 0xf1f8, 0xd020, { 10, 10, 7, 7, 7, 7, 2}}, + {m68000_base_device_ops::m68k_op_add_8_er_di, 0xf1f8, 0xd028, { 12, 12, 7, 7, 7, 7, 2}}, + {m68000_base_device_ops::m68k_op_add_8_er_ix, 0xf1f8, 0xd030, { 14, 14, 9, 9, 9, 9, 2}}, + {m68000_base_device_ops::m68k_op_add_16_er_d, 0xf1f8, 0xd040, { 4, 4, 2, 2, 2, 2, 2}}, + {m68000_base_device_ops::m68k_op_add_16_er_a, 0xf1f8, 0xd048, { 4, 4, 2, 2, 2, 2, 2}}, + {m68000_base_device_ops::m68k_op_add_16_er_ai, 0xf1f8, 0xd050, { 8, 8, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_add_16_er_pi, 0xf1f8, 0xd058, { 8, 8, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_add_16_er_pd, 0xf1f8, 0xd060, { 10, 10, 7, 7, 7, 7, 2}}, + {m68000_base_device_ops::m68k_op_add_16_er_di, 0xf1f8, 0xd068, { 12, 12, 7, 7, 7, 7, 2}}, + {m68000_base_device_ops::m68k_op_add_16_er_ix, 0xf1f8, 0xd070, { 14, 14, 9, 9, 9, 9, 2}}, + {m68000_base_device_ops::m68k_op_add_32_er_d, 0xf1f8, 0xd080, { 8, 6, 2, 2, 2, 2, 2}}, + {m68000_base_device_ops::m68k_op_add_32_er_a, 0xf1f8, 0xd088, { 8, 6, 2, 2, 2, 2, 2}}, + {m68000_base_device_ops::m68k_op_add_32_er_ai, 0xf1f8, 0xd090, { 14, 14, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_add_32_er_pi, 0xf1f8, 0xd098, { 14, 14, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_add_32_er_pd, 0xf1f8, 0xd0a0, { 16, 16, 7, 7, 7, 7, 2}}, + {m68000_base_device_ops::m68k_op_add_32_er_di, 0xf1f8, 0xd0a8, { 18, 18, 7, 7, 7, 7, 2}}, + {m68000_base_device_ops::m68k_op_add_32_er_ix, 0xf1f8, 0xd0b0, { 20, 20, 9, 9, 9, 9, 2}}, + {m68000_base_device_ops::m68k_op_adda_16_d, 0xf1f8, 0xd0c0, { 8, 8, 2, 2, 2, 2, 2}}, + {m68000_base_device_ops::m68k_op_adda_16_a, 0xf1f8, 0xd0c8, { 8, 8, 2, 2, 2, 2, 2}}, + {m68000_base_device_ops::m68k_op_adda_16_ai, 0xf1f8, 0xd0d0, { 12, 12, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_adda_16_pi, 0xf1f8, 0xd0d8, { 12, 12, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_adda_16_pd, 0xf1f8, 0xd0e0, { 14, 14, 7, 7, 7, 7, 2}}, + {m68000_base_device_ops::m68k_op_adda_16_di, 0xf1f8, 0xd0e8, { 16, 16, 7, 7, 7, 7, 2}}, + {m68000_base_device_ops::m68k_op_adda_16_ix, 0xf1f8, 0xd0f0, { 18, 18, 9, 9, 9, 9, 2}}, + {m68000_base_device_ops::m68k_op_addx_8_rr, 0xf1f8, 0xd100, { 4, 4, 2, 2, 2, 2, 2}}, + {m68000_base_device_ops::m68k_op_addx_8_mm, 0xf1f8, 0xd108, { 18, 18, 12, 12, 12, 12, 12}}, + {m68000_base_device_ops::m68k_op_add_8_re_ai, 0xf1f8, 0xd110, { 12, 12, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_add_8_re_pi, 0xf1f8, 0xd118, { 12, 12, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_add_8_re_pd, 0xf1f8, 0xd120, { 14, 14, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_add_8_re_di, 0xf1f8, 0xd128, { 16, 16, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_add_8_re_ix, 0xf1f8, 0xd130, { 18, 18, 11, 11, 11, 11, 4}}, + {m68000_base_device_ops::m68k_op_addx_16_rr, 0xf1f8, 0xd140, { 4, 4, 2, 2, 2, 2, 2}}, + {m68000_base_device_ops::m68k_op_addx_16_mm, 0xf1f8, 0xd148, { 18, 18, 12, 12, 12, 12, 12}}, + {m68000_base_device_ops::m68k_op_add_16_re_ai, 0xf1f8, 0xd150, { 12, 12, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_add_16_re_pi, 0xf1f8, 0xd158, { 12, 12, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_add_16_re_pd, 0xf1f8, 0xd160, { 14, 14, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_add_16_re_di, 0xf1f8, 0xd168, { 16, 16, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_add_16_re_ix, 0xf1f8, 0xd170, { 18, 18, 11, 11, 11, 11, 4}}, + {m68000_base_device_ops::m68k_op_addx_32_rr, 0xf1f8, 0xd180, { 8, 6, 2, 2, 2, 2, 2}}, + {m68000_base_device_ops::m68k_op_addx_32_mm, 0xf1f8, 0xd188, { 30, 30, 12, 12, 12, 12, 12}}, + {m68000_base_device_ops::m68k_op_add_32_re_ai, 0xf1f8, 0xd190, { 20, 20, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_add_32_re_pi, 0xf1f8, 0xd198, { 20, 20, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_add_32_re_pd, 0xf1f8, 0xd1a0, { 22, 22, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_add_32_re_di, 0xf1f8, 0xd1a8, { 24, 24, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_add_32_re_ix, 0xf1f8, 0xd1b0, { 26, 26, 11, 11, 11, 11, 4}}, + {m68000_base_device_ops::m68k_op_adda_32_d, 0xf1f8, 0xd1c0, { 8, 6, 2, 2, 2, 2, 2}}, + {m68000_base_device_ops::m68k_op_adda_32_a, 0xf1f8, 0xd1c8, { 8, 6, 2, 2, 2, 2, 2}}, + {m68000_base_device_ops::m68k_op_adda_32_ai, 0xf1f8, 0xd1d0, { 14, 14, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_adda_32_pi, 0xf1f8, 0xd1d8, { 14, 14, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_adda_32_pd, 0xf1f8, 0xd1e0, { 16, 16, 7, 7, 7, 7, 2}}, + {m68000_base_device_ops::m68k_op_adda_32_di, 0xf1f8, 0xd1e8, { 18, 18, 7, 7, 7, 7, 2}}, + {m68000_base_device_ops::m68k_op_adda_32_ix, 0xf1f8, 0xd1f0, { 20, 20, 9, 9, 9, 9, 2}}, + {m68000_base_device_ops::m68k_op_asr_8_s, 0xf1f8, 0xe000, { 6, 6, 6, 6, 6, 6, 6}}, + {m68000_base_device_ops::m68k_op_lsr_8_s, 0xf1f8, 0xe008, { 6, 6, 4, 4, 4, 4, 4}}, + {m68000_base_device_ops::m68k_op_roxr_8_s, 0xf1f8, 0xe010, { 6, 6, 12, 12, 12, 12, 12}}, + {m68000_base_device_ops::m68k_op_ror_8_s, 0xf1f8, 0xe018, { 6, 6, 8, 8, 8, 8, 8}}, + {m68000_base_device_ops::m68k_op_asr_8_r, 0xf1f8, 0xe020, { 6, 6, 6, 6, 6, 6, 6}}, + {m68000_base_device_ops::m68k_op_lsr_8_r, 0xf1f8, 0xe028, { 6, 6, 6, 6, 6, 6, 6}}, + {m68000_base_device_ops::m68k_op_roxr_8_r, 0xf1f8, 0xe030, { 6, 6, 12, 12, 12, 12, 12}}, + {m68000_base_device_ops::m68k_op_ror_8_r, 0xf1f8, 0xe038, { 6, 6, 8, 8, 8, 8, 8}}, + {m68000_base_device_ops::m68k_op_asr_16_s, 0xf1f8, 0xe040, { 6, 6, 6, 6, 6, 6, 6}}, + {m68000_base_device_ops::m68k_op_lsr_16_s, 0xf1f8, 0xe048, { 6, 6, 4, 4, 4, 4, 4}}, + {m68000_base_device_ops::m68k_op_roxr_16_s, 0xf1f8, 0xe050, { 6, 6, 12, 12, 12, 12, 12}}, + {m68000_base_device_ops::m68k_op_ror_16_s, 0xf1f8, 0xe058, { 6, 6, 8, 8, 8, 8, 8}}, + {m68000_base_device_ops::m68k_op_asr_16_r, 0xf1f8, 0xe060, { 6, 6, 6, 6, 6, 6, 6}}, + {m68000_base_device_ops::m68k_op_lsr_16_r, 0xf1f8, 0xe068, { 6, 6, 6, 6, 6, 6, 6}}, + {m68000_base_device_ops::m68k_op_roxr_16_r, 0xf1f8, 0xe070, { 6, 6, 12, 12, 12, 12, 12}}, + {m68000_base_device_ops::m68k_op_ror_16_r, 0xf1f8, 0xe078, { 6, 6, 8, 8, 8, 8, 8}}, + {m68000_base_device_ops::m68k_op_asr_32_s, 0xf1f8, 0xe080, { 8, 8, 6, 6, 6, 6, 6}}, + {m68000_base_device_ops::m68k_op_lsr_32_s, 0xf1f8, 0xe088, { 8, 8, 4, 4, 4, 4, 4}}, + {m68000_base_device_ops::m68k_op_roxr_32_s, 0xf1f8, 0xe090, { 8, 8, 12, 12, 12, 12, 12}}, + {m68000_base_device_ops::m68k_op_ror_32_s, 0xf1f8, 0xe098, { 8, 8, 8, 8, 8, 8, 8}}, + {m68000_base_device_ops::m68k_op_asr_32_r, 0xf1f8, 0xe0a0, { 8, 8, 6, 6, 6, 6, 6}}, + {m68000_base_device_ops::m68k_op_lsr_32_r, 0xf1f8, 0xe0a8, { 8, 8, 6, 6, 6, 6, 6}}, + {m68000_base_device_ops::m68k_op_roxr_32_r, 0xf1f8, 0xe0b0, { 8, 8, 12, 12, 12, 12, 12}}, + {m68000_base_device_ops::m68k_op_ror_32_r, 0xf1f8, 0xe0b8, { 8, 8, 8, 8, 8, 8, 8}}, + {m68000_base_device_ops::m68k_op_asl_8_s, 0xf1f8, 0xe100, { 6, 6, 8, 8, 8, 8, 8}}, + {m68000_base_device_ops::m68k_op_lsl_8_s, 0xf1f8, 0xe108, { 6, 6, 4, 4, 4, 4, 4}}, + {m68000_base_device_ops::m68k_op_roxl_8_s, 0xf1f8, 0xe110, { 6, 6, 12, 12, 12, 12, 12}}, + {m68000_base_device_ops::m68k_op_rol_8_s, 0xf1f8, 0xe118, { 6, 6, 8, 8, 8, 8, 8}}, + {m68000_base_device_ops::m68k_op_asl_8_r, 0xf1f8, 0xe120, { 6, 6, 8, 8, 8, 8, 8}}, + {m68000_base_device_ops::m68k_op_lsl_8_r, 0xf1f8, 0xe128, { 6, 6, 6, 6, 6, 6, 6}}, + {m68000_base_device_ops::m68k_op_roxl_8_r, 0xf1f8, 0xe130, { 6, 6, 12, 12, 12, 12, 12}}, + {m68000_base_device_ops::m68k_op_rol_8_r, 0xf1f8, 0xe138, { 6, 6, 8, 8, 8, 8, 8}}, + {m68000_base_device_ops::m68k_op_asl_16_s, 0xf1f8, 0xe140, { 6, 6, 8, 8, 8, 8, 8}}, + {m68000_base_device_ops::m68k_op_lsl_16_s, 0xf1f8, 0xe148, { 6, 6, 4, 4, 4, 4, 4}}, + {m68000_base_device_ops::m68k_op_roxl_16_s, 0xf1f8, 0xe150, { 6, 6, 12, 12, 12, 12, 12}}, + {m68000_base_device_ops::m68k_op_rol_16_s, 0xf1f8, 0xe158, { 6, 6, 8, 8, 8, 8, 8}}, + {m68000_base_device_ops::m68k_op_asl_16_r, 0xf1f8, 0xe160, { 6, 6, 8, 8, 8, 8, 8}}, + {m68000_base_device_ops::m68k_op_lsl_16_r, 0xf1f8, 0xe168, { 6, 6, 6, 6, 6, 6, 6}}, + {m68000_base_device_ops::m68k_op_roxl_16_r, 0xf1f8, 0xe170, { 6, 6, 12, 12, 12, 12, 12}}, + {m68000_base_device_ops::m68k_op_rol_16_r, 0xf1f8, 0xe178, { 6, 6, 8, 8, 8, 8, 8}}, + {m68000_base_device_ops::m68k_op_asl_32_s, 0xf1f8, 0xe180, { 8, 8, 8, 8, 8, 8, 8}}, + {m68000_base_device_ops::m68k_op_lsl_32_s, 0xf1f8, 0xe188, { 8, 8, 4, 4, 4, 4, 4}}, + {m68000_base_device_ops::m68k_op_roxl_32_s, 0xf1f8, 0xe190, { 8, 8, 12, 12, 12, 12, 12}}, + {m68000_base_device_ops::m68k_op_rol_32_s, 0xf1f8, 0xe198, { 8, 8, 8, 8, 8, 8, 8}}, + {m68000_base_device_ops::m68k_op_asl_32_r, 0xf1f8, 0xe1a0, { 8, 8, 8, 8, 8, 8, 8}}, + {m68000_base_device_ops::m68k_op_lsl_32_r, 0xf1f8, 0xe1a8, { 8, 8, 6, 6, 6, 6, 6}}, + {m68000_base_device_ops::m68k_op_roxl_32_r, 0xf1f8, 0xe1b0, { 8, 8, 12, 12, 12, 12, 12}}, + {m68000_base_device_ops::m68k_op_rol_32_r, 0xf1f8, 0xe1b8, { 8, 8, 8, 8, 8, 8, 8}}, + {m68000_base_device_ops::m68k_op_cpdbcc_32, 0xf1f8, 0xf048, {255, 255, 4, 4, 255, 255, 255}}, + {m68000_base_device_ops::m68k_op_cptrapcc_32, 0xf1f8, 0xf078, {255, 255, 4, 4, 255, 255, 255}}, + {m68000_base_device_ops::m68k_op_ptest_32, 0xffd8, 0xf548, {255, 255, 255, 255, 8, 255, 255}}, + {m68000_base_device_ops::m68k_op_rtm_32, 0xfff0, 0x06c0, {255, 255, 19, 19, 19, 19, 19}}, + {m68000_base_device_ops::m68k_op_trap, 0xfff0, 0x4e40, { 4, 4, 4, 4, 4, 4, 4}}, + {m68000_base_device_ops::m68k_op_btst_8_r_pi7, 0xf1ff, 0x011f, { 8, 8, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_btst_8_r_pd7, 0xf1ff, 0x0127, { 10, 10, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_btst_8_r_aw, 0xf1ff, 0x0138, { 12, 12, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_btst_8_r_al, 0xf1ff, 0x0139, { 16, 16, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_btst_8_r_pcdi, 0xf1ff, 0x013a, { 12, 12, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_btst_8_r_pcix, 0xf1ff, 0x013b, { 14, 14, 11, 11, 11, 11, 4}}, + {m68000_base_device_ops::m68k_op_btst_8_r_i, 0xf1ff, 0x013c, { 8, 8, 6, 6, 6, 6, 4}}, + {m68000_base_device_ops::m68k_op_bchg_8_r_pi7, 0xf1ff, 0x015f, { 12, 12, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_bchg_8_r_pd7, 0xf1ff, 0x0167, { 14, 14, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_bchg_8_r_aw, 0xf1ff, 0x0178, { 16, 16, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_bchg_8_r_al, 0xf1ff, 0x0179, { 20, 20, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_bclr_8_r_pi7, 0xf1ff, 0x019f, { 12, 14, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_bclr_8_r_pd7, 0xf1ff, 0x01a7, { 14, 16, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_bclr_8_r_aw, 0xf1ff, 0x01b8, { 16, 18, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_bclr_8_r_al, 0xf1ff, 0x01b9, { 20, 22, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_bset_8_r_pi7, 0xf1ff, 0x01df, { 12, 12, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_bset_8_r_pd7, 0xf1ff, 0x01e7, { 14, 14, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_bset_8_r_aw, 0xf1ff, 0x01f8, { 16, 16, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_bset_8_r_al, 0xf1ff, 0x01f9, { 20, 20, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_move_8_d_pi7, 0xf1ff, 0x101f, { 8, 8, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_move_8_d_pd7, 0xf1ff, 0x1027, { 10, 10, 7, 7, 7, 7, 2}}, + {m68000_base_device_ops::m68k_op_move_8_d_aw, 0xf1ff, 0x1038, { 12, 12, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_move_8_d_al, 0xf1ff, 0x1039, { 16, 16, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_move_8_d_pcdi, 0xf1ff, 0x103a, { 12, 12, 7, 7, 7, 7, 2}}, + {m68000_base_device_ops::m68k_op_move_8_d_pcix, 0xf1ff, 0x103b, { 14, 14, 9, 9, 9, 9, 2}}, + {m68000_base_device_ops::m68k_op_move_8_d_i, 0xf1ff, 0x103c, { 8, 8, 4, 4, 4, 4, 2}}, + {m68000_base_device_ops::m68k_op_move_8_ai_pi7, 0xf1ff, 0x109f, { 12, 12, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_move_8_ai_pd7, 0xf1ff, 0x10a7, { 14, 14, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_move_8_ai_aw, 0xf1ff, 0x10b8, { 16, 16, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_move_8_ai_al, 0xf1ff, 0x10b9, { 20, 20, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_move_8_ai_pcdi, 0xf1ff, 0x10ba, { 16, 16, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_move_8_ai_pcix, 0xf1ff, 0x10bb, { 18, 18, 11, 11, 11, 11, 4}}, + {m68000_base_device_ops::m68k_op_move_8_ai_i, 0xf1ff, 0x10bc, { 12, 12, 6, 6, 6, 6, 4}}, + {m68000_base_device_ops::m68k_op_move_8_pi_pi7, 0xf1ff, 0x10df, { 12, 12, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_move_8_pi_pd7, 0xf1ff, 0x10e7, { 14, 14, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_move_8_pi_aw, 0xf1ff, 0x10f8, { 16, 16, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_move_8_pi_al, 0xf1ff, 0x10f9, { 20, 20, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_move_8_pi_pcdi, 0xf1ff, 0x10fa, { 16, 16, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_move_8_pi_pcix, 0xf1ff, 0x10fb, { 18, 18, 11, 11, 11, 11, 4}}, + {m68000_base_device_ops::m68k_op_move_8_pi_i, 0xf1ff, 0x10fc, { 12, 12, 6, 6, 6, 6, 4}}, + {m68000_base_device_ops::m68k_op_move_8_pd_pi7, 0xf1ff, 0x111f, { 12, 12, 9, 9, 9, 9, 5}}, + {m68000_base_device_ops::m68k_op_move_8_pd_pd7, 0xf1ff, 0x1127, { 14, 14, 10, 10, 10, 10, 5}}, + {m68000_base_device_ops::m68k_op_move_8_pd_aw, 0xf1ff, 0x1138, { 16, 16, 9, 9, 9, 9, 5}}, + {m68000_base_device_ops::m68k_op_move_8_pd_al, 0xf1ff, 0x1139, { 20, 20, 9, 9, 9, 9, 5}}, + {m68000_base_device_ops::m68k_op_move_8_pd_pcdi, 0xf1ff, 0x113a, { 16, 16, 10, 10, 10, 10, 5}}, + {m68000_base_device_ops::m68k_op_move_8_pd_pcix, 0xf1ff, 0x113b, { 18, 18, 12, 12, 12, 12, 5}}, + {m68000_base_device_ops::m68k_op_move_8_pd_i, 0xf1ff, 0x113c, { 12, 12, 7, 7, 7, 7, 5}}, + {m68000_base_device_ops::m68k_op_move_8_di_pi7, 0xf1ff, 0x115f, { 16, 16, 9, 9, 9, 9, 5}}, + {m68000_base_device_ops::m68k_op_move_8_di_pd7, 0xf1ff, 0x1167, { 18, 18, 10, 10, 10, 10, 5}}, + {m68000_base_device_ops::m68k_op_move_8_di_aw, 0xf1ff, 0x1178, { 20, 20, 9, 9, 9, 9, 5}}, + {m68000_base_device_ops::m68k_op_move_8_di_al, 0xf1ff, 0x1179, { 24, 24, 9, 9, 9, 9, 5}}, + {m68000_base_device_ops::m68k_op_move_8_di_pcdi, 0xf1ff, 0x117a, { 20, 20, 10, 10, 10, 10, 5}}, + {m68000_base_device_ops::m68k_op_move_8_di_pcix, 0xf1ff, 0x117b, { 22, 22, 12, 12, 12, 12, 5}}, + {m68000_base_device_ops::m68k_op_move_8_di_i, 0xf1ff, 0x117c, { 16, 16, 7, 7, 7, 7, 5}}, + {m68000_base_device_ops::m68k_op_move_8_ix_pi7, 0xf1ff, 0x119f, { 18, 18, 11, 11, 11, 11, 7}}, + {m68000_base_device_ops::m68k_op_move_8_ix_pd7, 0xf1ff, 0x11a7, { 20, 20, 12, 12, 12, 12, 7}}, + {m68000_base_device_ops::m68k_op_move_8_ix_aw, 0xf1ff, 0x11b8, { 22, 22, 11, 11, 11, 11, 7}}, + {m68000_base_device_ops::m68k_op_move_8_ix_al, 0xf1ff, 0x11b9, { 26, 26, 11, 11, 11, 11, 7}}, + {m68000_base_device_ops::m68k_op_move_8_ix_pcdi, 0xf1ff, 0x11ba, { 22, 22, 12, 12, 12, 12, 7}}, + {m68000_base_device_ops::m68k_op_move_8_ix_pcix, 0xf1ff, 0x11bb, { 24, 24, 14, 14, 14, 14, 7}}, + {m68000_base_device_ops::m68k_op_move_8_ix_i, 0xf1ff, 0x11bc, { 18, 18, 9, 9, 9, 9, 7}}, + {m68000_base_device_ops::m68k_op_move_32_d_aw, 0xf1ff, 0x2038, { 16, 16, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_move_32_d_al, 0xf1ff, 0x2039, { 20, 20, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_move_32_d_pcdi, 0xf1ff, 0x203a, { 16, 16, 7, 7, 7, 7, 2}}, + {m68000_base_device_ops::m68k_op_move_32_d_pcix, 0xf1ff, 0x203b, { 18, 18, 9, 9, 9, 9, 2}}, + {m68000_base_device_ops::m68k_op_move_32_d_i, 0xf1ff, 0x203c, { 12, 12, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_movea_32_aw, 0xf1ff, 0x2078, { 16, 16, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_movea_32_al, 0xf1ff, 0x2079, { 20, 20, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_movea_32_pcdi, 0xf1ff, 0x207a, { 16, 16, 7, 7, 7, 7, 2}}, + {m68000_base_device_ops::m68k_op_movea_32_pcix, 0xf1ff, 0x207b, { 18, 18, 9, 9, 9, 9, 2}}, + {m68000_base_device_ops::m68k_op_movea_32_i, 0xf1ff, 0x207c, { 12, 12, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_move_32_ai_aw, 0xf1ff, 0x20b8, { 24, 24, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_move_32_ai_al, 0xf1ff, 0x20b9, { 28, 28, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_move_32_ai_pcdi, 0xf1ff, 0x20ba, { 24, 24, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_move_32_ai_pcix, 0xf1ff, 0x20bb, { 26, 26, 11, 11, 11, 11, 4}}, + {m68000_base_device_ops::m68k_op_move_32_ai_i, 0xf1ff, 0x20bc, { 20, 20, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_move_32_pi_aw, 0xf1ff, 0x20f8, { 24, 24, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_move_32_pi_al, 0xf1ff, 0x20f9, { 28, 28, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_move_32_pi_pcdi, 0xf1ff, 0x20fa, { 24, 24, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_move_32_pi_pcix, 0xf1ff, 0x20fb, { 26, 26, 11, 11, 11, 11, 4}}, + {m68000_base_device_ops::m68k_op_move_32_pi_i, 0xf1ff, 0x20fc, { 20, 20, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_move_32_pd_aw, 0xf1ff, 0x2138, { 24, 26, 9, 9, 9, 9, 5}}, + {m68000_base_device_ops::m68k_op_move_32_pd_al, 0xf1ff, 0x2139, { 28, 30, 9, 9, 9, 9, 5}}, + {m68000_base_device_ops::m68k_op_move_32_pd_pcdi, 0xf1ff, 0x213a, { 24, 26, 10, 10, 10, 10, 5}}, + {m68000_base_device_ops::m68k_op_move_32_pd_pcix, 0xf1ff, 0x213b, { 26, 28, 12, 12, 12, 12, 5}}, + {m68000_base_device_ops::m68k_op_move_32_pd_i, 0xf1ff, 0x213c, { 20, 22, 9, 9, 9, 9, 5}}, + {m68000_base_device_ops::m68k_op_move_32_di_aw, 0xf1ff, 0x2178, { 28, 28, 9, 9, 9, 9, 5}}, + {m68000_base_device_ops::m68k_op_move_32_di_al, 0xf1ff, 0x2179, { 32, 32, 9, 9, 9, 9, 5}}, + {m68000_base_device_ops::m68k_op_move_32_di_pcdi, 0xf1ff, 0x217a, { 28, 28, 10, 10, 10, 10, 5}}, + {m68000_base_device_ops::m68k_op_move_32_di_pcix, 0xf1ff, 0x217b, { 30, 30, 12, 12, 12, 12, 5}}, + {m68000_base_device_ops::m68k_op_move_32_di_i, 0xf1ff, 0x217c, { 24, 24, 9, 9, 9, 9, 5}}, + {m68000_base_device_ops::m68k_op_move_32_ix_aw, 0xf1ff, 0x21b8, { 30, 30, 11, 11, 11, 11, 7}}, + {m68000_base_device_ops::m68k_op_move_32_ix_al, 0xf1ff, 0x21b9, { 34, 34, 11, 11, 11, 11, 7}}, + {m68000_base_device_ops::m68k_op_move_32_ix_pcdi, 0xf1ff, 0x21ba, { 30, 30, 12, 12, 12, 12, 7}}, + {m68000_base_device_ops::m68k_op_move_32_ix_pcix, 0xf1ff, 0x21bb, { 32, 32, 14, 14, 14, 14, 7}}, + {m68000_base_device_ops::m68k_op_move_32_ix_i, 0xf1ff, 0x21bc, { 26, 26, 11, 11, 11, 11, 7}}, + {m68000_base_device_ops::m68k_op_move_16_d_aw, 0xf1ff, 0x3038, { 12, 12, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_move_16_d_al, 0xf1ff, 0x3039, { 16, 16, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_move_16_d_pcdi, 0xf1ff, 0x303a, { 12, 12, 7, 7, 7, 7, 2}}, + {m68000_base_device_ops::m68k_op_move_16_d_pcix, 0xf1ff, 0x303b, { 14, 14, 9, 9, 9, 9, 2}}, + {m68000_base_device_ops::m68k_op_move_16_d_i, 0xf1ff, 0x303c, { 8, 8, 4, 4, 4, 4, 2}}, + {m68000_base_device_ops::m68k_op_movea_16_aw, 0xf1ff, 0x3078, { 12, 12, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_movea_16_al, 0xf1ff, 0x3079, { 16, 16, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_movea_16_pcdi, 0xf1ff, 0x307a, { 12, 12, 7, 7, 7, 7, 2}}, + {m68000_base_device_ops::m68k_op_movea_16_pcix, 0xf1ff, 0x307b, { 14, 14, 9, 9, 9, 9, 2}}, + {m68000_base_device_ops::m68k_op_movea_16_i, 0xf1ff, 0x307c, { 8, 8, 4, 4, 4, 4, 2}}, + {m68000_base_device_ops::m68k_op_move_16_ai_aw, 0xf1ff, 0x30b8, { 16, 16, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_move_16_ai_al, 0xf1ff, 0x30b9, { 20, 20, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_move_16_ai_pcdi, 0xf1ff, 0x30ba, { 16, 16, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_move_16_ai_pcix, 0xf1ff, 0x30bb, { 18, 18, 11, 11, 11, 11, 4}}, + {m68000_base_device_ops::m68k_op_move_16_ai_i, 0xf1ff, 0x30bc, { 12, 12, 6, 6, 6, 6, 4}}, + {m68000_base_device_ops::m68k_op_move_16_pi_aw, 0xf1ff, 0x30f8, { 16, 16, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_move_16_pi_al, 0xf1ff, 0x30f9, { 20, 20, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_move_16_pi_pcdi, 0xf1ff, 0x30fa, { 16, 16, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_move_16_pi_pcix, 0xf1ff, 0x30fb, { 18, 18, 11, 11, 11, 11, 4}}, + {m68000_base_device_ops::m68k_op_move_16_pi_i, 0xf1ff, 0x30fc, { 12, 12, 6, 6, 6, 6, 4}}, + {m68000_base_device_ops::m68k_op_move_16_pd_aw, 0xf1ff, 0x3138, { 16, 16, 9, 9, 9, 9, 5}}, + {m68000_base_device_ops::m68k_op_move_16_pd_al, 0xf1ff, 0x3139, { 20, 20, 9, 9, 9, 9, 5}}, + {m68000_base_device_ops::m68k_op_move_16_pd_pcdi, 0xf1ff, 0x313a, { 16, 16, 10, 10, 10, 10, 5}}, + {m68000_base_device_ops::m68k_op_move_16_pd_pcix, 0xf1ff, 0x313b, { 18, 18, 12, 12, 12, 12, 5}}, + {m68000_base_device_ops::m68k_op_move_16_pd_i, 0xf1ff, 0x313c, { 12, 12, 7, 7, 7, 7, 5}}, + {m68000_base_device_ops::m68k_op_move_16_di_aw, 0xf1ff, 0x3178, { 20, 20, 9, 9, 9, 9, 5}}, + {m68000_base_device_ops::m68k_op_move_16_di_al, 0xf1ff, 0x3179, { 24, 24, 9, 9, 9, 9, 5}}, + {m68000_base_device_ops::m68k_op_move_16_di_pcdi, 0xf1ff, 0x317a, { 20, 20, 10, 10, 10, 10, 5}}, + {m68000_base_device_ops::m68k_op_move_16_di_pcix, 0xf1ff, 0x317b, { 22, 22, 12, 12, 12, 12, 5}}, + {m68000_base_device_ops::m68k_op_move_16_di_i, 0xf1ff, 0x317c, { 16, 16, 7, 7, 7, 7, 5}}, + {m68000_base_device_ops::m68k_op_move_16_ix_aw, 0xf1ff, 0x31b8, { 22, 22, 11, 11, 11, 11, 7}}, + {m68000_base_device_ops::m68k_op_move_16_ix_al, 0xf1ff, 0x31b9, { 26, 26, 11, 11, 11, 11, 7}}, + {m68000_base_device_ops::m68k_op_move_16_ix_pcdi, 0xf1ff, 0x31ba, { 22, 22, 12, 12, 12, 12, 7}}, + {m68000_base_device_ops::m68k_op_move_16_ix_pcix, 0xf1ff, 0x31bb, { 24, 24, 14, 14, 14, 14, 7}}, + {m68000_base_device_ops::m68k_op_move_16_ix_i, 0xf1ff, 0x31bc, { 18, 18, 9, 9, 9, 9, 7}}, + {m68000_base_device_ops::m68k_op_chk_32_aw, 0xf1ff, 0x4138, {255, 255, 12, 12, 12, 12, 8}}, + {m68000_base_device_ops::m68k_op_chk_32_al, 0xf1ff, 0x4139, {255, 255, 12, 12, 12, 12, 8}}, + {m68000_base_device_ops::m68k_op_chk_32_pcdi, 0xf1ff, 0x413a, {255, 255, 13, 13, 13, 13, 8}}, + {m68000_base_device_ops::m68k_op_chk_32_pcix, 0xf1ff, 0x413b, {255, 255, 15, 15, 15, 15, 8}}, + {m68000_base_device_ops::m68k_op_chk_32_i, 0xf1ff, 0x413c, {255, 255, 12, 12, 12, 12, 8}}, + {m68000_base_device_ops::m68k_op_chk_16_aw, 0xf1ff, 0x41b8, { 18, 16, 12, 12, 12, 12, 8}}, + {m68000_base_device_ops::m68k_op_chk_16_al, 0xf1ff, 0x41b9, { 22, 20, 12, 12, 12, 12, 8}}, + {m68000_base_device_ops::m68k_op_chk_16_pcdi, 0xf1ff, 0x41ba, { 18, 16, 13, 13, 13, 13, 8}}, + {m68000_base_device_ops::m68k_op_chk_16_pcix, 0xf1ff, 0x41bb, { 20, 18, 15, 15, 15, 15, 8}}, + {m68000_base_device_ops::m68k_op_chk_16_i, 0xf1ff, 0x41bc, { 14, 12, 10, 10, 10, 10, 8}}, + {m68000_base_device_ops::m68k_op_lea_32_aw, 0xf1ff, 0x41f8, { 8, 8, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_lea_32_al, 0xf1ff, 0x41f9, { 12, 12, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_lea_32_pcdi, 0xf1ff, 0x41fa, { 8, 8, 7, 7, 7, 7, 2}}, + {m68000_base_device_ops::m68k_op_lea_32_pcix, 0xf1ff, 0x41fb, { 12, 12, 9, 9, 9, 9, 2}}, + {m68000_base_device_ops::m68k_op_addq_8_pi7, 0xf1ff, 0x501f, { 12, 12, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_addq_8_pd7, 0xf1ff, 0x5027, { 14, 14, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_addq_8_aw, 0xf1ff, 0x5038, { 16, 16, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_addq_8_al, 0xf1ff, 0x5039, { 20, 20, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_addq_16_aw, 0xf1ff, 0x5078, { 16, 16, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_addq_16_al, 0xf1ff, 0x5079, { 20, 20, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_addq_32_aw, 0xf1ff, 0x50b8, { 24, 24, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_addq_32_al, 0xf1ff, 0x50b9, { 28, 28, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_subq_8_pi7, 0xf1ff, 0x511f, { 12, 12, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_subq_8_pd7, 0xf1ff, 0x5127, { 14, 14, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_subq_8_aw, 0xf1ff, 0x5138, { 16, 16, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_subq_8_al, 0xf1ff, 0x5139, { 20, 20, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_subq_16_aw, 0xf1ff, 0x5178, { 16, 16, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_subq_16_al, 0xf1ff, 0x5179, { 20, 20, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_subq_32_aw, 0xf1ff, 0x51b8, { 24, 24, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_subq_32_al, 0xf1ff, 0x51b9, { 28, 28, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_or_8_er_pi7, 0xf1ff, 0x801f, { 8, 8, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_or_8_er_pd7, 0xf1ff, 0x8027, { 10, 10, 7, 7, 7, 7, 2}}, + {m68000_base_device_ops::m68k_op_or_8_er_aw, 0xf1ff, 0x8038, { 12, 12, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_or_8_er_al, 0xf1ff, 0x8039, { 16, 16, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_or_8_er_pcdi, 0xf1ff, 0x803a, { 12, 12, 7, 7, 7, 7, 2}}, + {m68000_base_device_ops::m68k_op_or_8_er_pcix, 0xf1ff, 0x803b, { 14, 14, 9, 9, 9, 9, 2}}, + {m68000_base_device_ops::m68k_op_or_8_er_i, 0xf1ff, 0x803c, { 8, 8, 4, 4, 4, 4, 2}}, + {m68000_base_device_ops::m68k_op_or_16_er_aw, 0xf1ff, 0x8078, { 12, 12, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_or_16_er_al, 0xf1ff, 0x8079, { 16, 16, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_or_16_er_pcdi, 0xf1ff, 0x807a, { 12, 12, 7, 7, 7, 7, 2}}, + {m68000_base_device_ops::m68k_op_or_16_er_pcix, 0xf1ff, 0x807b, { 14, 14, 9, 9, 9, 9, 2}}, + {m68000_base_device_ops::m68k_op_or_16_er_i, 0xf1ff, 0x807c, { 8, 8, 4, 4, 4, 4, 2}}, + {m68000_base_device_ops::m68k_op_or_32_er_aw, 0xf1ff, 0x80b8, { 18, 18, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_or_32_er_al, 0xf1ff, 0x80b9, { 22, 22, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_or_32_er_pcdi, 0xf1ff, 0x80ba, { 18, 18, 7, 7, 7, 7, 2}}, + {m68000_base_device_ops::m68k_op_or_32_er_pcix, 0xf1ff, 0x80bb, { 20, 20, 9, 9, 9, 9, 2}}, + {m68000_base_device_ops::m68k_op_or_32_er_i, 0xf1ff, 0x80bc, { 16, 14, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_divu_16_aw, 0xf1ff, 0x80f8, {148, 116, 48, 48, 48, 48, 44}}, + {m68000_base_device_ops::m68k_op_divu_16_al, 0xf1ff, 0x80f9, {152, 120, 48, 48, 48, 48, 44}}, + {m68000_base_device_ops::m68k_op_divu_16_pcdi, 0xf1ff, 0x80fa, {148, 116, 49, 49, 49, 49, 44}}, + {m68000_base_device_ops::m68k_op_divu_16_pcix, 0xf1ff, 0x80fb, {150, 118, 51, 51, 51, 51, 44}}, + {m68000_base_device_ops::m68k_op_divu_16_i, 0xf1ff, 0x80fc, {144, 112, 46, 46, 46, 46, 44}}, + {m68000_base_device_ops::m68k_op_sbcd_8_mm_ay7, 0xf1ff, 0x810f, { 18, 18, 16, 16, 16, 16, 16}}, + {m68000_base_device_ops::m68k_op_or_8_re_pi7, 0xf1ff, 0x811f, { 12, 12, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_or_8_re_pd7, 0xf1ff, 0x8127, { 14, 14, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_or_8_re_aw, 0xf1ff, 0x8138, { 16, 16, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_or_8_re_al, 0xf1ff, 0x8139, { 20, 20, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_pack_16_mm_ay7, 0xf1ff, 0x814f, {255, 255, 13, 13, 13, 13, 13}}, + {m68000_base_device_ops::m68k_op_or_16_re_aw, 0xf1ff, 0x8178, { 16, 16, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_or_16_re_al, 0xf1ff, 0x8179, { 20, 20, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_unpk_16_mm_ay7, 0xf1ff, 0x818f, {255, 255, 13, 13, 13, 13, 13}}, + {m68000_base_device_ops::m68k_op_or_32_re_aw, 0xf1ff, 0x81b8, { 24, 24, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_or_32_re_al, 0xf1ff, 0x81b9, { 28, 28, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_divs_16_aw, 0xf1ff, 0x81f8, {166, 130, 60, 60, 60, 60, 56}}, + {m68000_base_device_ops::m68k_op_divs_16_al, 0xf1ff, 0x81f9, {170, 134, 60, 60, 60, 60, 56}}, + {m68000_base_device_ops::m68k_op_divs_16_pcdi, 0xf1ff, 0x81fa, {166, 130, 61, 61, 61, 61, 56}}, + {m68000_base_device_ops::m68k_op_divs_16_pcix, 0xf1ff, 0x81fb, {168, 132, 63, 63, 63, 63, 56}}, + {m68000_base_device_ops::m68k_op_divs_16_i, 0xf1ff, 0x81fc, {162, 126, 58, 58, 58, 58, 56}}, + {m68000_base_device_ops::m68k_op_sub_8_er_pi7, 0xf1ff, 0x901f, { 8, 8, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_sub_8_er_pd7, 0xf1ff, 0x9027, { 10, 10, 7, 7, 7, 7, 2}}, + {m68000_base_device_ops::m68k_op_sub_8_er_aw, 0xf1ff, 0x9038, { 12, 12, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_sub_8_er_al, 0xf1ff, 0x9039, { 16, 16, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_sub_8_er_pcdi, 0xf1ff, 0x903a, { 12, 12, 7, 7, 7, 7, 2}}, + {m68000_base_device_ops::m68k_op_sub_8_er_pcix, 0xf1ff, 0x903b, { 14, 14, 9, 9, 9, 9, 2}}, + {m68000_base_device_ops::m68k_op_sub_8_er_i, 0xf1ff, 0x903c, { 8, 8, 4, 4, 4, 4, 2}}, + {m68000_base_device_ops::m68k_op_sub_16_er_aw, 0xf1ff, 0x9078, { 12, 12, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_sub_16_er_al, 0xf1ff, 0x9079, { 16, 16, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_sub_16_er_pcdi, 0xf1ff, 0x907a, { 12, 12, 7, 7, 7, 7, 2}}, + {m68000_base_device_ops::m68k_op_sub_16_er_pcix, 0xf1ff, 0x907b, { 14, 14, 9, 9, 9, 9, 2}}, + {m68000_base_device_ops::m68k_op_sub_16_er_i, 0xf1ff, 0x907c, { 8, 8, 4, 4, 4, 4, 2}}, + {m68000_base_device_ops::m68k_op_sub_32_er_aw, 0xf1ff, 0x90b8, { 18, 18, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_sub_32_er_al, 0xf1ff, 0x90b9, { 22, 22, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_sub_32_er_pcdi, 0xf1ff, 0x90ba, { 18, 18, 7, 7, 7, 7, 2}}, + {m68000_base_device_ops::m68k_op_sub_32_er_pcix, 0xf1ff, 0x90bb, { 20, 20, 9, 9, 9, 9, 2}}, + {m68000_base_device_ops::m68k_op_sub_32_er_i, 0xf1ff, 0x90bc, { 16, 14, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_suba_16_aw, 0xf1ff, 0x90f8, { 16, 16, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_suba_16_al, 0xf1ff, 0x90f9, { 20, 20, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_suba_16_pcdi, 0xf1ff, 0x90fa, { 16, 16, 7, 7, 7, 7, 2}}, + {m68000_base_device_ops::m68k_op_suba_16_pcix, 0xf1ff, 0x90fb, { 18, 18, 9, 9, 9, 9, 2}}, + {m68000_base_device_ops::m68k_op_suba_16_i, 0xf1ff, 0x90fc, { 12, 12, 4, 4, 4, 4, 2}}, + {m68000_base_device_ops::m68k_op_subx_8_mm_ay7, 0xf1ff, 0x910f, { 18, 18, 12, 12, 12, 12, 12}}, + {m68000_base_device_ops::m68k_op_sub_8_re_pi7, 0xf1ff, 0x911f, { 12, 12, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_sub_8_re_pd7, 0xf1ff, 0x9127, { 14, 14, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_sub_8_re_aw, 0xf1ff, 0x9138, { 16, 16, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_sub_8_re_al, 0xf1ff, 0x9139, { 20, 20, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_sub_16_re_aw, 0xf1ff, 0x9178, { 16, 16, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_sub_16_re_al, 0xf1ff, 0x9179, { 20, 20, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_sub_32_re_aw, 0xf1ff, 0x91b8, { 24, 24, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_sub_32_re_al, 0xf1ff, 0x91b9, { 28, 28, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_suba_32_aw, 0xf1ff, 0x91f8, { 18, 18, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_suba_32_al, 0xf1ff, 0x91f9, { 22, 22, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_suba_32_pcdi, 0xf1ff, 0x91fa, { 18, 18, 7, 7, 7, 7, 2}}, + {m68000_base_device_ops::m68k_op_suba_32_pcix, 0xf1ff, 0x91fb, { 20, 20, 9, 9, 9, 9, 2}}, + {m68000_base_device_ops::m68k_op_suba_32_i, 0xf1ff, 0x91fc, { 16, 14, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_cmp_8_pi7, 0xf1ff, 0xb01f, { 8, 8, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_cmp_8_pd7, 0xf1ff, 0xb027, { 10, 10, 7, 7, 7, 7, 2}}, + {m68000_base_device_ops::m68k_op_cmp_8_aw, 0xf1ff, 0xb038, { 12, 12, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_cmp_8_al, 0xf1ff, 0xb039, { 16, 16, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_cmp_8_pcdi, 0xf1ff, 0xb03a, { 12, 12, 7, 7, 7, 7, 2}}, + {m68000_base_device_ops::m68k_op_cmp_8_pcix, 0xf1ff, 0xb03b, { 14, 14, 9, 9, 9, 9, 2}}, + {m68000_base_device_ops::m68k_op_cmp_8_i, 0xf1ff, 0xb03c, { 8, 8, 4, 4, 4, 4, 2}}, + {m68000_base_device_ops::m68k_op_cmp_16_aw, 0xf1ff, 0xb078, { 12, 12, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_cmp_16_al, 0xf1ff, 0xb079, { 16, 16, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_cmp_16_pcdi, 0xf1ff, 0xb07a, { 12, 12, 7, 7, 7, 7, 2}}, + {m68000_base_device_ops::m68k_op_cmp_16_pcix, 0xf1ff, 0xb07b, { 14, 14, 9, 9, 9, 9, 2}}, + {m68000_base_device_ops::m68k_op_cmp_16_i, 0xf1ff, 0xb07c, { 8, 8, 4, 4, 4, 4, 2}}, + {m68000_base_device_ops::m68k_op_cmp_32_aw, 0xf1ff, 0xb0b8, { 18, 18, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_cmp_32_al, 0xf1ff, 0xb0b9, { 22, 22, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_cmp_32_pcdi, 0xf1ff, 0xb0ba, { 18, 18, 7, 7, 7, 7, 2}}, + {m68000_base_device_ops::m68k_op_cmp_32_pcix, 0xf1ff, 0xb0bb, { 20, 20, 9, 9, 9, 9, 2}}, + {m68000_base_device_ops::m68k_op_cmp_32_i, 0xf1ff, 0xb0bc, { 14, 14, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_cmpa_16_aw, 0xf1ff, 0xb0f8, { 14, 14, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_cmpa_16_al, 0xf1ff, 0xb0f9, { 18, 18, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_cmpa_16_pcdi, 0xf1ff, 0xb0fa, { 14, 14, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_cmpa_16_pcix, 0xf1ff, 0xb0fb, { 16, 16, 11, 11, 11, 11, 4}}, + {m68000_base_device_ops::m68k_op_cmpa_16_i, 0xf1ff, 0xb0fc, { 10, 10, 6, 6, 6, 6, 4}}, + {m68000_base_device_ops::m68k_op_cmpm_8_ay7, 0xf1ff, 0xb10f, { 12, 12, 9, 9, 9, 9, 9}}, + {m68000_base_device_ops::m68k_op_eor_8_pi7, 0xf1ff, 0xb11f, { 12, 12, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_eor_8_pd7, 0xf1ff, 0xb127, { 14, 14, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_eor_8_aw, 0xf1ff, 0xb138, { 16, 16, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_eor_8_al, 0xf1ff, 0xb139, { 20, 20, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_eor_16_aw, 0xf1ff, 0xb178, { 16, 16, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_eor_16_al, 0xf1ff, 0xb179, { 20, 20, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_eor_32_aw, 0xf1ff, 0xb1b8, { 24, 24, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_eor_32_al, 0xf1ff, 0xb1b9, { 28, 28, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_cmpa_32_aw, 0xf1ff, 0xb1f8, { 18, 18, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_cmpa_32_al, 0xf1ff, 0xb1f9, { 22, 22, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_cmpa_32_pcdi, 0xf1ff, 0xb1fa, { 18, 18, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_cmpa_32_pcix, 0xf1ff, 0xb1fb, { 20, 20, 11, 11, 11, 11, 4}}, + {m68000_base_device_ops::m68k_op_cmpa_32_i, 0xf1ff, 0xb1fc, { 14, 14, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_and_8_er_pi7, 0xf1ff, 0xc01f, { 8, 8, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_and_8_er_pd7, 0xf1ff, 0xc027, { 10, 10, 7, 7, 7, 7, 2}}, + {m68000_base_device_ops::m68k_op_and_8_er_aw, 0xf1ff, 0xc038, { 12, 12, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_and_8_er_al, 0xf1ff, 0xc039, { 16, 16, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_and_8_er_pcdi, 0xf1ff, 0xc03a, { 12, 12, 7, 7, 7, 7, 2}}, + {m68000_base_device_ops::m68k_op_and_8_er_pcix, 0xf1ff, 0xc03b, { 14, 14, 9, 9, 9, 9, 2}}, + {m68000_base_device_ops::m68k_op_and_8_er_i, 0xf1ff, 0xc03c, { 8, 8, 4, 4, 4, 4, 2}}, + {m68000_base_device_ops::m68k_op_and_16_er_aw, 0xf1ff, 0xc078, { 12, 12, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_and_16_er_al, 0xf1ff, 0xc079, { 16, 16, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_and_16_er_pcdi, 0xf1ff, 0xc07a, { 12, 12, 7, 7, 7, 7, 2}}, + {m68000_base_device_ops::m68k_op_and_16_er_pcix, 0xf1ff, 0xc07b, { 14, 14, 9, 9, 9, 9, 2}}, + {m68000_base_device_ops::m68k_op_and_16_er_i, 0xf1ff, 0xc07c, { 8, 8, 4, 4, 4, 4, 2}}, + {m68000_base_device_ops::m68k_op_and_32_er_aw, 0xf1ff, 0xc0b8, { 18, 18, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_and_32_er_al, 0xf1ff, 0xc0b9, { 22, 22, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_and_32_er_pcdi, 0xf1ff, 0xc0ba, { 18, 18, 7, 7, 7, 7, 2}}, + {m68000_base_device_ops::m68k_op_and_32_er_pcix, 0xf1ff, 0xc0bb, { 20, 20, 9, 9, 9, 9, 2}}, + {m68000_base_device_ops::m68k_op_and_32_er_i, 0xf1ff, 0xc0bc, { 16, 14, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_mulu_16_aw, 0xf1ff, 0xc0f8, { 62, 38, 31, 31, 31, 31, 27}}, + {m68000_base_device_ops::m68k_op_mulu_16_al, 0xf1ff, 0xc0f9, { 66, 42, 31, 31, 31, 31, 27}}, + {m68000_base_device_ops::m68k_op_mulu_16_pcdi, 0xf1ff, 0xc0fa, { 62, 38, 32, 32, 32, 32, 27}}, + {m68000_base_device_ops::m68k_op_mulu_16_pcix, 0xf1ff, 0xc0fb, { 64, 40, 34, 34, 34, 34, 27}}, + {m68000_base_device_ops::m68k_op_mulu_16_i, 0xf1ff, 0xc0fc, { 58, 34, 29, 29, 29, 29, 27}}, + {m68000_base_device_ops::m68k_op_abcd_8_mm_ay7, 0xf1ff, 0xc10f, { 18, 18, 16, 16, 16, 16, 16}}, + {m68000_base_device_ops::m68k_op_and_8_re_pi7, 0xf1ff, 0xc11f, { 12, 12, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_and_8_re_pd7, 0xf1ff, 0xc127, { 14, 14, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_and_8_re_aw, 0xf1ff, 0xc138, { 16, 16, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_and_8_re_al, 0xf1ff, 0xc139, { 20, 20, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_and_16_re_aw, 0xf1ff, 0xc178, { 16, 16, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_and_16_re_al, 0xf1ff, 0xc179, { 20, 20, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_and_32_re_aw, 0xf1ff, 0xc1b8, { 24, 24, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_and_32_re_al, 0xf1ff, 0xc1b9, { 28, 28, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_muls_16_aw, 0xf1ff, 0xc1f8, { 62, 40, 31, 31, 31, 31, 27}}, + {m68000_base_device_ops::m68k_op_muls_16_al, 0xf1ff, 0xc1f9, { 66, 44, 31, 31, 31, 31, 27}}, + {m68000_base_device_ops::m68k_op_muls_16_pcdi, 0xf1ff, 0xc1fa, { 62, 40, 32, 32, 32, 32, 27}}, + {m68000_base_device_ops::m68k_op_muls_16_pcix, 0xf1ff, 0xc1fb, { 64, 42, 34, 34, 34, 34, 27}}, + {m68000_base_device_ops::m68k_op_muls_16_i, 0xf1ff, 0xc1fc, { 58, 36, 29, 29, 29, 29, 27}}, + {m68000_base_device_ops::m68k_op_add_8_er_pi7, 0xf1ff, 0xd01f, { 8, 8, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_add_8_er_pd7, 0xf1ff, 0xd027, { 10, 10, 7, 7, 7, 7, 2}}, + {m68000_base_device_ops::m68k_op_add_8_er_aw, 0xf1ff, 0xd038, { 12, 12, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_add_8_er_al, 0xf1ff, 0xd039, { 16, 16, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_add_8_er_pcdi, 0xf1ff, 0xd03a, { 12, 12, 7, 7, 7, 7, 2}}, + {m68000_base_device_ops::m68k_op_add_8_er_pcix, 0xf1ff, 0xd03b, { 14, 14, 9, 9, 9, 9, 2}}, + {m68000_base_device_ops::m68k_op_add_8_er_i, 0xf1ff, 0xd03c, { 8, 8, 4, 4, 4, 4, 2}}, + {m68000_base_device_ops::m68k_op_add_16_er_aw, 0xf1ff, 0xd078, { 12, 12, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_add_16_er_al, 0xf1ff, 0xd079, { 16, 16, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_add_16_er_pcdi, 0xf1ff, 0xd07a, { 12, 12, 7, 7, 7, 7, 2}}, + {m68000_base_device_ops::m68k_op_add_16_er_pcix, 0xf1ff, 0xd07b, { 14, 14, 9, 9, 9, 9, 2}}, + {m68000_base_device_ops::m68k_op_add_16_er_i, 0xf1ff, 0xd07c, { 8, 8, 4, 4, 4, 4, 2}}, + {m68000_base_device_ops::m68k_op_add_32_er_aw, 0xf1ff, 0xd0b8, { 18, 18, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_add_32_er_al, 0xf1ff, 0xd0b9, { 22, 22, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_add_32_er_pcdi, 0xf1ff, 0xd0ba, { 18, 18, 7, 7, 7, 7, 2}}, + {m68000_base_device_ops::m68k_op_add_32_er_pcix, 0xf1ff, 0xd0bb, { 20, 20, 9, 9, 9, 9, 2}}, + {m68000_base_device_ops::m68k_op_add_32_er_i, 0xf1ff, 0xd0bc, { 16, 14, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_adda_16_aw, 0xf1ff, 0xd0f8, { 16, 16, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_adda_16_al, 0xf1ff, 0xd0f9, { 20, 20, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_adda_16_pcdi, 0xf1ff, 0xd0fa, { 16, 16, 7, 7, 7, 7, 2}}, + {m68000_base_device_ops::m68k_op_adda_16_pcix, 0xf1ff, 0xd0fb, { 18, 18, 9, 9, 9, 9, 2}}, + {m68000_base_device_ops::m68k_op_adda_16_i, 0xf1ff, 0xd0fc, { 12, 12, 4, 4, 4, 4, 2}}, + {m68000_base_device_ops::m68k_op_addx_8_mm_ay7, 0xf1ff, 0xd10f, { 18, 18, 12, 12, 12, 12, 12}}, + {m68000_base_device_ops::m68k_op_add_8_re_pi7, 0xf1ff, 0xd11f, { 12, 12, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_add_8_re_pd7, 0xf1ff, 0xd127, { 14, 14, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_add_8_re_aw, 0xf1ff, 0xd138, { 16, 16, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_add_8_re_al, 0xf1ff, 0xd139, { 20, 20, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_add_16_re_aw, 0xf1ff, 0xd178, { 16, 16, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_add_16_re_al, 0xf1ff, 0xd179, { 20, 20, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_add_32_re_aw, 0xf1ff, 0xd1b8, { 24, 24, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_add_32_re_al, 0xf1ff, 0xd1b9, { 28, 28, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_adda_32_aw, 0xf1ff, 0xd1f8, { 18, 18, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_adda_32_al, 0xf1ff, 0xd1f9, { 22, 22, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_adda_32_pcdi, 0xf1ff, 0xd1fa, { 18, 18, 7, 7, 7, 7, 2}}, + {m68000_base_device_ops::m68k_op_adda_32_pcix, 0xf1ff, 0xd1fb, { 20, 20, 9, 9, 9, 9, 2}}, + {m68000_base_device_ops::m68k_op_adda_32_i, 0xf1ff, 0xd1fc, { 16, 14, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_ori_8_d, 0xfff8, 0x0000, { 8, 8, 2, 2, 2, 2, 2}}, + {m68000_base_device_ops::m68k_op_ori_8_ai, 0xfff8, 0x0010, { 16, 16, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_ori_8_pi, 0xfff8, 0x0018, { 16, 16, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_ori_8_pd, 0xfff8, 0x0020, { 18, 18, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_ori_8_di, 0xfff8, 0x0028, { 20, 20, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_ori_8_ix, 0xfff8, 0x0030, { 22, 22, 11, 11, 11, 11, 4}}, + {m68000_base_device_ops::m68k_op_ori_16_d, 0xfff8, 0x0040, { 8, 8, 2, 2, 2, 2, 2}}, + {m68000_base_device_ops::m68k_op_ori_16_ai, 0xfff8, 0x0050, { 16, 16, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_ori_16_pi, 0xfff8, 0x0058, { 16, 16, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_ori_16_pd, 0xfff8, 0x0060, { 18, 18, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_ori_16_di, 0xfff8, 0x0068, { 20, 20, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_ori_16_ix, 0xfff8, 0x0070, { 22, 22, 11, 11, 11, 11, 4}}, + {m68000_base_device_ops::m68k_op_ori_32_d, 0xfff8, 0x0080, { 16, 14, 2, 2, 2, 2, 2}}, + {m68000_base_device_ops::m68k_op_ori_32_ai, 0xfff8, 0x0090, { 28, 28, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_ori_32_pi, 0xfff8, 0x0098, { 28, 28, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_ori_32_pd, 0xfff8, 0x00a0, { 30, 30, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_ori_32_di, 0xfff8, 0x00a8, { 32, 32, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_ori_32_ix, 0xfff8, 0x00b0, { 34, 34, 11, 11, 11, 11, 4}}, + {m68000_base_device_ops::m68k_op_chk2cmp2_8_ai, 0xfff8, 0x00d0, {255, 255, 22, 22, 22, 22, 18}}, + {m68000_base_device_ops::m68k_op_chk2cmp2_8_di, 0xfff8, 0x00e8, {255, 255, 23, 23, 23, 23, 18}}, + {m68000_base_device_ops::m68k_op_chk2cmp2_8_ix, 0xfff8, 0x00f0, {255, 255, 25, 25, 25, 25, 18}}, + {m68000_base_device_ops::m68k_op_andi_8_d, 0xfff8, 0x0200, { 8, 8, 2, 2, 2, 2, 2}}, + {m68000_base_device_ops::m68k_op_andi_8_ai, 0xfff8, 0x0210, { 16, 16, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_andi_8_pi, 0xfff8, 0x0218, { 16, 16, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_andi_8_pd, 0xfff8, 0x0220, { 18, 18, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_andi_8_di, 0xfff8, 0x0228, { 20, 20, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_andi_8_ix, 0xfff8, 0x0230, { 22, 22, 11, 11, 11, 11, 4}}, + {m68000_base_device_ops::m68k_op_andi_16_d, 0xfff8, 0x0240, { 8, 8, 2, 2, 2, 2, 2}}, + {m68000_base_device_ops::m68k_op_andi_16_ai, 0xfff8, 0x0250, { 16, 16, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_andi_16_pi, 0xfff8, 0x0258, { 16, 16, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_andi_16_pd, 0xfff8, 0x0260, { 18, 18, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_andi_16_di, 0xfff8, 0x0268, { 20, 20, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_andi_16_ix, 0xfff8, 0x0270, { 22, 22, 11, 11, 11, 11, 4}}, + {m68000_base_device_ops::m68k_op_andi_32_d, 0xfff8, 0x0280, { 14, 14, 2, 2, 2, 2, 2}}, + {m68000_base_device_ops::m68k_op_andi_32_ai, 0xfff8, 0x0290, { 28, 28, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_andi_32_pi, 0xfff8, 0x0298, { 28, 28, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_andi_32_pd, 0xfff8, 0x02a0, { 30, 30, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_andi_32_di, 0xfff8, 0x02a8, { 32, 32, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_andi_32_ix, 0xfff8, 0x02b0, { 34, 34, 11, 11, 11, 11, 4}}, + {m68000_base_device_ops::m68k_op_chk2cmp2_16_ai, 0xfff8, 0x02d0, {255, 255, 22, 22, 22, 22, 18}}, + {m68000_base_device_ops::m68k_op_chk2cmp2_16_di, 0xfff8, 0x02e8, {255, 255, 23, 23, 23, 23, 18}}, + {m68000_base_device_ops::m68k_op_chk2cmp2_16_ix, 0xfff8, 0x02f0, {255, 255, 25, 25, 25, 25, 18}}, + {m68000_base_device_ops::m68k_op_subi_8_d, 0xfff8, 0x0400, { 8, 8, 2, 2, 2, 2, 2}}, + {m68000_base_device_ops::m68k_op_subi_8_ai, 0xfff8, 0x0410, { 16, 16, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_subi_8_pi, 0xfff8, 0x0418, { 16, 16, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_subi_8_pd, 0xfff8, 0x0420, { 18, 18, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_subi_8_di, 0xfff8, 0x0428, { 20, 20, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_subi_8_ix, 0xfff8, 0x0430, { 22, 22, 11, 11, 11, 11, 4}}, + {m68000_base_device_ops::m68k_op_subi_16_d, 0xfff8, 0x0440, { 8, 8, 2, 2, 2, 2, 2}}, + {m68000_base_device_ops::m68k_op_subi_16_ai, 0xfff8, 0x0450, { 16, 16, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_subi_16_pi, 0xfff8, 0x0458, { 16, 16, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_subi_16_pd, 0xfff8, 0x0460, { 18, 18, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_subi_16_di, 0xfff8, 0x0468, { 20, 20, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_subi_16_ix, 0xfff8, 0x0470, { 22, 22, 11, 11, 11, 11, 4}}, + {m68000_base_device_ops::m68k_op_subi_32_d, 0xfff8, 0x0480, { 16, 14, 2, 2, 2, 2, 2}}, + {m68000_base_device_ops::m68k_op_subi_32_ai, 0xfff8, 0x0490, { 28, 28, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_subi_32_pi, 0xfff8, 0x0498, { 28, 28, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_subi_32_pd, 0xfff8, 0x04a0, { 30, 30, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_subi_32_di, 0xfff8, 0x04a8, { 32, 32, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_subi_32_ix, 0xfff8, 0x04b0, { 34, 34, 11, 11, 11, 11, 4}}, + {m68000_base_device_ops::m68k_op_chk2cmp2_32_ai, 0xfff8, 0x04d0, {255, 255, 22, 22, 22, 22, 18}}, + {m68000_base_device_ops::m68k_op_chk2cmp2_32_di, 0xfff8, 0x04e8, {255, 255, 23, 23, 23, 23, 18}}, + {m68000_base_device_ops::m68k_op_chk2cmp2_32_ix, 0xfff8, 0x04f0, {255, 255, 25, 25, 25, 25, 18}}, + {m68000_base_device_ops::m68k_op_addi_8_d, 0xfff8, 0x0600, { 8, 8, 2, 2, 2, 2, 2}}, + {m68000_base_device_ops::m68k_op_addi_8_ai, 0xfff8, 0x0610, { 16, 16, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_addi_8_pi, 0xfff8, 0x0618, { 16, 16, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_addi_8_pd, 0xfff8, 0x0620, { 18, 18, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_addi_8_di, 0xfff8, 0x0628, { 20, 20, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_addi_8_ix, 0xfff8, 0x0630, { 22, 22, 11, 11, 11, 11, 4}}, + {m68000_base_device_ops::m68k_op_addi_16_d, 0xfff8, 0x0640, { 8, 8, 2, 2, 2, 2, 2}}, + {m68000_base_device_ops::m68k_op_addi_16_ai, 0xfff8, 0x0650, { 16, 16, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_addi_16_pi, 0xfff8, 0x0658, { 16, 16, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_addi_16_pd, 0xfff8, 0x0660, { 18, 18, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_addi_16_di, 0xfff8, 0x0668, { 20, 20, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_addi_16_ix, 0xfff8, 0x0670, { 22, 22, 11, 11, 11, 11, 4}}, + {m68000_base_device_ops::m68k_op_addi_32_d, 0xfff8, 0x0680, { 16, 14, 2, 2, 2, 2, 2}}, + {m68000_base_device_ops::m68k_op_addi_32_ai, 0xfff8, 0x0690, { 28, 28, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_addi_32_pi, 0xfff8, 0x0698, { 28, 28, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_addi_32_pd, 0xfff8, 0x06a0, { 30, 30, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_addi_32_di, 0xfff8, 0x06a8, { 32, 32, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_addi_32_ix, 0xfff8, 0x06b0, { 34, 34, 11, 11, 11, 11, 4}}, + {m68000_base_device_ops::m68k_op_callm_32_ai, 0xfff8, 0x06d0, {255, 255, 64, 64, 64, 64, 60}}, + {m68000_base_device_ops::m68k_op_callm_32_di, 0xfff8, 0x06e8, {255, 255, 65, 65, 65, 65, 60}}, + {m68000_base_device_ops::m68k_op_callm_32_ix, 0xfff8, 0x06f0, {255, 255, 67, 67, 67, 67, 60}}, + {m68000_base_device_ops::m68k_op_btst_32_s_d, 0xfff8, 0x0800, { 10, 10, 4, 4, 4, 4, 4}}, + {m68000_base_device_ops::m68k_op_btst_8_s_ai, 0xfff8, 0x0810, { 12, 12, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_btst_8_s_pi, 0xfff8, 0x0818, { 12, 12, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_btst_8_s_pd, 0xfff8, 0x0820, { 14, 14, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_btst_8_s_di, 0xfff8, 0x0828, { 16, 16, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_btst_8_s_ix, 0xfff8, 0x0830, { 18, 18, 11, 11, 11, 11, 4}}, + {m68000_base_device_ops::m68k_op_bchg_32_s_d, 0xfff8, 0x0840, { 12, 12, 4, 4, 4, 4, 4}}, + {m68000_base_device_ops::m68k_op_bchg_8_s_ai, 0xfff8, 0x0850, { 16, 16, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_bchg_8_s_pi, 0xfff8, 0x0858, { 16, 16, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_bchg_8_s_pd, 0xfff8, 0x0860, { 18, 18, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_bchg_8_s_di, 0xfff8, 0x0868, { 20, 20, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_bchg_8_s_ix, 0xfff8, 0x0870, { 22, 22, 11, 11, 11, 11, 4}}, + {m68000_base_device_ops::m68k_op_bclr_32_s_d, 0xfff8, 0x0880, { 14, 14, 4, 4, 4, 4, 4}}, + {m68000_base_device_ops::m68k_op_bclr_8_s_ai, 0xfff8, 0x0890, { 16, 16, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_bclr_8_s_pi, 0xfff8, 0x0898, { 16, 16, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_bclr_8_s_pd, 0xfff8, 0x08a0, { 18, 18, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_bclr_8_s_di, 0xfff8, 0x08a8, { 20, 20, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_bclr_8_s_ix, 0xfff8, 0x08b0, { 22, 22, 11, 11, 11, 11, 4}}, + {m68000_base_device_ops::m68k_op_bset_32_s_d, 0xfff8, 0x08c0, { 12, 12, 4, 4, 4, 4, 4}}, + {m68000_base_device_ops::m68k_op_bset_8_s_ai, 0xfff8, 0x08d0, { 16, 16, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_bset_8_s_pi, 0xfff8, 0x08d8, { 16, 16, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_bset_8_s_pd, 0xfff8, 0x08e0, { 18, 18, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_bset_8_s_di, 0xfff8, 0x08e8, { 20, 20, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_bset_8_s_ix, 0xfff8, 0x08f0, { 22, 22, 11, 11, 11, 11, 4}}, + {m68000_base_device_ops::m68k_op_eori_8_d, 0xfff8, 0x0a00, { 8, 8, 2, 2, 2, 2, 2}}, + {m68000_base_device_ops::m68k_op_eori_8_ai, 0xfff8, 0x0a10, { 16, 16, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_eori_8_pi, 0xfff8, 0x0a18, { 16, 16, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_eori_8_pd, 0xfff8, 0x0a20, { 18, 18, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_eori_8_di, 0xfff8, 0x0a28, { 20, 20, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_eori_8_ix, 0xfff8, 0x0a30, { 22, 22, 11, 11, 11, 11, 4}}, + {m68000_base_device_ops::m68k_op_eori_16_d, 0xfff8, 0x0a40, { 8, 8, 2, 2, 2, 2, 2}}, + {m68000_base_device_ops::m68k_op_eori_16_ai, 0xfff8, 0x0a50, { 16, 16, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_eori_16_pi, 0xfff8, 0x0a58, { 16, 16, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_eori_16_pd, 0xfff8, 0x0a60, { 18, 18, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_eori_16_di, 0xfff8, 0x0a68, { 20, 20, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_eori_16_ix, 0xfff8, 0x0a70, { 22, 22, 11, 11, 11, 11, 4}}, + {m68000_base_device_ops::m68k_op_eori_32_d, 0xfff8, 0x0a80, { 16, 14, 2, 2, 2, 2, 2}}, + {m68000_base_device_ops::m68k_op_eori_32_ai, 0xfff8, 0x0a90, { 28, 28, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_eori_32_pi, 0xfff8, 0x0a98, { 28, 28, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_eori_32_pd, 0xfff8, 0x0aa0, { 30, 30, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_eori_32_di, 0xfff8, 0x0aa8, { 32, 32, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_eori_32_ix, 0xfff8, 0x0ab0, { 34, 34, 11, 11, 11, 11, 4}}, + {m68000_base_device_ops::m68k_op_cas_8_ai, 0xfff8, 0x0ad0, {255, 255, 16, 16, 16, 16, 12}}, + {m68000_base_device_ops::m68k_op_cas_8_pi, 0xfff8, 0x0ad8, {255, 255, 16, 16, 16, 16, 12}}, + {m68000_base_device_ops::m68k_op_cas_8_pd, 0xfff8, 0x0ae0, {255, 255, 17, 17, 17, 17, 12}}, + {m68000_base_device_ops::m68k_op_cas_8_di, 0xfff8, 0x0ae8, {255, 255, 17, 17, 17, 17, 12}}, + {m68000_base_device_ops::m68k_op_cas_8_ix, 0xfff8, 0x0af0, {255, 255, 19, 19, 19, 19, 12}}, + {m68000_base_device_ops::m68k_op_cmpi_8_d, 0xfff8, 0x0c00, { 8, 8, 2, 2, 2, 2, 2}}, + {m68000_base_device_ops::m68k_op_cmpi_8_ai, 0xfff8, 0x0c10, { 12, 12, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_cmpi_8_pi, 0xfff8, 0x0c18, { 12, 12, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_cmpi_8_pd, 0xfff8, 0x0c20, { 14, 14, 7, 7, 7, 7, 2}}, + {m68000_base_device_ops::m68k_op_cmpi_8_di, 0xfff8, 0x0c28, { 16, 16, 7, 7, 7, 7, 2}}, + {m68000_base_device_ops::m68k_op_cmpi_8_ix, 0xfff8, 0x0c30, { 18, 18, 9, 9, 9, 9, 2}}, + {m68000_base_device_ops::m68k_op_cmpi_16_d, 0xfff8, 0x0c40, { 8, 8, 2, 2, 2, 2, 2}}, + {m68000_base_device_ops::m68k_op_cmpi_16_ai, 0xfff8, 0x0c50, { 12, 12, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_cmpi_16_pi, 0xfff8, 0x0c58, { 12, 12, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_cmpi_16_pd, 0xfff8, 0x0c60, { 14, 14, 7, 7, 7, 7, 2}}, + {m68000_base_device_ops::m68k_op_cmpi_16_di, 0xfff8, 0x0c68, { 16, 16, 7, 7, 7, 7, 2}}, + {m68000_base_device_ops::m68k_op_cmpi_16_ix, 0xfff8, 0x0c70, { 18, 18, 9, 9, 9, 9, 2}}, + {m68000_base_device_ops::m68k_op_cmpi_32_d, 0xfff8, 0x0c80, { 14, 12, 2, 2, 2, 2, 2}}, + {m68000_base_device_ops::m68k_op_cmpi_32_ai, 0xfff8, 0x0c90, { 20, 20, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_cmpi_32_pi, 0xfff8, 0x0c98, { 20, 20, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_cmpi_32_pd, 0xfff8, 0x0ca0, { 22, 22, 7, 7, 7, 7, 2}}, + {m68000_base_device_ops::m68k_op_cmpi_32_di, 0xfff8, 0x0ca8, { 24, 24, 7, 7, 7, 7, 2}}, + {m68000_base_device_ops::m68k_op_cmpi_32_ix, 0xfff8, 0x0cb0, { 26, 26, 9, 9, 9, 9, 2}}, + {m68000_base_device_ops::m68k_op_cas_16_ai, 0xfff8, 0x0cd0, {255, 255, 16, 16, 16, 16, 12}}, + {m68000_base_device_ops::m68k_op_cas_16_pi, 0xfff8, 0x0cd8, {255, 255, 16, 16, 16, 16, 12}}, + {m68000_base_device_ops::m68k_op_cas_16_pd, 0xfff8, 0x0ce0, {255, 255, 17, 17, 17, 17, 12}}, + {m68000_base_device_ops::m68k_op_cas_16_di, 0xfff8, 0x0ce8, {255, 255, 17, 17, 17, 17, 12}}, + {m68000_base_device_ops::m68k_op_cas_16_ix, 0xfff8, 0x0cf0, {255, 255, 19, 19, 19, 19, 12}}, + {m68000_base_device_ops::m68k_op_moves_8_ai, 0xfff8, 0x0e10, {255, 18, 9, 9, 9, 9, 5}}, + {m68000_base_device_ops::m68k_op_moves_8_pi, 0xfff8, 0x0e18, {255, 18, 9, 9, 9, 9, 5}}, + {m68000_base_device_ops::m68k_op_moves_8_pd, 0xfff8, 0x0e20, {255, 20, 10, 10, 10, 10, 5}}, + {m68000_base_device_ops::m68k_op_moves_8_di, 0xfff8, 0x0e28, {255, 26, 10, 10, 10, 10, 5}}, + {m68000_base_device_ops::m68k_op_moves_8_ix, 0xfff8, 0x0e30, {255, 30, 12, 12, 12, 12, 5}}, + {m68000_base_device_ops::m68k_op_moves_16_ai, 0xfff8, 0x0e50, {255, 18, 9, 9, 9, 9, 5}}, + {m68000_base_device_ops::m68k_op_moves_16_pi, 0xfff8, 0x0e58, {255, 18, 9, 9, 9, 9, 5}}, + {m68000_base_device_ops::m68k_op_moves_16_pd, 0xfff8, 0x0e60, {255, 20, 10, 10, 10, 10, 5}}, + {m68000_base_device_ops::m68k_op_moves_16_di, 0xfff8, 0x0e68, {255, 26, 10, 10, 10, 10, 5}}, + {m68000_base_device_ops::m68k_op_moves_16_ix, 0xfff8, 0x0e70, {255, 30, 12, 12, 12, 12, 5}}, + {m68000_base_device_ops::m68k_op_moves_32_ai, 0xfff8, 0x0e90, {255, 22, 9, 9, 9, 9, 5}}, + {m68000_base_device_ops::m68k_op_moves_32_pi, 0xfff8, 0x0e98, {255, 22, 9, 9, 9, 9, 5}}, + {m68000_base_device_ops::m68k_op_moves_32_pd, 0xfff8, 0x0ea0, {255, 28, 10, 10, 10, 10, 5}}, + {m68000_base_device_ops::m68k_op_moves_32_di, 0xfff8, 0x0ea8, {255, 32, 10, 10, 10, 10, 5}}, + {m68000_base_device_ops::m68k_op_moves_32_ix, 0xfff8, 0x0eb0, {255, 36, 12, 12, 12, 12, 5}}, + {m68000_base_device_ops::m68k_op_cas_32_ai, 0xfff8, 0x0ed0, {255, 255, 16, 16, 16, 16, 12}}, + {m68000_base_device_ops::m68k_op_cas_32_pi, 0xfff8, 0x0ed8, {255, 255, 16, 16, 16, 16, 12}}, + {m68000_base_device_ops::m68k_op_cas_32_pd, 0xfff8, 0x0ee0, {255, 255, 17, 17, 17, 17, 12}}, + {m68000_base_device_ops::m68k_op_cas_32_di, 0xfff8, 0x0ee8, {255, 255, 17, 17, 17, 17, 12}}, + {m68000_base_device_ops::m68k_op_cas_32_ix, 0xfff8, 0x0ef0, {255, 255, 19, 19, 19, 19, 12}}, + {m68000_base_device_ops::m68k_op_move_8_aw_d, 0xfff8, 0x11c0, { 12, 12, 4, 4, 4, 4, 4}}, + {m68000_base_device_ops::m68k_op_move_8_aw_ai, 0xfff8, 0x11d0, { 16, 16, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_move_8_aw_pi, 0xfff8, 0x11d8, { 16, 16, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_move_8_aw_pd, 0xfff8, 0x11e0, { 18, 18, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_move_8_aw_di, 0xfff8, 0x11e8, { 20, 20, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_move_8_aw_ix, 0xfff8, 0x11f0, { 22, 22, 11, 11, 11, 11, 4}}, + {m68000_base_device_ops::m68k_op_move_8_al_d, 0xfff8, 0x13c0, { 16, 16, 6, 6, 6, 6, 6}}, + {m68000_base_device_ops::m68k_op_move_8_al_ai, 0xfff8, 0x13d0, { 20, 20, 10, 10, 10, 10, 6}}, + {m68000_base_device_ops::m68k_op_move_8_al_pi, 0xfff8, 0x13d8, { 20, 20, 10, 10, 10, 10, 6}}, + {m68000_base_device_ops::m68k_op_move_8_al_pd, 0xfff8, 0x13e0, { 22, 22, 11, 11, 11, 11, 6}}, + {m68000_base_device_ops::m68k_op_move_8_al_di, 0xfff8, 0x13e8, { 24, 24, 11, 11, 11, 11, 6}}, + {m68000_base_device_ops::m68k_op_move_8_al_ix, 0xfff8, 0x13f0, { 26, 26, 13, 13, 13, 13, 6}}, + {m68000_base_device_ops::m68k_op_move_8_pi7_d, 0xfff8, 0x1ec0, { 8, 8, 4, 4, 4, 4, 4}}, + {m68000_base_device_ops::m68k_op_move_8_pi7_ai, 0xfff8, 0x1ed0, { 12, 12, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_move_8_pi7_pi, 0xfff8, 0x1ed8, { 12, 12, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_move_8_pi7_pd, 0xfff8, 0x1ee0, { 14, 14, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_move_8_pi7_di, 0xfff8, 0x1ee8, { 16, 16, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_move_8_pi7_ix, 0xfff8, 0x1ef0, { 18, 18, 11, 11, 11, 11, 4}}, + {m68000_base_device_ops::m68k_op_move_8_pd7_d, 0xfff8, 0x1f00, { 8, 8, 5, 5, 5, 5, 5}}, + {m68000_base_device_ops::m68k_op_move_8_pd7_ai, 0xfff8, 0x1f10, { 12, 12, 9, 9, 9, 9, 5}}, + {m68000_base_device_ops::m68k_op_move_8_pd7_pi, 0xfff8, 0x1f18, { 12, 12, 9, 9, 9, 9, 5}}, + {m68000_base_device_ops::m68k_op_move_8_pd7_pd, 0xfff8, 0x1f20, { 14, 14, 10, 10, 10, 10, 5}}, + {m68000_base_device_ops::m68k_op_move_8_pd7_di, 0xfff8, 0x1f28, { 16, 16, 10, 10, 10, 10, 5}}, + {m68000_base_device_ops::m68k_op_move_8_pd7_ix, 0xfff8, 0x1f30, { 18, 18, 12, 12, 12, 12, 5}}, + {m68000_base_device_ops::m68k_op_move_32_aw_d, 0xfff8, 0x21c0, { 16, 16, 4, 4, 4, 4, 4}}, + {m68000_base_device_ops::m68k_op_move_32_aw_a, 0xfff8, 0x21c8, { 16, 16, 4, 4, 4, 4, 4}}, + {m68000_base_device_ops::m68k_op_move_32_aw_ai, 0xfff8, 0x21d0, { 24, 24, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_move_32_aw_pi, 0xfff8, 0x21d8, { 24, 24, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_move_32_aw_pd, 0xfff8, 0x21e0, { 26, 26, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_move_32_aw_di, 0xfff8, 0x21e8, { 28, 28, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_move_32_aw_ix, 0xfff8, 0x21f0, { 30, 30, 11, 11, 11, 11, 4}}, + {m68000_base_device_ops::m68k_op_move_32_al_d, 0xfff8, 0x23c0, { 20, 20, 6, 6, 6, 6, 6}}, + {m68000_base_device_ops::m68k_op_move_32_al_a, 0xfff8, 0x23c8, { 20, 20, 6, 6, 6, 6, 6}}, + {m68000_base_device_ops::m68k_op_move_32_al_ai, 0xfff8, 0x23d0, { 28, 28, 10, 10, 10, 10, 6}}, + {m68000_base_device_ops::m68k_op_move_32_al_pi, 0xfff8, 0x23d8, { 28, 28, 10, 10, 10, 10, 6}}, + {m68000_base_device_ops::m68k_op_move_32_al_pd, 0xfff8, 0x23e0, { 30, 30, 11, 11, 11, 11, 6}}, + {m68000_base_device_ops::m68k_op_move_32_al_di, 0xfff8, 0x23e8, { 32, 32, 11, 11, 11, 11, 6}}, + {m68000_base_device_ops::m68k_op_move_32_al_ix, 0xfff8, 0x23f0, { 34, 34, 13, 13, 13, 13, 6}}, + {m68000_base_device_ops::m68k_op_move_16_aw_d, 0xfff8, 0x31c0, { 12, 12, 4, 4, 4, 4, 4}}, + {m68000_base_device_ops::m68k_op_move_16_aw_a, 0xfff8, 0x31c8, { 12, 12, 4, 4, 4, 4, 4}}, + {m68000_base_device_ops::m68k_op_move_16_aw_ai, 0xfff8, 0x31d0, { 16, 16, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_move_16_aw_pi, 0xfff8, 0x31d8, { 16, 16, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_move_16_aw_pd, 0xfff8, 0x31e0, { 18, 18, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_move_16_aw_di, 0xfff8, 0x31e8, { 20, 20, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_move_16_aw_ix, 0xfff8, 0x31f0, { 22, 22, 11, 11, 11, 11, 4}}, + {m68000_base_device_ops::m68k_op_move_16_al_d, 0xfff8, 0x33c0, { 16, 16, 6, 6, 6, 6, 6}}, + {m68000_base_device_ops::m68k_op_move_16_al_a, 0xfff8, 0x33c8, { 16, 16, 6, 6, 6, 6, 6}}, + {m68000_base_device_ops::m68k_op_move_16_al_ai, 0xfff8, 0x33d0, { 20, 20, 10, 10, 10, 10, 6}}, + {m68000_base_device_ops::m68k_op_move_16_al_pi, 0xfff8, 0x33d8, { 20, 20, 10, 10, 10, 10, 6}}, + {m68000_base_device_ops::m68k_op_move_16_al_pd, 0xfff8, 0x33e0, { 22, 22, 11, 11, 11, 11, 6}}, + {m68000_base_device_ops::m68k_op_move_16_al_di, 0xfff8, 0x33e8, { 24, 24, 11, 11, 11, 11, 6}}, + {m68000_base_device_ops::m68k_op_move_16_al_ix, 0xfff8, 0x33f0, { 26, 26, 13, 13, 13, 13, 6}}, + {m68000_base_device_ops::m68k_op_negx_8_d, 0xfff8, 0x4000, { 4, 4, 2, 2, 2, 2, 2}}, + {m68000_base_device_ops::m68k_op_negx_8_ai, 0xfff8, 0x4010, { 12, 12, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_negx_8_pi, 0xfff8, 0x4018, { 12, 12, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_negx_8_pd, 0xfff8, 0x4020, { 14, 14, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_negx_8_di, 0xfff8, 0x4028, { 16, 16, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_negx_8_ix, 0xfff8, 0x4030, { 18, 18, 11, 11, 11, 11, 4}}, + {m68000_base_device_ops::m68k_op_negx_16_d, 0xfff8, 0x4040, { 4, 4, 2, 2, 2, 2, 2}}, + {m68000_base_device_ops::m68k_op_negx_16_ai, 0xfff8, 0x4050, { 12, 12, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_negx_16_pi, 0xfff8, 0x4058, { 12, 12, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_negx_16_pd, 0xfff8, 0x4060, { 14, 14, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_negx_16_di, 0xfff8, 0x4068, { 16, 16, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_negx_16_ix, 0xfff8, 0x4070, { 18, 18, 11, 11, 11, 11, 4}}, + {m68000_base_device_ops::m68k_op_negx_32_d, 0xfff8, 0x4080, { 6, 6, 2, 2, 2, 2, 2}}, + {m68000_base_device_ops::m68k_op_negx_32_ai, 0xfff8, 0x4090, { 20, 20, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_negx_32_pi, 0xfff8, 0x4098, { 20, 20, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_negx_32_pd, 0xfff8, 0x40a0, { 22, 22, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_negx_32_di, 0xfff8, 0x40a8, { 24, 24, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_negx_32_ix, 0xfff8, 0x40b0, { 26, 26, 11, 11, 11, 11, 4}}, + {m68000_base_device_ops::m68k_op_move_16_frs_d, 0xfff8, 0x40c0, { 6, 4, 8, 8, 8, 8, 8}}, + {m68000_base_device_ops::m68k_op_move_16_frs_ai, 0xfff8, 0x40d0, { 12, 12, 12, 12, 12, 12, 8}}, + {m68000_base_device_ops::m68k_op_move_16_frs_pi, 0xfff8, 0x40d8, { 12, 12, 12, 12, 12, 12, 8}}, + {m68000_base_device_ops::m68k_op_move_16_frs_pd, 0xfff8, 0x40e0, { 14, 14, 13, 13, 13, 13, 8}}, + {m68000_base_device_ops::m68k_op_move_16_frs_di, 0xfff8, 0x40e8, { 16, 16, 13, 13, 13, 13, 8}}, + {m68000_base_device_ops::m68k_op_move_16_frs_ix, 0xfff8, 0x40f0, { 18, 18, 15, 15, 15, 15, 8}}, + {m68000_base_device_ops::m68k_op_clr_8_d, 0xfff8, 0x4200, { 4, 4, 2, 2, 2, 2, 2}}, + {m68000_base_device_ops::m68k_op_clr_8_ai, 0xfff8, 0x4210, { 12, 8, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_clr_8_pi, 0xfff8, 0x4218, { 12, 8, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_clr_8_pd, 0xfff8, 0x4220, { 14, 10, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_clr_8_di, 0xfff8, 0x4228, { 16, 12, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_clr_8_ix, 0xfff8, 0x4230, { 18, 14, 11, 11, 11, 11, 4}}, + {m68000_base_device_ops::m68k_op_clr_16_d, 0xfff8, 0x4240, { 4, 4, 2, 2, 2, 2, 2}}, + {m68000_base_device_ops::m68k_op_clr_16_ai, 0xfff8, 0x4250, { 12, 8, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_clr_16_pi, 0xfff8, 0x4258, { 12, 8, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_clr_16_pd, 0xfff8, 0x4260, { 14, 10, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_clr_16_di, 0xfff8, 0x4268, { 16, 12, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_clr_16_ix, 0xfff8, 0x4270, { 18, 14, 11, 11, 11, 11, 4}}, + {m68000_base_device_ops::m68k_op_clr_32_d, 0xfff8, 0x4280, { 6, 6, 2, 2, 2, 2, 2}}, + {m68000_base_device_ops::m68k_op_clr_32_ai, 0xfff8, 0x4290, { 20, 12, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_clr_32_pi, 0xfff8, 0x4298, { 20, 12, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_clr_32_pd, 0xfff8, 0x42a0, { 22, 14, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_clr_32_di, 0xfff8, 0x42a8, { 24, 16, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_clr_32_ix, 0xfff8, 0x42b0, { 26, 20, 11, 11, 11, 11, 4}}, + {m68000_base_device_ops::m68k_op_move_16_frc_d, 0xfff8, 0x42c0, {255, 4, 4, 4, 4, 4, 4}}, + {m68000_base_device_ops::m68k_op_move_16_frc_ai, 0xfff8, 0x42d0, {255, 12, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_move_16_frc_pi, 0xfff8, 0x42d8, {255, 12, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_move_16_frc_pd, 0xfff8, 0x42e0, {255, 14, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_move_16_frc_di, 0xfff8, 0x42e8, {255, 16, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_move_16_frc_ix, 0xfff8, 0x42f0, {255, 18, 11, 11, 11, 11, 4}}, + {m68000_base_device_ops::m68k_op_neg_8_d, 0xfff8, 0x4400, { 4, 4, 2, 2, 2, 2, 2}}, + {m68000_base_device_ops::m68k_op_neg_8_ai, 0xfff8, 0x4410, { 12, 12, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_neg_8_pi, 0xfff8, 0x4418, { 12, 12, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_neg_8_pd, 0xfff8, 0x4420, { 14, 14, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_neg_8_di, 0xfff8, 0x4428, { 16, 16, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_neg_8_ix, 0xfff8, 0x4430, { 18, 18, 11, 11, 11, 11, 4}}, + {m68000_base_device_ops::m68k_op_neg_16_d, 0xfff8, 0x4440, { 4, 4, 2, 2, 2, 2, 2}}, + {m68000_base_device_ops::m68k_op_neg_16_ai, 0xfff8, 0x4450, { 12, 12, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_neg_16_pi, 0xfff8, 0x4458, { 12, 12, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_neg_16_pd, 0xfff8, 0x4460, { 14, 14, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_neg_16_di, 0xfff8, 0x4468, { 16, 16, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_neg_16_ix, 0xfff8, 0x4470, { 18, 18, 11, 11, 11, 11, 4}}, + {m68000_base_device_ops::m68k_op_neg_32_d, 0xfff8, 0x4480, { 6, 6, 2, 2, 2, 2, 2}}, + {m68000_base_device_ops::m68k_op_neg_32_ai, 0xfff8, 0x4490, { 20, 20, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_neg_32_pi, 0xfff8, 0x4498, { 20, 20, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_neg_32_pd, 0xfff8, 0x44a0, { 22, 22, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_neg_32_di, 0xfff8, 0x44a8, { 24, 24, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_neg_32_ix, 0xfff8, 0x44b0, { 26, 26, 11, 11, 11, 11, 4}}, + {m68000_base_device_ops::m68k_op_move_16_toc_d, 0xfff8, 0x44c0, { 12, 12, 4, 4, 4, 4, 4}}, + {m68000_base_device_ops::m68k_op_move_16_toc_ai, 0xfff8, 0x44d0, { 16, 16, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_move_16_toc_pi, 0xfff8, 0x44d8, { 16, 16, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_move_16_toc_pd, 0xfff8, 0x44e0, { 18, 18, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_move_16_toc_di, 0xfff8, 0x44e8, { 20, 20, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_move_16_toc_ix, 0xfff8, 0x44f0, { 22, 22, 11, 11, 11, 11, 4}}, + {m68000_base_device_ops::m68k_op_not_8_d, 0xfff8, 0x4600, { 4, 4, 2, 2, 2, 2, 2}}, + {m68000_base_device_ops::m68k_op_not_8_ai, 0xfff8, 0x4610, { 12, 12, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_not_8_pi, 0xfff8, 0x4618, { 12, 12, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_not_8_pd, 0xfff8, 0x4620, { 14, 14, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_not_8_di, 0xfff8, 0x4628, { 16, 16, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_not_8_ix, 0xfff8, 0x4630, { 18, 18, 11, 11, 11, 11, 4}}, + {m68000_base_device_ops::m68k_op_not_16_d, 0xfff8, 0x4640, { 4, 4, 2, 2, 2, 2, 2}}, + {m68000_base_device_ops::m68k_op_not_16_ai, 0xfff8, 0x4650, { 12, 12, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_not_16_pi, 0xfff8, 0x4658, { 12, 12, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_not_16_pd, 0xfff8, 0x4660, { 14, 14, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_not_16_di, 0xfff8, 0x4668, { 16, 16, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_not_16_ix, 0xfff8, 0x4670, { 18, 18, 11, 11, 11, 11, 4}}, + {m68000_base_device_ops::m68k_op_not_32_d, 0xfff8, 0x4680, { 6, 6, 2, 2, 2, 2, 2}}, + {m68000_base_device_ops::m68k_op_not_32_ai, 0xfff8, 0x4690, { 20, 20, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_not_32_pi, 0xfff8, 0x4698, { 20, 20, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_not_32_pd, 0xfff8, 0x46a0, { 22, 22, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_not_32_di, 0xfff8, 0x46a8, { 24, 24, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_not_32_ix, 0xfff8, 0x46b0, { 26, 26, 11, 11, 11, 11, 4}}, + {m68000_base_device_ops::m68k_op_move_16_tos_d, 0xfff8, 0x46c0, { 12, 12, 8, 8, 8, 8, 8}}, + {m68000_base_device_ops::m68k_op_move_16_tos_ai, 0xfff8, 0x46d0, { 16, 16, 12, 12, 12, 12, 8}}, + {m68000_base_device_ops::m68k_op_move_16_tos_pi, 0xfff8, 0x46d8, { 16, 16, 12, 12, 12, 12, 8}}, + {m68000_base_device_ops::m68k_op_move_16_tos_pd, 0xfff8, 0x46e0, { 18, 18, 13, 13, 13, 13, 8}}, + {m68000_base_device_ops::m68k_op_move_16_tos_di, 0xfff8, 0x46e8, { 20, 20, 13, 13, 13, 13, 8}}, + {m68000_base_device_ops::m68k_op_move_16_tos_ix, 0xfff8, 0x46f0, { 22, 22, 15, 15, 15, 15, 8}}, + {m68000_base_device_ops::m68k_op_nbcd_8_d, 0xfff8, 0x4800, { 6, 6, 6, 6, 6, 6, 6}}, + {m68000_base_device_ops::m68k_op_link_32, 0xfff8, 0x4808, {255, 255, 6, 6, 6, 6, 6}}, + {m68000_base_device_ops::m68k_op_nbcd_8_ai, 0xfff8, 0x4810, { 12, 12, 10, 10, 10, 10, 6}}, + {m68000_base_device_ops::m68k_op_nbcd_8_pi, 0xfff8, 0x4818, { 12, 12, 10, 10, 10, 10, 6}}, + {m68000_base_device_ops::m68k_op_nbcd_8_pd, 0xfff8, 0x4820, { 14, 14, 11, 11, 11, 11, 6}}, + {m68000_base_device_ops::m68k_op_nbcd_8_di, 0xfff8, 0x4828, { 16, 16, 11, 11, 11, 11, 6}}, + {m68000_base_device_ops::m68k_op_nbcd_8_ix, 0xfff8, 0x4830, { 18, 18, 13, 13, 13, 13, 6}}, + {m68000_base_device_ops::m68k_op_swap_32, 0xfff8, 0x4840, { 4, 4, 4, 4, 4, 4, 4}}, + {m68000_base_device_ops::m68k_op_bkpt, 0xfff8, 0x4848, {255, 10, 10, 10, 10, 10, 10}}, + {m68000_base_device_ops::m68k_op_pea_32_ai, 0xfff8, 0x4850, { 12, 12, 9, 9, 9, 9, 5}}, + {m68000_base_device_ops::m68k_op_pea_32_di, 0xfff8, 0x4868, { 16, 16, 10, 10, 10, 10, 5}}, + {m68000_base_device_ops::m68k_op_pea_32_ix, 0xfff8, 0x4870, { 20, 20, 12, 12, 12, 12, 5}}, + {m68000_base_device_ops::m68k_op_ext_16, 0xfff8, 0x4880, { 4, 4, 4, 4, 4, 4, 4}}, + {m68000_base_device_ops::m68k_op_movem_16_re_ai, 0xfff8, 0x4890, { 8, 8, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_movem_16_re_pd, 0xfff8, 0x48a0, { 8, 8, 4, 4, 4, 4, 4}}, + {m68000_base_device_ops::m68k_op_movem_16_re_di, 0xfff8, 0x48a8, { 12, 12, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_movem_16_re_ix, 0xfff8, 0x48b0, { 14, 14, 11, 11, 11, 11, 4}}, + {m68000_base_device_ops::m68k_op_ext_32, 0xfff8, 0x48c0, { 4, 4, 4, 4, 4, 4, 4}}, + {m68000_base_device_ops::m68k_op_movem_32_re_ai, 0xfff8, 0x48d0, { 8, 8, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_movem_32_re_pd, 0xfff8, 0x48e0, { 8, 8, 4, 4, 4, 4, 4}}, + {m68000_base_device_ops::m68k_op_movem_32_re_di, 0xfff8, 0x48e8, { 12, 12, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_movem_32_re_ix, 0xfff8, 0x48f0, { 14, 14, 11, 11, 11, 11, 4}}, + {m68000_base_device_ops::m68k_op_extb_32, 0xfff8, 0x49c0, {255, 255, 4, 4, 4, 4, 4}}, + {m68000_base_device_ops::m68k_op_tst_8_d, 0xfff8, 0x4a00, { 4, 4, 2, 2, 2, 2, 2}}, + {m68000_base_device_ops::m68k_op_tst_8_ai, 0xfff8, 0x4a10, { 8, 8, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_tst_8_pi, 0xfff8, 0x4a18, { 8, 8, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_tst_8_pd, 0xfff8, 0x4a20, { 10, 10, 7, 7, 7, 7, 2}}, + {m68000_base_device_ops::m68k_op_tst_8_di, 0xfff8, 0x4a28, { 12, 12, 7, 7, 7, 7, 2}}, + {m68000_base_device_ops::m68k_op_tst_8_ix, 0xfff8, 0x4a30, { 14, 14, 9, 9, 9, 9, 2}}, + {m68000_base_device_ops::m68k_op_tst_16_d, 0xfff8, 0x4a40, { 4, 4, 2, 2, 2, 2, 2}}, + {m68000_base_device_ops::m68k_op_tst_16_a, 0xfff8, 0x4a48, {255, 255, 2, 2, 2, 2, 2}}, + {m68000_base_device_ops::m68k_op_tst_16_ai, 0xfff8, 0x4a50, { 8, 8, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_tst_16_pi, 0xfff8, 0x4a58, { 8, 8, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_tst_16_pd, 0xfff8, 0x4a60, { 10, 10, 7, 7, 7, 7, 2}}, + {m68000_base_device_ops::m68k_op_tst_16_di, 0xfff8, 0x4a68, { 12, 12, 7, 7, 7, 7, 2}}, + {m68000_base_device_ops::m68k_op_tst_16_ix, 0xfff8, 0x4a70, { 14, 14, 9, 9, 9, 9, 2}}, + {m68000_base_device_ops::m68k_op_tst_32_d, 0xfff8, 0x4a80, { 4, 4, 2, 2, 2, 2, 2}}, + {m68000_base_device_ops::m68k_op_tst_32_a, 0xfff8, 0x4a88, {255, 255, 2, 2, 2, 2, 2}}, + {m68000_base_device_ops::m68k_op_tst_32_ai, 0xfff8, 0x4a90, { 12, 12, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_tst_32_pi, 0xfff8, 0x4a98, { 12, 12, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_tst_32_pd, 0xfff8, 0x4aa0, { 14, 14, 7, 7, 7, 7, 2}}, + {m68000_base_device_ops::m68k_op_tst_32_di, 0xfff8, 0x4aa8, { 16, 16, 7, 7, 7, 7, 2}}, + {m68000_base_device_ops::m68k_op_tst_32_ix, 0xfff8, 0x4ab0, { 18, 18, 9, 9, 9, 9, 2}}, + {m68000_base_device_ops::m68k_op_tas_8_d, 0xfff8, 0x4ac0, { 4, 4, 4, 4, 4, 4, 4}}, + {m68000_base_device_ops::m68k_op_tas_8_ai, 0xfff8, 0x4ad0, { 18, 18, 16, 16, 16, 16, 12}}, + {m68000_base_device_ops::m68k_op_tas_8_pi, 0xfff8, 0x4ad8, { 18, 18, 16, 16, 16, 16, 12}}, + {m68000_base_device_ops::m68k_op_tas_8_pd, 0xfff8, 0x4ae0, { 20, 20, 17, 17, 17, 17, 12}}, + {m68000_base_device_ops::m68k_op_tas_8_di, 0xfff8, 0x4ae8, { 22, 22, 17, 17, 17, 17, 12}}, + {m68000_base_device_ops::m68k_op_tas_8_ix, 0xfff8, 0x4af0, { 24, 24, 19, 19, 19, 19, 12}}, + {m68000_base_device_ops::m68k_op_mull_32_d, 0xfff8, 0x4c00, {255, 255, 43, 43, 43, 43, 43}}, + {m68000_base_device_ops::m68k_op_mull_32_ai, 0xfff8, 0x4c10, {255, 255, 47, 47, 47, 47, 43}}, + {m68000_base_device_ops::m68k_op_mull_32_pi, 0xfff8, 0x4c18, {255, 255, 47, 47, 47, 47, 43}}, + {m68000_base_device_ops::m68k_op_mull_32_pd, 0xfff8, 0x4c20, {255, 255, 48, 48, 48, 48, 43}}, + {m68000_base_device_ops::m68k_op_mull_32_di, 0xfff8, 0x4c28, {255, 255, 48, 48, 48, 48, 43}}, + {m68000_base_device_ops::m68k_op_mull_32_ix, 0xfff8, 0x4c30, {255, 255, 50, 50, 50, 50, 43}}, + {m68000_base_device_ops::m68k_op_divl_32_d, 0xfff8, 0x4c40, {255, 255, 84, 84, 84, 84, 84}}, + {m68000_base_device_ops::m68k_op_divl_32_ai, 0xfff8, 0x4c50, {255, 255, 88, 88, 88, 88, 84}}, + {m68000_base_device_ops::m68k_op_divl_32_pi, 0xfff8, 0x4c58, {255, 255, 88, 88, 88, 88, 84}}, + {m68000_base_device_ops::m68k_op_divl_32_pd, 0xfff8, 0x4c60, {255, 255, 89, 89, 89, 89, 84}}, + {m68000_base_device_ops::m68k_op_divl_32_di, 0xfff8, 0x4c68, {255, 255, 89, 89, 89, 89, 84}}, + {m68000_base_device_ops::m68k_op_divl_32_ix, 0xfff8, 0x4c70, {255, 255, 91, 91, 91, 91, 84}}, + {m68000_base_device_ops::m68k_op_movem_16_er_ai, 0xfff8, 0x4c90, { 12, 12, 12, 12, 12, 12, 8}}, + {m68000_base_device_ops::m68k_op_movem_16_er_pi, 0xfff8, 0x4c98, { 12, 12, 8, 8, 8, 8, 8}}, + {m68000_base_device_ops::m68k_op_movem_16_er_di, 0xfff8, 0x4ca8, { 16, 16, 13, 13, 13, 13, 8}}, + {m68000_base_device_ops::m68k_op_movem_16_er_ix, 0xfff8, 0x4cb0, { 18, 18, 15, 15, 15, 15, 8}}, + {m68000_base_device_ops::m68k_op_movem_32_er_ai, 0xfff8, 0x4cd0, { 12, 12, 12, 12, 12, 12, 8}}, + {m68000_base_device_ops::m68k_op_movem_32_er_pi, 0xfff8, 0x4cd8, { 12, 12, 8, 8, 8, 8, 8}}, + {m68000_base_device_ops::m68k_op_movem_32_er_di, 0xfff8, 0x4ce8, { 16, 16, 13, 13, 13, 13, 8}}, + {m68000_base_device_ops::m68k_op_movem_32_er_ix, 0xfff8, 0x4cf0, { 18, 18, 15, 15, 15, 15, 8}}, + {m68000_base_device_ops::m68k_op_link_16, 0xfff8, 0x4e50, { 16, 16, 5, 5, 5, 5, 5}}, + {m68000_base_device_ops::m68k_op_unlk_32, 0xfff8, 0x4e58, { 12, 12, 6, 6, 6, 6, 6}}, + {m68000_base_device_ops::m68k_op_move_32_tou, 0xfff8, 0x4e60, { 4, 6, 2, 2, 2, 2, 2}}, + {m68000_base_device_ops::m68k_op_move_32_fru, 0xfff8, 0x4e68, { 4, 6, 2, 2, 2, 2, 2}}, + {m68000_base_device_ops::m68k_op_jsr_32_ai, 0xfff8, 0x4e90, { 16, 16, 4, 4, 4, 4, 0}}, + {m68000_base_device_ops::m68k_op_jsr_32_di, 0xfff8, 0x4ea8, { 18, 18, 5, 5, 5, 5, 0}}, + {m68000_base_device_ops::m68k_op_jsr_32_ix, 0xfff8, 0x4eb0, { 22, 22, 7, 7, 7, 7, 0}}, + {m68000_base_device_ops::m68k_op_jmp_32_ai, 0xfff8, 0x4ed0, { 8, 8, 4, 4, 4, 4, 0}}, + {m68000_base_device_ops::m68k_op_jmp_32_di, 0xfff8, 0x4ee8, { 10, 10, 5, 5, 5, 5, 0}}, + {m68000_base_device_ops::m68k_op_jmp_32_ix, 0xfff8, 0x4ef0, { 14, 14, 7, 7, 7, 7, 0}}, + {m68000_base_device_ops::m68k_op_st_8_d, 0xfff8, 0x50c0, { 6, 4, 4, 4, 4, 4, 4}}, + {m68000_base_device_ops::m68k_op_dbt_16, 0xfff8, 0x50c8, { 12, 12, 6, 6, 6, 6, 6}}, + {m68000_base_device_ops::m68k_op_st_8_ai, 0xfff8, 0x50d0, { 12, 12, 10, 10, 10, 10, 6}}, + {m68000_base_device_ops::m68k_op_st_8_pi, 0xfff8, 0x50d8, { 12, 12, 10, 10, 10, 10, 6}}, + {m68000_base_device_ops::m68k_op_st_8_pd, 0xfff8, 0x50e0, { 14, 14, 11, 11, 11, 11, 6}}, + {m68000_base_device_ops::m68k_op_st_8_di, 0xfff8, 0x50e8, { 16, 16, 11, 11, 11, 11, 6}}, + {m68000_base_device_ops::m68k_op_st_8_ix, 0xfff8, 0x50f0, { 18, 18, 13, 13, 13, 13, 6}}, + {m68000_base_device_ops::m68k_op_sf_8_d, 0xfff8, 0x51c0, { 4, 4, 4, 4, 4, 4, 4}}, + {m68000_base_device_ops::m68k_op_dbf_16, 0xfff8, 0x51c8, { 12, 12, 6, 4, 4, 4, 4}}, + {m68000_base_device_ops::m68k_op_sf_8_ai, 0xfff8, 0x51d0, { 12, 12, 10, 10, 10, 10, 6}}, + {m68000_base_device_ops::m68k_op_sf_8_pi, 0xfff8, 0x51d8, { 12, 12, 10, 10, 10, 10, 6}}, + {m68000_base_device_ops::m68k_op_sf_8_pd, 0xfff8, 0x51e0, { 14, 14, 11, 11, 11, 11, 6}}, + {m68000_base_device_ops::m68k_op_sf_8_di, 0xfff8, 0x51e8, { 16, 16, 11, 11, 11, 11, 6}}, + {m68000_base_device_ops::m68k_op_sf_8_ix, 0xfff8, 0x51f0, { 18, 18, 13, 13, 13, 13, 6}}, + {m68000_base_device_ops::m68k_op_shi_8_d, 0xfff8, 0x52c0, { 4, 4, 4, 4, 4, 4, 4}}, + {m68000_base_device_ops::m68k_op_dbhi_16, 0xfff8, 0x52c8, { 12, 12, 6, 6, 6, 6, 6}}, + {m68000_base_device_ops::m68k_op_shi_8_ai, 0xfff8, 0x52d0, { 12, 12, 10, 10, 10, 10, 6}}, + {m68000_base_device_ops::m68k_op_shi_8_pi, 0xfff8, 0x52d8, { 12, 12, 10, 10, 10, 10, 6}}, + {m68000_base_device_ops::m68k_op_shi_8_pd, 0xfff8, 0x52e0, { 14, 14, 11, 11, 11, 11, 6}}, + {m68000_base_device_ops::m68k_op_shi_8_di, 0xfff8, 0x52e8, { 16, 16, 11, 11, 11, 11, 6}}, + {m68000_base_device_ops::m68k_op_shi_8_ix, 0xfff8, 0x52f0, { 18, 18, 13, 13, 13, 13, 6}}, + {m68000_base_device_ops::m68k_op_sls_8_d, 0xfff8, 0x53c0, { 4, 4, 4, 4, 4, 4, 4}}, + {m68000_base_device_ops::m68k_op_dbls_16, 0xfff8, 0x53c8, { 12, 12, 6, 6, 6, 6, 6}}, + {m68000_base_device_ops::m68k_op_sls_8_ai, 0xfff8, 0x53d0, { 12, 12, 10, 10, 10, 10, 6}}, + {m68000_base_device_ops::m68k_op_sls_8_pi, 0xfff8, 0x53d8, { 12, 12, 10, 10, 10, 10, 6}}, + {m68000_base_device_ops::m68k_op_sls_8_pd, 0xfff8, 0x53e0, { 14, 14, 11, 11, 11, 11, 6}}, + {m68000_base_device_ops::m68k_op_sls_8_di, 0xfff8, 0x53e8, { 16, 16, 11, 11, 11, 11, 6}}, + {m68000_base_device_ops::m68k_op_sls_8_ix, 0xfff8, 0x53f0, { 18, 18, 13, 13, 13, 13, 6}}, + {m68000_base_device_ops::m68k_op_scc_8_d, 0xfff8, 0x54c0, { 4, 4, 4, 4, 4, 4, 4}}, + {m68000_base_device_ops::m68k_op_dbcc_16, 0xfff8, 0x54c8, { 12, 12, 6, 6, 6, 6, 6}}, + {m68000_base_device_ops::m68k_op_scc_8_ai, 0xfff8, 0x54d0, { 12, 12, 10, 10, 10, 10, 6}}, + {m68000_base_device_ops::m68k_op_scc_8_pi, 0xfff8, 0x54d8, { 12, 12, 10, 10, 10, 10, 6}}, + {m68000_base_device_ops::m68k_op_scc_8_pd, 0xfff8, 0x54e0, { 14, 14, 11, 11, 11, 11, 6}}, + {m68000_base_device_ops::m68k_op_scc_8_di, 0xfff8, 0x54e8, { 16, 16, 11, 11, 11, 11, 6}}, + {m68000_base_device_ops::m68k_op_scc_8_ix, 0xfff8, 0x54f0, { 18, 18, 13, 13, 13, 13, 6}}, + {m68000_base_device_ops::m68k_op_scs_8_d, 0xfff8, 0x55c0, { 4, 4, 4, 4, 4, 4, 4}}, + {m68000_base_device_ops::m68k_op_dbcs_16, 0xfff8, 0x55c8, { 12, 12, 6, 6, 6, 6, 6}}, + {m68000_base_device_ops::m68k_op_scs_8_ai, 0xfff8, 0x55d0, { 12, 12, 10, 10, 10, 10, 6}}, + {m68000_base_device_ops::m68k_op_scs_8_pi, 0xfff8, 0x55d8, { 12, 12, 10, 10, 10, 10, 6}}, + {m68000_base_device_ops::m68k_op_scs_8_pd, 0xfff8, 0x55e0, { 14, 14, 11, 11, 11, 11, 6}}, + {m68000_base_device_ops::m68k_op_scs_8_di, 0xfff8, 0x55e8, { 16, 16, 11, 11, 11, 11, 6}}, + {m68000_base_device_ops::m68k_op_scs_8_ix, 0xfff8, 0x55f0, { 18, 18, 13, 13, 13, 13, 6}}, + {m68000_base_device_ops::m68k_op_sne_8_d, 0xfff8, 0x56c0, { 4, 4, 4, 4, 4, 4, 4}}, + {m68000_base_device_ops::m68k_op_dbne_16, 0xfff8, 0x56c8, { 12, 12, 6, 6, 6, 6, 6}}, + {m68000_base_device_ops::m68k_op_sne_8_ai, 0xfff8, 0x56d0, { 12, 12, 10, 10, 10, 10, 6}}, + {m68000_base_device_ops::m68k_op_sne_8_pi, 0xfff8, 0x56d8, { 12, 12, 10, 10, 10, 10, 6}}, + {m68000_base_device_ops::m68k_op_sne_8_pd, 0xfff8, 0x56e0, { 14, 14, 11, 11, 11, 11, 6}}, + {m68000_base_device_ops::m68k_op_sne_8_di, 0xfff8, 0x56e8, { 16, 16, 11, 11, 11, 11, 6}}, + {m68000_base_device_ops::m68k_op_sne_8_ix, 0xfff8, 0x56f0, { 18, 18, 13, 13, 13, 13, 6}}, + {m68000_base_device_ops::m68k_op_seq_8_d, 0xfff8, 0x57c0, { 4, 4, 4, 4, 4, 4, 4}}, + {m68000_base_device_ops::m68k_op_dbeq_16, 0xfff8, 0x57c8, { 12, 12, 6, 6, 6, 6, 6}}, + {m68000_base_device_ops::m68k_op_seq_8_ai, 0xfff8, 0x57d0, { 12, 12, 10, 10, 10, 10, 6}}, + {m68000_base_device_ops::m68k_op_seq_8_pi, 0xfff8, 0x57d8, { 12, 12, 10, 10, 10, 10, 6}}, + {m68000_base_device_ops::m68k_op_seq_8_pd, 0xfff8, 0x57e0, { 14, 14, 11, 11, 11, 11, 6}}, + {m68000_base_device_ops::m68k_op_seq_8_di, 0xfff8, 0x57e8, { 16, 16, 11, 11, 11, 11, 6}}, + {m68000_base_device_ops::m68k_op_seq_8_ix, 0xfff8, 0x57f0, { 18, 18, 13, 13, 13, 13, 6}}, + {m68000_base_device_ops::m68k_op_svc_8_d, 0xfff8, 0x58c0, { 4, 4, 4, 4, 4, 4, 4}}, + {m68000_base_device_ops::m68k_op_dbvc_16, 0xfff8, 0x58c8, { 12, 12, 6, 6, 6, 6, 6}}, + {m68000_base_device_ops::m68k_op_svc_8_ai, 0xfff8, 0x58d0, { 12, 12, 10, 10, 10, 10, 6}}, + {m68000_base_device_ops::m68k_op_svc_8_pi, 0xfff8, 0x58d8, { 12, 12, 10, 10, 10, 10, 6}}, + {m68000_base_device_ops::m68k_op_svc_8_pd, 0xfff8, 0x58e0, { 14, 14, 11, 11, 11, 11, 6}}, + {m68000_base_device_ops::m68k_op_svc_8_di, 0xfff8, 0x58e8, { 16, 16, 11, 11, 11, 11, 6}}, + {m68000_base_device_ops::m68k_op_svc_8_ix, 0xfff8, 0x58f0, { 18, 18, 13, 13, 13, 13, 6}}, + {m68000_base_device_ops::m68k_op_svs_8_d, 0xfff8, 0x59c0, { 4, 4, 4, 4, 4, 4, 4}}, + {m68000_base_device_ops::m68k_op_dbvs_16, 0xfff8, 0x59c8, { 12, 12, 6, 6, 6, 6, 6}}, + {m68000_base_device_ops::m68k_op_svs_8_ai, 0xfff8, 0x59d0, { 12, 12, 10, 10, 10, 10, 6}}, + {m68000_base_device_ops::m68k_op_svs_8_pi, 0xfff8, 0x59d8, { 12, 12, 10, 10, 10, 10, 6}}, + {m68000_base_device_ops::m68k_op_svs_8_pd, 0xfff8, 0x59e0, { 14, 14, 11, 11, 11, 11, 6}}, + {m68000_base_device_ops::m68k_op_svs_8_di, 0xfff8, 0x59e8, { 16, 16, 11, 11, 11, 11, 6}}, + {m68000_base_device_ops::m68k_op_svs_8_ix, 0xfff8, 0x59f0, { 18, 18, 13, 13, 13, 13, 6}}, + {m68000_base_device_ops::m68k_op_spl_8_d, 0xfff8, 0x5ac0, { 4, 4, 4, 4, 4, 4, 4}}, + {m68000_base_device_ops::m68k_op_dbpl_16, 0xfff8, 0x5ac8, { 12, 12, 6, 6, 6, 6, 6}}, + {m68000_base_device_ops::m68k_op_spl_8_ai, 0xfff8, 0x5ad0, { 12, 12, 10, 10, 10, 10, 6}}, + {m68000_base_device_ops::m68k_op_spl_8_pi, 0xfff8, 0x5ad8, { 12, 12, 10, 10, 10, 10, 6}}, + {m68000_base_device_ops::m68k_op_spl_8_pd, 0xfff8, 0x5ae0, { 14, 14, 11, 11, 11, 11, 6}}, + {m68000_base_device_ops::m68k_op_spl_8_di, 0xfff8, 0x5ae8, { 16, 16, 11, 11, 11, 11, 6}}, + {m68000_base_device_ops::m68k_op_spl_8_ix, 0xfff8, 0x5af0, { 18, 18, 13, 13, 13, 13, 6}}, + {m68000_base_device_ops::m68k_op_smi_8_d, 0xfff8, 0x5bc0, { 4, 4, 4, 4, 4, 4, 4}}, + {m68000_base_device_ops::m68k_op_dbmi_16, 0xfff8, 0x5bc8, { 12, 12, 6, 6, 6, 6, 6}}, + {m68000_base_device_ops::m68k_op_smi_8_ai, 0xfff8, 0x5bd0, { 12, 12, 10, 10, 10, 10, 6}}, + {m68000_base_device_ops::m68k_op_smi_8_pi, 0xfff8, 0x5bd8, { 12, 12, 10, 10, 10, 10, 6}}, + {m68000_base_device_ops::m68k_op_smi_8_pd, 0xfff8, 0x5be0, { 14, 14, 11, 11, 11, 11, 6}}, + {m68000_base_device_ops::m68k_op_smi_8_di, 0xfff8, 0x5be8, { 16, 16, 11, 11, 11, 11, 6}}, + {m68000_base_device_ops::m68k_op_smi_8_ix, 0xfff8, 0x5bf0, { 18, 18, 13, 13, 13, 13, 6}}, + {m68000_base_device_ops::m68k_op_sge_8_d, 0xfff8, 0x5cc0, { 4, 4, 4, 4, 4, 4, 4}}, + {m68000_base_device_ops::m68k_op_dbge_16, 0xfff8, 0x5cc8, { 12, 12, 6, 6, 6, 6, 6}}, + {m68000_base_device_ops::m68k_op_sge_8_ai, 0xfff8, 0x5cd0, { 12, 12, 10, 10, 10, 10, 6}}, + {m68000_base_device_ops::m68k_op_sge_8_pi, 0xfff8, 0x5cd8, { 12, 12, 10, 10, 10, 10, 6}}, + {m68000_base_device_ops::m68k_op_sge_8_pd, 0xfff8, 0x5ce0, { 14, 14, 11, 11, 11, 11, 6}}, + {m68000_base_device_ops::m68k_op_sge_8_di, 0xfff8, 0x5ce8, { 16, 16, 11, 11, 11, 11, 6}}, + {m68000_base_device_ops::m68k_op_sge_8_ix, 0xfff8, 0x5cf0, { 18, 18, 13, 13, 13, 13, 6}}, + {m68000_base_device_ops::m68k_op_slt_8_d, 0xfff8, 0x5dc0, { 4, 4, 4, 4, 4, 4, 4}}, + {m68000_base_device_ops::m68k_op_dblt_16, 0xfff8, 0x5dc8, { 12, 12, 6, 6, 6, 6, 6}}, + {m68000_base_device_ops::m68k_op_slt_8_ai, 0xfff8, 0x5dd0, { 12, 12, 10, 10, 10, 10, 6}}, + {m68000_base_device_ops::m68k_op_slt_8_pi, 0xfff8, 0x5dd8, { 12, 12, 10, 10, 10, 10, 6}}, + {m68000_base_device_ops::m68k_op_slt_8_pd, 0xfff8, 0x5de0, { 14, 14, 11, 11, 11, 11, 6}}, + {m68000_base_device_ops::m68k_op_slt_8_di, 0xfff8, 0x5de8, { 16, 16, 11, 11, 11, 11, 6}}, + {m68000_base_device_ops::m68k_op_slt_8_ix, 0xfff8, 0x5df0, { 18, 18, 13, 13, 13, 13, 6}}, + {m68000_base_device_ops::m68k_op_sgt_8_d, 0xfff8, 0x5ec0, { 4, 4, 4, 4, 4, 4, 4}}, + {m68000_base_device_ops::m68k_op_dbgt_16, 0xfff8, 0x5ec8, { 12, 12, 6, 6, 6, 6, 6}}, + {m68000_base_device_ops::m68k_op_sgt_8_ai, 0xfff8, 0x5ed0, { 12, 12, 10, 10, 10, 10, 6}}, + {m68000_base_device_ops::m68k_op_sgt_8_pi, 0xfff8, 0x5ed8, { 12, 12, 10, 10, 10, 10, 6}}, + {m68000_base_device_ops::m68k_op_sgt_8_pd, 0xfff8, 0x5ee0, { 14, 14, 11, 11, 11, 11, 6}}, + {m68000_base_device_ops::m68k_op_sgt_8_di, 0xfff8, 0x5ee8, { 16, 16, 11, 11, 11, 11, 6}}, + {m68000_base_device_ops::m68k_op_sgt_8_ix, 0xfff8, 0x5ef0, { 18, 18, 13, 13, 13, 13, 6}}, + {m68000_base_device_ops::m68k_op_sle_8_d, 0xfff8, 0x5fc0, { 4, 4, 4, 4, 4, 4, 4}}, + {m68000_base_device_ops::m68k_op_dble_16, 0xfff8, 0x5fc8, { 12, 12, 6, 6, 6, 6, 6}}, + {m68000_base_device_ops::m68k_op_sle_8_ai, 0xfff8, 0x5fd0, { 12, 12, 10, 10, 10, 10, 6}}, + {m68000_base_device_ops::m68k_op_sle_8_pi, 0xfff8, 0x5fd8, { 12, 12, 10, 10, 10, 10, 6}}, + {m68000_base_device_ops::m68k_op_sle_8_pd, 0xfff8, 0x5fe0, { 14, 14, 11, 11, 11, 11, 6}}, + {m68000_base_device_ops::m68k_op_sle_8_di, 0xfff8, 0x5fe8, { 16, 16, 11, 11, 11, 11, 6}}, + {m68000_base_device_ops::m68k_op_sle_8_ix, 0xfff8, 0x5ff0, { 18, 18, 13, 13, 13, 13, 6}}, + {m68000_base_device_ops::m68k_op_sbcd_8_mm_ax7, 0xfff8, 0x8f08, { 18, 18, 16, 16, 16, 16, 16}}, + {m68000_base_device_ops::m68k_op_pack_16_mm_ax7, 0xfff8, 0x8f48, {255, 255, 13, 13, 13, 13, 13}}, + {m68000_base_device_ops::m68k_op_unpk_16_mm_ax7, 0xfff8, 0x8f88, {255, 255, 13, 13, 13, 13, 13}}, + {m68000_base_device_ops::m68k_op_subx_8_mm_ax7, 0xfff8, 0x9f08, { 18, 18, 12, 12, 12, 12, 12}}, + {m68000_base_device_ops::m68k_op_cmpm_8_ax7, 0xfff8, 0xbf08, { 12, 12, 9, 9, 9, 9, 9}}, + {m68000_base_device_ops::m68k_op_abcd_8_mm_ax7, 0xfff8, 0xcf08, { 18, 18, 16, 16, 16, 16, 16}}, + {m68000_base_device_ops::m68k_op_addx_8_mm_ax7, 0xfff8, 0xdf08, { 18, 18, 12, 12, 12, 12, 12}}, + {m68000_base_device_ops::m68k_op_asr_16_ai, 0xfff8, 0xe0d0, { 12, 12, 9, 9, 9, 9, 5}}, + {m68000_base_device_ops::m68k_op_asr_16_pi, 0xfff8, 0xe0d8, { 12, 12, 9, 9, 9, 9, 5}}, + {m68000_base_device_ops::m68k_op_asr_16_pd, 0xfff8, 0xe0e0, { 14, 14, 10, 10, 10, 10, 5}}, + {m68000_base_device_ops::m68k_op_asr_16_di, 0xfff8, 0xe0e8, { 16, 16, 10, 10, 10, 10, 5}}, + {m68000_base_device_ops::m68k_op_asr_16_ix, 0xfff8, 0xe0f0, { 18, 18, 12, 12, 12, 12, 5}}, + {m68000_base_device_ops::m68k_op_asl_16_ai, 0xfff8, 0xe1d0, { 12, 12, 10, 10, 10, 10, 6}}, + {m68000_base_device_ops::m68k_op_asl_16_pi, 0xfff8, 0xe1d8, { 12, 12, 10, 10, 10, 10, 6}}, + {m68000_base_device_ops::m68k_op_asl_16_pd, 0xfff8, 0xe1e0, { 14, 14, 11, 11, 11, 11, 6}}, + {m68000_base_device_ops::m68k_op_asl_16_di, 0xfff8, 0xe1e8, { 16, 16, 11, 11, 11, 11, 6}}, + {m68000_base_device_ops::m68k_op_asl_16_ix, 0xfff8, 0xe1f0, { 18, 18, 13, 13, 13, 13, 6}}, + {m68000_base_device_ops::m68k_op_lsr_16_ai, 0xfff8, 0xe2d0, { 12, 12, 9, 9, 9, 9, 5}}, + {m68000_base_device_ops::m68k_op_lsr_16_pi, 0xfff8, 0xe2d8, { 12, 12, 9, 9, 9, 9, 5}}, + {m68000_base_device_ops::m68k_op_lsr_16_pd, 0xfff8, 0xe2e0, { 14, 14, 10, 10, 10, 10, 5}}, + {m68000_base_device_ops::m68k_op_lsr_16_di, 0xfff8, 0xe2e8, { 16, 16, 10, 10, 10, 10, 5}}, + {m68000_base_device_ops::m68k_op_lsr_16_ix, 0xfff8, 0xe2f0, { 18, 18, 12, 12, 12, 12, 5}}, + {m68000_base_device_ops::m68k_op_lsl_16_ai, 0xfff8, 0xe3d0, { 12, 12, 9, 9, 9, 9, 5}}, + {m68000_base_device_ops::m68k_op_lsl_16_pi, 0xfff8, 0xe3d8, { 12, 12, 9, 9, 9, 9, 5}}, + {m68000_base_device_ops::m68k_op_lsl_16_pd, 0xfff8, 0xe3e0, { 14, 14, 10, 10, 10, 10, 5}}, + {m68000_base_device_ops::m68k_op_lsl_16_di, 0xfff8, 0xe3e8, { 16, 16, 10, 10, 10, 10, 5}}, + {m68000_base_device_ops::m68k_op_lsl_16_ix, 0xfff8, 0xe3f0, { 18, 18, 12, 12, 12, 12, 5}}, + {m68000_base_device_ops::m68k_op_roxr_16_ai, 0xfff8, 0xe4d0, { 12, 12, 9, 9, 9, 9, 5}}, + {m68000_base_device_ops::m68k_op_roxr_16_pi, 0xfff8, 0xe4d8, { 12, 12, 9, 9, 9, 9, 5}}, + {m68000_base_device_ops::m68k_op_roxr_16_pd, 0xfff8, 0xe4e0, { 14, 14, 10, 10, 10, 10, 5}}, + {m68000_base_device_ops::m68k_op_roxr_16_di, 0xfff8, 0xe4e8, { 16, 16, 10, 10, 10, 10, 5}}, + {m68000_base_device_ops::m68k_op_roxr_16_ix, 0xfff8, 0xe4f0, { 18, 18, 12, 12, 12, 12, 5}}, + {m68000_base_device_ops::m68k_op_roxl_16_ai, 0xfff8, 0xe5d0, { 12, 12, 9, 9, 9, 9, 5}}, + {m68000_base_device_ops::m68k_op_roxl_16_pi, 0xfff8, 0xe5d8, { 12, 12, 9, 9, 9, 9, 5}}, + {m68000_base_device_ops::m68k_op_roxl_16_pd, 0xfff8, 0xe5e0, { 14, 14, 10, 10, 10, 10, 5}}, + {m68000_base_device_ops::m68k_op_roxl_16_di, 0xfff8, 0xe5e8, { 16, 16, 10, 10, 10, 10, 5}}, + {m68000_base_device_ops::m68k_op_roxl_16_ix, 0xfff8, 0xe5f0, { 18, 18, 12, 12, 12, 12, 5}}, + {m68000_base_device_ops::m68k_op_ror_16_ai, 0xfff8, 0xe6d0, { 12, 12, 11, 11, 11, 11, 7}}, + {m68000_base_device_ops::m68k_op_ror_16_pi, 0xfff8, 0xe6d8, { 12, 12, 11, 11, 11, 11, 7}}, + {m68000_base_device_ops::m68k_op_ror_16_pd, 0xfff8, 0xe6e0, { 14, 14, 12, 12, 12, 12, 7}}, + {m68000_base_device_ops::m68k_op_ror_16_di, 0xfff8, 0xe6e8, { 16, 16, 12, 12, 12, 12, 7}}, + {m68000_base_device_ops::m68k_op_ror_16_ix, 0xfff8, 0xe6f0, { 18, 18, 14, 14, 14, 14, 7}}, + {m68000_base_device_ops::m68k_op_rol_16_ai, 0xfff8, 0xe7d0, { 12, 12, 11, 11, 11, 11, 7}}, + {m68000_base_device_ops::m68k_op_rol_16_pi, 0xfff8, 0xe7d8, { 12, 12, 11, 11, 11, 11, 7}}, + {m68000_base_device_ops::m68k_op_rol_16_pd, 0xfff8, 0xe7e0, { 14, 14, 12, 12, 12, 12, 7}}, + {m68000_base_device_ops::m68k_op_rol_16_di, 0xfff8, 0xe7e8, { 16, 16, 12, 12, 12, 12, 7}}, + {m68000_base_device_ops::m68k_op_rol_16_ix, 0xfff8, 0xe7f0, { 18, 18, 14, 14, 14, 14, 7}}, + {m68000_base_device_ops::m68k_op_bftst_32_d, 0xfff8, 0xe8c0, {255, 255, 6, 6, 6, 6, 6}}, + {m68000_base_device_ops::m68k_op_bftst_32_ai, 0xfff8, 0xe8d0, {255, 255, 17, 17, 17, 17, 13}}, + {m68000_base_device_ops::m68k_op_bftst_32_di, 0xfff8, 0xe8e8, {255, 255, 18, 18, 18, 18, 13}}, + {m68000_base_device_ops::m68k_op_bftst_32_ix, 0xfff8, 0xe8f0, {255, 255, 20, 20, 20, 20, 13}}, + {m68000_base_device_ops::m68k_op_bfextu_32_d, 0xfff8, 0xe9c0, {255, 255, 8, 8, 8, 8, 8}}, + {m68000_base_device_ops::m68k_op_bfextu_32_ai, 0xfff8, 0xe9d0, {255, 255, 19, 19, 19, 19, 15}}, + {m68000_base_device_ops::m68k_op_bfextu_32_di, 0xfff8, 0xe9e8, {255, 255, 20, 20, 20, 20, 15}}, + {m68000_base_device_ops::m68k_op_bfextu_32_ix, 0xfff8, 0xe9f0, {255, 255, 22, 22, 22, 22, 15}}, + {m68000_base_device_ops::m68k_op_bfchg_32_d, 0xfff8, 0xeac0, {255, 255, 12, 12, 12, 12, 12}}, + {m68000_base_device_ops::m68k_op_bfchg_32_ai, 0xfff8, 0xead0, {255, 255, 24, 24, 24, 24, 20}}, + {m68000_base_device_ops::m68k_op_bfchg_32_di, 0xfff8, 0xeae8, {255, 255, 25, 25, 25, 25, 20}}, + {m68000_base_device_ops::m68k_op_bfchg_32_ix, 0xfff8, 0xeaf0, {255, 255, 27, 27, 27, 27, 20}}, + {m68000_base_device_ops::m68k_op_bfexts_32_d, 0xfff8, 0xebc0, {255, 255, 8, 8, 8, 8, 8}}, + {m68000_base_device_ops::m68k_op_bfexts_32_ai, 0xfff8, 0xebd0, {255, 255, 19, 19, 19, 19, 15}}, + {m68000_base_device_ops::m68k_op_bfexts_32_di, 0xfff8, 0xebe8, {255, 255, 20, 20, 20, 20, 15}}, + {m68000_base_device_ops::m68k_op_bfexts_32_ix, 0xfff8, 0xebf0, {255, 255, 22, 22, 22, 22, 15}}, + {m68000_base_device_ops::m68k_op_bfclr_32_d, 0xfff8, 0xecc0, {255, 255, 12, 12, 12, 12, 12}}, + {m68000_base_device_ops::m68k_op_bfclr_32_ai, 0xfff8, 0xecd0, {255, 255, 24, 24, 24, 24, 20}}, + {m68000_base_device_ops::m68k_op_bfclr_32_di, 0xfff8, 0xece8, {255, 255, 25, 25, 25, 25, 20}}, + {m68000_base_device_ops::m68k_op_bfclr_32_ix, 0xfff8, 0xecf0, {255, 255, 27, 27, 27, 27, 20}}, + {m68000_base_device_ops::m68k_op_bfffo_32_d, 0xfff8, 0xedc0, {255, 255, 18, 18, 18, 18, 18}}, + {m68000_base_device_ops::m68k_op_bfffo_32_ai, 0xfff8, 0xedd0, {255, 255, 32, 32, 32, 32, 28}}, + {m68000_base_device_ops::m68k_op_bfffo_32_di, 0xfff8, 0xede8, {255, 255, 33, 33, 33, 33, 28}}, + {m68000_base_device_ops::m68k_op_bfffo_32_ix, 0xfff8, 0xedf0, {255, 255, 35, 35, 35, 35, 28}}, + {m68000_base_device_ops::m68k_op_bfset_32_d, 0xfff8, 0xeec0, {255, 255, 12, 12, 12, 12, 12}}, + {m68000_base_device_ops::m68k_op_bfset_32_ai, 0xfff8, 0xeed0, {255, 255, 24, 24, 24, 24, 20}}, + {m68000_base_device_ops::m68k_op_bfset_32_di, 0xfff8, 0xeee8, {255, 255, 25, 25, 25, 25, 20}}, + {m68000_base_device_ops::m68k_op_bfset_32_ix, 0xfff8, 0xeef0, {255, 255, 27, 27, 27, 27, 20}}, + {m68000_base_device_ops::m68k_op_bfins_32_d, 0xfff8, 0xefc0, {255, 255, 10, 10, 10, 10, 10}}, + {m68000_base_device_ops::m68k_op_bfins_32_ai, 0xfff8, 0xefd0, {255, 255, 21, 21, 21, 21, 17}}, + {m68000_base_device_ops::m68k_op_bfins_32_di, 0xfff8, 0xefe8, {255, 255, 22, 22, 22, 22, 17}}, + {m68000_base_device_ops::m68k_op_bfins_32_ix, 0xfff8, 0xeff0, {255, 255, 24, 24, 24, 24, 17}}, + {m68000_base_device_ops::m68k_op_ftrapcc_32, 0xfff8, 0xf278, {255, 255, 4, 4, 255, 255, 255}}, + {m68000_base_device_ops::m68k_op_pflushan_32, 0xfff8, 0xf510, {255, 255, 255, 255, 4, 4, 4}}, + {m68000_base_device_ops::m68k_op_pflusha_32, 0xfff8, 0xf518, {255, 255, 255, 255, 4, 4, 4}}, + {m68000_base_device_ops::m68k_op_move16_32, 0xfff8, 0xf620, {255, 255, 255, 255, 4, 4, 4}}, + {m68000_base_device_ops::m68k_op_ori_8_pi7, 0xffff, 0x001f, { 16, 16, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_ori_8_pd7, 0xffff, 0x0027, { 18, 18, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_ori_8_aw, 0xffff, 0x0038, { 20, 20, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_ori_8_al, 0xffff, 0x0039, { 24, 24, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_ori_16_toc, 0xffff, 0x003c, { 20, 16, 12, 12, 12, 12, 12}}, + {m68000_base_device_ops::m68k_op_ori_16_aw, 0xffff, 0x0078, { 20, 20, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_ori_16_al, 0xffff, 0x0079, { 24, 24, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_ori_16_tos, 0xffff, 0x007c, { 20, 16, 12, 12, 12, 12, 12}}, + {m68000_base_device_ops::m68k_op_ori_32_aw, 0xffff, 0x00b8, { 32, 32, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_ori_32_al, 0xffff, 0x00b9, { 36, 36, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_chk2cmp2_8_aw, 0xffff, 0x00f8, {255, 255, 22, 22, 22, 22, 18}}, + {m68000_base_device_ops::m68k_op_chk2cmp2_8_al, 0xffff, 0x00f9, {255, 255, 22, 22, 22, 22, 18}}, + {m68000_base_device_ops::m68k_op_chk2cmp2_8_pcdi, 0xffff, 0x00fa, {255, 255, 23, 23, 23, 23, 23}}, + {m68000_base_device_ops::m68k_op_chk2cmp2_8_pcix, 0xffff, 0x00fb, {255, 255, 23, 23, 23, 23, 23}}, + {m68000_base_device_ops::m68k_op_andi_8_pi7, 0xffff, 0x021f, { 16, 16, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_andi_8_pd7, 0xffff, 0x0227, { 18, 18, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_andi_8_aw, 0xffff, 0x0238, { 20, 20, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_andi_8_al, 0xffff, 0x0239, { 24, 24, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_andi_16_toc, 0xffff, 0x023c, { 20, 16, 12, 12, 12, 12, 12}}, + {m68000_base_device_ops::m68k_op_andi_16_aw, 0xffff, 0x0278, { 20, 20, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_andi_16_al, 0xffff, 0x0279, { 24, 24, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_andi_16_tos, 0xffff, 0x027c, { 20, 16, 12, 12, 12, 12, 12}}, + {m68000_base_device_ops::m68k_op_andi_32_aw, 0xffff, 0x02b8, { 32, 32, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_andi_32_al, 0xffff, 0x02b9, { 36, 36, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_chk2cmp2_16_aw, 0xffff, 0x02f8, {255, 255, 22, 22, 22, 22, 18}}, + {m68000_base_device_ops::m68k_op_chk2cmp2_16_al, 0xffff, 0x02f9, {255, 255, 22, 22, 22, 22, 18}}, + {m68000_base_device_ops::m68k_op_chk2cmp2_16_pcdi, 0xffff, 0x02fa, {255, 255, 23, 23, 23, 23, 23}}, + {m68000_base_device_ops::m68k_op_chk2cmp2_16_pcix, 0xffff, 0x02fb, {255, 255, 23, 23, 23, 23, 23}}, + {m68000_base_device_ops::m68k_op_subi_8_pi7, 0xffff, 0x041f, { 16, 16, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_subi_8_pd7, 0xffff, 0x0427, { 18, 18, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_subi_8_aw, 0xffff, 0x0438, { 20, 20, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_subi_8_al, 0xffff, 0x0439, { 24, 24, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_subi_16_aw, 0xffff, 0x0478, { 20, 20, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_subi_16_al, 0xffff, 0x0479, { 24, 24, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_subi_32_aw, 0xffff, 0x04b8, { 32, 32, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_subi_32_al, 0xffff, 0x04b9, { 36, 36, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_chk2cmp2_32_aw, 0xffff, 0x04f8, {255, 255, 22, 22, 22, 22, 18}}, + {m68000_base_device_ops::m68k_op_chk2cmp2_32_al, 0xffff, 0x04f9, {255, 255, 22, 22, 22, 22, 18}}, + {m68000_base_device_ops::m68k_op_chk2cmp2_32_pcdi, 0xffff, 0x04fa, {255, 255, 23, 23, 23, 23, 23}}, + {m68000_base_device_ops::m68k_op_chk2cmp2_32_pcix, 0xffff, 0x04fb, {255, 255, 23, 23, 23, 23, 23}}, + {m68000_base_device_ops::m68k_op_addi_8_pi7, 0xffff, 0x061f, { 16, 16, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_addi_8_pd7, 0xffff, 0x0627, { 18, 18, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_addi_8_aw, 0xffff, 0x0638, { 20, 20, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_addi_8_al, 0xffff, 0x0639, { 24, 24, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_addi_16_aw, 0xffff, 0x0678, { 20, 20, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_addi_16_al, 0xffff, 0x0679, { 24, 24, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_addi_32_aw, 0xffff, 0x06b8, { 32, 32, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_addi_32_al, 0xffff, 0x06b9, { 36, 36, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_callm_32_aw, 0xffff, 0x06f8, {255, 255, 64, 64, 64, 64, 60}}, + {m68000_base_device_ops::m68k_op_callm_32_al, 0xffff, 0x06f9, {255, 255, 64, 64, 64, 64, 60}}, + {m68000_base_device_ops::m68k_op_callm_32_pcdi, 0xffff, 0x06fa, {255, 255, 65, 65, 65, 65, 60}}, + {m68000_base_device_ops::m68k_op_callm_32_pcix, 0xffff, 0x06fb, {255, 255, 67, 67, 67, 67, 60}}, + {m68000_base_device_ops::m68k_op_btst_8_s_pi7, 0xffff, 0x081f, { 12, 12, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_btst_8_s_pd7, 0xffff, 0x0827, { 14, 14, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_btst_8_s_aw, 0xffff, 0x0838, { 16, 16, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_btst_8_s_al, 0xffff, 0x0839, { 20, 20, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_btst_8_s_pcdi, 0xffff, 0x083a, { 16, 16, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_btst_8_s_pcix, 0xffff, 0x083b, { 18, 18, 11, 11, 11, 11, 4}}, + {m68000_base_device_ops::m68k_op_bchg_8_s_pi7, 0xffff, 0x085f, { 16, 16, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_bchg_8_s_pd7, 0xffff, 0x0867, { 18, 18, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_bchg_8_s_aw, 0xffff, 0x0878, { 20, 20, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_bchg_8_s_al, 0xffff, 0x0879, { 24, 24, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_bclr_8_s_pi7, 0xffff, 0x089f, { 16, 16, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_bclr_8_s_pd7, 0xffff, 0x08a7, { 18, 18, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_bclr_8_s_aw, 0xffff, 0x08b8, { 20, 20, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_bclr_8_s_al, 0xffff, 0x08b9, { 24, 24, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_bset_8_s_pi7, 0xffff, 0x08df, { 16, 16, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_bset_8_s_pd7, 0xffff, 0x08e7, { 18, 18, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_bset_8_s_aw, 0xffff, 0x08f8, { 20, 20, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_bset_8_s_al, 0xffff, 0x08f9, { 24, 24, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_eori_8_pi7, 0xffff, 0x0a1f, { 16, 16, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_eori_8_pd7, 0xffff, 0x0a27, { 18, 18, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_eori_8_aw, 0xffff, 0x0a38, { 20, 20, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_eori_8_al, 0xffff, 0x0a39, { 24, 24, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_eori_16_toc, 0xffff, 0x0a3c, { 20, 16, 12, 12, 12, 12, 12}}, + {m68000_base_device_ops::m68k_op_eori_16_aw, 0xffff, 0x0a78, { 20, 20, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_eori_16_al, 0xffff, 0x0a79, { 24, 24, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_eori_16_tos, 0xffff, 0x0a7c, { 20, 16, 12, 12, 12, 12, 12}}, + {m68000_base_device_ops::m68k_op_eori_32_aw, 0xffff, 0x0ab8, { 32, 32, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_eori_32_al, 0xffff, 0x0ab9, { 36, 36, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_cas_8_pi7, 0xffff, 0x0adf, {255, 255, 16, 16, 16, 16, 12}}, + {m68000_base_device_ops::m68k_op_cas_8_pd7, 0xffff, 0x0ae7, {255, 255, 17, 17, 17, 17, 12}}, + {m68000_base_device_ops::m68k_op_cas_8_aw, 0xffff, 0x0af8, {255, 255, 16, 16, 16, 16, 12}}, + {m68000_base_device_ops::m68k_op_cas_8_al, 0xffff, 0x0af9, {255, 255, 16, 16, 16, 16, 12}}, + {m68000_base_device_ops::m68k_op_cmpi_8_pi7, 0xffff, 0x0c1f, { 12, 12, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_cmpi_8_pd7, 0xffff, 0x0c27, { 14, 14, 7, 7, 7, 7, 2}}, + {m68000_base_device_ops::m68k_op_cmpi_8_aw, 0xffff, 0x0c38, { 16, 16, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_cmpi_8_al, 0xffff, 0x0c39, { 20, 20, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_cmpi_8_pcdi, 0xffff, 0x0c3a, {255, 255, 7, 7, 7, 7, 7}}, + {m68000_base_device_ops::m68k_op_cmpi_8_pcix, 0xffff, 0x0c3b, {255, 255, 9, 9, 9, 9, 9}}, + {m68000_base_device_ops::m68k_op_cmpi_16_aw, 0xffff, 0x0c78, { 16, 16, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_cmpi_16_al, 0xffff, 0x0c79, { 20, 20, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_cmpi_16_pcdi, 0xffff, 0x0c7a, {255, 255, 7, 7, 7, 7, 7}}, + {m68000_base_device_ops::m68k_op_cmpi_16_pcix, 0xffff, 0x0c7b, {255, 255, 9, 9, 9, 9, 9}}, + {m68000_base_device_ops::m68k_op_cmpi_32_aw, 0xffff, 0x0cb8, { 24, 24, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_cmpi_32_al, 0xffff, 0x0cb9, { 28, 28, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_cmpi_32_pcdi, 0xffff, 0x0cba, {255, 255, 7, 7, 7, 7, 7}}, + {m68000_base_device_ops::m68k_op_cmpi_32_pcix, 0xffff, 0x0cbb, {255, 255, 9, 9, 9, 9, 9}}, + {m68000_base_device_ops::m68k_op_cas_16_aw, 0xffff, 0x0cf8, {255, 255, 16, 16, 16, 16, 12}}, + {m68000_base_device_ops::m68k_op_cas_16_al, 0xffff, 0x0cf9, {255, 255, 16, 16, 16, 16, 12}}, + {m68000_base_device_ops::m68k_op_cas2_16, 0xffff, 0x0cfc, {255, 255, 12, 12, 12, 12, 12}}, + {m68000_base_device_ops::m68k_op_moves_8_pi7, 0xffff, 0x0e1f, {255, 18, 9, 9, 9, 9, 5}}, + {m68000_base_device_ops::m68k_op_moves_8_pd7, 0xffff, 0x0e27, {255, 20, 10, 10, 10, 10, 5}}, + {m68000_base_device_ops::m68k_op_moves_8_aw, 0xffff, 0x0e38, {255, 26, 9, 9, 9, 9, 5}}, + {m68000_base_device_ops::m68k_op_moves_8_al, 0xffff, 0x0e39, {255, 30, 9, 9, 9, 9, 5}}, + {m68000_base_device_ops::m68k_op_moves_16_aw, 0xffff, 0x0e78, {255, 26, 9, 9, 9, 9, 5}}, + {m68000_base_device_ops::m68k_op_moves_16_al, 0xffff, 0x0e79, {255, 30, 9, 9, 9, 9, 5}}, + {m68000_base_device_ops::m68k_op_moves_32_aw, 0xffff, 0x0eb8, {255, 32, 9, 9, 9, 9, 5}}, + {m68000_base_device_ops::m68k_op_moves_32_al, 0xffff, 0x0eb9, {255, 36, 9, 9, 9, 9, 5}}, + {m68000_base_device_ops::m68k_op_cas_32_aw, 0xffff, 0x0ef8, {255, 255, 16, 16, 16, 16, 12}}, + {m68000_base_device_ops::m68k_op_cas_32_al, 0xffff, 0x0ef9, {255, 255, 16, 16, 16, 16, 12}}, + {m68000_base_device_ops::m68k_op_cas2_32, 0xffff, 0x0efc, {255, 255, 12, 12, 12, 12, 12}}, + {m68000_base_device_ops::m68k_op_move_8_aw_pi7, 0xffff, 0x11df, { 16, 16, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_move_8_aw_pd7, 0xffff, 0x11e7, { 18, 18, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_move_8_aw_aw, 0xffff, 0x11f8, { 20, 20, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_move_8_aw_al, 0xffff, 0x11f9, { 24, 24, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_move_8_aw_pcdi, 0xffff, 0x11fa, { 20, 20, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_move_8_aw_pcix, 0xffff, 0x11fb, { 22, 22, 11, 11, 11, 11, 4}}, + {m68000_base_device_ops::m68k_op_move_8_aw_i, 0xffff, 0x11fc, { 16, 16, 6, 6, 6, 6, 4}}, + {m68000_base_device_ops::m68k_op_move_8_al_pi7, 0xffff, 0x13df, { 20, 20, 10, 10, 10, 10, 6}}, + {m68000_base_device_ops::m68k_op_move_8_al_pd7, 0xffff, 0x13e7, { 22, 22, 11, 11, 11, 11, 6}}, + {m68000_base_device_ops::m68k_op_move_8_al_aw, 0xffff, 0x13f8, { 24, 24, 10, 10, 10, 10, 6}}, + {m68000_base_device_ops::m68k_op_move_8_al_al, 0xffff, 0x13f9, { 28, 28, 10, 10, 10, 10, 6}}, + {m68000_base_device_ops::m68k_op_move_8_al_pcdi, 0xffff, 0x13fa, { 24, 24, 11, 11, 11, 11, 6}}, + {m68000_base_device_ops::m68k_op_move_8_al_pcix, 0xffff, 0x13fb, { 26, 26, 13, 13, 13, 13, 6}}, + {m68000_base_device_ops::m68k_op_move_8_al_i, 0xffff, 0x13fc, { 20, 20, 8, 8, 8, 8, 6}}, + {m68000_base_device_ops::m68k_op_move_8_pi7_pi7, 0xffff, 0x1edf, { 12, 12, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_move_8_pi7_pd7, 0xffff, 0x1ee7, { 14, 14, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_move_8_pi7_aw, 0xffff, 0x1ef8, { 16, 16, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_move_8_pi7_al, 0xffff, 0x1ef9, { 20, 20, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_move_8_pi7_pcdi, 0xffff, 0x1efa, { 16, 16, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_move_8_pi7_pcix, 0xffff, 0x1efb, { 18, 18, 11, 11, 11, 11, 4}}, + {m68000_base_device_ops::m68k_op_move_8_pi7_i, 0xffff, 0x1efc, { 12, 12, 6, 6, 6, 6, 4}}, + {m68000_base_device_ops::m68k_op_move_8_pd7_pi7, 0xffff, 0x1f1f, { 12, 12, 9, 9, 9, 9, 5}}, + {m68000_base_device_ops::m68k_op_move_8_pd7_pd7, 0xffff, 0x1f27, { 14, 14, 10, 10, 10, 10, 5}}, + {m68000_base_device_ops::m68k_op_move_8_pd7_aw, 0xffff, 0x1f38, { 16, 16, 9, 9, 9, 9, 5}}, + {m68000_base_device_ops::m68k_op_move_8_pd7_al, 0xffff, 0x1f39, { 20, 20, 9, 9, 9, 9, 5}}, + {m68000_base_device_ops::m68k_op_move_8_pd7_pcdi, 0xffff, 0x1f3a, { 16, 16, 10, 10, 10, 10, 5}}, + {m68000_base_device_ops::m68k_op_move_8_pd7_pcix, 0xffff, 0x1f3b, { 18, 18, 12, 12, 12, 12, 5}}, + {m68000_base_device_ops::m68k_op_move_8_pd7_i, 0xffff, 0x1f3c, { 12, 12, 7, 7, 7, 7, 5}}, + {m68000_base_device_ops::m68k_op_move_32_aw_aw, 0xffff, 0x21f8, { 28, 28, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_move_32_aw_al, 0xffff, 0x21f9, { 32, 32, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_move_32_aw_pcdi, 0xffff, 0x21fa, { 28, 28, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_move_32_aw_pcix, 0xffff, 0x21fb, { 30, 30, 11, 11, 11, 11, 4}}, + {m68000_base_device_ops::m68k_op_move_32_aw_i, 0xffff, 0x21fc, { 24, 24, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_move_32_al_aw, 0xffff, 0x23f8, { 32, 32, 10, 10, 10, 10, 6}}, + {m68000_base_device_ops::m68k_op_move_32_al_al, 0xffff, 0x23f9, { 36, 36, 10, 10, 10, 10, 6}}, + {m68000_base_device_ops::m68k_op_move_32_al_pcdi, 0xffff, 0x23fa, { 32, 32, 11, 11, 11, 11, 6}}, + {m68000_base_device_ops::m68k_op_move_32_al_pcix, 0xffff, 0x23fb, { 34, 34, 13, 13, 13, 13, 6}}, + {m68000_base_device_ops::m68k_op_move_32_al_i, 0xffff, 0x23fc, { 28, 28, 10, 10, 10, 10, 6}}, + {m68000_base_device_ops::m68k_op_move_16_aw_aw, 0xffff, 0x31f8, { 20, 20, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_move_16_aw_al, 0xffff, 0x31f9, { 24, 24, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_move_16_aw_pcdi, 0xffff, 0x31fa, { 20, 20, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_move_16_aw_pcix, 0xffff, 0x31fb, { 22, 22, 11, 11, 11, 11, 4}}, + {m68000_base_device_ops::m68k_op_move_16_aw_i, 0xffff, 0x31fc, { 16, 16, 6, 6, 6, 6, 4}}, + {m68000_base_device_ops::m68k_op_move_16_al_aw, 0xffff, 0x33f8, { 24, 24, 10, 10, 10, 10, 6}}, + {m68000_base_device_ops::m68k_op_move_16_al_al, 0xffff, 0x33f9, { 28, 28, 10, 10, 10, 10, 6}}, + {m68000_base_device_ops::m68k_op_move_16_al_pcdi, 0xffff, 0x33fa, { 24, 24, 11, 11, 11, 11, 6}}, + {m68000_base_device_ops::m68k_op_move_16_al_pcix, 0xffff, 0x33fb, { 26, 26, 13, 13, 13, 13, 6}}, + {m68000_base_device_ops::m68k_op_move_16_al_i, 0xffff, 0x33fc, { 20, 20, 8, 8, 8, 8, 6}}, + {m68000_base_device_ops::m68k_op_negx_8_pi7, 0xffff, 0x401f, { 12, 12, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_negx_8_pd7, 0xffff, 0x4027, { 14, 14, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_negx_8_aw, 0xffff, 0x4038, { 16, 16, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_negx_8_al, 0xffff, 0x4039, { 20, 20, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_negx_16_aw, 0xffff, 0x4078, { 16, 16, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_negx_16_al, 0xffff, 0x4079, { 20, 20, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_negx_32_aw, 0xffff, 0x40b8, { 24, 24, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_negx_32_al, 0xffff, 0x40b9, { 28, 28, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_move_16_frs_aw, 0xffff, 0x40f8, { 16, 16, 12, 12, 12, 12, 8}}, + {m68000_base_device_ops::m68k_op_move_16_frs_al, 0xffff, 0x40f9, { 20, 20, 12, 12, 12, 12, 8}}, + {m68000_base_device_ops::m68k_op_clr_8_pi7, 0xffff, 0x421f, { 12, 8, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_clr_8_pd7, 0xffff, 0x4227, { 14, 10, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_clr_8_aw, 0xffff, 0x4238, { 16, 12, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_clr_8_al, 0xffff, 0x4239, { 20, 14, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_clr_16_aw, 0xffff, 0x4278, { 16, 12, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_clr_16_al, 0xffff, 0x4279, { 20, 14, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_clr_32_aw, 0xffff, 0x42b8, { 24, 16, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_clr_32_al, 0xffff, 0x42b9, { 28, 20, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_move_16_frc_aw, 0xffff, 0x42f8, {255, 16, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_move_16_frc_al, 0xffff, 0x42f9, {255, 20, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_neg_8_pi7, 0xffff, 0x441f, { 12, 12, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_neg_8_pd7, 0xffff, 0x4427, { 14, 14, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_neg_8_aw, 0xffff, 0x4438, { 16, 16, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_neg_8_al, 0xffff, 0x4439, { 20, 20, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_neg_16_aw, 0xffff, 0x4478, { 16, 16, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_neg_16_al, 0xffff, 0x4479, { 20, 20, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_neg_32_aw, 0xffff, 0x44b8, { 24, 24, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_neg_32_al, 0xffff, 0x44b9, { 28, 28, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_move_16_toc_aw, 0xffff, 0x44f8, { 20, 20, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_move_16_toc_al, 0xffff, 0x44f9, { 24, 24, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_move_16_toc_pcdi, 0xffff, 0x44fa, { 20, 20, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_move_16_toc_pcix, 0xffff, 0x44fb, { 22, 22, 11, 11, 11, 11, 4}}, + {m68000_base_device_ops::m68k_op_move_16_toc_i, 0xffff, 0x44fc, { 16, 16, 6, 6, 6, 6, 4}}, + {m68000_base_device_ops::m68k_op_not_8_pi7, 0xffff, 0x461f, { 12, 12, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_not_8_pd7, 0xffff, 0x4627, { 14, 14, 9, 9, 9, 9, 4}}, + {m68000_base_device_ops::m68k_op_not_8_aw, 0xffff, 0x4638, { 16, 16, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_not_8_al, 0xffff, 0x4639, { 20, 20, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_not_16_aw, 0xffff, 0x4678, { 16, 16, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_not_16_al, 0xffff, 0x4679, { 20, 20, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_not_32_aw, 0xffff, 0x46b8, { 24, 24, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_not_32_al, 0xffff, 0x46b9, { 28, 28, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_move_16_tos_aw, 0xffff, 0x46f8, { 20, 20, 12, 12, 12, 12, 8}}, + {m68000_base_device_ops::m68k_op_move_16_tos_al, 0xffff, 0x46f9, { 24, 24, 12, 12, 12, 12, 8}}, + {m68000_base_device_ops::m68k_op_move_16_tos_pcdi, 0xffff, 0x46fa, { 20, 20, 13, 13, 13, 13, 8}}, + {m68000_base_device_ops::m68k_op_move_16_tos_pcix, 0xffff, 0x46fb, { 22, 22, 15, 15, 15, 15, 8}}, + {m68000_base_device_ops::m68k_op_move_16_tos_i, 0xffff, 0x46fc, { 16, 16, 10, 10, 10, 10, 8}}, + {m68000_base_device_ops::m68k_op_link_32_a7, 0xffff, 0x480f, {255, 255, 6, 6, 6, 6, 6}}, + {m68000_base_device_ops::m68k_op_nbcd_8_pi7, 0xffff, 0x481f, { 12, 12, 10, 10, 10, 10, 6}}, + {m68000_base_device_ops::m68k_op_nbcd_8_pd7, 0xffff, 0x4827, { 14, 14, 11, 11, 11, 11, 6}}, + {m68000_base_device_ops::m68k_op_nbcd_8_aw, 0xffff, 0x4838, { 16, 16, 10, 10, 10, 10, 6}}, + {m68000_base_device_ops::m68k_op_nbcd_8_al, 0xffff, 0x4839, { 20, 20, 10, 10, 10, 10, 6}}, + {m68000_base_device_ops::m68k_op_pea_32_aw, 0xffff, 0x4878, { 16, 16, 9, 9, 9, 9, 5}}, + {m68000_base_device_ops::m68k_op_pea_32_al, 0xffff, 0x4879, { 20, 20, 9, 9, 9, 9, 5}}, + {m68000_base_device_ops::m68k_op_pea_32_pcdi, 0xffff, 0x487a, { 16, 16, 10, 10, 10, 10, 5}}, + {m68000_base_device_ops::m68k_op_pea_32_pcix, 0xffff, 0x487b, { 20, 20, 12, 12, 12, 12, 5}}, + {m68000_base_device_ops::m68k_op_movem_16_re_aw, 0xffff, 0x48b8, { 12, 12, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_movem_16_re_al, 0xffff, 0x48b9, { 16, 16, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_movem_32_re_aw, 0xffff, 0x48f8, { 12, 12, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_movem_32_re_al, 0xffff, 0x48f9, { 16, 16, 8, 8, 8, 8, 4}}, + {m68000_base_device_ops::m68k_op_tst_8_pi7, 0xffff, 0x4a1f, { 8, 8, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_tst_8_pd7, 0xffff, 0x4a27, { 10, 10, 7, 7, 7, 7, 2}}, + {m68000_base_device_ops::m68k_op_tst_8_aw, 0xffff, 0x4a38, { 12, 12, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_tst_8_al, 0xffff, 0x4a39, { 16, 16, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_tst_8_pcdi, 0xffff, 0x4a3a, {255, 255, 7, 7, 7, 7, 7}}, + {m68000_base_device_ops::m68k_op_tst_8_pcix, 0xffff, 0x4a3b, {255, 255, 9, 9, 9, 9, 9}}, + {m68000_base_device_ops::m68k_op_tst_8_i, 0xffff, 0x4a3c, {255, 255, 6, 6, 6, 6, 6}}, + {m68000_base_device_ops::m68k_op_tst_16_aw, 0xffff, 0x4a78, { 12, 12, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_tst_16_al, 0xffff, 0x4a79, { 16, 16, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_tst_16_pcdi, 0xffff, 0x4a7a, {255, 255, 7, 7, 7, 7, 7}}, + {m68000_base_device_ops::m68k_op_tst_16_pcix, 0xffff, 0x4a7b, {255, 255, 9, 9, 9, 9, 9}}, + {m68000_base_device_ops::m68k_op_tst_16_i, 0xffff, 0x4a7c, {255, 255, 6, 6, 6, 6, 6}}, + {m68000_base_device_ops::m68k_op_tst_32_aw, 0xffff, 0x4ab8, { 16, 16, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_tst_32_al, 0xffff, 0x4ab9, { 20, 20, 6, 6, 6, 6, 2}}, + {m68000_base_device_ops::m68k_op_tst_32_pcdi, 0xffff, 0x4aba, {255, 255, 7, 7, 7, 7, 7}}, + {m68000_base_device_ops::m68k_op_tst_32_pcix, 0xffff, 0x4abb, {255, 255, 9, 9, 9, 9, 9}}, + {m68000_base_device_ops::m68k_op_tst_32_i, 0xffff, 0x4abc, {255, 255, 6, 6, 6, 6, 6}}, + {m68000_base_device_ops::m68k_op_tas_8_pi7, 0xffff, 0x4adf, { 18, 18, 16, 16, 16, 16, 12}}, + {m68000_base_device_ops::m68k_op_tas_8_pd7, 0xffff, 0x4ae7, { 20, 20, 17, 17, 17, 17, 12}}, + {m68000_base_device_ops::m68k_op_tas_8_aw, 0xffff, 0x4af8, { 22, 22, 16, 16, 16, 16, 12}}, + {m68000_base_device_ops::m68k_op_tas_8_al, 0xffff, 0x4af9, { 26, 26, 16, 16, 16, 16, 12}}, + {m68000_base_device_ops::m68k_op_illegal, 0xffff, 0x4afc, { 4, 4, 4, 4, 4, 4, 4}}, + {m68000_base_device_ops::m68k_op_mull_32_aw, 0xffff, 0x4c38, {255, 255, 47, 47, 47, 47, 43}}, + {m68000_base_device_ops::m68k_op_mull_32_al, 0xffff, 0x4c39, {255, 255, 47, 47, 47, 47, 43}}, + {m68000_base_device_ops::m68k_op_mull_32_pcdi, 0xffff, 0x4c3a, {255, 255, 48, 48, 48, 48, 43}}, + {m68000_base_device_ops::m68k_op_mull_32_pcix, 0xffff, 0x4c3b, {255, 255, 50, 50, 50, 50, 43}}, + {m68000_base_device_ops::m68k_op_mull_32_i, 0xffff, 0x4c3c, {255, 255, 47, 47, 47, 47, 43}}, + {m68000_base_device_ops::m68k_op_divl_32_aw, 0xffff, 0x4c78, {255, 255, 88, 88, 88, 88, 84}}, + {m68000_base_device_ops::m68k_op_divl_32_al, 0xffff, 0x4c79, {255, 255, 88, 88, 88, 88, 84}}, + {m68000_base_device_ops::m68k_op_divl_32_pcdi, 0xffff, 0x4c7a, {255, 255, 89, 89, 89, 89, 84}}, + {m68000_base_device_ops::m68k_op_divl_32_pcix, 0xffff, 0x4c7b, {255, 255, 91, 91, 91, 91, 84}}, + {m68000_base_device_ops::m68k_op_divl_32_i, 0xffff, 0x4c7c, {255, 255, 88, 88, 88, 88, 84}}, + {m68000_base_device_ops::m68k_op_movem_16_er_aw, 0xffff, 0x4cb8, { 16, 16, 12, 12, 12, 12, 8}}, + {m68000_base_device_ops::m68k_op_movem_16_er_al, 0xffff, 0x4cb9, { 20, 20, 12, 12, 12, 12, 8}}, + {m68000_base_device_ops::m68k_op_movem_16_er_pcdi, 0xffff, 0x4cba, { 16, 16, 9, 9, 9, 9, 9}}, + {m68000_base_device_ops::m68k_op_movem_16_er_pcix, 0xffff, 0x4cbb, { 18, 18, 11, 11, 11, 11, 11}}, + {m68000_base_device_ops::m68k_op_movem_32_er_aw, 0xffff, 0x4cf8, { 16, 16, 12, 12, 12, 12, 8}}, + {m68000_base_device_ops::m68k_op_movem_32_er_al, 0xffff, 0x4cf9, { 20, 20, 12, 12, 12, 12, 8}}, + {m68000_base_device_ops::m68k_op_movem_32_er_pcdi, 0xffff, 0x4cfa, { 16, 16, 9, 9, 9, 9, 9}}, + {m68000_base_device_ops::m68k_op_movem_32_er_pcix, 0xffff, 0x4cfb, { 18, 18, 11, 11, 11, 11, 11}}, + {m68000_base_device_ops::m68k_op_link_16_a7, 0xffff, 0x4e57, { 16, 16, 5, 5, 5, 5, 5}}, + {m68000_base_device_ops::m68k_op_unlk_32_a7, 0xffff, 0x4e5f, { 12, 12, 6, 6, 6, 6, 6}}, + {m68000_base_device_ops::m68k_op_reset, 0xffff, 0x4e70, { 0, 0, 0, 0, 0, 0, 0}}, + {m68000_base_device_ops::m68k_op_nop, 0xffff, 0x4e71, { 4, 4, 2, 2, 2, 2, 2}}, + {m68000_base_device_ops::m68k_op_stop, 0xffff, 0x4e72, { 4, 4, 8, 8, 8, 8, 8}}, + {m68000_base_device_ops::m68k_op_rte_32, 0xffff, 0x4e73, { 20, 24, 20, 20, 20, 20, 20}}, + {m68000_base_device_ops::m68k_op_rtd_32, 0xffff, 0x4e74, {255, 16, 10, 10, 10, 10, 10}}, + {m68000_base_device_ops::m68k_op_rts_32, 0xffff, 0x4e75, { 16, 16, 10, 10, 10, 10, 10}}, + {m68000_base_device_ops::m68k_op_trapv, 0xffff, 0x4e76, { 4, 4, 4, 4, 4, 4, 4}}, + {m68000_base_device_ops::m68k_op_rtr_32, 0xffff, 0x4e77, { 20, 20, 14, 14, 14, 14, 14}}, + {m68000_base_device_ops::m68k_op_movec_32_cr, 0xffff, 0x4e7a, {255, 12, 6, 6, 6, 6, 6}}, + {m68000_base_device_ops::m68k_op_movec_32_rc, 0xffff, 0x4e7b, {255, 10, 12, 12, 12, 12, 12}}, + {m68000_base_device_ops::m68k_op_jsr_32_aw, 0xffff, 0x4eb8, { 18, 18, 4, 4, 4, 4, 0}}, + {m68000_base_device_ops::m68k_op_jsr_32_al, 0xffff, 0x4eb9, { 20, 20, 4, 4, 4, 4, 0}}, + {m68000_base_device_ops::m68k_op_jsr_32_pcdi, 0xffff, 0x4eba, { 18, 18, 5, 5, 5, 5, 0}}, + {m68000_base_device_ops::m68k_op_jsr_32_pcix, 0xffff, 0x4ebb, { 22, 22, 7, 7, 7, 7, 0}}, + {m68000_base_device_ops::m68k_op_jmp_32_aw, 0xffff, 0x4ef8, { 10, 10, 4, 4, 4, 4, 0}}, + {m68000_base_device_ops::m68k_op_jmp_32_al, 0xffff, 0x4ef9, { 12, 12, 4, 4, 4, 4, 0}}, + {m68000_base_device_ops::m68k_op_jmp_32_pcdi, 0xffff, 0x4efa, { 10, 10, 5, 5, 5, 5, 0}}, + {m68000_base_device_ops::m68k_op_jmp_32_pcix, 0xffff, 0x4efb, { 14, 14, 7, 7, 7, 7, 0}}, + {m68000_base_device_ops::m68k_op_st_8_pi7, 0xffff, 0x50df, { 12, 12, 10, 10, 10, 10, 6}}, + {m68000_base_device_ops::m68k_op_st_8_pd7, 0xffff, 0x50e7, { 14, 14, 11, 11, 11, 11, 6}}, + {m68000_base_device_ops::m68k_op_st_8_aw, 0xffff, 0x50f8, { 16, 16, 10, 10, 10, 10, 6}}, + {m68000_base_device_ops::m68k_op_st_8_al, 0xffff, 0x50f9, { 20, 20, 10, 10, 10, 10, 6}}, + {m68000_base_device_ops::m68k_op_trapt_16, 0xffff, 0x50fa, {255, 255, 6, 6, 6, 6, 6}}, + {m68000_base_device_ops::m68k_op_trapt_32, 0xffff, 0x50fb, {255, 255, 8, 8, 8, 8, 8}}, + {m68000_base_device_ops::m68k_op_trapt, 0xffff, 0x50fc, {255, 255, 4, 4, 4, 4, 4}}, + {m68000_base_device_ops::m68k_op_sf_8_pi7, 0xffff, 0x51df, { 12, 12, 10, 10, 10, 10, 6}}, + {m68000_base_device_ops::m68k_op_sf_8_pd7, 0xffff, 0x51e7, { 14, 14, 11, 11, 11, 11, 6}}, + {m68000_base_device_ops::m68k_op_sf_8_aw, 0xffff, 0x51f8, { 16, 16, 10, 10, 10, 10, 6}}, + {m68000_base_device_ops::m68k_op_sf_8_al, 0xffff, 0x51f9, { 20, 20, 10, 10, 10, 10, 6}}, + {m68000_base_device_ops::m68k_op_trapf_16, 0xffff, 0x51fa, {255, 255, 6, 6, 6, 6, 6}}, + {m68000_base_device_ops::m68k_op_trapf_32, 0xffff, 0x51fb, {255, 255, 8, 8, 8, 8, 8}}, + {m68000_base_device_ops::m68k_op_trapf, 0xffff, 0x51fc, {255, 255, 4, 4, 4, 4, 4}}, + {m68000_base_device_ops::m68k_op_shi_8_pi7, 0xffff, 0x52df, { 12, 12, 10, 10, 10, 10, 6}}, + {m68000_base_device_ops::m68k_op_shi_8_pd7, 0xffff, 0x52e7, { 14, 14, 11, 11, 11, 11, 6}}, + {m68000_base_device_ops::m68k_op_shi_8_aw, 0xffff, 0x52f8, { 16, 16, 10, 10, 10, 10, 6}}, + {m68000_base_device_ops::m68k_op_shi_8_al, 0xffff, 0x52f9, { 20, 20, 10, 10, 10, 10, 6}}, + {m68000_base_device_ops::m68k_op_traphi_16, 0xffff, 0x52fa, {255, 255, 6, 6, 6, 6, 6}}, + {m68000_base_device_ops::m68k_op_traphi_32, 0xffff, 0x52fb, {255, 255, 8, 8, 8, 8, 8}}, + {m68000_base_device_ops::m68k_op_traphi, 0xffff, 0x52fc, {255, 255, 4, 4, 4, 4, 4}}, + {m68000_base_device_ops::m68k_op_sls_8_pi7, 0xffff, 0x53df, { 12, 12, 10, 10, 10, 10, 6}}, + {m68000_base_device_ops::m68k_op_sls_8_pd7, 0xffff, 0x53e7, { 14, 14, 11, 11, 11, 11, 6}}, + {m68000_base_device_ops::m68k_op_sls_8_aw, 0xffff, 0x53f8, { 16, 16, 10, 10, 10, 10, 6}}, + {m68000_base_device_ops::m68k_op_sls_8_al, 0xffff, 0x53f9, { 20, 20, 10, 10, 10, 10, 6}}, + {m68000_base_device_ops::m68k_op_trapls_16, 0xffff, 0x53fa, {255, 255, 6, 6, 6, 6, 6}}, + {m68000_base_device_ops::m68k_op_trapls_32, 0xffff, 0x53fb, {255, 255, 8, 8, 8, 8, 8}}, + {m68000_base_device_ops::m68k_op_trapls, 0xffff, 0x53fc, {255, 255, 4, 4, 4, 4, 4}}, + {m68000_base_device_ops::m68k_op_scc_8_pi7, 0xffff, 0x54df, { 12, 12, 10, 10, 10, 10, 6}}, + {m68000_base_device_ops::m68k_op_scc_8_pd7, 0xffff, 0x54e7, { 14, 14, 11, 11, 11, 11, 6}}, + {m68000_base_device_ops::m68k_op_scc_8_aw, 0xffff, 0x54f8, { 16, 16, 10, 10, 10, 10, 6}}, + {m68000_base_device_ops::m68k_op_scc_8_al, 0xffff, 0x54f9, { 20, 20, 10, 10, 10, 10, 6}}, + {m68000_base_device_ops::m68k_op_trapcc_16, 0xffff, 0x54fa, {255, 255, 6, 6, 6, 6, 6}}, + {m68000_base_device_ops::m68k_op_trapcc_32, 0xffff, 0x54fb, {255, 255, 8, 8, 8, 8, 8}}, + {m68000_base_device_ops::m68k_op_trapcc, 0xffff, 0x54fc, {255, 255, 4, 4, 4, 4, 4}}, + {m68000_base_device_ops::m68k_op_scs_8_pi7, 0xffff, 0x55df, { 12, 12, 10, 10, 10, 10, 6}}, + {m68000_base_device_ops::m68k_op_scs_8_pd7, 0xffff, 0x55e7, { 14, 14, 11, 11, 11, 11, 6}}, + {m68000_base_device_ops::m68k_op_scs_8_aw, 0xffff, 0x55f8, { 16, 16, 10, 10, 10, 10, 6}}, + {m68000_base_device_ops::m68k_op_scs_8_al, 0xffff, 0x55f9, { 20, 20, 10, 10, 10, 10, 6}}, + {m68000_base_device_ops::m68k_op_trapcs_16, 0xffff, 0x55fa, {255, 255, 6, 6, 6, 6, 6}}, + {m68000_base_device_ops::m68k_op_trapcs_32, 0xffff, 0x55fb, {255, 255, 8, 8, 8, 8, 8}}, + {m68000_base_device_ops::m68k_op_trapcs, 0xffff, 0x55fc, {255, 255, 4, 4, 4, 4, 4}}, + {m68000_base_device_ops::m68k_op_sne_8_pi7, 0xffff, 0x56df, { 12, 12, 10, 10, 10, 10, 6}}, + {m68000_base_device_ops::m68k_op_sne_8_pd7, 0xffff, 0x56e7, { 14, 14, 11, 11, 11, 11, 6}}, + {m68000_base_device_ops::m68k_op_sne_8_aw, 0xffff, 0x56f8, { 16, 16, 10, 10, 10, 10, 6}}, + {m68000_base_device_ops::m68k_op_sne_8_al, 0xffff, 0x56f9, { 20, 20, 10, 10, 10, 10, 6}}, + {m68000_base_device_ops::m68k_op_trapne_16, 0xffff, 0x56fa, {255, 255, 6, 6, 6, 6, 6}}, + {m68000_base_device_ops::m68k_op_trapne_32, 0xffff, 0x56fb, {255, 255, 8, 8, 8, 8, 8}}, + {m68000_base_device_ops::m68k_op_trapne, 0xffff, 0x56fc, {255, 255, 4, 4, 4, 4, 4}}, + {m68000_base_device_ops::m68k_op_seq_8_pi7, 0xffff, 0x57df, { 12, 12, 10, 10, 10, 10, 6}}, + {m68000_base_device_ops::m68k_op_seq_8_pd7, 0xffff, 0x57e7, { 14, 14, 11, 11, 11, 11, 6}}, + {m68000_base_device_ops::m68k_op_seq_8_aw, 0xffff, 0x57f8, { 16, 16, 10, 10, 10, 10, 6}}, + {m68000_base_device_ops::m68k_op_seq_8_al, 0xffff, 0x57f9, { 20, 20, 10, 10, 10, 10, 6}}, + {m68000_base_device_ops::m68k_op_trapeq_16, 0xffff, 0x57fa, {255, 255, 6, 6, 6, 6, 6}}, + {m68000_base_device_ops::m68k_op_trapeq_32, 0xffff, 0x57fb, {255, 255, 8, 8, 8, 8, 8}}, + {m68000_base_device_ops::m68k_op_trapeq, 0xffff, 0x57fc, {255, 255, 4, 4, 4, 4, 4}}, + {m68000_base_device_ops::m68k_op_svc_8_pi7, 0xffff, 0x58df, { 12, 12, 10, 10, 10, 10, 6}}, + {m68000_base_device_ops::m68k_op_svc_8_pd7, 0xffff, 0x58e7, { 14, 14, 11, 11, 11, 11, 6}}, + {m68000_base_device_ops::m68k_op_svc_8_aw, 0xffff, 0x58f8, { 16, 16, 10, 10, 10, 10, 6}}, + {m68000_base_device_ops::m68k_op_svc_8_al, 0xffff, 0x58f9, { 20, 20, 10, 10, 10, 10, 6}}, + {m68000_base_device_ops::m68k_op_trapvc_16, 0xffff, 0x58fa, {255, 255, 6, 6, 6, 6, 6}}, + {m68000_base_device_ops::m68k_op_trapvc_32, 0xffff, 0x58fb, {255, 255, 8, 8, 8, 8, 8}}, + {m68000_base_device_ops::m68k_op_trapvc, 0xffff, 0x58fc, {255, 255, 4, 4, 4, 4, 4}}, + {m68000_base_device_ops::m68k_op_svs_8_pi7, 0xffff, 0x59df, { 12, 12, 10, 10, 10, 10, 6}}, + {m68000_base_device_ops::m68k_op_svs_8_pd7, 0xffff, 0x59e7, { 14, 14, 11, 11, 11, 11, 6}}, + {m68000_base_device_ops::m68k_op_svs_8_aw, 0xffff, 0x59f8, { 16, 16, 10, 10, 10, 10, 6}}, + {m68000_base_device_ops::m68k_op_svs_8_al, 0xffff, 0x59f9, { 20, 20, 10, 10, 10, 10, 6}}, + {m68000_base_device_ops::m68k_op_trapvs_16, 0xffff, 0x59fa, {255, 255, 6, 6, 6, 6, 6}}, + {m68000_base_device_ops::m68k_op_trapvs_32, 0xffff, 0x59fb, {255, 255, 8, 8, 8, 8, 8}}, + {m68000_base_device_ops::m68k_op_trapvs, 0xffff, 0x59fc, {255, 255, 4, 4, 4, 4, 4}}, + {m68000_base_device_ops::m68k_op_spl_8_pi7, 0xffff, 0x5adf, { 12, 12, 10, 10, 10, 10, 6}}, + {m68000_base_device_ops::m68k_op_spl_8_pd7, 0xffff, 0x5ae7, { 14, 14, 11, 11, 11, 11, 6}}, + {m68000_base_device_ops::m68k_op_spl_8_aw, 0xffff, 0x5af8, { 16, 16, 10, 10, 10, 10, 6}}, + {m68000_base_device_ops::m68k_op_spl_8_al, 0xffff, 0x5af9, { 20, 20, 10, 10, 10, 10, 6}}, + {m68000_base_device_ops::m68k_op_trappl_16, 0xffff, 0x5afa, {255, 255, 6, 6, 6, 6, 6}}, + {m68000_base_device_ops::m68k_op_trappl_32, 0xffff, 0x5afb, {255, 255, 8, 8, 8, 8, 8}}, + {m68000_base_device_ops::m68k_op_trappl, 0xffff, 0x5afc, {255, 255, 4, 4, 4, 4, 4}}, + {m68000_base_device_ops::m68k_op_smi_8_pi7, 0xffff, 0x5bdf, { 12, 12, 10, 10, 10, 10, 6}}, + {m68000_base_device_ops::m68k_op_smi_8_pd7, 0xffff, 0x5be7, { 14, 14, 11, 11, 11, 11, 6}}, + {m68000_base_device_ops::m68k_op_smi_8_aw, 0xffff, 0x5bf8, { 16, 16, 10, 10, 10, 10, 6}}, + {m68000_base_device_ops::m68k_op_smi_8_al, 0xffff, 0x5bf9, { 20, 20, 10, 10, 10, 10, 6}}, + {m68000_base_device_ops::m68k_op_trapmi_16, 0xffff, 0x5bfa, {255, 255, 6, 6, 6, 6, 6}}, + {m68000_base_device_ops::m68k_op_trapmi_32, 0xffff, 0x5bfb, {255, 255, 8, 8, 8, 8, 8}}, + {m68000_base_device_ops::m68k_op_trapmi, 0xffff, 0x5bfc, {255, 255, 4, 4, 4, 4, 4}}, + {m68000_base_device_ops::m68k_op_sge_8_pi7, 0xffff, 0x5cdf, { 12, 12, 10, 10, 10, 10, 6}}, + {m68000_base_device_ops::m68k_op_sge_8_pd7, 0xffff, 0x5ce7, { 14, 14, 11, 11, 11, 11, 6}}, + {m68000_base_device_ops::m68k_op_sge_8_aw, 0xffff, 0x5cf8, { 16, 16, 10, 10, 10, 10, 6}}, + {m68000_base_device_ops::m68k_op_sge_8_al, 0xffff, 0x5cf9, { 20, 20, 10, 10, 10, 10, 6}}, + {m68000_base_device_ops::m68k_op_trapge_16, 0xffff, 0x5cfa, {255, 255, 6, 6, 6, 6, 6}}, + {m68000_base_device_ops::m68k_op_trapge_32, 0xffff, 0x5cfb, {255, 255, 8, 8, 8, 8, 8}}, + {m68000_base_device_ops::m68k_op_trapge, 0xffff, 0x5cfc, {255, 255, 4, 4, 4, 4, 4}}, + {m68000_base_device_ops::m68k_op_slt_8_pi7, 0xffff, 0x5ddf, { 12, 12, 10, 10, 10, 10, 6}}, + {m68000_base_device_ops::m68k_op_slt_8_pd7, 0xffff, 0x5de7, { 14, 14, 11, 11, 11, 11, 6}}, + {m68000_base_device_ops::m68k_op_slt_8_aw, 0xffff, 0x5df8, { 16, 16, 10, 10, 10, 10, 6}}, + {m68000_base_device_ops::m68k_op_slt_8_al, 0xffff, 0x5df9, { 20, 20, 10, 10, 10, 10, 6}}, + {m68000_base_device_ops::m68k_op_traplt_16, 0xffff, 0x5dfa, {255, 255, 6, 6, 6, 6, 6}}, + {m68000_base_device_ops::m68k_op_traplt_32, 0xffff, 0x5dfb, {255, 255, 8, 8, 8, 8, 8}}, + {m68000_base_device_ops::m68k_op_traplt, 0xffff, 0x5dfc, {255, 255, 4, 4, 4, 4, 4}}, + {m68000_base_device_ops::m68k_op_sgt_8_pi7, 0xffff, 0x5edf, { 12, 12, 10, 10, 10, 10, 6}}, + {m68000_base_device_ops::m68k_op_sgt_8_pd7, 0xffff, 0x5ee7, { 14, 14, 11, 11, 11, 11, 6}}, + {m68000_base_device_ops::m68k_op_sgt_8_aw, 0xffff, 0x5ef8, { 16, 16, 10, 10, 10, 10, 6}}, + {m68000_base_device_ops::m68k_op_sgt_8_al, 0xffff, 0x5ef9, { 20, 20, 10, 10, 10, 10, 6}}, + {m68000_base_device_ops::m68k_op_trapgt_16, 0xffff, 0x5efa, {255, 255, 6, 6, 6, 6, 6}}, + {m68000_base_device_ops::m68k_op_trapgt_32, 0xffff, 0x5efb, {255, 255, 8, 8, 8, 8, 8}}, + {m68000_base_device_ops::m68k_op_trapgt, 0xffff, 0x5efc, {255, 255, 4, 4, 4, 4, 4}}, + {m68000_base_device_ops::m68k_op_sle_8_pi7, 0xffff, 0x5fdf, { 12, 12, 10, 10, 10, 10, 6}}, + {m68000_base_device_ops::m68k_op_sle_8_pd7, 0xffff, 0x5fe7, { 14, 14, 11, 11, 11, 11, 6}}, + {m68000_base_device_ops::m68k_op_sle_8_aw, 0xffff, 0x5ff8, { 16, 16, 10, 10, 10, 10, 6}}, + {m68000_base_device_ops::m68k_op_sle_8_al, 0xffff, 0x5ff9, { 20, 20, 10, 10, 10, 10, 6}}, + {m68000_base_device_ops::m68k_op_traple_16, 0xffff, 0x5ffa, {255, 255, 6, 6, 6, 6, 6}}, + {m68000_base_device_ops::m68k_op_traple_32, 0xffff, 0x5ffb, {255, 255, 8, 8, 8, 8, 8}}, + {m68000_base_device_ops::m68k_op_traple, 0xffff, 0x5ffc, {255, 255, 4, 4, 4, 4, 4}}, + {m68000_base_device_ops::m68k_op_bra_16, 0xffff, 0x6000, { 10, 10, 10, 10, 10, 10, 10}}, + {m68000_base_device_ops::m68k_op_bra_32, 0xffff, 0x60ff, { 10, 10, 10, 10, 10, 10, 10}}, + {m68000_base_device_ops::m68k_op_bsr_16, 0xffff, 0x6100, { 18, 18, 7, 7, 7, 7, 7}}, + {m68000_base_device_ops::m68k_op_bsr_32, 0xffff, 0x61ff, { 18, 18, 7, 7, 7, 7, 7}}, + {m68000_base_device_ops::m68k_op_bhi_16, 0xffff, 0x6200, { 10, 10, 6, 6, 6, 6, 6}}, + {m68000_base_device_ops::m68k_op_bhi_32, 0xffff, 0x62ff, { 10, 10, 6, 6, 6, 6, 6}}, + {m68000_base_device_ops::m68k_op_bls_16, 0xffff, 0x6300, { 10, 10, 6, 6, 6, 6, 6}}, + {m68000_base_device_ops::m68k_op_bls_32, 0xffff, 0x63ff, { 10, 10, 6, 6, 6, 6, 6}}, + {m68000_base_device_ops::m68k_op_bcc_16, 0xffff, 0x6400, { 10, 10, 6, 6, 6, 6, 6}}, + {m68000_base_device_ops::m68k_op_bcc_32, 0xffff, 0x64ff, { 10, 10, 6, 6, 6, 6, 6}}, + {m68000_base_device_ops::m68k_op_bcs_16, 0xffff, 0x6500, { 10, 10, 6, 6, 6, 6, 6}}, + {m68000_base_device_ops::m68k_op_bcs_32, 0xffff, 0x65ff, { 10, 10, 6, 6, 6, 6, 6}}, + {m68000_base_device_ops::m68k_op_bne_16, 0xffff, 0x6600, { 10, 10, 6, 6, 6, 6, 6}}, + {m68000_base_device_ops::m68k_op_bne_32, 0xffff, 0x66ff, { 10, 10, 6, 6, 6, 6, 6}}, + {m68000_base_device_ops::m68k_op_beq_16, 0xffff, 0x6700, { 10, 10, 6, 6, 6, 6, 6}}, + {m68000_base_device_ops::m68k_op_beq_32, 0xffff, 0x67ff, { 10, 10, 6, 6, 6, 6, 6}}, + {m68000_base_device_ops::m68k_op_bvc_16, 0xffff, 0x6800, { 10, 10, 6, 6, 6, 6, 6}}, + {m68000_base_device_ops::m68k_op_bvc_32, 0xffff, 0x68ff, { 10, 10, 6, 6, 6, 6, 6}}, + {m68000_base_device_ops::m68k_op_bvs_16, 0xffff, 0x6900, { 10, 10, 6, 6, 6, 6, 6}}, + {m68000_base_device_ops::m68k_op_bvs_32, 0xffff, 0x69ff, { 10, 10, 6, 6, 6, 6, 6}}, + {m68000_base_device_ops::m68k_op_bpl_16, 0xffff, 0x6a00, { 10, 10, 6, 6, 6, 6, 6}}, + {m68000_base_device_ops::m68k_op_bpl_32, 0xffff, 0x6aff, { 10, 10, 6, 6, 6, 6, 6}}, + {m68000_base_device_ops::m68k_op_bmi_16, 0xffff, 0x6b00, { 10, 10, 6, 6, 6, 6, 6}}, + {m68000_base_device_ops::m68k_op_bmi_32, 0xffff, 0x6bff, { 10, 10, 6, 6, 6, 6, 6}}, + {m68000_base_device_ops::m68k_op_bge_16, 0xffff, 0x6c00, { 10, 10, 6, 6, 6, 6, 6}}, + {m68000_base_device_ops::m68k_op_bge_32, 0xffff, 0x6cff, { 10, 10, 6, 6, 6, 6, 6}}, + {m68000_base_device_ops::m68k_op_blt_16, 0xffff, 0x6d00, { 10, 10, 6, 6, 6, 6, 6}}, + {m68000_base_device_ops::m68k_op_blt_32, 0xffff, 0x6dff, { 10, 10, 6, 6, 6, 6, 6}}, + {m68000_base_device_ops::m68k_op_bgt_16, 0xffff, 0x6e00, { 10, 10, 6, 6, 6, 6, 6}}, + {m68000_base_device_ops::m68k_op_bgt_32, 0xffff, 0x6eff, { 10, 10, 6, 6, 6, 6, 6}}, + {m68000_base_device_ops::m68k_op_ble_16, 0xffff, 0x6f00, { 10, 10, 6, 6, 6, 6, 6}}, + {m68000_base_device_ops::m68k_op_ble_32, 0xffff, 0x6fff, { 10, 10, 6, 6, 6, 6, 6}}, + {m68000_base_device_ops::m68k_op_sbcd_8_mm_axy7, 0xffff, 0x8f0f, { 18, 18, 16, 16, 16, 16, 16}}, + {m68000_base_device_ops::m68k_op_pack_16_mm_axy7, 0xffff, 0x8f4f, {255, 255, 13, 13, 13, 13, 13}}, + {m68000_base_device_ops::m68k_op_unpk_16_mm_axy7, 0xffff, 0x8f8f, {255, 255, 13, 13, 13, 13, 13}}, + {m68000_base_device_ops::m68k_op_subx_8_mm_axy7, 0xffff, 0x9f0f, { 18, 18, 12, 12, 12, 12, 12}}, + {m68000_base_device_ops::m68k_op_cmpm_8_axy7, 0xffff, 0xbf0f, { 12, 12, 9, 9, 9, 9, 9}}, + {m68000_base_device_ops::m68k_op_abcd_8_mm_axy7, 0xffff, 0xcf0f, { 18, 18, 16, 16, 16, 16, 16}}, + {m68000_base_device_ops::m68k_op_addx_8_mm_axy7, 0xffff, 0xdf0f, { 18, 18, 12, 12, 12, 12, 12}}, + {m68000_base_device_ops::m68k_op_asr_16_aw, 0xffff, 0xe0f8, { 16, 16, 9, 9, 9, 9, 5}}, + {m68000_base_device_ops::m68k_op_asr_16_al, 0xffff, 0xe0f9, { 20, 20, 9, 9, 9, 9, 5}}, + {m68000_base_device_ops::m68k_op_asl_16_aw, 0xffff, 0xe1f8, { 16, 16, 10, 10, 10, 10, 6}}, + {m68000_base_device_ops::m68k_op_asl_16_al, 0xffff, 0xe1f9, { 20, 20, 10, 10, 10, 10, 6}}, + {m68000_base_device_ops::m68k_op_lsr_16_aw, 0xffff, 0xe2f8, { 16, 16, 9, 9, 9, 9, 5}}, + {m68000_base_device_ops::m68k_op_lsr_16_al, 0xffff, 0xe2f9, { 20, 20, 9, 9, 9, 9, 5}}, + {m68000_base_device_ops::m68k_op_lsl_16_aw, 0xffff, 0xe3f8, { 16, 16, 9, 9, 9, 9, 5}}, + {m68000_base_device_ops::m68k_op_lsl_16_al, 0xffff, 0xe3f9, { 20, 20, 9, 9, 9, 9, 5}}, + {m68000_base_device_ops::m68k_op_roxr_16_aw, 0xffff, 0xe4f8, { 16, 16, 9, 9, 9, 9, 5}}, + {m68000_base_device_ops::m68k_op_roxr_16_al, 0xffff, 0xe4f9, { 20, 20, 9, 9, 9, 9, 5}}, + {m68000_base_device_ops::m68k_op_roxl_16_aw, 0xffff, 0xe5f8, { 16, 16, 9, 9, 9, 9, 5}}, + {m68000_base_device_ops::m68k_op_roxl_16_al, 0xffff, 0xe5f9, { 20, 20, 9, 9, 9, 9, 5}}, + {m68000_base_device_ops::m68k_op_ror_16_aw, 0xffff, 0xe6f8, { 16, 16, 11, 11, 11, 11, 7}}, + {m68000_base_device_ops::m68k_op_ror_16_al, 0xffff, 0xe6f9, { 20, 20, 11, 11, 11, 11, 7}}, + {m68000_base_device_ops::m68k_op_rol_16_aw, 0xffff, 0xe7f8, { 16, 16, 11, 11, 11, 11, 7}}, + {m68000_base_device_ops::m68k_op_rol_16_al, 0xffff, 0xe7f9, { 20, 20, 11, 11, 11, 11, 7}}, + {m68000_base_device_ops::m68k_op_bftst_32_aw, 0xffff, 0xe8f8, {255, 255, 17, 17, 17, 17, 13}}, + {m68000_base_device_ops::m68k_op_bftst_32_al, 0xffff, 0xe8f9, {255, 255, 17, 17, 17, 17, 13}}, + {m68000_base_device_ops::m68k_op_bftst_32_pcdi, 0xffff, 0xe8fa, {255, 255, 18, 18, 18, 18, 13}}, + {m68000_base_device_ops::m68k_op_bftst_32_pcix, 0xffff, 0xe8fb, {255, 255, 20, 20, 20, 20, 13}}, + {m68000_base_device_ops::m68k_op_bfextu_32_aw, 0xffff, 0xe9f8, {255, 255, 19, 19, 19, 19, 15}}, + {m68000_base_device_ops::m68k_op_bfextu_32_al, 0xffff, 0xe9f9, {255, 255, 19, 19, 19, 19, 15}}, + {m68000_base_device_ops::m68k_op_bfextu_32_pcdi, 0xffff, 0xe9fa, {255, 255, 20, 20, 20, 20, 15}}, + {m68000_base_device_ops::m68k_op_bfextu_32_pcix, 0xffff, 0xe9fb, {255, 255, 22, 22, 22, 22, 15}}, + {m68000_base_device_ops::m68k_op_bfchg_32_aw, 0xffff, 0xeaf8, {255, 255, 24, 24, 24, 24, 20}}, + {m68000_base_device_ops::m68k_op_bfchg_32_al, 0xffff, 0xeaf9, {255, 255, 24, 24, 24, 24, 20}}, + {m68000_base_device_ops::m68k_op_bfexts_32_aw, 0xffff, 0xebf8, {255, 255, 19, 19, 19, 19, 15}}, + {m68000_base_device_ops::m68k_op_bfexts_32_al, 0xffff, 0xebf9, {255, 255, 19, 19, 19, 19, 15}}, + {m68000_base_device_ops::m68k_op_bfexts_32_pcdi, 0xffff, 0xebfa, {255, 255, 20, 20, 20, 20, 15}}, + {m68000_base_device_ops::m68k_op_bfexts_32_pcix, 0xffff, 0xebfb, {255, 255, 22, 22, 22, 22, 15}}, + {m68000_base_device_ops::m68k_op_bfclr_32_aw, 0xffff, 0xecf8, {255, 255, 24, 24, 24, 24, 20}}, + {m68000_base_device_ops::m68k_op_bfclr_32_al, 0xffff, 0xecf9, {255, 255, 24, 24, 24, 24, 20}}, + {m68000_base_device_ops::m68k_op_bfffo_32_aw, 0xffff, 0xedf8, {255, 255, 32, 32, 32, 32, 28}}, + {m68000_base_device_ops::m68k_op_bfffo_32_al, 0xffff, 0xedf9, {255, 255, 32, 32, 32, 32, 28}}, + {m68000_base_device_ops::m68k_op_bfffo_32_pcdi, 0xffff, 0xedfa, {255, 255, 33, 33, 33, 33, 28}}, + {m68000_base_device_ops::m68k_op_bfffo_32_pcix, 0xffff, 0xedfb, {255, 255, 35, 35, 35, 35, 28}}, + {m68000_base_device_ops::m68k_op_bfset_32_aw, 0xffff, 0xeef8, {255, 255, 24, 24, 24, 24, 20}}, + {m68000_base_device_ops::m68k_op_bfset_32_al, 0xffff, 0xeef9, {255, 255, 24, 24, 24, 24, 20}}, + {m68000_base_device_ops::m68k_op_bfins_32_aw, 0xffff, 0xeff8, {255, 255, 21, 21, 21, 21, 17}}, + {m68000_base_device_ops::m68k_op_bfins_32_al, 0xffff, 0xeff9, {255, 255, 21, 21, 21, 21, 17}}, + {0, 0, 0, {0, 0, 0, 0, 0}} +}; + + +/* Build the opcode handler jump table */ + +static void m68ki_set_one(unsigned short opcode, const opcode_handler_struct *s) +{ + for(int i=0; icycles[i] != 0xff) { + m68ki_cycles[i][opcode] = s->cycles[i]; + m68ki_instruction_jump_table[i][opcode] = s->opcode_handler; + } +} + +void m68ki_build_opcode_table(void) +{ + const opcode_handler_struct *ostruct; + int i; + int j; + int k; + + for(i = 0; i < 0x10000; i++) + { + /* default to illegal */ + for(k=0;kmask != 0xff00) + { + for(i = 0;i < 0x10000;i++) + { + if((i & ostruct->mask) == ostruct->match) + m68ki_set_one(i, ostruct); + } + ostruct++; + } + while(ostruct->mask == 0xff00) + { + for(i = 0;i <= 0xff;i++) + m68ki_set_one(ostruct->match | i, ostruct); + ostruct++; + } + while(ostruct->mask == 0xff20) + { + for(i = 0;i < 4;i++) + { + for(j = 0;j < 32;j++) + { + m68ki_set_one(ostruct->match | (i << 6) | j, ostruct); + } + } + ostruct++; + } + while(ostruct->mask == 0xf1f8) + { + for(i = 0;i < 8;i++) + { + for(j = 0;j < 8;j++) + m68ki_set_one(ostruct->match | (i << 9) | j, ostruct); + } + ostruct++; + } + while(ostruct->mask == 0xffd8) + { + for(i = 0;i < 2;i++) + { + for(j = 0;j < 8;j++) + { + m68ki_set_one(ostruct->match | (i << 5) | j, ostruct); + } + } + ostruct++; + } + while(ostruct->mask == 0xfff0) + { + for(i = 0;i <= 0x0f;i++) + m68ki_set_one(ostruct->match | i, ostruct); + ostruct++; + } + while(ostruct->mask == 0xf1ff) + { + for(i = 0;i <= 0x07;i++) + m68ki_set_one(ostruct->match | (i << 9), ostruct); + ostruct++; + } + while(ostruct->mask == 0xfff8) + { + for(i = 0;i <= 0x07;i++) + m68ki_set_one(ostruct->match | i, ostruct); + ostruct++; + } + while(ostruct->mask == 0xffff) + { + m68ki_set_one(ostruct->match, ostruct); + ostruct++; + } + + // if we fell all the way through with a non-zero mask, the opcode table wasn't built properly + if (ostruct->mask != 0) + { + fatalerror("m68ki_build_opcode_table: unhandled opcode mask %x (match %x), m68k core will not function!\n", ostruct->mask, ostruct->match); + } +} + + +/* ======================================================================== */ +/* ============================== END OF FILE ============================= */ +/* ======================================================================== */ diff --git a/src/devices/cpu/m68000/m68kops.h b/src/devices/cpu/m68000/m68kops.h new file mode 100644 index 00000000000..3f936f646f2 --- /dev/null +++ b/src/devices/cpu/m68000/m68kops.h @@ -0,0 +1,1995 @@ +// license:BSD-3-Clause +// copyright-holders:Karl Stenerud +/* ======================================================================== */ +/* ============================ OPCODE HANDLERS =========================== */ +/* ======================================================================== */ + + +#ifdef OPCODE_PROTOTYPES + +static void m68k_op_1010(m68000_base_device* mc68kcpu); +static void m68k_op_1111(m68000_base_device* mc68kcpu); +static void m68k_op_040fpu0_32(m68000_base_device* mc68kcpu); +static void m68k_op_040fpu1_32(m68000_base_device* mc68kcpu); +static void m68k_op_abcd_8_rr(m68000_base_device* mc68kcpu); +static void m68k_op_abcd_8_mm_ax7(m68000_base_device* mc68kcpu); +static void m68k_op_abcd_8_mm_ay7(m68000_base_device* mc68kcpu); +static void m68k_op_abcd_8_mm_axy7(m68000_base_device* mc68kcpu); +static void m68k_op_abcd_8_mm(m68000_base_device* mc68kcpu); +static void m68k_op_add_8_er_d(m68000_base_device* mc68kcpu); +static void m68k_op_add_8_er_ai(m68000_base_device* mc68kcpu); +static void m68k_op_add_8_er_pi(m68000_base_device* mc68kcpu); +static void m68k_op_add_8_er_pi7(m68000_base_device* mc68kcpu); +static void m68k_op_add_8_er_pd(m68000_base_device* mc68kcpu); +static void m68k_op_add_8_er_pd7(m68000_base_device* mc68kcpu); +static void m68k_op_add_8_er_di(m68000_base_device* mc68kcpu); +static void m68k_op_add_8_er_ix(m68000_base_device* mc68kcpu); +static void m68k_op_add_8_er_aw(m68000_base_device* mc68kcpu); +static void m68k_op_add_8_er_al(m68000_base_device* mc68kcpu); +static void m68k_op_add_8_er_pcdi(m68000_base_device* mc68kcpu); +static void m68k_op_add_8_er_pcix(m68000_base_device* mc68kcpu); +static void m68k_op_add_8_er_i(m68000_base_device* mc68kcpu); +static void m68k_op_add_16_er_d(m68000_base_device* mc68kcpu); +static void m68k_op_add_16_er_a(m68000_base_device* mc68kcpu); +static void m68k_op_add_16_er_ai(m68000_base_device* mc68kcpu); +static void m68k_op_add_16_er_pi(m68000_base_device* mc68kcpu); +static void m68k_op_add_16_er_pd(m68000_base_device* mc68kcpu); +static void m68k_op_add_16_er_di(m68000_base_device* mc68kcpu); +static void m68k_op_add_16_er_ix(m68000_base_device* mc68kcpu); +static void m68k_op_add_16_er_aw(m68000_base_device* mc68kcpu); +static void m68k_op_add_16_er_al(m68000_base_device* mc68kcpu); +static void m68k_op_add_16_er_pcdi(m68000_base_device* mc68kcpu); +static void m68k_op_add_16_er_pcix(m68000_base_device* mc68kcpu); +static void m68k_op_add_16_er_i(m68000_base_device* mc68kcpu); +static void m68k_op_add_32_er_d(m68000_base_device* mc68kcpu); +static void m68k_op_add_32_er_a(m68000_base_device* mc68kcpu); +static void m68k_op_add_32_er_ai(m68000_base_device* mc68kcpu); +static void m68k_op_add_32_er_pi(m68000_base_device* mc68kcpu); +static void m68k_op_add_32_er_pd(m68000_base_device* mc68kcpu); +static void m68k_op_add_32_er_di(m68000_base_device* mc68kcpu); +static void m68k_op_add_32_er_ix(m68000_base_device* mc68kcpu); +static void m68k_op_add_32_er_aw(m68000_base_device* mc68kcpu); +static void m68k_op_add_32_er_al(m68000_base_device* mc68kcpu); +static void m68k_op_add_32_er_pcdi(m68000_base_device* mc68kcpu); +static void m68k_op_add_32_er_pcix(m68000_base_device* mc68kcpu); +static void m68k_op_add_32_er_i(m68000_base_device* mc68kcpu); +static void m68k_op_add_8_re_ai(m68000_base_device* mc68kcpu); +static void m68k_op_add_8_re_pi(m68000_base_device* mc68kcpu); +static void m68k_op_add_8_re_pi7(m68000_base_device* mc68kcpu); +static void m68k_op_add_8_re_pd(m68000_base_device* mc68kcpu); +static void m68k_op_add_8_re_pd7(m68000_base_device* mc68kcpu); +static void m68k_op_add_8_re_di(m68000_base_device* mc68kcpu); +static void m68k_op_add_8_re_ix(m68000_base_device* mc68kcpu); +static void m68k_op_add_8_re_aw(m68000_base_device* mc68kcpu); +static void m68k_op_add_8_re_al(m68000_base_device* mc68kcpu); +static void m68k_op_add_16_re_ai(m68000_base_device* mc68kcpu); +static void m68k_op_add_16_re_pi(m68000_base_device* mc68kcpu); +static void m68k_op_add_16_re_pd(m68000_base_device* mc68kcpu); +static void m68k_op_add_16_re_di(m68000_base_device* mc68kcpu); +static void m68k_op_add_16_re_ix(m68000_base_device* mc68kcpu); +static void m68k_op_add_16_re_aw(m68000_base_device* mc68kcpu); +static void m68k_op_add_16_re_al(m68000_base_device* mc68kcpu); +static void m68k_op_add_32_re_ai(m68000_base_device* mc68kcpu); +static void m68k_op_add_32_re_pi(m68000_base_device* mc68kcpu); +static void m68k_op_add_32_re_pd(m68000_base_device* mc68kcpu); +static void m68k_op_add_32_re_di(m68000_base_device* mc68kcpu); +static void m68k_op_add_32_re_ix(m68000_base_device* mc68kcpu); +static void m68k_op_add_32_re_aw(m68000_base_device* mc68kcpu); +static void m68k_op_add_32_re_al(m68000_base_device* mc68kcpu); +static void m68k_op_adda_16_d(m68000_base_device* mc68kcpu); +static void m68k_op_adda_16_a(m68000_base_device* mc68kcpu); +static void m68k_op_adda_16_ai(m68000_base_device* mc68kcpu); +static void m68k_op_adda_16_pi(m68000_base_device* mc68kcpu); +static void m68k_op_adda_16_pd(m68000_base_device* mc68kcpu); +static void m68k_op_adda_16_di(m68000_base_device* mc68kcpu); +static void m68k_op_adda_16_ix(m68000_base_device* mc68kcpu); +static void m68k_op_adda_16_aw(m68000_base_device* mc68kcpu); +static void m68k_op_adda_16_al(m68000_base_device* mc68kcpu); +static void m68k_op_adda_16_pcdi(m68000_base_device* mc68kcpu); +static void m68k_op_adda_16_pcix(m68000_base_device* mc68kcpu); +static void m68k_op_adda_16_i(m68000_base_device* mc68kcpu); +static void m68k_op_adda_32_d(m68000_base_device* mc68kcpu); +static void m68k_op_adda_32_a(m68000_base_device* mc68kcpu); +static void m68k_op_adda_32_ai(m68000_base_device* mc68kcpu); +static void m68k_op_adda_32_pi(m68000_base_device* mc68kcpu); +static void m68k_op_adda_32_pd(m68000_base_device* mc68kcpu); +static void m68k_op_adda_32_di(m68000_base_device* mc68kcpu); +static void m68k_op_adda_32_ix(m68000_base_device* mc68kcpu); +static void m68k_op_adda_32_aw(m68000_base_device* mc68kcpu); +static void m68k_op_adda_32_al(m68000_base_device* mc68kcpu); +static void m68k_op_adda_32_pcdi(m68000_base_device* mc68kcpu); +static void m68k_op_adda_32_pcix(m68000_base_device* mc68kcpu); +static void m68k_op_adda_32_i(m68000_base_device* mc68kcpu); +static void m68k_op_addi_8_d(m68000_base_device* mc68kcpu); +static void m68k_op_addi_8_ai(m68000_base_device* mc68kcpu); +static void m68k_op_addi_8_pi(m68000_base_device* mc68kcpu); +static void m68k_op_addi_8_pi7(m68000_base_device* mc68kcpu); +static void m68k_op_addi_8_pd(m68000_base_device* mc68kcpu); +static void m68k_op_addi_8_pd7(m68000_base_device* mc68kcpu); +static void m68k_op_addi_8_di(m68000_base_device* mc68kcpu); +static void m68k_op_addi_8_ix(m68000_base_device* mc68kcpu); +static void m68k_op_addi_8_aw(m68000_base_device* mc68kcpu); +static void m68k_op_addi_8_al(m68000_base_device* mc68kcpu); +static void m68k_op_addi_16_d(m68000_base_device* mc68kcpu); +static void m68k_op_addi_16_ai(m68000_base_device* mc68kcpu); +static void m68k_op_addi_16_pi(m68000_base_device* mc68kcpu); +static void m68k_op_addi_16_pd(m68000_base_device* mc68kcpu); +static void m68k_op_addi_16_di(m68000_base_device* mc68kcpu); +static void m68k_op_addi_16_ix(m68000_base_device* mc68kcpu); +static void m68k_op_addi_16_aw(m68000_base_device* mc68kcpu); +static void m68k_op_addi_16_al(m68000_base_device* mc68kcpu); +static void m68k_op_addi_32_d(m68000_base_device* mc68kcpu); +static void m68k_op_addi_32_ai(m68000_base_device* mc68kcpu); +static void m68k_op_addi_32_pi(m68000_base_device* mc68kcpu); +static void m68k_op_addi_32_pd(m68000_base_device* mc68kcpu); +static void m68k_op_addi_32_di(m68000_base_device* mc68kcpu); +static void m68k_op_addi_32_ix(m68000_base_device* mc68kcpu); +static void m68k_op_addi_32_aw(m68000_base_device* mc68kcpu); +static void m68k_op_addi_32_al(m68000_base_device* mc68kcpu); +static void m68k_op_addq_8_d(m68000_base_device* mc68kcpu); +static void m68k_op_addq_8_ai(m68000_base_device* mc68kcpu); +static void m68k_op_addq_8_pi(m68000_base_device* mc68kcpu); +static void m68k_op_addq_8_pi7(m68000_base_device* mc68kcpu); +static void m68k_op_addq_8_pd(m68000_base_device* mc68kcpu); +static void m68k_op_addq_8_pd7(m68000_base_device* mc68kcpu); +static void m68k_op_addq_8_di(m68000_base_device* mc68kcpu); +static void m68k_op_addq_8_ix(m68000_base_device* mc68kcpu); +static void m68k_op_addq_8_aw(m68000_base_device* mc68kcpu); +static void m68k_op_addq_8_al(m68000_base_device* mc68kcpu); +static void m68k_op_addq_16_d(m68000_base_device* mc68kcpu); +static void m68k_op_addq_16_a(m68000_base_device* mc68kcpu); +static void m68k_op_addq_16_ai(m68000_base_device* mc68kcpu); +static void m68k_op_addq_16_pi(m68000_base_device* mc68kcpu); +static void m68k_op_addq_16_pd(m68000_base_device* mc68kcpu); +static void m68k_op_addq_16_di(m68000_base_device* mc68kcpu); +static void m68k_op_addq_16_ix(m68000_base_device* mc68kcpu); +static void m68k_op_addq_16_aw(m68000_base_device* mc68kcpu); +static void m68k_op_addq_16_al(m68000_base_device* mc68kcpu); +static void m68k_op_addq_32_d(m68000_base_device* mc68kcpu); +static void m68k_op_addq_32_a(m68000_base_device* mc68kcpu); +static void m68k_op_addq_32_ai(m68000_base_device* mc68kcpu); +static void m68k_op_addq_32_pi(m68000_base_device* mc68kcpu); +static void m68k_op_addq_32_pd(m68000_base_device* mc68kcpu); +static void m68k_op_addq_32_di(m68000_base_device* mc68kcpu); +static void m68k_op_addq_32_ix(m68000_base_device* mc68kcpu); +static void m68k_op_addq_32_aw(m68000_base_device* mc68kcpu); +static void m68k_op_addq_32_al(m68000_base_device* mc68kcpu); +static void m68k_op_addx_8_rr(m68000_base_device* mc68kcpu); +static void m68k_op_addx_16_rr(m68000_base_device* mc68kcpu); +static void m68k_op_addx_32_rr(m68000_base_device* mc68kcpu); +static void m68k_op_addx_8_mm_ax7(m68000_base_device* mc68kcpu); +static void m68k_op_addx_8_mm_ay7(m68000_base_device* mc68kcpu); +static void m68k_op_addx_8_mm_axy7(m68000_base_device* mc68kcpu); +static void m68k_op_addx_8_mm(m68000_base_device* mc68kcpu); +static void m68k_op_addx_16_mm(m68000_base_device* mc68kcpu); +static void m68k_op_addx_32_mm(m68000_base_device* mc68kcpu); +static void m68k_op_and_8_er_d(m68000_base_device* mc68kcpu); +static void m68k_op_and_8_er_ai(m68000_base_device* mc68kcpu); +static void m68k_op_and_8_er_pi(m68000_base_device* mc68kcpu); +static void m68k_op_and_8_er_pi7(m68000_base_device* mc68kcpu); +static void m68k_op_and_8_er_pd(m68000_base_device* mc68kcpu); +static void m68k_op_and_8_er_pd7(m68000_base_device* mc68kcpu); +static void m68k_op_and_8_er_di(m68000_base_device* mc68kcpu); +static void m68k_op_and_8_er_ix(m68000_base_device* mc68kcpu); +static void m68k_op_and_8_er_aw(m68000_base_device* mc68kcpu); +static void m68k_op_and_8_er_al(m68000_base_device* mc68kcpu); +static void m68k_op_and_8_er_pcdi(m68000_base_device* mc68kcpu); +static void m68k_op_and_8_er_pcix(m68000_base_device* mc68kcpu); +static void m68k_op_and_8_er_i(m68000_base_device* mc68kcpu); +static void m68k_op_and_16_er_d(m68000_base_device* mc68kcpu); +static void m68k_op_and_16_er_ai(m68000_base_device* mc68kcpu); +static void m68k_op_and_16_er_pi(m68000_base_device* mc68kcpu); +static void m68k_op_and_16_er_pd(m68000_base_device* mc68kcpu); +static void m68k_op_and_16_er_di(m68000_base_device* mc68kcpu); +static void m68k_op_and_16_er_ix(m68000_base_device* mc68kcpu); +static void m68k_op_and_16_er_aw(m68000_base_device* mc68kcpu); +static void m68k_op_and_16_er_al(m68000_base_device* mc68kcpu); +static void m68k_op_and_16_er_pcdi(m68000_base_device* mc68kcpu); +static void m68k_op_and_16_er_pcix(m68000_base_device* mc68kcpu); +static void m68k_op_and_16_er_i(m68000_base_device* mc68kcpu); +static void m68k_op_and_32_er_d(m68000_base_device* mc68kcpu); +static void m68k_op_and_32_er_ai(m68000_base_device* mc68kcpu); +static void m68k_op_and_32_er_pi(m68000_base_device* mc68kcpu); +static void m68k_op_and_32_er_pd(m68000_base_device* mc68kcpu); +static void m68k_op_and_32_er_di(m68000_base_device* mc68kcpu); +static void m68k_op_and_32_er_ix(m68000_base_device* mc68kcpu); +static void m68k_op_and_32_er_aw(m68000_base_device* mc68kcpu); +static void m68k_op_and_32_er_al(m68000_base_device* mc68kcpu); +static void m68k_op_and_32_er_pcdi(m68000_base_device* mc68kcpu); +static void m68k_op_and_32_er_pcix(m68000_base_device* mc68kcpu); +static void m68k_op_and_32_er_i(m68000_base_device* mc68kcpu); +static void m68k_op_and_8_re_ai(m68000_base_device* mc68kcpu); +static void m68k_op_and_8_re_pi(m68000_base_device* mc68kcpu); +static void m68k_op_and_8_re_pi7(m68000_base_device* mc68kcpu); +static void m68k_op_and_8_re_pd(m68000_base_device* mc68kcpu); +static void m68k_op_and_8_re_pd7(m68000_base_device* mc68kcpu); +static void m68k_op_and_8_re_di(m68000_base_device* mc68kcpu); +static void m68k_op_and_8_re_ix(m68000_base_device* mc68kcpu); +static void m68k_op_and_8_re_aw(m68000_base_device* mc68kcpu); +static void m68k_op_and_8_re_al(m68000_base_device* mc68kcpu); +static void m68k_op_and_16_re_ai(m68000_base_device* mc68kcpu); +static void m68k_op_and_16_re_pi(m68000_base_device* mc68kcpu); +static void m68k_op_and_16_re_pd(m68000_base_device* mc68kcpu); +static void m68k_op_and_16_re_di(m68000_base_device* mc68kcpu); +static void m68k_op_and_16_re_ix(m68000_base_device* mc68kcpu); +static void m68k_op_and_16_re_aw(m68000_base_device* mc68kcpu); +static void m68k_op_and_16_re_al(m68000_base_device* mc68kcpu); +static void m68k_op_and_32_re_ai(m68000_base_device* mc68kcpu); +static void m68k_op_and_32_re_pi(m68000_base_device* mc68kcpu); +static void m68k_op_and_32_re_pd(m68000_base_device* mc68kcpu); +static void m68k_op_and_32_re_di(m68000_base_device* mc68kcpu); +static void m68k_op_and_32_re_ix(m68000_base_device* mc68kcpu); +static void m68k_op_and_32_re_aw(m68000_base_device* mc68kcpu); +static void m68k_op_and_32_re_al(m68000_base_device* mc68kcpu); +static void m68k_op_andi_8_d(m68000_base_device* mc68kcpu); +static void m68k_op_andi_8_ai(m68000_base_device* mc68kcpu); +static void m68k_op_andi_8_pi(m68000_base_device* mc68kcpu); +static void m68k_op_andi_8_pi7(m68000_base_device* mc68kcpu); +static void m68k_op_andi_8_pd(m68000_base_device* mc68kcpu); +static void m68k_op_andi_8_pd7(m68000_base_device* mc68kcpu); +static void m68k_op_andi_8_di(m68000_base_device* mc68kcpu); +static void m68k_op_andi_8_ix(m68000_base_device* mc68kcpu); +static void m68k_op_andi_8_aw(m68000_base_device* mc68kcpu); +static void m68k_op_andi_8_al(m68000_base_device* mc68kcpu); +static void m68k_op_andi_16_d(m68000_base_device* mc68kcpu); +static void m68k_op_andi_16_ai(m68000_base_device* mc68kcpu); +static void m68k_op_andi_16_pi(m68000_base_device* mc68kcpu); +static void m68k_op_andi_16_pd(m68000_base_device* mc68kcpu); +static void m68k_op_andi_16_di(m68000_base_device* mc68kcpu); +static void m68k_op_andi_16_ix(m68000_base_device* mc68kcpu); +static void m68k_op_andi_16_aw(m68000_base_device* mc68kcpu); +static void m68k_op_andi_16_al(m68000_base_device* mc68kcpu); +static void m68k_op_andi_32_d(m68000_base_device* mc68kcpu); +static void m68k_op_andi_32_ai(m68000_base_device* mc68kcpu); +static void m68k_op_andi_32_pi(m68000_base_device* mc68kcpu); +static void m68k_op_andi_32_pd(m68000_base_device* mc68kcpu); +static void m68k_op_andi_32_di(m68000_base_device* mc68kcpu); +static void m68k_op_andi_32_ix(m68000_base_device* mc68kcpu); +static void m68k_op_andi_32_aw(m68000_base_device* mc68kcpu); +static void m68k_op_andi_32_al(m68000_base_device* mc68kcpu); +static void m68k_op_andi_16_toc(m68000_base_device* mc68kcpu); +static void m68k_op_andi_16_tos(m68000_base_device* mc68kcpu); +static void m68k_op_asr_8_s(m68000_base_device* mc68kcpu); +static void m68k_op_asr_16_s(m68000_base_device* mc68kcpu); +static void m68k_op_asr_32_s(m68000_base_device* mc68kcpu); +static void m68k_op_asr_8_r(m68000_base_device* mc68kcpu); +static void m68k_op_asr_16_r(m68000_base_device* mc68kcpu); +static void m68k_op_asr_32_r(m68000_base_device* mc68kcpu); +static void m68k_op_asr_16_ai(m68000_base_device* mc68kcpu); +static void m68k_op_asr_16_pi(m68000_base_device* mc68kcpu); +static void m68k_op_asr_16_pd(m68000_base_device* mc68kcpu); +static void m68k_op_asr_16_di(m68000_base_device* mc68kcpu); +static void m68k_op_asr_16_ix(m68000_base_device* mc68kcpu); +static void m68k_op_asr_16_aw(m68000_base_device* mc68kcpu); +static void m68k_op_asr_16_al(m68000_base_device* mc68kcpu); +static void m68k_op_asl_8_s(m68000_base_device* mc68kcpu); +static void m68k_op_asl_16_s(m68000_base_device* mc68kcpu); +static void m68k_op_asl_32_s(m68000_base_device* mc68kcpu); +static void m68k_op_asl_8_r(m68000_base_device* mc68kcpu); +static void m68k_op_asl_16_r(m68000_base_device* mc68kcpu); +static void m68k_op_asl_32_r(m68000_base_device* mc68kcpu); +static void m68k_op_asl_16_ai(m68000_base_device* mc68kcpu); +static void m68k_op_asl_16_pi(m68000_base_device* mc68kcpu); +static void m68k_op_asl_16_pd(m68000_base_device* mc68kcpu); +static void m68k_op_asl_16_di(m68000_base_device* mc68kcpu); +static void m68k_op_asl_16_ix(m68000_base_device* mc68kcpu); +static void m68k_op_asl_16_aw(m68000_base_device* mc68kcpu); +static void m68k_op_asl_16_al(m68000_base_device* mc68kcpu); +static void m68k_op_bhi_8(m68000_base_device* mc68kcpu); +static void m68k_op_bls_8(m68000_base_device* mc68kcpu); +static void m68k_op_bcc_8(m68000_base_device* mc68kcpu); +static void m68k_op_bcs_8(m68000_base_device* mc68kcpu); +static void m68k_op_bne_8(m68000_base_device* mc68kcpu); +static void m68k_op_beq_8(m68000_base_device* mc68kcpu); +static void m68k_op_bvc_8(m68000_base_device* mc68kcpu); +static void m68k_op_bvs_8(m68000_base_device* mc68kcpu); +static void m68k_op_bpl_8(m68000_base_device* mc68kcpu); +static void m68k_op_bmi_8(m68000_base_device* mc68kcpu); +static void m68k_op_bge_8(m68000_base_device* mc68kcpu); +static void m68k_op_blt_8(m68000_base_device* mc68kcpu); +static void m68k_op_bgt_8(m68000_base_device* mc68kcpu); +static void m68k_op_ble_8(m68000_base_device* mc68kcpu); +static void m68k_op_bhi_16(m68000_base_device* mc68kcpu); +static void m68k_op_bls_16(m68000_base_device* mc68kcpu); +static void m68k_op_bcc_16(m68000_base_device* mc68kcpu); +static void m68k_op_bcs_16(m68000_base_device* mc68kcpu); +static void m68k_op_bne_16(m68000_base_device* mc68kcpu); +static void m68k_op_beq_16(m68000_base_device* mc68kcpu); +static void m68k_op_bvc_16(m68000_base_device* mc68kcpu); +static void m68k_op_bvs_16(m68000_base_device* mc68kcpu); +static void m68k_op_bpl_16(m68000_base_device* mc68kcpu); +static void m68k_op_bmi_16(m68000_base_device* mc68kcpu); +static void m68k_op_bge_16(m68000_base_device* mc68kcpu); +static void m68k_op_blt_16(m68000_base_device* mc68kcpu); +static void m68k_op_bgt_16(m68000_base_device* mc68kcpu); +static void m68k_op_ble_16(m68000_base_device* mc68kcpu); +static void m68k_op_bhi_32(m68000_base_device* mc68kcpu); +static void m68k_op_bls_32(m68000_base_device* mc68kcpu); +static void m68k_op_bcc_32(m68000_base_device* mc68kcpu); +static void m68k_op_bcs_32(m68000_base_device* mc68kcpu); +static void m68k_op_bne_32(m68000_base_device* mc68kcpu); +static void m68k_op_beq_32(m68000_base_device* mc68kcpu); +static void m68k_op_bvc_32(m68000_base_device* mc68kcpu); +static void m68k_op_bvs_32(m68000_base_device* mc68kcpu); +static void m68k_op_bpl_32(m68000_base_device* mc68kcpu); +static void m68k_op_bmi_32(m68000_base_device* mc68kcpu); +static void m68k_op_bge_32(m68000_base_device* mc68kcpu); +static void m68k_op_blt_32(m68000_base_device* mc68kcpu); +static void m68k_op_bgt_32(m68000_base_device* mc68kcpu); +static void m68k_op_ble_32(m68000_base_device* mc68kcpu); +static void m68k_op_bchg_32_r_d(m68000_base_device* mc68kcpu); +static void m68k_op_bchg_8_r_ai(m68000_base_device* mc68kcpu); +static void m68k_op_bchg_8_r_pi(m68000_base_device* mc68kcpu); +static void m68k_op_bchg_8_r_pi7(m68000_base_device* mc68kcpu); +static void m68k_op_bchg_8_r_pd(m68000_base_device* mc68kcpu); +static void m68k_op_bchg_8_r_pd7(m68000_base_device* mc68kcpu); +static void m68k_op_bchg_8_r_di(m68000_base_device* mc68kcpu); +static void m68k_op_bchg_8_r_ix(m68000_base_device* mc68kcpu); +static void m68k_op_bchg_8_r_aw(m68000_base_device* mc68kcpu); +static void m68k_op_bchg_8_r_al(m68000_base_device* mc68kcpu); +static void m68k_op_bchg_32_s_d(m68000_base_device* mc68kcpu); +static void m68k_op_bchg_8_s_ai(m68000_base_device* mc68kcpu); +static void m68k_op_bchg_8_s_pi(m68000_base_device* mc68kcpu); +static void m68k_op_bchg_8_s_pi7(m68000_base_device* mc68kcpu); +static void m68k_op_bchg_8_s_pd(m68000_base_device* mc68kcpu); +static void m68k_op_bchg_8_s_pd7(m68000_base_device* mc68kcpu); +static void m68k_op_bchg_8_s_di(m68000_base_device* mc68kcpu); +static void m68k_op_bchg_8_s_ix(m68000_base_device* mc68kcpu); +static void m68k_op_bchg_8_s_aw(m68000_base_device* mc68kcpu); +static void m68k_op_bchg_8_s_al(m68000_base_device* mc68kcpu); +static void m68k_op_bclr_32_r_d(m68000_base_device* mc68kcpu); +static void m68k_op_bclr_8_r_ai(m68000_base_device* mc68kcpu); +static void m68k_op_bclr_8_r_pi(m68000_base_device* mc68kcpu); +static void m68k_op_bclr_8_r_pi7(m68000_base_device* mc68kcpu); +static void m68k_op_bclr_8_r_pd(m68000_base_device* mc68kcpu); +static void m68k_op_bclr_8_r_pd7(m68000_base_device* mc68kcpu); +static void m68k_op_bclr_8_r_di(m68000_base_device* mc68kcpu); +static void m68k_op_bclr_8_r_ix(m68000_base_device* mc68kcpu); +static void m68k_op_bclr_8_r_aw(m68000_base_device* mc68kcpu); +static void m68k_op_bclr_8_r_al(m68000_base_device* mc68kcpu); +static void m68k_op_bclr_32_s_d(m68000_base_device* mc68kcpu); +static void m68k_op_bclr_8_s_ai(m68000_base_device* mc68kcpu); +static void m68k_op_bclr_8_s_pi(m68000_base_device* mc68kcpu); +static void m68k_op_bclr_8_s_pi7(m68000_base_device* mc68kcpu); +static void m68k_op_bclr_8_s_pd(m68000_base_device* mc68kcpu); +static void m68k_op_bclr_8_s_pd7(m68000_base_device* mc68kcpu); +static void m68k_op_bclr_8_s_di(m68000_base_device* mc68kcpu); +static void m68k_op_bclr_8_s_ix(m68000_base_device* mc68kcpu); +static void m68k_op_bclr_8_s_aw(m68000_base_device* mc68kcpu); +static void m68k_op_bclr_8_s_al(m68000_base_device* mc68kcpu); +static void m68k_op_bfchg_32_d(m68000_base_device* mc68kcpu); +static void m68k_op_bfchg_32_ai(m68000_base_device* mc68kcpu); +static void m68k_op_bfchg_32_di(m68000_base_device* mc68kcpu); +static void m68k_op_bfchg_32_ix(m68000_base_device* mc68kcpu); +static void m68k_op_bfchg_32_aw(m68000_base_device* mc68kcpu); +static void m68k_op_bfchg_32_al(m68000_base_device* mc68kcpu); +static void m68k_op_bfclr_32_d(m68000_base_device* mc68kcpu); +static void m68k_op_bfclr_32_ai(m68000_base_device* mc68kcpu); +static void m68k_op_bfclr_32_di(m68000_base_device* mc68kcpu); +static void m68k_op_bfclr_32_ix(m68000_base_device* mc68kcpu); +static void m68k_op_bfclr_32_aw(m68000_base_device* mc68kcpu); +static void m68k_op_bfclr_32_al(m68000_base_device* mc68kcpu); +static void m68k_op_bfexts_32_d(m68000_base_device* mc68kcpu); +static void m68k_op_bfexts_32_ai(m68000_base_device* mc68kcpu); +static void m68k_op_bfexts_32_di(m68000_base_device* mc68kcpu); +static void m68k_op_bfexts_32_ix(m68000_base_device* mc68kcpu); +static void m68k_op_bfexts_32_aw(m68000_base_device* mc68kcpu); +static void m68k_op_bfexts_32_al(m68000_base_device* mc68kcpu); +static void m68k_op_bfexts_32_pcdi(m68000_base_device* mc68kcpu); +static void m68k_op_bfexts_32_pcix(m68000_base_device* mc68kcpu); +static void m68k_op_bfextu_32_d(m68000_base_device* mc68kcpu); +static void m68k_op_bfextu_32_ai(m68000_base_device* mc68kcpu); +static void m68k_op_bfextu_32_di(m68000_base_device* mc68kcpu); +static void m68k_op_bfextu_32_ix(m68000_base_device* mc68kcpu); +static void m68k_op_bfextu_32_aw(m68000_base_device* mc68kcpu); +static void m68k_op_bfextu_32_al(m68000_base_device* mc68kcpu); +static void m68k_op_bfextu_32_pcdi(m68000_base_device* mc68kcpu); +static void m68k_op_bfextu_32_pcix(m68000_base_device* mc68kcpu); +static void m68k_op_bfffo_32_d(m68000_base_device* mc68kcpu); +static void m68k_op_bfffo_32_ai(m68000_base_device* mc68kcpu); +static void m68k_op_bfffo_32_di(m68000_base_device* mc68kcpu); +static void m68k_op_bfffo_32_ix(m68000_base_device* mc68kcpu); +static void m68k_op_bfffo_32_aw(m68000_base_device* mc68kcpu); +static void m68k_op_bfffo_32_al(m68000_base_device* mc68kcpu); +static void m68k_op_bfffo_32_pcdi(m68000_base_device* mc68kcpu); +static void m68k_op_bfffo_32_pcix(m68000_base_device* mc68kcpu); +static void m68k_op_bfins_32_d(m68000_base_device* mc68kcpu); +static void m68k_op_bfins_32_ai(m68000_base_device* mc68kcpu); +static void m68k_op_bfins_32_di(m68000_base_device* mc68kcpu); +static void m68k_op_bfins_32_ix(m68000_base_device* mc68kcpu); +static void m68k_op_bfins_32_aw(m68000_base_device* mc68kcpu); +static void m68k_op_bfins_32_al(m68000_base_device* mc68kcpu); +static void m68k_op_bfset_32_d(m68000_base_device* mc68kcpu); +static void m68k_op_bfset_32_ai(m68000_base_device* mc68kcpu); +static void m68k_op_bfset_32_di(m68000_base_device* mc68kcpu); +static void m68k_op_bfset_32_ix(m68000_base_device* mc68kcpu); +static void m68k_op_bfset_32_aw(m68000_base_device* mc68kcpu); +static void m68k_op_bfset_32_al(m68000_base_device* mc68kcpu); +static void m68k_op_bftst_32_d(m68000_base_device* mc68kcpu); +static void m68k_op_bftst_32_ai(m68000_base_device* mc68kcpu); +static void m68k_op_bftst_32_di(m68000_base_device* mc68kcpu); +static void m68k_op_bftst_32_ix(m68000_base_device* mc68kcpu); +static void m68k_op_bftst_32_aw(m68000_base_device* mc68kcpu); +static void m68k_op_bftst_32_al(m68000_base_device* mc68kcpu); +static void m68k_op_bftst_32_pcdi(m68000_base_device* mc68kcpu); +static void m68k_op_bftst_32_pcix(m68000_base_device* mc68kcpu); +static void m68k_op_bkpt(m68000_base_device* mc68kcpu); +static void m68k_op_bra_8(m68000_base_device* mc68kcpu); +static void m68k_op_bra_16(m68000_base_device* mc68kcpu); +static void m68k_op_bra_32(m68000_base_device* mc68kcpu); +static void m68k_op_bset_32_r_d(m68000_base_device* mc68kcpu); +static void m68k_op_bset_8_r_ai(m68000_base_device* mc68kcpu); +static void m68k_op_bset_8_r_pi(m68000_base_device* mc68kcpu); +static void m68k_op_bset_8_r_pi7(m68000_base_device* mc68kcpu); +static void m68k_op_bset_8_r_pd(m68000_base_device* mc68kcpu); +static void m68k_op_bset_8_r_pd7(m68000_base_device* mc68kcpu); +static void m68k_op_bset_8_r_di(m68000_base_device* mc68kcpu); +static void m68k_op_bset_8_r_ix(m68000_base_device* mc68kcpu); +static void m68k_op_bset_8_r_aw(m68000_base_device* mc68kcpu); +static void m68k_op_bset_8_r_al(m68000_base_device* mc68kcpu); +static void m68k_op_bset_32_s_d(m68000_base_device* mc68kcpu); +static void m68k_op_bset_8_s_ai(m68000_base_device* mc68kcpu); +static void m68k_op_bset_8_s_pi(m68000_base_device* mc68kcpu); +static void m68k_op_bset_8_s_pi7(m68000_base_device* mc68kcpu); +static void m68k_op_bset_8_s_pd(m68000_base_device* mc68kcpu); +static void m68k_op_bset_8_s_pd7(m68000_base_device* mc68kcpu); +static void m68k_op_bset_8_s_di(m68000_base_device* mc68kcpu); +static void m68k_op_bset_8_s_ix(m68000_base_device* mc68kcpu); +static void m68k_op_bset_8_s_aw(m68000_base_device* mc68kcpu); +static void m68k_op_bset_8_s_al(m68000_base_device* mc68kcpu); +static void m68k_op_bsr_8(m68000_base_device* mc68kcpu); +static void m68k_op_bsr_16(m68000_base_device* mc68kcpu); +static void m68k_op_bsr_32(m68000_base_device* mc68kcpu); +static void m68k_op_btst_32_r_d(m68000_base_device* mc68kcpu); +static void m68k_op_btst_8_r_ai(m68000_base_device* mc68kcpu); +static void m68k_op_btst_8_r_pi(m68000_base_device* mc68kcpu); +static void m68k_op_btst_8_r_pi7(m68000_base_device* mc68kcpu); +static void m68k_op_btst_8_r_pd(m68000_base_device* mc68kcpu); +static void m68k_op_btst_8_r_pd7(m68000_base_device* mc68kcpu); +static void m68k_op_btst_8_r_di(m68000_base_device* mc68kcpu); +static void m68k_op_btst_8_r_ix(m68000_base_device* mc68kcpu); +static void m68k_op_btst_8_r_aw(m68000_base_device* mc68kcpu); +static void m68k_op_btst_8_r_al(m68000_base_device* mc68kcpu); +static void m68k_op_btst_8_r_pcdi(m68000_base_device* mc68kcpu); +static void m68k_op_btst_8_r_pcix(m68000_base_device* mc68kcpu); +static void m68k_op_btst_8_r_i(m68000_base_device* mc68kcpu); +static void m68k_op_btst_32_s_d(m68000_base_device* mc68kcpu); +static void m68k_op_btst_8_s_ai(m68000_base_device* mc68kcpu); +static void m68k_op_btst_8_s_pi(m68000_base_device* mc68kcpu); +static void m68k_op_btst_8_s_pi7(m68000_base_device* mc68kcpu); +static void m68k_op_btst_8_s_pd(m68000_base_device* mc68kcpu); +static void m68k_op_btst_8_s_pd7(m68000_base_device* mc68kcpu); +static void m68k_op_btst_8_s_di(m68000_base_device* mc68kcpu); +static void m68k_op_btst_8_s_ix(m68000_base_device* mc68kcpu); +static void m68k_op_btst_8_s_aw(m68000_base_device* mc68kcpu); +static void m68k_op_btst_8_s_al(m68000_base_device* mc68kcpu); +static void m68k_op_btst_8_s_pcdi(m68000_base_device* mc68kcpu); +static void m68k_op_btst_8_s_pcix(m68000_base_device* mc68kcpu); +static void m68k_op_callm_32_ai(m68000_base_device* mc68kcpu); +static void m68k_op_callm_32_di(m68000_base_device* mc68kcpu); +static void m68k_op_callm_32_ix(m68000_base_device* mc68kcpu); +static void m68k_op_callm_32_aw(m68000_base_device* mc68kcpu); +static void m68k_op_callm_32_al(m68000_base_device* mc68kcpu); +static void m68k_op_callm_32_pcdi(m68000_base_device* mc68kcpu); +static void m68k_op_callm_32_pcix(m68000_base_device* mc68kcpu); +static void m68k_op_cas_8_ai(m68000_base_device* mc68kcpu); +static void m68k_op_cas_8_pi(m68000_base_device* mc68kcpu); +static void m68k_op_cas_8_pi7(m68000_base_device* mc68kcpu); +static void m68k_op_cas_8_pd(m68000_base_device* mc68kcpu); +static void m68k_op_cas_8_pd7(m68000_base_device* mc68kcpu); +static void m68k_op_cas_8_di(m68000_base_device* mc68kcpu); +static void m68k_op_cas_8_ix(m68000_base_device* mc68kcpu); +static void m68k_op_cas_8_aw(m68000_base_device* mc68kcpu); +static void m68k_op_cas_8_al(m68000_base_device* mc68kcpu); +static void m68k_op_cas_16_ai(m68000_base_device* mc68kcpu); +static void m68k_op_cas_16_pi(m68000_base_device* mc68kcpu); +static void m68k_op_cas_16_pd(m68000_base_device* mc68kcpu); +static void m68k_op_cas_16_di(m68000_base_device* mc68kcpu); +static void m68k_op_cas_16_ix(m68000_base_device* mc68kcpu); +static void m68k_op_cas_16_aw(m68000_base_device* mc68kcpu); +static void m68k_op_cas_16_al(m68000_base_device* mc68kcpu); +static void m68k_op_cas_32_ai(m68000_base_device* mc68kcpu); +static void m68k_op_cas_32_pi(m68000_base_device* mc68kcpu); +static void m68k_op_cas_32_pd(m68000_base_device* mc68kcpu); +static void m68k_op_cas_32_di(m68000_base_device* mc68kcpu); +static void m68k_op_cas_32_ix(m68000_base_device* mc68kcpu); +static void m68k_op_cas_32_aw(m68000_base_device* mc68kcpu); +static void m68k_op_cas_32_al(m68000_base_device* mc68kcpu); +static void m68k_op_cas2_16(m68000_base_device* mc68kcpu); +static void m68k_op_cas2_32(m68000_base_device* mc68kcpu); +static void m68k_op_chk_16_d(m68000_base_device* mc68kcpu); +static void m68k_op_chk_16_ai(m68000_base_device* mc68kcpu); +static void m68k_op_chk_16_pi(m68000_base_device* mc68kcpu); +static void m68k_op_chk_16_pd(m68000_base_device* mc68kcpu); +static void m68k_op_chk_16_di(m68000_base_device* mc68kcpu); +static void m68k_op_chk_16_ix(m68000_base_device* mc68kcpu); +static void m68k_op_chk_16_aw(m68000_base_device* mc68kcpu); +static void m68k_op_chk_16_al(m68000_base_device* mc68kcpu); +static void m68k_op_chk_16_pcdi(m68000_base_device* mc68kcpu); +static void m68k_op_chk_16_pcix(m68000_base_device* mc68kcpu); +static void m68k_op_chk_16_i(m68000_base_device* mc68kcpu); +static void m68k_op_chk_32_d(m68000_base_device* mc68kcpu); +static void m68k_op_chk_32_ai(m68000_base_device* mc68kcpu); +static void m68k_op_chk_32_pi(m68000_base_device* mc68kcpu); +static void m68k_op_chk_32_pd(m68000_base_device* mc68kcpu); +static void m68k_op_chk_32_di(m68000_base_device* mc68kcpu); +static void m68k_op_chk_32_ix(m68000_base_device* mc68kcpu); +static void m68k_op_chk_32_aw(m68000_base_device* mc68kcpu); +static void m68k_op_chk_32_al(m68000_base_device* mc68kcpu); +static void m68k_op_chk_32_pcdi(m68000_base_device* mc68kcpu); +static void m68k_op_chk_32_pcix(m68000_base_device* mc68kcpu); +static void m68k_op_chk_32_i(m68000_base_device* mc68kcpu); +static void m68k_op_chk2cmp2_8_pcdi(m68000_base_device* mc68kcpu); +static void m68k_op_chk2cmp2_8_pcix(m68000_base_device* mc68kcpu); +static void m68k_op_chk2cmp2_8_ai(m68000_base_device* mc68kcpu); +static void m68k_op_chk2cmp2_8_di(m68000_base_device* mc68kcpu); +static void m68k_op_chk2cmp2_8_ix(m68000_base_device* mc68kcpu); +static void m68k_op_chk2cmp2_8_aw(m68000_base_device* mc68kcpu); +static void m68k_op_chk2cmp2_8_al(m68000_base_device* mc68kcpu); +static void m68k_op_chk2cmp2_16_pcdi(m68000_base_device* mc68kcpu); +static void m68k_op_chk2cmp2_16_pcix(m68000_base_device* mc68kcpu); +static void m68k_op_chk2cmp2_16_ai(m68000_base_device* mc68kcpu); +static void m68k_op_chk2cmp2_16_di(m68000_base_device* mc68kcpu); +static void m68k_op_chk2cmp2_16_ix(m68000_base_device* mc68kcpu); +static void m68k_op_chk2cmp2_16_aw(m68000_base_device* mc68kcpu); +static void m68k_op_chk2cmp2_16_al(m68000_base_device* mc68kcpu); +static void m68k_op_chk2cmp2_32_pcdi(m68000_base_device* mc68kcpu); +static void m68k_op_chk2cmp2_32_pcix(m68000_base_device* mc68kcpu); +static void m68k_op_chk2cmp2_32_ai(m68000_base_device* mc68kcpu); +static void m68k_op_chk2cmp2_32_di(m68000_base_device* mc68kcpu); +static void m68k_op_chk2cmp2_32_ix(m68000_base_device* mc68kcpu); +static void m68k_op_chk2cmp2_32_aw(m68000_base_device* mc68kcpu); +static void m68k_op_chk2cmp2_32_al(m68000_base_device* mc68kcpu); +static void m68k_op_clr_8_d(m68000_base_device* mc68kcpu); +static void m68k_op_clr_8_ai(m68000_base_device* mc68kcpu); +static void m68k_op_clr_8_pi(m68000_base_device* mc68kcpu); +static void m68k_op_clr_8_pi7(m68000_base_device* mc68kcpu); +static void m68k_op_clr_8_pd(m68000_base_device* mc68kcpu); +static void m68k_op_clr_8_pd7(m68000_base_device* mc68kcpu); +static void m68k_op_clr_8_di(m68000_base_device* mc68kcpu); +static void m68k_op_clr_8_ix(m68000_base_device* mc68kcpu); +static void m68k_op_clr_8_aw(m68000_base_device* mc68kcpu); +static void m68k_op_clr_8_al(m68000_base_device* mc68kcpu); +static void m68k_op_clr_16_d(m68000_base_device* mc68kcpu); +static void m68k_op_clr_16_ai(m68000_base_device* mc68kcpu); +static void m68k_op_clr_16_pi(m68000_base_device* mc68kcpu); +static void m68k_op_clr_16_pd(m68000_base_device* mc68kcpu); +static void m68k_op_clr_16_di(m68000_base_device* mc68kcpu); +static void m68k_op_clr_16_ix(m68000_base_device* mc68kcpu); +static void m68k_op_clr_16_aw(m68000_base_device* mc68kcpu); +static void m68k_op_clr_16_al(m68000_base_device* mc68kcpu); +static void m68k_op_clr_32_d(m68000_base_device* mc68kcpu); +static void m68k_op_clr_32_ai(m68000_base_device* mc68kcpu); +static void m68k_op_clr_32_pi(m68000_base_device* mc68kcpu); +static void m68k_op_clr_32_pd(m68000_base_device* mc68kcpu); +static void m68k_op_clr_32_di(m68000_base_device* mc68kcpu); +static void m68k_op_clr_32_ix(m68000_base_device* mc68kcpu); +static void m68k_op_clr_32_aw(m68000_base_device* mc68kcpu); +static void m68k_op_clr_32_al(m68000_base_device* mc68kcpu); +static void m68k_op_cmp_8_d(m68000_base_device* mc68kcpu); +static void m68k_op_cmp_8_ai(m68000_base_device* mc68kcpu); +static void m68k_op_cmp_8_pi(m68000_base_device* mc68kcpu); +static void m68k_op_cmp_8_pi7(m68000_base_device* mc68kcpu); +static void m68k_op_cmp_8_pd(m68000_base_device* mc68kcpu); +static void m68k_op_cmp_8_pd7(m68000_base_device* mc68kcpu); +static void m68k_op_cmp_8_di(m68000_base_device* mc68kcpu); +static void m68k_op_cmp_8_ix(m68000_base_device* mc68kcpu); +static void m68k_op_cmp_8_aw(m68000_base_device* mc68kcpu); +static void m68k_op_cmp_8_al(m68000_base_device* mc68kcpu); +static void m68k_op_cmp_8_pcdi(m68000_base_device* mc68kcpu); +static void m68k_op_cmp_8_pcix(m68000_base_device* mc68kcpu); +static void m68k_op_cmp_8_i(m68000_base_device* mc68kcpu); +static void m68k_op_cmp_16_d(m68000_base_device* mc68kcpu); +static void m68k_op_cmp_16_a(m68000_base_device* mc68kcpu); +static void m68k_op_cmp_16_ai(m68000_base_device* mc68kcpu); +static void m68k_op_cmp_16_pi(m68000_base_device* mc68kcpu); +static void m68k_op_cmp_16_pd(m68000_base_device* mc68kcpu); +static void m68k_op_cmp_16_di(m68000_base_device* mc68kcpu); +static void m68k_op_cmp_16_ix(m68000_base_device* mc68kcpu); +static void m68k_op_cmp_16_aw(m68000_base_device* mc68kcpu); +static void m68k_op_cmp_16_al(m68000_base_device* mc68kcpu); +static void m68k_op_cmp_16_pcdi(m68000_base_device* mc68kcpu); +static void m68k_op_cmp_16_pcix(m68000_base_device* mc68kcpu); +static void m68k_op_cmp_16_i(m68000_base_device* mc68kcpu); +static void m68k_op_cmp_32_d(m68000_base_device* mc68kcpu); +static void m68k_op_cmp_32_a(m68000_base_device* mc68kcpu); +static void m68k_op_cmp_32_ai(m68000_base_device* mc68kcpu); +static void m68k_op_cmp_32_pi(m68000_base_device* mc68kcpu); +static void m68k_op_cmp_32_pd(m68000_base_device* mc68kcpu); +static void m68k_op_cmp_32_di(m68000_base_device* mc68kcpu); +static void m68k_op_cmp_32_ix(m68000_base_device* mc68kcpu); +static void m68k_op_cmp_32_aw(m68000_base_device* mc68kcpu); +static void m68k_op_cmp_32_al(m68000_base_device* mc68kcpu); +static void m68k_op_cmp_32_pcdi(m68000_base_device* mc68kcpu); +static void m68k_op_cmp_32_pcix(m68000_base_device* mc68kcpu); +static void m68k_op_cmp_32_i(m68000_base_device* mc68kcpu); +static void m68k_op_cmpa_16_d(m68000_base_device* mc68kcpu); +static void m68k_op_cmpa_16_a(m68000_base_device* mc68kcpu); +static void m68k_op_cmpa_16_ai(m68000_base_device* mc68kcpu); +static void m68k_op_cmpa_16_pi(m68000_base_device* mc68kcpu); +static void m68k_op_cmpa_16_pd(m68000_base_device* mc68kcpu); +static void m68k_op_cmpa_16_di(m68000_base_device* mc68kcpu); +static void m68k_op_cmpa_16_ix(m68000_base_device* mc68kcpu); +static void m68k_op_cmpa_16_aw(m68000_base_device* mc68kcpu); +static void m68k_op_cmpa_16_al(m68000_base_device* mc68kcpu); +static void m68k_op_cmpa_16_pcdi(m68000_base_device* mc68kcpu); +static void m68k_op_cmpa_16_pcix(m68000_base_device* mc68kcpu); +static void m68k_op_cmpa_16_i(m68000_base_device* mc68kcpu); +static void m68k_op_cmpa_32_d(m68000_base_device* mc68kcpu); +static void m68k_op_cmpa_32_a(m68000_base_device* mc68kcpu); +static void m68k_op_cmpa_32_ai(m68000_base_device* mc68kcpu); +static void m68k_op_cmpa_32_pi(m68000_base_device* mc68kcpu); +static void m68k_op_cmpa_32_pd(m68000_base_device* mc68kcpu); +static void m68k_op_cmpa_32_di(m68000_base_device* mc68kcpu); +static void m68k_op_cmpa_32_ix(m68000_base_device* mc68kcpu); +static void m68k_op_cmpa_32_aw(m68000_base_device* mc68kcpu); +static void m68k_op_cmpa_32_al(m68000_base_device* mc68kcpu); +static void m68k_op_cmpa_32_pcdi(m68000_base_device* mc68kcpu); +static void m68k_op_cmpa_32_pcix(m68000_base_device* mc68kcpu); +static void m68k_op_cmpa_32_i(m68000_base_device* mc68kcpu); +static void m68k_op_cmpi_8_d(m68000_base_device* mc68kcpu); +static void m68k_op_cmpi_8_ai(m68000_base_device* mc68kcpu); +static void m68k_op_cmpi_8_pi(m68000_base_device* mc68kcpu); +static void m68k_op_cmpi_8_pi7(m68000_base_device* mc68kcpu); +static void m68k_op_cmpi_8_pd(m68000_base_device* mc68kcpu); +static void m68k_op_cmpi_8_pd7(m68000_base_device* mc68kcpu); +static void m68k_op_cmpi_8_di(m68000_base_device* mc68kcpu); +static void m68k_op_cmpi_8_ix(m68000_base_device* mc68kcpu); +static void m68k_op_cmpi_8_aw(m68000_base_device* mc68kcpu); +static void m68k_op_cmpi_8_al(m68000_base_device* mc68kcpu); +static void m68k_op_cmpi_8_pcdi(m68000_base_device* mc68kcpu); +static void m68k_op_cmpi_8_pcix(m68000_base_device* mc68kcpu); +static void m68k_op_cmpi_16_d(m68000_base_device* mc68kcpu); +static void m68k_op_cmpi_16_ai(m68000_base_device* mc68kcpu); +static void m68k_op_cmpi_16_pi(m68000_base_device* mc68kcpu); +static void m68k_op_cmpi_16_pd(m68000_base_device* mc68kcpu); +static void m68k_op_cmpi_16_di(m68000_base_device* mc68kcpu); +static void m68k_op_cmpi_16_ix(m68000_base_device* mc68kcpu); +static void m68k_op_cmpi_16_aw(m68000_base_device* mc68kcpu); +static void m68k_op_cmpi_16_al(m68000_base_device* mc68kcpu); +static void m68k_op_cmpi_16_pcdi(m68000_base_device* mc68kcpu); +static void m68k_op_cmpi_16_pcix(m68000_base_device* mc68kcpu); +static void m68k_op_cmpi_32_d(m68000_base_device* mc68kcpu); +static void m68k_op_cmpi_32_ai(m68000_base_device* mc68kcpu); +static void m68k_op_cmpi_32_pi(m68000_base_device* mc68kcpu); +static void m68k_op_cmpi_32_pd(m68000_base_device* mc68kcpu); +static void m68k_op_cmpi_32_di(m68000_base_device* mc68kcpu); +static void m68k_op_cmpi_32_ix(m68000_base_device* mc68kcpu); +static void m68k_op_cmpi_32_aw(m68000_base_device* mc68kcpu); +static void m68k_op_cmpi_32_al(m68000_base_device* mc68kcpu); +static void m68k_op_cmpi_32_pcdi(m68000_base_device* mc68kcpu); +static void m68k_op_cmpi_32_pcix(m68000_base_device* mc68kcpu); +static void m68k_op_cmpm_8_ax7(m68000_base_device* mc68kcpu); +static void m68k_op_cmpm_8_ay7(m68000_base_device* mc68kcpu); +static void m68k_op_cmpm_8_axy7(m68000_base_device* mc68kcpu); +static void m68k_op_cmpm_8(m68000_base_device* mc68kcpu); +static void m68k_op_cmpm_16(m68000_base_device* mc68kcpu); +static void m68k_op_cmpm_32(m68000_base_device* mc68kcpu); +static void m68k_op_cpbcc_32(m68000_base_device* mc68kcpu); +static void m68k_op_cpdbcc_32(m68000_base_device* mc68kcpu); +static void m68k_op_cpgen_32(m68000_base_device* mc68kcpu); +static void m68k_op_cpscc_32(m68000_base_device* mc68kcpu); +static void m68k_op_cptrapcc_32(m68000_base_device* mc68kcpu); +static void m68k_op_ftrapcc_32(m68000_base_device* mc68kcpu); +static void m68k_op_dbt_16(m68000_base_device* mc68kcpu); +static void m68k_op_dbf_16(m68000_base_device* mc68kcpu); +static void m68k_op_dbhi_16(m68000_base_device* mc68kcpu); +static void m68k_op_dbls_16(m68000_base_device* mc68kcpu); +static void m68k_op_dbcc_16(m68000_base_device* mc68kcpu); +static void m68k_op_dbcs_16(m68000_base_device* mc68kcpu); +static void m68k_op_dbne_16(m68000_base_device* mc68kcpu); +static void m68k_op_dbeq_16(m68000_base_device* mc68kcpu); +static void m68k_op_dbvc_16(m68000_base_device* mc68kcpu); +static void m68k_op_dbvs_16(m68000_base_device* mc68kcpu); +static void m68k_op_dbpl_16(m68000_base_device* mc68kcpu); +static void m68k_op_dbmi_16(m68000_base_device* mc68kcpu); +static void m68k_op_dbge_16(m68000_base_device* mc68kcpu); +static void m68k_op_dblt_16(m68000_base_device* mc68kcpu); +static void m68k_op_dbgt_16(m68000_base_device* mc68kcpu); +static void m68k_op_dble_16(m68000_base_device* mc68kcpu); +static void m68k_op_divs_16_d(m68000_base_device* mc68kcpu); +static void m68k_op_divs_16_ai(m68000_base_device* mc68kcpu); +static void m68k_op_divs_16_pi(m68000_base_device* mc68kcpu); +static void m68k_op_divs_16_pd(m68000_base_device* mc68kcpu); +static void m68k_op_divs_16_di(m68000_base_device* mc68kcpu); +static void m68k_op_divs_16_ix(m68000_base_device* mc68kcpu); +static void m68k_op_divs_16_aw(m68000_base_device* mc68kcpu); +static void m68k_op_divs_16_al(m68000_base_device* mc68kcpu); +static void m68k_op_divs_16_pcdi(m68000_base_device* mc68kcpu); +static void m68k_op_divs_16_pcix(m68000_base_device* mc68kcpu); +static void m68k_op_divs_16_i(m68000_base_device* mc68kcpu); +static void m68k_op_divu_16_d(m68000_base_device* mc68kcpu); +static void m68k_op_divu_16_ai(m68000_base_device* mc68kcpu); +static void m68k_op_divu_16_pi(m68000_base_device* mc68kcpu); +static void m68k_op_divu_16_pd(m68000_base_device* mc68kcpu); +static void m68k_op_divu_16_di(m68000_base_device* mc68kcpu); +static void m68k_op_divu_16_ix(m68000_base_device* mc68kcpu); +static void m68k_op_divu_16_aw(m68000_base_device* mc68kcpu); +static void m68k_op_divu_16_al(m68000_base_device* mc68kcpu); +static void m68k_op_divu_16_pcdi(m68000_base_device* mc68kcpu); +static void m68k_op_divu_16_pcix(m68000_base_device* mc68kcpu); +static void m68k_op_divu_16_i(m68000_base_device* mc68kcpu); +static void m68k_op_divl_32_d(m68000_base_device* mc68kcpu); +static void m68k_op_divl_32_ai(m68000_base_device* mc68kcpu); +static void m68k_op_divl_32_pi(m68000_base_device* mc68kcpu); +static void m68k_op_divl_32_pd(m68000_base_device* mc68kcpu); +static void m68k_op_divl_32_di(m68000_base_device* mc68kcpu); +static void m68k_op_divl_32_ix(m68000_base_device* mc68kcpu); +static void m68k_op_divl_32_aw(m68000_base_device* mc68kcpu); +static void m68k_op_divl_32_al(m68000_base_device* mc68kcpu); +static void m68k_op_divl_32_pcdi(m68000_base_device* mc68kcpu); +static void m68k_op_divl_32_pcix(m68000_base_device* mc68kcpu); +static void m68k_op_divl_32_i(m68000_base_device* mc68kcpu); +static void m68k_op_eor_8_d(m68000_base_device* mc68kcpu); +static void m68k_op_eor_8_ai(m68000_base_device* mc68kcpu); +static void m68k_op_eor_8_pi(m68000_base_device* mc68kcpu); +static void m68k_op_eor_8_pi7(m68000_base_device* mc68kcpu); +static void m68k_op_eor_8_pd(m68000_base_device* mc68kcpu); +static void m68k_op_eor_8_pd7(m68000_base_device* mc68kcpu); +static void m68k_op_eor_8_di(m68000_base_device* mc68kcpu); +static void m68k_op_eor_8_ix(m68000_base_device* mc68kcpu); +static void m68k_op_eor_8_aw(m68000_base_device* mc68kcpu); +static void m68k_op_eor_8_al(m68000_base_device* mc68kcpu); +static void m68k_op_eor_16_d(m68000_base_device* mc68kcpu); +static void m68k_op_eor_16_ai(m68000_base_device* mc68kcpu); +static void m68k_op_eor_16_pi(m68000_base_device* mc68kcpu); +static void m68k_op_eor_16_pd(m68000_base_device* mc68kcpu); +static void m68k_op_eor_16_di(m68000_base_device* mc68kcpu); +static void m68k_op_eor_16_ix(m68000_base_device* mc68kcpu); +static void m68k_op_eor_16_aw(m68000_base_device* mc68kcpu); +static void m68k_op_eor_16_al(m68000_base_device* mc68kcpu); +static void m68k_op_eor_32_d(m68000_base_device* mc68kcpu); +static void m68k_op_eor_32_ai(m68000_base_device* mc68kcpu); +static void m68k_op_eor_32_pi(m68000_base_device* mc68kcpu); +static void m68k_op_eor_32_pd(m68000_base_device* mc68kcpu); +static void m68k_op_eor_32_di(m68000_base_device* mc68kcpu); +static void m68k_op_eor_32_ix(m68000_base_device* mc68kcpu); +static void m68k_op_eor_32_aw(m68000_base_device* mc68kcpu); +static void m68k_op_eor_32_al(m68000_base_device* mc68kcpu); +static void m68k_op_eori_8_d(m68000_base_device* mc68kcpu); +static void m68k_op_eori_8_ai(m68000_base_device* mc68kcpu); +static void m68k_op_eori_8_pi(m68000_base_device* mc68kcpu); +static void m68k_op_eori_8_pi7(m68000_base_device* mc68kcpu); +static void m68k_op_eori_8_pd(m68000_base_device* mc68kcpu); +static void m68k_op_eori_8_pd7(m68000_base_device* mc68kcpu); +static void m68k_op_eori_8_di(m68000_base_device* mc68kcpu); +static void m68k_op_eori_8_ix(m68000_base_device* mc68kcpu); +static void m68k_op_eori_8_aw(m68000_base_device* mc68kcpu); +static void m68k_op_eori_8_al(m68000_base_device* mc68kcpu); +static void m68k_op_eori_16_d(m68000_base_device* mc68kcpu); +static void m68k_op_eori_16_ai(m68000_base_device* mc68kcpu); +static void m68k_op_eori_16_pi(m68000_base_device* mc68kcpu); +static void m68k_op_eori_16_pd(m68000_base_device* mc68kcpu); +static void m68k_op_eori_16_di(m68000_base_device* mc68kcpu); +static void m68k_op_eori_16_ix(m68000_base_device* mc68kcpu); +static void m68k_op_eori_16_aw(m68000_base_device* mc68kcpu); +static void m68k_op_eori_16_al(m68000_base_device* mc68kcpu); +static void m68k_op_eori_32_d(m68000_base_device* mc68kcpu); +static void m68k_op_eori_32_ai(m68000_base_device* mc68kcpu); +static void m68k_op_eori_32_pi(m68000_base_device* mc68kcpu); +static void m68k_op_eori_32_pd(m68000_base_device* mc68kcpu); +static void m68k_op_eori_32_di(m68000_base_device* mc68kcpu); +static void m68k_op_eori_32_ix(m68000_base_device* mc68kcpu); +static void m68k_op_eori_32_aw(m68000_base_device* mc68kcpu); +static void m68k_op_eori_32_al(m68000_base_device* mc68kcpu); +static void m68k_op_eori_16_toc(m68000_base_device* mc68kcpu); +static void m68k_op_eori_16_tos(m68000_base_device* mc68kcpu); +static void m68k_op_exg_32_dd(m68000_base_device* mc68kcpu); +static void m68k_op_exg_32_aa(m68000_base_device* mc68kcpu); +static void m68k_op_exg_32_da(m68000_base_device* mc68kcpu); +static void m68k_op_ext_16(m68000_base_device* mc68kcpu); +static void m68k_op_ext_32(m68000_base_device* mc68kcpu); +static void m68k_op_extb_32(m68000_base_device* mc68kcpu); +static void m68k_op_illegal(m68000_base_device* mc68kcpu); +static void m68k_op_jmp_32_ai(m68000_base_device* mc68kcpu); +static void m68k_op_jmp_32_di(m68000_base_device* mc68kcpu); +static void m68k_op_jmp_32_ix(m68000_base_device* mc68kcpu); +static void m68k_op_jmp_32_aw(m68000_base_device* mc68kcpu); +static void m68k_op_jmp_32_al(m68000_base_device* mc68kcpu); +static void m68k_op_jmp_32_pcdi(m68000_base_device* mc68kcpu); +static void m68k_op_jmp_32_pcix(m68000_base_device* mc68kcpu); +static void m68k_op_jsr_32_ai(m68000_base_device* mc68kcpu); +static void m68k_op_jsr_32_di(m68000_base_device* mc68kcpu); +static void m68k_op_jsr_32_ix(m68000_base_device* mc68kcpu); +static void m68k_op_jsr_32_aw(m68000_base_device* mc68kcpu); +static void m68k_op_jsr_32_al(m68000_base_device* mc68kcpu); +static void m68k_op_jsr_32_pcdi(m68000_base_device* mc68kcpu); +static void m68k_op_jsr_32_pcix(m68000_base_device* mc68kcpu); +static void m68k_op_lea_32_ai(m68000_base_device* mc68kcpu); +static void m68k_op_lea_32_di(m68000_base_device* mc68kcpu); +static void m68k_op_lea_32_ix(m68000_base_device* mc68kcpu); +static void m68k_op_lea_32_aw(m68000_base_device* mc68kcpu); +static void m68k_op_lea_32_al(m68000_base_device* mc68kcpu); +static void m68k_op_lea_32_pcdi(m68000_base_device* mc68kcpu); +static void m68k_op_lea_32_pcix(m68000_base_device* mc68kcpu); +static void m68k_op_link_16_a7(m68000_base_device* mc68kcpu); +static void m68k_op_link_16(m68000_base_device* mc68kcpu); +static void m68k_op_link_32_a7(m68000_base_device* mc68kcpu); +static void m68k_op_link_32(m68000_base_device* mc68kcpu); +static void m68k_op_lsr_8_s(m68000_base_device* mc68kcpu); +static void m68k_op_lsr_16_s(m68000_base_device* mc68kcpu); +static void m68k_op_lsr_32_s(m68000_base_device* mc68kcpu); +static void m68k_op_lsr_8_r(m68000_base_device* mc68kcpu); +static void m68k_op_lsr_16_r(m68000_base_device* mc68kcpu); +static void m68k_op_lsr_32_r(m68000_base_device* mc68kcpu); +static void m68k_op_lsr_16_ai(m68000_base_device* mc68kcpu); +static void m68k_op_lsr_16_pi(m68000_base_device* mc68kcpu); +static void m68k_op_lsr_16_pd(m68000_base_device* mc68kcpu); +static void m68k_op_lsr_16_di(m68000_base_device* mc68kcpu); +static void m68k_op_lsr_16_ix(m68000_base_device* mc68kcpu); +static void m68k_op_lsr_16_aw(m68000_base_device* mc68kcpu); +static void m68k_op_lsr_16_al(m68000_base_device* mc68kcpu); +static void m68k_op_lsl_8_s(m68000_base_device* mc68kcpu); +static void m68k_op_lsl_16_s(m68000_base_device* mc68kcpu); +static void m68k_op_lsl_32_s(m68000_base_device* mc68kcpu); +static void m68k_op_lsl_8_r(m68000_base_device* mc68kcpu); +static void m68k_op_lsl_16_r(m68000_base_device* mc68kcpu); +static void m68k_op_lsl_32_r(m68000_base_device* mc68kcpu); +static void m68k_op_lsl_16_ai(m68000_base_device* mc68kcpu); +static void m68k_op_lsl_16_pi(m68000_base_device* mc68kcpu); +static void m68k_op_lsl_16_pd(m68000_base_device* mc68kcpu); +static void m68k_op_lsl_16_di(m68000_base_device* mc68kcpu); +static void m68k_op_lsl_16_ix(m68000_base_device* mc68kcpu); +static void m68k_op_lsl_16_aw(m68000_base_device* mc68kcpu); +static void m68k_op_lsl_16_al(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_d_d(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_d_ai(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_d_pi(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_d_pi7(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_d_pd(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_d_pd7(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_d_di(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_d_ix(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_d_aw(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_d_al(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_d_pcdi(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_d_pcix(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_d_i(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_ai_d(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_ai_ai(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_ai_pi(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_ai_pi7(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_ai_pd(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_ai_pd7(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_ai_di(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_ai_ix(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_ai_aw(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_ai_al(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_ai_pcdi(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_ai_pcix(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_ai_i(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_pi7_d(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_pi_d(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_pi7_ai(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_pi7_pi(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_pi7_pi7(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_pi7_pd(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_pi7_pd7(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_pi7_di(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_pi7_ix(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_pi7_aw(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_pi7_al(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_pi7_pcdi(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_pi7_pcix(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_pi7_i(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_pi_ai(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_pi_pi(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_pi_pi7(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_pi_pd(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_pi_pd7(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_pi_di(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_pi_ix(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_pi_aw(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_pi_al(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_pi_pcdi(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_pi_pcix(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_pi_i(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_pd7_d(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_pd_d(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_pd7_ai(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_pd7_pi(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_pd7_pi7(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_pd7_pd(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_pd7_pd7(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_pd7_di(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_pd7_ix(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_pd7_aw(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_pd7_al(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_pd7_pcdi(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_pd7_pcix(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_pd7_i(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_pd_ai(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_pd_pi(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_pd_pi7(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_pd_pd(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_pd_pd7(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_pd_di(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_pd_ix(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_pd_aw(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_pd_al(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_pd_pcdi(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_pd_pcix(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_pd_i(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_di_d(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_di_ai(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_di_pi(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_di_pi7(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_di_pd(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_di_pd7(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_di_di(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_di_ix(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_di_aw(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_di_al(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_di_pcdi(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_di_pcix(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_di_i(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_ix_d(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_ix_ai(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_ix_pi(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_ix_pi7(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_ix_pd(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_ix_pd7(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_ix_di(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_ix_ix(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_ix_aw(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_ix_al(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_ix_pcdi(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_ix_pcix(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_ix_i(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_aw_d(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_aw_ai(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_aw_pi(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_aw_pi7(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_aw_pd(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_aw_pd7(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_aw_di(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_aw_ix(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_aw_aw(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_aw_al(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_aw_pcdi(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_aw_pcix(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_aw_i(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_al_d(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_al_ai(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_al_pi(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_al_pi7(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_al_pd(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_al_pd7(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_al_di(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_al_ix(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_al_aw(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_al_al(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_al_pcdi(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_al_pcix(m68000_base_device* mc68kcpu); +static void m68k_op_move_8_al_i(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_d_d(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_d_a(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_d_ai(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_d_pi(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_d_pd(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_d_di(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_d_ix(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_d_aw(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_d_al(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_d_pcdi(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_d_pcix(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_d_i(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_ai_d(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_ai_a(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_ai_ai(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_ai_pi(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_ai_pd(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_ai_di(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_ai_ix(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_ai_aw(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_ai_al(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_ai_pcdi(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_ai_pcix(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_ai_i(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_pi_d(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_pi_a(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_pi_ai(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_pi_pi(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_pi_pd(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_pi_di(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_pi_ix(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_pi_aw(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_pi_al(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_pi_pcdi(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_pi_pcix(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_pi_i(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_pd_d(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_pd_a(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_pd_ai(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_pd_pi(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_pd_pd(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_pd_di(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_pd_ix(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_pd_aw(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_pd_al(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_pd_pcdi(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_pd_pcix(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_pd_i(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_di_d(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_di_a(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_di_ai(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_di_pi(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_di_pd(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_di_di(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_di_ix(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_di_aw(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_di_al(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_di_pcdi(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_di_pcix(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_di_i(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_ix_d(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_ix_a(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_ix_ai(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_ix_pi(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_ix_pd(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_ix_di(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_ix_ix(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_ix_aw(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_ix_al(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_ix_pcdi(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_ix_pcix(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_ix_i(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_aw_d(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_aw_a(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_aw_ai(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_aw_pi(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_aw_pd(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_aw_di(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_aw_ix(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_aw_aw(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_aw_al(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_aw_pcdi(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_aw_pcix(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_aw_i(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_al_d(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_al_a(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_al_ai(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_al_pi(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_al_pd(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_al_di(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_al_ix(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_al_aw(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_al_al(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_al_pcdi(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_al_pcix(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_al_i(m68000_base_device* mc68kcpu); +static void m68k_op_move_32_d_d(m68000_base_device* mc68kcpu); +static void m68k_op_move_32_d_a(m68000_base_device* mc68kcpu); +static void m68k_op_move_32_d_ai(m68000_base_device* mc68kcpu); +static void m68k_op_move_32_d_pi(m68000_base_device* mc68kcpu); +static void m68k_op_move_32_d_pd(m68000_base_device* mc68kcpu); +static void m68k_op_move_32_d_di(m68000_base_device* mc68kcpu); +static void m68k_op_move_32_d_ix(m68000_base_device* mc68kcpu); +static void m68k_op_move_32_d_aw(m68000_base_device* mc68kcpu); +static void m68k_op_move_32_d_al(m68000_base_device* mc68kcpu); +static void m68k_op_move_32_d_pcdi(m68000_base_device* mc68kcpu); +static void m68k_op_move_32_d_pcix(m68000_base_device* mc68kcpu); +static void m68k_op_move_32_d_i(m68000_base_device* mc68kcpu); +static void m68k_op_move_32_ai_d(m68000_base_device* mc68kcpu); +static void m68k_op_move_32_ai_a(m68000_base_device* mc68kcpu); +static void m68k_op_move_32_ai_ai(m68000_base_device* mc68kcpu); +static void m68k_op_move_32_ai_pi(m68000_base_device* mc68kcpu); +static void m68k_op_move_32_ai_pd(m68000_base_device* mc68kcpu); +static void m68k_op_move_32_ai_di(m68000_base_device* mc68kcpu); +static void m68k_op_move_32_ai_ix(m68000_base_device* mc68kcpu); +static void m68k_op_move_32_ai_aw(m68000_base_device* mc68kcpu); +static void m68k_op_move_32_ai_al(m68000_base_device* mc68kcpu); +static void m68k_op_move_32_ai_pcdi(m68000_base_device* mc68kcpu); +static void m68k_op_move_32_ai_pcix(m68000_base_device* mc68kcpu); +static void m68k_op_move_32_ai_i(m68000_base_device* mc68kcpu); +static void m68k_op_move_32_pi_d(m68000_base_device* mc68kcpu); +static void m68k_op_move_32_pi_a(m68000_base_device* mc68kcpu); +static void m68k_op_move_32_pi_ai(m68000_base_device* mc68kcpu); +static void m68k_op_move_32_pi_pi(m68000_base_device* mc68kcpu); +static void m68k_op_move_32_pi_pd(m68000_base_device* mc68kcpu); +static void m68k_op_move_32_pi_di(m68000_base_device* mc68kcpu); +static void m68k_op_move_32_pi_ix(m68000_base_device* mc68kcpu); +static void m68k_op_move_32_pi_aw(m68000_base_device* mc68kcpu); +static void m68k_op_move_32_pi_al(m68000_base_device* mc68kcpu); +static void m68k_op_move_32_pi_pcdi(m68000_base_device* mc68kcpu); +static void m68k_op_move_32_pi_pcix(m68000_base_device* mc68kcpu); +static void m68k_op_move_32_pi_i(m68000_base_device* mc68kcpu); +static void m68k_op_move_32_pd_d(m68000_base_device* mc68kcpu); +static void m68k_op_move_32_pd_a(m68000_base_device* mc68kcpu); +static void m68k_op_move_32_pd_ai(m68000_base_device* mc68kcpu); +static void m68k_op_move_32_pd_pi(m68000_base_device* mc68kcpu); +static void m68k_op_move_32_pd_pd(m68000_base_device* mc68kcpu); +static void m68k_op_move_32_pd_di(m68000_base_device* mc68kcpu); +static void m68k_op_move_32_pd_ix(m68000_base_device* mc68kcpu); +static void m68k_op_move_32_pd_aw(m68000_base_device* mc68kcpu); +static void m68k_op_move_32_pd_al(m68000_base_device* mc68kcpu); +static void m68k_op_move_32_pd_pcdi(m68000_base_device* mc68kcpu); +static void m68k_op_move_32_pd_pcix(m68000_base_device* mc68kcpu); +static void m68k_op_move_32_pd_i(m68000_base_device* mc68kcpu); +static void m68k_op_move_32_di_d(m68000_base_device* mc68kcpu); +static void m68k_op_move_32_di_a(m68000_base_device* mc68kcpu); +static void m68k_op_move_32_di_ai(m68000_base_device* mc68kcpu); +static void m68k_op_move_32_di_pi(m68000_base_device* mc68kcpu); +static void m68k_op_move_32_di_pd(m68000_base_device* mc68kcpu); +static void m68k_op_move_32_di_di(m68000_base_device* mc68kcpu); +static void m68k_op_move_32_di_ix(m68000_base_device* mc68kcpu); +static void m68k_op_move_32_di_aw(m68000_base_device* mc68kcpu); +static void m68k_op_move_32_di_al(m68000_base_device* mc68kcpu); +static void m68k_op_move_32_di_pcdi(m68000_base_device* mc68kcpu); +static void m68k_op_move_32_di_pcix(m68000_base_device* mc68kcpu); +static void m68k_op_move_32_di_i(m68000_base_device* mc68kcpu); +static void m68k_op_move_32_ix_d(m68000_base_device* mc68kcpu); +static void m68k_op_move_32_ix_a(m68000_base_device* mc68kcpu); +static void m68k_op_move_32_ix_ai(m68000_base_device* mc68kcpu); +static void m68k_op_move_32_ix_pi(m68000_base_device* mc68kcpu); +static void m68k_op_move_32_ix_pd(m68000_base_device* mc68kcpu); +static void m68k_op_move_32_ix_di(m68000_base_device* mc68kcpu); +static void m68k_op_move_32_ix_ix(m68000_base_device* mc68kcpu); +static void m68k_op_move_32_ix_aw(m68000_base_device* mc68kcpu); +static void m68k_op_move_32_ix_al(m68000_base_device* mc68kcpu); +static void m68k_op_move_32_ix_pcdi(m68000_base_device* mc68kcpu); +static void m68k_op_move_32_ix_pcix(m68000_base_device* mc68kcpu); +static void m68k_op_move_32_ix_i(m68000_base_device* mc68kcpu); +static void m68k_op_move_32_aw_d(m68000_base_device* mc68kcpu); +static void m68k_op_move_32_aw_a(m68000_base_device* mc68kcpu); +static void m68k_op_move_32_aw_ai(m68000_base_device* mc68kcpu); +static void m68k_op_move_32_aw_pi(m68000_base_device* mc68kcpu); +static void m68k_op_move_32_aw_pd(m68000_base_device* mc68kcpu); +static void m68k_op_move_32_aw_di(m68000_base_device* mc68kcpu); +static void m68k_op_move_32_aw_ix(m68000_base_device* mc68kcpu); +static void m68k_op_move_32_aw_aw(m68000_base_device* mc68kcpu); +static void m68k_op_move_32_aw_al(m68000_base_device* mc68kcpu); +static void m68k_op_move_32_aw_pcdi(m68000_base_device* mc68kcpu); +static void m68k_op_move_32_aw_pcix(m68000_base_device* mc68kcpu); +static void m68k_op_move_32_aw_i(m68000_base_device* mc68kcpu); +static void m68k_op_move_32_al_d(m68000_base_device* mc68kcpu); +static void m68k_op_move_32_al_a(m68000_base_device* mc68kcpu); +static void m68k_op_move_32_al_ai(m68000_base_device* mc68kcpu); +static void m68k_op_move_32_al_pi(m68000_base_device* mc68kcpu); +static void m68k_op_move_32_al_pd(m68000_base_device* mc68kcpu); +static void m68k_op_move_32_al_di(m68000_base_device* mc68kcpu); +static void m68k_op_move_32_al_ix(m68000_base_device* mc68kcpu); +static void m68k_op_move_32_al_aw(m68000_base_device* mc68kcpu); +static void m68k_op_move_32_al_al(m68000_base_device* mc68kcpu); +static void m68k_op_move_32_al_pcdi(m68000_base_device* mc68kcpu); +static void m68k_op_move_32_al_pcix(m68000_base_device* mc68kcpu); +static void m68k_op_move_32_al_i(m68000_base_device* mc68kcpu); +static void m68k_op_movea_16_d(m68000_base_device* mc68kcpu); +static void m68k_op_movea_16_a(m68000_base_device* mc68kcpu); +static void m68k_op_movea_16_ai(m68000_base_device* mc68kcpu); +static void m68k_op_movea_16_pi(m68000_base_device* mc68kcpu); +static void m68k_op_movea_16_pd(m68000_base_device* mc68kcpu); +static void m68k_op_movea_16_di(m68000_base_device* mc68kcpu); +static void m68k_op_movea_16_ix(m68000_base_device* mc68kcpu); +static void m68k_op_movea_16_aw(m68000_base_device* mc68kcpu); +static void m68k_op_movea_16_al(m68000_base_device* mc68kcpu); +static void m68k_op_movea_16_pcdi(m68000_base_device* mc68kcpu); +static void m68k_op_movea_16_pcix(m68000_base_device* mc68kcpu); +static void m68k_op_movea_16_i(m68000_base_device* mc68kcpu); +static void m68k_op_movea_32_d(m68000_base_device* mc68kcpu); +static void m68k_op_movea_32_a(m68000_base_device* mc68kcpu); +static void m68k_op_movea_32_ai(m68000_base_device* mc68kcpu); +static void m68k_op_movea_32_pi(m68000_base_device* mc68kcpu); +static void m68k_op_movea_32_pd(m68000_base_device* mc68kcpu); +static void m68k_op_movea_32_di(m68000_base_device* mc68kcpu); +static void m68k_op_movea_32_ix(m68000_base_device* mc68kcpu); +static void m68k_op_movea_32_aw(m68000_base_device* mc68kcpu); +static void m68k_op_movea_32_al(m68000_base_device* mc68kcpu); +static void m68k_op_movea_32_pcdi(m68000_base_device* mc68kcpu); +static void m68k_op_movea_32_pcix(m68000_base_device* mc68kcpu); +static void m68k_op_movea_32_i(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_frc_d(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_frc_ai(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_frc_pi(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_frc_pd(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_frc_di(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_frc_ix(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_frc_aw(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_frc_al(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_toc_d(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_toc_ai(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_toc_pi(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_toc_pd(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_toc_di(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_toc_ix(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_toc_aw(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_toc_al(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_toc_pcdi(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_toc_pcix(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_toc_i(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_frs_d(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_frs_ai(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_frs_pi(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_frs_pd(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_frs_di(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_frs_ix(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_frs_aw(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_frs_al(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_tos_d(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_tos_ai(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_tos_pi(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_tos_pd(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_tos_di(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_tos_ix(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_tos_aw(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_tos_al(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_tos_pcdi(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_tos_pcix(m68000_base_device* mc68kcpu); +static void m68k_op_move_16_tos_i(m68000_base_device* mc68kcpu); +static void m68k_op_move_32_fru(m68000_base_device* mc68kcpu); +static void m68k_op_move_32_tou(m68000_base_device* mc68kcpu); +static void m68k_op_movec_32_cr(m68000_base_device* mc68kcpu); +static void m68k_op_movec_32_rc(m68000_base_device* mc68kcpu); +static void m68k_op_movem_16_re_pd(m68000_base_device* mc68kcpu); +static void m68k_op_movem_16_re_ai(m68000_base_device* mc68kcpu); +static void m68k_op_movem_16_re_di(m68000_base_device* mc68kcpu); +static void m68k_op_movem_16_re_ix(m68000_base_device* mc68kcpu); +static void m68k_op_movem_16_re_aw(m68000_base_device* mc68kcpu); +static void m68k_op_movem_16_re_al(m68000_base_device* mc68kcpu); +static void m68k_op_movem_32_re_pd(m68000_base_device* mc68kcpu); +static void m68k_op_movem_32_re_ai(m68000_base_device* mc68kcpu); +static void m68k_op_movem_32_re_di(m68000_base_device* mc68kcpu); +static void m68k_op_movem_32_re_ix(m68000_base_device* mc68kcpu); +static void m68k_op_movem_32_re_aw(m68000_base_device* mc68kcpu); +static void m68k_op_movem_32_re_al(m68000_base_device* mc68kcpu); +static void m68k_op_movem_16_er_pi(m68000_base_device* mc68kcpu); +static void m68k_op_movem_16_er_pcdi(m68000_base_device* mc68kcpu); +static void m68k_op_movem_16_er_pcix(m68000_base_device* mc68kcpu); +static void m68k_op_movem_16_er_ai(m68000_base_device* mc68kcpu); +static void m68k_op_movem_16_er_di(m68000_base_device* mc68kcpu); +static void m68k_op_movem_16_er_ix(m68000_base_device* mc68kcpu); +static void m68k_op_movem_16_er_aw(m68000_base_device* mc68kcpu); +static void m68k_op_movem_16_er_al(m68000_base_device* mc68kcpu); +static void m68k_op_movem_32_er_pi(m68000_base_device* mc68kcpu); +static void m68k_op_movem_32_er_pcdi(m68000_base_device* mc68kcpu); +static void m68k_op_movem_32_er_pcix(m68000_base_device* mc68kcpu); +static void m68k_op_movem_32_er_ai(m68000_base_device* mc68kcpu); +static void m68k_op_movem_32_er_di(m68000_base_device* mc68kcpu); +static void m68k_op_movem_32_er_ix(m68000_base_device* mc68kcpu); +static void m68k_op_movem_32_er_aw(m68000_base_device* mc68kcpu); +static void m68k_op_movem_32_er_al(m68000_base_device* mc68kcpu); +static void m68k_op_movep_16_re(m68000_base_device* mc68kcpu); +static void m68k_op_movep_32_re(m68000_base_device* mc68kcpu); +static void m68k_op_movep_16_er(m68000_base_device* mc68kcpu); +static void m68k_op_movep_32_er(m68000_base_device* mc68kcpu); +static void m68k_op_moves_8_ai(m68000_base_device* mc68kcpu); +static void m68k_op_moves_8_pi(m68000_base_device* mc68kcpu); +static void m68k_op_moves_8_pi7(m68000_base_device* mc68kcpu); +static void m68k_op_moves_8_pd(m68000_base_device* mc68kcpu); +static void m68k_op_moves_8_pd7(m68000_base_device* mc68kcpu); +static void m68k_op_moves_8_di(m68000_base_device* mc68kcpu); +static void m68k_op_moves_8_ix(m68000_base_device* mc68kcpu); +static void m68k_op_moves_8_aw(m68000_base_device* mc68kcpu); +static void m68k_op_moves_8_al(m68000_base_device* mc68kcpu); +static void m68k_op_moves_16_ai(m68000_base_device* mc68kcpu); +static void m68k_op_moves_16_pi(m68000_base_device* mc68kcpu); +static void m68k_op_moves_16_pd(m68000_base_device* mc68kcpu); +static void m68k_op_moves_16_di(m68000_base_device* mc68kcpu); +static void m68k_op_moves_16_ix(m68000_base_device* mc68kcpu); +static void m68k_op_moves_16_aw(m68000_base_device* mc68kcpu); +static void m68k_op_moves_16_al(m68000_base_device* mc68kcpu); +static void m68k_op_moves_32_ai(m68000_base_device* mc68kcpu); +static void m68k_op_moves_32_pi(m68000_base_device* mc68kcpu); +static void m68k_op_moves_32_pd(m68000_base_device* mc68kcpu); +static void m68k_op_moves_32_di(m68000_base_device* mc68kcpu); +static void m68k_op_moves_32_ix(m68000_base_device* mc68kcpu); +static void m68k_op_moves_32_aw(m68000_base_device* mc68kcpu); +static void m68k_op_moves_32_al(m68000_base_device* mc68kcpu); +static void m68k_op_moveq_32(m68000_base_device* mc68kcpu); +static void m68k_op_move16_32(m68000_base_device* mc68kcpu); +static void m68k_op_muls_16_d(m68000_base_device* mc68kcpu); +static void m68k_op_muls_16_ai(m68000_base_device* mc68kcpu); +static void m68k_op_muls_16_pi(m68000_base_device* mc68kcpu); +static void m68k_op_muls_16_pd(m68000_base_device* mc68kcpu); +static void m68k_op_muls_16_di(m68000_base_device* mc68kcpu); +static void m68k_op_muls_16_ix(m68000_base_device* mc68kcpu); +static void m68k_op_muls_16_aw(m68000_base_device* mc68kcpu); +static void m68k_op_muls_16_al(m68000_base_device* mc68kcpu); +static void m68k_op_muls_16_pcdi(m68000_base_device* mc68kcpu); +static void m68k_op_muls_16_pcix(m68000_base_device* mc68kcpu); +static void m68k_op_muls_16_i(m68000_base_device* mc68kcpu); +static void m68k_op_mulu_16_d(m68000_base_device* mc68kcpu); +static void m68k_op_mulu_16_ai(m68000_base_device* mc68kcpu); +static void m68k_op_mulu_16_pi(m68000_base_device* mc68kcpu); +static void m68k_op_mulu_16_pd(m68000_base_device* mc68kcpu); +static void m68k_op_mulu_16_di(m68000_base_device* mc68kcpu); +static void m68k_op_mulu_16_ix(m68000_base_device* mc68kcpu); +static void m68k_op_mulu_16_aw(m68000_base_device* mc68kcpu); +static void m68k_op_mulu_16_al(m68000_base_device* mc68kcpu); +static void m68k_op_mulu_16_pcdi(m68000_base_device* mc68kcpu); +static void m68k_op_mulu_16_pcix(m68000_base_device* mc68kcpu); +static void m68k_op_mulu_16_i(m68000_base_device* mc68kcpu); +static void m68k_op_mull_32_d(m68000_base_device* mc68kcpu); +static void m68k_op_mull_32_ai(m68000_base_device* mc68kcpu); +static void m68k_op_mull_32_pi(m68000_base_device* mc68kcpu); +static void m68k_op_mull_32_pd(m68000_base_device* mc68kcpu); +static void m68k_op_mull_32_di(m68000_base_device* mc68kcpu); +static void m68k_op_mull_32_ix(m68000_base_device* mc68kcpu); +static void m68k_op_mull_32_aw(m68000_base_device* mc68kcpu); +static void m68k_op_mull_32_al(m68000_base_device* mc68kcpu); +static void m68k_op_mull_32_pcdi(m68000_base_device* mc68kcpu); +static void m68k_op_mull_32_pcix(m68000_base_device* mc68kcpu); +static void m68k_op_mull_32_i(m68000_base_device* mc68kcpu); +static void m68k_op_nbcd_8_d(m68000_base_device* mc68kcpu); +static void m68k_op_nbcd_8_ai(m68000_base_device* mc68kcpu); +static void m68k_op_nbcd_8_pi(m68000_base_device* mc68kcpu); +static void m68k_op_nbcd_8_pi7(m68000_base_device* mc68kcpu); +static void m68k_op_nbcd_8_pd(m68000_base_device* mc68kcpu); +static void m68k_op_nbcd_8_pd7(m68000_base_device* mc68kcpu); +static void m68k_op_nbcd_8_di(m68000_base_device* mc68kcpu); +static void m68k_op_nbcd_8_ix(m68000_base_device* mc68kcpu); +static void m68k_op_nbcd_8_aw(m68000_base_device* mc68kcpu); +static void m68k_op_nbcd_8_al(m68000_base_device* mc68kcpu); +static void m68k_op_neg_8_d(m68000_base_device* mc68kcpu); +static void m68k_op_neg_8_ai(m68000_base_device* mc68kcpu); +static void m68k_op_neg_8_pi(m68000_base_device* mc68kcpu); +static void m68k_op_neg_8_pi7(m68000_base_device* mc68kcpu); +static void m68k_op_neg_8_pd(m68000_base_device* mc68kcpu); +static void m68k_op_neg_8_pd7(m68000_base_device* mc68kcpu); +static void m68k_op_neg_8_di(m68000_base_device* mc68kcpu); +static void m68k_op_neg_8_ix(m68000_base_device* mc68kcpu); +static void m68k_op_neg_8_aw(m68000_base_device* mc68kcpu); +static void m68k_op_neg_8_al(m68000_base_device* mc68kcpu); +static void m68k_op_neg_16_d(m68000_base_device* mc68kcpu); +static void m68k_op_neg_16_ai(m68000_base_device* mc68kcpu); +static void m68k_op_neg_16_pi(m68000_base_device* mc68kcpu); +static void m68k_op_neg_16_pd(m68000_base_device* mc68kcpu); +static void m68k_op_neg_16_di(m68000_base_device* mc68kcpu); +static void m68k_op_neg_16_ix(m68000_base_device* mc68kcpu); +static void m68k_op_neg_16_aw(m68000_base_device* mc68kcpu); +static void m68k_op_neg_16_al(m68000_base_device* mc68kcpu); +static void m68k_op_neg_32_d(m68000_base_device* mc68kcpu); +static void m68k_op_neg_32_ai(m68000_base_device* mc68kcpu); +static void m68k_op_neg_32_pi(m68000_base_device* mc68kcpu); +static void m68k_op_neg_32_pd(m68000_base_device* mc68kcpu); +static void m68k_op_neg_32_di(m68000_base_device* mc68kcpu); +static void m68k_op_neg_32_ix(m68000_base_device* mc68kcpu); +static void m68k_op_neg_32_aw(m68000_base_device* mc68kcpu); +static void m68k_op_neg_32_al(m68000_base_device* mc68kcpu); +static void m68k_op_negx_8_d(m68000_base_device* mc68kcpu); +static void m68k_op_negx_8_ai(m68000_base_device* mc68kcpu); +static void m68k_op_negx_8_pi(m68000_base_device* mc68kcpu); +static void m68k_op_negx_8_pi7(m68000_base_device* mc68kcpu); +static void m68k_op_negx_8_pd(m68000_base_device* mc68kcpu); +static void m68k_op_negx_8_pd7(m68000_base_device* mc68kcpu); +static void m68k_op_negx_8_di(m68000_base_device* mc68kcpu); +static void m68k_op_negx_8_ix(m68000_base_device* mc68kcpu); +static void m68k_op_negx_8_aw(m68000_base_device* mc68kcpu); +static void m68k_op_negx_8_al(m68000_base_device* mc68kcpu); +static void m68k_op_negx_16_d(m68000_base_device* mc68kcpu); +static void m68k_op_negx_16_ai(m68000_base_device* mc68kcpu); +static void m68k_op_negx_16_pi(m68000_base_device* mc68kcpu); +static void m68k_op_negx_16_pd(m68000_base_device* mc68kcpu); +static void m68k_op_negx_16_di(m68000_base_device* mc68kcpu); +static void m68k_op_negx_16_ix(m68000_base_device* mc68kcpu); +static void m68k_op_negx_16_aw(m68000_base_device* mc68kcpu); +static void m68k_op_negx_16_al(m68000_base_device* mc68kcpu); +static void m68k_op_negx_32_d(m68000_base_device* mc68kcpu); +static void m68k_op_negx_32_ai(m68000_base_device* mc68kcpu); +static void m68k_op_negx_32_pi(m68000_base_device* mc68kcpu); +static void m68k_op_negx_32_pd(m68000_base_device* mc68kcpu); +static void m68k_op_negx_32_di(m68000_base_device* mc68kcpu); +static void m68k_op_negx_32_ix(m68000_base_device* mc68kcpu); +static void m68k_op_negx_32_aw(m68000_base_device* mc68kcpu); +static void m68k_op_negx_32_al(m68000_base_device* mc68kcpu); +static void m68k_op_nop(m68000_base_device* mc68kcpu); +static void m68k_op_not_8_d(m68000_base_device* mc68kcpu); +static void m68k_op_not_8_ai(m68000_base_device* mc68kcpu); +static void m68k_op_not_8_pi(m68000_base_device* mc68kcpu); +static void m68k_op_not_8_pi7(m68000_base_device* mc68kcpu); +static void m68k_op_not_8_pd(m68000_base_device* mc68kcpu); +static void m68k_op_not_8_pd7(m68000_base_device* mc68kcpu); +static void m68k_op_not_8_di(m68000_base_device* mc68kcpu); +static void m68k_op_not_8_ix(m68000_base_device* mc68kcpu); +static void m68k_op_not_8_aw(m68000_base_device* mc68kcpu); +static void m68k_op_not_8_al(m68000_base_device* mc68kcpu); +static void m68k_op_not_16_d(m68000_base_device* mc68kcpu); +static void m68k_op_not_16_ai(m68000_base_device* mc68kcpu); +static void m68k_op_not_16_pi(m68000_base_device* mc68kcpu); +static void m68k_op_not_16_pd(m68000_base_device* mc68kcpu); +static void m68k_op_not_16_di(m68000_base_device* mc68kcpu); +static void m68k_op_not_16_ix(m68000_base_device* mc68kcpu); +static void m68k_op_not_16_aw(m68000_base_device* mc68kcpu); +static void m68k_op_not_16_al(m68000_base_device* mc68kcpu); +static void m68k_op_not_32_d(m68000_base_device* mc68kcpu); +static void m68k_op_not_32_ai(m68000_base_device* mc68kcpu); +static void m68k_op_not_32_pi(m68000_base_device* mc68kcpu); +static void m68k_op_not_32_pd(m68000_base_device* mc68kcpu); +static void m68k_op_not_32_di(m68000_base_device* mc68kcpu); +static void m68k_op_not_32_ix(m68000_base_device* mc68kcpu); +static void m68k_op_not_32_aw(m68000_base_device* mc68kcpu); +static void m68k_op_not_32_al(m68000_base_device* mc68kcpu); +static void m68k_op_or_8_er_d(m68000_base_device* mc68kcpu); +static void m68k_op_or_8_er_ai(m68000_base_device* mc68kcpu); +static void m68k_op_or_8_er_pi(m68000_base_device* mc68kcpu); +static void m68k_op_or_8_er_pi7(m68000_base_device* mc68kcpu); +static void m68k_op_or_8_er_pd(m68000_base_device* mc68kcpu); +static void m68k_op_or_8_er_pd7(m68000_base_device* mc68kcpu); +static void m68k_op_or_8_er_di(m68000_base_device* mc68kcpu); +static void m68k_op_or_8_er_ix(m68000_base_device* mc68kcpu); +static void m68k_op_or_8_er_aw(m68000_base_device* mc68kcpu); +static void m68k_op_or_8_er_al(m68000_base_device* mc68kcpu); +static void m68k_op_or_8_er_pcdi(m68000_base_device* mc68kcpu); +static void m68k_op_or_8_er_pcix(m68000_base_device* mc68kcpu); +static void m68k_op_or_8_er_i(m68000_base_device* mc68kcpu); +static void m68k_op_or_16_er_d(m68000_base_device* mc68kcpu); +static void m68k_op_or_16_er_ai(m68000_base_device* mc68kcpu); +static void m68k_op_or_16_er_pi(m68000_base_device* mc68kcpu); +static void m68k_op_or_16_er_pd(m68000_base_device* mc68kcpu); +static void m68k_op_or_16_er_di(m68000_base_device* mc68kcpu); +static void m68k_op_or_16_er_ix(m68000_base_device* mc68kcpu); +static void m68k_op_or_16_er_aw(m68000_base_device* mc68kcpu); +static void m68k_op_or_16_er_al(m68000_base_device* mc68kcpu); +static void m68k_op_or_16_er_pcdi(m68000_base_device* mc68kcpu); +static void m68k_op_or_16_er_pcix(m68000_base_device* mc68kcpu); +static void m68k_op_or_16_er_i(m68000_base_device* mc68kcpu); +static void m68k_op_or_32_er_d(m68000_base_device* mc68kcpu); +static void m68k_op_or_32_er_ai(m68000_base_device* mc68kcpu); +static void m68k_op_or_32_er_pi(m68000_base_device* mc68kcpu); +static void m68k_op_or_32_er_pd(m68000_base_device* mc68kcpu); +static void m68k_op_or_32_er_di(m68000_base_device* mc68kcpu); +static void m68k_op_or_32_er_ix(m68000_base_device* mc68kcpu); +static void m68k_op_or_32_er_aw(m68000_base_device* mc68kcpu); +static void m68k_op_or_32_er_al(m68000_base_device* mc68kcpu); +static void m68k_op_or_32_er_pcdi(m68000_base_device* mc68kcpu); +static void m68k_op_or_32_er_pcix(m68000_base_device* mc68kcpu); +static void m68k_op_or_32_er_i(m68000_base_device* mc68kcpu); +static void m68k_op_or_8_re_ai(m68000_base_device* mc68kcpu); +static void m68k_op_or_8_re_pi(m68000_base_device* mc68kcpu); +static void m68k_op_or_8_re_pi7(m68000_base_device* mc68kcpu); +static void m68k_op_or_8_re_pd(m68000_base_device* mc68kcpu); +static void m68k_op_or_8_re_pd7(m68000_base_device* mc68kcpu); +static void m68k_op_or_8_re_di(m68000_base_device* mc68kcpu); +static void m68k_op_or_8_re_ix(m68000_base_device* mc68kcpu); +static void m68k_op_or_8_re_aw(m68000_base_device* mc68kcpu); +static void m68k_op_or_8_re_al(m68000_base_device* mc68kcpu); +static void m68k_op_or_16_re_ai(m68000_base_device* mc68kcpu); +static void m68k_op_or_16_re_pi(m68000_base_device* mc68kcpu); +static void m68k_op_or_16_re_pd(m68000_base_device* mc68kcpu); +static void m68k_op_or_16_re_di(m68000_base_device* mc68kcpu); +static void m68k_op_or_16_re_ix(m68000_base_device* mc68kcpu); +static void m68k_op_or_16_re_aw(m68000_base_device* mc68kcpu); +static void m68k_op_or_16_re_al(m68000_base_device* mc68kcpu); +static void m68k_op_or_32_re_ai(m68000_base_device* mc68kcpu); +static void m68k_op_or_32_re_pi(m68000_base_device* mc68kcpu); +static void m68k_op_or_32_re_pd(m68000_base_device* mc68kcpu); +static void m68k_op_or_32_re_di(m68000_base_device* mc68kcpu); +static void m68k_op_or_32_re_ix(m68000_base_device* mc68kcpu); +static void m68k_op_or_32_re_aw(m68000_base_device* mc68kcpu); +static void m68k_op_or_32_re_al(m68000_base_device* mc68kcpu); +static void m68k_op_ori_8_d(m68000_base_device* mc68kcpu); +static void m68k_op_ori_8_ai(m68000_base_device* mc68kcpu); +static void m68k_op_ori_8_pi(m68000_base_device* mc68kcpu); +static void m68k_op_ori_8_pi7(m68000_base_device* mc68kcpu); +static void m68k_op_ori_8_pd(m68000_base_device* mc68kcpu); +static void m68k_op_ori_8_pd7(m68000_base_device* mc68kcpu); +static void m68k_op_ori_8_di(m68000_base_device* mc68kcpu); +static void m68k_op_ori_8_ix(m68000_base_device* mc68kcpu); +static void m68k_op_ori_8_aw(m68000_base_device* mc68kcpu); +static void m68k_op_ori_8_al(m68000_base_device* mc68kcpu); +static void m68k_op_ori_16_d(m68000_base_device* mc68kcpu); +static void m68k_op_ori_16_ai(m68000_base_device* mc68kcpu); +static void m68k_op_ori_16_pi(m68000_base_device* mc68kcpu); +static void m68k_op_ori_16_pd(m68000_base_device* mc68kcpu); +static void m68k_op_ori_16_di(m68000_base_device* mc68kcpu); +static void m68k_op_ori_16_ix(m68000_base_device* mc68kcpu); +static void m68k_op_ori_16_aw(m68000_base_device* mc68kcpu); +static void m68k_op_ori_16_al(m68000_base_device* mc68kcpu); +static void m68k_op_ori_32_d(m68000_base_device* mc68kcpu); +static void m68k_op_ori_32_ai(m68000_base_device* mc68kcpu); +static void m68k_op_ori_32_pi(m68000_base_device* mc68kcpu); +static void m68k_op_ori_32_pd(m68000_base_device* mc68kcpu); +static void m68k_op_ori_32_di(m68000_base_device* mc68kcpu); +static void m68k_op_ori_32_ix(m68000_base_device* mc68kcpu); +static void m68k_op_ori_32_aw(m68000_base_device* mc68kcpu); +static void m68k_op_ori_32_al(m68000_base_device* mc68kcpu); +static void m68k_op_ori_16_toc(m68000_base_device* mc68kcpu); +static void m68k_op_ori_16_tos(m68000_base_device* mc68kcpu); +static void m68k_op_pack_16_rr(m68000_base_device* mc68kcpu); +static void m68k_op_pack_16_mm_ax7(m68000_base_device* mc68kcpu); +static void m68k_op_pack_16_mm_ay7(m68000_base_device* mc68kcpu); +static void m68k_op_pack_16_mm_axy7(m68000_base_device* mc68kcpu); +static void m68k_op_pack_16_mm(m68000_base_device* mc68kcpu); +static void m68k_op_pea_32_ai(m68000_base_device* mc68kcpu); +static void m68k_op_pea_32_di(m68000_base_device* mc68kcpu); +static void m68k_op_pea_32_ix(m68000_base_device* mc68kcpu); +static void m68k_op_pea_32_aw(m68000_base_device* mc68kcpu); +static void m68k_op_pea_32_al(m68000_base_device* mc68kcpu); +static void m68k_op_pea_32_pcdi(m68000_base_device* mc68kcpu); +static void m68k_op_pea_32_pcix(m68000_base_device* mc68kcpu); +static void m68k_op_pflusha_32(m68000_base_device* mc68kcpu); +static void m68k_op_pflushan_32(m68000_base_device* mc68kcpu); +static void m68k_op_pmmu_32(m68000_base_device* mc68kcpu); +static void m68k_op_ptest_32(m68000_base_device* mc68kcpu); +static void m68k_op_reset(m68000_base_device* mc68kcpu); +static void m68k_op_ror_8_s(m68000_base_device* mc68kcpu); +static void m68k_op_ror_16_s(m68000_base_device* mc68kcpu); +static void m68k_op_ror_32_s(m68000_base_device* mc68kcpu); +static void m68k_op_ror_8_r(m68000_base_device* mc68kcpu); +static void m68k_op_ror_16_r(m68000_base_device* mc68kcpu); +static void m68k_op_ror_32_r(m68000_base_device* mc68kcpu); +static void m68k_op_ror_16_ai(m68000_base_device* mc68kcpu); +static void m68k_op_ror_16_pi(m68000_base_device* mc68kcpu); +static void m68k_op_ror_16_pd(m68000_base_device* mc68kcpu); +static void m68k_op_ror_16_di(m68000_base_device* mc68kcpu); +static void m68k_op_ror_16_ix(m68000_base_device* mc68kcpu); +static void m68k_op_ror_16_aw(m68000_base_device* mc68kcpu); +static void m68k_op_ror_16_al(m68000_base_device* mc68kcpu); +static void m68k_op_rol_8_s(m68000_base_device* mc68kcpu); +static void m68k_op_rol_16_s(m68000_base_device* mc68kcpu); +static void m68k_op_rol_32_s(m68000_base_device* mc68kcpu); +static void m68k_op_rol_8_r(m68000_base_device* mc68kcpu); +static void m68k_op_rol_16_r(m68000_base_device* mc68kcpu); +static void m68k_op_rol_32_r(m68000_base_device* mc68kcpu); +static void m68k_op_rol_16_ai(m68000_base_device* mc68kcpu); +static void m68k_op_rol_16_pi(m68000_base_device* mc68kcpu); +static void m68k_op_rol_16_pd(m68000_base_device* mc68kcpu); +static void m68k_op_rol_16_di(m68000_base_device* mc68kcpu); +static void m68k_op_rol_16_ix(m68000_base_device* mc68kcpu); +static void m68k_op_rol_16_aw(m68000_base_device* mc68kcpu); +static void m68k_op_rol_16_al(m68000_base_device* mc68kcpu); +static void m68k_op_roxr_8_s(m68000_base_device* mc68kcpu); +static void m68k_op_roxr_16_s(m68000_base_device* mc68kcpu); +static void m68k_op_roxr_32_s(m68000_base_device* mc68kcpu); +static void m68k_op_roxr_8_r(m68000_base_device* mc68kcpu); +static void m68k_op_roxr_16_r(m68000_base_device* mc68kcpu); +static void m68k_op_roxr_32_r(m68000_base_device* mc68kcpu); +static void m68k_op_roxr_16_ai(m68000_base_device* mc68kcpu); +static void m68k_op_roxr_16_pi(m68000_base_device* mc68kcpu); +static void m68k_op_roxr_16_pd(m68000_base_device* mc68kcpu); +static void m68k_op_roxr_16_di(m68000_base_device* mc68kcpu); +static void m68k_op_roxr_16_ix(m68000_base_device* mc68kcpu); +static void m68k_op_roxr_16_aw(m68000_base_device* mc68kcpu); +static void m68k_op_roxr_16_al(m68000_base_device* mc68kcpu); +static void m68k_op_roxl_8_s(m68000_base_device* mc68kcpu); +static void m68k_op_roxl_16_s(m68000_base_device* mc68kcpu); +static void m68k_op_roxl_32_s(m68000_base_device* mc68kcpu); +static void m68k_op_roxl_8_r(m68000_base_device* mc68kcpu); +static void m68k_op_roxl_16_r(m68000_base_device* mc68kcpu); +static void m68k_op_roxl_32_r(m68000_base_device* mc68kcpu); +static void m68k_op_roxl_16_ai(m68000_base_device* mc68kcpu); +static void m68k_op_roxl_16_pi(m68000_base_device* mc68kcpu); +static void m68k_op_roxl_16_pd(m68000_base_device* mc68kcpu); +static void m68k_op_roxl_16_di(m68000_base_device* mc68kcpu); +static void m68k_op_roxl_16_ix(m68000_base_device* mc68kcpu); +static void m68k_op_roxl_16_aw(m68000_base_device* mc68kcpu); +static void m68k_op_roxl_16_al(m68000_base_device* mc68kcpu); +static void m68k_op_rtd_32(m68000_base_device* mc68kcpu); +static void m68k_op_rte_32(m68000_base_device* mc68kcpu); +static void m68k_op_rtm_32(m68000_base_device* mc68kcpu); +static void m68k_op_rtr_32(m68000_base_device* mc68kcpu); +static void m68k_op_rts_32(m68000_base_device* mc68kcpu); +static void m68k_op_sbcd_8_rr(m68000_base_device* mc68kcpu); +static void m68k_op_sbcd_8_mm_ax7(m68000_base_device* mc68kcpu); +static void m68k_op_sbcd_8_mm_ay7(m68000_base_device* mc68kcpu); +static void m68k_op_sbcd_8_mm_axy7(m68000_base_device* mc68kcpu); +static void m68k_op_sbcd_8_mm(m68000_base_device* mc68kcpu); +static void m68k_op_st_8_d(m68000_base_device* mc68kcpu); +static void m68k_op_st_8_ai(m68000_base_device* mc68kcpu); +static void m68k_op_st_8_pi(m68000_base_device* mc68kcpu); +static void m68k_op_st_8_pi7(m68000_base_device* mc68kcpu); +static void m68k_op_st_8_pd(m68000_base_device* mc68kcpu); +static void m68k_op_st_8_pd7(m68000_base_device* mc68kcpu); +static void m68k_op_st_8_di(m68000_base_device* mc68kcpu); +static void m68k_op_st_8_ix(m68000_base_device* mc68kcpu); +static void m68k_op_st_8_aw(m68000_base_device* mc68kcpu); +static void m68k_op_st_8_al(m68000_base_device* mc68kcpu); +static void m68k_op_sf_8_d(m68000_base_device* mc68kcpu); +static void m68k_op_sf_8_ai(m68000_base_device* mc68kcpu); +static void m68k_op_sf_8_pi(m68000_base_device* mc68kcpu); +static void m68k_op_sf_8_pi7(m68000_base_device* mc68kcpu); +static void m68k_op_sf_8_pd(m68000_base_device* mc68kcpu); +static void m68k_op_sf_8_pd7(m68000_base_device* mc68kcpu); +static void m68k_op_sf_8_di(m68000_base_device* mc68kcpu); +static void m68k_op_sf_8_ix(m68000_base_device* mc68kcpu); +static void m68k_op_sf_8_aw(m68000_base_device* mc68kcpu); +static void m68k_op_sf_8_al(m68000_base_device* mc68kcpu); +static void m68k_op_shi_8_d(m68000_base_device* mc68kcpu); +static void m68k_op_sls_8_d(m68000_base_device* mc68kcpu); +static void m68k_op_scc_8_d(m68000_base_device* mc68kcpu); +static void m68k_op_scs_8_d(m68000_base_device* mc68kcpu); +static void m68k_op_sne_8_d(m68000_base_device* mc68kcpu); +static void m68k_op_seq_8_d(m68000_base_device* mc68kcpu); +static void m68k_op_svc_8_d(m68000_base_device* mc68kcpu); +static void m68k_op_svs_8_d(m68000_base_device* mc68kcpu); +static void m68k_op_spl_8_d(m68000_base_device* mc68kcpu); +static void m68k_op_smi_8_d(m68000_base_device* mc68kcpu); +static void m68k_op_sge_8_d(m68000_base_device* mc68kcpu); +static void m68k_op_slt_8_d(m68000_base_device* mc68kcpu); +static void m68k_op_sgt_8_d(m68000_base_device* mc68kcpu); +static void m68k_op_sle_8_d(m68000_base_device* mc68kcpu); +static void m68k_op_shi_8_ai(m68000_base_device* mc68kcpu); +static void m68k_op_shi_8_pi(m68000_base_device* mc68kcpu); +static void m68k_op_shi_8_pi7(m68000_base_device* mc68kcpu); +static void m68k_op_shi_8_pd(m68000_base_device* mc68kcpu); +static void m68k_op_shi_8_pd7(m68000_base_device* mc68kcpu); +static void m68k_op_shi_8_di(m68000_base_device* mc68kcpu); +static void m68k_op_shi_8_ix(m68000_base_device* mc68kcpu); +static void m68k_op_shi_8_aw(m68000_base_device* mc68kcpu); +static void m68k_op_shi_8_al(m68000_base_device* mc68kcpu); +static void m68k_op_sls_8_ai(m68000_base_device* mc68kcpu); +static void m68k_op_sls_8_pi(m68000_base_device* mc68kcpu); +static void m68k_op_sls_8_pi7(m68000_base_device* mc68kcpu); +static void m68k_op_sls_8_pd(m68000_base_device* mc68kcpu); +static void m68k_op_sls_8_pd7(m68000_base_device* mc68kcpu); +static void m68k_op_sls_8_di(m68000_base_device* mc68kcpu); +static void m68k_op_sls_8_ix(m68000_base_device* mc68kcpu); +static void m68k_op_sls_8_aw(m68000_base_device* mc68kcpu); +static void m68k_op_sls_8_al(m68000_base_device* mc68kcpu); +static void m68k_op_scc_8_ai(m68000_base_device* mc68kcpu); +static void m68k_op_scc_8_pi(m68000_base_device* mc68kcpu); +static void m68k_op_scc_8_pi7(m68000_base_device* mc68kcpu); +static void m68k_op_scc_8_pd(m68000_base_device* mc68kcpu); +static void m68k_op_scc_8_pd7(m68000_base_device* mc68kcpu); +static void m68k_op_scc_8_di(m68000_base_device* mc68kcpu); +static void m68k_op_scc_8_ix(m68000_base_device* mc68kcpu); +static void m68k_op_scc_8_aw(m68000_base_device* mc68kcpu); +static void m68k_op_scc_8_al(m68000_base_device* mc68kcpu); +static void m68k_op_scs_8_ai(m68000_base_device* mc68kcpu); +static void m68k_op_scs_8_pi(m68000_base_device* mc68kcpu); +static void m68k_op_scs_8_pi7(m68000_base_device* mc68kcpu); +static void m68k_op_scs_8_pd(m68000_base_device* mc68kcpu); +static void m68k_op_scs_8_pd7(m68000_base_device* mc68kcpu); +static void m68k_op_scs_8_di(m68000_base_device* mc68kcpu); +static void m68k_op_scs_8_ix(m68000_base_device* mc68kcpu); +static void m68k_op_scs_8_aw(m68000_base_device* mc68kcpu); +static void m68k_op_scs_8_al(m68000_base_device* mc68kcpu); +static void m68k_op_sne_8_ai(m68000_base_device* mc68kcpu); +static void m68k_op_sne_8_pi(m68000_base_device* mc68kcpu); +static void m68k_op_sne_8_pi7(m68000_base_device* mc68kcpu); +static void m68k_op_sne_8_pd(m68000_base_device* mc68kcpu); +static void m68k_op_sne_8_pd7(m68000_base_device* mc68kcpu); +static void m68k_op_sne_8_di(m68000_base_device* mc68kcpu); +static void m68k_op_sne_8_ix(m68000_base_device* mc68kcpu); +static void m68k_op_sne_8_aw(m68000_base_device* mc68kcpu); +static void m68k_op_sne_8_al(m68000_base_device* mc68kcpu); +static void m68k_op_seq_8_ai(m68000_base_device* mc68kcpu); +static void m68k_op_seq_8_pi(m68000_base_device* mc68kcpu); +static void m68k_op_seq_8_pi7(m68000_base_device* mc68kcpu); +static void m68k_op_seq_8_pd(m68000_base_device* mc68kcpu); +static void m68k_op_seq_8_pd7(m68000_base_device* mc68kcpu); +static void m68k_op_seq_8_di(m68000_base_device* mc68kcpu); +static void m68k_op_seq_8_ix(m68000_base_device* mc68kcpu); +static void m68k_op_seq_8_aw(m68000_base_device* mc68kcpu); +static void m68k_op_seq_8_al(m68000_base_device* mc68kcpu); +static void m68k_op_svc_8_ai(m68000_base_device* mc68kcpu); +static void m68k_op_svc_8_pi(m68000_base_device* mc68kcpu); +static void m68k_op_svc_8_pi7(m68000_base_device* mc68kcpu); +static void m68k_op_svc_8_pd(m68000_base_device* mc68kcpu); +static void m68k_op_svc_8_pd7(m68000_base_device* mc68kcpu); +static void m68k_op_svc_8_di(m68000_base_device* mc68kcpu); +static void m68k_op_svc_8_ix(m68000_base_device* mc68kcpu); +static void m68k_op_svc_8_aw(m68000_base_device* mc68kcpu); +static void m68k_op_svc_8_al(m68000_base_device* mc68kcpu); +static void m68k_op_svs_8_ai(m68000_base_device* mc68kcpu); +static void m68k_op_svs_8_pi(m68000_base_device* mc68kcpu); +static void m68k_op_svs_8_pi7(m68000_base_device* mc68kcpu); +static void m68k_op_svs_8_pd(m68000_base_device* mc68kcpu); +static void m68k_op_svs_8_pd7(m68000_base_device* mc68kcpu); +static void m68k_op_svs_8_di(m68000_base_device* mc68kcpu); +static void m68k_op_svs_8_ix(m68000_base_device* mc68kcpu); +static void m68k_op_svs_8_aw(m68000_base_device* mc68kcpu); +static void m68k_op_svs_8_al(m68000_base_device* mc68kcpu); +static void m68k_op_spl_8_ai(m68000_base_device* mc68kcpu); +static void m68k_op_spl_8_pi(m68000_base_device* mc68kcpu); +static void m68k_op_spl_8_pi7(m68000_base_device* mc68kcpu); +static void m68k_op_spl_8_pd(m68000_base_device* mc68kcpu); +static void m68k_op_spl_8_pd7(m68000_base_device* mc68kcpu); +static void m68k_op_spl_8_di(m68000_base_device* mc68kcpu); +static void m68k_op_spl_8_ix(m68000_base_device* mc68kcpu); +static void m68k_op_spl_8_aw(m68000_base_device* mc68kcpu); +static void m68k_op_spl_8_al(m68000_base_device* mc68kcpu); +static void m68k_op_smi_8_ai(m68000_base_device* mc68kcpu); +static void m68k_op_smi_8_pi(m68000_base_device* mc68kcpu); +static void m68k_op_smi_8_pi7(m68000_base_device* mc68kcpu); +static void m68k_op_smi_8_pd(m68000_base_device* mc68kcpu); +static void m68k_op_smi_8_pd7(m68000_base_device* mc68kcpu); +static void m68k_op_smi_8_di(m68000_base_device* mc68kcpu); +static void m68k_op_smi_8_ix(m68000_base_device* mc68kcpu); +static void m68k_op_smi_8_aw(m68000_base_device* mc68kcpu); +static void m68k_op_smi_8_al(m68000_base_device* mc68kcpu); +static void m68k_op_sge_8_ai(m68000_base_device* mc68kcpu); +static void m68k_op_sge_8_pi(m68000_base_device* mc68kcpu); +static void m68k_op_sge_8_pi7(m68000_base_device* mc68kcpu); +static void m68k_op_sge_8_pd(m68000_base_device* mc68kcpu); +static void m68k_op_sge_8_pd7(m68000_base_device* mc68kcpu); +static void m68k_op_sge_8_di(m68000_base_device* mc68kcpu); +static void m68k_op_sge_8_ix(m68000_base_device* mc68kcpu); +static void m68k_op_sge_8_aw(m68000_base_device* mc68kcpu); +static void m68k_op_sge_8_al(m68000_base_device* mc68kcpu); +static void m68k_op_slt_8_ai(m68000_base_device* mc68kcpu); +static void m68k_op_slt_8_pi(m68000_base_device* mc68kcpu); +static void m68k_op_slt_8_pi7(m68000_base_device* mc68kcpu); +static void m68k_op_slt_8_pd(m68000_base_device* mc68kcpu); +static void m68k_op_slt_8_pd7(m68000_base_device* mc68kcpu); +static void m68k_op_slt_8_di(m68000_base_device* mc68kcpu); +static void m68k_op_slt_8_ix(m68000_base_device* mc68kcpu); +static void m68k_op_slt_8_aw(m68000_base_device* mc68kcpu); +static void m68k_op_slt_8_al(m68000_base_device* mc68kcpu); +static void m68k_op_sgt_8_ai(m68000_base_device* mc68kcpu); +static void m68k_op_sgt_8_pi(m68000_base_device* mc68kcpu); +static void m68k_op_sgt_8_pi7(m68000_base_device* mc68kcpu); +static void m68k_op_sgt_8_pd(m68000_base_device* mc68kcpu); +static void m68k_op_sgt_8_pd7(m68000_base_device* mc68kcpu); +static void m68k_op_sgt_8_di(m68000_base_device* mc68kcpu); +static void m68k_op_sgt_8_ix(m68000_base_device* mc68kcpu); +static void m68k_op_sgt_8_aw(m68000_base_device* mc68kcpu); +static void m68k_op_sgt_8_al(m68000_base_device* mc68kcpu); +static void m68k_op_sle_8_ai(m68000_base_device* mc68kcpu); +static void m68k_op_sle_8_pi(m68000_base_device* mc68kcpu); +static void m68k_op_sle_8_pi7(m68000_base_device* mc68kcpu); +static void m68k_op_sle_8_pd(m68000_base_device* mc68kcpu); +static void m68k_op_sle_8_pd7(m68000_base_device* mc68kcpu); +static void m68k_op_sle_8_di(m68000_base_device* mc68kcpu); +static void m68k_op_sle_8_ix(m68000_base_device* mc68kcpu); +static void m68k_op_sle_8_aw(m68000_base_device* mc68kcpu); +static void m68k_op_sle_8_al(m68000_base_device* mc68kcpu); +static void m68k_op_stop(m68000_base_device* mc68kcpu); +static void m68k_op_sub_8_er_d(m68000_base_device* mc68kcpu); +static void m68k_op_sub_8_er_ai(m68000_base_device* mc68kcpu); +static void m68k_op_sub_8_er_pi(m68000_base_device* mc68kcpu); +static void m68k_op_sub_8_er_pi7(m68000_base_device* mc68kcpu); +static void m68k_op_sub_8_er_pd(m68000_base_device* mc68kcpu); +static void m68k_op_sub_8_er_pd7(m68000_base_device* mc68kcpu); +static void m68k_op_sub_8_er_di(m68000_base_device* mc68kcpu); +static void m68k_op_sub_8_er_ix(m68000_base_device* mc68kcpu); +static void m68k_op_sub_8_er_aw(m68000_base_device* mc68kcpu); +static void m68k_op_sub_8_er_al(m68000_base_device* mc68kcpu); +static void m68k_op_sub_8_er_pcdi(m68000_base_device* mc68kcpu); +static void m68k_op_sub_8_er_pcix(m68000_base_device* mc68kcpu); +static void m68k_op_sub_8_er_i(m68000_base_device* mc68kcpu); +static void m68k_op_sub_16_er_d(m68000_base_device* mc68kcpu); +static void m68k_op_sub_16_er_a(m68000_base_device* mc68kcpu); +static void m68k_op_sub_16_er_ai(m68000_base_device* mc68kcpu); +static void m68k_op_sub_16_er_pi(m68000_base_device* mc68kcpu); +static void m68k_op_sub_16_er_pd(m68000_base_device* mc68kcpu); +static void m68k_op_sub_16_er_di(m68000_base_device* mc68kcpu); +static void m68k_op_sub_16_er_ix(m68000_base_device* mc68kcpu); +static void m68k_op_sub_16_er_aw(m68000_base_device* mc68kcpu); +static void m68k_op_sub_16_er_al(m68000_base_device* mc68kcpu); +static void m68k_op_sub_16_er_pcdi(m68000_base_device* mc68kcpu); +static void m68k_op_sub_16_er_pcix(m68000_base_device* mc68kcpu); +static void m68k_op_sub_16_er_i(m68000_base_device* mc68kcpu); +static void m68k_op_sub_32_er_d(m68000_base_device* mc68kcpu); +static void m68k_op_sub_32_er_a(m68000_base_device* mc68kcpu); +static void m68k_op_sub_32_er_ai(m68000_base_device* mc68kcpu); +static void m68k_op_sub_32_er_pi(m68000_base_device* mc68kcpu); +static void m68k_op_sub_32_er_pd(m68000_base_device* mc68kcpu); +static void m68k_op_sub_32_er_di(m68000_base_device* mc68kcpu); +static void m68k_op_sub_32_er_ix(m68000_base_device* mc68kcpu); +static void m68k_op_sub_32_er_aw(m68000_base_device* mc68kcpu); +static void m68k_op_sub_32_er_al(m68000_base_device* mc68kcpu); +static void m68k_op_sub_32_er_pcdi(m68000_base_device* mc68kcpu); +static void m68k_op_sub_32_er_pcix(m68000_base_device* mc68kcpu); +static void m68k_op_sub_32_er_i(m68000_base_device* mc68kcpu); +static void m68k_op_sub_8_re_ai(m68000_base_device* mc68kcpu); +static void m68k_op_sub_8_re_pi(m68000_base_device* mc68kcpu); +static void m68k_op_sub_8_re_pi7(m68000_base_device* mc68kcpu); +static void m68k_op_sub_8_re_pd(m68000_base_device* mc68kcpu); +static void m68k_op_sub_8_re_pd7(m68000_base_device* mc68kcpu); +static void m68k_op_sub_8_re_di(m68000_base_device* mc68kcpu); +static void m68k_op_sub_8_re_ix(m68000_base_device* mc68kcpu); +static void m68k_op_sub_8_re_aw(m68000_base_device* mc68kcpu); +static void m68k_op_sub_8_re_al(m68000_base_device* mc68kcpu); +static void m68k_op_sub_16_re_ai(m68000_base_device* mc68kcpu); +static void m68k_op_sub_16_re_pi(m68000_base_device* mc68kcpu); +static void m68k_op_sub_16_re_pd(m68000_base_device* mc68kcpu); +static void m68k_op_sub_16_re_di(m68000_base_device* mc68kcpu); +static void m68k_op_sub_16_re_ix(m68000_base_device* mc68kcpu); +static void m68k_op_sub_16_re_aw(m68000_base_device* mc68kcpu); +static void m68k_op_sub_16_re_al(m68000_base_device* mc68kcpu); +static void m68k_op_sub_32_re_ai(m68000_base_device* mc68kcpu); +static void m68k_op_sub_32_re_pi(m68000_base_device* mc68kcpu); +static void m68k_op_sub_32_re_pd(m68000_base_device* mc68kcpu); +static void m68k_op_sub_32_re_di(m68000_base_device* mc68kcpu); +static void m68k_op_sub_32_re_ix(m68000_base_device* mc68kcpu); +static void m68k_op_sub_32_re_aw(m68000_base_device* mc68kcpu); +static void m68k_op_sub_32_re_al(m68000_base_device* mc68kcpu); +static void m68k_op_suba_16_d(m68000_base_device* mc68kcpu); +static void m68k_op_suba_16_a(m68000_base_device* mc68kcpu); +static void m68k_op_suba_16_ai(m68000_base_device* mc68kcpu); +static void m68k_op_suba_16_pi(m68000_base_device* mc68kcpu); +static void m68k_op_suba_16_pd(m68000_base_device* mc68kcpu); +static void m68k_op_suba_16_di(m68000_base_device* mc68kcpu); +static void m68k_op_suba_16_ix(m68000_base_device* mc68kcpu); +static void m68k_op_suba_16_aw(m68000_base_device* mc68kcpu); +static void m68k_op_suba_16_al(m68000_base_device* mc68kcpu); +static void m68k_op_suba_16_pcdi(m68000_base_device* mc68kcpu); +static void m68k_op_suba_16_pcix(m68000_base_device* mc68kcpu); +static void m68k_op_suba_16_i(m68000_base_device* mc68kcpu); +static void m68k_op_suba_32_d(m68000_base_device* mc68kcpu); +static void m68k_op_suba_32_a(m68000_base_device* mc68kcpu); +static void m68k_op_suba_32_ai(m68000_base_device* mc68kcpu); +static void m68k_op_suba_32_pi(m68000_base_device* mc68kcpu); +static void m68k_op_suba_32_pd(m68000_base_device* mc68kcpu); +static void m68k_op_suba_32_di(m68000_base_device* mc68kcpu); +static void m68k_op_suba_32_ix(m68000_base_device* mc68kcpu); +static void m68k_op_suba_32_aw(m68000_base_device* mc68kcpu); +static void m68k_op_suba_32_al(m68000_base_device* mc68kcpu); +static void m68k_op_suba_32_pcdi(m68000_base_device* mc68kcpu); +static void m68k_op_suba_32_pcix(m68000_base_device* mc68kcpu); +static void m68k_op_suba_32_i(m68000_base_device* mc68kcpu); +static void m68k_op_subi_8_d(m68000_base_device* mc68kcpu); +static void m68k_op_subi_8_ai(m68000_base_device* mc68kcpu); +static void m68k_op_subi_8_pi(m68000_base_device* mc68kcpu); +static void m68k_op_subi_8_pi7(m68000_base_device* mc68kcpu); +static void m68k_op_subi_8_pd(m68000_base_device* mc68kcpu); +static void m68k_op_subi_8_pd7(m68000_base_device* mc68kcpu); +static void m68k_op_subi_8_di(m68000_base_device* mc68kcpu); +static void m68k_op_subi_8_ix(m68000_base_device* mc68kcpu); +static void m68k_op_subi_8_aw(m68000_base_device* mc68kcpu); +static void m68k_op_subi_8_al(m68000_base_device* mc68kcpu); +static void m68k_op_subi_16_d(m68000_base_device* mc68kcpu); +static void m68k_op_subi_16_ai(m68000_base_device* mc68kcpu); +static void m68k_op_subi_16_pi(m68000_base_device* mc68kcpu); +static void m68k_op_subi_16_pd(m68000_base_device* mc68kcpu); +static void m68k_op_subi_16_di(m68000_base_device* mc68kcpu); +static void m68k_op_subi_16_ix(m68000_base_device* mc68kcpu); +static void m68k_op_subi_16_aw(m68000_base_device* mc68kcpu); +static void m68k_op_subi_16_al(m68000_base_device* mc68kcpu); +static void m68k_op_subi_32_d(m68000_base_device* mc68kcpu); +static void m68k_op_subi_32_ai(m68000_base_device* mc68kcpu); +static void m68k_op_subi_32_pi(m68000_base_device* mc68kcpu); +static void m68k_op_subi_32_pd(m68000_base_device* mc68kcpu); +static void m68k_op_subi_32_di(m68000_base_device* mc68kcpu); +static void m68k_op_subi_32_ix(m68000_base_device* mc68kcpu); +static void m68k_op_subi_32_aw(m68000_base_device* mc68kcpu); +static void m68k_op_subi_32_al(m68000_base_device* mc68kcpu); +static void m68k_op_subq_8_d(m68000_base_device* mc68kcpu); +static void m68k_op_subq_8_ai(m68000_base_device* mc68kcpu); +static void m68k_op_subq_8_pi(m68000_base_device* mc68kcpu); +static void m68k_op_subq_8_pi7(m68000_base_device* mc68kcpu); +static void m68k_op_subq_8_pd(m68000_base_device* mc68kcpu); +static void m68k_op_subq_8_pd7(m68000_base_device* mc68kcpu); +static void m68k_op_subq_8_di(m68000_base_device* mc68kcpu); +static void m68k_op_subq_8_ix(m68000_base_device* mc68kcpu); +static void m68k_op_subq_8_aw(m68000_base_device* mc68kcpu); +static void m68k_op_subq_8_al(m68000_base_device* mc68kcpu); +static void m68k_op_subq_16_d(m68000_base_device* mc68kcpu); +static void m68k_op_subq_16_a(m68000_base_device* mc68kcpu); +static void m68k_op_subq_16_ai(m68000_base_device* mc68kcpu); +static void m68k_op_subq_16_pi(m68000_base_device* mc68kcpu); +static void m68k_op_subq_16_pd(m68000_base_device* mc68kcpu); +static void m68k_op_subq_16_di(m68000_base_device* mc68kcpu); +static void m68k_op_subq_16_ix(m68000_base_device* mc68kcpu); +static void m68k_op_subq_16_aw(m68000_base_device* mc68kcpu); +static void m68k_op_subq_16_al(m68000_base_device* mc68kcpu); +static void m68k_op_subq_32_d(m68000_base_device* mc68kcpu); +static void m68k_op_subq_32_a(m68000_base_device* mc68kcpu); +static void m68k_op_subq_32_ai(m68000_base_device* mc68kcpu); +static void m68k_op_subq_32_pi(m68000_base_device* mc68kcpu); +static void m68k_op_subq_32_pd(m68000_base_device* mc68kcpu); +static void m68k_op_subq_32_di(m68000_base_device* mc68kcpu); +static void m68k_op_subq_32_ix(m68000_base_device* mc68kcpu); +static void m68k_op_subq_32_aw(m68000_base_device* mc68kcpu); +static void m68k_op_subq_32_al(m68000_base_device* mc68kcpu); +static void m68k_op_subx_8_rr(m68000_base_device* mc68kcpu); +static void m68k_op_subx_16_rr(m68000_base_device* mc68kcpu); +static void m68k_op_subx_32_rr(m68000_base_device* mc68kcpu); +static void m68k_op_subx_8_mm_ax7(m68000_base_device* mc68kcpu); +static void m68k_op_subx_8_mm_ay7(m68000_base_device* mc68kcpu); +static void m68k_op_subx_8_mm_axy7(m68000_base_device* mc68kcpu); +static void m68k_op_subx_8_mm(m68000_base_device* mc68kcpu); +static void m68k_op_subx_16_mm(m68000_base_device* mc68kcpu); +static void m68k_op_subx_32_mm(m68000_base_device* mc68kcpu); +static void m68k_op_swap_32(m68000_base_device* mc68kcpu); +static void m68k_op_tas_8_d(m68000_base_device* mc68kcpu); +static void m68k_op_tas_8_ai(m68000_base_device* mc68kcpu); +static void m68k_op_tas_8_pi(m68000_base_device* mc68kcpu); +static void m68k_op_tas_8_pi7(m68000_base_device* mc68kcpu); +static void m68k_op_tas_8_pd(m68000_base_device* mc68kcpu); +static void m68k_op_tas_8_pd7(m68000_base_device* mc68kcpu); +static void m68k_op_tas_8_di(m68000_base_device* mc68kcpu); +static void m68k_op_tas_8_ix(m68000_base_device* mc68kcpu); +static void m68k_op_tas_8_aw(m68000_base_device* mc68kcpu); +static void m68k_op_tas_8_al(m68000_base_device* mc68kcpu); +static void m68k_op_trap(m68000_base_device* mc68kcpu); +static void m68k_op_trapt(m68000_base_device* mc68kcpu); +static void m68k_op_trapt_16(m68000_base_device* mc68kcpu); +static void m68k_op_trapt_32(m68000_base_device* mc68kcpu); +static void m68k_op_trapf(m68000_base_device* mc68kcpu); +static void m68k_op_trapf_16(m68000_base_device* mc68kcpu); +static void m68k_op_trapf_32(m68000_base_device* mc68kcpu); +static void m68k_op_traphi(m68000_base_device* mc68kcpu); +static void m68k_op_trapls(m68000_base_device* mc68kcpu); +static void m68k_op_trapcc(m68000_base_device* mc68kcpu); +static void m68k_op_trapcs(m68000_base_device* mc68kcpu); +static void m68k_op_trapne(m68000_base_device* mc68kcpu); +static void m68k_op_trapeq(m68000_base_device* mc68kcpu); +static void m68k_op_trapvc(m68000_base_device* mc68kcpu); +static void m68k_op_trapvs(m68000_base_device* mc68kcpu); +static void m68k_op_trappl(m68000_base_device* mc68kcpu); +static void m68k_op_trapmi(m68000_base_device* mc68kcpu); +static void m68k_op_trapge(m68000_base_device* mc68kcpu); +static void m68k_op_traplt(m68000_base_device* mc68kcpu); +static void m68k_op_trapgt(m68000_base_device* mc68kcpu); +static void m68k_op_traple(m68000_base_device* mc68kcpu); +static void m68k_op_traphi_16(m68000_base_device* mc68kcpu); +static void m68k_op_trapls_16(m68000_base_device* mc68kcpu); +static void m68k_op_trapcc_16(m68000_base_device* mc68kcpu); +static void m68k_op_trapcs_16(m68000_base_device* mc68kcpu); +static void m68k_op_trapne_16(m68000_base_device* mc68kcpu); +static void m68k_op_trapeq_16(m68000_base_device* mc68kcpu); +static void m68k_op_trapvc_16(m68000_base_device* mc68kcpu); +static void m68k_op_trapvs_16(m68000_base_device* mc68kcpu); +static void m68k_op_trappl_16(m68000_base_device* mc68kcpu); +static void m68k_op_trapmi_16(m68000_base_device* mc68kcpu); +static void m68k_op_trapge_16(m68000_base_device* mc68kcpu); +static void m68k_op_traplt_16(m68000_base_device* mc68kcpu); +static void m68k_op_trapgt_16(m68000_base_device* mc68kcpu); +static void m68k_op_traple_16(m68000_base_device* mc68kcpu); +static void m68k_op_traphi_32(m68000_base_device* mc68kcpu); +static void m68k_op_trapls_32(m68000_base_device* mc68kcpu); +static void m68k_op_trapcc_32(m68000_base_device* mc68kcpu); +static void m68k_op_trapcs_32(m68000_base_device* mc68kcpu); +static void m68k_op_trapne_32(m68000_base_device* mc68kcpu); +static void m68k_op_trapeq_32(m68000_base_device* mc68kcpu); +static void m68k_op_trapvc_32(m68000_base_device* mc68kcpu); +static void m68k_op_trapvs_32(m68000_base_device* mc68kcpu); +static void m68k_op_trappl_32(m68000_base_device* mc68kcpu); +static void m68k_op_trapmi_32(m68000_base_device* mc68kcpu); +static void m68k_op_trapge_32(m68000_base_device* mc68kcpu); +static void m68k_op_traplt_32(m68000_base_device* mc68kcpu); +static void m68k_op_trapgt_32(m68000_base_device* mc68kcpu); +static void m68k_op_traple_32(m68000_base_device* mc68kcpu); +static void m68k_op_trapv(m68000_base_device* mc68kcpu); +static void m68k_op_tst_8_d(m68000_base_device* mc68kcpu); +static void m68k_op_tst_8_ai(m68000_base_device* mc68kcpu); +static void m68k_op_tst_8_pi(m68000_base_device* mc68kcpu); +static void m68k_op_tst_8_pi7(m68000_base_device* mc68kcpu); +static void m68k_op_tst_8_pd(m68000_base_device* mc68kcpu); +static void m68k_op_tst_8_pd7(m68000_base_device* mc68kcpu); +static void m68k_op_tst_8_di(m68000_base_device* mc68kcpu); +static void m68k_op_tst_8_ix(m68000_base_device* mc68kcpu); +static void m68k_op_tst_8_aw(m68000_base_device* mc68kcpu); +static void m68k_op_tst_8_al(m68000_base_device* mc68kcpu); +static void m68k_op_tst_8_pcdi(m68000_base_device* mc68kcpu); +static void m68k_op_tst_8_pcix(m68000_base_device* mc68kcpu); +static void m68k_op_tst_8_i(m68000_base_device* mc68kcpu); +static void m68k_op_tst_16_d(m68000_base_device* mc68kcpu); +static void m68k_op_tst_16_a(m68000_base_device* mc68kcpu); +static void m68k_op_tst_16_ai(m68000_base_device* mc68kcpu); +static void m68k_op_tst_16_pi(m68000_base_device* mc68kcpu); +static void m68k_op_tst_16_pd(m68000_base_device* mc68kcpu); +static void m68k_op_tst_16_di(m68000_base_device* mc68kcpu); +static void m68k_op_tst_16_ix(m68000_base_device* mc68kcpu); +static void m68k_op_tst_16_aw(m68000_base_device* mc68kcpu); +static void m68k_op_tst_16_al(m68000_base_device* mc68kcpu); +static void m68k_op_tst_16_pcdi(m68000_base_device* mc68kcpu); +static void m68k_op_tst_16_pcix(m68000_base_device* mc68kcpu); +static void m68k_op_tst_16_i(m68000_base_device* mc68kcpu); +static void m68k_op_tst_32_d(m68000_base_device* mc68kcpu); +static void m68k_op_tst_32_a(m68000_base_device* mc68kcpu); +static void m68k_op_tst_32_ai(m68000_base_device* mc68kcpu); +static void m68k_op_tst_32_pi(m68000_base_device* mc68kcpu); +static void m68k_op_tst_32_pd(m68000_base_device* mc68kcpu); +static void m68k_op_tst_32_di(m68000_base_device* mc68kcpu); +static void m68k_op_tst_32_ix(m68000_base_device* mc68kcpu); +static void m68k_op_tst_32_aw(m68000_base_device* mc68kcpu); +static void m68k_op_tst_32_al(m68000_base_device* mc68kcpu); +static void m68k_op_tst_32_pcdi(m68000_base_device* mc68kcpu); +static void m68k_op_tst_32_pcix(m68000_base_device* mc68kcpu); +static void m68k_op_tst_32_i(m68000_base_device* mc68kcpu); +static void m68k_op_unlk_32_a7(m68000_base_device* mc68kcpu); +static void m68k_op_unlk_32(m68000_base_device* mc68kcpu); +static void m68k_op_unpk_16_rr(m68000_base_device* mc68kcpu); +static void m68k_op_unpk_16_mm_ax7(m68000_base_device* mc68kcpu); +static void m68k_op_unpk_16_mm_ay7(m68000_base_device* mc68kcpu); +static void m68k_op_unpk_16_mm_axy7(m68000_base_device* mc68kcpu); +static void m68k_op_unpk_16_mm(m68000_base_device* mc68kcpu); +static void m68k_op_cinv_32(m68000_base_device* mc68kcpu); +static void m68k_op_cpush_32(m68000_base_device* mc68kcpu); +#else +/* Build the opcode handler table */ +void m68ki_build_opcode_table(void); + +extern void (*m68ki_instruction_jump_table[][0x10000])(m68000_base_device *m68k); /* opcode handler jump table */ +extern unsigned char m68ki_cycles[][0x10000]; + + +/* ======================================================================== */ +/* ============================== END OF FILE ============================= */ +/* ======================================================================== */ + + +#endif diff --git a/src/devices/cpu/m68000/makefile b/src/devices/cpu/m68000/makefile new file mode 100644 index 00000000000..12b29fa267a --- /dev/null +++ b/src/devices/cpu/m68000/makefile @@ -0,0 +1,31 @@ +# extension for executables +EXE := + +ifeq ($(OS),Windows_NT) +EXE := .exe +endif +ifeq ($(OS),os2) +EXE := .exe +endif + +.PHONY: all clean + +all : m68kmake$(EXE) m68kops.c clean + +clean: + @echo Cleaning... + -@rm -f m68kmake$(EXE) + -@rm -f m68kmake.o + +m68kmake.o: m68kmake.c + @echo $(notdir $<) + @gcc -x c++ -std=gnu++98 -o "$@" -c "$<" + +m68kmake$(EXE) : m68kmake.o + @echo Linking $@... + @g++ -lstdc++ $^ -o $@ + +m68kops.c: m68kmake$(EXE) m68k_in.c + @echo Generating M68K source files... + @m68kmake$(EXE) . m68k_in.c + diff --git a/src/devices/cpu/m6805/6805dasm.c b/src/devices/cpu/m6805/6805dasm.c new file mode 100644 index 00000000000..9471d976924 --- /dev/null +++ b/src/devices/cpu/m6805/6805dasm.c @@ -0,0 +1,214 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/* + * A quick-hack 68(7)05 disassembler + * + * Note: this is not the good and proper way to disassemble anything, but it works + * + * I'm afraid to put my name on it, but I feel obligated: + * This code written by Aaron Giles (agiles@sirius.com) for the MAME project + * + */ + +#include "emu.h" +#include "debugger.h" +#include "m6805.h" + +enum addr_mode { + _imp=0, /* implicit */ + _btr, /* bit test and relative */ + _bit, /* bit set/clear */ + _rel, /* relative */ + _imm, /* immediate */ + _dir, /* direct address */ + _ext, /* extended address */ + _idx, /* indexed */ + _ix1, /* indexed + byte offset */ + _ix2 /* indexed + word offset */ +}; + +enum op_names { + adca=0, adda, anda, asl, asla, aslx, asr, asra, + asrx, bcc, bclr, bcs, beq, bhcc, bhcs, bhi, + bih, bil, bita, bls, bmc, bmi, bms, bne, + bpl, bra, brclr, brn, brset, bset, bsr, clc, + cli, clr, clra, clrx, cmpa, com, coma, comx, + cpx, dec, deca, decx, eora, ill, inc, inca, + incx, jmp, jsr, lda, ldx, lsr, lsra, lsrx, + neg, nega, negx, nop, ora, rol, rola, rolx, + ror, rora, rorx, rsp, rti, rts, sbca, sec, + sei, sta, stx, suba, swi, tax, tst, tsta, + tstx, txa +}; + +static const char *const op_name_str[] = { + "adca", "adda", "anda", "asl", "asla", "aslx", "asr", "asra", + "asrx", "bcc", "bclr", "bcs", "beq", "bhcc", "bhcs", "bhi", + "bih", "bil", "bita", "bls", "bmc", "bmi", "bms", "bne", + "bpl", "bra", "brclr","brn", "brset","bset", "bsr", "clc", + "cli", "clr", "clra", "clrx", "cmpa", "com", "coma", "comx", + "cpx", "dec", "deca", "decx", "eora", "*ill", "inc", "inca", + "incx", "jmp", "jsr", "lda", "ldx", "lsr", "lsra", "lsrx", + "neg", "nega", "negx", "nop", "ora", "rol", "rola", "rolx", + "ror", "rora", "rorx", "rsp", "rti", "rts", "sbca", "sec", + "sei", "sta", "stx", "suba", "swi", "tax", "tst", "tsta", + "tstx", "txa" +}; + +static const unsigned char disasm[0x100][2] = { + {brset,_btr},{brclr,_btr},{brset,_btr},{brclr,_btr},/* 00 */ + {brset,_btr},{brclr,_btr},{brset,_btr},{brclr,_btr}, + {brset,_btr},{brclr,_btr},{brset,_btr},{brclr,_btr}, + {brset,_btr},{brclr,_btr},{brset,_btr},{brclr,_btr}, + {bset, _bit},{bclr, _bit},{bset, _bit},{bclr, _bit},/* 10 */ + {bset, _bit},{bclr, _bit},{bset, _bit},{bclr, _bit}, + {bset, _bit},{bclr, _bit},{bset, _bit},{bclr, _bit}, + {bset, _bit},{bclr, _bit},{bset, _bit},{bclr, _bit}, + {bra, _rel},{brn, _rel},{bhi, _rel},{bls, _rel},/* 20 */ + {bcc, _rel},{bcs, _rel},{bne, _rel},{beq, _rel}, + {bhcc, _rel},{bhcs, _rel},{bpl, _rel},{bmi, _rel}, + {bmc, _rel},{bms, _rel},{bil, _rel},{bih, _rel}, + {neg, _dir},{ill, _imp},{ill, _imp},{com, _dir},/* 30 */ + {lsr, _dir},{ill, _imp},{ror, _dir},{asr, _dir}, + {asl, _dir},{rol, _dir},{dec, _dir},{ill, _imp}, + {inc, _dir},{tst, _dir},{ill, _imp},{clr, _dir}, + {nega, _imp},{ill, _imp},{ill, _imp},{coma, _imp},/* 40 */ + {lsra, _imp},{ill, _imp},{rora, _imp},{asra, _imp}, + {asla, _imp},{rola, _imp},{deca, _imp},{ill, _imp}, + {inca, _imp},{tsta, _imp},{ill, _imp},{clra, _imp}, + {negx, _imp},{ill, _imp},{ill, _imp},{comx, _imp},/* 50 */ + {lsrx, _imp},{ill, _imp},{rorx, _imp},{asrx, _imp}, + {aslx, _imp},{rolx, _imp},{decx, _imp},{ill, _imp}, + {incx, _imp},{tstx, _imp},{ill, _imp},{clrx, _imp}, + {neg, _ix1},{ill, _imp},{ill, _imp},{com, _ix1},/* 60 */ + {lsr, _ix1},{ill, _imp},{ror, _ix1},{asr, _ix1}, + {asl, _ix1},{rol, _ix1},{dec, _ix1},{ill, _imp}, + {inc, _ix1},{tst, _ix1},{jmp, _ix1},{clr, _ix1}, + {neg, _idx},{ill, _imp},{ill, _imp},{com, _idx},/* 70 */ + {lsr, _idx},{ill, _imp},{ror, _idx},{asr, _idx}, + {asl, _idx},{rol, _idx},{dec, _idx},{ill, _imp}, + {inc, _idx},{tst, _idx},{jmp, _idx},{clr, _idx}, + {rti, _imp},{rts, _imp},{ill, _imp},{swi, _imp},/* 80 */ + {ill, _imp},{ill, _imp},{ill, _imp},{ill, _imp}, + {ill, _imp},{ill, _imp},{ill, _imp},{ill, _imp}, + {ill, _imp},{ill, _imp},{ill, _imp},{ill, _imp}, + {ill, _imp},{ill, _imp},{ill, _imp},{ill, _imp},/* 90 */ + {ill, _imp},{ill, _imp},{ill, _imp},{tax, _imp}, + {clc, _imp},{sec, _imp},{cli, _imp},{sei, _imp}, + {rsp, _imp},{nop, _imp},{ill, _imp},{txa, _imp}, + {suba, _imm},{cmpa, _imm},{sbca, _imm},{cpx, _imm},/* a0 */ + {anda, _imm},{bita, _imm},{lda, _imm},{ill, _imp}, + {eora, _imm},{adca, _imm},{ora, _imm},{adda, _imm}, + {ill, _imp},{bsr, _rel},{ldx, _imm},{ill, _imp}, + {suba, _dir},{cmpa, _dir},{sbca, _dir},{cpx, _dir},/* b0 */ + {anda, _dir},{bita, _dir},{lda, _dir},{sta, _dir}, + {eora, _dir},{adca, _dir},{ora, _dir},{adda, _dir}, + {jmp, _dir},{jsr, _dir},{ldx, _dir},{stx, _dir}, + {suba, _ext},{cmpa, _ext},{sbca, _ext},{cpx, _ext},/* c0 */ + {anda, _ext},{bita, _ext},{lda, _ext},{sta, _ext}, + {eora, _ext},{adca, _ext},{ora, _ext},{adda, _ext}, + {jmp, _ext},{jsr, _ext},{ldx, _ext},{stx, _ext}, + {suba, _ix2},{cmpa, _ix2},{sbca, _ix2},{cpx, _ix2},/* d0 */ + {anda, _ix2},{bita, _ix2},{lda, _ix2},{sta, _ix2}, + {eora, _ix2},{adca, _ix2},{ora, _ix2},{adda, _ix2}, + {jmp, _ix2},{jsr, _ix2},{ldx, _ix2},{stx, _ix2}, + {suba, _ix1},{cmpa, _ix1},{sbca, _ix1},{cpx, _ix1},/* e0 */ + {anda, _ix1},{bita, _ix1},{lda, _ix1},{sta, _ix1}, + {eora, _ix1},{adca, _ix1},{ora, _ix1},{adda, _ix1}, + {jmp, _ix1},{jsr, _ix1},{ldx, _ix1},{stx, _ix1}, + {suba, _idx},{cmpa, _idx},{sbca, _idx},{cpx, _idx},/* f0 */ + {anda, _idx},{bita, _idx},{lda, _idx},{sta, _idx}, + {eora, _idx},{adca, _idx},{ora, _idx},{adda, _idx}, + {jmp, _idx},{jsr, _idx},{ldx, _idx},{stx, _idx} +}; + +#if 0 +static const char *const opcode_strings[0x0100] = +{ + "brset0", "brclr0", "brset1", "brclr1", "brset2", "brclr2", "brset3", "brclr3", /*00*/ + "brset4", "brclr4", "brset5", "brclr5", "brset6", "brclr6", "brset7", "brclr7", + "bset0", "bclr0", "bset1", "bclr1", "bset2", "bclr2", "bset3", "bclr3", /*10*/ + "bset4", "bclr4", "bset5", "bclr5", "bset6", "bclr6", "bset7", "bclr7", + "bra", "brn", "bhi", "bls", "bcc", "bcs", "bne", "beq", /*20*/ + "bhcc", "bhcs", "bpl", "bmi", "bmc", "bms", "bil", "bih", + "neg_di", "illegal", "illegal", "com_di", "lsr_di", "illegal", "ror_di", "asr_di", /*30*/ + "asl_di", "rol_di", "dec_di", "illegal", "inc_di", "tst_di", "illegal", "clr_di", + "nega", "illegal", "illegal", "coma", "lsra", "illegal", "rora", "asra", /*40*/ + "asla", "rola", "deca", "illegal", "inca", "tsta", "illegal", "clra", + "negx", "illegal", "illegal", "comx", "lsrx", "illegal", "rorx", "asrx", /*50*/ + "aslx", "rolx", "decx", "illegal", "incx", "tstx", "illegal", "clrx", + "neg_ix1", "illegal", "illegal", "com_ix1", "lsr_ix1", "illegal", "ror_ix1", "asr_ix1", /*60*/ + "asl_ix1", "rol_ix1", "dec_ix1", "illegal", "inc_ix1", "tst_ix1", "jmp_ix1", "clr_ix1", + "neg_ix", "illegal", "illegal", "com_ix", "lsr_ix", "illegal", "ror_ix", "asr_ix", /*70*/ + "asl_ix", "rol_ix", "dec_ix", "illegal", "inc_ix", "tst_ix", "jmp_ix", "clr_ix", + "rti", "rts", "illegal", "swi", "illegal", "illegal", "illegal", "illegal", /*80*/ + "illegal", "illegal", "illegal", "illegal", "illegal", "illegal", "illegal", "illegal", + "illegal", "illegal", "illegal", "illegal", "illegal", "illegal", "illegal", "tax", /*90*/ + "clc", "sec", "cli", "sei", "rsp", "nop", "illegal", "txa", + "suba_im", "cmpa_im", "sbca_im", "cpx_im", "anda_im", "bita_im", "lda_im", "illegal", /*A0*/ + "eora_im", "adca_im", "ora_im", "adda_im", "illegal", "bsr", "ldx_im", "illegal", + "suba_di", "cmpa_di", "sbca_di", "cpx_di", "anda_di", "bita_di", "lda_di", "sta_di", /*B0*/ + "eora_di", "adca_di", "ora_di", "adda_di", "jmp_di", "jsr_di", "ldx_di", "stx_di", + "suba_ex", "cmpa_ex", "sbca_ex", "cpx_ex", "anda_ex", "bita_ex", "lda_ex", "sta_ex", /*C0*/ + "eora_ex", "adca_ex", "ora_ex", "adda_ex", "jmp_ex", "jsr_ex", "ldx_ex", "stx_ex", + "suba_ix2", "cmpa_ix2", "sbca_ix2", "cpx_ix2", "anda_ix2", "bita_ix2", "lda_ix2", "sta_ix2", /*D0*/ + "eora_ix2", "adca_ix2", "ora_ix2", "adda_ix2", "jmp_ix2", "jsr_ix2", "ldx_ix2", "stx_ix2", + "suba_ix1", "cmpa_ix1", "sbca_ix1", "cpx_ix1", "anda_ix1", "bita_ix1", "lda_ix1", "sta_ix1", /*E0*/ + "eora_ix1", "adca_ix1", "ora_ix1", "adda_ix1", "jmp_ix1", "jsr_ix1", "ldx_ix1", "stx_ix1", + "suba_ix", "cmpa_ix", "sbca_ix", "cpx_ix", "anda_ix", "bita_ix", "lda_ix", "sta_ix", /*F0*/ + "eora_ix", "adca_ix", "ora_ix", "adda_ix", "jmp_ix", "jsr_ix", "ldx_ix", "stx_ix" +}; +#endif + +CPU_DISASSEMBLE( m6805 ) +{ + int code, bit; + UINT16 ea; + UINT32 flags = 0; + + code = oprom[0]; + + if (disasm[code][0] == bsr || disasm[code][0] == jsr) + flags = DASMFLAG_STEP_OVER; + else if (disasm[code][0] == rts || disasm[code][0] == rti) + flags = DASMFLAG_STEP_OUT; + + buffer += sprintf(buffer, "%-6s", op_name_str[disasm[code][0]]); + + switch( disasm[code][1] ) + { + case _btr: /* bit test and relative branch */ + bit = (code >> 1) & 7; + sprintf (buffer, "%d,$%02X,$%03X", bit, opram[1], pc + 3 + (INT8)opram[2]); + return 3 | flags | DASMFLAG_SUPPORTED; + case _bit: /* bit test */ + bit = (code >> 1) & 7; + sprintf (buffer, "%d,$%03X", bit, opram[1]); + return 2 | flags | DASMFLAG_SUPPORTED; + case _rel: /* relative */ + sprintf (buffer, "$%03X", pc + 2 + (INT8)opram[1]); + return 2 | flags | DASMFLAG_SUPPORTED; + case _imm: /* immediate */ + sprintf (buffer, "#$%02X", opram[1]); + return 2 | flags | DASMFLAG_SUPPORTED; + case _dir: /* direct (zero page address) */ + sprintf (buffer, "$%02X", opram[1]); + return 2 | flags | DASMFLAG_SUPPORTED; + case _ext: /* extended (16 bit address) */ + ea = (opram[1] << 8) + opram[2]; + sprintf (buffer, "$%04X", ea); + return 3 | flags | DASMFLAG_SUPPORTED; + case _idx: /* indexed */ + sprintf (buffer, "(x)"); + return 1 | flags | DASMFLAG_SUPPORTED; + case _ix1: /* indexed + byte (zero page) */ + sprintf (buffer, "(x+$%02X)", opram[1]); + return 2 | flags | DASMFLAG_SUPPORTED; + case _ix2: /* indexed + word (16 bit address) */ + ea = (opram[1] << 8) + opram[2]; + sprintf (buffer, "(x+$%04X)", ea); + return 3 | flags | DASMFLAG_SUPPORTED; + default: /* implicit */ + return 1 | flags | DASMFLAG_SUPPORTED; + } +} diff --git a/src/devices/cpu/m6805/6805ops.inc b/src/devices/cpu/m6805/6805ops.inc new file mode 100644 index 00000000000..713be5e0d7b --- /dev/null +++ b/src/devices/cpu/m6805/6805ops.inc @@ -0,0 +1,1806 @@ + +/* + +HNZC + +? = undefined +* = affected +- = unaffected +0 = cleared +1 = set +# = ccr directly affected by instruction +@ = special - carry set if bit 7 is set + +*/ + +#define OP_HANDLER(_name) void m6805_base_device::_name() +#define DERIVED_OP_HANDLER(_arch,_name) void _arch##_device::_name() + +#define OP_HANDLER_BIT(_name) void m6805_base_device::_name(UINT8 bit) + +OP_HANDLER( illegal ) +{ + logerror("M6805: illegal opcode\n"); +} + +/* $00/$02/$04/$06/$08/$0A/$0C/$0E BRSET direct,relative ---- */ +OP_HANDLER_BIT( brset ) +{ + UINT8 t,r; + DIRBYTE(r); + IMMBYTE(t); + + CLC; + + if (r&bit) { + SEC; + PC+=SIGNED(t); + } +} + +/* $01/$03/$05/$07/$09/$0B/$0D/$0F BRCLR direct,relative ---- */ +OP_HANDLER_BIT( brclr ) +{ + UINT8 t,r; + DIRBYTE(r); + IMMBYTE(t); + + SEC; + + if (!(r&bit)) { + CLC; + PC+=SIGNED(t); + } +} + +/* $10/$12/$14/$16/$18/$1A/$1C/$1E BSET direct ---- */ +OP_HANDLER_BIT( bset ) +{ + UINT8 t,r; + DIRBYTE(t); r=t|bit; + WM(EAD,r); +} + +/* $11/$13/$15/$17/$19/$1B/$1D/$1F BCLR direct ---- */ +OP_HANDLER_BIT( bclr) +{ + UINT8 t,r; + DIRBYTE(t); r=t&(~bit); + WM(EAD,r); +} + +/* $20 BRA relative ---- */ +OP_HANDLER( bra ) +{ + UINT8 t; + IMMBYTE(t); + PC+=SIGNED(t); +} + +/* $21 BRN relative ---- */ +OP_HANDLER( brn ) +{ + SKIPBYTE(); +} + +/* $22 BHI relative ---- */ +OP_HANDLER( bhi ) +{ + BRANCH( !(CC&(CFLAG|ZFLAG)) ); +} + +/* $23 BLS relative ---- */ +OP_HANDLER( bls ) +{ + BRANCH( CC&(CFLAG|ZFLAG) ); +} + +/* $24 BCC relative ---- */ +OP_HANDLER( bcc ) +{ + BRANCH( !(CC&CFLAG) ); +} + +/* $25 BCS relative ---- */ +OP_HANDLER( bcs ) +{ + BRANCH( CC&CFLAG ); +} + +/* $26 BNE relative ---- */ +OP_HANDLER( bne ) +{ + BRANCH( !(CC&ZFLAG) ); +} + +/* $27 BEQ relative ---- */ +OP_HANDLER( beq ) +{ + BRANCH( CC&ZFLAG ); +} + +/* $28 BHCC relative ---- */ +OP_HANDLER( bhcc ) +{ + BRANCH( !(CC&HFLAG) ); +} + +/* $29 BHCS relative ---- */ +OP_HANDLER( bhcs ) +{ + BRANCH( CC&HFLAG ); +} + +/* $2a BPL relative ---- */ +OP_HANDLER( bpl ) +{ + BRANCH( !(CC&NFLAG) ); +} + +/* $2b BMI relative ---- */ +OP_HANDLER( bmi ) +{ + BRANCH( CC&NFLAG ); +} + +/* $2c BMC relative ---- */ +OP_HANDLER( bmc ) +{ + BRANCH( !(CC&IFLAG) ); +} + +/* $2d BMS relative ---- */ +OP_HANDLER( bms ) +{ + BRANCH( CC&IFLAG ); +} + +/* $2e BIL relative ---- */ +OP_HANDLER( bil ) +{ + BRANCH(m_irq_state[0] != CLEAR_LINE); +} + +DERIVED_OP_HANDLER( hd63705, bil ) +{ + BRANCH(m_nmi_state != CLEAR_LINE); +} + +/* $2f BIH relative ---- */ +OP_HANDLER( bih ) +{ + BRANCH(m_irq_state[0] == CLEAR_LINE); +} + +DERIVED_OP_HANDLER( hd63705, bih ) +{ + BRANCH(m_nmi_state == CLEAR_LINE); +} + +/* $30 NEG direct -*** */ +OP_HANDLER( neg_di ) +{ + UINT8 t; + UINT16 r; + DIRBYTE(t); + r=-t; + CLR_NZC; + SET_FLAGS8(0,t,r); + WM(EAD,r); +} + +/* $31 ILLEGAL */ + +/* $32 ILLEGAL */ + +/* $33 COM direct -**1 */ +OP_HANDLER( com_di ) +{ + UINT8 t; + DIRBYTE(t); + t = ~t; + CLR_NZ; + SET_NZ8(t); + SEC; + WM(EAD,t); +} + +/* $34 LSR direct -0** */ +OP_HANDLER( lsr_di ) +{ + UINT8 t; + DIRBYTE(t); + CLR_NZC; + CC |= (t&0x01); + t >>= 1; + SET_Z8(t); + WM(EAD,t); +} + +/* $35 ILLEGAL */ + +/* $36 ROR direct -*** */ +OP_HANDLER( ror_di ) +{ + UINT8 t,r; + DIRBYTE(t); + r = (CC & 0x01) << 7; + CLR_NZC; + CC |= (t & 0x01); + r |= t>>1; + SET_NZ8(r); + WM(EAD,r); +} + +/* $37 ASR direct ?*** */ +OP_HANDLER( asr_di ) +{ + UINT8 t; + DIRBYTE(t); + CLR_NZC; CC|=(t&0x01); + t>>=1; t|=((t&0x40)<<1); + SET_NZ8(t); + WM(EAD,t); +} + +/* $38 LSL direct ?*** */ +OP_HANDLER( lsl_di ) +{ + UINT8 t; + UINT16 r; + DIRBYTE(t); + r = t << 1; + CLR_NZC; + SET_FLAGS8(t,t,r); + WM(EAD,r); +} + +/* $39 ROL direct -*** */ +OP_HANDLER( rol_di ) +{ + UINT16 t,r; + DIRBYTE(t); + r = CC & 0x01; + r |= t << 1; + CLR_NZC; + SET_FLAGS8(t,t,r); + WM(EAD,r); +} + +/* $3a DEC direct -**- */ +OP_HANDLER( dec_di ) +{ + UINT8 t; + DIRBYTE(t); + --t; + CLR_NZ; SET_FLAGS8D(t); + WM(EAD,t); +} + +/* $3b ILLEGAL */ + +/* $3c INC direct -**- */ +OP_HANDLER( inc_di ) +{ + UINT8 t; + DIRBYTE(t); + ++t; + CLR_NZ; SET_FLAGS8I(t); + WM(EAD,t); +} + +/* $3d TST direct -**- */ +OP_HANDLER( tst_di ) +{ + UINT8 t; + DIRBYTE(t); + CLR_NZ; SET_NZ8(t); +} + +/* $3e ILLEGAL */ + +/* $3f CLR direct -0100 */ +OP_HANDLER( clr_di ) +{ + DIRECT; + CLR_NZ; SEZ; + WM(EAD,0); +} + +/* $40 NEGA inherent ?*** */ +OP_HANDLER( nega ) +{ + UINT16 r; + r = -A; + CLR_NZC; SET_FLAGS8(0,A,r); + A = r; +} + +/* $41 ILLEGAL */ + +/* $42 ILLEGAL */ + +/* $43 COMA inherent -**1 */ +OP_HANDLER( coma ) +{ + A = ~A; + CLR_NZ; + SET_NZ8(A); + SEC; +} + +/* $44 LSRA inherent -0** */ +OP_HANDLER( lsra ) +{ + CLR_NZC; + CC |= (A & 0x01); + A >>= 1; + SET_Z8(A); +} + +/* $45 ILLEGAL */ + +/* $46 RORA inherent -*** */ +OP_HANDLER( rora ) +{ + UINT8 r; + r = (CC & 0x01) << 7; + CLR_NZC; + CC |= (A & 0x01); + r |= A >> 1; + SET_NZ8(r); + A = r; +} + +/* $47 ASRA inherent ?*** */ +OP_HANDLER( asra ) +{ + CLR_NZC; + CC |= (A & 0x01); + A = (A & 0x80) | (A >> 1); + SET_NZ8(A); +} + +/* $48 LSLA inherent ?*** */ +OP_HANDLER( lsla ) +{ + UINT16 r; + r = A << 1; + CLR_NZC; + SET_FLAGS8(A,A,r); + A = r; +} + +/* $49 ROLA inherent -*** */ +OP_HANDLER( rola ) +{ + UINT16 t,r; + t = A; + r = CC & 0x01; + r |= t << 1; + CLR_NZC; + SET_FLAGS8(t,t,r); + A = r; +} + +/* $4a DECA inherent -**- */ +OP_HANDLER( deca ) +{ + --A; + CLR_NZ; + SET_FLAGS8D(A); +} + +/* $4b ILLEGAL */ + +/* $4c INCA inherent -**- */ +OP_HANDLER( inca ) +{ + ++A; + CLR_NZ; + SET_FLAGS8I(A); +} + +/* $4d TSTA inherent -**- */ +OP_HANDLER( tsta ) +{ + CLR_NZ; + SET_NZ8(A); +} + +/* $4e ILLEGAL */ + +/* $4f CLRA inherent -010 */ +OP_HANDLER( clra ) +{ + A = 0; + CLR_NZ; + SEZ; +} + +/* $50 NEGX inherent ?*** */ +OP_HANDLER( negx ) +{ + UINT16 r; + r = -X; + CLR_NZC; + SET_FLAGS8(0,X,r); + X = r; +} + +/* $51 ILLEGAL */ + +/* $52 ILLEGAL */ + +/* $53 COMX inherent -**1 */ +OP_HANDLER( comx ) +{ + X = ~X; + CLR_NZ; + SET_NZ8(X); + SEC; +} + +/* $54 LSRX inherent -0** */ +OP_HANDLER( lsrx ) +{ + CLR_NZC; + CC |= (X & 0x01); + X >>= 1; + SET_Z8(X); +} + +/* $55 ILLEGAL */ + +/* $56 RORX inherent -*** */ +OP_HANDLER( rorx ) +{ + UINT8 r; + r = (CC & 0x01) << 7; + CLR_NZC; + CC |= (X & 0x01); + r |= X>>1; + SET_NZ8(r); + X = r; +} + +/* $57 ASRX inherent ?*** */ +OP_HANDLER( asrx ) +{ + CLR_NZC; + CC |= (X & 0x01); + X = (X & 0x80) | (X >> 1); + SET_NZ8(X); +} + +/* $58 ASLX inherent ?*** */ +OP_HANDLER( aslx ) +{ + UINT16 r; + r = X << 1; + CLR_NZC; + SET_FLAGS8(X,X,r); + X = r; +} + +/* $59 ROLX inherent -*** */ +OP_HANDLER( rolx ) +{ + UINT16 t,r; + t = X; + r = CC & 0x01; + r |= t<<1; + CLR_NZC; + SET_FLAGS8(t,t,r); + X = r; +} + +/* $5a DECX inherent -**- */ +OP_HANDLER( decx ) +{ + --X; + CLR_NZ; + SET_FLAGS8D(X); +} + +/* $5b ILLEGAL */ + +/* $5c INCX inherent -**- */ +OP_HANDLER( incx ) +{ + ++X; + CLR_NZ; + SET_FLAGS8I(X); +} + +/* $5d TSTX inherent -**- */ +OP_HANDLER( tstx ) +{ + CLR_NZ; + SET_NZ8(X); +} + +/* $5e ILLEGAL */ + +/* $5f CLRX inherent -010 */ +OP_HANDLER( clrx ) +{ + X = 0; + CLR_NZC; + SEZ; +} + +/* $60 NEG indexed, 1 byte offset -*** */ +OP_HANDLER( neg_ix1 ) +{ + UINT8 t; + UINT16 r; + IDX1BYTE(t); r=-t; + CLR_NZC; SET_FLAGS8(0,t,r); + WM(EAD,r); +} + +/* $61 ILLEGAL */ + +/* $62 ILLEGAL */ + +/* $63 COM indexed, 1 byte offset -**1 */ +OP_HANDLER( com_ix1 ) +{ + UINT8 t; + IDX1BYTE(t); t = ~t; + CLR_NZ; SET_NZ8(t); SEC; + WM(EAD,t); +} + +/* $64 LSR indexed, 1 byte offset -0** */ +OP_HANDLER( lsr_ix1 ) +{ + UINT8 t; + IDX1BYTE(t); + CLR_NZC; + CC |= (t & 0x01); + t >>= 1; + SET_Z8(t); + WM(EAD,t); +} + +/* $65 ILLEGAL */ + +/* $66 ROR indexed, 1 byte offset -*** */ +OP_HANDLER( ror_ix1 ) +{ + UINT8 t,r; + IDX1BYTE(t); + r = (CC & 0x01) << 7; + CLR_NZC; + CC |= (t & 0x01); + r |= t>>1; + SET_NZ8(r); + WM(EAD,r); +} + +/* $67 ASR indexed, 1 byte offset ?*** */ +OP_HANDLER( asr_ix1 ) +{ + UINT8 t; + IDX1BYTE(t); + CLR_NZC; CC|=(t&0x01); + t>>=1; t|=((t&0x40)<<1); + SET_NZ8(t); + WM(EAD,t); +} + +/* $68 LSL indexed, 1 byte offset ?*** */ +OP_HANDLER( lsl_ix1 ) +{ + UINT8 t; + UINT16 r; + IDX1BYTE(t); + r = t << 1; + CLR_NZC; + SET_FLAGS8(t,t,r); + WM(EAD,r); +} + +/* $69 ROL indexed, 1 byte offset -*** */ +OP_HANDLER( rol_ix1 ) +{ + UINT16 t,r; + IDX1BYTE(t); + r = CC & 0x01; + r |= t << 1; + CLR_NZC; + SET_FLAGS8(t,t,r); + WM(EAD,r); +} + +/* $6a DEC indexed, 1 byte offset -**- */ +OP_HANDLER( dec_ix1 ) +{ + UINT8 t; + IDX1BYTE(t); + --t; + CLR_NZ; SET_FLAGS8D(t); + WM(EAD,t); +} + +/* $6b ILLEGAL */ + +/* $6c INC indexed, 1 byte offset -**- */ +OP_HANDLER( inc_ix1 ) +{ + UINT8 t; + IDX1BYTE(t); + ++t; + CLR_NZ; SET_FLAGS8I(t); + WM(EAD,t); +} + +/* $6d TST indexed, 1 byte offset -**- */ +OP_HANDLER( tst_ix1 ) +{ + UINT8 t; + IDX1BYTE(t); + CLR_NZ; SET_NZ8(t); +} + +/* $6e ILLEGAL */ + +/* $6f CLR indexed, 1 byte offset -0100 */ +OP_HANDLER( clr_ix1 ) +{ + INDEXED1; + CLR_NZC; SEZ; + WM(EAD,0); +} + +/* $70 NEG indexed -*** */ +OP_HANDLER( neg_ix ) +{ + UINT8 t; + UINT16 r; + IDXBYTE(t); r=-t; + CLR_NZC; SET_FLAGS8(0,t,r); + WM(EAD,r); +} + +/* $71 ILLEGAL */ + +/* $72 ILLEGAL */ + +/* $73 COM indexed -**1 */ +OP_HANDLER( com_ix ) +{ + UINT8 t; + IDXBYTE(t); t = ~t; + CLR_NZ; SET_NZ8(t); SEC; + WM(EAD,t); +} + +/* $74 LSR indexed -0** */ +OP_HANDLER( lsr_ix ) +{ + UINT8 t; + IDXBYTE(t); + CLR_NZC; + CC |= (t & 0x01); + t >>= 1; + SET_Z8(t); + WM(EAD,t); +} + +/* $75 ILLEGAL */ + +/* $76 ROR indexed -*** */ +OP_HANDLER( ror_ix ) +{ + UINT8 t,r; + IDXBYTE(t); + r = (CC & 0x01) << 7; + CLR_NZC; + CC |= (t & 0x01); + r |= t >> 1; + SET_NZ8(r); + WM(EAD,r); +} + +/* $77 ASR indexed ?*** */ +OP_HANDLER( asr_ix ) +{ + UINT8 t; + IDXBYTE(t); + CLR_NZC; + CC |= (t & 0x01); + t = (t & 0x80) | (t >> 1); + SET_NZ8(t); + WM(EAD,t); +} + +/* $78 LSL indexed ?*** */ +OP_HANDLER( lsl_ix ) +{ + UINT8 t; + UINT16 r; + IDXBYTE(t); r=t<<1; + CLR_NZC; SET_FLAGS8(t,t,r); + WM(EAD,r); +} + +/* $79 ROL indexed -*** */ +OP_HANDLER( rol_ix ) +{ + UINT16 t,r; + IDXBYTE(t); + r = CC & 0x01; + r |= t << 1; + CLR_NZC; + SET_FLAGS8(t,t,r); + WM(EAD,r); +} + +/* $7a DEC indexed -**- */ +OP_HANDLER( dec_ix ) +{ + UINT8 t; + IDXBYTE(t); + --t; + CLR_NZ; SET_FLAGS8D(t); + WM(EAD,t); +} + +/* $7b ILLEGAL */ + +/* $7c INC indexed -**- */ +OP_HANDLER( inc_ix ) +{ + UINT8 t; + IDXBYTE(t); + ++t; + CLR_NZ; SET_FLAGS8I(t); + WM(EAD,t); +} + +/* $7d TST indexed -**- */ +OP_HANDLER( tst_ix ) +{ + UINT8 t; + IDXBYTE(t); + CLR_NZ; SET_NZ8(t); +} + +/* $7e ILLEGAL */ + +/* $7f CLR indexed -0100 */ +OP_HANDLER( clr_ix ) +{ + INDEXED; + CLR_NZC; SEZ; + WM(EAD,0); +} + +/* $80 RTI inherent #### */ +OP_HANDLER( rti ) +{ + PULLBYTE(CC); + PULLBYTE(A); + PULLBYTE(X); + PULLWORD(m_pc); +#if IRQ_LEVEL_DETECT + if( m_irq_state != CLEAR_LINE && (CC & IFLAG) == 0 ) + { + m_pending_interrupts |= M6805_INT_IRQ; + } +#endif +} + +/* $81 RTS inherent ---- */ +OP_HANDLER( rts ) +{ + PULLWORD(m_pc); +} + +/* $82 ILLEGAL */ + +/* $83 SWI absolute indirect ---- */ +OP_HANDLER( swi ) +{ + PUSHWORD(m_pc); + PUSHBYTE(m_x); + PUSHBYTE(m_a); + PUSHBYTE(m_cc); + SEI; + RM16(0xfffc, &m_pc); +} + +DERIVED_OP_HANDLER( hd63705, swi ) +{ + PUSHWORD(m_pc); + PUSHBYTE(m_x); + PUSHBYTE(m_a); + PUSHBYTE(m_cc); + SEI; + RM16(0x1ffa, &m_pc); +} +/* $84 ILLEGAL */ + +/* $85 ILLEGAL */ + +/* $86 ILLEGAL */ + +/* $87 ILLEGAL */ + +/* $88 ILLEGAL */ + +/* $89 ILLEGAL */ + +/* $8A ILLEGAL */ + +/* $8B ILLEGAL */ + +/* $8C ILLEGAL */ + +/* $8D ILLEGAL */ + +/* $8E ILLEGAL */ + +/* $8F ILLEGAL */ + +/* $90 ILLEGAL */ + +/* $91 ILLEGAL */ + +/* $92 ILLEGAL */ + +/* $93 ILLEGAL */ + +/* $94 ILLEGAL */ + +/* $95 ILLEGAL */ + +/* $96 ILLEGAL */ + +/* $97 TAX inherent ---- */ +OP_HANDLER( tax ) +{ + X = A; +} + +/* $98 CLC */ + +/* $99 SEC */ + +/* $9A CLI */ + +/* $9B SEI */ + +/* $9C RSP inherent ---- */ +OP_HANDLER( rsp ) +{ + S = SP_MASK; +} + +/* $9D NOP inherent ---- */ +OP_HANDLER( nop ) +{ +} + +/* $9E ILLEGAL */ + +/* $9F TXA inherent ---- */ +OP_HANDLER( txa ) +{ + A = X; +} + +/* $a0 SUBA immediate ?*** */ +OP_HANDLER( suba_im ) +{ + UINT16 t,r; + IMMBYTE(t); + r = A - t; + CLR_NZC; + SET_FLAGS8(A,t,r); + A = r; +} + +/* $a1 CMPA immediate ?*** */ +OP_HANDLER( cmpa_im ) +{ + UINT16 t,r; + IMMBYTE(t); + r = A - t; + CLR_NZC; + SET_FLAGS8(A,t,r); +} + +/* $a2 SBCA immediate ?*** */ +OP_HANDLER( sbca_im ) +{ + UINT16 t,r; + IMMBYTE(t); + r = A - t - (CC & 0x01); + CLR_NZC; + SET_FLAGS8(A,t,r); + A = r; +} + +/* $a3 CPX immediate -*** */ +OP_HANDLER( cpx_im ) +{ + UINT16 t,r; + IMMBYTE(t); + r = X - t; + CLR_NZC; + SET_FLAGS8(X,t,r); +} + +/* $a4 ANDA immediate -**- */ +OP_HANDLER( anda_im ) +{ + UINT8 t; + IMMBYTE(t); + A &= t; + CLR_NZ; + SET_NZ8(A); +} + +/* $a5 BITA immediate -**- */ +OP_HANDLER( bita_im ) +{ + UINT8 t,r; + IMMBYTE(t); + r = A & t; + CLR_NZ; + SET_NZ8(r); +} + +/* $a6 LDA immediate -**- */ +OP_HANDLER( lda_im ) +{ + IMMBYTE(A); + CLR_NZ; + SET_NZ8(A); +} + +/* $a7 ILLEGAL */ + +/* $a8 EORA immediate -**- */ +OP_HANDLER( eora_im ) +{ + UINT8 t; + IMMBYTE(t); + A ^= t; + CLR_NZ; + SET_NZ8(A); +} + +/* $a9 ADCA immediate **** */ +OP_HANDLER( adca_im ) +{ + UINT16 t,r; + IMMBYTE(t); + r = A + t + (CC & 0x01); + CLR_HNZC; + SET_FLAGS8(A,t,r); + SET_H(A,t,r); + A = r; +} + +/* $aa ORA immediate -**- */ +OP_HANDLER( ora_im ) +{ + UINT8 t; + IMMBYTE(t); + A |= t; + CLR_NZ; + SET_NZ8(A); +} + +/* $ab ADDA immediate **** */ +OP_HANDLER( adda_im ) +{ + UINT16 t,r; + IMMBYTE(t); + r = A + t; + CLR_HNZC; + SET_FLAGS8(A,t,r); + SET_H(A,t,r); + A = r; +} + +/* $ac ILLEGAL */ + +/* $ad BSR ---- */ +OP_HANDLER( bsr ) +{ + UINT8 t; + IMMBYTE(t); + PUSHWORD(m_pc); + PC += SIGNED(t); +} + +/* $ae LDX immediate -**- */ +OP_HANDLER( ldx_im ) +{ + IMMBYTE(X); + CLR_NZ; + SET_NZ8(X); +} + +/* $af ILLEGAL */ + +/* $b0 SUBA direct ?*** */ +OP_HANDLER( suba_di ) +{ + UINT16 t,r; + DIRBYTE(t); + r = A - t; + CLR_NZC; + SET_FLAGS8(A,t,r); + A = r; +} + +/* $b1 CMPA direct ?*** */ +OP_HANDLER( cmpa_di ) +{ + UINT16 t,r; + DIRBYTE(t); + r = A - t; + CLR_NZC; + SET_FLAGS8(A,t,r); +} + +/* $b2 SBCA direct ?*** */ +OP_HANDLER( sbca_di ) +{ + UINT16 t,r; + DIRBYTE(t); + r = A - t - (CC & 0x01); + CLR_NZC; + SET_FLAGS8(A,t,r); + A = r; +} + +/* $b3 CPX direct -*** */ +OP_HANDLER( cpx_di ) +{ + UINT16 t,r; + DIRBYTE(t); + r = X - t; + CLR_NZC; + SET_FLAGS8(X,t,r); +} + +/* $b4 ANDA direct -**- */ +OP_HANDLER( anda_di ) +{ + UINT8 t; + DIRBYTE(t); + A &= t; + CLR_NZ; + SET_NZ8(A); +} + +/* $b5 BITA direct -**- */ +OP_HANDLER( bita_di ) +{ + UINT8 t,r; + DIRBYTE(t); + r = A & t; + CLR_NZ; + SET_NZ8(r); +} + +/* $b6 LDA direct -**- */ +OP_HANDLER( lda_di ) +{ + DIRBYTE(A); + CLR_NZ; + SET_NZ8(A); +} + +/* $b7 STA direct -**- */ +OP_HANDLER( sta_di ) +{ + CLR_NZ; + SET_NZ8(A); + DIRECT; + WM(EAD,A); +} + +/* $b8 EORA direct -**- */ +OP_HANDLER( eora_di ) +{ + UINT8 t; + DIRBYTE(t); + A ^= t; + CLR_NZ; + SET_NZ8(A); +} + +/* $b9 ADCA direct **** */ +OP_HANDLER( adca_di ) +{ + UINT16 t,r; + DIRBYTE(t); + r = A + t + (CC & 0x01); + CLR_HNZC; + SET_FLAGS8(A,t,r); + SET_H(A,t,r); + A = r; +} + +/* $ba ORA direct -**- */ +OP_HANDLER( ora_di ) +{ + UINT8 t; + DIRBYTE(t); + A |= t; + CLR_NZ; + SET_NZ8(A); +} + +/* $bb ADDA direct **** */ +OP_HANDLER( adda_di ) +{ + UINT16 t,r; + DIRBYTE(t); + r = A + t; + CLR_HNZC; + SET_FLAGS8(A,t,r); + SET_H(A,t,r); + A = r; +} + +/* $bc JMP direct -*** */ +OP_HANDLER( jmp_di ) +{ + DIRECT; + PC = EA; +} + +/* $bd JSR direct ---- */ +OP_HANDLER( jsr_di ) +{ + DIRECT; + PUSHWORD(m_pc); + PC = EA; +} + +/* $be LDX direct -**- */ +OP_HANDLER( ldx_di ) +{ + DIRBYTE(X); + CLR_NZ; + SET_NZ8(X); +} + +/* $bf STX direct -**- */ +OP_HANDLER( stx_di ) +{ + CLR_NZ; + SET_NZ8(X); + DIRECT; + WM(EAD,X); +} + +/* $c0 SUBA extended ?*** */ +OP_HANDLER( suba_ex ) +{ + UINT16 t,r; + EXTBYTE(t); + r = A - t; + CLR_NZC; + SET_FLAGS8(A,t,r); + A = r; +} + +/* $c1 CMPA extended ?*** */ +OP_HANDLER( cmpa_ex ) +{ + UINT16 t,r; + EXTBYTE(t); + r = A - t; + CLR_NZC; + SET_FLAGS8(A,t,r); +} + +/* $c2 SBCA extended ?*** */ +OP_HANDLER( sbca_ex ) +{ + UINT16 t,r; + EXTBYTE(t); + r = A - t - (CC & 0x01); + CLR_NZC; + SET_FLAGS8(A,t,r); + A = r; +} + +/* $c3 CPX extended -*** */ +OP_HANDLER( cpx_ex ) +{ + UINT16 t,r; + EXTBYTE(t); + r = X - t; + CLR_NZC; + SET_FLAGS8(X,t,r); +} + +/* $c4 ANDA extended -**- */ +OP_HANDLER( anda_ex ) +{ + UINT8 t; + EXTBYTE(t); + A &= t; + CLR_NZ; + SET_NZ8(A); +} + +/* $c5 BITA extended -**- */ +OP_HANDLER( bita_ex ) +{ + UINT8 t,r; + EXTBYTE(t); + r = A & t; + CLR_NZ; + SET_NZ8(r); +} + +/* $c6 LDA extended -**- */ +OP_HANDLER( lda_ex ) +{ + EXTBYTE(A); + CLR_NZ; + SET_NZ8(A); +} + +/* $c7 STA extended -**- */ +OP_HANDLER( sta_ex ) +{ + CLR_NZ; + SET_NZ8(A); + EXTENDED; + WM(EAD,A); +} + +/* $c8 EORA extended -**- */ +OP_HANDLER( eora_ex ) +{ + UINT8 t; + EXTBYTE(t); + A ^= t; + CLR_NZ; + SET_NZ8(A); +} + +/* $c9 ADCA extended **** */ +OP_HANDLER( adca_ex ) +{ + UINT16 t,r; + EXTBYTE(t); + r = A + t + (CC & 0x01); + CLR_HNZC; + SET_FLAGS8(A,t,r); + SET_H(A,t,r); + A = r; +} + +/* $ca ORA extended -**- */ +OP_HANDLER( ora_ex ) +{ + UINT8 t; + EXTBYTE(t); + A |= t; + CLR_NZ; + SET_NZ8(A); +} + +/* $cb ADDA extended **** */ +OP_HANDLER( adda_ex ) +{ + UINT16 t,r; + EXTBYTE(t); + r = A + t; + CLR_HNZC; + SET_FLAGS8(A,t,r); + SET_H(A,t,r); + A = r; +} + +/* $cc JMP extended -*** */ +OP_HANDLER( jmp_ex ) +{ + EXTENDED; + PC = EA; +} + +/* $cd JSR extended ---- */ +OP_HANDLER( jsr_ex ) +{ + EXTENDED; + PUSHWORD(m_pc); + PC = EA; +} + +/* $ce LDX extended -**- */ +OP_HANDLER( ldx_ex ) +{ + EXTBYTE(X); + CLR_NZ; + SET_NZ8(X); +} + +/* $cf STX extended -**- */ +OP_HANDLER( stx_ex ) +{ + CLR_NZ; + SET_NZ8(X); + EXTENDED; + WM(EAD,X); +} + +/* $d0 SUBA indexed, 2 byte offset ?*** */ +OP_HANDLER( suba_ix2 ) +{ + UINT16 t,r; + IDX2BYTE(t); + r = A - t; + CLR_NZC; + SET_FLAGS8(A,t,r); + A = r; +} + +/* $d1 CMPA indexed, 2 byte offset ?*** */ +OP_HANDLER( cmpa_ix2 ) +{ + UINT16 t,r; + IDX2BYTE(t); + r = A - t; + CLR_NZC; + SET_FLAGS8(A,t,r); +} + +/* $d2 SBCA indexed, 2 byte offset ?*** */ +OP_HANDLER( sbca_ix2 ) +{ + UINT16 t,r; + IDX2BYTE(t); + r = A - t - (CC & 0x01); + CLR_NZC; + SET_FLAGS8(A,t,r); + A = r; +} + +/* $d3 CPX indexed, 2 byte offset -*** */ +OP_HANDLER( cpx_ix2 ) +{ + UINT16 t,r; + IDX2BYTE(t); + r = X - t; + CLR_NZC; + SET_FLAGS8(X,t,r); +} + +/* $d4 ANDA indexed, 2 byte offset -**- */ +OP_HANDLER( anda_ix2 ) +{ + UINT8 t; + IDX2BYTE(t); + A &= t; + CLR_NZ; + SET_NZ8(A); +} + +/* $d5 BITA indexed, 2 byte offset -**- */ +OP_HANDLER( bita_ix2 ) +{ + UINT8 t,r; + IDX2BYTE(t); + r = A & t; + CLR_NZ; + SET_NZ8(r); +} + +/* $d6 LDA indexed, 2 byte offset -**- */ +OP_HANDLER( lda_ix2 ) +{ + IDX2BYTE(A); + CLR_NZ; + SET_NZ8(A); +} + +/* $d7 STA indexed, 2 byte offset -**- */ +OP_HANDLER( sta_ix2 ) +{ + CLR_NZ; + SET_NZ8(A); + INDEXED2; + WM(EAD,A); +} + +/* $d8 EORA indexed, 2 byte offset -**- */ +OP_HANDLER( eora_ix2 ) +{ + UINT8 t; + IDX2BYTE(t); + A ^= t; + CLR_NZ; + SET_NZ8(A); +} + +/* $d9 ADCA indexed, 2 byte offset **** */ +OP_HANDLER( adca_ix2 ) +{ + UINT16 t,r; + IDX2BYTE(t); + r = A + t + (CC & 0x01); + CLR_HNZC; + SET_FLAGS8(A,t,r); + SET_H(A,t,r); + A = r; +} + +/* $da ORA indexed, 2 byte offset -**- */ +OP_HANDLER( ora_ix2 ) +{ + UINT8 t; + IDX2BYTE(t); + A |= t; + CLR_NZ; + SET_NZ8(A); +} + +/* $db ADDA indexed, 2 byte offset **** */ +OP_HANDLER( adda_ix2 ) +{ + UINT16 t,r; + IDX2BYTE(t); + r = A + t; + CLR_HNZC; + SET_FLAGS8(A,t,r); + SET_H(A,t,r); + A = r; +} + +/* $dc JMP indexed, 2 byte offset -*** */ +OP_HANDLER( jmp_ix2 ) +{ + INDEXED2; + PC = EA; +} + +/* $dd JSR indexed, 2 byte offset ---- */ +OP_HANDLER( jsr_ix2 ) +{ + INDEXED2; + PUSHWORD(m_pc); + PC = EA; +} + +/* $de LDX indexed, 2 byte offset -**- */ +OP_HANDLER( ldx_ix2 ) +{ + IDX2BYTE(X); + CLR_NZ; + SET_NZ8(X); +} + +/* $df STX indexed, 2 byte offset -**- */ +OP_HANDLER( stx_ix2 ) +{ + CLR_NZ; + SET_NZ8(X); + INDEXED2; + WM(EAD,X); +} + +/* $e0 SUBA indexed, 1 byte offset ?*** */ +OP_HANDLER( suba_ix1 ) +{ + UINT16 t,r; + IDX1BYTE(t); + r = A - t; + CLR_NZC; + SET_FLAGS8(A,t,r); + A = r; +} + +/* $e1 CMPA indexed, 1 byte offset ?*** */ +OP_HANDLER( cmpa_ix1 ) +{ + UINT16 t,r; + IDX1BYTE(t); + r = A - t; + CLR_NZC; + SET_FLAGS8(A,t,r); +} + +/* $e2 SBCA indexed, 1 byte offset ?*** */ +OP_HANDLER( sbca_ix1 ) +{ + UINT16 t,r; + IDX1BYTE(t); + r = A - t - (CC & 0x01); + CLR_NZC; + SET_FLAGS8(A,t,r); + A = r; +} + +/* $e3 CPX indexed, 1 byte offset -*** */ +OP_HANDLER( cpx_ix1 ) +{ + UINT16 t,r; + IDX1BYTE(t); + r = X - t; + CLR_NZC; + SET_FLAGS8(X,t,r); +} + +/* $e4 ANDA indexed, 1 byte offset -**- */ +OP_HANDLER( anda_ix1 ) +{ + UINT8 t; + IDX1BYTE(t); + A &= t; + CLR_NZ; + SET_NZ8(A); +} + +/* $e5 BITA indexed, 1 byte offset -**- */ +OP_HANDLER( bita_ix1 ) +{ + UINT8 t,r; + IDX1BYTE(t); + r = A & t; + CLR_NZ; + SET_NZ8(r); +} + +/* $e6 LDA indexed, 1 byte offset -**- */ +OP_HANDLER( lda_ix1 ) +{ + IDX1BYTE(A); + CLR_NZ; + SET_NZ8(A); +} + +/* $e7 STA indexed, 1 byte offset -**- */ +OP_HANDLER( sta_ix1 ) +{ + CLR_NZ; + SET_NZ8(A); + INDEXED1; + WM(EAD,A); +} + +/* $e8 EORA indexed, 1 byte offset -**- */ +OP_HANDLER( eora_ix1 ) +{ + UINT8 t; + IDX1BYTE(t); + A ^= t; + CLR_NZ; + SET_NZ8(A); +} + +/* $e9 ADCA indexed, 1 byte offset **** */ +OP_HANDLER( adca_ix1 ) +{ + UINT16 t,r; + IDX1BYTE(t); + r = A + t + (CC & 0x01); + CLR_HNZC; + SET_FLAGS8(A,t,r); + SET_H(A,t,r); + A = r; +} + +/* $ea ORA indexed, 1 byte offset -**- */ +OP_HANDLER( ora_ix1 ) +{ + UINT8 t; + IDX1BYTE(t); + A |= t; + CLR_NZ; + SET_NZ8(A); +} + +/* $eb ADDA indexed, 1 byte offset **** */ +OP_HANDLER( adda_ix1 ) +{ + UINT16 t,r; + IDX1BYTE(t); + r = A + t; + CLR_HNZC; + SET_FLAGS8(A,t,r); + SET_H(A,t,r); + A = r; +} + +/* $ec JMP indexed, 1 byte offset -*** */ +OP_HANDLER( jmp_ix1 ) +{ + INDEXED1; + PC = EA; +} + +/* $ed JSR indexed, 1 byte offset ---- */ +OP_HANDLER( jsr_ix1 ) +{ + INDEXED1; + PUSHWORD(m_pc); + PC = EA; +} + +/* $ee LDX indexed, 1 byte offset -**- */ +OP_HANDLER( ldx_ix1 ) +{ + IDX1BYTE(X); + CLR_NZ; + SET_NZ8(X); +} + +/* $ef STX indexed, 1 byte offset -**- */ +OP_HANDLER( stx_ix1 ) +{ + CLR_NZ; + SET_NZ8(X); + INDEXED1; + WM(EAD,X); +} + +/* $f0 SUBA indexed ?*** */ +OP_HANDLER( suba_ix ) +{ + UINT16 t,r; + IDXBYTE(t); + r = A - t; + CLR_NZC; + SET_FLAGS8(A,t,r); + A = r; +} + +/* $f1 CMPA indexed ?*** */ +OP_HANDLER( cmpa_ix ) +{ + UINT16 t,r; + IDXBYTE(t); + r = A - t; + CLR_NZC; + SET_FLAGS8(A,t,r); +} + +/* $f2 SBCA indexed ?*** */ +OP_HANDLER( sbca_ix ) +{ + UINT16 t,r; + IDXBYTE(t); + r = A - t - (CC & 0x01); + CLR_NZC; + SET_FLAGS8(A,t,r); + A = r; +} + +/* $f3 CPX indexed -*** */ +OP_HANDLER( cpx_ix ) +{ + UINT16 t,r; + IDXBYTE(t); + r = X - t; + CLR_NZC; + SET_FLAGS8(X,t,r); +} + +/* $f4 ANDA indexed -**- */ +OP_HANDLER( anda_ix ) +{ + UINT8 t; + IDXBYTE(t); + A &= t; + CLR_NZ; + SET_NZ8(A); +} + +/* $f5 BITA indexed -**- */ +OP_HANDLER( bita_ix ) +{ + UINT8 t,r; + IDXBYTE(t); + r = A & t; + CLR_NZ; + SET_NZ8(r); +} + +/* $f6 LDA indexed -**- */ +OP_HANDLER( lda_ix ) +{ + IDXBYTE(A); + CLR_NZ; + SET_NZ8(A); +} + +/* $f7 STA indexed -**- */ +OP_HANDLER( sta_ix ) +{ + CLR_NZ; + SET_NZ8(A); + INDEXED; + WM(EAD,A); +} + +/* $f8 EORA indexed -**- */ +OP_HANDLER( eora_ix ) +{ + UINT8 t; + IDXBYTE(t); + A ^= t; + CLR_NZ; + SET_NZ8(A); +} + +/* $f9 ADCA indexed **** */ +OP_HANDLER( adca_ix ) +{ + UINT16 t,r; + IDXBYTE(t); + r = A + t + (CC & 0x01); + CLR_HNZC; + SET_FLAGS8(A,t,r); + SET_H(A,t,r); + A = r; +} + +/* $fa ORA indexed -**- */ +OP_HANDLER( ora_ix ) +{ + UINT8 t; + IDXBYTE(t); + A |= t; + CLR_NZ; + SET_NZ8(A); +} + +/* $fb ADDA indexed **** */ +OP_HANDLER( adda_ix ) +{ + UINT16 t,r; + IDXBYTE(t); + r = A + t; + CLR_HNZC; + SET_FLAGS8(A,t,r); + SET_H(A,t,r); + A = r; +} + +/* $fc JMP indexed -*** */ +OP_HANDLER( jmp_ix ) +{ + INDEXED; + PC = EA; +} + +/* $fd JSR indexed ---- */ +OP_HANDLER( jsr_ix ) +{ + INDEXED; + PUSHWORD(m_pc); + PC = EA; +} + +/* $fe LDX indexed -**- */ +OP_HANDLER( ldx_ix ) +{ + IDXBYTE(X); + CLR_NZ; + SET_NZ8(X); +} + +/* $ff STX indexed -**- */ +OP_HANDLER( stx_ix ) +{ + CLR_NZ; + SET_NZ8(X); + INDEXED; + WM(EAD,X); +} diff --git a/src/devices/cpu/m6805/m6805.c b/src/devices/cpu/m6805/m6805.c new file mode 100644 index 00000000000..b7fc47c8dfc --- /dev/null +++ b/src/devices/cpu/m6805/m6805.c @@ -0,0 +1,1003 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*** m6805: Portable 6805 emulator ****************************************** + + m6805.c (Also supports hd68705 and hd63705 variants) + + References: + + 6809 Simulator V09, By L.C. Benschop, Eindhoven The Netherlands. + + m6809: Portable 6809 emulator, DS (6809 code in MAME, derived from + the 6809 Simulator V09) + + 6809 Microcomputer Programming & Interfacing with Experiments" + by Andrew C. Staugaard, Jr.; Howard W. Sams & Co., Inc. + + System dependencies: UINT16 must be 16 bit unsigned int + UINT8 must be 8 bit unsigned int + UINT32 must be more than 16 bits + arrays up to 65536 bytes must be supported + machine must be twos complement + + Additional Notes: + + K.Wilkins 18/03/99 - Added 63705 functonality and modified all CPU functions + necessary to support: + Variable width address bus + Different stack pointer + Alternate boot vectors + Alternate interrups vectors + + +*****************************************************************************/ + +#include "emu.h" +#include "debugger.h" +#include "m6805.h" + +#define IRQ_LEVEL_DETECT 0 + +/****************************************************************************/ +/* Read a byte from given memory location */ +/****************************************************************************/ +#define M6805_RDMEM(addr) ((unsigned)m_program->read_byte(addr)) + +/****************************************************************************/ +/* Write a byte to given memory location */ +/****************************************************************************/ +#define M6805_WRMEM(addr, value) (m_program->write_byte(addr, value)) + +/****************************************************************************/ +/* M6805_RDOP() is identical to M6805_RDMEM() except it is used for reading */ +/* opcodes. In case of system with memory mapped I/O, this function can be */ +/* used to greatly speed up emulation */ +/****************************************************************************/ +#define M6805_RDOP(addr) ((unsigned)m_direct->read_byte(addr)) + +/****************************************************************************/ +/* M6805_RDOP_ARG() is identical to M6805_RDOP() but it's used for reading */ +/* opcode arguments. This difference can be used to support systems that */ +/* use different encoding mechanisms for opcodes and opcode arguments */ +/****************************************************************************/ +#define M6805_RDOP_ARG(addr) ((unsigned)m_direct->read_byte(addr)) + +#define SP_MASK m_sp_mask /* stack pointer mask */ +#define SP_LOW m_sp_low /* stack pointer low water mark */ +#define PC m_pc.w.l /* program counter lower word */ +#define S m_s.w.l /* stack pointer lower word */ +#define A m_a /* accumulator */ +#define X m_x /* index register */ +#define CC m_cc /* condition codes */ + +#define EAD m_ea.d +#define EA m_ea.w.l + + +/* DS -- THESE ARE RE-DEFINED IN m6805.h TO RAM, ROM or FUNCTIONS IN cpuintrf.c */ +#define RM(addr) M6805_RDMEM(addr) +#define WM(addr, value) M6805_WRMEM(addr, value) +#define M_RDOP(addr) M6805_RDOP(addr) +#define M_RDOP_ARG(addr) M6805_RDOP_ARG(addr) + +/* macros to tweak the PC and SP */ +#define SP_INC if( ++S > SP_MASK) S = SP_LOW +#define SP_DEC if( --S < SP_LOW) S = SP_MASK +#define SP_ADJUST(s) ( ( (s) & SP_MASK ) | SP_LOW ) + +/* macros to access memory */ +#define IMMBYTE(b) {b = M_RDOP_ARG(PC++);} +#define IMMWORD(w) {w.d = 0; w.b.h = M_RDOP_ARG(PC); w.b.l = M_RDOP_ARG(PC+1); PC+=2;} +#define SKIPBYTE() {M_RDOP_ARG(PC++);} + +#define PUSHBYTE(b) wr_s_handler_b(&b) +#define PUSHWORD(w) wr_s_handler_w(&w) +#define PULLBYTE(b) rd_s_handler_b(&b) +#define PULLWORD(w) rd_s_handler_w(&w) + +/* CC masks H INZC + 7654 3210 */ +#define CFLAG 0x01 +#define ZFLAG 0x02 +#define NFLAG 0x04 +#define IFLAG 0x08 +#define HFLAG 0x10 + +#define CLR_NZ CC&=~(NFLAG|ZFLAG) +#define CLR_HNZC CC&=~(HFLAG|NFLAG|ZFLAG|CFLAG) +#define CLR_Z CC&=~(ZFLAG) +#define CLR_NZC CC&=~(NFLAG|ZFLAG|CFLAG) +#define CLR_ZC CC&=~(ZFLAG|CFLAG) + +/* macros for CC -- CC bits affected should be reset before calling */ +#define SET_Z(a) if(!a)SEZ +#define SET_Z8(a) SET_Z((UINT8)a) +#define SET_N8(a) CC|=((a&0x80)>>5) +#define SET_H(a,b,r) CC|=((a^b^r)&0x10) +#define SET_C8(a) CC|=((a&0x100)>>8) + +const UINT8 m6805_base_device::m_flags8i[256]= /* increment */ +{ + 0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, + 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, + 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, + 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, + 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, + 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, + 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, + 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04 +}; + +const UINT8 m6805_base_device::m_flags8d[256]= /* decrement */ +{ + 0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, + 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, + 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, + 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, + 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, + 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, + 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04, + 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04 +}; +#define SET_FLAGS8I(a) {CC |= m_flags8i[(a) & 0xff];} +#define SET_FLAGS8D(a) {CC |= m_flags8d[(a) & 0xff];} + +/* combos */ +#define SET_NZ8(a) {SET_N8(a); SET_Z(a);} +#define SET_FLAGS8(a,b,r) {SET_N8(r); SET_Z8(r); SET_C8(r);} + +/* for treating an unsigned UINT8 as a signed INT16 */ +#define SIGNED(b) ((INT16)(b & 0x80 ? b | 0xff00 : b)) + +/* Macros for addressing modes */ +#define DIRECT EAD=0; IMMBYTE(m_ea.b.l) +#define IMM8 EA = PC++ +#define EXTENDED IMMWORD(m_ea) +#define INDEXED EA = X +#define INDEXED1 {EAD = 0; IMMBYTE(m_ea.b.l); EA += X;} +#define INDEXED2 {IMMWORD(m_ea); EA += X;} + +/* macros to set status flags */ +#if defined(SEC) +#undef SEC +#endif +#define SEC CC |= CFLAG +#define CLC CC &=~ CFLAG +#define SEZ CC |= ZFLAG +#define CLZ CC &=~ ZFLAG +#define SEN CC |= NFLAG +#define CLN CC &=~ NFLAG +#define SEH CC |= HFLAG +#define CLH CC &=~ HFLAG +#define SEI CC |= IFLAG +#define CLI CC &=~ IFLAG + +/* macros for convenience */ +#define DIRBYTE(b) {DIRECT; b = RM(EAD);} +#define EXTBYTE(b) {EXTENDED; b = RM(EAD);} +#define IDXBYTE(b) {INDEXED; b = RM(EAD);} +#define IDX1BYTE(b) {INDEXED1; b = RM(EAD);} +#define IDX2BYTE(b) {INDEXED2; b = RM(EAD);} +/* Macros for branch instructions */ +#define BRANCH(f) { UINT8 t; IMMBYTE(t); if(f) { PC += SIGNED(t); } } + +/* what they say it is ... */ +const UINT8 m6805_base_device::m_cycles1[] = +{ + /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ + /*0*/ 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + /*1*/ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + /*2*/ 4, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + /*3*/ 6, 0, 0, 6, 6, 0, 6, 6, 6, 6, 6, 6, 0, 6, 6, 0, + /*4*/ 4, 0, 0, 4, 4, 0, 4, 4, 4, 4, 4, 0, 4, 4, 0, 4, + /*5*/ 4, 0, 0, 4, 4, 0, 4, 4, 4, 4, 4, 0, 4, 4, 0, 4, + /*6*/ 7, 0, 0, 7, 7, 0, 7, 7, 7, 7, 7, 0, 7, 7, 0, 7, + /*7*/ 6, 0, 0, 6, 6, 0, 6, 6, 6, 6, 6, 0, 6, 6, 0, 6, + /*8*/ 9, 6, 0,11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /*9*/ 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 0, 2, + /*A*/ 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 0, 8, 2, 0, + /*B*/ 4, 4, 4, 4, 4, 4, 4, 5, 4, 4, 4, 4, 3, 7, 4, 5, + /*C*/ 5, 5, 5, 5, 5, 5, 5, 6, 5, 5, 5, 5, 4, 8, 5, 6, + /*D*/ 6, 6, 6, 6, 6, 6, 6, 7, 6, 6, 6, 6, 5, 9, 6, 7, + /*E*/ 5, 5, 5, 5, 5, 5, 5, 6, 5, 5, 5, 5, 4, 8, 5, 6, + /*F*/ 4, 4, 4, 4, 4, 4, 4, 5, 4, 4, 4, 4, 3, 7, 4, 5 +}; + + +/* pre-clear a PAIR union; clearing h2 and h3 only might be faster? */ +#define CLEAR_PAIR(p) p->d = 0 + +void m6805_base_device::rd_s_handler_b(UINT8 *b) +{ + SP_INC; + *b = RM( S ); +} + +void m6805_base_device::rd_s_handler_w(PAIR *p) +{ + CLEAR_PAIR(p); + SP_INC; + p->b.h = RM( S ); + SP_INC; + p->b.l = RM( S ); +} + +void m6805_base_device::wr_s_handler_b(UINT8 *b) +{ + WM( S, *b ); + SP_DEC; +} + +void m6805_base_device::wr_s_handler_w(PAIR *p) +{ + WM( S, p->b.l ); + SP_DEC; + WM( S, p->b.h ); + SP_DEC; +} + +void m6805_base_device::RM16(UINT32 addr, PAIR *p) +{ + CLEAR_PAIR(p); + p->b.h = RM(addr); + ++addr; +// if( ++addr > AMASK ) addr = 0; + p->b.l = RM(addr); +} + +/* Generate interrupt - m68705 version */ +void m68705_device::interrupt() +{ + if ((m_pending_interrupts & ((1 << M6805_IRQ_LINE) | M68705_INT_MASK)) != 0 ) + { + if ((CC & IFLAG) == 0) + { + PUSHWORD(m_pc); + PUSHBYTE(m_x); + PUSHBYTE(m_a); + PUSHBYTE(m_cc); + SEI; + standard_irq_callback(0); + + if ((m_pending_interrupts & (1 << M68705_IRQ_LINE)) != 0 ) + { + m_pending_interrupts &= ~(1 << M68705_IRQ_LINE); + RM16(0xfffa, &m_pc); + } + else if ((m_pending_interrupts & (1 << M68705_INT_TIMER)) != 0) + { + m_pending_interrupts &= ~(1 << M68705_INT_TIMER); + RM16(0xfff8, &m_pc); + } + } + m_icount -= 11; + } +} + +void m6805_base_device::interrupt_vector() +{ + RM16(0xffff - 5, &m_pc); +} + +void m68hc05eg_device::interrupt_vector() +{ + if ((m_pending_interrupts & (1 << M68HC05EG_INT_IRQ)) != 0) + { + m_pending_interrupts &= ~(1 << M68HC05EG_INT_IRQ); + RM16(0x1ffa, &m_pc); + } + else if((m_pending_interrupts & (1 << M68HC05EG_INT_TIMER)) != 0) + { + m_pending_interrupts &= ~(1 << M68HC05EG_INT_TIMER); + RM16(0x1ff8, &m_pc); + } + else if((m_pending_interrupts & (1 << M68HC05EG_INT_CPI)) != 0) + { + m_pending_interrupts &= ~(1 << M68HC05EG_INT_CPI); + RM16(0x1ff6, &m_pc); + } +} + +void hd63705_device::interrupt_vector() +{ + /* Need to add emulation of other interrupt sources here KW-2/4/99 */ + /* This is just a quick patch for Namco System 2 operation */ + + if ((m_pending_interrupts & (1 << HD63705_INT_IRQ1)) != 0) + { + m_pending_interrupts &= ~(1 << HD63705_INT_IRQ1); + RM16(0x1ff8, &m_pc); + } + else if ((m_pending_interrupts & (1 << HD63705_INT_IRQ2)) != 0) + { + m_pending_interrupts &= ~(1 << HD63705_INT_IRQ2); + RM16(0x1fec, &m_pc); + } + else if ((m_pending_interrupts & (1 << HD63705_INT_ADCONV)) != 0) + { + m_pending_interrupts &= ~(1 << HD63705_INT_ADCONV); + RM16(0x1fea, &m_pc); + } + else if ((m_pending_interrupts & (1 << HD63705_INT_TIMER1)) != 0) + { + m_pending_interrupts &= ~(1 << HD63705_INT_TIMER1); + RM16(0x1ff6, &m_pc); + } + else if ((m_pending_interrupts & (1 << HD63705_INT_TIMER2)) != 0) + { + m_pending_interrupts &= ~(1 << HD63705_INT_TIMER2); + RM16(0x1ff4, &m_pc); + } + else if ((m_pending_interrupts & (1 << HD63705_INT_TIMER3)) != 0) + { + m_pending_interrupts &= ~(1<direct(); + + // set our instruction counter + m_icountptr = &m_icount; + + // register our state for the debugger + std::string tempstr; + state_add(STATE_GENPC, "GENPC", m_pc.w.l).noshow(); + state_add(STATE_GENFLAGS, "GENFLAGS", m_cc).callimport().callexport().formatstr("%8s").noshow(); + state_add(M6805_A, "A", m_a).mask(0xff); + state_add(M6805_PC, "PC", m_pc.w.l).mask(0xffff); + state_add(M6805_S, "S", m_s.w.l).mask(0xff); + state_add(M6805_X, "X", m_x).mask(0xff); + state_add(M6805_CC, "CC", m_cc).mask(0xff); + + // register for savestates + save_item(NAME(EA)); + save_item(NAME(SP_MASK)); + save_item(NAME(SP_LOW)); + save_item(NAME(A)); + save_item(NAME(PC)); + save_item(NAME(S)); + save_item(NAME(X)); + save_item(NAME(CC)); + save_item(NAME(m_pending_interrupts)); + save_item(NAME(m_irq_state)); + save_item(NAME(m_nmi_state)); +} + + +void m6805_base_device::device_reset() +{ + m_ea.w.l = 0; + m_sp_mask = 0x07f; + m_sp_low = 0x060; + m_pc.w.l = 0; + m_s.w.l = SP_MASK; + m_a = 0; + m_x = 0; + m_cc = 0; + m_pending_interrupts = 0; + + memset(m_irq_state, 0, sizeof(int) * 9); + m_nmi_state = 0; + + m_program = &space(AS_PROGRAM); + m_direct = &m_program->direct(); + + /* IRQ disabled */ + SEI; + + RM16(0xfffe, &m_pc); +} + + +//------------------------------------------------- +// memory_space_config - return the configuration +// of the specified address space, or NULL if +// the space doesn't exist +//------------------------------------------------- + +const address_space_config *m6805_base_device::memory_space_config(address_spacenum spacenum) const +{ + if (spacenum == AS_PROGRAM) + { + return &m_program_config; + } + return NULL; +} + + +//------------------------------------------------- +// state_string_export - export state as a string +// for the debugger +//------------------------------------------------- + +void m6805_base_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + switch (entry.index()) + { + case STATE_GENFLAGS: + strprintf(str, "%c%c%c%c%c%c%c%c", + (m_cc & 0x80) ? '?' : '.', + (m_cc & 0x40) ? '?' : '.', + (m_cc & 0x20) ? '?' : '.', + (m_cc & 0x10) ? 'H' : '.', + (m_cc & 0x08) ? 'I' : '.', + (m_cc & 0x04) ? 'N' : '.', + (m_cc & 0x02) ? 'Z' : '.', + (m_cc & 0x01) ? 'C' : '.'); + break; + } +} + + +//------------------------------------------------- +// disasm_min_opcode_bytes - return the length +// of the shortest instruction, in bytes +//------------------------------------------------- + +UINT32 m6805_base_device::disasm_min_opcode_bytes() const +{ + return 1; +} + + +//------------------------------------------------- +// disasm_max_opcode_bytes - return the length +// of the longest instruction, in bytes +//------------------------------------------------- + +UINT32 m6805_base_device::disasm_max_opcode_bytes() const +{ + return 3; +} + + +//------------------------------------------------- +// disasm_disassemble - call the disassembly +// helper function +//------------------------------------------------- + +offs_t m6805_base_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( m6805 ); + return CPU_DISASSEMBLE_NAME(m6805)(this, buffer, pc, oprom, opram, options); +} + + +void m6805_device::execute_set_input(int inputnum, int state) +{ + /* Basic 6805 only has one IRQ line */ + /* See HD63705 specific version */ + if (m_irq_state[0] != state) + { + m_irq_state[0] = state; + + if (state != CLEAR_LINE) + { + m_pending_interrupts |= 1 << M6805_IRQ_LINE; + } + } +} + +#include "6805ops.inc" + +//------------------------------------------------- +// execute_clocks_to_cycles - convert the raw +// clock into cycles per second +//------------------------------------------------- + +UINT64 m6805_base_device::execute_clocks_to_cycles(UINT64 clocks) const +{ + return (clocks + 3) / 4; +} + + +//------------------------------------------------- +// execute_cycles_to_clocks - convert a cycle +// count back to raw clocks +//------------------------------------------------- + +UINT64 m6805_base_device::execute_cycles_to_clocks(UINT64 cycles) const +{ + return cycles * 4; +} + + +//------------------------------------------------- +// execute_min_cycles - return minimum number of +// cycles it takes for one instruction to execute +//------------------------------------------------- + +UINT32 m6805_base_device::execute_min_cycles() const +{ + return 2; +} + + +//------------------------------------------------- +// execute_max_cycles - return maximum number of +// cycles it takes for one instruction to execute +//------------------------------------------------- + +UINT32 m6805_base_device::execute_max_cycles() const +{ + return 10; +} + + +//------------------------------------------------- +// execute_input_lines - return the number of +// input/interrupt lines +//------------------------------------------------- + +UINT32 m6805_base_device::execute_input_lines() const +{ + return 9; +} + + +/* execute instructions on this CPU until icount expires */ +void m6805_base_device::execute_run() +{ + UINT8 ireg; + + S = SP_ADJUST( S ); /* Taken from CPU_SET_CONTEXT when pointer'afying */ + + do + { + if (m_pending_interrupts != 0) + { + interrupt(); + } + + debugger_instruction_hook(this, PC); + + ireg=M_RDOP(PC++); + + switch( ireg ) + { + case 0x00: brset(0x01); break; + case 0x01: brclr(0x01); break; + case 0x02: brset(0x02); break; + case 0x03: brclr(0x02); break; + case 0x04: brset(0x04); break; + case 0x05: brclr(0x04); break; + case 0x06: brset(0x08); break; + case 0x07: brclr(0x08); break; + case 0x08: brset(0x10); break; + case 0x09: brclr(0x10); break; + case 0x0A: brset(0x20); break; + case 0x0B: brclr(0x20); break; + case 0x0C: brset(0x40); break; + case 0x0D: brclr(0x40); break; + case 0x0E: brset(0x80); break; + case 0x0F: brclr(0x80); break; + case 0x10: bset(0x01); break; + case 0x11: bclr(0x01); break; + case 0x12: bset(0x02); break; + case 0x13: bclr(0x02); break; + case 0x14: bset(0x04); break; + case 0x15: bclr(0x04); break; + case 0x16: bset(0x08); break; + case 0x17: bclr(0x08); break; + case 0x18: bset(0x10); break; + case 0x19: bclr(0x10); break; + case 0x1a: bset(0x20); break; + case 0x1b: bclr(0x20); break; + case 0x1c: bset(0x40); break; + case 0x1d: bclr(0x40); break; + case 0x1e: bset(0x80); break; + case 0x1f: bclr(0x80); break; + case 0x20: bra(); break; + case 0x21: brn(); break; + case 0x22: bhi(); break; + case 0x23: bls(); break; + case 0x24: bcc(); break; + case 0x25: bcs(); break; + case 0x26: bne(); break; + case 0x27: beq(); break; + case 0x28: bhcc(); break; + case 0x29: bhcs(); break; + case 0x2a: bpl(); break; + case 0x2b: bmi(); break; + case 0x2c: bmc(); break; + case 0x2d: bms(); break; + case 0x2e: bil(); break; + case 0x2f: bih(); break; + case 0x30: neg_di(); break; + case 0x31: illegal(); break; + case 0x32: illegal(); break; + case 0x33: com_di(); break; + case 0x34: lsr_di(); break; + case 0x35: illegal(); break; + case 0x36: ror_di(); break; + case 0x37: asr_di(); break; + case 0x38: lsl_di(); break; + case 0x39: rol_di(); break; + case 0x3a: dec_di(); break; + case 0x3b: illegal(); break; + case 0x3c: inc_di(); break; + case 0x3d: tst_di(); break; + case 0x3e: illegal(); break; + case 0x3f: clr_di(); break; + case 0x40: nega(); break; + case 0x41: illegal(); break; + case 0x42: illegal(); break; + case 0x43: coma(); break; + case 0x44: lsra(); break; + case 0x45: illegal(); break; + case 0x46: rora(); break; + case 0x47: asra(); break; + case 0x48: lsla(); break; + case 0x49: rola(); break; + case 0x4a: deca(); break; + case 0x4b: illegal(); break; + case 0x4c: inca(); break; + case 0x4d: tsta(); break; + case 0x4e: illegal(); break; + case 0x4f: clra(); break; + case 0x50: negx(); break; + case 0x51: illegal(); break; + case 0x52: illegal(); break; + case 0x53: comx(); break; + case 0x54: lsrx(); break; + case 0x55: illegal(); break; + case 0x56: rorx(); break; + case 0x57: asrx(); break; + case 0x58: aslx(); break; + case 0x59: rolx(); break; + case 0x5a: decx(); break; + case 0x5b: illegal(); break; + case 0x5c: incx(); break; + case 0x5d: tstx(); break; + case 0x5e: illegal(); break; + case 0x5f: clrx(); break; + case 0x60: neg_ix1(); break; + case 0x61: illegal(); break; + case 0x62: illegal(); break; + case 0x63: com_ix1(); break; + case 0x64: lsr_ix1(); break; + case 0x65: illegal(); break; + case 0x66: ror_ix1(); break; + case 0x67: asr_ix1(); break; + case 0x68: lsl_ix1(); break; + case 0x69: rol_ix1(); break; + case 0x6a: dec_ix1(); break; + case 0x6b: illegal(); break; + case 0x6c: inc_ix1(); break; + case 0x6d: tst_ix1(); break; + case 0x6e: illegal(); break; + case 0x6f: clr_ix1(); break; + case 0x70: neg_ix(); break; + case 0x71: illegal(); break; + case 0x72: illegal(); break; + case 0x73: com_ix(); break; + case 0x74: lsr_ix(); break; + case 0x75: illegal(); break; + case 0x76: ror_ix(); break; + case 0x77: asr_ix(); break; + case 0x78: lsl_ix(); break; + case 0x79: rol_ix(); break; + case 0x7a: dec_ix(); break; + case 0x7b: illegal(); break; + case 0x7c: inc_ix(); break; + case 0x7d: tst_ix(); break; + case 0x7e: illegal(); break; + case 0x7f: clr_ix(); break; + case 0x80: rti(); break; + case 0x81: rts(); break; + case 0x82: illegal(); break; + case 0x83: swi(); break; + case 0x84: illegal(); break; + case 0x85: illegal(); break; + case 0x86: illegal(); break; + case 0x87: illegal(); break; + case 0x88: illegal(); break; + case 0x89: illegal(); break; + case 0x8a: illegal(); break; + case 0x8b: illegal(); break; + case 0x8c: illegal(); break; + case 0x8d: illegal(); break; + case 0x8e: illegal(); break; + case 0x8f: illegal(); break; + case 0x90: illegal(); break; + case 0x91: illegal(); break; + case 0x92: illegal(); break; + case 0x93: illegal(); break; + case 0x94: illegal(); break; + case 0x95: illegal(); break; + case 0x96: illegal(); break; + case 0x97: tax(); break; + case 0x98: CLC; break; + case 0x99: SEC; break; +#if IRQ_LEVEL_DETECT + case 0x9a: CLI; if (m_irq_state != CLEAR_LINE) m_pending_interrupts |= 1 << M6805_IRQ_LINE; break; +#else + case 0x9a: CLI; break; +#endif + case 0x9b: SEI; break; + case 0x9c: rsp(); break; + case 0x9d: nop(); break; + case 0x9e: illegal(); break; + case 0x9f: txa(); break; + case 0xa0: suba_im(); break; + case 0xa1: cmpa_im(); break; + case 0xa2: sbca_im(); break; + case 0xa3: cpx_im(); break; + case 0xa4: anda_im(); break; + case 0xa5: bita_im(); break; + case 0xa6: lda_im(); break; + case 0xa7: illegal(); break; + case 0xa8: eora_im(); break; + case 0xa9: adca_im(); break; + case 0xaa: ora_im(); break; + case 0xab: adda_im(); break; + case 0xac: illegal(); break; + case 0xad: bsr(); break; + case 0xae: ldx_im(); break; + case 0xaf: illegal(); break; + case 0xb0: suba_di(); break; + case 0xb1: cmpa_di(); break; + case 0xb2: sbca_di(); break; + case 0xb3: cpx_di(); break; + case 0xb4: anda_di(); break; + case 0xb5: bita_di(); break; + case 0xb6: lda_di(); break; + case 0xb7: sta_di(); break; + case 0xb8: eora_di(); break; + case 0xb9: adca_di(); break; + case 0xba: ora_di(); break; + case 0xbb: adda_di(); break; + case 0xbc: jmp_di(); break; + case 0xbd: jsr_di(); break; + case 0xbe: ldx_di(); break; + case 0xbf: stx_di(); break; + case 0xc0: suba_ex(); break; + case 0xc1: cmpa_ex(); break; + case 0xc2: sbca_ex(); break; + case 0xc3: cpx_ex(); break; + case 0xc4: anda_ex(); break; + case 0xc5: bita_ex(); break; + case 0xc6: lda_ex(); break; + case 0xc7: sta_ex(); break; + case 0xc8: eora_ex(); break; + case 0xc9: adca_ex(); break; + case 0xca: ora_ex(); break; + case 0xcb: adda_ex(); break; + case 0xcc: jmp_ex(); break; + case 0xcd: jsr_ex(); break; + case 0xce: ldx_ex(); break; + case 0xcf: stx_ex(); break; + case 0xd0: suba_ix2(); break; + case 0xd1: cmpa_ix2(); break; + case 0xd2: sbca_ix2(); break; + case 0xd3: cpx_ix2(); break; + case 0xd4: anda_ix2(); break; + case 0xd5: bita_ix2(); break; + case 0xd6: lda_ix2(); break; + case 0xd7: sta_ix2(); break; + case 0xd8: eora_ix2(); break; + case 0xd9: adca_ix2(); break; + case 0xda: ora_ix2(); break; + case 0xdb: adda_ix2(); break; + case 0xdc: jmp_ix2(); break; + case 0xdd: jsr_ix2(); break; + case 0xde: ldx_ix2(); break; + case 0xdf: stx_ix2(); break; + case 0xe0: suba_ix1(); break; + case 0xe1: cmpa_ix1(); break; + case 0xe2: sbca_ix1(); break; + case 0xe3: cpx_ix1(); break; + case 0xe4: anda_ix1(); break; + case 0xe5: bita_ix1(); break; + case 0xe6: lda_ix1(); break; + case 0xe7: sta_ix1(); break; + case 0xe8: eora_ix1(); break; + case 0xe9: adca_ix1(); break; + case 0xea: ora_ix1(); break; + case 0xeb: adda_ix1(); break; + case 0xec: jmp_ix1(); break; + case 0xed: jsr_ix1(); break; + case 0xee: ldx_ix1(); break; + case 0xef: stx_ix1(); break; + case 0xf0: suba_ix(); break; + case 0xf1: cmpa_ix(); break; + case 0xf2: sbca_ix(); break; + case 0xf3: cpx_ix(); break; + case 0xf4: anda_ix(); break; + case 0xf5: bita_ix(); break; + case 0xf6: lda_ix(); break; + case 0xf7: sta_ix(); break; + case 0xf8: eora_ix(); break; + case 0xf9: adca_ix(); break; + case 0xfa: ora_ix(); break; + case 0xfb: adda_ix(); break; + case 0xfc: jmp_ix(); break; + case 0xfd: jsr_ix(); break; + case 0xfe: ldx_ix(); break; + case 0xff: stx_ix(); break; + } + m_icount -= m_cycles1[ireg]; + } while( m_icount > 0 ); +} + +/**************************************************************************** + * M68HC05EG section + ****************************************************************************/ +void m68hc05eg_device::device_reset() +{ + m6805_base_device::device_reset(); + + m_sp_mask = 0xff; + m_sp_low = 0xc0; + + RM16(0x1ffe, &m_pc); +} + +void m68hc05eg_device::execute_set_input(int inputnum, int state) +{ + if (m_irq_state[inputnum] != state) + { + m_irq_state[inputnum] = state; + + if (state != CLEAR_LINE) + { + m_pending_interrupts |= 1 << inputnum; + } + } +} + + +/**************************************************************************** + * M68705 section + ****************************************************************************/ +void m68705_device::device_reset() +{ + m6805_base_device::device_reset(); + + RM16(0xfffe, &m_pc); +} + +void m68705_device::execute_set_input(int inputnum, int state) +{ + if (m_irq_state[inputnum] != state) + { + m_irq_state[inputnum] = state; + + if (state != CLEAR_LINE) + { + m_pending_interrupts |= 1 << inputnum; + } + } +} + + +/**************************************************************************** + * HD63705 section + ****************************************************************************/ +void hd63705_device::device_reset() +{ + m6805_base_device::device_reset(); + + m_sp_mask = 0x17f; + m_sp_low = 0x100; + m_s.w.l = SP_MASK; + + RM16(0x1ffe, &m_pc); +} + +void hd63705_device::execute_set_input(int inputnum, int state) +{ + if (inputnum == INPUT_LINE_NMI) + { + if (m_nmi_state != state) + { + m_nmi_state = state; + + if (state != CLEAR_LINE) + { + m_pending_interrupts |= 1 << HD63705_INT_NMI; + } + } + } + else if (inputnum <= HD63705_INT_ADCONV) + { + if (m_irq_state[inputnum] != state) + { + m_irq_state[inputnum] = state; + + if (state != CLEAR_LINE) + { + m_pending_interrupts |= 1 << inputnum; + } + } + } +} + +const device_type M6805 = &device_creator; +const device_type M68HC05EG = &device_creator; +const device_type M68705 = &device_creator; +const device_type HD63705 = &device_creator; diff --git a/src/devices/cpu/m6805/m6805.h b/src/devices/cpu/m6805/m6805.h new file mode 100644 index 00000000000..26bccefbd15 --- /dev/null +++ b/src/devices/cpu/m6805/m6805.h @@ -0,0 +1,418 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*** m6805: Portable 6805 emulator ******************************************/ + +#pragma once + +#ifndef __M6805_H__ +#define __M6805_H__ + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class m6805_device; + +// device type definition +extern const device_type M6805; +extern const device_type M68HC05EG; +extern const device_type M68705; +extern const device_type HD63705; + +// ======================> m6805_base_device + +// Used by core CPU interface +class m6805_base_device : public cpu_device +{ +public: + // construction/destruction + m6805_base_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock, const device_type type, const char *name, UINT32 addr_width, const char *shortname, const char *source); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_execute_interface overrides + virtual UINT32 execute_min_cycles() const; + virtual UINT32 execute_max_cycles() const; + virtual UINT32 execute_input_lines() const; + virtual void execute_run(); + virtual void execute_set_input(int inputnum, int state) = 0; + virtual UINT64 execute_clocks_to_cycles(UINT64 clocks) const; + virtual UINT64 execute_cycles_to_clocks(UINT64 cycles) const; + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const; + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const; + virtual UINT32 disasm_max_opcode_bytes() const; + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + + // device_state_interface overrides + virtual void state_string_export(const device_state_entry &entry, std::string &str); + +private: + // opcode/condition tables + static const UINT8 m_flags8i[256]; + static const UINT8 m_flags8d[256]; + static const UINT8 m_cycles1[256]; + +protected: + void rd_s_handler_b(UINT8 *b); + void rd_s_handler_w(PAIR *p); + void wr_s_handler_b(UINT8 *b); + void wr_s_handler_w(PAIR *p); + void RM16(UINT32 addr, PAIR *p); + + void brset(UINT8 bit); + void brclr(UINT8 bit); + void bset(UINT8 bit); + void bclr(UINT8 bit); + + void bra(); + void brn(); + void bhi(); + void bls(); + void bcc(); + void bcs(); + void bne(); + void beq(); + void bhcc(); + void bhcs(); + void bpl(); + void bmi(); + void bmc(); + void bms(); + virtual void bil(); + virtual void bih(); + void bsr(); + + void neg_di(); + void com_di(); + void lsr_di(); + void ror_di(); + void asr_di(); + void lsl_di(); + void rol_di(); + void dec_di(); + void inc_di(); + void tst_di(); + void clr_di(); + + void nega(); + void coma(); + void lsra(); + void rora(); + void asra(); + void lsla(); + void rola(); + void deca(); + void inca(); + void tsta(); + void clra(); + + void negx(); + void comx(); + void lsrx(); + void rorx(); + void asrx(); + void aslx(); + void lslx(); + void rolx(); + void decx(); + void incx(); + void tstx(); + void clrx(); + + void neg_ix1(); + void com_ix1(); + void lsr_ix1(); + void ror_ix1(); + void asr_ix1(); + void lsl_ix1(); + void rol_ix1(); + void dec_ix1(); + void inc_ix1(); + void tst_ix1(); + void clr_ix1(); + + void neg_ix(); + void com_ix(); + void lsr_ix(); + void ror_ix(); + void asr_ix(); + void lsl_ix(); + void rol_ix(); + void dec_ix(); + void inc_ix(); + void tst_ix(); + void clr_ix(); + + void rti(); + void rts(); + virtual void swi(); + + void tax(); + void txa(); + + void rsp(); + void nop(); + + void suba_im(); + void cmpa_im(); + void sbca_im(); + void cpx_im(); + void anda_im(); + void bita_im(); + void lda_im(); + void eora_im(); + void adca_im(); + void ora_im(); + void adda_im(); + + void ldx_im(); + void suba_di(); + void cmpa_di(); + void sbca_di(); + void cpx_di(); + void anda_di(); + void bita_di(); + void lda_di(); + void sta_di(); + void eora_di(); + void adca_di(); + void ora_di(); + void adda_di(); + void jmp_di(); + void jsr_di(); + void ldx_di(); + void stx_di(); + void suba_ex(); + void cmpa_ex(); + void sbca_ex(); + void cpx_ex(); + void anda_ex(); + void bita_ex(); + void lda_ex(); + void sta_ex(); + void eora_ex(); + void adca_ex(); + void ora_ex(); + void adda_ex(); + void jmp_ex(); + void jsr_ex(); + void ldx_ex(); + void stx_ex(); + void suba_ix2(); + void cmpa_ix2(); + void sbca_ix2(); + void cpx_ix2(); + void anda_ix2(); + void bita_ix2(); + void lda_ix2(); + void sta_ix2(); + void eora_ix2(); + void adca_ix2(); + void ora_ix2(); + void adda_ix2(); + void jmp_ix2(); + void jsr_ix2(); + void ldx_ix2(); + void stx_ix2(); + void suba_ix1(); + void cmpa_ix1(); + void sbca_ix1(); + void cpx_ix1(); + void anda_ix1(); + void bita_ix1(); + void lda_ix1(); + void sta_ix1(); + void eora_ix1(); + void adca_ix1(); + void ora_ix1(); + void adda_ix1(); + void jmp_ix1(); + void jsr_ix1(); + void ldx_ix1(); + void stx_ix1(); + void suba_ix(); + void cmpa_ix(); + void sbca_ix(); + void cpx_ix(); + void anda_ix(); + void bita_ix(); + void lda_ix(); + void sta_ix(); + void eora_ix(); + void adca_ix(); + void ora_ix(); + void adda_ix(); + void jmp_ix(); + void jsr_ix(); + void ldx_ix(); + void stx_ix(); + + void illegal(); + + virtual void interrupt(); + virtual void interrupt_vector(); + + const char *m_tag; + + // address spaces + const address_space_config m_program_config; + + // CPU registers + PAIR m_ea; /* effective address */ + + UINT32 m_sp_mask; /* Stack pointer address mask */ + UINT32 m_sp_low; /* Stack pointer low water mark (or floor) */ + PAIR m_pc; /* Program counter */ + PAIR m_s; /* Stack pointer */ + UINT8 m_a; /* Accumulator */ + UINT8 m_x; /* Index register */ + UINT8 m_cc; /* Condition codes */ + + UINT16 m_pending_interrupts; /* MB */ + + int m_irq_state[9]; /* KW Additional lines for HD63705 */ + int m_nmi_state; + + // other internal states + int m_icount; + + // address spaces + address_space *m_program; + direct_read_data *m_direct; +}; + +// ======================> m6805_device + +class m6805_device : public m6805_base_device +{ +public: + // construction/destruction + m6805_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : m6805_base_device(mconfig, tag, owner, clock, M6805, "M6805", 12, "m6805", __FILE__) { } + +protected: + virtual void execute_set_input(int inputnum, int state); +}; + +// ======================> m68hc05eg_device + +class m68hc05eg_device : public m6805_base_device +{ +public: + // construction/destruction + m68hc05eg_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : m6805_base_device(mconfig, tag, owner, clock, M68HC05EG, "M68HC05EG", 13, "m68hc05eg", __FILE__) { } + +protected: + // device-level overrides + virtual void device_reset(); + + virtual void execute_set_input(int inputnum, int state); + + virtual void interrupt_vector(); +}; + +// ======================> m68705_device + +class m68705_device : public m6805_base_device +{ +public: + // construction/destruction + m68705_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : m6805_base_device(mconfig, tag, owner, clock, M68705, "M68705", 12, "m68705", __FILE__) { } + +protected: + // device-level overrides + virtual void device_reset(); + + virtual void execute_set_input(int inputnum, int state); + + virtual void interrupt(); +}; + +// ======================> hd63705_device + +class hd63705_device : public m6805_base_device +{ +public: + // construction/destruction + hd63705_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : m6805_base_device(mconfig, tag, owner, clock, HD63705, "HD63705", 16, "hd63705", __FILE__) { } + +protected: + // device-level overrides + virtual void device_reset(); + + virtual void execute_set_input(int inputnum, int state); + + virtual void interrupt_vector(); + + // opcodes + virtual void bil(); + virtual void bih(); + virtual void swi(); +}; + +enum { M6805_PC=1, M6805_S, M6805_CC, M6805_A, M6805_X, M6805_IRQ_STATE }; + +#define M6805_IRQ_LINE 0 + +/**************************************************************************** + * 68HC05EG section + ****************************************************************************/ + +#define M68HC05EG_INT_IRQ (M6805_IRQ_LINE) +#define M68HC05EG_INT_TIMER (M6805_IRQ_LINE+1) +#define M68HC05EG_INT_CPI (M6805_IRQ_LINE+2) + +/**************************************************************************** + * 68705 section + ****************************************************************************/ + +#define M68705_A M6805_A +#define M68705_PC M6805_PC +#define M68705_S M6805_S +#define M68705_X M6805_X +#define M68705_CC M6805_CC +#define M68705_IRQ_STATE M6805_IRQ_STATE + +#define M68705_INT_MASK 0x03 +#define M68705_IRQ_LINE M6805_IRQ_LINE +#define M68705_INT_TIMER 0x01 + +/**************************************************************************** + * HD63705 section + ****************************************************************************/ + +#define HD63705_A M6805_A +#define HD63705_PC M6805_PC +#define HD63705_S M6805_S +#define HD63705_X M6805_X +#define HD63705_CC M6805_CC +#define HD63705_NMI_STATE M6805_IRQ_STATE +#define HD63705_IRQ1_STATE M6805_IRQ_STATE+1 +#define HD63705_IRQ2_STATE M6805_IRQ_STATE+2 +#define HD63705_ADCONV_STATE M6805_IRQ_STATE+3 + +#define HD63705_INT_MASK 0x1ff + +#define HD63705_INT_IRQ1 0x00 +#define HD63705_INT_IRQ2 0x01 +#define HD63705_INT_TIMER1 0x02 +#define HD63705_INT_TIMER2 0x03 +#define HD63705_INT_TIMER3 0x04 +#define HD63705_INT_PCI 0x05 +#define HD63705_INT_SCI 0x06 +#define HD63705_INT_ADCONV 0x07 +#define HD63705_INT_NMI 0x08 + +CPU_DISASSEMBLE( m6805 ); + +#endif /* __M6805_H__ */ diff --git a/src/devices/cpu/m6809/6309dasm.c b/src/devices/cpu/m6809/6309dasm.c new file mode 100644 index 00000000000..d39f03796e2 --- /dev/null +++ b/src/devices/cpu/m6809/6309dasm.c @@ -0,0 +1,943 @@ +// license:BSD-3-Clause +// copyright-holders:Nathan Woods,Tim Lindner +/***************************************************************************** + + 6309dasm.c - a 6309 opcode disassembler + Version 1.0 5-AUG-2000 + Copyright Tim Lindner + + Based on: + 6809dasm.c - a 6809 opcode disassembler + Version 1.4 1-MAR-95 + Copyright Sean Riddle + + Thanks to Franklin Bowen for bug fixes, ideas + + Freely distributable on any medium given all copyrights are retained + by the author and no charge greater than $7.00 is made for obtaining + this software + + Please send all bug reports, update ideas and data files to: + tlindner@ix.netcom.com + +*****************************************************************************/ + +#include "emu.h" +#include "debugger.h" +#include "hd6309.h" + +// Opcode structure +struct opcodeinfo +{ + UINT8 opcode; // 8-bit opcode value + UINT8 length; // Opcode length in bytes + char name[6]; // Opcode name + UINT8 mode; // Addressing mode + unsigned flags; // Disassembly flags +}; + +enum hd6309_addressing_modes +{ + INH, // Inherent + DIR, // Direct + DIR_IM, // Direct in memory (6309 only) + IND, // Indexed + REL, // Relative (8 bit) + LREL, // Long relative (16 bit) + EXT, // Extended + IMM, // Immediate + IMM_RR, // Register-to-register + IMM_BW, // Bitwise operations (6309 only) + IMM_TFM, // Transfer from memory (6309 only) + PG1, // Switch to page 1 opcodes + PG2 // Switch to page 2 opcodes +}; + +// Page 0 opcodes (single byte) +static const opcodeinfo hd6309_pg0opcodes[] = +{ + { 0x00, 2, "NEG", DIR }, + { 0x01, 3, "OIM", DIR_IM }, + { 0x02, 3, "AIM", DIR_IM }, + { 0x03, 2, "COM", DIR }, + { 0x04, 2, "LSR", DIR }, + { 0x05, 3, "EIM", DIR_IM }, + { 0x06, 2, "ROR", DIR }, + { 0x07, 2, "ASR", DIR }, + { 0x08, 2, "ASL", DIR }, + { 0x09, 2, "ROL", DIR }, + { 0x0A, 2, "DEC", DIR }, + { 0x0B, 3, "TIM", DIR_IM }, + { 0x0C, 2, "INC", DIR }, + { 0x0D, 2, "TST", DIR }, + { 0x0E, 2, "JMP", DIR }, + { 0x0F, 2, "CLR", DIR }, + + { 0x10, 1, "page1", PG1 }, + { 0x11, 1, "page2", PG2 }, + { 0x12, 1, "NOP", INH }, + { 0x13, 1, "SYNC", INH }, + { 0x14, 1, "SEXW", INH }, + { 0x16, 3, "LBRA", LREL }, + { 0x17, 3, "LBSR", LREL , DASMFLAG_STEP_OVER }, + { 0x19, 1, "DAA", INH }, + { 0x1A, 2, "ORCC", IMM }, + { 0x1C, 2, "ANDCC", IMM }, + { 0x1D, 1, "SEX", INH }, + { 0x1E, 2, "EXG", IMM_RR }, + { 0x1F, 2, "TFR", IMM_RR }, + + { 0x20, 2, "BRA", REL }, + { 0x21, 2, "BRN", REL }, + { 0x22, 2, "BHI", REL }, + { 0x23, 2, "BLS", REL }, + { 0x24, 2, "BCC", REL }, + { 0x25, 2, "BCS", REL }, + { 0x26, 2, "BNE", REL }, + { 0x27, 2, "BEQ", REL }, + { 0x28, 2, "BVC", REL }, + { 0x29, 2, "BVS", REL }, + { 0x2A, 2, "BPL", REL }, + { 0x2B, 2, "BMI", REL }, + { 0x2C, 2, "BGE", REL }, + { 0x2D, 2, "BLT", REL }, + { 0x2E, 2, "BGT", REL }, + { 0x2F, 2, "BLE", REL }, + + { 0x30, 2, "LEAX", IND }, + { 0x31, 2, "LEAY", IND }, + { 0x32, 2, "LEAS", IND }, + { 0x33, 2, "LEAU", IND }, + { 0x34, 2, "PSHS", INH }, + { 0x35, 2, "PULS", INH }, + { 0x36, 2, "PSHU", INH }, + { 0x37, 2, "PULU", INH }, + { 0x39, 1, "RTS", INH }, + { 0x3A, 1, "ABX", INH }, + { 0x3B, 1, "RTI", INH }, + { 0x3C, 2, "CWAI", IMM }, + { 0x3D, 1, "MUL", INH }, + { 0x3F, 1, "SWI", INH }, + + { 0x40, 1, "NEGA", INH }, + { 0x43, 1, "COMA", INH }, + { 0x44, 1, "LSRA", INH }, + { 0x46, 1, "RORA", INH }, + { 0x47, 1, "ASRA", INH }, + { 0x48, 1, "ASLA", INH }, + { 0x49, 1, "ROLA", INH }, + { 0x4A, 1, "DECA", INH }, + { 0x4C, 1, "INCA", INH }, + { 0x4D, 1, "TSTA", INH }, + { 0x4F, 1, "CLRA", INH }, + + { 0x50, 1, "NEGB", INH }, + { 0x53, 1, "COMB", INH }, + { 0x54, 1, "LSRB", INH }, + { 0x56, 1, "RORB", INH }, + { 0x57, 1, "ASRB", INH }, + { 0x58, 1, "ASLB", INH }, + { 0x59, 1, "ROLB", INH }, + { 0x5A, 1, "DECB", INH }, + { 0x5C, 1, "INCB", INH }, + { 0x5D, 1, "TSTB", INH }, + { 0x5F, 1, "CLRB", INH }, + + { 0x60, 2, "NEG", IND }, + { 0x61, 3, "OIM", IND }, + { 0x62, 3, "AIM", IND }, + { 0x63, 2, "COM", IND }, + { 0x64, 2, "LSR", IND }, + { 0x65, 3, "EIM", IND }, + { 0x66, 2, "ROR", IND }, + { 0x67, 2, "ASR", IND }, + { 0x68, 2, "ASL", IND }, + { 0x69, 2, "ROL", IND }, + { 0x6A, 2, "DEC", IND }, + { 0x6B, 3, "TIM", IND }, + { 0x6C, 2, "INC", IND }, + { 0x6D, 2, "TST", IND }, + { 0x6E, 2, "JMP", IND }, + { 0x6F, 2, "CLR", IND }, + + { 0x70, 3, "NEG", EXT }, + { 0x71, 4, "OIM", EXT }, + { 0x72, 4, "AIM", EXT }, + { 0x73, 3, "COM", EXT }, + { 0x74, 3, "LSR", EXT }, + { 0x75, 4, "EIM", EXT }, + { 0x76, 3, "ROR", EXT }, + { 0x77, 3, "ASR", EXT }, + { 0x78, 3, "ASL", EXT }, + { 0x79, 3, "ROL", EXT }, + { 0x7A, 3, "DEC", EXT }, + { 0x7B, 4, "TIM", EXT }, + { 0x7C, 3, "INC", EXT }, + { 0x7D, 3, "TST", EXT }, + { 0x7E, 3, "JMP", EXT }, + { 0x7F, 3, "CLR", EXT }, + + { 0x80, 2, "SUBA", IMM }, + { 0x81, 2, "CMPA", IMM }, + { 0x82, 2, "SBCA", IMM }, + { 0x83, 3, "SUBD", IMM }, + { 0x84, 2, "ANDA", IMM }, + { 0x85, 2, "BITA", IMM }, + { 0x86, 2, "LDA", IMM }, + { 0x88, 2, "EORA", IMM }, + { 0x89, 2, "ADCA", IMM }, + { 0x8A, 2, "ORA", IMM }, + { 0x8B, 2, "ADDA", IMM }, + { 0x8C, 3, "CMPX", IMM }, + { 0x8D, 2, "BSR", REL , DASMFLAG_STEP_OVER }, + { 0x8E, 3, "LDX", IMM }, + + { 0x90, 2, "SUBA", DIR }, + { 0x91, 2, "CMPA", DIR }, + { 0x92, 2, "SBCA", DIR }, + { 0x93, 2, "SUBD", DIR }, + { 0x94, 2, "ANDA", DIR }, + { 0x95, 2, "BITA", DIR }, + { 0x96, 2, "LDA", DIR }, + { 0x97, 2, "STA", DIR }, + { 0x98, 2, "EORA", DIR }, + { 0x99, 2, "ADCA", DIR }, + { 0x9A, 2, "ORA", DIR }, + { 0x9B, 2, "ADDA", DIR }, + { 0x9C, 2, "CMPX", DIR }, + { 0x9D, 2, "JSR", DIR , DASMFLAG_STEP_OVER }, + { 0x9E, 2, "LDX", DIR }, + { 0x9F, 2, "STX", DIR }, + + { 0xA0, 2, "SUBA", IND }, + { 0xA1, 2, "CMPA", IND }, + { 0xA2, 2, "SBCA", IND }, + { 0xA3, 2, "SUBD", IND }, + { 0xA4, 2, "ANDA", IND }, + { 0xA5, 2, "BITA", IND }, + { 0xA6, 2, "LDA", IND }, + { 0xA7, 2, "STA", IND }, + { 0xA8, 2, "EORA", IND }, + { 0xA9, 2, "ADCA", IND }, + { 0xAA, 2, "ORA", IND }, + { 0xAB, 2, "ADDA", IND }, + { 0xAC, 2, "CMPX", IND }, + { 0xAD, 2, "JSR", IND , DASMFLAG_STEP_OVER }, + { 0xAE, 2, "LDX", IND }, + { 0xAF, 2, "STX", IND }, + + { 0xB0, 3, "SUBA", EXT }, + { 0xB1, 3, "CMPA", EXT }, + { 0xB2, 3, "SBCA", EXT }, + { 0xB3, 3, "SUBD", EXT }, + { 0xB4, 3, "ANDA", EXT }, + { 0xB5, 3, "BITA", EXT }, + { 0xB6, 3, "LDA", EXT }, + { 0xB7, 3, "STA", EXT }, + { 0xB8, 3, "EORA", EXT }, + { 0xB9, 3, "ADCA", EXT }, + { 0xBA, 3, "ORA", EXT }, + { 0xBB, 3, "ADDA", EXT }, + { 0xBC, 3, "CMPX", EXT }, + { 0xBD, 3, "JSR", EXT , DASMFLAG_STEP_OVER }, + { 0xBE, 3, "LDX", EXT }, + { 0xBF, 3, "STX", EXT }, + + { 0xC0, 2, "SUBB", IMM }, + { 0xC1, 2, "CMPB", IMM }, + { 0xC2, 2, "SBCB", IMM }, + { 0xC3, 3, "ADDD", IMM }, + { 0xC4, 2, "ANDB", IMM }, + { 0xC5, 2, "BITB", IMM }, + { 0xC6, 2, "LDB", IMM }, + { 0xC8, 2, "EORB", IMM }, + { 0xC9, 2, "ADCB", IMM }, + { 0xCA, 2, "ORB", IMM }, + { 0xCB, 2, "ADDB", IMM }, + { 0xCC, 3, "LDD", IMM }, + { 0xCD, 5, "LDQ", IMM }, + { 0xCE, 3, "LDU", IMM }, + + { 0xD0, 2, "SUBB", DIR }, + { 0xD1, 2, "CMPB", DIR }, + { 0xD2, 2, "SBCB", DIR }, + { 0xD3, 2, "ADDD", DIR }, + { 0xD4, 2, "ANDB", DIR }, + { 0xD5, 2, "BITB", DIR }, + { 0xD6, 2, "LDB", DIR }, + { 0xD7, 2, "STB", DIR }, + { 0xD8, 2, "EORB", DIR }, + { 0xD9, 2, "ADCB", DIR }, + { 0xDA, 2, "ORB", DIR }, + { 0xDB, 2, "ADDB", DIR }, + { 0xDC, 2, "LDD", DIR }, + { 0xDD, 2, "STD", DIR }, + { 0xDE, 2, "LDU", DIR }, + { 0xDF, 2, "STU", DIR }, + + { 0xE0, 2, "SUBB", IND }, + { 0xE1, 2, "CMPB", IND }, + { 0xE2, 2, "SBCB", IND }, + { 0xE3, 2, "ADDD", IND }, + { 0xE4, 2, "ANDB", IND }, + { 0xE5, 2, "BITB", IND }, + { 0xE6, 2, "LDB", IND }, + { 0xE7, 2, "STB", IND }, + { 0xE8, 2, "EORB", IND }, + { 0xE9, 2, "ADCB", IND }, + { 0xEA, 2, "ORB", IND }, + { 0xEB, 2, "ADDB", IND }, + { 0xEC, 2, "LDD", IND }, + { 0xED, 2, "STD", IND }, + { 0xEE, 2, "LDU", IND }, + { 0xEF, 2, "STU", IND }, + + { 0xF0, 3, "SUBB", EXT }, + { 0xF1, 3, "CMPB", EXT }, + { 0xF2, 3, "SBCB", EXT }, + { 0xF3, 3, "ADDD", EXT }, + { 0xF4, 3, "ANDB", EXT }, + { 0xF5, 3, "BITB", EXT }, + { 0xF6, 3, "LDB", EXT }, + { 0xF7, 3, "STB", EXT }, + { 0xF8, 3, "EORB", EXT }, + { 0xF9, 3, "ADCB", EXT }, + { 0xFA, 3, "ORB", EXT }, + { 0xFB, 3, "ADDB", EXT }, + { 0xFC, 3, "LDD", EXT }, + { 0xFD, 3, "STD", EXT }, + { 0xFE, 3, "LDU", EXT }, + { 0xFF, 3, "STU", EXT } +}; + +// Page 1 opcodes (0x10 0x..) +static const opcodeinfo hd6309_pg1opcodes[] = +{ + { 0x21, 4, "LBRN", LREL }, + { 0x22, 4, "LBHI", LREL }, + { 0x23, 4, "LBLS", LREL }, + { 0x24, 4, "LBCC", LREL }, + { 0x25, 4, "LBCS", LREL }, + { 0x26, 4, "LBNE", LREL }, + { 0x27, 4, "LBEQ", LREL }, + { 0x28, 4, "LBVC", LREL }, + { 0x29, 4, "LBVS", LREL }, + { 0x2A, 4, "LBPL", LREL }, + { 0x2B, 4, "LBMI", LREL }, + { 0x2C, 4, "LBGE", LREL }, + { 0x2D, 4, "LBLT", LREL }, + { 0x2E, 4, "LBGT", LREL }, + { 0x2F, 4, "LBLE", LREL }, + + { 0x30, 3, "ADDR", IMM_RR }, + { 0x31, 3, "ADCR", IMM_RR }, + { 0x32, 3, "SUBR", IMM_RR }, + { 0x33, 3, "SBCR", IMM_RR }, + { 0x34, 3, "ANDR", IMM_RR }, + { 0x35, 3, "ORR", IMM_RR }, + { 0x36, 3, "EORR", IMM_RR }, + { 0x37, 3, "CMPR", IMM_RR }, + + { 0x38, 2, "PSHSW", INH }, + { 0x39, 2, "PULSW", INH }, + { 0x3A, 2, "PSHUW", INH }, + { 0x3B, 2, "PULUW", INH }, + + { 0x3F, 2, "SWI2", INH }, + + { 0x40, 2, "NEGD", INH }, + { 0x43, 2, "COMD", INH }, + { 0x44, 2, "LSRD", INH }, + { 0x46, 2, "RORD", INH }, + { 0x47, 2, "ASRD", INH }, + { 0x48, 2, "ASLD", INH }, + { 0x49, 2, "ROLD", INH }, + + { 0x4A, 2, "DECD", INH }, + { 0x4C, 2, "INCD", INH }, + { 0x4D, 2, "TSTD", INH }, + { 0x4f, 2, "CLRD", INH }, + + { 0x53, 2, "COMW", INH }, + { 0x54, 2, "LSRW", INH }, + { 0x56, 2, "RORW", INH }, + { 0x59, 2, "ROLW", INH }, + { 0x5A, 2, "DECW", INH }, + { 0x5C, 2, "INCW", INH }, + { 0x5D, 2, "TSTW", INH }, + { 0x5F, 2, "CLRW", INH }, + { 0x80, 4, "SUBW", IMM }, + { 0x81, 4, "CMPW", IMM }, + { 0x82, 4, "SBCD", IMM }, + + { 0x83, 4, "CMPD", IMM }, + + { 0x84, 4, "ANDD", IMM }, + { 0x85, 4, "BITD", IMM }, + { 0x86, 4, "LDW", IMM }, + { 0x88, 4, "EORD", IMM }, + { 0x89, 4, "ADCD", IMM }, + { 0x8A, 4, "ORD", IMM }, + { 0x8B, 4, "ADDW", IMM }, + + { 0x8C, 4, "CMPY", IMM }, + { 0x8E, 4, "LDY", IMM }, + + { 0x90, 3, "SUBW", DIR }, + { 0x91, 3, "CMPW", DIR }, + { 0x92, 3, "SBCD", DIR }, + + { 0x93, 3, "CMPD", DIR }, + + { 0x94, 3, "ANDD", DIR }, + { 0x95, 3, "BITD", DIR }, + { 0x96, 3, "LDW", DIR }, + { 0x97, 3, "STW", DIR }, + { 0x98, 3, "EORD", DIR }, + { 0x99, 3, "ADCD", DIR }, + { 0x9A, 3, "ORD", DIR }, + { 0x9B, 3, "ADDW", DIR }, + + { 0x9C, 3, "CMPY", DIR }, + { 0x9E, 3, "LDY", DIR }, + { 0x9F, 3, "STY", DIR }, + + { 0xA0, 3, "SUBW", IND }, + { 0xA1, 3, "CMPW", IND }, + { 0xA2, 3, "SBCD", IND }, + + { 0xA3, 3, "CMPD", IND }, + + { 0xA4, 3, "ANDD", IND }, + { 0xA5, 3, "BITD", IND }, + + { 0xA6, 3, "LDW", IND }, + { 0xA7, 3, "STW", IND }, + { 0xA8, 3, "EORD", IND }, + { 0xA9, 3, "ADCD", IND }, + { 0xAA, 3, "ORD", IND }, + { 0xAB, 3, "ADDW", IND }, + + { 0xAC, 3, "CMPY", IND }, + { 0xAE, 3, "LDY", IND }, + { 0xAF, 3, "STY", IND }, + + { 0xB0, 4, "SUBW", EXT }, + { 0xB1, 4, "CMPW", EXT }, + { 0xB2, 4, "SBCD", EXT }, + + { 0xB3, 4, "CMPD", EXT }, + + { 0xB4, 4, "ANDD", EXT }, + { 0xB5, 4, "BITD", EXT }, + { 0xB6, 4, "LDW", EXT }, + { 0xB7, 4, "STW", EXT }, + { 0xB8, 4, "EORD", EXT }, + { 0xB9, 4, "ADCD", EXT }, + { 0xBA, 4, "ORD", EXT }, + { 0xBB, 4, "ADDW", EXT }, + + { 0xBC, 4, "CMPY", EXT }, + { 0xBE, 4, "LDY", EXT }, + { 0xBF, 4, "STY", EXT }, + { 0xCE, 4, "LDS", IMM }, + + { 0xDC, 3, "LDQ", DIR }, + { 0xDD, 3, "STQ", DIR }, + + { 0xDE, 3, "LDS", DIR }, + { 0xDF, 3, "STS", DIR }, + + { 0xEC, 3, "LDQ", IND }, + { 0xED, 3, "STQ", IND }, + { 0xEE, 3, "LDS", IND }, + + { 0xEE, 3, "LDS", IND }, + { 0xEF, 3, "STS", IND }, + + { 0xFC, 4, "LDQ", EXT }, + { 0xFD, 4, "STQ", EXT }, + + { 0xFE, 4, "LDS", EXT }, + { 0xFF, 4, "STS", EXT } +}; + +// Page 2 opcodes (0x11 0x..) +static const opcodeinfo hd6309_pg2opcodes[] = +{ + { 0x30, 4, "BAND", IMM_BW }, + { 0x31, 4, "BIAND", IMM_BW }, + { 0x32, 4, "BOR", IMM_BW }, + { 0x33, 4, "BIOR", IMM_BW }, + { 0x34, 4, "BEOR", IMM_BW }, + { 0x35, 4, "BIEOR", IMM_BW }, + + { 0x36, 4, "LDBT", IMM_BW }, + { 0x37, 4, "STBT", IMM_BW }, + + { 0x38, 3, "TFM", IMM_TFM }, + { 0x39, 3, "TFM", IMM_TFM }, + { 0x3A, 3, "TFM", IMM_TFM }, + { 0x3B, 3, "TFM", IMM_TFM }, + + { 0x3C, 3, "BITMD", IMM }, + { 0x3D, 3, "LDMD", IMM }, + + { 0x3F, 2, "SWI3", INH }, + + { 0x43, 2, "COME", INH }, + { 0x4A, 2, "DECE", INH }, + { 0x4C, 2, "INCE", INH }, + { 0x4D, 2, "TSTE", INH }, + { 0x4F, 2, "CLRE", INH }, + { 0x53, 2, "COMF", INH }, + { 0x5A, 2, "DECF", INH }, + { 0x5C, 2, "INCF", INH }, + { 0x5D, 2, "TSTF", INH }, + { 0x5F, 2, "CLRF", INH }, + + { 0x80, 3, "SUBE", IMM }, + { 0x81, 3, "CMPE", IMM }, + + { 0x83, 4, "CMPU", IMM }, + + { 0x86, 3, "LDE", IMM }, + { 0x8b, 3, "ADDE", IMM }, + + { 0x8C, 4, "CMPS", IMM }, + + { 0x8D, 3, "DIVD", IMM }, + { 0x8E, 4, "DIVQ", IMM }, + { 0x8F, 4, "MULD", IMM }, + { 0x90, 3, "SUBE", DIR }, + { 0x91, 3, "CMPE", DIR }, + + { 0x93, 3, "CMPU", DIR }, + + { 0x96, 3, "LDE", DIR }, + { 0x97, 3, "STE", DIR }, + { 0x9B, 3, "ADDE", DIR }, + + { 0x9C, 3, "CMPS", DIR }, + + { 0x9D, 3, "DIVD", DIR }, + { 0x9E, 3, "DIVQ", DIR }, + { 0x9F, 3, "MULD", DIR }, + + { 0xA0, 3, "SUBE", IND }, + { 0xA1, 3, "CMPE", IND }, + + { 0xA3, 3, "CMPU", IND }, + + { 0xA6, 3, "LDE", IND }, + { 0xA7, 3, "STE", IND }, + { 0xAB, 3, "ADDE", IND }, + + { 0xAC, 3, "CMPS", IND }, + + { 0xAD, 3, "DIVD", IND }, + { 0xAE, 3, "DIVQ", IND }, + { 0xAF, 3, "MULD", IND }, + { 0xB0, 4, "SUBE", EXT }, + { 0xB1, 4, "CMPE", EXT }, + + { 0xB3, 4, "CMPU", EXT }, + + { 0xB6, 4, "LDE", EXT }, + { 0xB7, 4, "STE", EXT }, + + { 0xBB, 4, "ADDE", EXT }, + { 0xBC, 4, "CMPS", EXT }, + + { 0xBD, 4, "DIVD", EXT }, + { 0xBE, 4, "DIVQ", EXT }, + { 0xBF, 4, "MULD", EXT }, + + { 0xC0, 3, "SUBF", IMM }, + { 0xC1, 3, "CMPF", IMM }, + { 0xC6, 3, "LDF", IMM }, + { 0xCB, 3, "ADDF", IMM }, + + { 0xD0, 3, "SUBF", DIR }, + { 0xD1, 3, "CMPF", DIR }, + { 0xD6, 3, "LDF", DIR }, + { 0xD7, 3, "STF", DIR }, + { 0xDB, 3, "ADDF", DIR }, + + { 0xE0, 3, "SUBF", IND }, + { 0xE1, 3, "CMPF", IND }, + { 0xE6, 3, "LDF", IND }, + { 0xE7, 3, "STF", IND }, + { 0xEB, 3, "ADDF", IND }, + + { 0xF0, 4, "SUBF", EXT }, + { 0xF1, 4, "CMPF", EXT }, + { 0xF6, 4, "LDF", EXT }, + { 0xF7, 4, "STF", EXT }, + { 0xFB, 4, "ADDF", EXT } +}; + +static const opcodeinfo *const hd6309_pgpointers[3] = +{ + hd6309_pg0opcodes, hd6309_pg1opcodes, hd6309_pg2opcodes +}; + +static const int hd6309_numops[3] = +{ + ARRAY_LENGTH(hd6309_pg0opcodes), + ARRAY_LENGTH(hd6309_pg1opcodes), + ARRAY_LENGTH(hd6309_pg2opcodes) +}; + +static const char *const hd6309_regs[5] = { "X", "Y", "U", "S", "PC" }; + +static const char *const hd6309_btwregs[5] = { "CC", "A", "B", "inv" }; + +static const char *const hd6309_teregs[16] = +{ + "D", "X", "Y", "U", "S", "PC", "W", "V", + "A", "B", "CC", "DP", "0", "0", "E", "F" +}; + +static const char *const hd6309_tfmregs[16] = { + "D", "X", "Y", "U", "S", "inv", "inv", "inv", + "inv", "inv", "inv", "inv", "inv", "inv", "inv", "inv" +}; + +static const char *const tfm_s[] = { "%s+,%s+", "%s-,%s-", "%s+,%s", "%s,%s+" }; + +CPU_DISASSEMBLE( hd6309 ) +{ + UINT8 opcode, mode, pb, pbm, reg; + const UINT8 *operandarray; + unsigned int ea, flags; + int numoperands, offset, indirect; + + int i, p = 0, page = 0, opcode_found = FALSE; + + do + { + opcode = oprom[p++]; + for (i = 0; i < hd6309_numops[page]; i++) + if (hd6309_pgpointers[page][i].opcode == opcode) + break; + + if (i < hd6309_numops[page]) + opcode_found = TRUE; + else + { + strcpy(buffer, "Illegal Opcode"); + return p | DASMFLAG_SUPPORTED; + } + + if (hd6309_pgpointers[page][i].mode >= PG1) + { + page = hd6309_pgpointers[page][i].mode - PG1 + 1; + opcode_found = FALSE; + } + } while (!opcode_found); + + if (page == 0) + numoperands = hd6309_pgpointers[page][i].length - 1; + else + numoperands = hd6309_pgpointers[page][i].length - 2; + + operandarray = &opram[p]; + p += numoperands; + pc += p; + mode = hd6309_pgpointers[page][i].mode; + flags = hd6309_pgpointers[page][i].flags; + + buffer += sprintf(buffer, "%-6s", hd6309_pgpointers[page][i].name); + + switch (mode) + { + case INH: + switch (opcode) + { + case 0x34: // PSHS + case 0x36: // PSHU + pb = operandarray[0]; + if (pb & 0x80) + buffer += sprintf(buffer, "PC"); + if (pb & 0x40) + buffer += sprintf(buffer, "%s%s", (pb&0x80)?",":"", (opcode==0x34)?"U":"S"); + if (pb & 0x20) + buffer += sprintf(buffer, "%sY", (pb&0xc0)?",":""); + if (pb & 0x10) + buffer += sprintf(buffer, "%sX", (pb&0xe0)?",":""); + if (pb & 0x08) + buffer += sprintf(buffer, "%sDP", (pb&0xf0)?",":""); + if (pb & 0x04) + buffer += sprintf(buffer, "%sB", (pb&0xf8)?",":""); + if (pb & 0x02) + buffer += sprintf(buffer, "%sA", (pb&0xfc)?",":""); + if (pb & 0x01) + buffer += sprintf(buffer, "%sCC", (pb&0xfe)?",":""); + break; + case 0x35: // PULS + case 0x37: // PULU + pb = operandarray[0]; + if (pb & 0x01) + buffer += sprintf(buffer, "CC"); + if (pb & 0x02) + buffer += sprintf(buffer, "%sA", (pb&0x01)?",":""); + if (pb & 0x04) + buffer += sprintf(buffer, "%sB", (pb&0x03)?",":""); + if (pb & 0x08) + buffer += sprintf(buffer, "%sDP", (pb&0x07)?",":""); + if (pb & 0x10) + buffer += sprintf(buffer, "%sX", (pb&0x0f)?",":""); + if (pb & 0x20) + buffer += sprintf(buffer, "%sY", (pb&0x1f)?",":""); + if (pb & 0x40) + buffer += sprintf(buffer, "%s%s", (pb&0x3f)?",":"", (opcode==0x35)?"U":"S"); + if (pb & 0x80) + buffer += sprintf(buffer, "%sPC ; (PUL? PC=RTS)", (pb&0x7f)?",":""); + break; + default: + // No operands + break; + } + break; + + case DIR: + ea = operandarray[0]; + buffer += sprintf(buffer, "$%02X", ea); + break; + + case DIR_IM: + buffer += sprintf(buffer, "#$%02X,", operandarray[0]); + buffer += sprintf(buffer, "$%02X", operandarray[1]); + break; + + case REL: + offset = (INT8)operandarray[0]; + buffer += sprintf(buffer, "$%04X", (pc + offset) & 0xffff); + break; + + case LREL: + offset = (INT16)((operandarray[0] << 8) + operandarray[1]); + buffer += sprintf(buffer, "$%04X", (pc + offset) & 0xffff); + break; + + case EXT: + if (numoperands == 3) + { + pb = operandarray[0]; + ea = (operandarray[1] << 8) + operandarray[2]; + buffer += sprintf(buffer, "#$%02X,$%04X", pb, ea); + } + else + if (numoperands == 2) + { + ea = (operandarray[0] << 8) + operandarray[1]; + buffer += sprintf(buffer, "$%04X", ea); + } + break; + + case IND: + if (numoperands == 2) + { + buffer += sprintf(buffer, "#$%02X,", operandarray[0]); + pb = operandarray[1]; + } + else + { + pb = operandarray[0]; + } + + reg = (pb >> 5) & 3; + pbm = pb & 0x8f; + indirect = ((pb & 0x90) == 0x90 )? TRUE : FALSE; + + // open brackets if indirect + if (indirect && pbm != 0x82) + buffer += sprintf(buffer, "["); + + switch (pbm) + { + case 0x80: // ,R+ or operations relative to W + if (indirect) + { + switch (reg) + { + case 0x00: + buffer += sprintf(buffer, ",W"); + break; + case 0x01: + offset = (INT16)((opram[p+0] << 8) + opram[p+1]); + p += 2; + buffer += sprintf(buffer, "%s", (offset < 0) ? "-" : ""); + buffer += sprintf(buffer, "$%04X,W", (offset < 0) ? -offset : offset); + break; + case 0x02: + buffer += sprintf(buffer, ",W++"); + break; + case 0x03: + buffer += sprintf(buffer, ",--W"); + break; + } + } + else + buffer += sprintf(buffer, ",%s+", hd6309_regs[reg]); + break; + + case 0x81: // ,R++ + buffer += sprintf(buffer, ",%s++", hd6309_regs[reg]); + break; + + case 0x82: // ,-R + if (indirect) + strcpy(buffer, "Illegal Postbyte"); + else + buffer += sprintf(buffer, ",-%s", hd6309_regs[reg]); + break; + + case 0x83: // ,--R + buffer += sprintf(buffer, ",--%s", hd6309_regs[reg]); + break; + + case 0x84: // ,R + buffer += sprintf(buffer, ",%s", hd6309_regs[reg]); + break; + + case 0x85: // (+/- B),R + buffer += sprintf(buffer, "B,%s", hd6309_regs[reg]); + break; + + case 0x86: // (+/- A),R + buffer += sprintf(buffer, "A,%s", hd6309_regs[reg]); + break; + + case 0x87: // (+/- E),R + buffer += sprintf(buffer, "E,%s", hd6309_regs[reg]); + break; + + case 0x88: // (+/- 7 bit offset),R + offset = (INT8)opram[p++]; + buffer += sprintf(buffer, "%s", (offset < 0) ? "-" : ""); + buffer += sprintf(buffer, "$%02X,", (offset < 0) ? -offset : offset); + buffer += sprintf(buffer, "%s", hd6309_regs[reg]); + break; + + case 0x89: // (+/- 15 bit offset),R + offset = (INT16)((opram[p+0] << 8) + opram[p+1]); + p += 2; + buffer += sprintf(buffer, "%s", (offset < 0) ? "-" : ""); + buffer += sprintf(buffer, "$%04X,", (offset < 0) ? -offset : offset); + buffer += sprintf(buffer, "%s", hd6309_regs[reg]); + break; + + case 0x8a: // (+/- F),R + buffer += sprintf(buffer, "F,%s", hd6309_regs[reg]); + break; + + case 0x8b: // (+/- D),R + buffer += sprintf(buffer, "D,%s", hd6309_regs[reg]); + break; + + case 0x8c: // (+/- 7 bit offset),PC + offset = (INT8)opram[p++]; + buffer += sprintf(buffer, "%s", (offset < 0) ? "-" : ""); + buffer += sprintf(buffer, "$%02X,PC", (offset < 0) ? -offset : offset); + break; + + case 0x8d: // (+/- 15 bit offset),PC + offset = (INT16)((opram[p+0] << 8) + opram[p+1]); + p += 2; + buffer += sprintf(buffer, "%s", (offset < 0) ? "-" : ""); + buffer += sprintf(buffer, "$%04X,PC", (offset < 0) ? -offset : offset); + break; + + case 0x8e: // (+/- W),R + buffer += sprintf(buffer, "W,%s", hd6309_regs[reg]); + break; + + case 0x8f: // address or operations relative to W + if (indirect) + { + ea = (UINT16)((opram[p+0] << 8) + opram[p+1]); + p += 2; + buffer += sprintf(buffer, "$%04X", ea); + break; + } + else + { + switch (reg) + { + case 0x00: + buffer += sprintf(buffer, ",W"); + break; + case 0x01: + offset = (INT16)((opram[p+0] << 8) + opram[p+1]); + p += 2; + buffer += sprintf(buffer, "%s", (offset < 0) ? "-" : ""); + buffer += sprintf(buffer, "$%04X,W", (offset < 0) ? -offset : offset); + break; + case 0x02: + buffer += sprintf(buffer, ",W++"); + break; + case 0x03: + buffer += sprintf(buffer, ",--W"); + break; + } + } + break; + + default: // (+/- 4 bit offset),R + offset = pb & 0x1f; + if (offset > 15) + offset = offset - 32; + buffer += sprintf(buffer, "%s", (offset < 0) ? "-" : ""); + buffer += sprintf(buffer, "$%X,", (offset < 0) ? -offset : offset); + buffer += sprintf(buffer, "%s", hd6309_regs[reg]); + break; + } + + // close brackets if indirect + if (indirect && pbm != 0x82) + buffer += sprintf(buffer, "]"); + break; + + case IMM: + if (numoperands == 4) + { + ea = (operandarray[0] << 24) + (operandarray[1] << 16) + (operandarray[2] << 8) + operandarray[3]; + buffer += sprintf(buffer, "#$%08X", ea); + } + else + if (numoperands == 2) + { + ea = (operandarray[0] << 8) + operandarray[1]; + buffer += sprintf(buffer, "#$%04X", ea); + } + else + if (numoperands == 1) + { + ea = operandarray[0]; + buffer += sprintf(buffer, "#$%02X", ea); + } + break; + + case IMM_RR: + pb = operandarray[0]; + buffer += sprintf(buffer, "%s,%s", hd6309_teregs[(pb >> 4) & 0xf], hd6309_teregs[pb & 0xf]); + break; + + case IMM_BW: + pb = operandarray[0]; + buffer += sprintf(buffer, "%s,", hd6309_btwregs[((pb & 0xc0) >> 6)]); + buffer += sprintf(buffer, "%d,", (pb & 0x38) >> 3); + buffer += sprintf(buffer, "%d,", (pb & 0x07)); + buffer += sprintf(buffer, "$%02X", operandarray[1]); + break; + + case IMM_TFM: + pb = operandarray[0]; + buffer += sprintf(buffer, tfm_s[opcode & 0x07], hd6309_tfmregs[(pb >> 4) & 0xf], hd6309_tfmregs[pb & 0xf]); + break; + } + + return p | flags | DASMFLAG_SUPPORTED; +} diff --git a/src/devices/cpu/m6809/6809dasm.c b/src/devices/cpu/m6809/6809dasm.c new file mode 100644 index 00000000000..192dda3b484 --- /dev/null +++ b/src/devices/cpu/m6809/6809dasm.c @@ -0,0 +1,616 @@ +// license:BSD-3-Clause +// copyright-holders:Nathan Woods, Sean Riddle +/***************************************************************************** + + 6809dasm.c - a 6809 opcode disassembler + Version 1.4 1-MAR-95 + Copyright Sean Riddle + + Thanks to Franklin Bowen for bug fixes, ideas + + Freely distributable on any medium given all copyrights are retained + by the author and no charge greater than $7.00 is made for obtaining + this software + + Please send all bug reports, update ideas and data files to: + sriddle@ionet.net + +*****************************************************************************/ + +#include "emu.h" +#include "debugger.h" +#include "m6809.h" +#include "m6809inl.h" + +// Opcode structure +struct opcodeinfo +{ + UINT8 opcode; // 8-bit opcode value + UINT8 length; // Opcode length in bytes + char name[6]; // Opcode name + UINT8 mode; // Addressing mode + unsigned flags; // Disassembly flags +}; + +enum m6809_addressing_modes +{ + INH, // Inherent + DIR, // Direct + IND, // Indexed + REL, // Relative (8 bit) + LREL, // Long relative (16 bit) + EXT, // Extended + IMM, // Immediate + IMM_RR, // Register-to-register + PG1, // Switch to page 1 opcodes + PG2 // Switch to page 2 opcodes +}; + +// Page 0 opcodes (single byte) +static const opcodeinfo m6809_pg0opcodes[] = +{ + { 0x00, 2, "NEG", DIR }, + { 0x03, 2, "COM", DIR }, + { 0x04, 2, "LSR", DIR }, + { 0x06, 2, "ROR", DIR }, + { 0x07, 2, "ASR", DIR }, + { 0x08, 2, "ASL", DIR }, + { 0x09, 2, "ROL", DIR }, + { 0x0A, 2, "DEC", DIR }, + { 0x0C, 2, "INC", DIR }, + { 0x0D, 2, "TST", DIR }, + { 0x0E, 2, "JMP", DIR }, + { 0x0F, 2, "CLR", DIR }, + + { 0x10, 1, "page1", PG1 }, + { 0x11, 1, "page2", PG2 }, + { 0x12, 1, "NOP", INH }, + { 0x13, 1, "SYNC", INH }, + { 0x16, 3, "LBRA", LREL }, + { 0x17, 3, "LBSR", LREL , DASMFLAG_STEP_OVER }, + { 0x19, 1, "DAA", INH }, + { 0x1A, 2, "ORCC", IMM }, + { 0x1C, 2, "ANDCC", IMM }, + { 0x1D, 1, "SEX", INH }, + { 0x1E, 2, "EXG", IMM_RR }, + { 0x1F, 2, "TFR", IMM_RR }, + + { 0x20, 2, "BRA", REL }, + { 0x21, 2, "BRN", REL }, + { 0x22, 2, "BHI", REL }, + { 0x23, 2, "BLS", REL }, + { 0x24, 2, "BCC", REL }, + { 0x25, 2, "BCS", REL }, + { 0x26, 2, "BNE", REL }, + { 0x27, 2, "BEQ", REL }, + { 0x28, 2, "BVC", REL }, + { 0x29, 2, "BVS", REL }, + { 0x2A, 2, "BPL", REL }, + { 0x2B, 2, "BMI", REL }, + { 0x2C, 2, "BGE", REL }, + { 0x2D, 2, "BLT", REL }, + { 0x2E, 2, "BGT", REL }, + { 0x2F, 2, "BLE", REL }, + + { 0x30, 2, "LEAX", IND }, + { 0x31, 2, "LEAY", IND }, + { 0x32, 2, "LEAS", IND }, + { 0x33, 2, "LEAU", IND }, + { 0x34, 2, "PSHS", INH }, + { 0x35, 2, "PULS", INH }, + { 0x36, 2, "PSHU", INH }, + { 0x37, 2, "PULU", INH }, + { 0x39, 1, "RTS", INH }, + { 0x3A, 1, "ABX", INH }, + { 0x3B, 1, "RTI", INH }, + { 0x3C, 2, "CWAI", IMM }, + { 0x3D, 1, "MUL", INH }, + { 0x3F, 1, "SWI", INH }, + + { 0x40, 1, "NEGA", INH }, + { 0x43, 1, "COMA", INH }, + { 0x44, 1, "LSRA", INH }, + { 0x46, 1, "RORA", INH }, + { 0x47, 1, "ASRA", INH }, + { 0x48, 1, "ASLA", INH }, + { 0x49, 1, "ROLA", INH }, + { 0x4A, 1, "DECA", INH }, + { 0x4C, 1, "INCA", INH }, + { 0x4D, 1, "TSTA", INH }, + { 0x4F, 1, "CLRA", INH }, + + { 0x50, 1, "NEGB", INH }, + { 0x53, 1, "COMB", INH }, + { 0x54, 1, "LSRB", INH }, + { 0x56, 1, "RORB", INH }, + { 0x57, 1, "ASRB", INH }, + { 0x58, 1, "ASLB", INH }, + { 0x59, 1, "ROLB", INH }, + { 0x5A, 1, "DECB", INH }, + { 0x5C, 1, "INCB", INH }, + { 0x5D, 1, "TSTB", INH }, + { 0x5F, 1, "CLRB", INH }, + + { 0x60, 2, "NEG", IND }, + { 0x63, 2, "COM", IND }, + { 0x64, 2, "LSR", IND }, + { 0x66, 2, "ROR", IND }, + { 0x67, 2, "ASR", IND }, + { 0x68, 2, "ASL", IND }, + { 0x69, 2, "ROL", IND }, + { 0x6A, 2, "DEC", IND }, + { 0x6C, 2, "INC", IND }, + { 0x6D, 2, "TST", IND }, + { 0x6E, 2, "JMP", IND }, + { 0x6F, 2, "CLR", IND }, + + { 0x70, 3, "NEG", EXT }, + { 0x73, 3, "COM", EXT }, + { 0x74, 3, "LSR", EXT }, + { 0x76, 3, "ROR", EXT }, + { 0x77, 3, "ASR", EXT }, + { 0x78, 3, "ASL", EXT }, + { 0x79, 3, "ROL", EXT }, + { 0x7A, 3, "DEC", EXT }, + { 0x7C, 3, "INC", EXT }, + { 0x7D, 3, "TST", EXT }, + { 0x7E, 3, "JMP", EXT }, + { 0x7F, 3, "CLR", EXT }, + + { 0x80, 2, "SUBA", IMM }, + { 0x81, 2, "CMPA", IMM }, + { 0x82, 2, "SBCA", IMM }, + { 0x83, 3, "SUBD", IMM }, + { 0x84, 2, "ANDA", IMM }, + { 0x85, 2, "BITA", IMM }, + { 0x86, 2, "LDA", IMM }, + { 0x88, 2, "EORA", IMM }, + { 0x89, 2, "ADCA", IMM }, + { 0x8A, 2, "ORA", IMM }, + { 0x8B, 2, "ADDA", IMM }, + { 0x8C, 3, "CMPX", IMM }, + { 0x8D, 2, "BSR", REL , DASMFLAG_STEP_OVER }, + { 0x8E, 3, "LDX", IMM }, + + { 0x90, 2, "SUBA", DIR }, + { 0x91, 2, "CMPA", DIR }, + { 0x92, 2, "SBCA", DIR }, + { 0x93, 2, "SUBD", DIR }, + { 0x94, 2, "ANDA", DIR }, + { 0x95, 2, "BITA", DIR }, + { 0x96, 2, "LDA", DIR }, + { 0x97, 2, "STA", DIR }, + { 0x98, 2, "EORA", DIR }, + { 0x99, 2, "ADCA", DIR }, + { 0x9A, 2, "ORA", DIR }, + { 0x9B, 2, "ADDA", DIR }, + { 0x9C, 2, "CMPX", DIR }, + { 0x9D, 2, "JSR", DIR , DASMFLAG_STEP_OVER }, + { 0x9E, 2, "LDX", DIR }, + { 0x9F, 2, "STX", DIR }, + + { 0xA0, 2, "SUBA", IND }, + { 0xA1, 2, "CMPA", IND }, + { 0xA2, 2, "SBCA", IND }, + { 0xA3, 2, "SUBD", IND }, + { 0xA4, 2, "ANDA", IND }, + { 0xA5, 2, "BITA", IND }, + { 0xA6, 2, "LDA", IND }, + { 0xA7, 2, "STA", IND }, + { 0xA8, 2, "EORA", IND }, + { 0xA9, 2, "ADCA", IND }, + { 0xAA, 2, "ORA", IND }, + { 0xAB, 2, "ADDA", IND }, + { 0xAC, 2, "CMPX", IND }, + { 0xAD, 2, "JSR", IND , DASMFLAG_STEP_OVER }, + { 0xAE, 2, "LDX", IND }, + { 0xAF, 2, "STX", IND }, + + { 0xB0, 3, "SUBA", EXT }, + { 0xB1, 3, "CMPA", EXT }, + { 0xB2, 3, "SBCA", EXT }, + { 0xB3, 3, "SUBD", EXT }, + { 0xB4, 3, "ANDA", EXT }, + { 0xB5, 3, "BITA", EXT }, + { 0xB6, 3, "LDA", EXT }, + { 0xB7, 3, "STA", EXT }, + { 0xB8, 3, "EORA", EXT }, + { 0xB9, 3, "ADCA", EXT }, + { 0xBA, 3, "ORA", EXT }, + { 0xBB, 3, "ADDA", EXT }, + { 0xBC, 3, "CMPX", EXT }, + { 0xBD, 3, "JSR", EXT , DASMFLAG_STEP_OVER }, + { 0xBE, 3, "LDX", EXT }, + { 0xBF, 3, "STX", EXT }, + + { 0xC0, 2, "SUBB", IMM }, + { 0xC1, 2, "CMPB", IMM }, + { 0xC2, 2, "SBCB", IMM }, + { 0xC3, 3, "ADDD", IMM }, + { 0xC4, 2, "ANDB", IMM }, + { 0xC5, 2, "BITB", IMM }, + { 0xC6, 2, "LDB", IMM }, + { 0xC8, 2, "EORB", IMM }, + { 0xC9, 2, "ADCB", IMM }, + { 0xCA, 2, "ORB", IMM }, + { 0xCB, 2, "ADDB", IMM }, + { 0xCC, 3, "LDD", IMM }, + { 0xCE, 3, "LDU", IMM }, + + { 0xD0, 2, "SUBB", DIR }, + { 0xD1, 2, "CMPB", DIR }, + { 0xD2, 2, "SBCB", DIR }, + { 0xD3, 2, "ADDD", DIR }, + { 0xD4, 2, "ANDB", DIR }, + { 0xD5, 2, "BITB", DIR }, + { 0xD6, 2, "LDB", DIR }, + { 0xD7, 2, "STB", DIR }, + { 0xD8, 2, "EORB", DIR }, + { 0xD9, 2, "ADCB", DIR }, + { 0xDA, 2, "ORB", DIR }, + { 0xDB, 2, "ADDB", DIR }, + { 0xDC, 2, "LDD", DIR }, + { 0xDD, 2, "STD", DIR }, + { 0xDE, 2, "LDU", DIR }, + { 0xDF, 2, "STU", DIR }, + + { 0xE0, 2, "SUBB", IND }, + { 0xE1, 2, "CMPB", IND }, + { 0xE2, 2, "SBCB", IND }, + { 0xE3, 2, "ADDD", IND }, + { 0xE4, 2, "ANDB", IND }, + { 0xE5, 2, "BITB", IND }, + { 0xE6, 2, "LDB", IND }, + { 0xE7, 2, "STB", IND }, + { 0xE8, 2, "EORB", IND }, + { 0xE9, 2, "ADCB", IND }, + { 0xEA, 2, "ORB", IND }, + { 0xEB, 2, "ADDB", IND }, + { 0xEC, 2, "LDD", IND }, + { 0xED, 2, "STD", IND }, + { 0xEE, 2, "LDU", IND }, + { 0xEF, 2, "STU", IND }, + + { 0xF0, 3, "SUBB", EXT }, + { 0xF1, 3, "CMPB", EXT }, + { 0xF2, 3, "SBCB", EXT }, + { 0xF3, 3, "ADDD", EXT }, + { 0xF4, 3, "ANDB", EXT }, + { 0xF5, 3, "BITB", EXT }, + { 0xF6, 3, "LDB", EXT }, + { 0xF7, 3, "STB", EXT }, + { 0xF8, 3, "EORB", EXT }, + { 0xF9, 3, "ADCB", EXT }, + { 0xFA, 3, "ORB", EXT }, + { 0xFB, 3, "ADDB", EXT }, + { 0xFC, 3, "LDD", EXT }, + { 0xFD, 3, "STD", EXT }, + { 0xFE, 3, "LDU", EXT }, + { 0xFF, 3, "STU", EXT } +}; + +// Page 1 opcodes (0x10 0x..) +static const opcodeinfo m6809_pg1opcodes[] = +{ + { 0x21, 4, "LBRN", LREL }, + { 0x22, 4, "LBHI", LREL }, + { 0x23, 4, "LBLS", LREL }, + { 0x24, 4, "LBCC", LREL }, + { 0x25, 4, "LBCS", LREL }, + { 0x26, 4, "LBNE", LREL }, + { 0x27, 4, "LBEQ", LREL }, + { 0x28, 4, "LBVC", LREL }, + { 0x29, 4, "LBVS", LREL }, + { 0x2A, 4, "LBPL", LREL }, + { 0x2B, 4, "LBMI", LREL }, + { 0x2C, 4, "LBGE", LREL }, + { 0x2D, 4, "LBLT", LREL }, + { 0x2E, 4, "LBGT", LREL }, + { 0x2F, 4, "LBLE", LREL }, + { 0x3F, 2, "SWI2", INH }, + { 0x83, 4, "CMPD", IMM }, + { 0x8C, 4, "CMPY", IMM }, + { 0x8E, 4, "LDY", IMM }, + { 0x93, 3, "CMPD", DIR }, + { 0x9C, 3, "CMPY", DIR }, + { 0x9E, 3, "LDY", DIR }, + { 0x9F, 3, "STY", DIR }, + { 0xA3, 3, "CMPD", IND }, + { 0xAC, 3, "CMPY", IND }, + { 0xAE, 3, "LDY", IND }, + { 0xAF, 3, "STY", IND }, + { 0xB3, 4, "CMPD", EXT }, + { 0xBC, 4, "CMPY", EXT }, + { 0xBE, 4, "LDY", EXT }, + { 0xBF, 4, "STY", EXT }, + { 0xCE, 4, "LDS", IMM }, + { 0xDE, 3, "LDS", DIR }, + { 0xDF, 3, "STS", DIR }, + { 0xEE, 3, "LDS", IND }, + { 0xEF, 3, "STS", IND }, + { 0xFE, 4, "LDS", EXT }, + { 0xFF, 4, "STS", EXT } +}; + +// Page 2 opcodes (0x11 0x..) +static const opcodeinfo m6809_pg2opcodes[] = +{ + { 0x3F, 2, "SWI3", INH }, + { 0x83, 4, "CMPU", IMM }, + { 0x8C, 4, "CMPS", IMM }, + { 0x93, 3, "CMPU", DIR }, + { 0x9C, 3, "CMPS", DIR }, + { 0xA3, 3, "CMPU", IND }, + { 0xAC, 3, "CMPS", IND }, + { 0xB3, 4, "CMPU", EXT }, + { 0xBC, 4, "CMPS", EXT } +}; + +static const opcodeinfo *const m6809_pgpointers[3] = +{ + m6809_pg0opcodes, m6809_pg1opcodes, m6809_pg2opcodes +}; + +static const int m6809_numops[3] = +{ + ARRAY_LENGTH(m6809_pg0opcodes), + ARRAY_LENGTH(m6809_pg1opcodes), + ARRAY_LENGTH(m6809_pg2opcodes) +}; + +static const char *const m6809_regs[5] = { "X", "Y", "U", "S", "PC" }; + +static const char *const m6809_regs_te[16] = +{ + "D", "X", "Y", "U", "S", "PC", "inv", "inv", + "A", "B", "CC", "DP", "inv", "inv", "inv", "inv" +}; + +CPU_DISASSEMBLE( m6809 ) +{ + UINT8 opcode, mode, pb, pbm, reg; + const UINT8 *operandarray; + unsigned int ea, flags; + int numoperands, offset, indirect; + int i, p = 0, page = 0, opcode_found = FALSE; + + do + { + opcode = oprom[p++]; + + for (i = 0; i < m6809_numops[page]; i++) + if (m6809_pgpointers[page][i].opcode == opcode) + break; + + if (i < m6809_numops[page]) + opcode_found = TRUE; + else + { + strcpy(buffer, "Illegal Opcode"); + return p | DASMFLAG_SUPPORTED; + } + + if (m6809_pgpointers[page][i].mode >= PG1) + { + page = m6809_pgpointers[page][i].mode - PG1 + 1; + opcode_found = FALSE; + } + } while (!opcode_found); + + if (page == 0) + numoperands = m6809_pgpointers[page][i].length - 1; + else + numoperands = m6809_pgpointers[page][i].length - 2; + + operandarray = &opram[p]; + p += numoperands; + pc += p; + mode = m6809_pgpointers[page][i].mode; + flags = m6809_pgpointers[page][i].flags; + + buffer += sprintf(buffer, "%-6s", m6809_pgpointers[page][i].name); + + switch (mode) + { + case INH: + switch (opcode) + { + case 0x34: // PSHS + case 0x36: // PSHU + pb = operandarray[0]; + if (pb & 0x80) + buffer += sprintf(buffer, "PC"); + if (pb & 0x40) + buffer += sprintf(buffer, "%s%s", (pb&0x80)?",":"", (opcode==0x34)?"U":"S"); + if (pb & 0x20) + buffer += sprintf(buffer, "%sY", (pb&0xc0)?",":""); + if (pb & 0x10) + buffer += sprintf(buffer, "%sX", (pb&0xe0)?",":""); + if (pb & 0x08) + buffer += sprintf(buffer, "%sDP", (pb&0xf0)?",":""); + if (pb & 0x04) + buffer += sprintf(buffer, "%sB", (pb&0xf8)?",":""); + if (pb & 0x02) + buffer += sprintf(buffer, "%sA", (pb&0xfc)?",":""); + if (pb & 0x01) + buffer += sprintf(buffer, "%sCC", (pb&0xfe)?",":""); + break; + case 0x35: // PULS + case 0x37: // PULU + pb = operandarray[0]; + if (pb & 0x01) + buffer += sprintf(buffer, "CC"); + if (pb & 0x02) + buffer += sprintf(buffer, "%sA", (pb&0x01)?",":""); + if (pb & 0x04) + buffer += sprintf(buffer, "%sB", (pb&0x03)?",":""); + if (pb & 0x08) + buffer += sprintf(buffer, "%sDP", (pb&0x07)?",":""); + if (pb & 0x10) + buffer += sprintf(buffer, "%sX", (pb&0x0f)?",":""); + if (pb & 0x20) + buffer += sprintf(buffer, "%sY", (pb&0x1f)?",":""); + if (pb & 0x40) + buffer += sprintf(buffer, "%s%s", (pb&0x3f)?",":"", (opcode==0x35)?"U":"S"); + if (pb & 0x80) + buffer += sprintf(buffer, "%sPC ; (PUL? PC=RTS)", (pb&0x7f)?",":""); + break; + default: + // No operands + break; + } + break; + + case DIR: + ea = operandarray[0]; + buffer += sprintf(buffer, "$%02X", ea); + break; + + case REL: + offset = (INT8)operandarray[0]; + buffer += sprintf(buffer, "$%04X", (pc + offset) & 0xffff); + break; + + case LREL: + offset = (INT16)((operandarray[0] << 8) + operandarray[1]); + buffer += sprintf(buffer, "$%04X", (pc + offset) & 0xffff); + break; + + case EXT: + ea = (operandarray[0] << 8) + operandarray[1]; + buffer += sprintf(buffer, "$%04X", ea); + break; + + case IND: + pb = operandarray[0]; + reg = (pb >> 5) & 3; + pbm = pb & 0x8f; + indirect = ((pb & 0x90) == 0x90 )? TRUE : FALSE; + + // open brackets if indirect + if (indirect && pbm != 0x80 && pbm != 0x82) + buffer += sprintf(buffer, "["); + + switch (pbm) + { + case 0x80: // ,R+ + if (indirect) + strcpy(buffer, "Illegal Postbyte"); + else + buffer += sprintf(buffer, ",%s+", m6809_regs[reg]); + break; + + case 0x81: // ,R++ + buffer += sprintf(buffer, ",%s++", m6809_regs[reg]); + break; + + case 0x82: // ,-R + if (indirect) + strcpy(buffer, "Illegal Postbyte"); + else + buffer += sprintf(buffer, ",-%s", m6809_regs[reg]); + break; + + case 0x83: // ,--R + buffer += sprintf(buffer, ",--%s", m6809_regs[reg]); + break; + + case 0x84: // ,R + buffer += sprintf(buffer, ",%s", m6809_regs[reg]); + break; + + case 0x85: // (+/- B),R + buffer += sprintf(buffer, "B,%s", m6809_regs[reg]); + break; + + case 0x86: // (+/- A),R + buffer += sprintf(buffer, "A,%s", m6809_regs[reg]); + break; + + case 0x87: + strcpy(buffer, "Illegal Postbyte"); + break; + + case 0x88: // (+/- 7 bit offset),R + offset = (INT8)opram[p++]; + buffer += sprintf(buffer, "%s", (offset < 0) ? "-" : ""); + buffer += sprintf(buffer, "$%02X,", (offset < 0) ? -offset : offset); + buffer += sprintf(buffer, "%s", m6809_regs[reg]); + break; + + case 0x89: // (+/- 15 bit offset),R + offset = (INT16)((opram[p+0] << 8) + opram[p+1]); + p += 2; + buffer += sprintf(buffer, "%s", (offset < 0) ? "-" : ""); + buffer += sprintf(buffer, "$%04X,", (offset < 0) ? -offset : offset); + buffer += sprintf(buffer, "%s", m6809_regs[reg]); + break; + + case 0x8a: + strcpy(buffer, "Illegal Postbyte"); + break; + + case 0x8b: // (+/- D),R + buffer += sprintf(buffer, "D,%s", m6809_regs[reg]); + break; + + case 0x8c: // (+/- 7 bit offset),PC + offset = (INT8)opram[p++]; + buffer += sprintf(buffer, "%s", (offset < 0) ? "-" : ""); + buffer += sprintf(buffer, "$%02X,PC", (offset < 0) ? -offset : offset); + break; + + case 0x8d: // (+/- 15 bit offset),PC + offset = (INT16)((opram[p+0] << 8) + opram[p+1]); + p += 2; + buffer += sprintf(buffer, "%s", (offset < 0) ? "-" : ""); + buffer += sprintf(buffer, "$%04X,PC", (offset < 0) ? -offset : offset); + break; + + case 0x8e: + strcpy(buffer, "Illegal Postbyte"); + break; + + case 0x8f: // address + ea = (UINT16)((opram[p+0] << 8) + opram[p+1]); + p += 2; + buffer += sprintf(buffer, "$%04X", ea); + break; + + default: // (+/- 4 bit offset),R + offset = pb & 0x1f; + if (offset > 15) + offset = offset - 32; + buffer += sprintf(buffer, "%s", (offset < 0) ? "-" : ""); + buffer += sprintf(buffer, "$%X,", (offset < 0) ? -offset : offset); + buffer += sprintf(buffer, "%s", m6809_regs[reg]); + break; + } + + // close brackets if indirect + if (indirect && pbm != 0x80 && pbm != 0x82) + buffer += sprintf(buffer, "]"); + break; + + case IMM: + if (numoperands == 2) + { + ea = (operandarray[0] << 8) + operandarray[1]; + buffer += sprintf(buffer, "#$%04X", ea); + } + else + if (numoperands == 1) + { + ea = operandarray[0]; + buffer += sprintf(buffer, "#$%02X", ea); + } + break; + + case IMM_RR: + pb = operandarray[0]; + buffer += sprintf(buffer, "%s,%s", m6809_regs_te[(pb >> 4) & 0xf], m6809_regs_te[pb & 0xf]); + break; + } + + return p | flags | DASMFLAG_SUPPORTED; +} diff --git a/src/devices/cpu/m6809/base6x09.ops b/src/devices/cpu/m6809/base6x09.ops new file mode 100644 index 00000000000..334521eb385 --- /dev/null +++ b/src/devices/cpu/m6809/base6x09.ops @@ -0,0 +1,537 @@ +NMI: + m_nmi_asserted = false; + m_cc |= CC_E; + set_regop16(m_s); + m_temp.w = entire_state_registers(); + %PUSH_REGISTERS; + m_cc |= CC_I | CC_F; + set_ea(VECTOR_NMI); + eat(1); + standard_irq_callback(INPUT_LINE_NMI); + goto INTERRUPT_VECTOR; + +FIRQ: + if (firq_saves_entire_state()) + { + m_cc |= CC_E; + m_temp.w = entire_state_registers(); + } + else + { + m_cc &= ~CC_E; + m_temp.w = partial_state_registers(); + } + set_regop16(m_s); + %PUSH_REGISTERS; + m_cc |= CC_I | CC_F; + set_ea(VECTOR_FIRQ); + eat(1); + standard_irq_callback(M6809_FIRQ_LINE); + goto INTERRUPT_VECTOR; + +IRQ: + m_cc |= CC_E; + set_regop16(m_s); + m_temp.w = entire_state_registers(); + %PUSH_REGISTERS; + m_cc |= CC_I; + set_ea(VECTOR_IRQ); + eat(1); + standard_irq_callback(M6809_IRQ_LINE); + goto INTERRUPT_VECTOR; + +INTERRUPT_VECTOR: + @eat(4); + @m_pc.b.h = read_operand(0); // Not sure if this is cycle exact + @m_pc.b.l = read_operand(1); // Not sure if this is cycle exact + return; + +NEG8: + @m_temp.b.l = read_operand(); + m_temp.b.l = set_flags(CC_NZVC, (UINT8)0, m_temp.b.l, -m_temp.b.l); + @eat(hd6309_native_mode() ? 0 : 1); + @write_operand(m_temp.b.l); + return; + +COM8: + @m_temp.b.l = read_operand(); + m_cc &= ~CC_V; + m_cc |= CC_C; + m_temp.b.l = set_flags(CC_NZ, (UINT8) ~m_temp.b.l); + @eat(hd6309_native_mode() ? 0 : 1); + @write_operand(m_temp.b.l); + return; + +LSR8: + @m_temp.b.l = read_operand(); + m_cc &= ~CC_C; + m_cc |= (m_temp.b.l & 1) ? CC_C : 0; + m_temp.b.l = set_flags(CC_NZ, m_temp.b.l >> 1); + @eat(hd6309_native_mode() ? 0 : 1); + @write_operand(m_temp.b.l); + return; + +ROR8: + @m_temp.b.l = read_operand(); + m_temp.b.l = set_flags(CC_NZ, rotate_right(m_temp.b.l)); + @eat(hd6309_native_mode() ? 0 : 1); + @write_operand(m_temp.b.l); + return; + +ASR8: + @m_temp.b.l = read_operand(); + m_cc &= ~CC_NZC; + m_cc |= (m_temp.b.l & 1) ? CC_C : 0; + m_temp.b.l = set_flags(CC_NZ, ((INT8) m_temp.b.l) >> 1); + @eat(hd6309_native_mode() ? 0 : 1); + @write_operand(m_temp.b.l); + return; + +ASL8: + @m_temp.b.l = read_operand(); + m_temp.b.l = set_flags(CC_NZVC, m_temp.b.l, m_temp.b.l, m_temp.b.l << 1); + @eat(hd6309_native_mode() ? 0 : 1); + @write_operand(m_temp.b.l); + return; + +ROL8: + @m_temp.b.l = read_operand(); + m_temp.b.l = set_flags(CC_NZV, m_temp.b.l, m_temp.b.l, rotate_left(m_temp.b.l)); + @eat(hd6309_native_mode() ? 0 : 1); + @write_operand(m_temp.b.l); + return; + +DEC8: + @m_temp.b.l = read_operand(); + m_temp.b.l = set_flags(CC_NZV, m_temp.b.l, 1, m_temp.b.l - 1); + @eat(hd6309_native_mode() && is_register_addressing_mode() ? 0 : 1); + @write_operand(m_temp.b.l); + return; + +INC8: + @m_temp.b.l = read_operand(); + m_temp.b.l = set_flags(CC_NZV, m_temp.b.l, 1, m_temp.b.l + 1); + @eat(hd6309_native_mode() && is_register_addressing_mode() ? 0 : 1); + @write_operand(m_temp.b.l); + return; + +TST8: + @m_temp.b.l = read_operand(); + set_flags(CC_NZV, m_temp.b.l); + eat(hd6309_native_mode() ? 0 : 1); + eat(is_register_addressing_mode() ? 0 : 1); + return; + +JMP: + m_pc.w = m_ea.w; + return; + +CLR8: + @read_operand(); + m_cc &= ~CC_NZVC; + m_cc |= CC_Z; + @eat(hd6309_native_mode() && is_register_addressing_mode() ? 0 : 1); + @write_operand(0); + return; + +NEG16: + m_temp.b.h = read_operand(0); + m_temp.b.l = read_operand(1); + m_temp.w = set_flags(CC_NZVC, (UINT16)0, m_temp.w, -m_temp.w); + eat(hd6309_native_mode() ? 0 : 1); + write_operand(0, m_temp.b.h); + write_operand(1, m_temp.b.l); + return; + +LSR16: + @m_temp.b.h = read_operand(0); + @m_temp.b.l = read_operand(1); + m_cc &= ~CC_C; + m_cc |= (m_temp.w & 1) ? CC_C : 0; + m_temp.w = set_flags(CC_NZ, m_temp.w >> 1); + @eat(hd6309_native_mode() ? 0 : 1); + @write_operand(0, m_temp.b.h); + write_operand(1, m_temp.b.l); + return; + +ROR16: + @m_temp.b.h = read_operand(0); + @m_temp.b.l = read_operand(1); + m_temp.w = set_flags(CC_NZ, rotate_right(m_temp.w)); + @eat(hd6309_native_mode() ? 0 : 1); + @write_operand(0, m_temp.b.h); + write_operand(1, m_temp.b.l); + return; + +ASR16: + @m_temp.b.h = read_operand(0); + @m_temp.b.l = read_operand(1); + m_cc &= ~CC_NZC; + m_cc |= (m_temp.w & 1) ? CC_C : 0; + m_temp.w = set_flags(CC_NZ, ((INT16) m_temp.w) >> 1); + @eat(hd6309_native_mode() ? 0 : 1); + @write_operand(0, m_temp.b.h); + write_operand(1, m_temp.b.l); + return; + +ASL16: + @m_temp.b.h = read_operand(0); + @m_temp.b.l = read_operand(1); + m_temp.w = set_flags(CC_NZVC, m_temp.w, m_temp.w, m_temp.w << 1); + @eat(hd6309_native_mode() ? 0 : 1); + @write_operand(0, m_temp.b.h); + write_operand(1, m_temp.b.l); + return; + +ROL16: + @m_temp.b.h = read_operand(0); + @m_temp.b.l = read_operand(1); + m_temp.w = set_flags(CC_NZV, rotate_left(m_temp.w)); + @eat(hd6309_native_mode() ? 0 : 1); + @write_operand(0, m_temp.b.h); + write_operand(1, m_temp.b.l); + return; + +DEC16: + m_temp.b.h = read_operand(0); + m_temp.b.l = read_operand(1); + m_temp.w = set_flags(CC_NZVC, m_temp.w, 1, m_temp.w - 1); + eat(hd6309_native_mode() ? 0 : 1); + write_operand(0, m_temp.b.h); + write_operand(1, m_temp.b.l); + return; + +INC16: + m_temp.b.h = read_operand(0); + m_temp.b.l = read_operand(1); + m_temp.w = set_flags(CC_NZVC, m_temp.w, 1, m_temp.w + 1); + eat(hd6309_native_mode() ? 0 : 1); + write_operand(0, m_temp.b.h); + write_operand(1, m_temp.b.l); + return; + +TST16: + m_temp.b.h = read_operand(0); + m_temp.b.l = read_operand(1); + set_flags(CC_NZV, m_temp.w); + eat(hd6309_native_mode() ? 0 : 1); + eat(is_register_addressing_mode() ? 0 : 1); + return; + +CLR16: + eat(hd6309_native_mode() ? 0 : 1); + m_cc &= ~CC_NZVC; + m_cc |= CC_Z; + write_operand(0, 0x00); + write_operand(1, 0x00); + return; + +SUB8: + m_temp.b.l = read_operand(); + regop8() = set_flags(CC_NZVC, regop8(), m_temp.b.l, regop8() - m_temp.b.l); + return; + +CMP8: + m_temp.b.l = read_operand(); + set_flags(CC_NZVC, regop8(), m_temp.b.l, regop8() - m_temp.b.l); + return; + +SBC8: + m_temp.w = (UINT16)read_operand() + (m_cc & CC_C ? 1 : 0); + regop8() = set_flags(CC_NZVC, regop8(), m_temp.b.l, regop8() - m_temp.w); + return; + +AND8: + m_cc &= ~CC_V; + regop8() = set_flags(CC_NZ, (UINT8)0, regop8(), regop8() & read_operand()); + return; + +BIT8: + m_cc &= ~CC_V; + set_flags(CC_NZ, (UINT8)0, regop8(), regop8() & read_operand()); + return; + +EOR8: + m_cc &= ~CC_V; + regop8() = set_flags(CC_NZ, (UINT8)0, regop8(), regop8() ^ read_operand()); + return; + +ADC8: + m_temp.w = (UINT16)read_operand() + (m_cc & CC_C ? 1 : 0); + regop8() = set_flags(add8_sets_h() ? CC_HNZVC : CC_NZVC, regop8(), m_temp.b.l, regop8() + m_temp.w); + return; + +OR8: + m_cc &= ~CC_V; + regop8() = set_flags(CC_NZ, (UINT8)0, regop8(), regop8() | read_operand()); + return; + +ADD8: + m_temp.b.l = read_operand(); + regop8() = set_flags(add8_sets_h() ? CC_HNZVC : CC_NZVC, regop8(), m_temp.b.l, regop8() + m_temp.b.l); + return; + +ADD16: + @m_temp.b.h = read_operand(0); + @m_temp.b.l = read_operand(1); + regop16().w = set_flags(CC_NZVC, regop16().w, m_temp.w, regop16().w + m_temp.w); + eat(hd6309_native_mode() ? 0 : 1); + return; + +SUB16: + @m_temp.b.h = read_operand(0); + @m_temp.b.l = read_operand(1); + regop16().w = set_flags(CC_NZVC, regop16().w, m_temp.w, regop16().w - m_temp.w); + eat(hd6309_native_mode() ? 0 : 1); + return; + +CMP16: + @m_temp.b.h = read_operand(0); + @m_temp.b.l = read_operand(1); + set_flags(CC_NZVC, regop16().w, m_temp.w, regop16().w - m_temp.w); + eat(hd6309_native_mode() ? 0 : 1); + return; + +LD8: + regop8() = read_operand(); + set_flags(CC_NZV, regop8()); + return; + +LD16: + @regop16().b.h = read_operand(0); + @regop16().b.l = read_operand(1); + set_flags(CC_NZV, regop16().w); + if (®op16() == &m_s) + m_lds_encountered = true; + return; + +ST8: + write_ea(set_flags(CC_NZV, regop8())); + return; + +ST16: + @write_operand(0, regop16().b.h); + @write_operand(1, regop16().b.l); + set_flags(CC_NZV, regop16().w); + return; + +NOP: + eat(hd6309_native_mode() ? 0 : 1); + return; + +SYNC: + // SYNC stops processing instructions until an interrupt request happens. + // This doesn't require the corresponding interrupt to be enabled: if it + // is disabled, execution continues with the next instruction. + eat(3); + + while(!m_nmi_asserted && !m_firq_line && !m_irq_line) + { + // massaging the PC this way makes the debugger's behavior more + // intuitive + m_pc.w--; + + @eat_remaining(); + + // unmassage... + m_pc.w++; + } + return; + +DAA: + daa(); + eat(hd6309_native_mode() ? 0 : 1); + return; + +ORCC: + m_cc |= read_operand(); + eat(hd6309_native_mode() ? 0 : 1); + return; + +ANDCC: + m_cc &= read_operand(); + eat(1); + return; + +SEX: + m_d.w = set_flags(CC_NZ, (INT8) m_d.b.l); + eat(hd6309_native_mode() ? 0 : 1); + return; + +BRANCH: + @m_temp.b.l = read_opcode_arg(); + eat(1); + if (branch_taken()) + { + m_pc.w += (INT8) m_temp.b.l; + } + return; + +LBRANCH: + @m_temp.b.h = read_opcode_arg(); + @m_temp.b.l = read_opcode_arg(); + eat(1); + if (branch_taken()) + { + m_pc.w += m_temp.w; + eat(hd6309_native_mode() ? 0 : 1); + } + return; + +BSR: + @m_temp.b.l = read_opcode_arg(); + m_ea.w = m_pc.w + (INT8) m_temp.b.l; + @eat(hd6309_native_mode() ? 2 : 3); + goto GOTO_SUBROUTINE; + +LBSR: + @m_temp.b.h = read_opcode_arg(); + @m_temp.b.l = read_opcode_arg(); + m_ea.w = m_pc.w + (INT16) m_temp.w; + @eat(hd6309_native_mode() ? 2 : 4); + goto GOTO_SUBROUTINE; + +JSR: + @eat(2); + goto GOTO_SUBROUTINE; + +GOTO_SUBROUTINE: + @write_memory(--m_s.w, m_pc.b.l); + @write_memory(--m_s.w, m_pc.b.h); + m_pc = m_ea; + return; + +RTS: + m_temp.w = 0x80; // RTS is equivalent to "PULS PC" + eat(hd6309_native_mode() ? 0 : 1); + set_regop16(m_s); + goto PULL_REGISTERS; + +ABX: + m_x.w += m_d.b.l; + eat(hd6309_native_mode() ? 0 : 2); + return; + +MUL: + mul(); + eat(hd6309_native_mode() ? 9 : 10); + return; + +RTI: + set_regop16(m_s); + m_temp.w = 0x01; // PULS CC + %PULL_REGISTERS; + m_temp.w = ((m_cc & CC_E) ? entire_state_registers() : partial_state_registers()) & ~0x01; + goto PULL_REGISTERS; + +CWAI: + @m_cc &= read_opcode_arg(); + @eat(2); + + m_cc |= CC_E; + set_regop16(m_s); + m_temp.w = entire_state_registers(); + %PUSH_REGISTERS; + + while((m_ea.w = get_pending_interrupt()) == 0) + { + // massaging the PC this way makes the debugger's behavior more + // intuitive + m_pc.w -= 2; + + @eat_remaining(); + + // unmassage... + m_pc.w += 2; + } + + if (m_nmi_asserted) + m_nmi_asserted = false; + + set_ea(m_ea.w); // need to do this to set the addressing mode + m_cc |= CC_I | (m_ea.w != VECTOR_IRQ ? CC_F : 0); + + // invoke standard interrupt callback for MAME core + switch (m_ea.w) + { + case VECTOR_NMI: standard_irq_callback(INPUT_LINE_NMI); break; + case VECTOR_FIRQ: standard_irq_callback(M6809_FIRQ_LINE); break; + case VECTOR_IRQ: standard_irq_callback(M6809_IRQ_LINE); break; + default: break; + } + + goto INTERRUPT_VECTOR; + +LEA_xy: + regop16().w = set_flags(CC_Z, m_ea.w); + eat(1); + return; + +LEA_us: + if (®op16() == &m_s) + m_lds_encountered = true; + regop16().w = m_ea.w; + eat(1); + return; + +PSHS: + @m_temp.w = read_opcode_arg(); + @eat(hd6309_native_mode() ? 2 : 3); + set_regop16(m_s); + goto PUSH_REGISTERS; + +PULS: + @m_temp.w = read_opcode_arg(); + @eat(hd6309_native_mode() ? 1 : 2); + set_regop16(m_s); + goto PULL_REGISTERS; + +PSHU: + @m_temp.w = read_opcode_arg(); + @eat(hd6309_native_mode() ? 2 : 3); + set_regop16(m_u); + goto PUSH_REGISTERS; + +PULU: + @m_temp.w = read_opcode_arg(); + @eat(hd6309_native_mode() ? 1 : 2); + set_regop16(m_u); + goto PULL_REGISTERS; + +SWI: + // doesn't use SOFTWARE_INTERRUPT label because SWI will + // inhibit IRQ/FIRQ + set_ea(VECTOR_SWI); + m_cc |= CC_E; + set_regop16(m_s); + m_temp.w = entire_state_registers(); + %PUSH_REGISTERS; + m_cc |= CC_I | CC_F; + goto INTERRUPT_VECTOR; + +SWI2: + set_ea(VECTOR_SWI2); + goto SOFTWARE_INTERRUPT; + +SWI3: + set_ea(VECTOR_SWI3); + goto SOFTWARE_INTERRUPT; + +SOFTWARE_INTERRUPT: + // used for SWI2/SWI3 and illegal/div0 on 6309 + m_cc |= CC_E; + set_regop16(m_s); + m_temp.w = entire_state_registers(); + %PUSH_REGISTERS; + goto INTERRUPT_VECTOR; + +DIRECT: + @set_ea(((UINT16)m_dp << 8) | read_opcode_arg()); + @eat(hd6309_native_mode() ? 0 : 1); + return; + +EXTENDED: + @set_ea_h(read_opcode_arg()); + @set_ea_l(read_opcode_arg()); + @eat(hd6309_native_mode() ? 0 : 1); + return; diff --git a/src/devices/cpu/m6809/hd6309.c b/src/devices/cpu/m6809/hd6309.c new file mode 100644 index 00000000000..5b270d26c90 --- /dev/null +++ b/src/devices/cpu/m6809/hd6309.c @@ -0,0 +1,812 @@ +// license:BSD-3-Clause +// copyright-holders:Nathan Woods,Tim Lindner +/********************************************************************* + + hd6309.c + + Copyright John Butler + Copyright Tim Lindner + + References: + + HD63B09EP Technical Reference Guide, by Chet Simpson with addition + by Alan Dekok + 6809 Simulator V09, By L.C. Benschop, Eindhoven The Netherlands. + + m6809: Portable 6809 emulator, DS (6809 code in MAME, derived from + the 6809 Simulator V09) + + 6809 Microcomputer Programming & Interfacing with Experiments" + by Andrew C. Staugaard, Jr.; Howard W. Sams & Co., Inc. + + System dependencies: UINT16 must be 16 bit unsigned int + UINT8 must be 8 bit unsigned int + UINT32 must be more than 16 bits + arrays up to 65536 bytes must be supported + machine must be twos complement + + History: + +March 2013 NPW: + Rewrite of 6809/6309/Konami CPU; attempted to make cycle exact. + +070614 ZV: + Fixed N flag setting in DIV overflow + +991026 HJB: + Fixed missing calls to cpu_changepc() for the TFR and EXG ocpodes. + Replaced m6809_slapstic checks by a macro (CHANGE_PC). ESB still + needs the tweaks. + +991024 HJB: + Tried to improve speed: Using bit7 of cycles1/2 as flag for multi + byte opcodes is gone, those opcodes now call fetch_effective_address(). + Got rid of the slow/fast flags for stack (S and U) memory accesses. + Minor changes to use 32 bit values as arguments to memory functions + and added defines for that purpose (e.g. X = 16bit XD = 32bit). + +990312 HJB: + Added bugfixes according to Aaron's findings. + Reset only sets CC_II and CC_IF, DP to zero and PC from reset vector. +990311 HJB: + Added _info functions. Now uses static m6808_Regs struct instead + of single statics. Changed the 16 bit registers to use the generic + PAIR union. Registers defined using macros. Split the core into + four execution loops for M6802, M6803, M6808 and HD63701. + TST, TSTA and TSTB opcodes reset carry flag. + Modified the read/write stack handlers to push LSB first then MSB + and pull MSB first then LSB. + +990228 HJB: + Changed the interrupt handling again. Now interrupts are taken + either right at the moment the lines are asserted or whenever + an interrupt is enabled and the corresponding line is still + asserted. That way the pending_interrupts checks are not + needed anymore. However, the CWAI and SYNC flags still need + some flags, so I changed the name to 'int_state'. + This core also has the code for the old interrupt system removed. + +990225 HJB: + Cleaned up the code here and there, added some comments. + Slightly changed the SAR opcodes (similiar to other CPU cores). + Added symbolic names for the flag bits. + Changed the way CWAI/Interrupt() handle CPU state saving. + A new flag M6809_STATE in pending_interrupts is used to determine + if a state save is needed on interrupt entry or already done by CWAI. + Added M6809_IRQ_LINE and M6809_FIRQ_LINE defines to m6809.h + Moved the internal interrupt_pending flags from m6809.h to m6809.c + Changed CWAI cycles2[0x3c] to be 2 (plus all or at least 19 if + CWAI actually pushes the entire state). + Implemented undocumented TFR/EXG for undefined source and mixed 8/16 + bit transfers (they should transfer/exchange the constant $ff). + Removed unused jmp/jsr _slap functions from 6809ops.c, + m6809_slapstick check moved into the opcode functions. + +000809 TJL: + Started converting m6809 into hd6309 + +001217 TJL: + Finished: + All opcodes + Dual Timing + To Do: + Verify new DIV opcodes. + +070805 TJL: + Fixed ADDR and ADCR opcodes not to clear the H condition code. Fixed ANDR, + EORR, ORR, ADDR, ADCR, SBCR, and SUBR to evaluate condition codes after + the destination register was set. Fixed BITMD opcode to only effect the Z + condition code. Fixed BITMD opcode to clear only tested flags. Fixed EXG + and TFR register promotion and demotion. Fixed illegal instruction handler + to not set I and F condition codes. Credit to Darren Atkinson for the + discovery of these bugs. + +090907 TJL: + The SEXW instruction is clearing the Overflow flag (V). It should not do + that. When an invalid source or destination register is specified for + the TFM instructions, real hardware invokes the Illegal Instruction + trap, whereas the emulator simply ignores the instruction. Credit to + Darren Atkinson for the discovery of these bugs. + +*****************************************************************************/ + +#include "emu.h" +#include "debugger.h" +#include "hd6309.h" +#include "m6809inl.h" + + +//************************************************************************** +// DEVICE INTERFACE +//************************************************************************** + +const device_type HD6309 = &device_creator; + + +//------------------------------------------------- +// hd6309_device - constructor +//------------------------------------------------- + +hd6309_device::hd6309_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : m6809_base_device(mconfig, "HD6309", tag, owner, clock, HD6309, 4, "hd6309", __FILE__) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void hd6309_device::device_start() +{ + super::device_start(); + + // register our state for the debugger + state_add(HD6309_E, "E", m_w.b.h).mask(0xff); + state_add(HD6309_F, "F", m_w.b.l).mask(0xff); + state_add(HD6309_W, "W", m_w.w).mask(0xffff); + state_add(HD6309_V, "V", m_v.w).mask(0xffff); + state_add(HD6309_MD, "MD", m_md).mask(0xff); + + // initialize variables + m_w.w = 0x0000; + m_v.w = 0x0000; + m_md = 0x00; + m_temp_im = 0x00; + + // setup regtable + save_item(NAME(m_w.w)); + save_item(NAME(m_v.w)); + save_item(NAME(m_md)); + save_item(NAME(m_temp_im)); +} + + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void hd6309_device::device_reset() +{ + super::device_reset(); + + // initialize variables + m_md = 0x00; +} + + +//------------------------------------------------- +// device_pre_save - device-specific pre-save +//------------------------------------------------- + +void hd6309_device::device_pre_save() +{ + if (m_reg8 == &m_d.b.h) m_reg = HD6309_A; + else if (m_reg8 == &m_d.b.l) m_reg = HD6309_B; + else if (m_reg8 == &m_w.b.h) m_reg = HD6309_E; + else if (m_reg8 == &m_w.b.l) m_reg = HD6309_F; + else if (m_reg8 == &m_cc) m_reg = HD6309_CC; + else if (m_reg8 == &m_dp) m_reg = HD6309_DP; + else if (m_reg8 == &m_md) m_reg = HD6309_MD; + else if (m_reg8 == &m_temp.b.l) m_reg = HD6309_ZERO_BYTE; + + else if (m_reg16 == &m_d) m_reg = HD6309_D; + else if (m_reg16 == &m_x) m_reg = HD6309_X; + else if (m_reg16 == &m_y) m_reg = HD6309_Y; + else if (m_reg16 == &m_u) m_reg = HD6309_U; + else if (m_reg16 == &m_s) m_reg = HD6309_S; + else if (m_reg16 == &m_pc) m_reg = HD6309_PC; + else if (m_reg16 == &m_w) m_reg = HD6309_W; + else if (m_reg16 == &m_v) m_reg = HD6309_V; + else if (m_reg16 == &m_temp) m_reg = HD6309_ZERO_WORD; + else + m_reg = 0; +} + + +//------------------------------------------------- +// device_post_load - device-specific post-load +//------------------------------------------------- + +void hd6309_device::device_post_load() +{ + m_reg8 = NULL; + m_reg16 = NULL; + + switch(m_reg) + { + case HD6309_A: + set_regop8(m_d.b.h); + break; + case HD6309_B: + set_regop8(m_d.b.l); + break; + case HD6309_E: + set_regop8(m_w.b.h); + break; + case HD6309_F: + set_regop8(m_w.b.l); + break; + case HD6309_CC: + set_regop8(m_cc); + break; + case HD6309_DP: + set_regop8(m_dp); + break; + case HD6309_MD: + set_regop8(m_md); + break; + case HD6309_ZERO_BYTE: + set_regop8(m_temp.b.l); + break; + + case HD6309_D: + set_regop16(m_d); + break; + case HD6309_X: + set_regop16(m_x); + break; + case HD6309_Y: + set_regop16(m_y); + break; + case HD6309_U: + set_regop16(m_u); + break; + case HD6309_S: + set_regop16(m_s); + break; + case HD6309_PC: + set_regop16(m_pc); + break; + case HD6309_W: + set_regop16(m_w); + break; + case HD6309_V: + set_regop16(m_v); + break; + case HD6309_ZERO_WORD: + set_regop16(m_temp); + break; + } +} + + +//------------------------------------------------- +// disasm_min_opcode_bytes - return the length +// of the shortest instruction, in bytes +//------------------------------------------------- + +UINT32 hd6309_device::disasm_min_opcode_bytes() const +{ + return 1; +} + + + +//------------------------------------------------- +// disasm_max_opcode_bytes - return the length +// of the longest instruction, in bytes +//------------------------------------------------- + +UINT32 hd6309_device::disasm_max_opcode_bytes() const +{ + return 5; +} + + + +//------------------------------------------------- +// disasm_disassemble - call the disassembly +// helper function +//------------------------------------------------- + +offs_t hd6309_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( hd6309 ); + return CPU_DISASSEMBLE_NAME(hd6309)(this, buffer, pc, oprom, opram, options); +} + + + +//------------------------------------------------- +// read_operand +//------------------------------------------------- + +inline UINT8 hd6309_device::read_operand() +{ + switch(m_addressing_mode) + { + case ADDRESSING_MODE_EA: return read_memory(m_ea.w); + case ADDRESSING_MODE_IMMEDIATE: return read_opcode_arg(); + case ADDRESSING_MODE_REGISTER_A: return m_d.b.h; + case ADDRESSING_MODE_REGISTER_B: return m_d.b.l; + case ADDRESSING_MODE_REGISTER_E: return m_w.b.h; + case ADDRESSING_MODE_REGISTER_F: return m_w.b.l; + default: fatalerror("Unexpected"); + } +} + + +//------------------------------------------------- +// read_operand +//------------------------------------------------- + +inline UINT8 hd6309_device::read_operand(int ordinal) +{ + switch(m_addressing_mode) + { + case ADDRESSING_MODE_EA: return read_memory(m_ea.w + ordinal); + case ADDRESSING_MODE_IMMEDIATE: return read_opcode_arg(); + case ADDRESSING_MODE_REGISTER_D: return (ordinal & 1) ? m_d.b.l : m_d.b.h; + case ADDRESSING_MODE_REGISTER_W: return (ordinal & 1) ? m_w.b.l : m_w.b.h; + case ADDRESSING_MODE_REGISTER_X: return (ordinal & 1) ? m_x.b.l : m_x.b.h; + case ADDRESSING_MODE_REGISTER_Y: return (ordinal & 1) ? m_y.b.l : m_y.b.h; + case ADDRESSING_MODE_REGISTER_U: return (ordinal & 1) ? m_u.b.l : m_u.b.h; + case ADDRESSING_MODE_REGISTER_S: return (ordinal & 1) ? m_s.b.l : m_s.b.h; + case ADDRESSING_MODE_REGISTER_V: return (ordinal & 1) ? m_v.b.l : m_v.b.h; + case ADDRESSING_MODE_REGISTER_PC: return (ordinal & 1) ? m_pc.b.l : m_pc.b.h; + case ADDRESSING_MODE_ZERO: return 0x00; + default: fatalerror("Unexpected"); + } +} + + +//------------------------------------------------- +// write_operand +//------------------------------------------------- + +inline void hd6309_device::write_operand(UINT8 data) +{ + switch(m_addressing_mode) + { + case ADDRESSING_MODE_EA: write_memory(m_ea.w, data); break; + case ADDRESSING_MODE_REGISTER_A: m_d.b.h = data; break; + case ADDRESSING_MODE_REGISTER_B: m_d.b.l = data; break; + case ADDRESSING_MODE_REGISTER_E: m_w.b.h = data; break; + case ADDRESSING_MODE_REGISTER_F: m_w.b.l = data; break; + case ADDRESSING_MODE_ZERO: break; + default: fatalerror("Unexpected"); + } +} + + +//------------------------------------------------- +// write_operand +//------------------------------------------------- + +inline void hd6309_device::write_operand(int ordinal, UINT8 data) +{ + switch(m_addressing_mode) + { + case ADDRESSING_MODE_EA: write_memory(m_ea.w + ordinal, data); break; + case ADDRESSING_MODE_REGISTER_D: *((ordinal & 1) ? &m_d.b.l : &m_d.b.h) = data; break; + case ADDRESSING_MODE_REGISTER_W: *((ordinal & 1) ? &m_w.b.l : &m_w.b.h) = data; break; + case ADDRESSING_MODE_REGISTER_X: *((ordinal & 1) ? &m_x.b.l : &m_x.b.h) = data; break; + case ADDRESSING_MODE_REGISTER_Y: *((ordinal & 1) ? &m_y.b.l : &m_y.b.h) = data; break; + case ADDRESSING_MODE_REGISTER_U: *((ordinal & 1) ? &m_u.b.l : &m_u.b.h) = data; break; + case ADDRESSING_MODE_REGISTER_S: *((ordinal & 1) ? &m_s.b.l : &m_s.b.h) = data; break; + case ADDRESSING_MODE_REGISTER_V: *((ordinal & 1) ? &m_v.b.l : &m_v.b.h) = data; break; + case ADDRESSING_MODE_REGISTER_PC: *((ordinal & 1) ? &m_pc.b.l : &m_pc.b.h) = data; break; + case ADDRESSING_MODE_ZERO: break; + default: fatalerror("Unexpected"); + } +} + + +//------------------------------------------------- +// bittest_register +//------------------------------------------------- + +inline UINT8 &hd6309_device::bittest_register() +{ + switch(m_temp_im & 0xC0) + { + case 0x00: return m_cc; + case 0x40: return m_d.b.h; + case 0x80: return m_d.b.l; + default: return m_temp.b.l; + } +} + + +//------------------------------------------------- +// bittest_source +//------------------------------------------------- + +inline bool hd6309_device::bittest_source() +{ + return (m_temp.b.l & (1 << ((m_temp_im >> 3) & 0x07))) ? true : false; +} + + +//------------------------------------------------- +// bittest_dest +//------------------------------------------------- + +inline bool hd6309_device::bittest_dest() +{ + return (bittest_register() & (1 << ((m_temp_im >> 0) & 0x07))) ? true : false; +} + + +//------------------------------------------------- +// bittest_set +//------------------------------------------------- + +inline void hd6309_device::bittest_set(bool result) +{ + if (result) + bittest_register() |= (1 << ((m_temp_im >> 0) & 0x07)); + else + bittest_register() &= ~(1 << ((m_temp_im >> 0) & 0x07)); + eat(4); +} + + +//------------------------------------------------- +// read_exgtfr_register +//------------------------------------------------- + +inline m6809_base_device::exgtfr_register hd6309_device::read_exgtfr_register(UINT8 reg) +{ + UINT16 value = 0; + + switch(reg & 0x0F) + { + case 0: value = m_d.w; break; // D + case 1: value = m_x.w; break; // X + case 2: value = m_y.w; break; // Y + case 3: value = m_u.w; break; // U + case 4: value = m_s.w; break; // S + case 5: value = m_pc.w; break; // PC + case 6: value = m_w.w; break; // W + case 7: value = m_v.w; break; // V + case 8: value = ((UINT16) m_d.b.h) << 8 | m_d.b.h; break; // A + case 9: value = ((UINT16) m_d.b.l) << 8 | m_d.b.l; break; // B + case 10: value = ((UINT16) m_cc) << 8 | m_cc; break; // CC + case 11: value = ((UINT16) m_dp) << 8 | m_dp; break; // DP + case 12: value = 0; break; // 0 + case 13: value = 0; break; // 0 + case 14: value = ((UINT16) m_w.b.h) << 8 | m_w.b.h; break; // E + case 15: value = ((UINT16) m_w.b.l) << 8 | m_w.b.l; break; // F + default: + fatalerror("Should not reach here"); + } + + exgtfr_register result; + result.byte_value = (UINT8)value; + result.word_value = value; + return result; +} + + + +//------------------------------------------------- +// write_exgtfr_register +//------------------------------------------------- + +inline void hd6309_device::write_exgtfr_register(UINT8 reg, m6809_base_device::exgtfr_register value) +{ + switch(reg & 0x0F) + { + case 0: m_d.w = value.word_value; break; // D + case 1: m_x.w = value.word_value; break; // X + case 2: m_y.w = value.word_value; break; // Y + case 3: m_u.w = value.word_value; break; // U + case 4: m_s.w = value.word_value; break; // S + case 5: m_pc.w = value.word_value; break; // PC + case 6: m_w.w = value.word_value; break; // W + case 7: m_v.w = value.word_value; break; // V + case 8: m_d.b.h = (UINT8) (value.word_value >> 8); break; // A + case 9: m_d.b.l = (UINT8) (value.word_value >> 0); break; // B + case 10: m_cc = (UINT8) (value.word_value >> 0); break; // CC + case 11: m_dp = (UINT8) (value.word_value >> 8); break; // DP + case 12: break; // 0 + case 13: break; // 0 + case 14: m_w.b.h = (UINT8) (value.word_value >> 8); break; // E + case 15: m_w.b.l = (UINT8) (value.word_value >> 0); break; // F + default: + fatalerror("Should not reach here"); + } +} + + + +//------------------------------------------------- +// tfr_read +//------------------------------------------------- + +inline bool hd6309_device::tfr_read(UINT8 opcode, UINT8 arg, UINT8 &data) +{ + PAIR16 *reg; + + switch(arg & 0xF0) + { + case 0x00: reg = &m_d; break; + case 0x10: reg = &m_x; break; + case 0x20: reg = &m_y; break; + case 0x30: reg = &m_u; break; + case 0x40: reg = &m_s; break; + default: return false; + } + + data = read_memory(reg->w); + + switch(opcode & 0x03) + { + case 0x00: reg->w++; break; // TFM R0+,R1+ + case 0x01: reg->w--; break; // TFM R0-,R1- + case 0x02: reg->w++; break; // TFM R0+,R1 + case 0x03: break; // TFM R0,R1+ + } + + return true; +} + + + +//------------------------------------------------- +// tfr_write +//------------------------------------------------- + +inline bool hd6309_device::tfr_write(UINT8 opcode, UINT8 arg, UINT8 data) +{ + PAIR16 *reg; + + switch(arg & 0x0F) + { + case 0x00: reg = &m_d; break; + case 0x01: reg = &m_x; break; + case 0x02: reg = &m_y; break; + case 0x03: reg = &m_u; break; + case 0x04: reg = &m_s; break; + default: return false; + } + + write_memory(reg->w, data); + + switch(opcode & 0x03) + { + case 0x00: reg->w++; break; // TFM R0+,R1+ + case 0x01: reg->w--; break; // TFM R0-,R1- + case 0x02: break; // TFM R0+,R1 + case 0x03: reg->w++; break; // TFM R0,R1+ + } + + return true; +} + + + +//------------------------------------------------- +// register_register_op +//------------------------------------------------- + +void hd6309_device::register_register_op() +{ + UINT8 operand = read_opcode_arg(); + + // if the 8/16 bit values are mismatched, we need to promote + bool promote = ((operand & 0x80) ? true : false) != ((operand & 0x08) ? true : false); + + // we're using m_temp as "register 0" + m_temp.w = 0; + + // set destination + switch((operand >> 0) & 0x0F) + { + case 0: set_regop16(m_d); break; // D + case 1: set_regop16(m_x); break; // X + case 2: set_regop16(m_y); break; // Y + case 3: set_regop16(m_u); break; // U + case 4: set_regop16(m_s); break; // S + case 5: set_regop16(m_pc); break; // PC + case 6: set_regop16(m_w); break; // W + case 7: set_regop16(m_v); break; // V + case 8: if (promote) set_regop16(m_d); else set_regop8(m_d.b.h); break; // A + case 9: if (promote) set_regop16(m_d); else set_regop8(m_d.b.l); break; // B + case 10: if (promote) set_regop16(m_temp); else set_regop8(m_cc); break; // CC + case 11: if (promote) set_regop16(m_temp); else set_regop8(m_dp); break; // DP + case 12: if (promote) set_regop16(m_temp); else set_regop8(m_temp.b.l); break; // 0 + case 13: if (promote) set_regop16(m_temp); else set_regop8(m_temp.b.l); break; // 0 + case 14: if (promote) set_regop16(m_w); else set_regop8(m_w.b.h); break; // E + case 15: if (promote) set_regop16(m_w); else set_regop8(m_w.b.l); break; // F + default: + fatalerror("Should not reach here"); + } + + // set source + switch((operand >> 4) & 0x0F) + { + case 0: m_addressing_mode = ADDRESSING_MODE_REGISTER_D; break; // D + case 1: m_addressing_mode = ADDRESSING_MODE_REGISTER_X; break; // X + case 2: m_addressing_mode = ADDRESSING_MODE_REGISTER_Y; break; // Y + case 3: m_addressing_mode = ADDRESSING_MODE_REGISTER_U; break; // U + case 4: m_addressing_mode = ADDRESSING_MODE_REGISTER_S; break; // S + case 5: m_addressing_mode = ADDRESSING_MODE_REGISTER_PC; break; // PC + case 6: m_addressing_mode = ADDRESSING_MODE_REGISTER_W; break; // W + case 7: m_addressing_mode = ADDRESSING_MODE_REGISTER_V; break; // V + case 8: m_addressing_mode = promote ? ADDRESSING_MODE_REGISTER_D : ADDRESSING_MODE_REGISTER_A; break; // A + case 9: m_addressing_mode = promote ? ADDRESSING_MODE_REGISTER_D : ADDRESSING_MODE_REGISTER_B; break; // B + case 10: m_addressing_mode = promote ? ADDRESSING_MODE_ZERO : ADDRESSING_MODE_REGISTER_CC; break; // CC + case 11: m_addressing_mode = promote ? ADDRESSING_MODE_ZERO : ADDRESSING_MODE_REGISTER_DP; break; // DP + case 12: m_addressing_mode = ADDRESSING_MODE_ZERO; break; // 0 + case 13: m_addressing_mode = ADDRESSING_MODE_ZERO; break; // 0 + case 14: m_addressing_mode = promote ? ADDRESSING_MODE_REGISTER_W : ADDRESSING_MODE_REGISTER_E; break; // E + case 15: m_addressing_mode = promote ? ADDRESSING_MODE_REGISTER_W : ADDRESSING_MODE_REGISTER_F; break; // F + default: + fatalerror("Should not reach here"); + } + + // eat a single CPU cycle + eat(1); +} + + +//------------------------------------------------- +// get_q +//------------------------------------------------- + +UINT32 hd6309_device::get_q() +{ + PAIR result; + result.w.h = m_d.w; + result.w.l = m_w.w; + return result.d; +} + + +//------------------------------------------------- +// put_q +//------------------------------------------------- + +void hd6309_device::put_q(UINT32 value) +{ + PAIR pair; + pair.d = value; + m_d.w = pair.w.h; + m_w.w = pair.w.l; +} + + +//------------------------------------------------- +// muld - (Q := D * operand) +//------------------------------------------------- + +void hd6309_device::muld() +{ + UINT32 result; + result = ((INT16) m_d.w) * ((INT16) m_temp.w); + put_q(set_flags(CC_NZ, result)); + m_cc &= ~CC_VC; +} + + +//------------------------------------------------- +// divq - (D := Q / operand; W := Q % operand) +//------------------------------------------------- + +bool hd6309_device::divq() +{ + INT32 result; + + // check for divide by zero + if (m_temp.w == 0) + return false; + + INT32 q = get_q(); + INT32 old_q = q; + + // do the divide/modulo + result = q / (INT16) m_temp.w; + m_d.w = q % (INT16) m_temp.w; + + // set NZ condition codes + m_w.w = set_flags(CC_NZ, result); + + // set C condition code + if (m_w.w & 0x0001) + m_cc |= CC_C; + else + m_cc &= ~CC_C; + + if ((result > 32768) || (result < -32767)) + { + // soft overflow + m_cc |= CC_V; + + if ((result > 65536 ) || (result < -65535 )) + { + // hard overflow - division is aborted + if (old_q < 0) + m_cc |= CC_N; + else if (old_q == 0 ) + m_cc |= CC_Z; + + put_q(old_q); + } + } + else + { + // no overflow + m_cc &= ~CC_V; + } + + return true; +} + + +//------------------------------------------------- +// divd - (D := D / operand; W := D % operand) +//------------------------------------------------- + +bool hd6309_device::divd() +{ + // check for divide by zero + if (m_temp.b.l == 0) + return false; + + INT16 old_d = m_d.w; + INT16 result; + + // do the divide/modulo + result = ((INT16) m_d.w) / (INT8) m_temp.b.l; + m_d.b.h = ((INT16) m_d.w) % (INT8) m_temp.b.l; + + // set NZ condition codes + m_d.b.l = set_flags(CC_NZ, result); + + // set C condition code + if (m_d.b.l & 0x01) + m_cc |= CC_C; + else + m_cc &= ~CC_C; + + if ((result > 128) || (result < -127)) + { + // soft overflow + m_cc |= CC_V; + + if ((result > 256 ) || (result < -255 )) + { + // hard overflow - division is aborted + set_flags(CC_NZ, old_d); + m_d.w = abs(old_d); + } + } + else + { + // no overflow + m_cc &= ~CC_V; + } + + return true; +} + + +//------------------------------------------------- +// execute_one - try to execute a single instruction +//------------------------------------------------- + +inline void hd6309_device::execute_one() +{ + switch(pop_state()) + { +#include "cpu/m6809/hd6309.inc" + } +} + + +//------------------------------------------------- +// execute_run - execute a timeslice's worth of +// opcodes +//------------------------------------------------- + +void hd6309_device::execute_run() +{ + do + { + execute_one(); + } while(m_icount > 0); +} diff --git a/src/devices/cpu/m6809/hd6309.h b/src/devices/cpu/m6809/hd6309.h new file mode 100644 index 00000000000..15da7a6cc8d --- /dev/null +++ b/src/devices/cpu/m6809/hd6309.h @@ -0,0 +1,148 @@ +// license:BSD-3-Clause +// copyright-holders:Nathan Woods +/********************************************************************* + + hd6309.h + + Portable Hitachi 6309 emulator + +**********************************************************************/ + +#pragma once + +#ifndef __HD6309_H__ +#define __HD6309_H__ + +#include "m6809.h" + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// device type definition +extern const device_type HD6309; + +// ======================> hd6309_device + +class hd6309_device : public m6809_base_device +{ +public: + // construction/destruction + hd6309_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_pre_save(); + virtual void device_post_load(); + + // device_execute_interface overrides + virtual void execute_run(); + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const; + virtual UINT32 disasm_max_opcode_bytes() const; + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + +private: + typedef m6809_base_device super; + + // addressing modes + enum + { + ADDRESSING_MODE_REGISTER_E = 5, + ADDRESSING_MODE_REGISTER_F = 6, + ADDRESSING_MODE_REGISTER_W = 7, + ADDRESSING_MODE_REGISTER_X = 8, + ADDRESSING_MODE_REGISTER_Y = 9, + ADDRESSING_MODE_REGISTER_U = 10, + ADDRESSING_MODE_REGISTER_S = 11, + ADDRESSING_MODE_REGISTER_CC = 12, + ADDRESSING_MODE_REGISTER_DP = 13, + ADDRESSING_MODE_REGISTER_PC = 14, + ADDRESSING_MODE_REGISTER_V = 15, + ADDRESSING_MODE_ZERO = 16 + }; + + // interrupt vectors + enum + { + VECTOR_ILLEGAL = 0xFFF0 + }; + + // CPU registers + PAIR16 m_w; + PAIR16 m_v; + UINT8 m_md; + + // other state + UINT8 m_temp_im; + + // operand reading/writing + UINT8 read_operand(); + UINT8 read_operand(int ordinal); + void write_operand(UINT8 data); + void write_operand(int ordinal, UINT8 data); + + // interrupt registers + bool firq_saves_entire_state() { return m_md & 0x02; } + UINT16 entire_state_registers() { return hd6309_native_mode() ? 0x3FF : 0xFF; } + + // bit tests + UINT8 &bittest_register(); + bool bittest_source(); + bool bittest_dest(); + void bittest_set(bool result); + + // complex instructions + void muld(); + bool divq(); + bool divd(); + + // the Q register + UINT32 get_q(); + void put_q(UINT32 value); + + // miscellaneous + void set_e() { m_addressing_mode = ADDRESSING_MODE_REGISTER_E; } + void set_f() { m_addressing_mode = ADDRESSING_MODE_REGISTER_F; } + void set_w() { m_addressing_mode = ADDRESSING_MODE_REGISTER_W; } + exgtfr_register read_exgtfr_register(UINT8 reg); + void write_exgtfr_register(UINT8 reg, exgtfr_register value); + bool tfr_read(UINT8 opcode, UINT8 arg, UINT8 &data); + bool tfr_write(UINT8 opcode, UINT8 arg, UINT8 data); + bool add8_sets_h() { return (m_opcode & 0xFE) != 0x30; } + void register_register_op(); + bool hd6309_native_mode() { return m_md & 0x01; } + + void execute_one(); +}; + +enum +{ + HD6309_PC = M6809_PC, + HD6309_S = M6809_S, + HD6309_CC = M6809_CC, + HD6309_A = M6809_A, + HD6309_B = M6809_B, + HD6309_D = M6809_D, + HD6309_U = M6809_U, + HD6309_X = M6809_X, + HD6309_Y = M6809_Y, + HD6309_DP = M6809_DP, + + HD6309_E = 1000, + HD6309_F, + HD6309_W, + HD6309_V, + HD6309_MD, + HD6309_ZERO_BYTE, + HD6309_ZERO_WORD +}; + +#define HD6309_IRQ_LINE M6809_IRQ_LINE /* 0 - IRQ line number */ +#define HD6309_FIRQ_LINE M6809_FIRQ_LINE /* 1 - FIRQ line number */ + +#endif // __HD6309_H__ diff --git a/src/devices/cpu/m6809/hd6309.ops b/src/devices/cpu/m6809/hd6309.ops new file mode 100644 index 00000000000..6da3a904d2b --- /dev/null +++ b/src/devices/cpu/m6809/hd6309.ops @@ -0,0 +1,1085 @@ +MAIN: + // check interrupt lines + switch(get_pending_interrupt()) + { + case VECTOR_NMI: goto NMI; + case VECTOR_FIRQ: goto FIRQ; + case VECTOR_IRQ: goto IRQ; + } + + // debugger hook + m_ppc = m_pc; + debugger_instruction_hook(this, m_pc.w); + + // opcode fetch + @m_opcode = read_opcode(); + + // dispatch opcode + switch(m_opcode) + { + case 0x00: %DIRECT; %NEG8; return; + case 0x01: %IMM_IM; %DIRECT; %OIM; return; + case 0x02: %IMM_IM; %DIRECT; %AIM; return; + case 0x03: %DIRECT; %COM8; return; + case 0x04: %DIRECT; %LSR8; return; + case 0x05: %IMM_IM; %DIRECT; %EIM; return; + case 0x06: %DIRECT; %ROR8; return; + case 0x07: %DIRECT; %ASR8; return; + case 0x08: %DIRECT; %ASL8; return; + case 0x09: %DIRECT; %ROL8; return; + case 0x0A: %DIRECT; %DEC8; return; + case 0x0B: %IMM_IM; %DIRECT; %TIM; return; + case 0x0C: %DIRECT; %INC8; return; + case 0x0D: %DIRECT; %TST8; return; + case 0x0E: %DIRECT; %JMP; return; + case 0x0F: %DIRECT; %CLR8; return; + + case 0x10: %DISPATCH10; return; + case 0x11: %DISPATCH11; return; + case 0x12: %NOP; return; + case 0x13: %SYNC; return; + case 0x14: %SEXW; return; + case 0x16: set_cond(true); %LBRANCH; return; + case 0x17: %LBSR; return; + case 0x19: %DAA; return; + case 0x1A: set_imm(); %ORCC; return; + case 0x1C: set_imm(); %ANDCC; return; + case 0x1D: %SEX; return; + case 0x1E: %EXG; return; + case 0x1F: %TFR; return; + + case 0x20: set_cond(true); %BRANCH; return; + case 0x21: set_cond(false); %BRANCH; return; + case 0x22: set_cond(cond_hi()); %BRANCH; return; + case 0x23: set_cond(!cond_hi()); %BRANCH; return; + case 0x24: set_cond(cond_cc()); %BRANCH; return; + case 0x25: set_cond(!cond_cc()); %BRANCH; return; + case 0x26: set_cond(cond_ne()); %BRANCH; return; + case 0x27: set_cond(!cond_ne()); %BRANCH; return; + case 0x28: set_cond(cond_vc()); %BRANCH; return; + case 0x29: set_cond(!cond_vc()); %BRANCH; return; + case 0x2A: set_cond(cond_pl()); %BRANCH; return; + case 0x2B: set_cond(!cond_pl()); %BRANCH; return; + case 0x2C: set_cond(cond_ge()); %BRANCH; return; + case 0x2D: set_cond(!cond_ge()); %BRANCH; return; + case 0x2E: set_cond(cond_gt()); %BRANCH; return; + case 0x2F: set_cond(!cond_gt()); %BRANCH; return; + + case 0x30: set_regop16(m_x); %INDEXED; %LEA_xy; return; + case 0x31: set_regop16(m_y); %INDEXED; %LEA_xy; return; + case 0x32: set_regop16(m_s); %INDEXED; %LEA_us; return; + case 0x33: set_regop16(m_u); %INDEXED; %LEA_us; return; + case 0x34: %PSHS; return; + case 0x35: %PULS; return; + case 0x36: %PSHU; return; + case 0x37: %PULU; return; + case 0x39: %RTS; return; + case 0x3A: %ABX; return; + case 0x3B: %RTI; return; + case 0x3C: %CWAI; return; + case 0x3D: %MUL; return; + case 0x3F: %SWI; return; + + case 0x40: set_a(); %NEG8; return; + case 0x43: set_a(); %COM8; return; + case 0x44: set_a(); %LSR8; return; + case 0x46: set_a(); %ROR8; return; + case 0x47: set_a(); %ASR8; return; + case 0x48: set_a(); %ASL8; return; + case 0x49: set_a(); %ROL8; return; + case 0x4A: set_a(); %DEC8; return; + case 0x4C: set_a(); %INC8; return; + case 0x4D: set_a(); %TST8; return; + case 0x4F: set_a(); %CLR8; return; + + case 0x50: set_b(); %NEG8; return; + case 0x53: set_b(); %COM8; return; + case 0x54: set_b(); %LSR8; return; + case 0x56: set_b(); %ROR8; return; + case 0x57: set_b(); %ASR8; return; + case 0x58: set_b(); %ASL8; return; + case 0x59: set_b(); %ROL8; return; + case 0x5A: set_b(); %DEC8; return; + case 0x5C: set_b(); %INC8; return; + case 0x5D: set_b(); %TST8; return; + case 0x5F: set_b(); %CLR8; return; + + case 0x60: %INDEXED; %NEG8; return; + case 0x61: %IMM_IM; %INDEXED; %OIM; return; + case 0x62: %IMM_IM; %INDEXED; %AIM; return; + case 0x63: %INDEXED; %COM8; return; + case 0x64: %INDEXED; %LSR8; return; + case 0x65: %IMM_IM; %INDEXED; %EIM; return; + case 0x66: %INDEXED; %ROR8; return; + case 0x67: %INDEXED; %ASR8; return; + case 0x68: %INDEXED; %ASL8; return; + case 0x69: %INDEXED; %ROL8; return; + case 0x6A: %INDEXED; %DEC8; return; + case 0x6B: %IMM_IM; %INDEXED; %TIM; return; + case 0x6C: %INDEXED; %INC8; return; + case 0x6D: %INDEXED; %TST8; return; + case 0x6E: %INDEXED; %JMP; return; + case 0x6F: %INDEXED; %CLR8; return; + + case 0x70: %EXTENDED; %NEG8; return; + case 0x71: %IMM_IM; %EXTENDED; %OIM; return; + case 0x72: %IMM_IM; %EXTENDED; %AIM; return; + case 0x73: %EXTENDED; %COM8; return; + case 0x74: %EXTENDED; %LSR8; return; + case 0x75: %IMM_IM; %EXTENDED; %EIM; return; + case 0x76: %EXTENDED; %ROR8; return; + case 0x77: %EXTENDED; %ASR8; return; + case 0x78: %EXTENDED; %ASL8; return; + case 0x79: %EXTENDED; %ROL8; return; + case 0x7A: %EXTENDED; %DEC8; return; + case 0x7B: %IMM_IM; %EXTENDED; %TIM; return; + case 0x7C: %EXTENDED; %INC8; return; + case 0x7D: %EXTENDED; %TST8; return; + case 0x7E: %EXTENDED; %JMP; return; + case 0x7F: %EXTENDED; %CLR8; return; + + case 0x80: set_regop8(m_d.b.h); set_imm(); %SUB8; return; + case 0x81: set_regop8(m_d.b.h); set_imm(); %CMP8; return; + case 0x82: set_regop8(m_d.b.h); set_imm(); %SBC8; return; + case 0x83: set_regop16(m_d); set_imm(); %SUB16; return; + case 0x84: set_regop8(m_d.b.h); set_imm(); %AND8; return; + case 0x85: set_regop8(m_d.b.h); set_imm(); %BIT8; return; + case 0x86: set_regop8(m_d.b.h); set_imm(); %LD8; return; + case 0x88: set_regop8(m_d.b.h); set_imm(); %EOR8; return; + case 0x89: set_regop8(m_d.b.h); set_imm(); %ADC8; return; + case 0x8A: set_regop8(m_d.b.h); set_imm(); %OR8; return; + case 0x8B: set_regop8(m_d.b.h); set_imm(); %ADD8; return; + case 0x8C: set_regop16(m_x); set_imm(); %CMP16; return; + case 0x8D: %BSR; return; + case 0x8E: set_regop16(m_x); set_imm(); %LD16; return; + + case 0x90: set_regop8(m_d.b.h); %DIRECT; %SUB8; return; + case 0x91: set_regop8(m_d.b.h); %DIRECT; %CMP8; return; + case 0x92: set_regop8(m_d.b.h); %DIRECT; %SBC8; return; + case 0x93: set_regop16(m_d); %DIRECT; %SUB16; return; + case 0x94: set_regop8(m_d.b.h); %DIRECT; %AND8; return; + case 0x95: set_regop8(m_d.b.h); %DIRECT; %BIT8; return; + case 0x96: set_regop8(m_d.b.h); %DIRECT; %LD8; return; + case 0x97: set_regop8(m_d.b.h); %DIRECT; %ST8; return; + case 0x98: set_regop8(m_d.b.h); %DIRECT; %EOR8; return; + case 0x99: set_regop8(m_d.b.h); %DIRECT; %ADC8; return; + case 0x9A: set_regop8(m_d.b.h); %DIRECT; %OR8; return; + case 0x9B: set_regop8(m_d.b.h); %DIRECT; %ADD8; return; + case 0x9C: set_regop16(m_x); %DIRECT; %CMP16; return; + case 0x9D: %DIRECT; %JSR; return; + case 0x9E: set_regop16(m_x); %DIRECT; %LD16; return; + case 0x9F: set_regop16(m_x); %DIRECT; %ST16; return; + + case 0xA0: set_regop8(m_d.b.h); %INDEXED; %SUB8; return; + case 0xA1: set_regop8(m_d.b.h); %INDEXED; %CMP8; return; + case 0xA2: set_regop8(m_d.b.h); %INDEXED; %SBC8; return; + case 0xA3: set_regop16(m_d); %INDEXED; %SUB16; return; + case 0xA4: set_regop8(m_d.b.h); %INDEXED; %AND8; return; + case 0xA5: set_regop8(m_d.b.h); %INDEXED; %BIT8; return; + case 0xA6: set_regop8(m_d.b.h); %INDEXED; %LD8; return; + case 0xA7: set_regop8(m_d.b.h); %INDEXED; %ST8; return; + case 0xA8: set_regop8(m_d.b.h); %INDEXED; %EOR8; return; + case 0xA9: set_regop8(m_d.b.h); %INDEXED; %ADC8; return; + case 0xAA: set_regop8(m_d.b.h); %INDEXED; %OR8; return; + case 0xAB: set_regop8(m_d.b.h); %INDEXED; %ADD8; return; + case 0xAC: set_regop16(m_x); %INDEXED; %CMP16; return; + case 0xAD: %INDEXED; %JSR_ind; return; + case 0xAE: set_regop16(m_x); %INDEXED; %LD16; return; + case 0xAF: set_regop16(m_x); %INDEXED; %ST16; return; + + case 0xB0: set_regop8(m_d.b.h); %EXTENDED; %SUB8; return; + case 0xB1: set_regop8(m_d.b.h); %EXTENDED; %CMP8; return; + case 0xB2: set_regop8(m_d.b.h); %EXTENDED; %SBC8; return; + case 0xB3: set_regop16(m_d); %EXTENDED; %SUB16; return; + case 0xB4: set_regop8(m_d.b.h); %EXTENDED; %AND8; return; + case 0xB5: set_regop8(m_d.b.h); %EXTENDED; %BIT8; return; + case 0xB6: set_regop8(m_d.b.h); %EXTENDED; %LD8; return; + case 0xB7: set_regop8(m_d.b.h); %EXTENDED; %ST8; return; + case 0xB8: set_regop8(m_d.b.h); %EXTENDED; %EOR8; return; + case 0xB9: set_regop8(m_d.b.h); %EXTENDED; %ADC8; return; + case 0xBA: set_regop8(m_d.b.h); %EXTENDED; %OR8; return; + case 0xBB: set_regop8(m_d.b.h); %EXTENDED; %ADD8; return; + case 0xBC: set_regop16(m_x); %EXTENDED; %CMP16; return; + case 0xBD: %EXTENDED; %JSR; return; + case 0xBE: set_regop16(m_x); %EXTENDED; %LD16; return; + case 0xBF: set_regop16(m_x); %EXTENDED; %ST16; return; + + case 0xC0: set_regop8(m_d.b.l); set_imm(); %SUB8; return; + case 0xC1: set_regop8(m_d.b.l); set_imm(); %CMP8; return; + case 0xC2: set_regop8(m_d.b.l); set_imm(); %SBC8; return; + case 0xC3: set_regop16(m_d); set_imm(); %ADD16; return; + case 0xC4: set_regop8(m_d.b.l); set_imm(); %AND8; return; + case 0xC5: set_regop8(m_d.b.l); set_imm(); %BIT8; return; + case 0xC6: set_regop8(m_d.b.l); set_imm(); %LD8; return; + case 0xC8: set_regop8(m_d.b.l); set_imm(); %EOR8; return; + case 0xC9: set_regop8(m_d.b.l); set_imm(); %ADC8; return; + case 0xCA: set_regop8(m_d.b.l); set_imm(); %OR8; return; + case 0xCB: set_regop8(m_d.b.l); set_imm(); %ADD8; return; + case 0xCC: set_regop16(m_d); set_imm(); %LD16; return; + case 0xCD: set_imm(); %LDQ; return; + case 0xCE: set_regop16(m_u); set_imm(); %LD16; return; + + case 0xD0: set_regop8(m_d.b.l); %DIRECT; %SUB8; return; + case 0xD1: set_regop8(m_d.b.l); %DIRECT; %CMP8; return; + case 0xD2: set_regop8(m_d.b.l); %DIRECT; %SBC8; return; + case 0xD3: set_regop16(m_d); %DIRECT; %ADD16; return; + case 0xD4: set_regop8(m_d.b.l); %DIRECT; %AND8; return; + case 0xD5: set_regop8(m_d.b.l); %DIRECT; %BIT8; return; + case 0xD6: set_regop8(m_d.b.l); %DIRECT; %LD8; return; + case 0xD7: set_regop8(m_d.b.l); %DIRECT; %ST8; return; + case 0xD8: set_regop8(m_d.b.l); %DIRECT; %EOR8; return; + case 0xD9: set_regop8(m_d.b.l); %DIRECT; %ADC8; return; + case 0xDA: set_regop8(m_d.b.l); %DIRECT; %OR8; return; + case 0xDB: set_regop8(m_d.b.l); %DIRECT; %ADD8; return; + case 0xDC: set_regop16(m_d); %DIRECT; %LD16; return; + case 0xDD: set_regop16(m_d); %DIRECT; %ST16; return; + case 0xDE: set_regop16(m_u); %DIRECT; %LD16; return; + case 0xDF: set_regop16(m_u); %DIRECT; %ST16; return; + + case 0xE0: set_regop8(m_d.b.l); %INDEXED; %SUB8; return; + case 0xE1: set_regop8(m_d.b.l); %INDEXED; %CMP8; return; + case 0xE2: set_regop8(m_d.b.l); %INDEXED; %SBC8; return; + case 0xE3: set_regop16(m_d); %INDEXED; %ADD16; return; + case 0xE4: set_regop8(m_d.b.l); %INDEXED; %AND8; return; + case 0xE5: set_regop8(m_d.b.l); %INDEXED; %BIT8; return; + case 0xE6: set_regop8(m_d.b.l); %INDEXED; %LD8; return; + case 0xE7: set_regop8(m_d.b.l); %INDEXED; %ST8; return; + case 0xE8: set_regop8(m_d.b.l); %INDEXED; %EOR8; return; + case 0xE9: set_regop8(m_d.b.l); %INDEXED; %ADC8; return; + case 0xEA: set_regop8(m_d.b.l); %INDEXED; %OR8; return; + case 0xEB: set_regop8(m_d.b.l); %INDEXED; %ADD8; return; + case 0xEC: set_regop16(m_d); %INDEXED; %LD16; return; + case 0xED: set_regop16(m_d); %INDEXED; %ST16; return; + case 0xEE: set_regop16(m_u); %INDEXED; %LD16; return; + case 0xEF: set_regop16(m_u); %INDEXED; %ST16; return; + + case 0xF0: set_regop8(m_d.b.l); %EXTENDED; %SUB8; return; + case 0xF1: set_regop8(m_d.b.l); %EXTENDED; %CMP8; return; + case 0xF2: set_regop8(m_d.b.l); %EXTENDED; %SBC8; return; + case 0xF3: set_regop16(m_d); %EXTENDED; %ADD16; return; + case 0xF4: set_regop8(m_d.b.l); %EXTENDED; %AND8; return; + case 0xF5: set_regop8(m_d.b.l); %EXTENDED; %BIT8; return; + case 0xF6: set_regop8(m_d.b.l); %EXTENDED; %LD8; return; + case 0xF7: set_regop8(m_d.b.l); %EXTENDED; %ST8; return; + case 0xF8: set_regop8(m_d.b.l); %EXTENDED; %EOR8; return; + case 0xF9: set_regop8(m_d.b.l); %EXTENDED; %ADC8; return; + case 0xFA: set_regop8(m_d.b.l); %EXTENDED; %OR8; return; + case 0xFB: set_regop8(m_d.b.l); %EXTENDED; %ADD8; return; + case 0xFC: set_regop16(m_d); %EXTENDED; %LD16; return; + case 0xFD: set_regop16(m_d); %EXTENDED; %ST16; return; + case 0xFE: set_regop16(m_u); %EXTENDED; %LD16; return; + case 0xFF: set_regop16(m_u); %EXTENDED; %ST16; return; + default: %ILLEGAL; return; + } + return; + +DISPATCH10: + @m_opcode = read_opcode(); + switch(m_opcode) + { + case 0x20: set_cond(true); %LBRANCH; return; + case 0x21: set_cond(false); %LBRANCH; return; + case 0x22: set_cond(cond_hi()); %LBRANCH; return; + case 0x23: set_cond(!cond_hi()); %LBRANCH; return; + case 0x24: set_cond(cond_cc()); %LBRANCH; return; + case 0x25: set_cond(!cond_cc()); %LBRANCH; return; + case 0x26: set_cond(cond_ne()); %LBRANCH; return; + case 0x27: set_cond(!cond_ne()); %LBRANCH; return; + case 0x28: set_cond(cond_vc()); %LBRANCH; return; + case 0x29: set_cond(!cond_vc()); %LBRANCH; return; + case 0x2A: set_cond(cond_pl()); %LBRANCH; return; + case 0x2B: set_cond(!cond_pl()); %LBRANCH; return; + case 0x2C: set_cond(cond_ge()); %LBRANCH; return; + case 0x2D: set_cond(!cond_ge()); %LBRANCH; return; + case 0x2E: set_cond(cond_gt()); %LBRANCH; return; + case 0x2F: set_cond(!cond_gt()); %LBRANCH; return; + + case 0x30: register_register_op(); %ADD*; return; + case 0x31: register_register_op(); %ADC*; return; + case 0x32: register_register_op(); %SUB*; return; + case 0x33: register_register_op(); %SBC*; return; + case 0x34: register_register_op(); %AND*; return; + case 0x35: register_register_op(); %OR*; return; + case 0x36: register_register_op(); %EOR*; return; + case 0x37: register_register_op(); %CMP*; return; + case 0x38: %PSHSW; return; + case 0x39: %PULSW; return; + case 0x3A: %PSHUW; return; + case 0x3B: %PULUW; return; + case 0x3F: %SWI2; return; + + case 0x40: set_d(); %NEG16; return; + case 0x43: set_d(); %COM16; return; + case 0x44: set_d(); %LSR16; return; + case 0x46: set_d(); %ROR16; return; + case 0x47: set_d(); %ASR16; return; + case 0x48: set_d(); %ASL16; return; + case 0x49: set_d(); %ROL16; return; + case 0x4A: set_d(); %DEC16; return; + case 0x4C: set_d(); %INC16; return; + case 0x4D: set_d(); %TST16; return; + case 0x4F: set_d(); %CLR16; return; + + case 0x50: set_w(); %NEG16; return; + case 0x53: set_w(); %COM16; return; + case 0x54: set_w(); %LSR16; return; + case 0x56: set_w(); %ROR16; return; + case 0x57: set_w(); %ASR16; return; + case 0x58: set_w(); %ASL16; return; + case 0x59: set_w(); %ROL16; return; + case 0x5A: set_w(); %DEC16; return; + case 0x5C: set_w(); %INC16; return; + case 0x5D: set_w(); %TST16; return; + case 0x5F: set_w(); %CLR16; return; + + case 0x80: set_regop16(m_w); set_imm(); %SUB16; return; + case 0x81: set_regop16(m_w); set_imm(); %CMP16; return; + case 0x82: set_regop16(m_d); set_imm(); %SBC16; return; + case 0x83: set_regop16(m_d); set_imm(); %CMP16; return; + case 0x84: set_regop16(m_d); set_imm(); %AND16; return; + case 0x85: set_regop16(m_d); set_imm(); %BIT16; return; + case 0x86: set_regop16(m_w); set_imm(); %LD16; return; + case 0x88: set_regop16(m_d); set_imm(); %EOR16; return; + case 0x89: set_regop16(m_d); set_imm(); %ADC16; return; + case 0x8A: set_regop16(m_d); set_imm(); %OR16; return; + case 0x8B: set_regop16(m_w); set_imm(); %ADD16; return; + case 0x8C: set_regop16(m_y); set_imm(); %CMP16; return; + case 0x8E: set_regop16(m_y); set_imm(); %LD16; return; + + case 0x90: set_regop16(m_w); %DIRECT; %SUB16; return; + case 0x91: set_regop16(m_w); %DIRECT; %CMP16; return; + case 0x92: set_regop16(m_d); %DIRECT; %SBC16; return; + case 0x93: set_regop16(m_d); %DIRECT; %CMP16; return; + case 0x94: set_regop16(m_d); %DIRECT; %AND16; return; + case 0x95: set_regop16(m_d); %DIRECT; %BIT16; return; + case 0x96: set_regop16(m_w); %DIRECT; %LD16; return; + case 0x97: set_regop16(m_w); %DIRECT; %ST16; return; + case 0x98: set_regop16(m_d); %DIRECT; %EOR16; return; + case 0x99: set_regop16(m_d); %DIRECT; %ADC16; return; + case 0x9A: set_regop16(m_d); %DIRECT; %OR16; return; + case 0x9B: set_regop16(m_w); %DIRECT; %ADD16; return; + case 0x9C: set_regop16(m_y); %DIRECT; %CMP16; return; + case 0x9E: set_regop16(m_y); %DIRECT; %LD16; return; + case 0x9F: set_regop16(m_y); %DIRECT; %ST16; return; + + case 0xA0: set_regop16(m_w); %INDEXED; %SUB16; return; + case 0xA1: set_regop16(m_w); %INDEXED; %CMP16; return; + case 0xA2: set_regop16(m_d); %INDEXED; %SBC16; return; + case 0xA3: set_regop16(m_d); %INDEXED; %CMP16; return; + case 0xA4: set_regop16(m_d); %INDEXED; %AND16; return; + case 0xA5: set_regop16(m_d); %INDEXED; %BIT16; return; + case 0xA6: set_regop16(m_w); %INDEXED; %LD16; return; + case 0xA7: set_regop16(m_w); %INDEXED; %ST16; return; + case 0xA8: set_regop16(m_d); %INDEXED; %EOR16; return; + case 0xA9: set_regop16(m_d); %INDEXED; %ADC16; return; + case 0xAA: set_regop16(m_d); %INDEXED; %OR16; return; + case 0xAB: set_regop16(m_w); %INDEXED; %ADD16; return; + case 0xAC: set_regop16(m_y); %INDEXED; %CMP16; return; + case 0xAE: set_regop16(m_y); %INDEXED; %LD16; return; + case 0xAF: set_regop16(m_y); %INDEXED; %ST16; return; + + case 0xB0: set_regop16(m_w); %EXTENDED; %SUB16; return; + case 0xB1: set_regop16(m_w); %EXTENDED; %CMP16; return; + case 0xB2: set_regop16(m_d); %EXTENDED; %SBC16; return; + case 0xB3: set_regop16(m_d); %EXTENDED; %CMP16; return; + case 0xB4: set_regop16(m_d); %EXTENDED; %AND16; return; + case 0xB5: set_regop16(m_d); %EXTENDED; %BIT16; return; + case 0xB6: set_regop16(m_w); %EXTENDED; %LD16; return; + case 0xB7: set_regop16(m_w); %EXTENDED; %ST16; return; + case 0xB8: set_regop16(m_d); %EXTENDED; %EOR16; return; + case 0xB9: set_regop16(m_d); %EXTENDED; %ADC16; return; + case 0xBA: set_regop16(m_d); %EXTENDED; %OR16; return; + case 0xBB: set_regop16(m_w); %EXTENDED; %ADD16; return; + case 0xBC: set_regop16(m_y); %EXTENDED; %CMP16; return; + case 0xBE: set_regop16(m_y); %EXTENDED; %LD16; return; + case 0xBF: set_regop16(m_y); %EXTENDED; %ST16; return; + + case 0xCE: set_regop16(m_s); set_imm(); %LD16; return; + case 0xDC: %DIRECT; %LDQ; return; + case 0xDD: %DIRECT; %STQ; return; + case 0xDE: set_regop16(m_s); %DIRECT; %LD16; return; + case 0xDF: set_regop16(m_s); %DIRECT; %ST16; return; + case 0xEC: %INDEXED; %LDQ; return; + case 0xED: %INDEXED; %STQ; return; + case 0xEE: set_regop16(m_s); %INDEXED; %LD16; return; + case 0xEF: set_regop16(m_s); %INDEXED; %ST16; return; + case 0xFC: %EXTENDED; %LDQ; return; + case 0xFD: %EXTENDED; %STQ; return; + case 0xFE: set_regop16(m_s); %EXTENDED; %LD16; return; + case 0xFF: set_regop16(m_s); %EXTENDED; %ST16; return; + + default: %ILLEGAL; return; + } + return; + +DISPATCH11: + @m_opcode = read_opcode(); + switch(m_opcode) + { + case 0x30: %BAND; return; + case 0x31: %BIAND; return; + case 0x32: %BOR; return; + case 0x33: %BIOR; return; + case 0x34: %BEOR; return; + case 0x35: %BIEOR; return; + case 0x36: %LDBT; return; + case 0x37: %STBT; return; + case 0x38: %TFM; return; + case 0x39: %TFM; return; + case 0x3A: %TFM; return; + case 0x3B: %TFM; return; + case 0x3C: set_regop8(m_md); set_imm(); %BIT8; return; + case 0x3D: set_regop8(m_md); set_imm(); %LD8; return; + case 0x3F: %SWI3; return; + + case 0x43: set_e(); %COM8; return; + case 0x4A: set_e(); %DEC8; return; + case 0x4C: set_e(); %INC8; return; + case 0x4D: set_e(); %TST8; return; + case 0x4F: set_e(); %CLR8; return; + + case 0x53: set_f(); %COM8; return; + case 0x5A: set_f(); %DEC8; return; + case 0x5C: set_f(); %INC8; return; + case 0x5D: set_f(); %TST8; return; + case 0x5F: set_f(); %CLR8; return; + + case 0x80: set_regop8(m_w.b.h); set_imm(); %SUB8; return; + case 0x81: set_regop8(m_w.b.h); set_imm(); %CMP8; return; + case 0x83: set_regop16(m_u); set_imm(); %CMP16; return; + case 0x86: set_regop8(m_w.b.h); set_imm(); %LD8; return; + case 0x8B: set_regop8(m_w.b.h); set_imm(); %ADD8; return; + case 0x8C: set_regop16(m_s); set_imm(); %CMP16; return; + case 0x8D: set_imm(); %DIVD; return; + case 0x8E: set_imm(); %DIVQ; return; + case 0x8F: set_imm(); %MULD; return; + + case 0x90: set_regop8(m_w.b.h); %DIRECT; %SUB8; return; + case 0x91: set_regop8(m_w.b.h); %DIRECT; %CMP8; return; + case 0x93: set_regop16(m_u); %DIRECT; %CMP16; return; + case 0x96: set_regop8(m_w.b.h); %DIRECT; %LD8; return; + case 0x97: set_regop8(m_w.b.h); %DIRECT; %ST8; return; + case 0x9B: set_regop8(m_w.b.h); %DIRECT; %ADD8; return; + case 0x9C: set_regop16(m_s); %DIRECT; %CMP16; return; + case 0x9D: %DIRECT; %DIVD; return; + case 0x9E: %DIRECT; %DIVQ; return; + case 0x9F: %DIRECT; %MULD; return; + + case 0xA0: set_regop8(m_w.b.h); %INDEXED; %SUB8; return; + case 0xA1: set_regop8(m_w.b.h); %INDEXED; %CMP8; return; + case 0xA3: set_regop16(m_u); %INDEXED; %CMP16; return; + case 0xA6: set_regop8(m_w.b.h); %INDEXED; %LD8; return; + case 0xA7: set_regop8(m_w.b.h); %INDEXED; %ST8; return; + case 0xAB: set_regop8(m_w.b.h); %INDEXED; %ADD8; return; + case 0xAC: set_regop16(m_s); %INDEXED; %CMP16; return; + case 0xAD: %INDEXED; %DIVD; return; + case 0xAE: %INDEXED; %DIVQ; return; + case 0xAF: %INDEXED; %MULD; return; + + case 0xB0: set_regop8(m_w.b.h); %EXTENDED; %SUB8; return; + case 0xB1: set_regop8(m_w.b.h); %EXTENDED; %CMP8; return; + case 0xB3: set_regop16(m_u); %EXTENDED; %CMP16; return; + case 0xB6: set_regop8(m_w.b.h); %EXTENDED; %LD8; return; + case 0xB7: set_regop8(m_w.b.h); %EXTENDED; %ST8; return; + case 0xBB: set_regop8(m_w.b.h); %EXTENDED; %ADD8; return; + case 0xBC: set_regop16(m_s); %EXTENDED; %CMP16; return; + case 0xBD: %EXTENDED; %DIVD; return; + case 0xBE: %EXTENDED; %DIVQ; return; + case 0xBF: %EXTENDED; %MULD; return; + + case 0xC0: set_regop8(m_w.b.l); set_imm(); %SUB8; return; + case 0xC1: set_regop8(m_w.b.l); set_imm(); %CMP8; return; + case 0xC6: set_regop8(m_w.b.l); set_imm(); %LD8; return; + case 0xCB: set_regop8(m_w.b.l); set_imm(); %ADD8; return; + + case 0xD0: set_regop8(m_w.b.l); %DIRECT; %SUB8; return; + case 0xD1: set_regop8(m_w.b.l); %DIRECT; %CMP8; return; + case 0xD6: set_regop8(m_w.b.l); %DIRECT; %LD8; return; + case 0xD7: set_regop8(m_w.b.l); %DIRECT; %ST8; return; + case 0xDB: set_regop8(m_w.b.l); %DIRECT; %ADD8; return; + + case 0xE0: set_regop8(m_w.b.l); %INDEXED; %SUB8; return; + case 0xE1: set_regop8(m_w.b.l); %INDEXED; %CMP8; return; + case 0xE6: set_regop8(m_w.b.l); %INDEXED; %LD8; return; + case 0xE7: set_regop8(m_w.b.l); %INDEXED; %ST8; return; + case 0xEB: set_regop8(m_w.b.l); %INDEXED; %ADD8; return; + + case 0xF0: set_regop8(m_w.b.l); %EXTENDED; %SUB8; return; + case 0xF1: set_regop8(m_w.b.l); %EXTENDED; %CMP8; return; + case 0xF6: set_regop8(m_w.b.l); %EXTENDED; %LD8; return; + case 0xF7: set_regop8(m_w.b.l); %EXTENDED; %ST8; return; + case 0xFB: set_regop8(m_w.b.l); %EXTENDED; %ADD8; return; + + default: %ILLEGAL; return; + } + return; + +#include "base6x09.ops" + +PUSH_REGISTERS: + if (m_temp.w & 0x80) + { + @write_memory(--regop16().w, m_pc.b.l); + @write_memory(--regop16().w, m_pc.b.h); + nop(); + } + if (m_temp.w & 0x40) + { + @write_memory(--regop16().w, (®op16() == &m_s) ? m_u.b.l : m_s.b.l); + @write_memory(--regop16().w, (®op16() == &m_s) ? m_u.b.h : m_s.b.h); + nop(); + } + if (m_temp.w & 0x20) + { + @write_memory(--regop16().w, m_y.b.l); + @write_memory(--regop16().w, m_y.b.h); + nop(); + } + if (m_temp.w & 0x10) + { + @write_memory(--regop16().w, m_x.b.l); + @write_memory(--regop16().w, m_x.b.h); + nop(); + } + if (m_temp.w & 0x08) + { + @write_memory(--regop16().w, m_dp); + nop(); + } + if (m_temp.w & 0x200) + { + @write_memory(--regop16().w, m_w.b.l); + nop(); + } + if (m_temp.w & 0x100) + { + @write_memory(--regop16().w, m_w.b.h); + nop(); + } + if (m_temp.w & 0x04) + { + @write_memory(--regop16().w, m_d.b.l); + nop(); + } + if (m_temp.w & 0x02) + { + @write_memory(--regop16().w, m_d.b.h); + nop(); + } + if (m_temp.w & 0x01) + { + @write_memory(--regop16().w, m_cc); + nop(); + } + return; + +PULL_REGISTERS: + if (m_temp.w & 0x01) + { + @m_cc = read_memory(regop16().w++); + nop(); + } + if (m_temp.w & 0x02) + { + @m_d.b.h = read_memory(regop16().w++); + nop(); + } + if (m_temp.w & 0x04) + { + @m_d.b.l = read_memory(regop16().w++); + nop(); + } + if (m_temp.w & 0x100) + { + @m_w.b.h = read_memory(regop16().w++); + nop(); + } + if (m_temp.w & 0x200) + { + @m_w.b.l = read_memory(regop16().w++); + nop(); + } + if (m_temp.w & 0x08) + { + @m_dp = read_memory(regop16().w++); + nop(); + } + if (m_temp.w & 0x10) + { + @m_x.b.h = read_memory(regop16().w++); + @m_x.b.l = read_memory(regop16().w++); + nop(); + } + if (m_temp.w & 0x20) + { + @m_y.b.h = read_memory(regop16().w++); + @m_y.b.l = read_memory(regop16().w++); + nop(); + } + if (m_temp.w & 0x40) + { + @(®op16() == &m_s ? m_u : m_s).b.h = read_memory(regop16().w++); + @(®op16() == &m_s ? m_u : m_s).b.l = read_memory(regop16().w++); + nop(); + } + if (m_temp.w & 0x80) + { + @m_pc.b.h = read_memory(regop16().w++); + @m_pc.b.l = read_memory(regop16().w++); + nop(); + } + @eat(1); + return; + +INDEXED: + @m_opcode = read_opcode_arg(); + if (m_opcode & 0x80) + { + switch(m_opcode & 0x7F) + { + case 0x00: case 0x20: case 0x40: case 0x60: + m_temp.w = ireg(); + ireg()++; + eat((hd6309_native_mode() && !(m_opcode & 0x10)) ? 2 : 3); + break; + + case 0x01: case 0x21: case 0x41: case 0x61: + case 0x11: case 0x31: case 0x51: case 0x71: + m_temp.w = ireg(); + ireg() += 2; + eat((hd6309_native_mode() && !(m_opcode & 0x10)) ? 3 : 4); + break; + + case 0x02: case 0x22: case 0x42: case 0x62: + ireg()--; + m_temp.w = ireg(); + eat((hd6309_native_mode() && !(m_opcode & 0x10)) ? 2 : 3); + break; + + case 0x03: case 0x23: case 0x43: case 0x63: + case 0x13: case 0x33: case 0x53: case 0x73: + ireg() -= 2; + m_temp.w = ireg(); + eat((hd6309_native_mode() && !(m_opcode & 0x10)) ? 3 : 4); + break; + + case 0x04: case 0x24: case 0x44: case 0x64: + case 0x14: case 0x34: case 0x54: case 0x74: + m_temp.w = ireg(); + eat(1); + break; + + case 0x05: case 0x25: case 0x45: case 0x65: + case 0x15: case 0x35: case 0x55: case 0x75: + m_temp.w = ireg() + (INT8) m_d.b.l; + eat(2); + break; + + case 0x06: case 0x26: case 0x46: case 0x66: + case 0x16: case 0x36: case 0x56: case 0x76: + m_temp.w = ireg() + (INT8) m_d.b.h; + eat(2); + break; + + case 0x08: case 0x28: case 0x48: case 0x68: + case 0x18: case 0x38: case 0x58: case 0x78: + @m_temp.w = ireg() + (INT8) read_opcode_arg(); + eat(1); + break; + + case 0x09: case 0x29: case 0x49: case 0x69: + case 0x19: case 0x39: case 0x59: case 0x79: + @m_temp.b.h = read_opcode_arg(); + @m_temp.b.l = read_opcode_arg(); + m_temp.w = ireg() + m_temp.w; + eat(hd6309_native_mode() ? 2 : 3); + break; + + case 0x0B: case 0x2B: case 0x4B: case 0x6B: + case 0x1B: case 0x3B: case 0x5B: case 0x7B: + m_temp.w = ireg() + m_d.w; + eat((hd6309_native_mode() && !(m_opcode & 0x10)) ? 3 : 5); + break; + + case 0x0C: case 0x2C: case 0x4C: case 0x6C: + case 0x1C: case 0x3C: case 0x5C: case 0x7C: + @m_temp.b.l = read_opcode_arg(); + m_temp.w = m_pc.w + (INT8) m_temp.b.l; + eat(1); + break; + + case 0x0D: case 0x2D: case 0x4D: case 0x6D: + case 0x1D: case 0x3D: case 0x5D: case 0x7D: + @m_temp.b.h = read_opcode_arg(); + @m_temp.b.l = read_opcode_arg(); + m_temp.w = m_pc.w + (INT16) m_temp.w; + eat((hd6309_native_mode() && !(m_opcode & 0x10)) ? 2 : 4); + break; + + case 0x1F: case 0x3F: case 0x5F: case 0x7F: + @m_temp.b.h = read_opcode_arg(); + @m_temp.b.l = read_opcode_arg(); + eat(1); + break; + + case 0x07: case 0x27: case 0x47: case 0x67: + case 0x17: case 0x37: case 0x57: case 0x77: + // 6309 specific mode + m_temp.w = ireg() + (INT8) m_w.b.h; + eat(2); + break; + + case 0x0A: case 0x2A: case 0x4A: case 0x6A: + case 0x1A: case 0x3A: case 0x5A: case 0x7A: + // 6309 specific mode + m_temp.w = ireg() + (INT8) m_w.b.l; + eat(2); + break; + + case 0x0E: case 0x2E: case 0x4E: case 0x6E: + case 0x1E: case 0x3E: case 0x5E: case 0x7E: + // 6309 specific mode + m_temp.w = ireg() + m_w.w; + eat((hd6309_native_mode() && !(m_opcode & 0x10)) ? 2 : 5); + break; + + case 0x0F: + // 6309 specific mode + m_temp.w = m_w.w; + eat(1); + break; + + case 0x2F: + // 6309 specific mode + @m_temp.b.h = read_opcode_arg(); + @m_temp.b.l = read_opcode_arg(); + m_temp.w = m_w.w + m_temp.w; + eat(hd6309_native_mode() ? 1 : 5); + break; + + case 0x4F: + // 6309 specific mode + m_temp.w = m_w.w; + m_w.w += 2; + eat((hd6309_native_mode() && !(m_opcode & 0x10)) ? 2 : 4); + break; + + case 0x6F: + // 6309 specific mode + m_w.w -= 2; + m_temp.w = m_w.w; + eat((hd6309_native_mode() && !(m_opcode & 0x10)) ? 2 : 4); + break; + + default: + goto ILLEGAL; + } + + // indirect mode + if (m_opcode & 0x10) + { + set_ea(m_temp.w); + @m_temp.b.h = read_operand(0); + @m_temp.b.l = read_operand(1); + eat(1); + } + } + else + { + // 5-bit offset + m_temp.w = ireg() + (INT8) ((m_opcode & 0x0F) | (m_opcode & 0x10 ? 0xF0 : 0x00)); + eat(2); + } + @set_ea(m_temp.w); + return; + +EXG: + { + UINT8 param = read_opcode_arg(); + exgtfr_register reg1 = read_exgtfr_register(param >> 4); + exgtfr_register reg2 = read_exgtfr_register(param >> 0); + write_exgtfr_register(param >> 4, reg2); + write_exgtfr_register(param >> 0, reg1); + } + eat(hd6309_native_mode() ? 3 : 6); + return; + +TFR: + { + UINT8 param = read_opcode_arg(); + exgtfr_register reg = read_exgtfr_register(param >> 4); + write_exgtfr_register(param >> 0, reg); + } + eat(hd6309_native_mode() ? 2 : 4); + return; + +ILLEGAL: + m_md |= 0x40; // illegal op flag + set_ea(VECTOR_ILLEGAL); + goto SOFTWARE_INTERRUPT; + +DIVIDE_BY_ZERO: + m_md |= 0x80; // divide by zero flag + set_ea(VECTOR_ILLEGAL); + goto SOFTWARE_INTERRUPT; + +IMM_IM: + @m_temp_im = read_opcode_arg(); + return; + +JSR_ind: + // this is dubious, but the old core did this + eat(hd6309_native_mode() ? -1 : 0); + goto JSR; + +LDQ: + @m_d.b.h = read_operand(0); + @m_d.b.l = read_operand(1); + @m_w.b.h = read_operand(2); + @m_w.b.l = read_operand(3); + set_flags(CC_NZV, get_q()); + return; + +STQ: + @write_operand(0, m_d.b.h); + @write_operand(1, m_d.b.l); + @write_operand(2, m_w.b.h); + @write_operand(3, m_w.b.l); + set_flags(CC_NZV, get_q()); + return; + +OIM: + @m_temp.b.l = read_operand(); + m_cc &= ~CC_V; + m_temp.b.l = set_flags(CC_NZ, (UINT8)0, m_temp.b.l, m_temp.b.l | m_temp_im); + @eat(1); // this is just a guess + @write_operand(m_temp.b.l); + return; + +AIM: + @m_temp.b.l = read_operand(); + m_cc &= ~CC_V; + m_temp.b.l = set_flags(CC_NZ, (UINT8)0, m_temp.b.l, m_temp.b.l & m_temp_im); + @eat(1); // this is just a guess + @write_operand(m_temp.b.l); + return; + +EIM: + @m_temp.b.l = read_operand(); + m_cc &= ~CC_V; + m_temp.b.l = set_flags(CC_NZ, (UINT8)0, m_temp.b.l, m_temp.b.l ^ m_temp_im); + @eat(1); // this is just a guess + @write_operand(m_temp.b.l); + return; + +TIM: + @m_temp.b.l = read_operand(); + m_cc &= ~CC_V; + m_temp.b.l = set_flags(CC_NZ, (UINT8)0, m_temp.b.l, m_temp.b.l & m_temp_im); + @eat(2); // this is just a guess + return; + +TFM: + // The TFM instruction takes up 6 CPU cycles, plus 3 CPU cycles + // for each byte transferred. At least three of these are spent + // reading the opcodes (00010001 001110xx xxxxxxxx). + // + // The old (pre-0.149) core allowed interrupts to interrupt + // execution of the transfer by implementing a transfer as an + // operation that executed one transfer, and bumped the program + // counter back. However, some documentation suggests that TFM + // was abortable, so we now have a get_pending_interrupt() call + // here. + // + // Lastly, I have no information on the precise sub-instruction timing + // here; the timings of the reads and writes are really just a guess. + @m_temp.b.l = read_opcode_arg(); + + while (m_w.w != 0x0000) + { + // TFM is abortable - we need to check for a pending interrupt + if (get_pending_interrupt() != 0) + { + m_pc.w -= 3; + return; + } + + if (!tfr_read(m_opcode, m_temp.b.l, m_temp.b.h)) + goto ILLEGAL; + @eat(0); + + if (!tfr_write(m_opcode, m_temp.b.l, m_temp.b.h)) + goto ILLEGAL; + @eat(1); + + m_w.w--; + } + + // Not sure if this sub instruction timing is accurate either + @eat(3); + return; + +COM16: + m_temp.b.h = read_operand(0); + m_temp.b.l = read_operand(1); + m_cc &= ~CC_V; + m_cc |= CC_C; + m_temp.w = set_flags(CC_NZ, (UINT16) ~m_temp.w); + eat(hd6309_native_mode() ? 0 : 1); + write_operand(0, m_temp.b.h); + write_operand(1, m_temp.b.l); + return; + +ADC16: + @m_temp.b.h = read_operand(0); + @m_temp.b.l = read_operand(1); + regop16().w = set_flags(CC_NZVC, regop16().w, m_temp.w, regop16().w + m_temp.w + (m_cc & CC_C ? 1 : 0)); + eat(hd6309_native_mode() ? 0 : 1); + return; + +SBC16: + @m_temp.b.h = read_operand(0); + @m_temp.b.l = read_operand(1); + regop16().w = set_flags(CC_NZVC, regop16().w, m_temp.w, regop16().w - m_temp.w - (m_cc & CC_C ? 1 : 0)); + eat(hd6309_native_mode() ? 0 : 1); + return; + +AND16: + @m_temp.b.h = read_operand(0); + @m_temp.b.l = read_operand(1); + m_cc &= ~CC_V; + regop16().w = set_flags(CC_NZ, (UINT16)0, regop16().w, regop16().w & m_temp.w); + return; + +BIT16: + @m_temp.b.h = read_operand(0); + @m_temp.b.l = read_operand(1); + m_cc &= ~CC_V; + set_flags(CC_NZ, (UINT16)0, regop16().w, regop16().w & m_temp.w); + return; + +OR16: + @m_temp.b.h = read_operand(0); + @m_temp.b.l = read_operand(1); + m_cc &= ~CC_V; + regop16().w = set_flags(CC_NZ, (UINT16)0, regop16().w, regop16().w | m_temp.w); + return; + +EOR16: + @m_temp.b.h = read_operand(0); + @m_temp.b.l = read_operand(1); + m_cc &= ~CC_V; + regop16().w = set_flags(CC_NZ, (UINT16)0, regop16().w, regop16().w ^ m_temp.w); + return; + +PSHSW: + m_temp.w = 0x300; // PSHS W + eat(2); + set_regop16(m_s); + goto PUSH_REGISTERS; + +PULSW: + m_temp.w = 0x300; // PULS W + eat(2); + set_regop16(m_s); + goto PULL_REGISTERS; + +PSHUW: + m_temp.w = 0x300; // PSHU W + eat(2); + set_regop16(m_u); + goto PUSH_REGISTERS; + +PULUW: + m_temp.w = 0x300; // PULU W + eat(2); + set_regop16(m_u); + goto PULL_REGISTERS; + +BAND: + %IMM_IM; + %DIRECT; + @m_temp.b.l = read_operand(); + bittest_set(bittest_dest() && bittest_source()); + return; + +BIAND: + %IMM_IM; + %DIRECT; + @m_temp.b.l = read_operand(); + bittest_set(bittest_dest() && !bittest_source()); + return; + +BOR: + %IMM_IM; + %DIRECT; + @m_temp.b.l = read_operand(); + bittest_set(bittest_dest() || bittest_source()); + return; + +BIOR: + %IMM_IM; + %DIRECT; + @m_temp.b.l = read_operand(); + bittest_set(bittest_dest() || !bittest_source()); + return; + +BEOR: + %IMM_IM; + %DIRECT; + @m_temp.b.l = read_operand(); + bittest_set(bittest_dest() != bittest_source()); + return; + +BIEOR: + %IMM_IM; + %DIRECT; + @m_temp.b.l = read_operand(); + bittest_set(bittest_dest() != !bittest_source()); + return; + +LDBT: + %IMM_IM; + %DIRECT; + @m_temp.b.l = read_operand(); + bittest_set(bittest_source()); + return; + +STBT: + %IMM_IM; + %DIRECT; + @m_temp.b.l = read_operand(); + if (bittest_source()) + m_temp.b.l |= (1 << ((m_temp_im >> 0) & 0x07)); + else + m_temp.b.l &= ~(1 << ((m_temp_im >> 0) & 0x07)); + @eat(2); + write_operand(m_temp.b.l); + return; + +MULD: + @m_temp.b.h = read_operand(0); + @m_temp.b.l = read_operand(1); + muld(); + return; + +DIVQ: + @m_temp.b.h = read_operand(0); + @m_temp.b.l = read_operand(1); + if (!divq()) + goto DIVIDE_BY_ZERO; + return; + +DIVD: + @m_temp.b.l = read_operand(); + if (!divd()) + goto DIVIDE_BY_ZERO; + return; + +SEXW: + m_d.w = set_flags(CC_N, (m_w.w & 0x8000) ? 0xFFFF : 0x0000); + if ((m_d.w == 0x0000) && (m_w.w == 0x0000)) + m_cc |= CC_Z; + else + m_cc &= ~CC_Z; + return; diff --git a/src/devices/cpu/m6809/knmidasm.c b/src/devices/cpu/m6809/knmidasm.c new file mode 100644 index 00000000000..5c325e81718 --- /dev/null +++ b/src/devices/cpu/m6809/knmidasm.c @@ -0,0 +1,1877 @@ +// license:BSD-3-Clause +// copyright-holders:Nathan Woods +#include "emu.h" +#include "debugger.h" +#include "konami.h" + +#ifndef TRUE +#define TRUE -1 +#define FALSE 0 +#endif + +/* + +0x08 leax indexed +0x09 leay indexed (not confirmed) +0x0a leau indexed +0x0b leas indexed (not confirmed) + +0x0c pushs xx +0x0d pushu xx (not confirmed) +0x0e pulls xx +0x0f pulls xx (not confirmed) + +0x10 lda xx +0x11 ldb xx +0x12 lda indexed +0x13 ldb indexed + +0x14 adda xx +0x15 addb xx (not confirmed) +0x16 adda indexed (not confirmed) +0x17 addb indexed + +0x18 adca xx +0x19 adcb xx (not confirmed) +0x1a adca indexed (not confirmed) +0x1b adcb indexed (not confirmed) + +0x1c suba xx +0x1d subb xx +0x1e suba indexed +0x1f subb indexed + +0x20 sbca xx +0x21 sbcb xx +0x22 sbca indexed +0x23 sbcb indexed + +0x24 anda xx +0x25 andb xx +0x26 anda indexed +0x27 andb indexed + +0x28 bita xx +0x29 bitb xx +0x2a bita indexed +0x2b bitb indexed + +0x2c eora xx +0x2d eorb xx +0x2e eora indexed +0x2f eorb indexed + +0x30 ora xx +0x31 orb xx +0x32 ora indexed +0x33 orb indexed + +0x34 cmpa xx +0x35 cmpb xx +0x36 cmpa indexed +0x37 cmpb indexed + +CUSTOM OPCODE: Set Address lines 16-23 +-------------------------------------- +0x38 setlines xx +0x39 setlines indexed + +The eight bits taken as parameter set address lines 16 to 23. + + +0x3a sta indexed +0x3b stb indexed +0x3c andcc +0x3d orcc + +0x3e exg xx +0x3f tfr xx + +0x40 ldd xx xx +0x41 ldd indexed +0x42 ldx xx xx +0x43 ldx indexed +0x44 ldy xx xx +0x45 ldy indexed (not confirmed) +0x46 ldu xx xx +0x47 ldu indexed +0x48 lds xx xx +0x49 lds indexed (not confirmed) + +0x4a cmpd xx xx +0x4b cmpd indexed +0x4c cmpx xx xx +0x4d cmpx indexed +0x4e cmpy xx xx (not confirmed) +0x4f cmpy indexed (not confirmed) +0x50 cmpu xx xx (not confirmed) +0x51 cmpu indexed (not confirmed) +0x52 cmps xx xx (not confirmed) +0x53 cmps indexed (not confirmed) + +0x54 addd xx xx +0x55 addd indexed (not confirmed) +0x56 subd xx xx +0x57 subd indexed (not confirmed) + +0x58 std indexed +0x59 stx indexed +0x5a sty indexed +0x5b stu indexed +0x5c sts indexed (not confirmed) + + +BRANCH OPCODE TABLE : +--------------------- + +Opcode M6809 Konami +BRA 20 60 +BRN 21 70 +BHI 22 61 +BLS 23 71 +BCC 24 62 +BCS 25 72 +BNE 26 63 +BEQ 27 73 +BVC 28 64 +BVS 29 74 +BPL 2a 65 +BMI 2b 75 +BGE 2c 66 +BLT 2d 76 +BGT 2e 67 +BLE 2f 77 + +Long versions of the branchs are the number + 8. + +0x80 clra +0x81 clrb +0x82 clr indexed + +0x83 coma +0x84 comb +0x85 com indexed + +0x86 nega (not confirmed) +0x87 negb (not confirmed) +0x88 neg indexed (not confirmed) + +0x89 inca +0x8a incb (not confirmed) +0x8b inc indexed + +0x8c deca +0x8d decb +0x8e dec indexed + +0x8f rts + +0x90 tsta (not confirmed) +0x91 tstb (not confirmed) +0x92 tst indexed (not confirmed) + +0x93 lsra +0x94 lsrb +0x95 lsr indexed + +0x96 rora +0x97 rorb +0x98 ror indexed + +0x99 asra +0x9a asrb +0x9b asr indexed + +0x9c asla +0x9d aslb +0x9e asl indexed + +0x9f rti + +0xa0 rola +0xa1 rolb +0xa2 rol indexed + +0xa3 lsrw indexed ( not confirmed ) +0xa4 rorw indexed ( not confirmed ) +0xa5 asrw indexed ( not confirmed ) +0xa6 aslw indexed ( not confirmed ) +0xa7 rolw indexed ( not confirmed ) + +0xa8 jmp indexed +0xa9 jsr indexed +0xaa bsr xx +0xab lbsr xx xx +0xac decb,jnz xx +0xad decx,jnz xx +0xae nop + +0xb0 abx +0xb1 daa +0xb2 sex + +0xb3 mul + +0xb4 lmul x:y = x * y + +0xb5 divx x = ( x / b ), b = ( x % b ) + +CUSTOM OPCODE: BlockMove (y,x,u): +--------------------------------- +0xb6 bmove y,x,u + +y = pointer to source address +x = pointer to destination address +u = bytes to move + +One byte is copied at a time and x and y get incremented for each access. + +CUSTOM OPCODE: Move (y,x,u): +--------------------------------- +0xb7 move y,x,u + +y = pointer to source address +x = pointer to destination address +u = counter + +Copy ONE byte, increment x and y, decrement u. + +0xb8 lsrd xx +0xb9 lsrd indexed +0xba rord xx ( not confirmed ) +0xbb rord indexed ( not confirmed ) +0xbc asrd xx ( not confirmed ) +0xbd asrd indexed ( not confirmed ) +0xbe asld xx +0xbf asld indexed ( not confirmed ) +0xc0 rold xx ( not confirmed ) +0xc1 rold indexed ( not confirmed ) + +0xc2 clrd +0xc3 clrw indexed ( clears an entire word ) ( not confirmed ) + +0xc4 negd (not confirmed ) +0xc5 negw indexed + +0xc6 incd (not confirmed ) +0xc7 incw indexed + +0xc8 decd (not confirmed ) +0xc9 decw indexed + +0xca tstd +0xcb tstw indexed + +0xcc absa +0xcd absb +0xce absd + +CUSTOM OPCODE: BlockSet (a,x,u): +--------------------------------- +0xcf bset a,x,u + +a = source data +x = pointer to destination address +u = bytes to move + +One byte is copied at a time and x get incremented for each access. + +CUSTOM OPCODE: BlockSet (d,x,u): (not confirmed) +-------------------------------- +0xd0 bset d,x,u + +d = source data +x = pointer to destination address +u = bytes to move/2 + +Two bytes are copied at a time and x get incremented twice for each access. + +*/ + +static unsigned byte_count; +static unsigned local_pc; +static unsigned flags; + +static const unsigned char *opram_ptr; + +static unsigned char get_next_byte( void ) { + return opram_ptr[byte_count++]; +} + +/* Table for indexed operations */ +static const char index_reg[8][3] = { + "?", /* 0 - extended mode */ + "?", /* 1 */ + "x", /* 2 */ + "y", /* 3 */ + "?", /* 4 - direct page */ + "u", /* 5 */ + "s", /* 6 */ + "pc" /* 7 - pc */ +}; + +/* Table for tfr/exg operations */ +static const char tfrexg_reg[8][3] = { + "a", /* 0 */ + "b", /* 1 */ + "x", /* 2 */ + "y", /* 3 */ + "s", /* 4 */ + "u", /* 5 */ + "?", /* 6 */ + "?", /* 7 */ +}; + +/* Table for stack S operations */ +static const char stack_reg_s[8][3] = { + "cc", + "a", + "b", + "dp", + "x", + "y", + "u", + "pc" +}; + +/* Table for stack U operations */ +static const char stack_reg_u[8][3] = { + "cc", + "a", + "b", + "dp", + "x", + "y", + "s", + "pc" +}; + +static void calc_indexed( unsigned char mode, char *buf ) { + char buf2[30]; + int idx, type; + + idx = ( mode >> 4 ) & 7; + type = mode & 0x0f; + + /* special modes */ + if ( mode & 0x80 ) { + if ( type & 8 ) { /* indirect */ + switch ( type & 7 ) { + case 0x00: /* register a */ + sprintf( buf2, "[a,%s]", index_reg[idx] ); + break; + + case 0x01: /* register b */ + sprintf( buf2, "[b,%s]", index_reg[idx] ); + break; + + case 0x04: /* direct - mode */ + sprintf( buf2, "[$%02x]", get_next_byte() ); + break; + + case 0x07: /* register d */ + sprintf( buf2, "[d,%s]", index_reg[idx] ); + break; + + default: + sprintf( buf2, "[?,%s]", index_reg[idx] ); + break; + } + } else { + switch ( type & 7 ) { + case 0x00: /* register a */ + sprintf( buf2, "a,%s", index_reg[idx] ); + break; + + case 0x01: /* register b */ + sprintf( buf2, "b,%s", index_reg[idx] ); + break; + + case 0x04: /* direct - mode */ + sprintf( buf2, "$%02x", get_next_byte() ); + break; + + case 0x07: /* register d */ + sprintf( buf2, "d,%s", index_reg[idx] ); + break; + + default: + sprintf( buf2, "????,%s", index_reg[idx] ); + break; + } + } + } else { + if ( type & 8 ) { /* indirect */ + switch ( type & 7 ) { + case 0: /* auto increment */ + sprintf( buf2, "[,%s+]", index_reg[idx] ); + break; + + case 1: /* auto increment double */ + sprintf( buf2, "[,%s++]", index_reg[idx] ); + break; + + case 2: /* auto decrement */ + sprintf( buf2, "[,-%s]", index_reg[idx] ); + break; + + case 3: /* auto decrement double */ + sprintf( buf2, "[,--%s]", index_reg[idx] ); + break; + + case 4: /* post byte offset */ + { + int val = get_next_byte(); + + if ( val & 0x80 ) + sprintf( buf2, "[#$-%02x,%s]", 0x100 - val, index_reg[idx] ); + else + sprintf( buf2, "[#$%02x,%s]", val, index_reg[idx] ); + } + break; + + case 5: /* post word offset */ + { + int val = get_next_byte() << 8; + + val |= get_next_byte(); + + if ( val & 0x8000 ) + sprintf( buf2, "[#$-%04x,%s]", 0x10000 - val, index_reg[idx] ); + else + sprintf( buf2, "[#$%04x,%s]", val, index_reg[idx] ); + } + break; + + case 6: /* simple */ + sprintf( buf2, "[,%s]", index_reg[idx] ); + break; + + case 7: /* extended */ + { + int val = get_next_byte() << 8; + + val |= get_next_byte(); + + sprintf( buf2, "[$%04x]", val ); + } + break; + } + } else { + switch ( type & 7 ) { + case 0: /* auto increment */ + sprintf( buf2, ",%s+", index_reg[idx] ); + break; + + case 1: /* auto increment double */ + sprintf( buf2, ",%s++", index_reg[idx] ); + break; + + case 2: /* auto decrement */ + sprintf( buf2, ",-%s", index_reg[idx] ); + break; + + case 3: /* auto decrement double */ + sprintf( buf2, ",--%s", index_reg[idx] ); + break; + + case 4: /* post byte offset */ + { + int val = get_next_byte(); + + if ( val & 0x80 ) + sprintf( buf2, "#$-%02x,%s", 0x100 - val , index_reg[idx] ); + else + sprintf( buf2, "#$%02x,%s", val, index_reg[idx] ); + } + break; + + case 5: /* post word offset */ + { + int val = get_next_byte() << 8; + + val |= get_next_byte(); + + if ( val & 0x8000 ) + sprintf( buf2, "#$-%04x,%s", 0x10000 - val, index_reg[idx] ); + else + sprintf( buf2, "#$%04x,%s", val, index_reg[idx] ); + } + break; + + case 6: /* simple */ + sprintf( buf2, ",%s", index_reg[idx] ); + break; + + case 7: /* extended */ + { + int val = get_next_byte() << 8; + + val |= get_next_byte(); + + sprintf( buf2, "$%04x", val ); + } + break; + + } + } + } + + strcat( buf, buf2 ); +} + +static void do_relative( char *buf ) { + char buf2[30]; + signed char offs = ( signed char )get_next_byte(); + + sprintf( buf2, "$%04x (%d)", local_pc + byte_count + offs, (int)offs ); + + strcat( buf, buf2 ); +} + +static void do_relative_word( char *buf ) { + char buf2[30]; + signed short offs; + int val = get_next_byte() << 8; + + val |= get_next_byte(); + + offs = ( signed short )val; + + sprintf( buf2, "$%04x (%d)", local_pc + byte_count + offs, (int)offs ); + + strcat( buf, buf2 ); +} + +static void do_addressing( char *buf ) { + unsigned char mode = get_next_byte(); + + calc_indexed( mode, buf ); +} + +/********************************************************************************* + + Opcodes + +*********************************************************************************/ + +static void illegal( char *buf ) { + sprintf( buf, "illegal/unknown " ); + +} + +static void leax( char *buf ) { + sprintf( buf, "leax " ); + do_addressing( buf ); +} + +static void leay( char *buf ) { + sprintf( buf, "leay " ); + do_addressing( buf ); +} + +static void leau( char *buf ) { + sprintf( buf, "leau " ); + do_addressing( buf ); +} + +static void leas( char *buf ) { + sprintf( buf, "leas " ); + do_addressing( buf ); +} + +static void lda( char *buf ) { + sprintf( buf, "lda #$%02x", get_next_byte() ); +} + +static void ldb( char *buf ) { + sprintf( buf, "ldb #$%02x", get_next_byte() ); +} + +static void lda2( char *buf ) { + sprintf( buf, "lda " ); + do_addressing( buf ); +} + +static void ldb2( char *buf ) { + sprintf( buf, "ldb " ); + do_addressing( buf ); +} + +static void adda( char *buf ) { + sprintf( buf, "adda #$%02x", get_next_byte() ); +} + +static void addb( char *buf ) { + sprintf( buf, "addb #$%02x", get_next_byte() ); +} + +static void adda2( char *buf ) { + sprintf( buf, "adda " ); + do_addressing( buf ); +} + +static void addb2( char *buf ) { + sprintf( buf, "addb " ); + do_addressing( buf ); +} + +static void suba( char *buf ) { + sprintf( buf, "suba #$%02x", get_next_byte() ); +} + +static void subb( char *buf ) { + sprintf( buf, "subb #$%02x", get_next_byte() ); +} + +static void suba2( char *buf ) { + sprintf( buf, "suba " ); + do_addressing( buf ); +} + +static void subb2( char *buf ) { + sprintf( buf, "subb " ); + do_addressing( buf ); +} + +static void sbca( char *buf ) { + sprintf( buf, "sbca #$%02x", get_next_byte() ); +} + +static void sbcb( char *buf ) { + sprintf( buf, "sbcb #$%02x", get_next_byte() ); +} + +static void sbca2( char *buf ) { + sprintf( buf, "sbca " ); + do_addressing( buf ); +} + +static void sbcb2( char *buf ) { + sprintf( buf, "sbcb " ); + do_addressing( buf ); +} + +static void adca( char *buf ) { + sprintf( buf, "adca #$%02x", get_next_byte() ); +} + +static void adca2( char *buf ) { + sprintf( buf, "adca " ); + do_addressing( buf ); +} + +static void adcb2( char *buf ) { + sprintf( buf, "adcb " ); + do_addressing( buf ); +} + +static void adcb( char *buf ) { + sprintf( buf, "adcb #$%02x", get_next_byte() ); +} + +static void anda( char *buf ) { + sprintf( buf, "anda #$%02x", get_next_byte() ); +} + +static void andb( char *buf ) { + sprintf( buf, "andb #$%02x", get_next_byte() ); +} + +static void anda2( char *buf ) { + sprintf( buf, "anda " ); + do_addressing( buf ); +} + +static void andb2( char *buf ) { + sprintf( buf, "andb " ); + do_addressing( buf ); +} + +static void bita( char *buf ) { + sprintf( buf, "bita #$%02x", get_next_byte() ); +} + +static void bitb( char *buf ) { + sprintf( buf, "bitb #$%02x", get_next_byte() ); +} + +static void bita2( char *buf ) { + sprintf( buf, "bita " ); + do_addressing( buf ); +} + +static void bitb2( char *buf ) { + sprintf( buf, "bitb " ); + do_addressing( buf ); +} + +static void eora( char *buf ) { + sprintf( buf, "eora #$%02x", get_next_byte() ); +} + +static void eorb( char *buf ) { + sprintf( buf, "eorb #$%02x", get_next_byte() ); +} + +static void eora2( char *buf ) { + sprintf( buf, "eora " ); + do_addressing( buf ); +} + +static void eorb2( char *buf ) { + sprintf( buf, "eorb " ); + do_addressing( buf ); +} + +static void ora( char *buf ) { + sprintf( buf, "ora #$%02x", get_next_byte() ); +} + +static void orb( char *buf ) { + sprintf( buf, "orb #$%02x", get_next_byte() ); +} + +static void ora2( char *buf ) { + sprintf( buf, "ora " ); + do_addressing( buf ); +} + +static void orb2( char *buf ) { + sprintf( buf, "orb " ); + do_addressing( buf ); +} + +static void cmpa( char *buf ) { + sprintf( buf, "cmpa #$%02x", get_next_byte() ); +} + +static void cmpb( char *buf ) { + sprintf( buf, "cmpb #$%02x", get_next_byte() ); +} + +static void cmpa2( char *buf ) { + sprintf( buf, "cmpa " ); + do_addressing( buf ); +} + +static void cmpb2( char *buf ) { + sprintf( buf, "cmpb " ); + do_addressing( buf ); +} + +static void setlines( char *buf ) { + sprintf( buf, "setlines #$%02x", get_next_byte() ); +} + +static void setlines2( char *buf ) { + sprintf( buf, "setlines " ); + do_addressing( buf ); +} + +static void sta2( char *buf ) { + sprintf( buf, "sta " ); + do_addressing( buf ); +} + +static void stb2( char *buf ) { + sprintf( buf, "stb " ); + do_addressing( buf ); +} + +static void ldd( char *buf ) { + int val = get_next_byte() << 8; + + val |= get_next_byte(); + + sprintf( buf, "ldd #$%04x", val ); +} + +static void ldd2( char *buf ) { + sprintf( buf, "ldd " ); + do_addressing( buf ); +} + +static void ldx( char *buf ) { + int val = get_next_byte() << 8; + + val |= get_next_byte(); + + sprintf( buf, "ldx #$%04x", val ); +} + +static void ldx2( char *buf ) { + sprintf( buf, "ldx " ); + do_addressing( buf ); +} + +static void ldy( char *buf ) { + int val = get_next_byte() << 8; + + val |= get_next_byte(); + + sprintf( buf, "ldy #$%04x", val ); +} + +static void ldy2( char *buf ) { + sprintf( buf, "ldy " ); + do_addressing( buf ); +} + +static void ldu( char *buf ) { + int val = get_next_byte() << 8; + + val |= get_next_byte(); + + sprintf( buf, "ldu #$%04x", val ); +} + +static void ldu2( char *buf ) { + sprintf( buf, "ldu " ); + do_addressing( buf ); +} + +static void lds( char *buf ) { + int val = get_next_byte() << 8; + + val |= get_next_byte(); + + sprintf( buf, "lds #$%04x", val ); +} + +static void lds2( char *buf ) { + sprintf( buf, "lds " ); + do_addressing( buf ); +} + +static void cmpd( char *buf ) { + int val = get_next_byte() << 8; + + val |= get_next_byte(); + + sprintf( buf, "cmpd #$%04x", val ); +} + +static void cmpd2( char *buf ) { + sprintf( buf, "cmpd " ); + do_addressing( buf ); +} + +static void cmpx( char *buf ) { + int val = get_next_byte() << 8; + + val |= get_next_byte(); + + sprintf( buf, "cmpx #$%04x", val ); +} + +static void cmpx2( char *buf ) { + sprintf( buf, "cmpx " ); + do_addressing( buf ); +} + +static void cmpy( char *buf ) { + int val = get_next_byte() << 8; + + val |= get_next_byte(); + + sprintf( buf, "cmpy #$%04x", val ); +} + +static void cmpy2( char *buf ) { + sprintf( buf, "cmpy " ); + do_addressing( buf ); +} + +static void cmpu( char *buf ) { + int val = get_next_byte() << 8; + + val |= get_next_byte(); + + sprintf( buf, "cmpu #$%04x", val ); +} + +static void cmpu2( char *buf ) { + sprintf( buf, "cmpu " ); + do_addressing( buf ); +} + +static void cmps( char *buf ) { + int val = get_next_byte() << 8; + + val |= get_next_byte(); + + sprintf( buf, "cmps #$%04x", val ); +} + +static void cmps2( char *buf ) { + sprintf( buf, "cmps " ); + do_addressing( buf ); +} + +static void addd2( char *buf ) { + sprintf( buf, "addd " ); + do_addressing( buf ); +} + +static void subd2( char *buf ) { + sprintf( buf, "subd " ); + do_addressing( buf ); +} + +static void std2( char *buf ) { + sprintf( buf, "std " ); + do_addressing( buf ); +} + +static void stx2( char *buf ) { + sprintf( buf, "stx " ); + do_addressing( buf ); +} + +static void sty2( char *buf ) { + sprintf( buf, "sty " ); + do_addressing( buf ); +} + +static void stu2( char *buf ) { + sprintf( buf, "stu " ); + do_addressing( buf ); +} + +static void sts2( char *buf ) { + sprintf( buf, "sts " ); + do_addressing( buf ); +} + +static void bra( char *buf ) { + sprintf( buf, "bra " ); + do_relative( buf ); +} + +static void lbra( char *buf ) { + sprintf( buf, "lbra " ); + do_relative_word( buf ); +} + +static void brn( char *buf ) { + sprintf( buf, "brn " ); + do_relative( buf ); +} + +static void lbrn( char *buf ) { + sprintf( buf, "lbrn " ); + do_relative_word( buf ); +} + +static void bhi( char *buf ) { + sprintf( buf, "bhi " ); + do_relative( buf ); +} + +static void lbhi( char *buf ) { + sprintf( buf, "lbhi " ); + do_relative_word( buf ); +} + +static void bls( char *buf ) { + sprintf( buf, "bls " ); + do_relative( buf ); +} + +static void lbls( char *buf ) { + sprintf( buf, "lbls " ); + do_relative_word( buf ); +} + +static void bcc( char *buf ) { + sprintf( buf, "bcc " ); + do_relative( buf ); +} + +static void lbcc( char *buf ) { + sprintf( buf, "lbcc " ); + do_relative_word( buf ); +} + +static void bcs( char *buf ) { + sprintf( buf, "bcs " ); + do_relative( buf ); +} + +static void lbcs( char *buf ) { + sprintf( buf, "lbcs " ); + do_relative_word( buf ); +} + +static void bne( char *buf ) { + sprintf( buf, "bne " ); + do_relative( buf ); +} + +static void lbne( char *buf ) { + sprintf( buf, "lbne " ); + do_relative_word( buf ); +} + +static void beq( char *buf ) { + sprintf( buf, "beq " ); + do_relative( buf ); +} + +static void lbeq( char *buf ) { + sprintf( buf, "lbeq " ); + do_relative_word( buf ); +} + +static void bvc( char *buf ) { + sprintf( buf, "bvc " ); + do_relative( buf ); +} + +static void lbvc( char *buf ) { + sprintf( buf, "lbvc " ); + do_relative_word( buf ); +} + +static void bvs( char *buf ) { + sprintf( buf, "bvs " ); + do_relative( buf ); +} + +static void lbvs( char *buf ) { + sprintf( buf, "lbvs " ); + do_relative_word( buf ); +} + +static void bpl( char *buf ) { + sprintf( buf, "bpl " ); + do_relative( buf ); +} + +static void lbpl( char *buf ) { + sprintf( buf, "lbpl " ); + do_relative_word( buf ); +} + +static void bmi( char *buf ) { + sprintf( buf, "bmi " ); + do_relative( buf ); +} + +static void lbmi( char *buf ) { + sprintf( buf, "lbmi " ); + do_relative_word( buf ); +} + +static void bge( char *buf ) { + sprintf( buf, "bge " ); + do_relative( buf ); +} + +static void lbge( char *buf ) { + sprintf( buf, "lbge " ); + do_relative_word( buf ); +} + +static void blt( char *buf ) { + sprintf( buf, "blt " ); + do_relative( buf ); +} + +static void lblt( char *buf ) { + sprintf( buf, "lblt " ); + do_relative_word( buf ); +} + +static void bgt( char *buf ) { + sprintf( buf, "bgt " ); + do_relative( buf ); +} + +static void lbgt( char *buf ) { + sprintf( buf, "lbgt " ); + do_relative_word( buf ); +} + +static void ble( char *buf ) { + sprintf( buf, "ble " ); + do_relative( buf ); +} + +static void lble( char *buf ) { + sprintf( buf, "lble " ); + do_relative_word( buf ); +} + +static void clra( char *buf ) { + sprintf( buf, "clra" ); +} + +static void clrb( char *buf ) { + sprintf( buf, "clrb" ); +} + +static void clrd( char *buf ) { + sprintf( buf, "clrd" ); +} + +static void clrw( char *buf ) { + sprintf( buf, "clrw " ); + do_addressing( buf ); +} + +static void negd( char *buf ) { + sprintf( buf, "negd" ); +} + +static void negw( char *buf ) { + sprintf( buf, "negw" ); + do_addressing( buf ); +} + +static void incd( char *buf ) { + sprintf( buf, "incd" ); +} + +static void incw( char *buf ) { + sprintf( buf, "incw " ); + do_addressing( buf ); +} + +static void decd( char *buf ) { + sprintf( buf, "decd" ); +} + +static void decw( char *buf ) { + sprintf( buf, "decw " ); + do_addressing( buf ); +} + +static void tstd( char *buf ) { + sprintf( buf, "tstd " ); +} + +static void tstw( char *buf ) { + sprintf( buf, "tstw " ); + do_addressing( buf ); +} + +static void clr2( char *buf ) { + sprintf( buf, "clr " ); + do_addressing( buf ); +} + +static void coma( char *buf ) { + sprintf( buf, "coma" ); +} + +static void comb( char *buf ) { + sprintf( buf, "comb" ); +} + +static void com2( char *buf ) { + sprintf( buf, "com " ); + do_addressing( buf ); +} + +static void nega( char *buf ) { + sprintf( buf, "nega" ); +} + +static void negb( char *buf ) { + sprintf( buf, "negb" ); +} + +static void neg2( char *buf ) { + sprintf( buf, "neg " ); + do_addressing( buf ); +} + +static void inca( char *buf ) { + sprintf( buf, "inca" ); +} + +static void incb( char *buf ) { + sprintf( buf, "incb" ); +} + +static void inc2( char *buf ) { + sprintf( buf, "inc " ); + do_addressing( buf ); +} + +static void deca( char *buf ) { + sprintf( buf, "deca" ); +} + +static void decb( char *buf ) { + sprintf( buf, "decb" ); +} + +static void dec2( char *buf ) { + sprintf( buf, "dec " ); + do_addressing( buf ); +} + +static void rts( char *buf ) { + sprintf( buf, "rts" ); + flags = DASMFLAG_STEP_OUT; +} + +static void asla( char *buf ) { + sprintf( buf, "asla" ); +} + +static void aslb( char *buf ) { + sprintf( buf, "aslb" ); +} + +static void asl2( char *buf ) { + sprintf( buf, "asl " ); + do_addressing( buf ); +} + +static void rora( char *buf ) { + sprintf( buf, "rora" ); +} + +static void rorb( char *buf ) { + sprintf( buf, "rorb" ); +} + +static void ror2( char *buf ) { + sprintf( buf, "ror " ); + do_addressing( buf ); +} + +static void rti( char *buf ) { + sprintf( buf, "rti" ); + flags = DASMFLAG_STEP_OUT; +} + +static void jsr2( char *buf ) { + sprintf( buf, "jsr " ); + do_addressing( buf ); + flags = DASMFLAG_STEP_OVER; +} + +static void jmp2( char *buf ) { + sprintf( buf, "jmp " ); + do_addressing( buf ); +} + +static void bsr( char *buf ) { + sprintf( buf, "bsr " ); + do_relative( buf ); + flags = DASMFLAG_STEP_OVER; +} + +static void lbsr( char *buf ) { + sprintf( buf, "lbsr " ); + do_relative_word( buf ); + flags = DASMFLAG_STEP_OVER; +} + +static void decbjnz( char *buf ) { + sprintf( buf, "decb,jnz " ); + do_relative( buf ); + flags = DASMFLAG_STEP_OVER; +} + +static void decxjnz( char *buf ) { + sprintf( buf, "decx,jnz " ); + do_relative( buf ); + flags = DASMFLAG_STEP_OVER; +} + +static void addd( char *buf ) { + int val = get_next_byte() << 8; + + val |= get_next_byte(); + + sprintf( buf, "addd #$%04x", val ); +} + +static void subd( char *buf ) { + int val = get_next_byte() << 8; + + val |= get_next_byte(); + + sprintf( buf, "subd #$%04x", val ); +} + +static void tsta( char *buf ) { + sprintf( buf, "tsta" ); +} + +static void tstb( char *buf ) { + sprintf( buf, "tstb" ); +} + +static void tst2( char *buf ) { + sprintf( buf, "tst " ); + do_addressing( buf ); +} + +static void lsra( char *buf ) { + sprintf( buf, "lsra" ); +} + +static void lsrb( char *buf ) { + sprintf( buf, "lsrb" ); +} + +static void lsr2( char *buf ) { + sprintf( buf, "lsr " ); + do_addressing( buf ); +} + +static void asra( char *buf ) { + sprintf( buf, "asra" ); +} + +static void asrb( char *buf ) { + sprintf( buf, "asrb" ); +} + +static void asr2( char *buf ) { + sprintf( buf, "asr " ); + do_addressing( buf ); +} + +static void abx( char *buf ) { + sprintf( buf, "abx" ); +} + +static void sex( char *buf ) { + sprintf( buf, "sex" ); +} + +static void daa( char *buf ) { + sprintf( buf, "daa" ); +} + +static void mul( char *buf ) { + sprintf( buf, "mul" ); +} + +static void lmul( char *buf ) { + sprintf( buf, "lmul" ); +} + +static void divx( char *buf ) { + sprintf( buf, "div x,b" ); +} + +static void andcc( char *buf ) { + sprintf( buf, "andcc #$%02x", get_next_byte() ); +} + +static void orcc( char *buf ) { + sprintf( buf, "orcc #$%02x", get_next_byte() ); +} + +static void pushs( char *buf ) { + int mask = get_next_byte(), i; + + sprintf( buf, "pushs " ); + + for ( i = 0; i < 8; i++ ) { + if ( ( mask >> i ) & 1 ) { + strcat( buf, stack_reg_s[i] ); + mask &= ~( 1 << i ); + if ( mask ) + strcat( buf, "," ); + else + return; + } + } +} + +static void pushu( char *buf ) { + int mask = get_next_byte(), i; + + sprintf( buf, "pushu " ); + + for ( i = 0; i < 8; i++ ) { + if ( ( mask >> i ) & 1 ) { + strcat( buf, stack_reg_u[i] ); + mask &= ~( 1 << i ); + if ( mask ) + strcat( buf, "," ); + else + return; + } + } +} + +static void pulls( char *buf ) { + int mask = get_next_byte(), i; + + sprintf( buf, "pulls " ); + + for ( i = 0; i < 8; i++ ) { + if ( ( mask >> i ) & 1 ) { + strcat( buf, stack_reg_s[i] ); + if (i == 7) + flags = DASMFLAG_STEP_OUT; + mask &= ~( 1 << i ); + if ( mask ) + strcat( buf, "," ); + else + return; + } + } +} + +static void pullu( char *buf ) { + int mask = get_next_byte(), i; + + sprintf( buf, "pullu " ); + + for ( i = 0; i < 8; i++ ) { + if ( ( mask >> i ) & 1 ) { + strcat( buf, stack_reg_s[i] ); + mask &= ~( 1 << i ); + if ( mask ) + strcat( buf, "," ); + else + return; + } + } +} + +static void rola( char *buf ) { + sprintf( buf, "rola" ); +} + +static void rolb( char *buf ) { + sprintf( buf, "rolb" ); +} + +static void rol2( char *buf ) { + sprintf( buf, "rol " ); + do_addressing( buf ); +} + +static void bmove( char *buf ) { + sprintf( buf, "bmove y,x,u" ); +} + +static void move( char *buf ) { + sprintf( buf, "move y,x,u" ); +} + +static void bset( char *buf ) { + sprintf( buf, "bset a,x,u" ); +} + +static void bset2( char *buf ) { + sprintf( buf, "bset d,x,u" ); +} + +static void nop( char *buf ) { + sprintf( buf, "nop" ); +} + +static void tfr( char *buf ) { + int mask = get_next_byte(); + + sprintf( buf, "tfr " ); + + strcat( buf, tfrexg_reg[ mask & 0x07 ] ); + strcat( buf, "," ); + strcat( buf, tfrexg_reg[ ( mask >> 4 ) & 0x07 ] ); +} + +static void exg( char *buf ) { + int mask = get_next_byte(); + + sprintf( buf, "exg " ); + + strcat( buf, tfrexg_reg[ mask & 0x07 ] ); + strcat( buf, "," ); + strcat( buf, tfrexg_reg[ ( mask >> 4 ) & 0x07 ] ); +} + +static void lsrd( char *buf ) { + sprintf( buf, "lsrd #$%02x", get_next_byte() ); +} + +static void lsrd2( char *buf ) { + sprintf( buf, "lsrd " ); + do_addressing( buf ); +} + +static void rord( char *buf ) { + sprintf( buf, "rord #$%02x", get_next_byte() ); +} + +static void rord2( char *buf ) { + sprintf( buf, "rord " ); + do_addressing( buf ); +} + +static void asrd( char *buf ) { + sprintf( buf, "asrd #$%02x", get_next_byte() ); +} + +static void asrd2( char *buf ) { + sprintf( buf, "asrd " ); + do_addressing( buf ); +} + +static void asld( char *buf ) { + sprintf( buf, "asld #$%02x", get_next_byte() ); +} + +static void asld2( char *buf ) { + sprintf( buf, "asld " ); + do_addressing( buf ); +} + +static void rold( char *buf ) { + sprintf( buf, "rold #$%02x", get_next_byte() ); +} + +static void rold2( char *buf ) { + sprintf( buf, "rold " ); + do_addressing( buf ); +} + +static void lsrw( char *buf ) { + sprintf( buf, "lsrw " ); + do_addressing( buf ); +} + +static void rorw( char *buf ) { + sprintf( buf, "lsrw " ); + do_addressing( buf ); +} + +static void asrw( char *buf ) { + sprintf( buf, "asrw " ); + do_addressing( buf ); +} + +static void aslw( char *buf ) { + sprintf( buf, "aslw " ); + do_addressing( buf ); +} + +static void rolw( char *buf ) { + sprintf( buf, "rolw " ); + do_addressing( buf ); +} + +static void absa( char *buf ) { + sprintf( buf, "absa" ); +} + +static void absb( char *buf ) { + sprintf( buf, "absb" ); +} + +static void absd( char *buf ) { + sprintf( buf, "absd" ); +} + +/********************************************************************************* + + Opcode Table + +*********************************************************************************/ + +struct konami_opcode_def { + void (*decode)( char *buf ); + int confirmed; +}; + +static const konami_opcode_def op_table[256] = { + /* 00 */ { illegal, 0 }, + /* 01 */ { illegal, 0 }, + /* 02 */ { illegal, 0 }, + /* 03 */ { illegal, 0 }, + /* 04 */ { illegal, 0 }, + /* 05 */ { illegal, 0 }, + /* 06 */ { illegal, 0 }, + /* 07 */ { illegal, 0 }, + /* 08 */ { leax, 1 }, + /* 09 */ { leay, 1 }, + /* 0a */ { leau, 1 }, + /* 0b */ { leas, 0 }, + /* 0c */ { pushs, 1 }, + /* 0d */ { pushu, 0 }, + /* 0e */ { pulls, 1 }, + /* 0f */ { pullu, 0 }, + + /* 10 */ { lda, 1 }, + /* 11 */ { ldb, 1 }, + /* 12 */ { lda2, 1 }, + /* 13 */ { ldb2, 1 }, + /* 14 */ { adda, 1 }, + /* 15 */ { addb, 1 }, + /* 16 */ { adda2, 1 }, + /* 17 */ { addb2, 1 }, + /* 18 */ { adca, 1 }, + /* 19 */ { adcb, 1 }, + /* 1a */ { adca2, 1 }, + /* 1b */ { adcb2, 1 }, + /* 1c */ { suba, 1 }, + /* 1d */ { subb, 1 }, + /* 1e */ { suba2, 1 }, + /* 1f */ { subb2, 1 }, + + /* 20 */ { sbca, 0 }, + /* 21 */ { sbcb, 0 }, + /* 22 */ { sbca2, 0 }, + /* 23 */ { sbcb2, 0 }, + /* 24 */ { anda, 1 }, + /* 25 */ { andb, 1 }, + /* 26 */ { anda2, 1 }, + /* 27 */ { andb2, 1 }, + /* 28 */ { bita, 0 }, + /* 29 */ { bitb, 0 }, + /* 2a */ { bita2, 0 }, + /* 2b */ { bitb2, 0 }, + /* 2c */ { eora, 0 }, + /* 2d */ { eorb, 0 }, + /* 2e */ { eora2, 0 }, + /* 2f */ { eorb2, 0 }, + + /* 30 */ { ora, 1 }, + /* 31 */ { orb, 1 }, + /* 32 */ { ora2, 1 }, + /* 33 */ { orb2, 1 }, + /* 34 */ { cmpa, 1 }, + /* 35 */ { cmpb, 1 }, + /* 36 */ { cmpa2, 1 }, + /* 37 */ { cmpb2, 1 }, + /* 38 */ { setlines, 0 }, + /* 39 */ { setlines2, 0 }, + /* 3a */ { sta2, 1 }, + /* 3b */ { stb2, 1 }, + /* 3c */ { andcc, 1 }, + /* 3d */ { orcc, 0 }, + /* 3e */ { exg, 0 }, + /* 3f */ { tfr, 0 }, + + /* 40 */ { ldd, 1 }, + /* 41 */ { ldd2, 1 }, + /* 42 */ { ldx, 1 }, + /* 43 */ { ldx2, 1 }, + /* 44 */ { ldy, 1 }, + /* 45 */ { ldy2, 1 }, + /* 46 */ { ldu, 1 }, + /* 47 */ { ldu2, 1 }, + /* 48 */ { lds, 1 }, + /* 49 */ { lds2, 1 }, + /* 4a */ { cmpd, 1 }, + /* 4b */ { cmpd2, 1 }, + /* 4c */ { cmpx, 1 }, + /* 4d */ { cmpx2, 1 }, + /* 4e */ { cmpy, 1 }, + /* 4f */ { cmpy2, 1 }, + + /* 50 */ { cmpu, 1 }, + /* 51 */ { cmpu2, 1 }, + /* 52 */ { cmps, 1 }, + /* 53 */ { cmps2, 1 }, + /* 54 */ { addd, 0 }, + /* 55 */ { addd2, 0 }, + /* 56 */ { subd, 1 }, + /* 57 */ { subd2, 0 }, + /* 58 */ { std2, 1 }, + /* 59 */ { stx2, 1 }, + /* 5a */ { sty2, 1 }, + /* 5b */ { stu2, 1 }, + /* 5c */ { sts2, 1 }, + /* 5d */ { illegal, 0 }, + /* 5e */ { illegal, 0 }, + /* 5f */ { illegal, 0 }, + + /* 60 */ { bra, 1 }, + /* 61 */ { bhi, 1 }, + /* 62 */ { bcc, 1 }, + /* 63 */ { bne, 1 }, + /* 64 */ { bvc, 1 }, + /* 65 */ { bpl, 1 }, + /* 66 */ { bge, 1 }, + /* 67 */ { bgt, 1 }, + /* 68 */ { lbra, 1 }, + /* 69 */ { lbhi, 1 }, + /* 6a */ { lbcc, 1 }, + /* 6b */ { lbne, 1 }, + /* 6c */ { lbvc, 1 }, + /* 6d */ { lbpl, 1 }, + /* 6e */ { lbge, 1 }, + /* 6f */ { lbgt, 1 }, + + /* 70 */ { brn, 1 }, + /* 71 */ { bls, 1 }, + /* 72 */ { bcs, 1 }, + /* 73 */ { beq, 1 }, + /* 74 */ { bvs, 1 }, + /* 75 */ { bmi, 1 }, + /* 76 */ { blt, 1 }, + /* 77 */ { ble, 1 }, + /* 78 */ { lbrn, 1 }, + /* 79 */ { lbls, 1 }, + /* 7a */ { lbcs, 1 }, + /* 7b */ { lbeq, 1 }, + /* 7c */ { lbvs, 1 }, + /* 7d */ { lbmi, 1 }, + /* 7e */ { lblt, 1 }, + /* 7f */ { lble, 1 }, + + /* 80 */ { clra, 1 }, + /* 81 */ { clrb, 1 }, + /* 82 */ { clr2, 1 }, + /* 83 */ { coma, 1 }, + /* 84 */ { comb, 0 }, + /* 85 */ { com2, 0 }, + /* 86 */ { nega, 0 }, + /* 87 */ { negb, 0 }, + /* 88 */ { neg2, 0 }, + /* 89 */ { inca, 1 }, + /* 8a */ { incb, 1 }, + /* 8b */ { inc2, 1 }, + /* 8c */ { deca, 1 }, + /* 8d */ { decb, 1 }, + /* 8e */ { dec2, 1 }, + /* 8f */ { rts, 1 }, + + /* 90 */ { tsta, 0 }, + /* 91 */ { tstb, 0 }, + /* 92 */ { tst2, 0 }, + /* 93 */ { lsra, 1 }, + /* 94 */ { lsrb, 1 }, + /* 95 */ { lsr2, 0 }, + /* 96 */ { rora, 0 }, + /* 97 */ { rorb, 0 }, + /* 98 */ { ror2, 0 }, + /* 99 */ { asra, 0 }, + /* 9a */ { asrb, 0 }, + /* 9b */ { asr2, 0 }, + /* 9c */ { asla, 1 }, + /* 9d */ { aslb, 1 }, + /* 9e */ { asl2, 0 }, + /* 9f */ { rti, 1 }, + + /* a0 */ { rola, 1 }, + /* a1 */ { rolb, 0 }, + /* a2 */ { rol2, 0 }, + /* a3 */ { lsrw, 0 }, + /* a4 */ { rorw, 0 }, + /* a5 */ { asrw, 0 }, + /* a6 */ { aslw, 0 }, + /* a7 */ { rolw, 0 }, + /* a8 */ { jmp2, 1 }, + /* a9 */ { jsr2, 1 }, + /* aa */ { bsr, 1 }, + /* ab */ { lbsr, 1 }, + /* ac */ { decbjnz, 0 }, + /* ad */ { decxjnz, 0 }, + /* ae */ { nop, 0 }, + /* af */ { illegal, 0 }, + + /* b0 */ { abx, 0 }, + /* b1 */ { daa, 0 }, + /* b2 */ { sex, 0 }, + /* b3 */ { mul, 1 }, + /* b4 */ { lmul, 0 }, + /* b5 */ { divx, 0 }, + /* b6 */ { bmove, 1 }, + /* b7 */ { move, 0 }, + /* b8 */ { lsrd, 0 }, + /* b9 */ { lsrd2, 0 }, + /* ba */ { rord, 0 }, + /* bb */ { rord2, 0 }, + /* bc */ { asrd, 0 }, + /* bd */ { asrd2, 0 }, + /* be */ { asld, 0 }, + /* bf */ { asld2, 0 }, + + /* c0 */ { rold, 0 }, + /* c1 */ { rold2, 0 }, + /* c2 */ { clrd, 1 }, + /* c3 */ { clrw, 0 }, + /* c4 */ { negd, 0 }, + /* c5 */ { negw, 0 }, + /* c6 */ { incd, 0 }, + /* c7 */ { incw, 0 }, + /* c8 */ { decd, 0 }, + /* c9 */ { decw, 0 }, + /* ca */ { tstd, 0 }, + /* cb */ { tstw, 0 }, + /* cc */ { absa, 0 }, + /* cd */ { absb, 0 }, + /* ce */ { absd, 0 }, + /* cf */ { bset, 0 }, + + /* d0 */ { bset2, 0 }, + /* d1 */ { illegal, 0 }, + /* d2 */ { illegal, 0 }, + /* d3 */ { illegal, 0 }, + /* d4 */ { illegal, 0 }, + /* d5 */ { illegal, 0 }, + /* d6 */ { illegal, 0 }, + /* d7 */ { illegal, 0 }, + /* d8 */ { illegal, 0 }, + /* d9 */ { illegal, 0 }, + /* da */ { illegal, 0 }, + /* db */ { illegal, 0 }, + /* dc */ { illegal, 0 }, + /* dd */ { illegal, 0 }, + /* de */ { illegal, 0 }, + /* df */ { illegal, 0 }, + + /* e0 */ { illegal, 0 }, + /* e1 */ { illegal, 0 }, + /* e2 */ { illegal, 0 }, + /* e3 */ { illegal, 0 }, + /* e4 */ { illegal, 0 }, + /* e5 */ { illegal, 0 }, + /* e6 */ { illegal, 0 }, + /* e7 */ { illegal, 0 }, + /* e8 */ { illegal, 0 }, + /* e9 */ { illegal, 0 }, + /* ea */ { illegal, 0 }, + /* eb */ { illegal, 0 }, + /* ec */ { illegal, 0 }, + /* ed */ { illegal, 0 }, + /* ee */ { illegal, 0 }, + /* ef */ { illegal, 0 }, + + /* f0 */ { illegal, 0 }, + /* f1 */ { illegal, 0 }, + /* f2 */ { illegal, 0 }, + /* f3 */ { illegal, 0 }, + /* f4 */ { illegal, 0 }, + /* f5 */ { illegal, 0 }, + /* f6 */ { illegal, 0 }, + /* f7 */ { illegal, 0 }, + /* f8 */ { illegal, 0 }, + /* f9 */ { illegal, 0 }, + /* fa */ { illegal, 0 }, + /* fb */ { illegal, 0 }, + /* fc */ { illegal, 0 }, + /* fd */ { illegal, 0 }, + /* fe */ { illegal, 0 }, + /* ff */ { illegal, 0 } +}; + +CPU_DISASSEMBLE( konami ) +{ + buffer[0] = '\0'; + + local_pc = pc; + byte_count = 1; + opram_ptr = opram; + flags = 0; + + (op_table[*oprom].decode)( buffer ); + + return byte_count | flags | DASMFLAG_SUPPORTED; +} diff --git a/src/devices/cpu/m6809/konami.c b/src/devices/cpu/m6809/konami.c new file mode 100644 index 00000000000..8dc2bf3ab78 --- /dev/null +++ b/src/devices/cpu/m6809/konami.c @@ -0,0 +1,380 @@ +// license:BSD-3-Clause +// copyright-holders:Nathan Woods +/********************************************************************* + + konami.c + + Portable Konami cpu emulator + + Based on M6809 cpu core copyright John Butler + + References: + + 6809 Simulator V09, By L.C. Benschop, Eindhoven The Netherlands. + + m6809: Portable 6809 emulator, DS (6809 code in MAME, derived from + the 6809 Simulator V09) + + 6809 Microcomputer Programming & Interfacing with Experiments" + by Andrew C. Staugaard, Jr.; Howard W. Sams & Co., Inc. + + System dependencies: UINT16 must be 16 bit unsigned int + UINT8 must be 8 bit unsigned int + UINT32 must be more than 16 bits + arrays up to 65536 bytes must be supported + machine must be twos complement + + History: + +March 2013 NPW: + Rewrite of 6809/6309/Konami CPU; overall core is now unified and + supports mid-instruction timings. + + Some of the instruction timings have changed with the new core; the + old core had some nonsensical timings. For example (from scontra): + + 819A 3A 07 1F 8C STA $1f8C + + Under the old core, this took four clock cycles, which is dubious + because this instruction would have to do four opcode reads and one + write. OGalibert says that the current timings are just a guess and + nobody has done precise readings, so I'm replacing the old guesses + with new guesses. + +991022 HJB: + Tried to improve speed: Using bit7 of cycles1 as flag for multi + byte opcodes is gone, those opcodes now instead go through opcode2(). + Inlined fetch_effective_address() into that function as well. + Got rid of the slow/fast flags for stack (S and U) memory accesses. + Minor changes to use 32 bit values as arguments to memory functions + and added defines for that purpose (e.g. X = 16bit XD = 32bit). + +990720 EHC: + Created this file + +*****************************************************************************/ + +#include "emu.h" +#include "debugger.h" +#include "konami.h" +#include "m6809inl.h" + + +//************************************************************************** +// PARAMETERS +//************************************************************************** + +// turn off 'unreferenced label' errors +#if defined(__GNUC__) && __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 2) +#pragma GCC diagnostic ignored "-Wunused-label" +#endif +#ifdef _MSC_VER +#pragma warning( disable : 4102 ) +#endif + + +//************************************************************************** +// DEVICE INTERFACE +//************************************************************************** + +const device_type KONAMI = &device_creator; + + +//------------------------------------------------- +// konami_cpu_device - constructor +//------------------------------------------------- + +konami_cpu_device::konami_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : m6809_base_device(mconfig, "KONAMI CPU", tag, owner, clock, KONAMI, 1, "konami_cpu", __FILE__), + m_set_lines(*this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void konami_cpu_device::device_start() +{ + super::device_start(); + + // resolve callbacks + m_set_lines.resolve(); +} + + +//------------------------------------------------- +// disasm_disassemble - call the disassembly +// helper function +//------------------------------------------------- + +offs_t konami_cpu_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( konami ); + return CPU_DISASSEMBLE_NAME(konami)(this, buffer, pc, oprom, opram, options); +} + + +//------------------------------------------------- +// read_operand +//------------------------------------------------- + +inline UINT8 konami_cpu_device::read_operand() +{ + return super::read_operand(); +} + + +//------------------------------------------------- +// read_operand +//------------------------------------------------- + +inline UINT8 konami_cpu_device::read_operand(int ordinal) +{ + switch(m_addressing_mode) + { + case ADDRESSING_MODE_EA: return read_memory(m_ea.w + ordinal); + case ADDRESSING_MODE_IMMEDIATE: return read_opcode_arg(); + case ADDRESSING_MODE_REGISTER_D: return (ordinal & 1) ? m_d.b.l : m_d.b.h; + default: fatalerror("Unexpected"); + } +} + + +//------------------------------------------------- +// write_operand +//------------------------------------------------- + +inline void konami_cpu_device::write_operand(UINT8 data) +{ + super::write_operand(data); +} + + + +//------------------------------------------------- +// write_operand +//------------------------------------------------- + +inline void konami_cpu_device::write_operand(int ordinal, UINT8 data) +{ + switch(m_addressing_mode) + { + case ADDRESSING_MODE_IMMEDIATE: /* do nothing */ break; + case ADDRESSING_MODE_EA: write_memory(m_ea.w + ordinal, data); break; + case ADDRESSING_MODE_REGISTER_D: *((ordinal & 1) ? &m_d.b.l : &m_d.b.h) = data; break; + default: fatalerror("Unexpected"); + } +} + + +//------------------------------------------------- +// ireg +//------------------------------------------------- + +inline UINT16 &konami_cpu_device::ireg() +{ + switch(m_opcode & 0x70) + { + case 0x20: return m_x.w; + case 0x30: return m_y.w; + case 0x50: return m_u.w; + case 0x60: return m_s.w; + case 0x70: return m_pc.w; + default: + fatalerror("Should not get here"); + // never executed + //return m_x.w; + } +} + + +//------------------------------------------------- +// read_exgtfr_register +//------------------------------------------------- + +inline m6809_base_device::exgtfr_register konami_cpu_device::read_exgtfr_register(UINT8 reg) +{ + exgtfr_register result; + result.word_value = 0x00FF; + + switch(reg & 0x07) + { + case 0: result.word_value = m_d.b.h; break; // A + case 1: result.word_value = m_d.b.l; break; // B + case 2: result.word_value = m_x.w; break; // X + case 3: result.word_value = m_y.w; break; // Y + case 4: result.word_value = m_s.w; break; // S + case 5: result.word_value = m_u.w; break; // U + } + result.byte_value = (UINT8) result.word_value; + return result; +} + + +//------------------------------------------------- +// write_exgtfr_register +//------------------------------------------------- + +inline void konami_cpu_device::write_exgtfr_register(UINT8 reg, m6809_base_device::exgtfr_register value) +{ + switch(reg & 0x07) + { + case 0: m_d.b.h = value.byte_value; break; // A + case 1: m_d.b.l = value.byte_value; break; // B + case 2: m_x.w = value.word_value; break; // X + case 3: m_y.w = value.word_value; break; // Y + case 4: m_s.w = value.word_value; break; // S + case 5: m_u.w = value.word_value; break; // U + } +} + + +//------------------------------------------------- +// safe_shift_right +//------------------------------------------------- + +template T konami_cpu_device::safe_shift_right(T value, UINT32 shift) +{ + T result; + + if (shift < (sizeof(T) * 8)) + result = value >> shift; + else if (value < 0) + result = (T) -1; + else + result = 0; + + return result; +} + + +//------------------------------------------------- +// safe_shift_right_unsigned +//------------------------------------------------- + +template T konami_cpu_device::safe_shift_right_unsigned(T value, UINT32 shift) +{ + T result; + + if (shift < (sizeof(T) * 8)) + result = value >> shift; + else + result = 0; + + return result; +} + +//------------------------------------------------- +// safe_shift_left +//------------------------------------------------- + +template T konami_cpu_device::safe_shift_left(T value, UINT32 shift) +{ + T result; + + if (shift < (sizeof(T) * 8)) + result = value << shift; + else + result = 0; + + return result; +} + + +//------------------------------------------------- +// lmul +//------------------------------------------------- + +inline void konami_cpu_device::lmul() +{ + PAIR result; + + // do the multiply + result.d = (UINT32)m_x.w * m_y.w; + + // set the result registers + m_x.w = result.w.h; + m_y.w = result.w.l; + + // set Z flag + set_flags(CC_Z, result.d); + + // set C flag + if (result.d & 0x8000) + m_cc |= CC_C; + else + m_cc &= ~CC_C; +} + + +//------------------------------------------------- +// divx +//------------------------------------------------- + +inline void konami_cpu_device::divx() +{ + UINT16 result; + UINT8 remainder; + + if (m_d.b.l != 0) + { + result = m_x.w / m_d.b.l; + remainder = m_x.w % m_d.b.l; + } + else + { + // divide by zero; not sure what happens + result = 0; + remainder = 0; + } + + // set results and Z flag + m_x.w = set_flags(CC_Z, result); + m_d.b.l = remainder; + + // set C flag + if (result & 0x0080) + m_cc |= CC_C; + else + m_cc &= ~CC_C; +} + + +//------------------------------------------------- +// set_lines +//------------------------------------------------- + +void konami_cpu_device::set_lines(UINT8 data) +{ + if (!m_set_lines.isnull()) + m_set_lines((offs_t)0, data); +} + + +//------------------------------------------------- +// execute_one - try to execute a single instruction +//------------------------------------------------- + +inline void konami_cpu_device::execute_one() +{ + switch(pop_state()) + { +#include "cpu/m6809/konami.inc" + } +} + + +//------------------------------------------------- +// execute_run - execute a timeslice's worth of +// opcodes +//------------------------------------------------- + +void konami_cpu_device::execute_run() +{ + do + { + execute_one(); + } while(m_icount > 0); +} diff --git a/src/devices/cpu/m6809/konami.h b/src/devices/cpu/m6809/konami.h new file mode 100644 index 00000000000..dfc5c741497 --- /dev/null +++ b/src/devices/cpu/m6809/konami.h @@ -0,0 +1,81 @@ +// license:BSD-3-Clause +// copyright-holders:Nathan Woods +/********************************************************************* + + konami.h + + Portable Konami CPU emulator + +**********************************************************************/ + +#pragma once + +#ifndef __KONAMI_CPU_H__ +#define __KONAMI_CPU_H__ + +#include "m6809.h" + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +#define MCFG_KONAMICPU_LINE_CB(_devcb) \ + devcb = &konami_cpu_device::set_line_callback(*device, DEVCB_##_devcb); + + +// device type definition +extern const device_type KONAMI; + +// ======================> konami_cpu_device + +class konami_cpu_device : public m6809_base_device +{ +public: + // construction/destruction + konami_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // configuration + template static devcb_base &set_line_callback(device_t &device, _Object object) { return downcast(device).m_set_lines.set_callback(object); } + +protected: + // device-level overrides + virtual void device_start(); + + // device_execute_interface overrides + virtual void execute_run(); + + // device_disasm_interface overrides + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + +private: + typedef m6809_base_device super; + + // incidentals + devcb_write8 m_set_lines; + + // konami-specific addressing modes + UINT16 &ireg(); + UINT8 read_operand(); + UINT8 read_operand(int ordinal); + void write_operand(UINT8 data); + void write_operand(int ordinal, UINT8 data); + exgtfr_register read_exgtfr_register(UINT8 reg); + void write_exgtfr_register(UINT8 reg, exgtfr_register value); + + // instructions + void lmul(); + void divx(); + + // miscellaneous + template T safe_shift_right(T value, UINT32 shift); + template T safe_shift_right_unsigned(T value, UINT32 shift); + template T safe_shift_left(T value, UINT32 shift); + void set_lines(UINT8 data); + void execute_one(); +}; + +#define KONAMI_IRQ_LINE M6809_IRQ_LINE /* 0 - IRQ line number */ +#define KONAMI_FIRQ_LINE M6809_FIRQ_LINE /* 1 - FIRQ line number */ + +#endif /* __KONAMI_CPU_H__ */ diff --git a/src/devices/cpu/m6809/konami.ops b/src/devices/cpu/m6809/konami.ops new file mode 100644 index 00000000000..e2246f85b71 --- /dev/null +++ b/src/devices/cpu/m6809/konami.ops @@ -0,0 +1,605 @@ +MAIN: + // check interrupt lines + switch(get_pending_interrupt()) + { + case VECTOR_NMI: goto NMI; + case VECTOR_FIRQ: goto FIRQ; + case VECTOR_IRQ: goto IRQ; + } + + // debugger hook + m_ppc = m_pc; + debugger_instruction_hook(this, m_pc.w); + + // opcode fetch + @m_opcode = read_opcode(); + + // dispatch opcode + switch(m_opcode) + { + case 0x08: set_regop16(m_x); %INDEXED; %LEA_xy; return; + case 0x09: set_regop16(m_y); %INDEXED; %LEA_xy; return; + case 0x0A: set_regop16(m_u); %INDEXED; %LEA_us; return; + case 0x0B: set_regop16(m_s); %INDEXED; %LEA_us; return; + case 0x0C: %PSHS; return; + case 0x0D: %PSHU; return; + case 0x0E: %PULS; return; + case 0x0F: %PULU; return; + + case 0x10: set_regop8(m_d.b.h); set_imm(); %LD8; return; + case 0x11: set_regop8(m_d.b.l); set_imm(); %LD8; return; + case 0x12: set_regop8(m_d.b.h); %INDEXED; %LD8; return; + case 0x13: set_regop8(m_d.b.l); %INDEXED; %LD8; return; + case 0x14: set_regop8(m_d.b.h); set_imm(); %ADD8; return; + case 0x15: set_regop8(m_d.b.l); set_imm(); %ADD8; return; + case 0x16: set_regop8(m_d.b.h); %INDEXED; %ADD8; return; + case 0x17: set_regop8(m_d.b.l); %INDEXED; %ADD8; return; + case 0x18: set_regop8(m_d.b.h); set_imm(); %ADC8; return; + case 0x19: set_regop8(m_d.b.l); set_imm(); %ADC8; return; + case 0x1A: set_regop8(m_d.b.h); %INDEXED; %ADC8; return; + case 0x1B: set_regop8(m_d.b.l); %INDEXED; %ADC8; return; + case 0x1C: set_regop8(m_d.b.h); set_imm(); %SUB8; return; + case 0x1D: set_regop8(m_d.b.l); set_imm(); %SUB8; return; + case 0x1E: set_regop8(m_d.b.h); %INDEXED; %SUB8; return; + case 0x1F: set_regop8(m_d.b.l); %INDEXED; %SUB8; return; + + case 0x20: set_regop8(m_d.b.h); set_imm(); %SBC8; return; + case 0x21: set_regop8(m_d.b.l); set_imm(); %SBC8; return; + case 0x22: set_regop8(m_d.b.h); %INDEXED; %SBC8; return; + case 0x23: set_regop8(m_d.b.l); %INDEXED; %SBC8; return; + case 0x24: set_regop8(m_d.b.h); set_imm(); %AND8; return; + case 0x25: set_regop8(m_d.b.l); set_imm(); %AND8; return; + case 0x26: set_regop8(m_d.b.h); %INDEXED; %AND8; return; + case 0x27: set_regop8(m_d.b.l); %INDEXED; %AND8; return; + case 0x28: set_regop8(m_d.b.h); set_imm(); %BIT8; return; + case 0x29: set_regop8(m_d.b.l); set_imm(); %BIT8; return; + case 0x2A: set_regop8(m_d.b.h); %INDEXED; %BIT8; return; + case 0x2B: set_regop8(m_d.b.l); %INDEXED; %BIT8; return; + case 0x2C: set_regop8(m_d.b.h); set_imm(); %EOR8; return; + case 0x2D: set_regop8(m_d.b.l); set_imm(); %EOR8; return; + case 0x2E: set_regop8(m_d.b.h); %INDEXED; %EOR8; return; + case 0x2F: set_regop8(m_d.b.l); %INDEXED; %EOR8; return; + + case 0x30: set_regop8(m_d.b.h); set_imm(); %OR8; return; + case 0x31: set_regop8(m_d.b.l); set_imm(); %OR8; return; + case 0x32: set_regop8(m_d.b.h); %INDEXED; %OR8; return; + case 0x33: set_regop8(m_d.b.l); %INDEXED; %OR8; return; + case 0x34: set_regop8(m_d.b.h); set_imm(); %CMP8; return; + case 0x35: set_regop8(m_d.b.l); set_imm(); %CMP8; return; + case 0x36: set_regop8(m_d.b.h); %INDEXED; %CMP8; return; + case 0x37: set_regop8(m_d.b.l); %INDEXED; %CMP8; return; + case 0x38: set_imm(); %SETLINE; return; + case 0x39: %INDEXED; %SETLINE; return; + case 0x3A: set_regop8(m_d.b.h); %INDEXED; %ST8; return; + case 0x3B: set_regop8(m_d.b.l); %INDEXED; %ST8; return; + case 0x3C: set_imm(); %ANDCC; return; + case 0x3D: set_imm(); %ORCC; return; + case 0x3E: %EXG; return; + case 0x3F: %TFR; return; + + case 0x40: set_regop16(m_d); set_imm(); %LD16; return; + case 0x41: set_regop16(m_d); %INDEXED; %LD16; return; + case 0x42: set_regop16(m_x); set_imm(); %LD16; return; + case 0x43: set_regop16(m_x); %INDEXED; %LD16; return; + case 0x44: set_regop16(m_y); set_imm(); %LD16; return; + case 0x45: set_regop16(m_y); %INDEXED; %LD16; return; + case 0x46: set_regop16(m_u); set_imm(); %LD16; return; + case 0x47: set_regop16(m_u); %INDEXED; %LD16; return; + case 0x48: set_regop16(m_s); set_imm(); %LD16; return; + case 0x49: set_regop16(m_s); %INDEXED; %LD16; return; + case 0x4A: set_regop16(m_d); set_imm(); %CMP16; return; + case 0x4B: set_regop16(m_d); %INDEXED; %CMP16; return; + case 0x4C: set_regop16(m_x); set_imm(); %CMP16; return; + case 0x4D: set_regop16(m_x); %INDEXED; %CMP16; return; + case 0x4E: set_regop16(m_y); set_imm(); %CMP16; return; + case 0x4F: set_regop16(m_y); %INDEXED; %CMP16; return; + + case 0x50: set_regop16(m_u); set_imm(); %CMP16; return; + case 0x51: set_regop16(m_u); %INDEXED; %CMP16; return; + case 0x52: set_regop16(m_s); set_imm(); %CMP16; return; + case 0x53: set_regop16(m_s); %INDEXED; %CMP16; return; + case 0x54: set_regop16(m_d); set_imm(); %ADD16; return; + case 0x55: set_regop16(m_d); %INDEXED; %ADD16; return; + case 0x56: set_regop16(m_d); set_imm(); %SUB16; return; + case 0x57: set_regop16(m_d); %INDEXED; %SUB16; return; + case 0x58: set_regop16(m_d); %INDEXED; %ST16; return; + case 0x59: set_regop16(m_x); %INDEXED; %ST16; return; + case 0x5A: set_regop16(m_y); %INDEXED; %ST16; return; + case 0x5B: set_regop16(m_u); %INDEXED; %ST16; return; + case 0x5C: set_regop16(m_s); %INDEXED; %ST16; return; + + case 0x60: set_cond(true); %BRANCH; return; + case 0x61: set_cond(cond_hi()); %BRANCH; return; + case 0x62: set_cond(cond_cc()); %BRANCH; return; + case 0x63: set_cond(cond_ne()); %BRANCH; return; + case 0x64: set_cond(cond_vc()); %BRANCH; return; + case 0x65: set_cond(cond_pl()); %BRANCH; return; + case 0x66: set_cond(cond_ge()); %BRANCH; return; + case 0x67: set_cond(cond_gt()); %BRANCH; return; + case 0x68: set_cond(true); %LBRANCH; return; + case 0x69: set_cond(cond_hi()); %LBRANCH; return; + case 0x6A: set_cond(cond_cc()); %LBRANCH; return; + case 0x6B: set_cond(cond_ne()); %LBRANCH; return; + case 0x6C: set_cond(cond_vc()); %LBRANCH; return; + case 0x6D: set_cond(cond_pl()); %LBRANCH; return; + case 0x6E: set_cond(cond_ge()); %LBRANCH; return; + case 0x6F: set_cond(cond_gt()); %LBRANCH; return; + + case 0x70: set_cond(false); %BRANCH; return; + case 0x71: set_cond(!cond_hi()); %BRANCH; return; + case 0x72: set_cond(!cond_cc()); %BRANCH; return; + case 0x73: set_cond(!cond_ne()); %BRANCH; return; + case 0x74: set_cond(!cond_vc()); %BRANCH; return; + case 0x75: set_cond(!cond_pl()); %BRANCH; return; + case 0x76: set_cond(!cond_ge()); %BRANCH; return; + case 0x77: set_cond(!cond_gt()); %BRANCH; return; + case 0x78: set_cond(false); %LBRANCH; return; + case 0x79: set_cond(!cond_hi()); %LBRANCH; return; + case 0x7A: set_cond(!cond_cc()); %LBRANCH; return; + case 0x7B: set_cond(!cond_ne()); %LBRANCH; return; + case 0x7C: set_cond(!cond_vc()); %LBRANCH; return; + case 0x7D: set_cond(!cond_pl()); %LBRANCH; return; + case 0x7E: set_cond(!cond_ge()); %LBRANCH; return; + case 0x7F: set_cond(!cond_gt()); %LBRANCH; return; + + case 0x80: set_a(); %CLR8; return; + case 0x81: set_b(); %CLR8; return; + case 0x82: %INDEXED; %CLR8; return; + case 0x83: set_a(); %COM8; return; + case 0x84: set_b(); %COM8; return; + case 0x85: %INDEXED; %COM8; return; + case 0x86: set_a(); %NEG8; return; + case 0x87: set_b(); %NEG8; return; + case 0x88: %INDEXED; %NEG8; return; + case 0x89: set_a(); %INC8; return; + case 0x8A: set_b(); %INC8; return; + case 0x8B: %INDEXED; %INC8; return; + case 0x8C: set_a(); %DEC8; return; + case 0x8D: set_b(); %DEC8; return; + case 0x8E: %INDEXED; %DEC8; return; + case 0x8F: %RTS; return; + + case 0x90: set_a(); %TST8; return; + case 0x91: set_b(); %TST8; return; + case 0x92: %INDEXED; %TST8; return; + case 0x93: set_a(); %LSR8; return; + case 0x94: set_b(); %LSR8; return; + case 0x95: %INDEXED; %LSR8; return; + case 0x96: set_a(); %ROR8; return; + case 0x97: set_b(); %ROR8; return; + case 0x98: %INDEXED; %ROR8; return; + case 0x99: set_a(); %ASR8; return; + case 0x9A: set_b(); %ASR8; return; + case 0x9B: %INDEXED; %ASR8; return; + case 0x9C: set_a(); %ASL8; return; + case 0x9D: set_b(); %ASL8; return; + case 0x9E: %INDEXED; %ASL8; return; + case 0x9F: %RTI; return; + + case 0xA0: set_a(); %ROL8; return; + case 0xA1: set_b(); %ROL8; return; + case 0xA2: %INDEXED; %ROL8; return; + case 0xA3: %INDEXED; %LSR16; return; + case 0xA4: %INDEXED; %ROR16; return; + case 0xA5: %INDEXED; %ASR16; return; + case 0xA6: %INDEXED; %ASL16; return; + case 0xA7: %INDEXED; %ROL16; return; + case 0xA8: %INDEXED; %JMP; return; + case 0xA9: %INDEXED; %JSR; return; + case 0xAA: %BSR; return; + case 0xAB: %LBSR; return; + case 0xAC: %DECBJNZ; return; + case 0xAD: %DECXJNZ; return; + case 0xAE: %NOP; return; + + case 0xB0: %ABX; return; + case 0xB1: %DAA; return; + case 0xB2: %SEX; return; + case 0xB3: %MUL; return; + case 0xB4: %LMUL; return; + case 0xB5: %DIVX; return; + case 0xB6: %BMOVE; return; + case 0xB7: %MOVE; return; + case 0xB8: set_imm(); %LSRD; return; + case 0xB9: %INDEXED; %LSRD; return; + case 0xBA: set_imm(); %RORD; return; + case 0xBB: %INDEXED; %RORD; return; + case 0xBC: set_imm(); %ASRD; return; + case 0xBD: %INDEXED; %ASRD; return; + case 0xBE: set_imm(); %ASLD; return; + case 0xBF: %INDEXED; %ASLD; return; + + case 0xC0: set_imm(); %ROLD; return; + case 0xC1: %INDEXED; %ROLD; return; + case 0xC2: set_d(); %CLR16; return; + case 0xC3: %INDEXED; %CLR16; return; + case 0xC4: set_d(); %NEG16; return; + case 0xC5: %INDEXED; %NEG16; return; + case 0xC6: set_d(); %INC16; return; + case 0xC7: %INDEXED; %INC16; return; + case 0xC8: set_d(); %DEC16; return; + case 0xC9: %INDEXED; %DEC16; return; + case 0xCA: set_d(); %TST16; return; + case 0xCB: %INDEXED; %TST16; return; + case 0xCC: set_a(); %ABS8; return; + case 0xCD: set_b(); %ABS8; return; + case 0xCE: set_d(); %ABS16; return; + case 0xCF: %BSET; return; + + case 0xD0: %BSET2; return; + default: %ILLEGAL; return; + } + return; + +#include "base6x09.ops" + +PUSH_REGISTERS: + if (m_temp.w & 0x80) + { + @write_memory(--regop16().w, m_pc.b.l); + @write_memory(--regop16().w, m_pc.b.h); + nop(); + } + if (m_temp.w & 0x40) + { + @write_memory(--regop16().w, (®op16() == &m_s) ? m_u.b.l : m_s.b.l); + @write_memory(--regop16().w, (®op16() == &m_s) ? m_u.b.h : m_s.b.h); + nop(); + } + if (m_temp.w & 0x20) + { + @write_memory(--regop16().w, m_y.b.l); + @write_memory(--regop16().w, m_y.b.h); + nop(); + } + if (m_temp.w & 0x10) + { + @write_memory(--regop16().w, m_x.b.l); + @write_memory(--regop16().w, m_x.b.h); + nop(); + } + if (m_temp.w & 0x08) + { + @write_memory(--regop16().w, m_dp); + nop(); + } + if (m_temp.w & 0x04) + { + @write_memory(--regop16().w, m_d.b.l); + nop(); + } + if (m_temp.w & 0x02) + { + @write_memory(--regop16().w, m_d.b.h); + nop(); + } + if (m_temp.w & 0x01) + { + @write_memory(--regop16().w, m_cc); + nop(); + } + return; + +PULL_REGISTERS: + if (m_temp.w & 0x01) + { + @m_cc = read_memory(regop16().w++); + nop(); + } + if (m_temp.w & 0x02) + { + @m_d.b.h = read_memory(regop16().w++); + nop(); + } + if (m_temp.w & 0x04) + { + @m_d.b.l = read_memory(regop16().w++); + nop(); + } + if (m_temp.w & 0x08) + { + @m_dp = read_memory(regop16().w++); + nop(); + } + if (m_temp.w & 0x10) + { + @m_x.b.h = read_memory(regop16().w++); + @m_x.b.l = read_memory(regop16().w++); + nop(); + } + if (m_temp.w & 0x20) + { + @m_y.b.h = read_memory(regop16().w++); + @m_y.b.l = read_memory(regop16().w++); + nop(); + } + if (m_temp.w & 0x40) + { + @(®op16() == &m_s ? m_u : m_s).b.h = read_memory(regop16().w++); + @(®op16() == &m_s ? m_u : m_s).b.l = read_memory(regop16().w++); + nop(); + } + if (m_temp.w & 0x80) + { + @m_pc.b.h = read_memory(regop16().w++); + @m_pc.b.l = read_memory(regop16().w++); + nop(); + } + @eat(1); + return; + +INDEXED: + @m_opcode = read_opcode_arg(); + switch(m_opcode & 0xF7) + { + case 0x07: + // extended addressing mode + @m_temp.b.h = read_opcode_arg(); + @m_temp.b.l = read_opcode_arg(); + break; + + case 0x20: case 0x30: case 0x50: case 0x60: case 0x70: + // auto increment + m_temp.w = ireg(); + ireg()++; + eat(2); + break; + + case 0x21: case 0x31: case 0x51: case 0x61: case 0x71: + // double auto increment + m_temp.w = ireg(); + ireg() += 2; + eat(3); + break; + + case 0x22: case 0x32: case 0x52: case 0x62: case 0x72: + // auto decrement + ireg()--; + m_temp.w = ireg(); + eat(2); + break; + + case 0x23: case 0x33: case 0x53: case 0x63: case 0x73: + // double auto decrement + ireg() -= 2; + m_temp.w = ireg(); + eat(3); + break; + + case 0x24: case 0x34: case 0x54: case 0x64: case 0x74: + // postbyte offset + m_ea.w = ireg(); // need to do this now because ireg() might be PC + @m_temp.b.l = read_opcode_arg(); + m_temp.w = m_ea.w + (INT8) m_temp.b.l; + eat(1); + break; + + case 0x25: case 0x35: case 0x55: case 0x65: case 0x75: + // postword offset + m_ea.w = ireg(); // need to do this now because ireg() might be PC + @m_temp.b.h = read_opcode_arg(); + @m_temp.b.l = read_opcode_arg(); + m_temp.w = m_ea.w + (INT16) m_temp.w; + eat(2); + break; + + case 0x26: case 0x36: case 0x56: case 0x66: case 0x76: + m_temp.w = ireg(); + break; + + case 0xC4: + // direct addressing mode + m_temp.b.h = m_dp; + @m_temp.b.l = read_opcode_arg(); + break; + + case 0xA0: case 0xB0: case 0xD0: case 0xE0: case 0xF0: + // relative to register A + m_temp.w = ireg() + (INT8) m_d.b.h; + @eat(1); + break; + + case 0xA1: case 0xB1: case 0xD1: case 0xE1: case 0xF1: + // relative to register B + m_temp.w = ireg() + (INT8) m_d.b.l; + @eat(1); + break; + + case 0xA7: case 0xB7: case 0xD7: case 0xE7: case 0xF7: + // relative to register D + m_temp.w = ireg() + (INT16) m_d.w; + @eat(4); + break; + + default: + logerror("KONAMI: Unknown/Invalid postbyte at PC = %04x\n", m_pc.w - 1); + m_temp.w = 0; + break; + } + + if (m_opcode & 0x08) + { + // indirect mode + set_ea(m_temp.w); + @m_temp.b.h = read_operand(0); + @m_temp.b.l = read_operand(1); + nop(); + } + + set_ea(m_temp.w); + return; + +EXG: + { + // konami's EXG instruction differs enough from 6809 to fork the code + UINT8 param = read_opcode_arg(); + exgtfr_register reg1 = read_exgtfr_register(param >> 0); + exgtfr_register reg2 = read_exgtfr_register(param >> 4); + write_exgtfr_register(param >> 0, reg2); + write_exgtfr_register(param >> 4, reg1); + } + eat(hd6309_native_mode() ? 3 : 6); + return; + +TFR: + { + // konami's TFR instruction differs enough from 6809 to fork the code + UINT8 param = read_opcode_arg(); + exgtfr_register reg = read_exgtfr_register(param >> 0); + write_exgtfr_register(param >> 4, reg); + } + eat(hd6309_native_mode() ? 2 : 4); + return; + +SETLINE: + @set_lines(read_operand()); + return; + +MOVE: + @m_temp.b.l = read_memory(m_y.w++); + @write_memory(m_x.w++, m_temp.b.l); + m_u.w--; + return; + +BMOVE: + // BMOVE does not appear to be interruptable, at least judging from the + // old implementation + while(m_u.w != 0) + { + @m_temp.b.l = read_memory(m_y.w++); + @write_memory(m_x.w++, m_temp.b.l); + m_u.w--; + } + return; + +BSET: + // BSET does not appear to be interruptable, at least judging from the + // old implementation + while(m_u.w != 0) + { + @eat(1); + @write_memory(m_x.w++, m_d.b.h); + m_u.w--; + } + return; + +BSET2: + // BSET2 does not appear to be interruptable, at least judging from the + // old implementation + while(m_u.w != 0) + { + @eat(1); + @write_memory(m_x.w++, m_d.b.h); + @write_memory(m_x.w++, m_d.b.l); + m_u.w--; + } + return; + +DECXJNZ: + // not sure if this affects V? + m_x.w = set_flags(CC_NZV, m_x.w, 1, m_x.w - 1); + @eat(1); + set_cond(cond_ne()); + goto BRANCH; + +DECBJNZ: + // not sure if this affects V? + m_d.b.l = set_flags(CC_NZV, m_d.b.l, 1, m_d.b.l - 1); + @eat(1); + set_cond(cond_ne()); + goto BRANCH; + +LSRD: + @m_temp.b.l = read_operand(); + if (m_temp.b.l != 0x00) + { + // set C condition code + if (m_d.w & safe_shift_left(1, m_temp.b.l)) + m_cc |= CC_C; + else + m_cc &= ~CC_C; + + m_d.w = set_flags(CC_NZ, safe_shift_right_unsigned(m_d.w, m_temp.b.l)); + } + eat(1); + return; + +ASLD: + @m_temp.b.l = read_operand(); + if (m_temp.b.l != 0x00) + { + // set C condition code + if (m_d.w & safe_shift_right(0x10000, m_temp.b.l)) + m_cc |= CC_C; + else + m_cc &= ~CC_C; + + m_d.w = set_flags(CC_NZV, safe_shift_left(m_d.w, m_temp.b.l)); + } + eat(1); + return; + +ASRD: + @m_temp.b.l = read_operand(); + if (m_temp.b.l != 0x00) + { + // set C condition code + if (m_d.w & safe_shift_left(1, m_temp.b.l)) + m_cc |= CC_C; + else + m_cc &= ~CC_C; + + m_d.w = set_flags(CC_NZ, safe_shift_right(m_d.w, m_temp.b.l)); + } + eat(1); + return; + +ROLD: + @m_temp.b.l = read_operand(); + + // doing this as a loop is lame + while(m_temp.b.l--) + m_temp.w = set_flags(CC_NZ, rotate_left(m_temp.w)); + + eat(1); + return; + +RORD: + @m_temp.b.l = read_operand(); + + // doing this as a loop is lame + while(m_temp.b.l--) + m_temp.w = set_flags(CC_NZ, rotate_right(m_temp.w)); + + eat(1); + return; + +ABS8: + @m_temp.b.l = read_operand(); + m_temp.b.l = set_flags(CC_NZVC, 0, m_temp.b.l, ((INT8) m_temp.b.l) >= 0 ? m_temp.b.l : -m_temp.b.l); + @eat(1); + write_operand(m_temp.b.l); + return; + +ABS16: + @m_temp.b.h = read_operand(0); + @m_temp.b.l = read_operand(1); + m_temp.w = set_flags(CC_NZVC, 0, m_temp.w, ((INT16) m_temp.w) >= 0 ? m_temp.w : -m_temp.w); + @eat(1); + @write_operand(0, m_temp.b.h); + write_operand(1, m_temp.b.l); + return; + +LMUL: + lmul(); + eat(21); + return; + +DIVX: + divx(); + eat(10); + return; + +ILLEGAL: + log_illegal(); + return; diff --git a/src/devices/cpu/m6809/m6809.c b/src/devices/cpu/m6809/m6809.c new file mode 100644 index 00000000000..d69b0417453 --- /dev/null +++ b/src/devices/cpu/m6809/m6809.c @@ -0,0 +1,608 @@ +// license:BSD-3-Clause +// copyright-holders:Nathan Woods +/*** m6809: Portable 6809 emulator ****************************************** + + Copyright John Butler + + References: + + 6809 Simulator V09, By L.C. Benschop, Eindhoven The Netherlands. + + m6809: Portable 6809 emulator, DS (6809 code in MAME, derived from + the 6809 Simulator V09) + + 6809 Microcomputer Programming & Interfacing with Experiments" + by Andrew C. Staugaard, Jr.; Howard W. Sams & Co., Inc. + + System dependencies: UINT16 must be 16 bit unsigned int + UINT8 must be 8 bit unsigned int + UINT32 must be more than 16 bits + arrays up to 65536 bytes must be supported + machine must be twos complement + + History: + +March 2013 NPW: + Rewrite of 6809/6309/Konami CPU; attempted to make cycle exact. + +991026 HJB: + Fixed missing calls to cpu_changepc() for the TFR and EXG ocpodes. + Replaced m6809_slapstic checks by a macro (CHANGE_PC). ESB still + needs the tweaks. + +991024 HJB: + Tried to improve speed: Using bit7 of cycles1/2 as flag for multi + byte opcodes is gone, those opcodes now call fetch_effective_address(). + Got rid of the slow/fast flags for stack (S and U) memory accesses. + Minor changes to use 32 bit values as arguments to memory functions + and added defines for that purpose (e.g. X = 16bit XD = 32bit). + +990312 HJB: + Added bugfixes according to Aaron's findings. + Reset only sets CC_II and CC_IF, DP to zero and PC from reset vector. +990311 HJB: + Added _info functions. Now uses static m6808_Regs struct instead + of single statics. Changed the 16 bit registers to use the generic + PAIR union. Registers defined using macros. Split the core into + four execution loops for M6802, M6803, M6808 and HD63701. + TST, TSTA and TSTB opcodes reset carry flag. + Modified the read/write stack handlers to push LSB first then MSB + and pull MSB first then LSB. + +990228 HJB: + Changed the interrupt handling again. Now interrupts are taken + either right at the moment the lines are asserted or whenever + an interrupt is enabled and the corresponding line is still + asserted. That way the pending_interrupts checks are not + needed anymore. However, the CWAI and SYNC flags still need + some flags, so I changed the name to 'int_state'. + This core also has the code for the old interrupt system removed. + +990225 HJB: + Cleaned up the code here and there, added some comments. + Slightly changed the SAR opcodes (similiar to other CPU cores). + Added symbolic names for the flag bits. + Changed the way CWAI/Interrupt() handle CPU state saving. + A new flag M6809_STATE in pending_interrupts is used to determine + if a state save is needed on interrupt entry or already done by CWAI. + Added M6809_IRQ_LINE and M6809_FIRQ_LINE defines to m6809.h + Moved the internal interrupt_pending flags from m6809.h to m6809.c + Changed CWAI cycles2[0x3c] to be 2 (plus all or at least 19 if + CWAI actually pushes the entire state). + Implemented undocumented TFR/EXG for undefined source and mixed 8/16 + bit transfers (they should transfer/exchange the constant $ff). + Removed unused jmp/jsr _slap functions from 6809ops.c, + m6809_slapstick check moved into the opcode functions. + +*****************************************************************************/ + +#include "emu.h" +#include "debugger.h" +#include "m6809.h" +#include "m6809inl.h" + + +//************************************************************************** +// PARAMETERS +//************************************************************************** + +#define LOG_INTERRUPTS 0 + +// turn off 'unreferenced label' errors +// this pragma doesn't work on older GCCs, so cut off at 4.2 +#if defined(__GNUC__) && __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 2) +#pragma GCC diagnostic ignored "-Wunused-label" +#endif +#ifdef _MSC_VER +#pragma warning( disable : 4102 ) +#endif + +//************************************************************************** +// DEVICE INTERFACE +//************************************************************************** + +const device_type M6809 = &device_creator; +const device_type M6809E = &device_creator; + + +//------------------------------------------------- +// m6809_base_device - constructor +//------------------------------------------------- + +m6809_base_device::m6809_base_device(const machine_config &mconfig, const char *name, const char *tag, device_t *owner, UINT32 clock, const device_type type, int divider, const char *shortname, const char *source) + : cpu_device(mconfig, type, name, tag, owner, clock, shortname, source), + m_lic_func(*this), + m_program_config("program", ENDIANNESS_BIG, 8, 16), + m_sprogram_config("decrypted_opcodes", ENDIANNESS_BIG, 8, 16), + m_clock_divider(divider) +{ + m_mintf = NULL; +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void m6809_base_device::device_start() +{ + if (!m_mintf) + m_mintf = new mi_default; + + m_mintf->m_program = &space(AS_PROGRAM); + m_mintf->m_sprogram = has_space(AS_DECRYPTED_OPCODES) ? &space(AS_DECRYPTED_OPCODES) : m_mintf->m_program; + + m_mintf->m_direct = &m_mintf->m_program->direct(); + m_mintf->m_sdirect = &m_mintf->m_sprogram->direct(); + + m_lic_func.resolve_safe(); + + // register our state for the debugger + state_add(STATE_GENPC, "GENPC", m_pc.w).noshow(); + state_add(STATE_GENPCBASE, "GENPCBASE", m_ppc.w).noshow(); + state_add(STATE_GENFLAGS, "GENFLAGS", m_cc).callimport().callexport().formatstr("%8s").noshow(); + state_add(M6809_PC, "PC", m_pc.w).mask(0xffff); + state_add(M6809_S, "S", m_s.w).mask(0xffff); + state_add(M6809_CC, "CC", m_cc).mask(0xff); + state_add(M6809_U, "U", m_u.w).mask(0xffff); + state_add(M6809_A, "A", m_d.b.h).mask(0xff); + state_add(M6809_B, "B", m_d.b.l).mask(0xff); + state_add(M6809_X, "X", m_x.w).mask(0xffff); + state_add(M6809_Y, "Y", m_y.w).mask(0xffff); + state_add(M6809_DP, "DP", m_dp).mask(0xff); + + // initialize variables + m_cc = 0; + m_pc.w = 0; + m_s.w = 0; + m_u.w = 0; + m_d.w = 0; + m_x.w = 0; + m_y.w = 0; + m_dp = 0; + m_reg = 0; + m_reg8 = NULL; + m_reg16 = NULL; + + // setup regtable + save_item(NAME(m_pc.w)); + save_item(NAME(m_ppc.w)); + save_item(NAME(m_d.w)); + save_item(NAME(m_dp)); + save_item(NAME(m_u.w)); + save_item(NAME(m_s.w)); + save_item(NAME(m_x.w)); + save_item(NAME(m_y.w)); + save_item(NAME(m_cc)); + save_item(NAME(m_temp.w)); + save_item(NAME(m_opcode)); + save_item(NAME(m_nmi_asserted)); + save_item(NAME(m_nmi_line)); + save_item(NAME(m_firq_line)); + save_item(NAME(m_irq_line)); + save_item(NAME(m_lds_encountered)); + save_item(NAME(m_state)); + save_item(NAME(m_ea.w)); + save_item(NAME(m_addressing_mode)); + save_item(NAME(m_reg)); + save_item(NAME(m_cond)); + + // set our instruction counter + m_icountptr = &m_icount; + m_icount = 0; +} + + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void m6809_base_device::device_reset() +{ + m_nmi_line = false; + m_nmi_asserted = false; + m_firq_line = false; + m_irq_line = false; + m_lds_encountered = false; + + m_dp = 0x00; // reset direct page register + + m_cc |= CC_I; // IRQ disabled + m_cc |= CC_F; // FIRQ disabled + + m_pc.b.h = m_addrspace[AS_PROGRAM]->read_byte(VECTOR_RESET_FFFE + 0); + m_pc.b.l = m_addrspace[AS_PROGRAM]->read_byte(VECTOR_RESET_FFFE + 1); + + // reset sub-instruction state + reset_state(); +} + + + +//------------------------------------------------- +// device_pre_save - device-specific pre-save +//------------------------------------------------- + +void m6809_base_device::device_pre_save() +{ + if (m_reg8 == &m_d.b.h) + m_reg = M6809_A; + else if (m_reg8 == &m_d.b.l) + m_reg = M6809_B; + else if (m_reg16 == &m_d) + m_reg = M6809_D; + else if (m_reg16 == &m_x) + m_reg = M6809_X; + else if (m_reg16 == &m_y) + m_reg = M6809_Y; + else if (m_reg16 == &m_u) + m_reg = M6809_U; + else if (m_reg16 == &m_s) + m_reg = M6809_S; + else + m_reg = 0; +} + + +//------------------------------------------------- +// device_post_load - device-specific post-load +//------------------------------------------------- + +void m6809_base_device::device_post_load() +{ + m_reg8 = NULL; + m_reg16 = NULL; + + switch(m_reg) + { + case M6809_A: + set_regop8(m_d.b.h); + break; + case M6809_B: + set_regop8(m_d.b.l); + break; + case M6809_D: + set_regop16(m_d); + break; + case M6809_X: + set_regop16(m_x); + break; + case M6809_Y: + set_regop16(m_y); + break; + case M6809_U: + set_regop16(m_u); + break; + case M6809_S: + set_regop16(m_s); + break; + } +} + + +//------------------------------------------------- +// memory_space_config - return the configuration +// of the specified address space, or NULL if +// the space doesn't exist +//------------------------------------------------- + +const address_space_config *m6809_base_device::memory_space_config(address_spacenum spacenum) const +{ + switch(spacenum) + { + case AS_PROGRAM: return &m_program_config; + case AS_DECRYPTED_OPCODES: return has_configured_map(AS_DECRYPTED_OPCODES) ? &m_sprogram_config : NULL; + default: return NULL; + } +} + + +//------------------------------------------------- +// state_string_export - export state as a string +// for the debugger +//------------------------------------------------- + +void m6809_base_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + switch (entry.index()) + { + case STATE_GENFLAGS: + strprintf(str, "%c%c%c%c%c%c%c%c", + (m_cc & 0x80) ? 'E' : '.', + (m_cc & 0x40) ? 'F' : '.', + (m_cc & 0x20) ? 'H' : '.', + (m_cc & 0x10) ? 'I' : '.', + (m_cc & 0x08) ? 'N' : '.', + (m_cc & 0x04) ? 'Z' : '.', + (m_cc & 0x02) ? 'V' : '.', + (m_cc & 0x01) ? 'C' : '.'); + break; + } +} + + +//------------------------------------------------- +// disasm_min_opcode_bytes - return the length +// of the shortest instruction, in bytes +//------------------------------------------------- + +UINT32 m6809_base_device::disasm_min_opcode_bytes() const +{ + return 1; +} + + +//------------------------------------------------- +// disasm_max_opcode_bytes - return the length +// of the longest instruction, in bytes +//------------------------------------------------- + +UINT32 m6809_base_device::disasm_max_opcode_bytes() const +{ + return 5; +} + + +//------------------------------------------------- +// disasm_disassemble - call the disassembly +// helper function +//------------------------------------------------- + +offs_t m6809_base_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( m6809 ); + return CPU_DISASSEMBLE_NAME(m6809)(this, buffer, pc, oprom, opram, options); +} + + +//************************************************************************** +// CORE EXECUTION LOOP +//************************************************************************** + +//------------------------------------------------- +// execute_clocks_to_cycles - convert the raw +// clock into cycles per second +//------------------------------------------------- + +UINT64 m6809_base_device::execute_clocks_to_cycles(UINT64 clocks) const +{ + return (clocks + m_clock_divider - 1) / m_clock_divider; +} + + +//------------------------------------------------- +// execute_cycles_to_clocks - convert a cycle +// count back to raw clocks +//------------------------------------------------- + +UINT64 m6809_base_device::execute_cycles_to_clocks(UINT64 cycles) const +{ + return cycles * m_clock_divider; +} + + +//------------------------------------------------- +// execute_min_cycles - return minimum number of +// cycles it takes for one instruction to execute +//------------------------------------------------- + +UINT32 m6809_base_device::execute_min_cycles() const +{ + return 1; +} + + +//------------------------------------------------- +// execute_max_cycles - return maximum number of +// cycles it takes for one instruction to execute +//------------------------------------------------- + +UINT32 m6809_base_device::execute_max_cycles() const +{ + return 19; +} + + +//------------------------------------------------- +// execute_input_lines - return the number of +// input/interrupt lines +//------------------------------------------------- + +UINT32 m6809_base_device::execute_input_lines() const +{ + return 3; +} + + +//------------------------------------------------- +// execute_set_input - act on a changed input/ +// interrupt line +//------------------------------------------------- + +void m6809_base_device::execute_set_input(int inputnum, int state) +{ + if (LOG_INTERRUPTS) + logerror("%s: inputnum=%s state=%d totalcycles=%d\n", machine().describe_context(), inputnum_string(inputnum), state, (int) attotime_to_clocks(machine().time())); + + switch(inputnum) + { + case INPUT_LINE_NMI: + // NMI is edge triggered + m_nmi_asserted = m_nmi_asserted || ((state != CLEAR_LINE) && !m_nmi_line && m_lds_encountered); + m_nmi_line = (state != CLEAR_LINE); + break; + + case M6809_FIRQ_LINE: + // FIRQ is line triggered + m_firq_line = (state != CLEAR_LINE); + break; + + case M6809_IRQ_LINE: + // IRQ is line triggered + m_irq_line = (state != CLEAR_LINE); + break; + } +} + + +//------------------------------------------------- +// inputnum_string +//------------------------------------------------- + +const char *m6809_base_device::inputnum_string(int inputnum) +{ + switch(inputnum) + { + case INPUT_LINE_NMI: return "NMI"; + case M6809_FIRQ_LINE: return "FIRQ"; + case M6809_IRQ_LINE: return "IRQ"; + default: return "???"; + } +} + + +//------------------------------------------------- +// read_exgtfr_register +//------------------------------------------------- + +m6809_base_device::exgtfr_register m6809_base_device::read_exgtfr_register(UINT8 reg) +{ + exgtfr_register result; + result.byte_value = 0xFF; + result.word_value = 0x00FF; + + switch(reg & 0x0F) + { + case 0: result.word_value = m_d.w; break; // D + case 1: result.word_value = m_x.w; break; // X + case 2: result.word_value = m_y.w; break; // Y + case 3: result.word_value = m_u.w; break; // U + case 4: result.word_value = m_s.w; break; // S + case 5: result.word_value = m_pc.w; break; // PC + case 8: result.byte_value = m_d.b.h; break; // A + case 9: result.byte_value = m_d.b.l; break; // B + case 10: result.byte_value = m_cc; break; // CC + case 11: result.byte_value = m_dp; break; // DP + } + return result; +} + + +//------------------------------------------------- +// write_exgtfr_register +//------------------------------------------------- + +void m6809_base_device::write_exgtfr_register(UINT8 reg, m6809_base_device::exgtfr_register value) +{ + switch(reg & 0x0F) + { + case 0: m_d.w = value.word_value; break; // D + case 1: m_x.w = value.word_value; break; // X + case 2: m_y.w = value.word_value; break; // Y + case 3: m_u.w = value.word_value; break; // U + case 4: m_s.w = value.word_value; break; // S + case 5: m_pc.w = value.word_value; break; // PC + case 8: m_d.b.h = value.byte_value; break; // A + case 9: m_d.b.l = value.byte_value; break; // B + case 10: m_cc = value.byte_value; break; // CC + case 11: m_dp = value.byte_value; break; // DP + } +} + + +//------------------------------------------------- +// log_illegal - used to log hits to illegal +// instructions (except for HD6309 which traps) +//------------------------------------------------- + +void m6809_base_device::log_illegal() +{ + logerror("%s: illegal opcode at %04x\n", machine().describe_context(), (unsigned) m_pc.w); +} + + +//------------------------------------------------- +// execute_one - try to execute a single instruction +//------------------------------------------------- + +void m6809_base_device::execute_one() +{ + switch(pop_state()) + { +#include "cpu/m6809/m6809.inc" + } +} + + +//------------------------------------------------- +// execute_run - execute a timeslice's worth of +// opcodes +//------------------------------------------------- + +void m6809_base_device::execute_run() +{ + do + { + execute_one(); + } while(m_icount > 0); +} + + +UINT8 m6809_base_device::mi_default::read(UINT16 adr) +{ + return m_program->read_byte(adr); +} + +UINT8 m6809_base_device::mi_default::read_opcode(UINT16 adr) +{ + return m_sdirect->read_byte(adr); +} + +UINT8 m6809_base_device::mi_default::read_opcode_arg(UINT16 adr) +{ + return m_direct->read_byte(adr); +} + + +void m6809_base_device::mi_default::write(UINT16 adr, UINT8 val) +{ + m_program->write_byte(adr, val); +} + + + +//------------------------------------------------- +// m6809_device +//------------------------------------------------- + +m6809_device::m6809_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : m6809_base_device(mconfig, "M6809", tag, owner, clock, M6809, 1, "m6809", __FILE__) +{ +} + + + +//------------------------------------------------- +// m6809e_device +//------------------------------------------------- + +m6809e_device::m6809e_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : m6809_base_device(mconfig, "M6809E", tag, owner, clock, M6809E, 4, "m6809e", __FILE__) +{ +} + +WRITE_LINE_MEMBER( m6809_base_device::irq_line ) +{ + set_input_line( M6809_IRQ_LINE, state ); +} + +WRITE_LINE_MEMBER( m6809_base_device::firq_line ) +{ + set_input_line( M6809_FIRQ_LINE, state ); +} + +WRITE_LINE_MEMBER( m6809_base_device::nmi_line ) +{ + set_input_line( INPUT_LINE_NMI, state ); +} diff --git a/src/devices/cpu/m6809/m6809.h b/src/devices/cpu/m6809/m6809.h new file mode 100644 index 00000000000..595585cd098 --- /dev/null +++ b/src/devices/cpu/m6809/m6809.h @@ -0,0 +1,318 @@ +// license:BSD-3-Clause +// copyright-holders:Nathan Woods +/********************************************************************* + + m6809.h + + Portable Motorola 6809 emulator + +**********************************************************************/ + +#pragma once + +#ifndef __M6809_H__ +#define __M6809_H__ + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class m6809_device; + + +// device type definition +extern const device_type M6809; +extern const device_type M6809E; + +// ======================> m6809_base_device + +// Used by core CPU interface +class m6809_base_device : public cpu_device +{ +public: + // construction/destruction + m6809_base_device(const machine_config &mconfig, const char *name, const char *tag, device_t *owner, UINT32 clock, const device_type type, int divider, const char *shortname, const char *source); + + DECLARE_WRITE_LINE_MEMBER( irq_line ); + DECLARE_WRITE_LINE_MEMBER( firq_line ); + DECLARE_WRITE_LINE_MEMBER( nmi_line ); + +protected: + class memory_interface { + public: + address_space *m_program, *m_sprogram; + direct_read_data *m_direct, *m_sdirect; + + virtual ~memory_interface() {} + virtual UINT8 read(UINT16 adr) = 0; + virtual UINT8 read_opcode(UINT16 adr) = 0; + virtual UINT8 read_opcode_arg(UINT16 adr) = 0; + virtual void write(UINT16 adr, UINT8 val) = 0; + }; + + class mi_default : public memory_interface { + public: + virtual ~mi_default() {} + virtual UINT8 read(UINT16 adr); + virtual UINT8 read_opcode(UINT16 adr); + virtual UINT8 read_opcode_arg(UINT16 adr); + virtual void write(UINT16 adr, UINT8 val); + }; + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_pre_save(); + virtual void device_post_load(); + + // device_execute_interface overrides + virtual UINT32 execute_min_cycles() const; + virtual UINT32 execute_max_cycles() const; + virtual UINT32 execute_input_lines() const; + virtual void execute_run(); + virtual void execute_set_input(int inputnum, int state); + virtual UINT64 execute_clocks_to_cycles(UINT64 clocks) const; + virtual UINT64 execute_cycles_to_clocks(UINT64 cycles) const; + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const; + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const; + virtual UINT32 disasm_max_opcode_bytes() const; + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + + // device_state_interface overrides + virtual void state_string_export(const device_state_entry &entry, std::string &str); + + // addressing modes + enum + { + ADDRESSING_MODE_IMMEDIATE = 0, + ADDRESSING_MODE_EA = 1, + ADDRESSING_MODE_REGISTER_A = 2, + ADDRESSING_MODE_REGISTER_B = 3, + ADDRESSING_MODE_REGISTER_D = 4 + }; + + // register transfer + struct exgtfr_register + { + UINT8 byte_value; + UINT16 word_value; + }; + + // flag bits in the cc register + enum + { + CC_C = 0x01, // Carry + CC_V = 0x02, // Overflow + CC_Z = 0x04, // Zero + CC_N = 0x08, // Negative + CC_I = 0x10, // Inhibit IRQ + CC_H = 0x20, // Half (auxiliary) carry + CC_F = 0x40, // Inhibit FIRQ + CC_E = 0x80 // Entire state pushed + }; + + // flag combinations + enum + { + CC_VC = CC_V | CC_C, + CC_ZC = CC_Z | CC_C, + CC_NZ = CC_N | CC_Z, + CC_NZC = CC_N | CC_Z | CC_C, + CC_NZV = CC_N | CC_Z | CC_V, + CC_NZVC = CC_N | CC_Z | CC_V | CC_C, + CC_HNZVC = CC_H | CC_N | CC_Z | CC_V | CC_C + }; + + // interrupt vectors + enum + { + VECTOR_SWI3 = 0xFFF2, + VECTOR_SWI2 = 0xFFF4, + VECTOR_FIRQ = 0xFFF6, + VECTOR_IRQ = 0xFFF8, + VECTOR_SWI = 0xFFFA, + VECTOR_NMI = 0xFFFC, + VECTOR_RESET_FFFE = 0xFFFE + }; + + // Memory interface + memory_interface * m_mintf; + + // CPU registers + PAIR16 m_pc; // program counter + PAIR16 m_ppc; // previous program counter + PAIR16 m_d; // accumulator a and b + PAIR16 m_x, m_y; // index registers + PAIR16 m_u, m_s; // stack pointers + UINT8 m_dp; // direct page register + UINT8 m_cc; + PAIR16 m_temp; + UINT8 m_opcode; + + // other internal state + UINT8 * m_reg8; + PAIR16 * m_reg16; + int m_reg; + bool m_nmi_line; + bool m_nmi_asserted; + bool m_firq_line; + bool m_irq_line; + bool m_lds_encountered; + int m_icount; + int m_addressing_mode; + PAIR16 m_ea; // effective address + + // Callbacks + devcb_write_line m_lic_func; // LIC pin on the 6809E + + // eat cycles + inline void eat(int cycles) { m_icount -= cycles; } + void eat_remaining(); + + // read a byte from given memory location + inline UINT8 read_memory(UINT16 address) { eat(1); return m_mintf->read(address); } + + // write a byte to given memory location + inline void write_memory(UINT16 address, UINT8 data) { eat(1); m_mintf->write(address, data); } + + // read_opcode() is like read_memory() except it is used for reading opcodes. In the case of a system + // with memory mapped I/O, this function can be used to greatly speed up emulation. + inline UINT8 read_opcode(UINT16 address) { eat(1); return m_mintf->read_opcode(address); } + + // read_opcode_arg() is identical to read_opcode() except it is used for reading opcode arguments. This + // difference can be used to support systems that use different encoding mechanisms for opcodes + // and opcode arguments. + inline UINT8 read_opcode_arg(UINT16 address) { eat(1); return m_mintf->read_opcode_arg(address); } + + // read_opcode() and bump the program counter + inline UINT8 read_opcode() { return read_opcode(m_pc.w++); } + inline UINT8 read_opcode_arg() { return read_opcode_arg(m_pc.w++); } + + // state stack - implemented as a UINT32 + void push_state(UINT8 state) { m_state = (m_state << 8) | state; } + UINT8 pop_state() { UINT8 result = (UINT8) m_state; m_state >>= 8; return result; } + void reset_state() { m_state = 0; } + + // effective address reading/writing + UINT8 read_ea() { return read_memory(m_ea.w); } + void write_ea(UINT8 data) { write_memory(m_ea.w, data); } + void set_ea(UINT16 ea) { m_ea.w = ea; m_addressing_mode = ADDRESSING_MODE_EA; } + void set_ea_h(UINT8 ea_h) { m_ea.b.h = ea_h; } + void set_ea_l(UINT8 ea_l) { m_ea.b.l = ea_l; m_addressing_mode = ADDRESSING_MODE_EA; } + + // operand reading/writing + UINT8 read_operand(); + UINT8 read_operand(int ordinal); + void write_operand(UINT8 data); + void write_operand(int ordinal, UINT8 data); + + // instructions + void daa(); + void mul(); + + // miscellaneous + void nop() { } + template T rotate_right(T value); + template UINT32 rotate_left(T value); + void set_a() { m_addressing_mode = ADDRESSING_MODE_REGISTER_A; } + void set_b() { m_addressing_mode = ADDRESSING_MODE_REGISTER_B; } + void set_d() { m_addressing_mode = ADDRESSING_MODE_REGISTER_D; } + void set_imm() { m_addressing_mode = ADDRESSING_MODE_IMMEDIATE; } + void set_regop8(UINT8 ®) { m_reg8 = ® m_reg16 = NULL; } + void set_regop16(PAIR16 ®) { m_reg16 = ® m_reg8 = NULL; } + UINT8 ®op8() { assert(m_reg8 != NULL); return *m_reg8; } + PAIR16 ®op16() { assert(m_reg16 != NULL); return *m_reg16; } + bool is_register_register_op_16_bit() { return m_reg16 != NULL; } + bool add8_sets_h() { return true; } + bool hd6309_native_mode() { return false; } + + // index reg + UINT16 &ireg(); + + // flags + template T set_flags(UINT8 mask, T a, T b, UINT32 r); + template T set_flags(UINT8 mask, T r); + + // branch conditions + inline bool cond_hi() { return !(m_cc & CC_ZC); } // BHI/BLS + inline bool cond_cc() { return !(m_cc & CC_C); } // BCC/BCS + inline bool cond_ne() { return !(m_cc & CC_Z); } // BNE/BEQ + inline bool cond_vc() { return !(m_cc & CC_V); } // BVC/BVS + inline bool cond_pl() { return !(m_cc & CC_N); } // BPL/BMI + inline bool cond_ge() { return (m_cc & CC_N ? true : false) == (m_cc & CC_V ? true : false); } // BGE/BLT + inline bool cond_gt() { return cond_ge() && !(m_cc & CC_Z); } // BGT/BLE + inline void set_cond(bool cond) { m_cond = cond; } + inline bool branch_taken() { return m_cond; } + + // interrupt registers + bool firq_saves_entire_state() { return false; } + UINT16 partial_state_registers() { return 0x81; } + UINT16 entire_state_registers() { return 0xFF; } + + // miscellaneous + inline exgtfr_register read_exgtfr_register(UINT8 reg); + inline void write_exgtfr_register(UINT8 reg, exgtfr_register value); + bool is_register_addressing_mode(); + bool is_ea_addressing_mode() { return m_addressing_mode == ADDRESSING_MODE_EA; } + UINT16 get_pending_interrupt(); + void log_illegal(); + +private: + // address spaces + const address_space_config m_program_config; + const address_space_config m_sprogram_config; + + // other state + UINT32 m_state; + bool m_cond; + + // incidentals + int m_clock_divider; + + // functions + inline void execute_one(); + const char *inputnum_string(int inputnum); +}; + +// ======================> m6809_device + +class m6809_device : public m6809_base_device +{ +public: + // construction/destruction + m6809_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +// ======================> m6809e_device + +#define MCFG_M6809E_LIC_CB(_devcb) \ + m6809e_device::set_lic_cb(*device, DEVCB_##_devcb); + + +class m6809e_device : public m6809_base_device +{ +public: + // construction/destruction + m6809e_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // static configuration helpers + template static devcb_base &set_lic_cb(device_t &device, _Object object) { return downcast(device).m_lic_func.set_callback(object); } +}; + +enum +{ + M6809_PC=1, M6809_S, M6809_CC ,M6809_A, M6809_B, M6809_D, M6809_U, M6809_X, M6809_Y, + M6809_DP +}; + +#define M6809_IRQ_LINE 0 /* IRQ line number */ +#define M6809_FIRQ_LINE 1 /* FIRQ line number */ + +/* M6809e has LIC line to indicate opcode/data fetch */ + +#endif /* __M6809_H__ */ diff --git a/src/devices/cpu/m6809/m6809.ops b/src/devices/cpu/m6809/m6809.ops new file mode 100644 index 00000000000..96b9f6c11a7 --- /dev/null +++ b/src/devices/cpu/m6809/m6809.ops @@ -0,0 +1,581 @@ +MAIN: + // check interrupt lines + switch(get_pending_interrupt()) + { + case VECTOR_NMI: goto NMI; + case VECTOR_FIRQ: goto FIRQ; + case VECTOR_IRQ: goto IRQ; + } + + // debugger hook + m_ppc = m_pc; + debugger_instruction_hook(this, m_pc.w); + + // opcode fetch + m_lic_func(ASSERT_LINE); + @m_opcode = read_opcode(); + m_lic_func(CLEAR_LINE); + + // dispatch opcode + switch(m_opcode) + { + case 0x00: case 0x01: %DIRECT; %NEG8; return; + case 0x03: case 0x02: %DIRECT; %COM8; return; + case 0x04: case 0x05: %DIRECT; %LSR8; return; + case 0x06: %DIRECT; %ROR8; return; + case 0x07: %DIRECT; %ASR8; return; + case 0x08: %DIRECT; %ASL8; return; + case 0x09: %DIRECT; %ROL8; return; + case 0x0A: case 0x0B: %DIRECT; %DEC8; return; + case 0x0C: %DIRECT; %INC8; return; + case 0x0D: %DIRECT; %TST8; return; + case 0x0E: %DIRECT; %JMP; return; + case 0x0F: %DIRECT; %CLR8; return; + + case 0x10: %DISPATCH10; return; + case 0x11: %DISPATCH11; return; + case 0x12: %NOP; return; + case 0x13: %SYNC; return; + case 0x16: set_cond(true); %LBRANCH; return; + case 0x17: %LBSR; return; + case 0x19: %DAA; return; + case 0x1A: set_imm(); %ORCC; return; + case 0x1C: set_imm(); %ANDCC; return; + case 0x1D: %SEX; return; + case 0x1E: %EXG; return; + case 0x1F: %TFR; return; + + case 0x20: set_cond(true); %BRANCH; return; + case 0x21: set_cond(false); %BRANCH; return; + case 0x22: set_cond(cond_hi()); %BRANCH; return; + case 0x23: set_cond(!cond_hi()); %BRANCH; return; + case 0x24: set_cond(cond_cc()); %BRANCH; return; + case 0x25: set_cond(!cond_cc()); %BRANCH; return; + case 0x26: set_cond(cond_ne()); %BRANCH; return; + case 0x27: set_cond(!cond_ne()); %BRANCH; return; + case 0x28: set_cond(cond_vc()); %BRANCH; return; + case 0x29: set_cond(!cond_vc()); %BRANCH; return; + case 0x2A: set_cond(cond_pl()); %BRANCH; return; + case 0x2B: set_cond(!cond_pl()); %BRANCH; return; + case 0x2C: set_cond(cond_ge()); %BRANCH; return; + case 0x2D: set_cond(!cond_ge()); %BRANCH; return; + case 0x2E: set_cond(cond_gt()); %BRANCH; return; + case 0x2F: set_cond(!cond_gt()); %BRANCH; return; + + case 0x30: set_regop16(m_x); %INDEXED; %LEA_xy; return; + case 0x31: set_regop16(m_y); %INDEXED; %LEA_xy; return; + case 0x32: set_regop16(m_s); %INDEXED; %LEA_us; return; + case 0x33: set_regop16(m_u); %INDEXED; %LEA_us; return; + case 0x34: %PSHS; return; + case 0x35: %PULS; return; + case 0x36: %PSHU; return; + case 0x37: %PULU; return; + case 0x39: %RTS; return; + case 0x3A: %ABX; return; + case 0x3B: %RTI; return; + case 0x3C: %CWAI; return; + case 0x3D: %MUL; return; + case 0x3F: %SWI; return; + + case 0x40: case 0x41: set_a(); %NEG8; return; + case 0x43: case 0x42: set_a(); %COM8; return; + case 0x44: case 0x45: set_a(); %LSR8; return; + case 0x46: set_a(); %ROR8; return; + case 0x47: set_a(); %ASR8; return; + case 0x48: set_a(); %ASL8; return; + case 0x49: set_a(); %ROL8; return; + case 0x4A: case 0x4B: set_a(); %DEC8; return; + case 0x4C: set_a(); %INC8; return; + case 0x4D: set_a(); %TST8; return; + case 0x4E: set_a(); %JMP; return; + case 0x4F: set_a(); %CLR8; return; + + case 0x50: case 0x51: set_b(); %NEG8; return; + case 0x53: case 0x52: set_b(); %COM8; return; + case 0x54: case 0x55: set_b(); %LSR8; return; + case 0x56: set_b(); %ROR8; return; + case 0x57: set_b(); %ASR8; return; + case 0x58: set_b(); %ASL8; return; + case 0x59: set_b(); %ROL8; return; + case 0x5A: case 0x5B: set_b(); %DEC8; return; + case 0x5C: set_b(); %INC8; return; + case 0x5D: set_b(); %TST8; return; + case 0x5E: set_b(); %JMP; return; + case 0x5F: set_b(); %CLR8; return; + + case 0x60: case 0x61: %INDEXED; %NEG8; return; + case 0x63: case 0x62: %INDEXED; %COM8; return; + case 0x64: case 0x65: %INDEXED; %LSR8; return; + case 0x66: %INDEXED; %ROR8; return; + case 0x67: %INDEXED; %ASR8; return; + case 0x68: %INDEXED; %ASL8; return; + case 0x69: %INDEXED; %ROL8; return; + case 0x6A: case 0x6B: %INDEXED; %DEC8; return; + case 0x6C: %INDEXED; %INC8; return; + case 0x6D: %INDEXED; %TST8; return; + case 0x6E: %INDEXED; %JMP; return; + case 0x6F: %INDEXED; %CLR8; return; + + case 0x70: case 0x71: %EXTENDED; %NEG8; return; + case 0x73: case 0x72: %EXTENDED; %COM8; return; + case 0x74: case 0x75: %EXTENDED; %LSR8; return; + case 0x76: %EXTENDED; %ROR8; return; + case 0x77: %EXTENDED; %ASR8; return; + case 0x78: %EXTENDED; %ASL8; return; + case 0x79: %EXTENDED; %ROL8; return; + case 0x7A: case 0x7B: %EXTENDED; %DEC8; return; + case 0x7C: %EXTENDED; %INC8; return; + case 0x7D: %EXTENDED; %TST8; return; + case 0x7E: %EXTENDED; %JMP; return; + case 0x7F: %EXTENDED; %CLR8; return; + + case 0x80: set_regop8(m_d.b.h); set_imm(); %SUB8; return; + case 0x81: set_regop8(m_d.b.h); set_imm(); %CMP8; return; + case 0x82: set_regop8(m_d.b.h); set_imm(); %SBC8; return; + case 0x83: set_regop16(m_d); set_imm(); %SUB16; return; + case 0x84: set_regop8(m_d.b.h); set_imm(); %AND8; return; + case 0x85: set_regop8(m_d.b.h); set_imm(); %BIT8; return; + case 0x86: set_regop8(m_d.b.h); set_imm(); %LD8; return; + case 0x87: set_regop8(m_d.b.h); set_imm(); %ST8; return; + case 0x88: set_regop8(m_d.b.h); set_imm(); %EOR8; return; + case 0x89: set_regop8(m_d.b.h); set_imm(); %ADC8; return; + case 0x8A: set_regop8(m_d.b.h); set_imm(); %OR8; return; + case 0x8B: set_regop8(m_d.b.h); set_imm(); %ADD8; return; + case 0x8C: set_regop16(m_x); set_imm(); %CMP16; return; + case 0x8D: %BSR; return; + case 0x8E: set_regop16(m_x); set_imm(); %LD16; return; + case 0x8F: set_regop16(m_x); set_imm(); %ST16; return; + + case 0x90: set_regop8(m_d.b.h); %DIRECT; %SUB8; return; + case 0x91: set_regop8(m_d.b.h); %DIRECT; %CMP8; return; + case 0x92: set_regop8(m_d.b.h); %DIRECT; %SBC8; return; + case 0x93: set_regop16(m_d); %DIRECT; %SUB16; return; + case 0x94: set_regop8(m_d.b.h); %DIRECT; %AND8; return; + case 0x95: set_regop8(m_d.b.h); %DIRECT; %BIT8; return; + case 0x96: set_regop8(m_d.b.h); %DIRECT; %LD8; return; + case 0x97: set_regop8(m_d.b.h); %DIRECT; %ST8; return; + case 0x98: set_regop8(m_d.b.h); %DIRECT; %EOR8; return; + case 0x99: set_regop8(m_d.b.h); %DIRECT; %ADC8; return; + case 0x9A: set_regop8(m_d.b.h); %DIRECT; %OR8; return; + case 0x9B: set_regop8(m_d.b.h); %DIRECT; %ADD8; return; + case 0x9C: set_regop16(m_x); %DIRECT; %CMP16; return; + case 0x9D: %DIRECT; %JSR; return; + case 0x9E: set_regop16(m_x); %DIRECT; %LD16; return; + case 0x9F: set_regop16(m_x); %DIRECT; %ST16; return; + + case 0xA0: set_regop8(m_d.b.h); %INDEXED; %SUB8; return; + case 0xA1: set_regop8(m_d.b.h); %INDEXED; %CMP8; return; + case 0xA2: set_regop8(m_d.b.h); %INDEXED; %SBC8; return; + case 0xA3: set_regop16(m_d); %INDEXED; %SUB16; return; + case 0xA4: set_regop8(m_d.b.h); %INDEXED; %AND8; return; + case 0xA5: set_regop8(m_d.b.h); %INDEXED; %BIT8; return; + case 0xA6: set_regop8(m_d.b.h); %INDEXED; %LD8; return; + case 0xA7: set_regop8(m_d.b.h); %INDEXED; %ST8; return; + case 0xA8: set_regop8(m_d.b.h); %INDEXED; %EOR8; return; + case 0xA9: set_regop8(m_d.b.h); %INDEXED; %ADC8; return; + case 0xAA: set_regop8(m_d.b.h); %INDEXED; %OR8; return; + case 0xAB: set_regop8(m_d.b.h); %INDEXED; %ADD8; return; + case 0xAC: set_regop16(m_x); %INDEXED; %CMP16; return; + case 0xAD: %INDEXED; %JSR; return; + case 0xAE: set_regop16(m_x); %INDEXED; %LD16; return; + case 0xAF: set_regop16(m_x); %INDEXED; %ST16; return; + + case 0xB0: set_regop8(m_d.b.h); %EXTENDED; %SUB8; return; + case 0xB1: set_regop8(m_d.b.h); %EXTENDED; %CMP8; return; + case 0xB2: set_regop8(m_d.b.h); %EXTENDED; %SBC8; return; + case 0xB3: set_regop16(m_d); %EXTENDED; %SUB16; return; + case 0xB4: set_regop8(m_d.b.h); %EXTENDED; %AND8; return; + case 0xB5: set_regop8(m_d.b.h); %EXTENDED; %BIT8; return; + case 0xB6: set_regop8(m_d.b.h); %EXTENDED; %LD8; return; + case 0xB7: set_regop8(m_d.b.h); %EXTENDED; %ST8; return; + case 0xB8: set_regop8(m_d.b.h); %EXTENDED; %EOR8; return; + case 0xB9: set_regop8(m_d.b.h); %EXTENDED; %ADC8; return; + case 0xBA: set_regop8(m_d.b.h); %EXTENDED; %OR8; return; + case 0xBB: set_regop8(m_d.b.h); %EXTENDED; %ADD8; return; + case 0xBC: set_regop16(m_x); %EXTENDED; %CMP16; return; + case 0xBD: %EXTENDED; %JSR; return; + case 0xBE: set_regop16(m_x); %EXTENDED; %LD16; return; + case 0xBF: set_regop16(m_x); %EXTENDED; %ST16; return; + + case 0xC0: set_regop8(m_d.b.l); set_imm(); %SUB8; return; + case 0xC1: set_regop8(m_d.b.l); set_imm(); %CMP8; return; + case 0xC2: set_regop8(m_d.b.l); set_imm(); %SBC8; return; + case 0xC3: set_regop16(m_d); set_imm(); %ADD16; return; + case 0xC4: set_regop8(m_d.b.l); set_imm(); %AND8; return; + case 0xC5: set_regop8(m_d.b.l); set_imm(); %BIT8; return; + case 0xC6: set_regop8(m_d.b.l); set_imm(); %LD8; return; + case 0xC7: set_regop8(m_d.b.l); set_imm(); %ST8; return; + case 0xC8: set_regop8(m_d.b.l); set_imm(); %EOR8; return; + case 0xC9: set_regop8(m_d.b.l); set_imm(); %ADC8; return; + case 0xCA: set_regop8(m_d.b.l); set_imm(); %OR8; return; + case 0xCB: set_regop8(m_d.b.l); set_imm(); %ADD8; return; + case 0xCC: set_regop16(m_d); set_imm(); %LD16; return; + case 0xCD: set_regop16(m_d); set_imm(); %ST16; return; + case 0xCE: set_regop16(m_u); set_imm(); %LD16; return; + case 0xCF: set_regop16(m_u); set_imm(); %ST16; return; + + case 0xD0: set_regop8(m_d.b.l); %DIRECT; %SUB8; return; + case 0xD1: set_regop8(m_d.b.l); %DIRECT; %CMP8; return; + case 0xD2: set_regop8(m_d.b.l); %DIRECT; %SBC8; return; + case 0xD3: set_regop16(m_d); %DIRECT; %ADD16; return; + case 0xD4: set_regop8(m_d.b.l); %DIRECT; %AND8; return; + case 0xD5: set_regop8(m_d.b.l); %DIRECT; %BIT8; return; + case 0xD6: set_regop8(m_d.b.l); %DIRECT; %LD8; return; + case 0xD7: set_regop8(m_d.b.l); %DIRECT; %ST8; return; + case 0xD8: set_regop8(m_d.b.l); %DIRECT; %EOR8; return; + case 0xD9: set_regop8(m_d.b.l); %DIRECT; %ADC8; return; + case 0xDA: set_regop8(m_d.b.l); %DIRECT; %OR8; return; + case 0xDB: set_regop8(m_d.b.l); %DIRECT; %ADD8; return; + case 0xDC: set_regop16(m_d); %DIRECT; %LD16; return; + case 0xDD: set_regop16(m_d); %DIRECT; %ST16; return; + case 0xDE: set_regop16(m_u); %DIRECT; %LD16; return; + case 0xDF: set_regop16(m_u); %DIRECT; %ST16; return; + + case 0xE0: set_regop8(m_d.b.l); %INDEXED; %SUB8; return; + case 0xE1: set_regop8(m_d.b.l); %INDEXED; %CMP8; return; + case 0xE2: set_regop8(m_d.b.l); %INDEXED; %SBC8; return; + case 0xE3: set_regop16(m_d); %INDEXED; %ADD16; return; + case 0xE4: set_regop8(m_d.b.l); %INDEXED; %AND8; return; + case 0xE5: set_regop8(m_d.b.l); %INDEXED; %BIT8; return; + case 0xE6: set_regop8(m_d.b.l); %INDEXED; %LD8; return; + case 0xE7: set_regop8(m_d.b.l); %INDEXED; %ST8; return; + case 0xE8: set_regop8(m_d.b.l); %INDEXED; %EOR8; return; + case 0xE9: set_regop8(m_d.b.l); %INDEXED; %ADC8; return; + case 0xEA: set_regop8(m_d.b.l); %INDEXED; %OR8; return; + case 0xEB: set_regop8(m_d.b.l); %INDEXED; %ADD8; return; + case 0xEC: set_regop16(m_d); %INDEXED; %LD16; return; + case 0xED: set_regop16(m_d); %INDEXED; %ST16; return; + case 0xEE: set_regop16(m_u); %INDEXED; %LD16; return; + case 0xEF: set_regop16(m_u); %INDEXED; %ST16; return; + + case 0xF0: set_regop8(m_d.b.l); %EXTENDED; %SUB8; return; + case 0xF1: set_regop8(m_d.b.l); %EXTENDED; %CMP8; return; + case 0xF2: set_regop8(m_d.b.l); %EXTENDED; %SBC8; return; + case 0xF3: set_regop16(m_d); %EXTENDED; %ADD16; return; + case 0xF4: set_regop8(m_d.b.l); %EXTENDED; %AND8; return; + case 0xF5: set_regop8(m_d.b.l); %EXTENDED; %BIT8; return; + case 0xF6: set_regop8(m_d.b.l); %EXTENDED; %LD8; return; + case 0xF7: set_regop8(m_d.b.l); %EXTENDED; %ST8; return; + case 0xF8: set_regop8(m_d.b.l); %EXTENDED; %EOR8; return; + case 0xF9: set_regop8(m_d.b.l); %EXTENDED; %ADC8; return; + case 0xFA: set_regop8(m_d.b.l); %EXTENDED; %OR8; return; + case 0xFB: set_regop8(m_d.b.l); %EXTENDED; %ADD8; return; + case 0xFC: set_regop16(m_d); %EXTENDED; %LD16; return; + case 0xFD: set_regop16(m_d); %EXTENDED; %ST16; return; + case 0xFE: set_regop16(m_u); %EXTENDED; %LD16; return; + case 0xFF: set_regop16(m_u); %EXTENDED; %ST16; return; + default: %ILLEGAL; return; + } + return; + +DISPATCH10: + @m_opcode = read_opcode(); + switch(m_opcode) + { + case 0x20: set_cond(true); %LBRANCH; return; + case 0x21: set_cond(false); %LBRANCH; return; + case 0x22: set_cond(cond_hi()); %LBRANCH; return; + case 0x23: set_cond(!cond_hi()); %LBRANCH; return; + case 0x24: set_cond(cond_cc()); %LBRANCH; return; + case 0x25: set_cond(!cond_cc()); %LBRANCH; return; + case 0x26: set_cond(cond_ne()); %LBRANCH; return; + case 0x27: set_cond(!cond_ne()); %LBRANCH; return; + case 0x28: set_cond(cond_vc()); %LBRANCH; return; + case 0x29: set_cond(!cond_vc()); %LBRANCH; return; + case 0x2A: set_cond(cond_pl()); %LBRANCH; return; + case 0x2B: set_cond(!cond_pl()); %LBRANCH; return; + case 0x2C: set_cond(cond_ge()); %LBRANCH; return; + case 0x2D: set_cond(!cond_ge()); %LBRANCH; return; + case 0x2E: set_cond(cond_gt()); %LBRANCH; return; + case 0x2F: set_cond(!cond_gt()); %LBRANCH; return; + + case 0x3F: %SWI2; return; + + case 0x83: set_regop16(m_d); set_imm(); %CMP16; return; + case 0x8C: set_regop16(m_y); set_imm(); %CMP16; return; + case 0x8E: set_regop16(m_y); set_imm(); %LD16; return; + case 0x8F: set_regop16(m_y); set_imm(); %ST16; return; + case 0x93: set_regop16(m_d); %DIRECT; %CMP16; return; + case 0x9C: set_regop16(m_y); %DIRECT; %CMP16; return; + case 0x9E: set_regop16(m_y); %DIRECT; %LD16; return; + case 0x9F: set_regop16(m_y); %DIRECT; %ST16; return; + case 0xA3: set_regop16(m_d); %INDEXED; %CMP16; return; + case 0xAC: set_regop16(m_y); %INDEXED; %CMP16; return; + case 0xAE: set_regop16(m_y); %INDEXED; %LD16; return; + case 0xAF: set_regop16(m_y); %INDEXED; %ST16; return; + case 0xB3: set_regop16(m_d); %EXTENDED; %CMP16; return; + case 0xBC: set_regop16(m_y); %EXTENDED; %CMP16; return; + case 0xBE: set_regop16(m_y); %EXTENDED; %LD16; return; + case 0xBF: set_regop16(m_y); %EXTENDED; %ST16; return; + + case 0xCE: set_regop16(m_s); set_imm(); %LD16; return; + case 0xCF: set_regop16(m_s); set_imm(); %ST16; return; + case 0xDE: set_regop16(m_s); %DIRECT; %LD16; return; + case 0xDF: set_regop16(m_s); %DIRECT; %ST16; return; + case 0xEE: set_regop16(m_s); %INDEXED; %LD16; return; + case 0xEF: set_regop16(m_s); %INDEXED; %ST16; return; + case 0xFE: set_regop16(m_s); %EXTENDED; %LD16; return; + case 0xFF: set_regop16(m_s); %EXTENDED; %ST16; return; + + default: %ILLEGAL; return; + } + return; + +DISPATCH11: + @m_opcode = read_opcode(); + switch(m_opcode) + { + case 0x3F: %SWI3; return; + case 0x83: set_regop16(m_u); set_imm(); %CMP16; return; + case 0x8C: set_regop16(m_s); set_imm(); %CMP16; return; + case 0x93: set_regop16(m_u); %DIRECT; %CMP16; return; + case 0x9C: set_regop16(m_s); %DIRECT; %CMP16; return; + case 0xA3: set_regop16(m_u); %INDEXED; %CMP16; return; + case 0xAC: set_regop16(m_s); %INDEXED; %CMP16; return; + case 0xB3: set_regop16(m_u); %EXTENDED; %CMP16; return; + case 0xBC: set_regop16(m_s); %EXTENDED; %CMP16; return; + + default: %ILLEGAL; return; + } + return; + +#include "base6x09.ops" + +PUSH_REGISTERS: + if (m_temp.w & 0x80) + { + @write_memory(--regop16().w, m_pc.b.l); + @write_memory(--regop16().w, m_pc.b.h); + nop(); + } + if (m_temp.w & 0x40) + { + @write_memory(--regop16().w, (®op16() == &m_s) ? m_u.b.l : m_s.b.l); + @write_memory(--regop16().w, (®op16() == &m_s) ? m_u.b.h : m_s.b.h); + nop(); + } + if (m_temp.w & 0x20) + { + @write_memory(--regop16().w, m_y.b.l); + @write_memory(--regop16().w, m_y.b.h); + nop(); + } + if (m_temp.w & 0x10) + { + @write_memory(--regop16().w, m_x.b.l); + @write_memory(--regop16().w, m_x.b.h); + nop(); + } + if (m_temp.w & 0x08) + { + @write_memory(--regop16().w, m_dp); + nop(); + } + if (m_temp.w & 0x04) + { + @write_memory(--regop16().w, m_d.b.l); + nop(); + } + if (m_temp.w & 0x02) + { + @write_memory(--regop16().w, m_d.b.h); + nop(); + } + if (m_temp.w & 0x01) + { + @write_memory(--regop16().w, m_cc); + nop(); + } + return; + +PULL_REGISTERS: + if (m_temp.w & 0x01) + { + @m_cc = read_memory(regop16().w++); + nop(); + } + if (m_temp.w & 0x02) + { + @m_d.b.h = read_memory(regop16().w++); + nop(); + } + if (m_temp.w & 0x04) + { + @m_d.b.l = read_memory(regop16().w++); + nop(); + } + if (m_temp.w & 0x08) + { + @m_dp = read_memory(regop16().w++); + nop(); + } + if (m_temp.w & 0x10) + { + @m_x.b.h = read_memory(regop16().w++); + @m_x.b.l = read_memory(regop16().w++); + nop(); + } + if (m_temp.w & 0x20) + { + @m_y.b.h = read_memory(regop16().w++); + @m_y.b.l = read_memory(regop16().w++); + nop(); + } + if (m_temp.w & 0x40) + { + @(®op16() == &m_s ? m_u : m_s).b.h = read_memory(regop16().w++); + @(®op16() == &m_s ? m_u : m_s).b.l = read_memory(regop16().w++); + nop(); + } + if (m_temp.w & 0x80) + { + @m_pc.b.h = read_memory(regop16().w++); + @m_pc.b.l = read_memory(regop16().w++); + nop(); + } + @eat(1); + return; + +INDEXED: + @m_opcode = read_opcode_arg(); + if (m_opcode & 0x80) + { + switch(m_opcode & 0x7F) + { + case 0x00: case 0x20: case 0x40: case 0x60: + case 0x10: case 0x30: case 0x50: case 0x70: + m_temp.w = ireg(); + ireg()++; + eat(3); + break; + + case 0x01: case 0x21: case 0x41: case 0x61: + case 0x11: case 0x31: case 0x51: case 0x71: + m_temp.w = ireg(); + ireg() += 2; + eat(4); + break; + + case 0x02: case 0x22: case 0x42: case 0x62: + case 0x12: case 0x32: case 0x52: case 0x72: + ireg()--; + m_temp.w = ireg(); + eat(3); + break; + + case 0x03: case 0x23: case 0x43: case 0x63: + case 0x13: case 0x33: case 0x53: case 0x73: + ireg() -= 2; + m_temp.w = ireg(); + eat(4); + break; + + case 0x04: case 0x24: case 0x44: case 0x64: + case 0x14: case 0x34: case 0x54: case 0x74: + m_temp.w = ireg(); + eat(1); + break; + + case 0x05: case 0x25: case 0x45: case 0x65: + case 0x15: case 0x35: case 0x55: case 0x75: + m_temp.w = ireg() + (INT8) m_d.b.l; + eat(2); + break; + + case 0x06: case 0x26: case 0x46: case 0x66: + case 0x16: case 0x36: case 0x56: case 0x76: + m_temp.w = ireg() + (INT8) m_d.b.h; + eat(2); + break; + + case 0x08: case 0x28: case 0x48: case 0x68: + case 0x18: case 0x38: case 0x58: case 0x78: + @m_temp.w = ireg() + (INT8) read_opcode_arg(); + eat(1); + break; + + case 0x09: case 0x29: case 0x49: case 0x69: + case 0x19: case 0x39: case 0x59: case 0x79: + @m_temp.b.h = read_opcode_arg(); + @m_temp.b.l = read_opcode_arg(); + m_temp.w = ireg() + m_temp.w; + eat(3); + break; + + case 0x0B: case 0x2B: case 0x4B: case 0x6B: + case 0x1B: case 0x3B: case 0x5B: case 0x7B: + m_temp.w = ireg() + m_d.w; + eat(5); + break; + + case 0x0C: case 0x2C: case 0x4C: case 0x6C: + case 0x1C: case 0x3C: case 0x5C: case 0x7C: + @m_temp.b.l = read_opcode_arg(); + m_temp.w = m_pc.w + (INT8) m_temp.b.l; + eat(1); + break; + + case 0x0D: case 0x2D: case 0x4D: case 0x6D: + case 0x1D: case 0x3D: case 0x5D: case 0x7D: + @m_temp.b.h = read_opcode_arg(); + @m_temp.b.l = read_opcode_arg(); + m_temp.w = m_pc.w + (INT16) m_temp.w; + eat(4); + break; + + case 0x0F: case 0x2F: case 0x4F: case 0x6F: + case 0x1F: case 0x3F: case 0x5F: case 0x7F: + @m_temp.b.h = read_opcode_arg(); + @m_temp.b.l = read_opcode_arg(); + eat(1); + break; + + default: + m_temp.w = 0x0000; + break; + } + + // indirect mode + if (m_opcode & 0x10) + { + set_ea(m_temp.w); + @m_temp.b.h = read_operand(0); + @m_temp.b.l = read_operand(1); + eat(1); + } + } + else + { + // 5-bit offset + m_temp.w = ireg() + (INT8) ((m_opcode & 0x0F) | (m_opcode & 0x10 ? 0xF0 : 0x00)); + eat(2); + } + @set_ea(m_temp.w); + return; + +EXG: + { + UINT8 param = read_opcode_arg(); + exgtfr_register reg1 = read_exgtfr_register(param >> 4); + exgtfr_register reg2 = read_exgtfr_register(param >> 0); + write_exgtfr_register(param >> 4, reg2); + write_exgtfr_register(param >> 0, reg1); + } + eat(hd6309_native_mode() ? 3 : 6); + return; + +TFR: + { + UINT8 param = read_opcode_arg(); + exgtfr_register reg = read_exgtfr_register(param >> 4); + write_exgtfr_register(param >> 0, reg); + if ((param & 0x0F) == 4) { + m_lds_encountered = true; + } + } + eat(hd6309_native_mode() ? 2 : 4); + return; + +ILLEGAL: + log_illegal(); + return; diff --git a/src/devices/cpu/m6809/m6809inl.h b/src/devices/cpu/m6809/m6809inl.h new file mode 100644 index 00000000000..8fd1cfe330d --- /dev/null +++ b/src/devices/cpu/m6809/m6809inl.h @@ -0,0 +1,273 @@ +// license:BSD-3-Clause +// copyright-holders:Nathan Woods +/********************************************************************* + + m6809inl.h + + Portable 6809 emulator - Inline functions for the purposes of + optimization + +**********************************************************************/ + +#include "m6809.h" + +//------------------------------------------------- +// rotate_right +//------------------------------------------------- + +template +inline ATTR_FORCE_INLINE T m6809_base_device::rotate_right(T value) +{ + bool new_carry = (value & 1) ? true : false; + value = value >> 1; + + T high_bit = ((T) 1) << (sizeof(T) * 8 - 1); + if (m_cc & CC_C) + value |= high_bit; + else + value &= ~high_bit; + + if (new_carry) + m_cc |= CC_C; + else + m_cc &= ~CC_C; + return value; +} + + +//------------------------------------------------- +// rotate_left +//------------------------------------------------- + +template +inline ATTR_FORCE_INLINE UINT32 m6809_base_device::rotate_left(T value) +{ + T high_bit = ((T) 1) << (sizeof(T) * 8 - 1); + bool new_carry = (value & high_bit) ? true : false; + + UINT32 new_value = value; + new_value <<= 1; + + if (m_cc & CC_C) + new_value |= 1; + else + new_value &= ~1; + + if (new_carry) + m_cc |= CC_C; + else + m_cc &= ~CC_C; + return new_value; +} + + +//------------------------------------------------- +// read_operand +//------------------------------------------------- + +inline ATTR_FORCE_INLINE UINT8 m6809_base_device::read_operand() +{ + switch(m_addressing_mode) + { + case ADDRESSING_MODE_EA: return read_memory(m_ea.w); + case ADDRESSING_MODE_IMMEDIATE: return read_opcode_arg(); + case ADDRESSING_MODE_REGISTER_A: return m_d.b.h; + case ADDRESSING_MODE_REGISTER_B: return m_d.b.l; + default: fatalerror("Unexpected"); return 0x00; + } +} + + +//------------------------------------------------- +// read_operand +//------------------------------------------------- + +inline ATTR_FORCE_INLINE UINT8 m6809_base_device::read_operand(int ordinal) +{ + switch(m_addressing_mode) + { + case ADDRESSING_MODE_EA: return read_memory(m_ea.w + ordinal); + case ADDRESSING_MODE_IMMEDIATE: return read_opcode_arg(); + default: fatalerror("Unexpected"); return 0x00; + } +} + + +//------------------------------------------------- +// write_operand +//------------------------------------------------- + +inline ATTR_FORCE_INLINE void m6809_base_device::write_operand(UINT8 data) +{ + switch(m_addressing_mode) + { + case ADDRESSING_MODE_IMMEDIATE: /* do nothing */ break; + case ADDRESSING_MODE_EA: write_memory(m_ea.w, data); break; + case ADDRESSING_MODE_REGISTER_A: m_d.b.h = data; break; + case ADDRESSING_MODE_REGISTER_B: m_d.b.l = data; break; + default: fatalerror("Unexpected"); break; + } +} + + +//------------------------------------------------- +// write_operand +//------------------------------------------------- + +inline ATTR_FORCE_INLINE void m6809_base_device::write_operand(int ordinal, UINT8 data) +{ + switch(m_addressing_mode) + { + case ADDRESSING_MODE_IMMEDIATE: /* do nothing */ break; + case ADDRESSING_MODE_EA: write_memory(m_ea.w + ordinal, data); break; + default: fatalerror("Unexpected"); break; + } +} + + +//------------------------------------------------- +// daa - decimal arithmetic adjustment instruction +//------------------------------------------------- + +inline ATTR_FORCE_INLINE void m6809_base_device::daa() +{ + UINT16 t, cf = 0; + UINT8 msn = m_d.b.h & 0xF0; + UINT8 lsn = m_d.b.h & 0x0F; + + // compute the carry + if (lsn > 0x09 || m_cc & CC_H) cf |= 0x06; + if (msn > 0x80 && lsn > 0x09 ) cf |= 0x60; + if (msn > 0x90 || m_cc & CC_C) cf |= 0x60; + + // calculate the result + t = m_d.b.h + cf; + + m_cc &= ~CC_V; + if (t & 0x0100) // keep carry from previous operation + m_cc |= CC_C; + + // and put it back into A + m_d.b.h = set_flags(CC_NZ, (UINT8) t); +} + + +//------------------------------------------------- +// mul +//------------------------------------------------- + +inline ATTR_FORCE_INLINE void m6809_base_device::mul() +{ + // perform multiply + UINT16 result = ((UINT16) m_d.b.h) * ((UINT16) m_d.b.l); + + // set result and Z flag + m_d.w = set_flags(CC_Z, result); + + // set C flag + if (m_d.w & 0x0080) + m_cc |= CC_C; + else + m_cc &= ~CC_C; +} + + +//------------------------------------------------- +// ireg +//------------------------------------------------- + +inline ATTR_FORCE_INLINE UINT16 &m6809_base_device::ireg() +{ + switch(m_opcode & 0x60) + { + case 0x00: return m_x.w; + case 0x20: return m_y.w; + case 0x40: return m_u.w; + case 0x60: return m_s.w; + default: + fatalerror("Unexpected"); + return m_x.w; + } +} + + +//------------------------------------------------- +// set_flags +//------------------------------------------------- + +template +inline T m6809_base_device::set_flags(UINT8 mask, T a, T b, UINT32 r) +{ + T hi_bit = (T) (1 << (sizeof(T) * 8 - 1)); + + m_cc &= ~mask; + if (mask & CC_H) + m_cc |= ((a ^ b ^ r) & 0x10) ? CC_H : 0; + if (mask & CC_N) + m_cc |= (r & hi_bit) ? CC_N : 0; + if (mask & CC_Z) + m_cc |= (((T)r) == 0) ? CC_Z : 0; + if (mask & CC_V) + m_cc |= ((a ^ b ^ r ^ (r >> 1)) & hi_bit) ? CC_V : 0; + if (mask & CC_C) + m_cc |= (r & (hi_bit << 1)) ? CC_C : 0; + return (T) r; +} + + +//------------------------------------------------- +// set_flags +//------------------------------------------------- + +template +inline T m6809_base_device::set_flags(UINT8 mask, T r) +{ + return set_flags(mask, (T)0, r, r); +} + + +//------------------------------------------------- +// eat_remaining +//------------------------------------------------- + +inline void m6809_base_device::eat_remaining() +{ + // we do this in order to be nice to people debugging + UINT16 real_pc = m_pc.w; + + eat(m_icount); + + m_pc.w = m_ppc.w; + debugger_instruction_hook(this, m_pc.w); + m_pc.w = real_pc; +} + + + +//------------------------------------------------- +// is_register_addressing_mode +//------------------------------------------------- + +inline bool m6809_base_device::is_register_addressing_mode() +{ + return (m_addressing_mode != ADDRESSING_MODE_IMMEDIATE) + && (m_addressing_mode != ADDRESSING_MODE_EA); +} + + + +//------------------------------------------------- +// get_pending_interrupt +//------------------------------------------------- + +inline UINT16 m6809_base_device::get_pending_interrupt() +{ + if (m_nmi_asserted) + return VECTOR_NMI; + else if (!(m_cc & CC_F) && m_firq_line) + return VECTOR_FIRQ; + else if (!(m_cc & CC_I) && m_irq_line) + return VECTOR_IRQ; + else + return 0; +} diff --git a/src/devices/cpu/m6809/m6809make.py b/src/devices/cpu/m6809/m6809make.py new file mode 100644 index 00000000000..28e018f8b2d --- /dev/null +++ b/src/devices/cpu/m6809/m6809make.py @@ -0,0 +1,125 @@ +#!/usr/bin/python + +import sys +import re + +# Initial state +state = 1 +text = "" +dispatch_to_states = { "MAIN" : 0 } +states_to_dispatch = { 0 : "MAIN" } + +def load_file(fname, lines): + path = fname.rpartition('/')[0] + if path != "": + path += '/' + try: + f = open(fname, "rU") + except Exception: + err = sys.exc_info()[1] + sys.stderr.write("Cannot read opcodes file %s [%s]\n" % (fname, err)) + sys.exit(1) + + rawlines = re.split('(\n|; *\n?)', f.read()) + count = 0 + while count < len(rawlines)-1: + line = rawlines[count+0] + rawlines[count+1] + if line.startswith("#include"): + load_file(path + line.split('"')[1], lines) + else: + lines.append(line) + count += 2 + + f.close() + +# Get lines +lines = [] +load_file(sys.argv[1], lines) + +count = 0 +while count < len(lines): + # Retrieve this line + line = lines[count] + + # Retrieve the whitespace + whitespace = line[:len(line) - len(line.lstrip())] + + # Check to see if the next line is a return + next_line_is_return = (count + 1 == len(lines)) or lines[count+1].strip() == "return;" + + # Check to see if the next line is a dispatch followed by return + next_line_is_dispatch_and_return = (count + 1 < len(lines)) and re.match('([A-Za-z0-9\t ]+\:)*\s*\%', lines[count+1]) and lines[count+2].strip() == "return;" + + if re.match('([A-Za-z0-9\t ]+\:)*\s*\%', line): + # This is a dispatch - find the '%' + percent_pos = line.find("%") + dispatch = line[percent_pos+1:].strip("\t\n; ") + + # Do we have a label? + label = line[:percent_pos].strip() + if label != "": + text += whitespace + label + "\n" + whitespace += "\t" + + # Create the goto command + if dispatch[-1:] == "*": + goto_command = "if (is_register_register_op_16_bit()) goto %s16; else goto %s8;\n" %(dispatch[:-1], dispatch[:-1]) + else: + goto_command = "goto %s;\n" % dispatch + + # Are we right before a 'return'? + if next_line_is_return: + text += whitespace + goto_command + count += 1 # Skip the return + elif next_line_is_dispatch_and_return: + # We are followed by a dispatch/return combo; identify the next dispatch + percent_pos = lines[count+1].find("%") + next_dispatch = lines[count+1][percent_pos+1:].strip("\t\n; ") + + # If there is no state number associated with the next dispatch, make one + if next_dispatch not in dispatch_to_states: + dispatch_to_states[next_dispatch] = state + states_to_dispatch[state] = next_dispatch + state += 1 + + text += whitespace + "push_state(%s);\t// %s\n" % (dispatch_to_states[next_dispatch], next_dispatch) + text += whitespace + goto_command + count += 2 # Skip the dispatch/return + + else: + # Normal dispatch + text += whitespace + "push_state(%s);\n" % state + text += whitespace + goto_command + text += "state_%s:\n" % state + state += 1 + else: + # "Normal" code + # Is there an '@' here? + check_icount = line.lstrip().startswith("@") + if check_icount: + line = line.replace("@", "", 1) + + # Output the line + text += line + + # If we have to decrement the icount, output more info + if check_icount and not next_line_is_return: + text += whitespace + "if (UNEXPECTED(m_icount <= 0)) { push_state(%s); return; }\n" % state + text += "state_%s:\n" % state + state += 1 + + # Advance to next line + count += 1 + +# Output the case labels +for i in range(0, state): + print("\tcase %d: goto %s;" % (i, states_to_dispatch.get(i, "state_%d" % i))) + +# Output a default case +print "\tdefault:" +print "\t\tfatalerror(\"Unexpected state\");" +print "\t\tbreak;" +print + +# Finally output the text +print text diff --git a/src/devices/cpu/mb86233/mb86233.c b/src/devices/cpu/mb86233/mb86233.c new file mode 100644 index 00000000000..0ad34296064 --- /dev/null +++ b/src/devices/cpu/mb86233/mb86233.c @@ -0,0 +1,1655 @@ +// license:BSD-3-Clause +// copyright-holders:Ernesto Corvi +/*************************************************************************** + + mb86233.c + Core implementation for the portable Fujitsu MB86233 series DSP emulator. + + Written by ElSemi + MAME version by Ernesto Corvi + + TODO: + - Properly emulate the TGP Tables from the ROM (See GETEXTERNAL) + - Many unknown opcodes and addressing modes + - Interrupts? + +***************************************************************************/ + +#include "emu.h" +#include "debugger.h" +#include "mb86233.h" + + +const device_type MB86233 = &device_creator; + + +mb86233_cpu_device::mb86233_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : cpu_device(mconfig, MB86233, "MB86233", tag, owner, clock, "mb86233", __FILE__) + , m_program_config("program", ENDIANNESS_LITTLE, 32, 32, -2) + , m_data_config("data", ENDIANNESS_LITTLE, 32, 32, 0) + , m_fifo_read_cb(*this) + , m_fifo_read_ok_cb(*this) + , m_fifo_write_cb(*this) + , m_tablergn(NULL) + , m_Tables(NULL) +{ +} + + +offs_t mb86233_cpu_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( mb86233 ); + return CPU_DISASSEMBLE_NAME(mb86233)(this, buffer, pc, oprom, opram, options); +} + + +/*************************************************************************** + MACROS +***************************************************************************/ + +#define ZERO_FLAG (1 << 0) +#define SIGN_FLAG (1 << 1) +#define EXTERNAL_FLAG (1 << 2) //This seems to be a flag coming from some external circuit?? + +#define GETPC() m_pc +#define GETA() m_a +#define GETB() m_b +#define GETD() m_d +#define GETP() m_p +#define GETSR() m_sr +#define GETGPR(a) m_gpr[a] +#define GETSHIFT() m_shift +#define GETPCS() m_pcs +#define GETPCSP() m_pcsp +#define GETEB() m_eb +#define GETREPS() m_reps +#define GETEXTPORT() m_extport +#define GETFIFOWAIT() m_fifo_wait +#define GETARAM() m_ARAM +#define GETBRAM() m_BRAM +#define GETREPCNT() m_repcnt + +#define ROPCODE(a) m_direct->read_dword(a<<2) +#define RDMEM(a) m_program->read_dword((a<<2)) +#define WRMEM(a,v) m_program->write_dword((a<<2), v) + +/*************************************************************************** + Initialization and Shutdown +***************************************************************************/ + +void mb86233_cpu_device::device_start() +{ + m_pc = 0; + m_a.u = 0; + m_b.u = 0; + m_d.u = 0; + m_p.u = 0; + m_reps = 0; + m_pcs[0] = m_pcs[1] = m_pcs[2] = m_pcs[3] = 0; + m_pcsp = 0; + m_eb = 0; + m_shift = 0; + m_repcnt = 0; + m_sr = 0; + memset(m_gpr, 0, sizeof(m_gpr)); + memset(m_extport, 0, sizeof(m_extport)); + m_fifo_wait = 0; + + m_fifo_read_cb.resolve_safe(0); + m_fifo_read_ok_cb.resolve_safe(0); + m_fifo_write_cb.resolve_safe(); + + m_program = &space(AS_PROGRAM); + m_direct = &m_program->direct(); + + if ( m_tablergn ) + { + m_Tables = (UINT32*) machine().root_device().memregion(m_tablergn)->base(); + } + + memset( m_RAM, 0, 2 * 0x200 * sizeof(UINT32) ); + m_ARAM = &m_RAM[0]; + m_BRAM = &m_RAM[0x200]; + + save_item(NAME(m_pc)); + save_item(NAME(m_a.u)); + save_item(NAME(m_b.u)); + save_item(NAME(m_d.u)); + save_item(NAME(m_p.u)); + save_item(NAME(m_reps)); + save_item(NAME(m_pcs)); + save_item(NAME(m_pcsp)); + save_item(NAME(m_eb)); + save_item(NAME(m_shift)); + save_item(NAME(m_repcnt)); + save_item(NAME(m_sr)); + save_item(NAME(m_gpr)); + save_item(NAME(m_extport)); + save_item(NAME(m_RAM)); + + state_add( MB86233_PC, "PC", m_pc).formatstr("%04X"); + state_add( MB86233_A, "PA", m_a.u).formatstr("%08X"); + state_add( MB86233_B, "PB", m_b.u).formatstr("%08X"); + state_add( MB86233_P, "PP", m_p.u).formatstr("%08X"); + state_add( MB86233_D, "PD", m_d.u).formatstr("%08X"); + state_add( MB86233_REP, "REPS", m_reps).formatstr("%08X"); + state_add( MB86233_SP, "PCSP", m_pcsp).mask(0xf).formatstr("%01X"); + state_add( MB86233_EB, "EB", m_eb).formatstr("%08X"); + state_add( MB86233_SHIFT, "SHIFT", m_shift).formatstr("%08X"); + state_add( MB86233_R0, "R0", m_gpr[0]).formatstr("%08X"); + state_add( MB86233_R1, "R1", m_gpr[1]).formatstr("%08X"); + state_add( MB86233_R2, "R2", m_gpr[2]).formatstr("%08X"); + state_add( MB86233_R3, "R3", m_gpr[3]).formatstr("%08X"); + state_add( MB86233_R4, "R4", m_gpr[4]).formatstr("%08X"); + state_add( MB86233_R5, "R5", m_gpr[5]).formatstr("%08X"); + state_add( MB86233_R6, "R6", m_gpr[6]).formatstr("%08X"); + state_add( MB86233_R7, "R7", m_gpr[7]).formatstr("%08X"); + state_add( MB86233_R8, "R8", m_gpr[8]).formatstr("%08X"); + state_add( MB86233_R9, "R9", m_gpr[9]).formatstr("%08X"); + state_add( MB86233_R10, "R10", m_gpr[10]).formatstr("%08X"); + state_add( MB86233_R11, "R11", m_gpr[11]).formatstr("%08X"); + state_add( MB86233_R12, "R12", m_gpr[12]).formatstr("%08X"); + state_add( MB86233_R13, "R13", m_gpr[13]).formatstr("%08X"); + state_add( MB86233_R14, "R14", m_gpr[14]).formatstr("%08X"); + state_add( MB86233_R15, "R15", m_gpr[15]).formatstr("%08X"); + + state_add( STATE_GENPC, "GENPC", m_pc).noshow(); + state_add( STATE_GENFLAGS, "GENFLAGS", m_sr).formatstr("%2s").noshow(); + + m_icountptr = &m_icount; +} + + +void mb86233_cpu_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + switch (entry.index()) + { + case STATE_GENFLAGS: + strprintf(str, "%c%c", (m_sr & SIGN_FLAG) ? 'N' : 'n', (m_sr & ZERO_FLAG) ? 'Z' : 'z'); + break; + } +} + + +void mb86233_cpu_device::device_reset() +{ + /* zero registers and flags */ + m_pc = 0; + m_sr = 0; + m_pcsp = 0; + m_eb = 0; + m_shift = 0; + m_fifo_wait = 0; +} + + + +/*************************************************************************** + Status Register +***************************************************************************/ + +#define ZERO_FLAG (1 << 0) +#define SIGN_FLAG (1 << 1) +#define EXTERNAL_FLAG (1 << 2) //This seems to be a flag coming from some external circuit?? + +void mb86233_cpu_device::FLAGSF( float v ) +{ + GETSR() &= ~(ZERO_FLAG|SIGN_FLAG); + + if ( v == 0 ) + GETSR() |= ZERO_FLAG; + + if ( v < 0 ) + GETSR() |= SIGN_FLAG; +} + +void mb86233_cpu_device::FLAGSI( UINT32 v ) +{ + GETSR() &= ~(ZERO_FLAG|SIGN_FLAG); + + if ( v == 0 ) + GETSR() |= ZERO_FLAG; + + if ( v & 0x80000000 ) + GETSR() |= SIGN_FLAG; +} + + + +/*************************************************************************** + Condition Codes +***************************************************************************/ + +int mb86233_cpu_device::COND( UINT32 cond ) +{ + switch( cond ) + { + case 0x00: /* eq */ + if ( (GETSR() & ZERO_FLAG) ) return 1; + break; + + case 0x01: /* ge */ + if ( (GETSR() & ZERO_FLAG) || ((GETSR() & SIGN_FLAG)==0) ) return 1; + break; + + case 0x02: /* le */ + if ( (GETSR() & ZERO_FLAG) || (GETSR() & SIGN_FLAG) ) return 1; + break; + + case 0x06: /* never */ + break; + + case 0x0a: + if(GETSR() & EXTERNAL_FLAG) return 1; + break; + + case 0x10: /* --r12 != 0 */ + GETGPR(12)--; + if ( GETGPR(12) != 0 ) return 1; + break; + + case 0x11: /* --r13 != 0 */ + GETGPR(13)--; + if ( GETGPR(13) != 0 ) return 1; + break; + + case 0x16: /* always */ + return 1; + + default: + logerror( "TGP: Unknown condition code (cc=%d) at PC:%x\n", cond, GETPC()); + break; + } + + return 0; +} + + + +/*************************************************************************** + ALU +***************************************************************************/ + +void mb86233_cpu_device::ALU( UINT32 alu) +{ + float ftmp; + + switch(alu) + { + case 0x00: /* NOP */ + break; + + case 0x01: /* D = D & A */ + GETD().u &= GETA().u; + FLAGSI( GETD().u); + break; + + case 0x02: /* D = D | A */ + GETD().u |= GETA().u; + FLAGSI( GETD().u); + break; + + case 0x03: /* D = D ^ A */ + GETD().u ^= GETA().u; + FLAGSI( GETD().u); + break; + + case 0x04: /* D = D ~ A */ + GETD().u = ~GETA().u; + FLAGSI( GETD().u); + break; + + case 0x05: /* CMP D,A */ + ftmp = GETD().f - GETA().f; + FLAGSF( ftmp); + m_icount--; + break; + + case 0x06: /* D = D + A */ + GETD().f += GETA().f; + FLAGSF( GETD().f); + m_icount--; + break; + + case 0x07: /* D = D - A */ + GETD().f -= GETA().f; + FLAGSF( GETD().f); + m_icount--; + break; + + case 0x08: /* P = A * B */ + GETP().f = GETA().f * GETB().f; + m_icount--; + break; + + case 0x09: /* D = D + P; P = A * B */ + GETD().f += GETP().f; + GETP().f = GETA().f * GETB().f; + FLAGSF( GETD().f); + m_icount--; + break; + + case 0x0A: /* D = D - P; P = A * B */ + GETD().f -= GETP().f; + GETP().f = GETA().f * GETB().f; + FLAGSF( GETD().f); + m_icount--; + break; + + case 0x0B: /* D = fabs(D) */ + GETD().f = fabs( GETD().f ); + FLAGSF( GETD().f); + m_icount--; + break; + + case 0x0C: /* D = D + P */ + GETD().f += GETP().f; + FLAGSF( GETD().f); + m_icount--; + break; + + case 0x0D: /* D = P; P = A * B */ + GETD().f = GETP().f; + GETP().f = GETA().f * GETB().f; + FLAGSF( GETD().f); + m_icount--; + break; + + case 0x0E: /* D = float(D) */ + GETD().f = (float)GETD().i; + FLAGSF( GETD().f); + m_icount--; + break; + + case 0x0F: /* D = int(D) */ + switch((m_fpucontrol>>1)&3) + { + //case 0: GETD().i = floor(GETD().f+0.5f); break; + //case 1: GETD().i = ceil(GETD().f); break; + case 2: GETD().i = floor(GETD().f); break; // Manx TT + case 3: GETD().i = (INT32)GETD().f; break; + default: popmessage("TGP uses D = int(D) with FPU control = %02x, contact MAMEdev",m_fpucontrol>>1); break; + } + + FLAGSI( GETD().i); + break; + + case 0x10: /* D = D / A */ + if ( GETA().u != 0 ) + GETD().f = GETD().f / GETA().f; + FLAGSF( GETD().f); + m_icount--; + break; + + case 0x11: /* D = -D */ + GETD().f = -GETD().f; + FLAGSF( GETD().f); + m_icount--; + break; + + case 0x13: /* D = A + B */ + GETD().f = GETA().f + GETB().f; + FLAGSF( GETD().f); + m_icount--; + break; + + case 0x14: /* D = B - A */ + GETD().f = GETB().f - GETA().f; + FLAGSF( GETD().f); + m_icount--; + break; + + case 0x16: /* LSR D, SHIFT */ + GETD().u >>= GETSHIFT(); + FLAGSI( GETD().u); + break; + + case 0x17: /* LSL D, SHIFT */ + GETD().u <<= GETSHIFT(); + FLAGSI( GETD().u); + break; + + case 0x18: /* ASR D, SHIFT */ +// GETD().u = (GETD().u & 0x80000000) | (GETD().u >> GETSHIFT()); + GETD().i >>= GETSHIFT(); + FLAGSI( GETD().u); + break; + + case 0x1A: /* D = D + A */ + GETD().i += GETA().i; + FLAGSI( GETD().u); + break; + + case 0x1B: /* D = D - A */ + GETD().i -= GETA().i; + FLAGSI( GETD().u); + break; + + default: + fatalerror( "TGP: Unknown ALU op %x at PC:%04x\n", alu, GETPC() ); + } +} + + + +/*************************************************************************** + Memory Access +***************************************************************************/ + +UINT32 mb86233_cpu_device::ScaleExp(unsigned int v,int scale) +{ + int exp=(v>>23)&0xff; + exp+=scale; + v&=~0x7f800000; + return v|(exp<<23); +} + + +UINT32 mb86233_cpu_device::GETEXTERNAL( UINT32 EB, UINT32 offset ) +{ + UINT32 addr; + + if ( EB == 0 && offset >= 0x20 && offset <= 0x2f ) /* TGP Tables in ROM - FIXME - */ + { + if(offset>=0x20 && offset<=0x23) //SIN from value at RAM(0x20) in 0x4000/PI steps + { + UINT32 r; + UINT32 value=GETEXTPORT()[0x20]; + UINT32 off; + value+=(offset-0x20)<<14; + off=value&0x3fff; + if((value&0x7fff)==0) + r=0; + else if((value&0x7fff)==0x4000) + r=0x3f800000; + else + { + if(value&0x4000) + off=0x4000-off; + r=m_Tables[off]; + } + if(value&0x8000) + r|=1<<31; + return r; + } + + if(offset==0x27) + { + unsigned int value=GETEXTPORT()[0x27]; + int exp=(value>>23)&0xff; + unsigned int res=0; + unsigned int sign=0; + MB86233_REG a,b; + int index; + + a.u=GETEXTPORT()[0x24]; + b.u=GETEXTPORT()[0x25]; + + + if(!exp) + { + if((a.u&0x7fffffff)<=(b.u&0x7fffffff)) + { + if(b.u&0x80000000) + res=0xc000; + else + res=0x4000; + } + else + { + if(a.u&0x80000000) + res=0x8000; + else + res=0x0000; + } + return res; + } + + if((a.u^b.u)&0x80000000) + sign=16; //the negative values are in the high word + + if((exp&0x70)!=0x70) + index=0; + else if(exp<0x70 || exp>0x7e) + index=0x3fff; + else + { + int expdif=exp-0x71; + int base; + int mask; + int shift; + + + if(expdif<0) + expdif=0; + base=1<>shift)&mask); + + } + + res=(m_Tables[index+0x10000/4]>>sign)&0xffff; + + if((a.u&0x7fffffff)<=(b.u&0x7fffffff)) + res=0x4000-res; + + + if((a.u&0x80000000) && (b.u&0x80000000)) //3rd quadrant + { + res=0x8000|res; + } + else if((a.u&0x80000000) && !(b.u&0x80000000)) //2nd quadrant + { + res=res&0x7fff; + } + else if(!(a.u&0x80000000) && (b.u&0x80000000)) //2nd quadrant + { + res=0x8000|res; + } + + return res; + + } + + if(offset==0x28) + { + UINT32 offset=(GETEXTPORT()[0x28]>>10)&0x1fff; + UINT32 value=m_Tables[offset*2+0x20000/4]; + UINT32 srcexp=(GETEXTPORT()[0x28]>>23)&0xff; + + value&=0x7FFFFFFF; + + return ScaleExp(value,0x7f-srcexp); + } + if(offset==0x29) + { + UINT32 offset=(GETEXTPORT()[0x28]>>10)&0x1fff; + UINT32 value=m_Tables[offset*2+(0x20000/4)+1]; + UINT32 srcexp=(GETEXTPORT()[0x28]>>23)&0xff; + + value&=0x7FFFFFFF; + if(GETEXTPORT()[0x28]&(1<<31)) + value|=1<<31; + + return ScaleExp(value,0x7f-srcexp); + } + if(offset==0x2a) + { + UINT32 offset=((GETEXTPORT()[0x2a]>>11)&0x1fff)^0x1000; + UINT32 value=m_Tables[offset*2+0x30000/4]; + UINT32 srcexp=(GETEXTPORT()[0x2a]>>24)&0x7f; + + value&=0x7FFFFFFF; + + return ScaleExp(value,0x3f-srcexp); + } + if(offset==0x2b) + { + UINT32 offset=((GETEXTPORT()[0x2a]>>11)&0x1fff)^0x1000; + UINT32 value=m_Tables[offset*2+(0x30000/4)+1]; + UINT32 srcexp=(GETEXTPORT()[0x2a]>>24)&0x7f; + + value&=0x7FFFFFFF; + if(GETEXTPORT()[0x2a]&(1<<31)) + value|=1<<31; + + return ScaleExp(value,0x3f-srcexp); + } + + return GETEXTPORT()[offset]; + } + + addr = ( EB & 0xFFFF0000 ) | ( offset & 0xFFFF ); + + return RDMEM(addr); +} + +void mb86233_cpu_device::SETEXTERNAL( UINT32 EB, UINT32 offset, UINT32 value ) +{ + UINT32 addr; + + if ( EB == 0 && offset >= 0x20 && offset <= 0x2f ) /* TGP Tables in ROM - FIXME - */ + { + GETEXTPORT()[offset] = value; + + if(offset==0x25 || offset==0x24) + { + if((GETEXTPORT()[0x24]&0x7fffffff)<=(GETEXTPORT()[0x25]&0x7fffffff)) + { + GETSR()|=EXTERNAL_FLAG; + } + else + { + GETSR()&=~EXTERNAL_FLAG; + } + } + return; + } + + addr = ( EB & 0xFFFF0000 ) | ( offset & 0xFFFF ); + + WRMEM( addr, value ); +} + + + +/*************************************************************************** + Register Access +***************************************************************************/ + +UINT32 mb86233_cpu_device::GETREGS( UINT32 reg, int source ) +{ + UINT32 mode = ( reg >> 6 ) & 0x07; + + reg &= 0x3f; + + if ( mode == 0 || mode == 1 || mode == 3 ) + { + if ( reg < 0x10 ) + { + return GETGPR(reg); + } + + switch( reg ) + { + case 0x10: /* A */ + return GETA().u; + + case 0x11: /* A.e */ + return (GETA().u >> 23) & 0xff; + + case 0x12: /* A.m */ + return (GETA().u & 0x7fffff) | ((GETA().u&0x80000000) >> 8); + + case 0x13: /* B */ + return GETB().u; + + case 0x14: /* B.e */ + return (GETB().u >> 23) & 0xff; + + case 0x15: /* B.m */ + return (GETB().u & 0x7fffff) | ((GETB().u&0x80000000) >> 8); + + case 0x19: /* D */ + return GETD().u; + + case 0x1A: /* D.e */ + return (GETD().u >> 23) & 0xff; + + case 0x1B: /* D.m */ + return (GETD().u & 0x7fffff) | ((GETD().u&0x80000000) >> 8); + + case 0x1C: /* P */ + return GETP().u; + + case 0x1D: /* P.e */ + return (GETP().u >> 23) & 0xff; + + case 0x1E: /* P.m */ + return (GETP().u & 0x7fffff) | ((GETP().u&0x80000000) >> 8); + + case 0x1F: /* Shift */ + return GETSHIFT(); + + case 0x20: /* Parallel Port */ + logerror( "TGP: Parallel port read at PC:%04x\n", GETPC() ); + return 0; + + case 0x21: /* FIn */ + { + if ( m_fifo_read_ok_cb() == ASSERT_LINE ) + { + return m_fifo_read_cb(); + } + + GETFIFOWAIT() = 1; + return 0; + } + + case 0x22: /* FOut */ + return 0; + + case 0x23: /* EB */ + return GETEB(); + + case 0x34: + return GETREPCNT(); + + default: + fatalerror( "TGP: Unknown GETREG (%d) at PC=%04x\n", reg, GETPC() ); + } + } + else if ( mode == 2 ) /* Indexed */ + { + UINT32 addr = reg & 0x1f; + + if ( source ) + { + if( !( reg & 0x20 ) ) + addr += GETGPR(0); + + addr += GETGPR(2); + } + else + { + if( !( reg & 0x20 ) ) + addr += GETGPR(1); + + addr += GETGPR(3); + } + + return addr; + } + else if( mode == 6 ) /* Indexed with postop */ + { + UINT32 addr = 0; + + if ( source ) + { + if( !( reg & 0x20 ) ) + addr += GETGPR(0); + + addr += GETGPR(2); + } + else + { + if( !( reg & 0x20 ) ) + addr += GETGPR(1); + + addr += GETGPR(3); + } + + if ( reg & 0x10 ) + { + if ( source ) + GETGPR(2) -= 0x20 - ( reg & 0x1f ); + else + GETGPR(3) -= 0x20 - ( reg & 0x1f ); + } + else + { + if ( source ) + GETGPR(2) += ( reg & 0x1f ); + else + GETGPR(3) += ( reg & 0x1f ); + } + + return addr; + } + else + { + fatalerror( "TGP: Unknown GETREG mode %d at PC:%04x\n", mode, GETPC() ); + } + + // never executed + //return 0; +} + +void mb86233_cpu_device::SETREGS( UINT32 reg, UINT32 val ) +{ + int mode = ( reg >> 6) & 0x07; + + reg &= 0x3f; + + if( mode == 0 || mode == 1 || mode == 3 ) + { + if(reg==12 || reg==13) // counter regs seem to be 8 bit only + val&=0xff; + + if ( reg < 0x10 ) + { + GETGPR(reg) = val; + return; + } + + switch( reg ) + { + case 0x10: /* A */ + GETA().u = val; + break; + + case 0x11: /* A.e */ + GETA().u &= ~((0x0000007f) << 23); + GETA().u |= (( val & 0xff ) << 23 ); + break; + + case 0x12: /* A.m */ + GETA().u &= ~( 0x807fffff ); + GETA().u |= ( val & 0x7fffff ); + GETA().u |= ( val & 0x800000 ) << 8; + break; + + case 0x13: /* B */ + GETB().u = val; + break; + + case 0x14: /* B.e */ + GETB().u &= ~((0x0000007f) << 23); + GETB().u |= (( val & 0xff ) << 23 ); + break; + + case 0x15: /* B.m */ + GETB().u &= ~( 0x807fffff ); + GETB().u |= ( val & 0x7fffff ); + GETB().u |= ( val & 0x800000 ) << 8; + break; + + case 0x19: /* D */ + GETD().u = val; + break; + + case 0x1A: /* D.e */ + GETD().u &= ~((0x0000007f) << 23); + GETD().u |= (( val & 0xff ) << 23 ); + break; + + case 0x1B: /* B.m */ + GETD().u &= ~( 0x807fffff ); + GETD().u |= ( val & 0x7fffff ); + GETD().u |= ( val & 0x800000 ) << 8; + break; + + case 0x1C: /* P */ + GETP().u = val; + break; + + case 0x1D: /* P.e */ + GETP().u &= ~((0x000000ff) << 23); + GETP().u |= (( val & 0xff ) << 23 ); + break; + + case 0x1E: /* P.m */ + GETP().u &= ~( 0x807fffff ); + GETP().u |= ( val & 0x7fffff ); + GETP().u |= ( val & 0x800000 ) << 8; + break; + + case 0x1F: + GETSHIFT() = val; + break; + + case 0x20: /* Parallel Port */ + logerror( "TGP: Parallel port write: %08x at PC:%04x\n", val, GETPC() ); + break; + + case 0x22: /* FOut */ + m_fifo_write_cb( val ); + break; + + case 0x23: + GETEB() = val; + break; + + case 0x34: + GETREPCNT() = val; + break; + + default: + fatalerror( "TGP: Unknown register write (r:%d, mode:%d) at PC:%04x\n", reg, mode, GETPC()); + } + } + else + { + fatalerror( "TGP: Unknown register write (r:%d, mode:%d) at PC:%04x\n", reg, mode, GETPC()); + } +} + + +/*************************************************************************** + Addressing Modes +***************************************************************************/ + +UINT32 mb86233_cpu_device::INDIRECT( UINT32 reg, int source ) +{ + UINT32 mode = ( reg >> 6 ) & 0x07; + + if ( mode == 0 || mode == 1 || mode == 3 ) + { + return reg; + } + else if ( mode == 2 ) + { + UINT32 addr = reg & 0x3f; + + if ( source ) + { + if( !(reg & 0x20) ) + addr += GETGPR(0); + + addr += GETGPR(2); + } + else + { + if( !(reg & 0x20) ) + addr += GETGPR(1); + + addr += GETGPR(3); + } + + return addr; + } + else if ( mode == 6 || mode == 7 ) + { + UINT32 addr = 0; + + if ( source ) + { + if ( !( reg & 0x20 ) ) + addr += GETGPR(0); + + addr += GETGPR(2); + } + else + { + if ( !( reg & 0x20 ) ) + addr += GETGPR(1); + + addr += GETGPR(3); + } + + if ( reg & 0x10 ) + { + if ( source ) + GETGPR(2) -= 0x20 - ( reg & 0x1f ); + else + GETGPR(3) -= 0x20 - ( reg & 0x1f ); + } + else + { + if ( source ) + GETGPR(2) += ( reg & 0x1f ); + else + GETGPR(3) += ( reg & 0x1f ); + } + if( mode == 7) + { + if ( source ) + GETGPR(2)&=0x3f; + else + GETGPR(3)&=0x3f; + } + + return addr; + } + else + { + fatalerror( "TGP: Unknown INDIRECT mode %d at PC:%04x\n", mode, GETPC() ); + } + + // never executed + //return 0; +} + +/*************************************************************************** + Core Execution Loop +***************************************************************************/ + +void mb86233_cpu_device::execute_run() +{ + while( m_icount > 0 ) + { + UINT32 val; + UINT32 opcode; + + debugger_instruction_hook(this, GETPC()); + + opcode = ROPCODE(GETPC()); + + GETFIFOWAIT() = 0; + + switch( (opcode >> 26) & 0x3f ) + { + case 0x00: /* dual move */ + { + UINT32 r1 = opcode & 0x1ff; + UINT32 r2 = ( opcode >> 9 ) & 0x7f; + UINT32 alu = ( opcode >> 21 ) & 0x1f; + UINT32 op = ( opcode >> 16 ) & 0x1f; + + ALU( alu ); + + switch( op ) + { + case 0x01: + GETA().u = GETARAM()[INDIRECT(r1,1)]; + GETB().u = GETEXTERNAL( GETEB(),INDIRECT(r2|(2<<6), 0)); + break; + + case 0x04: // ? + GETA().u = GETARAM()[r1]; + GETB().u = GETEXTERNAL( GETEB(),r2); + break; + + case 0x0C: + GETA().u = GETARAM()[INDIRECT(r1,1)]; + GETB().u = GETBRAM()[r2]; + break; + + case 0x0D: // VF2 shadows + GETA().u = GETARAM()[INDIRECT(r1,1)]; + GETB().u = GETBRAM()[INDIRECT(r2|2<<6,0)]; + break; + + case 0x0F: + GETA().u = GETARAM()[r1]; + GETB().u = GETBRAM()[INDIRECT(r2|6<<6,0)]; + break; + + case 0x10: + GETA().u = GETBRAM()[INDIRECT(r1,1)]; + GETB().u = GETARAM()[r2]; + break; + + case 0x11: + GETA().u = GETBRAM()[INDIRECT(r1,1)]; + GETB().u = GETARAM()[INDIRECT(r2|(2<<6),0)]; + break; + + default: + logerror( "TGP: Unknown TGP double move (op=%d) at PC:%x\n", op, GETPC()); + break; + } + } + break; + + case 0x7: /* LD/MOV */ + { + UINT32 r1 = opcode & 0x1ff; + UINT32 r2 = ( opcode >> 9 ) & 0x7f; + UINT32 alu = ( opcode >> 21 ) & 0x1f; + UINT32 op = ( opcode >> 16 ) & 0x1f; + + switch( op ) + { + case 0x04: /* MOV RAM->External */ + { + SETEXTERNAL( GETEB(), r2, GETARAM()[r1]); + ALU(alu); + } + break; + + case 0x0c: /* MOV RAM->BRAM */ + { + GETBRAM()[r2] = GETARAM()[r1]; + ALU(alu); + } + break; + + case 0x0d: /* Move RAM->BRAM indirect? */ + { + val = GETARAM()[r1]; + ALU(alu); + GETBRAM()[INDIRECT(r2|(2<<6),0)] = val; + } + break; + + case 0x1d: /* MOV RAM->Reg */ + { + if ( r1 & 0x180 ) + { + val = GETARAM()[GETREGS(r1,0)]; + } + else + { + val = GETARAM()[r1]; + } + + /* if we're waiting for data, don't complete the instruction */ + if ( GETFIFOWAIT() ) + break; + + ALU(alu); + SETREGS(r2,val); + } + break; + + case 0x1c: /* MOV Reg->RAMInd */ + { + val = GETREGS(r2,1); + + /* if we're waiting for data, don't complete the instruction */ + if ( GETFIFOWAIT() ) + break; + + ALU(alu); + + if ( ( r2 >> 6 ) & 0x01) + { + SETEXTERNAL( GETEB(),INDIRECT(r1,0),val); + } + else + { + GETARAM()[INDIRECT(r1,0)] = val; + } + } + break; + + case 0x1f: /* MOV Reg->Reg */ + { + if ( r1 == 0x10 && r2 == 0xf ) + { + /* NOP */ + ALU( alu); + } + else + { + val = GETREGS(r1,1); + + /* if we're waiting for data, don't complete the instruction */ + if ( GETFIFOWAIT() ) + break; + + ALU(alu); + SETREGS(r2, val); + } + } + break; + + case 0x0f: /* MOV RAMInd->BRAMInd */ + { + val = GETARAM()[INDIRECT(r1,1)]; + ALU(alu); + GETBRAM()[INDIRECT(r2|(6<<6),0)] = val; + } + break; + + case 0x13: /* MOV BRAMInd->RAMInd */ + { + val = GETBRAM()[INDIRECT(r1,1)]; + ALU(alu); + GETARAM()[INDIRECT(r2|(6<<6),0)] = val; + } + break; + + case 0x10: /* MOV RAMInd->RAM */ + { + val = GETBRAM()[INDIRECT(r1,1)]; + ALU(alu); + GETARAM()[r2] = val; + } + break; + + case 0x1e: /* External->Reg */ + { + UINT32 offset; + + if ( (( r2 >> 6 ) & 7) == 1 ) + { + offset = INDIRECT(r1,1); + val = GETEXTERNAL(0,offset); + } + else + { + offset = INDIRECT(r1,0); + val = GETEXTERNAL(GETEB(),offset); + } + + ALU(alu); + SETREGS(r2,val); + } + break; + + case 0x03: /* RAM->External Ind */ + { + val = GETARAM()[r1]; + ALU(alu); + SETEXTERNAL(GETEB(),INDIRECT(r2|(6<<6),0),val); + } + break; + + case 0x07: /* RAMInd->External */ + { + val = GETARAM()[INDIRECT(r1,1)]; + ALU(alu); + SETEXTERNAL( GETEB(),INDIRECT(r2|(6<<6),0),val); + } + break; + + case 0x08: /* External->RAM */ + { + val = GETEXTERNAL( GETEB(),INDIRECT(r1,1)); + ALU(alu); + GETARAM()[r2] = val; + } + break; + + case 0x0b: /* External->RAMInd */ + { + val = GETEXTERNAL( GETEB(),INDIRECT(r1,1)); + ALU( alu); + GETARAM()[INDIRECT(r2|(6<<6),0)] = val; + } + break; + + case 0x17: /* External r2-> RAMInd r3 */ + { + UINT32 offset; + + offset = INDIRECT(r1,1); + + val = GETEXTERNAL( GETEB(), offset); + ALU(alu); + GETARAM()[INDIRECT(r2|(6<<6),0)] = val; + } + break; + case 0x14: + { + UINT32 offset; + + offset = INDIRECT(r1,1); + + val = GETEXTERNAL( 0, offset); + ALU(alu); + GETARAM()[r2] = val; + } + break; + + default: + fatalerror( "TGP: Unknown TGP move (op=%02x) at PC:%x\n", op, GETPC()); + } + } + break; + + case 0x0d: /* CONTROL? */ + { + UINT32 sub = (opcode>>16) & 0xff; + + switch(sub) + { + case 0x0a: // FPU Round Control opcode + m_fpucontrol = opcode & 0xff; + logerror( "TGP: FPU Round CONTROL sets %02x at PC:%x\n", m_fpucontrol, GETPC()); + break; + default: + logerror( "TGP: Unknown CONTROL sub-type %02x at PC:%x\n", sub, GETPC()); + break; + } + + break; + } + + case 0x0e: /* LDIMM24 */ + { + UINT32 sub = (opcode>>24) & 0x03; + UINT32 imm = opcode & 0xffffff; + + /* sign extend 24->32 */ + if ( imm & 0x800000 ) + imm |= 0xFF000000; + + switch( sub ) + { + case 0x00: /* P */ + GETP().u = imm; + break; + + case 0x01: /* A */ + GETA().u = imm; + break; + + case 0x02: /* B */ + GETB().u = imm; + break; + + case 0x03: /* D */ + GETD().u = imm; + break; + } + } + break; + + case 0x0f: /* REP/CLEAR/FLAGS */ + { + UINT32 alu = ( opcode >> 20 ) & 0x1f; + UINT32 sub2 = ( opcode >> 16 ) & 0x0f; + + ALU(alu); + + if( sub2 == 0x00 ) /* CLEAR reg */ + { + UINT32 reg = opcode & 0x1f; + + switch( reg ) + { + case 0x10: + GETD().u = 0; + break; + + case 0x08: + GETB().u = 0; + break; + + case 0x04: + GETA().u = 0; + break; + } + } + else if ( sub2 == 0x04 ) /* REP xxx */ + { + UINT32 sub3 = ( opcode >> 12 ) & 0x0f; + + if ( sub3 == 0 ) + { + GETREPS() = opcode & 0xfff; + + if ( GETREPS() == 0 ) + GETREPS() = 0x100; + + GETPC()++; + } + else if ( sub3 == 8 ) + { + GETREPS() = GETREGS( opcode & 0xfff, 0 ); + GETPC()++; + } + } + else if ( sub2 == 0x02 ) /* CLRFLAGS */ + { + GETSR() &= ~(opcode&0xfff); + } + else if ( sub2 == 0x06 ) /* SETFLAGS */ + { + GETSR() |= (opcode&0xfff); + } + } + break; + + case 0x10: /* LDIMM rx */ + { + UINT32 sub = (opcode>>24) & 0x03; + UINT32 imm = opcode & 0xffff; + + GETGPR(sub) = imm; + } + break; + + case 0x13: /* LDIMM r1x */ + { + UINT32 sub = (opcode>>24) & 0x03; + UINT32 imm = opcode & 0xffffff; + + if ( sub == 0 ) /* R12 */ + GETGPR(12) = imm; + else if ( sub == 1 ) /* R13 */ + GETGPR(13) = imm; + else + logerror( "TGP: Unknown LDIMM r12 (sub=%d) at PC:%04x\n", sub, GETPC() ); + } + break; + + case 0x14: /* LDIMM m,e */ + { + UINT32 sub = (opcode>>24) & 0x03; + UINT32 imm = opcode & 0xffffff; + + if ( sub == 0 ) /* A */ + { + GETA().u = imm; + } + else if ( sub == 1 ) /* A.e */ + { + GETA().u &= ~0x7f800000; + GETA().u |= (imm & 0xff) << 23; + } + else if ( sub == 2 ) /* A.m */ + { + GETA().u &= 0x7f800000; + GETA().u |= (imm & 0x7fffff ) | ((imm & 0x800000) << 8); + } + else + { + fatalerror( "TGP: Unknown LDIMM m,e (sub=%d) at PC:%04x\n", sub, GETPC() ); + } + } + break; + + case 0x15: /* LDIMM m,e */ + { + UINT32 sub = (opcode>>24) & 0x03; + UINT32 imm = opcode & 0xffffff; + + if ( sub == 0 ) /* B.e again? */ + { + //GETB().u = ((imm & 0x7f) << 23) | ((imm & 0xff) << 8) | ( imm & 0xff ); + GETB().u &= ~0x7f800000; + GETB().u |= (imm & 0xff) << 23; + } + else if ( sub == 1 ) /* B.e */ + { + GETB().u &= ~0x7f800000; + GETB().u |= (imm & 0xff) << 23; + } + else if ( sub == 2 ) /* B.m */ + { + GETB().u &= 0x7f800000; + GETB().u |= (imm & 0x7fffff ) | ((imm & 0x800000) << 8); + } + else + { + fatalerror( "TGP: Unknown LDIMM m,e (sub=%d) at PC:%04x\n", sub, GETPC() ); + } + } + break; + + case 0x16: /* LDIMM m,e */ + { + UINT32 sub = (opcode>>24) & 0x03; + UINT32 imm = opcode & 0xffffff; + + if ( sub == 1 ) /* clear + D.m */ + { + GETD().u = (imm & 0x7fffff ) | ((imm & 0x800000) << 8); + } + else if ( sub == 2 ) /* D.e */ + { + GETD().u &= ~0x7f800000; + GETD().u |= (imm & 0xff) << 23; + } + else if ( sub == 3 ) /* D.m */ + { + GETD().u &= 0x7f800000; + GETD().u |= (imm & 0x7fffff ) | ((imm & 0x800000) << 8); + } + else + { + fatalerror( "TGP: Unknown LDIMM m,e (sub=%d) at PC:%04x\n", sub, GETPC() ); + } + } + break; + + case 0x17: /* LDIMM special reg */ + { + UINT32 sub = (opcode>>24) & 0x03; + UINT32 imm = opcode & 0xffffff; + + if ( sub == 0x03 ) + { + GETSHIFT() = imm; + } + else + { + logerror( "TGP: Unknown LDIMM special reg (sub=%d) at PC:%04x\n", sub, GETPC() ); + } + } + break; + + case 0x18: /* LDIMM external reg */ + { + UINT32 sub = (opcode>>24) & 0x03; + UINT32 imm = opcode & 0xffffff; + + if ( sub == 0x03 ) + { + GETEB() = imm; + } + else + { + fatalerror( "TGP: Unknown LDIMM external reg (sub=%d) at PC:%04x\n", sub, GETPC() ); + } + } + break; + + case 0x1d: //LDIMM to Rep regs + { + UINT32 sub = (opcode>>24)&0x3; + UINT32 imm = opcode&0xffffff; + if(sub == 0x00) + { + GETREPCNT() = imm; + } + else + { + fatalerror( "TGP: Unknown LDIMM REPCnt (sub=%d) at PC:%04x\n", sub, GETPC() ); + } + } + break; + + case 0x2f: /* Conditional Branches */ + { + UINT32 cond = ( opcode >> 20 ) & 0x1f; + UINT32 subtype = ( opcode >> 16 ) & 0x0f; + UINT32 data = opcode & 0xffff; + + if( COND( cond) ) + { + switch( subtype ) + { + case 0x00: /* BRIF */ + GETPC() = data - 1; + break; + + case 0x02: /* BRIF indirect */ + data = GETREGS(data&0x7f,0) - 1; + + /* if we're waiting for data, don't complete the instruction */ + if ( GETFIFOWAIT() ) + break; + + GETPC() = data; + break; + + case 0x04: /* BSIF */ + GETPCS()[GETPCSP()] = GETPC(); + GETPCSP()++; + GETPC() = data - 1; + break; + + case 0x06: /* BSIF indirect */ + GETPCS()[GETPCSP()] = GETPC(); + GETPCSP()++; + if ( data & 0x4000 ) + data = GETREGS(data&0x7f,0) - 1; + else + data = ((GETARAM()[data&0x3ff])&0xffff)-1; + + /* if we're waiting for data, don't complete the instruction */ + if ( GETFIFOWAIT() ) + break; + + GETPC() = data; + break; + + case 0x0a: /* RTIF */ + --GETPCSP(); + GETPC() = GETPCS()[GETPCSP()]; + break; + + case 0x0c: /* LDIF */ + SETREGS(((data>>9)&0x7f), GETARAM()[data&0x1FF] ); + break; + + case 0x0e: /* RIIF */ + fatalerror( "TGP: RIIF unimplemented at PC:%04x\n", GETPC() ); + + default: + fatalerror( "TGP: Unknown Branch opcode (subtype=%d) at PC:%04x\n", subtype, GETPC() ); + } + } + } + break; + + case 0x3f: /* Inverse Conditional Branches */ + { + UINT32 cond = ( opcode >> 20 ) & 0x1f; + UINT32 subtype = ( opcode >> 16 ) & 0x0f; + UINT32 data = opcode & 0xffff; + + if( !COND( cond) ) + { + switch( subtype ) + { + case 0x00: /* BRUL */ + GETPC() = data - 1; + break; + + case 0x02: /* BRUL indirect */ + data = GETREGS(data&0x7f,0) - 1; + + /* if we're waiting for data, don't complete the instruction */ + if ( GETFIFOWAIT() ) + break; + + GETPC() = data; + break; + + case 0x04: /* BSUL */ + GETPCS()[GETPCSP()] = GETPC(); + GETPCSP()++; + GETPC() = data - 1; + break; + + case 0x06: /* BSUL indirect */ + data = GETARAM()[data] - 1; + + /* if we're waiting for data, don't complete the instruction */ + if ( GETFIFOWAIT() ) + break; + + GETPC() = data; + break; + + case 0x0a: /* RTUL */ + --GETPCSP(); + GETPC() = GETPCS()[GETPCSP()]; + break; + + case 0x0c: /* LDUL */ + SETREGS(((data>>9)&0x7f), GETARAM()[data&0x1FF] ); + break; + + case 0x0e: /* RIUL */ + fatalerror( "TGP: RIUL unimplemented at PC:%04x\n", GETPC() ); + + default: + fatalerror( "TGP: Unknown Branch opcode (subtype=%d) at PC:%04x\n", subtype, GETPC() ); + } + } + } + break; + + case 0x1f: + case 0x12: + logerror( "TGP: unknown opcode %08x at PC:%04x (%02x)\n", opcode, GETPC(),(opcode >> 26) & 0x3f ); + break; + + default: + fatalerror( "TGP: unknown opcode %08x at PC:%04x (%02x)\n", opcode, GETPC(),(opcode >> 26) & 0x3f ); + } + + if ( GETFIFOWAIT() == 0 ) + { + if( GETREPS() == 0 ) + GETPC()++; + else + --GETREPS(); + + m_icount--; + } + else + { + m_icount = 0; + } + } +} diff --git a/src/devices/cpu/mb86233/mb86233.h b/src/devices/cpu/mb86233/mb86233.h new file mode 100644 index 00000000000..a52f419e66d --- /dev/null +++ b/src/devices/cpu/mb86233/mb86233.h @@ -0,0 +1,145 @@ +// license:BSD-3-Clause +// copyright-holders:Ernesto Corvi +#pragma once + +#ifndef __MB86233_H__ +#define __MB86233_H__ + + +/*************************************************************************** + REGISTER ENUMERATION +***************************************************************************/ + +enum +{ + MB86233_PC=1, + MB86233_A, + MB86233_B, + MB86233_D, + MB86233_P, + MB86233_REP, + MB86233_SP, + MB86233_EB, + MB86233_SHIFT, + MB86233_FLAGS, + MB86233_R0, + MB86233_R1, + MB86233_R2, + MB86233_R3, + MB86233_R4, + MB86233_R5, + MB86233_R6, + MB86233_R7, + MB86233_R8, + MB86233_R9, + MB86233_R10, + MB86233_R11, + MB86233_R12, + MB86233_R13, + MB86233_R14, + MB86233_R15 +}; + + +#define MCFG_MB86233_FIFO_READ_CB(_devcb) mb86233_cpu_device::set_fifo_read_cb(*device, DEVCB_##_devcb); +#define MCFG_MB86233_FIFO_READ_OK_CB(_devcb) mb86233_cpu_device::set_fifo_read_ok_cb(*device, DEVCB_##_devcb); +#define MCFG_MB86233_FIFO_WRITE_CB(_devcb) mb86233_cpu_device::set_fifo_write_cb(*device, DEVCB_##_devcb); +#define MCFG_MB86233_TABLE_REGION(_region) mb86233_cpu_device::set_tablergn(*device, _region); + + +class mb86233_cpu_device : public cpu_device +{ +public: + // construction/destruction + mb86233_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // static configuration helpers + template static devcb_base &set_fifo_read_cb(device_t &device, _Object object) { return downcast(device).m_fifo_read_cb.set_callback(object); } + template static devcb_base &set_fifo_read_ok_cb(device_t &device, _Object object) { return downcast(device).m_fifo_read_ok_cb.set_callback(object); } + template static devcb_base &set_fifo_write_cb(device_t &device, _Object object) { return downcast(device).m_fifo_write_cb.set_callback(object); } + static void set_tablergn(device_t &device, const char *tablergn) { downcast(device).m_tablergn = tablergn; } + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_execute_interface overrides + virtual UINT32 execute_min_cycles() const { return 1; } + virtual UINT32 execute_max_cycles() const { return 2; } + virtual UINT32 execute_input_lines() const { return 0; } + virtual void execute_run(); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const { return (spacenum == AS_PROGRAM) ? &m_program_config : ( (spacenum == AS_DATA) ? &m_data_config : NULL ); } + + // device_state_interface overrides + void state_string_export(const device_state_entry &entry, std::string &str); + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const { return 4; } + virtual UINT32 disasm_max_opcode_bytes() const { return 4; } + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + +private: + address_space_config m_program_config; + address_space_config m_data_config; + + union MB86233_REG + { + INT32 i; + UINT32 u; + float f; + }; + + UINT16 m_pc; + MB86233_REG m_a; + MB86233_REG m_b; + MB86233_REG m_d; + MB86233_REG m_p; + + UINT16 m_reps; + UINT16 m_pcs[4]; + UINT8 m_pcsp; + UINT32 m_eb; + UINT32 m_shift; + UINT32 m_repcnt; + UINT16 m_sr; + UINT8 m_fpucontrol; + + UINT32 m_gpr[16]; + UINT32 m_extport[0x30]; + + address_space *m_program; + direct_read_data *m_direct; + int m_icount; + + /* FIFO */ + int m_fifo_wait; + devcb_read32 m_fifo_read_cb; + devcb_read_line m_fifo_read_ok_cb; + devcb_write32 m_fifo_write_cb; + const char *m_tablergn; + + /* internal RAM */ + UINT32 m_RAM[2 * 0x200]; + UINT32 *m_ARAM, *m_BRAM; + UINT32 *m_Tables; + + void FLAGSF( float v ); + void FLAGSI( UINT32 v ); + int COND( UINT32 cond ); + void ALU( UINT32 alu); + UINT32 ScaleExp(unsigned int v,int scale); + UINT32 GETEXTERNAL( UINT32 EB, UINT32 offset ); + void SETEXTERNAL( UINT32 EB, UINT32 offset, UINT32 value ); + UINT32 GETREGS( UINT32 reg, int source ); + void SETREGS( UINT32 reg, UINT32 val ); + UINT32 INDIRECT( UINT32 reg, int source ); + +}; + + +extern const device_type MB86233; + +#endif /* __MB86233_H__ */ diff --git a/src/devices/cpu/mb86233/mb86233d.c b/src/devices/cpu/mb86233/mb86233d.c new file mode 100644 index 00000000000..6e27c3b4d06 --- /dev/null +++ b/src/devices/cpu/mb86233/mb86233d.c @@ -0,0 +1,784 @@ +// license:BSD-3-Clause +// copyright-holders:Ernesto Corvi +#include "emu.h" +#include "debugger.h" +#include "mb86233.h" + +static char * COND(unsigned int cond) +{ + static char bufs[4][256]; + static int bufindex = 0; + char *buf = &bufs[bufindex++][0]; + + bufindex &= 3; + + switch(cond) + { + case 0x16: + sprintf(buf,"always"); + return buf; + + case 0x00: + sprintf(buf,"eq"); + return buf; + + case 0x01: + sprintf(buf,"ge"); + return buf; + + case 0x02: + sprintf(buf,"le"); + return buf; + + case 0x06: + sprintf(buf,"never"); + return buf; + + case 0x10: + sprintf(buf,"(--r12)!=0"); + return buf; + + case 0x11: + sprintf(buf,"(--r13)!=0"); + return buf; + } + + sprintf(buf,"unk (%x)",cond); + return buf; +} + +static char * REGS( UINT32 reg, int IsSource ) +{ + static char bufs[4][256]; + static int bufindex = 0; + char *buf = &bufs[bufindex++][0]; + int mode = (reg >> 6 ) & 0x07; + + bufindex &= 3; + + reg &= 0x3f; + + if ( mode == 0 || mode == 1 || mode == 3 ) + { + if ( reg < 0x10 ) + { + sprintf(buf,"r%d",reg); + return buf; + } + + switch(reg) + { + case 0x10: + sprintf(buf,"a"); + break; + + case 0x11: + sprintf(buf,"a.e"); + break; + + case 0x12: + sprintf(buf,"a.m"); + break; + + case 0x13: + sprintf(buf,"b"); + break; + + case 0x14: + sprintf(buf,"b.e"); + break; + + case 0x15: + sprintf(buf,"b.m"); + break; + + case 0x19: + sprintf(buf,"d"); + break; + + case 0x1a: + sprintf(buf,"d.e"); + break; + + case 0x1b: + sprintf(buf,"d.m"); + break; + + case 0x1c: + sprintf(buf,"p"); + break; + + case 0x1d: + sprintf(buf,"p.e"); + break; + + case 0x1e: + sprintf(buf,"p.m"); + break; + + case 0x1f: + sprintf(buf,"shift"); + break; + + case 0x20: + sprintf(buf,"parport"); + break; + + case 0x21: + sprintf(buf,"FIn"); + break; + + case 0x22: + sprintf(buf,"FOut"); + break; + + case 0x23: + sprintf(buf,"EB"); + break; + + default: + sprintf(buf,"Unkreg (%x)",reg); + break; + } + } + else if ( mode == 2 ) + { + char *p = buf; + + p += sprintf(p,"0x%x+",reg & 0x1f); + + if ( IsSource ) + { + if ( !( reg & 0x20 ) ) + p += sprintf(p,"r0+"); + + p += sprintf(p,"r2"); + } + else + { + if ( !( reg & 0x20 ) ) + p += sprintf(p,"r1+"); + + p += sprintf(p,"r3"); + } + } + else if ( mode == 6 ) + { + char *p = buf; + + if ( IsSource ) + { + if ( !( reg & 0x20 ) ) + p += sprintf(p,"r0+"); + + p += sprintf(p,"r2"); + } + else + { + if ( !( reg & 0x20 ) ) + p += sprintf(p,"r1+"); + + p += sprintf(p,"r3"); + } + + if ( reg & 0x10 ) + p += sprintf(p,"--%d", 0x20 - ( reg & 0x1f ) ); + else + p += sprintf(p,"++%d", reg & 0x1f ); + } + else + { + sprintf(buf,"UNKMOD %x (0x%x)", mode, reg); + } + + return buf; +} + +static char * INDIRECT( UINT32 reg, int IsSource ) +{ + static char bufs[4][256]; + static int bufindex = 0; + char *buf = &bufs[bufindex++][0]; + int mode = ( reg >> 6 ) & 0x07; + + bufindex &= 3; + + if ( mode == 0 || mode == 3 || mode == 1) + { + sprintf(buf,"0x%x",reg); + } + else if ( mode == 2 ) + { + char *p = buf; + + p += sprintf(p,"0x%x+",reg&0x1f); + + if ( IsSource ) + { + if ( !(reg & 0x20) ) + p += sprintf(p,"r0+"); + + p += sprintf(p,"r2"); + } + else + { + if ( !(reg & 0x20) ) + p += sprintf(p,"r1+"); + + p += sprintf(p,"r3"); + } + } + else if ( mode == 6 || mode == 7 ) + { + char *p = buf; + + if ( IsSource ) + { + if ( !( reg & 0x20 ) ) + p += sprintf(p,"r0+"); + + p += sprintf(p,"r2"); + } + else + { + if( !( reg & 0x20 ) ) + p += sprintf(p,"r1+"); + + p += sprintf(p,"r3"); + } + + if ( reg & 0x10 ) + p += sprintf(p,"--%d",0x20 - ( reg & 0x1f )); + else + p += sprintf(p,"++%d",reg & 0x1f); + } + else + { + sprintf(buf,"UNKMOD %x (0x%x)", mode, reg); + } + + return buf; +} + + +static char * ALU( UINT32 alu) +{ + static char bufs[4][256]; + static int bufindex = 0; + char *buf = &bufs[bufindex++][0]; + + bufindex &= 3; + + switch( alu ) + { + case 0x0: + buf[0] = 0; + break; + + case 0x1: + sprintf(buf,"d=d&a"); + break; + + case 0x2: + sprintf(buf,"d=d|a"); + break; + + case 0x3: + sprintf(buf,"d=d^a"); + break; + + case 0x5: + sprintf(buf,"cmp d,a"); + break; + + case 0x6: + sprintf(buf,"d=d+a"); + break; + + case 0x7: + sprintf(buf,"d=d-a"); + break; + + case 0x8: + sprintf(buf,"p=a*b"); + break; + + case 0x9: + sprintf(buf,"d=d+p, p=a*b"); + break; + + case 0xa: + sprintf(buf,"d=d-p, p=a*b"); + break; + + case 0xb: + sprintf(buf,"d=fabs d"); + break; + + case 0xc: + sprintf(buf,"d=d+p"); + break; + + case 0xd: + sprintf(buf,"d=p, p=a*b"); + break; + + case 0xe: + sprintf(buf,"d=float(d)"); + break; + + case 0xf: + sprintf(buf,"d=int(d)"); + break; + + case 0x10: + sprintf(buf,"d=d/a"); + break; + + case 0x11: + sprintf(buf,"d=-d"); + break; + + case 0x13: + sprintf(buf,"d=a+b"); + break; + + case 0x14: + sprintf(buf,"d=b-a"); + break; + + case 0x16: + sprintf(buf,"d=(lsr d,shift)"); + break; + + case 0x17: + sprintf(buf,"d=(lsl d,shift)"); + break; + + case 0x18: + sprintf(buf,"d=(asr d,shift)"); + break; + + case 0x1a: + sprintf(buf,"d=d+a (int)"); + break; + + case 0x1b: + sprintf(buf,"d=d-a (int)"); + break; + + default: + sprintf(buf,"ALU UNK(%x)",alu); + break; + } + + return buf; +} + +static unsigned dasm_mb86233(char *buffer, UINT32 opcode ) +{ + char *p = buffer; + UINT32 grp = ( opcode >> 26 ) & 0x3f; + + switch( grp ) + { + case 0x0: /* Dual move */ + { + UINT32 r1=opcode & 0x1ff; + UINT32 r2=(opcode>>9) & 0x7f; + UINT32 alu=(opcode>>21) & 0x1f; + UINT32 op=(opcode>>16) & 0x1f; + + if ( alu != 0 ) + p += sprintf(p, "%s, ", ALU(alu) ); + + switch( op ) + { + case 0x0c: /* a = RAM[addr], b = BRAM[addr] */ + p += sprintf(p,"LAB RAM(0x%x)->a,BRAM(0x%x)->b",r1,r2); + break; + + case 0x0d: /* a = RAM[addr], b = BRAM[addr] */ + p += sprintf(p,"LAB RAM(0x%x)->a,BRAM(%s)->b",r1,INDIRECT(r2|(2<<6),0)); + break; + + case 0x0f: /* a = RAM[addr], b = BRAM[reg] */ + p += sprintf(p,"LAB RAM(0x%x)->a,BRAM(%s)->b",r1,INDIRECT(r2|(6<<6),0)); + break; + + case 0x10: /* a = BRAM[reg], b = RAM[addr] */ + p += sprintf(p,"LAB BRAM(%s)->a,RAM(0x%x)->b",INDIRECT(r1,1),r2); + break; + + default: + p += sprintf(p,"UNKDUAL (%x)",op); + break; + } + } + break; + + case 0x7: /* LD/MOV */ + { + UINT32 r1=opcode & 0x1ff; + UINT32 r2=(opcode>>9) & 0x7f; + UINT32 alu=(opcode>>21) & 0x1f; + UINT32 op=(opcode>>16) & 0x1f; + + if ( alu != 0 ) + { + p += sprintf(p, "%s", ALU(alu) ); + + if ( !(op == 0x1f && r1 == 0x10 && r2 == 0x0f) ) + p += sprintf(p, ", "); + } + + switch(op) + { + case 0x03: /* RAM->External Indirect */ + { + p += sprintf(p,"MOV RAM(0x%x)->E(EB+%s)",r1,INDIRECT(r2|(6<<6),0)); + } + break; + + case 0x04: /* MOV RAM->External */ + { + p += sprintf(p,"MOV RAM(0x%x)->E(EB+0x%x)",r1,r2); + } + break; + + case 0x07: /* RAMInd->External */ + { + p += sprintf(p,"MOV RAM(%s)->E(EB+%s)",INDIRECT(r1,1),INDIRECT(r2|(6<<6),0)); + } + break; + + case 0x08: /* External->RAM */ + { + p += sprintf(p,"MOV EXT(EB+"); + p += sprintf(p,"%s",INDIRECT(r1,1)); + p += sprintf(p,")->RAM(0x%x)",r2); + } + break; + + case 0x0b: /* External->RAMInd */ + { + int mode = ( r1 >> 6 ) & 0x07; + + p += sprintf(p,"MOV EXT(EB+"); + + if ( mode == 0 || mode == 3 || mode == 1 ) + p += sprintf(p,"RAM("); + + p += sprintf(p,"%s",INDIRECT(r1,1)); + + if ( mode == 0 || mode == 3 || mode == 1) + p += sprintf(p,")"); + + p += sprintf(p,")->RAM(%s)",INDIRECT(r2|(6<<6),0)); + } + break; + + case 0x0c: /* MOV RAM->BRAM */ + p += sprintf(p,"MOV RAM(0x%x)->BRAM(0x%x)",r1,r2); + break; + + case 0x0f: /* MOV RAMInd->BRAMInd */ + p += sprintf(p,"MOV RAM(%s)->BRAM(%s)",INDIRECT(r1,1),INDIRECT(r2|(6<<6),0)); + break; + + case 0x10: /* MOV BRAMInd->RAM */ + p += sprintf(p,"MOV BRAM(%s)->RAM(0x%x)",INDIRECT(r1,1),r2); + break; + + case 0x13: /* MOV BRAMInd->RAMInd */ + p += sprintf(p,"MOV BRAM(%s)->RAM(%s)",INDIRECT(r1,1),INDIRECT(r2|(6<<6),0)); + break; + + case 0x1c: /* MOV Reg->RAMInd */ + if ( ( r2 >> 6 ) & 0x01) + { + p += sprintf(p,"MOV %s->EXT(EB+%s)",REGS(r2,1),INDIRECT(r1,0)); + } + else + { + p += sprintf(p,"MOV %s->RAM(%s)",REGS(r2,1),INDIRECT(r1,0)); + } + break; + + case 0x1d: /* MOV RAM->Reg */ + { + if ( r1 & 0x180 ) + { + p += sprintf(p,"MOV RAM(%s)->%s",REGS(r1,0),REGS(r2,0)); + } + else + { + p += sprintf(p,"MOV RAM(0x%x)->%s",r1,REGS(r2,0)); + } + } + break; + + case 0x1e: /* External->Reg */ + { + int mode2 = (r2 >> 6) & 1; + p += sprintf(p,"MOV EXT(EB+%s)->%s",INDIRECT(r1,mode2),REGS(r2,0)); + } + break; + + case 0x1f: /* MOV Reg->Reg */ + if ( !(r1 == 0x10 && r2 == 0x0f) ) + { + p += sprintf(p,"MOV %s->%s",REGS(r1,1),REGS(r2,0)); + } + break; + + default: + p += sprintf(p,"UNKMV (0x%x)",op); + break; + } + } + break; + + case 0x0e: /* Load 24 bit val */ + { + UINT32 sub=(opcode>>24)&0x3; + static const char regs[4] = { 'p', 'a', 'b', 'd' }; + + p += sprintf(p,"LDIMM24 0x%X->%c",opcode&0xffffff, regs[sub]); + } + break; + + case 0x0f: /* repeat */ + { + UINT32 alu = ( opcode >> 20 ) & 0x1f; + UINT32 sub2 = ( opcode >> 16 ) & 0x0f; + + if ( alu != 0 ) + p += sprintf(p, "%s, ", ALU(alu) ); + + if ( sub2 == 0x00 ) + { + p += sprintf(p,"CLEAR "); + + switch( opcode & 0x3f ) + { + case 0x04: p += sprintf(p, "a" ); break; + case 0x08: p += sprintf(p, "b" ); break; + case 0x10: p += sprintf(p, "d" ); break; + default: p += sprintf(p, "UNKNOWN REG(%x)",opcode&0x3F); break; + } + } + else if ( sub2 == 0x02 ) + p += sprintf(p,"CLRFLAG 0x%x",opcode&0xffff); + else if ( sub2==0x4 ) + { + if ( (opcode & 0xfff) == 0 ) + p += sprintf(p,"REP 0x100"); + else + p += sprintf(p,"REP 0x%x",opcode&0xff); + } + else if ( sub2 == 0x06 ) + p += sprintf(p,"SETFLAG 0x%x",opcode&0xffff); + } + break; + + case 0x10: + { + UINT32 dst=(opcode>>24)&0xf; + UINT32 imm=(opcode)&0xFFFF; + + if ( dst <= 3 ) + p += sprintf(p,"LDIMM 0x%x->r%d",imm,dst); + else + p += sprintf(p,"LDIMM 0x%x->UNKDST(0x%x)",imm,dst); + } + break; + + case 0x13: + { + UINT32 sub = ( opcode >> 24 ) & 0x03; + + p += sprintf(p,"LDIMM 0x%X->",opcode&0xffffff); + + if ( sub == 0 ) p += sprintf(p,"r12"); + else if ( sub == 1 ) p += sprintf(p,"r13"); + else p += sprintf(p,"UNKREG(%x)", sub); + } + break; + + case 0x14: + { + UINT32 sub = ( opcode >> 24 ) & 0x03; + + p += sprintf(p,"LDIMM 0x%X->",opcode&0xffffff); + + if ( sub == 0 ) p += sprintf(p,"a.exp"); + else if ( sub == 1 ) p += sprintf(p,"a.e"); + else if ( sub == 2 ) p += sprintf(p,"a.m"); + else p += sprintf(p,"UNKREG(%x)", sub); + } + break; + + case 0x15: + { + UINT32 sub = ( opcode >> 24 ) & 0x03; + + p += sprintf(p,"LDIMM 0x%X->",opcode&0xffffff); + + if ( sub == 0 ) p += sprintf(p,"b.exp"); + else if ( sub == 1 ) p += sprintf(p,"b.e"); + else if ( sub == 2 ) p += sprintf(p,"b.m"); + else p += sprintf(p,"UNKREG(%x)", sub); + } + break; + + case 0x16: + { + UINT32 sub = ( opcode >> 24 ) & 0x03; + + p += sprintf(p,"LDIMM 0x%X->",opcode&0xffffff); + + if ( sub == 2 ) p += sprintf(p,"d.e"); + else if ( sub == 3 ) p += sprintf(p,"d.m"); + else p += sprintf(p,"UNKREG(%x)", sub); + } + break; + + case 0x17: + { + UINT32 sub = ( opcode >> 24 ) & 0x03; + + p += sprintf(p,"LDIMM 0x%X->",opcode&0xffffff); + + if ( sub == 0x03 ) p += sprintf(p,"shift"); + else p += sprintf(p,"UNKREG(%x)", sub); + } + break; + + case 0x18: + { + UINT32 sub = ( opcode >> 24 ) & 0x03; + + p += sprintf(p,"LDIMM24 0x%X->",opcode&0xffffff); + + if ( sub == 0x03 ) p += sprintf(p,"EB"); + else p += sprintf(p,"UNKREG(%x)", sub); + } + break; + + case 0x2f: + { + UINT32 cond = ( opcode >> 20 ) & 0x1f; + UINT32 subtype = ( opcode >> 16 ) & 0x0f; + UINT32 data = opcode & 0xffff; + + switch( subtype ) + { + case 0: + p += sprintf(p,"BRIF %s 0x%X", COND(cond), data); + break; + + case 2: + p += sprintf(p,"BRIF %s ", COND(cond)); + if ( data & 0x4000 ) + p += sprintf(p,"%s",REGS(data&0x3f,0)); + else + p += sprintf(p,"RAM(0x%x)",data); + break; + + case 4: + p += sprintf(p,"BSIF %s 0x%X", COND(cond), data); + break; + + case 0x6: + p += sprintf(p,"BSIF %s ", COND(cond)); + if ( data & 0x4000 ) + p += sprintf(p,"%s",REGS(data&0x3f,0)); + else + p += sprintf(p,"RAM(0x%x)",data); + break; + + case 0xa: + p += sprintf(p,"RTIF %s", COND(cond)); + break; + + case 0xc: + p += sprintf(p,"LDIF %s RAM(0x%x)->%s", COND(cond),data&0x1ff,REGS((data>>9)&0x3f,0)); + break; + + case 0xe: + p += sprintf(p,"RIIF %s", COND(cond)); + break; + + default: + p += sprintf(p,"UNKG5 (%x cond %x)",subtype,cond); + break; + } + } + break; + + case 0x3f: + { + UINT32 cond = ( opcode >> 20 ) & 0x1f; + UINT32 subtype = ( opcode >> 16 ) & 0x0f; + UINT32 data = opcode & 0xffff; + + switch( subtype ) + { + case 0: + p += sprintf(p,"BRUL %s 0x%X", COND(cond), data); + break; + + case 2: + p += sprintf(p,"BRUL %s ", COND(cond)); + if ( data & 0x4000 ) + p += sprintf(p,"%s",REGS(data&0x3f,0)); + else + p += sprintf(p,"RAM(0x%x)",data); + break; + + case 4: + p += sprintf(p,"BSUL %s 0x%X", COND(cond), data); + break; + + case 0x6: + p += sprintf(p,"BSUL %s ", COND(cond)); + if ( data & 0x4000 ) + p += sprintf(p,"%s",REGS(data&0x3f,0)); + else + p += sprintf(p,"RAM(0x%x)",data); + break; + + case 0xa: + p += sprintf(p,"RTUL %s", COND(cond)); + break; + + case 0xc: + p += sprintf(p,"LDUL %s RAM(0x%x)->%s", COND(cond),data&0x1ff,REGS((data>>9)&0x3f,0)); + break; + + case 0xe: + p += sprintf(p,"RIUL %s", COND(cond)); + break; + + default: + p += sprintf(p,"UNKG5 (%x cond %x)",subtype,cond); + break; + } + } + break; + + default: + p += sprintf(p,"UNKOP"); + break; + } + + return (1 | DASMFLAG_SUPPORTED); +} + +CPU_DISASSEMBLE( mb86233 ) +{ + UINT32 op = *(UINT32 *)oprom; + op = LITTLE_ENDIANIZE_INT32(op); + return dasm_mb86233(buffer, op); +} diff --git a/src/devices/cpu/mb86235/mb86235.c b/src/devices/cpu/mb86235/mb86235.c new file mode 100644 index 00000000000..c68a66e4e7b --- /dev/null +++ b/src/devices/cpu/mb86235/mb86235.c @@ -0,0 +1,129 @@ +// license:BSD-3-Clause +// copyright-holders:Angelo Salese, ElSemi +/***************************************************************************** + * + * MB86235 "TGPx4" (c) Fujitsu + * + * Written by Angelo Salese & ElSemi + * + * TODO: + * - Everything! + * + *****************************************************************************/ + +#include "emu.h" +#include "debugger.h" +#include "mb86235.h" + + +const device_type MB86235 = &device_creator; + + + + + +#define mb86235_readop(A) m_program->read_dword(A) +#define mb86235_readmem(A) m_program->read_dword(A) +#define mb86235_writemem(A,B) m_program->write_dword((A),B) + + +/*********************************** + * illegal opcodes + ***********************************/ +void mb86235_cpu_device::mb86235_illegal() +{ + //logerror("mb86235 illegal opcode at 0x%04x\n", m_pc); + m_icount -= 1; +} + +/* Execute cycles */ +void mb86235_cpu_device::execute_run() +{ + UINT32 opcode; + + do + { + debugger_instruction_hook(this, m_pc); + + opcode = mb86235_readop(m_pc); + //m_pc++; + + switch( opcode ) + { + default: + mb86235_illegal(); + break; + } + + } while( m_icount > 0 ); +} + + +void mb86235_cpu_device::device_start() +{ + m_program = &space(AS_PROGRAM); + + save_item(NAME(m_pc)); + save_item(NAME(m_flags)); + + // Register state for debugger + //state_add( CP1610_R0, "PC", m_pc ).formatstr("%02X"); + state_add( STATE_GENPC, "curpc", m_pc ).noshow(); + state_add( STATE_GENFLAGS, "GENFLAGS", m_flags ).noshow(); + + m_icountptr = &m_icount; +} + +void mb86235_cpu_device::device_reset() +{ +} + +#if 0 +void mb86235_cpu_device::execute_set_input(int irqline, int state) +{ + switch(irqline) + { + case MB86235_INT_INTRM: + m_intrm_pending = (state == ASSERT_LINE); + m_intrm_state = state; + break; + case MB86235_RESET: + if (state == ASSERT_LINE) + m_reset_pending = 1; + m_reset_state = state; + break; + case MB86235_INT_INTR: + if (state == ASSERT_LINE) + m_intr_pending = 1; + m_intr_state = state; + break; + } +} +#endif + +mb86235_cpu_device::mb86235_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : cpu_device(mconfig, MB86235, "MB86235", tag, owner, clock, "mb86235", __FILE__) + , m_program_config("program", ENDIANNESS_LITTLE, 32, 32, -2) +{ +} + + +void mb86235_cpu_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + switch (entry.index()) + { + case STATE_GENFLAGS: + strprintf(str, "%c%c%c%c", + m_flags & 0x80 ? 'S':'.', + m_flags & 0x40 ? 'Z':'.', + m_flags & 0x20 ? 'V':'.', + m_flags & 0x10 ? 'C':'.'); + break; + } +} + +offs_t mb86235_cpu_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( mb86235 ); + return CPU_DISASSEMBLE_NAME(mb86235)(this, buffer, pc, oprom, opram, options); +} diff --git a/src/devices/cpu/mb86235/mb86235.h b/src/devices/cpu/mb86235/mb86235.h new file mode 100644 index 00000000000..f7fc4e51bf1 --- /dev/null +++ b/src/devices/cpu/mb86235/mb86235.h @@ -0,0 +1,70 @@ +// license:BSD-3-Clause +// copyright-holders:Angelo Salese, ElSemi +/***************************************************************************** + * + * template for CPU cores + * + *****************************************************************************/ + +#pragma once + +#ifndef __MB86235_H__ +#define __MB86235_H__ + +#if 0 +enum +{ + MB86235_R0=1, MB86235_R1, MB86235_R2, MB86235_R3, + MB86235_R4, MB86235_R5, MB86235_R6, MB86235_R7 +}; +#endif + + +class mb86235_cpu_device : public cpu_device +{ +public: + // construction/destruction + mb86235_cpu_device(const machine_config &mconfig, const char *_tag, device_t *_owner, UINT32 _clock); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_execute_interface overrides + virtual UINT32 execute_min_cycles() const { return 1; } + virtual UINT32 execute_max_cycles() const { return 7; } + virtual UINT32 execute_input_lines() const { return 0; } + virtual void execute_run(); + //virtual void execute_set_input(int inputnum, int state); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const { return (spacenum == AS_PROGRAM) ? &m_program_config : NULL; } + + // device_state_interface overrides + void state_string_export(const device_state_entry &entry, std::string &str); + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const { return 8; } + virtual UINT32 disasm_max_opcode_bytes() const { return 8; } + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + +private: + address_space_config m_program_config; + + UINT8 m_pc; /* registers */ + UINT8 m_flags; /* flags */ + address_space *m_program; + int m_icount; + + void mb86235_illegal(); + +}; + + +extern const device_type MB86235; + + +CPU_DISASSEMBLE( mb86235 ); + +#endif /* __MB86235_H__ */ diff --git a/src/devices/cpu/mb86235/mb86235d.c b/src/devices/cpu/mb86235/mb86235d.c new file mode 100644 index 00000000000..e77da1a0cad --- /dev/null +++ b/src/devices/cpu/mb86235/mb86235d.c @@ -0,0 +1,144 @@ +// license:BSD-3-Clause +// copyright-holders:Angelo Salese, ElSemi +#include "emu.h" +#include "debugger.h" +#include "mb86235.h" + +static const char *const alu_opcode_string[] = +{ + "FADD", + "FADDZ", + "FSUB", + "FSUBZ", + + "FCMP", + "FABS", + "FABC", + "ALUNOP", + + "FEA", + "FES", + "FRCP", + "FRSQ", + + "FLOG", + "CIF", + "CFI", + "CFIB", + + "ADD", + "ADDZ", + "SUB", + "SUBZ", + + "CMP", + "ABS", + "ATR", + "ATRZ", + + "AND", + "OR", + "XOR", + "NOT", + + "LSR", + "LSL", + "ASR", + "ASL" +}; + +static const char *const ctrl_opcode_string[] = +{ + "NOP", + "REP", + "SETL", + "CLRF", + "PUSH", + "POP", + "???", + "???", + "SETM", + "SETMCBSA", + "SETMCBSB", + "SETMRF", + "SETMRDY", + "SETMWAIT", + "???", + "???", + "DBcc", /* TODO */ + "DBNcc", /* TODO */ + "DJMP", + "DBLP", + "DBBC", + "DBBS", + "???", + "???", + "DCcc", /* TODO */ + "DCNcc", /* TODO */ + "DCALL", + "DRET", + "???", + "???", + "???", + "???" +}; + +static unsigned dasm_mb86235(char *buffer, UINT32 opcode, UINT32 opcode2) +{ + char *p = buffer; + UINT32 grp = ( opcode2 >> 29 ) & 0x7; + UINT32 aluop = (opcode2 >> (24)) & 0x1f; + + switch(grp) + { + case 0: // ALU2 + + p += sprintf(p,"%s TRANS2_1",alu_opcode_string[aluop]); + break; + case 1: // ALU2 + p += sprintf(p,"%s TRANS1_1",alu_opcode_string[aluop]); + break; + case 2: // ALU2 + CTRL + { + UINT32 ctrlop = (opcode >> (22)) & 0x1f; + //UINT32 ef1 = (opcode >> 16) & 0x3f; + //UINT32 ef2 = (opcode >> 0) & 0xffff; + + p += sprintf(p,"%s %s",alu_opcode_string[aluop],ctrl_opcode_string[ctrlop]); + } + break; + case 4: // ALU1 + p += sprintf(p,"%s TRANS2_2",alu_opcode_string[aluop]); + break; + case 5: // ALU1 + p += sprintf(p,"%s TRANS1_2",alu_opcode_string[aluop]); + break; + case 6: // ALU1 + { + UINT32 ctrlop = (opcode >> (22)) & 0x1f; + //UINT32 ef1 = (opcode >> 16) & 0x3f; + //UINT32 ef2 = (opcode >> 0) & 0xffff; + + p += sprintf(p,"%s %s",alu_opcode_string[aluop],ctrl_opcode_string[ctrlop]); + break; + } + case 7: + p += sprintf(p,"TRANS1_3"); + break; + default: + p += sprintf(p,"UNK ???"); + break; + } + + return (2 | DASMFLAG_SUPPORTED); +} + +CPU_DISASSEMBLE( mb86235 ) +{ + UINT32 op = *(UINT32 *)oprom; + UINT32 op2 = *(UINT32 *)(oprom + 4); + op = LITTLE_ENDIANIZE_INT32(op); + op2 = LITTLE_ENDIANIZE_INT32(op2); + + return dasm_mb86235(buffer, op, op2); +} diff --git a/src/devices/cpu/mb88xx/mb88dasm.c b/src/devices/cpu/mb88xx/mb88dasm.c new file mode 100644 index 00000000000..49bf547ccd4 --- /dev/null +++ b/src/devices/cpu/mb88xx/mb88dasm.c @@ -0,0 +1,224 @@ +// license:BSD-3-Clause +// copyright-holders:Ernesto Corvi +/******************************************************************************* + + mb88dasm.c + Core implementation for the portable Fujitsu MB88xx series MCU disassembler. + + Written by Ernesto Corvi + +*******************************************************************************/ + +#include "emu.h" +#include "mb88xx.h" + + +CPU_DISASSEMBLE( mb88 ) +{ + unsigned startpc = pc; + UINT8 op = oprom[pc++ - startpc]; + UINT8 arg = oprom[pc - startpc]; + + switch( op ) + { + case 0x00: sprintf( buffer, "nop" ); break; + case 0x01: sprintf( buffer, "outO (PortO<=A)" ); break; + case 0x02: sprintf( buffer, "outP" ); break; + case 0x03: sprintf( buffer, "outR (PortR[Y]<=A)" ); break; + case 0x04: sprintf( buffer, "tay (Y<=A)" ); break; + case 0x05: sprintf( buffer, "tath (TH<=A)" ); break; + case 0x06: sprintf( buffer, "tatl (TL<=A)" ); break; + case 0x07: sprintf( buffer, "tas (SB<=A)" ); break; + case 0x08: sprintf( buffer, "icy (Y++)" ); break; + case 0x09: sprintf( buffer, "icm (M[X,Y]++)" ); break; + case 0x0A: sprintf( buffer, "stic (M[X,Y]<=A; Y++)" ); break; + case 0x0B: sprintf( buffer, "x (A<=>M[X,Y])" ); break; + case 0x0C: sprintf( buffer, "rol" ); break; + case 0x0D: sprintf( buffer, "load (A<=M[X,Y])" ); break; + case 0x0E: sprintf( buffer, "adc (A<=A+M[X,Y]+cf)" ); break; + case 0x0F: sprintf( buffer, "and (A<=A & M[X,Y])" ); break; + case 0x10: sprintf( buffer, "daa (A<=A+6 if (A>9 | cf=1)" ); break; + case 0x11: sprintf( buffer, "das (A<=A+10 if (A>9 | cf=1)" ); break; + case 0x12: sprintf( buffer, "inK (A<=PortK)" ); break; + case 0x13: sprintf( buffer, "inR (A<=PortR[Y])" ); break; + case 0x14: sprintf( buffer, "tya (A<=Y)" ); break; + case 0x15: sprintf( buffer, "ttha (A<=TH)" ); break; + case 0x16: sprintf( buffer, "ttla (A<=TL)" ); break; + case 0x17: sprintf( buffer, "tsa (A<=S)" ); break; + case 0x18: sprintf( buffer, "dcy (Y--)" ); break; + case 0x19: sprintf( buffer, "dcm (M[X,Y]--)" ); break; + case 0x1A: sprintf( buffer, "stdc (M[X,Y]<=A; Y--)" ); break; + case 0x1B: sprintf( buffer, "xx (A<=>X)" ); break; + case 0x1C: sprintf( buffer, "ror" ); break; + case 0x1D: sprintf( buffer, "store (M[X,Y]<=A)" ); break; + case 0x1E: sprintf( buffer, "sbc (A<=M[X,Y]-A-cf)" ); break; + case 0x1F: sprintf( buffer, "or (A<=A | M[X,Y])" ); break; + case 0x20: sprintf( buffer, "setR (PortR bit[Y]<=1)" ); break; + case 0x21: sprintf( buffer, "setc (cf<=1)" ); break; + case 0x22: sprintf( buffer, "rstR (PortR bit[Y]<=0)" ); break; + case 0x23: sprintf( buffer, "rstc (cf<=0)" ); break; + case 0x24: sprintf( buffer, "tstR (st<=PortR bit[Y])" ); break; + case 0x25: sprintf( buffer, "tsti (st<=IRQ Line)" ); break; + case 0x26: sprintf( buffer, "tstv (st<=vf)" ); break; + case 0x27: sprintf( buffer, "tsts (st<=sf)" ); break; + case 0x28: sprintf( buffer, "tstc (st<=cf)" ); break; + case 0x29: sprintf( buffer, "tstz (st<=zf)" ); break; + case 0x2A: sprintf( buffer, "sts (M[X,Y]<=SB)" ); break; + case 0x2B: sprintf( buffer, "ls (SB<=M[X,Y])" ); break; + case 0x2C: sprintf( buffer, "rts" ); break; + case 0x2D: sprintf( buffer, "neg (A=-A)" ); break; + case 0x2E: sprintf( buffer, "c (A==M[X,Y])" ); break; + case 0x2F: sprintf( buffer, "eor (A ^ M[X,Y])" ); break; + case 0x30: + case 0x31: + case 0x32: + case 0x33: sprintf( buffer, "sbit%d (M[X,Y] bit%d=1)", op&3, op&3 ); break; + case 0x34: + case 0x35: + case 0x36: + case 0x37: sprintf( buffer, "rbit%d (M[X,Y] bit%d=0)", op&3, op&3 ); break; + case 0x38: + case 0x39: + case 0x3A: + case 0x3B: sprintf( buffer, "tbit%d (M[X,Y] bit%d == 1)", op&3, op&3 ); break; + case 0x3C: sprintf( buffer, "rti" ); break; + case 0x3D: sprintf( buffer, "jpa #$%02x (jump always)", arg ); pc++; break; + case 0x3E: sprintf( buffer, "en #$%02x (enable bits)", arg ); pc++; break; + case 0x3F: sprintf( buffer, "dis #$%02x (disable bits)", arg ); pc++; break; + case 0x40: + case 0x41: + case 0x42: + case 0x43: sprintf( buffer, "setd%d (PortR bit%d<=1)", op&3, op&3 ); break; + case 0x44: + case 0x45: + case 0x46: + case 0x47: sprintf( buffer, "rstd%d (PortR bit%d<=0)", op&3, op&3 ); break; + case 0x48: + case 0x49: + case 0x4A: + case 0x4B: sprintf( buffer, "tstd%d (PortR bit%d == 1)", (op&3)+8, (op&3)+8 ); break; + case 0x4C: + case 0x4D: + case 0x4E: + case 0x4F: sprintf( buffer, "tba%d (A bit%d == 1)", op&3, op&3 ); break; + case 0x50: + case 0x51: + case 0x52: + case 0x53: sprintf( buffer, "xd%d (A<=>M[0,%d])", op&3, op&3 ); break; + case 0x54: + case 0x55: + case 0x56: + case 0x57: sprintf( buffer, "xyd%d (Y<=>M[0,%d])", (op&3)+4, (op&3)+4 ); break; + case 0x58: + case 0x59: + case 0x5A: + case 0x5B: + case 0x5C: + case 0x5D: + case 0x5E: + case 0x5F: sprintf( buffer, "lxi #$%1x (X<=$%1x)", op&7, op&7 ); break; + case 0x60: + case 0x61: + case 0x62: + case 0x63: + case 0x64: + case 0x65: + case 0x66: + case 0x67: sprintf( buffer, "call %02x%02x (call if st=1)", op&7, arg ); pc++; break; + case 0x68: + case 0x69: + case 0x6A: + case 0x6B: + case 0x6C: + case 0x6D: + case 0x6E: + case 0x6F: sprintf( buffer, "jpl %02x%02x (jump if st=1)", op&7, arg ); pc++; break; + case 0x70: + case 0x71: + case 0x72: + case 0x73: + case 0x74: + case 0x75: + case 0x76: + case 0x77: + case 0x78: + case 0x79: + case 0x7A: + case 0x7B: + case 0x7C: + case 0x7D: + case 0x7E: + case 0x7F: sprintf( buffer, "ai #$%1x (A<=A+$%1x)", op&0xf, op&0xf ); break; + case 0x80: + case 0x81: + case 0x82: + case 0x83: + case 0x84: + case 0x85: + case 0x86: + case 0x87: + case 0x88: + case 0x89: + case 0x8A: + case 0x8B: + case 0x8C: + case 0x8D: + case 0x8E: + case 0x8F: sprintf( buffer, "lyi #$%1x (Y<=$%1x)", op&0xf, op&0xf ); break; + case 0x90: + case 0x91: + case 0x92: + case 0x93: + case 0x94: + case 0x95: + case 0x96: + case 0x97: + case 0x98: + case 0x99: + case 0x9A: + case 0x9B: + case 0x9C: + case 0x9D: + case 0x9E: + case 0x9F: sprintf( buffer, "li #$%1x (A<=$%1x)", op&0xf, op&0xf ); break; + case 0xA0: + case 0xA1: + case 0xA2: + case 0xA3: + case 0xA4: + case 0xA5: + case 0xA6: + case 0xA7: + case 0xA8: + case 0xA9: + case 0xAA: + case 0xAB: + case 0xAC: + case 0xAD: + case 0xAE: + case 0xAF: sprintf( buffer, "cyi #$%1x (Y==$%1x)", op&0xf, op&0xf ); break; + case 0xB0: + case 0xB1: + case 0xB2: + case 0xB3: + case 0xB4: + case 0xB5: + case 0xB6: + case 0xB7: + case 0xB8: + case 0xB9: + case 0xBA: + case 0xBB: + case 0xBC: + case 0xBD: + case 0xBE: + case 0xBF: sprintf( buffer, "ci #$%1x (A==$%1x)", op&0xf, op&0xf ); break; + + default: + /* C0-FF */ + sprintf( buffer, "jmp $%04x (jump if st=1)", (pc&(~0x3f))+ op-0xC0 ); + break; + } + + return (pc - startpc) | DASMFLAG_SUPPORTED; +} diff --git a/src/devices/cpu/mb88xx/mb88xx.c b/src/devices/cpu/mb88xx/mb88xx.c new file mode 100644 index 00000000000..0508bfad1d4 --- /dev/null +++ b/src/devices/cpu/mb88xx/mb88xx.c @@ -0,0 +1,974 @@ +// license:BSD-3-Clause +// copyright-holders:Ernesto Corvi +/*************************************************************************** + + mb88xx.c + Core implementation for the portable Fujitsu MB88xx series MCU emulator. + + Written by Ernesto Corvi + + + TODO: + - Add support for the timer + - Add support for the serial interface + - Split the core to support multiple CPU types? + +***************************************************************************/ + +#include "emu.h" +#include "debugger.h" +#include "mb88xx.h" + + +const device_type MB88 = &device_creator; +const device_type MB88201 = &device_creator; +const device_type MB88202 = &device_creator; +const device_type MB8841 = &device_creator; +const device_type MB8842 = &device_creator; +const device_type MB8843 = &device_creator; +const device_type MB8844 = &device_creator; + + +/*************************************************************************** + CONSTANTS +***************************************************************************/ + +#define SERIAL_PRESCALE 6 /* guess */ +#define TIMER_PRESCALE 32 /* guess */ + +#define SERIAL_DISABLE_THRESH 1000 /* at this value, we give up driving the serial port */ + +#define INT_CAUSE_SERIAL 0x01 +#define INT_CAUSE_TIMER 0x02 +#define INT_CAUSE_EXTERNAL 0x04 + + +/*************************************************************************** + MACROS +***************************************************************************/ + +#define READOP(a) (m_direct->read_byte(a)) + +#define RDMEM(a) (m_data->read_byte(a)) +#define WRMEM(a,v) (m_data->write_byte((a), (v))) + +#define READPORT(a) (m_io->read_byte(a)) +#define WRITEPORT(a,v) (m_io->write_byte((a), (v))) + +#define TEST_ST() (m_st & 1) +#define TEST_ZF() (m_zf & 1) +#define TEST_CF() (m_cf & 1) +#define TEST_VF() (m_vf & 1) +#define TEST_SF() (m_sf & 1) +#define TEST_NF() (m_nf & 1) + +#define UPDATE_ST_C(v) m_st=(v&0x10) ? 0 : 1 +#define UPDATE_ST_Z(v) m_st=(v==0) ? 0 : 1 + +#define UPDATE_CF(v) m_cf=((v&0x10)==0) ? 0 : 1 +#define UPDATE_ZF(v) m_zf=(v!=0) ? 0 : 1 + +#define CYCLES(x) do { m_icount -= (x); } while (0) + +#define GETPC() (((int)m_PA << 6)+m_PC) +#define GETEA() ((m_X << 4)+m_Y) + +#define INCPC() do { m_PC++; if ( m_PC >= 0x40 ) { m_PC = 0; m_PA++; } } while (0) + + +/*************************************************************************** + ADDRESS MAPS +***************************************************************************/ + +static ADDRESS_MAP_START(program_9bit, AS_PROGRAM, 8, mb88_cpu_device) + AM_RANGE(0x000, 0x1ff) AM_ROM +ADDRESS_MAP_END + +static ADDRESS_MAP_START(program_10bit, AS_PROGRAM, 8, mb88_cpu_device) + AM_RANGE(0x000, 0x3ff) AM_ROM +ADDRESS_MAP_END + +static ADDRESS_MAP_START(program_11bit, AS_PROGRAM, 8, mb88_cpu_device) + AM_RANGE(0x000, 0x7ff) AM_ROM +ADDRESS_MAP_END + +static ADDRESS_MAP_START(data_4bit, AS_DATA, 8, mb88_cpu_device) + AM_RANGE(0x00, 0x0f) AM_RAM +ADDRESS_MAP_END + +static ADDRESS_MAP_START(data_5bit, AS_DATA, 8, mb88_cpu_device) + AM_RANGE(0x00, 0x1f) AM_RAM +ADDRESS_MAP_END + +static ADDRESS_MAP_START(data_6bit, AS_DATA, 8, mb88_cpu_device) + AM_RANGE(0x00, 0x3f) AM_RAM +ADDRESS_MAP_END + +static ADDRESS_MAP_START(data_7bit, AS_DATA, 8, mb88_cpu_device) + AM_RANGE(0x00, 0x7f) AM_RAM +ADDRESS_MAP_END + + +mb88_cpu_device::mb88_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : cpu_device(mconfig, MB88, "MB88xx", tag, owner, clock, "mb88xx", __FILE__) + , m_program_config("program", ENDIANNESS_BIG, 8, 11, 0) + , m_data_config("data", ENDIANNESS_BIG, 8, 7, 0) + , m_io_config("io", ENDIANNESS_BIG, 8, 3, 0) + , m_PLA(NULL) +{ +} + + +mb88_cpu_device::mb88_cpu_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source, int program_width, int data_width) + : cpu_device(mconfig, type, name, tag, owner, clock, shortname, source) + , m_program_config("program", ENDIANNESS_BIG, 8, program_width, 0, ( (program_width == 9) ? ADDRESS_MAP_NAME(program_9bit) : (program_width == 10) ? ADDRESS_MAP_NAME(program_10bit) : ADDRESS_MAP_NAME(program_11bit) ) ) + , m_data_config("data", ENDIANNESS_BIG, 8, data_width, 0, ( (data_width == 4) ? ADDRESS_MAP_NAME(data_4bit) : (data_width == 5) ? ADDRESS_MAP_NAME(data_5bit) : (data_width == 6) ? ADDRESS_MAP_NAME(data_6bit) : ADDRESS_MAP_NAME(data_7bit) ) ) + , m_io_config("io", ENDIANNESS_BIG, 8, 3, 0) + , m_PLA(NULL) +{ +} + +mb88201_cpu_device::mb88201_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : mb88_cpu_device(mconfig, MB88201, "MB88201", tag, owner, clock, "mb88201", __FILE__, 9, 4) +{ +} + +mb88202_cpu_device::mb88202_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : mb88_cpu_device(mconfig, MB88202, "MB88202", tag, owner, clock, "mb88202", __FILE__, 10, 5) +{ +} + + +mb8841_cpu_device::mb8841_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : mb88_cpu_device(mconfig, MB8841, "MB8841", tag, owner, clock, "mb8841", __FILE__, 11, 7) +{ +} + + +mb8842_cpu_device::mb8842_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : mb88_cpu_device(mconfig, MB8842, "MB8842", tag, owner, clock, "mb8842", __FILE__, 11, 7) +{ +} + + +mb8843_cpu_device::mb8843_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : mb88_cpu_device(mconfig, MB8843, "MB8843", tag, owner, clock, "mb8843", __FILE__, 10, 6) +{ +} + + +mb8844_cpu_device::mb8844_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : mb88_cpu_device(mconfig, MB8844, "MB8844", tag, owner, clock, "mb8844", __FILE__, 10, 6) +{ +} + + +offs_t mb88_cpu_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( mb88 ); + return CPU_DISASSEMBLE_NAME(mb88)(this, buffer, pc, oprom, opram, options); +} + + +/*************************************************************************** + INITIALIZATION AND SHUTDOWN +***************************************************************************/ + +void mb88_cpu_device::device_start() +{ + m_program = &space(AS_PROGRAM); + m_direct = &m_program->direct(); + m_data = &space(AS_DATA); + m_io = &space(AS_IO); + + m_serial = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(mb88_cpu_device::serial_timer), this)); + + m_ctr = 0; + + save_item(NAME(m_PC)); + save_item(NAME(m_PA)); + save_item(NAME(m_SP[0])); + save_item(NAME(m_SP[1])); + save_item(NAME(m_SP[2])); + save_item(NAME(m_SP[3])); + save_item(NAME(m_SI)); + save_item(NAME(m_A)); + save_item(NAME(m_X)); + save_item(NAME(m_Y)); + save_item(NAME(m_st)); + save_item(NAME(m_zf)); + save_item(NAME(m_cf)); + save_item(NAME(m_vf)); + save_item(NAME(m_sf)); + save_item(NAME(m_nf)); + save_item(NAME(m_pio)); + save_item(NAME(m_TH)); + save_item(NAME(m_TL)); + save_item(NAME(m_TP)); + save_item(NAME(m_ctr)); + save_item(NAME(m_SB)); + save_item(NAME(m_SBcount)); + save_item(NAME(m_pending_interrupt)); + + state_add( MB88_PC, "PC", m_PC).formatstr("%02X"); + state_add( MB88_PA, "PA", m_PA).formatstr("%02X"); + state_add( MB88_SI, "SI", m_SI).formatstr("%01X"); + state_add( MB88_A, "A", m_A).formatstr("%01X"); + state_add( MB88_X, "X", m_X).formatstr("%01X"); + state_add( MB88_Y, "Y", m_Y).formatstr("%01X"); + state_add( MB88_PIO, "PIO", m_pio).formatstr("%02X"); + state_add( MB88_TH, "TH", m_TH).formatstr("%01X"); + state_add( MB88_TL, "TL", m_TL).formatstr("%01X"); + state_add( MB88_SB, "SB", m_SB).formatstr("%01X"); + + state_add( STATE_GENPC, "GENPC", m_debugger_pc ).callimport().callexport().noshow(); + state_add( STATE_GENFLAGS, "GENFLAGS", m_debugger_flags ).callimport().callexport().formatstr("%6s").noshow(); + m_icountptr = &m_icount; +} + + +void mb88_cpu_device::state_import(const device_state_entry &entry) +{ + switch (entry.index()) + { + case STATE_GENFLAGS: + m_st = (m_debugger_flags & 0x01) ? 1 : 0; + m_zf = (m_debugger_flags & 0x02) ? 1 : 0; + m_cf = (m_debugger_flags & 0x04) ? 1 : 0; + m_vf = (m_debugger_flags & 0x08) ? 1 : 0; + m_sf = (m_debugger_flags & 0x10) ? 1 : 0; + m_nf = (m_debugger_flags & 0x20) ? 1 : 0; + break; + + case STATE_GENPC: + m_PC = m_debugger_pc & 0x3f; + m_PA = ( m_debugger_pc >> 6 ) & 0x1f; + break; + } +} + + +void mb88_cpu_device::state_export(const device_state_entry &entry) +{ + switch (entry.index()) + { + case STATE_GENFLAGS: + m_debugger_flags = 0; + if (TEST_ST()) m_debugger_flags |= 0x01; + if (TEST_ZF()) m_debugger_flags |= 0x02; + if (TEST_CF()) m_debugger_flags |= 0x04; + if (TEST_VF()) m_debugger_flags |= 0x08; + if (TEST_SF()) m_debugger_flags |= 0x10; + if (TEST_NF()) m_debugger_flags |= 0x20; + break; + + case STATE_GENPC: + m_debugger_pc = GETPC(); + break; + } +} + + +void mb88_cpu_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + switch (entry.index()) + { + case STATE_GENFLAGS: + strprintf(str, "%c%c%c%c%c%c", + TEST_ST() ? 'T' : 't', + TEST_ZF() ? 'Z' : 'z', + TEST_CF() ? 'C' : 'c', + TEST_VF() ? 'V' : 'v', + TEST_SF() ? 'S' : 's', + TEST_NF() ? 'I' : 'i'); + + break; + } +} + + +void mb88_cpu_device::device_reset() +{ + /* zero registers and flags */ + m_PC = 0; + m_PA = 0; + m_SP[0] = m_SP[1] = m_SP[2] = m_SP[3] = 0; + m_SI = 0; + m_A = 0; + m_X = 0; + m_Y = 0; + m_st = 1; /* start off with st=1 */ + m_zf = 0; + m_cf = 0; + m_vf = 0; + m_sf = 0; + m_nf = 0; + m_pio = 0; + m_TH = 0; + m_TL = 0; + m_TP = 0; + m_SB = 0; + m_SBcount = 0; + m_pending_interrupt = 0; +} + +/*************************************************************************** + CORE EXECUTION LOOP +***************************************************************************/ + +TIMER_CALLBACK_MEMBER( mb88_cpu_device::serial_timer ) +{ + m_SBcount++; + + /* if we get too many interrupts with no servicing, disable the timer + until somebody does something */ + if (m_SBcount >= SERIAL_DISABLE_THRESH) + m_serial->adjust(attotime::never); + + /* only read if not full; this is needed by the Namco 52xx to ensure that + the program can write to S and recover the value even if serial is enabled */ + if (!m_sf) + { + m_SB = (m_SB >> 1) | (READPORT(MB88_PORTSI) ? 8 : 0); + + if (m_SBcount >= 4) + { + m_sf = 1; + m_pending_interrupt |= INT_CAUSE_SERIAL; + } + } + +} + +int mb88_cpu_device::pla( int inA, int inB ) +{ + int index = ((inB&1) << 4) | (inA&0x0f); + + if ( m_PLA ) + return m_PLA[index]; + + return index; +} + +void mb88_cpu_device::execute_set_input(int inputnum, int state) +{ + /* on falling edge trigger interrupt */ + if ( (m_pio & 0x04) && m_nf && state == CLEAR_LINE ) + { + m_pending_interrupt |= INT_CAUSE_EXTERNAL; + } + + m_nf = (state != CLEAR_LINE) ? 1 : 0; +} + +void mb88_cpu_device::update_pio_enable( UINT8 newpio ) +{ + /* if the serial state has changed, configure the timer */ + if ((m_pio ^ newpio) & 0x30) + { + if ((newpio & 0x30) == 0) + m_serial->adjust(attotime::never); + else if ((newpio & 0x30) == 0x20) + m_serial->adjust(attotime::from_hz(clock() / SERIAL_PRESCALE), 0, attotime::from_hz(clock() / SERIAL_PRESCALE)); + else + fatalerror("mb88xx: update_pio_enable set serial enable to unsupported value %02X\n", newpio & 0x30); + } + + m_pio = newpio; +} + +void mb88_cpu_device::increment_timer() +{ + m_TL = (m_TL + 1) & 0x0f; + if (m_TL == 0) + { + m_TH = (m_TH + 1) & 0x0f; + if (m_TH == 0) + { + m_vf = 1; + m_pending_interrupt |= INT_CAUSE_TIMER; + } + } +} + +void mb88_cpu_device::update_pio( int cycles ) +{ + /* TODO: improve/validate serial and timer support */ + + /* internal clock enable */ + if ( m_pio & 0x80 ) + { + m_TP += cycles; + while (m_TP >= TIMER_PRESCALE) + { + m_TP -= TIMER_PRESCALE; + increment_timer(); + } + } + + /* process pending interrupts */ + if (m_pending_interrupt & m_pio) + { + m_SP[m_SI] = GETPC(); + m_SP[m_SI] |= TEST_CF() << 15; + m_SP[m_SI] |= TEST_ZF() << 14; + m_SP[m_SI] |= TEST_ST() << 13; + m_SI = ( m_SI + 1 ) & 3; + + /* the datasheet doesn't mention interrupt vectors but + the Arabian MCU program expects the following */ + if (m_pending_interrupt & m_pio & INT_CAUSE_EXTERNAL) + { + /* if we have a live external source, call the irqcallback */ + standard_irq_callback( 0 ); + m_PC = 0x02; + } + else if (m_pending_interrupt & m_pio & INT_CAUSE_TIMER) + { + m_PC = 0x04; + } + else if (m_pending_interrupt & m_pio & INT_CAUSE_SERIAL) + { + m_PC = 0x06; + } + + m_PA = 0x00; + m_st = 1; + m_pending_interrupt = 0; + + CYCLES(3); /* ? */ + } +} + +WRITE_LINE_MEMBER( mb88_cpu_device::clock_w ) +{ + if (state != m_ctr) + { + m_ctr = state; + + /* on a falling clock, increment the timer, but only if enabled */ + if (m_ctr == 0 && (m_pio & 0x40)) + increment_timer(); + } +} + + +void mb88_cpu_device::execute_run() +{ + while (m_icount > 0) + { + UINT8 opcode, arg, oc; + + /* fetch the opcode */ + debugger_instruction_hook(this, GETPC()); + opcode = READOP(GETPC()); + + /* increment the PC */ + INCPC(); + + /* start with instruction doing 1 cycle */ + oc = 1; + + switch (opcode) + { + case 0x00: /* nop ZCS:...*/ + m_st = 1; + break; + + case 0x01: /* outO ZCS:...*/ + WRITEPORT( MB88_PORTO, pla( m_A,TEST_CF()) ); + m_st = 1; + break; + + case 0x02: /* outP ZCS:... */ + WRITEPORT( MB88_PORTP, m_A ); + m_st = 1; + break; + + case 0x03: /* outR ZCS:... */ + arg = m_Y; + WRITEPORT( MB88_PORTR0+(arg&3), m_A ); + m_st = 1; + break; + + case 0x04: /* tay ZCS:... */ + m_Y = m_A; + m_st = 1; + break; + + case 0x05: /* tath ZCS:... */ + m_TH = m_A; + m_st = 1; + break; + + case 0x06: /* tatl ZCS:... */ + m_TL = m_A; + m_st = 1; + break; + + case 0x07: /* tas ZCS:... */ + m_SB = m_A; + m_st = 1; + break; + + case 0x08: /* icy ZCS:x.x */ + m_Y++; + UPDATE_ST_C(m_Y); + m_Y &= 0x0f; + UPDATE_ZF(m_Y); + break; + + case 0x09: /* icm ZCS:x.x */ + arg=RDMEM(GETEA()); + arg++; + UPDATE_ST_C(arg); + arg &= 0x0f; + UPDATE_ZF(arg); + WRMEM(GETEA(),arg); + break; + + case 0x0a: /* stic ZCS:x.x */ + WRMEM(GETEA(),m_A); + m_Y++; + UPDATE_ST_C(m_Y); + m_Y &= 0x0f; + UPDATE_ZF(m_Y); + break; + + case 0x0b: /* x ZCS:x.. */ + arg = RDMEM(GETEA()); + WRMEM(GETEA(),m_A); + m_A = arg; + UPDATE_ZF(m_A); + m_st = 1; + break; + + case 0x0c: /* rol ZCS:xxx */ + m_A <<= 1; + m_A |= TEST_CF(); + UPDATE_ST_C(m_A); + m_cf = m_st ^ 1; + m_A &= 0x0f; + UPDATE_ZF(m_A); + break; + + case 0x0d: /* l ZCS:x.. */ + m_A = RDMEM(GETEA()); + UPDATE_ZF(m_A); + m_st = 1; + break; + + case 0x0e: /* adc ZCS:xxx */ + arg = RDMEM(GETEA()); + arg += m_A; + arg += TEST_CF(); + UPDATE_ST_C(arg); + m_cf = m_st ^ 1; + m_A = arg & 0x0f; + UPDATE_ZF(m_A); + break; + + case 0x0f: /* and ZCS:x.x */ + m_A &= RDMEM(GETEA()); + UPDATE_ZF(m_A); + m_st = m_zf ^ 1; + break; + + case 0x10: /* daa ZCS:.xx */ + if ( TEST_CF() || m_A > 9 ) m_A += 6; + UPDATE_ST_C(m_A); + m_cf = m_st ^ 1; + m_A &= 0x0f; + break; + + case 0x11: /* das ZCS:.xx */ + if ( TEST_CF() || m_A > 9 ) m_A += 10; + UPDATE_ST_C(m_A); + m_cf = m_st ^ 1; + m_A &= 0x0f; + break; + + case 0x12: /* inK ZCS:x.. */ + m_A = READPORT( MB88_PORTK ) & 0x0f; + UPDATE_ZF(m_A); + m_st = 1; + break; + + case 0x13: /* inR ZCS:x.. */ + arg = m_Y; + m_A = READPORT( MB88_PORTR0+(arg&3) ) & 0x0f; + UPDATE_ZF(m_A); + m_st = 1; + break; + + case 0x14: /* tya ZCS:x.. */ + m_A = m_Y; + UPDATE_ZF(m_A); + m_st = 1; + break; + + case 0x15: /* ttha ZCS:x.. */ + m_A = m_TH; + UPDATE_ZF(m_A); + m_st = 1; + break; + + case 0x16: /* ttla ZCS:x.. */ + m_A = m_TL; + UPDATE_ZF(m_A); + m_st = 1; + break; + + case 0x17: /* tsa ZCS:x.. */ + m_A = m_SB; + UPDATE_ZF(m_A); + m_st = 1; + break; + + case 0x18: /* dcy ZCS:..x */ + m_Y--; + UPDATE_ST_C(m_Y); + m_Y &= 0x0f; + break; + + case 0x19: /* dcm ZCS:x.x */ + arg=RDMEM(GETEA()); + arg--; + UPDATE_ST_C(arg); + arg &= 0x0f; + UPDATE_ZF(arg); + WRMEM(GETEA(),arg); + break; + + case 0x1a: /* stdc ZCS:x.x */ + WRMEM(GETEA(),m_A); + m_Y--; + UPDATE_ST_C(m_Y); + m_Y &= 0x0f; + UPDATE_ZF(m_Y); + break; + + case 0x1b: /* xx ZCS:x.. */ + arg = m_X; + m_X = m_A; + m_A = arg; + UPDATE_ZF(m_A); + m_st = 1; + break; + + case 0x1c: /* ror ZCS:xxx */ + m_A |= TEST_CF() << 4; + UPDATE_ST_C(m_A << 4); + m_cf = m_st ^ 1; + m_A >>= 1; + m_A &= 0x0f; + UPDATE_ZF(m_A); + break; + + case 0x1d: /* st ZCS:x.. */ + WRMEM(GETEA(),m_A); + m_st = 1; + break; + + case 0x1e: /* sbc ZCS:xxx */ + arg = RDMEM(GETEA()); + arg -= m_A; + arg -= TEST_CF(); + UPDATE_ST_C(arg); + m_cf = m_st ^ 1; + m_A = arg & 0x0f; + UPDATE_ZF(m_A); + break; + + case 0x1f: /* or ZCS:x.x */ + m_A |= RDMEM(GETEA()); + UPDATE_ZF(m_A); + m_st = m_zf ^ 1; + break; + + case 0x20: /* setR ZCS:... */ + arg = READPORT( MB88_PORTR0+(m_Y/4) ); + WRITEPORT( MB88_PORTR0+(m_Y/4), arg | ( 1 << (m_Y%4) ) ); + m_st = 1; + break; + + case 0x21: /* setc ZCS:.xx */ + m_cf = 1; + m_st = 1; + break; + + case 0x22: /* rstR ZCS:... */ + arg = READPORT( MB88_PORTR0+(m_Y/4) ); + WRITEPORT( MB88_PORTR0+(m_Y/4), arg & ~( 1 << (m_Y%4) ) ); + m_st = 1; + break; + + case 0x23: /* rstc ZCS:.xx */ + m_cf = 0; + m_st = 1; + break; + + case 0x24: /* tstr ZCS:..x */ + arg = READPORT( MB88_PORTR0+(m_Y/4) ); + m_st = ( arg & ( 1 << (m_Y%4) ) ) ? 0 : 1; + break; + + case 0x25: /* tsti ZCS:..x */ + m_st = m_nf ^ 1; + break; + + case 0x26: /* tstv ZCS:..x */ + m_st = m_vf ^ 1; + m_vf = 0; + break; + + case 0x27: /* tsts ZCS:..x */ + m_st = m_sf ^ 1; + if (m_sf) + { + /* re-enable the timer if we disabled it previously */ + if (m_SBcount >= SERIAL_DISABLE_THRESH) + m_serial->adjust(attotime::from_hz(clock() / SERIAL_PRESCALE), 0, attotime::from_hz(clock() / SERIAL_PRESCALE)); + m_SBcount = 0; + } + m_sf = 0; + break; + + case 0x28: /* tstc ZCS:..x */ + m_st = m_cf ^ 1; + break; + + case 0x29: /* tstz ZCS:..x */ + m_st = m_zf ^ 1; + break; + + case 0x2a: /* sts ZCS:x.. */ + WRMEM(GETEA(),m_SB); + UPDATE_ZF(m_SB); + m_st = 1; + break; + + case 0x2b: /* ls ZCS:x.. */ + m_SB = RDMEM(GETEA()); + UPDATE_ZF(m_SB); + m_st = 1; + break; + + case 0x2c: /* rts ZCS:... */ + m_SI = ( m_SI - 1 ) & 3; + m_PC = m_SP[m_SI] & 0x3f; + m_PA = (m_SP[m_SI] >> 6) & 0x1f; + m_st = 1; + break; + + case 0x2d: /* neg ZCS: ..x */ + m_A = (~m_A)+1; + m_A &= 0x0f; + UPDATE_ST_Z(m_A); + break; + + case 0x2e: /* c ZCS:xxx */ + arg = RDMEM(GETEA()); + arg -= m_A; + UPDATE_CF(arg); + arg &= 0x0f; + UPDATE_ST_Z(arg); + m_zf = m_st ^ 1; + break; + + case 0x2f: /* eor ZCS:x.x */ + m_A ^= RDMEM(GETEA()); + UPDATE_ST_Z(m_A); + m_zf = m_st ^ 1; + break; + + case 0x30: case 0x31: case 0x32: case 0x33: /* sbit ZCS:... */ + arg = RDMEM(GETEA()); + WRMEM(GETEA(), arg | (1 << (opcode&3))); + m_st = 1; + break; + + case 0x34: case 0x35: case 0x36: case 0x37: /* rbit ZCS:... */ + arg = RDMEM(GETEA()); + WRMEM(GETEA(), arg & ~(1 << (opcode&3))); + m_st = 1; + break; + + case 0x38: case 0x39: case 0x3a: case 0x3b: /* tbit ZCS:... */ + arg = RDMEM(GETEA()); + m_st = ( arg & (1 << (opcode&3) ) ) ? 0 : 1; + break; + + case 0x3c: /* rti ZCS:... */ + /* restore address and saved state flags on the top bits of the stack */ + m_SI = ( m_SI - 1 ) & 3; + m_PC = m_SP[m_SI] & 0x3f; + m_PA = (m_SP[m_SI] >> 6) & 0x1f; + m_st = (m_SP[m_SI] >> 13)&1; + m_zf = (m_SP[m_SI] >> 14)&1; + m_cf = (m_SP[m_SI] >> 15)&1; + break; + + case 0x3d: /* jpa imm ZCS:..x */ + m_PA = READOP(GETPC()) & 0x1f; + m_PC = m_A * 4; + oc = 2; + m_st = 1; + break; + + case 0x3e: /* en imm ZCS:... */ + update_pio_enable(m_pio | READOP(GETPC())); + INCPC(); + oc = 2; + m_st = 1; + break; + + case 0x3f: /* dis imm ZCS:... */ + update_pio_enable(m_pio & ~(READOP(GETPC()))); + INCPC(); + oc = 2; + m_st = 1; + break; + + case 0x40: case 0x41: case 0x42: case 0x43: /* setD ZCS:... */ + arg = READPORT(MB88_PORTR0); + arg |= (1 << (opcode&3)); + WRITEPORT(MB88_PORTR0,arg); + m_st = 1; + break; + + case 0x44: case 0x45: case 0x46: case 0x47: /* rstD ZCS:... */ + arg = READPORT(MB88_PORTR0); + arg &= ~(1 << (opcode&3)); + WRITEPORT(MB88_PORTR0,arg); + m_st = 1; + break; + + case 0x48: case 0x49: case 0x4a: case 0x4b: /* tstD ZCS:..x */ + arg = READPORT(MB88_PORTR2); + m_st = (arg & (1 << (opcode&3))) ? 0 : 1; + break; + + case 0x4c: case 0x4d: case 0x4e: case 0x4f: /* tba ZCS:..x */ + m_st = (m_A & (1 << (opcode&3))) ? 0 : 1; + break; + + case 0x50: case 0x51: case 0x52: case 0x53: /* xd ZCS:x.. */ + arg = RDMEM(opcode&3); + WRMEM((opcode&3),m_A); + m_A = arg; + UPDATE_ZF(m_A); + m_st = 1; + break; + + case 0x54: case 0x55: case 0x56: case 0x57: /* xyd ZCS:x.. */ + arg = RDMEM((opcode&3)+4); + WRMEM((opcode&3)+4,m_Y); + m_Y = arg; + UPDATE_ZF(m_Y); + m_st = 1; + break; + + case 0x58: case 0x59: case 0x5a: case 0x5b: + case 0x5c: case 0x5d: case 0x5e: case 0x5f: /* lxi ZCS:x.. */ + m_X = opcode & 7; + UPDATE_ZF(m_X); + m_st = 1; + break; + + case 0x60: case 0x61: case 0x62: case 0x63: + case 0x64: case 0x65: case 0x66: case 0x67: /* call imm ZCS:..x */ + arg = READOP(GETPC()); + INCPC(); + oc = 2; + if ( TEST_ST() ) + { + m_SP[m_SI] = GETPC(); + m_SI = ( m_SI + 1 ) & 3; + m_PC = arg & 0x3f; + m_PA = ( ( opcode & 7 ) << 2 ) | ( arg >> 6 ); + } + m_st = 1; + break; + + case 0x68: case 0x69: case 0x6a: case 0x6b: + case 0x6c: case 0x6d: case 0x6e: case 0x6f: /* jpl imm ZCS:..x */ + arg = READOP(GETPC()); + INCPC(); + oc = 2; + if ( TEST_ST() ) + { + m_PC = arg & 0x3f; + m_PA = ( ( opcode & 7 ) << 2 ) | ( arg >> 6 ); + } + m_st = 1; + break; + + case 0x70: case 0x71: case 0x72: case 0x73: + case 0x74: case 0x75: case 0x76: case 0x77: + case 0x78: case 0x79: case 0x7a: case 0x7b: + case 0x7c: case 0x7d: case 0x7e: case 0x7f: /* ai ZCS:xxx */ + arg = opcode & 0x0f; + arg += m_A; + UPDATE_ST_C(arg); + m_cf = m_st ^ 1; + m_A = arg & 0x0f; + UPDATE_ZF(m_A); + break; + + case 0x80: case 0x81: case 0x82: case 0x83: + case 0x84: case 0x85: case 0x86: case 0x87: + case 0x88: case 0x89: case 0x8a: case 0x8b: + case 0x8c: case 0x8d: case 0x8e: case 0x8f: /* lxi ZCS:x.. */ + m_Y = opcode & 0x0f; + UPDATE_ZF(m_Y); + m_st = 1; + break; + + case 0x90: case 0x91: case 0x92: case 0x93: + case 0x94: case 0x95: case 0x96: case 0x97: + case 0x98: case 0x99: case 0x9a: case 0x9b: + case 0x9c: case 0x9d: case 0x9e: case 0x9f: /* li ZCS:x.. */ + m_A = opcode & 0x0f; + UPDATE_ZF(m_A); + m_st = 1; + break; + + case 0xa0: case 0xa1: case 0xa2: case 0xa3: + case 0xa4: case 0xa5: case 0xa6: case 0xa7: + case 0xa8: case 0xa9: case 0xaa: case 0xab: + case 0xac: case 0xad: case 0xae: case 0xaf: /* cyi ZCS:xxx */ + arg = (opcode & 0x0f) - m_Y; + UPDATE_CF(arg); + arg &= 0x0f; + UPDATE_ST_Z(arg); + m_zf = m_st ^ 1; + break; + + case 0xb0: case 0xb1: case 0xb2: case 0xb3: + case 0xb4: case 0xb5: case 0xb6: case 0xb7: + case 0xb8: case 0xb9: case 0xba: case 0xbb: + case 0xbc: case 0xbd: case 0xbe: case 0xbf: /* ci ZCS:xxx */ + arg = (opcode & 0x0f) - m_A; + UPDATE_CF(arg); + arg &= 0x0f; + UPDATE_ST_Z(arg); + m_zf = m_st ^ 1; + break; + + default: /* jmp ZCS:..x */ + if ( TEST_ST() ) + { + m_PC = opcode & 0x3f; + } + m_st = 1; + break; + } + + /* update cycle counts */ + CYCLES( oc ); + + /* update interrupts, serial and timer flags */ + update_pio(oc); + } +} diff --git a/src/devices/cpu/mb88xx/mb88xx.h b/src/devices/cpu/mb88xx/mb88xx.h new file mode 100644 index 00000000000..3603d9dfc91 --- /dev/null +++ b/src/devices/cpu/mb88xx/mb88xx.h @@ -0,0 +1,217 @@ +// license:BSD-3-Clause +// copyright-holders:Ernesto Corvi +/*************************************************************************** + + mb88xx.h + Core implementation for the portable Fujitsu MB88xx series MCU emulator. + + Written by Ernesto Corvi + +***************************************************************************/ + +#pragma once + +#ifndef __MB88XX_H__ +#define __MB88XX_H__ + + +/*************************************************************************** + PORT ENUMERATION +***************************************************************************/ + +enum +{ + MB88_PORTK = 0, /* input only, 4 bits */ + MB88_PORTO, /* output only, PLA function output */ + MB88_PORTP, /* 4 bits */ + MB88_PORTR0, /* R0-R3, 4 bits */ + MB88_PORTR1, /* R4-R7, 4 bits */ + MB88_PORTR2, /* R8-R11, 4 bits */ + MB88_PORTR3, /* R12-R15, 4 bits */ + MB88_PORTSI /* SI, 1 bit */ +}; + +/*************************************************************************** + REGISTER ENUMERATION +***************************************************************************/ + +enum +{ + MB88_PC=1, + MB88_PA, + MB88_FLAGS, + MB88_SI, + MB88_A, + MB88_X, + MB88_Y, + MB88_PIO, + MB88_TH, + MB88_TL, + MB88_SB +}; + +#define MB88_IRQ_LINE 0 + + +CPU_DISASSEMBLE( mb88 ); + + +// Configure 32 byte PLA, if NULL (default) assume direct output */ +#define MCFG_MB88_PLA(_pla) mb88_cpu_device::set_pla(*device, _pla); + + +class mb88_cpu_device : public cpu_device +{ +public: + // construction/destruction + mb88_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + mb88_cpu_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source, int program_width, int data_width); + + // static configuration helpers + static void set_pla(device_t &device, UINT8 *pla) { downcast(device).m_PLA = pla; } + + DECLARE_WRITE_LINE_MEMBER( clock_w ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_execute_interface overrides + virtual UINT32 execute_min_cycles() const { return 1; } + virtual UINT32 execute_max_cycles() const { return 3; } + virtual UINT32 execute_input_lines() const { return 1; } + virtual void execute_run(); + virtual void execute_set_input(int inputnum, int state); + virtual UINT64 execute_clocks_to_cycles(UINT64 clocks) const { return (clocks + 6 - 1) / 6; } + virtual UINT64 execute_cycles_to_clocks(UINT64 cycles) const { return (cycles * 6); } + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const { return (spacenum == AS_PROGRAM) ? &m_program_config : ( (spacenum == AS_DATA) ? &m_data_config : ( (spacenum == AS_IO) ? &m_io_config : NULL ) ); } + + // device_state_interface overrides + void state_string_export(const device_state_entry &entry, std::string &str); + void state_import(const device_state_entry &entry); + void state_export(const device_state_entry &entry); + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const { return 1; } + virtual UINT32 disasm_max_opcode_bytes() const { return 2; } + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + +private: + address_space_config m_program_config; + address_space_config m_data_config; + address_space_config m_io_config; + + UINT8 m_PC; /* Program Counter: 6 bits */ + UINT8 m_PA; /* Page Address: 4 bits */ + UINT16 m_SP[4]; /* Stack is 4*10 bit addresses deep, but we also use 3 top bits per address to store flags during irq */ + UINT8 m_SI; /* Stack index: 2 bits */ + UINT8 m_A; /* Accumulator: 4 bits */ + UINT8 m_X; /* Index X: 4 bits */ + UINT8 m_Y; /* Index Y: 4 bits */ + UINT8 m_st; /* State flag: 1 bit */ + UINT8 m_zf; /* Zero flag: 1 bit */ + UINT8 m_cf; /* Carry flag: 1 bit */ + UINT8 m_vf; /* Timer overflow flag: 1 bit */ + UINT8 m_sf; /* Serial Full/Empty flag: 1 bit */ + UINT8 m_nf; /* Interrupt flag: 1 bit */ + + /* Peripheral Control */ + UINT8 m_pio; /* Peripheral enable bits: 8 bits */ + + /* Timer registers */ + UINT8 m_TH; /* Timer High: 4 bits */ + UINT8 m_TL; /* Timer Low: 4 bits */ + UINT8 m_TP; /* Timer Prescale: 6 bits? */ + UINT8 m_ctr; /* current external counter value */ + + /* Serial registers */ + UINT8 m_SB; /* Serial buffer: 4 bits */ + UINT16 m_SBcount; /* number of bits received */ + emu_timer *m_serial; + + /* PLA configuration */ + UINT8 * m_PLA; + + /* IRQ handling */ + UINT8 m_pending_interrupt; + + address_space *m_program; + direct_read_data *m_direct; + address_space *m_data; + address_space *m_io; + int m_icount; + + // For the debugger + UINT16 m_debugger_pc; + UINT8 m_debugger_flags; + + TIMER_CALLBACK_MEMBER( serial_timer ); + int pla( int inA, int inB ); + void update_pio_enable( UINT8 newpio ); + void increment_timer(); + void update_pio( int cycles ); + +}; + + +class mb88201_cpu_device : public mb88_cpu_device +{ +public: + // construction/destruction + mb88201_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +class mb88202_cpu_device : public mb88_cpu_device +{ +public: + // construction/destruction + mb88202_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +class mb8841_cpu_device : public mb88_cpu_device +{ +public: + // construction/destruction + mb8841_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +class mb8842_cpu_device : public mb88_cpu_device +{ +public: + // construction/destruction + mb8842_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +class mb8843_cpu_device : public mb88_cpu_device +{ +public: + // construction/destruction + mb8843_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +class mb8844_cpu_device : public mb88_cpu_device +{ +public: + // construction/destruction + mb8844_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +extern const device_type MB88; +extern const device_type MB88201; +extern const device_type MB88202; +extern const device_type MB8841; +extern const device_type MB8842; +extern const device_type MB8843; +extern const device_type MB8844; + + +#endif /* __MB88XX_H__ */ diff --git a/src/devices/cpu/mc68hc11/hc11dasm.c b/src/devices/cpu/mc68hc11/hc11dasm.c new file mode 100644 index 00000000000..eed3df13c5e --- /dev/null +++ b/src/devices/cpu/mc68hc11/hc11dasm.c @@ -0,0 +1,1299 @@ +// license:BSD-3-Clause +// copyright-holders:Ville Linde +/* + Motorola M68HC11 disassembler + + Written by Ville Linde +*/ + +#include "emu.h" + +enum +{ + EA_IMM8 = 1, + EA_IMM16, + EA_EXT, + EA_REL, + EA_DIRECT, + EA_DIRECT_IMM8, + EA_DIRECT_IMM8_REL, + EA_IND_X, + EA_IND_X_IMM8, + EA_IND_X_IMM8_REL, + EA_IND_Y, + EA_IND_Y_IMM8, + EA_IND_Y_IMM8_REL, + PAGE2, + PAGE3, + PAGE4 +}; + +struct M68HC11_OPCODE { + char mnemonic[32]; + int address_mode; +}; + +static const M68HC11_OPCODE opcode_table[256] = +{ + /* 0x00 - 0x0f */ + { "test", 0, }, + { "nop", 0, }, + { "idiv", 0, }, + { "fdiv", 0, }, + { "lsrd", 0, }, + { "asld", 0, }, + { "tap", 0, }, + { "tpa", 0, }, + { "inx", 0, }, + { "dex", 0, }, + { "clv", 0, }, + { "sev", 0, }, + { "clc", 0, }, + { "sec", 0, }, + { "cli", 0, }, + { "sei", 0, }, + /* 0x10 - 0x1f */ + { "sba", 0, }, + { "cba", 0, }, + { "brset", EA_DIRECT_IMM8_REL, }, + { "brclr", EA_DIRECT_IMM8_REL, }, + { "bset", EA_DIRECT_IMM8, }, + { "bclr", EA_DIRECT_IMM8, }, + { "tab", 0, }, + { "tba", 0, }, + { "page2", PAGE2, }, + { "daa", 0, }, + { "page3", PAGE3, }, + { "aba", 0, }, + { "bset", EA_IND_X_IMM8, }, + { "bclr", EA_IND_X_IMM8, }, + { "brset", EA_IND_X_IMM8_REL, }, + { "brclr", EA_IND_X_IMM8_REL, }, + /* 0x20 - 0x2f */ + { "bra", EA_REL, }, + { "brn", EA_REL, }, + { "bhi", EA_REL, }, + { "bls", EA_REL, }, + { "bcc", EA_REL, }, + { "bcs", EA_REL, }, + { "bne", EA_REL, }, + { "beq", EA_REL, }, + { "bvc", EA_REL, }, + { "bvs", EA_REL, }, + { "bpl", EA_REL, }, + { "bmi", EA_REL, }, + { "bge", EA_REL, }, + { "blt", EA_REL, }, + { "bgt", EA_REL, }, + { "ble", EA_REL, }, + /* 0x30 - 0x3f */ + { "tsx", 0, }, + { "ins", 0, }, + { "pula", 0, }, + { "pulb", 0, }, + { "des", 0, }, + { "txs", 0, }, + { "psha", 0, }, + { "pshb", 0, }, + { "pulx", 0, }, + { "rts", 0, }, + { "abx", 0, }, + { "rti", 0, }, + { "pshx", 0, }, + { "mul", 0, }, + { "wai", 0, }, + { "swi", 0, }, + /* 0x40 - 0x4f */ + { "nega", 0, }, + { "?", 0, }, + { "?", 0, }, + { "coma", 0, }, + { "lsra", 0, }, + { "?", 0, }, + { "rora", 0, }, + { "asra", 0, }, + { "asla", 0, }, + { "rola", 0, }, + { "deca", 0, }, + { "?", 0, }, + { "inca", 0, }, + { "tsta", 0, }, + { "?", 0, }, + { "clra", 0, }, + /* 0x50 - 0x5f */ + { "negb", 0, }, + { "?", 0, }, + { "?", 0, }, + { "comb", 0, }, + { "lsrb", 0, }, + { "?", 0, }, + { "rorb", 0, }, + { "asrb", 0, }, + { "aslb", 0, }, + { "rolb", 0, }, + { "decb", 0, }, + { "?", 0, }, + { "incb", 0, }, + { "tstb", 0, }, + { "?", 0, }, + { "clrb", 0, }, + /* 0x60 - 0x6f */ + { "neg", EA_IND_X, }, + { "?", 0, }, + { "?", 0, }, + { "com", EA_IND_X, }, + { "lsr", EA_IND_X, }, + { "?", 0, }, + { "ror", EA_IND_X, }, + { "asr", EA_IND_X, }, + { "asl", EA_IND_X, }, + { "rol", EA_IND_X, }, + { "dec", EA_IND_X, }, + { "?", 0, }, + { "inc", EA_IND_X, }, + { "tst", EA_IND_X, }, + { "jmp", EA_IND_X, }, + { "clr", EA_IND_X, }, + /* 0x70 - 0x7f */ + { "neg", EA_EXT, }, + { "?", 0, }, + { "?", 0, }, + { "com", EA_EXT, }, + { "lsr", EA_EXT, }, + { "?", 0, }, + { "ror", EA_EXT, }, + { "asr", EA_EXT, }, + { "asl", EA_EXT, }, + { "rol", EA_EXT, }, + { "dec", EA_EXT, }, + { "?", 0, }, + { "inc", EA_EXT, }, + { "tst", EA_EXT, }, + { "jmp", EA_EXT, }, + { "clr", EA_EXT, }, + /* 0x80 - 0x8f */ + { "suba", EA_IMM8, }, + { "cmpa", EA_IMM8, }, + { "sbca", EA_IMM8, }, + { "subd", EA_IMM16, }, + { "anda", EA_IMM8, }, + { "bita", EA_IMM8, }, + { "ldaa", EA_IMM8, }, + { "?", 0, }, + { "eora", EA_IMM8, }, + { "adca", EA_IMM8, }, + { "oraa", EA_IMM8, }, + { "adda", EA_IMM8, }, + { "cpx", EA_IMM16, }, + { "bsr", EA_REL, }, + { "lds", EA_IMM16, }, + { "xgdx", 0, }, + /* 0x90 - 0x9f */ + { "suba", EA_DIRECT, }, + { "cmpa", EA_DIRECT, }, + { "sbca", EA_DIRECT, }, + { "subd", EA_DIRECT, }, + { "anda", EA_DIRECT, }, + { "bita", EA_DIRECT, }, + { "ldaa", EA_DIRECT, }, + { "staa", EA_DIRECT, }, + { "eora", EA_DIRECT, }, + { "adca", EA_DIRECT, }, + { "oraa", EA_DIRECT, }, + { "adda", EA_DIRECT, }, + { "cpx", EA_DIRECT, }, + { "jsr", EA_DIRECT, }, + { "lds", EA_DIRECT, }, + { "sts", EA_DIRECT, }, + /* 0xa0 - 0xaf */ + { "suba", EA_IND_X, }, + { "cmpa", EA_IND_X, }, + { "sbca", EA_IND_X, }, + { "subd", EA_IND_X, }, + { "anda", EA_IND_X, }, + { "bita", EA_IND_X, }, + { "ldaa", EA_IND_X, }, + { "staa", EA_IND_X, }, + { "eora", EA_IND_X, }, + { "adca", EA_IND_X, }, + { "oraa", EA_IND_X, }, + { "adda", EA_IND_X, }, + { "cpx", EA_IND_X, }, + { "jsr", EA_IND_X, }, + { "lds", EA_IND_X, }, + { "sts", EA_IND_X, }, + /* 0xb0 - 0xbf */ + { "suba", EA_EXT, }, + { "cmpa", EA_EXT, }, + { "sbca", EA_EXT, }, + { "subd", EA_EXT, }, + { "anda", EA_EXT, }, + { "bita", EA_EXT, }, + { "ldaa", EA_EXT, }, + { "staa", EA_EXT, }, + { "eora", EA_EXT, }, + { "adca", EA_EXT, }, + { "oraa", EA_EXT, }, + { "adda", EA_EXT, }, + { "cpx", EA_EXT, }, + { "jsr", EA_EXT, }, + { "lds", EA_EXT, }, + { "sts", EA_EXT, }, + /* 0xc0 - 0xcf */ + { "subb", EA_IMM8, }, + { "cmpb", EA_IMM8, }, + { "sbcb", EA_IMM8, }, + { "addd", EA_IMM16, }, + { "andb", EA_IMM8, }, + { "bitb", EA_IMM8, }, + { "ldab", EA_IMM8, }, + { "?", 0, }, + { "eorb", EA_IMM8, }, + { "adcb", EA_IMM8, }, + { "orab", EA_IMM8, }, + { "addb", EA_IMM8, }, + { "ldd", EA_IMM16, }, + { "page4", PAGE4, }, + { "ldx", EA_IMM16, }, + { "stop", 0, }, + /* 0xd0 - 0xdf */ + { "subb", EA_DIRECT, }, + { "cmpb", EA_DIRECT, }, + { "sbcb", EA_DIRECT, }, + { "addd", EA_DIRECT, }, + { "andb", EA_DIRECT, }, + { "bitb", EA_DIRECT, }, + { "ldab", EA_DIRECT, }, + { "stab", EA_DIRECT, }, + { "eorb", EA_DIRECT, }, + { "adcb", EA_DIRECT, }, + { "orab", EA_DIRECT, }, + { "addb", EA_DIRECT, }, + { "ldd", EA_DIRECT, }, + { "std", EA_DIRECT, }, + { "ldx", EA_DIRECT, }, + { "stx", EA_DIRECT, }, + /* 0xe0 - 0xef */ + { "subb", EA_IND_X, }, + { "cmpb", EA_IND_X, }, + { "sbcb", EA_IND_X, }, + { "addd", EA_IND_X, }, + { "andb", EA_IND_X, }, + { "bitb", EA_IND_X, }, + { "ldab", EA_IND_X, }, + { "stab", EA_IND_X, }, + { "eorb", EA_IND_X, }, + { "adcb", EA_IND_X, }, + { "orab", EA_IND_X, }, + { "addb", EA_IND_X, }, + { "ldd", EA_IND_X, }, + { "std", EA_IND_X, }, + { "ldx", EA_IND_X, }, + { "stx", EA_IND_X, }, + /* 0xf0 - 0xff */ + { "subb", EA_EXT, }, + { "cmpb", EA_EXT, }, + { "sbcb", EA_EXT, }, + { "addd", EA_EXT, }, + { "andb", EA_EXT, }, + { "bitb", EA_EXT, }, + { "ldab", EA_EXT, }, + { "stab", EA_EXT, }, + { "eorb", EA_EXT, }, + { "adcb", EA_EXT, }, + { "orab", EA_EXT, }, + { "addb", EA_EXT, }, + { "ldd", EA_EXT, }, + { "std", EA_EXT, }, + { "ldx", EA_EXT, }, + { "stx", EA_EXT, }, +}; + + +/*****************************************************************************/ + + +static const M68HC11_OPCODE opcode_table_page2[256] = +{ + /* 0x00 - 0x0f */ + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "iny", 0, }, + { "dey", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + /* 0x10 - 0x1f */ + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "bset", EA_IND_Y_IMM8, }, + { "bclr", EA_IND_Y_IMM8, }, + { "brset", EA_IND_Y_IMM8_REL, }, + { "brlcr", EA_IND_Y_IMM8_REL, }, + /* 0x20 - 0x2f */ + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + /* 0x30 - 0x3f */ + { "tsy", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "tys", 0, }, + { "?", 0, }, + { "?", 0, }, + { "puly", 0, }, + { "?", 0, }, + { "aby", 0, }, + { "?", 0, }, + { "pshy", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + /* 0x40 - 0x4f */ + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + /* 0x50 - 0x5f */ + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + /* 0x60 - 0x6f */ + { "neg", EA_IND_Y, }, + { "?", 0, }, + { "?", 0, }, + { "com", EA_IND_Y, }, + { "lsr", EA_IND_Y, }, + { "?", 0, }, + { "ror", EA_IND_Y, }, + { "asr", EA_IND_Y, }, + { "asl", EA_IND_Y, }, + { "rol", EA_IND_Y, }, + { "dec", EA_IND_Y, }, + { "?", 0, }, + { "inc", EA_IND_Y, }, + { "tst", EA_IND_Y, }, + { "jmp", EA_IND_Y, }, + { "clr", EA_IND_Y, }, + /* 0x70 - 0x7f */ + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + /* 0x80 - 0x8f */ + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "cpy", EA_IMM16, }, + { "?", 0, }, + { "?", 0, }, + { "xgdy", 0, }, + /* 0x90 - 0x9f */ + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "cpy", EA_DIRECT, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + /* 0xa0 - 0xaf */ + { "suba", EA_IND_Y, }, + { "cmpa", EA_IND_Y, }, + { "sbca", EA_IND_Y, }, + { "subd", EA_IND_Y, }, + { "anda", EA_IND_Y, }, + { "bita", EA_IND_Y, }, + { "ldaa", EA_IND_Y, }, + { "staa", EA_IND_Y, }, + { "eora", EA_IND_Y, }, + { "adca", EA_IND_Y, }, + { "oraa", EA_IND_Y, }, + { "adda", EA_IND_Y, }, + { "cpy", EA_IND_Y, }, + { "jsr", EA_IND_Y, }, + { "lds", EA_IND_Y, }, + { "sts", EA_IND_Y, }, + /* 0xb0 - 0xbf */ + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "cpy", EA_EXT, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + /* 0xc0 - 0xcf */ + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "ldy", EA_IMM16, }, + { "?", 0, }, + /* 0xd0 - 0xdf */ + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "ldy", EA_DIRECT, }, + { "sty", EA_DIRECT, }, + /* 0xe0 - 0xef */ + { "subb", EA_IND_Y, }, + { "cmpb", EA_IND_Y, }, + { "sbcb", EA_IND_Y, }, + { "addd", EA_IND_Y, }, + { "andb", EA_IND_Y, }, + { "bitb", EA_IND_Y, }, + { "ldab", EA_IND_Y, }, + { "stab", EA_IND_Y, }, + { "eorb", EA_IND_Y, }, + { "adcb", EA_IND_Y, }, + { "orab", EA_IND_Y, }, + { "addb", EA_IND_Y, }, + { "ldd", EA_IND_Y, }, + { "std", EA_IND_Y, }, + { "ldy", EA_IND_Y, }, + { "sty", EA_IND_Y, }, + /* 0xf0 - 0xff */ + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "ldy", EA_EXT, }, + { "sty", EA_EXT, }, +}; + + +/*****************************************************************************/ + + +static const M68HC11_OPCODE opcode_table_page3[256] = +{ + /* 0x00 - 0x0f */ + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + /* 0x10 - 0x1f */ + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + /* 0x20 - 0x2f */ + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + /* 0x30 - 0x3f */ + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + /* 0x40 - 0x4f */ + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + /* 0x50 - 0x5f */ + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + /* 0x60 - 0x6f */ + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + /* 0x70 - 0x7f */ + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + /* 0x80 - 0x8f */ + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "cpd", EA_IMM16, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + /* 0x90 - 0x9f */ + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "cpd", EA_DIRECT, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + /* 0xa0 - 0xaf */ + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "cpd", EA_IND_X, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "cpy", EA_IND_X, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + /* 0xb0 - 0xbf */ + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "cpd", EA_EXT, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + /* 0xc0 - 0xcf */ + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + /* 0xd0 - 0xdf */ + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + /* 0xe0 - 0xef */ + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "ldy", EA_IND_X, }, + { "sty", EA_IND_X, }, + /* 0xf0 - 0xff */ + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, +}; + + +/*****************************************************************************/ + + +static const M68HC11_OPCODE opcode_table_page4[256] = +{ + /* 0x00 - 0x0f */ + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + /* 0x10 - 0x1f */ + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + /* 0x20 - 0x2f */ + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + /* 0x30 - 0x3f */ + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + /* 0x40 - 0x4f */ + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + /* 0x50 - 0x5f */ + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + /* 0x60 - 0x6f */ + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + /* 0x70 - 0x7f */ + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + /* 0x80 - 0x8f */ + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + /* 0x90 - 0x9f */ + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + /* 0xa0 - 0xaf */ + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "cpd", EA_IND_Y, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "cpx", EA_IND_Y, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + /* 0xb0 - 0xbf */ + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + /* 0xc0 - 0xcf */ + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + /* 0xd0 - 0xdf */ + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + /* 0xe0 - 0xef */ + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "ldx", EA_IND_Y, }, + { "stx", EA_IND_Y, }, + /* 0xf0 - 0xff */ + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, + { "?", 0, }, +}; + + +/*****************************************************************************/ + +static char *output; +static const UINT8 *rombase; + +static void ATTR_PRINTF(1,2) print(const char *fmt, ...) +{ + va_list vl; + + va_start(vl, fmt); + output += vsprintf(output, fmt, vl); + va_end(vl); +} + +static UINT8 fetch(void) +{ + return *rombase++; +} + +static UINT16 fetch16(void) +{ + UINT16 w; + w = (rombase[0] << 8) | rombase[1]; + rombase+=2; + return w; +} + +static UINT32 decode_opcode(UINT32 pc, const M68HC11_OPCODE *op_table) +{ + UINT8 imm8, mask; + INT8 rel8; + UINT16 imm16; + UINT8 op2; + UINT32 flags = 0; + + if (!strcmp(op_table->mnemonic, "jsr") || !strcmp(op_table->mnemonic, "bsr")) + flags = DASMFLAG_STEP_OVER; + else if (!strcmp(op_table->mnemonic, "rts") || !strcmp(op_table->mnemonic, "rti")) + flags = DASMFLAG_STEP_OUT; + + switch(op_table->address_mode) + { + case EA_IMM8: + imm8 = fetch(); + print("%s 0x%02X", op_table->mnemonic, imm8); + break; + + case EA_IMM16: + imm16 = fetch16(); + print("%s 0x%04X", op_table->mnemonic, imm16); + break; + + case EA_DIRECT: + imm8 = fetch(); + print("%s (0x%04X)", op_table->mnemonic, imm8); + break; + + case EA_EXT: + imm16 = fetch16(); + print("%s (0x%04X)", op_table->mnemonic, imm16); + break; + + case EA_IND_X: + imm8 = fetch(); + print("%s (X+0x%02X)", op_table->mnemonic, imm8); + break; + + case EA_REL: + rel8 = fetch(); + print("%s [0x%04X]", op_table->mnemonic, pc+2+rel8); + break; + + case EA_DIRECT_IMM8: + imm8 = fetch(); + mask = fetch(); + print("%s (0x%04X), 0x%02X", op_table->mnemonic, imm8, mask); + break; + + case EA_IND_X_IMM8: + imm8 = fetch(); + mask = fetch(); + print("%s (X+0x%02X), 0x%02X", op_table->mnemonic, imm8, mask); + break; + + case EA_DIRECT_IMM8_REL: + imm8 = fetch(); + mask = fetch(); + rel8 = fetch(); + print("%s (0x%04X), 0x%02X, [0x%04X]", op_table->mnemonic, imm8, mask, pc+4+rel8); + break; + + case EA_IND_X_IMM8_REL: + imm8 = fetch(); + mask = fetch(); + rel8 = fetch(); + print("%s (X+0x%02X), 0x%02X, [0x%04X]", op_table->mnemonic, imm8, mask, pc+4+rel8); + break; + + case EA_IND_Y: + imm8 = fetch(); + print("%s (Y+0x%02X)", op_table->mnemonic, imm8); + break; + + case EA_IND_Y_IMM8: + imm8 = fetch(); + mask = fetch(); + print("%s (Y+0x%02X), 0x%02X", op_table->mnemonic, imm8, mask); + break; + + case EA_IND_Y_IMM8_REL: + imm8 = fetch(); + mask = fetch(); + rel8 = fetch(); + print("%s (Y+0x%02X), 0x%02X, [0x%04X]", op_table->mnemonic, imm8, mask, pc+2+rel8); + break; + + case PAGE2: + op2 = fetch(); + return decode_opcode(pc, &opcode_table_page2[op2]); + + case PAGE3: + op2 = fetch(); + return decode_opcode(pc, &opcode_table_page3[op2]); + + case PAGE4: + op2 = fetch(); + return decode_opcode(pc, &opcode_table_page4[op2]); + + default: + print("%s", op_table->mnemonic); + } + return flags; +} + +CPU_DISASSEMBLE( hc11 ) +{ + UINT32 flags = 0; + UINT8 opcode; + + output = buffer; + rombase = oprom; + + opcode = fetch(); + flags = decode_opcode(pc, &opcode_table[opcode]); + + return (rombase-oprom) | flags | DASMFLAG_SUPPORTED; +} diff --git a/src/devices/cpu/mc68hc11/hc11ops.h b/src/devices/cpu/mc68hc11/hc11ops.h new file mode 100644 index 00000000000..2eafc2850a2 --- /dev/null +++ b/src/devices/cpu/mc68hc11/hc11ops.h @@ -0,0 +1,319 @@ +// license:BSD-3-Clause +// copyright-holders:Ville Linde, Angelo Salese, hap + +const mc68hc11_cpu_device::hc11_opcode_list_struct mc68hc11_cpu_device::hc11_opcode_list[] = +{ + /* page opcode handler */ + { 0, 0x1b, &HC11OP(aba) }, + { 0, 0x3a, &HC11OP(abx) }, + { 0x18, 0x3a, &HC11OP(aby) }, + { 0, 0x89, &HC11OP(adca_imm) }, + { 0, 0x99, &HC11OP(adca_dir) }, + { 0, 0xb9, &HC11OP(adca_ext) }, + { 0, 0xa9, &HC11OP(adca_indx) }, + { 0x18, 0xa9, &HC11OP(adca_indy) }, + { 0, 0xc9, &HC11OP(adcb_imm) }, + { 0, 0xd9, &HC11OP(adcb_dir) }, + { 0, 0xf9, &HC11OP(adcb_ext) }, + { 0, 0xe9, &HC11OP(adcb_indx) }, + { 0x18, 0xe9, &HC11OP(adcb_indy) }, + { 0, 0x8b, &HC11OP(adda_imm) }, + { 0, 0x9b, &HC11OP(adda_dir) }, + { 0, 0xbb, &HC11OP(adda_ext) }, + { 0, 0xab, &HC11OP(adda_indx) }, + { 0x18, 0xab, &HC11OP(adda_indy) }, + { 0, 0xcb, &HC11OP(addb_imm) }, + { 0, 0xdb, &HC11OP(addb_dir) }, + { 0, 0xfb, &HC11OP(addb_ext) }, + { 0, 0xeb, &HC11OP(addb_indx) }, + { 0x18, 0xeb, &HC11OP(addb_indy) }, + { 0, 0xc3, &HC11OP(addd_imm) }, + { 0, 0xd3, &HC11OP(addd_dir) }, + { 0, 0xf3, &HC11OP(addd_ext) }, + { 0, 0xe3, &HC11OP(addd_indx) }, + { 0x18, 0xe3, &HC11OP(addd_indy) }, + { 0, 0x84, &HC11OP(anda_imm) }, + { 0, 0x94, &HC11OP(anda_dir) }, + { 0, 0xb4, &HC11OP(anda_ext) }, + { 0, 0xa4, &HC11OP(anda_indx) }, + { 0x18, 0xa4, &HC11OP(anda_indy) }, + { 0, 0xc4, &HC11OP(andb_imm) }, + { 0, 0xd4, &HC11OP(andb_dir) }, + { 0, 0xf4, &HC11OP(andb_ext) }, + { 0, 0xe4, &HC11OP(andb_indx) }, + { 0x18, 0xe4, &HC11OP(andb_indy) }, + { 0, 0x48, &HC11OP(asla) }, + { 0, 0x58, &HC11OP(aslb) }, + { 0, 0x78, &HC11OP(asl_ext) }, +// { 0, 0x68, &HC11OP(asl_indx) }, +// { 0x18, 0x68, &HC11OP(asl_indy) }, +// { 0, 0x47, &HC11OP(asra) }, +// { 0, 0x57, &HC11OP(asrb) }, +// { 0, 0x77, &HC11OP(asr_ext) }, +// { 0, 0x67, &HC11OP(asr_indx) }, +// { 0x18, 0x67, &HC11OP(asr_indy) }, + { 0, 0x24, &HC11OP(bcc) }, + { 0, 0x15, &HC11OP(bclr_dir) }, + { 0, 0x1d, &HC11OP(bclr_indx) }, +// { 0x18, 0x1d, &HC11OP(bclr_indy) }, + { 0, 0x25, &HC11OP(bcs) }, + { 0, 0x27, &HC11OP(beq) }, +// { 0, 0x2c, &HC11OP(bge) }, +// { 0, 0x2e, &HC11OP(bgt) }, + { 0, 0x22, &HC11OP(bhi) }, + { 0, 0x85, &HC11OP(bita_imm) }, + { 0, 0x95, &HC11OP(bita_dir) }, + { 0, 0xb5, &HC11OP(bita_ext) }, + { 0, 0xa5, &HC11OP(bita_indx) }, + { 0x18, 0xa5, &HC11OP(bita_indy) }, + { 0, 0xc5, &HC11OP(bitb_imm) }, + { 0, 0xd5, &HC11OP(bitb_dir) }, + { 0, 0xf5, &HC11OP(bitb_ext) }, + { 0, 0xe5, &HC11OP(bitb_indx) }, + { 0x18, 0xe5, &HC11OP(bitb_indy) }, + { 0, 0x2f, &HC11OP(ble) }, + { 0, 0x23, &HC11OP(bls) }, +// { 0, 0x2d, &HC11OP(blt) }, + { 0, 0x2b, &HC11OP(bmi) }, + { 0, 0x26, &HC11OP(bne) }, + { 0, 0x2a, &HC11OP(bpl) }, + { 0, 0x20, &HC11OP(bra) }, + { 0, 0x13, &HC11OP(brclr_dir) }, + { 0, 0x1f, &HC11OP(brclr_indx) }, +// { 0x18, 0x1f, &HC11OP(brclr_indy) }, + { 0, 0x21, &HC11OP(brn) }, + { 0, 0x12, &HC11OP(brset_dir) }, + { 0, 0x1e, &HC11OP(brset_indx) }, +// { 0x18, 0x1e, &HC11OP(brset_indy) }, + { 0, 0x14, &HC11OP(bset_dir) }, + { 0, 0x1c, &HC11OP(bset_indx) }, +// { 0x18, 0x1c, &HC11OP(bset_indy) }, + { 0, 0x8d, &HC11OP(bsr) }, + { 0, 0x28, &HC11OP(bvc) }, + { 0, 0x29, &HC11OP(bvs) }, + { 0, 0x11, &HC11OP(cba) }, + { 0, 0x0c, &HC11OP(clc) }, + { 0, 0x0e, &HC11OP(cli) }, + { 0, 0x4f, &HC11OP(clra) }, + { 0, 0x5f, &HC11OP(clrb) }, + { 0, 0x7f, &HC11OP(clr_ext) }, + { 0, 0x6f, &HC11OP(clr_indx) }, + { 0x18, 0x6f, &HC11OP(clr_indy) }, + { 0, 0x0a, &HC11OP(clv) }, + { 0, 0x81, &HC11OP(cmpa_imm) }, + { 0, 0x91, &HC11OP(cmpa_dir) }, + { 0, 0xb1, &HC11OP(cmpa_ext) }, + { 0, 0xa1, &HC11OP(cmpa_indx) }, + { 0x18, 0xa1, &HC11OP(cmpa_indy) }, + { 0, 0xc1, &HC11OP(cmpb_imm) }, + { 0, 0xd1, &HC11OP(cmpb_dir) }, + { 0, 0xf1, &HC11OP(cmpb_ext) }, + { 0, 0xe1, &HC11OP(cmpb_indx) }, + { 0x18, 0xe1, &HC11OP(cmpb_indy) }, + { 0, 0x43, &HC11OP(coma) }, + { 0, 0x53, &HC11OP(comb) }, +// { 0, 0x73, &HC11OP(com_ext) }, +// { 0, 0x63, &HC11OP(com_indx) }, +// { 0x18, 0x63, &HC11OP(com_indy) }, + { 0x1a, 0x83, &HC11OP(cpd_imm) }, + { 0x1a, 0x93, &HC11OP(cpd_dir) }, + { 0x1a, 0xb3, &HC11OP(cpd_ext) }, + { 0x1a, 0xa3, &HC11OP(cpd_indx) }, + { 0xcd, 0xa3, &HC11OP(cpd_indy) }, + { 0, 0x8c, &HC11OP(cpx_imm) }, + { 0, 0x9c, &HC11OP(cpx_dir) }, + { 0, 0xbc, &HC11OP(cpx_ext) }, + { 0, 0xac, &HC11OP(cpx_indx) }, + { 0xcd, 0xac, &HC11OP(cpx_indy) }, + { 0x18, 0x8c, &HC11OP(cpy_imm) }, + { 0x18, 0x9c, &HC11OP(cpy_dir) }, + { 0x18, 0xbc, &HC11OP(cpy_ext) }, + { 0x1a, 0xac, &HC11OP(cpy_indx) }, + { 0x18, 0xac, &HC11OP(cpy_indy) }, +// { 0, 0x19, &HC11OP(daa) }, + { 0, 0x4a, &HC11OP(deca) }, + { 0, 0x5a, &HC11OP(decb) }, + { 0, 0x7a, &HC11OP(dec_ext) }, + { 0, 0x6a, &HC11OP(dec_indx) }, + { 0x18, 0x6a, &HC11OP(dec_indy) }, +// { 0, 0x34, &HC11OP(des) }, + { 0, 0x09, &HC11OP(dex) }, + { 0x18, 0x09, &HC11OP(dey) }, + { 0, 0x88, &HC11OP(eora_imm) }, + { 0, 0x98, &HC11OP(eora_dir) }, + { 0, 0xb8, &HC11OP(eora_ext) }, + { 0, 0xa8, &HC11OP(eora_indx) }, + { 0x18, 0xa8, &HC11OP(eora_indy) }, + { 0, 0xc8, &HC11OP(eorb_imm) }, + { 0, 0xd8, &HC11OP(eorb_dir) }, + { 0, 0xf8, &HC11OP(eorb_ext) }, + { 0, 0xe8, &HC11OP(eorb_indx) }, + { 0x18, 0xe8, &HC11OP(eorb_indy) }, +// { 0, 0x03, &HC11OP(fdiv) }, + { 0, 0x02, &HC11OP(idiv) }, + { 0, 0x4c, &HC11OP(inca) }, + { 0, 0x5c, &HC11OP(incb) }, + { 0, 0x7c, &HC11OP(inc_ext) }, + { 0, 0x6c, &HC11OP(inc_indx) }, + { 0x18, 0x6c, &HC11OP(inc_indy) }, +// { 0, 0x31, &HC11OP(ins) }, + { 0, 0x08, &HC11OP(inx) }, + { 0x18, 0x08, &HC11OP(iny) }, + { 0, 0x7e, &HC11OP(jmp_ext) }, + { 0, 0x6e, &HC11OP(jmp_indx) }, + { 0x18, 0x6e, &HC11OP(jmp_indy) }, + { 0, 0x9d, &HC11OP(jsr_dir) }, + { 0, 0xbd, &HC11OP(jsr_ext) }, + { 0, 0xad, &HC11OP(jsr_indx) }, + { 0x18, 0xad, &HC11OP(jsr_indy) }, + { 0, 0x86, &HC11OP(ldaa_imm) }, + { 0, 0x96, &HC11OP(ldaa_dir) }, + { 0, 0xb6, &HC11OP(ldaa_ext) }, + { 0, 0xa6, &HC11OP(ldaa_indx) }, + { 0x18, 0xa6, &HC11OP(ldaa_indy) }, + { 0, 0xc6, &HC11OP(ldab_imm) }, + { 0, 0xd6, &HC11OP(ldab_dir) }, + { 0, 0xf6, &HC11OP(ldab_ext) }, + { 0, 0xe6, &HC11OP(ldab_indx) }, + { 0x18, 0xe6, &HC11OP(ldab_indy) }, + { 0, 0xcc, &HC11OP(ldd_imm) }, + { 0, 0xdc, &HC11OP(ldd_dir) }, + { 0, 0xfc, &HC11OP(ldd_ext) }, + { 0, 0xec, &HC11OP(ldd_indx) }, + { 0x18, 0xec, &HC11OP(ldd_indy) }, + { 0, 0x8e, &HC11OP(lds_imm) }, + { 0, 0x9e, &HC11OP(lds_dir) }, + { 0, 0xbe, &HC11OP(lds_ext) }, + { 0, 0xae, &HC11OP(lds_indx) }, + { 0x18, 0xae, &HC11OP(lds_indy) }, + { 0, 0xce, &HC11OP(ldx_imm) }, + { 0, 0xde, &HC11OP(ldx_dir) }, + { 0, 0xfe, &HC11OP(ldx_ext) }, + { 0, 0xee, &HC11OP(ldx_indx) }, + { 0xcd, 0xee, &HC11OP(ldx_indy) }, + { 0x18, 0xce, &HC11OP(ldy_imm) }, + { 0x18, 0xde, &HC11OP(ldy_dir) }, + { 0x18, 0xfe, &HC11OP(ldy_ext) }, + { 0x1a, 0xee, &HC11OP(ldy_indx) }, + { 0x18, 0xee, &HC11OP(ldy_indy) }, + { 0, 0x05, &HC11OP(lsld) }, + { 0, 0x44, &HC11OP(lsra) }, + { 0, 0x54, &HC11OP(lsrb) }, +// { 0, 0x74, &HC11OP(lsr_ext) }, +// { 0, 0x64, &HC11OP(lsr_indx) }, +// { 0x18, 0x64, &HC11OP(lsr_indy) }, + { 0, 0x04, &HC11OP(lsrd) }, + { 0, 0x3d, &HC11OP(mul) }, + { 0, 0x40, &HC11OP(nega) }, + { 0, 0x50, &HC11OP(negb) }, + { 0, 0x70, &HC11OP(neg_ext) }, + { 0, 0x60, &HC11OP(neg_indx) }, + { 0x18, 0x60, &HC11OP(neg_indy) }, + { 0, 0x01, &HC11OP(nop) }, + { 0, 0x8a, &HC11OP(oraa_imm) }, + { 0, 0x9a, &HC11OP(oraa_dir) }, + { 0, 0xba, &HC11OP(oraa_ext) }, + { 0, 0xaa, &HC11OP(oraa_indx) }, + { 0x18, 0xaa, &HC11OP(oraa_indy) }, + { 0, 0xca, &HC11OP(orab_imm) }, + { 0, 0xda, &HC11OP(orab_dir) }, + { 0, 0xfa, &HC11OP(orab_ext) }, + { 0, 0xea, &HC11OP(orab_indx) }, + { 0x18, 0xea, &HC11OP(orab_indy) }, + { 0, 0x36, &HC11OP(psha) }, + { 0, 0x37, &HC11OP(pshb) }, + { 0, 0x3c, &HC11OP(pshx) }, + { 0x18, 0x3c, &HC11OP(pshy) }, + { 0, 0x32, &HC11OP(pula) }, + { 0, 0x33, &HC11OP(pulb) }, + { 0, 0x38, &HC11OP(pulx) }, + { 0x18, 0x38, &HC11OP(puly) }, + { 0, 0x49, &HC11OP(rola) }, + { 0, 0x59, &HC11OP(rolb) }, + { 0, 0x79, &HC11OP(rol_ext) }, + { 0, 0x69, &HC11OP(rol_indx) }, + { 0x18, 0x69, &HC11OP(rol_indy) }, + { 0, 0x46, &HC11OP(rora) }, + { 0, 0x56, &HC11OP(rorb) }, +// { 0, 0x76, &HC11OP(ror_ext) }, +// { 0, 0x66, &HC11OP(ror_indx) }, +// { 0x18, 0x66, &HC11OP(ror_indy) }, + { 0, 0x3b, &HC11OP(rti) }, + { 0, 0x39, &HC11OP(rts) }, + { 0, 0x10, &HC11OP(sba) }, + { 0, 0x82, &HC11OP(sbca_imm) }, +// { 0, 0x92, &HC11OP(sbca_dir) }, +// { 0, 0xb2, &HC11OP(sbca_ext) }, + { 0, 0xa2, &HC11OP(sbca_indx) }, + { 0x18, 0xa2, &HC11OP(sbca_indy) }, + { 0, 0xc2, &HC11OP(sbcb_imm) }, +// { 0, 0xd2, &HC11OP(sbcb_dir) }, +// { 0, 0xf2, &HC11OP(sbcb_ext) }, + { 0, 0xe2, &HC11OP(sbcb_indx) }, + { 0x18, 0xe2, &HC11OP(sbcb_indy) }, + { 0, 0x0d, &HC11OP(sec) }, + { 0, 0x0f, &HC11OP(sei) }, + { 0, 0x0b, &HC11OP(sev) }, + { 0, 0x97, &HC11OP(staa_dir) }, + { 0, 0xb7, &HC11OP(staa_ext) }, + { 0, 0xa7, &HC11OP(staa_indx) }, + { 0x18, 0xa7, &HC11OP(staa_indy) }, + { 0, 0xd7, &HC11OP(stab_dir) }, + { 0, 0xf7, &HC11OP(stab_ext) }, + { 0, 0xe7, &HC11OP(stab_indx) }, + { 0x18, 0xe7, &HC11OP(stab_indy) }, + { 0, 0xdd, &HC11OP(std_dir) }, + { 0, 0xfd, &HC11OP(std_ext) }, + { 0, 0xed, &HC11OP(std_indx) }, + { 0x18, 0xed, &HC11OP(std_indy) }, + { 0, 0x9f, &HC11OP(sts_dir) }, +// { 0, 0xbf, &HC11OP(sts_ext) }, +// { 0, 0xaf, &HC11OP(sts_indx) }, +// { 0x18, 0xaf, &HC11OP(sts_indy) }, + { 0, 0xdf, &HC11OP(stx_dir) }, + { 0, 0xff, &HC11OP(stx_ext) }, + { 0, 0xef, &HC11OP(stx_indx) }, + { 0xcd, 0xef, &HC11OP(stx_indy) }, + { 0x18, 0xdf, &HC11OP(sty_dir) }, + { 0x18, 0xff, &HC11OP(sty_ext) }, + { 0x1a, 0xef, &HC11OP(sty_indx) }, + { 0x18, 0xef, &HC11OP(sty_indy) }, + { 0, 0xcf, &HC11OP(stop) }, + { 0, 0x80, &HC11OP(suba_imm) }, + { 0, 0x90, &HC11OP(suba_dir) }, + { 0, 0xb0, &HC11OP(suba_ext) }, + { 0, 0xa0, &HC11OP(suba_indx) }, + { 0x18, 0xa0, &HC11OP(suba_indy) }, + { 0, 0xc0, &HC11OP(subb_imm) }, + { 0, 0xd0, &HC11OP(subb_dir) }, + { 0, 0xf0, &HC11OP(subb_ext) }, + { 0, 0xe0, &HC11OP(subb_indx) }, + { 0x18, 0xe0, &HC11OP(subb_indy) }, + { 0, 0x83, &HC11OP(subd_imm) }, + { 0, 0x93, &HC11OP(subd_dir) }, + { 0, 0xb3, &HC11OP(subd_ext) }, + { 0, 0xa3, &HC11OP(subd_indx) }, + { 0x18, 0xa3, &HC11OP(subd_indy) }, + { 0, 0x3f, &HC11OP(swi) }, + { 0, 0x16, &HC11OP(tab) }, + { 0, 0x06, &HC11OP(tap) }, + { 0, 0x17, &HC11OP(tba) }, + { 0, 0x00, &HC11OP(test) }, + { 0, 0x07, &HC11OP(tpa) }, + { 0, 0x4d, &HC11OP(tsta) }, + { 0, 0x5d, &HC11OP(tstb) }, + { 0, 0x7d, &HC11OP(tst_ext) }, + { 0, 0x6d, &HC11OP(tst_indx) }, + { 0x18, 0x6d, &HC11OP(tst_indy) }, + { 0, 0x30, &HC11OP(tsx) }, + { 0x18, 0x30, &HC11OP(tsy) }, + { 0, 0x35, &HC11OP(txs) }, + { 0x18, 0x35, &HC11OP(tys) }, + { 0, 0x3e, &HC11OP(wai) }, + { 0, 0x8f, &HC11OP(xgdx) }, + { 0x18, 0x8f, &HC11OP(xgdy) }, + + { 0, 0x18, &HC11OP(page2) }, + { 0, 0x1a, &HC11OP(page3) }, + { 0, 0xcd, &HC11OP(page4) }, +}; diff --git a/src/devices/cpu/mc68hc11/hc11ops.inc b/src/devices/cpu/mc68hc11/hc11ops.inc new file mode 100644 index 00000000000..cb71a839c2f --- /dev/null +++ b/src/devices/cpu/mc68hc11/hc11ops.inc @@ -0,0 +1,3592 @@ +// license:BSD-3-Clause +// copyright-holders:Ville Linde, Angelo Salese, hap + +#define SET_Z8(r) (m_ccr |= ((UINT8)r == 0) ? CC_Z : 0) +#define SET_Z16(r) (m_ccr |= ((UINT16)r == 0) ? CC_Z : 0) +#define SET_N8(r) (m_ccr |= (r & 0x80) ? CC_N : 0) +#define SET_N16(r) (m_ccr |= (r & 0x8000) ? CC_N : 0) +#define SET_V_ADD8(r,s,d) (m_ccr |= (((r) ^ (s)) & ((r) ^ (d)) & 0x80) ? CC_V : 0) +#define SET_V_SUB8(r,s,d) (m_ccr |= (((d) ^ (s)) & ((d) ^ (r)) & 0x80) ? CC_V : 0) +#define SET_V_ADD16(r,s,d) (m_ccr |= (((r) ^ (s)) & ((r) ^ (d)) & 0x8000) ? CC_V : 0) +#define SET_V_SUB16(r,s,d) (m_ccr |= (((d) ^ (s)) & ((d) ^ (r)) & 0x8000) ? CC_V : 0) +#define SET_H(r,s,d) (m_ccr |= (((r) ^ (s) ^ (d)) & 0x10) ? CC_H : 0) +#define SET_C8(x) (m_ccr |= ((x) & 0x100) ? CC_C : 0) +#define SET_C16(x) (m_ccr |= ((x) & 0x10000) ? CC_C : 0) +#define CLEAR_Z() (m_ccr &= ~(CC_Z)) +#define CLEAR_C() (m_ccr &= ~(CC_C)) +#define CLEAR_NZV() (m_ccr &= ~(CC_N | CC_Z | CC_V)) +#define CLEAR_ZVC() (m_ccr &= ~(CC_Z | CC_V | CC_C)) +#define CLEAR_NZVC() (m_ccr &= ~(CC_N | CC_Z | CC_V | CC_C)) +#define CLEAR_HNZVC() (m_ccr &= ~(CC_H | CC_N | CC_Z | CC_V | CC_C)) + +#define SET_ZFLAG() (m_ccr |= CC_Z) +#define SET_NFLAG() (m_ccr |= CC_N) +#define SET_VFLAG() (m_ccr |= CC_V) + +#define REG_A m_d.d8.a +#define REG_B m_d.d8.b +#define REG_D m_d.d16 + +void mc68hc11_cpu_device::CYCLES(int cycles) +{ + m_icount -= cycles; +} + +void mc68hc11_cpu_device::SET_PC(int pc) +{ + m_pc = pc; +} + +void mc68hc11_cpu_device::PUSH8(UINT8 value) +{ + WRITE8(m_sp--, value); +} + +void mc68hc11_cpu_device::PUSH16(UINT16 value) +{ + WRITE8(m_sp--, (value >> 0) & 0xff); + WRITE8(m_sp--, (value >> 8) & 0xff); +} + +UINT8 mc68hc11_cpu_device::POP8() +{ + return READ8(++m_sp); +} + +UINT16 mc68hc11_cpu_device::POP16() +{ + UINT16 r = 0; + r |= (READ8(++m_sp) << 8); + r |= (READ8(++m_sp) << 0); + return r; +} + + + +/*****************************************************************************/ + +/* ABA 0x1B */ +void HC11OP(aba)() +{ + UINT16 r = REG_A + REG_B; + CLEAR_HNZVC(); + SET_H(r, REG_B, REG_A); + SET_N8(r); + SET_Z8(r); + SET_V_ADD8(r, REG_B, REG_A); + SET_C8(r); + REG_A = (UINT8)r; + CYCLES(2); +} + + +/* ABX 0x3A */ +void HC11OP(abx)() +{ + m_ix += REG_B; + CYCLES(3); +} + + +/* ABY 0x18, 0x3A */ +void HC11OP(aby)() +{ + m_iy += REG_B; + CYCLES(4); +} + + +/* ADCA IMM 0x89 */ +void HC11OP(adca_imm)() +{ + UINT8 i = FETCH(); + UINT16 r = REG_A + i + ((m_ccr & CC_C) ? 1 : 0); + CLEAR_HNZVC(); + SET_H(r, i, REG_A); + SET_N8(r); + SET_Z8(r); + SET_V_ADD8(r, i, REG_A); + SET_C8(r); + REG_A = (UINT8)r; + CYCLES(2); +} + +/* ADCA DIR 0x99 */ +void HC11OP(adca_dir)() +{ + UINT8 d = FETCH(); + UINT8 i = READ8(d); + UINT16 r = REG_A + i + ((m_ccr & CC_C) ? 1 : 0); + CLEAR_HNZVC(); + SET_H(r, i, REG_A); + SET_N8(r); + SET_Z8(r); + SET_V_ADD8(r, i, REG_A); + SET_C8(r); + REG_A = (UINT8)r; + CYCLES(3); +} + +/* ADCA EXT 0xB9 */ +void HC11OP(adca_ext)() +{ + UINT16 adr = FETCH16(); + UINT8 i = READ8(adr); + UINT16 r = REG_A + i + ((m_ccr & CC_C) ? 1 : 0); + CLEAR_HNZVC(); + SET_H(r, i, REG_A); + SET_N8(r); + SET_Z8(r); + SET_V_ADD8(r, i, REG_A); + SET_C8(r); + REG_A = (UINT8)r; + CYCLES(4); +} + +/* ADCA IND, X 0xA9 */ +void HC11OP(adca_indx)() +{ + UINT8 offset = FETCH(); + UINT8 i = READ8(m_ix + offset); + UINT16 r = REG_A + i + ((m_ccr & CC_C) ? 1 : 0); + CLEAR_HNZVC(); + SET_H(r, i, REG_A); + SET_N8(r); + SET_Z8(r); + SET_V_ADD8(r, i, REG_A); + SET_C8(r); + REG_A = (UINT8)r; + CYCLES(4); +} + +/* ADCA IND, Y 0x18, 0xA9 */ +void HC11OP(adca_indy)() +{ + UINT8 offset = FETCH(); + UINT8 i = READ8(m_iy + offset); + UINT16 r = REG_A + i + ((m_ccr & CC_C) ? 1 : 0); + CLEAR_HNZVC(); + SET_H(r, i, REG_A); + SET_N8(r); + SET_Z8(r); + SET_V_ADD8(r, i, REG_A); + SET_C8(r); + REG_A = (UINT8)r; + CYCLES(5); +} + + +/* ADCB IMM 0xC9 */ +void HC11OP(adcb_imm)() +{ + UINT8 i = FETCH(); + UINT16 r = REG_B + i + ((m_ccr & CC_C) ? 1 : 0); + CLEAR_HNZVC(); + SET_H(r, i, REG_B); + SET_N8(r); + SET_Z8(r); + SET_V_ADD8(r, i, REG_B); + SET_C8(r); + REG_B = (UINT8)r; + CYCLES(2); +} + +/* ADCB DIR 0xD9 */ +void HC11OP(adcb_dir)() +{ + UINT8 d = FETCH(); + UINT8 i = READ8(d); + UINT16 r = REG_B + i + ((m_ccr & CC_C) ? 1 : 0); + CLEAR_HNZVC(); + SET_H(r, i, REG_B); + SET_N8(r); + SET_Z8(r); + SET_V_ADD8(r, i, REG_B); + SET_C8(r); + REG_B = (UINT8)r; + CYCLES(3); +} + +/* ADCB EXT 0xF9 */ +void HC11OP(adcb_ext)() +{ + UINT16 adr = FETCH16(); + UINT8 i = READ8(adr); + UINT16 r = REG_B + i + ((m_ccr & CC_C) ? 1 : 0); + CLEAR_HNZVC(); + SET_H(r, i, REG_B); + SET_N8(r); + SET_Z8(r); + SET_V_ADD8(r, i, REG_B); + SET_C8(r); + REG_B = (UINT8)r; + CYCLES(4); +} + +/* ADCB IND, X 0xE9 */ +void HC11OP(adcb_indx)() +{ + UINT8 offset = FETCH(); + UINT8 i = READ8(m_ix + offset); + UINT16 r = REG_B + i + ((m_ccr & CC_C) ? 1 : 0); + CLEAR_HNZVC(); + SET_H(r, i, REG_B); + SET_N8(r); + SET_Z8(r); + SET_V_ADD8(r, i, REG_B); + SET_C8(r); + REG_B = (UINT8)r; + CYCLES(4); +} + +/* ADCB IND, Y 0x18, 0xE9 */ +void HC11OP(adcb_indy)() +{ + UINT8 offset = FETCH(); + UINT8 i = READ8(m_iy + offset); + UINT16 r = REG_B + i + ((m_ccr & CC_C) ? 1 : 0); + CLEAR_HNZVC(); + SET_H(r, i, REG_B); + SET_N8(r); + SET_Z8(r); + SET_V_ADD8(r, i, REG_B); + SET_C8(r); + REG_B = (UINT8)r; + CYCLES(5); +} + + +/* ADDA IMM 0x8B */ +void HC11OP(adda_imm)() +{ + UINT8 i = FETCH(); + UINT16 r = REG_A + i; + CLEAR_HNZVC(); + SET_H(r, i, REG_A); + SET_N8(r); + SET_Z8(r); + SET_V_ADD8(r, i, REG_A); + SET_C8(r); + REG_A = (UINT8)r; + CYCLES(2); +} + +/* ADDA DIR 0x9B */ +void HC11OP(adda_dir)() +{ + UINT8 d = FETCH(); + UINT8 i = READ8(d); + UINT16 r = REG_A + i; + CLEAR_HNZVC(); + SET_H(r, i, REG_A); + SET_N8(r); + SET_Z8(r); + SET_V_ADD8(r, i, REG_A); + SET_C8(r); + REG_A = (UINT8)r; + CYCLES(3); +} + +/* ADDA EXT 0xBB */ +void HC11OP(adda_ext)() +{ + UINT16 adr = FETCH16(); + UINT8 i = READ8(adr); + UINT16 r = REG_A + i; + CLEAR_HNZVC(); + SET_H(r, i, REG_A); + SET_N8(r); + SET_Z8(r); + SET_V_ADD8(r, i, REG_A); + SET_C8(r); + REG_A = (UINT8)r; + CYCLES(4); +} + +/* ADDA IND, X 0xAB */ +void HC11OP(adda_indx)() +{ + UINT8 offset = FETCH(); + UINT8 i = READ8(m_ix + offset); + UINT16 r = REG_A + i; + CLEAR_HNZVC(); + SET_H(r, i, REG_A); + SET_N8(r); + SET_Z8(r); + SET_V_ADD8(r, i, REG_A); + SET_C8(r); + REG_A = (UINT8)r; + CYCLES(4); +} + +/* ADDA IND, Y 0x18, 0xAB */ +void HC11OP(adda_indy)() +{ + UINT8 offset = FETCH(); + UINT8 i = READ8(m_iy + offset); + UINT16 r = REG_A + i; + CLEAR_HNZVC(); + SET_H(r, i, REG_A); + SET_N8(r); + SET_Z8(r); + SET_V_ADD8(r, i, REG_A); + SET_C8(r); + REG_A = (UINT8)r; + CYCLES(5); +} + + +/* ADDB IMM 0xCB */ +void HC11OP(addb_imm)() +{ + UINT8 i = FETCH(); + UINT16 r = REG_B + i; + CLEAR_HNZVC(); + SET_H(r, i, REG_B); + SET_N8(r); + SET_Z8(r); + SET_V_ADD8(r, i, REG_B); + SET_C8(r); + REG_B = (UINT8)r; + CYCLES(2); +} + +/* ADDB DIR 0xDB */ +void HC11OP(addb_dir)() +{ + UINT8 d = FETCH(); + UINT8 i = READ8(d); + UINT16 r = REG_B + i; + CLEAR_HNZVC(); + SET_H(r, i, REG_B); + SET_N8(r); + SET_Z8(r); + SET_V_ADD8(r, i, REG_B); + SET_C8(r); + REG_B = (UINT8)r; + CYCLES(3); +} + +/* ADDB EXT 0xFB */ +void HC11OP(addb_ext)() +{ + UINT16 adr = FETCH16(); + UINT8 i = READ8(adr); + UINT16 r = REG_B + i; + CLEAR_HNZVC(); + SET_H(r, i, REG_B); + SET_N8(r); + SET_Z8(r); + SET_V_ADD8(r, i, REG_B); + SET_C8(r); + REG_B = (UINT8)r; + CYCLES(4); +} + +/* ADDB IND, X 0xEB */ +void HC11OP(addb_indx)() +{ + UINT8 offset = FETCH(); + UINT8 i = READ8(m_ix + offset); + UINT16 r = REG_B + i; + CLEAR_HNZVC(); + SET_H(r, i, REG_B); + SET_N8(r); + SET_Z8(r); + SET_V_ADD8(r, i, REG_B); + SET_C8(r); + REG_B = (UINT8)r; + CYCLES(4); +} + +/* ADDB IND, Y 0x18, 0xEB */ +void HC11OP(addb_indy)() +{ + UINT8 offset = FETCH(); + UINT8 i = READ8(m_iy + offset); + UINT16 r = REG_B + i; + CLEAR_HNZVC(); + SET_H(r, i, REG_B); + SET_N8(r); + SET_Z8(r); + SET_V_ADD8(r, i, REG_B); + SET_C8(r); + REG_B = (UINT8)r; + CYCLES(5); +} + + +/* ADDD IMM 0xC3 */ +void HC11OP(addd_imm)() +{ + UINT16 i = FETCH16(); + UINT32 r = REG_D + i; + CLEAR_NZVC(); + SET_N16(r); + SET_Z16(r); + SET_V_ADD16(r, i, REG_D); + SET_C16(r); + REG_D = (UINT16)r; + CYCLES(4); +} + +/* ADDD DIR 0xD3 */ +void HC11OP(addd_dir)() +{ + UINT8 d = FETCH(); + UINT16 i = READ16(d); + UINT32 r = REG_D + i; + CLEAR_NZVC(); + SET_N16(r); + SET_Z16(r); + SET_V_ADD16(r, i, REG_D); + SET_C16(r); + REG_D = (UINT16)r; + CYCLES(5); +} + +/* ADDD EXT 0xF3 */ +void HC11OP(addd_ext)() +{ + UINT16 adr = FETCH16(); + UINT16 i = READ16(adr); + UINT32 r = REG_D + i; + CLEAR_NZVC(); + SET_N16(r); + SET_Z16(r); + SET_V_ADD16(r, i, REG_D); + SET_C16(r); + REG_D = (UINT16)r; + CYCLES(6); +} + +/* ADDD IND, X 0xE3 */ +void HC11OP(addd_indx)() +{ + UINT8 offset = FETCH(); + UINT16 i = READ16(m_ix + offset); + UINT32 r = REG_D + i; + CLEAR_NZVC(); + SET_N16(r); + SET_Z16(r); + SET_V_ADD16(r, i, REG_D); + SET_C16(r); + REG_D = (UINT16)r; + CYCLES(6); +} + +/* ADDD IND, Y 0x18, 0xE3 */ +void HC11OP(addd_indy)() +{ + UINT8 offset = FETCH(); + UINT16 i = READ16(m_iy + offset); + UINT32 r = REG_D + i; + CLEAR_NZVC(); + SET_N16(r); + SET_Z16(r); + SET_V_ADD16(r, i, REG_D); + SET_C16(r); + REG_D = (UINT16)r; + CYCLES(7); +} + + +/* ANDA IMM 0x84 */ +void HC11OP(anda_imm)() +{ + UINT8 i = FETCH(); + CLEAR_NZV(); + REG_A &= i; + SET_N8(REG_A); + SET_Z8(REG_A); + CYCLES(2); +} + +/* ANDA DIR 0x94 */ +void HC11OP(anda_dir)() +{ + UINT8 d = FETCH(); + UINT8 i = READ8(d); + CLEAR_NZV(); + REG_A &= i; + SET_N8(REG_A); + SET_Z8(REG_A); + CYCLES(3); +} + +/* ANDA EXT 0xB4 */ +void HC11OP(anda_ext)() +{ + UINT16 adr = FETCH16(); + UINT8 i = READ8(adr); + CLEAR_NZV(); + REG_A &= i; + SET_N8(REG_A); + SET_Z8(REG_A); + CYCLES(4); +} + +/* ANDA IND, X 0xA4 */ +void HC11OP(anda_indx)() +{ + UINT8 offset = FETCH(); + UINT8 i = READ8(m_ix + offset); + CLEAR_NZV(); + REG_A &= i; + SET_N8(REG_A); + SET_Z8(REG_A); + CYCLES(4); +} + +/* ANDA IND, Y 0x18, 0xA4 */ +void HC11OP(anda_indy)() +{ + UINT8 offset = FETCH(); + UINT8 i = READ8(m_iy + offset); + CLEAR_NZV(); + REG_A &= i; + SET_N8(REG_A); + SET_Z8(REG_A); + CYCLES(5); +} + + +/* ANDB IMM 0xC4 */ +void HC11OP(andb_imm)() +{ + UINT8 i = FETCH(); + CLEAR_NZV(); + REG_B &= i; + SET_N8(REG_B); + SET_Z8(REG_B); + CYCLES(2); +} + +/* ANDB DIR 0xD4 */ +void HC11OP(andb_dir)() +{ + UINT8 d = FETCH(); + UINT8 i = READ8(d); + CLEAR_NZV(); + REG_B &= i; + SET_N8(REG_B); + SET_Z8(REG_B); + CYCLES(3); +} + +/* ANDB EXT 0xF4 */ +void HC11OP(andb_ext)() +{ + UINT16 adr = FETCH16(); + UINT8 i = READ8(adr); + CLEAR_NZV(); + REG_B &= i; + SET_N8(REG_B); + SET_Z8(REG_B); + CYCLES(4); +} + +/* ANDB IND, X 0xE4 */ +void HC11OP(andb_indx)() +{ + UINT8 offset = FETCH(); + UINT8 i = READ8(m_ix + offset); + CLEAR_NZV(); + REG_B &= i; + SET_N8(REG_B); + SET_Z8(REG_B); + CYCLES(4); +} + +/* ANDB IND, Y 0x18, 0xE4 */ +void HC11OP(andb_indy)() +{ + UINT8 offset = FETCH(); + UINT8 i = READ8(m_iy + offset); + CLEAR_NZV(); + REG_B &= i; + SET_N8(REG_B); + SET_Z8(REG_B); + CYCLES(5); +} + +/* ASLA 0x48 */ +void HC11OP(asla)() +{ + UINT16 r = REG_A << 1; + CLEAR_NZVC(); + SET_C8(r); + REG_A = (UINT16)(r); + SET_N8(REG_A); + SET_Z8(REG_A); + + if (((m_ccr & CC_N) && (m_ccr & CC_C) == 0) || + ((m_ccr & CC_N) == 0 && (m_ccr & CC_C))) + { + m_ccr |= CC_V; + } + + CYCLES(2); +} + +/* ASLB 0x58 */ +void HC11OP(aslb)() +{ + UINT16 r = REG_B << 1; + CLEAR_NZVC(); + SET_C8(r); + REG_B = (UINT16)(r); + SET_N8(REG_B); + SET_Z8(REG_B); + + if (((m_ccr & CC_N) && (m_ccr & CC_C) == 0) || + ((m_ccr & CC_N) == 0 && (m_ccr & CC_C))) + { + m_ccr |= CC_V; + } + + CYCLES(2); +} + +/* ASL EXT 0x78 */ +void HC11OP(asl_ext)() +{ + UINT16 adr = FETCH16(); + UINT8 i = READ8(adr); + UINT16 r = i << 1; + CLEAR_NZVC(); + SET_C8(r); + WRITE8(adr, r); + SET_N8(r); + SET_Z8(r); + + if (((m_ccr & CC_N) && (m_ccr & CC_C) == 0) || + ((m_ccr & CC_N) == 0 && (m_ccr & CC_C))) + { + m_ccr |= CC_V; + } + + CYCLES(6); +} + +/* BITA IMM 0x85 */ +void HC11OP(bita_imm)() +{ + UINT8 i = FETCH(); + UINT8 r = REG_A & i; + CLEAR_NZV(); + SET_N8(r); + SET_Z8(r); + CYCLES(2); +} + +/* BITA DIR 0x95 */ +void HC11OP(bita_dir)() +{ + UINT8 d = FETCH(); + UINT8 i = READ8(d); + UINT8 r = REG_A & i; + CLEAR_NZV(); + SET_N8(r); + SET_Z8(r); + CYCLES(3); +} + +/* BITA EXT 0xB5 */ +void HC11OP(bita_ext)() +{ + UINT16 adr = FETCH16(); + UINT8 i = READ8(adr); + UINT8 r = REG_A & i; + CLEAR_NZV(); + SET_N8(r); + SET_Z8(r); + CYCLES(4); +} + +/* BITA IND, X 0xA5 */ +void HC11OP(bita_indx)() +{ + UINT8 offset = FETCH(); + UINT8 i = READ8(m_ix + offset); + UINT8 r = REG_A & i; + CLEAR_NZV(); + SET_N8(r); + SET_Z8(r); + CYCLES(4); +} + +/* BITA IND, Y 0x18, 0xA5 */ +void HC11OP(bita_indy)() +{ + UINT8 offset = FETCH(); + UINT8 i = READ8(m_iy + offset); + UINT8 r = REG_A & i; + CLEAR_NZV(); + SET_N8(r); + SET_Z8(r); + CYCLES(5); +} + + +/* BITB IMM 0xC5 */ +void HC11OP(bitb_imm)() +{ + UINT8 i = FETCH(); + UINT8 r = REG_B & i; + CLEAR_NZV(); + SET_N8(r); + SET_Z8(r); + CYCLES(2); +} + +/* BITB DIR 0xD5 */ +void HC11OP(bitb_dir)() +{ + UINT8 d = FETCH(); + UINT8 i = READ8(d); + UINT8 r = REG_B & i; + CLEAR_NZV(); + SET_N8(r); + SET_Z8(r); + CYCLES(3); +} + +/* BITB EXT 0xF5 */ +void HC11OP(bitb_ext)() +{ + UINT16 adr = FETCH16(); + UINT8 i = READ8(adr); + UINT8 r = REG_B & i; + CLEAR_NZV(); + SET_N8(r); + SET_Z8(r); + CYCLES(4); +} + +/* BITB IND, X 0xE5 */ +void HC11OP(bitb_indx)() +{ + UINT8 offset = FETCH(); + UINT8 i = READ8(m_ix + offset); + UINT8 r = REG_B & i; + CLEAR_NZV(); + SET_N8(r); + SET_Z8(r); + CYCLES(4); +} + +/* BITB IND, Y 0x18, 0xE5 */ +void HC11OP(bitb_indy)() +{ + UINT8 offset = FETCH(); + UINT8 i = READ8(m_iy + offset); + UINT8 r = REG_B & i; + CLEAR_NZV(); + SET_N8(r); + SET_Z8(r); + CYCLES(5); +} + +/* BCC 0x24 */ +void HC11OP(bcc)() +{ + INT8 rel = FETCH(); + if ((m_ccr & CC_C) == 0) /* Branch if C flag clear */ + { + SET_PC(m_ppc + rel + 2); + } + CYCLES(3); +} + +/* BCLR DIR 0x15 */ +void HC11OP(bclr_dir)() +{ + UINT8 d = FETCH(); + UINT8 mask = FETCH(); + UINT8 r = READ8(d) & ~mask; + WRITE8(d, r); + CLEAR_NZV(); + SET_N8(r); + SET_Z8(r); + CYCLES(6); +} + +/* BCLR INDX 0x1d */ +void HC11OP(bclr_indx)() +{ + UINT8 offset = FETCH(); + UINT8 mask = FETCH(); + UINT8 r = READ8(m_ix + offset) & ~mask; + WRITE8(m_ix + offset, r); + CLEAR_NZV(); + SET_N8(r); + SET_Z8(r); + + CYCLES(7); +} + +/* BCS 0x25 */ +void HC11OP(bcs)() +{ + INT8 rel = FETCH(); + if (m_ccr & CC_C) /* Branch if C flag set */ + { + SET_PC(m_ppc + rel + 2); + } + CYCLES(3); +} + + +/* BEQ 0x27 */ +void HC11OP(beq)() +{ + INT8 rel = FETCH(); + if (m_ccr & CC_Z) /* Branch if Z flag set */ + { + SET_PC(m_ppc + rel + 2); + } + CYCLES(3); +} + + +/* BHI 0x22 */ +void HC11OP(bhi)() +{ + INT8 rel = FETCH(); + if (((m_ccr & CC_C) == 0) && ((m_ccr & CC_Z) == 0)) /* Branch if C and Z flag clear */ + { + SET_PC(m_ppc + rel + 2); + } + CYCLES(3); +} + + +/* BNE 0x26 */ +void HC11OP(bne)() +{ + INT8 rel = FETCH(); + if ((m_ccr & CC_Z) == 0) /* Branch if Z flag clear */ + { + SET_PC(m_ppc + rel + 2); + } + CYCLES(3); +} + + +/* BLE 0x2F */ +void HC11OP(ble)() +{ + UINT8 n = (m_ccr & CC_N) ? 1 : 0; + UINT8 v = (m_ccr & CC_V) ? 1 : 0; + INT8 rel = FETCH(); + if ((m_ccr & CC_Z) || (n ^ v)) /* Branch if Z flag set or (N ^ V) */ + { + SET_PC(m_ppc + rel + 2); + } + CYCLES(3); +} + +/* BLS 0x23 */ +void HC11OP(bls)() +{ + INT8 rel = FETCH(); + if (m_ccr & CC_C || m_ccr & CC_Z) /* Branch if C or Z flag set */ + { + SET_PC(m_ppc + rel + 2); + } + CYCLES(3); +} + +/* BMI 0x2B */ +void HC11OP(bmi)() +{ + INT8 rel = FETCH(); + if (m_ccr & CC_N) /* Branch if N flag set */ + { + SET_PC(m_ppc + rel + 2); + } + CYCLES(3); +} + +/* BPL 0x2A */ +void HC11OP(bpl)() +{ + INT8 rel = FETCH(); + if ((m_ccr & CC_N) == 0) /* Branch if N flag clear */ + { + SET_PC(m_ppc + rel + 2); + } + CYCLES(3); +} + + +/* BRA 0x20 */ +void HC11OP(bra)() +{ + INT8 rel = FETCH(); + SET_PC(m_ppc + rel + 2); + CYCLES(3); +} + +/* BRCLR DIR 0x13 */ +void HC11OP(brclr_dir)() +{ + UINT8 d = FETCH(); + UINT8 mask = FETCH(); + INT8 rel = FETCH(); + UINT8 i = READ8(d); + + if ((i & mask) == 0) + { + SET_PC(m_ppc + rel + 4); + } + + CYCLES(6); +} + + +/* BRCLR INDX 0x1F */ +void HC11OP(brclr_indx)() +{ + UINT8 offset = FETCH(); + UINT8 mask = FETCH(); + INT8 rel = FETCH(); + UINT8 i = READ8(m_ix + offset); + + if ((i & mask) == 0) + { + SET_PC(m_ppc + rel + 4); + } + + CYCLES(7); +} + +/* BRSET DIR 0x12 */ +void HC11OP(brset_dir)() +{ + UINT8 d = FETCH(); + UINT8 mask = FETCH(); + INT8 rel = FETCH(); + UINT8 i = READ8(d); + + if(i & mask) + { + SET_PC(m_ppc + rel + 4); + } + + CYCLES(6); +} + + +/* BRSET INDX 0x1E */ +void HC11OP(brset_indx)() +{ + UINT8 offset = FETCH(); + UINT8 mask = FETCH(); + INT8 rel = FETCH(); + UINT8 i = READ8(m_ix + offset); + + if ((~i & mask) == 0) + { + SET_PC(m_ppc + rel + 4); + } + + CYCLES(7); +} + + +/* BRN 0x21 */ +void HC11OP(brn)() +{ + /* with this opcode the branch condition is always false. */ + SET_PC(m_ppc + 2); + CYCLES(3); +} + +/* BSET DIR 0x14 */ +void HC11OP(bset_dir)() +{ + UINT8 d = FETCH(); + UINT8 mask = FETCH(); + UINT8 r = READ8(d) | mask; + WRITE8(d, r); + CLEAR_NZV(); + SET_N8(r); + SET_Z8(r); + CYCLES(6); +} + +/* BSET INDX 0x1c */ +void HC11OP(bset_indx)() +{ + UINT8 offset = FETCH(); + UINT8 mask = FETCH(); + UINT8 r = READ8(m_ix + offset) | mask; + WRITE8(m_ix + offset, r); + CLEAR_NZV(); + SET_N8(r); + SET_Z8(r); + + CYCLES(7); +} + +/* BSR 0x8D */ +void HC11OP(bsr)() +{ + INT8 rel = FETCH(); + UINT16 rt_adr = m_pc; + PUSH16(rt_adr); + SET_PC(m_ppc + rel + 2); + CYCLES(6); +} + +/* BVC 0x28 */ +void HC11OP(bvc)() +{ + INT8 rel = FETCH(); + if ((m_ccr & CC_V) == 0) /* Branch if V flag clear */ + { + SET_PC(m_ppc + rel + 2); + } + CYCLES(3); +} + +/* BVS 0x29 */ +void HC11OP(bvs)() +{ + INT8 rel = FETCH(); + if (m_ccr & CC_V) /* Branch if V flag set */ + { + SET_PC(m_ppc + rel + 2); + } + CYCLES(3); +} + +/* CBA 0x11 */ +void HC11OP(cba)() +{ + UINT16 r = REG_A - REG_B; + CLEAR_NZVC(); + SET_N8(r); + SET_Z8(r); + SET_V_SUB8(r, REG_B, REG_A); + SET_C8(r); + CYCLES(2); +} + +/* CLC 0x0C */ +void HC11OP(clc)() +{ + m_ccr &= ~CC_C; + CYCLES(2); +} + + +/* CLI 0x0E */ +void HC11OP(cli)() +{ + m_ccr &= ~CC_I; + CYCLES(2); +} + + +/* CLRA 0x4F */ +void HC11OP(clra)() +{ + REG_A = 0; + CLEAR_NZVC(); + SET_ZFLAG(); + CYCLES(2); +} + +/* CLRB 0x5F */ +void HC11OP(clrb)() +{ + REG_B = 0; + CLEAR_NZVC(); + SET_ZFLAG(); + CYCLES(2); +} + +/* CLR EXT 0x7F */ +void HC11OP(clr_ext)() +{ + UINT16 adr = FETCH16(); + WRITE8(adr, 0); + CLEAR_NZVC(); + SET_ZFLAG(); + CYCLES(6); +} + +/* CLR IND, X 0x6F */ +void HC11OP(clr_indx)() +{ + UINT8 offset = FETCH(); + WRITE8(m_ix + offset, 0); + CLEAR_NZVC(); + SET_ZFLAG(); + CYCLES(6); +} + +/* CLR IND, Y 0x18, 0x6F */ +void HC11OP(clr_indy)() +{ + UINT8 offset = FETCH(); + WRITE8(m_iy + offset, 0); + CLEAR_NZVC(); + SET_ZFLAG(); + CYCLES(7); +} + + +/* CLV 0x0A */ +void HC11OP(clv)() +{ + m_ccr &= ~CC_V; + CYCLES(2); +} + + +/* CMPA IMM 0x81 */ +void HC11OP(cmpa_imm)() +{ + UINT8 i = FETCH(); + UINT16 r = REG_A - i; + CLEAR_NZVC(); + SET_N8(r); + SET_Z8(r); + SET_V_SUB8(r, i, REG_A); + SET_C8(r); + CYCLES(2); +} + +/* CMPA DIR 0x91 */ +void HC11OP(cmpa_dir)() +{ + UINT8 d = FETCH(); + UINT8 i = READ8(d); + UINT16 r = REG_A - i; + CLEAR_NZVC(); + SET_N8(r); + SET_Z8(r); + SET_V_SUB8(r, i, REG_A); + SET_C8(r); + CYCLES(3); +} + +/* CMPA EXT 0xB1 */ +void HC11OP(cmpa_ext)() +{ + UINT16 adr = FETCH16(); + UINT8 i = READ8(adr); + UINT16 r = REG_A - i; + CLEAR_NZVC(); + SET_N8(r); + SET_Z8(r); + SET_V_SUB8(r, i, REG_A); + SET_C8(r); + CYCLES(4); +} + +/* CMPA IND, X 0xA1 */ +void HC11OP(cmpa_indx)() +{ + UINT8 offset = FETCH(); + UINT8 i = READ8(m_ix + offset); + UINT16 r = REG_A - i; + CLEAR_NZVC(); + SET_N8(r); + SET_Z8(r); + SET_V_SUB8(r, i, REG_A); + SET_C8(r); + CYCLES(4); +} + +/* CMPA IND, Y 0x18, 0xA1 */ +void HC11OP(cmpa_indy)() +{ + UINT8 offset = FETCH(); + UINT8 i = READ8(m_iy + offset); + UINT16 r = REG_A - i; + CLEAR_NZVC(); + SET_N8(r); + SET_Z8(r); + SET_V_SUB8(r, i, REG_A); + SET_C8(r); + CYCLES(5); +} + + +/* CMPB IMM 0xC1 */ +void HC11OP(cmpb_imm)() +{ + UINT8 i = FETCH(); + UINT16 r = REG_B - i; + CLEAR_NZVC(); + SET_N8(r); + SET_Z8(r); + SET_V_SUB8(r, i, REG_B); + SET_C8(r); + CYCLES(2); +} + +/* CMPB DIR 0xD1 */ +void HC11OP(cmpb_dir)() +{ + UINT8 d = FETCH(); + UINT8 i = READ8(d); + UINT16 r = REG_B - i; + CLEAR_NZVC(); + SET_N8(r); + SET_Z8(r); + SET_V_SUB8(r, i, REG_B); + SET_C8(r); + CYCLES(3); +} + +/* CMPB EXT 0xF1 */ +void HC11OP(cmpb_ext)() +{ + UINT16 adr = FETCH16(); + UINT8 i = READ8(adr); + UINT16 r = REG_B - i; + CLEAR_NZVC(); + SET_N8(r); + SET_Z8(r); + SET_V_SUB8(r, i, REG_B); + SET_C8(r); + CYCLES(4); +} + +/* CMPB IND, X 0xE1 */ +void HC11OP(cmpb_indx)() +{ + UINT8 offset = FETCH(); + UINT8 i = READ8(m_ix + offset); + UINT16 r = REG_B - i; + CLEAR_NZVC(); + SET_N8(r); + SET_Z8(r); + SET_V_SUB8(r, i, REG_B); + SET_C8(r); + CYCLES(4); +} + +/* CMPB IND, Y 0x18, 0xE1 */ +void HC11OP(cmpb_indy)() +{ + UINT8 offset = FETCH(); + UINT8 i = READ8(m_iy + offset); + UINT16 r = REG_B - i; + CLEAR_NZVC(); + SET_N8(r); + SET_Z8(r); + SET_V_SUB8(r, i, REG_B); + SET_C8(r); + CYCLES(5); +} + + +/* COMA , 0x43 */ +void HC11OP(coma)() +{ + UINT16 r = 0xff - REG_A; + CLEAR_NZVC(); + SET_N8(r); + SET_Z8(r); + m_ccr |= CC_C; //always set for M6800 compatibility + REG_A = r; + CYCLES(2); +} + + +/* COMB , 0x53 */ +void HC11OP(comb)() +{ + UINT16 r = 0xff - REG_B; + CLEAR_NZVC(); + SET_N8(r); + SET_Z8(r); + m_ccr |= CC_C; //always set for M6800 compatibility + REG_B = r; + CYCLES(2); +} + + +/* CPD IMM 0x1A, 0x83 */ +void HC11OP(cpd_imm)() +{ + UINT16 i = FETCH16(); + UINT32 r = REG_D - i; + CLEAR_NZVC(); + SET_N16(r); + SET_Z16(r); + SET_V_SUB16(r, i, REG_D); + SET_C16(r); + CYCLES(5); +} + +/* CPD DIR 0x1A, 0x93 */ +void HC11OP(cpd_dir)() +{ + UINT8 d = FETCH(); + UINT16 i = READ16(d); + UINT32 r = REG_D - i; + CLEAR_NZVC(); + SET_N16(r); + SET_Z16(r); + SET_V_SUB16(r, i, REG_D); + SET_C16(r); + CYCLES(6); +} + +/* CPD EXT 0x1A, 0xB3 */ +void HC11OP(cpd_ext)() +{ + UINT16 adr = FETCH16(); + UINT16 i = READ16(adr); + UINT32 r = REG_D - i; + CLEAR_NZVC(); + SET_N16(r); + SET_Z16(r); + SET_V_SUB16(r, i, REG_D); + SET_C16(r); + CYCLES(7); +} + +/* CPD IND, X 0x1A, 0xA3 */ +void HC11OP(cpd_indx)() +{ + UINT8 offset = FETCH(); + UINT16 i = READ16(m_ix + offset); + UINT32 r = REG_D - i; + CLEAR_NZVC(); + SET_N16(r); + SET_Z16(r); + SET_V_SUB16(r, i, REG_D); + SET_C16(r); + CYCLES(7); +} + +/* CPD IND, Y 0xCD, 0xA3 */ +void HC11OP(cpd_indy)() +{ + UINT8 offset = FETCH(); + UINT16 i = READ16(m_iy + offset); + UINT32 r = REG_D - i; + CLEAR_NZVC(); + SET_N16(r); + SET_Z16(r); + SET_V_SUB16(r, i, REG_D); + SET_C16(r); + CYCLES(7); +} + + +/* CPX IMM 0x8C */ +void HC11OP(cpx_imm)() +{ + UINT16 i = FETCH16(); + UINT32 r = m_ix - i; + CLEAR_NZVC(); + SET_N16(r); + SET_Z16(r); + SET_V_SUB16(r, i, m_ix); + SET_C16(r); + CYCLES(4); +} + +/* CPX DIR 0x9C */ +void HC11OP(cpx_dir)() +{ + UINT8 d = FETCH(); + UINT16 i = READ16(d); + UINT32 r = m_ix - i; + CLEAR_NZVC(); + SET_N16(r); + SET_Z16(r); + SET_V_SUB16(r, i, m_ix); + SET_C16(r); + CYCLES(5); +} + +/* CPX EXT 0xBC */ +void HC11OP(cpx_ext)() +{ + UINT16 adr = FETCH16(); + UINT16 i = READ16(adr); + UINT32 r = m_ix - i; + CLEAR_NZVC(); + SET_N16(r); + SET_Z16(r); + SET_V_SUB16(r, i, m_ix); + SET_C16(r); + CYCLES(6); +} + +/* CPX IND, X 0xAC */ +void HC11OP(cpx_indx)() +{ + UINT8 offset = FETCH(); + UINT16 i = READ16(m_ix + offset); + UINT32 r = m_ix - i; + CLEAR_NZVC(); + SET_N16(r); + SET_Z16(r); + SET_V_SUB16(r, i, m_ix); + SET_C16(r); + CYCLES(6); +} + +/* CPX IND, Y 0xCD, 0xAC */ +void HC11OP(cpx_indy)() +{ + UINT8 offset = FETCH(); + UINT16 i = READ16(m_iy + offset); + UINT32 r = m_ix - i; + CLEAR_NZVC(); + SET_N16(r); + SET_Z16(r); + SET_V_SUB16(r, i, m_ix); + SET_C16(r); + CYCLES(7); +} + +/* CPY IMM 0x18, 0x8C */ +void HC11OP(cpy_imm)() +{ + UINT16 i = FETCH16(); + UINT32 r = m_iy - i; + CLEAR_NZVC(); + SET_N16(r); + SET_Z16(r); + SET_V_SUB16(r, i, m_iy); + SET_C16(r); + CYCLES(5); +} + +/* CPY DIR 0x18 0x9C */ +void HC11OP(cpy_dir)() +{ + UINT8 d = FETCH(); + UINT16 i = READ16(d); + UINT32 r = m_iy - i; + CLEAR_NZVC(); + SET_N16(r); + SET_Z16(r); + SET_V_SUB16(r, i, m_iy); + SET_C16(r); + CYCLES(6); +} + +/* CPY EXT 0x18 0xBC */ +void HC11OP(cpy_ext)() +{ + UINT16 adr = FETCH16(); + UINT16 i = READ16(adr); + UINT32 r = m_iy - i; + CLEAR_NZVC(); + SET_N16(r); + SET_Z16(r); + SET_V_SUB16(r, i, m_iy); + SET_C16(r); + CYCLES(7); +} + +/* CPY IND, X 0x1A 0xAC */ +void HC11OP(cpy_indx)() +{ + UINT8 offset = FETCH(); + UINT16 i = READ16(m_ix + offset); + UINT32 r = m_iy - i; + CLEAR_NZVC(); + SET_N16(r); + SET_Z16(r); + SET_V_SUB16(r, i, m_iy); + SET_C16(r); + CYCLES(7); +} + +/* CPY IND, Y 0x18 0xAC */ +void HC11OP(cpy_indy)() +{ + UINT8 offset = FETCH(); + UINT16 i = READ16(m_iy + offset); + UINT32 r = m_iy - i; + CLEAR_NZVC(); + SET_N16(r); + SET_Z16(r); + SET_V_SUB16(r, i, m_iy); + SET_C16(r); + CYCLES(7); +} + +/* DECA 0x4A */ +void HC11OP(deca)() +{ + CLEAR_NZV(); + if (REG_A == 0x80) + SET_VFLAG(); + REG_A--; + SET_N8(REG_A); + SET_Z8(REG_A); + CYCLES(2); +} + +/* DECB 0x5A */ +void HC11OP(decb)() +{ + CLEAR_NZV(); + if (REG_B == 0x80) + SET_VFLAG(); + REG_B--; + SET_N8(REG_B); + SET_Z8(REG_B); + CYCLES(2); +} + +/* DEC EXT 0x7A */ +void HC11OP(dec_ext)() +{ + UINT16 adr = FETCH16(); + UINT8 i = READ8(adr); + + CLEAR_NZV(); + if (i == 0x80) + SET_VFLAG(); + i--; + SET_N8(i); + SET_Z8(i); + WRITE8(adr, i); + CYCLES(6); +} + +/* DEC INDX 0x6A */ +void HC11OP(dec_indx)() +{ + UINT8 offset = FETCH(); + UINT8 i = READ8(m_ix + offset); + + CLEAR_NZV(); + if (i == 0x80) + SET_VFLAG(); + i--; + SET_N8(i); + SET_Z8(i); + WRITE8(m_ix + offset, i); + CYCLES(6); +} + +/* DEC INDY 0x18 0x6A */ +void HC11OP(dec_indy)() +{ + UINT8 offset = FETCH(); + UINT8 i = READ8(m_iy + offset); + + CLEAR_NZV(); + if (i == 0x80) + SET_VFLAG(); + i--; + SET_N8(i); + SET_Z8(i); + WRITE8(m_iy + offset, i); + CYCLES(7); +} + +/* DEX 0x09 */ +void HC11OP(dex)() +{ + CLEAR_Z(); + m_ix--; + SET_Z16(m_ix); + CYCLES(3); +} + + +/* DEY 0x18, 0x09 */ +void HC11OP(dey)() +{ + CLEAR_Z(); + m_iy--; + SET_Z16(m_iy); + CYCLES(4); +} + + +/* EORA IMM 0x88 */ +void HC11OP(eora_imm)() +{ + UINT8 i = FETCH(); + CLEAR_NZV(); + REG_A ^= i; + SET_N8(REG_A); + SET_Z8(REG_A); + CYCLES(2); +} + +/* EORA DIR 0x98 */ +void HC11OP(eora_dir)() +{ + UINT8 d = FETCH(); + UINT8 i = READ8(d); + CLEAR_NZV(); + REG_A ^= i; + SET_N8(REG_A); + SET_Z8(REG_A); + CYCLES(3); +} + +/* EORA EXT 0xB8 */ +void HC11OP(eora_ext)() +{ + UINT16 adr = FETCH16(); + UINT8 i = READ8(adr); + CLEAR_NZV(); + REG_A ^= i; + SET_N8(REG_A); + SET_Z8(REG_A); + CYCLES(4); +} + +/* EORA IND, X 0xA8 */ +void HC11OP(eora_indx)() +{ + UINT8 offset = FETCH(); + UINT8 i = READ8(m_ix + offset); + CLEAR_NZV(); + REG_A ^= i; + SET_N8(REG_A); + SET_Z8(REG_A); + CYCLES(4); +} + +/* EORA IND, Y 0x18, 0xA8 */ +void HC11OP(eora_indy)() +{ + UINT8 offset = FETCH(); + UINT8 i = READ8(m_iy + offset); + CLEAR_NZV(); + REG_A ^= i; + SET_N8(REG_A); + SET_Z8(REG_A); + CYCLES(5); +} + + +/* EORB IMM 0xC8 */ +void HC11OP(eorb_imm)() +{ + UINT8 i = FETCH(); + CLEAR_NZV(); + REG_B ^= i; + SET_N8(REG_B); + SET_Z8(REG_B); + CYCLES(2); +} + +/* EORB DIR 0xD8 */ +void HC11OP(eorb_dir)() +{ + UINT8 d = FETCH(); + UINT8 i = READ8(d); + CLEAR_NZV(); + REG_B ^= i; + SET_N8(REG_B); + SET_Z8(REG_B); + CYCLES(3); +} + +/* EORB EXT 0xF8 */ +void HC11OP(eorb_ext)() +{ + UINT16 adr = FETCH16(); + UINT8 i = READ8(adr); + CLEAR_NZV(); + REG_B ^= i; + SET_N8(REG_B); + SET_Z8(REG_B); + CYCLES(4); +} + +/* EORB IND, X 0xE8 */ +void HC11OP(eorb_indx)() +{ + UINT8 offset = FETCH(); + UINT8 i = READ8(m_ix + offset); + CLEAR_NZV(); + REG_B ^= i; + SET_N8(REG_B); + SET_Z8(REG_B); + CYCLES(4); +} + +/* EORB IND, Y 0x18, 0xE8 */ +void HC11OP(eorb_indy)() +{ + UINT8 offset = FETCH(); + UINT8 i = READ8(m_iy + offset); + CLEAR_NZV(); + REG_B ^= i; + SET_N8(REG_B); + SET_Z8(REG_B); + CYCLES(5); +} + +/* IDIV 0x02 */ +void HC11OP(idiv)() +{ + UINT16 numerator = REG_D; + UINT16 denominator = m_ix; + UINT16 remainder; + UINT16 result; + + CLEAR_ZVC(); + if(denominator == 0) // divide by zero behaviour + { + remainder = 0xffff; // TODO: undefined behaviour according to the docs + result = 0xffff; + logerror("HC11: divide by zero at PC=%04x\n",m_pc-1); + m_ccr |= CC_C; + } + else + { + remainder = numerator % denominator; + result = numerator / denominator; + } + m_ix = result; + REG_D = remainder; + SET_Z16(result); + + CYCLES(41); +} + +/* INCA 0x4C */ +void HC11OP(inca)() +{ + CLEAR_NZV(); + if (REG_A == 0x7f) + SET_VFLAG(); + REG_A++; + SET_N8(REG_A); + SET_Z8(REG_A); + CYCLES(2); +} + +/* INCB 0x5C */ +void HC11OP(incb)() +{ + CLEAR_NZV(); + if (REG_B == 0x7f) + SET_VFLAG(); + REG_B++; + SET_N8(REG_B); + SET_Z8(REG_B); + CYCLES(2); +} + +/* INC EXT 0x7C */ +void HC11OP(inc_ext)() +{ + UINT16 adr = FETCH16(); + UINT8 i = READ8(adr); + + CLEAR_NZV(); + if (i == 0x7f) + SET_VFLAG(); + i++; + SET_N8(i); + SET_Z8(i); + WRITE8(adr, i); + CYCLES(6); +} + +/* INC INDX 0x6C */ +void HC11OP(inc_indx)() +{ + UINT8 offset = FETCH(); + UINT8 i = READ8(m_ix + offset); + + CLEAR_NZV(); + if (i == 0x7f) + SET_VFLAG(); + i++; + SET_N8(i); + SET_Z8(i); + WRITE8(m_ix + offset, i); + CYCLES(6); +} + + +/* INC INDY 0x18 0x6C */ +void HC11OP(inc_indy)() +{ + UINT8 offset = FETCH(); + UINT8 i = READ8(m_iy + offset); + + CLEAR_NZV(); + if (i == 0x7f) + SET_VFLAG(); + i++; + SET_N8(i); + SET_Z8(i); + WRITE8(m_iy + offset, i); + CYCLES(7); +} + + +/* INX 0x08 */ +void HC11OP(inx)() +{ + CLEAR_Z(); + m_ix++; + SET_Z16(m_ix); + CYCLES(3); +} + +/* INY 0x18, 0x08 */ +void HC11OP(iny)() +{ + CLEAR_Z(); + m_iy++; + SET_Z16(m_iy); + CYCLES(4); +} + +/* JMP IND X 0x6E */ +void HC11OP(jmp_indx)() +{ + UINT16 adr = FETCH(); + SET_PC(m_ix + adr); + CYCLES(3); +} + +/* JMP IND Y 0x18 0x6E */ +void HC11OP(jmp_indy)() +{ + UINT16 adr = FETCH(); + SET_PC(m_iy + adr); + CYCLES(4); +} + +/* JMP EXT 0x7E */ +void HC11OP(jmp_ext)() +{ + UINT16 adr = FETCH16(); + SET_PC(adr); + CYCLES(3); +} + + +/* JSR DIR 0x9D */ +void HC11OP(jsr_dir)() +{ + UINT8 i = FETCH(); + UINT16 rt_adr = m_pc; + PUSH16(rt_adr); + SET_PC(i); + CYCLES(5); +} + +/* JSR EXT 0xBD */ +void HC11OP(jsr_ext)() +{ + UINT16 adr = FETCH16(); + UINT16 rt_adr = m_pc; + PUSH16(rt_adr); + SET_PC(adr); + CYCLES(6); +} + +/* JSR IND, X 0xAD */ +void HC11OP(jsr_indx)() +{ + UINT8 offset = FETCH(); + UINT16 rt_adr = m_pc; + PUSH16(rt_adr); + SET_PC(m_ix + offset); + CYCLES(6); +} + +/* JSR IND, Y 0x18, 0xAD */ +void HC11OP(jsr_indy)() +{ + UINT8 offset = FETCH(); + UINT16 rt_adr = m_pc; + PUSH16(rt_adr); + SET_PC(m_iy + offset); + CYCLES(6); +} + + +/* LDAA IMM 0x86 */ +void HC11OP(ldaa_imm)() +{ + CLEAR_NZV(); + REG_A = FETCH(); + SET_N8(REG_A); + SET_Z8(REG_A); + CYCLES(2); +} + +/* LDAA DIR 0x96 */ +void HC11OP(ldaa_dir)() +{ + UINT8 d = FETCH(); + CLEAR_NZV(); + REG_A = READ8(d); + SET_N8(REG_A); + SET_Z8(REG_A); + CYCLES(3); +} + +/* LDAA EXT 0xB6 */ +void HC11OP(ldaa_ext)() +{ + UINT16 adr = FETCH16(); + CLEAR_NZV(); + REG_A = READ8(adr); + SET_N8(REG_A); + SET_Z8(REG_A); + CYCLES(4); +} + +/* LDAA IND, X 0xA6 */ +void HC11OP(ldaa_indx)() +{ + UINT8 offset = FETCH(); + CLEAR_NZV(); + REG_A = READ8(m_ix + offset); + SET_N8(REG_A); + SET_Z8(REG_A); + CYCLES(4); +} + +/* LDAA IND, Y 0x18, 0xA6 */ +void HC11OP(ldaa_indy)() +{ + UINT8 offset = FETCH(); + CLEAR_NZV(); + REG_A = READ8(m_iy + offset); + SET_N8(REG_A); + SET_Z8(REG_A); + CYCLES(5); +} + +/* LDAB IMM 0xC6 */ +void HC11OP(ldab_imm)() +{ + CLEAR_NZV(); + REG_B = FETCH(); + SET_N8(REG_B); + SET_Z8(REG_B); + CYCLES(2); +} + +/* LDAB DIR 0xD6 */ +void HC11OP(ldab_dir)() +{ + UINT8 d = FETCH(); + CLEAR_NZV(); + REG_B = READ8(d); + SET_N8(REG_B); + SET_Z8(REG_B); + CYCLES(3); +} + +/* LDAB EXT 0xF6 */ +void HC11OP(ldab_ext)() +{ + UINT16 adr = FETCH16(); + CLEAR_NZV(); + REG_B = READ8(adr); + SET_N8(REG_B); + SET_Z8(REG_B); + CYCLES(4); +} + +/* LDAB IND, X 0xE6 */ +void HC11OP(ldab_indx)() +{ + UINT8 offset = FETCH(); + CLEAR_NZV(); + REG_B = READ8(m_ix + offset); + SET_N8(REG_B); + SET_Z8(REG_B); + CYCLES(4); +} + +/* LDAB IND, Y 0x18, 0xE6 */ +void HC11OP(ldab_indy)() +{ + UINT8 offset = FETCH(); + CLEAR_NZV(); + REG_B = READ8(m_iy + offset); + SET_N8(REG_B); + SET_Z8(REG_B); + CYCLES(5); +} + + +/* LDD IMM 0xCC */ +void HC11OP(ldd_imm)() +{ + CLEAR_NZV(); + REG_D = FETCH16(); + SET_N16(REG_D); + SET_Z16(REG_D); + CYCLES(3); +} + +/* LDD DIR 0xDC */ +void HC11OP(ldd_dir)() +{ + UINT8 d = FETCH(); + CLEAR_NZV(); + REG_D = READ16(d); + SET_N16(REG_D); + SET_Z16(REG_D); + CYCLES(4); +} + +/* LDD EXT 0xFC */ +void HC11OP(ldd_ext)() +{ + UINT16 adr = FETCH16(); + CLEAR_NZV(); + REG_D = READ16(adr); + SET_N16(REG_D); + SET_Z16(REG_D); + CYCLES(5); +} + +/* LDD IND, X 0xEC */ +void HC11OP(ldd_indx)() +{ + UINT8 offset = FETCH(); + CLEAR_NZV(); + REG_D = READ16(m_ix + offset); + SET_N16(REG_D); + SET_Z16(REG_D); + CYCLES(5); +} + +/* LDD IND, Y 0x18, 0xEC */ +void HC11OP(ldd_indy)() +{ + UINT8 offset = FETCH(); + CLEAR_NZV(); + REG_D = READ16(m_iy + offset); + SET_N16(REG_D); + SET_Z16(REG_D); + CYCLES(6); +} + + +/* LDS IMM 0x8E */ +void HC11OP(lds_imm)() +{ + CLEAR_NZV(); + m_sp = FETCH16(); + SET_N16(m_sp); + SET_Z16(m_sp); + CYCLES(3); +} + +/* LDS DIR 0x9E */ +void HC11OP(lds_dir)() +{ + UINT8 i = FETCH(); + CLEAR_NZV(); + m_sp = READ16(i); + SET_N16(m_sp); + SET_Z16(m_sp); + CYCLES(4); +} + +/* LDS EXT 0xBE */ +void HC11OP(lds_ext)() +{ + UINT16 adr = FETCH16(); + CLEAR_NZV(); + m_sp = READ16(adr); + SET_N16(m_sp); + SET_Z16(m_sp); + CYCLES(5); +} + +/* LDS IND, X 0xAE */ +void HC11OP(lds_indx)() +{ + UINT8 offset = FETCH(); + CLEAR_NZV(); + m_sp = READ16(m_ix + offset); + SET_N16(m_sp); + SET_Z16(m_sp); + CYCLES(5); +} + +/* LDS IND, Y 0x18, 0xAE */ +void HC11OP(lds_indy)() +{ + UINT8 offset = FETCH(); + CLEAR_NZV(); + m_sp = READ16(m_iy + offset); + SET_N16(m_sp); + SET_Z16(m_sp); + CYCLES(6); +} + + +/* LDX IMM 0xCE */ +void HC11OP(ldx_imm)() +{ + CLEAR_NZV(); + m_ix = FETCH16(); + SET_N16(m_ix); + SET_Z16(m_ix); + CYCLES(3); +} + +/* LDX DIR 0xDE */ +void HC11OP(ldx_dir)() +{ + UINT8 d = FETCH(); + CLEAR_NZV(); + m_ix = READ16(d); + SET_N16(m_ix); + SET_Z16(m_ix); + CYCLES(4); +} + +/* LDX EXT 0xFE */ +void HC11OP(ldx_ext)() +{ + UINT16 adr = FETCH16(); + CLEAR_NZV(); + m_ix = READ16(adr); + SET_N16(m_ix); + SET_Z16(m_ix); + CYCLES(5); +} + +/* LDX IND, X 0xEE */ +void HC11OP(ldx_indx)() +{ + UINT8 offset = FETCH(); + CLEAR_NZV(); + m_ix = READ16(m_ix + offset); + SET_N16(m_ix); + SET_Z16(m_ix); + CYCLES(5); +} + +/* LDX IND, Y 0xCD, 0xEE */ +void HC11OP(ldx_indy)() +{ + UINT8 offset = FETCH(); + CLEAR_NZV(); + m_ix = READ16(m_iy + offset); + SET_N16(m_ix); + SET_Z16(m_ix); + CYCLES(6); +} + + +/* LDY IMM 0x18, 0xCE */ +void HC11OP(ldy_imm)() +{ + CLEAR_NZV(); + m_iy = FETCH16(); + SET_N16(m_iy); + SET_Z16(m_iy); + CYCLES(4); +} + +/* LDY DIR 0x18, 0xDE */ +void HC11OP(ldy_dir)() +{ + UINT8 d = FETCH(); + CLEAR_NZV(); + m_iy = READ16(d); + SET_N16(m_iy); + SET_Z16(m_iy); + CYCLES(5); +} + +/* LDY EXT 0x18, 0xFE */ +void HC11OP(ldy_ext)() +{ + UINT16 adr = FETCH16(); + CLEAR_NZV(); + m_iy = READ16(adr); + SET_N16(m_iy); + SET_Z16(m_iy); + CYCLES(6); +} + +/* LDY IND, X 0x1A, 0xEE */ +void HC11OP(ldy_indx)() +{ + UINT8 offset = FETCH(); + CLEAR_NZV(); + m_iy = READ16(m_ix + offset); + SET_N16(m_iy); + SET_Z16(m_iy); + CYCLES(6); +} + +/* LDY IND, Y 0x18, 0xEE */ +void HC11OP(ldy_indy)() +{ + UINT8 offset = FETCH(); + CLEAR_NZV(); + m_iy = READ16(m_iy + offset); + SET_N16(m_iy); + SET_Z16(m_iy); + CYCLES(6); +} + +/* LSLD 0x05 */ +void HC11OP(lsld)() +{ + UINT32 r = REG_D << 1; + CLEAR_NZVC(); + SET_C16(r); + REG_D = (UINT16)(r); + SET_N16(REG_D); + SET_Z16(REG_D); + + if (((m_ccr & CC_N) && (m_ccr & CC_C) == 0) || + ((m_ccr & CC_N) == 0 && (m_ccr & CC_C))) + { + m_ccr |= CC_V; + } + + CYCLES(3); +} + +/* LSRA 0x44 */ +void HC11OP(lsra)() +{ + UINT16 r = REG_A >> 1; + CLEAR_NZVC(); + m_ccr |= (REG_A & 1) ? CC_C : 0; + REG_A = (UINT8)(r); + m_ccr |= ((m_ccr & CC_C)) ? CC_V : 0; + SET_Z8(REG_A); + + CYCLES(2); +} + +/* LSRB 0x54 */ +void HC11OP(lsrb)() +{ + UINT16 r = REG_B >> 1; + CLEAR_NZVC(); + m_ccr |= (REG_B & 1) ? CC_C : 0; + REG_B = (UINT8)(r); + m_ccr |= ((m_ccr & CC_C)) ? CC_V : 0; + SET_Z8(REG_B); + + CYCLES(2); +} + +/* LSRD 0x04 */ +void HC11OP(lsrd)() +{ + UINT32 r = REG_D >> 1; + CLEAR_NZVC(); + m_ccr |= (REG_D & 1) ? CC_C : 0; + REG_D = (UINT16)(r); + m_ccr |= ((m_ccr & CC_C)) ? CC_V : 0; + + SET_N16(REG_D); + SET_Z16(REG_D); + + CYCLES(3); +} + +/* MUL 0x3d */ +void HC11OP(mul)() +{ + REG_D = REG_A * REG_B; + CLEAR_C(); + m_ccr |= (REG_B & 0x80) ? CC_C : 0; + CYCLES(10); +} + +/* NEGA 0x40 */ +void HC11OP(nega)() +{ + REG_A = 0x00 - REG_A; + CLEAR_NZVC(); + SET_N8(REG_A); + SET_Z8(REG_A); + m_ccr |= (REG_A == 0x80) ? CC_V : 0; + m_ccr |= (REG_A != 0x00) ? CC_C : 0; + CYCLES(2); +} + +/* NEGB 0x50 */ +void HC11OP(negb)() +{ + REG_B = 0x00 - REG_B; + CLEAR_NZVC(); + SET_N8(REG_B); + SET_Z8(REG_B); + m_ccr |= (REG_B == 0x80) ? CC_V : 0; + m_ccr |= (REG_B != 0x00) ? CC_C : 0; + CYCLES(2); +} + + +/* NEG EXT 0x70 */ +void HC11OP(neg_ext)() +{ + UINT16 adr = FETCH16(); + UINT8 i = 0x00 - READ8(adr); + CLEAR_NZVC(); + SET_N8(i); + SET_Z8(i); + m_ccr |= (i == 0x80) ? CC_V : 0; + m_ccr |= (i != 0x00) ? CC_C : 0; + WRITE8(adr, i); + CYCLES(6); +} + + +/* NEG INDX 0x60 */ +void HC11OP(neg_indx)() +{ + UINT16 offset = FETCH(); + UINT8 i = 0x00 - READ8(m_ix + offset); + CLEAR_NZVC(); + SET_N8(i); + SET_Z8(i); + m_ccr |= (i == 0x80) ? CC_V : 0; + m_ccr |= (i != 0x00) ? CC_C : 0; + WRITE8(m_ix + offset, i); + CYCLES(6); +} + + +/* NEG INDY 0x18 0x60 */ +void HC11OP(neg_indy)() +{ + UINT16 offset = FETCH(); + UINT8 i = 0x00 - READ8(m_iy + offset); + CLEAR_NZVC(); + SET_N8(i); + SET_Z8(i); + m_ccr |= (i == 0x80) ? CC_V : 0; + m_ccr |= (i != 0x00) ? CC_C : 0; + WRITE8(m_iy + offset, i); + CYCLES(7); +} + + +/* NOP 0x01 */ +void HC11OP(nop)() +{ + CYCLES(2); +} + +/* PSHA 0x36 */ +void HC11OP(psha)() +{ + PUSH8(REG_A); + CYCLES(3); +} + +/* ORAA IMM 0x8A */ +void HC11OP(oraa_imm)() +{ + UINT8 i = FETCH(); + CLEAR_NZV(); + REG_A |= i; + SET_N8(REG_A); + SET_Z8(REG_A); + CYCLES(2); +} + +/* ORAA DIR 0x9A */ +void HC11OP(oraa_dir)() +{ + UINT8 d = FETCH(); + UINT8 i = READ8(d); + CLEAR_NZV(); + REG_A |= i; + SET_N8(REG_A); + SET_Z8(REG_A); + CYCLES(3); +} + +/* ORAA EXT 0xBA */ +void HC11OP(oraa_ext)() +{ + UINT16 adr = FETCH16(); + UINT8 i = READ8(adr); + CLEAR_NZV(); + REG_A |= i; + SET_N8(REG_A); + SET_Z8(REG_A); + CYCLES(4); +} + +/* ORAA IND, X 0xAA */ +void HC11OP(oraa_indx)() +{ + UINT8 offset = FETCH(); + UINT8 i = READ8(m_ix + offset); + CLEAR_NZV(); + REG_A |= i; + SET_N8(REG_A); + SET_Z8(REG_A); + CYCLES(4); +} + +/* ORAA IND, Y 0x18, 0xAA */ +void HC11OP(oraa_indy)() +{ + UINT8 offset = FETCH(); + UINT8 i = READ8(m_iy + offset); + CLEAR_NZV(); + REG_A |= i; + SET_N8(REG_A); + SET_Z8(REG_A); + CYCLES(5); +} + + +/* ORAB IMM 0xCA */ +void HC11OP(orab_imm)() +{ + UINT8 i = FETCH(); + CLEAR_NZV(); + REG_B |= i; + SET_N8(REG_B); + SET_Z8(REG_B); + CYCLES(2); +} + +/* ORAB DIR 0xDA */ +void HC11OP(orab_dir)() +{ + UINT8 d = FETCH(); + UINT8 i = READ8(d); + CLEAR_NZV(); + REG_B |= i; + SET_N8(REG_B); + SET_Z8(REG_B); + CYCLES(3); +} + +/* ORAB EXT 0xFA */ +void HC11OP(orab_ext)() +{ + UINT16 adr = FETCH16(); + UINT8 i = READ8(adr); + CLEAR_NZV(); + REG_B |= i; + SET_N8(REG_B); + SET_Z8(REG_B); + CYCLES(4); +} + +/* ORAB IND, X 0xEA */ +void HC11OP(orab_indx)() +{ + UINT8 offset = FETCH(); + UINT8 i = READ8(m_ix + offset); + CLEAR_NZV(); + REG_B |= i; + SET_N8(REG_B); + SET_Z8(REG_B); + CYCLES(4); +} + +/* ORAB IND, Y 0x18, 0xEA */ +void HC11OP(orab_indy)() +{ + UINT8 offset = FETCH(); + UINT8 i = READ8(m_iy + offset); + CLEAR_NZV(); + REG_B |= i; + SET_N8(REG_B); + SET_Z8(REG_B); + CYCLES(5); +} + + +/* PSHB 0x37 */ +void HC11OP(pshb)() +{ + PUSH8(REG_B); + CYCLES(3); +} + + +/* PSHX 0x3C */ +void HC11OP(pshx)() +{ + PUSH16(m_ix); + CYCLES(4); +} + + +/* PSHY 0x18, 0x3C */ +void HC11OP(pshy)() +{ + PUSH16(m_iy); + CYCLES(5); +} + + +/* PULA 0x32 */ +void HC11OP(pula)() +{ + REG_A = POP8(); + CYCLES(4); +} + + +/* PULB 0x33 */ +void HC11OP(pulb)() +{ + REG_B = POP8(); + CYCLES(4); +} + + +/* PULX 0x38 */ +void HC11OP(pulx)() +{ + m_ix = POP16(); + CYCLES(5); +} + + +/* PULY 0x18, 0x38 */ +void HC11OP(puly)() +{ + m_iy = POP16(); + CYCLES(6); +} + +/* ROLA 0x49 */ +void HC11OP(rola)() +{ + UINT16 r = ((REG_A & 0x7f) << 1) | ((m_ccr & CC_C) ? 1 : 0); + CLEAR_NZVC(); + m_ccr |= (REG_A & 0x80) ? CC_C : 0; + REG_A = (UINT8)(r); + SET_N8(REG_A); + SET_Z8(REG_A); + + if (((m_ccr & CC_N) && (m_ccr & CC_C) == 0) || + ((m_ccr & CC_N) == 0 && (m_ccr & CC_C))) + { + m_ccr |= CC_V; + } + + CYCLES(2); +} + +/* ROLB 0x59 */ +void HC11OP(rolb)() +{ + UINT16 r = ((REG_B & 0x7f) << 1) | ((m_ccr & CC_C) ? 1 : 0); + CLEAR_NZVC(); + m_ccr |= (REG_B & 0x80) ? CC_C : 0; + REG_B = (UINT8)(r); + SET_N8(REG_B); + SET_Z8(REG_B); + + if (((m_ccr & CC_N) && (m_ccr & CC_C) == 0) || + ((m_ccr & CC_N) == 0 && (m_ccr & CC_C))) + { + m_ccr |= CC_V; + } + + CYCLES(2); +} + +/* ROL EXT 0x79 */ +void HC11OP(rol_ext)() +{ + UINT16 adr = FETCH16(); + UINT8 r = READ8(adr); + UINT8 c = (r & 0x80); + r = ((r & 0x7f) << 1) | ((m_ccr & CC_C) ? 1 : 0); + CLEAR_NZVC(); + m_ccr |= (c & 0x80) ? CC_C : 0; + SET_N8(r); + SET_Z8(r); + WRITE8(adr, r); + + if (((m_ccr & CC_N) && (m_ccr & CC_C) == 0) || + ((m_ccr & CC_N) == 0 && (m_ccr & CC_C))) + { + m_ccr |= CC_V; + } + + CYCLES(6); +} + +/* ROL INDX 0x69 */ +void HC11OP(rol_indx)() +{ + UINT8 offset = FETCH(); + UINT8 i = READ8(m_ix + offset); + UINT8 c = (i & 0x80); + i = ((i & 0x7f) << 1) | ((m_ccr & CC_C) ? 1 : 0); + CLEAR_NZVC(); + m_ccr |= (c & 0x80) ? CC_C : 0; + SET_N8(i); + SET_Z8(i); + WRITE8(m_ix + offset, i); + + if (((m_ccr & CC_N) && (m_ccr & CC_C) == 0) || + ((m_ccr & CC_N) == 0 && (m_ccr & CC_C))) + { + m_ccr |= CC_V; + } + + CYCLES(6); +} + +/* ROL INDY 0x18 0x69 */ +void HC11OP(rol_indy)() +{ + UINT8 offset = FETCH(); + UINT8 i = READ8(m_iy + offset); + UINT8 c = (i & 0x80); + i = ((i & 0x7f) << 1) | ((m_ccr & CC_C) ? 1 : 0); + CLEAR_NZVC(); + m_ccr |= (c & 0x80) ? CC_C : 0; + SET_N8(i); + SET_Z8(i); + WRITE8(m_iy + offset, i); + + if (((m_ccr & CC_N) && (m_ccr & CC_C) == 0) || + ((m_ccr & CC_N) == 0 && (m_ccr & CC_C))) + { + m_ccr |= CC_V; + } + + CYCLES(6); +} + + +/* RORA 0x46 */ +void HC11OP(rora)() +{ + UINT16 r = ((REG_A & 0xfe) >> 1) | ((m_ccr & CC_C) ? 0x80 : 0); + CLEAR_NZVC(); + m_ccr |= (REG_A & 1) ? CC_C : 0; + REG_A = (UINT8)(r); + SET_N8(REG_A); + SET_Z8(REG_A); + + if (((m_ccr & CC_N) && (m_ccr & CC_C) == 0) || + ((m_ccr & CC_N) == 0 && (m_ccr & CC_C))) + { + m_ccr |= CC_V; + } + + CYCLES(2); +} + +/* RORB 0x56 */ +void HC11OP(rorb)() +{ + UINT16 r = ((REG_B & 0xfe) >> 1) | ((m_ccr & CC_C) ? 0x80 : 0); + CLEAR_NZVC(); + m_ccr |= (REG_B & 1) ? CC_C : 0; + REG_B = (UINT8)(r); + SET_N8(REG_B); + SET_Z8(REG_B); + + if (((m_ccr & CC_N) && (m_ccr & CC_C) == 0) || + ((m_ccr & CC_N) == 0 && (m_ccr & CC_C))) + { + m_ccr |= CC_V; + } + + CYCLES(2); +} + +/* RTI 0x3B */ +void HC11OP(rti)() +{ + UINT16 rt_adr; + UINT8 x_flag = m_ccr & CC_X; + m_ccr = POP8(); + if(x_flag == 0 && m_ccr & CC_X) //X flag cannot do a 0->1 transition with this instruction. + m_ccr &= ~CC_X; + REG_B = POP8(); + REG_A = POP8(); + m_ix = POP16(); + m_iy = POP16(); + rt_adr = POP16(); + SET_PC(rt_adr); + CYCLES(12); +} + +/* RTS 0x39 */ +void HC11OP(rts)() +{ + UINT16 rt_adr = POP16(); + SET_PC(rt_adr); + CYCLES(5); +} + + +/* SBA 0x10 */ +void HC11OP(sba)() +{ + UINT16 r = REG_A - REG_B; + CLEAR_NZVC(); + SET_N8(r); + SET_Z8(r); + SET_V_SUB8(r, REG_B, REG_A); + SET_C8(r); + REG_A = (UINT8)r; + CYCLES(2); +} + + +/* SBCA IMM 0x82 */ +void HC11OP(sbca_imm)() +{ + UINT8 i = FETCH(); + UINT16 r = (REG_A - i) - ((m_ccr & CC_C) ? 1 : 0); + CLEAR_NZVC(); + SET_N8(r); + SET_Z8(r); + SET_V_SUB8(r, i, REG_A); + SET_C8(r); + REG_A = (UINT8)r; + CYCLES(2); +} + +/* SBCA IND, X 0xA2 */ +void HC11OP(sbca_indx)() +{ + UINT8 offset = FETCH(); + UINT8 i = READ8(m_ix + offset); + UINT16 r = (REG_A - i) - ((m_ccr & CC_C) ? 1 : 0); + CLEAR_NZVC(); + SET_N8(r); + SET_Z8(r); + SET_V_SUB8(r, i, REG_A); + SET_C8(r); + REG_A = (UINT8)r; + CYCLES(4); +} + +/* SBCA IND, Y 0x18, 0xA2 */ +void HC11OP(sbca_indy)() +{ + UINT8 offset = FETCH(); + UINT8 i = READ8(m_iy + offset); + UINT16 r = (REG_A - i) - ((m_ccr & CC_C) ? 1 : 0); + CLEAR_NZVC(); + SET_N8(r); + SET_Z8(r); + SET_V_SUB8(r, i, REG_A); + SET_C8(r); + REG_A = (UINT8)r; + CYCLES(5); +} + +/* SBCB IMM 0xC2 */ +void HC11OP(sbcb_imm)() +{ + UINT8 i = FETCH(); + UINT16 r = (REG_B - i) - ((m_ccr & CC_C) ? 1 : 0); + CLEAR_NZVC(); + SET_N8(r); + SET_Z8(r); + SET_V_SUB8(r, i, REG_B); + SET_C8(r); + REG_B = (UINT8)r; + CYCLES(2); +} + +/* SBCB IND, X 0xE2 */ +void HC11OP(sbcb_indx)() +{ + UINT8 offset = FETCH(); + UINT8 i = READ8(m_ix + offset); + UINT16 r = (REG_B - i) - ((m_ccr & CC_C) ? 1 : 0); + CLEAR_NZVC(); + SET_N8(r); + SET_Z8(r); + SET_V_SUB8(r, i, REG_B); + SET_C8(r); + REG_B = (UINT8)r; + CYCLES(4); +} + +/* SBCB IND, Y 0x18, 0xE2 */ +void HC11OP(sbcb_indy)() +{ + UINT8 offset = FETCH(); + UINT8 i = READ8(m_iy + offset); + UINT16 r = (REG_B - i) - ((m_ccr & CC_C) ? 1 : 0); + CLEAR_NZVC(); + SET_N8(r); + SET_Z8(r); + SET_V_SUB8(r, i, REG_B); + SET_C8(r); + REG_B = (UINT8)r; + CYCLES(5); +} + +/* SEC 0x0D */ +void HC11OP(sec)() +{ + m_ccr |= CC_C; + CYCLES(2); +} + +/* SEI 0x0F */ +void HC11OP(sei)() +{ + m_ccr |= CC_I; + CYCLES(2); +} + +/* SEV 0x0B */ +void HC11OP(sev)() +{ + m_ccr |= CC_V; + CYCLES(2); +} + +/* STAA DIR 0x97 */ +void HC11OP(staa_dir)() +{ + UINT8 d = FETCH(); + CLEAR_NZV(); + SET_N8(REG_A); + SET_Z8(REG_A); + WRITE8(d, REG_A); + CYCLES(3); +} + +/* STAA EXT 0xB7 */ +void HC11OP(staa_ext)() +{ + UINT16 adr = FETCH16(); + CLEAR_NZV(); + SET_N8(REG_A); + SET_Z8(REG_A); + WRITE8(adr, REG_A); + CYCLES(4); +} + +/* STAA IND, X 0xA7 */ +void HC11OP(staa_indx)() +{ + UINT8 offset = FETCH(); + CLEAR_NZV(); + SET_N8(REG_A); + SET_Z8(REG_A); + WRITE8(m_ix + offset, REG_A); + CYCLES(4); +} + +/* STAA IND, Y 0x18, 0xA7 */ +void HC11OP(staa_indy)() +{ + UINT8 offset = FETCH(); + CLEAR_NZV(); + SET_N8(REG_A); + SET_Z8(REG_A); + WRITE8(m_iy + offset, REG_A); + CYCLES(5); +} + +/* STAB DIR 0xD7 */ +void HC11OP(stab_dir)() +{ + UINT8 d = FETCH(); + CLEAR_NZV(); + SET_N8(REG_B); + SET_Z8(REG_B); + WRITE8(d, REG_B); + CYCLES(3); +} + +/* STAB EXT 0xF7 */ +void HC11OP(stab_ext)() +{ + UINT16 adr = FETCH16(); + CLEAR_NZV(); + SET_N8(REG_B); + SET_Z8(REG_B); + WRITE8(adr, REG_B); + CYCLES(4); +} + +/* STAB IND, X 0xE7 */ +void HC11OP(stab_indx)() +{ + UINT8 offset = FETCH(); + CLEAR_NZV(); + SET_N8(REG_B); + SET_Z8(REG_B); + WRITE8(m_ix + offset, REG_B); + CYCLES(4); +} + +/* STAB IND, Y 0x18, 0xE7 */ +void HC11OP(stab_indy)() +{ + UINT8 offset = FETCH(); + CLEAR_NZV(); + SET_N8(REG_B); + SET_Z8(REG_B); + WRITE8(m_iy + offset, REG_B); + CYCLES(5); +} + + +/* STD DIR 0xDD */ +void HC11OP(std_dir)() +{ + UINT8 d = FETCH(); + CLEAR_NZV(); + WRITE16(d, REG_D); + SET_N16(REG_D); + SET_Z16(REG_D); + CYCLES(4); +} + +/* STD EXT 0xFD */ +void HC11OP(std_ext)() +{ + UINT16 adr = FETCH16(); + CLEAR_NZV(); + WRITE16(adr, REG_D); + SET_N16(REG_D); + SET_Z16(REG_D); + CYCLES(5); +} + +/* STD IND, X 0xED */ +void HC11OP(std_indx)() +{ + UINT8 offset = FETCH(); + CLEAR_NZV(); + WRITE16(m_ix + offset, REG_D); + SET_N16(REG_D); + SET_Z16(REG_D); + CYCLES(5); +} + +/* STD IND, Y 0x18, 0xED */ +void HC11OP(std_indy)() +{ + UINT8 offset = FETCH(); + CLEAR_NZV(); + WRITE16(m_iy + offset, REG_D); + SET_N16(REG_D); + SET_Z16(REG_D); + CYCLES(6); +} + +/* STS DIR 0x9F */ +void HC11OP(sts_dir)() +{ + UINT8 d = FETCH(); + UINT16 r = m_sp; + CLEAR_NZV(); + WRITE8(d, (r & 0xff00) >> 8); + WRITE8(d + 1, (r & 0xff)); + SET_N16(r); + SET_Z16(r); + CYCLES(4); +} + + +/* STX DIR 0xDF */ +void HC11OP(stx_dir)() +{ + UINT8 adr = FETCH(); + UINT16 r = m_ix; + CLEAR_NZV(); + WRITE8(adr, (r & 0xff00) >> 8); + WRITE8(adr + 1, (r & 0xff)); + SET_N16(r); + SET_Z16(r); + CYCLES(4); +} + +/* STX EXT 0xFF */ +void HC11OP(stx_ext)() +{ + UINT16 adr = FETCH16(); + UINT16 r = m_ix; + CLEAR_NZV(); + WRITE8(adr, (r & 0xff00) >> 8); + WRITE8(adr + 1, (r & 0xff)); + SET_N16(r); + SET_Z16(r); + CYCLES(5); +} + + +/* STX INDX 0xEF */ +void HC11OP(stx_indx)() +{ + UINT16 adr = FETCH(); + UINT16 r = m_ix; + CLEAR_NZV(); + WRITE8(m_ix + adr, (r & 0xff00) >> 8); + WRITE8(m_ix + adr + 1, (r & 0xff)); + SET_N16(r); + SET_Z16(r); + CYCLES(5); +} + + +/* STX INDY 0xCD 0xEF */ +void HC11OP(stx_indy)() +{ + UINT16 adr = FETCH(); + UINT16 r = m_ix; + CLEAR_NZV(); + WRITE8(m_iy + adr, (r & 0xff00) >> 8); + WRITE8(m_iy + adr + 1, (r & 0xff)); + SET_N16(r); + SET_Z16(r); + CYCLES(6); +} + +/* STY DIR 0x18 0xDF */ +void HC11OP(sty_dir)() +{ + UINT8 adr = FETCH(); + UINT16 r = m_iy; + CLEAR_NZV(); + WRITE8(adr, (r & 0xff00) >> 8); + WRITE8(adr + 1, (r & 0xff)); + SET_N16(r); + SET_Z16(r); + CYCLES(5); +} + + +/* STY EXT 0x18 0xFF */ +void HC11OP(sty_ext)() +{ + UINT16 adr = FETCH16(); + UINT16 r = m_iy; + CLEAR_NZV(); + WRITE8(adr, (r & 0xff00) >> 8); + WRITE8(adr + 1, (r & 0xff)); + SET_N16(r); + SET_Z16(r); + CYCLES(6); +} + +/* STY INDX 0x1A 0xEF */ +void HC11OP(sty_indx)() +{ + UINT16 adr = FETCH(); + UINT16 r = m_iy; + CLEAR_NZV(); + WRITE8(m_ix + adr, (r & 0xff00) >> 8); + WRITE8(m_ix + adr + 1, (r & 0xff)); + SET_N16(r); + SET_Z16(r); + CYCLES(6); +} + +/* STY INDY 0x18 0xEF */ +void HC11OP(sty_indy)() +{ + UINT16 adr = FETCH(); + UINT16 r = m_iy; + CLEAR_NZV(); + WRITE8(m_iy + adr, (r & 0xff00) >> 8); + WRITE8(m_iy + adr + 1, (r & 0xff)); + SET_N16(r); + SET_Z16(r); + CYCLES(6); +} + +/* STOP 0xCF */ +void HC11OP(stop)() +{ + if(m_stop_state == 0 && ((m_ccr & CC_S) == 0)) + { + m_stop_state = 1; + } + + if(m_stop_state == 1) + { + SET_PC(m_ppc); // wait for an exception + } + + if(m_stop_state == 2) + { + m_stop_state = 0; + } + + CYCLES(2); +} + + +/* SUBA IMM 0x80 */ +void HC11OP(suba_imm)() +{ + UINT8 i = FETCH(); + UINT16 r = REG_A - i; + CLEAR_NZVC(); + SET_N8(r); + SET_Z8(r); + SET_V_SUB8(r, i, REG_A); + SET_C8(r); + REG_A = (UINT8)r; + CYCLES(2); +} + + +/* SUBA DIR 0xd0 */ +void HC11OP(suba_dir)() +{ + UINT8 d = FETCH(); + UINT8 i = READ8(d); + UINT16 r = REG_A - i; + CLEAR_NZVC(); + SET_N8(r); + SET_Z8(r); + SET_V_SUB8(r, i, REG_A); + SET_C8(r); + REG_A = (UINT8)r; + CYCLES(3); +} + + +/* SUBA EXT 0xE0 */ +void HC11OP(suba_ext)() +{ + UINT16 adr = FETCH16(); + UINT8 i = READ8(adr); + UINT16 r = REG_A - i; + CLEAR_NZVC(); + SET_N8(r); + SET_Z8(r); + SET_V_SUB8(r, i, REG_A); + SET_C8(r); + REG_A = (UINT8)r; + CYCLES(4); +} + + +/* SUBA INDX 0xA0 */ +void HC11OP(suba_indx)() +{ + UINT16 adr = FETCH(); + UINT8 i = READ8(m_ix + adr); + UINT16 r = REG_A - i; + CLEAR_NZVC(); + SET_N8(r); + SET_Z8(r); + SET_V_SUB8(r, i, REG_A); + SET_C8(r); + REG_A = (UINT8)r; + CYCLES(4); +} + + +/* SUBA INDY 0x18 0xA0 */ +void HC11OP(suba_indy)() +{ + UINT16 adr = FETCH(); + UINT8 i = READ8(m_iy + adr); + UINT16 r = REG_A - i; + CLEAR_NZVC(); + SET_N8(r); + SET_Z8(r); + SET_V_SUB8(r, i, REG_A); + SET_C8(r); + REG_A = (UINT8)r; + CYCLES(5); +} + + +/* SUBB IMM 0xC0 */ +void HC11OP(subb_imm)() +{ + UINT8 i = FETCH(); + UINT16 r = REG_B - i; + CLEAR_NZVC(); + SET_N8(r); + SET_Z8(r); + SET_V_SUB8(r, i, REG_B); + SET_C8(r); + REG_B = (UINT8)r; + CYCLES(2); +} + + +/* SUBB DIR 0xD0 */ +void HC11OP(subb_dir)() +{ + UINT8 d = FETCH(); + UINT8 i = READ8(d); + UINT16 r = REG_B - i; + CLEAR_NZVC(); + SET_N8(r); + SET_Z8(r); + SET_V_SUB8(r, i, REG_B); + SET_C8(r); + REG_B = (UINT8)r; + CYCLES(3); +} + + +/* SUBB EXT 0xF0 */ +void HC11OP(subb_ext)() +{ + UINT16 adr = FETCH16(); + UINT8 i = READ8(adr); + UINT16 r = REG_B - i; + CLEAR_NZVC(); + SET_N8(r); + SET_Z8(r); + SET_V_SUB8(r, i, REG_B); + SET_C8(r); + REG_B = (UINT8)r; + CYCLES(4); +} + + +/* SUBB INDX 0xE0 */ +void HC11OP(subb_indx)() +{ + UINT16 adr = FETCH(); + UINT8 i = READ8(m_ix + adr); + UINT16 r = REG_B - i; + CLEAR_NZVC(); + SET_N8(r); + SET_Z8(r); + SET_V_SUB8(r, i, REG_B); + SET_C8(r); + REG_B = (UINT8)r; + CYCLES(4); +} + +/* SUBB INDY 0x18 0xE0 */ +void HC11OP(subb_indy)() +{ + UINT16 adr = FETCH(); + UINT8 i = READ8(m_iy + adr); + UINT16 r = REG_B - i; + CLEAR_NZVC(); + SET_N8(r); + SET_Z8(r); + SET_V_SUB8(r, i, REG_B); + SET_C8(r); + REG_B = (UINT8)r; + CYCLES(5); +} + +/* SUBD IMM 0x83 */ +void HC11OP(subd_imm)() +{ + UINT16 i = FETCH16(); + UINT32 r = REG_D - i; + CLEAR_NZVC(); + SET_N16(r); + SET_Z16(r); + SET_V_SUB16(r, i, REG_D); + SET_C16(r); + REG_D = (UINT16)r; + CYCLES(4); +} + +/* SUBD DIR 0x93 */ +void HC11OP(subd_dir)() +{ + UINT8 d = FETCH(); + UINT16 i = READ16(d); + UINT32 r = REG_D - i; + CLEAR_NZVC(); + SET_N16(r); + SET_Z16(r); + SET_V_SUB16(r, i, REG_D); + SET_C16(r); + REG_D = (UINT16)r; + CYCLES(5); +} + +/* SUBD EXT 0xB3 */ +void HC11OP(subd_ext)() +{ + UINT16 addr = FETCH16(); + UINT16 i = READ16(addr); + UINT32 r = REG_D - i; + CLEAR_NZVC(); + SET_N16(r); + SET_Z16(r); + SET_V_SUB16(r, i, REG_D); + SET_C16(r); + REG_D = (UINT16)r; + CYCLES(6); +} + +/* SUBD INDX 0xA3 */ +void HC11OP(subd_indx)() +{ + UINT8 offset = FETCH(); + UINT16 i = READ16(m_ix + offset); + UINT32 r = REG_D - i; + CLEAR_NZVC(); + SET_N16(r); + SET_Z16(r); + SET_V_SUB16(r, i, REG_D); + SET_C16(r); + REG_D = (UINT16)r; + CYCLES(6); +} + +/* SUBD INDY 0x18 0xA3 */ +void HC11OP(subd_indy)() +{ + UINT8 offset = FETCH(); + UINT16 i = READ16(m_iy + offset); + UINT32 r = REG_D - i; + CLEAR_NZVC(); + SET_N16(r); + SET_Z16(r); + SET_V_SUB16(r, i, REG_D); + SET_C16(r); + REG_D = (UINT16)r; + CYCLES(7); +} + +/* SWI 0x3F */ +void HC11OP(swi)() +{ + UINT16 pc_vector; + //m_pc++; + PUSH16(m_pc); + PUSH16(m_iy); + PUSH16(m_ix); + PUSH8(REG_A); + PUSH8(REG_B); + PUSH8(m_ccr); + pc_vector = READ16(0xfff6); + SET_PC(pc_vector); + m_ccr |= CC_I; //irq taken, mask the flag + CYCLES(14); +} + +/* TAB 0x16 */ +void HC11OP(tab)() +{ + CLEAR_NZV(); + REG_B = REG_A; + SET_N8(REG_B); + SET_Z8(REG_B); + CYCLES(2); +} + +/* TAP 0x06 */ +void HC11OP(tap)() +{ + UINT8 x_flag = m_ccr & CC_X; + m_ccr = REG_A; + if(x_flag == 0 && m_ccr & CC_X) //X flag cannot do a 0->1 transition with this instruction. + m_ccr &= ~CC_X; + + CYCLES(2); +} + +/* TBA 0x17 */ +void HC11OP(tba)() +{ + CLEAR_NZV(); + REG_A = REG_B; + SET_N8(REG_A); + SET_Z8(REG_A); + CYCLES(2); +} + +/* TEST 0x00 */ +void HC11OP(test)() +{ +// if(m_test_mode) + SET_PC(m_ppc); // Note: docs says "incremented" but the behaviour makes me think that's actually "decremented". +// else +// { +// TODO: execute an illegal opcode exception here (NMI) +// } + + CYCLES(1); +} + +/* TPA 0x07 */ +void HC11OP(tpa)() +{ + REG_A = m_ccr; + CYCLES(2); +} + + +/* TSTA 0x4D */ +void HC11OP(tsta)() +{ + CLEAR_NZVC(); + SET_N8(REG_A); + SET_Z8(REG_A); + CYCLES(2); +} + +/* TSTB 0x5D */ +void HC11OP(tstb)() +{ + CLEAR_NZVC(); + SET_N8(REG_B); + SET_Z8(REG_B); + CYCLES(2); +} + +/* TST EXT 0x7D */ +void HC11OP(tst_ext)() +{ + UINT16 adr = FETCH16(); + UINT8 i = READ8(adr); + CLEAR_NZVC(); + SET_N8(i); + SET_Z8(i); + CYCLES(6); +} + +/* TST IND, X 0x6D */ +void HC11OP(tst_indx)() +{ + UINT8 offset = FETCH(); + UINT8 i = READ8(m_ix + offset); + CLEAR_NZVC(); + SET_N8(i); + SET_Z8(i); + CYCLES(6); +} + +/* TST IND, Y 0x18, 0x6D */ +void HC11OP(tst_indy)() +{ + UINT8 offset = FETCH(); + UINT8 i = READ8(m_iy + offset); + CLEAR_NZVC(); + SET_N8(i); + SET_Z8(i); + CYCLES(6); +} + +/* TSX 0x30 */ +void HC11OP(tsx)() +{ + m_ix = m_sp + 1; + CYCLES(3); +} + +/* TSY 0x18 0x30 */ +void HC11OP(tsy)() +{ + m_iy = m_sp + 1; + CYCLES(4); +} + +/* TXS 0x35 */ +void HC11OP(txs)() +{ + m_sp = m_ix - 1; + CYCLES(3); +} + +/* TYS 0x18 0x35 */ +void HC11OP(tys)() +{ + m_sp = m_iy - 1; + CYCLES(4); +} + +/* WAI 0x3E */ +void HC11OP(wai)() +{ + if(m_wait_state == 0) + { + /* TODO: the following is bogus, pushes regs HERE in an instruction that wants an irq to go out? */ + PUSH16(m_pc); + PUSH16(m_iy); + PUSH16(m_ix); + PUSH8(REG_A); + PUSH8(REG_B); + PUSH8(m_ccr); + CYCLES(14); + m_wait_state = 1; + } + if(m_wait_state == 1) + { + SET_PC(m_ppc); // wait for an exception + CYCLES(1); + } + if(m_wait_state == 2) + { + m_wait_state = 0; + CYCLES(1); + } +} + +/* XGDX 0x8F */ +void HC11OP(xgdx)() +{ + UINT16 tmp = REG_D; + REG_D = m_ix; + m_ix = tmp; + CYCLES(3); +} + + +/* XGDY 0x18, 0x8F */ +void HC11OP(xgdy)() +{ + UINT16 tmp = REG_D; + REG_D = m_iy; + m_iy = tmp; + CYCLES(4); +} + +/*****************************************************************************/ + +void HC11OP(page2)() +{ + UINT8 op2 = FETCH(); + (this->*hc11_optable_page2[op2])(); +} + +void HC11OP(page3)() +{ + UINT8 op2 = FETCH(); + (this->*hc11_optable_page3[op2])(); +} + +void HC11OP(page4)() +{ + UINT8 op2 = FETCH(); + (this->*hc11_optable_page4[op2])(); +} + +void HC11OP(invalid)() +{ + fatalerror("HC11: Invalid opcode 0x%02X at %04X\n", READ8(m_pc-1), m_pc-1); +} diff --git a/src/devices/cpu/mc68hc11/mc68hc11.c b/src/devices/cpu/mc68hc11/mc68hc11.c new file mode 100644 index 00000000000..f05d9126334 --- /dev/null +++ b/src/devices/cpu/mc68hc11/mc68hc11.c @@ -0,0 +1,599 @@ +// license:BSD-3-Clause +// copyright-holders:Ville Linde, Angelo Salese, hap +/* + Motorola MC68HC11 emulator + + Written by Ville Linde & Angelo Salese + +TODO: +- Interrupts handling is really bare-bones, just to make Hit Poker happy; +- Timers are really sketchy as per now, only TOC1 is emulated so far; +- Complete opcodes hook-up; +- Emulate the MC68HC12 (same as HC11 with a bunch of new opcodes); + + */ + +#include "emu.h" +#include "debugger.h" +#include "mc68hc11.h" + +enum +{ + HC11_PC = 1, + HC11_SP, + HC11_A, + HC11_B, + HC11_IX, + HC11_IY +}; + +#define CC_S 0x80 +#define CC_X 0x40 +#define CC_H 0x20 +#define CC_I 0x10 +#define CC_N 0x08 +#define CC_Z 0x04 +#define CC_V 0x02 +#define CC_C 0x01 + +static const int div_tab[4] = { 1, 4, 8, 16 }; + + +const device_type MC68HC11 = &device_creator; + + +mc68hc11_cpu_device::mc68hc11_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : cpu_device(mconfig, MC68HC11, "MC68HC11", tag, owner, clock, "mc68hc11", __FILE__) + , m_program_config("program", ENDIANNESS_LITTLE, 8, 16, 0 ) + , m_io_config("io", ENDIANNESS_LITTLE, 8, 8, 0) + /* defaults it to the HC11M0 version for now (I might strip this down on a later date) */ + , m_has_extended_io(1) + , m_internal_ram_size(1280) + , m_init_value(0x01) +{ +} + + +offs_t mc68hc11_cpu_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( hc11 ); + return CPU_DISASSEMBLE_NAME(hc11)(this, buffer, pc, oprom, opram, options); +} + + +#define HC11OP(XX) mc68hc11_cpu_device::hc11_##XX + +/*****************************************************************************/ +/* Internal registers */ + +UINT8 mc68hc11_cpu_device::hc11_regs_r(UINT32 address) +{ + int reg = address & 0xff; + + switch(reg) + { + case 0x00: /* PORTA */ + return m_io->read_byte(MC68HC11_IO_PORTA); + case 0x01: /* DDRA */ + return 0; + case 0x02: /* PIOC */ + return 0; + case 0x03: /* PORTC */ + return m_io->read_byte(MC68HC11_IO_PORTC); + case 0x04: /* PORTB */ + return m_io->read_byte(MC68HC11_IO_PORTB); + case 0x08: /* PORTD */ + return m_io->read_byte(MC68HC11_IO_PORTD); + case 0x09: /* DDRD */ + return 0; + case 0x0a: /* PORTE */ + return m_io->read_byte(MC68HC11_IO_PORTE); + case 0x0e: /* TCNT */ + return m_tcnt >> 8; + case 0x0f: + return m_tcnt & 0xff; + case 0x16: /* TOC1 */ + return m_toc1 >> 8; + case 0x17: + return m_toc1 & 0xff; + case 0x23: + return m_tflg1; + case 0x28: /* SPCR1 */ + return 0; + case 0x30: /* ADCTL */ + return 0x80; + case 0x31: /* ADR1 */ + { + if (m_adctl & 0x10) + { + return m_io->read_byte((m_adctl & 0x4) + MC68HC11_IO_AD0); + } + else + { + return m_io->read_byte((m_adctl & 0x7) + MC68HC11_IO_AD0); + } + } + case 0x32: /* ADR2 */ + { + if (m_adctl & 0x10) + { + return m_io->read_byte((m_adctl & 0x4) + MC68HC11_IO_AD1); + } + else + { + return m_io->read_byte((m_adctl & 0x7) + MC68HC11_IO_AD0); + } + } + case 0x33: /* ADR3 */ + { + if (m_adctl & 0x10) + { + return m_io->read_byte((m_adctl & 0x4) + MC68HC11_IO_AD2); + } + else + { + return m_io->read_byte((m_adctl & 0x7) + MC68HC11_IO_AD0); + } + } + case 0x34: /* ADR4 */ + { + if (m_adctl & 0x10) + { + return m_io->read_byte((m_adctl & 0x4) + MC68HC11_IO_AD3); + } + else + { + return m_io->read_byte((m_adctl & 0x7) + MC68HC11_IO_AD0); + } + } + case 0x38: /* OPT2 */ + return 0; + case 0x70: /* SCBDH */ + return 0; + case 0x71: /* SCBDL */ + return 0; + case 0x72: /* SCCR1 */ + return 0; + case 0x73: /* SCCR2 */ + return 0; + case 0x74: /* SCSR1 */ + return 0x40; + case 0x7c: /* PORTH */ + return m_io->read_byte(MC68HC11_IO_PORTH); + case 0x7e: /* PORTG */ + return m_io->read_byte(MC68HC11_IO_PORTG); + case 0x7f: /* DDRG */ + return 0; + + case 0x88: /* SPCR2 */ + return 0; + case 0x89: /* SPSR2 */ + return 0x80; + case 0x8a: /* SPDR2 */ + return m_io->read_byte(MC68HC11_IO_SPI2_DATA); + + case 0x8b: /* OPT4 */ + return 0; + } + + logerror("HC11: regs_r %02X\n", reg); + return 0; // Dummy +} + +void mc68hc11_cpu_device::hc11_regs_w(UINT32 address, UINT8 value) +{ + int reg = address & 0xff; + + switch(reg) + { + case 0x00: /* PORTA */ + m_io->write_byte(MC68HC11_IO_PORTA, value); + return; + case 0x01: /* DDRA */ + //osd_printf_debug("HC11: ddra = %02X\n", value); + return; + case 0x03: /* PORTC */ + m_io->write_byte(MC68HC11_IO_PORTC, value); + return; + case 0x04: /* PORTC */ + m_io->write_byte(MC68HC11_IO_PORTB, value); + return; + case 0x08: /* PORTD */ + m_io->write_byte(MC68HC11_IO_PORTD, value); //mask & 0x3f? + return; + case 0x09: /* DDRD */ + //osd_printf_debug("HC11: ddrd = %02X\n", value); + return; + case 0x0a: /* PORTE */ + m_io->write_byte(MC68HC11_IO_PORTE, value); + return; + case 0x0e: /* TCNT */ + case 0x0f: + logerror("HC11: TCNT register write %02x %02x!\n",address,value); + return; + case 0x16: /* TOC1 */ + /* TODO: inhibit for one bus cycle */ + m_toc1 = (value << 8) | (m_toc1 & 0xff); + return; + case 0x17: + m_toc1 = (value & 0xff) | (m_toc1 & 0xff00); + return; + case 0x22: /* TMSK1 */ + m_tmsk1 = value; + return; + case 0x23: + m_tflg1 &= ~value; + return; + case 0x24: /* TMSK2 */ + m_pr = value & 3; + return; + case 0x28: /* SPCR1 */ + return; + case 0x30: /* ADCTL */ + m_adctl = value; + return; + case 0x38: /* OPT2 */ + return; + case 0x39: /* OPTION */ + return; + case 0x3a: /* COPRST (watchdog) */ + return; + + case 0x3d: /* INIT */ + { + int reg_page = value & 0xf; + int ram_page = (value >> 4) & 0xf; + + if (reg_page == ram_page) { + m_reg_position = reg_page << 12; + m_ram_position = (ram_page << 12) + ((m_has_extended_io) ? 0x100 : 0x80); + } else { + m_reg_position = reg_page << 12; + m_ram_position = ram_page << 12; + } + return; + } + + case 0x3f: /* CONFIG */ + return; + + case 0x70: /* SCBDH */ + return; + case 0x71: /* SCBDL */ + return; + case 0x72: /* SCCR1 */ + return; + case 0x73: /* SCCR2 */ + return; + case 0x77: /* SCDRL */ + return; + case 0x7c: /* PORTH */ + m_io->write_byte(MC68HC11_IO_PORTH, value); + return; + case 0x7d: /* DDRH */ + //osd_printf_debug("HC11: ddrh = %02X at %04X\n", value, m_pc); + return; + case 0x7e: /* PORTG */ + m_io->write_byte(MC68HC11_IO_PORTG, value); + return; + case 0x7f: /* DDRG */ + //osd_printf_debug("HC11: ddrg = %02X at %04X\n", value, m_pc); + return; + + case 0x88: /* SPCR2 */ + return; + case 0x89: /* SPSR2 */ + return; + case 0x8a: /* SPDR2 */ + m_io->write_byte(MC68HC11_IO_SPI2_DATA, value); + return; + + case 0x8b: /* OPT4 */ + return; + + } + + logerror("HC11: regs_w %02X, %02X\n", reg, value); +} + +/*****************************************************************************/ + +UINT8 mc68hc11_cpu_device::FETCH() +{ + return m_direct->read_byte(m_pc++); +} + +UINT16 mc68hc11_cpu_device::FETCH16() +{ + UINT16 w; + w = (m_direct->read_byte(m_pc) << 8) | (m_direct->read_byte(m_pc+1)); + m_pc += 2; + return w; +} + +UINT8 mc68hc11_cpu_device::READ8(UINT32 address) +{ + if(address >= m_reg_position && address < m_reg_position+(m_has_extended_io ? 0x100 : 0x40)) + { + return hc11_regs_r(address); + } + else if(address >= m_ram_position && address < m_ram_position+m_internal_ram_size) + { + return m_internal_ram[address-m_ram_position]; + } + return m_program->read_byte(address); +} + +void mc68hc11_cpu_device::WRITE8(UINT32 address, UINT8 value) +{ + if(address >= m_reg_position && address < m_reg_position+(m_has_extended_io ? 0x100 : 0x40)) + { + hc11_regs_w(address, value); + return; + } + else if(address >= m_ram_position && address < m_ram_position+m_internal_ram_size) + { + m_internal_ram[address-m_ram_position] = value; + return; + } + m_program->write_byte(address, value); +} + +UINT16 mc68hc11_cpu_device::READ16(UINT32 address) +{ + return (READ8(address) << 8) | (READ8(address+1)); +} + +void mc68hc11_cpu_device::WRITE16(UINT32 address, UINT16 value) +{ + WRITE8(address+0, (value >> 8) & 0xff); + WRITE8(address+1, (value >> 0) & 0xff); +} + +/*****************************************************************************/ + + +#include "hc11ops.inc" +#include "hc11ops.h" + +void mc68hc11_cpu_device::device_start() +{ + int i; + + /* clear the opcode tables */ + for(i=0; i < 256; i++) { + hc11_optable[i] = &HC11OP(invalid); + hc11_optable_page2[i] = &HC11OP(invalid); + hc11_optable_page3[i] = &HC11OP(invalid); + hc11_optable_page4[i] = &HC11OP(invalid); + } + /* fill the opcode tables */ + for(i=0; i < sizeof(hc11_opcode_list)/sizeof(hc11_opcode_list_struct); i++) + { + switch(hc11_opcode_list[i].page) + { + case 0x00: + hc11_optable[hc11_opcode_list[i].opcode] = hc11_opcode_list[i].handler; + break; + case 0x18: + hc11_optable_page2[hc11_opcode_list[i].opcode] = hc11_opcode_list[i].handler; + break; + case 0x1A: + hc11_optable_page3[hc11_opcode_list[i].opcode] = hc11_opcode_list[i].handler; + break; + case 0xCD: + hc11_optable_page4[hc11_opcode_list[i].opcode] = hc11_opcode_list[i].handler; + break; + } + } + + m_internal_ram.resize(m_internal_ram_size); + + m_program = &space(AS_PROGRAM); + m_direct = &m_program->direct(); + m_io = &space(AS_IO); + + save_item(NAME(m_pc)); + save_item(NAME(m_ix)); + save_item(NAME(m_iy)); + save_item(NAME(m_sp)); + save_item(NAME(m_ppc)); + save_item(NAME(m_ccr)); + save_item(NAME(m_d.d8.a)); + save_item(NAME(m_d.d8.b)); + save_item(NAME(m_adctl)); + save_item(NAME(m_ad_channel)); + save_item(NAME(m_ram_position)); + save_item(NAME(m_reg_position)); + save_item(NAME(m_irq_state)); + save_item(NAME(m_has_extended_io)); + save_item(NAME(m_internal_ram_size)); + save_item(NAME(m_init_value)); + save_item(NAME(m_internal_ram)); + save_item(NAME(m_wait_state)); + save_item(NAME(m_stop_state)); + save_item(NAME(m_tflg1)); + save_item(NAME(m_tmsk1)); + save_item(NAME(m_toc1)); + save_item(NAME(m_tcnt)); +// save_item(NAME(m_por)); + save_item(NAME(m_pr)); + save_item(NAME(m_frc_base)); + + m_pc = 0; + m_d.d16 = 0; + m_ix = 0; + m_iy = 0; + m_sp = 0; + m_ppc = 0; + m_adctl = 0; + m_ad_channel = 0; + m_irq_state[0] = m_irq_state[1] = 0; + m_ram_position = 0; + m_reg_position = 0; + m_tflg1 = 0; + m_tmsk1 = 0; + + state_add( HC11_PC, "PC", m_pc).formatstr("%04X"); + state_add( HC11_SP, "SP", m_sp).formatstr("%04X"); + state_add( HC11_A, "A", m_d.d8.a).formatstr("%02X"); + state_add( HC11_B, "B", m_d.d8.b).formatstr("%02X"); + state_add( HC11_IX, "IX", m_ix).formatstr("%04X"); + state_add( HC11_IY, "IY", m_iy).formatstr("%04X"); + + state_add( STATE_GENPC, "GENPC", m_pc).noshow(); + state_add( STATE_GENFLAGS, "GENFLAGS", m_ccr).formatstr("%8s").noshow(); + + m_icountptr = &m_icount; +} + + +void mc68hc11_cpu_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + switch (entry.index()) + { + case STATE_GENFLAGS: + strprintf(str, "%c%c%c%c%c%c%c%c", + (m_ccr & CC_S) ? 'S' : '.', + (m_ccr & CC_X) ? 'X' : '.', + (m_ccr & CC_H) ? 'H' : '.', + (m_ccr & CC_I) ? 'I' : '.', + (m_ccr & CC_N) ? 'N' : '.', + (m_ccr & CC_Z) ? 'Z' : '.', + (m_ccr & CC_V) ? 'V' : '.', + (m_ccr & CC_C) ? 'C' : '.'); + break; + } +} + + +void mc68hc11_cpu_device::device_reset() +{ + m_pc = READ16(0xfffe); + m_wait_state = 0; + m_stop_state = 0; + m_ccr = CC_X | CC_I | CC_S; + hc11_regs_w(0x3d,m_init_value); + m_toc1 = 0xffff; + m_tcnt = 0xffff; +// m_por = 1; // for first timer overflow / compare stuff + m_pr = 3; // timer prescale + m_frc_base = 0; +} + +/* +IRQ table vectors: +0xffd6: SCI +0xffd8: SPI +0xffda: Pulse Accumulator Input Edge +0xffdc: Pulse Accumulator Overflow +0xffde: Timer Overflow +0xffe0: Timer Output Capture 5 +0xffe2: Timer Output Capture 4 +0xffe4: Timer Output Capture 3 +0xffe6: Timer Output Capture 2 +0xffe8: Timer Output Capture 1 +0xffea: Timer Input Capture 3 +0xffec: Timer Input Capture 2 +0xffee: Timer Input Capture 1 +0xfff0: Real Time Int +0xfff2: IRQ +0xfff4: XIRQ +0xfff6: SWI (Trap IRQ) +0xfff8: Illegal Opcode (NMI) +0xfffa: CO-Processor Fail +0xfffc: Clock Monitor +0xfffe: RESET +*/ + +void mc68hc11_cpu_device::check_irq_lines() +{ + if( m_irq_state[MC68HC11_IRQ_LINE]!=CLEAR_LINE && (!(m_ccr & CC_I)) ) + { + UINT16 pc_vector; + + if(m_wait_state == 0) + { + PUSH16(m_pc); + PUSH16(m_iy); + PUSH16(m_ix); + PUSH8(REG_A); + PUSH8(REG_B); + PUSH8(m_ccr); + } + pc_vector = READ16(0xfff2); + SET_PC(pc_vector); + m_ccr |= CC_I; //irq taken, mask the flag + if(m_wait_state == 1) { m_wait_state = 2; } + if(m_stop_state == 1) { m_stop_state = 2; } + standard_irq_callback(MC68HC11_IRQ_LINE); + } + + /* check timers here */ + { + int divider = div_tab[m_pr & 3]; + UINT64 cur_time = total_cycles(); + UINT32 add = (cur_time - m_frc_base) / divider; + + if (add > 0) + { + for(UINT32 i=0;i 0) + { + UINT8 op; + + check_irq_lines(); + + m_ppc = m_pc; + debugger_instruction_hook(this, m_pc); + + op = FETCH(); + (this->*hc11_optable[op])(); + } +} diff --git a/src/devices/cpu/mc68hc11/mc68hc11.h b/src/devices/cpu/mc68hc11/mc68hc11.h new file mode 100644 index 00000000000..6098cebdfe4 --- /dev/null +++ b/src/devices/cpu/mc68hc11/mc68hc11.h @@ -0,0 +1,443 @@ +// license:BSD-3-Clause +// copyright-holders:Ville Linde, Angelo Salese, hap +#pragma once + +#ifndef __MC68HC11_H__ +#define __MC68HC11_H__ + + +#define MC68HC11_IO_PORTA 0x00 +#define MC68HC11_IO_PORTB 0x01 +#define MC68HC11_IO_PORTC 0x02 +#define MC68HC11_IO_PORTD 0x03 +#define MC68HC11_IO_PORTE 0x04 +#define MC68HC11_IO_PORTF 0x05 +#define MC68HC11_IO_PORTG 0x06 +#define MC68HC11_IO_PORTH 0x07 +#define MC68HC11_IO_SPI1_DATA 0x08 +#define MC68HC11_IO_SPI2_DATA 0x09 +#define MC68HC11_IO_AD0 0x10 +#define MC68HC11_IO_AD1 0x11 +#define MC68HC11_IO_AD2 0x12 +#define MC68HC11_IO_AD3 0x13 +#define MC68HC11_IO_AD4 0x14 +#define MC68HC11_IO_AD5 0x15 +#define MC68HC11_IO_AD6 0x16 +#define MC68HC11_IO_AD7 0x17 + +#define MC68HC11_IRQ_LINE 0 +#define MC68HC11_TOC1_LINE 1 + + +extern const device_type MC68HC11; + + +#define MCFG_MC68HC11_CONFIG(_has_extended_io, _internal_ram_size, _init_value) \ + mc68hc11_cpu_device::set_has_extended_io(*device, _has_extended_io); \ + mc68hc11_cpu_device::set_internal_ram_size(*device, _internal_ram_size); \ + mc68hc11_cpu_device::set_init_value(*device, _init_value); + + +class mc68hc11_cpu_device : public cpu_device +{ +public: + // construction/destruction + mc68hc11_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // I/O enable flag + static void set_has_extended_io(device_t &device, int has_extended_io) { downcast(device).m_has_extended_io = has_extended_io; } + static void set_internal_ram_size(device_t &device, int internal_ram_size) { downcast(device).m_internal_ram_size = internal_ram_size; } + // default value for INIT register + static void set_init_value(device_t &device, int init_value) { downcast(device).m_init_value = init_value; } + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_execute_interface overrides + virtual UINT32 execute_min_cycles() const { return 1; } + virtual UINT32 execute_max_cycles() const { return 41; } + virtual UINT32 execute_input_lines() const { return 2; } + virtual UINT32 execute_default_irq_vector() const { return 0; } + virtual void execute_run(); + virtual void execute_set_input(int inputnum, int state); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const + { + return (spacenum == AS_PROGRAM) ? &m_program_config : ( (spacenum == AS_IO) ? &m_io_config : NULL ); + } + + // device_state_interface overrides + void state_string_export(const device_state_entry &entry, std::string &str); + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const { return 1; } + virtual UINT32 disasm_max_opcode_bytes() const { return 5; } + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + +private: + address_space_config m_program_config; + address_space_config m_io_config; + + union { + struct { +#ifdef LSB_FIRST + UINT8 b; + UINT8 a; +#else + UINT8 a; + UINT8 b; +#endif + } d8; + UINT16 d16; + } m_d; + + UINT16 m_ix; + UINT16 m_iy; + UINT16 m_sp; + UINT16 m_pc; + UINT16 m_ppc; + UINT8 m_ccr; + + UINT8 m_adctl; + int m_ad_channel; + + UINT8 m_irq_state[2]; + direct_read_data *m_direct; + address_space *m_program; + address_space *m_io; + int m_icount; + + int m_ram_position; + int m_reg_position; + dynamic_buffer m_internal_ram; + + int m_has_extended_io; // extended I/O enable flag + int m_internal_ram_size; + int m_init_value; + + UINT8 m_wait_state; + UINT8 m_stop_state; + + UINT8 m_tflg1; + UINT8 m_tmsk1; + UINT16 m_toc1; + UINT16 m_tcnt; +// UINT8 m_por; + UINT8 m_pr; + + UINT64 m_frc_base; + + typedef void (mc68hc11_cpu_device::*ophandler)(); + struct hc11_opcode_list_struct + { + int page; + int opcode; + ophandler handler; + }; + static const hc11_opcode_list_struct hc11_opcode_list[]; + + ophandler hc11_optable[256]; + ophandler hc11_optable_page2[256]; + ophandler hc11_optable_page3[256]; + ophandler hc11_optable_page4[256]; + + UINT8 hc11_regs_r(UINT32 address); + void hc11_regs_w(UINT32 address, UINT8 value); + UINT8 FETCH(); + UINT16 FETCH16(); + UINT8 READ8(UINT32 address); + void WRITE8(UINT32 address, UINT8 value); + UINT16 READ16(UINT32 address); + void WRITE16(UINT32 address, UINT16 value); + void CYCLES(int cycles); + void SET_PC(int pc); + void PUSH8(UINT8 value); + void PUSH16(UINT16 value); + UINT8 POP8(); + UINT16 POP16(); + void hc11_aba(); + void hc11_abx(); + void hc11_aby(); + void hc11_adca_imm(); + void hc11_adca_dir(); + void hc11_adca_ext(); + void hc11_adca_indx(); + void hc11_adca_indy(); + void hc11_adcb_imm(); + void hc11_adcb_dir(); + void hc11_adcb_ext(); + void hc11_adcb_indx(); + void hc11_adcb_indy(); + void hc11_adda_imm(); + void hc11_adda_dir(); + void hc11_adda_ext(); + void hc11_adda_indx(); + void hc11_adda_indy(); + void hc11_addb_imm(); + void hc11_addb_dir(); + void hc11_addb_ext(); + void hc11_addb_indx(); + void hc11_addb_indy(); + void hc11_addd_imm(); + void hc11_addd_dir(); + void hc11_addd_ext(); + void hc11_addd_indx(); + void hc11_addd_indy(); + void hc11_anda_imm(); + void hc11_anda_dir(); + void hc11_anda_ext(); + void hc11_anda_indx(); + void hc11_anda_indy(); + void hc11_andb_imm(); + void hc11_andb_dir(); + void hc11_andb_ext(); + void hc11_andb_indx(); + void hc11_andb_indy(); + void hc11_asla(); + void hc11_aslb(); + void hc11_asl_ext(); + void hc11_bita_imm(); + void hc11_bita_dir(); + void hc11_bita_ext(); + void hc11_bita_indx(); + void hc11_bita_indy(); + void hc11_bitb_imm(); + void hc11_bitb_dir(); + void hc11_bitb_ext(); + void hc11_bitb_indx(); + void hc11_bitb_indy(); + void hc11_bcc(); + void hc11_bclr_dir(); + void hc11_bclr_indx(); + void hc11_bcs(); + void hc11_beq(); + void hc11_bhi(); + void hc11_bne(); + void hc11_ble(); + void hc11_bls(); + void hc11_bmi(); + void hc11_bpl(); + void hc11_bra(); + void hc11_brclr_dir(); + void hc11_brclr_indx(); + void hc11_brset_dir(); + void hc11_brset_indx(); + void hc11_brn(); + void hc11_bset_dir(); + void hc11_bset_indx(); + void hc11_bsr(); + void hc11_bvc(); + void hc11_bvs(); + void hc11_cba(); + void hc11_clc(); + void hc11_cli(); + void hc11_clra(); + void hc11_clrb(); + void hc11_clr_ext(); + void hc11_clr_indx(); + void hc11_clr_indy(); + void hc11_clv(); + void hc11_cmpa_imm(); + void hc11_cmpa_dir(); + void hc11_cmpa_ext(); + void hc11_cmpa_indx(); + void hc11_cmpa_indy(); + void hc11_cmpb_imm(); + void hc11_cmpb_dir(); + void hc11_cmpb_ext(); + void hc11_cmpb_indx(); + void hc11_cmpb_indy(); + void hc11_coma(); + void hc11_comb(); + void hc11_cpd_imm(); + void hc11_cpd_dir(); + void hc11_cpd_ext(); + void hc11_cpd_indx(); + void hc11_cpd_indy(); + void hc11_cpx_imm(); + void hc11_cpx_dir(); + void hc11_cpx_ext(); + void hc11_cpx_indx(); + void hc11_cpx_indy(); + void hc11_cpy_imm(); + void hc11_cpy_dir(); + void hc11_cpy_ext(); + void hc11_cpy_indx(); + void hc11_cpy_indy(); + void hc11_deca(); + void hc11_decb(); + void hc11_dec_ext(); + void hc11_dec_indx(); + void hc11_dec_indy(); + void hc11_dex(); + void hc11_dey(); + void hc11_eora_imm(); + void hc11_eora_dir(); + void hc11_eora_ext(); + void hc11_eora_indx(); + void hc11_eora_indy(); + void hc11_eorb_imm(); + void hc11_eorb_dir(); + void hc11_eorb_ext(); + void hc11_eorb_indx(); + void hc11_eorb_indy(); + void hc11_idiv(); + void hc11_inca(); + void hc11_incb(); + void hc11_inc_ext(); + void hc11_inc_indx(); + void hc11_inc_indy(); + void hc11_inx(); + void hc11_iny(); + void hc11_jmp_indx(); + void hc11_jmp_indy(); + void hc11_jmp_ext(); + void hc11_jsr_dir(); + void hc11_jsr_ext(); + void hc11_jsr_indx(); + void hc11_jsr_indy(); + void hc11_ldaa_imm(); + void hc11_ldaa_dir(); + void hc11_ldaa_ext(); + void hc11_ldaa_indx(); + void hc11_ldaa_indy(); + void hc11_ldab_imm(); + void hc11_ldab_dir(); + void hc11_ldab_ext(); + void hc11_ldab_indx(); + void hc11_ldab_indy(); + void hc11_ldd_imm(); + void hc11_ldd_dir(); + void hc11_ldd_ext(); + void hc11_ldd_indx(); + void hc11_ldd_indy(); + void hc11_lds_imm(); + void hc11_lds_dir(); + void hc11_lds_ext(); + void hc11_lds_indx(); + void hc11_lds_indy(); + void hc11_ldx_imm(); + void hc11_ldx_dir(); + void hc11_ldx_ext(); + void hc11_ldx_indx(); + void hc11_ldx_indy(); + void hc11_ldy_imm(); + void hc11_ldy_dir(); + void hc11_ldy_ext(); + void hc11_ldy_indx(); + void hc11_ldy_indy(); + void hc11_lsld(); + void hc11_lsra(); + void hc11_lsrb(); + void hc11_lsrd(); + void hc11_mul(); + void hc11_nega(); + void hc11_negb(); + void hc11_neg_ext(); + void hc11_neg_indx(); + void hc11_neg_indy(); + void hc11_nop(); + void hc11_psha(); + void hc11_oraa_imm(); + void hc11_oraa_dir(); + void hc11_oraa_ext(); + void hc11_oraa_indx(); + void hc11_oraa_indy(); + void hc11_orab_imm(); + void hc11_orab_dir(); + void hc11_orab_ext(); + void hc11_orab_indx(); + void hc11_orab_indy(); + void hc11_pshb(); + void hc11_pshx(); + void hc11_pshy(); + void hc11_pula(); + void hc11_pulb(); + void hc11_pulx(); + void hc11_puly(); + void hc11_rola(); + void hc11_rolb(); + void hc11_rol_ext(); + void hc11_rol_indx(); + void hc11_rol_indy(); + void hc11_rora(); + void hc11_rorb(); + void hc11_rti(); + void hc11_rts(); + void hc11_sba(); + void hc11_sbca_imm(); + void hc11_sbca_indx(); + void hc11_sbca_indy(); + void hc11_sbcb_imm(); + void hc11_sbcb_indx(); + void hc11_sbcb_indy(); + void hc11_sec(); + void hc11_sei(); + void hc11_sev(); + void hc11_staa_dir(); + void hc11_staa_ext(); + void hc11_staa_indx(); + void hc11_staa_indy(); + void hc11_stab_dir(); + void hc11_stab_ext(); + void hc11_stab_indx(); + void hc11_stab_indy(); + void hc11_std_dir(); + void hc11_std_ext(); + void hc11_std_indx(); + void hc11_std_indy(); + void hc11_sts_dir(); + void hc11_stx_dir(); + void hc11_stx_ext(); + void hc11_stx_indx(); + void hc11_stx_indy(); + void hc11_sty_dir(); + void hc11_sty_ext(); + void hc11_sty_indx(); + void hc11_sty_indy(); + void hc11_stop(); + void hc11_suba_imm(); + void hc11_suba_dir(); + void hc11_suba_ext(); + void hc11_suba_indx(); + void hc11_suba_indy(); + void hc11_subb_imm(); + void hc11_subb_dir(); + void hc11_subb_ext(); + void hc11_subb_indx(); + void hc11_subb_indy(); + void hc11_subd_imm(); + void hc11_subd_dir(); + void hc11_subd_ext(); + void hc11_subd_indx(); + void hc11_subd_indy(); + void hc11_swi(); + void hc11_tab(); + void hc11_tap(); + void hc11_tba(); + void hc11_test(); + void hc11_tpa(); + void hc11_tsta(); + void hc11_tstb(); + void hc11_tst_ext(); + void hc11_tst_indx(); + void hc11_tst_indy(); + void hc11_tsx(); + void hc11_tsy(); + void hc11_txs(); + void hc11_tys(); + void hc11_wai(); + void hc11_xgdx(); + void hc11_xgdy(); + void hc11_page2(); + void hc11_page3(); + void hc11_page4(); + void hc11_invalid(); + void check_irq_lines(); +}; + + +#endif /* __MC68HC11_H__ */ diff --git a/src/devices/cpu/mcs48/mcs48.c b/src/devices/cpu/mcs48/mcs48.c new file mode 100644 index 00000000000..a24cf72f0d6 --- /dev/null +++ b/src/devices/cpu/mcs48/mcs48.c @@ -0,0 +1,1334 @@ +// license:BSD-3-Clause +// copyright-holders:Mirko Buffoni +/* +EA pin - defined by architecture, must implement: + 1 means external access, bypassing internal ROM + reimplement as a push, not a pull +T0 output clock +*/ + +/*************************************************************************** + + mcs48.c + + Intel MCS-48/UPI-41 Portable Emulator + + Copyright Mirko Buffoni + Based on the original work Copyright Dan Boris, an 8048 emulator + You are not allowed to distribute this software commercially + +**************************************************************************** + + Note that the default internal divisor for this chip is by 3 and + then again by 5, or by 15 total. + +**************************************************************************** + + Chip RAM ROM I/O + ---- --- --- --- + 8021 64 1k 21 (ROM, reduced instruction set) + + 8035 64 0 27 (external ROM) + 8048 64 1k 27 (ROM) + 8648 64 1k 27 (OTPROM) + 8748 64 1k 27 (EPROM) + 8884 64 1k + N7751 128 2k + + 8039 128 0 27 (external ROM) + 8049 128 2k 27 (ROM) + 8749 128 2k 27 (EPROM) + M58715 128 0 (external ROM) + +**************************************************************************** + + UPI-41/42 chips are MCS-48 derived, with some opcode changes: + + MCS-48 opcode UPI-41/42 opcode + ------------- ---------------- + 02: OUTL BUS,A OUT DBB,A + 08: INS BUS,A + 22: IN DBB,A + 75: ENT0 CLK + 80: MOVX A,@R0 + 81: MOVX A,@R1 + 86: JNI JOBF + 88: ORL BUS,#n + 90: MOVX @R0,A MOV STS,A + 91: MOVX @R1,A + 98: ANL BUS,#n + D6: JNIBF + E5: SEL MB0 EN DMA + F5: SEL MB1 EN FLAGS + + Chip numbers are similar to the MCS-48 series: + + Chip RAM ROM I/O + ---- --- --- --- + 8041 128 1k + 8741 128 1k (EPROM) + + 8042 256 2k + 8242 256 2k + 8242 256 2k + +***************************************************************************/ + +#include "emu.h" +#include "debugger.h" +#include "mcs48.h" + + +/*************************************************************************** + CONSTANTS +***************************************************************************/ + +/* timer/counter enable bits */ +#define TIMER_ENABLED 0x01 +#define COUNTER_ENABLED 0x02 + +/* flag bits */ +#define C_FLAG 0x80 +#define A_FLAG 0x40 +#define F_FLAG 0x20 +#define B_FLAG 0x10 + +/* status bits (UPI-41) */ +#define STS_F1 0x08 +#define STS_F0 0x04 +#define STS_IBF 0x02 +#define STS_OBF 0x01 + +/* port 2 bits (UPI-41) */ +#define P2_OBF 0x10 +#define P2_NIBF 0x20 +#define P2_DRQ 0x40 +#define P2_NDACK 0x80 + +/* enable bits (UPI-41) */ +#define ENABLE_FLAGS 0x01 +#define ENABLE_DMA 0x02 + +/* feature masks */ +#define MCS48_FEATURE 0x01 +#define UPI41_FEATURE 0x02 + + + +/*************************************************************************** + MACROS +***************************************************************************/ + +/* ROM is mapped to AS_PROGRAM */ +#define program_r(a) m_program->read_byte(a) + +/* RAM is mapped to AS_DATA */ +#define ram_r(a) m_data->read_byte(a) +#define ram_w(a,V) m_data->write_byte(a, V) + +/* ports are mapped to AS_IO */ +#define ext_r(a) m_io->read_byte(a) +#define ext_w(a,V) m_io->write_byte(a, V) +#define port_r(a) m_io->read_byte(MCS48_PORT_P0 + a) +#define port_w(a,V) m_io->write_byte(MCS48_PORT_P0 + a, V) +#define test_r(a) m_io->read_byte(MCS48_PORT_T0 + a) +#define test_w(a,V) m_io->write_byte(MCS48_PORT_T0 + a, V) +#define bus_r() m_io->read_byte(MCS48_PORT_BUS) +#define bus_w(V) m_io->write_byte(MCS48_PORT_BUS, V) +#define ea_r() m_io->read_byte(MCS48_PORT_EA) +#define prog_w(V) m_io->write_byte(MCS48_PORT_PROG, V) + +/* r0-r7 map to memory via the regptr */ +#define R0 m_regptr[0] +#define R1 m_regptr[1] +#define R2 m_regptr[2] +#define R3 m_regptr[3] +#define R4 m_regptr[4] +#define R5 m_regptr[5] +#define R6 m_regptr[6] +#define R7 m_regptr[7] + + + +const device_type I8021 = &device_creator; +const device_type I8022 = &device_creator; +const device_type I8035 = &device_creator; +const device_type I8048 = &device_creator; +const device_type I8648 = &device_creator; +const device_type I8748 = &device_creator; +const device_type I8039 = &device_creator; +const device_type I8049 = &device_creator; +const device_type I8749 = &device_creator; +const device_type I8040 = &device_creator; +const device_type I8050 = &device_creator; +const device_type I8041 = &device_creator; +const device_type I8741 = &device_creator; +const device_type I8042 = &device_creator; +const device_type I8242 = &device_creator; +const device_type I8742 = &device_creator; +const device_type MB8884 = &device_creator; +const device_type N7751 = &device_creator; +const device_type M58715 = &device_creator; + + +/*************************************************************************** + ADDRESS MAPS +***************************************************************************/ + +/* FIXME: the memory maps should probably support rom banking for EA */ +static ADDRESS_MAP_START(program_10bit, AS_PROGRAM, 8, mcs48_cpu_device) + AM_RANGE(0x000, 0x3ff) AM_ROM +ADDRESS_MAP_END + +static ADDRESS_MAP_START(program_11bit, AS_PROGRAM, 8, mcs48_cpu_device) + AM_RANGE(0x000, 0x7ff) AM_ROM +ADDRESS_MAP_END + +static ADDRESS_MAP_START(program_12bit, AS_PROGRAM, 8, mcs48_cpu_device) + AM_RANGE(0x000, 0xfff) AM_ROM +ADDRESS_MAP_END + +static ADDRESS_MAP_START(data_6bit, AS_DATA, 8, mcs48_cpu_device) + AM_RANGE(0x00, 0x3f) AM_RAM +ADDRESS_MAP_END + +static ADDRESS_MAP_START(data_7bit, AS_DATA, 8, mcs48_cpu_device) + AM_RANGE(0x00, 0x7f) AM_RAM +ADDRESS_MAP_END + +static ADDRESS_MAP_START(data_8bit, AS_DATA, 8, mcs48_cpu_device) + AM_RANGE(0x00, 0xff) AM_RAM +ADDRESS_MAP_END + + +mcs48_cpu_device::mcs48_cpu_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, int rom_size, int ram_size, UINT8 feature_mask) + : cpu_device(mconfig, type, name, tag, owner, clock, shortname, __FILE__) + , m_program_config("program", ENDIANNESS_LITTLE, 8, 12, 0 + , ( ( rom_size == 1024 ) ? ADDRESS_MAP_NAME(program_10bit) : ( ( rom_size == 2048 ) ? ADDRESS_MAP_NAME(program_11bit) : ( ( rom_size == 4096 ) ? ADDRESS_MAP_NAME(program_12bit) : NULL ) ) )) + , m_data_config("data", ENDIANNESS_LITTLE, 8, ( ( ram_size == 64 ) ? 6 : ( ( ram_size == 128 ) ? 7 : 8 ) ), 0 + , ( ( ram_size == 64 ) ? ADDRESS_MAP_NAME(data_6bit) : ( ( ram_size == 128 ) ? ADDRESS_MAP_NAME(data_7bit) : ADDRESS_MAP_NAME(data_8bit) ) )) + , m_io_config("io", ENDIANNESS_LITTLE, 8, 9, 0) + , m_psw(0) + , m_feature_mask(feature_mask) + , m_int_rom_size(rom_size) +{ + // Sanity checks + if ( ram_size != 64 && ram_size != 128 && ram_size != 256 ) + { + fatalerror("mcs48: Invalid RAM size\n"); + } + + if ( rom_size != 0 && rom_size != 1024 && rom_size != 2048 && rom_size != 4096 ) + { + fatalerror("mcs48: Invalid ROM size\n"); + } +} + +i8021_device::i8021_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : mcs48_cpu_device(mconfig, I8021, "I8021", tag, owner, clock, "i8021", 1024, 64) +{ +} + +i8022_device::i8022_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : mcs48_cpu_device(mconfig, I8022, "I8022", tag, owner, clock, "i8022", 2048, 128) +{ +} + +i8035_device::i8035_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : mcs48_cpu_device(mconfig, I8035, "I8035", tag, owner, clock, "i8035", 0, 64) +{ +} + +i8048_device::i8048_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : mcs48_cpu_device(mconfig, I8048, "I8048", tag, owner, clock, "i8048", 1024, 64) +{ +} + +i8648_device::i8648_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : mcs48_cpu_device(mconfig, I8648, "I8648", tag, owner, clock, "i8648", 1024, 64) +{ +} + +i8748_device::i8748_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : mcs48_cpu_device(mconfig, I8748, "I8748", tag, owner, clock, "i8748", 1024, 64) +{ +} + +i8039_device::i8039_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : mcs48_cpu_device(mconfig, I8039, "I8039", tag, owner, clock, "i8039", 0, 128) +{ +} + +i8049_device::i8049_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : mcs48_cpu_device(mconfig, I8049, "I8049", tag, owner, clock, "i8049", 2048, 128) +{ +} + +i8749_device::i8749_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : mcs48_cpu_device(mconfig, I8749, "I8749", tag, owner, clock, "i8749", 2048, 128) +{ +} + +i8040_device::i8040_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : mcs48_cpu_device(mconfig, I8040, "I8040", tag, owner, clock, "i8040", 0, 256) +{ +} + +i8050_device::i8050_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : mcs48_cpu_device(mconfig, I8050, "I8050", tag, owner, clock, "i8050", 4096, 256) +{ +} + +mb8884_device::mb8884_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : mcs48_cpu_device(mconfig, MB8884, "MB8884", tag, owner, clock, "mb8884", 0, 64) +{ +} + +n7751_device::n7751_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : mcs48_cpu_device(mconfig, N7751, "N7751", tag, owner, clock, "n7751", 1024, 64) +{ +} + +m58715_device::m58715_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : mcs48_cpu_device(mconfig, M58715, "M58715", tag, owner, clock, "m58715", 2048, 128) +{ +} + +upi41_cpu_device::upi41_cpu_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, int rom_size, int ram_size) + : mcs48_cpu_device(mconfig, type, name, tag, owner, clock, shortname, rom_size, ram_size, UPI41_FEATURE) +{ +} + +i8041_device::i8041_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : upi41_cpu_device(mconfig, I8041, "I8041", tag, owner, clock, "i8041", 1024, 128) +{ +} + +i8741_device::i8741_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : upi41_cpu_device(mconfig, I8741, "I8741", tag, owner, clock, "i8741", 1024, 128) +{ +} + +i8042_device::i8042_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : upi41_cpu_device(mconfig, I8042, "I8042", tag, owner, clock, "i8042", 2048, 256) +{ +} + +i8242_device::i8242_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : upi41_cpu_device(mconfig, I8242, "I8242", tag, owner, clock, "i8242", 2048, 256) +{ +} + +i8742_device::i8742_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : upi41_cpu_device(mconfig, I8742, "I8742", tag, owner, clock, "i8742", 2048, 256) +{ +} + + +offs_t mcs48_cpu_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( mcs48 ); + return CPU_DISASSEMBLE_NAME(mcs48)(this, buffer, pc, oprom, opram, options); +} + + +offs_t upi41_cpu_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( upi41 ); + return CPU_DISASSEMBLE_NAME(upi41)(this, buffer, pc, oprom, opram, options); +} + +/*************************************************************************** + INLINE FUNCTIONS +***************************************************************************/ + +/*------------------------------------------------- + opcode_fetch - fetch an opcode byte +-------------------------------------------------*/ + +UINT8 mcs48_cpu_device::opcode_fetch() +{ + return m_direct->read_byte(m_pc++); +} + + +/*------------------------------------------------- + argument_fetch - fetch an opcode argument + byte +-------------------------------------------------*/ + +UINT8 mcs48_cpu_device::argument_fetch() +{ + return m_direct->read_byte(m_pc++); +} + + +/*------------------------------------------------- + update_regptr - update the regptr member to + point to the appropriate register bank +-------------------------------------------------*/ + +void mcs48_cpu_device::update_regptr() +{ + m_regptr = (UINT8 *)m_data->get_write_ptr((m_psw & B_FLAG) ? 24 : 0); +} + + +/*------------------------------------------------- + push_pc_psw - push the m_pc and m_psw values onto + the stack +-------------------------------------------------*/ + +void mcs48_cpu_device::push_pc_psw() +{ + UINT8 sp = m_psw & 0x07; + ram_w(8 + 2*sp, m_pc); + ram_w(9 + 2*sp, ((m_pc >> 8) & 0x0f) | (m_psw & 0xf0)); + m_psw = (m_psw & 0xf8) | ((sp + 1) & 0x07); +} + + +/*------------------------------------------------- + pull_pc_psw - pull the PC and PSW values from + the stack +-------------------------------------------------*/ + +void mcs48_cpu_device::pull_pc_psw() +{ + UINT8 sp = (m_psw - 1) & 0x07; + m_pc = ram_r(8 + 2*sp); + m_pc |= ram_r(9 + 2*sp) << 8; + m_psw = ((m_pc >> 8) & 0xf0) | 0x08 | sp; + m_pc &= 0xfff; + update_regptr(); +} + + +/*------------------------------------------------- + pull_pc - pull the PC value from the stack, + leaving the upper part of PSW intact +-------------------------------------------------*/ + +void mcs48_cpu_device::pull_pc() +{ + UINT8 sp = (m_psw - 1) & 0x07; + m_pc = ram_r(8 + 2*sp); + m_pc |= ram_r(9 + 2*sp) << 8; + m_pc &= 0xfff; + m_psw = (m_psw & 0xf0) | 0x08 | sp; +} + + +/*------------------------------------------------- + execute_add - perform the logic of an ADD + instruction +-------------------------------------------------*/ + +void mcs48_cpu_device::execute_add(UINT8 dat) +{ + UINT16 temp = m_a + dat; + UINT16 temp4 = (m_a & 0x0f) + (dat & 0x0f); + + m_psw &= ~(C_FLAG | A_FLAG); + m_psw |= (temp4 << 2) & A_FLAG; + m_psw |= (temp >> 1) & C_FLAG; + m_a = temp; +} + + +/*------------------------------------------------- + execute_addc - perform the logic of an ADDC + instruction +-------------------------------------------------*/ + +void mcs48_cpu_device::execute_addc(UINT8 dat) +{ + UINT8 carryin = (m_psw & C_FLAG) >> 7; + UINT16 temp = m_a + dat + carryin; + UINT16 temp4 = (m_a & 0x0f) + (dat & 0x0f) + carryin; + + m_psw &= ~(C_FLAG | A_FLAG); + m_psw |= (temp4 << 2) & A_FLAG; + m_psw |= (temp >> 1) & C_FLAG; + m_a = temp; +} + + +/*------------------------------------------------- + execute_jmp - perform the logic of a JMP + instruction +-------------------------------------------------*/ + +void mcs48_cpu_device::execute_jmp(UINT16 address) +{ + UINT16 a11 = (m_irq_in_progress) ? 0 : m_a11; + m_pc = address | a11; +} + + +/*------------------------------------------------- + execute_call - perform the logic of a CALL + instruction +-------------------------------------------------*/ + +void mcs48_cpu_device::execute_call(UINT16 address) +{ + push_pc_psw(); + execute_jmp(address); +} + + +/*------------------------------------------------- + execute_jcc - perform the logic of a + conditional jump instruction +-------------------------------------------------*/ + +void mcs48_cpu_device::execute_jcc(UINT8 result) +{ + UINT8 offset = argument_fetch(); + if (result != 0) + m_pc = ((m_pc - 1) & 0xf00) | offset; +} + + +/*------------------------------------------------- + p2_mask - return the mask of bits that the + code can directly affect +-------------------------------------------------*/ + +UINT8 mcs48_cpu_device::p2_mask() +{ + UINT8 result = 0xff; + if ((m_feature_mask & UPI41_FEATURE) == 0) + return result; + if (m_flags_enabled) + result &= ~(P2_OBF | P2_NIBF); + if (m_dma_enabled) + result &= ~(P2_DRQ | P2_NDACK); + return result; +} + + +/*------------------------------------------------- + expander_operation - perform an operation via + the 8243 expander chip +-------------------------------------------------*/ + +void mcs48_cpu_device::expander_operation(UINT8 operation, UINT8 port) +{ + /* put opcode/data on low 4 bits of P2 */ + port_w(2, m_p2 = (m_p2 & 0xf0) | (operation << 2) | (port & 3)); + + /* generate high-to-low transition on PROG line */ + prog_w(0); + + /* put data on low 4 bits of P2 */ + if (operation != 0) + port_w(2, m_p2 = (m_p2 & 0xf0) | (m_a & 0x0f)); + else + m_a = port_r(2) | 0x0f; + + /* generate low-to-high transition on PROG line */ + prog_w(1); +} + + + +/*************************************************************************** + OPCODE HANDLERS +***************************************************************************/ + +#define OPHANDLER(_name) int mcs48_cpu_device::_name() + +#define SPLIT_OPHANDLER(_name, _mcs48name, _upi41name) \ +OPHANDLER(_name) { return (!(m_feature_mask & UPI41_FEATURE)) ? _mcs48name() : _upi41name(); } + + +OPHANDLER( illegal ) +{ + logerror("MCS-48 PC:%04X - Illegal opcode = %02x\n", m_pc - 1, program_r(m_pc - 1)); + return 1; +} + +OPHANDLER( add_a_r0 ) { execute_add(R0); return 1; } +OPHANDLER( add_a_r1 ) { execute_add(R1); return 1; } +OPHANDLER( add_a_r2 ) { execute_add(R2); return 1; } +OPHANDLER( add_a_r3 ) { execute_add(R3); return 1; } +OPHANDLER( add_a_r4 ) { execute_add(R4); return 1; } +OPHANDLER( add_a_r5 ) { execute_add(R5); return 1; } +OPHANDLER( add_a_r6 ) { execute_add(R6); return 1; } +OPHANDLER( add_a_r7 ) { execute_add(R7); return 1; } +OPHANDLER( add_a_xr0 ) { execute_add(ram_r(R0)); return 1; } +OPHANDLER( add_a_xr1 ) { execute_add(ram_r(R1)); return 1; } +OPHANDLER( add_a_n ) { execute_add(argument_fetch()); return 2; } + +OPHANDLER( adc_a_r0 ) { execute_addc(R0); return 1; } +OPHANDLER( adc_a_r1 ) { execute_addc(R1); return 1; } +OPHANDLER( adc_a_r2 ) { execute_addc(R2); return 1; } +OPHANDLER( adc_a_r3 ) { execute_addc(R3); return 1; } +OPHANDLER( adc_a_r4 ) { execute_addc(R4); return 1; } +OPHANDLER( adc_a_r5 ) { execute_addc(R5); return 1; } +OPHANDLER( adc_a_r6 ) { execute_addc(R6); return 1; } +OPHANDLER( adc_a_r7 ) { execute_addc(R7); return 1; } +OPHANDLER( adc_a_xr0 ) { execute_addc(ram_r(R0)); return 1; } +OPHANDLER( adc_a_xr1 ) { execute_addc(ram_r(R1)); return 1; } +OPHANDLER( adc_a_n ) { execute_addc(argument_fetch()); return 2; } + +OPHANDLER( anl_a_r0 ) { m_a &= R0; return 1; } +OPHANDLER( anl_a_r1 ) { m_a &= R1; return 1; } +OPHANDLER( anl_a_r2 ) { m_a &= R2; return 1; } +OPHANDLER( anl_a_r3 ) { m_a &= R3; return 1; } +OPHANDLER( anl_a_r4 ) { m_a &= R4; return 1; } +OPHANDLER( anl_a_r5 ) { m_a &= R5; return 1; } +OPHANDLER( anl_a_r6 ) { m_a &= R6; return 1; } +OPHANDLER( anl_a_r7 ) { m_a &= R7; return 1; } +OPHANDLER( anl_a_xr0 ) { m_a &= ram_r(R0); return 1; } +OPHANDLER( anl_a_xr1 ) { m_a &= ram_r(R1); return 1; } +OPHANDLER( anl_a_n ) { m_a &= argument_fetch(); return 2; } + +OPHANDLER( anl_bus_n ) { bus_w(bus_r() & argument_fetch()); return 2; } +OPHANDLER( anl_p1_n ) { port_w(1, m_p1 &= argument_fetch()); return 2; } +OPHANDLER( anl_p2_n ) { port_w(2, m_p2 &= argument_fetch() | ~p2_mask()); return 2; } +OPHANDLER( anld_p4_a ) { expander_operation(MCS48_EXPANDER_OP_AND, 4); return 2; } +OPHANDLER( anld_p5_a ) { expander_operation(MCS48_EXPANDER_OP_AND, 5); return 2; } +OPHANDLER( anld_p6_a ) { expander_operation(MCS48_EXPANDER_OP_AND, 6); return 2; } +OPHANDLER( anld_p7_a ) { expander_operation(MCS48_EXPANDER_OP_AND, 7); return 2; } + +OPHANDLER( call_0 ) { execute_call(argument_fetch() | 0x000); return 2; } +OPHANDLER( call_1 ) { execute_call(argument_fetch() | 0x100); return 2; } +OPHANDLER( call_2 ) { execute_call(argument_fetch() | 0x200); return 2; } +OPHANDLER( call_3 ) { execute_call(argument_fetch() | 0x300); return 2; } +OPHANDLER( call_4 ) { execute_call(argument_fetch() | 0x400); return 2; } +OPHANDLER( call_5 ) { execute_call(argument_fetch() | 0x500); return 2; } +OPHANDLER( call_6 ) { execute_call(argument_fetch() | 0x600); return 2; } +OPHANDLER( call_7 ) { execute_call(argument_fetch() | 0x700); return 2; } + +OPHANDLER( clr_a ) { m_a = 0; return 1; } +OPHANDLER( clr_c ) { m_psw &= ~C_FLAG; return 1; } +OPHANDLER( clr_f0 ) { m_psw &= ~F_FLAG; m_sts &= ~STS_F0; return 1; } +OPHANDLER( clr_f1 ) { m_sts &= ~STS_F1; return 1; } + +OPHANDLER( cpl_a ) { m_a ^= 0xff; return 1; } +OPHANDLER( cpl_c ) { m_psw ^= C_FLAG; return 1; } +OPHANDLER( cpl_f0 ) { m_psw ^= F_FLAG; m_sts ^= STS_F0; return 1; } +OPHANDLER( cpl_f1 ) { m_sts ^= STS_F1; return 1; } + +OPHANDLER( da_a ) +{ + if ((m_a & 0x0f) > 0x09 || (m_psw & A_FLAG)) + { + m_a += 0x06; + if ((m_a & 0xf0) == 0x00) + m_psw |= C_FLAG; + } + if ((m_a & 0xf0) > 0x90 || (m_psw & C_FLAG)) + { + m_a += 0x60; + m_psw |= C_FLAG; + } + else + m_psw &= ~C_FLAG; + return 1; +} + +OPHANDLER( dec_a ) { m_a--; return 1; } +OPHANDLER( dec_r0 ) { R0--; return 1; } +OPHANDLER( dec_r1 ) { R1--; return 1; } +OPHANDLER( dec_r2 ) { R2--; return 1; } +OPHANDLER( dec_r3 ) { R3--; return 1; } +OPHANDLER( dec_r4 ) { R4--; return 1; } +OPHANDLER( dec_r5 ) { R5--; return 1; } +OPHANDLER( dec_r6 ) { R6--; return 1; } +OPHANDLER( dec_r7 ) { R7--; return 1; } + +OPHANDLER( dis_i ) { m_xirq_enabled = FALSE; return 1; } +OPHANDLER( dis_tcnti ) { m_tirq_enabled = FALSE; m_timer_overflow = FALSE; return 1; } + +OPHANDLER( djnz_r0 ) { execute_jcc(--R0 != 0); return 2; } +OPHANDLER( djnz_r1 ) { execute_jcc(--R1 != 0); return 2; } +OPHANDLER( djnz_r2 ) { execute_jcc(--R2 != 0); return 2; } +OPHANDLER( djnz_r3 ) { execute_jcc(--R3 != 0); return 2; } +OPHANDLER( djnz_r4 ) { execute_jcc(--R4 != 0); return 2; } +OPHANDLER( djnz_r5 ) { execute_jcc(--R5 != 0); return 2; } +OPHANDLER( djnz_r6 ) { execute_jcc(--R6 != 0); return 2; } +OPHANDLER( djnz_r7 ) { execute_jcc(--R7 != 0); return 2; } + +OPHANDLER( en_i ) { m_xirq_enabled = TRUE; return 1 + check_irqs(); } +OPHANDLER( en_tcnti ) { m_tirq_enabled = TRUE; return 1 + check_irqs(); } +OPHANDLER( en_dma ) { m_dma_enabled = TRUE; port_w(2, m_p2); return 1; } +OPHANDLER( en_flags ) { m_flags_enabled = TRUE; port_w(2, m_p2); return 1; } +OPHANDLER( ent0_clk ) +{ + logerror("MCS-48 PC:%04X - Unimplemented opcode = %02x\n", m_pc - 1, program_r(m_pc - 1)); + return 1; +} + +OPHANDLER( in_a_p1 ) { m_a = port_r(1) & m_p1; return 2; } +OPHANDLER( in_a_p2 ) { m_a = port_r(2) & m_p2; return 2; } +OPHANDLER( ins_a_bus ) { m_a = bus_r(); return 2; } +OPHANDLER( in_a_dbb ) +{ + /* acknowledge the IBF IRQ and clear the bit in STS */ + if ((m_sts & STS_IBF) != 0) + standard_irq_callback(UPI41_INPUT_IBF); + m_sts &= ~STS_IBF; + + /* if P2 flags are enabled, update the state of P2 */ + if (m_flags_enabled && (m_p2 & P2_NIBF) == 0) + port_w(2, m_p2 |= P2_NIBF); + m_a = m_dbbi; + return 2; +} + +OPHANDLER( inc_a ) { m_a++; return 1; } +OPHANDLER( inc_r0 ) { R0++; return 1; } +OPHANDLER( inc_r1 ) { R1++; return 1; } +OPHANDLER( inc_r2 ) { R2++; return 1; } +OPHANDLER( inc_r3 ) { R3++; return 1; } +OPHANDLER( inc_r4 ) { R4++; return 1; } +OPHANDLER( inc_r5 ) { R5++; return 1; } +OPHANDLER( inc_r6 ) { R6++; return 1; } +OPHANDLER( inc_r7 ) { R7++; return 1; } +OPHANDLER( inc_xr0 ) { ram_w(R0, ram_r(R0) + 1); return 1; } +OPHANDLER( inc_xr1 ) { ram_w(R1, ram_r(R1) + 1); return 1; } + +OPHANDLER( jb_0 ) { execute_jcc((m_a & 0x01) != 0); return 2; } +OPHANDLER( jb_1 ) { execute_jcc((m_a & 0x02) != 0); return 2; } +OPHANDLER( jb_2 ) { execute_jcc((m_a & 0x04) != 0); return 2; } +OPHANDLER( jb_3 ) { execute_jcc((m_a & 0x08) != 0); return 2; } +OPHANDLER( jb_4 ) { execute_jcc((m_a & 0x10) != 0); return 2; } +OPHANDLER( jb_5 ) { execute_jcc((m_a & 0x20) != 0); return 2; } +OPHANDLER( jb_6 ) { execute_jcc((m_a & 0x40) != 0); return 2; } +OPHANDLER( jb_7 ) { execute_jcc((m_a & 0x80) != 0); return 2; } +OPHANDLER( jc ) { execute_jcc((m_psw & C_FLAG) != 0); return 2; } +OPHANDLER( jf0 ) { execute_jcc((m_psw & F_FLAG) != 0); return 2; } +OPHANDLER( jf1 ) { execute_jcc((m_sts & STS_F1) != 0); return 2; } +OPHANDLER( jnc ) { execute_jcc((m_psw & C_FLAG) == 0); return 2; } +OPHANDLER( jni ) { execute_jcc(m_irq_state != 0); return 2; } +OPHANDLER( jnibf ) { execute_jcc((m_sts & STS_IBF) == 0); return 2; } +OPHANDLER( jnt_0 ) { execute_jcc(test_r(0) == 0); return 2; } +OPHANDLER( jnt_1 ) { execute_jcc(test_r(1) == 0); return 2; } +OPHANDLER( jnz ) { execute_jcc(m_a != 0); return 2; } +OPHANDLER( jobf ) { execute_jcc((m_sts & STS_OBF) != 0); return 2; } +OPHANDLER( jtf ) { execute_jcc(m_timer_flag); m_timer_flag = FALSE; return 2; } +OPHANDLER( jt_0 ) { execute_jcc(test_r(0) != 0); return 2; } +OPHANDLER( jt_1 ) { execute_jcc(test_r(1) != 0); return 2; } +OPHANDLER( jz ) { execute_jcc(m_a == 0); return 2; } + +OPHANDLER( jmp_0 ) { execute_jmp(argument_fetch() | 0x000); return 2; } +OPHANDLER( jmp_1 ) { execute_jmp(argument_fetch() | 0x100); return 2; } +OPHANDLER( jmp_2 ) { execute_jmp(argument_fetch() | 0x200); return 2; } +OPHANDLER( jmp_3 ) { execute_jmp(argument_fetch() | 0x300); return 2; } +OPHANDLER( jmp_4 ) { execute_jmp(argument_fetch() | 0x400); return 2; } +OPHANDLER( jmp_5 ) { execute_jmp(argument_fetch() | 0x500); return 2; } +OPHANDLER( jmp_6 ) { execute_jmp(argument_fetch() | 0x600); return 2; } +OPHANDLER( jmp_7 ) { execute_jmp(argument_fetch() | 0x700); return 2; } +OPHANDLER( jmpp_xa ) { m_pc &= 0xf00; m_pc |= program_r(m_pc | m_a); return 2; } + +OPHANDLER( mov_a_n ) { m_a = argument_fetch(); return 2; } +OPHANDLER( mov_a_psw ) { m_a = m_psw; return 1; } +OPHANDLER( mov_a_r0 ) { m_a = R0; return 1; } +OPHANDLER( mov_a_r1 ) { m_a = R1; return 1; } +OPHANDLER( mov_a_r2 ) { m_a = R2; return 1; } +OPHANDLER( mov_a_r3 ) { m_a = R3; return 1; } +OPHANDLER( mov_a_r4 ) { m_a = R4; return 1; } +OPHANDLER( mov_a_r5 ) { m_a = R5; return 1; } +OPHANDLER( mov_a_r6 ) { m_a = R6; return 1; } +OPHANDLER( mov_a_r7 ) { m_a = R7; return 1; } +OPHANDLER( mov_a_xr0 ) { m_a = ram_r(R0); return 1; } +OPHANDLER( mov_a_xr1 ) { m_a = ram_r(R1); return 1; } +OPHANDLER( mov_a_t ) { m_a = m_timer; return 1; } + +OPHANDLER( mov_psw_a ) { m_psw = m_a; update_regptr(); return 1; } +OPHANDLER( mov_sts_a ) { m_sts = (m_sts & 0x0f) | (m_a & 0xf0); return 1; } +OPHANDLER( mov_r0_a ) { R0 = m_a; return 1; } +OPHANDLER( mov_r1_a ) { R1 = m_a; return 1; } +OPHANDLER( mov_r2_a ) { R2 = m_a; return 1; } +OPHANDLER( mov_r3_a ) { R3 = m_a; return 1; } +OPHANDLER( mov_r4_a ) { R4 = m_a; return 1; } +OPHANDLER( mov_r5_a ) { R5 = m_a; return 1; } +OPHANDLER( mov_r6_a ) { R6 = m_a; return 1; } +OPHANDLER( mov_r7_a ) { R7 = m_a; return 1; } +OPHANDLER( mov_r0_n ) { R0 = argument_fetch(); return 2; } +OPHANDLER( mov_r1_n ) { R1 = argument_fetch(); return 2; } +OPHANDLER( mov_r2_n ) { R2 = argument_fetch(); return 2; } +OPHANDLER( mov_r3_n ) { R3 = argument_fetch(); return 2; } +OPHANDLER( mov_r4_n ) { R4 = argument_fetch(); return 2; } +OPHANDLER( mov_r5_n ) { R5 = argument_fetch(); return 2; } +OPHANDLER( mov_r6_n ) { R6 = argument_fetch(); return 2; } +OPHANDLER( mov_r7_n ) { R7 = argument_fetch(); return 2; } +OPHANDLER( mov_t_a ) { m_timer = m_a; return 1; } +OPHANDLER( mov_xr0_a ) { ram_w(R0, m_a); return 1; } +OPHANDLER( mov_xr1_a ) { ram_w(R1, m_a); return 1; } +OPHANDLER( mov_xr0_n ) { ram_w(R0, argument_fetch()); return 2; } +OPHANDLER( mov_xr1_n ) { ram_w(R1, argument_fetch()); return 2; } + +OPHANDLER( movd_a_p4 ) { expander_operation(MCS48_EXPANDER_OP_READ, 4); return 2; } +OPHANDLER( movd_a_p5 ) { expander_operation(MCS48_EXPANDER_OP_READ, 5); return 2; } +OPHANDLER( movd_a_p6 ) { expander_operation(MCS48_EXPANDER_OP_READ, 6); return 2; } +OPHANDLER( movd_a_p7 ) { expander_operation(MCS48_EXPANDER_OP_READ, 7); return 2; } +OPHANDLER( movd_p4_a ) { expander_operation(MCS48_EXPANDER_OP_WRITE, 4); return 2; } +OPHANDLER( movd_p5_a ) { expander_operation(MCS48_EXPANDER_OP_WRITE, 5); return 2; } +OPHANDLER( movd_p6_a ) { expander_operation(MCS48_EXPANDER_OP_WRITE, 6); return 2; } +OPHANDLER( movd_p7_a ) { expander_operation(MCS48_EXPANDER_OP_WRITE, 7); return 2; } + +OPHANDLER( movp_a_xa ) { m_a = program_r((m_pc & 0xf00) | m_a); return 2; } +OPHANDLER( movp3_a_xa ) { m_a = program_r(0x300 | m_a); return 2; } + +OPHANDLER( movx_a_xr0 ) { m_a = ext_r(R0); return 2; } +OPHANDLER( movx_a_xr1 ) { m_a = ext_r(R1); return 2; } +OPHANDLER( movx_xr0_a ) { ext_w(R0, m_a); return 2; } +OPHANDLER( movx_xr1_a ) { ext_w(R1, m_a); return 2; } + +OPHANDLER( nop ) { return 1; } + +OPHANDLER( orl_a_r0 ) { m_a |= R0; return 1; } +OPHANDLER( orl_a_r1 ) { m_a |= R1; return 1; } +OPHANDLER( orl_a_r2 ) { m_a |= R2; return 1; } +OPHANDLER( orl_a_r3 ) { m_a |= R3; return 1; } +OPHANDLER( orl_a_r4 ) { m_a |= R4; return 1; } +OPHANDLER( orl_a_r5 ) { m_a |= R5; return 1; } +OPHANDLER( orl_a_r6 ) { m_a |= R6; return 1; } +OPHANDLER( orl_a_r7 ) { m_a |= R7; return 1; } +OPHANDLER( orl_a_xr0 ) { m_a |= ram_r(R0); return 1; } +OPHANDLER( orl_a_xr1 ) { m_a |= ram_r(R1); return 1; } +OPHANDLER( orl_a_n ) { m_a |= argument_fetch(); return 2; } + +OPHANDLER( orl_bus_n ) { bus_w(bus_r() | argument_fetch()); return 2; } +OPHANDLER( orl_p1_n ) { port_w(1, m_p1 |= argument_fetch()); return 2; } +OPHANDLER( orl_p2_n ) { port_w(2, m_p2 |= argument_fetch() & p2_mask()); return 2; } +OPHANDLER( orld_p4_a ) { expander_operation(MCS48_EXPANDER_OP_OR, 4); return 2; } +OPHANDLER( orld_p5_a ) { expander_operation(MCS48_EXPANDER_OP_OR, 5); return 2; } +OPHANDLER( orld_p6_a ) { expander_operation(MCS48_EXPANDER_OP_OR, 6); return 2; } +OPHANDLER( orld_p7_a ) { expander_operation(MCS48_EXPANDER_OP_OR, 7); return 2; } + +OPHANDLER( outl_bus_a ) { bus_w(m_a); return 2; } +OPHANDLER( outl_p1_a ) { port_w(1, m_p1 = m_a); return 2; } +OPHANDLER( outl_p2_a ) { UINT8 mask = p2_mask(); port_w(2, m_p2 = (m_p2 & ~mask) | (m_a & mask)); return 2; } +OPHANDLER( out_dbb_a ) +{ + /* copy to the DBBO and update the bit in STS */ + m_dbbo = m_a; + m_sts |= STS_OBF; + + /* if P2 flags are enabled, update the state of P2 */ + if (m_flags_enabled && (m_p2 & P2_OBF) == 0) + port_w(2, m_p2 |= P2_OBF); + return 2; +} + + +OPHANDLER( ret ) { pull_pc(); return 2; } +OPHANDLER( retr ) +{ + pull_pc_psw(); + + /* implicitly clear the IRQ in progress flip flop and re-check interrupts */ + m_irq_in_progress = FALSE; + return 2 + check_irqs(); +} + +OPHANDLER( rl_a ) { m_a = (m_a << 1) | (m_a >> 7); return 1; } +OPHANDLER( rlc_a ) { UINT8 newc = m_a & C_FLAG; m_a = (m_a << 1) | (m_psw >> 7); m_psw = (m_psw & ~C_FLAG) | newc; return 1; } + +OPHANDLER( rr_a ) { m_a = (m_a >> 1) | (m_a << 7); return 1; } +OPHANDLER( rrc_a ) { UINT8 newc = (m_a << 7) & C_FLAG; m_a = (m_a >> 1) | (m_psw & C_FLAG); m_psw = (m_psw & ~C_FLAG) | newc; return 1; } + +OPHANDLER( sel_mb0 ) { m_a11 = 0x000; return 1; } +OPHANDLER( sel_mb1 ) { m_a11 = 0x800; return 1; } + +OPHANDLER( sel_rb0 ) { m_psw &= ~B_FLAG; update_regptr(); return 1; } +OPHANDLER( sel_rb1 ) { m_psw |= B_FLAG; update_regptr(); return 1; } + +OPHANDLER( stop_tcnt ) { m_timecount_enabled = 0; return 1; } + +OPHANDLER( strt_cnt ) { m_timecount_enabled = COUNTER_ENABLED; m_t1_history = test_r(1); return 1; } +OPHANDLER( strt_t ) { m_timecount_enabled = TIMER_ENABLED; m_prescaler = 0; return 1; } + +OPHANDLER( swap_a ) { m_a = (m_a << 4) | (m_a >> 4); return 1; } + +OPHANDLER( xch_a_r0 ) { UINT8 tmp = m_a; m_a = R0; R0 = tmp; return 1; } +OPHANDLER( xch_a_r1 ) { UINT8 tmp = m_a; m_a = R1; R1 = tmp; return 1; } +OPHANDLER( xch_a_r2 ) { UINT8 tmp = m_a; m_a = R2; R2 = tmp; return 1; } +OPHANDLER( xch_a_r3 ) { UINT8 tmp = m_a; m_a = R3; R3 = tmp; return 1; } +OPHANDLER( xch_a_r4 ) { UINT8 tmp = m_a; m_a = R4; R4 = tmp; return 1; } +OPHANDLER( xch_a_r5 ) { UINT8 tmp = m_a; m_a = R5; R5 = tmp; return 1; } +OPHANDLER( xch_a_r6 ) { UINT8 tmp = m_a; m_a = R6; R6 = tmp; return 1; } +OPHANDLER( xch_a_r7 ) { UINT8 tmp = m_a; m_a = R7; R7 = tmp; return 1; } +OPHANDLER( xch_a_xr0 ) { UINT8 tmp = m_a; m_a = ram_r(R0); ram_w(R0, tmp); return 1; } +OPHANDLER( xch_a_xr1 ) { UINT8 tmp = m_a; m_a = ram_r(R1); ram_w(R1, tmp); return 1; } + +OPHANDLER( xchd_a_xr0 ) { UINT8 oldram = ram_r(R0); ram_w(R0, (oldram & 0xf0) | (m_a & 0x0f)); m_a = (m_a & 0xf0) | (oldram & 0x0f); return 1; } +OPHANDLER( xchd_a_xr1 ) { UINT8 oldram = ram_r(R1); ram_w(R1, (oldram & 0xf0) | (m_a & 0x0f)); m_a = (m_a & 0xf0) | (oldram & 0x0f); return 1; } + +OPHANDLER( xrl_a_r0 ) { m_a ^= R0; return 1; } +OPHANDLER( xrl_a_r1 ) { m_a ^= R1; return 1; } +OPHANDLER( xrl_a_r2 ) { m_a ^= R2; return 1; } +OPHANDLER( xrl_a_r3 ) { m_a ^= R3; return 1; } +OPHANDLER( xrl_a_r4 ) { m_a ^= R4; return 1; } +OPHANDLER( xrl_a_r5 ) { m_a ^= R5; return 1; } +OPHANDLER( xrl_a_r6 ) { m_a ^= R6; return 1; } +OPHANDLER( xrl_a_r7 ) { m_a ^= R7; return 1; } +OPHANDLER( xrl_a_xr0 ) { m_a ^= ram_r(R0); return 1; } +OPHANDLER( xrl_a_xr1 ) { m_a ^= ram_r(R1); return 1; } +OPHANDLER( xrl_a_n ) { m_a ^= argument_fetch(); return 2; } + +SPLIT_OPHANDLER( split_02, outl_bus_a, out_dbb_a ) +SPLIT_OPHANDLER( split_08, ins_a_bus, illegal ) +SPLIT_OPHANDLER( split_22, illegal, in_a_dbb ) +SPLIT_OPHANDLER( split_75, ent0_clk, illegal ) +SPLIT_OPHANDLER( split_80, movx_a_xr0, illegal ) +SPLIT_OPHANDLER( split_81, movx_a_xr1, illegal ) +SPLIT_OPHANDLER( split_86, jni, jobf ) +SPLIT_OPHANDLER( split_88, orl_bus_n, illegal ) +SPLIT_OPHANDLER( split_90, movx_xr0_a, mov_sts_a ) +SPLIT_OPHANDLER( split_91, movx_xr1_a, illegal ) +SPLIT_OPHANDLER( split_98, anl_bus_n, illegal ) +SPLIT_OPHANDLER( split_d6, illegal, jnibf ) +SPLIT_OPHANDLER( split_e5, sel_mb0, en_dma ) +SPLIT_OPHANDLER( split_f5, sel_mb1, en_flags ) + + + +/*************************************************************************** + OPCODE TABLES +***************************************************************************/ + +#define OP(_a) &mcs48_cpu_device::_a + +const mcs48_cpu_device::mcs48_ophandler mcs48_cpu_device::s_opcode_table[256]= +{ + OP(nop), OP(illegal), OP(split_02), OP(add_a_n), OP(jmp_0), OP(en_i), OP(illegal), OP(dec_a), /* 00 */ + OP(split_08), OP(in_a_p1), OP(in_a_p2), OP(illegal), OP(movd_a_p4), OP(movd_a_p5), OP(movd_a_p6), OP(movd_a_p7), + OP(inc_xr0), OP(inc_xr1), OP(jb_0), OP(adc_a_n), OP(call_0), OP(dis_i), OP(jtf), OP(inc_a), /* 10 */ + OP(inc_r0), OP(inc_r1), OP(inc_r2), OP(inc_r3), OP(inc_r4), OP(inc_r5), OP(inc_r6), OP(inc_r7), + OP(xch_a_xr0), OP(xch_a_xr1), OP(split_22), OP(mov_a_n), OP(jmp_1), OP(en_tcnti), OP(jnt_0), OP(clr_a), /* 20 */ + OP(xch_a_r0), OP(xch_a_r1), OP(xch_a_r2), OP(xch_a_r3), OP(xch_a_r4), OP(xch_a_r5), OP(xch_a_r6), OP(xch_a_r7), + OP(xchd_a_xr0), OP(xchd_a_xr1), OP(jb_1), OP(illegal), OP(call_1), OP(dis_tcnti), OP(jt_0), OP(cpl_a), /* 30 */ + OP(illegal), OP(outl_p1_a), OP(outl_p2_a), OP(illegal), OP(movd_p4_a), OP(movd_p5_a), OP(movd_p6_a), OP(movd_p7_a), + OP(orl_a_xr0), OP(orl_a_xr1), OP(mov_a_t), OP(orl_a_n), OP(jmp_2), OP(strt_cnt), OP(jnt_1), OP(swap_a), /* 40 */ + OP(orl_a_r0), OP(orl_a_r1), OP(orl_a_r2), OP(orl_a_r3), OP(orl_a_r4), OP(orl_a_r5), OP(orl_a_r6), OP(orl_a_r7), + OP(anl_a_xr0), OP(anl_a_xr1), OP(jb_2), OP(anl_a_n), OP(call_2), OP(strt_t), OP(jt_1), OP(da_a), /* 50 */ + OP(anl_a_r0), OP(anl_a_r1), OP(anl_a_r2), OP(anl_a_r3), OP(anl_a_r4), OP(anl_a_r5), OP(anl_a_r6), OP(anl_a_r7), + OP(add_a_xr0), OP(add_a_xr1), OP(mov_t_a), OP(illegal), OP(jmp_3), OP(stop_tcnt), OP(illegal), OP(rrc_a), /* 60 */ + OP(add_a_r0), OP(add_a_r1), OP(add_a_r2), OP(add_a_r3), OP(add_a_r4), OP(add_a_r5), OP(add_a_r6), OP(add_a_r7), + OP(adc_a_xr0), OP(adc_a_xr1), OP(jb_3), OP(illegal), OP(call_3), OP(split_75), OP(jf1), OP(rr_a), /* 70 */ + OP(adc_a_r0), OP(adc_a_r1), OP(adc_a_r2), OP(adc_a_r3), OP(adc_a_r4), OP(adc_a_r5), OP(adc_a_r6), OP(adc_a_r7), + OP(split_80), OP(split_81), OP(illegal), OP(ret), OP(jmp_4), OP(clr_f0), OP(split_86), OP(illegal), /* 80 */ + OP(split_88), OP(orl_p1_n), OP(orl_p2_n), OP(illegal), OP(orld_p4_a), OP(orld_p5_a), OP(orld_p6_a), OP(orld_p7_a), + OP(split_90), OP(split_91), OP(jb_4), OP(retr), OP(call_4), OP(cpl_f0), OP(jnz), OP(clr_c), /* 90 */ + OP(split_98), OP(anl_p1_n), OP(anl_p2_n), OP(illegal), OP(anld_p4_a), OP(anld_p5_a), OP(anld_p6_a), OP(anld_p7_a), + OP(mov_xr0_a), OP(mov_xr1_a), OP(illegal), OP(movp_a_xa), OP(jmp_5), OP(clr_f1), OP(illegal), OP(cpl_c), /* A0 */ + OP(mov_r0_a), OP(mov_r1_a), OP(mov_r2_a), OP(mov_r3_a), OP(mov_r4_a), OP(mov_r5_a), OP(mov_r6_a), OP(mov_r7_a), + OP(mov_xr0_n), OP(mov_xr1_n), OP(jb_5), OP(jmpp_xa), OP(call_5), OP(cpl_f1), OP(jf0), OP(illegal), /* B0 */ + OP(mov_r0_n), OP(mov_r1_n), OP(mov_r2_n), OP(mov_r3_n), OP(mov_r4_n), OP(mov_r5_n), OP(mov_r6_n), OP(mov_r7_n), + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(jmp_6), OP(sel_rb0), OP(jz), OP(mov_a_psw), /* C0 */ + OP(dec_r0), OP(dec_r1), OP(dec_r2), OP(dec_r3), OP(dec_r4), OP(dec_r5), OP(dec_r6), OP(dec_r7), + OP(xrl_a_xr0), OP(xrl_a_xr1), OP(jb_6), OP(xrl_a_n), OP(call_6), OP(sel_rb1), OP(split_d6), OP(mov_psw_a), /* D0 */ + OP(xrl_a_r0), OP(xrl_a_r1), OP(xrl_a_r2), OP(xrl_a_r3), OP(xrl_a_r4), OP(xrl_a_r5), OP(xrl_a_r6), OP(xrl_a_r7), + OP(illegal), OP(illegal), OP(illegal), OP(movp3_a_xa),OP(jmp_7), OP(split_e5), OP(jnc), OP(rl_a), /* E0 */ + OP(djnz_r0), OP(djnz_r1), OP(djnz_r2), OP(djnz_r3), OP(djnz_r4), OP(djnz_r5), OP(djnz_r6), OP(djnz_r7), + OP(mov_a_xr0), OP(mov_a_xr1), OP(jb_7), OP(illegal), OP(call_7), OP(split_f5), OP(jc), OP(rlc_a), /* F0 */ + OP(mov_a_r0), OP(mov_a_r1), OP(mov_a_r2), OP(mov_a_r3), OP(mov_a_r4), OP(mov_a_r5), OP(mov_a_r6), OP(mov_a_r7) +}; + + + +/*************************************************************************** + INITIALIZATION/RESET +***************************************************************************/ + +/*------------------------------------------------- + mcs48_init - generic MCS-48 initialization +-------------------------------------------------*/ + +void mcs48_cpu_device::device_start() +{ + /* External access line + * EA=1 : read from external rom + * EA=0 : read from internal rom + */ + + m_a = 0; + m_timer = 0; + m_prescaler = 0; + m_t1_history = 0; + m_dbbi = 0; + m_dbbo = 0; + m_irq_state = 0; + + /* FIXME: Current implementation suboptimal */ + m_ea = (m_int_rom_size ? 0 : 1); + + m_program = &space(AS_PROGRAM); + m_direct = &m_program->direct(); + m_data = &space(AS_DATA); + m_io = &space(AS_IO); + + /* set up the state table */ + { + state_add(MCS48_PC, "PC", m_pc).mask(0xfff); + state_add(STATE_GENPC, "GENPC", m_pc).mask(0xfff).noshow(); + state_add(STATE_GENPCBASE, "GENPCBASE", m_prevpc).mask(0xfff).noshow(); + state_add(STATE_GENSP, "GENSP", m_psw).mask(0x7).noshow(); + state_add(STATE_GENFLAGS, "GENFLAGS", m_psw).noshow().formatstr("%10s"); + state_add(MCS48_A, "A", m_a); + state_add(MCS48_TC, "TC", m_timer); + state_add(MCS48_TPRE, "TPRE", m_prescaler).mask(0x1f); + state_add(MCS48_P1, "P1", m_p1); + state_add(MCS48_P2, "P2", m_p2); + + std::string tempstr; + for (int regnum = 0; regnum < 8; regnum++) { + strprintf(tempstr, "R%d", regnum); + state_add(MCS48_R0 + regnum, tempstr.c_str(), m_rtemp).callimport().callexport(); + } + state_add(MCS48_EA, "EA", m_ea).mask(0x1); + + if (m_feature_mask & UPI41_FEATURE) + { + state_add(MCS48_STS, "STS", m_sts); + state_add(MCS48_DBBI, "DBBI", m_dbbi); + state_add(MCS48_DBBO, "DBBO", m_dbbo); + } + + } + + /* ensure that regptr is valid before get_info gets called */ + update_regptr(); + + save_item(NAME(m_prevpc)); + save_item(NAME(m_pc)); + + save_item(NAME(m_a)); + save_item(NAME(m_psw)); + save_item(NAME(m_p1)); + save_item(NAME(m_p2)); + save_item(NAME(m_ea)); + save_item(NAME(m_timer)); + save_item(NAME(m_prescaler)); + save_item(NAME(m_t1_history)); + save_item(NAME(m_sts)); + save_item(NAME(m_dbbi)); + save_item(NAME(m_dbbo)); + + save_item(NAME(m_irq_state)); + save_item(NAME(m_irq_in_progress)); + save_item(NAME(m_timer_overflow)); + save_item(NAME(m_timer_flag)); + save_item(NAME(m_tirq_enabled)); + save_item(NAME(m_xirq_enabled)); + save_item(NAME(m_timecount_enabled)); + save_item(NAME(m_flags_enabled)); + save_item(NAME(m_dma_enabled)); + + save_item(NAME(m_a11)); + + m_icountptr = &m_icount; +} + + +void mcs48_cpu_device::device_reset() +{ + /* confirmed from reset description */ + m_pc = 0; + m_psw = (m_psw & (C_FLAG | A_FLAG)) | 0x08; + m_a11 = 0x000; + bus_w(0xff); + m_p1 = 0xff; + m_p2 = 0xff; + port_w(1, m_p1); + port_w(2, m_p2); + m_tirq_enabled = FALSE; + m_xirq_enabled = FALSE; + m_timecount_enabled = 0; + m_timer_flag = FALSE; + m_sts = 0; + m_flags_enabled = FALSE; + m_dma_enabled = FALSE; + + /* confirmed from interrupt logic description */ + m_irq_in_progress = FALSE; + m_timer_overflow = FALSE; +} + + + +/*************************************************************************** + EXECUTION +***************************************************************************/ + +/*------------------------------------------------- + check_irqs - check for and process IRQs +-------------------------------------------------*/ + +int mcs48_cpu_device::check_irqs() +{ + /* if something is in progress, we do nothing */ + if (m_irq_in_progress) + return 0; + + /* external interrupts take priority */ + if ((m_irq_state || (m_sts & STS_IBF) != 0) && m_xirq_enabled) + { + m_irq_in_progress = TRUE; + + /* transfer to location 0x03 */ + push_pc_psw(); + m_pc = 0x03; + + /* indicate we took the external IRQ */ + standard_irq_callback(0); + return 2; + } + + /* timer overflow interrupts follow */ + if (m_timer_overflow && m_tirq_enabled) + { + m_irq_in_progress = TRUE; + + /* transfer to location 0x07 */ + push_pc_psw(); + m_pc = 0x07; + + /* timer overflow flip-flop is reset once taken */ + m_timer_overflow = FALSE; + return 2; + } + return 0; +} + + +/*------------------------------------------------- + burn_cycles - burn cycles, processing timers + and counters +-------------------------------------------------*/ + +void mcs48_cpu_device::burn_cycles(int count) +{ + int timerover = FALSE; + + /* if the timer is enabled, accumulate prescaler cycles */ + if (m_timecount_enabled & TIMER_ENABLED) + { + UINT8 oldtimer = m_timer; + m_prescaler += count; + m_timer += m_prescaler >> 5; + m_prescaler &= 0x1f; + timerover = (oldtimer != 0 && m_timer == 0); + } + + /* if the counter is enabled, poll the T1 test input once for each cycle */ + else if (m_timecount_enabled & COUNTER_ENABLED) + for ( ; count > 0; count--) + { + m_t1_history = (m_t1_history << 1) | (test_r(1) & 1); + if ((m_t1_history & 3) == 2) + timerover = (++m_timer == 0); + } + + /* if either source caused a timer overflow, set the flags and check IRQs */ + if (timerover) + { + m_timer_flag = TRUE; + + /* according to the docs, if an overflow occurs with interrupts disabled, the overflow is not stored */ + if (m_tirq_enabled) + { + m_timer_overflow = TRUE; + check_irqs(); + } + } +} + + +/*------------------------------------------------- + mcs48_execute - execute until we run out + of cycles +-------------------------------------------------*/ + +void mcs48_cpu_device::execute_run() +{ + int curcycles; + + update_regptr(); + + /* external interrupts may have been set since we last checked */ + curcycles = check_irqs(); + m_icount -= curcycles; + if (m_timecount_enabled != 0) + burn_cycles(curcycles); + + /* iterate over remaining cycles, guaranteeing at least one instruction */ + do + { + unsigned opcode; + + /* fetch next opcode */ + m_prevpc = m_pc; + debugger_instruction_hook(this, m_pc); + opcode = opcode_fetch(); + + /* process opcode and count cycles */ + curcycles = (this->*s_opcode_table[opcode])(); + + /* burn the cycles */ + m_icount -= curcycles; + if (m_timecount_enabled != 0) + burn_cycles(curcycles); + + } while (m_icount > 0); +} + + + +/*************************************************************************** + DATA ACCESS HELPERS +***************************************************************************/ + +/*------------------------------------------------- + upi41_master_r - master CPU data/status + read +-------------------------------------------------*/ + +READ8_MEMBER( upi41_cpu_device::upi41_master_r ) +{ + /* if just reading the status, return it */ + if ((offset & 1) != 0) + return m_sts; + + /* if the output buffer was full, it gets cleared now */ + if (m_sts & STS_OBF) + { + m_sts &= ~STS_OBF; + if (m_flags_enabled) + port_w(2, m_p2 &= ~P2_OBF); + } + return m_dbbo; +} + + +/*------------------------------------------------- + upi41_master_w - master CPU command/data + write +-------------------------------------------------*/ + +TIMER_CALLBACK_MEMBER( upi41_cpu_device::master_callback ) +{ + UINT8 a0 = (param >> 8) & 1; + UINT8 data = param; + + /* data always goes to the input buffer */ + m_dbbi = data; + + /* set the appropriate flags */ + if ((m_sts & STS_IBF) == 0) + { + m_sts |= STS_IBF; + if (m_flags_enabled) + port_w(2, m_p2 &= ~P2_NIBF); + } + + /* set F1 accordingly */ + if (a0 == 0) + m_sts &= ~STS_F1; + else + m_sts |= STS_F1; +} + +WRITE8_MEMBER( upi41_cpu_device::upi41_master_w ) +{ + machine().scheduler().synchronize(timer_expired_delegate(FUNC(upi41_cpu_device::master_callback), this), (offset << 8) | data); +} + + + +/*************************************************************************** + GENERAL CONTEXT ACCESS +***************************************************************************/ + +/*------------------------------------------------- + mcs48_import_state - import state from the + debugger into our internal format +-------------------------------------------------*/ + +void mcs48_cpu_device::state_import(const device_state_entry &entry) +{ + switch (entry.index()) + { + case MCS48_R0: + case MCS48_R1: + case MCS48_R2: + case MCS48_R3: + case MCS48_R4: + case MCS48_R5: + case MCS48_R6: + case MCS48_R7: + m_regptr[entry.index() - MCS48_R0] = m_rtemp; + break; + + default: + fatalerror("CPU_IMPORT_STATE(mcs48) called for unexpected value\n"); + } +} + + +/*------------------------------------------------- + mcs48_export_state - prepare state for + exporting to the debugger +-------------------------------------------------*/ + +void mcs48_cpu_device::state_export(const device_state_entry &entry) +{ + switch (entry.index()) + { + case MCS48_R0: + case MCS48_R1: + case MCS48_R2: + case MCS48_R3: + case MCS48_R4: + case MCS48_R5: + case MCS48_R6: + case MCS48_R7: + m_rtemp = m_regptr[entry.index() - MCS48_R0]; + break; + + default: + fatalerror("CPU_EXPORT_STATE(mcs48) called for unexpected value\n"); + } +} + +void mcs48_cpu_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + switch (entry.index()) + { + case STATE_GENFLAGS: + strprintf(str, "%c%c %c%c%c%c%c%c%c%c", + m_irq_state ? 'I':'.', + m_a11 ? 'M':'.', + m_psw & 0x80 ? 'C':'.', + m_psw & 0x40 ? 'A':'.', + m_psw & 0x20 ? 'F':'.', + m_psw & 0x10 ? 'B':'.', + m_psw & 0x08 ? '?':'.', + m_psw & 0x04 ? '4':'.', + m_psw & 0x02 ? '2':'.', + m_psw & 0x01 ? '1':'.'); + break; + } +} + + +void mcs48_cpu_device::execute_set_input(int inputnum, int state) +{ + switch( inputnum ) + { + case MCS48_INPUT_IRQ: + m_irq_state = (state != CLEAR_LINE); + break; + + case MCS48_INPUT_EA: + m_ea = (state != CLEAR_LINE); + break; + } +} diff --git a/src/devices/cpu/mcs48/mcs48.h b/src/devices/cpu/mcs48/mcs48.h new file mode 100644 index 00000000000..a8184bcbd34 --- /dev/null +++ b/src/devices/cpu/mcs48/mcs48.h @@ -0,0 +1,643 @@ +// license:BSD-3-Clause +// copyright-holders:Mirko Buffoni +/*************************************************************************** + + mcs48.c + + Intel MCS-48/UPI-41 Portable Emulator + + Copyright Mirko Buffoni + Based on the original work Copyright Dan Boris, an 8048 emulator + You are not allowed to distribute this software commercially + +***************************************************************************/ + +#pragma once + +#ifndef __MCS48_H__ +#define __MCS48_H__ + + + +/*************************************************************************** + CONSTANTS +***************************************************************************/ + +/* register access indexes */ +enum +{ + MCS48_PC, + MCS48_PSW, + MCS48_A, + MCS48_TC, + MCS48_TPRE, + MCS48_P1, + MCS48_P2, + MCS48_R0, + MCS48_R1, + MCS48_R2, + MCS48_R3, + MCS48_R4, + MCS48_R5, + MCS48_R6, + MCS48_R7, + MCS48_EA, + MCS48_STS, /* UPI-41 systems only */ + MCS48_DBBO, /* UPI-41 systems only */ + MCS48_DBBI, /* UPI-41 systems only */ + + MCS48_GENPC = STATE_GENPC, + MCS48_GENSP = STATE_GENSP, + MCS48_GENPCBASE = STATE_GENPCBASE +}; + + +/* I/O port access indexes */ +enum +{ + MCS48_INPUT_IRQ = 0, + UPI41_INPUT_IBF = 0, + MCS48_INPUT_EA +}; + + +/* special I/O space ports */ +enum +{ + MCS48_PORT_P0 = 0x100, /* Not used */ + MCS48_PORT_P1 = 0x101, + MCS48_PORT_P2 = 0x102, + MCS48_PORT_T0 = 0x110, + MCS48_PORT_T1 = 0x111, + MCS48_PORT_BUS = 0x120, + MCS48_PORT_PROG = 0x121 /* PROG line to 8243 expander */ +}; + + +/* 8243 expander operations */ +enum +{ + MCS48_EXPANDER_OP_READ = 0, + MCS48_EXPANDER_OP_WRITE = 1, + MCS48_EXPANDER_OP_OR = 2, + MCS48_EXPANDER_OP_AND = 3 +}; + + + +/*************************************************************************** + MACROS +***************************************************************************/ + +#define MCS48_LC_CLOCK(_L, _C) \ + (1 / (2 * 3.14159265358979323846 * sqrt(_L * _C))) + +#define MCS48_ALE_CLOCK(_clock) \ + attotime::from_hz(_clock/(3*5)) + +/* Official Intel MCS-48 parts */ +extern const device_type I8021; /* 1k internal ROM, 64 bytes internal RAM */ +extern const device_type I8022; /* 2k internal ROM, 128 bytes internal RAM */ +extern const device_type I8035; /* external ROM, 64 bytes internal RAM */ +extern const device_type I8048; /* 1k internal ROM, 64 bytes internal RAM */ +extern const device_type I8648; /* 1k internal OTP ROM, 64 bytes internal RAM */ +extern const device_type I8748; /* 1k internal EEPROM, 64 bytes internal RAM */ +extern const device_type I8039; /* external ROM, 128 bytes internal RAM */ +extern const device_type I8049; /* 2k internal ROM, 128 bytes internal RAM */ +extern const device_type I8749; /* 2k internal EEPROM, 128 bytes internal RAM */ +extern const device_type I8040; /* external ROM, 256 bytes internal RAM */ +extern const device_type I8050; /* 4k internal ROM, 256 bytes internal RAM */ + +/* Official Intel UPI-41 parts */ +extern const device_type I8041; /* 1k internal ROM, 128 bytes internal RAM */ +extern const device_type I8741; /* 1k internal EEPROM, 128 bytes internal RAM */ +extern const device_type I8042; /* 2k internal ROM, 256 bytes internal RAM */ +extern const device_type I8242; /* 2k internal ROM, 256 bytes internal RAM */ +extern const device_type I8742; /* 2k internal EEPROM, 256 bytes internal RAM */ + +/* Clones */ +extern const device_type MB8884; /* 8035 clone */ +extern const device_type N7751; /* 8048 clone */ +extern const device_type M58715; /* 8049 clone */ + + + +class mcs48_cpu_device : public cpu_device +{ +public: + // construction/destruction + mcs48_cpu_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, int rom_size, int ram_size, UINT8 feature_mask = 0); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_execute_interface overrides + virtual UINT64 execute_clocks_to_cycles(UINT64 clocks) const { return (clocks + 15 - 1) / 15; } + virtual UINT64 execute_cycles_to_clocks(UINT64 cycles) const { return (cycles * 15); } + virtual UINT32 execute_min_cycles() const { return 1; } + virtual UINT32 execute_max_cycles() const { return 3; } + virtual UINT32 execute_input_lines() const { return 2; } + virtual UINT32 execute_default_irq_vector() const { return MCS48_INPUT_IRQ; } + virtual void execute_run(); + virtual void execute_set_input(int inputnum, int state); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const + { + return (spacenum == AS_PROGRAM) ? &m_program_config : ( (spacenum == AS_IO) ? &m_io_config : ( (spacenum == AS_DATA) ? &m_data_config : NULL ) ); + } + + // device_state_interface overrides + virtual void state_import(const device_state_entry &entry); + virtual void state_export(const device_state_entry &entry); + void state_string_export(const device_state_entry &entry, std::string &str); + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const { return 1; } + virtual UINT32 disasm_max_opcode_bytes() const { return 2; } + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + +protected: + address_space_config m_program_config; + address_space_config m_data_config; + address_space_config m_io_config; + + UINT16 m_prevpc; /* 16-bit previous program counter */ + UINT16 m_pc; /* 16-bit program counter */ + + UINT8 m_a; /* 8-bit accumulator */ + UINT8 * m_regptr; /* pointer to r0-r7 */ + UINT8 m_psw; /* 8-bit psw */ + UINT8 m_p1; /* 8-bit latched port 1 */ + UINT8 m_p2; /* 8-bit latched port 2 */ + UINT8 m_ea; /* 1-bit latched ea input */ + UINT8 m_timer; /* 8-bit timer */ + UINT8 m_prescaler; /* 5-bit timer prescaler */ + UINT8 m_t1_history; /* 8-bit history of the T1 input */ + UINT8 m_sts; /* 8-bit status register (UPI-41 only, except for F1) */ + UINT8 m_dbbi; /* 8-bit input data buffer (UPI-41 only) */ + UINT8 m_dbbo; /* 8-bit output data buffer (UPI-41 only) */ + + UINT8 m_irq_state; /* TRUE if an IRQ is pending */ + UINT8 m_irq_in_progress; /* TRUE if an IRQ is in progress */ + UINT8 m_timer_overflow; /* TRUE on a timer overflow; cleared by taking interrupt */ + UINT8 m_timer_flag; /* TRUE on a timer overflow; cleared on JTF */ + UINT8 m_tirq_enabled; /* TRUE if the timer IRQ is enabled */ + UINT8 m_xirq_enabled; /* TRUE if the external IRQ is enabled */ + UINT8 m_timecount_enabled; /* bitmask of timer/counter enabled */ + UINT8 m_flags_enabled; /* TRUE if I/O flags have been enabled (UPI-41 only) */ + UINT8 m_dma_enabled; /* TRUE if DMA has been enabled (UPI-41 only) */ + + UINT16 m_a11; /* A11 value, either 0x000 or 0x800 */ + + int m_icount; + + /* Memory spaces */ + address_space *m_program; + direct_read_data *m_direct; + address_space *m_data; + address_space *m_io; + + UINT8 m_feature_mask; /* processor feature flags */ + UINT16 m_int_rom_size; /* internal rom size */ + + UINT8 m_rtemp; /* temporary for import/export */ + + typedef int (mcs48_cpu_device::*mcs48_ophandler)(); + static const mcs48_ophandler s_opcode_table[256]; + + UINT8 opcode_fetch(); + UINT8 argument_fetch(); + void update_regptr(); + void push_pc_psw(); + void pull_pc_psw(); + void pull_pc(); + void execute_add(UINT8 dat); + void execute_addc(UINT8 dat); + void execute_jmp(UINT16 address); + void execute_call(UINT16 address); + void execute_jcc(UINT8 result); + UINT8 p2_mask(); + void expander_operation(UINT8 operation, UINT8 port); + int check_irqs(); + void burn_cycles(int count); + + int illegal(); + int add_a_r0(); + int add_a_r1(); + int add_a_r2(); + int add_a_r3(); + int add_a_r4(); + int add_a_r5(); + int add_a_r6(); + int add_a_r7(); + int add_a_xr0(); + int add_a_xr1(); + int add_a_n(); + int adc_a_r0(); + int adc_a_r1(); + int adc_a_r2(); + int adc_a_r3(); + int adc_a_r4(); + int adc_a_r5(); + int adc_a_r6(); + int adc_a_r7(); + int adc_a_xr0(); + int adc_a_xr1(); + int adc_a_n(); + int anl_a_r0(); + int anl_a_r1(); + int anl_a_r2(); + int anl_a_r3(); + int anl_a_r4(); + int anl_a_r5(); + int anl_a_r6(); + int anl_a_r7(); + int anl_a_xr0(); + int anl_a_xr1(); + int anl_a_n(); + int anl_bus_n(); + int anl_p1_n(); + int anl_p2_n(); + int anld_p4_a(); + int anld_p5_a(); + int anld_p6_a(); + int anld_p7_a(); + int call_0(); + int call_1(); + int call_2(); + int call_3(); + int call_4(); + int call_5(); + int call_6(); + int call_7(); + int clr_a(); + int clr_c(); + int clr_f0(); + int clr_f1(); + int cpl_a(); + int cpl_c(); + int cpl_f0(); + int cpl_f1(); + int da_a(); + int dec_a(); + int dec_r0(); + int dec_r1(); + int dec_r2(); + int dec_r3(); + int dec_r4(); + int dec_r5(); + int dec_r6(); + int dec_r7(); + int dis_i(); + int dis_tcnti(); + int djnz_r0(); + int djnz_r1(); + int djnz_r2(); + int djnz_r3(); + int djnz_r4(); + int djnz_r5(); + int djnz_r6(); + int djnz_r7(); + int en_i(); + int en_tcnti(); + int en_dma(); + int en_flags(); + int ent0_clk(); + int in_a_p1(); + int in_a_p2(); + int ins_a_bus(); + int in_a_dbb(); + int inc_a(); + int inc_r0(); + int inc_r1(); + int inc_r2(); + int inc_r3(); + int inc_r4(); + int inc_r5(); + int inc_r6(); + int inc_r7(); + int inc_xr0(); + int inc_xr1(); + int jb_0(); + int jb_1(); + int jb_2(); + int jb_3(); + int jb_4(); + int jb_5(); + int jb_6(); + int jb_7(); + int jc(); + int jf0(); + int jf1(); + int jnc(); + int jni(); + int jnibf(); + int jnt_0(); + int jnt_1(); + int jnz(); + int jobf(); + int jtf(); + int jt_0(); + int jt_1(); + int jz(); + int jmp_0(); + int jmp_1(); + int jmp_2(); + int jmp_3(); + int jmp_4(); + int jmp_5(); + int jmp_6(); + int jmp_7(); + int jmpp_xa(); + int mov_a_n(); + int mov_a_psw(); + int mov_a_r0(); + int mov_a_r1(); + int mov_a_r2(); + int mov_a_r3(); + int mov_a_r4(); + int mov_a_r5(); + int mov_a_r6(); + int mov_a_r7(); + int mov_a_xr0(); + int mov_a_xr1(); + int mov_a_t(); + int mov_psw_a(); + int mov_sts_a(); + int mov_r0_a(); + int mov_r1_a(); + int mov_r2_a(); + int mov_r3_a(); + int mov_r4_a(); + int mov_r5_a(); + int mov_r6_a(); + int mov_r7_a(); + int mov_r0_n(); + int mov_r1_n(); + int mov_r2_n(); + int mov_r3_n(); + int mov_r4_n(); + int mov_r5_n(); + int mov_r6_n(); + int mov_r7_n(); + int mov_t_a(); + int mov_xr0_a(); + int mov_xr1_a(); + int mov_xr0_n(); + int mov_xr1_n(); + int movd_a_p4(); + int movd_a_p5(); + int movd_a_p6(); + int movd_a_p7(); + int movd_p4_a(); + int movd_p5_a(); + int movd_p6_a(); + int movd_p7_a(); + int movp_a_xa(); + int movp3_a_xa(); + int movx_a_xr0(); + int movx_a_xr1(); + int movx_xr0_a(); + int movx_xr1_a(); + int nop(); + int orl_a_r0(); + int orl_a_r1(); + int orl_a_r2(); + int orl_a_r3(); + int orl_a_r4(); + int orl_a_r5(); + int orl_a_r6(); + int orl_a_r7(); + int orl_a_xr0(); + int orl_a_xr1(); + int orl_a_n(); + int orl_bus_n(); + int orl_p1_n(); + int orl_p2_n(); + int orld_p4_a(); + int orld_p5_a(); + int orld_p6_a(); + int orld_p7_a(); + int outl_bus_a(); + int outl_p1_a(); + int outl_p2_a(); + int out_dbb_a(); + int ret(); + int retr(); + int rl_a(); + int rlc_a(); + int rr_a(); + int rrc_a(); + int sel_mb0(); + int sel_mb1(); + int sel_rb0(); + int sel_rb1(); + int stop_tcnt(); + int strt_cnt(); + int strt_t(); + int swap_a(); + int xch_a_r0(); + int xch_a_r1(); + int xch_a_r2(); + int xch_a_r3(); + int xch_a_r4(); + int xch_a_r5(); + int xch_a_r6(); + int xch_a_r7(); + int xch_a_xr0(); + int xch_a_xr1(); + int xchd_a_xr0(); + int xchd_a_xr1(); + int xrl_a_r0(); + int xrl_a_r1(); + int xrl_a_r2(); + int xrl_a_r3(); + int xrl_a_r4(); + int xrl_a_r5(); + int xrl_a_r6(); + int xrl_a_r7(); + int xrl_a_xr0(); + int xrl_a_xr1(); + int xrl_a_n(); + int split_02(); + int split_08(); + int split_22(); + int split_75(); + int split_80(); + int split_81(); + int split_86(); + int split_88(); + int split_90(); + int split_91(); + int split_98(); + int split_d6(); + int split_e5(); + int split_f5(); + +}; + +class i8021_device : public mcs48_cpu_device +{ +public: + // construction/destruction + i8021_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // device_execute_interface overrides + virtual UINT64 execute_clocks_to_cycles(UINT64 clocks) const { return (clocks + 30 - 1) / 30; } + virtual UINT64 execute_cycles_to_clocks(UINT64 cycles) const { return (cycles * 30); } +}; + +class i8022_device : public mcs48_cpu_device +{ +public: + // construction/destruction + i8022_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // device_execute_interface overrides + virtual UINT64 execute_clocks_to_cycles(UINT64 clocks) const { return (clocks + 30 - 1) / 30; } + virtual UINT64 execute_cycles_to_clocks(UINT64 cycles) const { return (cycles * 30); } +}; + +class i8035_device : public mcs48_cpu_device +{ +public: + // construction/destruction + i8035_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class i8048_device : public mcs48_cpu_device +{ +public: + // construction/destruction + i8048_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class i8648_device : public mcs48_cpu_device +{ +public: + // construction/destruction + i8648_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class i8748_device : public mcs48_cpu_device +{ +public: + // construction/destruction + i8748_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class i8039_device : public mcs48_cpu_device +{ +public: + // construction/destruction + i8039_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class i8049_device : public mcs48_cpu_device +{ +public: + // construction/destruction + i8049_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class i8749_device : public mcs48_cpu_device +{ +public: + // construction/destruction + i8749_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class i8040_device : public mcs48_cpu_device +{ +public: + // construction/destruction + i8040_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class i8050_device : public mcs48_cpu_device +{ +public: + // construction/destruction + i8050_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class mb8884_device : public mcs48_cpu_device +{ +public: + // construction/destruction + mb8884_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class n7751_device : public mcs48_cpu_device +{ +public: + // construction/destruction + n7751_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class m58715_device : public mcs48_cpu_device +{ +public: + // construction/destruction + m58715_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +class upi41_cpu_device : public mcs48_cpu_device +{ +public: + // construction/destruction + upi41_cpu_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, int rom_size, int ram_size); + + /* functions for talking to the input/output buffers on the UPI41-class chips */ + DECLARE_READ8_MEMBER(upi41_master_r); + DECLARE_WRITE8_MEMBER(upi41_master_w); + +protected: + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + + TIMER_CALLBACK_MEMBER( master_callback ); +}; + +class i8041_device : public upi41_cpu_device +{ +public: + // construction/destruction + i8041_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class i8741_device : public upi41_cpu_device +{ +public: + // construction/destruction + i8741_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class i8042_device : public upi41_cpu_device +{ +public: + // construction/destruction + i8042_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class i8242_device : public upi41_cpu_device +{ +public: + // construction/destruction + i8242_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class i8742_device : public upi41_cpu_device +{ +public: + // construction/destruction + i8742_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +#endif /* __MCS48_H__ */ diff --git a/src/devices/cpu/mcs48/mcs48dsm.c b/src/devices/cpu/mcs48/mcs48dsm.c new file mode 100644 index 00000000000..9e2a080430c --- /dev/null +++ b/src/devices/cpu/mcs48/mcs48dsm.c @@ -0,0 +1,313 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + mcs48dsm.c + + Simple MCS-48/UPI-41 disassembler. + Written by Aaron Giles + +***************************************************************************/ + +#include "emu.h" + + +static UINT32 common_dasm(device_t *device, char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, int upi41) +{ + const UINT8 *startram = opram; + UINT32 flags = 0; + + opram++; + switch (*oprom++) + { + case 0x00: sprintf(buffer, "nop"); break; + case 0x02: if (!upi41) + sprintf(buffer, "out bus,a"); + else + sprintf(buffer, "out dbb,a"); break; + case 0x03: sprintf(buffer, "add a,#$%02X", *opram++); break; + case 0x04: sprintf(buffer, "jmp $0%02X", *opram++); break; + case 0x05: sprintf(buffer, "en i"); break; + case 0x07: sprintf(buffer, "dec a"); break; + case 0x08: if (!upi41) + sprintf(buffer, "in a,bus"); + else + sprintf(buffer, "illegal"); break; + case 0x09: sprintf(buffer, "in a,p1"); break; + case 0x0a: sprintf(buffer, "in a,p2"); break; + case 0x0c: sprintf(buffer, "movd a,p4"); break; + case 0x0d: sprintf(buffer, "movd a,p5"); break; + case 0x0e: sprintf(buffer, "movd a,p6"); break; + case 0x0f: sprintf(buffer, "movd a,p7"); break; + case 0x10: sprintf(buffer, "inc @r0"); break; + case 0x11: sprintf(buffer, "inc @r1"); break; + case 0x12: sprintf(buffer, "jb0 $%03X", (pc & 0xf00) | *opram++); break; + case 0x13: sprintf(buffer, "addc a,#$%02X", *opram++); break; + case 0x14: sprintf(buffer, "call $0%02X", *opram++); flags = DASMFLAG_STEP_OVER; break; + case 0x15: sprintf(buffer, "dis i"); break; + case 0x16: sprintf(buffer, "jtf $%03X", (pc & 0xf00) | *opram++); break; + case 0x17: sprintf(buffer, "inc a"); break; + case 0x18: sprintf(buffer, "inc r0"); break; + case 0x19: sprintf(buffer, "inc r1"); break; + case 0x1a: sprintf(buffer, "inc r2"); break; + case 0x1b: sprintf(buffer, "inc r3"); break; + case 0x1c: sprintf(buffer, "inc r4"); break; + case 0x1d: sprintf(buffer, "inc r5"); break; + case 0x1e: sprintf(buffer, "inc r6"); break; + case 0x1f: sprintf(buffer, "inc r7"); break; + case 0x20: sprintf(buffer, "xch a,@r0"); break; + case 0x21: sprintf(buffer, "xch a,@r1"); break; + case 0x22: if (!upi41) + sprintf(buffer, "illegal"); + else + sprintf(buffer, "in a,dbb"); break; + case 0x23: sprintf(buffer, "mov a,#$%02X", *opram++); break; + case 0x24: sprintf(buffer, "jmp $1%02X", *opram++); break; + case 0x25: sprintf(buffer, "en tcnti"); break; + case 0x26: sprintf(buffer, "jnt0 $%03X", (pc & 0xf00) | *opram++); break; + case 0x27: sprintf(buffer, "clr a"); break; + case 0x28: sprintf(buffer, "xch a,r0"); break; + case 0x29: sprintf(buffer, "xch a,r1"); break; + case 0x2a: sprintf(buffer, "xch a,r2"); break; + case 0x2b: sprintf(buffer, "xch a,r3"); break; + case 0x2c: sprintf(buffer, "xch a,r4"); break; + case 0x2d: sprintf(buffer, "xch a,r5"); break; + case 0x2e: sprintf(buffer, "xch a,r6"); break; + case 0x2f: sprintf(buffer, "xch a,r7"); break; + case 0x30: sprintf(buffer, "xchd a,@r0"); break; + case 0x31: sprintf(buffer, "xchd a,@r1"); break; + case 0x32: sprintf(buffer, "jb1 $%03X", (pc & 0xf00) | *opram++); break; + case 0x34: sprintf(buffer, "call $1%02X", *opram++); flags = DASMFLAG_STEP_OVER; break; + case 0x35: sprintf(buffer, "dis tcnti"); break; + case 0x36: sprintf(buffer, "jt0 $%03X", (pc & 0xf00) | *opram++); break; + case 0x37: sprintf(buffer, "cpl a"); break; + case 0x39: sprintf(buffer, "outl p1,a"); break; + case 0x3a: sprintf(buffer, "outl p2,a"); break; + case 0x3c: sprintf(buffer, "movd p4,a"); break; + case 0x3d: sprintf(buffer, "movd p5,a"); break; + case 0x3e: sprintf(buffer, "movd p6,a"); break; + case 0x3f: sprintf(buffer, "movd p7,a"); break; + case 0x40: sprintf(buffer, "orl a,@r0"); break; + case 0x41: sprintf(buffer, "orl a,@r1"); break; + case 0x42: sprintf(buffer, "mov a,t"); break; + case 0x43: sprintf(buffer, "orl a,#$%02X", *opram++); break; + case 0x44: sprintf(buffer, "jmp $2%02X", *opram++); break; + case 0x45: sprintf(buffer, "strt cnt"); break; + case 0x46: sprintf(buffer, "jnt1 $%03X", (pc & 0xf00) | *opram++); break; + case 0x47: sprintf(buffer, "swap a"); break; + case 0x48: sprintf(buffer, "orl a,r0"); break; + case 0x49: sprintf(buffer, "orl a,r1"); break; + case 0x4a: sprintf(buffer, "orl a,r2"); break; + case 0x4b: sprintf(buffer, "orl a,r3"); break; + case 0x4c: sprintf(buffer, "orl a,r4"); break; + case 0x4d: sprintf(buffer, "orl a,r5"); break; + case 0x4e: sprintf(buffer, "orl a,r6"); break; + case 0x4f: sprintf(buffer, "orl a,r7"); break; + case 0x50: sprintf(buffer, "anl a,@r0"); break; + case 0x51: sprintf(buffer, "anl a,@r1"); break; + case 0x52: sprintf(buffer, "jb2 $%03X", (pc & 0xf00) | *opram++); break; + case 0x53: sprintf(buffer, "anl a,#$%02X", *opram++); break; + case 0x54: sprintf(buffer, "call $2%02X", *opram++); flags = DASMFLAG_STEP_OVER; break; + case 0x55: sprintf(buffer, "strt t"); break; + case 0x56: sprintf(buffer, "jt1 $%03X", (pc & 0xf00) | *opram++); break; + case 0x57: sprintf(buffer, "da a"); break; + case 0x58: sprintf(buffer, "anl a,r0"); break; + case 0x59: sprintf(buffer, "anl a,r1"); break; + case 0x5a: sprintf(buffer, "anl a,r2"); break; + case 0x5b: sprintf(buffer, "anl a,r3"); break; + case 0x5c: sprintf(buffer, "anl a,r4"); break; + case 0x5d: sprintf(buffer, "anl a,r5"); break; + case 0x5e: sprintf(buffer, "anl a,r6"); break; + case 0x5f: sprintf(buffer, "anl a,r7"); break; + case 0x60: sprintf(buffer, "add a,@r0"); break; + case 0x61: sprintf(buffer, "add a,@r1"); break; + case 0x62: sprintf(buffer, "mov t,a"); break; + case 0x64: sprintf(buffer, "jmp $3%02X", *opram++); break; + case 0x65: sprintf(buffer, "stop tcnt"); break; + case 0x67: sprintf(buffer, "rrc a"); break; + case 0x68: sprintf(buffer, "add a,r0"); break; + case 0x69: sprintf(buffer, "add a,r1"); break; + case 0x6a: sprintf(buffer, "add a,r2"); break; + case 0x6b: sprintf(buffer, "add a,r3"); break; + case 0x6c: sprintf(buffer, "add a,r4"); break; + case 0x6d: sprintf(buffer, "add a,r5"); break; + case 0x6e: sprintf(buffer, "add a,r6"); break; + case 0x6f: sprintf(buffer, "add a,r7"); break; + case 0x70: sprintf(buffer, "addc a,@r0"); break; + case 0x71: sprintf(buffer, "addc a,@r1"); break; + case 0x72: sprintf(buffer, "jb3 $%03X", (pc & 0xf00) | *opram++); break; + case 0x74: sprintf(buffer, "call $3%02X", *opram++); flags = DASMFLAG_STEP_OVER; break; + case 0x75: if (!upi41) + sprintf(buffer, "ent0 clk"); + else + sprintf(buffer, "illegal"); break; + case 0x76: sprintf(buffer, "jf1 $%03X", (pc & 0xf00) | *opram++); break; + case 0x77: sprintf(buffer, "rr a"); break; + case 0x78: sprintf(buffer, "addc a,r0"); break; + case 0x79: sprintf(buffer, "addc a,r1"); break; + case 0x7a: sprintf(buffer, "addc a,r2"); break; + case 0x7b: sprintf(buffer, "addc a,r3"); break; + case 0x7c: sprintf(buffer, "addc a,r4"); break; + case 0x7d: sprintf(buffer, "addc a,r5"); break; + case 0x7e: sprintf(buffer, "addc a,r6"); break; + case 0x7f: sprintf(buffer, "addc a,r7"); break; + case 0x80: if (!upi41) + sprintf(buffer, "movx a,@r0"); + else + sprintf(buffer, "illegal"); break; + case 0x81: if (!upi41) + sprintf(buffer, "movx a,@r1"); + else + sprintf(buffer, "illegal"); break; + case 0x83: sprintf(buffer, "ret"); flags = DASMFLAG_STEP_OUT; break; + case 0x84: sprintf(buffer, "jmp $4%02X", *opram++); break; + case 0x85: sprintf(buffer, "clr f0"); break; + case 0x86: if (!upi41) + sprintf(buffer, "jni $%03X", (pc & 0xf00) | *opram++); + else + sprintf(buffer, "jobf $%03X", (pc & 0xf00) | *opram++); break; + case 0x88: if (!upi41) + sprintf(buffer, "orl bus,#$%02X", *opram++); + else + sprintf(buffer, "illegal"); break; + case 0x89: sprintf(buffer, "orl p1,#$%02X", *opram++); break; + case 0x8a: sprintf(buffer, "orl p2,#$%02X", *opram++); break; + case 0x8c: sprintf(buffer, "orld p4,a"); break; + case 0x8d: sprintf(buffer, "orld p5,a"); break; + case 0x8e: sprintf(buffer, "orld p6,a"); break; + case 0x8f: sprintf(buffer, "orld p7,a"); break; + case 0x90: if (!upi41) + sprintf(buffer, "movx @r0,a"); + else + sprintf(buffer, "mov sts,a"); break; + case 0x91: if (!upi41) + sprintf(buffer, "movx @r1,a"); + else + sprintf(buffer, "illegal"); break; + case 0x92: sprintf(buffer, "jb4 $%03X", (pc & 0xf00) | *opram++); break; + case 0x93: sprintf(buffer, "retr"); flags = DASMFLAG_STEP_OUT; break; + case 0x94: sprintf(buffer, "call $4%02X", *opram++); flags = DASMFLAG_STEP_OVER; break; + case 0x95: sprintf(buffer, "cpl f0"); break; + case 0x96: sprintf(buffer, "jnz $%03X", (pc & 0xf00) | *opram++); break; + case 0x97: sprintf(buffer, "clr c"); break; + case 0x98: if (!upi41) + sprintf(buffer, "anl bus,#$%02X", *opram++); + else + sprintf(buffer, "illegal"); break; + case 0x99: sprintf(buffer, "anl p1,#$%02X", *opram++); break; + case 0x9a: sprintf(buffer, "anl p2,#$%02X", *opram++); break; + case 0x9c: sprintf(buffer, "anld p4,a"); break; + case 0x9d: sprintf(buffer, "anld p5,a"); break; + case 0x9e: sprintf(buffer, "anld p6,a"); break; + case 0x9f: sprintf(buffer, "anld p7,a"); break; + case 0xa0: sprintf(buffer, "mov @r0,a"); break; + case 0xa1: sprintf(buffer, "mov @r1,a"); break; + case 0xa3: sprintf(buffer, "movp a,@a"); break; + case 0xa4: sprintf(buffer, "jmp $5%02X", *opram++); break; + case 0xa5: sprintf(buffer, "clr f1"); break; + case 0xa7: sprintf(buffer, "cpl c"); break; + case 0xa8: sprintf(buffer, "mov r0,a"); break; + case 0xa9: sprintf(buffer, "mov r1,a"); break; + case 0xaa: sprintf(buffer, "mov r2,a"); break; + case 0xab: sprintf(buffer, "mov r3,a"); break; + case 0xac: sprintf(buffer, "mov r4,a"); break; + case 0xad: sprintf(buffer, "mov r5,a"); break; + case 0xae: sprintf(buffer, "mov r6,a"); break; + case 0xaf: sprintf(buffer, "mov r7,a"); break; + case 0xb0: sprintf(buffer, "mov @r0,#$%02X", *opram++); break; + case 0xb1: sprintf(buffer, "mov @r1,#$%02X", *opram++); break; + case 0xb2: sprintf(buffer, "jb5 $%03X", (pc & 0xf00) | *opram++); break; + case 0xb3: sprintf(buffer, "jmpp @a"); break; + case 0xb4: sprintf(buffer, "call $5%02X", *opram++); flags = DASMFLAG_STEP_OVER; break; + case 0xb5: sprintf(buffer, "cpl f1"); break; + case 0xb6: sprintf(buffer, "jf0 $%03X", (pc & 0xf00) | *opram++); break; + case 0xb8: sprintf(buffer, "mov r0,#$%02X", *opram++); break; + case 0xb9: sprintf(buffer, "mov r1,#$%02X", *opram++); break; + case 0xba: sprintf(buffer, "mov r2,#$%02X", *opram++); break; + case 0xbb: sprintf(buffer, "mov r3,#$%02X", *opram++); break; + case 0xbc: sprintf(buffer, "mov r4,#$%02X", *opram++); break; + case 0xbd: sprintf(buffer, "mov r5,#$%02X", *opram++); break; + case 0xbe: sprintf(buffer, "mov r6,#$%02X", *opram++); break; + case 0xbf: sprintf(buffer, "mov r7,#$%02X", *opram++); break; + case 0xc4: sprintf(buffer, "jmp $6%02X", *opram++); break; + case 0xc5: sprintf(buffer, "sel rb0"); break; + case 0xc6: sprintf(buffer, "jz $%03X", (pc & 0xf00) | *opram++); break; + case 0xc7: sprintf(buffer, "mov a,psw"); break; + case 0xc8: sprintf(buffer, "dec r0"); break; + case 0xc9: sprintf(buffer, "dec r1"); break; + case 0xca: sprintf(buffer, "dec r2"); break; + case 0xcb: sprintf(buffer, "dec r3"); break; + case 0xcc: sprintf(buffer, "dec r4"); break; + case 0xcd: sprintf(buffer, "dec r5"); break; + case 0xce: sprintf(buffer, "dec r6"); break; + case 0xcf: sprintf(buffer, "dec r7"); break; + case 0xd0: sprintf(buffer, "xrl a,@r0"); break; + case 0xd1: sprintf(buffer, "xrl a,@r1"); break; + case 0xd2: sprintf(buffer, "jb6 $%03X", (pc & 0xf00) | *opram++); break; + case 0xd3: sprintf(buffer, "xrl a,#$%02X", *opram++); break; + case 0xd4: sprintf(buffer, "call $6%02X", *opram++); flags = DASMFLAG_STEP_OVER; break; + case 0xd5: sprintf(buffer, "sel rb1"); break; + case 0xd6: if (!upi41) + sprintf(buffer, "illegal"); + else + sprintf(buffer, "jnibf $%03X", (pc & 0xf00) | *opram++); break; + case 0xd7: sprintf(buffer, "mov psw,a"); break; + case 0xd8: sprintf(buffer, "xrl a,r0"); break; + case 0xd9: sprintf(buffer, "xrl a,r1"); break; + case 0xda: sprintf(buffer, "xrl a,r2"); break; + case 0xdb: sprintf(buffer, "xrl a,r3"); break; + case 0xdc: sprintf(buffer, "xrl a,r4"); break; + case 0xdd: sprintf(buffer, "xrl a,r5"); break; + case 0xde: sprintf(buffer, "xrl a,r6"); break; + case 0xdf: sprintf(buffer, "xrl a,r7"); break; + case 0xe3: sprintf(buffer, "movp3 a,@a"); break; + case 0xe4: sprintf(buffer, "jmp $7%02X", *opram++); break; + case 0xe5: if (!upi41) + sprintf(buffer, "sel mb0"); + else + sprintf(buffer, "en dma"); break; + case 0xe6: sprintf(buffer, "jnc $%03X", (pc & 0xf00) | *opram++); break; + case 0xe7: sprintf(buffer, "rl a"); break; + case 0xe8: sprintf(buffer, "djnz r0,$%03X", (pc & 0xf00) | *opram++); flags = DASMFLAG_STEP_OVER; break; + case 0xe9: sprintf(buffer, "djnz r1,$%03X", (pc & 0xf00) | *opram++); flags = DASMFLAG_STEP_OVER; break; + case 0xea: sprintf(buffer, "djnz r2,$%03X", (pc & 0xf00) | *opram++); flags = DASMFLAG_STEP_OVER; break; + case 0xeb: sprintf(buffer, "djnz r3,$%03X", (pc & 0xf00) | *opram++); flags = DASMFLAG_STEP_OVER; break; + case 0xec: sprintf(buffer, "djnz r4,$%03X", (pc & 0xf00) | *opram++); flags = DASMFLAG_STEP_OVER; break; + case 0xed: sprintf(buffer, "djnz r5,$%03X", (pc & 0xf00) | *opram++); flags = DASMFLAG_STEP_OVER; break; + case 0xee: sprintf(buffer, "djnz r6,$%03X", (pc & 0xf00) | *opram++); flags = DASMFLAG_STEP_OVER; break; + case 0xef: sprintf(buffer, "djnz r7,$%03X", (pc & 0xf00) | *opram++); flags = DASMFLAG_STEP_OVER; break; + case 0xf0: sprintf(buffer, "mov a,@r0"); break; + case 0xf1: sprintf(buffer, "mov a,@r1"); break; + case 0xf2: sprintf(buffer, "jb7 $%03X", (pc & 0xf00) | *opram++); break; + case 0xf4: sprintf(buffer, "call $7%02X", *opram++); flags = DASMFLAG_STEP_OVER; break; + case 0xf5: if (!upi41) + sprintf(buffer, "sel mb1"); + else + sprintf(buffer, "en flags"); break; + case 0xf6: sprintf(buffer, "jc $%03X", (pc & 0xf00) | *opram++); break; + case 0xf7: sprintf(buffer, "rlc a"); break; + case 0xf8: sprintf(buffer, "mov a,r0"); break; + case 0xf9: sprintf(buffer, "mov a,r1"); break; + case 0xfa: sprintf(buffer, "mov a,r2"); break; + case 0xfb: sprintf(buffer, "mov a,r3"); break; + case 0xfc: sprintf(buffer, "mov a,r4"); break; + case 0xfd: sprintf(buffer, "mov a,r5"); break; + case 0xfe: sprintf(buffer, "mov a,r6"); break; + case 0xff: sprintf(buffer, "mov a,r7"); break; + default: sprintf(buffer, "illegal"); break; + } + + return (opram - startram) | flags | DASMFLAG_SUPPORTED; +} + + +CPU_DISASSEMBLE( mcs48 ) +{ + return common_dasm(device, buffer, pc, oprom, opram, FALSE); +} + + +CPU_DISASSEMBLE( upi41 ) +{ + return common_dasm(device, buffer, pc, oprom, opram, TRUE); +} diff --git a/src/devices/cpu/mcs51/mcs51.c b/src/devices/cpu/mcs51/mcs51.c new file mode 100644 index 00000000000..3b791f2b78c --- /dev/null +++ b/src/devices/cpu/mcs51/mcs51.c @@ -0,0 +1,2514 @@ +// license:BSD-3-Clause +// copyright-holders:Steve Ellenoff, Manuel Abadia, Couriersud +/***************************************************************************** + * + * i8051.c + * Portable MCS-51 Family Emulator + * + * Chips in the family: + * 8051 Product Line (8031,8051,8751) + * 8052 Product Line (8032,8052,8752) + * 8054 Product Line (8054) + * 8058 Product Line (8058) + * + * Copyright Steve Ellenoff, all rights reserved. + * + * This work is based on: + * #1) 'Intel(tm) MC51 Microcontroller Family Users Manual' and + * #2) 8051 simulator by Travis Marlatte + * #3) Portable UPI-41/8041/8741/8042/8742 emulator V0.1 by Juergen Buchmueller (MAME CORE) + * + *****************************************************************************/ + +/***************************************************************************** + * DS5002FP emulator by Manuel Abadia + * + * October 2008, couriersud: Merged back in mcs51 + * + * What has been added? + * - Extra SFRs + * - Bytewide Bus Support + * - Memory Partition and Memory Range + * - Bootstrap Configuration + * - Power Fail Interrupt + * - Timed Access + * - Stop Mode + * - Idle Mode + * + * What is not implemented? + * - Peripherals and Reprogrammable Peripheral Controller + * - CRC-16 + * - Watchdog timer + * + * The main features of the DS5002FP are: + * - 100% code-compatible with 8051 + * - Directly addresses 64kB program/64kB data memory + * - Nonvolatile memory control circuitry + * - 10-year data retention in the absence of power + * - In-system reprogramming via serial port + * - Dedicated memory bus, preserving four 8-bit ports for general purpose I/O + * - Power-fail reset + * - Early warning power-fail interrupt + * - Watchdog timer + * - Accesses up to 128kB on the bytewide bus + * - Decodes memory for 32kB x 8 or 128kB x 8 SRAMs + * - Four additional decoded peripheral-chip enables + * - CRC hardware for checking memory validity + * - Optionally emulates an 8042-style slave interface + * - Memory encryption using an 80-bit encryption key + * - Automatic random generation of encryption keys + * - Self-destruct input for tamper protection + * - Optional top-coating prevents microprobe + * + *****************************************************************************/ + +/****************************************************************************** + * Notes: + * + * The term cycles is used here to really refer to clock oscilations, because 1 machine cycle + * actually takes 12 oscilations. + * + * Read/Write/Modify Instruction - + * Data is read from the Port Latch (not the Port Pin!), possibly modified, and + * written back to (the pin? and) the latch! + * + * The following all perform this on a port address.. + * (anl, orl, xrl, jbc, cpl, inc, dec, djnz, mov px.y,c, clr px.y, setb px.y) + * + * Serial UART emulation is not really accurate, but faked enough to work as far as i can tell + * + * August 27,2003: Currently support for only 8031/8051/8751 chips (ie 128 RAM) + * October 14,2003: Added initial support for the 8752 (ie 256 RAM) + * October 22,2003: Full support for the 8752 (ie 256 RAM) + * July 28,2004: Fixed MOVX command and added External Ram Paging Support + * July 31,2004: Added Serial Mode 0 Support & Fixed Interrupt Flags for Serial Port + * + * October, 2008, Couriersud - Major rewrite + * + *****************************************************************************/ + +/* TODO: Varios + * - EA pin - defined by architecture, must implement: + * 1 means external access, bypassing internal ROM + * - T0 output clock ? + * + * - Implement 80C52 extended serial capabilities + * - Fix serial communication - This is a big hack (but working) right now. + * - Implement 83C751 in sslam.c + * - Fix cardline.c + * most likely due to different behaviour of I/O pins. The boards + * actually use 80CXX, i.e. CMOS versions. + * "Normal" 805X will return a 0 if reading from a output port which has + * a 0 written to it's latch. At least cardline expects a 1 here. + * + * Done: (Couriersud) + * - Merged DS5002FP + * - Disassembler now uses type specific memory names + * - Merged DS5002FP disasm + * - added 83C751 memory names to disassembler + * - Pointer-ified + * - Implemented cmos features + * - Implemented 80C52 interrupt handling + * - Fix segas18.c (segaic16.c) memory handling. + * - Fix sslam.c + * - Fix limenko.c videopkr.c : Issue with core allocation of ram (duplicate savestate) + * - Handle internal ram better (debugger visible) + * - Fixed port reading + * - Rewrote Macros for better readability + * - Fixed and rewrote Interrupt handling + * - Now returns INTERNAL_DIVIDER, adjusted cycle counts + * - Remove unnecessary and duplicated code + * - Remove unnecessary functions + * - Rewrite to have sfr-registers stored in int_ram. + * - Debugger may now watch sfr-registers as well. + * - implemented interrupt callbacks (HOLD_LINE now supported) + * - Runtime switch for processor type - remove ifdefs + * - internal memory maps for internal rom versions (internal ram now displayed in debugger) + * - more timer cleanups from manual + */ + +#include "emu.h" +#include "debugger.h" +#include "mcs51.h" + +#define VERBOSE 0 + +#define LOG(x) do { if (VERBOSE) logerror x; } while (0) + +/*************************************************************************** + CONSTANTS +***************************************************************************/ + +enum +{ + FEATURE_NONE = 0x00, + FEATURE_I8052 = 0x01, + FEATURE_CMOS = 0x02, + FEATURE_I80C52 = 0x04, + FEATURE_DS5002FP = 0x08 +}; + +/* Internal address in SFR of registers */ +enum +{ + ADDR_PSW = 0xd0, + ADDR_ACC = 0xe0, + ADDR_B = 0xf0, + + ADDR_P0 = 0x80, + ADDR_SP = 0x81, + ADDR_DPL = 0x82, + ADDR_DPH = 0x83, + ADDR_PCON = 0x87, + ADDR_TCON = 0x88, + ADDR_TMOD = 0x89, + ADDR_TL0 = 0x8a, + ADDR_TL1 = 0x8b, + ADDR_TH0 = 0x8c, + ADDR_TH1 = 0x8d, + ADDR_P1 = 0x90, + ADDR_SCON = 0x98, + ADDR_SBUF = 0x99, + ADDR_P2 = 0xa0, + ADDR_IE = 0xa8, + ADDR_P3 = 0xb0, + ADDR_IP = 0xb8, + + /* 8052 Only registers */ + ADDR_T2CON = 0xc8, + ADDR_RCAP2L = 0xca, + ADDR_RCAP2H = 0xcb, + ADDR_TL2 = 0xcc, + ADDR_TH2 = 0xcd, + + /* 80C52 Only registers */ + ADDR_IPH = 0xb7, + ADDR_SADDR = 0xa9, + ADDR_SADEN = 0xb9, + + /* Philips 80C52 */ + ADDR_AUXR = 0x8e, + ADDR_AUXR1 = 0xa2, + + /* DS5002FP */ + ADDR_CRCR = 0xc1, + ADDR_CRCL = 0xc2, + ADDR_CRCH = 0xc3, + ADDR_MCON = 0xc6, + ADDR_TA = 0xc7, + ADDR_RNR = 0xcf, + ADDR_RPCTL = 0xd8, + ADDR_RPS = 0xda + +}; + +/* PC vectors */ + +enum +{ + V_RESET = 0x000, /* power on address */ + V_IE0 = 0x003, /* External Interrupt 0 */ + V_TF0 = 0x00b, /* Timer 0 Overflow */ + V_IE1 = 0x013, /* External Interrupt 1 */ + V_TF1 = 0x01b, /* Timer 1 Overflow */ + V_RITI = 0x023, /* Serial Receive/Transmit */ + + /* 8052 Only Vectors */ + V_TF2 = 0x02b, /* Timer 2 Overflow */ + + /* DS5002FP */ + V_PFI = 0x02b /* Power Failure Interrupt */ +}; + + +const device_type I8031 = &device_creator; +const device_type I8032 = &device_creator; +const device_type I8051 = &device_creator; +const device_type I8751 = &device_creator; +const device_type I8052 = &device_creator; +const device_type I8752 = &device_creator; +const device_type I80C31 = &device_creator; +const device_type I80C51 = &device_creator; +const device_type I87C51 = &device_creator; +const device_type I80C32 = &device_creator; +const device_type I80C52 = &device_creator; +const device_type I87C52 = &device_creator; +const device_type AT89C4051 = &device_creator; +const device_type DS5002FP = &device_creator; + + +/*************************************************************************** + ADDRESS MAPS +***************************************************************************/ + +static ADDRESS_MAP_START(program_12bit, AS_PROGRAM, 8, mcs51_cpu_device) + AM_RANGE(0x00, 0x0fff) AM_ROM +ADDRESS_MAP_END + +static ADDRESS_MAP_START(program_13bit, AS_PROGRAM, 8, mcs51_cpu_device) + AM_RANGE(0x00, 0x1fff) AM_ROM +ADDRESS_MAP_END + +static ADDRESS_MAP_START(data_7bit, AS_DATA, 8, mcs51_cpu_device) + AM_RANGE(0x0000, 0x007f) AM_RAM + AM_RANGE(0x0100, 0x01ff) AM_RAM /* SFR */ +ADDRESS_MAP_END + +static ADDRESS_MAP_START(data_8bit, AS_DATA, 8, mcs51_cpu_device) + AM_RANGE(0x0000, 0x00ff) AM_RAM + AM_RANGE(0x0100, 0x01ff) AM_RAM /* SFR */ +ADDRESS_MAP_END + + +mcs51_cpu_device::mcs51_cpu_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, int program_width, int data_width, UINT8 features) + : cpu_device(mconfig, type, name, tag, owner, clock, shortname, __FILE__) + , m_program_config("program", ENDIANNESS_LITTLE, 8, 16, 0 + , ( ( program_width == 12 ) ? ADDRESS_MAP_NAME(program_12bit) : ( ( program_width == 13 ) ? ADDRESS_MAP_NAME(program_13bit) : NULL ) )) + , m_data_config("data", ENDIANNESS_LITTLE, 8, 9, 0 + , ( ( data_width == 7 ) ? ADDRESS_MAP_NAME(data_7bit) : ( ( data_width == 8 ) ? ADDRESS_MAP_NAME(data_8bit) : NULL ) )) + , m_io_config("io", ENDIANNESS_LITTLE, 8, 18, 0) + , m_pc(0) + , m_features(features) + , m_ram_mask( (data_width == 8) ? 0xFF : 0x7F ) + , m_num_interrupts(5) + , m_rtemp(0) +{ + m_ds5002fp.mcon = 0; + m_ds5002fp.rpctl = 0; + m_ds5002fp.crc = 0; + + /* default to standard cmos interfacing */ + + for (int i=0; i < ARRAY_LENGTH(m_forced_inputs); i++) + m_forced_inputs[i] = 0; +} + + +i8031_device::i8031_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : mcs51_cpu_device(mconfig, I8031, "I8031", tag, owner, clock, "i8031", 0, 7) +{ +} + +i8051_device::i8051_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : mcs51_cpu_device(mconfig, I8051, "I8051", tag, owner, clock, "i8051", 12, 7) +{ +} + +i8751_device::i8751_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : mcs51_cpu_device(mconfig, I8751, "I8751", tag, owner, clock, "i8751", 12, 7) +{ +} + +i8052_device::i8052_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, int program_width, int data_width, UINT8 features) + : mcs51_cpu_device(mconfig, type, name, tag, owner, clock, shortname, program_width, data_width, features | FEATURE_I8052) +{ + m_num_interrupts = 6; +} + +i8052_device::i8052_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : mcs51_cpu_device(mconfig, I8052, "I8052", tag, owner, clock, "i8052", 13, 8, FEATURE_I8052) +{ + m_num_interrupts = 6; +} + +i8032_device::i8032_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : i8052_device(mconfig, I8032, "I8032", tag, owner, clock, "i8032", 0, 8) +{ +} + +i8752_device::i8752_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : i8052_device(mconfig, I8752, "I8752", tag, owner, clock, "i8752", 13, 8) +{ +} + +i80c31_device::i80c31_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : i8052_device(mconfig, I80C31, "I80C31", tag, owner, clock, "i80c31", 0, 7) +{ +} + +i80c51_device::i80c51_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, int program_width, int data_width, UINT8 features) + : mcs51_cpu_device(mconfig, type, name, tag, owner, clock, shortname, program_width, data_width, features | FEATURE_CMOS) +{ +} + +i80c51_device::i80c51_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : mcs51_cpu_device(mconfig, I80C51, "I80C51", tag, owner, clock, "i80c51", 12, 7) +{ +} + +i87c51_device::i87c51_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : i80c51_device(mconfig, I87C51, "I87C51", tag, owner, clock, "i87c51", 12, 7) +{ +} + + +i80c52_device::i80c52_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, int program_width, int data_width, UINT8 features) + : i8052_device(mconfig, type, name, tag, owner, clock, shortname, program_width, data_width, features | FEATURE_I80C52 | FEATURE_CMOS) +{ +} + +i80c52_device::i80c52_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : i8052_device(mconfig, I80C52, "I80C52", tag, owner, clock, "i80C52", 13, 8, FEATURE_I80C52 | FEATURE_CMOS) +{ +} + +i80c32_device::i80c32_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : i80c52_device(mconfig, I80C32, "I80C32", tag, owner, clock, "i80c32", 0, 8) +{ +} + + +i87c52_device::i87c52_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : i80c52_device(mconfig, I87C52, "I87C52", tag, owner, clock, "i87c52", 13, 8) +{ +} + +at89c4051_device::at89c4051_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : i80c51_device(mconfig, AT89C4051, "AT89C4051", tag, owner, clock, "at89c4051", 12, 7) +{ +} + +ds5002fp_device::ds5002fp_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : mcs51_cpu_device(mconfig, DS5002FP, "DS5002FP", tag, owner, clock, "ds5002fp", 12, 7, FEATURE_DS5002FP | FEATURE_CMOS) +{ +} + + +/*************************************************************************** + MACROS +***************************************************************************/ + +/* Read Opcode/Opcode Arguments from Program Code */ +#define ROP(pc) m_direct->read_byte(pc) +#define ROP_ARG(pc) m_direct->read_byte(pc) + +/* Read a byte from External Code Memory (Usually Program Rom(s) Space) */ +#define CODEMEM_R(a) (UINT8)m_program->read_byte(a) + +/* Read/Write a byte from/to External Data Memory (Usually RAM or other I/O) */ +#define DATAMEM_R(a) (UINT8)m_io->read_byte(a) +#define DATAMEM_W(a,v) m_io->write_byte(a, v) + +/* Read/Write a byte from/to the Internal RAM */ + +#define IRAM_R(a) iram_read(a) +#define IRAM_W(a, d) iram_write(a, d) + +/* Read/Write a byte from/to the Internal RAM indirectly */ +/* (called from indirect addressing) */ +UINT8 mcs51_cpu_device::iram_iread(offs_t a) { return (a <= m_ram_mask) ? m_data->read_byte(a) : 0xff; } +void mcs51_cpu_device::iram_iwrite(offs_t a, UINT8 d) { if (a <= m_ram_mask) m_data->write_byte(a, d); } + +#define IRAM_IR(a) iram_iread(a) +#define IRAM_IW(a, d) iram_iwrite(a, d) + +/* Form an Address to Read/Write to External RAM indirectly */ +/* (called from indirect addressing) */ +#define ERAM_ADDR(a,m) external_ram_iaddr(a,m) + +/* Read/Write a bit from Bit Addressable Memory */ +#define BIT_R(a) bit_address_r(a) +#define BIT_W(a,v) bit_address_w(a, v) + +/* Input/Output a byte from given I/O port */ +#define IN(port) ((UINT8)m_io->read_byte(port)) +#define OUT(port,value) m_io->write_byte(port,value) + + +/*************************************************************************** + SHORTCUTS +***************************************************************************/ + +#define PPC m_ppc +#define PC m_pc +#define RWM m_rwm + +/* SFR Registers - These are accessed directly for speed on read */ +/* Read accessors */ + +#define SFR_A(a) m_sfr_ram[(a)] +#define SET_SFR_A(a,v) do { SFR_A(a) = (v); } while (0) + +#define ACC SFR_A(ADDR_ACC) +#define PSW SFR_A(ADDR_PSW) + +#define P0 ((const UINT8) SFR_A(ADDR_P0)) +#define P1 ((const UINT8) SFR_A(ADDR_P1)) +#define P2 ((const UINT8) SFR_A(ADDR_P2)) +#define P3 ((const UINT8) SFR_A(ADDR_P3)) + +#define SP SFR_A(ADDR_SP) +#define DPL SFR_A(ADDR_DPL) +#define DPH SFR_A(ADDR_DPH) +#define PCON SFR_A(ADDR_PCON) +#define TCON SFR_A(ADDR_TCON) +#define TMOD SFR_A(ADDR_TMOD) +#define TL0 SFR_A(ADDR_TL0) +#define TL1 SFR_A(ADDR_TL1) +#define TH0 SFR_A(ADDR_TH0) +#define TH1 SFR_A(ADDR_TH1) +#define SCON SFR_A(ADDR_SCON) +#define IE SFR_A(ADDR_IE) +#define IP SFR_A(ADDR_IP) +#define B SFR_A(ADDR_B) +#define SBUF SFR_A(ADDR_SBUF) + +#define R_REG(r) m_internal_ram[(r) | (PSW & 0x18)] +#define DPTR ((DPH<<8) | DPL) + +/* 8052 Only registers */ +#define T2CON SFR_A(ADDR_T2CON) +#define RCAP2L SFR_A(ADDR_RCAP2L) +#define RCAP2H SFR_A(ADDR_RCAP2H) +#define TL2 SFR_A(ADDR_TL2) +#define TH2 SFR_A(ADDR_TH2) + +/* 80C52 Only registers */ +#define IPH SFR_A(ADDR_IPH) +#define SADDR SFR_A(ADDR_SADDR) +#define SADEN SFR_A(ADDR_SADEN) + +/* Philips 80C52 */ +/* ============= */ +/* Reduced EMI Mode + * The AO bit (AUXR.0) in the AUXR register when set disables the + * ALE output. + */ +#define AUXR SFR_A(ADDR_AUXR) + +/* The dual DPTR structure (see Figure 12) is a way by which the + * 80C52/54/58 will specify the address of an external data memory + * location. There are two 16-bit DPTR registers that address the + * external memory, and a single bit called DPS = AUXR1/bit0 that + * allows the program code to switch between them. + */ +#define AUXR1 SFR_A(ADDR_AUXR1) + +/* DS5002FP only registers */ +#define CRCR SFR_A(ADDR_CRCR) +#define CRCL SFR_A(ADDR_CRCL) +#define CRCH SFR_A(ADDR_CRCH) +#define MCON SFR_A(ADDR_MCON) +#define TA SFR_A(ADDR_TA) +#define RNR SFR_A(ADDR_RNR) +#define RPCTL SFR_A(ADDR_RPCTL) +#define RPS SFR_A(ADDR_RPS) + + +/* WRITE accessors */ + +/* Shortcuts */ + +#define SET_PSW(v) do { SFR_A(ADDR_PSW) = (v); SET_PARITY(); } while (0) +#define SET_ACC(v) do { SFR_A(ADDR_ACC) = (v); SET_PARITY(); } while (0) + +/* These trigger actions on modification and have to be written through SFR_W */ +#define SET_P0(v) IRAM_W(ADDR_P0, v) +#define SET_P1(v) IRAM_W(ADDR_P1, v) +#define SET_P2(v) IRAM_W(ADDR_P2, v) +#define SET_P3(v) IRAM_W(ADDR_P3, v) + +/* Within the cpu core, do not trigger a send */ +#define SET_SBUF(v) SET_SFR_A(ADDR_SBUF, v) + +/* No actions triggered on write */ +#define SET_REG(r, v) do { m_internal_ram[(r) | (PSW & 0x18)] = (v); } while (0) + +#define SET_DPTR(n) do { DPH = ((n) >> 8) & 0xff; DPL = (n) & 0xff; } while (0) + +/* Macros for Setting Flags */ +#define SET_X(R, v) do { R = (v);} while (0) + +#define SET_CY(n) SET_PSW((PSW & 0x7f) | (n<<7)) //Carry Flag +#define SET_AC(n) SET_PSW((PSW & 0xbf) | (n<<6)) //Aux.Carry Flag +#define SET_FO(n) SET_PSW((PSW & 0xdf) | (n<<5)) //User Flag +#define SET_RS(n) SET_PSW((PSW & 0xe7) | (n<<3)) //R Bank Select +#define SET_OV(n) SET_PSW((PSW & 0xfb) | (n<<2)) //Overflow Flag +#define SET_P(n) SET_PSW((PSW & 0xfe) | (n<<0)) //Parity Flag + +#define SET_BIT(R, n, v) do { R = (R & ~(1<<(n))) | ((v) << (n));} while (0) +#define GET_BIT(R, n) (((R)>>(n)) & 0x01) + +#define SET_EA(n) SET_BIT(IE, 7, n) //Global Interrupt Enable/Disable +#define SET_ES(n) SET_BIT(IE, 4, v) //Serial Interrupt Enable/Disable +#define SET_ET1(n) SET_BIT(IE, 3, n) //Timer 1 Interrupt Enable/Disable +#define SET_EX1(n) SET_BIT(IE, 2, n) //External Int 1 Interrupt Enable/Disable +#define SET_ET0(n) SET_BIT(IE, 1, n) //Timer 0 Interrupt Enable/Disable +#define SET_EX0(n) SET_BIT(IE, 0, n) //External Int 0 Interrupt Enable/Disable +/* 8052 Only flags */ +#define SET_ET2(n) SET_BIT(IE, 5, n) //Timer 2 Interrupt Enable/Disable + +/* 8052 Only flags */ +#define SET_PT2(n) SET_BIT(IP, 5, n); //Set Timer 2 Priority Level + +#define SET_PS0(n) SET_BIT(IP, 4, n) //Set Serial Priority Level +#define SET_PT1(n) SET_BIT(IP, 3, n) //Set Timer 1 Priority Level +#define SET_PX1(n) SET_BIT(IP, 2, n) //Set External Int 1 Priority Level +#define SET_PT0(n) SET_BIT(IP, 1, n) //Set Timer 0 Priority Level +#define SET_PX0(n) SET_BIT(IP, 0, n) //Set External Int 0 Priority Level + +#define SET_TF1(n) SET_BIT(TCON, 7, n) //Indicated Timer 1 Overflow Int Triggered +#define SET_TR1(n) SET_BIT(TCON, 6, n) //IndicateS Timer 1 is running +#define SET_TF0(n) SET_BIT(TCON, 5, n) //Indicated Timer 0 Overflow Int Triggered +#define SET_TR0(n) SET_BIT(TCON, 4, n) //IndicateS Timer 0 is running +#define SET_IE1(n) SET_BIT(TCON, 3, n) //Indicated External Int 1 Triggered +#define SET_IT1(n) SET_BIT(TCON, 2, n) //Indicates how External Int 1 is Triggered +#define SET_IE0(n) SET_BIT(TCON, 1, n) //Indicated External Int 0 Triggered +#define SET_IT0(n) SET_BIT(TCON, 0, n) //Indicates how External Int 0 is Triggered + +#define SET_SM0(n) SET_BIT(SCON, 7, n) //Sets Serial Port Mode +#define SET_SM1(n) SET_BIT(SCON, 6, n) //Sets Serial Port Mode +#define SET_SM2(n) SET_BIT(SCON, 5, n) //Sets Serial Port Mode (Multiprocesser mode) +#define SET_REN(n) SET_BIT(SCON, 4, n) //Sets Serial Port Receive Enable +#define SET_TB8(n) SET_BIT(SCON, 3, n) //Transmit 8th Bit +#define SET_RB8(n) SET_BIT(SCON, 2, n) //Receive 8th Bit +#define SET_TI(n) SET_BIT(SCON, 1, n) //Indicates Transmit Interrupt Occurred +#define SET_RI(n) SET_BIT(SCON, 0, n) //Indicates Receive Interrupt Occurred + +#define SET_GATE1(n) SET_BIT(TMOD, 7, n) //Timer 1 Gate Mode +#define SET_CT1(n) SET_BIT(TMOD, 6, n) //Timer 1 Counter Mode +#define SET_M1_1(n) SET_BIT(TMOD, 5, n) //Timer 1 Timer Mode Bit 1 +#define SET_M1_0(n) SET_BIT(TMOD, 4, n) //Timer 1 Timer Mode Bit 0 +#define SET_GATE0(n) SET_BIT(TMOD, 3, n) //Timer 0 Gate Mode +#define SET_CT0(n) SET_BIT(TMOD, 2, n) //Timer 0 Counter Mode +#define SET_M0_1(n) SET_BIT(TMOD, 1, n) //Timer 0 Timer Mode Bit 1 +#define SET_M0_0(n) SET_BIT(TMOD, 0, n) //Timer 0 Timer Mode Bit 0 + + + +/* 8052 Only flags - T2CON Flags */ +#define SET_TF2(n) SET_BIT(T2CON, 7, n) //Indicated Timer 2 Overflow Int Triggered +#define SET_EXF2(n) SET_BIT(T2CON, 6, n) //Indicates Timer 2 External Flag +#define SET_RCLK(n) SET_BIT(T2CON, 5, n) //Receive Clock +#define SET_TCLK(n) SET_BIT(T2CON, 4, n) //Transmit Clock +#define SET_EXEN2(n) SET_BIT(T2CON, 3, n) //Timer 2 External Interrupt Enable +#define SET_TR2(n) SET_BIT(T2CON, 2, n) //Indicates Timer 2 is running +#define SET_CT2(n) SET_BIT(T2CON, 1, n) //Sets Timer 2 Counter/Timer Mode +#define SET_CP(n) SET_BIT(T2CON, 0, n) //Sets Timer 2 Capture/Reload Mode + +#define SET_GF1(n) SET_BIT(PCON, 3, n) +#define SET_GF0(n) SET_BIT(PCON, 2, n) +#define SET_PD(n) SET_BIT(PCON, 1, n) +#define SET_IDL(n) SET_BIT(PCON, 0, n) + +/* Macros for accessing flags */ + +#define GET_CY GET_BIT(PSW, 7) +#define GET_AC GET_BIT(PSW, 6) +#define GET_FO GET_BIT(PSW, 5) +#define GET_RS GET_BIT(PSW, 3) +#define GET_OV GET_BIT(PSW, 2) +#define GET_P GET_BIT(PSW, 0) + +#define GET_EA GET_BIT(IE, 7) +#define GET_ET2 GET_BIT(IE, 5) +#define GET_ES GET_BIT(IE, 4) +#define GET_ET1 GET_BIT(IE, 3) +#define GET_EX1 GET_BIT(IE, 2) +#define GET_ET0 GET_BIT(IE, 1) +#define GET_EX0 GET_BIT(IE, 0) + +/* 8052 Only flags */ +#define GET_PT2 GET_BIT(IP, 5) + +#define GET_PS GET_BIT(IP, 4) +#define GET_PT1 GET_BIT(IP, 3) +#define GET_PX1 GET_BIT(IP, 2) +#define GET_PT0 GET_BIT(IP, 1) +#define GET_PX0 GET_BIT(IP, 0) + +#define GET_TF1 GET_BIT(TCON, 7) +#define GET_TR1 GET_BIT(TCON, 6) +#define GET_TF0 GET_BIT(TCON, 5) +#define GET_TR0 GET_BIT(TCON, 4) +#define GET_IE1 GET_BIT(TCON, 3) +#define GET_IT1 GET_BIT(TCON, 2) +#define GET_IE0 GET_BIT(TCON, 1) +#define GET_IT0 GET_BIT(TCON, 0) + +#define GET_SM0 GET_BIT(SCON, 7) +#define GET_SM1 GET_BIT(SCON, 6) +#define GET_SM2 GET_BIT(SCON, 5) +#define GET_REN GET_BIT(SCON, 4) +#define GET_TB8 GET_BIT(SCON, 3) +#define GET_RB8 GET_BIT(SCON, 2) +#define GET_TI GET_BIT(SCON, 1) +#define GET_RI GET_BIT(SCON, 0) + +#define GET_GATE1 GET_BIT(TMOD, 7) +#define GET_CT1 GET_BIT(TMOD, 6) +#define GET_M1_1 GET_BIT(TMOD, 5) +#define GET_M1_0 GET_BIT(TMOD, 4) +#define GET_GATE0 GET_BIT(TMOD, 3) +#define GET_CT0 GET_BIT(TMOD, 2) +#define GET_M0_1 GET_BIT(TMOD, 1) +#define GET_M0_0 GET_BIT(TMOD, 0) + +#define GET_SMOD GET_BIT(PCON, 7) + +/* Only in 80C51BH & other cmos */ + +#define GET_GF1 GET_BIT(PCON, 3) +#define GET_GF0 GET_BIT(PCON, 2) +#define GET_PD GET_BIT(PCON, 1) +#define GET_IDL (GET_BIT(PCON, 0) & ~(GET_PD)) /* PD takes precedence! */ + +/* 8052 Only flags */ +#define GET_TF2 GET_BIT(T2CON, 7) +#define GET_EXF2 GET_BIT(T2CON, 6) +#define GET_RCLK GET_BIT(T2CON, 5) +#define GET_TCLK GET_BIT(T2CON, 4) +#define GET_EXEN2 GET_BIT(T2CON, 3) +#define GET_TR2 GET_BIT(T2CON, 2) +#define GET_CT2 GET_BIT(T2CON, 1) +#define GET_CP GET_BIT(T2CON, 0) + +/* DS5002FP Only flags */ + +/* PCON Flags - DS5002FP */ + +#define GET_POR GET_BIT(PCON, 6) +#define GET_PFW GET_BIT(PCON, 5) +#define GET_WTR GET_BIT(PCON, 4) +#define GET_EPFW GET_BIT(PCON, 3) +#define GET_EWT GET_BIT(PCON, 2) + +#define SET_PFW(n) SET_BIT(PCON, 5, n) + +/* MCON Flags - DS5002FP */ + +#define GET_PA ((MCON & 0xf0)>>4) +#define GET_RG1 GET_BIT(MCON, 3) +#define GET_PES GET_BIT(MCON, 2) +#define GET_PM GET_BIT(MCON, 1) +#define GET_SL GET_BIT(MCON, 0) + +/* RPCTL Flags - DS5002FP */ +#define GET_RNR GET_BIT(RPCTL, 7) /* Bit 6 ?? */ +#define GET_EXBS GET_BIT(RPCTL, 5) +#define GET_AE GET_BIT(RPCTL, 4) +#define GET_IBI GET_BIT(RPCTL, 3) +#define GET_DMA GET_BIT(RPCTL, 2) +#define GET_RPCON GET_BIT(RPCTL, 1) +#define GET_RG0 GET_BIT(RPCTL, 0) + + +/*Add and Subtract Flag settings*/ +#define DO_ADD_FLAGS(a,d,c) do_add_flags(a, d, c) +#define DO_SUB_FLAGS(a,d,c) do_sub_flags(a, d, c) + +#define SET_PARITY() do {m_recalc_parity |= 1;} while (0) +#define PUSH_PC() push_pc() +#define POP_PC() pop_pc() + +/* Clear Current IRQ */ +#define CLEAR_CURRENT_IRQ() clear_current_irq() + + +/* Hold callback functions so they can be set by caller (before the cpu reset) */ + +/*************************************************************************** + INLINE FUNCTIONS +***************************************************************************/ + +void mcs51_cpu_device::clear_current_irq() +{ + if (m_cur_irq_prio >= 0) + m_irq_active &= ~(1 << m_cur_irq_prio); + if (m_irq_active & 4) + m_cur_irq_prio = 2; + else if (m_irq_active & 2) + m_cur_irq_prio = 1; + else if (m_irq_active & 1) + m_cur_irq_prio = 0; + else + m_cur_irq_prio = -1; + LOG(("New: %d %02x\n", m_cur_irq_prio, m_irq_active)); +} + +UINT8 mcs51_cpu_device::r_acc() { return SFR_A(ADDR_ACC); } + +UINT8 mcs51_cpu_device::r_psw() { return SFR_A(ADDR_PSW); } + +void mcs51_cpu_device::update_ptrs() +{ + m_internal_ram = (UINT8 *)m_data->get_write_ptr(0x00); + m_sfr_ram = (UINT8 *)m_data->get_write_ptr(0x100); +} + + +/* Generate an external ram address for read/writing using indirect addressing mode */ + +/*The lowest 8 bits of the address are passed in (from the R0/R1 register), however + the hardware can be configured to set the rest of the address lines to any available output port pins, which + means the only way we can implement this is to allow the driver to setup a callback to generate the + address as defined by the specific hardware setup. We'll assume the address won't be bigger than 32 bits + + Couriersud, October 2008: + There is no way external hardware can distinguish between 8bit access and 16 bit access. + During 16bit access the high order byte of the address is output on port 2. We therefore + assume that most hardware will use port 2 for 8bit access as well. + + On configurations where 8 bit access in conjunction with other ports is used, + it is up to the driver to use AM_MIRROR to mask out the high level address and + provide it's own mapping. +*/ + +/* + The DS5002FP has 2 16 bits data address buses (the byte-wide bus and the expanded bus). The exact memory position accessed depends on the + partition mode, the memory range and the expanded bus select. The partition mode and the expanded bus select can be changed at any time. + + In order to simplify memory mapping to the data address bus, the following address map is assumed for partitioned mode: + + 0x00000-0x0ffff -> data memory on the expanded bus + 0x10000-0x1ffff -> data memory on the byte-wide bus + + For non-partitioned mode the following memory map is assumed: + + 0x0000-0xffff -> data memory (the bus used to access it does not matter) +*/ + +offs_t mcs51_cpu_device::external_ram_iaddr(offs_t offset, offs_t mem_mask) +{ + /* Memory Range (RG1 and RG0 @ MCON and RPCTL registers) */ + static const UINT16 ds5002fp_ranges[4] = { 0x1fff, 0x3fff, 0x7fff, 0xffff }; + /* Memory Partition Table (RG1 & RG0 @ MCON & RPCTL registers) */ + static const UINT32 ds5002fp_partitions[16] = { + 0x0000, 0x1000, 0x2000, 0x3000, 0x4000, 0x5000, 0x6000, 0x7000, + 0x8000, 0x9000, 0xa000, 0xb000, 0xc000, 0xd000, 0xe000, 0x10000 }; + + /* if partition mode is set, adjust offset based on the bus */ + if (m_features & FEATURE_DS5002FP) + { + if (!GET_PM) { + if (!GET_EXBS) { + if ((offset >= ds5002fp_partitions[GET_PA]) && (offset <= ds5002fp_ranges[m_ds5002fp.range])) { + offset += 0x10000; + } + } + } + } + else + { + if (mem_mask == 0x00ff) + return (offset & mem_mask) | (P2 << 8); + } + return offset; +} + +/* Internal ram read/write */ + +UINT8 mcs51_cpu_device::iram_read(size_t offset) +{ + return (((offset) < 0x80) ? m_data->read_byte(offset) : sfr_read(offset)); +} + +void mcs51_cpu_device::iram_write(size_t offset, UINT8 data) +{ + if ((offset) < 0x80) + m_data->write_byte(offset, data); + else + sfr_write(offset, data); +} + +/*Push the current PC to the stack*/ +void mcs51_cpu_device::push_pc() +{ + UINT8 tmpSP = SP+1; //Grab and Increment Stack Pointer + IRAM_IW(tmpSP, (PC & 0xff)); //Store low byte of PC to Internal Ram (Use IRAM_IW to store stack above 128 bytes) + tmpSP++; // "" + SP = tmpSP; // "" + IRAM_IW(tmpSP, ( (PC & 0xff00) >> 8)); //Store hi byte of PC to next address in Internal Ram (Use IRAM_IW to store stack above 128 bytes) +} + +/*Pop the current PC off the stack and into the pc*/ +void mcs51_cpu_device::pop_pc() +{ + UINT8 tmpSP = SP; //Grab Stack Pointer + PC = (IRAM_IR(tmpSP--) & 0xff) << 8; //Store hi byte to PC (must use IRAM_IR to access stack pointing above 128 bytes) + PC = PC | IRAM_IR(tmpSP--); //Store lo byte to PC (must use IRAM_IR to access stack pointing above 128 bytes) + SP = tmpSP; //Decrement Stack Pointer +} + +//Set the PSW Parity Flag +void mcs51_cpu_device::set_parity() +{ + //This flag will be set when the accumulator contains an odd # of bits set.. + UINT8 p = 0; + int i; + UINT8 a = ACC; + + for (i=0; i<8; i++) { //Test for each of the 8 bits in the ACC! + p ^= (a & 1); + a = (a >> 1); + } + + SET_P(p & 1); +} + +UINT8 mcs51_cpu_device::bit_address_r(UINT8 offset) +{ + UINT8 word; + UINT8 mask; + int bit_pos; + int distance; /* distance between bit addressable words */ + /* 1 for normal bits, 8 for sfr bit addresses */ + + //User defined bit addresses 0x20-0x2f (values are 0x0-0x7f) + if (offset < 0x80) { + distance = 1; + word = ( (offset & 0x78) >> 3) * distance + 0x20; + bit_pos = offset & 0x7; + mask = (0x1 << bit_pos); + return((IRAM_R(word) & mask) >> bit_pos); + } + //SFR bit addressable registers + else { + distance = 8; + word = ( (offset & 0x78) >> 3) * distance + 0x80; + bit_pos = offset & 0x7; + mask = (0x1 << bit_pos); + return ((IRAM_R(word) & mask) >> bit_pos); + } +} + + +void mcs51_cpu_device::bit_address_w(UINT8 offset, UINT8 bit) +{ + int word; + UINT8 mask; + int bit_pos; + UINT8 result; + int distance; + + /* User defined bit addresses 0x20-0x2f (values are 0x0-0x7f) */ + if (offset < 0x80) { + distance = 1; + word = ((offset & 0x78) >> 3) * distance + 0x20; + bit_pos = offset & 0x7; + bit = (bit & 0x1) << bit_pos; + mask = ~(1 << bit_pos) & 0xff; + result = IRAM_R(word) & mask; + result = result | bit; + IRAM_W(word, result); + } + /* SFR bit addressable registers */ + else { + distance = 8; + word = ((offset & 0x78) >> 3) * distance + 0x80; + bit_pos = offset & 0x7; + bit = (bit & 0x1) << bit_pos; + mask = ~(1 << bit_pos) & 0xff; + result = IRAM_R(word) & mask; + result = result | bit; + IRAM_W(word, result); + } +} + +void mcs51_cpu_device::do_add_flags(UINT8 a, UINT8 data, UINT8 c) +{ + UINT16 result = a+data+c; + INT16 result1 = (INT8)a+(INT8)data+c; + + SET_CY((result & 0x100) >> 8); + result = (a&0x0f)+(data&0x0f)+c; + SET_AC((result & 0x10) >> 4); + SET_OV(result1 < -128 || result1 > 127); +} + +void mcs51_cpu_device::do_sub_flags(UINT8 a, UINT8 data, UINT8 c) +{ + UINT16 result = a-(data+c); + INT16 result1 = (INT8)a-(INT8)(data+c); + + SET_CY((result & 0x100) >> 8); + result = (a&0x0f)-((data&0x0f)+c); + SET_AC((result & 0x10) >> 4); + SET_OV((result1 < -128 || result1 > 127)); +} + +void mcs51_cpu_device::transmit_receive(int source) +{ + int mode = (GET_SM0<<1) | GET_SM1; + + if (source == 1) /* timer1 */ + m_uart.smod_div = (m_uart.smod_div + 1) & (2-GET_SMOD); + + switch(mode) { + //8 bit shifter ( + start,stop bit ) - baud set by clock freq / 12 + case 0: + m_uart.rx_clk += (source == 0) ? 16 : 0; /* clock / 12 */ + m_uart.tx_clk += (source == 0) ? 16 : 0; /* clock / 12 */ + break; + //8 bit uart ( + start,stop bit ) - baud set by timer1 or timer2 + case 1: + case 3: + if (source == 1) + { + m_uart.tx_clk += (GET_TCLK ? 0 : !m_uart.smod_div); + m_uart.rx_clk += (GET_RCLK ? 0 : !m_uart.smod_div); + } + if (source == 2) + { + m_uart.tx_clk += (GET_TCLK ? 1 : 0); + m_uart.rx_clk += (GET_RCLK ? 1 : 0); + } + break; + //9 bit uart + case 2: + m_uart.rx_clk += (source == 0) ? (GET_SMOD ? 6 : 3) : 0; /* clock / 12 * 3 / 8 (16) = clock / 32 (64)*/ + m_uart.tx_clk += (source == 0) ? (GET_SMOD ? 6 : 3) : 0; /* clock / 12 */ + break; + } + /* transmit ? */ + if (m_uart.tx_clk >= 16) + { + m_uart.tx_clk &= 0x0f; + if(m_uart.bits_to_send) + { + m_uart.bits_to_send--; + if(m_uart.bits_to_send == 0) { + //Call the callback function + if(!m_serial_tx_callback.isnull()) + m_serial_tx_callback(*m_io, 0, m_uart.data_out, 0xff); + //Set Interrupt Flag + SET_TI(1); + } + } + + } + /* receive */ + if (m_uart.rx_clk >= 16) + { + m_uart.rx_clk &= 0x0f; + if (m_uart.delay_cycles>0) + { + m_uart.delay_cycles--; + if (m_uart.delay_cycles == 0) + { + int data = 0; + //Call our callball function to retrieve the data + if(!m_serial_rx_callback.isnull()) + data = m_serial_rx_callback(*m_io, 0, 0xff); + LOG(("RX Deliver %d\n", data)); + SET_SBUF(data); + //Flag the IRQ + SET_RI(1); + SET_RB8(1); // HACK force 2nd stop bit + } + } + } +} + + +void mcs51_cpu_device::update_timer_t0(int cycles) +{ + int mode = (GET_M0_1<<1) | GET_M0_0; + UINT32 count = 0; + + if (GET_TR0) + { + UINT32 delta; + + /* counter / external input */ + delta = GET_CT0 ? m_t0_cnt : cycles; + /* taken, reset */ + m_t0_cnt = 0; + /* TODO: Not sure about IE0. The manual specifies INT0=high, + * which in turn means CLEAR_LINE. + * IE0 may be edge triggered depending on IT0 */ + if (GET_GATE0 && !GET_IE0) + delta = 0; + + switch(mode) { + case 0: /* 13 Bit Timer Mode */ + count = ((TH0<<5) | ( TL0 & 0x1f ) ); + count += delta; + if ( count & 0xffffe000 ) /* Check for overflow */ + SET_TF0(1); + TH0 = (count>>5) & 0xff; + TL0 = count & 0x1f ; + break; + case 1: /* 16 Bit Timer Mode */ + count = ((TH0<<8) | TL0); + count += delta; + if ( count & 0xffff0000 ) /* Check for overflow */ + SET_TF0(1); + TH0 = (count>>8) & 0xff; + TL0 = count & 0xff; + break; + case 2: /* 8 Bit Autoreload */ + count = ((UINT32) TL0) + delta; + if ( count & 0xffffff00 ) /* Check for overflow */ + { + SET_TF0(1); + count += TH0; /* Reload timer */ + } + /* Update new values of the counter */ + TL0 = count & 0xff; + break; + case 3: + /* Split Timer 1 */ + count = ((UINT32) TL0) + delta; + if ( count & 0xffffff00 ) /* Check for overflow */ + SET_TF0(1); + TL0 = count & 0xff; /* Update new values of the counter */ + break; + } + } + if (GET_TR1) + { + switch(mode) + { + case 3: + /* Split Timer 2 */ + count = ((UINT32) TH0) + cycles; /* No gate control or counting !*/ + if ( count & 0xffffff00 ) /* Check for overflow */ + SET_TF1(1); + TH0 = count & 0xff; /* Update new values of the counter */ + break; + } + } +} + +/* From the DS5002FP User Manual +When Timer 1 is selected for operation in Mode 3, it stops counting and holds its current value. This +action is the same as setting TR1 = 0. When Timer 0 is selected in Mode 3, Timer 1???s control bits are +stolen as described above. As a result, Timer 1???s functions are limited in this MODE. It is forced to +operate as a timer whose clock in-put is 12 tCLK and it cannot generate an interrupt on overflow. In +addition, it also cannot be used with the GATE function. However, it can be started and stopped by +switching it into or out of Mode 3 or it can be assigned as a baud rate generator for the serial port. +*/ + +/* Intel documentation: + * Timer 1 may still be used in modes 0, 1, and 2, while timer 0 + * is in mode 3. With one important exception: No interrupts + * will be generated by timer 1 while timer 0 is using the TF1 + * overflow flag + */ + +void mcs51_cpu_device::update_timer_t1(int cycles) +{ + UINT8 mode = (GET_M1_1<<1) | GET_M1_0; + UINT8 mode_0 = (GET_M0_1<<1) | GET_M0_0; + UINT32 count = 0; + + if (mode_0 != 3) + { + if (GET_TR1) + { + UINT32 delta; + UINT32 overflow = 0; + + /* counter / external input */ + delta = GET_CT1 ? m_t1_cnt : cycles; + /* taken, reset */ + m_t1_cnt = 0; + /* TODO: Not sure about IE0. The manual specifies INT0=high, + * which in turn means CLEAR_LINE. Change to access last_state? + * IE0 may be edge triggered depending on IT0 */ + if (GET_GATE1 && !GET_IE1) + delta = 0; + + switch(mode) { + case 0: /* 13 Bit Timer Mode */ + count = ((TH1<<5) | ( TL1 & 0x1f ) ); + count += delta; + overflow = count & 0xffffe000; /* Check for overflow */ + TH1 = (count>>5) & 0xff; + TL1 = count & 0x1f ; + break; + case 1: /* 16 Bit Timer Mode */ + count = ((TH1<<8) | TL1); + count += delta; + overflow = count & 0xffff0000; /* Check for overflow */ + TH1 = (count>>8) & 0xff; + TL1 = count & 0xff; + break; + case 2: /* 8 Bit Autoreload */ + count = ((UINT32) TL1) + delta; + overflow = count & 0xffffff00; /* Check for overflow */ + if ( overflow ) + { + count += TH1; /* Reload timer */ + } + /* Update new values of the counter */ + TL1 = count & 0xff; + break; + case 3: + /* do nothing */ + break; + } + if (overflow) + { + SET_TF1(1); + transmit_receive(1); + } + } + } + else + { + UINT32 delta; + UINT32 overflow = 0; + + delta = cycles; + /* taken, reset */ + m_t1_cnt = 0; + switch(mode) { + case 0: /* 13 Bit Timer Mode */ + count = ((TH1<<5) | ( TL1 & 0x1f ) ); + count += delta; + overflow = count & 0xffffe000; /* Check for overflow */ + TH1 = (count>>5) & 0xff; + TL1 = count & 0x1f ; + break; + case 1: /* 16 Bit Timer Mode */ + count = ((TH1<<8) | TL1); + count += delta; + overflow = count & 0xffff0000; /* Check for overflow */ + TH1 = (count>>8) & 0xff; + TL1 = count & 0xff; + break; + case 2: /* 8 Bit Autoreload */ + count = ((UINT32) TL1) + delta; + overflow = count & 0xffffff00; /* Check for overflow */ + if ( overflow ) + { + count += TH1; /* Reload timer */ + } + /* Update new values of the counter */ + TL1 = count & 0xff; + break; + case 3: + /* do nothing */ + break; + } + if (overflow) + { + transmit_receive(1); + } + } +} + +void mcs51_cpu_device::update_timer_t2(int cycles) +{ + /* Update Timer 2 */ + if(GET_TR2) { + int mode = ((GET_TCLK | GET_RCLK) << 1) | GET_CP; + int delta = GET_CT2 ? m_t2_cnt : (mode & 2) ? cycles * (12/2) : cycles; + + UINT32 count = ((TH2<<8) | TL2) + delta; + m_t2_cnt = 0; + + switch (mode) + { + case 0: /* 16 Bit Auto Reload */ + if ( count & 0xffff0000 ) + { + SET_TF2(1); + count += ((RCAP2H<<8) | RCAP2L); + } + else if (GET_EXEN2 && m_t2ex_cnt>0) + { + count += ((RCAP2H<<8) | RCAP2L); + m_t2ex_cnt = 0; + } + TH2 = (count>>8) & 0xff; + TL2 = count & 0xff; + break; + case 1: /* 16 Bit Capture */ + if ( count & 0xffff0000 ) + SET_TF2(1); + TH2 = (count>>8) & 0xff; + TL2 = count & 0xff; + + if (GET_EXEN2 && m_t2ex_cnt>0) + { + RCAP2H = TH2; + RCAP2L = TL2; + m_t2ex_cnt = 0; + } + break; + case 2: + case 3: /* Baud rate */ + if ( count & 0xffff0000 ) + { + count += ((RCAP2H<<8) | RCAP2L); + transmit_receive(2); + } + TH2 = (count>>8) & 0xff; + TL2 = count & 0xff; + break; + } + } +} + +void mcs51_cpu_device::update_timers(int cycles) +{ + while (cycles--) + { + update_timer_t0(1); + update_timer_t1(1); + + if (m_features & FEATURE_I8052) + { + update_timer_t2(1); + } + } +} + +//Set up to transmit data out of serial port +//NOTE: Enable Serial Port Interrupt bit is NOT required to send/receive data! + +void mcs51_cpu_device::serial_transmit(UINT8 data) +{ + int mode = (GET_SM0<<1) | GET_SM1; + + //Flag that we're sending data + m_uart.data_out = data; + LOG(("serial_transmit: %x %x\n", mode, data)); + switch(mode) { + //8 bit shifter ( + start,stop bit ) - baud set by clock freq / 12 + case 0: + m_uart.bits_to_send = 8+2; + break; + //8 bit uart ( + start,stop bit ) - baud set by timer1 or timer2 + case 1: + m_uart.bits_to_send = 8+2; + break; + //9 bit uart + case 2: + case 3: + m_uart.bits_to_send = 8+3; + break; + } +} + +void mcs51_cpu_device::serial_receive() +{ + int mode = (GET_SM0<<1) | GET_SM1; + + if (GET_REN) { + switch(mode) { + //8 bit shifter ( + start,stop bit ) - baud set by clock freq / 12 + case 0: + m_uart.delay_cycles = 8+2; + break; + //8 bit uart ( + start,stop bit ) - baud set by timer1 or timer2 + case 1: + m_uart.delay_cycles = 8+2; + break; + //9 bit uart + case 2: + case 3: + m_uart.delay_cycles = 8+3; + break; + } + } +} + +/* Check and update status of serial port */ +void mcs51_cpu_device::update_serial(int cycles) +{ + while (--cycles>=0) + transmit_receive(0); +} + +/* Check and update status of serial port */ +void mcs51_cpu_device::update_irq_prio(UINT8 ipl, UINT8 iph) +{ + int i; + for (i=0; i<8; i++) + m_irq_prio[i] = ((ipl >> i) & 1) | (((iph >>i ) & 1) << 1); +} + +/*************************************************************************** + CALLBACKS - TODO: Remove +***************************************************************************/ + + +void mcs51_cpu_device::i8051_set_serial_tx_callback(write8_delegate tx_func) +{ + m_serial_tx_callback = tx_func; +} + +void mcs51_cpu_device::i8051_set_serial_rx_callback(read8_delegate rx_func) +{ + m_serial_rx_callback = rx_func; +} + +/*************************************************************************** + OPCODES +***************************************************************************/ + +#define OPHANDLER( _name ) void mcs51_cpu_device::_name (UINT8 r) + +#include "mcs51ops.inc" + + +void mcs51_cpu_device::execute_op(UINT8 op) +{ + if (m_recalc_parity) + { + set_parity(); + m_recalc_parity = 0; + } + + switch( op ) + { + case 0x00: nop(op); break; //NOP + case 0x01: ajmp(op); break; //AJMP code addr + case 0x02: ljmp(op); break; //LJMP code addr + case 0x03: rr_a(op); break; //RR A + case 0x04: inc_a(op); break; //INC A + case 0x05: RWM=1; inc_mem(op); RWM=0; break; //INC data addr + + case 0x06: + case 0x07: inc_ir(op&1); break; //INC @R0/@R1 + + case 0x08: + case 0x09: + case 0x0a: + case 0x0b: + case 0x0c: + case 0x0d: + case 0x0e: + case 0x0f: inc_r(op&7); break; //INC R0 to R7 + + case 0x10: RWM=1; jbc(op); RWM=0; break; //JBC bit addr, code addr + case 0x11: acall(op); break; //ACALL code addr + case 0x12: lcall(op); break; //LCALL code addr + case 0x13: rrc_a(op); break; //RRC A + case 0x14: dec_a(op); break; //DEC A + case 0x15: RWM=1; dec_mem(op); RWM=0; break; //DEC data addr + + case 0x16: + case 0x17: dec_ir(op&1); break; //DEC @R0/@R1 + + case 0x18: + case 0x19: + case 0x1a: + case 0x1b: + case 0x1c: + case 0x1d: + case 0x1e: + case 0x1f: dec_r(op&7); break; //DEC R0 to R7 + + case 0x20: jb(op); break; //JB bit addr, code addr + case 0x21: ajmp(op); break; //AJMP code addr + case 0x22: ret(op); break; //RET + case 0x23: rl_a(op); break; //RL A + case 0x24: add_a_byte(op); break; //ADD A, #data + case 0x25: add_a_mem(op); break; //ADD A, data addr + + case 0x26: + case 0x27: add_a_ir(op&1); break; //ADD A, @R0/@R1 + + case 0x28: + case 0x29: + case 0x2a: + case 0x2b: + case 0x2c: + case 0x2d: + case 0x2e: + case 0x2f: add_a_r(op&7); break; //ADD A, R0 to R7 + + case 0x30: jnb(op); break; //JNB bit addr, code addr + case 0x31: acall(op); break; //ACALL code addr + case 0x32: reti(op); break; //RETI + case 0x33: rlc_a(op); break; //RLC A + case 0x34: addc_a_byte(op); break; //ADDC A, #data + case 0x35: addc_a_mem(op); break; //ADDC A, data addr + + case 0x36: + case 0x37: addc_a_ir(op&1); break; //ADDC A, @R0/@R1 + + case 0x38: + case 0x39: + case 0x3a: + case 0x3b: + case 0x3c: + case 0x3d: + case 0x3e: + case 0x3f: addc_a_r(op&7); break; //ADDC A, R0 to R7 + + case 0x40: jc(op); break; //JC code addr + case 0x41: ajmp(op); break; //AJMP code addr + case 0x42: RWM=1; orl_mem_a(op); RWM=0; break; //ORL data addr, A + case 0x43: RWM=1; orl_mem_byte(op); RWM=0; break; //ORL data addr, #data + case 0x44: orl_a_byte(op); break; + case 0x45: orl_a_mem(op); break; //ORL A, data addr + + case 0x46: + case 0x47: orl_a_ir(op&1); break; //ORL A, @RO/@R1 + + case 0x48: + case 0x49: + case 0x4a: + case 0x4b: + case 0x4c: + case 0x4d: + case 0x4e: + case 0x4f: orl_a_r(op&7); break; //ORL A, RO to R7 + + case 0x50: jnc(op); break; //JNC code addr + case 0x51: acall(op); break; //ACALL code addr + case 0x52: RWM=1; anl_mem_a(op); RWM=0; break; //ANL data addr, A + case 0x53: RWM=1; anl_mem_byte(op); RWM=0; break; //ANL data addr, #data + case 0x54: anl_a_byte(op); break; //ANL A, #data + case 0x55: anl_a_mem(op); break; //ANL A, data addr + + case 0x56: + case 0x57: anl_a_ir(op&1); break; //ANL A, @RO/@R1 + + case 0x58: + case 0x59: + case 0x5a: + case 0x5b: + case 0x5c: + case 0x5d: + case 0x5e: + case 0x5f: anl_a_r(op&7); break; //ANL A, RO to R7 + + case 0x60: jz(op); break; //JZ code addr + case 0x61: ajmp(op); break; //AJMP code addr + case 0x62: RWM=1; xrl_mem_a(op); RWM=0; break; //XRL data addr, A + case 0x63: RWM=1; xrl_mem_byte(op); RWM=0; break; //XRL data addr, #data + case 0x64: xrl_a_byte(op); break; //XRL A, #data + case 0x65: xrl_a_mem(op); break; //XRL A, data addr + + case 0x66: + case 0x67: xrl_a_ir(op&1); break; //XRL A, @R0/@R1 + + case 0x68: + case 0x69: + case 0x6a: + case 0x6b: + case 0x6c: + case 0x6d: + case 0x6e: + case 0x6f: xrl_a_r(op&7); break; //XRL A, R0 to R7 + + case 0x70: jnz(op); break; //JNZ code addr + case 0x71: acall(op); break; //ACALL code addr + case 0x72: orl_c_bitaddr(op); break; //ORL C, bit addr + case 0x73: jmp_iadptr(op); break; //JMP @A+DPTR + case 0x74: mov_a_byte(op); break; //MOV A, #data + case 0x75: mov_mem_byte(op); break; //MOV data addr, #data + + case 0x76: + case 0x77: mov_ir_byte(op&1); break; //MOV @R0/@R1, #data + + case 0x78: + case 0x79: + case 0x7a: + case 0x7b: + case 0x7c: + case 0x7d: + case 0x7e: + case 0x7f: mov_r_byte(op&7); break; //MOV R0 to R7, #data + + case 0x80: sjmp(op); break; //SJMP code addr + case 0x81: ajmp(op); break; //AJMP code addr + case 0x82: anl_c_bitaddr(op); break; //ANL C, bit addr + case 0x83: movc_a_iapc(op); break; //MOVC A, @A + PC + case 0x84: div_ab(op); break; //DIV AB + case 0x85: mov_mem_mem(op); break; //MOV data addr, data addr + + case 0x86: + case 0x87: mov_mem_ir(op&1); break; //MOV data addr, @R0/@R1 + + case 0x88: + case 0x89: + case 0x8a: + case 0x8b: + case 0x8c: + case 0x8d: + case 0x8e: + case 0x8f: mov_mem_r(op&7); break; //MOV data addr,R0 to R7 + + case 0x90: mov_dptr_byte(op); break; //MOV DPTR, #data + case 0x91: acall(op); break; //ACALL code addr + case 0x92: RWM = 1; mov_bitaddr_c(op); RWM = 0; break; //MOV bit addr, C + case 0x93: movc_a_iadptr(op); break; //MOVC A, @A + DPTR + case 0x94: subb_a_byte(op); break; //SUBB A, #data + case 0x95: subb_a_mem(op); break; //SUBB A, data addr + + case 0x96: + case 0x97: subb_a_ir(op&1); break; //SUBB A, @R0/@R1 + + case 0x98: + case 0x99: + case 0x9a: + case 0x9b: + case 0x9c: + case 0x9d: + case 0x9e: + case 0x9f: subb_a_r(op&7); break; //SUBB A, R0 to R7 + + case 0xa0: orl_c_nbitaddr(op); break; //ORL C, /bit addr + case 0xa1: ajmp(op); break; //AJMP code addr + case 0xa2: mov_c_bitaddr(op); break; //MOV C, bit addr + case 0xa3: inc_dptr(op); break; //INC DPTR + case 0xa4: mul_ab(op); break; //MUL AB + case 0xa5: illegal(op); break; //reserved + + case 0xa6: + case 0xa7: mov_ir_mem(op&1); break; //MOV @R0/@R1, data addr + + case 0xa8: + case 0xa9: + case 0xaa: + case 0xab: + case 0xac: + case 0xad: + case 0xae: + case 0xaf: mov_r_mem(op&7); break; //MOV R0 to R7, data addr + + case 0xb0: anl_c_nbitaddr(op); break; //ANL C,/bit addr + case 0xb1: acall(op); break; //ACALL code addr + case 0xb2: RWM=1; cpl_bitaddr(op); RWM=0; break; //CPL bit addr + case 0xb3: cpl_c(op); break; //CPL C + case 0xb4: cjne_a_byte(op); break; //CJNE A, #data, code addr + case 0xb5: cjne_a_mem(op); break; //CJNE A, data addr, code addr + + case 0xb6: + case 0xb7: cjne_ir_byte(op&1); break; //CJNE @R0/@R1, #data, code addr + + case 0xb8: + case 0xb9: + case 0xba: + case 0xbb: + case 0xbc: + case 0xbd: + case 0xbe: + case 0xbf: cjne_r_byte(op&7); break; //CJNE R0 to R7, #data, code addr + + case 0xc0: push(op); break; //PUSH data addr + case 0xc1: ajmp(op); break; //AJMP code addr + case 0xc2: RWM=1; clr_bitaddr(op); RWM=0; break; //CLR bit addr + case 0xc3: clr_c(op); break; //CLR C + case 0xc4: swap_a(op); break; //SWAP A + case 0xc5: xch_a_mem(op); break; //XCH A, data addr + + case 0xc6: + case 0xc7: xch_a_ir(op&1); break; //XCH A, @RO/@R1 + + case 0xc8: + case 0xc9: + case 0xca: + case 0xcb: + case 0xcc: + case 0xcd: + case 0xce: + case 0xcf: xch_a_r(op&7); break; //XCH A, RO to R7 + + case 0xd0: pop(op); break; //POP data addr + case 0xd1: acall(op); break; //ACALL code addr + case 0xd2: RWM=1; setb_bitaddr(op); RWM=0; break; //SETB bit addr + case 0xd3: setb_c(op); break; //SETB C + case 0xd4: da_a(op); break; //DA A + case 0xd5: RWM=1; djnz_mem(op); RWM=0; break; //DJNZ data addr, code addr + + case 0xd6: + case 0xd7: xchd_a_ir(op&1); break; //XCHD A, @R0/@R1 + + case 0xd8: + case 0xd9: + case 0xda: + case 0xdb: + case 0xdc: + case 0xdd: + case 0xde: + case 0xdf: djnz_r(op&7); break; //DJNZ R0 to R7,code addr + + case 0xe0: movx_a_idptr(op); break; //MOVX A,@DPTR + case 0xe1: ajmp(op); break; //AJMP code addr + + case 0xe2: + case 0xe3: movx_a_ir(op&1); break; //MOVX A, @R0/@R1 + + case 0xe4: clr_a(op); break; //CLR A + case 0xe5: mov_a_mem(op); break; //MOV A, data addr + case 0xe6: + case 0xe7: mov_a_ir(op&1); break; //MOV A,@RO/@R1 + + case 0xe8: + case 0xe9: + case 0xea: + case 0xeb: + case 0xec: + case 0xed: + case 0xee: + case 0xef: mov_a_r(op&7); break; //MOV A,R0 to R7 + + case 0xf0: movx_idptr_a(op); break; //MOVX @DPTR,A + case 0xf1: acall(op); break; //ACALL code addr + + case 0xf2: + case 0xf3: movx_ir_a(op&1); break; //MOVX @R0/@R1,A + + case 0xf4: cpl_a(op); break; //CPL A + case 0xf5: mov_mem_a(op); break; //MOV data addr, A + + case 0xf6: + case 0xf7: mov_ir_a(op&1); break; //MOV @R0/@R1, A + + case 0xf8: + case 0xf9: + case 0xfa: + case 0xfb: + case 0xfc: + case 0xfd: + case 0xfe: + case 0xff: mov_r_a(op&7); break; //MOV R0 to R7, A + default: + illegal(op); + } +} + +/*************************************************************************** + OPCODE CYCLES +***************************************************************************/ + +/* # of oscilations each opcode requires*/ +const UINT8 mcs51_cpu_device::mcs51_cycles[256] = { + 1,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1, + 2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1, + 2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1, + 2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1, + 2,2,1,2,1,1,1,1,1,1,1,1,1,1,1,1, + 2,2,1,2,1,1,1,1,1,1,1,1,1,1,1,1, + 2,2,1,2,1,1,1,1,1,1,1,1,1,1,1,1, + 2,2,2,2,1,2,1,1,1,1,1,1,1,1,1,1, + 2,2,2,2,4,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1, + 2,2,1,2,4,1,2,2,2,2,2,2,2,2,2,2, + 2,2,1,1,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 2,2,1,1,1,2,1,1,2,2,2,2,2,2,2,2, + 2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1, + 2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1 +}; + +/*********************************************************************************** + Check for pending Interrupts and process - returns # of cycles used for the int + + Note about priority & interrupting interrupts.. + 1) A high priority interrupt cannot be interrupted by anything! + 2) A low priority interrupt can ONLY be interrupted by a high priority interrupt + 3) If more than 1 Interrupt Flag is set (ie, 2 simultaneous requests occur), + the following logic works as follows: + 1) If two requests come in of different priority levels, the higher one is selected.. + 2) If the requests are of the same level, an internal order is used: + a) IEO + b) TFO + c) IE1 + d) TF1 + e) RI+TI + f) TF2+EXF2 + **********************************************************************************/ +void mcs51_cpu_device::check_irqs() +{ + UINT8 ints = (GET_IE0 | (GET_TF0<<1) | (GET_IE1<<2) | (GET_TF1<<3) + | ((GET_RI|GET_TI)<<4)); + UINT8 int_vec = 0; + UINT8 int_mask = 0; + int priority_request = -1; + int i; + + //If All Inerrupts Disabled or no pending abort.. + int_mask = (GET_EA ? IE : 0x00); + + if (m_features & FEATURE_I8052) + ints |= ((GET_TF2|GET_EXF2)<<5); + + if (m_features & FEATURE_DS5002FP) + { + ints |= ((GET_PFW)<<5); + m_irq_prio[6] = 3; /* force highest priority */ + /* mask out interrupts not enabled */ + ints &= ((int_mask & 0x1f) | ((GET_EPFW)<<5)); + } + else + { + /* mask out interrupts not enabled */ + ints &= int_mask; + } + + if (!ints) return; + + /* CLear IDL - got enabled interrupt */ + if (m_features & FEATURE_CMOS) + { + /* any interrupt terminates idle mode */ + SET_IDL(0); + /* external interrupt wakes up */ + if (ints & (GET_IE0 | GET_IE1)) + /* but not the DS5002FP */ + if (!(m_features & FEATURE_DS5002FP)) + SET_PD(0); + } + + for (i=0; i priority_request) + { + priority_request = m_irq_prio[i]; + int_vec = (i<<3) | 3; + } + } + } + + /* Skip the interrupt request if currently processing interrupt + * and the new request does not have a higher priority + */ + + LOG(("Request: %d\n", priority_request)); + if (m_irq_active && (priority_request <= m_cur_irq_prio)) + { + LOG(("higher or equal priority irq (%u) in progress already, skipping ...\n", m_cur_irq_prio)); + return; + } + + /* also break out of jb int0, loops */ + if (ROP(PC) == 0x20 && ROP_ARG(PC+1) == 0xb2 && ROP_ARG(PC+2) == 0xfd) + PC += 3; + + //Save current pc to stack, set pc to new interrupt vector + push_pc(); + PC = int_vec; + + /* interrupts take 24 cycles */ + m_inst_cycles += 2; + + //Set current Irq & Priority being serviced + m_cur_irq_prio = priority_request; + m_irq_active |= (1 << priority_request); + + LOG(("Take: %d %02x\n", m_cur_irq_prio, m_irq_active)); + + //Clear any interrupt flags that should be cleared since we're servicing the irq! + switch(int_vec) { + case V_IE0: + //External Int Flag only cleared when configured as Edge Triggered.. + if(GET_IT0) /* for some reason having this, breaks alving dmd games */ + SET_IE0(0); + + /* indicate we took the external IRQ */ + standard_irq_callback(0); + + break; + case V_TF0: + //Timer 0 - Always clear Flag + SET_TF0(0); + break; + case V_IE1: + //External Int Flag only cleared when configured as Edge Triggered.. + if(GET_IT1) /* for some reason having this, breaks alving dmd games */ + SET_IE1(0); + /* indicate we took the external IRQ */ + standard_irq_callback(1); + + break; + case V_TF1: + //Timer 1 - Always clear Flag + SET_TF1(0); + break; + case V_RITI: + /* no flags are cleared, TI and RI remain set until reset by software */ + break; + /* I8052 specific */ + case V_TF2: + /* no flags are cleared according to manual */ + break; + /* DS5002FP specific */ + /* case V_PFI: + * no flags are cleared, PFW is reset by software + * This has the same vector as V_TF2. + */ + + } +} + +void mcs51_cpu_device::burn_cycles(int cycles) +{ + /* Update Timer (if any timers are running) */ + update_timers(cycles); + + /* Update Serial (only for mode 0) */ + update_serial(cycles); + + /* check_irqs */ + check_irqs(); +} + +void mcs51_cpu_device::execute_set_input(int irqline, int state) +{ + /* From the manual: + * + * In operation all the interrupt flags are latched into the + * interrupt control system during State 5 of every machine cycle. + * The samples are polled during the following machine cycle. + * + * ==> Since we do not emulate sub-states, this assumes that the signal is present + * for at least one cycle (12 states) + * + */ + UINT32 new_state = (m_last_line_state & ~(1 << irqline)) | ((state != CLEAR_LINE) << irqline); + /* detect 0->1 transistions */ + UINT32 tr_state = (~m_last_line_state) & new_state; + + switch( irqline ) + { + //External Interrupt 0 + case MCS51_INT0_LINE: + //Line Asserted? + if (state != CLEAR_LINE) { + //Need cleared->active line transition? (Logical 1-0 Pulse on the line) - CLEAR->ASSERT Transition since INT0 active lo! + if (GET_IT0) { + if (GET_BIT(tr_state, MCS51_INT0_LINE)) + SET_IE0(1); + } + else + SET_IE0(1); //Nope, just set it.. + } + else + { + if (!GET_IT0) /* clear if level triggered */ + SET_IE0(0); + } + + break; + + //External Interrupt 1 + case MCS51_INT1_LINE: + + //Line Asserted? + if (state != CLEAR_LINE) { + //Need cleared->active line transition? (Logical 1-0 Pulse on the line) - CLEAR->ASSERT Transition since INT1 active lo! + if(GET_IT1){ + if (GET_BIT(tr_state, MCS51_INT1_LINE)) + SET_IE1(1); + } + else + SET_IE1(1); //Nope, just set it.. + } + else + { + if (!GET_IT1) /* clear if level triggered */ + SET_IE1(0); + } + break; + + case MCS51_T0_LINE: + if (GET_BIT(tr_state, MCS51_T0_LINE) && GET_TR0) + m_t0_cnt++; + break; + + case MCS51_T1_LINE: + if (GET_BIT(tr_state, MCS51_T1_LINE) && GET_TR1) + m_t1_cnt++; + break; + + case MCS51_T2_LINE: + if (m_features & FEATURE_I8052) + { + if (GET_BIT(tr_state, MCS51_T2_LINE) && GET_TR1) + m_t2_cnt++; + } + else + fatalerror("mcs51: Trying to set T2_LINE on a non I8052 type cpu.\n"); + break; + + case MCS51_T2EX_LINE: + if (m_features & FEATURE_I8052) + { + if (GET_BIT(tr_state, MCS51_T2EX_LINE)) + { + SET_EXF2(1); + m_t2ex_cnt++; + } + } + else + fatalerror("mcs51: Trying to set T2EX_LINE on a non I8052 type cpu.\n"); + break; + + case MCS51_RX_LINE: /* Serial Port Receive */ + /* Is the enable flags for this interrupt set? */ + if (state != CLEAR_LINE) + { + serial_receive(); + } + break; + + /* Power Fail Interrupt */ + case DS5002FP_PFI_LINE: + if (m_features & FEATURE_DS5002FP) + { + /* Need cleared->active line transition? (Logical 1-0 Pulse on the line) - CLEAR->ASSERT Transition since INT1 active lo! */ + if (GET_BIT(tr_state, MCS51_INT1_LINE)) + SET_PFW(1); + } + else + fatalerror("mcs51: Trying to set DS5002FP_PFI_LINE on a non DS5002FP type cpu.\n"); + break; + } + m_last_line_state = new_state; +} + +/* Execute cycles - returns number of cycles actually run */ +void mcs51_cpu_device::execute_run() +{ + UINT8 op; + + update_ptrs(); + + /* external interrupts may have been set since we last checked */ + m_inst_cycles = 0; + check_irqs(); + + /* if in powerdown, just return */ + if ((m_features & FEATURE_CMOS) && GET_PD) + { + m_icount = 0; + return; + } + + m_icount -= m_inst_cycles; + burn_cycles(m_inst_cycles); + + if ((m_features & FEATURE_CMOS) && GET_IDL) + { + do + { + /* burn the cycles */ + m_icount--; + burn_cycles(1); + } while( m_icount > 0 ); + return; + } + + do + { + /* Read next opcode */ + PPC = PC; + debugger_instruction_hook(this, PC); + op = m_direct->read_byte(PC++); + + /* process opcode and count cycles */ + m_inst_cycles = mcs51_cycles[op]; + execute_op(op); + + /* burn the cycles */ + m_icount -= m_inst_cycles; + + /* if in powerdown, just return */ + if ((m_features & FEATURE_CMOS) && GET_PD) + return; + + burn_cycles(m_inst_cycles); + + /* decrement the timed access window */ + if (m_features & FEATURE_DS5002FP) + m_ds5002fp.ta_window = (m_ds5002fp.ta_window ? (m_ds5002fp.ta_window - 1) : 0x00); + + /* If the chip entered in idle mode, end the loop */ + if ((m_features & FEATURE_CMOS) && GET_IDL) + return; + + } while( m_icount > 0 ); +} + + +/**************************************************************************** + * MCS51/8051 Section + ****************************************************************************/ + +void mcs51_cpu_device::sfr_write(size_t offset, UINT8 data) +{ + /* update register */ + assert(offset >= 0x80 && offset <= 0xff); + + switch (offset) + { + case ADDR_P0: OUT(MCS51_PORT_P0,data); break; + case ADDR_P1: OUT(MCS51_PORT_P1,data); break; + case ADDR_P2: OUT(MCS51_PORT_P2,data); break; + case ADDR_P3: OUT(MCS51_PORT_P3,data); break; + case ADDR_SBUF: serial_transmit(data); break; + case ADDR_PSW: SET_PARITY(); break; + case ADDR_ACC: SET_PARITY(); break; + case ADDR_IP: update_irq_prio(data, 0); break; + /* R_SBUF = data; //This register is used only for "Receiving data coming in!" */ + + case ADDR_B: + case ADDR_SP: + case ADDR_DPL: + case ADDR_DPH: + case ADDR_PCON: + case ADDR_TCON: + case ADDR_TMOD: + case ADDR_IE: + case ADDR_TL0: + case ADDR_TL1: + case ADDR_TH0: + case ADDR_TH1: + case ADDR_SCON: + break; + default: + LOG(("mcs51 '%s': attemping to write to an invalid/non-implemented SFR address: %x at 0x%04x, data=%x\n", tag(), (UINT32)offset,PC,data)); + /* no write in this case according to manual */ + return; + } + m_data->write_byte((size_t)offset | 0x100, data); +} + +UINT8 mcs51_cpu_device::sfr_read(size_t offset) +{ + assert(offset >= 0x80 && offset <= 0xff); + + switch (offset) + { + /* Read/Write/Modify operations read the port latch ! */ + /* Move to memory map */ + case ADDR_P0: return RWM ? P0 : (P0 | m_forced_inputs[0]) & IN(MCS51_PORT_P0); + case ADDR_P1: return RWM ? P1 : (P1 | m_forced_inputs[1]) & IN(MCS51_PORT_P1); + case ADDR_P2: return RWM ? P2 : (P2 | m_forced_inputs[2]) & IN(MCS51_PORT_P2); + case ADDR_P3: return RWM ? P3 : (P3 | m_forced_inputs[3]) & IN(MCS51_PORT_P3); + + case ADDR_PSW: + case ADDR_ACC: + case ADDR_B: + case ADDR_SP: + case ADDR_DPL: + case ADDR_DPH: + case ADDR_PCON: + case ADDR_TCON: + case ADDR_TMOD: + case ADDR_TL0: + case ADDR_TL1: + case ADDR_TH0: + case ADDR_TH1: + case ADDR_SCON: + case ADDR_SBUF: + case ADDR_IE: + case ADDR_IP: + return m_data->read_byte((size_t) offset | 0x100); + /* Illegal or non-implemented sfr */ + default: + LOG(("mcs51 '%s': attemping to read an invalid/non-implemented SFR address: %x at 0x%04x\n", tag(), (UINT32)offset,PC)); + /* according to the manual, the read may return random bits */ + return 0xff; + } +} + + +void mcs51_cpu_device::device_start() +{ + m_program = &space(AS_PROGRAM); + m_direct = &m_program->direct(); + m_data = &space(AS_DATA); + m_io = &space(AS_IO); + + /* ensure these pointers are set before get_info is called */ + update_ptrs(); + + /* Save states */ + + save_item(NAME(m_ppc)); + save_item(NAME(m_pc)); + save_item(NAME(m_rwm) ); + save_item(NAME(m_cur_irq_prio) ); + save_item(NAME(m_last_line_state) ); + save_item(NAME(m_t0_cnt) ); + save_item(NAME(m_t1_cnt) ); + save_item(NAME(m_t2_cnt) ); + save_item(NAME(m_t2ex_cnt) ); + save_item(NAME(m_recalc_parity) ); + save_item(NAME(m_irq_prio) ); + save_item(NAME(m_irq_active) ); + save_item(NAME(m_ds5002fp.previous_ta) ); + save_item(NAME(m_ds5002fp.ta_window) ); + save_item(NAME(m_ds5002fp.range) ); + save_item(NAME(m_uart.data_out)); + save_item(NAME(m_uart.bits_to_send)); + save_item(NAME(m_uart.smod_div)); + save_item(NAME(m_uart.rx_clk)); + save_item(NAME(m_uart.tx_clk)); + save_item(NAME(m_uart.delay_cycles)); + + state_add( MCS51_PC, "PC", m_pc).formatstr("%04X"); + state_add( MCS51_SP, "SP", SP).formatstr("%02X"); + state_add( MCS51_PSW, "PSW", PSW).formatstr("%02X"); + state_add( MCS51_ACC, "A", ACC).formatstr("%02X"); + state_add( MCS51_B, "B", B).formatstr("%02X"); + state_add( MCS51_DPH, "DPH", DPH).formatstr("%02X"); + state_add( MCS51_DPL, "DPL", DPL).formatstr("%02X"); + state_add( MCS51_IE, "IE", IE).formatstr("%02X"); + state_add( MCS51_R0, "R0", m_rtemp).callimport().callexport().formatstr("%02X"); + state_add( MCS51_R1, "R1", m_rtemp).callimport().callexport().formatstr("%02X"); + state_add( MCS51_R2, "R2", m_rtemp).callimport().callexport().formatstr("%02X"); + state_add( MCS51_R3, "R3", m_rtemp).callimport().callexport().formatstr("%02X"); + state_add( MCS51_R4, "R4", m_rtemp).callimport().callexport().formatstr("%02X"); + state_add( MCS51_R5, "R5", m_rtemp).callimport().callexport().formatstr("%02X"); + state_add( MCS51_R6, "R6", m_rtemp).callimport().callexport().formatstr("%02X"); + state_add( MCS51_R7, "R7", m_rtemp).callimport().callexport().formatstr("%02X"); + state_add( MCS51_RB, "RB", m_rtemp).mask(0x03).callimport().callexport().formatstr("%02X"); + + state_add( STATE_GENPC, "GENPC", m_pc ).noshow(); + state_add( STATE_GENFLAGS, "GENFLAGS", m_rtemp).formatstr("%8s").noshow(); + + m_icountptr = &m_icount; +} + + +void mcs51_cpu_device::state_import(const device_state_entry &entry) +{ + switch (entry.index()) + { + case MCS51_R0: + case MCS51_R1: + case MCS51_R2: + case MCS51_R3: + case MCS51_R4: + case MCS51_R5: + case MCS51_R6: + case MCS51_R7: + SET_REG( entry.index() - MCS51_R0, m_rtemp ); + break; + + case MCS51_RB: + SET_RS( m_rtemp ); + break; + + default: + fatalerror("CPU_IMPORT_STATE(mcs48) called for unexpected value\n"); + } +} + +void mcs51_cpu_device::state_export(const device_state_entry &entry) +{ + switch (entry.index()) + { + case MCS51_R0: + case MCS51_R1: + case MCS51_R2: + case MCS51_R3: + case MCS51_R4: + case MCS51_R5: + case MCS51_R6: + case MCS51_R7: + m_rtemp = R_REG(entry.index() - MCS51_R0); + break; + + case MCS51_RB: + m_rtemp = ((PSW & 0x18)>>3); + break; + + default: + fatalerror("CPU_EXPORT_STATE(mcs51) called for unexpected value\n"); + } +} + +void mcs51_cpu_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + switch (entry.index()) + { + case STATE_GENFLAGS: + strprintf(str,"%c%c%c%c%c%c%c%c", + PSW & 0x80 ? 'C':'.', + PSW & 0x40 ? 'A':'.', + PSW & 0x20 ? 'F':'.', + PSW & 0x10 ? '0':'.', + PSW & 0x08 ? '1':'.', + PSW & 0x04 ? 'V':'.', + PSW & 0x02 ? '?':'.', + PSW & 0x01 ? 'P':'.'); + break; + } +} + +/* Reset registers to the initial values */ +void mcs51_cpu_device::device_reset() +{ + update_ptrs(); + + m_last_line_state = 0; + m_t0_cnt = 0; + m_t1_cnt = 0; + m_t2_cnt = 0; + m_t2ex_cnt = 0; + /* Flag as NO IRQ in Progress */ + m_irq_active = 0; + m_cur_irq_prio = -1; + + /* these are all defined reset states */ + PC = 0; + SP = 0x7; + SET_PSW(0); + SET_ACC(0); + DPH = 0; + DPL = 0; + B = 0; + IP = 0; + update_irq_prio(IP, 0); + IE = 0; + SCON = 0; + TCON = 0; + TMOD = 0; + PCON = 0; + TH1 = 0; + TH0 = 0; + TL1 = 0; + TL0 = 0; + /* set the port configurations to all 1's */ + SET_P3(0xff); + SET_P2(0xff); + SET_P1(0xff); + SET_P0(0xff); + + /* 8052 Only registers */ + if (m_features & FEATURE_I8052) + { + T2CON = 0; + RCAP2L = 0; + RCAP2H = 0; + TL2 = 0; + TH2 = 0; + } + + /* 80C52 Only registers */ + if (m_features & FEATURE_I80C52) + { + IPH = 0; + update_irq_prio(IP, IPH); + SADDR = 0; + SADEN = 0; + } + + /* DS5002FP Only registers */ + if (m_features & FEATURE_DS5002FP) + { + // set initial values (some of them are set using the bootstrap loader) + PCON = 0; + MCON = m_ds5002fp.mcon & 0xfb; + RPCTL = m_ds5002fp.rpctl & 0x01; + RPS = 0; + RNR = 0; + CRCR = m_ds5002fp.crc & 0xf0; + CRCL = 0; + CRCH = 0; + TA = 0; + + // set internal CPU state + m_ds5002fp.previous_ta = 0; + m_ds5002fp.ta_window = 0; + m_ds5002fp.range = (GET_RG1 << 1) | GET_RG0; + } + + m_uart.data_out = 0; + m_uart.rx_clk = 0; + m_uart.tx_clk = 0; + m_uart.bits_to_send = 0; + m_uart.delay_cycles = 0; + m_uart.smod_div = 0; + + m_recalc_parity = 0; +} + + +/**************************************************************************** + * 8052 Section + ****************************************************************************/ + +void i8052_device::sfr_write(size_t offset, UINT8 data) +{ + switch (offset) + { + /* 8052 family specific */ + case ADDR_T2CON: + case ADDR_RCAP2L: + case ADDR_RCAP2H: + case ADDR_TL2: + case ADDR_TH2: + m_data->write_byte((size_t) offset | 0x100, data); + break; + + default: + mcs51_cpu_device::sfr_write(offset, data); + } +} + +UINT8 i8052_device::sfr_read(size_t offset) +{ + switch (offset) + { + /* 8052 family specific */ + case ADDR_T2CON: + case ADDR_RCAP2L: + case ADDR_RCAP2H: + case ADDR_TL2: + case ADDR_TH2: + return m_data->read_byte((size_t) offset | 0x100); + default: + return mcs51_cpu_device::sfr_read(offset); + } +} + + +/**************************************************************************** + * 80C52 Section + ****************************************************************************/ + +void i80c52_device::sfr_write(size_t offset, UINT8 data) +{ + switch (offset) + { + /* 80c52 family specific */ + case ADDR_IP: + update_irq_prio(data, IPH); + break; + case ADDR_IPH: + update_irq_prio(IP, data); + break; + case ADDR_SADDR: + case ADDR_SADEN: + break; + + default: + i8052_device::sfr_write(offset, data); + return; + } + m_data->write_byte((size_t) offset | 0x100, data); +} + +UINT8 i80c52_device::sfr_read(size_t offset) +{ + switch (offset) + { + /* 80c52 family specific */ + case ADDR_IPH: + case ADDR_SADDR: + case ADDR_SADEN: + return m_data->read_byte((size_t) offset | 0x100); + default: + return i8052_device::sfr_read(offset); + } +} + + +/**************************************************************************** + * DS5002FP Section + ****************************************************************************/ + + +#define DS5_LOGW(a, d) LOG(("ds5002fp '%s': write to " # a " register at 0x%04x, data=%x\n", tag(), PC, d)) +#define DS5_LOGR(a, d) LOG(("ds5002fp '%s': read from " # a " register at 0x%04x\n", tag(), PC)) + +UINT8 mcs51_cpu_device::ds5002fp_protected(size_t offset, UINT8 data, UINT8 ta_mask, UINT8 mask) +{ + UINT8 is_timed_access; + + is_timed_access = (m_ds5002fp.ta_window > 0) && (TA == 0x55); + if (is_timed_access) + { + ta_mask = 0xff; + } + data = (m_sfr_ram[offset] & (~ta_mask)) | (data & ta_mask); + return (m_sfr_ram[offset] & (~mask)) | (data & mask); +} + +void ds5002fp_device::sfr_write(size_t offset, UINT8 data) +{ + switch (offset) + { + case ADDR_TA: + m_ds5002fp.previous_ta = TA; + /* init the time window after having wrote 0xaa */ + if ((data == 0xaa) && (m_ds5002fp.ta_window == 0)) + { + m_ds5002fp.ta_window = 6; /* 4*12 + 2*12 */ + LOG(("ds5002fp '%s': TA window initiated at 0x%04x\n", tag(), PC)); + } + break; + case ADDR_MCON: data = ds5002fp_protected(ADDR_MCON, data, 0x0f, 0xf7); DS5_LOGW(MCON, data); break; + case ADDR_RPCTL: data = ds5002fp_protected(ADDR_RPCTL, data, 0xef, 0xfe); DS5_LOGW(RPCTL, data); break; + case ADDR_CRCR: data = ds5002fp_protected(ADDR_CRCR, data, 0xff, 0x0f); DS5_LOGW(CRCR, data); break; + case ADDR_PCON: data = ds5002fp_protected(ADDR_PCON, data, 0xb9, 0xff); break; + case ADDR_IP: data = ds5002fp_protected(ADDR_IP, data, 0x7f, 0xff); break; + case ADDR_CRCL: DS5_LOGW(CRCL, data); break; + case ADDR_CRCH: DS5_LOGW(CRCH, data); break; + case ADDR_RNR: DS5_LOGW(RNR, data); break; + case ADDR_RPS: DS5_LOGW(RPS, data); break; + default: + mcs51_cpu_device::sfr_write(offset, data); + return; + } + m_data->write_byte((size_t) offset | 0x100, data); +} + +UINT8 ds5002fp_device::sfr_read(size_t offset) +{ + switch (offset) + { + case ADDR_CRCR: DS5_LOGR(CRCR, data); break; + case ADDR_CRCL: DS5_LOGR(CRCL, data); break; + case ADDR_CRCH: DS5_LOGR(CRCH, data); break; + case ADDR_MCON: DS5_LOGR(MCON, data); break; + case ADDR_TA: DS5_LOGR(TA, data); break; + case ADDR_RNR: DS5_LOGR(RNR, data); break; + case ADDR_RPCTL: DS5_LOGR(RPCTL, data); break; + case ADDR_RPS: DS5_LOGR(RPS, data); break; + case ADDR_PCON: + SET_PFW(0); /* reset PFW flag */ + return mcs51_cpu_device::sfr_read(offset); + default: + return mcs51_cpu_device::sfr_read(offset); + } + return m_data->read_byte((size_t) offset | 0x100); +} + + +offs_t mcs51_cpu_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( i8051 ); + return CPU_DISASSEMBLE_NAME(i8051)(this, buffer, pc, oprom, opram, options); +} + + +offs_t i8052_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( i8052 ); + return CPU_DISASSEMBLE_NAME(i8052)(this, buffer, pc, oprom, opram, options); +} + + +offs_t i80c31_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( i80c51 ); + return CPU_DISASSEMBLE_NAME(i80c51)(this, buffer, pc, oprom, opram, options); +} + + +offs_t i80c51_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( i80c51 ); + return CPU_DISASSEMBLE_NAME(i80c51)(this, buffer, pc, oprom, opram, options); +} + + +offs_t i80c52_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( i80c52 ); + return CPU_DISASSEMBLE_NAME(i80c52)(this, buffer, pc, oprom, opram, options); +} + + +offs_t ds5002fp_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( ds5002fp ); + return CPU_DISASSEMBLE_NAME(ds5002fp)(this, buffer, pc, oprom, opram, options); +} diff --git a/src/devices/cpu/mcs51/mcs51.h b/src/devices/cpu/mcs51/mcs51.h new file mode 100644 index 00000000000..e8effbbd950 --- /dev/null +++ b/src/devices/cpu/mcs51/mcs51.h @@ -0,0 +1,518 @@ +// license:BSD-3-Clause +// copyright-holders:Steve Ellenoff, Manuel Abadia, Couriersud +/***************************************************************************** + * + * mcs51.h + * Portable MCS-51 Family Emulator + * + * Chips in the family: + * 8051 Product Line (8031,8051,8751) + * 8052 Product Line (8032,8052,8752) + * 8054 Product Line (8054) + * 8058 Product Line (8058) + * + * Copyright Steve Ellenoff, all rights reserved. + * + * This work is based on: + * #1) 'Intel(tm) MC51 Microcontroller Family Users Manual' and + * #2) 8051 simulator by Travis Marlatte + * #3) Portable UPI-41/8041/8741/8042/8742 emulator V0.1 by Juergen Buchmueller (MAME CORE) + * + * 2008, October, Couriersud + * - Rewrite of timer, interrupt and serial code + * - addition of CMOS features + * - internal memory maps + * - addition of new processor types + * - full emulation of 8xCx2 processors + *****************************************************************************/ + +#pragma once + +#ifndef __MCS51_H__ +#define __MCS51_H__ + + +enum +{ + MCS51_PC=1, MCS51_SP, MCS51_PSW, MCS51_ACC, MCS51_B, MCS51_DPH, MCS51_DPL, MCS51_IE, + MCS51_R0, MCS51_R1, MCS51_R2, MCS51_R3, MCS51_R4, MCS51_R5, MCS51_R6, MCS51_R7, MCS51_RB +}; + +enum +{ + MCS51_INT0_LINE = 0, /* P3.2: External Interrupt 0 */ + MCS51_INT1_LINE, /* P3.3: External Interrupt 1 */ + MCS51_RX_LINE, /* P3.0: Serial Port Receive Line */ + MCS51_T0_LINE, /* P3,4: Timer 0 External Input */ + MCS51_T1_LINE, /* P3.5: Timer 1 External Input */ + MCS51_T2_LINE, /* P1.0: Timer 2 External Input */ + MCS51_T2EX_LINE, /* P1.1: Timer 2 Capture Reload Trigger */ + + DS5002FP_PFI_LINE /* DS5002FP Power fail interrupt */ +}; + +/* special I/O space ports */ + +enum +{ + MCS51_PORT_P0 = 0x20000, + MCS51_PORT_P1 = 0x20001, + MCS51_PORT_P2 = 0x20002, + MCS51_PORT_P3 = 0x20003, + MCS51_PORT_TX = 0x20004 /* P3.1 */ +}; + +/* At least CMOS devices may be forced to read from ports configured as output. + * All you need is a low impedance output connect to the port. + */ + +#define MCFG_MCS51_PORT1_CONFIG(_forced_inputs) \ + mcs51_cpu_device::set_port_forced_input(*device, 1, _forced_inputs); +#define MCFG_MCS51_PORT2_CONFIG(_forced_inputs) \ + mcs51_cpu_device::set_port_forced_input(*device, 2, _forced_inputs); +#define MCFG_MCS51_PORT3_CONFIG(_forced_inputs) \ + mcs51_cpu_device::set_port_forced_input(*device, 3, _forced_inputs); + +class mcs51_cpu_device : public cpu_device +{ +public: + // construction/destruction + mcs51_cpu_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, int program_width, int data_width, UINT8 features = 0); + + void i8051_set_serial_tx_callback(write8_delegate tx_func); + void i8051_set_serial_rx_callback(read8_delegate rx_func); + + // configuration helpers + static void set_port_forced_input(device_t &device, UINT8 port, UINT8 forced_input) { downcast(device).m_forced_inputs[port] = forced_input; } + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_execute_interface overrides + virtual UINT64 execute_clocks_to_cycles(UINT64 clocks) const { return (clocks + 12 - 1) / 12; } + virtual UINT64 execute_cycles_to_clocks(UINT64 cycles) const { return (cycles * 12); } + virtual UINT32 execute_min_cycles() const { return 1; } + virtual UINT32 execute_max_cycles() const { return 20; } + virtual UINT32 execute_input_lines() const { return 6; } + virtual UINT32 execute_default_irq_vector() const { return 0; } + virtual void execute_run(); + virtual void execute_set_input(int inputnum, int state); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const + { + return (spacenum == AS_PROGRAM) ? &m_program_config : ( (spacenum == AS_IO) ? &m_io_config : ( (spacenum == AS_DATA) ? &m_data_config : NULL ) ); + } + + // device_state_interface overrides + virtual void state_import(const device_state_entry &entry); + virtual void state_export(const device_state_entry &entry); + void state_string_export(const device_state_entry &entry, std::string &str); + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const { return 1; } + virtual UINT32 disasm_max_opcode_bytes() const { return 5; } + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + +protected: + address_space_config m_program_config; + address_space_config m_data_config; + address_space_config m_io_config; + + //Internal stuff + UINT16 m_ppc; //previous pc + UINT16 m_pc; //current pc + UINT16 m_features; //features of this cpu + UINT8 m_rwm; //Signals that the current instruction is a read/write/modify instruction + + int m_inst_cycles; /* cycles for the current instruction */ + int m_ram_mask; /* second ram bank for indirect access available ? */ + int m_num_interrupts; /* number of interrupts supported */ + int m_recalc_parity; /* recalculate parity before next instruction */ + UINT32 m_last_line_state; /* last state of input lines line */ + int m_t0_cnt; /* number of 0->1 transistions on T0 line */ + int m_t1_cnt; /* number of 0->1 transistions on T1 line */ + int m_t2_cnt; /* number of 0->1 transistions on T2 line */ + int m_t2ex_cnt; /* number of 0->1 transistions on T2EX line */ + int m_cur_irq_prio; /* Holds value of the current IRQ Priority Level; -1 if no irq */ + UINT8 m_irq_active; /* mask which irq levels are serviced */ + UINT8 m_irq_prio[8]; /* interrupt priority */ + + UINT8 m_forced_inputs[4]; /* allow read even if configured as output */ + + int m_icount; + + struct mcs51_uart + { + UINT8 data_out; //Data to send out + UINT8 bits_to_send; //How many bits left to send when transmitting out the serial port + + int smod_div; /* signal divided by 2^SMOD */ + int rx_clk; /* rx clock */ + int tx_clk; /* tx clock */ + UINT8 delay_cycles; //Gross Hack; + } m_uart; /* internal uart */ + + /* Internal Ram */ + UINT8 *m_internal_ram; /* 128 RAM (8031/51) + 128 RAM in second bank (8032/52) */ + UINT8 *m_sfr_ram; /* 128 SFR - these are in 0x80 - 0xFF */ + + /* SFR Callbacks */ + virtual void sfr_write(size_t offset, UINT8 data); + virtual UINT8 sfr_read(size_t offset); + + /* Memory spaces */ + address_space *m_program; + direct_read_data *m_direct; + address_space *m_data; + address_space *m_io; + + /* Serial Port TX/RX Callbacks */ + // TODO: Move to special port r/w + write8_delegate m_serial_tx_callback; //Call back funciton when sending data out of serial port + read8_delegate m_serial_rx_callback; //Call back function to retrieve data when receiving serial port data + + /* DS5002FP */ + struct { + UINT8 previous_ta; /* Previous Timed Access value */ + UINT8 ta_window; /* Limed Access window */ + UINT8 range; /* Memory Range */ + /* Bootstrap Configuration */ + UINT8 mcon; /* bootstrap loader MCON register */ + UINT8 rpctl; /* bootstrap loader RPCTL register */ + UINT8 crc; /* bootstrap loader CRC register */ + } m_ds5002fp; + + // for the debugger + UINT8 m_rtemp; + + static const UINT8 mcs51_cycles[256]; + + UINT8 iram_iread(offs_t a); + void iram_iwrite(offs_t a, UINT8 d); + void clear_current_irq(); + UINT8 r_acc(); + UINT8 r_psw(); + void update_ptrs(); + offs_t external_ram_iaddr(offs_t offset, offs_t mem_mask); + UINT8 iram_read(size_t offset); + void iram_write(size_t offset, UINT8 data); + void push_pc(); + void pop_pc(); + void set_parity(); + UINT8 bit_address_r(UINT8 offset); + void bit_address_w(UINT8 offset, UINT8 bit); + void do_add_flags(UINT8 a, UINT8 data, UINT8 c); + void do_sub_flags(UINT8 a, UINT8 data, UINT8 c); + void transmit_receive(int source); + void update_timer_t0(int cycles); + void update_timer_t1(int cycles); + void update_timer_t2(int cycles); + void update_timers(int cycles); + void serial_transmit(UINT8 data); + void serial_receive(); + void update_serial(int cycles); + void update_irq_prio(UINT8 ipl, UINT8 iph); + void execute_op(UINT8 op); + void check_irqs(); + void burn_cycles(int cycles); + void acall(UINT8 r); + void add_a_byte(UINT8 r); + void add_a_mem(UINT8 r); + void add_a_ir(UINT8 r); + void add_a_r(UINT8 r); + void addc_a_byte(UINT8 r); + void addc_a_mem(UINT8 r); + void addc_a_ir(UINT8 r); + void addc_a_r(UINT8 r); + void ajmp(UINT8 r); + void anl_mem_a(UINT8 r); + void anl_mem_byte(UINT8 r); + void anl_a_byte(UINT8 r); + void anl_a_mem(UINT8 r); + void anl_a_ir(UINT8 r); + void anl_a_r(UINT8 r); + void anl_c_bitaddr(UINT8 r); + void anl_c_nbitaddr(UINT8 r); + void cjne_a_byte(UINT8 r); + void cjne_a_mem(UINT8 r); + void cjne_ir_byte(UINT8 r); + void cjne_r_byte(UINT8 r); + void clr_bitaddr(UINT8 r); + void clr_c(UINT8 r); + void clr_a(UINT8 r); + void cpl_bitaddr(UINT8 r); + void cpl_c(UINT8 r); + void cpl_a(UINT8 r); + void da_a(UINT8 r); + void dec_a(UINT8 r); + void dec_mem(UINT8 r); + void dec_ir(UINT8 r); + void dec_r(UINT8 r); + void div_ab(UINT8 r); + void djnz_mem(UINT8 r); + void djnz_r(UINT8 r); + void inc_a(UINT8 r); + void inc_mem(UINT8 r); + void inc_ir(UINT8 r); + void inc_r(UINT8 r); + void inc_dptr(UINT8 r); + void jb(UINT8 r); + void jbc(UINT8 r); + void jc(UINT8 r); + void jmp_iadptr(UINT8 r); + void jnb(UINT8 r); + void jnc(UINT8 r); + void jnz(UINT8 r); + void jz(UINT8 r); + void lcall(UINT8 r); + void ljmp(UINT8 r); + void mov_a_byte(UINT8 r); + void mov_a_mem(UINT8 r); + void mov_a_ir(UINT8 r); + void mov_a_r(UINT8 r); + void mov_mem_byte(UINT8 r); + void mov_mem_mem(UINT8 r); + void mov_ir_byte(UINT8 r); + void mov_r_byte(UINT8 r); + void mov_mem_ir(UINT8 r); + void mov_mem_r(UINT8 r); + void mov_dptr_byte(UINT8 r); + void mov_bitaddr_c(UINT8 r); + void mov_ir_mem(UINT8 r); + void mov_r_mem(UINT8 r); + void mov_mem_a(UINT8 r); + void mov_ir_a(UINT8 r); + void mov_r_a(UINT8 r); + void movc_a_iapc(UINT8 r); + void mov_c_bitaddr(UINT8 r); + void movc_a_iadptr(UINT8 r); + void movx_a_idptr(UINT8 r); + void movx_a_ir(UINT8 r); + void movx_idptr_a(UINT8 r); + void movx_ir_a(UINT8 r); + void mul_ab(UINT8 r); + void nop(UINT8 r); + void orl_mem_a(UINT8 r); + void orl_mem_byte(UINT8 r); + void orl_a_byte(UINT8 r); + void orl_a_mem(UINT8 r); + void orl_a_ir(UINT8 r); + void orl_a_r(UINT8 r); + void orl_c_bitaddr(UINT8 r); + void orl_c_nbitaddr(UINT8 r); + void pop(UINT8 r); + void push(UINT8 r); + void ret(UINT8 r); + void reti(UINT8 r); + void rl_a(UINT8 r); + void rlc_a(UINT8 r); + void rr_a(UINT8 r); + void rrc_a(UINT8 r); + void setb_c(UINT8 r); + void setb_bitaddr(UINT8 r); + void sjmp(UINT8 r); + void subb_a_byte(UINT8 r); + void subb_a_mem(UINT8 r); + void subb_a_ir(UINT8 r); + void subb_a_r(UINT8 r); + void swap_a(UINT8 r); + void xch_a_mem(UINT8 r); + void xch_a_ir(UINT8 r); + void xch_a_r(UINT8 r); + void xchd_a_ir(UINT8 r); + void xrl_mem_a(UINT8 r); + void xrl_mem_byte(UINT8 r); + void xrl_a_byte(UINT8 r); + void xrl_a_mem(UINT8 r); + void xrl_a_ir(UINT8 r); + void xrl_a_r(UINT8 r); + void illegal(UINT8 r); + UINT8 ds5002fp_protected(size_t offset, UINT8 data, UINT8 ta_mask, UINT8 mask); + +}; + + +/* variants with no internal rom and 128 byte internal memory */ +extern const device_type I8031; +/* variants with no internal rom and 256 byte internal memory */ +extern const device_type I8032; +/* variants 4k internal rom and 128 byte internal memory */ +extern const device_type I8051; +extern const device_type I8751; +/* variants 8k internal rom and 256 byte internal memory and more registers */ +extern const device_type I8052; +extern const device_type I8752; +/* cmos variants */ +extern const device_type I80C31; +extern const device_type I80C51; +extern const device_type I87C51; +extern const device_type I80C32; +extern const device_type I80C52; +extern const device_type I87C52; +/* 4k internal perom and 128 internal ram and 2 analog comparators */ +extern const device_type AT89C4051; + +extern const device_type DS5002FP; + + +class i8031_device : public mcs51_cpu_device +{ +public: + // construction/destruction + i8031_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class i8051_device : public mcs51_cpu_device +{ +public: + // construction/destruction + i8051_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class i8751_device : public mcs51_cpu_device +{ +public: + // construction/destruction + i8751_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +class i8052_device : public mcs51_cpu_device +{ +public: + // construction/destruction + i8052_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + i8052_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, int program_width, int data_width, UINT8 features = 0); + +protected: + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + + /* SFR Callbacks */ + virtual void sfr_write(size_t offset, UINT8 data); + virtual UINT8 sfr_read(size_t offset); +}; + +class i8032_device : public i8052_device +{ +public: + // construction/destruction + i8032_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class i8752_device : public i8052_device +{ +public: + // construction/destruction + i8752_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class i80c31_device : public i8052_device +{ +public: + // construction/destruction + i80c31_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); +}; + + +class i80c51_device : public mcs51_cpu_device +{ +public: + // construction/destruction + i80c51_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + i80c51_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, int program_width, int data_width, UINT8 features = 0); + +protected: + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); +}; + +class i87c51_device : public i80c51_device +{ +public: + // construction/destruction + i87c51_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +class i80c52_device : public i8052_device +{ +public: + // construction/destruction + i80c52_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + i80c52_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, int program_width, int data_width, UINT8 features = 0); + +protected: + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + + /* SFR Callbacks */ + virtual void sfr_write(size_t offset, UINT8 data); + virtual UINT8 sfr_read(size_t offset); +}; + +class i80c32_device : public i80c52_device +{ +public: + // construction/destruction + i80c32_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class i87c52_device : public i80c52_device +{ +public: + // construction/destruction + i87c52_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class at89c4051_device : public i80c51_device +{ +public: + // construction/destruction + at89c4051_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +/* + * The DS5002FP has 2 16 bits data address buses (the byte-wide bus and the expanded bus). The exact memory position accessed depends on the + * partition mode, the memory range and the expanded bus select. The partition mode and the expanded bus select can be changed at any time. + * + * In order to simplify memory mapping to the data address bus, the following address map is assumed for partitioned mode: + + * 0x00000-0x0ffff -> data memory on the expanded bus + * 0x10000-0x1ffff -> data memory on the byte-wide bus + + * For non-partitioned mode the following memory map is assumed: + + * 0x0000-0xffff -> data memory (the bus used to access it does not matter) + * + * Internal ram 128k and security features + */ + +#define MCFG_DS5002FP_CONFIG(_mcon, _rpctl, _crc) \ + ds5002fp_device::set_mcon(*device, _mcon); \ + ds5002fp_device::set_rpctl(*device, _rpctl); \ + ds5002fp_device::set_crc(*device, _crc); + +class ds5002fp_device : public mcs51_cpu_device +{ +public: + // construction/destruction + ds5002fp_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + static void set_mcon(device_t &device, UINT8 mcon) { downcast(device).m_ds5002fp.mcon = mcon; } + static void set_rpctl(device_t &device, UINT8 rpctl) { downcast(device).m_ds5002fp.rpctl = rpctl; } + static void set_crc(device_t &device, UINT8 crc) { downcast(device).m_ds5002fp.crc = crc; } + +protected: + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + + /* SFR Callbacks */ + virtual void sfr_write(size_t offset, UINT8 data); + virtual UINT8 sfr_read(size_t offset); +}; + + +#endif /* __MCS51_H__ */ diff --git a/src/devices/cpu/mcs51/mcs51dasm.c b/src/devices/cpu/mcs51/mcs51dasm.c new file mode 100644 index 00000000000..9c0758c4e35 --- /dev/null +++ b/src/devices/cpu/mcs51/mcs51dasm.c @@ -0,0 +1,1213 @@ +// license:BSD-3-Clause +// copyright-holders:Steve Ellenoff +/***************************************************************************** + * + * i8051dasm.c + * Portable MCS-51 Family Emulator + * + * Chips in the family: + * 8051 Product Line (8031,8051,8751) + * 8052 Product Line (8032,8052,8752) + * 8054 Product Line (8054) + * 8058 Product Line (8058) + * + * Copyright Steve Ellenoff, all rights reserved. + * + * This work is based on: + * #1) 'Intel(tm) MC51 Microcontroller Family Users Manual' and + * #2) 8051 simulator by Travis Marlatte + * #3) Portable UPI-41/8041/8741/8042/8742 emulator V0.1 by Juergen Buchmueller (MAME CORE) + * + ***************************************************************************** + * Symbol Memory Name Tables borrowed from: + * D52 8052 Disassembler - Copyright Jeffery L. Post + *****************************************************************************/ + +#include "emu.h" +#include "debugger.h" +#include "mcs51.h" + +enum +{ + FEATURE_NONE = 0x00, + FEATURE_I8052 = 0x01, + FEATURE_CMOS = 0x02, + FEATURE_I80C52 = 0x04, + FEATURE_DS5002FP = 0x08, + FEATURE_I83C751 = 0x08 +}; + + +#define SHOW_MEMORY_NAMES 1 + +#ifdef SHOW_MEMORY_NAMES + +/*Display the memory address names for data & bit address access*/ + +//SFR Names + +static const struct { + int feature; + int addr; + const char *name; +} mem_name_feature[] = +{ + { FEATURE_NONE, 0x00, "rb0r0" }, + { FEATURE_NONE, 0x01, "rb0r1" }, + { FEATURE_NONE, 0x02, "rb0r2" }, + { FEATURE_NONE, 0x03, "rb0r3" }, + { FEATURE_NONE, 0x04, "rb0r4" }, + { FEATURE_NONE, 0x05, "rb0r5" }, + { FEATURE_NONE, 0x06, "rb0r6" }, + { FEATURE_NONE, 0x07, "rb0r7" }, + { FEATURE_NONE, 0x08, "rb1r0" }, + { FEATURE_NONE, 0x09, "rb1r1" }, + { FEATURE_NONE, 0x0a, "rb1r2" }, + { FEATURE_NONE, 0x0b, "rb1r3" }, + { FEATURE_NONE, 0x0c, "rb1r4" }, + { FEATURE_NONE, 0x0d, "rb1r5" }, + { FEATURE_NONE, 0x0e, "rb1r6" }, + { FEATURE_NONE, 0x0f, "rb1r7" }, + { FEATURE_NONE, 0x10, "rb2r0" }, + { FEATURE_NONE, 0x11, "rb2r1" }, + { FEATURE_NONE, 0x12, "rb2r2" }, + { FEATURE_NONE, 0x13, "rb2r3" }, + { FEATURE_NONE, 0x14, "rb2r4" }, + { FEATURE_NONE, 0x15, "rb2r5" }, + { FEATURE_NONE, 0x16, "rb2r6" }, + { FEATURE_NONE, 0x17, "rb2r7" }, + { FEATURE_NONE, 0x18, "rb3r0" }, + { FEATURE_NONE, 0x19, "rb3r1" }, + { FEATURE_NONE, 0x1a, "rb3r2" }, + { FEATURE_NONE, 0x1b, "rb3r3" }, + { FEATURE_NONE, 0x1c, "rb3r4" }, + { FEATURE_NONE, 0x1d, "rb3r5" }, + { FEATURE_NONE, 0x1e, "rb3r6" }, + { FEATURE_NONE, 0x1f, "rb3r7" }, + + { FEATURE_NONE, 0x80, "p0" }, + { FEATURE_NONE, 0x81, "sp" }, + { FEATURE_NONE, 0x82, "dpl" }, + { FEATURE_NONE, 0x83, "dph" }, + { FEATURE_NONE, 0x87, "pcon" }, + { FEATURE_NONE, 0x88, "tcon" }, + { FEATURE_NONE, 0x89, "tmod" }, + { FEATURE_NONE, 0x8a, "tl0" }, + { FEATURE_NONE, 0x8b, "tl1" }, + { FEATURE_NONE, 0x8c, "th0" }, + { FEATURE_NONE, 0x8d, "th1" }, + { FEATURE_NONE, 0x90, "p1" }, + { FEATURE_NONE, 0x98, "scon" }, + { FEATURE_NONE, 0x99, "sbuf" }, + { FEATURE_NONE, 0xa0, "p2" }, + { FEATURE_NONE, 0xa8, "ie" }, + { FEATURE_NONE, 0xb0, "p3" }, + { FEATURE_NONE, 0xb8, "ip" }, + { FEATURE_NONE, 0xd0, "psw" }, + { FEATURE_NONE, 0xe0, "acc" }, + { FEATURE_NONE, 0xf0, "b" }, + + { FEATURE_I8052, 0xc8, "t2con" }, + { FEATURE_I8052, 0xca, "rcap2l" }, + { FEATURE_I8052, 0xcb, "rcap2h" }, + { FEATURE_I8052, 0xcc, "tl2" }, + { FEATURE_I8052, 0xcd, "th2" }, + + { FEATURE_I80C52, 0xb7, "iph" }, + { FEATURE_I80C52, 0xa9, "saddr" }, + { FEATURE_I80C52, 0xb9, "saden" }, + + { FEATURE_DS5002FP, 0x8e, "pwcm" }, + { FEATURE_DS5002FP, 0x8f, "pwmp" }, + { FEATURE_DS5002FP, 0xc1, "crcr" }, + { FEATURE_DS5002FP, 0xc2, "crcl" }, + { FEATURE_DS5002FP, 0xc3, "crch" }, + { FEATURE_DS5002FP, 0xc6, "mcon" }, + { FEATURE_DS5002FP, 0xc7, "ta" }, + { FEATURE_DS5002FP, 0xcf, "rnr" }, + { FEATURE_DS5002FP, 0xd8, "rpctl" }, + { FEATURE_DS5002FP, 0xd9, "rps" }, + + { FEATURE_I83C751, 0x98, "i2con" }, + { FEATURE_I83C751, 0x99, "i2dat" }, + { FEATURE_I83C751, 0xd8, "i2cfg" }, + { FEATURE_I83C751, 0xf8, "i2sta" }, /* read only */ + + /* bit addresses */ + + { FEATURE_NONE, 0x188, "it0" }, + { FEATURE_NONE, 0x189, "ie0" }, + { FEATURE_NONE, 0x18a, "it1" }, + { FEATURE_NONE, 0x18b, "ie1" }, + { FEATURE_NONE, 0x18c, "tr0" }, + { FEATURE_NONE, 0x18d, "tf0" }, + { FEATURE_NONE, 0x18e, "tr1" }, + { FEATURE_NONE, 0x18f, "tf1" }, + + { FEATURE_NONE, 0x198, "ri" }, + { FEATURE_NONE, 0x199, "ti" }, + { FEATURE_NONE, 0x19a, "rb8" }, + { FEATURE_NONE, 0x19b, "tb8" }, + { FEATURE_NONE, 0x19c, "ren" }, + { FEATURE_NONE, 0x19d, "sm2" }, + { FEATURE_NONE, 0x19e, "sm1" }, + { FEATURE_NONE, 0x19f, "sm0" }, + + { FEATURE_I83C751, 0x198, "xstp" }, /* read: no function */ + { FEATURE_I83C751, 0x199, "xstr" }, /* read: MASTER */ + { FEATURE_I83C751, 0x19a, "cstp" }, /* read: STP */ + { FEATURE_I83C751, 0x19b, "cstr" }, /* read: STR */ + { FEATURE_I83C751, 0x19c, "carl" }, /* read: ARL */ + { FEATURE_I83C751, 0x19d, "cdr" }, /* read: DRDY */ + { FEATURE_I83C751, 0x19e, "idle" }, /* read: ATN */ + { FEATURE_I83C751, 0x19f, "cxa" }, /* read: RDAT */ + + { FEATURE_NONE, 0x1a8, "ex0" }, + { FEATURE_NONE, 0x1a9, "et0" }, + { FEATURE_NONE, 0x1aa, "ex1" }, + { FEATURE_NONE, 0x1ab, "et1" }, + { FEATURE_NONE, 0x1ac, "es" }, + { FEATURE_NONE, 0x1ad, "ie.5" }, + { FEATURE_NONE, 0x1ae, "ie.6" }, + { FEATURE_NONE, 0x1af, "ea" }, + + { FEATURE_I83C751, 0x1ac, "ei2" }, + { FEATURE_I8052, 0x1ad, "et2" }, + + /* FIXME: port 3 - depends on external circuits and not really + * implemented in the core. TBD */ + { FEATURE_NONE, 0x1b0, "rxd" }, + { FEATURE_NONE, 0x1b1, "txd" }, + { FEATURE_NONE, 0x1b2, "int0" }, + { FEATURE_NONE, 0x1b3, "int1" }, + { FEATURE_NONE, 0x1b4, "t0" }, + { FEATURE_NONE, 0x1b5, "t1" }, + { FEATURE_NONE, 0x1b6, "wr" }, + { FEATURE_NONE, 0x1b7, "rd" }, + + { FEATURE_NONE, 0x1b8, "px0" }, + { FEATURE_NONE, 0x1b9, "pt0" }, + { FEATURE_NONE, 0x1ba, "px1" }, + { FEATURE_NONE, 0x1bb, "pt1" }, + { FEATURE_NONE, 0x1bc, "ps" }, + { FEATURE_NONE, 0x1bd, "ip.5" }, + { FEATURE_NONE, 0x1be, "ip.6" }, + { FEATURE_NONE, 0x1bf, "ip.7" }, + + { FEATURE_I8052, 0x1bd, "pt2" }, + { FEATURE_I83C751, 0x1bc, "pi2" }, + + { FEATURE_I8052, 0x1c8, "cprl2" }, + { FEATURE_I8052, 0x1c9, "ct2" }, + { FEATURE_I8052, 0x1ca, "tr2" }, + { FEATURE_I8052, 0x1cb, "exen2" }, + { FEATURE_I8052, 0x1cc, "tclk" }, + { FEATURE_I8052, 0x1cd, "rclk" }, + { FEATURE_I8052, 0x1ce, "exf2" }, + { FEATURE_I8052, 0x1cf, "tf2" }, + + { FEATURE_NONE, 0x1d0, "p" }, + { FEATURE_NONE, 0x1d1, "psw.1" }, + { FEATURE_NONE, 0x1d2, "ov" }, + { FEATURE_NONE, 0x1d3, "rs0" }, + { FEATURE_NONE, 0x1d4, "rs1" }, + { FEATURE_NONE, 0x1d5, "f0" }, + { FEATURE_NONE, 0x1d6, "ac" }, + { FEATURE_NONE, 0x1d7, "cy" }, + + { FEATURE_DS5002FP, 0x1d8, "rg0" }, + { FEATURE_DS5002FP, 0x1d9, "rpc" }, + { FEATURE_DS5002FP, 0x1da, "dma" }, + { FEATURE_DS5002FP, 0x1db, "ibi" }, + { FEATURE_DS5002FP, 0x1dc, "ae" }, + { FEATURE_DS5002FP, 0x1dd, "exbs" }, + { FEATURE_DS5002FP, 0x1de, "d8.6" }, + { FEATURE_DS5002FP, 0x1df, "rnr" }, + + { FEATURE_I83C751, 0x1d8, "ct0" }, + { FEATURE_I83C751, 0x1d9, "ct1" }, + { FEATURE_I83C751, 0x1da, "i2cfg.2" }, + { FEATURE_I83C751, 0x1db, "i2cfg.3" }, + { FEATURE_I83C751, 0x1dc, "tirun" }, + { FEATURE_I83C751, 0x1dd, "clrti" }, + { FEATURE_I83C751, 0x1de, "masterq" }, + { FEATURE_I83C751, 0x1df, "slaven" }, + + { FEATURE_I83C751, 0x1f8, "xstp" }, + { FEATURE_I83C751, 0x1f9, "xstr" }, + { FEATURE_I83C751, 0x1fa, "makstp" }, + { FEATURE_I83C751, 0x1fb, "makstr" }, + { FEATURE_I83C751, 0x1fc, "xactv" }, + { FEATURE_I83C751, 0x1fd, "xdata" }, + { FEATURE_I83C751, 0x1fe, "idle" }, + { FEATURE_I83C751, 0x1ff, "i2sta.7" }, + + /* unknown + * "ibf", "obf", "idsm", "obfc", e8 - eb + * "ma0", "ma1", "mb0", "mb1", ec - ef + */ + + { -1 } +}; + +static void init_mem_names(int feature_set, const char **mem_names) +{ + int i; + int feature; + + /* Set defaults / i8051 */ + for (i = 0; feature = mem_name_feature[i].feature, feature >= 0; i++) + { + if ( feature == FEATURE_NONE ) + mem_names[mem_name_feature[i].addr] = mem_name_feature[i].name; + } + + /* Set specific memory names */ + for (i = 0; feature = mem_name_feature[i].feature, feature >= 0; i++) + { + if (feature & feature_set) + mem_names[mem_name_feature[i].addr] = mem_name_feature[i].name; + } + +} + +static const char *get_data_address( const char **mem_names, UINT8 arg ) +{ + static char buffer_array[4][32]; + static int whichbuf; + char *buffer = &buffer_array[++whichbuf % 4][0]; + + if (mem_names[arg] == NULL) + sprintf(buffer,"$%02X",arg); + else + sprintf(buffer,"%s", mem_names[arg]); + return buffer; +} + +static const char *get_bit_address( const char **mem_names, UINT8 arg ) +{ + static char buffer[32]; + + if(arg < 0x80) + { + //Bit address 0-7F can be referred to as 20.0, 20.1, to 20.7 for address 0, and 2f.0,2f.1 to 2f.7 for address 7f + if(arg < 0x7f) + sprintf(buffer,"$%02X.%d",(arg >> 3) | 0x20, arg & 0x07); + else + sprintf(buffer,"$%02X",arg); + } + else + { + if (mem_names[arg | 0x100] == NULL) + { + if (mem_names[arg & 0xf8] == NULL) + sprintf(buffer,"$%02X.%d", arg & 0xf8, arg & 0x07); + else + sprintf(buffer,"%s.%d", mem_names[arg & 0xf8], arg & 0x07); + } + else + sprintf(buffer,"%s", mem_names[arg | 0x100]); + } + return buffer; +} + +#else + +/*Just display the actual memory address for data & bit address access*/ + +static const char *get_data_address( UINT8 arg ) +{ + static char buffer[32]; + sprintf(buffer,"$%02X",arg); + return buffer; +} + +static const char *get_bit_address( UINT8 arg ) +{ + static char buffer[32]; + sprintf(buffer,"$%02X",arg); + return buffer; +} + +#endif + +static offs_t mcs51_dasm( const char **mem_names, char *dst, offs_t pc, const UINT8 *oprom, const UINT8 *opram) +{ + UINT32 flags = 0; + unsigned PC = pc; + const char *sym, *sym2; + UINT8 op, data; + UINT16 addr; + INT8 rel; + + op = oprom[PC++ - pc]; + switch( op ) + { + //NOP + case 0x00: /* 1: 0000 0000 */ + sprintf(dst, "nop"); + break; + + //AJMP code addr /* 1: aaa0 0001 */ + case 0x01: + case 0x21: + case 0x41: + case 0x61: + case 0x81: + case 0xa1: + case 0xc1: + case 0xe1: + addr = opram[PC++ - pc]; + addr|= (PC & 0xf800) | ((op & 0xe0) << 3); + sprintf(dst, "ajmp $%04X", addr); + break; + + //LJMP code addr + case 0x02: /* 1: 0000 0010 */ + addr = (opram[PC++ - pc]<<8) & 0xff00; + addr|= opram[PC++ - pc]; + sprintf(dst, "ljmp $%04X", addr); + break; + + //RR A + case 0x03: /* 1: 0000 0011 */ + sprintf(dst, "rr a"); + break; + + //INC A + case 0x04: /* 1: 0000 0100 */ + sprintf(dst, "inc a"); + break; + + //INC data addr + case 0x05: /* 1: 0000 0101 */ + sym = get_data_address(mem_names, opram[PC++ - pc]); + sprintf(dst, "inc %s", sym); + break; + + //INC @R0/@R1 /* 1: 0000 011i */ + case 0x06: + case 0x07: + sprintf(dst, "inc @r%d", op&1); + break; + + //INC R0 to R7 /* 1: 0000 1rrr */ + case 0x08: + case 0x09: + case 0x0a: + case 0x0b: + case 0x0c: + case 0x0d: + case 0x0e: + case 0x0f: + sprintf(dst, "inc r%d", op&7); + break; + + //JBC bit addr, code addr + case 0x10: /* 1: 0001 0000 */ + sym = get_bit_address(mem_names, opram[PC++ - pc]); + rel = opram[PC++ - pc]; + sprintf(dst, "jbc %s,$%04X", sym, PC + rel); + break; + + //ACALL code addr /* 1: aaa1 0001 */ + case 0x11: + case 0x31: + case 0x51: + case 0x71: + case 0x91: + case 0xb1: + case 0xd1: + case 0xf1: + sprintf(dst, "acall $%04X", (PC & 0xf800) | ((op & 0xe0) << 3) | opram[PC - pc]); + PC++; + flags = DASMFLAG_STEP_OVER; + break; + + //LCALL code addr + case 0x12: /* 1: 0001 0010 */ + addr = (opram[PC++ - pc]<<8) & 0xff00; + addr|= opram[PC++ - pc]; + sprintf(dst, "lcall $%04X", addr); + flags = DASMFLAG_STEP_OVER; + break; + + //RRC A + case 0x13: /* 1: 0001 0011 */ + sprintf(dst, "rrc a"); + break; + + //DEC A + case 0x14: /* 1: 0001 0100 */ + sprintf(dst, "dec a"); + break; + + //DEC data addr + case 0x15: /* 1: 0001 0101 */ + sym = get_data_address(mem_names, opram[PC++ - pc]); + sprintf(dst, "dec %s", sym); + break; + + //Unable to test + //DEC @R0/@R1 /* 1: 0001 011i */ + case 0x16: + case 0x17: + sprintf(dst, "dec @r%d", op&1); + break; + + //DEC R0 to R7 /* 1: 0001 1rrr */ + case 0x18: + case 0x19: + case 0x1a: + case 0x1b: + case 0x1c: + case 0x1d: + case 0x1e: + case 0x1f: + sprintf(dst, "dec r%d", op&7); + break; + + //JB bit addr, code addr + case 0x20: /* 1: 0010 0000 */ + sym = get_bit_address(mem_names, opram[PC++ - pc]); + rel = opram[PC++ - pc]; + sprintf(dst, "jb %s,$%04X", sym, (PC + rel)); + break; + + //RET + case 0x22: /* 1: 0010 0010 */ + sprintf(dst, "ret"); + flags = DASMFLAG_STEP_OUT; + break; + + //RL A + case 0x23: /* 1: 0010 0011 */ + sprintf(dst, "rl a"); + break; + + //ADD A, #data + case 0x24: /* 1: 0010 0100 */ + sprintf(dst, "add a,#$%02X", opram[PC++ - pc]); + break; + + //ADD A, data addr + case 0x25: /* 1: 0010 0101 */ + sym = get_data_address(mem_names, opram[PC++ - pc]); + sprintf(dst, "add a,%s", sym); + break; + + //Unable to Test + //ADD A, @R0/@R1 /* 1: 0010 011i */ + case 0x26: + case 0x27: + sprintf(dst, "add a,@r%d", op&1); + break; + + //ADD A, R0 to R7 /* 1: 0010 1rrr */ + case 0x28: + case 0x29: + case 0x2a: + case 0x2b: + case 0x2c: + case 0x2d: + case 0x2e: + case 0x2f: + sprintf(dst, "add a,r%d", op&7); + break; + + //JNB bit addr, code addr + case 0x30: /* 1: 0011 0000 */ + sym = get_bit_address(mem_names, opram[PC++ - pc]); + rel = opram[PC++ - pc]; + sprintf(dst, "jnb %s,$%04X", sym, (PC + rel)); + break; + + //RETI + case 0x32: /* 1: 0011 0010 */ + sprintf(dst, "reti"); + flags = DASMFLAG_STEP_OUT; + break; + + //RLC A + case 0x33: /* 1: 0011 0011 */ + sprintf(dst, "rlc a"); + break; + + //ADDC A, #data + case 0x34: /* 1: 0011 0100 */ + sprintf(dst, "addc a,#$%02X", opram[PC++ - pc]); + break; + + //ADDC A, data addr + case 0x35: /* 1: 0011 0101 */ + sym = get_data_address(mem_names, opram[PC++ - pc]); + sprintf(dst, "addc a,%s", sym); + break; + + //ADDC A, @R0/@R1 /* 1: 0011 011i */ + case 0x36: + case 0x37: + sprintf(dst, "addc a,@r%d", op&1); + break; + + //ADDC A, R0 to R7 /* 1: 0011 1rrr */ + case 0x38: + case 0x39: + case 0x3a: + case 0x3b: + case 0x3c: + case 0x3d: + case 0x3e: + case 0x3f: + sprintf(dst, "addc a,r%d", op&7); + break; + + //JC code addr + case 0x40: /* 1: 0100 0000 */ + rel = opram[PC++ - pc]; + sprintf(dst, "jc $%04X", PC + rel); + break; + + //ORL data addr, A + case 0x42: /* 1: 0100 0010 */ + sym = get_data_address(mem_names, opram[PC++ - pc]); + sprintf(dst, "orl %s,a", sym); + break; + + //ORL data addr, #data + case 0x43: /* 1: 0100 0011 */ + sym = get_data_address(mem_names, opram[PC++ - pc]); + sprintf(dst, "orl %s,#$%02X", sym, opram[PC++ - pc]); + break; + + //Unable to Test + //ORL A, #data + case 0x44: /* 1: 0100 0100 */ + sprintf(dst, "orl a,#$%02X", opram[PC++ - pc]); + break; + + //ORL A, data addr + case 0x45: /* 1: 0100 0101 */ + sym = get_data_address(mem_names, opram[PC++ - pc]); + sprintf(dst, "orl a,%s", sym); + break; + + //ORL A, @RO/@R1 /* 1: 0100 011i */ + case 0x46: + case 0x47: + sprintf(dst, "orl a,@r%d", op&1); + break; + + //ORL A, RO to R7 /* 1: 0100 1rrr */ + case 0x48: + case 0x49: + case 0x4a: + case 0x4b: + case 0x4c: + case 0x4d: + case 0x4e: + case 0x4f: + sprintf(dst, "orl a,r%d", op&7); + break; + + //JNC code addr + case 0x50: /* 1: 0101 0000 */ + rel = opram[PC++ - pc]; + sprintf(dst, "jnc $%04X", PC + rel); + break; + + //Unable to test + //ANL data addr, A + case 0x52: /* 1: 0101 0010 */ + sym = get_data_address(mem_names, opram[PC++ - pc]); + sprintf(dst, "anl %s,a", sym); + break; + + //Unable to test + //ANL data addr, #data + case 0x53: /* 1: 0101 0011 */ + sym = get_data_address(mem_names, opram[PC++ - pc]); + sprintf(dst, "anl %s,#$%02X", sym, opram[PC++ - pc]); + break; + + //ANL A, #data + case 0x54: /* 1: 0101 0100 */ + sprintf(dst, "anl a,#$%02X", opram[PC++ - pc]); + break; + + //ANL A, data addr + case 0x55: /* 1: 0101 0101 */ + sym = get_data_address(mem_names, opram[PC++ - pc]); + sprintf(dst, "anl a,%s", sym); + break; + + //Unable to test + //ANL A, @RO/@R1 /* 1: 0101 011i */ + case 0x56: + case 0x57: + sprintf(dst, "anl a,@r%d", op&1); + break; + + //ANL A, RO to R7 /* 1: 0101 1rrr */ + case 0x58: + case 0x59: + case 0x5a: + case 0x5b: + case 0x5c: + case 0x5d: + case 0x5e: + case 0x5f: + sprintf(dst, "anl a,r%d", op&7); + break; + + //JZ code addr + case 0x60: /* 1: 0110 0000 */ + rel = opram[PC++ - pc]; + sprintf(dst, "jz $%04X", PC + rel); + break; + + //Unable to test + //XRL data addr, A + case 0x62: /* 1: 0110 0010 */ + sym = get_data_address(mem_names, opram[PC++ - pc]); + sprintf(dst, "xrl %s,a", sym); + break; + + //XRL data addr, #data + case 0x63: /* 1: 0110 0011 */ + sym = get_data_address(mem_names, opram[PC++ - pc]); + sprintf(dst, "xrl %s,#$%02X", sym, opram[PC++ - pc]); + break; + + //XRL A, #data + case 0x64: /* 1: 0110 0100 */ + sprintf(dst, "xrl a,#$%02X", opram[PC++ - pc]); + break; + + //XRL A, data addr + case 0x65: /* 1: 0110 0101 */ + sym = get_data_address(mem_names, opram[PC++ - pc]); + sprintf(dst, "xrl a,%s", sym); + break; + + //Unable to test + //XRL A, @R0/@R1 /* 1: 0110 011i */ + case 0x66: + case 0x67: + sprintf(dst, "xrl a,@r%d", op&1); + break; + + //XRL A, R0 to R7 /* 1: 0110 1rrr */ + case 0x68: + case 0x69: + case 0x6a: + case 0x6b: + case 0x6c: + case 0x6d: + case 0x6e: + case 0x6f: + sprintf(dst, "xrl a,r%d", op&7); + break; + + //JNZ code addr + case 0x70: /* 1: 0111 0000 */ + rel = opram[PC++ - pc]; + sprintf(dst, "jnz $%04X", PC + rel); + break; + + //Unable to test + //ORL C, bit addr + case 0x72: /* 1: 0111 0010 */ + sym = get_bit_address(mem_names, opram[PC++ - pc]); + sprintf(dst, "orl c,%s", sym); + break; + + //Unable to test + //JMP @A+DPTR + case 0x73: /* 1: 0111 0011 */ + sprintf(dst, "jmp @a+dptr"); + break; + + //MOV A, #data + case 0x74: /* 1: 0111 0100 */ + sprintf(dst, "mov a,#$%02X", opram[PC++ - pc]); + break; + + //MOV data addr, #data + case 0x75: /* 1: 0111 0101 */ + sym = get_data_address(mem_names, opram[PC++ - pc]); + sprintf(dst, "mov %s,#$%02X", sym, opram[PC++ - pc]); + break; + + //Unable to test + //MOV @R0/@R1, #data /* 1: 0111 011i */ + case 0x76: + case 0x77: + sprintf(dst, "mov @r%d,#$%02X", op&1, opram[PC++ - pc]); + break; + + //MOV R0 to R7, #data /* 1: 0111 1rrr */ + case 0x78: + case 0x79: + case 0x7a: + case 0x7b: + case 0x7c: + case 0x7d: + case 0x7e: + case 0x7f: + sprintf(dst, "mov r%d,#$%02X", (op & 7), opram[PC++ - pc]); + break; + + //SJMP code addr + case 0x80: /* 1: 1000 0000 */ + rel = opram[PC++ - pc]; + sprintf(dst, "sjmp $%04X", PC + rel); + break; + + //ANL C, bit addr + case 0x82: /* 1: 1000 0010 */ + sym = get_bit_address(mem_names, opram[PC++ - pc]); + sprintf(dst, "anl c,%s", sym); + break; + + //MOVC A, @A + PC + case 0x83: /* 1: 1000 0011 */ + sprintf(dst, "movc a,@a+pc"); + break; + + //DIV AB + case 0x84: /* 1: 1000 0100 */ + sprintf(dst, "div ab"); + break; + + //MOV data addr, data addr (Note: 1st address is src, 2nd is dst, but the mov command works as mov dst,src) + case 0x85: /* 1: 1000 0101 */ + sym = get_data_address(mem_names, opram[PC++ - pc]); + sym2 = get_data_address(mem_names, opram[PC++ - pc]); + sprintf(dst, "mov %s,%s", sym2, sym); + break; + + //Unable to test + //MOV data addr, @R0/@R1/* 1: 1000 011i */ + case 0x86: + case 0x87: + sym = get_data_address(mem_names, opram[PC++ - pc]); + sprintf(dst, "mov %s,@r%d", sym, op&1); + break; + + //MOV data addr,R0 to R7/* 1: 1000 1rrr */ + case 0x88: + case 0x89: + case 0x8a: + case 0x8b: + case 0x8c: + case 0x8d: + case 0x8e: + case 0x8f: + sym = get_data_address(mem_names, opram[PC++ - pc]); + sprintf(dst, "mov %s,r%d", sym, op&7); + break; + + //MOV DPTR, #data16 + case 0x90: /* 1: 1001 0000 */ + addr = (opram[PC++ - pc]<<8) & 0xff00; + addr|= opram[PC++ - pc]; + sprintf(dst, "mov dptr,#$%04X", addr); + break; + + //MOV bit addr, C + case 0x92: /* 1: 1001 0010 */ + sym = get_bit_address(mem_names, opram[PC++ - pc]); + sprintf(dst, "mov %s,c", sym); + break; + + //MOVC A, @A + DPTR + case 0x93: /* 1: 1001 0011 */ + sprintf(dst, "movc a,@a+dptr"); + break; + + //SUBB A, #data + case 0x94: /* 1: 1001 0100 */ + sprintf(dst, "subb a,#$%02X", opram[PC++ - pc]); + break; + + //SUBB A, data addr + case 0x95: /* 1: 1001 0101 */ + sym = get_data_address(mem_names, opram[PC++ - pc]); + sprintf(dst, "subb a,%s", sym); + break; + + //Unable to test + //SUBB A, @R0/@R1 /* 1: 1001 011i */ + case 0x96: + case 0x97: + sprintf(dst, "subb a,@r%d", op&1); + break; + + //SUBB A, R0 to R7 /* 1: 1001 1rrr */ + case 0x98: + case 0x99: + case 0x9a: + case 0x9b: + case 0x9c: + case 0x9d: + case 0x9e: + case 0x9f: + sprintf(dst, "subb a,r%d", op&7); + break; + + //Unable to test + //ORL C, /bit addr + case 0xa0: /* 1: 1010 0000 */ + sym = get_bit_address(mem_names, opram[PC++ - pc]); + sprintf(dst, "orl c,/%s", sym); + break; + + //MOV C, bit addr + case 0xa2: /* 1: 1010 0010 */ + sym = get_bit_address(mem_names, opram[PC++ - pc]); + sprintf(dst, "mov c,%s", sym); + break; + + //INC DPTR + case 0xa3: /* 1: 1010 0011 */ + sprintf(dst, "inc dptr"); + break; + + //MUL AB + case 0xa4: /* 1: 1010 0100 */ + sprintf(dst, "mul ab"); + break; + + //reserved + case 0xa5: /* 1: 1010 0101 */ + sprintf(dst, "ill/rsv"); + break; + + //Unable to test + //MOV @R0/@R1, data addr /* 1: 1010 011i */ + case 0xa6: + case 0xa7: + sym = get_data_address(mem_names, opram[PC++ - pc]); + sprintf(dst, "mov @r%d,%s", op&1, sym); + break; + + //MOV R0 to R7, data addr /* 1: 1010 1rrr */ + case 0xa8: + case 0xa9: + case 0xaa: + case 0xab: + case 0xac: + case 0xad: + case 0xae: + case 0xaf: + sym = get_data_address(mem_names, opram[PC++ - pc]); + sprintf(dst, "mov r%d,%s", op&7, sym); + break; + + //ANL C,/bit addr + case 0xb0: /* 1: 1011 0000 */ + sym = get_bit_address(mem_names, opram[PC++ - pc]); + sprintf(dst, "anl c,/%s", sym); + break; + + //CPL bit addr + case 0xb2: /* 1: 1011 0010 */ + sym = get_bit_address(mem_names, opram[PC++ - pc]); + sprintf(dst, "cpl %s", sym); + break; + + //Unable to test + //CPL C + case 0xb3: /* 1: 1011 0011 */ + sprintf(dst, "cpl c"); + break; + + //CJNE A, #data, code addr + case 0xb4: /* 1: 1011 0100 */ + data = opram[PC++ - pc]; + rel = opram[PC++ - pc]; + sprintf(dst, "cjne a,#$%02X,$%04X", data, PC + rel); + break; + + //CJNE A, data addr, code addr + case 0xb5: /* 1: 1011 0101 */ + sym = get_data_address(mem_names, opram[PC++ - pc]); + rel = opram[PC++ - pc]; + sprintf(dst, "cjne a,%s,$%04X", sym, PC + rel); + break; + + //Unable to test + //CJNE @R0/@R1, #data, code addr /* 1: 1011 011i */ + case 0xb6: + case 0xb7: + data = opram[PC++ - pc]; + rel = opram[PC++ - pc]; + sprintf(dst, "cjne @r%d,#$%02X,$%04X", op&1, data, PC + rel); + break; + + //CJNE R0 to R7, #data, code addr/* 1: 1011 1rrr */ + case 0xb8: + case 0xb9: + case 0xba: + case 0xbb: + case 0xbc: + case 0xbd: + case 0xbe: + case 0xbf: + data = opram[PC++ - pc]; + rel = opram[PC++ - pc]; + sprintf(dst, "cjne r%d,#$%02X,$%04X", op&7, data, PC + rel); + break; + + //PUSH data addr + case 0xc0: /* 1: 1100 0000 */ + sym = get_data_address(mem_names, opram[PC++ - pc]); + sprintf(dst, "push %s", sym); + break; + + //CLR bit addr + case 0xc2: /* 1: 1100 0010 */ + sym = get_bit_address(mem_names, opram[PC++ - pc]); + sprintf(dst, "clr %s", sym); + break; + + //CLR C + case 0xc3: /* 1: 1100 0011 */ + sprintf(dst, "clr c"); + break; + + //SWAP A + case 0xc4: /* 1: 1100 0100 */ + sprintf(dst, "swap a"); + break; + + //XCH A, data addr + case 0xc5: /* 1: 1100 0101 */ + sym = get_data_address(mem_names, opram[PC++ - pc]); + sprintf(dst, "xch a,%s", sym); + break; + + //XCH A, @RO/@R1 /* 1: 1100 011i */ + case 0xc6: + case 0xc7: + sprintf(dst, "xch a,@r%d", op&1); + break; + + //XCH A, RO to R7 /* 1: 1100 1rrr */ + case 0xc8: + case 0xc9: + case 0xca: + case 0xcb: + case 0xcc: + case 0xcd: + case 0xce: + case 0xcf: + sprintf(dst, "xch a,r%d", op&7); + break; + + //POP data addr + case 0xd0: /* 1: 1101 0000 */ + sym = get_data_address(mem_names, opram[PC++ - pc]); + sprintf(dst, "pop %s", sym); + break; + + //SETB bit addr + case 0xd2: /* 1: 1101 0010 */ + sym = get_bit_address(mem_names, opram[PC++ - pc]); + sprintf(dst, "setb %s", sym); + break; + + //SETB C + case 0xd3: /* 1: 1101 0011 */ + sprintf(dst, "setb c"); + break; + + //Unable to test + //DA A + case 0xd4: /* 1: 1101 0100 */ + sprintf(dst, "da a"); + break; + + //DJNZ data addr, code addr + case 0xd5: /* 1: 1101 0101 */ + sym = get_data_address(mem_names, opram[PC++ - pc]); + rel = opram[PC++ - pc]; + sprintf(dst, "djnz %s,$%04X", sym, PC + rel); + flags = DASMFLAG_STEP_OVER; + break; + + //XCHD A, @R0/@R1 /* 1: 1101 011i */ + case 0xd6: + case 0xd7: + sprintf(dst, "xchd a,@r%d", op&1); + break; + + //DJNZ R0 to R7,code addr /* 1: 1101 1rrr */ + case 0xd8: + case 0xd9: + case 0xda: + case 0xdb: + case 0xdc: + case 0xdd: + case 0xde: + case 0xdf: + rel = opram[PC++ - pc]; + sprintf(dst, "djnz r%d,$%04X", op&7, (PC + rel)); + flags = DASMFLAG_STEP_OVER; + break; + + //MOVX A,@DPTR + case 0xe0: /* 1: 1110 0000 */ + sprintf(dst, "movx a,@dptr"); + break; + + //Unable to test + //MOVX A, @R0/@R1 /* 1: 1110 001i */ + case 0xe2: + case 0xe3: + sprintf(dst, "movx a,@r%d", op&1); + break; + + //CLR A + case 0xe4: /* 1: 1110 0100 */ + sprintf(dst, "clr a"); + break; + + //MOV A, data addr + case 0xe5: /* 1: 1110 0101 */ + sym = get_data_address(mem_names, opram[PC++ - pc]); + sprintf(dst, "mov a,%s", sym); + break; + + //Unable to test + //MOV A,@RO/@R1 /* 1: 1110 011i */ + case 0xe6: + case 0xe7: + sprintf(dst, "mov a,@r%d", op&1); + break; + + //MOV A,R0 to R7 /* 1: 1110 1rrr */ + case 0xe8: + case 0xe9: + case 0xea: + case 0xeb: + case 0xec: + case 0xed: + case 0xee: + case 0xef: + sprintf(dst, "mov a,r%d", op&7); + break; + + //MOVX @DPTR,A + case 0xf0: /* 1: 1111 0000 */ + sprintf(dst, "movx @dptr,a"); + break; + + //Unable to test + //MOVX @R0/@R1,A /* 1: 1111 001i */ + case 0xf2: + case 0xf3: + sprintf(dst, "movx @r%d,a", op&1); + break; + + //CPL A + case 0xf4: /* 1: 1111 0100 */ + sprintf(dst, "cpl a"); + break; + + //MOV data addr, A + case 0xf5: /* 1: 1111 0101 */ + sym = get_data_address(mem_names, opram[PC++ - pc]); + sprintf(dst, "mov %s,a", sym); + break; + + //MOV @R0/@R1, A /* 1: 1111 011i */ + case 0xf6: + case 0xf7: + sprintf(dst, "mov @r%d,a", op&1); + break; + + //MOV R0 to R7, A /* 1: 1111 1rrr */ + case 0xf8: + case 0xf9: + case 0xfa: + case 0xfb: + case 0xfc: + case 0xfd: + case 0xfe: + case 0xff: + sprintf(dst, "mov r%d,a", op&7); + break; + + default: + sprintf(dst, "illegal"); + } + return (PC - pc) | flags | DASMFLAG_SUPPORTED; + +} + +CPU_DISASSEMBLE( i8051 ) +{ + static const char *mem_names[0x200]; + static int mem_names_initialized = 0; + + if (!mem_names_initialized) + { + init_mem_names( FEATURE_NONE, mem_names); + mem_names_initialized = 1; + } + return mcs51_dasm(mem_names, buffer, pc, oprom, opram); +} + +CPU_DISASSEMBLE( i8052 ) +{ + static const char *mem_names[0x200]; + static int mem_names_initialized = 0; + + if (!mem_names_initialized) + { + init_mem_names( FEATURE_I8052, mem_names); + mem_names_initialized = 1; + } + return mcs51_dasm(mem_names, buffer, pc, oprom, opram); +} + +CPU_DISASSEMBLE( i80c51 ) +{ + static const char *mem_names[0x200]; + static int mem_names_initialized = 0; + + if (!mem_names_initialized) + { + init_mem_names( FEATURE_CMOS, mem_names); + mem_names_initialized = 1; + } + return mcs51_dasm(mem_names, buffer, pc, oprom, opram); +} + +CPU_DISASSEMBLE( i80c52 ) +{ + static const char *mem_names[0x200]; + static int mem_names_initialized = 0; + + if (!mem_names_initialized) + { + init_mem_names( FEATURE_I8052 | FEATURE_CMOS | FEATURE_I80C52, mem_names); + mem_names_initialized = 1; + } + return mcs51_dasm(mem_names, buffer, pc, oprom, opram); +} + +CPU_DISASSEMBLE( ds5002fp ) +{ + static const char *mem_names[0x200]; + static int mem_names_initialized = 0; + + if (!mem_names_initialized) + { + init_mem_names( FEATURE_DS5002FP | FEATURE_CMOS, mem_names); + mem_names_initialized = 1; + } + return mcs51_dasm(mem_names, buffer, pc, oprom, opram); +} diff --git a/src/devices/cpu/mcs51/mcs51ops.inc b/src/devices/cpu/mcs51/mcs51ops.inc new file mode 100644 index 00000000000..e60cc3505eb --- /dev/null +++ b/src/devices/cpu/mcs51/mcs51ops.inc @@ -0,0 +1,980 @@ +/******************************************************************************************* + NOTE: All registers are accessed directly, instead of using the SFR_R() function for speed + Direct register access is availabe from the R_(register name) macros.. ex: ACC for the ACC + with the exception of the PC +********************************************************************************************/ + +//ACALL code addr /* 1: aaa1 0001 */ +OPHANDLER( acall ) +{ + UINT8 addr = ROP_ARG(PC++); //Grab code address byte + PUSH_PC(); //Save PC to the stack + //Thanks Gerrit for help with this! :) + PC = (PC & 0xf800) | ((r & 0xe0) << 3) | addr; +} + +//ADD A, #data /* 1: 0010 0100 */ +OPHANDLER( add_a_byte ) +{ + UINT8 data = ROP_ARG(PC++); //Grab data + UINT8 result = ACC + data; //Add data to accumulator + DO_ADD_FLAGS(ACC,data,0); //Set Flags + SET_ACC(result); //Store 8 bit result of addtion in ACC +} + +//ADD A, data addr /* 1: 0010 0101 */ +OPHANDLER( add_a_mem ) +{ + UINT8 addr = ROP_ARG(PC++); //Grab data address + UINT8 data = IRAM_R(addr); //Grab data from data address + UINT8 result = ACC + data; //Add data to accumulator + DO_ADD_FLAGS(ACC,data,0); //Set Flags + SET_ACC(result); //Store 8 bit result of addtion in ACC +} + +//ADD A, @R0/@R1 /* 1: 0010 011i */ +OPHANDLER( add_a_ir ) +{ + UINT8 data = IRAM_IR(R_REG(r)); //Grab data from memory pointed to by R0 or R1 + UINT8 result = ACC + data; //Add data to accumulator + DO_ADD_FLAGS(ACC,data,0); //Set Flags + SET_ACC(result); //Store 8 bit result of addtion in ACC +} + +//ADD A, R0 to R7 /* 1: 0010 1rrr */ +OPHANDLER( add_a_r ) +{ + UINT8 data = R_REG(r); //Grab data from R0 - R7 + UINT8 result = ACC + data; //Add data to accumulator + DO_ADD_FLAGS(ACC,data,0); //Set Flags + SET_ACC(result); //Store 8 bit result of addtion in ACC +} + +//ADDC A, #data /* 1: 0011 0100 */ +OPHANDLER( addc_a_byte ) +{ + UINT8 data = ROP_ARG(PC++); //Grab data + UINT8 result = ACC + data + GET_CY; //Add data + carry flag to accumulator + DO_ADD_FLAGS(ACC,data,GET_CY); //Set Flags + SET_ACC(result); //Store 8 bit result of addtion in ACC +} + +//ADDC A, data addr /* 1: 0011 0101 */ +OPHANDLER( addc_a_mem ) +{ + UINT8 addr = ROP_ARG(PC++); //Grab data address + UINT8 data = IRAM_R(addr); //Grab data from data address + UINT8 result = ACC + data + GET_CY; //Add data + carry flag to accumulator + DO_ADD_FLAGS(ACC,data,GET_CY); //Set Flags + SET_ACC(result); //Store 8 bit result of addtion in ACC +} + +//ADDC A, @R0/@R1 /* 1: 0011 011i */ +OPHANDLER( addc_a_ir ) +{ + UINT8 data = IRAM_IR(R_REG(r)); //Grab data from memory pointed to by R0 or R1 + UINT8 result = ACC + data + GET_CY; //Add data + carry flag to accumulator + DO_ADD_FLAGS(ACC,data,GET_CY); //Set Flags + SET_ACC(result); //Store 8 bit result of addtion in ACC +} + +//ADDC A, R0 to R7 /* 1: 0011 1rrr */ +OPHANDLER( addc_a_r ) +{ + UINT8 data = R_REG(r); //Grab data from R0 - R7 + UINT8 result = ACC + data + GET_CY; //Add data + carry flag to accumulator + DO_ADD_FLAGS(ACC,data,GET_CY); //Set Flags + SET_ACC(result); //Store 8 bit result of addtion in ACC +} + +//AJMP code addr /* 1: aaa0 0001 */ +OPHANDLER( ajmp ) +{ + UINT8 addr = ROP_ARG(PC++); //Grab code address byte + //Thanks Gerrit for help with this! :) + PC = (PC & 0xf800) | ((r & 0xe0) << 3) | addr; +} + +//ANL data addr, A /* 1: 0101 0010 */ +OPHANDLER( anl_mem_a ) +{ + UINT8 addr = ROP_ARG(PC++); //Grab data address + UINT8 data = IRAM_R(addr); //Grab data from data address + IRAM_W(addr,data & ACC); //Set data address value to it's value Logical AND with ACC +} + +//ANL data addr, #data /* 1: 0101 0011 */ +OPHANDLER( anl_mem_byte ) +{ + UINT8 addr = ROP_ARG(PC++); //Grab data address + UINT8 data = ROP_ARG(PC++); //Grab data + UINT8 srcdata = IRAM_R(addr); //Grab data from data address + IRAM_W(addr,srcdata & data); //Set data address value to it's value Logical AND with Data +} + +//ANL A, #data /* 1: 0101 0100 */ +OPHANDLER( anl_a_byte ) +{ + UINT8 data = ROP_ARG(PC++); //Grab data + SET_ACC(ACC & data); //Set ACC to value of ACC Logical AND with Data +} + +//ANL A, data addr /* 1: 0101 0101 */ +OPHANDLER( anl_a_mem ) +{ + UINT8 addr = ROP_ARG(PC++); //Grab data address + UINT8 data = IRAM_R(addr); //Grab data from data address + SET_ACC(ACC & data); //Set ACC to value of ACC Logical AND with Data +} + +//ANL A, @RO/@R1 /* 1: 0101 011i */ +OPHANDLER( anl_a_ir ) +{ + UINT8 data = IRAM_IR(R_REG(r)); //Grab data from address R0 or R1 points to + SET_ACC(ACC & data); //Set ACC to value of ACC Logical AND with Data +} + +//ANL A, RO to R7 /* 1: 0101 1rrr */ +OPHANDLER( anl_a_r ) +{ + UINT8 data = R_REG(r); //Grab data from R0 - R7 + SET_ACC(ACC & data); //Set ACC to value of ACC Logical AND with Data +} + +//ANL C, bit addr /* 1: 1000 0010 */ +OPHANDLER( anl_c_bitaddr ) +{ + int cy = GET_CY; + UINT8 addr = ROP_ARG(PC++); //Grab bit address + UINT8 bit = BIT_R(addr); //Grab bit data from bit address + SET_CY( (cy & bit) ); //Set Carry flag to Carry Flag Value Logical AND with Bit +} + +//ANL C,/bit addr /* 1: 1011 0000 */ +OPHANDLER( anl_c_nbitaddr ) +{ + int cy = GET_CY; + UINT8 addr = ROP_ARG(PC++); //Grab bit address + UINT8 bit = BIT_R(addr); //Grab bit data from bit address + bit = ((~bit)&1); //Complement bit + SET_CY( (cy & bit) ); //Set Carry flag to Carry Flag Value Logical AND with Complemented Bit +} + +//CJNE A, #data, code addr /* 1: 1011 0100 */ +OPHANDLER( cjne_a_byte ) +{ + UINT8 data = ROP_ARG(PC++); //Grab data + INT8 rel_addr = ROP_ARG(PC++); //Grab relative code address + + if(ACC != data) //Jump if values are not equal + { + PC = PC + rel_addr; + } + + //Set carry flag to 1 if 1st compare value is < 2nd compare value + SET_CY( (ACC < data) ); +} + +//CJNE A, data addr, code addr /* 1: 1011 0101 */ +OPHANDLER( cjne_a_mem ) +{ + UINT8 addr = ROP_ARG(PC++); //Grab data address + INT8 rel_addr = ROP_ARG(PC++); //Grab relative code address + UINT8 data = IRAM_R(addr); //Pull value from data address + + if(ACC != data) //Jump if values are not equal + { + PC = PC + rel_addr; + } + + //Set carry flag to 1 if 1st compare value is < 2nd compare value + SET_CY( (ACC < data) ); +} + +//CJNE @R0/@R1, #data, code addr /* 1: 1011 011i */ +OPHANDLER( cjne_ir_byte ) +{ + UINT8 data = ROP_ARG(PC++); //Grab data + INT8 rel_addr = ROP_ARG(PC++); //Grab relative code address + UINT8 srcdata = IRAM_IR(R_REG(r)); //Grab value pointed to by R0 or R1 + + if(srcdata != data) //Jump if values are not equal + { + PC = PC + rel_addr; + } + + //Set carry flag to 1 if 1st compare value is < 2nd compare value + SET_CY( (srcdata < data) ); +} + +//CJNE R0 to R7, #data, code addr /* 1: 1011 1rrr */ +OPHANDLER( cjne_r_byte ) +{ + UINT8 data = ROP_ARG(PC++); //Grab data + INT8 rel_addr = ROP_ARG(PC++); //Grab relative code address + UINT8 srcdata = R_REG(r); //Grab value of R0 - R7 + + if(srcdata != data) //Jump if values are not equal + { + PC = PC + rel_addr; + } + + //Set carry flag to 1 if 1st compare value is < 2nd compare value + SET_CY( (srcdata < data) ); +} + +//CLR bit addr /* 1: 1100 0010 */ +OPHANDLER( clr_bitaddr ) +{ + UINT8 addr = ROP_ARG(PC++); //Grab bit address + BIT_W(addr,0); //Clear bit at specified bit address +} + +//CLR C /* 1: 1100 0011 */ +OPHANDLER( clr_c ) +{ + SET_CY(0); //Clear Carry Flag +} + +//CLR A /* 1: 1110 0100 */ +OPHANDLER( clr_a ) +{ + SET_ACC(0); //Clear Accumulator +} + +//CPL bit addr /* 1: 1011 0010 */ +OPHANDLER( cpl_bitaddr ) +{ + UINT8 addr = ROP_ARG(PC++); //Grab bit address + UINT8 data = (~BIT_R(addr))&1; + BIT_W(addr,data); //Complement bit at specified bit address +} + +//CPL C /* 1: 1011 0011 */ +OPHANDLER( cpl_c ) +{ + UINT8 bit = (~GET_CY)&1; //Complement Carry Flag + SET_CY(bit); +} + +//CPL A /* 1: 1111 0100 */ +OPHANDLER( cpl_a ) +{ + UINT8 data = ((~ACC)&0xff); + SET_ACC(data); //Complement Accumulator +} + +//DA A /* 1: 1101 0100 */ +OPHANDLER( da_a ) +{ +/*From several sources, since none said the same thing: + The decimal adjust instruction is associated with the use of the ADD and ADDC instructions. + The eight-bit value in the accumulator is adjusted to form two BCD digits of four bits each. + If the accumulator contents bits 0-3 are greater than 9, OR the AC flag is set, then six is added to + produce a proper BCD digit. + If the carry is set, OR the four high bits 4-7 exceed nine, six is added to the value of these bits. + The carry flag will be set if the result is > 0x99, but not cleared otherwise */ + + UINT16 new_acc = ACC & 0xff; + if(GET_AC || (new_acc & 0x0f) > 0x09) + new_acc += 0x06; + if(GET_CY || ((new_acc & 0xf0) > 0x90) || (new_acc & ~0xff)) + new_acc += 0x60; + SET_ACC(new_acc&0xff); + if(new_acc & ~0xff) + SET_CY(1); +} + +//DEC A /* 1: 0001 0100 */ +OPHANDLER( dec_a ) +{ + SET_ACC(ACC-1); +} + +//DEC data addr /* 1: 0001 0101 */ +OPHANDLER( dec_mem ) +{ + UINT8 addr = ROP_ARG(PC++); //Grab data address + UINT8 data = IRAM_R(addr); + IRAM_W(addr,data-1); +} + +//DEC @R0/@R1 /* 1: 0001 011i */ +OPHANDLER( dec_ir ) +{ + UINT8 data = IRAM_IR(R_REG(r)); + IRAM_W(R_REG(r),data-1); +} + +//DEC R0 to R7 /* 1: 0001 1rrr */ +OPHANDLER( dec_r ) +{ + SET_REG(r, R_REG(r) - 1); +} + +//DIV AB /* 1: 1000 0100 */ +OPHANDLER( div_ab ) +{ + if( B == 0 ) { + //Overflow flag is set! + SET_OV(1); + //Really the values are undefined according to the manual, but we'll just leave them as is.. + //SET_ACC(0xff); + //SFR_W(B,0xff); + } + else { + int a = (int)ACC / B; + int b = (int)ACC % B; + //A gets quotient byte, B gets remainder byte + SET_ACC(a); + B = b; + //Overflow flag is cleared + SET_OV(0); + } + //Carry Flag is always cleared + SET_CY(0); +} + +//DJNZ data addr, code addr /* 1: 1101 0101 */ +OPHANDLER( djnz_mem ) +{ + UINT8 addr = ROP_ARG(PC++); //Grab data address + INT8 rel_addr = ROP_ARG(PC++); //Grab relative code address + IRAM_W(addr,IRAM_R(addr) - 1); //Decrement value contained at data address + if(IRAM_R(addr) != 0) //Branch if contents of data address is not 0 + { + PC = PC + rel_addr; + } +} + +//DJNZ R0 to R7,code addr /* 1: 1101 1rrr */ +OPHANDLER( djnz_r ) +{ + INT8 rel_addr = ROP_ARG(PC++); //Grab relative code address + SET_REG(r ,R_REG(r) - 1); //Decrement value + if(R_REG(r) != 0) //Branch if contents of R0 - R7 is not 0 + { + PC = PC + rel_addr; + } +} + +//INC A /* 1: 0000 0100 */ +OPHANDLER( inc_a ) +{ + SET_ACC(ACC+1); +} + +//INC data addr /* 1: 0000 0101 */ +OPHANDLER( inc_mem ) +{ + UINT8 addr = ROP_ARG(PC++); //Grab data address + UINT8 data = IRAM_R(addr); + IRAM_W(addr,data+1); +} + +//INC @R0/@R1 /* 1: 0000 011i */ +OPHANDLER( inc_ir ) +{ + UINT8 data = IRAM_IR(R_REG(r)); + IRAM_W(R_REG(r),data+1); +} + +//INC R0 to R7 /* 1: 0000 1rrr */ +OPHANDLER( inc_r ) +{ + UINT8 data = R_REG(r); + SET_REG(r, data + 1); +} + +//INC DPTR /* 1: 1010 0011 */ +OPHANDLER( inc_dptr ) +{ + UINT16 dptr = (DPTR)+1; + SET_DPTR(dptr); +} + +//JB bit addr, code addr /* 1: 0010 0000 */ +OPHANDLER( jb ) +{ + UINT8 addr = ROP_ARG(PC++); //Grab bit address + INT8 rel_addr = ROP_ARG(PC++); //Grab relative code address + if(BIT_R(addr)) //If bit set at specified bit address, jump + { + PC = PC + rel_addr; + } +} + +//JBC bit addr, code addr /* 1: 0001 0000 */ +OPHANDLER( jbc ) +{ + UINT8 addr = ROP_ARG(PC++); //Grab bit address + INT8 rel_addr = ROP_ARG(PC++); //Grab relative code address + if(BIT_R(addr)) { //If bit set at specified bit address, jump + PC = PC + rel_addr; + BIT_W(addr,0); //Clear Bit also + } +} + +//JC code addr /* 1: 0100 0000 */ +OPHANDLER( jc ) +{ + INT8 rel_addr = ROP_ARG(PC++); //Grab relative code address + if(GET_CY) //Jump if Carry Flag Set + { + PC = PC + rel_addr; + } +} + +//JMP @A+DPTR /* 1: 0111 0011 */ +OPHANDLER( jmp_iadptr ) +{ + PC = ACC + DPTR; +} + +//JNB bit addr, code addr /* 1: 0011 0000 */ +OPHANDLER( jnb ) +{ + UINT8 addr = ROP_ARG(PC++); //Grab bit address + INT8 rel_addr = ROP_ARG(PC++); //Grab relative code address + if(!BIT_R(addr)) //If bit NOT set at specified bit address, jump + { + PC = PC + rel_addr; + } +} + +//JNC code addr /* 1: 0101 0000 */ +OPHANDLER( jnc ) +{ + INT8 rel_addr = ROP_ARG(PC++); //Grab relative code address + if(!GET_CY) //Jump if Carry Flag not set + { + PC = PC + rel_addr; + } +} + +//JNZ code addr /* 1: 0111 0000 */ +OPHANDLER( jnz ) +{ + INT8 rel_addr = ROP_ARG(PC++); //Grab relative code address + if(ACC != 0) //Branch if ACC is not 0 + { + PC = PC+rel_addr; + } +} + +//JZ code addr /* 1: 0110 0000 */ +OPHANDLER( jz ) +{ + INT8 rel_addr = ROP_ARG(PC++); //Grab relative code address + if(ACC == 0) //Branch if ACC is 0 + { + PC = PC+rel_addr; + } +} + +//LCALL code addr /* 1: 0001 0010 */ +OPHANDLER( lcall ) +{ + UINT8 addr_hi, addr_lo; + addr_hi = ROP_ARG(PC++); + addr_lo = ROP_ARG(PC++); + PUSH_PC(); + PC = (UINT16)((addr_hi<<8) | addr_lo); +} + +//LJMP code addr /* 1: 0000 0010 */ +OPHANDLER( ljmp ) +{ + UINT8 addr_hi, addr_lo; + addr_hi = ROP_ARG(PC++); + addr_lo = ROP_ARG(PC++); + PC = (UINT16)((addr_hi<<8) | addr_lo); +} + +//MOV A, #data /* 1: 0111 0100 */ +OPHANDLER( mov_a_byte ) +{ + UINT8 data = ROP_ARG(PC++); //Grab data + SET_ACC(data); //Store data to ACC +} + +//MOV A, data addr /* 1: 1110 0101 */ +OPHANDLER( mov_a_mem ) +{ + UINT8 addr = ROP_ARG(PC++); //Grab data address + SET_ACC(IRAM_R(addr)); //Store contents of data address to ACC +} + +//MOV A,@RO/@R1 /* 1: 1110 011i */ +OPHANDLER( mov_a_ir ) +{ + SET_ACC(IRAM_IR(R_REG(r))); //Store contents of address pointed by R0 or R1 to ACC +} + +//MOV A,R0 to R7 /* 1: 1110 1rrr */ +OPHANDLER( mov_a_r ) +{ + SET_ACC(R_REG(r)); //Store contents of R0 - R7 to ACC +} + +//MOV data addr, #data /* 1: 0111 0101 */ +OPHANDLER( mov_mem_byte ) +{ + UINT8 addr = ROP_ARG(PC++); //Grab data address + UINT8 data = ROP_ARG(PC++); //Grab data + IRAM_W(addr,data); //Store data to data address location +} + +//MOV data addr, data addr /* 1: 1000 0101 */ +OPHANDLER( mov_mem_mem ) +{ + //1st address is src, 2nd is dst, but the mov command works as mov dst,src) + UINT8 src,dst; + src = ROP_ARG(PC++); //Grab source data address + dst = ROP_ARG(PC++); //Grab destination data address + IRAM_W(dst,IRAM_R(src)); //Read source address contents and store to destination address +} + +//MOV @R0/@R1, #data /* 1: 0111 011i */ +OPHANDLER( mov_ir_byte ) +{ + UINT8 data = ROP_ARG(PC++); //Grab data + IRAM_IW(R_REG(r),data); //Store data to address pointed by R0 or R1 +} + +//MOV R0 to R7, #data /* 1: 0111 1rrr */ +OPHANDLER( mov_r_byte ) +{ + UINT8 data = ROP_ARG(PC++); //Grab data + SET_REG(r, data); //Store to R0 - R7 +} + +//MOV data addr, @R0/@R1 /* 1: 1000 011i */ +OPHANDLER( mov_mem_ir ) +{ + UINT8 addr = ROP_ARG(PC++); //Grab data address + IRAM_W(addr,IRAM_IR(R_REG(r))); //Store contents pointed to by R0 or R1 to data address +} + +//MOV data addr,R0 to R7 /* 1: 1000 1rrr */ +OPHANDLER( mov_mem_r ) +{ + UINT8 addr = ROP_ARG(PC++); //Grab data address + IRAM_W(addr,R_REG(r)); //Store contents of R0 - R7 to data address +} + +//MOV DPTR, #data16 /* 1: 1001 0000 */ +OPHANDLER( mov_dptr_byte ) +{ + UINT8 data_hi, data_lo; + data_hi = ROP_ARG(PC++); //Grab hi byte + data_lo = ROP_ARG(PC++); //Grab lo byte + SET_DPTR((UINT16)((data_hi<<8)|data_lo)); //Store to DPTR +} + +//MOV bit addr, C /* 1: 1001 0010 */ +OPHANDLER( mov_bitaddr_c ) +{ + UINT8 addr = ROP_ARG(PC++); //Grab bit address + BIT_W(addr,GET_CY); //Store Carry Flag to Bit Address +} + +//MOV @R0/@R1, data addr /* 1: 1010 011i */ +OPHANDLER( mov_ir_mem ) +{ + UINT8 addr = ROP_ARG(PC++); //Grab data address + IRAM_IW(R_REG(r),IRAM_R(addr)); //Store data from data address to address pointed to by R0 or R1 +} + +//MOV R0 to R7, data addr /* 1: 1010 1rrr */ +OPHANDLER( mov_r_mem ) +{ + UINT8 addr = ROP_ARG(PC++); //Grab data address + SET_REG(r, IRAM_R(addr)); //Store to R0 - R7 +} + +//MOV data addr, A /* 1: 1111 0101 */ +OPHANDLER( mov_mem_a ) +{ + UINT8 addr = ROP_ARG(PC++); //Grab data address + IRAM_W(addr,ACC); //Store A to data address +} + +//MOV @R0/@R1, A /* 1: 1111 011i */ +OPHANDLER( mov_ir_a ) +{ + IRAM_IW(R_REG(r),ACC); //Store A to location pointed to by R0 or R1 +} + +//MOV R0 to R7, A /* 1: 1111 1rrr */ +OPHANDLER( mov_r_a ) +{ + SET_REG(r, ACC); //Store A to R0-R7 +} + +//MOVC A, @A + PC /* 1: 1000 0011 */ +OPHANDLER( movc_a_iapc ) +{ + UINT8 data; + data = CODEMEM_R(ACC+PC); //Move a byte from CODE(Program) Memory and store to ACC + SET_ACC(data); +} + +//MOV C, bit addr /* 1: 1010 0010 */ +OPHANDLER( mov_c_bitaddr ) +{ + UINT8 addr = ROP_ARG(PC++); //Grab bit address + SET_CY( (BIT_R(addr)) ); //Store Bit from Bit Address to Carry Flag +} + +//MOVC A, @A + DPTR /* 1: 1001 0011 */ +OPHANDLER( movc_a_iadptr ) +{ + UINT8 data; + data = CODEMEM_R(ACC + DPTR); //Move a byte from CODE(Program) Memory and store to ACC + SET_ACC(data); +} + +//MOVX A,@DPTR /* 1: 1110 0000 */ +//(Move External Ram 16 bit address to A) +OPHANDLER( movx_a_idptr ) +{ +// UINT8 byte = DATAMEM_R(R_DPTR); //Grab 1 byte from External DATA memory pointed to by dptr + UINT32 addr = ERAM_ADDR(DPTR, 0xFFFF); + UINT8 byte = DATAMEM_R(addr); //Grab 1 byte from External DATA memory pointed to by dptr + SET_ACC(byte); //Store to ACC +} + +//MOVX A, @R0/@R1 /* 1: 1110 001i */ +//(Move External Ram 8 bit address to A) +OPHANDLER( movx_a_ir ) +{ + UINT32 addr = ERAM_ADDR(R_REG(r),0xFF); //Grab address by reading location pointed to by R0 or R1 + UINT8 byte = DATAMEM_R(addr); //Grab 1 byte from External DATA memory pointed to by address + SET_ACC(byte); //Store to ACC +} + +//MOVX @DPTR,A /* 1: 1111 0000 */ +//(Move A to External Ram 16 bit address) +OPHANDLER( movx_idptr_a ) +{ +// DATAMEM_W(R_DPTR, ACC); //Store ACC to External DATA memory address pointed to by DPTR + UINT32 addr = ERAM_ADDR(DPTR, 0xFFFF); + DATAMEM_W(addr, ACC); //Store ACC to External DATA memory address pointed to by DPTR +} + +//MOVX @R0/@R1,A /* 1: 1111 001i */ +//(Move A to External Ram 8 bit address) +OPHANDLER( movx_ir_a ) +{ + UINT32 addr = ERAM_ADDR(R_REG(r),0xFF); //Grab address by reading location pointed to by R0 or R1 + DATAMEM_W(addr, ACC); //Store ACC to External DATA memory address +} + +//MUL AB /* 1: 1010 0100 */ +OPHANDLER( mul_ab ) +{ + UINT16 result = ACC * B; + //A gets lo bits, B gets hi bits of result + B = (UINT8) ((result & 0xFF00) >> 8); + SET_ACC((UINT8)(result & 0x00FF)); + //Set flags + SET_OV( ((result & 0x100) >> 8) ); //Set/Clear Overflow Flag if result > 255 + SET_CY(0); //Carry Flag always cleared +} + +//NOP /* 1: 0000 0000 */ +OPHANDLER( nop ) +{ +} + +//ORL data addr, A /* 1: 0100 0010 */ +OPHANDLER( orl_mem_a ) +{ + UINT8 addr = ROP_ARG(PC++); //Grab data address + UINT8 data = IRAM_R(addr); //Grab data from data address + IRAM_W(addr,data | ACC); //Set data address value to it's value Logical OR with ACC +} + +//ORL data addr, #data /* 1: 0100 0011 */ +OPHANDLER( orl_mem_byte ) +{ + UINT8 addr = ROP_ARG(PC++); //Grab data address + UINT8 data = ROP_ARG(PC++); //Grab data + UINT8 srcdata = IRAM_R(addr); //Grab data from data address + IRAM_W(addr,srcdata | data); //Set data address value to it's value Logical OR with Data +} + +//ORL A, #data /* 1: 0100 0100 */ +OPHANDLER( orl_a_byte ) +{ + UINT8 data = ROP_ARG(PC++); //Grab data + SET_ACC(ACC | data); //Set ACC to value of ACC Logical OR with Data +} + +//ORL A, data addr /* 1: 0100 0101 */ +OPHANDLER( orl_a_mem ) +{ + UINT8 addr = ROP_ARG(PC++); //Grab data address + UINT8 data = IRAM_R(addr); //Grab data from data address + SET_ACC(ACC | data); //Set ACC to value of ACC Logical OR with Data +} + +//ORL A, @RO/@R1 /* 1: 0100 011i */ +OPHANDLER( orl_a_ir ) +{ + UINT8 data = IRAM_IR(R_REG(r)); //Grab data from address R0 or R1 points to + SET_ACC(ACC | data); //Set ACC to value of ACC Logical OR with Data +} + +//ORL A, RO to R7 /* 1: 0100 1rrr */ +OPHANDLER( orl_a_r ) +{ + UINT8 data = R_REG(r); //Grab data from R0 - R7 + SET_ACC(ACC | data); //Set ACC to value of ACC Logical OR with Data +} + +//ORL C, bit addr /* 1: 0111 0010 */ +OPHANDLER( orl_c_bitaddr ) +{ + int cy = GET_CY; + UINT8 addr = ROP_ARG(PC++); //Grab bit address + UINT8 bit = BIT_R(addr); //Grab bit data from bit address + SET_CY( (cy | bit) ); //Set Carry flag to Carry Flag Value Logical OR with Bit +} + +//ORL C, /bit addr /* 1: 1010 0000 */ +OPHANDLER( orl_c_nbitaddr ) +{ + int cy = GET_CY; + UINT8 addr = ROP_ARG(PC++); //Grab bit address + UINT8 bit = BIT_R(addr); //Grab bit data from bit address + bit = ((~bit)&1); //Complement bit + SET_CY( (cy | bit) ); //Set Carry flag to Carry Flag Value Logical OR with Complemented Bit +} + +//POP data addr /* 1: 1101 0000 */ +OPHANDLER( pop ) +{ + UINT8 addr = ROP_ARG(PC++); //Grab data address + IRAM_W(addr, IRAM_IR(SP)); //Store to contents of data addr, data pointed to by Stack - IRAM_IR needed to access upper 128 bytes of stack + //IRAM_IW(addr, IRAM_IR(R_SP)); //Store to contents of data addr, data pointed to by Stack - doesn't work, sfr's are not restored this way and it's not an indirect access anyway + SP = SP-1; //Decrement SP +} + +//PUSH data addr /* 1: 1100 0000 */ +OPHANDLER( push ) +{ + UINT8 addr = ROP_ARG(PC++); //Grab data address + UINT8 tmpSP = SP+1; //Grab and Increment Stack Pointer + SP = tmpSP; // "" + IRAM_IW(tmpSP, IRAM_R(addr)); //Store to stack contents of data address - IRAM_IW needed to store to upper 128 bytes of stack, however, can't use IRAM_IR because that won't store the sfrs and it's not an indirect access anyway +} + +//RET /* 1: 0010 0010 */ +OPHANDLER( ret ) +{ + POP_PC(); +} + +//RETI /* 1: 0011 0010 */ +OPHANDLER( reti ) +{ + POP_PC(); + CLEAR_CURRENT_IRQ(); +} + +//RL A /* 1: 0010 0011 */ +OPHANDLER( rl_a ) +{ + //Left Shift A, Bit 7 carries to Bit 0 + int carry = ((ACC & 0x80) >> 7); + int data = (ACC<<1) & 0xfe; + SET_ACC( data | carry); +} + +//RLC A /* 1: 0011 0011 */ +OPHANDLER( rlc_a ) +{ + //Left Shift A, Bit 7 goes to Carry Flag, Original Carry Flag goes to Bit 0 of ACC + int carry = ((ACC & 0x80) >> 7); + int data = ((ACC<<1) & 0xfe) | GET_CY; + SET_ACC( data); + SET_CY(carry); +} + +//RR A /* 1: 0000 0011 */ +OPHANDLER( rr_a ) +{ + //Right Shift A, Bit 0 carries to Bit 7 + int carry = ((ACC & 1) << 7); + int data = (ACC>>1) & 0x7f; + SET_ACC( data | carry); +} + +//RRC A /* 1: 0001 0011 */ +OPHANDLER( rrc_a ) +{ + //Right Shift A, Bit 0 goes to Carry Flag, Bit 7 of ACC gets set to original Carry Flag + int carry = (ACC & 1); + int data = ((ACC>>1) & 0x7f) | (GET_CY<<7); + SET_ACC( data); + SET_CY(carry); +} + +//SETB C /* 1: 1101 0011 */ +OPHANDLER( setb_c ) +{ + SET_CY(1); //Set Carry Flag +} + +//SETB bit addr /* 1: 1101 0010 */ +OPHANDLER( setb_bitaddr ) +{ + UINT8 addr = ROP_ARG(PC++); //Grab bit address + BIT_W(addr,1); //Set Bit at Bit Address +} + +//SJMP code addr /* 1: 1000 0000 */ +OPHANDLER( sjmp ) +{ + INT8 rel_addr = ROP_ARG(PC++); //Grab relative code address + PC = PC + rel_addr; //Update PC +} + +//SUBB A, #data /* 1: 1001 0100 */ +OPHANDLER( subb_a_byte ) +{ + UINT8 data = ROP_ARG(PC++); //Grab data + UINT8 result = ACC - data - GET_CY; //Subtract data & carry flag from accumulator + DO_SUB_FLAGS(ACC,data,GET_CY); //Set Flags + SET_ACC(result); //Store 8 bit result of addtion in ACC + +} + +//SUBB A, data addr /* 1: 1001 0101 */ +OPHANDLER( subb_a_mem ) +{ + UINT8 addr = ROP_ARG(PC++); //Grab data address + UINT8 data = IRAM_R(addr); //Grab data from data address + UINT8 result = ACC - data - GET_CY; //Subtract data & carry flag from accumulator + DO_SUB_FLAGS(ACC,data,GET_CY); //Set Flags + SET_ACC(result); //Store 8 bit result of addtion in ACC +} + +//SUBB A, @R0/@R1 /* 1: 1001 011i */ +OPHANDLER( subb_a_ir ) +{ + UINT8 data = IRAM_IR(R_REG(r)); //Grab data from memory pointed to by R0 or R1 + UINT8 result = ACC - data - GET_CY; //Subtract data & carry flag from accumulator + DO_SUB_FLAGS(ACC,data,GET_CY); //Set Flags + SET_ACC(result); //Store 8 bit result of addtion in ACC +} + +//SUBB A, R0 to R7 /* 1: 1001 1rrr */ +OPHANDLER( subb_a_r ) +{ + UINT8 data = R_REG(r); //Grab data from R0 - R7 + UINT8 result = ACC - data - GET_CY; //Subtract data & carry flag from accumulator + DO_SUB_FLAGS(ACC,data,GET_CY); //Set Flags + SET_ACC(result); //Store 8 bit result of addtion in ACC +} + +//SWAP A /* 1: 1100 0100 */ +OPHANDLER( swap_a ) +{ + UINT8 a_nib_lo, a_nib_hi; + a_nib_hi = (ACC & 0x0f) << 4; //Grab lo byte of ACC and move to hi + a_nib_lo = (ACC & 0xf0) >> 4; //Grab hi byte of ACC and move to lo + SET_ACC( a_nib_hi | a_nib_lo); +} + +//XCH A, data addr /* 1: 1100 0101 */ +OPHANDLER( xch_a_mem ) +{ + UINT8 addr = ROP_ARG(PC++); //Grab data address + UINT8 data = IRAM_R(addr); //Grab data + UINT8 oldACC = ACC; //Hold value of ACC + SET_ACC(data); //Sets ACC to data + IRAM_W(addr,oldACC); //Sets data address to old value of ACC +} + +//XCH A, @RO/@R1 /* 1: 1100 011i */ +OPHANDLER( xch_a_ir ) +{ + UINT8 data = IRAM_IR(R_REG(r)); //Grab data pointed to by R0 or R1 + UINT8 oldACC = ACC; //Hold value of ACC + SET_ACC(data); //Sets ACC to data + IRAM_W(R_REG(r),oldACC); //Sets data address to old value of ACC +} + +//XCH A, RO to R7 /* 1: 1100 1rrr */ +OPHANDLER( xch_a_r ) +{ + UINT8 data = R_REG(r); //Grab data from R0-R7 + UINT8 oldACC = ACC; //Hold value of ACC + SET_ACC(data); //Sets ACC to data + SET_REG(r, oldACC); //Sets data address to old value of ACC +} + +//XCHD A, @R0/@R1 /* 1: 1101 011i */ +OPHANDLER( xchd_a_ir ) +{ + UINT8 acc, ir_data; + ir_data = IRAM_IR(R_REG(r)); //Grab data pointed to by R0 or R1 + acc = ACC; //Grab ACC value + SET_ACC( (acc & 0xf0) | (ir_data & 0x0f) ); //Set ACC to lower nibble of data pointed to by R0 or R1 + IRAM_W(R_REG(r), (ir_data & 0xf0) | (acc & 0x0f) ); //Set data pointed to by R0 or R1 to lower nibble of ACC +} + +//XRL data addr, A /* 1: 0110 0010 */ +OPHANDLER( xrl_mem_a ) +{ + UINT8 addr = ROP_ARG(PC++); //Grab data address + UINT8 data = IRAM_R(addr); //Grab data from data address + IRAM_W(addr,data ^ ACC); //Set data address value to it's value Logical XOR with ACC +} + +//XRL data addr, #data /* 1: 0110 0011 */ +OPHANDLER( xrl_mem_byte ) +{ + UINT8 addr = ROP_ARG(PC++); //Grab data address + UINT8 data = ROP_ARG(PC++); //Grab data + UINT8 srcdata = IRAM_R(addr); //Grab data from data address + IRAM_W(addr,srcdata ^ data); //Set data address value to it's value Logical XOR with Data +} + +//XRL A, #data /* 1: 0110 0100 */ +OPHANDLER( xrl_a_byte ) +{ + UINT8 data = ROP_ARG(PC++); //Grab data + SET_ACC(ACC ^ data); //Set ACC to value of ACC Logical XOR with Data +} + +//XRL A, data addr /* 1: 0110 0101 */ +OPHANDLER( xrl_a_mem ) +{ + UINT8 addr = ROP_ARG(PC++); //Grab data address + UINT8 data = IRAM_R(addr); //Grab data from data address + SET_ACC(ACC ^ data); //Set ACC to value of ACC Logical XOR with Data +} + +//XRL A, @R0/@R1 /* 1: 0110 011i */ +OPHANDLER( xrl_a_ir ) +{ + UINT8 data = IRAM_IR(R_REG(r)); //Grab data from address R0 or R1 points to + SET_ACC(ACC ^ data); //Set ACC to value of ACC Logical XOR with Data +} + +//XRL A, R0 to R7 /* 1: 0110 1rrr */ +OPHANDLER( xrl_a_r ) +{ + UINT8 data = R_REG(r); //Grab data from R0 - R7 + SET_ACC(ACC ^ data); //Set ACC to value of ACC Logical XOR with Data +} + +//illegal opcodes +OPHANDLER( illegal ) +{ + LOG(("i8051 '%s': illegal opcode at 0x%03x: %02x\n", tag(), PC-1, r)); +} diff --git a/src/devices/cpu/mcs96/i8x9x.c b/src/devices/cpu/mcs96/i8x9x.c new file mode 100644 index 00000000000..1170aa4fa1a --- /dev/null +++ b/src/devices/cpu/mcs96/i8x9x.c @@ -0,0 +1,373 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +/*************************************************************************** + + i8x9x.h + + MCS96, 8x9x branch, the original version + +***************************************************************************/ + +#include "emu.h" +#include "i8x9x.h" + +i8x9x_device::i8x9x_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + mcs96_device(mconfig, type, name, tag, owner, clock, 8, "i8x9x", __FILE__), + io_config("io", ENDIANNESS_LITTLE, 16, 16, -1) +{ +} + +offs_t i8x9x_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + return disasm_generic(buffer, pc, oprom, opram, options, disasm_entries); +} + +const address_space_config *i8x9x_device::memory_space_config(address_spacenum spacenum) const +{ + return spacenum == AS_PROGRAM ? &program_config : spacenum == AS_IO ? &io_config : NULL; +} + +void i8x9x_device::device_start() +{ + mcs96_device::device_start(); + io = &space(AS_IO); + cycles_scaling = 3; +} + +void i8x9x_device::device_reset() +{ + mcs96_device::device_reset(); + memset(hso_info, 0, sizeof(hso_info)); + memset(&hso_cam_hold, 0, sizeof(hso_cam_hold)); + hso_command = 0; + hso_time = 0; + base_timer2 = 0; + ios0 = ios1 = ioc0 = ioc1 = 0x00; + ad_result = 0; + ad_done = 0; + sp_stat = 0; + serial_send_timer = 0; +} + +void i8x9x_device::commit_hso_cam() +{ + for(int i=0; i<8; i++) + if(!hso_info[i].active) { + if(hso_command != 0x18 && hso_command != 0x19) + logerror("%s: hso cam %02x %04x in slot %d (%04x)\n", tag(), hso_command, hso_time, i, PPC); + hso_info[i].active = true; + hso_info[i].command = hso_command; + hso_info[i].time = hso_time; + internal_update(total_cycles()); + return; + } + hso_cam_hold.active = true; + hso_cam_hold.command = hso_command; + hso_cam_hold.time = hso_time; +} + +void i8x9x_device::ad_start(UINT64 current_time) +{ + ad_result = (io->read_word(2*((ad_command & 7) + A0)) << 6) | 8 | (ad_command & 7); + ad_done = current_time + 88; + internal_update(current_time); +} + +void i8x9x_device::serial_send(UINT8 data) +{ + serial_send_buf = data; + serial_send_timer = total_cycles() + 9600; +} + +void i8x9x_device::serial_send_done() +{ + serial_send_timer = 0; + io->write_word(SERIAL*2, serial_send_buf); + pending_irq |= IRQ_SERIAL; + sp_stat |= 0x20; + check_irq(); +} + +void i8x9x_device::io_w8(UINT8 adr, UINT8 data) +{ + switch(adr) { + case 0x02: + ad_command = data; + if(ad_command & 8) + ad_start(total_cycles()); + break; + case 0x03: + logerror("%s: hsi_mode %02x (%04x)\n", tag(), data, PPC); + break; + case 0x04: + hso_time = (hso_time & 0xff00) | data; + break; + case 0x05: + hso_time = (hso_time & 0x00ff) | (data << 8); + commit_hso_cam(); + break; + case 0x06: + hso_command = data; + break; + case 0x07: + logerror("%s: sbuf %02x (%04x)\n", tag(), data, PPC); + serial_send(data); + break; + case 0x08: + PSW = (PSW & 0xff00) | data; + check_irq(); + break; + case 0x09: + pending_irq = data; + logerror("%s: int_pending %02x (%04x)\n", tag(), data, PPC); + break; + case 0x0a: + logerror("%s: watchdog %02x (%04x)\n", tag(), data, PPC); + break; + case 0x0e: + logerror("%s: baud rate %02x (%04x)\n", tag(), data, PPC); + break; + case 0x0f: + logerror("%s: io port 1 %02x (%04x)\n", tag(), data, PPC); + io->write_word(P1*2, data); + break; + case 0x10: + logerror("%s: io port 2 %02x (%04x)\n", tag(), data, PPC); + io->write_word(P2*2, data); + break; + case 0x11: + logerror("%s: sp con %02x (%04x)\n", tag(), data, PPC); + break; + case 0x15: + logerror("%s: ioc0 %02x (%04x)\n", tag(), data, PPC); + ioc0 = data; + break; + case 0x16: + logerror("%s: ioc1 %02x (%04x)\n", tag(), data, PPC); + ioc1 = data; + break; + case 0x17: + logerror("%s: pwm control %02x (%04x)\n", tag(), data, PPC); + break; + } + return; +} + +void i8x9x_device::io_w16(UINT8 adr, UINT16 data) +{ + switch(adr) { + case 0: + break; + case 4: + hso_time = data; + commit_hso_cam(); + break; + default: + io_w8(adr, data); + io_w8(adr+1, data>>8); + break; + } + return; +} + +UINT8 i8x9x_device::io_r8(UINT8 adr) +{ + switch(adr) { + case 0x00: + return 0x00; + case 0x01: + return 0x00; + case 0x02: + return ad_result; + case 0x03: + return ad_result >> 8; + case 0x04: + logerror("%s: read hsi time l (%04x)\n", tag(), PPC); + return 0x00; + case 0x05: + logerror("%s: read hsi time h (%04x)\n", tag(), PPC); + return 0x00; + case 0x06: + logerror("%s: read hsi status (%04x)\n", tag(), PPC); + return 0x00; + case 0x07: + logerror("%s: read sbuf %02x (%04x)\n", tag(), sbuf, PPC); + return sbuf; + case 0x08: + return PSW; + case 0x09: + logerror("%s: read int pending (%04x)\n", tag(), PPC); + return pending_irq; + case 0x0a: + logerror("%s: read timer1 l (%04x)\n", tag(), PPC); + return timer_value(1, total_cycles()); + case 0x0b: + logerror("%s: read timer1 h (%04x)\n", tag(), PPC); + return timer_value(1, total_cycles()) >> 8; + case 0x0c: + logerror("%s: read timer2 l (%04x)\n", tag(), PPC); + return timer_value(2, total_cycles()); + case 0x0d: + logerror("%s: read timer2 h (%04x)\n", tag(), PPC); + return timer_value(2, total_cycles()) >> 8; + case 0x0e: { + static int last = -1; + if(io->read_word(P0*2) != last) { + last = io->read_word(P0*2); + logerror("%s: read p0 %02x\n", tag(), io->read_word(P0*2)); + } + return io->read_word(P0*2); + } + case 0x0f: + return io->read_word(P1*2); + case 0x10: + return io->read_word(P2*2); + case 0x11: { + UINT8 res = sp_stat; + sp_stat &= 0x80; + logerror("%s: read sp stat %02x (%04x)\n", tag(), res, PPC); + return res; + } + case 0x15: + logerror("%s: read ios 0 %02x (%04x)\n", tag(), ios0, PPC); + return ios0; + case 0x16: { + UINT8 res = ios1; + ios1 = ios1 & 0xc0; + return res; + } + default: + logerror("%s: io_r8 %02x (%04x)\n", tag(), adr, PPC); + return 0x00; + } +} + +UINT16 i8x9x_device::io_r16(UINT8 adr) +{ + switch(adr) { + case 0x00: + return 0x0000; + case 0x02: + return ad_result; + case 0x04: + logerror("%s: read hsi time (%04x)\n", tag(), PPC); + return 0x0000; + case 0x0a: + return timer_value(1, total_cycles()); + case 0x0c: + logerror("%s: read timer2 (%04x)\n", tag(), PPC); + return timer_value(2, total_cycles()); + default: + return io_r8(adr) | (io_r8(adr+1) << 8); + } +} + +void i8x9x_device::do_exec_partial() +{ +} + +void i8x9x_device::serial_w(UINT8 val) +{ + sbuf = val; + sp_stat |= 0x40; + pending_irq |= IRQ_SERIAL; + check_irq(); +} + +UINT16 i8x9x_device::timer_value(int timer, UINT64 current_time) const +{ + if(timer == 2) + current_time -= base_timer2; + return current_time >> 3; +} + +UINT64 i8x9x_device::timer_time_until(int timer, UINT64 current_time, UINT16 timer_value) const +{ + UINT64 timer_base = timer == 2 ? base_timer2 : 0; + UINT64 delta = (current_time - timer_base) >> 3; + UINT32 tdelta = UINT16(timer_value - delta); + if(!tdelta) + tdelta = 0x10000; + return timer_base + ((delta + tdelta) << 3); +} + +void i8x9x_device::trigger_cam(int id, UINT64 current_time) +{ + hso_cam_entry &cam = hso_info[id]; + cam.active = false; + switch(cam.command & 0x0f) { + case 0x8: case 0x9: case 0xa: case 0xb: + ios1 |= 1 << (cam.command & 3); + pending_irq |= IRQ_SOFT; + check_irq(); + break; + + default: + logerror("%s: Action %x unimplemented\n", tag(), cam.command & 0x0f); + break; + } +} + +void i8x9x_device::internal_update(UINT64 current_time) +{ + UINT16 current_timer1 = timer_value(1, current_time); + UINT16 current_timer2 = timer_value(2, current_time); + + for(int i=0; i<8; i++) + if(hso_info[i].active) { + UINT8 cmd = hso_info[i].command; + UINT16 t = hso_info[i].time; + if(((cmd & 0x40) && t == current_timer2) || + (!(cmd & 0x40) && t == current_timer1)) { + if(cmd != 0x18 && cmd != 0x19) + logerror("%s: hso cam %02x %04x in slot %d triggered\n", + tag(), cmd, t, i); + trigger_cam(i, current_time); + } + } + + if(current_time == ad_done) { + ad_done = 0; + ad_result &= ~8; + } + + if(current_time == serial_send_timer) + serial_send_done(); + + UINT64 event_time = 0; + for(int i=0; i<8; i++) { + if(!hso_info[i].active && hso_cam_hold.active) { + hso_info[i] = hso_cam_hold; + hso_cam_hold.active = false; + logerror("%s: hso cam %02x %04x in slot %d from hold\n", tag(), hso_cam_hold.command, hso_cam_hold.time, i); + } + if(hso_info[i].active) { + UINT64 new_time = timer_time_until(hso_info[i].command & 0x40 ? 2 : 1, current_time, hso_info[i].time); + if(!event_time || new_time < event_time) + event_time = new_time; + } + } + + if(ad_done && ad_done < event_time) + event_time = ad_done; + + if(serial_send_timer && serial_send_timer < event_time) + event_time = serial_send_timer; + + recompute_bcount(event_time); +} + +c8095_device::c8095_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + i8x9x_device(mconfig, C8095, "C8095", tag, owner, clock, "c8095", __FILE__) +{ +} + +p8098_device::p8098_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + i8x9x_device(mconfig, P8098, "P8098", tag, owner, clock, "p8098", __FILE__) +{ +} + +const device_type C8095 = &device_creator; +const device_type P8098 = &device_creator; + +#include "cpu/mcs96/i8x9x.inc" diff --git a/src/devices/cpu/mcs96/i8x9x.h b/src/devices/cpu/mcs96/i8x9x.h new file mode 100644 index 00000000000..3f700fd6e9d --- /dev/null +++ b/src/devices/cpu/mcs96/i8x9x.h @@ -0,0 +1,98 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +/*************************************************************************** + + i8x9x.h + + MCS96, 8x9x branch, the original version + +***************************************************************************/ + +#ifndef __I8X9X_H__ +#define __I8X9X_H__ + +#include "mcs96.h" + +class i8x9x_device : public mcs96_device { +public: + enum { + A0, A1, A2, A3, A4, A5, A6, A7, + SERIAL, + P0, P1, P2 + }; + + i8x9x_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + void serial_w(UINT8 val); + +protected: + virtual void device_start(); + virtual void device_reset(); + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const; + + static const disasm_entry disasm_entries[0x100]; + + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + virtual void do_exec_full(); + virtual void do_exec_partial(); + virtual void internal_update(UINT64 current_time); + virtual void io_w8(UINT8 adr, UINT8 data); + virtual void io_w16(UINT8 adr, UINT16 data); + virtual UINT8 io_r8(UINT8 adr); + virtual UINT16 io_r16(UINT8 adr); + +private: + enum { + IRQ_TIMER = 0x01, + IRQ_AD = 0x02, + IRQ_HSI = 0x04, + IRQ_HSO = 0x08, + IRQ_HSI0 = 0x10, + IRQ_SOFT = 0x20, + IRQ_SERIAL = 0x40, + IRQ_EXTINT = 0x80 + }; + + struct hso_cam_entry { + bool active; + UINT8 command; + UINT16 time; + }; + + address_space_config io_config; + address_space *io; + + hso_cam_entry hso_info[8]; + hso_cam_entry hso_cam_hold; + + UINT64 base_timer2, ad_done; + UINT8 hso_command, ad_command; + UINT16 hso_time, ad_result; + UINT8 ios0, ios1, ioc0, ioc1; + UINT8 sbuf, sp_stat; + UINT8 serial_send_buf; + UINT64 serial_send_timer; + + UINT16 timer_value(int timer, UINT64 current_time) const; + UINT64 timer_time_until(int timer, UINT64 current_time, UINT16 timer_value) const; + void commit_hso_cam(); + void trigger_cam(int id, UINT64 current_time); + void ad_start(UINT64 current_time); + void serial_send(UINT8 data); + void serial_send_done(); +}; + +class c8095_device : public i8x9x_device { +public: + c8095_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class p8098_device : public i8x9x_device { +public: + p8098_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +extern const device_type C8095; +extern const device_type P8098; + +#endif diff --git a/src/devices/cpu/mcs96/i8xc196.c b/src/devices/cpu/mcs96/i8xc196.c new file mode 100644 index 00000000000..19553280de2 --- /dev/null +++ b/src/devices/cpu/mcs96/i8xc196.c @@ -0,0 +1,76 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +/*************************************************************************** + + i8xc196.h + + MCS96, c196 branch, the enhanced 16 bits bus version + +***************************************************************************/ + +#include "emu.h" +#include "i8xc196.h" + +i8xc196_device::i8xc196_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + mcs96_device(mconfig, type, name, tag, owner, clock, 16, shortname, source) +{ +} + +offs_t i8xc196_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + return disasm_generic(buffer, pc, oprom, opram, options, disasm_entries); +} + +void i8xc196_device::io_w8(UINT8 adr, UINT8 data) +{ + switch(adr) { + case 0: + break; + case 1: + break; + default: + logerror("%s: io_w8 %02x, %02x (%04x)\n", tag(), adr, data, PPC); + } + return; +} + +void i8xc196_device::io_w16(UINT8 adr, UINT16 data) +{ + switch(adr) { + case 0: + break; + default: + io_w8(adr, data); + io_w8(adr+1, data>>8); + break; + } + return; +} + +UINT8 i8xc196_device::io_r8(UINT8 adr) +{ + switch(adr) { + case 0x00: + return 0x00; + case 0x01: + return 0x00; + } + UINT8 data = 0x00; + logerror("%s: io_r8 %02x, %02x (%04x)\n", tag(), adr, data, PPC); + return data; +} + +UINT16 i8xc196_device::io_r16(UINT8 adr) +{ + if(adr < 2) + return 0x0000; + UINT16 data = 0x0000; + logerror("%s: io_r16 %02x, %04x (%04x)\n", tag(), adr, data, PPC); + return data; +} + +void i8xc196_device::do_exec_partial() +{ +} + +#include "cpu/mcs96/i8xc196.inc" diff --git a/src/devices/cpu/mcs96/i8xc196.h b/src/devices/cpu/mcs96/i8xc196.h new file mode 100644 index 00000000000..299f6c9128d --- /dev/null +++ b/src/devices/cpu/mcs96/i8xc196.h @@ -0,0 +1,46 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +/*************************************************************************** + + i8xc196.h + + MCS96, c196 branch, the enhanced 16 bits bus version + +***************************************************************************/ + +#ifndef __I8XC196_H__ +#define __I8XC196_H__ + +#include "mcs96.h" + +class i8xc196_device : public mcs96_device { +public: + i8xc196_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + static const disasm_entry disasm_entries[0x100]; + + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + virtual void do_exec_full(); + virtual void do_exec_partial(); + + virtual void io_w8(UINT8 adr, UINT8 data); + virtual void io_w16(UINT8 adr, UINT16 data); + virtual UINT8 io_r8(UINT8 adr); + virtual UINT16 io_r16(UINT8 adr); + +#define O(o) void o ## _196_full(); void o ## _196_partial() + + O(bmov_direct_2); + O(bmovi_direct_2); + O(cmpl_direct_2); + O(djnzw_rrel8); + O(idlpd_none); + O(pop_indexed_1); + O(pop_indirect_1); + O(popa_none); + O(pusha_none); + +#undef O +}; + +#endif diff --git a/src/devices/cpu/mcs96/mcs96.c b/src/devices/cpu/mcs96/mcs96.c new file mode 100644 index 00000000000..4c4cf849b88 --- /dev/null +++ b/src/devices/cpu/mcs96/mcs96.c @@ -0,0 +1,751 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +/*************************************************************************** + + mcs96.h + + MCS96, 8098/8398/8798 branch + +***************************************************************************/ + +#include "emu.h" +#include "debugger.h" +#include "mcs96.h" + +mcs96_device::mcs96_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, int data_width, const char *shortname, const char *source) : + cpu_device(mconfig, type, name, tag, owner, clock, shortname, source), + program_config("program", ENDIANNESS_LITTLE, data_width, 16) +{ +} + +void mcs96_device::device_start() +{ + program = &space(AS_PROGRAM); + direct = &program->direct(); + m_icountptr = &icount; + + state_add(STATE_GENPC, "GENPC", PC).noshow(); + state_add(STATE_GENPCBASE, "GENPCBASE", PPC).noshow(); + state_add(STATE_GENSP, "GENSP", R[0]).noshow(); + state_add(STATE_GENFLAGS, "GENFLAGS", PSW).formatstr("%16s").noshow(); + state_add(MCS96_PC, "PC", PC); + state_add(MCS96_PSW, "PSW", PSW); + state_add(MCS96_R, "SP", R[0]); + for(int i=1; i<0x74; i++) { + char buf[10]; + sprintf(buf, "R%02x", i*2+0x18); + state_add(MCS96_R+i, buf, R[i]); + } + + memset(R, 0, sizeof(R)); +} + +void mcs96_device::device_reset() +{ + PC = 0x2080; + PPC = PC; + PSW = 0; + pending_irq = 0x00; + irq_requested = false; + inst_state = STATE_FETCH; +} + +UINT32 mcs96_device::execute_min_cycles() const +{ + return 4; +} + +UINT32 mcs96_device::execute_max_cycles() const +{ + return 33; +} + +UINT32 mcs96_device::execute_input_lines() const +{ + return 1; +} + +void mcs96_device::recompute_bcount(UINT64 event_time) +{ + if(!event_time || event_time >= total_cycles() + icount) { + bcount = 0; + return; + } + bcount = total_cycles() + icount - event_time; +} + +void mcs96_device::check_irq() +{ + irq_requested = (PSW & pending_irq) && (PSW & F_I); +} + +void mcs96_device::execute_run() +{ + internal_update(total_cycles()); + + // if(inst_substate) + // do_exec_partial(); + + while(icount > 0) { + while(icount > bcount) { + int picount = inst_state >= 0x200 ? -1 : icount; + do_exec_full(); + if(icount == picount) { + fatalerror("Unhandled %x (%04x)\n", inst_state, PPC); + } + } + while(bcount && icount <= bcount) + internal_update(total_cycles() + icount - bcount); + // if(inst_substate) + // do_exec_partial(); + } +} + +void mcs96_device::execute_set_input(int inputnum, int state) +{ + switch(inputnum) { + case EXINT_LINE: + if(state) + pending_irq |= 0x80; + else + pending_irq &= 0x7f; + check_irq(); + break; + } +} + +const address_space_config *mcs96_device::memory_space_config(address_spacenum spacenum) const +{ + return (spacenum == AS_PROGRAM) ? &program_config : NULL; +} + +void mcs96_device::state_import(const device_state_entry &entry) +{ +} + +void mcs96_device::state_export(const device_state_entry &entry) +{ +} + +void mcs96_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + switch(entry.index()) { + case STATE_GENFLAGS: + case MCS96_PSW: + strprintf(str, "%c%c%c%c%c%c%c %c%c%c%c%c%c%c%c", + PSW & F_Z ? 'Z' : '.', + PSW & F_N ? 'N' : '.', + PSW & F_V ? 'V' : '.', + PSW & F_VT ? 'v' : '.', + PSW & F_C ? 'C' : '.', + PSW & F_I ? 'I' : '.', + PSW & F_ST ? 'S' : '.', + PSW & 0x80 ? '7' : '.', + PSW & 0x40 ? '6' : '.', + PSW & 0x20 ? '5' : '.', + PSW & 0x10 ? '4' : '.', + PSW & 0x08 ? '3' : '.', + PSW & 0x04 ? '2' : '.', + PSW & 0x02 ? '1' : '.', + PSW & 0x01 ? '0' : '.'); + break; + } +} + +std::string mcs96_device::regname(UINT8 reg) +{ + char res[32]; + switch(reg) { + case 0x18: + strcpy(res, "sp"); + break; + + case 0x19: + strcpy(res, "sph"); + break; + + default: + sprintf(res, "%02x", reg); + break; + } + return res; +} + +offs_t mcs96_device::disasm_generic(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options, const disasm_entry *entries) +{ + bool prefix_fe = false; + int off = 0; + if(oprom[0] == 0xfe && entries[oprom[1]].opcode_fe) { + prefix_fe = true; + pc++; + off++; + oprom++; + } + const disasm_entry &e = entries[oprom[0]]; + UINT32 flags = e.flags | DASMFLAG_SUPPORTED; + buffer += sprintf(buffer, "%s", prefix_fe ? e.opcode_fe : e.opcode); + + switch(e.mode) { + case DASM_none: + flags |= 1; + break; + + case DASM_nop_2: + sprintf(buffer, " %02x", oprom[1]); + flags |= 2; + break; + + case DASM_rel8: { + int delta = oprom[1]; + if(delta & 0x80) + delta -= 0x100; + sprintf(buffer, " %04x", (pc+2+delta) & 0xffff); + flags |= 2; + break; + } + + case DASM_rel11: { + int delta = ((oprom[0] << 8) | oprom[1]) & 0x7ff; + if(delta & 0x400) + delta -= 0x800; + sprintf(buffer, " %04x", (pc+2+delta) & 0xffff); + flags |= 2; + break; + } + + case DASM_rel16: { + int delta = oprom[1] | (oprom[2] << 8); + sprintf(buffer, " %04x", (pc+3+delta) & 0xffff); + flags |= 3; + break; + } + + case DASM_rrel8: { + int delta = oprom[2]; + if(delta & 0x80) + delta -= 0x100; + sprintf(buffer, " %s, %04x", regname(oprom[1]).c_str(), (pc+3+delta) & 0xffff); + flags |= 3; + break; + } + + case DASM_brrel8: { + int delta = oprom[2]; + if(delta & 0x80) + delta -= 0x100; + sprintf(buffer, " %d, %s, %04x", oprom[0] & 7, regname(oprom[1]).c_str(), (pc+3+delta) & 0xffff); + flags |= 3; + break; + } + + case DASM_direct_1: + sprintf(buffer, " %s", regname(oprom[1]).c_str()); + flags |= 2; + break; + + case DASM_direct_2: + sprintf(buffer, " %s, %s", regname(oprom[2]).c_str(), regname(oprom[1]).c_str()); + flags |= 3; + break; + + case DASM_direct_3: + sprintf(buffer, " %s, %s, %s", regname(oprom[3]).c_str(), regname(oprom[2]).c_str(), regname(oprom[1]).c_str()); + flags |= 4; + break; + + case DASM_immed_1b: + sprintf(buffer, " #%02x", oprom[1]); + flags |= 2; + break; + + case DASM_immed_2b: + sprintf(buffer, " %s, #%02x", regname(oprom[2]).c_str(), oprom[1]); + flags |= 3; + break; + + case DASM_immed_or_reg_2b: + if(oprom[1] >= 0x10) + sprintf(buffer, " %s, %s", regname(oprom[2]).c_str(), regname(oprom[1]).c_str()); + else + sprintf(buffer, " %s, #%02x", regname(oprom[2]).c_str(), oprom[1]); + flags |= 3; + break; + + case DASM_immed_3b: + sprintf(buffer, " %s, %s, #%02x", regname(oprom[3]).c_str(), regname(oprom[2]).c_str(), oprom[1]); + flags |= 4; + break; + + case DASM_immed_1w: + sprintf(buffer, " #%02x%02x", oprom[2], oprom[1]); + flags |= 3; + break; + + case DASM_immed_2w: + sprintf(buffer, " %s, #%02x%02x", regname(oprom[3]).c_str(), oprom[2], oprom[1]); + flags |= 4; + break; + + case DASM_immed_3w: + sprintf(buffer, " %s, %s, #%02x%02x", regname(oprom[4]).c_str(), regname(oprom[3]).c_str(), oprom[2], oprom[1]); + flags |= 5; + break; + + case DASM_indirect_1n: + sprintf(buffer, " [%s]", regname(oprom[1]).c_str()); + flags |= 2; + break; + + case DASM_indirect_1: + if(oprom[1] & 0x01) { + sprintf(buffer, " [%s]+", regname(oprom[1]-1).c_str()); + flags |= 2; + } else { + sprintf(buffer, " [%s]", regname(oprom[1]).c_str()); + flags |= 2; + } + break; + + case DASM_indirect_2: + if(oprom[1] & 0x01) { + sprintf(buffer, " %s, [%s]+", regname(oprom[2]).c_str(), regname(oprom[1]-1).c_str()); + flags |= 3; + } else { + sprintf(buffer, " %s, [%s]", regname(oprom[2]).c_str(), regname(oprom[1]).c_str()); + flags |= 3; + } + break; + + case DASM_indirect_3: + if(oprom[1] & 0x01) { + sprintf(buffer, " %s, %s, [%s]+", regname(oprom[3]).c_str(), regname(oprom[2]).c_str(), regname(oprom[1]-1).c_str()); + flags |= 4; + } else { + sprintf(buffer, " %s, %s, [%s]", regname(oprom[3]).c_str(), regname(oprom[2]).c_str(), regname(oprom[1]).c_str()); + flags |= 4; + } + break; + + case DASM_indexed_1: + if(oprom[1] & 0x01) { + if(oprom[1] == 0x01) + sprintf(buffer, " %02x%02x", oprom[3], oprom[2]); + else + sprintf(buffer, " %02x%02x[%s]", oprom[3], oprom[2], regname(oprom[1]-1).c_str()); + flags |= 4; + } else { + int delta = oprom[2]; + if(delta & 0x80) + delta -= 0x100; + if(oprom[1] == 0x00) { + if(delta < 0) + sprintf(buffer, " %04x", delta & 0xffff); + else + sprintf(buffer, " %02x", delta); + } else { + if(delta < 0) + sprintf(buffer, " -%02x[%s]", -delta, regname(oprom[1]).c_str()); + else + sprintf(buffer, " %02x[%s]", delta, regname(oprom[1]).c_str()); + } + flags |= 3; + } + break; + + case DASM_indexed_2: + if(oprom[1] & 0x01) { + if(oprom[1] == 0x01) + sprintf(buffer, " %s, %02x%02x", regname(oprom[4]).c_str(), oprom[3], oprom[2]); + else + sprintf(buffer, " %s, %02x%02x[%s]", regname(oprom[4]).c_str(), oprom[3], oprom[2], regname(oprom[1]-1).c_str()); + flags |= 5; + } else { + int delta = oprom[2]; + if(delta & 0x80) + delta -= 0x100; + if(oprom[1] == 0x00) { + if(delta < 0) + sprintf(buffer, " %s, %04x", regname(oprom[3]).c_str(), delta & 0xffff); + else + sprintf(buffer, " %s, %02x", regname(oprom[3]).c_str(), delta); + } else { + if(delta < 0) + sprintf(buffer, " %s, -%02x[%s]", regname(oprom[3]).c_str(), -delta, regname(oprom[1]).c_str()); + else + sprintf(buffer, " %s, %02x[%s]", regname(oprom[3]).c_str(), delta, regname(oprom[1]).c_str()); + } + flags |= 4; + } + break; + + case DASM_indexed_3: + if(oprom[1] & 0x01) { + if(oprom[1] == 0x01) + sprintf(buffer, " %s, %s, %02x%02x", regname(oprom[5]).c_str(), regname(oprom[4]).c_str(), oprom[3], oprom[2]); + else + sprintf(buffer, " %s, %s, %02x%02x[%s]", regname(oprom[5]).c_str(), regname(oprom[4]).c_str(), oprom[3], oprom[2], regname(oprom[1]-1).c_str()); + flags |= 6; + } else { + int delta = oprom[2]; + if(delta & 0x80) + delta -= 0x100; + if(oprom[1] == 0x00) { + if(delta < 0) + sprintf(buffer, " %s, %s, %04x", regname(oprom[4]).c_str(), regname(oprom[3]).c_str(), delta & 0xffff); + else + sprintf(buffer, " %s, %s, %02x", regname(oprom[4]).c_str(), regname(oprom[3]).c_str(), delta); + } else { + if(delta < 0) + sprintf(buffer, " %s, %s, -%02x[%s]", regname(oprom[4]).c_str(), regname(oprom[3]).c_str(), -delta, regname(oprom[1]).c_str()); + else + sprintf(buffer, " %s, %s, %02x[%s]", regname(oprom[4]).c_str(), regname(oprom[3]).c_str(), delta, regname(oprom[1]).c_str()); + } + flags |= 5; + } + break; + + default: + fprintf(stderr, "Unhandled dasm mode %d\n", e.mode); + abort(); + }; + + return flags+off; +} + +UINT32 mcs96_device::disasm_min_opcode_bytes() const +{ + return 1; +} + +UINT32 mcs96_device::disasm_max_opcode_bytes() const +{ + return 7; +} + +void mcs96_device::io_w8(UINT8 adr, UINT8 data) +{ + switch(adr) { + case 0x02: + logerror("%s: ad_command %02x (%04x)\n", tag(), data, PPC); + break; + case 0x03: + logerror("%s: hsi_mode %02x (%04x)\n", tag(), data, PPC); + break; + case 0x04: + logerror("%s: hso_time.l %02x (%04x)\n", tag(), data, PPC); + break; + case 0x05: + logerror("%s: hso_time.h %02x (%04x)\n", tag(), data, PPC); + break; + case 0x06: + logerror("%s: hso_command %02x (%04x)\n", tag(), data, PPC); + break; + case 0x07: + logerror("%s: sbuf %02x (%04x)\n", tag(), data, PPC); + break; + case 0x08: + PSW = (PSW & 0xff00) | data; + break; + case 0x09: + logerror("%s: int_pending %02x (%04x)\n", tag(), data, PPC); + break; + case 0x0a: + logerror("%s: watchdog %02x (%04x)\n", tag(), data, PPC); + break; + case 0x0e: + logerror("%s: baud rate %02x (%04x)\n", tag(), data, PPC); + break; + case 0x0f: + logerror("%s: io port 1 %02x (%04x)\n", tag(), data, PPC); + break; + case 0x10: + logerror("%s: io port 2 %02x (%04x)\n", tag(), data, PPC); + break; + case 0x11: + logerror("%s: sp con %02x (%04x)\n", tag(), data, PPC); + break; + case 0x15: + logerror("%s: ioc0 %02x (%04x)\n", tag(), data, PPC); + break; + case 0x16: + logerror("%s: ioc1 %02x (%04x)\n", tag(), data, PPC); + break; + case 0x17: + logerror("%s: pwm control %02x (%04x)\n", tag(), data, PPC); + break; + } + return; +} + +void mcs96_device::io_w16(UINT8 adr, UINT16 data) +{ + switch(adr) { + case 0: + break; + case 4: + logerror("%s: hso_time %04x (%04x)\n", tag(), data, PPC); + break; + default: + io_w8(adr, data); + io_w8(adr+1, data>>8); + break; + } + return; +} + +UINT8 mcs96_device::io_r8(UINT8 adr) +{ + switch(adr) { + case 0x00: + return 0x00; + case 0x01: + return 0x00; + case 0x08: + return PSW; + } + UINT8 data = 0x00; + logerror("%s: io_r8 %02x, %02x (%04x)\n", tag(), adr, data, PPC); + return data; +} + +UINT16 mcs96_device::io_r16(UINT8 adr) +{ + if(adr < 2) + return 0x0000; + UINT16 data = 0x0000; + logerror("%s: io_r16 %02x, %04x (%04x)\n", tag(), adr, data, PPC); + return data; +} + +void mcs96_device::reg_w8(UINT8 adr, UINT8 data) +{ + if(adr < 0x18) + io_w8(adr, data); + else { + UINT16 &r = R[(adr - 0x18) >> 1]; + if(adr & 0x01) + r = (r & 0x00ff) | (data << 8); + else + r = (r & 0xff00) | data; + } +} + +void mcs96_device::reg_w16(UINT8 adr, UINT16 data) +{ + adr &= 0xfe; + if(adr < 0x18) + io_w16(adr, data); + else + R[(adr-0x18) >> 1] = data; +} + +UINT8 mcs96_device::reg_r8(UINT8 adr) +{ + if(adr < 0x18) + return io_r8(adr); + + UINT16 data = R[(adr - 0x18) >> 1]; + if(adr & 0x01) + return data >> 8; + else + return data; +} + +UINT16 mcs96_device::reg_r16(UINT8 adr) +{ + adr &= 0xfe; + if(adr < 0x18) + return io_r16(adr); + + return R[(adr-0x18) >> 1]; +} + +void mcs96_device::any_w8(UINT16 adr, UINT8 data) +{ + if(adr < 0x18) + io_w8(adr, data); + else if(adr < 0x100) { + UINT16 &r = R[(adr - 0x18) >> 1]; + if(adr & 0x01) + r = (r & 0x00ff) | (data << 8); + else + r = (r & 0xff00) | data; + } else + program->write_byte(adr, data); +} + +void mcs96_device::any_w16(UINT16 adr, UINT16 data) +{ + adr &= 0xfffe; + if(adr < 0x18) + io_w16(adr, data); + else if(adr < 0x100) + R[(adr-0x18) >> 1] = data; + else + program->write_word(adr, data); +} + +UINT8 mcs96_device::any_r8(UINT16 adr) +{ + if(adr < 0x18) + return io_r8(adr); + else if(adr < 0x100) { + UINT16 data = R[(adr - 0x18) >> 1]; + if(adr & 0x01) + return data >> 8; + else + return data; + } else + return program->read_byte(adr); +} + +UINT16 mcs96_device::any_r16(UINT16 adr) +{ + adr &= 0xfffe; + if(adr < 0x18) + return io_r16(adr); + else if(adr < 0x100) + return R[(adr-0x18) >> 1]; + else + return program->read_word(adr); +} + +UINT8 mcs96_device::do_addb(UINT8 v1, UINT8 v2) +{ + UINT16 sum = v1+v2; + PSW &= ~(F_Z|F_N|F_C|F_V); + if(!UINT8(sum)) + PSW |= F_Z; + else if(INT8(sum) < 0) + PSW |= F_N; + if(~(v1^v2) & (v1^sum) & 0x80) + PSW |= F_V|F_VT; + if(sum & 0xff00) + PSW |= F_C; + return sum; +} + +UINT16 mcs96_device::do_add(UINT16 v1, UINT16 v2) +{ + UINT32 sum = v1+v2; + PSW &= ~(F_Z|F_N|F_C|F_V); + if(!UINT16(sum)) + PSW |= F_Z; + else if(INT16(sum) < 0) + PSW |= F_N; + if(~(v1^v2) & (v1^sum) & 0x8000) + PSW |= F_V|F_VT; + if(sum & 0xffff0000) + PSW |= F_C; + return sum; +} + +UINT8 mcs96_device::do_subb(UINT8 v1, UINT8 v2) +{ + UINT16 diff = v1 - v2; + PSW &= ~(F_N|F_V|F_Z|F_C); + if(!UINT8(diff)) + PSW |= F_Z; + else if(INT8(diff) < 0) + PSW |= F_N; + if((v1^v2) & (v1^diff) & 0x80) + PSW |= F_V; + if(!(diff & 0xff00)) + PSW |= F_C; + return diff; +} + +UINT16 mcs96_device::do_sub(UINT16 v1, UINT16 v2) +{ + UINT32 diff = v1 - v2; + PSW &= ~(F_N|F_V|F_Z|F_C); + if(!UINT16(diff)) + PSW |= F_Z; + else if(INT16(diff) < 0) + PSW |= F_N; + if((v1^v2) & (v1^diff) & 0x8000) + PSW |= F_V; + if(!(diff & 0xffff0000)) + PSW |= F_C; + return diff; +} + +UINT8 mcs96_device::do_addcb(UINT8 v1, UINT8 v2) +{ + UINT16 sum = v1+v2+(PSW & F_C ? 1 : 0); + PSW &= ~(F_Z|F_N|F_C|F_V); + if(!UINT8(sum)) + PSW |= F_Z; + else if(INT8(sum) < 0) + PSW |= F_N; + if(~(v1^v2) & (v1^sum) & 0x80) + PSW |= F_V|F_VT; + if(sum & 0xff00) + PSW |= F_C; + return sum; +} + +UINT16 mcs96_device::do_addc(UINT16 v1, UINT16 v2) +{ + UINT32 sum = v1+v2+(PSW & F_C ? 1 : 0); + PSW &= ~(F_Z|F_N|F_C|F_V); + if(!UINT16(sum)) + PSW |= F_Z; + else if(INT16(sum) < 0) + PSW |= F_N; + if(~(v1^v2) & (v1^sum) & 0x8000) + PSW |= F_V|F_VT; + if(sum & 0xffff0000) + PSW |= F_C; + return sum; +} + +UINT8 mcs96_device::do_subcb(UINT8 v1, UINT8 v2) +{ + UINT16 diff = v1 - v2 - (PSW & F_C ? 0 : 1); + PSW &= ~(F_N|F_V|F_Z|F_C); + if(!UINT8(diff)) + PSW |= F_Z; + else if(INT8(diff) < 0) + PSW |= F_N; + if((v1^v2) & (v1^diff) & 0x80) + PSW |= F_V; + if(!(diff & 0xff00)) + PSW |= F_C; + return diff; +} + +UINT16 mcs96_device::do_subc(UINT16 v1, UINT16 v2) +{ + UINT32 diff = v1 - v2 - (PSW & F_C ? 0 : 1); + PSW &= ~(F_N|F_V|F_Z|F_C); + if(!UINT16(diff)) + PSW |= F_Z; + else if(INT16(diff) < 0) + PSW |= F_N; + if((v1^v2) & (v1^diff) & 0x8000) + PSW |= F_V; + if(!(diff & 0xffff0000)) + PSW |= F_C; + return diff; +} + +void mcs96_device::set_nz8(UINT8 v) +{ + PSW &= ~(F_N|F_V|F_Z|F_C); + if(!v) + PSW |= F_Z; + else if(INT8(v) < 0) + PSW |= F_N; +} + +void mcs96_device::set_nz16(UINT16 v) +{ + PSW &= ~(F_N|F_V|F_Z|F_C); + if(!v) + PSW |= F_Z; + else if(INT16(v) < 0) + PSW |= F_N; +} + +#include "cpu/mcs96/mcs96.inc" diff --git a/src/devices/cpu/mcs96/mcs96.h b/src/devices/cpu/mcs96/mcs96.h new file mode 100644 index 00000000000..31e90d137ca --- /dev/null +++ b/src/devices/cpu/mcs96/mcs96.h @@ -0,0 +1,256 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert, R. Belmont +/*************************************************************************** + + mcs96.h + + MCS96 + +***************************************************************************/ + +#ifndef __MCS96_H__ +#define __MCS96_H__ + +class mcs96_device : public cpu_device { +public: + enum { + EXINT_LINE = 1 + }; + + mcs96_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, int data_width, const char *shortname, const char *source); + +protected: + enum { + STATE_FETCH = 0x200, + STATE_FETCH_NOIRQ = 0x201 + }; + + enum { + F_ST = 0x0100, + F_I = 0x0200, + F_C = 0x0800, + F_VT = 0x1000, + F_V = 0x2000, + F_N = 0x4000, + F_Z = 0x8000 + }; + + struct disasm_entry { + const char *opcode, *opcode_fe; + int mode; + offs_t flags; + }; + + enum { + DASM_none, /* No parameters */ + DASM_nop_2, /* One ignored parameter byte */ + DASM_rel8, /* Relative, 8 bits */ + DASM_rel11, /* Relative, 11 bits */ + DASM_rel16, /* Relative, 16 bits */ + DASM_rrel8, /* Register + relative, 8 bits */ + DASM_brrel8, /* Bit test + register + relative, 8 bits */ + DASM_direct_1, /* Register-direct references, 1 operator */ + DASM_direct_2, /* Register-direct references, 2 operators */ + DASM_direct_3, /* Register-direct references, 3 operators */ + DASM_immed_1b, /* Immediate references to byte, 1 operator */ + DASM_immed_2b, /* Immediate references to byte, 2 operators */ + DASM_immed_or_reg_2b, /* Immediate references to byte or register, 2 operators */ + DASM_immed_3b, /* Immediate references to byte, 3 operators */ + DASM_immed_1w, /* Immediate references to word, 1 operator */ + DASM_immed_2w, /* Immediate references to word, 2 operators */ + DASM_immed_3w, /* Immediate references to word, 3 operators */ + DASM_indirect_1n, /* Indirect normal, 1 operator */ + DASM_indirect_1, /* Indirect, normal or auto-incrementing, 1 operator */ + DASM_indirect_2, /* Indirect, normal or auto-incrementing, 2 operators */ + DASM_indirect_3, /* Indirect, normal or auto-incrementing, 3 operators */ + DASM_indexed_1, /* Indexed, short or long, 1 operator */ + DASM_indexed_2, /* Indexed, short or long, 2 operators */ + DASM_indexed_3 /* Indexed, short or long, 3 operators */ + }; + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_execute_interface overrides + virtual UINT32 execute_min_cycles() const; + virtual UINT32 execute_max_cycles() const; + virtual UINT32 execute_input_lines() const; + virtual void execute_run(); + virtual void execute_set_input(int inputnum, int state); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const; + + // device_state_interface overrides + virtual void state_import(const device_state_entry &entry); + virtual void state_export(const device_state_entry &entry); + virtual void state_string_export(const device_state_entry &entry, std::string &str); + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const; + virtual UINT32 disasm_max_opcode_bytes() const; + virtual offs_t disasm_generic(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options, const disasm_entry *entries); + + address_space_config program_config; + address_space *program; + direct_read_data *direct; + + int icount, bcount, inst_state, cycles_scaling; + UINT8 pending_irq; + UINT16 PC, PPC, PSW; + UINT16 OP1; + UINT8 OP2, OP3, OPI; + UINT32 TMP; + UINT16 R[0x74]; + bool irq_requested; + + virtual void do_exec_full() = 0; + virtual void do_exec_partial() = 0; + virtual void internal_update(UINT64 current_time) = 0; + virtual void io_w8(UINT8 adr, UINT8 data) = 0; + virtual void io_w16(UINT8 adr, UINT16 data) = 0; + virtual UINT8 io_r8(UINT8 adr) = 0; + virtual UINT16 io_r16(UINT8 adr) = 0; + + void recompute_bcount(UINT64 event_time); + static std::string regname(UINT8 reg); + + inline void next(int cycles) { icount -= cycles_scaling*cycles; inst_state = STATE_FETCH; } + inline void next_noirq(int cycles) { icount -= cycles_scaling*cycles; inst_state = STATE_FETCH_NOIRQ; } + void check_irq(); + inline UINT8 read_pc() { return direct->read_byte(PC++); } + + void reg_w8(UINT8 adr, UINT8 data); + void reg_w16(UINT8 adr, UINT16 data); + void any_w8(UINT16 adr, UINT8 data); + void any_w16(UINT16 adr, UINT16 data); + + UINT8 reg_r8(UINT8 adr); + UINT16 reg_r16(UINT8 adr); + UINT8 any_r8(UINT16 adr); + UINT16 any_r16(UINT16 adr); + + UINT8 do_addb(UINT8 v1, UINT8 v2); + UINT16 do_add(UINT16 v1, UINT16 v2); + UINT8 do_subb(UINT8 v1, UINT8 v2); + UINT16 do_sub(UINT16 v1, UINT16 v2); + + UINT8 do_addcb(UINT8 v1, UINT8 v2); + UINT16 do_addc(UINT16 v1, UINT16 v2); + UINT8 do_subcb(UINT8 v1, UINT8 v2); + UINT16 do_subc(UINT16 v1, UINT16 v2); + + void set_nz8(UINT8 v); + void set_nz16(UINT16 v); + +#define O(o) void o ## _full(); void o ## _partial() + + O(add_direct_2); O(add_direct_3); O(add_immed_2w); O(add_immed_3w); O(add_indexed_2); O(add_indexed_3); O(add_indirect_2); O(add_indirect_3); + O(addb_direct_2); O(addb_direct_3); O(addb_immed_2b); O(addb_immed_3b); O(addb_indexed_2); O(addb_indexed_3); O(addb_indirect_2); O(addb_indirect_3); + O(addc_direct_2); O(addc_immed_2w); O(addc_indexed_2); O(addc_indirect_2); + O(addcb_direct_2); O(addcb_immed_2w); O(addcb_indexed_2); O(addcb_indirect_2); + O(and_direct_2); O(and_direct_3); O(and_immed_2w); O(and_immed_3w); O(and_indexed_2); O(and_indexed_3); O(and_indirect_2); O(and_indirect_3); + O(andb_direct_2); O(andb_direct_3); O(andb_immed_2b); O(andb_immed_3b); O(andb_indexed_2); O(andb_indexed_3); O(andb_indirect_2); O(andb_indirect_3); + O(br_indirect_1n); + O(clr_direct_1); + O(clrb_direct_1); + O(clrc_none); + O(clrvt_none); + O(cmp_direct_2); O(cmp_immed_2w); O(cmp_indexed_2); O(cmp_indirect_2); + O(cmpb_direct_2); O(cmpb_immed_2b); O(cmpb_indexed_2); O(cmpb_indirect_2); + O(dec_direct_1); + O(decb_direct_1); + O(di_none); + O(div_direct_2); O(div_immed_2w); O(div_indexed_2); O(div_indirect_2); + O(divb_direct_2); O(divb_immed_2b); O(divb_indexed_2); O(divb_indirect_2); + O(divu_direct_2); O(divu_immed_2w); O(divu_indexed_2); O(divu_indirect_2); + O(divub_direct_2); O(divub_immed_2b); O(divub_indexed_2); O(divub_indirect_2); + O(djnz_rrel8); + O(djnzw_rrel8); + O(ei_none); + O(ext_direct_1); + O(extb_direct_1); + O(idlpd_none); + O(inc_direct_1); + O(incb_direct_1); + O(jbc_brrel8); + O(jbs_brrel8); + O(jc_rel8); + O(je_rel8); + O(jge_rel8); + O(jgt_rel8); + O(jh_rel8); + O(jle_rel8); + O(jlt_rel8); + O(jnc_rel8); + O(jne_rel8); + O(jnh_rel8); + O(jnst_rel8); + O(jnv_rel8); + O(jnvt_rel8); + O(jst_rel8); + O(jv_rel8); + O(jvt_rel8); + O(lcall_rel16); + O(ld_direct_2); O(ld_immed_2w); O(ld_indexed_2); O(ld_indirect_2); + O(ldb_direct_2); O(ldb_immed_2b); O(ldb_indexed_2); O(ldb_indirect_2); + O(ldbse_direct_2); O(ldbse_immed_2b); O(ldbse_indexed_2); O(ldbse_indirect_2); + O(ldbze_direct_2); O(ldbze_immed_2b); O(ldbze_indexed_2); O(ldbze_indirect_2); + O(ljmp_rel16); + O(mul_direct_2); O(mul_direct_3); O(mul_immed_2w); O(mul_immed_3w); O(mul_indexed_2); O(mul_indexed_3); O(mul_indirect_2); O(mul_indirect_3); + O(mulb_direct_2); O(mulb_direct_3); O(mulb_immed_2b); O(mulb_immed_3b); O(mulb_indexed_2); O(mulb_indexed_3); O(mulb_indirect_2); O(mulb_indirect_3); + O(mulu_direct_2); O(mulu_direct_3); O(mulu_immed_2w); O(mulu_immed_3w); O(mulu_indexed_2); O(mulu_indexed_3); O(mulu_indirect_2); O(mulu_indirect_3); + O(mulub_direct_2); O(mulub_direct_3); O(mulub_immed_2b); O(mulub_immed_3b); O(mulub_indexed_2); O(mulub_indexed_3); O(mulub_indirect_2); O(mulub_indirect_3); + O(neg_direct_1); + O(negb_direct_1); + O(nop_none); + O(norml_direct_2); + O(not_direct_1); + O(notb_direct_1); + O(or_direct_2); O(or_immed_2w); O(or_indexed_2); O(or_indirect_2); + O(orb_direct_2); O(orb_immed_2b); O(orb_indexed_2); O(orb_indirect_2); + O(pop_direct_1); O(pop_indexed_1); O(pop_indirect_1); + O(popf_none); + O(push_direct_1); O(push_immed_1w); O(push_indexed_1); O(push_indirect_1); + O(pushf_none); + O(ret_none); + O(rst_none); + O(scall_rel11); + O(setc_none); + O(shl_immed_or_reg_2b); + O(shlb_immed_or_reg_2b); + O(shll_immed_or_reg_2b); + O(shr_immed_or_reg_2b); + O(shra_immed_or_reg_2b); + O(shrab_immed_or_reg_2b); + O(shral_immed_or_reg_2b); + O(shrb_immed_or_reg_2b); + O(shrl_immed_or_reg_2b); + O(sjmp_rel11); + O(skip_immed_1b); + O(st_direct_2); O(st_indexed_2); O(st_indirect_2); + O(stb_direct_2); O(stb_indexed_2); O(stb_indirect_2); + O(sub_direct_2); O(sub_direct_3); O(sub_immed_2w); O(sub_immed_3w); O(sub_indexed_2); O(sub_indexed_3); O(sub_indirect_2); O(sub_indirect_3); + O(subb_direct_2); O(subb_direct_3); O(subb_immed_2b); O(subb_immed_3b); O(subb_indexed_2); O(subb_indexed_3); O(subb_indirect_2); O(subb_indirect_3); + O(subc_direct_2); O(subc_immed_2w); O(subc_indexed_2); O(subc_indirect_2); + O(subcb_direct_2); O(subcb_immed_2w); O(subcb_indexed_2); O(subcb_indirect_2); + O(trap_none); + O(xch_direct_2); + O(xchb_direct_2); + O(xor_direct_2); O(xor_immed_2w); O(xor_indexed_2); O(xor_indirect_2); + O(xorb_direct_2); O(xorb_immed_2b); O(xorb_indexed_2); O(xorb_indirect_2); + + O(fetch); + O(fetch_noirq); + +#undef O +}; + +enum { + MCS96_PC = 1, + MCS96_PSW, + MCS96_R // 0x74 entries +}; + +#endif diff --git a/src/devices/cpu/mcs96/mcs96make.py b/src/devices/cpu/mcs96/mcs96make.py new file mode 100644 index 00000000000..72d8f36cfa6 --- /dev/null +++ b/src/devices/cpu/mcs96/mcs96make.py @@ -0,0 +1,196 @@ +#!/usr/bin/python + +from __future__ import print_function + +USAGE = """ +Usage: +%s mcs96ops.lst mcs96.inc +""" +import sys + +def save_full_one(f, t, name, source): + print("void %s_device::%s_full()" % (t, name), file=f) + print("{", file=f) + for line in source: + print(line, file=f) + print("}", file=f) + print("", file=f) + +class Opcode: + def __init__(self, rng, name, amode, is_196, ea): + rng1 = rng.split("-") + self.rng_start = int(rng1[0], 16) + if len(rng1) == 2: + self.rng_end = int(rng1[1], 16) + else: + self.rng_end = self.rng_start + self.name = name + self.amode = amode + self.source = [] + self.is_196 = is_196 + if amode in ea: + for line in ea[amode].source: + self.source.append(line) + + def add_source_line(self, line): + self.source.append(line) + +class Special: + def __init__(self, name): + self.name = name + self.source = [] + + def add_source_line(self, line): + self.source.append(line) + +class Macro: + def __init__(self, tokens): + self.name = tokens[1] + self.params = [] + for i in range(2, len(tokens)): + self.params.append(tokens[i]) + self.source = [] + + def add_source_line(self, line): + self.source.append(line) + + def apply(self, target, tokens): + values = [] + for i in range(1, len(tokens)): + values.append(tokens[i]) + for i in range(0, len(self.source)): + line = self.source[i] + for j in range(0, len(self.params)): + line = line.replace(self.params[j], values[j]) + target.add_source_line(line) + +class OpcodeList: + def __init__(self, fname, is_196): + self.opcode_info = [] + self.opcode_per_id = {} + self.ea = {} + self.macros = {} + try: + f = open(fname, "rU") + except Exception: + err = sys.exc_info()[1] + sys.stderr.write("Cannot read opcodes file %s [%s]\n" % (fname, err)) + sys.exit(1) + + inf = None + for line in f: + if line.startswith("#"): + continue + line = line.rstrip() + if not line: + continue + if line.startswith(" ") or line.startswith("\t"): + # append instruction to last opcode, maybe expand a macro + tokens = line.split() + if tokens[0] in self.macros: + self.macros[tokens[0]].apply(inf, tokens) + else: + inf.add_source_line(line) + else: + # New something + tokens = line.split() + # Addressing mode header + if tokens[0] == "eadr": + inf = Special(tokens[1]) + self.ea[inf.name] = inf + elif tokens[0] == "fetch": + inf = Special(tokens[0]) + self.fetch = inf + elif tokens[0] == "fetch_noirq": + inf = Special(tokens[0]) + self.fetch_noirq = inf + elif tokens[0] == "macro": + inf = Macro(tokens) + self.macros[inf.name] = inf + else: + inf = Opcode(tokens[0], tokens[1], tokens[2], len(tokens) >= 4 and tokens[3] == "196", self.ea) + self.opcode_info.append(inf) + if is_196 or not inf.is_196: + for i in range(inf.rng_start, inf.rng_end+1): + self.opcode_per_id[i] = inf + + def save_dasm(self, f, t): + print("const %s_device::disasm_entry %s_device::disasm_entries[0x100] = {" % (t, t), file=f) + for i in range(0, 0x100): + if i in self.opcode_per_id: + opc = self.opcode_per_id[i] + alt = "NULL" + if i + 0xfe00 in self.opcode_per_id: + alt = "\"" + self.opcode_per_id[i+0xfe00].name + "\"" + if opc.name == "scall" or opc.name == "lcall": + flags = "DASMFLAG_STEP_OVER" + elif opc.name == "rts": + flags = "DASMFLAG_STEP_OUT" + else: + flags = "0" + print("\t{ \"%s\", %s, DASM_%s, %s }," % (opc.name, alt, opc.amode, flags), file=f) + else: + print("\t{ \"???\", NULL, DASM_none, 0 },", file=f) + print("};", file=f) + print("", file=f) + + def save_opcodes(self, f, t): + pf = "" + is_196 = False + if t == "i8xc196": + pf = "_196" + is_196 = True + for opc in self.opcode_info: + if opc.is_196 == is_196: + save_full_one(f, t, opc.name + "_" + opc.amode + pf, opc.source) + if not is_196: + save_full_one(f, t, "fetch", self.fetch.source) + save_full_one(f, t, "fetch_noirq", self.fetch_noirq.source) + + def save_exec(self, f, t): + print("void %s_device::do_exec_full()" % t, file=f) + print("{", file=f) + print("\tswitch(inst_state) {", file=f) + for i in range(0x000, 0x200): + opc = None + if i >= 0x100 and i-0x100+0xfe00 in self.opcode_per_id: + opc = self.opcode_per_id[i-0x100+0xfe00] + if opc is None and (i & 0xff) in self.opcode_per_id: + opc = self.opcode_per_id[i & 0xff] + if opc is not None: + nm = opc.name + "_" + opc.amode + if opc.is_196: + nm += "_196" + print("\tcase 0x%03x: %s_full(); break;" % (i, nm), file=f) + print("\tcase 0x200: fetch_full(); break;", file=f) + print("\tcase 0x201: fetch_noirq_full(); break;", file=f) + print("\t}", file=f) + print("}", file=f) + +def main(argv): + if len(argv) != 4: + print(USAGE % argv[0]) + return 1 + + t = argv[1] + opcodes = OpcodeList(argv[2], t == "i8xc196") + + try: + f = open(argv[3], "w") + except Exception: + err = sys.exc_info()[1] + sys.stderr.write("cannot write file %s [%s]\n" % (argv[3], err)) + sys.exit(1) + + if t != "mcs96": + opcodes.save_dasm(f, t) + if t != "i8x9x": + opcodes.save_opcodes(f, t) + if t != "mcs96": + opcodes.save_exec(f, t) + f.close() + +# ====================================================================== +if __name__ == "__main__": + sys.exit(main(sys.argv)) + diff --git a/src/devices/cpu/mcs96/mcs96ops.lst b/src/devices/cpu/mcs96/mcs96ops.lst new file mode 100644 index 00000000000..7ccedf358da --- /dev/null +++ b/src/devices/cpu/mcs96/mcs96ops.lst @@ -0,0 +1,1852 @@ +fetch + if(irq_requested) { + int level; + for(level = 7; level >= 0 && !(PSW & pending_irq & (1<> 16); + next(4); + +07 inc direct_1 + TMP = reg_r16(OP1); + reg_w16(OP1, do_add(TMP, 1)); + next(4); + +08 shr immed_or_reg_2b + if(OP1 >= 0x10) { + OP1 = reg_r8(OP1) & 0x1f; + } + TMP = reg_r16(OP2); + PSW &= ~(F_Z|F_N|F_C|F_V|F_ST); + if(OP1 >= 2 && (TMP & (0xffff >> (OP1 <= 16 ? 17-OP1 : 0)))) + PSW |= F_ST; + if(OP1 >= 1 && OP1 <= 16 && (TMP & (0x0001 << (OP1-1)))) + PSW |= F_C; + TMP = UINT16(TMP) >> OP1; + if(!TMP) + PSW |= F_Z; + else if(INT16(TMP) < 0) + PSW |= F_N; + reg_w16(OP2, TMP); + next(OP1 ? 7+OP1 : 8); + +09 shl immed_or_reg_2b + if(OP1 >= 0x10) { + OP1 = reg_r8(OP1) & 0x1f; + } + TMP = reg_r16(OP2); + PSW &= ~(F_Z|F_N|F_C|F_V|F_ST); + if(OP1 >= 2 && (TMP & (0xffff << (OP1 <= 16 ? 17-OP1 : 0)))) + PSW |= F_ST; + if(OP1 >= 1 && OP1 <= 16 && (TMP & (0x8000 >> (OP1-1)))) + PSW |= F_C; + TMP = UINT16(TMP << OP1); + if(!TMP) + PSW |= F_Z; + else if(INT16(TMP) < 0) + PSW |= F_N; + reg_w16(OP2, TMP); + next(OP1 ? 7+OP1 : 8); + +0a shra immed_or_reg_2b + if(OP1 >= 0x10) { + OP1 = reg_r8(OP1) & 0x1f; + } + TMP = reg_r16(OP2); + PSW &= ~(F_Z|F_N|F_C|F_V|F_ST); + if(OP1 >= 2 && (TMP & (0xffff >> (OP1 <= 16 ? 17-OP1 : 0)))) + PSW |= F_ST; + if(OP1 >= 1 && OP1 <= 16 && (TMP & (0x0001 << (OP1-1)))) + PSW |= F_C; + TMP = INT16(TMP) >> OP1; + if(!TMP) + PSW |= F_Z; + else if(INT16(TMP) < 0) + PSW |= F_N; + reg_w16(OP2, TMP); + next(OP1 ? 7+OP1 : 8); + +0c shrl immed_or_reg_2b + if(OP1 >= 0x10) { + OP1 = reg_r8(OP1) & 0x1f; + } + OP2 &= 0xfc; + TMP = reg_r16(OP2); + TMP |= reg_r16(OP2+2) << 16; + PSW &= ~(F_Z|F_N|F_C|F_V|F_ST); + if(OP1 >= 2 && (TMP & (0xffffffff >> (33-OP1)))) + PSW |= F_ST; + if(OP1 >= 1 && (TMP & (0x00000001 << (OP1-1)))) + PSW |= F_C; + TMP = TMP >> OP1; + if(!TMP) + PSW |= F_Z; + else if(INT32(TMP) < 0) + PSW |= F_N; + reg_w16(OP2, TMP); + reg_w16(OP2+2, TMP >> 16); + next(OP1 ? 7+OP1 : 8); + +0d shll immed_or_reg_2b + if(OP1 >= 0x10) { + OP1 = reg_r8(OP1) & 0x1f; + } + OP2 &= 0xfc; + TMP = reg_r16(OP2); + TMP |= reg_r16(OP2+2) << 16; + PSW &= ~(F_Z|F_N|F_C|F_V|F_ST); + if(OP1 >= 2 && (TMP & (0xffffffff << (33-OP1)))) + PSW |= F_ST; + if(OP1 >= 1 && (TMP & (0x80000000 >> (OP1-1)))) + PSW |= F_C; + TMP = TMP << OP1; + if(!TMP) + PSW |= F_Z; + else if(INT32(TMP) < 0) + PSW |= F_N; + reg_w16(OP2, TMP); + reg_w16(OP2+2, TMP >> 16); + next(OP1 ? 7+OP1 : 8); + +0e shral immed_or_reg_2b + if(OP1 >= 0x10) { + OP1 = reg_r8(OP1) & 0x1f; + } + OP2 &= 0xfc; + TMP = reg_r16(OP2); + TMP |= reg_r16(OP2+2) << 16; + PSW &= ~(F_Z|F_N|F_C|F_V|F_ST); + if(OP1 >= 2 && (TMP & (0xffffffff >> (33-OP1)))) + PSW |= F_ST; + if(OP1 >= 1 && (TMP & (0x00000001 << (OP1-1)))) + PSW |= F_C; + TMP = INT32(TMP) >> OP1; + if(!TMP) + PSW |= F_Z; + else if(INT32(TMP) < 0) + PSW |= F_N; + reg_w16(OP2, TMP); + reg_w16(OP2+2, TMP >> 16); + next(OP1 ? 7+OP1 : 8); + +0f norml direct_2 + OP2 &= 0xfc; + TMP = reg_r16(OP2); + TMP |= reg_r16(OP2+2) << 16; + for(OP3 = 0; OP3 < 31 && INT32(TMP) >= 0; OP3++); + PSW &= ~(F_Z|F_N|F_C); + if(!TMP) + PSW |= F_Z; + reg_w8(OP1, OP3); + reg_w16(OP2, TMP); + reg_w16(OP2+2, TMP >> 16); + next(11+OP3); + +11 clrb direct_1 + reg_w8(OP1, 0x00); + next(4); + +12 notb direct_1 + TMP = ~reg_r8(OP1); + set_nz8(TMP); + reg_w8(OP1, TMP); + next(4); + +13 negb direct_1 + TMP = reg_r8(OP1); + reg_w8(OP1, do_subb(0, TMP)); + next(4); + +14 xchb direct_2 + +15 decb direct_1 + TMP = reg_r8(OP1); + reg_w8(OP1, do_subb(TMP, 1)); + next(4); + +16 extb direct_1 + OP1 &= 0xfe; + TMP = INT8(reg_r8(OP1)); + set_nz8(TMP); + reg_w16(OP1, TMP); + next(4); + +17 incb direct_1 + TMP = reg_r8(OP1); + reg_w8(OP1, do_addb(TMP, 1)); + next(4); + +18 shrb immed_or_reg_2b + if(OP1 >= 0x10) { + OP1 = reg_r8(OP1) & 0x1f; + } + TMP = reg_r8(OP2); + PSW &= ~(F_Z|F_N|F_C|F_V|F_ST); + if(OP1 >= 2 && (TMP & (0xff >> (OP1 <= 8 ? 9-OP1 : 0)))) + PSW |= F_ST; + if(OP1 >= 1 && OP1 <= 8 && (TMP & (0x01 << (OP1-1)))) + PSW |= F_C; + TMP = UINT8(TMP) >> OP1; + if(!TMP) + PSW |= F_Z; + else if(INT8(TMP) < 0) + PSW |= F_N; + reg_w8(OP2, TMP); + next(OP1 ? 7+OP1 : 8); + +19 shlb immed_or_reg_2b + if(OP1 >= 0x10) { + OP1 = reg_r8(OP1) & 0x1f; + } + TMP = reg_r8(OP2); + PSW &= ~(F_Z|F_N|F_C|F_V|F_ST); + if(OP1 >= 2 && (TMP & (0xff << (OP1 <= 8 ? 9-OP1 : 0)))) + PSW |= F_ST; + if(OP1 >= 1 && OP1 <= 8 && (TMP & (0x80 >> (OP1-1)))) + PSW |= F_C; + TMP = UINT8(TMP << OP1); + if(!TMP) + PSW |= F_Z; + else if(INT8(TMP) < 0) + PSW |= F_N; + reg_w8(OP2, TMP); + next(OP1 ? 7+OP1 : 8); + +1a shrab immed_or_reg_2b + if(OP1 >= 0x10) { + OP1 = reg_r8(OP1) & 0x1f; + } + TMP = reg_r8(OP2); + PSW &= ~(F_Z|F_N|F_C|F_V|F_ST); + if(OP1 >= 2 && (TMP & (0xff >> (OP1 <= 8 ? 9-OP1 : 0)))) + PSW |= F_ST; + if(OP1 >= 1 && OP1 <= 8 && (TMP & (0x01 << (OP1-1)))) + PSW |= F_C; + TMP = UINT8(INT8(TMP) >> OP1); + if(!TMP) + PSW |= F_Z; + else if(INT8(TMP) < 0) + PSW |= F_N; + reg_w8(OP2, TMP); + next(OP1 ? 7+OP1 : 8); + +20-27 sjmp rel11 + PC += OP1; + next(8); + +28-2f scall rel11 + TMP = reg_r16(0x18); + TMP -= 2; + reg_w16(0x18, TMP); + any_w16(TMP, PC); + PC += OP1; + next(13); // real is 13/16 depending on sp's position + +30-37 jbc brrel8 + TMP = reg_r8(OP2); + if(!((TMP >> (inst_state & 7)) & 1)) { + PC += OP1; + next(9); + } else { + next(5); + } + +38-3f jbs brrel8 + TMP = reg_r8(OP2); + if((TMP >> (inst_state & 7)) & 1) { + PC += OP1; + next(9); + } else { + next(5); + } + +40 and direct_3 + TMP = reg_r16(OP1); + TMP &= reg_r16(OP2); + set_nz16(TMP); + reg_w16(OP3, TMP); + next(5); + +41 and immed_3w + TMP = OP1 & reg_r16(OP2); + set_nz16(TMP); + reg_w16(OP3, TMP); + next(6); + +42 and indirect_3 + TMP = any_r16(OP1); + TMP &= reg_r16(OP2); + set_nz16(TMP); + reg_w16(OP3, TMP); + post_indirect 2 7 8 // +5 when external + +43 and indexed_3 + TMP = any_r16(OP1); + TMP &= reg_r16(OP2); + set_nz16(TMP); + reg_w16(OP3, TMP); + post_indexed 7 8 // +5 when external + +44 add direct_3 + TMP = reg_r16(OP1); + TMP = do_add(reg_r16(OP2), TMP); + reg_w16(OP3, TMP); + next(5); + +45 add immed_3w + TMP = do_add(reg_r16(OP2), OP1); + reg_w16(OP3, TMP); + next(6); + +46 add indirect_3 + TMP = any_r16(OP1); + TMP = do_add(reg_r16(OP2), TMP); + reg_w16(OP3, TMP); + post_indirect 2 7 8 // +5 when external + +47 add indexed_3 + TMP = any_r16(OP1); + TMP = do_add(reg_r16(OP2), TMP); + reg_w16(OP3, TMP); + post_indexed 7 8 // +5 when external + +48 sub direct_3 + TMP = reg_r16(OP1); + TMP = do_sub(reg_r16(OP2), TMP); + reg_w16(OP3, TMP); + next(5); + +49 sub immed_3w + TMP = do_sub(reg_r16(OP2), OP1); + reg_w16(OP3, TMP); + next(6); + +4a sub indirect_3 + TMP = any_r16(OP1); + TMP = do_sub(reg_r16(OP2), TMP); + reg_w16(OP3, TMP); + post_indexed 7 8 // +5 when external + +4b sub indexed_3 + TMP = any_r16(OP1); + TMP = do_sub(reg_r16(OP2), TMP); + reg_w16(OP3, TMP); + post_indexed 7 8 // +5 when external + +4c mulu direct_3 + TMP = reg_r16(OP1); + TMP *= reg_r16(OP2); + OP3 &= 0xfc; + reg_w16(OP3, TMP); + reg_w16(OP3+2, TMP >> 16); + next(26); + +4d mulu immed_3w + TMP = OP1 * reg_r16(OP2); + OP3 &= 0xfc; + reg_w16(OP3, TMP); + reg_w16(OP3+2, TMP >> 16); + next(27); + +4e mulu indirect_3 + TMP = any_r16(OP1); + TMP *= reg_r16(OP2); + OP3 &= 0xfc; + reg_w16(OP3, TMP); + reg_w16(OP3+2, TMP >> 16); + post_indirect 2 28 29 // +5 when external + +4f mulu indexed_3 + TMP = any_r16(OP1); + TMP *= reg_r16(OP2); + OP3 &= 0xfc; + reg_w16(OP3, TMP); + reg_w16(OP3+2, TMP >> 16); + post_indexed 28 29 // +5 when external + +fe4c mul direct_3 + TMP = reg_r16(OP1); + TMP = INT16(reg_r16(OP2)) * INT16(TMP); + OP3 &= 0xfc; + reg_w16(OP3, TMP); + reg_w16(OP3+2, TMP >> 16); + next(30); + +fe4d mul immed_3w + TMP = INT16(OP1) * INT16(reg_r16(OP2)); + OP3 &= 0xfc; + reg_w16(OP3, TMP); + reg_w16(OP3+2, TMP >> 16); + next(31); + +fe4e mul indirect_3 + TMP = any_r16(OP1); + TMP = INT16(reg_r16(OP2)) * INT16(TMP); + OP3 &= 0xfc; + reg_w16(OP3, TMP); + reg_w16(OP3+2, TMP >> 16); + post_indirect 2 32 33 // +5 when external + +fe4f mul indexed_3 + TMP = any_r16(OP1); + TMP = INT16(reg_r16(OP2)) * INT16(TMP); + OP3 &= 0xfc; + reg_w16(OP3, TMP); + reg_w16(OP3+2, TMP >> 16); + post_indexed 32 33 // +5 when external + +50 andb direct_3 + TMP = reg_r8(OP1); + TMP &= reg_r8(OP2); + set_nz8(TMP); + reg_w8(OP3, TMP); + next(5); + +51 andb immed_3b + TMP = OP1 & reg_r8(OP2); + set_nz8(TMP); + reg_w8(OP3, TMP); + next(5); + +52 andb indirect_3 + TMP = any_r8(OP1); + TMP &= reg_r8(OP2); + set_nz8(TMP); + reg_w8(OP3, TMP); + post_indirect 1 7 8 // +5 when external + +53 andb indexed_3 + TMP = any_r8(OP1); + TMP &= reg_r8(OP2); + set_nz8(TMP); + reg_w8(OP3, TMP); + post_indexed 7 8 // +5 when external + +54 addb direct_3 + TMP = reg_r8(OP1); + TMP = do_addb(reg_r8(OP2), TMP); + reg_w8(OP3, TMP); + next(5); + +55 addb immed_3b + TMP = do_addb(reg_r8(OP2), OP1); + reg_w8(OP3, TMP); + next(5); + +56 addb indirect_3 + TMP = any_r8(OP1); + TMP = do_addb(reg_r8(OP2), TMP); + reg_w8(OP3, TMP); + post_indirect 1 7 8 // +5 when external + +57 addb indexed_3 + TMP = any_r8(OP1); + TMP = do_addb(reg_r8(OP2), TMP); + reg_w8(OP3, TMP); + post_indexed 7 8 // +5 when external + +58 subb direct_3 + TMP = reg_r8(OP1); + TMP = do_subb(reg_r8(OP2), TMP); + reg_w8(OP3, TMP); + next(5); + +59 subb immed_3b + TMP = do_subb(reg_r8(OP2), OP1); + reg_w8(OP3, TMP); + next(5); + +5a subb indirect_3 + TMP = any_r8(OP1); + TMP = do_subb(reg_r8(OP2), TMP); + reg_w8(OP3, TMP); + post_indirect 1 7 8 // +5 when external + +5b subb indexed_3 + TMP = any_r8(OP1); + TMP = do_subb(reg_r8(OP2), TMP); + reg_w8(OP3, TMP); + post_indexed 7 8 // +5 when external + +5c mulub direct_3 + TMP = reg_r8(OP1); + TMP *= reg_r8(OP2); + reg_w16(OP3, TMP); + next(18); + +5d mulub immed_3b + TMP = OP1 * reg_r8(OP2); + reg_w16(OP3, TMP); + next(18); + +5e mulub indirect_3 + TMP = any_r8(OP1); + TMP *= reg_r8(OP2); + reg_w16(OP3, TMP); + post_indirect 1 20 21 // +5 when external + +5f mulub indexed_3 + TMP = any_r8(OP1); + TMP = reg_r8(OP2); + reg_w16(OP3, TMP); + post_indexed 20 21 // +5 when external + +fe5c mulb direct_3 + TMP = reg_r8(OP1); + TMP = INT8(reg_r8(OP2)) * INT8(TMP); + reg_w16(OP3, TMP); + next(22); + +fe5d mulb immed_3b + TMP = INT8(OP1) * INT8(reg_r8(OP2)); + reg_w16(OP3, TMP); + next(22); + +fe5e mulb indirect_3 + TMP = any_r8(OP1); + TMP = INT8(reg_r8(OP2)) * INT8(TMP); + reg_w16(OP3, TMP); + post_indirect 1 24 25 // +5 when external + +fe5f mulb indexed_3 + TMP = any_r8(OP1); + TMP = INT8(reg_r8(OP2)) * INT8(TMP); + reg_w16(OP3, TMP); + post_indexed 24 25 // +5 when external + +60 and direct_2 + TMP = reg_r16(OP1); + TMP &= reg_r16(OP2); + set_nz16(TMP); + reg_w16(OP2, TMP); + next(4); + +61 and immed_2w + TMP = OP1 & reg_r16(OP2); + set_nz16(TMP); + reg_w16(OP2, TMP); + next(5); + +62 and indirect_2 + TMP = any_r16(OP1); + TMP &= reg_r16(OP2); + set_nz16(TMP); + reg_w16(OP2, TMP); + post_indirect 2 6 7 // +5 when external + +63 and indexed_2 + TMP = any_r16(OP1); + TMP &= reg_r16(OP2); + set_nz16(TMP); + reg_w16(OP2, TMP); + post_indexed 6 7 // +5 when external + +64 add direct_2 + TMP = reg_r16(OP1); + TMP = do_add(reg_r16(OP2), TMP); + reg_w16(OP2, TMP); + next(4); + +65 add immed_2w + TMP = do_add(reg_r16(OP2), OP1); + reg_w16(OP2, TMP); + next(5); + +66 add indirect_2 + TMP = any_r16(OP1); + TMP = do_add(reg_r16(OP2), TMP); + reg_w16(OP2, TMP); + post_indirect 2 6 7 // +5 when external + +67 add indexed_2 + TMP = any_r16(OP1); + TMP = do_add(reg_r16(OP2), TMP); + reg_w16(OP2, TMP); + post_indexed 6 7 // +5 when external + +68 sub direct_2 + TMP = reg_r16(OP1); + TMP = do_sub(reg_r16(OP2), TMP); + reg_w16(OP2, TMP); + next(4); + +69 sub immed_2w + TMP = do_sub(reg_r16(OP2), OP1); + reg_w16(OP2, TMP); + next(5); + +6a sub indirect_2 + TMP = any_r16(OP1); + TMP = do_sub(reg_r16(OP2), TMP); + reg_w16(OP2, TMP); + post_indirect 2 6 7 // +5 when external + +6b sub indexed_2 + TMP = any_r16(OP1); + TMP = do_sub(reg_r16(OP2), TMP); + reg_w16(OP2, TMP); + post_indexed 6 7 // +5 when external + +6c mulu direct_2 + OP2 &= 0xfc; + TMP = reg_r16(OP1); + TMP *= reg_r16(OP2); + reg_w16(OP2, TMP); + reg_w16(OP2+2, TMP >> 16); + next(25); + +6d mulu immed_2w + OP2 &= 0xfc; + TMP = OP1 * reg_r16(OP2); + reg_w16(OP2, TMP); + reg_w16(OP2+2, TMP >> 16); + next(26); + +6e mulu indirect_2 + OP2 &= 0xfc; + TMP = any_r16(OP1); + TMP *= reg_r16(OP2); + reg_w16(OP2, TMP); + reg_w16(OP2+2, TMP >> 16); + post_indirect 2 27 28 // +5 when external + +6f mulu indexed_2 + OP2 &= 0xfc; + TMP = any_r16(OP1); + TMP *= reg_r16(OP2); + reg_w16(OP2, TMP); + reg_w16(OP2+2, TMP >> 16); + post_indexed 27 28 // +5 when external + +fe6c mul direct_2 + OP2 &= 0xfc; + TMP = reg_r16(OP1); + TMP = INT16(reg_r16(OP2)) * INT16(TMP); + reg_w16(OP2, TMP); + reg_w16(OP2+2, TMP >> 16); + next(29); + +fe6d mul immed_2w + OP2 &= 0xfc; + TMP = INT16(OP1) * INT16(reg_r16(OP2)); + reg_w16(OP2, TMP); + reg_w16(OP2+2, TMP >> 16); + next(30); + +fe6e mul indirect_2 + OP2 &= 0xfc; + TMP = any_r16(OP1); + TMP = INT16(reg_r16(OP2)) * INT16(TMP); + reg_w16(OP2, TMP); + reg_w16(OP2+2, TMP >> 16); + post_indirect 2 31 32 // +5 when external + +fe6f mul indexed_2 + OP2 &= 0xfc; + TMP = any_r16(OP1); + TMP = INT16(reg_r16(OP2)) * INT16(TMP); + reg_w16(OP2, TMP); + reg_w16(OP2+2, TMP >> 16); + post_indexed 31 32 // +5 when external + +70 andb direct_2 + TMP = reg_r8(OP1); + TMP &= reg_r8(OP2); + set_nz8(TMP); + reg_w8(OP2, TMP); + next(4); + +71 andb immed_2b + TMP = OP1 & reg_r8(OP2); + set_nz8(TMP); + reg_w8(OP2, TMP); + next(4); + +72 andb indirect_2 + TMP = any_r8(OP1); + TMP &= reg_r8(OP2); + set_nz8(TMP); + reg_w8(OP2, TMP); + post_indirect 1 6 7 // +5 when external + +73 andb indexed_2 + TMP = any_r8(OP1); + TMP &= reg_r8(OP2); + set_nz8(TMP); + reg_w8(OP3, TMP); + post_indexed 6 7 // +5 when external + +74 addb direct_2 + TMP = reg_r8(OP1); + TMP = do_addb(reg_r8(OP2), TMP); + reg_w8(OP2, TMP); + next(4); + +75 addb immed_2b + TMP = do_addb(reg_r8(OP2), OP1); + reg_w8(OP2, TMP); + next(4); + +76 addb indirect_2 + TMP = any_r8(OP1); + TMP = do_addb(reg_r8(OP2), TMP); + reg_w8(OP2, TMP); + post_indirect 1 6 7 // +5 when external + +77 addb indexed_2 + TMP = any_r8(OP1); + TMP = do_addb(reg_r8(OP2), TMP); + reg_w8(OP2, TMP); + post_indexed 6 7 // +5 when external + +78 subb direct_2 + TMP = reg_r8(OP1); + TMP = do_subb(reg_r8(OP2), TMP); + reg_w8(OP2, TMP); + next(4); + +79 subb immed_2b + TMP = do_subb(reg_r8(OP2), OP1); + reg_w8(OP2, TMP); + next(4); + +7a subb indirect_2 + TMP = any_r8(OP1); + TMP = do_subb(reg_r8(OP2), TMP); + reg_w8(OP2, TMP); + post_indirect 1 6 7 // +5 when external + +7b subb indexed_2 + TMP = any_r8(OP1); + TMP = do_subb(reg_r8(OP2), TMP); + reg_w8(OP2, TMP); + post_indexed 6 7 // +5 when external + +7c mulub direct_2 + OP2 &= 0xfe; + TMP = reg_r8(OP1); + TMP *= reg_r8(OP2); + reg_w16(OP2, TMP); + next(17); + +7d mulub immed_2b + OP2 &= 0xfe; + TMP = OP1 * reg_r8(OP2); + reg_w16(OP2, TMP); + next(17); + +7e mulub indirect_2 + OP2 &= 0xfe; + TMP = any_r8(OP1); + TMP *= reg_r8(OP2); + reg_w16(OP2, TMP); + post_indirect 1 19 20 // +5 when external + +7f mulub indexed_2 + OP2 &= 0xfe; + TMP = any_r8(OP1); + TMP *= reg_r8(OP2); + reg_w16(OP2, TMP); + post_indexed 19 20 // +5 when external + +fe7c mulb direct_2 + OP2 &= 0xfe; + TMP = reg_r8(OP1); + TMP = INT8(reg_r16(OP2)) * INT8(TMP); + reg_w16(OP2, TMP); + next(21); + +fe7d mulb immed_2b + OP2 &= 0xfe; + TMP = INT8(OP1) * INT8(reg_r8(OP2)); + reg_w16(OP2, TMP); + next(21); + +fe7e mulb indirect_2 + OP2 &= 0xfe; + TMP = any_r8(OP1); + TMP = INT8(reg_r8(OP2)) * INT8(TMP); + reg_w16(OP2, TMP); + post_indirect 1 23 24 // +5 when external + +fe7f mulb indexed_2 + OP2 &= 0xfe; + TMP = any_r16(OP1); + TMP = INT8(reg_r16(OP2)) * INT8(TMP); + reg_w16(OP2, TMP); + post_indexed 23 24 // +5 when external + +80 or direct_2 + TMP = reg_r16(OP1); + TMP |= reg_r16(OP2); + set_nz16(TMP); + reg_w16(OP2, TMP); + next(4); + +81 or immed_2w + TMP = OP1 | reg_r16(OP2); + set_nz16(TMP); + reg_w16(OP2, TMP); + next(5); + +82 or indirect_2 + TMP = any_r16(OP1); + TMP |= reg_r16(OP2); + set_nz16(TMP); + reg_w16(OP2, TMP); + post_indirect 2 6 7 // +5 when external + +83 or indexed_2 + TMP = any_r16(OP1); + TMP |= reg_r16(OP2); + set_nz16(TMP); + reg_w16(OP2, TMP); + post_indexed 6 7 // +5 when external + +84 xor direct_2 + TMP = reg_r16(OP1); + TMP ^= reg_r16(OP2); + set_nz16(TMP); + reg_w16(OP2, TMP); + next(4); + +85 xor immed_2w + TMP = OP1 ^ reg_r16(OP2); + set_nz16(TMP); + reg_w16(OP2, TMP); + next(5); + +86 xor indirect_2 + TMP = any_r16(OP1); + TMP ^= reg_r16(OP2); + set_nz16(TMP); + reg_w16(OP2, TMP); + post_indirect 2 6 7 // +5 when external + +87 xor indexed_2 + TMP = any_r16(OP1); + TMP ^= reg_r16(OP2); + set_nz16(TMP); + reg_w16(OP2, TMP); + post_indexed 6 7 // +5 when external + +88 cmp direct_2 + TMP = reg_r16(OP1); + do_sub(reg_r16(OP2), TMP); + next(4); + +89 cmp immed_2w + do_sub(reg_r16(OP2), OP1); + next(5); + +8a cmp indirect_2 + TMP = any_r16(OP1); + do_sub(reg_r16(OP2), TMP); + post_indirect 2 6 7 // +5 when external + +8b cmp indexed_2 + TMP = any_r16(OP1); + do_sub(reg_r16(OP2), TMP); + post_indexed 6 7 // +5 when external + +8c divu direct_2 + OP2 &= 0xfc; + PSW &= ~F_V; + OP1 = reg_r16(OP1); + if(OP1) { + TMP = reg_r16(OP2); + TMP |= reg_r16(OP2+2); + UINT32 TMP2 = TMP / OP1; + if(TMP2 > 65535) + PSW |= F_V|F_VT; + TMP = TMP % OP1; + TMP = (TMP2 & 0xffff) | ((TMP & 0xffff) << 16); + reg_w16(OP2, TMP); + reg_w16(OP2+2, TMP >> 16); + } + next(25); + +8d divu immed_2w + OP2 &= 0xfc; + PSW &= ~F_V; + if(OP1) { + TMP = reg_r16(OP2); + TMP |= reg_r16(OP2+2); + UINT32 TMP2 = TMP / OP1; + if(TMP2 > 65535) + PSW |= F_V|F_VT; + TMP = TMP % OP1; + TMP = (TMP2 & 0xffff) | ((TMP & 0xffff) << 16); + reg_w16(OP2, TMP); + reg_w16(OP2+2, TMP >> 16); + } + next(26); + +8e divu indirect_2 + OP2 &= 0xfc; + PSW &= ~F_V; + UINT32 d = any_r16(OP1); + if(d) { + TMP = reg_r16(OP2); + TMP |= reg_r16(OP2+2); + UINT32 TMP2 = TMP / d; + if(TMP2 > 65535) + PSW |= F_V|F_VT; + TMP = TMP % d; + TMP = (TMP2 & 0xffff) | ((TMP & 0xffff) << 16); + reg_w16(OP2, TMP); + reg_w16(OP2+2, TMP >> 16); + } + post_indirect 2 28 29 // +4 when external + +8f divu indexed_2 + OP2 &= 0xfc; + PSW &= ~F_V; + UINT32 d = any_r16(OP1); + if(d) { + TMP = reg_r16(OP2); + TMP |= reg_r16(OP2+2); + UINT32 TMP2 = TMP / d; + if(TMP2 > 65535) + PSW |= F_V|F_VT; + TMP = TMP % d; + TMP = (TMP2 & 0xffff) | ((TMP & 0xffff) << 16); + reg_w16(OP2, TMP); + reg_w16(OP2+2, TMP >> 16); + } + post_indexed 28 29 // +4 when external + +fe8c div direct_2 + OP2 &= 0xfc; + PSW &= ~F_V; + OP1 = reg_r16(OP1); + if(OP1) { + TMP = reg_r16(OP2); + TMP |= reg_r16(OP2+2); + INT32 TMP2 = INT32(TMP) / INT16(OP1); + if(TMP2 > 32767 || TMP2 < -32768) + PSW |= F_V|F_VT; + TMP = TMP % INT16(OP1); + TMP = (TMP2 & 0xffff) | ((TMP & 0xffff) << 16); + reg_w16(OP2, TMP); + reg_w16(OP2+2, TMP >> 16); + } + next(30); + +fe8d div immed_2w + OP2 &= 0xfc; + PSW &= ~F_V; + if(OP1) { + TMP = reg_r16(OP2); + TMP |= reg_r16(OP2+2); + INT32 TMP2 = INT32(TMP) / INT16(OP1); + if(TMP2 > 32767 || TMP2 < -32768) + PSW |= F_V|F_VT; + TMP = TMP % INT16(OP1); + TMP = (TMP2 & 0xffff) | ((TMP & 0xffff) << 16); + reg_w16(OP2, TMP); + reg_w16(OP2+2, TMP >> 16); + } + next(30); + +fe8e div indirect_2 + OP2 &= 0xfc; + PSW &= ~F_V; + INT32 d = INT16(any_r16(OP1)); + if(d) { + TMP = reg_r16(OP2); + TMP |= reg_r16(OP2+2); + INT32 TMP2 = INT32(TMP) / d; + if(TMP2 > 32767 || TMP2 < -32768) + PSW |= F_V|F_VT; + TMP = TMP % d; + TMP = (TMP2 & 0xffff) | ((TMP & 0xffff) << 16); + reg_w16(OP2, TMP); + reg_w16(OP2+2, TMP >> 16); + } + post_indirect 2 32 33 // +4 when external + +fe8f div indexed_2 + OP2 &= 0xfc; + PSW &= ~F_V; + INT32 d = INT16(any_r16(OP1)); + if(d) { + TMP = reg_r16(OP2); + TMP |= reg_r16(OP2+2); + INT32 TMP2 = INT32(TMP) / d; + if(TMP2 > 32767 || TMP2 < -32768) + PSW |= F_V|F_VT; + TMP = TMP % d; + TMP = (TMP2 & 0xffff) | ((TMP & 0xffff) << 16); + reg_w16(OP2, TMP); + reg_w16(OP2+2, TMP >> 16); + } + post_indexed 32 33 // +4 when external + +90 orb direct_2 + TMP = reg_r8(OP1); + TMP |= reg_r8(OP2); + set_nz8(TMP); + reg_w8(OP2, TMP); + next(4); + +91 orb immed_2b + TMP = OP1 | reg_r8(OP2); + set_nz8(TMP); + reg_w8(OP2, TMP); + next(4); + +92 orb indirect_2 + TMP = any_r8(OP1); + TMP |= reg_r8(OP2); + set_nz8(TMP); + reg_w8(OP2, TMP); + post_indirect 1 6 7 // +5 when external + +93 orb indexed_2 + TMP = any_r8(OP1); + TMP |= reg_r8(OP2); + set_nz8(TMP); + reg_w8(OP2, TMP); + post_indexed 6 7 // +5 when external + +94 xorb direct_2 + TMP = reg_r8(OP1); + TMP ^= reg_r8(OP2); + set_nz8(TMP); + reg_w8(OP2, TMP); + next(4); + +95 xorb immed_2b + TMP = OP1 ^ reg_r8(OP2); + set_nz8(TMP); + reg_w8(OP2, TMP); + next(4); + +96 xorb indirect_2 + TMP = any_r8(OP1); + TMP ^= reg_r8(OP2); + set_nz8(TMP); + reg_w8(OP2, TMP); + post_indirect 1 6 7 // +5 when external + +97 xorb indexed_2 + TMP = any_r8(OP1); + TMP ^= reg_r8(OP2); + set_nz8(TMP); + reg_w8(OP2, TMP); + post_indexed 6 7 // +5 when external + +98 cmpb direct_2 + TMP = reg_r8(OP1); + do_subb(reg_r8(OP2), TMP); + next(4); + +99 cmpb immed_2b + do_subb(reg_r8(OP2), OP1); + next(4); + +9a cmpb indirect_2 + TMP = any_r8(OP1); + do_subb(reg_r8(OP2), TMP); + post_indirect 1 6 7 // +5 when external + +9b cmpb indexed_2 + TMP = any_r8(OP1); + do_subb(reg_r8(OP2), TMP); + post_indexed 6 7 // +5 when external + +9c divub direct_2 + PSW &= ~F_V; + OP1 = reg_r8(OP1); + if(OP1) { + TMP = reg_r16(OP2); + UINT32 TMP2 = TMP / OP1; + if(TMP2 > 255) + PSW |= F_V|F_VT; + TMP = TMP % OP1; + TMP = (TMP2 & 0xff) | ((TMP & 0xff) << 8); + reg_w16(OP2, TMP); + } + next(17); + +9d divub immed_2b + PSW &= ~F_V; + if(OP1) { + TMP = reg_r16(OP2); + UINT32 TMP2 = TMP / OP1; + if(TMP2 > 255) + PSW |= F_V|F_VT; + TMP = TMP % OP1; + TMP = (TMP2 & 0xff) | ((TMP & 0xff) << 8); + reg_w16(OP2, TMP); + } + next(17); + +9e divub indirect_2 + PSW &= ~F_V; + UINT32 d = any_r8(OP1); + if(d) { + TMP = reg_r16(OP2); + UINT32 TMP2 = TMP / d; + if(TMP2 > 255) + PSW |= F_V|F_VT; + TMP = TMP % d; + TMP = (TMP2 & 0xff) | ((TMP & 0xff) << 8); + reg_w16(OP2, TMP); + } + post_indirect 1 20 21 // +4 when external + +9f divub indexed_2 + PSW &= ~F_V; + UINT32 d = any_r8(OP1); + if(d) { + TMP = reg_r16(OP2); + UINT32 TMP2 = TMP / d; + if(TMP2 > 255) + PSW |= F_V|F_VT; + TMP = TMP % d; + TMP = (TMP2 & 0xff) | ((TMP & 0xff) << 8); + reg_w16(OP2, TMP); + } + post_indexed 20 21 // +4 when external + +fe9c divb direct_2 + PSW &= ~F_V; + OP1 = reg_r8(OP1); + if(OP1) { + TMP = reg_r16(OP2); + UINT32 TMP2 = INT16(TMP) / INT8(OP1); + if(INT16(TMP2) > 127 || INT16(TMP2) < -128) + PSW |= F_V|F_VT; + TMP = INT16(TMP) % INT8(OP1); + TMP = (TMP2 & 0xff) | ((TMP & 0xff) << 8); + reg_w16(OP2, TMP); + } + next(21); + +fe9d divb immed_2b + PSW &= ~F_V; + if(OP1) { + TMP = reg_r16(OP2); + UINT32 TMP2 = INT16(TMP) / INT8(OP1); + if(INT16(TMP2) > 127 || INT16(TMP2) < -128) + PSW |= F_V|F_VT; + TMP = INT16(TMP) % INT8(OP1); + TMP = (TMP2 & 0xff) | ((TMP & 0xff) << 8); + reg_w16(OP2, TMP); + } + next(21); + +fe9e divb indirect_2 + PSW &= ~F_V; + INT32 d = INT8(any_r8(OP1)); + if(d) { + TMP = reg_r16(OP2); + UINT32 TMP2 = INT16(TMP) / d; + if(INT16(TMP2) > 127 || INT16(TMP2) < -128) + PSW |= F_V|F_VT; + TMP = INT16(TMP) % d; + TMP = (TMP2 & 0xff) | ((TMP & 0xff) << 8); + reg_w16(OP2, TMP); + } + post_indirect 1 24 25 // +4 when external + +fe9f divb indexed_2 + PSW &= ~F_V; + INT32 d = INT8(any_r8(OP1)); + if(d) { + TMP = reg_r16(OP2); + UINT32 TMP2 = INT16(TMP) / d; + if(INT16(TMP2) > 127 || INT16(TMP2) < -128) + PSW |= F_V|F_VT; + TMP = INT16(TMP) % d; + TMP = (TMP2 & 0xff) | ((TMP & 0xff) << 8); + reg_w16(OP2, TMP); + } + post_indexed 1 24 25 // +4 when external + +a0 ld direct_2 + reg_w16(OP2, reg_r16(OP1)); + next(4); + +a1 ld immed_2w + reg_w16(OP2, OP1); + next(5); + +a2 ld indirect_2 + reg_w16(OP2, any_r16(OP1)); + post_indirect 2 6 7 // +5 when external + +a3 ld indexed_2 + reg_w16(OP2, any_r16(OP1)); + post_indexed 6 7 // +5 when external + +a4 addc direct_2 + TMP = reg_r16(OP1); + TMP = do_addc(reg_r16(OP2), TMP); + reg_w16(OP2, TMP); + next(4); + +a5 addc immed_2w + TMP = do_addc(reg_r16(OP2), OP1); + reg_w16(OP2, TMP); + next(5); + +a6 addc indirect_2 + TMP = any_r16(OP1); + TMP = do_addc(reg_r16(OP2), TMP); + reg_w16(OP2, TMP); + post_indirect 2 6 7 // +5 when external + +a7 addc indexed_2 + TMP = any_r16(OP1); + TMP = do_addc(reg_r16(OP2), TMP); + reg_w16(OP2, TMP); + post_indexed 6 7 // +5 when external + +a8 subc direct_2 + TMP = reg_r16(OP1); + TMP = do_subc(reg_r16(OP2), TMP); + reg_w16(OP2, TMP); + next(4); + +a9 subc immed_2w + TMP = do_subc(reg_r16(OP2), OP1); + reg_w16(OP2, TMP); + next(5); + +aa subc indirect_2 + TMP = any_r16(OP1); + TMP = do_subc(reg_r16(OP2), TMP); + reg_w16(OP2, TMP); + post_indirect 2 6 7 // +5 when external + +ab subc indexed_2 + TMP = any_r16(OP1); + TMP = do_subc(reg_r16(OP2), TMP); + reg_w16(OP2, TMP); + post_indexed 6 7 // +5 when external + +ac ldbze direct_2 + reg_w16(OP2, UINT8(reg_r8(OP1))); + next(4); + +ad ldbze immed_2b + reg_w16(OP2, UINT8(OP1)); + next(4); + +ae ldbze indirect_2 + reg_w16(OP2, UINT8(any_r8(OP1))); + post_indirect 1 6 7 // +5 when external + +af ldbze indexed_2 + reg_w16(OP2, UINT8(any_r8(OP1))); + post_indexed 6 7 // +5 when external + +b0 ldb direct_2 + reg_w8(OP2, reg_r8(OP1)); + next(4); + +b1 ldb immed_2b + reg_w8(OP2, OP1); + next(4); + +b2 ldb indirect_2 + reg_w8(OP2, any_r8(OP1)); + post_indirect 1 6 7 // +5 when external + +b3 ldb indexed_2 + reg_w8(OP2, any_r8(OP1)); + post_indexed 6 7 // +5 when external + +b4 addcb direct_2 + TMP = reg_r8(OP1); + TMP = do_addcb(reg_r8(OP2), TMP); + reg_w8(OP2, TMP); + next(4); + +b5 addcb immed_2w + TMP = do_addcb(reg_r8(OP2), OP1); + reg_w8(OP2, TMP); + next(4); + +b6 addcb indirect_2 + TMP = any_r8(OP1); + TMP = do_addcb(reg_r8(OP2), TMP); + reg_w8(OP2, TMP); + post_indirect 1 6 7 // +5 when external + +b7 addcb indexed_2 + TMP = any_r8(OP1); + TMP = do_addcb(reg_r8(OP2), TMP); + reg_w8(OP2, TMP); + post_indexed 6 7 // +5 when external + +b8 subcb direct_2 + TMP = reg_r8(OP1); + TMP = do_subcb(reg_r8(OP2), TMP); + reg_w8(OP2, TMP); + next(4); + +b9 subcb immed_2w + TMP = do_subcb(reg_r8(OP2), OP1); + reg_w8(OP2, TMP); + next(4); + +ba subcb indirect_2 + TMP = any_r8(OP1); + TMP = do_subcb(reg_r8(OP2), TMP); + reg_w8(OP2, TMP); + post_indirect 1 6 7 // +5 when external + +bb subcb indexed_2 + TMP = any_r8(OP1); + TMP = do_subcb(reg_r8(OP2), TMP); + reg_w8(OP2, TMP); + post_indexed 6 7 // +5 when external + +bc ldbse direct_2 + reg_w16(OP2, INT8(reg_r8(OP1))); + next(4); + +bd ldbse immed_2b + reg_w16(OP2, INT8(OP1)); + next(4); + +be ldbse indirect_2 + reg_w16(OP2, INT8(any_r8(OP1))); + post_indirect 1 6 7 // +5 when external + +bf ldbse indexed_2 + reg_w16(OP2, INT8(any_r8(OP1))); + post_indexed 6 7 // +5 when external + +c0 st direct_2 + reg_w16(OP1, reg_r16(OP2)); + next(4); + +c1 bmov direct_2 196 + +c2 st indirect_2 + any_w16(OP1, reg_r16(OP2)); + post_indirect 2 7 8 // +4 when external + +c3 st indexed_2 + any_w16(OP1, reg_r16(OP2)); + post_indexed 7 8 // +4 when external + +c4 stb direct_2 + reg_w8(OP1, reg_r8(OP2)); + next(4); + +c5 cmpl direct_2 196 + +c6 stb indirect_2 + any_w8(OP1, reg_r8(OP2)); + post_indirect 1 7 8 // +4 when external + +c7 stb indexed_2 + any_w8(OP1, reg_r8(OP2)); + post_indexed 7 8 // +5 when external + +c8 push direct_1 + TMP = reg_r16(0x18); + TMP -= 2; + reg_w16(0x18, TMP); + OP1 = reg_r16(OP1); + any_w16(TMP, OP1); + next(8); // +4 is external sp + +c9 push immed_1w + TMP = reg_r16(0x18); + TMP -= 2; + reg_w16(0x18, TMP); + any_w16(TMP, OP1); + next(8); // +4 is external sp + +ca push indirect_1 + TMP = reg_r16(0x18); + TMP -= 2; + reg_w16(0x18, TMP); + OP1 = any_r16(OP1); + any_w16(TMP, OP1); + post_indirect 2 11 12 // +4 when external + +cb push indexed_1 + TMP = reg_r16(0x18); + TMP -= 2; + reg_w16(0x18, TMP); + OP1 = any_r16(OP1); + any_w16(TMP, OP1); + post_indexed 11 12 // +4 when external + +cc pop direct_1 + TMP = reg_r16(0x18); + reg_w16(0x18, TMP+2); + TMP = any_r16(TMP); + reg_w16(OP1, TMP); + next(12); // +2 when external sp + +cd bmovi direct_2 196 + +ce pop indirect_1 + TMP = reg_r16(0x18); + reg_w16(0x18, TMP+2); + TMP = any_r16(TMP); + if((OPI & 0xfe) == 0x18) + OP1 += 2; + any_w16(OP1, TMP); + post_indirect 2 14 14 // +2 when external sp, +4 when external write + +ce pop indirect_1 196 + TMP = reg_r16(0x18); + reg_w16(0x18, TMP+2); + TMP = any_r16(TMP); + if((OPI & 0xfe) == 0x18) + OP1 += 2; + any_w16(OP1, TMP); + post_indirect 2 14 14 // +2 when external sp, +4 when external write + +cf pop indexed_1 + TMP = reg_r16(0x18); + reg_w16(0x18, TMP+2); + TMP = any_r16(TMP); + any_w16(OP1, TMP); + post_indexed 14 14 // +2 when external sp, +4 when external write + +cf pop indexed_1 196 + TMP = reg_r16(0x18); + reg_w16(0x18, TMP+2); + TMP = any_r16(TMP); + if((OPI & 0xfe) == 0x18) + OP1 += 2; + any_w16(OP1, TMP); + post_indexed 14 14 // +2 when external sp, +4 when external write + +d0 jnst rel8 + if(!(PSW & F_ST)) { + PC += OP1; + next(8); + } else { + PSW &= ~F_VT; + next(4); + } + +d1 jnh rel8 + if((PSW & (F_C|F_N)) != F_C) { + PC += OP1; + next(8); + } else { + next(4); + } + +d2 jgt rel8 + if(!(PSW & (F_Z|F_N))) { + PC += OP1; + next(8); + } else { + next(4); + } + +d3 jnc rel8 + if(!(PSW & F_C)) { + PC += OP1; + next(8); + } else { + next(4); + } + +d4 jnvt rel8 + if(!(PSW & F_VT)) { + PC += OP1; + next(8); + } else { + PSW &= ~F_VT; + next(4); + } + +d5 jnv rel8 + if(!(PSW & F_V)) { + PC += OP1; + next(8); + } else { + next(4); + } + +d6 jge rel8 + if(!(PSW & F_N)) { + PC += OP1; + next(8); + } else { + next(4); + } + +d7 jne rel8 + if(!(PSW & F_Z)) { + PC += OP1; + next(8); + } else { + next(4); + } + +d8 jst rel8 + if(PSW & F_ST) { + PC += OP1; + next(8); + } else { + PSW &= ~F_VT; + next(4); + } + +d9 jh rel8 + if((PSW & (F_C|F_N)) == F_C) { + PC += OP1; + next(8); + } else { + next(4); + } + +da jle rel8 + if(PSW & (F_Z|F_N)) { + PC += OP1; + next(8); + } else { + next(4); + } + +db jc rel8 + if(PSW & F_C) { + PC += OP1; + next(8); + } else { + next(4); + } + +dc jvt rel8 + if(PSW & F_VT) { + PSW &= ~F_VT; + PC += OP1; + next(8); + } else { + next(4); + } + +dd jv rel8 + if(PSW & F_V) { + PC += OP1; + next(8); + } else { + next(4); + } + +de jlt rel8 + if(PSW & F_N) { + PC += OP1; + next(8); + } else { + next(4); + } + +df je rel8 + if(PSW & F_Z) { + PC += OP1; + next(8); + } else { + next(4); + } + +e0 djnz rrel8 + TMP = reg_r8(OP2); + TMP = UINT8(TMP-1); + reg_w8(OP2, TMP); + if(TMP) { + PC += OP1; + next(9); + } else { + next(5); + } + +e1 djnzw rrel8 196 + TMP = reg_r16(OP2); + TMP = TMP-1; + reg_w16(OP2, TMP); + if(TMP) { + PC += OP1; + next(10); + } else { + next(6); + } + +e3 br indirect_1n + PC = OP1; + next(8); + +e7 ljmp rel16 + PC += OP1; + next(8); + +ef lcall rel16 + TMP = reg_r16(0x18); + TMP -= 2; + reg_w16(0x18, TMP); + any_w16(TMP, PC); + PC += OP1; + next(13); // +3 for external sp + +f0 ret none + TMP = reg_r16(0x18); + reg_w16(0x18, TMP+2); + PC = any_r16(TMP); + next(12); // +4 for external sp + +f2 pushf none + TMP = reg_r16(0x18); + TMP -= 2; + reg_w16(0x18, TMP); + any_w16(TMP, PSW); + PSW = 0x0000; + check_irq(); + next_noirq(8); // +4 for external sp + +f3 popf none + TMP = reg_r16(0x18); + reg_w16(0x18, TMP+2); + PSW = any_r16(TMP); + check_irq(); + next_noirq(9); // +4 for external sp + +f4 pusha none 196 + +f5 popa none 196 + +f6 idlpd none 196 + +f7 trap none + TMP = reg_r16(0x18); + TMP -= 2; + reg_w16(0x18, TMP); + any_w16(TMP, PC); + PC = any_r16(0x2010); + next_noirq(21); // +3 for external sp + +f8 clrc none + PSW &= ~F_C; + next(4); + +f9 setc none + PSW |= F_C; + next(4); + +fa di none + PSW &= ~F_I; + check_irq(); + next_noirq(4); + +fb ei none + PSW |= F_I; + check_irq(); + next_noirq(4); + +fc clrvt none + PSW &= ~F_VT; + next(4); + +fd nop none + next(4); + +ff rst none + PC = 0x2080; + next(4); diff --git a/src/devices/cpu/melps4/m58846.c b/src/devices/cpu/melps4/m58846.c new file mode 100644 index 00000000000..4d892d38307 --- /dev/null +++ b/src/devices/cpu/melps4/m58846.c @@ -0,0 +1,213 @@ +// license:BSD-3-Clause +// copyright-holders:hap +/* + + Mitsubishi M58846 MCU + +*/ + +#include "m58846.h" + + +const device_type M58846 = &device_creator; + + +// internal memory maps +static ADDRESS_MAP_START(program_2kx9, AS_PROGRAM, 16, m58846_device) + AM_RANGE(0x0000, 0x07ff) AM_ROM +ADDRESS_MAP_END + + +static ADDRESS_MAP_START(data_128x4, AS_DATA, 8, m58846_device) + AM_RANGE(0x00, 0x7f) AM_RAM +ADDRESS_MAP_END + + +// device definitions +m58846_device::m58846_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : melps4_cpu_device(mconfig, M58846, "M58846", tag, owner, clock, 11, ADDRESS_MAP_NAME(program_2kx9), 7, ADDRESS_MAP_NAME(data_128x4), 12 /* number of D pins */, 2 /* subroutine page */, 1 /* interrupt page */, "m58846", __FILE__) +{ } + + +// disasm +offs_t m58846_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE(m58846); + return CPU_DISASSEMBLE_NAME(m58846)(this, buffer, pc, oprom, opram, options); +} + + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void m58846_device::device_start() +{ + melps4_cpu_device::device_start(); + m_timer = timer_alloc(0); +} + + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void m58846_device::device_reset() +{ + melps4_cpu_device::device_reset(); + reset_timer(); +} + + + +//------------------------------------------------- +// timers +//------------------------------------------------- + +void m58846_device::reset_timer() +{ + attotime base = attotime::from_ticks(6, unscaled_clock()); + m_timer->adjust(base); +} + +void m58846_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + if (id != 0) + return; + + // timer 1: 7-bit fixed counter (manual specifically says 127) + if (++m_tmr_count[0] == 127) + { + m_tmr_count[0] = 0; + m_irqflag[1] = true; + m_possible_irq = true; + } + + // timer 2: 8-bit user defined counter with auto-reload + if (m_v & 8 && ++m_tmr_count[1] == 0) + { + m_tmr_count[1] = m_tmr_reload; + m_irqflag[2] = true; + m_possible_irq = true; + m_port_t ^= 1; + m_write_t(m_port_t); + } + + // schedule next timeout + reset_timer(); +} + +void m58846_device::write_v(UINT8 data) +{ + // d0: enable timer 1 irq + // d1: enable timer 2 irq? (TODO) + // d2: ? + // d3: timer 2 enable + m_tmr_irq_enabled[0] = (data & 1) ? true : false; + m_possible_irq = true; + + m_v = data; +} + + + +//------------------------------------------------- +// execute +//------------------------------------------------- + +void m58846_device::execute_one() +{ + // handle one opcode + switch (m_op & 0x1f0) + { + case 0x30: op_sey(); break; + case 0x70: op_sp(); break; + case 0xa0: op_a(); break; + case 0xb0: op_la(); break; + + case 0xc0: case 0xd0: case 0xe0: case 0xf0: op_lxy(); break; + + default: + switch (m_op & 0x1fc) + { + case 0x20: op_szb(); break; + case 0x4c: op_sb(); break; + case 0x58: op_szk(); break; + case 0x5c: op_rb(); break; + case 0x60: op_xam(); break; + case 0x64: op_tam(); break; + case 0x68: op_xamd(); break; + case 0x6c: op_xami(); break; + + default: + switch (m_op) + { + case 0x06: case 0x07: op_su(); break; + case 0x40: case 0x41: op_lcps(); break; + case 0x4a: case 0x4b: op_lz(); break; + case 0x54: case 0x55: op_ias(); break; + + case 0x00: op_nop(); break; + case 0x01: op_ba(); break; + case 0x02: op_iny(); break; + case 0x03: op_dey(); break; + case 0x04: op_di(); break; + case 0x05: op_ei(); break; + case 0x09: op_tabe(); break; // undocumented + case 0x0a: op_am(); break; + case 0x0b: op_ose(); break; + case 0x0c: op_tya(); break; + case 0x0f: op_cma(); break; + + case 0x10: op_cls(); break; + case 0x11: op_clds(); break; + case 0x13: op_cld(); break; + case 0x14: op_rd(); break; + case 0x15: op_sd(); break; + case 0x16: op_tepa(); break; + case 0x17: op_ospa(); break; + case 0x18: op_rl(); break; // undocumented + case 0x19: op_rr(); break; // undocumented + case 0x1a: op_teab(); break; + case 0x1b: op_osab(); break; + case 0x1c: op_tba(); break; + case 0x1d: op_tay(); break; + case 0x1e: op_tab(); break; + + case 0x26: op_seam(); break; + case 0x2b: op_szd(); break; + case 0x2f: op_szc(); break; + + case 0x43: op_amc(); break; + case 0x44: op_rt(); break; + case 0x45: op_rts(); break; + case 0x46: op_rti(); break; + case 0x48: op_rc(); break; + case 0x49: op_sc(); break; + + case 0x53: op_amcs(); break; + case 0x57: op_iak(); break; + + case 0x81: op_ofa(); break; + case 0x82: op_snz1(); break; + case 0x83: op_snz2(); break; + case 0x84: op_oga(); break; + case 0x85: op_t2ab(); break; + case 0x86: op_tva(); break; + case 0x8a: op_tab2(); break; + case 0x8c: op_iaf(); break; + + default: + melps4_cpu_device::execute_one(); + break; + + } + break; // 0x1ff + + } + break; // 0x1fc + + } // big switch +} diff --git a/src/devices/cpu/melps4/m58846.h b/src/devices/cpu/melps4/m58846.h new file mode 100644 index 00000000000..25d850b455e --- /dev/null +++ b/src/devices/cpu/melps4/m58846.h @@ -0,0 +1,46 @@ +// license:BSD-3-Clause +// copyright-holders:hap +/* + + Mitsubishi M58846 MCU + +*/ + +#ifndef _M58846_H_ +#define _M58846_H_ + +#include "melps4.h" + +// note: for pinout and more info, see melps4.h + + +class m58846_device : public melps4_cpu_device +{ +public: + m58846_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_execute_interface overrides + virtual void execute_one(); + + // device_disasm_interface overrides + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + + // timers + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + virtual void write_v(UINT8 data); + + emu_timer *m_timer; + void reset_timer(); +}; + + + +extern const device_type M58846; + + +#endif /* _M58846_H_ */ diff --git a/src/devices/cpu/melps4/melps4.c b/src/devices/cpu/melps4/melps4.c new file mode 100644 index 00000000000..b7390eaccf5 --- /dev/null +++ b/src/devices/cpu/melps4/melps4.c @@ -0,0 +1,440 @@ +// license:BSD-3-Clause +// copyright-holders:hap +/* + + Mitsubishi MELPS 4 MCU family cores + + Known types and their features: + (* means not emulated yet) + + *M58840: 42-pin DIL, 2Kx9 ROM, 128x4 RAM, A/D converter + *M58841: almost same as M58840 + *M58842: 64-pin DIL, external ROM(11-bit PC), rest is same as M58840 + *M58843: 28-pin DIL, 1Kx9 ROM, 64x4 RAM, A/D converter + *M58844: almost same as M58843 + *M58845: 42-pin DIL, 2Kx9 ROM, 128x4 RAM, A/D converter, 2 timers + M58846: 42-pin DIL, 2Kx9 ROM, 128x4 RAM, 2 timers(not same as M58845), extra I/O ports + *M58847: 40-pin DIL, 2Kx9 ROM, 128x4 RAM, extra I/O ports(not same as M58846) + *M58848: ? (couldn't find info, just that it exists) + + MELPS 41/42 subfamily: + + *M58494: 72-pin QFP CMOS, 4Kx10 ROM, 32x4 internal + 4Kx4 external RAM, 2 timers + *M58496: 72-pin QFP CMOS, 2Kx10 ROM, 128x4 internal + 256x4 external RAM, 1 timer, low-power + *M58497: almost same as M58496 + + MELPS 760 family has more differences, document them when needed. + MELPS 720 family as well + + + References: + - 1980 and 1982 Mitsubishi LSI Data Books + - M34550Mx-XXXFP datasheet (this one is MELPS 720 family) + + TODO: + - need more drivers that use this, to be sure that emulation is accurate + - add output PLA + +*/ + +#include "melps4.h" +#include "debugger.h" + + +// disasm +void melps4_cpu_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + switch (entry.index()) + { + // obviously not from a single flags register, letters are made up + case STATE_GENFLAGS: + strprintf(str, "%c%c%c%c%c %c%c%c", + m_intp ? 'P':'p', + m_inte ? 'I':'i', + m_sm ? 'S':'s', + m_cps ? 'D':'d', + m_cy ? 'C':'c', + m_irqflag[0] ? 'X':'.', // exf + m_irqflag[1] ? '1':'.', // 1f + m_irqflag[2] ? '2':'.' // 2f + ); + break; + + default: break; + } +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +enum +{ + MELPS4_PC=1, MELPS4_A, MELPS4_B, MELPS4_E, + MELPS4_Y, MELPS4_X, MELPS4_Z, + MELPS4_H, MELPS4_L, MELPS4_C, MELPS4_V, MELPS4_W +}; + +void melps4_cpu_device::device_start() +{ + m_program = &space(AS_PROGRAM); + m_data = &space(AS_DATA); + m_prgmask = (1 << m_prgwidth) - 1; + m_datamask = (1 << m_datawidth) - 1; + m_d_mask = (1 << m_d_pins) - 1; + + // resolve callbacks + m_read_k.resolve_safe(0); + m_read_d.resolve_safe(0); + m_read_s.resolve_safe(0); + m_read_f.resolve_safe(0); + + m_write_d.resolve_safe(); + m_write_s.resolve_safe(); + m_write_f.resolve_safe(); + m_write_g.resolve_safe(); + m_write_u.resolve_safe(); + m_write_t.resolve_safe(); + + // zerofill + m_pc = 0; + m_prev_pc = 0; + memset(m_stack, 0, sizeof(m_stack)); + m_op = 0; + m_prev_op = 0; + m_bitmask = 0; + + m_port_d = 0; + m_port_s = 0; + m_port_f = 0; + m_port_t = 0; + + m_sm = m_sms = false; + m_ba_flag = false; + m_sp_param = 0; + m_cps = 0; + m_skip = false; + m_inte = 0; + m_intp = 1; + m_irqflag[0] = m_irqflag[1] = m_irqflag[2] = false; + m_int_state = 0; + m_t_in_state = 0; + m_prohibit_irq = false; + m_possible_irq = false; + + memset(m_tmr_count, 0, sizeof(m_tmr_count)); + m_tmr_reload = 0; + m_tmr_irq_enabled[0] = m_tmr_irq_enabled[1] = false; + + m_a = 0; + m_b = 0; + m_e = 0; + m_y = m_y2 = 0; + m_x = m_x2 = 0; + m_z = m_z2 = 0; + m_cy = m_cy2 = 0; + + m_h = 0; + m_l = 0; + m_c = 7; + m_v = 0; + m_w = 0; + + // register for savestates + save_item(NAME(m_pc)); + save_item(NAME(m_prev_pc)); + save_item(NAME(m_stack)); + save_item(NAME(m_op)); + save_item(NAME(m_prev_op)); + save_item(NAME(m_bitmask)); + + save_item(NAME(m_port_d)); + save_item(NAME(m_port_s)); + save_item(NAME(m_port_f)); + save_item(NAME(m_port_t)); + + save_item(NAME(m_sm)); + save_item(NAME(m_sms)); + save_item(NAME(m_ba_flag)); + save_item(NAME(m_sp_param)); + save_item(NAME(m_cps)); + save_item(NAME(m_skip)); + save_item(NAME(m_inte)); + save_item(NAME(m_intp)); + save_item(NAME(m_irqflag)); + save_item(NAME(m_int_state)); + save_item(NAME(m_t_in_state)); + save_item(NAME(m_prohibit_irq)); + save_item(NAME(m_possible_irq)); + + save_item(NAME(m_tmr_count)); + save_item(NAME(m_tmr_reload)); + save_item(NAME(m_tmr_irq_enabled)); + + save_item(NAME(m_a)); + save_item(NAME(m_b)); + save_item(NAME(m_e)); + save_item(NAME(m_y)); save_item(NAME(m_y2)); + save_item(NAME(m_x)); save_item(NAME(m_x2)); + save_item(NAME(m_z)); save_item(NAME(m_z2)); + save_item(NAME(m_cy)); save_item(NAME(m_cy2)); + + save_item(NAME(m_h)); + save_item(NAME(m_l)); + save_item(NAME(m_c)); + save_item(NAME(m_v)); + save_item(NAME(m_w)); + + // register state for debugger + state_add(STATE_GENPC, "curpc", m_pc).formatstr("%04X").noshow(); + state_add(STATE_GENFLAGS, "GENFLAGS", m_cy).formatstr("%9s").noshow(); + + state_add(MELPS4_PC, "PC", m_pc).formatstr("%04X"); + state_add(MELPS4_A, "A", m_a).formatstr("%2d"); // show in decimal + state_add(MELPS4_B, "B", m_b).formatstr("%2d"); // " + state_add(MELPS4_E, "E", m_e).formatstr("%02X"); + state_add(MELPS4_Y, "Y", m_y).formatstr("%1X"); + state_add(MELPS4_X, "X", m_x).formatstr("%1d"); + state_add(MELPS4_Z, "Z", m_z).formatstr("%1d"); + + state_add(MELPS4_H, "H", m_h).formatstr("%1X"); + state_add(MELPS4_L, "L", m_l).formatstr("%1X"); + state_add(MELPS4_C, "C", m_c).formatstr("%1X"); + state_add(MELPS4_V, "V", m_v).formatstr("%1X"); + state_add(MELPS4_W, "W", m_w).formatstr("%1X"); + + m_icountptr = &m_icount; +} + + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void melps4_cpu_device::device_reset() +{ + m_sm = m_sms = false; + m_ba_flag = false; + m_skip = false; + m_op = m_prev_op = 0; + m_pc = m_prev_pc = 0; + op_lcps(); // CPS=0 + + // clear interrupts + m_inte = 0; + m_intp = 1; + write_v(0); + write_w(0); + m_irqflag[0] = m_irqflag[1] = m_irqflag[2] = false; + m_prohibit_irq = false; + m_possible_irq = false; + + // clear ports + write_d_pin(MELPS4_PORTD_CLR, 0); + write_gen_port(MELPS4_PORTS, 0); + write_gen_port(MELPS4_PORTF, 0); + write_gen_port(MELPS4_PORTG, 0); + write_gen_port(MELPS4_PORTU, 0); + m_write_t(0); m_port_t = 0; +} + + + +//------------------------------------------------- +// i/o handling +//------------------------------------------------- + +UINT8 melps4_cpu_device::read_gen_port(int port) +{ + // input generic port + switch (port) + { + case MELPS4_PORTS: + return m_port_s | m_read_s(port, 0xff); + case MELPS4_PORTF: + return m_port_f | (m_read_f(port, 0xff) & 0xf); + + default: + break; + } + + return 0; +} + +void melps4_cpu_device::write_gen_port(int port, UINT8 data) +{ + // output generic port + switch (port) + { + case MELPS4_PORTS: + m_port_s = data; + m_write_s(port, data, 0xff); + break; + case MELPS4_PORTF: + m_port_f = data & 0xf; + m_write_f(port, data & 0xf, 0xff); + break; + case MELPS4_PORTG: + m_write_g(port, data & 0xf, 0xff); + break; + case MELPS4_PORTU: + m_write_u(port, data & 1, 0xff); + break; + + default: + break; + } +} + +int melps4_cpu_device::read_d_pin(int bit) +{ + // read port D, return state of selected pin + bit &= 0xf; + UINT16 d = (m_port_d | m_read_d(bit, 0xffff)) & m_d_mask; + return d >> bit & 1; +} + +void melps4_cpu_device::write_d_pin(int bit, int state) +{ + // clear all port D pins + if (bit == MELPS4_PORTD_CLR) + { + m_port_d = 0; + m_write_d(bit, 0, 0xffff); + } + + // set/reset one port D pin + else + { + bit &= 0xf; + m_port_d = ((m_port_d & (~(1 << bit))) | (state << bit)) & m_d_mask; + m_write_d(bit, m_port_d, 0xffff); + } +} + + + +//------------------------------------------------- +// interrupts +//------------------------------------------------- + +void melps4_cpu_device::execute_set_input(int line, int state) +{ + state = (state) ? 1 : 0; + + switch (line) + { + // external interrupt + case MELPS4_INPUT_LINE_INT: + // irq on rising/falling edge + if (state != m_int_state && state == m_intp) + { + m_irqflag[0] = true; + m_possible_irq = true; + } + m_int_state = state; + break; + + // timer input pin + case MELPS4_INPUT_LINE_T: + write_t_in(state); + break; + + default: + break; + } +} + +void melps4_cpu_device::do_interrupt(int which) +{ + m_inte = 0; + m_irqflag[which] = false; + + m_icount--; + push_pc(); + m_sms = m_sm; + m_sm = false; + m_op = 0; // fake nop + m_pc = m_int_page << 7 | (which * 2); + + standard_irq_callback(which); +} + +void melps4_cpu_device::check_interrupt() +{ + if (!m_inte) + return; + + int which = 0; + + // assume that lower irq vectors have higher priority + if (m_irqflag[0]) + which = 0; + else if (m_irqflag[1] && m_tmr_irq_enabled[0]) + which = 1; + else if (m_irqflag[2] && m_tmr_irq_enabled[1]) + which = 2; + else + return; + + do_interrupt(which); +} + + + +//------------------------------------------------- +// execute +//------------------------------------------------- + +void melps4_cpu_device::execute_one() +{ + // B is at $18x and BM is at $10x for all MCU types + if (m_op >= 0x180) + op_b(); + else if (m_op >= 0x100) + op_bm(); + else + op_illegal(); +} + +void melps4_cpu_device::execute_run() +{ + while (m_icount > 0) + { + // remember previous state + m_prev_op = m_op; + m_prev_pc = m_pc; + + // Interrupts are not accepted during skips or LXY, LA, EI, DI, RT/RTS/RTI or any branch. + // Documentation is conflicting here: older docs say that it is allowed during skips, + // newer docs specifically say when interrupts are prohibited. + if (m_possible_irq && !m_prohibit_irq && !m_skip) + { + m_possible_irq = false; + check_interrupt(); + } + m_prohibit_irq = false; + + // fetch next opcode + debugger_instruction_hook(this, m_pc); + m_icount--; + m_op = m_program->read_word(m_pc << 1) & 0x1ff; + m_bitmask = 1 << (m_op & 3); + m_pc = (m_pc & ~0x7f) | ((m_pc + 1) & 0x7f); // stays in the same page + + // handle opcode if it's not skipped + if (m_skip) + { + // if it's a long jump, skip next one as well + if (m_op != m_ba_op && (m_op & ~0xf) != m_sp_mask) + { + m_skip = false; + m_op = 0; // fake nop + } + } + else + execute_one(); + } +} diff --git a/src/devices/cpu/melps4/melps4.h b/src/devices/cpu/melps4/melps4.h new file mode 100644 index 00000000000..329ea035b13 --- /dev/null +++ b/src/devices/cpu/melps4/melps4.h @@ -0,0 +1,366 @@ +// license:BSD-3-Clause +// copyright-holders:hap +/* + + Mitsubishi MELPS 4 MCU family cores + +*/ + +#ifndef _MELPS4_H_ +#define _MELPS4_H_ + +#include "emu.h" + + +// I/O ports setup + +// K input or A/D input port, up to 16 pins +#define MCFG_MELPS4_READ_K_CB(_devcb) \ + melps4_cpu_device::set_read_k_callback(*device, DEVCB_##_devcb); + +// D discrete I/O port, up to 16 pins - offset 0-15 for bit, 16 for all pins clear +#define MCFG_MELPS4_READ_D_CB(_devcb) \ + melps4_cpu_device::set_read_d_callback(*device, DEVCB_##_devcb); +#define MCFG_MELPS4_WRITE_D_CB(_devcb) \ + melps4_cpu_device::set_write_d_callback(*device, DEVCB_##_devcb); + +// 8-bit S generic I/O port +#define MCFG_MELPS4_READ_S_CB(_devcb) \ + melps4_cpu_device::set_read_s_callback(*device, DEVCB_##_devcb); +#define MCFG_MELPS4_WRITE_S_CB(_devcb) \ + melps4_cpu_device::set_write_s_callback(*device, DEVCB_##_devcb); + +// 4-bit F generic I/O port +#define MCFG_MELPS4_READ_F_CB(_devcb) \ + melps4_cpu_device::set_read_f_callback(*device, DEVCB_##_devcb); +#define MCFG_MELPS4_WRITE_F_CB(_devcb) \ + melps4_cpu_device::set_write_f_callback(*device, DEVCB_##_devcb); + +// 4-bit G generic output port +#define MCFG_MELPS4_WRITE_G_CB(_devcb) \ + melps4_cpu_device::set_write_g_callback(*device, DEVCB_##_devcb); + +// 1-bit U generic output port +#define MCFG_MELPS4_WRITE_U_CB(_devcb) \ + melps4_cpu_device::set_write_u_callback(*device, DEVCB_##_devcb); + +// T timer I/O pin (use execute_set_input for reads) +#define MCFG_MELPS4_WRITE_T_CB(_devcb) \ + melps4_cpu_device::set_write_t_callback(*device, DEVCB_##_devcb); + + +#define MELPS4_PORTD_CLR 16 + +// only generic ports here +enum +{ + MELPS4_PORTS = 0, + MELPS4_PORTF, + MELPS4_PORTG, + MELPS4_PORTU +}; + +enum +{ + MELPS4_INPUT_LINE_INT = 0, + MELPS4_INPUT_LINE_T +}; + + + +// pinout reference + +/* + ______ ______ + D9 1 |* \_/ | 42 D8 + D10 2 | | 41 D7 + D11 3 | | 40 D6 + RESET 4 | | 39 D5 + T 5 | | 38 D4 + K0 6 | | 37 D3 + K1 7 | | 36 D2 + K2 8 | | 35 D1 + K3 9 | | 34 D0 + G0 10 | | 33 Xin + G1 11 | M58846 | 32 Xout + G2 12 | | 31 S7 + G3 13 | | 30 S6 + U 14 | | 29 S5 + F0 15 | | 28 S4 + F1 16 | | 27 S3 + F2 17 | | 26 S2 + F3 18 | | 25 S1 + INT 19 | | 24 S0 + CNVss 20 | | 23 Vp + Vss 21 |_______________| 22 Vdd + +*/ + + +class melps4_cpu_device : public cpu_device +{ +public: + // construction/destruction + melps4_cpu_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, int prgwidth, address_map_constructor program, int datawidth, address_map_constructor data, int d_pins, UINT8 sm_page, UINT8 int_page, const char *shortname, const char *source) + : cpu_device(mconfig, type, name, tag, owner, clock, shortname, source) + , m_program_config("program", ENDIANNESS_LITTLE, 16, prgwidth, -1, program) + , m_data_config("data", ENDIANNESS_LITTLE, 8, datawidth, 0, data) + , m_prgwidth(prgwidth) + , m_datawidth(datawidth) + , m_d_pins(d_pins) + , m_sm_page(sm_page) + , m_int_page(int_page) + , m_xami_mask(0xf) + , m_sp_mask(0x7<<4) + , m_ba_op(0x01) + , m_stack_levels(3) + , m_read_k(*this) + , m_read_d(*this) + , m_read_s(*this) + , m_read_f(*this) + , m_write_d(*this) + , m_write_s(*this) + , m_write_f(*this) + , m_write_g(*this) + , m_write_u(*this) + , m_write_t(*this) + { } + + // static configuration helpers + template static devcb_base &set_read_k_callback(device_t &device, _Object object) { return downcast(device).m_read_k.set_callback(object); } + template static devcb_base &set_read_d_callback(device_t &device, _Object object) { return downcast(device).m_read_d.set_callback(object); } + template static devcb_base &set_read_s_callback(device_t &device, _Object object) { return downcast(device).m_read_s.set_callback(object); } + template static devcb_base &set_read_f_callback(device_t &device, _Object object) { return downcast(device).m_read_f.set_callback(object); } + + template static devcb_base &set_write_d_callback(device_t &device, _Object object) { return downcast(device).m_write_d.set_callback(object); } + template static devcb_base &set_write_s_callback(device_t &device, _Object object) { return downcast(device).m_write_s.set_callback(object); } + template static devcb_base &set_write_f_callback(device_t &device, _Object object) { return downcast(device).m_write_f.set_callback(object); } + template static devcb_base &set_write_g_callback(device_t &device, _Object object) { return downcast(device).m_write_g.set_callback(object); } + template static devcb_base &set_write_u_callback(device_t &device, _Object object) { return downcast(device).m_write_u.set_callback(object); } + template static devcb_base &set_write_t_callback(device_t &device, _Object object) { return downcast(device).m_write_t.set_callback(object); } + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_execute_interface overrides + virtual UINT64 execute_clocks_to_cycles(UINT64 clocks) const { return (clocks + 6 - 1) / 6; } // 6 t-states per machine cycle + virtual UINT64 execute_cycles_to_clocks(UINT64 cycles) const { return (cycles * 6); } // " + virtual UINT32 execute_min_cycles() const { return 1; } + virtual UINT32 execute_max_cycles() const { return 1+1; } // max opcode cycles + interrupt duration + virtual UINT32 execute_input_lines() const { return 3; } // up to 3 (some internal) + virtual void execute_set_input(int line, int state); + virtual void execute_run(); + virtual void execute_one(); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const { return(spacenum == AS_PROGRAM) ? &m_program_config : ((spacenum == AS_DATA) ? &m_data_config : NULL); } + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const { return 2; } + virtual UINT32 disasm_max_opcode_bytes() const { return 2; } + virtual void state_string_export(const device_state_entry &entry, std::string &str); + + address_space_config m_program_config; + address_space_config m_data_config; + address_space *m_program; + address_space *m_data; + + int m_icount; + + // fixed settings or mask options that differ between MCU type + int m_prgwidth; // number of bits and bitmask for ROM/RAM size: see melps4.c for info + int m_datawidth; // " + int m_prgmask; // " + int m_datamask; // " + int m_d_pins; // number of D port pins and bitmask: 11 on '40,'41,'42,'44, 8 on '43, 12 on '45,'46, 16 on '47 + int m_d_mask; // " + + UINT8 m_sm_page; // subroutine default page: 14 on '40 to '44, 2 on '45,'46, 0 on '47 + UINT8 m_int_page; // interrupt routine page: 12 on '40 to '44, 1 on '45,'46, 2 on '47 + UINT8 m_xami_mask; // mask option for XAMI opcode on '40,'41,'45 (0xf for others) + UINT16 m_sp_mask; // SP opcode location(middle 4 bits): 7 on '40 to '46, 3 on '47 + UINT16 m_ba_op; // BA opcode location: 1 on '40 to '46, N/A on '47 + UINT8 m_stack_levels; // 3 levels on MELPS 4, 12 levels on MELPS 41/42 + + // internal state, misc regs + UINT16 m_pc; // program counter (11 or 10-bit) + UINT16 m_prev_pc; + UINT16 m_stack[12]; // callstack (SK0-SKx, same size as PC) + UINT16 m_op; + UINT16 m_prev_op; + UINT8 m_bitmask; // opcode bit argument + + UINT16 m_port_d; // last written port data + UINT8 m_port_s; // " + UINT8 m_port_f; // " + UINT8 m_port_t; // " + + bool m_sm, m_sms; // subroutine mode flag + irq stack + bool m_ba_flag; // temp flag indicates BA opcode was executed + UINT8 m_sp_param; // temp register holding SP opcode parameter + UINT8 m_cps; // DP,CY or DP',CY' selected + bool m_skip; // skip next opcode + UINT8 m_inte; // interrupt enable flag + int m_intp; // external interrupt polarity ('40 to '44) + bool m_irqflag[3]; // irq flags: exf, 1f, 2f (external, timer 1, timer 2) + int m_int_state; // INT pin state + int m_t_in_state; // T input pin state + bool m_prohibit_irq; // interrupt is prohibited during certain opcodes + bool m_possible_irq; // indicate that irq needs to be rechecked + + UINT8 m_tmr_count[2]; // timer active count + UINT8 m_tmr_reload; // timer(2) auto reload + bool m_tmr_irq_enabled[2]; + + // work registers (unless specified, each is 4-bit) + UINT8 m_a; // accumulator + UINT8 m_b; // generic + UINT8 m_e; // 8-bit register, hold data for S output + UINT8 m_y, m_y2; // RAM index Y, Y' (Z.XX.YYYY is DP aka Data Pointer) + UINT8 m_x, m_x2; // RAM index X, X', 2-bit + UINT8 m_z, m_z2; // RAM index Z, Z', 1-bit, optional + UINT8 m_cy, m_cy2; // carry flag(s) + + UINT8 m_h; // A/D converter H or generic + UINT8 m_l; // A/D converter L or generic + UINT8 m_c; // A/D converter counter + UINT8 m_v; // timer control V + UINT8 m_w; // timer control W + + // i/o handlers + devcb_read16 m_read_k; + devcb_read16 m_read_d; + devcb_read8 m_read_s; + devcb_read8 m_read_f; + + devcb_write16 m_write_d; + devcb_write8 m_write_s; + devcb_write8 m_write_f; + devcb_write8 m_write_g; + devcb_write8 m_write_u; + devcb_write_line m_write_t; + + virtual void write_t_in(int state) { m_t_in_state = state; } + virtual void write_v(UINT8 data) { m_v = data; } + virtual void write_w(UINT8 data) { m_w = data; } + virtual void do_interrupt(int which); + virtual void check_interrupt(); + + UINT8 read_gen_port(int port); + void write_gen_port(int port, UINT8 data); + int read_d_pin(int bit); + void write_d_pin(int bit, int state); + + // misc internal helpers + UINT8 ram_r(); + void ram_w(UINT8 data); + void pop_pc(); + void push_pc(); + + // opcode handlers + void op_tab(); + void op_tba(); + void op_tay(); + void op_tya(); + void op_teab(); + void op_tabe(); + void op_tepa(); + void op_txa(); + void op_tax(); + + void op_lxy(); + void op_lz(); + void op_iny(); + void op_dey(); + void op_lcps(); + void op_sadr(); + + void op_tam(); + void op_xam(); + void op_xamd(); + void op_xami(); + + void op_la(); + void op_am(); + void op_amc(); + void op_amcs(); + void op_a(); + void op_sc(); + void op_rc(); + void op_szc(); + void op_cma(); + void op_rl(); + void op_rr(); + + void op_sb(); + void op_rb(); + void op_szb(); + + void op_seam(); + void op_sey(); + + void op_tla(); + void op_tha(); + void op_taj(); + void op_xal(); + void op_xah(); + void op_lc7(); + void op_dec(); + void op_shl(); + void op_rhl(); + void op_cpa(); + void op_cpas(); + void op_cpae(); + void op_szj(); + + void op_t1ab(); + void op_trab(); + void op_t2ab(); + void op_tab1(); + void op_tabr(); + void op_tab2(); + void op_tva(); + void op_twa(); + void op_snz1(); + void op_snz2(); + + void op_ba(); + void op_sp(); + void op_b(); + void op_bm(); + + void op_rt(); + void op_rts(); + void op_rti(); + + void op_cld(); + void op_cls(); + void op_clds(); + void op_sd(); + void op_rd(); + void op_szd(); + void op_osab(); + void op_ospa(); + void op_ose(); + void op_ias(); + void op_ofa(); + void op_iaf(); + void op_oga(); + void op_iak(); + void op_szk(); + void op_su(); + + void op_ei(); + void op_di(); + void op_inth(); + void op_intl(); + + void op_nop(); + void op_illegal(); +}; + + + +#endif /* _MELPS4_H_ */ diff --git a/src/devices/cpu/melps4/melps4d.c b/src/devices/cpu/melps4/melps4d.c new file mode 100644 index 00000000000..4c2ca2fd9d4 --- /dev/null +++ b/src/devices/cpu/melps4/melps4d.c @@ -0,0 +1,141 @@ +// license:BSD-3-Clause +// copyright-holders:hap +/* + + Mitsubishi MELPS 4 MCU family disassembler + + Not counting the extra opcodes for peripherals (eg. timers, A/D), + each MCU in the series has small differences in the opcode map. + +*/ + +#include "emu.h" +#include "debugger.h" +#include "melps4.h" + + +// opcode mnemonics +enum e_mnemonics +{ + em_ILL, + em_TAB, em_TBA, em_TAY, em_TYA, em_TEAB, em_TABE, em_TEPA, em_TXA, em_TAX, + em_LXY, em_LZ, em_INY, em_DEY, em_LCPS, em_SADR, + em_TAM, em_XAM, em_XAMD, em_XAMI, + em_LA, em_AM, em_AMC, em_AMCS, em_A, em_SC, em_RC, em_SZC, em_CMA, em_RL, em_RR, + em_SB, em_RB, em_SZB, em_SEAM, em_SEY, + em_TLA, em_THA, em_TAJ, em_XAL, em_XAH, em_LC7, em_DEC, em_SHL, em_RHL, em_CPA, em_CPAS, em_CPAE, em_SZJ, + em_T1AB, em_TRAB, em_T2AB, em_TAB1, em_TABR, em_TAB2, em_TVA, em_TWA, em_SNZ1, em_SNZ2, + em_BA, em_SP, em_B, em_BM, em_RT, em_RTS, em_RTI, + em_CLD, em_CLS, em_CLDS, em_SD, em_RD, em_SZD, em_OSAB, em_OSPA, em_OSE, em_IAS, em_OFA, em_IAF, em_OGA, em_IAK, em_SZK, em_SU, em_RU, + em_EI, em_DI, em_INTH, em_INTL, em_NOP +}; + +static const char *const em_name[] = +{ + "?", + "TAB", "TBA", "TAY", "TYA", "TEAB", "TABE", "TEPA", "TXA", "TAX", + "LXY", "LZ", "INY", "DEY", "LCPS", "SADR", + "TAM", "XAM", "XAMD", "XAMI", + "LA", "AM", "AMC", "AMCS", "A", "SC", "RC", "SZC", "CMA", "RL", "RR", + "SB", "RB", "SZB", "SEAM", "SEY", + "TLA", "THA", "TAJ", "XAL", "XAH", "LC7", "DEC", "SHL", "RHL", "CPA", "CPAS", "CPAE", "SZJ", + "T1AB", "TRAB", "T2AB", "TAB1", "TABR", "TAB2", "TVA", "TWA", "SNZ1", "SNZ2", + "BA", "SP", "B", "BM", "RT", "RTS", "RTI", + "CLD", "CLS", "CLDS", "SD", "RD", "SZD", "OSAB", "OSPA", "OSE", "IAS", "OFA", "IAF", "OGA", "IAK", "SZK", "SU", "RU", + "EI", "DI", "INTH", "INTL", "NOP" +}; + +// number of bits per opcode parameter +static const UINT8 em_bits[] = +{ + 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 6, 1, 0, 0, 1, 2, + 2, 2, 2, 2, + 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, + 2, 2, 2, 0, 4, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 4, 7, 7, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 2, 0, 0, + 0, 0, 0, 0, 0 +}; + +#define _OVER DASMFLAG_STEP_OVER +#define _OUT DASMFLAG_STEP_OUT + +static const UINT32 em_flags[] = +{ + 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, _OVER, _OUT, _OUT, _OUT, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0 +}; + + + +// M58846 disasm + +static const UINT8 m58846_opmap[0xc0] = +{ +// 0 1 2 3 4 5 6 7 8 9 A B C D E F + em_NOP, em_BA, em_INY, em_DEY, em_DI, em_EI, em_RU, em_SU, 0, em_TABE, em_AM, em_OSE, em_TYA, 0, 0, em_CMA, // 0x + em_CLS, em_CLDS, 0, em_CLD, em_RD, em_SD, em_TEPA, em_OSPA, em_RL, em_RR, em_TEAB, em_OSAB, em_TBA, em_TAY, em_TAB, 0, // 1x + em_SZB, em_SZB, em_SZB, em_SZB, 0, 0, em_SEAM, 0, 0, 0, 0, em_SZD, 0, 0, 0, em_SZC, // 2x + em_SEY, em_SEY, em_SEY, em_SEY, em_SEY, em_SEY, em_SEY, em_SEY, em_SEY, em_SEY, em_SEY, em_SEY, em_SEY, em_SEY, em_SEY, em_SEY, // 3x + em_LCPS, em_LCPS, 0, em_AMC, em_RT, em_RTS, em_RTI, 0, em_RC, em_SC, em_LZ, em_LZ, em_SB, em_SB, em_SB, em_SB, // 4x + 0, 0, 0, em_AMCS, em_IAS, em_IAS, 0, em_IAK, em_SZK, em_SZK, em_SZK, em_SZK, em_RB, em_RB, em_RB, em_RB, // 5x + em_XAM, em_XAM, em_XAM, em_XAM, em_TAM, em_TAM, em_TAM, em_TAM, em_XAMD, em_XAMD, em_XAMD, em_XAMD, em_XAMI, em_XAMI, em_XAMI, em_XAMI, // 6x + em_SP, em_SP, em_SP, em_SP, em_SP, em_SP, em_SP, em_SP, em_SP, em_SP, em_SP, em_SP, em_SP, em_SP, em_SP, em_SP, // 7x + 0, em_OFA, em_SNZ1, em_SNZ2, em_OGA, em_T2AB, em_TVA, 0, 0, 0, em_TAB2, 0, em_IAF, 0, 0, 0, // 8x + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9x + em_A, em_A, em_A, em_A, em_A, em_A, em_A, em_A, em_A, em_A, em_A, em_A, em_A, em_A, em_A, em_A, // Ax + em_LA, em_LA, em_LA, em_LA, em_LA, em_LA, em_LA, em_LA, em_LA, em_LA, em_LA, em_LA, em_LA, em_LA, em_LA, em_LA // Bx +}; + +CPU_DISASSEMBLE(m58846) +{ + UINT16 op = (oprom[0] | oprom[1] << 8) & 0x1ff; + char *dst = buffer; + + // get opcode + UINT8 instr; + if (op >= 0x180) + instr = em_B; + else if (op >= 0x100) + instr = em_BM; + else if (op >= 0xc0) + instr = em_LXY; + else + instr = m58846_opmap[op]; + + dst += sprintf(dst, "%-6s", em_name[instr]); + + // get immediate param + UINT8 bits = em_bits[instr]; + + // special case for LXY x,y + if (instr == em_LXY) + { + UINT8 x = op >> 4 & 3; + UINT8 y = op & 0xf; + dst += sprintf(dst, " %d,%d", x, y); + } + else if (bits > 0) + { + UINT8 param = op & ((1 << bits) - 1); + if (bits > 4) + dst += sprintf(dst, " $%02X", param); + else + dst += sprintf(dst, " %d", param); + } + + return 1 | em_flags[instr] | DASMFLAG_SUPPORTED; +} diff --git a/src/devices/cpu/melps4/melps4op.c b/src/devices/cpu/melps4/melps4op.c new file mode 100644 index 00000000000..4f77764a66b --- /dev/null +++ b/src/devices/cpu/melps4/melps4op.c @@ -0,0 +1,699 @@ +// license:BSD-3-Clause +// copyright-holders:hap + +// MELPS 4 opcode handlers + +#include "melps4.h" + + +// internal helpers + +inline UINT8 melps4_cpu_device::ram_r() +{ + UINT8 address = (m_z << 6 | m_x << 4 | m_y) & m_datamask; + return m_data->read_byte(address) & 0xf; +} + +inline void melps4_cpu_device::ram_w(UINT8 data) +{ + UINT8 address = (m_z << 6 | m_x << 4 | m_y) & m_datamask; + m_data->write_byte(address, data & 0xf); +} + +void melps4_cpu_device::pop_pc() +{ + m_pc = m_stack[0]; + for (int i = 0; i < m_stack_levels-1; i++) + m_stack[i] = m_stack[i+1]; +} + +void melps4_cpu_device::push_pc() +{ + for (int i = m_stack_levels-1; i >= 1; i--) + m_stack[i] = m_stack[i-1]; + m_stack[0] = m_pc; +} + + +// Register-to-register transfers + +void melps4_cpu_device::op_tab() +{ + // TAB: transfer B to A + m_a = m_b; +} + +void melps4_cpu_device::op_tba() +{ + // TBA: transfer A to B + m_b = m_a; +} + +void melps4_cpu_device::op_tay() +{ + // TAY: transfer Y to A + m_a = m_y; +} + +void melps4_cpu_device::op_tya() +{ + // TYA: transfer A to Y + m_y = m_a; +} + +void melps4_cpu_device::op_teab() +{ + // TEAB: transfer A and B to E + m_e = m_b << 4 | m_a; +} + +void melps4_cpu_device::op_tabe() +{ + // TABE(undocumented): transfer E to A and B + m_a = m_e & 0xf; + m_b = m_e >> 4; +} + +void melps4_cpu_device::op_tepa() +{ + // TEPA: decode A by PLA and transfer to E + op_illegal(); +} + +void melps4_cpu_device::op_txa() +{ + // TXA: transfer bits 0,1 of A to X, inverted bit 2 to Z, inverted bit 3 to carry + op_illegal(); +} + +void melps4_cpu_device::op_tax() +{ + // TAX: transfer X to bits 0,1 of A, inverted Z to bit 2, inverted carry to bit 3 + op_illegal(); +} + + +// RAM addresses + +void melps4_cpu_device::op_lxy() +{ + // LXY x,y: load immediate into X,Y, skip any next LXY + m_prohibit_irq = true; + if ((m_op & ~0x3f) != (m_prev_op & ~0x3f)) + { + m_x = m_op >> 4 & 3; + m_y = m_op & 0xf; + } +} + +void melps4_cpu_device::op_lz() +{ + // LZ z: load immediate into Z + m_z = m_op & 1; +} + +void melps4_cpu_device::op_iny() +{ + // INY: increment Y, skip next on overflow + m_y = (m_y + 1) & 0xf; + m_skip = (m_y == 0); +} + +void melps4_cpu_device::op_dey() +{ + // DEY: decrement Y, skip next on overflow + m_y = (m_y - 1) & 0xf; + m_skip = (m_y == 0xf); +} + +void melps4_cpu_device::op_lcps() +{ + // LCPS i: choose active DP,CY or DP',CY' + if ((m_op & 1) != m_cps) + { + m_cps = m_op & 1; + + // swap registers + UINT8 x, y, z, cy; + x = m_x; + y = m_y; + z = m_z; + cy = m_cy; + + m_x = m_x2; + m_y = m_y2; + m_z = m_z2; + m_cy = m_cy2; + + m_x2 = x; + m_y2 = y; + m_z2 = z; + m_cy2 = cy; + } +} + +void melps4_cpu_device::op_sadr() +{ + // SADR j: .. + op_illegal(); +} + + +// RAM-accumulator transfers + +void melps4_cpu_device::op_tam() +{ + // TAM j: transfer RAM to A, xor X with j + m_a = ram_r(); + m_x ^= m_op & 3; +} + +void melps4_cpu_device::op_xam() +{ + // XAM j: exchange RAM with A, xor X with j + UINT8 a = m_a; + m_a = ram_r(); + ram_w(a); + m_x ^= m_op & 3; +} + +void melps4_cpu_device::op_xamd() +{ + // XAMD j: XAM j, DEY + op_xam(); + op_dey(); +} + +void melps4_cpu_device::op_xami() +{ + // XAMI j: XAM j, skip next on Y mask(default 0xf), increment Y + op_xam(); + m_skip = ((m_y & m_xami_mask) == m_xami_mask); + m_y = (m_y + 1) & 0xf; +} + + +// Arithmetic Operations + +void melps4_cpu_device::op_la() +{ + // LA n: load immediate into A, skip any next LA + m_prohibit_irq = true; + if ((m_op & ~0xf) != (m_prev_op & ~0xf)) + m_a = m_op & 0xf; +} + +void melps4_cpu_device::op_am() +{ + // AM: add RAM to A + m_a = (m_a + ram_r()) & 0xf; +} + +void melps4_cpu_device::op_amc() +{ + // AMC: add RAM+CY to A and CY + m_a += ram_r() + m_cy; + m_cy = m_a >> 4 & 1; + m_a &= 0xf; +} + +void melps4_cpu_device::op_amcs() +{ + // AMCS: AMC, skip next on carry + op_amc(); + m_skip = (m_cy != 0); +} + +void melps4_cpu_device::op_a() +{ + // A n: add immediate to A, skip next on no carry (except when n=6) + UINT8 n = m_op & 0xf; + m_a += n; + m_skip = !(m_a & 0x10 || n == 6); + m_a &= 0xf; +} + +void melps4_cpu_device::op_sc() +{ + // SC: set carry + m_cy = 1; +} + +void melps4_cpu_device::op_rc() +{ + // RC: reset carry + m_cy = 0; +} + +void melps4_cpu_device::op_szc() +{ + // SZC: skip next on no carry + m_skip = !m_cy; +} + +void melps4_cpu_device::op_cma() +{ + // CMA: complement A + m_a ^= 0xf; +} + +void melps4_cpu_device::op_rl() +{ + // RL(undocumented): rotate A left through carry + UINT8 c = m_a >> 3 & 1; + m_a = (m_a << 1 | m_cy) & 0xf; + m_cy = c; +} + +void melps4_cpu_device::op_rr() +{ + // RR(undocumented): rotate A right through carry + UINT8 c = m_a & 1; + m_a = m_a >> 1 | m_cy << 3; + m_cy = c; +} + + +// Bit operations + +void melps4_cpu_device::op_sb() +{ + // SB j: set RAM bit + ram_w(ram_r() | m_bitmask); +} + +void melps4_cpu_device::op_rb() +{ + // RB j: reset RAM bit + ram_w(ram_r() & ~m_bitmask); +} + +void melps4_cpu_device::op_szb() +{ + // SZB j: skip next if RAM bit is 0 + m_skip = !(ram_r() & m_bitmask); +} + + +// Compares + +void melps4_cpu_device::op_seam() +{ + // SEAM: skip next if A equals RAM + m_skip = (m_a == ram_r()); +} + +void melps4_cpu_device::op_sey() +{ + // SEY y: skip next if Y equals immediate + m_skip = (m_y == (m_op & 0xf)); +} + + +// A/D converter operations + +void melps4_cpu_device::op_tla() +{ + // TLA: transfer A to L + m_l = m_a; +} + +void melps4_cpu_device::op_tha() +{ + // THA: transfer A to H + m_h = m_a; +} + +void melps4_cpu_device::op_taj() +{ + // TAJ: transfer J(hi/lo) to A designated by Y + op_illegal(); +} + +void melps4_cpu_device::op_xal() +{ + // XAL: exchange A with L + UINT8 a = m_a; + m_a = m_l; + m_l = a; +} + +void melps4_cpu_device::op_xah() +{ + // XAH: exchange A with H + UINT8 a = m_a; + m_a = m_h; + m_h = a; +} + +void melps4_cpu_device::op_lc7() +{ + // LC7: load 7 into C + m_c = 7; +} + +void melps4_cpu_device::op_dec() +{ + // DEC: decrement C, skip next on overflow + m_c = (m_c - 1) & 7; + m_skip = (m_c == 7); +} + +void melps4_cpu_device::op_shl() +{ + // SHL: set bit in L or H designated by C + UINT8 mask = 1 << (m_c & 3); + if (m_c & 4) + m_h |= mask; + else + m_l |= mask; +} + +void melps4_cpu_device::op_rhl() +{ + // RHL: reset bit in L or H designated by C + UINT8 mask = 1 << (m_c & 3); + if (m_c & 4) + m_h &= ~mask; + else + m_l &= ~mask; +} + +void melps4_cpu_device::op_cpa() +{ + // CPA: .. + op_illegal(); +} + +void melps4_cpu_device::op_cpas() +{ + // CPAS: .. + op_illegal(); +} + +void melps4_cpu_device::op_cpae() +{ + // CPAE: .. + op_illegal(); +} + +void melps4_cpu_device::op_szj() +{ + // SZJ: skip next if J bit designated by Y is 0 + op_illegal(); +} + + +// Timer instruction + +void melps4_cpu_device::op_t1ab() +{ + // T1AB: transfer A and B to timer 1 + m_tmr_count[0] = m_b << 4 | m_a; +} + +void melps4_cpu_device::op_trab() +{ + // TRAB: transfer A and B to timer 2 reload + m_tmr_reload = m_b << 4 | m_a; +} + +void melps4_cpu_device::op_t2ab() +{ + // T2AB: transfer A and B to timer 2 and timer 2 reload + m_tmr_reload = m_tmr_count[1] = m_b << 4 | m_a; +} + +void melps4_cpu_device::op_tab1() +{ + // TAB1: transfer timer 1 to A and B + m_a = m_tmr_count[0] & 0xf; + m_b = m_tmr_count[0] >> 4; +} + +void melps4_cpu_device::op_tabr() +{ + // TABR: transfer timer 2 reload to A and B + m_a = m_tmr_reload & 0xf; + m_b = m_tmr_reload >> 4; +} + +void melps4_cpu_device::op_tab2() +{ + // TAB2: transfer timer 2 to A and B + m_a = m_tmr_count[1] & 0xf; + m_b = m_tmr_count[1] >> 4; +} + +void melps4_cpu_device::op_tva() +{ + // TVA: transfer A to timer control V + write_v(m_a); +} + +void melps4_cpu_device::op_twa() +{ + // TWA: transfer A to timer control W + write_w(m_a); +} + +void melps4_cpu_device::op_snz1() +{ + // SNZ1: skip next on flag 1F + m_skip = m_irqflag[1]; + m_irqflag[1] = false; +} + +void melps4_cpu_device::op_snz2() +{ + // SNZ2: skip next on flag 2F + m_skip = m_irqflag[2]; + m_irqflag[2] = false; +} + + +// Jumps + +void melps4_cpu_device::op_ba() +{ + // BA: indicate next branch is indirect + m_prohibit_irq = true; + m_ba_flag = true; +} + +void melps4_cpu_device::op_sp() +{ + // SP: set page for next branch + // note: mnemonic is guessed, manual names it BL or BML + m_prohibit_irq = true; + m_sp_param = m_op & 0xf; +} + +void melps4_cpu_device::op_b() +{ + // B xy: branch + m_prohibit_irq = true; + + // determine new page: + // - short call: subroutine page + // - short jump: current page, or sub. page + 1 when in sub. mode + // - long jump/call(B/BM preceded by SP): temp SP register + UINT8 page = m_pc >> 7; + if ((m_prev_op & ~0xf) == m_sp_mask) + { + m_sm = false; + page = m_sp_param; + } + else if (m_sm) + page = m_sm_page | (m_op >> 7 & 1); + + m_pc = page << 7 | (m_op & 0x7f); + + // if BA opcode was executed, set PC low 4 bits to A + if (m_ba_flag) + { + m_ba_flag = false; + m_pc = (m_pc & ~0xf) | m_a; + } +} + +void melps4_cpu_device::op_bm() +{ + // BM xy call subroutine + // don't push stack on short calls when in subroutine mode + if (!m_sm || (m_prev_op & ~0xf) == m_sp_mask) + push_pc(); + + // set subroutine mode - it is reset after long jump/call or return + m_sm = true; + op_b(); +} + + +// Program returns + +void melps4_cpu_device::op_rt() +{ + // RT: return from subroutine + m_prohibit_irq = true; + m_sm = false; + pop_pc(); +} + +void melps4_cpu_device::op_rts() +{ + // RTS: RT, skip next + op_rt(); + m_skip = true; +} + +void melps4_cpu_device::op_rti() +{ + // RTI: return from interrupt routine + op_rt(); + m_sm = m_sms; +} + + +// Input/Output + +void melps4_cpu_device::op_cld() +{ + // CLD: clear port D + write_d_pin(MELPS4_PORTD_CLR, 0); +} + +void melps4_cpu_device::op_cls() +{ + // CLS: clear port S + write_gen_port(MELPS4_PORTS, 0); +} + +void melps4_cpu_device::op_clds() +{ + // CLDS: CLD, CLS + op_cld(); + op_cls(); +} + +void melps4_cpu_device::op_sd() +{ + // SD: set port D pin designated by Y + write_d_pin(m_y, 1); +} + +void melps4_cpu_device::op_rd() +{ + // RD: reset port D pin designated by Y + write_d_pin(m_y, 0); +} + +void melps4_cpu_device::op_szd() +{ + // SZD: skip next if port D pin designated by Y is 0 + m_skip = !read_d_pin(m_y); +} + +void melps4_cpu_device::op_osab() +{ + // OSAB: output A and B to port S + write_gen_port(MELPS4_PORTS, m_b << 4 | m_a); +} + +void melps4_cpu_device::op_ospa() +{ + // OSPA: decode A by PLA and output to port S + op_illegal(); +} + +void melps4_cpu_device::op_ose() +{ + // OSE: output E to port S + write_gen_port(MELPS4_PORTS, m_e); +} + +void melps4_cpu_device::op_ias() +{ + // IAS i: transfer port S(hi/lo) to A + int shift = (m_op & 1) ? 0 : 4; + m_a = read_gen_port(MELPS4_PORTS) >> shift & 0xf; +} + +void melps4_cpu_device::op_ofa() +{ + // OFA: output A to port F + write_gen_port(MELPS4_PORTF, m_a); +} + +void melps4_cpu_device::op_iaf() +{ + // IAF: input port F to A + m_a = read_gen_port(MELPS4_PORTF); +} + +void melps4_cpu_device::op_oga() +{ + // OGA: output A to port G + write_gen_port(MELPS4_PORTG, m_a); +} + +void melps4_cpu_device::op_iak() +{ + // IAK: input port K to A + m_a = m_read_k(0, 0xffff) & 0xf; +} + +void melps4_cpu_device::op_szk() +{ + // SZK j: skip next if port K bit is reset + m_skip = !(m_read_k(0, 0xffff) & m_bitmask); +} + +void melps4_cpu_device::op_su() +{ + // SU/RU: set/reset port U + write_gen_port(MELPS4_PORTU, m_op & 1); +} + + +// Interrupts + +void melps4_cpu_device::op_ei() +{ + // EI: enable interrupt flag + m_prohibit_irq = true; + m_possible_irq = true; + m_inte = 1; +} + +void melps4_cpu_device::op_di() +{ + // DI: disable interrupt flag + m_prohibit_irq = true; + m_inte = 0; +} + +void melps4_cpu_device::op_inth() +{ + // INTH: set external interrupt polarity high (rising edge) + m_intp = 1; +} + +void melps4_cpu_device::op_intl() +{ + // INTL: set external interrupt polarity low (falling edge) + m_intp = 0; +} + + +// Misc + +void melps4_cpu_device::op_nop() +{ + // NOP: no operation +} + +void melps4_cpu_device::op_illegal() +{ + logerror("%s unknown opcode $%03X at $%04X\n", tag(), m_op, m_prev_pc); +} diff --git a/src/devices/cpu/minx/minx.c b/src/devices/cpu/minx/minx.c new file mode 100644 index 00000000000..e822fbd9ecc --- /dev/null +++ b/src/devices/cpu/minx/minx.c @@ -0,0 +1,234 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +/* + Implementation for the Nintendo Minx CPU. + + Registers (mindX13.txt): + 8bit: A B H L FLAGS N U V + 16bit: BA + 24bit: HL, X1, X2, NN, SP + + + "sunlab": + 16bit: + V:PC if high bit set, extended to 23 bits, upper 8 bits V + SP + BA + I:HL + (XI:)X + (YI:)Y + + 8bit: + A, B, H, L + U - delayed jump bank. When a jump occurs, V is set to this value + V + F - flags IDLBSOCZ + I - Interrupt branch + D - Interrupt disable + L - low mask mode enable + B - bcd decimal mode enable + S - sign flag + O - overflow flag + C - carry flag + Z - zero flag + E - exception register + I + N + XI - index/extension + YI - index/extension + +TODO: +- Add support for O and C flags in NEG8 instruction +- Verify MUL (CE D8) and DIV (CE D9) +- Doublecheck behaviour of CMPN instructions ( CF 60 .. CF 63 ) + +*/ + +#include "emu.h" +#include "debugger.h" +#include "minx.h" + +#define FLAG_I 0x80 +#define FLAG_D 0x40 +#define FLAG_L 0x20 +#define FLAG_B 0x10 +#define FLAG_S 0x08 +#define FLAG_O 0x04 +#define FLAG_C 0x02 +#define FLAG_Z 0x01 + +#define EXEC_X0 0x80 +#define EXEC_X1 0x40 +#define EXEC_X2 0x20 +#define EXEC_DZ 0x10 +#define EXEC_EN 0x08 +#define EXEC_04 0x04 +#define EXEC_02 0x02 +#define EXEC_01 0x01 + + +#define RD(offset) m_program->read_byte( offset ) +#define WR(offset,data) m_program->write_byte( offset, data ) +#define GET_MINX_PC ( ( m_PC & 0x8000 ) ? ( m_V << 15 ) | (m_PC & 0x7FFF ) : m_PC ) + + +const device_type MINX = &device_creator; + + +minx_cpu_device::minx_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : cpu_device(mconfig, MINX, "Nintendo Minx", tag, owner, clock, "minx", __FILE__) + , m_program_config("program", ENDIANNESS_BIG, 8, 24, 0) +{ +} + + +UINT16 minx_cpu_device::rd16( UINT32 offset ) +{ + return RD( offset ) | ( RD( offset + 1 ) << 8 ); +} + + +void minx_cpu_device::wr16( UINT32 offset, UINT16 data ) +{ + WR( offset, ( data & 0x00FF ) ); + WR( offset + 1, ( data >> 8 ) ); +} + + +void minx_cpu_device::device_start() +{ + m_program = &space(AS_PROGRAM); + + state_add( MINX_PC, "PC", m_PC ).formatstr("%04X"); + state_add( MINX_SP, "SP", m_SP ).formatstr("%04X"); + state_add( MINX_BA, "BA", m_BA ).formatstr("%04X"); + state_add( MINX_HL, "HL", m_HL ).formatstr("%04X"); + state_add( MINX_X, "X", m_X ).formatstr("%04X"); + state_add( MINX_Y, "Y", m_Y ).formatstr("%04X"); + state_add( MINX_U, "U", m_U ).formatstr("%02X"); + state_add( MINX_V, "V", m_V ).formatstr("%02X"); + state_add( MINX_F, "F", m_F ).formatstr("%02X"); + state_add( MINX_E, "E", m_E ).formatstr("%02X"); + state_add( MINX_N, "N", m_N ).formatstr("%02X"); + state_add( MINX_I, "I", m_I ).formatstr("%02X"); + state_add( MINX_XI, "XI", m_XI ).formatstr("%02X"); + state_add( MINX_YI, "YI", m_YI ).formatstr("%02X"); + + state_add(STATE_GENPC, "curpc", m_curpc).formatstr("%06X").noshow(); + state_add(STATE_GENFLAGS, "GENFLAGS", m_flags).formatstr("%14s").noshow(); + + m_icountptr = &m_icount; +} + + +void minx_cpu_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + switch (entry.index()) + { + case STATE_GENFLAGS: + strprintf(str, "%c%c%c%c%c%c%c%c-%c%c%c%c%c", + m_F & FLAG_I ? 'I' : '.', + m_F & FLAG_D ? 'D' : '.', + m_F & FLAG_L ? 'L' : '.', + m_F & FLAG_B ? 'B' : '.', + m_F & FLAG_S ? 'S' : '.', + m_F & FLAG_O ? 'O' : '.', + m_F & FLAG_C ? 'C' : '.', + m_F & FLAG_Z ? 'Z' : '.', + m_E & EXEC_X0 ? '0' : '.', + m_E & EXEC_X1 ? '1' : '.', + m_E & EXEC_X2 ? '2' : '.', + m_E & EXEC_DZ ? 'z' : '.', + m_E & EXEC_EN ? 'E' : '.' ); + break; + } +} + + +void minx_cpu_device::device_reset() +{ + m_SP = m_BA = m_HL = m_X = m_Y = 0; + m_U = m_V = m_F = m_E = m_I = m_XI = m_YI = 0; + m_halted = m_interrupt_pending = 0; + + m_PC = rd16( 0 ); +} + + +UINT8 minx_cpu_device::rdop() +{ + UINT8 op = RD( GET_MINX_PC ); + m_PC++; + return op; +} + + +UINT16 minx_cpu_device::rdop16() +{ + UINT16 op = rdop(); + op = op | ( rdop() << 8 ); + return op; +} + + +#include "minxfunc.h" +#include "minxopce.h" +#include "minxopcf.h" +#include "minxops.h" + + +void minx_cpu_device::execute_run() +{ + do + { + m_curpc = GET_MINX_PC; + debugger_instruction_hook(this, m_curpc); + + if ( m_interrupt_pending ) + { + m_halted = 0; + if ( ! ( m_F & 0xc0 ) && m_U == m_V ) + { + //logerror("minx_execute(): taking IRQ\n"); + PUSH8( m_V ); + PUSH16( m_PC ); + PUSH8( m_F ); + + /* Set Interrupt Branch flag */ + m_F |= 0x80; + m_V = 0; + m_PC = rd16( standard_irq_callback( 0 ) << 1 ); + m_icount -= 28; /* This cycle count is a guess */ + } + } + + if ( m_halted ) + { + m_icount -= insnminx_cycles_CE[0xAE]; + } + else + { + execute_one(); + } + } while ( m_icount > 0 ); +} + + +void minx_cpu_device::execute_set_input(int inputnum, int state) +{ + if ( state == ASSERT_LINE ) + { + m_interrupt_pending = 1; + } + else + { + m_interrupt_pending = 0; + } +} + + +offs_t minx_cpu_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( minx ); + return CPU_DISASSEMBLE_NAME(minx)(this, buffer, pc, oprom, opram, options); +} diff --git a/src/devices/cpu/minx/minx.h b/src/devices/cpu/minx/minx.h new file mode 100644 index 00000000000..836b76026cc --- /dev/null +++ b/src/devices/cpu/minx/minx.h @@ -0,0 +1,121 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +#pragma once + +#ifndef __MINX_H__ +#define __MINX_H__ + + +enum +{ + MINX_PC=1, MINX_SP, MINX_BA, MINX_HL, MINX_X, MINX_Y, + MINX_U, MINX_V, MINX_F, MINX_E, MINX_N, MINX_I, + MINX_XI, MINX_YI +}; + + +class minx_cpu_device : public cpu_device +{ +public: + // construction/destruction + minx_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_execute_interface overrides + virtual UINT32 execute_min_cycles() const { return 1; } + virtual UINT32 execute_max_cycles() const { return 4; } + virtual UINT32 execute_input_lines() const { return 1; } + virtual void execute_run(); + virtual void execute_set_input(int inputnum, int state); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const { return (spacenum == AS_PROGRAM) ? &m_program_config : NULL; } + + // device_state_interface overrides + void state_string_export(const device_state_entry &entry, std::string &str); + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const { return 1; } + virtual UINT32 disasm_max_opcode_bytes() const { return 5; } + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + +private: + address_space_config m_program_config; + + UINT16 m_PC; + UINT16 m_SP; + UINT16 m_BA; + UINT16 m_HL; + UINT16 m_X; + UINT16 m_Y; + UINT8 m_U; + UINT8 m_V; + UINT8 m_F; + UINT8 m_E; + UINT8 m_N; + UINT8 m_I; + UINT8 m_XI; + UINT8 m_YI; + UINT8 m_halted; + UINT8 m_interrupt_pending; + address_space *m_program; + int m_icount; + // For debugger + UINT32 m_curpc; + UINT16 m_flags; + + UINT16 rd16( UINT32 offset ); + void wr16( UINT32 offset, UINT16 data ); + UINT8 rdop(); + UINT16 rdop16(); + UINT8 ADD8( UINT8 arg1, UINT8 arg2 ); + UINT16 ADD16( UINT16 arg1, UINT16 arg2 ); + UINT8 ADDC8( UINT8 arg1, UINT8 arg2 ); + UINT16 ADDC16( UINT16 arg1, UINT16 arg2 ); + UINT8 INC8( UINT8 arg ); + UINT16 INC16( UINT16 arg ); + UINT8 SUB8( UINT8 arg1, UINT8 arg2 ); + UINT16 SUB16( UINT16 arg1, UINT16 arg2 ); + UINT8 SUBC8( UINT8 arg1, UINT8 arg2 ); + UINT16 SUBC16( UINT16 arg1, UINT16 arg2 ); + UINT8 DEC8( UINT8 arg ); + UINT16 DEC16( UINT16 arg ); + UINT8 AND8( UINT8 arg1, UINT8 arg2 ); + UINT8 OR8( UINT8 arg1, UINT8 arg2 ); + UINT8 XOR8( UINT8 arg1, UINT8 arg2 ); + UINT8 NOT8( UINT8 arg ); + UINT8 NEG8( UINT8 arg ); + UINT8 SAL8( UINT8 arg ); + UINT8 SAR8( UINT8 arg ); + UINT8 SHL8( UINT8 arg ); + UINT8 SHR8( UINT8 arg ); + UINT8 ROLC8( UINT8 arg ); + UINT8 RORC8( UINT8 arg ); + UINT8 ROL8( UINT8 arg ); + UINT8 ROR8( UINT8 arg ); + void PUSH8( UINT8 arg ); + void PUSH16( UINT16 arg ); + UINT8 POP8(); + UINT16 POP16(); + void JMP( UINT16 arg ); + void CALL( UINT16 arg ); + + void execute_one(); + void execute_one_ce(); + void execute_one_cf(); + + static const int insnminx_cycles[256]; + static const int insnminx_cycles_CE[256]; + static const int insnminx_cycles_CF[256]; + +}; + + +extern const device_type MINX; + + +#endif /* __MINX_H__ */ diff --git a/src/devices/cpu/minx/minxd.c b/src/devices/cpu/minx/minxd.c new file mode 100644 index 00000000000..58789942409 --- /dev/null +++ b/src/devices/cpu/minx/minxd.c @@ -0,0 +1,465 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +/************************************************************ + + Nintendo Minx CPU disassembly + + +************************************************************/ + +#include "emu.h" +#include "debugger.h" +#include "minx.h" + +enum e_mnemonic { + zADD=0, zADDC, zAND, zBCDD, zBCDE, zBCDX, zCALL, zCALLC, zCALLG, zCALLGE, zCALLL, + zCALLLE, zCALLN, zCALLNC, zCALLNO, zCALLNZ, zCALLO, zCALLP, zCALLNX0, + zCALLNX1, zCALLNX2, zCALLNX3, zCALLX0, zCALLX1, zCALLX2, zCALLX3, zCALLZ, + zCMP, zCMPN, zDEC, zDIV, zEXT, zHALT, zINC, zINT, + zJC, zJDBNZ, zJG, zJGE, zJINT, zJL, zJLE, zJMP, + zJN, zJNX0, zJNX1, zJNX2, zJNX3, zJNC, zJNO, zJNZ, + zJO, zJP, zJX0, zJX1, zJX2, zJX3, zJZ, zMOV, + zMUL, zNEG, zNOP, zNOT, zOR, zPOP, zPOPA, zPOPAX, + zPOPX, zPUSH, zPUSHA, zPUSHAX, zPUSHX, zRET, zRETI, zRETSKIP, + zROL, zROLC, zROR, zRORC, zSAL, zSAR, zSHL, zSHR, zSUB, + zSUBC, zTEST, zXCHG, zXOR, zDB +}; + +enum e_operand { + R_A=1, /* A */ + R_B, /* B */ + R_L, /* L */ + R_H, /* H */ + R_N, /* N */ + R_F, /* F */ + R_SP, /* SP */ + R_BA, /* BA */ + R_HL, /* HL */ + R_X, /* X */ + R_Y, /* Y */ + R_U, /* U */ + R_V, /* V */ + R_I, /* I */ + R_XI, /* XI */ + R_YI, /* YI */ + R_PC, /* PC */ + I_8, /* 8 bit immediate */ + I_16, /* 16 bit immediate */ + D_8, /* PC + 8 bit displacement (signed) */ + D_16, /* PC + 16 bit displacement */ + S_8, /* SP + 8 bit displacement (signed) */ + M_IHL, /* [I+HL] */ + M_N8, /* [I+N+ofs8] */ + M_I16, /* [I+ofs16] */ + M_X, /* [X] */ + M_Y, /* [Y] */ + M_X8, /* [X + 8 bit displacement (signed)] */ + M_Y8, /* [Y + 8 bit displacement (signed)] */ + M_XL, /* [X + L (signed)] */ + M_YL, /* [Y + L (signed)] */ + M_16, /* [16bit] */ + M_HL, /* [HL] */ + OP, OP1 +}; + +static const char *const s_mnemonic[] = { + "add", "addc", "and", "bcdd", "bcde", "bcdx", "call", "callc", "callg", "callge", "calll", + "callle", "calln", "callnc", "callno", "callnz", "callo", "callp", "callnx0", + "callnx1", "callnx2", "callnx3", "callx0", "callx1", "callx2", "callx3", "callz", + "cmp", "cmpn", "dec", "div", "ext", "halt", "inc", "int", + "jc", "jdbnz", "jg", "jge", "jint", "jl", "jle", "jmp", + "jn", "jnx0", "jnx1", "jnx2", "jnx3", "jnc", "jno", "jnz", + "jo", "jp", "jx0", "jx1", "jx2", "jx3", "jz", "mov", + "mul", "neg", "nop", "not", "or", "pop", "popa", "popax", + "popx", "push", "pusha", "pushax", "pushx", "ret", "reti", "retskip", + "rol", "rolc", "ror", "rorc", "sal", "sar", "shl", "shr", "sub", + "subc", "test", "xchg", "xor", "db" +}; + +#define _OVER DASMFLAG_STEP_OVER +#define _OUT DASMFLAG_STEP_OUT + +static const UINT32 s_flags[] = { + 0, 0, 0, 0, 0, 0, _OVER, _OVER, _OVER, _OVER, _OVER, + _OVER, _OVER, _OVER, _OVER, _OVER, _OVER, _OVER, _OVER, + _OVER, _OVER, _OVER, _OVER, _OVER, _OVER, _OVER, _OVER, + 0, 0, 0, 0, 0, _OVER, 0, _OVER, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, _OUT, _OUT, _OUT, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, +}; + +struct minxdasm { + UINT8 mnemonic; + UINT8 argument1; + UINT8 argument2; +}; + +static const minxdasm mnemonic[256] = { + /* 00 - 0F */ + {zADD,R_A,R_A}, {zADD,R_A,R_B}, {zADD,R_A,I_8}, {zADD,R_A,M_IHL}, + {zADD,R_A,M_N8}, {zADD,R_A,M_I16}, {zADD,R_A,M_X}, {zADD,R_A,M_Y}, + {zADDC,R_A,R_A}, {zADDC,R_A,R_B}, {zADDC,R_A,I_8}, {zADDC,R_A,M_IHL}, + {zADDC,R_A,M_N8}, {zADDC,R_A,M_I16}, {zADDC,R_A,M_X}, {zADDC,R_A,M_Y}, + /* 10 - 1F */ + {zSUB,R_A,R_A}, {zSUB,R_A,R_B}, {zSUB,R_A,I_8}, {zSUB,R_A,M_IHL}, + {zSUB,R_A,M_N8}, {zSUB,R_A,M_I16}, {zSUB,R_A,M_X}, {zSUB,R_A,M_Y}, + {zSUBC,R_A,R_A}, {zSUBC,R_A,R_B}, {zSUBC,R_A,I_8}, {zSUBC,R_A,M_IHL}, + {zSUBC,R_A,M_N8}, {zSUBC,R_A,M_I16}, {zSUBC,R_A,M_X}, {zSUBC,R_A,M_Y}, + /* 20 - 2F */ + {zAND,R_A,R_A}, {zAND,R_A,R_B}, {zAND,R_A,I_8}, {zAND,R_A,M_IHL}, + {zAND,R_A,M_N8}, {zAND,R_A,M_I16}, {zAND,R_A,M_X}, {zAND,R_A,M_Y}, + {zOR,R_A,R_A}, {zOR,R_A,R_B}, {zOR,R_A,I_8}, {zOR,R_A,M_IHL}, + {zOR,R_A,M_N8}, {zOR,R_A,M_I16}, {zOR,R_A,M_X}, {zOR,R_A,M_Y}, + /* 30 - 3F */ + {zCMP,R_A,R_A}, {zCMP,R_A,R_B}, {zCMP,R_A,I_8}, {zCMP,R_A,M_IHL}, + {zCMP,R_A,M_N8}, {zCMP,R_A,M_I16}, {zCMP,R_A,M_X}, {zCMP,R_A,M_Y}, + {zXOR,R_A,R_A}, {zXOR,R_A,R_B}, {zXOR,R_A,I_8}, {zXOR,R_A,M_IHL}, + {zXOR,R_A,M_N8}, {zXOR,R_A,M_I16}, {zXOR,R_A,M_X}, {zXOR,R_A,M_Y}, + /* 40 - 4F */ + {zMOV,R_A,R_A}, {zMOV,R_A,R_B}, {zMOV,R_A,R_L}, {zMOV,R_A,R_H}, + {zMOV,R_A,M_N8}, {zMOV,R_A,M_IHL}, {zMOV,R_A,M_X}, {zMOV,R_A,M_Y}, + {zMOV,R_B,R_A}, {zMOV,R_B,R_B}, {zMOV,R_B,R_L}, {zMOV,R_B,R_H}, + {zMOV,R_B,M_N8}, {zMOV,R_B,M_IHL}, {zMOV,R_B,M_X}, {zMOV,R_B,M_Y}, + /* 50 - 5F */ + {zMOV,R_L,R_A}, {zMOV,R_L,R_B}, {zMOV,R_L,R_L}, {zMOV,R_L,R_H}, + {zMOV,R_L,M_N8}, {zMOV,R_L,M_IHL}, {zMOV,R_L,M_X}, {zMOV,R_L,M_Y}, + {zMOV,R_H,R_A}, {zMOV,R_H,R_B}, {zMOV,R_H,R_L}, {zMOV,R_H,R_H}, + {zMOV,R_H,M_N8}, {zMOV,R_H,M_IHL}, {zMOV,R_H,M_X}, {zMOV,R_H,M_Y}, + /* 60 - 6F */ + {zMOV,M_X,R_A}, {zMOV,M_X,R_B}, {zMOV,M_X,R_L}, {zMOV,M_X,R_H}, + {zMOV,M_X,M_N8}, {zMOV,M_X,M_IHL}, {zMOV,M_X,M_X}, {zMOV,M_X,M_Y}, + {zMOV,M_IHL,R_A}, {zMOV,M_IHL,R_B}, {zMOV,M_IHL,R_L}, {zMOV,M_IHL,R_H}, + {zMOV,M_IHL,M_N8}, {zMOV,M_IHL,M_IHL}, {zMOV,M_IHL,M_X}, {zMOV,M_IHL,M_Y}, + /* 70 - 7F */ + {zMOV,M_Y,R_A}, {zMOV,M_Y,R_B}, {zMOV,M_Y,R_L}, {zMOV,M_Y,R_H}, + {zMOV,M_Y,M_N8}, {zMOV,M_Y,M_IHL}, {zMOV,M_Y,M_X}, {zMOV,M_Y,M_Y}, + {zMOV,M_N8,R_A}, {zMOV,M_N8,R_B}, {zMOV,M_N8,R_L}, {zMOV,M_N8,R_H}, + {zDB,OP,0}, {zMOV,M_N8,M_IHL}, {zMOV,M_N8,M_X}, {zMOV,M_N8,M_Y}, + /* 80 - 8F */ + {zINC,R_A,0}, {zINC,R_B,0}, {zINC,R_L,0}, {zINC,R_H,0}, + {zINC,R_N,0}, {zINC,M_N8,0}, {zINC,M_IHL,0}, {zINC,R_SP,0}, + {zDEC,R_A,0}, {zDEC,R_B,0}, {zDEC,R_L,0}, {zDEC,R_H,0}, + {zDEC,R_N,0}, {zDEC,M_N8,0}, {zDEC,M_IHL,0}, {zDEC,R_SP,0}, + /* 90 - 9F */ + {zINC,R_BA,0}, {zINC,R_HL,0}, {zINC,R_X,0}, {zINC,R_Y,0}, + {zTEST,R_A,R_B}, {zTEST,M_IHL,I_8}, {zTEST,R_A,I_8}, {zTEST,R_B,I_8}, + {zDEC,R_BA,0}, {zDEC,R_HL,0}, {zDEC,R_X,0}, {zDEC,R_Y,0}, + {zAND,R_F,I_8}, {zOR,R_F,I_8}, {zXOR,R_F,I_8}, {zMOV,R_F,I_8}, + /* A0 - AF */ + {zPUSH,R_BA,0}, {zPUSH,R_HL,0}, {zPUSH,R_X,0}, {zPUSH,R_Y,0}, + {zPUSH,R_N,0}, {zPUSH,R_I,0}, {zPUSHX,0,0}, {zPUSH,R_F,0}, + {zPOP,R_BA,0}, {zPOP,R_HL,0}, {zPOP,R_X,0}, {zPOP,R_Y,0}, + {zPOP,R_N,0}, {zPOP,R_I,0}, {zPOP,0,0}, {zPOP,R_F,0}, + /* B0 - BF */ + {zMOV,R_A,I_8}, {zMOV,R_B,I_8}, {zMOV,R_L,I_8}, {zMOV,R_H,I_8}, + {zMOV,R_N,I_8}, {zMOV,M_IHL,I_8}, {zMOV,M_X,I_8}, {zMOV,M_Y,I_8}, + {zMOV,R_BA,M_I16}, {zMOV,R_HL,M_I16}, {zMOV,R_X,M_I16}, {zMOV,R_Y,M_I16}, + {zMOV,M_I16,R_BA}, {zMOV,M_I16,R_HL}, {zMOV,M_I16,R_X}, {zMOV,M_I16,R_Y}, + /* C0 - CF */ + {zADD,R_BA,I_16}, {zADD,R_HL,I_16}, {zADD,R_X,I_16}, {zADD,R_Y,I_16}, + {zMOV,R_BA,I_16}, {zMOV,R_HL,I_16}, {zMOV,R_X,I_16}, {zMOV,R_Y,I_16}, + {zXCHG,R_BA,R_HL}, {zXCHG,R_BA,R_X}, {zXCHG,R_BA,R_Y}, {zXCHG,R_BA,R_SP}, + {zXCHG,R_A,R_B}, {zXCHG,R_A,M_IHL}, {zDB,0,0}, {zDB,0,0}, + /* D0 - DF */ + {zSUB,R_BA,I_16}, {zSUB,R_HL,I_16}, {zSUB,R_X,I_16}, {zSUB,R_Y,I_16}, + {zCMP,R_BA,I_16}, {zCMP,R_HL,I_16}, {zCMP,R_X,I_16}, {zCMP,R_Y,I_16}, + {zAND,M_N8,I_8}, {zOR,M_N8,I_8}, {zXOR,M_N8,I_8}, {zCMP,M_N8,I_8}, + {zTEST,M_N8,I_8}, {zMOV,M_N8,I_8}, {zBCDE,0,0}, {zBCDD,0,0}, + /* E0 - EF */ + {zCALLC,D_8,0}, {zCALLNC,D_8,0}, {zCALLZ,D_8,0}, {zCALLNZ,D_8,0}, + {zJC,D_8,0}, {zJNC,D_8,0}, {zJZ,D_8,0}, {zJNZ,D_8,0}, + {zCALLC,D_16,0}, {zCALLNC,D_16,0}, {zCALLZ,D_16,0}, {zCALLNZ,D_16,0}, + {zJC,D_16,0}, {zJNC,D_16,0}, {zJZ,D_16,0}, {zJNZ,D_16,0}, + /* F0 - FF */ + {zCALL,D_8,0}, {zJMP,D_8,0}, {zCALL,D_16}, {zJMP,D_16}, + {zJMP,R_HL,0}, {zJDBNZ,D_8,0}, {zBCDX,R_A,0}, {zBCDX,M_IHL,0}, + {zRET,0,0}, {zRETI,0,0}, {zRETSKIP,0,0}, {zCALL,M_I16}, + {zINT,I_8,0}, {zJINT,I_8,0}, {zDB,OP,0}, {zNOP,0,0} +}; + +static const minxdasm mnemonic_ce[256] = { + /* 00 - 0F */ + {zADD,R_A,M_X8}, {zADD,R_A,M_Y8}, {zADD,R_A,M_XL}, {zADD,R_A,M_YL}, + {zADD,M_IHL,R_A}, {zADD,M_IHL,I_8}, {zADD,M_IHL,M_X}, {zADD,M_IHL,M_Y}, + {zADDC,R_A,M_X8}, {zADDC,R_A,M_Y8}, {zADDC,R_A,M_XL}, {zADDC,R_A,M_YL}, + {zADDC,M_IHL,R_A}, {zADDC,M_IHL,I_8}, {zADDC,M_IHL,M_X}, {zADDC,M_IHL,M_Y}, + /* 10 - 1F */ + {zSUB,R_A,M_X8}, {zSUB,R_A,M_Y8}, {zSUB,R_A,M_XL}, {zSUB,R_A,M_YL}, + {zSUB,M_IHL,R_A}, {zSUB,M_IHL,I_8}, {zSUB,M_IHL,M_X}, {zSUB,M_IHL,M_Y}, + {zSUBC,R_A,M_X8}, {zSUBC,R_A,M_Y8}, {zSUBC,R_A,M_XL}, {zSUBC,R_A,M_YL}, + {zSUBC,M_IHL,R_A}, {zSUBC,M_IHL,I_8}, {zSUBC,M_IHL,M_X}, {zSUBC,M_IHL,M_Y}, + /* 20 - 2F */ + {zAND,R_A,M_X8}, {zAND,R_A,M_Y8}, {zAND,R_A,M_XL}, {zAND,R_A,M_YL}, + {zAND,M_IHL,R_A}, {zAND,M_IHL,I_8}, {zAND,M_IHL,M_X}, {zAND,M_IHL,M_Y}, + {zOR,R_A,M_X8}, {zOR,R_A,M_Y8}, {zOR,R_A,M_XL}, {zOR,R_A,M_YL}, + {zOR,M_IHL,R_A}, {zOR,M_IHL,I_8}, {zOR,M_IHL,M_X}, {zOR,M_IHL,M_Y}, + /* 30 - 3F */ + {zCMP,R_A,M_X8}, {zCMP,R_A,M_Y8}, {zCMP,R_A,M_XL}, {zCMP,R_A,M_YL}, + {zCMP,M_IHL,R_A}, {zCMP,M_IHL,I_8}, {zCMP,M_IHL,M_X}, {zCMP,M_IHL,M_Y}, + {zXOR,R_A,M_X8}, {zXOR,R_A,M_Y8}, {zXOR,R_A,M_XL}, {zXOR,R_A,M_YL}, + {zXOR,M_IHL,R_A}, {zXOR,M_IHL,I_8}, {zXOR,M_IHL,M_X}, {zXOR,M_IHL,M_Y}, + /* 40 - 4F */ + {zMOV,R_A,M_X8}, {zMOV,R_A,M_Y8}, {zMOV,R_A,M_XL}, {zMOV,R_A,M_YL}, + {zMOV,M_X8,R_A}, {zMOV,M_Y8,R_A}, {zMOV,M_X,R_A}, {zMOV,M_Y,R_A}, + {zMOV,R_B,M_X8}, {zMOV,R_B,M_Y8}, {zMOV,R_B,M_XL}, {zMOV,R_B,M_YL}, + {zMOV,M_X8,R_B}, {zMOV,M_Y8,R_B}, {zMOV,M_X,R_B}, {zMOV,M_Y,R_B}, + /* 50 - 5F */ + {zMOV,R_L,M_X8}, {zMOV,R_L,M_Y8}, {zMOV,R_L,M_XL}, {zMOV,R_L,M_YL}, + {zMOV,M_X8,R_L}, {zMOV,M_Y8,R_L}, {zMOV,M_X,R_L}, {zMOV,M_Y,R_L}, + {zMOV,R_H,M_X8}, {zMOV,R_H,M_Y8}, {zMOV,R_H,M_XL}, {zMOV,R_H,M_YL}, + {zMOV,M_X8,R_H}, {zMOV,M_Y8,R_H}, {zMOV,M_X,R_H}, {zMOV,M_Y,R_H}, + /* 60 - 6F */ + {zMOV,M_IHL,M_X8}, {zMOV,M_IHL,M_Y8}, {zMOV,M_IHL,M_XL}, {zMOV,M_IHL,M_YL}, + {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP}, + {zMOV,M_X,M_X8}, {zMOV,M_X,M_Y8}, {zMOV,M_X,M_XL}, {zMOV,M_X,M_YL}, + {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP}, + /* 70 - 7F */ + {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP}, + {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP}, + {zMOV,M_Y,M_X8}, {zMOV,M_Y,M_Y8}, {zMOV,M_Y,M_XL}, {zMOV,M_Y,M_YL}, + {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP}, + /* 80 - 8F */ + {zSAL,R_A,0}, {zSAL,R_B,0}, {zSAL,M_N8,0}, {zSAL,M_IHL,0}, + {zSHL,R_A,0}, {zSHL,R_B,0}, {zSHL,M_N8,0}, {zSHL,M_IHL,0}, + {zSAR,R_A,0}, {zSAR,R_B,0}, {zSAR,M_N8,0}, {zSAR,M_IHL,0}, + {zSHR,R_A,0}, {zSHR,R_B,0}, {zSHR,M_N8,0}, {zSHR,M_IHL,0}, + /* 90 - 9F */ + {zROLC,R_A,0}, {zROLC,R_B,0}, {zROLC,M_N8,0}, {zROLC,M_IHL,0}, + {zROL,R_A,0}, {zROL,R_B,0}, {zROL,M_N8,0}, {zROL,M_IHL,0}, + {zRORC,R_A,0}, {zRORC,R_B,0}, {zRORC,M_N8,0}, {zRORC,M_IHL,0}, + {zROR,R_A,0}, {zROR,R_B,0}, {zROR,M_N8,0}, {zROR,M_IHL,0}, + /* A0 - AF */ + {zNOT,R_A,0}, {zNOT,R_B,0}, {zNOT,M_N8,0}, {zNOT,M_IHL,0}, + {zNEG,R_A,0}, {zNEG,R_B,0}, {zNEG,M_N8,0}, {zNEG,M_IHL,0}, + {zEXT,R_BA,R_A}, {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP}, + {zDB,OP1,OP}, {zDB,OP1,OP}, {zHALT,0,0}, {zNOP,0,0}, + /* B0 - BF */ + {zAND,R_B,I_8}, {zAND,R_L,I_8}, {zAND,R_H,I_8}, {zDB,OP1,OP}, + {zOR,R_B,I_8}, {zOR,R_L,I_8}, {zOR,R_H,I_8}, {zDB,OP1,OP}, + {zXOR,R_B,I_8}, {zXOR,R_L,I_8}, {zXOR,R_H,I_8}, {zDB,OP1,OP}, + {zCMP,R_B,I_8}, {zCMP,R_L,I_8}, {zCMP,R_H,I_8}, {zCMP,R_N,I_8}, + /* C0 - CF */ + {zMOV,R_A,R_N}, {zMOV,R_A,R_F}, {zMOV,R_N,R_A}, {zMOV,R_F,R_A}, + {zMOV,R_U,I_8}, {zMOV,R_I,I_8}, {zMOV,R_XI,I_8}, {zMOV,R_YI,I_8}, + {zMOV,R_A,R_V}, {zMOV,R_A,R_I}, {zMOV,R_A,R_XI}, {zMOV,R_A,R_YI}, + {zMOV,R_U,R_A}, {zMOV,R_I,R_A}, {zMOV,R_XI,R_A}, {zMOV,R_YI,R_A}, + /* D0 - DF */ + {zMOV,R_A,M_16}, {zMOV,R_B,M_16}, {zMOV,R_H,M_16}, {zMOV,R_L,M_16}, + {zMOV,M_16,R_A}, {zMOV,M_16,R_B}, {zMOV,M_16,R_H}, {zMOV,M_16,R_L}, + {zMUL,R_HL,R_A}, {zDIV,R_HL,R_A}, {zDB,OP1,OP}, {zDB,OP1,OP}, + {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP}, + /* E0 - EF */ + {zJL,D_8,0}, {zJLE,D_8,0}, {zJG,D_8,0}, {zJGE,D_8,0}, + {zJO,D_8,0}, {zJNO,D_8,0}, {zJP,D_8,0}, {zJN,D_8,0}, + {zJNX0,D_8,0}, {zJNX1,D_8,0}, {zJNX2,D_8,0}, {zJNX3,D_8,0}, + {zJX0,D_8,0}, {zJX1,D_8,0}, {zJX2,D_8,0}, {zJX3,D_8,0}, + /* F0 - FF */ + {zCALLL,D_8,0}, {zCALLLE,D_8,0}, {zCALLG,D_8,0}, {zCALLGE,D_8,0}, + {zCALLO,D_8,0}, {zCALLNO,D_8,0}, {zCALLP,D_8,0}, {zCALLN,D_8,0}, + {zCALLNX0,D_8,0}, {zCALLNX1,D_8,0}, {zCALLNX2,D_8,0}, {zCALLNX3,D_8,0}, + {zCALLX0,D_8,0}, {zCALLX1,D_8,0}, {zCALLX2,D_8,0}, {zCALLX3,D_8,0} +}; + +static const minxdasm mnemonic_cf[256] = { + /* 00 - 0F */ + {zADD,R_BA,R_BA}, {zADD,R_BA,R_HL}, {zADD,R_BA,R_X}, {zADD,R_BA,R_Y}, + {zADDC,R_BA,R_BA}, {zADDC,R_BA,R_HL}, {zADDC,R_BA,R_X}, {zADDC,R_BA,R_Y}, + {zSUB,R_BA,R_BA}, {zSUB,R_BA,R_HL}, {zSUB,R_BA,R_X}, {zSUB,R_BA,R_Y}, + {zSUBC,R_BA,R_BA}, {zSUBC,R_BA,R_HL}, {zSUBC,R_BA,R_X}, {zSUBC,R_BA,R_Y}, + /* 10 - 1F */ + {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP}, + {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP}, + {zCMP,R_BA,R_BA}, {zCMP,R_BA,R_HL}, {zCMP,R_BA,R_X}, {zCMP,R_BA,R_Y}, + {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP}, + /* 20 - 2F */ + {zADD,R_HL,R_BA}, {zADD,R_HL,R_HL}, {zADD,R_HL,R_X}, {zADD,R_HL,R_Y}, + {zADDC,R_HL,R_BA}, {zADDC,R_HL,R_HL}, {zADDC,R_HL,R_X}, {zADDC,R_HL,R_Y}, + {zSUB,R_HL,R_BA}, {zSUB,R_HL,R_HL}, {zSUB,R_HL,R_X}, {zSUB,R_HL,R_Y}, + {zSUBC,R_HL,R_BA}, {zSUBC,R_HL,R_HL}, {zSUBC,R_HL,R_X}, {zSUBC,R_HL,R_Y}, + /* 30 - 3F */ + {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP}, + {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP}, + {zCMP,R_HL,R_BA}, {zCMP,R_HL,R_HL}, {zCMP,R_HL,R_X}, {zCMP,R_HL,R_Y}, + {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP}, + /* 40 - 4F */ + {zADD,R_X,R_BA}, {zADD,R_X,R_HL}, {zADD,R_Y,R_BA}, {zADD,R_Y,R_HL}, + {zADD,R_SP,R_BA}, {zADD,R_SP,R_HL}, {zDB,OP1,}, {zDB,OP1,OP}, + {zSUB,R_X,R_BA}, {zSUB,R_X,R_HL}, {zSUB,R_Y,R_BA}, {zSUB,R_Y,R_HL}, + {zSUB,R_SP,R_BA}, {zSUB,R_SP,R_HL}, {zDB,OP1,OP}, {zDB,OP1,OP}, + /* 50 - 5F */ + {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP}, + {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP}, + {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP}, + {zCMP,R_SP,R_BA}, {zCMP,R_SP,R_HL}, {zDB,OP1,OP}, {zDB,OP1,OP}, + /* 60 - 6F */ + {zCMPN,R_BA,I_16}, {zCMPN,R_HL,I_16}, {zCMPN,R_X,I_16}, {zCMPN,R_Y,I_16}, + {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP}, + {zADD,R_SP,I_16}, {zDB,OP1,OP}, {zSUB,R_SP,I_16}, {zDB,OP1,OP}, + {zCMP,R_SP,I_16}, {zDB,OP1,OP}, {zMOV,R_SP,I_16}, {zDB,OP1,OP}, + /* 70 - 7F */ + {zMOV,R_BA,S_8}, {zMOV,R_HL,S_8}, {zMOV,R_X,S_8}, {zMOV,R_Y,S_8}, + {zMOV,S_8,R_BA}, {zMOV,S_8,R_HL}, {zMOV,S_8,R_X}, {zMOV,S_8,R_Y}, + {zMOV,R_SP,M_I16}, {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP}, + {zMOV,M_I16,R_SP}, {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP}, + /* 80 - 8F */ + {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP}, + {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP}, + {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP}, + {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP}, + /* 90 - 9F */ + {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP}, + {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP}, + {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP}, + {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP}, + /* A0 - AF */ + {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP}, + {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP}, + {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP}, + {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP}, + /* B0 - BF */ + {zPUSH,R_A,0}, {zPUSH,R_B,0}, {zPUSH,R_L,0}, {zPUSH,R_H,0}, + {zPOP,R_A,0}, {zPOP,R_B,0}, {zPOP,R_L,0}, {zPOP,R_H,0}, + {zPUSHA,0,0}, {zPUSHAX,0,0}, {zDB,OP1,OP}, {zDB,OP1,OP}, + {zPOPA,0,0}, {zPOPAX,0,0}, {zDB,OP1,OP}, {zDB,OP1,OP}, + /* C0 - CF */ + {zMOV,R_BA,M_HL}, {zMOV,R_HL,M_HL}, {zMOV,R_X,M_HL}, {zMOV,R_Y,M_HL}, + {zMOV,M_HL,R_BA}, {zMOV,M_HL,R_HL}, {zMOV,M_HL,R_X}, {zMOV,M_HL,R_Y}, + {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP}, + {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP}, {zDB,OP1,OP}, + /* D0 - DF */ + {zMOV,R_BA,M_X}, {zMOV,R_HL,M_X}, {zMOV,R_X,M_X}, {zMOV,R_Y,M_X}, + {zMOV,M_X,R_BA}, {zMOV,M_X,R_HL}, {zMOV,M_X,R_X}, {zMOV,M_X,R_Y}, + {zMOV,R_BA,M_Y}, {zMOV,R_HL,M_Y}, {zMOV,R_X,M_Y}, {zMOV,R_Y,M_Y}, + {zMOV,M_Y,R_BA}, {zMOV,M_Y,R_HL}, {zMOV,M_Y,R_X}, {zMOV,M_Y,R_Y}, + /* E0 - EF */ + {zMOV,R_BA,R_BA}, {zMOV,R_BA,R_HL}, {zMOV,R_BA,R_X}, {zMOV,R_BA,R_Y}, + {zMOV,R_HL,R_BA}, {zMOV,R_HL,R_HL}, {zMOV,R_HL,R_X}, {zMOV,R_HL,R_Y}, + {zMOV,R_X,R_BA}, {zMOV,R_X,R_HL}, {zMOV,R_X,R_X}, {zMOV,R_X,R_Y}, + {zMOV,R_Y,R_BA}, {zMOV,R_Y,R_HL}, {zMOV,R_Y,R_X}, {zMOV,R_Y,R_Y}, + /* F0 - FF */ + {zMOV,R_SP,R_BA}, {zMOV,R_SP,R_HL}, {zMOV,R_SP,R_X}, {zMOV,R_SP,R_Y}, + {zMOV,R_HL,R_SP}, {zMOV,R_HL,R_PC}, {zDB,OP1,OP}, {zDB,OP1,OP}, + {zMOV,R_BA,R_SP}, {zMOV,R_BA,R_PC}, {zMOV,R_X,R_SP}, {zDB,OP1,OP}, + {zDB,OP1,OP}, {zDB,OP1,OP}, {zMOV,R_Y,R_SP}, {zDB,OP1,OP} +}; + +#define HANDLE_ARGUMENT \ +case R_A: dst += sprintf( dst, "%cA", fill ); break; \ +case R_B: dst += sprintf( dst, "%cB", fill ); break; \ +case R_L: dst += sprintf( dst, "%cL", fill ); break; \ +case R_H: dst += sprintf( dst, "%cH", fill ); break; \ +case R_N: dst += sprintf( dst, "%cN", fill ); break; \ +case R_F: dst += sprintf( dst, "%cF", fill ); break; \ +case R_SP: dst += sprintf( dst, "%cSP", fill ); break; \ +case R_BA: dst += sprintf( dst, "%cBA", fill ); break; \ +case R_HL: dst += sprintf( dst, "%cHL", fill ); break; \ +case R_X: dst += sprintf( dst, "%cX", fill ); break; \ +case R_Y: dst += sprintf( dst, "%cY", fill ); break; \ +case R_U: dst += sprintf( dst, "%cU", fill ); break; \ +case R_V: dst += sprintf( dst, "%cV", fill ); break; \ +case R_I: dst += sprintf( dst, "%cI", fill ); break; \ +case R_XI: dst += sprintf( dst, "%cXI", fill ); break; \ +case R_YI: dst += sprintf( dst, "%cYI", fill ); break; \ +case R_PC: dst += sprintf( dst, "%cPC", fill ); break; \ +case I_8: /* 8 bit immediate */ \ + ea = oprom[pos++]; \ + dst += sprintf( dst, "%c$%02X", fill, ea ); \ + break; \ +case I_16: /* 16 bit immediate */ \ + ea = oprom[pos++]; \ + ea += oprom[pos++] << 8; \ + dst += sprintf( dst, "%c$%04X", fill, ea ); \ + break; \ +case D_8: /* PC + 8 bit displacement (signed) */ \ + ofs8 = oprom[pos++]; \ + dst += sprintf( dst, "%c$%04X", fill, pc + pos - 1 + ofs8 ); \ + break; \ +case D_16: /* PC + 16 bit displacement */ \ + ea = oprom[pos++]; \ + ea += oprom[pos++] << 8; \ + ea = ea - 1; \ + dst += sprintf( dst, "%c$%04X", fill, pc + pos + ea ); \ + break; \ +case S_8: /* SP + 8 bit displacement (signed) */ \ + ea = oprom[pos++]; \ + dst += sprintf( dst, "%cSP+$%02X", fill, ea ); \ + break; \ +case M_IHL: dst += sprintf( dst, "%c[I+HL]", fill ); break; \ +case M_N8: /* [I+N+ofs8] */ \ + ea = oprom[pos++]; \ + dst += sprintf( dst, "%c[I+N+$%02X]", fill, ea ); \ + break; \ +case M_I16: /* [I+ofs16] */ \ + ea = oprom[pos++]; \ + ea += oprom[pos++] << 8; \ + dst += sprintf( dst, "%c[I+$%04X]", fill, ea ); \ + break; \ +case M_X: dst += sprintf( dst, "%c[X]", fill ); break; \ +case M_Y: dst += sprintf( dst, "%c[Y]", fill ); break; \ +case M_X8: /* [X + 8 bit displacement (signed)] */ \ + ea = oprom[pos++]; \ + dst += sprintf( dst, "%c[X+$%02X]", fill, ea ); \ + break; \ +case M_Y8: /* [Y + 8 bit displacement (signed)] */ \ + ea = oprom[pos++]; \ + dst += sprintf( dst, "%c[Y+$%02X]", fill, ea ); \ + break; \ +case M_XL: dst += sprintf( dst, "%c[X+L]", fill ); break; \ +case M_YL: dst += sprintf( dst, "%c[Y+L]", fill ); break; \ +case M_16: /* [16bit] */ \ + ea = oprom[pos++]; \ + ea += oprom[pos++] << 8; \ + dst += sprintf( dst, "%c[$%04X]", fill, ea ); \ + break; \ +case M_HL: dst += sprintf( dst, "%c[HL]", fill ); break; \ +case OP: dst += sprintf( dst, "%c$%02X", fill, op ); break; \ +case OP1: dst += sprintf( dst, "%c$%02X", fill, op1 ); break; + +CPU_DISASSEMBLE( minx ) +{ + const minxdasm *instr; + UINT8 op, op1; + INT8 ofs8 = 0; + UINT16 ea = 0; + int pos = 0; + char *dst = buffer; + + op1 = op = oprom[pos++]; + + switch (op) { + case 0xCE: + op = oprom[pos++]; + instr = &mnemonic_ce[op]; + break; + case 0xCF: + op = oprom[pos++]; + instr = &mnemonic_cf[op]; + break; + default: + instr = &mnemonic[op]; + break; + } + + dst += sprintf( dst, "%-6s", s_mnemonic[ instr->mnemonic ] ); + + if ( instr->argument1 ) { + char fill = ' '; + //int arg = 0; + switch( instr->argument1 ) { + HANDLE_ARGUMENT; + } + } + if ( instr->argument2 ) { + char fill = ','; + //int arg = 1; + switch( instr->argument2 ) { + HANDLE_ARGUMENT; + } + } + return pos | s_flags[instr->mnemonic] | DASMFLAG_SUPPORTED; +} diff --git a/src/devices/cpu/minx/minxfunc.h b/src/devices/cpu/minx/minxfunc.h new file mode 100644 index 00000000000..45478bc6667 --- /dev/null +++ b/src/devices/cpu/minx/minxfunc.h @@ -0,0 +1,364 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +UINT8 minx_cpu_device::ADD8( UINT8 arg1, UINT8 arg2 ) +{ + UINT32 res = arg1 + arg2; + m_F = ( m_F & ~ ( FLAG_S | FLAG_O | FLAG_C | FLAG_Z ) ) + | ( ( res & 0x80 ) ? FLAG_S : 0 ) + | ( ( ( arg2 ^ arg1 ^ 0x80 ) & ( arg2 ^ res ) & 0x80 ) ? FLAG_O : 0 ) + | ( ( res & 0xFF00 ) ? FLAG_C : 0 ) + | ( ( res ) ? 0 : FLAG_Z ) + ; + return res & 0xFF; +} + + +UINT16 minx_cpu_device::ADD16( UINT16 arg1, UINT16 arg2 ) +{ + UINT32 res = arg1 + arg2; + m_F = ( m_F & ~ ( FLAG_S | FLAG_O | FLAG_C | FLAG_Z ) ) + | ( ( res & 0x8000 ) ? FLAG_S : 0 ) + | ( ( ( arg2 ^ arg1 ^ 0x8000 ) & ( arg2 ^ res ) & 0x8000 ) ? FLAG_O : 0 ) + | ( ( res & 0xFF0000 ) ? FLAG_C : 0 ) + | ( ( res ) ? 0 : FLAG_Z ) + ; + return res & 0xFFFF; +} + + +UINT8 minx_cpu_device::ADDC8( UINT8 arg1, UINT8 arg2 ) +{ + UINT32 res = arg1 + arg2 + ( ( m_F & FLAG_C ) ? 1 : 0 ); + m_F = ( m_F & ~ ( FLAG_S | FLAG_O | FLAG_C | FLAG_Z ) ) + | ( ( res & 0x80 ) ? FLAG_S : 0 ) + | ( ( ( arg2 ^ arg1 ^ 0x80 ) & ( arg2 ^ res ) & 0x80 ) ? FLAG_O : 0 ) + | ( ( res & 0xFF00 ) ? FLAG_C : 0 ) + | ( ( res ) ? 0 : FLAG_Z ) + ; + return res & 0xFF; +} + + +UINT16 minx_cpu_device::ADDC16( UINT16 arg1, UINT16 arg2 ) +{ + UINT32 res = arg1 + arg2 + ( ( m_F & FLAG_C ) ? 1 : 0 ); + m_F = ( m_F & ~ ( FLAG_S | FLAG_O | FLAG_C | FLAG_Z ) ) + | ( ( res & 0x8000 ) ? FLAG_S : 0 ) + | ( ( ( arg2 ^ arg1 ^ 0x8000 ) & ( arg2 ^ res ) & 0x8000 ) ? FLAG_O : 0 ) + | ( ( res & 0xFF0000 ) ? FLAG_C : 0 ) + | ( ( res ) ? 0 : FLAG_Z ) + ; + return res & 0xFFFF; +} + + +UINT8 minx_cpu_device::INC8( UINT8 arg ) +{ + UINT8 old_F = m_F; + UINT8 res = ADD8( arg, 1 ); + m_F = ( old_F & ~ ( FLAG_Z ) ) + | ( ( res ) ? 0 : FLAG_Z ) + ; + return res; +} + + +UINT16 minx_cpu_device::INC16( UINT16 arg ) +{ + UINT8 old_F = m_F; + UINT16 res = ADD16( arg, 1 ); + m_F = ( old_F & ~ ( FLAG_Z ) ) + | ( ( res ) ? 0 : FLAG_Z ) + ; + return res; +} + + +UINT8 minx_cpu_device::SUB8( UINT8 arg1, UINT8 arg2 ) +{ + UINT32 res = arg1 - arg2; + m_F = ( m_F & ~ ( FLAG_S | FLAG_O | FLAG_C | FLAG_Z ) ) + | ( ( res & 0x80 ) ? FLAG_S : 0 ) + | ( ( ( arg2 ^ arg1 ) & ( arg1 ^ res ) & 0x80 ) ? FLAG_O : 0 ) + | ( ( res & 0xFF00 ) ? FLAG_C : 0 ) + | ( ( res ) ? 0 : FLAG_Z ) + ; + return res & 0xFF; +} + + +UINT16 minx_cpu_device::SUB16( UINT16 arg1, UINT16 arg2 ) +{ + UINT32 res = arg1 - arg2; + m_F = ( m_F & ~ ( FLAG_S | FLAG_O | FLAG_C | FLAG_Z ) ) + | ( ( res & 0x8000 ) ? FLAG_S : 0 ) + | ( ( ( arg2 ^ arg1 ) & ( arg1 ^ res ) & 0x8000 ) ? FLAG_O : 0 ) + | ( ( res & 0xFF0000 ) ? FLAG_C : 0 ) + | ( ( res ) ? 0 : FLAG_Z ) + ; + return res & 0xFFFF; +} + + +UINT8 minx_cpu_device::SUBC8( UINT8 arg1, UINT8 arg2 ) +{ + UINT32 res = arg1 - arg2 - ( ( m_F & FLAG_C ) ? 1 : 0 ); + m_F = ( m_F & ~ ( FLAG_S | FLAG_O | FLAG_C | FLAG_Z ) ) + | ( ( res & 0x80 ) ? FLAG_S : 0 ) + | ( ( ( arg2 ^ arg1 ) & ( arg1 ^ res ) & 0x80 ) ? FLAG_O : 0 ) + | ( ( res & 0xFF00 ) ? FLAG_C : 0 ) + | ( ( res ) ? 0 : FLAG_Z ) + ; + return res & 0xFF; +} + + +UINT16 minx_cpu_device::SUBC16( UINT16 arg1, UINT16 arg2 ) +{ + UINT32 res = arg1 - arg2 - ( ( m_F & FLAG_C ) ? 1 : 0 ); + m_F = ( m_F & ~ ( FLAG_S | FLAG_O | FLAG_C | FLAG_Z ) ) + | ( ( res & 0x8000 ) ? FLAG_S : 0 ) + | ( ( ( arg2 ^ arg1 ) & ( arg1 ^ res ) & 0x8000 ) ? FLAG_O : 0 ) + | ( ( res & 0xFF0000 ) ? FLAG_C : 0 ) + | ( ( res ) ? 0 : FLAG_Z ) + ; + return res & 0xFFFF; +} + + +UINT8 minx_cpu_device::DEC8( UINT8 arg ) +{ + UINT8 old_F = m_F; + UINT8 res = SUB8( arg, 1 ); + m_F = ( old_F & ~ ( FLAG_Z ) ) + | ( ( res ) ? 0 : FLAG_Z ) + ; + return res; +} + + +UINT16 minx_cpu_device::DEC16( UINT16 arg ) +{ + UINT8 old_F = m_F; + UINT16 res = SUB16( arg, 1 ); + m_F = ( old_F & ~ ( FLAG_Z ) ) + | ( ( res ) ? 0 : FLAG_Z ) + ; + return res; +} + + +UINT8 minx_cpu_device::AND8( UINT8 arg1, UINT8 arg2 ) +{ + UINT8 res = arg1 & arg2; + m_F = ( m_F & ~ ( FLAG_S | FLAG_Z ) ) + | ( ( res & 0x80 ) ? FLAG_S : 0 ) + | ( ( res ) ? 0 : FLAG_Z ) + ; + return res; +} + + +UINT8 minx_cpu_device::OR8( UINT8 arg1, UINT8 arg2 ) +{ + UINT8 res = arg1 | arg2; + m_F = ( m_F & ~ ( FLAG_S | FLAG_Z ) ) + | ( ( res & 0x80 ) ? FLAG_S : 0 ) + | ( ( res ) ? 0 : FLAG_Z ) + ; + return res; +} + + +UINT8 minx_cpu_device::XOR8( UINT8 arg1, UINT8 arg2 ) +{ + UINT8 res = arg1 ^ arg2; + m_F = ( m_F & ~ ( FLAG_S | FLAG_Z ) ) + | ( ( res & 0x80 ) ? FLAG_S : 0 ) + | ( ( res ) ? 0 : FLAG_Z ) + ; + return res; +} + + +UINT8 minx_cpu_device::NOT8( UINT8 arg ) +{ + UINT8 res = ~arg; + m_F = ( m_F & ~ ( FLAG_S | FLAG_Z ) ) + | ( ( res & 0x80 ) ? FLAG_S : 0 ) + | ( ( res ) ? 0 : FLAG_Z ) + ; + return res; +} + + +UINT8 minx_cpu_device::NEG8( UINT8 arg ) +{ + UINT8 res = -arg; + m_F = ( m_F & ~ ( FLAG_S | FLAG_O | FLAG_C | FLAG_Z ) ) + | ( ( res & 0x80 ) ? FLAG_S : 0 ) + | ( ( res ) ? 0 : FLAG_Z ) + ; + return res; +} + + +UINT8 minx_cpu_device::SAL8( UINT8 arg ) +{ + UINT16 res = arg << 1; + m_F = ( m_F & ~ ( FLAG_S | FLAG_O | FLAG_C | FLAG_Z ) ) + | ( ( res & 0x80 ) ? FLAG_S : 0 ) + | ( ( arg != 0 && res == 0 ) ? FLAG_O : 0 ) + | ( ( arg & 0x80 ) ? FLAG_C : 0 ) + | ( ( res ) ? 0 : FLAG_Z ) + ; + return res; +} + + +UINT8 minx_cpu_device::SAR8( UINT8 arg ) +{ + UINT16 res = ( arg >> 1 ) | ( arg & 0x80 ); + m_F = ( m_F & ~ ( FLAG_S | FLAG_O | FLAG_C | FLAG_Z ) ) + | ( ( res & 0x80 ) ? FLAG_S : 0 ) + | ( ( arg != 0x80 && res == 0x80 ) ? FLAG_O : 0 ) + | ( ( arg & 0x01 ) ? FLAG_C : 0 ) + | ( ( res ) ? 0 : FLAG_Z ) + ; + return res & 0xFF; +} + + +UINT8 minx_cpu_device::SHL8( UINT8 arg ) +{ + UINT16 res = arg << 1; + m_F = ( m_F & ~ ( FLAG_S | FLAG_C | FLAG_Z ) ) + | ( ( res & 0x80 ) ? FLAG_S : 0 ) + | ( ( arg & 0x80 ) ? FLAG_C : 0 ) + | ( ( res ) ? 0 : FLAG_Z ) + ; + return res; +} + + +UINT8 minx_cpu_device::SHR8( UINT8 arg ) +{ + UINT16 res = arg >> 1; + m_F = ( m_F & ~ ( FLAG_S | FLAG_C | FLAG_Z ) ) + | ( ( res & 0x80 ) ? FLAG_S : 0 ) + | ( ( arg & 0x01 ) ? FLAG_C : 0 ) + | ( ( res ) ? 0 : FLAG_Z ) + ; + return res & 0xFF; +} + + +UINT8 minx_cpu_device::ROLC8( UINT8 arg ) +{ + UINT16 res = ( arg << 1 ) | ( ( m_F & FLAG_C ) ? 1 : 0 ); + m_F = ( m_F & ~ ( FLAG_S | FLAG_C | FLAG_Z ) ) + | ( ( res & 0x80 ) ? FLAG_S : 0 ) + | ( ( arg & 0x80 ) ? FLAG_C : 0 ) + | ( ( res ) ? 0 : FLAG_Z ) + ; + return res & 0xFF; +} + + +UINT8 minx_cpu_device::RORC8( UINT8 arg ) +{ + UINT16 res = ( arg >> 1 ) | ( ( m_F & FLAG_C ) ? 0x80 : 0 ); + m_F = ( m_F & ~ ( FLAG_S | FLAG_C | FLAG_Z ) ) + | ( ( res & 0x80 ) ? FLAG_S : 0 ) + | ( ( arg & 0x01 ) ? FLAG_C : 0 ) + | ( ( res ) ? 0 : FLAG_Z ) + ; + return res & 0xFF; +} + + +UINT8 minx_cpu_device::ROL8( UINT8 arg ) +{ + UINT16 res = ( arg << 1 ) | ( ( arg & 0x80 ) ? 1 : 0 ); + m_F = ( m_F & ~ ( FLAG_S | FLAG_C | FLAG_Z ) ) + | ( ( res & 0x80 ) ? FLAG_S : 0 ) + | ( ( arg & 0x80 ) ? FLAG_C : 0 ) + | ( ( res ) ? 0 : FLAG_Z ) + ; + return res & 0xFF; +} + + +UINT8 minx_cpu_device::ROR8( UINT8 arg ) +{ + UINT16 res = ( arg >> 1 ) | ( ( arg & 0x01 ) ? 0x80 : 0 ); + m_F = ( m_F & ~ ( FLAG_S | FLAG_C | FLAG_Z ) ) + | ( ( res & 0x80 ) ? FLAG_S : 0 ) + | ( ( arg & 0x01 ) ? FLAG_C : 0 ) + | ( ( res ) ? 0 : FLAG_Z ) + ; + return res & 0xFF; +} + + +void minx_cpu_device::PUSH8( UINT8 arg ) +{ + m_SP = m_SP - 1; + WR( m_SP, arg ); +} + + +void minx_cpu_device::PUSH16( UINT16 arg ) +{ + PUSH8( arg >> 8 ); + PUSH8( arg & 0x00FF ); +} + + +UINT8 minx_cpu_device::POP8() +{ + UINT8 res = RD( m_SP ); + m_SP = m_SP + 1; + return res; +} + + +UINT16 minx_cpu_device::POP16() +{ + return POP8() | ( POP8() << 8 ); +} + + +void minx_cpu_device::JMP( UINT16 arg ) +{ + m_V = m_U; + m_PC = arg; +} + + +void minx_cpu_device::CALL( UINT16 arg ) +{ + PUSH8( m_V ); + PUSH16( m_PC ); + JMP( arg ); +} + + +#define AD1_IHL UINT32 addr1 = ( m_I << 16 ) | m_HL +#define AD1_IN8 UINT32 addr1 = ( m_I << 16 ) | ( m_N << 8 ) | rdop() +#define AD1_I16 UINT32 addr1 = ( m_I << 16 ) | rdop16() +#define AD1_XIX UINT32 addr1 = ( m_XI << 16 ) | m_X +#define AD1_YIY UINT32 addr1 = ( m_YI << 16 ) | m_Y +#define AD1_X8 UINT32 addr1 = ( m_XI << 16 ) | ( m_X + rdop() ) +#define AD1_Y8 UINT32 addr1 = ( m_YI << 16 ) | ( m_Y + rdop() ) +#define AD1_XL UINT32 addr1 = ( m_XI << 16 ) | ( m_X + ( m_HL & 0x00FF ) ) +#define AD1_YL UINT32 addr1 = ( m_YI << 16 ) | ( m_Y + ( m_HL & 0x00FF ) ) +#define AD2_IHL UINT32 addr2 = ( m_I << 16 ) | m_HL +#define AD2_IN8 UINT32 addr2 = ( m_I << 16 ) | ( m_N << 8 ) | rdop() +#define AD2_I16 UINT32 addr2 = ( m_I << 16 ) | rdop(); addr2 |= ( rdop() << 8 ) +#define AD2_XIX UINT32 addr2 = ( m_XI << 16 ) | m_X +#define AD2_YIY UINT32 addr2 = ( m_YI << 16 ) | m_Y +#define AD2_X8 UINT32 addr2 = ( m_XI << 16 ) | ( m_X + rdop() ) +#define AD2_Y8 UINT32 addr2 = ( m_YI << 16 ) | ( m_Y + rdop() ) +#define AD2_XL UINT32 addr2 = ( m_XI << 16 ) | ( m_X + ( m_HL & 0x00FF ) ) +#define AD2_YL UINT32 addr2 = ( m_YI << 16 ) | ( m_Y + ( m_HL & 0x00FF ) ) diff --git a/src/devices/cpu/minx/minxopce.h b/src/devices/cpu/minx/minxopce.h new file mode 100644 index 00000000000..ec0198273e3 --- /dev/null +++ b/src/devices/cpu/minx/minxopce.h @@ -0,0 +1,563 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol + +void minx_cpu_device::execute_one_ce() +{ + const UINT8 opcode = rdop(); + + switch (opcode) + { + case 0x00: { AD2_X8; m_BA = ( m_BA & 0xFF00 ) | ADD8( ( m_BA & 0x00FF ), RD( addr2 ) ); } + break; + case 0x01: { AD2_Y8; m_BA = ( m_BA & 0xFF00 ) | ADD8( ( m_BA & 0x00FF ), RD( addr2 ) ); } + break; + case 0x02: { AD2_XL; m_BA = ( m_BA & 0xFF00 ) | ADD8( ( m_BA & 0x00FF ), RD( addr2 ) ); } + break; + case 0x03: { AD2_YL; m_BA = ( m_BA & 0xFF00 ) | ADD8( ( m_BA & 0x00FF ), RD( addr2 ) ); } + break; + case 0x04: { AD1_IHL; WR( addr1, ADD8( RD( addr1 ), ( m_BA & 0x00FF ) ) ); } + break; + case 0x05: { AD1_IHL; WR( addr1, ADD8( RD( addr1 ), rdop() ) ); } + break; + case 0x06: { AD1_IHL; AD2_XIX; WR( addr1, ADD8( RD( addr1 ), RD( addr2 ) ) ); } + break; + case 0x07: { AD1_IHL; AD2_YIY; WR( addr1, ADD8( RD( addr1 ), RD( addr2 ) ) ); } + break; + case 0x08: { AD2_X8; m_BA = ( m_BA & 0xFF00 ) | ADDC8( ( m_BA & 0x00FF ), RD( addr2 ) ); } + break; + case 0x09: { AD2_Y8; m_BA = ( m_BA & 0xFF00 ) | ADDC8( ( m_BA & 0x00FF ), RD( addr2 ) ); } + break; + case 0x0A: { AD2_XL; m_BA = ( m_BA & 0xFF00 ) | ADDC8( ( m_BA & 0x00FF ), RD( addr2 ) ); } + break; + case 0x0B: { AD2_YL; m_BA = ( m_BA & 0xFF00 ) | ADDC8( ( m_BA & 0x00FF ), RD( addr2 ) ); } + break; + case 0x0C: { AD1_IHL; WR( addr1, ADDC8( RD( addr1 ), ( m_BA & 0x00FF ) ) ); } + break; + case 0x0D: { AD1_IHL; WR( addr1, ADDC8( RD( addr1 ), rdop() ) ); } + break; + case 0x0E: { AD1_IHL; AD2_XIX; WR( addr1, ADDC8( RD( addr1 ), RD( addr2 ) ) ); } + break; + case 0x0F: { AD1_IHL; AD2_YIY; WR( addr1, ADDC8( RD( addr1 ), RD( addr2 ) ) ); } + break; + + case 0x10: { AD2_X8; m_BA = ( m_BA & 0xFF00 ) | SUB8( ( m_BA & 0x00FF ), RD( addr2 ) ); } + break; + case 0x11: { AD2_Y8; m_BA = ( m_BA & 0xFF00 ) | SUB8( ( m_BA & 0x00FF ), RD( addr2 ) ); } + break; + case 0x12: { AD2_XL; m_BA = ( m_BA & 0xFF00 ) | SUB8( ( m_BA & 0x00FF ), RD( addr2 ) ); } + break; + case 0x13: { AD2_YL; m_BA = ( m_BA & 0xFF00 ) | SUB8( ( m_BA & 0x00FF ), RD( addr2 ) ); } + break; + case 0x14: { AD1_IHL; WR( addr1, SUB8( RD( addr1 ), ( m_BA & 0x00FF ) ) ); } + break; + case 0x15: { AD1_IHL; WR( addr1, SUB8( RD( addr1 ), rdop() ) ); } + break; + case 0x16: { AD1_IHL; AD2_XIX; WR( addr1, SUB8( RD( addr1 ), RD( addr2 ) ) ); } + break; + case 0x17: { AD1_IHL; AD2_YIY; WR( addr1, SUB8( RD( addr1 ), RD( addr2 ) ) ); } + break; + case 0x18: { AD2_X8; m_BA = ( m_BA & 0xFF00 ) | SUBC8( ( m_BA & 0x00FF ), RD( addr2 ) ); } + break; + case 0x19: { AD2_Y8; m_BA = ( m_BA & 0xFF00 ) | SUBC8( ( m_BA & 0x00FF ), RD( addr2 ) ); } + break; + case 0x1A: { AD2_XL; m_BA = ( m_BA & 0xFF00 ) | SUBC8( ( m_BA & 0x00FF ), RD( addr2 ) ); } + break; + case 0x1B: { AD2_YL; m_BA = ( m_BA & 0xFF00 ) | SUBC8( ( m_BA & 0x00FF ), RD( addr2 ) ); } + break; + case 0x1C: { AD1_IHL; WR( addr1, SUBC8( RD( addr1 ), ( m_BA & 0x00FF ) ) ); } + break; + case 0x1D: { AD1_IHL; WR( addr1, SUBC8( RD( addr1 ), rdop() ) ); } + break; + case 0x1E: { AD1_IHL; AD2_XIX; WR( addr1, SUBC8( RD( addr1 ), RD( addr2 ) ) ); } + break; + case 0x1F: { AD1_IHL; AD2_YIY; WR( addr1, SUBC8( RD( addr1 ), RD( addr2 ) ) ); } + break; + + case 0x20: { AD2_X8; m_BA = ( m_BA & 0xFF00 ) | AND8( ( m_BA & 0x00FF ), RD( addr2 ) ); } + break; + case 0x21: { AD2_Y8; m_BA = ( m_BA & 0xFF00 ) | AND8( ( m_BA & 0x00FF ), RD( addr2 ) ); } + break; + case 0x22: { AD2_XL; m_BA = ( m_BA & 0xFF00 ) | AND8( ( m_BA & 0x00FF ), RD( addr2 ) ); } + break; + case 0x23: { AD2_YL; m_BA = ( m_BA & 0xFF00 ) | AND8( ( m_BA & 0x00FF ), RD( addr2 ) ); } + break; + case 0x24: { AD1_IHL; WR( addr1, AND8( RD( addr1 ), ( m_BA & 0x00FF ) ) ); } + break; + case 0x25: { AD1_IHL; WR( addr1, AND8( RD( addr1 ), rdop() ) ); } + break; + case 0x26: { AD1_IHL; AD2_XIX; WR( addr1, AND8( RD( addr1 ), RD( addr2 ) ) ); } + break; + case 0x27: { AD1_IHL; AD2_YIY; WR( addr1, AND8( RD( addr1 ), RD( addr2 ) ) ); } + break; + case 0x28: { AD2_X8; m_BA = ( m_BA & 0xFF00 ) | OR8( ( m_BA & 0x00FF ), RD( addr2 ) ); } + break; + case 0x29: { AD2_Y8; m_BA = ( m_BA & 0xFF00 ) | OR8( ( m_BA & 0x00FF ), RD( addr2 ) ); } + break; + case 0x2A: { AD2_XL; m_BA = ( m_BA & 0xFF00 ) | OR8( ( m_BA & 0x00FF ), RD( addr2 ) ); } + break; + case 0x2B: { AD2_YL; m_BA = ( m_BA & 0xFF00 ) | OR8( ( m_BA & 0x00FF ), RD( addr2 ) ); } + break; + case 0x2C: { AD1_IHL; WR( addr1, OR8( RD( addr1 ), ( m_BA & 0x00FF ) ) ); } + break; + case 0x2D: { AD1_IHL; WR( addr1, OR8( RD( addr1 ), rdop() ) ); } + break; + case 0x2E: { AD1_IHL; AD2_XIX; WR( addr1, OR8( RD( addr1 ), RD( addr2 ) ) ); } + break; + case 0x2F: { AD1_IHL; AD2_YIY; WR( addr1, OR8( RD( addr1 ), RD( addr2 ) ) ); } + break; + + case 0x30: { AD2_X8; SUB8( ( m_BA & 0x00FF ), RD( addr2 ) ); } + break; + case 0x31: { AD2_Y8; SUB8( ( m_BA & 0x00FF ), RD( addr2 ) ); } + break; + case 0x32: { AD2_XL; SUB8( ( m_BA & 0x00FF ), RD( addr2 ) ); } + break; + case 0x33: { AD2_YL; SUB8( ( m_BA & 0x00FF ), RD( addr2 ) ); } + break; + case 0x34: { AD1_IHL; SUB8( RD( addr1 ), ( m_BA & 0x00FF ) ); } + break; + case 0x35: { AD1_IHL; SUB8( RD( addr1 ), rdop() ); } + break; + case 0x36: { AD1_IHL; AD2_XIX; SUB8( RD( addr1 ), RD( addr2 ) ); } + break; + case 0x37: { AD1_IHL; AD2_YIY; SUB8( RD( addr1 ), RD( addr2 ) ); } + break; + case 0x38: { AD2_X8; m_BA = ( m_BA & 0xFF00 ) | XOR8( ( m_BA & 0x00FF ), RD( addr2 ) ); } + break; + case 0x39: { AD2_Y8; m_BA = ( m_BA & 0xFF00 ) | XOR8( ( m_BA & 0x00FF ), RD( addr2 ) ); } + break; + case 0x3A: { AD2_XL; m_BA = ( m_BA & 0xFF00 ) | XOR8( ( m_BA & 0x00FF ), RD( addr2 ) ); } + break; + case 0x3B: { AD2_YL; m_BA = ( m_BA & 0xFF00 ) | XOR8( ( m_BA & 0x00FF ), RD( addr2 ) ); } + break; + case 0x3C: { AD1_IHL; WR( addr1, XOR8( RD( addr1 ), ( m_BA & 0x00FF ) ) ); } + break; + case 0x3D: { AD1_IHL; WR( addr1, XOR8( RD( addr1 ), rdop() ) ); } + break; + case 0x3E: { AD1_IHL; AD2_XIX; WR( addr1, XOR8( RD( addr1 ), RD( addr2 ) ) ); } + break; + case 0x3F: { AD1_IHL; AD2_YIY; WR( addr1, XOR8( RD( addr1 ), RD( addr2 ) ) ); } + break; + + case 0x40: { AD2_X8; m_BA = ( m_BA & 0xFF00 ) | RD( addr2 ); } + break; + case 0x41: { AD2_Y8; m_BA = ( m_BA & 0xFF00 ) | RD( addr2 ); } + break; + case 0x42: { AD2_XL; m_BA = ( m_BA & 0xFF00 ) | RD( addr2 ); } + break; + case 0x43: { AD2_YL; m_BA = ( m_BA & 0xFF00 ) | RD( addr2 ); } + break; + case 0x44: { AD1_X8; WR( addr1, ( m_BA & 0x00FF ) ); } + break; + case 0x45: { AD1_Y8; WR( addr1, ( m_BA & 0x00FF ) ); } + break; + case 0x46: { AD1_XL; WR( addr1, ( m_BA & 0x00FF ) ); } + break; + case 0x47: { AD1_YL; WR( addr1, ( m_BA & 0x00FF ) ); } + break; + case 0x48: { AD2_X8; m_BA = ( m_BA & 0x00FF ) | ( RD( addr2 ) << 8 ); } + break; + case 0x49: { AD2_Y8; m_BA = ( m_BA & 0x00FF ) | ( RD( addr2 ) << 8 ); } + break; + case 0x4A: { AD2_XL; m_BA = ( m_BA & 0x00FF ) | ( RD( addr2 ) << 8 ); } + break; + case 0x4B: { AD2_YL; m_BA = ( m_BA & 0x00FF ) | ( RD( addr2 ) << 8 ); } + break; + case 0x4C: { AD1_X8; WR( addr1, ( m_BA >> 8 ) ); } + break; + case 0x4D: { AD1_Y8; WR( addr1, ( m_BA >> 8 ) ); } + break; + case 0x4E: { AD1_XL; WR( addr1, ( m_BA >> 8 ) ); } + break; + case 0x4F: { AD1_YL; WR( addr1, ( m_BA >> 8 ) ); } + break; + + case 0x50: { AD2_X8; m_HL = ( m_HL & 0xFF00 ) | RD( addr2 ); } + break; + case 0x51: { AD2_Y8; m_HL = ( m_HL & 0xFF00 ) | RD( addr2 ); } + break; + case 0x52: { AD2_XL; m_HL = ( m_HL & 0xFF00 ) | RD( addr2 ); } + break; + case 0x53: { AD2_YL; m_HL = ( m_HL & 0xFF00 ) | RD( addr2 ); } + break; + case 0x54: { AD1_X8; WR( addr1, ( m_HL & 0x00FF ) ); } + break; + case 0x55: { AD1_Y8; WR( addr1, ( m_HL & 0x00FF ) ); } + break; + case 0x56: { AD1_XL; WR( addr1, ( m_HL & 0x00FF ) ); } + break; + case 0x57: { AD1_YL; WR( addr1, ( m_HL & 0x00FF ) ); } + break; + case 0x58: { AD2_X8; m_HL = ( m_HL & 0x00FF ) | ( RD( addr2 ) << 8 ); } + break; + case 0x59: { AD2_Y8; m_HL = ( m_HL & 0x00FF ) | ( RD( addr2 ) << 8 ); } + break; + case 0x5A: { AD2_XL; m_HL = ( m_HL & 0x00FF ) | ( RD( addr2 ) << 8 ); } + break; + case 0x5B: { AD2_YL; m_HL = ( m_HL & 0x00FF ) | ( RD( addr2 ) << 8 ); } + break; + case 0x5C: { AD1_X8; WR( addr1, ( m_HL >> 8 ) ); } + break; + case 0x5D: { AD1_Y8; WR( addr1, ( m_HL >> 8 ) ); } + break; + case 0x5E: { AD1_XL; WR( addr1, ( m_HL >> 8 ) ); } + break; + case 0x5F: { AD1_YL; WR( addr1, ( m_HL >> 8 ) ); } + break; + + case 0x60: { AD1_IHL; AD2_X8; WR( addr1, RD( addr2 ) ); } + break; + case 0x61: { AD1_IHL; AD2_Y8; WR( addr1, RD( addr2 ) ); } + break; + case 0x62: { AD1_IHL; AD2_XL; WR( addr1, RD( addr2 ) ); } + break; + case 0x63: { AD1_IHL; AD2_YL; WR( addr1, RD( addr2 ) ); } + break; + case 0x64: { /* illegal operation? */ } + break; + case 0x65: { /* illegal operation? */ } + break; + case 0x66: { /* illegal operation? */ } + break; + case 0x67: { /* illegal operation? */ } + break; + case 0x68: { AD1_XIX; AD2_X8; WR( addr1, RD( addr2 ) ); } + break; + case 0x69: { AD1_XIX; AD2_Y8; WR( addr1, RD( addr2 ) ); } + break; + case 0x6A: { AD1_XIX; AD2_XL; WR( addr1, RD( addr2 ) ); } + break; + case 0x6B: { AD1_XIX; AD2_YL; WR( addr1, RD( addr2 ) ); } + break; + case 0x6C: { /* illegal operation? */ } + break; + case 0x6D: { /* illegal operation? */ } + break; + case 0x6E: { /* illegal operation? */ } + break; + case 0x6F: { /* illegal operation? */ } + break; + + case 0x70: { /* illegal operation? */ } + break; + case 0x71: { /* illegal operation? */ } + break; + case 0x72: { /* illegal operation? */ } + break; + case 0x73: { /* illegal operation? */ } + break; + case 0x74: { /* illegal operation? */ } + break; + case 0x75: { /* illegal operation? */ } + break; + case 0x76: { /* illegal operation? */ } + break; + case 0x77: { /* illegal operation? */ } + break; + case 0x78: { AD1_YIY; AD2_X8; WR( addr1, RD( addr2 ) ); } + break; + case 0x79: { AD1_YIY; AD2_Y8; WR( addr1, RD( addr2 ) ); } + break; + case 0x7A: { AD1_YIY; AD2_XL; WR( addr1, RD( addr2 ) ); } + break; + case 0x7B: { AD1_YIY; AD2_YL; WR( addr1, RD( addr2 ) ); } + break; + case 0x7C: { /* illegal operation? */ } + break; + case 0x7D: { /* illegal operation? */ } + break; + case 0x7E: { /* illegal operation? */ } + break; + case 0x7F: { /* illegal operation? */ } + break; + + case 0x80: { m_BA = ( m_BA & 0xFF00 ) | SAL8( m_BA & 0x00FF ); } + break; + case 0x81: { m_BA = ( m_BA & 0x00FF ) | ( SAL8( m_BA >> 8 )<< 8 ); } + break; + case 0x82: { AD1_IN8; WR( addr1, SAL8( RD( addr1 ) ) ); } + break; + case 0x83: { AD1_IHL; WR( addr1, SAL8( RD( addr1 ) ) ); } + break; + case 0x84: { m_BA = ( m_BA & 0xFF00 ) | SHL8( m_BA & 0x00FF ); } + break; + case 0x85: { m_BA = ( m_BA & 0x00FF ) | ( SHL8( m_BA >> 8 ) << 8 ); } + break; + case 0x86: { AD1_IN8; WR( addr1, SHL8( RD( addr1 ) ) ); } + break; + case 0x87: { AD1_IHL; WR( addr1, SHL8( RD( addr1 ) ) ); } + break; + case 0x88: { m_BA = ( m_BA & 0xFF00 ) | SAR8( m_BA & 0x00FF ); } + break; + case 0x89: { m_BA = ( m_BA & 0x00FF ) | ( SAR8( m_BA >> 8 ) << 8 ); } + break; + case 0x8A: { AD1_IN8; WR( addr1, SAR8( RD( addr1 ) ) ); } + break; + case 0x8B: { AD1_IHL; WR( addr1, SAR8( RD( addr1 ) ) ); } + break; + case 0x8C: { m_BA = ( m_BA & 0xFF00 ) | SHR8( m_BA & 0x00FF ); } + break; + case 0x8D: { m_BA = ( m_BA & 0x00FF ) | ( SHR8( m_BA >> 8 ) << 8 ); } + break; + case 0x8E: { AD1_IN8; WR( addr1, SHR8( RD( addr1 ) ) ); } + break; + case 0x8F: { AD1_IHL; WR( addr1, SHR8( RD( addr1 ) ) ); } + break; + + case 0x90: { m_BA = ( m_BA & 0xFF00 ) | ROLC8( m_BA & 0x00FF ); } + break; + case 0x91: { m_BA = ( m_BA & 0x00FF ) | ( ROLC8( m_BA >> 8 ) << 8 ); } + break; + case 0x92: { AD1_IN8; WR( addr1, ROLC8( RD( addr1 ) ) ); } + break; + case 0x93: { AD1_IHL; WR( addr1, ROLC8( RD( addr1 ) ) ); } + break; + case 0x94: { m_BA = ( m_BA & 0xFF00 ) | ROL8( m_BA & 0x00FF ); } + break; + case 0x95: { m_BA = ( m_BA & 0x00FF ) | ( ROL8( m_BA >> 8 ) << 8 ); } + break; + case 0x96: { AD1_IN8; WR( addr1, ROL8( RD( addr1 ) ) ); } + break; + case 0x97: { AD1_IHL; WR( addr1, ROL8( RD( addr1 ) ) ); } + break; + case 0x98: { m_BA = ( m_BA & 0xFF00 ) | RORC8( m_BA & 0x00FF ); } + break; + case 0x99: { m_BA = ( m_BA & 0x00FF ) | ( RORC8( m_BA >> 8 ) << 8 ); } + break; + case 0x9A: { AD1_IN8; WR( addr1, RORC8( RD( addr1 ) ) ); } + break; + case 0x9B: { AD1_IHL; WR( addr1, RORC8( RD( addr1 ) ) ); } + break; + case 0x9C: { m_BA = ( m_BA & 0xFF00 ) | ROR8( m_BA & 0x00FF ); } + break; + case 0x9D: { m_BA = ( m_BA & 0x00FF ) | ( ROR8( m_BA >> 8 ) << 8 ); } + break; + case 0x9E: { AD1_IN8; WR( addr1, ROR8( RD( addr1 ) ) ); } + break; + case 0x9F: { AD1_IHL; WR( addr1, ROR8( RD( addr1 ) ) ); } + break; + + case 0xA0: { m_BA = ( m_BA & 0xFF00 ) | NOT8( m_BA & 0x00FF ); } + break; + case 0xA1: { m_BA = ( m_BA & 0x00FF ) | ( NOT8( m_BA >> 8 ) << 8 ); } + break; + case 0xA2: { AD1_IN8; WR( addr1, NOT8( RD( addr1 ) ) ); } + break; + case 0xA3: { AD1_IHL; WR( addr1, NOT8( RD( addr1 ) ) ); } + break; + case 0xA4: { m_BA = ( m_BA & 0xFF00 ) | NEG8( m_BA & 0x00FF ); } + break; + case 0xA5: { m_BA = ( m_BA & 0x00FF ) | ( NEG8( m_BA >> 8 ) << 8 ); } + break; + case 0xA6: { AD1_IN8; WR( addr1, NEG8( RD( addr1 ) ) ); } + break; + case 0xA7: { AD1_IHL; WR( addr1, NEG8( RD( addr1 ) ) ); } + break; + case 0xA8: { m_BA = ( ( m_BA & 0x0080 ) ? ( 0xFF00 | m_BA ) : ( m_BA & 0x00FF ) ); } + break; + case 0xA9: { /* illegal operation? */ } + break; + case 0xAA: { /* illegal operation? */ } + break; + case 0xAB: { /* illegal operation? */ } + break; + case 0xAC: { /* illegal operation? */ } + break; + case 0xAD: { /* illegal operation? */ } + break; + case 0xAE: { /* HALT */ m_halted = 1; } + break; + case 0xAF: { } + break; + + case 0xB0: { m_BA = ( m_BA & 0x00FF ) | ( AND8( ( m_BA >> 8 ), rdop() ) << 8 ); } + break; + case 0xB1: { m_HL = ( m_HL & 0xFF00 ) | AND8( ( m_HL & 0x00FF ), rdop() ); } + break; + case 0xB2: { m_HL = ( m_HL & 0x00FF ) | ( AND8( ( m_HL >> 8 ), rdop() ) << 8 ); } + break; + case 0xB3: { /* illegal operation? */ } + break; + case 0xB4: { m_BA = ( m_BA & 0x00FF ) | ( OR8( ( m_BA >> 8 ), rdop() ) << 8 ); } + break; + case 0xB5: { m_HL = ( m_HL & 0xFF00 ) | OR8( ( m_HL & 0x00FF ), rdop() ); } + break; + case 0xB6: { m_HL = ( m_HL & 0x00FF ) | ( OR8( ( m_HL >> 8 ), rdop() ) << 8 ); } + break; + case 0xB7: { /* illegal operation? */ } + break; + case 0xB8: { m_BA = ( m_BA & 0x00FF ) | ( XOR8( ( m_BA >> 8 ), rdop() ) << 8 ); } + break; + case 0xB9: { m_HL = ( m_HL & 0xFF00 ) | XOR8( ( m_HL & 0x00FF ), rdop() ); } + break; + case 0xBA: { m_HL = ( m_HL & 0x00FF ) | ( XOR8( ( m_HL >> 8 ), rdop() ) << 8 ); } + break; + case 0xBB: { /* illegal operation? */ } + break; + case 0xBC: { SUB8( ( m_BA >> 8 ), rdop() ); } + break; + case 0xBD: { SUB8( ( m_HL & 0x00FF), rdop() ); } + break; + case 0xBE: { SUB8( ( m_HL >> 8 ), rdop() ); } + break; + case 0xBF: { SUB8( m_N, rdop() ); } + break; + + case 0xC0: { m_BA = ( m_BA & 0xFF00 ) | m_N; } + break; + case 0xC1: { m_BA = ( m_BA & 0xFF00 ) | m_F; } + break; + case 0xC2: { m_N = ( m_BA & 0x00FF ); } + break; + case 0xC3: { m_F = ( m_BA & 0x00FF ); } + break; + case 0xC4: { m_U = rdop(); } + break; + case 0xC5: { m_I = rdop(); } + break; + case 0xC6: { m_XI = rdop(); } + break; + case 0xC7: { m_YI = rdop(); } + break; + case 0xC8: { m_BA = ( m_BA & 0xFF00 ) | m_V; } + break; + case 0xC9: { m_BA = ( m_BA & 0xFF00 ) | m_I; } + break; + case 0xCA: { m_BA = ( m_BA & 0xFF00 ) | m_XI; } + break; + case 0xCB: { m_BA = ( m_BA & 0xFF00 ) | m_YI; } + break; + case 0xCC: { m_U = ( m_BA & 0x00FF ); } + break; + case 0xCD: { m_I = ( m_BA & 0x00FF ); } + break; + case 0xCE: { m_XI = ( m_BA & 0x00FF ); } + break; + case 0xCF: { m_YI = ( m_BA & 0x00FF ); } + break; + + case 0xD0: { AD2_I16; m_BA = ( m_BA & 0xFF00 ) | RD( addr2 ); } + break; + case 0xD1: { AD2_I16; m_BA = ( m_BA & 0x00FF ) | ( RD( addr2 ) << 8 ); } + break; + case 0xD2: { AD2_I16; m_HL = ( m_HL & 0xFF00 ) | RD( addr2 ); } + break; + case 0xD3: { AD2_I16; m_HL = ( m_HL & 0x00FF ) | ( RD( addr2 ) << 8 ); } + break; + case 0xD4: { AD1_I16; WR( addr1, ( m_BA & 0x00FF ) ); } + break; + case 0xD5: { AD1_I16; WR( addr1, ( m_BA >> 8 ) ); } + break; + case 0xD6: { AD1_I16; WR( addr1, ( m_HL & 0x00FF ) ); } + break; + case 0xD7: { AD1_I16; WR( addr1, ( m_HL >> 8 ) ); } + break; + case 0xD8: { m_HL = ( m_HL & 0x00FF ) * ( m_BA & 0x00FF ); } + break; + case 0xD9: { int d = m_HL / ( m_BA & 0x00FF ); m_HL = ( ( m_HL - ( ( m_BA & 0x00FF ) * d ) ) << 8 ) | d; } + break; + case 0xDA: { /* illegal operation? */ } + break; + case 0xDB: { /* illegal operation? */ } + break; + case 0xDC: { /* illegal operation? */ } + break; + case 0xDD: { /* illegal operation? */ } + break; + case 0xDE: { /* illegal operation? */ } + break; + case 0xDF: { /* illegal operation? */ } + break; + + case 0xE0: { INT8 d8 = rdop(); if ( ( ( m_F & ( FLAG_S | FLAG_O ) ) == FLAG_S ) || ( ( m_F & ( FLAG_S | FLAG_O ) ) == FLAG_O ) ) { JMP( m_PC + d8 - 1 ); } } + break; + case 0xE1: { INT8 d8 = rdop(); if ( ( m_F & FLAG_Z ) || ( ( m_F & ( FLAG_S | FLAG_O ) ) == FLAG_S ) || ( ( m_F & ( FLAG_S | FLAG_O ) ) == FLAG_O ) ) { JMP( m_PC + d8 - 1 ); } } + break; + case 0xE2: { INT8 d8 = rdop(); if ( !( m_F & FLAG_Z ) && ( ( ( m_F & ( FLAG_S | FLAG_O ) ) == 0 ) || ( ( m_F & ( FLAG_S | FLAG_O ) ) == ( FLAG_S | FLAG_O ) ) ) ) { JMP( m_PC + d8 - 1 ); } } + break; + case 0xE3: { INT8 d8 = rdop(); if ( ( ( m_F & ( FLAG_S | FLAG_O ) ) == 0 ) || ( ( m_F & ( FLAG_S | FLAG_O ) ) == ( FLAG_S | FLAG_O ) ) ) { JMP( m_PC + d8 - 1 ); } } + break; + case 0xE4: { INT8 d8 = rdop(); if ( ( m_F & FLAG_O ) ) { JMP( m_PC + d8 - 1 ); } } + break; + case 0xE5: { INT8 d8 = rdop(); if ( ! ( m_F & FLAG_O ) ) { JMP( m_PC + d8 - 1 ); } } + break; + case 0xE6: { INT8 d8 = rdop(); if ( ! ( m_F & FLAG_S ) ) { JMP( m_PC + d8 - 1 ); } } + break; + case 0xE7: { INT8 d8 = rdop(); if ( ( m_F & FLAG_S ) ) { JMP( m_PC + d8 - 1 ); } } + break; + case 0xE8: { INT8 d8 = rdop(); if ( ! ( m_E & EXEC_X0 ) ) { JMP( m_PC + d8 - 1 ); } } + break; + case 0xE9: { INT8 d8 = rdop(); if ( ! ( m_E & EXEC_X1 ) ) { JMP( m_PC + d8 - 1 ); } } + break; + case 0xEA: { INT8 d8 = rdop(); if ( ! ( m_E & EXEC_X2 ) ) { JMP( m_PC + d8 - 1 ); } } + break; + case 0xEB: { INT8 d8 = rdop(); if ( ! ( m_E & EXEC_DZ ) ) { JMP( m_PC + d8 - 1 ); } } + break; + case 0xEC: { INT8 d8 = rdop(); if ( ( m_E & EXEC_X0 ) ) { JMP( m_PC + d8 - 1 ); } } + break; + case 0xED: { INT8 d8 = rdop(); if ( ( m_E & EXEC_X1 ) ) { JMP( m_PC + d8 - 1 ); } } + break; + case 0xEE: { INT8 d8 = rdop(); if ( ( m_E & EXEC_X2 ) ) { JMP( m_PC + d8 - 1 ); } } + break; + case 0xEF: { INT8 d8 = rdop(); if ( ( m_E & EXEC_DZ ) ) { JMP( m_PC + d8 - 1 ); } } + break; + + case 0xF0: { INT8 d8 = rdop(); if ( ( ( m_F & ( FLAG_S | FLAG_O ) ) == FLAG_S ) || ( ( m_F & ( FLAG_S | FLAG_O ) ) == FLAG_O ) ) { CALL( m_PC + d8 - 1 ); m_icount -= 12; } } + break; + case 0xF1: { INT8 d8 = rdop(); if ( ( m_F & FLAG_Z ) || ( ( m_F & ( FLAG_S | FLAG_O ) ) == FLAG_S ) || ( ( m_F & ( FLAG_S | FLAG_O ) ) == FLAG_O ) ) { CALL( m_PC + d8 - 1 ); m_icount -= 12; } } + break; + case 0xF2: { INT8 d8 = rdop(); if ( !( m_F & FLAG_Z ) && ( ( ( m_F & ( FLAG_S | FLAG_O ) ) == 0 ) || ( ( m_F & ( FLAG_S | FLAG_O ) ) == ( FLAG_S | FLAG_O ) ) ) ) { CALL( m_PC + d8 - 1 ); m_icount -= 12; } } + break; + case 0xF3: { INT8 d8 = rdop(); if ( ( ( m_F & ( FLAG_S | FLAG_O ) ) == 0 ) || ( ( m_F & ( FLAG_S | FLAG_O ) ) == ( FLAG_S | FLAG_O ) ) ) { CALL( m_PC + d8 - 1 ); } } + break; + case 0xF4: { INT8 d8 = rdop(); if ( ( m_F & FLAG_O ) ) { CALL( m_PC + d8 - 1 ); m_icount -= 12; } } + break; + case 0xF5: { INT8 d8 = rdop(); if ( ! ( m_F & FLAG_O ) ) { CALL( m_PC + d8 - 1 ); m_icount -= 12; } } + break; + case 0xF6: { INT8 d8 = rdop(); if ( ! ( m_F & FLAG_S ) ) { CALL( m_PC + d8 - 1 ); m_icount -= 12; } } + break; + case 0xF7: { INT8 d8 = rdop(); if ( ( m_F & FLAG_S ) ) { CALL( m_PC + d8 - 1 ); m_icount -= 12; } } + break; + case 0xF8: { INT8 d8 = rdop(); if ( ! ( m_E & EXEC_X0 ) ) { CALL( m_PC + d8 - 1 ); m_icount -= 12; } } + break; + case 0xF9: { INT8 d8 = rdop(); if ( ! ( m_E & EXEC_X1 ) ) { CALL( m_PC + d8 - 1 ); m_icount -= 12; } } + break; + case 0xFA: { INT8 d8 = rdop(); if ( ! ( m_E & EXEC_X2 ) ) { CALL( m_PC + d8 - 1 ); m_icount -= 12; } } + break; + case 0xFB: { INT8 d8 = rdop(); if ( ! ( m_E & EXEC_DZ ) ) { CALL( m_PC + d8 - 1 ); m_icount -= 12; } } + break; + case 0xFC: { INT8 d8 = rdop(); if ( ( m_E & EXEC_X0 ) ) { CALL( m_PC + d8 - 1 ); m_icount -= 12; } } + break; + case 0xFD: { INT8 d8 = rdop(); if ( ( m_E & EXEC_X1 ) ) { CALL( m_PC + d8 - 1 ); m_icount -= 12; } } + break; + case 0xFE: { INT8 d8 = rdop(); if ( ( m_E & EXEC_X2 ) ) { CALL( m_PC + d8 - 1 ); m_icount -= 12; } } + break; + case 0xFF: { INT8 d8 = rdop(); if ( ( m_E & EXEC_DZ ) ) { CALL( m_PC + d8 - 1 ); m_icount -= 12; } } + break; + } + + m_icount -= insnminx_cycles_CE[opcode]; +} + + +const int minx_cpu_device::insnminx_cycles_CE[256] = { + 16, 16, 16, 16, 16, 20, 20, 20, 16, 16, 16, 16, 16, 20, 20, 20, + 16, 16, 16, 16, 16, 20, 20, 20, 16, 16, 16, 16, 16, 20, 20, 20, + 16, 16, 16, 16, 16, 20, 20, 20, 16, 16, 16, 16, 16, 20, 20, 20, + 16, 16, 16, 16, 16, 20, 20, 20, 16, 16, 16, 16, 16, 20, 20, 20, + + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 20, 20, 20, 20, 1, 1, 1, 1, 20, 20, 20, 20, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 20, 20, 20, 20, 1, 1, 1, 1, + + 12, 12, 20, 16, 12, 12, 20, 16, 12, 12, 20, 16, 12, 12, 20, 16, + 12, 12, 20, 16, 12, 12, 20, 16, 12, 12, 20, 16, 12, 12, 20, 16, + 12, 12, 20, 16, 12, 12, 20, 16, 12, 1, 1, 1, 1, 1, 8, 8, + 12, 12, 12, 1, 12, 12, 12, 1, 20, 20, 20, 20, 12, 12, 12, 1, + + 8, 8, 8, 12, 16, 12, 12, 12, 8, 8, 8, 8, 12, 8, 8, 8, + 20, 20, 20, 20, 20, 20, 20, 20, 48, 52, 1, 1, 1, 1, 1, 1, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12 +}; diff --git a/src/devices/cpu/minx/minxopcf.h b/src/devices/cpu/minx/minxopcf.h new file mode 100644 index 00000000000..f81d991304a --- /dev/null +++ b/src/devices/cpu/minx/minxopcf.h @@ -0,0 +1,563 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol + +void minx_cpu_device::execute_one_cf() +{ + const UINT8 opcode = rdop(); + + switch (opcode) + { + case 0x00: { m_BA = ADD16( m_BA, m_BA ); } + break; + case 0x01: { m_BA = ADD16( m_BA, m_HL ); } + break; + case 0x02: { m_BA = ADD16( m_BA, m_X ); } + break; + case 0x03: { m_BA = ADD16( m_BA, m_Y ); } + break; + case 0x04: { m_BA = ADDC16( m_BA, m_BA ); } + break; + case 0x05: { m_BA = ADDC16( m_BA, m_HL ); } + break; + case 0x06: { m_BA = ADDC16( m_BA, m_X ); } + break; + case 0x07: { m_BA = ADDC16( m_BA, m_Y ); } + break; + case 0x08: { m_BA = SUB16( m_BA, m_BA ); } + break; + case 0x09: { m_BA = SUB16( m_BA, m_HL ); } + break; + case 0x0A: { m_BA = SUB16( m_BA, m_X ); } + break; + case 0x0B: { m_BA = SUB16( m_BA, m_Y ); } + break; + case 0x0C: { m_BA = SUBC16( m_BA, m_BA ); } + break; + case 0x0D: { m_BA = SUBC16( m_BA, m_HL ); } + break; + case 0x0E: { m_BA = SUBC16( m_BA, m_X ); } + break; + case 0x0F: { m_BA = SUBC16( m_BA, m_Y ); } + break; + + case 0x10: { /* illegal instruction? */ } + break; + case 0x11: { /* illegal instruction? */ } + break; + case 0x12: { /* illegal instruction? */ } + break; + case 0x13: { /* illegal instruction? */ } + break; + case 0x14: { /* illegal instruction? */ } + break; + case 0x15: { /* illegal instruction? */ } + break; + case 0x16: { /* illegal instruction? */ } + break; + case 0x17: { /* illegal instruction? */ } + break; + case 0x18: { SUB16( m_BA, m_BA ); } + break; + case 0x19: { SUB16( m_BA, m_HL ); } + break; + case 0x1A: { SUB16( m_BA, m_X ); } + break; + case 0x1B: { SUB16( m_BA, m_Y ); } + break; + case 0x1C: { /* illegal instruction? */ } + break; + case 0x1D: { /* illegal instruction? */ } + break; + case 0x1E: { /* illegal instruction? */ } + break; + case 0x1F: { /* illegal instruction? */ } + break; + + case 0x20: { m_HL = ADD16( m_HL, m_BA ); } + break; + case 0x21: { m_HL = ADD16( m_HL, m_HL ); } + break; + case 0x22: { m_HL = ADD16( m_HL, m_X ); } + break; + case 0x23: { m_HL = ADD16( m_HL, m_Y ); } + break; + case 0x24: { m_HL = ADDC16( m_HL, m_BA ); } + break; + case 0x25: { m_HL = ADDC16( m_HL, m_HL ); } + break; + case 0x26: { m_HL = ADDC16( m_HL, m_X ); } + break; + case 0x27: { m_HL = ADDC16( m_HL, m_Y ); } + break; + case 0x28: { m_HL = SUB16( m_HL, m_BA ); } + break; + case 0x29: { m_HL = SUB16( m_HL, m_HL ); } + break; + case 0x2A: { m_HL = SUB16( m_HL, m_X ); } + break; + case 0x2B: { m_HL = SUB16( m_HL, m_Y ); } + break; + case 0x2C: { m_HL = SUBC16( m_HL, m_BA ); } + break; + case 0x2D: { m_HL = SUBC16( m_HL, m_HL ); } + break; + case 0x2E: { m_HL = SUBC16( m_HL, m_X ); } + break; + case 0x2F: { m_HL = SUBC16( m_HL, m_Y ); } + break; + + case 0x30: { /* illegal instruction? */ } + break; + case 0x31: { /* illegal instruction? */ } + break; + case 0x32: { /* illegal instruction? */ } + break; + case 0x33: { /* illegal instruction? */ } + break; + case 0x34: { /* illegal instruction? */ } + break; + case 0x35: { /* illegal instruction? */ } + break; + case 0x36: { /* illegal instruction? */ } + break; + case 0x37: { /* illegal instruction? */ } + break; + case 0x38: { SUB16( m_HL, m_BA ); } + break; + case 0x39: { SUB16( m_HL, m_HL ); } + break; + case 0x3A: { SUB16( m_HL, m_X ); } + break; + case 0x3B: { SUB16( m_HL, m_Y ); } + break; + case 0x3C: { /* illegal instruction? */ } + break; + case 0x3D: { /* illegal instruction? */ } + break; + case 0x3E: { /* illegal instruction? */ } + break; + case 0x3F: { /* illegal instruction? */ } + break; + + case 0x40: { m_X = ADD16( m_X, m_BA ); } + break; + case 0x41: { m_X = ADD16( m_X, m_HL ); } + break; + case 0x42: { m_Y = ADD16( m_Y, m_BA ); } + break; + case 0x43: { m_Y = ADD16( m_Y, m_HL ); } + break; + case 0x44: { m_SP = ADD16( m_SP, m_BA ); } + break; + case 0x45: { m_SP = ADD16( m_SP, m_HL ); } + break; + case 0x46: { /* illegal instruction? */ } + break; + case 0x47: { /* illegal instruction? */ } + break; + case 0x48: { m_X = SUB16( m_X, m_BA ); } + break; + case 0x49: { m_X = SUB16( m_X, m_HL ); } + break; + case 0x4A: { m_Y = SUB16( m_Y, m_BA ); } + break; + case 0x4B: { m_Y = SUB16( m_Y, m_HL ); } + break; + case 0x4C: { m_SP = SUB16( m_SP, m_BA ); } + break; + case 0x4D: { m_SP = SUB16( m_SP, m_HL ); } + break; + case 0x4E: { /* illegal instruction? */ } + break; + case 0x4F: { /* illegal instruction? */ } + break; + + case 0x50: { /* illegal instruction? */ } + break; + case 0x51: { /* illegal instruction? */ } + break; + case 0x52: { /* illegal instruction? */ } + break; + case 0x53: { /* illegal instruction? */ } + break; + case 0x54: { /* illegal instruction? */ } + break; + case 0x55: { /* illegal instruction? */ } + break; + case 0x56: { /* illegal instruction? */ } + break; + case 0x57: { /* illegal instruction? */ } + break; + case 0x58: { /* illegal instruction? */ } + break; + case 0x59: { /* illegal instruction? */ } + break; + case 0x5A: { /* illegal instruction? */ } + break; + case 0x5B: { /* illegal instruction? */ } + break; + case 0x5C: { SUB16( m_SP, m_BA ); } + break; + case 0x5D: { SUB16( m_SP, m_HL ); } + break; + case 0x5E: { /* illegal instruction? */ } + break; + case 0x5F: { /* illegal instruction? */ } + break; + + case 0x60: { ADDC16( m_BA, rdop16() ); /* ??? */ } + break; + case 0x61: { ADDC16( m_HL, rdop16() ); /* ??? */ } + break; + case 0x62: { ADDC16( m_X, rdop16() ); /* ??? */ } + break; + case 0x63: { ADDC16( m_Y, rdop16() ); /* ??? */ } + break; + case 0x64: { /* illegal instruction? */ } + break; + case 0x65: { /* illegal instruction? */ } + break; + case 0x66: { /* illegal instruction? */ } + break; + case 0x67: { /* illegal instruction? */ } + break; + case 0x68: { m_SP = ADD16( m_SP, rdop16() ); } + break; + case 0x69: { /* illegal instruction? */ } + break; + case 0x6A: { m_SP = SUB16( m_SP, rdop16() ); } + break; + case 0x6B: { /* illegal instruction? */ } + break; + case 0x6C: { SUB16( m_SP, rdop16() ); } + break; + case 0x6D: { /* illegal instruction? */ } + break; + case 0x6E: { m_SP = rdop16(); } + break; + case 0x6F: { /* illegal instruction? */ } + break; + + case 0x70: { UINT8 ofs8 = rdop(); m_BA = rd16( m_SP + ofs8 ); } + break; + case 0x71: { UINT8 ofs8 = rdop(); m_HL = rd16( m_SP + ofs8 ); } + break; + case 0x72: { UINT8 ofs8 = rdop(); m_X = rd16( m_SP + ofs8 ); } + break; + case 0x73: { UINT8 ofs8 = rdop(); m_Y = rd16( m_SP + ofs8 ); } + break; + case 0x74: { UINT8 ofs8 = rdop(); wr16( m_SP + ofs8, m_BA ); } + break; + case 0x75: { UINT8 ofs8 = rdop(); wr16( m_SP + ofs8, m_HL ); } + break; + case 0x76: { UINT8 ofs8 = rdop(); wr16( m_SP + ofs8, m_X ); } + break; + case 0x77: { UINT8 ofs8 = rdop(); wr16( m_SP + ofs8, m_Y ); } + break; + case 0x78: { AD2_I16; m_SP = rd16( addr2 ); } + break; + case 0x79: { /* illegal instruction? */ } + break; + case 0x7A: { /* illegal instruction? */ } + break; + case 0x7B: { /* illegal instruction? */ } + break; + case 0x7C: { AD1_I16; wr16( addr1, m_SP ); } + break; + case 0x7D: { /* illegal instruction? */ } + break; + case 0x7E: { /* illegal instruction? */ } + break; + case 0x7F: { /* illegal instruction? */ } + break; + + case 0x80: { /* illegal instruction? */ } + break; + case 0x81: { /* illegal instruction? */ } + break; + case 0x82: { /* illegal instruction? */ } + break; + case 0x83: { /* illegal instruction? */ } + break; + case 0x84: { /* illegal instruction? */ } + break; + case 0x85: { /* illegal instruction? */ } + break; + case 0x86: { /* illegal instruction? */ } + break; + case 0x87: { /* illegal instruction? */ } + break; + case 0x88: { /* illegal instruction? */ } + break; + case 0x89: { /* illegal instruction? */ } + break; + case 0x8A: { /* illegal instruction? */ } + break; + case 0x8B: { /* illegal instruction? */ } + break; + case 0x8C: { /* illegal instruction? */ } + break; + case 0x8D: { /* illegal instruction? */ } + break; + case 0x8E: { /* illegal instruction? */ } + break; + case 0x8F: { /* illegal instruction? */ } + break; + + case 0x90: { /* illegal instruction? */ } + break; + case 0x91: { /* illegal instruction? */ } + break; + case 0x92: { /* illegal instruction? */ } + break; + case 0x93: { /* illegal instruction? */ } + break; + case 0x94: { /* illegal instruction? */ } + break; + case 0x95: { /* illegal instruction? */ } + break; + case 0x96: { /* illegal instruction? */ } + break; + case 0x97: { /* illegal instruction? */ } + break; + case 0x98: { /* illegal instruction? */ } + break; + case 0x99: { /* illegal instruction? */ } + break; + case 0x9A: { /* illegal instruction? */ } + break; + case 0x9B: { /* illegal instruction? */ } + break; + case 0x9C: { /* illegal instruction? */ } + break; + case 0x9D: { /* illegal instruction? */ } + break; + case 0x9E: { /* illegal instruction? */ } + break; + case 0x9F: { /* illegal instruction? */ } + break; + + case 0xA0: { /* illegal instruction? */ } + break; + case 0xA1: { /* illegal instruction? */ } + break; + case 0xA2: { /* illegal instruction? */ } + break; + case 0xA3: { /* illegal instruction? */ } + break; + case 0xA4: { /* illegal instruction? */ } + break; + case 0xA5: { /* illegal instruction? */ } + break; + case 0xA6: { /* illegal instruction? */ } + break; + case 0xA7: { /* illegal instruction? */ } + break; + case 0xA8: { /* illegal instruction? */ } + break; + case 0xA9: { /* illegal instruction? */ } + break; + case 0xAA: { /* illegal instruction? */ } + break; + case 0xAB: { /* illegal instruction? */ } + break; + case 0xAC: { /* illegal instruction? */ } + break; + case 0xAD: { /* illegal instruction? */ } + break; + case 0xAE: { /* illegal instruction? */ } + break; + case 0xAF: { /* illegal instruction? */ } + break; + + case 0xB0: { PUSH8( m_BA & 0x00FF ); } + break; + case 0xB1: { PUSH8( m_BA >> 8 ); } + break; + case 0xB2: { PUSH8( m_HL & 0x00FF ); } + break; + case 0xB3: { PUSH8( m_HL >> 8 ); } + break; + case 0xB4: { m_BA = ( m_BA & 0xFF00 ) | POP8(); } + break; + case 0xB5: { m_BA = ( m_BA & 0x00FF ) | ( POP8() << 8 ); } + break; + case 0xB6: { m_HL = ( m_HL & 0xFF00 ) | POP8(); } + break; + case 0xB7: { m_HL = ( m_HL & 0x00FF ) | ( POP8() << 8 ); } + break; + case 0xB8: { PUSH16( m_BA ); PUSH16( m_HL ); PUSH16( m_X ); PUSH16( m_Y ); PUSH8( m_N ); } + break; + case 0xB9: { PUSH16( m_BA ); PUSH16( m_HL ); PUSH16( m_X ); PUSH16( m_Y ); PUSH8( m_N ); PUSH8( m_I ); PUSH8( m_XI ); PUSH8( m_YI ); } + break; + case 0xBA: { /* illegal instruction? */ } + break; + case 0xBB: { /* illegal instruction? */ } + break; + case 0xBC: { m_N = POP8(); m_Y = POP16(); m_X = POP16(); m_HL = POP16(); m_BA = POP16(); } + break; + case 0xBD: { m_YI = POP8(); m_XI = POP8(); m_I = POP8(); m_N = POP8(); m_Y = POP16(); m_X = POP16(); m_HL = POP16(); m_BA = POP16(); } + break; + case 0xBE: { /* illegal instruction? */ } + break; + case 0xBF: { /* illegal instruction? */ } + break; + + case 0xC0: { AD2_IHL; m_BA = rd16( addr2 ); } + break; + case 0xC1: { AD2_IHL; m_HL = rd16( addr2 ); } + break; + case 0xC2: { AD2_IHL; m_X = rd16( addr2 ); } + break; + case 0xC3: { AD2_IHL; m_Y = rd16( addr2 ); } + break; + case 0xC4: { AD1_IHL; wr16( addr1, m_BA ); } + break; + case 0xC5: { AD1_IHL; wr16( addr1, m_HL ); } + break; + case 0xC6: { AD1_IHL; wr16( addr1, m_X ); } + break; + case 0xC7: { AD1_IHL; wr16( addr1, m_Y ); } + break; + case 0xC8: { /* illegal instruction? */ } + break; + case 0xC9: { /* illegal instruction? */ } + break; + case 0xCA: { /* illegal instruction? */ } + break; + case 0xCB: { /* illegal instruction? */ } + break; + case 0xCC: { /* illegal instruction? */ } + break; + case 0xCD: { /* illegal instruction? */ } + break; + case 0xCE: { /* illegal instruction? */ } + break; + case 0xCF: { /* illegal instruction? */ } + break; + + case 0xD0: { AD2_XIX; m_BA = rd16( addr2 ); } + break; + case 0xD1: { AD2_XIX; m_HL = rd16( addr2 ); } + break; + case 0xD2: { AD2_XIX; m_X = rd16( addr2 ); } + break; + case 0xD3: { AD2_XIX; m_Y = rd16( addr2 ); } + break; + case 0xD4: { AD1_XIX; wr16( addr1, m_BA ); } + break; + case 0xD5: { AD1_XIX; wr16( addr1, m_HL ); } + break; + case 0xD6: { AD1_XIX; wr16( addr1, m_X ); } + break; + case 0xD7: { AD1_XIX; wr16( addr1, m_Y ); } + break; + case 0xD8: { AD2_YIY; m_BA = rd16( addr2 ); } + break; + case 0xD9: { AD2_YIY; m_HL = rd16( addr2 ); } + break; + case 0xDA: { AD2_YIY; m_X = rd16( addr2 ); } + break; + case 0xDB: { AD2_YIY; m_Y = rd16( addr2 ); } + break; + case 0xDC: { AD1_YIY; wr16( addr1, m_BA ); } + break; + case 0xDD: { AD1_YIY; wr16( addr1, m_HL ); } + break; + case 0xDE: { AD1_YIY; wr16( addr1, m_X ); } + break; + case 0xDF: { AD1_YIY; wr16( addr1, m_Y ); } + break; + + case 0xE0: { } //{ m_BA = m_BA; } + break; + case 0xE1: { m_BA = m_HL; } + break; + case 0xE2: { m_BA = m_X; } + break; + case 0xE3: { m_BA = m_Y; } + break; + case 0xE4: { m_HL = m_BA; } + break; + case 0xE5: { } //{ m_HL = m_HL; } + break; + case 0xE6: { m_HL = m_X; } + break; + case 0xE7: { m_HL = m_Y; } + break; + case 0xE8: { m_X = m_BA; } + break; + case 0xE9: { m_X = m_HL; } + break; + case 0xEA: { } //{ m_X = m_X; } + break; + case 0xEB: { m_X = m_Y; } + break; + case 0xEC: { m_Y = m_BA; } + break; + case 0xED: { m_Y = m_HL; } + break; + case 0xEE: { m_Y = m_X; } + break; + case 0xEF: { } //{ m_Y = m_Y; } + break; + + case 0xF0: { m_SP = m_BA; } + break; + case 0xF1: { m_SP = m_HL; } + break; + case 0xF2: { m_SP = m_X; } + break; + case 0xF3: { m_SP = m_Y; } + break; + case 0xF4: { m_HL = m_SP; } + break; + case 0xF5: { m_HL = m_PC; } + break; + case 0xF6: { /* illegal instruction? */ } + break; + case 0xF7: { /* illegal instruction? */ } + break; + case 0xF8: { m_BA = m_SP; } + break; + case 0xF9: { m_BA = m_PC; } + break; + case 0xFA: { m_X = m_SP; } + break; + case 0xFB: { /* illegal instruction? */ } + break; + case 0xFC: { /* illegal instruction? */ } + break; + case 0xFD: { /* illegal instruction? */ } + break; + case 0xFE: { m_Y = m_SP; } + break; + case 0xFF: { /* illegal instruction? */ } + break; + } + + m_icount -= insnminx_cycles_CF[opcode]; +} + + +const int minx_cpu_device::insnminx_cycles_CF[256] = { + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 1, 1, 1, 1, 1, 1, 1, 1, 16, 16, 16, 16, 1, 1, 1, 1, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 1, 1, 1, 1, 1, 1, 1, 1, 16, 16, 16, 16, 1, 1, 1, 1, + + 16, 16, 16, 16, 16, 16, 1, 1, 16, 16, 16, 16, 16, 16, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 16, 1, 1, + 16, 16, 16, 16, 1, 1, 1, 1, 16, 1, 16, 1, 16, 1, 16, 1, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 1, 1, 1, 24, 1, 1, 1, + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 12, 12, 12, 12, 12, 12, 12, 12, 48, 60, 1, 1, 32, 40, 1, 1, + + 20, 20, 20, 20, 20, 20, 20, 20, 1, 1, 1, 1, 1, 1, 1, 1, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 1, 1, 8, 8, 8, 1, 1, 1, 8, 1 +}; diff --git a/src/devices/cpu/minx/minxops.h b/src/devices/cpu/minx/minxops.h new file mode 100644 index 00000000000..b19e733deb2 --- /dev/null +++ b/src/devices/cpu/minx/minxops.h @@ -0,0 +1,563 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol + +void minx_cpu_device::execute_one() +{ + const UINT8 opcode = rdop(); + + switch (opcode) + { + case 0x00: { m_BA = ( m_BA & 0xFF00 ) | ADD8( ( m_BA & 0x00FF ), ( m_BA & 0xFF ) ); } + break; + case 0x01: { m_BA = ( m_BA & 0xFF00 ) | ADD8( ( m_BA & 0x00FF ), ( m_BA >> 8 ) ); } + break; + case 0x02: { m_BA = ( m_BA & 0xFF00 ) | ADD8( ( m_BA & 0x00FF ), rdop() ); } + break; + case 0x03: { AD2_IHL; m_BA = ( m_BA & 0xFF00 ) | ADD8( ( m_BA & 0x00FF ), RD( addr2 ) ); } + break; + case 0x04: { AD2_IN8; m_BA = ( m_BA & 0xFF00 ) | ADD8( ( m_BA & 0x00FF ), RD( addr2 ) ); } + break; + case 0x05: { AD2_I16; m_BA = ( m_BA & 0xFF00 ) | ADD8( ( m_BA & 0x00FF ), RD( addr2 ) ); } + break; + case 0x06: { AD2_XIX; m_BA = ( m_BA & 0xFF00 ) | ADD8( ( m_BA & 0x00FF ), RD( addr2 ) ); } + break; + case 0x07: { AD2_YIY; m_BA = ( m_BA & 0xFF00 ) | ADD8( ( m_BA & 0x00FF ), RD( addr2 ) ); } + break; + case 0x08: { m_BA = ( m_BA & 0xFF00 ) | ADDC8( ( m_BA & 0x00FF ), ( m_BA & 0xFF ) ); } + break; + case 0x09: { m_BA = ( m_BA & 0xFF00 ) | ADDC8( ( m_BA & 0x00FF ), ( m_BA >> 8 ) ); } + break; + case 0x0A: { m_BA = ( m_BA & 0xFF00 ) | ADDC8( ( m_BA & 0x00FF ), rdop() ); } + break; + case 0x0B: { AD2_IHL; m_BA = ( m_BA & 0xFF00 ) | ADDC8( ( m_BA & 0x00FF ), RD( addr2 ) ); } + break; + case 0x0C: { AD2_IN8; m_BA = ( m_BA & 0xFF00 ) | ADDC8( ( m_BA & 0x00FF ), RD( addr2 ) ); } + break; + case 0x0D: { AD2_I16; m_BA = ( m_BA & 0xFF00 ) | ADDC8( ( m_BA & 0x00FF ), RD( addr2 ) ); } + break; + case 0x0E: { AD2_XIX; m_BA = ( m_BA & 0xFF00 ) | ADDC8( ( m_BA & 0x00FF ), RD( addr2 ) ); } + break; + case 0x0F: { AD2_YIY; m_BA = ( m_BA & 0xFF00 ) | ADDC8( ( m_BA & 0x00FF ), RD( addr2 ) ); } + break; + + case 0x10: { m_BA = ( m_BA & 0xFF00 ) | SUB8( ( m_BA & 0x00FF ), ( m_BA & 0xFF ) ); } + break; + case 0x11: { m_BA = ( m_BA & 0xFF00 ) | SUB8( ( m_BA & 0x00FF ), ( m_BA >> 8 ) ); } + break; + case 0x12: { m_BA = ( m_BA & 0xFF00 ) | SUB8( ( m_BA & 0x00FF ), rdop() ); } + break; + case 0x13: { AD2_IHL; m_BA = ( m_BA & 0xFF00 ) | SUB8( ( m_BA & 0x00FF ), RD( addr2 ) ); } + break; + case 0x14: { AD2_IN8; m_BA = ( m_BA & 0xFF00 ) | SUB8( ( m_BA & 0x00FF ), RD( addr2 ) ); } + break; + case 0x15: { AD2_I16; m_BA = ( m_BA & 0xFF00 ) | SUB8( ( m_BA & 0x00FF ), RD( addr2 ) ); } + break; + case 0x16: { AD2_XIX; m_BA = ( m_BA & 0xFF00 ) | SUB8( ( m_BA & 0x00FF ), RD( addr2 ) ); } + break; + case 0x17: { AD2_YIY; m_BA = ( m_BA & 0xFF00 ) | SUB8( ( m_BA & 0x00FF ), RD( addr2 ) ); } + break; + case 0x18: { m_BA = ( m_BA & 0xFF00 ) | SUBC8( ( m_BA & 0x00FF ), ( m_BA & 0xFF ) ); } + break; + case 0x19: { m_BA = ( m_BA & 0xFF00 ) | SUBC8( ( m_BA & 0x00FF ), ( m_BA >> 8 ) ); } + break; + case 0x1A: { m_BA = ( m_BA & 0xFF00 ) | SUBC8( ( m_BA & 0x00FF ), rdop() ); } + break; + case 0x1B: { AD2_IHL; m_BA = ( m_BA & 0xFF00 ) | SUBC8( ( m_BA & 0x00FF ), RD( addr2 ) ); } + break; + case 0x1C: { AD2_IN8; m_BA = ( m_BA & 0xFF00 ) | SUBC8( ( m_BA & 0x00FF ), RD( addr2 ) ); } + break; + case 0x1D: { AD2_I16; m_BA = ( m_BA & 0xFF00 ) | SUBC8( ( m_BA & 0x00FF ), RD( addr2 ) ); } + break; + case 0x1E: { AD2_XIX; m_BA = ( m_BA & 0xFF00 ) | SUBC8( ( m_BA & 0x00FF ), RD( addr2 ) ); } + break; + case 0x1F: { AD2_YIY; m_BA = ( m_BA & 0xFF00 ) | SUBC8( ( m_BA & 0x00FF ), RD( addr2 ) ); } + break; + + case 0x20: { m_BA = ( m_BA & 0xFF00 ) | AND8( ( m_BA & 0x00FF ), ( m_BA & 0xFF ) ); } + break; + case 0x21: { m_BA = ( m_BA & 0xFF00 ) | AND8( ( m_BA & 0x00FF ), ( m_BA >> 8 ) ); } + break; + case 0x22: { m_BA = ( m_BA & 0xFF00 ) | AND8( ( m_BA & 0x00FF ), rdop() ); } + break; + case 0x23: { AD2_IHL; m_BA = ( m_BA & 0xFF00 ) | AND8( ( m_BA & 0x00FF ), RD( addr2 ) ); } + break; + case 0x24: { AD2_IN8; m_BA = ( m_BA & 0xFF00 ) | AND8( ( m_BA & 0x00FF ), RD( addr2 ) ); } + break; + case 0x25: { AD2_I16; m_BA = ( m_BA & 0xFF00 ) | AND8( ( m_BA & 0x00FF ), RD( addr2 ) ); } + break; + case 0x26: { AD2_XIX; m_BA = ( m_BA & 0xFF00 ) | AND8( ( m_BA & 0x00FF ), RD( addr2 ) ); } + break; + case 0x27: { AD2_YIY; m_BA = ( m_BA & 0xFF00 ) | AND8( ( m_BA & 0x00FF ), RD( addr2 ) ); } + break; + case 0x28: { m_BA = ( m_BA & 0xFF00 ) | OR8( ( m_BA & 0x00FF ), ( m_BA & 0xFF ) ); } + break; + case 0x29: { m_BA = ( m_BA & 0xFF00 ) | OR8( ( m_BA & 0x00FF ), ( m_BA >> 8 ) ); } + break; + case 0x2A: { m_BA = ( m_BA & 0xFF00 ) | OR8( ( m_BA & 0x00FF ), rdop() ); } + break; + case 0x2B: { AD2_IHL; m_BA = ( m_BA & 0xFF00 ) | OR8( ( m_BA & 0x00FF ), RD( addr2 ) ); } + break; + case 0x2C: { AD2_IN8; m_BA = ( m_BA & 0xFF00 ) | OR8( ( m_BA & 0x00FF ), RD( addr2 ) ); } + break; + case 0x2D: { AD2_I16; m_BA = ( m_BA & 0xFF00 ) | OR8( ( m_BA & 0x00FF ), RD( addr2 ) ); } + break; + case 0x2E: { AD2_XIX; m_BA = ( m_BA & 0xFF00 ) | OR8( ( m_BA & 0x00FF ), RD( addr2 ) ); } + break; + case 0x2F: { AD2_YIY; m_BA = ( m_BA & 0xFF00 ) | OR8( ( m_BA & 0x00FF ), RD( addr2 ) ); } + break; + + case 0x30: { SUB8( ( m_BA & 0x00FF ), ( m_BA & 0xFF ) ); } + break; + case 0x31: { SUB8( ( m_BA & 0x00FF ), ( m_BA >> 8 ) ); } + break; + case 0x32: { SUB8( ( m_BA & 0x00FF ), rdop() ); } + break; + case 0x33: { AD2_IHL; SUB8( ( m_BA & 0x00FF ), RD( addr2 ) ); } + break; + case 0x34: { AD2_IN8; SUB8( ( m_BA & 0x00FF ), RD( addr2 ) ); } + break; + case 0x35: { AD2_I16; SUB8( ( m_BA & 0x00FF ), RD( addr2 ) ); } + break; + case 0x36: { AD2_XIX; SUB8( ( m_BA & 0x00FF ), RD( addr2 ) ); } + break; + case 0x37: { AD2_YIY; SUB8( ( m_BA & 0x00FF ), RD( addr2 ) ); } + break; + case 0x38: { m_BA = ( m_BA & 0xFF00 ) | XOR8( ( m_BA & 0x00FF ), ( m_BA & 0xFF ) ); } + break; + case 0x39: { m_BA = ( m_BA & 0xFF00 ) | XOR8( ( m_BA & 0x00FF ), ( m_BA >> 8 ) ); } + break; + case 0x3A: { m_BA = ( m_BA & 0xFF00 ) | XOR8( ( m_BA & 0x00FF ), rdop() ); } + break; + case 0x3B: { AD2_IHL; m_BA = ( m_BA & 0xFF00 ) | XOR8( ( m_BA & 0x00FF ), RD( addr2 ) ); } + break; + case 0x3C: { AD2_IN8; m_BA = ( m_BA & 0xFF00 ) | XOR8( ( m_BA & 0x00FF ), RD( addr2 ) ); } + break; + case 0x3D: { AD2_I16; m_BA = ( m_BA & 0xFF00 ) | XOR8( ( m_BA & 0x00FF ), RD( addr2 ) ); } + break; + case 0x3E: { AD2_XIX; m_BA = ( m_BA & 0xFF00 ) | XOR8( ( m_BA & 0x00FF ), RD( addr2 ) ); } + break; + case 0x3F: { AD2_YIY; m_BA = ( m_BA & 0xFF00 ) | XOR8( ( m_BA & 0x00FF ), RD( addr2 ) ); } + break; + + case 0x40: { m_BA = ( m_BA & 0xFF00 ) | ( m_BA & 0x00FF); } + break; + case 0x41: { m_BA = ( m_BA & 0xFF00 ) | ( m_BA >> 8 ); } + break; + case 0x42: { m_BA = ( m_BA & 0xFF00 ) | ( m_HL & 0x00FF); } + break; + case 0x43: { m_BA = ( m_BA & 0xFF00 ) | ( m_HL >> 8 ); } + break; + case 0x44: { AD2_IN8; m_BA = ( m_BA & 0xFF00 ) | RD( addr2 ); } + break; + case 0x45: { AD2_IHL; m_BA = ( m_BA & 0xFF00 ) | RD( addr2 ); } + break; + case 0x46: { AD2_XIX; m_BA = ( m_BA & 0xFF00 ) | RD( addr2 ); } + break; + case 0x47: { AD2_YIY; m_BA = ( m_BA & 0xFF00 ) | RD( addr2 ); } + break; + case 0x48: { m_BA = ( m_BA & 0x00FF ) | ( ( m_BA & 0x00FF) << 8 ); } + break; + case 0x49: { m_BA = ( m_BA & 0x00FF ) | ( ( m_BA >> 8 ) << 8 ); } + break; + case 0x4A: { m_BA = ( m_BA & 0x00FF ) | ( ( m_HL & 0x00FF) << 8 ); } + break; + case 0x4B: { m_BA = ( m_BA & 0x00FF ) | ( ( m_HL >> 8 ) << 8 ); } + break; + case 0x4C: { AD2_IN8; m_BA = ( m_BA & 0x00FF ) | ( RD( addr2 ) << 8 ); } + break; + case 0x4D: { AD2_IHL; m_BA = ( m_BA & 0x00FF ) | ( RD( addr2 ) << 8 ); } + break; + case 0x4E: { AD2_XIX; m_BA = ( m_BA & 0x00FF ) | ( RD( addr2 ) << 8 ); } + break; + case 0x4F: { AD2_YIY; m_BA = ( m_BA & 0x00FF ) | ( RD( addr2 ) << 8 ); } + break; + + case 0x50: { m_HL = ( m_HL & 0xFF00 ) | ( m_BA & 0x00FF); } + break; + case 0x51: { m_HL = ( m_HL & 0xFF00 ) | ( m_BA >> 8 ); } + break; + case 0x52: { m_HL = ( m_HL & 0xFF00 ) | ( m_HL & 0x00FF); } + break; + case 0x53: { m_HL = ( m_HL & 0xFF00 ) | ( m_HL >> 8 ); } + break; + case 0x54: { AD2_IN8; m_HL = ( m_HL & 0xFF00 ) | RD( addr2 ); } + break; + case 0x55: { AD2_IHL; m_HL = ( m_HL & 0xFF00 ) | RD( addr2 ); } + break; + case 0x56: { AD2_XIX; m_HL = ( m_HL & 0xFF00 ) | RD( addr2 ); } + break; + case 0x57: { AD2_YIY; m_HL = ( m_HL & 0xFF00 ) | RD( addr2 ); } + break; + case 0x58: { m_HL = ( m_HL & 0x00FF ) | ( ( m_BA & 0x00FF) << 8 ); } + break; + case 0x59: { m_HL = ( m_HL & 0x00FF ) | ( ( m_BA >> 8 ) << 8 ); } + break; + case 0x5A: { m_HL = ( m_HL & 0x00FF ) | ( ( m_HL & 0x00FF) << 8 ); } + break; + case 0x5B: { m_HL = ( m_HL & 0x00FF ) | ( ( m_HL >> 8 ) << 8 ); } + break; + case 0x5C: { AD2_IN8; m_HL = ( m_HL & 0x00FF ) | ( RD( addr2 ) << 8 ); } + break; + case 0x5D: { AD2_IHL; m_HL = ( m_HL & 0x00FF ) | ( RD( addr2 ) << 8 ); } + break; + case 0x5E: { AD2_XIX; m_HL = ( m_HL & 0x00FF ) | ( RD( addr2 ) << 8 ); } + break; + case 0x5F: { AD2_YIY; m_HL = ( m_HL & 0x00FF ) | ( RD( addr2 ) << 8 ); } + break; + + case 0x60: { AD1_XIX; WR( addr1, ( m_BA & 0x00FF ) ); } + break; + case 0x61: { AD1_XIX; WR( addr1, ( m_BA >> 8 ) ); } + break; + case 0x62: { AD1_XIX; WR( addr1, ( m_HL & 0x00FF ) ); } + break; + case 0x63: { AD1_XIX; WR( addr1, ( m_HL >> 8 ) ); } + break; + case 0x64: { AD1_XIX; AD2_IN8; WR( addr1, RD( addr2 ) ); } + break; + case 0x65: { AD1_XIX; AD2_IHL; WR( addr1, RD( addr2 ) ); } + break; + case 0x66: { AD1_XIX; AD2_XIX; WR( addr1, RD( addr2 ) ); } + break; + case 0x67: { AD1_XIX; AD2_YIY; WR( addr1, RD( addr2 ) ); } + break; + case 0x68: { AD1_IHL; WR( addr1, ( m_BA & 0x00FF ) ); } + break; + case 0x69: { AD1_IHL; WR( addr1, ( m_BA >> 8 ) ); } + break; + case 0x6A: { AD1_IHL; WR( addr1, ( m_HL & 0x00FF ) ); } + break; + case 0x6B: { AD1_IHL; WR( addr1, ( m_HL >> 8 ) ); } + break; + case 0x6C: { AD1_IHL; AD2_IN8; WR( addr1, RD( addr2 ) ); } + break; + case 0x6D: { AD1_IHL; AD2_IHL; WR( addr1, RD( addr2 ) ); } + break; + case 0x6E: { AD1_IHL; AD2_XIX; WR( addr1, RD( addr2 ) ); } + break; + case 0x6F: { AD1_IHL; AD2_YIY; WR( addr1, RD( addr2 ) ); } + break; + + case 0x70: { AD1_YIY; WR( addr1, ( m_BA & 0x00FF ) ); } + break; + case 0x71: { AD1_YIY; WR( addr1, ( m_BA >> 8 ) ); } + break; + case 0x72: { AD1_YIY; WR( addr1, ( m_HL & 0x00FF ) ); } + break; + case 0x73: { AD1_YIY; WR( addr1, ( m_HL >> 8 ) ); } + break; + case 0x74: { AD1_YIY; AD2_IN8; WR( addr1, RD( addr2 ) ); } + break; + case 0x75: { AD1_YIY; AD2_IHL; WR( addr1, RD( addr2 ) ); } + break; + case 0x76: { AD1_YIY; AD2_XIX; WR( addr1, RD( addr2 ) ); } + break; + case 0x77: { AD1_YIY; AD2_YIY; WR( addr1, RD( addr2 ) ); } + break; + case 0x78: { AD1_IN8; WR( addr1, ( m_BA & 0x00FF ) ); } + break; + case 0x79: { AD1_IN8; WR( addr1, ( m_BA >> 8 ) ); } + break; + case 0x7A: { AD1_IN8; WR( addr1, ( m_HL & 0x00FF ) ); } + break; + case 0x7B: { AD1_IN8; WR( addr1, ( m_HL >> 8 ) ); } + break; + case 0x7C: { /* illegal operation? */ } + break; + case 0x7D: { AD1_IN8; AD2_IHL; WR( addr1, RD( addr2 ) ); } + break; + case 0x7E: { AD1_IN8; AD2_XIX; WR( addr1, RD( addr2 ) ); } + break; + case 0x7F: { AD1_IN8; AD2_YIY; WR( addr1, RD( addr2 ) ); } + break; + + case 0x80: { m_BA = ( m_BA & 0xFF00 ) | INC8( m_BA & 0x00FF ); } + break; + case 0x81: { m_BA = ( m_BA & 0x00FF ) | ( INC8( m_BA >> 8 ) << 8 ); } + break; + case 0x82: { m_HL = ( m_HL & 0xFF00 ) | INC8( m_HL & 0x00FF ); } + break; + case 0x83: { m_HL = ( m_HL & 0x00FF ) | ( INC8( m_HL >> 8 ) << 8 ); } + break; + case 0x84: { m_N = INC8( m_N ); } + break; + case 0x85: { AD1_IN8; WR( addr1, INC8( RD( addr1 ) ) ); } + break; + case 0x86: { AD1_IHL; WR( addr1, INC8( RD( addr1 ) ) ); } + break; + case 0x87: { m_SP = INC16( m_SP ); } + break; + case 0x88: { m_BA = ( m_BA & 0xFF00 ) | DEC8( m_BA & 0x00FF ); } + break; + case 0x89: { m_BA = ( m_BA & 0x00FF ) | ( DEC8( m_BA >> 8 ) << 8 ); } + break; + case 0x8A: { m_HL = ( m_HL & 0xFF00 ) | DEC8( m_HL & 0x00FF ); } + break; + case 0x8B: { m_HL = ( m_HL & 0x00FF ) | ( DEC8( m_HL >> 8 ) << 8 ); } + break; + case 0x8C: { m_N = DEC8( m_N ); } + break; + case 0x8D: { AD1_IN8; WR( addr1, DEC8( RD( addr1 ) ) ); } + break; + case 0x8E: { AD1_IHL; WR( addr1, DEC8( RD( addr1 ) ) ); } + break; + case 0x8F: { m_SP = DEC8( m_SP ); } + break; + + case 0x90: { m_BA = INC16( m_BA ); } + break; + case 0x91: { m_HL = INC16( m_HL ); } + break; + case 0x92: { m_X = INC16( m_X ); } + break; + case 0x93: { m_Y = INC16( m_Y ); } + break; + case 0x94: { m_F = ( AND8( ( m_BA & 0x00FF ), ( m_BA >> 8 ) ) ) ? m_F & ~FLAG_Z : m_F | FLAG_Z;} + break; + case 0x95: { AD1_IHL; m_F = ( AND8( RD( addr1 ), rdop() ) ) ? m_F & ~FLAG_Z : m_F | FLAG_Z; } + break; + case 0x96: { m_F = ( AND8( ( m_BA & 0x00FF ), rdop() ) ) ? m_F & ~FLAG_Z : m_F | FLAG_Z; } + break; + case 0x97: { m_F = ( AND8( ( m_BA >> 8 ), rdop() ) ) ? m_F & ~FLAG_Z : m_F | FLAG_Z; } + break; + case 0x98: { m_BA = DEC16( m_BA ); } + break; + case 0x99: { m_HL = DEC16( m_HL ); } + break; + case 0x9A: { m_X = DEC16( m_X ); } + break; + case 0x9B: { m_Y = DEC16( m_Y ); } + break; + case 0x9C: { m_F = m_F & rdop(); } + break; + case 0x9D: { m_F = m_F | rdop(); } + break; + case 0x9E: { m_F = m_F ^ rdop(); } + break; + case 0x9F: { m_F = rdop(); } + break; + + case 0xA0: { PUSH16( m_BA ); } + break; + case 0xA1: { PUSH16( m_HL ); } + break; + case 0xA2: { PUSH16( m_X ); } + break; + case 0xA3: { PUSH16( m_Y ); } + break; + case 0xA4: { PUSH8( m_N ); } + break; + case 0xA5: { PUSH8( m_I ); } + break; + case 0xA6: { PUSH8( m_XI ); PUSH8( m_YI ); } + break; + case 0xA7: { PUSH8( m_F ); } + break; + case 0xA8: { m_BA = POP16(); } + break; + case 0xA9: { m_HL = POP16();} + break; + case 0xAA: { m_X = POP16(); } + break; + case 0xAB: { m_Y = POP16(); } + break; + case 0xAC: { m_N = POP8(); } + break; + case 0xAD: { m_I = POP8(); } + break; + case 0xAE: { m_YI = POP8(); m_XI = POP8(); } + break; + case 0xAF: { m_F = POP8(); } + break; + + case 0xB0: { UINT8 op = rdop(); m_BA = ( m_BA & 0xFF00 ) | op; } + break; + case 0xB1: { UINT8 op = rdop(); m_BA = ( m_BA & 0x00FF ) | ( op << 8 ); } + break; + case 0xB2: { UINT8 op = rdop(); m_HL = ( m_HL & 0xFF00 ) | op; } + break; + case 0xB3: { UINT8 op = rdop(); m_HL = ( m_HL & 0x00FF ) | ( op << 8 ); } + break; + case 0xB4: { UINT8 op = rdop(); m_N = op; } + break; + case 0xB5: { AD1_IHL; UINT8 op = rdop(); WR( addr1, op); } + break; + case 0xB6: { AD1_XIX; UINT8 op = rdop(); WR( addr1, op ); } + break; + case 0xB7: { AD1_YIY; UINT8 op = rdop(); WR( addr1, op ); } + break; + case 0xB8: { AD2_I16; m_BA = rd16( addr2 ); } + break; + case 0xB9: { AD2_I16; m_HL = rd16( addr2 ); } + break; + case 0xBA: { AD2_I16; m_X = rd16( addr2 ); } + break; + case 0xBB: { AD2_I16; m_Y = rd16( addr2 ); } + break; + case 0xBC: { AD1_I16; wr16( addr1, m_BA ); } + break; + case 0xBD: { AD1_I16; wr16( addr1, m_HL ); } + break; + case 0xBE: { AD1_I16; wr16( addr1, m_X ); } + break; + case 0xBF: { AD1_I16; wr16( addr1, m_Y ); } + break; + + case 0xC0: { m_BA = ADD16( m_BA, rdop16() ); } + break; + case 0xC1: { m_HL = ADD16( m_HL, rdop16() ); } + break; + case 0xC2: { m_X = ADD16( m_X, rdop16() ); } + break; + case 0xC3: { m_Y = ADD16( m_Y, rdop16() ); } + break; + case 0xC4: { m_BA = rdop16(); } + break; + case 0xC5: { m_HL = rdop16(); } + break; + case 0xC6: { m_X = rdop16(); } + break; + case 0xC7: { m_Y = rdop16(); } + break; + case 0xC8: { UINT16 t = m_BA; m_BA = m_HL; m_HL = t; } + break; + case 0xC9: { UINT16 t = m_BA; m_BA = m_X; m_X = t; } + break; + case 0xCA: { UINT16 t = m_BA; m_BA = m_Y; m_Y = t; } + break; + case 0xCB: { UINT16 t = m_BA; m_BA = m_SP; m_SP = t; } + break; + case 0xCC: { m_BA = ( m_BA >> 8 ) | ( ( m_BA & 0x00FF ) << 8 ); } + break; + case 0xCD: { UINT8 t; AD2_IHL; t = RD( addr2 ); WR( addr2, ( m_BA & 0x00FF ) ); m_BA = ( m_BA & 0xFF00 ) | t; } + break; + case 0xCE: { execute_one_ce(); } + break; + case 0xCF: { execute_one_cf(); } + break; + + case 0xD0: { m_BA = SUB16( m_BA, rdop16() ); } + break; + case 0xD1: { m_HL = SUB16( m_HL, rdop16() ); } + break; + case 0xD2: { m_X = SUB16( m_X, rdop16() ); } + break; + case 0xD3: { m_Y = SUB16( m_Y, rdop16() ); } + break; + case 0xD4: { SUB16( m_BA, rdop16() ); } + break; + case 0xD5: { SUB16( m_HL, rdop16() ); } + break; + case 0xD6: { SUB16( m_X, rdop16() ); } + break; + case 0xD7: { SUB16( m_Y, rdop16() ); } + break; + case 0xD8: { AD1_IN8; WR( addr1, AND8( RD( addr1 ), rdop() ) ); } + break; + case 0xD9: { AD1_IN8; WR( addr1, OR8( RD( addr1 ), rdop() ) ); } + break; + case 0xDA: { AD1_IN8; WR( addr1, XOR8( RD( addr1 ), rdop() ) ); } + break; + case 0xDB: { AD1_IN8; SUB8( RD( addr1 ), rdop() ); } + break; + case 0xDC: { AD1_IN8; m_F = ( AND8( RD( addr1 ), rdop() ) ) ? m_F & ~FLAG_Z : m_F | FLAG_Z; } + break; + case 0xDD: { AD1_IN8; WR( addr1, rdop() ); } + break; + case 0xDE: { m_BA = ( m_BA & 0xFF00 ) | ( ( m_BA & 0x000F ) | ( ( m_BA & 0x0F00 ) >> 4 ) ); } + break; + case 0xDF: { m_BA = ( ( m_BA & 0x0080 ) ? 0xFF00 : 0x0000 ) | ( m_BA & 0x000F ); } + break; + + case 0xE0: { INT8 d8 = rdop(); if ( m_F & FLAG_C ) { CALL( m_PC + d8 - 1 ); m_icount -= 12; } } + break; + case 0xE1: { INT8 d8 = rdop(); if ( ! ( m_F & FLAG_C ) ) { CALL( m_PC + d8- 1 ); m_icount -= 12; } } + break; + case 0xE2: { INT8 d8 = rdop(); if ( m_F & FLAG_Z ) { CALL( m_PC + d8 - 1 ); m_icount -= 12; } } + break; + case 0xE3: { INT8 d8 = rdop(); if ( ! ( m_F & FLAG_Z ) ) { CALL( m_PC + d8 - 1 ); m_icount -= 12; } } + break; + case 0xE4: { INT8 d8 = rdop(); if ( m_F & FLAG_C ) { JMP( m_PC + d8 - 1 ); } } + break; + case 0xE5: { INT8 d8 = rdop(); if ( ! ( m_F & FLAG_C ) ) { JMP( m_PC + d8 - 1 ); } } + break; + case 0xE6: { INT8 d8 = rdop(); if ( m_F & FLAG_Z ) { JMP( m_PC + d8 - 1 ); } } + break; + case 0xE7: { INT8 d8 = rdop(); if ( ! ( m_F & FLAG_Z ) ) { JMP( m_PC + d8 - 1 ); } } + break; + case 0xE8: { UINT16 d16 = rdop16(); if ( m_F & FLAG_C ) { CALL( m_PC + d16 - 1 ); m_icount -= 12; } } + break; + case 0xE9: { UINT16 d16 = rdop16(); if ( ! ( m_F & FLAG_C ) ) { CALL( m_PC + d16 - 1 ); m_icount -= 12; } } + break; + case 0xEA: { UINT16 d16 = rdop16(); if ( m_F & FLAG_Z ) { CALL( m_PC + d16 - 1 ); m_icount -= 12; } } + break; + case 0xEB: { UINT16 d16 = rdop16(); if ( ! ( m_F & FLAG_Z ) ) { CALL( m_PC + d16 - 1 ); m_icount -= 12; } } + break; + case 0xEC: { UINT16 d16 = rdop16(); if ( m_F & FLAG_C ) { JMP( m_PC + d16 - 1 ); } } + break; + case 0xED: { UINT16 d16 = rdop16(); if ( ! ( m_F & FLAG_C ) ) { JMP( m_PC + d16 - 1 ); } } + break; + case 0xEE: { UINT16 d16 = rdop16(); if ( m_F & FLAG_Z ) { JMP( m_PC + d16 - 1 ); } } + break; + case 0xEF: { UINT16 d16 = rdop16(); if ( ! ( m_F & FLAG_Z ) ) { JMP( m_PC + d16 - 1 ); } } + break; + + case 0xF0: { INT8 d8 = rdop(); CALL( m_PC + d8 - 1 ); } + break; + case 0xF1: { INT8 d8 = rdop(); JMP( m_PC + d8 - 1 ); } + break; + case 0xF2: { UINT16 d16 = rdop16(); CALL( m_PC + d16 - 1 ); } + break; + case 0xF3: { UINT16 d16 = rdop16(); JMP( m_PC + d16 - 1 ); } + break; + case 0xF4: { JMP( m_HL ); } + break; + case 0xF5: { INT8 d8 = rdop(); m_BA = m_BA - 0x0100; if ( m_BA & 0xFF00 ) { JMP( m_PC + d8 - 1 ); } } + break; + case 0xF6: { m_BA = ( m_BA & 0xFF00 ) | ( ( m_BA & 0x00F0 ) >> 4 ) | ( ( m_BA & 0x000F ) << 4 ); } + break; + case 0xF7: { UINT8 d; AD1_IHL; d = RD( addr1 ); WR( addr1, ( ( d & 0xF0 ) >> 4 ) | ( ( d & 0x0F ) << 4 ) ); } + break; + case 0xF8: { m_PC = POP16(); m_V = POP8(); m_U = m_V; } + break; + case 0xF9: { m_F = POP8(); m_PC = POP16(); m_V = POP8(); m_U = m_V; } + break; + case 0xFA: { m_PC = POP16() + 2; m_V = POP8(); m_U = m_V; } + break; + case 0xFB: { AD1_I16; CALL( rd16( addr1 ) ); } + break; + case 0xFC: { UINT8 i = rdop() & 0xFE; CALL( rd16( i ) ); PUSH8( m_F ); } + break; + case 0xFD: { UINT8 i = rdop() & 0xFE; JMP( rd16( i ) ); /* PUSH8( m_F );?? */ } + break; + case 0xFE: { /* illegal operation? */ } + break; + case 0xFF: { } + break; + } + + m_icount -= insnminx_cycles[opcode]; +} + + +const int minx_cpu_device::insnminx_cycles[256] = { + 8, 8, 8, 8, 12, 16, 8, 8, 8, 8, 8, 8, 12, 16, 8, 8, + 8, 8, 8, 8, 12, 16, 8, 8, 8, 8, 8, 8, 12, 16, 8, 8, + 8, 8, 8, 8, 12, 16, 8, 8, 8, 8, 8, 8, 12, 16, 8, 8, + 8, 8, 8, 8, 12, 16, 8, 8, 8, 8, 8, 8, 12, 16, 8, 8, + + 4, 4, 4, 4, 12, 8, 8, 8, 4, 4, 4, 4, 12, 8, 8, 8, + 4, 4, 4, 4, 12, 8, 8, 8, 4, 4, 4, 4, 12, 8, 8, 8, + 8, 8, 8, 8, 16, 12, 12, 12, 8, 8, 8, 8, 16, 12, 12, 12, + 8, 8, 8, 8, 16, 12, 12, 12, 12, 12, 12, 12, 1, 16, 16, 16, + + 8, 8, 8, 8, 8, 16, 12, 8, 8, 8, 8, 8, 8, 16, 12, 8, + 8, 8, 8, 8, 8, 12, 8, 8, 8, 8, 8, 8, 12, 12, 12, 12, + 16, 16, 16, 16, 12, 12, 16, 12, 12, 12, 12, 12, 8, 8, 12, 8, + 8, 8, 8, 8, 8, 12, 12, 12, 20, 20, 20, 20, 1, 1, 1, 1, + + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 8, 12, 0, 0, + 12, 12, 12, 12, 12, 12, 12, 12, 20, 20, 20, 16, 16, 16, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 12, 12, 12, 12, 12, 12, 12, 12, + 20, 8, 24, 12, 8, 1, 8, 12, 8, 8, 8, 20, 20, 1, 1, 8 +}; diff --git a/src/devices/cpu/mips/mips3.c b/src/devices/cpu/mips/mips3.c new file mode 100644 index 00000000000..00e3d7bc1c0 --- /dev/null +++ b/src/devices/cpu/mips/mips3.c @@ -0,0 +1,3079 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + mips3.c + Core implementation for the portable MIPS III/IV emulator. + Written by Aaron Giles + + Still not implemented: + * DMULT needs to be fixed properly + +***************************************************************************/ + +#include "emu.h" +#include "debugger.h" +#include "mips3.h" +#include "mips3com.h" + + +#define ENABLE_OVERFLOWS 0 + +/*************************************************************************** + HELPER MACROS +***************************************************************************/ + +#define RSVAL32 ((UINT32)m_core->r[RSREG]) +#define RTVAL32 ((UINT32)m_core->r[RTREG]) +#define RDVAL32 ((UINT32)m_core->r[RDREG]) + +#define RSVAL64 (m_core->r[RSREG]) +#define RTVAL64 (m_core->r[RTREG]) +#define RDVAL64 (m_core->r[RDREG]) + +#define FRVALS_FR0 (((float *)&m_core->cpr[1][0])[FRREG]) +#define FTVALS_FR0 (((float *)&m_core->cpr[1][0])[FTREG]) +#define FSVALS_FR0 (((float *)&m_core->cpr[1][0])[FSREG]) +#define FDVALS_FR0 (((float *)&m_core->cpr[1][0])[FDREG]) +#define FSVALW_FR0 (((UINT32 *)&m_core->cpr[1][0])[FSREG]) +#define FDVALW_FR0 (((UINT32 *)&m_core->cpr[1][0])[FDREG]) + +#define FRVALD_FR0 (*(double *)&m_core->cpr[1][FRREG/2]) +#define FTVALD_FR0 (*(double *)&m_core->cpr[1][FTREG/2]) +#define FSVALD_FR0 (*(double *)&m_core->cpr[1][FSREG/2]) +#define FDVALD_FR0 (*(double *)&m_core->cpr[1][FDREG/2]) +#define FSVALL_FR0 (((UINT64 *)&m_core->cpr[1][0])[FSREG/2]) +#define FDVALL_FR0 (((UINT64 *)&m_core->cpr[1][0])[FDREG/2]) + +#define FRVALS_FR1 (((float *)&m_core->cpr[1][FRREG])[BYTE_XOR_LE(0)]) +#define FTVALS_FR1 (((float *)&m_core->cpr[1][FTREG])[BYTE_XOR_LE(0)]) +#define FSVALS_FR1 (((float *)&m_core->cpr[1][FSREG])[BYTE_XOR_LE(0)]) +#define FDVALS_FR1 (((float *)&m_core->cpr[1][FDREG])[BYTE_XOR_LE(0)]) +#define FSVALW_FR1 (((UINT32 *)&m_core->cpr[1][FSREG])[BYTE_XOR_LE(0)]) +#define FDVALW_FR1 (((UINT32 *)&m_core->cpr[1][FDREG])[BYTE_XOR_LE(0)]) + +#define FRVALD_FR1 (*(double *)&m_core->cpr[1][FRREG]) +#define FTVALD_FR1 (*(double *)&m_core->cpr[1][FTREG]) +#define FSVALD_FR1 (*(double *)&m_core->cpr[1][FSREG]) +#define FDVALD_FR1 (*(double *)&m_core->cpr[1][FDREG]) +#define FSVALL_FR1 (*(UINT64 *)&m_core->cpr[1][FSREG]) +#define FDVALL_FR1 (*(UINT64 *)&m_core->cpr[1][FDREG]) + +#define ADDPC(x) m_nextpc = m_core->pc + ((x) << 2) +#define ADDPCL(x,l) { m_nextpc = m_core->pc + ((x) << 2); m_core->r[l] = (INT32)(m_core->pc + 4); } +#define ABSPC(x) m_nextpc = (m_core->pc & 0xf0000000) | ((x) << 2) +#define ABSPCL(x,l) { m_nextpc = (m_core->pc & 0xf0000000) | ((x) << 2); m_core->r[l] = (INT32)(m_core->pc + 4); } +#define SETPC(x) m_nextpc = (x) +#define SETPCL(x,l) { m_nextpc = (x); m_core->r[l] = (INT32)(m_core->pc + 4); } + +#define HIVAL (UINT32)m_core->r[REG_HI] +#define LOVAL (UINT32)m_core->r[REG_LO] +#define HIVAL64 m_core->r[REG_HI] +#define LOVAL64 m_core->r[REG_LO] +#define SR m_core->cpr[0][COP0_Status] +#define CAUSE m_core->cpr[0][COP0_Cause] + +#define GET_FCC(n) (m_cf[1][n]) +#define SET_FCC(n,v) (m_cf[1][n] = (v)) + +#define IS_FR0 (!(SR & SR_FR)) +#define IS_FR1 (SR & SR_FR) + +/* size of the execution code cache */ +#define CACHE_SIZE (32 * 1024 * 1024) + + + +static const UINT8 fcc_shift[8] = { 23, 25, 26, 27, 28, 29, 30, 31 }; + +/* lookup table for FP modes */ +static const UINT8 fpmode_source[4] = +{ + uml::ROUND_ROUND, + uml::ROUND_TRUNC, + uml::ROUND_CEIL, + uml::ROUND_FLOOR +}; + + + +/*************************************************************************** + MEMORY ACCESSORS +***************************************************************************/ + +#define ROPCODE(pc) direct->read_dword(pc) + + +const device_type VR4300BE = &device_creator; +const device_type VR4300LE = &device_creator; +const device_type VR4310BE = &device_creator; +const device_type VR4310LE = &device_creator; +const device_type R4600BE = &device_creator; +const device_type R4600LE = &device_creator; +const device_type R4650BE = &device_creator; +const device_type R4650LE = &device_creator; +const device_type R4700BE = &device_creator; +const device_type R4700LE = &device_creator; +const device_type R5000BE = &device_creator; +const device_type R5000LE = &device_creator; +const device_type QED5271BE = &device_creator; +const device_type QED5271LE = &device_creator; +const device_type RM7000BE = &device_creator; +const device_type RM7000LE = &device_creator; + + +mips3_device::mips3_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, mips3_flavor flavor, endianness_t endianness) + : cpu_device(mconfig, type, name, tag, owner, clock, shortname, __FILE__) + , m_program_config("program", endianness, 32, 32, 0, 32, MIPS3_MIN_PAGE_SHIFT) + , m_flavor(flavor) + , m_core(NULL) + , m_ppc(0) + , m_nextpc(0) + , m_pcbase(0) + , m_op(0) + , m_interrupt_cycles(0) + , m_ll_value(0) + , m_lld_value(0) + , m_badcop_value(0) + , m_tlb_table(NULL) + , m_lwl(endianness == ENDIANNESS_BIG ? &mips3_device::lwl_be : &mips3_device::lwl_le) + , m_lwr(endianness == ENDIANNESS_BIG ? &mips3_device::lwr_be : &mips3_device::lwr_le) + , m_swl(endianness == ENDIANNESS_BIG ? &mips3_device::swl_be : &mips3_device::swl_le) + , m_swr(endianness == ENDIANNESS_BIG ? &mips3_device::swr_be : &mips3_device::swr_le) + , m_ldl(endianness == ENDIANNESS_BIG ? &mips3_device::ldl_be : &mips3_device::ldl_le) + , m_ldr(endianness == ENDIANNESS_BIG ? &mips3_device::ldr_be : &mips3_device::ldr_le) + , m_sdl(endianness == ENDIANNESS_BIG ? &mips3_device::sdl_be : &mips3_device::sdl_le) + , m_sdr(endianness == ENDIANNESS_BIG ? &mips3_device::sdr_be : &mips3_device::sdr_le) + , c_system_clock(0) + , m_pfnmask(0) + , m_tlbentries(0) + , m_bigendian(endianness == ENDIANNESS_BIG) + , m_byte_xor(m_bigendian ? BYTE4_XOR_BE(0) : BYTE4_XOR_LE(0)) + , m_word_xor(m_bigendian ? WORD_XOR_BE(0) : WORD_XOR_LE(0)) + , c_icache_size(0) + , c_dcache_size(0) + , m_vtlb(NULL) + , m_fastram_select(0) + , m_debugger_temp(0) + , m_cache(CACHE_SIZE + sizeof(internal_mips3_state)) + , m_drcuml(NULL) + , m_drcfe(NULL) + , m_drcoptions(0) + , m_cache_dirty(0) + , m_entry(NULL) + , m_nocode(NULL) + , m_out_of_cycles(NULL) + , m_tlb_mismatch(NULL) + , m_hotspot_select(0) +{ + memset(m_fpmode, 0, sizeof(m_fpmode)); + + for (int i = 0; i < 3; i++) + { + m_read8[i] = NULL; + m_write8[i] = NULL; + m_read16[i] = NULL; + m_write16[i] = NULL; + m_read32[i] = NULL; + m_read32mask[i] = NULL; + m_write32[i] = NULL; + m_write32mask[i] = NULL; + m_read64[i] = NULL; + m_read64mask[i] = NULL; + m_write64[i] = NULL; + m_write64mask[i] = NULL; + } + + for (int i = 0; i < 18; i++) + { + m_exception[i] = NULL; + m_exception_norecover[i] = NULL; + } + memset(m_fastram, 0, sizeof(m_fastram)); + memset(m_hotspot, 0, sizeof(m_hotspot)); +} + + +void mips3_device::device_stop() +{ + if (m_vtlb != NULL) + { + vtlb_free(m_vtlb); + m_vtlb = NULL; + } + + if (m_drcfe != NULL) + { + auto_free(machine(), m_drcfe); + m_drcfe = NULL; + } + if (m_drcuml != NULL) + { + auto_free(machine(), m_drcuml); + m_drcuml = NULL; + } +} + +/*************************************************************************** + EXECEPTION HANDLING +***************************************************************************/ + +void mips3_device::generate_exception(int exception, int backup) +{ + UINT32 offset = 0x180; +/* + useful for catching exceptions: + + if (exception != 0) + { + fprintf(stderr, "Exception: PC=%08X, PPC=%08X\n", m_core->pc, m_ppc); + debugger_break(machine()); + } +*/ + + /* back up if necessary */ + if (backup) + m_core->pc = m_ppc; + + /* translate our fake fill exceptions into real exceptions */ + if (exception == EXCEPTION_TLBLOAD_FILL || exception == EXCEPTION_TLBSTORE_FILL) + { + offset = 0; + exception = (exception - EXCEPTION_TLBLOAD_FILL) + EXCEPTION_TLBLOAD; + } + + /* set the exception PC */ + m_core->cpr[0][COP0_EPC] = m_core->pc; + + /* put the cause in the low 8 bits and clear the branch delay flag */ + CAUSE = (CAUSE & ~0x800000ff) | (exception << 2); + + /* set the appropriate bits for coprocessor exceptions */ + if(exception == EXCEPTION_BADCOP) + { + CAUSE |= m_badcop_value << 28; + } + + /* if we were in a branch delay slot, adjust */ + if (m_nextpc != ~0) + { + m_nextpc = ~0; + m_core->cpr[0][COP0_EPC] -= 4; + CAUSE |= 0x80000000; + } + + /* set the exception level */ + SR |= SR_EXL; + + /* based on the BEV bit, we either go to ROM or RAM */ + m_core->pc = (SR & SR_BEV) ? 0xbfc00200 : 0x80000000; + + /* most exceptions go to offset 0x180, except for TLB stuff */ + if (exception >= EXCEPTION_TLBMOD && exception <= EXCEPTION_TLBSTORE) + { + osd_printf_debug("TLB miss @ %08X\n", (UINT32)m_core->cpr[0][COP0_BadVAddr]); + } + m_core->pc += offset; + +/* + useful for tracking interrupts + + if ((CAUSE & 0x7f) == 0) + logerror("Took interrupt -- Cause = %08X, PC = %08X\n", (UINT32)CAUSE, m_core->pc); +*/ +} + + +void mips3_device::generate_tlb_exception(int exception, offs_t address) +{ + m_core->cpr[0][COP0_BadVAddr] = address; + if(exception == EXCEPTION_TLBLOAD || exception == EXCEPTION_TLBSTORE || exception == EXCEPTION_TLBLOAD_FILL || exception == EXCEPTION_TLBSTORE_FILL) + { + m_core->cpr[0][COP0_Context] = (m_core->cpr[0][COP0_Context] & 0xff800000) | ((address >> 9) & 0x007ffff0); + m_core->cpr[0][COP0_EntryHi] = (address & 0xffffe000) | (m_core->cpr[0][COP0_EntryHi] & 0xff); + } + generate_exception(exception, 1); +} + + +void mips3_device::invalid_instruction(UINT32 op) +{ + generate_exception(EXCEPTION_INVALIDOP, 1); +} + + + +/*************************************************************************** + IRQ HANDLING +***************************************************************************/ + +void mips3_device::check_irqs() +{ + if ((CAUSE & SR & 0xfc00) && (SR & SR_IE) && !(SR & SR_EXL) && !(SR & SR_ERL)) + generate_exception(EXCEPTION_INTERRUPT, 0); +} + + + +/*************************************************************************** + CORE CALLBACKS +***************************************************************************/ + +void mips3_device::device_start() +{ + m_isdrc = (mconfig().options().drc() && !mconfig().m_force_no_drc) ? true : false; + + /* allocate the implementation-specific state from the full cache */ + m_core = (internal_mips3_state *)m_cache.alloc_near(sizeof(internal_mips3_state)); + + /* initialize based on the config */ + memset(m_core, 0, sizeof(internal_mips3_state)); + + m_cpu_clock = clock(); + m_program = &space(AS_PROGRAM); + m_direct = &m_program->direct(); + + /* configure flavor-specific parameters */ + m_pfnmask = 0x00ffffff; + m_tlbentries = MIPS3_MAX_TLB_ENTRIES; + + /* VR4300 and VR5432 have 4 fewer PFN bits, and only 32 TLB entries */ + if (m_flavor == MIPS3_TYPE_VR4300) + { + m_pfnmask = 0x000fffff; + m_tlbentries = 32; + } + + /* set up the endianness */ + m_program->accessors(m_memory); + + /* allocate the virtual TLB */ + m_vtlb = vtlb_alloc(this, AS_PROGRAM, 2 * m_tlbentries + 2, 0); + + /* allocate a timer for the compare interrupt */ + m_compare_int_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(mips3_device::compare_int_callback), this)); + + m_tlb_table = vtlb_table(m_vtlb); + + UINT32 flags = 0; + /* initialize the UML generator */ + m_drcuml = auto_alloc(machine(), drcuml_state(*this, m_cache, flags, 8, 32, 2)); + + /* add symbols for our stuff */ + m_drcuml->symbol_add(&m_core->pc, sizeof(m_core->pc), "pc"); + m_drcuml->symbol_add(&m_core->icount, sizeof(m_core->icount), "icount"); + for (int regnum = 0; regnum < 32; regnum++) + { + char buf[10]; + sprintf(buf, "r%d", regnum); + m_drcuml->symbol_add(&m_core->r[regnum], sizeof(m_core->r[regnum]), buf); + sprintf(buf, "f%d", regnum); + m_drcuml->symbol_add(&m_core->cpr[1][regnum], sizeof(m_core->cpr[1][regnum]), buf); + } + m_drcuml->symbol_add(&m_core->r[REG_LO], sizeof(m_core->r[REG_LO]), "lo"); + m_drcuml->symbol_add(&m_core->r[REG_HI], sizeof(m_core->r[REG_LO]), "hi"); + m_drcuml->symbol_add(&m_core->cpr[0][COP0_Index], sizeof(m_core->cpr[0][COP0_Index]), "Index"); + m_drcuml->symbol_add(&m_core->cpr[0][COP0_Random], sizeof(m_core->cpr[0][COP0_Random]), "Random"); + m_drcuml->symbol_add(&m_core->cpr[0][COP0_EntryLo0], sizeof(m_core->cpr[0][COP0_EntryLo0]), "EntryLo0"); + m_drcuml->symbol_add(&m_core->cpr[0][COP0_EntryLo1], sizeof(m_core->cpr[0][COP0_EntryLo1]), "EntryLo1"); + m_drcuml->symbol_add(&m_core->cpr[0][COP0_Context], sizeof(m_core->cpr[0][COP0_Context]), "Context"); + m_drcuml->symbol_add(&m_core->cpr[0][COP0_PageMask], sizeof(m_core->cpr[0][COP0_PageMask]), "PageMask"); + m_drcuml->symbol_add(&m_core->cpr[0][COP0_Wired], sizeof(m_core->cpr[0][COP0_Wired]), "Wired"); + m_drcuml->symbol_add(&m_core->cpr[0][COP0_BadVAddr], sizeof(m_core->cpr[0][COP0_BadVAddr]), "BadVAddr"); + m_drcuml->symbol_add(&m_core->cpr[0][COP0_Count], sizeof(m_core->cpr[0][COP0_Count]), "Count"); + m_drcuml->symbol_add(&m_core->cpr[0][COP0_EntryHi], sizeof(m_core->cpr[0][COP0_EntryHi]), "EntryHi"); + m_drcuml->symbol_add(&m_core->cpr[0][COP0_Compare], sizeof(m_core->cpr[0][COP0_Compare]), "Compare"); + m_drcuml->symbol_add(&m_core->cpr[0][COP0_Status], sizeof(m_core->cpr[0][COP0_Status]), "Status"); + m_drcuml->symbol_add(&m_core->cpr[0][COP0_Cause], sizeof(m_core->cpr[0][COP0_Cause]), "Cause"); + m_drcuml->symbol_add(&m_core->cpr[0][COP0_EPC], sizeof(m_core->cpr[0][COP0_EPC]), "EPC"); + m_drcuml->symbol_add(&m_core->cpr[0][COP0_PRId], sizeof(m_core->cpr[0][COP0_PRId]), "PRId"); + m_drcuml->symbol_add(&m_core->cpr[0][COP0_Config], sizeof(m_core->cpr[0][COP0_Config]), "Config"); + m_drcuml->symbol_add(&m_core->cpr[0][COP0_LLAddr], sizeof(m_core->cpr[0][COP0_LLAddr]), "LLAddr"); + m_drcuml->symbol_add(&m_core->cpr[0][COP0_XContext], sizeof(m_core->cpr[0][COP0_XContext]), "XContext"); + m_drcuml->symbol_add(&m_core->cpr[0][COP0_ECC], sizeof(m_core->cpr[0][COP0_ECC]), "ECC"); + m_drcuml->symbol_add(&m_core->cpr[0][COP0_CacheErr], sizeof(m_core->cpr[0][COP0_CacheErr]), "CacheErr"); + m_drcuml->symbol_add(&m_core->cpr[0][COP0_TagLo], sizeof(m_core->cpr[0][COP0_TagLo]), "TagLo"); + m_drcuml->symbol_add(&m_core->cpr[0][COP0_TagHi], sizeof(m_core->cpr[0][COP0_TagHi]), "TagHi"); + m_drcuml->symbol_add(&m_core->cpr[0][COP0_ErrorPC], sizeof(m_core->cpr[0][COP0_ErrorPC]), "ErrorPC"); + m_drcuml->symbol_add(&m_core->ccr[1][31], sizeof(m_core->cpr[1][31]), "fcr31"); + m_drcuml->symbol_add(&m_core->mode, sizeof(m_core->mode), "mode"); + m_drcuml->symbol_add(&m_core->arg0, sizeof(m_core->arg0), "arg0"); + m_drcuml->symbol_add(&m_core->arg1, sizeof(m_core->arg1), "arg1"); + m_drcuml->symbol_add(&m_core->numcycles, sizeof(m_core->numcycles), "numcycles"); + m_drcuml->symbol_add(&m_fpmode, sizeof(m_fpmode), "fpmode"); + + /* initialize the front-end helper */ + m_drcfe = auto_alloc(machine(), mips3_frontend(this, COMPILE_BACKWARDS_BYTES, COMPILE_FORWARDS_BYTES, SINGLE_INSTRUCTION_MODE ? 1 : COMPILE_MAX_SEQUENCE)); + + /* allocate memory for cache-local state and initialize it */ + memcpy(m_fpmode, fpmode_source, sizeof(fpmode_source)); + + /* compute the register parameters */ + for (int regnum = 0; regnum < 34; regnum++) + { + m_regmap[regnum] = (regnum == 0) ? uml::parameter(0) : uml::parameter::make_memory(&m_core->r[regnum]); + m_regmaplo[regnum] = (regnum == 0) ? uml::parameter(0) : uml::parameter::make_memory(LOPTR(&m_core->r[regnum])); + } + + /* if we have registers to spare, assign r2, r3, r4 to leftovers */ + if (!DISABLE_FAST_REGISTERS) + { + drcbe_info beinfo; + + m_drcuml->get_backend_info(beinfo); + if (beinfo.direct_iregs > 4) + { + m_regmap[2] = uml::I4; + m_regmaplo[2] = uml::I4; + } + if (beinfo.direct_iregs > 5) + { + m_regmap[3] = uml::I5; + m_regmaplo[3] = uml::I5; + } + if (beinfo.direct_iregs > 6) + { + m_regmap[4] = uml::I6; + m_regmaplo[4] = uml::I6; + } + } + + /* mark the cache dirty so it is updated on next execute */ + m_cache_dirty = TRUE; + + + /* register for save states */ + save_item(NAME(m_core->pc)); + save_item(NAME(m_core->r)); + save_item(NAME(m_core->cpr)); + save_item(NAME(m_core->ccr)); + save_item(NAME(m_core->llbit)); + save_item(NAME(m_core->count_zero_time)); + for (int tlbindex = 0; tlbindex < m_tlbentries; tlbindex++) + { + save_item(NAME(m_tlb[tlbindex].page_mask), tlbindex); + save_item(NAME(m_tlb[tlbindex].entry_hi), tlbindex); + save_item(NAME(m_tlb[tlbindex].entry_lo), tlbindex); + } + + // Register state with debugger + state_add( MIPS3_PC, "PC", m_core->pc).formatstr("%08X"); + +#if USE_ABI_REG_NAMES + state_add( MIPS3_R0, "zero", m_core->r[0]).callimport().formatstr("%016X"); // Can't change R0 + state_add( MIPS3_R1, "at", m_core->r[1]).formatstr("%016X"); + state_add( MIPS3_R2, "v0", m_core->r[2]).formatstr("%016X"); + state_add( MIPS3_R3, "v1", m_core->r[3]).formatstr("%016X"); + state_add( MIPS3_R4, "a0", m_core->r[4]).formatstr("%016X"); + state_add( MIPS3_R5, "a1", m_core->r[5]).formatstr("%016X"); + state_add( MIPS3_R6, "a2", m_core->r[6]).formatstr("%016X"); + state_add( MIPS3_R7, "a3", m_core->r[7]).formatstr("%016X"); + state_add( MIPS3_R8, "t0", m_core->r[8]).formatstr("%016X"); + state_add( MIPS3_R9, "t1", m_core->r[9]).formatstr("%016X"); + state_add( MIPS3_R10, "t2", m_core->r[10]).formatstr("%016X"); + state_add( MIPS3_R11, "t3", m_core->r[11]).formatstr("%016X"); + state_add( MIPS3_R12, "t4", m_core->r[12]).formatstr("%016X"); + state_add( MIPS3_R13, "t5", m_core->r[13]).formatstr("%016X"); + state_add( MIPS3_R14, "t6", m_core->r[14]).formatstr("%016X"); + state_add( MIPS3_R15, "t7", m_core->r[15]).formatstr("%016X"); + state_add( MIPS3_R16, "s0", m_core->r[16]).formatstr("%016X"); + state_add( MIPS3_R17, "s1", m_core->r[17]).formatstr("%016X"); + state_add( MIPS3_R18, "s2", m_core->r[18]).formatstr("%016X"); + state_add( MIPS3_R19, "s3", m_core->r[19]).formatstr("%016X"); + state_add( MIPS3_R20, "s4", m_core->r[20]).formatstr("%016X"); + state_add( MIPS3_R21, "s5", m_core->r[21]).formatstr("%016X"); + state_add( MIPS3_R22, "s6", m_core->r[22]).formatstr("%016X"); + state_add( MIPS3_R23, "s7", m_core->r[23]).formatstr("%016X"); + state_add( MIPS3_R24, "t8", m_core->r[24]).formatstr("%016X"); + state_add( MIPS3_R25, "t9", m_core->r[25]).formatstr("%016X"); + state_add( MIPS3_R26, "k0", m_core->r[26]).formatstr("%016X"); + state_add( MIPS3_R27, "k1", m_core->r[27]).formatstr("%016X"); + state_add( MIPS3_R28, "gp", m_core->r[28]).formatstr("%016X"); + state_add( MIPS3_R29, "sp", m_core->r[29]).formatstr("%016X"); + state_add( MIPS3_R30, "fp", m_core->r[30]).formatstr("%016X"); + state_add( MIPS3_R31, "ra", m_core->r[31]).formatstr("%016X"); +#else + state_add( MIPS3_R0, "R0", m_core->r[0]).callimport().formatstr("%016X"); // Can't change R0 + state_add( MIPS3_R1, "R1", m_core->r[1]).formatstr("%016X"); + state_add( MIPS3_R2, "R2", m_core->r[2]).formatstr("%016X"); + state_add( MIPS3_R3, "R3", m_core->r[3]).formatstr("%016X"); + state_add( MIPS3_R4, "R4", m_core->r[4]).formatstr("%016X"); + state_add( MIPS3_R5, "R5", m_core->r[5]).formatstr("%016X"); + state_add( MIPS3_R6, "R6", m_core->r[6]).formatstr("%016X"); + state_add( MIPS3_R7, "R7", m_core->r[7]).formatstr("%016X"); + state_add( MIPS3_R8, "R8", m_core->r[8]).formatstr("%016X"); + state_add( MIPS3_R9, "R9", m_core->r[9]).formatstr("%016X"); + state_add( MIPS3_R10, "R10", m_core->r[10]).formatstr("%016X"); + state_add( MIPS3_R11, "R11", m_core->r[11]).formatstr("%016X"); + state_add( MIPS3_R12, "R12", m_core->r[12]).formatstr("%016X"); + state_add( MIPS3_R13, "R13", m_core->r[13]).formatstr("%016X"); + state_add( MIPS3_R14, "R14", m_core->r[14]).formatstr("%016X"); + state_add( MIPS3_R15, "R15", m_core->r[15]).formatstr("%016X"); + state_add( MIPS3_R16, "R16", m_core->r[16]).formatstr("%016X"); + state_add( MIPS3_R17, "R17", m_core->r[17]).formatstr("%016X"); + state_add( MIPS3_R18, "R18", m_core->r[18]).formatstr("%016X"); + state_add( MIPS3_R19, "R19", m_core->r[19]).formatstr("%016X"); + state_add( MIPS3_R20, "R20", m_core->r[20]).formatstr("%016X"); + state_add( MIPS3_R21, "R21", m_core->r[21]).formatstr("%016X"); + state_add( MIPS3_R22, "R22", m_core->r[22]).formatstr("%016X"); + state_add( MIPS3_R23, "R23", m_core->r[23]).formatstr("%016X"); + state_add( MIPS3_R24, "R24", m_core->r[24]).formatstr("%016X"); + state_add( MIPS3_R25, "R25", m_core->r[25]).formatstr("%016X"); + state_add( MIPS3_R26, "R26", m_core->r[26]).formatstr("%016X"); + state_add( MIPS3_R27, "R27", m_core->r[27]).formatstr("%016X"); + state_add( MIPS3_R28, "R28", m_core->r[28]).formatstr("%016X"); + state_add( MIPS3_R29, "R29", m_core->r[29]).formatstr("%016X"); + state_add( MIPS3_R30, "R30", m_core->r[30]).formatstr("%016X"); + state_add( MIPS3_R31, "R31", m_core->r[31]).formatstr("%016X"); +#endif + state_add( MIPS3_HI, "HI", m_core->r[REG_HI]).formatstr("%016X"); + state_add( MIPS3_LO, "LO", m_core->r[REG_LO]).formatstr("%016X"); + + state_add( MIPS3_CCR1_31, "CCR31", m_core->ccr[1][31]).formatstr("%08X"); + + state_add( MIPS3_FPR0, "FPR0", m_core->cpr[1][0]).formatstr("%016X"); + state_add( MIPS3_FPS0, "FPS0", m_core->cpr[1][0]).formatstr("%17s"); + state_add( MIPS3_FPD0, "FPD0", m_core->cpr[1][0]).formatstr("%17s"); + state_add( MIPS3_FPR1, "FPR1", m_core->cpr[1][1]).formatstr("%016X"); + state_add( MIPS3_FPS1, "FPS1", m_core->cpr[1][1]).formatstr("%17s"); + state_add( MIPS3_FPD1, "FPD1", m_core->cpr[1][1]).formatstr("%17s"); + state_add( MIPS3_FPR2, "FPR2", m_core->cpr[1][2]).formatstr("%016X"); + state_add( MIPS3_FPS2, "FPS2", m_core->cpr[1][2]).formatstr("%17s"); + state_add( MIPS3_FPD2, "FPD2", m_core->cpr[1][2]).formatstr("%17s"); + state_add( MIPS3_FPR3, "FPR3", m_core->cpr[1][3]).formatstr("%016X"); + state_add( MIPS3_FPS3, "FPS3", m_core->cpr[1][3]).formatstr("%17s"); + state_add( MIPS3_FPD3, "FPD3", m_core->cpr[1][3]).formatstr("%17s"); + state_add( MIPS3_FPR4, "FPR4", m_core->cpr[1][4]).formatstr("%016X"); + state_add( MIPS3_FPS4, "FPS4", m_core->cpr[1][4]).formatstr("%17s"); + state_add( MIPS3_FPD4, "FPD4", m_core->cpr[1][4]).formatstr("%17s"); + state_add( MIPS3_FPR5, "FPR5", m_core->cpr[1][5]).formatstr("%016X"); + state_add( MIPS3_FPS5, "FPS5", m_core->cpr[1][5]).formatstr("%17s"); + state_add( MIPS3_FPD5, "FPD5", m_core->cpr[1][5]).formatstr("%17s"); + state_add( MIPS3_FPR6, "FPR6", m_core->cpr[1][6]).formatstr("%016X"); + state_add( MIPS3_FPS6, "FPS6", m_core->cpr[1][6]).formatstr("%17s"); + state_add( MIPS3_FPD6, "FPD6", m_core->cpr[1][6]).formatstr("%17s"); + state_add( MIPS3_FPR7, "FPR7", m_core->cpr[1][7]).formatstr("%016X"); + state_add( MIPS3_FPS7, "FPS7", m_core->cpr[1][7]).formatstr("%17s"); + state_add( MIPS3_FPD7, "FPD7", m_core->cpr[1][7]).formatstr("%17s"); + state_add( MIPS3_FPR8, "FPR8", m_core->cpr[1][8]).formatstr("%016X"); + state_add( MIPS3_FPS8, "FPS8", m_core->cpr[1][8]).formatstr("%17s"); + state_add( MIPS3_FPD8, "FPD8", m_core->cpr[1][8]).formatstr("%17s"); + state_add( MIPS3_FPR9, "FPR9", m_core->cpr[1][9]).formatstr("%016X"); + state_add( MIPS3_FPS9, "FPS9", m_core->cpr[1][9]).formatstr("%17s"); + state_add( MIPS3_FPD9, "FPD9", m_core->cpr[1][9]).formatstr("%17s"); + state_add( MIPS3_FPR10, "FPR10", m_core->cpr[1][10]).formatstr("%016X"); + state_add( MIPS3_FPS10, "FPS10", m_core->cpr[1][10]).formatstr("%17s"); + state_add( MIPS3_FPD10, "FPD10", m_core->cpr[1][10]).formatstr("%17s"); + state_add( MIPS3_FPR11, "FPR11", m_core->cpr[1][11]).formatstr("%016X"); + state_add( MIPS3_FPS11, "FPS11", m_core->cpr[1][11]).formatstr("%17s"); + state_add( MIPS3_FPD11, "FPD11", m_core->cpr[1][11]).formatstr("%17s"); + state_add( MIPS3_FPR12, "FPR12", m_core->cpr[1][12]).formatstr("%016X"); + state_add( MIPS3_FPS12, "FPS12", m_core->cpr[1][12]).formatstr("%17s"); + state_add( MIPS3_FPD12, "FPD12", m_core->cpr[1][12]).formatstr("%17s"); + state_add( MIPS3_FPR13, "FPR13", m_core->cpr[1][13]).formatstr("%016X"); + state_add( MIPS3_FPS13, "FPS13", m_core->cpr[1][13]).formatstr("%17s"); + state_add( MIPS3_FPD13, "FPD13", m_core->cpr[1][13]).formatstr("%17s"); + state_add( MIPS3_FPR14, "FPR14", m_core->cpr[1][14]).formatstr("%016X"); + state_add( MIPS3_FPS14, "FPS14", m_core->cpr[1][14]).formatstr("%17s"); + state_add( MIPS3_FPD14, "FPD14", m_core->cpr[1][14]).formatstr("%17s"); + state_add( MIPS3_FPR15, "FPR15", m_core->cpr[1][15]).formatstr("%016X"); + state_add( MIPS3_FPS15, "FPS15", m_core->cpr[1][15]).formatstr("%17s"); + state_add( MIPS3_FPD15, "FPD15", m_core->cpr[1][15]).formatstr("%17s"); + state_add( MIPS3_FPR16, "FPR16", m_core->cpr[1][16]).formatstr("%016X"); + state_add( MIPS3_FPS16, "FPS16", m_core->cpr[1][16]).formatstr("%17s"); + state_add( MIPS3_FPD16, "FPD16", m_core->cpr[1][16]).formatstr("%17s"); + state_add( MIPS3_FPR17, "FPR17", m_core->cpr[1][17]).formatstr("%016X"); + state_add( MIPS3_FPS17, "FPS17", m_core->cpr[1][17]).formatstr("%17s"); + state_add( MIPS3_FPD17, "FPD17", m_core->cpr[1][17]).formatstr("%17s"); + state_add( MIPS3_FPR18, "FPR18", m_core->cpr[1][18]).formatstr("%016X"); + state_add( MIPS3_FPS18, "FPS18", m_core->cpr[1][18]).formatstr("%17s"); + state_add( MIPS3_FPD18, "FPD18", m_core->cpr[1][18]).formatstr("%17s"); + state_add( MIPS3_FPR19, "FPR19", m_core->cpr[1][19]).formatstr("%016X"); + state_add( MIPS3_FPS19, "FPS19", m_core->cpr[1][19]).formatstr("%17s"); + state_add( MIPS3_FPD19, "FPD19", m_core->cpr[1][19]).formatstr("%17s"); + state_add( MIPS3_FPR20, "FPR20", m_core->cpr[1][20]).formatstr("%016X"); + state_add( MIPS3_FPS20, "FPS20", m_core->cpr[1][20]).formatstr("%17s"); + state_add( MIPS3_FPD20, "FPD20", m_core->cpr[1][20]).formatstr("%17s"); + state_add( MIPS3_FPR21, "FPR21", m_core->cpr[1][21]).formatstr("%016X"); + state_add( MIPS3_FPS21, "FPS21", m_core->cpr[1][21]).formatstr("%17s"); + state_add( MIPS3_FPD21, "FPD21", m_core->cpr[1][21]).formatstr("%17s"); + state_add( MIPS3_FPR22, "FPR22", m_core->cpr[1][22]).formatstr("%016X"); + state_add( MIPS3_FPS22, "FPS22", m_core->cpr[1][22]).formatstr("%17s"); + state_add( MIPS3_FPD22, "FPD22", m_core->cpr[1][22]).formatstr("%17s"); + state_add( MIPS3_FPR23, "FPR23", m_core->cpr[1][23]).formatstr("%016X"); + state_add( MIPS3_FPS23, "FPS23", m_core->cpr[1][23]).formatstr("%17s"); + state_add( MIPS3_FPD23, "FPD23", m_core->cpr[1][23]).formatstr("%17s"); + state_add( MIPS3_FPR24, "FPR24", m_core->cpr[1][24]).formatstr("%016X"); + state_add( MIPS3_FPS24, "FPS24", m_core->cpr[1][24]).formatstr("%17s"); + state_add( MIPS3_FPD24, "FPD24", m_core->cpr[1][24]).formatstr("%17s"); + state_add( MIPS3_FPR25, "FPR25", m_core->cpr[1][25]).formatstr("%016X"); + state_add( MIPS3_FPS25, "FPS25", m_core->cpr[1][25]).formatstr("%17s"); + state_add( MIPS3_FPD25, "FPD25", m_core->cpr[1][25]).formatstr("%17s"); + state_add( MIPS3_FPR26, "FPR26", m_core->cpr[1][26]).formatstr("%016X"); + state_add( MIPS3_FPS26, "FPS26", m_core->cpr[1][26]).formatstr("%17s"); + state_add( MIPS3_FPD26, "FPD26", m_core->cpr[1][26]).formatstr("%17s"); + state_add( MIPS3_FPR27, "FPR27", m_core->cpr[1][27]).formatstr("%016X"); + state_add( MIPS3_FPS27, "FPS27", m_core->cpr[1][27]).formatstr("%17s"); + state_add( MIPS3_FPD27, "FPD27", m_core->cpr[1][27]).formatstr("%17s"); + state_add( MIPS3_FPR28, "FPR28", m_core->cpr[1][28]).formatstr("%016X"); + state_add( MIPS3_FPS28, "FPS28", m_core->cpr[1][28]).formatstr("%17s"); + state_add( MIPS3_FPD28, "FPD28", m_core->cpr[1][28]).formatstr("%17s"); + state_add( MIPS3_FPR29, "FPR29", m_core->cpr[1][29]).formatstr("%016X"); + state_add( MIPS3_FPS29, "FPS29", m_core->cpr[1][29]).formatstr("%17s"); + state_add( MIPS3_FPD29, "FPD29", m_core->cpr[1][29]).formatstr("%17s"); + state_add( MIPS3_FPR30, "FPR30", m_core->cpr[1][30]).formatstr("%016X"); + state_add( MIPS3_FPS30, "FPS30", m_core->cpr[1][30]).formatstr("%17s"); + state_add( MIPS3_FPD30, "FPD30", m_core->cpr[1][30]).formatstr("%17s"); + state_add( MIPS3_FPR31, "FPR31", m_core->cpr[1][31]).formatstr("%016X"); + state_add( MIPS3_FPS31, "FPS31", m_core->cpr[1][31]).formatstr("%17s"); + state_add( MIPS3_FPD31, "FPD31", m_core->cpr[1][31]).formatstr("%17s"); + + state_add( MIPS3_SR, "SR", m_core->cpr[0][COP0_Status]).formatstr("%08X"); + state_add( MIPS3_EPC, "EPC", m_core->cpr[0][COP0_EPC]).formatstr("%08X"); + state_add( MIPS3_CAUSE, "Cause", m_core->cpr[0][COP0_Cause]).formatstr("%08X"); + state_add( MIPS3_COUNT, "Count", m_debugger_temp).callexport().formatstr("%08X"); + state_add( MIPS3_COMPARE, "Compare", m_core->cpr[0][COP0_Compare]).formatstr("%08X"); + state_add( MIPS3_INDEX, "Index", m_core->cpr[0][COP0_Index]).formatstr("%08X"); + state_add( MIPS3_RANDOM, "Random", m_core->cpr[0][COP0_Random]).formatstr("%08X"); + state_add( MIPS3_ENTRYHI, "EntryHi", m_core->cpr[0][COP0_EntryHi]).formatstr("%016X"); + state_add( MIPS3_ENTRYLO0, "EntryLo0", m_core->cpr[0][COP0_EntryLo0]).formatstr("%016X"); + state_add( MIPS3_ENTRYLO1, "EntryLo1", m_core->cpr[0][COP0_EntryLo1]).formatstr("%016X"); + state_add( MIPS3_PAGEMASK, "PageMask", m_core->cpr[0][COP0_PageMask]).formatstr("%016X"); + state_add( MIPS3_WIRED, "Wired", m_core->cpr[0][COP0_Wired]).formatstr("%08X"); + state_add( MIPS3_BADVADDR, "BadVAddr", m_core->cpr[0][COP0_BadVAddr]).formatstr("%08X"); + + state_add( STATE_GENPC, "GENPC", m_core->pc).noshow(); + state_add( STATE_GENSP, "GENSP", m_core->r[31]).noshow(); + state_add( STATE_GENFLAGS, "GENFLAGS", m_debugger_temp).formatstr("%1s").noshow(); + + m_icountptr = &m_core->icount; +} + + +void mips3_device::state_export(const device_state_entry &entry) +{ + switch (entry.index()) + { + case MIPS3_COUNT: + m_debugger_temp = (total_cycles() - m_core->count_zero_time) / 2; + break; + } +} + + +void mips3_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + switch (entry.index()) + { + case MIPS3_FPS0: + strprintf(str, "!%16g", *(float *)&m_core->cpr[1][0]); + break; + + case MIPS3_FPD0: + strprintf(str, "!%16g", *(double *)&m_core->cpr[1][0]); + break; + + case MIPS3_FPS1: + strprintf(str, "!%16g", *(float *)&m_core->cpr[1][1]); + break; + + case MIPS3_FPD1: + strprintf(str, "!%16g", *(double *)&m_core->cpr[1][1]); + break; + + case MIPS3_FPS2: + strprintf(str, "!%16g", *(float *)&m_core->cpr[1][2]); + break; + + case MIPS3_FPD2: + strprintf(str, "!%16g", *(double *)&m_core->cpr[1][2]); + break; + + case MIPS3_FPS3: + strprintf(str, "!%16g", *(float *)&m_core->cpr[1][3]); + break; + + case MIPS3_FPD3: + strprintf(str, "!%16g", *(double *)&m_core->cpr[1][3]); + break; + + case MIPS3_FPS4: + strprintf(str, "!%16g", *(float *)&m_core->cpr[1][4]); + break; + + case MIPS3_FPD4: + strprintf(str, "!%16g", *(double *)&m_core->cpr[1][4]); + break; + + case MIPS3_FPS5: + strprintf(str, "!%16g", *(float *)&m_core->cpr[1][5]); + break; + + case MIPS3_FPD5: + strprintf(str, "!%16g", *(double *)&m_core->cpr[1][5]); + break; + + case MIPS3_FPS6: + strprintf(str, "!%16g", *(float *)&m_core->cpr[1][6]); + break; + + case MIPS3_FPD6: + strprintf(str, "!%16g", *(double *)&m_core->cpr[1][6]); + break; + + case MIPS3_FPS7: + strprintf(str, "!%16g", *(float *)&m_core->cpr[1][7]); + break; + + case MIPS3_FPD7: + strprintf(str, "!%16g", *(double *)&m_core->cpr[1][7]); + break; + + case MIPS3_FPS8: + strprintf(str, "!%16g", *(float *)&m_core->cpr[1][8]); + break; + + case MIPS3_FPD8: + strprintf(str, "!%16g", *(double *)&m_core->cpr[1][8]); + break; + + case MIPS3_FPS9: + strprintf(str, "!%16g", *(float *)&m_core->cpr[1][9]); + break; + + case MIPS3_FPD9: + strprintf(str, "!%16g", *(double *)&m_core->cpr[1][9]); + break; + + case MIPS3_FPS10: + strprintf(str, "!%16g", *(float *)&m_core->cpr[1][10]); + break; + + case MIPS3_FPD10: + strprintf(str, "!%16g", *(double *)&m_core->cpr[1][10]); + break; + + case MIPS3_FPS11: + strprintf(str, "!%16g", *(float *)&m_core->cpr[1][11]); + break; + + case MIPS3_FPD11: + strprintf(str, "!%16g", *(double *)&m_core->cpr[1][11]); + break; + + case MIPS3_FPS12: + strprintf(str, "!%16g", *(float *)&m_core->cpr[1][12]); + break; + + case MIPS3_FPD12: + strprintf(str, "!%16g", *(double *)&m_core->cpr[1][12]); + break; + + case MIPS3_FPS13: + strprintf(str, "!%16g", *(float *)&m_core->cpr[1][13]); + break; + + case MIPS3_FPD13: + strprintf(str, "!%16g", *(double *)&m_core->cpr[1][13]); + break; + + case MIPS3_FPS14: + strprintf(str, "!%16g", *(float *)&m_core->cpr[1][14]); + break; + + case MIPS3_FPD14: + strprintf(str, "!%16g", *(double *)&m_core->cpr[1][14]); + break; + + case MIPS3_FPS15: + strprintf(str, "!%16g", *(float *)&m_core->cpr[1][15]); + break; + + case MIPS3_FPD15: + strprintf(str, "!%16g", *(double *)&m_core->cpr[1][15]); + break; + + case MIPS3_FPS16: + strprintf(str, "!%16g", *(float *)&m_core->cpr[1][16]); + break; + + case MIPS3_FPD16: + strprintf(str, "!%16g", *(double *)&m_core->cpr[1][16]); + break; + + case MIPS3_FPS17: + strprintf(str, "!%16g", *(float *)&m_core->cpr[1][17]); + break; + + case MIPS3_FPD17: + strprintf(str, "!%16g", *(double *)&m_core->cpr[1][17]); + break; + + case MIPS3_FPS18: + strprintf(str, "!%16g", *(float *)&m_core->cpr[1][18]); + break; + + case MIPS3_FPD18: + strprintf(str, "!%16g", *(double *)&m_core->cpr[1][18]); + break; + + case MIPS3_FPS19: + strprintf(str, "!%16g", *(float *)&m_core->cpr[1][19]); + break; + + case MIPS3_FPD19: + strprintf(str, "!%16g", *(double *)&m_core->cpr[1][19]); + break; + + case MIPS3_FPS20: + strprintf(str, "!%16g", *(float *)&m_core->cpr[1][20]); + break; + + case MIPS3_FPD20: + strprintf(str, "!%16g", *(double *)&m_core->cpr[1][20]); + break; + + case MIPS3_FPS21: + strprintf(str, "!%16g", *(float *)&m_core->cpr[1][21]); + break; + + case MIPS3_FPD21: + strprintf(str, "!%16g", *(double *)&m_core->cpr[1][21]); + break; + + case MIPS3_FPS22: + strprintf(str, "!%16g", *(float *)&m_core->cpr[1][22]); + break; + + case MIPS3_FPD22: + strprintf(str, "!%16g", *(double *)&m_core->cpr[1][22]); + break; + + case MIPS3_FPS23: + strprintf(str, "!%16g", *(float *)&m_core->cpr[1][23]); + break; + + case MIPS3_FPD23: + strprintf(str, "!%16g", *(double *)&m_core->cpr[1][23]); + break; + + case MIPS3_FPS24: + strprintf(str, "!%16g", *(float *)&m_core->cpr[1][24]); + break; + + case MIPS3_FPD24: + strprintf(str, "!%16g", *(double *)&m_core->cpr[1][24]); + break; + + case MIPS3_FPS25: + strprintf(str, "!%16g", *(float *)&m_core->cpr[1][25]); + break; + + case MIPS3_FPD25: + strprintf(str, "!%16g", *(double *)&m_core->cpr[1][25]); + break; + + case MIPS3_FPS26: + strprintf(str, "!%16g", *(float *)&m_core->cpr[1][26]); + break; + + case MIPS3_FPD26: + strprintf(str, "!%16g", *(double *)&m_core->cpr[1][26]); + break; + + case MIPS3_FPS27: + strprintf(str, "!%16g", *(float *)&m_core->cpr[1][27]); + break; + + case MIPS3_FPD27: + strprintf(str, "!%16g", *(double *)&m_core->cpr[1][27]); + break; + + case MIPS3_FPS28: + strprintf(str, "!%16g", *(float *)&m_core->cpr[1][28]); + break; + + case MIPS3_FPD28: + strprintf(str, "!%16g", *(double *)&m_core->cpr[1][28]); + break; + + case MIPS3_FPS29: + strprintf(str, "!%16g", *(float *)&m_core->cpr[1][29]); + break; + + case MIPS3_FPD29: + strprintf(str, "!%16g", *(double *)&m_core->cpr[1][29]); + break; + + case MIPS3_FPS30: + strprintf(str, "!%16g", *(float *)&m_core->cpr[1][30]); + break; + + case MIPS3_FPD30: + strprintf(str, "!%16g", *(double *)&m_core->cpr[1][30]); + break; + + case MIPS3_FPS31: + strprintf(str, "!%16g", *(float *)&m_core->cpr[1][31]); + break; + + case MIPS3_FPD31: + strprintf(str, "!%16g", *(double *)&m_core->cpr[1][31]); + break; + + case STATE_GENFLAGS: + strprintf(str, " "); + break; + } +} + + +void mips3_device::device_reset() +{ + /* common reset */ + m_nextpc = ~0; + memset(m_cf, 0, sizeof(m_cf)); + + /* initialize the state */ + m_core->pc = 0xbfc00000; + m_core->cpr[0][COP0_Status] = SR_BEV | SR_ERL; + m_core->cpr[0][COP0_Wired] = 0; + m_core->cpr[0][COP0_Compare] = 0xffffffff; + m_core->cpr[0][COP0_Count] = 0; + m_core->cpr[0][COP0_Config] = compute_config_register(); + m_core->cpr[0][COP0_PRId] = compute_prid_register(); + m_core->count_zero_time = total_cycles(); + + /* initialize the TLB state */ + for (int tlbindex = 0; tlbindex < m_tlbentries; tlbindex++) + { + mips3_tlb_entry *entry = &m_tlb[tlbindex]; + entry->page_mask = 0; + entry->entry_hi = 0xffffffff; + entry->entry_lo[0] = 0xfffffff8; + entry->entry_lo[1] = 0xfffffff8; + vtlb_load(m_vtlb, 2 * tlbindex + 0, 0, 0, 0); + vtlb_load(m_vtlb, 2 * tlbindex + 1, 0, 0, 0); + } + + /* load the fixed TLB range */ + vtlb_load(m_vtlb, 2 * m_tlbentries + 0, (0xa0000000 - 0x80000000) >> MIPS3_MIN_PAGE_SHIFT, 0x80000000, 0x00000000 | VTLB_READ_ALLOWED | VTLB_WRITE_ALLOWED | VTLB_FETCH_ALLOWED | VTLB_FLAG_VALID); + vtlb_load(m_vtlb, 2 * m_tlbentries + 1, (0xc0000000 - 0xa0000000) >> MIPS3_MIN_PAGE_SHIFT, 0xa0000000, 0x00000000 | VTLB_READ_ALLOWED | VTLB_WRITE_ALLOWED | VTLB_FETCH_ALLOWED | VTLB_FLAG_VALID); + + m_core->mode = (MODE_KERNEL << 1) | 0; + m_cache_dirty = TRUE; + m_interrupt_cycles = 0; +} + + +bool mips3_device::memory_translate(address_spacenum spacenum, int intention, offs_t &address) +{ + /* only applies to the program address space */ + if (spacenum == AS_PROGRAM) + { + const vtlb_entry *table = vtlb_table(m_vtlb); + vtlb_entry entry = table[address >> MIPS3_MIN_PAGE_SHIFT]; + if ((entry & (1 << (intention & (TRANSLATE_TYPE_MASK | TRANSLATE_USER_MASK)))) == 0) + return false; + address = (entry & ~MIPS3_MIN_PAGE_MASK) | (address & MIPS3_MIN_PAGE_MASK); + } + return true; +} + + +offs_t mips3_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern unsigned dasmmips3(char *, unsigned, UINT32); + UINT32 op = *(UINT32 *)oprom; + if (m_bigendian) + op = BIG_ENDIANIZE_INT32(op); + else + op = LITTLE_ENDIANIZE_INT32(op); + return dasmmips3(buffer, pc, op); +} + + + +/*************************************************************************** + TLB HANDLING +***************************************************************************/ + +inline bool mips3_device::RBYTE(offs_t address, UINT32 *result) +{ + const UINT32 tlbval = m_tlb_table[address >> 12]; + if (tlbval & VTLB_READ_ALLOWED) + { + const UINT32 tlbaddress = (tlbval & ~0xfff) | (address & 0xfff); + for (int ramnum = 0; ramnum < m_fastram_select; ramnum++) + { + if (tlbaddress < m_fastram[ramnum].start || tlbaddress > m_fastram[ramnum].end) + { + continue; + } + *result = m_fastram[ramnum].offset_base8[tlbaddress ^ m_byte_xor]; + return true; + } + *result = (*m_memory.read_byte)(*m_program, tlbaddress); + } + else + { + if(tlbval & VTLB_FLAG_FIXED) + { + generate_tlb_exception(EXCEPTION_TLBLOAD, address); + } + else + { + generate_tlb_exception(EXCEPTION_TLBLOAD_FILL, address); + } + *result = 0; + return false; + } + return true; +} + +inline bool mips3_device::RHALF(offs_t address, UINT32 *result) +{ + const UINT32 tlbval = m_tlb_table[address >> 12]; + if (tlbval & VTLB_READ_ALLOWED) + { + const UINT32 tlbaddress = (tlbval & ~0xfff) | (address & 0xfff); + for (int ramnum = 0; ramnum < m_fastram_select; ramnum++) + { + if (tlbaddress < m_fastram[ramnum].start || tlbaddress > m_fastram[ramnum].end) + { + continue; + } + *result = m_fastram[ramnum].offset_base16[(tlbaddress ^ m_word_xor) >> 1]; + return true; + } + *result = (*m_memory.read_word)(*m_program, tlbaddress); + } + else + { + if(tlbval & VTLB_FLAG_FIXED) + { + generate_tlb_exception(EXCEPTION_TLBLOAD, address); + } + else + { + generate_tlb_exception(EXCEPTION_TLBLOAD_FILL, address); + } + *result = 0; + return false; + } + return true; +} + +inline bool mips3_device::RWORD(offs_t address, UINT32 *result) +{ + const UINT32 tlbval = m_tlb_table[address >> 12]; + if (tlbval & VTLB_READ_ALLOWED) + { + const UINT32 tlbaddress = (tlbval & ~0xfff) | (address & 0xfff); + for (int ramnum = 0; ramnum < m_fastram_select; ramnum++) + { + if (tlbaddress < m_fastram[ramnum].start || tlbaddress > m_fastram[ramnum].end) + { + continue; + } + *result = m_fastram[ramnum].offset_base32[tlbaddress >> 2]; + return true; + } + *result = (*m_memory.read_dword)(*m_program, tlbaddress); + } + else + { + if(tlbval & VTLB_FLAG_FIXED) + { + generate_tlb_exception(EXCEPTION_TLBLOAD, address); + } + else + { + generate_tlb_exception(EXCEPTION_TLBLOAD_FILL, address); + } + *result = 0; + return false; + } + return true; +} + +inline bool mips3_device::RWORD_MASKED(offs_t address, UINT32 *result, UINT32 mem_mask) +{ + const UINT32 tlbval = m_tlb_table[address >> 12]; + if (tlbval & VTLB_READ_ALLOWED) + { + *result = (*m_memory.read_dword_masked)(*m_program, (tlbval & ~0xfff) | (address & 0xfff), mem_mask); + } + else + { + if(tlbval & VTLB_FLAG_FIXED) + { + generate_tlb_exception(EXCEPTION_TLBLOAD, address); + } + else + { + generate_tlb_exception(EXCEPTION_TLBLOAD_FILL, address); + } + *result = 0; + return false; + } + return true; +} + +inline bool mips3_device::RDOUBLE(offs_t address, UINT64 *result) +{ + const UINT32 tlbval = m_tlb_table[address >> 12]; + if (tlbval & VTLB_READ_ALLOWED) + { + *result = (*m_memory.read_qword)(*m_program, (tlbval & ~0xfff) | (address & 0xfff)); + } + else + { + if(tlbval & VTLB_FLAG_FIXED) + { + generate_tlb_exception(EXCEPTION_TLBLOAD, address); + } + else + { + generate_tlb_exception(EXCEPTION_TLBLOAD_FILL, address); + } + *result = 0; + return false; + } + return true; +} + +inline bool mips3_device::RDOUBLE_MASKED(offs_t address, UINT64 *result, UINT64 mem_mask) +{ + const UINT32 tlbval = m_tlb_table[address >> 12]; + if (tlbval & VTLB_READ_ALLOWED) + { + *result = (*m_memory.read_qword_masked)(*m_program, (tlbval & ~0xfff) | (address & 0xfff), mem_mask); + } + else + { + if(tlbval & VTLB_FLAG_FIXED) + { + generate_tlb_exception(EXCEPTION_TLBLOAD, address); + } + else + { + generate_tlb_exception(EXCEPTION_TLBLOAD_FILL, address); + } + *result = 0; + return false; + } + return true; +} + +inline void mips3_device::WBYTE(offs_t address, UINT8 data) +{ + const UINT32 tlbval = m_tlb_table[address >> 12]; + if (tlbval & VTLB_WRITE_ALLOWED) + { + const UINT32 tlbaddress = (tlbval & ~0xfff) | (address & 0xfff); + for (int ramnum = 0; ramnum < m_fastram_select; ramnum++) + { + if (m_fastram[ramnum].readonly == TRUE || tlbaddress < m_fastram[ramnum].start || tlbaddress > m_fastram[ramnum].end) + { + continue; + } + m_fastram[ramnum].offset_base8[tlbaddress ^ m_byte_xor] = data; + return; + } + (*m_memory.write_byte)(*m_program, tlbaddress, data); + } + else + { + if(tlbval & VTLB_READ_ALLOWED) + { + generate_tlb_exception(EXCEPTION_TLBMOD, address); + } + else if(tlbval & VTLB_FLAG_FIXED) + { + generate_tlb_exception(EXCEPTION_TLBSTORE, address); + } + else + { + generate_tlb_exception(EXCEPTION_TLBSTORE_FILL, address); + } + } +} + +inline void mips3_device::WHALF(offs_t address, UINT16 data) +{ + const UINT32 tlbval = m_tlb_table[address >> 12]; + if (tlbval & VTLB_WRITE_ALLOWED) + { + const UINT32 tlbaddress = (tlbval & ~0xfff) | (address & 0xfff); + for (int ramnum = 0; ramnum < m_fastram_select; ramnum++) + { + if (m_fastram[ramnum].readonly == TRUE || tlbaddress < m_fastram[ramnum].start || tlbaddress > m_fastram[ramnum].end) + { + continue; + } + m_fastram[ramnum].offset_base16[(tlbaddress ^ m_word_xor) >> 1] = data; + return; + } + (*m_memory.write_word)(*m_program, tlbaddress, data); + } + else + { + if(tlbval & VTLB_READ_ALLOWED) + { + generate_tlb_exception(EXCEPTION_TLBMOD, address); + } + else if(tlbval & VTLB_FLAG_FIXED) + { + generate_tlb_exception(EXCEPTION_TLBSTORE, address); + } + else + { + generate_tlb_exception(EXCEPTION_TLBSTORE_FILL, address); + } + } +} + +inline void mips3_device::WWORD(offs_t address, UINT32 data) +{ + const UINT32 tlbval = m_tlb_table[address >> 12]; + if (tlbval & VTLB_WRITE_ALLOWED) + { + const UINT32 tlbaddress = (tlbval & ~0xfff) | (address & 0xfff); + for (int ramnum = 0; ramnum < m_fastram_select; ramnum++) + { + if (m_fastram[ramnum].readonly == TRUE || tlbaddress < m_fastram[ramnum].start || tlbaddress > m_fastram[ramnum].end) + { + continue; + } + m_fastram[ramnum].offset_base32[tlbaddress >> 2] = data; + return; + } + (*m_memory.write_dword)(*m_program, tlbaddress, data); + } + else + { + if(tlbval & VTLB_READ_ALLOWED) + { + generate_tlb_exception(EXCEPTION_TLBMOD, address); + } + else if(tlbval & VTLB_FLAG_FIXED) + { + generate_tlb_exception(EXCEPTION_TLBSTORE, address); + } + else + { + generate_tlb_exception(EXCEPTION_TLBSTORE_FILL, address); + } + } +} + +inline void mips3_device::WWORD_MASKED(offs_t address, UINT32 data, UINT32 mem_mask) +{ + const UINT32 tlbval = m_tlb_table[address >> 12]; + if (tlbval & VTLB_WRITE_ALLOWED) + { + (*m_memory.write_dword_masked)(*m_program, (tlbval & ~0xfff) | (address & 0xfff), data, mem_mask); + } + else + { + if(tlbval & VTLB_READ_ALLOWED) + { + generate_tlb_exception(EXCEPTION_TLBMOD, address); + } + else if(tlbval & VTLB_FLAG_FIXED) + { + generate_tlb_exception(EXCEPTION_TLBSTORE, address); + } + else + { + generate_tlb_exception(EXCEPTION_TLBSTORE_FILL, address); + } + } +} + +inline void mips3_device::WDOUBLE(offs_t address, UINT64 data) +{ + const UINT32 tlbval = m_tlb_table[address >> 12]; + if (tlbval & VTLB_WRITE_ALLOWED) + { + (*m_memory.write_qword)(*m_program, (tlbval & ~0xfff) | (address & 0xfff), data); + } + else + { + if(tlbval & VTLB_READ_ALLOWED) + { + generate_tlb_exception(EXCEPTION_TLBMOD, address); + } + else if(tlbval & VTLB_FLAG_FIXED) + { + generate_tlb_exception(EXCEPTION_TLBSTORE, address); + } + else + { + generate_tlb_exception(EXCEPTION_TLBSTORE_FILL, address); + } + } +} + +inline void mips3_device::WDOUBLE_MASKED(offs_t address, UINT64 data, UINT64 mem_mask) +{ + const UINT32 tlbval = m_tlb_table[address >> 12]; + if (tlbval & VTLB_WRITE_ALLOWED) + { + (*m_memory.write_qword_masked)(*m_program, (tlbval & ~0xfff) | (address & 0xfff), data, mem_mask); + } + else + { + if(tlbval & VTLB_READ_ALLOWED) + { + generate_tlb_exception(EXCEPTION_TLBMOD, address); + } + else if(tlbval & VTLB_FLAG_FIXED) + { + generate_tlb_exception(EXCEPTION_TLBSTORE, address); + } + else + { + generate_tlb_exception(EXCEPTION_TLBSTORE_FILL, address); + } + } +} + + + +/*************************************************************************** + COP0 (SYSTEM) EXECUTION HANDLING +***************************************************************************/ + +UINT64 mips3_device::get_cop0_reg(int idx) +{ + if (idx == COP0_Count) + { + /* it doesn't really take 250 cycles to read this register, but it helps speed */ + /* up loops that hammer on it */ + if (m_core->icount >= MIPS3_COUNT_READ_CYCLES) + m_core->icount -= MIPS3_COUNT_READ_CYCLES; + else + m_core->icount = 0; + return (UINT32)((total_cycles() - m_core->count_zero_time) / 2); + } + else if (idx == COP0_Cause) + { + /* it doesn't really take 250 cycles to read this register, but it helps speed */ + /* up loops that hammer on it */ + if (m_core->icount >= MIPS3_CAUSE_READ_CYCLES) + m_core->icount -= MIPS3_CAUSE_READ_CYCLES; + else + m_core->icount = 0; + } + else if (idx == COP0_Random) + { + int wired = m_core->cpr[0][COP0_Wired] & 0x3f; + int range = 48 - wired; + if (range > 0) + return ((total_cycles() - m_core->count_zero_time) % range + wired) & 0x3f; + else + return 47; + } + return m_core->cpr[0][idx]; +} + +void mips3_device::set_cop0_reg(int idx, UINT64 val) +{ + switch (idx) + { + case COP0_Cause: + CAUSE = (CAUSE & 0xfc00) | (val & ~0xfc00); + if (CAUSE & 0x300) + { + /* if we're in a delay slot, propogate the target PC before generating the exception */ + if (m_nextpc != ~0) + { + m_core->pc = m_nextpc; + m_nextpc = ~0; + } + generate_exception(EXCEPTION_INTERRUPT, 0); + } + break; + + case COP0_Status: + { + /* update interrupts and cycle counting */ + UINT32 diff = m_core->cpr[0][idx] ^ val; +// if (val & 0xe0) +// fatalerror("System set 64-bit addressing mode, SR=%08X\n", val); + m_core->cpr[0][idx] = val; + if (diff & 0x8000) + mips3com_update_cycle_counting(); + check_irqs(); + break; + } + + case COP0_Count: + m_core->cpr[0][idx] = val; + m_core->count_zero_time = total_cycles() - ((UINT64)(UINT32)val * 2); + mips3com_update_cycle_counting(); + break; + + case COP0_Compare: + m_core->compare_armed = 1; + CAUSE &= ~0x8000; + m_core->cpr[0][idx] = val & 0xffffffff; + mips3com_update_cycle_counting(); + break; + + case COP0_PRId: + break; + + case COP0_Config: + m_core->cpr[0][idx] = (m_core->cpr[0][idx] & ~7) | (val & 7); + break; + + case COP0_EntryHi: + /* if the ASID changes, remap */ + if ((m_core->cpr[0][idx] ^ val) & 0xff) + { + m_core->cpr[0][idx] = val; + mips3com_asid_changed(); + } + m_core->cpr[0][idx] = val; + break; + + default: + m_core->cpr[0][idx] = val; + break; + } +} + +inline UINT64 mips3_device::get_cop0_creg(int idx) +{ + return m_core->ccr[0][idx]; +} + +inline void mips3_device::set_cop0_creg(int idx, UINT64 val) +{ + m_core->ccr[0][idx] = val; +} + +void mips3_device::handle_cop0(UINT32 op) +{ + if ((SR & SR_KSU_MASK) != SR_KSU_KERNEL && !(SR & SR_COP0)) + { + m_badcop_value = 0; + generate_exception(EXCEPTION_BADCOP, 1); + } + + switch (RSREG) + { + case 0x00: /* MFCz */ if (RTREG) RTVAL64 = (INT32)get_cop0_reg(RDREG); break; + case 0x01: /* DMFCz */ if (RTREG) RTVAL64 = get_cop0_reg(RDREG); break; + case 0x02: /* CFCz */ if (RTREG) RTVAL64 = (INT32)get_cop0_creg(RDREG); break; + case 0x04: /* MTCz */ set_cop0_reg(RDREG, RTVAL32); break; + case 0x05: /* DMTCz */ set_cop0_reg(RDREG, RTVAL64); break; + case 0x06: /* CTCz */ set_cop0_creg(RDREG, RTVAL32); break; + case 0x08: /* BC */ + switch (RTREG) + { + case 0x00: /* BCzF */ if (!m_cf[0]) ADDPC(SIMMVAL); break; + case 0x01: /* BCzF */ if (m_cf[0]) ADDPC(SIMMVAL); break; + case 0x02: /* BCzFL */ invalid_instruction(op); break; + case 0x03: /* BCzTL */ invalid_instruction(op); break; + default: invalid_instruction(op); break; + } + break; + case 0x10: + case 0x11: + case 0x12: + case 0x13: + case 0x14: + case 0x15: + case 0x16: + case 0x17: + case 0x18: + case 0x19: + case 0x1a: + case 0x1b: + case 0x1c: + case 0x1d: + case 0x1e: + case 0x1f: /* COP */ + switch (op & 0x01ffffff) + { + case 0x01: /* TLBR */ + mips3com_tlbr(); + break; + + case 0x02: /* TLBWI */ + mips3com_tlbwi(); + break; + + case 0x06: /* TLBWR */ + mips3com_tlbwr(); + break; + + case 0x08: /* TLBP */ + mips3com_tlbp(); + break; + + case 0x10: /* RFE */ invalid_instruction(op); break; + case 0x18: /* ERET */ logerror("ERET\n"); m_core->pc = m_core->cpr[0][COP0_EPC]; SR &= ~SR_EXL; check_irqs(); m_lld_value ^= 0xffffffff; m_ll_value ^= 0xffffffff; break; + case 0x20: /* WAIT */ break; + default: invalid_instruction(op); break; + } + break; + default: invalid_instruction(op); break; + } +} + + + +/*************************************************************************** + COP1 (FPU) EXECUTION HANDLING +***************************************************************************/ + +inline UINT32 mips3_device::get_cop1_reg32(int idx) +{ + if (IS_FR0) + return ((UINT32 *)&m_core->cpr[1][0])[idx]; + else + return m_core->cpr[1][idx]; +} + +inline UINT64 mips3_device::get_cop1_reg64(int idx) +{ + if (IS_FR0) + return ((UINT64 *)&m_core->cpr[1][0])[idx/2]; + else + return m_core->cpr[1][idx]; +} + +inline void mips3_device::set_cop1_reg32(int idx, UINT32 val) +{ + if (IS_FR0) + ((UINT32 *)&m_core->cpr[1][0])[idx] = val; + else + m_core->cpr[1][idx] = val; +} + +inline void mips3_device::set_cop1_reg64(int idx, UINT64 val) +{ + if (IS_FR0) + ((UINT64 *)&m_core->cpr[1][0])[idx/2] = val; + else + m_core->cpr[1][idx] = val; +} + +inline UINT64 mips3_device::get_cop1_creg(int idx) +{ + if (idx == 31) + { + UINT32 result = m_core->ccr[1][31] & ~0xfe800000; + int i; + + for (i = 0; i < 8; i++) + if (m_cf[1][i]) + result |= 1 << fcc_shift[i]; + return result; + } + return m_core->ccr[1][idx]; +} + +inline void mips3_device::set_cop1_creg(int idx, UINT64 val) +{ + m_core->ccr[1][idx] = val; + if (idx == 31) + { + int i; + + for (i = 0; i < 8; i++) + m_cf[1][i] = (val >> fcc_shift[i]) & 1; + } +} + +void mips3_device::handle_cop1_fr0(UINT32 op) +{ + double dtemp; + + /* note: additional condition codes available on R5000 only */ + + if (!(SR & SR_COP1)) + { + m_badcop_value = 1; + generate_exception(EXCEPTION_BADCOP, 1); + } + + switch (RSREG) + { + case 0x00: /* MFCz */ if (RTREG) RTVAL64 = (INT32)get_cop1_reg32(RDREG); break; + case 0x01: /* DMFCz */ if (RTREG) RTVAL64 = get_cop1_reg64(RDREG); break; + case 0x02: /* CFCz */ if (RTREG) RTVAL64 = (INT32)get_cop1_creg(RDREG); break; + case 0x04: /* MTCz */ set_cop1_reg32(RDREG, RTVAL32); break; + case 0x05: /* DMTCz */ set_cop1_reg64(RDREG, RTVAL64); break; + case 0x06: /* CTCz */ set_cop1_creg(RDREG, RTVAL32); break; + case 0x08: /* BC */ + switch ((op >> 16) & 3) + { + case 0x00: /* BCzF */ if (!GET_FCC((op >> 18) & 7)) ADDPC(SIMMVAL); break; + case 0x01: /* BCzT */ if (GET_FCC((op >> 18) & 7)) ADDPC(SIMMVAL); break; + case 0x02: /* BCzFL */ if (!GET_FCC((op >> 18) & 7)) ADDPC(SIMMVAL); else m_core->pc += 4; break; + case 0x03: /* BCzTL */ if (GET_FCC((op >> 18) & 7)) ADDPC(SIMMVAL); else m_core->pc += 4; break; + } + break; + default: + switch (op & 0x3f) + { + case 0x00: + if (IS_SINGLE(op)) /* ADD.S */ + FDVALS_FR0 = FSVALS_FR0 + FTVALS_FR0; + else /* ADD.D */ + FDVALD_FR0 = FSVALD_FR0 + FTVALD_FR0; + break; + + case 0x01: + if (IS_SINGLE(op)) /* SUB.S */ + FDVALS_FR0 = FSVALS_FR0 - FTVALS_FR0; + else /* SUB.D */ + FDVALD_FR0 = FSVALD_FR0 - FTVALD_FR0; + break; + + case 0x02: + if (IS_SINGLE(op)) /* MUL.S */ + FDVALS_FR0 = FSVALS_FR0 * FTVALS_FR0; + else /* MUL.D */ + FDVALD_FR0 = FSVALD_FR0 * FTVALD_FR0; + break; + + case 0x03: + if (IS_SINGLE(op)) /* DIV.S */ + FDVALS_FR0 = FSVALS_FR0 / FTVALS_FR0; + else /* DIV.D */ + FDVALD_FR0 = FSVALD_FR0 / FTVALD_FR0; + break; + + case 0x04: + if (IS_SINGLE(op)) /* SQRT.S */ + FDVALS_FR0 = sqrt(FSVALS_FR0); + else /* SQRT.D */ + FDVALD_FR0 = sqrt(FSVALD_FR0); + break; + + case 0x05: + if (IS_SINGLE(op)) /* ABS.S */ + FDVALS_FR0 = fabs(FSVALS_FR0); + else /* ABS.D */ + FDVALD_FR0 = fabs(FSVALD_FR0); + break; + + case 0x06: + if (IS_SINGLE(op)) /* MOV.S */ + FDVALS_FR0 = FSVALS_FR0; + else /* MOV.D */ + FDVALD_FR0 = FSVALD_FR0; + break; + + case 0x07: + if (IS_SINGLE(op)) /* NEG.S */ + FDVALS_FR0 = -FSVALS_FR0; + else /* NEG.D */ + FDVALD_FR0 = -FSVALD_FR0; + break; + + case 0x08: + if (IS_SINGLE(op)) /* ROUND.L.S */ + { + double temp = FSVALS_FR0; + if (temp < 0) + temp = ceil(temp - 0.5); + else + temp = floor(temp + 0.5); + FDVALL_FR0 = (INT64)temp; + } + else /* ROUND.L.D */ + { + double temp = FSVALD_FR0; + if (temp < 0) + temp = ceil(temp - 0.5); + else + temp = floor(temp + 0.5); + FDVALL_FR0 = (INT64)temp; + } + break; + + case 0x09: + if (IS_SINGLE(op)) /* TRUNC.L.S */ + { + double temp = FSVALS_FR0; + if (temp < 0) + temp = ceil(temp); + else + temp = floor(temp); + FDVALL_FR0 = (INT64)temp; + } + else /* TRUNC.L.D */ + { + double temp = FSVALD_FR0; + if (temp < 0) + temp = ceil(temp); + else + temp = floor(temp); + FDVALL_FR0 = (INT64)temp; + } + break; + + case 0x0a: + if (IS_SINGLE(op)) /* CEIL.L.S */ + dtemp = ceil(FSVALS_FR0); + else /* CEIL.L.D */ + dtemp = ceil(FSVALD_FR0); + FDVALL_FR0 = (INT64)dtemp; + break; + + case 0x0b: + if (IS_SINGLE(op)) /* FLOOR.L.S */ + dtemp = floor(FSVALS_FR0); + else /* FLOOR.L.D */ + dtemp = floor(FSVALD_FR0); + FDVALL_FR0 = (INT64)dtemp; + break; + + case 0x0c: + if (IS_SINGLE(op)) /* ROUND.W.S */ + { + dtemp = FSVALS_FR0; + if (dtemp < 0) + dtemp = ceil(dtemp - 0.5); + else + dtemp = floor(dtemp + 0.5); + FDVALW_FR0 = (INT32)dtemp; + } + else /* ROUND.W.D */ + { + dtemp = FSVALD_FR0; + if (dtemp < 0) + dtemp = ceil(dtemp - 0.5); + else + dtemp = floor(dtemp + 0.5); + FDVALW_FR0 = (INT32)dtemp; + } + break; + + case 0x0d: + if (IS_SINGLE(op)) /* TRUNC.W.S */ + { + dtemp = FSVALS_FR0; + if (dtemp < 0) + dtemp = ceil(dtemp); + else + dtemp = floor(dtemp); + FDVALW_FR0 = (INT32)dtemp; + } + else /* TRUNC.W.D */ + { + dtemp = FSVALD_FR0; + if (dtemp < 0) + dtemp = ceil(dtemp); + else + dtemp = floor(dtemp); + FDVALW_FR0 = (INT32)dtemp; + } + break; + + case 0x0e: + if (IS_SINGLE(op)) /* CEIL.W.S */ + dtemp = ceil(FSVALS_FR0); + else /* CEIL.W.D */ + dtemp = ceil(FSVALD_FR0); + FDVALW_FR0 = (INT32)dtemp; + break; + + case 0x0f: + if (IS_SINGLE(op)) /* FLOOR.W.S */ + dtemp = floor(FSVALS_FR0); + else /* FLOOR.W.D */ + dtemp = floor(FSVALD_FR0); + FDVALW_FR0 = (INT32)dtemp; + break; + + case 0x11: /* R5000 */ + if (GET_FCC((op >> 18) & 7) == ((op >> 16) & 1)) + { + if (IS_SINGLE(op)) /* MOVT/F.S */ + FDVALS_FR0 = FSVALS_FR0; + else /* MOVT/F.D */ + FDVALD_FR0 = FSVALD_FR0; + } + break; + + case 0x12: /* R5000 */ + if (RTVAL64 == 0) + { + if (IS_SINGLE(op)) /* MOVZ.S */ + FDVALS_FR0 = FSVALS_FR0; + else /* MOVZ.D */ + FDVALD_FR0 = FSVALD_FR0; + } + break; + + case 0x13: /* R5000 */ + if (RTVAL64 != 0) + { + if (IS_SINGLE(op)) /* MOVN.S */ + FDVALS_FR0 = FSVALS_FR0; + else /* MOVN.D */ + FDVALD_FR0 = FSVALD_FR0; + } + break; + + case 0x15: /* R5000 */ + if (IS_SINGLE(op)) /* RECIP.S */ + FDVALS_FR0 = 1.0f / FSVALS_FR0; + else /* RECIP.D */ + FDVALD_FR0 = 1.0 / FSVALD_FR0; + break; + + case 0x16: /* R5000 */ + if (IS_SINGLE(op)) /* RSQRT.S */ + FDVALS_FR0 = 1.0f / sqrt(FSVALS_FR0); + else /* RSQRT.D */ + FDVALD_FR0 = 1.0 / sqrt(FSVALD_FR0); + break; + + case 0x20: + if (IS_INTEGRAL(op)) + { + if (IS_SINGLE(op)) /* CVT.S.W */ + FDVALS_FR0 = (INT32)FSVALW_FR0; + else /* CVT.S.L */ + FDVALS_FR0 = (INT64)FSVALL_FR0; + } + else /* CVT.S.D */ + FDVALS_FR0 = FSVALD_FR0; + break; + + case 0x21: + if (IS_INTEGRAL(op)) + { + if (IS_SINGLE(op)) /* CVT.D.W */ + FDVALD_FR0 = (INT32)FSVALW_FR0; + else /* CVT.D.L */ + FDVALD_FR0 = (INT64)FSVALL_FR0; + } + else /* CVT.D.S */ + FDVALD_FR0 = FSVALS_FR0; + break; + + case 0x24: + if (IS_SINGLE(op)) /* CVT.W.S */ + FDVALW_FR0 = (INT32)FSVALS_FR0; + else + FDVALW_FR0 = (INT32)FSVALD_FR0; + break; + + case 0x25: + if (IS_SINGLE(op)) /* CVT.L.S */ + FDVALL_FR0 = (INT64)FSVALS_FR0; + else /* CVT.L.D */ + FDVALL_FR0 = (INT64)FSVALD_FR0; + break; + + case 0x30: + case 0x38: + if (IS_SINGLE(op)) /* C.F.S */ + SET_FCC((op >> 8) & 7, 0); + else /* C.F.D */ + SET_FCC((op >> 8) & 7, 0); + break; + + case 0x31: + case 0x39: + if (IS_SINGLE(op)) /* C.UN.S */ + SET_FCC((op >> 8) & 7, 0); + else /* C.UN.D */ + SET_FCC((op >> 8) & 7, 0); + break; + + case 0x32: + case 0x3a: + if (IS_SINGLE(op)) /* C.EQ.S */ + SET_FCC((op >> 8) & 7, (FSVALS_FR0 == FTVALS_FR0)); + else /* C.EQ.D */ + SET_FCC((op >> 8) & 7, (FSVALD_FR0 == FTVALD_FR0)); + break; + + case 0x33: + case 0x3b: + if (IS_SINGLE(op)) /* C.UEQ.S */ + SET_FCC((op >> 8) & 7, (FSVALS_FR0 == FTVALS_FR0)); + else /* C.UEQ.D */ + SET_FCC((op >> 8) & 7, (FSVALD_FR0 == FTVALD_FR0)); + break; + + case 0x34: + case 0x3c: + if (IS_SINGLE(op)) /* C.OLT.S */ + SET_FCC((op >> 8) & 7, (FSVALS_FR0 < FTVALS_FR0)); + else /* C.OLT.D */ + SET_FCC((op >> 8) & 7, (FSVALD_FR0 < FTVALD_FR0)); + break; + + case 0x35: + case 0x3d: + if (IS_SINGLE(op)) /* C.ULT.S */ + SET_FCC((op >> 8) & 7, (FSVALS_FR0 < FTVALS_FR0)); + else /* C.ULT.D */ + SET_FCC((op >> 8) & 7, (FSVALD_FR0 < FTVALD_FR0)); + break; + + case 0x36: + case 0x3e: + if (IS_SINGLE(op)) /* C.OLE.S */ + SET_FCC((op >> 8) & 7, (FSVALS_FR0 <= FTVALS_FR0)); + else /* C.OLE.D */ + SET_FCC((op >> 8) & 7, (FSVALD_FR0 <= FTVALD_FR0)); + break; + + case 0x37: + case 0x3f: + if (IS_SINGLE(op)) /* C.ULE.S */ + SET_FCC((op >> 8) & 7, (FSVALS_FR0 <= FTVALS_FR0)); + else /* C.ULE.D */ + SET_FCC((op >> 8) & 7, (FSVALD_FR0 <= FTVALD_FR0)); + break; + + default: + fprintf(stderr, "cop1 %X\n", op); + break; + } + break; + } +} + + +void mips3_device::handle_cop1_fr1(UINT32 op) +{ + double dtemp; + + /* note: additional condition codes available on R5000 only */ + + if (!(SR & SR_COP1)) + { + m_badcop_value = 1; + generate_exception(EXCEPTION_BADCOP, 1); + } + + switch (RSREG) + { + case 0x00: /* MFCz */ if (RTREG) RTVAL64 = (INT32)get_cop1_reg32(RDREG); break; + case 0x01: /* DMFCz */ if (RTREG) RTVAL64 = get_cop1_reg64(RDREG); break; + case 0x02: /* CFCz */ if (RTREG) RTVAL64 = (INT32)get_cop1_creg(RDREG); break; + case 0x04: /* MTCz */ set_cop1_reg32(RDREG, RTVAL32); break; + case 0x05: /* DMTCz */ set_cop1_reg64(RDREG, RTVAL64); break; + case 0x06: /* CTCz */ set_cop1_creg(RDREG, RTVAL32); break; + case 0x08: /* BC */ + switch ((op >> 16) & 3) + { + case 0x00: /* BCzF */ if (!GET_FCC((op >> 18) & 7)) ADDPC(SIMMVAL); break; + case 0x01: /* BCzT */ if (GET_FCC((op >> 18) & 7)) ADDPC(SIMMVAL); break; + case 0x02: /* BCzFL */ if (!GET_FCC((op >> 18) & 7)) ADDPC(SIMMVAL); else m_core->pc += 4; break; + case 0x03: /* BCzTL */ if (GET_FCC((op >> 18) & 7)) ADDPC(SIMMVAL); else m_core->pc += 4; break; + } + break; + default: + switch (op & 0x3f) + { + case 0x00: + if (IS_SINGLE(op)) /* ADD.S */ + FDVALS_FR1 = FSVALS_FR1 + FTVALS_FR1; + else /* ADD.D */ + FDVALD_FR1 = FSVALD_FR1 + FTVALD_FR1; + break; + + case 0x01: + if (IS_SINGLE(op)) /* SUB.S */ + FDVALS_FR1 = FSVALS_FR1 - FTVALS_FR1; + else /* SUB.D */ + FDVALD_FR1 = FSVALD_FR1 - FTVALD_FR1; + break; + + case 0x02: + if (IS_SINGLE(op)) /* MUL.S */ + FDVALS_FR1 = FSVALS_FR1 * FTVALS_FR1; + else /* MUL.D */ + FDVALD_FR1 = FSVALD_FR1 * FTVALD_FR1; + break; + + case 0x03: + if (IS_SINGLE(op)) /* DIV.S */ + FDVALS_FR1 = FSVALS_FR1 / FTVALS_FR1; + else /* DIV.D */ + FDVALD_FR1 = FSVALD_FR1 / FTVALD_FR1; + break; + + case 0x04: + if (IS_SINGLE(op)) /* SQRT.S */ + FDVALS_FR1 = sqrt(FSVALS_FR1); + else /* SQRT.D */ + FDVALD_FR1 = sqrt(FSVALD_FR1); + break; + + case 0x05: + if (IS_SINGLE(op)) /* ABS.S */ + FDVALS_FR1 = fabs(FSVALS_FR1); + else /* ABS.D */ + FDVALD_FR1 = fabs(FSVALD_FR1); + break; + + case 0x06: + if (IS_SINGLE(op)) /* MOV.S */ + FDVALS_FR1 = FSVALS_FR1; + else /* MOV.D */ + FDVALD_FR1 = FSVALD_FR1; + break; + + case 0x07: + if (IS_SINGLE(op)) /* NEG.S */ + FDVALS_FR1 = -FSVALS_FR1; + else /* NEG.D */ + FDVALD_FR1 = -FSVALD_FR1; + break; + + case 0x08: + if (IS_SINGLE(op)) /* ROUND.L.S */ + { + double temp = FSVALS_FR1; + if (temp < 0) + temp = ceil(temp - 0.5); + else + temp = floor(temp + 0.5); + FDVALL_FR1 = (INT64)temp; + } + else /* ROUND.L.D */ + { + double temp = FSVALD_FR1; + if (temp < 0) + temp = ceil(temp - 0.5); + else + temp = floor(temp + 0.5); + FDVALL_FR1 = (INT64)temp; + } + break; + + case 0x09: + if (IS_SINGLE(op)) /* TRUNC.L.S */ + { + double temp = FSVALS_FR1; + if (temp < 0) + temp = ceil(temp); + else + temp = floor(temp); + FDVALL_FR1 = (INT64)temp; + } + else /* TRUNC.L.D */ + { + double temp = FSVALD_FR1; + if (temp < 0) + temp = ceil(temp); + else + temp = floor(temp); + FDVALL_FR1 = (INT64)temp; + } + break; + + case 0x0a: + if (IS_SINGLE(op)) /* CEIL.L.S */ + dtemp = ceil(FSVALS_FR1); + else /* CEIL.L.D */ + dtemp = ceil(FSVALD_FR1); + FDVALL_FR1 = (INT64)dtemp; + break; + + case 0x0b: + if (IS_SINGLE(op)) /* FLOOR.L.S */ + dtemp = floor(FSVALS_FR1); + else /* FLOOR.L.D */ + dtemp = floor(FSVALD_FR1); + FDVALL_FR1 = (INT64)dtemp; + break; + + case 0x0c: + if (IS_SINGLE(op)) /* ROUND.W.S */ + { + dtemp = FSVALS_FR1; + if (dtemp < 0) + dtemp = ceil(dtemp - 0.5); + else + dtemp = floor(dtemp + 0.5); + FDVALW_FR1 = (INT32)dtemp; + } + else /* ROUND.W.D */ + { + dtemp = FSVALD_FR1; + if (dtemp < 0) + dtemp = ceil(dtemp - 0.5); + else + dtemp = floor(dtemp + 0.5); + FDVALW_FR1 = (INT32)dtemp; + } + break; + + case 0x0d: + if (IS_SINGLE(op)) /* TRUNC.W.S */ + { + dtemp = FSVALS_FR1; + if (dtemp < 0) + dtemp = ceil(dtemp); + else + dtemp = floor(dtemp); + FDVALW_FR1 = (INT32)dtemp; + } + else /* TRUNC.W.D */ + { + dtemp = FSVALD_FR1; + if (dtemp < 0) + dtemp = ceil(dtemp); + else + dtemp = floor(dtemp); + FDVALW_FR1 = (INT32)dtemp; + } + break; + + case 0x0e: + if (IS_SINGLE(op)) /* CEIL.W.S */ + dtemp = ceil(FSVALS_FR1); + else /* CEIL.W.D */ + dtemp = ceil(FSVALD_FR1); + FDVALW_FR1 = (INT32)dtemp; + break; + + case 0x0f: + if (IS_SINGLE(op)) /* FLOOR.W.S */ + dtemp = floor(FSVALS_FR1); + else /* FLOOR.W.D */ + dtemp = floor(FSVALD_FR1); + FDVALW_FR1 = (INT32)dtemp; + break; + + case 0x11: /* R5000 */ + if (GET_FCC((op >> 18) & 7) == ((op >> 16) & 1)) + { + if (IS_SINGLE(op)) /* MOVT/F.S */ + FDVALS_FR1 = FSVALS_FR1; + else /* MOVT/F.D */ + FDVALD_FR1 = FSVALD_FR1; + } + break; + + case 0x12: /* R5000 */ + if (RTVAL64 == 0) + { + if (IS_SINGLE(op)) /* MOVZ.S */ + FDVALS_FR1 = FSVALS_FR1; + else /* MOVZ.D */ + FDVALD_FR1 = FSVALD_FR1; + } + break; + + case 0x13: /* R5000 */ + if (RTVAL64 != 0) + { + if (IS_SINGLE(op)) /* MOVN.S */ + FDVALS_FR1 = FSVALS_FR1; + else /* MOVN.D */ + FDVALD_FR1 = FSVALD_FR1; + } + break; + + case 0x15: /* R5000 */ + if (IS_SINGLE(op)) /* RECIP.S */ + FDVALS_FR1 = 1.0f / FSVALS_FR1; + else /* RECIP.D */ + FDVALD_FR1 = 1.0 / FSVALD_FR1; + break; + + case 0x16: /* R5000 */ + if (IS_SINGLE(op)) /* RSQRT.S */ + FDVALS_FR1 = 1.0f / sqrt(FSVALS_FR1); + else /* RSQRT.D */ + FDVALD_FR1 = 1.0 / sqrt(FSVALD_FR1); + break; + + case 0x20: + if (IS_INTEGRAL(op)) + { + if (IS_SINGLE(op)) /* CVT.S.W */ + FDVALS_FR1 = (INT32)FSVALW_FR1; + else /* CVT.S.L */ + FDVALS_FR1 = (INT64)FSVALL_FR1; + } + else /* CVT.S.D */ + FDVALS_FR1 = FSVALD_FR1; + break; + + case 0x21: + if (IS_INTEGRAL(op)) + { + if (IS_SINGLE(op)) /* CVT.D.W */ + FDVALD_FR1 = (INT32)FSVALW_FR1; + else /* CVT.D.L */ + FDVALD_FR1 = (INT64)FSVALL_FR1; + } + else /* CVT.D.S */ + FDVALD_FR1 = FSVALS_FR1; + break; + + case 0x24: + if (IS_SINGLE(op)) /* CVT.W.S */ + FDVALW_FR1 = (INT32)FSVALS_FR1; + else + FDVALW_FR1 = (INT32)FSVALD_FR1; + break; + + case 0x25: + if (IS_SINGLE(op)) /* CVT.L.S */ + FDVALL_FR1 = (INT64)FSVALS_FR1; + else /* CVT.L.D */ + FDVALL_FR1 = (INT64)FSVALD_FR1; + break; + + case 0x30: + case 0x38: + if (IS_SINGLE(op)) /* C.F.S */ + SET_FCC((op >> 8) & 7, 0); + else /* C.F.D */ + SET_FCC((op >> 8) & 7, 0); + break; + + case 0x31: + case 0x39: + if (IS_SINGLE(op)) /* C.UN.S */ + SET_FCC((op >> 8) & 7, 0); + else /* C.UN.D */ + SET_FCC((op >> 8) & 7, 0); + break; + + case 0x32: + case 0x3a: + if (IS_SINGLE(op)) /* C.EQ.S */ + SET_FCC((op >> 8) & 7, (FSVALS_FR1 == FTVALS_FR1)); + else /* C.EQ.D */ + SET_FCC((op >> 8) & 7, (FSVALD_FR1 == FTVALD_FR1)); + break; + + case 0x33: + case 0x3b: + if (IS_SINGLE(op)) /* C.UEQ.S */ + SET_FCC((op >> 8) & 7, (FSVALS_FR1 == FTVALS_FR1)); + else /* C.UEQ.D */ + SET_FCC((op >> 8) & 7, (FSVALD_FR1 == FTVALD_FR1)); + break; + + case 0x34: + case 0x3c: + if (IS_SINGLE(op)) /* C.OLT.S */ + SET_FCC((op >> 8) & 7, (FSVALS_FR1 < FTVALS_FR1)); + else /* C.OLT.D */ + SET_FCC((op >> 8) & 7, (FSVALD_FR1 < FTVALD_FR1)); + break; + + case 0x35: + case 0x3d: + if (IS_SINGLE(op)) /* C.ULT.S */ + SET_FCC((op >> 8) & 7, (FSVALS_FR1 < FTVALS_FR1)); + else /* C.ULT.D */ + SET_FCC((op >> 8) & 7, (FSVALD_FR1 < FTVALD_FR1)); + break; + + case 0x36: + case 0x3e: + if (IS_SINGLE(op)) /* C.OLE.S */ + SET_FCC((op >> 8) & 7, (FSVALS_FR1 <= FTVALS_FR1)); + else /* C.OLE.D */ + SET_FCC((op >> 8) & 7, (FSVALD_FR1 <= FTVALD_FR1)); + break; + + case 0x37: + case 0x3f: + if (IS_SINGLE(op)) /* C.ULE.S */ + SET_FCC((op >> 8) & 7, (FSVALS_FR1 <= FTVALS_FR1)); + else /* C.ULE.D */ + SET_FCC((op >> 8) & 7, (FSVALD_FR1 <= FTVALD_FR1)); + break; + + default: + fprintf(stderr, "cop1 %X\n", op); + break; + } + break; + } +} + + + +/*************************************************************************** + COP1X (FPU EXTRA) EXECUTION HANDLING +***************************************************************************/ + +void mips3_device::handle_cop1x_fr0(UINT32 op) +{ + UINT64 temp64; + UINT32 temp; + + if (!(SR & SR_COP1)) + { + m_badcop_value = 1; + generate_exception(EXCEPTION_BADCOP, 1); + } + + switch (op & 0x3f) + { + case 0x00: /* LWXC1 */ + if (RWORD(RSVAL32 + RTVAL32, &temp)) FDVALW_FR0 = temp; + break; + + case 0x01: /* LDXC1 */ + if (RDOUBLE(RSVAL32 + RTVAL32, &temp64)) FDVALL_FR0 = temp64; + break; + + case 0x08: /* SWXC1 */ + WWORD(RSVAL32 + RTVAL32, get_cop1_reg32(FDREG)); + break; + + case 0x09: /* SDXC1 */ + WDOUBLE(RSVAL32 + RTVAL32, get_cop1_reg64(FDREG)); + break; + + case 0x0f: /* PREFX */ + break; + + case 0x20: /* MADD.S */ + FDVALS_FR0 = FSVALS_FR0 * FTVALS_FR0 + FRVALS_FR0; + break; + + case 0x21: /* MADD.D */ + FDVALD_FR0 = FSVALD_FR0 * FTVALD_FR0 + FRVALD_FR0; + break; + + case 0x28: /* MSUB.S */ + FDVALS_FR0 = FSVALS_FR0 * FTVALS_FR0 - FRVALS_FR0; + break; + + case 0x29: /* MSUB.D */ + FDVALD_FR0 = FSVALD_FR0 * FTVALD_FR0 - FRVALD_FR0; + break; + + case 0x30: /* NMADD.S */ + FDVALS_FR0 = -(FSVALS_FR0 * FTVALS_FR0 + FRVALS_FR0); + break; + + case 0x31: /* NMADD.D */ + FDVALD_FR0 = -(FSVALD_FR0 * FTVALD_FR0 + FRVALD_FR0); + break; + + case 0x38: /* NMSUB.S */ + FDVALS_FR0 = -(FSVALS_FR0 * FTVALS_FR0 - FRVALS_FR0); + break; + + case 0x39: /* NMSUB.D */ + FDVALD_FR0 = -(FSVALD_FR0 * FTVALD_FR0 - FRVALD_FR0); + break; + + case 0x24: /* MADD.W */ + case 0x25: /* MADD.L */ + case 0x2c: /* MSUB.W */ + case 0x2d: /* MSUB.L */ + case 0x34: /* NMADD.W */ + case 0x35: /* NMADD.L */ + case 0x3c: /* NMSUB.W */ + case 0x3d: /* NMSUB.L */ + default: + fprintf(stderr, "cop1x %X\n", op); + break; + } +} + +void mips3_device::handle_cop1x_fr1(UINT32 op) +{ + UINT64 temp64; + UINT32 temp; + + if (!(SR & SR_COP1)) + { + m_badcop_value = 1; + generate_exception(EXCEPTION_BADCOP, 1); + } + + switch (op & 0x3f) + { + case 0x00: /* LWXC1 */ + if (RWORD(RSVAL32 + RTVAL32, &temp)) FDVALW_FR1 = temp; + break; + + case 0x01: /* LDXC1 */ + if (RDOUBLE(RSVAL32 + RTVAL32, &temp64)) FDVALL_FR1 = temp64; + break; + + case 0x08: /* SWXC1 */ + WWORD(RSVAL32 + RTVAL32, get_cop1_reg32(FDREG)); + break; + + case 0x09: /* SDXC1 */ + WDOUBLE(RSVAL32 + RTVAL32, get_cop1_reg64(FDREG)); + break; + + case 0x0f: /* PREFX */ + break; + + case 0x20: /* MADD.S */ + FDVALS_FR1 = FSVALS_FR1 * FTVALS_FR1 + FRVALS_FR1; + break; + + case 0x21: /* MADD.D */ + FDVALD_FR1 = FSVALD_FR1 * FTVALD_FR1 + FRVALD_FR1; + break; + + case 0x28: /* MSUB.S */ + FDVALS_FR1 = FSVALS_FR1 * FTVALS_FR1 - FRVALS_FR1; + break; + + case 0x29: /* MSUB.D */ + FDVALD_FR1 = FSVALD_FR1 * FTVALD_FR1 - FRVALD_FR1; + break; + + case 0x30: /* NMADD.S */ + FDVALS_FR1 = -(FSVALS_FR1 * FTVALS_FR1 + FRVALS_FR1); + break; + + case 0x31: /* NMADD.D */ + FDVALD_FR1 = -(FSVALD_FR1 * FTVALD_FR1 + FRVALD_FR1); + break; + + case 0x38: /* NMSUB.S */ + FDVALS_FR1 = -(FSVALS_FR1 * FTVALS_FR1 - FRVALS_FR1); + break; + + case 0x39: /* NMSUB.D */ + FDVALD_FR1 = -(FSVALD_FR1 * FTVALD_FR1 - FRVALD_FR1); + break; + + case 0x24: /* MADD.W */ + case 0x25: /* MADD.L */ + case 0x2c: /* MSUB.W */ + case 0x2d: /* MSUB.L */ + case 0x34: /* NMADD.W */ + case 0x35: /* NMADD.L */ + case 0x3c: /* NMSUB.W */ + case 0x3d: /* NMSUB.L */ + default: + fprintf(stderr, "cop1x %X\n", op); + break; + } +} + + + +/*************************************************************************** + COP2 (CUSTOM) EXECUTION HANDLING +***************************************************************************/ + +inline UINT64 mips3_device::get_cop2_reg(int idx) +{ + return m_core->cpr[2][idx]; +} + +inline void mips3_device::set_cop2_reg(int idx, UINT64 val) +{ + m_core->cpr[2][idx] = val; +} + +inline UINT64 mips3_device::get_cop2_creg(int idx) +{ + return m_core->ccr[2][idx]; +} + +inline void mips3_device::set_cop2_creg(int idx, UINT64 val) +{ + m_core->ccr[2][idx] = val; +} + +void mips3_device::handle_cop2(UINT32 op) +{ + if (!(SR & SR_COP2)) + { + m_badcop_value = 2; + generate_exception(EXCEPTION_BADCOP, 1); + } + + switch (RSREG) + { + case 0x00: /* MFCz */ if (RTREG) RTVAL64 = (INT32)get_cop2_reg(RDREG); break; + case 0x01: /* DMFCz */ if (RTREG) RTVAL64 = get_cop2_reg(RDREG); break; + case 0x02: /* CFCz */ if (RTREG) RTVAL64 = (INT32)get_cop2_creg(RDREG); break; + case 0x04: /* MTCz */ set_cop2_reg(RDREG, RTVAL32); break; + case 0x05: /* DMTCz */ set_cop2_reg(RDREG, RTVAL64); break; + case 0x06: /* CTCz */ set_cop2_creg(RDREG, RTVAL32); break; + case 0x08: /* BC */ + switch (RTREG) + { + case 0x00: /* BCzF */ if (!m_cf[2]) ADDPC(SIMMVAL); break; + case 0x01: /* BCzF */ if (m_cf[2]) ADDPC(SIMMVAL); break; + case 0x02: /* BCzFL */ invalid_instruction(op); break; + case 0x03: /* BCzTL */ invalid_instruction(op); break; + default: invalid_instruction(op); break; + } + break; + case 0x10: + case 0x11: + case 0x12: + case 0x13: + case 0x14: + case 0x15: + case 0x16: + case 0x17: + case 0x18: + case 0x19: + case 0x1a: + case 0x1b: + case 0x1c: + case 0x1d: + case 0x1e: + case 0x1f: /* COP */ invalid_instruction(op); break; + default: invalid_instruction(op); break; + } +} + + + +/*************************************************************************** + CORE EXECUTION LOOP +***************************************************************************/ + +void mips3_device::handle_regimm(UINT32 op) +{ + switch (RTREG) + { + case 0x00: /* BLTZ */ if ((INT64)RSVAL64 < 0) ADDPC(SIMMVAL); break; + case 0x01: /* BGEZ */ if ((INT64)RSVAL64 >= 0) ADDPC(SIMMVAL); break; + case 0x02: /* BLTZL */ if ((INT64)RSVAL64 < 0) ADDPC(SIMMVAL); else m_core->pc += 4; break; + case 0x03: /* BGEZL */ if ((INT64)RSVAL64 >= 0) ADDPC(SIMMVAL); else m_core->pc += 4; break; + case 0x08: /* TGEI */ if ((INT64)RSVAL64 >= SIMMVAL) generate_exception(EXCEPTION_TRAP, 1); break; + case 0x09: /* TGEIU */ if (RSVAL64 >= UIMMVAL) generate_exception(EXCEPTION_TRAP, 1); break; + case 0x0a: /* TLTI */ if ((INT64)RSVAL64 < SIMMVAL) generate_exception(EXCEPTION_TRAP, 1); break; + case 0x0b: /* TLTIU */ if (RSVAL64 >= UIMMVAL) generate_exception(EXCEPTION_TRAP, 1); break; + case 0x0c: /* TEQI */ if (RSVAL64 == UIMMVAL) generate_exception(EXCEPTION_TRAP, 1); break; + case 0x0e: /* TNEI */ if (RSVAL64 != UIMMVAL) generate_exception(EXCEPTION_TRAP, 1); break; + case 0x10: /* BLTZAL */ if ((INT64)RSVAL64 < 0) ADDPCL(SIMMVAL,31); break; + case 0x11: /* BGEZAL */ if ((INT64)RSVAL64 >= 0) ADDPCL(SIMMVAL,31); break; + case 0x12: /* BLTZALL */ if ((INT64)RSVAL64 < 0) ADDPCL(SIMMVAL,31) else m_core->pc += 4; break; + case 0x13: /* BGEZALL */ if ((INT64)RSVAL64 >= 0) ADDPCL(SIMMVAL,31) else m_core->pc += 4; break; + default: /* ??? */ invalid_instruction(op); break; + } +} + +void mips3_device::handle_special(UINT32 op) +{ + switch (op & 63) + { + case 0x00: /* SLL */ if (RDREG) RDVAL64 = (INT32)(RTVAL32 << SHIFT); break; + case 0x01: /* MOVF - R5000*/if (RDREG && GET_FCC((op >> 18) & 7) == ((op >> 16) & 1)) RDVAL64 = RSVAL64; break; + case 0x02: /* SRL */ if (RDREG) RDVAL64 = (INT32)(RTVAL32 >> SHIFT); break; + case 0x03: /* SRA */ if (RDREG) RDVAL64 = (INT32)RTVAL32 >> SHIFT; break; + case 0x04: /* SLLV */ if (RDREG) RDVAL64 = (INT32)(RTVAL32 << (RSVAL32 & 31)); break; + case 0x06: /* SRLV */ if (RDREG) RDVAL64 = (INT32)(RTVAL32 >> (RSVAL32 & 31)); break; + case 0x07: /* SRAV */ if (RDREG) RDVAL64 = (INT32)RTVAL32 >> (RSVAL32 & 31); break; + case 0x08: /* JR */ SETPC(RSVAL32); break; + case 0x09: /* JALR */ SETPCL(RSVAL32,RDREG); break; + case 0x0a: /* MOVZ - R5000 */if (RTVAL64 == 0) { if (RDREG) RDVAL64 = RSVAL64; } break; + case 0x0b: /* MOVN - R5000 */if (RTVAL64 != 0) { if (RDREG) RDVAL64 = RSVAL64; } break; + case 0x0c: /* SYSCALL */ generate_exception(EXCEPTION_SYSCALL, 1); break; + case 0x0d: /* BREAK */ generate_exception(EXCEPTION_BREAK, 1); break; + case 0x0f: /* SYNC */ /* effective no-op */ break; + case 0x10: /* MFHI */ if (RDREG) RDVAL64 = HIVAL64; break; + case 0x11: /* MTHI */ HIVAL64 = RSVAL64; break; + case 0x12: /* MFLO */ if (RDREG) RDVAL64 = LOVAL64; break; + case 0x13: /* MTLO */ LOVAL64 = RSVAL64; break; + case 0x14: /* DSLLV */ if (RDREG) RDVAL64 = RTVAL64 << (RSVAL32 & 63); break; + case 0x16: /* DSRLV */ if (RDREG) RDVAL64 = RTVAL64 >> (RSVAL32 & 63); break; + case 0x17: /* DSRAV */ if (RDREG) RDVAL64 = (INT64)RTVAL64 >> (RSVAL32 & 63); break; + case 0x18: /* MULT */ + { + UINT64 temp64 = (INT64)(INT32)RSVAL32 * (INT64)(INT32)RTVAL32; + LOVAL64 = (INT32)temp64; + HIVAL64 = (INT32)(temp64 >> 32); + m_core->icount -= 3; + break; + } + case 0x19: /* MULTU */ + { + UINT64 temp64 = (UINT64)RSVAL32 * (UINT64)RTVAL32; + LOVAL64 = (INT32)temp64; + HIVAL64 = (INT32)(temp64 >> 32); + m_core->icount -= 3; + break; + } + case 0x1a: /* DIV */ + if (RTVAL32) + { + LOVAL64 = (INT32)((INT32)RSVAL32 / (INT32)RTVAL32); + HIVAL64 = (INT32)((INT32)RSVAL32 % (INT32)RTVAL32); + } + m_core->icount -= 35; + break; + case 0x1b: /* DIVU */ + if (RTVAL32) + { + LOVAL64 = (INT32)(RSVAL32 / RTVAL32); + HIVAL64 = (INT32)(RSVAL32 % RTVAL32); + } + m_core->icount -= 35; + break; + case 0x1c: /* DMULT */ + { + UINT64 temp64 = (INT64)RSVAL64 * (INT64)RTVAL64; + LOVAL64 = temp64; + HIVAL64 = (INT64)temp64 >> 63; + m_core->icount -= 7; + break; + } + case 0x1d: /* DMULTU */ + { + UINT64 temp64 = (UINT64)RSVAL64 * (UINT64)RTVAL64; + LOVAL64 = temp64; + HIVAL64 = 0; + m_core->icount -= 7; + break; + } + case 0x1e: /* DDIV */ + if (RTVAL64) + { + LOVAL64 = (INT64)RSVAL64 / (INT64)RTVAL64; + HIVAL64 = (INT64)RSVAL64 % (INT64)RTVAL64; + } + m_core->icount -= 67; + break; + case 0x1f: /* DDIVU */ + if (RTVAL64) + { + LOVAL64 = RSVAL64 / RTVAL64; + HIVAL64 = RSVAL64 % RTVAL64; + } + m_core->icount -= 67; + break; + case 0x20: /* ADD */ + if (ENABLE_OVERFLOWS && RSVAL32 > ~RTVAL32) generate_exception(EXCEPTION_OVERFLOW, 1); + else if (RDREG) RDVAL64 = (INT32)(RSVAL32 + RTVAL32); + break; + case 0x21: /* ADDU */ if (RDREG) RDVAL64 = (INT32)(RSVAL32 + RTVAL32); break; + case 0x22: /* SUB */ + if (ENABLE_OVERFLOWS && RSVAL32 < RTVAL32) generate_exception(EXCEPTION_OVERFLOW, 1); + else if (RDREG) RDVAL64 = (INT32)(RSVAL32 - RTVAL32); + break; + case 0x23: /* SUBU */ if (RDREG) RDVAL64 = (INT32)(RSVAL32 - RTVAL32); break; + case 0x24: /* AND */ if (RDREG) RDVAL64 = RSVAL64 & RTVAL64; break; + case 0x25: /* OR */ if (RDREG) RDVAL64 = RSVAL64 | RTVAL64; break; + case 0x26: /* XOR */ if (RDREG) RDVAL64 = RSVAL64 ^ RTVAL64; break; + case 0x27: /* NOR */ if (RDREG) RDVAL64 = ~(RSVAL64 | RTVAL64); break; + case 0x2a: /* SLT */ if (RDREG) RDVAL64 = (INT64)RSVAL64 < (INT64)RTVAL64; break; + case 0x2b: /* SLTU */ if (RDREG) RDVAL64 = (UINT64)RSVAL64 < (UINT64)RTVAL64; break; + case 0x2c: /* DADD */ + if (ENABLE_OVERFLOWS && RSVAL64 > ~RTVAL64) generate_exception(EXCEPTION_OVERFLOW, 1); + else if (RDREG) RDVAL64 = RSVAL64 + RTVAL64; + break; + case 0x2d: /* DADDU */ if (RDREG) RDVAL64 = RSVAL64 + RTVAL64; break; + case 0x2e: /* DSUB */ + if (ENABLE_OVERFLOWS && RSVAL64 < RTVAL64) generate_exception(EXCEPTION_OVERFLOW, 1); + else if (RDREG) RDVAL64 = RSVAL64 - RTVAL64; + break; + case 0x2f: /* DSUBU */ if (RDREG) RDVAL64 = RSVAL64 - RTVAL64; break; + case 0x30: /* TGE */ if ((INT64)RSVAL64 >= (INT64)RTVAL64) generate_exception(EXCEPTION_TRAP, 1); break; + case 0x31: /* TGEU */ if (RSVAL64 >= RTVAL64) generate_exception(EXCEPTION_TRAP, 1); break; + case 0x32: /* TLT */ if ((INT64)RSVAL64 < (INT64)RTVAL64) generate_exception(EXCEPTION_TRAP, 1); break; + case 0x33: /* TLTU */ if (RSVAL64 < RTVAL64) generate_exception(EXCEPTION_TRAP, 1); break; + case 0x34: /* TEQ */ if (RSVAL64 == RTVAL64) generate_exception(EXCEPTION_TRAP, 1); break; + case 0x36: /* TNE */ if (RSVAL64 != RTVAL64) generate_exception(EXCEPTION_TRAP, 1); break; + case 0x38: /* DSLL */ if (RDREG) RDVAL64 = RTVAL64 << SHIFT; break; + case 0x3a: /* DSRL */ if (RDREG) RDVAL64 = RTVAL64 >> SHIFT; break; + case 0x3b: /* DSRA */ if (RDREG) RDVAL64 = (INT64)RTVAL64 >> SHIFT; break; + case 0x3c: /* DSLL32 */ if (RDREG) RDVAL64 = RTVAL64 << (SHIFT + 32); break; + case 0x3e: /* DSRL32 */ if (RDREG) RDVAL64 = RTVAL64 >> (SHIFT + 32); break; + case 0x3f: /* DSRA32 */ if (RDREG) RDVAL64 = (INT64)RTVAL64 >> (SHIFT + 32); break; + default: /* ??? */ invalid_instruction(op); break; + } +} + +void mips3_device::execute_run() +{ + if (m_isdrc) + { + int execute_result; + + /* reset the cache if dirty */ + if (m_cache_dirty) + code_flush_cache(); + m_cache_dirty = FALSE; + + /* execute */ + do + { + /* run as much as we can */ + execute_result = m_drcuml->execute(*m_entry); + + /* if we need to recompile, do it */ + if (execute_result == EXECUTE_MISSING_CODE) + { + code_compile_block(m_core->mode, m_core->pc); + } + else if (execute_result == EXECUTE_UNMAPPED_CODE) + { + fatalerror("Attempted to execute unmapped code at PC=%08X\n", m_core->pc); + } + else if (execute_result == EXECUTE_RESET_CACHE) + { + code_flush_cache(); + } + + } while (execute_result != EXECUTE_OUT_OF_CYCLES); + + return; + } + + /* count cycles and interrupt cycles */ + m_core->icount -= m_interrupt_cycles; + m_interrupt_cycles = 0; + + /* update timers & such */ + mips3com_update_cycle_counting(); + + /* check for IRQs */ + check_irqs(); + + /* core execution loop */ + do + { + UINT32 op; + UINT64 temp64 = 0; + UINT32 temp; + + /* debugging */ + m_ppc = m_core->pc; + debugger_instruction_hook(this, m_core->pc); + + /* instruction fetch */ + if(!RWORD(m_core->pc, &op)) + { + continue; + } + + /* adjust for next PC */ + if (m_nextpc != ~0) + { + m_core->pc = m_nextpc; + m_nextpc = ~0; + } + else + m_core->pc += 4; + + /* parse the instruction */ + const int switch_val = (op >> 26) & 0x3f; + + switch (switch_val) + { + case 0x00: /* SPECIAL */ + handle_special(op); + break; + + case 0x01: /* REGIMM */ + handle_regimm(op); + break; + + case 0x02: /* J */ ABSPC(LIMMVAL); break; + case 0x03: /* JAL */ ABSPCL(LIMMVAL,31); break; + case 0x04: /* BEQ */ if (RSVAL64 == RTVAL64) ADDPC(SIMMVAL); break; + case 0x05: /* BNE */ if (RSVAL64 != RTVAL64) ADDPC(SIMMVAL); break; + case 0x06: /* BLEZ */ if ((INT64)RSVAL64 <= 0) ADDPC(SIMMVAL); break; + case 0x07: /* BGTZ */ if ((INT64)RSVAL64 > 0) ADDPC(SIMMVAL); break; + case 0x08: /* ADDI */ + if (ENABLE_OVERFLOWS && RSVAL32 > ~SIMMVAL) generate_exception(EXCEPTION_OVERFLOW, 1); + else if (RTREG) RTVAL64 = (INT32)(RSVAL32 + SIMMVAL); + break; + case 0x09: /* ADDIU */ if (RTREG) RTVAL64 = (INT32)(RSVAL32 + SIMMVAL); break; + case 0x0a: /* SLTI */ if (RTREG) RTVAL64 = (INT64)RSVAL64 < (INT64)SIMMVAL; break; + case 0x0b: /* SLTIU */ if (RTREG) RTVAL64 = (UINT64)RSVAL64 < (UINT64)SIMMVAL; break; + case 0x0c: /* ANDI */ if (RTREG) RTVAL64 = RSVAL64 & UIMMVAL; break; + case 0x0d: /* ORI */ if (RTREG) RTVAL64 = RSVAL64 | UIMMVAL; break; + case 0x0e: /* XORI */ if (RTREG) RTVAL64 = RSVAL64 ^ UIMMVAL; break; + case 0x0f: /* LUI */ if (RTREG) RTVAL64 = (INT32)(UIMMVAL << 16); break; + case 0x10: /* COP0 */ handle_cop0(op); break; + case 0x11: /* COP1 */ if (IS_FR0) handle_cop1_fr0(op); else handle_cop1_fr1(op); break; + case 0x12: /* COP2 */ handle_cop2(op); break; + case 0x13: /* COP1X - R5000 */if (IS_FR0) handle_cop1x_fr0(op); else handle_cop1x_fr1(op); break; + case 0x14: /* BEQL */ if (RSVAL64 == RTVAL64) ADDPC(SIMMVAL); else m_core->pc += 4; break; + case 0x15: /* BNEL */ if (RSVAL64 != RTVAL64) ADDPC(SIMMVAL); else m_core->pc += 4; break; + case 0x16: /* BLEZL */ if ((INT64)RSVAL64 <= 0) ADDPC(SIMMVAL); else m_core->pc += 4; break; + case 0x17: /* BGTZL */ if ((INT64)RSVAL64 > 0) ADDPC(SIMMVAL); else m_core->pc += 4; break; + case 0x18: /* DADDI */ + if (ENABLE_OVERFLOWS && (INT64)RSVAL64 > ~SIMMVAL) generate_exception(EXCEPTION_OVERFLOW, 1); + else if (RTREG) RTVAL64 = RSVAL64 + (INT64)SIMMVAL; + break; + case 0x19: /* DADDIU */ if (RTREG) RTVAL64 = RSVAL64 + (UINT64)SIMMVAL; break; + case 0x1a: /* LDL */ (this->*m_ldl)(op); break; + case 0x1b: /* LDR */ (this->*m_ldr)(op); break; + case 0x1c: /* IDT-specific opcodes: mad/madu/mul on R4640/4650, msub on RC32364 */ + switch (op & 0x1f) + { + case 2: /* MUL */ + RDVAL64 = (INT32)((INT32)RSVAL32 * (INT32)RTVAL32); + m_core->icount -= 3; + break; + default: invalid_instruction(op); + } + break; + case 0x20: /* LB */ if (RBYTE(SIMMVAL+RSVAL32, &temp) && RTREG) RTVAL64 = (INT8)temp; break; + case 0x21: /* LH */ if (RHALF(SIMMVAL+RSVAL32, &temp) && RTREG) RTVAL64 = (INT16)temp; break; + case 0x22: /* LWL */ (this->*m_lwl)(op); break; + case 0x23: /* LW */ if (RWORD(SIMMVAL+RSVAL32, &temp) && RTREG) RTVAL64 = (INT32)temp; break; + case 0x24: /* LBU */ if (RBYTE(SIMMVAL+RSVAL32, &temp) && RTREG) RTVAL64 = (UINT8)temp; break; + case 0x25: /* LHU */ if (RHALF(SIMMVAL+RSVAL32, &temp) && RTREG) RTVAL64 = (UINT16)temp; break; + case 0x26: /* LWR */ (this->*m_lwr)(op); break; + case 0x27: /* LWU */ if (RWORD(SIMMVAL+RSVAL32, &temp) && RTREG) RTVAL64 = (UINT32)temp; break; + case 0x28: /* SB */ WBYTE(SIMMVAL+RSVAL32, RTVAL32); break; + case 0x29: /* SH */ WHALF(SIMMVAL+RSVAL32, RTVAL32); break; + case 0x2a: /* SWL */ (this->*m_swl)(op); break; + case 0x2b: /* SW */ WWORD(SIMMVAL+RSVAL32, RTVAL32); break; + case 0x2c: /* SDL */ (this->*m_sdl)(op); break; + case 0x2d: /* SDR */ (this->*m_sdr)(op); break; + case 0x2e: /* SWR */ (this->*m_swr)(op); break; + case 0x2f: /* CACHE */ /* effective no-op */ break; + case 0x30: /* LL */ if (RWORD(SIMMVAL+RSVAL32, &temp) && RTREG) RTVAL64 = (UINT32)temp; m_ll_value = RTVAL32; break; + case 0x31: /* LWC1 */ + if (!(SR & SR_COP1)) + { + m_badcop_value = 1; + generate_exception(EXCEPTION_BADCOP, 1); + } + if (RWORD(SIMMVAL+RSVAL32, &temp)) set_cop1_reg32(RTREG, temp); break; + case 0x32: /* LWC2 */ if (RWORD(SIMMVAL+RSVAL32, &temp)) set_cop2_reg(RTREG, temp); break; + case 0x33: /* PREF */ /* effective no-op */ break; + case 0x34: /* LLD */ if (RDOUBLE(SIMMVAL+RSVAL32, &temp64) && RTREG) RTVAL64 = temp64; m_lld_value = temp64; break; + case 0x35: /* LDC1 */ + if (!(SR & SR_COP1)) + { + m_badcop_value = 1; + generate_exception(EXCEPTION_BADCOP, 1); + } + if (RDOUBLE(SIMMVAL+RSVAL32, &temp64)) set_cop1_reg64(RTREG, temp64); break; + case 0x36: /* LDC2 */ if (RDOUBLE(SIMMVAL+RSVAL32, &temp64)) set_cop2_reg(RTREG, temp64); break; + case 0x37: /* LD */ if (RDOUBLE(SIMMVAL+RSVAL32, &temp64) && RTREG) RTVAL64 = temp64; break; + case 0x38: /* SC */ if (RWORD(SIMMVAL+RSVAL32, &temp) && RTREG) + { + if (temp == m_ll_value) + { + WWORD(SIMMVAL+RSVAL32, RTVAL32); + RTVAL64 = (UINT32)1; + } + else + { + RTVAL64 = (UINT32)0; + } + } + break; + case 0x39: /* SWC1 */ + if (!(SR & SR_COP1)) + { + m_badcop_value = 1; + generate_exception(EXCEPTION_BADCOP, 1); + } + WWORD(SIMMVAL+RSVAL32, get_cop1_reg32(RTREG)); break; + case 0x3a: /* SWC2 */ WWORD(SIMMVAL+RSVAL32, get_cop2_reg(RTREG)); break; + case 0x3b: /* SWC3 */ invalid_instruction(op); break; + case 0x3c: /* SCD */ if (RDOUBLE(SIMMVAL+RSVAL32, &temp64) && RTREG) + { + if (temp64 == m_lld_value) + { + WDOUBLE(SIMMVAL+RSVAL32, RTVAL64); + RTVAL64 = 1; + } + else + { + RTVAL64 = 0; + } + } + break; + case 0x3d: /* SDC1 */ + if (!(SR & SR_COP1)) + { + m_badcop_value = 1; + generate_exception(EXCEPTION_BADCOP, 1); + } + WDOUBLE(SIMMVAL+RSVAL32, get_cop1_reg64(RTREG)); break; + case 0x3e: /* SDC2 */ WDOUBLE(SIMMVAL+RSVAL32, get_cop2_reg(RTREG)); break; + case 0x3f: /* SD */ WDOUBLE(SIMMVAL+RSVAL32, RTVAL64); break; + default: /* ??? */ invalid_instruction(op); break; + } + m_core->icount--; + + } while (m_core->icount > 0 || m_nextpc != ~0); + + m_core->icount -= m_interrupt_cycles; + m_interrupt_cycles = 0; +} + + + +/*************************************************************************** + COMPLEX OPCODE IMPLEMENTATIONS +***************************************************************************/ + +void mips3_device::lwl_be(UINT32 op) +{ + offs_t offs = SIMMVAL + RSVAL32; + int shift = 8 * (offs & 3); + UINT32 mask = 0xffffffffUL << shift; + UINT32 temp; + + if (RWORD_MASKED(offs & ~3, &temp, mask >> shift) && RTREG) + RTVAL64 = (INT32)((RTVAL32 & ~mask) | (temp << shift)); +} + +void mips3_device::lwr_be(UINT32 op) +{ + offs_t offs = SIMMVAL + RSVAL32; + int shift = 8 * (~offs & 3); + UINT32 mask = 0xffffffffUL >> shift; + UINT32 temp; + + if (RWORD_MASKED(offs & ~3, &temp, mask << shift) && RTREG) + RTVAL64 = (INT32)((RTVAL32 & ~mask) | (temp >> shift)); +} + +void mips3_device::ldl_be(UINT32 op) +{ + offs_t offs = SIMMVAL + RSVAL32; + int shift = 8 * (offs & 7); + UINT64 mask = U64(0xffffffffffffffff) << shift; + UINT64 temp; + + if (RDOUBLE_MASKED(offs & ~7, &temp, mask >> shift) && RTREG) + RTVAL64 = (RTVAL64 & ~mask) | (temp << shift); +} + +void mips3_device::ldr_be(UINT32 op) +{ + offs_t offs = SIMMVAL + RSVAL32; + int shift = 8 * (~offs & 7); + UINT64 mask = U64(0xffffffffffffffff) >> shift; + UINT64 temp; + + if (RDOUBLE_MASKED(offs & ~7, &temp, mask << shift) && RTREG) + RTVAL64 = (RTVAL64 & ~mask) | (temp >> shift); +} + +void mips3_device::swl_be(UINT32 op) +{ + offs_t offs = SIMMVAL + RSVAL32; + int shift = 8 * (offs & 3); + UINT32 mask = 0xffffffffUL >> shift; + WWORD_MASKED(offs & ~3, RTVAL32 >> shift, mask); +} + +void mips3_device::swr_be(UINT32 op) +{ + offs_t offs = SIMMVAL + RSVAL32; + int shift = 8 * (~offs & 3); + UINT32 mask = 0xffffffffUL << shift; + WWORD_MASKED(offs & ~3, RTVAL32 << shift, mask); +} + +void mips3_device::sdl_be(UINT32 op) +{ + offs_t offs = SIMMVAL + RSVAL32; + int shift = 8 * (offs & 7); + UINT64 mask = U64(0xffffffffffffffff) >> shift; + WDOUBLE_MASKED(offs & ~7, RTVAL64 >> shift, mask); +} + +void mips3_device::sdr_be(UINT32 op) +{ + offs_t offs = SIMMVAL + RSVAL32; + int shift = 8 * (~offs & 7); + UINT64 mask = U64(0xffffffffffffffff) << shift; + WDOUBLE_MASKED(offs & ~7, RTVAL64 << shift, mask); +} + + + +void mips3_device::lwl_le(UINT32 op) +{ + offs_t offs = SIMMVAL + RSVAL32; + int shift = 8 * (~offs & 3); + UINT32 mask = 0xffffffffUL << shift; + UINT32 temp; + + if (RWORD_MASKED(offs & ~3, &temp, mask >> shift) && RTREG) + RTVAL64 = (INT32)((RTVAL32 & ~mask) | (temp << shift)); +} + +void mips3_device::lwr_le(UINT32 op) +{ + offs_t offs = SIMMVAL + RSVAL32; + int shift = 8 * (offs & 3); + UINT32 mask = 0xffffffffUL >> shift; + UINT32 temp; + + if (RWORD_MASKED(offs & ~3, &temp, mask << shift) && RTREG) + RTVAL64 = (INT32)((RTVAL32 & ~mask) | (temp >> shift)); +} + +void mips3_device::ldl_le(UINT32 op) +{ + offs_t offs = SIMMVAL + RSVAL32; + int shift = 8 * (~offs & 7); + UINT64 mask = U64(0xffffffffffffffff) << shift; + UINT64 temp; + + if (RDOUBLE_MASKED(offs & ~7, &temp, mask >> shift) && RTREG) + RTVAL64 = (RTVAL64 & ~mask) | (temp << shift); +} + +void mips3_device::ldr_le(UINT32 op) +{ + offs_t offs = SIMMVAL + RSVAL32; + int shift = 8 * (offs & 7); + UINT64 mask = U64(0xffffffffffffffff) >> shift; + UINT64 temp; + + if (RDOUBLE_MASKED(offs & ~7, &temp, mask << shift) && RTREG) + RTVAL64 = (RTVAL64 & ~mask) | (temp >> shift); +} + +void mips3_device::swl_le(UINT32 op) +{ + offs_t offs = SIMMVAL + RSVAL32; + int shift = 8 * (~offs & 3); + UINT32 mask = 0xffffffffUL >> shift; + WWORD_MASKED(offs & ~3, RTVAL32 >> shift, mask); +} + +void mips3_device::swr_le(UINT32 op) +{ + offs_t offs = SIMMVAL + RSVAL32; + int shift = 8 * (offs & 3); + UINT32 mask = 0xffffffffUL << shift; + WWORD_MASKED(offs & ~3, RTVAL32 << shift, mask); +} + +void mips3_device::sdl_le(UINT32 op) +{ + offs_t offs = SIMMVAL + RSVAL32; + int shift = 8 * (~offs & 7); + UINT64 mask = U64(0xffffffffffffffff) >> shift; + WDOUBLE_MASKED(offs & ~7, RTVAL64 >> shift, mask); +} + +void mips3_device::sdr_le(UINT32 op) +{ + offs_t offs = SIMMVAL + RSVAL32; + int shift = 8 * (offs & 7); + UINT64 mask = U64(0xffffffffffffffff) << shift; + WDOUBLE_MASKED(offs & ~7, RTVAL64 << shift, mask); +} diff --git a/src/devices/cpu/mips/mips3.h b/src/devices/cpu/mips/mips3.h new file mode 100644 index 00000000000..b8d9330cffb --- /dev/null +++ b/src/devices/cpu/mips/mips3.h @@ -0,0 +1,781 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + mips3.h + + Interface file for the universal machine language-based + MIPS III/IV emulator. + +***************************************************************************/ + +#pragma once + +#ifndef __MIPS3_H__ +#define __MIPS3_H__ + + +#include "cpu/vtlb.h" +#include "cpu/drcfe.h" +#include "cpu/drcuml.h" +#include "cpu/drcumlsh.h" + + +// NEC VR4300 series is MIPS III with 32-bit address bus and slightly custom COP0/TLB +extern const device_type VR4300BE; +extern const device_type VR4300LE; +// VR4310 = VR4300 with different speed bin +extern const device_type VR4310BE; +extern const device_type VR4310LE; +extern const device_type R4600BE; +extern const device_type R4600LE; +extern const device_type R4650BE; +extern const device_type R4650LE; +extern const device_type R4700BE; +extern const device_type R4700LE; +extern const device_type R5000BE; +extern const device_type R5000LE; +extern const device_type QED5271BE; +extern const device_type QED5271LE; +extern const device_type RM7000BE; +extern const device_type RM7000LE; + + +/*************************************************************************** + REGISTER ENUMERATION +***************************************************************************/ + +enum +{ + MIPS3_PC = 1, + MIPS3_R0, + MIPS3_R1, + MIPS3_R2, + MIPS3_R3, + MIPS3_R4, + MIPS3_R5, + MIPS3_R6, + MIPS3_R7, + MIPS3_R8, + MIPS3_R9, + MIPS3_R10, + MIPS3_R11, + MIPS3_R12, + MIPS3_R13, + MIPS3_R14, + MIPS3_R15, + MIPS3_R16, + MIPS3_R17, + MIPS3_R18, + MIPS3_R19, + MIPS3_R20, + MIPS3_R21, + MIPS3_R22, + MIPS3_R23, + MIPS3_R24, + MIPS3_R25, + MIPS3_R26, + MIPS3_R27, + MIPS3_R28, + MIPS3_R29, + MIPS3_R30, + MIPS3_R31, + MIPS3_HI, + MIPS3_LO, + MIPS3_FPR0, + MIPS3_FPS0, + MIPS3_FPD0, + MIPS3_FPR1, + MIPS3_FPS1, + MIPS3_FPD1, + MIPS3_FPR2, + MIPS3_FPS2, + MIPS3_FPD2, + MIPS3_FPR3, + MIPS3_FPS3, + MIPS3_FPD3, + MIPS3_FPR4, + MIPS3_FPS4, + MIPS3_FPD4, + MIPS3_FPR5, + MIPS3_FPS5, + MIPS3_FPD5, + MIPS3_FPR6, + MIPS3_FPS6, + MIPS3_FPD6, + MIPS3_FPR7, + MIPS3_FPS7, + MIPS3_FPD7, + MIPS3_FPR8, + MIPS3_FPS8, + MIPS3_FPD8, + MIPS3_FPR9, + MIPS3_FPS9, + MIPS3_FPD9, + MIPS3_FPR10, + MIPS3_FPS10, + MIPS3_FPD10, + MIPS3_FPR11, + MIPS3_FPS11, + MIPS3_FPD11, + MIPS3_FPR12, + MIPS3_FPS12, + MIPS3_FPD12, + MIPS3_FPR13, + MIPS3_FPS13, + MIPS3_FPD13, + MIPS3_FPR14, + MIPS3_FPS14, + MIPS3_FPD14, + MIPS3_FPR15, + MIPS3_FPS15, + MIPS3_FPD15, + MIPS3_FPR16, + MIPS3_FPS16, + MIPS3_FPD16, + MIPS3_FPR17, + MIPS3_FPS17, + MIPS3_FPD17, + MIPS3_FPR18, + MIPS3_FPS18, + MIPS3_FPD18, + MIPS3_FPR19, + MIPS3_FPS19, + MIPS3_FPD19, + MIPS3_FPR20, + MIPS3_FPS20, + MIPS3_FPD20, + MIPS3_FPR21, + MIPS3_FPS21, + MIPS3_FPD21, + MIPS3_FPR22, + MIPS3_FPS22, + MIPS3_FPD22, + MIPS3_FPR23, + MIPS3_FPS23, + MIPS3_FPD23, + MIPS3_FPR24, + MIPS3_FPS24, + MIPS3_FPD24, + MIPS3_FPR25, + MIPS3_FPS25, + MIPS3_FPD25, + MIPS3_FPR26, + MIPS3_FPS26, + MIPS3_FPD26, + MIPS3_FPR27, + MIPS3_FPS27, + MIPS3_FPD27, + MIPS3_FPR28, + MIPS3_FPS28, + MIPS3_FPD28, + MIPS3_FPR29, + MIPS3_FPS29, + MIPS3_FPD29, + MIPS3_FPR30, + MIPS3_FPS30, + MIPS3_FPD30, + MIPS3_FPR31, + MIPS3_FPS31, + MIPS3_FPD31, + MIPS3_CCR1_31, + MIPS3_SR, + MIPS3_EPC, + MIPS3_CAUSE, + MIPS3_COUNT, + MIPS3_COMPARE, + MIPS3_INDEX, + MIPS3_RANDOM, + MIPS3_ENTRYHI, + MIPS3_ENTRYLO0, + MIPS3_ENTRYLO1, + MIPS3_PAGEMASK, + MIPS3_WIRED, + MIPS3_BADVADDR +}; + +#define MIPS3_MAX_FASTRAM 3 +#define MIPS3_MAX_HOTSPOTS 16 + +enum +{ + CPUINFO_INT_MIPS3_DRC_OPTIONS = CPUINFO_INT_CPU_SPECIFIC, + + CPUINFO_INT_MIPS3_FASTRAM_SELECT, + CPUINFO_INT_MIPS3_FASTRAM_START, + CPUINFO_INT_MIPS3_FASTRAM_END, + CPUINFO_INT_MIPS3_FASTRAM_READONLY, + + CPUINFO_INT_MIPS3_HOTSPOT_SELECT, + CPUINFO_INT_MIPS3_HOTSPOT_PC, + CPUINFO_INT_MIPS3_HOTSPOT_OPCODE, + CPUINFO_INT_MIPS3_HOTSPOT_CYCLES, + + CPUINFO_PTR_MIPS3_FASTRAM_BASE = CPUINFO_PTR_CPU_SPECIFIC +}; + + + +/*************************************************************************** + INTERRUPT CONSTANTS +***************************************************************************/ + +#define MIPS3_IRQ0 0 /* IRQ0 */ +#define MIPS3_IRQ1 1 /* IRQ1 */ +#define MIPS3_IRQ2 2 /* IRQ2 */ +#define MIPS3_IRQ3 3 /* IRQ3 */ +#define MIPS3_IRQ4 4 /* IRQ4 */ +#define MIPS3_IRQ5 5 /* IRQ5 */ + + + +/*************************************************************************** + STRUCTURES +***************************************************************************/ + +/* MIPS3 TLB entry */ +struct mips3_tlb_entry +{ + UINT64 page_mask; + UINT64 entry_hi; + UINT64 entry_lo[2]; +}; + +/* internal compiler state */ +struct compiler_state +{ + UINT32 cycles; /* accumulated cycles */ + UINT8 checkints; /* need to check interrupts before next instruction */ + UINT8 checksoftints; /* need to check software interrupts before next instruction */ + uml::code_label labelnum; /* index for local labels */ +}; + +#define MIPS3_MAX_TLB_ENTRIES 48 + +#define MCFG_MIPS3_ICACHE_SIZE(_size) \ + mips3_device::set_icache_size(*device, _size); + +#define MCFG_MIPS3_DCACHE_SIZE(_size) \ + mips3_device::set_dcache_size(*device, _size); + +#define MCFG_MIPS3_SYSTEM_CLOCK(_clock) \ + mips3_device::set_system_clock(*device, _clock); + + +class mips3_frontend; + +class mips3_device : public cpu_device +{ + friend class mips3_frontend; + +protected: + /* MIPS flavors */ + enum mips3_flavor + { + /* MIPS III variants */ + MIPS3_TYPE_MIPS_III, + MIPS3_TYPE_VR4300, + MIPS3_TYPE_R4600, + MIPS3_TYPE_R4650, + MIPS3_TYPE_R4700, + + /* MIPS IV variants */ + MIPS3_TYPE_MIPS_IV, + MIPS3_TYPE_R5000, + MIPS3_TYPE_QED5271, + MIPS3_TYPE_RM7000 + }; + +public: + // construction/destruction + mips3_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, mips3_flavor flavor, endianness_t endiannes); + + static void set_icache_size(device_t &device, size_t icache_size) { downcast(device).c_icache_size = icache_size; } + static void set_dcache_size(device_t &device, size_t dcache_size) { downcast(device).c_dcache_size = dcache_size; } + static void set_system_clock(device_t &device, UINT32 system_clock) { downcast(device).c_system_clock = system_clock; } + + TIMER_CALLBACK_MEMBER(compare_int_callback); + + void add_fastram(offs_t start, offs_t end, UINT8 readonly, void *base); + void clear_fastram(UINT32 select_start); + void mips3drc_set_options(UINT32 options); + void mips3drc_add_hotspot(offs_t pc, UINT32 opcode, UINT32 cycles); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_stop(); + + // device_execute_interface overrides + virtual UINT32 execute_min_cycles() const { return 1; } + virtual UINT32 execute_max_cycles() const { return 40; } + virtual UINT32 execute_input_lines() const { return 6; } + virtual void execute_run(); + virtual void execute_set_input(int inputnum, int state); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const { return (spacenum == AS_PROGRAM) ? &m_program_config : NULL; } + virtual bool memory_translate(address_spacenum spacenum, int intention, offs_t &address); + + // device_state_interface overrides + virtual void state_export(const device_state_entry &entry); + void state_string_export(const device_state_entry &entry, std::string &str); + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const { return 4; } + virtual UINT32 disasm_max_opcode_bytes() const { return 4; } + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + + +private: + struct internal_mips3_state + { + /* core registers */ + UINT32 pc; + int icount; + UINT64 r[35]; + + /* COP registers */ + UINT64 cpr[3][32]; + UINT64 ccr[3][32]; + UINT32 llbit; + + UINT32 mode; /* current global mode */ + + /* parameters for subroutines */ + UINT64 numcycles; /* return value from gettotalcycles */ + const char * format; /* format string for print_debug */ + UINT32 arg0; /* print_debug argument 1 */ + UINT32 arg1; /* print_debug argument 2 */ + + UINT64 count_zero_time; + UINT32 compare_armed; + UINT32 jmpdest; /* destination jump target */ + + }; + + address_space_config m_program_config; + mips3_flavor m_flavor; + + /* core state */ + internal_mips3_state *m_core; + + /* internal stuff */ + UINT32 m_ppc; + UINT32 m_nextpc; + UINT32 m_pcbase; + UINT8 m_cf[4][8]; + int m_op; + int m_interrupt_cycles; + UINT32 m_ll_value; + UINT64 m_lld_value; + UINT32 m_badcop_value; + const vtlb_entry *m_tlb_table; + + /* endian-dependent load/store */ + typedef void (mips3_device::*loadstore_func)(UINT32 op); + loadstore_func m_lwl; + loadstore_func m_lwr; + loadstore_func m_swl; + loadstore_func m_swr; + loadstore_func m_ldl; + loadstore_func m_ldr; + loadstore_func m_sdl; + loadstore_func m_sdr; + + address_space *m_program; + direct_read_data *m_direct; + UINT32 c_system_clock; + UINT32 m_cpu_clock; + emu_timer * m_compare_int_timer; + + /* derived info based on flavor */ + UINT32 m_pfnmask; + UINT8 m_tlbentries; + + /* memory accesses */ + bool m_bigendian; + UINT32 m_byte_xor; + UINT32 m_word_xor; + data_accessors m_memory; + + /* cache memory */ + size_t c_icache_size; + size_t c_dcache_size; + + /* MMU */ + vtlb_state * m_vtlb; + mips3_tlb_entry m_tlb[MIPS3_MAX_TLB_ENTRIES]; + + /* fast RAM */ + UINT32 m_fastram_select; + struct + { + offs_t start; /* start of the RAM block */ + offs_t end; /* end of the RAM block */ + UINT8 readonly; /* TRUE if read-only */ + void * base; /* base in memory where the RAM lives */ + UINT8 * offset_base8; /* base in memory where the RAM lives, 8-bit pointer, with the start offset pre-applied */ + UINT16 * offset_base16; /* base in memory where the RAM lives, 16-bit pointer, with the start offset pre-applied */ + UINT32 * offset_base32; /* base in memory where the RAM lives, 32-bit pointer, with the start offset pre-applied */ + } m_fastram[MIPS3_MAX_FASTRAM]; + + UINT32 m_debugger_temp; + + /* core state */ + drc_cache m_cache; /* pointer to the DRC code cache */ + drcuml_state * m_drcuml; /* DRC UML generator state */ + mips3_frontend * m_drcfe; /* pointer to the DRC front-end state */ + UINT32 m_drcoptions; /* configurable DRC options */ + + /* internal stuff */ + UINT8 m_cache_dirty; /* true if we need to flush the cache */ + + /* tables */ + UINT8 m_fpmode[4]; /* FPU mode table */ + + /* register mappings */ + uml::parameter m_regmap[34]; /* parameter to register mappings for all 32 integer registers */ + uml::parameter m_regmaplo[34]; /* parameter to register mappings for all 32 integer registers */ + + /* subroutines */ + uml::code_handle * m_entry; /* entry point */ + uml::code_handle * m_nocode; /* nocode exception handler */ + uml::code_handle * m_out_of_cycles; /* out of cycles exception handler */ + uml::code_handle * m_tlb_mismatch; /* tlb mismatch handler */ + uml::code_handle * m_read8[3]; /* read byte */ + uml::code_handle * m_write8[3]; /* write byte */ + uml::code_handle * m_read16[3]; /* read half */ + uml::code_handle * m_write16[3]; /* write half */ + uml::code_handle * m_read32[3]; /* read word */ + uml::code_handle * m_read32mask[3]; /* read word masked */ + uml::code_handle * m_write32[3]; /* write word */ + uml::code_handle * m_write32mask[3]; /* write word masked */ + uml::code_handle * m_read64[3]; /* read double */ + uml::code_handle * m_read64mask[3]; /* read double masked */ + uml::code_handle * m_write64[3]; /* write double */ + uml::code_handle * m_write64mask[3]; /* write double masked */ + uml::code_handle * m_exception[18/*EXCEPTION_COUNT*/]; /* array of exception handlers */ + uml::code_handle * m_exception_norecover[18/*EXCEPTION_COUNT*/]; /* array of no-recover exception handlers */ + + /* hotspots */ + UINT32 m_hotspot_select; + struct + { + offs_t pc; /* PC to consider */ + UINT32 opcode; /* required opcode at that PC */ + UINT32 cycles; /* number of cycles to eat when hit */ + } m_hotspot[MIPS3_MAX_HOTSPOTS]; + bool m_isdrc; + + + void generate_exception(int exception, int backup); + void generate_tlb_exception(int exception, offs_t address); + void invalid_instruction(UINT32 op); + void check_irqs(); +public: + void mips3com_update_cycle_counting(); + void mips3com_asid_changed(); + void mips3com_tlbr(); + void mips3com_tlbwi(); + void mips3com_tlbwr(); + void mips3com_tlbp(); +private: + UINT32 compute_config_register(); + UINT32 compute_prid_register(); + + void tlb_map_entry(int tlbindex); + void tlb_write_common(int tlbindex); + + bool RBYTE(offs_t address, UINT32 *result); + bool RHALF(offs_t address, UINT32 *result); + bool RWORD(offs_t address, UINT32 *result); + bool RWORD_MASKED(offs_t address, UINT32 *result, UINT32 mem_mask); + bool RDOUBLE(offs_t address, UINT64 *result); + bool RDOUBLE_MASKED(offs_t address, UINT64 *result, UINT64 mem_mask); + void WBYTE(offs_t address, UINT8 data); + void WHALF(offs_t address, UINT16 data); + void WWORD(offs_t address, UINT32 data); + void WWORD_MASKED(offs_t address, UINT32 data, UINT32 mem_mask); + void WDOUBLE(offs_t address, UINT64 data); + void WDOUBLE_MASKED(offs_t address, UINT64 data, UINT64 mem_mask); + + UINT64 get_cop0_reg(int idx); + void set_cop0_reg(int idx, UINT64 val); + UINT64 get_cop0_creg(int idx); + void set_cop0_creg(int idx, UINT64 val); + void handle_cop0(UINT32 op); + + UINT32 get_cop1_reg32(int idx); + UINT64 get_cop1_reg64(int idx); + void set_cop1_reg32(int idx, UINT32 val); + void set_cop1_reg64(int idx, UINT64 val); + UINT64 get_cop1_creg(int idx); + void set_cop1_creg(int idx, UINT64 val); + void handle_cop1_fr0(UINT32 op); + void handle_cop1_fr1(UINT32 op); + void handle_cop1x_fr0(UINT32 op); + void handle_cop1x_fr1(UINT32 op); + + UINT64 get_cop2_reg(int idx); + void set_cop2_reg(int idx, UINT64 val); + UINT64 get_cop2_creg(int idx); + void set_cop2_creg(int idx, UINT64 val); + void handle_cop2(UINT32 op); + + void handle_special(UINT32 op); + void handle_regimm(UINT32 op); + + void lwl_be(UINT32 op); + void lwr_be(UINT32 op); + void ldl_be(UINT32 op); + void ldr_be(UINT32 op); + void swl_be(UINT32 op); + void swr_be(UINT32 op); + void sdl_be(UINT32 op); + void sdr_be(UINT32 op); + void lwl_le(UINT32 op); + void lwr_le(UINT32 op); + void ldl_le(UINT32 op); + void ldr_le(UINT32 op); + void swl_le(UINT32 op); + void swr_le(UINT32 op); + void sdl_le(UINT32 op); + void sdr_le(UINT32 op); + void load_fast_iregs(drcuml_block *block); + void save_fast_iregs(drcuml_block *block); + void code_flush_cache(); + void code_compile_block(UINT8 mode, offs_t pc); +public: + void func_get_cycles(); + void func_printf_exception(); + void func_printf_debug(); + void func_printf_probe(); + void func_unimplemented(); +private: + void static_generate_entry_point(); + void static_generate_nocode_handler(); + void static_generate_out_of_cycles(); + void static_generate_tlb_mismatch(); + void static_generate_exception(UINT8 exception, int recover, const char *name); + void static_generate_memory_accessor(int mode, int size, int iswrite, int ismasked, const char *name, uml::code_handle **handleptr); + + void generate_update_mode(drcuml_block *block); + void generate_update_cycles(drcuml_block *block, compiler_state *compiler, uml::parameter param, int allow_exception); + void generate_checksum_block(drcuml_block *block, compiler_state *compiler, const opcode_desc *seqhead, const opcode_desc *seqlast); + void generate_sequence_instruction(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); + void generate_delay_slot_and_branch(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, UINT8 linkreg); + + int generate_opcode(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); + int generate_special(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); + int generate_regimm(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); + int generate_idt(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); + + int generate_set_cop0_reg(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, UINT8 reg); + int generate_get_cop0_reg(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, UINT8 reg); + int generate_cop0(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); + int generate_cop1(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); + int generate_cop1x(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); + + void check_cop0_access(drcuml_block *block); + void check_cop1_access(drcuml_block *block); + void generate_badcop(drcuml_block *block, const int cop); + + void log_add_disasm_comment(drcuml_block *block, UINT32 pc, UINT32 op); + const char *log_desc_flags_to_string(UINT32 flags); + void log_register_list(drcuml_state *drcuml, const char *string, const UINT32 *reglist, const UINT32 *regnostarlist); + void log_opcode_desc(drcuml_state *drcuml, const opcode_desc *desclist, int indent); + +}; + + +class vr4300be_device : public mips3_device +{ +public: + // construction/destruction + vr4300be_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : mips3_device(mconfig, VR4300BE, "VR4300 (big)", tag, owner, clock, "vr4300be", MIPS3_TYPE_VR4300, ENDIANNESS_BIG) + { } +}; + +class vr4300le_device : public mips3_device +{ +public: + // construction/destruction + vr4300le_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : mips3_device(mconfig, VR4300LE, "VR4300 (little)", tag, owner, clock, "vr4300le", MIPS3_TYPE_VR4300, ENDIANNESS_LITTLE) + { } +}; + +class vr4310be_device : public mips3_device +{ +public: + // construction/destruction + vr4310be_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : mips3_device(mconfig, VR4310BE, "VR4310 (big)", tag, owner, clock, "vr4310be", MIPS3_TYPE_VR4300, ENDIANNESS_BIG) + { } +}; + +class vr4310le_device : public mips3_device +{ +public: + // construction/destruction + vr4310le_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : mips3_device(mconfig, VR4310LE, "VR4310 (little)", tag, owner, clock, "vr4310le", MIPS3_TYPE_VR4300, ENDIANNESS_LITTLE) + { } +}; + +class r4600be_device : public mips3_device +{ +public: + // construction/destruction + r4600be_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : mips3_device(mconfig, R4600BE, "R4600 (big)", tag, owner, clock, "r4600be", MIPS3_TYPE_R4600, ENDIANNESS_BIG) + { } +}; + +class r4600le_device : public mips3_device +{ +public: + // construction/destruction + r4600le_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : mips3_device(mconfig, R4600LE, "R4600 (little)", tag, owner, clock, "r4600le", MIPS3_TYPE_R4600, ENDIANNESS_LITTLE) + { } +}; + +class r4650be_device : public mips3_device +{ +public: + // construction/destruction + r4650be_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : mips3_device(mconfig, R4650BE, "IDT R4650 (big)", tag, owner, clock, "r4650be", MIPS3_TYPE_R4650, ENDIANNESS_BIG) + { } +}; + +class r4650le_device : public mips3_device +{ +public: + // construction/destruction + r4650le_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : mips3_device(mconfig, R4650LE, "IDT R4650 (little)", tag, owner, clock, "r4650le", MIPS3_TYPE_R4650, ENDIANNESS_LITTLE) + { } +}; + +class r4700be_device : public mips3_device +{ +public: + // construction/destruction + r4700be_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : mips3_device(mconfig, R4700BE, "R4700 (big)", tag, owner, clock, "r4700be", MIPS3_TYPE_R4700, ENDIANNESS_BIG) + { } +}; + +class r4700le_device : public mips3_device +{ +public: + // construction/destruction + r4700le_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : mips3_device(mconfig, R4700LE, "R4700 (little)", tag, owner, clock, "r4700le", MIPS3_TYPE_R4700, ENDIANNESS_LITTLE) + { } +}; + +class r5000be_device : public mips3_device +{ +public: + // construction/destruction + r5000be_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : mips3_device(mconfig, R5000BE, "R5000 (big)", tag, owner, clock, "r5000be", MIPS3_TYPE_R5000, ENDIANNESS_BIG) + { } +}; + +class r5000le_device : public mips3_device +{ +public: + // construction/destruction + r5000le_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : mips3_device(mconfig, R5000LE, "R5000 (little)", tag, owner, clock, "r5000le", MIPS3_TYPE_R5000, ENDIANNESS_LITTLE) + { } +}; + +class qed5271be_device : public mips3_device +{ +public: + // construction/destruction + qed5271be_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : mips3_device(mconfig, QED5271BE, "QED5271 (big)", tag, owner, clock, "qed5271be", MIPS3_TYPE_QED5271, ENDIANNESS_BIG) + { } +}; + +class qed5271le_device : public mips3_device +{ +public: + // construction/destruction + qed5271le_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : mips3_device(mconfig, QED5271LE, "QED5271 (little)", tag, owner, clock, "qed5271le", MIPS3_TYPE_QED5271, ENDIANNESS_LITTLE) + { } +}; + +class rm7000be_device : public mips3_device +{ +public: + // construction/destruction + rm7000be_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : mips3_device(mconfig, RM7000BE, "RM7000 (big)", tag, owner, clock, "rm7000be", MIPS3_TYPE_RM7000, ENDIANNESS_BIG) + { } +}; + +class rm7000le_device : public mips3_device +{ +public: + // construction/destruction + rm7000le_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : mips3_device(mconfig, RM7000LE, "RM7000 (little)", tag, owner, clock, "rm7000le", MIPS3_TYPE_RM7000, ENDIANNESS_LITTLE) + { } +}; + + + +class mips3_frontend : public drc_frontend +{ +public: + // construction/destruction + mips3_frontend(mips3_device *mips3, UINT32 window_start, UINT32 window_end, UINT32 max_sequence); + +protected: + // required overrides + virtual bool describe(opcode_desc &desc, const opcode_desc *prev); + +private: + // internal helpers + bool describe_special(UINT32 op, opcode_desc &desc); + bool describe_regimm(UINT32 op, opcode_desc &desc); + bool describe_idt(UINT32 op, opcode_desc &desc); + bool describe_cop0(UINT32 op, opcode_desc &desc); + bool describe_cop1(UINT32 op, opcode_desc &desc); + bool describe_cop1x(UINT32 op, opcode_desc &desc); + bool describe_cop2(UINT32 op, opcode_desc &desc); + + // internal state + mips3_device *m_mips3; +}; + + +/*************************************************************************** + COMPILER-SPECIFIC OPTIONS +***************************************************************************/ + +/* fix me -- how do we make this work?? */ +#define MIPS3DRC_STRICT_VERIFY 0x0001 /* verify all instructions */ +#define MIPS3DRC_STRICT_COP0 0x0002 /* validate all COP0 instructions */ +#define MIPS3DRC_STRICT_COP1 0x0004 /* validate all COP1 instructions */ +#define MIPS3DRC_STRICT_COP2 0x0008 /* validate all COP2 instructions */ +#define MIPS3DRC_FLUSH_PC 0x0010 /* flush the PC value before each memory access */ +#define MIPS3DRC_CHECK_OVERFLOWS 0x0020 /* actually check overflows on add/sub instructions */ +#define MIPS3DRC_ACCURATE_DIVZERO 0x0040 /* load correct values into HI/LO on integer divide-by-zero */ + +#define MIPS3DRC_COMPATIBLE_OPTIONS (MIPS3DRC_STRICT_VERIFY | MIPS3DRC_STRICT_COP1 | MIPS3DRC_STRICT_COP0 | MIPS3DRC_STRICT_COP2 | MIPS3DRC_FLUSH_PC) +#define MIPS3DRC_FASTEST_OPTIONS (0) + + +#endif /* __MIPS3_H__ */ diff --git a/src/devices/cpu/mips/mips3com.c b/src/devices/cpu/mips/mips3com.c new file mode 100644 index 00000000000..0409014eeba --- /dev/null +++ b/src/devices/cpu/mips/mips3com.c @@ -0,0 +1,433 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + mips3com.c + + Common MIPS III/IV definitions and functions + +***************************************************************************/ + +#include "emu.h" +#include "mips3com.h" + + +/*************************************************************************** + FUNCTION PROTOTYPES +***************************************************************************/ + +static void tlb_entry_log_half(mips3_tlb_entry *entry, int tlbindex, int which); + + + +/*************************************************************************** + INLINE FUNCTIONS +***************************************************************************/ + +/*------------------------------------------------- + tlb_entry_matches_asid - TRUE if the given + TLB entry matches the provided ASID +-------------------------------------------------*/ + +INLINE int tlb_entry_matches_asid(const mips3_tlb_entry *entry, UINT8 asid) +{ + return (entry->entry_hi & 0xff) == asid; +} + + +/*------------------------------------------------- + tlb_entry_is_global - TRUE if the given + TLB entry is global +-------------------------------------------------*/ + +INLINE int tlb_entry_is_global(const mips3_tlb_entry *entry) +{ + return (entry->entry_lo[0] & entry->entry_lo[1] & TLB_GLOBAL); +} + + +void mips3_device::execute_set_input(int inputnum, int state) +{ + if (inputnum >= MIPS3_IRQ0 && inputnum <= MIPS3_IRQ5) + { + if (state != CLEAR_LINE) + m_core->cpr[0][COP0_Cause] |= 0x400 << inputnum; + else + m_core->cpr[0][COP0_Cause] &= ~(0x400 << inputnum); + } +} + + +/*************************************************************************** + INITIALIZATION AND SHUTDOWN +***************************************************************************/ + +/*------------------------------------------------- + mips3com_update_cycle_counting - update cycle + counts and the timers +-------------------------------------------------*/ + +void mips3_device::mips3com_update_cycle_counting() +{ + /* modify the timer to go off */ + if (m_core->compare_armed && (m_core->cpr[0][COP0_Status] & SR_IMEX5)) + { + UINT32 count = (total_cycles() - m_core->count_zero_time) / 2; + UINT32 compare = m_core->cpr[0][COP0_Compare]; + UINT32 delta = compare - count; + attotime newtime = cycles_to_attotime((UINT64)delta * 2); + m_compare_int_timer->adjust(newtime); + return; + } + m_compare_int_timer->adjust(attotime::never); +} + + + +/*************************************************************************** + TLB HANDLING +***************************************************************************/ + +/*------------------------------------------------- + mips3com_asid_changed - remap all non-global + TLB entries +-------------------------------------------------*/ + +void mips3_device::mips3com_asid_changed() +{ + int tlbindex; + + /* iterate over all non-global TLB entries and remap them */ + for (tlbindex = 0; tlbindex < m_tlbentries; tlbindex++) + if (!tlb_entry_is_global(&m_tlb[tlbindex])) + tlb_map_entry(tlbindex); +} + + +/*------------------------------------------------- + mips3com_tlbr - execute the tlbr instruction +-------------------------------------------------*/ + +void mips3_device::mips3com_tlbr() +{ + UINT32 tlbindex = m_core->cpr[0][COP0_Index] & 0x3f; + + /* only handle entries within the TLB */ + if (tlbindex < m_tlbentries) + { + mips3_tlb_entry *entry = &m_tlb[tlbindex]; + + /* copy data from the TLB entry into the COP0 registers */ + m_core->cpr[0][COP0_PageMask] = entry->page_mask; + m_core->cpr[0][COP0_EntryHi] = entry->entry_hi; + m_core->cpr[0][COP0_EntryLo0] = entry->entry_lo[0]; + m_core->cpr[0][COP0_EntryLo1] = entry->entry_lo[1]; + } +} + + +/*------------------------------------------------- + mips3com_tlbwi - execute the tlbwi instruction +-------------------------------------------------*/ + +void mips3_device::mips3com_tlbwi() +{ + /* use the common handler and write based off the COP0 Index register */ + tlb_write_common(m_core->cpr[0][COP0_Index] & 0x3f); +} + + +/*------------------------------------------------- + mips3com_tlbwr - execute the tlbwr instruction +-------------------------------------------------*/ + +void mips3_device::mips3com_tlbwr() +{ + UINT32 wired = m_core->cpr[0][COP0_Wired] & 0x3f; + UINT32 unwired = m_tlbentries - wired; + UINT32 tlbindex = m_tlbentries - 1; + + /* "random" is based off of the current cycle counting through the non-wired pages */ + if (unwired > 0) + tlbindex = ((total_cycles() - m_core->count_zero_time) % unwired + wired) & 0x3f; + + /* use the common handler to write to this tlbindex */ + tlb_write_common(tlbindex); +} + + +/*------------------------------------------------- + mips3com_tlbp - execute the tlbp instruction +-------------------------------------------------*/ + +void mips3_device::mips3com_tlbp() +{ + UINT32 tlbindex; + + /* iterate over TLB entries */ + for (tlbindex = 0; tlbindex < m_tlbentries; tlbindex++) + { + mips3_tlb_entry *entry = &m_tlb[tlbindex]; + UINT64 mask = ~((entry->page_mask >> 13) & 0xfff) << 13; + + /* if the relevant bits of EntryHi match the relevant bits of the TLB */ + if ((entry->entry_hi & mask) == (m_core->cpr[0][COP0_EntryHi] & mask)) + + /* and if we are either global or matching the current ASID, then stop */ + if ((entry->entry_hi & 0xff) == (m_core->cpr[0][COP0_EntryHi] & 0xff) || ((entry->entry_lo[0] & entry->entry_lo[1]) & TLB_GLOBAL)) + break; + } + + /* validate that our tlb_table was in sync */ +// vpn = ((m_cores->cpr[0][COP0_EntryHi] >> 13) & 0x07ffffff) << 1; + if (tlbindex != m_tlbentries) + m_core->cpr[0][COP0_Index] = tlbindex; + else + m_core->cpr[0][COP0_Index] = 0x80000000; +} + + + +/*************************************************************************** + INTERNAL HELPERS +***************************************************************************/ + +/*------------------------------------------------- + compare_int_callback - callback that fires + whenever a compare interrupt is generated +-------------------------------------------------*/ + +TIMER_CALLBACK_MEMBER( mips3_device::compare_int_callback ) +{ + set_input_line(MIPS3_IRQ5, ASSERT_LINE); +} + + +/*------------------------------------------------- + compute_config_register - compute the value + of the config register +-------------------------------------------------*/ + +UINT32 mips3_device::compute_config_register() +{ + /* set the cache line size to 32 bytes */ + UINT32 configreg = 0x00026030; + int divisor; + + // NEC VR series does not use a 100% compatible COP0/TLB implementation + if (m_flavor == MIPS3_TYPE_VR4300) + { + /* + For VR43xx, Config is as follows: + bit 31 = always 0 + bits 28-30 = EC + bits 24-27 = EP + bits 16-23 = always b0000010 + bit 15 = endian indicator as standard MIPS III + bits 4-14 = always b11001000110 + bit 3 = CU + bits 0-2 = K0 ("Coherency algorithm of kseg0") + */ + + configreg = 0x6460; + } + else + { + /* set the data cache size */ + if (c_icache_size <= 0x01000) configreg |= 0 << 6; + else if (c_icache_size <= 0x02000) configreg |= 1 << 6; + else if (c_icache_size <= 0x04000) configreg |= 2 << 6; + else if (c_icache_size <= 0x08000) configreg |= 3 << 6; + else if (c_icache_size <= 0x10000) configreg |= 4 << 6; + else if (c_icache_size <= 0x20000) configreg |= 5 << 6; + else if (c_icache_size <= 0x40000) configreg |= 6 << 6; + else configreg |= 7 << 6; + + /* set the instruction cache size */ + if (c_icache_size <= 0x01000) configreg |= 0 << 9; + else if (c_icache_size <= 0x02000) configreg |= 1 << 9; + else if (c_icache_size <= 0x04000) configreg |= 2 << 9; + else if (c_icache_size <= 0x08000) configreg |= 3 << 9; + else if (c_icache_size <= 0x10000) configreg |= 4 << 9; + else if (c_icache_size <= 0x20000) configreg |= 5 << 9; + else if (c_icache_size <= 0x40000) configreg |= 6 << 9; + else configreg |= 7 << 9; + + + /* set the system clock divider */ + divisor = 2; + if (c_system_clock != 0) + { + divisor = m_cpu_clock / c_system_clock; + if (c_system_clock * divisor != m_cpu_clock) + { + configreg |= 0x80000000; + divisor = m_cpu_clock * 2 / c_system_clock; + } + } + configreg |= (((divisor < 2) ? 2 : (divisor > 8) ? 8 : divisor) - 2) << 28; + } + + /* set the endianness bit */ + if (m_bigendian) + configreg |= 0x00008000; + + return configreg; +} + + +/*------------------------------------------------- + compute_prid_register - compute the value + of the PRId register +-------------------------------------------------*/ + +UINT32 mips3_device::compute_prid_register() +{ + switch (m_flavor) + { + case MIPS3_TYPE_VR4300: + return 0x0b00; + + case MIPS3_TYPE_R4600: + case MIPS3_TYPE_R4650: + return 0x2000; + + case MIPS3_TYPE_R4700: + return 0x2100; + + case MIPS3_TYPE_R5000: + case MIPS3_TYPE_QED5271: + return 0x2300; + + case MIPS3_TYPE_RM7000: + return 0x2700; + + default: + fatalerror("Unknown MIPS flavor specified\n"); + } + // never executed + //return 0x2000; +} + + +/*------------------------------------------------- + tlb_map_entry - map a single TLB + entry +-------------------------------------------------*/ + +void mips3_device::tlb_map_entry(int tlbindex) +{ + int current_asid = m_core->cpr[0][COP0_EntryHi] & 0xff; + mips3_tlb_entry *entry = &m_tlb[tlbindex]; + UINT32 count, vpn; + int which; + + /* the ASID doesn't match the current ASID, and if the page isn't global, unmap it from the TLB */ + if (!tlb_entry_matches_asid(entry, current_asid) && !tlb_entry_is_global(entry)) + { + vtlb_load(m_vtlb, 2 * tlbindex + 0, 0, 0, 0); + vtlb_load(m_vtlb, 2 * tlbindex + 1, 0, 0, 0); + return; + } + + /* extract the VPN index; ignore if the virtual address is beyond 32 bits */ + vpn = ((entry->entry_hi >> 13) & 0x07ffffff) << 1; + if (vpn >= (1 << (MIPS3_MAX_PADDR_SHIFT - MIPS3_MIN_PAGE_SHIFT))) + { + vtlb_load(m_vtlb, 2 * tlbindex + 0, 0, 0, 0); + vtlb_load(m_vtlb, 2 * tlbindex + 1, 0, 0, 0); + return; + } + + /* get the number of pages from the page mask */ + count = ((entry->page_mask >> 13) & 0x00fff) + 1; + + /* loop over both the even and odd pages */ + for (which = 0; which < 2; which++) + { + UINT32 effvpn = vpn + count * which; + UINT64 lo = entry->entry_lo[which]; + UINT32 pfn; + UINT32 flags = 0; + + /* compute physical page index */ + pfn = (lo >> 6) & m_pfnmask; + + /* valid? */ + if ((lo & 2) != 0) + { + flags |= VTLB_FLAG_VALID | VTLB_READ_ALLOWED | VTLB_FETCH_ALLOWED; + + /* writable? */ + if ((lo & 4) != 0) + flags |= VTLB_WRITE_ALLOWED; + + /* mirror the flags for user mode if the VPN is in user space */ + if (effvpn < (0x80000000 >> MIPS3_MIN_PAGE_SHIFT)) + flags |= (flags << 4) & (VTLB_USER_READ_ALLOWED | VTLB_USER_WRITE_ALLOWED | VTLB_USER_FETCH_ALLOWED); + } + + /* load the virtual TLB with the corresponding entries */ + if ((effvpn + count) <= (0x80000000 >> MIPS3_MIN_PAGE_SHIFT) || effvpn >= (0xc0000000 >> MIPS3_MIN_PAGE_SHIFT)) + vtlb_load(m_vtlb, 2 * tlbindex + which, count, effvpn << MIPS3_MIN_PAGE_SHIFT, (pfn << MIPS3_MIN_PAGE_SHIFT) | flags); + else + vtlb_load(m_vtlb, 2 * tlbindex + which, 0, 0, 0); + } +} + + +/*------------------------------------------------- + tlb_write_common - common routine for writing + a TLB entry +-------------------------------------------------*/ + +void mips3_device::tlb_write_common(int tlbindex) +{ + /* only handle entries within the TLB */ + if (tlbindex < m_tlbentries) + { + mips3_tlb_entry *entry = &m_tlb[tlbindex]; + + /* fill in the new TLB entry from the COP0 registers */ + entry->page_mask = m_core->cpr[0][COP0_PageMask]; + entry->entry_hi = m_core->cpr[0][COP0_EntryHi] & ~(entry->page_mask & U64(0x0000000001ffe000)); + entry->entry_lo[0] = m_core->cpr[0][COP0_EntryLo0]; + entry->entry_lo[1] = m_core->cpr[0][COP0_EntryLo1]; + + /* remap this TLB entry */ + tlb_map_entry(tlbindex); + + /* log the two halves once they are in */ + tlb_entry_log_half(entry, tlbindex, 0); + tlb_entry_log_half(entry, tlbindex, 1); + } +} + + +/*------------------------------------------------- + tlb_entry_log_half - log half of a single TLB + entry +-------------------------------------------------*/ + +static void tlb_entry_log_half(mips3_tlb_entry *entry, int tlbindex, int which) +{ +if (PRINTF_TLB) +{ + UINT64 hi = entry->entry_hi; + UINT64 lo = entry->entry_lo[which]; + UINT32 vpn = (((hi >> 13) & 0x07ffffff) << 1); + UINT32 asid = hi & 0xff; + UINT32 r = (hi >> 62) & 3; + UINT32 pfn = (lo >> 6) & 0x00ffffff; + UINT32 c = (lo >> 3) & 7; + UINT32 pagesize = (((entry->page_mask >> 13) & 0xfff) + 1) << MIPS3_MIN_PAGE_SHIFT; + UINT64 vaddr = (UINT64)vpn * MIPS3_MIN_PAGE_SIZE; + UINT64 paddr = (UINT64)pfn * MIPS3_MIN_PAGE_SIZE; + + vaddr += pagesize * which; + + printf("index=%08X pagesize=%08X vaddr=%08X%08X paddr=%08X%08X asid=%02X r=%X c=%X dvg=%c%c%c\n", + tlbindex, pagesize, (UINT32)(vaddr >> 32), (UINT32)vaddr, (UINT32)(paddr >> 32), (UINT32)paddr, + asid, r, c, (lo & 4) ? 'd' : '.', (lo & 2) ? 'v' : '.', (lo & 1) ? 'g' : '.'); +} +} diff --git a/src/devices/cpu/mips/mips3com.h b/src/devices/cpu/mips/mips3com.h new file mode 100644 index 00000000000..86d7f0c7a05 --- /dev/null +++ b/src/devices/cpu/mips/mips3com.h @@ -0,0 +1,191 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + mips3com.h + + Common MIPS III/IV definitions and functions + +***************************************************************************/ + +#pragma once + +#ifndef __MIPS3COM_H__ +#define __MIPS3COM_H__ + +#include "mips3.h" +#include "cpu/vtlb.h" + + +/*************************************************************************** + DEBUGGING +***************************************************************************/ + +#define PRINTF_TLB (0) +#define USE_ABI_REG_NAMES (1) + +#define DISABLE_FAST_REGISTERS (0) +#define SINGLE_INSTRUCTION_MODE (0) + +#define PRINTF_EXCEPTIONS (0) +#define PRINTF_MMU (0) + +#define PROBE_ADDRESS ~0 + + +/*************************************************************************** + CONSTANTS +***************************************************************************/ + +/* map variables */ +#define MAPVAR_PC M0 +#define MAPVAR_CYCLES M1 + +/* modes */ +#define MODE_KERNEL 0 +#define MODE_SUPER 1 +#define MODE_USER 2 + +/* compilation boundaries -- how far back/forward does the analysis extend? */ +#define COMPILE_BACKWARDS_BYTES 128 +#define COMPILE_FORWARDS_BYTES 512 +#define COMPILE_MAX_INSTRUCTIONS ((COMPILE_BACKWARDS_BYTES/4) + (COMPILE_FORWARDS_BYTES/4)) +#define COMPILE_MAX_SEQUENCE 64 + +/* exit codes */ +#define EXECUTE_OUT_OF_CYCLES 0 +#define EXECUTE_MISSING_CODE 1 +#define EXECUTE_UNMAPPED_CODE 2 +#define EXECUTE_RESET_CACHE 3 + + + +#define LOPTR(x) ((UINT32 *)(x) + NATIVE_ENDIAN_VALUE_LE_BE(0,1)) + + +/*************************************************************************** + CONSTANTS +***************************************************************************/ + +/* core parameters */ +#define MIPS3_MIN_PAGE_SHIFT 12 +#define MIPS3_MIN_PAGE_SIZE (1 << MIPS3_MIN_PAGE_SHIFT) +#define MIPS3_MIN_PAGE_MASK (MIPS3_MIN_PAGE_SIZE - 1) +#define MIPS3_MAX_PADDR_SHIFT 32 + +/* cycle parameters */ +#define MIPS3_COUNT_READ_CYCLES 250 +#define MIPS3_CAUSE_READ_CYCLES 250 + +/* TLB bits */ +#define TLB_GLOBAL 0x01 +#define TLB_VALID 0x02 +#define TLB_DIRTY 0x04 +#define TLB_PRESENT 0x08 + +/* COP0 registers */ +#define COP0_Index 0 +#define COP0_Random 1 +#define COP0_EntryLo 2 +#define COP0_EntryLo0 2 +#define COP0_EntryLo1 3 +#define COP0_Context 4 +#define COP0_PageMask 5 +#define COP0_Wired 6 +#define COP0_BadVAddr 8 +#define COP0_Count 9 +#define COP0_EntryHi 10 +#define COP0_Compare 11 +#define COP0_Status 12 +#define COP0_Cause 13 +#define COP0_EPC 14 +#define COP0_PRId 15 +#define COP0_Config 16 +#define COP0_LLAddr 17 +#define COP0_XContext 20 +#define COP0_ECC 26 +#define COP0_CacheErr 27 +#define COP0_TagLo 28 +#define COP0_TagHi 29 +#define COP0_ErrorPC 30 + +/* Status register bits */ +#define SR_IE 0x00000001 +#define SR_EXL 0x00000002 +#define SR_ERL 0x00000004 +#define SR_KSU_MASK 0x00000018 +#define SR_KSU_KERNEL 0x00000000 +#define SR_KSU_SUPERVISOR 0x00000008 +#define SR_KSU_USER 0x00000010 +#define SR_IMSW0 0x00000100 +#define SR_IMSW1 0x00000200 +#define SR_IMEX0 0x00000400 +#define SR_IMEX1 0x00000800 +#define SR_IMEX2 0x00001000 +#define SR_IMEX3 0x00002000 +#define SR_IMEX4 0x00004000 +#define SR_IMEX5 0x00008000 +#define SR_DE 0x00010000 +#define SR_CE 0x00020000 +#define SR_CH 0x00040000 +#define SR_SR 0x00100000 +#define SR_TS 0x00200000 +#define SR_BEV 0x00400000 +#define SR_ITS 0x01000000 /* VR4300 only, Application Note doesn't give purpose */ +#define SR_RE 0x02000000 +#define SR_FR 0x04000000 +#define SR_RP 0x08000000 +#define SR_COP0 0x10000000 +#define SR_COP1 0x20000000 +#define SR_COP2 0x40000000 +#define SR_COP3 0x80000000 + +/* exception types */ +#define EXCEPTION_INTERRUPT 0 +#define EXCEPTION_TLBMOD 1 +#define EXCEPTION_TLBLOAD 2 +#define EXCEPTION_TLBSTORE 3 +#define EXCEPTION_ADDRLOAD 4 +#define EXCEPTION_ADDRSTORE 5 +#define EXCEPTION_BUSINST 6 +#define EXCEPTION_BUSDATA 7 +#define EXCEPTION_SYSCALL 8 +#define EXCEPTION_BREAK 9 +#define EXCEPTION_INVALIDOP 10 +#define EXCEPTION_BADCOP 11 +#define EXCEPTION_OVERFLOW 12 +#define EXCEPTION_TRAP 13 +#define EXCEPTION_TLBLOAD_FILL 16 +#define EXCEPTION_TLBSTORE_FILL 17 +#define EXCEPTION_COUNT 18 + + + +/*************************************************************************** + HELPER MACROS +***************************************************************************/ + +#define REG_LO 32 +#define REG_HI 33 + +#define RSREG ((op >> 21) & 31) +#define RTREG ((op >> 16) & 31) +#define RDREG ((op >> 11) & 31) +#define SHIFT ((op >> 6) & 31) + +#define FRREG ((op >> 21) & 31) +#define FTREG ((op >> 16) & 31) +#define FSREG ((op >> 11) & 31) +#define FDREG ((op >> 6) & 31) + +#define IS_SINGLE(o) (((o) & (1 << 21)) == 0) +#define IS_DOUBLE(o) (((o) & (1 << 21)) != 0) +#define IS_FLOAT(o) (((o) & (1 << 23)) == 0) +#define IS_INTEGRAL(o) (((o) & (1 << 23)) != 0) + +#define SIMMVAL ((INT16)op) +#define UIMMVAL ((UINT16)op) +#define LIMMVAL (op & 0x03ffffff) + + +#endif /* __MIPS3COM_H__ */ diff --git a/src/devices/cpu/mips/mips3drc.c b/src/devices/cpu/mips/mips3drc.c new file mode 100644 index 00000000000..22af8e16063 --- /dev/null +++ b/src/devices/cpu/mips/mips3drc.c @@ -0,0 +1,3310 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + mips3drc.c + + Universal machine language-based MIPS III/IV emulator. + +**************************************************************************** + + Future improvements/changes: + + * Add DRC option to flush PC before calling memory handlers + + * Constant tracking? (hasn't bought us much in the past) + + * Customized mapped/unmapped memory handlers + - create 3 sets of handlers: cached, uncached, general + - default to general + - in general case, if cached use RECALL to point to cached code + - (same for uncached) + - in cached/uncached case, fall back to general case + +***************************************************************************/ + +#include "emu.h" +#include "debugger.h" +#include "mips3com.h" +#include "mips3fe.h" +#include "cpu/drcfe.h" +#include "cpu/drcuml.h" +#include "cpu/drcumlsh.h" + +extern unsigned dasmmips3(char *buffer, unsigned pc, UINT32 op); + +using namespace uml; + + +/*************************************************************************** + MACROS +***************************************************************************/ + +#define R32(reg) m_regmaplo[reg] +#define LO32 R32(REG_LO) +#define HI32 R32(REG_HI) +#define CPR032(reg) mem(LOPTR(&m_core->cpr[0][reg])) +#define CCR032(reg) mem(LOPTR(&m_core->ccr[0][reg])) +#define FPR32(reg) mem(((m_core->mode & 1) == 0) ? &((float *)&m_core->cpr[1][0])[reg] : (float *)&m_core->cpr[1][reg]) +#define CCR132(reg) mem(LOPTR(&m_core->ccr[1][reg])) +#define CPR232(reg) mem(LOPTR(&m_core->cpr[2][reg])) +#define CCR232(reg) mem(LOPTR(&m_core->ccr[2][reg])) + +#define R64(reg) m_regmap[reg] +#define LO64 R64(REG_LO) +#define HI64 R64(REG_HI) +#define CPR064(reg) mem(&m_core->cpr[0][reg]) +#define CCR064(reg) mem(&m_core->ccr[0][reg]) +#define FPR64(reg) mem(((m_core->mode & 1) == 0) ? (double *)&m_core->cpr[1][(reg)/2] : (double *)&m_core->cpr[1][reg]) +#define CCR164(reg) mem(&m_core->ccr[1][reg]) +#define CPR264(reg) mem(&m_core->cpr[2][reg]) +#define CCR264(reg) mem(&m_core->ccr[2][reg]) + +#define FCCSHIFT(which) fcc_shift[(m_flavor < MIPS3_TYPE_MIPS_IV) ? 0 : ((which) & 7)] +#define FCCMASK(which) ((UINT32)(1 << FCCSHIFT(which))) + + + +/*************************************************************************** + FUNCTION PROTOTYPES +***************************************************************************/ + +static void cfunc_printf_exception(void *param); +static void cfunc_get_cycles(void *param); +static void cfunc_printf_probe(void *param); + + +/*************************************************************************** + PRIVATE GLOBAL VARIABLES +***************************************************************************/ + +/* bit indexes for various FCCs */ +static const UINT8 fcc_shift[8] = { 23, 25, 26, 27, 28, 29, 30, 31 }; + + +/*************************************************************************** + INLINE FUNCTIONS +***************************************************************************/ + +/*------------------------------------------------- + epc - compute the exception PC from a + descriptor +-------------------------------------------------*/ + +INLINE UINT32 epc(const opcode_desc *desc) +{ + return (desc->flags & OPFLAG_IN_DELAY_SLOT) ? (desc->pc - 3) : desc->pc; +} + + +/*------------------------------------------------- + alloc_handle - allocate a handle if not + already allocated +-------------------------------------------------*/ + +INLINE void alloc_handle(drcuml_state *drcuml, code_handle **handleptr, const char *name) +{ + if (*handleptr == NULL) + *handleptr = drcuml->handle_alloc(name); +} + + +/*------------------------------------------------- + load_fast_iregs - load any fast integer + registers +-------------------------------------------------*/ + +inline void mips3_device::load_fast_iregs(drcuml_block *block) +{ + int regnum; + + for (regnum = 0; regnum < ARRAY_LENGTH(m_regmap); regnum++) + if (m_regmap[regnum].is_int_register()) + UML_DMOV(block, ireg(m_regmap[regnum].ireg() - REG_I0), mem(&m_core->r[regnum])); +} + + +/*------------------------------------------------- + save_fast_iregs - save any fast integer + registers +-------------------------------------------------*/ + +inline void mips3_device::save_fast_iregs(drcuml_block *block) +{ + int regnum; + + for (regnum = 0; regnum < ARRAY_LENGTH(m_regmap); regnum++) + if (m_regmap[regnum].is_int_register()) + UML_DMOV(block, mem(&m_core->r[regnum]), ireg(m_regmap[regnum].ireg() - REG_I0)); +} + + + +/*************************************************************************** + CORE CALLBACKS +***************************************************************************/ + +/*------------------------------------------------- + mips3drc_set_options - configure DRC options +-------------------------------------------------*/ + +void mips3_device::mips3drc_set_options(UINT32 options) +{ + if (!(mconfig().options().drc() && !mconfig().m_force_no_drc)) return; + m_drcoptions = options; +} + +/*------------------------------------------------- + mips3drc_clears_fastram - clears fastram + region starting at index select_start +-------------------------------------------------*/ +void mips3_device::clear_fastram(UINT32 select_start) +{ + for (int i=select_start; ireset(); + + try + { + /* generate the entry point and out-of-cycles handlers */ + static_generate_entry_point(); + static_generate_nocode_handler(); + static_generate_out_of_cycles(); + static_generate_tlb_mismatch(); + + /* append exception handlers for various types */ + static_generate_exception(EXCEPTION_INTERRUPT, TRUE, "exception_interrupt"); + static_generate_exception(EXCEPTION_INTERRUPT, FALSE, "exception_interrupt_norecover"); + static_generate_exception(EXCEPTION_TLBMOD, TRUE, "exception_tlbmod"); + static_generate_exception(EXCEPTION_TLBLOAD, TRUE, "exception_tlbload"); + static_generate_exception(EXCEPTION_TLBSTORE, TRUE, "exception_tlbstore"); + static_generate_exception(EXCEPTION_TLBLOAD_FILL, TRUE, "exception_tlbload_fill"); + static_generate_exception(EXCEPTION_TLBSTORE_FILL, TRUE, "exception_tlbstore_fill"); + static_generate_exception(EXCEPTION_ADDRLOAD, TRUE, "exception_addrload"); + static_generate_exception(EXCEPTION_ADDRSTORE, TRUE, "exception_addrstore"); + static_generate_exception(EXCEPTION_SYSCALL, TRUE, "exception_syscall"); + static_generate_exception(EXCEPTION_BREAK, TRUE, "exception_break"); + static_generate_exception(EXCEPTION_INVALIDOP, TRUE, "exception_invalidop"); + static_generate_exception(EXCEPTION_BADCOP, TRUE, "exception_badcop"); + static_generate_exception(EXCEPTION_OVERFLOW, TRUE, "exception_overflow"); + static_generate_exception(EXCEPTION_TRAP, TRUE, "exception_trap"); + + /* add subroutines for memory accesses */ + for (mode = 0; mode < 3; mode++) + { + static_generate_memory_accessor(mode, 1, FALSE, FALSE, "read8", &m_read8[mode]); + static_generate_memory_accessor(mode, 1, TRUE, FALSE, "write8", &m_write8[mode]); + static_generate_memory_accessor(mode, 2, FALSE, FALSE, "read16", &m_read16[mode]); + static_generate_memory_accessor(mode, 2, TRUE, FALSE, "write16", &m_write16[mode]); + static_generate_memory_accessor(mode, 4, FALSE, FALSE, "read32", &m_read32[mode]); + static_generate_memory_accessor(mode, 4, FALSE, TRUE, "read32mask", &m_read32mask[mode]); + static_generate_memory_accessor(mode, 4, TRUE, FALSE, "write32", &m_write32[mode]); + static_generate_memory_accessor(mode, 4, TRUE, TRUE, "write32mask", &m_write32mask[mode]); + static_generate_memory_accessor(mode, 8, FALSE, FALSE, "read64", &m_read64[mode]); + static_generate_memory_accessor(mode, 8, FALSE, TRUE, "read64mask", &m_read64mask[mode]); + static_generate_memory_accessor(mode, 8, TRUE, FALSE, "write64", &m_write64[mode]); + static_generate_memory_accessor(mode, 8, TRUE, TRUE, "write64mask", &m_write64mask[mode]); + } + } + catch (drcuml_block::abort_compilation &) + { + fatalerror("Unrecoverable error generating static code\n"); + } +} + + +/*------------------------------------------------- + code_compile_block - compile a block of the + given mode at the specified pc +-------------------------------------------------*/ + +void mips3_device::code_compile_block(UINT8 mode, offs_t pc) +{ + drcuml_state *drcuml = m_drcuml; + compiler_state compiler = { 0 }; + const opcode_desc *seqhead, *seqlast; + const opcode_desc *desclist; + int override = FALSE; + drcuml_block *block; + + g_profiler.start(PROFILER_DRC_COMPILE); + + /* get a description of this sequence */ + desclist = m_drcfe->describe_code(pc); + if (drcuml->logging() || drcuml->logging_native()) + log_opcode_desc(drcuml, desclist, 0); + + /* if we get an error back, flush the cache and try again */ + bool succeeded = false; + while (!succeeded) + { + try + { + /* start the block */ + block = drcuml->begin_block(4096); + + /* loop until we get through all instruction sequences */ + for (seqhead = desclist; seqhead != NULL; seqhead = seqlast->next()) + { + const opcode_desc *curdesc; + UINT32 nextpc; + + /* add a code log entry */ + if (drcuml->logging()) + block->append_comment("-------------------------"); // comment + + /* determine the last instruction in this sequence */ + for (seqlast = seqhead; seqlast != NULL; seqlast = seqlast->next()) + if (seqlast->flags & OPFLAG_END_SEQUENCE) + break; + assert(seqlast != NULL); + + /* if we don't have a hash for this mode/pc, or if we are overriding all, add one */ + if (override || !drcuml->hash_exists(mode, seqhead->pc)) + UML_HASH(block, mode, seqhead->pc); // hash mode,pc + + /* if we already have a hash, and this is the first sequence, assume that we */ + /* are recompiling due to being out of sync and allow future overrides */ + else if (seqhead == desclist) + { + override = TRUE; + UML_HASH(block, mode, seqhead->pc); // hash mode,pc + } + + /* otherwise, redispatch to that fixed PC and skip the rest of the processing */ + else + { + UML_LABEL(block, seqhead->pc | 0x80000000); // label seqhead->pc | 0x80000000 + UML_HASHJMP(block, m_core->mode, seqhead->pc, *m_nocode); + // hashjmp ,seqhead->pc,nocode + continue; + } + + /* validate this code block if we're not pointing into ROM */ + if (m_program->get_write_ptr(seqhead->physpc) != NULL) + generate_checksum_block(block, &compiler, seqhead, seqlast); + + /* label this instruction, if it may be jumped to locally */ + if (seqhead->flags & OPFLAG_IS_BRANCH_TARGET) + UML_LABEL(block, seqhead->pc | 0x80000000); // label seqhead->pc | 0x80000000 + + /* iterate over instructions in the sequence and compile them */ + for (curdesc = seqhead; curdesc != seqlast->next(); curdesc = curdesc->next()) + generate_sequence_instruction(block, &compiler, curdesc); + + /* if we need to return to the start, do it */ + if (seqlast->flags & OPFLAG_RETURN_TO_START) + nextpc = pc; + + /* otherwise we just go to the next instruction */ + else + nextpc = seqlast->pc + (seqlast->skipslots + 1) * 4; + + /* count off cycles and go there */ + generate_update_cycles(block, &compiler, nextpc, TRUE); // + + /* if the last instruction can change modes, use a variable mode; otherwise, assume the same mode */ + if (seqlast->flags & OPFLAG_CAN_CHANGE_MODES) + UML_HASHJMP(block, mem(&m_core->mode), nextpc, *m_nocode); + // hashjmp ,nextpc,nocode + else if (seqlast->next() == NULL || seqlast->next()->pc != nextpc) + UML_HASHJMP(block, m_core->mode, nextpc, *m_nocode); + // hashjmp ,nextpc,nocode + } + + /* end the sequence */ + block->end(); + g_profiler.stop(); + succeeded = true; + } + catch (drcuml_block::abort_compilation &) + { + code_flush_cache(); + } + } +} + + + +/*************************************************************************** + C FUNCTION CALLBACKS +***************************************************************************/ + +static void cfunc_mips3com_update_cycle_counting(void *param) +{ + ((mips3_device *)param)->mips3com_update_cycle_counting(); +} + +static void cfunc_mips3com_asid_changed(void *param) +{ + ((mips3_device *)param)->mips3com_asid_changed(); +} + +static void cfunc_mips3com_tlbr(void *param) +{ + ((mips3_device *)param)->mips3com_tlbr(); +} + +static void cfunc_mips3com_tlbwi(void *param) +{ + ((mips3_device *)param)->mips3com_tlbwi(); +} + +static void cfunc_mips3com_tlbwr(void *param) +{ + ((mips3_device *)param)->mips3com_tlbwr(); +} + +static void cfunc_mips3com_tlbp(void *param) +{ + ((mips3_device *)param)->mips3com_tlbp(); +} + +/*------------------------------------------------- + cfunc_get_cycles - compute the total number + of cycles executed so far +-------------------------------------------------*/ + +void mips3_device::func_get_cycles() +{ + m_core->numcycles = total_cycles(); +} + +static void cfunc_get_cycles(void *param) +{ + ((mips3_device *)param)->func_get_cycles(); +} + + +/*------------------------------------------------- + cfunc_printf_exception - log any exceptions that + aren't interrupts +-------------------------------------------------*/ + +void mips3_device::func_printf_exception() +{ + printf("Exception: EPC=%08X Cause=%08X BadVAddr=%08X Jmp=%08X\n", (UINT32)m_core->cpr[0][COP0_EPC], (UINT32)m_core->cpr[0][COP0_Cause], (UINT32)m_core->cpr[0][COP0_BadVAddr], m_core->pc); + func_printf_probe(); +} + +static void cfunc_printf_exception(void *param) +{ + ((mips3_device *)param)->func_printf_exception(); +} + +/*------------------------------------------------- + cfunc_printf_debug - generic printf for + debugging +-------------------------------------------------*/ + +void mips3_device::func_printf_debug() +{ + printf(m_core->format, m_core->arg0, m_core->arg1); +} + +static void cfunc_printf_debug(void *param) +{ + ((mips3_device *)param)->func_printf_debug(); +} + + +/*------------------------------------------------- + cfunc_printf_probe - print the current CPU + state and return +-------------------------------------------------*/ + +void mips3_device::func_printf_probe() +{ + printf(" PC=%08X r1=%08X%08X r2=%08X%08X r3=%08X%08X\n", + m_core->pc, + (UINT32)(m_core->r[1] >> 32), (UINT32)m_core->r[1], + (UINT32)(m_core->r[2] >> 32), (UINT32)m_core->r[2], + (UINT32)(m_core->r[3] >> 32), (UINT32)m_core->r[3]); + printf(" r4=%08X%08X r5=%08X%08X r6=%08X%08X r7=%08X%08X\n", + (UINT32)(m_core->r[4] >> 32), (UINT32)m_core->r[4], + (UINT32)(m_core->r[5] >> 32), (UINT32)m_core->r[5], + (UINT32)(m_core->r[6] >> 32), (UINT32)m_core->r[6], + (UINT32)(m_core->r[7] >> 32), (UINT32)m_core->r[7]); + printf(" r8=%08X%08X r9=%08X%08X r10=%08X%08X r11=%08X%08X\n", + (UINT32)(m_core->r[8] >> 32), (UINT32)m_core->r[8], + (UINT32)(m_core->r[9] >> 32), (UINT32)m_core->r[9], + (UINT32)(m_core->r[10] >> 32), (UINT32)m_core->r[10], + (UINT32)(m_core->r[11] >> 32), (UINT32)m_core->r[11]); + printf("r12=%08X%08X r13=%08X%08X r14=%08X%08X r15=%08X%08X\n", + (UINT32)(m_core->r[12] >> 32), (UINT32)m_core->r[12], + (UINT32)(m_core->r[13] >> 32), (UINT32)m_core->r[13], + (UINT32)(m_core->r[14] >> 32), (UINT32)m_core->r[14], + (UINT32)(m_core->r[15] >> 32), (UINT32)m_core->r[15]); + printf("r16=%08X%08X r17=%08X%08X r18=%08X%08X r19=%08X%08X\n", + (UINT32)(m_core->r[16] >> 32), (UINT32)m_core->r[16], + (UINT32)(m_core->r[17] >> 32), (UINT32)m_core->r[17], + (UINT32)(m_core->r[18] >> 32), (UINT32)m_core->r[18], + (UINT32)(m_core->r[19] >> 32), (UINT32)m_core->r[19]); + printf("r20=%08X%08X r21=%08X%08X r22=%08X%08X r23=%08X%08X\n", + (UINT32)(m_core->r[20] >> 32), (UINT32)m_core->r[20], + (UINT32)(m_core->r[21] >> 32), (UINT32)m_core->r[21], + (UINT32)(m_core->r[22] >> 32), (UINT32)m_core->r[22], + (UINT32)(m_core->r[23] >> 32), (UINT32)m_core->r[23]); + printf("r24=%08X%08X r25=%08X%08X r26=%08X%08X r27=%08X%08X\n", + (UINT32)(m_core->r[24] >> 32), (UINT32)m_core->r[24], + (UINT32)(m_core->r[25] >> 32), (UINT32)m_core->r[25], + (UINT32)(m_core->r[26] >> 32), (UINT32)m_core->r[26], + (UINT32)(m_core->r[27] >> 32), (UINT32)m_core->r[27]); + printf("r28=%08X%08X r29=%08X%08X r30=%08X%08X r31=%08X%08X\n", + (UINT32)(m_core->r[28] >> 32), (UINT32)m_core->r[28], + (UINT32)(m_core->r[29] >> 32), (UINT32)m_core->r[29], + (UINT32)(m_core->r[30] >> 32), (UINT32)m_core->r[30], + (UINT32)(m_core->r[31] >> 32), (UINT32)m_core->r[31]); + printf(" hi=%08X%08X lo=%08X%08X\n", + (UINT32)(m_core->r[REG_HI] >> 32), (UINT32)m_core->r[REG_HI], + (UINT32)(m_core->r[REG_LO] >> 32), (UINT32)m_core->r[REG_LO]); +} + +static void cfunc_printf_probe(void *param) +{ + ((mips3_device *)param)->func_printf_probe(); +} + +/*------------------------------------------------- + cfunc_unimplemented - handler for + unimplemented opcdes +-------------------------------------------------*/ + +void mips3_device::func_unimplemented() +{ + UINT32 opcode = m_core->arg0; + fatalerror("PC=%08X: Unimplemented op %08X (%02X,%02X)\n", m_core->pc, opcode, opcode >> 26, opcode & 0x3f); +} + +static void cfunc_unimplemented(void *param) +{ + ((mips3_device *)param)->func_unimplemented(); +} + + +/*************************************************************************** + STATIC CODEGEN +***************************************************************************/ + +/*------------------------------------------------- + static_generate_entry_point - generate a + static entry point +-------------------------------------------------*/ + +void mips3_device::static_generate_entry_point() +{ + drcuml_state *drcuml = m_drcuml; + code_label skip = 1; + drcuml_block *block; + + block = drcuml->begin_block(20); + + /* forward references */ + alloc_handle(drcuml, &m_exception_norecover[EXCEPTION_INTERRUPT], "interrupt_norecover"); + alloc_handle(drcuml, &m_nocode, "nocode"); + + alloc_handle(drcuml, &m_entry, "entry"); + UML_HANDLE(block, *m_entry); // handle entry + + /* reset the FPU mode */ + UML_AND(block, I0, CCR132(31), 3); // and i0,ccr1[31],3 + UML_LOAD(block, I0, &m_fpmode[0], I0, SIZE_BYTE, SCALE_x1);// load i0,fpmode,i0,byte + UML_SETFMOD(block, I0); // setfmod i0 + + /* load fast integer registers */ + load_fast_iregs(block); + + /* check for interrupts */ + UML_AND(block, I0, CPR032(COP0_Cause), CPR032(COP0_Status)); // and i0,[Cause],[Status] + UML_AND(block, I0, I0, 0xfc00); // and i0,i0,0xfc00,Z + UML_JMPc(block, COND_Z, skip); // jmp skip,Z + UML_TEST(block, CPR032(COP0_Status), SR_IE); // test [Status],SR_IE + UML_JMPc(block, COND_Z, skip); // jmp skip,Z + UML_TEST(block, CPR032(COP0_Status), SR_EXL | SR_ERL); // test [Status],SR_EXL | SR_ERL + UML_JMPc(block, COND_NZ, skip); // jmp skip,NZ + UML_MOV(block, I0, mem(&m_core->pc)); // mov i0,pc + UML_MOV(block, I1, 0); // mov i1,0 + UML_CALLH(block, *m_exception_norecover[EXCEPTION_INTERRUPT]); // callh exception_norecover + UML_LABEL(block, skip); // skip: + + /* generate a hash jump via the current mode and PC */ + UML_HASHJMP(block, mem(&m_core->mode), mem(&m_core->pc), *m_nocode); + // hashjmp ,,nocode + block->end(); +} + + +/*------------------------------------------------- + static_generate_nocode_handler - generate an + exception handler for "out of code" +-------------------------------------------------*/ + +void mips3_device::static_generate_nocode_handler() +{ + drcuml_state *drcuml = m_drcuml; + drcuml_block *block; + + /* begin generating */ + block = drcuml->begin_block(10); + + /* generate a hash jump via the current mode and PC */ + alloc_handle(drcuml, &m_nocode, "nocode"); + UML_HANDLE(block, *m_nocode); // handle nocode + UML_GETEXP(block, I0); // getexp i0 + UML_MOV(block, mem(&m_core->pc), I0); // mov [pc],i0 + save_fast_iregs(block); + UML_EXIT(block, EXECUTE_MISSING_CODE); // exit EXECUTE_MISSING_CODE + + block->end(); +} + + +/*------------------------------------------------- + static_generate_out_of_cycles - generate an + out of cycles exception handler +-------------------------------------------------*/ + +void mips3_device::static_generate_out_of_cycles() +{ + drcuml_state *drcuml = m_drcuml; + drcuml_block *block; + + /* begin generating */ + block = drcuml->begin_block(10); + + /* generate a hash jump via the current mode and PC */ + alloc_handle(drcuml, &m_out_of_cycles, "out_of_cycles"); + UML_HANDLE(block, *m_out_of_cycles); // handle out_of_cycles + UML_GETEXP(block, I0); // getexp i0 + UML_MOV(block, mem(&m_core->pc), I0); // mov ,i0 + save_fast_iregs(block); + UML_EXIT(block, EXECUTE_OUT_OF_CYCLES); // exit EXECUTE_OUT_OF_CYCLES + + block->end(); +} + + +/*------------------------------------------------- + static_generate_tlb_mismatch - generate a + TLB mismatch handler +-------------------------------------------------*/ + +void mips3_device::static_generate_tlb_mismatch() +{ + drcuml_state *drcuml = m_drcuml; + drcuml_block *block; + + /* forward references */ + alloc_handle(drcuml, &m_exception[EXCEPTION_TLBLOAD], "exception_tlbload"); + alloc_handle(drcuml, &m_exception[EXCEPTION_TLBLOAD_FILL], "exception_tlbload_fill"); + + /* begin generating */ + block = drcuml->begin_block(20); + + /* generate a hash jump via the current mode and PC */ + alloc_handle(drcuml, &m_tlb_mismatch, "tlb_mismatch"); + UML_HANDLE(block, *m_tlb_mismatch); // handle tlb_mismatch + UML_RECOVER(block, I0, MAPVAR_PC); // recover i0,PC + UML_MOV(block, mem(&m_core->pc), I0); // mov ,i0 + UML_SHR(block, I1, I0, 12); // shr i1,i0,12 + UML_LOAD(block, I1, (void *)vtlb_table(m_vtlb), I1, SIZE_DWORD, SCALE_x4);// load i1,[vtlb_table],i1,dword + if (PRINTF_MMU) + { + static const char text[] = "TLB mismatch @ %08X (ent=%08X)\n"; + UML_MOV(block, mem(&m_core->format), (FPTR)text); // mov [format],text + UML_MOV(block, mem(&m_core->arg0), I0); // mov [arg0],i0 + UML_MOV(block, mem(&m_core->arg1), I1); // mov [arg1],i1 + UML_CALLC(block, cfunc_printf_debug, this); // callc printf_debug + } + UML_TEST(block, I1, VTLB_FETCH_ALLOWED); // test i1,VTLB_FETCH_ALLOWED + UML_JMPc(block, COND_NZ, 1); // jmp 1,nz + UML_TEST(block, I1, VTLB_FLAG_FIXED); // test i1,VTLB_FLAG_FIXED + UML_EXHc(block, COND_NZ, *m_exception[EXCEPTION_TLBLOAD], I0); // exh exception[TLBLOAD],i0,nz + UML_EXH(block, *m_exception[EXCEPTION_TLBLOAD_FILL], I0); // exh exception[TLBLOAD_FILL],i0 + UML_LABEL(block, 1); // 1: + save_fast_iregs(block); + + // the saved PC may be set 1 instruction back with the low bit set to indicate + // a delay slot; in this path we want the original instruction address, so recover it + UML_ADD(block, I0, mem(&m_core->pc), 3); // add i0,,3 + UML_AND(block, mem(&m_core->pc), I0, ~3); // and ,i0,~3 + UML_EXIT(block, EXECUTE_MISSING_CODE); // exit EXECUTE_MISSING_CODE + + block->end(); +} + + +/*------------------------------------------------- + static_generate_exception - generate a static + exception handler +-------------------------------------------------*/ + +void mips3_device::static_generate_exception(UINT8 exception, int recover, const char *name) +{ + code_handle *&exception_handle = recover ? m_exception[exception] : m_exception_norecover[exception]; + drcuml_state *drcuml = m_drcuml; + UINT32 offset = 0x180; + code_label next = 1; + code_label skip = 2; + drcuml_block *block; + + /* translate our fake fill exceptions into real exceptions */ + if (exception == EXCEPTION_TLBLOAD_FILL || exception == EXCEPTION_TLBSTORE_FILL) + { + offset = 0x000; + exception = (exception - EXCEPTION_TLBLOAD_FILL) + EXCEPTION_TLBLOAD; + } + + /* begin generating */ + block = drcuml->begin_block(1024); + + /* add a global entry for this */ + alloc_handle(drcuml, &exception_handle, name); + UML_HANDLE(block, *exception_handle); // handle name + + /* exception parameter is expected to be the fault address in this case */ + if (exception == EXCEPTION_TLBLOAD || exception == EXCEPTION_TLBSTORE || exception == EXCEPTION_TLBMOD || exception == EXCEPTION_ADDRLOAD || exception == EXCEPTION_ADDRSTORE) + { + /* set BadVAddr to the fault address */ + UML_GETEXP(block, I0); // getexp i0 + UML_TEST(block, CPR032(COP0_Status), SR_EXL); // test [Status],SR_EXL + UML_MOVc(block, COND_Z, CPR032(COP0_BadVAddr), I0); // mov [BadVAddr],i0,Z + } + + if (exception == EXCEPTION_TLBLOAD || exception == EXCEPTION_TLBSTORE) + { + /* set the upper bits of EntryHi and the lower bits of Context to the fault page */ + UML_ROLINS(block, CPR032(COP0_EntryHi), I0, 0, 0xffffe000); // rolins [EntryHi],i0,0,0xffffe000 + UML_ROLINS(block, CPR032(COP0_Context), I0, 32-9, 0x7ffff0); // rolins [Context],i0,32-9,0x7ffff0 + } + + /* set the EPC and Cause registers */ + if (recover) + { + UML_RECOVER(block, I0, MAPVAR_PC); // recover i0,PC + UML_RECOVER(block, I1, MAPVAR_CYCLES); // recover i1,CYCLES + } + + UML_AND(block, I2, CPR032(COP0_Cause), ~0x800000ff); // and i2,[Cause],~0x800000ff + UML_TEST(block, I0, 1); // test i0,1 + UML_JMPc(block, COND_Z, next); // jz + UML_OR(block, I2, I2, 0x80000000); // or i2,i2,0x80000000 + UML_SUB(block, I0, I0, 1); // sub i0,i0,1 + UML_LABEL(block, next); // : + UML_MOV(block, I3, offset); // mov i3,offset + UML_TEST(block, CPR032(COP0_Status), SR_EXL); // test [Status],SR_EXL + UML_MOVc(block, COND_Z, CPR032(COP0_EPC), I0); // mov [EPC],i0,Z + UML_MOVc(block, COND_NZ, I3, 0x180); // mov i3,0x180,NZ + UML_OR(block, CPR032(COP0_Cause), I2, exception << 2); // or [Cause],i2,exception << 2 + + /* for BADCOP exceptions, we use the exception parameter to know which COP */ + if (exception == EXCEPTION_BADCOP) + { + UML_GETEXP(block, I0); // getexp i0 + UML_ROLINS(block, CPR032(COP0_Cause), I0, 28, 0x30000000); // rolins [Cause],i0,28,0x30000000 + } + + /* set EXL in the SR */ + UML_OR(block, I0, CPR032(COP0_Status), SR_EXL); // or i0,[Status],SR_EXL + UML_MOV(block, CPR032(COP0_Status), I0); // mov [Status],i0 + generate_update_mode(block); + + /* optionally print exceptions */ + if ((PRINTF_EXCEPTIONS && exception != EXCEPTION_INTERRUPT && exception != EXCEPTION_SYSCALL) || + (PRINTF_MMU && (exception == EXCEPTION_TLBLOAD || exception == EXCEPTION_TLBSTORE))) + { + UML_CALLC(block, cfunc_printf_exception, this); // callc cfunc_printf_exception,NULL + } + + /* choose our target PC */ + UML_ADD(block, I0, I3, 0xbfc00200); // add i0,i3,0xbfc00200 + UML_TEST(block, CPR032(COP0_Status), SR_BEV); // test CPR032(COP0_Status),SR_BEV + UML_JMPc(block, COND_NZ, skip); // jnz + UML_ADD(block, I0, I3, 0x80000000); // add i0,i3,0x80000000,z + UML_LABEL(block, skip); // : + + /* adjust cycles */ + UML_SUB(block, mem(&m_core->icount), mem(&m_core->icount), I1); // sub icount,icount,cycles,S + UML_EXHc(block, COND_S, *m_out_of_cycles, I0); // exh out_of_cycles,i0 + + UML_HASHJMP(block, mem(&m_core->mode), I0, *m_nocode);// hashjmp ,i0,nocode + + block->end(); +} + + +/*------------------------------------------------------------------ + static_generate_memory_accessor +------------------------------------------------------------------*/ + +void mips3_device::static_generate_memory_accessor(int mode, int size, int iswrite, int ismasked, const char *name, code_handle **handleptr) +{ + /* on entry, address is in I0; data for writes is in I1; mask for accesses is in I2 */ + /* on exit, read result is in I0 */ + /* routine trashes I0-I3 */ + code_handle &exception_tlb = *m_exception[iswrite ? EXCEPTION_TLBSTORE : EXCEPTION_TLBLOAD]; + code_handle &exception_tlbfill = *m_exception[iswrite ? EXCEPTION_TLBSTORE_FILL : EXCEPTION_TLBLOAD_FILL]; + code_handle &exception_addrerr = *m_exception[iswrite ? EXCEPTION_ADDRSTORE : EXCEPTION_ADDRLOAD]; + drcuml_state *drcuml = m_drcuml; + drcuml_block *block; + int tlbmiss = 0; + int label = 1; + int ramnum; + + /* begin generating */ + block = drcuml->begin_block(1024); + + /* add a global entry for this */ + alloc_handle(drcuml, handleptr, name); + UML_HANDLE(block, **handleptr); // handle *handleptr + + /* user mode? generate address exception if top bit is set */ + if (mode == MODE_USER) + { + UML_TEST(block, I0, 0x80000000); // test i0,0x80000000 + UML_EXHc(block, COND_NZ, exception_addrerr, I0); // exh addrerr,i0,nz + } + + /* supervisor mode? generate address exception if not in user space or in $C0000000-DFFFFFFF */ + if (mode == MODE_SUPER) + { + int addrok; + UML_TEST(block, I0, 0x80000000); // test i0,0x80000000 + UML_JMPc(block, COND_Z, addrok = label++); // jz addrok + UML_SHR(block, I3, I0, 29); // shr i3,i0,29 + UML_CMP(block, I3, 6); // cmp i3,6 + UML_EXHc(block, COND_NE, exception_addrerr, I0); // exh addrerr,i0,ne + UML_LABEL(block, addrok); // addrok: + } + + /* general case: assume paging and perform a translation */ + UML_SHR(block, I3, I0, 12); // shr i3,i0,12 + UML_LOAD(block, I3, (void *)vtlb_table(m_vtlb), I3, SIZE_DWORD, SCALE_x4);// load i3,[vtlb_table],i3,dword + UML_TEST(block, I3, iswrite ? VTLB_WRITE_ALLOWED : VTLB_READ_ALLOWED);// test i3,iswrite ? VTLB_WRITE_ALLOWED : VTLB_READ_ALLOWED + UML_JMPc(block, COND_Z, tlbmiss = label++); // jmp tlbmiss,z + UML_ROLINS(block, I0, I3, 0, 0xfffff000); // rolins i0,i3,0,0xfffff000 + + if ((machine().debug_flags & DEBUG_FLAG_ENABLED) == 0) + for (ramnum = 0; ramnum < MIPS3_MAX_FASTRAM; ramnum++) + if (m_fastram[ramnum].base != NULL && (!iswrite || !m_fastram[ramnum].readonly)) + { + void *fastbase = (UINT8 *)m_fastram[ramnum].base - m_fastram[ramnum].start; + UINT32 skip = label++; + if (m_fastram[ramnum].end != 0xffffffff) + { + UML_CMP(block, I0, m_fastram[ramnum].end); // cmp i0,end + UML_JMPc(block, COND_A, skip); // ja skip + } + if (m_fastram[ramnum].start != 0x00000000) + { + UML_CMP(block, I0, m_fastram[ramnum].start);// cmp i0,fastram_start + UML_JMPc(block, COND_B, skip); // jb skip + } + + if (!iswrite) + { + if (size == 1) + { + UML_XOR(block, I0, I0, m_bigendian ? BYTE4_XOR_BE(0) : BYTE4_XOR_LE(0)); + // xor i0,i0,bytexor + UML_LOAD(block, I0, fastbase, I0, SIZE_BYTE, SCALE_x1); // load i0,fastbase,i0,byte + } + else if (size == 2) + { + UML_XOR(block, I0, I0, m_bigendian ? WORD_XOR_BE(0) : WORD_XOR_LE(0)); + // xor i0,i0,wordxor + UML_LOAD(block, I0, fastbase, I0, SIZE_WORD, SCALE_x1); // load i0,fastbase,i0,word_x1 + } + else if (size == 4) + { + UML_LOAD(block, I0, fastbase, I0, SIZE_DWORD, SCALE_x1); // load i0,fastbase,i0,dword_x1 + } + else if (size == 8) + { + UML_DLOAD(block, I0, fastbase, I0, SIZE_QWORD, SCALE_x1); // dload i0,fastbase,i0,qword_x1 + UML_DROR(block, I0, I0, 32 * (m_bigendian ? BYTE_XOR_BE(0) : BYTE_XOR_LE(0))); + // dror i0,i0,32*bytexor + } + UML_RET(block); // ret + } + else + { + if (size == 1) + { + UML_XOR(block, I0, I0, m_bigendian ? BYTE4_XOR_BE(0) : BYTE4_XOR_LE(0)); + // xor i0,i0,bytexor + UML_STORE(block, fastbase, I0, I1, SIZE_BYTE, SCALE_x1);// store fastbase,i0,i1,byte + } + else if (size == 2) + { + UML_XOR(block, I0, I0, m_bigendian ? WORD_XOR_BE(0) : WORD_XOR_LE(0)); + // xor i0,i0,wordxor + UML_STORE(block, fastbase, I0, I1, SIZE_WORD, SCALE_x1);// store fastbase,i0,i1,word_x1 + } + else if (size == 4) + { + if (ismasked) + { + UML_LOAD(block, I3, fastbase, I0, SIZE_DWORD, SCALE_x1); // load i3,fastbase,i0,dword_x1 + UML_ROLINS(block, I3, I1, 0, I2); // rolins i3,i1,0,i2 + UML_STORE(block, fastbase, I0, I3, SIZE_DWORD, SCALE_x1); // store fastbase,i0,i3,dword_x1 + } + else + UML_STORE(block, fastbase, I0, I1, SIZE_DWORD, SCALE_x1); // store fastbase,i0,i1,dword_x1 + } + else if (size == 8) + { + UML_DROR(block, I1, I1, 32 * (m_bigendian ? BYTE_XOR_BE(0) : BYTE_XOR_LE(0))); + // dror i1,i1,32*bytexor + if (ismasked) + { + UML_DROR(block, I2, I2, 32 * (m_bigendian ? BYTE_XOR_BE(0) : BYTE_XOR_LE(0))); + // dror i2,i2,32*bytexor + UML_DLOAD(block, I3, fastbase, I0, SIZE_QWORD, SCALE_x1); // dload i3,fastbase,i0,qword_x1 + UML_DROLINS(block, I3, I1, 0, I2); // drolins i3,i1,0,i2 + UML_DSTORE(block, fastbase, I0, I3, SIZE_QWORD, SCALE_x1); // dstore fastbase,i0,i3,qword_x1 + } + else + UML_DSTORE(block, fastbase, I0, I1, SIZE_QWORD, SCALE_x1); // dstore fastbase,i0,i1,qword_x1 + } + UML_RET(block); // ret + } + + UML_LABEL(block, skip); // skip: + } + + switch (size) + { + case 1: + if (iswrite) + UML_WRITE(block, I0, I1, SIZE_BYTE, SPACE_PROGRAM); // write i0,i1,program_byte + else + UML_READ(block, I0, I0, SIZE_BYTE, SPACE_PROGRAM); // read i0,i0,program_byte + break; + + case 2: + if (iswrite) + UML_WRITE(block, I0, I1, SIZE_WORD, SPACE_PROGRAM); // write i0,i1,program_word + else + UML_READ(block, I0, I0, SIZE_WORD, SPACE_PROGRAM); // read i0,i0,program_word + break; + + case 4: + if (iswrite) + { + if (!ismasked) + UML_WRITE(block, I0, I1, SIZE_DWORD, SPACE_PROGRAM); // write i0,i1,program_dword + else + UML_WRITEM(block, I0, I1, I2, SIZE_DWORD, SPACE_PROGRAM); // writem i0,i1,i2,program_dword + } + else + { + if (!ismasked) + UML_READ(block, I0, I0, SIZE_DWORD, SPACE_PROGRAM); // read i0,i0,program_dword + else + UML_READM(block, I0, I0, I2, SIZE_DWORD, SPACE_PROGRAM); // readm i0,i0,i2,program_dword + } + break; + + case 8: + if (iswrite) + { + if (!ismasked) + UML_DWRITE(block, I0, I1, SIZE_QWORD, SPACE_PROGRAM); // dwrite i0,i1,program_qword + else + UML_DWRITEM(block, I0, I1, I2, SIZE_QWORD, SPACE_PROGRAM); // dwritem i0,i1,i2,program_qword + } + else + { + if (!ismasked) + UML_DREAD(block, I0, I0, SIZE_QWORD, SPACE_PROGRAM); // dread i0,i0,program_qword + else + UML_DREADM(block, I0, I0, I2, SIZE_QWORD, SPACE_PROGRAM); // dreadm i0,i0,i2,program_qword + } + break; + } + UML_RET(block); // ret + + if (tlbmiss != 0) + { + UML_LABEL(block, tlbmiss); // tlbmiss: + if (iswrite) + { + UML_TEST(block, I3, VTLB_READ_ALLOWED); // test i3,VTLB_READ_ALLOWED + UML_EXHc(block, COND_NZ, *m_exception[EXCEPTION_TLBMOD], I0); + // exh tlbmod,i0,nz + } + UML_TEST(block, I3, VTLB_FLAG_FIXED); // test i3,VTLB_FLAG_FIXED + UML_EXHc(block, COND_NZ, exception_tlb, I0); // exh tlb,i0,nz + UML_EXH(block, exception_tlbfill, I0); // exh tlbfill,i0 + } + + block->end(); +} + + + +/*************************************************************************** + CODE GENERATION +***************************************************************************/ + +/*------------------------------------------------- + generate_update_mode - update the mode based + on a new SR (in i0); trashes i2 +-------------------------------------------------*/ + +void mips3_device::generate_update_mode(drcuml_block *block) +{ + UML_ROLAND(block, I2, I0, 32-2, 0x06); // roland i2,i0,32-2,0x06 + UML_TEST(block, I0, SR_EXL | SR_ERL); // test i0,SR_EXL | SR_ERL + UML_MOVc(block, COND_NZ, I2, 0); // mov i2,0,nz + UML_ROLINS(block, I2, I0, 32-26, 0x01); // rolins i2,i0,32-26,0x01 + UML_MOV(block, mem(&m_core->mode), I2); // mov [mode],i2 +} + + +/*------------------------------------------------- + generate_update_cycles - generate code to + subtract cycles from the icount and generate + an exception if out +-------------------------------------------------*/ + +void mips3_device::generate_update_cycles(drcuml_block *block, compiler_state *compiler, uml::parameter param, int allow_exception) +{ + /* check software interrupts if pending */ + if (compiler->checksoftints) + { + code_label skip; + + compiler->checksoftints = FALSE; + UML_AND(block, I0, CPR032(COP0_Cause), CPR032(COP0_Status)); // and i0,[Cause],[Status] + UML_AND(block, I0, I0, 0x0300); // and i0,i0,0x0300 + UML_JMPc(block, COND_Z, skip = compiler->labelnum++); // jmp skip,Z + UML_MOV(block, I0, param); // mov i0,nextpc + UML_MOV(block, I1, compiler->cycles); // mov i1,cycles + UML_CALLH(block, *m_exception_norecover[EXCEPTION_INTERRUPT]);// callh interrupt_norecover + UML_LABEL(block, skip); // skip: + } + + /* check full interrupts if pending */ + if (compiler->checkints) + { + code_label skip; + + compiler->checkints = FALSE; + UML_AND(block, I0, CPR032(COP0_Cause), CPR032(COP0_Status)); // and i0,[Cause],[Status] + UML_AND(block, I0, I0, 0xfc00); // and i0,i0,0xfc00 + UML_JMPc(block, COND_Z, skip = compiler->labelnum++); // jmp skip,Z + UML_TEST(block, CPR032(COP0_Status), SR_IE); // test [Status],SR_IE + UML_JMPc(block, COND_Z, skip); // jmp skip,Z + UML_TEST(block, CPR032(COP0_Status), SR_EXL | SR_ERL); // test [Status],SR_EXL | SR_ERL + UML_JMPc(block, COND_NZ, skip); // jmp skip,NZ + UML_MOV(block, I0, param); // mov i0,nextpc + UML_MOV(block, I1, compiler->cycles); // mov i1,cycles + UML_CALLH(block, *m_exception_norecover[EXCEPTION_INTERRUPT]);// callh interrupt_norecover + UML_LABEL(block, skip); // skip: + } + + /* account for cycles */ + if (compiler->cycles > 0) + { + UML_SUB(block, mem(&m_core->icount), mem(&m_core->icount), MAPVAR_CYCLES); // sub icount,icount,cycles + UML_MAPVAR(block, MAPVAR_CYCLES, 0); // mapvar cycles,0 + if (allow_exception) + UML_EXHc(block, COND_S, *m_out_of_cycles, param); + // exh out_of_cycles,nextpc + } + compiler->cycles = 0; +} + + +/*------------------------------------------------- + generate_checksum_block - generate code to + validate a sequence of opcodes +-------------------------------------------------*/ + +void mips3_device::generate_checksum_block(drcuml_block *block, compiler_state *compiler, const opcode_desc *seqhead, const opcode_desc *seqlast) +{ + const opcode_desc *curdesc; + if (m_drcuml->logging()) + block->append_comment("[Validation for %08X]", seqhead->pc); // comment + + /* loose verify or single instruction: just compare and fail */ + if (!(m_drcoptions & MIPS3DRC_STRICT_VERIFY) || seqhead->next() == NULL) + { + if (!(seqhead->flags & OPFLAG_VIRTUAL_NOOP)) + { + UINT32 sum = seqhead->opptr.l[0]; + void *base = m_direct->read_ptr(seqhead->physpc); + UML_LOAD(block, I0, base, 0, SIZE_DWORD, SCALE_x4); // load i0,base,0,dword + + if (seqhead->delay.first() != NULL && seqhead->physpc != seqhead->delay.first()->physpc) + { + base = m_direct->read_ptr(seqhead->delay.first()->physpc); + assert(base != NULL); + UML_LOAD(block, I1, base, 0, SIZE_DWORD, SCALE_x4); // load i1,base,dword + UML_ADD(block, I0, I0, I1); // add i0,i0,i1 + + sum += seqhead->delay.first()->opptr.l[0]; + } + + UML_CMP(block, I0, sum); // cmp i0,opptr[0] + UML_EXHc(block, COND_NE, *m_nocode, epc(seqhead)); // exne nocode,seqhead->pc + } + } + + /* full verification; sum up everything */ + else + { +#if 0 + for (curdesc = seqhead->next(); curdesc != seqlast->next(); curdesc = curdesc->next()) + if (!(curdesc->flags & OPFLAG_VIRTUAL_NOOP)) + { + void *base = m_direct->read_ptr(seqhead->physpc); + UML_LOAD(block, I0, base, 0, SIZE_DWORD, SCALE_x4); // load i0,base,0,dword + UML_CMP(block, I0, curdesc->opptr.l[0]); // cmp i0,opptr[0] + UML_EXHc(block, COND_NE, *m_nocode, epc(seqhead)); // exne nocode,seqhead->pc + } +#else + UINT32 sum = 0; + void *base = m_direct->read_ptr(seqhead->physpc); + UML_LOAD(block, I0, base, 0, SIZE_DWORD, SCALE_x4); // load i0,base,0,dword + sum += seqhead->opptr.l[0]; + for (curdesc = seqhead->next(); curdesc != seqlast->next(); curdesc = curdesc->next()) + if (!(curdesc->flags & OPFLAG_VIRTUAL_NOOP)) + { + base = m_direct->read_ptr(curdesc->physpc); + assert(base != NULL); + UML_LOAD(block, I1, base, 0, SIZE_DWORD, SCALE_x4); // load i1,base,dword + UML_ADD(block, I0, I0, I1); // add i0,i0,i1 + sum += curdesc->opptr.l[0]; + + if (curdesc->delay.first() != NULL && (curdesc == seqlast || (curdesc->next() != NULL && curdesc->next()->physpc != curdesc->delay.first()->physpc))) + { + base = m_direct->read_ptr(curdesc->delay.first()->physpc); + assert(base != NULL); + UML_LOAD(block, I1, base, 0, SIZE_DWORD, SCALE_x4); // load i1,base,dword + UML_ADD(block, I0, I0, I1); // add i0,i0,i1 + sum += curdesc->delay.first()->opptr.l[0]; + } + } + UML_CMP(block, I0, sum); // cmp i0,sum + UML_EXHc(block, COND_NE, *m_nocode, epc(seqhead)); // exne nocode,seqhead->pc +#endif + } +} + + +/*------------------------------------------------- + generate_sequence_instruction - generate code + for a single instruction in a sequence +-------------------------------------------------*/ + +void mips3_device::generate_sequence_instruction(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) +{ + offs_t expc; + int hotnum; + + /* add an entry for the log */ + if (m_drcuml->logging() && !(desc->flags & OPFLAG_VIRTUAL_NOOP)) + log_add_disasm_comment(block, desc->pc, desc->opptr.l[0]); + + /* set the PC map variable */ + expc = (desc->flags & OPFLAG_IN_DELAY_SLOT) ? desc->pc - 3 : desc->pc; + UML_MAPVAR(block, MAPVAR_PC, expc); // mapvar PC,expc + + /* accumulate total cycles */ + compiler->cycles += desc->cycles; + + /* is this a hotspot? */ + for (hotnum = 0; hotnum < MIPS3_MAX_HOTSPOTS; hotnum++) + if (m_hotspot[hotnum].pc != 0 && desc->pc == m_hotspot[hotnum].pc && desc->opptr.l[0] == m_hotspot[hotnum].opcode) + { + compiler->cycles += m_hotspot[hotnum].cycles; + break; + } + + /* update the icount map variable */ + UML_MAPVAR(block, MAPVAR_CYCLES, compiler->cycles); // mapvar CYCLES,compiler->cycles + + /* if we want a probe, add it here */ + if (desc->pc == PROBE_ADDRESS) + { + UML_MOV(block, mem(&m_core->pc), desc->pc); // mov [pc],desc->pc + UML_CALLC(block, cfunc_printf_probe, this); // callc cfunc_printf_probe,mips3 + } + + /* if we are debugging, call the debugger */ + if ((machine().debug_flags & DEBUG_FLAG_ENABLED) != 0) + { + UML_MOV(block, mem(&m_core->pc), desc->pc); // mov [pc],desc->pc + save_fast_iregs(block); + UML_DEBUG(block, desc->pc); // debug desc->pc + } + + /* if we hit an unmapped address, fatal error */ + if (desc->flags & OPFLAG_COMPILER_UNMAPPED) + { + UML_MOV(block, mem(&m_core->pc), desc->pc); // mov [pc],desc->pc + save_fast_iregs(block); + UML_EXIT(block, EXECUTE_UNMAPPED_CODE); // exit EXECUTE_UNMAPPED_CODE + } + + /* if we hit a compiler page fault, it's just like a TLB mismatch */ + if (desc->flags & OPFLAG_COMPILER_PAGE_FAULT) + { + if (PRINTF_MMU) + { + static const char text[] = "Compiler page fault @ %08X"; + UML_MOV(block, mem(&m_core->format), (FPTR)text); // mov [format],text + UML_MOV(block, mem(&m_core->arg0), desc->pc); // mov [arg0],desc->pc + UML_CALLC(block, cfunc_printf_debug, this); // callc printf_debug + } + UML_EXH(block, *m_tlb_mismatch, 0); // exh tlb_mismatch,0 + } + + /* validate our TLB entry at this PC; if we fail, we need to handle it */ + if ((desc->flags & OPFLAG_VALIDATE_TLB) && (desc->pc < 0x80000000 || desc->pc >= 0xc0000000)) + { + const vtlb_entry *tlbtable = vtlb_table(m_vtlb); + + /* if we currently have a valid TLB read entry, we just verify */ + if (tlbtable[desc->pc >> 12] & VTLB_FETCH_ALLOWED) + { + if (PRINTF_MMU) + { + static const char text[] = "Checking TLB at @ %08X\n"; + UML_MOV(block, mem(&m_core->format), (FPTR)text); // mov [format],text + UML_MOV(block, mem(&m_core->arg0), desc->pc); // mov [arg0],desc->pc + UML_CALLC(block, cfunc_printf_debug, this); // callc printf_debug + } + UML_LOAD(block, I0, &tlbtable[desc->pc >> 12], 0, SIZE_DWORD, SCALE_x4); // load i0,tlbtable[desc->pc >> 12],0,dword + UML_CMP(block, I0, tlbtable[desc->pc >> 12]); // cmp i0,*tlbentry + UML_EXHc(block, COND_NE, *m_tlb_mismatch, 0); // exh tlb_mismatch,0,NE + } + + /* otherwise, we generate an unconditional exception */ + else + { + if (PRINTF_MMU) + { + static const char text[] = "No valid TLB @ %08X\n"; + UML_MOV(block, mem(&m_core->format), (FPTR)text); // mov [format],text + UML_MOV(block, mem(&m_core->arg0), desc->pc); // mov [arg0],desc->pc + UML_CALLC(block, cfunc_printf_debug, this); // callc printf_debug + } + UML_EXH(block, *m_tlb_mismatch, 0); // exh tlb_mismatch,0 + } + } + + /* if this is an invalid opcode, generate the exception now */ + if (desc->flags & OPFLAG_INVALID_OPCODE) + UML_EXH(block, *m_exception[EXCEPTION_INVALIDOP], 0); // exh invalidop,0 + + /* otherwise, unless this is a virtual no-op, it's a regular instruction */ + else if (!(desc->flags & OPFLAG_VIRTUAL_NOOP)) + { + /* compile the instruction */ + if (!generate_opcode(block, compiler, desc)) + { + UML_MOV(block, mem(&m_core->pc), desc->pc); // mov [pc],desc->pc + UML_MOV(block, mem(&m_core->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_unimplemented, this); // callc cfunc_unimplemented + } + } +} + + +/*------------------------------------------------------------------ + generate_delay_slot_and_branch +------------------------------------------------------------------*/ + +void mips3_device::generate_delay_slot_and_branch(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, UINT8 linkreg) +{ + compiler_state compiler_temp = *compiler; + UINT32 op = desc->opptr.l[0]; + + /* fetch the target register if dynamic, in case it is modified by the delay slot */ + if (desc->targetpc == BRANCH_TARGET_DYNAMIC) + { + UML_MOV(block, mem(&m_core->jmpdest), R32(RSREG)); // mov [jmpdest], + + } + + /* set the link if needed -- before the delay slot */ + if (linkreg != 0) + { + UML_DMOV(block, R64(linkreg), (INT32)(desc->pc + 8)); // dmov ,desc->pc + 8 + } + + /* compile the delay slot using temporary compiler state */ + assert(desc->delay.first() != NULL); + generate_sequence_instruction(block, &compiler_temp, desc->delay.first()); // + + /* update the cycles and jump through the hash table to the target */ + if (desc->targetpc != BRANCH_TARGET_DYNAMIC) + { + generate_update_cycles(block, &compiler_temp, desc->targetpc, TRUE); // + if (desc->flags & OPFLAG_INTRABLOCK_BRANCH) + UML_JMP(block, desc->targetpc | 0x80000000); // jmp desc->targetpc | 0x80000000 + else + UML_HASHJMP(block, m_core->mode, desc->targetpc, *m_nocode); + // hashjmp ,desc->targetpc,nocode + } + else + { + generate_update_cycles(block, &compiler_temp, mem(&m_core->jmpdest), TRUE); + // + UML_HASHJMP(block, m_core->mode, mem(&m_core->jmpdest), *m_nocode); + // hashjmp ,,nocode + } + + /* update the label */ + compiler->labelnum = compiler_temp.labelnum; + + /* reset the mapvar to the current cycles and account for skipped slots */ + compiler->cycles += desc->skipslots; + UML_MAPVAR(block, MAPVAR_CYCLES, compiler->cycles); // mapvar CYCLES,compiler->cycles +} + + +/*------------------------------------------------- + generate_opcode - generate code for a specific + opcode +-------------------------------------------------*/ + +int mips3_device::generate_opcode(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) +{ + int in_delay_slot = ((desc->flags & OPFLAG_IN_DELAY_SLOT) != 0); + UINT32 op = desc->opptr.l[0]; + UINT8 opswitch = op >> 26; + code_label skip; + + switch (opswitch) + { + /* ----- sub-groups ----- */ + + case 0x00: /* SPECIAL - MIPS I */ + return generate_special(block, compiler, desc); + + case 0x01: /* REGIMM - MIPS I */ + return generate_regimm(block, compiler, desc); + + case 0x1c: /* IDT-specific */ + return generate_idt(block, compiler, desc); + + + /* ----- jumps and branches ----- */ + + case 0x02: /* J - MIPS I */ + generate_delay_slot_and_branch(block, compiler, desc, 0); // + return TRUE; + + case 0x03: /* JAL - MIPS I */ + generate_delay_slot_and_branch(block, compiler, desc, 31); // + return TRUE; + + case 0x04: /* BEQ - MIPS I */ + case 0x14: /* BEQL - MIPS II */ + UML_DCMP(block, R64(RSREG), R64(RTREG)); // dcmp , + UML_JMPc(block, COND_NE, skip = compiler->labelnum++); // jmp skip,NE + generate_delay_slot_and_branch(block, compiler, desc, 0); // + UML_LABEL(block, skip); // skip: + return TRUE; + + case 0x05: /* BNE - MIPS I */ + case 0x15: /* BNEL - MIPS II */ + UML_DCMP(block, R64(RSREG), R64(RTREG)); // dcmp , + UML_JMPc(block, COND_E, skip = compiler->labelnum++); // jmp skip,E + generate_delay_slot_and_branch(block, compiler, desc, 0); // + UML_LABEL(block, skip); // skip: + return TRUE; + + case 0x06: /* BLEZ - MIPS I */ + case 0x16: /* BLEZL - MIPS II */ + if (RSREG != 0) + { + UML_DCMP(block, R64(RSREG), 0); // dcmp ,0 + UML_JMPc(block, COND_G, skip = compiler->labelnum++); // jmp skip,G + generate_delay_slot_and_branch(block, compiler, desc, 0); // + UML_LABEL(block, skip); // skip: + } + else + generate_delay_slot_and_branch(block, compiler, desc, 0); // + return TRUE; + + case 0x07: /* BGTZ - MIPS I */ + case 0x17: /* BGTZL - MIPS II */ + UML_DCMP(block, R64(RSREG), 0); // dcmp ,0 + UML_JMPc(block, COND_LE, skip = compiler->labelnum++); // jmp skip,LE + generate_delay_slot_and_branch(block, compiler, desc, 0); // + UML_LABEL(block, skip); // skip: + return TRUE; + + + /* ----- immediate arithmetic ----- */ + + case 0x0f: /* LUI - MIPS I */ + if (RTREG != 0) + UML_DMOV(block, R64(RTREG), UIMMVAL << 16); // dmov ,UIMMVAL << 16 + return TRUE; + + case 0x08: /* ADDI - MIPS I */ + UML_ADD(block, I0, R32(RSREG), SIMMVAL); // add i0,,SIMMVAL + if (m_drcoptions & MIPS3DRC_CHECK_OVERFLOWS) + UML_EXHc(block, COND_V, *m_exception[EXCEPTION_OVERFLOW], 0); + // exh overflow,0 + if (RTREG != 0) + UML_DSEXT(block, R64(RTREG), I0, SIZE_DWORD); // dsext ,i0,dword + return TRUE; + + case 0x09: /* ADDIU - MIPS I */ + if (RTREG != 0) + { + UML_ADD(block, I0, R32(RSREG), SIMMVAL); // add i0,,SIMMVAL,V + UML_DSEXT(block, R64(RTREG), I0, SIZE_DWORD); // dsext ,i0,dword + } + return TRUE; + + case 0x18: /* DADDI - MIPS III */ + UML_DADD(block, I0, R64(RSREG), SIMMVAL); // dadd i0,,SIMMVAL + if (m_drcoptions & MIPS3DRC_CHECK_OVERFLOWS) + UML_EXHc(block, COND_V, *m_exception[EXCEPTION_OVERFLOW], 0); + // exh overflow,0 + if (RTREG != 0) + UML_DMOV(block, R64(RTREG), I0); // dmov ,i0 + return TRUE; + + case 0x19: /* DADDIU - MIPS III */ + if (RTREG != 0) + UML_DADD(block, R64(RTREG), R64(RSREG), SIMMVAL); // dadd ,,SIMMVAL + return TRUE; + + case 0x0c: /* ANDI - MIPS I */ + if (RTREG != 0) + UML_DAND(block, R64(RTREG), R64(RSREG), UIMMVAL); // dand ,,UIMMVAL + return TRUE; + + case 0x0d: /* ORI - MIPS I */ + if (RTREG != 0) + UML_DOR(block, R64(RTREG), R64(RSREG), UIMMVAL); // dor ,,UIMMVAL + return TRUE; + + case 0x0e: /* XORI - MIPS I */ + if (RTREG != 0) + UML_DXOR(block, R64(RTREG), R64(RSREG), UIMMVAL); // dxor ,,UIMMVAL + return TRUE; + + case 0x0a: /* SLTI - MIPS I */ + if (RTREG != 0) + { + UML_DCMP(block, R64(RSREG), SIMMVAL); // dcmp ,SIMMVAL + UML_DSETc(block, COND_L, R64(RTREG)); // dset ,l + } + return TRUE; + + case 0x0b: /* SLTIU - MIPS I */ + if (RTREG != 0) + { + UML_DCMP(block, R64(RSREG), SIMMVAL); // dcmp ,SIMMVAL + UML_DSETc(block, COND_B, R64(RTREG)); // dset ,b + } + return TRUE; + + + /* ----- memory load operations ----- */ + + case 0x20: /* LB - MIPS I */ + UML_ADD(block, I0, R32(RSREG), SIMMVAL); // add i0,,SIMMVAL + UML_CALLH(block, *m_read8[m_core->mode >> 1]); // callh read8 + if (RTREG != 0) + UML_DSEXT(block, R64(RTREG), I0, SIZE_BYTE); // dsext ,i0,byte + if (!in_delay_slot) + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); + return TRUE; + + case 0x21: /* LH - MIPS I */ + UML_ADD(block, I0, R32(RSREG), SIMMVAL); // add i0,,SIMMVAL + UML_CALLH(block, *m_read16[m_core->mode >> 1]); // callh read16 + if (RTREG != 0) + UML_DSEXT(block, R64(RTREG), I0, SIZE_WORD); // dsext ,i0,word + if (!in_delay_slot) + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); + return TRUE; + + case 0x23: /* LW - MIPS I */ + UML_ADD(block, I0, R32(RSREG), SIMMVAL); // add i0,,SIMMVAL + UML_CALLH(block, *m_read32[m_core->mode >> 1]); // callh read32 + if (RTREG != 0) + UML_DSEXT(block, R64(RTREG), I0, SIZE_DWORD); // dsext ,i0 + if (!in_delay_slot) + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); + return TRUE; + + case 0x30: /* LL - MIPS II */ + UML_ADD(block, I0, R32(RSREG), SIMMVAL); // add i0,,SIMMVAL + UML_CALLH(block, *m_read32[m_core->mode >> 1]); // callh read32 + if (RTREG != 0) + UML_DSEXT(block, R64(RTREG), I0, SIZE_DWORD); // dsext ,i0 + UML_MOV(block, mem(&m_core->llbit), 1); // mov [llbit],1 + if (!in_delay_slot) + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); + return TRUE; + + case 0x24: /* LBU - MIPS I */ + UML_ADD(block, I0, R32(RSREG), SIMMVAL); // add i0,,SIMMVAL + UML_CALLH(block, *m_read8[m_core->mode >> 1]); // callh read8 + if (RTREG != 0) + UML_DAND(block, R64(RTREG), I0, 0xff); // dand ,i0,0xff + if (!in_delay_slot) + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); + return TRUE; + + case 0x25: /* LHU - MIPS I */ + UML_ADD(block, I0, R32(RSREG), SIMMVAL); // add i0,,SIMMVAL + UML_CALLH(block, *m_read16[m_core->mode >> 1]); // callh read16 + if (RTREG != 0) + UML_DAND(block, R64(RTREG), I0, 0xffff); // dand ,i0,0xffff + if (!in_delay_slot) + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); + return TRUE; + + case 0x27: /* LWU - MIPS III */ + UML_ADD(block, I0, R32(RSREG), SIMMVAL); // add i0,,SIMMVAL + UML_CALLH(block, *m_read32[m_core->mode >> 1]); // callh read32 + if (RTREG != 0) + UML_DAND(block, R64(RTREG), I0, 0xffffffff); // dand ,i0,0xffffffff + if (!in_delay_slot) + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); + return TRUE; + + case 0x37: /* LD - MIPS III */ + UML_ADD(block, I0, R32(RSREG), SIMMVAL); // add i0,,SIMMVAL + UML_CALLH(block, *m_read64[m_core->mode >> 1]); // callh read64 + if (RTREG != 0) + UML_DMOV(block, R64(RTREG), I0); // dmov ,i0 + if (!in_delay_slot) + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); + return TRUE; + + case 0x34: /* LLD - MIPS III */ + UML_ADD(block, I0, R32(RSREG), SIMMVAL); // add i0,,SIMMVAL + UML_CALLH(block, *m_read64[m_core->mode >> 1]); // callh read64 + if (RTREG != 0) + UML_DMOV(block, R64(RTREG), I0); // dmov ,i0 + UML_MOV(block, mem(&m_core->llbit), 1); // mov [llbit],1 + if (!in_delay_slot) + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); + return TRUE; + + case 0x22: /* LWL - MIPS I */ + UML_ADD(block, I0, R32(RSREG), SIMMVAL); // add i0,,SIMMVAL + UML_SHL(block, I1, I0, 3); // shl i1,i0,3 + UML_AND(block, I0, I0, ~3); // and i0,i0,~3 + if (!m_bigendian) + UML_XOR(block, I1, I1, 0x18); // xor i1,i1,0x18 + UML_SHR(block, I2, ~0, I1); // shr i2,~0,i1 + UML_CALLH(block, *m_read32mask[m_core->mode >> 1]); + // callh read32mask + if (RTREG != 0) + { + UML_SHL(block, I2, ~0, I1); // shl i2,~0,i1 + UML_MOV(block, I3, R32(RTREG)); // mov i3, + UML_ROLINS(block, I3, I0, I1, I2); // rolins i3,i0,i1,i2 + UML_DSEXT(block, R64(RTREG), I3, SIZE_DWORD); // dsext ,i3,dword + } + if (!in_delay_slot) + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); + return TRUE; + + case 0x26: /* LWR - MIPS I */ + UML_ADD(block, I0, R32(RSREG), SIMMVAL); // add i0,,SIMMVAL + UML_SHL(block, I1, I0, 3); // shl i1,i0,3 + UML_AND(block, I0, I0, ~3); // and i0,i0,~3 + if (m_bigendian) + UML_XOR(block, I1, I1, 0x18); // xor i1,i1,0x18 + UML_SHL(block, I2, ~0, I1); // shl i2,~0,i1 + UML_CALLH(block, *m_read32mask[m_core->mode >> 1]); + // callh read32mask + if (RTREG != 0) + { + UML_SHR(block, I2, ~0, I1); // shr i2,~0,i1 + UML_SUB(block, I1, 32, I1); // sub i1,32,i1 + UML_MOV(block, I3, R32(RTREG)); // mov i3, + UML_ROLINS(block, I3, I0, I1, I2); // rolins i3,i0,i1,i2 + UML_DSEXT(block, R64(RTREG), I3, SIZE_DWORD); // dsext ,i3,dword + } + if (!in_delay_slot) + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); + return TRUE; + + case 0x1a: /* LDL - MIPS III */ + UML_ADD(block, I0, R32(RSREG), SIMMVAL); // add i0,,SIMMVAL + UML_SHL(block, I1, I0, 3); // shl i1,i0,3 + UML_AND(block, I0, I0, ~7); // and i0,i0,~7 + if (!m_bigendian) + UML_XOR(block, I1, I1, 0x38); // xor i1,i1,0x38 + UML_DSHR(block, I2, (UINT64)~0, I1); // dshr i2,~0,i1 + UML_CALLH(block, *m_read64mask[m_core->mode >> 1]); + // callh read64mask + if (RTREG != 0) + { + UML_DSHL(block, I2, (UINT64)~0, I1); // dshl i2,~0,i1 + UML_DROLINS(block, R64(RTREG), I0, I1, I2); // drolins ,i0,i1,i2 + } + if (!in_delay_slot) + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); + return TRUE; + + case 0x1b: /* LDR - MIPS III */ + UML_ADD(block, I0, R32(RSREG), SIMMVAL); // add i0,,SIMMVAL + UML_SHL(block, I1, I0, 3); // shl i1,i0,3 + UML_AND(block, I0, I0, ~7); // and i0,i0,~7 + if (m_bigendian) + UML_XOR(block, I1, I1, 0x38); // xor i1,i1,0x38 + UML_DSHL(block, I2, (UINT64)~0, I1); // dshl i2,~0,i1 + UML_CALLH(block, *m_read64mask[m_core->mode >> 1]); + // callh read64mask + if (RTREG != 0) + { + UML_DSHR(block, I2, (UINT64)~0, I1); // dshr i2,~0,i1 + UML_SUB(block, I1, 64, I1); // sub i1,64,i1 + UML_DROLINS(block, R64(RTREG), I0, I1, I2); // drolins ,i0,i1,i2 + } + if (!in_delay_slot) + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); + return TRUE; + + case 0x31: /* LWC1 - MIPS I */ + check_cop1_access(block); + UML_ADD(block, I0, R32(RSREG), SIMMVAL); // add i0,,SIMMVAL + UML_CALLH(block, *m_read32[m_core->mode >> 1]); // callh read32 + UML_MOV(block, FPR32(RTREG), I0); // mov ,i0 + if (!in_delay_slot) + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); + return TRUE; + + case 0x35: /* LDC1 - MIPS III */ + check_cop1_access(block); + UML_ADD(block, I0, R32(RSREG), SIMMVAL); // add i0,,SIMMVAL + UML_CALLH(block, *m_read64[m_core->mode >> 1]); // callh read64 + UML_DMOV(block, FPR64(RTREG), I0); // dmov ,i0 + if (!in_delay_slot) + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); + return TRUE; + + case 0x32: /* LWC2 - MIPS I */ + UML_ADD(block, I0, R32(RSREG), SIMMVAL); // add i0,,SIMMVAL + UML_CALLH(block, *m_read32[m_core->mode >> 1]); // callh read32 + UML_DAND(block, CPR264(RTREG), I0, 0xffffffff); // dand ,i0,0xffffffff + if (!in_delay_slot) + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); + return TRUE; + + case 0x36: /* LDC2 - MIPS II */ + UML_ADD(block, I0, R32(RSREG), SIMMVAL); // add i0,,SIMMVAL + UML_CALLH(block, *m_read64[m_core->mode >> 1]); // callh read64 + UML_DMOV(block, CPR264(RTREG), I0); // dmov ,i0 + if (!in_delay_slot) + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); + return TRUE; + + + /* ----- memory store operations ----- */ + + case 0x28: /* SB - MIPS I */ + UML_ADD(block, I0, R32(RSREG), SIMMVAL); // add i0,,SIMMVAL + UML_MOV(block, I1, R32(RTREG)); // mov i1, + UML_CALLH(block, *m_write8[m_core->mode >> 1]); // callh write8 + if (!in_delay_slot) + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); + return TRUE; + + case 0x29: /* SH - MIPS I */ + UML_ADD(block, I0, R32(RSREG), SIMMVAL); // add i0,,SIMMVAL + UML_MOV(block, I1, R32(RTREG)); // mov i1, + UML_CALLH(block, *m_write16[m_core->mode >> 1]); // callh write16 + if (!in_delay_slot) + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); + return TRUE; + + case 0x2b: /* SW - MIPS I */ + UML_ADD(block, I0, R32(RSREG), SIMMVAL); // add i0,,SIMMVAL + UML_MOV(block, I1, R32(RTREG)); // mov i1, + UML_CALLH(block, *m_write32[m_core->mode >> 1]); // callh write32 + if (!in_delay_slot) + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); + return TRUE; + + case 0x38: /* SC - MIPS II */ + UML_CMP(block, mem(&m_core->llbit), 0); // cmp [llbit],0 + UML_JMPc(block, COND_E, skip = compiler->labelnum++); // je skip + UML_ADD(block, I0, R32(RSREG), SIMMVAL); // add i0,,SIMMVAL + UML_MOV(block, I1, R32(RTREG)); // mov i1, + UML_CALLH(block, *m_write32[m_core->mode >> 1]); // callh write32 + UML_LABEL(block, skip); // skip: + UML_DSEXT(block, R64(RTREG), mem(&m_core->llbit), SIZE_DWORD); // dsext ,[llbit],dword + if (!in_delay_slot) + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); + return TRUE; + + case 0x3f: /* SD - MIPS III */ + UML_ADD(block, I0, R32(RSREG), SIMMVAL); // add i0,,SIMMVAL + UML_DMOV(block, I1, R64(RTREG)); // dmov i1, + UML_CALLH(block, *m_write64[m_core->mode >> 1]); // callh write64 + if (!in_delay_slot) + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); + return TRUE; + + case 0x3c: /* SCD - MIPS III */ + UML_CMP(block, mem(&m_core->llbit), 0); // cmp [llbit],0 + UML_JMPc(block, COND_E, skip = compiler->labelnum++); // je skip + UML_ADD(block, I0, R32(RSREG), SIMMVAL); // add i0,,SIMMVAL + UML_DMOV(block, I1, R64(RTREG)); // dmov i1, + UML_CALLH(block, *m_write64[m_core->mode >> 1]); // callh write64 + UML_LABEL(block, skip); // skip: + UML_DSEXT(block, R64(RTREG), mem(&m_core->llbit), SIZE_DWORD); // dsext ,[llbit],dword + if (!in_delay_slot) + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); + return TRUE; + + case 0x2a: /* SWL - MIPS I */ + UML_ADD(block, I0, R32(RSREG), SIMMVAL); // add i0,,SIMMVAL + UML_SHL(block, I3, I0, 3); // shl i3,i0,3 + UML_AND(block, I0, I0, ~3); // and i0,i0,~3 + UML_MOV(block, I1, R32(RTREG)); // mov i1, + if (!m_bigendian) + UML_XOR(block, I3, I3, 0x18); // xor i3,i3,0x18 + UML_SHR(block, I2, ~0, I3); // shr i2,~0,i3 + UML_SHR(block, I1, I1, I3); // shr i1,i1,i3 + UML_CALLH(block, *m_write32mask[m_core->mode >> 1]); + // callh write32mask + if (!in_delay_slot) + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); + return TRUE; + + case 0x2e: /* SWR - MIPS I */ + UML_ADD(block, I0, R32(RSREG), SIMMVAL); // add i0,,SIMMVAL + UML_SHL(block, I3, I0, 3); // shl i3,i0,3 + UML_AND(block, I0, I0, ~3); // and i0,i0,~3 + UML_MOV(block, I1, R32(RTREG)); // mov i1, + if (m_bigendian) + UML_XOR(block, I3, I3, 0x18); // xor i3,i3,0x18 + UML_SHL(block, I2, ~0, I3); // shl i2,~0,i3 + UML_SHL(block, I1, I1, I3); // shl i1,i1,i3 + UML_CALLH(block, *m_write32mask[m_core->mode >> 1]); + // callh write32mask + if (!in_delay_slot) + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); + return TRUE; + + case 0x2c: /* SDL - MIPS III */ + UML_ADD(block, I0, R32(RSREG), SIMMVAL); // add i0,,SIMMVAL + UML_SHL(block, I3, I0, 3); // shl i3,i0,3 + UML_AND(block, I0, I0, ~7); // and i0,i0,~7 + UML_DMOV(block, I1, R64(RTREG)); // dmov i1, + if (!m_bigendian) + UML_XOR(block, I3, I3, 0x38); // xor i3,i3,0x38 + UML_DSHR(block, I2, (UINT64)~0, I3); // dshr i2,~0,i3 + UML_DSHR(block, I1, I1, I3); // dshr i1,i1,i3 + UML_CALLH(block, *m_write64mask[m_core->mode >> 1]); + // callh write64mask + if (!in_delay_slot) + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); + return TRUE; + + case 0x2d: /* SDR - MIPS III */ + UML_ADD(block, I0, R32(RSREG), SIMMVAL); // add i0,,SIMMVAL + UML_SHL(block, I3, I0, 3); // shl i3,i0,3 + UML_AND(block, I0, I0, ~7); // and i0,i0,~7 + UML_DMOV(block, I1, R64(RTREG)); // dmov i1, + if (m_bigendian) + UML_XOR(block, I3, I3, 0x38); // xor i3,i3,0x38 + UML_DSHL(block, I2, (UINT64)~0, I3); // dshl i2,~0,i3 + UML_DSHL(block, I1, I1, I3); // dshl i1,i1,i3 + UML_CALLH(block, *m_write64mask[m_core->mode >> 1]); + // callh write64mask + if (!in_delay_slot) + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); + return TRUE; + + case 0x39: /* SWC1 - MIPS I */ + check_cop1_access(block); + UML_ADD(block, I0, R32(RSREG), SIMMVAL); // add i0,,SIMMVAL + UML_MOV(block, I1, FPR32(RTREG)); // mov i1, + UML_CALLH(block, *m_write32[m_core->mode >> 1]); // callh write32 + if (!in_delay_slot) + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); + return TRUE; + + case 0x3d: /* SDC1 - MIPS III */ + check_cop1_access(block); + UML_ADD(block, I0, R32(RSREG), SIMMVAL); // add i0,,SIMMVAL + UML_DMOV(block, I1, FPR64(RTREG)); // dmov i1, + UML_CALLH(block, *m_write64[m_core->mode >> 1]); // callh write64 + if (!in_delay_slot) + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); + return TRUE; + + case 0x3a: /* SWC2 - MIPS I */ + UML_ADD(block, I0, R32(RSREG), SIMMVAL); // add i0,,SIMMVAL + UML_MOV(block, I1, CPR232(RTREG)); // mov i1, + UML_CALLH(block, *m_write32[m_core->mode >> 1]); // callh write32 + if (!in_delay_slot) + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); + return TRUE; + + case 0x3e: /* SDC2 - MIPS II */ + UML_ADD(block, I0, R32(RSREG), SIMMVAL); // add i0,,SIMMVAL + UML_DMOV(block, I1, CPR264(RTREG)); // dmov i1, + UML_CALLH(block, *m_write64[m_core->mode >> 1]); // callh write64 + if (!in_delay_slot) + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); + return TRUE; + + + /* ----- effective no-ops ----- */ + + case 0x2f: /* CACHE - MIPS II */ + case 0x33: /* PREF - MIPS IV */ + return TRUE; + + + /* ----- coprocessor instructions ----- */ + + case 0x10: /* COP0 - MIPS I */ + return generate_cop0(block, compiler, desc); + + case 0x11: /* COP1 - MIPS I */ + return generate_cop1(block, compiler, desc); + + case 0x13: /* COP1X - MIPS IV */ + return generate_cop1x(block, compiler, desc); + + case 0x12: /* COP2 - MIPS I */ + UML_EXH(block, *m_exception[EXCEPTION_INVALIDOP], 0);// exh invalidop,0 + return TRUE; + + + /* ----- unimplemented/illegal instructions ----- */ + +// default: /* ??? */ invalid_instruction(op); break; + } + + return FALSE; +} + + +/*------------------------------------------------- + generate_special - compile opcodes in the + 'SPECIAL' group +-------------------------------------------------*/ + +int mips3_device::generate_special(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) +{ + UINT32 op = desc->opptr.l[0]; + UINT8 opswitch = op & 63; + + switch (opswitch) + { + /* ----- shift instructions ----- */ + + case 0x00: /* SLL - MIPS I */ + if (RDREG != 0) + { + UML_SHL(block, I0, R32(RTREG), SHIFT); // shl i0,, + UML_DSEXT(block, R64(RDREG), I0, SIZE_DWORD); // dsext ,i0,dword + } + return TRUE; + + case 0x02: /* SRL - MIPS I */ + if (RDREG != 0) + { + UML_SHR(block, I0, R32(RTREG), SHIFT); // shr i0,, + UML_DSEXT(block, R64(RDREG), I0, SIZE_DWORD); // dsext ,i0,dword + } + return TRUE; + + case 0x03: /* SRA - MIPS I */ + if (RDREG != 0) + { + UML_SAR(block, I0, R32(RTREG), SHIFT); // sar i0,, + UML_DSEXT(block, R64(RDREG), I0, SIZE_DWORD); // dsext ,i0,dword + } + return TRUE; + + case 0x04: /* SLLV - MIPS I */ + if (RDREG != 0) + { + UML_SHL(block, I0, R32(RTREG), R32(RSREG)); // shl i0,, + UML_DSEXT(block, R64(RDREG), I0, SIZE_DWORD); // dsext ,i0,dword + } + return TRUE; + + case 0x06: /* SRLV - MIPS I */ + if (RDREG != 0) + { + UML_SHR(block, I0, R32(RTREG), R32(RSREG)); // shr i0,, + UML_DSEXT(block, R64(RDREG), I0, SIZE_DWORD); // dsext ,i0,dword + } + return TRUE; + + case 0x07: /* SRAV - MIPS I */ + if (RDREG != 0) + { + UML_SAR(block, I0, R32(RTREG), R32(RSREG)); // sar i0,, + UML_DSEXT(block, R64(RDREG), I0, SIZE_DWORD); // dsext ,i0,dword + } + return TRUE; + + case 0x38: /* DSLL - MIPS III */ + if (RDREG != 0) + UML_DSHL(block, R64(RDREG), R64(RTREG), SHIFT); // dshl ,, + return TRUE; + + case 0x3a: /* DSRL - MIPS III */ + if (RDREG != 0) + UML_DSHR(block, R64(RDREG), R64(RTREG), SHIFT); // dshr ,, + return TRUE; + + case 0x3b: /* DSRA - MIPS III */ + if (RDREG != 0) + UML_DSAR(block, R64(RDREG), R64(RTREG), SHIFT); // dsar ,, + return TRUE; + + case 0x3c: /* DSLL32 - MIPS III */ + if (RDREG != 0) + UML_DSHL(block, R64(RDREG), R64(RTREG), SHIFT + 32); // dshl ,,+32 + return TRUE; + + case 0x3e: /* DSRL32 - MIPS III */ + if (RDREG != 0) + UML_DSHR(block, R64(RDREG), R64(RTREG), SHIFT + 32); // dshr ,,+32 + return TRUE; + + case 0x3f: /* DSRA32 - MIPS III */ + if (RDREG != 0) + UML_DSAR(block, R64(RDREG), R64(RTREG), SHIFT + 32); // dsar ,,+32 + return TRUE; + + case 0x14: /* DSLLV - MIPS III */ + if (RDREG != 0) + UML_DSHL(block, R64(RDREG), R64(RTREG), R64(RSREG)); // dshl ,, + return TRUE; + + case 0x16: /* DSRLV - MIPS III */ + if (RDREG != 0) + UML_DSHR(block, R64(RDREG), R64(RTREG), R64(RSREG)); // dshr ,, + return TRUE; + + case 0x17: /* DSRAV - MIPS III */ + if (RDREG != 0) + UML_DSAR(block, R64(RDREG), R64(RTREG), R64(RSREG)); // dsar ,, + return TRUE; + + + /* ----- basic arithmetic ----- */ + + case 0x20: /* ADD - MIPS I */ + if (m_drcoptions & MIPS3DRC_CHECK_OVERFLOWS) + { + UML_ADD(block, I0, R32(RSREG), R32(RTREG)); // add i0,, + UML_EXHc(block, COND_V, *m_exception[EXCEPTION_OVERFLOW], 0); + // exh overflow,0,V + if (RDREG != 0) + UML_DSEXT(block, R64(RDREG), I0, SIZE_DWORD); // dsext ,i0,dword + } + else if (RDREG != 0) + { + UML_ADD(block, I0, R32(RSREG), R32(RTREG)); // add i0,, + UML_DSEXT(block, R64(RDREG), I0, SIZE_DWORD); // dsext ,i0,dword + } + return TRUE; + + case 0x21: /* ADDU - MIPS I */ + if (RDREG != 0) + { + UML_ADD(block, I0, R32(RSREG), R32(RTREG)); // add i0,, + UML_DSEXT(block, R64(RDREG), I0, SIZE_DWORD); // dsext ,i0,dword + } + return TRUE; + + case 0x2c: /* DADD - MIPS III */ + if (m_drcoptions & MIPS3DRC_CHECK_OVERFLOWS) + { + UML_DADD(block, I0, R64(RSREG), R64(RTREG)); // dadd i0,, + UML_EXHc(block, COND_V, *m_exception[EXCEPTION_OVERFLOW], 0); + // exh overflow,0,V + if (RDREG != 0) + UML_DMOV(block, R64(RDREG), I0); // dmov ,i0 + } + else if (RDREG != 0) + UML_DADD(block, R64(RDREG), R64(RSREG), R64(RTREG)); // dadd ,, + return TRUE; + + case 0x2d: /* DADDU - MIPS III */ + if (RDREG != 0) + UML_DADD(block, R64(RDREG), R64(RSREG), R64(RTREG)); // dadd ,, + return TRUE; + + case 0x22: /* SUB - MIPS I */ + if (m_drcoptions & MIPS3DRC_CHECK_OVERFLOWS) + { + UML_SUB(block, I0, R32(RSREG), R32(RTREG)); // sub i0,, + UML_EXHc(block, COND_V, *m_exception[EXCEPTION_OVERFLOW], 0); + // exh overflow,0,V + if (RDREG != 0) + UML_DSEXT(block, R64(RDREG), I0, SIZE_DWORD); // dsext ,i0,dword + } + else if (RDREG != 0) + { + UML_SUB(block, I0, R32(RSREG), R32(RTREG)); // sub i0,, + UML_DSEXT(block, R64(RDREG), I0, SIZE_DWORD); // dsext ,i0,dword + } + return TRUE; + + case 0x23: /* SUBU - MIPS I */ + if (RDREG != 0) + { + UML_SUB(block, I0, R32(RSREG), R32(RTREG)); // sub i0,, + UML_DSEXT(block, R64(RDREG), I0, SIZE_DWORD); // dsext ,i0,dword + } + return TRUE; + + case 0x2e: /* DSUB - MIPS III */ + if (m_drcoptions & MIPS3DRC_CHECK_OVERFLOWS) + { + UML_DSUB(block, I0, R64(RSREG), R64(RTREG)); // dsub i0,, + UML_EXHc(block, COND_V, *m_exception[EXCEPTION_OVERFLOW], 0); + // exh overflow,0,V + if (RDREG != 0) + UML_DMOV(block, R64(RDREG), I0); // dmov ,i0 + } + else if (RDREG != 0) + UML_DSUB(block, R64(RDREG), R64(RSREG), R64(RTREG)); // dsub ,, + return TRUE; + + case 0x2f: /* DSUBU - MIPS III */ + if (RDREG != 0) + UML_DSUB(block, R64(RDREG), R64(RSREG), R64(RTREG)); // dsub ,, + return TRUE; + + case 0x18: /* MULT - MIPS I */ + UML_MULS(block, I0, I1, R32(RSREG), R32(RTREG)); // muls i0,i1,, + UML_DSEXT(block, LO64, I0, SIZE_DWORD); // dsext lo,i0,dword + UML_DSEXT(block, HI64, I1, SIZE_DWORD); // dsext hi,i1,dword + return TRUE; + + case 0x19: /* MULTU - MIPS I */ + UML_MULU(block, I0, I1, R32(RSREG), R32(RTREG)); // mulu i0,i1,, + UML_DSEXT(block, LO64, I0, SIZE_DWORD); // dsext lo,i0,dword + UML_DSEXT(block, HI64, I1, SIZE_DWORD); // dsext hi,i1,dword + return TRUE; + + case 0x1c: /* DMULT - MIPS III */ + UML_DMULS(block, LO64, HI64, R64(RSREG), R64(RTREG)); // dmuls lo,hi,, + return TRUE; + + case 0x1d: /* DMULTU - MIPS III */ + UML_DMULU(block, LO64, HI64, R64(RSREG), R64(RTREG)); // dmulu lo,hi,, + return TRUE; + + case 0x1a: /* DIV - MIPS I */ + UML_DIVS(block, I0, I1, R32(RSREG), R32(RTREG)); // divs i0,i1,, + UML_DSEXT(block, LO64, I0, SIZE_DWORD); // dsext lo,i0,dword + UML_DSEXT(block, HI64, I1, SIZE_DWORD); // dsext hi,i1,dword + return TRUE; + + case 0x1b: /* DIVU - MIPS I */ + UML_DIVU(block, I0, I1, R32(RSREG), R32(RTREG)); // divu i0,i1,, + UML_DSEXT(block, LO64, I0, SIZE_DWORD); // dsext lo,i0,dword + UML_DSEXT(block, HI64, I1, SIZE_DWORD); // dsext hi,i1,dword + return TRUE; + + case 0x1e: /* DDIV - MIPS III */ + UML_DDIVS(block, LO64, HI64, R64(RSREG), R64(RTREG)); // ddivs lo,hi,, + return TRUE; + + case 0x1f: /* DDIVU - MIPS III */ + UML_DDIVU(block, LO64, HI64, R64(RSREG), R64(RTREG)); // ddivu lo,hi,, + return TRUE; + + + /* ----- basic logical ops ----- */ + + case 0x24: /* AND - MIPS I */ + if (RDREG != 0) + UML_DAND(block, R64(RDREG), R64(RSREG), R64(RTREG)); // dand ,, + return TRUE; + + case 0x25: /* OR - MIPS I */ + if (RDREG != 0) + UML_DOR(block, R64(RDREG), R64(RSREG), R64(RTREG)); // dor ,, + return TRUE; + + case 0x26: /* XOR - MIPS I */ + if (RDREG != 0) + UML_DXOR(block, R64(RDREG), R64(RSREG), R64(RTREG)); // dxor ,, + return TRUE; + + case 0x27: /* NOR - MIPS I */ + if (RDREG != 0) + { + UML_DOR(block, I0, R64(RSREG), R64(RTREG)); // dor i0,, + UML_DXOR(block, R64(RDREG), I0, (UINT64)~0); // dxor ,i0,~0 + } + return TRUE; + + + /* ----- basic comparisons ----- */ + + case 0x2a: /* SLT - MIPS I */ + if (RDREG != 0) + { + UML_DCMP(block, R64(RSREG), R64(RTREG)); // dcmp , + UML_DSETc(block, COND_L, R64(RDREG)); // dset ,l + } + return TRUE; + + case 0x2b: /* SLTU - MIPS I */ + if (RDREG != 0) + { + UML_DCMP(block, R64(RSREG), R64(RTREG)); // dcmp , + UML_DSETc(block, COND_B, R64(RDREG)); // dset ,b + } + return TRUE; + + + /* ----- conditional traps ----- */ + + case 0x30: /* TGE - MIPS II */ + UML_DCMP(block, R64(RSREG), R64(RTREG)); // dcmp , + UML_EXHc(block, COND_GE, *m_exception[EXCEPTION_TRAP], 0);// exh trap,0,GE + return TRUE; + + case 0x31: /* TGEU - MIPS II */ + UML_DCMP(block, R64(RSREG), R64(RTREG)); // dcmp , + UML_EXHc(block, COND_AE, *m_exception[EXCEPTION_TRAP], 0);// exh trap,0,AE + return TRUE; + + case 0x32: /* TLT - MIPS II */ + UML_DCMP(block, R64(RSREG), R64(RTREG)); // dcmp , + UML_EXHc(block, COND_L, *m_exception[EXCEPTION_TRAP], 0);// exh trap,0,LT + return TRUE; + + case 0x33: /* TLTU - MIPS II */ + UML_DCMP(block, R64(RSREG), R64(RTREG)); // dcmp , + UML_EXHc(block, COND_B, *m_exception[EXCEPTION_TRAP], 0);// exh trap,0,B + return TRUE; + + case 0x34: /* TEQ - MIPS II */ + UML_DCMP(block, R64(RSREG), R64(RTREG)); // dcmp , + UML_EXHc(block, COND_E, *m_exception[EXCEPTION_TRAP], 0);// exh trap,0,E + return TRUE; + + case 0x36: /* TNE - MIPS II */ + UML_DCMP(block, R64(RSREG), R64(RTREG)); // dcmp , + UML_EXHc(block, COND_NE, *m_exception[EXCEPTION_TRAP], 0);// exh trap,0,NE + return TRUE; + + + /* ----- conditional moves ----- */ + + case 0x0a: /* MOVZ - MIPS IV */ + if (RDREG != 0) + { + UML_DCMP(block, R64(RTREG), 0); // dcmp ,0 + UML_DMOVc(block, COND_Z, R64(RDREG), R64(RSREG)); // dmov ,,Z + } + return TRUE; + + case 0x0b: /* MOVN - MIPS IV */ + if (RDREG != 0) + { + UML_DCMP(block, R64(RTREG), 0); // dcmp ,0 + UML_DMOVc(block, COND_NZ, R64(RDREG), R64(RSREG)); // dmov ,,NZ + } + return TRUE; + + case 0x01: /* MOVF/MOVT - MIPS IV */ + if (RDREG != 0) + { + UML_TEST(block, CCR132(31), FCCMASK(op >> 18)); // test ccr31,fcc_mask[x] + UML_DMOVc(block, ((op >> 16) & 1) ? COND_NZ : COND_Z, R64(RDREG), R64(RSREG)); + // dmov ,,NZ/Z + } + return TRUE; + + + /* ----- jumps and branches ----- */ + + case 0x08: /* JR - MIPS I */ + generate_delay_slot_and_branch(block, compiler, desc, 0); // + return TRUE; + + case 0x09: /* JALR - MIPS I */ + generate_delay_slot_and_branch(block, compiler, desc, RDREG); // + return TRUE; + + + /* ----- system calls ----- */ + + case 0x0c: /* SYSCALL - MIPS I */ + UML_EXH(block, *m_exception[EXCEPTION_SYSCALL], 0); // exh syscall,0 + return TRUE; + + case 0x0d: /* BREAK - MIPS I */ + UML_EXH(block, *m_exception[EXCEPTION_BREAK], 0); // exh break,0 + return TRUE; + + + /* ----- effective no-ops ----- */ + + case 0x0f: /* SYNC - MIPS II */ + return TRUE; + + + /* ----- hi/lo register access ----- */ + + case 0x10: /* MFHI - MIPS I */ + if (RDREG != 0) + UML_DMOV(block, R64(RDREG), HI64); // dmov ,hi + return TRUE; + + case 0x11: /* MTHI - MIPS I */ + UML_DMOV(block, HI64, R64(RSREG)); // dmov hi, + return TRUE; + + case 0x12: /* MFLO - MIPS I */ + if (RDREG != 0) + UML_DMOV(block, R64(RDREG), LO64); // dmov ,lo + return TRUE; + + case 0x13: /* MTLO - MIPS I */ + UML_DMOV(block, LO64, R64(RSREG)); // dmov lo, + return TRUE; + } + return FALSE; +} + + +/*------------------------------------------------- + generate_regimm - compile opcodes in the + 'REGIMM' group +-------------------------------------------------*/ + +int mips3_device::generate_regimm(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) +{ + UINT32 op = desc->opptr.l[0]; + UINT8 opswitch = RTREG; + code_label skip; + + switch (opswitch) + { + case 0x00: /* BLTZ */ + case 0x02: /* BLTZL */ + case 0x10: /* BLTZAL */ + case 0x12: /* BLTZALL */ + if (RSREG != 0) + { + UML_DCMP(block, R64(RSREG), 0); // dcmp ,0 + UML_JMPc(block, COND_GE, skip = compiler->labelnum++); // jmp skip,GE + generate_delay_slot_and_branch(block, compiler, desc, (opswitch & 0x10) ? 31 : 0); + // + UML_LABEL(block, skip); // skip: + } + return TRUE; + + case 0x01: /* BGEZ */ + case 0x03: /* BGEZL */ + case 0x11: /* BGEZAL */ + case 0x13: /* BGEZALL */ + if (RSREG != 0) + { + UML_DCMP(block, R64(RSREG), 0); // dcmp ,0 + UML_JMPc(block, COND_L, skip = compiler->labelnum++); // jmp skip,L + generate_delay_slot_and_branch(block, compiler, desc, (opswitch & 0x10) ? 31 : 0); + // + UML_LABEL(block, skip); // skip: + } + else + generate_delay_slot_and_branch(block, compiler, desc, (opswitch & 0x10) ? 31 : 0); + // + return TRUE; + + case 0x08: /* TGEI */ + UML_DCMP(block, R64(RSREG), SIMMVAL); // dcmp ,SIMMVAL + UML_EXHc(block, COND_GE, *m_exception[EXCEPTION_TRAP], 0);// exh trap,0,GE + return TRUE; + + case 0x09: /* TGEIU */ + UML_DCMP(block, R64(RSREG), SIMMVAL); // dcmp ,SIMMVAL + UML_EXHc(block, COND_AE, *m_exception[EXCEPTION_TRAP], 0);// exh trap,0,AE + return TRUE; + + case 0x0a: /* TLTI */ + UML_DCMP(block, R64(RSREG), SIMMVAL); // dcmp ,SIMMVAL + UML_EXHc(block, COND_L, *m_exception[EXCEPTION_TRAP], 0);// exh trap,0,L + return TRUE; + + case 0x0b: /* TLTIU */ + UML_DCMP(block, R64(RSREG), SIMMVAL); // dcmp ,SIMMVAL + UML_EXHc(block, COND_B, *m_exception[EXCEPTION_TRAP], 0);// exh trap,0,B + return TRUE; + + case 0x0c: /* TEQI */ + UML_DCMP(block, R64(RSREG), SIMMVAL); // dcmp ,SIMMVAL + UML_EXHc(block, COND_E, *m_exception[EXCEPTION_TRAP], 0);// exh trap,0,E + return TRUE; + + case 0x0e: /* TNEI */ + UML_DCMP(block, R64(RSREG), SIMMVAL); // dcmp ,SIMMVAL + UML_EXHc(block, COND_NE, *m_exception[EXCEPTION_TRAP], 0);// exh trap,0,NE + return TRUE; + } + return FALSE; +} + + +/*------------------------------------------------- + generate_idt - compile opcodes in the IDT- + specific group +-------------------------------------------------*/ + +int mips3_device::generate_idt(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) +{ + UINT32 op = desc->opptr.l[0]; + UINT8 opswitch = op & 0x1f; + + /* only enabled on IDT processors */ + if (m_flavor != MIPS3_TYPE_R4650) + return FALSE; + + switch (opswitch) + { + case 0: /* MAD */ + if (RSREG != 0 && RTREG != 0) + { + UML_MULS(block, I0, I1, R32(RSREG), R32(RTREG)); // muls i0,i1,rsreg,rtreg + UML_ADD(block, I0, I0, LO32); // add i0,i0,lo + UML_ADDC(block, I1, I1, HI32); // addc i1,i1,hi + UML_DSEXT(block, LO64, I0, SIZE_DWORD); // dsext lo,i0,dword + UML_DSEXT(block, HI64, I1, SIZE_DWORD); // dsext hi,i1,dword + } + return TRUE; + + case 1: /* MADU */ + if (RSREG != 0 && RTREG != 0) + { + UML_MULU(block, I0, I1, R32(RSREG), R32(RTREG)); // mulu i0,i1,rsreg,rtreg + UML_ADD(block, I0, I0, LO32); // add i0,i0,lo + UML_ADDC(block, I1, I1, HI32); // addc i1,i1,hi + UML_DSEXT(block, LO64, I0, SIZE_DWORD); // dsext lo,i0,dword + UML_DSEXT(block, HI64, I1, SIZE_DWORD); // dsext hi,i1,dword + } + return TRUE; + + case 2: /* MUL */ + if (RDREG != 0) + { + UML_MULS(block, I0, I0, R32(RSREG), R32(RTREG)); // muls i0,i0,rsreg,rtreg + UML_DSEXT(block, R64(RDREG), I0, SIZE_DWORD); // dsext rdreg,i0,dword + } + return TRUE; + } + return FALSE; +} + + +/*------------------------------------------------- + generate_set_cop0_reg - generate code to + handle special COP0 registers +-------------------------------------------------*/ + +int mips3_device::generate_set_cop0_reg(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, UINT8 reg) +{ + int in_delay_slot = ((desc->flags & OPFLAG_IN_DELAY_SLOT) != 0); + code_label link; + + switch (reg) + { + case COP0_Cause: + UML_ROLINS(block, CPR032(COP0_Cause), I0, 0, ~0xfc00); // rolins [Cause],i0,0,~0xfc00 + compiler->checksoftints = TRUE; + if (!in_delay_slot) + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); + return TRUE; + + case COP0_Status: + generate_update_cycles(block, compiler, desc->pc, !in_delay_slot); // + UML_MOV(block, I1, CPR032(COP0_Status)); // mov i1,[Status] + UML_MOV(block, CPR032(COP0_Status), I0); // mov [Status],i0 + generate_update_mode(block); // + UML_XOR(block, I0, I0, I1); // xor i0,i0,i1 + UML_TEST(block, I0, 0x8000); // test i0,0x8000 + UML_CALLCc(block, COND_NZ, cfunc_mips3com_update_cycle_counting, this); // callc mips3com_update_cycle_counting,mips.core,NZ + compiler->checkints = TRUE; + if (!in_delay_slot) + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); + return TRUE; + + case COP0_Count: + generate_update_cycles(block, compiler, desc->pc, !in_delay_slot); // + UML_MOV(block, CPR032(COP0_Count), I0); // mov [Count],i0 + UML_CALLC(block, cfunc_get_cycles, this); // callc cfunc_get_cycles,mips3 + UML_DAND(block, I0, I0, 0xffffffff); // and i0,i0,0xffffffff + UML_DADD(block, I0, I0, I0); // dadd i0,i0,i0 + UML_DSUB(block, mem(&m_core->count_zero_time), mem(&m_core->numcycles), I0); + // dsub [count_zero_time],[m_numcycles],i0 + UML_CALLC(block, cfunc_mips3com_update_cycle_counting, this); // callc mips3com_update_cycle_counting,mips.core + return TRUE; + + case COP0_Compare: + UML_MOV(block, mem(&m_core->compare_armed), 1); // mov [compare_armed],1 + generate_update_cycles(block, compiler, desc->pc, !in_delay_slot); // + UML_MOV(block, CPR032(COP0_Compare), I0); // mov [Compare],i0 + UML_AND(block, CPR032(COP0_Cause), CPR032(COP0_Cause), ~0x8000); // and [Cause],[Cause],~0x8000 + UML_CALLC(block, cfunc_mips3com_update_cycle_counting, this); // callc mips3com_update_cycle_counting,mips.core + return TRUE; + + case COP0_PRId: + return TRUE; + + case COP0_Config: + UML_ROLINS(block, CPR032(COP0_Config), I0, 0, 0x0007); // rolins [Config],i0,0,0x0007 + return TRUE; + + case COP0_EntryHi: + UML_XOR(block, I1, I0, CPR032(reg)); // xor i1,i0,cpr0[reg] + UML_MOV(block, CPR032(reg), I0); // mov cpr0[reg],i0 + UML_TEST(block, I1, 0xff); // test i1,0xff + UML_JMPc(block, COND_Z, link = compiler->labelnum++); // jmp link,z + UML_CALLC(block, cfunc_mips3com_asid_changed, this); // callc mips3com_asid_changed + UML_LABEL(block, link); // link: + return TRUE; + + default: + UML_MOV(block, CPR032(reg), I0); // mov cpr0[reg],i0 + return TRUE; + } +} + + +/*------------------------------------------------- + generate_get_cop0_reg - generate code to + read special COP0 registers +-------------------------------------------------*/ + +int mips3_device::generate_get_cop0_reg(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, UINT8 reg) +{ + code_label link1, link2; + + switch (reg) + { + case COP0_Count: + generate_update_cycles(block, compiler, desc->pc, FALSE); // + UML_CALLC(block, cfunc_get_cycles, this); // callc cfunc_get_cycles,mips3 + UML_DSUB(block, I0, mem(&m_core->numcycles), mem(&m_core->count_zero_time)); + // dsub i0,[numcycles],[count_zero_time] + UML_DSHR(block, I0, I0, 1); // dshr i0,i0,1 + UML_DSEXT(block, I0, I0, SIZE_DWORD); // dsext i0,i0,dword + return TRUE; + + case COP0_Random: + generate_update_cycles(block, compiler, desc->pc, FALSE); // + UML_CALLC(block, cfunc_get_cycles, this); // callc cfunc_get_cycles,mips3 + UML_DSUB(block, I0, mem(&m_core->numcycles), mem(&m_core->count_zero_time)); + // dsub i0,[numcycles],[count_zero_time] + UML_AND(block, I1, CPR032(COP0_Wired), 0x3f); // and i1,[Wired],0x3f + UML_SUB(block, I2, 48, I1); // sub i2,48,i1 + UML_JMPc(block, COND_BE, link1 = compiler->labelnum++); // jmp link1,BE + UML_DAND(block, I2, I2, 0xffffffff); // dand i2,i2,0xffffffff + UML_DDIVU(block, I0, I2, I0, I2); // ddivu i0,i2,i0,i2 + UML_ADD(block, I0, I2, I1); // add i0,i2,i1 + UML_DAND(block, I0, I0, 0x3f); // dand i0,i0,0x3f + UML_JMP(block, link2 = compiler->labelnum++); // jmp link2 + UML_LABEL(block, link1); // link1: + UML_DMOV(block, I0, 47); // dmov i0,47 + UML_LABEL(block, link2); // link2: + return TRUE; + + default: + UML_DSEXT(block, I0, CPR032(reg), SIZE_DWORD); // dsext i0,cpr0[reg],dword + return TRUE; + } +} + + +/*------------------------------------------------------------------------- + generate_badcop - raise a BADCOP exception +-------------------------------------------------------------------------*/ + +void mips3_device::generate_badcop(drcuml_block *block, const int cop) +{ + UML_TEST(block, CPR032(COP0_Status), SR_COP0 << cop); // test [Status], SR_COP0 << cop + UML_EXHc(block, COND_Z, *m_exception[EXCEPTION_BADCOP], cop); // exh badcop,cop,Z +} + +/*------------------------------------------------------------------------- + check_cop0_access - raise a BADCOP exception if we're not in kernel mode +-------------------------------------------------------------------------*/ + +void mips3_device::check_cop0_access(drcuml_block *block) +{ + if ((m_core->mode >> 1) != MODE_KERNEL) + { + generate_badcop(block, 0); + } +} + +/*------------------------------------------------- + generate_cop0 - compile COP0 opcodes +-------------------------------------------------*/ + +int mips3_device::generate_cop0(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) +{ + UINT32 op = desc->opptr.l[0]; + UINT8 opswitch = RSREG; + int skip; + + /* generate an exception if COP0 is disabled unless we are in kernel mode */ + if ((m_core->mode >> 1) != MODE_KERNEL) + { + UML_TEST(block, CPR032(COP0_Status), SR_COP0); // test [Status],SR_COP0 + UML_EXHc(block, COND_Z, *m_exception[EXCEPTION_BADCOP], 0);// exh cop,0,Z + } + + switch (opswitch) + { + case 0x00: /* MFCz */ + if (RTREG != 0) + { + generate_get_cop0_reg(block, compiler, desc, RDREG); // + UML_DSEXT(block, R64(RTREG), I0, SIZE_DWORD); // dsext ,i0,dword + } + return TRUE; + + case 0x01: /* DMFCz */ + if (RTREG != 0) + { + generate_get_cop0_reg(block, compiler, desc, RDREG); // + UML_DMOV(block, R64(RTREG), I0); // dmov ,i0 + } + return TRUE; + + case 0x02: /* CFCz */ + if (RTREG != 0) + UML_DSEXT(block, R64(RTREG), CCR032(RDREG), SIZE_DWORD); // dsext ,ccr0[rdreg],dword + return TRUE; + + case 0x04: /* MTCz */ + UML_DSEXT(block, I0, R32(RTREG), SIZE_DWORD); // dsext i0,,dword + generate_set_cop0_reg(block, compiler, desc, RDREG); // + return TRUE; + + case 0x05: /* DMTCz */ + UML_DMOV(block, I0, R64(RTREG)); // dmov i0, + generate_set_cop0_reg(block, compiler, desc, RDREG); // + return TRUE; + + case 0x06: /* CTCz */ + UML_DSEXT(block, CCR064(RDREG), R32(RTREG), SIZE_DWORD); // dsext ccr0[rdreg],,dword + return TRUE; + + case 0x10: + case 0x11: + case 0x12: + case 0x13: + case 0x14: + case 0x15: + case 0x16: + case 0x17: + case 0x18: + case 0x19: + case 0x1a: + case 0x1b: + case 0x1c: + case 0x1d: + case 0x1e: + case 0x1f: /* COP */ + switch (op & 0x01ffffff) + { + case 0x01: /* TLBR */ + UML_CALLC(block, cfunc_mips3com_tlbr, this); // callc mips3com_tlbr,mips3 + return TRUE; + + case 0x02: /* TLBWI */ + UML_CALLC(block, cfunc_mips3com_tlbwi, this); // callc mips3com_tlbwi,mips3 + return TRUE; + + case 0x06: /* TLBWR */ + UML_CALLC(block, cfunc_mips3com_tlbwr, this); // callc mips3com_tlbwr,mips3 + return TRUE; + + case 0x08: /* TLBP */ + UML_CALLC(block, cfunc_mips3com_tlbp, this); // callc mips3com_tlbp,mips3 + return TRUE; + + case 0x18: /* ERET */ + UML_MOV(block, mem(&m_core->llbit), 0); // mov [llbit],0 + UML_MOV(block, I0, CPR032(COP0_Status)); // mov i0,[Status] + UML_TEST(block, I0, SR_ERL); // test i0,SR_ERL + UML_JMPc(block, COND_NZ, skip = compiler->labelnum++); // jmp skip,nz + UML_AND(block, I0, I0, ~SR_EXL); // and i0,i0,~SR_EXL + UML_MOV(block, CPR032(COP0_Status), I0); // mov [Status],i0 + generate_update_mode(block); + compiler->checkints = TRUE; + generate_update_cycles(block, compiler, CPR032(COP0_EPC), TRUE);// + UML_HASHJMP(block, mem(&m_core->mode), CPR032(COP0_EPC), *m_nocode); + // hashjmp ,[EPC],nocode + UML_LABEL(block, skip); // skip: + UML_AND(block, I0, I0, ~SR_ERL); // and i0,i0,~SR_ERL + UML_MOV(block, CPR032(COP0_Status), I0); // mov [Status],i0 + generate_update_mode(block); + compiler->checkints = TRUE; + generate_update_cycles(block, compiler, CPR032(COP0_ErrorPC), TRUE); + // + UML_HASHJMP(block, mem(&m_core->mode), CPR032(COP0_ErrorPC), *m_nocode); + // hashjmp ,[EPC],nocode + return TRUE; + + case 0x20: /* WAIT */ + return TRUE; + } + break; + } + + return FALSE; +} + + + +/*************************************************************************** + COP1 RECOMPILATION +***************************************************************************/ + +/*------------------------------------------------------------------------- + check_cop1_access - raise a BADCOP exception if COP1 is not enabled +-------------------------------------------------------------------------*/ + +void mips3_device::check_cop1_access(drcuml_block *block) +{ + if (m_drcoptions & MIPS3DRC_STRICT_COP1) + { + generate_badcop(block, 1); + } +} + +/*------------------------------------------------- + generate_cop1 - compile COP1 opcodes +-------------------------------------------------*/ + +int mips3_device::generate_cop1(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) +{ + UINT32 op = desc->opptr.l[0]; + code_label skip; + condition_t condition; + + check_cop1_access(block); + + switch (RSREG) + { + case 0x00: /* MFC1 - MIPS I */ + if (RTREG != 0) + UML_DSEXT(block, R64(RTREG), FPR32(RDREG), SIZE_DWORD); // dsext ,fpr[rdreg],dword + return TRUE; + + case 0x01: /* DMFC1 - MIPS III */ + if (RTREG != 0) + UML_DMOV(block, R64(RTREG), FPR64(RDREG)); // dmov ,fpr[rdreg] + return TRUE; + + case 0x02: /* CFC1 - MIPS I */ + if (RTREG != 0) + UML_DSEXT(block, R64(RTREG), CCR132(RDREG), SIZE_DWORD); // dsext ,ccr132[rdreg],dword + return TRUE; + + case 0x04: /* MTC1 - MIPS I */ + UML_MOV(block, FPR32(RDREG), R32(RTREG)); // mov fpr[rdreg], + return TRUE; + + case 0x05: /* DMTC1 - MIPS III */ + UML_DMOV(block, FPR64(RDREG), R64(RTREG)); // dmov fpr[rdreg], + return TRUE; + + case 0x06: /* CTC1 - MIPS I */ + if (RDREG != 31) + UML_DSEXT(block, CCR164(RDREG), R32(RTREG), SIZE_DWORD); // dsext ccr1[rdreg],,dword + else + { + UML_XOR(block, I0, CCR132(31), R32(RTREG)); // xor i0,ccr1[31], + UML_DSEXT(block, CCR164(31), R32(RTREG), SIZE_DWORD); // dsext ccr1[31],,dword + UML_TEST(block, I0, 3); // test i0,3 + UML_JMPc(block, COND_Z, skip = compiler->labelnum++); // jmp skip,Z + UML_AND(block, I0, CCR132(31), 3); // and i0,ccr1[31],3 + UML_LOAD(block, I0, &m_fpmode[0], I0, SIZE_BYTE, SCALE_x1);// load i0,fpmode,i0,byte + UML_SETFMOD(block, I0); // setfmod i0 + UML_LABEL(block, skip); // skip: + } + return TRUE; + + case 0x08: /* BC */ + switch ((op >> 16) & 3) + { + case 0x00: /* BCzF - MIPS I */ + case 0x02: /* BCzFL - MIPS II */ + UML_TEST(block, CCR132(31), FCCMASK(op >> 18)); // test ccr1[31],fccmask[which] + UML_JMPc(block, COND_NZ, skip = compiler->labelnum++); // jmp skip,NZ + generate_delay_slot_and_branch(block, compiler, desc, 0);// + UML_LABEL(block, skip); // skip: + return TRUE; + + case 0x01: /* BCzT - MIPS I */ + case 0x03: /* BCzTL - MIPS II */ + UML_TEST(block, CCR132(31), FCCMASK(op >> 18)); // test ccr1[31],fccmask[which] + UML_JMPc(block, COND_Z, skip = compiler->labelnum++); // jmp skip,Z + generate_delay_slot_and_branch(block, compiler, desc, 0);// + UML_LABEL(block, skip); // skip: + return TRUE; + } + break; + + default: + switch (op & 0x3f) + { + case 0x00: + if (IS_SINGLE(op)) /* ADD.S - MIPS I */ + UML_FSADD(block, FPR32(FDREG), FPR32(FSREG), FPR32(FTREG)); // fsadd ,, + else /* ADD.D - MIPS I */ + UML_FDADD(block, FPR64(FDREG), FPR64(FSREG), FPR64(FTREG)); // fdadd ,, + return TRUE; + + case 0x01: + if (IS_SINGLE(op)) /* SUB.S - MIPS I */ + UML_FSSUB(block, FPR32(FDREG), FPR32(FSREG), FPR32(FTREG)); // fssub ,, + else /* SUB.D - MIPS I */ + UML_FDSUB(block, FPR64(FDREG), FPR64(FSREG), FPR64(FTREG)); // fdsub ,, + return TRUE; + + case 0x02: + if (IS_SINGLE(op)) /* MUL.S - MIPS I */ + UML_FSMUL(block, FPR32(FDREG), FPR32(FSREG), FPR32(FTREG)); // fsmul ,, + else /* MUL.D - MIPS I */ + UML_FDMUL(block, FPR64(FDREG), FPR64(FSREG), FPR64(FTREG)); // fdmul ,, + return TRUE; + + case 0x03: + if (IS_SINGLE(op)) /* DIV.S - MIPS I */ + UML_FSDIV(block, FPR32(FDREG), FPR32(FSREG), FPR32(FTREG)); // fsdiv ,, + else /* DIV.D - MIPS I */ + UML_FDDIV(block, FPR64(FDREG), FPR64(FSREG), FPR64(FTREG)); // fddiv ,, + return TRUE; + + case 0x04: + if (IS_SINGLE(op)) /* SQRT.S - MIPS II */ + UML_FSSQRT(block, FPR32(FDREG), FPR32(FSREG)); // fssqrt , + else /* SQRT.D - MIPS II */ + UML_FDSQRT(block, FPR64(FDREG), FPR64(FSREG)); // fdsqrt , + return TRUE; + + case 0x05: + if (IS_SINGLE(op)) /* ABS.S - MIPS I */ + UML_FSABS(block, FPR32(FDREG), FPR32(FSREG)); // fsabs , + else /* ABS.D - MIPS I */ + UML_FDABS(block, FPR64(FDREG), FPR64(FSREG)); // fdabs , + return TRUE; + + case 0x06: + if (IS_SINGLE(op)) /* MOV.S - MIPS I */ + UML_FSMOV(block, FPR32(FDREG), FPR32(FSREG)); // fsmov , + else /* MOV.D - MIPS I */ + UML_FDMOV(block, FPR64(FDREG), FPR64(FSREG)); // fdmov , + return TRUE; + + case 0x07: + if (IS_SINGLE(op)) /* NEG.S - MIPS I */ + { + UML_FSNEG(block, FPR32(FDREG), FPR32(FSREG)); // fsneg , + UML_CMP(block, FPR32(FSREG), 0); // cmp ,0.0 + UML_MOVc(block, COND_E, FPR32(FDREG), 0x80000000); // mov ,-0.0,e + } + else /* NEG.D - MIPS I */ + { + UML_FDNEG(block, FPR64(FDREG), FPR64(FSREG)); // fdneg , + UML_DCMP(block, FPR64(FSREG), 0); // cmp ,0.0 + UML_DMOVc(block, COND_E, FPR64(FDREG), U64(0x8000000000000000));// dmov ,-0.0,e + } + return TRUE; + + case 0x08: + if (IS_SINGLE(op)) /* ROUND.L.S - MIPS III */ + UML_FSTOINT(block, FPR64(FDREG), FPR32(FSREG), SIZE_QWORD, ROUND_ROUND);// fstoint ,,qword,round + else /* ROUND.L.D - MIPS III */ + UML_FDTOINT(block, FPR64(FDREG), FPR64(FSREG), SIZE_QWORD, ROUND_ROUND);// fdtoint ,,qword,round + UML_DSEXT(block, FPR64(FDREG), FPR64(FDREG), SIZE_DWORD); + return TRUE; + + case 0x09: + if (IS_SINGLE(op)) /* TRUNC.L.S - MIPS III */ + UML_FSTOINT(block, FPR64(FDREG), FPR32(FSREG), SIZE_QWORD, ROUND_TRUNC);// fstoint ,,qword,trunc + else /* TRUNC.L.D - MIPS III */ + UML_FDTOINT(block, FPR64(FDREG), FPR64(FSREG), SIZE_QWORD, ROUND_TRUNC);// fdtoint ,,qword,trunc + UML_DSEXT(block, FPR64(FDREG), FPR64(FDREG), SIZE_DWORD); + return TRUE; + + case 0x0a: + if (IS_SINGLE(op)) /* CEIL.L.S - MIPS III */ + UML_FSTOINT(block, FPR64(FDREG), FPR32(FSREG), SIZE_QWORD, ROUND_CEIL);// fstoint ,,qword,ceil + else /* CEIL.L.D - MIPS III */ + UML_FDTOINT(block, FPR64(FDREG), FPR64(FSREG), SIZE_QWORD, ROUND_CEIL);// fdtoint ,,qword,ceil + UML_DSEXT(block, FPR64(FDREG), FPR64(FDREG), SIZE_DWORD); + return TRUE; + + case 0x0b: + if (IS_SINGLE(op)) /* FLOOR.L.S - MIPS III */ + UML_FSTOINT(block, FPR64(FDREG), FPR32(FSREG), SIZE_QWORD, ROUND_FLOOR);// fstoint ,,qword,floor + else /* FLOOR.L.D - MIPS III */ + UML_FDTOINT(block, FPR64(FDREG), FPR64(FSREG), SIZE_QWORD, ROUND_FLOOR);// fdtoint ,,qword,floor + UML_DSEXT(block, FPR64(FDREG), FPR64(FDREG), SIZE_DWORD); + return TRUE; + + case 0x0c: + if (IS_SINGLE(op)) /* ROUND.W.S - MIPS II */ + UML_FSTOINT(block, FPR32(FDREG), FPR32(FSREG), SIZE_DWORD, ROUND_ROUND);// fstoint ,,dword,round + else /* ROUND.W.D - MIPS II */ + UML_FDTOINT(block, FPR32(FDREG), FPR64(FSREG), SIZE_DWORD, ROUND_ROUND);// fdtoint ,,dword,round + return TRUE; + + case 0x0d: + if (IS_SINGLE(op)) /* TRUNC.W.S - MIPS II */ + UML_FSTOINT(block, FPR32(FDREG), FPR32(FSREG), SIZE_DWORD, ROUND_TRUNC);// fstoint ,,dword,trunc + else /* TRUNC.W.D - MIPS II */ + UML_FDTOINT(block, FPR32(FDREG), FPR64(FSREG), SIZE_DWORD, ROUND_TRUNC);// fdtoint ,,dword,trunc + return TRUE; + + case 0x0e: + if (IS_SINGLE(op)) /* CEIL.W.S - MIPS II */ + UML_FSTOINT(block, FPR32(FDREG), FPR32(FSREG), SIZE_DWORD, ROUND_CEIL);// fstoint ,,dword,ceil + else /* CEIL.W.D - MIPS II */ + UML_FDTOINT(block, FPR32(FDREG), FPR64(FSREG), SIZE_DWORD, ROUND_CEIL);// fdtoint ,,dword,ceil + return TRUE; + + case 0x0f: + if (IS_SINGLE(op)) /* FLOOR.W.S - MIPS II */ + UML_FSTOINT(block, FPR32(FDREG), FPR32(FSREG), SIZE_DWORD, ROUND_FLOOR);// fstoint ,,dword,floor + else /* FLOOR.W.D - MIPS II */ + UML_FDTOINT(block, FPR32(FDREG), FPR64(FSREG), SIZE_DWORD, ROUND_FLOOR);// fdtoint ,,dword,floor + return TRUE; + + case 0x11: + condition = ((op >> 16) & 1) ? COND_NZ : COND_Z; + UML_TEST(block, CCR132(31), FCCMASK(op >> 18)); // test ccr31,fccmask[op] + if (IS_SINGLE(op)) /* MOVT/F.S - MIPS IV */ + UML_FSMOVc(block, condition, FPR32(FDREG), FPR32(FSREG)); // fsmov ,,condition + else /* MOVT/F.D - MIPS IV */ + UML_FDMOVc(block, condition, FPR64(FDREG), FPR64(FSREG)); // fdmov ,,condition + return TRUE; + + case 0x12: + UML_DCMP(block, R64(RTREG), 0); // dcmp ,0 + if (IS_SINGLE(op)) /* MOVZ.S - MIPS IV */ + UML_FSMOVc(block, COND_Z, FPR32(FDREG), FPR32(FSREG)); // fsmov ,,Z + else /* MOVZ.D - MIPS IV */ + UML_FDMOVc(block, COND_Z, FPR64(FDREG), FPR64(FSREG)); // fdmov ,,Z + return TRUE; + + case 0x13: + UML_DCMP(block, R64(RTREG), 0); // dcmp ,0 + if (IS_SINGLE(op)) /* MOVN.S - MIPS IV */ + UML_FSMOVc(block, COND_NZ, FPR32(FDREG), FPR32(FSREG)); // fsmov ,,NZ + else /* MOVN.D - MIPS IV */ + UML_FDMOVc(block, COND_NZ, FPR64(FDREG), FPR64(FSREG)); // fdmov ,,NZ + return TRUE; + + case 0x15: + if (IS_SINGLE(op)) /* RECIP.S - MIPS IV */ + UML_FSRECIP(block, FPR32(FDREG), FPR32(FSREG)); // fsrecip , + else /* RECIP.D - MIPS IV */ + UML_FDRECIP(block, FPR64(FDREG), FPR64(FSREG)); // fdrecip , + return TRUE; + + case 0x16: + if (IS_SINGLE(op)) /* RSQRT.S - MIPS IV */ + UML_FSRSQRT(block, FPR32(FDREG), FPR32(FSREG)); // fsrsqrt , + else /* RSQRT.D - MIPS IV */ + UML_FDRSQRT(block, FPR64(FDREG), FPR64(FSREG)); // fdrsqrt , + return TRUE; + + case 0x20: + if (IS_INTEGRAL(op)) + { + if (IS_SINGLE(op)) /* CVT.S.W - MIPS I */ + UML_FSFRINT(block, FPR32(FDREG), FPR32(FSREG), SIZE_DWORD); // fsfrint ,,dword + else /* CVT.S.L - MIPS I */ + UML_FSFRINT(block, FPR32(FDREG), FPR64(FSREG), SIZE_QWORD); // fsfrint ,,qword + } + else /* CVT.S.D - MIPS I */ + UML_FSFRFLT(block, FPR32(FDREG), FPR64(FSREG), SIZE_QWORD); // fsfrflt ,,qword + return TRUE; + + case 0x21: + if (IS_INTEGRAL(op)) + { + if (IS_SINGLE(op)) /* CVT.D.W - MIPS I */ + UML_FDFRINT(block, FPR64(FDREG), FPR32(FSREG), SIZE_DWORD); // fdfrint ,,dword + else /* CVT.D.L - MIPS I */ + UML_FDFRINT(block, FPR64(FDREG), FPR64(FSREG), SIZE_QWORD); // fdfrint ,,qword + } + else /* CVT.D.S - MIPS I */ + UML_FDFRFLT(block, FPR64(FDREG), FPR32(FSREG), SIZE_DWORD); // fdfrflt ,,dword + return TRUE; + + case 0x24: + if (IS_SINGLE(op)) /* CVT.W.S - MIPS I */ + UML_FSTOINT(block, FPR32(FDREG), FPR32(FSREG), SIZE_DWORD, ROUND_DEFAULT);// fstoint ,,dword,default + else /* CVT.W.D - MIPS I */ + UML_FDTOINT(block, FPR32(FDREG), FPR64(FSREG), SIZE_DWORD, ROUND_DEFAULT);// fdtoint ,,dword,default + return TRUE; + + case 0x25: + if (IS_SINGLE(op)) /* CVT.L.S - MIPS I */ + UML_FSTOINT(block, FPR64(FDREG), FPR32(FSREG), SIZE_QWORD, ROUND_DEFAULT);// fstoint ,,qword,default + else /* CVT.L.D - MIPS I */ + UML_FDTOINT(block, FPR64(FDREG), FPR64(FSREG), SIZE_QWORD, ROUND_DEFAULT);// fdtoint ,,qword,default + return TRUE; + + case 0x30: + case 0x38: /* C.F.S/D - MIPS I */ + UML_AND(block, CCR132(31), CCR132(31), ~FCCMASK(op >> 8)); // and ccr31,ccr31,~fccmask[op] + return TRUE; + + case 0x31: + case 0x39: + if (IS_SINGLE(op)) /* C.UN.S - MIPS I */ + UML_FSCMP(block, FPR32(FSREG), FPR32(FTREG)); // fscmp , + else /* C.UN.D - MIPS I */ + UML_FDCMP(block, FPR64(FSREG), FPR64(FTREG)); // fdcmp , + UML_SETc(block, COND_U, I0); // set i0,u + UML_ROLINS(block, CCR132(31), I0, FCCSHIFT(op >> 8), FCCMASK(op >> 8)); + // rolins ccr31,i0,fccshift,fcc + return TRUE; + + case 0x32: + case 0x3a: + if (IS_SINGLE(op)) /* C.EQ.S - MIPS I */ + UML_FSCMP(block, FPR32(FSREG), FPR32(FTREG)); // fscmp , + else /* C.EQ.D - MIPS I */ + UML_FDCMP(block, FPR64(FSREG), FPR64(FTREG)); // fdcmp , + UML_SETc(block, COND_E, I0); // set i0,e + UML_SETc(block, COND_NU, I1); // set i1,nu + UML_AND(block, I0, I0, I1); // and i0,i0,i1 + UML_ROLINS(block, CCR132(31), I0, FCCSHIFT(op >> 8), FCCMASK(op >> 8)); + // rolins ccr31,i0,fccshift,fcc + return TRUE; + + case 0x33: + case 0x3b: + if (IS_SINGLE(op)) /* C.UEQ.S - MIPS I */ + UML_FSCMP(block, FPR32(FSREG), FPR32(FTREG)); // fscmp , + else /* C.UEQ.D - MIPS I */ + UML_FDCMP(block, FPR64(FSREG), FPR64(FTREG)); // fdcmp , + UML_SETc(block, COND_U, I0); // set i0,u + UML_SETc(block, COND_E, I1); // set i1,e + UML_OR(block, I0, I0, I1); // or i0,i0,i1 + UML_ROLINS(block, CCR132(31), I0, FCCSHIFT(op >> 8), FCCMASK(op >> 8)); + // rolins ccr31,i0,fccshift,fcc + return TRUE; + + case 0x34: + case 0x3c: + if (IS_SINGLE(op)) /* C.OLT.S - MIPS I */ + UML_FSCMP(block, FPR32(FSREG), FPR32(FTREG)); // fscmp , + else /* C.OLT.D - MIPS I */ + UML_FDCMP(block, FPR64(FSREG), FPR64(FTREG)); // fdcmp , + UML_SETc(block, COND_B, I0); // set i0,b + UML_SETc(block, COND_NU, I1); // set i1,nu + UML_AND(block, I0, I0, I1); // and i0,i0,i1 + UML_ROLINS(block, CCR132(31), I0, FCCSHIFT(op >> 8), FCCMASK(op >> 8)); + // rolins ccr31,i0,fccshift,fcc + return TRUE; + + case 0x35: + case 0x3d: + if (IS_SINGLE(op)) /* C.ULT.S - MIPS I */ + UML_FSCMP(block, FPR32(FSREG), FPR32(FTREG)); // fscmp , + else /* C.ULT.D - MIPS I */ + UML_FDCMP(block, FPR64(FSREG), FPR64(FTREG)); // fdcmp , + UML_SETc(block, COND_U, I0); // set i0,u + UML_SETc(block, COND_B, I1); // set i1,b + UML_OR(block, I0, I0, I1); // or i0,i0,i1 + UML_ROLINS(block, CCR132(31), I0, FCCSHIFT(op >> 8), FCCMASK(op >> 8)); + // rolins ccr31,i0,fccshift,fcc + return TRUE; + + case 0x36: + case 0x3e: + if (IS_SINGLE(op)) /* C.OLE.S - MIPS I */ + UML_FSCMP(block, FPR32(FSREG), FPR32(FTREG)); // fscmp , + else /* C.OLE.D - MIPS I */ + UML_FDCMP(block, FPR64(FSREG), FPR64(FTREG)); // fdcmp , + UML_SETc(block, COND_BE, I0); // set i0,be + UML_SETc(block, COND_NU, I1); // set i1,nu + UML_AND(block, I0, I0, I1); // and i0,i0,i1 + UML_ROLINS(block, CCR132(31), I0, FCCSHIFT(op >> 8), FCCMASK(op >> 8)); + // rolins ccr31,i0,fccshift,fcc + return TRUE; + + case 0x37: + case 0x3f: + if (IS_SINGLE(op)) /* C.ULE.S - MIPS I */ + UML_FSCMP(block, FPR32(FSREG), FPR32(FTREG)); // fscmp , + else /* C.ULE.D - MIPS I */ + UML_FDCMP(block, FPR64(FSREG), FPR64(FTREG)); // fdcmp , + UML_SETc(block, COND_U, I0); // set i0,u + UML_SETc(block, COND_BE, I1); // set i1,be + UML_OR(block, I0, I0, I1); // or i0,i0,i1 + UML_ROLINS(block, CCR132(31), I0, FCCSHIFT(op >> 8), FCCMASK(op >> 8)); + // rolins ccr31,i0,fccshift,fcc + return TRUE; + } + break; + } + return FALSE; +} + + + +/*************************************************************************** + COP1X RECOMPILATION +***************************************************************************/ + +/*------------------------------------------------- + generate_cop1x - compile COP1X opcodes +-------------------------------------------------*/ + +int mips3_device::generate_cop1x(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) +{ + int in_delay_slot = ((desc->flags & OPFLAG_IN_DELAY_SLOT) != 0); + UINT32 op = desc->opptr.l[0]; + + check_cop1_access(block); + + switch (op & 0x3f) + { + case 0x00: /* LWXC1 - MIPS IV */ + UML_ADD(block, I0, R32(RSREG), R32(RTREG)); // add i0,, + UML_CALLH(block, *m_read32[m_core->mode >> 1]); // callh read32 + UML_MOV(block, FPR32(FDREG), I0); // mov ,i0 + if (!in_delay_slot) + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); + return TRUE; + + case 0x01: /* LDXC1 - MIPS IV */ + UML_ADD(block, I0, R32(RSREG), R32(RTREG)); // add i0,, + UML_CALLH(block, *m_read64[m_core->mode >> 1]); // callh read64 + UML_DMOV(block, FPR64(FDREG), I0); // dmov ,i0 + if (!in_delay_slot) + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); + return TRUE; + + case 0x08: /* SWXC1 - MIPS IV */ + UML_ADD(block, I0, R32(RSREG), R32(RTREG)); // add i0,, + UML_MOV(block, I1, FPR32(FSREG)); // mov i1, + UML_CALLH(block, *m_write32[m_core->mode >> 1]); // callh write32 + if (!in_delay_slot) + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); + return TRUE; + + case 0x09: /* SDXC1 - MIPS IV */ + UML_ADD(block, I0, R32(RSREG), R32(RTREG)); // add i0,, + UML_DMOV(block, I1, FPR64(FSREG)); // dmov i1, + UML_CALLH(block, *m_write64[m_core->mode >> 1]); // callh write64 + if (!in_delay_slot) + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); + return TRUE; + + case 0x0f: /* PREFX */ + return TRUE; + + case 0x20: /* MADD.S - MIPS IV */ + UML_FSMUL(block, F0, FPR32(FSREG), FPR32(FTREG)); // fsmul f0,, + UML_FSADD(block, FPR32(FDREG), F0, FPR32(FRREG)); // fsadd ,f0, + return TRUE; + + case 0x21: /* MADD.D - MIPS IV */ + UML_FDMUL(block, F0, FPR64(FSREG), FPR64(FTREG)); // fdmul f0,, + UML_FDADD(block, FPR64(FDREG), F0, FPR64(FRREG)); // fdadd ,f0, + return TRUE; + + case 0x28: /* MSUB.S - MIPS IV */ + UML_FSMUL(block, F0, FPR32(FSREG), FPR32(FTREG)); // fsmul f0,, + UML_FSSUB(block, FPR32(FDREG), F0, FPR32(FRREG)); // fssub ,f0, + return TRUE; + + case 0x29: /* MSUB.D - MIPS IV */ + UML_FDMUL(block, F0, FPR64(FSREG), FPR64(FTREG)); // fdmul f0,, + UML_FDSUB(block, FPR64(FDREG), F0, FPR64(FRREG)); // fdsub ,f0, + return TRUE; + + case 0x30: /* NMADD.S - MIPS IV */ + UML_FSMUL(block, F0, FPR32(FSREG), FPR32(FTREG)); // fsmul f0,, + UML_FSADD(block, F0, F0, FPR32(FRREG)); // fsadd f0,f0, + UML_FSNEG(block, FPR32(FDREG), F0); // fsneg ,f0 + return TRUE; + + case 0x31: /* NMADD.D - MIPS IV */ + UML_FDMUL(block, F0, FPR64(FSREG), FPR64(FTREG)); // fdmul f0,, + UML_FDADD(block, F0, F0, FPR64(FRREG)); // fdadd f0,f0, + UML_FDNEG(block, FPR64(FDREG), F0); // fdneg ,f0 + return TRUE; + + case 0x38: /* NMSUB.S - MIPS IV */ + UML_FSMUL(block, F0, FPR32(FSREG), FPR32(FTREG)); // fsmul f0,, + UML_FSSUB(block, FPR32(FDREG), FPR32(FRREG), F0); // fssub ,,f0 + return TRUE; + + case 0x39: /* NMSUB.D - MIPS IV */ + UML_FDMUL(block, F0, FPR64(FSREG), FPR64(FTREG)); // fdmul f0,, + UML_FDSUB(block, FPR64(FDREG), FPR64(FRREG), F0); // fdsub ,,f0 + return TRUE; + + default: + fprintf(stderr, "cop1x %X\n", op); + break; + } + return FALSE; +} + + + +/*************************************************************************** + CODE LOGGING HELPERS +***************************************************************************/ + +/*------------------------------------------------- + log_add_disasm_comment - add a comment + including disassembly of a MIPS instruction +-------------------------------------------------*/ + +void mips3_device::log_add_disasm_comment(drcuml_block *block, UINT32 pc, UINT32 op) +{ + if (m_drcuml->logging()) + { + char buffer[100]; + dasmmips3(buffer, pc, op); + block->append_comment("%08X: %s", pc, buffer); // comment + } +} + + +/*------------------------------------------------- + log_desc_flags_to_string - generate a string + representing the instruction description + flags +-------------------------------------------------*/ + +const char *mips3_device::log_desc_flags_to_string(UINT32 flags) +{ + static char tempbuf[30]; + char *dest = tempbuf; + + /* branches */ + if (flags & OPFLAG_IS_UNCONDITIONAL_BRANCH) + *dest++ = 'U'; + else if (flags & OPFLAG_IS_CONDITIONAL_BRANCH) + *dest++ = 'C'; + else + *dest++ = '.'; + + /* intrablock branches */ + *dest++ = (flags & OPFLAG_INTRABLOCK_BRANCH) ? 'i' : '.'; + + /* branch targets */ + *dest++ = (flags & OPFLAG_IS_BRANCH_TARGET) ? 'B' : '.'; + + /* delay slots */ + *dest++ = (flags & OPFLAG_IN_DELAY_SLOT) ? 'D' : '.'; + + /* exceptions */ + if (flags & OPFLAG_WILL_CAUSE_EXCEPTION) + *dest++ = 'E'; + else if (flags & OPFLAG_CAN_CAUSE_EXCEPTION) + *dest++ = 'e'; + else + *dest++ = '.'; + + /* read/write */ + if (flags & OPFLAG_READS_MEMORY) + *dest++ = 'R'; + else if (flags & OPFLAG_WRITES_MEMORY) + *dest++ = 'W'; + else + *dest++ = '.'; + + /* TLB validation */ + *dest++ = (flags & OPFLAG_VALIDATE_TLB) ? 'V' : '.'; + + /* TLB modification */ + *dest++ = (flags & OPFLAG_MODIFIES_TRANSLATION) ? 'T' : '.'; + + /* redispatch */ + *dest++ = (flags & OPFLAG_REDISPATCH) ? 'R' : '.'; + return tempbuf; +} + + +/*------------------------------------------------- + log_register_list - log a list of GPR registers +-------------------------------------------------*/ + +void mips3_device::log_register_list(drcuml_state *drcuml, const char *string, const UINT32 *reglist, const UINT32 *regnostarlist) +{ + int count = 0; + int regnum; + + /* skip if nothing */ + if (reglist[0] == 0 && reglist[1] == 0 && reglist[2] == 0) + return; + + drcuml->log_printf("[%s:", string); + + for (regnum = 1; regnum < 32; regnum++) + if (reglist[0] & REGFLAG_R(regnum)) + { + drcuml->log_printf("%sr%d", (count++ == 0) ? "" : ",", regnum); + if (regnostarlist != NULL && !(regnostarlist[0] & REGFLAG_R(regnum))) + drcuml->log_printf("*"); + } + + for (regnum = 0; regnum < 32; regnum++) + if (reglist[1] & REGFLAG_CPR1(regnum)) + { + drcuml->log_printf("%sfr%d", (count++ == 0) ? "" : ",", regnum); + if (regnostarlist != NULL && !(regnostarlist[1] & REGFLAG_CPR1(regnum))) + drcuml->log_printf("*"); + } + + if (reglist[2] & REGFLAG_LO) + { + drcuml->log_printf("%slo", (count++ == 0) ? "" : ","); + if (regnostarlist != NULL && !(regnostarlist[2] & REGFLAG_LO)) + drcuml->log_printf("*"); + } + if (reglist[2] & REGFLAG_HI) + { + drcuml->log_printf("%shi", (count++ == 0) ? "" : ","); + if (regnostarlist != NULL && !(regnostarlist[2] & REGFLAG_HI)) + drcuml->log_printf("*"); + } + if (reglist[2] & REGFLAG_FCC) + { + drcuml->log_printf("%sfcc", (count++ == 0) ? "" : ","); + if (regnostarlist != NULL && !(regnostarlist[2] & REGFLAG_FCC)) + drcuml->log_printf("*"); + } + + drcuml->log_printf("] "); +} + + +/*------------------------------------------------- + log_opcode_desc - log a list of descriptions +-------------------------------------------------*/ + +void mips3_device::log_opcode_desc(drcuml_state *drcuml, const opcode_desc *desclist, int indent) +{ + /* open the file, creating it if necessary */ + if (indent == 0) + drcuml->log_printf("\nDescriptor list @ %08X\n", desclist->pc); + + /* output each descriptor */ + for ( ; desclist != NULL; desclist = desclist->next()) + { + char buffer[100]; + + /* disassemle the current instruction and output it to the log */ + if (drcuml->logging() || drcuml->logging_native()) + { + if (desclist->flags & OPFLAG_VIRTUAL_NOOP) + strcpy(buffer, ""); + else + dasmmips3(buffer, desclist->pc, desclist->opptr.l[0]); + } + else + strcpy(buffer, "???"); + drcuml->log_printf("%08X [%08X] t:%08X f:%s: %-30s", desclist->pc, desclist->physpc, desclist->targetpc, log_desc_flags_to_string(desclist->flags), buffer); + + /* output register states */ + log_register_list(drcuml, "use", desclist->regin, NULL); + log_register_list(drcuml, "mod", desclist->regout, desclist->regreq); + drcuml->log_printf("\n"); + + /* if we have a delay slot, output it recursively */ + if (desclist->delay.first() != NULL) + log_opcode_desc(drcuml, desclist->delay.first(), indent + 1); + + /* at the end of a sequence add a dividing line */ + if (desclist->flags & OPFLAG_END_SEQUENCE) + drcuml->log_printf("-----\n"); + } +} diff --git a/src/devices/cpu/mips/mips3dsm.c b/src/devices/cpu/mips/mips3dsm.c new file mode 100644 index 00000000000..d453a17f1c0 --- /dev/null +++ b/src/devices/cpu/mips/mips3dsm.c @@ -0,0 +1,548 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + mips3dsm.c + Disassembler for the portable MIPS 3 emulator. + Written by Aaron Giles + +***************************************************************************/ + +#include "emu.h" + +#define USE_ABI_REG_NAMES (1) + +#if USE_ABI_REG_NAMES +static const char *const reg[32] = +{ + "$0", "$at", "$v0", "$v1", "$a0", "$a1", "$a2", "$a3", + "$t0", "$t1", "$t2", "$t3", "$t4", "$t5", "$t6", "$t7", + "$s0", "$s1", "$s2", "$s3", "$s4", "$s5", "$s6", "$s7", + "$t8", "$t9", "$k0", "$k1", "$gp", "$sp", "$fp", "$ra" +}; +#else +static const char *const reg[32] = +{ + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", + "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", + "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", + "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31" +}; +#endif + +static const char *const cacheop[32] = +{ + "I_Invd", "D_WBInvd", "Unknown 2", "Unknown 3", "I_IndexLoadTag", "D_IndexLoadTag", "Unknown 6", "Unknown 7", + "I_IndexStoreTag", "D_IndexStoreTag", "Unknown 10", "Unknown 11", "Unknown 12", "D_CreateDirtyExcl", "Unknown 14", "Unknown 15", + "I_HitInvalid", "D_HitInvalid", "Unknown 18", "Unknown 19", "I_Fill", "D_HitWBInvalid", "Unknown 22", "Unknown 23", + "I_HitWB", "D_HitWB", "Unknown 26", "Unknown 27", "Unknown 28", "Unknown 29", "Unknown 30", "Unknown 31" +}; + + +static const char *const cpreg[4][32] = +{ + { + "Index","Random","EntryLo0","EntryLo1","Context","PageMask","Wired","Error", + "BadVAddr","Count","EntryHi","Compare","SR","Cause","EPC","PRId", + "Config","LLAddr","WatchLo","WatchHi","XContext","cpr21","cpr22","cpr23", + "cpr24","cpr25","ECC","CacheError","TagLo","TagHi","ErrorEPC","cpr31" + }, + { + "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", + "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", + "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", + "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31" + }, + { + "cpr0", "cpr1", "cpr2", "cpr3", "cpr4", "cpr5", "cpr6", "cpr7", + "cpr8", "cpr9", "cpr10","cpr11","cpr12","cpr13","cpr14","cpr15", + "cpr16","cpr17","cpr18","cpr19","cpr20","cpr21","cpr22","cpr23", + "cpr24","cpr25","cpr26","cpr27","cpr28","cpr29","cpr30","cpr31" + }, + { + "cpr0", "cpr1", "cpr2", "cpr3", "cpr4", "cpr5", "cpr6", "cpr7", + "cpr8", "cpr9", "cpr10","cpr11","cpr12","cpr13","cpr14","cpr15", + "cpr16","cpr17","cpr18","cpr19","cpr20","cpr21","cpr22","cpr23", + "cpr24","cpr25","cpr26","cpr27","cpr28","cpr29","cpr30","cpr31" + } +}; + + +static const char *const ccreg[4][32] = +{ + { + "ccr0", "ccr1", "ccr2", "ccr3", "ccr4", "ccr5", "ccr6", "ccr7", + "ccr8", "ccr9", "ccr10","ccr11","ccr12","ccr13","ccr14","ccr15", + "ccr16","ccr17","ccr18","ccr19","ccr20","ccr21","ccr22","ccr23", + "ccr24","ccr25","ccr26","ccr27","ccr28","ccr29","ccr30","ccr31" + }, + { + "ccr0", "ccr1", "ccr2", "ccr3", "ccr4", "ccr5", "ccr6", "ccr7", + "ccr8", "ccr9", "ccr10","ccr11","ccr12","ccr13","ccr14","ccr15", + "ccr16","ccr17","ccr18","ccr19","ccr20","ccr21","ccr22","ccr23", + "ccr24","ccr25","ccr26","ccr27","ccr28","ccr29","ccr30","ccr31" + }, + { + "ccr0", "ccr1", "ccr2", "ccr3", "ccr4", "ccr5", "ccr6", "ccr7", + "ccr8", "ccr9", "ccr10","ccr11","ccr12","ccr13","ccr14","ccr15", + "ccr16","ccr17","ccr18","ccr19","ccr20","ccr21","ccr22","ccr23", + "ccr24","ccr25","ccr26","ccr27","ccr28","ccr29","ccr30","ccr31" + }, + { + "ccr0", "ccr1", "ccr2", "ccr3", "ccr4", "ccr5", "ccr6", "ccr7", + "ccr8", "ccr9", "ccr10","ccr11","ccr12","ccr13","ccr14","ccr15", + "ccr16","ccr17","ccr18","ccr19","ccr20","ccr21","ccr22","ccr23", + "ccr24","ccr25","ccr26","ccr27","ccr28","ccr29","ccr30","ccr31" + } +}; + + +/*************************************************************************** + CODE CODE +***************************************************************************/ + +INLINE char *signed_16bit(INT16 val) +{ + static char temp[10]; + if (val < 0) + sprintf(temp, "-$%x", -val); + else + sprintf(temp, "$%x", val); + return temp; +} + +static UINT32 dasm_cop0(UINT32 pc, UINT32 op, char *buffer) +{ + int rt = (op >> 16) & 31; + int rd = (op >> 11) & 31; + UINT32 flags = 0; + + switch ((op >> 21) & 31) + { + case 0x00: sprintf(buffer, "mfc0 %s,%s", reg[rt], cpreg[0][rd]); break; + case 0x01: sprintf(buffer, "dmfc0 %s,%s", reg[rt], cpreg[0][rd]); break; + case 0x02: sprintf(buffer, "cfc0 %s,%s", reg[rt], ccreg[0][rd]); break; + case 0x04: sprintf(buffer, "mtc0 %s,%s", reg[rt], cpreg[0][rd]); break; + case 0x05: sprintf(buffer, "dmtc0 %s,%s", reg[rt], cpreg[0][rd]); break; + case 0x06: sprintf(buffer, "ctc0 %s,%s", reg[rt], ccreg[0][rd]); break; + case 0x08: /* BC */ + switch (rt) + { + case 0x00: sprintf(buffer, "bc0f $%08x", pc + 4 + ((INT16)op << 2)); break; + case 0x01: sprintf(buffer, "bc0t $%08x", pc + 4 + ((INT16)op << 2)); break; + case 0x02: sprintf(buffer, "bc0fl [invalid]"); break; + case 0x03: sprintf(buffer, "bc0tl [invalid]"); break; + default: sprintf(buffer, "dc.l $%08x [invalid]", op); break; + } + break; + case 0x10: + case 0x11: + case 0x12: + case 0x13: + case 0x14: + case 0x15: + case 0x16: + case 0x17: + case 0x18: + case 0x19: + case 0x1a: + case 0x1b: + case 0x1c: + case 0x1d: + case 0x1e: + case 0x1f: /* COP */ + switch (op & 0x01ffffff) + { + case 0x01: sprintf(buffer, "tlbr"); break; + case 0x02: sprintf(buffer, "tlbwi"); break; + case 0x06: sprintf(buffer, "tlbwr"); break; + case 0x08: sprintf(buffer, "tlbp"); break; + case 0x10: sprintf(buffer, "rfe"); flags = DASMFLAG_STEP_OUT; break; + case 0x18: sprintf(buffer, "eret [invalid]"); break; + default: sprintf(buffer, "cop0 $%07x", op & 0x01ffffff); break; + } + break; + default: sprintf(buffer, "dc.l $%08x [invalid]", op); break; + } + return flags; +} + +static UINT32 dasm_cop1(UINT32 pc, UINT32 op, char *buffer) +{ + static const char *const format_table[] = + { + "?","?","?","?","?","?","?","?","?","?","?","?","?","?","?","?", + "s","d","?","?","w","l","?","?","?","?","?","?","?","?","?","?" + }; + const char *fmt = format_table[(op >> 21) & 31]; + int ft = (op >> 16) & 31; + int fs = (op >> 11) & 31; + int fd = (op >> 6) & 31; + int rt = (op >> 16) & 31; + int rd = (op >> 11) & 31; + UINT32 flags = 0; + + switch ((op >> 21) & 31) + { + case 0x00: sprintf(buffer, "mfc1 %s,%s", reg[rt], cpreg[1][rd]); break; + case 0x01: sprintf(buffer, "dmfc1 %s,%s", reg[rt], cpreg[1][rd]); break; + case 0x02: sprintf(buffer, "cfc1 %s,%s", reg[rt], ccreg[1][rd]); break; + case 0x04: sprintf(buffer, "mtc1 %s,%s", reg[rt], cpreg[1][rd]); break; + case 0x05: sprintf(buffer, "dmtc1 %s,%s", reg[rt], cpreg[1][rd]); break; + case 0x06: sprintf(buffer, "ctc1 %s,%s", reg[rt], ccreg[1][rd]); break; + case 0x08: /* BC */ + switch (rt & 3) + { + case 0x00: sprintf(buffer, "bc1f $%08x,%d", pc + 4 + ((INT16)op << 2), (op >> 18) & 7); break; + case 0x01: sprintf(buffer, "bc1t $%08x,%d", pc + 4 + ((INT16)op << 2), (op >> 18) & 7); break; + case 0x02: sprintf(buffer, "bc1fl $%08x,%d", pc + 4 + ((INT16)op << 2), (op >> 18) & 7); flags = DASMFLAG_STEP_OVER | DASMFLAG_STEP_OVER_EXTRA(1); break; + case 0x03: sprintf(buffer, "bc1tl $%08x,%d", pc + 4 + ((INT16)op << 2), (op >> 18) & 7); flags = DASMFLAG_STEP_OVER | DASMFLAG_STEP_OVER_EXTRA(1); break; + } + break; + default: /* COP */ + switch (op & 0x3f) + { + case 0x00: sprintf(buffer, "add.%s %s,%s,%s", fmt, cpreg[1][fd], cpreg[1][fs], cpreg[1][ft]); break; + case 0x01: sprintf(buffer, "sub.%s %s,%s,%s", fmt, cpreg[1][fd], cpreg[1][fs], cpreg[1][ft]); break; + case 0x02: sprintf(buffer, "mul.%s %s,%s,%s", fmt, cpreg[1][fd], cpreg[1][fs], cpreg[1][ft]); break; + case 0x03: sprintf(buffer, "div.%s %s,%s,%s", fmt, cpreg[1][fd], cpreg[1][fs], cpreg[1][ft]); break; + case 0x04: sprintf(buffer, "sqrt.%s %s,%s", fmt, cpreg[1][fd], cpreg[1][fs]); break; + case 0x05: sprintf(buffer, "abs.%s %s,%s", fmt, cpreg[1][fd], cpreg[1][fs]); break; + case 0x06: sprintf(buffer, "mov.%s %s,%s", fmt, cpreg[1][fd], cpreg[1][fs]); break; + case 0x07: sprintf(buffer, "neg.%s %s,%s", fmt, cpreg[1][fd], cpreg[1][fs]); break; + case 0x08: sprintf(buffer, "round.l.%s %s,%s", fmt, cpreg[1][fd], cpreg[1][fs]); break; + case 0x09: sprintf(buffer, "trunc.l.%s %s,%s", fmt, cpreg[1][fd], cpreg[1][fs]); break; + case 0x0a: sprintf(buffer, "ceil.l.%s %s,%s", fmt, cpreg[1][fd], cpreg[1][fs]); break; + case 0x0b: sprintf(buffer, "floor.l.%s %s,%s", fmt, cpreg[1][fd], cpreg[1][fs]); break; + case 0x0c: sprintf(buffer, "round.w.%s %s,%s", fmt, cpreg[1][fd], cpreg[1][fs]); break; + case 0x0d: sprintf(buffer, "trunc.w.%s %s,%s", fmt, cpreg[1][fd], cpreg[1][fs]); break; + case 0x0e: sprintf(buffer, "ceil.w.%s %s,%s", fmt, cpreg[1][fd], cpreg[1][fs]); break; + case 0x0f: sprintf(buffer, "floor.w.%s %s,%s", fmt, cpreg[1][fd], cpreg[1][fs]); break; + case 0x11: sprintf(buffer, "mov%c.%s %s,%s,%d", ((op >> 16) & 1) ? 't' : 'f', fmt, cpreg[1][fd], cpreg[1][fs], (op >> 18) & 7); break; + case 0x12: sprintf(buffer, "movz.%s %s,%s,%s", fmt, cpreg[1][fd], cpreg[1][fs], reg[rt]); break; + case 0x13: sprintf(buffer, "movn.%s %s,%s,%s", fmt, cpreg[1][fd], cpreg[1][fs], reg[rt]); break; + case 0x15: sprintf(buffer, "recip.%s %s,%s", fmt, cpreg[1][fd], cpreg[1][fs]); break; + case 0x16: sprintf(buffer, "rsqrt.%s %s,%s", fmt, cpreg[1][fd], cpreg[1][fs]); break; + case 0x20: sprintf(buffer, "cvt.s.%s %s,%s", fmt, cpreg[1][fd], cpreg[1][fs]); break; + case 0x21: sprintf(buffer, "cvt.d.%s %s,%s", fmt, cpreg[1][fd], cpreg[1][fs]); break; + case 0x24: sprintf(buffer, "cvt.w.%s %s,%s", fmt, cpreg[1][fd], cpreg[1][fs]); break; + case 0x25: sprintf(buffer, "cvt.l.%s %s,%s", fmt, cpreg[1][fd], cpreg[1][fs]); break; + case 0x30: sprintf(buffer, "c.f.%s %s,%s,%d", fmt, cpreg[1][fs], cpreg[1][ft], (op >> 8) & 7); break; + case 0x31: sprintf(buffer, "c.un.%s %s,%s,%d", fmt, cpreg[1][fs], cpreg[1][ft], (op >> 8) & 7); break; + case 0x32: sprintf(buffer, "c.eq.%s %s,%s,%d", fmt, cpreg[1][fs], cpreg[1][ft], (op >> 8) & 7); break; + case 0x33: sprintf(buffer, "c.ueq.%s %s,%s,%d", fmt, cpreg[1][fs], cpreg[1][ft], (op >> 8) & 7); break; + case 0x34: sprintf(buffer, "c.olt.%s %s,%s,%d", fmt, cpreg[1][fs], cpreg[1][ft], (op >> 8) & 7); break; + case 0x35: sprintf(buffer, "c.ult.%s %s,%s,%d", fmt, cpreg[1][fs], cpreg[1][ft], (op >> 8) & 7); break; + case 0x36: sprintf(buffer, "c.ole.%s %s,%s,%d", fmt, cpreg[1][fs], cpreg[1][ft], (op >> 8) & 7); break; + case 0x37: sprintf(buffer, "c.ule.%s %s,%s,%d", fmt, cpreg[1][fs], cpreg[1][ft], (op >> 8) & 7); break; + case 0x38: sprintf(buffer, "c.sf.%s %s,%s,%d", fmt, cpreg[1][fs], cpreg[1][ft], (op >> 8) & 7); break; + case 0x39: sprintf(buffer, "c.ngle.%s %s,%s,%d", fmt, cpreg[1][fs], cpreg[1][ft], (op >> 8) & 7);break; + case 0x3a: sprintf(buffer, "c.seq.%s %s,%s,%d", fmt, cpreg[1][fs], cpreg[1][ft], (op >> 8) & 7); break; + case 0x3b: sprintf(buffer, "c.ngl.%s %s,%s,%d", fmt, cpreg[1][fs], cpreg[1][ft], (op >> 8) & 7); break; + case 0x3c: sprintf(buffer, "c.lt.%s %s,%s,%d", fmt, cpreg[1][fs], cpreg[1][ft], (op >> 8) & 7); break; + case 0x3d: sprintf(buffer, "c.nge.%s %s,%s,%d", fmt, cpreg[1][fs], cpreg[1][ft], (op >> 8) & 7); break; + case 0x3e: sprintf(buffer, "c.le.%s %s,%s,%d", fmt, cpreg[1][fs], cpreg[1][ft], (op >> 8) & 7); break; + case 0x3f: sprintf(buffer, "c.ngt.%s %s,%s,%d", fmt, cpreg[1][fs], cpreg[1][ft], (op >> 8) & 7); break; + default: sprintf(buffer, "cop1 $%07x", op & 0x01ffffff); break; + } + break; + } + return flags; +} + +static UINT32 dasm_cop1x(UINT32 pc, UINT32 op, char *buffer) +{ + static const char *const format3_table[] = + { + "s","d","?","?","w","l","?","?" + }; + const char *fmt3 = format3_table[op & 7]; + int fr = (op >> 21) & 31; + int ft = (op >> 16) & 31; + int fs = (op >> 11) & 31; + int fd = (op >> 6) & 31; + int rs = (op >> 21) & 31; + int rt = (op >> 16) & 31; + int rd = (op >> 11) & 31; + UINT32 flags = 0; + + switch (op & 0x3f) + { + case 0x00: sprintf(buffer, "lwxc1 %s,%s(%s)", cpreg[1][fd], reg[rt], reg[rs]); break; + case 0x01: sprintf(buffer, "ldxc1 %s,%s(%s)", cpreg[1][fd], reg[rt], reg[rs]); break; + case 0x08: sprintf(buffer, "swxc1 %s,%s(%s)", cpreg[1][fd], reg[rt], reg[rs]); break; + case 0x09: sprintf(buffer, "sdxc1 %s,%s(%s)", cpreg[1][fd], reg[rt], reg[rs]); break; + case 0x0f: sprintf(buffer, "prefx %d,%s(%s)", rd, reg[rt], reg[rs]); break; + case 0x20: + case 0x21: + case 0x22: + case 0x23: + case 0x24: + case 0x25: + case 0x26: + case 0x27: sprintf(buffer, "madd.%s %s,%s,%s,%s", fmt3, cpreg[1][fd], cpreg[1][fr], cpreg[1][fs], cpreg[1][ft]); break; + case 0x28: + case 0x29: + case 0x2a: + case 0x2b: + case 0x2c: + case 0x2d: + case 0x2e: + case 0x2f: sprintf(buffer, "msub.%s %s,%s,%s,%s", fmt3, cpreg[1][fd], cpreg[1][fr], cpreg[1][fs], cpreg[1][ft]); break; + case 0x30: + case 0x31: + case 0x32: + case 0x33: + case 0x34: + case 0x35: + case 0x36: + case 0x37: sprintf(buffer, "nmadd.%s %s,%s,%s,%s", fmt3, cpreg[1][fd], cpreg[1][fr], cpreg[1][fs], cpreg[1][ft]); break; + case 0x38: + case 0x39: + case 0x3a: + case 0x3b: + case 0x3c: + case 0x3d: + case 0x3e: + case 0x3f: sprintf(buffer, "nmsub.%s %s,%s,%s,%s", fmt3, cpreg[1][fd], cpreg[1][fr], cpreg[1][fs], cpreg[1][ft]); break; + default: sprintf(buffer, "cop1 $%07x", op & 0x01ffffff); break; + } + return flags; +} + +static UINT32 dasm_cop2(UINT32 pc, UINT32 op, char *buffer) +{ + int rt = (op >> 16) & 31; + int rd = (op >> 11) & 31; + UINT32 flags = 0; + + switch ((op >> 21) & 31) + { + case 0x00: sprintf(buffer, "mfc2 %s,%s", reg[rt], cpreg[2][rd]); break; + case 0x01: sprintf(buffer, "dmfc2 %s,%s", reg[rt], cpreg[2][rd]); break; + case 0x02: sprintf(buffer, "cfc2 %s,%s", reg[rt], ccreg[2][rd]); break; + case 0x04: sprintf(buffer, "mtc2 %s,%s", reg[rt], cpreg[2][rd]); break; + case 0x05: sprintf(buffer, "dmtc2 %s,%s", reg[rt], cpreg[2][rd]); break; + case 0x06: sprintf(buffer, "ctc2 %s,%s", reg[rt], ccreg[2][rd]); break; + case 0x08: /* BC */ + switch (rt) + { + case 0x00: sprintf(buffer, "bc2f $%08x", pc + 4 + ((INT16)op << 2)); break; + case 0x01: sprintf(buffer, "bc2t $%08x", pc + 4 + ((INT16)op << 2)); break; + case 0x02: sprintf(buffer, "bc2fl [invalid]"); break; + case 0x03: sprintf(buffer, "bc2tl [invalid]"); break; + default: sprintf(buffer, "dc.l $%08x [invalid]", op); break; + } + break; + case 0x10: + case 0x11: + case 0x12: + case 0x13: + case 0x14: + case 0x15: + case 0x16: + case 0x17: + case 0x18: + case 0x19: + case 0x1a: + case 0x1b: + case 0x1c: + case 0x1d: + case 0x1e: + case 0x1f: /* COP */ + sprintf(buffer, "cop2 $%07x", op & 0x01ffffff); + break; + default: sprintf(buffer, "dc.l $%08x [invalid]", op); break; + } + return flags; +} + +unsigned dasmmips3(char *buffer, unsigned pc, UINT32 op) +{ + int rs = (op >> 21) & 31; + int rt = (op >> 16) & 31; + int rd = (op >> 11) & 31; + int shift = (op >> 6) & 31; + UINT32 flags = 0; + + switch (op >> 26) + { + case 0x00: /* SPECIAL */ + switch (op & 63) + { + case 0x00: if (op == 0) + sprintf(buffer, "nop"); + else + sprintf(buffer, "sll %s,%s,%d", reg[rd], reg[rt], shift); break; + case 0x01: sprintf(buffer, "mov%c %s,%s,%d", ((op >> 16) & 1) ? 't' : 'f', reg[rd], reg[rs], (op >> 18) & 7); break; + case 0x02: sprintf(buffer, "srl %s,%s,%d", reg[rd], reg[rt], shift); break; + case 0x03: sprintf(buffer, "sra %s,%s,%d", reg[rd], reg[rt], shift); break; + case 0x04: sprintf(buffer, "sllv %s,%s,%s", reg[rd], reg[rt], reg[rs]); break; + case 0x06: sprintf(buffer, "srlv %s,%s,%s", reg[rd], reg[rt], reg[rs]); break; + case 0x07: sprintf(buffer, "srav %s,%s,%s", reg[rd], reg[rt], reg[rs]); break; + case 0x08: sprintf(buffer, "jr %s", reg[rs]); if (rs == 31) flags = DASMFLAG_STEP_OUT; break; + case 0x09: if (rd == 31) + sprintf(buffer, "jalr %s", reg[rs]); + else + sprintf(buffer, "jalr %s,%s", reg[rs], reg[rd]); flags = DASMFLAG_STEP_OVER | DASMFLAG_STEP_OVER_EXTRA(1); break; + case 0x0a: sprintf(buffer, "movz %s,%s,%s", reg[rd], reg[rs], reg[rt]); break; + case 0x0b: sprintf(buffer, "movn %s,%s,%s", reg[rd], reg[rs], reg[rt]); break; + case 0x0c: sprintf(buffer, "syscall"); flags = DASMFLAG_STEP_OVER; break; + case 0x0d: sprintf(buffer, "break"); flags = DASMFLAG_STEP_OVER; break; + case 0x0f: sprintf(buffer, "sync"); break; + case 0x10: sprintf(buffer, "mfhi %s", reg[rd]); break; + case 0x11: sprintf(buffer, "mthi %s", reg[rs]); break; + case 0x12: sprintf(buffer, "mflo %s", reg[rd]); break; + case 0x13: sprintf(buffer, "mtlo %s", reg[rs]); break; + case 0x14: sprintf(buffer, "dsllv %s,%s,%s", reg[rd], reg[rt], reg[rs]); break; + case 0x16: sprintf(buffer, "dsrlv %s,%s,%s", reg[rd], reg[rt], reg[rs]); break; + case 0x17: sprintf(buffer, "dsrav %s,%s,%s", reg[rd], reg[rt], reg[rs]); break; + case 0x18: sprintf(buffer, "mult %s,%s", reg[rs], reg[rt]); break; + case 0x19: sprintf(buffer, "multu %s,%s", reg[rs], reg[rt]); break; + case 0x1a: sprintf(buffer, "div %s,%s", reg[rs], reg[rt]); break; + case 0x1b: sprintf(buffer, "divu %s,%s", reg[rs], reg[rt]); break; + case 0x1c: sprintf(buffer, "dmult %s,%s", reg[rs], reg[rt]); break; + case 0x1d: sprintf(buffer, "dmultu %s,%s", reg[rs], reg[rt]); break; + case 0x1e: sprintf(buffer, "ddiv %s,%s", reg[rs], reg[rt]); break; + case 0x1f: sprintf(buffer, "ddivu %s,%s", reg[rs], reg[rt]); break; + case 0x20: sprintf(buffer, "add %s,%s,%s", reg[rd], reg[rs], reg[rt]); break; + case 0x21: sprintf(buffer, "addu %s,%s,%s", reg[rd], reg[rs], reg[rt]); break; + case 0x22: sprintf(buffer, "sub %s,%s,%s", reg[rd], reg[rs], reg[rt]); break; + case 0x23: sprintf(buffer, "subu %s,%s,%s", reg[rd], reg[rs], reg[rt]); break; + case 0x24: sprintf(buffer, "and %s,%s,%s", reg[rd], reg[rs], reg[rt]); break; + case 0x25: sprintf(buffer, "or %s,%s,%s", reg[rd], reg[rs], reg[rt]); break; + case 0x26: sprintf(buffer, "xor %s,%s,%s", reg[rd], reg[rs], reg[rt]); break; + case 0x27: sprintf(buffer, "nor %s,%s,%s", reg[rd], reg[rs], reg[rt]); break; + case 0x2a: sprintf(buffer, "slt %s,%s,%s", reg[rd], reg[rs], reg[rt]); break; + case 0x2b: sprintf(buffer, "sltu %s,%s,%s", reg[rd], reg[rs], reg[rt]); break; + case 0x2c: sprintf(buffer, "dadd %s,%s,%s", reg[rd], reg[rs], reg[rt]); break; + case 0x2d: sprintf(buffer, "daddu %s,%s,%s", reg[rd], reg[rs], reg[rt]); break; + case 0x2e: sprintf(buffer, "dsub %s,%s,%s", reg[rd], reg[rs], reg[rt]); break; + case 0x2f: sprintf(buffer, "dsubu %s,%s,%s", reg[rd], reg[rs], reg[rt]); break; + case 0x30: sprintf(buffer, "tge %s,%s", reg[rs], reg[rt]); flags = DASMFLAG_STEP_OVER; break; + case 0x31: sprintf(buffer, "tgeu %s,%s", reg[rs], reg[rt]); flags = DASMFLAG_STEP_OVER; break; + case 0x32: sprintf(buffer, "tlt %s,%s", reg[rs], reg[rt]); flags = DASMFLAG_STEP_OVER; break; + case 0x33: sprintf(buffer, "tltu %s,%s", reg[rs], reg[rt]); flags = DASMFLAG_STEP_OVER; break; + case 0x34: sprintf(buffer, "teq %s,%s", reg[rs], reg[rt]); flags = DASMFLAG_STEP_OVER; break; + case 0x36: sprintf(buffer, "tne %s,%s", reg[rs], reg[rt]) ;flags = DASMFLAG_STEP_OVER; break; + case 0x38: sprintf(buffer, "dsll %s,%s,%d", reg[rd], reg[rt], shift); break; + case 0x3a: sprintf(buffer, "dsrl %s,%s,%d", reg[rd], reg[rt], shift); break; + case 0x3b: sprintf(buffer, "dsra %s,%s,%d", reg[rd], reg[rt], shift); break; + case 0x3c: sprintf(buffer, "dsll %s,%s,%d", reg[rd], reg[rt], shift+32); break; + case 0x3e: sprintf(buffer, "dsrl %s,%s,%d", reg[rd], reg[rt], shift+32); break; + case 0x3f: sprintf(buffer, "dsra %s,%s,%d", reg[rd], reg[rt], shift+32); break; + default: sprintf(buffer, "dc.l $%08x [invalid]", op); break; + } + break; + + case 0x01: /* REGIMM */ + switch ((op >> 16) & 31) + { + case 0x00: sprintf(buffer, "bltz %s,$%08x", reg[rs], pc + 4 + ((INT16)op << 2)); break; + case 0x01: sprintf(buffer, "bgez %s,$%08x", reg[rs], pc + 4 + ((INT16)op << 2)); break; + case 0x02: sprintf(buffer, "bltzl %s,$%08x", reg[rs], pc + 4 + ((INT16)op << 2)); break; + case 0x03: sprintf(buffer, "bgezl %s,$%08x", reg[rs], pc + 4 + ((INT16)op << 2)); break; + case 0x08: sprintf(buffer, "tgei %s,%s", reg[rs], signed_16bit(op)); flags = DASMFLAG_STEP_OVER; break; + case 0x09: sprintf(buffer, "tgeiu %s,%s", reg[rs], signed_16bit(op)); flags = DASMFLAG_STEP_OVER; break; + case 0x0a: sprintf(buffer, "tlti %s,%s", reg[rs], signed_16bit(op)); flags = DASMFLAG_STEP_OVER; break; + case 0x0b: sprintf(buffer, "tltiu %s,%s", reg[rs], signed_16bit(op)); flags = DASMFLAG_STEP_OVER; break; + case 0x0c: sprintf(buffer, "teqi %s,%s", reg[rs], signed_16bit(op)); flags = DASMFLAG_STEP_OVER; break; + case 0x0e: sprintf(buffer, "tnei %s,%s", reg[rs], signed_16bit(op)); flags = DASMFLAG_STEP_OVER; break; + case 0x10: sprintf(buffer, "bltzal %s,$%08x", reg[rs], pc + 4 + ((INT16)op << 2)); flags = DASMFLAG_STEP_OVER | DASMFLAG_STEP_OVER_EXTRA(1); break; + case 0x11: sprintf(buffer, "bgezal %s,$%08x", reg[rs], pc + 4 + ((INT16)op << 2)); flags = DASMFLAG_STEP_OVER | DASMFLAG_STEP_OVER_EXTRA(1); break; + case 0x12: sprintf(buffer, "bltzall %s,$%08x", reg[rs], pc + 4 + ((INT16)op << 2)); flags = DASMFLAG_STEP_OVER | DASMFLAG_STEP_OVER_EXTRA(1); break; + case 0x13: sprintf(buffer, "bgezall %s,$%08x", reg[rs], pc + 4 + ((INT16)op << 2)); flags = DASMFLAG_STEP_OVER | DASMFLAG_STEP_OVER_EXTRA(1); break; + default: sprintf(buffer, "dc.l $%08x [invalid]", op); break; + } + break; + + case 0x02: sprintf(buffer, "j $%08x", (pc & 0xf0000000) | ((op & 0x03ffffff) << 2)); break; + case 0x03: sprintf(buffer, "jal $%08x", (pc & 0xf0000000) | ((op & 0x03ffffff) << 2)); flags = DASMFLAG_STEP_OVER | DASMFLAG_STEP_OVER_EXTRA(1); break; + case 0x04: if (rs == 0 && rt == 0) + sprintf(buffer, "b $%08x", pc + 4 + ((INT16)op << 2)); + else + sprintf(buffer, "beq %s,%s,$%08x", reg[rs], reg[rt], pc + 4 + ((INT16)op << 2));break; + case 0x05: sprintf(buffer, "bne %s,%s,$%08x", reg[rs], reg[rt], pc + 4 + ((INT16)op << 2));break; + case 0x06: sprintf(buffer, "blez %s,$%08x", reg[rs], pc + 4 + ((INT16)op << 2)); break; + case 0x07: sprintf(buffer, "bgtz %s,$%08x", reg[rs], pc + 4 + ((INT16)op << 2)); break; + case 0x08: sprintf(buffer, "addi %s,%s,%s", reg[rt], reg[rs], signed_16bit(op)); break; + case 0x09: sprintf(buffer, "addiu %s,%s,%s", reg[rt], reg[rs], signed_16bit(op)); break; + case 0x0a: sprintf(buffer, "slti %s,%s,%s", reg[rt], reg[rs], signed_16bit(op)); break; + case 0x0b: sprintf(buffer, "sltiu %s,%s,%s", reg[rt], reg[rs], signed_16bit(op)); break; + case 0x0c: sprintf(buffer, "andi %s,%s,$%04x", reg[rt], reg[rs], (UINT16)op); break; + case 0x0d: sprintf(buffer, "ori %s,%s,$%04x", reg[rt], reg[rs], (UINT16)op); break; + case 0x0e: sprintf(buffer, "xori %s,%s,$%04x", reg[rt], reg[rs], (UINT16)op); break; + case 0x0f: sprintf(buffer, "lui %s,$%04x", reg[rt], (UINT16)op); break; + case 0x10: flags = dasm_cop0(pc, op, buffer); break; + case 0x11: flags = dasm_cop1(pc, op, buffer); break; + case 0x12: flags = dasm_cop2(pc, op, buffer); break; + case 0x13: flags = dasm_cop1x(pc, op, buffer); break; + case 0x14: sprintf(buffer, "beql %s,%s,$%08x", reg[rs], reg[rt], pc + 4 + ((INT16)op << 2));break; + case 0x15: sprintf(buffer, "bnel %s,%s,$%08x", reg[rs], reg[rt], pc + 4 + ((INT16)op << 2));break; + case 0x16: sprintf(buffer, "blezl %s,%s,$%08x", reg[rs], reg[rt], pc + 4 + ((INT16)op << 2));break; + case 0x17: sprintf(buffer, "bgtzl %s,%s,$%08x", reg[rs], reg[rt], pc + 4 + ((INT16)op << 2));break; + case 0x18: sprintf(buffer, "daddi %s,%s,%s", reg[rt], reg[rs], signed_16bit(op)); break; + case 0x19: sprintf(buffer, "daddiu %s,%s,%s", reg[rt], reg[rs], signed_16bit(op)); break; + case 0x1a: sprintf(buffer, "ldl %s,%s(%s)", reg[rt], signed_16bit(op), reg[rs]); break; + case 0x1b: sprintf(buffer, "ldr %s,%s(%s)", reg[rt], signed_16bit(op), reg[rs]); break; + case 0x1c: /* IDT-specific opcodes: mad/madu/mul on R4640/4650, msub on RC32364 */ + switch (op & 0x1f) + { + case 0: sprintf(buffer, "mad %s,%s", reg[rs], reg[rt]); break; + case 1: sprintf(buffer, "madu %s,%s", reg[rs], reg[rt]); break; + case 2: sprintf(buffer, "mul %s,%s,%s", reg[rs], reg[rt], reg[rd]); break; + case 4: sprintf(buffer, "msub %s,%s", reg[rs], reg[rt]); break; + default:sprintf(buffer, "dc.l $%08x [invalid]", op); break; + } + break; + case 0x20: sprintf(buffer, "lb %s,%s(%s)", reg[rt], signed_16bit(op), reg[rs]); break; + case 0x21: sprintf(buffer, "lh %s,%s(%s)", reg[rt], signed_16bit(op), reg[rs]); break; + case 0x22: sprintf(buffer, "lwl %s,%s(%s)", reg[rt], signed_16bit(op), reg[rs]); break; + case 0x23: sprintf(buffer, "lw %s,%s(%s)", reg[rt], signed_16bit(op), reg[rs]); break; + case 0x24: sprintf(buffer, "lbu %s,%s(%s)", reg[rt], signed_16bit(op), reg[rs]); break; + case 0x25: sprintf(buffer, "lhu %s,%s(%s)", reg[rt], signed_16bit(op), reg[rs]); break; + case 0x26: sprintf(buffer, "lwr %s,%s(%s)", reg[rt], signed_16bit(op), reg[rs]); break; + case 0x27: sprintf(buffer, "lwu %s,%s(%s)", reg[rt], signed_16bit(op), reg[rs]); break; + case 0x28: sprintf(buffer, "sb %s,%s(%s)", reg[rt], signed_16bit(op), reg[rs]); break; + case 0x29: sprintf(buffer, "sh %s,%s(%s)", reg[rt], signed_16bit(op), reg[rs]); break; + case 0x2a: sprintf(buffer, "swl %s,%s(%s)", reg[rt], signed_16bit(op), reg[rs]); break; + case 0x2b: sprintf(buffer, "sw %s,%s(%s)", reg[rt], signed_16bit(op), reg[rs]); break; + case 0x2c: sprintf(buffer, "sdl %s,%s(%s)", reg[rt], signed_16bit(op), reg[rs]); break; + case 0x2d: sprintf(buffer, "sdr %s,%s(%s)", reg[rt], signed_16bit(op), reg[rs]); break; + case 0x2e: sprintf(buffer, "swr %s,%s(%s)", reg[rt], signed_16bit(op), reg[rs]); break; + case 0x2f: sprintf(buffer, "cache %s,%s(%s)", cacheop[rt], reg[rs], signed_16bit(op)); break; + case 0x30: sprintf(buffer, "ll %s,%s(%s)", reg[rt], signed_16bit(op), reg[rs]); break; + case 0x31: sprintf(buffer, "lwc1 %s,%s(%s)", cpreg[1][rt], signed_16bit(op), reg[rs]); break; + case 0x32: sprintf(buffer, "lwc2 %s,%s(%s)", cpreg[2][rt], signed_16bit(op), reg[rs]); break; + case 0x33: sprintf(buffer, "pref $%x,%s(%s)", rt, signed_16bit(op), reg[rs]); break; + case 0x34: sprintf(buffer, "lld %s,%s(%s)", reg[rt], signed_16bit(op), reg[rs]); break; + case 0x35: sprintf(buffer, "ldc1 %s,%s(%s)", cpreg[1][rt], signed_16bit(op), reg[rs]); break; + case 0x36: sprintf(buffer, "ldc2 %s,%s(%s)", cpreg[2][rt], signed_16bit(op), reg[rs]); break; + case 0x37: sprintf(buffer, "ld %s,%s(%s)", reg[rt], signed_16bit(op), reg[rs]); break; + case 0x38: sprintf(buffer, "sc %s,%s(%s)", reg[rt], signed_16bit(op), reg[rs]); break; + case 0x39: sprintf(buffer, "swc1 %s,%s(%s)", cpreg[1][rt], signed_16bit(op), reg[rs]); break; + case 0x3a: sprintf(buffer, "swc2 %s,%s(%s)", cpreg[2][rt], signed_16bit(op), reg[rs]); break; + case 0x3c: sprintf(buffer, "scd %s,%s(%s)", reg[rt], signed_16bit(op), reg[rs]); break; + case 0x3d: sprintf(buffer, "sdc1 %s,%s(%s)", cpreg[1][rt], signed_16bit(op), reg[rs]); break; + case 0x3e: sprintf(buffer, "sdc2 %s,%s(%s)", cpreg[2][rt], signed_16bit(op), reg[rs]); break; + case 0x3f: sprintf(buffer, "sd %s,%s(%s)", reg[rt], signed_16bit(op), reg[rs]); break; + default: sprintf(buffer, "dc.l $%08x [invalid]", op); break; + } + return 4 | flags | DASMFLAG_SUPPORTED; +} + + +CPU_DISASSEMBLE( mips3be ) +{ + UINT32 op = *(UINT32 *)oprom; + op = BIG_ENDIANIZE_INT32(op); + return dasmmips3(buffer, pc, op); +} + + +CPU_DISASSEMBLE( mips3le ) +{ + UINT32 op = *(UINT32 *)oprom; + op = LITTLE_ENDIANIZE_INT32(op); + return dasmmips3(buffer, pc, op); +} diff --git a/src/devices/cpu/mips/mips3fe.c b/src/devices/cpu/mips/mips3fe.c new file mode 100644 index 00000000000..42055c39e24 --- /dev/null +++ b/src/devices/cpu/mips/mips3fe.c @@ -0,0 +1,741 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + mips3fe.c + + Front-end for MIPS3 recompiler + +***************************************************************************/ + +#include "emu.h" +#include "mips3fe.h" +#include "mips3com.h" + + +//************************************************************************** +// MIPS3 FRONTEND +//************************************************************************** + +//------------------------------------------------- +// mips3_frontend - constructor +//------------------------------------------------- + +mips3_frontend::mips3_frontend(mips3_device *mips3, UINT32 window_start, UINT32 window_end, UINT32 max_sequence) + : drc_frontend(*mips3, window_start, window_end, max_sequence), + m_mips3(mips3) +{ +} + + +//------------------------------------------------- +// describe - build a description of a single +// instruction +//------------------------------------------------- + +bool mips3_frontend::describe(opcode_desc &desc, const opcode_desc *prev) +{ + UINT32 op, opswitch; + + // compute the physical PC + assert((desc.physpc & 3) == 0); + if (!m_mips3->memory_translate(AS_PROGRAM, TRANSLATE_FETCH, desc.physpc)) + { + // uh-oh: a page fault; leave the description empty and just if this is the first instruction, leave it empty and + // mark as needing to validate; otherwise, just end the sequence here + desc.flags |= OPFLAG_VALIDATE_TLB | OPFLAG_CAN_CAUSE_EXCEPTION | OPFLAG_COMPILER_PAGE_FAULT | OPFLAG_VIRTUAL_NOOP | OPFLAG_END_SEQUENCE; + return true; + } + + // fetch the opcode + assert((desc.physpc & 3) == 0); + op = desc.opptr.l[0] = m_mips3->m_direct->read_dword(desc.physpc); + + // all instructions are 4 bytes and default to a single cycle each + desc.length = 4; + desc.cycles = 1; + + // parse the instruction + opswitch = op >> 26; + switch (opswitch) + { + case 0x00: // SPECIAL + return describe_special(op, desc); + + case 0x01: // REGIMM + return describe_regimm(op, desc); + + case 0x10: // COP0 + return describe_cop0(op, desc); + + case 0x11: // COP1 + return describe_cop1(op, desc); + + case 0x12: // COP2 + return describe_cop2(op, desc); + + case 0x13: // COP1X - MIPS IV + if (m_mips3->m_flavor < mips3_device::MIPS3_TYPE_MIPS_IV) + return false; + return describe_cop1x(op, desc); + + case 0x1c: // IDT-specific opcodes: mad/madu/mul on R4640/4650, msub on RC32364 + return describe_idt(op, desc); + + case 0x02: // J + desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; + desc.targetpc = (desc.pc & 0xf0000000) | (LIMMVAL << 2); + desc.delayslots = 1; + return true; + + case 0x03: // JAL + desc.regout[0] |= REGFLAG_R(31); + desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; + desc.targetpc = (desc.pc & 0xf0000000) | (LIMMVAL << 2); + desc.delayslots = 1; + return true; + + case 0x04: // BEQ + case 0x05: // BNE + case 0x14: // BEQL + case 0x15: // BNEL + if ((opswitch == 0x04 || opswitch == 0x14) && RSREG == RTREG) + desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; + else + { + desc.regin[0] |= REGFLAG_R(RSREG) | REGFLAG_R(RTREG); + desc.flags |= OPFLAG_IS_CONDITIONAL_BRANCH; + } + desc.targetpc = desc.pc + 4 + SIMMVAL * 4; + desc.delayslots = 1; + desc.skipslots = (opswitch & 0x10) ? 1 : 0; + return true; + + case 0x06: // BLEZ + case 0x07: // BGTZ + case 0x16: // BLEZL + case 0x17: // BGTZL + if ((opswitch == 0x06 || opswitch == 0x16) && RSREG == 0) + desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; + else + { + desc.regin[0] |= REGFLAG_R(RSREG); + desc.flags |= OPFLAG_IS_CONDITIONAL_BRANCH; + } + desc.targetpc = desc.pc + 4 + SIMMVAL * 4; + desc.delayslots = 1; + desc.skipslots = (opswitch & 0x10) ? 1 : 0; + return true; + + case 0x08: // ADDI + case 0x18: // DADDI + desc.regin[0] |= REGFLAG_R(RSREG); + desc.regout[0] |= REGFLAG_R(RTREG); + desc.flags |= OPFLAG_CAN_CAUSE_EXCEPTION; + return true; + + case 0x09: // ADDIU + case 0x0a: // SLTI + case 0x0b: // SLTIU + case 0x0c: // ANDI + case 0x0d: // ORI + case 0x0e: // XORI + case 0x19: // DADDIU + desc.regin[0] |= REGFLAG_R(RSREG); + desc.regout[0] |= REGFLAG_R(RTREG); + return true; + + case 0x0f: // LUI + desc.regout[0] |= REGFLAG_R(RTREG); + return true; + + case 0x1a: // LDL + case 0x1b: // LDR + case 0x22: // LWL + case 0x26: // LWR + desc.regin[0] |= REGFLAG_R(RTREG); + case 0x20: // LB + case 0x21: // LH + case 0x23: // LW + case 0x24: // LBU + case 0x25: // LHU + case 0x27: // LWU + case 0x30: // LL + case 0x34: // LLD + case 0x37: // LD + desc.regin[0] |= REGFLAG_R(RSREG); + desc.regout[0] |= REGFLAG_R(RTREG); + desc.flags |= OPFLAG_READS_MEMORY | OPFLAG_CAN_CAUSE_EXCEPTION; + return true; + + case 0x28: // SB + case 0x29: // SH + case 0x2a: // SWL + case 0x2b: // SW + case 0x2c: // SDL + case 0x2d: // SDR + case 0x2e: // SWR + case 0x3f: // SD + desc.regin[0] |= REGFLAG_R(RSREG) | REGFLAG_R(RTREG); + desc.flags |= OPFLAG_WRITES_MEMORY | OPFLAG_CAN_CAUSE_EXCEPTION; + return true; + + case 0x38: // SC + case 0x3c: // SCD + desc.regin[0] |= REGFLAG_R(RSREG) | REGFLAG_R(RTREG); + desc.regout[0] |= REGFLAG_R(RTREG); + desc.flags |= OPFLAG_WRITES_MEMORY | OPFLAG_CAN_CAUSE_EXCEPTION; + return true; + + case 0x31: // LWC1 + case 0x35: // LDC1 + desc.regin[0] |= REGFLAG_R(RSREG); + desc.regout[1] |= REGFLAG_CPR1(RTREG); + desc.flags |= OPFLAG_READS_MEMORY | OPFLAG_CAN_CAUSE_EXCEPTION; + return true; + + case 0x39: // SWC1 + case 0x3d: // SDC1 + desc.regin[0] |= REGFLAG_R(RSREG); + desc.regin[1] |= REGFLAG_CPR1(RTREG); + desc.flags |= OPFLAG_WRITES_MEMORY | OPFLAG_CAN_CAUSE_EXCEPTION; + return true; + + case 0x32: // LWC2 + case 0x36: // LDC2 + desc.regin[0] |= REGFLAG_R(RSREG); + desc.flags |= OPFLAG_READS_MEMORY | OPFLAG_CAN_CAUSE_EXCEPTION; + return true; + + case 0x3a: // SWC2 + case 0x3e: // SDC2 + desc.regin[0] |= REGFLAG_R(RSREG); + desc.flags |= OPFLAG_WRITES_MEMORY | OPFLAG_CAN_CAUSE_EXCEPTION; + return true; + + case 0x33: // PREF + if (m_mips3->m_flavor < mips3_device::MIPS3_TYPE_MIPS_IV) + return false; + case 0x2f: // CACHE + // effective no-op + return true; + } + + return false; +} + + +//------------------------------------------------- +// describe_special - build a description of a +// single instruction in the 'special' group +//------------------------------------------------- + +bool mips3_frontend::describe_special(UINT32 op, opcode_desc &desc) +{ + switch (op & 63) + { + case 0x00: // SLL + case 0x02: // SRL + case 0x03: // SRA + case 0x38: // DSLL + case 0x3a: // DSRL + case 0x3b: // DSRA + case 0x3c: // DSLL32 + case 0x3e: // DSRL32 + case 0x3f: // DSRA32 + desc.regin[0] |= REGFLAG_R(RTREG); + desc.regout[0] |= REGFLAG_R(RDREG); + return true; + + case 0x0a: // MOVZ - MIPS IV + case 0x0b: // MOVN - MIPS IV + if (m_mips3->m_flavor < mips3_device::MIPS3_TYPE_MIPS_IV) + return false; + desc.regin[0] |= REGFLAG_R(RDREG); + case 0x04: // SLLV + case 0x06: // SRLV + case 0x07: // SRAV + case 0x14: // DSLLV + case 0x16: // DSRLV + case 0x17: // DSRAV + case 0x21: // ADDU + case 0x23: // SUBU + case 0x24: // AND + case 0x25: // OR + case 0x26: // XOR + case 0x27: // NOR + case 0x2a: // SLT + case 0x2b: // SLTU + case 0x2d: // DADDU + case 0x2f: // DSUBU + desc.regin[0] |= REGFLAG_R(RSREG) | REGFLAG_R(RTREG); + desc.regout[0] |= REGFLAG_R(RDREG); + return true; + + case 0x20: // ADD + case 0x22: // SUB + case 0x2c: // DADD + case 0x2e: // DSUB + desc.regin[0] |= REGFLAG_R(RSREG) | REGFLAG_R(RTREG); + desc.regout[0] |= REGFLAG_R(RDREG); + desc.flags |= OPFLAG_CAN_CAUSE_EXCEPTION; + return true; + + case 0x30: // TGE + case 0x31: // TGEU + case 0x32: // TLT + case 0x33: // TLTU + case 0x34: // TEQ + case 0x36: // TNE + desc.regin[0] |= REGFLAG_R(RSREG) | REGFLAG_R(RTREG); + desc.flags |= OPFLAG_CAN_CAUSE_EXCEPTION; + return true; + + case 0x01: // MOVF - MIPS IV + if (m_mips3->m_flavor < mips3_device::MIPS3_TYPE_MIPS_IV) + return false; + desc.regin[0] |= REGFLAG_R(RSREG); + desc.regin[2] |= REGFLAG_FCC; + desc.regout[0] |= REGFLAG_R(RDREG); + return true; + + case 0x08: // JR + desc.regin[0] |= REGFLAG_R(RSREG); + desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; + desc.targetpc = BRANCH_TARGET_DYNAMIC; + desc.delayslots = 1; + return true; + + case 0x09: // JALR + desc.regin[0] |= REGFLAG_R(RSREG); + desc.regout[0] |= REGFLAG_R(RDREG); + desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; + desc.targetpc = BRANCH_TARGET_DYNAMIC; + desc.delayslots = 1; + return true; + + case 0x10: // MFHI + desc.regin[0] |= REGFLAG_HI; + desc.regout[0] |= REGFLAG_R(RDREG); + return true; + + case 0x11: // MTHI + desc.regin[0] |= REGFLAG_R(RSREG); + desc.regout[0] |= REGFLAG_HI; + return true; + + case 0x12: // MFLO + desc.regin[2] |= REGFLAG_LO; + desc.regout[0] |= REGFLAG_R(RDREG); + return true; + + case 0x13: // MTLO + desc.regin[0] |= REGFLAG_R(RSREG); + desc.regout[2] |= REGFLAG_LO; + return true; + + case 0x18: // MULT + case 0x19: // MULTU + desc.regin[0] |= REGFLAG_R(RSREG) | REGFLAG_R(RTREG); + desc.regout[2] |= REGFLAG_LO | REGFLAG_HI; + desc.cycles = 3; + return true; + + case 0x1a: // DIV + case 0x1b: // DIVU + desc.regin[0] |= REGFLAG_R(RSREG) | REGFLAG_R(RTREG); + desc.regout[2] |= REGFLAG_LO | REGFLAG_HI; + desc.cycles = 35; + return true; + + case 0x1c: // DMULT + case 0x1d: // DMULTU + desc.regin[0] |= REGFLAG_R(RSREG) | REGFLAG_R(RTREG); + desc.regout[2] |= REGFLAG_LO | REGFLAG_HI; + desc.cycles = 7; + return true; + + case 0x1e: // DDIV + case 0x1f: // DDIVU + desc.regin[0] |= REGFLAG_R(RSREG) | REGFLAG_R(RTREG); + desc.regout[2] |= REGFLAG_LO | REGFLAG_HI; + desc.cycles = 67; + return true; + + case 0x0c: // SYSCALL + case 0x0d: // BREAK + desc.flags |= OPFLAG_WILL_CAUSE_EXCEPTION | OPFLAG_END_SEQUENCE; + return true; + + case 0x0f: // SYNC + // effective no-op + return true; + } + + return false; +} + + +//------------------------------------------------- +// describe_regimm - build a description of a +// single instruction in the 'regimm' group +//------------------------------------------------- + +bool mips3_frontend::describe_regimm(UINT32 op, opcode_desc &desc) +{ + switch (RTREG) + { + case 0x00: // BLTZ + case 0x01: // BGEZ + case 0x02: // BLTZL + case 0x03: // BGEZL + if (RTREG == 0x01 && RSREG == 0) + desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; + else + { + desc.regin[0] |= REGFLAG_R(RSREG); + desc.flags |= OPFLAG_IS_CONDITIONAL_BRANCH; + } + desc.targetpc = desc.pc + 4 + SIMMVAL * 4; + desc.delayslots = 1; + desc.skipslots = (RTREG & 0x02) ? 1 : 0; + return true; + + case 0x08: // TGEI + case 0x09: // TGEIU + case 0x0a: // TLTI + case 0x0b: // TLTIU + case 0x0c: // TEQI + case 0x0e: // TNEI + desc.regin[0] |= REGFLAG_R(RSREG); + desc.flags |= OPFLAG_CAN_CAUSE_EXCEPTION; + return true; + + case 0x10: // BLTZAL + case 0x11: // BGEZAL + case 0x12: // BLTZALL + case 0x13: // BGEZALL + if (RTREG == 0x11 && RSREG == 0) + desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; + else + { + desc.regin[0] |= REGFLAG_R(RSREG); + desc.flags |= OPFLAG_IS_CONDITIONAL_BRANCH; + } + desc.regout[0] |= REGFLAG_R(31); + desc.targetpc = desc.pc + 4 + SIMMVAL * 4; + desc.delayslots = 1; + desc.skipslots = (RTREG & 0x02) ? 1 : 0; + return true; + } + + return false; +} + + +//------------------------------------------------- +// describe_idt - build a description of a single +// instruction in the IDT-specific group +//------------------------------------------------- + +bool mips3_frontend::describe_idt(UINT32 op, opcode_desc &desc) +{ + // only on the R4650 + if (m_mips3->m_flavor != mips3_device::MIPS3_TYPE_R4650) + return false; + + switch (op & 0x1f) + { + case 0: // MAD + case 1: // MADU + desc.regin[0] |= REGFLAG_R(RSREG) | REGFLAG_R(RTREG); + desc.regin[2] |= REGFLAG_LO | REGFLAG_HI; + desc.regout[2] |= REGFLAG_LO | REGFLAG_HI; + return true; + + case 2: // MUL + desc.regin[0] |= REGFLAG_R(RSREG) | REGFLAG_R(RTREG); + desc.regout[0] |= REGFLAG_R(RDREG); + desc.cycles = 3; + return true; + } + + return false; +} + + +//------------------------------------------------- +// describe_cop0 - build a description of a +// single instruction in the COP0 group +//------------------------------------------------- + +bool mips3_frontend::describe_cop0(UINT32 op, opcode_desc &desc) +{ + // any COP0 instruction can potentially cause an exception + desc.flags |= OPFLAG_CAN_CAUSE_EXCEPTION; + + switch (RSREG) + { + case 0x00: // MFCz + case 0x01: // DMFCz + if (RDREG == COP0_Count) + desc.cycles += MIPS3_COUNT_READ_CYCLES; + if (RDREG == COP0_Cause) + desc.cycles += MIPS3_CAUSE_READ_CYCLES; + desc.regout[0] |= REGFLAG_R(RTREG); + return true; + + case 0x02: // CFCz + desc.regout[0] |= REGFLAG_R(RTREG); + return true; + + case 0x04: // MTCz + case 0x05: // DMTCz + case 0x06: // CTCz + desc.regin[0] |= REGFLAG_R(RTREG); + if (RSREG == 0x04 || RSREG == 0x05) + { + if (RDREG == COP0_Cause) + desc.flags |= OPFLAG_CAN_TRIGGER_SW_INT; + if (RDREG == COP0_Status) + desc.flags |= OPFLAG_CAN_EXPOSE_EXTERNAL_INT | OPFLAG_CAN_CHANGE_MODES | OPFLAG_END_SEQUENCE; + } + return true; + + case 0x08: // BC + switch (RTREG) + { + case 0x00: // BCzF + case 0x01: // BCzT + desc.flags |= OPFLAG_IS_CONDITIONAL_BRANCH; + desc.targetpc = desc.pc + 4 + SIMMVAL * 4; + desc.delayslots = 1; + return true; + } + return false; + + case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17: + case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f: // COP + switch (op & 0x01ffffff) + { + case 0x01: // TLBR + case 0x08: // TLBP + case 0x20: // WAIT + return true; + + case 0x02: // TLBWI + case 0x06: // TLBWR + desc.flags |= OPFLAG_MODIFIES_TRANSLATION; + return true; + + case 0x18: // ERET + desc.flags |= OPFLAG_CAN_CHANGE_MODES | OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; + return true; + } + return false; + } + + return false; +} + + +//------------------------------------------------- +// describe_cop1 - build a description of a +// single instruction in the COP1 group +//------------------------------------------------- + +bool mips3_frontend::describe_cop1(UINT32 op, opcode_desc &desc) +{ + // any COP1 instruction can potentially cause an exception +// desc.flags |= OPFLAG_CAN_CAUSE_EXCEPTION; + + switch (RSREG) + { + case 0x00: // MFCz + case 0x01: // DMFCz + desc.regin[1] |= REGFLAG_CPR1(RDREG); + desc.regout[0] |= REGFLAG_R(RTREG); + return true; + + case 0x02: // CFCz + desc.regout[0] |= REGFLAG_R(RTREG); + return true; + + case 0x04: // MTCz + case 0x05: // DMTCz + desc.regin[0] |= REGFLAG_R(RTREG); + desc.regout[1] |= REGFLAG_CPR1(RDREG); + return true; + + case 0x06: // CTCz + desc.regin[0] |= REGFLAG_R(RTREG); + return true; + + case 0x08: // BC + switch (RTREG & 3) + { + case 0x00: // BCzF + case 0x01: // BCzT + case 0x02: // BCzFL + case 0x03: // BCzTL + desc.regin[2] |= REGFLAG_FCC; + desc.flags |= OPFLAG_IS_CONDITIONAL_BRANCH; + desc.targetpc = desc.pc + 4 + SIMMVAL * 4; + desc.delayslots = 1; + desc.skipslots = (RTREG & 0x02) ? 1 : 0; + return true; + } + return false; + + case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17: + case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f: // COP + switch (op & 0x3f) + { + case 0x12: // MOVZ - MIPS IV + case 0x13: // MOVN - MIPS IV + if (m_mips3->m_flavor < mips3_device::MIPS3_TYPE_MIPS_IV) + return false; + case 0x00: // ADD + case 0x01: // SUB + case 0x02: // MUL + case 0x03: // DIV + desc.regin[1] |= REGFLAG_CPR1(FSREG) | REGFLAG_CPR1(FTREG); + desc.regout[1] |= REGFLAG_CPR1(FDREG); + return true; + + case 0x15: // RECIP - MIPS IV + case 0x16: // RSQRT - MIPS IV + if (m_mips3->m_flavor < mips3_device::MIPS3_TYPE_MIPS_IV) + return false; + case 0x04: // SQRT + case 0x05: // ABS + case 0x06: // MOV + case 0x07: // NEG + case 0x08: // ROUND.L + case 0x09: // TRUNC.L + case 0x0a: // CEIL.L + case 0x0b: // FLOOR.L + case 0x0c: // ROUND.W + case 0x0d: // TRUNC.W + case 0x0e: // CEIL.W + case 0x0f: // FLOOR.W + case 0x20: // CVT.S + case 0x21: // CVT.D + case 0x24: // CVT.W + case 0x25: // CVT.L + desc.regin[1] |= REGFLAG_CPR1(FSREG); + desc.regout[1] |= REGFLAG_CPR1(FDREG); + return true; + + case 0x11: // MOVT/F - MIPS IV + if (m_mips3->m_flavor < mips3_device::MIPS3_TYPE_MIPS_IV) + return false; + desc.regin[1] |= REGFLAG_CPR1(FSREG); + desc.regin[2] |= REGFLAG_FCC; + desc.regout[1] |= REGFLAG_CPR1(FDREG); + return true; + + case 0x30: case 0x38: // C.F + case 0x31: case 0x39: // C.UN + desc.regout[2] |= REGFLAG_FCC; + return true; + + case 0x32: case 0x3a: // C.EQ + case 0x33: case 0x3b: // C.UEQ + case 0x34: case 0x3c: // C.OLT + case 0x35: case 0x3d: // C.ULT + case 0x36: case 0x3e: // C.OLE + case 0x37: case 0x3f: // C.ULE + desc.regin[1] |= REGFLAG_CPR1(FSREG) | REGFLAG_CPR1(FTREG); + desc.regout[2] |= REGFLAG_FCC; + return true; + } + return false; + } + + return false; +} + + +//------------------------------------------------- +// describe_cop1x - build a description of a +// single instruction in the COP1X group +//------------------------------------------------- + +bool mips3_frontend::describe_cop1x(UINT32 op, opcode_desc &desc) +{ + // any COP1 instruction can potentially cause an exception +// desc.flags |= OPFLAG_CAN_CAUSE_EXCEPTION; + + switch (op & 0x3f) + { + case 0x00: // LWXC1 + case 0x01: // LDXC1 + desc.regin[0] |= REGFLAG_R(RSREG) | REGFLAG_R(RTREG); + desc.regout[1] |= REGFLAG_CPR1(FDREG); + desc.flags |= OPFLAG_READS_MEMORY; + return true; + + case 0x08: // SWXC1 + case 0x09: // SDXC1 + desc.regin[0] |= REGFLAG_R(RSREG) | REGFLAG_R(RTREG); + desc.regin[1] |= REGFLAG_CPR1(FDREG); + desc.flags |= OPFLAG_WRITES_MEMORY; + return true; + + case 0x0f: // PREFX + // effective no-op + return true; + + case 0x20: case 0x21: // MADD + case 0x28: case 0x29: // MSUB + case 0x30: case 0x31: // NMADD + case 0x38: case 0x39: // NMSUB + desc.regin[1] |= REGFLAG_CPR1(FSREG) | REGFLAG_CPR1(FTREG) | REGFLAG_CPR1(FRREG); + desc.regout[1] |= REGFLAG_CPR1(FDREG); + return true; + } + + return false; +} + + +//------------------------------------------------- +// describe_cop2 - build a description of a +// single instruction in the COP2 group +//------------------------------------------------- + +bool mips3_frontend::describe_cop2(UINT32 op, opcode_desc &desc) +{ + // any COP2 instruction can potentially cause an exception + desc.flags |= OPFLAG_CAN_CAUSE_EXCEPTION; + + switch (RSREG) + { + case 0x00: // MFCz + case 0x01: // DMFCz + case 0x02: // CFCz + desc.regout[0] |= REGFLAG_R(RTREG); + return true; + + case 0x04: // MTCz + case 0x05: // DMTCz + case 0x06: // CTCz + desc.regin[0] |= REGFLAG_R(RTREG); + return true; + + case 0x08: // BC + switch (RTREG) + { + case 0x00: // BCzF + case 0x01: // BCzT + desc.flags |= OPFLAG_IS_CONDITIONAL_BRANCH; + desc.targetpc = desc.pc + 4 + SIMMVAL * 4; + desc.delayslots = 1; + return true; + } + return false; + } + + return false; +} diff --git a/src/devices/cpu/mips/mips3fe.h b/src/devices/cpu/mips/mips3fe.h new file mode 100644 index 00000000000..15e90c922e0 --- /dev/null +++ b/src/devices/cpu/mips/mips3fe.h @@ -0,0 +1,33 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + mips3fe.h + + Front-end for MIPS3 recompiler + +***************************************************************************/ + +#pragma once + +#ifndef __MIPS3FE_H__ +#define __MIPS3FE_H__ + + +//************************************************************************** +// MACROS +//************************************************************************** + +// register flags 0 +#define REGFLAG_R(n) (((n) == 0) ? 0 : (1 << (n))) + +// register flags 1 +#define REGFLAG_CPR1(n) (1 << (n)) + +// register flags 2 +#define REGFLAG_LO (1 << 0) +#define REGFLAG_HI (1 << 1) +#define REGFLAG_FCC (1 << 2) + + +#endif /* __MIPS3FE_H__ */ diff --git a/src/devices/cpu/mips/r3000.c b/src/devices/cpu/mips/r3000.c new file mode 100644 index 00000000000..1b64e05799c --- /dev/null +++ b/src/devices/cpu/mips/r3000.c @@ -0,0 +1,1347 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + r3000.c + Core implementation for the portable MIPS R3000 emulator. + Written by Aaron Giles + +***************************************************************************/ + +#include "emu.h" +#include "debugger.h" +#include "r3000.h" + + +#define ENABLE_OVERFLOWS 0 + + +/*************************************************************************** + CONSTANTS +***************************************************************************/ + +#define COP0_Index 0 +#define COP0_Random 1 +#define COP0_EntryLo 2 +#define COP0_Context 4 +#define COP0_BadVAddr 8 +#define COP0_Status 12 +#define COP0_Cause 13 +#define COP0_EPC 14 +#define COP0_PRId 15 + +#define SR_IEc 0x00000001 +#define SR_KUc 0x00000002 +#define SR_IEp 0x00000004 +#define SR_KUp 0x00000008 +#define SR_IEo 0x00000010 +#define SR_KUo 0x00000020 +#define SR_IMSW0 0x00000100 +#define SR_IMSW1 0x00000200 +#define SR_IMEX0 0x00000400 +#define SR_IMEX1 0x00000800 +#define SR_IMEX2 0x00001000 +#define SR_IMEX3 0x00002000 +#define SR_IMEX4 0x00004000 +#define SR_IMEX5 0x00008000 +#define SR_IsC 0x00010000 +#define SR_SwC 0x00020000 +#define SR_PZ 0x00040000 +#define SR_CM 0x00080000 +#define SR_PE 0x00100000 +#define SR_TS 0x00200000 +#define SR_BEV 0x00400000 +#define SR_RE 0x02000000 +#define SR_COP0 0x10000000 +#define SR_COP1 0x20000000 +#define SR_COP2 0x40000000 +#define SR_COP3 0x80000000 + +#define EXCEPTION_INTERRUPT 0 +#define EXCEPTION_TLBMOD 1 +#define EXCEPTION_TLBLOAD 2 +#define EXCEPTION_TLBSTORE 3 +#define EXCEPTION_ADDRLOAD 4 +#define EXCEPTION_ADDRSTORE 5 +#define EXCEPTION_BUSINST 6 +#define EXCEPTION_BUSDATA 7 +#define EXCEPTION_SYSCALL 8 +#define EXCEPTION_BREAK 9 +#define EXCEPTION_INVALIDOP 10 +#define EXCEPTION_BADCOP 11 +#define EXCEPTION_OVERFLOW 12 +#define EXCEPTION_TRAP 13 + + +/*************************************************************************** + HELPER MACROS +***************************************************************************/ + +#define RSREG ((m_op >> 21) & 31) +#define RTREG ((m_op >> 16) & 31) +#define RDREG ((m_op >> 11) & 31) +#define SHIFT ((m_op >> 6) & 31) + +#define RSVAL m_r[RSREG] +#define RTVAL m_r[RTREG] +#define RDVAL m_r[RDREG] + +#define SIMMVAL ((INT16)m_op) +#define UIMMVAL ((UINT16)m_op) +#define LIMMVAL (m_op & 0x03ffffff) + +#define ADDPC(x) do { m_nextpc = m_pc + ((x) << 2); } while (0) +#define ADDPCL(x,l) do { m_nextpc = m_pc + ((x) << 2); m_r[l] = m_pc + 4; } while (0) +#define ABSPC(x) do { m_nextpc = (m_pc & 0xf0000000) | ((x) << 2); } while (0) +#define ABSPCL(x,l) do { m_nextpc = (m_pc & 0xf0000000) | ((x) << 2); m_r[l] = m_pc + 4; } while (0) +#define SETPC(x) do { m_nextpc = (x); } while (0) +#define SETPCL(x,l) do { m_nextpc = (x); m_r[l] = m_pc + 4; } while (0) + +#define RBYTE(x) (this->*m_cur->m_read_byte)(x) +#define RWORD(x) (this->*m_cur->m_read_word)(x) +#define RLONG(x) (this->*m_cur->m_read_dword)(x) + +#define WBYTE(x,v) (this->*m_cur->m_write_byte)(x, v) +#define WWORD(x,v) (this->*m_cur->m_write_word)(x, v) +#define WLONG(x,v) (this->*m_cur->m_write_dword)(x, v) + +#define SR m_cpr[0][COP0_Status] +#define CAUSE m_cpr[0][COP0_Cause] + + +//************************************************************************** +// DEVICE INTERFACE +//************************************************************************** + +const device_type R3041 = &device_creator; +const device_type R3051 = &device_creator; +const device_type R3052 = &device_creator; +const device_type R3071 = &device_creator; +const device_type R3081 = &device_creator; + + +//------------------------------------------------- +// r3000_device - constructor +//------------------------------------------------- + +r3000_device::r3000_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, chip_type chiptype, const char *shortname, const char *source) + : cpu_device(mconfig, type, name, tag, owner, clock, shortname, source), + m_program_config_be("program", ENDIANNESS_BIG, 32, 29), + m_program_config_le("program", ENDIANNESS_LITTLE, 32, 29), + m_program(NULL), + m_direct(NULL), + m_chip_type(chiptype), + m_hasfpu(false), + m_endianness(ENDIANNESS_BIG), + m_pc(0), + m_nextpc(0), + m_hi(0), + m_lo(0), + m_ppc(0), + m_op(0), + m_icount(0), + m_interrupt_cycles(0), + m_in_brcond0(*this), + m_in_brcond1(*this), + m_in_brcond2(*this), + m_in_brcond3(*this) +{ + // set our instruction counter + m_icountptr = &m_icount; + + // clear some additional state + memset(m_r, 0, sizeof(m_r)); + memset(m_cpr, 0, sizeof(m_cpr)); + memset(m_ccr, 0, sizeof(m_ccr)); +} + + +//------------------------------------------------- +// ~r3000_device - destructor +//------------------------------------------------- + +r3000_device::~r3000_device() +{ +} + + +//------------------------------------------------- +// r3041_device - constructor +//------------------------------------------------- + +r3041_device::r3041_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : r3000_device(mconfig, R3041, "R3041", tag, owner, clock, CHIP_TYPE_R3041, "r3041", __FILE__) { } + + +//------------------------------------------------- +// r3051_device - constructor +//------------------------------------------------- + +r3051_device::r3051_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : r3000_device(mconfig, R3051, "R3051", tag, owner, clock, CHIP_TYPE_R3051, "r3051", __FILE__) { } + + +//------------------------------------------------- +// r3052_device - constructor +//------------------------------------------------- + +r3052_device::r3052_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : r3000_device(mconfig, R3052, "R3052", tag, owner, clock, CHIP_TYPE_R3052, "r3052", __FILE__) { } + + +//------------------------------------------------- +// r3071_device - constructor +//------------------------------------------------- + +r3071_device::r3071_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : r3000_device(mconfig, R3071, "R3071", tag, owner, clock, CHIP_TYPE_R3071, "r3071", __FILE__) { } + + +//------------------------------------------------- +// r3081_device - constructor +//------------------------------------------------- + +r3081_device::r3081_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : r3000_device(mconfig, R3081, "R3081", tag, owner, clock, CHIP_TYPE_R3081, "r3081", __FILE__) { } + + +//------------------------------------------------- +// device_start - start up the device +//------------------------------------------------- + +void r3000_device::device_start() +{ + // get our address spaces + m_program = &space(AS_PROGRAM); + m_direct = &m_program->direct(); + + // determine the cache sizes + switch (m_chip_type) + { + case CHIP_TYPE_R3041: + { + m_icache_size = 2048; + m_dcache_size = 512; + break; + } + case CHIP_TYPE_R3051: + { + m_icache_size = 4096; + m_dcache_size = 2048; + break; + } + case CHIP_TYPE_R3052: + { + m_icache_size = 8192; + m_dcache_size = 2048; + break; + } + + // TODO: R3071 and R3081 have configurable cache sizes + case CHIP_TYPE_R3071: + { + m_icache_size = 16384; // or 8kB + m_dcache_size = 4096; // or 8kB + break; + } + case CHIP_TYPE_R3081: + { + m_icache_size = 16384; // or 8kB + m_dcache_size = 4096; // or 8kB + m_hasfpu = true; + break; + } + } + + // allocate cache memory + m_icache.resize(m_icache_size/4); + m_dcache.resize(m_dcache_size/4); + + m_cache = &m_dcache[0]; + m_cache_size = m_dcache_size; + + // set up memory handlers + m_memory_hand.m_read_byte = &r3000_device::readmem; + m_memory_hand.m_read_word = &r3000_device::readmem_word; + m_memory_hand.m_read_dword = &r3000_device::readmem_dword; + m_memory_hand.m_write_byte = &r3000_device::writemem; + m_memory_hand.m_write_word = &r3000_device::writemem_word; + m_memory_hand.m_write_dword = &r3000_device::writemem_dword; + + if (m_endianness == ENDIANNESS_BIG) + { + m_lwl = &r3000_device::lwl_be; + m_lwr = &r3000_device::lwr_be; + m_swl = &r3000_device::swl_be; + m_swr = &r3000_device::swr_be; + + m_cache_hand.m_read_byte = &r3000_device::readcache_be; + m_cache_hand.m_read_word = &r3000_device::readcache_be_word; + m_cache_hand.m_read_dword = &r3000_device::readcache_be_dword; + m_cache_hand.m_write_byte = &r3000_device::writecache_be; + m_cache_hand.m_write_word = &r3000_device::writecache_be_word; + m_cache_hand.m_write_dword = &r3000_device::writecache_be_dword; + } + else + { + m_lwl = &r3000_device::lwl_le; + m_lwr = &r3000_device::lwr_le; + m_swl = &r3000_device::swl_le; + m_swr = &r3000_device::swr_le; + + m_cache_hand.m_read_byte = &r3000_device::readcache_le; + m_cache_hand.m_read_word = &r3000_device::readcache_le_word; + m_cache_hand.m_read_dword = &r3000_device::readcache_le_dword; + m_cache_hand.m_write_byte = &r3000_device::writecache_le; + m_cache_hand.m_write_word = &r3000_device::writecache_le_word; + m_cache_hand.m_write_dword = &r3000_device::writecache_le_dword; + } + + // resolve conditional branch input handlers + m_in_brcond0.resolve_safe(0); + m_in_brcond1.resolve_safe(0); + m_in_brcond2.resolve_safe(0); + m_in_brcond3.resolve_safe(0); + + // register our state for the debugger + state_add(STATE_GENPC, "GENPC", m_pc).noshow(); + state_add(STATE_GENPCBASE, "GENPCBASE", m_ppc).noshow(); + state_add(STATE_GENSP, "GENSP", m_r[31]).noshow(); + state_add(STATE_GENFLAGS, "GENFLAGS", SR).callimport().callexport().formatstr("%6s").noshow(); + state_add(R3000_PC, "PC", m_pc); + state_add(R3000_SR, "SR", SR); + state_add(R3000_R0, "R0", m_r[0]); + state_add(R3000_R1, "R1", m_r[1]); + state_add(R3000_R2, "R2", m_r[2]); + state_add(R3000_R3, "R3", m_r[3]); + state_add(R3000_R4, "R4", m_r[4]); + state_add(R3000_R5, "R5", m_r[5]); + state_add(R3000_R6, "R6", m_r[6]); + state_add(R3000_R7, "R7", m_r[7]); + state_add(R3000_R8, "R8", m_r[8]); + state_add(R3000_R9, "R9", m_r[9]); + state_add(R3000_R10, "R10", m_r[10]); + state_add(R3000_R11, "R11", m_r[11]); + state_add(R3000_R12, "R12", m_r[12]); + state_add(R3000_R13, "R13", m_r[13]); + state_add(R3000_R14, "R14", m_r[14]); + state_add(R3000_R15, "R15", m_r[15]); + state_add(R3000_R16, "R16", m_r[16]); + state_add(R3000_R17, "R17", m_r[17]); + state_add(R3000_R18, "R18", m_r[18]); + state_add(R3000_R19, "R19", m_r[19]); + state_add(R3000_R20, "R20", m_r[20]); + state_add(R3000_R21, "R21", m_r[21]); + state_add(R3000_R22, "R22", m_r[22]); + state_add(R3000_R23, "R23", m_r[23]); + state_add(R3000_R24, "R24", m_r[24]); + state_add(R3000_R25, "R25", m_r[25]); + state_add(R3000_R26, "R26", m_r[26]); + state_add(R3000_R27, "R27", m_r[27]); + state_add(R3000_R28, "R28", m_r[28]); + state_add(R3000_R29, "R29", m_r[29]); + state_add(R3000_R30, "R30", m_r[30]); + state_add(R3000_R31, "R31", m_r[31]); + + // register our state for saving + save_item(NAME(m_pc)); + save_item(NAME(m_nextpc)); + save_item(NAME(m_hi)); + save_item(NAME(m_lo)); + save_item(NAME(m_r)); + save_item(NAME(m_cpr)); + save_item(NAME(m_ccr)); + save_item(NAME(m_ppc)); + save_item(NAME(m_op)); + save_item(NAME(m_interrupt_cycles)); + save_item(NAME(m_icache)); + save_item(NAME(m_dcache)); +} + + +//------------------------------------------------- +// device_post_load - +//------------------------------------------------- +void r3000_device::device_post_load() +{ + if (m_cpr[0][COP0_Status] & SR_IsC) + m_cur = &m_cache_hand; + else + m_cur = &m_memory_hand; +} + + +//------------------------------------------------- +// device_reset - reset the device +//------------------------------------------------- + +void r3000_device::device_reset() +{ + // initialize the rest of the config + m_cur = &m_memory_hand; + + // initialize the state + m_pc = 0xbfc00000; + m_nextpc = ~0; + m_cpr[0][COP0_PRId] = 0x0200; + m_cpr[0][COP0_Status] = 0x0000; +} + + +//------------------------------------------------- +// memory_space_config - return the configuration +// of the specified address space, or NULL if +// the space doesn't exist +//------------------------------------------------- + +const address_space_config *r3000_device::memory_space_config(address_spacenum spacenum) const +{ + if (spacenum == AS_PROGRAM) + return (m_endianness == ENDIANNESS_BIG) ? &m_program_config_be : &m_program_config_le; + else + return NULL; +} + + +//------------------------------------------------- +// state_import - import state into the device, +// after it has been set +//------------------------------------------------- + +void r3000_device::state_import(const device_state_entry &entry) +{ + switch (entry.index()) + { + case STATE_GENFLAGS: + break; + + default: + fatalerror("r3000_device::state_import called for unexpected value\n"); + } +} + + +//------------------------------------------------- +// state_export - export state out of the device +//------------------------------------------------- + +void r3000_device::state_export(const device_state_entry &entry) +{ + switch (entry.index()) + { + case STATE_GENFLAGS: + break; + + default: + fatalerror("r3000_device::state_export called for unexpected value\n"); + } +} + + +//------------------------------------------------- +// state_string_export - export state as a string +// for the debugger +//------------------------------------------------- + +void r3000_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + switch (entry.index()) + { + case STATE_GENFLAGS: + break; + } +} + + +//------------------------------------------------- +// disasm_min_opcode_bytes - return the length +// of the shortest instruction, in bytes +//------------------------------------------------- + +UINT32 r3000_device::disasm_min_opcode_bytes() const +{ + return 4; +} + + +//------------------------------------------------- +// disasm_max_opcode_bytes - return the length +// of the longest instruction, in bytes +//------------------------------------------------- + +UINT32 r3000_device::disasm_max_opcode_bytes() const +{ + return 4; +} + + +//------------------------------------------------- +// disasm_disassemble - call the disassembly +// helper function +//------------------------------------------------- + +offs_t r3000_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( r3000le ); + extern CPU_DISASSEMBLE( r3000be ); + + if (m_endianness == ENDIANNESS_BIG) + return CPU_DISASSEMBLE_NAME(r3000be)(this, buffer, pc, oprom, opram, options); + else + return CPU_DISASSEMBLE_NAME(r3000le)(this, buffer, pc, oprom, opram, options); +} + + +/*************************************************************************** + MEMORY ACCESSORS +***************************************************************************/ + +inline UINT32 r3000_device::readop(offs_t pc) +{ + return m_direct->read_dword(pc); +} + +UINT8 r3000_device::readmem(offs_t offset) +{ + return m_program->read_byte(offset); +} + +UINT16 r3000_device::readmem_word(offs_t offset) +{ + return m_program->read_word(offset); +} + +UINT32 r3000_device::readmem_dword(offs_t offset) +{ + return m_program->read_dword(offset); +} + +void r3000_device::writemem(offs_t offset, UINT8 data) +{ + m_program->write_byte(offset, data); +} + +void r3000_device::writemem_word(offs_t offset, UINT16 data) +{ + m_program->write_word(offset, data); +} + +void r3000_device::writemem_dword(offs_t offset, UINT32 data) +{ + m_program->write_dword(offset, data); +} + + +/*************************************************************************** + BIG ENDIAN CACHE I/O +***************************************************************************/ + +UINT8 r3000_device::readcache_be(offs_t offset) +{ + offset &= 0x1fffffff; + return (offset * 4 < m_cache_size) ? m_cache[BYTE4_XOR_BE(offset)] : 0xff; +} + +UINT16 r3000_device::readcache_be_word(offs_t offset) +{ + offset &= 0x1fffffff; + return (offset * 4 < m_cache_size) ? *(UINT16 *)&m_cache[WORD_XOR_BE(offset)] : 0xffff; +} + +UINT32 r3000_device::readcache_be_dword(offs_t offset) +{ + offset &= 0x1fffffff; + return (offset * 4 < m_cache_size) ? *(UINT32 *)&m_cache[offset] : 0xffffffff; +} + +void r3000_device::writecache_be(offs_t offset, UINT8 data) +{ + offset &= 0x1fffffff; + if (offset * 4 < m_cache_size) m_cache[BYTE4_XOR_BE(offset)] = data; +} + +void r3000_device::writecache_be_word(offs_t offset, UINT16 data) +{ + offset &= 0x1fffffff; + if (offset * 4 < m_cache_size) *(UINT16 *)&m_cache[WORD_XOR_BE(offset)] = data; +} + +void r3000_device::writecache_be_dword(offs_t offset, UINT32 data) +{ + offset &= 0x1fffffff; + if (offset * 4 < m_cache_size) *(UINT32 *)&m_cache[offset] = data; +} + +UINT8 r3000_device::readcache_le(offs_t offset) +{ + offset &= 0x1fffffff; + return (offset * 4 < m_cache_size) ? m_cache[BYTE4_XOR_LE(offset)] : 0xff; +} + + +/*************************************************************************** + LITTLE ENDIAN CACHE I/O +***************************************************************************/ + +UINT16 r3000_device::readcache_le_word(offs_t offset) +{ + offset &= 0x1fffffff; + return (offset * 4 < m_cache_size) ? *(UINT16 *)&m_cache[WORD_XOR_LE(offset)] : 0xffff; +} + +UINT32 r3000_device::readcache_le_dword(offs_t offset) +{ + offset &= 0x1fffffff; + return (offset * 4 < m_cache_size) ? *(UINT32 *)&m_cache[offset] : 0xffffffff; +} + +void r3000_device::writecache_le(offs_t offset, UINT8 data) +{ + offset &= 0x1fffffff; + if (offset * 4 < m_cache_size) m_cache[BYTE4_XOR_LE(offset)] = data; +} + +void r3000_device::writecache_le_word(offs_t offset, UINT16 data) +{ + offset &= 0x1fffffff; + if (offset * 4 < m_cache_size) *(UINT16 *)&m_cache[WORD_XOR_LE(offset)] = data; +} + +void r3000_device::writecache_le_dword(offs_t offset, UINT32 data) +{ + offset &= 0x1fffffff; + if (offset * 4 < m_cache_size) *(UINT32 *)&m_cache[offset] = data; +} + + +/*************************************************************************** + EXECEPTION HANDLING +***************************************************************************/ + +inline void r3000_device::generate_exception(int exception) +{ + // set the exception PC + m_cpr[0][COP0_EPC] = m_pc; + + // put the cause in the low 8 bits and clear the branch delay flag + CAUSE = (CAUSE & ~0x800000ff) | (exception << 2); + + // if we were in a branch delay slot, adjust + if (m_nextpc != ~0) + { + m_nextpc = ~0; + m_cpr[0][COP0_EPC] -= 4; + CAUSE |= 0x80000000; + } + + // shift the exception bits + SR = (SR & 0xffffffc0) | ((SR << 2) & 0x3c); + + // based on the BEV bit, we either go to ROM or RAM + m_pc = (SR & SR_BEV) ? 0xbfc00000 : 0x80000000; + + // most exceptions go to offset 0x180, except for TLB stuff + if (exception >= EXCEPTION_TLBMOD && exception <= EXCEPTION_TLBSTORE) + m_pc += 0x80; + else + m_pc += 0x180; +} + + +inline void r3000_device::invalid_instruction() +{ + generate_exception(EXCEPTION_INVALIDOP); +} + + +/*************************************************************************** + IRQ HANDLING +***************************************************************************/ + +void r3000_device::check_irqs() +{ + if ((CAUSE & SR & 0xff00) && (SR & SR_IEc)) + generate_exception(EXCEPTION_INTERRUPT); +} + + +void r3000_device::set_irq_line(int irqline, int state) +{ + if (state != CLEAR_LINE) + CAUSE |= 0x400 << irqline; + else + CAUSE &= ~(0x400 << irqline); + + check_irqs(); +} + + +/*************************************************************************** + COP0 (SYSTEM) EXECUTION HANDLING +***************************************************************************/ + +inline UINT32 r3000_device::get_cop0_reg(int idx) +{ + return m_cpr[0][idx]; +} + +inline void r3000_device::set_cop0_reg(int idx, UINT32 val) +{ + if (idx == COP0_Cause) + { + CAUSE = (CAUSE & 0xfc00) | (val & ~0xfc00); + + // update interrupts -- software ints can occur this way + check_irqs(); + } + else if (idx == COP0_Status) + { + UINT32 oldsr = m_cpr[0][idx]; + UINT32 diff = oldsr ^ val; + + // handle cache isolation + if (diff & SR_IsC) + { + if (val & SR_IsC) + m_cur = &m_cache_hand; + else + m_cur = &m_memory_hand; + } + + // handle cache switching + if (diff & SR_SwC) + { + if (val & SR_SwC) + m_cache = &m_icache[0], m_cache_size = m_icache_size; + else + m_cache = &m_dcache[0], m_cache_size = m_dcache_size; + } + m_cpr[0][idx] = val; + + // update interrupts + check_irqs(); + } + else + m_cpr[0][idx] = val; +} + +inline UINT32 r3000_device::get_cop0_creg(int idx) +{ + return m_ccr[0][idx]; +} + +inline void r3000_device::set_cop0_creg(int idx, UINT32 val) +{ + m_ccr[0][idx] = val; +} + +inline void r3000_device::handle_cop0() +{ + if (!(SR & SR_COP0) && (SR & SR_KUc)) + generate_exception(EXCEPTION_BADCOP); + + switch (RSREG) + { + case 0x00: /* MFCz */ if (RTREG) RTVAL = get_cop0_reg(RDREG); break; + case 0x02: /* CFCz */ if (RTREG) RTVAL = get_cop0_creg(RDREG); break; + case 0x04: /* MTCz */ set_cop0_reg(RDREG, RTVAL); break; + case 0x06: /* CTCz */ set_cop0_creg(RDREG, RTVAL); break; + case 0x08: /* BC */ + switch (RTREG) + { + case 0x00: /* BCzF */ if (!m_in_brcond0()) ADDPC(SIMMVAL); break; + case 0x01: /* BCzT */ if (m_in_brcond0()) ADDPC(SIMMVAL); break; + case 0x02: /* BCzFL */ invalid_instruction(); break; + case 0x03: /* BCzTL */ invalid_instruction(); break; + default: invalid_instruction(); break; + } + break; + case 0x10: + case 0x11: + case 0x12: + case 0x13: + case 0x14: + case 0x15: + case 0x16: + case 0x17: + case 0x18: + case 0x19: + case 0x1a: + case 0x1b: + case 0x1c: + case 0x1d: + case 0x1e: + case 0x1f: /* COP */ + switch (m_op & 0x01ffffff) + { + case 0x01: /* TLBR */ break; + case 0x02: /* TLBWI */ break; + case 0x06: /* TLBWR */ break; + case 0x08: /* TLBP */ break; + case 0x10: /* RFE */ SR = (SR & 0xfffffff0) | ((SR >> 2) & 0x0f); break; + case 0x18: /* ERET */ invalid_instruction(); break; + default: invalid_instruction(); break; + } + break; + default: invalid_instruction(); break; + } +} + + +/*************************************************************************** + COP1 (FPU) EXECUTION HANDLING +***************************************************************************/ + +inline UINT32 r3000_device::get_cop1_reg(int idx) +{ + return m_cpr[1][idx]; +} + +inline void r3000_device::set_cop1_reg(int idx, UINT32 val) +{ + m_cpr[1][idx] = val; +} + +inline UINT32 r3000_device::get_cop1_creg(int idx) +{ + return m_ccr[1][idx]; +} + +inline void r3000_device::set_cop1_creg(int idx, UINT32 val) +{ + m_ccr[1][idx] = val; +} + +inline void r3000_device::handle_cop1() +{ + if (!(SR & SR_COP1)) + generate_exception(EXCEPTION_BADCOP); + if (!m_hasfpu) + return; + + switch (RSREG) + { + case 0x00: /* MFCz */ if (RTREG) RTVAL = get_cop1_reg(RDREG); break; + case 0x02: /* CFCz */ if (RTREG) RTVAL = get_cop1_creg(RDREG); break; + case 0x04: /* MTCz */ set_cop1_reg(RDREG, RTVAL); break; + case 0x06: /* CTCz */ set_cop1_creg(RDREG, RTVAL); break; + case 0x08: /* BC */ + switch (RTREG) + { + case 0x00: /* BCzF */ if (!m_in_brcond1()) ADDPC(SIMMVAL); break; + case 0x01: /* BCzT */ if (m_in_brcond1()) ADDPC(SIMMVAL); break; + case 0x02: /* BCzFL */ invalid_instruction(); break; + case 0x03: /* BCzTL */ invalid_instruction(); break; + default: invalid_instruction(); break; + } + break; + case 0x10: + case 0x11: + case 0x12: + case 0x13: + case 0x14: + case 0x15: + case 0x16: + case 0x17: + case 0x18: + case 0x19: + case 0x1a: + case 0x1b: + case 0x1c: + case 0x1d: + case 0x1e: + case 0x1f: /* COP */ invalid_instruction(); break; + default: invalid_instruction(); break; + } +} + + +/*************************************************************************** + COP2 (CUSTOM) EXECUTION HANDLING +***************************************************************************/ + +inline UINT32 r3000_device::get_cop2_reg(int idx) +{ + return m_cpr[2][idx]; +} + +inline void r3000_device::set_cop2_reg(int idx, UINT32 val) +{ + m_cpr[2][idx] = val; +} + +inline UINT32 r3000_device::get_cop2_creg(int idx) +{ + return m_ccr[2][idx]; +} + +inline void r3000_device::set_cop2_creg(int idx, UINT32 val) +{ + m_ccr[2][idx] = val; +} + +inline void r3000_device::handle_cop2() +{ + if (!(SR & SR_COP2)) + generate_exception(EXCEPTION_BADCOP); + + switch (RSREG) + { + case 0x00: /* MFCz */ if (RTREG) RTVAL = get_cop2_reg(RDREG); break; + case 0x02: /* CFCz */ if (RTREG) RTVAL = get_cop2_creg(RDREG); break; + case 0x04: /* MTCz */ set_cop2_reg(RDREG, RTVAL); break; + case 0x06: /* CTCz */ set_cop2_creg(RDREG, RTVAL); break; + case 0x08: /* BC */ + switch (RTREG) + { + case 0x00: /* BCzF */ if (!m_in_brcond2()) ADDPC(SIMMVAL); break; + case 0x01: /* BCzT */ if (m_in_brcond2()) ADDPC(SIMMVAL); break; + case 0x02: /* BCzFL */ invalid_instruction(); break; + case 0x03: /* BCzTL */ invalid_instruction(); break; + default: invalid_instruction(); break; + } + break; + case 0x10: + case 0x11: + case 0x12: + case 0x13: + case 0x14: + case 0x15: + case 0x16: + case 0x17: + case 0x18: + case 0x19: + case 0x1a: + case 0x1b: + case 0x1c: + case 0x1d: + case 0x1e: + case 0x1f: /* COP */ invalid_instruction(); break; + default: invalid_instruction(); break; + } +} + + +/*************************************************************************** + COP3 (CUSTOM) EXECUTION HANDLING +***************************************************************************/ + +inline UINT32 r3000_device::get_cop3_reg(int idx) +{ + return m_cpr[3][idx]; +} + +inline void r3000_device::set_cop3_reg(int idx, UINT32 val) +{ + m_cpr[3][idx] = val; +} + +inline UINT32 r3000_device::get_cop3_creg(int idx) +{ + return m_ccr[3][idx]; +} + +inline void r3000_device::set_cop3_creg(int idx, UINT32 val) +{ + m_ccr[3][idx] = val; +} + +inline void r3000_device::handle_cop3() +{ + if (!(SR & SR_COP3)) + generate_exception(EXCEPTION_BADCOP); + + switch (RSREG) + { + case 0x00: /* MFCz */ if (RTREG) RTVAL = get_cop3_reg(RDREG); break; + case 0x02: /* CFCz */ if (RTREG) RTVAL = get_cop3_creg(RDREG); break; + case 0x04: /* MTCz */ set_cop3_reg(RDREG, RTVAL); break; + case 0x06: /* CTCz */ set_cop3_creg(RDREG, RTVAL); break; + case 0x08: /* BC */ + switch (RTREG) + { + case 0x00: /* BCzF */ if (!m_in_brcond3()) ADDPC(SIMMVAL); break; + case 0x01: /* BCzT */ if (m_in_brcond3()) ADDPC(SIMMVAL); break; + case 0x02: /* BCzFL */ invalid_instruction(); break; + case 0x03: /* BCzTL */ invalid_instruction(); break; + default: invalid_instruction(); break; + } + break; + case 0x10: + case 0x11: + case 0x12: + case 0x13: + case 0x14: + case 0x15: + case 0x16: + case 0x17: + case 0x18: + case 0x19: + case 0x1a: + case 0x1b: + case 0x1c: + case 0x1d: + case 0x1e: + case 0x1f: /* COP */ invalid_instruction(); break; + default: invalid_instruction(); break; + } +} + + +/*************************************************************************** + CORE EXECUTION LOOP +***************************************************************************/ + +//------------------------------------------------- +// execute_min_cycles - return minimum number of +// cycles it takes for one instruction to execute +//------------------------------------------------- + +UINT32 r3000_device::execute_min_cycles() const +{ + return 1; +} + + +//------------------------------------------------- +// execute_max_cycles - return maximum number of +// cycles it takes for one instruction to execute +//------------------------------------------------- + +UINT32 r3000_device::execute_max_cycles() const +{ + return 40; +} + + +//------------------------------------------------- +// execute_input_lines - return the number of +// input/interrupt lines +//------------------------------------------------- + +UINT32 r3000_device::execute_input_lines() const +{ + return 6; +} + + +//------------------------------------------------- +// execute_set_input +//------------------------------------------------- + +void r3000_device::execute_set_input(int inputnum, int state) +{ + set_irq_line(inputnum, state); +} + + +//------------------------------------------------- +// execute_run +//------------------------------------------------- + +void r3000_device::execute_run() +{ + // count cycles and interrupt cycles + m_icount -= m_interrupt_cycles; + m_interrupt_cycles = 0; + + // check for IRQs + check_irqs(); + + // core execution loop + do + { + UINT64 temp64; + int temp; + + // debugging + m_ppc = m_pc; + debugger_instruction_hook(this, m_pc); + + // instruction fetch + m_op = readop(m_pc); + + // adjust for next PC + if (m_nextpc != ~0) + { + m_pc = m_nextpc; + m_nextpc = ~0; + } + else + m_pc += 4; + + // parse the instruction + switch (m_op >> 26) + { + case 0x00: /* SPECIAL */ + switch (m_op & 63) + { + case 0x00: /* SLL */ if (RDREG) RDVAL = RTVAL << SHIFT; break; + case 0x02: /* SRL */ if (RDREG) RDVAL = RTVAL >> SHIFT; break; + case 0x03: /* SRA */ if (RDREG) RDVAL = (INT32)RTVAL >> SHIFT; break; + case 0x04: /* SLLV */ if (RDREG) RDVAL = RTVAL << (RSVAL & 31); break; + case 0x06: /* SRLV */ if (RDREG) RDVAL = RTVAL >> (RSVAL & 31); break; + case 0x07: /* SRAV */ if (RDREG) RDVAL = (INT32)RTVAL >> (RSVAL & 31); break; + case 0x08: /* JR */ SETPC(RSVAL); break; + case 0x09: /* JALR */ SETPCL(RSVAL, RDREG); break; + case 0x0c: /* SYSCALL */ generate_exception(EXCEPTION_SYSCALL); break; + case 0x0d: /* BREAK */ generate_exception(EXCEPTION_BREAK); break; + case 0x0f: /* SYNC */ invalid_instruction(); break; + case 0x10: /* MFHI */ if (RDREG) RDVAL = m_hi; break; + case 0x11: /* MTHI */ m_hi = RSVAL; break; + case 0x12: /* MFLO */ if (RDREG) RDVAL = m_lo; break; + case 0x13: /* MTLO */ m_lo = RSVAL; break; + case 0x18: /* MULT */ + temp64 = (INT64)(INT32)RSVAL * (INT64)(INT32)RTVAL; + m_lo = (UINT32)temp64; + m_hi = (UINT32)(temp64 >> 32); + m_icount -= 11; + break; + case 0x19: /* MULTU */ + temp64 = (UINT64)RSVAL * (UINT64)RTVAL; + m_lo = (UINT32)temp64; + m_hi = (UINT32)(temp64 >> 32); + m_icount -= 11; + break; + case 0x1a: /* DIV */ + if (RTVAL) + { + m_lo = (INT32)RSVAL / (INT32)RTVAL; + m_hi = (INT32)RSVAL % (INT32)RTVAL; + } + m_icount -= 34; + break; + case 0x1b: /* DIVU */ + if (RTVAL) + { + m_lo = RSVAL / RTVAL; + m_hi = RSVAL % RTVAL; + } + m_icount -= 34; + break; + case 0x20: /* ADD */ + if (ENABLE_OVERFLOWS && RSVAL > ~RTVAL) generate_exception(EXCEPTION_OVERFLOW); + else RDVAL = RSVAL + RTVAL; + break; + case 0x21: /* ADDU */ if (RDREG) RDVAL = RSVAL + RTVAL; break; + case 0x22: /* SUB */ + if (ENABLE_OVERFLOWS && RSVAL < RTVAL) generate_exception(EXCEPTION_OVERFLOW); + else RDVAL = RSVAL - RTVAL; + break; + case 0x23: /* SUBU */ if (RDREG) RDVAL = RSVAL - RTVAL; break; + case 0x24: /* AND */ if (RDREG) RDVAL = RSVAL & RTVAL; break; + case 0x25: /* OR */ if (RDREG) RDVAL = RSVAL | RTVAL; break; + case 0x26: /* XOR */ if (RDREG) RDVAL = RSVAL ^ RTVAL; break; + case 0x27: /* NOR */ if (RDREG) RDVAL = ~(RSVAL | RTVAL); break; + case 0x2a: /* SLT */ if (RDREG) RDVAL = (INT32)RSVAL < (INT32)RTVAL; break; + case 0x2b: /* SLTU */ if (RDREG) RDVAL = (UINT32)RSVAL < (UINT32)RTVAL; break; + case 0x30: /* TEQ */ invalid_instruction(); break; + case 0x31: /* TGEU */ invalid_instruction(); break; + case 0x32: /* TLT */ invalid_instruction(); break; + case 0x33: /* TLTU */ invalid_instruction(); break; + case 0x34: /* TGE */ invalid_instruction(); break; + case 0x36: /* TNE */ invalid_instruction(); break; + default: /* ??? */ invalid_instruction(); break; + } + break; + + case 0x01: /* REGIMM */ + switch (RTREG) + { + case 0x00: /* BLTZ */ if ((INT32)RSVAL < 0) ADDPC(SIMMVAL); break; + case 0x01: /* BGEZ */ if ((INT32)RSVAL >= 0) ADDPC(SIMMVAL); break; + case 0x02: /* BLTZL */ invalid_instruction(); break; + case 0x03: /* BGEZL */ invalid_instruction(); break; + case 0x08: /* TGEI */ invalid_instruction(); break; + case 0x09: /* TGEIU */ invalid_instruction(); break; + case 0x0a: /* TLTI */ invalid_instruction(); break; + case 0x0b: /* TLTIU */ invalid_instruction(); break; + case 0x0c: /* TEQI */ invalid_instruction(); break; + case 0x0e: /* TNEI */ invalid_instruction(); break; + case 0x10: /* BLTZAL */ if ((INT32)RSVAL < 0) ADDPCL(SIMMVAL,31); break; + case 0x11: /* BGEZAL */ if ((INT32)RSVAL >= 0) ADDPCL(SIMMVAL,31); break; + case 0x12: /* BLTZALL */ invalid_instruction(); break; + case 0x13: /* BGEZALL */ invalid_instruction(); break; + default: /* ??? */ invalid_instruction(); break; + } + break; + + case 0x02: /* J */ ABSPC(LIMMVAL); break; + case 0x03: /* JAL */ ABSPCL(LIMMVAL,31); break; + case 0x04: /* BEQ */ if (RSVAL == RTVAL) ADDPC(SIMMVAL); break; + case 0x05: /* BNE */ if (RSVAL != RTVAL) ADDPC(SIMMVAL); break; + case 0x06: /* BLEZ */ if ((INT32)RSVAL <= 0) ADDPC(SIMMVAL); break; + case 0x07: /* BGTZ */ if ((INT32)RSVAL > 0) ADDPC(SIMMVAL); break; + case 0x08: /* ADDI */ + if (ENABLE_OVERFLOWS && RSVAL > ~SIMMVAL) generate_exception(EXCEPTION_OVERFLOW); + else if (RTREG) RTVAL = RSVAL + SIMMVAL; + break; + case 0x09: /* ADDIU */ if (RTREG) RTVAL = RSVAL + SIMMVAL; break; + case 0x0a: /* SLTI */ if (RTREG) RTVAL = (INT32)RSVAL < (INT32)SIMMVAL; break; + case 0x0b: /* SLTIU */ if (RTREG) RTVAL = (UINT32)RSVAL < (UINT32)SIMMVAL; break; + case 0x0c: /* ANDI */ if (RTREG) RTVAL = RSVAL & UIMMVAL; break; + case 0x0d: /* ORI */ if (RTREG) RTVAL = RSVAL | UIMMVAL; break; + case 0x0e: /* XORI */ if (RTREG) RTVAL = RSVAL ^ UIMMVAL; break; + case 0x0f: /* LUI */ if (RTREG) RTVAL = UIMMVAL << 16; break; + case 0x10: /* COP0 */ handle_cop0(); break; + case 0x11: /* COP1 */ handle_cop1(); break; + case 0x12: /* COP2 */ handle_cop2(); break; + case 0x13: /* COP3 */ handle_cop3(); break; + case 0x14: /* BEQL */ invalid_instruction(); break; + case 0x15: /* BNEL */ invalid_instruction(); break; + case 0x16: /* BLEZL */ invalid_instruction(); break; + case 0x17: /* BGTZL */ invalid_instruction(); break; + case 0x20: /* LB */ temp = RBYTE(SIMMVAL+RSVAL); if (RTREG) RTVAL = (INT8)temp; break; + case 0x21: /* LH */ temp = RWORD(SIMMVAL+RSVAL); if (RTREG) RTVAL = (INT16)temp; break; + case 0x22: /* LWL */ (*this.*m_lwl)(); break; + case 0x23: /* LW */ temp = RLONG(SIMMVAL+RSVAL); if (RTREG) RTVAL = temp; break; + case 0x24: /* LBU */ temp = RBYTE(SIMMVAL+RSVAL); if (RTREG) RTVAL = (UINT8)temp; break; + case 0x25: /* LHU */ temp = RWORD(SIMMVAL+RSVAL); if (RTREG) RTVAL = (UINT16)temp; break; + case 0x26: /* LWR */ (*this.*m_lwr)(); break; + case 0x28: /* SB */ WBYTE(SIMMVAL+RSVAL, RTVAL); break; + case 0x29: /* SH */ WWORD(SIMMVAL+RSVAL, RTVAL); break; + case 0x2a: /* SWL */ (*this.*m_swl)(); break; + case 0x2b: /* SW */ WLONG(SIMMVAL+RSVAL, RTVAL); break; + case 0x2e: /* SWR */ (*this.*m_swr)(); break; + case 0x2f: /* CACHE */ invalid_instruction(); break; + case 0x30: /* LL */ invalid_instruction(); break; + case 0x31: /* LWC1 */ set_cop1_reg(RTREG, RLONG(SIMMVAL+RSVAL)); break; + case 0x32: /* LWC2 */ set_cop2_reg(RTREG, RLONG(SIMMVAL+RSVAL)); break; + case 0x33: /* LWC3 */ set_cop3_reg(RTREG, RLONG(SIMMVAL+RSVAL)); break; + case 0x34: /* LDC0 */ invalid_instruction(); break; + case 0x35: /* LDC1 */ invalid_instruction(); break; + case 0x36: /* LDC2 */ invalid_instruction(); break; + case 0x37: /* LDC3 */ invalid_instruction(); break; + case 0x38: /* SC */ invalid_instruction(); break; + case 0x39: /* LWC1 */ WLONG(SIMMVAL+RSVAL, get_cop1_reg(RTREG)); break; + case 0x3a: /* LWC2 */ WLONG(SIMMVAL+RSVAL, get_cop2_reg(RTREG)); break; + case 0x3b: /* LWC3 */ WLONG(SIMMVAL+RSVAL, get_cop3_reg(RTREG)); break; + case 0x3c: /* SDC0 */ invalid_instruction(); break; + case 0x3d: /* SDC1 */ invalid_instruction(); break; + case 0x3e: /* SDC2 */ invalid_instruction(); break; + case 0x3f: /* SDC3 */ invalid_instruction(); break; + default: /* ??? */ invalid_instruction(); break; + } + m_icount--; + + } while (m_icount > 0 || m_nextpc != ~0); + + m_icount -= m_interrupt_cycles; + m_interrupt_cycles = 0; +} + + +/*************************************************************************** + COMPLEX OPCODE IMPLEMENTATIONS +***************************************************************************/ + +void r3000_device::lwl_be() +{ + offs_t offs = SIMMVAL + RSVAL; + UINT32 temp = RLONG(offs & ~3); + if (RTREG) + { + if (!(offs & 3)) RTVAL = temp; + else + { + int shift = 8 * (offs & 3); + RTVAL = (RTVAL & (0x00ffffff >> (24 - shift))) | (temp << shift); + } + } +} + +void r3000_device::lwr_be() +{ + offs_t offs = SIMMVAL + RSVAL; + UINT32 temp = RLONG(offs & ~3); + if (RTREG) + { + if ((offs & 3) == 3) RTVAL = temp; + else + { + int shift = 8 * (offs & 3); + RTVAL = (RTVAL & (0xffffff00 << shift)) | (temp >> (24 - shift)); + } + } +} + +void r3000_device::swl_be() +{ + offs_t offs = SIMMVAL + RSVAL; + if (!(offs & 3)) WLONG(offs, RTVAL); + else + { + UINT32 temp = RLONG(offs & ~3); + int shift = 8 * (offs & 3); + WLONG(offs & ~3, (temp & (0xffffff00 << (24 - shift))) | (RTVAL >> shift)); + } +} + + +void r3000_device::swr_be() +{ + offs_t offs = SIMMVAL + RSVAL; + if ((offs & 3) == 3) WLONG(offs & ~3, RTVAL); + else + { + UINT32 temp = RLONG(offs & ~3); + int shift = 8 * (offs & 3); + WLONG(offs & ~3, (temp & (0x00ffffff >> shift)) | (RTVAL << (24 - shift))); + } +} + + + +void r3000_device::lwl_le() +{ + offs_t offs = SIMMVAL + RSVAL; + UINT32 temp = RLONG(offs & ~3); + if (RTREG) + { + if (!(offs & 3)) RTVAL = temp; + else + { + int shift = 8 * (offs & 3); + RTVAL = (RTVAL & (0xffffff00 << (24 - shift))) | (temp >> shift); + } + } +} + +void r3000_device::lwr_le() +{ + offs_t offs = SIMMVAL + RSVAL; + UINT32 temp = RLONG(offs & ~3); + if (RTREG) + { + if ((offs & 3) == 3) RTVAL = temp; + else + { + int shift = 8 * (offs & 3); + RTVAL = (RTVAL & (0x00ffffff >> shift)) | (temp << (24 - shift)); + } + } +} + +void r3000_device::swl_le() +{ + offs_t offs = SIMMVAL + RSVAL; + if (!(offs & 3)) WLONG(offs, RTVAL); + else + { + UINT32 temp = RLONG(offs & ~3); + int shift = 8 * (offs & 3); + WLONG(offs & ~3, (temp & (0x00ffffff >> (24 - shift))) | (RTVAL << shift)); + } +} + +void r3000_device::swr_le() +{ + offs_t offs = SIMMVAL + RSVAL; + if ((offs & 3) == 3) WLONG(offs & ~3, RTVAL); + else + { + UINT32 temp = RLONG(offs & ~3); + int shift = 8 * (offs & 3); + WLONG(offs & ~3, (temp & (0xffffff00 << shift)) | (RTVAL >> (24 - shift))); + } +} diff --git a/src/devices/cpu/mips/r3000.h b/src/devices/cpu/mips/r3000.h new file mode 100644 index 00000000000..a29ea5cd163 --- /dev/null +++ b/src/devices/cpu/mips/r3000.h @@ -0,0 +1,319 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + r3000.h + Interface file for the portable MIPS R3000 emulator. + Written by Aaron Giles + +***************************************************************************/ + +#ifndef __R3000_H__ +#define __R3000_H__ + + +/*************************************************************************** + INTERFACE CONFIGURATION MACROS +***************************************************************************/ + +#define MCFG_R3000_ENDIANNESS(_endianness) \ + r3000_device::static_set_endianness(*device, _endianness); + +#define MCFG_R3000_BRCOND0_INPUT(_devcb) \ + devcb = &r3000_device::static_set_brcond0_input(*device, DEVCB_##_devcb); + +#define MCFG_R3000_BRCOND1_INPUT(_devcb) \ + devcb = &r3000_device::static_set_brcond1_input(*device, DEVCB_##_devcb); + +#define MCFG_R3000_BRCOND2_INPUT(_devcb) \ + devcb = &r3000_device::static_set_brcond2_input(*device, DEVCB_##_devcb); + +#define MCFG_R3000_BRCOND3_INPUT(_devcb) \ + devcb = &r3000_device::static_set_brcond3_input(*device, DEVCB_##_devcb); + + +/*************************************************************************** + REGISTER ENUMERATION +***************************************************************************/ + +enum +{ + R3000_PC=1,R3000_SR, + R3000_R0,R3000_R1,R3000_R2,R3000_R3,R3000_R4,R3000_R5,R3000_R6,R3000_R7, + R3000_R8,R3000_R9,R3000_R10,R3000_R11,R3000_R12,R3000_R13,R3000_R14,R3000_R15, + R3000_R16,R3000_R17,R3000_R18,R3000_R19,R3000_R20,R3000_R21,R3000_R22,R3000_R23, + R3000_R24,R3000_R25,R3000_R26,R3000_R27,R3000_R28,R3000_R29,R3000_R30,R3000_R31 +}; + + +/*************************************************************************** + INTERRUPT CONSTANTS +***************************************************************************/ + +#define R3000_IRQ0 0 /* IRQ0 */ +#define R3000_IRQ1 1 /* IRQ1 */ +#define R3000_IRQ2 2 /* IRQ2 */ +#define R3000_IRQ3 3 /* IRQ3 */ +#define R3000_IRQ4 4 /* IRQ4 */ +#define R3000_IRQ5 5 /* IRQ5 */ + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> r3000_device + +class r3000_device : public cpu_device +{ +protected: + enum chip_type + { + CHIP_TYPE_R3041, + CHIP_TYPE_R3051, + CHIP_TYPE_R3052, + CHIP_TYPE_R3071, + CHIP_TYPE_R3081 + }; + + // construction/destruction + r3000_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, chip_type chiptype, const char *shortname, const char *source); + virtual ~r3000_device(); + +public: + // inline configuration helpers + static void static_set_endianness(device_t &device, endianness_t endianness) + { + downcast(device).m_endianness = endianness; + } + + template static devcb_base &static_set_brcond0_input(device_t &device, _Object object) + { + return downcast(device).m_in_brcond0.set_callback(object); + } + + template static devcb_base &static_set_brcond1_input(device_t &device, _Object object) + { + return downcast(device).m_in_brcond1.set_callback(object); + } + + template static devcb_base &static_set_brcond2_input(device_t &device, _Object object) + { + return downcast(device).m_in_brcond2.set_callback(object); + } + + template static devcb_base &static_set_brcond3_input(device_t &device, _Object object) + { + return downcast(device).m_in_brcond3.set_callback(object); + } + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_post_load(); + + // device_execute_interface overrides + virtual UINT32 execute_min_cycles() const; + virtual UINT32 execute_max_cycles() const; + virtual UINT32 execute_input_lines() const; + virtual void execute_run(); + virtual void execute_set_input(int inputnum, int state); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const; + + // device_state_interface overrides + virtual void state_import(const device_state_entry &entry); + virtual void state_export(const device_state_entry &entry); + virtual void state_string_export(const device_state_entry &entry, std::string &str); + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const; + virtual UINT32 disasm_max_opcode_bytes() const; + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + + // memory accessors + struct r3000_data_accessors + { + UINT8 (r3000_device::*m_read_byte)(offs_t byteaddress); + UINT16 (r3000_device::*m_read_word)(offs_t byteaddress); + UINT32 (r3000_device::*m_read_dword)(offs_t byteaddress); + void (r3000_device::*m_write_byte)(offs_t byteaddress, UINT8 data); + void (r3000_device::*m_write_word)(offs_t byteaddress, UINT16 data); + void (r3000_device::*m_write_dword)(offs_t byteaddress, UINT32 data); + }; + + UINT32 readop(offs_t pc); + UINT8 readmem(offs_t offset); + UINT16 readmem_word(offs_t offset); + UINT32 readmem_dword(offs_t offset); + void writemem(offs_t offset, UINT8 data); + void writemem_word(offs_t offset, UINT16 data); + void writemem_dword(offs_t offset, UINT32 data); + + UINT8 readcache_be(offs_t offset); + UINT16 readcache_be_word(offs_t offset); + UINT32 readcache_be_dword(offs_t offset); + void writecache_be(offs_t offset, UINT8 data); + void writecache_be_word(offs_t offset, UINT16 data); + void writecache_be_dword(offs_t offset, UINT32 data); + + UINT8 readcache_le(offs_t offset); + UINT16 readcache_le_word(offs_t offset); + UINT32 readcache_le_dword(offs_t offset); + void writecache_le(offs_t offset, UINT8 data); + void writecache_le_word(offs_t offset, UINT16 data); + void writecache_le_dword(offs_t offset, UINT32 data); + + // interrupts + void generate_exception(int exception); + void check_irqs(); + void set_irq_line(int irqline, int state); + void invalid_instruction(); + + // instructions + UINT32 get_cop0_reg(int idx); + void set_cop0_reg(int idx, UINT32 val); + UINT32 get_cop0_creg(int idx); + void set_cop0_creg(int idx, UINT32 val); + void handle_cop0(); + + UINT32 get_cop1_reg(int idx); + void set_cop1_reg(int idx, UINT32 val); + UINT32 get_cop1_creg(int idx); + void set_cop1_creg(int idx, UINT32 val); + void handle_cop1(); + + UINT32 get_cop2_reg(int idx); + void set_cop2_reg(int idx, UINT32 val); + UINT32 get_cop2_creg(int idx); + void set_cop2_creg(int idx, UINT32 val); + void handle_cop2(); + + UINT32 get_cop3_reg(int idx); + void set_cop3_reg(int idx, UINT32 val); + UINT32 get_cop3_creg(int idx); + void set_cop3_creg(int idx, UINT32 val); + void handle_cop3(); + + // complex opcodes + void lwl_be(); + void lwr_be(); + void swl_be(); + void swr_be(); + + void lwl_le(); + void lwr_le(); + void swl_le(); + void swr_le(); + + // address spaces + const address_space_config m_program_config_be; + const address_space_config m_program_config_le; + address_space *m_program; + direct_read_data *m_direct; + + // configuration + chip_type m_chip_type; + bool m_hasfpu; + endianness_t m_endianness; + + // core registers + UINT32 m_pc; + UINT32 m_nextpc; + UINT32 m_hi; + UINT32 m_lo; + UINT32 m_r[32]; + + // COP registers + UINT32 m_cpr[4][32]; + UINT32 m_ccr[4][32]; + + // internal stuff + UINT32 m_ppc; + UINT32 m_op; + int m_icount; + int m_interrupt_cycles; + + // endian-dependent load/store + void (r3000_device::*m_lwl)(); + void (r3000_device::*m_lwr)(); + void (r3000_device::*m_swl)(); + void (r3000_device::*m_swr)(); + + // memory accesses + r3000_data_accessors *m_cur; + r3000_data_accessors m_memory_hand; + r3000_data_accessors m_cache_hand; + + // cache memory + UINT32 * m_cache; + std::vector m_icache; + std::vector m_dcache; + size_t m_cache_size; + size_t m_icache_size; + size_t m_dcache_size; + + // I/O + devcb_read_line m_in_brcond0; + devcb_read_line m_in_brcond1; + devcb_read_line m_in_brcond2; + devcb_read_line m_in_brcond3; +}; + + +// ======================> r3041_device + +class r3041_device : public r3000_device +{ +public: + r3041_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +// ======================> r3051_device + +class r3051_device : public r3000_device +{ +public: + r3051_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +// ======================> r3052_device + +class r3052_device : public r3000_device +{ +public: + r3052_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +// ======================> r3071_device + +class r3071_device : public r3000_device +{ +public: + r3071_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +// ======================> r3081_device + +class r3081_device : public r3000_device +{ +public: + r3081_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +// device type definition + +extern const device_type R3041; +extern const device_type R3051; +extern const device_type R3052; +extern const device_type R3071; +extern const device_type R3081; + +#endif /* __R3000_H__ */ diff --git a/src/devices/cpu/mips/r3kdasm.c b/src/devices/cpu/mips/r3kdasm.c new file mode 100644 index 00000000000..78521a9679f --- /dev/null +++ b/src/devices/cpu/mips/r3kdasm.c @@ -0,0 +1,389 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + r3kdasm.c + Disassembler for the portable R3000 emulator. + Written by Aaron Giles + +***************************************************************************/ + +#include "emu.h" + + +static const char *const reg[32] = +{ + "0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", + "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", + "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", + "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31" +}; + + +static const char *const cpreg[4][32] = +{ + { + "Index","Random","EntryLo","cpr3", "Context", "cpr5", "cpr6", "cpr7", + "BadVAddr", "cpr9", "EntryHi","cpr11","SR","Cause","EPC","PRId", + "cpr16","cpr17","cpr18","cpr19","cpr20","cpr21","cpr22","cpr23", + "cpr24","cpr25","cpr26","cpr27","cpr28","cpr29","cpr30","cpr31" + }, + { + "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", + "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", + "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", + "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31" + }, + { + "cpr0", "cpr1", "cpr2", "cpr3", "cpr4", "cpr5", "cpr6", "cpr7", + "cpr8", "cpr9", "cpr10","cpr11","cpr12","cpr13","cpr14","cpr15", + "cpr16","cpr17","cpr18","cpr19","cpr20","cpr21","cpr22","cpr23", + "cpr24","cpr25","cpr26","cpr27","cpr28","cpr29","cpr30","cpr31" + }, + { + "cpr0", "cpr1", "cpr2", "cpr3", "cpr4", "cpr5", "cpr6", "cpr7", + "cpr8", "cpr9", "cpr10","cpr11","cpr12","cpr13","cpr14","cpr15", + "cpr16","cpr17","cpr18","cpr19","cpr20","cpr21","cpr22","cpr23", + "cpr24","cpr25","cpr26","cpr27","cpr28","cpr29","cpr30","cpr31" + } +}; + + +static const char *const ccreg[4][32] = +{ + { + "ccr0", "ccr1", "ccr2", "ccr3", "ccr4", "ccr5", "ccr6", "ccr7", + "ccr8", "ccr9", "ccr10","ccr11","ccr12","ccr13","ccr14","ccr15", + "ccr16","ccr17","ccr18","ccr19","ccr20","ccr21","ccr22","ccr23", + "ccr24","ccr25","ccr26","ccr27","ccr28","ccr29","ccr30","ccr31" + }, + { + "ccr0", "ccr1", "ccr2", "ccr3", "ccr4", "ccr5", "ccr6", "ccr7", + "ccr8", "ccr9", "ccr10","ccr11","ccr12","ccr13","ccr14","ccr15", + "ccr16","ccr17","ccr18","ccr19","ccr20","ccr21","ccr22","ccr23", + "ccr24","ccr25","ccr26","ccr27","ccr28","ccr29","ccr30","ccr31" + }, + { + "ccr0", "ccr1", "ccr2", "ccr3", "ccr4", "ccr5", "ccr6", "ccr7", + "ccr8", "ccr9", "ccr10","ccr11","ccr12","ccr13","ccr14","ccr15", + "ccr16","ccr17","ccr18","ccr19","ccr20","ccr21","ccr22","ccr23", + "ccr24","ccr25","ccr26","ccr27","ccr28","ccr29","ccr30","ccr31" + }, + { + "ccr0", "ccr1", "ccr2", "ccr3", "ccr4", "ccr5", "ccr6", "ccr7", + "ccr8", "ccr9", "ccr10","ccr11","ccr12","ccr13","ccr14","ccr15", + "ccr16","ccr17","ccr18","ccr19","ccr20","ccr21","ccr22","ccr23", + "ccr24","ccr25","ccr26","ccr27","ccr28","ccr29","ccr30","ccr31" + } +}; + + +/*************************************************************************** + CODE CODE +***************************************************************************/ + +INLINE char *signed_16bit(INT16 val) +{ + static char temp[10]; + if (val < 0) + sprintf(temp, "-$%x", -val); + else + sprintf(temp, "$%x", val); + return temp; +} + +static UINT32 dasm_cop(UINT32 pc, int cop, UINT32 op, char *buffer) +{ + int rt = (op >> 16) & 31; + int rd = (op >> 11) & 31; + UINT32 flags = 0; + + switch ((op >> 21) & 31) + { + case 0x00: sprintf(buffer, "mfc%d %s,%s", cop, reg[rt], cpreg[cop][rd]); break; + case 0x02: sprintf(buffer, "cfc%d %s,%s", cop, reg[rt], ccreg[cop][rd]); break; + case 0x04: sprintf(buffer, "mtc%d %s,%s", cop, reg[rt], cpreg[cop][rd]); break; + case 0x06: sprintf(buffer, "ctc%d %s,%s", cop, reg[rt], ccreg[cop][rd]); break; + case 0x08: /* BC */ + switch (rt) + { + case 0x00: sprintf(buffer, "bc%df $%08x", cop, pc + 4 + ((INT16)op << 2)); break; + case 0x01: sprintf(buffer, "bc%dt $%08x", cop, pc + 4 + ((INT16)op << 2)); break; + case 0x02: sprintf(buffer, "bc%dfl [invalid]", cop); break; + case 0x03: sprintf(buffer, "bc%dtl [invalid]", cop); break; + default: sprintf(buffer, "dc.l $%08x [invalid]", op); break; + } + break; + case 0x10: + case 0x11: + case 0x12: + case 0x13: + case 0x14: + case 0x15: + case 0x16: + case 0x17: + case 0x18: + case 0x19: + case 0x1a: + case 0x1b: + case 0x1c: + case 0x1d: + case 0x1e: + case 0x1f: /* COP */ + if (cop == 0) + { + switch (op & 0x01ffffff) + { + case 0x01: sprintf(buffer, "tlbr"); break; + case 0x02: sprintf(buffer, "tlbwi"); break; + case 0x06: sprintf(buffer, "tlbwr"); break; + case 0x08: sprintf(buffer, "tlbp"); break; + case 0x10: sprintf(buffer, "rfe"); break; + case 0x18: sprintf(buffer, "eret [invalid]"); break; + default: sprintf(buffer, "cop%d $%07x", cop, op & 0x01ffffff); break; + } + } + else + sprintf(buffer, "cop%d $%07x", cop, op & 0x01ffffff); break; + default: sprintf(buffer, "dc.l $%08x [invalid]", op); break; + } + + return flags; +} + +static UINT32 dasm_cop1(UINT32 pc, UINT32 op, char *buffer) +{ + static const char *const format_table[] = + { + "?","?","?","?","?","?","?","?","?","?","?","?","?","?","?","?", + "s","d","?","?","w","l","?","?","?","?","?","?","?","?","?","?" + }; + const char *fmt = format_table[(op >> 21) & 31]; + int ft = (op >> 16) & 31; + int fs = (op >> 11) & 31; + int fd = (op >> 6) & 31; + int rt = (op >> 16) & 31; + int rd = (op >> 11) & 31; + UINT32 flags = 0; + + switch ((op >> 21) & 31) + { + case 0x00: sprintf(buffer, "mfc1 %s,%s", reg[rt], cpreg[1][rd]); break; + case 0x01: sprintf(buffer, "dmfc1 %s,%s", reg[rt], cpreg[1][rd]); break; + case 0x02: sprintf(buffer, "cfc1 %s,%s", reg[rt], ccreg[1][rd]); break; + case 0x04: sprintf(buffer, "mtc1 %s,%s", reg[rt], cpreg[1][rd]); break; + case 0x05: sprintf(buffer, "dmtc1 %s,%s", reg[rt], cpreg[1][rd]); break; + case 0x06: sprintf(buffer, "ctc1 %s,%s", reg[rt], ccreg[1][rd]); break; + case 0x08: /* BC */ + switch (rt & 3) + { + case 0x00: sprintf(buffer, "bc1f $%08x,%d", pc + 4 + ((INT16)op << 2), (op >> 18) & 7); break; + case 0x01: sprintf(buffer, "bc1t $%08x,%d", pc + 4 + ((INT16)op << 2), (op >> 18) & 7); break; + case 0x02: sprintf(buffer, "bc1fl $%08x,%d", pc + 4 + ((INT16)op << 2), (op >> 18) & 7); flags = DASMFLAG_STEP_OVER | DASMFLAG_STEP_OVER_EXTRA(1); break; + case 0x03: sprintf(buffer, "bc1tl $%08x,%d", pc + 4 + ((INT16)op << 2), (op >> 18) & 7); flags = DASMFLAG_STEP_OVER | DASMFLAG_STEP_OVER_EXTRA(1); break; + } + break; + default: /* COP */ + switch (op & 0x3f) + { + case 0x00: sprintf(buffer, "add.%s %s,%s,%s", fmt, cpreg[1][fd], cpreg[1][fs], cpreg[1][ft]); break; + case 0x01: sprintf(buffer, "sub.%s %s,%s,%s", fmt, cpreg[1][fd], cpreg[1][fs], cpreg[1][ft]); break; + case 0x02: sprintf(buffer, "mul.%s %s,%s,%s", fmt, cpreg[1][fd], cpreg[1][fs], cpreg[1][ft]); break; + case 0x03: sprintf(buffer, "div.%s %s,%s,%s", fmt, cpreg[1][fd], cpreg[1][fs], cpreg[1][ft]); break; + case 0x04: sprintf(buffer, "sqrt.%s %s,%s", fmt, cpreg[1][fd], cpreg[1][fs]); break; + case 0x05: sprintf(buffer, "abs.%s %s,%s", fmt, cpreg[1][fd], cpreg[1][fs]); break; + case 0x06: sprintf(buffer, "mov.%s %s,%s", fmt, cpreg[1][fd], cpreg[1][fs]); break; + case 0x07: sprintf(buffer, "neg.%s %s,%s", fmt, cpreg[1][fd], cpreg[1][fs]); break; + case 0x08: sprintf(buffer, "round.l.%s %s,%s", fmt, cpreg[1][fd], cpreg[1][fs]); break; + case 0x09: sprintf(buffer, "trunc.l.%s %s,%s", fmt, cpreg[1][fd], cpreg[1][fs]); break; + case 0x0a: sprintf(buffer, "ceil.l.%s %s,%s", fmt, cpreg[1][fd], cpreg[1][fs]); break; + case 0x0b: sprintf(buffer, "floor.l.%s %s,%s", fmt, cpreg[1][fd], cpreg[1][fs]); break; + case 0x0c: sprintf(buffer, "round.w.%s %s,%s", fmt, cpreg[1][fd], cpreg[1][fs]); break; + case 0x0d: sprintf(buffer, "trunc.w.%s %s,%s", fmt, cpreg[1][fd], cpreg[1][fs]); break; + case 0x0e: sprintf(buffer, "ceil.w.%s %s,%s", fmt, cpreg[1][fd], cpreg[1][fs]); break; + case 0x0f: sprintf(buffer, "floor.w.%s %s,%s", fmt, cpreg[1][fd], cpreg[1][fs]); break; + case 0x11: sprintf(buffer, "mov%c.%s %s,%s,%d", ((op >> 16) & 1) ? 't' : 'f', fmt, cpreg[1][fd], cpreg[1][fs], (op >> 18) & 7); break; + case 0x12: sprintf(buffer, "movz.%s %s,%s,%s", fmt, cpreg[1][fd], cpreg[1][fs], reg[rt]); break; + case 0x13: sprintf(buffer, "movn.%s %s,%s,%s", fmt, cpreg[1][fd], cpreg[1][fs], reg[rt]); break; + case 0x15: sprintf(buffer, "recip.%s %s,%s", fmt, cpreg[1][fd], cpreg[1][fs]); break; + case 0x16: sprintf(buffer, "rsqrt.%s %s,%s", fmt, cpreg[1][fd], cpreg[1][fs]); break; + case 0x20: sprintf(buffer, "cvt.s.%s %s,%s", fmt, cpreg[1][fd], cpreg[1][fs]); break; + case 0x21: sprintf(buffer, "cvt.d.%s %s,%s", fmt, cpreg[1][fd], cpreg[1][fs]); break; + case 0x24: sprintf(buffer, "cvt.w.%s %s,%s", fmt, cpreg[1][fd], cpreg[1][fs]); break; + case 0x25: sprintf(buffer, "cvt.l.%s %s,%s", fmt, cpreg[1][fd], cpreg[1][fs]); break; + case 0x30: sprintf(buffer, "c.f.%s %s,%s,%d", fmt, cpreg[1][fs], cpreg[1][ft], (op >> 8) & 7); break; + case 0x31: sprintf(buffer, "c.un.%s %s,%s,%d", fmt, cpreg[1][fs], cpreg[1][ft], (op >> 8) & 7); break; + case 0x32: sprintf(buffer, "c.eq.%s %s,%s,%d", fmt, cpreg[1][fs], cpreg[1][ft], (op >> 8) & 7); break; + case 0x33: sprintf(buffer, "c.ueq.%s %s,%s,%d", fmt, cpreg[1][fs], cpreg[1][ft], (op >> 8) & 7); break; + case 0x34: sprintf(buffer, "c.olt.%s %s,%s,%d", fmt, cpreg[1][fs], cpreg[1][ft], (op >> 8) & 7); break; + case 0x35: sprintf(buffer, "c.ult.%s %s,%s,%d", fmt, cpreg[1][fs], cpreg[1][ft], (op >> 8) & 7); break; + case 0x36: sprintf(buffer, "c.ole.%s %s,%s,%d", fmt, cpreg[1][fs], cpreg[1][ft], (op >> 8) & 7); break; + case 0x37: sprintf(buffer, "c.ule.%s %s,%s,%d", fmt, cpreg[1][fs], cpreg[1][ft], (op >> 8) & 7); break; + case 0x38: sprintf(buffer, "c.sf.%s %s,%s,%d", fmt, cpreg[1][fs], cpreg[1][ft], (op >> 8) & 7); break; + case 0x39: sprintf(buffer, "c.ngle.%s %s,%s,%d", fmt, cpreg[1][fs], cpreg[1][ft], (op >> 8) & 7);break; + case 0x3a: sprintf(buffer, "c.seq.%s %s,%s,%d", fmt, cpreg[1][fs], cpreg[1][ft], (op >> 8) & 7); break; + case 0x3b: sprintf(buffer, "c.ngl.%s %s,%s,%d", fmt, cpreg[1][fs], cpreg[1][ft], (op >> 8) & 7); break; + case 0x3c: sprintf(buffer, "c.lt.%s %s,%s,%d", fmt, cpreg[1][fs], cpreg[1][ft], (op >> 8) & 7); break; + case 0x3d: sprintf(buffer, "c.nge.%s %s,%s,%d", fmt, cpreg[1][fs], cpreg[1][ft], (op >> 8) & 7); break; + case 0x3e: sprintf(buffer, "c.le.%s %s,%s,%d", fmt, cpreg[1][fs], cpreg[1][ft], (op >> 8) & 7); break; + case 0x3f: sprintf(buffer, "c.ngt.%s %s,%s,%d", fmt, cpreg[1][fs], cpreg[1][ft], (op >> 8) & 7); break; + default: sprintf(buffer, "cop1 $%07x", op & 0x01ffffff); break; + } + break; + } + return flags; +} + +static unsigned dasmr3k(char *buffer, unsigned pc, UINT32 op) +{ + int rs = (op >> 21) & 31; + int rt = (op >> 16) & 31; + int rd = (op >> 11) & 31; + int shift = (op >> 6) & 31; + UINT32 flags = 0; + + switch (op >> 26) + { + case 0x00: /* SPECIAL */ + switch (op & 63) + { + case 0x00: if (op == 0) + sprintf(buffer, "nop"); + else + sprintf(buffer, "sll %s,%s,%d", reg[rd], reg[rt], shift); break; + case 0x02: sprintf(buffer, "srl %s,%s,%d", reg[rd], reg[rt], shift); break; + case 0x03: sprintf(buffer, "sra %s,%s,%d", reg[rd], reg[rt], shift); break; + case 0x04: sprintf(buffer, "sllv %s,%s,%s", reg[rd], reg[rt], reg[rs]); break; + case 0x06: sprintf(buffer, "srlv %s,%s,%s", reg[rd], reg[rt], reg[rs]); break; + case 0x07: sprintf(buffer, "srav %s,%s,%s", reg[rd], reg[rt], reg[rs]); break; + case 0x08: sprintf(buffer, "jr %s", reg[rs]); if (rs == 31) flags = DASMFLAG_STEP_OUT; break; + case 0x09: if (rd == 31) + sprintf(buffer, "jalr %s", reg[rs]); + else + sprintf(buffer, "jalr %s,%s", reg[rs], reg[rd]); flags = DASMFLAG_STEP_OVER | DASMFLAG_STEP_OVER_EXTRA(1); break; + case 0x0c: sprintf(buffer, "syscall"); flags = DASMFLAG_STEP_OVER; break; + case 0x0d: sprintf(buffer, "break"); flags = DASMFLAG_STEP_OVER; break; + case 0x0f: sprintf(buffer, "sync [invalid]"); break; + case 0x10: sprintf(buffer, "mfhi %s", reg[rd]); break; + case 0x11: sprintf(buffer, "mthi %s", reg[rs]); break; + case 0x12: sprintf(buffer, "mflo %s", reg[rd]); break; + case 0x13: sprintf(buffer, "mtlo %s", reg[rs]); break; + case 0x18: sprintf(buffer, "mult %s,%s", reg[rs], reg[rt]); break; + case 0x19: sprintf(buffer, "multu %s,%s", reg[rs], reg[rt]); break; + case 0x1a: sprintf(buffer, "div %s,%s", reg[rs], reg[rt]); break; + case 0x1b: sprintf(buffer, "divu %s,%s", reg[rs], reg[rt]); break; + case 0x20: sprintf(buffer, "add %s,%s,%s", reg[rd], reg[rs], reg[rt]); break; + case 0x21: sprintf(buffer, "addu %s,%s,%s", reg[rd], reg[rs], reg[rt]); break; + case 0x22: sprintf(buffer, "sub %s,%s,%s", reg[rd], reg[rs], reg[rt]); break; + case 0x23: sprintf(buffer, "subu %s,%s,%s", reg[rd], reg[rs], reg[rt]); break; + case 0x24: sprintf(buffer, "and %s,%s,%s", reg[rd], reg[rs], reg[rt]); break; + case 0x25: sprintf(buffer, "or %s,%s,%s", reg[rd], reg[rs], reg[rt]); break; + case 0x26: sprintf(buffer, "xor %s,%s,%s", reg[rd], reg[rs], reg[rt]); break; + case 0x27: sprintf(buffer, "nor %s,%s,%s", reg[rd], reg[rs], reg[rt]); break; + case 0x2a: sprintf(buffer, "slt %s,%s,%s", reg[rd], reg[rs], reg[rt]); break; + case 0x2b: sprintf(buffer, "sltu %s,%s,%s", reg[rd], reg[rs], reg[rt]); break; + case 0x30: sprintf(buffer, "teq [invalid]"); break; + case 0x31: sprintf(buffer, "tgeu [invalid]"); break; + case 0x32: sprintf(buffer, "tlt [invalid]"); break; + case 0x33: sprintf(buffer, "tltu [invalid]"); break; + case 0x34: sprintf(buffer, "tge [invalid]"); break; + case 0x36: sprintf(buffer, "tne [invalid]"); break; + default: sprintf(buffer, "dc.l $%08x [invalid]", op); break; + } + break; + + case 0x01: /* REGIMM */ + switch ((op >> 16) & 31) + { + case 0x00: sprintf(buffer, "bltz %s,$%08x", reg[rs], pc + 4 + ((INT16)op << 2)); break; + case 0x01: sprintf(buffer, "bgez %s,$%08x", reg[rs], pc + 4 + ((INT16)op << 2)); break; + case 0x02: sprintf(buffer, "bltzl [invalid]"); break; + case 0x03: sprintf(buffer, "bgezl [invalid]"); break; + case 0x08: sprintf(buffer, "tgei [invalid]"); break; + case 0x09: sprintf(buffer, "tgeiu [invalid]"); break; + case 0x0a: sprintf(buffer, "tlti [invalid]"); break; + case 0x0b: sprintf(buffer, "tltiu [invalid]"); break; + case 0x0c: sprintf(buffer, "teqi [invalid]"); break; + case 0x0e: sprintf(buffer, "tnei [invalid]"); break; + case 0x10: sprintf(buffer, "bltzal %s,$%08x", reg[rs], pc + 4 + ((INT16)op << 2)); flags = DASMFLAG_STEP_OVER | DASMFLAG_STEP_OVER_EXTRA(1); break; + case 0x11: sprintf(buffer, "bgezal %s,$%08x", reg[rs], pc + 4 + ((INT16)op << 2)); flags = DASMFLAG_STEP_OVER | DASMFLAG_STEP_OVER_EXTRA(1); break; + case 0x12: sprintf(buffer, "bltzall [invalid]"); break; + case 0x13: sprintf(buffer, "bgezall [invalid]"); break; + default: sprintf(buffer, "dc.l $%08x [invalid]", op); break; + } + break; + + case 0x02: sprintf(buffer, "j $%08x", (pc & 0xf0000000) | ((op & 0x0fffffff) << 2)); break; + case 0x03: sprintf(buffer, "jal $%08x", (pc & 0xf0000000) | ((op & 0x0fffffff) << 2)); flags = DASMFLAG_STEP_OVER | DASMFLAG_STEP_OVER_EXTRA(1); break; + case 0x04: if (rs == 0 && rt == 0) + sprintf(buffer, "b $%08x", pc + 4 + ((INT16)op << 2)); + else + sprintf(buffer, "beq %s,%s,$%08x", reg[rs], reg[rt], pc + 4 + ((INT16)op << 2));break; + case 0x05: sprintf(buffer, "bne %s,%s,$%08x", reg[rs], reg[rt], pc + 4 + ((INT16)op << 2));break; + case 0x06: sprintf(buffer, "blez %s,$%08x", reg[rs], pc + 4 + ((INT16)op << 2)); break; + case 0x07: sprintf(buffer, "bgtz %s,$%08x", reg[rs], pc + 4 + ((INT16)op << 2)); break; + case 0x08: sprintf(buffer, "addi %s,%s,%s", reg[rt], reg[rs], signed_16bit(op)); break; + case 0x09: sprintf(buffer, "addiu %s,%s,%s", reg[rt], reg[rs], signed_16bit(op)); break; + case 0x0a: sprintf(buffer, "slti %s,%s,%s", reg[rt], reg[rs], signed_16bit(op)); break; + case 0x0b: sprintf(buffer, "sltiu %s,%s,%s", reg[rt], reg[rs], signed_16bit(op)); break; + case 0x0c: sprintf(buffer, "andi %s,%s,$%04x", reg[rt], reg[rs], (UINT16)op); break; + case 0x0d: sprintf(buffer, "ori %s,%s,$%04x", reg[rt], reg[rs], (UINT16)op); break; + case 0x0e: sprintf(buffer, "xori %s,%s,$%04x", reg[rt], reg[rs], (UINT16)op); break; + case 0x0f: sprintf(buffer, "lui %s,$%04x", reg[rt], (UINT16)op); break; + case 0x10: flags = dasm_cop(pc, 0, op, buffer); break; + case 0x11: flags = dasm_cop1(pc, op, buffer); break; + case 0x12: flags = dasm_cop(pc, 2, op, buffer); break; + case 0x13: flags = dasm_cop(pc, 3, op, buffer); break; + case 0x14: sprintf(buffer, "beql [invalid]"); break; + case 0x15: sprintf(buffer, "bnel [invalid]"); break; + case 0x16: sprintf(buffer, "blezl [invalid]"); break; + case 0x17: sprintf(buffer, "bgtzl [invalid]"); break; + case 0x20: sprintf(buffer, "lb %s,%s(%s)", reg[rt], signed_16bit(op), reg[rs]); break; + case 0x21: sprintf(buffer, "lh %s,%s(%s)", reg[rt], signed_16bit(op), reg[rs]); break; + case 0x22: sprintf(buffer, "lwl %s,%s(%s)", reg[rt], signed_16bit(op), reg[rs]); break; + case 0x23: sprintf(buffer, "lw %s,%s(%s)", reg[rt], signed_16bit(op), reg[rs]); break; + case 0x24: sprintf(buffer, "lbu %s,%s(%s)", reg[rt], signed_16bit(op), reg[rs]); break; + case 0x25: sprintf(buffer, "lhu %s,%s(%s)", reg[rt], signed_16bit(op), reg[rs]); break; + case 0x26: sprintf(buffer, "lwr %s,%s(%s)", reg[rt], signed_16bit(op), reg[rs]); break; + case 0x28: sprintf(buffer, "sb %s,%s(%s)", reg[rt], signed_16bit(op), reg[rs]); break; + case 0x29: sprintf(buffer, "sh %s,%s(%s)", reg[rt], signed_16bit(op), reg[rs]); break; + case 0x2a: sprintf(buffer, "swl %s,%s(%s)", reg[rt], signed_16bit(op), reg[rs]); break; + case 0x2b: sprintf(buffer, "sw %s,%s(%s)", reg[rt], signed_16bit(op), reg[rs]); break; + case 0x2e: sprintf(buffer, "swr %s,%s(%s)", reg[rt], signed_16bit(op), reg[rs]); break; + case 0x2f: sprintf(buffer, "cache [invalid]"); break; + case 0x30: sprintf(buffer, "ll [invalid]"); break; + case 0x31: sprintf(buffer, "lwc1 %s,%s(%s)", cpreg[1][rt], signed_16bit(op), reg[rs]); break; + case 0x32: sprintf(buffer, "lwc2 %s,%s(%s)", cpreg[2][rt], signed_16bit(op), reg[rs]); break; + case 0x33: sprintf(buffer, "lwc3 %s,%s(%s)", cpreg[3][rt], signed_16bit(op), reg[rs]); break; + case 0x34: sprintf(buffer, "ldc0 [invalid]"); break; + case 0x35: sprintf(buffer, "ldc1 [invalid]"); break; + case 0x36: sprintf(buffer, "ldc2 [invalid]"); break; + case 0x37: sprintf(buffer, "ldc3 [invalid]"); break; + case 0x38: sprintf(buffer, "sc [invalid]"); break; + case 0x39: sprintf(buffer, "swc1 %s,%s(%s)", cpreg[1][rt], signed_16bit(op), reg[rs]); break; + case 0x3a: sprintf(buffer, "swc2 %s,%s(%s)", cpreg[2][rt], signed_16bit(op), reg[rs]); break; + case 0x3b: sprintf(buffer, "swc3 %s,%s(%s)", cpreg[3][rt], signed_16bit(op), reg[rs]); break; + case 0x3c: sprintf(buffer, "sdc0 [invalid]"); break; + case 0x3d: sprintf(buffer, "sdc1 [invalid]"); break; + case 0x3e: sprintf(buffer, "sdc2 [invalid]"); break; + case 0x3f: sprintf(buffer, "sdc3 [invalid]"); break; + default: sprintf(buffer, "dc.l $%08x [invalid]", op); break; + } + return 4 | flags | DASMFLAG_SUPPORTED; +} + + +CPU_DISASSEMBLE( r3000be ) +{ + UINT32 op = *(UINT32 *)oprom; + op = BIG_ENDIANIZE_INT32(op); + return dasmr3k(buffer, pc, op); +} + + +CPU_DISASSEMBLE( r3000le ) +{ + UINT32 op = *(UINT32 *)oprom; + op = LITTLE_ENDIANIZE_INT32(op); + return dasmr3k(buffer, pc, op); +} diff --git a/src/devices/cpu/mn10200/mn10200.c b/src/devices/cpu/mn10200/mn10200.c new file mode 100644 index 00000000000..bf00be5b984 --- /dev/null +++ b/src/devices/cpu/mn10200/mn10200.c @@ -0,0 +1,2230 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert, R. Belmont, hap +/* + Panasonic MN10200 emulator + + Written by Olivier Galibert + Peripherals and improvements by R. Belmont and hap + +*/ + +#include "emu.h" +#include "debugger.h" +#include "mn10200.h" + +#define log_write(...) +#define log_event(...) + +enum mn10200_flag +{ + FLAG_ZF = 0x0001, // zero flag + FLAG_NF = 0x0002, // negative flag + FLAG_CF = 0x0004, // carry flag + FLAG_VF = 0x0008, // overflow flag + FLAG_ZX = 0x0010, // extended zero flag + FLAG_NX = 0x0020, // extended negative flag + FLAG_CX = 0x0040, // extended carry flag + FLAG_VX = 0x0080, // extended overflow flag + FLAG_IM0 = 0x0100, // interrupt mask + FLAG_IM1 = 0x0200, // " + FLAG_IM2 = 0x0400, // " + FLAG_IE = 0x0800, // interrupt enable + FLAG_S0 = 0x1000, // software bit + FLAG_S1 = 0x2000, // software bit + FLAG_D14 = 0x4000, // ? + FLAG_D15 = 0x8000 // ? +}; + + +const device_type MN1020012A = &device_creator; + +// internal memory maps +static ADDRESS_MAP_START( mn1020012a_internal_map, AS_PROGRAM, 16, mn10200_device ) + AM_RANGE(0x00fc00, 0x00ffff) AM_READWRITE8(io_control_r, io_control_w, 0xffff) +ADDRESS_MAP_END + + +// device definitions +mn1020012a_device::mn1020012a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : mn10200_device(mconfig, MN1020012A, "MN1020012A", tag, owner, clock, ADDRESS_MAP_NAME(mn1020012a_internal_map), "mn1020012a", __FILE__) +{ } + + +// disasm +void mn10200_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + switch (entry.index()) + { + case STATE_GENFLAGS: + strprintf(str, "S=%d irq=%s im=%d %c%c%c%c %c%c%c%c", + (m_psw >> 12) & 3, + m_psw & FLAG_IE ? "on " : "off", + (m_psw >> 8) & 7, + m_psw & FLAG_VX ? 'V' : '-', + m_psw & FLAG_CX ? 'C' : '-', + m_psw & FLAG_NX ? 'N' : '-', + m_psw & FLAG_ZX ? 'Z' : '-', + m_psw & FLAG_VF ? 'v' : '-', + m_psw & FLAG_CF ? 'c' : '-', + m_psw & FLAG_NF ? 'n' : '-', + m_psw & FLAG_ZF ? 'z' : '-'); + break; + } +} + +offs_t mn10200_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( mn10200 ); + return CPU_DISASSEMBLE_NAME(mn10200)(this, buffer, pc, oprom, opram, options); +} + + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +enum +{ + MN10200_PC = 0, + MN10200_PSW, + MN10200_MDR, + MN10200_D0, + MN10200_D1, + MN10200_D2, + MN10200_D3, + MN10200_A0, + MN10200_A1, + MN10200_A2, + MN10200_A3, + MN10200_NMICR, + MN10200_IAGR +}; + +void mn10200_device::device_start() +{ + m_program = &space(AS_PROGRAM); + + // resolve callbacks + m_read_port0.resolve_safe(0xff); + m_read_port1.resolve_safe(0xff); + m_read_port2.resolve_safe(0xff); + m_read_port3.resolve_safe(0xff); + m_read_port4.resolve_safe(0xff); + + m_write_port0.resolve_safe(); + m_write_port1.resolve_safe(); + m_write_port2.resolve_safe(); + m_write_port3.resolve_safe(); + m_write_port4.resolve_safe(); + + // init and register for savestates + save_item(NAME(m_pc)); + save_item(NAME(m_d)); + save_item(NAME(m_a)); + save_item(NAME(m_psw)); + save_item(NAME(m_mdr)); + + // interrupts + memset(&m_icrl, 0, sizeof(m_icrl)); + memset(&m_icrh, 0, sizeof(m_icrh)); + + save_item(NAME(m_nmicr)); + save_item(NAME(m_iagr)); + save_item(NAME(m_extmdl)); + save_item(NAME(m_extmdh)); + save_item(NAME(m_icrl)); + save_item(NAME(m_icrh)); + save_item(NAME(m_possible_irq)); + + // timers + m_sysclock_base = attotime::from_hz(unscaled_clock() / 2); + + for (int tmr = 0; tmr < MN10200_NUM_TIMERS_8BIT; tmr++) + { + m_timer_timers[tmr] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(mn10200_device::simple_timer_cb), this)); + m_timer_timers[tmr]->adjust(attotime::never, tmr); + } + + for (int i = 0; i < MN10200_NUM_TIMERS_8BIT; i++) + { + m_simple_timer[i].mode = 0; + m_simple_timer[i].base = 0; + m_simple_timer[i].cur = 0; + + save_item(NAME(m_simple_timer[i].mode), i); + save_item(NAME(m_simple_timer[i].base), i); + save_item(NAME(m_simple_timer[i].cur), i); + } + + for (int i = 0; i < MN10200_NUM_PRESCALERS; i++) + { + m_prescaler[i].mode = 0; + m_prescaler[i].base = 0; + m_prescaler[i].cur = 0; + + save_item(NAME(m_prescaler[i].mode), i); + save_item(NAME(m_prescaler[i].base), i); + save_item(NAME(m_prescaler[i].cur), i); + } + + // dma + for (int i = 0; i < 8; i++) + { + m_dma[i].adr = 0; + m_dma[i].count = 0; + m_dma[i].iadr = 0; + m_dma[i].ctrll = 0; + m_dma[i].ctrlh = 0; + m_dma[i].irq = 0; + + save_item(NAME(m_dma[i].adr), i); + save_item(NAME(m_dma[i].count), i); + save_item(NAME(m_dma[i].iadr), i); + save_item(NAME(m_dma[i].ctrll), i); + save_item(NAME(m_dma[i].ctrlh), i); + save_item(NAME(m_dma[i].irq), i); + } + + // serial + for (int i = 0; i < 2; i++) + { + m_serial[i].ctrll = 0; + m_serial[i].ctrlh = 0; + m_serial[i].buf = 0; + + save_item(NAME(m_serial[i].ctrll), i); + save_item(NAME(m_serial[i].ctrlh), i); + save_item(NAME(m_serial[i].buf), i); + } + + // ports + m_p4 = 0xf; + + save_item(NAME(m_pplul)); + save_item(NAME(m_ppluh)); + save_item(NAME(m_p3md)); + save_item(NAME(m_p4)); + + for (int i = 0; i < 4; i++) + { + m_port[i].out = 0; + m_port[i].dir = 0; + + save_item(NAME(m_port[i].out), i); + save_item(NAME(m_port[i].dir), i); + } + + // register for debugger + state_add( MN10200_PC, "PC", m_pc ).mask(0xffffff).formatstr("%06X"); + state_add( MN10200_MDR, "MDR", m_mdr).formatstr("%04X"); + state_add( MN10200_D0, "D0", m_d[0]).mask(0xffffff).formatstr("%06X"); + state_add( MN10200_D1, "D1", m_d[1]).mask(0xffffff).formatstr("%06X"); + state_add( MN10200_D2, "D2", m_d[2]).mask(0xffffff).formatstr("%06X"); + state_add( MN10200_D3, "D3", m_d[3]).mask(0xffffff).formatstr("%06X"); + state_add( MN10200_A0, "A0", m_a[0]).mask(0xffffff).formatstr("%06X"); + state_add( MN10200_A1, "A1", m_a[1]).mask(0xffffff).formatstr("%06X"); + state_add( MN10200_A2, "A2", m_a[2]).mask(0xffffff).formatstr("%06X"); + state_add( MN10200_A3, "A3", m_a[3]).mask(0xffffff).formatstr("%06X"); + state_add( MN10200_NMICR, "MNICR", m_nmicr).formatstr("%02X"); + state_add( MN10200_IAGR, "IAGR", m_iagr).formatstr("%02X"); + + state_add( STATE_GENPC, "GENPC", m_pc ).noshow(); + state_add( STATE_GENFLAGS, "GENFLAGS", m_psw).formatstr("%26s").noshow(); + + m_icountptr = &m_cycles; +} + + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void mn10200_device::device_reset() +{ + change_pc(0x80000); + m_psw = 0; + + // note: officially, these registers are reset to 'undefined' + memset(m_d, 0, sizeof(m_d)); + memset(m_a, 0, sizeof(m_a)); + m_mdr = 0; + + // reset internal peripherals + m_nmicr = 0; + m_iagr = 0; + write_mem16(0xfc00, 0x8000); + write_mem16(0xfc02, 0x0737); + + // need to clear them twice since some rely on the value of others + for (int i = 0; i < 2; i++) + for (int address = 0xfc04; address < 0x10000; address++) + write_mem16(address, 0); + + m_possible_irq = false; +} + + + +//------------------------------------------------- +// interrupts +//------------------------------------------------- + +void mn10200_device::take_irq(int level, int group) +{ + m_cycles -= 7; + + write_mem24(m_a[3] - 4, m_pc); + write_mem16(m_a[3] - 6, m_psw); + m_a[3] -= 6; + change_pc(0x80008); + m_psw = (m_psw & 0xf0ff) | (level << 8); + m_iagr = group; +} + +void mn10200_device::check_irq() +{ + if (!m_nmicr && !(m_psw & FLAG_IE)) + return; + + int level = m_psw >> 8 & 7; + int group = 0; + + // find highest valid level + for (int i = 1; i < 11; i++) + { + if (m_icrl[i] >> 4 & m_icrh[i] & 0xf && (m_icrh[i] >> 4 & 7) < level) + { + level = m_icrh[i] >> 4 & 7; + group = i; + } + } + + // take interrupt + if (m_nmicr && group) + take_irq(level, 0); + else if (m_nmicr) + take_irq(0, 0); + else if (group) + take_irq(level, group); + + return; +} + +void mn10200_device::check_ext_irq() +{ + for (int i = 0; i < 4; i++) + { + // active irq at low or high? (not edge triggered) + if ((m_p4 >> i & 1) == (m_extmdl >> (i * 2) & 3)) + m_icrl[8] |= (1 << (4 + i)); + } + + m_possible_irq = true; +} + +void mn10200_device::execute_set_input(int irqnum, int state) +{ + // take an external IRQ + assert(((UINT32)irqnum) < MN10200_MAX_EXT_IRQ); + + int pin = state ? 0 : 1; + int old = m_p4 >> irqnum & 1; + bool active = false; + + switch (m_extmdl >> (irqnum * 2) & 3) + { + // 'L' level + case 0: + active = (pin == 0); + break; + + // 'H' level + case 1: + active = (pin == 1); + break; + + // falling edge + case 2: + active = (pin == 0 && old == 1); + break; + + // rising edge + case 3: + active = (pin == 1 && old == 0); + break; + } + + m_p4 &= ~(1 << irqnum); + m_p4 |= pin << irqnum; + + if (active) + { + m_icrl[8] |= (1 << (4 + irqnum)); + m_possible_irq = true; + } +} + + + +//------------------------------------------------- +// timers +//------------------------------------------------- + +int mn10200_device::timer_tick_simple(int tmr) +{ + int next = tmr + 1; + + // is it a cascaded timer, and enabled? + if (next < MN10200_NUM_TIMERS_8BIT && m_simple_timer[next].mode & 0x83 && (m_simple_timer[next].mode & 0x83) == 0x81) + { + // did it underflow? + if (--m_simple_timer[next].cur == 0xff) + { + // cascaded underflow? + if (timer_tick_simple(next) != 2) + { + m_simple_timer[next].cur = m_simple_timer[next].base; + return 1; + } + } + + return 2; + } + else + { + // trigger irq + m_icrl[1 + (tmr >> 2)] |= (1 << (4 + (tmr & 3))); + m_possible_irq = true; + + return 0; + } +} + +void mn10200_device::refresh_timer(int tmr) +{ + // 0: external pin + // 1: cascaded (handled elsewhere) + // 2: prescaler 0 + // 3: prescaler 1 + int p = m_simple_timer[tmr].mode & 1; + + // enabled, and source is prescaler? + if ((m_simple_timer[tmr].mode & 0x82) == 0x82 && m_prescaler[p].mode & 0x80) + { + attotime period = m_sysclock_base * (m_prescaler[p].base + 1) * (m_simple_timer[tmr].cur + 1); + m_timer_timers[tmr]->adjust(period, tmr); + } + else + { + m_timer_timers[tmr]->adjust(attotime::never, tmr); + } +} + +void mn10200_device::refresh_all_timers() +{ + for (int tmr = 0; tmr < MN10200_NUM_TIMERS_8BIT; tmr++) + refresh_timer(tmr); +} + +TIMER_CALLBACK_MEMBER( mn10200_device::simple_timer_cb ) +{ + int tmr = param; + + // handle our expiring and also tick our cascaded children + if (timer_tick_simple(tmr) == 2) + m_simple_timer[tmr].cur = 0xff; // cascaded and no underflow occurred + else + m_simple_timer[tmr].cur = m_simple_timer[tmr].base; + + // refresh this timer + refresh_timer(tmr); +} + + + +//------------------------------------------------- +// opcode helpers +//------------------------------------------------- + +void mn10200_device::illegal(UINT8 prefix, UINT8 op) +{ + logerror("MN10200: illegal opcode %x %x @ PC=%x\n", prefix, op, m_pc); + m_nmicr |= 2; +} + +UINT32 mn10200_device::do_add(UINT32 a, UINT32 b, UINT32 c) +{ + UINT32 r = (a & 0xffffff) + (b & 0xffffff) + c; + + m_psw &= 0xff00; + if ((a^r) & (b^r) & 0x00800000) + m_psw |= FLAG_VX; + if (r & 0x01000000) + m_psw |= FLAG_CX; + if (r & 0x00800000) + m_psw |= FLAG_NX; + if ((r & 0x00ffffff) == 0) + m_psw |= FLAG_ZX; + if ((a^r) & (b^r) & 0x00008000) + m_psw |= FLAG_VF; + if (((a & 0xffff) + (b & 0xffff) + c) & 0x00010000) + m_psw |= FLAG_CF; + if (r & 0x00008000) + m_psw |= FLAG_NF; + if ((r & 0x0000ffff) == 0) + m_psw |= FLAG_ZF; + + return r; +} + +UINT32 mn10200_device::do_sub(UINT32 a, UINT32 b, UINT32 c) +{ + UINT32 r = (a & 0xffffff) - (b & 0xffffff) - c; + + m_psw &= 0xff00; + if ((a^b) & (a^r) & 0x00800000) + m_psw |= FLAG_VX; + if (r & 0x01000000) + m_psw |= FLAG_CX; + if (r & 0x00800000) + m_psw |= FLAG_NX; + if ((r & 0x00ffffff) == 0) + m_psw |= FLAG_ZX; + if ((a^b) & (a^r) & 0x00008000) + m_psw |= FLAG_VF; + if (((a & 0xffff) - (b & 0xffff) - c) & 0x00010000) + m_psw |= FLAG_CF; + if (r & 0x00008000) + m_psw |= FLAG_NF; + if ((r & 0x0000ffff) == 0) + m_psw |= FLAG_ZF; + + return r; +} + +void mn10200_device::test_nz16(UINT16 v) +{ + m_psw &= 0xfff0; + if (v & 0x8000) + m_psw |= FLAG_NF; + if (v == 0) + m_psw |= FLAG_ZF; +} + +void mn10200_device::do_jsr(UINT32 to, UINT32 ret) +{ + m_a[3] -= 4; + write_mem24(m_a[3], ret); + change_pc(to); +} + +void mn10200_device::do_branch(int condition) +{ + if (condition) + { + m_cycles -= 1; + change_pc(m_pc + (INT8)read_arg8(m_pc)); + } +} + + + +//------------------------------------------------- +// execute loop +//------------------------------------------------- + +void mn10200_device::execute_run() +{ + while (m_cycles > 0) + { + // internal peripheral, external pin, or prev instruction may have changed irq state + while (m_possible_irq) + { + m_possible_irq = false; + check_irq(); + } + + debugger_instruction_hook(this, m_pc); + + m_cycles -= 1; + UINT8 op = read_arg8(m_pc); + m_pc += 1; + + // main opcodes + switch (op) + { + // mov dm, (an) + case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: + case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f: + write_mem16(m_a[op>>2&3], m_d[op&3]); + break; + + // movb dm, (an) + case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17: + case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f: + write_mem8(m_a[op>>2&3], m_d[op&3]); // note: error in manual + break; + + // mov (an), dm + case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27: + case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: case 0x2f: + m_d[op&3] = (INT16)read_mem16(m_a[op>>2&3]); + break; + + // movbu (an), dm + 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: + m_d[op&3] = read_mem8(m_a[op>>2&3]); + break; + + // mov dm, (d8, an) + case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: case 0x46: case 0x47: + case 0x48: case 0x49: case 0x4a: case 0x4b: case 0x4c: case 0x4d: case 0x4e: case 0x4f: + write_mem16((m_a[op>>2&3] + (INT8)read_arg8(m_pc)), m_d[op&3]); + m_pc += 1; + break; + + // mov am, (d8, an) + case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x55: case 0x56: case 0x57: + case 0x58: case 0x59: case 0x5a: case 0x5b: case 0x5c: case 0x5d: case 0x5e: case 0x5f: + m_cycles -= 1; + write_mem24((m_a[op>>2&3] + (INT8)read_arg8(m_pc)), m_a[op&3]); + m_pc += 1; + break; + + // mov (d8, an), dm + case 0x60: case 0x61: case 0x62: case 0x63: case 0x64: case 0x65: case 0x66: case 0x67: + case 0x68: case 0x69: case 0x6a: case 0x6b: case 0x6c: case 0x6d: case 0x6e: case 0x6f: + m_d[op&3] = (INT16)read_mem16(m_a[op>>2&3] + (INT8)read_arg8(m_pc)); + m_pc += 1; + break; + + // mov (d8, an), am + 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: + m_cycles -= 1; + m_a[op&3] = read_mem24(m_a[op>>2&3] + (INT8)read_arg8(m_pc)); + m_pc += 1; + break; + + // mov dn, dm + case 0x81: case 0x82: case 0x83: case 0x84: case 0x86: case 0x87: + case 0x88: case 0x89: case 0x8b: case 0x8c: case 0x8d: case 0x8e: + m_d[op&3] = m_d[op>>2&3]; + break; + + // mov imm8, dn + case 0x80: case 0x85: case 0x8a: case 0x8f: + m_d[op&3] = (INT8)read_arg8(m_pc); + m_pc += 1; + break; + + // add dn, dm + case 0x90: case 0x91: case 0x92: case 0x93: case 0x94: case 0x95: case 0x96: case 0x97: + case 0x98: case 0x99: case 0x9a: case 0x9b: case 0x9c: case 0x9d: case 0x9e: case 0x9f: + m_d[op&3] = do_add(m_d[op&3], m_d[op>>2&3]); + break; + + // sub dn, dm + case 0xa0: case 0xa1: case 0xa2: case 0xa3: case 0xa4: case 0xa5: case 0xa6: case 0xa7: + case 0xa8: case 0xa9: case 0xaa: case 0xab: case 0xac: case 0xad: case 0xae: case 0xaf: + m_d[op&3] = do_sub(m_d[op&3], m_d[op>>2&3]); + break; + + // extx dn + case 0xb0: case 0xb1: case 0xb2: case 0xb3: + m_d[op&3] = (INT16)m_d[op&3]; + break; + + // extxu dn + case 0xb4: case 0xb5: case 0xb6: case 0xb7: + m_d[op&3] = (UINT16)m_d[op&3]; + break; + + // extxb dn + case 0xb8: case 0xb9: case 0xba: case 0xbb: + m_d[op&3] = (INT8)m_d[op&3]; + break; + + // extxbu dn + case 0xbc: case 0xbd: case 0xbe: case 0xbf: + m_d[op&3] = (UINT8)m_d[op&3]; + break; + + // mov dn, (abs16) + case 0xc0: case 0xc1: case 0xc2: case 0xc3: + write_mem16(read_arg16(m_pc), m_d[op&3]); + m_pc += 2; + break; + + // movb dn, (abs16) + case 0xc4: case 0xc5: case 0xc6: case 0xc7: + write_mem8(read_arg16(m_pc), m_d[op&3]); + m_pc += 2; + break; + + // mov (abs16), dn + case 0xc8: case 0xc9: case 0xca: case 0xcb: + m_d[op&3] = (INT16)read_mem16(read_arg16(m_pc)); + m_pc += 2; + break; + + // movbu (abs16), dn + case 0xcc: case 0xcd: case 0xce: case 0xcf: + m_d[op&3] = read_mem8(read_arg16(m_pc)); + m_pc += 2; + break; + + // add imm8, an + case 0xd0: case 0xd1: case 0xd2: case 0xd3: + m_a[op&3] = do_add(m_a[op&3], (INT8)read_arg8(m_pc)); + m_pc += 1; + break; + + // add imm8, dn + case 0xd4: case 0xd5: case 0xd6: case 0xd7: + m_d[op&3] = do_add(m_d[op&3], (INT8)read_arg8(m_pc)); + m_pc += 1; + break; + + // cmp imm8, dn + case 0xd8: case 0xd9: case 0xda: case 0xdb: + do_sub(m_d[op&3], (INT8)read_arg8(m_pc)); + m_pc += 1; + break; + + // mov imm16, an + case 0xdc: case 0xdd: case 0xde: case 0xdf: + m_a[op&3] = read_arg16(m_pc); + m_pc += 2; + break; + + // blt label8 + case 0xe0: + do_branch(((m_psw & (FLAG_NF|FLAG_VF)) == FLAG_NF) || ((m_psw & (FLAG_NF|FLAG_VF)) == FLAG_VF)); // (VF^NF)=1 + m_pc += 1; + break; + + // bgt label8 + case 0xe1: + do_branch(((m_psw & (FLAG_ZF|FLAG_NF|FLAG_VF)) == 0) || ((m_psw & (FLAG_ZF|FLAG_NF|FLAG_VF)) == (FLAG_NF|FLAG_VF))); // ((VF^NF)|ZF)=0 + m_pc += 1; + break; + + // bge label8 + case 0xe2: + do_branch(((m_psw & (FLAG_NF|FLAG_VF)) == 0) || ((m_psw & (FLAG_NF|FLAG_VF)) == (FLAG_NF|FLAG_VF))); // (VF^NF)=0 + m_pc += 1; + break; + + // ble label8 + case 0xe3: + do_branch((m_psw & FLAG_ZF) || ((m_psw & (FLAG_NF|FLAG_VF)) == FLAG_NF) || ((m_psw & (FLAG_NF|FLAG_VF)) == FLAG_VF)); // ((VF^NF)|ZF)=1 + m_pc += 1; + break; + + // bcs label8 + case 0xe4: + do_branch(m_psw & FLAG_CF); // CF=1 + m_pc += 1; + break; + + // bhi label8 + case 0xe5: + do_branch(!(m_psw & (FLAG_ZF|FLAG_CF))); // (CF|ZF)=0 + m_pc += 1; + break; + + // bcc label8 + case 0xe6: + do_branch(!(m_psw & FLAG_CF)); // CF=0 + m_pc += 1; + break; + + // bls label8 + case 0xe7: + do_branch(m_psw & (FLAG_ZF|FLAG_CF)); // (CF|ZF)=1 + m_pc += 1; + break; + + // beq label8 + case 0xe8: + do_branch(m_psw & FLAG_ZF); // ZF=1 + m_pc += 1; + break; + + // bne label8 + case 0xe9: + do_branch(!(m_psw & FLAG_ZF)); // ZF=0 + m_pc += 1; + break; + + // bra label8 + case 0xea: + do_branch(); + m_pc += 1; + break; + + // rti + case 0xeb: + m_cycles -= 5; + m_psw = read_mem16(m_a[3]); + change_pc(read_mem24(m_a[3] + 2)); + m_a[3] += 6; + m_possible_irq = true; + break; + + // cmp imm16, an + case 0xec: case 0xed: case 0xee: case 0xef: + do_sub(m_a[op&3], read_arg16(m_pc)); + m_pc += 2; + break; + + // nop + case 0xf6: + break; + + // mov imm16, dn + case 0xf8: case 0xf9: case 0xfa: case 0xfb: + m_d[op&3] = (INT16)read_arg16(m_pc); + m_pc += 2; + break; + + // jmp label16 + case 0xfc: + m_cycles -= 1; + change_pc(m_pc + 2 + (INT16)read_arg16(m_pc)); + break; + + // jsr label16 + case 0xfd: + m_cycles -= 3; + do_jsr(m_pc + 2 + (INT16)read_arg16(m_pc), m_pc + 2); + break; + + // rts + case 0xfe: + m_cycles -= 4; + change_pc(read_mem24(m_a[3])); + m_a[3] += 4; + break; + + default: + illegal(0, op); + m_possible_irq = true; + break; + + + + // extended code f0 (2 bytes) + case 0xf0: + m_cycles -= 1; + op = read_arg8(m_pc); + m_pc += 1; + + switch (op) + { + // jmp (an) + case 0x00: case 0x04: case 0x08: case 0x0c: + m_cycles -= 1; + change_pc(m_a[op>>2&3]); + break; + + // jsr (an) + case 0x01: case 0x05: case 0x09: case 0x0d: + m_cycles -= 3; + do_jsr(m_a[op>>2&3], m_pc); + break; + + // bset dm, (an) + case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27: + case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: case 0x2f: + { + m_cycles -= 3; + UINT8 v = read_mem8(m_a[op>>2&3]); + test_nz16(v & m_d[op&3]); + write_mem8(m_a[op>>2&3], v | m_d[op&3]); + break; + } + + // bclr dm, (an) + 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: + { + m_cycles -= 3; + UINT8 v = read_mem8(m_a[op>>2&3]); + test_nz16(v & m_d[op&3]); + write_mem8(m_a[op>>2&3], v & ~m_d[op&3]); + break; + } + + // movb (di, an), dm + case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: case 0x46: case 0x47: + case 0x48: case 0x49: case 0x4a: case 0x4b: case 0x4c: case 0x4d: case 0x4e: case 0x4f: + case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x55: case 0x56: case 0x57: + case 0x58: case 0x59: case 0x5a: case 0x5b: case 0x5c: case 0x5d: case 0x5e: case 0x5f: + case 0x60: case 0x61: case 0x62: case 0x63: case 0x64: case 0x65: case 0x66: case 0x67: + case 0x68: case 0x69: case 0x6a: case 0x6b: case 0x6c: case 0x6d: case 0x6e: case 0x6f: + case 0x70: case 0x71: case 0x72: case 0x73: case 0x74: case 0x75: case 0x76: case 0x77: + case 0x78: case 0x79: case 0x7a: case 0x7b: case 0x7c: case 0x7d: case 0x7e: case 0x7f: + m_d[op&3] = (INT8)read_mem8(m_a[op>>2&3] + m_d[op>>4&3]); + break; + + // movbu (di, an), dm + case 0x80: case 0x81: case 0x82: case 0x83: case 0x84: case 0x85: case 0x86: case 0x87: + case 0x88: case 0x89: case 0x8a: case 0x8b: case 0x8c: case 0x8d: case 0x8e: case 0x8f: + case 0x90: case 0x91: case 0x92: case 0x93: case 0x94: case 0x95: case 0x96: case 0x97: + case 0x98: case 0x99: case 0x9a: case 0x9b: case 0x9c: case 0x9d: case 0x9e: case 0x9f: + case 0xa0: case 0xa1: case 0xa2: case 0xa3: case 0xa4: case 0xa5: case 0xa6: case 0xa7: + case 0xa8: case 0xa9: case 0xaa: case 0xab: case 0xac: case 0xad: case 0xae: case 0xaf: + case 0xb0: case 0xb1: case 0xb2: case 0xb3: case 0xb4: case 0xb5: case 0xb6: case 0xb7: + case 0xb8: case 0xb9: case 0xba: case 0xbb: case 0xbc: case 0xbd: case 0xbe: case 0xbf: + m_d[op&3] = read_mem8(m_a[op>>2&3] + m_d[op>>4&3]); + break; + + // movb dm, (di, an) + case 0xc0: case 0xc1: case 0xc2: case 0xc3: case 0xc4: case 0xc5: case 0xc6: case 0xc7: + case 0xc8: case 0xc9: case 0xca: case 0xcb: case 0xcc: case 0xcd: case 0xce: case 0xcf: + case 0xd0: case 0xd1: case 0xd2: case 0xd3: case 0xd4: case 0xd5: case 0xd6: case 0xd7: + case 0xd8: case 0xd9: case 0xda: case 0xdb: case 0xdc: case 0xdd: case 0xde: case 0xdf: + case 0xe0: case 0xe1: case 0xe2: case 0xe3: case 0xe4: case 0xe5: case 0xe6: case 0xe7: + case 0xe8: case 0xe9: case 0xea: case 0xeb: case 0xec: case 0xed: case 0xee: case 0xef: + case 0xf0: case 0xf1: case 0xf2: case 0xf3: case 0xf4: case 0xf5: case 0xf6: case 0xf7: + case 0xf8: case 0xf9: case 0xfa: case 0xfb: case 0xfc: case 0xfd: case 0xfe: case 0xff: + write_mem8(m_a[op>>2&3] + m_d[op>>4&3], m_d[op&3]); + break; + + default: + illegal(0xf0, op); + m_possible_irq = true; + break; + } + break; + + + + // extended code f1 (2 bytes) + case 0xf1: + m_cycles -= 1; + op = read_arg8(m_pc); + m_pc += 1; + + switch (op & 0xc0) + { + // mov (di, an), am + case 0x00: + m_cycles -= 1; + m_a[op&3] = read_mem24(m_a[op>>2&3] + m_d[op>>4&3]); + break; + + // mov (di, an), dm + case 0x40: + m_d[op&3] = (INT16)read_mem16(m_a[op>>2&3] + m_d[op>>4&3]); + break; + + // mov am, (di, an) + case 0x80: + m_cycles -= 1; + write_mem24(m_a[op>>2&3] + m_d[op>>4&3], m_a[op&3]); + break; + + // mov dm, (di, an) + case 0xc0: + write_mem16(m_a[op>>2&3] + m_d[op>>4&3], m_d[op&3]); + break; + } + break; + + + + // extended code f2 (2 bytes) + case 0xf2: + m_cycles -= 1; + op = read_arg8(m_pc); + m_pc += 1; + + switch (op & 0xf0) + { + // add dm, an + case 0x00: + m_a[op&3] = do_add(m_a[op&3], m_d[op>>2&3]); + break; + + // sub dm, an + case 0x10: + m_a[op&3] = do_sub(m_a[op&3], m_d[op>>2&3]); + break; + + // cmp dm, an + case 0x20: + do_sub(m_a[op&3], m_d[op>>2&3]); + break; + + // mov dm, an + case 0x30: + m_a[op&3] = m_d[op>>2&3]; + break; + + // add an, am + case 0x40: + m_a[op&3] = do_add(m_a[op&3], m_a[op>>2&3]); + break; + + // sub an, am + case 0x50: + m_a[op&3] = do_sub(m_a[op&3], m_a[op>>2&3]); + break; + + // cmp an, am + case 0x60: + do_sub(m_a[op&3], m_a[op>>2&3]); + break; + + // mov an, am + case 0x70: + m_a[op&3] = m_a[op>>2&3]; + break; + + // addc dn, dm + case 0x80: + { + UINT16 mask0 = ~FLAG_ZF | (m_psw & FLAG_ZF); + m_d[op&3] = do_add(m_d[op&3], m_d[op>>2&3], (m_psw & FLAG_CF) ? 1 : 0); + m_psw &= mask0; // ZF can only be set if it was set before the operation + break; + } + + // subc dn, dm + case 0x90: + { + UINT16 mask0 = ~FLAG_ZF | (m_psw & FLAG_ZF); + m_d[op&3] = do_sub(m_d[op&3], m_d[op>>2&3], (m_psw & FLAG_CF) ? 1 : 0); + m_psw &= mask0; // ZF can only be set if it was set before the operation + break; + } + + // add an, dm + case 0xc0: + m_d[op&3] = do_add(m_d[op&3], m_a[op>>2&3]); + break; + + // sub an, dm + case 0xd0: + m_d[op&3] = do_sub(m_d[op&3], m_a[op>>2&3]); + break; + + // cmp an, dm + case 0xe0: + do_sub(m_d[op&3], m_a[op>>2&3]); + break; + + // mov an, dm + case 0xf0: + m_d[op&3] = m_a[op>>2&3]; + break; + + default: + illegal(0xf2, op); + m_possible_irq = true; + break; + } + break; + + + + // extended code f3 (2 bytes) + case 0xf3: + m_cycles -= 1; + op = read_arg8(m_pc); + m_pc += 1; + + switch (op) + { + // and dn, dm + case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: + case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f: + test_nz16(m_d[op&3] &= 0xff0000 | m_d[op>>2&3]); + break; + + // or dn, dm + case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17: + case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f: + test_nz16(m_d[op&3] |= 0x00ffff & m_d[op>>2&3]); + break; + + // xor dn, dm + case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27: + case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: case 0x2f: + test_nz16(m_d[op&3] ^= 0x00ffff & m_d[op>>2&3]); + break; + + // rol dn + case 0x30: case 0x31: case 0x32: case 0x33: + { + UINT32 d = m_d[op&3]; + test_nz16(m_d[op&3] = (d & 0xff0000) | ((d << 1) & 0x00fffe) | ((m_psw & FLAG_CF) ? 1 : 0)); + if (d & 0x8000) + m_psw |= FLAG_CF; + break; + } + + // ror dn + case 0x34: case 0x35: case 0x36: case 0x37: + { + UINT32 d = m_d[op&3]; + test_nz16(m_d[op&3] = (d & 0xff0000) | ((d >> 1) & 0x007fff) | ((m_psw & FLAG_CF) ? 0x8000 : 0)); + if (d & 1) + m_psw |= FLAG_CF; + break; + } + + // asr dn + case 0x38: case 0x39: case 0x3a: case 0x3b: + { + UINT32 d = m_d[op&3]; + test_nz16(m_d[op&3] = (d & 0xff8000) | ((d >> 1) & 0x007fff)); + if (d & 1) + m_psw |= FLAG_CF; + break; + } + + // lsr dn + case 0x3c: case 0x3d: case 0x3e: case 0x3f: + { + UINT32 d = m_d[op&3]; + test_nz16(m_d[op&3] = (d & 0xff0000) | ((d >> 1) & 0x007fff)); + if (d & 1) + m_psw |= FLAG_CF; + break; + } + + // mul dn, dm + case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: case 0x46: case 0x47: + case 0x48: case 0x49: case 0x4a: case 0x4b: case 0x4c: case 0x4d: case 0x4e: case 0x4f: + { + m_cycles -= 10; + UINT32 res = ((INT16)m_d[op&3]) * ((INT16)m_d[op>>2&3]); + m_d[op&3] = res & 0xffffff; + m_psw &= 0xff00; // f4 is undefined + if (res & 0x80000000) + m_psw |= FLAG_NF; + else if (res == 0) + m_psw |= FLAG_ZF; + m_mdr = res >> 16; + break; + } + + // mulu dn, dm + case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x55: case 0x56: case 0x57: + case 0x58: case 0x59: case 0x5a: case 0x5b: case 0x5c: case 0x5d: case 0x5e: case 0x5f: + { + m_cycles -= 10; + UINT32 res = ((UINT16)m_d[op&3]) * ((UINT16)m_d[op>>2&3]); + m_d[op&3] = res & 0xffffff; + m_psw &= 0xff00; // f4 is undefined + if (res & 0x80000000) + m_psw |= FLAG_NF; + else if (res == 0) + m_psw |= FLAG_ZF; + m_mdr = res >> 16; + break; + } + + // divu dn, dm + case 0x60: case 0x61: case 0x62: case 0x63: case 0x64: case 0x65: case 0x66: case 0x67: + case 0x68: case 0x69: case 0x6a: case 0x6b: case 0x6c: case 0x6d: case 0x6e: case 0x6f: + { + UINT32 n, d, q, r; + m_cycles -= 11; + m_psw &= 0xff00; // f7 may be undefined + + n = (m_mdr << 16) | (UINT16)m_d[op&3]; + d = (UINT16)m_d[op>>2&3]; + if (d == 0) + { + // divide by 0 + m_psw |= FLAG_VF; + break; + } + q = n / d; + r = n % d; + if (q >= 0x10000) + { + // overflow (Dm and MDR are undefined) + m_psw |= FLAG_VF; + break; + } + m_d[op&3] = q; + m_mdr = r; + if (q == 0) + m_psw |= FLAG_ZF | FLAG_ZX; + if (q & 0x8000) + m_psw |= FLAG_NF; + break; + } + + // cmp dn, dm + case 0x90: case 0x91: case 0x92: case 0x93: case 0x94: case 0x95: case 0x96: case 0x97: + case 0x98: case 0x99: case 0x9a: case 0x9b: case 0x9c: case 0x9d: case 0x9e: case 0x9f: + do_sub(m_d[op&3], m_d[op>>2&3]); + break; + + // mov dn, mdr + case 0xc0: case 0xc4: case 0xc8: case 0xcc: + m_mdr = m_d[op>>2&3]; + break; + + // ext dn + case 0xc1: case 0xc5: case 0xc9: case 0xcd: + m_cycles -= 1; + m_mdr = (m_d[op>>2&3] & 0x8000) ? 0xffff : 0x0000; + break; + + // mov dn, psw + case 0xd0: case 0xd4: case 0xd8: case 0xdc: + m_cycles -= 1; + m_psw = m_d[op>>2&3]; + m_possible_irq = true; + break; + + // mov mdr, dn + case 0xe0: case 0xe1: case 0xe2: case 0xe3: + m_d[op&3] = m_mdr; + break; + + // not dn + case 0xe4: case 0xe5: case 0xe6: case 0xe7: + test_nz16(m_d[op&3] ^= 0x00ffff); + break; + + // mov psw, dn + case 0xf0: case 0xf1: case 0xf2: case 0xf3: + m_d[op&3] = m_psw; + break; + + default: + illegal(0xf3, op); + m_possible_irq = true; + break; + } + break; + + + + // extended code f4 (5 bytes) + case 0xf4: + m_cycles -= 1; + op = read_arg8(m_pc); + m_pc += 1; + m_cycles -= 1; + + switch (op) + { + // mov dm, (d24, an) + case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: + case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f: + write_mem16(read_arg24(m_pc) + m_a[op>>2&3], m_d[op&3]); + break; + + // mov am, (d24, an) + case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17: + case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f: + m_cycles -= 1; + write_mem24(read_arg24(m_pc) + m_a[op>>2&3], m_a[op&3]); + break; + + // movb dm, (d24, an) + case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27: + case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: case 0x2f: + write_mem8(read_arg24(m_pc) + m_a[op>>2&3], m_d[op&3]); + break; + + // movx dm, (d24, an) + 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: + m_cycles -= 1; + write_mem24(read_arg24(m_pc) + m_a[op>>2&3], m_d[op&3]); + break; + + // mov dn, (abs24) + case 0x40: case 0x41: case 0x42: case 0x43: + write_mem16(read_arg24(m_pc), m_d[op&3]); + break; + + // movb dn, (abs24) + case 0x44: case 0x45: case 0x46: case 0x47: + write_mem8(read_arg24(m_pc), m_d[op&3]); + break; + + // mov an, (abs24) + case 0x50: case 0x51: case 0x52: case 0x53: + m_cycles -= 1; + write_mem24(read_arg24(m_pc), m_a[op&3]); + break; + + // add imm24, dn + case 0x60: case 0x61: case 0x62: case 0x63: + m_d[op&3] = do_add(m_d[op&3], read_arg24(m_pc)); + break; + + // add imm24, an + case 0x64: case 0x65: case 0x66: case 0x67: + m_a[op&3] = do_add(m_a[op&3], read_arg24(m_pc)); + break; + + // sub imm24, dn + case 0x68: case 0x69: case 0x6a: case 0x6b: + m_d[op&3] = do_sub(m_d[op&3], read_arg24(m_pc)); + break; + + // sub imm24, an + case 0x6c: case 0x6d: case 0x6e: case 0x6f: + m_a[op&3] = do_sub(m_a[op&3], read_arg24(m_pc)); + break; + + // mov imm24, dn + case 0x70: case 0x71: case 0x72: case 0x73: + m_d[op&3] = read_arg24(m_pc); + break; + + // mov imm24, an + case 0x74: case 0x75: case 0x76: case 0x77: + m_a[op&3] = read_arg24(m_pc); + break; + + // cmp imm24, dn + case 0x78: case 0x79: case 0x7a: case 0x7b: + do_sub(m_d[op&3], read_arg24(m_pc)); + break; + + // cmp imm24, an + case 0x7c: case 0x7d: case 0x7e: case 0x7f: + do_sub(m_a[op&3], read_arg24(m_pc)); + break; + + // mov (d24, an), dm + 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: + m_d[op&3] = (INT16)read_mem16(m_a[op>>2&3] + read_arg24(m_pc)); + break; + + // movbu (d24, an), dm + case 0x90: case 0x91: case 0x92: case 0x93: case 0x94: case 0x95: case 0x96: case 0x97: + case 0x98: case 0x99: case 0x9a: case 0x9b: case 0x9c: case 0x9d: case 0x9e: case 0x9f: + m_d[op&3] = read_mem8(m_a[op>>2&3] + read_arg24(m_pc)); + break; + + // movb (d24, an), dm + case 0xa0: case 0xa1: case 0xa2: case 0xa3: case 0xa4: case 0xa5: case 0xa6: case 0xa7: + case 0xa8: case 0xa9: case 0xaa: case 0xab: case 0xac: case 0xad: case 0xae: case 0xaf: + m_d[op&3] = (INT8)read_mem8(m_a[op>>2&3] + read_arg24(m_pc)); + break; + + // movx (d24, an), dm + case 0xb0: case 0xb1: case 0xb2: case 0xb3: case 0xb4: case 0xb5: case 0xb6: case 0xb7: + case 0xb8: case 0xb9: case 0xba: case 0xbb: case 0xbc: case 0xbd: case 0xbe: case 0xbf: + m_cycles -= 1; + m_d[op&3] = read_mem24(m_a[op>>2&3] + read_arg24(m_pc)); + break; + + // mov (abs24), dn + case 0xc0: case 0xc1: case 0xc2: case 0xc3: + m_d[op&3] = (INT16)read_mem16(read_arg24(m_pc)); + break; + + // movb (abs24), dn + case 0xc4: case 0xc5: case 0xc6: case 0xc7: + m_d[op&3] = (INT8)read_mem8(read_arg24(m_pc)); + break; + + // movbu (abs24), dn + case 0xc8: case 0xc9: case 0xca: case 0xcb: + m_d[op&3] = read_mem8(read_arg24(m_pc)); + break; + + // mov (abs24), an + case 0xd0: case 0xd1: case 0xd2: case 0xd3: + m_cycles -= 1; + m_a[op&3] = read_mem24(read_arg24(m_pc)); + break; + + // jmp label24 + case 0xe0: + m_cycles -= 1; + change_pc(m_pc + read_arg24(m_pc)); + break; + + // jsr label24 + case 0xe1: + m_cycles -= 2; + do_jsr(m_pc + read_arg24(m_pc), m_pc + 3); + break; + + // mov (d24, an), am + 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: + m_cycles -= 1; + m_a[op&3] = read_mem24(m_a[op>>2&3] + read_arg24(m_pc)); + break; + + default: + illegal(0xf4, op); + m_possible_irq = true; + break; + } + m_pc += 3; + break; + + + + // extended code f5 (3 bytes) + case 0xf5: + m_cycles -= 1; + op = read_arg8(m_pc); + m_pc += 1; + + switch (op) + { + // and imm8, dn + case 0x00: case 0x01: case 0x02: case 0x03: + test_nz16(m_d[op&3] &= 0xff0000 | read_arg8(m_pc)); + break; + + // btst imm8, dn + case 0x04: case 0x05: case 0x06: case 0x07: + test_nz16(m_d[op&3] & read_arg8(m_pc)); + break; + + // or imm8, dn + case 0x08: case 0x09: case 0x0a: case 0x0b: + test_nz16(m_d[op&3] |= read_arg8(m_pc)); + break; + + // addnf imm8, an + case 0x0c: case 0x0d: case 0x0e: case 0x0f: + m_a[op&3] = m_a[op&3] + (INT8)read_arg8(m_pc); + break; + + // movb dm, (d8, an) + case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17: + case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f: + write_mem8(m_a[op>>2&3] + (INT8)read_arg8(m_pc), m_d[op&3]); + break; + + // movb (d8, an), dm + case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27: + case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: case 0x2f: + m_d[op&3] = (INT8)read_mem8(m_a[op>>2&3] + (INT8)read_arg8(m_pc)); + break; + + // movbu (d8, an), dm + 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: + m_d[op&3] = read_mem8(m_a[op>>2&3] + (INT8)read_arg8(m_pc)); + break; + + // movx dm, (d8, an) + case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x55: case 0x56: case 0x57: + case 0x58: case 0x59: case 0x5a: case 0x5b: case 0x5c: case 0x5d: case 0x5e: case 0x5f: + m_cycles -= 1; + write_mem24(m_a[op>>2&3] + (INT8)read_arg8(m_pc), m_d[op&3]); + break; + + // movx (d8, an), dm + 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: + m_cycles -= 1; + m_d[op&3] = read_mem24(m_a[op>>2&3] + (INT8)read_arg8(m_pc)); + break; + + // bltx label8 + case 0xe0: + do_branch(((m_psw & (FLAG_NX|FLAG_VX)) == FLAG_NX) || ((m_psw & (FLAG_NX|FLAG_VX)) == FLAG_VX)); // (VX^NX)=1 + break; + + // bgtx label8 + case 0xe1: + do_branch(((m_psw & (FLAG_ZX|FLAG_NX|FLAG_VX)) == 0) || ((m_psw & (FLAG_ZX|FLAG_NX|FLAG_VX)) == (FLAG_NX|FLAG_VX))); // ((VX^NX)|ZX)=0 + break; + + // bgex label8 + case 0xe2: + do_branch(((m_psw & (FLAG_NX|FLAG_VX)) == 0) || ((m_psw & (FLAG_NX|FLAG_VX)) == (FLAG_NX|FLAG_VX))); // (VX^NX)=0 + break; + + // blex label8 + case 0xe3: + do_branch((m_psw & FLAG_ZX) || ((m_psw & (FLAG_NX|FLAG_VX)) == FLAG_NX) || ((m_psw & (FLAG_NX|FLAG_VX)) == FLAG_VX)); // ((VX^NX)|ZX)=1 + break; + + // bcsx label8 + case 0xe4: + do_branch(m_psw & FLAG_CX); // CX=1 + break; + + // bhix label8 + case 0xe5: + do_branch(!(m_psw & (FLAG_ZX|FLAG_CX))); // (CX|ZX)=0 + break; + + // bccx label8 + case 0xe6: + do_branch(!(m_psw & FLAG_CX)); // CX=0 + break; + + // blsx label8 + case 0xe7: + do_branch(m_psw & (FLAG_ZX|FLAG_CX)); // (CX|ZX)=1 + break; + + // beqx label8 + case 0xe8: + do_branch(m_psw & FLAG_ZX); // ZX=1 + break; + + // bnex label8 + case 0xe9: + do_branch(!(m_psw & FLAG_ZX)); // ZX=0 + break; + + // bvcx label8 + case 0xec: + do_branch(!(m_psw & FLAG_VX)); // VX=0 + break; + + // bvsx label8 + case 0xed: + do_branch(m_psw & FLAG_VX); // VX=1 + break; + + // bncx label8 + case 0xee: + do_branch(!(m_psw & FLAG_NX)); // NX=0 + break; + + // bnsx label8 + case 0xef: + do_branch(m_psw & FLAG_NX); // NX=1 + break; + + // bvc label8 + case 0xfc: + do_branch(!(m_psw & FLAG_VF)); // VF=0 + break; + + // bvs label8 + case 0xfd: + do_branch(m_psw & FLAG_VF); // VF=1 + break; + + // bnc label8 + case 0xfe: + do_branch(!(m_psw & FLAG_NF)); // NF=0 + break; + + // bns label8 + case 0xff: + do_branch(m_psw & FLAG_NF); // NF=1 + break; + + default: + illegal(0xf5, op); + m_possible_irq = true; + break; + } + m_pc += 1; + break; + + + + // extended code f7 (4 bytes) + case 0xf7: + m_cycles -= 1; + op = read_arg8(m_pc); + m_pc += 1; + + switch (op) + { + // and imm16, dn + case 0x00: case 0x01: case 0x02: case 0x03: + test_nz16(m_d[op&3] &= 0xff0000 | read_arg16(m_pc)); + break; + + // btst imm16, dn + case 0x04: case 0x05: case 0x06: case 0x07: + test_nz16(m_d[op&3] & read_arg16(m_pc)); + break; + + // add imm16, an + case 0x08: case 0x09: case 0x0a: case 0x0b: + m_a[op&3] = do_add(m_a[op&3], (INT16)read_arg16(m_pc)); + break; + + // sub imm16, an + case 0x0c: case 0x0d: case 0x0e: case 0x0f: + m_a[op&3] = do_sub(m_a[op&3], (INT16)read_arg16(m_pc)); + break; + + // and imm16, psw + case 0x10: + m_cycles -= 1; + m_psw &= read_arg16(m_pc); + break; + + // or imm16, psw + case 0x14: + m_cycles -= 1; + m_psw |= read_arg16(m_pc); + m_possible_irq = true; + break; + + // add imm16, dn + case 0x18: case 0x19: case 0x1a: case 0x1b: + m_d[op&3] = do_add(m_d[op&3], (INT16)read_arg16(m_pc)); + break; + + // sub imm16, dn + case 0x1c: case 0x1d: case 0x1e: case 0x1f: + m_d[op&3] = do_sub(m_d[op&3], (INT16)read_arg16(m_pc)); + break; + + // mov an, (abs16) + case 0x20: case 0x21: case 0x22: case 0x23: + m_cycles -= 1; + write_mem24(read_arg16(m_pc), m_a[op&3]); + break; + + // mov (abs16), an + case 0x30: case 0x31: case 0x32: case 0x33: + m_cycles -= 1; + m_a[op&3] = read_mem24(read_arg16(m_pc)); + break; + + // or imm16, dn + case 0x40: case 0x41: case 0x42: case 0x43: + test_nz16(m_d[op&3] |= read_arg16(m_pc)); + break; + + // cmp imm16, dn + case 0x48: case 0x49: case 0x4a: case 0x4b: + do_sub(m_d[op&3], (INT16)read_arg16(m_pc)); + break; + + // xor imm16, dn + case 0x4c: case 0x4d: case 0x4e: case 0x4f: + test_nz16(m_d[op&3] ^= read_arg16(m_pc)); + break; + + // movbu (d16, an), dm + case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x55: case 0x56: case 0x57: + case 0x58: case 0x59: case 0x5a: case 0x5b: case 0x5c: case 0x5d: case 0x5e: case 0x5f: + m_d[op&3] = read_mem8(m_a[op>>2&3] + (INT16)read_arg16(m_pc)); + break; + + // movx dm, (d16, an) + case 0x60: case 0x61: case 0x62: case 0x63: case 0x64: case 0x65: case 0x66: case 0x67: + case 0x68: case 0x69: case 0x6a: case 0x6b: case 0x6c: case 0x6d: case 0x6e: case 0x6f: + m_cycles -= 1; + write_mem24(m_a[op>>2&3] + (INT16)read_arg16(m_pc), m_d[op&3]); + break; + + // movx (d16, an), dm + 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: + m_cycles -= 1; + m_d[op&3] = read_mem24(m_a[op>>2&3] + (INT16)read_arg16(m_pc)); + break; + + // mov dm, (d16, an) + 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: + write_mem16(m_a[op>>2&3] + (INT16)read_arg16(m_pc), m_d[op&3]); + break; + + // movb dm, (d16, an) + case 0x90: case 0x91: case 0x92: case 0x93: case 0x94: case 0x95: case 0x96: case 0x97: + case 0x98: case 0x99: case 0x9a: case 0x9b: case 0x9c: case 0x9d: case 0x9e: case 0x9f: + write_mem8(m_a[op>>2&3] + (INT16)read_arg16(m_pc), m_d[op&3]); + break; + + // mov am, (d16, an) + case 0xa0: case 0xa1: case 0xa2: case 0xa3: case 0xa4: case 0xa5: case 0xa6: case 0xa7: + case 0xa8: case 0xa9: case 0xaa: case 0xab: case 0xac: case 0xad: case 0xae: case 0xaf: + m_cycles -= 1; + write_mem24(m_a[op>>2&3] + (INT16)read_arg16(m_pc), m_a[op&3]); + break; + + // mov (d16, an), am + case 0xb0: case 0xb1: case 0xb2: case 0xb3: case 0xb4: case 0xb5: case 0xb6: case 0xb7: + case 0xb8: case 0xb9: case 0xba: case 0xbb: case 0xbc: case 0xbd: case 0xbe: case 0xbf: + m_cycles -= 1; + m_a[op&3] = read_mem24(m_a[op>>2&3] + (INT16)read_arg16(m_pc)); + break; + + // mov (d16, an), dm + case 0xc0: case 0xc1: case 0xc2: case 0xc3: case 0xc4: case 0xc5: case 0xc6: case 0xc7: + case 0xc8: case 0xc9: case 0xca: case 0xcb: case 0xcc: case 0xcd: case 0xce: case 0xcf: + m_d[op&3] = (INT16)read_mem16(m_a[op>>2&3] + (INT16)read_arg16(m_pc)); + break; + + // movb (d16, an), dm + case 0xd0: case 0xd1: case 0xd2: case 0xd3: case 0xd4: case 0xd5: case 0xd6: case 0xd7: + case 0xd8: case 0xd9: case 0xda: case 0xdb: case 0xdc: case 0xdd: case 0xde: case 0xdf: + m_d[op&3] = (INT8)read_mem8(m_a[op>>2&3] + (INT16)read_arg16(m_pc)); + break; + + default: + illegal(0xf7, op); + m_possible_irq = true; + break; + } + m_pc += 2; + break; + + } // end main switch + + } // end loop +} + + + +//------------------------------------------------- +// internal i/o +//------------------------------------------------- + +WRITE8_MEMBER(mn10200_device::io_control_w) +{ + switch (offset) + { + case 0x000: + if(data & 12) + { + log_event("CPU", "Stop request"); + } + break; + + case 0x001: + log_event("WATCHDOG", "Write %d", data>>7); + break; + + case 0x002: case 0x003: // Memory control + break; + + case 0x030: case 0x031: // Memory mode reg 0 + case 0x032: case 0x033: // Memory mode reg 1 + case 0x034: case 0x035: // Memory mode reg 2 + case 0x036: case 0x037: // Memory mode reg 3 + break; + + // irq control + // group 0, NMI control + case 0x040: + m_nmicr &= data; // nmi ack + break; + case 0x041: + break; + + // group 1-10, maskable irq control + case 0x042: case 0x044: case 0x046: case 0x048: case 0x04a: + case 0x04c: case 0x04e: case 0x050: case 0x052: case 0x054: + m_icrl[(offset & 0x3f) >> 1] &= data; // irq ack + + // group 8, external irqs might still be active + if (offset == 0x050) + check_ext_irq(); + break; + + case 0x043: case 0x045: case 0x047: case 0x049: case 0x04b: + case 0x04d: case 0x04f: case 0x051: case 0x053: case 0x055: + m_icrh[(offset & 0x3f) >> 1] = data; + m_possible_irq = true; + break; + + // external irq control + case 0x056: + m_extmdl = data; + check_ext_irq(); + break; + case 0x057: + m_extmdh = data & 3; + break; + + case 0x100: case 0x101: // DRAM control reg + case 0x102: case 0x103: // Refresh counter + break; + + case 0x180: case 0x190: + { + int ser = (offset-0x180) >> 4; + // const char *parity[8] = { "no", "1", "2", "3", "l", "h", "even", "odd" }; + // const char *source[4] = { "sbt0", "timer 8", "2", "timer 9" }; + m_serial[ser].ctrll = data; + + // log_event("MN102", "Serial %d length=%c, parity=%s, stop=%c, source=%s", + // ser, + // data & 0x80 ? '8' : '7', parity[(data >> 4) & 7], + // data & 8 ? '2' : '1', source[data & 3]); + break; + } + + case 0x181: case 0x191: + { + int ser = (offset-0x180) >> 4; + m_serial[ser].ctrlh = data; + // log_event("MN102", "Serial %d transmit=%s, receive=%s, break=%s, proto=%s, order=%s", + // ser, + // data & 0x80 ? "on" : "off", data & 0x40 ? "on" : "off", + // data & 0x20 ? "on" : "off", data & 8 ? "sync" : "async", + // data & 2 ? "msb" : "lsb"); + break; + } + + case 0x182: case 0x192: + { + int ser = (offset-0x180) >> 4; + m_serial[ser].buf = data; + log_event("MN102", "Serial %d buffer=%02x", ser, data); + break; + } + + case 0x1a0: + log_event("MN102", "AN %s timer7=%s /%d %s %s", + data & 0x80 ? "on" : "off", data & 0x40 ? "on" : "off", + 1 << ((data >> 2) & 3), data & 2 ? "continuous" : "single", data & 1 ? "one" : "multi"); + break; + + case 0x1a1: + log_event("MN102", "AN chans=0-%d current=%d", (data >> 4) & 7, data & 7); + break; + + // 8-bit timers + // timer base + case 0x210: case 0x211: case 0x212: case 0x213: case 0x214: + case 0x215: case 0x216: case 0x217: case 0x218: case 0x219: + m_simple_timer[offset & 0xf].base = data; + break; + + // prescaler base + case 0x21a: case 0x21b: + m_prescaler[offset & 1].base = data; + break; + + // timer mode + case 0x220: case 0x221: case 0x222: case 0x223: case 0x224: + case 0x225: case 0x226: case 0x227: case 0x228: case 0x229: + m_simple_timer[offset & 0xf].mode = data & 0xc3; + + // reload + if (data & 0x40) + m_simple_timer[offset & 0xf].cur = m_simple_timer[offset & 0xf].base; + + refresh_timer(offset & 0xf); + break; + + // prescaler mode + case 0x22a: case 0x22b: + m_prescaler[offset & 1].mode = data & 0xc0; + + // reload + if (data & 0x40) + m_prescaler[offset & 1].cur = m_prescaler[offset & 1].base; + + refresh_all_timers(); + break; + + case 0x230: case 0x240: case 0x250: + { + // const char *modes[4] = { "single", "double", "ioa", "iob" }; + // const char *sources[8] = { "pres.0", "pres.1", "iob", "sysclk", "*4", "*1", "6", "7" }; + // printf("MN10200: Timer %d comp=%s on_1=%s on_match=%s phase=%s source=%s\n", + // 10 + ((offset-0x230) >> 4), + // modes[data >> 6], data & 0x20 ? "cleared" : "not cleared", data & 0x10 ? "cleared" : "not cleared", + // data & 8 ? "tff" : "rsff", sources[data & 7]); + break; + } + + case 0x231: case 0x241: case 0x251: + { + // const char *modes[4] = { "up", "down", "up on ioa", "up on iob" }; + // printf("MN10200: Timer %d %s ff=%s op=%s ext_trig=%s %s\n", + // 10 + ((offset-0x230) >> 4), + // data & 0x80 ? "enable" : "disable", data & 0x40 ? "operate" : "clear", + // modes[(data >> 4) & 3], data & 2 ? "on" : "off", data & 1 ? "one-shot" : "repeat"); + + break; + } + + case 0x234: case 0x244: case 0x254: + log_event("MN102", "Timer %d ca=--%02x", 10 + ((offset-0x230) >> 4), data); + break; + + case 0x235: case 0x245: case 0x255: + log_event("MN102", "Timer %d ca=%02x--", 10 + ((offset-0x230) >> 4), data); + break; + + case 0x236: case 0x246: case 0x256: + log_event("MN102", "Timer %d ca read trigger", 10 + ((offset-0x230) >> 4)); + break; + + case 0x237: case 0x247: case 0x257: + break; + + case 0x238: case 0x248: case 0x258: + log_event("MN102", "Timer %d cb=--%02x", 10 + ((offset-0x230) >> 4), data); + break; + + case 0x239: case 0x249: case 0x259: + log_event("MN102", "Timer %d cb=%02x--", 10 + ((offset-0x230) >> 4), data); + break; + + case 0x23a: case 0x24a: case 0x25a: + log_event("MN102", "Timer %d cb read trigger", 10 + ((offset-0x230) >> 4)); + break; + + case 0x23b: case 0x24b: case 0x25b: + break; + + case 0x260: case 0x261: + { + // const char *mode[4] = { "sysbuf", "4-phase", "4-phase 1/2", "3" }; + // log_event("MN102", "Sync Output %c timing=%s out=%s dir=%s mode=%s", + // offset == 0x261 ? 'B' : 'A', + // data & 0x10 ? "12A" : "1", data & 8 ? "sync a" :"P13-10", + // data & 4 ? "ccw" : "cw", mode[data & 3]); + break; + } + + case 0x262: + log_event("MN102", "Sync Output buffer = %02x", data); + break; + + case 0x280: case 0x290: case 0x2a0: case 0x2b0: case 0x2c0: case 0x2d0: case 0x2e0: case 0x2f0: + { + int dma = (offset-0x280) >> 4; + m_dma[dma].adr = (m_dma[dma].adr & 0x00ffff00) | data; + logerror("MN10200: DMA %d adr=%06x\n", dma, m_dma[dma].adr); + break; + } + + case 0x281: case 0x291: case 0x2a1: case 0x2b1: case 0x2c1: case 0x2d1: case 0x2e1: case 0x2f1: + { + int dma = (offset-0x280) >> 4; + m_dma[dma].adr = (m_dma[dma].adr & 0x00ff00ff) | (data << 8); + logerror("MN10200: DMA %d adr=%06x\n", dma, m_dma[dma].adr); + break; + } + + case 0x282: case 0x292: case 0x2a2: case 0x2b2: case 0x2c2: case 0x2d2: case 0x2e2: case 0x2f2: + { + int dma = (offset-0x280) >> 4; + m_dma[dma].adr = (m_dma[dma].adr & 0x0000ffff) | (data << 16); + logerror("MN10200: DMA %d adr=%06x\n", dma, m_dma[dma].adr); + break; + } + + case 0x283: case 0x293: case 0x2a3: case 0x2b3: case 0x2c3: case 0x2d3: case 0x2e3: case 0x2f3: + break; + + case 0x284: case 0x294: case 0x2a4: case 0x2b4: case 0x2c4: case 0x2d4: case 0x2e4: case 0x2f4: + { + int dma = (offset-0x280) >> 4; + m_dma[dma].count = (m_dma[dma].count & 0x00ffff00) | data; + logerror("MN10200: DMA %d count=%06x\n", dma, m_dma[dma].count); + break; + } + + case 0x285: case 0x295: case 0x2a5: case 0x2b5: case 0x2c5: case 0x2d5: case 0x2e5: case 0x2f5: + { + int dma = (offset-0x280) >> 4; + m_dma[dma].count = (m_dma[dma].count & 0x00ff00ff) | (data << 8); + logerror("MN10200: DMA %d count=%06x\n", dma, m_dma[dma].count); + break; + } + + case 0x286: case 0x296: case 0x2a6: case 0x2b6: case 0x2c6: case 0x2d6: case 0x2e6: case 0x2f6: + { + int dma = (offset-0x280) >> 4; + m_dma[dma].count = (m_dma[dma].count & 0x0000ffff) | (data << 16); + logerror("MN10200: DMA %d count=%06x\n", dma, m_dma[dma].count); + break; + } + + case 0x287: case 0x297: case 0x2a7: case 0x2b7: case 0x2c7: case 0x2d7: case 0x2e7: case 0x2f7: + break; + + case 0x288: case 0x298: case 0x2a8: case 0x2b8: case 0x2c8: case 0x2d8: case 0x2e8: case 0x2f8: + { + int dma = (offset-0x280) >> 4; + m_dma[dma].iadr = (m_dma[dma].iadr & 0xff00) | data; + logerror("MN10200: DMA %d iadr=%03x\n", dma, m_dma[dma].iadr); + break; + } + + case 0x289: case 0x299: case 0x2a9: case 0x2b9: case 0x2c9: case 0x2d9: case 0x2e9: case 0x2f9: + { + int dma = (offset-0x280) >> 4; + m_dma[dma].iadr = (m_dma[dma].iadr & 0x00ff) | ((data & 3) << 8); + logerror("MN10200: DMA %d iadr=%03x\n", dma, m_dma[dma].iadr); + break; + } + + case 0x28a: case 0x29a: case 0x2aa: case 0x2ba: case 0x2ca: case 0x2da: case 0x2ea: case 0x2fa: + { + static const char *const trans[4] = { "M-IO", "M-M", "M-X1", "m-X2" }; + static const char *const start[32] = + { + "soft", "a/d", "ser0tx", "set0rx", "ser1tx", "ser1rx", + "timer0", "timer1", "timer2", "timer3", "timer4", "timer5", "timer6", "timer7", "timer8", "timer9", + "timer10u", "timer10a", "timer10b", + "timer11u", "timer11a", "timer12b", + "timer12a", "timer12b", + "irq0", "irq1", "irq2", "irq3", + "X0e", "X1e", "X0l", "X1l" + }; + + int dma = (offset-0x280) >> 4; + m_dma[dma].ctrll = data; + logerror("MN10200: DMA %d control ack=%s, trans=%s, start=%s\n", + dma, + data & 0x80 ? "level" : "pulse", + trans[(data >> 5) & 3], + start[data & 31]); + + break; + } + + case 0x28b: case 0x29b: case 0x2ab: case 0x2bb: case 0x2cb: case 0x2db: case 0x2eb: case 0x2fb: + { + static const char *const tradr[4] = { "inc", "dec", "fixed", "reserved" }; + int dma = (offset-0x280) >> 4; + m_dma[dma].ctrlh = data; + logerror("MN10200: DMA %d control %s irq=%s %s %s dir=%s %s %s\n", + dma, + data & 0x80 ? "enable" : "disable", + data & 0x40 ? "off" : "on", + data & 0x20 ? "byte" : "word", + data & 0x10 ? "burst" : "single", + data & 0x08 ? "dst" : "src", + data & 0x04 ? "continue" : "normal", + tradr[data & 3]); + + break; + } + + case 0x28c: case 0x29c: case 0x2ac: case 0x2bc: case 0x2cc: case 0x2dc: case 0x2ec: case 0x2fc: + { + int dma = (offset-0x280) >> 4; + m_dma[dma].irq = data & 7; + logerror("MN10200: DMA %d irq=%d\n", dma, data & 7); + break; + } + + case 0x28d: case 0x29d: case 0x2ad: case 0x2bd: case 0x2cd: case 0x2dd: case 0x2ed: case 0x2fd: + break; + + case 0x3b2: + log_event("MN102", "Timer I/O 4-0 = %c%c%c%c%c", + data & 0x10 ? 'o' : 'i', + data & 0x08 ? 'o' : 'i', + data & 0x04 ? 'o' : 'i', + data & 0x02 ? 'o' : 'i', + data & 0x01 ? 'o' : 'i'); + break; + + case 0x3b3: + log_event("MN102", "Timer I/O 12b/a-10b/a = %c%c %c%c %c%c", + data & 0x20 ? 'o' : 'i', + data & 0x10 ? 'o' : 'i', + data & 0x08 ? 'o' : 'i', + data & 0x04 ? 'o' : 'i', + data & 0x02 ? 'o' : 'i', + data & 0x01 ? 'o' : 'i'); + break; + + // ports + // pull-up control + case 0x3b0: + m_pplul = data & 0x7f; + break; + case 0x3b1: + m_ppluh = data & 0x3f; + break; + + // outputs + case 0x3c0: + m_port[0].out = data; + m_write_port0(MN10200_PORT0, m_port[0].out | (m_port[0].dir ^ 0xff), 0xff); + break; + case 0x264: + m_port[1].out = data; + m_write_port1(MN10200_PORT1, m_port[1].out | (m_port[1].dir ^ 0xff), 0xff); + break; + case 0x3c2: + m_port[2].out = data & 0x0f; + m_write_port2(MN10200_PORT2, m_port[2].out | (m_port[2].dir ^ 0x0f), 0xff); + break; + case 0x3c3: + m_port[3].out = data & 0x1f; + m_write_port3(MN10200_PORT3, m_port[3].out | (m_port[3].dir ^ 0x1f), 0xff); + break; + + // directions (0=input, 1=output) + case 0x3e0: + m_port[0].dir = data; + break; + case 0x3e1: + m_port[1].dir = data; + break; + case 0x3e2: + m_port[2].dir = data & 0x0f; + break; + case 0x3e3: + m_port[3].dir = data & 0x1f; + break; + + // port 3 output mode + case 0x3f3: + m_p3md = data & 0x7f; + break; + + + default: + log_event("MN102", "internal_w %04x, %02x (%03x)", offset+0xfc00, data, adr); + break; + } +} + + +READ8_MEMBER(mn10200_device::io_control_r) +{ + switch (offset) + { + // active irq group + case 0x00e: + return m_iagr << 1; + case 0x00f: + return 0; + + // irq control + // group 0, NMI control + case 0x040: + return m_nmicr; + case 0x041: + return 0; + + // group 1-10, maskable irq control + case 0x042: case 0x044: case 0x046: case 0x048: case 0x04a: + case 0x04c: case 0x04e: case 0x050: case 0x052: case 0x054: + // low 4 bits are a mask of IEN and IRF + return (m_icrl[(offset & 0x3f) >> 1] & 0xf0) | (m_icrl[(offset & 0x3f) >> 1] >> 4 & m_icrh[(offset & 0x3f) >> 1]); + + case 0x043: case 0x045: case 0x047: case 0x049: case 0x04b: + case 0x04d: case 0x04f: case 0x051: case 0x053: case 0x055: + return m_icrh[(offset & 0x3f) >> 1]; + + // external irq control + case 0x056: + return m_extmdl; + case 0x057: + return m_extmdh | (m_p4 << 4); + + case 0x180: case 0x190: + return m_serial[(offset-0x180) >> 4].ctrll; + + case 0x181: case 0x191: + return m_serial[(offset-0x180) >> 4].ctrlh; + + case 0x182: + { + static int zz; + return zz++; + } + + case 0x183: + return 0x10; + + // 8-bit timers + // timer counter (not accurate) + case 0x200: case 0x201: case 0x202: case 0x203: case 0x204: + case 0x205: case 0x206: case 0x207: case 0x208: case 0x209: + return m_simple_timer[offset & 0xf].cur; + + // prescaler counter (not accurate) + case 0x20a: case 0x20b: + return m_prescaler[offset & 1].cur; + + // timer base + case 0x210: case 0x211: case 0x212: case 0x213: case 0x214: + case 0x215: case 0x216: case 0x217: case 0x218: case 0x219: + return m_simple_timer[offset & 0xf].base; + + // prescaler base + case 0x21a: case 0x21b: + return m_prescaler[offset & 1].base; + + // timer mode + case 0x220: case 0x221: case 0x222: case 0x223: case 0x224: + case 0x225: case 0x226: case 0x227: case 0x228: case 0x229: + return m_simple_timer[offset & 0xf].mode; + + // prescaler mode + case 0x22a: case 0x22b: + return m_prescaler[offset & 1].mode; + + case 0x28c: case 0x29c: case 0x2ac: case 0x2bc: case 0x2cc: case 0x2dc: case 0x2ec: case 0x2fc: + { + int dma = (offset-0x280) >> 4; + return m_dma[dma].irq; + } + + // ports + // pull-up control + case 0x3b0: + return m_pplul; + case 0x3b1: + return m_ppluh; + + // outputs + case 0x3c0: + return m_port[0].out; + case 0x264: + return m_port[1].out; + case 0x3c2: + return m_port[2].out; + case 0x3c3: + return m_port[3].out; + + // inputs + case 0x3d0: + return m_read_port0(MN10200_PORT0, 0xff) | m_port[0].dir; + case 0x3d1: + return m_read_port1(MN10200_PORT1, 0xff) | m_port[1].dir; + case 0x3d2: + return (m_read_port2(MN10200_PORT2, 0xff) & 0x0f) | m_port[2].dir; + case 0x3d3: + return (m_read_port3(MN10200_PORT3, 0xff) & 0x1f) | m_port[3].dir; + + // directions (0=input, 1=output) + case 0x3e0: + return m_port[0].dir; + case 0x3e1: + return m_port[1].dir; + case 0x3e2: + return m_port[2].dir; + case 0x3e3: + return m_port[3].dir; + + // port 3 output mode + case 0x3f3: + return m_p3md; + + + default: + log_event("MN102", "internal_r %04x (%03x)", offset+0xfc00, adr); + break; + } + + return 0; +} diff --git a/src/devices/cpu/mn10200/mn10200.h b/src/devices/cpu/mn10200/mn10200.h new file mode 100644 index 00000000000..59be253f852 --- /dev/null +++ b/src/devices/cpu/mn10200/mn10200.h @@ -0,0 +1,218 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert, R. Belmont, hap +/* + Panasonic MN10200 emulator + + Written by Olivier Galibert + MAME conversion by R. Belmont + +*/ + +#ifndef MN10200_H +#define MN10200_H + +// port setup +#define MCFG_MN10200_READ_PORT_CB(X, _devcb) \ + mn10200_device::set_read_port##X##_callback(*device, DEVCB_##_devcb); +#define MCFG_MN10200_WRITE_PORT_CB(X, _devcb) \ + mn10200_device::set_write_port##X##_callback(*device, DEVCB_##_devcb); + +enum +{ + MN10200_PORT0 = 0, + MN10200_PORT1, + MN10200_PORT2, + MN10200_PORT3, + MN10200_PORT4 +}; + +enum +{ + MN10200_IRQ0 = 0, + MN10200_IRQ1, + MN10200_IRQ2, + MN10200_IRQ3, + + MN10200_MAX_EXT_IRQ +}; + + +#define MN10200_NUM_PRESCALERS (2) +#define MN10200_NUM_TIMERS_8BIT (10) +#define MN10200_NUM_IRQ_GROUPS (31) + + +class mn10200_device : public cpu_device +{ +public: + // construction/destruction + mn10200_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, address_map_constructor program, const char *shortname, const char *source) + : cpu_device(mconfig, type, name, tag, owner, clock, shortname, source) + , m_program_config("program", ENDIANNESS_LITTLE, 16, 24, 0, program) + , m_read_port0(*this), m_read_port1(*this), m_read_port2(*this), m_read_port3(*this), m_read_port4(*this) + , m_write_port0(*this), m_write_port1(*this), m_write_port2(*this), m_write_port3(*this), m_write_port4(*this) + { } + + // static configuration helpers + template static devcb_base &set_read_port0_callback(device_t &device, _Object object) { return downcast(device).m_read_port0.set_callback(object); } + template static devcb_base &set_read_port1_callback(device_t &device, _Object object) { return downcast(device).m_read_port1.set_callback(object); } + template static devcb_base &set_read_port2_callback(device_t &device, _Object object) { return downcast(device).m_read_port2.set_callback(object); } + template static devcb_base &set_read_port3_callback(device_t &device, _Object object) { return downcast(device).m_read_port3.set_callback(object); } + template static devcb_base &set_read_port4_callback(device_t &device, _Object object) { return downcast(device).m_read_port4.set_callback(object); } + + template static devcb_base &set_write_port0_callback(device_t &device, _Object object) { return downcast(device).m_write_port0.set_callback(object); } + template static devcb_base &set_write_port1_callback(device_t &device, _Object object) { return downcast(device).m_write_port1.set_callback(object); } + template static devcb_base &set_write_port2_callback(device_t &device, _Object object) { return downcast(device).m_write_port2.set_callback(object); } + template static devcb_base &set_write_port3_callback(device_t &device, _Object object) { return downcast(device).m_write_port3.set_callback(object); } + template static devcb_base &set_write_port4_callback(device_t &device, _Object object) { return downcast(device).m_write_port4.set_callback(object); } + + DECLARE_READ8_MEMBER(io_control_r); + DECLARE_WRITE8_MEMBER(io_control_w); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_execute_interface overrides + virtual UINT64 execute_clocks_to_cycles(UINT64 clocks) const { return (clocks + 2 - 1) / 2; } // internal /2 divider + virtual UINT64 execute_cycles_to_clocks(UINT64 cycles) const { return (cycles * 2); } // internal /2 divider + virtual UINT32 execute_min_cycles() const { return 1; } + virtual UINT32 execute_max_cycles() const { return 13+7; } // max opcode cycles + interrupt duration + virtual UINT32 execute_input_lines() const { return 4; } + virtual void execute_run(); + virtual void execute_set_input(int inputnum, int state); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const { return (spacenum == AS_PROGRAM) ? &m_program_config : NULL; } + + // device_state_interface overrides + void state_string_export(const device_state_entry &entry, std::string &str); + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const { return 1; } + virtual UINT32 disasm_max_opcode_bytes() const { return 7; } + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + +private: + address_space_config m_program_config; + address_space *m_program; + + // i/o handlers + devcb_read8 m_read_port0, m_read_port1, m_read_port2, m_read_port3, m_read_port4; + devcb_write8 m_write_port0, m_write_port1, m_write_port2, m_write_port3, m_write_port4; + + int m_cycles; + + // The UINT32s are really UINT24 + UINT32 m_pc; + UINT32 m_d[4]; + UINT32 m_a[4]; + UINT16 m_psw; + UINT16 m_mdr; + + // interrupts + void take_irq(int level, int group); + void check_irq(); + void check_ext_irq(); + + UINT8 m_icrl[MN10200_NUM_IRQ_GROUPS]; + UINT8 m_icrh[MN10200_NUM_IRQ_GROUPS]; + + UINT8 m_nmicr; + UINT8 m_iagr; + UINT8 m_extmdl; + UINT8 m_extmdh; + bool m_possible_irq; + + // timers + void refresh_timer(int tmr); + void refresh_all_timers(); + int timer_tick_simple(int tmr); + TIMER_CALLBACK_MEMBER( simple_timer_cb ); + + attotime m_sysclock_base; + emu_timer *m_timer_timers[MN10200_NUM_TIMERS_8BIT]; + + struct + { + UINT8 mode; + UINT8 base; + UINT8 cur; + } m_simple_timer[MN10200_NUM_TIMERS_8BIT]; + + struct + { + UINT8 mode; + UINT8 base; + UINT8 cur; + } m_prescaler[MN10200_NUM_PRESCALERS]; + + // dma + struct + { + UINT32 adr; + UINT32 count; + UINT16 iadr; + UINT8 ctrll; + UINT8 ctrlh; + UINT8 irq; + } m_dma[8]; + + // serial + struct + { + UINT8 ctrll; + UINT8 ctrlh; + UINT8 buf; + } m_serial[2]; + + // ports + UINT8 m_pplul; + UINT8 m_ppluh; + UINT8 m_p3md; + UINT8 m_p4; + + struct + { + UINT8 out; + UINT8 dir; + } m_port[4]; + + // internal read/write + inline UINT8 read_arg8(UINT32 address) { return m_program->read_byte(address); } + inline UINT16 read_arg16(UINT32 address) { return m_program->read_byte(address) | m_program->read_byte(address + 1) << 8; } + inline UINT32 read_arg24(UINT32 address) { return m_program->read_byte(address) | m_program->read_byte(address + 1) << 8 | m_program->read_byte(address + 2) << 16; } + + inline UINT8 read_mem8(UINT32 address) { return m_program->read_byte(address); } + inline UINT16 read_mem16(UINT32 address) { return m_program->read_word(address & ~1); } + inline UINT32 read_mem24(UINT32 address) { return m_program->read_word(address & ~1) | m_program->read_byte((address & ~1) + 2) << 16; } + + inline void write_mem8(UINT32 address, UINT8 data) { m_program->write_byte(address, data); } + inline void write_mem16(UINT32 address, UINT16 data) { m_program->write_word(address & ~1, data); } + inline void write_mem24(UINT32 address, UINT32 data) { m_program->write_word(address & ~1, data); m_program->write_byte((address & ~1) + 2, data >> 16); } + + inline void change_pc(UINT32 pc) { m_pc = pc & 0xffffff; } + + // opcode helpers + void illegal(UINT8 prefix, UINT8 op); + UINT32 do_add(UINT32 a, UINT32 b, UINT32 c = 0); + UINT32 do_sub(UINT32 a, UINT32 b, UINT32 c = 0); + void test_nz16(UINT16 v); + void do_jsr(UINT32 to, UINT32 ret); + void do_branch(int condition = 1); +}; + + +class mn1020012a_device : public mn10200_device +{ +public: + mn1020012a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + + +extern const device_type MN1020012A; + + +#endif // MN10200_H diff --git a/src/devices/cpu/mn10200/mn102dis.c b/src/devices/cpu/mn10200/mn102dis.c new file mode 100644 index 00000000000..c3b09b0ed93 --- /dev/null +++ b/src/devices/cpu/mn10200/mn102dis.c @@ -0,0 +1,1038 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert, R. Belmont, hap +/* + Panasonic MN10200 disassembler +*/ + +#include "emu.h" + +#include + +static const UINT8 *sOpROM; // current opROM pointer +static UINT32 sBasePC; + +static UINT8 program_read_byte(offs_t pc) +{ + return sOpROM[pc - sBasePC]; +} + +static UINT32 r16u(offs_t pc) +{ + return sOpROM[pc - sBasePC] | (sOpROM[pc - sBasePC + 1]<<8); +} + +static INT32 r16s(offs_t pc) +{ + return (INT16)(sOpROM[pc - sBasePC] | (sOpROM[pc - sBasePC + 1]<<8)); +} + +static UINT32 r24u(offs_t pc) +{ + return sOpROM[pc - sBasePC] | (sOpROM[pc - sBasePC + 1]<<8) | (sOpROM[pc - sBasePC + 2]<<16); +} + +static INT32 r24s(offs_t pc) +{ + return sOpROM[pc - sBasePC] | (sOpROM[pc - sBasePC + 1]<<8) | ((INT8)sOpROM[pc - sBasePC + 2]<<16); +} + +static const char *i8str(INT8 v) +{ + static char res[0x10]; + if(v>=0) + sprintf(res, "$%x", v); + else + sprintf(res, "-$%x", (UINT8)(-v)); + return res; +} + +static const char *i16str(INT16 v) +{ + static char res[0x10]; + if(v>=0) + sprintf(res, "$%x", v); + else + sprintf(res, "-$%x", (UINT16)(-v)); + return res; +} + +static const char *i24str(INT32 v) +{ + static char res[0x10]; + if(v>=0) + sprintf(res, "$%x", v); + else + sprintf(res, "-$%x", -v); + return res; +} + + +static int mn102_disassemble(char *buffer, UINT32 pc, const UINT8 *oprom) +{ + UINT8 opcode; + + sOpROM = oprom; + sBasePC = pc; + + opcode = program_read_byte(pc); + switch(opcode) + { + case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: + case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f: + sprintf(buffer, "mov d%d, (a%d)", opcode & 3, (opcode>>2) & 3); + return 1; + + case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17: + case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f: + sprintf(buffer, "movb d%d, (a%d)", opcode & 3, (opcode>>2) & 3); + return 1; + + case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27: + case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: case 0x2f: + sprintf(buffer, "mov (a%d), d%d", (opcode>>2) & 3, opcode & 3); + return 1; + + 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: + sprintf(buffer, "movbu (a%d), d%d", (opcode>>2) & 3, opcode & 3); + return 1; + + case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: case 0x46: case 0x47: + case 0x48: case 0x49: case 0x4a: case 0x4b: case 0x4c: case 0x4d: case 0x4e: case 0x4f: + sprintf(buffer, "mov d%d, (%s, a%d)", opcode & 3, i8str(program_read_byte(pc+1)), (opcode>>2) & 3); + return 2; + + case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x55: case 0x56: case 0x57: + case 0x58: case 0x59: case 0x5a: case 0x5b: case 0x5c: case 0x5d: case 0x5e: case 0x5f: + sprintf(buffer, "mov a%d, (%s, a%d)", opcode & 3, i8str(program_read_byte(pc+1)), (opcode>>2) & 3); + return 2; + + case 0x60: case 0x61: case 0x62: case 0x63: case 0x64: case 0x65: case 0x66: case 0x67: + case 0x68: case 0x69: case 0x6a: case 0x6b: case 0x6c: case 0x6d: case 0x6e: case 0x6f: + sprintf(buffer, "mov (%s, a%d), d%d", i8str(program_read_byte(pc+1)), (opcode>>2) & 3, opcode & 3); + return 2; + + case 0x70: case 0x71: case 0x72: case 0x73: case 0x74: case 0x75: case 0x76: case 0x77: + case 0x78: case 0x79: case 0x7a: case 0x7b: case 0x7c: case 0x7d: case 0x7e: case 0x7f: + sprintf(buffer, "mov (%s, a%d), a%d", i8str(program_read_byte(pc+1)), (opcode>>2) & 3, opcode & 3); + return 2; + + case 0x81: case 0x82: case 0x83: case 0x84: case 0x86: case 0x87: + case 0x88: case 0x89: case 0x8b: case 0x8c: case 0x8d: case 0x8e: + sprintf(buffer, "mov d%d, d%d", (opcode>>2) & 3, opcode & 3); + return 1; + + case 0x80: case 0x85: case 0x8a: case 0x8f: + sprintf(buffer, "mov %s, d%d", i8str(program_read_byte(pc+1)), opcode & 3); + return 2; + + case 0x90: case 0x91: case 0x92: case 0x93: case 0x94: case 0x95: case 0x96: case 0x97: + case 0x98: case 0x99: case 0x9a: case 0x9b: case 0x9c: case 0x9d: case 0x9e: case 0x9f: + sprintf(buffer, "add d%d, d%d", (opcode>>2) & 3, opcode & 3); + return 1; + + case 0xa0: case 0xa1: case 0xa2: case 0xa3: case 0xa4: case 0xa5: case 0xa6: case 0xa7: + case 0xa8: case 0xa9: case 0xaa: case 0xab: case 0xac: case 0xad: case 0xae: case 0xaf: + sprintf(buffer, "sub d%d, d%d", (opcode>>2) & 3, opcode & 3); + return 1; + + case 0xb0: case 0xb1: case 0xb2: case 0xb3: + sprintf(buffer, "extx d%d", opcode & 3); + return 1; + + case 0xb4: case 0xb5: case 0xb6: case 0xb7: + sprintf(buffer, "extxu d%d", opcode & 3); + return 1; + + case 0xb8: case 0xb9: case 0xba: case 0xbb: + sprintf(buffer, "extxb d%d", opcode & 3); + return 1; + + case 0xbc: case 0xbd: case 0xbe: case 0xbf: + sprintf(buffer, "extxbu d%d", opcode & 3); + return 1; + + case 0xc0: case 0xc1: case 0xc2: case 0xc3: + sprintf(buffer, "mov d%d, ($%04x)", opcode & 3, r16u(pc+1)); + return 3; + + case 0xc4: case 0xc5: case 0xc6: case 0xc7: + sprintf(buffer, "movb d%d, ($%04x)", opcode & 3, r16u(pc+1)); + return 3; + + case 0xc8: case 0xc9: case 0xca: case 0xcb: + sprintf(buffer, "mov ($%04x), d%d", r16u(pc+1), opcode & 3); + return 3; + + case 0xcc: case 0xcd: case 0xce: case 0xcf: + sprintf(buffer, "movbu ($%04x), d%d", r16u(pc+1), opcode & 3); + return 3; + + case 0xd0: case 0xd1: case 0xd2: case 0xd3: + sprintf(buffer, "add %s, a%d", i8str(program_read_byte(pc+1)), opcode & 3); + return 2; + + case 0xd4: case 0xd5: case 0xd6: case 0xd7: + sprintf(buffer, "add %s, d%d", i8str(program_read_byte(pc+1)), opcode & 3); + return 2; + + case 0xd8: case 0xd9: case 0xda: case 0xdb: + sprintf(buffer, "cmp %s, d%d", i8str(program_read_byte(pc+1)), opcode & 3); + return 2; + + case 0xdc: case 0xdd: case 0xde: case 0xdf: + sprintf(buffer, "move $%04x, a%d", r16u(pc+1), opcode & 3); + return 3; + + case 0xe0: + sprintf(buffer, "blt $%x", (pc+2+(INT8)program_read_byte(pc+1)) & 0xffffff); + return 2; + + case 0xe1: + sprintf(buffer, "bgt $%x", (pc+2+(INT8)program_read_byte(pc+1)) & 0xffffff); + return 2; + + case 0xe2: + sprintf(buffer, "bge $%x", (pc+2+(INT8)program_read_byte(pc+1)) & 0xffffff); + return 2; + + case 0xe3: + sprintf(buffer, "ble $%x", (pc+2+(INT8)program_read_byte(pc+1)) & 0xffffff); + return 2; + + case 0xe4: + sprintf(buffer, "bcs $%x", (pc+2+(INT8)program_read_byte(pc+1)) & 0xffffff); + return 2; + + case 0xe5: + sprintf(buffer, "bhi $%x", (pc+2+(INT8)program_read_byte(pc+1)) & 0xffffff); + return 2; + + case 0xe6: + sprintf(buffer, "bcc $%x", (pc+2+(INT8)program_read_byte(pc+1)) & 0xffffff); + return 2; + + case 0xe7: + sprintf(buffer, "bls $%x", (pc+2+(INT8)program_read_byte(pc+1)) & 0xffffff); + return 2; + + case 0xe8: + sprintf(buffer, "beq $%x", (pc+2+(INT8)program_read_byte(pc+1)) & 0xffffff); + return 2; + + case 0xe9: + sprintf(buffer, "bne $%x", (pc+2+(INT8)program_read_byte(pc+1)) & 0xffffff); + return 2; + + case 0xea: + sprintf(buffer, "bra $%x", (pc+2+(INT8)program_read_byte(pc+1)) & 0xffffff); + return 2; + + case 0xeb: + sprintf(buffer, "rti"); + return 1; + + case 0xec: case 0xed: case 0xee: case 0xef: + sprintf(buffer, "cmp $%04x, a%d", r16u(pc+1), opcode & 3); + return 3; + + case 0xf0: + opcode = program_read_byte(pc+1); + switch(opcode) + { + case 0x00: case 0x04: case 0x08: case 0x0c: + sprintf(buffer, "jmp (a%d)", (opcode>>2) & 3); + return 2; + + case 0x01: case 0x05: case 0x09: case 0x0d: + sprintf(buffer, "jsr (a%d)", (opcode>>2) & 3); + return 2; + + case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27: + case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: case 0x2f: + sprintf(buffer, "bset d%d, (a%d)", opcode & 3, (opcode>>2) & 3); + return 2; + + 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: + sprintf(buffer, "bclr d%d, (a%d)", opcode & 3, (opcode>>2) & 3); + return 2; + + case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: case 0x46: case 0x47: + case 0x48: case 0x49: case 0x4a: case 0x4b: case 0x4c: case 0x4d: case 0x4e: case 0x4f: + case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x55: case 0x56: case 0x57: + case 0x58: case 0x59: case 0x5a: case 0x5b: case 0x5c: case 0x5d: case 0x5e: case 0x5f: + case 0x60: case 0x61: case 0x62: case 0x63: case 0x64: case 0x65: case 0x66: case 0x67: + case 0x68: case 0x69: case 0x6a: case 0x6b: case 0x6c: case 0x6d: case 0x6e: case 0x6f: + case 0x70: case 0x71: case 0x72: case 0x73: case 0x74: case 0x75: case 0x76: case 0x77: + case 0x78: case 0x79: case 0x7a: case 0x7b: case 0x7c: case 0x7d: case 0x7e: case 0x7f: + sprintf(buffer, "movb (d%d, a%d), d%d", (opcode>>4) & 3, (opcode>>2) & 3, opcode & 3); + return 2; + + case 0x80: case 0x81: case 0x82: case 0x83: case 0x84: case 0x85: case 0x86: case 0x87: + case 0x88: case 0x89: case 0x8a: case 0x8b: case 0x8c: case 0x8d: case 0x8e: case 0x8f: + case 0x90: case 0x91: case 0x92: case 0x93: case 0x94: case 0x95: case 0x96: case 0x97: + case 0x98: case 0x99: case 0x9a: case 0x9b: case 0x9c: case 0x9d: case 0x9e: case 0x9f: + case 0xa0: case 0xa1: case 0xa2: case 0xa3: case 0xa4: case 0xa5: case 0xa6: case 0xa7: + case 0xa8: case 0xa9: case 0xaa: case 0xab: case 0xac: case 0xad: case 0xae: case 0xaf: + case 0xb0: case 0xb1: case 0xb2: case 0xb3: case 0xb4: case 0xb5: case 0xb6: case 0xb7: + case 0xb8: case 0xb9: case 0xba: case 0xbb: case 0xbc: case 0xbd: case 0xbe: case 0xbf: + sprintf(buffer, "movbu (d%d, a%d), d%d", (opcode>>4) & 3, (opcode>>2) & 3, opcode & 3); + return 2; + + case 0xc0: case 0xc1: case 0xc2: case 0xc3: case 0xc4: case 0xc5: case 0xc6: case 0xc7: + case 0xc8: case 0xc9: case 0xca: case 0xcb: case 0xcc: case 0xcd: case 0xce: case 0xcf: + case 0xd0: case 0xd1: case 0xd2: case 0xd3: case 0xd4: case 0xd5: case 0xd6: case 0xd7: + case 0xd8: case 0xd9: case 0xda: case 0xdb: case 0xdc: case 0xdd: case 0xde: case 0xdf: + case 0xe0: case 0xe1: case 0xe2: case 0xe3: case 0xe4: case 0xe5: case 0xe6: case 0xe7: + case 0xe8: case 0xe9: case 0xea: case 0xeb: case 0xec: case 0xed: case 0xee: case 0xef: + case 0xf0: case 0xf1: case 0xf2: case 0xf3: case 0xf4: case 0xf5: case 0xf6: case 0xf7: + case 0xf8: case 0xf9: case 0xfa: case 0xfb: case 0xfc: case 0xfd: case 0xfe: case 0xff: + sprintf(buffer, "movb d%d, (d%d, a%d)", opcode & 3, (opcode>>4) & 3, (opcode>>2) & 3); + return 2; + + default: + goto illegal2; + } + + case 0xf1: + opcode = program_read_byte(pc+1); + switch(opcode&0xc0) + { + case 0x00: + sprintf(buffer, "mov (d%d, a%d), a%d", (opcode>>4) & 3, (opcode>>2) & 3, opcode & 3); + return 2; + + case 0x40: + sprintf(buffer, "mov (d%d, a%d), d%d", (opcode>>4) & 3, (opcode>>2) & 3, opcode & 3); + return 2; + + case 0x80: + sprintf(buffer, "mov a%d, (d%d, a%d)", opcode & 3, (opcode>>4) & 3, (opcode>>2) & 3); + return 2; + + case 0xc0: + sprintf(buffer, "mov d%d, (d%d, a%d)", opcode & 3, (opcode>>4) & 3, (opcode>>2) & 3); + return 2; + } + break; + + case 0xf2: + opcode = program_read_byte(pc+1); + switch(opcode&0xf0) + { + case 0x00: + sprintf(buffer, "add d%d, a%d", (opcode>>2) & 3, opcode & 3); + return 2; + + case 0x10: + sprintf(buffer, "sub d%d, a%d", (opcode>>2) & 3, opcode & 3); + return 2; + + case 0x20: + sprintf(buffer, "cmp d%d, a%d", (opcode>>2) & 3, opcode & 3); + return 2; + + case 0x30: + sprintf(buffer, "mov d%d, a%d", (opcode>>2) & 3, opcode & 3); + return 2; + + case 0x40: + sprintf(buffer, "add a%d, a%d", (opcode>>2) & 3, opcode & 3); + return 2; + + case 0x50: + sprintf(buffer, "sub a%d, a%d", (opcode>>2) & 3, opcode & 3); + return 2; + + case 0x60: + sprintf(buffer, "cmp a%d, a%d", (opcode>>2) & 3, opcode & 3); + return 2; + + case 0x70: + sprintf(buffer, "mov a%d, a%d", (opcode>>2) & 3, opcode & 3); + return 2; + + case 0x80: + sprintf(buffer, "addc d%d, d%d", (opcode>>2) & 3, opcode & 3); + return 2; + + case 0x90: + sprintf(buffer, "subc d%d, d%d", (opcode>>2) & 3, opcode & 3); + return 2; + + case 0xc0: + sprintf(buffer, "add a%d, d%d", (opcode>>2) & 3, opcode & 3); + return 2; + + case 0xd0: + sprintf(buffer, "sub a%d, d%d", (opcode>>2) & 3, opcode & 3); + return 2; + + case 0xe0: + sprintf(buffer, "cmp a%d, d%d", (opcode>>2) & 3, opcode & 3); + return 2; + + case 0xf0: + sprintf(buffer, "mov a%d, d%d", (opcode>>2) & 3, opcode & 3); + return 2; + + default: + goto illegal2; + } + + case 0xf3: + opcode = program_read_byte(pc+1); + switch(opcode) + { + case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: + case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f: + sprintf(buffer, "and d%d, d%d", (opcode>>2) & 3, opcode & 3); + return 2; + + case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17: + case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f: + sprintf(buffer, "or d%d, d%d", (opcode>>2) & 3, opcode & 3); + return 2; + + case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27: + case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: case 0x2f: + sprintf(buffer, "xor d%d, d%d", (opcode>>2) & 3, opcode & 3); + return 2; + + case 0x30: case 0x31: case 0x32: case 0x33: + sprintf(buffer, "rol d%d", opcode & 3); + return 2; + + case 0x34: case 0x35: case 0x36: case 0x37: + sprintf(buffer, "ror d%d", opcode & 3); + return 2; + + case 0x38: case 0x39: case 0x3a: case 0x3b: + sprintf(buffer, "asr d%d", opcode & 3); + return 2; + + case 0x3c: case 0x3d: case 0x3e: case 0x3f: + sprintf(buffer, "lsr d%d", opcode & 3); + return 2; + + case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: case 0x46: case 0x47: + case 0x48: case 0x49: case 0x4a: case 0x4b: case 0x4c: case 0x4d: case 0x4e: case 0x4f: + sprintf(buffer, "mul d%d, d%d", (opcode>>2) & 3, opcode & 3); + return 2; + + case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x55: case 0x56: case 0x57: + case 0x58: case 0x59: case 0x5a: case 0x5b: case 0x5c: case 0x5d: case 0x5e: case 0x5f: + sprintf(buffer, "mulu d%d, d%d", (opcode>>2) & 3, opcode & 3); + return 2; + + case 0x60: case 0x61: case 0x62: case 0x63: case 0x64: case 0x65: case 0x66: case 0x67: + case 0x68: case 0x69: case 0x6a: case 0x6b: case 0x6c: case 0x6d: case 0x6e: case 0x6f: + sprintf(buffer, "divu d%d, d%d", (opcode>>2) & 3, opcode & 3); + return 2; + + case 0x90: case 0x91: case 0x92: case 0x93: case 0x94: case 0x95: case 0x96: case 0x97: + case 0x98: case 0x99: case 0x9a: case 0x9b: case 0x9c: case 0x9d: case 0x9e: case 0x9f: + sprintf(buffer, "cmp d%d, d%d", (opcode>>2) & 3, opcode & 3); + return 2; + + case 0xc0: case 0xc4: case 0xc8: case 0xcc: + sprintf(buffer, "mov d%d, mdr", (opcode>>2) & 3); + return 2; + + case 0xc1: case 0xc5: case 0xc9: case 0xcd: + sprintf(buffer, "ext d%d", (opcode>>2) & 3); + return 2; + + case 0xd0: case 0xd4: case 0xd8: case 0xdc: + sprintf(buffer, "mov d%d, psw", (opcode>>2) & 3); + return 2; + + case 0xe0: case 0xe1: case 0xe2: case 0xe3: + sprintf(buffer, "mov mdr, d%d", opcode & 3); + return 2; + + case 0xe4: case 0xe5: case 0xe6: case 0xe7: + sprintf(buffer, "not d%d", opcode & 3); + return 2; + + case 0xf0: case 0xf1: case 0xf2: case 0xf3: + sprintf(buffer, "mov psw, d%d", opcode & 3); + return 2; + + case 0xfc: + sprintf(buffer, "pxst"); + return 2; + + case 0xfe: + opcode = program_read_byte(pc+2); + switch(opcode) + { + case 0xc0: case 0xc1: case 0xc2: case 0xc3: case 0xc4: case 0xc5: case 0xc6: case 0xc7: + sprintf(buffer, "tbz ($%x) %d, $%x", r24u(pc+3), opcode & 7, + (pc+7+(INT8)program_read_byte(pc+6)) & 0xffffff); + return 7; + + case 0xc8: case 0xc9: case 0xca: case 0xcb: case 0xcc: case 0xcd: case 0xce: case 0xcf: + sprintf(buffer, "tbnz ($%x) %d, $%x", r24u(pc+3), opcode & 7, + (pc+7+(INT8)program_read_byte(pc+6)) & 0xffffff); + return 7; + + case 0xd0: case 0xd1: case 0xd2: case 0xd3: case 0xd4: case 0xd5: case 0xd6: case 0xd7: + sprintf(buffer, "bset ($%x) %d", r24u(pc+2), opcode & 7); + return 6; + + case 0xd8: case 0xd9: case 0xda: case 0xdb: case 0xdc: case 0xdd: case 0xde: case 0xdf: + sprintf(buffer, "bclr ($%x) %d", r24u(pc+2), opcode & 7); + return 6; + + default: + goto illegal3; + } + + case 0xff: + opcode = program_read_byte(pc+2); + switch(opcode) + { + case 0x80: case 0x81: case 0x82: case 0x83: case 0x84: case 0x85: case 0x86: case 0x87: + case 0x88: case 0x89: case 0x8a: case 0x8b: case 0x8c: case 0x8d: case 0x8e: case 0x8f: + sprintf(buffer, "tbz (%s, a%d) %d, $%x", i8str(program_read_byte(pc+3)), 2+((opcode>>3)&1), opcode & 7, + (pc+5+(INT8)program_read_byte(pc+4)) & 0xffffff); + return 5; + + case 0x90: case 0x91: case 0x92: case 0x93: case 0x94: case 0x95: case 0x96: case 0x97: + case 0x98: case 0x99: case 0x9a: case 0x9b: case 0x9c: case 0x9d: case 0x9e: case 0x9f: + sprintf(buffer, "bset (%s, a%d) %d", i8str(program_read_byte(pc+3)), 2+((opcode>>3)&1), opcode & 7); + return 4; + + case 0xa0: case 0xa1: case 0xa2: case 0xa3: case 0xa4: case 0xa5: case 0xa6: case 0xa7: + case 0xa8: case 0xa9: case 0xaa: case 0xab: case 0xac: case 0xad: case 0xae: case 0xaf: + sprintf(buffer, "tbnz (%s, a%d) %d, $%x", i8str(program_read_byte(pc+3)), 2+((opcode>>3)&1), opcode & 7, + (pc+5+(INT8)program_read_byte(pc+4)) & 0xffffff); + return 5; + + case 0xb0: case 0xb1: case 0xb2: case 0xb3: case 0xb4: case 0xb5: case 0xb6: case 0xb7: + case 0xb8: case 0xb9: case 0xba: case 0xbb: case 0xbc: case 0xbd: case 0xbe: case 0xbf: + sprintf(buffer, "bclr (%s, a%d) %d", i8str(program_read_byte(pc+3)), 2+((opcode>>3)&1), opcode & 7); + return 4; + + default: + goto illegal3; + } + + default: + goto illegal2; + } + + case 0xf4: + opcode = program_read_byte(pc+1); + switch(opcode) + { + case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: + case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f: + sprintf(buffer, "mov d%d, (%s, a%d)", opcode & 3, i24str(r24s(pc+2)), (opcode>>2) & 3); + return 5; + + case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17: + case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f: + sprintf(buffer, "mov a%d, (%s, a%d)", opcode & 3, i24str(r24s(pc+2)), (opcode>>2) & 3); + return 5; + + case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27: + case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: case 0x2f: + sprintf(buffer, "movb d%d, (%s, a%d)", opcode & 3, i24str(r24s(pc+2)), (opcode>>2) & 3); + return 5; + + 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: + sprintf(buffer, "movx d%d, (%s, a%d)", opcode & 3, i24str(r24s(pc+2)), (opcode>>2) & 3); + return 5; + + case 0x40: case 0x41: case 0x42: case 0x43: + sprintf(buffer, "mov d%d, ($%06x)", opcode & 3, r24u(pc+2)); + return 5; + + case 0x44: case 0x45: case 0x46: case 0x47: + sprintf(buffer, "movb d%d, ($%06x)", opcode & 3, r24u(pc+2)); + return 5; + + case 0x4b: + sprintf(buffer, "bset %02x, ($%06x)", program_read_byte(pc+5), r24u(pc+2)); + return 6; + + case 0x4f: + sprintf(buffer, "bclr %02x, ($%06x)", program_read_byte(pc+5), r24u(pc+2)); + return 6; + + case 0x50: case 0x51: case 0x52: case 0x53: + sprintf(buffer, "mov a%d, ($%06x)", opcode & 3, r24u(pc+2)); + return 5; + + case 0x60: case 0x61: case 0x62: case 0x63: + sprintf(buffer, "add %s, d%d", i24str(r24s(pc+2)), opcode & 3); + return 5; + + case 0x64: case 0x65: case 0x66: case 0x67: + sprintf(buffer, "add %s, a%d", i24str(r24s(pc+2)), opcode & 3); + return 5; + + case 0x68: case 0x69: case 0x6a: case 0x6b: + sprintf(buffer, "sub %s, d%d", i24str(r24s(pc+2)), opcode & 3); + return 5; + + case 0x6c: case 0x6d: case 0x6e: case 0x6f: + sprintf(buffer, "sub %s, a%d", i24str(r24s(pc+2)), opcode & 3); + return 5; + + case 0x70: case 0x71: case 0x72: case 0x73: + sprintf(buffer, "mov %s, d%d", i24str(r24s(pc+2)), opcode & 3); + return 5; + + case 0x74: case 0x75: case 0x76: case 0x77: + sprintf(buffer, "mov $%06x, a%d", r24u(pc+2), opcode & 3); + return 5; + + case 0x78: case 0x79: case 0x7a: case 0x7b: + sprintf(buffer, "cmp %s, d%d", i24str(r24s(pc+2)), opcode & 3); + return 5; + + case 0x7c: case 0x7d: case 0x7e: case 0x7f: + sprintf(buffer, "cmp $%06x, a%d", r24u(pc+2), opcode & 3); + return 5; + + case 0x80: case 0x81: case 0x82: case 0x83: case 0x84: case 0x85: case 0x86: case 0x87: + case 0x88: case 0x89: case 0x8a: case 0x8b: case 0x8c: case 0x8d: case 0x8e: case 0x8f: + sprintf(buffer, "mov (%s, a%d), d%d", i24str(r24s(pc+2)), (opcode>>2) & 3, opcode & 3); + return 5; + + case 0x90: case 0x91: case 0x92: case 0x93: case 0x94: case 0x95: case 0x96: case 0x97: + case 0x98: case 0x99: case 0x9a: case 0x9b: case 0x9c: case 0x9d: case 0x9e: case 0x9f: + sprintf(buffer, "movbu (%s, a%d), d%d", i24str(r24s(pc+2)), (opcode>>2) & 3, opcode & 3); + return 5; + + case 0xa0: case 0xa1: case 0xa2: case 0xa3: case 0xa4: case 0xa5: case 0xa6: case 0xa7: + case 0xa8: case 0xa9: case 0xaa: case 0xab: case 0xac: case 0xad: case 0xae: case 0xaf: + sprintf(buffer, "movb (%s, a%d), d%d", i24str(r24s(pc+2)), (opcode>>2) & 3, opcode & 3); + return 5; + + case 0xb0: case 0xb1: case 0xb2: case 0xb3: case 0xb4: case 0xb5: case 0xb6: case 0xb7: + case 0xb8: case 0xb9: case 0xba: case 0xbb: case 0xbc: case 0xbd: case 0xbe: case 0xbf: + sprintf(buffer, "movx (%s, a%d), d%d", i24str(r24s(pc+2)), (opcode>>2) & 3, opcode & 3); + return 5; + + case 0xc0: case 0xc1: case 0xc2: case 0xc3: + sprintf(buffer, "mov ($%06x), d%d", r24u(pc+2), opcode & 3); + return 5; + + case 0xc4: case 0xc5: case 0xc6: case 0xc7: + sprintf(buffer, "movb ($%06x), d%d", r24u(pc+2), opcode & 3); + return 5; + + case 0xc8: case 0xc9: case 0xca: case 0xcb: + sprintf(buffer, "movbu ($%06x), d%d", r24u(pc+2), opcode & 3); + return 5; + + case 0xd0: case 0xd1: case 0xd2: case 0xd3: + sprintf(buffer, "mov ($%06x), a%d", r24u(pc+2), opcode & 3); + return 5; + + case 0xe0: + sprintf(buffer, "jmp $%x", (pc+5+r24s(pc+2)) & 0xffffff); + return 5; + + case 0xe1: + sprintf(buffer, "jsr $%x", (pc+5+r24s(pc+2)) & 0xffffff); + return 5; + + case 0xe3: + sprintf(buffer, "bset $%02x, ($%x)", program_read_byte(pc+4), r16u(pc+2)); + return 6; + + case 0xe7: + sprintf(buffer, "bclr $%02x, ($%x)", program_read_byte(pc+4), r16u(pc+2)); + return 6; + + case 0xe8: case 0xe9: case 0xea: case 0xeb: + sprintf(buffer, "bset $%02x, (%s, a%d)", program_read_byte(pc+3), i8str(program_read_byte(pc+2)), opcode & 3); + return 4; + + case 0xec: case 0xed: case 0xee: case 0xef: + sprintf(buffer, "bclr $%02x, (%s, a%d)", program_read_byte(pc+3), i8str(program_read_byte(pc+2)), opcode & 3); + return 4; + + 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: + sprintf(buffer, "mov (%s, a%d), a%d", i24str(r24s(pc+2)), (opcode>>2) & 3, opcode & 3); + return 5; + + default: + goto illegal2; + } + + case 0xf5: + opcode = program_read_byte(pc+1); + switch(opcode) + { + case 0x00: case 0x01: case 0x02: case 0x03: + sprintf(buffer, "and $%02x, d%d", program_read_byte(pc+2), opcode & 3); + return 3; + + case 0x04: case 0x05: case 0x06: case 0x07: + sprintf(buffer, "btst $%02x, d%d", program_read_byte(pc+2), opcode & 3); + return 3; + + case 0x08: case 0x09: case 0x0a: case 0x0b: + sprintf(buffer, "or $%02x, d%d", program_read_byte(pc+2), opcode & 3); + return 3; + + case 0x0c: case 0x0d: case 0x0e: case 0x0f: + sprintf(buffer, "addnf %s, a%d", i8str(program_read_byte(pc+2)), opcode & 3); + return 3; + + case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17: + case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f: + sprintf(buffer, "movb d%d, (%s, a%d)", opcode & 3, i8str(program_read_byte(pc+2)), (opcode>>2) & 3); + return 3; + + case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27: + case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: case 0x2f: + sprintf(buffer, "movb (%s, a%d), d%d", i8str(program_read_byte(pc+2)), (opcode>>2) & 3, opcode & 3); + return 3; + + case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37: + case 0x38: case 0x39: case 0x3a: case 0x3b: case 0x3c: case 0x3d: case 0x3e: case 0x3f: + sprintf(buffer, "movbu (%s, a%d), d%d", i8str(program_read_byte(pc+2)), (opcode>>2) & 3, opcode & 3); + return 3; + + case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: case 0x46: case 0x47: + case 0x48: case 0x49: case 0x4a: case 0x4b: case 0x4c: case 0x4d: case 0x4e: case 0x4f: + { + UINT8 opcode2 = program_read_byte(pc+2); + switch(opcode2) + { + case 0x00: + sprintf(buffer, "mulql d%d, d%d", (opcode>>3) & 3, opcode & 3); + return 3; + + case 0x01: + sprintf(buffer, "mulqh d%d, d%d", (opcode>>3) & 3, opcode & 3); + return 3; + + default: + goto illegal3; + } + } + + case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x55: case 0x56: case 0x57: + case 0x58: case 0x59: case 0x5a: case 0x5b: case 0x5c: case 0x5d: case 0x5e: case 0x5f: + sprintf(buffer, "movx d%d, (%s, a%d)", opcode & 3, i8str(program_read_byte(pc+2)), (opcode>>2) & 3); + return 3; + + case 0x60: case 0x61: case 0x62: case 0x63: case 0x64: case 0x65: case 0x66: case 0x67: + case 0x68: case 0x69: case 0x6a: case 0x6b: case 0x6c: case 0x6d: case 0x6e: case 0x6f: + { + UINT8 opcode2 = program_read_byte(pc+2); + switch(opcode2) + { + case 0x10: + sprintf(buffer, "mulq d%d, d%d", (opcode>>3) & 3, opcode & 3); + return 3; + + default: + goto illegal3; + } + } + + case 0x70: case 0x71: case 0x72: case 0x73: case 0x74: case 0x75: case 0x76: case 0x77: + case 0x78: case 0x79: case 0x7a: case 0x7b: case 0x7c: case 0x7d: case 0x7e: case 0x7f: + sprintf(buffer, "movx (%s, a%d), d%d", i8str(program_read_byte(pc+2)), (opcode>>2) & 3, opcode & 3); + return 3; + + case 0x80: case 0x81: case 0x82: case 0x83: case 0x84: case 0x85: case 0x86: case 0x87: + case 0x88: case 0x89: case 0x8a: case 0x8b: case 0x8c: case 0x8d: case 0x8e: case 0x8f: + sprintf(buffer, "tbz (%s, a%d) %d, $%x", i8str(program_read_byte(pc+2)), (opcode>>3)&1, opcode & 7, + (pc+4+(INT8)program_read_byte(pc+3)) & 0xffffff); + return 4; + + case 0x90: case 0x91: case 0x92: case 0x93: case 0x94: case 0x95: case 0x96: case 0x97: + case 0x98: case 0x99: case 0x9a: case 0x9b: case 0x9c: case 0x9d: case 0x9e: case 0x9f: + sprintf(buffer, "bset (%s, a%d) %d", i8str(program_read_byte(pc+2)), (opcode>>3)&1, opcode & 7); + return 3; + + case 0xa0: case 0xa1: case 0xa2: case 0xa3: case 0xa4: case 0xa5: case 0xa6: case 0xa7: + case 0xa8: case 0xa9: case 0xaa: case 0xab: case 0xac: case 0xad: case 0xae: case 0xaf: + sprintf(buffer, "tbnz (%s, a%d) %d, $%x", i8str(program_read_byte(pc+2)), (opcode>>3)&1, opcode & 7, + (pc+4+(INT8)program_read_byte(pc+3)) & 0xffffff); + return 4; + + case 0xb0: case 0xb1: case 0xb2: case 0xb3: case 0xb4: case 0xb5: case 0xb6: case 0xb7: + case 0xb8: case 0xb9: case 0xba: case 0xbb: case 0xbc: case 0xbd: case 0xbe: case 0xbf: + sprintf(buffer, "bclr (%s, a%d) %d", i8str(program_read_byte(pc+2)), (opcode>>3)&1, opcode & 7); + return 3; + + case 0xc0: case 0xc1: case 0xc2: case 0xc3: case 0xc4: case 0xc5: case 0xc6: case 0xc7: + sprintf(buffer, "tbz ($%x) %d, $%x", r16u(pc+2), opcode & 7, + (pc+5+(INT8)program_read_byte(pc+4)) & 0xffffff); + return 5; + + case 0xc8: case 0xc9: case 0xca: case 0xcb: case 0xcc: case 0xcd: case 0xce: case 0xcf: + sprintf(buffer, "tbnz ($%x) %d, $%x", r16u(pc+2), opcode & 7, + (pc+5+(INT8)program_read_byte(pc+4)) & 0xffffff); + return 5; + + case 0xd0: case 0xd1: case 0xd2: case 0xd3: case 0xd4: case 0xd5: case 0xd6: case 0xd7: + sprintf(buffer, "bset ($%x) %d", r16u(pc+2), opcode & 7); + return 4; + + case 0xd8: case 0xd9: case 0xda: case 0xdb: case 0xdc: case 0xdd: case 0xde: case 0xdf: + sprintf(buffer, "bclr ($%x) %d", r16u(pc+2), opcode & 7); + return 4; + + case 0xe0: + sprintf(buffer, "bltx $%x", (pc+3+(INT8)program_read_byte(pc+2)) & 0xffffff); + return 3; + + case 0xe1: + sprintf(buffer, "bgtx $%x", (pc+3+(INT8)program_read_byte(pc+2)) & 0xffffff); + return 3; + + case 0xe2: + sprintf(buffer, "bgex $%x", (pc+3+(INT8)program_read_byte(pc+2)) & 0xffffff); + return 3; + + case 0xe3: + sprintf(buffer, "blex $%x", (pc+3+(INT8)program_read_byte(pc+2)) & 0xffffff); + return 3; + + case 0xe4: + sprintf(buffer, "bcsx $%x", (pc+3+(INT8)program_read_byte(pc+2)) & 0xffffff); + return 3; + + case 0xe5: + sprintf(buffer, "bhix $%x", (pc+3+(INT8)program_read_byte(pc+2)) & 0xffffff); + return 3; + + case 0xe6: + sprintf(buffer, "bccx $%x", (pc+3+(INT8)program_read_byte(pc+2)) & 0xffffff); + return 3; + + case 0xe7: + sprintf(buffer, "blsx $%x", (pc+3+(INT8)program_read_byte(pc+2)) & 0xffffff); + return 3; + + case 0xe8: + sprintf(buffer, "beqx $%x", (pc+3+(INT8)program_read_byte(pc+2)) & 0xffffff); + return 3; + + case 0xe9: + sprintf(buffer, "bnex $%x", (pc+3+(INT8)program_read_byte(pc+2)) & 0xffffff); + return 3; + + case 0xec: + sprintf(buffer, "bvcx $%x", (pc+3+(INT8)program_read_byte(pc+2)) & 0xffffff); + return 3; + + case 0xed: + sprintf(buffer, "bvsx $%x", (pc+3+(INT8)program_read_byte(pc+2)) & 0xffffff); + return 3; + + case 0xee: + sprintf(buffer, "bncx $%x", (pc+3+(INT8)program_read_byte(pc+2)) & 0xffffff); + return 3; + + case 0xef: + sprintf(buffer, "bnsx $%x", (pc+3+(INT8)program_read_byte(pc+2)) & 0xffffff); + return 3; + + case 0xf0: case 0xf1: case 0xf2: case 0xf3: case 0xf4: case 0xf5: case 0xf6: case 0xf7: + { + UINT8 opcode2 = program_read_byte(pc+2); + switch(opcode2) + { + case 0x04: + sprintf(buffer, "mulql %s, d%d", i8str(program_read_byte(pc+3)), opcode & 3); + return 4; + + case 0x05: + sprintf(buffer, "mulqh %s, d%d", i8str(program_read_byte(pc+3)), opcode & 3); + return 4; + + case 0x08: + sprintf(buffer, "mulql %s, d%d", i16str(r16s(pc+3)), opcode & 3); + return 5; + + case 0x09: + sprintf(buffer, "mulqh %s, d%d", i16str(r16s(pc+3)), opcode & 3); + return 5; + + default: + goto illegal3; + } + } + + case 0xfc: + sprintf(buffer, "bvc $%x", (pc+3+(INT8)program_read_byte(pc+2)) & 0xffffff); + return 3; + + case 0xfd: + sprintf(buffer, "bvs $%x", (pc+3+(INT8)program_read_byte(pc+2)) & 0xffffff); + return 3; + + case 0xfe: + sprintf(buffer, "bnc $%x", (pc+3+(INT8)program_read_byte(pc+2)) & 0xffffff); + return 3; + + case 0xff: + sprintf(buffer, "bns $%x", (pc+3+(INT8)program_read_byte(pc+2)) & 0xffffff); + return 3; + + default: + goto illegal2; + } + + case 0xf6: + sprintf(buffer, "nop"); + return 1; + + case 0xf7: + opcode = program_read_byte(pc+1); + switch(opcode) + { + case 0x00: case 0x01: case 0x02: case 0x03: + sprintf(buffer, "and $%04x, d%d", r16u(pc+2), opcode & 3); + return 4; + + case 0x04: case 0x05: case 0x06: case 0x07: + sprintf(buffer, "btst $%04x, d%d", r16u(pc+2), opcode & 3); + return 4; + + case 0x08: case 0x09: case 0x0a: case 0x0b: + sprintf(buffer, "add %s, a%d", i16str(r16s(pc+2)), opcode & 3); + return 4; + + case 0x0c: case 0x0d: case 0x0e: case 0x0f: + sprintf(buffer, "sub %s, a%d", i16str(r16s(pc+2)), opcode & 3); + return 4; + + case 0x10: + sprintf(buffer, "and $%04x, psw", r16u(pc+2)); + return 4; + + case 0x14: + sprintf(buffer, "or $%04x, psw", r16u(pc+2)); + return 4; + + case 0x18: case 0x19: case 0x1a: case 0x1b: + sprintf(buffer, "add %s, d%d", i16str(r16u(pc+2)), opcode & 3); + return 4; + + case 0x1c: case 0x1d: case 0x1e: case 0x1f: + sprintf(buffer, "sub %s, d%d", i16str(r16s(pc+2)), opcode & 3); + return 4; + + case 0x20: case 0x21: case 0x22: case 0x23: + sprintf(buffer, "mov a%d, ($%04x)", opcode & 3, r16u(pc+2)); + return 4; + + case 0x30: case 0x31: case 0x32: case 0x33: + sprintf(buffer, "mov ($%04x), a%d", r16u(pc+2), opcode & 3); + return 4; + + case 0x40: case 0x41: case 0x42: case 0x43: + sprintf(buffer, "or $%04x, d%d", r16u(pc+2), opcode & 3); + return 4; + + case 0x48: case 0x49: case 0x4a: case 0x4b: + sprintf(buffer, "cmp %s, d%d", i16str(r16u(pc+2)), opcode & 3); + return 4; + + case 0x4c: case 0x4d: case 0x4e: case 0x4f: + sprintf(buffer, "xor $%04x, d%d", r16u(pc+2), opcode & 3); + return 4; + + case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x55: case 0x56: case 0x57: + case 0x58: case 0x59: case 0x5a: case 0x5b: case 0x5c: case 0x5d: case 0x5e: case 0x5f: + sprintf(buffer, "movbu (%s, a%d), d%d", i16str(r16s(pc+2)), (opcode>>2) & 3, opcode & 3); + return 4; + + case 0x60: case 0x61: case 0x62: case 0x63: case 0x64: case 0x65: case 0x66: case 0x67: + case 0x68: case 0x69: case 0x6a: case 0x6b: case 0x6c: case 0x6d: case 0x6e: case 0x6f: + sprintf(buffer, "movx d%d, (%s, a%d)", opcode & 3, i16str(r16s(pc+2)), (opcode>>2) & 3); + return 4; + + case 0x70: case 0x71: case 0x72: case 0x73: case 0x74: case 0x75: case 0x76: case 0x77: + case 0x78: case 0x79: case 0x7a: case 0x7b: case 0x7c: case 0x7d: case 0x7e: case 0x7f: + sprintf(buffer, "movx (%s, a%d), d%d", i16str(r16s(pc+2)), (opcode>>2) & 3, opcode & 3); + return 4; + + case 0x80: case 0x81: case 0x82: case 0x83: case 0x84: case 0x85: case 0x86: case 0x87: + case 0x88: case 0x89: case 0x8a: case 0x8b: case 0x8c: case 0x8d: case 0x8e: case 0x8f: + sprintf(buffer, "mov d%d, (%s, a%d)", opcode & 3, i16str(r16s(pc+2)), (opcode>>2) & 3); + return 4; + + case 0x90: case 0x91: case 0x92: case 0x93: case 0x94: case 0x95: case 0x96: case 0x97: + case 0x98: case 0x99: case 0x9a: case 0x9b: case 0x9c: case 0x9d: case 0x9e: case 0x9f: + sprintf(buffer, "movb d%d, (%s, a%d)", opcode & 3, i16str(r16s(pc+2)), (opcode>>2) & 3); + return 4; + + case 0xa0: case 0xa1: case 0xa2: case 0xa3: case 0xa4: case 0xa5: case 0xa6: case 0xa7: + case 0xa8: case 0xa9: case 0xaa: case 0xab: case 0xac: case 0xad: case 0xae: case 0xaf: + sprintf(buffer, "mov a%d, (%s, a%d)", opcode & 3, i16str(r16s(pc+2)), (opcode>>2) & 3); + return 4; + + case 0xb0: case 0xb1: case 0xb2: case 0xb3: case 0xb4: case 0xb5: case 0xb6: case 0xb7: + case 0xb8: case 0xb9: case 0xba: case 0xbb: case 0xbc: case 0xbd: case 0xbe: case 0xbf: + sprintf(buffer, "mov (%s, a%d), a%d", i16str(r16s(pc+2)), (opcode>>2) & 3, opcode & 3); + return 4; + + case 0xc0: case 0xc1: case 0xc2: case 0xc3: case 0xc4: case 0xc5: case 0xc6: case 0xc7: + case 0xc8: case 0xc9: case 0xca: case 0xcb: case 0xcc: case 0xcd: case 0xce: case 0xcf: + sprintf(buffer, "mov (%s, a%d), d%d", i16str(r16s(pc+2)), (opcode>>2) & 3, opcode & 3); + return 4; + + case 0xd0: case 0xd1: case 0xd2: case 0xd3: case 0xd4: case 0xd5: case 0xd6: case 0xd7: + case 0xd8: case 0xd9: case 0xda: case 0xdb: case 0xdc: case 0xdd: case 0xde: case 0xdf: + sprintf(buffer, "movb (%s, a%d), d%d", i16str(r16s(pc+2)), (opcode>>2) & 3, opcode & 3); + return 4; + + default: + goto illegal2; + } + + case 0xf8: case 0xf9: case 0xfa: case 0xfb: + sprintf(buffer, "mov %s, d%d", i16str(r16s(pc+1)), opcode & 3); + return 3; + + case 0xfc: + sprintf(buffer, "jmp $%x", (pc+3+r16s(pc+1)) & 0xffffff); + return 3; + + case 0xfd: + sprintf(buffer, "jsr $%x", (pc+3+r16s(pc+1)) & 0xffffff); + return 3; + + case 0xfe: + sprintf(buffer, "rts"); + return 1; + + default: + goto illegal1; + }; + + illegal1: + sprintf(buffer, "dc.b $%02x", program_read_byte(pc)); + return 1; + + illegal2: + sprintf(buffer, "dc.b $%02x $%02x", program_read_byte(pc), program_read_byte(pc+1)); + return 2; + + illegal3: + sprintf(buffer, "dc.b $%02x $%02x $%02x", program_read_byte(pc), program_read_byte(pc+1), program_read_byte(pc+2)); + return 3; +} + +CPU_DISASSEMBLE( mn10200 ) +{ + return mn102_disassemble(buffer, pc, oprom); +} diff --git a/src/devices/cpu/nec/nec.c b/src/devices/cpu/nec/nec.c new file mode 100644 index 00000000000..6c53cfa677a --- /dev/null +++ b/src/devices/cpu/nec/nec.c @@ -0,0 +1,541 @@ +// license:BSD-3-Clause +// copyright-holders:Bryan McPhail +/**************************************************************************** + + NEC V20/V30/V33 emulator + + --------------------------------------------- + + V20 = uPD70108 = 8-bit data bus @ 5MHz or 8MHz + V20HL = uPD70108H = V20 with EMS support (24-bit address bus) + + V25 = uPD70320 = V20 with on-chip features: + - 256 bytes on-chip RAM + - 8 register banks + - 4-bit input port + - 20-bit I/O port + - 2 channel serial interface + - interrupt controller + - 2 channel DMA controller + - 2 channel 16-bit timer + - new instructions: BTCLR, RETRBI, STOP, BRKCS, TSKSW, + MOVSPA, MOVSPB + + V25+ = uPD70325 = V25 @ 8MHz or 10MHz plus changes: + - faster DMA + - improved serial interface + + --------------------------------------------- + + V30 = uPD70116 = 16-bit data bus version of V20 + V30HL = uPD70116H = 16-bit data bus version of V20HL + V30MX = V30HL with separate address and data busses + + V35 = uPD70330 = 16-bit data bus version of V25 + + V35+ = uPD70335 = 16-bit data bus version of V25+ + + --------------------------------------------- + + V40 = uPD70208 = 8-bit data bus @ 10MHz + V40HL = uPD70208H = V40 with support up to 20Mhz + + --------------------------------------------- + + V50 = uPD70216 = 16-bit data bus version of V40 + V50HL = uPD70216H = 16-bit data bus version of V40HL + + --------------------------------------------- + + V41 = uPD70270 + + V51 = uPD70280 + + + + V33A = uPD70136A (interrupt vector #s compatible with x86) + V53A = uPD70236A + + + + Instruction differences: + V20, V30, V40, V50 have dedicated emulation instructions + (BRKEM, RETEM, CALLN) + + V33 / V33A has dedicated address mode instructions (V53 / V53A are based on those cores with extra peripherals) + (BRKXA, RETXA) + + + + (Re)Written June-September 2000 by Bryan McPhail (mish@tendril.co.uk) based + on code by Oliver Bergmann (Raul_Bloodworth@hotmail.com) who based code + on the i286 emulator by Fabrice Frances which had initial work based on + David Hedley's pcemu(!). + + This new core features 99% accurate cycle counts for each processor, + there are still some complex situations where cycle counts are wrong, + typically where a few instructions have differing counts for odd/even + source and odd/even destination memory operands. + + Flag settings are also correct for the NEC processors rather than the + I86 versions. + + Changelist: + + 22/02/2003: + Removed cycle counts from memory accesses - they are certainly wrong, + and there is already a memory access cycle penalty in the opcodes + using them. + + Fixed save states. + + Fixed ADJBA/ADJBS/ADJ4A/ADJ4S flags/return values for all situations. + (Fixes bugs in Geostorm and Thunderblaster) + + Fixed carry flag on NEG (I thought this had been fixed circa Mame 0.58, + but it seems I never actually submitted the fix). + + Fixed many cycle counts in instructions and bug in cycle count + macros (odd word cases were testing for odd instruction word address + not data address). + + Todo! + Double check cycle timing is 100%. + +****************************************************************************/ + +#include "emu.h" +#include "debugger.h" + +typedef UINT8 BOOLEAN; +typedef UINT8 BYTE; +typedef UINT16 WORD; +typedef UINT32 DWORD; + +#include "nec.h" +#include "necpriv.h" + +const device_type V20 = &device_creator; +const device_type V30 = &device_creator; +const device_type V33 = &device_creator; +const device_type V33A =&device_creator; + + + +nec_common_device::nec_common_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, bool is_16bit, offs_t fetch_xor, UINT8 prefetch_size, UINT8 prefetch_cycles, UINT32 chip_type) + : cpu_device(mconfig, type, name, tag, owner, clock, shortname, __FILE__) + , m_program_config("program", ENDIANNESS_LITTLE, is_16bit ? 16 : 8, 20, 0) + , m_io_config("io", ENDIANNESS_LITTLE, is_16bit ? 16 : 8, 16, 0) + , m_fetch_xor(fetch_xor) + , m_prefetch_size(prefetch_size) + , m_prefetch_cycles(prefetch_cycles) + , m_chip_type(chip_type) +{ +} + + +v20_device::v20_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nec_common_device(mconfig, V20, "V20", tag, owner, clock, "v20", false, 0, 4, 4, V20_TYPE) +{ +} + + +v30_device::v30_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nec_common_device(mconfig, V30, "V30", tag, owner, clock, "v30", true, BYTE_XOR_LE(0), 6, 2, V30_TYPE) +{ +} + + +/* FIXME: Need information about prefetch size and cycles for V33. + * complete guess below, nbbatman will not work + * properly without. */ +v33_device::v33_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nec_common_device(mconfig, V33, "V33", tag, owner, clock, "v33", true, BYTE_XOR_LE(0), 6, 1, V33_TYPE) +{ +} + + +v33a_device::v33a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nec_common_device(mconfig, V33A, "V33A", tag, owner, clock, "v33A", true, BYTE_XOR_LE(0), 6, 1, V33_TYPE) +{ +} + + +offs_t nec_common_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( nec ); + return CPU_DISASSEMBLE_NAME(nec)(this, buffer, pc, oprom, opram, options); +} + + +void nec_common_device::prefetch() +{ + m_prefetch_count--; +} + +void nec_common_device::do_prefetch(int previous_ICount) +{ + int diff = previous_ICount - (int) m_icount; + + /* The implementation is not accurate, but comes close. + * It does not respect that the V30 will fetch two bytes + * at once directly, but instead uses only 2 cycles instead + * of 4. There are however only very few sources publicly + * available and they are vague. + */ + while (m_prefetch_count<0) + { + m_prefetch_count++; + if (diff>m_prefetch_cycles) + diff -= m_prefetch_cycles; + else + m_icount -= m_prefetch_cycles; + } + + if (m_prefetch_reset) + { + m_prefetch_count = 0; + m_prefetch_reset = 0; + return; + } + + while (diff>=m_prefetch_cycles && m_prefetch_count < m_prefetch_size) + { + diff -= m_prefetch_cycles; + m_prefetch_count++; + } + +} + +UINT8 nec_common_device::fetch() +{ + prefetch(); + return m_direct->read_byte((Sreg(PS)<<4)+m_ip++, m_fetch_xor); +} + +UINT16 nec_common_device::fetchword() +{ + UINT16 r = FETCH(); + r |= (FETCH()<<8); + return r; +} + +#include "necinstr.h" +#include "necmacro.h" +#include "necea.h" +#include "necmodrm.h" + +static UINT8 parity_table[256]; + +UINT8 nec_common_device::fetchop() +{ + prefetch(); + return m_direct->read_byte(( Sreg(PS)<<4)+m_ip++, m_fetch_xor); +} + + + +/***************************************************************************/ + +void nec_common_device::device_reset() +{ + memset( &m_regs.w, 0, sizeof(m_regs.w)); + + m_ip = 0; + m_TF = 0; + m_IF = 0; + m_DF = 0; + m_MF = 1; // brkem should set to 0 when implemented + m_SignVal = 0; + m_AuxVal = 0; + m_OverVal = 0; + m_ZeroVal = 1; + m_CarryVal = 0; + m_ParityVal = 1; + m_pending_irq = 0; + m_nmi_state = 0; + m_irq_state = 0; + m_poll_state = 1; + m_halted = 0; + + Sreg(PS) = 0xffff; + Sreg(SS) = 0; + Sreg(DS0) = 0; + Sreg(DS1) = 0; + + CHANGE_PC; +} + + +void nec_common_device::nec_interrupt(unsigned int_num, int/*INTSOURCES*/ source) +{ + UINT32 dest_seg, dest_off; + + i_pushf(); + m_TF = m_IF = 0; + + if (source == INT_IRQ) /* get vector */ + int_num = (standard_irq_callback)(0); + + dest_off = read_mem_word(int_num*4); + dest_seg = read_mem_word(int_num*4+2); + + PUSH(Sreg(PS)); + PUSH(m_ip); + m_ip = (WORD)dest_off; + Sreg(PS) = (WORD)dest_seg; + CHANGE_PC; +} + +void nec_common_device::nec_trap() +{ + (this->*s_nec_instruction[fetchop()])(); + nec_interrupt(NEC_TRAP_VECTOR, BRK); +} + +void nec_common_device::external_int() +{ + if (m_pending_irq & NMI_IRQ) + { + nec_interrupt(NEC_NMI_VECTOR, NMI_IRQ); + m_pending_irq &= ~NMI_IRQ; + } + else if (m_pending_irq) + { + /* the actual vector is retrieved after pushing flags */ + /* and clearing the IF */ + nec_interrupt((UINT32)-1, INT_IRQ); + m_irq_state = CLEAR_LINE; + m_pending_irq &= ~INT_IRQ; + } +} + +/****************************************************************************/ +/* OPCODES */ +/****************************************************************************/ + +#include "necinstr.inc" + +/*****************************************************************************/ + +void nec_common_device::execute_set_input(int irqline, int state) +{ + switch (irqline) + { + case 0: + m_irq_state = state; + if (state == CLEAR_LINE) + m_pending_irq &= ~INT_IRQ; + else + { + m_pending_irq |= INT_IRQ; + m_halted = 0; + } + break; + case INPUT_LINE_NMI: + if (m_nmi_state == state) return; + m_nmi_state = state; + if (state != CLEAR_LINE) + { + m_pending_irq |= NMI_IRQ; + m_halted = 0; + } + break; + case NEC_INPUT_LINE_POLL: + m_poll_state = state; + break; + } +} + +void nec_common_device::device_start() +{ + unsigned int i, j, c; + + static const WREGS wreg_name[8]={ AW, CW, DW, BW, SP, BP, IX, IY }; + static const BREGS breg_name[8]={ AL, CL, DL, BL, AH, CH, DH, BH }; + + for (i = 0; i < 256; i++) + { + for (j = i, c = 0; j > 0; j >>= 1) + if (j & 1) c++; + parity_table[i] = !(c & 1); + } + + for (i = 0; i < 256; i++) + { + Mod_RM.reg.b[i] = breg_name[(i & 0x38) >> 3]; + Mod_RM.reg.w[i] = wreg_name[(i & 0x38) >> 3]; + } + + for (i = 0xc0; i < 0x100; i++) + { + Mod_RM.RM.w[i] = wreg_name[i & 7]; + Mod_RM.RM.b[i] = breg_name[i & 7]; + } + + m_no_interrupt = 0; + m_prefetch_count = 0; + m_prefetch_reset = 0; + m_prefix_base = 0; + m_seg_prefix = 0; + m_EA = 0; + m_EO = 0; + m_E16 = 0; + m_debugger_temp = 0; + m_ip = 0; + + memset(m_regs.w, 0x00, sizeof(m_regs.w)); + memset(m_sregs, 0x00, sizeof(m_sregs)); + + save_item(NAME(m_regs.w)); + save_item(NAME(m_sregs)); + + save_item(NAME(m_ip)); + save_item(NAME(m_TF)); + save_item(NAME(m_IF)); + save_item(NAME(m_DF)); + save_item(NAME(m_MF)); + save_item(NAME(m_SignVal)); + save_item(NAME(m_AuxVal)); + save_item(NAME(m_OverVal)); + save_item(NAME(m_ZeroVal)); + save_item(NAME(m_CarryVal)); + save_item(NAME(m_ParityVal)); + save_item(NAME(m_pending_irq)); + save_item(NAME(m_nmi_state)); + save_item(NAME(m_irq_state)); + save_item(NAME(m_poll_state)); + save_item(NAME(m_no_interrupt)); + save_item(NAME(m_halted)); + save_item(NAME(m_prefetch_count)); + save_item(NAME(m_prefetch_reset)); + + m_program = &space(AS_PROGRAM); + m_direct = &m_program->direct(); + m_io = &space(AS_IO); + + state_add( NEC_PC, "PC", m_debugger_temp).callimport().callexport().formatstr("%05X"); + state_add( NEC_IP, "IP", m_ip).formatstr("%04X"); + state_add( NEC_SP, "SP", Wreg(SP)).formatstr("%04X"); + state_add( NEC_FLAGS, "F", m_debugger_temp).callimport().callexport().formatstr("%04X"); + state_add( NEC_AW, "AW", Wreg(AW)).formatstr("%04X"); + state_add( NEC_CW, "CW", Wreg(CW)).formatstr("%04X"); + state_add( NEC_DW, "DW", Wreg(DW)).formatstr("%04X"); + state_add( NEC_BW, "BW", Wreg(BW)).formatstr("%04X"); + state_add( NEC_BP, "BP", Wreg(BP)).formatstr("%04X"); + state_add( NEC_IX, "IX", Wreg(IX)).formatstr("%04X"); + state_add( NEC_IY, "IY", Wreg(IY)).formatstr("%04X"); + state_add( NEC_ES, "DS1", Sreg(DS1)).formatstr("%04X"); + state_add( NEC_CS, "PS", Sreg(PS)).formatstr("%04X"); + state_add( NEC_SS, "SS", Sreg(SS)).formatstr("%04X"); + state_add( NEC_DS, "DS0", Sreg(DS0)).formatstr("%04X"); + + state_add( STATE_GENPC, "GENPC", m_debugger_temp).callimport().callexport().noshow(); + state_add( STATE_GENSP, "GENSP", m_debugger_temp).callimport().callexport().noshow(); + state_add( STATE_GENFLAGS, "GENFLAGS", m_debugger_temp).formatstr("%16s").noshow(); + + m_icountptr = &m_icount; +} + +void nec_common_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + UINT16 flags = CompressFlags(); + + switch (entry.index()) + { + case STATE_GENFLAGS: + strprintf(str, "%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c", + flags & 0x8000 ? 'N':'E', + flags & 0x4000 ? '?':'.', + flags & 0x2000 ? '?':'.', + flags & 0x1000 ? '?':'.', + flags & 0x0800 ? 'O':'.', + flags & 0x0400 ? 'D':'.', + flags & 0x0200 ? 'I':'.', + flags & 0x0100 ? 'T':'.', + flags & 0x0080 ? 'S':'.', + flags & 0x0040 ? 'Z':'.', + flags & 0x0020 ? '?':'.', + flags & 0x0010 ? 'A':'.', + flags & 0x0008 ? '?':'.', + flags & 0x0004 ? 'P':'.', + flags & 0x0002 ? '.':'?', + flags & 0x0001 ? 'C':'.'); + break; + } +} + +void nec_common_device::state_import(const device_state_entry &entry) +{ + switch (entry.index()) + { + case NEC_PC: + if( m_debugger_temp - (Sreg(PS)<<4) < 0x10000 ) + { + m_ip = m_debugger_temp - (Sreg(PS)<<4); + } + else + { + Sreg(PS) = m_debugger_temp >> 4; + m_ip = m_debugger_temp & 0x0000f; + } + break; + + case NEC_FLAGS: + ExpandFlags(m_debugger_temp); + break; + } +} + + +void nec_common_device::state_export(const device_state_entry &entry) +{ + switch (entry.index()) + { + case STATE_GENPC: + case NEC_PC: + m_debugger_temp = (Sreg(PS)<<4) + m_ip; + break; + + case STATE_GENSP: + m_debugger_temp = (Sreg(SS)<<4) + Wreg(SP); + break; + + case NEC_FLAGS: + m_debugger_temp = CompressFlags(); + break; + } +} + + +void nec_common_device::execute_run() +{ + int prev_ICount; + + if (m_halted) + { + m_icount = 0; + debugger_instruction_hook(this, (Sreg(PS)<<4) + m_ip); + return; + } + + while(m_icount>0) { + /* Dispatch IRQ */ + if (m_pending_irq && m_no_interrupt==0) + { + if (m_pending_irq & NMI_IRQ) + external_int(); + else if (m_IF) + external_int(); + } + + /* No interrupt allowed between last instruction and this one */ + if (m_no_interrupt) + m_no_interrupt--; + + debugger_instruction_hook(this, (Sreg(PS)<<4) + m_ip); + prev_ICount = m_icount; + (this->*s_nec_instruction[fetchop()])(); + do_prefetch(prev_ICount); + } +} diff --git a/src/devices/cpu/nec/nec.h b/src/devices/cpu/nec/nec.h new file mode 100644 index 00000000000..2e881591426 --- /dev/null +++ b/src/devices/cpu/nec/nec.h @@ -0,0 +1,433 @@ +// license:BSD-3-Clause +// copyright-holders:Bryan McPhail +/* ASG 971222 -- rewrote this interface */ +#ifndef __NEC_H_ +#define __NEC_H_ + + +#define NEC_INPUT_LINE_INTP0 10 +#define NEC_INPUT_LINE_INTP1 11 +#define NEC_INPUT_LINE_INTP2 12 +#define NEC_INPUT_LINE_POLL 20 + +enum +{ + NEC_PC=0, + NEC_IP, NEC_AW, NEC_CW, NEC_DW, NEC_BW, NEC_SP, NEC_BP, NEC_IX, NEC_IY, + NEC_FLAGS, NEC_ES, NEC_CS, NEC_SS, NEC_DS, + NEC_PENDING +}; + + +class nec_common_device : public cpu_device +{ +public: + // construction/destruction + nec_common_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, bool is_16bit, offs_t fetch_xor, UINT8 prefetch_size, UINT8 prefetch_cycles, UINT32 chip_type); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_execute_interface overrides + virtual UINT32 execute_min_cycles() const { return 1; } + virtual UINT32 execute_max_cycles() const { return 80; } + virtual UINT32 execute_input_lines() const { return 1; } + virtual UINT32 execute_default_irq_vector() const { return 0xff; } + virtual void execute_run(); + virtual void execute_set_input(int inputnum, int state); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const { return (spacenum == AS_PROGRAM) ? &m_program_config : ( (spacenum == AS_IO) ? &m_io_config : NULL); } + + // device_state_interface overrides + void state_string_export(const device_state_entry &entry, std::string &str); + virtual void state_import(const device_state_entry &entry); + virtual void state_export(const device_state_entry &entry); + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const { return 1; } + virtual UINT32 disasm_max_opcode_bytes() const { return 8; } + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + +private: + address_space_config m_program_config; + address_space_config m_io_config; + +/* NEC registers */ +union necbasicregs +{ /* eight general registers */ + UINT16 w[8]; /* viewed as 16 bits registers */ + UINT8 b[16]; /* or as 8 bit registers */ +}; + + necbasicregs m_regs; + offs_t m_fetch_xor; + UINT16 m_sregs[4]; + + UINT16 m_ip; + + /* PSW flags */ + INT32 m_SignVal; + UINT32 m_AuxVal; /* 0 or non-0 valued flags */ + UINT32 m_OverVal; + UINT32 m_ZeroVal; + UINT32 m_CarryVal; + UINT32 m_ParityVal; + UINT8 m_TF; /* 0 or 1 valued flags */ + UINT8 m_IF; + UINT8 m_DF; + UINT8 m_MF; + + /* interrupt related */ + UINT32 m_pending_irq; + UINT32 m_nmi_state; + UINT32 m_irq_state; + UINT32 m_poll_state; + UINT8 m_no_interrupt; + UINT8 m_halted; + + address_space *m_program; + direct_read_data *m_direct; + address_space *m_io; + int m_icount; + + UINT8 m_prefetch_size; + UINT8 m_prefetch_cycles; + INT8 m_prefetch_count; + UINT8 m_prefetch_reset; + UINT32 m_chip_type; + + UINT32 m_prefix_base; /* base address of the latest prefix segment */ + UINT8 m_seg_prefix; /* prefix segment indicator */ + + UINT32 m_EA; + UINT16 m_EO; + UINT16 m_E16; + + UINT32 m_debugger_temp; + + typedef void (nec_common_device::*nec_ophandler)(); + typedef UINT32 (nec_common_device::*nec_eahandler)(); + static const nec_ophandler s_nec_instruction[256]; + static const nec_eahandler s_GetEA[192]; + + inline void prefetch(); + void do_prefetch(int previous_ICount); + inline UINT8 fetch(); + inline UINT16 fetchword(); + UINT8 fetchop(); + void nec_interrupt(unsigned int_num, int source); + void nec_trap(); + void external_int(); + + void i_add_br8(); + void i_add_wr16(); + void i_add_r8b(); + void i_add_r16w(); + void i_add_ald8(); + void i_add_axd16(); + void i_push_es(); + void i_pop_es(); + void i_or_br8(); + void i_or_r8b(); + void i_or_wr16(); + void i_or_r16w(); + void i_or_ald8(); + void i_or_axd16(); + void i_push_cs(); + void i_pre_nec(); + void i_adc_br8(); + void i_adc_wr16(); + void i_adc_r8b(); + void i_adc_r16w(); + void i_adc_ald8(); + void i_adc_axd16(); + void i_push_ss(); + void i_pop_ss(); + void i_sbb_br8(); + void i_sbb_wr16(); + void i_sbb_r8b(); + void i_sbb_r16w(); + void i_sbb_ald8(); + void i_sbb_axd16(); + void i_push_ds(); + void i_pop_ds(); + void i_and_br8(); + void i_and_r8b(); + void i_and_wr16(); + void i_and_r16w(); + void i_and_ald8(); + void i_and_axd16(); + void i_es(); + void i_daa(); + void i_sub_br8(); + void i_sub_wr16(); + void i_sub_r8b(); + void i_sub_r16w(); + void i_sub_ald8(); + void i_sub_axd16(); + void i_cs(); + void i_das(); + void i_xor_br8(); + void i_xor_r8b(); + void i_xor_wr16(); + void i_xor_r16w(); + void i_xor_ald8(); + void i_xor_axd16(); + void i_ss(); + void i_aaa(); + void i_cmp_br8(); + void i_cmp_wr16(); + void i_cmp_r8b(); + void i_cmp_r16w(); + void i_cmp_ald8(); + void i_cmp_axd16(); + void i_ds(); + void i_aas(); + void i_inc_ax(); + void i_inc_cx(); + void i_inc_dx(); + void i_inc_bx(); + void i_inc_sp(); + void i_inc_bp(); + void i_inc_si(); + void i_inc_di(); + void i_dec_ax(); + void i_dec_cx(); + void i_dec_dx(); + void i_dec_bx(); + void i_dec_sp(); + void i_dec_bp(); + void i_dec_si(); + void i_dec_di(); + void i_push_ax(); + void i_push_cx(); + void i_push_dx(); + void i_push_bx(); + void i_push_sp(); + void i_push_bp(); + void i_push_si(); + void i_push_di(); + void i_pop_ax(); + void i_pop_cx(); + void i_pop_dx(); + void i_pop_bx(); + void i_pop_sp(); + void i_pop_bp(); + void i_pop_si(); + void i_pop_di(); + void i_pusha(); + void i_popa(); + void i_chkind(); + void i_repnc(); + void i_repc(); + void i_push_d16(); + void i_imul_d16(); + void i_push_d8(); + void i_imul_d8(); + void i_insb(); + void i_insw(); + void i_outsb(); + void i_outsw(); + void i_jo(); + void i_jno(); + void i_jc(); + void i_jnc(); + void i_jz(); + void i_jnz(); + void i_jce(); + void i_jnce(); + void i_js(); + void i_jns(); + void i_jp(); + void i_jnp(); + void i_jl(); + void i_jnl(); + void i_jle(); + void i_jnle(); + void i_80pre(); + void i_82pre(); + void i_81pre(); + void i_83pre(); + void i_test_br8(); + void i_test_wr16(); + void i_xchg_br8(); + void i_xchg_wr16(); + void i_mov_br8(); + void i_mov_r8b(); + void i_mov_wr16(); + void i_mov_r16w(); + void i_mov_wsreg(); + void i_lea(); + void i_mov_sregw(); + void i_invalid(); + void i_popw(); + void i_nop(); + void i_xchg_axcx(); + void i_xchg_axdx(); + void i_xchg_axbx(); + void i_xchg_axsp(); + void i_xchg_axbp(); + void i_xchg_axsi(); + void i_xchg_axdi(); + void i_cbw(); + void i_cwd(); + void i_call_far(); + void i_pushf(); + void i_popf(); + void i_sahf(); + void i_lahf(); + void i_mov_aldisp(); + void i_mov_axdisp(); + void i_mov_dispal(); + void i_mov_dispax(); + void i_movsb(); + void i_movsw(); + void i_cmpsb(); + void i_cmpsw(); + void i_test_ald8(); + void i_test_axd16(); + void i_stosb(); + void i_stosw(); + void i_lodsb(); + void i_lodsw(); + void i_scasb(); + void i_scasw(); + void i_mov_ald8(); + void i_mov_cld8(); + void i_mov_dld8(); + void i_mov_bld8(); + void i_mov_ahd8(); + void i_mov_chd8(); + void i_mov_dhd8(); + void i_mov_bhd8(); + void i_mov_axd16(); + void i_mov_cxd16(); + void i_mov_dxd16(); + void i_mov_bxd16(); + void i_mov_spd16(); + void i_mov_bpd16(); + void i_mov_sid16(); + void i_mov_did16(); + void i_rotshft_bd8(); + void i_rotshft_wd8(); + void i_ret_d16(); + void i_ret(); + void i_les_dw(); + void i_lds_dw(); + void i_mov_bd8(); + void i_mov_wd16(); + void i_enter(); + void i_leave(); + void i_retf_d16(); + void i_retf(); + void i_int3(); + void i_int(); + void i_into(); + void i_iret(); + void i_rotshft_b(); + void i_rotshft_w(); + void i_rotshft_bcl(); + void i_rotshft_wcl(); + void i_aam(); + void i_aad(); + void i_setalc(); + void i_trans(); + void i_fpo(); + void i_loopne(); + void i_loope(); + void i_loop(); + void i_jcxz(); + void i_inal(); + void i_inax(); + void i_outal(); + void i_outax(); + void i_call_d16(); + void i_jmp_d16(); + void i_jmp_far(); + void i_jmp_d8(); + void i_inaldx(); + void i_inaxdx(); + void i_outdxal(); + void i_outdxax(); + void i_lock(); + void i_repne(); + void i_repe(); + void i_hlt(); + void i_cmc(); + void i_f6pre(); + void i_f7pre(); + void i_clc(); + void i_stc(); + void i_di(); + void i_ei(); + void i_cld(); + void i_std(); + void i_fepre(); + void i_ffpre(); + void i_wait(); + + UINT32 EA_000(); + UINT32 EA_001(); + UINT32 EA_002(); + UINT32 EA_003(); + UINT32 EA_004(); + UINT32 EA_005(); + UINT32 EA_006(); + UINT32 EA_007(); + UINT32 EA_100(); + UINT32 EA_101(); + UINT32 EA_102(); + UINT32 EA_103(); + UINT32 EA_104(); + UINT32 EA_105(); + UINT32 EA_106(); + UINT32 EA_107(); + UINT32 EA_200(); + UINT32 EA_201(); + UINT32 EA_202(); + UINT32 EA_203(); + UINT32 EA_204(); + UINT32 EA_205(); + UINT32 EA_206(); + UINT32 EA_207(); +}; + + +class v20_device : public nec_common_device +{ +public: + v20_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +class v30_device : public nec_common_device +{ +public: + v30_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +class v33_device : public nec_common_device +{ +public: + v33_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class v33a_device : public nec_common_device +{ +public: + v33a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +extern const device_type V20; +extern const device_type V30; +extern const device_type V33; +extern const device_type V33A; + + + +#endif diff --git a/src/devices/cpu/nec/necdasm.c b/src/devices/cpu/nec/necdasm.c new file mode 100644 index 00000000000..726ada18247 --- /dev/null +++ b/src/devices/cpu/nec/necdasm.c @@ -0,0 +1,1603 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/* + NEC V-series Disassembler + + Originally Written for i386 by Ville Linde + Converted to NEC-V by Aaron Giles +*/ + +#include "emu.h" + +static const UINT8 *Iconfig; + +enum +{ + PARAM_REG8 = 1, /* 8-bit register */ + PARAM_REG16, /* 16-bit register */ + PARAM_REG2_8, /* 8-bit register */ + PARAM_REG2_16, /* 16-bit register */ + PARAM_RM8, /* 8-bit memory or register */ + PARAM_RM16, /* 16-bit memory or register */ + PARAM_RMPTR8, /* 8-bit memory or register */ + PARAM_RMPTR16, /* 16-bit memory or register */ + PARAM_I3, /* 3-bit immediate */ + PARAM_I4, /* 4-bit immediate */ + PARAM_I8, /* 8-bit signed immediate */ + PARAM_I16, /* 16-bit signed immediate */ + PARAM_UI8, /* 8-bit unsigned immediate */ + PARAM_IMM, /* 16-bit immediate */ + PARAM_ADDR, /* 16:16 address */ + PARAM_REL8, /* 8-bit PC-relative displacement */ + PARAM_REL16, /* 16-bit PC-relative displacement */ + PARAM_MEM_OFFS, /* 16-bit mem offset */ + PARAM_SREG, /* segment register */ + PARAM_SFREG, /* V25/V35 special function register */ + PARAM_1, /* used by shift/rotate instructions */ + PARAM_AL, + PARAM_CL, + PARAM_DL, + PARAM_BL, + PARAM_AH, + PARAM_CH, + PARAM_DH, + PARAM_BH, + PARAM_AW, + PARAM_CW, + PARAM_DW, + PARAM_BW, + PARAM_SP, + PARAM_BP, + PARAM_IX, + PARAM_IY +}; + +enum +{ + MODRM = 1, + GROUP, + FPU, + TWO_BYTE, + PREFIX, + SEG_PS, + SEG_DS0, + SEG_DS1, + SEG_SS +}; + +struct NEC_I386_OPCODE { + char mnemonic[32]; + UINT32 flags; + UINT32 param1; + UINT32 param2; + UINT32 param3; + offs_t dasm_flags; +}; + +struct NEC_GROUP_OP { + char mnemonic[32]; + const NEC_I386_OPCODE *opcode; +}; + +static const UINT8 *opcode_ptr; +static const UINT8 *opcode_ptr_base; + +static const NEC_I386_OPCODE necv_opcode_table1[256] = +{ + // 0x00 + {"add", MODRM, PARAM_RM8, PARAM_REG8, 0 }, + {"add", MODRM, PARAM_RM16, PARAM_REG16, 0 }, + {"add", MODRM, PARAM_REG8, PARAM_RM8, 0 }, + {"add", MODRM, PARAM_REG16, PARAM_RM16, 0 }, + {"add", 0, PARAM_AL, PARAM_UI8, 0 }, + {"add", 0, PARAM_AW, PARAM_IMM, 0 }, + {"push ds1", 0, 0, 0, 0 }, + {"pop ds1", 0, 0, 0, 0 }, + {"or", MODRM, PARAM_RM8, PARAM_REG8, 0 }, + {"or", MODRM, PARAM_RM16, PARAM_REG16, 0 }, + {"or", MODRM, PARAM_REG8, PARAM_RM8, 0 }, + {"or", MODRM, PARAM_REG16, PARAM_RM16, 0 }, + {"or", 0, PARAM_AL, PARAM_UI8, 0 }, + {"or", 0, PARAM_AW, PARAM_IMM, 0 }, + {"push ps", 0, 0, 0, 0 }, + {"two_byte", TWO_BYTE, 0, 0, 0 }, + // 0x10 + {"addc", MODRM, PARAM_RM8, PARAM_REG8, 0 }, + {"addc", MODRM, PARAM_RM16, PARAM_REG16, 0 }, + {"addc", MODRM, PARAM_REG8, PARAM_RM8, 0 }, + {"addc", MODRM, PARAM_REG16, PARAM_RM16, 0 }, + {"addc", 0, PARAM_AL, PARAM_UI8, 0 }, + {"addc", 0, PARAM_AW, PARAM_IMM, 0 }, + {"push ss", 0, 0, 0, 0 }, + {"pop ss", 0, 0, 0, 0 }, + {"subc", MODRM, PARAM_RM8, PARAM_REG8, 0 }, + {"subc", MODRM, PARAM_RM16, PARAM_REG16, 0 }, + {"subc", MODRM, PARAM_REG8, PARAM_RM8, 0 }, + {"subc", MODRM, PARAM_REG16, PARAM_RM16, 0 }, + {"subc", 0, PARAM_AL, PARAM_UI8, 0 }, + {"subc", 0, PARAM_AW, PARAM_IMM, 0 }, + {"push ds0", 0, 0, 0, 0 }, + {"pop ds0", 0, 0, 0, 0 }, + // 0x20 + {"and", MODRM, PARAM_RM8, PARAM_REG8, 0 }, + {"and", MODRM, PARAM_RM16, PARAM_REG16, 0 }, + {"and", MODRM, PARAM_REG8, PARAM_RM8, 0 }, + {"and", MODRM, PARAM_REG16, PARAM_RM16, 0 }, + {"and", 0, PARAM_AL, PARAM_UI8, 0 }, + {"and", 0, PARAM_AW, PARAM_IMM, 0 }, + {"ds1:", SEG_DS1, 0, 0, 0 }, + {"adj4a", 0, 0, 0, 0 }, + {"sub", MODRM, PARAM_RM8, PARAM_REG8, 0 }, + {"sub", MODRM, PARAM_RM16, PARAM_REG16, 0 }, + {"sub", MODRM, PARAM_REG8, PARAM_RM8, 0 }, + {"sub", MODRM, PARAM_REG16, PARAM_RM16, 0 }, + {"sub", 0, PARAM_AL, PARAM_UI8, 0 }, + {"sub", 0, PARAM_AW, PARAM_IMM, 0 }, + {"ps:", SEG_PS, 0, 0, 0 }, + {"adj4s", 0, 0, 0, 0 }, + // 0x30 + {"xor", MODRM, PARAM_RM8, PARAM_REG8, 0 }, + {"xor", MODRM, PARAM_RM16, PARAM_REG16, 0 }, + {"xor", MODRM, PARAM_REG8, PARAM_RM8, 0 }, + {"xor", MODRM, PARAM_REG16, PARAM_RM16, 0 }, + {"xor", 0, PARAM_AL, PARAM_UI8, 0 }, + {"xor", 0, PARAM_AW, PARAM_IMM, 0 }, + {"ss:", SEG_SS, 0, 0, 0 }, + {"adjba", 0, 0, 0, 0 }, + {"cmp", MODRM, PARAM_RM8, PARAM_REG8, 0 }, + {"cmp", MODRM, PARAM_RM16, PARAM_REG16, 0 }, + {"cmp", MODRM, PARAM_REG8, PARAM_RM8, 0 }, + {"cmp", MODRM, PARAM_REG16, PARAM_RM16, 0 }, + {"cmp", 0, PARAM_AL, PARAM_UI8, 0 }, + {"cmp", 0, PARAM_AW, PARAM_IMM, 0 }, + {"ds0:", SEG_DS0, 0, 0, 0 }, + {"adjbs", 0, 0, 0, 0 }, + // 0x40 + {"inc", 0, PARAM_AW, 0, 0 }, + {"inc", 0, PARAM_CW, 0, 0 }, + {"inc", 0, PARAM_DW, 0, 0 }, + {"inc", 0, PARAM_BW, 0, 0 }, + {"inc", 0, PARAM_SP, 0, 0 }, + {"inc", 0, PARAM_BP, 0, 0 }, + {"inc", 0, PARAM_IX, 0, 0 }, + {"inc", 0, PARAM_IY, 0, 0 }, + {"dec", 0, PARAM_AW, 0, 0 }, + {"dec", 0, PARAM_CW, 0, 0 }, + {"dec", 0, PARAM_DW, 0, 0 }, + {"dec", 0, PARAM_BW, 0, 0 }, + {"dec", 0, PARAM_SP, 0, 0 }, + {"dec", 0, PARAM_BP, 0, 0 }, + {"dec", 0, PARAM_IX, 0, 0 }, + {"dec", 0, PARAM_IY, 0, 0 }, + // 0x50 + {"push", 0, PARAM_AW, 0, 0 }, + {"push", 0, PARAM_CW, 0, 0 }, + {"push", 0, PARAM_DW, 0, 0 }, + {"push", 0, PARAM_BW, 0, 0 }, + {"push", 0, PARAM_SP, 0, 0 }, + {"push", 0, PARAM_BP, 0, 0 }, + {"push", 0, PARAM_IX, 0, 0 }, + {"push", 0, PARAM_IY, 0, 0 }, + {"pop", 0, PARAM_AW, 0, 0 }, + {"pop", 0, PARAM_CW, 0, 0 }, + {"pop", 0, PARAM_DW, 0, 0 }, + {"pop", 0, PARAM_BW, 0, 0 }, + {"pop", 0, PARAM_SP, 0, 0 }, + {"pop", 0, PARAM_BP, 0, 0 }, + {"pop", 0, PARAM_IX, 0, 0 }, + {"pop", 0, PARAM_IY, 0, 0 }, + // 0x60 + {"push r", 0, 0, 0, 0 }, + {"pop r", 0, 0, 0, 0 }, + {"chkind", MODRM, PARAM_REG16, PARAM_RM16, 0 }, + {"brkn", 0, PARAM_UI8, 0, 0, DASMFLAG_STEP_OVER}, /* V25S/V35S only */ + {"repnc", PREFIX, 0, 0, 0 }, + {"repc", PREFIX, 0, 0, 0 }, + {"fpo2 0", 0, 0, 0, 0 }, /* for a coprocessor that was never made */ + {"fpo2 1", 0, 0, 0, 0 }, /* for a coprocessor that was never made */ + {"push", 0, PARAM_IMM, 0, 0 }, + {"mul", MODRM, PARAM_REG16, PARAM_RM16, PARAM_IMM }, + {"push", 0, PARAM_I8, 0, 0 }, + {"mul", MODRM, PARAM_REG16, PARAM_RM16, PARAM_I8 }, + {"inmb", 0, 0, 0, 0 }, + {"inmw", 0, 0, 0, 0 }, + {"outmb", 0, 0, 0, 0 }, + {"outmw", 0, 0, 0, 0 }, + // 0x70 + {"bv", 0, PARAM_REL8, 0, 0 }, + {"bnv", 0, PARAM_REL8, 0, 0 }, + {"bc", 0, PARAM_REL8, 0, 0 }, + {"bnc", 0, PARAM_REL8, 0, 0 }, + {"be", 0, PARAM_REL8, 0, 0 }, + {"bne", 0, PARAM_REL8, 0, 0 }, + {"bnh", 0, PARAM_REL8, 0, 0 }, + {"bh", 0, PARAM_REL8, 0, 0 }, + {"bn", 0, PARAM_REL8, 0, 0 }, + {"bp", 0, PARAM_REL8, 0, 0 }, + {"bpe", 0, PARAM_REL8, 0, 0 }, + {"bpo", 0, PARAM_REL8, 0, 0 }, + {"blt", 0, PARAM_REL8, 0, 0 }, + {"bge", 0, PARAM_REL8, 0, 0 }, + {"ble", 0, PARAM_REL8, 0, 0 }, + {"bgt", 0, PARAM_REL8, 0, 0 }, + // 0x80 + {"immb", GROUP, 0, 0, 0 }, + {"immw", GROUP, 0, 0, 0 }, + {"immb", GROUP, 0, 0, 0 }, + {"immws", GROUP, 0, 0, 0 }, + {"test", MODRM, PARAM_RM8, PARAM_REG8, 0 }, + {"test", MODRM, PARAM_RM16, PARAM_REG16, 0 }, + {"xch", MODRM, PARAM_REG8, PARAM_RM8, 0 }, + {"xch", MODRM, PARAM_REG16, PARAM_RM16, 0 }, + {"mov", MODRM, PARAM_RM8, PARAM_REG8, 0 }, + {"mov", MODRM, PARAM_RM16, PARAM_REG16, 0 }, + {"mov", MODRM, PARAM_REG8, PARAM_RM8, 0 }, + {"mov", MODRM, PARAM_REG16, PARAM_RM16, 0 }, + {"mov", MODRM, PARAM_RM16, PARAM_SREG, 0 }, + {"ldea", MODRM, PARAM_REG16, PARAM_RM16, 0 }, + {"mov", MODRM, PARAM_SREG, PARAM_RM16, 0 }, + {"pop", MODRM, PARAM_RM16, 0, 0 }, + // 0x90 + {"nop", 0, 0, 0, 0 }, + {"xch", 0, PARAM_AW, PARAM_CW, 0 }, + {"xch", 0, PARAM_AW, PARAM_DW, 0 }, + {"xch", 0, PARAM_AW, PARAM_BW, 0 }, + {"xch", 0, PARAM_AW, PARAM_SP, 0 }, + {"xch", 0, PARAM_AW, PARAM_BP, 0 }, + {"xch", 0, PARAM_AW, PARAM_IX, 0 }, + {"xch", 0, PARAM_AW, PARAM_IY, 0 }, + {"cvtbw", 0, 0, 0, 0 }, + {"cvtwl", 0, 0, 0, 0 }, + {"call", 0, PARAM_ADDR, 0, 0, DASMFLAG_STEP_OVER}, + {"poll", 0, 0, 0, 0 }, + {"push psw", 0, 0, 0, 0 }, + {"pop psw", 0, 0, 0, 0 }, + {"mov psw,ah", 0, 0, 0, 0 }, + {"mov ah,psw", 0, 0, 0, 0 }, + // 0xa0 + {"mov", 0, PARAM_AL, PARAM_MEM_OFFS, 0 }, + {"mov", 0, PARAM_AW, PARAM_MEM_OFFS, 0 }, + {"mov", 0, PARAM_MEM_OFFS, PARAM_AL, 0 }, + {"mov", 0, PARAM_MEM_OFFS, PARAM_AW, 0 }, + {"movbkb", 0, 0, 0, 0 }, + {"movbkw", 0, 0, 0, 0 }, + {"cmpbkb", 0, 0, 0, 0 }, + {"cmpbkw", 0, 0, 0, 0 }, + {"test", 0, PARAM_AL, PARAM_UI8, 0 }, + {"test", 0, PARAM_AW, PARAM_IMM, 0 }, + {"stmb", 0, 0, 0, 0 }, + {"stmw", 0, 0, 0, 0 }, + {"ldmb", 0, 0, 0, 0 }, + {"ldmw", 0, 0, 0, 0 }, + {"cmpmb", 0, 0, 0, 0 }, + {"cmpmw", 0, 0, 0, 0 }, + // 0xb0 + {"mov", 0, PARAM_AL, PARAM_UI8, 0 }, + {"mov", 0, PARAM_CL, PARAM_UI8, 0 }, + {"mov", 0, PARAM_DL, PARAM_UI8, 0 }, + {"mov", 0, PARAM_BL, PARAM_UI8, 0 }, + {"mov", 0, PARAM_AH, PARAM_UI8, 0 }, + {"mov", 0, PARAM_CH, PARAM_UI8, 0 }, + {"mov", 0, PARAM_DH, PARAM_UI8, 0 }, + {"mov", 0, PARAM_BH, PARAM_UI8, 0 }, + {"mov", 0, PARAM_AW, PARAM_IMM, 0 }, + {"mov", 0, PARAM_CW, PARAM_IMM, 0 }, + {"mov", 0, PARAM_DW, PARAM_IMM, 0 }, + {"mov", 0, PARAM_BW, PARAM_IMM, 0 }, + {"mov", 0, PARAM_SP, PARAM_IMM, 0 }, + {"mov", 0, PARAM_BP, PARAM_IMM, 0 }, + {"mov", 0, PARAM_IX, PARAM_IMM, 0 }, + {"mov", 0, PARAM_IY, PARAM_IMM, 0 }, + // 0xc0 + {"shiftbi", GROUP, 0, 0, 0 }, + {"shiftwi", GROUP, 0, 0, 0 }, + {"ret", 0, PARAM_I16, 0, 0, DASMFLAG_STEP_OUT}, + {"ret", 0, 0, 0, 0, DASMFLAG_STEP_OUT}, + {"mov ds1,", MODRM, PARAM_REG16, PARAM_RM16, 0 }, + {"mov ds0,", MODRM, PARAM_REG16, PARAM_RM16, 0 }, + {"mov", MODRM, PARAM_RMPTR8, PARAM_UI8, 0 }, + {"mov", MODRM, PARAM_RMPTR16, PARAM_IMM, 0 }, + {"prepare", 0, PARAM_I16, PARAM_UI8, 0 }, + {"dispose", 0, 0, 0, 0 }, + {"retf", 0, PARAM_I16, 0, 0, DASMFLAG_STEP_OUT}, + {"retf", 0, 0, 0, 0, DASMFLAG_STEP_OUT}, + {"brk 3", 0, 0, 0, 0, DASMFLAG_STEP_OVER}, + {"brk", 0, PARAM_UI8, 0, 0, DASMFLAG_STEP_OVER}, + {"brkv", 0, 0, 0, 0 }, + {"reti", 0, 0, 0, 0, DASMFLAG_STEP_OUT}, + // 0xd0 + {"shiftb", GROUP, 0, 0, 0 }, + {"shiftw", GROUP, 0, 0, 0 }, + {"shiftbv", GROUP, 0, 0, 0 }, + {"shiftwv", GROUP, 0, 0, 0 }, + {"cvtbd", 0, PARAM_I8, 0, 0 }, + {"cvtdb", 0, PARAM_I8, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"trans", 0, 0, 0, 0 }, + {"escape", FPU, 0, 0, 0 }, + {"escape", FPU, 0, 0, 0 }, + {"escape", FPU, 0, 0, 0 }, + {"escape", FPU, 0, 0, 0 }, + {"escape", FPU, 0, 0, 0 }, + {"escape", FPU, 0, 0, 0 }, + {"escape", FPU, 0, 0, 0 }, + {"escape", FPU, 0, 0, 0 }, + // 0xe0 + {"dbnzne", 0, PARAM_REL8, 0, 0, DASMFLAG_STEP_OVER}, + {"dbnze", 0, PARAM_REL8, 0, 0, DASMFLAG_STEP_OVER}, + {"dbnz", 0, PARAM_REL8, 0, 0, DASMFLAG_STEP_OVER}, + {"bcwz", 0, PARAM_REL8, 0, 0 }, + {"in", 0, PARAM_AL, PARAM_UI8, 0 }, + {"in", 0, PARAM_AW, PARAM_UI8, 0 }, + {"out", 0, PARAM_UI8, PARAM_AL, 0 }, + {"out", 0, PARAM_UI8, PARAM_AW, 0 }, + {"call", 0, PARAM_REL16, 0, 0, DASMFLAG_STEP_OVER}, + {"br", 0, PARAM_REL16, 0, 0 }, + {"br", 0, PARAM_ADDR, 0, 0 }, + {"br", 0, PARAM_REL8, 0, 0 }, + {"in", 0, PARAM_AL, PARAM_DW, 0 }, + {"in", 0, PARAM_AW, PARAM_DW, 0 }, + {"out", 0, PARAM_DW, PARAM_AL, 0 }, + {"out", 0, PARAM_DW, PARAM_AW, 0 }, + // 0xf0 + {"buslock", PREFIX, 0, 0, 0 }, + {"brks", 0, PARAM_UI8, 0, 0, DASMFLAG_STEP_OVER}, /* V25S/V35S only */ + {"repne", PREFIX, 0, 0, 0 }, + {"rep", PREFIX, 0, 0, 0 }, + {"halt", 0, 0, 0, 0 }, + {"not1 cy", 0, 0, 0, 0 }, + {"group1b", GROUP, 0, 0, 0 }, + {"group1w", GROUP, 0, 0, 0 }, + {"clr1 cy", 0, 0, 0, 0 }, + {"set1 cy", 0, 0, 0, 0 }, + {"di", 0, 0, 0, 0 }, + {"ei", 0, 0, 0, 0 }, + {"clr1 dir", 0, 0, 0, 0 }, + {"set1 dir", 0, 0, 0, 0 }, + {"group2b", GROUP, 0, 0, 0 }, + {"group2w", GROUP, 0, 0, 0 } +}; + +static const NEC_I386_OPCODE necv_opcode_table2[256] = +{ + // 0x00 + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + // 0x10 + {"test1", MODRM, PARAM_RMPTR8, PARAM_CL, 0 }, + {"test1", MODRM, PARAM_RMPTR16, PARAM_CL, 0 }, + {"clr1", MODRM, PARAM_RMPTR8, PARAM_CL, 0 }, + {"clr1", MODRM, PARAM_RMPTR16, PARAM_CL, 0 }, + {"set1", MODRM, PARAM_RMPTR8, PARAM_CL, 0 }, + {"set1", MODRM, PARAM_RMPTR16, PARAM_CL, 0 }, + {"not1", MODRM, PARAM_RMPTR8, PARAM_CL, 0 }, + {"not1", MODRM, PARAM_RMPTR16, PARAM_CL, 0 }, + {"test1", MODRM, PARAM_RMPTR8, PARAM_I3, 0 }, + {"test1", MODRM, PARAM_RMPTR16, PARAM_I4, 0 }, + {"clr1", MODRM, PARAM_RMPTR8, PARAM_I3, 0 }, + {"clr1", MODRM, PARAM_RMPTR16, PARAM_I4, 0 }, + {"set1", MODRM, PARAM_RMPTR8, PARAM_I3, 0 }, + {"set1", MODRM, PARAM_RMPTR16, PARAM_I4, 0 }, + {"not1", MODRM, PARAM_RMPTR8, PARAM_I3, 0 }, + {"not1", MODRM, PARAM_RMPTR16, PARAM_I4, 0 }, + // 0x20 + {"add4s", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"sub4s", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"movspa", 0, 0, 0, 0 }, /* V25/V35 only */ + {"cmp4s", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"rol4", MODRM, PARAM_RMPTR8, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"ror4", MODRM, PARAM_RMPTR8, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"brkcs", MODRM, PARAM_REG2_16, 0, 0, DASMFLAG_STEP_OVER}, /* V25/V35 only */ + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + // 0x30 + {"???", 0, 0, 0, 0 }, + {"ins", MODRM, PARAM_REG2_8, PARAM_REG8, 0 }, + {"???", 0, 0, 0, 0 }, + {"ext", MODRM, PARAM_REG2_8, PARAM_REG8, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"ins", MODRM, PARAM_REG2_8, PARAM_I4, 0 }, + {"???", 0, 0, 0, 0 }, + {"ext", MODRM, PARAM_REG2_8, PARAM_I4, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + // 0x40 + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + // 0x50 + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + // 0x60 + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + // 0x70 + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + // 0x80 + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + // 0x90 + {"???", 0, 0, 0, 0 }, + {"retrbi", 0, 0, 0, 0 }, /* V25/V35 only */ + {"fint", 0, 0, 0, 0 }, /* V25/V35 only */ + {"???", 0, 0, 0, 0 }, + {"tsksw", MODRM, PARAM_REG2_16, 0, 0 }, /* V25/V35 only */ + {"movspb", MODRM, PARAM_REG2_16, 0, 0 }, /* V25/V35 only */ + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"btclr", 0, PARAM_SFREG, PARAM_I3, PARAM_REL8 }, /* V25/V35 only */ + {"???", 0, 0, 0, 0 }, + {"stop", 0, 0, 0, 0 }, /* V25/V35 only */ + {"???", 0, 0, 0, 0 }, + // 0xa0 + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + // 0xb0 + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + // 0xc0 + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + // 0xd0 + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + // 0xe0 + {"brkxa", 0, PARAM_UI8, 0, 0 }, /* V33,53 only */ + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + // 0xf0 + {"retxa", 0, PARAM_UI8, 0, 0 }, /* V33,53 only */ + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"brkem", 0, PARAM_UI8, 0, 0 } /* V20,30,40,50 only */ +}; + +static const NEC_I386_OPCODE immb_table[8] = +{ + {"add", 0, PARAM_RMPTR8, PARAM_UI8, 0 }, + {"or", 0, PARAM_RMPTR8, PARAM_UI8, 0 }, + {"addc", 0, PARAM_RMPTR8, PARAM_UI8, 0 }, + {"subc", 0, PARAM_RMPTR8, PARAM_UI8, 0 }, + {"and", 0, PARAM_RMPTR8, PARAM_UI8, 0 }, + {"sub", 0, PARAM_RMPTR8, PARAM_UI8, 0 }, + {"xor", 0, PARAM_RMPTR8, PARAM_UI8, 0 }, + {"cmp", 0, PARAM_RMPTR8, PARAM_UI8, 0 } +}; + +static const NEC_I386_OPCODE immw_table[8] = +{ + {"add", 0, PARAM_RMPTR16, PARAM_IMM, 0 }, + {"or", 0, PARAM_RMPTR16, PARAM_IMM, 0 }, + {"addc", 0, PARAM_RMPTR16, PARAM_IMM, 0 }, + {"subc", 0, PARAM_RMPTR16, PARAM_IMM, 0 }, + {"and", 0, PARAM_RMPTR16, PARAM_IMM, 0 }, + {"sub", 0, PARAM_RMPTR16, PARAM_IMM, 0 }, + {"xor", 0, PARAM_RMPTR16, PARAM_IMM, 0 }, + {"cmp", 0, PARAM_RMPTR16, PARAM_IMM, 0 } +}; + +static const NEC_I386_OPCODE immws_table[8] = +{ + {"add", 0, PARAM_RMPTR16, PARAM_I8, 0 }, + {"or", 0, PARAM_RMPTR16, PARAM_I8, 0 }, + {"addc", 0, PARAM_RMPTR16, PARAM_I8, 0 }, + {"subc", 0, PARAM_RMPTR16, PARAM_I8, 0 }, + {"and", 0, PARAM_RMPTR16, PARAM_I8, 0 }, + {"sub", 0, PARAM_RMPTR16, PARAM_I8, 0 }, + {"xor", 0, PARAM_RMPTR16, PARAM_I8, 0 }, + {"cmp", 0, PARAM_RMPTR16, PARAM_I8, 0 } +}; + +static const NEC_I386_OPCODE shiftbi_table[8] = +{ + {"rol", 0, PARAM_RMPTR8, PARAM_I8, 0 }, + {"ror", 0, PARAM_RMPTR8, PARAM_I8, 0 }, + {"rolc", 0, PARAM_RMPTR8, PARAM_I8, 0 }, + {"rorc", 0, PARAM_RMPTR8, PARAM_I8, 0 }, + {"shl", 0, PARAM_RMPTR8, PARAM_I8, 0 }, + {"shr", 0, PARAM_RMPTR8, PARAM_I8, 0 }, + {"???", 0, PARAM_RMPTR8, PARAM_I8, 0 }, + {"shra", 0, PARAM_RMPTR8, PARAM_I8, 0 } +}; + +static const NEC_I386_OPCODE shiftwi_table[8] = +{ + {"rol", 0, PARAM_RMPTR16, PARAM_I8, 0 }, + {"ror", 0, PARAM_RMPTR16, PARAM_I8, 0 }, + {"rolc", 0, PARAM_RMPTR16, PARAM_I8, 0 }, + {"rorc", 0, PARAM_RMPTR16, PARAM_I8, 0 }, + {"shl", 0, PARAM_RMPTR16, PARAM_I8, 0 }, + {"shr", 0, PARAM_RMPTR16, PARAM_I8, 0 }, + {"???", 0, PARAM_RMPTR16, PARAM_I8, 0 }, + {"shra", 0, PARAM_RMPTR16, PARAM_I8, 0 } +}; + +static const NEC_I386_OPCODE shiftb_table[8] = +{ + {"rol", 0, PARAM_RMPTR8, PARAM_1, 0 }, + {"ror", 0, PARAM_RMPTR8, PARAM_1, 0 }, + {"rolc", 0, PARAM_RMPTR8, PARAM_1, 0 }, + {"rorc", 0, PARAM_RMPTR8, PARAM_1, 0 }, + {"shl", 0, PARAM_RMPTR8, PARAM_1, 0 }, + {"shr", 0, PARAM_RMPTR8, PARAM_1, 0 }, + {"???", 0, PARAM_RMPTR8, PARAM_1, 0 }, + {"shra", 0, PARAM_RMPTR8, PARAM_1, 0 } +}; + +static const NEC_I386_OPCODE shiftw_table[8] = +{ + {"rol", 0, PARAM_RMPTR16, PARAM_1, 0 }, + {"ror", 0, PARAM_RMPTR16, PARAM_1, 0 }, + {"rolc", 0, PARAM_RMPTR16, PARAM_1, 0 }, + {"rorc", 0, PARAM_RMPTR16, PARAM_1, 0 }, + {"shl", 0, PARAM_RMPTR16, PARAM_1, 0 }, + {"shr", 0, PARAM_RMPTR16, PARAM_1, 0 }, + {"???", 0, PARAM_RMPTR16, PARAM_1, 0 }, + {"shra", 0, PARAM_RMPTR16, PARAM_1, 0 } +}; + +static const NEC_I386_OPCODE shiftbv_table[8] = +{ + {"rol", 0, PARAM_RMPTR8, PARAM_CL, 0 }, + {"ror", 0, PARAM_RMPTR8, PARAM_CL, 0 }, + {"rolc", 0, PARAM_RMPTR8, PARAM_CL, 0 }, + {"rorc", 0, PARAM_RMPTR8, PARAM_CL, 0 }, + {"shl", 0, PARAM_RMPTR8, PARAM_CL, 0 }, + {"shr", 0, PARAM_RMPTR8, PARAM_CL, 0 }, + {"???", 0, PARAM_RMPTR8, PARAM_CL, 0 }, + {"shra", 0, PARAM_RMPTR8, PARAM_CL, 0 } +}; + +static const NEC_I386_OPCODE shiftwv_table[8] = +{ + {"rol", 0, PARAM_RMPTR16, PARAM_CL, 0 }, + {"ror", 0, PARAM_RMPTR16, PARAM_CL, 0 }, + {"rolc", 0, PARAM_RMPTR16, PARAM_CL, 0 }, + {"rorc", 0, PARAM_RMPTR16, PARAM_CL, 0 }, + {"shl", 0, PARAM_RMPTR16, PARAM_CL, 0 }, + {"shr", 0, PARAM_RMPTR16, PARAM_CL, 0 }, + {"???", 0, PARAM_RMPTR16, PARAM_CL, 0 }, + {"shra", 0, PARAM_RMPTR16, PARAM_CL, 0 } +}; + +static const NEC_I386_OPCODE group1b_table[8] = +{ + {"test", 0, PARAM_RMPTR8, PARAM_UI8, 0 }, + {"???", 0, 0, 0, 0 }, + {"not", 0, PARAM_RMPTR8, 0, 0 }, + {"neg", 0, PARAM_RMPTR8, 0, 0 }, + {"mulu", 0, PARAM_RMPTR8, 0, 0 }, + {"mul", 0, PARAM_RMPTR8, 0, 0 }, + {"divu", 0, PARAM_RMPTR8, 0, 0 }, + {"div", 0, PARAM_RMPTR8, 0, 0 } +}; + +static const NEC_I386_OPCODE group1w_table[8] = +{ + {"test", 0, PARAM_RMPTR16, PARAM_IMM, 0 }, + {"???", 0, 0, 0, 0 }, + {"not", 0, PARAM_RMPTR16, 0, 0 }, + {"neg", 0, PARAM_RMPTR16, 0, 0 }, + {"mulu", 0, PARAM_RMPTR16, 0, 0 }, + {"mul", 0, PARAM_RMPTR16, 0, 0 }, + {"divu", 0, PARAM_RMPTR16, 0, 0 }, + {"div", 0, PARAM_RMPTR16, 0, 0 } +}; + +static const NEC_I386_OPCODE group2b_table[8] = +{ + {"inc", 0, PARAM_RMPTR8, 0, 0 }, + {"dec", 0, PARAM_RMPTR8, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 }, + {"???", 0, 0, 0, 0 } +}; + +static const NEC_I386_OPCODE group2w_table[8] = +{ + {"inc", 0, PARAM_RMPTR16, 0, 0 }, + {"dec", 0, PARAM_RMPTR16, 0, 0 }, + {"call", 0, PARAM_RMPTR16, 0, 0, DASMFLAG_STEP_OVER}, + {"call far ptr ",0, PARAM_RM16, 0, 0, DASMFLAG_STEP_OVER}, + {"br", 0, PARAM_RMPTR16, 0, 0 }, + {"br far ptr ",0, PARAM_RM16, 0, 0 }, + {"push", 0, PARAM_RMPTR16, 0, 0 }, + {"???", 0, 0, 0, 0 } +}; + +static const NEC_GROUP_OP group_op_table[] = +{ + { "immb", immb_table }, + { "immw", immw_table }, + { "immws", immws_table }, + { "shiftbi", shiftbi_table }, + { "shiftwi", shiftwi_table }, + { "shiftb", shiftb_table }, + { "shiftw", shiftw_table }, + { "shiftbv", shiftbv_table }, + { "shiftwv", shiftwv_table }, + { "group1b", group1b_table }, + { "group1w", group1w_table }, + { "group2b", group2b_table }, + { "group2w", group2w_table } +}; + + + +static const char *const nec_reg[8] = { "aw", "cw", "dw", "bw", "sp", "bp", "ix", "iy" }; +static const char *const nec_reg8[8] = { "al", "cl", "dl", "bl", "ah", "ch", "dh", "bh" }; +static const char *const nec_sreg[8] = { "ds1", "ps", "ss", "ds0", "???", "???", "???", "???" }; +static const char *const nec_sfreg[256] = +{ + /* 0x00 */ + "p0", "pm0", "pmc0", "???", "???", "???", "???", "???", + "p1", "pm1", "pmc1", "???", "???", "???", "???", "???", + /* 0x10 */ + "p2", "pm2", "pmc2", "???", "???", "???", "???", "???", + "???", "???", "???", "???", "???", "???", "???", "???", + /* 0x20 */ + "???", "???", "???", "???", "???", "???", "???", "???", + "???", "???", "???", "???", "???", "???", "???", "???", + /* 0x30 */ + "???", "???", "???", "???", "???", "???", "???", "???", + "pt", "???", "???", "pmt", "???", "???", "???", "???", + /* 0x40 */ + "intm", "???", "???", "???", "ems0", "ems1", "ems2", "???", + "???", "???", "???", "???", "exic0","exic1","exic2","???", + /* 0x50 */ + "???", "???", "???", "???", "???", "???", "???", "???", + "???", "???", "???", "???", "???", "???", "???", "???", + /* 0x60 */ + "rxb0", "???", "txb0", "???", "???", "srms0","stms0","???", + "scm0", "scc0", "brg0", "scs0", "seic0","sric0","stic0","???", + /* 0x70 */ + "rxb1", "???", "txb1", "???", "???", "srms1","stms1","???", + "scm1", "scc1", "brg1", "scs1", "seic1","sric1","stic1","???", + /* 0x80 */ + "tm0", "???", "md0", "???", "???", "???", "???", "???", + "tm1", "???", "md1", "???", "???", "???", "???", "???", + /* 0x90 */ + "tmc0", "tmc1", "???", "???", "tmms0","tmms1","tmms2","???", + "???", "???", "???", "???", "tmic0","tmic1","tmic2","???", + /* 0xa0 */ + "dmac0","dmam0","dmac1","dmam1","???", "???", "???", "???", + "???", "???", "???", "???", "dic0", "dic1", "???", "???", + /* 0xb0 */ + "???", "???", "???", "???", "???", "???", "???", "???", + "???", "???", "???", "???", "???", "???", "???", "???", + /* 0xc0 */ + "sar0l","sar0m","sar0h","???", "dar0l","dar0m","dar0h","???", + "tc0l", "tc0h", "???", "???", "???", "???", "???", "???", + /* 0xd0 */ + "sar1l","sar1m","sar1h","???", "dar1l","dar1m","dar1h","???", + "tc1l", "tc1h", "???", "???", "???", "???", "???", "???", + /* 0xe0 */ + "stbc", "rfm", "???", "???", "???", "???", "???", "???", + "wtc", "???", "flag", "prc", "tbic", "???", "???", "irqs", + /* 0xf0 */ + "???", "???", "???", "???", "???", "???", "???", "???", + "???", "???", "???", "???", "ispr", "???", "???", "idb" +}; + +static UINT32 pc; +static UINT8 modrm; +static UINT32 segment; +static offs_t dasm_flags; +static char modrm_string[256]; + +#define MODRM_REG1 ((modrm >> 3) & 0x7) +#define MODRM_REG2 (modrm & 0x7) + +#define MAX_LENGTH 8 + +INLINE UINT8 FETCH(void) +{ + if ((opcode_ptr - opcode_ptr_base) + 1 > MAX_LENGTH) + return 0xff; + pc++; + return *opcode_ptr++; +} + +#if 0 +INLINE UINT16 FETCH16(void) +{ + UINT16 d; + if ((opcode_ptr - opcode_ptr_base) + 2 > MAX_LENGTH) + return 0xffff; + d = opcode_ptr[0] | (opcode_ptr[1] << 8); + opcode_ptr += 2; + pc += 2; + return d; +} +#endif + +INLINE UINT8 FETCHD(void) +{ + if ((opcode_ptr - opcode_ptr_base) + 1 > MAX_LENGTH) + return 0xff; + pc++; + return *opcode_ptr++; +} + +INLINE UINT16 FETCHD16(void) +{ + UINT16 d; + if ((opcode_ptr - opcode_ptr_base) + 2 > MAX_LENGTH) + return 0xffff; + d = opcode_ptr[0] | (opcode_ptr[1] << 8); + opcode_ptr += 2; + pc += 2; + return d; +} + +static char *hexstring(UINT32 value, int digits) +{ + static char buffer[20]; + buffer[0] = '0'; + if (digits) + sprintf(&buffer[1], "%0*Xh", digits, value); + else + sprintf(&buffer[1], "%Xh", value); + return (buffer[1] >= '0' && buffer[1] <= '9') ? &buffer[1] : &buffer[0]; +} + +static char *shexstring(UINT32 value, int digits, int always) +{ + static char buffer[20]; + if (value >= 0x80000000) + sprintf(buffer, "-%s", hexstring(-value, digits)); + else if (always) + sprintf(buffer, "+%s", hexstring(value, digits)); + else + return hexstring(value, digits); + return buffer; +} + +static void handle_modrm(char* s) +{ + INT8 disp8; + INT16 disp16; + UINT8 mod, rm; + + modrm = FETCHD(); + mod = (modrm >> 6) & 0x3; + rm = (modrm & 0x7); + + if( modrm >= 0xc0 ) + return; + + switch(segment) + { + case SEG_PS: s += sprintf( s, "ps:" ); break; + case SEG_DS0: s += sprintf( s, "ds0:" ); break; + case SEG_DS1: s += sprintf( s, "ds1:" ); break; + case SEG_SS: s += sprintf( s, "ss:" ); break; + } + + s += sprintf( s, "[" ); + switch( rm ) + { + case 0: s += sprintf( s, "bw+ix" ); break; + case 1: s += sprintf( s, "bw+iy" ); break; + case 2: s += sprintf( s, "bp+ix" ); break; + case 3: s += sprintf( s, "bp+iy" ); break; + case 4: s += sprintf( s, "ix" ); break; + case 5: s += sprintf( s, "iy" ); break; + case 6: + if( mod == 0 ) { + disp16 = FETCHD16(); + s += sprintf( s, "%s", hexstring((unsigned) (UINT16) disp16, 0) ); + } else { + s += sprintf( s, "bp" ); + } + break; + case 7: s += sprintf( s, "bw" ); break; + } + if( mod == 1 ) { + disp8 = FETCHD(); + s += sprintf( s, "%s", shexstring((INT32)disp8, 0, TRUE) ); + } else if( mod == 2 ) { + disp16 = FETCHD16(); + s += sprintf( s, "%s", shexstring((INT32)disp16, 0, TRUE) ); + } + s += sprintf( s, "]" ); +} + +static char* handle_param(char* s, UINT32 param) +{ + UINT8 i8; + UINT16 i16; + UINT16 ptr; + UINT32 addr; + INT8 d8; + INT16 d16; + + switch(param) + { + case PARAM_REG8: + s += sprintf( s, "%s", nec_reg8[MODRM_REG1] ); + break; + + case PARAM_REG16: + s += sprintf( s, "%s", nec_reg[MODRM_REG1] ); + break; + + case PARAM_REG2_8: + s += sprintf( s, "%s", nec_reg8[MODRM_REG2] ); + break; + + case PARAM_REG2_16: + s += sprintf( s, "%s", nec_reg[MODRM_REG2] ); + break; + + case PARAM_RM8: + case PARAM_RMPTR8: + if( modrm >= 0xc0 ) { + s += sprintf( s, "%s", nec_reg8[MODRM_REG2] ); + } else { + if (param == PARAM_RMPTR8) + s += sprintf( s, "byte ptr " ); + s += sprintf( s, "%s", modrm_string ); + } + break; + + case PARAM_RM16: + case PARAM_RMPTR16: + if( modrm >= 0xc0 ) { + s += sprintf( s, "%s", nec_reg[MODRM_REG2] ); + } else { + if (param == PARAM_RMPTR16) + s += sprintf( s, "word ptr " ); + s += sprintf( s, "%s", modrm_string ); + } + break; + + case PARAM_I3: + i8 = FETCHD(); + s += sprintf( s, "%d", i8 & 0x07 ); + break; + + case PARAM_I4: + i8 = FETCHD(); + s += sprintf( s, "%d", i8 & 0x0f ); + break; + + case PARAM_I8: + i8 = FETCHD(); + s += sprintf( s, "%s", shexstring((INT8)i8, 0, FALSE) ); + break; + + case PARAM_I16: + i16 = FETCHD16(); + s += sprintf( s, "%s", shexstring((INT16)i16, 0, FALSE) ); + break; + + case PARAM_UI8: + i8 = FETCHD(); + s += sprintf( s, "%s", shexstring((UINT8)i8, 0, FALSE) ); + break; + + case PARAM_IMM: + i16 = FETCHD16(); + s += sprintf( s, "%s", hexstring(i16, 0) ); + break; + + case PARAM_ADDR: + addr = FETCHD16(); + ptr = FETCHD16(); + s += sprintf( s, "%s:", hexstring(ptr, 4) ); + s += sprintf( s, "%s", hexstring(addr, 0) ); + break; + + case PARAM_REL16: + /* make sure to keep the relative offset within the segment */ + d16 = FETCHD16(); + s += sprintf( s, "%s", hexstring((pc & 0xFFFF0000) | ((pc + d16) & 0x0000FFFF), 0) ); + break; + + case PARAM_REL8: + d8 = FETCHD(); + s += sprintf( s, "%s", hexstring(pc + d8, 0) ); + break; + + case PARAM_MEM_OFFS: + switch(segment) + { + case SEG_PS: s += sprintf( s, "ps:" ); break; + case SEG_DS0: s += sprintf( s, "ds0:" ); break; + case SEG_DS1: s += sprintf( s, "ds1:" ); break; + case SEG_SS: s += sprintf( s, "ss:" ); break; + } + + i16 = FETCHD16(); + s += sprintf( s, "[%s]", hexstring(i16, 0) ); + break; + + case PARAM_SREG: + s += sprintf( s, "%s", nec_sreg[MODRM_REG1] ); + break; + + case PARAM_SFREG: + i8 = FETCHD(); + s += sprintf( s, "%s", nec_sfreg[i8] ); + break; + + case PARAM_1: + s += sprintf( s, "1" ); + break; + + case PARAM_AL: s += sprintf( s, "al" ); break; + case PARAM_CL: s += sprintf( s, "cl" ); break; + case PARAM_DL: s += sprintf( s, "dl" ); break; + case PARAM_BL: s += sprintf( s, "bl" ); break; + case PARAM_AH: s += sprintf( s, "ah" ); break; + case PARAM_CH: s += sprintf( s, "ch" ); break; + case PARAM_DH: s += sprintf( s, "dh" ); break; + case PARAM_BH: s += sprintf( s, "bh" ); break; + + case PARAM_AW: s += sprintf( s, "aw" ); break; + case PARAM_CW: s += sprintf( s, "cw" ); break; + case PARAM_DW: s += sprintf( s, "dw" ); break; + case PARAM_BW: s += sprintf( s, "bw" ); break; + case PARAM_SP: s += sprintf( s, "sp" ); break; + case PARAM_BP: s += sprintf( s, "bp" ); break; + case PARAM_IX: s += sprintf( s, "ix" ); break; + case PARAM_IY: s += sprintf( s, "iy" ); break; + } + return s; +} + +static void handle_fpu(char *s, UINT8 op1, UINT8 op2) +{ + switch (op1 & 0x7) + { + case 0: // Group D8 + { + if (op2 < 0xc0) + { + pc--; // adjust fetch pointer, so modrm byte read again + opcode_ptr--; + handle_modrm( modrm_string ); + switch ((op2 >> 3) & 0x7) + { + case 0: sprintf(s, "fadd dword ptr %s", modrm_string); break; + case 1: sprintf(s, "fmul dword ptr %s", modrm_string); break; + case 2: sprintf(s, "fcom dword ptr %s", modrm_string); break; + case 3: sprintf(s, "fcomp dword ptr %s", modrm_string); break; + case 4: sprintf(s, "fsub dword ptr %s", modrm_string); break; + case 5: sprintf(s, "fsubr dword ptr %s", modrm_string); break; + case 6: sprintf(s, "fdiv dword ptr %s", modrm_string); break; + case 7: sprintf(s, "fdivr dword ptr %s", modrm_string); break; + } + } + else + { + switch ((op2 >> 3) & 0x7) + { + case 0: sprintf(s, "fadd st(0),st(%d)", op2 & 0x7); break; + case 1: sprintf(s, "fcom st(0),st(%d)", op2 & 0x7); break; + case 2: sprintf(s, "fsub st(0),st(%d)", op2 & 0x7); break; + case 3: sprintf(s, "fdiv st(0),st(%d)", op2 & 0x7); break; + case 4: sprintf(s, "fmul st(0),st(%d)", op2 & 0x7); break; + case 5: sprintf(s, "fcomp st(0),st(%d)", op2 & 0x7); break; + case 6: sprintf(s, "fsubr st(0),st(%d)", op2 & 0x7); break; + case 7: sprintf(s, "fdivr st(0),st(%d)", op2 & 0x7); break; + } + } + break; + } + + case 1: // Group D9 + { + if (op2 < 0xc0) + { + pc--; // adjust fetch pointer, so modrm byte read again + opcode_ptr--; + handle_modrm( modrm_string ); + switch ((op2 >> 3) & 0x7) + { + case 0: sprintf(s, "fld dword ptr %s", modrm_string); break; + case 1: sprintf(s, "??? (FPU)"); break; + case 2: sprintf(s, "fst dword ptr %s", modrm_string); break; + case 3: sprintf(s, "fstp dword ptr %s", modrm_string); break; + case 4: sprintf(s, "fldenv word ptr %s", modrm_string); break; + case 5: sprintf(s, "fldcw word ptr %s", modrm_string); break; + case 6: sprintf(s, "fstenv word ptr %s", modrm_string); break; + case 7: sprintf(s, "fstcw word ptr %s", modrm_string); break; + } + } + else + { + switch (op2 & 0x3f) + { + case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: + sprintf(s, "fld st(0),st(%d)", op2 & 0x7); break; + + case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f: + sprintf(s, "fxch st(0),st(%d)", op2 & 0x7); break; + + case 0x10: sprintf(s, "fnop"); break; + case 0x20: sprintf(s, "fchs"); break; + case 0x21: sprintf(s, "fabs"); break; + case 0x24: sprintf(s, "ftst"); break; + case 0x25: sprintf(s, "fxam"); break; + case 0x28: sprintf(s, "fld1"); break; + case 0x29: sprintf(s, "fldl2t"); break; + case 0x2a: sprintf(s, "fldl2e"); break; + case 0x2b: sprintf(s, "fldpi"); break; + case 0x2c: sprintf(s, "fldlg2"); break; + case 0x2d: sprintf(s, "fldln2"); break; + case 0x2e: sprintf(s, "fldz"); break; + case 0x30: sprintf(s, "f2xm1"); break; + case 0x31: sprintf(s, "fyl2x"); break; + case 0x32: sprintf(s, "fptan"); break; + case 0x33: sprintf(s, "fpatan"); break; + case 0x34: sprintf(s, "fxtract"); break; + case 0x35: sprintf(s, "fprem1"); break; + case 0x36: sprintf(s, "fdecstp"); break; + case 0x37: sprintf(s, "fincstp"); break; + case 0x38: sprintf(s, "fprem"); break; + case 0x39: sprintf(s, "fyl2xp1"); break; + case 0x3a: sprintf(s, "fsqrt"); break; + case 0x3b: sprintf(s, "fsincos"); break; + case 0x3c: sprintf(s, "frndint"); break; + case 0x3d: sprintf(s, "fscale"); break; + case 0x3e: sprintf(s, "fsin"); break; + case 0x3f: sprintf(s, "fcos"); break; + + default: sprintf(s, "??? (FPU)"); break; + } + } + break; + } + + case 2: // Group DA + { + if (op2 < 0xc0) + { + pc--; // adjust fetch pointer, so modrm byte read again + opcode_ptr--; + handle_modrm( modrm_string ); + switch ((op2 >> 3) & 0x7) + { + case 0: sprintf(s, "fiadd dword ptr %s", modrm_string); break; + case 1: sprintf(s, "fimul dword ptr %s", modrm_string); break; + case 2: sprintf(s, "ficom dword ptr %s", modrm_string); break; + case 3: sprintf(s, "ficomp dword ptr %s", modrm_string); break; + case 4: sprintf(s, "fisub dword ptr %s", modrm_string); break; + case 5: sprintf(s, "fisubr dword ptr %s", modrm_string); break; + case 6: sprintf(s, "fidiv dword ptr %s", modrm_string); break; + case 7: sprintf(s, "fidivr dword ptr %s", modrm_string); break; + } + } + else + { + switch (op2 & 0x3f) + { + case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: + sprintf(s, "fcmovb st(0),st(%d)", op2 & 0x7); break; + + case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f: + sprintf(s, "fcmove st(0),st(%d)", op2 & 0x7); break; + + case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17: + sprintf(s, "fcmovbe st(0),st(%d)", op2 & 0x7); break; + + case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f: + sprintf(s, "fcmovu st(0),st(%d)", op2 & 0x7); break; + + default: sprintf(s, "??? (FPU)"); break; + + } + } + break; + } + + case 3: // Group DB + { + if (op2 < 0xc0) + { + pc--; // adjust fetch pointer, so modrm byte read again + opcode_ptr--; + handle_modrm( modrm_string ); + switch ((op2 >> 3) & 0x7) + { + case 0: sprintf(s, "fild dword ptr %s", modrm_string); break; + case 1: sprintf(s, "??? (FPU)"); break; + case 2: sprintf(s, "fist dword ptr %s", modrm_string); break; + case 3: sprintf(s, "fistp dword ptr %s", modrm_string); break; + case 4: sprintf(s, "??? (FPU)"); break; + case 5: sprintf(s, "fld tword ptr %s", modrm_string); break; + case 6: sprintf(s, "??? (FPU)"); break; + case 7: sprintf(s, "fstp tword ptr %s", modrm_string); break; + } + } + else + { + switch (op2 & 0x3f) + { + case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: + sprintf(s, "fcmovnb st(0),st(%d)", op2 & 0x7); break; + + case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f: + sprintf(s, "fcmovne st(0),st(%d)", op2 & 0x7); break; + + case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17: + sprintf(s, "fcmovnbe st(0),st(%d)", op2 & 0x7); break; + + case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f: + sprintf(s, "fcmovnu st(0),st(%d)", op2 & 0x7); break; + + case 0x22: sprintf(s, "fclex"); break; + case 0x23: sprintf(s, "finit"); break; + + case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: case 0x2f: + sprintf(s, "fucomi st(0),st(%d)", op2 & 0x7); break; + + case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37: + sprintf(s, "fcomi st(0),st(%d)", op2 & 0x7); break; + + default: sprintf(s, "??? (FPU)"); break; + } + } + break; + } + + case 4: // Group DC + { + if (op2 < 0xc0) + { + pc--; // adjust fetch pointer, so modrm byte read again + opcode_ptr--; + handle_modrm( modrm_string ); + switch ((op2 >> 3) & 0x7) + { + case 0: sprintf(s, "fadd qword ptr %s", modrm_string); break; + case 1: sprintf(s, "fmul qword ptr %s", modrm_string); break; + case 2: sprintf(s, "fcom qword ptr %s", modrm_string); break; + case 3: sprintf(s, "fcomp qword ptr %s", modrm_string); break; + case 4: sprintf(s, "fsub qword ptr %s", modrm_string); break; + case 5: sprintf(s, "fsubr qword ptr %s", modrm_string); break; + case 6: sprintf(s, "fdiv qword ptr %s", modrm_string); break; + case 7: sprintf(s, "fdivr qword ptr %s", modrm_string); break; + } + } + else + { + switch (op2 & 0x3f) + { + case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: + sprintf(s, "fadd st(%d),st(0)", op2 & 0x7); break; + + case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f: + sprintf(s, "fmul st(%d),st(0)", op2 & 0x7); break; + + case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27: + sprintf(s, "fsubr st(%d),st(0)", op2 & 0x7); break; + + case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: case 0x2f: + sprintf(s, "fsub st(%d),st(0)", op2 & 0x7); break; + + case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37: + sprintf(s, "fdivr st(%d),st(0)", op2 & 0x7); break; + + case 0x38: case 0x39: case 0x3a: case 0x3b: case 0x3c: case 0x3d: case 0x3e: case 0x3f: + sprintf(s, "fdiv st(%d),st(0)", op2 & 0x7); break; + + default: sprintf(s, "??? (FPU)"); break; + } + } + break; + } + + case 5: // Group DD + { + if (op2 < 0xc0) + { + pc--; // adjust fetch pointer, so modrm byte read again + opcode_ptr--; + handle_modrm( modrm_string ); + switch ((op2 >> 3) & 0x7) + { + case 0: sprintf(s, "fld qword ptr %s", modrm_string); break; + case 1: sprintf(s, "??? (FPU)"); break; + case 2: sprintf(s, "fst qword ptr %s", modrm_string); break; + case 3: sprintf(s, "fstp qword ptr %s", modrm_string); break; + case 4: sprintf(s, "frstor %s", modrm_string); break; + case 5: sprintf(s, "??? (FPU)"); break; + case 6: sprintf(s, "fsave %s", modrm_string); break; + case 7: sprintf(s, "fstsw word ptr %s", modrm_string); break; + } + } + else + { + switch (op2 & 0x3f) + { + case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: + sprintf(s, "ffree st(%d)", op2 & 0x7); break; + + case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17: + sprintf(s, "fst st(%d)", op2 & 0x7); break; + + case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f: + sprintf(s, "fstp st(%d)", op2 & 0x7); break; + + case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27: + sprintf(s, "fucom st(%d), st(0)", op2 & 0x7); break; + + case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: case 0x2f: + sprintf(s, "fucomp st(%d)", op2 & 0x7); break; + + default: sprintf(s, "??? (FPU)"); break; + } + } + break; + } + + case 6: // Group DE + { + if (op2 < 0xc0) + { + pc--; // adjust fetch pointer, so modrm byte read again + opcode_ptr--; + handle_modrm( modrm_string ); + switch ((op2 >> 3) & 0x7) + { + case 0: sprintf(s, "fiadd word ptr %s", modrm_string); break; + case 1: sprintf(s, "fimul word ptr %s", modrm_string); break; + case 2: sprintf(s, "ficom word ptr %s", modrm_string); break; + case 3: sprintf(s, "ficomp word ptr %s", modrm_string); break; + case 4: sprintf(s, "fisub word ptr %s", modrm_string); break; + case 5: sprintf(s, "fisubr word ptr %s", modrm_string); break; + case 6: sprintf(s, "fidiv word ptr %s", modrm_string); break; + case 7: sprintf(s, "fidivr word ptr %s", modrm_string); break; + } + } + else + { + switch (op2 & 0x3f) + { + case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: + sprintf(s, "faddp st(%d)", op2 & 0x7); break; + + case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f: + sprintf(s, "fmulp st(%d)", op2 & 0x7); break; + + case 0x19: sprintf(s, "fcompp"); break; + + case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27: + sprintf(s, "fsubrp st(%d)", op2 & 0x7); break; + + case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: case 0x2f: + sprintf(s, "fsubp st(%d)", op2 & 0x7); break; + + case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37: + sprintf(s, "fdivrp st(%d), st(0)", op2 & 0x7); break; + + case 0x38: case 0x39: case 0x3a: case 0x3b: case 0x3c: case 0x3d: case 0x3e: case 0x3f: + sprintf(s, "fdivp st(%d)", op2 & 0x7); break; + + default: sprintf(s, "??? (FPU)"); break; + } + } + break; + } + + case 7: // Group DF + { + if (op2 < 0xc0) + { + pc--; // adjust fetch pointer, so modrm byte read again + opcode_ptr--; + handle_modrm( modrm_string ); + switch ((op2 >> 3) & 0x7) + { + case 0: sprintf(s, "fild word ptr %s", modrm_string); break; + case 1: sprintf(s, "??? (FPU)"); break; + case 2: sprintf(s, "fist word ptr %s", modrm_string); break; + case 3: sprintf(s, "fistp word ptr %s", modrm_string); break; + case 4: sprintf(s, "fbld %s", modrm_string); break; + case 5: sprintf(s, "fild qword ptr %s", modrm_string); break; + case 6: sprintf(s, "fbstp %s", modrm_string); break; + case 7: sprintf(s, "fistp qword ptr %s", modrm_string); break; + } + } + else + { + switch (op2 & 0x3f) + { + case 0x20: sprintf(s, "fstsw aw"); break; + + case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: case 0x2f: + sprintf(s, "fucomip st(%d)", op2 & 0x7); break; + + case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37: + sprintf(s, "fcomip st(%d),st(0)", op2 & 0x7); break; + + default: sprintf(s, "??? (FPU)"); break; + } + } + break; + } + } +} + +static void decode_opcode(char *s, const NEC_I386_OPCODE *op, UINT8 op1 ) +{ + int i; + UINT8 op2; + + switch( op->flags ) + { + case TWO_BYTE: + op2 = FETCHD(); + decode_opcode( s, &necv_opcode_table2[op2], op1 ); + return; + + case SEG_PS: + case SEG_DS0: + case SEG_DS1: + case SEG_SS: + segment = op->flags; + op2 = FETCH(); + if (Iconfig) op2 = Iconfig[op2]; + decode_opcode( s, &necv_opcode_table1[op2], op1 ); + return; + + case PREFIX: + s += sprintf( s, "%-8s", op->mnemonic ); + op2 = FETCH(); + if (Iconfig) op2 = Iconfig[op2]; + decode_opcode( s, &necv_opcode_table1[op2], op1 ); + return; + + case GROUP: + handle_modrm( modrm_string ); + for( i=0; i < ARRAY_LENGTH(group_op_table); i++ ) { + if( strcmp(op->mnemonic, group_op_table[i].mnemonic) == 0 ) + { + decode_opcode( s, &group_op_table[i].opcode[MODRM_REG1], op1 ); + return; + } + } + goto handle_unknown; + + case FPU: + op2 = FETCHD(); + handle_fpu( s, op1, op2); + return; + + case MODRM: + handle_modrm( modrm_string ); + break; + } + + s += sprintf( s, "%-8s", op->mnemonic ); + dasm_flags = op->dasm_flags; + + if( op->param1 != 0 ) { + s = handle_param( s, op->param1 ); + } + + if( op->param2 != 0 ) { + s += sprintf( s, "," ); + s = handle_param( s, op->param2 ); + } + + if( op->param3 != 0 ) { + s += sprintf( s, "," ); + s = handle_param( s, op->param3 ); + } + return; + +handle_unknown: + sprintf(s, "???"); +} + +int necv_dasm_one(char *buffer, UINT32 eip, const UINT8 *oprom, const UINT8 *decryption_table) +{ + UINT8 op; + Iconfig = decryption_table; + + opcode_ptr = opcode_ptr_base = oprom; + pc = eip; + dasm_flags = 0; + segment = 0; + + op = FETCH(); + + if (Iconfig) op = Iconfig[op]; + + decode_opcode( buffer, &necv_opcode_table1[op], op ); + return (pc-eip) | dasm_flags | DASMFLAG_SUPPORTED; +} + +CPU_DISASSEMBLE( nec ) +{ + return necv_dasm_one(buffer, pc, oprom, NULL); +} diff --git a/src/devices/cpu/nec/necea.h b/src/devices/cpu/nec/necea.h new file mode 100644 index 00000000000..2633637304a --- /dev/null +++ b/src/devices/cpu/nec/necea.h @@ -0,0 +1,59 @@ +// license:BSD-3-Clause +// copyright-holders:Bryan McPhail + +UINT32 nec_common_device::EA_000() { m_EO=Wreg(BW)+Wreg(IX); m_EA=DefaultBase(DS0)+m_EO; return m_EA; } +UINT32 nec_common_device::EA_001() { m_EO=Wreg(BW)+Wreg(IY); m_EA=DefaultBase(DS0)+m_EO; return m_EA; } +UINT32 nec_common_device::EA_002() { m_EO=Wreg(BP)+Wreg(IX); m_EA=DefaultBase(SS)+m_EO; return m_EA; } +UINT32 nec_common_device::EA_003() { m_EO=Wreg(BP)+Wreg(IY); m_EA=DefaultBase(SS)+m_EO; return m_EA; } +UINT32 nec_common_device::EA_004() { m_EO=Wreg(IX); m_EA=DefaultBase(DS0)+m_EO; return m_EA; } +UINT32 nec_common_device::EA_005() { m_EO=Wreg(IY); m_EA=DefaultBase(DS0)+m_EO; return m_EA; } +UINT32 nec_common_device::EA_006() { m_EO=FETCH(); m_EO+=FETCH()<<8; m_EA=DefaultBase(DS0)+m_EO; return m_EA; } +UINT32 nec_common_device::EA_007() { m_EO=Wreg(BW); m_EA=DefaultBase(DS0)+m_EO; return m_EA; } + +UINT32 nec_common_device::EA_100() { m_EO=(Wreg(BW)+Wreg(IX)+(INT8)FETCH()); m_EA=DefaultBase(DS0)+m_EO; return m_EA; } +UINT32 nec_common_device::EA_101() { m_EO=(Wreg(BW)+Wreg(IY)+(INT8)FETCH()); m_EA=DefaultBase(DS0)+m_EO; return m_EA; } +UINT32 nec_common_device::EA_102() { m_EO=(Wreg(BP)+Wreg(IX)+(INT8)FETCH()); m_EA=DefaultBase(SS)+m_EO; return m_EA; } +UINT32 nec_common_device::EA_103() { m_EO=(Wreg(BP)+Wreg(IY)+(INT8)FETCH()); m_EA=DefaultBase(SS)+m_EO; return m_EA; } +UINT32 nec_common_device::EA_104() { m_EO=(Wreg(IX)+(INT8)FETCH()); m_EA=DefaultBase(DS0)+m_EO; return m_EA; } +UINT32 nec_common_device::EA_105() { m_EO=(Wreg(IY)+(INT8)FETCH()); m_EA=DefaultBase(DS0)+m_EO; return m_EA; } +UINT32 nec_common_device::EA_106() { m_EO=(Wreg(BP)+(INT8)FETCH()); m_EA=DefaultBase(SS)+m_EO; return m_EA; } +UINT32 nec_common_device::EA_107() { m_EO=(Wreg(BW)+(INT8)FETCH()); m_EA=DefaultBase(DS0)+m_EO; return m_EA; } + +UINT32 nec_common_device::EA_200() { m_E16=FETCH(); m_E16+=FETCH()<<8; m_EO=Wreg(BW)+Wreg(IX)+(INT16)m_E16; m_EA=DefaultBase(DS0)+m_EO; return m_EA; } +UINT32 nec_common_device::EA_201() { m_E16=FETCH(); m_E16+=FETCH()<<8; m_EO=Wreg(BW)+Wreg(IY)+(INT16)m_E16; m_EA=DefaultBase(DS0)+m_EO; return m_EA; } +UINT32 nec_common_device::EA_202() { m_E16=FETCH(); m_E16+=FETCH()<<8; m_EO=Wreg(BP)+Wreg(IX)+(INT16)m_E16; m_EA=DefaultBase(SS)+m_EO; return m_EA; } +UINT32 nec_common_device::EA_203() { m_E16=FETCH(); m_E16+=FETCH()<<8; m_EO=Wreg(BP)+Wreg(IY)+(INT16)m_E16; m_EA=DefaultBase(SS)+m_EO; return m_EA; } +UINT32 nec_common_device::EA_204() { m_E16=FETCH(); m_E16+=FETCH()<<8; m_EO=Wreg(IX)+(INT16)m_E16; m_EA=DefaultBase(DS0)+m_EO; return m_EA; } +UINT32 nec_common_device::EA_205() { m_E16=FETCH(); m_E16+=FETCH()<<8; m_EO=Wreg(IY)+(INT16)m_E16; m_EA=DefaultBase(DS0)+m_EO; return m_EA; } +UINT32 nec_common_device::EA_206() { m_E16=FETCH(); m_E16+=FETCH()<<8; m_EO=Wreg(BP)+(INT16)m_E16; m_EA=DefaultBase(SS)+m_EO; return m_EA; } +UINT32 nec_common_device::EA_207() { m_E16=FETCH(); m_E16+=FETCH()<<8; m_EO=Wreg(BW)+(INT16)m_E16; m_EA=DefaultBase(DS0)+m_EO; return m_EA; } + +const nec_common_device::nec_eahandler nec_common_device::s_GetEA[192]= +{ + &nec_common_device::EA_000, &nec_common_device::EA_001, &nec_common_device::EA_002, &nec_common_device::EA_003, &nec_common_device::EA_004, &nec_common_device::EA_005, &nec_common_device::EA_006, &nec_common_device::EA_007, + &nec_common_device::EA_000, &nec_common_device::EA_001, &nec_common_device::EA_002, &nec_common_device::EA_003, &nec_common_device::EA_004, &nec_common_device::EA_005, &nec_common_device::EA_006, &nec_common_device::EA_007, + &nec_common_device::EA_000, &nec_common_device::EA_001, &nec_common_device::EA_002, &nec_common_device::EA_003, &nec_common_device::EA_004, &nec_common_device::EA_005, &nec_common_device::EA_006, &nec_common_device::EA_007, + &nec_common_device::EA_000, &nec_common_device::EA_001, &nec_common_device::EA_002, &nec_common_device::EA_003, &nec_common_device::EA_004, &nec_common_device::EA_005, &nec_common_device::EA_006, &nec_common_device::EA_007, + &nec_common_device::EA_000, &nec_common_device::EA_001, &nec_common_device::EA_002, &nec_common_device::EA_003, &nec_common_device::EA_004, &nec_common_device::EA_005, &nec_common_device::EA_006, &nec_common_device::EA_007, + &nec_common_device::EA_000, &nec_common_device::EA_001, &nec_common_device::EA_002, &nec_common_device::EA_003, &nec_common_device::EA_004, &nec_common_device::EA_005, &nec_common_device::EA_006, &nec_common_device::EA_007, + &nec_common_device::EA_000, &nec_common_device::EA_001, &nec_common_device::EA_002, &nec_common_device::EA_003, &nec_common_device::EA_004, &nec_common_device::EA_005, &nec_common_device::EA_006, &nec_common_device::EA_007, + &nec_common_device::EA_000, &nec_common_device::EA_001, &nec_common_device::EA_002, &nec_common_device::EA_003, &nec_common_device::EA_004, &nec_common_device::EA_005, &nec_common_device::EA_006, &nec_common_device::EA_007, + + &nec_common_device::EA_100, &nec_common_device::EA_101, &nec_common_device::EA_102, &nec_common_device::EA_103, &nec_common_device::EA_104, &nec_common_device::EA_105, &nec_common_device::EA_106, &nec_common_device::EA_107, + &nec_common_device::EA_100, &nec_common_device::EA_101, &nec_common_device::EA_102, &nec_common_device::EA_103, &nec_common_device::EA_104, &nec_common_device::EA_105, &nec_common_device::EA_106, &nec_common_device::EA_107, + &nec_common_device::EA_100, &nec_common_device::EA_101, &nec_common_device::EA_102, &nec_common_device::EA_103, &nec_common_device::EA_104, &nec_common_device::EA_105, &nec_common_device::EA_106, &nec_common_device::EA_107, + &nec_common_device::EA_100, &nec_common_device::EA_101, &nec_common_device::EA_102, &nec_common_device::EA_103, &nec_common_device::EA_104, &nec_common_device::EA_105, &nec_common_device::EA_106, &nec_common_device::EA_107, + &nec_common_device::EA_100, &nec_common_device::EA_101, &nec_common_device::EA_102, &nec_common_device::EA_103, &nec_common_device::EA_104, &nec_common_device::EA_105, &nec_common_device::EA_106, &nec_common_device::EA_107, + &nec_common_device::EA_100, &nec_common_device::EA_101, &nec_common_device::EA_102, &nec_common_device::EA_103, &nec_common_device::EA_104, &nec_common_device::EA_105, &nec_common_device::EA_106, &nec_common_device::EA_107, + &nec_common_device::EA_100, &nec_common_device::EA_101, &nec_common_device::EA_102, &nec_common_device::EA_103, &nec_common_device::EA_104, &nec_common_device::EA_105, &nec_common_device::EA_106, &nec_common_device::EA_107, + &nec_common_device::EA_100, &nec_common_device::EA_101, &nec_common_device::EA_102, &nec_common_device::EA_103, &nec_common_device::EA_104, &nec_common_device::EA_105, &nec_common_device::EA_106, &nec_common_device::EA_107, + + &nec_common_device::EA_200, &nec_common_device::EA_201, &nec_common_device::EA_202, &nec_common_device::EA_203, &nec_common_device::EA_204, &nec_common_device::EA_205, &nec_common_device::EA_206, &nec_common_device::EA_207, + &nec_common_device::EA_200, &nec_common_device::EA_201, &nec_common_device::EA_202, &nec_common_device::EA_203, &nec_common_device::EA_204, &nec_common_device::EA_205, &nec_common_device::EA_206, &nec_common_device::EA_207, + &nec_common_device::EA_200, &nec_common_device::EA_201, &nec_common_device::EA_202, &nec_common_device::EA_203, &nec_common_device::EA_204, &nec_common_device::EA_205, &nec_common_device::EA_206, &nec_common_device::EA_207, + &nec_common_device::EA_200, &nec_common_device::EA_201, &nec_common_device::EA_202, &nec_common_device::EA_203, &nec_common_device::EA_204, &nec_common_device::EA_205, &nec_common_device::EA_206, &nec_common_device::EA_207, + &nec_common_device::EA_200, &nec_common_device::EA_201, &nec_common_device::EA_202, &nec_common_device::EA_203, &nec_common_device::EA_204, &nec_common_device::EA_205, &nec_common_device::EA_206, &nec_common_device::EA_207, + &nec_common_device::EA_200, &nec_common_device::EA_201, &nec_common_device::EA_202, &nec_common_device::EA_203, &nec_common_device::EA_204, &nec_common_device::EA_205, &nec_common_device::EA_206, &nec_common_device::EA_207, + &nec_common_device::EA_200, &nec_common_device::EA_201, &nec_common_device::EA_202, &nec_common_device::EA_203, &nec_common_device::EA_204, &nec_common_device::EA_205, &nec_common_device::EA_206, &nec_common_device::EA_207, + &nec_common_device::EA_200, &nec_common_device::EA_201, &nec_common_device::EA_202, &nec_common_device::EA_203, &nec_common_device::EA_204, &nec_common_device::EA_205, &nec_common_device::EA_206, &nec_common_device::EA_207 +}; diff --git a/src/devices/cpu/nec/necinstr.h b/src/devices/cpu/nec/necinstr.h new file mode 100644 index 00000000000..6dd8d52aa49 --- /dev/null +++ b/src/devices/cpu/nec/necinstr.h @@ -0,0 +1,262 @@ +// license:BSD-3-Clause +// copyright-holders:Bryan McPhail + +const nec_common_device::nec_ophandler nec_common_device::s_nec_instruction[256] = +{ + &nec_common_device::i_add_br8, /* 0x00 */ + &nec_common_device::i_add_wr16, /* 0x01 */ + &nec_common_device::i_add_r8b, /* 0x02 */ + &nec_common_device::i_add_r16w, /* 0x03 */ + &nec_common_device::i_add_ald8, /* 0x04 */ + &nec_common_device::i_add_axd16, /* 0x05 */ + &nec_common_device::i_push_es, /* 0x06 */ + &nec_common_device::i_pop_es, /* 0x07 */ + &nec_common_device::i_or_br8, /* 0x08 */ + &nec_common_device::i_or_wr16, /* 0x09 */ + &nec_common_device::i_or_r8b, /* 0x0a */ + &nec_common_device::i_or_r16w, /* 0x0b */ + &nec_common_device::i_or_ald8, /* 0x0c */ + &nec_common_device::i_or_axd16, /* 0x0d */ + &nec_common_device::i_push_cs, /* 0x0e */ + &nec_common_device::i_pre_nec, /* 0x0f */ + &nec_common_device::i_adc_br8, /* 0x10 */ + &nec_common_device::i_adc_wr16, /* 0x11 */ + &nec_common_device::i_adc_r8b, /* 0x12 */ + &nec_common_device::i_adc_r16w, /* 0x13 */ + &nec_common_device::i_adc_ald8, /* 0x14 */ + &nec_common_device::i_adc_axd16, /* 0x15 */ + &nec_common_device::i_push_ss, /* 0x16 */ + &nec_common_device::i_pop_ss, /* 0x17 */ + &nec_common_device::i_sbb_br8, /* 0x18 */ + &nec_common_device::i_sbb_wr16, /* 0x19 */ + &nec_common_device::i_sbb_r8b, /* 0x1a */ + &nec_common_device::i_sbb_r16w, /* 0x1b */ + &nec_common_device::i_sbb_ald8, /* 0x1c */ + &nec_common_device::i_sbb_axd16, /* 0x1d */ + &nec_common_device::i_push_ds, /* 0x1e */ + &nec_common_device::i_pop_ds, /* 0x1f */ + &nec_common_device::i_and_br8, /* 0x20 */ + &nec_common_device::i_and_wr16, /* 0x21 */ + &nec_common_device::i_and_r8b, /* 0x22 */ + &nec_common_device::i_and_r16w, /* 0x23 */ + &nec_common_device::i_and_ald8, /* 0x24 */ + &nec_common_device::i_and_axd16, /* 0x25 */ + &nec_common_device::i_es, /* 0x26 */ + &nec_common_device::i_daa, /* 0x27 */ + &nec_common_device::i_sub_br8, /* 0x28 */ + &nec_common_device::i_sub_wr16, /* 0x29 */ + &nec_common_device::i_sub_r8b, /* 0x2a */ + &nec_common_device::i_sub_r16w, /* 0x2b */ + &nec_common_device::i_sub_ald8, /* 0x2c */ + &nec_common_device::i_sub_axd16, /* 0x2d */ + &nec_common_device::i_cs, /* 0x2e */ + &nec_common_device::i_das, /* 0x2f */ + &nec_common_device::i_xor_br8, /* 0x30 */ + &nec_common_device::i_xor_wr16, /* 0x31 */ + &nec_common_device::i_xor_r8b, /* 0x32 */ + &nec_common_device::i_xor_r16w, /* 0x33 */ + &nec_common_device::i_xor_ald8, /* 0x34 */ + &nec_common_device::i_xor_axd16, /* 0x35 */ + &nec_common_device::i_ss, /* 0x36 */ + &nec_common_device::i_aaa, /* 0x37 */ + &nec_common_device::i_cmp_br8, /* 0x38 */ + &nec_common_device::i_cmp_wr16, /* 0x39 */ + &nec_common_device::i_cmp_r8b, /* 0x3a */ + &nec_common_device::i_cmp_r16w, /* 0x3b */ + &nec_common_device::i_cmp_ald8, /* 0x3c */ + &nec_common_device::i_cmp_axd16, /* 0x3d */ + &nec_common_device::i_ds, /* 0x3e */ + &nec_common_device::i_aas, /* 0x3f */ + &nec_common_device::i_inc_ax, /* 0x40 */ + &nec_common_device::i_inc_cx, /* 0x41 */ + &nec_common_device::i_inc_dx, /* 0x42 */ + &nec_common_device::i_inc_bx, /* 0x43 */ + &nec_common_device::i_inc_sp, /* 0x44 */ + &nec_common_device::i_inc_bp, /* 0x45 */ + &nec_common_device::i_inc_si, /* 0x46 */ + &nec_common_device::i_inc_di, /* 0x47 */ + &nec_common_device::i_dec_ax, /* 0x48 */ + &nec_common_device::i_dec_cx, /* 0x49 */ + &nec_common_device::i_dec_dx, /* 0x4a */ + &nec_common_device::i_dec_bx, /* 0x4b */ + &nec_common_device::i_dec_sp, /* 0x4c */ + &nec_common_device::i_dec_bp, /* 0x4d */ + &nec_common_device::i_dec_si, /* 0x4e */ + &nec_common_device::i_dec_di, /* 0x4f */ + &nec_common_device::i_push_ax, /* 0x50 */ + &nec_common_device::i_push_cx, /* 0x51 */ + &nec_common_device::i_push_dx, /* 0x52 */ + &nec_common_device::i_push_bx, /* 0x53 */ + &nec_common_device::i_push_sp, /* 0x54 */ + &nec_common_device::i_push_bp, /* 0x55 */ + &nec_common_device::i_push_si, /* 0x56 */ + &nec_common_device::i_push_di, /* 0x57 */ + &nec_common_device::i_pop_ax, /* 0x58 */ + &nec_common_device::i_pop_cx, /* 0x59 */ + &nec_common_device::i_pop_dx, /* 0x5a */ + &nec_common_device::i_pop_bx, /* 0x5b */ + &nec_common_device::i_pop_sp, /* 0x5c */ + &nec_common_device::i_pop_bp, /* 0x5d */ + &nec_common_device::i_pop_si, /* 0x5e */ + &nec_common_device::i_pop_di, /* 0x5f */ + &nec_common_device::i_pusha, /* 0x60 */ + &nec_common_device::i_popa, /* 0x61 */ + &nec_common_device::i_chkind, /* 0x62 */ + &nec_common_device::i_invalid, /* 0x63 */ + &nec_common_device::i_repnc, /* 0x64 */ + &nec_common_device::i_repc, /* 0x65 */ + &nec_common_device::i_invalid, /* 0x66 */ + &nec_common_device::i_invalid, /* 0x67 */ + &nec_common_device::i_push_d16, /* 0x68 */ + &nec_common_device::i_imul_d16, /* 0x69 */ + &nec_common_device::i_push_d8, /* 0x6a */ + &nec_common_device::i_imul_d8, /* 0x6b */ + &nec_common_device::i_insb, /* 0x6c */ + &nec_common_device::i_insw, /* 0x6d */ + &nec_common_device::i_outsb, /* 0x6e */ + &nec_common_device::i_outsw, /* 0x6f */ + &nec_common_device::i_jo, /* 0x70 */ + &nec_common_device::i_jno, /* 0x71 */ + &nec_common_device::i_jc, /* 0x72 */ + &nec_common_device::i_jnc, /* 0x73 */ + &nec_common_device::i_jz, /* 0x74 */ + &nec_common_device::i_jnz, /* 0x75 */ + &nec_common_device::i_jce, /* 0x76 */ + &nec_common_device::i_jnce, /* 0x77 */ + &nec_common_device::i_js, /* 0x78 */ + &nec_common_device::i_jns, /* 0x79 */ + &nec_common_device::i_jp, /* 0x7a */ + &nec_common_device::i_jnp, /* 0x7b */ + &nec_common_device::i_jl, /* 0x7c */ + &nec_common_device::i_jnl, /* 0x7d */ + &nec_common_device::i_jle, /* 0x7e */ + &nec_common_device::i_jnle, /* 0x7f */ + &nec_common_device::i_80pre, /* 0x80 */ + &nec_common_device::i_81pre, /* 0x81 */ + &nec_common_device::i_82pre, /* 0x82 */ + &nec_common_device::i_83pre, /* 0x83 */ + &nec_common_device::i_test_br8, /* 0x84 */ + &nec_common_device::i_test_wr16, /* 0x85 */ + &nec_common_device::i_xchg_br8, /* 0x86 */ + &nec_common_device::i_xchg_wr16, /* 0x87 */ + &nec_common_device::i_mov_br8, /* 0x88 */ + &nec_common_device::i_mov_wr16, /* 0x89 */ + &nec_common_device::i_mov_r8b, /* 0x8a */ + &nec_common_device::i_mov_r16w, /* 0x8b */ + &nec_common_device::i_mov_wsreg, /* 0x8c */ + &nec_common_device::i_lea, /* 0x8d */ + &nec_common_device::i_mov_sregw, /* 0x8e */ + &nec_common_device::i_popw, /* 0x8f */ + &nec_common_device::i_nop, /* 0x90 */ + &nec_common_device::i_xchg_axcx, /* 0x91 */ + &nec_common_device::i_xchg_axdx, /* 0x92 */ + &nec_common_device::i_xchg_axbx, /* 0x93 */ + &nec_common_device::i_xchg_axsp, /* 0x94 */ + &nec_common_device::i_xchg_axbp, /* 0x95 */ + &nec_common_device::i_xchg_axsi, /* 0x96 */ + &nec_common_device::i_xchg_axdi, /* 0x97 */ + &nec_common_device::i_cbw, /* 0x98 */ + &nec_common_device::i_cwd, /* 0x99 */ + &nec_common_device::i_call_far, /* 0x9a */ + &nec_common_device::i_wait, /* 0x9b */ + &nec_common_device::i_pushf, /* 0x9c */ + &nec_common_device::i_popf, /* 0x9d */ + &nec_common_device::i_sahf, /* 0x9e */ + &nec_common_device::i_lahf, /* 0x9f */ + &nec_common_device::i_mov_aldisp, /* 0xa0 */ + &nec_common_device::i_mov_axdisp, /* 0xa1 */ + &nec_common_device::i_mov_dispal, /* 0xa2 */ + &nec_common_device::i_mov_dispax, /* 0xa3 */ + &nec_common_device::i_movsb, /* 0xa4 */ + &nec_common_device::i_movsw, /* 0xa5 */ + &nec_common_device::i_cmpsb, /* 0xa6 */ + &nec_common_device::i_cmpsw, /* 0xa7 */ + &nec_common_device::i_test_ald8, /* 0xa8 */ + &nec_common_device::i_test_axd16, /* 0xa9 */ + &nec_common_device::i_stosb, /* 0xaa */ + &nec_common_device::i_stosw, /* 0xab */ + &nec_common_device::i_lodsb, /* 0xac */ + &nec_common_device::i_lodsw, /* 0xad */ + &nec_common_device::i_scasb, /* 0xae */ + &nec_common_device::i_scasw, /* 0xaf */ + &nec_common_device::i_mov_ald8, /* 0xb0 */ + &nec_common_device::i_mov_cld8, /* 0xb1 */ + &nec_common_device::i_mov_dld8, /* 0xb2 */ + &nec_common_device::i_mov_bld8, /* 0xb3 */ + &nec_common_device::i_mov_ahd8, /* 0xb4 */ + &nec_common_device::i_mov_chd8, /* 0xb5 */ + &nec_common_device::i_mov_dhd8, /* 0xb6 */ + &nec_common_device::i_mov_bhd8, /* 0xb7 */ + &nec_common_device::i_mov_axd16, /* 0xb8 */ + &nec_common_device::i_mov_cxd16, /* 0xb9 */ + &nec_common_device::i_mov_dxd16, /* 0xba */ + &nec_common_device::i_mov_bxd16, /* 0xbb */ + &nec_common_device::i_mov_spd16, /* 0xbc */ + &nec_common_device::i_mov_bpd16, /* 0xbd */ + &nec_common_device::i_mov_sid16, /* 0xbe */ + &nec_common_device::i_mov_did16, /* 0xbf */ + &nec_common_device::i_rotshft_bd8, /* 0xc0 */ + &nec_common_device::i_rotshft_wd8, /* 0xc1 */ + &nec_common_device::i_ret_d16, /* 0xc2 */ + &nec_common_device::i_ret, /* 0xc3 */ + &nec_common_device::i_les_dw, /* 0xc4 */ + &nec_common_device::i_lds_dw, /* 0xc5 */ + &nec_common_device::i_mov_bd8, /* 0xc6 */ + &nec_common_device::i_mov_wd16, /* 0xc7 */ + &nec_common_device::i_enter, /* 0xc8 */ + &nec_common_device::i_leave, /* 0xc9 */ + &nec_common_device::i_retf_d16, /* 0xca */ + &nec_common_device::i_retf, /* 0xcb */ + &nec_common_device::i_int3, /* 0xcc */ + &nec_common_device::i_int, /* 0xcd */ + &nec_common_device::i_into, /* 0xce */ + &nec_common_device::i_iret, /* 0xcf */ + &nec_common_device::i_rotshft_b, /* 0xd0 */ + &nec_common_device::i_rotshft_w, /* 0xd1 */ + &nec_common_device::i_rotshft_bcl, /* 0xd2 */ + &nec_common_device::i_rotshft_wcl, /* 0xd3 */ + &nec_common_device::i_aam, /* 0xd4 */ + &nec_common_device::i_aad, /* 0xd5 */ + &nec_common_device::i_setalc, /* 0xd6 */ + &nec_common_device::i_trans, /* 0xd7 */ + &nec_common_device::i_fpo, /* 0xd8 */ + &nec_common_device::i_fpo, /* 0xd9 */ + &nec_common_device::i_fpo, /* 0xda */ + &nec_common_device::i_fpo, /* 0xdb */ + &nec_common_device::i_fpo, /* 0xdc */ + &nec_common_device::i_fpo, /* 0xdd */ + &nec_common_device::i_fpo, /* 0xde */ + &nec_common_device::i_fpo, /* 0xdf */ + &nec_common_device::i_loopne, /* 0xe0 */ + &nec_common_device::i_loope, /* 0xe1 */ + &nec_common_device::i_loop, /* 0xe2 */ + &nec_common_device::i_jcxz, /* 0xe3 */ + &nec_common_device::i_inal, /* 0xe4 */ + &nec_common_device::i_inax, /* 0xe5 */ + &nec_common_device::i_outal, /* 0xe6 */ + &nec_common_device::i_outax, /* 0xe7 */ + &nec_common_device::i_call_d16, /* 0xe8 */ + &nec_common_device::i_jmp_d16, /* 0xe9 */ + &nec_common_device::i_jmp_far, /* 0xea */ + &nec_common_device::i_jmp_d8, /* 0xeb */ + &nec_common_device::i_inaldx, /* 0xec */ + &nec_common_device::i_inaxdx, /* 0xed */ + &nec_common_device::i_outdxal, /* 0xee */ + &nec_common_device::i_outdxax, /* 0xef */ + &nec_common_device::i_lock, /* 0xf0 */ + &nec_common_device::i_invalid, /* 0xf1 */ + &nec_common_device::i_repne, /* 0xf2 */ + &nec_common_device::i_repe, /* 0xf3 */ + &nec_common_device::i_hlt, /* 0xf4 */ + &nec_common_device::i_cmc, /* 0xf5 */ + &nec_common_device::i_f6pre, /* 0xf6 */ + &nec_common_device::i_f7pre, /* 0xf7 */ + &nec_common_device::i_clc, /* 0xf8 */ + &nec_common_device::i_stc, /* 0xf9 */ + &nec_common_device::i_di, /* 0xfa */ + &nec_common_device::i_ei, /* 0xfb */ + &nec_common_device::i_cld, /* 0xfc */ + &nec_common_device::i_std, /* 0xfd */ + &nec_common_device::i_fepre, /* 0xfe */ + &nec_common_device::i_ffpre /* 0xff */ +}; diff --git a/src/devices/cpu/nec/necinstr.inc b/src/devices/cpu/nec/necinstr.inc new file mode 100644 index 00000000000..1630bf5c82f --- /dev/null +++ b/src/devices/cpu/nec/necinstr.inc @@ -0,0 +1,673 @@ +// license:BSD-3-Clause +// copyright-holders:Bryan McPhail +#define OP(num,func_name) void nec_common_device::func_name() + +OP( 0x00, i_add_br8 ) { DEF_br8; ADDB; PutbackRMByte(ModRM,dst); CLKM(2,2,2,16,16,7); } +OP( 0x01, i_add_wr16 ) { DEF_wr16; ADDW; PutbackRMWord(ModRM,dst); CLKR(24,24,11,24,16,7,2,m_EA);} +OP( 0x02, i_add_r8b ) { DEF_r8b; ADDB; RegByte(ModRM)=dst; CLKM(2,2,2,11,11,6); } +OP( 0x03, i_add_r16w ) { DEF_r16w; ADDW; RegWord(ModRM)=dst; CLKR(15,15,8,15,11,6,2,m_EA); } +OP( 0x04, i_add_ald8 ) { DEF_ald8; ADDB; Breg(AL)=dst; CLKS(4,4,2); } +OP( 0x05, i_add_axd16) { DEF_axd16; ADDW; Wreg(AW)=dst; CLKS(4,4,2); } +OP( 0x06, i_push_es ) { PUSH(Sreg(DS1)); CLKS(12,8,3); } +OP( 0x07, i_pop_es ) { POP(Sreg(DS1)); CLKS(12,8,5); } + +OP( 0x08, i_or_br8 ) { DEF_br8; ORB; PutbackRMByte(ModRM,dst); CLKM(2,2,2,16,16,7); } +OP( 0x09, i_or_wr16 ) { DEF_wr16; ORW; PutbackRMWord(ModRM,dst); CLKR(24,24,11,24,16,7,2,m_EA);} +OP( 0x0a, i_or_r8b ) { DEF_r8b; ORB; RegByte(ModRM)=dst; CLKM(2,2,2,11,11,6); } +OP( 0x0b, i_or_r16w ) { DEF_r16w; ORW; RegWord(ModRM)=dst; CLKR(15,15,8,15,11,6,2,m_EA); } +OP( 0x0c, i_or_ald8 ) { DEF_ald8; ORB; Breg(AL)=dst; CLKS(4,4,2); } +OP( 0x0d, i_or_axd16 ) { DEF_axd16; ORW; Wreg(AW)=dst; CLKS(4,4,2); } +OP( 0x0e, i_push_cs ) { PUSH(Sreg(PS)); CLKS(12,8,3); } +OP( 0x0f, i_pre_nec ) { UINT32 ModRM, tmp, tmp2; + switch (FETCH()) { + case 0x10 : BITOP_BYTE; CLKS(3,3,4); tmp2 = Breg(CL) & 0x7; m_ZeroVal = (tmp & (1<>8)&0xf); tmp &= 0xff; PutbackRMByte(ModRM,tmp); CLKM(13,13,9,28,28,15); break; + case 0x2a : ModRM = FETCH(); tmp = GetRMByte(ModRM); tmp2 = (Breg(AL) & 0xf)<<4; Breg(AL) = (Breg(AL) & 0xf0) | (tmp&0xf); tmp = tmp2 | (tmp>>4); PutbackRMByte(ModRM,tmp); CLKM(17,17,13,32,32,19); break; + case 0x31 : ModRM = FETCH(); ModRM=0; logerror("%06x: Unimplemented bitfield INS\n",PC()); break; + case 0x33 : ModRM = FETCH(); ModRM=0; logerror("%06x: Unimplemented bitfield EXT\n",PC()); break; + case 0xe0 : ModRM = FETCH(); ModRM=0; logerror("%06x: V33 unimplemented BRKXA (break to expansion address)\n",PC()); break; + case 0xf0 : ModRM = FETCH(); ModRM=0; logerror("%06x: V33 unimplemented RETXA (return from expansion address)\n",PC()); break; + case 0xff : ModRM = FETCH(); ModRM=0; logerror("%06x: unimplemented BRKEM (break to 8080 emulation mode)\n",PC()); break; + default: logerror("%06x: Unknown V20 instruction\n",PC()); break; + } +} + +OP( 0x10, i_adc_br8 ) { DEF_br8; src+=CF; ADDB; PutbackRMByte(ModRM,dst); CLKM(2,2,2,16,16,7); } +OP( 0x11, i_adc_wr16 ) { DEF_wr16; src+=CF; ADDW; PutbackRMWord(ModRM,dst); CLKR(24,24,11,24,16,7,2,m_EA);} +OP( 0x12, i_adc_r8b ) { DEF_r8b; src+=CF; ADDB; RegByte(ModRM)=dst; CLKM(2,2,2,11,11,6); } +OP( 0x13, i_adc_r16w ) { DEF_r16w; src+=CF; ADDW; RegWord(ModRM)=dst; CLKR(15,15,8,15,11,6,2,m_EA); } +OP( 0x14, i_adc_ald8 ) { DEF_ald8; src+=CF; ADDB; Breg(AL)=dst; CLKS(4,4,2); } +OP( 0x15, i_adc_axd16) { DEF_axd16; src+=CF; ADDW; Wreg(AW)=dst; CLKS(4,4,2); } +OP( 0x16, i_push_ss ) { PUSH(Sreg(SS)); CLKS(12,8,3); } +OP( 0x17, i_pop_ss ) { POP(Sreg(SS)); CLKS(12,8,5); m_no_interrupt=1; } + +OP( 0x18, i_sbb_br8 ) { DEF_br8; src+=CF; SUBB; PutbackRMByte(ModRM,dst); CLKM(2,2,2,16,16,7); } +OP( 0x19, i_sbb_wr16 ) { DEF_wr16; src+=CF; SUBW; PutbackRMWord(ModRM,dst); CLKR(24,24,11,24,16,7,2,m_EA);} +OP( 0x1a, i_sbb_r8b ) { DEF_r8b; src+=CF; SUBB; RegByte(ModRM)=dst; CLKM(2,2,2,11,11,6); } +OP( 0x1b, i_sbb_r16w ) { DEF_r16w; src+=CF; SUBW; RegWord(ModRM)=dst; CLKR(15,15,8,15,11,6,2,m_EA); } +OP( 0x1c, i_sbb_ald8 ) { DEF_ald8; src+=CF; SUBB; Breg(AL)=dst; CLKS(4,4,2); } +OP( 0x1d, i_sbb_axd16) { DEF_axd16; src+=CF; SUBW; Wreg(AW)=dst; CLKS(4,4,2); } +OP( 0x1e, i_push_ds ) { PUSH(Sreg(DS0)); CLKS(12,8,3); } +OP( 0x1f, i_pop_ds ) { POP(Sreg(DS0)); CLKS(12,8,5); } + +OP( 0x20, i_and_br8 ) { DEF_br8; ANDB; PutbackRMByte(ModRM,dst); CLKM(2,2,2,16,16,7); } +OP( 0x21, i_and_wr16 ) { DEF_wr16; ANDW; PutbackRMWord(ModRM,dst); CLKR(24,24,11,24,16,7,2,m_EA);} +OP( 0x22, i_and_r8b ) { DEF_r8b; ANDB; RegByte(ModRM)=dst; CLKM(2,2,2,11,11,6); } +OP( 0x23, i_and_r16w ) { DEF_r16w; ANDW; RegWord(ModRM)=dst; CLKR(15,15,8,15,11,6,2,m_EA); } +OP( 0x24, i_and_ald8 ) { DEF_ald8; ANDB; Breg(AL)=dst; CLKS(4,4,2); } +OP( 0x25, i_and_axd16) { DEF_axd16; ANDW; Wreg(AW)=dst; CLKS(4,4,2); } +OP( 0x26, i_es ) { m_seg_prefix=TRUE; m_prefix_base=Sreg(DS1)<<4; CLK(2); (this->*s_nec_instruction[fetchop()])(); m_seg_prefix=FALSE; } +OP( 0x27, i_daa ) { ADJ4(6,0x60); CLKS(3,3,2); } + +OP( 0x28, i_sub_br8 ) { DEF_br8; SUBB; PutbackRMByte(ModRM,dst); CLKM(2,2,2,16,16,7); } +OP( 0x29, i_sub_wr16 ) { DEF_wr16; SUBW; PutbackRMWord(ModRM,dst); CLKR(24,24,11,24,16,7,2,m_EA);} +OP( 0x2a, i_sub_r8b ) { DEF_r8b; SUBB; RegByte(ModRM)=dst; CLKM(2,2,2,11,11,6); } +OP( 0x2b, i_sub_r16w ) { DEF_r16w; SUBW; RegWord(ModRM)=dst; CLKR(15,15,8,15,11,6,2,m_EA); } +OP( 0x2c, i_sub_ald8 ) { DEF_ald8; SUBB; Breg(AL)=dst; CLKS(4,4,2); } +OP( 0x2d, i_sub_axd16) { DEF_axd16; SUBW; Wreg(AW)=dst; CLKS(4,4,2); } +OP( 0x2e, i_cs ) { m_seg_prefix=TRUE; m_prefix_base=Sreg(PS)<<4; CLK(2); (this->*s_nec_instruction[fetchop()])(); m_seg_prefix=FALSE; } +OP( 0x2f, i_das ) { ADJ4(-6,-0x60); CLKS(3,3,2); } + +OP( 0x30, i_xor_br8 ) { DEF_br8; XORB; PutbackRMByte(ModRM,dst); CLKM(2,2,2,16,16,7); } +OP( 0x31, i_xor_wr16 ) { DEF_wr16; XORW; PutbackRMWord(ModRM,dst); CLKR(24,24,11,24,16,7,2,m_EA);} +OP( 0x32, i_xor_r8b ) { DEF_r8b; XORB; RegByte(ModRM)=dst; CLKM(2,2,2,11,11,6); } +OP( 0x33, i_xor_r16w ) { DEF_r16w; XORW; RegWord(ModRM)=dst; CLKR(15,15,8,15,11,6,2,m_EA); } +OP( 0x34, i_xor_ald8 ) { DEF_ald8; XORB; Breg(AL)=dst; CLKS(4,4,2); } +OP( 0x35, i_xor_axd16) { DEF_axd16; XORW; Wreg(AW)=dst; CLKS(4,4,2); } +OP( 0x36, i_ss ) { m_seg_prefix=TRUE; m_prefix_base=Sreg(SS)<<4; CLK(2); (this->*s_nec_instruction[fetchop()])(); m_seg_prefix=FALSE; } +OP( 0x37, i_aaa ) { ADJB(6, (Breg(AL) > 0xf9) ? 2 : 1); CLKS(7,7,4); } + +OP( 0x38, i_cmp_br8 ) { DEF_br8; SUBB; CLKM(2,2,2,11,11,6); } +OP( 0x39, i_cmp_wr16 ) { DEF_wr16; SUBW; CLKR(15,15,8,15,11,6,2,m_EA);} +OP( 0x3a, i_cmp_r8b ) { DEF_r8b; SUBB; CLKM(2,2,2,11,11,6); } +OP( 0x3b, i_cmp_r16w ) { DEF_r16w; SUBW; CLKR(15,15,8,15,11,6,2,m_EA); } +OP( 0x3c, i_cmp_ald8 ) { DEF_ald8; SUBB; CLKS(4,4,2); } +OP( 0x3d, i_cmp_axd16) { DEF_axd16; SUBW; CLKS(4,4,2); } +OP( 0x3e, i_ds ) { m_seg_prefix=TRUE; m_prefix_base=Sreg(DS0)<<4; CLK(2); (this->*s_nec_instruction[fetchop()])(); m_seg_prefix=FALSE; } +OP( 0x3f, i_aas ) { ADJB(-6, (Breg(AL) < 6) ? -2 : -1); CLKS(7,7,4); } + +OP( 0x40, i_inc_ax ) { IncWordReg(AW); CLK(2); } +OP( 0x41, i_inc_cx ) { IncWordReg(CW); CLK(2); } +OP( 0x42, i_inc_dx ) { IncWordReg(DW); CLK(2); } +OP( 0x43, i_inc_bx ) { IncWordReg(BW); CLK(2); } +OP( 0x44, i_inc_sp ) { IncWordReg(SP); CLK(2); } +OP( 0x45, i_inc_bp ) { IncWordReg(BP); CLK(2); } +OP( 0x46, i_inc_si ) { IncWordReg(IX); CLK(2); } +OP( 0x47, i_inc_di ) { IncWordReg(IY); CLK(2); } + +OP( 0x48, i_dec_ax ) { DecWordReg(AW); CLK(2); } +OP( 0x49, i_dec_cx ) { DecWordReg(CW); CLK(2); } +OP( 0x4a, i_dec_dx ) { DecWordReg(DW); CLK(2); } +OP( 0x4b, i_dec_bx ) { DecWordReg(BW); CLK(2); } +OP( 0x4c, i_dec_sp ) { DecWordReg(SP); CLK(2); } +OP( 0x4d, i_dec_bp ) { DecWordReg(BP); CLK(2); } +OP( 0x4e, i_dec_si ) { DecWordReg(IX); CLK(2); } +OP( 0x4f, i_dec_di ) { DecWordReg(IY); CLK(2); } + +OP( 0x50, i_push_ax ) { PUSH(Wreg(AW)); CLKS(12,8,3); } +OP( 0x51, i_push_cx ) { PUSH(Wreg(CW)); CLKS(12,8,3); } +OP( 0x52, i_push_dx ) { PUSH(Wreg(DW)); CLKS(12,8,3); } +OP( 0x53, i_push_bx ) { PUSH(Wreg(BW)); CLKS(12,8,3); } +OP( 0x54, i_push_sp ) { PUSH(Wreg(SP)); CLKS(12,8,3); } +OP( 0x55, i_push_bp ) { PUSH(Wreg(BP)); CLKS(12,8,3); } +OP( 0x56, i_push_si ) { PUSH(Wreg(IX)); CLKS(12,8,3); } +OP( 0x57, i_push_di ) { PUSH(Wreg(IY)); CLKS(12,8,3); } + +OP( 0x58, i_pop_ax ) { POP(Wreg(AW)); CLKS(12,8,5); } +OP( 0x59, i_pop_cx ) { POP(Wreg(CW)); CLKS(12,8,5); } +OP( 0x5a, i_pop_dx ) { POP(Wreg(DW)); CLKS(12,8,5); } +OP( 0x5b, i_pop_bx ) { POP(Wreg(BW)); CLKS(12,8,5); } +OP( 0x5c, i_pop_sp ) { POP(Wreg(SP)); CLKS(12,8,5); } +OP( 0x5d, i_pop_bp ) { POP(Wreg(BP)); CLKS(12,8,5); } +OP( 0x5e, i_pop_si ) { POP(Wreg(IX)); CLKS(12,8,5); } +OP( 0x5f, i_pop_di ) { POP(Wreg(IY)); CLKS(12,8,5); } + +OP( 0x60, i_pusha ) { + unsigned tmp=Wreg(SP); + PUSH(Wreg(AW)); + PUSH(Wreg(CW)); + PUSH(Wreg(DW)); + PUSH(Wreg(BW)); + PUSH(tmp); + PUSH(Wreg(BP)); + PUSH(Wreg(IX)); + PUSH(Wreg(IY)); + CLKS(67,35,20); +} +static unsigned nec_popa_tmp; +OP( 0x61, i_popa ) { + POP(Wreg(IY)); + POP(Wreg(IX)); + POP(Wreg(BP)); + POP(nec_popa_tmp); + POP(Wreg(BW)); + POP(Wreg(DW)); + POP(Wreg(CW)); + POP(Wreg(AW)); + CLKS(75,43,22); +} +OP( 0x62, i_chkind ) { + UINT32 low,high,tmp; + GetModRM; + low = GetRMWord(ModRM); + high= GetnextRMWord; + tmp= RegWord(ModRM); + if (tmphigh) { + nec_interrupt(NEC_CHKIND_VECTOR, BRK); + } + m_icount-=20; + logerror("%06x: bound %04x high %04x low %04x tmp\n",PC(),high,low,tmp); +} +OP( 0x64, i_repnc ) { UINT32 next = fetchop(); UINT16 c = Wreg(CW); + switch(next) { /* Segments */ + case 0x26: m_seg_prefix=TRUE; m_prefix_base=Sreg(DS1)<<4; next = fetchop(); CLK(2); break; + case 0x2e: m_seg_prefix=TRUE; m_prefix_base=Sreg(PS)<<4; next = fetchop(); CLK(2); break; + case 0x36: m_seg_prefix=TRUE; m_prefix_base=Sreg(SS)<<4; next = fetchop(); CLK(2); break; + case 0x3e: m_seg_prefix=TRUE; m_prefix_base=Sreg(DS0)<<4; next = fetchop(); CLK(2); break; + } + + switch(next) { + case 0x6c: CLK(2); if (c) do { i_insb(); c--; } while (c>0 && !CF); Wreg(CW)=c; break; + case 0x6d: CLK(2); if (c) do { i_insw(); c--; } while (c>0 && !CF); Wreg(CW)=c; break; + case 0x6e: CLK(2); if (c) do { i_outsb(); c--; } while (c>0 && !CF); Wreg(CW)=c; break; + case 0x6f: CLK(2); if (c) do { i_outsw(); c--; } while (c>0 && !CF); Wreg(CW)=c; break; + case 0xa4: CLK(2); if (c) do { i_movsb(); c--; } while (c>0 && !CF); Wreg(CW)=c; break; + case 0xa5: CLK(2); if (c) do { i_movsw(); c--; } while (c>0 && !CF); Wreg(CW)=c; break; + case 0xa6: CLK(2); if (c) do { i_cmpsb(); c--; } while (c>0 && !CF); Wreg(CW)=c; break; + case 0xa7: CLK(2); if (c) do { i_cmpsw(); c--; } while (c>0 && !CF); Wreg(CW)=c; break; + case 0xaa: CLK(2); if (c) do { i_stosb(); c--; } while (c>0 && !CF); Wreg(CW)=c; break; + case 0xab: CLK(2); if (c) do { i_stosw(); c--; } while (c>0 && !CF); Wreg(CW)=c; break; + case 0xac: CLK(2); if (c) do { i_lodsb(); c--; } while (c>0 && !CF); Wreg(CW)=c; break; + case 0xad: CLK(2); if (c) do { i_lodsw(); c--; } while (c>0 && !CF); Wreg(CW)=c; break; + case 0xae: CLK(2); if (c) do { i_scasb(); c--; } while (c>0 && !CF); Wreg(CW)=c; break; + case 0xaf: CLK(2); if (c) do { i_scasw(); c--; } while (c>0 && !CF); Wreg(CW)=c; break; + default: logerror("%06x: REPNC invalid\n",PC()); (this->*s_nec_instruction[next])(); + } + m_seg_prefix=FALSE; +} + +OP( 0x65, i_repc ) { UINT32 next = fetchop(); UINT16 c = Wreg(CW); + switch(next) { /* Segments */ + case 0x26: m_seg_prefix=TRUE; m_prefix_base=Sreg(DS1)<<4; next = fetchop(); CLK(2); break; + case 0x2e: m_seg_prefix=TRUE; m_prefix_base=Sreg(PS)<<4; next = fetchop(); CLK(2); break; + case 0x36: m_seg_prefix=TRUE; m_prefix_base=Sreg(SS)<<4; next = fetchop(); CLK(2); break; + case 0x3e: m_seg_prefix=TRUE; m_prefix_base=Sreg(DS0)<<4; next = fetchop(); CLK(2); break; + } + + switch(next) { + case 0x6c: CLK(2); if (c) do { i_insb(); c--; } while (c>0 && CF); Wreg(CW)=c; break; + case 0x6d: CLK(2); if (c) do { i_insw(); c--; } while (c>0 && CF); Wreg(CW)=c; break; + case 0x6e: CLK(2); if (c) do { i_outsb(); c--; } while (c>0 && CF); Wreg(CW)=c; break; + case 0x6f: CLK(2); if (c) do { i_outsw(); c--; } while (c>0 && CF); Wreg(CW)=c; break; + case 0xa4: CLK(2); if (c) do { i_movsb(); c--; } while (c>0 && CF); Wreg(CW)=c; break; + case 0xa5: CLK(2); if (c) do { i_movsw(); c--; } while (c>0 && CF); Wreg(CW)=c; break; + case 0xa6: CLK(2); if (c) do { i_cmpsb(); c--; } while (c>0 && CF); Wreg(CW)=c; break; + case 0xa7: CLK(2); if (c) do { i_cmpsw(); c--; } while (c>0 && CF); Wreg(CW)=c; break; + case 0xaa: CLK(2); if (c) do { i_stosb(); c--; } while (c>0 && CF); Wreg(CW)=c; break; + case 0xab: CLK(2); if (c) do { i_stosw(); c--; } while (c>0 && CF); Wreg(CW)=c; break; + case 0xac: CLK(2); if (c) do { i_lodsb(); c--; } while (c>0 && CF); Wreg(CW)=c; break; + case 0xad: CLK(2); if (c) do { i_lodsw(); c--; } while (c>0 && CF); Wreg(CW)=c; break; + case 0xae: CLK(2); if (c) do { i_scasb(); c--; } while (c>0 && CF); Wreg(CW)=c; break; + case 0xaf: CLK(2); if (c) do { i_scasw(); c--; } while (c>0 && CF); Wreg(CW)=c; break; + default: logerror("%06x: REPC invalid\n",PC()); (this->*s_nec_instruction[next])(); + } + m_seg_prefix=FALSE; +} + +OP( 0x68, i_push_d16 ) { UINT32 tmp; tmp = FETCHWORD(); PUSH(tmp); CLKW(12,12,5,12,8,5,Wreg(SP)); } +OP( 0x69, i_imul_d16 ) { UINT32 tmp; DEF_r16w; tmp = FETCHWORD(); dst = (INT32)((INT16)src)*(INT32)((INT16)tmp); m_CarryVal = m_OverVal = (((INT32)dst) >> 15 != 0) && (((INT32)dst) >> 15 != -1); RegWord(ModRM)=(WORD)dst; m_icount-=(ModRM >=0xc0 )?38:47;} +OP( 0x6a, i_push_d8 ) { UINT32 tmp = (WORD)((INT16)((INT8)FETCH())); PUSH(tmp); CLKW(11,11,5,11,7,3,Wreg(SP)); } +OP( 0x6b, i_imul_d8 ) { UINT32 src2; DEF_r16w; src2= (WORD)((INT16)((INT8)FETCH())); dst = (INT32)((INT16)src)*(INT32)((INT16)src2); m_CarryVal = m_OverVal = (((INT32)dst) >> 15 != 0) && (((INT32)dst) >> 15 != -1); RegWord(ModRM)=(WORD)dst; m_icount-=(ModRM >=0xc0 )?31:39; } +OP( 0x6c, i_insb ) { PutMemB(DS1,Wreg(IY),read_port_byte(Wreg(DW))); Wreg(IY)+= -2 * m_DF + 1; CLK(8); } +OP( 0x6d, i_insw ) { PutMemW(DS1,Wreg(IY),read_port_word(Wreg(DW))); Wreg(IY)+= -4 * m_DF + 2; CLKS(18,10,8); } +OP( 0x6e, i_outsb ) { write_port_byte(Wreg(DW),GetMemB(DS0,Wreg(IX))); Wreg(IX)+= -2 * m_DF + 1; CLK(8); } +OP( 0x6f, i_outsw ) { write_port_word(Wreg(DW),GetMemW(DS0,Wreg(IX))); Wreg(IX)+= -4 * m_DF + 2; CLKS(18,10,8); } + +OP( 0x70, i_jo ) { JMP( OF); CLKS(4,4,3); } +OP( 0x71, i_jno ) { JMP(!OF); CLKS(4,4,3); } +OP( 0x72, i_jc ) { JMP( CF); CLKS(4,4,3); } +OP( 0x73, i_jnc ) { JMP(!CF); CLKS(4,4,3); } +OP( 0x74, i_jz ) { JMP( ZF); CLKS(4,4,3); } +OP( 0x75, i_jnz ) { JMP(!ZF); CLKS(4,4,3); } +OP( 0x76, i_jce ) { JMP(CF || ZF); CLKS(4,4,3); } +OP( 0x77, i_jnce ) { JMP(!(CF || ZF)); CLKS(4,4,3); } +OP( 0x78, i_js ) { JMP( SF); CLKS(4,4,3); } +OP( 0x79, i_jns ) { JMP(!SF); CLKS(4,4,3); } +OP( 0x7a, i_jp ) { JMP( PF); CLKS(4,4,3); } +OP( 0x7b, i_jnp ) { JMP(!PF); CLKS(4,4,3); } +OP( 0x7c, i_jl ) { JMP((SF!=OF)&&(!ZF)); CLKS(4,4,3); } +OP( 0x7d, i_jnl ) { JMP((ZF)||(SF==OF)); CLKS(4,4,3); } +OP( 0x7e, i_jle ) { JMP((ZF)||(SF!=OF)); CLKS(4,4,3); } +OP( 0x7f, i_jnle ) { JMP((SF==OF)&&(!ZF)); CLKS(4,4,3); } + +OP( 0x80, i_80pre ) { UINT32 dst, src; GetModRM; dst = GetRMByte(ModRM); src = FETCH(); + if (ModRM >=0xc0 ) CLKS(4,4,2) else if ((ModRM & 0x38)==0x38) CLKS(13,13,6) else CLKS(18,18,7) + switch (ModRM & 0x38) { + case 0x00: ADDB; PutbackRMByte(ModRM,dst); break; + case 0x08: ORB; PutbackRMByte(ModRM,dst); break; + case 0x10: src+=CF; ADDB; PutbackRMByte(ModRM,dst); break; + case 0x18: src+=CF; SUBB; PutbackRMByte(ModRM,dst); break; + case 0x20: ANDB; PutbackRMByte(ModRM,dst); break; + case 0x28: SUBB; PutbackRMByte(ModRM,dst); break; + case 0x30: XORB; PutbackRMByte(ModRM,dst); break; + case 0x38: SUBB; break; /* CMP */ + } +} + +OP( 0x81, i_81pre ) { UINT32 dst, src; GetModRM; dst = GetRMWord(ModRM); src = FETCH(); src+= (FETCH() << 8); + if (ModRM >=0xc0 ) CLKS(4,4,2) else if ((ModRM & 0x38)==0x38) CLKW(17,17,8,17,13,6,m_EA) else CLKW(26,26,11,26,18,7,m_EA) + switch (ModRM & 0x38) { + case 0x00: ADDW; PutbackRMWord(ModRM,dst); break; + case 0x08: ORW; PutbackRMWord(ModRM,dst); break; + case 0x10: src+=CF; ADDW; PutbackRMWord(ModRM,dst); break; + case 0x18: src+=CF; SUBW; PutbackRMWord(ModRM,dst); break; + case 0x20: ANDW; PutbackRMWord(ModRM,dst); break; + case 0x28: SUBW; PutbackRMWord(ModRM,dst); break; + case 0x30: XORW; PutbackRMWord(ModRM,dst); break; + case 0x38: SUBW; break; /* CMP */ + } +} + +OP( 0x82, i_82pre ) { UINT32 dst, src; GetModRM; dst = GetRMByte(ModRM); src = (BYTE)((INT8)FETCH()); + if (ModRM >=0xc0 ) CLKS(4,4,2) else if ((ModRM & 0x38)==0x38) CLKS(13,13,6) else CLKS(18,18,7) + switch (ModRM & 0x38) { + case 0x00: ADDB; PutbackRMByte(ModRM,dst); break; + case 0x08: ORB; PutbackRMByte(ModRM,dst); break; + case 0x10: src+=CF; ADDB; PutbackRMByte(ModRM,dst); break; + case 0x18: src+=CF; SUBB; PutbackRMByte(ModRM,dst); break; + case 0x20: ANDB; PutbackRMByte(ModRM,dst); break; + case 0x28: SUBB; PutbackRMByte(ModRM,dst); break; + case 0x30: XORB; PutbackRMByte(ModRM,dst); break; + case 0x38: SUBB; break; /* CMP */ + } +} + +OP( 0x83, i_83pre ) { UINT32 dst, src; GetModRM; dst = GetRMWord(ModRM); src = (WORD)((INT16)((INT8)FETCH())); + if (ModRM >=0xc0 ) CLKS(4,4,2) else if ((ModRM & 0x38)==0x38) CLKW(17,17,8,17,13,6,m_EA) else CLKW(26,26,11,26,18,7,m_EA) + switch (ModRM & 0x38) { + case 0x00: ADDW; PutbackRMWord(ModRM,dst); break; + case 0x08: ORW; PutbackRMWord(ModRM,dst); break; + case 0x10: src+=CF; ADDW; PutbackRMWord(ModRM,dst); break; + case 0x18: src+=CF; SUBW; PutbackRMWord(ModRM,dst); break; + case 0x20: ANDW; PutbackRMWord(ModRM,dst); break; + case 0x28: SUBW; PutbackRMWord(ModRM,dst); break; + case 0x30: XORW; PutbackRMWord(ModRM,dst); break; + case 0x38: SUBW; break; /* CMP */ + } +} + +OP( 0x84, i_test_br8 ) { DEF_br8; ANDB; CLKM(2,2,2,10,10,6); } +OP( 0x85, i_test_wr16 ) { DEF_wr16; ANDW; CLKR(14,14,8,14,10,6,2,m_EA); } +OP( 0x86, i_xchg_br8 ) { DEF_br8; RegByte(ModRM)=dst; PutbackRMByte(ModRM,src); CLKM(3,3,3,16,18,8); } +OP( 0x87, i_xchg_wr16 ) { DEF_wr16; RegWord(ModRM)=dst; PutbackRMWord(ModRM,src); CLKR(24,24,12,24,16,8,3,m_EA); } + +OP( 0x88, i_mov_br8 ) { UINT8 src; GetModRM; src = RegByte(ModRM); PutRMByte(ModRM,src); CLKM(2,2,2,9,9,3); } +OP( 0x89, i_mov_wr16 ) { UINT16 src; GetModRM; src = RegWord(ModRM); PutRMWord(ModRM,src); CLKR(13,13,5,13,9,3,2,m_EA); } +OP( 0x8a, i_mov_r8b ) { UINT8 src; GetModRM; src = GetRMByte(ModRM); RegByte(ModRM)=src; CLKM(2,2,2,11,11,5); } +OP( 0x8b, i_mov_r16w ) { UINT16 src; GetModRM; src = GetRMWord(ModRM); RegWord(ModRM)=src; CLKR(15,15,7,15,11,5,2,m_EA); } +OP( 0x8c, i_mov_wsreg ) { GetModRM; + switch (ModRM & 0x38) { + case 0x00: PutRMWord(ModRM,Sreg(DS1)); CLKR(14,14,5,14,10,3,2,m_EA); break; + case 0x08: PutRMWord(ModRM,Sreg(PS)); CLKR(14,14,5,14,10,3,2,m_EA); break; + case 0x10: PutRMWord(ModRM,Sreg(SS)); CLKR(14,14,5,14,10,3,2,m_EA); break; + case 0x18: PutRMWord(ModRM,Sreg(DS0)); CLKR(14,14,5,14,10,3,2,m_EA); break; + default: logerror("%06x: MOV Sreg - Invalid register\n",PC()); + } +} +OP( 0x8d, i_lea ) { UINT16 ModRM = FETCH(); (void)(this->*s_GetEA[ModRM])(); RegWord(ModRM)=m_EO; CLKS(4,4,2); } +OP( 0x8e, i_mov_sregw ) { UINT16 src; GetModRM; src = GetRMWord(ModRM); CLKR(15,15,7,15,11,5,2,m_EA); + switch (ModRM & 0x38) { + case 0x00: Sreg(DS1) = src; break; /* mov es,ew */ + case 0x08: Sreg(PS) = src; break; /* mov cs,ew */ + case 0x10: Sreg(SS) = src; break; /* mov ss,ew */ + case 0x18: Sreg(DS0) = src; break; /* mov ds,ew */ + default: logerror("%06x: MOV Sreg - Invalid register\n",PC()); + } + m_no_interrupt=1; +} +OP( 0x8f, i_popw ) { UINT16 tmp; GetModRM; POP(tmp); PutRMWord(ModRM,tmp); m_icount-=21; } +OP( 0x90, i_nop ) { CLK(3); /* { if (m_MF == 0) printf("90 -> %06x: \n",PC()); } */ } +OP( 0x91, i_xchg_axcx ) { XchgAWReg(CW); CLK(3); } +OP( 0x92, i_xchg_axdx ) { XchgAWReg(DW); CLK(3); } +OP( 0x93, i_xchg_axbx ) { XchgAWReg(BW); CLK(3); } +OP( 0x94, i_xchg_axsp ) { XchgAWReg(SP); CLK(3); } +OP( 0x95, i_xchg_axbp ) { XchgAWReg(BP); CLK(3); } +OP( 0x96, i_xchg_axsi ) { XchgAWReg(IX); CLK(3); } +OP( 0x97, i_xchg_axdi ) { XchgAWReg(IY); CLK(3); } + +OP( 0x98, i_cbw ) { Breg(AH) = (Breg(AL) & 0x80) ? 0xff : 0; CLK(2); } +OP( 0x99, i_cwd ) { Wreg(DW) = (Breg(AH) & 0x80) ? 0xffff : 0; CLK(4); } +OP( 0x9a, i_call_far ) { UINT32 tmp, tmp2; tmp = FETCHWORD(); tmp2 = FETCHWORD(); PUSH(Sreg(PS)); PUSH(m_ip); m_ip = (WORD)tmp; Sreg(PS) = (WORD)tmp2; CHANGE_PC; CLKW(29,29,13,29,21,9,Wreg(SP)); } +OP( 0x9b, i_wait ) { if (!m_poll_state) m_ip--; CLK(5); } +OP( 0x9c, i_pushf ) { UINT16 tmp = CompressFlags(); PUSH( tmp ); CLKS(12,8,3); } +OP( 0x9d, i_popf ) { UINT32 tmp; POP(tmp); ExpandFlags(tmp); CLKS(12,8,5); if (m_TF) nec_trap(); } +OP( 0x9e, i_sahf ) { UINT32 tmp = (CompressFlags() & 0xff00) | (Breg(AH) & 0xd5); ExpandFlags(tmp); CLKS(3,3,2); } +OP( 0x9f, i_lahf ) { Breg(AH) = CompressFlags() & 0xff; CLKS(3,3,2); } + +OP( 0xa0, i_mov_aldisp ) { UINT32 addr; addr = FETCHWORD(); Breg(AL) = GetMemB(DS0, addr); CLKS(10,10,5); } +OP( 0xa1, i_mov_axdisp ) { UINT32 addr; addr = FETCHWORD(); Wreg(AW) = GetMemW(DS0, addr); CLKW(14,14,7,14,10,5,addr); } +OP( 0xa2, i_mov_dispal ) { UINT32 addr; addr = FETCHWORD(); PutMemB(DS0, addr, Breg(AL)); CLKS(9,9,3); } +OP( 0xa3, i_mov_dispax ) { UINT32 addr; addr = FETCHWORD(); PutMemW(DS0, addr, Wreg(AW)); CLKW(13,13,5,13,9,3,addr); } +OP( 0xa4, i_movsb ) { UINT32 tmp = GetMemB(DS0,Wreg(IX)); PutMemB(DS1,Wreg(IY), tmp); Wreg(IY) += -2 * m_DF + 1; Wreg(IX) += -2 * m_DF + 1; CLKS(8,8,6); } +OP( 0xa5, i_movsw ) { UINT32 tmp = GetMemW(DS0,Wreg(IX)); PutMemW(DS1,Wreg(IY), tmp); Wreg(IY) += -4 * m_DF + 2; Wreg(IX) += -4 * m_DF + 2; CLKS(16,16,10); } +OP( 0xa6, i_cmpsb ) { UINT32 src = GetMemB(DS1, Wreg(IY)); UINT32 dst = GetMemB(DS0, Wreg(IX)); SUBB; Wreg(IY) += -2 * m_DF + 1; Wreg(IX) += -2 * m_DF + 1; CLKS(14,14,14); } +OP( 0xa7, i_cmpsw ) { UINT32 src = GetMemW(DS1, Wreg(IY)); UINT32 dst = GetMemW(DS0, Wreg(IX)); SUBW; Wreg(IY) += -4 * m_DF + 2; Wreg(IX) += -4 * m_DF + 2; CLKS(14,14,14); } + +OP( 0xa8, i_test_ald8 ) { DEF_ald8; ANDB; CLKS(4,4,2); } +OP( 0xa9, i_test_axd16 ) { DEF_axd16; ANDW; CLKS(4,4,2); } +OP( 0xaa, i_stosb ) { PutMemB(DS1,Wreg(IY),Breg(AL)); Wreg(IY) += -2 * m_DF + 1; CLKS(4,4,3); } +OP( 0xab, i_stosw ) { PutMemW(DS1,Wreg(IY),Wreg(AW)); Wreg(IY) += -4 * m_DF + 2; CLKW(8,8,5,8,4,3,Wreg(IY)); } +OP( 0xac, i_lodsb ) { Breg(AL) = GetMemB(DS0,Wreg(IX)); Wreg(IX) += -2 * m_DF + 1; CLKS(4,4,3); } +OP( 0xad, i_lodsw ) { Wreg(AW) = GetMemW(DS0,Wreg(IX)); Wreg(IX) += -4 * m_DF + 2; CLKW(8,8,5,8,4,3,Wreg(IX)); } +OP( 0xae, i_scasb ) { UINT32 src = GetMemB(DS1, Wreg(IY)); UINT32 dst = Breg(AL); SUBB; Wreg(IY) += -2 * m_DF + 1; CLKS(4,4,3); } +OP( 0xaf, i_scasw ) { UINT32 src = GetMemW(DS1, Wreg(IY)); UINT32 dst = Wreg(AW); SUBW; Wreg(IY) += -4 * m_DF + 2; CLKW(8,8,5,8,4,3,Wreg(IY)); } + +OP( 0xb0, i_mov_ald8 ) { Breg(AL) = FETCH(); CLKS(4,4,2); } +OP( 0xb1, i_mov_cld8 ) { Breg(CL) = FETCH(); CLKS(4,4,2); } +OP( 0xb2, i_mov_dld8 ) { Breg(DL) = FETCH(); CLKS(4,4,2); } +OP( 0xb3, i_mov_bld8 ) { Breg(BL) = FETCH(); CLKS(4,4,2); } +OP( 0xb4, i_mov_ahd8 ) { Breg(AH) = FETCH(); CLKS(4,4,2); } +OP( 0xb5, i_mov_chd8 ) { Breg(CH) = FETCH(); CLKS(4,4,2); } +OP( 0xb6, i_mov_dhd8 ) { Breg(DH) = FETCH(); CLKS(4,4,2); } +OP( 0xb7, i_mov_bhd8 ) { Breg(BH) = FETCH(); CLKS(4,4,2); } + +OP( 0xb8, i_mov_axd16 ) { Breg(AL) = FETCH(); Breg(AH) = FETCH(); CLKS(4,4,2); } +OP( 0xb9, i_mov_cxd16 ) { Breg(CL) = FETCH(); Breg(CH) = FETCH(); CLKS(4,4,2); } +OP( 0xba, i_mov_dxd16 ) { Breg(DL) = FETCH(); Breg(DH) = FETCH(); CLKS(4,4,2); } +OP( 0xbb, i_mov_bxd16 ) { Breg(BL) = FETCH(); Breg(BH) = FETCH(); CLKS(4,4,2); } +OP( 0xbc, i_mov_spd16 ) { Wreg(SP) = FETCHWORD(); CLKS(4,4,2); } +OP( 0xbd, i_mov_bpd16 ) { Wreg(BP) = FETCHWORD(); CLKS(4,4,2); } +OP( 0xbe, i_mov_sid16 ) { Wreg(IX) = FETCHWORD(); CLKS(4,4,2); } +OP( 0xbf, i_mov_did16 ) { Wreg(IY) = FETCHWORD(); CLKS(4,4,2); } + +OP( 0xc0, i_rotshft_bd8 ) { + UINT32 src, dst; UINT8 c; + GetModRM; src = (unsigned)GetRMByte(ModRM); dst=src; + c=FETCH(); + CLKM(7,7,2,19,19,6); + if (c) switch (ModRM & 0x38) { + case 0x00: do { ROL_BYTE; c--; CLK(1); } while (c>0); PutbackRMByte(ModRM,(BYTE)dst); break; + case 0x08: do { ROR_BYTE; c--; CLK(1); } while (c>0); PutbackRMByte(ModRM,(BYTE)dst); break; + case 0x10: do { ROLC_BYTE; c--; CLK(1); } while (c>0); PutbackRMByte(ModRM,(BYTE)dst); break; + case 0x18: do { RORC_BYTE; c--; CLK(1); } while (c>0); PutbackRMByte(ModRM,(BYTE)dst); break; + case 0x20: SHL_BYTE(c); break; + case 0x28: SHR_BYTE(c); break; + case 0x30: logerror("%06x: Undefined opcode 0xc0 0x30 (SHLA)\n",PC()); break; + case 0x38: SHRA_BYTE(c); break; + } +} + +OP( 0xc1, i_rotshft_wd8 ) { + UINT32 src, dst; UINT8 c; + GetModRM; src = (unsigned)GetRMWord(ModRM); dst=src; + c=FETCH(); + CLKM(7,7,2,27,19,6); + if (c) switch (ModRM & 0x38) { + case 0x00: do { ROL_WORD; c--; CLK(1); } while (c>0); PutbackRMWord(ModRM,(WORD)dst); break; + case 0x08: do { ROR_WORD; c--; CLK(1); } while (c>0); PutbackRMWord(ModRM,(WORD)dst); break; + case 0x10: do { ROLC_WORD; c--; CLK(1); } while (c>0); PutbackRMWord(ModRM,(WORD)dst); break; + case 0x18: do { RORC_WORD; c--; CLK(1); } while (c>0); PutbackRMWord(ModRM,(WORD)dst); break; + case 0x20: SHL_WORD(c); break; + case 0x28: SHR_WORD(c); break; + case 0x30: logerror("%06x: Undefined opcode 0xc1 0x30 (SHLA)\n",PC()); break; + case 0x38: SHRA_WORD(c); break; + } +} + +OP( 0xc2, i_ret_d16 ) { UINT32 count = FETCH(); count += FETCH() << 8; POP(m_ip); Wreg(SP)+=count; CHANGE_PC; CLKS(24,24,10); } +OP( 0xc3, i_ret ) { POP(m_ip); CHANGE_PC; CLKS(19,19,10); } +OP( 0xc4, i_les_dw ) { GetModRM; WORD tmp = GetRMWord(ModRM); RegWord(ModRM)=tmp; Sreg(DS1) = GetnextRMWord; CLKW(26,26,14,26,18,10,m_EA); } +OP( 0xc5, i_lds_dw ) { GetModRM; WORD tmp = GetRMWord(ModRM); RegWord(ModRM)=tmp; Sreg(DS0) = GetnextRMWord; CLKW(26,26,14,26,18,10,m_EA); } +OP( 0xc6, i_mov_bd8 ) { GetModRM; PutImmRMByte(ModRM); m_icount-=(ModRM >=0xc0 )?4:11; } +OP( 0xc7, i_mov_wd16 ) { GetModRM; PutImmRMWord(ModRM); m_icount-=(ModRM >=0xc0 )?4:15; } + +OP( 0xc8, i_enter ) { + UINT32 nb = FETCH(); + UINT32 i,level; + + m_icount-=23; + nb += FETCH() << 8; + level = FETCH(); + PUSH(Wreg(BP)); + Wreg(BP)=Wreg(SP); + Wreg(SP) -= nb; + for (i=1;i0); PutbackRMByte(ModRM,(BYTE)dst); break; + case 0x08: do { ROR_BYTE; c--; CLK(1); } while (c>0); PutbackRMByte(ModRM,(BYTE)dst); break; + case 0x10: do { ROLC_BYTE; c--; CLK(1); } while (c>0); PutbackRMByte(ModRM,(BYTE)dst); break; + case 0x18: do { RORC_BYTE; c--; CLK(1); } while (c>0); PutbackRMByte(ModRM,(BYTE)dst); break; + case 0x20: SHL_BYTE(c); break; + case 0x28: SHR_BYTE(c); break; + case 0x30: logerror("%06x: Undefined opcode 0xd2 0x30 (SHLA)\n",PC()); break; + case 0x38: SHRA_BYTE(c); break; + } +} + +OP( 0xd3, i_rotshft_wcl ) { + UINT32 src, dst; UINT8 c; GetModRM; src = (UINT32)GetRMWord(ModRM); dst=src; + c=Breg(CL); + CLKM(7,7,2,27,19,6); + if (c) switch (ModRM & 0x38) { + case 0x00: do { ROL_WORD; c--; CLK(1); } while (c>0); PutbackRMWord(ModRM,(WORD)dst); break; + case 0x08: do { ROR_WORD; c--; CLK(1); } while (c>0); PutbackRMWord(ModRM,(WORD)dst); break; + case 0x10: do { ROLC_WORD; c--; CLK(1); } while (c>0); PutbackRMWord(ModRM,(WORD)dst); break; + case 0x18: do { RORC_WORD; c--; CLK(1); } while (c>0); PutbackRMWord(ModRM,(WORD)dst); break; + case 0x20: SHL_WORD(c); break; + case 0x28: SHR_WORD(c); break; + case 0x30: logerror("%06x: Undefined opcode 0xd3 0x30 (SHLA)\n",PC()); break; + case 0x38: SHRA_WORD(c); break; + } +} + +OP( 0xd4, i_aam ) { FETCH(); Breg(AH) = Breg(AL) / 10; Breg(AL) %= 10; SetSZPF_Word(Wreg(AW)); CLKS(15,15,12); } +OP( 0xd5, i_aad ) { FETCH(); Breg(AL) = Breg(AH) * 10 + Breg(AL); Breg(AH) = 0; SetSZPF_Byte(Breg(AL)); CLKS(7,7,8); } +OP( 0xd6, i_setalc ) { Breg(AL) = (CF)?0xff:0x00; m_icount-=3; logerror("%06x: Undefined opcode (SETALC)\n",PC()); } +OP( 0xd7, i_trans ) { UINT32 dest = (Wreg(BW)+Breg(AL))&0xffff; Breg(AL) = GetMemB(DS0, dest); CLKS(9,9,5); } +OP( 0xd8, i_fpo ) { GetModRM; GetRMByte(ModRM); m_icount-=2; logerror("%06x: Unimplemented floating point control %04x\n",PC(),ModRM); } + +OP( 0xe0, i_loopne ) { INT8 disp = (INT8)FETCH(); Wreg(CW)--; if (!ZF && Wreg(CW)) { m_ip = (WORD)(m_ip+disp); /*CHANGE_PC;*/ CLKS(14,14,6); } else CLKS(5,5,3); } +OP( 0xe1, i_loope ) { INT8 disp = (INT8)FETCH(); Wreg(CW)--; if ( ZF && Wreg(CW)) { m_ip = (WORD)(m_ip+disp); /*CHANGE_PC;*/ CLKS(14,14,6); } else CLKS(5,5,3); } +OP( 0xe2, i_loop ) { INT8 disp = (INT8)FETCH(); Wreg(CW)--; if (Wreg(CW)) { m_ip = (WORD)(m_ip+disp); /*CHANGE_PC;*/ CLKS(13,13,6); } else CLKS(5,5,3); } +OP( 0xe3, i_jcxz ) { INT8 disp = (INT8)FETCH(); if (Wreg(CW) == 0) { m_ip = (WORD)(m_ip+disp); /*CHANGE_PC;*/ CLKS(13,13,6); } else CLKS(5,5,3); } +OP( 0xe4, i_inal ) { UINT8 port = FETCH(); Breg(AL) = read_port_byte(port); CLKS(9,9,5); } +OP( 0xe5, i_inax ) { UINT8 port = FETCH(); Wreg(AW) = read_port_word(port); CLKW(13,13,7,13,9,5,port); } +OP( 0xe6, i_outal ) { UINT8 port = FETCH(); write_port_byte(port, Breg(AL)); CLKS(8,8,3); } +OP( 0xe7, i_outax ) { UINT8 port = FETCH(); write_port_word(port, Wreg(AW)); CLKW(12,12,5,12,8,3,port); } + +OP( 0xe8, i_call_d16 ) { UINT32 tmp; tmp = FETCHWORD(); PUSH(m_ip); m_ip = (WORD)(m_ip+(INT16)tmp); CHANGE_PC; m_icount-=24; } +OP( 0xe9, i_jmp_d16 ) { UINT32 tmp; tmp = FETCHWORD(); m_ip = (WORD)(m_ip+(INT16)tmp); CHANGE_PC; m_icount-=15; } +OP( 0xea, i_jmp_far ) { UINT32 tmp,tmp1; tmp = FETCHWORD(); tmp1 = FETCHWORD(); Sreg(PS) = (WORD)tmp1; m_ip = (WORD)tmp; CHANGE_PC; m_icount-=27; } +OP( 0xeb, i_jmp_d8 ) { int tmp = (int)((INT8)FETCH()); m_icount-=12; m_ip = (WORD)(m_ip+tmp); } +OP( 0xec, i_inaldx ) { Breg(AL) = read_port_byte(Wreg(DW)); CLKS(8,8,5);} +OP( 0xed, i_inaxdx ) { Wreg(AW) = read_port_word(Wreg(DW)); CLKW(12,12,7,12,8,5,Wreg(DW)); } +OP( 0xee, i_outdxal ) { write_port_byte(Wreg(DW), Breg(AL)); CLKS(8,8,3); } +OP( 0xef, i_outdxax ) { write_port_word(Wreg(DW), Wreg(AW)); CLKW(12,12,5,12,8,3,Wreg(DW)); } + +OP( 0xf0, i_lock ) { logerror("%06x: Warning - BUSLOCK\n",PC()); m_no_interrupt=1; CLK(2); } +OP( 0xf2, i_repne ) { UINT32 next = fetchop(); UINT16 c = Wreg(CW); + switch(next) { /* Segments */ + case 0x26: m_seg_prefix=TRUE; m_prefix_base=Sreg(DS1)<<4; next = fetchop(); CLK(2); break; + case 0x2e: m_seg_prefix=TRUE; m_prefix_base=Sreg(PS)<<4; next = fetchop(); CLK(2); break; + case 0x36: m_seg_prefix=TRUE; m_prefix_base=Sreg(SS)<<4; next = fetchop(); CLK(2); break; + case 0x3e: m_seg_prefix=TRUE; m_prefix_base=Sreg(DS0)<<4; next = fetchop(); CLK(2); break; + } + + switch(next) { + case 0x6c: CLK(2); if (c) do { i_insb(); c--; } while (c>0); Wreg(CW)=c; break; + case 0x6d: CLK(2); if (c) do { i_insw(); c--; } while (c>0); Wreg(CW)=c; break; + case 0x6e: CLK(2); if (c) do { i_outsb(); c--; } while (c>0); Wreg(CW)=c; break; + case 0x6f: CLK(2); if (c) do { i_outsw(); c--; } while (c>0); Wreg(CW)=c; break; + case 0xa4: CLK(2); if (c) do { i_movsb(); c--; } while (c>0); Wreg(CW)=c; break; + case 0xa5: CLK(2); if (c) do { i_movsw(); c--; } while (c>0); Wreg(CW)=c; break; + case 0xa6: CLK(2); if (c) do { i_cmpsb(); c--; } while (c>0 && ZF==0); Wreg(CW)=c; break; + case 0xa7: CLK(2); if (c) do { i_cmpsw(); c--; } while (c>0 && ZF==0); Wreg(CW)=c; break; + case 0xaa: CLK(2); if (c) do { i_stosb(); c--; } while (c>0); Wreg(CW)=c; break; + case 0xab: CLK(2); if (c) do { i_stosw(); c--; } while (c>0); Wreg(CW)=c; break; + case 0xac: CLK(2); if (c) do { i_lodsb(); c--; } while (c>0); Wreg(CW)=c; break; + case 0xad: CLK(2); if (c) do { i_lodsw(); c--; } while (c>0); Wreg(CW)=c; break; + case 0xae: CLK(2); if (c) do { i_scasb(); c--; } while (c>0 && ZF==0); Wreg(CW)=c; break; + case 0xaf: CLK(2); if (c) do { i_scasw(); c--; } while (c>0 && ZF==0); Wreg(CW)=c; break; + default: logerror("%06x: REPNE invalid\n",PC()); (this->*s_nec_instruction[next])(); + } + m_seg_prefix=FALSE; +} +OP( 0xf3, i_repe ) { UINT32 next = fetchop(); UINT16 c = Wreg(CW); + switch(next) { /* Segments */ + case 0x26: m_seg_prefix=TRUE; m_prefix_base=Sreg(DS1)<<4; next = fetchop(); CLK(2); break; + case 0x2e: m_seg_prefix=TRUE; m_prefix_base=Sreg(PS)<<4; next = fetchop(); CLK(2); break; + case 0x36: m_seg_prefix=TRUE; m_prefix_base=Sreg(SS)<<4; next = fetchop(); CLK(2); break; + case 0x3e: m_seg_prefix=TRUE; m_prefix_base=Sreg(DS0)<<4; next = fetchop(); CLK(2); break; + } + + switch(next) { + case 0x6c: CLK(2); if (c) do { i_insb(); c--; } while (c>0); Wreg(CW)=c; break; + case 0x6d: CLK(2); if (c) do { i_insw(); c--; } while (c>0); Wreg(CW)=c; break; + case 0x6e: CLK(2); if (c) do { i_outsb(); c--; } while (c>0); Wreg(CW)=c; break; + case 0x6f: CLK(2); if (c) do { i_outsw(); c--; } while (c>0); Wreg(CW)=c; break; + case 0xa4: CLK(2); if (c) do { i_movsb(); c--; } while (c>0); Wreg(CW)=c; break; + case 0xa5: CLK(2); if (c) do { i_movsw(); c--; } while (c>0); Wreg(CW)=c; break; + case 0xa6: CLK(2); if (c) do { i_cmpsb(); c--; } while (c>0 && ZF==1); Wreg(CW)=c; break; + case 0xa7: CLK(2); if (c) do { i_cmpsw(); c--; } while (c>0 && ZF==1); Wreg(CW)=c; break; + case 0xaa: CLK(2); if (c) do { i_stosb(); c--; } while (c>0); Wreg(CW)=c; break; + case 0xab: CLK(2); if (c) do { i_stosw(); c--; } while (c>0); Wreg(CW)=c; break; + case 0xac: CLK(2); if (c) do { i_lodsb(); c--; } while (c>0); Wreg(CW)=c; break; + case 0xad: CLK(2); if (c) do { i_lodsw(); c--; } while (c>0); Wreg(CW)=c; break; + case 0xae: CLK(2); if (c) do { i_scasb(); c--; } while (c>0 && ZF==1); Wreg(CW)=c; break; + case 0xaf: CLK(2); if (c) do { i_scasw(); c--; } while (c>0 && ZF==1); Wreg(CW)=c; break; + default: logerror("%06x: REPE invalid\n",PC()); (this->*s_nec_instruction[next])(); + } + m_seg_prefix=FALSE; +} +OP( 0xf4, i_hlt ) { logerror("%06x: HALT\n",PC()); m_halted=1; m_icount=0; } +OP( 0xf5, i_cmc ) { m_CarryVal = !CF; CLK(2); } +OP( 0xf6, i_f6pre ) { UINT32 tmp; UINT32 uresult,uresult2; INT32 result,result2; + GetModRM; tmp = GetRMByte(ModRM); + switch (ModRM & 0x38) { + case 0x00: tmp &= FETCH(); m_CarryVal = m_OverVal = 0; SetSZPF_Byte(tmp); m_icount-=(ModRM >=0xc0 )?4:11; break; /* TEST */ + case 0x08: logerror("%06x: Undefined opcode 0xf6 0x08\n",PC()); break; + case 0x10: PutbackRMByte(ModRM,~tmp); m_icount-=(ModRM >=0xc0 )?2:16; break; /* NOT */ + case 0x18: m_CarryVal=(tmp!=0); tmp=(~tmp)+1; SetSZPF_Byte(tmp); PutbackRMByte(ModRM,tmp&0xff); m_icount-=(ModRM >=0xc0 )?2:16; break; /* NEG */ + case 0x20: uresult = Breg(AL)*tmp; Wreg(AW)=(WORD)uresult; m_CarryVal=m_OverVal=(Breg(AH)!=0); m_icount-=(ModRM >=0xc0 )?30:36; break; /* MULU */ + case 0x28: result = (INT16)((INT8)Breg(AL))*(INT16)((INT8)tmp); Wreg(AW)=(WORD)result; m_CarryVal=m_OverVal=(Breg(AH)!=0); m_icount-=(ModRM >=0xc0 )?30:36; break; /* MUL */ + case 0x30: if (tmp) { DIVUB; } else nec_interrupt(NEC_DIVIDE_VECTOR, BRK); m_icount-=(ModRM >=0xc0 )?43:53; break; + case 0x38: if (tmp) { DIVB; } else nec_interrupt(NEC_DIVIDE_VECTOR, BRK); m_icount-=(ModRM >=0xc0 )?43:53; break; + } +} + +OP( 0xf7, i_f7pre ) { UINT32 tmp,tmp2; UINT32 uresult,uresult2; INT32 result,result2; + GetModRM; tmp = GetRMWord(ModRM); + switch (ModRM & 0x38) { + case 0x00: tmp2 = FETCHWORD(); tmp &= tmp2; m_CarryVal = m_OverVal = 0; SetSZPF_Word(tmp); m_icount-=(ModRM >=0xc0 )?4:11; break; /* TEST */ + case 0x08: logerror("%06x: Undefined opcode 0xf7 0x08\n",PC()); break; + case 0x10: PutbackRMWord(ModRM,~tmp); m_icount-=(ModRM >=0xc0 )?2:16; break; /* NOT */ + case 0x18: m_CarryVal=(tmp!=0); tmp=(~tmp)+1; SetSZPF_Word(tmp); PutbackRMWord(ModRM,tmp&0xffff); m_icount-=(ModRM >=0xc0 )?2:16; break; /* NEG */ + case 0x20: uresult = Wreg(AW)*tmp; Wreg(AW)=uresult&0xffff; Wreg(DW)=((UINT32)uresult)>>16; m_CarryVal=m_OverVal=(Wreg(DW)!=0); m_icount-=(ModRM >=0xc0 )?30:36; break; /* MULU */ + case 0x28: result = (INT32)((INT16)Wreg(AW))*(INT32)((INT16)tmp); Wreg(AW)=result&0xffff; Wreg(DW)=result>>16; m_CarryVal=m_OverVal=(Wreg(DW)!=0); m_icount-=(ModRM >=0xc0 )?30:36; break; /* MUL */ + case 0x30: if (tmp) { DIVUW; } else nec_interrupt(NEC_DIVIDE_VECTOR, BRK); m_icount-=(ModRM >=0xc0 )?43:53; break; + case 0x38: if (tmp) { DIVW; } else nec_interrupt(NEC_DIVIDE_VECTOR, BRK); m_icount-=(ModRM >=0xc0 )?43:53; break; + } +} + +OP( 0xf8, i_clc ) { m_CarryVal = 0; CLK(2); } +OP( 0xf9, i_stc ) { m_CarryVal = 1; CLK(2); } +OP( 0xfa, i_di ) { SetIF(0); CLK(2); } +OP( 0xfb, i_ei ) { SetIF(1); CLK(2); } +OP( 0xfc, i_cld ) { SetDF(0); CLK(2); } +OP( 0xfd, i_std ) { SetDF(1); CLK(2); } +OP( 0xfe, i_fepre ) { UINT32 tmp, tmp1; GetModRM; tmp=GetRMByte(ModRM); + switch(ModRM & 0x38) { + case 0x00: tmp1 = tmp+1; m_OverVal = (tmp==0x7f); SetAF(tmp1,tmp,1); SetSZPF_Byte(tmp1); PutbackRMByte(ModRM,(BYTE)tmp1); CLKM(2,2,2,16,16,7); break; /* INC */ + case 0x08: tmp1 = tmp-1; m_OverVal = (tmp==0x80); SetAF(tmp1,tmp,1); SetSZPF_Byte(tmp1); PutbackRMByte(ModRM,(BYTE)tmp1); CLKM(2,2,2,16,16,7); break; /* DEC */ + default: logerror("%06x: FE Pre with unimplemented mod\n",PC()); + } +} +OP( 0xff, i_ffpre ) { UINT32 tmp, tmp1; GetModRM; tmp=GetRMWord(ModRM); + switch(ModRM & 0x38) { + case 0x00: tmp1 = tmp+1; m_OverVal = (tmp==0x7fff); SetAF(tmp1,tmp,1); SetSZPF_Word(tmp1); PutbackRMWord(ModRM,(WORD)tmp1); CLKM(2,2,2,24,16,7); break; /* INC */ + case 0x08: tmp1 = tmp-1; m_OverVal = (tmp==0x8000); SetAF(tmp1,tmp,1); SetSZPF_Word(tmp1); PutbackRMWord(ModRM,(WORD)tmp1); CLKM(2,2,2,24,16,7); break; /* DEC */ + case 0x10: PUSH(m_ip); m_ip = (WORD)tmp; CHANGE_PC; m_icount-=(ModRM >=0xc0 )?16:20; break; /* CALL */ + case 0x18: tmp1 = Sreg(PS); Sreg(PS) = GetnextRMWord; PUSH(tmp1); PUSH(m_ip); m_ip = tmp; CHANGE_PC; m_icount-=(ModRM >=0xc0 )?16:26; break; /* CALL FAR */ + case 0x20: m_ip = tmp; CHANGE_PC; m_icount-=13; break; /* JMP */ + case 0x28: m_ip = tmp; Sreg(PS) = GetnextRMWord; CHANGE_PC; m_icount-=15; break; /* JMP FAR */ + case 0x30: PUSH(tmp); m_icount-=4; break; + default: logerror("%06x: FF Pre with unimplemented mod\n",PC()); + } +} + +void nec_common_device::i_invalid() +{ + m_icount-=10; + logerror("%06x: Invalid Opcode\n",PC()); +} diff --git a/src/devices/cpu/nec/necmacro.h b/src/devices/cpu/nec/necmacro.h new file mode 100644 index 00000000000..a6091f34eba --- /dev/null +++ b/src/devices/cpu/nec/necmacro.h @@ -0,0 +1,269 @@ +// license:BSD-3-Clause +// copyright-holders:Bryan McPhail +/* parameter x = result, y = source 1, z = source 2 */ + +#define SetTF(x) (m_TF = (x)) +#define SetIF(x) (m_IF = (x)) +#define SetDF(x) (m_DF = (x)) +#define SetMD(x) (m_MF = (x)) /* OB [19.07.99] Mode Flag V30 */ + +#define SetCFB(x) (m_CarryVal = (x) & 0x100) +#define SetCFW(x) (m_CarryVal = (x) & 0x10000) +#define SetAF(x,y,z) (m_AuxVal = ((x) ^ ((y) ^ (z))) & 0x10) +#define SetSF(x) (m_SignVal = (x)) +#define SetZF(x) (m_ZeroVal = (x)) +#define SetPF(x) (m_ParityVal = (x)) + +#define SetSZPF_Byte(x) (m_SignVal=m_ZeroVal=m_ParityVal=(INT8)(x)) +#define SetSZPF_Word(x) (m_SignVal=m_ZeroVal=m_ParityVal=(INT16)(x)) + +#define SetOFW_Add(x,y,z) (m_OverVal = ((x) ^ (y)) & ((x) ^ (z)) & 0x8000) +#define SetOFB_Add(x,y,z) (m_OverVal = ((x) ^ (y)) & ((x) ^ (z)) & 0x80) +#define SetOFW_Sub(x,y,z) (m_OverVal = ((z) ^ (y)) & ((z) ^ (x)) & 0x8000) +#define SetOFB_Sub(x,y,z) (m_OverVal = ((z) ^ (y)) & ((z) ^ (x)) & 0x80) + +#define ADDB { UINT32 res=dst+src; SetCFB(res); SetOFB_Add(res,src,dst); SetAF(res,src,dst); SetSZPF_Byte(res); dst=(BYTE)res; } +#define ADDW { UINT32 res=dst+src; SetCFW(res); SetOFW_Add(res,src,dst); SetAF(res,src,dst); SetSZPF_Word(res); dst=(WORD)res; } + +#define SUBB { UINT32 res=dst-src; SetCFB(res); SetOFB_Sub(res,src,dst); SetAF(res,src,dst); SetSZPF_Byte(res); dst=(BYTE)res; } +#define SUBW { UINT32 res=dst-src; SetCFW(res); SetOFW_Sub(res,src,dst); SetAF(res,src,dst); SetSZPF_Word(res); dst=(WORD)res; } + +#define ORB dst|=src; m_CarryVal=m_OverVal=m_AuxVal=0; SetSZPF_Byte(dst) +#define ORW dst|=src; m_CarryVal=m_OverVal=m_AuxVal=0; SetSZPF_Word(dst) + +#define ANDB dst&=src; m_CarryVal=m_OverVal=m_AuxVal=0; SetSZPF_Byte(dst) +#define ANDW dst&=src; m_CarryVal=m_OverVal=m_AuxVal=0; SetSZPF_Word(dst) + +#define XORB dst^=src; m_CarryVal=m_OverVal=m_AuxVal=0; SetSZPF_Byte(dst) +#define XORW dst^=src; m_CarryVal=m_OverVal=m_AuxVal=0; SetSZPF_Word(dst) + +#define IncWordReg(Reg) \ + unsigned tmp = (unsigned)Wreg(Reg); \ + unsigned tmp1 = tmp+1; \ + m_OverVal = (tmp == 0x7fff); \ + SetAF(tmp1,tmp,1); \ + SetSZPF_Word(tmp1); \ + Wreg(Reg)=tmp1 + +#define DecWordReg(Reg) \ + unsigned tmp = (unsigned)Wreg(Reg); \ + unsigned tmp1 = tmp-1; \ + m_OverVal = (tmp == 0x8000); \ + SetAF(tmp1,tmp,1); \ + SetSZPF_Word(tmp1); \ + Wreg(Reg)=tmp1 + +#define JMP(flag) \ + int tmp; \ + EMPTY_PREFETCH(); \ + tmp = (int)((INT8)FETCH()); \ + if (flag) \ + { \ + static const UINT8 table[3]={3,10,10}; \ + m_ip = (WORD)(m_ip+tmp); \ + m_icount-=table[m_chip_type/8]; \ + CHANGE_PC; \ + return; \ + } + +#define ADJ4(param1,param2) \ + if (AF || ((Breg(AL) & 0xf) > 9)) \ + { \ + UINT16 tmp; \ + tmp = Breg(AL) + param1; \ + Breg(AL) = tmp; \ + m_AuxVal = 1; \ + m_CarryVal |= tmp & 0x100; \ + } \ + if (CF || (Breg(AL)>0x9f)) \ + { \ + Breg(AL) += param2; \ + m_CarryVal = 1; \ + } \ + SetSZPF_Byte(Breg(AL)) + +#define ADJB(param1,param2) \ + if (AF || ((Breg(AL) & 0xf) > 9)) \ + { \ + Breg(AL) += param1; \ + Breg(AH) += param2; \ + m_AuxVal = 1; \ + m_CarryVal = 1; \ + } \ + else \ + { \ + m_AuxVal = 0; \ + m_CarryVal = 0; \ + } \ + Breg(AL) &= 0x0F + +#define BITOP_BYTE \ + ModRM = FETCH(); \ + if (ModRM >= 0xc0) { \ + tmp=Breg(Mod_RM.RM.b[ModRM]); \ + } \ + else { \ + (this->*s_GetEA[ModRM])(); \ + tmp=read_mem_byte(m_EA); \ + } + +#define BITOP_WORD \ + ModRM = FETCH(); \ + if (ModRM >= 0xc0) { \ + tmp=Wreg(Mod_RM.RM.w[ModRM]); \ + } \ + else { \ + (this->*s_GetEA[ModRM])(); \ + tmp=read_mem_word(m_EA); \ + } + +#define BIT_NOT \ + if (tmp & (1<> 1)+(CF<<7) +#define ROR_WORD m_CarryVal = dst & 0x1; dst = (dst >> 1)+(CF<<15) +#define ROLC_BYTE dst = (dst << 1) + CF; SetCFB(dst) +#define ROLC_WORD dst = (dst << 1) + CF; SetCFW(dst) +#define RORC_BYTE dst = (CF<<8)+dst; m_CarryVal = dst & 0x01; dst >>= 1 +#define RORC_WORD dst = (CF<<16)+dst; m_CarryVal = dst & 0x01; dst >>= 1 +#define SHL_BYTE(c) m_icount-=c; dst <<= c; SetCFB(dst); SetSZPF_Byte(dst); PutbackRMByte(ModRM,(BYTE)dst) +#define SHL_WORD(c) m_icount-=c; dst <<= c; SetCFW(dst); SetSZPF_Word(dst); PutbackRMWord(ModRM,(WORD)dst) +#define SHR_BYTE(c) m_icount-=c; dst >>= c-1; m_CarryVal = dst & 0x1; dst >>= 1; SetSZPF_Byte(dst); PutbackRMByte(ModRM,(BYTE)dst) +#define SHR_WORD(c) m_icount-=c; dst >>= c-1; m_CarryVal = dst & 0x1; dst >>= 1; SetSZPF_Word(dst); PutbackRMWord(ModRM,(WORD)dst) +#define SHRA_BYTE(c) m_icount-=c; dst = ((INT8)dst) >> (c-1); m_CarryVal = dst & 0x1; dst = ((INT8)((BYTE)dst)) >> 1; SetSZPF_Byte(dst); PutbackRMByte(ModRM,(BYTE)dst) +#define SHRA_WORD(c) m_icount-=c; dst = ((INT16)dst) >> (c-1); m_CarryVal = dst & 0x1; dst = ((INT16)((WORD)dst)) >> 1; SetSZPF_Word(dst); PutbackRMWord(ModRM,(WORD)dst) + +#define DIVUB \ + uresult = Wreg(AW); \ + uresult2 = uresult % tmp; \ + if ((uresult /= tmp) > 0xff) { \ + nec_interrupt(NEC_DIVIDE_VECTOR, BRK); break; \ + } else { \ + Breg(AL) = uresult; \ + Breg(AH) = uresult2; \ + } + +#define DIVB \ + result = (INT16)Wreg(AW); \ + result2 = result % (INT16)((INT8)tmp); \ + if ((result /= (INT16)((INT8)tmp)) > 0xff) { \ + nec_interrupt(NEC_DIVIDE_VECTOR, BRK); break; \ + } else { \ + Breg(AL) = result; \ + Breg(AH) = result2; \ + } + +#define DIVUW \ + uresult = (((UINT32)Wreg(DW)) << 16) | Wreg(AW);\ + uresult2 = uresult % tmp; \ + if ((uresult /= tmp) > 0xffff) { \ + nec_interrupt(NEC_DIVIDE_VECTOR, BRK); break; \ + } else { \ + Wreg(AW)=uresult; \ + Wreg(DW)=uresult2; \ + } + +#define DIVW \ + result = ((UINT32)Wreg(DW) << 16) + Wreg(AW); \ + result2 = result % (INT32)((INT16)tmp); \ + if ((result /= (INT32)((INT16)tmp)) > 0xffff) { \ + nec_interrupt(NEC_DIVIDE_VECTOR, BRK); break; \ + } else { \ + Wreg(AW)=result; \ + Wreg(DW)=result2; \ + } + +#define ADD4S { \ + int i,v1,v2,result; \ + int count = (Breg(CL)+1)/2; \ + unsigned di = Wreg(IY); \ + unsigned si = Wreg(IX); \ + static const UINT8 table[3]={18,19,19}; \ + if (m_seg_prefix) logerror("%06x: Warning: seg_prefix defined for add4s\n",PC()); \ + m_ZeroVal = m_CarryVal = 0; \ + for (i=0;i>4)*10 + (tmp&0xf); \ + v2 = (tmp2>>4)*10 + (tmp2&0xf); \ + result = v1+v2+m_CarryVal; \ + m_CarryVal = result > 99 ? 1 : 0; \ + result = result % 100; \ + v1 = ((result/10)<<4) | (result % 10); \ + PutMemB(DS1, di,v1); \ + if (v1) m_ZeroVal = 1; \ + si++; \ + di++; \ + } \ +} + +#define SUB4S { \ + int count = (Breg(CL)+1)/2; \ + int i,v1,v2,result; \ + unsigned di = Wreg(IY); \ + unsigned si = Wreg(IX); \ + static const UINT8 table[3]={18,19,19}; \ + if (m_seg_prefix) logerror("%06x: Warning: seg_prefix defined for sub4s\n",PC()); \ + m_ZeroVal = m_CarryVal = 0; \ + for (i=0;i>4)*10 + (tmp&0xf); \ + v2 = (tmp2>>4)*10 + (tmp2&0xf); \ + if (v1 < (v2+m_CarryVal)) { \ + v1+=100; \ + result = v1-(v2+m_CarryVal); \ + m_CarryVal = 1; \ + } else { \ + result = v1-(v2+m_CarryVal); \ + m_CarryVal = 0; \ + } \ + v1 = ((result/10)<<4) | (result % 10); \ + PutMemB(DS1, di,v1); \ + if (v1) m_ZeroVal = 1; \ + si++; \ + di++; \ + } \ +} + +#define CMP4S { \ + int count = (Breg(CL)+1)/2; \ + int i,v1,v2,result; \ + unsigned di = Wreg(IY); \ + unsigned si = Wreg(IX); \ + static const UINT8 table[3]={14,19,19}; \ + if (m_seg_prefix) logerror("%06x: Warning: seg_prefix defined for cmp4s\n",PC()); \ + m_ZeroVal = m_CarryVal = 0; \ + for (i=0;i>4)*10 + (tmp&0xf); \ + v2 = (tmp2>>4)*10 + (tmp2&0xf); \ + if (v1 < (v2+m_CarryVal)) { \ + v1+=100; \ + result = v1-(v2+m_CarryVal); \ + m_CarryVal = 1; \ + } else { \ + result = v1-(v2+m_CarryVal); \ + m_CarryVal = 0; \ + } \ + v1 = ((result/10)<<4) | (result % 10); \ + if (v1) m_ZeroVal = 1; \ + si++; \ + di++; \ + } \ +} diff --git a/src/devices/cpu/nec/necmodrm.h b/src/devices/cpu/nec/necmodrm.h new file mode 100644 index 00000000000..8afc0240a78 --- /dev/null +++ b/src/devices/cpu/nec/necmodrm.h @@ -0,0 +1,106 @@ +// license:BSD-3-Clause +// copyright-holders:Bryan McPhail +static struct { + struct { + WREGS w[256]; + BREGS b[256]; + } reg; + struct { + WREGS w[256]; + BREGS b[256]; + } RM; +} Mod_RM; + +#define RegWord(ModRM) Wreg(Mod_RM.reg.w[ModRM]) +#define RegByte(ModRM) Breg(Mod_RM.reg.b[ModRM]) + +#define GetRMWord(ModRM) \ + ((ModRM) >= 0xc0 ? Wreg(Mod_RM.RM.w[ModRM]) : ( (this->*s_GetEA[ModRM])(), read_mem_word( m_EA ) )) + +#define PutbackRMWord(ModRM,val) \ +{ \ + if (ModRM >= 0xc0) Wreg(Mod_RM.RM.w[ModRM])=val; \ + else write_mem_word(m_EA,val); \ +} + +#define GetnextRMWord read_mem_word((m_EA&0xf0000)|((m_EA+2)&0xffff)) + +#define PutRMWord(ModRM,val) \ +{ \ + if (ModRM >= 0xc0) \ + Wreg(Mod_RM.RM.w[ModRM])=val; \ + else { \ + (this->*s_GetEA[ModRM])(); \ + write_mem_word( m_EA ,val); \ + } \ +} + +#define PutImmRMWord(ModRM) \ +{ \ + WORD val; \ + if (ModRM >= 0xc0) \ + Wreg(Mod_RM.RM.w[ModRM]) = FETCHWORD(); \ + else { \ + (this->*s_GetEA[ModRM])(); \ + val = FETCHWORD(); \ + write_mem_word( m_EA , val); \ + } \ +} + +#define GetRMByte(ModRM) \ + ((ModRM) >= 0xc0 ? Breg(Mod_RM.RM.b[ModRM]) : read_mem_byte( (this->*s_GetEA[ModRM])() )) + +#define PutRMByte(ModRM,val) \ +{ \ + if (ModRM >= 0xc0) \ + Breg(Mod_RM.RM.b[ModRM])=val; \ + else \ + write_mem_byte( (this->*s_GetEA[ModRM])() ,val); \ +} + +#define PutImmRMByte(ModRM) \ +{ \ + if (ModRM >= 0xc0) \ + Breg(Mod_RM.RM.b[ModRM])=FETCH(); \ + else { \ + (this->*s_GetEA[ModRM])(); \ + write_mem_byte( m_EA , FETCH() ); \ + } \ +} + +#define PutbackRMByte(ModRM,val) \ +{ \ + if (ModRM >= 0xc0) \ + Breg(Mod_RM.RM.b[ModRM])=val; \ + else \ + write_mem_byte(m_EA,val); \ +} + +#define DEF_br8 \ + UINT32 ModRM = FETCH(),src,dst; \ + src = RegByte(ModRM); \ + dst = GetRMByte(ModRM) + +#define DEF_wr16 \ + UINT32 ModRM = FETCH(),src,dst; \ + src = RegWord(ModRM); \ + dst = GetRMWord(ModRM) + +#define DEF_r8b \ + UINT32 ModRM = FETCH(),src,dst; \ + dst = RegByte(ModRM); \ + src = GetRMByte(ModRM) + +#define DEF_r16w \ + UINT32 ModRM = FETCH(),src,dst; \ + dst = RegWord(ModRM); \ + src = GetRMWord(ModRM) + +#define DEF_ald8 \ + UINT32 src = FETCH(); \ + UINT32 dst = Breg(AL) + +#define DEF_axd16 \ + UINT32 src = FETCH(); \ + UINT32 dst = Wreg(AW); \ + src += (FETCH() << 8) diff --git a/src/devices/cpu/nec/necpriv.h b/src/devices/cpu/nec/necpriv.h new file mode 100644 index 00000000000..bee9426cf8d --- /dev/null +++ b/src/devices/cpu/nec/necpriv.h @@ -0,0 +1,131 @@ +// license:BSD-3-Clause +// copyright-holders:Bryan McPhail +/* Cpu types, steps of 8 to help the cycle count calculation */ +#define V33_TYPE 0 +#define V30_TYPE 8 +#define V20_TYPE 16 + +#ifndef FALSE +#define FALSE 0 +#define TRUE 1 +#endif + +/* interrupt vectors */ +enum +{ + NEC_DIVIDE_VECTOR = 0, + NEC_TRAP_VECTOR = 1, + NEC_NMI_VECTOR = 2, + NEC_BRKV_VECTOR = 4, + NEC_CHKIND_VECTOR = 5 +}; + +/* interrupt sources */ +enum INTSOURCES +{ + BRK = 0, + INT_IRQ = 1, + NMI_IRQ = 2 +}; + + +enum SREGS { DS1=0, PS, SS, DS0 }; +enum WREGS { AW=0, CW, DW, BW, SP, BP, IX, IY }; +enum BREGS { + AL = NATIVE_ENDIAN_VALUE_LE_BE(0x0, 0x1), + AH = NATIVE_ENDIAN_VALUE_LE_BE(0x1, 0x0), + CL = NATIVE_ENDIAN_VALUE_LE_BE(0x2, 0x3), + CH = NATIVE_ENDIAN_VALUE_LE_BE(0x3, 0x2), + DL = NATIVE_ENDIAN_VALUE_LE_BE(0x4, 0x5), + DH = NATIVE_ENDIAN_VALUE_LE_BE(0x5, 0x4), + BL = NATIVE_ENDIAN_VALUE_LE_BE(0x6, 0x7), + BH = NATIVE_ENDIAN_VALUE_LE_BE(0x7, 0x6) +}; + +#define Sreg(x) m_sregs[x] +#define Wreg(x) m_regs.w[x] +#define Breg(x) m_regs.b[x] + +#define PC() ((Sreg(PS)<<4)+m_ip) + +#define CF (m_CarryVal!=0) +#define SF (m_SignVal<0) +#define ZF (m_ZeroVal==0) +#define PF parity_table[(BYTE)m_ParityVal] +#define AF (m_AuxVal!=0) +#define OF (m_OverVal!=0) + +/************************************************************************/ + +#define read_mem_byte(a) m_program->read_byte(a) +#define read_mem_word(a) m_program->read_word_unaligned(a) +#define write_mem_byte(a,d) m_program->write_byte((a),(d)) +#define write_mem_word(a,d) m_program->write_word_unaligned((a),(d)) + +#define read_port_byte(a) m_io->read_byte(a) +#define read_port_word(a) m_io->read_word_unaligned(a) +#define write_port_byte(a,d) m_io->write_byte((a),(d)) +#define write_port_word(a,d) m_io->write_word_unaligned((a),(d)) + +/************************************************************************/ + +#define CHANGE_PC do { EMPTY_PREFETCH(); } while (0) + +#define SegBase(Seg) (Sreg(Seg) << 4) + +#define DefaultBase(Seg) ((m_seg_prefix && (Seg==DS0 || Seg==SS)) ? m_prefix_base : Sreg(Seg) << 4) + +#define GetMemB(Seg,Off) (read_mem_byte(DefaultBase(Seg) + (Off))) +#define GetMemW(Seg,Off) (read_mem_word(DefaultBase(Seg) + (Off))) + +#define PutMemB(Seg,Off,x) { write_mem_byte(DefaultBase(Seg) + (Off), (x)); } +#define PutMemW(Seg,Off,x) { write_mem_word(DefaultBase(Seg) + (Off), (x)); } + +/* prefetch timing */ + +#define FETCH() fetch() +#define FETCHWORD() fetchword() +#define EMPTY_PREFETCH() m_prefetch_reset = 1 + + +#define PUSH(val) { Wreg(SP) -= 2; write_mem_word(((Sreg(SS)<<4)+Wreg(SP)), val); } +#define POP(var) { Wreg(SP) += 2; var = read_mem_word(((Sreg(SS)<<4) + ((Wreg(SP)-2) & 0xffff))); } + +#define GetModRM UINT32 ModRM=FETCH() + +/* Cycle count macros: + CLK - cycle count is the same on all processors + CLKS - cycle count differs between processors, list all counts + CLKW - cycle count for word read/write differs for odd/even source/destination address + CLKM - cycle count for reg/mem instructions + CLKR - cycle count for reg/mem instructions with different counts for odd/even addresses + + + Prefetch & buswait time is not emulated. + Extra cycles for PUSH'ing or POP'ing registers to odd addresses is not emulated. +*/ + +#define CLK(all) m_icount-=all +#define CLKS(v20,v30,v33) { const UINT32 ccount=(v20<<16)|(v30<<8)|v33; m_icount-=(ccount>>m_chip_type)&0x7f; } +#define CLKW(v20o,v30o,v33o,v20e,v30e,v33e,addr) { const UINT32 ocount=(v20o<<16)|(v30o<<8)|v33o, ecount=(v20e<<16)|(v30e<<8)|v33e; m_icount-=(addr&1)?((ocount>>m_chip_type)&0x7f):((ecount>>m_chip_type)&0x7f); } +#define CLKM(v20,v30,v33,v20m,v30m,v33m) { const UINT32 ccount=(v20<<16)|(v30<<8)|v33, mcount=(v20m<<16)|(v30m<<8)|v33m; m_icount-=( ModRM >=0xc0 )?((ccount>>m_chip_type)&0x7f):((mcount>>m_chip_type)&0x7f); } +#define CLKR(v20o,v30o,v33o,v20e,v30e,v33e,vall,addr) { const UINT32 ocount=(v20o<<16)|(v30o<<8)|v33o, ecount=(v20e<<16)|(v30e<<8)|v33e; if (ModRM >=0xc0) m_icount-=vall; else m_icount-=(addr&1)?((ocount>>m_chip_type)&0x7f):((ecount>>m_chip_type)&0x7f); } + +/************************************************************************/ +#define CompressFlags() (WORD)(int(CF) | 0x02 | (int(PF) << 2) | (int(AF) << 4) | (int(ZF) << 6) \ + | (int(SF) << 7) | (m_TF << 8) | (m_IF << 9) \ + | (m_DF << 10) | (int(OF) << 11) | 0x7000 | (m_MF << 15)) + +#define ExpandFlags(f) \ +{ \ + m_CarryVal = (f) & 0x0001; \ + m_ParityVal = !((f) & 0x0004); \ + m_AuxVal = (f) & 0x0010; \ + m_ZeroVal = !((f) & 0x0040); \ + m_SignVal = (f) & 0x0080 ? -1 : 0; \ + m_TF = ((f) & 0x0100) == 0x0100; \ + m_IF = ((f) & 0x0200) == 0x0200; \ + m_DF = ((f) & 0x0400) == 0x0400; \ + m_OverVal = (f) & 0x0800; \ + m_MF = ((f) & 0x8000) == 0x8000; \ +} diff --git a/src/devices/cpu/nec/v25.c b/src/devices/cpu/nec/v25.c new file mode 100644 index 00000000000..384043c8f9c --- /dev/null +++ b/src/devices/cpu/nec/v25.c @@ -0,0 +1,751 @@ +// license:BSD-3-Clause +// copyright-holders:Bryan McPhail, Alex W. Jackson +/**************************************************************************** + + NEC V25/V35 emulator + + --------------------------------------------- + + TODO: + + Using V20/V30 cycle counts for now. V25/V35 cycle counts + vary based on whether internal RAM access is enabled (RAMEN). + + BTCLR and STOP instructions not implemented. + + IBRK flag (trap I/O instructions) not implemented. + + Interrupt macro service function not implemented. + + Port implementation is incomplete: mode control registers are ignored. + + Timer implementation is incomplete: polling is not implemented + (reading any of the registers just returns the last value written) + + Serial interface and DMA functions not implemented. + Note that these functions differ considerably between + the V25/35 and the V25+/35+. + + Make internal RAM into a real RAM region, and use an + internal address map (remapped when IDB is written to) + instead of memory access wrapper functions. + That way the internal RAM would be visible to the debugger, + among other benefits. + +****************************************************************************/ + +#include "emu.h" +#include "debugger.h" + +typedef UINT8 BOOLEAN; +typedef UINT8 BYTE; +typedef UINT16 WORD; +typedef UINT32 DWORD; + +#include "v25.h" +#include "v25priv.h" + +const device_type V25 = &device_creator; +const device_type V35 = &device_creator; + + +v25_common_device::v25_common_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, bool is_16bit, offs_t fetch_xor, UINT8 prefetch_size, UINT8 prefetch_cycles, UINT32 chip_type) + : cpu_device(mconfig, type, name, tag, owner, clock, shortname, __FILE__) + , m_program_config("program", ENDIANNESS_LITTLE, is_16bit ? 16 : 8, 20, 0) + , m_io_config("io", ENDIANNESS_LITTLE, is_16bit ? 16 : 8, 17, 0) + , m_fetch_xor(fetch_xor) + , m_PCK(8) + , m_prefetch_size(prefetch_size) + , m_prefetch_cycles(prefetch_cycles) + , m_chip_type(chip_type) + , m_v25v35_decryptiontable(NULL) +{ +} + + +v25_device::v25_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : v25_common_device(mconfig, V25, "V25", tag, owner, clock, "v25", false, 0, 4, 4, V20_TYPE) +{ +} + + +v35_device::v35_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : v25_common_device(mconfig, V35, "V35", tag, owner, clock, "v35", true, BYTE_XOR_LE(0), 6, 2, V30_TYPE) +{ +} + + +TIMER_CALLBACK_MEMBER(v25_common_device::v25_timer_callback) +{ + m_pending_irq |= param; +} + +void v25_common_device::prefetch() +{ + m_prefetch_count--; +} + +void v25_common_device::do_prefetch(int previous_ICount) +{ + int diff = previous_ICount - (int) m_icount; + + /* The implementation is not accurate, but comes close. + * It does not respect that the V30 will fetch two bytes + * at once directly, but instead uses only 2 cycles instead + * of 4. There are however only very few sources publicly + * available and they are vague. + */ + while (m_prefetch_count<0) + { + m_prefetch_count++; + if (diff>m_prefetch_cycles) + diff -= m_prefetch_cycles; + else + m_icount -= m_prefetch_cycles; + } + + if (m_prefetch_reset) + { + m_prefetch_count = 0; + m_prefetch_reset = 0; + return; + } + + while (diff>=m_prefetch_cycles && m_prefetch_count < m_prefetch_size) + { + diff -= m_prefetch_cycles; + m_prefetch_count++; + } + +} + +UINT8 v25_common_device::fetch() +{ + prefetch(); + return m_direct->read_byte((Sreg(PS)<<4)+m_ip++, m_fetch_xor); +} + +UINT16 v25_common_device::fetchword() +{ + UINT16 r = FETCH(); + r |= (FETCH()<<8); + return r; +} + +#define nec_common_device v25_common_device + +#include "v25instr.h" +#include "necmacro.h" +#include "necea.h" +#include "necmodrm.h" + +static UINT8 parity_table[256]; + +UINT8 v25_common_device::fetchop() +{ + UINT8 ret; + + prefetch(); + ret = m_direct->read_byte(( Sreg(PS)<<4)+m_ip++, m_fetch_xor); + + if (m_MF == 0) + if (m_v25v35_decryptiontable) + { + ret = m_v25v35_decryptiontable[ret]; + } + return ret; +} + + + +/***************************************************************************/ + +void v25_common_device::device_reset() +{ + attotime time; + + m_ip = 0; + m_IBRK = 1; + m_F0 = 0; + m_F1 = 0; + m_TF = 0; + m_IF = 0; + m_DF = 0; + m_SignVal = 0; + m_AuxVal = 0; + m_OverVal = 0; + m_ZeroVal = 1; + m_CarryVal = 0; + m_ParityVal = 1; + m_pending_irq = 0; + m_unmasked_irq = INT_IRQ | NMI_IRQ; + m_bankswitch_irq = 0; + m_priority_inttu = 7; + m_priority_intd = 7; + m_priority_intp = 7; + m_priority_ints0 = 7; + m_priority_ints1 = 7; + m_IRQS = m_ISPR = 0; + m_nmi_state = 0; + m_irq_state = 0; + m_poll_state = 1; + m_mode_state = m_MF = (m_v25v35_decryptiontable) ? 0 : 1; + m_intp_state[0] = 0; + m_intp_state[1] = 0; + m_intp_state[2] = 0; + m_halted = 0; + + m_TM0 = m_MD0 = m_TM1 = m_MD1 = 0; + m_TMC0 = m_TMC1 = 0; + + m_RAMEN = 1; + m_TB = 20; + m_PCK = 8; + m_IDB = 0xFFE00; + + int tmp = m_PCK << m_TB; + time = attotime::from_hz(unscaled_clock()) * tmp; + m_timers[3]->adjust(time, INTTB, time); + + m_timers[0]->adjust(attotime::never); + m_timers[1]->adjust(attotime::never); + m_timers[2]->adjust(attotime::never); + + SetRB(7); + Sreg(PS) = 0xffff; + Sreg(SS) = 0; + Sreg(DS0) = 0; + Sreg(DS1) = 0; + + CHANGE_PC; +} + + +void v25_common_device::nec_interrupt(unsigned int_num, int /*INTSOURCES*/ source) +{ + UINT32 dest_seg, dest_off; + + i_pushf(); + m_TF = m_IF = 0; + m_MF = m_mode_state; + + switch(source) + { + case BRKN: /* force native mode */ + m_MF = 1; + break; + case BRKS: /* force secure mode */ + if (m_v25v35_decryptiontable) + m_MF = 0; + else + logerror("%06x: BRKS executed with no decryption table\n",PC()); + break; + case INT_IRQ: /* get vector */ + int_num = standard_irq_callback(0); + break; + default: + break; + } + + dest_off = read_mem_word(int_num*4); + dest_seg = read_mem_word(int_num*4+2); + + PUSH(Sreg(PS)); + PUSH(m_ip); + m_ip = (WORD)dest_off; + Sreg(PS) = (WORD)dest_seg; + CHANGE_PC; +} + +void v25_common_device::nec_bankswitch(unsigned bank_num) +{ + int tmp = CompressFlags(); + + m_TF = m_IF = 0; + m_MF = m_mode_state; + + SetRB(bank_num); + + Wreg(PSW_SAVE) = tmp; + Wreg(PC_SAVE) = m_ip; + m_ip = Wreg(VECTOR_PC); + CHANGE_PC; +} + +void v25_common_device::nec_trap() +{ + (this->*s_nec_instruction[fetchop()])(); + nec_interrupt(NEC_TRAP_VECTOR, BRK); +} + +#define INTERRUPT(source, vector, priority) \ + if(pending & (source)) { \ + m_IRQS = vector; \ + m_ISPR |= (1 << (priority)); \ + m_pending_irq &= ~(source); \ + if(m_bankswitch_irq & (source)) \ + nec_bankswitch(priority); \ + else \ + nec_interrupt(vector, source); \ + break; /* break out of loop */ \ + } + +/* interrupt sources subject to priority control */ +#define SOURCES (INTTU0 | INTTU1 | INTTU2 | INTD0 | INTD1 | INTP0 | INTP1 | INTP2 \ + | INTSER0 | INTSR0 | INTST0 | INTSER1 | INTSR1 | INTST1 | INTTB) + +void v25_common_device::external_int() +{ + int pending = m_pending_irq & m_unmasked_irq; + + if (pending & NMI_IRQ) + { + nec_interrupt(NEC_NMI_VECTOR, NMI_IRQ); + m_pending_irq &= ~NMI_IRQ; + } + else if (pending & SOURCES) + { + for(int i = 0; i < 8; i++) + { + if (m_ISPR & (1 << i)) break; + + if (m_priority_inttu == i) + { + INTERRUPT(INTTU0, NEC_INTTU0_VECTOR, i) + INTERRUPT(INTTU1, NEC_INTTU1_VECTOR, i) + INTERRUPT(INTTU2, NEC_INTTU2_VECTOR, i) + } + + if (m_priority_intd == i) + { + INTERRUPT(INTD0, NEC_INTD0_VECTOR, i) + INTERRUPT(INTD1, NEC_INTD1_VECTOR, i) + } + + if (m_priority_intp == i) + { + INTERRUPT(INTP0, NEC_INTP0_VECTOR, i) + INTERRUPT(INTP1, NEC_INTP1_VECTOR, i) + INTERRUPT(INTP2, NEC_INTP2_VECTOR, i) + } + + if (m_priority_ints0 == i) + { + INTERRUPT(INTSER0, NEC_INTSER0_VECTOR, i) + INTERRUPT(INTSR0, NEC_INTSR0_VECTOR, i) + INTERRUPT(INTST0, NEC_INTST0_VECTOR, i) + } + + if (m_priority_ints1 == i) + { + INTERRUPT(INTSER1, NEC_INTSER1_VECTOR, i) + INTERRUPT(INTSR1, NEC_INTSR1_VECTOR, i) + INTERRUPT(INTST1, NEC_INTST1_VECTOR, i) + } + + if (i == 7) + INTERRUPT(INTTB, NEC_INTTB_VECTOR, 7) + } + } + else if (pending & INT_IRQ) + { + /* the actual vector is retrieved after pushing flags */ + /* and clearing the IF */ + nec_interrupt((UINT32)-1, INT_IRQ); + m_irq_state = CLEAR_LINE; + m_pending_irq &= ~INT_IRQ; + } +} + +/****************************************************************************/ +/* OPCODES */ +/****************************************************************************/ + +#include "necinstr.inc" +#include "v25instr.inc" + +/*****************************************************************************/ + +void v25_common_device::execute_set_input(int irqline, int state) +{ + switch (irqline) + { + case 0: + m_irq_state = state; + if (state == CLEAR_LINE) + m_pending_irq &= ~INT_IRQ; + else + { + m_pending_irq |= INT_IRQ; + m_halted = 0; + } + break; + case INPUT_LINE_NMI: + if (m_nmi_state == state) return; + m_nmi_state = state; + if (state != CLEAR_LINE) + { + m_pending_irq |= NMI_IRQ; + m_halted = 0; + } + break; + case NEC_INPUT_LINE_INTP0: + case NEC_INPUT_LINE_INTP1: + case NEC_INPUT_LINE_INTP2: + irqline -= NEC_INPUT_LINE_INTP0; + if (m_intp_state[irqline] == state) return; + m_intp_state[irqline] = state; + if (state != CLEAR_LINE) + m_pending_irq |= (INTP0 << irqline); + break; + case NEC_INPUT_LINE_POLL: + m_poll_state = state; + break; + } +} + +offs_t v25_common_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern int necv_dasm_one(char *buffer, UINT32 eip, const UINT8 *oprom, const UINT8 *decryption_table); + + return necv_dasm_one(buffer, pc, oprom, m_v25v35_decryptiontable); +} + +void v25_common_device::device_start() +{ + unsigned int i, j, c; + + static const WREGS wreg_name[8]={ AW, CW, DW, BW, SP, BP, IX, IY }; + static const BREGS breg_name[8]={ AL, CL, DL, BL, AH, CH, DH, BH }; + + for (i = 0; i < 256; i++) + { + for (j = i, c = 0; j > 0; j >>= 1) + if (j & 1) c++; + parity_table[i] = !(c & 1); + } + + for (i = 0; i < 256; i++) + { + Mod_RM.reg.b[i] = breg_name[(i & 0x38) >> 3]; + Mod_RM.reg.w[i] = wreg_name[(i & 0x38) >> 3]; + } + + for (i = 0xc0; i < 0x100; i++) + { + Mod_RM.RM.w[i] = wreg_name[i & 7]; + Mod_RM.RM.b[i] = breg_name[i & 7]; + } + + m_no_interrupt = 0; + m_prefetch_count = 0; + m_prefetch_reset = 0; + m_prefix_base = 0; + m_seg_prefix = 0; + m_EA = 0; + m_EO = 0; + m_E16 = 0; + + for (i = 0; i < 4; i++) + m_timers[i] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(v25_common_device::v25_timer_callback),this)); + + save_item(NAME(m_ram.w)); + save_item(NAME(m_intp_state)); + + save_item(NAME(m_ip)); + save_item(NAME(m_IBRK)); + save_item(NAME(m_F0)); + save_item(NAME(m_F1)); + save_item(NAME(m_TF)); + save_item(NAME(m_IF)); + save_item(NAME(m_DF)); + save_item(NAME(m_MF)); + save_item(NAME(m_RBW)); + save_item(NAME(m_RBB)); + save_item(NAME(m_SignVal)); + save_item(NAME(m_AuxVal)); + save_item(NAME(m_OverVal)); + save_item(NAME(m_ZeroVal)); + save_item(NAME(m_CarryVal)); + save_item(NAME(m_ParityVal)); + save_item(NAME(m_pending_irq)); + save_item(NAME(m_unmasked_irq)); + save_item(NAME(m_bankswitch_irq)); + save_item(NAME(m_priority_inttu)); + save_item(NAME(m_priority_intd)); + save_item(NAME(m_priority_intp)); + save_item(NAME(m_priority_ints0)); + save_item(NAME(m_priority_ints1)); + save_item(NAME(m_IRQS)); + save_item(NAME(m_ISPR)); + save_item(NAME(m_nmi_state)); + save_item(NAME(m_irq_state)); + save_item(NAME(m_poll_state)); + save_item(NAME(m_mode_state)); + save_item(NAME(m_no_interrupt)); + save_item(NAME(m_halted)); + save_item(NAME(m_TM0)); + save_item(NAME(m_MD0)); + save_item(NAME(m_TM1)); + save_item(NAME(m_MD1)); + save_item(NAME(m_TMC0)); + save_item(NAME(m_TMC1)); + save_item(NAME(m_RAMEN)); + save_item(NAME(m_TB)); + save_item(NAME(m_PCK)); + save_item(NAME(m_IDB)); + save_item(NAME(m_prefetch_count)); + save_item(NAME(m_prefetch_reset)); + + m_program = &space(AS_PROGRAM); + m_direct = &m_program->direct(); + m_io = &space(AS_IO); + + state_add( V25_PC, "PC", m_debugger_temp).callimport().callexport().formatstr("%05X"); + state_add( V25_IP, "IP", m_ip).formatstr("%04X"); + state_add( V25_SP, "SP", m_debugger_temp).callimport().callexport().formatstr("%04X"); + state_add( V25_FLAGS, "F", m_debugger_temp).callimport().callexport().formatstr("%04X"); + state_add( V25_AW, "AW", m_debugger_temp).callimport().callexport().formatstr("%04X"); + state_add( V25_CW, "CW", m_debugger_temp).callimport().callexport().formatstr("%04X"); + state_add( V25_DW, "DW", m_debugger_temp).callimport().callexport().formatstr("%04X"); + state_add( V25_BW, "BW", m_debugger_temp).callimport().callexport().formatstr("%04X"); + state_add( V25_BP, "BP", m_debugger_temp).callimport().callexport().formatstr("%04X"); + state_add( V25_IX, "IX", m_debugger_temp).callimport().callexport().formatstr("%04X"); + state_add( V25_IY, "IY", m_debugger_temp).callimport().callexport().formatstr("%04X"); + state_add( V25_ES, "DS1", m_debugger_temp).callimport().callexport().formatstr("%04X"); + state_add( V25_CS, "PS", m_debugger_temp).callimport().callexport().formatstr("%04X"); + state_add( V25_SS, "SS", m_debugger_temp).callimport().callexport().formatstr("%04X"); + state_add( V25_DS, "DS0", m_debugger_temp).callimport().callexport().formatstr("%04X"); + + state_add( STATE_GENPC, "GENPC", m_debugger_temp).callimport().callexport().noshow(); + state_add( STATE_GENSP, "GENSP", m_debugger_temp).callimport().callexport().noshow(); + state_add( STATE_GENFLAGS, "GENFLAGS", m_debugger_temp).formatstr("%16s").noshow(); + + m_icountptr = &m_icount; +} + + +void v25_common_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + UINT16 flags = CompressFlags(); + + switch (entry.index()) + { + case STATE_GENFLAGS: + strprintf(str, "%c %d %c%c%c%c%c%c%c%c%c%c%c%c", + flags & 0x8000 ? 'N':'S', + (flags & 0x7000) >> 12, + flags & 0x0800 ? 'O':'.', + flags & 0x0400 ? 'D':'.', + flags & 0x0200 ? 'I':'.', + flags & 0x0100 ? 'T':'.', + flags & 0x0080 ? 'S':'.', + flags & 0x0040 ? 'Z':'.', + flags & 0x0020 ? '1':'.', + flags & 0x0010 ? 'A':'.', + flags & 0x0008 ? '0':'.', + flags & 0x0004 ? 'P':'.', + flags & 0x0002 ? '.':'I', + flags & 0x0001 ? 'C':'.'); + break; + } +} + +void v25_common_device::state_import(const device_state_entry &entry) +{ + switch (entry.index()) + { + case V25_PC: + if( m_debugger_temp - (Sreg(PS)<<4) < 0x10000 ) + { + m_ip = m_debugger_temp - (Sreg(PS)<<4); + } + else + { + Sreg(PS) = m_debugger_temp >> 4; + m_ip = m_debugger_temp & 0x0000f; + } + break; + + case V25_SP: + Wreg(SP) = m_debugger_temp; + break; + + case V25_FLAGS: + ExpandFlags(m_debugger_temp); + break; + + case V25_AW: + Wreg(AW) = m_debugger_temp; + break; + + case V25_CW: + Wreg(CW) = m_debugger_temp; + break; + + case V25_DW: + Wreg(DW) = m_debugger_temp; + break; + + case V25_BW: + Wreg(BW) = m_debugger_temp; + break; + + case V25_BP: + Wreg(BP) = m_debugger_temp; + break; + + case V25_IX: + Wreg(IX) = m_debugger_temp; + break; + + case V25_IY: + Wreg(IY) = m_debugger_temp; + break; + + case V25_ES: + Sreg(DS1) = m_debugger_temp; + break; + + case V25_CS: + Sreg(PS) = m_debugger_temp; + break; + + case V25_SS: + Sreg(SS) = m_debugger_temp; + break; + + case V25_DS: + Sreg(DS0) = m_debugger_temp; + break; + } +} + + +void v25_common_device::state_export(const device_state_entry &entry) +{ + switch (entry.index()) + { + case STATE_GENPC: + case V25_PC: + m_debugger_temp = (Sreg(PS)<<4) + m_ip; + break; + + case STATE_GENSP: + m_debugger_temp = (Sreg(SS)<<4) + Wreg(SP); + break; + + case V25_SP: + m_debugger_temp = Wreg(SP); + break; + + case V25_FLAGS: + m_debugger_temp = CompressFlags(); + break; + + case V25_AW: + m_debugger_temp = Wreg(AW); + break; + + case V25_CW: + m_debugger_temp = Wreg(CW); + break; + + case V25_DW: + m_debugger_temp = Wreg(DW); + break; + + case V25_BW: + m_debugger_temp = Wreg(BW); + break; + + case V25_BP: + m_debugger_temp = Wreg(BP); + break; + + case V25_IX: + m_debugger_temp = Wreg(IX); + break; + + case V25_IY: + m_debugger_temp = Wreg(IY); + break; + + case V25_ES: + m_debugger_temp = Sreg(DS1); + break; + + case V25_CS: + m_debugger_temp = Sreg(PS); + break; + + case V25_SS: + m_debugger_temp = Sreg(SS); + break; + + case V25_DS: + m_debugger_temp = Sreg(DS0); + break; + } +} + + +void v25_common_device::execute_run() +{ + int prev_ICount; + + int pending = m_pending_irq & m_unmasked_irq; + + if (m_halted && pending) + { + for(int i = 0; i < 8; i++) + { + if (m_ISPR & (1 << i)) break; + + if (m_priority_inttu == i && (pending & (INTTU0|INTTU1|INTTU2))) + m_halted = 0; + + if (m_priority_intd == i && (pending & (INTD0|INTD1))) + m_halted = 0; + + if (m_priority_intp == i && (pending & (INTP0|INTP1|INTP2))) + m_halted = 0; + + if (m_priority_ints0 == i && (pending & (INTSER0|INTSR0|INTST0))) + m_halted = 0; + + if (m_priority_ints1 == i && (pending & (INTSER1|INTSR1|INTST1))) + m_halted = 0; + + if (i == 7 && (pending & INTTB)) + m_halted = 0; + } + } + + if (m_halted) + { + m_icount = 0; + debugger_instruction_hook(this, (Sreg(PS)<<4) + m_ip); + return; + } + + while(m_icount>0) { + /* Dispatch IRQ */ + if (m_no_interrupt==0 && (m_pending_irq & m_unmasked_irq)) + { + if (m_pending_irq & NMI_IRQ) + external_int(); + else if (m_IF) + external_int(); + } + + /* No interrupt allowed between last instruction and this one */ + if (m_no_interrupt) + m_no_interrupt--; + + debugger_instruction_hook(this, (Sreg(PS)<<4) + m_ip); + prev_ICount = m_icount; + (this->*s_nec_instruction[fetchop()])(); + do_prefetch(prev_ICount); + } +} diff --git a/src/devices/cpu/nec/v25.h b/src/devices/cpu/nec/v25.h new file mode 100644 index 00000000000..41d55cc4fb8 --- /dev/null +++ b/src/devices/cpu/nec/v25.h @@ -0,0 +1,458 @@ +// license:BSD-3-Clause +// copyright-holders:Bryan McPhail, Alex W. Jackson +/* ASG 971222 -- rewrote this interface */ +#ifndef __NEC_V25_H_ +#define __NEC_V25_H_ + + +#define NEC_INPUT_LINE_INTP0 10 +#define NEC_INPUT_LINE_INTP1 11 +#define NEC_INPUT_LINE_INTP2 12 +#define NEC_INPUT_LINE_POLL 20 + +#define V25_PORT_P0 0x10000 +#define V25_PORT_P1 0x10002 +#define V25_PORT_P2 0x10004 +#define V25_PORT_PT 0x10006 + +enum +{ + V25_PC=0, + V25_IP, V25_AW, V25_CW, V25_DW, V25_BW, V25_SP, V25_BP, V25_IX, V25_IY, + V25_FLAGS, V25_ES, V25_CS, V25_SS, V25_DS, + V25_PENDING +}; + + +#define MCFG_V25_CONFIG(_table) \ + v25_common_device::set_decryption_table(*device, _table); + + +class v25_common_device : public cpu_device +{ +public: + // construction/destruction + v25_common_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, bool is_16bit, offs_t fetch_xor, UINT8 prefetch_size, UINT8 prefetch_cycles, UINT32 chip_type); + + // static configuration helpers + static void set_decryption_table(device_t &device, const UINT8 *decryption_table) { downcast(device).m_v25v35_decryptiontable = decryption_table; } + + TIMER_CALLBACK_MEMBER(v25_timer_callback); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_post_load() { notify_clock_changed(); } + + // device_execute_interface overrides + virtual UINT64 execute_clocks_to_cycles(UINT64 clocks) const { return clocks / m_PCK; } + virtual UINT64 execute_cycles_to_clocks(UINT64 cycles) const { return cycles * m_PCK; } + virtual UINT32 execute_min_cycles() const { return 1; } + virtual UINT32 execute_max_cycles() const { return 80; } + virtual UINT32 execute_input_lines() const { return 1; } + virtual UINT32 execute_default_irq_vector() const { return 0xff; } + virtual void execute_run(); + virtual void execute_set_input(int inputnum, int state); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const { return (spacenum == AS_PROGRAM) ? &m_program_config : ( (spacenum == AS_IO) ? &m_io_config : NULL); } + + // device_state_interface overrides + void state_string_export(const device_state_entry &entry, std::string &str); + virtual void state_import(const device_state_entry &entry); + virtual void state_export(const device_state_entry &entry); + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const { return 1; } + virtual UINT32 disasm_max_opcode_bytes() const { return 8; } + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + +private: + address_space_config m_program_config; + address_space_config m_io_config; + +/* internal RAM and register banks */ +union internalram +{ + UINT16 w[128]; + UINT8 b[256]; +}; + + internalram m_ram; + offs_t m_fetch_xor; + + UINT16 m_ip; + + /* PSW flags */ + INT32 m_SignVal; + UINT32 m_AuxVal, m_OverVal, m_ZeroVal, m_CarryVal, m_ParityVal; /* 0 or non-0 valued flags */ + UINT8 m_IBRK, m_F0, m_F1, m_TF, m_IF, m_DF, m_MF; /* 0 or 1 valued flags */ + UINT8 m_RBW, m_RBB; /* current register bank base, preshifted for word and byte registers */ + + /* interrupt related */ + UINT32 m_pending_irq; + UINT32 m_unmasked_irq; + UINT32 m_bankswitch_irq; + UINT8 m_priority_inttu, m_priority_intd, m_priority_intp, m_priority_ints0, m_priority_ints1; + UINT8 m_IRQS, m_ISPR; + UINT32 m_nmi_state; + UINT32 m_irq_state; + UINT32 m_poll_state; + UINT32 m_mode_state; + UINT32 m_intp_state[3]; + UINT8 m_no_interrupt; + UINT8 m_halted; + + /* timer related */ + UINT16 m_TM0, m_MD0, m_TM1, m_MD1; + UINT8 m_TMC0, m_TMC1; + emu_timer *m_timers[4]; + + /* system control */ + UINT8 m_RAMEN, m_TB, m_PCK; /* PRC register */ + UINT32 m_IDB; + + address_space *m_program; + direct_read_data *m_direct; + address_space *m_io; + int m_icount; + + UINT8 m_prefetch_size; + UINT8 m_prefetch_cycles; + INT8 m_prefetch_count; + UINT8 m_prefetch_reset; + UINT32 m_chip_type; + + UINT32 m_prefix_base; /* base address of the latest prefix segment */ + UINT8 m_seg_prefix; /* prefix segment indicator */ + + UINT32 m_EA; + UINT16 m_EO; + UINT16 m_E16; + + UINT32 m_debugger_temp; + + const UINT8 *m_v25v35_decryptiontable; // internal decryption table + + typedef void (v25_common_device::*nec_ophandler)(); + typedef UINT32 (v25_common_device::*nec_eahandler)(); + static const nec_ophandler s_nec_instruction[256]; + static const nec_eahandler s_GetEA[192]; + + inline void prefetch(); + void do_prefetch(int previous_ICount); + inline UINT8 fetch(); + inline UINT16 fetchword(); + inline UINT8 fetchop(); + void nec_interrupt(unsigned int_num, int /*INTSOURCES*/ source); + void nec_bankswitch(unsigned bank_num); + void nec_trap(); + void external_int(); + UINT8 read_irqcontrol(int /*INTSOURCES*/ source, UINT8 priority); + UINT8 read_sfr(unsigned o); + UINT16 read_sfr_word(unsigned o); + void write_irqcontrol(int /*INTSOURCES*/ source, UINT8 d); + void write_sfr(unsigned o, UINT8 d); + void write_sfr_word(unsigned o, UINT16 d); + UINT8 v25_read_byte(unsigned a); + UINT16 v25_read_word(unsigned a); + void v25_write_byte(unsigned a, UINT8 d); + void v25_write_word(unsigned a, UINT16 d); + + void i_add_br8(); + void i_add_wr16(); + void i_add_r8b(); + void i_add_r16w(); + void i_add_ald8(); + void i_add_axd16(); + void i_push_es(); + void i_pop_es(); + void i_or_br8(); + void i_or_r8b(); + void i_or_wr16(); + void i_or_r16w(); + void i_or_ald8(); + void i_or_axd16(); + void i_push_cs(); + void i_pre_nec(); + void i_pre_v25(); + void i_adc_br8(); + void i_adc_wr16(); + void i_adc_r8b(); + void i_adc_r16w(); + void i_adc_ald8(); + void i_adc_axd16(); + void i_push_ss(); + void i_pop_ss(); + void i_sbb_br8(); + void i_sbb_wr16(); + void i_sbb_r8b(); + void i_sbb_r16w(); + void i_sbb_ald8(); + void i_sbb_axd16(); + void i_push_ds(); + void i_pop_ds(); + void i_and_br8(); + void i_and_r8b(); + void i_and_wr16(); + void i_and_r16w(); + void i_and_ald8(); + void i_and_axd16(); + void i_es(); + void i_daa(); + void i_sub_br8(); + void i_sub_wr16(); + void i_sub_r8b(); + void i_sub_r16w(); + void i_sub_ald8(); + void i_sub_axd16(); + void i_cs(); + void i_das(); + void i_xor_br8(); + void i_xor_r8b(); + void i_xor_wr16(); + void i_xor_r16w(); + void i_xor_ald8(); + void i_xor_axd16(); + void i_ss(); + void i_aaa(); + void i_cmp_br8(); + void i_cmp_wr16(); + void i_cmp_r8b(); + void i_cmp_r16w(); + void i_cmp_ald8(); + void i_cmp_axd16(); + void i_ds(); + void i_aas(); + void i_inc_ax(); + void i_inc_cx(); + void i_inc_dx(); + void i_inc_bx(); + void i_inc_sp(); + void i_inc_bp(); + void i_inc_si(); + void i_inc_di(); + void i_dec_ax(); + void i_dec_cx(); + void i_dec_dx(); + void i_dec_bx(); + void i_dec_sp(); + void i_dec_bp(); + void i_dec_si(); + void i_dec_di(); + void i_push_ax(); + void i_push_cx(); + void i_push_dx(); + void i_push_bx(); + void i_push_sp(); + void i_push_bp(); + void i_push_si(); + void i_push_di(); + void i_pop_ax(); + void i_pop_cx(); + void i_pop_dx(); + void i_pop_bx(); + void i_pop_sp(); + void i_pop_bp(); + void i_pop_si(); + void i_pop_di(); + void i_pusha(); + void i_popa(); + void i_chkind(); + void i_repnc(); + void i_repc(); + void i_push_d16(); + void i_imul_d16(); + void i_push_d8(); + void i_imul_d8(); + void i_insb(); + void i_insw(); + void i_outsb(); + void i_outsw(); + void i_jo(); + void i_jno(); + void i_jc(); + void i_jnc(); + void i_jz(); + void i_jnz(); + void i_jce(); + void i_jnce(); + void i_js(); + void i_jns(); + void i_jp(); + void i_jnp(); + void i_jl(); + void i_jnl(); + void i_jle(); + void i_jnle(); + void i_80pre(); + void i_82pre(); + void i_81pre(); + void i_83pre(); + void i_test_br8(); + void i_test_wr16(); + void i_xchg_br8(); + void i_xchg_wr16(); + void i_mov_br8(); + void i_mov_r8b(); + void i_mov_wr16(); + void i_mov_r16w(); + void i_mov_wsreg(); + void i_lea(); + void i_mov_sregw(); + void i_invalid(); + void i_popw(); + void i_nop(); + void i_xchg_axcx(); + void i_xchg_axdx(); + void i_xchg_axbx(); + void i_xchg_axsp(); + void i_xchg_axbp(); + void i_xchg_axsi(); + void i_xchg_axdi(); + void i_cbw(); + void i_cwd(); + void i_call_far(); + void i_pushf(); + void i_popf(); + void i_sahf(); + void i_lahf(); + void i_mov_aldisp(); + void i_mov_axdisp(); + void i_mov_dispal(); + void i_mov_dispax(); + void i_movsb(); + void i_movsw(); + void i_cmpsb(); + void i_cmpsw(); + void i_test_ald8(); + void i_test_axd16(); + void i_stosb(); + void i_stosw(); + void i_lodsb(); + void i_lodsw(); + void i_scasb(); + void i_scasw(); + void i_mov_ald8(); + void i_mov_cld8(); + void i_mov_dld8(); + void i_mov_bld8(); + void i_mov_ahd8(); + void i_mov_chd8(); + void i_mov_dhd8(); + void i_mov_bhd8(); + void i_mov_axd16(); + void i_mov_cxd16(); + void i_mov_dxd16(); + void i_mov_bxd16(); + void i_mov_spd16(); + void i_mov_bpd16(); + void i_mov_sid16(); + void i_mov_did16(); + void i_rotshft_bd8(); + void i_rotshft_wd8(); + void i_ret_d16(); + void i_ret(); + void i_les_dw(); + void i_lds_dw(); + void i_mov_bd8(); + void i_mov_wd16(); + void i_enter(); + void i_leave(); + void i_retf_d16(); + void i_retf(); + void i_int3(); + void i_int(); + void i_into(); + void i_iret(); + void i_rotshft_b(); + void i_rotshft_w(); + void i_rotshft_bcl(); + void i_rotshft_wcl(); + void i_aam(); + void i_aad(); + void i_setalc(); + void i_trans(); + void i_fpo(); + void i_loopne(); + void i_loope(); + void i_loop(); + void i_jcxz(); + void i_inal(); + void i_inax(); + void i_outal(); + void i_outax(); + void i_call_d16(); + void i_jmp_d16(); + void i_jmp_far(); + void i_jmp_d8(); + void i_inaldx(); + void i_inaxdx(); + void i_outdxal(); + void i_outdxax(); + void i_lock(); + void i_repne(); + void i_repe(); + void i_hlt(); + void i_cmc(); + void i_f6pre(); + void i_f7pre(); + void i_clc(); + void i_stc(); + void i_di(); + void i_ei(); + void i_cld(); + void i_std(); + void i_fepre(); + void i_ffpre(); + void i_wait(); + void i_brkn(); + void i_brks(); + + UINT32 EA_000(); + UINT32 EA_001(); + UINT32 EA_002(); + UINT32 EA_003(); + UINT32 EA_004(); + UINT32 EA_005(); + UINT32 EA_006(); + UINT32 EA_007(); + UINT32 EA_100(); + UINT32 EA_101(); + UINT32 EA_102(); + UINT32 EA_103(); + UINT32 EA_104(); + UINT32 EA_105(); + UINT32 EA_106(); + UINT32 EA_107(); + UINT32 EA_200(); + UINT32 EA_201(); + UINT32 EA_202(); + UINT32 EA_203(); + UINT32 EA_204(); + UINT32 EA_205(); + UINT32 EA_206(); + UINT32 EA_207(); +}; + + +class v25_device : public v25_common_device +{ +public: + v25_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +class v35_device : public v25_common_device +{ +public: + v35_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +extern const device_type V25; +extern const device_type V35; + + +#endif diff --git a/src/devices/cpu/nec/v25instr.h b/src/devices/cpu/nec/v25instr.h new file mode 100644 index 00000000000..5d878f24f2b --- /dev/null +++ b/src/devices/cpu/nec/v25instr.h @@ -0,0 +1,261 @@ +// license:BSD-3-Clause +// copyright-holders:Bryan McPhail, Alex W. Jackson +const v25_common_device::nec_ophandler v25_common_device::s_nec_instruction[256] = +{ + &v25_common_device::i_add_br8, /* 0x00 */ + &v25_common_device::i_add_wr16, /* 0x01 */ + &v25_common_device::i_add_r8b, /* 0x02 */ + &v25_common_device::i_add_r16w, /* 0x03 */ + &v25_common_device::i_add_ald8, /* 0x04 */ + &v25_common_device::i_add_axd16, /* 0x05 */ + &v25_common_device::i_push_es, /* 0x06 */ + &v25_common_device::i_pop_es, /* 0x07 */ + &v25_common_device::i_or_br8, /* 0x08 */ + &v25_common_device::i_or_wr16, /* 0x09 */ + &v25_common_device::i_or_r8b, /* 0x0a */ + &v25_common_device::i_or_r16w, /* 0x0b */ + &v25_common_device::i_or_ald8, /* 0x0c */ + &v25_common_device::i_or_axd16, /* 0x0d */ + &v25_common_device::i_push_cs, /* 0x0e */ + &v25_common_device::i_pre_v25, /* 0x0f */ + &v25_common_device::i_adc_br8, /* 0x10 */ + &v25_common_device::i_adc_wr16, /* 0x11 */ + &v25_common_device::i_adc_r8b, /* 0x12 */ + &v25_common_device::i_adc_r16w, /* 0x13 */ + &v25_common_device::i_adc_ald8, /* 0x14 */ + &v25_common_device::i_adc_axd16, /* 0x15 */ + &v25_common_device::i_push_ss, /* 0x16 */ + &v25_common_device::i_pop_ss, /* 0x17 */ + &v25_common_device::i_sbb_br8, /* 0x18 */ + &v25_common_device::i_sbb_wr16, /* 0x19 */ + &v25_common_device::i_sbb_r8b, /* 0x1a */ + &v25_common_device::i_sbb_r16w, /* 0x1b */ + &v25_common_device::i_sbb_ald8, /* 0x1c */ + &v25_common_device::i_sbb_axd16, /* 0x1d */ + &v25_common_device::i_push_ds, /* 0x1e */ + &v25_common_device::i_pop_ds, /* 0x1f */ + &v25_common_device::i_and_br8, /* 0x20 */ + &v25_common_device::i_and_wr16, /* 0x21 */ + &v25_common_device::i_and_r8b, /* 0x22 */ + &v25_common_device::i_and_r16w, /* 0x23 */ + &v25_common_device::i_and_ald8, /* 0x24 */ + &v25_common_device::i_and_axd16, /* 0x25 */ + &v25_common_device::i_es, /* 0x26 */ + &v25_common_device::i_daa, /* 0x27 */ + &v25_common_device::i_sub_br8, /* 0x28 */ + &v25_common_device::i_sub_wr16, /* 0x29 */ + &v25_common_device::i_sub_r8b, /* 0x2a */ + &v25_common_device::i_sub_r16w, /* 0x2b */ + &v25_common_device::i_sub_ald8, /* 0x2c */ + &v25_common_device::i_sub_axd16, /* 0x2d */ + &v25_common_device::i_cs, /* 0x2e */ + &v25_common_device::i_das, /* 0x2f */ + &v25_common_device::i_xor_br8, /* 0x30 */ + &v25_common_device::i_xor_wr16, /* 0x31 */ + &v25_common_device::i_xor_r8b, /* 0x32 */ + &v25_common_device::i_xor_r16w, /* 0x33 */ + &v25_common_device::i_xor_ald8, /* 0x34 */ + &v25_common_device::i_xor_axd16, /* 0x35 */ + &v25_common_device::i_ss, /* 0x36 */ + &v25_common_device::i_aaa, /* 0x37 */ + &v25_common_device::i_cmp_br8, /* 0x38 */ + &v25_common_device::i_cmp_wr16, /* 0x39 */ + &v25_common_device::i_cmp_r8b, /* 0x3a */ + &v25_common_device::i_cmp_r16w, /* 0x3b */ + &v25_common_device::i_cmp_ald8, /* 0x3c */ + &v25_common_device::i_cmp_axd16, /* 0x3d */ + &v25_common_device::i_ds, /* 0x3e */ + &v25_common_device::i_aas, /* 0x3f */ + &v25_common_device::i_inc_ax, /* 0x40 */ + &v25_common_device::i_inc_cx, /* 0x41 */ + &v25_common_device::i_inc_dx, /* 0x42 */ + &v25_common_device::i_inc_bx, /* 0x43 */ + &v25_common_device::i_inc_sp, /* 0x44 */ + &v25_common_device::i_inc_bp, /* 0x45 */ + &v25_common_device::i_inc_si, /* 0x46 */ + &v25_common_device::i_inc_di, /* 0x47 */ + &v25_common_device::i_dec_ax, /* 0x48 */ + &v25_common_device::i_dec_cx, /* 0x49 */ + &v25_common_device::i_dec_dx, /* 0x4a */ + &v25_common_device::i_dec_bx, /* 0x4b */ + &v25_common_device::i_dec_sp, /* 0x4c */ + &v25_common_device::i_dec_bp, /* 0x4d */ + &v25_common_device::i_dec_si, /* 0x4e */ + &v25_common_device::i_dec_di, /* 0x4f */ + &v25_common_device::i_push_ax, /* 0x50 */ + &v25_common_device::i_push_cx, /* 0x51 */ + &v25_common_device::i_push_dx, /* 0x52 */ + &v25_common_device::i_push_bx, /* 0x53 */ + &v25_common_device::i_push_sp, /* 0x54 */ + &v25_common_device::i_push_bp, /* 0x55 */ + &v25_common_device::i_push_si, /* 0x56 */ + &v25_common_device::i_push_di, /* 0x57 */ + &v25_common_device::i_pop_ax, /* 0x58 */ + &v25_common_device::i_pop_cx, /* 0x59 */ + &v25_common_device::i_pop_dx, /* 0x5a */ + &v25_common_device::i_pop_bx, /* 0x5b */ + &v25_common_device::i_pop_sp, /* 0x5c */ + &v25_common_device::i_pop_bp, /* 0x5d */ + &v25_common_device::i_pop_si, /* 0x5e */ + &v25_common_device::i_pop_di, /* 0x5f */ + &v25_common_device::i_pusha, /* 0x60 */ + &v25_common_device::i_popa, /* 0x61 */ + &v25_common_device::i_chkind, /* 0x62 */ + &v25_common_device::i_brkn, /* 0x63 - V25S/V35S only */ + &v25_common_device::i_repnc, /* 0x64 */ + &v25_common_device::i_repc, /* 0x65 */ + &v25_common_device::i_invalid, /* 0x66 */ + &v25_common_device::i_invalid, /* 0x67 */ + &v25_common_device::i_push_d16, /* 0x68 */ + &v25_common_device::i_imul_d16, /* 0x69 */ + &v25_common_device::i_push_d8, /* 0x6a */ + &v25_common_device::i_imul_d8, /* 0x6b */ + &v25_common_device::i_insb, /* 0x6c */ + &v25_common_device::i_insw, /* 0x6d */ + &v25_common_device::i_outsb, /* 0x6e */ + &v25_common_device::i_outsw, /* 0x6f */ + &v25_common_device::i_jo, /* 0x70 */ + &v25_common_device::i_jno, /* 0x71 */ + &v25_common_device::i_jc, /* 0x72 */ + &v25_common_device::i_jnc, /* 0x73 */ + &v25_common_device::i_jz, /* 0x74 */ + &v25_common_device::i_jnz, /* 0x75 */ + &v25_common_device::i_jce, /* 0x76 */ + &v25_common_device::i_jnce, /* 0x77 */ + &v25_common_device::i_js, /* 0x78 */ + &v25_common_device::i_jns, /* 0x79 */ + &v25_common_device::i_jp, /* 0x7a */ + &v25_common_device::i_jnp, /* 0x7b */ + &v25_common_device::i_jl, /* 0x7c */ + &v25_common_device::i_jnl, /* 0x7d */ + &v25_common_device::i_jle, /* 0x7e */ + &v25_common_device::i_jnle, /* 0x7f */ + &v25_common_device::i_80pre, /* 0x80 */ + &v25_common_device::i_81pre, /* 0x81 */ + &v25_common_device::i_82pre, /* 0x82 */ + &v25_common_device::i_83pre, /* 0x83 */ + &v25_common_device::i_test_br8, /* 0x84 */ + &v25_common_device::i_test_wr16, /* 0x85 */ + &v25_common_device::i_xchg_br8, /* 0x86 */ + &v25_common_device::i_xchg_wr16, /* 0x87 */ + &v25_common_device::i_mov_br8, /* 0x88 */ + &v25_common_device::i_mov_wr16, /* 0x89 */ + &v25_common_device::i_mov_r8b, /* 0x8a */ + &v25_common_device::i_mov_r16w, /* 0x8b */ + &v25_common_device::i_mov_wsreg, /* 0x8c */ + &v25_common_device::i_lea, /* 0x8d */ + &v25_common_device::i_mov_sregw, /* 0x8e */ + &v25_common_device::i_popw, /* 0x8f */ + &v25_common_device::i_nop, /* 0x90 */ + &v25_common_device::i_xchg_axcx, /* 0x91 */ + &v25_common_device::i_xchg_axdx, /* 0x92 */ + &v25_common_device::i_xchg_axbx, /* 0x93 */ + &v25_common_device::i_xchg_axsp, /* 0x94 */ + &v25_common_device::i_xchg_axbp, /* 0x95 */ + &v25_common_device::i_xchg_axsi, /* 0x96 */ + &v25_common_device::i_xchg_axdi, /* 0x97 */ + &v25_common_device::i_cbw, /* 0x98 */ + &v25_common_device::i_cwd, /* 0x99 */ + &v25_common_device::i_call_far, /* 0x9a */ + &v25_common_device::i_wait, /* 0x9b */ + &v25_common_device::i_pushf, /* 0x9c */ + &v25_common_device::i_popf, /* 0x9d */ + &v25_common_device::i_sahf, /* 0x9e */ + &v25_common_device::i_lahf, /* 0x9f */ + &v25_common_device::i_mov_aldisp, /* 0xa0 */ + &v25_common_device::i_mov_axdisp, /* 0xa1 */ + &v25_common_device::i_mov_dispal, /* 0xa2 */ + &v25_common_device::i_mov_dispax, /* 0xa3 */ + &v25_common_device::i_movsb, /* 0xa4 */ + &v25_common_device::i_movsw, /* 0xa5 */ + &v25_common_device::i_cmpsb, /* 0xa6 */ + &v25_common_device::i_cmpsw, /* 0xa7 */ + &v25_common_device::i_test_ald8, /* 0xa8 */ + &v25_common_device::i_test_axd16, /* 0xa9 */ + &v25_common_device::i_stosb, /* 0xaa */ + &v25_common_device::i_stosw, /* 0xab */ + &v25_common_device::i_lodsb, /* 0xac */ + &v25_common_device::i_lodsw, /* 0xad */ + &v25_common_device::i_scasb, /* 0xae */ + &v25_common_device::i_scasw, /* 0xaf */ + &v25_common_device::i_mov_ald8, /* 0xb0 */ + &v25_common_device::i_mov_cld8, /* 0xb1 */ + &v25_common_device::i_mov_dld8, /* 0xb2 */ + &v25_common_device::i_mov_bld8, /* 0xb3 */ + &v25_common_device::i_mov_ahd8, /* 0xb4 */ + &v25_common_device::i_mov_chd8, /* 0xb5 */ + &v25_common_device::i_mov_dhd8, /* 0xb6 */ + &v25_common_device::i_mov_bhd8, /* 0xb7 */ + &v25_common_device::i_mov_axd16, /* 0xb8 */ + &v25_common_device::i_mov_cxd16, /* 0xb9 */ + &v25_common_device::i_mov_dxd16, /* 0xba */ + &v25_common_device::i_mov_bxd16, /* 0xbb */ + &v25_common_device::i_mov_spd16, /* 0xbc */ + &v25_common_device::i_mov_bpd16, /* 0xbd */ + &v25_common_device::i_mov_sid16, /* 0xbe */ + &v25_common_device::i_mov_did16, /* 0xbf */ + &v25_common_device::i_rotshft_bd8, /* 0xc0 */ + &v25_common_device::i_rotshft_wd8, /* 0xc1 */ + &v25_common_device::i_ret_d16, /* 0xc2 */ + &v25_common_device::i_ret, /* 0xc3 */ + &v25_common_device::i_les_dw, /* 0xc4 */ + &v25_common_device::i_lds_dw, /* 0xc5 */ + &v25_common_device::i_mov_bd8, /* 0xc6 */ + &v25_common_device::i_mov_wd16, /* 0xc7 */ + &v25_common_device::i_enter, /* 0xc8 */ + &v25_common_device::i_leave, /* 0xc9 */ + &v25_common_device::i_retf_d16, /* 0xca */ + &v25_common_device::i_retf, /* 0xcb */ + &v25_common_device::i_int3, /* 0xcc */ + &v25_common_device::i_int, /* 0xcd */ + &v25_common_device::i_into, /* 0xce */ + &v25_common_device::i_iret, /* 0xcf */ + &v25_common_device::i_rotshft_b, /* 0xd0 */ + &v25_common_device::i_rotshft_w, /* 0xd1 */ + &v25_common_device::i_rotshft_bcl, /* 0xd2 */ + &v25_common_device::i_rotshft_wcl, /* 0xd3 */ + &v25_common_device::i_aam, /* 0xd4 */ + &v25_common_device::i_aad, /* 0xd5 */ + &v25_common_device::i_setalc, /* 0xd6 */ + &v25_common_device::i_trans, /* 0xd7 */ + &v25_common_device::i_fpo, /* 0xd8 */ + &v25_common_device::i_fpo, /* 0xd9 */ + &v25_common_device::i_fpo, /* 0xda */ + &v25_common_device::i_fpo, /* 0xdb */ + &v25_common_device::i_fpo, /* 0xdc */ + &v25_common_device::i_fpo, /* 0xdd */ + &v25_common_device::i_fpo, /* 0xde */ + &v25_common_device::i_fpo, /* 0xdf */ + &v25_common_device::i_loopne, /* 0xe0 */ + &v25_common_device::i_loope, /* 0xe1 */ + &v25_common_device::i_loop, /* 0xe2 */ + &v25_common_device::i_jcxz, /* 0xe3 */ + &v25_common_device::i_inal, /* 0xe4 */ + &v25_common_device::i_inax, /* 0xe5 */ + &v25_common_device::i_outal, /* 0xe6 */ + &v25_common_device::i_outax, /* 0xe7 */ + &v25_common_device::i_call_d16, /* 0xe8 */ + &v25_common_device::i_jmp_d16, /* 0xe9 */ + &v25_common_device::i_jmp_far, /* 0xea */ + &v25_common_device::i_jmp_d8, /* 0xeb */ + &v25_common_device::i_inaldx, /* 0xec */ + &v25_common_device::i_inaxdx, /* 0xed */ + &v25_common_device::i_outdxal, /* 0xee */ + &v25_common_device::i_outdxax, /* 0xef */ + &v25_common_device::i_lock, /* 0xf0 */ + &v25_common_device::i_brks, /* 0xf1 */ + &v25_common_device::i_repne, /* 0xf2 */ + &v25_common_device::i_repe, /* 0xf3 */ + &v25_common_device::i_hlt, /* 0xf4 */ + &v25_common_device::i_cmc, /* 0xf5 */ + &v25_common_device::i_f6pre, /* 0xf6 */ + &v25_common_device::i_f7pre, /* 0xf7 */ + &v25_common_device::i_clc, /* 0xf8 */ + &v25_common_device::i_stc, /* 0xf9 */ + &v25_common_device::i_di, /* 0xfa */ + &v25_common_device::i_ei, /* 0xfb */ + &v25_common_device::i_cld, /* 0xfc */ + &v25_common_device::i_std, /* 0xfd */ + &v25_common_device::i_fepre, /* 0xfe */ + &v25_common_device::i_ffpre /* 0xff */ +}; diff --git a/src/devices/cpu/nec/v25instr.inc b/src/devices/cpu/nec/v25instr.inc new file mode 100644 index 00000000000..bd11b0626a8 --- /dev/null +++ b/src/devices/cpu/nec/v25instr.inc @@ -0,0 +1,84 @@ +// license:BSD-3-Clause +// copyright-holders:Bryan McPhail, Alex W. Jackson +#define GetRB \ + ModRM = FETCH(); \ + if (ModRM >= 0xc0) \ + tmp = Wreg(Mod_RM.RM.w[ModRM]) & 0x7; \ + else { \ + logerror("%06x: Invalid MODRM for register banking instruction\n",PC()); \ + tmp = 0; \ + } + +#define RETRBI \ + tmp = (Wreg(PSW_SAVE) & 0x7000) >> 12; \ + m_ip = Wreg(PC_SAVE); \ + ExpandFlags(Wreg(PSW_SAVE)); \ + SetRB(tmp); \ + CHANGE_PC + +#define TSKSW \ + Wreg(PSW_SAVE) = CompressFlags(); \ + Wreg(PC_SAVE) = m_ip; \ + SetRB(tmp); \ + m_ip = Wreg(PC_SAVE); \ + ExpandFlags(Wreg(PSW_SAVE)); \ + CHANGE_PC + +#define MOVSPA \ + tmp = (Wreg(PSW_SAVE) & 0x7000) >> 8; \ + Sreg(SS) = m_ram.w[tmp+SS]; \ + Wreg(SP) = m_ram.w[tmp+SP] + +#define MOVSPB \ + tmp <<= 4; \ + m_ram.w[tmp+SS] = Sreg(SS); \ + m_ram.w[tmp+SP] = Wreg(SP) + +#define FINT \ + for(tmp = 1; tmp < 0x100; tmp <<= 1) { \ + if(m_ISPR & tmp) { \ + m_ISPR &= ~tmp; \ + break; \ + } \ + } + +OP( 0x0f, i_pre_v25 ) { UINT32 ModRM, tmp, tmp2; + switch (FETCH()) { + case 0x10 : BITOP_BYTE; CLKS(3,3,4); tmp2 = Breg(CL) & 0x7; m_ZeroVal = (tmp & (1<>8)&0xf); tmp &= 0xff; PutbackRMByte(ModRM,tmp); CLKM(13,13,9,28,28,15); break; + case 0x2a : ModRM = FETCH(); tmp = GetRMByte(ModRM); tmp2 = (Breg(AL) & 0xf)<<4; Breg(AL) = (Breg(AL) & 0xf0) | (tmp&0xf); tmp = tmp2 | (tmp>>4); PutbackRMByte(ModRM,tmp); CLKM(17,17,13,32,32,19); break; + case 0x2d : GetRB; nec_bankswitch(tmp); CLK(15); break; + case 0x31 : ModRM = FETCH(); ModRM=0; logerror("%06x: Unimplemented bitfield INS\n",PC()); break; + case 0x33 : ModRM = FETCH(); ModRM=0; logerror("%06x: Unimplemented bitfield EXT\n",PC()); break; + case 0x91 : RETRBI; CLK(12); break; + case 0x92 : FINT; CLK(2); m_no_interrupt = 1; break; + case 0x94 : GetRB; TSKSW; CLK(20); break; + case 0x95 : GetRB; MOVSPB; CLK(11); break; + case 0x9e : logerror("%06x: STOP\n",PC()); m_icount=0; break; + default: logerror("%06x: Unknown V25 instruction\n",PC()); break; + } +} + +OP( 0x63, i_brkn ) { nec_interrupt(FETCH(), BRKN); CLKS(50,50,24); } +OP( 0xF1, i_brks ) { nec_interrupt(FETCH(), BRKS); CLKS(50,50,24); } diff --git a/src/devices/cpu/nec/v25priv.h b/src/devices/cpu/nec/v25priv.h new file mode 100644 index 00000000000..19e8fcb7171 --- /dev/null +++ b/src/devices/cpu/nec/v25priv.h @@ -0,0 +1,192 @@ +// license:BSD-3-Clause +// copyright-holders:Bryan McPhail, Alex W. Jackson +/* Cpu types, steps of 8 to help the cycle count calculation */ +#define V33_TYPE 0 +#define V30_TYPE 8 +#define V20_TYPE 16 + +#ifndef FALSE +#define FALSE 0 +#define TRUE 1 +#endif + +/* interrupt vectors */ +enum +{ + NEC_DIVIDE_VECTOR = 0, + NEC_TRAP_VECTOR = 1, + NEC_NMI_VECTOR = 2, + NEC_BRKV_VECTOR = 4, + NEC_CHKIND_VECTOR = 5, + NEC_IBRK_VECTOR = 19, + NEC_INTTU0_VECTOR = 28, + NEC_INTTU1_VECTOR = 29, + NEC_INTTU2_VECTOR = 30, + NEC_INTD0_VECTOR = 20, + NEC_INTD1_VECTOR = 21, + NEC_INTP0_VECTOR = 24, + NEC_INTP1_VECTOR = 25, + NEC_INTP2_VECTOR = 26, + NEC_INTSER0_VECTOR = 12, + NEC_INTSR0_VECTOR = 13, + NEC_INTST0_VECTOR = 14, + NEC_INTSER1_VECTOR = 16, + NEC_INTSR1_VECTOR = 17, + NEC_INTST1_VECTOR = 18, + NEC_INTTB_VECTOR = 31 +}; + +/* interrupt sources */ +enum INTSOURCES +{ + BRK = 0, + INT_IRQ = 1, + NMI_IRQ = 1 << 1, + INTTU0 = 1 << 2, + INTTU1 = 1 << 3, + INTTU2 = 1 << 4, + INTD0 = 1 << 5, + INTD1 = 1 << 6, + INTP0 = 1 << 7, + INTP1 = 1 << 8, + INTP2 = 1 << 9, + INTSER0 = 1 << 10, + INTSR0 = 1 << 11, + INTST0 = 1 << 12, + INTSER1 = 1 << 13, + INTSR1 = 1 << 14, + INTST1 = 1 << 15, + INTTB = 1 << 16, + BRKN = 1 << 17, + BRKS = 1 << 18 +}; + +enum { + VECTOR_PC = 0x02/2, + PSW_SAVE = 0x04/2, + PC_SAVE = 0x06/2 +}; + +enum SREGS { + DS1 = 0x0E/2, + PS = 0x0C/2, + SS = 0x0A/2, + DS0 = 0x08/2 +}; + +enum WREGS { + AW = 0x1E/2, + CW = 0x1C/2, + DW = 0x1A/2, + BW = 0x18/2, + SP = 0x16/2, + BP = 0x14/2, + IX = 0x12/2, + IY = 0x10/2 +}; + +enum BREGS { + AL = NATIVE_ENDIAN_VALUE_LE_BE(0x1E, 0x1F), + AH = NATIVE_ENDIAN_VALUE_LE_BE(0x1F, 0x1E), + CL = NATIVE_ENDIAN_VALUE_LE_BE(0x1C, 0x1D), + CH = NATIVE_ENDIAN_VALUE_LE_BE(0x1D, 0x1C), + DL = NATIVE_ENDIAN_VALUE_LE_BE(0x1A, 0x1B), + DH = NATIVE_ENDIAN_VALUE_LE_BE(0x1B, 0x1A), + BL = NATIVE_ENDIAN_VALUE_LE_BE(0x18, 0x19), + BH = NATIVE_ENDIAN_VALUE_LE_BE(0x19, 0x18) +}; + +#define SetRB(x) do { m_RBW = (x) << 4; m_RBB = (x) << 5; } while (0) + +#define Sreg(x) m_ram.w[m_RBW + (x)] +#define Wreg(x) m_ram.w[m_RBW + (x)] +#define Breg(x) m_ram.b[m_RBB + (x)] + +#define PC() ((Sreg(PS)<<4)+m_ip) + +#define CF (m_CarryVal!=0) +#define SF (m_SignVal<0) +#define ZF (m_ZeroVal==0) +#define PF parity_table[(BYTE)m_ParityVal] +#define AF (m_AuxVal!=0) +#define OF (m_OverVal!=0) +#define RB (m_RBW >> 4) + +/************************************************************************/ + +#define read_mem_byte(a) v25_read_byte((a)) +#define read_mem_word(a) v25_read_word((a)) +#define write_mem_byte(a,d) v25_write_byte((a),(d)) +#define write_mem_word(a,d) v25_write_word((a),(d)) + +#define read_port_byte(a) m_io->read_byte(a) +#define read_port_word(a) m_io->read_word_unaligned(a) +#define write_port_byte(a,d) m_io->write_byte((a),(d)) +#define write_port_word(a,d) m_io->write_word_unaligned((a),(d)) + +/************************************************************************/ + +#define CHANGE_PC do { EMPTY_PREFETCH(); } while (0) + +#define SegBase(Seg) (Sreg(Seg) << 4) + +#define DefaultBase(Seg) ((m_seg_prefix && (Seg==DS0 || Seg==SS)) ? m_prefix_base : Sreg(Seg) << 4) + +#define GetMemB(Seg,Off) (read_mem_byte(DefaultBase(Seg) + (Off))) +#define GetMemW(Seg,Off) (read_mem_word(DefaultBase(Seg) + (Off))) + +#define PutMemB(Seg,Off,x) { write_mem_byte(DefaultBase(Seg) + (Off), (x)); } +#define PutMemW(Seg,Off,x) { write_mem_word(DefaultBase(Seg) + (Off), (x)); } + +/* prefetch timing */ + +#define FETCH() fetch() +#define FETCHWORD() fetchword() +#define EMPTY_PREFETCH() m_prefetch_reset = 1 + + +#define PUSH(val) { Wreg(SP) -= 2; write_mem_word(((Sreg(SS)<<4)+Wreg(SP)), val); } +#define POP(var) { Wreg(SP) += 2; var = read_mem_word(((Sreg(SS)<<4) + ((Wreg(SP)-2) & 0xffff))); } + +#define GetModRM UINT32 ModRM=FETCH() + +/* Cycle count macros: + CLK - cycle count is the same on all processors + CLKS - cycle count differs between processors, list all counts + CLKW - cycle count for word read/write differs for odd/even source/destination address + CLKM - cycle count for reg/mem instructions + CLKR - cycle count for reg/mem instructions with different counts for odd/even addresses + + + Prefetch & buswait time is not emulated. + Extra cycles for PUSH'ing or POP'ing registers to odd addresses is not emulated. +*/ + +#define CLK(all) m_icount-=all +#define CLKS(v20,v30,v33) { const UINT32 ccount=(v20<<16)|(v30<<8)|v33; m_icount-=(ccount>>m_chip_type)&0x7f; } +#define CLKW(v20o,v30o,v33o,v20e,v30e,v33e,addr) { const UINT32 ocount=(v20o<<16)|(v30o<<8)|v33o, ecount=(v20e<<16)|(v30e<<8)|v33e; m_icount-=(addr&1)?((ocount>>m_chip_type)&0x7f):((ecount>>m_chip_type)&0x7f); } +#define CLKM(v20,v30,v33,v20m,v30m,v33m) { const UINT32 ccount=(v20<<16)|(v30<<8)|v33, mcount=(v20m<<16)|(v30m<<8)|v33m; m_icount-=( ModRM >=0xc0 )?((ccount>>m_chip_type)&0x7f):((mcount>>m_chip_type)&0x7f); } +#define CLKR(v20o,v30o,v33o,v20e,v30e,v33e,vall,addr) { const UINT32 ocount=(v20o<<16)|(v30o<<8)|v33o, ecount=(v20e<<16)|(v30e<<8)|v33e; if (ModRM >=0xc0) m_icount-=vall; else m_icount-=(addr&1)?((ocount>>m_chip_type)&0x7f):((ecount>>m_chip_type)&0x7f); } + +/************************************************************************/ +#define CompressFlags() (WORD)(CF | (m_IBRK << 1) | (PF << 2) | (m_F0 << 3) | (AF << 4) \ + | (m_F1 << 5) | (ZF << 6) | (SF << 7) | (m_TF << 8) | (m_IF << 9) \ + | (m_DF << 10) | (OF << 11) | (RB << 12) | (m_MF << 15)) + +#define ExpandFlags(f) \ +{ \ + m_CarryVal = (f) & 0x0001; \ + m_IBRK = ((f) & 0x0002) == 0x0002; \ + m_ParityVal = !((f) & 0x0004); \ + m_F0 = ((f) & 0x0008) == 0x0008; \ + m_AuxVal = (f) & 0x0010; \ + m_F1 = ((f) & 0x0020) == 0x0020; \ + m_ZeroVal = !((f) & 0x0040); \ + m_SignVal = (f) & 0x0080 ? -1 : 0; \ + m_TF = ((f) & 0x0100) == 0x0100; \ + m_IF = ((f) & 0x0200) == 0x0200; \ + m_DF = ((f) & 0x0400) == 0x0400; \ + m_OverVal = (f) & 0x0800; \ + /* RB only changes on BRKCS/RETRBI/TSKSW, so skip it */ \ + m_MF = ((f) & 0x8000) == 0x8000; \ +} diff --git a/src/devices/cpu/nec/v25sfr.c b/src/devices/cpu/nec/v25sfr.c new file mode 100644 index 00000000000..7e8afc8b39c --- /dev/null +++ b/src/devices/cpu/nec/v25sfr.c @@ -0,0 +1,403 @@ +// license:BSD-3-Clause +// copyright-holders:Bryan McPhail, Alex W. Jackson +/**************************************************************************** + + NEC V25/V35 special function registers and internal ram access + +****************************************************************************/ + +#include "emu.h" +#include "v25.h" +#include "v25priv.h" + +UINT8 v25_common_device::read_irqcontrol(int /*INTSOURCES*/ source, UINT8 priority) +{ + return (((m_pending_irq & source) ? 0x80 : 0x00) + | ((m_unmasked_irq & source) ? 0x00 : 0x40) + | ((m_bankswitch_irq & source) ? 0x10 : 0x00) + | priority); +} + +UINT8 v25_common_device::read_sfr(unsigned o) +{ + UINT8 ret; + + switch(o) + { + case 0x00: /* P0 */ + ret = m_io->read_byte(V25_PORT_P0); + break; + case 0x08: /* P1 */ + /* P1 is combined with the interrupt lines */ + ret = ((m_io->read_byte(V25_PORT_P1) & 0xF0) + | (m_nmi_state ? 0x00 : 0x01) + | (m_intp_state[0] ? 0x00 : 0x02) + | (m_intp_state[1] ? 0x00 : 0x04) + | (m_intp_state[2] ? 0x00 : 0x08)); + break; + case 0x10: /* P2 */ + ret = m_io->read_byte(V25_PORT_P2); + break; + case 0x38: /* PT */ + ret = m_io->read_byte(V25_PORT_PT); + break; + case 0x4C: /* EXIC0 */ + ret = read_irqcontrol(INTP0, m_priority_intp); + break; + case 0x4D: /* EXIC1 */ + ret = read_irqcontrol(INTP1, 7); + break; + case 0x4E: /* EXIC2 */ + ret = read_irqcontrol(INTP2, 7); + break; + case 0x9C: /* TMIC0 */ + ret = read_irqcontrol(INTTU0, m_priority_inttu); + break; + case 0x9D: /* TMIC1 */ + ret = read_irqcontrol(INTTU1, 7); + break; + case 0x9E: /* TMIC2 */ + ret = read_irqcontrol(INTTU2, 7); + break; + case 0xEA: /* FLAG */ + ret = ((m_F0 << 3) | (m_F1 << 5)); + break; + case 0xEB: /* PRC */ + ret = (m_RAMEN ? 0x40 : 0); + switch (m_TB) + { + case 10: + break; + case 13: + ret |= 0x04; + break; + case 16: + ret |= 0x08; + break; + case 20: + ret |= 0x0C; + break; + } + switch (m_PCK) + { + case 2: + break; + case 4: + ret |= 0x01; + break; + case 8: + ret |= 0x02; + break; + } + break; + case 0xEC: /* TBIC */ + ret = read_irqcontrol(INTTB, 7); + break; + case 0xEF: /* IRQS */ + ret = m_IRQS; + break; + case 0xFC: /* ISPR */ + ret = m_ISPR; + break; + case 0xFF: /* IDB */ + ret = (m_IDB >> 12); + break; + default: + logerror("%06x: Read from special function register %02x\n",PC(),o); + ret = 0; + } + return ret; +} + +UINT16 v25_common_device::read_sfr_word(unsigned o) +{ + UINT16 ret; + + switch(o) + { + case 0x80: /* TM0 */ + logerror("%06x: Warning: read back TM0\n",PC()); + ret = m_TM0; + break; + case 0x82: /* MD0 */ + logerror("%06x: Warning: read back MD0\n",PC()); + ret = m_MD0; + break; + case 0x88: /* TM1 */ + logerror("%06x: Warning: read back TM1\n",PC()); + ret = m_TM1; + break; + case 0x8A: /* MD1 */ + logerror("%06x: Warning: read back MD1\n",PC()); + ret = m_MD1; + break; + default: + ret = (read_sfr(o) | (read_sfr(o+1) << 8)); + } + return ret; +} + +void v25_common_device::write_irqcontrol(int /*INTSOURCES*/ source, UINT8 d) +{ + if(d & 0x80) + m_pending_irq |= source; + else + m_pending_irq &= ~source; + + if(d & 0x40) + m_unmasked_irq &= ~source; + else + m_unmasked_irq |= source; + + if(d & 0x20) + logerror("%06x: Warning: macro service function not implemented\n",PC()); + + if(d & 0x10) + m_bankswitch_irq |= source; + else + m_bankswitch_irq &= ~source; +} + +void v25_common_device::write_sfr(unsigned o, UINT8 d) +{ + int tmp; + attotime time; + + static const int timebases[4] = { 10, 13, 16, 20 }; + static const int clocks[4] = { 2, 4, 8, 0 }; + + switch(o) + { + case 0x00: /* P0 */ + m_io->write_byte(V25_PORT_P0, d); + break; + case 0x08: /* P1 */ + /* only the upper four bits of P1 can be used as output */ + m_io->write_byte(V25_PORT_P1, d & 0xF0); + break; + case 0x10: /* P2 */ + m_io->write_byte(V25_PORT_P2, d); + break; + case 0x4C: /* EXIC0 */ + write_irqcontrol(INTP0, d); + m_priority_intp = d & 0x7; + break; + case 0x4D: /* EXIC1 */ + write_irqcontrol(INTP1, d); + break; + case 0x4E: /* EXIC2 */ + write_irqcontrol(INTP2, d); + break; + case 0x90: /* TMC0 */ + m_TMC0 = d; + if(d & 1) /* oneshot mode */ + { + if(d & 0x80) + { + tmp = m_PCK * m_TM0 * ((d & 0x40) ? 128 : 12 ); + time = attotime::from_hz(unscaled_clock()) * tmp; + m_timers[0]->adjust(time, INTTU0); + } + else + m_timers[0]->adjust(attotime::never); + + if(d & 0x20) + { + tmp = m_PCK * m_MD0 * ((d & 0x10) ? 128 : 12 ); + time = attotime::from_hz(unscaled_clock()) * tmp; + m_timers[1]->adjust(time, INTTU1); + } + else + m_timers[1]->adjust(attotime::never); + } + else /* interval mode */ + { + if(d & 0x80) + { + tmp = m_PCK * m_MD0 * ((d & 0x40) ? 128 : 6 ); + time = attotime::from_hz(unscaled_clock()) * tmp; + m_timers[0]->adjust(time, INTTU0, time); + m_timers[1]->adjust(attotime::never); + m_TM0 = m_MD0; + } + else + { + m_timers[0]->adjust(attotime::never); + m_timers[1]->adjust(attotime::never); + } + } + break; + case 0x91: /* TMC1 */ + m_TMC1 = d & 0xC0; + if(d & 0x80) + { + tmp = m_PCK * m_MD1 * ((d & 0x40) ? 128 : 6 ); + time = attotime::from_hz(unscaled_clock()) * tmp; + m_timers[2]->adjust(time, INTTU2, time); + m_TM1 = m_MD1; + } + else + m_timers[2]->adjust(attotime::never); + break; + case 0x9C: /* TMIC0 */ + write_irqcontrol(INTTU0, d); + m_priority_inttu = d & 0x7; + break; + case 0x9D: /* TMIC1 */ + write_irqcontrol(INTTU1, d); + break; + case 0x9E: /* TMIC2 */ + write_irqcontrol(INTTU2, d); + break; + case 0xEA: /* FLAG */ + m_F0 = ((d & 0x08) == 0x08); + m_F1 = ((d & 0x20) == 0x20); + break; + case 0xEB: /* PRC */ + logerror("%06x: PRC set to %02x\n", PC(), d); + m_RAMEN = ((d & 0x40) == 0x40); + m_TB = timebases[(d & 0x0C) >> 2]; + m_PCK = clocks[d & 0x03]; + if (m_PCK == 0) + { + logerror(" Warning: invalid clock divider\n"); + m_PCK = 8; + } + tmp = m_PCK << m_TB; + time = attotime::from_hz(unscaled_clock()) * tmp; + m_timers[3]->adjust(time, INTTB, time); + notify_clock_changed(); /* make device_execute_interface pick up the new clocks_to_cycles() */ + logerror(" Internal RAM %sabled\n", (m_RAMEN ? "en" : "dis")); + logerror(" Time base set to 2^%d\n", m_TB); + logerror(" Clock divider set to %d\n", m_PCK); + break; + case 0xEC: /* TBIC */ + /* time base interrupt doesn't support macro service, bank switching or priority control */ + write_irqcontrol(INTTB, d & 0xC0); + break; + case 0xFF: /* IDB */ + m_IDB = (d << 12) | 0xE00; + logerror("%06x: IDB set to %02x\n",PC(),d); + break; + default: + logerror("%06x: Wrote %02x to special function register %02x\n",PC(),d,o); + } +} + +void v25_common_device::write_sfr_word(unsigned o, UINT16 d) +{ + switch(o) + { + case 0x80: /* TM0 */ + m_TM0 = d; + break; + case 0x82: /* MD0 */ + m_MD0 = d; + break; + case 0x88: /* TM1 */ + m_TM1 = d; + break; + case 0x8A: /* MD1 */ + m_MD1 = d; + break; + default: + write_sfr(o, d); + write_sfr(o+1, d >> 8); + } +} + +UINT8 v25_common_device::v25_read_byte(unsigned a) +{ + if((a & 0xFFE00) == m_IDB || a == 0xFFFFF) + { + unsigned o = a & 0x1FF; + + if(m_RAMEN && o < 0x100) + return m_ram.b[BYTE_XOR_LE(o)]; + + if(o >= 0x100) + return read_sfr(o-0x100); + } + + return m_program->read_byte(a); +} + +UINT16 v25_common_device::v25_read_word(unsigned a) +{ + if( a & 1 ) + return (v25_read_byte(a) | (v25_read_byte(a + 1) << 8)); + + if((a & 0xFFE00) == m_IDB) + { + unsigned o = a & 0x1FF; + + if(m_RAMEN && o < 0x100) + return m_ram.w[o/2]; + + if(o >= 0x100) + return read_sfr_word(o-0x100); + } + + if(a == 0xFFFFE) /* not sure about this - manual says FFFFC-FFFFE are "reserved" */ + return (m_program->read_byte(a) | (read_sfr(0xFF) << 8)); + + return m_program->read_word(a); +} + +void v25_common_device::v25_write_byte(unsigned a, UINT8 d) +{ + if((a & 0xFFE00) == m_IDB || a == 0xFFFFF) + { + unsigned o = a & 0x1FF; + + if(m_RAMEN && o < 0x100) + { + m_ram.b[BYTE_XOR_LE(o)] = d; + return; + } + + if(o >= 0x100) + { + write_sfr(o-0x100, d); + return; + } + } + + m_program->write_byte(a, d); +} + +void v25_common_device::v25_write_word(unsigned a, UINT16 d) +{ + if( a & 1 ) + { + v25_write_byte(a, d); + v25_write_byte(a + 1, d >> 8); + return; + } + + if((a & 0xFFE00) == m_IDB) + { + unsigned o = a & 0x1FF; + + if(m_RAMEN && o < 0x100) + { + m_ram.w[o/2] = d; + return; + } + + if(o >= 0x100) + { + write_sfr_word(o-0x100, d); + return; + } + } + + if(a == 0xFFFFE) /* not sure about this - manual says FFFFC-FFFFE are "reserved" */ + { + m_program->write_byte(a, d); + write_sfr(0xFF, d >> 8); + return; + } + + m_program->write_word(a, d); +} diff --git a/src/devices/cpu/nec/v53.c b/src/devices/cpu/nec/v53.c new file mode 100644 index 00000000000..43969a0a78c --- /dev/null +++ b/src/devices/cpu/nec/v53.c @@ -0,0 +1,578 @@ +// license:BSD-3-Clause +// copyright-holders:Bryan McPhail +/* V53 */ + +// V33 / V33A cores with onboard peripherals + +// Interrupt Controller is uPD71059 equivalent (a PIC8259 clone?) +// DMA Controller can operate in modes providing a subset of the uPD71071 or uPD71037 functionality (some modes unavailable / settings ignored) (uPD71071 mode is an extended 8237A, uPD71037 mode is plain 8237A) +// Serial Controller is based on the uPD71051 but with some changes (i8251 clone?) +// Timer Unit is functionally identical to uPD71054 (which in turn is said to be the same as a pit8253) + +#include "emu.h" +#include "v53.h" + + +const device_type V53 = &device_creator; +const device_type V53A =&device_creator; + +WRITE8_MEMBER(v53_base_device::BSEL_w) +{ + printf("v53: BSEL_w %02x\n", data); +} + +WRITE8_MEMBER(v53_base_device::BADR_w) +{ + printf("v53: BADR_w %02x\n", data); +} + +WRITE8_MEMBER(v53_base_device::BRC_w) +{ + printf("v53: BRC_w %02x\n", data); +} + +WRITE8_MEMBER(v53_base_device::WMB0_w) +{ + printf("v53: WMB0_w %02x\n", data); +} + +WRITE8_MEMBER(v53_base_device::WCY1_w) +{ + printf("v53: WCY1_w %02x\n", data); +} + +WRITE8_MEMBER(v53_base_device::WCY0_w) +{ + printf("v53: WCY0_w %02x\n", data); +} + +WRITE8_MEMBER(v53_base_device::WAC_w) +{ + printf("v53: WAC_w %02x\n", data); +} + +WRITE8_MEMBER(v53_base_device::TCKS_w) +{ + printf("v53: TCKS_w %02x\n", data); +} + +WRITE8_MEMBER(v53_base_device::SBCR_w) +{ + printf("v53: SBCR_w %02x\n", data); +} + +WRITE8_MEMBER(v53_base_device::REFC_w) +{ + printf("v53: REFC_w %02x\n", data); +} + +WRITE8_MEMBER(v53_base_device::WMB1_w) +{ + printf("v53: WMB1_w %02x\n", data); +} + +WRITE8_MEMBER(v53_base_device::WCY2_w) +{ + printf("v53: WCY2_w %02x\n", data); +} + +WRITE8_MEMBER(v53_base_device::WCY3_w) +{ + printf("v53: WCY3_w %02x\n", data); +} + +WRITE8_MEMBER(v53_base_device::WCY4_w) +{ + printf("v53: WCY4_w %02x\n", data); +} + +WRITE8_MEMBER(v53_base_device::SULA_w) +{ + printf("v53: SULA_w %02x\n", data); + m_SULA = data; + install_peripheral_io(); +} + +WRITE8_MEMBER(v53_base_device::TULA_w) +{ + printf("v53: TULA_w %02x\n", data); + m_TULA = data; + install_peripheral_io(); +} + +WRITE8_MEMBER(v53_base_device::IULA_w) +{ + printf("v53: IULA_w %02x\n", data); + m_IULA = data; + install_peripheral_io(); +} + +WRITE8_MEMBER(v53_base_device::DULA_w) +{ + printf("v53: DULA_w %02x\n", data); + m_DULA = data; + install_peripheral_io(); +} + +WRITE8_MEMBER(v53_base_device::OPHA_w) +{ + printf("v53: OPHA_w %02x\n", data); + m_OPHA = data; + install_peripheral_io(); +} + +WRITE8_MEMBER(v53_base_device::OPSEL_w) +{ + printf("v53: OPSEL_w %02x\n", data); + m_OPSEL = data; + install_peripheral_io(); +} + +WRITE8_MEMBER(v53_base_device::SCTL_w) +{ + // bit 7: unused + // bit 6: unused + // bit 5: unused + // bit 4: SCU input clock source + // bit 3: uPD71037 DMA mode - Carry A20 + // bit 2: uPD71037 DMA mode - Carry A16 + // bit 1: uPD71037 DMA mode enable (otherwise in uPD71071 mode) + // bit 0: Onboard pripheral I/O maps to 8-bit boundaries? (otherwise 16-bit) + + printf("v53: SCTL_w %02x\n", data); + m_SCTL = data; + install_peripheral_io(); +} +/* +m_WCY0 = 0x07; +m_WCY1 = 0x77; +m_WCY2 = 0x77; +m_WCY3 = 0x77; +m_WCY4 = 0x77; +m_WMB0 = 0x77; +m_WMB1 = 0x77; +m_WAC = 0x00; +m_TCKS = 0x00; +m_RFC = 0x80; +m_SBCR = 0x00; +m_BRC = 0x00; +// SCU +m_SMD = 0x4b; +m_SCM = 0x00; +m_SIMK = 0x03; +m_SST = 0x04; +// DMA +m_DCH = 0x01; +m_DMD = 0x00; +m_DCC = 0x0000; +m_DST = 0x00; +m_DMK = 0x0f; +*/ + +void v53_base_device::device_reset() +{ + nec_common_device::device_reset(); + + m_SCTL = 0x00; + m_OPSEL= 0x00; + + // peripheral addresses + m_SULA = 0x00; + m_TULA = 0x00; + m_IULA = 0x00; + m_DULA = 0x00; + m_OPHA = 0x00; + + m_simk = 0x03; +} + +void v53_base_device::device_start() +{ + nec_common_device::device_start(); + + m_txd_handler.resolve_safe(); + m_rts_handler.resolve_safe(); + m_dtr_handler.resolve_safe(); + m_rxrdy_handler.resolve_safe(); + m_txrdy_handler.resolve_safe(); + m_txempty_handler.resolve_safe(); + + m_out0_handler.resolve_safe(); + m_out1_handler.resolve_safe(); + m_out2_handler.resolve_safe(); + + m_out_hreq_cb.resolve_safe(); + m_out_eop_cb.resolve_safe(); + m_in_memr_cb.resolve_safe(0); + m_out_memw_cb.resolve_safe(); + m_in_ior_0_cb.resolve_safe(0); + m_in_ior_1_cb.resolve_safe(0); + m_in_ior_2_cb.resolve_safe(0); + m_in_ior_3_cb.resolve_safe(0); + m_out_iow_0_cb.resolve_safe(); + m_out_iow_1_cb.resolve_safe(); + m_out_iow_2_cb.resolve_safe(); + m_out_iow_3_cb.resolve_safe(); + m_out_dack_0_cb.resolve_safe(); + m_out_dack_1_cb.resolve_safe(); + m_out_dack_2_cb.resolve_safe(); + m_out_dack_3_cb.resolve_safe(); + + static_set_irq_acknowledge_callback(*this, device_irq_acknowledge_delegate(FUNC(pic8259_device::inta_cb), (pic8259_device*)m_v53icu)); +} + +void v53_base_device::install_peripheral_io() +{ + // unmap everything in I/O space up to the fixed position registers (we avoid overwriting them, it isn't a valid config) + space(AS_IO).unmap_readwrite(0x1000, 0xfeff); // todo, we need to have a way to NOT unmap things defined in the drivers, but instead have this act as an overlay mapping / unampping only!! + + // IOAG determines if the handlers used 8-bit or 16-bit access + // the hng64.c games first set everything up in 8-bit mode, then + // do the procedure again in 16-bit mode before using them?! + + int IOAG = m_SCTL & 1; + + if (m_OPSEL & 0x01) // DMA Unit available + { + UINT16 base = (m_OPHA << 8) | m_DULA; + base &= 0xfffe; + + if (m_SCTL & 0x02) // uPD71037 mode + { + if (IOAG) // 8-bit + { + } + else + { + } + } + else // uPD71071 mode + { + space(AS_IO).install_readwrite_handler(base+0x00, base+0x0f, read8_delegate(FUNC(upd71071_v53_device::read), (upd71071_v53_device*)m_v53dmau), write8_delegate(FUNC(upd71071_v53_device::write), (upd71071_v53_device*)m_v53dmau), 0xffff); + } + } + + if (m_OPSEL & 0x02) // Interupt Control Unit available + { + UINT16 base = (m_OPHA << 8) | m_IULA; + base &= 0xfffe; + + if (IOAG) // 8-bit + { + } + else + { + space(AS_IO).install_readwrite_handler(base+0x00, base+0x03, read8_delegate(FUNC(pic8259_device::read), (pic8259_device*)m_v53icu), write8_delegate(FUNC(pic8259_device::write), (pic8259_device*)m_v53icu), 0x00ff); + } + } + + if (m_OPSEL & 0x04) // Timer Control Unit available + { + UINT16 base = (m_OPHA << 8) | m_TULA; + //printf("installing TCU to %04x\n", base); + base &= 0xfffe; + + if (IOAG) // 8-bit + { + } + else + { + space(AS_IO).install_readwrite_handler(base+0x00, base+0x01, read8_delegate(FUNC(v53_base_device::tmu_tst0_r), this), write8_delegate(FUNC(v53_base_device::tmu_tct0_w), this), 0x00ff); + space(AS_IO).install_readwrite_handler(base+0x02, base+0x03, read8_delegate(FUNC(v53_base_device::tmu_tst1_r), this), write8_delegate(FUNC(v53_base_device::tmu_tct1_w), this), 0x00ff); + space(AS_IO).install_readwrite_handler(base+0x04, base+0x05, read8_delegate(FUNC(v53_base_device::tmu_tst2_r), this), write8_delegate(FUNC(v53_base_device::tmu_tct2_w), this), 0x00ff); + space(AS_IO).install_write_handler(base+0x06, base+0x07, write8_delegate(FUNC(v53_base_device::tmu_tmd_w), this), 0x00ff); + } + } + + if (m_OPSEL & 0x08) // Serial Control Unit available + { + UINT16 base = (m_OPHA << 8) | m_SULA; + base &= 0xfffe; + + if (IOAG) // 8-bit + { + } + else + { + space(AS_IO).install_readwrite_handler(base+0x00, base+0x01, read8_delegate(FUNC(v53_scu_device::data_r), (v53_scu_device*)m_v53scu), write8_delegate(FUNC(v53_scu_device::data_w), (v53_scu_device*)m_v53scu), 0x00ff); + space(AS_IO).install_readwrite_handler(base+0x02, base+0x03, read8_delegate(FUNC(v53_scu_device::status_r), (v53_scu_device*)m_v53scu), write8_delegate(FUNC(v53_scu_device::command_w), (v53_scu_device*)m_v53scu), 0x00ff); + space(AS_IO).install_write_handler(base+0x04, base+0x05, write8_delegate(FUNC(v53_scu_device::mode_w), (v53_scu_device*)m_v53scu), 0x00ff); + space(AS_IO).install_readwrite_handler(base+0x06, base+0x07, read8_delegate(FUNC(v53_base_device::scu_simk_r), this), write8_delegate(FUNC(v53_base_device::scu_simk_w), this), 0x00ff); + + } + } + +} + + + +/*** SCU ***/ + + +READ8_MEMBER(v53_base_device::scu_simk_r) +{ + printf("v53: scu_simk_r\n"); + return m_simk; +} + +WRITE8_MEMBER(v53_base_device::scu_simk_w) +{ + m_simk = data; + printf("v53: scu_simk_w %02x\n", data); +} + + + +/*** TCU ***/ + +WRITE8_MEMBER(v53_base_device::tmu_tct0_w) { m_v53tcu->write(space, 0, data); } +WRITE8_MEMBER(v53_base_device::tmu_tct1_w) { m_v53tcu->write(space, 1, data); } +WRITE8_MEMBER(v53_base_device::tmu_tct2_w) { m_v53tcu->write(space, 2, data); } +WRITE8_MEMBER(v53_base_device::tmu_tmd_w) { m_v53tcu->write(space, 3, data); } + + +READ8_MEMBER(v53_base_device::tmu_tst0_r) { return m_v53tcu->read(space, 0); } +READ8_MEMBER(v53_base_device::tmu_tst1_r) { return m_v53tcu->read(space, 1); } +READ8_MEMBER(v53_base_device::tmu_tst2_r) { return m_v53tcu->read(space, 2); } + + + + + +/*** DMA ***/ + +// could be wrong / nonexistent +WRITE_LINE_MEMBER(v53_base_device::dreq0_w) +{ + if (!(m_SCTL & 0x02)) + { + m_v53dmau->dreq0_w(state); + } + else + { + printf("v53: dreq0 not in 71071mode\n"); + } +} + +WRITE_LINE_MEMBER(v53_base_device::dreq1_w) +{ + if (!(m_SCTL & 0x02)) + { + m_v53dmau->dreq1_w(state); + } + else + { + printf("v53: dreq1 not in 71071mode\n"); + } +} + +WRITE_LINE_MEMBER(v53_base_device::dreq2_w) +{ + if (!(m_SCTL & 0x02)) + { + m_v53dmau->dreq2_w(state); + } + else + { + printf("v53: dreq2 not in 71071mode\n"); + } +} + +WRITE_LINE_MEMBER(v53_base_device::dreq3_w) +{ + if (!(m_SCTL & 0x02)) + { + m_v53dmau->dreq3_w(state); + } + else + { + printf("v53: dreq3 not in 71071mode\n"); + } +} + +WRITE_LINE_MEMBER(v53_base_device::hack_w) +{ + if (!(m_SCTL & 0x02)) + { + m_v53dmau->hack_w(state); + } + else + { + printf("v53: hack_w not in 71071mode\n"); + } +} + +/* General stuff */ + +static ADDRESS_MAP_START( v53_internal_port_map, AS_IO, 16, v53_base_device ) + AM_RANGE(0xffe0, 0xffe1) AM_WRITE8( BSEL_w, 0x00ff) // 0xffe0 // uPD71037 DMA mode bank selection register + AM_RANGE(0xffe0, 0xffe1) AM_WRITE8( BADR_w, 0xff00) // 0xffe1 // uPD71037 DMA mode bank register peripheral mapping (also uses OPHA) +// AM_RANGE(0xffe2, 0xffe3) // (reserved , 0x00ff) // 0xffe2 +// AM_RANGE(0xffe2, 0xffe3) // (reserved , 0xff00) // 0xffe3 +// AM_RANGE(0xffe4, 0xffe5) // (reserved , 0x00ff) // 0xffe4 +// AM_RANGE(0xffe4, 0xffe5) // (reserved , 0xff00) // 0xffe5 +// AM_RANGE(0xffe6, 0xffe7) // (reserved , 0x00ff) // 0xffe6 +// AM_RANGE(0xffe6, 0xffe7) // (reserved , 0xff00) // 0xffe7 +// AM_RANGE(0xffe8, 0xffe9) // (reserved , 0x00ff) // 0xffe8 + AM_RANGE(0xffe8, 0xffe9) AM_WRITE8( BRC_w , 0xff00) // 0xffe9 // baud rate counter (used for serial peripheral) + AM_RANGE(0xffea, 0xffeb) AM_WRITE8( WMB0_w, 0x00ff) // 0xffea // waitstate control + AM_RANGE(0xffea, 0xffeb) AM_WRITE8( WCY1_w, 0xff00) // 0xffeb // waitstate control + AM_RANGE(0xffec, 0xffed) AM_WRITE8( WCY0_w, 0x00ff) // 0xffec // waitstate control + AM_RANGE(0xffec, 0xffed) AM_WRITE8( WAC_w, 0xff00) // 0xffed // waitstate control +// AM_RANGE(0xffee, 0xffef) // (reserved , 0x00ff) // 0xffee +// AM_RANGE(0xffee, 0xffef) // (reserved , 0xff00) // 0xffef + AM_RANGE(0xfff0, 0xfff1) AM_WRITE8( TCKS_w, 0x00ff) // 0xfff0 // timer clocks + AM_RANGE(0xfff0, 0xfff1) AM_WRITE8( SBCR_w, 0xff00) // 0xfff1 // internal clock divider, halt behavior etc. + AM_RANGE(0xfff2, 0xfff3) AM_WRITE8( REFC_w, 0x00ff) // 0xfff2 // ram refresh control + AM_RANGE(0xfff2, 0xfff3) AM_WRITE8( WMB1_w, 0xff00) // 0xfff3 // waitstate control + AM_RANGE(0xfff4, 0xfff5) AM_WRITE8( WCY2_w, 0x00ff) // 0xfff4 // waitstate control + AM_RANGE(0xfff4, 0xfff5) AM_WRITE8( WCY3_w, 0xff00) // 0xfff5 // waitstate control + AM_RANGE(0xfff6, 0xfff7) AM_WRITE8( WCY4_w, 0x00ff) // 0xfff6 // waitstate control +// AM_RANGE(0xfff6, 0xfff7) // (reserved , 0xff00) // 0xfff7 + AM_RANGE(0xfff8, 0xfff9) AM_WRITE8( SULA_w, 0x00ff) // 0xfff8 // peripheral mapping + AM_RANGE(0xfff8, 0xfff9) AM_WRITE8( TULA_w, 0xff00) // 0xfff9 // peripheral mapping + AM_RANGE(0xfffa, 0xfffb) AM_WRITE8( IULA_w, 0x00ff) // 0xfffa // peripheral mapping + AM_RANGE(0xfffa, 0xfffb) AM_WRITE8( DULA_w, 0xff00) // 0xfffb // peripheral mapping + AM_RANGE(0xfffc, 0xfffd) AM_WRITE8( OPHA_w, 0x00ff) // 0xfffc // peripheral mapping (upper bits, common) + AM_RANGE(0xfffc, 0xfffd) AM_WRITE8( OPSEL_w, 0xff00) // 0xfffd // peripheral enabling + AM_RANGE(0xfffe, 0xffff) AM_WRITE8( SCTL_w, 0x00ff) // 0xfffe // peripheral configuration (& byte / word mapping) +// AM_RANGE(0xfffe, 0xffff) // (reserved , 0xff00) // 0xffff +ADDRESS_MAP_END + + + + +READ8_MEMBER(v53_base_device::get_pic_ack) +{ + return 0; +} + + + +// the external interface provides no external access to the usual IRQ line of the V33, everything goes through the interrupt controller +void v53_base_device::execute_set_input(int irqline, int state) +{ + switch (irqline) + { + case INPUT_LINE_IRQ0: m_v53icu->ir0_w(state); break; + case INPUT_LINE_IRQ1: m_v53icu->ir1_w(state); break; + case INPUT_LINE_IRQ2: m_v53icu->ir2_w(state); break; + case INPUT_LINE_IRQ3: m_v53icu->ir3_w(state); break; + case INPUT_LINE_IRQ4: m_v53icu->ir4_w(state); break; + case INPUT_LINE_IRQ5: m_v53icu->ir5_w(state); break; + case INPUT_LINE_IRQ6: m_v53icu->ir6_w(state); break; + case INPUT_LINE_IRQ7: m_v53icu->ir7_w(state); break; + + case INPUT_LINE_NMI: nec_common_device::execute_set_input(irqline, state); break; + case NEC_INPUT_LINE_POLL: nec_common_device::execute_set_input(irqline, state); break; + } +} + +// for hooking the interrupt controller output up to the core +WRITE_LINE_MEMBER(v53_base_device::internal_irq_w) +{ + nec_common_device::execute_set_input(0, state); +} + + +static MACHINE_CONFIG_FRAGMENT( v53 ) + + MCFG_DEVICE_ADD("pit", PIT8254, 0) // functionality identical to uPD71054 + MCFG_PIT8253_CLK0(16000000) // manual implicitly claims that these runs at same speed as the CPU + MCFG_PIT8253_CLK1(16000000) + MCFG_PIT8253_CLK2(16000000) + MCFG_PIT8253_OUT0_HANDLER(WRITELINE( v53_base_device, tcu_out0_trampoline_cb )) + MCFG_PIT8253_OUT1_HANDLER(WRITELINE( v53_base_device, tcu_out1_trampoline_cb )) + MCFG_PIT8253_OUT2_HANDLER(WRITELINE( v53_base_device, tcu_out2_trampoline_cb )) + + + MCFG_DEVICE_ADD("upd71071dma", V53_DMAU, 4000000) + MCFG_AM9517A_OUT_HREQ_CB(WRITELINE(v53_base_device, hreq_trampoline_cb)) + MCFG_AM9517A_OUT_EOP_CB(WRITELINE(v53_base_device, eop_trampoline_cb)) + MCFG_AM9517A_IN_MEMR_CB(READ8(v53_base_device, dma_memr_trampoline_r)) + MCFG_AM9517A_OUT_MEMW_CB(WRITE8(v53_base_device, dma_memw_trampoline_w)) + MCFG_AM9517A_IN_IOR_0_CB(READ8(v53_base_device, dma_io_0_trampoline_r)) + MCFG_AM9517A_IN_IOR_1_CB(READ8(v53_base_device, dma_io_1_trampoline_r)) + MCFG_AM9517A_IN_IOR_2_CB(READ8(v53_base_device, dma_io_2_trampoline_r)) + MCFG_AM9517A_IN_IOR_3_CB(READ8(v53_base_device, dma_io_3_trampoline_r)) + MCFG_AM9517A_OUT_IOW_0_CB(WRITE8(v53_base_device, dma_io_0_trampoline_w)) + MCFG_AM9517A_OUT_IOW_1_CB(WRITE8(v53_base_device, dma_io_1_trampoline_w)) + MCFG_AM9517A_OUT_IOW_2_CB(WRITE8(v53_base_device, dma_io_2_trampoline_w)) + MCFG_AM9517A_OUT_IOW_3_CB(WRITE8(v53_base_device, dma_io_3_trampoline_w)) + MCFG_AM9517A_OUT_DACK_0_CB(WRITELINE(v53_base_device, dma_dack0_trampoline_w)) + MCFG_AM9517A_OUT_DACK_1_CB(WRITELINE(v53_base_device, dma_dack1_trampoline_w)) + MCFG_AM9517A_OUT_DACK_2_CB(WRITELINE(v53_base_device, dma_dack2_trampoline_w)) + MCFG_AM9517A_OUT_DACK_3_CB(WRITELINE(v53_base_device, dma_dack3_trampoline_w)) + + + MCFG_PIC8259_ADD( "upd71059pic", WRITELINE(v53_base_device, internal_irq_w), VCC, READ8(v53_base_device,get_pic_ack)) + + + + MCFG_DEVICE_ADD("v53scu", V53_SCU, 0) + MCFG_I8251_TXD_HANDLER(WRITELINE(v53_base_device, scu_txd_trampoline_cb)) + MCFG_I8251_DTR_HANDLER(WRITELINE(v53_base_device, scu_dtr_trampoline_cb)) + MCFG_I8251_RTS_HANDLER(WRITELINE(v53_base_device, scu_rts_trampoline_cb)) + MCFG_I8251_RXRDY_HANDLER(WRITELINE(v53_base_device,scu_rxrdy_trampoline_cb)) + MCFG_I8251_TXRDY_HANDLER(WRITELINE(v53_base_device,scu_txrdy_trampoline_cb)) + MCFG_I8251_TXEMPTY_HANDLER(WRITELINE(v53_base_device, scu_txempty_trampoline_cb)) + MCFG_I8251_SYNDET_HANDLER(WRITELINE(v53_base_device, scu_syndet_trampoline_cb)) + +MACHINE_CONFIG_END + +machine_config_constructor v53_base_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( v53 ); +} + + +v53_base_device::v53_base_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, offs_t fetch_xor, UINT8 prefetch_size, UINT8 prefetch_cycles, UINT32 chip_type) + : nec_common_device(mconfig, type, name, tag, owner, clock, shortname, true, fetch_xor, prefetch_size, prefetch_cycles, chip_type), + m_io_space_config( "io", ENDIANNESS_LITTLE, 16, 16, 0, ADDRESS_MAP_NAME( v53_internal_port_map ) ), + m_v53tcu(*this, "pit"), + m_v53dmau(*this, "upd71071dma"), + m_v53icu(*this, "upd71059pic"), + m_v53scu(*this, "v53scu"), + // SCU + m_txd_handler(*this), + m_dtr_handler(*this), + m_rts_handler(*this), + m_rxrdy_handler(*this), + m_txrdy_handler(*this), + m_txempty_handler(*this), + m_syndet_handler(*this), + // TCU + m_out0_handler(*this), + m_out1_handler(*this), + m_out2_handler(*this), + // DMAU + m_out_hreq_cb(*this), + m_out_eop_cb(*this), + m_in_memr_cb(*this), + m_out_memw_cb(*this), + m_in_ior_0_cb(*this), + m_in_ior_1_cb(*this), + m_in_ior_2_cb(*this), + m_in_ior_3_cb(*this), + m_out_iow_0_cb(*this), + m_out_iow_1_cb(*this), + m_out_iow_2_cb(*this), + m_out_iow_3_cb(*this), + m_out_dack_0_cb(*this), + m_out_dack_1_cb(*this), + m_out_dack_2_cb(*this), + m_out_dack_3_cb(*this) +{ +} + + +v53_device::v53_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : v53_base_device(mconfig, V53, "V53", tag, owner, clock, "v53", BYTE_XOR_LE(0), 6, 1, V33_TYPE) +{ +} + + +v53a_device::v53a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : v53_base_device(mconfig, V53A, "V53A", tag, owner, clock, "v53a", BYTE_XOR_LE(0), 6, 1, V33_TYPE) +{ +} diff --git a/src/devices/cpu/nec/v53.h b/src/devices/cpu/nec/v53.h new file mode 100644 index 00000000000..796f620fd40 --- /dev/null +++ b/src/devices/cpu/nec/v53.h @@ -0,0 +1,309 @@ +// license:BSD-3-Clause +// copyright-holders:Bryan McPhail +/* V53 */ + +#include "nec.h" +#include "necpriv.h" + +#include "machine/pit8253.h" +#include "machine/am9517a.h" +#include "machine/pic8259.h" +#include "machine/i8251.h" + +// SCU + +#define MCFG_V53_SCU_TXD_HANDLER(_devcb) \ + devcb = &v53_base_device::set_txd_handler(*device, DEVCB_##_devcb); + +#define MCFG_V53_SCU_DTR_HANDLER(_devcb) \ + devcb = &v53_base_device::set_dtr_handler(*device, DEVCB_##_devcb); + +#define MCFG_V53_SCU_RTS_HANDLER(_devcb) \ + devcb = &v53_base_device::set_rts_handler(*device, DEVCB_##_devcb); + +#define MCFG_V53_SCU_RXRDY_HANDLER(_devcb) \ + devcb = &v53_base_device::set_rxrdy_handler(*device, DEVCB_##_devcb); + +#define MCFG_V53_SCU_TXRDY_HANDLER(_devcb) \ + devcb = &v53_base_device::set_txrdy_handler(*device, DEVCB_##_devcb); + +#define MCFG_V53_SCU_TXEMPTY_HANDLER(_devcb) \ + devcb = &v53_base_device::set_txempty_handler(*device, DEVCB_##_devcb); + +#define MCFG_V53_SCU_SYNDET_HANDLER(_devcb) \ + devcb = &v53_base_device::set_syndet_handler(*device, DEVCB_##_devcb); + +// TCU +#define MCFG_V53_TCU_CLK0(_clk) \ + v53_base_device::set_clk0(*device, _clk); + +#define MCFG_V53_TCU_CLK1(_clk) \ + v53_base_device::set_clk1(*device, _clk); + +#define MCFG_V53_TCU_CLK2(_clk) \ + v53_base_device::set_clk2(*device, _clk); + +#define MCFG_V53_TCU_OUT0_HANDLER(_devcb) \ + devcb = &v53_base_device::set_out0_handler(*device, DEVCB_##_devcb); + +#define MCFG_V53_TCU_OUT1_HANDLER(_devcb) \ + devcb = &v53_base_device::set_out1_handler(*device, DEVCB_##_devcb); + +#define MCFG_V53_TCU_OUT2_HANDLER(_devcb) \ + devcb = &v53_base_device::set_out2_handler(*device, DEVCB_##_devcb); + +// DMAU + +#define MCFG_V53_DMAU_OUT_HREQ_CB(_devcb) \ + devcb = &v53_base_device::set_out_hreq_callback(*device, DEVCB_##_devcb); + +#define MCFG_V53_DMAU_OUT_EOP_CB(_devcb) \ + devcb = &v53_base_device::set_out_eop_callback(*device, DEVCB_##_devcb); + +#define MCFG_V53_DMAU_IN_MEMR_CB(_devcb) \ + devcb = &v53_base_device::set_in_memr_callback(*device, DEVCB_##_devcb); + +#define MCFG_V53_DMAU_OUT_MEMW_CB(_devcb) \ + devcb = &v53_base_device::set_out_memw_callback(*device, DEVCB_##_devcb); + +#define MCFG_V53_DMAU_IN_IOR_0_CB(_devcb) \ + devcb = &v53_base_device::set_in_ior_0_callback(*device, DEVCB_##_devcb); + +#define MCFG_V53_DMAU_IN_IOR_1_CB(_devcb) \ + devcb = &v53_base_device::set_in_ior_1_callback(*device, DEVCB_##_devcb); + +#define MCFG_V53_DMAU_IN_IOR_2_CB(_devcb) \ + devcb = &v53_base_device::set_in_ior_2_callback(*device, DEVCB_##_devcb); + +#define MCFG_V53_DMAU_IN_IOR_3_CB(_devcb) \ + devcb = &v53_base_device::set_in_ior_3_callback(*device, DEVCB_##_devcb); + +#define MCFG_V53_DMAU_OUT_IOW_0_CB(_devcb) \ + devcb = &v53_base_device::set_out_iow_0_callback(*device, DEVCB_##_devcb); + +#define MCFG_V53_DMAU_OUT_IOW_1_CB(_devcb) \ + devcb = &v53_base_device::set_out_iow_1_callback(*device, DEVCB_##_devcb); + +#define MCFG_V53_DMAU_OUT_IOW_2_CB(_devcb) \ + devcb = &v53_base_device::set_out_iow_2_callback(*device, DEVCB_##_devcb); + +#define MCFG_V53_DMAU_OUT_IOW_3_CB(_devcb) \ + devcb = &v53_base_device::set_out_iow_3_callback(*device, DEVCB_##_devcb); + +#define MCFG_V53_DMAU_OUT_DACK_0_CB(_devcb) \ + devcb = &v53_base_device::set_out_dack_0_callback(*device, DEVCB_##_devcb); + +#define MCFG_V53_DMAU_OUT_DACK_1_CB(_devcb) \ + devcb = &v53_base_device::set_out_dack_1_callback(*device, DEVCB_##_devcb); + +#define MCFG_V53_DMAU_OUT_DACK_2_CB(_devcb) \ + devcb = &v53_base_device::set_out_dack_2_callback(*device, DEVCB_##_devcb); + +#define MCFG_V53_DMAU_OUT_DACK_3_CB(_devcb) \ + devcb = &v53_base_device::set_out_dack_3_callback(*device, DEVCB_##_devcb); + + + +class v53_base_device : public nec_common_device +{ +public: + v53_base_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, offs_t fetch_xor, UINT8 prefetch_size, UINT8 prefetch_cycles, UINT32 chip_type); + + DECLARE_WRITE8_MEMBER(BSEL_w); + DECLARE_WRITE8_MEMBER(BADR_w); + DECLARE_WRITE8_MEMBER(BRC_w); + DECLARE_WRITE8_MEMBER(WMB0_w); + DECLARE_WRITE8_MEMBER(WCY1_w); + DECLARE_WRITE8_MEMBER(WCY0_w); + DECLARE_WRITE8_MEMBER(WAC_w); + DECLARE_WRITE8_MEMBER(TCKS_w); + DECLARE_WRITE8_MEMBER(SBCR_w); + DECLARE_WRITE8_MEMBER(REFC_w); + DECLARE_WRITE8_MEMBER(WMB1_w); + DECLARE_WRITE8_MEMBER(WCY2_w); + DECLARE_WRITE8_MEMBER(WCY3_w); + DECLARE_WRITE8_MEMBER(WCY4_w); + DECLARE_WRITE8_MEMBER(SULA_w); + DECLARE_WRITE8_MEMBER(TULA_w); + DECLARE_WRITE8_MEMBER(IULA_w); + DECLARE_WRITE8_MEMBER(DULA_w); + DECLARE_WRITE8_MEMBER(OPHA_w); + DECLARE_WRITE8_MEMBER(OPSEL_w); + DECLARE_WRITE8_MEMBER(SCTL_w); + + UINT8 m_SCTL; + UINT8 m_OPSEL; + + UINT8 m_SULA; + UINT8 m_TULA; + UINT8 m_IULA; + UINT8 m_DULA; + UINT8 m_OPHA; + + // SCU + DECLARE_READ8_MEMBER(scu_simk_r); + DECLARE_WRITE8_MEMBER(scu_simk_w); + UINT8 m_simk; + template static devcb_base &set_txd_handler(device_t &device, _Object object) { return downcast(device).m_txd_handler.set_callback(object); } + template static devcb_base &set_dtr_handler(device_t &device, _Object object) { return downcast(device).m_dtr_handler.set_callback(object); } + template static devcb_base &set_rts_handler(device_t &device, _Object object) { return downcast(device).m_rts_handler.set_callback(object); } + template static devcb_base &set_rxrdy_handler(device_t &device, _Object object) { return downcast(device).m_rxrdy_handler.set_callback(object); } + template static devcb_base &set_txrdy_handler(device_t &device, _Object object) { return downcast(device).m_txrdy_handler.set_callback(object); } + template static devcb_base &set_txempty_handler(device_t &device, _Object object) { return downcast(device).m_txempty_handler.set_callback(object); } + template static devcb_base &set_syndet_handler(device_t &device, _Object object) { return downcast(device).m_syndet_handler.set_callback(object); } + DECLARE_WRITE_LINE_MEMBER(scu_txd_trampoline_cb) { m_txd_handler(state); } + DECLARE_WRITE_LINE_MEMBER(scu_dtr_trampoline_cb) { m_dtr_handler(state); } + DECLARE_WRITE_LINE_MEMBER(scu_rts_trampoline_cb) { m_rts_handler(state); } + DECLARE_WRITE_LINE_MEMBER(scu_rxrdy_trampoline_cb) { m_rxrdy_handler(state); } /* should we mask this here based on m_simk? it can mask the interrupt */ + DECLARE_WRITE_LINE_MEMBER(scu_txrdy_trampoline_cb) { m_txrdy_handler(state); } /* should we mask this here based on m_simk? it can mask the interrupt */ + DECLARE_WRITE_LINE_MEMBER(scu_txempty_trampoline_cb) { m_txempty_handler(state); } + DECLARE_WRITE_LINE_MEMBER(scu_syndet_trampoline_cb) { m_syndet_handler(state); } + + // TCU + DECLARE_READ8_MEMBER(tmu_tst0_r); + DECLARE_WRITE8_MEMBER(tmu_tct0_w); + DECLARE_READ8_MEMBER(tmu_tst1_r); + DECLARE_WRITE8_MEMBER(tmu_tct1_w); + DECLARE_READ8_MEMBER(tmu_tst2_r); + DECLARE_WRITE8_MEMBER(tmu_tct2_w); + DECLARE_WRITE8_MEMBER(tmu_tmd_w); +// static void set_clk0(device_t &device, double clk0) { downcast(device).m_clk0 = clk0; } +// static void set_clk1(device_t &device, double clk1) { downcast(device).m_clk1 = clk1; } +// static void set_clk2(device_t &device, double clk2) { downcast(device).m_clk2 = clk2; } + template static devcb_base &set_out0_handler(device_t &device, _Object object) { return downcast(device).m_out0_handler.set_callback(object); } + template static devcb_base &set_out1_handler(device_t &device, _Object object) { return downcast(device).m_out1_handler.set_callback(object); } + template static devcb_base &set_out2_handler(device_t &device, _Object object) { return downcast(device).m_out2_handler.set_callback(object); } + DECLARE_WRITE_LINE_MEMBER(tcu_out0_trampoline_cb){ m_out0_handler(state); } + DECLARE_WRITE_LINE_MEMBER(tcu_out1_trampoline_cb){ m_out1_handler(state); } + DECLARE_WRITE_LINE_MEMBER(tcu_out2_trampoline_cb){ m_out2_handler(state); } + + // DMAU + template static devcb_base &set_out_hreq_callback(device_t &device, _Object object) { return downcast(device).m_out_hreq_cb.set_callback(object); } + template static devcb_base &set_out_eop_callback(device_t &device, _Object object) { return downcast(device).m_out_eop_cb.set_callback(object); } + template static devcb_base &set_in_memr_callback(device_t &device, _Object object) { return downcast(device).m_in_memr_cb.set_callback(object); } + template static devcb_base &set_out_memw_callback(device_t &device, _Object object) { return downcast(device).m_out_memw_cb.set_callback(object); } + template static devcb_base &set_in_ior_0_callback(device_t &device, _Object object) { return downcast(device).m_in_ior_0_cb.set_callback(object); } + template static devcb_base &set_in_ior_1_callback(device_t &device, _Object object) { return downcast(device).m_in_ior_1_cb.set_callback(object); } + template static devcb_base &set_in_ior_2_callback(device_t &device, _Object object) { return downcast(device).m_in_ior_2_cb.set_callback(object); } + template static devcb_base &set_in_ior_3_callback(device_t &device, _Object object) { return downcast(device).m_in_ior_3_cb.set_callback(object); } + template static devcb_base &set_out_iow_0_callback(device_t &device, _Object object) { return downcast(device).m_out_iow_0_cb.set_callback(object); } + template static devcb_base &set_out_iow_1_callback(device_t &device, _Object object) { return downcast(device).m_out_iow_1_cb.set_callback(object); } + template static devcb_base &set_out_iow_2_callback(device_t &device, _Object object) { return downcast(device).m_out_iow_2_cb.set_callback(object); } + template static devcb_base &set_out_iow_3_callback(device_t &device, _Object object) { return downcast(device).m_out_iow_3_cb.set_callback(object); } + template static devcb_base &set_out_dack_0_callback(device_t &device, _Object object) { return downcast(device).m_out_dack_0_cb.set_callback(object); } + template static devcb_base &set_out_dack_1_callback(device_t &device, _Object object) { return downcast(device).m_out_dack_1_cb.set_callback(object); } + template static devcb_base &set_out_dack_2_callback(device_t &device, _Object object) { return downcast(device).m_out_dack_2_cb.set_callback(object); } + template static devcb_base &set_out_dack_3_callback(device_t &device, _Object object) { return downcast(device).m_out_dack_3_cb.set_callback(object); } + DECLARE_WRITE_LINE_MEMBER(hreq_trampoline_cb) { m_out_hreq_cb(state); } + DECLARE_WRITE_LINE_MEMBER(eop_trampoline_cb) { m_out_eop_cb(state); } + DECLARE_READ8_MEMBER(dma_memr_trampoline_r) { return m_in_memr_cb(space, offset); } + DECLARE_WRITE8_MEMBER(dma_memw_trampoline_w) { m_out_memw_cb(space, offset, data); } + DECLARE_READ8_MEMBER(dma_io_0_trampoline_r) { return m_in_ior_0_cb(space, offset); } + DECLARE_READ8_MEMBER(dma_io_1_trampoline_r) { return m_in_ior_1_cb(space, offset); } + DECLARE_READ8_MEMBER(dma_io_2_trampoline_r) { return m_in_ior_2_cb(space, offset); } + DECLARE_READ8_MEMBER(dma_io_3_trampoline_r) { return m_in_ior_3_cb(space, offset); } + DECLARE_WRITE8_MEMBER(dma_io_0_trampoline_w) { m_out_iow_0_cb(space, offset, data); } + DECLARE_WRITE8_MEMBER(dma_io_1_trampoline_w) { m_out_iow_1_cb(space, offset, data); } + DECLARE_WRITE8_MEMBER(dma_io_2_trampoline_w) { m_out_iow_2_cb(space, offset, data); } + DECLARE_WRITE8_MEMBER(dma_io_3_trampoline_w) { m_out_iow_3_cb(space, offset, data); } + DECLARE_WRITE_LINE_MEMBER(dma_dack0_trampoline_w) { m_out_dack_0_cb(state); } + DECLARE_WRITE_LINE_MEMBER(dma_dack1_trampoline_w) { m_out_dack_1_cb(state); } + DECLARE_WRITE_LINE_MEMBER(dma_dack2_trampoline_w) { m_out_dack_2_cb(state); } + DECLARE_WRITE_LINE_MEMBER(dma_dack3_trampoline_w) { m_out_dack_3_cb(state); } + + + DECLARE_WRITE_LINE_MEMBER(dreq0_w); + DECLARE_WRITE_LINE_MEMBER(dreq1_w); + DECLARE_WRITE_LINE_MEMBER(dreq2_w); + DECLARE_WRITE_LINE_MEMBER(dreq3_w); + DECLARE_WRITE_LINE_MEMBER(hack_w); + + + + void install_peripheral_io(); + + const address_space_config m_io_space_config; + + const address_space_config *memory_space_config(address_spacenum spacenum) const + { + switch (spacenum) + { + case AS_IO: return &m_io_space_config; + default: return nec_common_device::memory_space_config(spacenum); + } + } + + + + + DECLARE_READ8_MEMBER(get_pic_ack); + DECLARE_WRITE_LINE_MEMBER(internal_irq_w); + + +protected: + // device-level overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual void device_start(); + virtual void device_reset(); + virtual void execute_set_input(int inputnum, int state); + + required_device m_v53tcu; + required_device m_v53dmau; + required_device m_v53icu; + required_device m_v53scu; + + // SCU + devcb_write_line m_txd_handler; + devcb_write_line m_dtr_handler; + devcb_write_line m_rts_handler; + devcb_write_line m_rxrdy_handler; + devcb_write_line m_txrdy_handler; + devcb_write_line m_txempty_handler; + devcb_write_line m_syndet_handler; + + // TCU +// double m_clk0; +// double m_clk1; +// double m_clk2; + devcb_write_line m_out0_handler; + devcb_write_line m_out1_handler; + devcb_write_line m_out2_handler; + + + // DMAU + devcb_write_line m_out_hreq_cb; + devcb_write_line m_out_eop_cb; + devcb_read8 m_in_memr_cb; + devcb_write8 m_out_memw_cb; + devcb_read8 m_in_ior_0_cb; + devcb_read8 m_in_ior_1_cb; + devcb_read8 m_in_ior_2_cb; + devcb_read8 m_in_ior_3_cb; + devcb_write8 m_out_iow_0_cb; + devcb_write8 m_out_iow_1_cb; + devcb_write8 m_out_iow_2_cb; + devcb_write8 m_out_iow_3_cb; + devcb_write_line m_out_dack_0_cb; + devcb_write_line m_out_dack_1_cb; + devcb_write_line m_out_dack_2_cb; + devcb_write_line m_out_dack_3_cb; + + + +}; + + +class v53_device : public v53_base_device +{ +public: + v53_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class v53a_device : public v53_base_device +{ +public: + v53a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +extern const device_type V53; +extern const device_type V53A; diff --git a/src/devices/cpu/pdp1/pdp1.c b/src/devices/cpu/pdp1/pdp1.c new file mode 100644 index 00000000000..bb7beee4128 --- /dev/null +++ b/src/devices/cpu/pdp1/pdp1.c @@ -0,0 +1,1818 @@ +// license:BSD-3-Clause +// copyright-holders:Raphael Nabet +/* + * Note: Original Java source written by: + * + * Barry Silverman mailto:barry@disus.com or mailto:bss@media.mit.edu + * Vadim Gerasimov mailto:vadim@media.mit.edu + * + * MESS driver by Chris Salomon and Raphael Nabet. + * + * Basically, it has been rewritten entirely in order to perform cycle-level simulation + * (with only a few flip-flops being set one cycle too early or too late). I don't know if + * it is a good thing or a bad thing (it makes emulation more accurate, but slower, and + * code is more complex and less readable), but it appears to be the only way we could emulate + * mid-instruction sequence break. And it enables us to emulate the control panel fairly + * accurately. + * + * Additionnally, IOT functions have been modified to be external: IOT callback pointers are set + * at emulation initiation, and most IOT callback functions are part of the machine emulation. + * + * + * for the runnable java applet, with applet and Spacewar! source, go to: + * http://lcs.www.media.mit.edu/groups/el/projects/spacewar/ + * + * for a complete html version of the pdp1 handbook go to: + * http://www.dbit.com/~greeng3/pdp1/index.html + * + * there is another java simulator (by the same people) which runs the + * original pdp1 LISP interpreter, go to: + * http://lcs.www.media.mit.edu/groups/el/projects/pdp1 + * + * Another PDP1 emulator (or simulator) is at: + * ftp://minnie.cs.adfa.oz.au/pub/PDP-11/Sims/Supnik_2.3 + * It seems to emulate pdp1 I/O more accurately than we do. + * However, there is no CRT emulation. + * + * and finally, there is a nice article about SPACEWAR!, go to: + * http://ars-www.uchicago.edu/~eric/lore/spacewar/spacewar.html + * + * some extra documentation is available on spies: + * http://www.spies.com/~aek/pdf/dec/pdp1/ + * The file "F17_PDP1Maint.pdf" explains operation procedures and much of the internals of pdp-1. + * It was the main reference for this emulator. + * The file "F25_PDP1_IO.pdf" has interesting information on the I/O system, too. + * + * Following is an extract from the handbook: + * + * INTRODUCTION + * + * The Programmed Data Processor (PDP-1) is a high speed, solid state digital computer designed to + * operate with many types of input-output devices with no internal machine changes. It is a single + * address, single instruction, stored program computer with powerful program features. Five-megacycle + * circuits, a magnetic core memory and fully parallel processing make possible a computation rate of + * 100,000 additions per second. The PDP-1 is unusually versatile. It is easy to install, operate and + * maintain. Conventional 110-volt power is used, neither air conditioning nor floor reinforcement is + * necessary, and preventive maintenance is provided for by built-in marginal checking circuits. + * + * PDP-1 circuits are based on the designs of DEC's highly successful and reliable System Modules. + * Flip-flops and most switches use saturating transistors. Primary active elements are + * Micro-Alloy-Diffused transistors. + * + * The entire computer occupies only 17 square feet of floor space. It consists of four equipment frames, + * one of which is used as the operating station. + * + * CENTRAL PROCESSOR + * + * The Central Processor contains the control, arithmetic and memory addressing elements, and the memory + * buffer register. The word length is 18 binary digits. Instructions are performed in multiples of the + * memory cycle time of five microseconds. Add, subtract, deposit, and load, for example, are two-cycle + * instructions requiring 10 microseconds. Multiplication requires and average of 20 microseconds. + * Program features include: single address instructions, multiple step indirect addressing and logical + * arithmetic commands. Console features include: flip-flop indicators grouped for convenient octal + * reading, six program flags for automatic setting and computer sensing, and six sense switches for + * manual setting and computer sensing. + * + * MEMORY SYSTEM + * + * The coincident-current, magnetic core memory of a standard PDP-1 holds 4096 words of 18 bits each. + * Memory capacity may be readily expanded, in increments of 4096 words, to a maximum of 65,536 words. + * The read-rewrite time of the memory is five microseconds, the basic computer rate. Driving currents + * are automatically adjusted to compensate for temperature variations between 50 and 110 degrees + * Fahrenheit. The core memory storage may be supplemented by up to 24 magnetic tape transports. + * + * INPUT-OUTPUT + * + * PDP-1 is designed to operate a variety of buffered input-output devices. Standard equipment consistes + * of a perforated tape reader with a read speed of 400 lines per second, and alphanuermic typewriter for + * on-line operation in both input and output, and a perforated tape punch (alphanumeric or binary) with + * a speed of 63 lines per second. A variety of optional equipment is available, including the following: + * + * Precision CRT Display Type 30 + * Ultra-Precision CRT Display Type 31 + * Symbol Generator Type 33 + * Light Pen Type 32 + * Oscilloscope Display Type 34 + * Card Punch Control Type 40-1 + * Card Reader and Control Type 421 + * Magnetic Tape Transport Type 50 + * Programmed Magnetic Tape Control Type 51 + * Automatic Magnetic Tape Control Type 52 + * Automatic Magnetic Tape Control Type 510 + * Parallel Drum Type 23 + * Automatic Line Printer and Control Type 64 + * 18-bit Real Time Clock + * 18-bit Output Relay Buffer Type 140 + * Multiplexed A-D Converter Type 138/139 + * + * All in-out operations are performed through the In-Out Register or through the high speed input-output + * channels. + * + * The PDP-1 is also available with the optional Sequence Break System. This is a multi-channel priority + * interrupt feature which permits concurrent operation of several in-out devices. A one-channel Sequence + * Break System is included in the standard PDP-1. Optional Sequence Break Systems consist of 16, 32, 64, + * 128, and 256 channels. + * + * ... + * + * BASIC INSTRUCTIONS + * + * OPER. TIME + * INSTRUCTION CODE # EXPLANATION (usec) + * ------------------------------------------------------------------------------ + * add Y 40 Add C(Y) to C(AC) 10 + * and Y 02 Logical AND C(Y) with C(AC) 10 + * cal Y 16 Equals jda 100 10 + * dac Y 24 Deposit C(AC) in Y 10 + * dap Y 26 Deposit contents of address part of AC in Y 10 + * dio Y 32 Deposit C(IO) in Y 10 + * dip Y 30 Deposit contents of instruction part of AC in Y 10 + * div Y 56 Divide 40 max + * dzm Y 34 Deposit zero in Y 10 + * idx Y 44 Index (add one) C(Y), leave in Y & AC 10 + * ior Y 04 Inclusive OR C(Y) with C(AC) 10 + * iot Y 72 In-out transfer, see below + * isp Y 46 Index and skip if result is positive 10 + * jda Y 17 Equals dac Y and jsp Y+1 10 + * jmp Y 60 Take next instruction from Y 5 + * jsp Y 62 Jump to Y and save program counter in AC 5 + * lac Y 20 Load the AC with C(Y) 10 + * law N 70 Load the AC with the number N 5 + * law-N 71 Load the AC with the number -N 5 + * lio Y 22 Load IO with C(Y) 10 + * mul Y 54 Multiply 25 max + * opr 76 Operate, see below 5 + * sad Y 50 Skip next instruction if C(AC) <> C(Y) 10 + * sas Y 52 Skip next instruction if C(AC) = C(Y) 10 + * sft 66 Shift, see below 5 + * skp 64 Skip, see below 5 + * sub Y 42 Subtract C(Y) from C(AC) 10 + * xct Y 10 Execute instruction in Y 5+ + * xor Y 06 Exclusive OR C(Y) with C(AC) 10 + * + * OPERATE GROUP + * + * OPER. TIME + * INSTRUCTION CODE # EXPLANATION (usec) + * ------------------------------------------------------------------------------ + * cla 760200 Clear AC 5 + * clf 76000f Clear selected Program Flag (f = flag #) 5 + * cli 764000 Clear IO 5 + * cma 761000 Complement AC 5 + * hlt 760400 Halt 5 + * lap 760100 Load AC with Program Counter 5 + * lat 762200 Load AC from Test Word switches 5 + * nop 760000 No operation 5 + * stf 76001f Set selected Program Flag 5 + * + * IN-OUT TRANSFER GROUP + * + * PERFORATED TAPE READER + * + * INSTRUCTION CODE # EXPLANATION + * ------------------------------------------------------------------------------ + * rpa 720001 Read Perforated Tape Alphanumeric + * rpb 720002 Read Perforated Tape Binary + * rrb 720030 Read Reader Buffer + * + * PERFORATED TAPE PUNCH + * + * INSTRUCTION CODE # EXPLANATION + * ------------------------------------------------------------------------------ + * ppa 720005 Punch Perforated Tape Alphanumeric + * ppb 720006 Punch Perforated Tape Binary + * + * ALPHANUMERIC ON-LINE TYPEWRITER + * + * INSTRUCTION CODE # EXPLANATION + * ------------------------------------------------------------------------------ + * tyo 720003 Type Out + * tyi 720004 Type In + * + * SEQUENCE BREAK SYSTEM TYPE 120 + * + * INSTRUCTION CODE # EXPLANATION + * ------------------------------------------------------------------------------ + * esm 720055 Enter Sequence Break Mode + * lsm 720054 Leave Sequence Break Mode + * cbs 720056 Clear Sequence Break System + * dsc 72kn50 Deactivate Sequence Break Channel + * asc 72kn51 Activate Sequence Break Channel + * isb 72kn52 Initiate Sequence Break + * cac 720053 Clear All Channels + * + * HIGH SPEED DATA CONTROL TYPE 131 + * + * INSTRUCTION CODE # EXPLANATION + * ------------------------------------------------------------------------------ + * swc 72x046 Set Word Counter + * sia 720346 Set Location Counter + * sdf 720146 Stop Data Flow + * rlc 720366 Read Location Counter + * shr 720446 Set High Speed Channel Request + * + * PRECISION CRT DISPLAY TYPE 30 + * + * INSTRUCTION CODE # EXPLANATION + * ------------------------------------------------------------------------------ + * dpy 720007 Display One Point + * + * SYMBOL GENERATOR TYPE 33 + * + * INSTRUCTION CODE # EXPLANATION + * ------------------------------------------------------------------------------ + * gpl 722027 Generator Plot Left + * gpr 720027 Generator Plot Right + * glf 722026 Load Format + * gsp 720026 Space + * sdb 722007 Load Buffer, No Intensity + * + * ULTRA-PRECISION CRT DISPLAY TYPE 31 + * + * INSTRUCTION CODE # EXPLANATION + * ------------------------------------------------------------------------------ + * dpp 720407 Display One Point on Ultra Precision CRT + * + * CARD PUNCH CONTROL TYPE 40-1 + * + * INSTRUCTION CODE # EXPLANATION + * ------------------------------------------------------------------------------ + * lag 720044 Load a Group + * pac 720043 Punch a Card + * + * CARD READER TYPE 421 + * + * INSTRUCTION CODE # EXPLANATION + * ------------------------------------------------------------------------------ + * rac 720041 Read Card Alpha + * rbc 720042 Read Card Binary + * rcc 720032 Read Card Column + * + * PROGRAMMED MAGNETIC TAPE CONTROL TYPE 51 + * + * INSTRUCTION CODE # EXPLANATION + * ------------------------------------------------------------------------------ + * msm 720073 Select Mode + * mcs 720034 Check Status + * mcb 720070 Clear Buffer + * mwc 720071 Write a Character + * mrc 720072 Read Character + * + * AUTOMATIC MAGNETIC TAPE CONTROL TYPE 52 + * + * INSTRUCTION CODE # EXPLANATION + * ------------------------------------------------------------------------------ + * muf 72ue76 Tape Unit and FinalT + * mic 72ue75 Initial and Command + * mrf 72u067 Reset Final + * mri 72ug66 Reset Initial + * mes 72u035 Examine States + * mel 72u036 Examine Location + * inr 72ur67 Initiate a High Speed Channel Request + * ccr 72s067 Clear Command Register + * + * AUTOMATIC MAGNETIC TAPE CONTROL TYPE 510 + * + * INSTRUCTION CODE # EXPLANATION + * ------------------------------------------------------------------------------ + * sfc 720072 Skip if Tape Control Free + * rsr 720172 Read State Register + * crf 720272 Clear End-of-Record Flip-Flop + * cpm 720472 Clear Proceed Mode + * dur 72xx70 Load Density, Unit, Rewind + * mtf 73xx71 Load Tape Function Register + * cgo 720073 Clear Go + * + * MULTIPLEXED A-D CONVERTER TYPE 138/139 + * + * INSTRUCTION CODE # EXPLANATION + * ------------------------------------------------------------------------------ + * rcb 720031 Read Converter Buffer + * cad 720040 Convert a Voltage + * scv 72mm47 Select Multiplexer (1 of 64 Channels) + * icv 720060 Index Multiplexer + * + * AUTOMATIC LINE PRINTER TYPE 64 + * + * INSTRUCTION CODE # EXPLANATION + * ------------------------------------------------------------------------------ + * clrbuf 722045 Clear Buffer + * lpb 720045 Load Printer Buffer + * pas 721x45 Print and Space + * + * SKIP GROUP + * + * OPER. TIME + * INSTRUCTION CODE # EXPLANATION (usec) + * ------------------------------------------------------------------------------ + * sma 640400 Dkip on minus AC 5 + * spa 640200 Skip on plus AC 5 + * spi 642000 Skip on plus IO 5 + * sza 640100 Skip on ZERO (+0) AC 5 + * szf 6400f Skip on ZERO flag 5 + * szo 641000 Skip on ZERO overflow (and clear overflow) 5 + * szs 6400s0 Skip on ZERO sense switch 5 + * + * SHIFT/ROTATE GROUP + * + * OPER. TIME + * INSTRUCTION CODE # EXPLANATION (usec) + * ------------------------------------------------------------------------------ + * ral 661 Rotate AC left 5 + * rar 671 Rotate AC right 5 + * rcl 663 Rotate Combined AC & IO left 5 + * rcr 673 Rotate Combined AC & IO right 5 + * ril 662 Rotate IO left 5 + * rir 672 Rotate IO right 5 + * sal 665 Shift AC left 5 + * sar 675 Shift AC right 5 + * scl 667 Shift Combined AC & IO left 5 + * scr 677 Shift Combined AC & IO right 5 + * sil 666 Shift IO left 5 + * sir 676 Shift IO right 5 + */ + + +/* + TODO: + * support other extensions as time permits +*/ + + +#include "emu.h" +#include "debugger.h" +#include "pdp1.h" + +#define LOG 0 +#define LOG_EXTRA 0 +#define LOG_IOT_EXTRA 0 + +#define READ_PDP_18BIT(A) ((signed)m_program->read_dword((A)<<2)) +#define WRITE_PDP_18BIT(A,V) (m_program->write_dword((A)<<2,(V))) + + +#define PC m_pc +#define IR m_ir +#define MB m_mb +#define MA m_ma +#define AC m_ac +#define IO m_io +#define OV m_ov +#define EXD m_exd +/* note that we start counting flags/sense switches at 1, therefore n is in [1,6] */ +#define FLAGS m_pf +#define READFLAG(n) ((m_pf >> (6-(n))) & 1) +#define WRITEFLAG(n, data) (m_pf = (m_pf & ~(1 << (6-(n)))) | (((data) & 1) << (6-(n)))) +#define SENSE_SW m_ss +#define READSENSE(n) ((m_ss >> (6-(n))) & 1) +#define WRITESENSE(n, data) (m_ss = (m_ss & ~(1 << (6-(n)))) | (((data) & 1) << (6-(n)))) + +#define EXTENDED_ADDRESS_MASK m_extended_address_mask +#define ADDRESS_EXTENSION_MASK m_address_extension_mask +#define BASE_ADDRESS_MASK 0007777 + +#define INCREMENT_PC (PC = (PC & ADDRESS_EXTENSION_MASK) | ((PC+1) & BASE_ADDRESS_MASK)) +#define DECREMENT_PC (PC = (PC & ADDRESS_EXTENSION_MASK) | ((PC-1) & BASE_ADDRESS_MASK)) +#define INCREMENT_MA (MA = (MA & ADDRESS_EXTENSION_MASK) | ((MA+1) & BASE_ADDRESS_MASK)) +#define PREVIOUS_PC ((PC & ADDRESS_EXTENSION_MASK) | ((PC-1) & BASE_ADDRESS_MASK)) + + +const device_type PDP1 = &device_creator; + + +pdp1_device::pdp1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : cpu_device(mconfig, PDP1, "PDP1", tag, owner, clock, "pdp1_cpu", __FILE__) + , m_program_config("program", ENDIANNESS_BIG, 32, 18, 0) +{ + m_is_octal = true; +} + + +void pdp1_device::device_config_complete() +{ + // inherit a copy of the static data + const pdp1_reset_param_t *intf = reinterpret_cast(static_config()); + if (intf != NULL) + *static_cast(this) = *intf; + + // or initialize to defaults if none provided + else + { + memset(&read_binary_word, 0, sizeof(read_binary_word)); + memset(&io_sc_callback, 0, sizeof(io_sc_callback)); + extend_support = 0; + hw_mul_div = 0; + type_20_sbs = 0; + + for (int i = 0; i < 64; i++) + { + memset(&extern_iot[i], 0, sizeof(extern_iot[i])); + } + } +} + + +offs_t pdp1_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( pdp1 ); + return CPU_DISASSEMBLE_NAME(pdp1)(this, buffer, pc, oprom, opram, options); +} + + +/* + Interrupts are called "sequence break" in pdp1, but the general idea is the same. + + There are several interrupt lines. With the standard sequence break system, all lines + are logically or'ed to trigger a single interrupt level. Interrupts can be triggered + by either a pulse or a level on the interrupt lines. With the optional type 120 sequence + break system, each of 16 lines triggers is wired to a different priority level: additionnally, + each interrupt line can be masked out, and interrupt can be triggered through software. + + Also, instructions can be interrupted in the middle of execution. This is done by + decrementing the PC register: therefore the instruction is re-executed from start. + + Interrupt routines should not execute most IOT, as the interrupt may interrupt another. + + More details can be found in the handbook and the maintenance manual. +*/ +/* + This function MUST be called every time m_sbm, m_b4, m_irq_state or m_b2 change. +*/ +void pdp1_device::field_interrupt() +{ + /* current_irq: 1 bit for each active pending interrupt request + Pending interrupts are in b3 (simulated by (m_irq_state & m_b1) | m_b2)), but they + are only honored if no higher priority interrupt routine is in execution (one bit set in b4 + for each routine in execution). The relevant mask is created with (m_b4 | (- m_b4)), + as the carry chain (remember that -b4 = (~ b4) + 1) does precisely what we want. + b4: 0001001001000 + -b4: 1110110111000 + b4|-b4:1111111111000 + Neat, uh? + */ + int current_irq = ((m_irq_state & m_b1) | m_b2) & ~ (m_b4 | (- m_b4)); + int i; + + if (m_sbm && current_irq) + { + m_sbs_request = 1; + for (i=0; /*i<16 &&*/ (! ((current_irq >> i) & 1)); i++) + ; + m_sbs_level = i; + } + else + m_sbs_request = 0; +} + +void pdp1_device::execute_set_input(int irqline, int state) +{ + if (irqline == INPUT_LINE_NMI) + { + /* no specific NMI line */ + } + else if ((irqline >= 0) && (irqline < (m_type_20_sbs ? 1 : 16))) + { + unsigned int new_state = state ? 1 : 0; + + if (((m_irq_state >> irqline) & 1) != new_state) + { + m_irq_state = (m_irq_state & ~ (1 << irqline)) | (new_state << irqline); + + if ((new_state) && ((m_b1 >> irqline) & 1)) + m_b2 |= (new_state << irqline); + + /*m_b3 = m_irq_state | m_b2;*/ + + field_interrupt(); /* interrupt state has changed */ + } + } +} + + +static void null_iot(device_t *device, int op2, int nac, int mb, int *io, int ac) +{ + pdp1_device *pdp1 = dynamic_cast(device); + + pdp1->pdp1_null_iot(op2, nac, mb, io, ac); +} + +static void lem_eem_iot(device_t *device, int op2, int nac, int mb, int *io, int ac) +{ + pdp1_device *pdp1 = dynamic_cast(device); + + pdp1->pdp1_lem_eem_iot(op2, nac, mb, io, ac); +} + +static void sbs_iot(device_t *device, int op2, int nac, int mb, int *io, int ac) +{ + pdp1_device *pdp1 = dynamic_cast(device); + + pdp1->pdp1_sbs_iot(op2, nac, mb, io, ac); +} + +static void type_20_sbs_iot(device_t *device, int op2, int nac, int mb, int *io, int ac) +{ + pdp1_device *pdp1 = dynamic_cast(device); + + pdp1->pdp1_type_20_sbs_iot(op2, nac, mb, io, ac); +} + +void pdp1_device::device_start() +{ + int i; + + /* clean-up */ + m_pc = 0; + m_ir = 0; + m_mb = 0; + m_ma = 0; + m_ac = 0; + m_io = 0; + m_pf = 0; + m_ta = 0; + m_tw = 0; + m_ss = 0; + m_sngl_step = 0; + m_sngl_inst = 0; + m_extend_sw = 0; + m_run = 0; + m_cycle = 0; + m_defer = 0; + m_brk_ctr = 0; + m_ov = 0; + m_rim = 0; + m_sbm = 0; + m_exd = 0; + m_exc = 0; + m_ioc = 0; + m_ioh = 0; + m_ios = 0; + m_irq_state = 0; + m_b1 = 0; + m_b2 = 0; + m_b4 = 0; + m_rim_step = 0; + m_sbs_request = 0; + m_sbs_level = 0; + m_sbs_restore = 0; + m_no_sequence_break = 0; + m_debugger_temp = 0; + + m_program = &space(AS_PROGRAM); + + /* set up params and callbacks */ + for (i=0; i<64; i++) + { + m_extern_iot[i] = (extern_iot[i]) + ? extern_iot[i] + : null_iot; + } + m_read_binary_word = read_binary_word; + m_io_sc_callback = io_sc_callback; + m_extend_support = extend_support; + m_hw_mul_div = hw_mul_div; + m_type_20_sbs = type_20_sbs; + + switch (m_extend_support) + { + default: + m_extend_support = 0; + case 0: /* no extension */ + m_extended_address_mask = 07777; + m_address_extension_mask = 00000; + break; + case 1: /* 15-bit extension */ + m_extended_address_mask = 077777; + m_address_extension_mask = 070000; + break; + case 2: /* 16-bit extension */ + m_extended_address_mask = 0177777; + m_address_extension_mask = 0170000; + break; + } + + if (m_extend_support) + { + m_extern_iot[074] = lem_eem_iot; + } + m_extern_iot[054] = m_extern_iot[055] = m_extern_iot[056] = sbs_iot; + if (m_type_20_sbs) + { + m_extern_iot[050] = m_extern_iot[051] = m_extern_iot[052] = m_extern_iot[053] + = type_20_sbs_iot; + } + + state_add( PDP1_PC, "PC", m_pc).formatstr("%06O"); + state_add( PDP1_IR, "IR", m_ir).formatstr("%02O"); + state_add( PDP1_MB, "MB", m_mb).formatstr("%06O"); + state_add( PDP1_MA, "MA", m_ma).formatstr("%06O"); + state_add( PDP1_AC, "AC", m_ac).formatstr("%06O"); + state_add( PDP1_IO, "IO", m_io).formatstr("%06O"); + state_add( PDP1_OV, "OV", m_ov).formatstr("%1X"); + state_add( PDP1_PF, "FLAGS", m_pf).formatstr("%02O"); + state_add( PDP1_PF1, "FLAG1", m_debugger_temp).callimport().callexport().formatstr("%1X"); + state_add( PDP1_PF2, "FLAG2", m_debugger_temp).callimport().callexport().formatstr("%1X"); + state_add( PDP1_PF3, "FLAG3", m_debugger_temp).callimport().callexport().formatstr("%1X"); + state_add( PDP1_PF4, "FLAG4", m_debugger_temp).callimport().callexport().formatstr("%1X"); + state_add( PDP1_PF5, "FLAG5", m_debugger_temp).callimport().callexport().formatstr("%1X"); + state_add( PDP1_PF6, "FLAG6", m_debugger_temp).callimport().callexport().formatstr("%1X"); + state_add( PDP1_TA, "TA", m_ta).formatstr("%06O"); + state_add( PDP1_TW, "TW", m_tw).formatstr("%06O"); + state_add( PDP1_SS, "SS", m_ss).formatstr("%02O"); + state_add( PDP1_SS1, "SENSE1", m_debugger_temp).callimport().callexport().formatstr("%1X"); + state_add( PDP1_SS2, "SENSE2", m_debugger_temp).callimport().callexport().formatstr("%1X"); + state_add( PDP1_SS3, "SENSE3", m_debugger_temp).callimport().callexport().formatstr("%1X"); + state_add( PDP1_SS4, "SENSE4", m_debugger_temp).callimport().callexport().formatstr("%1X"); + state_add( PDP1_SS5, "SENSE5", m_debugger_temp).callimport().callexport().formatstr("%1X"); + state_add( PDP1_SS6, "SENSE6", m_debugger_temp).callimport().callexport().formatstr("%1X"); + state_add( PDP1_SNGL_STEP, "SNGLSTEP", m_sngl_step).mask(1).formatstr("%1X"); + state_add( PDP1_SNGL_INST, "SNGLINST", m_sngl_inst).mask(1).formatstr("%1X"); + state_add( PDP1_EXTEND_SW, "EXS", m_extend_sw).mask(1).formatstr("%1X"); + state_add( PDP1_RUN, "RUN", m_run).mask(1).formatstr("%1X"); + state_add( PDP1_CYC, "CYC", m_cycle).mask(1).formatstr("%1X"); + state_add( PDP1_DEFER, "DF", m_defer).mask(1).formatstr("%1X"); + state_add( PDP1_BRK_CTR, "BRKCTR", m_brk_ctr).mask(3).formatstr("%1X"); + state_add( PDP1_RIM, "RIM", m_rim).mask(1).formatstr("%1X"); + state_add( PDP1_SBM, "SBM", m_sbm).mask(1).formatstr("%1X"); + state_add( PDP1_EXD, "EXD", m_exd).mask(1).formatstr("%1X"); + state_add( PDP1_IOC, "IOC", m_ioc).mask(1).formatstr("%1X"); + state_add( PDP1_IOH, "IOH", m_ioh).mask(1).formatstr("%1X"); + state_add( PDP1_IOS, "IOS", m_ios).mask(1).formatstr("%1X"); + + state_add( STATE_GENPC, "GENPC", m_pc ).noshow(); + state_add( STATE_GENFLAGS, "GENFLAGS", m_pf ).formatstr("%13s").noshow(); + + m_icountptr = &m_icount; + + /* reset CPU flip-flops */ + pulse_start_clear(); +} + + +void pdp1_device::state_import(const device_state_entry &entry) +{ + switch (entry.index()) + { + case PDP1_PF1: + WRITEFLAG(1, m_debugger_temp ? 1 : 0); + break; + case PDP1_PF2: + WRITEFLAG(2, m_debugger_temp ? 1 : 0); + break; + case PDP1_PF3: + WRITEFLAG(3, m_debugger_temp ? 1 : 0); + break; + case PDP1_PF4: + WRITEFLAG(4, m_debugger_temp ? 1 : 0); + break; + case PDP1_PF5: + WRITEFLAG(5, m_debugger_temp ? 1 : 0); + break; + case PDP1_PF6: + WRITEFLAG(6, m_debugger_temp ? 1 : 0); + break; + case PDP1_SS1: + WRITESENSE(1, m_debugger_temp ? 1 : 0); + break; + case PDP1_SS2: + WRITESENSE(2, m_debugger_temp ? 1 : 0); + break; + case PDP1_SS3: + WRITESENSE(3, m_debugger_temp ? 1 : 0); + break; + case PDP1_SS4: + WRITESENSE(4, m_debugger_temp ? 1 : 0); + break; + case PDP1_SS5: + WRITESENSE(5, m_debugger_temp ? 1 : 0); + break; + case PDP1_SS6: + WRITESENSE(6, m_debugger_temp ? 1 : 0); + break; + } +} + + +void pdp1_device::state_export(const device_state_entry &entry) +{ + switch (entry.index()) + { + case PDP1_PF1: + m_debugger_temp = READFLAG(1); + break; + case PDP1_PF2: + m_debugger_temp = READFLAG(2); + break; + case PDP1_PF3: + m_debugger_temp = READFLAG(3); + break; + case PDP1_PF4: + m_debugger_temp = READFLAG(4); + break; + case PDP1_PF5: + m_debugger_temp = READFLAG(5); + break; + case PDP1_PF6: + m_debugger_temp = READFLAG(6); + break; + case PDP1_SS1: + m_debugger_temp = READSENSE(1); + break; + case PDP1_SS2: + m_debugger_temp = READSENSE(2); + break; + case PDP1_SS3: + m_debugger_temp = READSENSE(3); + break; + case PDP1_SS4: + m_debugger_temp = READSENSE(4); + break; + case PDP1_SS5: + m_debugger_temp = READSENSE(5); + break; + case PDP1_SS6: + m_debugger_temp = READSENSE(6); + break; + } +} + + +void pdp1_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + switch (entry.index()) + { + case STATE_GENFLAGS: + strprintf(str, "%c%c%c%c%c%c-%c%c%c%c%c%c", + (FLAGS & 040) ? '1' : '.', + (FLAGS & 020) ? '2' : '.', + (FLAGS & 010) ? '3' : '.', + (FLAGS & 004) ? '4' : '.', + (FLAGS & 002) ? '5' : '.', + (FLAGS & 001) ? '6' : '.', + (SENSE_SW & 040) ? '1' : '.', + (SENSE_SW & 020) ? '2' : '.', + (SENSE_SW & 010) ? '3' : '.', + (SENSE_SW & 004) ? '4' : '.', + (SENSE_SW & 002) ? '5' : '.', + (SENSE_SW & 001) ? '6' : '.'); + break; + } +} + + +void pdp1_device::device_reset() +{ + // Nothing to do?? +} + +/* + flags: + * 1 for each instruction which supports indirect addressing (memory reference instructions, + except cal and jda, and with the addition of jmp and jsp) + * 2 for memory reference instructions +*/ +static const UINT8 instruction_kind[32] = +{ +/* and ior xor xct cal/jda */ + 0, 3, 3, 3, 3, 0, 0, 2, +/* lac lio dac dap dip dio dzm */ + 3, 3, 3, 3, 3, 3, 3, 0, +/* add sub idx isp sad sas mus dis */ + 3, 3, 3, 3, 3, 3, 3, 3, +/* jmp jsp skp sft law iot opr */ + 1, 1, 0, 0, 0, 0, 0, 0 +}; + + +/* execute instructions on this CPU until icount expires */ +void pdp1_device::execute_run() +{ + do + { + debugger_instruction_hook(this, PC); + + + /* ioh should be cleared at the end of the instruction cycle, and ios at the + start of next instruction cycle, but who cares? */ + if (m_ioh && m_ios) + { + m_ioh = 0; + } + + + if ((! m_run) && (! m_rim)) + m_icount = 0; /* if processor is stopped, just burn cycles */ + else if (m_rim) + { + switch (m_rim_step) + { + case 0: + /* read first word as instruction */ + if (m_read_binary_word) + (*m_read_binary_word)(this); /* data will be transferred to IO register */ + m_rim_step = 1; + m_ios = 0; + break; + + case 1: + if (! m_ios) + { /* transfer incomplete: wait some more */ + m_icount = 0; + } + else + { /* data transfer complete */ + m_ios = 0; + + MB = IO; + IR = MB >> 13; /* basic opcode */ + if (IR == JMP) /* jmp instruction ? */ + { + PC = (MA & ADDRESS_EXTENSION_MASK) | (MB & BASE_ADDRESS_MASK); + m_rim = 0; /* exit read-in mode */ + m_run = 1; + m_rim_step = 0; + } + else if ((IR == DIO) || (IR == DAC)) /* dio or dac instruction ? */ + { /* there is a discrepancy: the pdp1 handbook tells that only dio should be used, + but the lisp tape uses the dac instruction instead */ + /* Yet maintenance manual p. 6-25 states clearly that the data is located + in IO and transfered to MB, so DAC is likely to be a mistake. */ + m_rim_step = 2; + } + else + { + /* what the heck? */ + if (LOG) + logerror("It seems this tape should not be operated in read-in mode\n"); + + m_rim = 0; /* exit read-in mode (right???) */ + m_rim_step = 0; + } + } + break; + + case 2: + /* read second word as data */ + if (m_read_binary_word) + (*m_read_binary_word)(this); /* data will be transferred to IO register */ + m_rim_step = 3; + m_ios = 0; + break; + + case 3: + if (! m_ios) + { /* transfer incomplete: wait some more */ + m_icount = 0; + } + else + { /* data transfer complete */ + m_ios = 0; + + MA = (PC & ADDRESS_EXTENSION_MASK) | (MB & BASE_ADDRESS_MASK); + + MB = IO; + WRITE_PDP_18BIT(MA, MB); + + m_rim_step = 0; + } + break; + } + } + else + { + /* yes, interrupt can occur in the midst of an instruction (impressing, huh?) */ + /* Note that break cannot occur during a one-cycle jump that is deferred only once, + or another break cycle. Also, it cannot interrupt the long cycle 1 of automatic + multiply/divide. (maintenance manual 6-19) */ + if (m_sbs_request && (! m_no_sequence_break) && (! m_brk_ctr)) + { /* begin sequence break */ + m_brk_ctr = 1; + } + if (m_brk_ctr) + { /* sequence break in progress */ + switch (m_brk_ctr) + { + case 1: + if (m_cycle) + DECREMENT_PC; /* set PC to point to aborted instruction, so that it can be re-run */ + + m_b4 |= (1 << m_sbs_level); /* set "interrupt in progress" flag */ + m_b2 &= ~(1 << m_sbs_level); /* clear interrupt request */ + field_interrupt(); + MA = m_sbs_level << 2; /* always 0 with standard sequence break system */ + MB = AC; /* save AC to MB */ + AC = (OV << 17) | (EXD << 16) | PC; /* save OV/EXD/PC to AC */ + EXD = OV = 0; /* according to maintenance manual p. 8-17 and ?-?? */ + m_cycle = m_defer = m_exc = 0; /* mere guess */ + WRITE_PDP_18BIT(MA, MB); /* save former AC to memory */ + INCREMENT_MA; + m_icount -= 5; + m_brk_ctr++; + break; + + case 2: + WRITE_PDP_18BIT(MA, MB = AC); /* save former OV/EXD/PC to memory */ + INCREMENT_MA; + m_icount -= 5; + m_brk_ctr++; + break; + + case 3: + WRITE_PDP_18BIT(MA, MB = IO); /* save IO to memory */ + INCREMENT_MA; + PC = MA; + m_icount -= 5; + m_brk_ctr = 0; + break; + } + } + else + { + if (m_no_sequence_break) + m_no_sequence_break = 0; + + if (! m_cycle) + { /* no instruction in progress: time to fetch a new instruction, I guess */ + MB = READ_PDP_18BIT(MA = PC); + INCREMENT_PC; + IR = MB >> 13; /* basic opcode */ + + if ((instruction_kind[IR] & 1) && (MB & 010000)) + { + m_defer = 1; + m_cycle = 1; /* instruction shall be executed later */ + + /* detect deferred one-cycle jumps */ + if ((IR == JMP) || (IR == JSP)) + { + m_no_sequence_break = 1; + /* detect JMP *(4*n+1) to memory module 0 if in sequence break mode */ + if (((MB & 0777703) == 0610001) && (m_sbm) && ! (MA & 0170000)) + { + int level = (MB & 0000074) >> 2; + + if ((m_type_20_sbs) || (level == 0)) + { + m_b4 &= ~(1 << level); + field_interrupt(); + if (m_extend_support) + EXD = 1; /* according to maintenance manual p. 6-33 */ + m_sbs_restore = 1; + } + } + } + } + else if (instruction_kind[IR] & 2) + m_cycle = 1; /* instruction shall be executed later */ + else + execute_instruction(); /* execute instruction at once */ + + m_icount -= 5; + } + else if (m_defer) + { /* defer cycle : handle indirect addressing */ + MA = (PC & ADDRESS_EXTENSION_MASK) | (MB & BASE_ADDRESS_MASK); + + MB = READ_PDP_18BIT(MA); + + /* determinate new value of m_defer */ + if (EXD) + { + m_defer = 0; + m_exc = 1; + } + else + m_defer = (MB & 010000) ? 1 : 0; + + /* execute JMP and JSP immediately if applicable */ + if ((! m_defer) && (! (instruction_kind[IR] & 2))) + { + execute_instruction(); /* execute instruction at once */ + /*m_cycle = 0;*/ + m_exc = 0; + + if (m_sbs_restore) + { /* interrupt return: according to maintenance manual p. 6-33 */ + if (m_extend_support) + EXD = (MB >> 16) & 1; + OV = (MB >> 17) & 1; + m_sbs_restore = 0; + } + } + + m_icount -= 5; + } + else + { /* memory reference instruction in cycle 1 */ + if (m_exc) + { + MA = MB & EXTENDED_ADDRESS_MASK; + m_exc = 0; + } + else + MA = (PC & ADDRESS_EXTENSION_MASK) | (MB & BASE_ADDRESS_MASK); + + execute_instruction(); /* execute instruction */ + + m_icount -= 5; + } + + if ((m_sngl_inst) && (! m_cycle)) + m_run = 0; + } + if (m_sngl_step) + m_run = 0; + } + } + while (m_icount > 0); +} + + +/* execute one instruction */ +void pdp1_device::execute_instruction() +{ + switch (IR) + { + case AND: /* Logical And */ + AC &= (MB = READ_PDP_18BIT(MA)); + break; + case IOR: /* Inclusive Or */ + AC |= (MB = READ_PDP_18BIT(MA)); + break; + case XOR: /* Exclusive Or */ + AC ^= (MB = READ_PDP_18BIT(MA)); + break; + case XCT: /* Execute */ + MB = READ_PDP_18BIT(MA); + IR = MB >> 13; /* basic opcode */ + if ((instruction_kind[IR] & 1) && (MB & 010000)) + { + m_defer = 1; + /*m_cycle = 1;*/ /* instruction shall be executed later */ + goto no_fetch; /* fall through to next instruction */ + } + else if (instruction_kind[IR] & 2) + { + /*m_cycle = 1;*/ /* instruction shall be executed later */ + goto no_fetch; /* fall through to next instruction */ + } + else + execute_instruction(); /* execute instruction at once */ + break; + case CALJDA: /* Call subroutine and Jump and Deposit Accumulator instructions */ + if (MB & 010000) + /* JDA */ + MA = (PC & ADDRESS_EXTENSION_MASK) | (MB & BASE_ADDRESS_MASK); + else + /* CAL: equivalent to JDA 100 */ + /* Note that I cannot tell for sure what happens to extension bits, but I did notice + that setting the extension bits to 0 would make cal basically useless, since + there would be no simple way the call routine could return to the callee + if it were located in another module with extend mode off (i.e. exd == 0). */ + MA = (PC & ADDRESS_EXTENSION_MASK) | 0100; + + WRITE_PDP_18BIT(MA, (MB = AC)); + INCREMENT_MA; + AC = (OV << 17) | (EXD << 16) | PC; + PC = MA; + break; + case LAC: /* Load Accumulator */ + AC = (MB = READ_PDP_18BIT(MA)); + break; + case LIO: /* Load i/o register */ + IO = (MB = READ_PDP_18BIT(MA)); + break; + case DAC: /* Deposit Accumulator */ + WRITE_PDP_18BIT(MA, (MB = AC)); + break; + case DAP: /* Deposit Address Part */ + WRITE_PDP_18BIT(MA, (MB = ((READ_PDP_18BIT(MA) & 0770000) | (AC & 0007777)))); + break; + case DIP: /* Deposit Instruction Part */ + WRITE_PDP_18BIT(MA, (MB = ((READ_PDP_18BIT(MA) & 0007777) | (AC & 0770000)))); + break; + case DIO: /* Deposit I/O Register */ + WRITE_PDP_18BIT(MA, (MB = IO)); + break; + case DZM: /* Deposit Zero in Memory */ + WRITE_PDP_18BIT(MA, (MB = 0)); + break; + case ADD: /* Add */ + { + /* overflow is set if the 2 operands have the same sign and the final result has another */ + int ov2; /* 1 if the operands have the same sign*/ + + MB = READ_PDP_18BIT(MA); + + ov2 = ((AC & 0400000) == (MB & 0400000)); + + AC = AC + MB; + AC = (AC + (AC >> 18)) & 0777777; /* propagate carry around */ + + /* I think we need to check for overflow before checking for -0, + because the sum -0+-0 = -0 = +0 would generate an overflow + otherwise. */ + if (ov2 && ((AC & 0400000) != (MB & 0400000))) + OV = 1; + + if (AC == 0777777) /* check for -0 */ + AC = 0; + + break; + } + case SUB: /* Subtract */ + { /* maintenance manual 7-14 seems to imply that substract does not test for -0. + The sim 2.3 source says so explicitely, though they do not give a reference. + It sounds a bit weird, but the reason is probably that doing so would + require additionnal logic that does not exist. */ + /* overflow is set if the 2 operands have the same sign and the final result has another */ + int ov2; /* 1 if the operands have the same sign*/ + + AC ^= 0777777; + + MB = READ_PDP_18BIT(MA); + + ov2 = ((AC & 0400000) == (MB & 0400000)); + + AC = AC + MB; + AC = (AC + (AC >> 18)) & 0777777; /* propagate carry around */ + + if (ov2 && ((AC & 0400000) != (MB & 0400000))) + OV = 1; + + AC ^= 0777777; + + break; + } + case IDX: /* Index */ + AC = READ_PDP_18BIT(MA) + 1; + + #if 0 + AC = (AC + (AC >> 18)) & 0777777; /* propagate carry around */ + if (AC == 0777777) /* check for -0 */ + AC = 0; + #else + if (AC >= 0777777) + AC = (AC + 1) & 0777777; + #endif + + WRITE_PDP_18BIT(MA, (MB = AC)); + break; + case ISP: /* Index and Skip if Positive */ + AC = READ_PDP_18BIT(MA) + 1; + + #if 0 + AC = (AC + (AC >> 18)) & 0777777; /* propagate carry around */ + if (AC == 0777777) /* check for -0 */ + AC = 0; + #else + if (AC >= 0777777) + AC = (AC + 1) & 0777777; + #endif + + WRITE_PDP_18BIT(MA, (MB = AC)); + if ((AC & 0400000) == 0) + INCREMENT_PC; + break; + case SAD: /* Skip if Accumulator and Y differ */ + if (AC != (MB = READ_PDP_18BIT(MA))) + INCREMENT_PC; + break; + case SAS: /* Skip if Accumulator and Y are the same */ + if (AC == (MB = READ_PDP_18BIT(MA))) + INCREMENT_PC; + break; + case MUS_MUL: /* Multiply Step or Multiply */ + if (m_hw_mul_div) + { /* MUL */ + int scr; + int smb, srm; + double etime = 4.; /* approximative */ + + IO = MB = AC; + MB = READ_PDP_18BIT(MA); + scr = 0; + if (MB & 0400000) + { + smb = 1; + MB = MB ^ 0777777; + } + else + smb = 0; + if (IO & 0400000) + { + srm = 1; + IO = IO ^ 0777777; + } + else + srm = 0; + AC = 0; + scr++; + while (scr < 022) + { + if (IO & 1) + { + /*assert(! (AC & 0400000));*/ + AC = AC + MB; + /* we can save carry around since both numbers are positive */ + /*AC = (AC + (AC >> 18)) & 0777777;*/ + etime += .65; /* approximative */ + } + IO = (IO >> 1) | ((AC & 1) << 17); + AC = AC >> 1; + scr++; + } + if (smb ^ srm) + { + AC = AC ^ 0777777; + IO = IO ^ 0777777; + } + + m_icount -= etime+.5; /* round to closest */ + } + else + { /* MUS */ + /* should we check for -0??? (Maintenance manual 7-14 seems to imply we should not: + as a matter of fact, since the MUS instruction is supposed to have positive operands, + there is no need to check for -0, therefore such a simplification does not sound + absurd.) */ + if ((IO & 1) == 1) + { + AC = AC + (MB = READ_PDP_18BIT(MA)); + AC = (AC + (AC >> 18)) & 0777777; /* propagate carry around */ + } + IO = (IO >> 1 | AC << 17) & 0777777; + AC >>= 1; + } + break; + case DIS_DIV: /* Divide Step or Divide */ + if (m_hw_mul_div) + { /* DIV */ + /* As a side note, the order of -0 detection and overflow checking does not matter, + because the sum of two positive number cannot give 0777777 (since positive + numbers are 0377777 at most, their sum is 0777776 at most). + Additionnally, we cannot have carry set and a result equal to 0777777 (since numbers + are 0777777 at most, their sum is 01777776 at most): this is nice, because it makes + the sequence: + AC = (AC + (AC >> 18)) & 0777777; // propagate carry around + if (AC == 0777777) // check for -0 + AC = 0; + equivalent to: + if (AC >= 0777777) + AC = (AC + 1) & 0777777; + which is a bit more efficient. */ + int acl; + int scr; + int smb, srm; + double etime = 0; /* approximative */ + + MB = READ_PDP_18BIT(MA); + scr = 0; + if (MB & 0400000) + { + smb = 1; + } + else + { + smb = 0; + MB = MB ^ 0777777; + } + if (AC & 0400000) + { + srm = 1; + AC = AC ^ 0777777; + IO = IO ^ 0777777; + } + else + srm = 0; + while (1) + { + AC = (AC + MB); + #if 1 + AC = (AC + (AC >> 18)) & 0777777; /* propagate carry around */ + if (AC == 0777777) /* check for -0 */ + AC = 0; + #else + if (AC >= 0777777) + AC = (AC + 1) & 0777777; + #endif + if (MB & 0400000) + MB = MB ^ 0777777; + + if (((scr == 0) && ! (AC & 0400000)) + || (scr == 022)) + break; + + scr++; + + if (! (AC & 0400000)) + MB = MB ^ 0777777; + + acl = AC >> 17; + AC = (AC << 1 | IO >> 17) & 0777777; + IO = ((IO << 1 | acl) & 0777777) ^ 1; + if (acl) + { + AC++; + AC = (AC + (AC >> 18)) & 0777777; + etime += .6; /* approximative */ + } + } + + AC = (AC + MB); + #if 1 + AC = (AC + (AC >> 18)) & 0777777; /* propagate carry around */ + if (AC == 0777777) /* check for -0 */ + AC = 0; + #else + if (AC >= 0777777) + AC = (AC + 1) & 0777777; + #endif + + if (scr) + { + INCREMENT_PC; + AC = AC >> 1; + } + + if (srm && (AC != 0)) + AC = AC ^ 0777777; + + if (((! scr) && (srm)) + || (scr && (srm ^ smb) && (IO != 0))) + IO = IO ^ 0777777; + + if (scr) + { + MB = AC; + AC = IO; + IO = MB; + } + if (scr) + etime += 20; /* approximative */ + else + etime += 2; /* approximative */ + + m_icount -= etime+.5; /* round to closest */ + } + else + { /* DIS */ + int acl; + + acl = AC >> 17; + AC = (AC << 1 | IO >> 17) & 0777777; + IO = ((IO << 1 | acl) & 0777777) ^ 1; + MB = READ_PDP_18BIT(MA); + if (IO & 1) + AC += (MB ^ 0777777); + else + /* Note that if AC+MB = 0777777, we are in trouble. I don't + know how a real PDP-1 behaves in this case. */ + AC += MB + 1; + AC = (AC + (AC >> 18)) & 0777777; /* propagate carry around */ + if (AC == 0777777) /* check for -0 */ + AC = 0; + } + break; + case JMP: /* Jump */ + if (m_exc) + PC = MB & EXTENDED_ADDRESS_MASK; + else + PC = (MA & ADDRESS_EXTENSION_MASK) | (MB & BASE_ADDRESS_MASK); + break; + case JSP: /* Jump and Save Program Counter */ + AC = (OV << 17) | (EXD << 16) | PC; + if (m_exc) + PC = MB & EXTENDED_ADDRESS_MASK; + else + PC = (MA & ADDRESS_EXTENSION_MASK) | (MB & BASE_ADDRESS_MASK); + break; + case SKP: /* Skip Instruction Group */ + { + int cond = ((MB & 0100) && (AC == 0)) /* ZERO Accumulator */ + || ((MB & 0200) && (AC >> 17 == 0)) /* Plus Accumulator */ + || ((MB & 0400) && (AC >> 17 == 1)) /* Minus Accumulator */ + || ((MB & 01000) && (OV == 0)) /* ZERO Overflow */ + || ((MB & 02000) && (IO >> 17 == 0)) /* Plus I/O Register */ + || (((MB & 7) != 0) && (((MB & 7) == 7) ? ! FLAGS : ! READFLAG(MB & 7))) /* ZERO Flag (deleted by mistake in PDP-1 handbook) */ + || (((MB & 070) != 0) && (((MB & 070) == 070) ? ! SENSE_SW : ! READSENSE((MB & 070) >> 3))); /* ZERO Switch */ + + if (! (MB & 010000)) + { + if (cond) + INCREMENT_PC; + } + else + { + if (!cond) + INCREMENT_PC; + } + if (MB & 01000) + OV = 0; + break; + } + case SFT: /* Shift Instruction Group */ + { + /* Bit 5 specifies direction of shift, Bit 6 specifies the character of the shift + (arithmetic or logical), Bits 7 and 8 enable the registers (01 = AC, 10 = IO, + and 11 = both) and Bits 9 through 17 specify the number of steps. */ + int nshift = 0; + int mask = MB & 0777; + + while (mask != 0) + { + nshift += mask & 1; + mask >>= 1; + } + switch ((MB >> 9) & 017) + { + int i; + + case 1: /* ral rotate accumulator left */ + for (i = 0; i < nshift; i++) + AC = (AC << 1 | AC >> 17) & 0777777; + break; + case 2: /* ril rotate i/o register left */ + for (i = 0; i < nshift; i++) + IO = (IO << 1 | IO >> 17) & 0777777; + break; + case 3: /* rcl rotate AC and IO left */ + for (i = 0; i < nshift; i++) + { + int tmp = AC; + + AC = (AC << 1 | IO >> 17) & 0777777; + IO = (IO << 1 | tmp >> 17) & 0777777; + } + break; + case 5: /* sal shift accumulator left */ + for (i = 0; i < nshift; i++) + AC = ((AC << 1 | AC >> 17) & 0377777) + (AC & 0400000); + break; + case 6: /* sil shift i/o register left */ + for (i = 0; i < nshift; i++) + IO = ((IO << 1 | IO >> 17) & 0377777) + (IO & 0400000); + break; + case 7: /* scl shift AC and IO left */ + for (i = 0; i < nshift; i++) + { + int tmp = AC; + + AC = ((AC << 1 | IO >> 17) & 0377777) + (AC & 0400000); /* shouldn't that be IO?, no it is the sign! */ + IO = (IO << 1 | tmp >> 17) & 0777777; + } + break; + case 9: /* rar rotate accumulator right */ + for (i = 0; i < nshift; i++) + AC = (AC >> 1 | AC << 17) & 0777777; + break; + case 10: /* rir rotate i/o register right */ + for (i = 0; i < nshift; i++) + IO = (IO >> 1 | IO << 17) & 0777777; + break; + case 11: /* rcr rotate AC and IO right */ + for (i = 0; i < nshift; i++) + { + int tmp = AC; + + AC = (AC >> 1 | IO << 17) & 0777777; + IO = (IO >> 1 | tmp << 17) & 0777777; + } + break; + case 13: /* sar shift accumulator right */ + for (i = 0; i < nshift; i++) + AC = (AC >> 1) + (AC & 0400000); + break; + case 14: /* sir shift i/o register right */ + for (i = 0; i < nshift; i++) + IO = (IO >> 1) + (IO & 0400000); + break; + case 15: /* scr shift AC and IO right */ + for (i = 0; i < nshift; i++) + { + int tmp = AC; + + AC = (AC >> 1) + (AC & 0400000); /* shouldn't that be IO, no it is the sign */ + IO = (IO >> 1 | tmp << 17) & 0777777; + } + break; + default: + if (LOG) + logerror("Undefined shift: 0%06o at 0%06o\n", MB, PREVIOUS_PC); + break; + } + break; + } + case LAW: /* Load Accumulator with N */ + AC = MB & 07777; + if (MB & 010000) + AC ^= 0777777; + break; + case IOT: /* In-Out Transfer Instruction Group */ + /* + The variations within this group of instructions perform all the in-out control + and information transfer functions. If Bit 5 (normally the Indirect Address bit) + is a ONE, the computer will enter a special waiting state until the completion pulse + from the activated device has returned. When this device delivers its completion, + the computer will resume operation of the instruction sequence. + + The computer may be interrupted from the special waiting state to serve a sequence + break request or a high speed channel request. + + Most in-out operations require a known minimum time before completion. This time + may be utilized for programming. The appropriate In-Out Transfer can be given with + no in-out wait (Bit 5 a ZERO and Bit 6 a ONE). The instruction sequence then + continues. This sequence must include an iot instruction 730000 which performs + nothing but the in-out wait. The computer will then enter the special waiting state + until the device returns the in-out restart pulse. If the device has already + returned the completion pulse before the instruction 730000, the computer will + proceed immediately. + + Bit 6 determines whether a completion pulse will or will not be received from + the in-out device. When it is different than Bit 5, a completion pulse will be + received. When it is the same as Bit 5, a completion pulse will not be received. + + In addition to the control function of Bits 5 and 6, Bits 7 through 11 are also + used as control bits serving to extend greatly the power of the iot instructions. + For example, Bits 12 through 17, which are used to designate a class of input or + output devices such as typewriters, may be further defined by Bits 7 through 11 + as referring to Typewriter 1, 2, 3, etc. In several of the optional in-out devices, + in particular the magnetic tape, Bits 7 through 11 specify particular functions + such as forward, backward etc. If a large number of specialized devices are to + be attached, these bits may be used to further the in-out transfer instruction + to perform totally distinct functions. + + Note that ioc is supposed to be set at the beggining of the memory cycle after + ioh is cleared. + However, we cannot set ioc at the beggining of every memory cycle as we + did before, because it breaks in the following case: + a) IOT instruction enables IO wait + b) sequence break in the middle of IO-halt + c) ioh is cleared in middle of sequence break routine + d) re-execute IOT instruction. Unfortunately, ioc has been cleared, therefore + we perform an IOT command pulse and IO wait again, which is completely WRONG. + Therefore ioc is cleared only after a IOT with wait is executed. + */ + if (MB & 010000) + { /* IOT with IO wait */ + if (m_ioc) + { /* the iot command line is pulsed only if ioc is asserted */ + (*m_extern_iot[MB & 0000077])(this, MB & 0000077, (MB & 0004000) == 0, MB, &IO, AC); + + m_ioh = 1; /* enable io wait */ + + m_ioc = 0; /* actually happens at the start of next memory cycle */ + + /* test ios now in case the IOT callback has sent a completion pulse immediately */ + if (m_ioh && m_ios) + { + /* ioh should be cleared at the end of the instruction cycle, and ios at the + start of next instruction cycle, but who cares? */ + m_ioh = 0; + //m_ios = 0; + } + } + + if (m_ioh) + DECREMENT_PC; + else + m_ioc = 1; /* actually happens at the start of next memory cycle */ + } + else + { /* IOT with no IO wait */ + (*m_extern_iot[MB & 0000077])(this, MB & 0000077, (MB & 0004000) != 0, MB, &IO, AC); + } + break; + case OPR: /* Operate Instruction Group */ + { + int nflag; + + if (MB & 00200) /* clear AC */ + AC = 0; + if (MB & 04000) /* clear I/O register */ + IO = 0; + if (MB & 02000) /* load Accumulator from Test Word */ + AC |= m_tw; + if (MB & 00100) /* load Accumulator with Program Counter */ + AC |= (OV << 17) | (EXD << 16) | PC; + nflag = MB & 7; + if (nflag) + { + if (nflag == 7) + FLAGS = (MB & 010) ? 077 : 000; + else + WRITEFLAG(nflag, (MB & 010) ? 1 : 0); + } + if (MB & 01000) /* Complement AC */ + AC ^= 0777777; + if (MB & 00400) /* Halt */ + { + if (LOG_EXTRA) + logerror("PDP1 Program executed HALT: at 0%06o\n", PREVIOUS_PC); + + m_run = 0; + } + break; + } + default: + if (LOG) + logerror("Illegal instruction: 0%06o at 0%06o\n", MB, PREVIOUS_PC); + + /* let us stop the CPU, like a real pdp-1 */ + m_run = 0; + + break; + } + m_cycle = 0; +no_fetch: + ; +} + + +/* + Handle unimplemented IOT +*/ +void pdp1_device::pdp1_null_iot(int op2, int nac, int mb, int *io, int ac) +{ + /* Note that the dummy IOT 0 is used to wait for the completion pulse + generated by the a pending IOT (IOT with completion pulse but no IO wait) */ + if (LOG_IOT_EXTRA) + { + if (op2 == 000) + logerror("IOT sync instruction: mb=0%06o, pc=0%06o\n", (unsigned) mb, (unsigned) m_pc); + } + if (LOG) + { + if (op2 != 000) + logerror("Not supported IOT command (no external IOT function given) 0%06o at 0%06o\n", mb, m_pc); + } +} + + +/* + Memory expansion control (type 15) + + IOT 74: LEM/EEM +*/ +void pdp1_device::pdp1_lem_eem_iot(int op2, int nac, int mb, int *io, int ac) +{ + if (! m_extend_support) /* extend mode supported? */ + { + if (LOG) + logerror("Ignoring internal error in file " __FILE__ " line %d.\n", __LINE__); + return; + } + if (LOG_EXTRA) + { + logerror("EEM/LEM instruction: mb=0%06o, pc=0%06o\n", mb, m_pc); + } + EXD = (mb & 0004000) ? 1 : 0; +} + + +/* + Standard sequence break system + + IOT 54: lsm + IOT 55: esm + IOT 56: cbs +*/ +void pdp1_device::pdp1_sbs_iot(int op2, int nac, int mb, int *io, int ac) +{ + switch (op2) + { + case 054: /* LSM */ + if (LOG_EXTRA) + logerror("LSM instruction: mb=0%06o, pc=0%06o\n", mb, m_pc); + + m_sbm = 0; + field_interrupt(); + break; + case 055: /* ESM */ + if (LOG_EXTRA) + logerror("ESM instruction: mb=0%06o, pc=0%06o\n", mb, m_pc); + + m_sbm = 1; + field_interrupt(); + break; + case 056: /* CBS */ + if (LOG_EXTRA) + logerror("CBS instruction: mb=0%06o, pc=0%06o\n", mb, m_pc); + + /*m_b3 = 0;*/ + m_b4 = 0; + field_interrupt(); + break; + default: + if (LOG) + logerror("Ignoring internal error in file " __FILE__ " line %d.\n", __LINE__); + + break; + } +} + + +/* + type 20 sequence break system + + IOT 50: dsc + IOT 51: asc + IOT 52: isb + IOT 53: cac +*/ +void pdp1_device::pdp1_type_20_sbs_iot(int op2, int nac, int mb, int *io, int ac) +{ + int channel, mask; + if (! m_type_20_sbs) /* type 20 sequence break system supported? */ + { + if (LOG) + logerror("Ignoring internal error in file " __FILE__ " line %d.\n", __LINE__); + return; + } + channel = (mb >> 6) & 017; + mask = 1 << channel; + switch (op2) + { + case 050: /* DSC */ + if (LOG_EXTRA) + logerror("DSC instruction: mb=0%06o, pc=0%06o\n", mb, m_pc); + + m_b1 &= ~mask; + field_interrupt(); + break; + case 051: /* ASC */ + if (LOG_EXTRA) + logerror("ASC instruction: mb=0%06o, pc=0%06o\n", mb, m_pc); + + m_b1 |= mask; + field_interrupt(); + break; + case 052: /* ISB */ + if (LOG_EXTRA) + logerror("ISB instruction: mb=0%06o, pc=0%06o\n", mb, m_pc); + + m_b2 |= mask; + field_interrupt(); + break; + case 053: /* CAC */ + if (LOG_EXTRA) + logerror("CAC instruction: mb=0%06o, pc=0%06o\n", mb, m_pc); + + m_b1 = 0; + field_interrupt(); + break; + default: + if (LOG) + logerror("Ignoring internal error in file " __FILE__ " line %d.\n", __LINE__); + + break; + } + +} + + +/* + Simulate a pulse on start/clear line: + reset most registers and flip-flops, and initialize a few emulator state + variables. +*/ +void pdp1_device::pulse_start_clear() +{ + /* processor registers */ + PC = 0; /* according to maintenance manual p. 6-17 */ + IR = 0; /* according to maintenance manual p. 6-13 */ + /*MB = 0;*/ /* ??? */ + /*MA = 0;*/ /* ??? */ + /*AC = 0;*/ /* ??? */ + /*IO = 0;*/ /* ??? */ + /*PF = 0;*/ /* ??? */ + + /* processor state flip-flops */ + m_run = 0; /* ??? */ + m_cycle = 0; /* mere guess */ + m_defer = 0; /* mere guess */ + m_brk_ctr = 0; /* mere guess */ + m_ov = 0; /* according to maintenance manual p. 7-18 */ + m_rim = 0; /* ??? */ + m_sbm = 0; /* ??? */ + EXD = 0; /* according to maintenance manual p. 8-16 */ + m_exc = 0; /* according to maintenance manual p. 8-16 */ + m_ioc = 1; /* according to maintenance manual p. 6-10 */ + m_ioh = 0; /* according to maintenance manual p. 6-10 */ + m_ios = 0; /* according to maintenance manual p. 6-10 */ + + m_b1 = m_type_20_sbs ? 0 : 1; /* mere guess */ + m_b2 = 0; /* mere guess */ + m_b4 = 0; /* mere guess */ + + + m_rim_step = 0; + m_sbs_restore = 0; /* mere guess */ + m_no_sequence_break = 0; /* mere guess */ + + field_interrupt(); + + /* now, we kindly ask IO devices to reset, too */ + if (m_io_sc_callback) + (*m_io_sc_callback)(this); +} diff --git a/src/devices/cpu/pdp1/pdp1.h b/src/devices/cpu/pdp1/pdp1.h new file mode 100644 index 00000000000..f4d1281aa07 --- /dev/null +++ b/src/devices/cpu/pdp1/pdp1.h @@ -0,0 +1,199 @@ +// license:BSD-3-Clause +// copyright-holders:Raphael Nabet +#pragma once + +#ifndef __PDP1_H__ +#define __PDP1_H__ + + + +/* register ids for pdp1_get_reg/pdp1_set_reg */ +enum +{ + PDP1_PC=1, PDP1_IR, PDP1_MB, PDP1_MA, PDP1_AC, PDP1_IO, + PDP1_PF, PDP1_PF1, PDP1_PF2, PDP1_PF3, PDP1_PF4, PDP1_PF5, PDP1_PF6, + PDP1_TA, PDP1_TW, + PDP1_SS, PDP1_SS1, PDP1_SS2, PDP1_SS3, PDP1_SS4, PDP1_SS5, PDP1_SS6, + PDP1_SNGL_STEP, PDP1_SNGL_INST, PDP1_EXTEND_SW, + PDP1_RUN, PDP1_CYC, PDP1_DEFER, PDP1_BRK_CTR, PDP1_OV, PDP1_RIM, PDP1_SBM, PDP1_EXD, + PDP1_IOC, PDP1_IOH, PDP1_IOS +}; + + +typedef void (*pdp1_extern_iot_func)(device_t *device, int op2, int nac, int mb, int *io, int ac); +typedef void (*pdp1_read_binary_word_func)(device_t *device); +typedef void (*pdp1_io_sc_func)(device_t *device); + + +struct pdp1_reset_param_t +{ + /* callbacks for iot instructions (required for any I/O) */ + pdp1_extern_iot_func extern_iot[64]; + /* read a word from the perforated tape reader (required for read-in mode) */ + pdp1_read_binary_word_func read_binary_word; + /* callback called when sc is pulsed: IO devices should reset */ + pdp1_io_sc_func io_sc_callback; + + /* 0: no extend support, 1: extend with 15-bit address, 2: extend with 16-bit address */ + int extend_support; + /* 1 to use hardware multiply/divide (MUL, DIV) instead of MUS, DIS */ + int hw_mul_div; + /* 0: standard sequence break system 1: type 20 sequence break system */ + int type_20_sbs; +}; + +#define IOT_NO_COMPLETION_PULSE -1 + + +#define AND 001 +#define IOR 002 +#define XOR 003 +#define XCT 004 +#define CALJDA 007 +#define LAC 010 +#define LIO 011 +#define DAC 012 +#define DAP 013 +#define DIP 014 +#define DIO 015 +#define DZM 016 +#define ADD 020 +#define SUB 021 +#define IDX 022 +#define ISP 023 +#define SAD 024 +#define SAS 025 +#define MUS_MUL 026 +#define DIS_DIV 027 +#define JMP 030 +#define JSP 031 +#define SKP 032 +#define SFT 033 +#define LAW 034 +#define IOT 035 +#define OPR 037 + + +class pdp1_device : public cpu_device + , public pdp1_reset_param_t +{ +public: + // construction/destruction + pdp1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + void pulse_start_clear(); + void io_complete() { m_ios = 1; } + void pdp1_null_iot(int op2, int nac, int mb, int *io, int ac); + void pdp1_lem_eem_iot(int op2, int nac, int mb, int *io, int ac); + void pdp1_sbs_iot(int op2, int nac, int mb, int *io, int ac); + void pdp1_type_20_sbs_iot(int op2, int nac, int mb, int *io, int ac); + +protected: + // device-level overrides + virtual void device_config_complete(); + virtual void device_start(); + virtual void device_reset(); + + // device_execute_interface overrides + virtual UINT32 execute_min_cycles() const { return 5; } + virtual UINT32 execute_max_cycles() const { return 31; } + virtual UINT32 execute_input_lines() const { return 16; } + virtual void execute_run(); + virtual void execute_set_input(int inputnum, int state); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const { return (spacenum == AS_PROGRAM) ? &m_program_config : NULL; } + + // device_state_interface overrides + virtual void state_import(const device_state_entry &entry); + virtual void state_export(const device_state_entry &entry); + void state_string_export(const device_state_entry &entry, std::string &str); + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const { return 4; } + virtual UINT32 disasm_max_opcode_bytes() const { return 4; } + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + +private: + address_space_config m_program_config; + + /* processor registers */ + UINT32 m_pc; /* program counter (12, 15 or 16 bits) */ + int m_ir; /* basic operation code of current instruction (5 bits) */ + int m_mb; /* memory buffer (used for holding the current instruction only) (18 bits) */ + int m_ma; /* memory address (12, 15 or 16 bits) */ + int m_ac; /* accumulator (18 bits) */ + int m_io; /* i/o register (18 bits) */ + int m_pf; /* program flag register (6 bits) */ + + /* operator panel switches */ + int m_ta; /* current state of the 12 or 16 address switches */ + int m_tw; /* current state of the 18 test word switches */ + int m_ss; /* current state of the 6 sense switches on the operator panel (6 bits) */ + unsigned int m_sngl_step; /* stop every memory cycle */ + unsigned int m_sngl_inst; /* stop every instruction */ + unsigned int m_extend_sw; /* extend switch (loaded into the extend flip-flop on start/read-in) */ + + /* processor state flip-flops */ + unsigned int m_run; /* processor is running */ + unsigned int m_cycle; /* processor is in the midst of an instruction */ + unsigned int m_defer; /* processor is handling deferred (i.e. indirect) addressing */ + unsigned int m_brk_ctr; /* break counter */ + unsigned int m_ov; /* overflow flip-flop */ + unsigned int m_rim; /* processor is in read-in mode */ + + unsigned int m_sbm; /* processor is in sequence break mode (i.e. interrupts are enabled) */ + + unsigned int m_exd; /* extend mode: processor is in extend mode */ + unsigned int m_exc : 1; /* extend-mode cycle: current instruction cycle is done in extend mode */ + unsigned int m_ioc; /* i-o commands: seems to be equivalent to (! ioh) */ + unsigned int m_ioh; /* i-o halt: processor is executing an Input-Output Transfer wait */ + unsigned int m_ios; /* i-o synchronizer: set on i-o operation completion */ + + /* sequence break system */ + UINT16 m_irq_state; /* mirrors the state of the interrupt pins */ + UINT16 m_b1; /* interrupt enable */ + UINT16 m_b2; /* interrupt pulse request pending - asynchronous with computer operation (set by pulses on irq_state, cleared when interrupt is taken) */ + /*UINT16 m_b3;*/ /* interrupt request pending - synchronous with computer operation (logical or of irq_state and b2???) */ + UINT16 m_b4; /* interrupt in progress */ + + /* additional emulator state variables */ + int m_rim_step; /* current step in rim execution */ + int m_sbs_request; /* interrupt request (i.e. (b3 & (~ b4)) && (! sbm)) */ + int m_sbs_level; /* interrupt request level (first bit in (b3 & (~ b4)) */ + int m_sbs_restore; /* set when a jump instruction is an interrupt return */ + int m_no_sequence_break; /* disable sequence break recognition for one cycle */ + + /* callbacks for iot instructions (required for any I/O) */ + pdp1_extern_iot_func m_extern_iot[64]; + /* read a word from the perforated tape reader (required for read-in mode) */ + pdp1_read_binary_word_func m_read_binary_word; + /* callback called when sc is pulsed: IO devices should reset */ + pdp1_io_sc_func m_io_sc_callback; + + /* 0: no extend support, 1: extend with 15-bit address, 2: extend with 16-bit address */ + int m_extend_support; + + int m_extended_address_mask; /* 07777 with no extend support, 077777 or 0177777 with extend support */ + int m_address_extension_mask; /* 00000 with no extend support, 070000 or 0170000 with extend support */ + + /* 1 to use hardware multiply/divide (MUL, DIV) instead of MUS, DIS */ + int m_hw_mul_div; + + /* 1 for 16-line sequence break system, 0 for default break system */ + int m_type_20_sbs; + + address_space *m_program; + int m_icount; + UINT32 m_debugger_temp; + + void field_interrupt(); + void execute_instruction(); + +}; + + +extern const device_type PDP1; + + +#endif /* __PDP1_H__ */ diff --git a/src/devices/cpu/pdp1/pdp1dasm.c b/src/devices/cpu/pdp1/pdp1dasm.c new file mode 100644 index 00000000000..c8682ca1491 --- /dev/null +++ b/src/devices/cpu/pdp1/pdp1dasm.c @@ -0,0 +1,294 @@ +// license:BSD-3-Clause +// copyright-holders:Raphael Nabet +#include "emu.h" +#include "cpu/pdp1/pdp1.h" + +/* PDP1 registers */ +static int ib; +static int y; + +INLINE void ea (void) +{ +/* while (1) + { + if (ib == 0) + return; + ib = (READ_PDP_18BIT (y) >> 12) & 1; + y = READ_PDP_18BIT (y) & 07777; + }*/ +} + +#define IN if (ib) sprintf(buffer+strlen(buffer)," i") + +CPU_DISASSEMBLE( pdp1 ) +{ + int md; + //int etime = 0; + + md = oprom[0] << 24 | oprom[1] << 16 | oprom[2] << 8 | oprom[3]; + + y = md & 07777; + ib = (md >> 12) & 1; /* */ + switch (md >> 13) + { + case AND: + ea (); + sprintf (buffer, "AND (0%06o)", y); + IN; + //etime = 10; + break; + case IOR: + ea (); + sprintf (buffer, "IOR (0%06o)", y); + IN; + //etime = 10; + break; + case XOR: + ea (); + sprintf (buffer, "XOR (0%06o)", y); + IN; + //etime = 10; + break; + case XCT: + ea (); + sprintf (buffer, "XCT (0%06o)", y); + IN; + //etime = 5; + break; + case CALJDA: + { + if (ib == 1) + sprintf (buffer, "JDA 0%06o ", y); + if (ib == 0) + sprintf (buffer, "CAL "); + //etime = 10; + break; + } + case LAC: + ea (); + sprintf (buffer, "LAC (0%06o)", y); + IN; + //etime = 10; + break; + case LIO: + ea (); + sprintf (buffer, "LIO (0%06o)", y); + IN; + //etime = 10; + break; + case DAC: + ea (); + sprintf (buffer, "DAC 0%06o ", y); + IN; + //etime = 10; + break; + case DAP: + ea (); + sprintf (buffer, "DAP 0%06o ", y); + IN; + //etime = 10; + break; + case DIP: + ea (); + sprintf (buffer, "DIP 0%06o ", y); + IN; + //etime = 10; + break; + case DIO: + ea (); + sprintf (buffer, "DIO 0%06o ", y); + IN; + //etime = 10; + break; + case DZM: + ea (); + sprintf (buffer, "DZM 0%06o ", y); + IN; + //etime = 10; + break; + case ADD: + ea (); + sprintf (buffer, "ADD (0%06o)", y); + IN; + //etime = 10; + break; + case SUB: + ea (); + sprintf (buffer, "SUB (0%06o)", y); + IN; + //etime = 10; + break; + case IDX: + ea (); + sprintf (buffer, "IDX (0%06o)", y); + IN; + //etime = 10; + break; + case ISP: + ea (); + sprintf (buffer, "ISP (0%06o)", y); + IN; + //etime = 10; + break; + case SAD: + ea (); + sprintf (buffer, "SAD (0%06o)", y); + IN; + //etime = 10; + break; + case SAS: + ea (); + sprintf (buffer, "SAS (0%06o)", y); + IN; + //etime = 10; + break; + case MUS_MUL: + ea (); + sprintf (buffer, "MUS (0%06o)", y); + IN; + //etime = 10; + break; + case DIS_DIV: + ea (); + sprintf (buffer, "DIS (0%06o)", y); + IN; + //etime = 10; + break; + case JMP: + ea (); + sprintf (buffer, "JMP 0%06o ", y); + IN; + //etime = 5; + break; + case JSP: + ea (); + sprintf (buffer, "JSP 0%06o ", y); + IN; + //etime = 5; + break; + case SKP: + { + buffer[0] = 0; + if ((y & 0100) == 0100) + sprintf (buffer, "SZA "); + if ((y & 0200) == 0200) + sprintf (buffer + strlen (buffer), "SPA "); + if ((y & 0400) == 0400) + sprintf (buffer + strlen (buffer), "SMA "); + if ((y & 01000) == 01000) + sprintf (buffer + strlen (buffer), "SZO "); + if ((y & 02000) == 02000) + sprintf (buffer + strlen (buffer), "SPI "); + if (y & 070) + sprintf (buffer + strlen (buffer), "SZS 0%01o ", (y & 070)); + if (y & 7) + sprintf (buffer + strlen (buffer), "SZF 0%01o ", (y & 7)); + IN; + //etime = 5; + break; + } + case SFT: + { + int nshift = 0; + int mask = md & 0777; + + while (mask != 0) + { + nshift += mask & 1; + mask = mask >> 1; + } + switch ((md >> 9) & 017) + { + case 1: + sprintf (buffer, "RAL 0%02o", nshift); + //etime = 5; + break; + case 2: + sprintf (buffer, "RIL 0%02o", nshift); + //etime = 5; + break; + case 3: + sprintf (buffer, "RCL 0%02o", nshift); + //etime = 5; + break; + case 5: + sprintf (buffer, "SAL 0%02o", nshift); + //etime = 5; + break; + case 6: + sprintf (buffer, "SIL 0%02o", nshift); + //etime = 5; + break; + case 7: + sprintf (buffer, "SCL 0%02o", nshift); + //etime = 5; + break; + case 9: + sprintf (buffer, "RAR 0%02o", nshift); + //etime = 5; + break; + case 10: + sprintf (buffer, "RIR 0%02o", nshift); + //etime = 5; + break; + case 11: + sprintf (buffer, "RCR 0%02o", nshift); + //etime = 5; + break; + case 13: + sprintf (buffer, "SAR 0%02o", nshift); + //etime = 5; + break; + case 14: + sprintf (buffer, "SIR 0%02o", nshift); + //etime = 5; + break; + case 15: + sprintf (buffer, "SCR 0%02o", nshift); + //etime = 5; + break; + default: + sprintf (buffer, "SKP ???"); + //etime = 5; + break; + } + break; + } + case LAW: + sprintf (buffer, "LAW 0%06o", y); + IN; + //etime = 5; + break; + case IOT: + sprintf (buffer, "IOT 0%06o", md); + //etime = 10; + break; + case OPR: + { + buffer[0] = 0; + if ((y & 04000) == 04000) + sprintf (buffer + strlen (buffer), "CLI "); + if ((y & 02000) == 02000) + sprintf (buffer + strlen (buffer), "LAT "); + if ((y & 01000) == 01000) + sprintf (buffer + strlen (buffer), "CMA "); + if ((y & 0400) == 0400) + sprintf (buffer + strlen (buffer), "HLT "); + if ((y & 0100) == 0100) + sprintf (buffer + strlen (buffer), "LAP "); + if ((y & 010) && (y & 7)) + sprintf (buffer + strlen (buffer), "STF 0%01o ", (y & 7)); + if ((!(y & 010)) && (y & 7)) + sprintf (buffer + strlen (buffer), "CLF 0%01o ", (y & 7)); + if (!(y)) + sprintf (buffer + strlen (buffer), "NOP "); + //etime = 5; + break; + } + default: + sprintf (buffer, "ILLEGAL"); + //etime = 5; + break; + } + return 4; +} diff --git a/src/devices/cpu/pdp1/tx0.c b/src/devices/cpu/pdp1/tx0.c new file mode 100644 index 00000000000..03c8441d88f --- /dev/null +++ b/src/devices/cpu/pdp1/tx0.c @@ -0,0 +1,1080 @@ +// license:BSD-3-Clause +// copyright-holders:Raphael Nabet +/* + TX-0 emulator + + Two variants: + * initial model 64kWord RAM + * later model 8kWord RAM + + Raphael Nabet 2004 +*/ + +#include "emu.h" +#include "debugger.h" +#include "tx0.h" + +#define LOG 0 +#define LOG_EXTRA 0 + + +#define READ_TX0_18BIT(A) ((signed)m_program->read_dword((A)<<2)) +#define WRITE_TX0_18BIT(A,V) (m_program->write_dword((A)<<2,(V))) + + +#define io_handler_rim 3 + +#define PC m_pc +#define IR m_ir +#define MBR m_mbr +#define MAR m_mar +#define AC m_ac +#define LR m_lr +#define XR m_xr +#define PF m_pf + +#define ADDRESS_MASK_64KW 0177777 +#define ADDRESS_MASK_8KW 0017777 + +#define INCREMENT_PC_64KW (PC = (PC+1) & ADDRESS_MASK_64KW) +#define INCREMENT_PC_8KW (PC = (PC+1) & ADDRESS_MASK_8KW) + + +const device_type TX0_8KW = &device_creator; +const device_type TX0_64KW = &device_creator; + + +tx0_device::tx0_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source, int addr_bits, int address_mask, int ir_mask) + : cpu_device(mconfig, type, name, tag, owner, clock, shortname, source) + , m_program_config("program", ENDIANNESS_BIG, 32, addr_bits , -2) + , m_address_mask(address_mask) + , m_ir_mask(ir_mask) + , m_cpy_handler(*this) + , m_r1l_handler(*this) + , m_dis_handler(*this) + , m_r3l_handler(*this) + , m_prt_handler(*this) + , m_rsv_handler(*this) + , m_p6h_handler(*this) + , m_p7h_handler(*this) + , m_sel_handler(*this) + , m_io_reset_callback(*this) +{ + m_is_octal = true; +} + +tx0_8kw_device::tx0_8kw_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : tx0_device(mconfig, TX0_8KW, "TX-0 8KW", tag, owner, clock, "tx0_8w_cpu", __FILE__, 13, ADDRESS_MASK_8KW, 037) +{ +} + + +tx0_64kw_device::tx0_64kw_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : tx0_device(mconfig, TX0_64KW, "TX-0 64KW", tag, owner, clock, "tx0_64kw_cpu", __FILE__, 16, ADDRESS_MASK_64KW, 03) +{ +} + + +int tx0_device::tx0_read(offs_t address) +{ + if ((address >= 16) || (m_gbl_cm_sel) || ((m_cm_sel >> address) & 1)) + /* core memory (CM) */ + return READ_TX0_18BIT(address); + else if ((m_lr_sel >> address) & 1) + /* live register (LR) */ + return LR; + + /* toggle switch storage (TSS) */ + return m_tss[address]; +} + +void tx0_device::tx0_write(offs_t address, int data) +{ + if ((address >= 16) || (m_gbl_cm_sel) || ((m_cm_sel >> address) & 1)) + /* core memory (CM) */ + WRITE_TX0_18BIT(address, data); + else if ((m_lr_sel >> address) & 1) + /* live register (LR) */ + LR = data; + else + /* toggle switch storage (TSS) */ + /* TSS is read-only */ + { + /* nothing */ + } +} + + +void tx0_device::device_start() +{ + m_mbr = 0; + m_ac = 0; + m_mar = 0; + m_lr = 0; + m_xr = 0; + m_pf = 0; + m_tbr = 0; + m_tac = 0; + for ( int i = 0; i < 16; i++ ) + { + m_tss[i] = 0; + } + m_cm_sel = 0; + m_lr_sel = 0; + m_gbl_cm_sel = 0; + m_stop_cyc0 = 0; + m_stop_cyc1 = 0; + m_cycle = 0; + m_pc = 0; + m_ir = 0; + m_run = 0; + m_rim = 0; + m_ioh = 0; + m_ios = 0; + + // Resolve callbacks + m_cpy_handler.resolve(); + m_r1l_handler.resolve(); + m_dis_handler.resolve(); + m_r3l_handler.resolve(); + m_prt_handler.resolve(); + m_rsv_handler.resolve(); + m_p6h_handler.resolve(); + m_p7h_handler.resolve(); + m_sel_handler.resolve(); + m_io_reset_callback.resolve(); + + m_program = &space(AS_PROGRAM); + + save_item(NAME(m_mbr)); + save_item(NAME(m_ac)); + save_item(NAME(m_mar)); + save_item(NAME(m_pc)); + save_item(NAME(m_ir)); + save_item(NAME(m_lr)); + save_item(NAME(m_xr)); + save_item(NAME(m_pf)); + save_item(NAME(m_tbr)); + save_item(NAME(m_tac)); + save_item(NAME(m_tss)); + save_item(NAME(m_cm_sel)); + save_item(NAME(m_lr_sel)); + save_item(NAME(m_gbl_cm_sel)); + save_item(NAME(m_stop_cyc0)); + save_item(NAME(m_stop_cyc1)); + save_item(NAME(m_run)); + save_item(NAME(m_rim)); + save_item(NAME(m_cycle)); + save_item(NAME(m_ioh)); + save_item(NAME(m_ios)); + save_item(NAME(m_rim_step)); + + // Register state for debugger + state_add( TX0_PC, "PC", m_pc ).mask(m_address_mask).formatstr("0%06O"); + state_add( TX0_IR, "IR", m_ir ).mask(m_ir_mask) .formatstr("0%02O"); + state_add( TX0_MBR, "MBR", m_mbr ).mask(0777777) .formatstr("0%06O"); + state_add( TX0_MAR, "MAR", m_mar ).mask(m_address_mask).formatstr("0%06O"); + state_add( TX0_AC, "AC", m_ac ).mask(0777777) .formatstr("0%06O"); + state_add( TX0_LR, "LR", m_lr ).mask(0777777) .formatstr("0%06O"); + state_add( TX0_XR, "XR", m_xr ).mask(0037777) .formatstr("0%05O"); + state_add( TX0_PF, "PF", m_pf ).mask(077) .formatstr("0%02O"); + state_add( TX0_TBR, "TBR", m_tbr ).mask(0777777) .formatstr("0%06O"); + state_add( TX0_TAC, "TAC", m_tac ).mask(0777777) .formatstr("0%06O"); + state_add( TX0_TSS00, "TSS00", m_tss[000] ).mask(0777777) .formatstr("0%06O"); + state_add( TX0_TSS01, "TSS01", m_tss[001] ).mask(0777777) .formatstr("0%06O"); + state_add( TX0_TSS02, "TSS02", m_tss[002] ).mask(0777777) .formatstr("0%06O"); + state_add( TX0_TSS03, "TSS03", m_tss[003] ).mask(0777777) .formatstr("0%06O"); + state_add( TX0_TSS04, "TSS04", m_tss[004] ).mask(0777777) .formatstr("0%06O"); + state_add( TX0_TSS05, "TSS05", m_tss[005] ).mask(0777777) .formatstr("0%06O"); + state_add( TX0_TSS06, "TSS06", m_tss[006] ).mask(0777777) .formatstr("0%06O"); + state_add( TX0_TSS07, "TSS07", m_tss[007] ).mask(0777777) .formatstr("0%06O"); + state_add( TX0_TSS10, "TSS10", m_tss[010] ).mask(0777777) .formatstr("0%06O"); + state_add( TX0_TSS11, "TSS11", m_tss[011] ).mask(0777777) .formatstr("0%06O"); + state_add( TX0_TSS12, "TSS12", m_tss[012] ).mask(0777777) .formatstr("0%06O"); + state_add( TX0_TSS13, "TSS13", m_tss[013] ).mask(0777777) .formatstr("0%06O"); + state_add( TX0_TSS14, "TSS14", m_tss[014] ).mask(0777777) .formatstr("0%06O"); + state_add( TX0_TSS15, "TSS15", m_tss[015] ).mask(0777777) .formatstr("0%06O"); + state_add( TX0_TSS16, "TSS16", m_tss[016] ).mask(0777777) .formatstr("0%06O"); + state_add( TX0_TSS17, "TSS17", m_tss[017] ).mask(0777777) .formatstr("0%06O"); + state_add( TX0_CM_SEL, "CMSEL", m_cm_sel ).mask(0177777) .formatstr("0%06O"); + state_add( TX0_LR_SEL, "LRSEL", m_lr_sel ).mask(0177777) .formatstr("0%06O"); + state_add( TX0_GBL_CM_SEL, "GBLCMSEL", m_gbl_cm_sel ).mask(1) .formatstr("%1X"); + state_add( TX0_STOP_CYC0, "STOPCYC0", m_stop_cyc0 ).mask(1) .formatstr("%1X"); + state_add( TX0_STOP_CYC1, "STOPCYC1", m_stop_cyc1 ).mask(1) .formatstr("%1X"); + state_add( TX0_RUN, "RUN", m_run ).mask(1) .formatstr("%1X"); + state_add( TX0_RIM, "RIM", m_rim ).mask(1) .formatstr("%1X"); + state_add( TX0_CYCLE, "CYCLE", m_cycle ) .formatstr("%1X"); + state_add( TX0_IOH, "IOH", m_ioh ) .formatstr("%1X"); + state_add( TX0_IOS, "IOS", m_ios ).mask(1) .formatstr("%1X"); + + state_add(STATE_GENPC, "GENPC", m_pc).formatstr("0%06O").noshow(); + state_add(STATE_GENFLAGS, "GENFLAGS", m_ir).noshow(); + + m_icountptr = &m_icount; +} + + +void tx0_device::device_reset() +{ + /* reset CPU flip-flops */ + pulse_reset(); + + m_gbl_cm_sel = 1; /* HACK */ +} + + +void tx0_device::call_io_handler(int io_handler) +{ + /* data will be transferred to AC */ + switch (io_handler) + { + case 0: m_cpy_handler(ASSERT_LINE); break; + case 1: m_r1l_handler(ASSERT_LINE); break; + case 2: m_dis_handler(ASSERT_LINE); break; + case 3: m_r3l_handler(ASSERT_LINE); break; + case 4: m_prt_handler(ASSERT_LINE); break; + case 5: m_rsv_handler(ASSERT_LINE); break; + case 6: m_p6h_handler(ASSERT_LINE); break; + case 7: m_p7h_handler(ASSERT_LINE); break; + } +} + + +/* execute instructions on this CPU until icount expires */ +void tx0_64kw_device::execute_run() +{ + do + { + debugger_instruction_hook(this, PC); + + + if (m_ioh && m_ios) + { + m_ioh = 0; + } + + + if ((! m_run) && (! m_rim)) + m_icount = 0; /* if processor is stopped, just burn cycles */ + else if (m_rim) + { + switch (m_rim_step) + { + case 0: + /* read first word as instruction */ + AC = 0; + call_io_handler(io_handler_rim); + m_rim_step = 1; + m_ios = 0; + break; + + case 1: + if (! m_ios) + { /* transfer incomplete: wait some more */ + m_icount = 0; + } + else + { /* data transfer complete */ + m_ios = 0; + + MBR = AC; + IR = MBR >> 16; /* basic opcode */ + if ((IR == 2) || (IR == 1)) /* trn or add instruction? */ + { + PC = MBR & ADDRESS_MASK_64KW; + m_rim = 0; /* exit read-in mode */ + m_run = (IR == 2) ? 1 : 0; /* stop if add instruction */ + m_rim_step = 0; + } + else if ((IR == 0) || (IR == 3)) /* sto or opr instruction? */ + { + MAR = MBR & ADDRESS_MASK_64KW; + m_rim_step = 2; + } + } + break; + + case 2: + /* read second word as data */ + AC = 0; + call_io_handler(io_handler_rim); + m_rim_step = 3; + m_ios = 0; + break; + + case 3: + if (! m_ios) + { /* transfer incomplete: wait some more */ + m_icount = 0; + } + else + { /* data transfer complete */ + m_ios = 0; + + tx0_write(MAR, MBR = AC); + + m_rim_step = 0; + } + break; + } + } + else + { + if (m_cycle == 0) + { /* fetch new instruction */ + MBR = tx0_read(MAR = PC); + INCREMENT_PC_64KW; + IR = MBR >> 16; /* basic opcode */ + MAR = MBR & ADDRESS_MASK_64KW; + } + + if (! m_ioh) + { + if ((m_stop_cyc0 && (m_cycle == 0)) + || (m_stop_cyc1 && (m_cycle == 1))) + m_run = 0; + + execute_instruction_64kw(); + } + + m_icount --; + } + } + while (m_icount > 0); +} + +/* execute instructions on this CPU until icount expires */ +void tx0_8kw_device::execute_run() +{ + do + { + debugger_instruction_hook(this, PC); + + + if (m_ioh && m_ios) + { + m_ioh = 0; + } + + + if ((! m_run) && (! m_rim)) + m_icount = 0; /* if processor is stopped, just burn cycles */ + else if (m_rim) + { + switch (m_rim_step) + { + case 0: + /* read first word as instruction */ + AC = 0; + call_io_handler(io_handler_rim); + m_rim_step = 1; + m_ios = 0; + break; + + case 1: + if (! m_ios) + { /* transfer incomplete: wait some more */ + m_icount = 0; + } + else + { /* data transfer complete */ + m_ios = 0; + + MBR = AC; + IR = MBR >> 13; /* basic opcode */ + if ((IR == 16) || (IR == 8)) /* trn or add instruction? */ + { + PC = MBR & ADDRESS_MASK_8KW; + m_rim = 0; /* exit read-in mode */ + m_run = (IR == 16) ? 1 : 0; /* stop if add instruction */ + m_rim_step = 0; + } + else if ((IR == 0) || (IR == 24)) /* sto or opr instruction? */ + { + MAR = MBR & ADDRESS_MASK_8KW; + m_rim_step = 2; + } + } + break; + + case 2: + /* read second word as data */ + AC = 0; + call_io_handler(io_handler_rim); + m_rim_step = 3; + m_ios = 0; + break; + + case 3: + if (! m_ios) + { /* transfer incomplete: wait some more */ + m_icount = 0; + } + else + { /* data transfer complete */ + m_ios = 0; + + tx0_write(MAR, MBR = AC); + + m_rim_step = 0; + } + break; + } + } + else + { + if (m_cycle == 0) + { /* fetch new instruction */ + MBR = tx0_read(MAR = PC); + INCREMENT_PC_8KW; + IR = MBR >> 13; /* basic opcode */ + MAR = MBR & ADDRESS_MASK_8KW; + } + + if (! m_ioh) + { + if ((m_stop_cyc0 && (m_cycle == 0)) + || (m_stop_cyc1 && (m_cycle == 1))) + m_run = 0; + + execute_instruction_8kw(); + } + + m_icount -= 1; + } + } + while (m_icount > 0); +} + + +/* execute one instruction */ +void tx0_64kw_device::execute_instruction_64kw() +{ + if (! m_cycle) + { + m_cycle = 1; /* most frequent case */ + switch (IR) + { + case 0: /* STOre */ + case 1: /* ADD */ + break; + + case 2: /* TRansfer on Negative */ + if (AC & 0400000) + { + PC = MAR & ADDRESS_MASK_64KW; + m_cycle = 0; /* instruction only takes one cycle if branch + is taken */ + } + break; + + case 3: /* OPeRate */ + if (MAR & 0100000) + /* (0.8) CLL = Clear the left nine digital positions of the AC */ + AC &= 0000777; + + if (MAR & 0040000) + /* (0.8) CLR = Clear the right nine digital positions of the AC */ + AC &= 0777000; + + if (((MAR & 0030000) >> 12) == 1) + /* (0.8) IOS In-Out Stop = Stop machine so that an In-Out command + (specified by digits 6 7 8 of MAR) may be executed */ + m_ioh = 1; + + if (((MAR & 0007000) >> 9) != 0) + { + /* ((MAR & 0007000) >> 9) is device ID */ + /* 7: */ + /* (0.8) P7H = Punch holes 1-6 in flexo tape specified by AC + digital positions 2, 5, 8, 11, 14, and 17. Also punches a 7th + hole on tape. */ + /* 6: */ + /* (0.8) P6H = Same as P7H but no seventh hole */ + /* 4: */ + /* (0.8) PNT = Print one flexowriter character specified by AC + digits 2, 5, 8, 11, 14, and 17. */ + /* 1: */ + /* (0.8) R1C = Read one line of flexo tape so that tape positions + 1, 2, 3, 4, 5, and 6 will be put in the AC digital positions 0, + 3, 6, 9, 12 and 15. */ + /* 3: */ + /* (0.8) R3C = Read one line of flexo tape into AC digits 0, 3, 6, + 9, 12 and 15. Then cycle the AC one digital position; read the + next line on tape into AC digits 0, 3, 6, 9, 12 and 15, cycle + the AC right one digital position and read the third and last + line into AC digits 0, 3, 6, 9, 12 and 15. (This command is + equal to a triple CYR-R1C.) */ + /* 2: */ + /* (0.8) DIS = Intensify a point on the scope with x and y + coordinates where x is specified by AC digits 0-8 with digit 0 + being used as the sign and y is specified by AC digits 9-17 + with digit 9 being used as the sign for y. The complement + system is in effect when the signs are negative. */ + /* (5 is undefined) */ + int index = (MAR & 0007000) >> 9; + + call_io_handler(index); + m_ioh = 1; + } + break; + } + } + else + { + m_cycle = 0; /* always true */ + switch (IR) + { + case 0: /* STOre */ + tx0_write(MAR, (MBR = AC)); + break; + + case 1: /* ADD */ + MBR = tx0_read(MAR); + + AC = AC + MBR; + AC = (AC + (AC >> 18)) & 0777777; /* propagate carry around */ + + if (AC == 0777777) /* check for -0 */ + AC = 0; + break; + + case 2: /* TRansfer on Negative */ + break; + + case 3: /* OPeRate */ + if ((MAR & 0000104) == 0000100) + /* (1.1) PEN = Read the light pen flip-flops 1 and 2 into AC(0) and + AC(1). */ + /*...*/{ } + + if ((MAR & 0000104) == 0000004) + /* (1.1) TAC = Insert a one in each digital position of the AC + wherever there is a one in the corresponding digital position + of the TAC. */ + /*...*/ { } + + if (MAR & 0000040) + /* (1.2) COM = Complement every digit in the accumulator */ + AC ^= 0777777; + + if ((MAR & 0000003) == 1) + /* (1.2) AMB = Store the contents of the AC in the MBR. */ + MBR = AC; + + if ((MAR & 0000003) == 3) + /* (1.2) TBR = Store the contents of the TBR in the MBR. */ + /*...*/ { } + + if ((MAR & 0000003) == 2) + /* (1.3) LMB = Store the contents of the LR in the MBR. */ + MBR = LR; + break; + + if (((MAR & 0000600) >> 7) == 1) + /* (1.3) MLR = Store the contents of the MBR (memory buffer + register) in the live reg. */ + LR = MBR; + + if (((MAR & 0000600) >> 7) == 2) + /* (1.4) SHR = Shift the AC right one place, i.e. multiply the AC + by 2^-1 */ + AC >>= 1; + + if (((MAR & 0000600) >> 7) == 3) + /* (1.4) CYR = Cycle the AC right one digital position (AC(17) will + become AC(0)) */ + AC = (AC >> 1) | ((AC & 1) << 17); + + if (MAR & 0000020) + /* (1.4) PAD = Partial add AC to MBR, that is, for every digital + position of the MBR that contains a one, complement the digit + in the corresponding digital position of the AC. This is also + called a half add. */ + AC ^= MBR; + + if (MAR & 0000010) + { /* (1.7) CRY = Partial add the 18 digits of the AC to the + corresponding 18 digits of the carry. + + To determine what the 18 digits of the carry are, use the + following rule: + + "Grouping the AC and MBR digits into pairs and proceeding from + right to left, assign the carry digit of the next pair to a one + if in the present pair MBR = 1 and AC = 0 or if in the present + pair AC = 1 and carry 1. + + (Note: the 0th digit pair determines the 17th pair's carry + digit)" */ + AC ^= MBR; + + AC = AC + MBR; + AC = (AC + (AC >> 18)) & 0777777; /* propagate carry around */ + + if (AC == 0777777) /* check for -0 */ + AC = 0; + } + + if (((MAR & 0030000) >> 12) == 3) + /* (1.8) Hlt = Halt the computer */ + m_run = 0; + + break; + } + } +} + +void tx0_device::indexed_address_eval() +{ + MAR = MAR + XR; + MAR = (MAR + (MAR >> 14)) & 0037777; /* propagate carry around */ + //if (MAR == 0037777) /* check for -0 */ + // MAR = 0; + if (MAR & 0020000) /* fix negative (right???) */ + MAR = (MAR + 1) & 0017777; +} + +/* execute one instruction */ +void tx0_8kw_device::execute_instruction_8kw() +{ + if (! m_cycle) + { + m_cycle = 1; /* most frequent case */ + switch (IR) + { + case 0: /* STOre */ + case 1: /* STore indeXed */ + case 2: /* Store indeX in Address */ + case 3: /* ADd One */ + case 4: /* Store LR */ + case 5: /* Store Lr indeXed */ + case 6: /* STore Zero */ + case 8: /* ADD */ + case 9: /* ADd indeXed */ + case 10: /* LoaD indeX */ + case 11: /* AUgment indeX */ + case 12: /* Load LR */ + case 13: /* Load Lr indeXed */ + case 14: /* LoaD Ac */ + case 15: /* Load Ac indeXed */ + break; + + case 16: /* TRansfer on Negative */ + if (AC & 0400000) + { + PC = MAR & 0017777; + m_cycle = 0; /* instruction only takes one cycle if branch + is taken */ + } + break; + + case 17: /* Transfer on ZEro */ + if ((AC == 0000000) || (AC == 0777777)) + { + PC = MAR & 0017777; + m_cycle = 0; /* instruction only takes one cycle if branch + is taken */ + } + break; + + case 18: /* Transfer and Set indeX */ + XR = PC; + PC = MAR & 0017777; + m_cycle = 0; /* instruction only takes one cycle if branch + is taken */ + break; + + case 19: /* Transfer and IndeX */ + if ((XR != 0000000) && (XR != 0037777)) + { + if (XR & 0020000) + XR ++; + else + XR--; + PC = MAR & 0017777; + m_cycle = 0; /* instruction only takes one cycle if branch + is taken */ + } + break; + + case 21: /* TRansfer indeXed */ + indexed_address_eval(); + case 20: /* TRAnsfer */ + PC = MAR & 0017777; + m_cycle = 0; /* instruction only takes one cycle if branch + is taken */ + break; + + case 22: /* Transfer on external LeVel */ + /*if (...) + { + PC = MAR & 0017777; + m_cycle = 0;*/ /* instruction only takes one cycle if branch + is taken */ + /*}*/ + break; + + case 24: /* OPeRate */ + case 25: + case 26: + case 27: + case 28: + case 29: + case 30: + case 31: + if (((IR & 001) == 00) && ((MAR & 017000) == 004000)) + { /* Select class instruction */ + if (IR & 004) + /* (0.8???) CLA = CLear Ac */ + AC = 0; + + /* (IOS???) SEL = SELect */ + m_sel_handler(ASSERT_LINE); + } + else + { /* Normal operate class instruction */ + if (((IR & 001) == 01) && ((MAR & 017000) == 011000)) + /* (0.6) CLL = CLear Left 9 bits of ac */ + AC &= 0000777; + + if (((IR & 001) == 01) && ((MAR & 017000) == 012000)) + /* (0.6) CLR = CLear Right 9 bits of ac */ + AC &= 0777000; + + if (IR & 002) + /* (0.7) AMB = transfer Ac to MBr */ + MBR = AC; + + if (IR & 004) + /* (0.8) CLA = CLear Ac */ + AC = 0; + + if (((IR & 001) == 01) && ((MAR & 010000) == 000000)) + { /* (IOS) In-Out group commands */ + /* ((MAR & 0007000) >> 9) is device ID */ + /* 0: */ + /* (***) CPY = CoPY synchronizes transmission of information + between in-out equipment and computer. */ + /* 1: */ + /* (IOS) R1L = Read 1 Line of tape from PETR into AC bits 0, 3, + 6, 9, 12, 15, with CYR before read (inclusive or) */ + /* 3: */ + /* (IOS) R3L = Read 3 Lines of tape from PETR into AC bits 0, + 3, 6, 9, 12, 15, with CYR before each read (inclusive or) */ + /* 2: */ + /* (IOS) DIS = DISplay a point on scope (AC bits 0-8 specify x + coordinate, AC bits 9-17 specify y coordinate). The + coordinate (0, 0) is usually at the lower left hand corner + of the scope. A console switch is available to relocate + (0,0) to the center. */ + /* 6: */ + /* (IOS) P6H = Punch one 6-bit line of flexo tape (without 7th + hole) from ac bits 2, 5, 8, 11, 14, 17. Note: lines + without 7th hole are ignored by PETR. */ + /* 7: */ + /* (IOS) P7H = same as P6H, but with 7th hole */ + /* 4: */ + /* (IOS) PRT = Print one six bit flexo character from AC bits + 2, 5, 8, 11, 14, 17. */ + /* (5 is undefined) */ + int index = (MAR & 0007000) >> 9; + + call_io_handler(index); + m_ioh = 1; + } + + if (((IR & 001) == 00) && ((MAR & 010000) == 010000)) + { /* (IOS) EX0 through EX7 = operate user's EXternal equipment. */ + switch ((MAR & 0007000) >> 9) + { + /* ... */ + } + } + } + break; + } + } + else + { + if (((IR != 2) && (IR != 3)) || (m_cycle == 2)) + m_cycle = 0; + else + m_cycle = 2; /* SXA and ADO have an extra cycle 2 */ + switch (IR) + { + case 1: /* STore indeXed */ + indexed_address_eval(); + case 0: /* STOre */ + tx0_write(MAR, (MBR = AC)); + break; + + case 2: /* Store indeX in Address */ + if (m_cycle) + { /* cycle 1 */ + MBR = tx0_read(MAR); + MBR = (MBR & 0760000) | (XR & 0017777); + } + else + { /* cycle 2 */ + tx0_write(MAR, MBR); + } + break; + + case 3: /* ADd One */ + if (m_cycle) + { /* cycle 1 */ + AC = tx0_read(MAR) + 1; + + #if 0 + AC = (AC + (AC >> 18)) & 0777777; /* propagate carry around */ + if (AC == 0777777) /* check for -0 (right???) */ + AC = 0; + #else + if (AC >= 0777777) + AC = (AC + 1) & 0777777; + #endif + } + else + { /* cycle 2 */ + tx0_write(MAR, (MBR = AC)); + } + break; + + case 5: /* Store Lr indeXed */ + indexed_address_eval(); + case 4: /* Store LR */ + tx0_write(MAR, (MBR = LR)); + break; + + case 6: /* STore Zero */ + tx0_write(MAR, (MBR = 0)); + break; + + case 9: /* ADd indeXed */ + indexed_address_eval(); + case 8: /* ADD */ + MBR = tx0_read(MAR); + + AC = AC + MBR; + AC = (AC + (AC >> 18)) & 0777777; /* propagate carry around */ + + if (AC == 0777777) /* check for -0 */ + AC = 0; + break; + + case 10: /* LoaD indeX */ + MBR = tx0_read(MAR); + XR = (MBR & 0017777) | ((MBR >> 4) & 0020000); + break; + + case 11: /* AUgment indeX */ + MBR = tx0_read(MAR); + + XR = XR + ((MBR & 0017777) | ((MBR >> 4) & 0020000)); + XR = (XR + (XR >> 14)) & 0037777; /* propagate carry around */ + + //if (XR == 0037777) /* check for -0 */ + // XR = 0; + break; + + case 13: /* Load Lr indeXed */ + indexed_address_eval(); + case 12: /* Load LR */ + LR = MBR = tx0_read(MAR); + break; + + case 15: /* Load Ac indeXed */ + indexed_address_eval(); + case 14: /* LoaD Ac */ + AC = MBR = tx0_read(MAR); + break; + + case 16: /* TRansfer on Negative */ + case 17: /* Transfer on ZEro */ + case 18: /* Transfer and Set indeX */ + case 19: /* Transfer and IndeX */ + case 20: /* TRAnsfer */ + case 21: /* TRansfer indeXed */ + case 22: /* Transfer on external LeVel */ + break; + + case 24: /* OPeRate */ + case 25: + case 26: + case 27: + case 28: + case 29: + case 30: + case 31: + if (((IR & 001) == 00) && ((MAR & 017000) == 004000)) + { /* Select class instruction */ + } + else + { /* Normal operate class instruction */ + if (((IR & 001) == 00) && ((MAR & 017000) == 003000)) + { /* (1.1) PEN = set ac bit 0 from light PEN ff, and ac bit 1 from + light gun ff. (ffs contain one if pen or gun saw displayed + point.) Then clear both light pen and light gun ffs */ + /*AC = (AC & 0177777) |?...;*/ + /*... = 0;*/ + } + + if (((IR & 001) == 00) && ((MAR & 017000) == 001000)) + /* (1.1) TAC = transfer TAC into ac (inclusive or) */ + AC |= m_tac; + + if (((IR & 001) == 00) && ((MAR & 017000) == 002000)) + /* (1.2) TBR = transfer TBR into mbr (inclusive or) */ + MBR |= m_tbr; + + if (((IR & 001) == 00) && ((MAR & 017000) == 006000)) + /* (1.2) RPF = Read Program Flag register into mbr (inclusive or) */ + MBR |= PF << 8; + + if (MAR & 0000040) + /* (1.2) COM = COMplement ac */ + AC ^= 0777777; + + if ((! (MAR & 0000400)) && (MAR & 0000100)) + { /* (1.2) XMB = Transfer XR contents to MBR */ + MBR = XR; + if (XR & 0020000) + MBR |= 0740000; + } + + if (MAR & 0000004) + { + switch (MAR & 0000003) + { + case 0000003: /* (1.2) And LR and MBR */ + MBR &= LR; + break; + + case 0000001: /* (1.3) Or LR into MBR */ + MBR |= LR; + break; + + default: + if (LOG) + logerror("unrecognized instruction"); + break; + } + } + + if (((! (MAR & 0000400)) && (MAR & 0000200)) && ((! (MAR & 0000004)) && (MAR & 0000002))) + { /* LMB and MBL used simultaneously interchange LR and MBR */ + int tmp = MBR; + MBR = LR; + LR = tmp; + } + else if ((! (MAR & 0000400)) && (MAR & 0000200)) + /* (1.4) MBL = Transfer MBR contents to LR */ + LR = MBR; + else if ((! (MAR & 0000004)) && (MAR & 0000002)) + /* (1.4) LMB = Store the contents of the LR in the MBR. */ + MBR = LR; + + if (MAR & 0000020) + /* (1.5) PAD = Partial ADd mbr to ac */ + AC ^= MBR; + + if (MAR & 0000400) + { + switch (MAR & 0000300) + { + case 0000000: /* (1.6) CYR = CYcle ac contents Right one binary + position (AC(17) -> AC(0)) */ + AC = (AC >> 1) | ((AC & 1) << 17); + break; + + case 0000200: /* (1.6) CYcle ac contents Right one binary + position (AC(0) unchanged) */ + AC = (AC >> 1) | (AC & 0400000); + break; + + default: + if (LOG) + logerror("unrecognized instruction"); + break; + } + } + + if (((IR & 001) == 00) && ((MAR & 017000) == 007000)) + /* (1.6) SPF = Set Program Flag register from mbr */ + PF = (MBR >> 8) & 077; + + if (MAR & 0000010) + { /* (1.7?) CRY = Partial ADd the 18 digits of the AC to the + corresponding 18 digits of the carry. */ + AC ^= MBR; + + AC = AC + MBR; + AC = (AC + (AC >> 18)) & 0777777; /* propagate carry around */ + + if (AC == 0777777) /* check for -0 */ + AC = 0; + } + + if ((! (MAR & 0000004)) && (MAR & 0000001)) + /* (1.8) MBX = Transfer MBR contents to XR */ + XR = (MBR & 0017777) | ((MBR >> 4) & 0020000); + + if (((IR & 001) == 01) && ((MAR & 017000) == 010000)) + /* (1.8) HLT = HaLT the computer and sound chime */ + m_run = 0; + } + break; + + default: /* Illegal */ + /* ... */ + break; + } + } +} + +/* + Simulate a pulse on reset line: + reset most registers and flip-flops, and initialize a few emulator state + variables. +*/ +void tx0_device::pulse_reset() +{ + /* processor registers */ + PC = 0; /* ??? */ + IR = 0; /* ??? */ + /*MBR = 0;*/ /* ??? */ + /*MAR = 0;*/ /* ??? */ + /*AC = 0;*/ /* ??? */ + /*LR = 0;*/ /* ??? */ + + /* processor state flip-flops */ + m_run = 0; /* ??? */ + m_rim = 0; /* ??? */ + m_ioh = 0; /* ??? */ + m_ios = 0; /* ??? */ + + m_rim_step = 0; + + /* now, we kindly ask IO devices to reset, too */ + m_io_reset_callback(ASSERT_LINE); +} + +void tx0_device::io_complete() +{ + m_ios = 1; +} + + +offs_t tx0_8kw_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( tx0_8kw ); + return CPU_DISASSEMBLE_NAME(tx0_8kw)(this, buffer, pc, oprom, opram, options); +} + + +offs_t tx0_64kw_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( tx0_64kw ); + return CPU_DISASSEMBLE_NAME(tx0_64kw)(this, buffer, pc, oprom, opram, options); +} diff --git a/src/devices/cpu/pdp1/tx0.h b/src/devices/cpu/pdp1/tx0.h new file mode 100644 index 00000000000..e88172bc8ff --- /dev/null +++ b/src/devices/cpu/pdp1/tx0.h @@ -0,0 +1,179 @@ +// license:BSD-3-Clause +// copyright-holders:Raphael Nabet +#pragma once + +#ifndef __TX0_H__ +#define __TX0_H__ + + + +/* register ids for tx0_get_reg/tx0_set_reg */ +enum +{ + TX0_MBR=1, TX0_AC, TX0_MAR, TX0_PC, TX0_IR, TX0_LR, TX0_XR, TX0_PF, + TX0_TBR, TX0_TAC, + TX0_TSS00, TX0_TSS01, TX0_TSS02, TX0_TSS03, TX0_TSS04, TX0_TSS05, TX0_TSS06, TX0_TSS07, + TX0_TSS10, TX0_TSS11, TX0_TSS12, TX0_TSS13, TX0_TSS14, TX0_TSS15, TX0_TSS16, TX0_TSS17, + TX0_CM_SEL, TX0_LR_SEL, TX0_GBL_CM_SEL, + TX0_STOP_CYC0, TX0_STOP_CYC1, + TX0_RUN, TX0_RIM, + TX0_CYCLE, TX0_IOH, TX0_IOS +}; + + +#define MCFG_TX0_CONFIG(_cpy_devcb, _r1l_devcb, _dis_devcb, _r3l_devcb, _prt_devcb, _rsv_devcb, _p6h_devcb, _p7h_devcb, _sel_devcb, _res_devcb) \ + tx0_device::set_cpy_cb(*device, DEVCB_##_cpy_devcb); \ + tx0_device::set_r1l_cb(*device, DEVCB_##_r1l_devcb); \ + tx0_device::set_dis_cb(*device, DEVCB_##_dis_devcb); \ + tx0_device::set_r3l_cb(*device, DEVCB_##_r3l_devcb); \ + tx0_device::set_prt_cb(*device, DEVCB_##_prt_devcb); \ + tx0_device::set_rsv_cb(*device, DEVCB_##_rsv_devcb); \ + tx0_device::set_p6h_cb(*device, DEVCB_##_p6h_devcb); \ + tx0_device::set_p7h_cb(*device, DEVCB_##_p7h_devcb); \ + tx0_device::set_sel_cb(*device, DEVCB_##_sel_devcb); \ + tx0_device::set_res_cb(*device, DEVCB_##_res_devcb); + + +class tx0_device : public cpu_device +{ +public: + // construction/destruction + tx0_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source, int addr_bits, int address_mask, int ir_mask); + + // static configuration helpers + template static devcb_base &set_cpy_cb(device_t &device, _Object object) { return downcast(device).m_cpy_handler.set_callback(object); } + template static devcb_base &set_r1l_cb(device_t &device, _Object object) { return downcast(device).m_r1l_handler.set_callback(object); } + template static devcb_base &set_dis_cb(device_t &device, _Object object) { return downcast(device).m_dis_handler.set_callback(object); } + template static devcb_base &set_r3l_cb(device_t &device, _Object object) { return downcast(device).m_r3l_handler.set_callback(object); } + template static devcb_base &set_prt_cb(device_t &device, _Object object) { return downcast(device).m_prt_handler.set_callback(object); } + template static devcb_base &set_rsv_cb(device_t &device, _Object object) { return downcast(device).m_rsv_handler.set_callback(object); } + template static devcb_base &set_p6h_cb(device_t &device, _Object object) { return downcast(device).m_p6h_handler.set_callback(object); } + template static devcb_base &set_p7h_cb(device_t &device, _Object object) { return downcast(device).m_p7h_handler.set_callback(object); } + template static devcb_base &set_sel_cb(device_t &device, _Object object) { return downcast(device).m_sel_handler.set_callback(object); } + template static devcb_base &set_res_cb(device_t &device, _Object object) { return downcast(device).m_io_reset_callback.set_callback(object); } + + void pulse_reset(); + void io_complete(); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_execute_interface overrides + virtual UINT32 execute_min_cycles() const { return 1; } + virtual UINT32 execute_max_cycles() const { return 3; } + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const { return (spacenum == AS_PROGRAM) ? &m_program_config : NULL; } + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const { return 4; } + virtual UINT32 disasm_max_opcode_bytes() const { return 4; } + +protected: + address_space_config m_program_config; + + /* processor registers */ + int m_mbr; /* memory buffer register (18 bits) */ + int m_ac; /* accumulator (18 bits) */ + int m_mar; /* memory address register (16 (64kW) or 13 (8kW) bits) */ + int m_pc; /* program counter (16 (64kW) or 13 (8kW) bits) */ + int m_ir; /* instruction register (2 (64kW) or 5 (8kW) bits) */ + int m_lr; /* live register (18 bits) */ + int m_xr; /* index register (14 bits) (8kW only) */ + int m_pf; /* program flags (6 bits expandable to 10) (8kW only) */ + + /* operator panel switches */ + int m_tbr; /* toggle switch buffer register (18 bits) */ + int m_tac; /* toggle switch accumulator (18 bits) */ + int m_tss[16]; /* toggle switch storage (18 bits * 16) */ + UINT16 m_cm_sel; /* individual cm select (1 bit * 16) */ + UINT16 m_lr_sel; /* individual lr select (1 bit * 16) */ + unsigned int m_gbl_cm_sel;/* global cm select (1 bit) */ + unsigned int m_stop_cyc0; /* stop on cycle 0 */ + unsigned int m_stop_cyc1; /* stop on cycle 1 */ + + /* processor state flip-flops */ + unsigned int m_run; /* processor is running */ + unsigned int m_rim; /* processor is in read-in mode */ + unsigned int m_cycle; /* 0 -> fetch */ + /* 1 -> execute (except for taken branches) */ + /* 2 -> extra execute cycle for SXA and ADO */ + + unsigned int m_ioh; /* i-o halt: processor is executing an Input-Output Transfer wait */ + unsigned int m_ios; /* i-o synchronizer: set on i-o operation completion */ + + /* additional emulator state variables */ + int m_rim_step; /* current step in rim execution */ + + int m_address_mask; /* address mask */ + int m_ir_mask; /* IR mask */ + + int m_icount; + + address_space *m_program; + + /* 8 standard I/O handlers: + 0: cpy (8kW only) + 1: r1l + 2: dis + 3: r3l + 4: prt + 5: reserved (for unimplemented typ instruction?) + 6: p6h + 7: p7h */ + devcb_write_line m_cpy_handler; + devcb_write_line m_r1l_handler; + devcb_write_line m_dis_handler; + devcb_write_line m_r3l_handler; + devcb_write_line m_prt_handler; + devcb_write_line m_rsv_handler; + devcb_write_line m_p6h_handler; + devcb_write_line m_p7h_handler; + /* select instruction handler */ + devcb_write_line m_sel_handler; + /* callback called when reset line is pulsed: IO devices should reset */ + devcb_write_line m_io_reset_callback; + + int tx0_read(offs_t address); + void tx0_write(offs_t address, int data); + void call_io_handler(int io_handler); + void indexed_address_eval(); +}; + + +class tx0_8kw_device : public tx0_device +{ +public: + // construction/destruction + tx0_8kw_device(const machine_config &mconfig, const char *_tag, device_t *_owner, UINT32 _clock); + +protected: + virtual void execute_run(); + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + +private: + void execute_instruction_8kw(); +}; + + +class tx0_64kw_device : public tx0_device +{ +public: + // construction/destruction + tx0_64kw_device(const machine_config &mconfig, const char *_tag, device_t *_owner, UINT32 _clock); + +protected: + virtual void execute_run(); + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + +private: + void execute_instruction_64kw(); +}; + + +extern const device_type TX0_64KW; +extern const device_type TX0_8KW; + +#endif /* __TX0_H__ */ diff --git a/src/devices/cpu/pdp1/tx0dasm.c b/src/devices/cpu/pdp1/tx0dasm.c new file mode 100644 index 00000000000..3d8a1daf9e1 --- /dev/null +++ b/src/devices/cpu/pdp1/tx0dasm.c @@ -0,0 +1,123 @@ +// license:BSD-3-Clause +// copyright-holders:Raphael Nabet +#include "emu.h" +#include "cpu/pdp1/tx0.h" + +CPU_DISASSEMBLE( tx0_64kw ) +{ + int md; + int x; + + md = oprom[0] << 24 | oprom[1] << 16 | oprom[2] << 8 | oprom[3]; + + x = md & 0177777; + switch (md >> 16) + { + case 0: + sprintf (buffer, "sto 0%06o", x); + break; + case 1: + sprintf (buffer, "add 0%06o", x); + break; + case 2: + sprintf (buffer, "trn 0%06o", x); + break; + case 3: + sprintf (buffer, "opr 0%06o", x); + break; + } + return 1; +} + +CPU_DISASSEMBLE( tx0_8kw ) +{ + int md; + int x; + + md = oprom[0] << 24 | oprom[1] << 16 | oprom[2] << 8 | oprom[3]; + + x = md & 0017777; + switch (md >> 13) + { + case 0: + sprintf (buffer, "sto 0%05o", x); + break; + case 1: + sprintf (buffer, "stx 0%05o", x); + break; + case 2: + sprintf (buffer, "sxa 0%05o", x); + break; + case 3: + sprintf (buffer, "ado 0%05o", x); + break; + case 4: + sprintf (buffer, "slr 0%05o", x); + break; + case 5: + sprintf (buffer, "slx 0%05o", x); + break; + case 6: + sprintf (buffer, "stz 0%05o", x); + break; + case 8: + sprintf (buffer, "add 0%05o", x); + break; + case 9: + sprintf (buffer, "adx 0%05o", x); + break; + case 10: + sprintf (buffer, "ldx 0%05o", x); + break; + case 11: + sprintf (buffer, "aux 0%05o", x); + break; + case 12: + sprintf (buffer, "llr 0%05o", x); + break; + case 13: + sprintf (buffer, "llx 0%05o", x); + break; + case 14: + sprintf (buffer, "lda 0%05o", x); + break; + case 15: + sprintf (buffer, "lax 0%05o", x); + break; + case 16: + sprintf (buffer, "trn 0%05o", x); + break; + case 17: + sprintf (buffer, "tze 0%05o", x); + break; + case 18: + sprintf (buffer, "tsx 0%05o", x); + break; + case 19: + sprintf (buffer, "tix 0%05o", x); + break; + case 20: + sprintf (buffer, "tra 0%05o", x); + break; + case 21: + sprintf (buffer, "trx 0%05o", x); + break; + case 22: + sprintf (buffer, "tlv 0%05o", x); + break; + case 24: + case 25: + case 26: + case 27: + case 28: + case 29: + case 30: + case 31: + sprintf (buffer, "opr 0%06o", md & 0177777); + break; + default: + sprintf (buffer, "illegal"); + break; + } + return 1; +} diff --git a/src/devices/cpu/pdp8/pdp8.c b/src/devices/cpu/pdp8/pdp8.c new file mode 100644 index 00000000000..d533380b87f --- /dev/null +++ b/src/devices/cpu/pdp8/pdp8.c @@ -0,0 +1,249 @@ +// license:BSD-3-Clause +// copyright-holders:Ryan Holtz +/* + First-gen DEC PDP-8 emulator skeleton + + Written by MooglyGuy +*/ + +#include "emu.h" +#include "debugger.h" +#include "pdp8.h" + +CPU_DISASSEMBLE( pdp8 ); + +#define OP ((op >> 011) & 07) + +#define MR_IND ((op >> 010) & 01) +#define MR_PAGE ((op >> 07) & 01) +#define MR_ADDR (op & 0177) + +#define IOT_DEVICE ((op >> 03) & 077) +#define IOT_IOP1 (op & 01) +#define IOT_IOP2 ((op >> 01) & 01) +#define IOT_IOP4 ((op >> 02) & 01) + +#define OPR_GROUP ((op >> 010) & 01) +#define OPR_CLA ((op >> 07) & 01) +#define OPR_CLL ((op >> 06) & 01) +#define OPR_CMA ((op >> 05) & 01) +#define OPR_CML ((op >> 04) & 01) +#define OPR_ROR ((op >> 03) & 01) +#define OPR_ROL ((op >> 02) & 01) +#define OPR_ROT2 ((op >> 01) & 01) +#define OPR_IAC (op & 01) + +#define OPR_SMA OPR_CLL +#define OPR_SZA OPR_CMA +#define OPR_SNL OPR_CML +#define OPR_REVSKIP OPR_ROR +#define OPR_OSR OPR_ROL +#define OPR_HLT OPR_ROT2 + +#define OPR_GROUP_MASK 0401 +#define OPR_GROUP1_VAL 0000 +#define OPR_GROUP2_VAL 0400 + +const device_type PDP8CPU = &device_creator; + +//------------------------------------------------- +// pdp8_device - constructor +//------------------------------------------------- + +pdp8_device::pdp8_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : cpu_device(mconfig, PDP8CPU, "PDP8CPU", tag, owner, clock, "pdp8_cpu", __FILE__), + m_program_config("program", ENDIANNESS_BIG, 12, 12), + m_pc(0), + m_ac(0), + m_mb(0), + m_ma(0), + m_sr(0), + m_l(0), + m_ir(0), + m_halt(true), + m_icount(0) +{ + // Allocate & setup +} + + +void pdp8_device::device_start() +{ + m_program = &space(AS_PROGRAM); + + // register our state for the debugger + std::string tempstr; + state_add(STATE_GENPC, "GENPC", m_pc).noshow(); + state_add(STATE_GENFLAGS, "GENFLAGS", m_l).callimport().callexport().formatstr("%1s").noshow(); + state_add(PDP8_PC, "PC", m_pc).mask(0xfff); + state_add(PDP8_AC, "AC", m_ac).mask(0xfff); + state_add(PDP8_MB, "MB", m_mb).mask(0xfff); + state_add(PDP8_MA, "MA", m_ma).mask(0xfff); + state_add(PDP8_SR, "SR", m_sr).mask(0xfff); + state_add(PDP8_L, "L", m_l).mask(0xf); + state_add(PDP8_IR, "IR", m_ir).mask(0xff); + state_add(PDP8_HALT, "HLT", m_halt).mask(0xf); + + // setup regtable + save_item(NAME(m_pc)); + save_item(NAME(m_ac)); + save_item(NAME(m_mb)); + save_item(NAME(m_ma)); + save_item(NAME(m_sr)); + save_item(NAME(m_l)); + save_item(NAME(m_ir)); + save_item(NAME(m_halt)); + + // set our instruction counter + m_icountptr = &m_icount; +} + +void pdp8_device::device_stop() +{ +} + +void pdp8_device::device_reset() +{ + m_pc = 0; + m_ac = 0; + m_mb = 0; + m_ma = 0; + m_sr = 0; + m_l = 0; + m_ir = 0; + m_halt = true; +} + + +//------------------------------------------------- +// memory_space_config - return the configuration +// of the specified address space, or NULL if +// the space doesn't exist +//------------------------------------------------- + +const address_space_config *pdp8_device::memory_space_config(address_spacenum spacenum) const +{ + if (spacenum == AS_PROGRAM) + { + return &m_program_config; + } + return NULL; +} + + +//------------------------------------------------- +// state_string_export - export state as a string +// for the debugger +//------------------------------------------------- + +void pdp8_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + switch (entry.index()) + { + case STATE_GENFLAGS: + strprintf(str, "%c", m_halt ? 'H' : '.'); + break; + } +} + + +//------------------------------------------------- +// disasm_min_opcode_bytes - return the length +// of the shortest instruction, in bytes +//------------------------------------------------- + +UINT32 pdp8_device::disasm_min_opcode_bytes() const +{ + return 2; +} + + +//------------------------------------------------- +// disasm_max_opcode_bytes - return the length +// of the longest instruction, in bytes +//------------------------------------------------- + +UINT32 pdp8_device::disasm_max_opcode_bytes() const +{ + return 2; +} + + +//------------------------------------------------- +// disasm_disassemble - call the disassembly +// helper function +//------------------------------------------------- + +offs_t pdp8_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( pdp8 ); + return CPU_DISASSEMBLE_NAME(pdp8)(this, buffer, pc, oprom, opram, options); +} + + +//************************************************************************** +// CORE EXECUTION LOOP +//************************************************************************** + +//------------------------------------------------- +// execute_min_cycles - return minimum number of +// cycles it takes for one instruction to execute +//------------------------------------------------- + +UINT32 pdp8_device::execute_min_cycles() const +{ + return 1; // TODO +} + + +//------------------------------------------------- +// execute_max_cycles - return maximum number of +// cycles it takes for one instruction to execute +//------------------------------------------------- + +UINT32 pdp8_device::execute_max_cycles() const +{ + return 3; // TODO +} + + +//------------------------------------------------- +// execute_input_lines - return the number of +// input/interrupt lines +//------------------------------------------------- + +UINT32 pdp8_device::execute_input_lines() const +{ + return 0; // TODO +} + + +//------------------------------------------------- +// execute_set_input - set the state of an input +// line during execution +//------------------------------------------------- + +void pdp8_device::execute_set_input(int inputnum, int state) +{ + // TODO +} + + +//------------------------------------------------- +// execute_run - execute a timeslice's worth of +// opcodes +//------------------------------------------------- + +void pdp8_device::execute_run() +{ + while (m_icount > 0) + { + m_pc &= 07777; + + debugger_instruction_hook(this, m_pc); + + UINT16 op = m_program->read_word(m_pc); + + --m_icount; + } +} diff --git a/src/devices/cpu/pdp8/pdp8.h b/src/devices/cpu/pdp8/pdp8.h new file mode 100644 index 00000000000..58332770dad --- /dev/null +++ b/src/devices/cpu/pdp8/pdp8.h @@ -0,0 +1,113 @@ +// license:BSD-3-Clause +// copyright-holders:Ryan Holtz +/* + First-gen DEC PDP-8 CPU emulator + + Written by MooglyGuy +*/ + +#pragma once + +#ifndef __PDP8_H__ +#define __PDP8_H__ + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> pdp8_device + +// Used by core CPU interface +class pdp8_device : public cpu_device +{ +public: + // construction/destruction + pdp8_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_stop(); + + // device_execute_interface overrides + virtual UINT32 execute_min_cycles() const; + virtual UINT32 execute_max_cycles() const; + virtual UINT32 execute_input_lines() const; + virtual void execute_run(); + virtual void execute_set_input(int inputnum, int state); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const; + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const; + virtual UINT32 disasm_max_opcode_bytes() const; + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + + // device_state_interface overrides + virtual void state_string_export(const device_state_entry &entry, std::string &str); + + // address spaces + const address_space_config m_program_config; + + enum state + { + FETCH, + DEFER, + EXECUTE, + WORD_COUNT, + CURRENT_ADDR, + BREAK + } + + enum opcode + { + AND = 0, + TAD, + ISZ, + DCA, + JMS, + JMP, + IOT, + OPR + } +private: + // CPU registers + UINT16 m_pc; + UINT16 m_ac; + UINT16 m_mb; + UINT16 m_ma; + UINT16 m_sr; + UINT8 m_l; + UINT8 m_ir; + bool m_halt; + + // other internal states + int m_icount; + + // address spaces + address_space *m_program; +}; + +// device type definition +extern const device_type PDP8CPU; + +/*************************************************************************** + REGISTER ENUMERATION +***************************************************************************/ + +enum +{ + PDP8_PC = 1, + PDP8_AC, + PDP8_MB, + PDP8_MA, + PDP8_SR, + PDP8_L, + PDP8_IR, + PDP8_HALT +}; + +CPU_DISASSEMBLE( pdp8 ); + +#endif /* __PDP8_H__ */ diff --git a/src/devices/cpu/pdp8/pdp8dasm.c b/src/devices/cpu/pdp8/pdp8dasm.c new file mode 100644 index 00000000000..18a7e3e769b --- /dev/null +++ b/src/devices/cpu/pdp8/pdp8dasm.c @@ -0,0 +1,174 @@ +// license:BSD-3-Clause +// copyright-holders:Ryan Holtz +/* + First-gen DEC PDP-8 disassembler + + Written by MooglyGuy +*/ + +#include "emu.h" + +static char *output; + +offs_t pdp8_dasm_one(char *buffer, offs_t pc, UINT16 op) +{ + UINT8 opcode = (op >> 011) & 07; + UINT16 current_page = pc & 07600; + UINT16 zero_addr = op & 0177; + UINT16 current_addr = current_page | zero_addr; + bool indirect = (op & 0400) ? true : false; + bool zero_page = (op & 0200) ? false : true; + + output = buffer; + + switch (opcode) + { + case 0: + output += sprintf(buffer, "AND %c %05o", indirect ? 'I' : ' ', zero_page ? zero_addr : current_addr); + break; + case 1: + output += sprintf(buffer, "TAD %c %05o", indirect ? 'I' : ' ', zero_page ? zero_addr : current_addr); + break; + case 2: + output += sprintf(buffer, "ISZ %c %05o", indirect ? 'I' : ' ', zero_page ? zero_addr : current_addr); + break; + case 3: + output += sprintf(buffer, "DCA %c %05o", indirect ? 'I' : ' ', zero_page ? zero_addr : current_addr); + break; + case 4: + output += sprintf(buffer, "JMS %c %05o", indirect ? 'I' : ' ', zero_page ? zero_addr : current_addr); + break; + case 5: + output += sprintf(buffer, "JMP %c %05o", indirect ? 'I' : ' ', zero_page ? zero_addr : current_addr); + break; + case 6: + output += sprintf(buffer, "IOT %03o %01o", (op >> 03) & 077, op & 07); + break; + case 7: + { + bool group2 = ((op & 0401) == 0400); + if (!group2) + { + if (!(op & 0377)) + { + output += sprintf(buffer, "NOP "); + } + else + { + if (op & 0200) + { + output += sprintf(buffer, "CLA "); + } + if (op & 0100) + { + output += sprintf(buffer, "CLL "); + } + if (op & 040) + { + output += sprintf(buffer, "CMA "); + } + if (op & 020) + { + output += sprintf(buffer, "CML "); + } + if (op & 01) + { + output += sprintf(buffer, "IAC "); + } + if (op & 010) + { + if (op & 02) + { + output += sprintf(buffer, "RTR "); + } + else + { + output += sprintf(buffer, "RAR "); + } + } + if (op & 04) + { + if (op & 02) + { + output += sprintf(buffer, "RTL "); + } + else + { + output += sprintf(buffer, "RAL "); + } + } + } + } + else + { + if (!(op & 0377)) + { + output += sprintf(buffer, "NOP "); + } + else + { + if (op & 010) + { + if (!(op & 0160)) + { + output += sprintf(buffer, "SKP "); + } + else + { + if (op & 0100) + { + output += sprintf(buffer, "SPA "); + } + if (op & 040) + { + output += sprintf(buffer, "SNA "); + } + if (op & 020) + { + output += sprintf(buffer, "SZL "); + } + } + } + else + { + if (op & 0100) + { + output += sprintf(buffer, "SMA "); + } + if (op & 040) + { + output += sprintf(buffer, "SZA "); + } + if (op & 020) + { + output += sprintf(buffer, "SNL "); + } + } + if (op & 0200) + { + output += sprintf(buffer, "CLA "); + } + if (op & 04) + { + output += sprintf(buffer, "OSR "); + } + if (op & 02) + { + output += sprintf(buffer, "HLT "); + } + } + } + } + } + + return 2 | DASMFLAG_SUPPORTED; +} + +/*****************************************************************************/ + +CPU_DISASSEMBLE( pdp8 ) +{ + UINT16 op = (*(UINT8 *)(opram + 0) << 8) | + (*(UINT8 *)(opram + 1) << 0); + return pdp8_dasm_one(buffer, pc, op); +} diff --git a/src/devices/cpu/pic16c5x/16c5xdsm.c b/src/devices/cpu/pic16c5x/16c5xdsm.c new file mode 100644 index 00000000000..45ff3154ec1 --- /dev/null +++ b/src/devices/cpu/pic16c5x/16c5xdsm.c @@ -0,0 +1,256 @@ +// license:BSD-3-Clause +// copyright-holders:Tony La Porta + /**************************************************************************\ + * Microchip PIC16C5x Emulator * + * * + * Copyright Tony La Porta * + * Originally written for the MAME project. * + * * + * * + * Addressing architecture is based on the Harvard addressing scheme. * + * * + * Many thanks to those involved in the i8039 Disassembler * + * as this was based on it. * + * * + * * + * * + * A Address to jump to. * + * B Bit address within an 8-bit file register. * + * D Destination select (0 = store result in W (accumulator)) * + * (1 = store result in file register) * + * F Register file address (00-1F). * + * K Literal field, constant data. * + * * + \**************************************************************************/ + +#include "emu.h" +#include + +static const UINT8 *rombase; +static const UINT8 *rambase; +static offs_t pcbase; +#define READOP16(A) (rombase[(A) - pcbase] | (rombase[(A) + 1 - pcbase] << 8)) +#define READARG16(A) (rambase[(A) - pcbase] | (rambase[(A) + 1 - pcbase] << 8)) + + + +typedef unsigned char byte; +typedef unsigned short int word; + +#define FMT(a,b) a, b +#define PTRS_PER_FORMAT 2 + +static const char *const regfile[32] = { "Reg$00 (IND)", "Reg$01 (TMR)", "Reg$02 (PCL)", "Reg$03 (ST)", "Reg$04 (FSR)", "Reg$05 (PTA)", "Reg$06 (PTB)", "Reg$07 (PTC)", + "Reg$08", "Reg$09", "Reg$0A", "Reg$0B", "Reg$0C", "Reg$0D", "Reg$0E", "Reg$0F", + "Reg$10", "Reg$11", "Reg$12", "Reg$13", "Reg$14", "Reg$15", "Reg$16", "Reg$17", + "Reg$18", "Reg$19", "Reg$1A", "Reg$1B", "Reg$1C", "Reg$1D", "Reg$1E", "Reg$1F" }; + +static const char *const dest[2] = { "W", "Reg" }; + +static const char *const PIC16C5xFormats[] = { + FMT("000000000000", "nop"), + FMT("000000000010", "option"), + FMT("000000000011", "sleep"), + FMT("000000000100", "clrwdt"), + FMT("000000000101", "tris Port A"), + FMT("000000000110", "tris Port B"), + FMT("000000000111", "tris Port C"), + FMT("0000001fffff", "movwf %F"), + FMT("000001000000", "clrw"), + FMT("0000011fffff", "clrf %F"), + FMT("000010dfffff", "subwf %F,%D"), + FMT("000011dfffff", "decf %F,%D"), + FMT("000100dfffff", "iorwf %F,%D"), + FMT("000101dfffff", "andwf %F,%D"), + FMT("000110dfffff", "xorwf %F,%D"), + FMT("000111dfffff", "addwf %F,%D"), + FMT("001000dfffff", "movf %F,%D"), + FMT("001001dfffff", "comf %F,%D"), + FMT("001010dfffff", "incf %F,%D"), + FMT("001011dfffff", "decfsz %F,%D"), + FMT("001100dfffff", "rrf %F,%D"), + FMT("001101dfffff", "rlf %F,%D"), + FMT("001110dfffff", "swapf %F,%D"), + FMT("001111dfffff", "incfsz %F,%D"), + FMT("0100bbbfffff", "bcf %F,%B"), + FMT("0101bbbfffff", "bsf %F,%B"), + FMT("0110bbbfffff", "btfsc %F,%B"), + FMT("0111bbbfffff", "btfss %F,%B"), + FMT("1000kkkkkkkk", "retlw %K"), + FMT("1001aaaaaaaa", "call %A"), + FMT("101aaaaaaaaa", "goto %A"), + FMT("1100kkkkkkkk", "movlw %K"), + FMT("1101kkkkkkkk", "iorlw %K"), + FMT("1110kkkkkkkk", "andlw %K"), + FMT("1111kkkkkkkk", "xorlw %K"), + NULL +}; + +#define MAX_OPS ((ARRAY_LENGTH(PIC16C5xFormats) - 1) / PTRS_PER_FORMAT) + +struct PIC16C5xOpcode { + word mask; /* instruction mask */ + word bits; /* constant bits */ + word extcode; /* value that gets extension code */ + const char *parse; /* how to parse bits */ + const char *fmt; /* instruction format */ +}; + +static PIC16C5xOpcode Op[MAX_OPS+1]; +static int OpInizialized = 0; + +static void InitDasm16C5x(void) +{ + const char *p; + const char *const *ops; + word mask, bits; + int bit; + int i; + + ops = PIC16C5xFormats; i = 0; + while (*ops) + { + p = *ops; + mask = 0; bits = 0; bit = 11; + while (*p && bit >= 0) + { + switch (*p++) + { + case '1': mask |= 1<= 0) + { + /* osd_printf_debug("{%c/%d}",*cp,bit); */ + switch(*cp) + { + case 'a': a <<=1; a |= ((code & (1< +#include + +#include "16c5xdsm.c" + + +unsigned char *Buffer; + + +int main(int argc,char *argv[]) +{ + int length=0, length_to_dump=0, offset=0, disasm_words=0; + int filelength=0, bytes_read; + int Counter=0; + + FILE *F; + char *String_Output; + + if(argc<2) + { + printf("\n"); + printf("PIC16C5x Disassembler 1.0 by Tony La Porta (C)2003+\n\n"); + printf("Usage: dis16c5x [ [ ] ]\n"); + printf(" source file data must be MSB first\n"); + printf(" starting address to disassemble from (decimal)\n"); + printf(" number of addresses to disassemble (decimal)\n"); + printf(" Precede values with 0x if HEX values preffered\n"); + exit(1); + } + + if(!(F=fopen(argv[1],"rb"))) + { + printf("\n%s: Can't open file %s\n",argv[0],argv[1]); + exit(2); + } + argv++; argc--; + if (argv[1]) + { + offset = strtol(argv[1],NULL,0); + argv++; argc--; + } + if (argv[1]) + { + length = strtol(argv[1],NULL,0); + argv++; argc--; + } + + fseek(F,0, SEEK_END); + filelength = ftell(F); + + length *= 2; + + if ((length > (filelength - (offset*2))) || (length == 0)) length = filelength - (offset*2); + printf("Length=%04Xh(words) Offset=$%04Xh filelength=%04Xh(words) %04Xh(bytes)\n",length/2,offset,filelength/2,filelength); + length_to_dump = length; + printf("Starting from %d, dumping %d opcodes (word size)\n",offset,length/2); + Buffer = calloc((filelength+1),sizeof(char)); + if (Buffer==NULL) + { + printf("Out of Memory !!!"); + fclose(F); + exit(3); + } + String_Output = calloc(80,sizeof(char)); + if (String_Output==NULL) + { + printf("Out of Memory !!!"); + free(Buffer); + fclose(F); + exit(4); + } + + if (fseek(F,0,SEEK_SET) != 0) + { + printf("Error seeking to beginning of file\n"); + free(String_Output); + free(Buffer); + fclose(F); + exit(5); + } + + Counter = offset; + bytes_read = fread(Buffer,sizeof(char),filelength,F); + if (bytes_read >= length) + { + for (; length > 0; length -= (disasm_words*2)) + { + int ii; + disasm_words = Dasm16C5x(String_Output,Counter); + printf("$%03X: ",Counter); + for (ii = 0; ii < disasm_words; ii++) + { + if (((Counter*2) + ii) > filelength) /* Past end of length to dump ? */ + { + sprintf(String_Output,"???? dw %02.2X%02.2Xh (Past end of disassembly !)",Buffer[((Counter-1)*2)+1],Buffer[((Counter-1)*2)]); + } + else + { + printf("%02.2x%02.2x ",Buffer[(Counter*2)+1],Buffer[(Counter*2)]); + } + Counter++ ; + } + for (; ii < 4; ii++) + { + printf(" "); + } + printf("\t%s\n",String_Output); + } + } + else + { + printf("ERROR length to dump was %d ", length_to_dump/2); + printf(", but bytes read from file were %d\n", bytes_read/2); + free(String_Output); + free(Buffer); + fclose(F); + exit(7); + } + free(String_Output); + free(Buffer); + fclose(F); + return(0); +} diff --git a/src/devices/cpu/pic16c5x/pic16c5x.c b/src/devices/cpu/pic16c5x/pic16c5x.c new file mode 100644 index 00000000000..3acd46944f7 --- /dev/null +++ b/src/devices/cpu/pic16c5x/pic16c5x.c @@ -0,0 +1,1123 @@ +// license:BSD-3-Clause +// copyright-holders:Tony La Porta + /**************************************************************************\ + * Microchip PIC16C5x Emulator * + * * + * Copyright Tony La Porta * + * Originally written for the MAME project. * + * * + * * + * Addressing architecture is based on the Harvard addressing scheme. * + * * + * * + * **** Change Log **** * + * TLP (06-Apr-2003) * + * - First Public release. * + * BO (07-Apr-2003) Ver 1.01 * + * - Renamed 'sleep' function to 'sleepic' to avoid C conflicts. * + * TLP (09-Apr-2003) Ver 1.10 * + * - Fixed modification of file register $03 (Status). * + * - Corrected support for 7FFh (12-bit) size ROMs. * + * - The 'call' and 'goto' instructions weren't correctly handling the * + * STATUS page info correctly. * + * - The FSR register was incorrectly oring the data with 0xe0 when read. * + * - Prescaler masking information was set to 3 instead of 7. * + * - Prescaler assign bit was set to 4 instead of 8. * + * - Timer source and edge select flags/masks were wrong. * + * - Corrected the memory bank selection in GET/SET_REGFILE and also the * + * indirect register addressing. * + * BMP (18-May-2003) Ver 1.11 * + * - pic16c5x_get_reg functions were missing 'returns'. * + * TLP (27-May-2003) Ver 1.12 * + * - Fixed the WatchDog timer count. * + * - The Prescaler rate was incorrectly being zeroed, instead of the * + * actual Prescaler counter in the CLRWDT and SLEEP instructions. * + * - Added masking to the FSR register. Upper unused bits are always 1. * + * TLP (27-Aug-2009) Ver 1.13 * + * - Indirect addressing was not taking into account special purpose * + * memory mapped locations. * + * - 'iorlw' instruction was saving the result to memory instead of * + * the W register. * + * - 'tris' instruction no longer modifies Port-C on PIC models that * + * do not have Port-C implemented. * + * TLP (07-Sep-2009) Ver 1.14 * + * - Edge sense control for the T0 count input was incorrectly reversed * + * * + * * + * **** Notes: **** * + * PIC WatchDog Timer has a separate internal clock. For the moment, we're * + * basing the count on a 4MHz input clock, since 4MHz is the typical * + * input frequency (but by no means always). * + * A single scaler is available for the Counter/Timer or WatchDog Timer. * + * When connected to the Counter/Timer, it functions as a Prescaler, * + * hence prescale overflows, tick the Counter/Timer. * + * When connected to the WatchDog Timer, it functions as a Postscaler * + * hence WatchDog Timer overflows, tick the Postscaler. This scenario * + * means that the WatchDog timeout occurs when the Postscaler has * + * reached the scaler rate value, not when the WatchDog reaches zero. * + * CLRWDT should prevent the WatchDog Timer from timing out and generating * + * a device reset, but how is not known. The manual also mentions that * + * the WatchDog Timer can only be disabled during ROM programming, and * + * no other means seem to exist??? * + * * + \**************************************************************************/ + +#include "emu.h" +#include "debugger.h" +#include "pic16c5x.h" + + +const device_type PIC16C54 = &device_creator; +const device_type PIC16C55 = &device_creator; +const device_type PIC16C56 = &device_creator; +const device_type PIC16C57 = &device_creator; +const device_type PIC16C58 = &device_creator; + + +/**************************************************************************** + * Internal Memory Maps + ****************************************************************************/ + +static ADDRESS_MAP_START( pic16c5x_rom_9, AS_PROGRAM, 16, pic16c5x_device ) + AM_RANGE(0x000, 0x1ff) AM_ROM +ADDRESS_MAP_END + +static ADDRESS_MAP_START( pic16c5x_ram_5, AS_DATA, 8, pic16c5x_device ) + AM_RANGE(0x00, 0x07) AM_RAM + AM_RANGE(0x08, 0x0f) AM_RAM + AM_RANGE(0x10, 0x1f) AM_RAM +ADDRESS_MAP_END + +static ADDRESS_MAP_START( pic16c5x_rom_10, AS_PROGRAM, 16, pic16c5x_device ) + AM_RANGE(0x000, 0x3ff) AM_ROM +ADDRESS_MAP_END + +static ADDRESS_MAP_START( pic16c5x_rom_11, AS_PROGRAM, 16, pic16c5x_device ) + AM_RANGE(0x000, 0x7ff) AM_ROM +ADDRESS_MAP_END + +static ADDRESS_MAP_START( pic16c5x_ram_7, AS_DATA, 8, pic16c5x_device ) + AM_RANGE(0x00, 0x07) AM_RAM AM_MIRROR(0x60) + AM_RANGE(0x08, 0x0f) AM_RAM AM_MIRROR(0x60) + AM_RANGE(0x10, 0x1f) AM_RAM + AM_RANGE(0x30, 0x3f) AM_RAM + AM_RANGE(0x50, 0x5f) AM_RAM + AM_RANGE(0x70, 0x7f) AM_RAM +ADDRESS_MAP_END + + +pic16c5x_device::pic16c5x_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, int program_width, int data_width, int picmodel) + : cpu_device(mconfig, type, name, tag, owner, clock, shortname, __FILE__) + , m_program_config("program", ENDIANNESS_LITTLE, 16, program_width, -1 + , ( ( program_width == 9 ) ? ADDRESS_MAP_NAME(pic16c5x_rom_9) : ( ( program_width == 10 ) ? ADDRESS_MAP_NAME(pic16c5x_rom_10) : ADDRESS_MAP_NAME(pic16c5x_rom_11) ))) + , m_data_config("data", ENDIANNESS_LITTLE, 8, data_width, 0 + , ( ( data_width == 5 ) ? ADDRESS_MAP_NAME(pic16c5x_ram_5) : ADDRESS_MAP_NAME(pic16c5x_ram_7) ) ) + , m_reset_vector((program_width == 9) ? 0x1ff : ((program_width == 10) ? 0x3ff : 0x7ff)) + , m_picmodel(picmodel) + , m_temp_config(0) + , m_picRAMmask((data_width == 5) ? 0x1f : 0x7f) + , m_read_a(*this) + , m_read_b(*this) + , m_read_c(*this) + , m_write_a(*this) + , m_write_b(*this) + , m_write_c(*this) + , m_read_t0(*this) +{ +} + + +pic16c54_device::pic16c54_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : pic16c5x_device(mconfig, PIC16C54, "PIC16C54", tag, owner, clock, "pic16c54", 9, 5, 0x16C54) +{ +} + +pic16c55_device::pic16c55_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : pic16c5x_device(mconfig, PIC16C55, "PIC16C55", tag, owner, clock, "pic16c55", 9, 5, 0x16C55) +{ +} + +pic16c56_device::pic16c56_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : pic16c5x_device(mconfig, PIC16C56, "PIC16C56", tag, owner, clock, "pic16c56", 10, 5, 0x16C56) +{ +} + +pic16c57_device::pic16c57_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : pic16c5x_device(mconfig, PIC16C57, "PIC16C57", tag, owner, clock, "pic16c57", 11, 7, 0x16C57) +{ +} + +pic16c58_device::pic16c58_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : pic16c5x_device(mconfig, PIC16C58, "PIC16C58", tag, owner, clock, "pic16c58", 11, 7, 0x16C58) +{ +} + + +offs_t pic16c5x_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( pic16c5x ); + return CPU_DISASSEMBLE_NAME(pic16c5x)(this, buffer, pc, oprom, opram, options); +} + + +void pic16c5x_device::update_internalram_ptr() +{ + m_internalram = (UINT8 *)m_data->get_write_ptr(0x00); +} + + + +#define PIC16C5x_RDOP(A) (m_direct->read_word((A)<<1)) +#define PIC16C5x_RAM_RDMEM(A) ((UINT8)m_data->read_byte(A)) +#define PIC16C5x_RAM_WRMEM(A,V) (m_data->write_byte(A,V)) + +#define M_RDRAM(A) (((A) < 8) ? m_internalram[A] : PIC16C5x_RAM_RDMEM(A)) +#define M_WRTRAM(A,V) do { if ((A) < 8) m_internalram[A] = (V); else PIC16C5x_RAM_WRMEM(A,V); } while (0) +#define M_RDOP(A) PIC16C5x_RDOP(A) +#define ADDR_MASK 0x7ff + + + +#define TMR0 m_internalram[1] +#define PCL m_internalram[2] +#define STATUS m_internalram[3] +#define FSR m_internalram[4] +#define PORTA m_internalram[5] +#define PORTB m_internalram[6] +#define PORTC m_internalram[7] +#define INDF M_RDRAM(FSR) + +#define ADDR (m_opcode.b.l & 0x1f) + +#define RISING_EDGE_T0 (( (int)(T0_in - m_old_T0) > 0) ? 1 : 0) +#define FALLING_EDGE_T0 (( (int)(T0_in - m_old_T0) < 0) ? 1 : 0) + + +/******** The following is the Status Flag register definition. *********/ + /* | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | */ + /* | PA | TO | PD | Z | DC | C | */ +#define PA_REG 0xe0 /* PA Program Page Preselect - bit 8 is unused here */ +#define TO_FLAG 0x10 /* TO Time Out flag (WatchDog) */ +#define PD_FLAG 0x08 /* PD Power Down flag */ +#define Z_FLAG 0x04 /* Z Zero Flag */ +#define DC_FLAG 0x02 /* DC Digit Carry/Borrow flag (Nibble) */ +#define C_FLAG 0x01 /* C Carry/Borrow Flag (Byte) */ + +#define PA (STATUS & PA_REG) +#define TO (STATUS & TO_FLAG) +#define PD (STATUS & PD_FLAG) +#define ZERO (STATUS & Z_FLAG) +#define DC (STATUS & DC_FLAG) +#define CARRY (STATUS & C_FLAG) + + +/******** The following is the Option Flag register definition. *********/ + /* | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | */ + /* | 0 | 0 | TOCS | TOSE | PSA | PS | */ +#define T0CS_FLAG 0x20 /* TOCS Timer 0 clock source select */ +#define T0SE_FLAG 0x10 /* TOSE Timer 0 clock source edge select */ +#define PSA_FLAG 0x08 /* PSA Prescaler Assignment bit */ +#define PS_REG 0x07 /* PS Prescaler Rate select */ + +#define T0CS (m_OPTION & T0CS_FLAG) +#define T0SE (m_OPTION & T0SE_FLAG) +#define PSA (m_OPTION & PSA_FLAG) +#define PS (m_OPTION & PS_REG) + + +/******** The following is the Config Flag register definition. *********/ + /* | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | */ + /* | CP | WDTE | FOSC | */ + /* CP Code Protect (ROM read protect) */ +#define WDTE_FLAG 0x04 /* WDTE WatchDog Timer enable */ +#define FOSC_FLAG 0x03 /* FOSC Oscillator source select */ + +#define WDTE (m_CONFIG & WDTE_FLAG) +#define FOSC (m_CONFIG & FOSC_FLAG) + + +/************************************************************************ + * Shortcuts + ************************************************************************/ + +#define CLR(flagreg, flag) ( flagreg &= (UINT8)(~flag) ) +#define SET(flagreg, flag) ( flagreg |= flag ) + + +/* Easy bit position selectors */ +#define POS ((m_opcode.b.l >> 5) & 7) +static const unsigned int bit_clr[8] = { 0xfe, 0xfd, 0xfb, 0xf7, 0xef, 0xdf, 0xbf, 0x7f }; +static const unsigned int bit_set[8] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 }; + + + +void pic16c5x_device::CALCULATE_Z_FLAG() +{ + if (m_ALU == 0) SET(STATUS, Z_FLAG); + else CLR(STATUS, Z_FLAG); +} + +void pic16c5x_device::CALCULATE_ADD_CARRY() +{ + if ((UINT8)(m_old_data) > (UINT8)(m_ALU)) { + SET(STATUS, C_FLAG); + } + else { + CLR(STATUS, C_FLAG); + } +} + +void pic16c5x_device::CALCULATE_ADD_DIGITCARRY() +{ + if (((UINT8)(m_old_data) & 0x0f) > ((UINT8)(m_ALU) & 0x0f)) { + SET(STATUS, DC_FLAG); + } + else { + CLR(STATUS, DC_FLAG); + } +} + +void pic16c5x_device::CALCULATE_SUB_CARRY() +{ + if ((UINT8)(m_old_data) < (UINT8)(m_ALU)) { + CLR(STATUS, C_FLAG); + } + else { + SET(STATUS, C_FLAG); + } +} + +void pic16c5x_device::CALCULATE_SUB_DIGITCARRY() +{ + if (((UINT8)(m_old_data) & 0x0f) < ((UINT8)(m_ALU) & 0x0f)) { + CLR(STATUS, DC_FLAG); + } + else { + SET(STATUS, DC_FLAG); + } +} + + + +UINT16 pic16c5x_device::POP_STACK() +{ + UINT16 data = m_STACK[1]; + m_STACK[1] = m_STACK[0]; + return (data & ADDR_MASK); +} +void pic16c5x_device::PUSH_STACK(UINT16 data) +{ + m_STACK[0] = m_STACK[1]; + m_STACK[1] = (data & ADDR_MASK); +} + + + +UINT8 pic16c5x_device::GET_REGFILE(offs_t addr) /* Read from internal memory */ +{ + UINT8 data; + + if (addr == 0) { /* Indirect addressing */ + addr = (FSR & m_picRAMmask); + } + + if ((m_picmodel == 0x16C57) || (m_picmodel == 0x16C58)) { + addr |= (FSR & 0x60); /* FSR bits 6-5 are used for banking in direct mode */ + } + + if ((addr & 0x10) == 0) addr &= 0x0f; + + switch(addr) + { + case 00: /* Not an actual register, so return 0 */ + data = 0; + break; + case 04: data = (FSR | (UINT8)(~m_picRAMmask)); + break; + case 05: data = m_read_a(PIC16C5x_PORTA, 0xff); + data &= m_TRISA; + data |= ((UINT8)(~m_TRISA) & PORTA); + data &= 0x0f; /* 4-bit port (only lower 4 bits used) */ + break; + case 06: data = m_read_b(PIC16C5x_PORTB, 0xff); + data &= m_TRISB; + data |= ((UINT8)(~m_TRISB) & PORTB); + break; + case 07: if ((m_picmodel == 0x16C55) || (m_picmodel == 0x16C57)) { + data = m_read_c(PIC16C5x_PORTC, 0xff); + data &= m_TRISC; + data |= ((UINT8)(~m_TRISC) & PORTC); + } + else { /* PIC16C54, PIC16C56, PIC16C58 */ + data = M_RDRAM(addr); + } + break; + default: data = M_RDRAM(addr); + break; + } + return data; +} + +void pic16c5x_device::STORE_REGFILE(offs_t addr, UINT8 data) /* Write to internal memory */ +{ + if (addr == 0) { /* Indirect addressing */ + addr = (FSR & m_picRAMmask); + } + + if ((m_picmodel == 0x16C57) || (m_picmodel == 0x16C58)) { + addr |= (FSR & 0x60); /* FSR bits 6-5 are used for banking in direct mode */ + } + + if ((addr & 0x10) == 0) addr &= 0x0f; + + switch(addr) + { + case 00: /* Not an actual register, nothing to save */ + break; + case 01: m_delay_timer = 2; /* Timer starts after next two instructions */ + if (PSA == 0) m_prescaler = 0; /* Must clear the Prescaler */ + TMR0 = data; + break; + case 02: PCL = data; + m_PC = ((STATUS & PA_REG) << 4) | data; + break; + case 03: STATUS &= (UINT8)(~PA_REG); STATUS |= (data & PA_REG); + break; + case 04: FSR = (data | (UINT8)(~m_picRAMmask)); + break; + case 05: data &= 0x0f; /* 4-bit port (only lower 4 bits used) */ + m_write_a(PIC16C5x_PORTA, data & (UINT8)(~m_TRISA), 0xff); + PORTA = data; + break; + case 06: m_write_b(PIC16C5x_PORTB, data & (UINT8)(~m_TRISB), 0xff); + PORTB = data; + break; + case 07: if ((m_picmodel == 0x16C55) || (m_picmodel == 0x16C57)) { + m_write_c(PIC16C5x_PORTC, data & (UINT8)(~m_TRISC), 0xff); + PORTC = data; + } + else { /* PIC16C54, PIC16C56, PIC16C58 */ + M_WRTRAM(addr, data); + } + break; + default: M_WRTRAM(addr, data); + break; + } +} + + +void pic16c5x_device::STORE_RESULT(offs_t addr, UINT8 data) +{ + if (m_opcode.b.l & 0x20) + { + STORE_REGFILE(addr, data); + } + else + { + m_W = data; + } +} + + +/************************************************************************ + * Emulate the Instructions + ************************************************************************/ + +/* This following function is here to fill in the void for */ +/* the opcode call function. This function is never called. */ + + +void pic16c5x_device::illegal() +{ + logerror("PIC16C5x: PC=%03x, Illegal opcode = %04x\n", (m_PC-1), m_opcode.w.l); +} + + +void pic16c5x_device::addwf() +{ + m_old_data = GET_REGFILE(ADDR); + m_ALU = m_old_data + m_W; + STORE_RESULT(ADDR, m_ALU); + CALCULATE_Z_FLAG(); + CALCULATE_ADD_CARRY(); + CALCULATE_ADD_DIGITCARRY(); +} + +void pic16c5x_device::andwf() +{ + m_ALU = GET_REGFILE(ADDR) & m_W; + STORE_RESULT(ADDR, m_ALU); + CALCULATE_Z_FLAG(); +} + +void pic16c5x_device::andlw() +{ + m_ALU = m_opcode.b.l & m_W; + m_W = m_ALU; + CALCULATE_Z_FLAG(); +} + +void pic16c5x_device::bcf() +{ + m_ALU = GET_REGFILE(ADDR); + m_ALU &= bit_clr[POS]; + STORE_REGFILE(ADDR, m_ALU); +} + +void pic16c5x_device::bsf() +{ + m_ALU = GET_REGFILE(ADDR); + m_ALU |= bit_set[POS]; + STORE_REGFILE(ADDR, m_ALU); +} + +void pic16c5x_device::btfss() +{ + if ((GET_REGFILE(ADDR) & bit_set[POS]) == bit_set[POS]) + { + m_PC++ ; + PCL = m_PC & 0xff; + m_inst_cycles += 1; /* Add NOP cycles */ + } +} + +void pic16c5x_device::btfsc() +{ + if ((GET_REGFILE(ADDR) & bit_set[POS]) == 0) + { + m_PC++ ; + PCL = m_PC & 0xff; + m_inst_cycles += 1; /* Add NOP cycles */ + } +} + +void pic16c5x_device::call() +{ + PUSH_STACK(m_PC); + m_PC = ((STATUS & PA_REG) << 4) | m_opcode.b.l; + m_PC &= 0x6ff; + PCL = m_PC & 0xff; +} + +void pic16c5x_device::clrw() +{ + m_W = 0; + SET(STATUS, Z_FLAG); +} + +void pic16c5x_device::clrf() +{ + STORE_REGFILE(ADDR, 0); + SET(STATUS, Z_FLAG); +} + +void pic16c5x_device::clrwdt() +{ + m_WDT = 0; + if (PSA) m_prescaler = 0; + SET(STATUS, TO_FLAG); + SET(STATUS, PD_FLAG); +} + +void pic16c5x_device::comf() +{ + m_ALU = (UINT8)(~(GET_REGFILE(ADDR))); + STORE_RESULT(ADDR, m_ALU); + CALCULATE_Z_FLAG(); +} + +void pic16c5x_device::decf() +{ + m_ALU = GET_REGFILE(ADDR) - 1; + STORE_RESULT(ADDR, m_ALU); + CALCULATE_Z_FLAG(); +} + +void pic16c5x_device::decfsz() +{ + m_ALU = GET_REGFILE(ADDR) - 1; + STORE_RESULT(ADDR, m_ALU); + if (m_ALU == 0) + { + m_PC++ ; + PCL = m_PC & 0xff; + m_inst_cycles += 1; /* Add NOP cycles */ + } +} + +void pic16c5x_device::goto_op() +{ + m_PC = ((STATUS & PA_REG) << 4) | (m_opcode.w.l & 0x1ff); + m_PC &= ADDR_MASK; + PCL = m_PC & 0xff; +} + +void pic16c5x_device::incf() +{ + m_ALU = GET_REGFILE(ADDR) + 1; + STORE_RESULT(ADDR, m_ALU); + CALCULATE_Z_FLAG(); +} + +void pic16c5x_device::incfsz() +{ + m_ALU = GET_REGFILE(ADDR) + 1; + STORE_RESULT(ADDR, m_ALU); + if (m_ALU == 0) + { + m_PC++ ; + PCL = m_PC & 0xff; + m_inst_cycles += 1; /* Add NOP cycles */ + } +} + +void pic16c5x_device::iorlw() +{ + m_ALU = m_opcode.b.l | m_W; + m_W = m_ALU; + CALCULATE_Z_FLAG(); +} + +void pic16c5x_device::iorwf() +{ + m_ALU = GET_REGFILE(ADDR) | m_W; + STORE_RESULT(ADDR, m_ALU); + CALCULATE_Z_FLAG(); +} + +void pic16c5x_device::movf() +{ + m_ALU = GET_REGFILE(ADDR); + STORE_RESULT(ADDR, m_ALU); + CALCULATE_Z_FLAG(); +} + +void pic16c5x_device::movlw() +{ + m_W = m_opcode.b.l; +} + +void pic16c5x_device::movwf() +{ + STORE_REGFILE(ADDR, m_W); +} + +void pic16c5x_device::nop() +{ + /* Do nothing */ +} + +void pic16c5x_device::option() +{ + m_OPTION = m_W & (T0CS_FLAG | T0SE_FLAG | PSA_FLAG | PS_REG); +} + +void pic16c5x_device::retlw() +{ + m_W = m_opcode.b.l; + m_PC = POP_STACK(); + PCL = m_PC & 0xff; +} + +void pic16c5x_device::rlf() +{ + m_ALU = GET_REGFILE(ADDR); + m_ALU <<= 1; + if (STATUS & C_FLAG) m_ALU |= 1; + if (GET_REGFILE(ADDR) & 0x80) SET(STATUS, C_FLAG); + else CLR(STATUS, C_FLAG); + STORE_RESULT(ADDR, m_ALU); +} + +void pic16c5x_device::rrf() +{ + m_ALU = GET_REGFILE(ADDR); + m_ALU >>= 1; + if (STATUS & C_FLAG) m_ALU |= 0x80; + if (GET_REGFILE(ADDR) & 1) SET(STATUS, C_FLAG); + else CLR(STATUS, C_FLAG); + STORE_RESULT(ADDR, m_ALU); +} + +void pic16c5x_device::sleepic() +{ + if (WDTE) m_WDT = 0; + if (PSA) m_prescaler = 0; + SET(STATUS, TO_FLAG); + CLR(STATUS, PD_FLAG); +} + +void pic16c5x_device::subwf() +{ + m_old_data = GET_REGFILE(ADDR); + m_ALU = m_old_data - m_W; + STORE_RESULT(ADDR, m_ALU); + CALCULATE_Z_FLAG(); + CALCULATE_SUB_CARRY(); + CALCULATE_SUB_DIGITCARRY(); +} + +void pic16c5x_device::swapf() +{ + m_ALU = ((GET_REGFILE(ADDR) << 4) & 0xf0); + m_ALU |= ((GET_REGFILE(ADDR) >> 4) & 0x0f); + STORE_RESULT(ADDR, m_ALU); +} + +void pic16c5x_device::tris() +{ + switch(m_opcode.b.l & 0x7) + { + case 05: if (m_TRISA == m_W) break; + else { m_TRISA = m_W | 0xf0; m_write_a(PIC16C5x_PORTA, PORTA & (UINT8)(~m_TRISA) & 0x0f, 0xff); break; } + case 06: if (m_TRISB == m_W) break; + else { m_TRISB = m_W; m_write_b(PIC16C5x_PORTB, PORTB & (UINT8)(~m_TRISB), 0xff); break; } + case 07: if ((m_picmodel == 0x16C55) || (m_picmodel == 0x16C57)) { + if (m_TRISC == m_W) break; + else { m_TRISC = m_W; m_write_c(PIC16C5x_PORTC, PORTC & (UINT8)(~m_TRISC), 0xff); break; } + } + else { + illegal(); break; + } + default: illegal(); break; + } +} + +void pic16c5x_device::xorlw() +{ + m_ALU = m_W ^ m_opcode.b.l; + m_W = m_ALU; + CALCULATE_Z_FLAG(); +} + +void pic16c5x_device::xorwf() +{ + m_ALU = GET_REGFILE(ADDR) ^ m_W; + STORE_RESULT(ADDR, m_ALU); + CALCULATE_Z_FLAG(); +} + + + + +/*********************************************************************** + * Opcode Table (Cycles, Instruction) + ***********************************************************************/ + +const pic16c5x_device::pic16c5x_opcode pic16c5x_device::s_opcode_main[256]= +{ +/*00*/ {1, &pic16c5x_device::nop },{0, &pic16c5x_device::illegal },{1, &pic16c5x_device::movwf },{1, &pic16c5x_device::movwf }, + {1, &pic16c5x_device::clrw },{0, &pic16c5x_device::illegal },{1, &pic16c5x_device::clrf },{1, &pic16c5x_device::clrf }, +/*08*/ {1, &pic16c5x_device::subwf },{1, &pic16c5x_device::subwf },{1, &pic16c5x_device::subwf },{1, &pic16c5x_device::subwf }, + {1, &pic16c5x_device::decf },{1, &pic16c5x_device::decf },{1, &pic16c5x_device::decf },{1, &pic16c5x_device::decf }, +/*10*/ {1, &pic16c5x_device::iorwf },{1, &pic16c5x_device::iorwf },{1, &pic16c5x_device::iorwf },{1, &pic16c5x_device::iorwf }, + {1, &pic16c5x_device::andwf },{1, &pic16c5x_device::andwf },{1, &pic16c5x_device::andwf },{1, &pic16c5x_device::andwf }, +/*18*/ {1, &pic16c5x_device::xorwf },{1, &pic16c5x_device::xorwf },{1, &pic16c5x_device::xorwf },{1, &pic16c5x_device::xorwf }, + {1, &pic16c5x_device::addwf },{1, &pic16c5x_device::addwf },{1, &pic16c5x_device::addwf },{1, &pic16c5x_device::addwf }, +/*20*/ {1, &pic16c5x_device::movf },{1, &pic16c5x_device::movf },{1, &pic16c5x_device::movf },{1, &pic16c5x_device::movf }, + {1, &pic16c5x_device::comf },{1, &pic16c5x_device::comf },{1, &pic16c5x_device::comf },{1, &pic16c5x_device::comf }, +/*28*/ {1, &pic16c5x_device::incf },{1, &pic16c5x_device::incf },{1, &pic16c5x_device::incf },{1, &pic16c5x_device::incf }, + {1, &pic16c5x_device::decfsz },{1, &pic16c5x_device::decfsz },{1, &pic16c5x_device::decfsz },{1, &pic16c5x_device::decfsz }, +/*30*/ {1, &pic16c5x_device::rrf },{1, &pic16c5x_device::rrf },{1, &pic16c5x_device::rrf },{1, &pic16c5x_device::rrf }, + {1, &pic16c5x_device::rlf },{1, &pic16c5x_device::rlf },{1, &pic16c5x_device::rlf },{1, &pic16c5x_device::rlf }, +/*38*/ {1, &pic16c5x_device::swapf },{1, &pic16c5x_device::swapf },{1, &pic16c5x_device::swapf },{1, &pic16c5x_device::swapf }, + {1, &pic16c5x_device::incfsz },{1, &pic16c5x_device::incfsz },{1, &pic16c5x_device::incfsz },{1, &pic16c5x_device::incfsz }, +/*40*/ {1, &pic16c5x_device::bcf },{1, &pic16c5x_device::bcf },{1, &pic16c5x_device::bcf },{1, &pic16c5x_device::bcf }, + {1, &pic16c5x_device::bcf },{1, &pic16c5x_device::bcf },{1, &pic16c5x_device::bcf },{1, &pic16c5x_device::bcf }, +/*48*/ {1, &pic16c5x_device::bcf },{1, &pic16c5x_device::bcf },{1, &pic16c5x_device::bcf },{1, &pic16c5x_device::bcf }, + {1, &pic16c5x_device::bcf },{1, &pic16c5x_device::bcf },{1, &pic16c5x_device::bcf },{1, &pic16c5x_device::bcf }, +/*50*/ {1, &pic16c5x_device::bsf },{1, &pic16c5x_device::bsf },{1, &pic16c5x_device::bsf },{1, &pic16c5x_device::bsf }, + {1, &pic16c5x_device::bsf },{1, &pic16c5x_device::bsf },{1, &pic16c5x_device::bsf },{1, &pic16c5x_device::bsf }, +/*58*/ {1, &pic16c5x_device::bsf },{1, &pic16c5x_device::bsf },{1, &pic16c5x_device::bsf },{1, &pic16c5x_device::bsf }, + {1, &pic16c5x_device::bsf },{1, &pic16c5x_device::bsf },{1, &pic16c5x_device::bsf },{1, &pic16c5x_device::bsf }, +/*60*/ {1, &pic16c5x_device::btfsc },{1, &pic16c5x_device::btfsc },{1, &pic16c5x_device::btfsc },{1, &pic16c5x_device::btfsc }, + {1, &pic16c5x_device::btfsc },{1, &pic16c5x_device::btfsc },{1, &pic16c5x_device::btfsc },{1, &pic16c5x_device::btfsc }, +/*68*/ {1, &pic16c5x_device::btfsc },{1, &pic16c5x_device::btfsc },{1, &pic16c5x_device::btfsc },{1, &pic16c5x_device::btfsc }, + {1, &pic16c5x_device::btfsc },{1, &pic16c5x_device::btfsc },{1, &pic16c5x_device::btfsc },{1, &pic16c5x_device::btfsc }, +/*70*/ {1, &pic16c5x_device::btfss },{1, &pic16c5x_device::btfss },{1, &pic16c5x_device::btfss },{1, &pic16c5x_device::btfss }, + {1, &pic16c5x_device::btfss },{1, &pic16c5x_device::btfss },{1, &pic16c5x_device::btfss },{1, &pic16c5x_device::btfss }, +/*78*/ {1, &pic16c5x_device::btfss },{1, &pic16c5x_device::btfss },{1, &pic16c5x_device::btfss },{1, &pic16c5x_device::btfss }, + {1, &pic16c5x_device::btfss },{1, &pic16c5x_device::btfss },{1, &pic16c5x_device::btfss },{1, &pic16c5x_device::btfss }, +/*80*/ {2, &pic16c5x_device::retlw },{2, &pic16c5x_device::retlw },{2, &pic16c5x_device::retlw },{2, &pic16c5x_device::retlw }, + {2, &pic16c5x_device::retlw },{2, &pic16c5x_device::retlw },{2, &pic16c5x_device::retlw },{2, &pic16c5x_device::retlw }, +/*88*/ {2, &pic16c5x_device::retlw },{2, &pic16c5x_device::retlw },{2, &pic16c5x_device::retlw },{2, &pic16c5x_device::retlw }, + {2, &pic16c5x_device::retlw },{2, &pic16c5x_device::retlw },{2, &pic16c5x_device::retlw },{2, &pic16c5x_device::retlw }, +/*90*/ {2, &pic16c5x_device::call },{2, &pic16c5x_device::call },{2, &pic16c5x_device::call },{2, &pic16c5x_device::call }, + {2, &pic16c5x_device::call },{2, &pic16c5x_device::call },{2, &pic16c5x_device::call },{2, &pic16c5x_device::call }, +/*98*/ {2, &pic16c5x_device::call },{2, &pic16c5x_device::call },{2, &pic16c5x_device::call },{2, &pic16c5x_device::call }, + {2, &pic16c5x_device::call },{2, &pic16c5x_device::call },{2, &pic16c5x_device::call },{2, &pic16c5x_device::call }, +/*A0*/ {2, &pic16c5x_device::goto_op },{2, &pic16c5x_device::goto_op },{2, &pic16c5x_device::goto_op },{2, &pic16c5x_device::goto_op }, + {2, &pic16c5x_device::goto_op },{2, &pic16c5x_device::goto_op },{2, &pic16c5x_device::goto_op },{2, &pic16c5x_device::goto_op }, +/*A8*/ {2, &pic16c5x_device::goto_op },{2, &pic16c5x_device::goto_op },{2, &pic16c5x_device::goto_op },{2, &pic16c5x_device::goto_op }, + {2, &pic16c5x_device::goto_op },{2, &pic16c5x_device::goto_op },{2, &pic16c5x_device::goto_op },{2, &pic16c5x_device::goto_op }, +/*B0*/ {2, &pic16c5x_device::goto_op },{2, &pic16c5x_device::goto_op },{2, &pic16c5x_device::goto_op },{2, &pic16c5x_device::goto_op }, + {2, &pic16c5x_device::goto_op },{2, &pic16c5x_device::goto_op },{2, &pic16c5x_device::goto_op },{2, &pic16c5x_device::goto_op }, +/*B8*/ {2, &pic16c5x_device::goto_op },{2, &pic16c5x_device::goto_op },{2, &pic16c5x_device::goto_op },{2, &pic16c5x_device::goto_op }, + {2, &pic16c5x_device::goto_op },{2, &pic16c5x_device::goto_op },{2, &pic16c5x_device::goto_op },{2, &pic16c5x_device::goto_op }, +/*C0*/ {1, &pic16c5x_device::movlw },{1, &pic16c5x_device::movlw },{1, &pic16c5x_device::movlw },{1, &pic16c5x_device::movlw }, + {1, &pic16c5x_device::movlw },{1, &pic16c5x_device::movlw },{1, &pic16c5x_device::movlw },{1, &pic16c5x_device::movlw }, +/*C8*/ {1, &pic16c5x_device::movlw },{1, &pic16c5x_device::movlw },{1, &pic16c5x_device::movlw },{1, &pic16c5x_device::movlw }, + {1, &pic16c5x_device::movlw },{1, &pic16c5x_device::movlw },{1, &pic16c5x_device::movlw },{1, &pic16c5x_device::movlw }, +/*D0*/ {1, &pic16c5x_device::iorlw },{1, &pic16c5x_device::iorlw },{1, &pic16c5x_device::iorlw },{1, &pic16c5x_device::iorlw }, + {1, &pic16c5x_device::iorlw },{1, &pic16c5x_device::iorlw },{1, &pic16c5x_device::iorlw },{1, &pic16c5x_device::iorlw }, +/*D8*/ {1, &pic16c5x_device::iorlw },{1, &pic16c5x_device::iorlw },{1, &pic16c5x_device::iorlw },{1, &pic16c5x_device::iorlw }, + {1, &pic16c5x_device::iorlw },{1, &pic16c5x_device::iorlw },{1, &pic16c5x_device::iorlw },{1, &pic16c5x_device::iorlw }, +/*E0*/ {1, &pic16c5x_device::andlw },{1, &pic16c5x_device::andlw },{1, &pic16c5x_device::andlw },{1, &pic16c5x_device::andlw }, + {1, &pic16c5x_device::andlw },{1, &pic16c5x_device::andlw },{1, &pic16c5x_device::andlw },{1, &pic16c5x_device::andlw }, +/*E8*/ {1, &pic16c5x_device::andlw },{1, &pic16c5x_device::andlw },{1, &pic16c5x_device::andlw },{1, &pic16c5x_device::andlw }, + {1, &pic16c5x_device::andlw },{1, &pic16c5x_device::andlw },{1, &pic16c5x_device::andlw },{1, &pic16c5x_device::andlw }, +/*F0*/ {1, &pic16c5x_device::xorlw },{1, &pic16c5x_device::xorlw },{1, &pic16c5x_device::xorlw },{1, &pic16c5x_device::xorlw }, + {1, &pic16c5x_device::xorlw },{1, &pic16c5x_device::xorlw },{1, &pic16c5x_device::xorlw },{1, &pic16c5x_device::xorlw }, +/*F8*/ {1, &pic16c5x_device::xorlw },{1, &pic16c5x_device::xorlw },{1, &pic16c5x_device::xorlw },{1, &pic16c5x_device::xorlw }, + {1, &pic16c5x_device::xorlw },{1, &pic16c5x_device::xorlw },{1, &pic16c5x_device::xorlw },{1, &pic16c5x_device::xorlw } +}; + + +const pic16c5x_device::pic16c5x_opcode pic16c5x_device::s_opcode_00x[16]= +{ +/*00*/ {1, &pic16c5x_device::nop },{0, &pic16c5x_device::illegal },{1, &pic16c5x_device::option },{1, &pic16c5x_device::sleepic }, + {1, &pic16c5x_device::clrwdt },{1, &pic16c5x_device::tris },{1, &pic16c5x_device::tris },{1, &pic16c5x_device::tris }, +/*08*/ {0, &pic16c5x_device::illegal },{0, &pic16c5x_device::illegal },{0, &pic16c5x_device::illegal },{0, &pic16c5x_device::illegal }, + {0, &pic16c5x_device::illegal },{0, &pic16c5x_device::illegal },{0, &pic16c5x_device::illegal },{0, &pic16c5x_device::illegal } +}; + + + +/**************************************************************************** + * Inits CPU emulation + ****************************************************************************/ + +enum +{ + PIC16C5x_PC=1, PIC16C5x_STK0, PIC16C5x_STK1, PIC16C5x_FSR, + PIC16C5x_W, PIC16C5x_ALU, PIC16C5x_STR, PIC16C5x_OPT, + PIC16C5x_TMR0, PIC16C5x_PRTA, PIC16C5x_PRTB, PIC16C5x_PRTC, + PIC16C5x_WDT, PIC16C5x_TRSA, PIC16C5x_TRSB, PIC16C5x_TRSC, + PIC16C5x_PSCL +}; + +void pic16c5x_device::device_start() +{ + m_program = &space(AS_PROGRAM); + m_direct = &m_program->direct(); + m_data = &space(AS_DATA); + + m_read_a.resolve_safe(0); + m_read_b.resolve_safe(0); + m_read_c.resolve_safe(0); + m_write_a.resolve_safe(); + m_write_b.resolve_safe(); + m_write_c.resolve_safe(); + m_read_t0.resolve_safe(0); + + /* ensure the internal ram pointers are set before get_info is called */ + update_internalram_ptr(); + + save_item(NAME(m_W)); + save_item(NAME(m_ALU)); + save_item(NAME(m_OPTION)); + save_item(NAME(TMR0)); + save_item(NAME(PCL)); + save_item(NAME(STATUS)); + save_item(NAME(FSR)); + save_item(NAME(PORTA)); + save_item(NAME(PORTB)); + save_item(NAME(PORTC)); + save_item(NAME(m_TRISA)); + save_item(NAME(m_TRISB)); + save_item(NAME(m_TRISC)); + save_item(NAME(m_old_T0)); + save_item(NAME(m_old_data)); + save_item(NAME(m_picRAMmask)); + save_item(NAME(m_WDT)); + save_item(NAME(m_prescaler)); + save_item(NAME(m_STACK[0])); + save_item(NAME(m_STACK[1])); + save_item(NAME(m_PC)); + save_item(NAME(m_PREVPC)); + save_item(NAME(m_CONFIG)); + save_item(NAME(m_opcode.d)); + save_item(NAME(m_delay_timer)); + save_item(NAME(m_picmodel)); + save_item(NAME(m_reset_vector)); + + save_item(NAME(m_temp_config)); + save_item(NAME(m_inst_cycles)); + + state_add( PIC16C5x_PC, "PC", m_PC).mask(0xfff).formatstr("%03X"); + state_add( PIC16C5x_W, "W", m_W).formatstr("%02X"); + state_add( PIC16C5x_ALU, "ALU", m_ALU).formatstr("%02X"); + state_add( PIC16C5x_STR, "STR", m_debugger_temp).mask(0xff).callimport().callexport().formatstr("%02X"); + state_add( PIC16C5x_TMR0, "TMR", m_debugger_temp).mask(0xff).callimport().callexport().formatstr("%02X"); + state_add( PIC16C5x_WDT, "WDT", m_WDT).formatstr("%04X"); + state_add( PIC16C5x_OPT, "OPT", m_OPTION).formatstr("%02X"); + state_add( PIC16C5x_STK0, "STK0", m_STACK[0]).mask(0xfff).formatstr("%03X"); + state_add( PIC16C5x_STK1, "STK1", m_STACK[1]).mask(0xfff).formatstr("%03X"); + state_add( PIC16C5x_PRTA, "PRTA", m_debugger_temp).mask(0xf).callimport().callexport().formatstr("%01X"); + state_add( PIC16C5x_PRTB, "PRTB", m_debugger_temp).mask(0xff).callimport().callexport().formatstr("%02X"); + state_add( PIC16C5x_PRTC, "PRTC", m_debugger_temp).mask(0xff).callimport().callexport().formatstr("%02X"); + state_add( PIC16C5x_TRSA, "TRSA", m_TRISA).mask(0xf).formatstr("%01X"); + state_add( PIC16C5x_TRSB, "TRSB", m_TRISB).formatstr("%02X"); + state_add( PIC16C5x_TRSC, "TRSC", m_TRISC).formatstr("%02X"); + state_add( PIC16C5x_FSR, "FSR", m_debugger_temp).mask(0xff).callimport().callexport().formatstr("%02X"); + state_add( PIC16C5x_PSCL, "PSCL", m_debugger_temp).callimport().formatstr("%3s"); + + state_add( STATE_GENPC, "GENPC", m_PC).noshow(); + state_add( STATE_GENFLAGS, "GENFLAGS", m_OPTION).formatstr("%13s").noshow(); + state_add( STATE_GENPCBASE, "PREVPC", m_PREVPC).noshow(); + + m_icountptr = &m_icount; +} + + +void pic16c5x_device::state_import(const device_state_entry &entry) +{ + switch (entry.index()) + { + case PIC16C5x_STR: + STATUS = m_debugger_temp; + break; + case PIC16C5x_TMR0: + TMR0 = m_debugger_temp; + break; + case PIC16C5x_PRTA: + PORTA = m_debugger_temp; + break; + case PIC16C5x_PRTB: + PORTB = m_debugger_temp; + break; + case PIC16C5x_PRTC: + PORTC = m_debugger_temp; + break; + case PIC16C5x_FSR: + FSR = ((m_debugger_temp & m_picRAMmask) | (UINT8)(~m_picRAMmask)); + break; + case PIC16C5x_PSCL: + m_prescaler = m_debugger_temp; + break; + } +} + +void pic16c5x_device::state_export(const device_state_entry &entry) +{ + switch (entry.index()) + { + case PIC16C5x_STR: + m_debugger_temp = STATUS; + break; + case PIC16C5x_TMR0: + m_debugger_temp = TMR0; + break; + case PIC16C5x_PRTA: + m_debugger_temp = PORTA & 0x0f; + break; + case PIC16C5x_PRTB: + m_debugger_temp = PORTB; + break; + case PIC16C5x_PRTC: + m_debugger_temp = PORTC; + break; + case PIC16C5x_FSR: + m_debugger_temp = ((FSR) & m_picRAMmask) | (UINT8)(~m_picRAMmask); + break; + } +} + +void pic16c5x_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + switch (entry.index()) + { + case PIC16C5x_PSCL: + strprintf(str, "%c%02X", ((m_OPTION & 0x08) ? 'W' : 'T'), m_prescaler); + break; + + case STATE_GENFLAGS: + strprintf(str, "%01x%c%c%c%c%c %c%c%c%03x", + (STATUS & 0xe0) >> 5, + STATUS & 0x10 ? '.':'O', /* WDT Overflow */ + STATUS & 0x08 ? 'P':'D', /* Power/Down */ + STATUS & 0x04 ? 'Z':'.', /* Zero */ + STATUS & 0x02 ? 'c':'b', /* Nibble Carry/Borrow */ + STATUS & 0x01 ? 'C':'B', /* Carry/Borrow */ + + m_OPTION & 0x20 ? 'C':'T', /* Counter/Timer */ + m_OPTION & 0x10 ? 'N':'P', /* Negative/Positive */ + m_OPTION & 0x08 ? 'W':'T', /* WatchDog/Timer */ + m_OPTION & 0x08 ? (1<<(m_OPTION&7)) : (2<<(m_OPTION&7)) ); + break; + } +} + +/**************************************************************************** + * Reset registers to their initial values + ****************************************************************************/ + +void pic16c5x_device::pic16c5x_reset_regs() +{ + m_PC = m_reset_vector; + m_CONFIG = m_temp_config; + m_TRISA = 0xff; + m_TRISB = 0xff; + m_TRISC = 0xff; + m_OPTION = (T0CS_FLAG | T0SE_FLAG | PSA_FLAG | PS_REG); + PCL = 0xff; + FSR |= (UINT8)(~m_picRAMmask); + PORTA &= 0x0f; + m_prescaler = 0; + m_delay_timer = 0; + m_old_T0 = 0; + m_inst_cycles = 0; +} + +void pic16c5x_device::pic16c5x_soft_reset() +{ + SET(STATUS, (TO_FLAG | PD_FLAG | Z_FLAG | DC_FLAG | C_FLAG)); + pic16c5x_reset_regs(); +} + +void pic16c5x_device::pic16c5x_set_config(UINT16 data) +{ + logerror("Writing %04x to the PIC16C5x config register\n",data); + m_temp_config = data; +} + + +void pic16c5x_device::device_reset() +{ + pic16c5x_reset_regs(); + CLR(STATUS, PA_REG); + SET(STATUS, (TO_FLAG | PD_FLAG)); +} + + +/**************************************************************************** + * WatchDog + ****************************************************************************/ + +void pic16c5x_device::pic16c5x_update_watchdog(int counts) +{ + /* WatchDog is set up to count 18,000 (0x464f hex) ticks to provide */ + /* the timeout period of 0.018ms based on a 4MHz input clock. */ + /* Note: the 4MHz clock should be divided by the PIC16C5x_CLOCK_DIVIDER */ + /* which effectively makes the PIC run at 1MHz internally. */ + + /* If the current instruction is CLRWDT or SLEEP, don't update the WDT */ + + if ((m_opcode.w.l != 3) && (m_opcode.w.l != 4)) + { + UINT16 old_WDT = m_WDT; + + m_WDT -= counts; + + if (m_WDT > 0x464f) { + m_WDT = 0x464f - (0xffff - m_WDT); + } + + if (((old_WDT != 0) && (old_WDT < m_WDT)) || (m_WDT == 0)) + { + if (PSA) { + m_prescaler++; + if (m_prescaler >= (1 << PS)) { /* Prescale values from 1 to 128 */ + m_prescaler = 0; + CLR(STATUS, TO_FLAG); + pic16c5x_soft_reset(); + } + } + else { + CLR(STATUS, TO_FLAG); + pic16c5x_soft_reset(); + } + } + } +} + + +/**************************************************************************** + * Update Timer + ****************************************************************************/ + +void pic16c5x_device::pic16c5x_update_timer(int counts) +{ + if (PSA == 0) { + m_prescaler += counts; + if (m_prescaler >= (2 << PS)) { /* Prescale values from 2 to 256 */ + TMR0 += (m_prescaler / (2 << PS)); + m_prescaler %= (2 << PS); /* Overflow prescaler */ + } + } + else { + TMR0 += counts; + } +} + + +/**************************************************************************** + * Execute IPeriod. Return 0 if emulation should be stopped + ****************************************************************************/ + +void pic16c5x_device::execute_run() +{ + UINT8 T0_in; + + update_internalram_ptr(); + + do + { + if (PD == 0) /* Sleep Mode */ + { + m_inst_cycles = 1; + debugger_instruction_hook(this, m_PC); + if (WDTE) { + pic16c5x_update_watchdog(1); + } + } + else + { + m_PREVPC = m_PC; + + debugger_instruction_hook(this, m_PC); + + m_opcode.d = M_RDOP(m_PC); + m_PC++; + PCL++; + + if ((m_opcode.w.l & 0xff0) != 0x000) { /* Do all opcodes except the 00? ones */ + m_inst_cycles = s_opcode_main[((m_opcode.w.l >> 4) & 0xff)].cycles; + (this->*s_opcode_main[((m_opcode.w.l >> 4) & 0xff)].function)(); + } + else { /* Opcode 0x00? has many opcodes in its minor nibble */ + m_inst_cycles = s_opcode_00x[(m_opcode.b.l & 0x1f)].cycles; + (this->*s_opcode_00x[(m_opcode.b.l & 0x1f)].function)(); + } + + if (T0CS) { /* Count mode */ + T0_in = m_read_t0() ? 1 : 0; + if (T0SE) { /* Count falling edge T0 input */ + if (FALLING_EDGE_T0) { + pic16c5x_update_timer(1); + } + } + else { /* Count rising edge T0 input */ + if (RISING_EDGE_T0) { + pic16c5x_update_timer(1); + } + } + m_old_T0 = T0_in; + } + else { /* Timer mode */ + if (m_delay_timer) { + m_delay_timer--; + } + else { + pic16c5x_update_timer(m_inst_cycles); + } + } + if (WDTE) { + pic16c5x_update_watchdog(m_inst_cycles); + } + } + + m_icount -= m_inst_cycles; + + } while (m_icount > 0); +} diff --git a/src/devices/cpu/pic16c5x/pic16c5x.h b/src/devices/cpu/pic16c5x/pic16c5x.h new file mode 100644 index 00000000000..5f45ca3bf33 --- /dev/null +++ b/src/devices/cpu/pic16c5x/pic16c5x.h @@ -0,0 +1,275 @@ +// license:BSD-3-Clause +// copyright-holders:Tony La Porta + /**************************************************************************\ + * Microchip PIC16C5x Emulator * + * * + * Copyright Tony La Porta * + * Originally written for the MAME project. * + * * + * * + * Addressing architecture is based on the Harvard addressing scheme. * + * * + \**************************************************************************/ + +#pragma once + +#ifndef __PIC16C5X_H__ +#define __PIC16C5X_H__ + + +// i/o ports +enum +{ + PIC16C5x_PORTA = 0, + PIC16C5x_PORTB, + PIC16C5x_PORTC +}; + +// port a, 4 bits, 2-way +#define MCFG_PIC16C5x_READ_A_CB(_devcb) \ + pic16c5x_device::set_read_a_callback(*device, DEVCB_##_devcb); +#define MCFG_PIC16C5x_WRITE_A_CB(_devcb) \ + pic16c5x_device::set_write_a_callback(*device, DEVCB_##_devcb); + +// port b, 8 bits, 2-way +#define MCFG_PIC16C5x_READ_B_CB(_devcb) \ + pic16c5x_device::set_read_b_callback(*device, DEVCB_##_devcb); +#define MCFG_PIC16C5x_WRITE_B_CB(_devcb) \ + pic16c5x_device::set_write_b_callback(*device, DEVCB_##_devcb); + +// port c, 8 bits, 2-way +#define MCFG_PIC16C5x_READ_C_CB(_devcb) \ + pic16c5x_device::set_read_c_callback(*device, DEVCB_##_devcb); +#define MCFG_PIC16C5x_WRITE_C_CB(_devcb) \ + pic16c5x_device::set_write_c_callback(*device, DEVCB_##_devcb); + +// T0 pin (readline) +#define MCFG_PIC16C5x_T0_CB(_devcb) \ + pic16c5x_device::set_t0_callback(*device, DEVCB_##_devcb); + +// CONFIG register +#define MCFG_PIC16C5x_SET_CONFIG(_data) \ + pic16c5x_device::set_config_static(*device, _data); + + + +extern const device_type PIC16C54; +extern const device_type PIC16C55; +extern const device_type PIC16C56; +extern const device_type PIC16C57; +extern const device_type PIC16C58; + + +class pic16c5x_device : public cpu_device +{ +public: + // construction/destruction + pic16c5x_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, int program_width, int data_width, int picmodel); + + // static configuration helpers + template static devcb_base &set_read_a_callback(device_t &device, _Object object) { return downcast(device).m_read_a.set_callback(object); } + template static devcb_base &set_read_b_callback(device_t &device, _Object object) { return downcast(device).m_read_b.set_callback(object); } + template static devcb_base &set_read_c_callback(device_t &device, _Object object) { return downcast(device).m_read_c.set_callback(object); } + + template static devcb_base &set_write_a_callback(device_t &device, _Object object) { return downcast(device).m_write_a.set_callback(object); } + template static devcb_base &set_write_b_callback(device_t &device, _Object object) { return downcast(device).m_write_b.set_callback(object); } + template static devcb_base &set_write_c_callback(device_t &device, _Object object) { return downcast(device).m_write_c.set_callback(object); } + + template static devcb_base &set_t0_callback(device_t &device, _Object object) { return downcast(device).m_read_t0.set_callback(object); } + + /**************************************************************************** + * Function to configure the CONFIG register. This is actually hard-wired + * during ROM programming, so should be called in the driver INIT, with + * the value if known (available in HEX dumps of the ROM). + */ + void pic16c5x_set_config(UINT16 data); + + // or with a macro + static void set_config_static(device_t &device, UINT16 data) { downcast(device).m_temp_config = data; } + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_execute_interface overrides + /************************************************************************** + * Internal Clock divisor + * + * External Clock is divided internally by 4 for the instruction cycle + * times. (Each instruction cycle passes through 4 machine states). This + * is handled by the cpu execution engine. + */ + virtual UINT64 execute_clocks_to_cycles(UINT64 clocks) const { return (clocks + 4 - 1) / 4; } + virtual UINT64 execute_cycles_to_clocks(UINT64 cycles) const { return (cycles * 4); } + virtual UINT32 execute_min_cycles() const { return 1; } + virtual UINT32 execute_max_cycles() const { return 2; } + virtual UINT32 execute_input_lines() const { return 1; } + virtual UINT32 execute_default_irq_vector() const { return 0; } + virtual void execute_run(); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const + { + return (spacenum == AS_PROGRAM) ? &m_program_config : ( (spacenum == AS_DATA) ? &m_data_config : NULL ); + } + + // device_state_interface overrides + virtual void state_import(const device_state_entry &entry); + virtual void state_export(const device_state_entry &entry); + void state_string_export(const device_state_entry &entry, std::string &str); + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const { return 2; } + virtual UINT32 disasm_max_opcode_bytes() const { return 2; } + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + +private: + address_space_config m_program_config; + address_space_config m_data_config; + + /******************** CPU Internal Registers *******************/ + UINT16 m_PC; + UINT16 m_PREVPC; /* previous program counter */ + UINT8 m_W; + UINT8 m_OPTION; + UINT16 m_CONFIG; + UINT8 m_ALU; + UINT16 m_WDT; + UINT8 m_TRISA; + UINT8 m_TRISB; + UINT8 m_TRISC; + UINT16 m_STACK[2]; + UINT16 m_prescaler; /* Note: this is really an 8-bit register */ + PAIR m_opcode; + UINT8 *m_internalram; + + int m_icount; + int m_reset_vector; + int m_picmodel; + int m_delay_timer; + UINT16 m_temp_config; + UINT8 m_old_T0; + INT8 m_old_data; + UINT8 m_picRAMmask; + int m_inst_cycles; + + address_space *m_program; + direct_read_data *m_direct; + address_space *m_data; + + // i/o handlers + devcb_read8 m_read_a; + devcb_read8 m_read_b; + devcb_read8 m_read_c; + devcb_write8 m_write_a; + devcb_write8 m_write_b; + devcb_write8 m_write_c; + devcb_read_line m_read_t0; + + // For debugger + int m_debugger_temp; + + /* opcode table entry */ + typedef void (pic16c5x_device::*pic16c5x_ophandler)(); + struct pic16c5x_opcode + { + UINT8 cycles; + pic16c5x_ophandler function; + }; + static const pic16c5x_opcode s_opcode_main[256]; + static const pic16c5x_opcode s_opcode_00x[16]; + + void update_internalram_ptr(); + void CALCULATE_Z_FLAG(); + void CALCULATE_ADD_CARRY(); + void CALCULATE_ADD_DIGITCARRY(); + void CALCULATE_SUB_CARRY(); + void CALCULATE_SUB_DIGITCARRY(); + UINT16 POP_STACK(); + void PUSH_STACK(UINT16 data); + UINT8 GET_REGFILE(offs_t addr); + void STORE_REGFILE(offs_t addr, UINT8 data); + void STORE_RESULT(offs_t addr, UINT8 data); + void illegal(); + void addwf(); + void andwf(); + void andlw(); + void bcf(); + void bsf(); + void btfss(); + void btfsc(); + void call(); + void clrw(); + void clrf(); + void clrwdt(); + void comf(); + void decf(); + void decfsz(); + void goto_op(); + void incf(); + void incfsz(); + void iorlw(); + void iorwf(); + void movf(); + void movlw(); + void movwf(); + void nop(); + void option(); + void retlw(); + void rlf(); + void rrf(); + void sleepic(); + void subwf(); + void swapf(); + void tris(); + void xorlw(); + void xorwf(); + void pic16c5x_reset_regs(); + void pic16c5x_soft_reset(); + void pic16c5x_update_watchdog(int counts); + void pic16c5x_update_timer(int counts); + +}; + + +class pic16c54_device : public pic16c5x_device +{ +public: + // construction/destruction + pic16c54_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +class pic16c55_device : public pic16c5x_device +{ +public: + // construction/destruction + pic16c55_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +class pic16c56_device : public pic16c5x_device +{ +public: + // construction/destruction + pic16c56_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +class pic16c57_device : public pic16c5x_device +{ +public: + // construction/destruction + pic16c57_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +class pic16c58_device : public pic16c5x_device +{ +public: + // construction/destruction + pic16c58_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +#endif /* __PIC16C5X_H__ */ diff --git a/src/devices/cpu/pic16c62x/16c62xdsm.c b/src/devices/cpu/pic16c62x/16c62xdsm.c new file mode 100644 index 00000000000..5bdd824dc16 --- /dev/null +++ b/src/devices/cpu/pic16c62x/16c62xdsm.c @@ -0,0 +1,267 @@ +// license:BSD-3-Clause +// copyright-holders:Tony La Porta + /**************************************************************************\ + * Microchip PIC16C62X Emulator * + * * + * Based On * + * Microchip PIC16C5X Emulator * + * Copyright Tony La Porta * + * Originally written for the MAME project. * + * * + * * + * Addressing architecture is based on the Harvard addressing scheme. * + * * + * Many thanks to those involved in the i8039 Disassembler * + * as this was based on it. * + * * + * * + * * + * A Address to jump to. * + * B Bit address within an 8-bit file register. * + * D Destination select (0 = store result in W (accumulator)) * + * (1 = store result in file register) * + * F Register file address (00-1F). * + * K Literal field, constant data. * + * X Not used * + * * + \**************************************************************************/ + +#include "emu.h" +#include + +static const UINT8 *rombase; +static const UINT8 *rambase; +static offs_t pcbase; +#define READOP16(A) (rombase[(A) - pcbase] | (rombase[(A) + 1 - pcbase] << 8)) +#define READARG16(A) (rambase[(A) - pcbase] | (rambase[(A) + 1 - pcbase] << 8)) + + + +typedef unsigned char byte; +typedef unsigned short int word; + +#define FMT(a,b) a, b +#define PTRS_PER_FORMAT 2 + +/* Registers bank 0/1 */ +static const char *const regfile[32] = { "Reg$00 (INDF)", "Reg$01 (TMR0/OPTION)", "Reg$02 (PCL)", "Reg$03 (STATUS)", "Reg$04 (FSR)", "Reg$05 (PORTA/TRISA)", "Reg$06 (PORTB/TRISB)", "Reg$07", + "Reg$08", "Reg$09", "Reg$0A (PCLATH)", "Reg$0B (INTCON)", "Reg$0C (PIR1/PIE1)", "Reg$0D", "Reg$0E (none/PCON)", "Reg$0F", + "Reg$10", "Reg$11", "Reg$12", "Reg$13", "Reg$14", "Reg$15", "Reg$16", "Reg$17", + "Reg$18", "Reg$19", "Reg$1A", "Reg$1B", "Reg$1C", "Reg$1D", "Reg$1E", "Reg$1F (CMCON/VRCON)" }; +/* Registers bank 1 */ +/*static const char *const regfile1[32] = { "Reg$00 (INDF)", "Reg$01 (OPTION)", "Reg$02 (PCL)", "Reg$03 (STATUS)", "Reg$04 (FSR)", "Reg$05 (TRISA)", "Reg$06 (TRISB)", "Reg$07", + "Reg$08", "Reg$09", "Reg$0A (PCLATH)", "Reg$0B (INTCON)", "Reg$0C (PIE1)", "Reg$0D", "Reg$0E (PCON)", "Reg$0F", + "Reg$10", "Reg$11", "Reg$12", "Reg$13", "Reg$14", "Reg$15", "Reg$16", "Reg$17", + "Reg$18", "Reg$19", "Reg$1A", "Reg$1B", "Reg$1C", "Reg$1D", "Reg$1E", "Reg$1F (VRCON)" }; +static const char **regfile[2] = { regfile0, regfile1 };*/ + +static const char *const dest[2] = { "W", "Reg" }; + +static const char *const PIC16C62xFormats[] = { + FMT("0000000xx00000", "nop"), + FMT("00000000001000", "return"), + FMT("00000000001001", "retfie"), + FMT("00000001100011", "sleep"), + FMT("00000001100100", "clrwdt"), + FMT("0000001fffffff", "movwf %F"), + FMT("00000100000011", "clrw"), + FMT("0000011fffffff", "clrf %F"), + FMT("000010dfffffff", "subwf %F,%D"), + FMT("000011dfffffff", "decf %F,%D"), + FMT("000100dfffffff", "iorwf %F,%D"), + FMT("000101dfffffff", "andwf %F,%D"), + FMT("000110dfffffff", "xorwf %F,%D"), + FMT("000111dfffffff", "addwf %F,%D"), + FMT("001000dfffffff", "movf %F,%D"), + FMT("001001dfffffff", "comf %F,%D"), + FMT("001010dfffffff", "incf %F,%D"), + FMT("001011dfffffff", "decfsz %F,%D"), + FMT("001100dfffffff", "rrf %F,%D"), + FMT("001101dfffffff", "rlf %F,%D"), + FMT("001110dfffffff", "swapf %F,%D"), + FMT("001111dfffffff", "incfsz %F,%D"), + FMT("0100bbbfffffff", "bcf %F,%B"), + FMT("0101bbbfffffff", "bsf %F,%B"), + FMT("0110bbbfffffff", "btfsc %F,%B"), + FMT("0111bbbfffffff", "btfss %F,%B"), + FMT("1101xxkkkkkkkk", "retlw %K"), + FMT("100aaaaaaaaaaa", "call %A"), + FMT("101aaaaaaaaaaa", "goto %A"), + FMT("1100xxkkkkkkkk", "movlw %K"), + FMT("111000kkkkkkkk", "iorlw %K"), + FMT("111001kkkkkkkk", "andlw %K"), + FMT("111010kkkkkkkk", "xorlw %K"), + FMT("11110xkkkkkkkk", "sublw %K"), + FMT("11111xkkkkkkkk", "addlw %K"), + NULL +}; + +#define MAX_OPS ((ARRAY_LENGTH(PIC16C62xFormats) - 1) / PTRS_PER_FORMAT) + +struct PIC16C62xOpcode { + word mask; /* instruction mask */ + word bits; /* constant bits */ + word extcode; /* value that gets extension code */ + const char *parse; /* how to parse bits */ + const char *fmt; /* instruction format */ +}; + +static PIC16C62xOpcode Op[MAX_OPS+1]; +static int OpInizialized = 0; + +static void InitDasm16C5x(void) +{ + const char *p; + const char *const *ops; + word mask, bits; + int bit; + int i; + + ops = PIC16C62xFormats; i = 0; + while (*ops) + { + p = *ops; + mask = 0; bits = 0; bit = 13; + while (*p && bit >= 0) + { + switch (*p++) + { + case '1': mask |= 1<= 0) + { + /* osd_printf_debug("{%c/%d}",*cp,bit); */ + switch(*cp) + { + case 'a': a <<=1; a |= ((code & (1< +#include + +#include "16c62xdsm.c" + + +unsigned char *Buffer; + + +int main(int argc,char *argv[]) +{ + int length=0, length_to_dump=0, offset=0, disasm_words=0; + int filelength=0, bytes_read; + int Counter=0; + + FILE *F; + char *String_Output; + + if(argc<2) + { + printf("\n"); + printf("PIC16C5x Disassembler 1.0 by Tony La Porta (C)2003+\n\n"); + printf("Usage: dis16c5x [ [ ] ]\n"); + printf(" source file data must be MSB first\n"); + printf(" starting address to disassemble from (decimal)\n"); + printf(" number of addresses to disassemble (decimal)\n"); + printf(" Precede values with 0x if HEX values preffered\n"); + exit(1); + } + + if(!(F=fopen(argv[1],"rb"))) + { + printf("\n%s: Can't open file %s\n",argv[0],argv[1]); + exit(2); + } + argv++; argc--; + if (argv[1]) + { + offset = strtol(argv[1],NULL,0); + argv++; argc--; + } + if (argv[1]) + { + length = strtol(argv[1],NULL,0); + argv++; argc--; + } + + fseek(F,0, SEEK_END); + filelength = ftell(F); + + length *= 2; + + if ((length > (filelength - (offset*2))) || (length == 0)) length = filelength - (offset*2); + printf("Length=%04Xh(words) Offset=$%04Xh filelength=%04Xh(words) %04Xh(bytes)\n",length/2,offset,filelength/2,filelength); + length_to_dump = length; + printf("Starting from %d, dumping %d opcodes (word size)\n",offset,length/2); + Buffer = calloc((filelength+1),sizeof(char)); + if (Buffer==NULL) + { + printf("Out of Memory !!!"); + fclose(F); + exit(3); + } + String_Output = calloc(80,sizeof(char)); + if (String_Output==NULL) + { + printf("Out of Memory !!!"); + free(Buffer); + fclose(F); + exit(4); + } + + if (fseek(F,0,SEEK_SET) != 0) + { + printf("Error seeking to beginning of file\n"); + free(String_Output); + free(Buffer); + fclose(F); + exit(5); + } + + Counter = offset; + bytes_read = fread(Buffer,sizeof(char),filelength,F); + if (bytes_read >= length) + { + for (; length > 0; length -= (disasm_words*2)) + { + int ii; + disasm_words = Dasm16C5x(String_Output,Counter); + printf("$%03X: ",Counter); + for (ii = 0; ii < disasm_words; ii++) + { + if (((Counter*2) + ii) > filelength) /* Past end of length to dump ? */ + { + sprintf(String_Output,"???? dw %02.2X%02.2Xh (Past end of disassembly !)",Buffer[((Counter-1)*2)+1],Buffer[((Counter-1)*2)]); + } + else + { + printf("%02.2x%02.2x ",Buffer[(Counter*2)+1],Buffer[(Counter*2)]); + } + Counter++ ; + } + for (; ii < 4; ii++) + { + printf(" "); + } + printf("\t%s\n",String_Output); + } + } + else + { + printf("ERROR length to dump was %d ", length_to_dump/2); + printf(", but bytes read from file were %d\n", bytes_read/2); + free(String_Output); + free(Buffer); + fclose(F); + exit(7); + } + free(String_Output); + free(Buffer); + fclose(F); + return(0); +} diff --git a/src/devices/cpu/pic16c62x/pic16c62x.c b/src/devices/cpu/pic16c62x/pic16c62x.c new file mode 100644 index 00000000000..2a38bcd5f93 --- /dev/null +++ b/src/devices/cpu/pic16c62x/pic16c62x.c @@ -0,0 +1,1189 @@ +// license:BSD-3-Clause +// copyright-holders:Tony La Porta + /**************************************************************************\ + * Microchip PIC16C62X Emulator * + * * + * Based On * + * Microchip PIC16C5X Emulator * + * Copyright Tony La Porta * + * Originally written for the MAME project. * + * * + * * + * Addressing architecture is based on the Harvard addressing scheme. * + * * + * * + * **** Change Log **** * + * SZ (22-Oct-2009) * + * - Improvements and tests * + * SZ (2-Oct-2009) * + * - Internal ram and registers * + * SZ (12-Sep-2009) * + * - Started working on it. * + * * + * * + * **** TODO **** * + * - Finish checking opcodes/instructions * + * - Internal devices * + * - Interrupts * + * - Everything ! * + * * + * **** DONE **** * + * - I/O ports * + * - Savestates * + * - Internal memory * + * - New opcodes * + * - Opcode disassembly * + * * + * **** Notes (from PIC16C5X): **** * + * PIC WatchDog Timer has a separate internal clock. For the moment, we're * + * basing the count on a 4MHz input clock, since 4MHz is the typical * + * input frequency (but by no means always). * + * A single scaler is available for the Counter/Timer or WatchDog Timer. * + * When connected to the Counter/Timer, it functions as a Prescaler, * + * hence prescale overflows, tick the Counter/Timer. * + * When connected to the WatchDog Timer, it functions as a Postscaler * + * hence WatchDog Timer overflows, tick the Postscaler. This scenario * + * means that the WatchDog timeout occurs when the Postscaler has * + * reached the scaler rate value, not when the WatchDog reaches zero. * + * CLRWDT should prevent the WatchDog Timer from timing out and generating * + * a device reset, but how is not known. The manual also mentions that * + * the WatchDog Timer can only be disabled during ROM programming, and * + * no other means seem to exist??? * + * * + \**************************************************************************/ + +#include "emu.h" +#include "debugger.h" +#include "pic16c62x.h" + + +const device_type PIC16C620 = &device_creator; +const device_type PIC16C620A = &device_creator; +const device_type PIC16C621 = &device_creator; +const device_type PIC16C621A = &device_creator; +const device_type PIC16C622 = &device_creator; +const device_type PIC16C622A = &device_creator; + + + +/**************************************************************************** + * Internal Memory Map + ****************************************************************************/ + +static ADDRESS_MAP_START( pic16c62x_rom_9, AS_PROGRAM, 16, pic16c62x_device ) + AM_RANGE(0x000, 0x1ff) AM_ROM +ADDRESS_MAP_END + +static ADDRESS_MAP_START( pic16c62x_rom_10, AS_PROGRAM, 16, pic16c62x_device ) + AM_RANGE(0x000, 0x3ff) AM_ROM +ADDRESS_MAP_END + +static ADDRESS_MAP_START( pic16c62x_rom_11, AS_PROGRAM, 16, pic16c62x_device ) + AM_RANGE(0x000, 0x7ff) AM_ROM +ADDRESS_MAP_END + +static ADDRESS_MAP_START( pic16c620_ram, AS_DATA, 8, pic16c62x_device ) + AM_RANGE(0x00, 0x06) AM_RAM + AM_RANGE(0x0a, 0x0c) AM_RAM + AM_RANGE(0x1f, 0x6f) AM_RAM + AM_RANGE(0x80, 0x86) AM_RAM + AM_RANGE(0x8a, 0x8e) AM_RAM + AM_RANGE(0x9f, 0x9f) AM_RAM +ADDRESS_MAP_END + +static ADDRESS_MAP_START( pic16c622_ram, AS_DATA, 8, pic16c62x_device ) + AM_RANGE(0x00, 0x06) AM_RAM + AM_RANGE(0x0a, 0x0c) AM_RAM + AM_RANGE(0x1f, 0x7f) AM_RAM + AM_RANGE(0x80, 0x86) AM_RAM + AM_RANGE(0x8a, 0x8e) AM_RAM + AM_RANGE(0x9f, 0xbf) AM_RAM +ADDRESS_MAP_END + +// pic16c620a, pic16c621a and pic16c622a +static ADDRESS_MAP_START( pic16c62xa_ram, AS_DATA, 8, pic16c62x_device ) + AM_RANGE(0x00, 0x06) AM_RAM + AM_RANGE(0x0a, 0x0c) AM_RAM + AM_RANGE(0x1f, 0x6f) AM_RAM + AM_RANGE(0x70, 0x7f) AM_RAM AM_SHARE(0) + AM_RANGE(0x80, 0x86) AM_RAM + AM_RANGE(0x8a, 0x8e) AM_RAM + AM_RANGE(0x9f, 0xbf) AM_RAM + AM_RANGE(0xf0, 0xff) AM_RAM AM_SHARE(0) +ADDRESS_MAP_END + + +pic16c62x_device::pic16c62x_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, int program_width, int picmodel) + : cpu_device(mconfig, type, name, tag, owner, clock, shortname, __FILE__) + , m_program_config("program", ENDIANNESS_LITTLE, 16, program_width, -1 + , ( ( program_width == 9 ) ? ADDRESS_MAP_NAME(pic16c62x_rom_9) : ( ( program_width == 10 ) ? ADDRESS_MAP_NAME(pic16c62x_rom_10) : ADDRESS_MAP_NAME(pic16c62x_rom_11) ))) + , m_data_config("data", ENDIANNESS_LITTLE, 8, 8, 0 + , ( ( picmodel == 0x16C620 || picmodel == 0x16C621 ) ? ADDRESS_MAP_NAME(pic16c620_ram) : ( ( picmodel == 0x16C622 ) ? ADDRESS_MAP_NAME(pic16c622_ram) : ADDRESS_MAP_NAME(pic16c62xa_ram) ) ) ) + , m_io_config("io", ENDIANNESS_LITTLE, 8, 5, 0) + , m_reset_vector(0x0) + , m_picmodel(picmodel) + , m_picRAMmask(0xff) +{ +} + + +pic16c620_device::pic16c620_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : pic16c62x_device(mconfig, PIC16C620, "PIC16C620", tag, owner, clock, "pic16c620", 9, 0x16C620) +{ +} + +pic16c620a_device::pic16c620a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : pic16c62x_device(mconfig, PIC16C620A, "PIC16C620A", tag, owner, clock, "pic16c620a", 9, 0x16C620A) +{ +} + +pic16c621_device::pic16c621_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : pic16c62x_device(mconfig, PIC16C621, "PIC16C621", tag, owner, clock, "pic16c621", 9, 0x16C621) +{ +} + +pic16c621a_device::pic16c621a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : pic16c62x_device(mconfig, PIC16C621A, "PIC16C621A", tag, owner, clock, "pic16c621a", 9, 0x16C621A) +{ +} + +pic16c622_device::pic16c622_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : pic16c62x_device(mconfig, PIC16C622, "PIC16C622", tag, owner, clock, "pic16c622", 9, 0x16C622) +{ +} + +pic16c622a_device::pic16c622a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : pic16c62x_device(mconfig, PIC16C622A, "PIC16C622A", tag, owner, clock, "pic16c622a", 9, 0x16C622A) +{ +} + + +offs_t pic16c62x_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( pic16c62x ); + return CPU_DISASSEMBLE_NAME(pic16c62x)(this, buffer, pc, oprom, opram, options); +} + + +void pic16c62x_device::update_internalram_ptr() +{ + m_internalram = (UINT8 *)m_data->get_write_ptr(0x00); +} + +#define PIC16C62x_RDOP(A) (m_direct->read_word((A)<<1)) +#define PIC16C62x_RAM_RDMEM(A) ((UINT8)m_data->read_byte(A)) +#define PIC16C62x_RAM_WRMEM(A,V) (m_data->write_byte(A,V)) +#define PIC16C62x_In(Port) ((UINT8)m_io->read_byte((Port))) +#define PIC16C62x_Out(Port,Value) (m_io->write_byte((Port),Value)) +/************ Read the state of the T0 Clock input signal ************/ +#define PIC16C62x_T0_In (m_io->read_byte(PIC16C62x_T0) >> 4) + +#define M_RDRAM(A) (((A) == 0) ? m_internalram[0] : PIC16C62x_RAM_RDMEM(A)) +#define M_WRTRAM(A,V) do { if ((A) == 0) m_internalram[0] = (V); else PIC16C62x_RAM_WRMEM(A,V); } while (0) +#define M_RDOP(A) PIC16C62x_RDOP(A) +#define P_IN(A) PIC16C62x_In(A) +#define P_OUT(A,V) PIC16C62x_Out(A,V) +#define S_T0_IN PIC16C62x_T0_In +#define ADDR_MASK 0x1fff + + + +#define TMR0 m_internalram[1] +#define PCL m_internalram[2] +#define STATUS m_internalram[3] +#define FSR m_internalram[4] +#define PORTA m_internalram[5] +#define PORTB m_internalram[6] +#define INDF M_RDRAM(FSR) + +#define RISING_EDGE_T0 (( (int)(T0_in - m_old_T0) > 0) ? 1 : 0) +#define FALLING_EDGE_T0 (( (int)(T0_in - m_old_T0) < 0) ? 1 : 0) + + +/******** The following is the Status Flag register definition. *********/ + /* | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | */ + /* |IRP|RP1|RP0| TO | PD | Z | DC | C | */ +#define IRP_FLAG 0x80 /* IRP Register Bank Select bit (used for indirect addressing) */ +#define RP1_FLAG 0x40 /* RP1 Register Bank Select bits (used for direct addressing) */ +#define RP0_FLAG 0x20 /* RP0 Register Bank Select bits (used for direct addressing) */ +#define TO_FLAG 0x10 /* TO Time Out flag (WatchDog) */ +#define PD_FLAG 0x08 /* PD Power Down flag */ +#define Z_FLAG 0x04 /* Z Zero Flag */ +#define DC_FLAG 0x02 /* DC Digit Carry/Borrow flag (Nibble) */ +#define C_FLAG 0x01 /* C Carry/Borrow Flag (Byte) */ + +#define IRP (STATUS & IRP_FLAG) +#define RP1 (STATUS & RP1_FLAG) +#define RP0 (STATUS & RP0_FLAG) +#define TO (STATUS & TO_FLAG) +#define PD (STATUS & PD_FLAG) +#define ZERO (STATUS & Z_FLAG) +#define DC (STATUS & DC_FLAG) +#define CARRY (STATUS & C_FLAG) + +#define ADDR ((m_opcode.b.l & 0x7f) | (RP0 << 2)) + +/******** The following is the Option Flag register definition. *********/ + /* | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | */ + /* | RBPU | INTEDG | TOCS | TOSE | PSA | PS | */ +#define RBPU_FLAG 0x80 /* RBPU Pull-up Enable */ +#define INTEDG_FLAG 0x40 /* INTEDG Interrupt Edge Select */ +#define T0CS_FLAG 0x20 /* TOCS Timer 0 clock source select */ +#define T0SE_FLAG 0x10 /* TOSE Timer 0 clock source edge select */ +#define PSA_FLAG 0x08 /* PSA Prescaler Assignment bit */ +#define PS_REG 0x07 /* PS Prescaler Rate select */ + +#define T0CS (m_OPTION & T0CS_FLAG) +#define T0SE (m_OPTION & T0SE_FLAG) +#define PSA (m_OPTION & PSA_FLAG) +#define PS (m_OPTION & PS_REG) + +/******** The following is the Config Flag register definition. *********/ + /* | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | */ + /* | CP | | BODEN | CP | PWRTE | WDTE | FOSC | */ + /* CP Code Protect (ROM read protect) */ +#define BODEN_FLAG 0x40 /* BODEN Brown-out Reset Enable */ +#define PWRTE_FLAG 0x08 /* PWRTE Power-up Timer Enable */ +#define WDTE_FLAG 0x04 /* WDTE WatchDog Timer enable */ +#define FOSC_FLAG 0x03 /* FOSC Oscillator source select */ + +#define WDTE (m_CONFIG & WDTE_FLAG) +#define FOSC (m_CONFIG & FOSC_FLAG) + + +/************************************************************************ + * Shortcuts + ************************************************************************/ + +#define CLR(flagreg, flag) ( flagreg &= (UINT8)(~flag) ) +#define SET(flagreg, flag) ( flagreg |= flag ) + + +/* Easy bit position selectors */ +#define POS ((m_opcode.w.l >> 7) & 7) +static const unsigned int bit_clr[8] = { 0xfe, 0xfd, 0xfb, 0xf7, 0xef, 0xdf, 0xbf, 0x7f }; +static const unsigned int bit_set[8] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 }; + + + +void pic16c62x_device::CALCULATE_Z_FLAG() +{ + if (m_ALU == 0) SET(STATUS, Z_FLAG); + else CLR(STATUS, Z_FLAG); +} + +void pic16c62x_device::CALCULATE_ADD_CARRY() +{ + if ((UINT8)(m_old_data) > (UINT8)(m_ALU)) { + SET(STATUS, C_FLAG); + } + else { + CLR(STATUS, C_FLAG); + } +} + +void pic16c62x_device::CALCULATE_ADD_DIGITCARRY() +{ + if (((UINT8)(m_old_data) & 0x0f) > ((UINT8)(m_ALU) & 0x0f)) { + SET(STATUS, DC_FLAG); + } + else { + CLR(STATUS, DC_FLAG); + } +} + +void pic16c62x_device::CALCULATE_SUB_CARRY() +{ + if ((UINT8)(m_old_data) < (UINT8)(m_ALU)) { + CLR(STATUS, C_FLAG); + } + else { + SET(STATUS, C_FLAG); + } +} + +void pic16c62x_device::CALCULATE_SUB_DIGITCARRY() +{ + if (((UINT8)(m_old_data) & 0x0f) < ((UINT8)(m_ALU) & 0x0f)) { + CLR(STATUS, DC_FLAG); + } + else { + SET(STATUS, DC_FLAG); + } +} + + +UINT16 pic16c62x_device::POP_STACK() +{ + UINT16 data = m_STACK[7]; + m_STACK[7] = m_STACK[6]; + m_STACK[6] = m_STACK[5]; + m_STACK[5] = m_STACK[4]; + m_STACK[4] = m_STACK[3]; + m_STACK[3] = m_STACK[2]; + m_STACK[2] = m_STACK[1]; + m_STACK[1] = m_STACK[0]; + return (data & ADDR_MASK); +} +void pic16c62x_device::PUSH_STACK(UINT16 data) +{ + m_STACK[0] = m_STACK[1]; + m_STACK[1] = m_STACK[2]; + m_STACK[2] = m_STACK[3]; + m_STACK[3] = m_STACK[4]; + m_STACK[4] = m_STACK[5]; + m_STACK[5] = m_STACK[6]; + m_STACK[6] = m_STACK[7]; + m_STACK[7] = (data & ADDR_MASK); +} + + + +UINT8 pic16c62x_device::GET_REGFILE(offs_t addr) /* Read from internal memory */ +{ + UINT8 data; + + if (addr == 0) { /* Indirect addressing */ + addr = (FSR & m_picRAMmask); + } + + switch(addr) + { + case 0x00: /* Not an actual register, so return 0 */ + case 0x80: + data = 0; + break; + case 0x02: + case 0x03: + case 0x0b: + case 0x82: + case 0x83: + case 0x8b: + data = M_RDRAM(addr & 0x7f); + break; + case 0x84: + case 0x04: data = (FSR | (UINT8)(~m_picRAMmask)); + break; + case 0x05: data = P_IN(0); + data &= m_TRISA; + data |= ((UINT8)(~m_TRISA) & PORTA); + data &= 0x1f; /* 5-bit port (only lower 5 bits used) */ + break; + case 0x06: data = P_IN(1); + data &= m_TRISB; + data |= ((UINT8)(~m_TRISB) & PORTB); + break; + case 0x8a: + case 0x0a: data = m_PCLATH; + break; + case 0x81: data = m_OPTION; + break; + case 0x85: data = m_TRISA; + break; + case 0x86: data = m_TRISB; + break; + default: data = M_RDRAM(addr); + break; + } + return data; +} + +void pic16c62x_device::STORE_REGFILE(offs_t addr, UINT8 data) /* Write to internal memory */ +{ + if (addr == 0) { /* Indirect addressing */ + addr = (FSR & m_picRAMmask); + } + + switch(addr) + { + case 0x80: + case 0x00: /* Not an actual register, nothing to save */ + break; + case 0x01: m_delay_timer = 2; /* Timer starts after next two instructions */ + if (PSA == 0) m_prescaler = 0; /* Must clear the Prescaler */ + TMR0 = data; + break; + case 0x82: + case 0x02: PCL = data; + m_PC = (m_PCLATH << 8) | data; + break; + case 0x83: + case 0x03: STATUS &= (UINT8)(~(IRP_FLAG|RP1_FLAG|RP0_FLAG)); STATUS |= (data & (IRP_FLAG|RP1_FLAG|RP0_FLAG)); + break; + case 0x84: + case 0x04: FSR = (data | (UINT8)(~m_picRAMmask)); + break; + case 0x05: data &= 0x1f; /* 5-bit port (only lower 5 bits used) */ + P_OUT(0,data & (UINT8)(~m_TRISA)); PORTA = data; + break; + case 0x06: P_OUT(1,data & (UINT8)(~m_TRISB)); PORTB = data; + break; + case 0x8a: + case 0x0a: + m_PCLATH = data & 0x1f; + M_WRTRAM(0x0a, m_PCLATH); + break; + case 0x8b: + case 0x0b: M_WRTRAM(0x0b, data); + break; + case 0x81: m_OPTION = data; + M_WRTRAM(0x81, data); + break; + case 0x85: if (m_TRISA != data) + { + m_TRISA = data | 0xf0; + P_OUT(2,m_TRISA); + P_OUT(0,PORTA & (UINT8)(~m_TRISA) & 0x0f); + M_WRTRAM(addr, data); + } + break; + case 0x86: if (m_TRISB != data) + { + m_TRISB = data; + P_OUT(3,m_TRISB); + P_OUT(1,PORTB & (UINT8)(~m_TRISB)); + M_WRTRAM(addr, data); + } + break; + default: M_WRTRAM(addr, data); + break; + } +} + + +void pic16c62x_device::STORE_RESULT(offs_t addr, UINT8 data) +{ + if (m_opcode.b.l & 0x80) + { + STORE_REGFILE(addr, data); + } + else + { + m_W = data; + } +} + + +/************************************************************************ + * Emulate the Instructions + ************************************************************************/ + +/* This following function is here to fill in the void for */ +/* the opcode call function. This function is never called. */ + + +void pic16c62x_device::illegal() +{ + logerror("PIC16C62x: PC=%03x, Illegal opcode = %04x\n", (m_PC-1), m_opcode.w.l); +} + + +void pic16c62x_device::addwf() +{ + m_old_data = GET_REGFILE(ADDR); + m_ALU = m_old_data + m_W; + STORE_RESULT(ADDR, m_ALU); + CALCULATE_Z_FLAG(); + CALCULATE_ADD_CARRY(); + CALCULATE_ADD_DIGITCARRY(); +} + +void pic16c62x_device::addlw() +{ + m_ALU = (m_opcode.b.l & 0xff) + m_W; + m_W = m_ALU; + CALCULATE_Z_FLAG(); + CALCULATE_ADD_CARRY(); + CALCULATE_ADD_DIGITCARRY(); +} + +void pic16c62x_device::andwf() +{ + m_ALU = GET_REGFILE(ADDR) & m_W; + STORE_RESULT(ADDR, m_ALU); + CALCULATE_Z_FLAG(); +} + +void pic16c62x_device::andlw() +{ + m_ALU = m_opcode.b.l & m_W; + m_W = m_ALU; + CALCULATE_Z_FLAG(); +} + +void pic16c62x_device::bcf() +{ + m_ALU = GET_REGFILE(ADDR); + m_ALU &= bit_clr[POS]; + STORE_REGFILE(ADDR, m_ALU); +} + +void pic16c62x_device::bsf() +{ + m_ALU = GET_REGFILE(ADDR); + m_ALU |= bit_set[POS]; + STORE_REGFILE(ADDR, m_ALU); +} + +void pic16c62x_device::btfss() +{ + if ((GET_REGFILE(ADDR) & bit_set[POS]) == bit_set[POS]) + { + m_PC++ ; + PCL = m_PC & 0xff; + m_inst_cycles += 1; /* Add NOP cycles */ + } +} + +void pic16c62x_device::btfsc() +{ + if ((GET_REGFILE(ADDR) & bit_set[POS]) == 0) + { + m_PC++ ; + PCL = m_PC & 0xff; + m_inst_cycles += 1; /* Add NOP cycles */ + } +} + +void pic16c62x_device::call() +{ + PUSH_STACK(m_PC); + m_PC = ((m_PCLATH & 0x18) << 8) | (m_opcode.w.l & 0x7ff); + m_PC &= ADDR_MASK; + PCL = m_PC & 0xff; +} + +void pic16c62x_device::clrw() +{ + m_W = 0; + SET(STATUS, Z_FLAG); +} + +void pic16c62x_device::clrf() +{ + STORE_REGFILE(ADDR, 0); + SET(STATUS, Z_FLAG); +} + +void pic16c62x_device::clrwdt() +{ + m_WDT = 0; + if (PSA) m_prescaler = 0; + SET(STATUS, TO_FLAG); + SET(STATUS, PD_FLAG); +} + +void pic16c62x_device::comf() +{ + m_ALU = (UINT8)(~(GET_REGFILE(ADDR))); + STORE_RESULT(ADDR, m_ALU); + CALCULATE_Z_FLAG(); +} + +void pic16c62x_device::decf() +{ + m_ALU = GET_REGFILE(ADDR) - 1; + STORE_RESULT(ADDR, m_ALU); + CALCULATE_Z_FLAG(); +} + +void pic16c62x_device::decfsz() +{ + m_ALU = GET_REGFILE(ADDR) - 1; + STORE_RESULT(ADDR, m_ALU); + if (m_ALU == 0) + { + m_PC++ ; + PCL = m_PC & 0xff; + m_inst_cycles += 1; /* Add NOP cycles */ + } +} + +void pic16c62x_device::goto_op() +{ + m_PC = ((m_PCLATH & 0x18) << 8) | (m_opcode.w.l & 0x7ff); + m_PC &= ADDR_MASK; + PCL = m_PC & 0xff; +} + +void pic16c62x_device::incf() +{ + m_ALU = GET_REGFILE(ADDR) + 1; + STORE_RESULT(ADDR, m_ALU); + CALCULATE_Z_FLAG(); +} + +void pic16c62x_device::incfsz() +{ + m_ALU = GET_REGFILE(ADDR) + 1; + STORE_RESULT(ADDR, m_ALU); + if (m_ALU == 0) + { + m_PC++ ; + PCL = m_PC & 0xff; + m_inst_cycles += 1; /* Add NOP cycles */ + } +} + +void pic16c62x_device::iorlw() +{ + m_ALU = m_opcode.b.l | m_W; + m_W = m_ALU; + CALCULATE_Z_FLAG(); +} + +void pic16c62x_device::iorwf() +{ + m_ALU = GET_REGFILE(ADDR) | m_W; + STORE_RESULT(ADDR, m_ALU); + CALCULATE_Z_FLAG(); +} + +void pic16c62x_device::movf() +{ + m_ALU = GET_REGFILE(ADDR); + STORE_RESULT(ADDR, m_ALU); + CALCULATE_Z_FLAG(); +} + +void pic16c62x_device::movlw() +{ + m_W = m_opcode.b.l; +} + +void pic16c62x_device::movwf() +{ + STORE_REGFILE(ADDR, m_W); +} + +void pic16c62x_device::nop() +{ + /* Do nothing */ +} + +void pic16c62x_device::option() +{ + m_OPTION = m_W; +} + +void pic16c62x_device::retlw() +{ + m_W = m_opcode.b.l; + m_PC = POP_STACK(); + PCL = m_PC & 0xff; +} + +void pic16c62x_device::returns() +{ + m_PC = POP_STACK(); + PCL = m_PC & 0xff; +} + +void pic16c62x_device::retfie() +{ + m_PC = POP_STACK(); + PCL = m_PC & 0xff; + //INTCON(7)=1; +} + +void pic16c62x_device::rlf() +{ + m_ALU = GET_REGFILE(ADDR); + m_ALU <<= 1; + if (STATUS & C_FLAG) m_ALU |= 1; + if (GET_REGFILE(ADDR) & 0x80) SET(STATUS, C_FLAG); + else CLR(STATUS, C_FLAG); + STORE_RESULT(ADDR, m_ALU); +} + +void pic16c62x_device::rrf() +{ + m_ALU = GET_REGFILE(ADDR); + m_ALU >>= 1; + if (STATUS & C_FLAG) m_ALU |= 0x80; + if (GET_REGFILE(ADDR) & 1) SET(STATUS, C_FLAG); + else CLR(STATUS, C_FLAG); + STORE_RESULT(ADDR, m_ALU); +} + +void pic16c62x_device::sleepic() +{ + if (WDTE) m_WDT = 0; + if (PSA) m_prescaler = 0; + SET(STATUS, TO_FLAG); + CLR(STATUS, PD_FLAG); +} + +void pic16c62x_device::subwf() +{ + m_old_data = GET_REGFILE(ADDR); + m_ALU = m_old_data - m_W; + STORE_RESULT(ADDR, m_ALU); + CALCULATE_Z_FLAG(); + CALCULATE_SUB_CARRY(); + CALCULATE_SUB_DIGITCARRY(); +} + +void pic16c62x_device::sublw() +{ + m_ALU = (m_opcode.b.l & 0xff) - m_W; + m_W = m_ALU; + CALCULATE_Z_FLAG(); + CALCULATE_SUB_CARRY(); + CALCULATE_SUB_DIGITCARRY(); +} + +void pic16c62x_device::swapf() +{ + m_ALU = ((GET_REGFILE(ADDR) << 4) & 0xf0); + m_ALU |= ((GET_REGFILE(ADDR) >> 4) & 0x0f); + STORE_RESULT(ADDR, m_ALU); +} + +void pic16c62x_device::tris() +{ + switch(m_opcode.b.l & 0x7) + { + case 05: STORE_REGFILE(0x85, m_W); break; + case 06: STORE_REGFILE(0x86, m_W); break; + default: illegal(); break; + } +} + +void pic16c62x_device::xorlw() +{ + m_ALU = m_W ^ m_opcode.b.l; + m_W = m_ALU; + CALCULATE_Z_FLAG(); +} + +void pic16c62x_device::xorwf() +{ + m_ALU = GET_REGFILE(ADDR) ^ m_W; + STORE_RESULT(ADDR, m_ALU); + CALCULATE_Z_FLAG(); +} + + +/*********************************************************************** + * Instruction Table (Format, Instruction, Cycles) + ***********************************************************************/ + +const pic16c62x_device::pic16c62x_instruction pic16c62x_device::s_instructiontable[]= +{ + {(char *)"000111dfffffff", &pic16c62x_device::addwf, 1}, + {(char *)"000101dfffffff", &pic16c62x_device::andwf, 1}, + {(char *)"0000011fffffff", &pic16c62x_device::clrf, 1}, + {(char *)"00000100000011", &pic16c62x_device::clrw, 1}, + {(char *)"001001dfffffff", &pic16c62x_device::comf, 1}, + {(char *)"000011dfffffff", &pic16c62x_device::decf, 1}, + {(char *)"001011dfffffff", &pic16c62x_device::decfsz, 1}, + {(char *)"001010dfffffff", &pic16c62x_device::incf, 1}, + {(char *)"001111dfffffff", &pic16c62x_device::incfsz, 1}, + {(char *)"000100dfffffff", &pic16c62x_device::iorwf, 1}, + {(char *)"001000dfffffff", &pic16c62x_device::movf, 1}, + {(char *)"0000001fffffff", &pic16c62x_device::movwf, 1}, + {(char *)"0000000xx00000", &pic16c62x_device::nop, 1}, + {(char *)"001101dfffffff", &pic16c62x_device::rlf, 1}, + {(char *)"001100dfffffff", &pic16c62x_device::rrf, 1}, + {(char *)"000010dfffffff", &pic16c62x_device::subwf, 1}, + {(char *)"001110dfffffff", &pic16c62x_device::swapf, 1}, + {(char *)"000110dfffffff", &pic16c62x_device::xorwf, 1}, + {(char *)"0100bbbfffffff", &pic16c62x_device::bcf, 1}, + {(char *)"0101bbbfffffff", &pic16c62x_device::bsf, 1}, + {(char *)"0110bbbfffffff", &pic16c62x_device::btfsc, 1}, + {(char *)"0111bbbfffffff", &pic16c62x_device::btfss, 1}, + {(char *)"11111xkkkkkkkk", &pic16c62x_device::addlw, 1}, + {(char *)"111001kkkkkkkk", &pic16c62x_device::andlw, 1}, + {(char *)"100aaaaaaaaaaa", &pic16c62x_device::call, 2}, + {(char *)"101aaaaaaaaaaa", &pic16c62x_device::goto_op, 2}, + {(char *)"111000kkkkkkkk", &pic16c62x_device::iorlw, 1}, + {(char *)"1100xxkkkkkkkk", &pic16c62x_device::movlw, 1}, + {(char *)"00000000001001", &pic16c62x_device::retfie, 2}, + {(char *)"1101xxkkkkkkkk", &pic16c62x_device::retlw, 2}, + {(char *)"00000000001000", &pic16c62x_device::returns, 2}, + {(char *)"00000001100011", &pic16c62x_device::sleepic, 1}, + {(char *)"11110xkkkkkkkk", &pic16c62x_device::sublw, 1}, + {(char *)"111010kkkkkkkk", &pic16c62x_device::xorlw, 1}, + {(char *)"00000001100100", &pic16c62x_device::clrwdt, 1}, + {(char *)"00000001100010", &pic16c62x_device::option, 1}, // deprecated + {(char *)"00000001100fff", &pic16c62x_device::tris, 1}, // deprecated + {NULL, NULL, 0} +}; + +/*********************************************************************** + * Opcode Table build function + ***********************************************************************/ + +void pic16c62x_device::build_opcode_table(void) +{ +int instr,mask,bits; +int a; + + // defaults + for ( a = 0; a < 16384; a++) + { + m_opcode_table[a].cycles = 0; + m_opcode_table[a].function = &pic16c62x_device::illegal; + } + // build table + for( instr = 0; s_instructiontable[instr].cycles != 0; instr++) + { + bits=0; + mask=0; + for ( a = 0; a < 14; a++) + { + switch (s_instructiontable[instr].format[a]) + { + case '0': + bits = bits << 1; + mask = (mask << 1) | 1; + break; + case '1': + bits = (bits << 1) | 1; + mask = (mask << 1) | 1; + break; + default: + bits = bits << 1; + mask = mask << 1; + break; + } + } + for ( a = 0; a < 16384; a++) + { + if (((a & mask) == bits) && (m_opcode_table[a].cycles == 0)) + { + m_opcode_table[a].cycles = s_instructiontable[instr].cycles; + m_opcode_table[a].function = s_instructiontable[instr].function; + } + } + } +} + +/**************************************************************************** + * Inits CPU emulation + ****************************************************************************/ + +void pic16c62x_device::device_start() +{ + m_program = &space(AS_PROGRAM); + m_direct = &m_program->direct(); + m_data = &space(AS_DATA); + m_io = &space(AS_IO); + + m_CONFIG = 0x3fff; + + /* ensure the internal ram pointers are set before get_info is called */ + update_internalram_ptr(); + + build_opcode_table(); + + save_item(NAME(m_W)); + save_item(NAME(m_ALU)); + save_item(NAME(m_OPTION)); + save_item(NAME(m_PCLATH)); + save_item(NAME(TMR0)); + save_item(NAME(PCL)); + save_item(NAME(STATUS)); + save_item(NAME(FSR)); + save_item(NAME(PORTA)); + save_item(NAME(PORTB)); + save_item(NAME(m_TRISA)); + save_item(NAME(m_TRISB)); + save_item(NAME(m_old_T0)); + save_item(NAME(m_old_data)); + save_item(NAME(m_picRAMmask)); + save_item(NAME(m_WDT)); + save_item(NAME(m_prescaler)); + save_item(NAME(m_STACK[0])); + save_item(NAME(m_STACK[1])); + save_item(NAME(m_STACK[2])); + save_item(NAME(m_STACK[3])); + save_item(NAME(m_STACK[4])); + save_item(NAME(m_STACK[5])); + save_item(NAME(m_STACK[6])); + save_item(NAME(m_STACK[7])); + save_item(NAME(m_PC)); + save_item(NAME(m_PREVPC)); + save_item(NAME(m_CONFIG)); + save_item(NAME(m_opcode.d)); + save_item(NAME(m_delay_timer)); + save_item(NAME(m_picmodel)); + save_item(NAME(m_reset_vector)); + + save_item(NAME(m_temp_config)); + save_item(NAME(m_inst_cycles)); + + state_add( PIC16C62x_PC, "PC", m_PC).mask(0xfff).formatstr("%03X"); + state_add( PIC16C62x_W, "W", m_W).formatstr("%02X"); + state_add( PIC16C62x_ALU, "ALU", m_ALU).formatstr("%02X"); + state_add( PIC16C62x_STR, "STR", m_debugger_temp).mask(0xff).callimport().callexport().formatstr("%02X"); + state_add( PIC16C62x_TMR0, "TMR", m_debugger_temp).mask(0xff).callimport().callexport().formatstr("%02X"); + state_add( PIC16C62x_WDT, "WDT", m_WDT).formatstr("%04X"); + state_add( PIC16C62x_OPT, "OPT", m_OPTION).formatstr("%02X"); + state_add( PIC16C62x_STK0, "STK0", m_STACK[0]).mask(0xfff).formatstr("%03X"); + state_add( PIC16C62x_STK1, "STK1", m_STACK[1]).mask(0xfff).formatstr("%03X"); + state_add( PIC16C62x_STK2, "STK2", m_STACK[2]).mask(0xfff).formatstr("%03X"); + state_add( PIC16C62x_STK3, "STK3", m_STACK[3]).mask(0xfff).formatstr("%03X"); + state_add( PIC16C62x_STK4, "STK4", m_STACK[4]).mask(0xfff).formatstr("%03X"); + state_add( PIC16C62x_STK5, "STK5", m_STACK[5]).mask(0xfff).formatstr("%03X"); + state_add( PIC16C62x_STK6, "STK6", m_STACK[6]).mask(0xfff).formatstr("%03X"); + state_add( PIC16C62x_STK7, "STK7", m_STACK[7]).mask(0xfff).formatstr("%03X"); + state_add( PIC16C62x_PRTA, "PRTA", m_debugger_temp).mask(0x1f).callimport().callexport().formatstr("%02X"); + state_add( PIC16C62x_PRTB, "PRTB", m_debugger_temp).mask(0xff).callimport().callexport().formatstr("%02X"); + state_add( PIC16C62x_TRSA, "TRSA", m_TRISA).mask(0x1f).formatstr("%02X"); + state_add( PIC16C62x_TRSB, "TRSB", m_TRISB).formatstr("%02X"); + state_add( PIC16C62x_FSR, "FSR", m_debugger_temp).mask(0xff).callimport().callexport().formatstr("%02X"); + state_add( PIC16C62x_PSCL, "PSCL", m_debugger_temp).callimport().formatstr("%3s"); + + state_add( STATE_GENPC, "GENPC", m_PC).noshow(); + state_add( STATE_GENFLAGS, "GENFLAGS", m_OPTION).formatstr("%13s").noshow(); + state_add( STATE_GENPCBASE, "PREVPC", m_PREVPC).noshow(); + + m_icountptr = &m_icount; +} + +void pic16c62x_device::state_import(const device_state_entry &entry) +{ + switch (entry.index()) + { + case PIC16C62x_STR: + STATUS = m_debugger_temp; + break; + case PIC16C62x_TMR0: + TMR0 = m_debugger_temp; + break; + case PIC16C62x_PRTA: + PORTA = m_debugger_temp; + break; + case PIC16C62x_PRTB: + PORTB = m_debugger_temp; + break; + case PIC16C62x_FSR: + FSR = ((m_debugger_temp & m_picRAMmask) | (UINT8)(~m_picRAMmask)); + break; + case PIC16C62x_PSCL: + m_prescaler = m_debugger_temp; + break; + } +} + +void pic16c62x_device::state_export(const device_state_entry &entry) +{ + switch (entry.index()) + { + case PIC16C62x_STR: + m_debugger_temp = STATUS; + break; + case PIC16C62x_TMR0: + m_debugger_temp = TMR0; + break; + case PIC16C62x_PRTA: + m_debugger_temp = PORTA & 0x1f; + break; + case PIC16C62x_PRTB: + m_debugger_temp = PORTB; + break; + case PIC16C62x_FSR: + m_debugger_temp = ((FSR) & m_picRAMmask) | (UINT8)(~m_picRAMmask); + break; + } +} + +void pic16c62x_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + switch (entry.index()) + { + case PIC16C62x_PSCL: + strprintf(str, "%c%02X", ((m_OPTION & 0x08) ? 'W' : 'T'), m_prescaler); + break; + + case STATE_GENFLAGS: + strprintf(str, "%01x%c%c%c%c%c %c%c%c%03x", + (STATUS & 0xe0) >> 5, + STATUS & 0x10 ? '.':'O', /* WDT Overflow */ + STATUS & 0x08 ? 'P':'D', /* Power/Down */ + STATUS & 0x04 ? 'Z':'.', /* Zero */ + STATUS & 0x02 ? 'c':'b', /* Nibble Carry/Borrow */ + STATUS & 0x01 ? 'C':'B', /* Carry/Borrow */ + + m_OPTION & 0x20 ? 'C':'T', /* Counter/Timer */ + m_OPTION & 0x10 ? 'N':'P', /* Negative/Positive */ + m_OPTION & 0x08 ? 'W':'T', /* WatchDog/Timer */ + m_OPTION & 0x08 ? (1<<(m_OPTION&7)) : (2<<(m_OPTION&7)) ); + break; + } +} + +/**************************************************************************** + * Reset registers to their initial values + ****************************************************************************/ + +void pic16c62x_device::pic16c62x_reset_regs() +{ + m_PC = m_reset_vector; + m_TRISA = 0x1f; + m_TRISB = 0xff; + m_OPTION = 0xff; + STATUS = 0x18; + PCL = 0; + FSR |= (UINT8)(~m_picRAMmask); + PORTA = 0; + m_prescaler = 0; + m_delay_timer = 0; + m_old_T0 = 0; + m_inst_cycles = 0; + PIC16C62x_RAM_WRMEM(0x85,m_TRISA); + PIC16C62x_RAM_WRMEM(0x86,m_TRISB); + PIC16C62x_RAM_WRMEM(0x81,m_OPTION); +} + +void pic16c62x_device::pic16c62x_soft_reset() +{ + SET(STATUS, (TO_FLAG | PD_FLAG | Z_FLAG | DC_FLAG | C_FLAG)); + pic16c62x_reset_regs(); +} + +void pic16c62x_device::pic16c62x_set_config(int data) +{ + logerror("Writing %04x to the PIC16C62x configuration bits\n",data); + m_CONFIG = (data & 0x3fff); +} + + +/**************************************************************************** + * WatchDog + ****************************************************************************/ + +void pic16c62x_device::pic16c62x_update_watchdog(int counts) +{ + /* TODO: needs updating */ + /* WatchDog is set up to count 18,000 (0x464f hex) ticks to provide */ + /* the timeout period of 0.018ms based on a 4MHz input clock. */ + /* Note: the 4MHz clock should be divided by the PIC16C5x_CLOCK_DIVIDER */ + /* which effectively makes the PIC run at 1MHz internally. */ + + /* If the current instruction is CLRWDT or SLEEP, don't update the WDT */ + + if ((m_opcode.w.l != 0x64) && (m_opcode.w.l != 0x63)) + { + UINT16 old_WDT = m_WDT; + + m_WDT -= counts; + + if (m_WDT > 0x464f) { + m_WDT = 0x464f - (0xffff - m_WDT); + } + + if (((old_WDT != 0) && (old_WDT < m_WDT)) || (m_WDT == 0)) + { + if (PSA) { + m_prescaler++; + if (m_prescaler >= (1 << PS)) { /* Prescale values from 1 to 128 */ + m_prescaler = 0; + CLR(STATUS, TO_FLAG); + pic16c62x_soft_reset(); + } + } + else { + CLR(STATUS, TO_FLAG); + pic16c62x_soft_reset(); + } + } + } +} + + +/**************************************************************************** + * Update Timer + ****************************************************************************/ + +void pic16c62x_device::pic16c62x_update_timer(int counts) +{ + if (PSA == 0) { + m_prescaler += counts; + if (m_prescaler >= (2 << PS)) { /* Prescale values from 2 to 256 */ + TMR0 += (m_prescaler / (2 << PS)); + m_prescaler %= (2 << PS); /* Overflow prescaler */ + } + } + else { + TMR0 += counts; + } +} + + +/**************************************************************************** + * Execute IPeriod. Return 0 if emulation should be stopped + ****************************************************************************/ + +void pic16c62x_device::execute_run() +{ + UINT8 T0_in; + + update_internalram_ptr(); + + do + { + if (PD == 0) /* Sleep Mode */ + { + m_inst_cycles = 1; + debugger_instruction_hook(this, m_PC); + if (WDTE) { + pic16c62x_update_watchdog(1); + } + } + else + { + m_PREVPC = m_PC; + + debugger_instruction_hook(this, m_PC); + + m_opcode.d = M_RDOP(m_PC); + m_PC++; + PCL++; + + m_inst_cycles = m_opcode_table[m_opcode.w.l & 16383].cycles; + (this->*m_opcode_table[m_opcode.w.l & 16383].function)(); + + if (T0CS) { /* Count mode */ + T0_in = S_T0_IN; + if (T0_in) T0_in = 1; + if (T0SE) { /* Count falling edge T0 input */ + if (FALLING_EDGE_T0) { + pic16c62x_update_timer(1); + } + } + else { /* Count rising edge T0 input */ + if (RISING_EDGE_T0) { + pic16c62x_update_timer(1); + } + } + m_old_T0 = T0_in; + } + else { /* Timer mode */ + if (m_delay_timer) { + m_delay_timer--; + } + else { + pic16c62x_update_timer(m_inst_cycles); + } + } + if (WDTE) { + pic16c62x_update_watchdog(m_inst_cycles); + } + } + + m_icount -= m_inst_cycles; + + } while (m_icount > 0); +} + + +void pic16c62x_device::device_reset() +{ + update_internalram_ptr(); + + pic16c62x_reset_regs(); + SET(STATUS, (TO_FLAG | PD_FLAG)); +} diff --git a/src/devices/cpu/pic16c62x/pic16c62x.h b/src/devices/cpu/pic16c62x/pic16c62x.h new file mode 100644 index 00000000000..f7ac6fd43ae --- /dev/null +++ b/src/devices/cpu/pic16c62x/pic16c62x.h @@ -0,0 +1,265 @@ +// license:BSD-3-Clause +// copyright-holders:Tony La Porta + /**************************************************************************\ + * Microchip PIC16C62X Emulator * + * * + * Based On * + * Microchip PIC16C5X Emulator * + * Copyright Tony La Porta * + * Originally written for the MAME project. * + * * + * * + * Addressing architecture is based on the Harvard addressing scheme. * + * * + \**************************************************************************/ + +#pragma once + +#ifndef __PIC16C62X_H__ +#define __PIC16C62X_H__ + + + + +/************************************************************************** + * Internal Clock divisor + * + * External Clock is divided internally by 4 for the instruction cycle + * times. (Each instruction cycle passes through 4 machine states). This + * is handled by the cpu execution engine. + */ + +enum +{ + PIC16C62x_PC=1, PIC16C62x_STK0, PIC16C62x_STK1, PIC16C62x_STK2, + PIC16C62x_STK3, PIC16C62x_STK4, PIC16C62x_STK5, PIC16C62x_STK6, + PIC16C62x_STK7, PIC16C62x_FSR, PIC16C62x_W, PIC16C62x_ALU, + PIC16C62x_STR, PIC16C62x_OPT, PIC16C62x_TMR0, PIC16C62x_PRTA, + PIC16C62x_PRTB, PIC16C62x_WDT, PIC16C62x_TRSA, PIC16C62x_TRSB, + PIC16C62x_PSCL +}; + +#define PIC16C62x_T0 0 + + +extern const device_type PIC16C620; +extern const device_type PIC16C620A; +//extern const device_type PIC16CR620A; +extern const device_type PIC16C621; +extern const device_type PIC16C621A; +extern const device_type PIC16C622; +extern const device_type PIC16C622A; + + +class pic16c62x_device : public cpu_device +{ +public: + // construction/destruction + pic16c62x_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, int program_width, int picmodel); + + /**************************************************************************** + * Function to configure the CONFIG register. This is actually hard-wired + * during ROM programming, so should be called in the driver INIT, with + * the value if known (available in HEX dumps of the ROM). + */ + + void pic16c62x_set_config(device_t *cpu, int data); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_execute_interface overrides + virtual UINT64 execute_clocks_to_cycles(UINT64 clocks) const { return (clocks + 4 - 1) / 4; } + virtual UINT64 execute_cycles_to_clocks(UINT64 cycles) const { return (cycles * 4); } + virtual UINT32 execute_min_cycles() const { return 1; } + virtual UINT32 execute_max_cycles() const { return 2; } + virtual UINT32 execute_input_lines() const { return 1; } + virtual UINT32 execute_default_irq_vector() const { return 0; } + virtual void execute_run(); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const + { + return (spacenum == AS_PROGRAM) ? &m_program_config : ( (spacenum == AS_IO) ? &m_io_config : ( (spacenum == AS_DATA) ? &m_data_config : NULL ) ); + } + + // device_state_interface overrides + virtual void state_import(const device_state_entry &entry); + virtual void state_export(const device_state_entry &entry); + void state_string_export(const device_state_entry &entry, std::string &str); + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const { return 2; } + virtual UINT32 disasm_max_opcode_bytes() const { return 2; } + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + +private: + address_space_config m_program_config; + address_space_config m_data_config; + address_space_config m_io_config; + + /******************** CPU Internal Registers *******************/ + UINT16 m_PC; + UINT16 m_PREVPC; /* previous program counter */ + UINT8 m_W; + UINT8 m_PCLATH; /* 0a,8a */ + UINT8 m_OPTION; /* 81 */ + UINT16 m_CONFIG; + UINT8 m_ALU; + UINT16 m_WDT; + UINT8 m_TRISA; /* 85 */ + UINT8 m_TRISB; /* 86 */ + UINT16 m_STACK[8]; + UINT16 m_prescaler; /* Note: this is really an 8-bit register */ + PAIR m_opcode; + UINT8 *m_internalram; + + int m_icount; + int m_reset_vector; + int m_picmodel; + int m_delay_timer; + UINT16 m_temp_config; + UINT8 m_old_T0; + INT8 m_old_data; + UINT8 m_picRAMmask; + int m_inst_cycles; + + address_space *m_program; + direct_read_data *m_direct; + address_space *m_data; + address_space *m_io; + + // For debugger + int m_debugger_temp; + + /* opcode table entry */ + typedef void (pic16c62x_device::*pic16c62x_ophandler)(); + struct pic16c62x_opcode + { + UINT8 cycles; + pic16c62x_ophandler function; + }; + pic16c62x_opcode m_opcode_table[16384]; + + /* instruction list entry */ + struct pic16c62x_instruction + { + char *format; + pic16c62x_ophandler function; + UINT8 cycles; + }; + static const pic16c62x_instruction s_instructiontable[]; + + void update_internalram_ptr(); + void CALCULATE_Z_FLAG(); + void CALCULATE_ADD_CARRY(); + void CALCULATE_ADD_DIGITCARRY(); + void CALCULATE_SUB_CARRY(); + void CALCULATE_SUB_DIGITCARRY(); + UINT16 POP_STACK(); + void PUSH_STACK(UINT16 data); + UINT8 GET_REGFILE(offs_t addr); + void STORE_REGFILE(offs_t addr, UINT8 data); + void STORE_RESULT(offs_t addr, UINT8 data); + void illegal(); + void addwf(); + void addlw(); + void andwf(); + void andlw(); + void bcf(); + void bsf(); + void btfss(); + void btfsc(); + void call(); + void clrw(); + void clrf(); + void clrwdt(); + void comf(); + void decf(); + void decfsz(); + void goto_op(); + void incf(); + void incfsz(); + void iorlw(); + void iorwf(); + void movf(); + void movlw(); + void movwf(); + void nop(); + void option(); + void retlw(); + void returns(); + void retfie(); + void rlf(); + void rrf(); + void sleepic(); + void subwf(); + void sublw(); + void swapf(); + void tris(); + void xorlw(); + void xorwf(); + void build_opcode_table(void); + void pic16c62x_reset_regs(); + void pic16c62x_soft_reset(); + void pic16c62x_set_config(int data); + void pic16c62x_update_watchdog(int counts); + void pic16c62x_update_timer(int counts); + +}; + + +class pic16c620_device : public pic16c62x_device +{ +public: + // construction/destruction + pic16c620_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class pic16c620a_device : public pic16c62x_device +{ +public: + // construction/destruction + pic16c620a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +/* +class pic16cr620a_device : public pic16c62x_device +{ +public: + // construction/destruction + pic16cr620a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}*/ + +class pic16c621_device : public pic16c62x_device +{ +public: + // construction/destruction + pic16c621_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class pic16c621a_device : public pic16c62x_device +{ +public: + // construction/destruction + pic16c621a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class pic16c622_device : public pic16c62x_device +{ +public: + // construction/destruction + pic16c622_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class pic16c622a_device : public pic16c62x_device +{ +public: + // construction/destruction + pic16c622a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +#endif /* __PIC16C62X_H__ */ diff --git a/src/devices/cpu/powerpc/drc_ops.c b/src/devices/cpu/powerpc/drc_ops.c new file mode 100644 index 00000000000..cfe3614fb5a --- /dev/null +++ b/src/devices/cpu/powerpc/drc_ops.c @@ -0,0 +1,3800 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/* PowerPC common opcodes */ + +// it really seems like this should be elsewhere - like maybe the floating point checks can hang out someplace else +#include + +#define USE_SSE2 0 +#define COMPILE_FPU 0 + +/* recompiler flags */ +#define RECOMPILE_UNIMPLEMENTED 0x0000 +#define RECOMPILE_SUCCESSFUL 0x0001 +#define RECOMPILE_SUCCESSFUL_CP(c,p) (RECOMPILE_SUCCESSFUL | (((c) & 0xff) << 16) | (((p) & 0xff) << 24)) +#define RECOMPILE_END_OF_STRING 0x0002 +#define RECOMPILE_ADD_DISPATCH 0x0004 + +INLINE void emit_mov_r64_m64(x86code **emitptr, UINT8 reghi, UINT8 reglo, DECLARE_MEMPARAMS) +{ + emit_mov_r32_m32(emitptr, reglo, MEMPARAMS); + emit_mov_r32_m32(emitptr, reghi, base, index, scale, disp+4); +} + +INLINE void emit_mov_m64_r64(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 reghi, UINT8 reglo) +{ + emit_mov_m32_r32(emitptr, MEMPARAMS, reglo); + emit_mov_m32_r32(emitptr, base, index, scale, disp+4, reghi); +} + + +static UINT32 compile_one(drc_core *drc, UINT32 pc); + +static void append_generate_exception(drc_core *drc, UINT8 exception); +static void append_check_interrupts(drc_core *drc, int inline_generate); +static UINT32 recompile_instruction(drc_core *drc, UINT32 pc, UINT32 *opptr); + +static UINT32 temp_ppc_pc; + +static void ppcdrc_init(void) +{ + drc_config drconfig; + + /* fill in the config */ + memset(&drconfig, 0, sizeof(drconfig)); + drconfig.cache_size = CACHE_SIZE; + drconfig.max_instructions = MAX_INSTRUCTIONS; + drconfig.address_bits = 32; + drconfig.lsbs_to_ignore = 2; + drconfig.uses_fp = 1; + drconfig.uses_sse = USE_SSE2; + drconfig.pc_in_memory = 0; + drconfig.icount_in_memory = 0; + drconfig.pcptr = (UINT32 *)&ppc.pc; + drconfig.icountptr = (UINT32 *)&ppc_icount; + drconfig.esiptr = NULL; + drconfig.cb_reset = CPU_RESET_NAME(ppcdrc); + drconfig.cb_recompile = ppcdrc_recompile; + drconfig.cb_entrygen = ppcdrc_entrygen; + + /* initialize the compiler */ + ppc.drc = drc_init(cpunum_get_active(), &drconfig); + ppc.drcoptions = 0; +} + +static void ppcdrc_reset(drc_core *drc) +{ + code_log_reset(); + + code_log("entry_point:", (x86code *)drc->entry_point, drc->out_of_cycles); + code_log("out_of_cycles:", drc->out_of_cycles, drc->recompile); + code_log("recompile:", drc->recompile, drc->dispatch); + code_log("dispatch:", drc->dispatch, drc->flush); + code_log("flush:", drc->flush, drc->cache_top); + + ppc.invoke_exception_handler = drc->cache_top; + drc_append_restore_volatiles(drc); + emit_mov_r32_m32(DRCTOP, REG_EAX, MBD(REG_ESP, 4)); + emit_mov_r32_m32(DRCTOP, REG_ESP, MABS(&ppc.host_esp)); + emit_mov_m32_r32(DRCTOP, MABS(&SRR0), REG_EDI); /* save return address */ + emit_jmp_r32(DRCTOP, REG_EAX); + code_log("invoke_exception_handler:", ppc.invoke_exception_handler, drc->cache_top); + + ppc.generate_interrupt_exception = drc->cache_top; + append_generate_exception(drc, EXCEPTION_IRQ); + code_log("generate_interrupt_exception:", ppc.generate_interrupt_exception, drc->cache_top); + + ppc.generate_syscall_exception = drc->cache_top; + append_generate_exception(drc, EXCEPTION_SYSTEM_CALL); + code_log("generate_syscall_exception:", ppc.generate_syscall_exception, drc->cache_top); + + ppc.generate_decrementer_exception = drc->cache_top; + append_generate_exception(drc, EXCEPTION_DECREMENTER); + code_log("generate_decrementer_exception:", ppc.generate_decrementer_exception, drc->cache_top); + + ppc.generate_trap_exception = drc->cache_top; + append_generate_exception(drc, EXCEPTION_TRAP); + code_log("generate_trap_exception:", ppc.generate_trap_exception, drc->cache_top); + + ppc.generate_dsi_exception = drc->cache_top; + append_generate_exception(drc, EXCEPTION_DSI); + code_log("generate_dsi_exception:", ppc.generate_dsi_exception, drc->cache_top); + + ppc.generate_isi_exception = drc->cache_top; + append_generate_exception(drc, EXCEPTION_ISI); + code_log("generate_isi_exception:", ppc.generate_isi_exception, drc->cache_top); + + if (!ppc.is603 && !ppc.is602) + { + ppc.generate_fit_exception = drc->cache_top; + append_generate_exception(drc, EXCEPTION_FIXED_INTERVAL_TIMER); + code_log("generate_fit_exception:", ppc.generate_fit_exception, drc->cache_top); + } +} + +static CPU_EXIT( ppcdrc ) +{ + drc_exit(ppc.drc); +} + +static UINT32 *ppcdrc_getopptr(UINT32 address) +{ + UINT32 *result; + UINT32 offset = 0; + + if (ppc.is603 || ppc.is602) + { + if (MSR & MSR_IR) + { + if (!ppc_translate_address(&address, PPC_TRANSLATE_CODE | PPC_TRANSLATE_READ | PPC_TRANSLATE_NOEXCEPTION)) + return NULL; + } + address = DWORD_XOR_BE(address); + offset = (address & 0x07) / sizeof(*result); + address &= ~0x07; + } + + result = (UINT32 *) memory_decrypted_read_ptr(ppc.core->program, address); + if (result) + result += offset; + return result; +} + +static void ppcdrc_recompile(drc_core *drc) +{ + int remaining = MAX_INSTRUCTIONS; + x86code *start = drc->cache_top; + UINT32 pc = ppc.pc; + UINT32 *opptr; + + (void)start; + + /* begin the sequence */ + drc_begin_sequence(drc, pc); + code_log_reset(); + + /* loose verification case: one verification here only */ + if (!(ppc.drcoptions & PPCDRC_OPTIONS_CHECK_SELFMOD_CODE)) + { + opptr = ppcdrc_getopptr(pc); + if (opptr) + drc_append_verify_code(drc, opptr, 4); + } + + /* loop until we hit an unconditional branch */ + while (--remaining != 0) + { + UINT32 result; + + /* compile one instruction */ + result = compile_one(drc, pc); + pc += (INT8)(result >> 24); + if (result & RECOMPILE_END_OF_STRING) + break; + + /* do not recompile across MMU page boundaries */ + if ((pc & 0x0FFF) == 0) + { + remaining = 0; + break; + } + } + + /* add dispatcher just in case */ + if (remaining == 0) + drc_append_dispatcher(drc); + + /* end the sequence */ + drc_end_sequence(drc); + +if (0) +{ + char label[40]; + sprintf(label, "Code @ %08X", ppc.pc); + code_log(label, start, drc->cache_top); +} +} + +static void update_counters(drc_core *drc) +{ + emit_link link1; + + /* decrementer */ + if (ppc.is603 || ppc.is602) + { + emit_cmp_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_dec_trigger_cycle)); + emit_jcc_short_link(DRCTOP, COND_NZ, &link1); + emit_or_m32_imm(DRCTOP, MABS(&ppc.exception_pending), 0x2); + resolve_link(DRCTOP, &link1); + } + + /* FIT */ + if (!ppc.is603 && !ppc.is602) + { + emit_link link2; + emit_cmp_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_fit_trigger_cycle)); + emit_jcc_short_link(DRCTOP, COND_NZ, &link1); + emit_cmp_r32_m32(DRCTOP, REG_EBP, MABS(&ppc.fit_int_enable)); + emit_jcc_short_link(DRCTOP, COND_Z, &link2); + emit_or_m32_imm(DRCTOP, MABS(&ppc.exception_pending), 0x4); + resolve_link(DRCTOP, &link1); + resolve_link(DRCTOP, &link2); + } +} + +static void ppcdrc_entrygen(drc_core *drc) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc.host_esp), REG_ESP); + append_check_interrupts(drc, 0); +} + +static UINT32 compile_one(drc_core *drc, UINT32 pc) +{ + int pcdelta, cycles; + UINT32 *opptr; + UINT32 result; + + /* register this instruction */ + drc_register_code_at_cache_top(drc, pc); + + /* get a pointer to the current instruction */ + opptr = ppcdrc_getopptr(pc); + + //log_symbol(drc, ~2); + //log_symbol(drc, pc); + + /* emit debugging call */ + drc_append_call_debugger(drc); + + /* null opptr? if legit, we need to generate an ISI exception */ + if (!opptr) + { + /* first check to see if the code is up to date; if not, recompile */ + emit_push_imm(DRCTOP, pc); + emit_call(DRCTOP, (x86code *)ppcdrc_getopptr); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_cmp_r32_imm(DRCTOP, REG_EAX, 0); + emit_jcc(DRCTOP, COND_NZ, drc->recompile); + + /* code is up to date; do the exception */ + emit_mov_m32_r32(DRCTOP, MABS(&SRR0), REG_EDI); /* save return address */ + emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(&ppc.generate_isi_exception)); + emit_jmp_r32(DRCTOP, REG_EAX); + return RECOMPILE_SUCCESSFUL | RECOMPILE_END_OF_STRING; + } + + /* emit self-modifying code checks */ + if (ppc.drcoptions & PPCDRC_OPTIONS_CHECK_SELFMOD_CODE) + { + drc_append_verify_code(drc, opptr, 4); + } + + /* compile the instruction */ + result = recompile_instruction(drc, pc, opptr); + + /* handle the results */ + if (!(result & RECOMPILE_SUCCESSFUL)) + fatalerror("Unimplemented op %08X\n", *opptr); + + pcdelta = (INT8)(result >> 24); + cycles = (INT8)(result >> 16); + + /* epilogue */ + update_counters(drc); + drc_append_standard_epilogue(drc, cycles, pcdelta, 1); + + if (result & RECOMPILE_ADD_DISPATCH) + drc_append_dispatcher(drc); + + return (result & 0xffff) | ((UINT8)cycles << 16) | ((UINT8)pcdelta << 24); +} + +static UINT32 recompile_instruction(drc_core *drc, UINT32 pc, UINT32 *opptr) +{ + UINT32 opcode; + temp_ppc_pc = pc; + + opcode = *opptr; + + code_log_add_entry(pc, opcode, drc->cache_top); + + if (opcode != 0) { // this is a little workaround for VF3 + switch(opcode >> 26) + { + case 19: return ppc.optable19[(opcode >> 1) & 0x3ff](drc, opcode); + case 31: return ppc.optable31[(opcode >> 1) & 0x3ff](drc, opcode); + case 59: return ppc.optable59[(opcode >> 1) & 0x3ff](drc, opcode); + case 63: return ppc.optable63[(opcode >> 1) & 0x3ff](drc, opcode); + default: return ppc.optable[opcode >> 26](drc, opcode); + } + } + return RECOMPILE_SUCCESSFUL | RECOMPILE_END_OF_STRING; +} + + +static const UINT32 exception_vector[32] = +{ + 0x0000, 0x0500, 0x0900, 0x0700, 0x0c00, 0x1400, 0x0300, 0x0400, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x1000, 0x1010, 0x1020 +}; + +static void append_generate_exception(drc_core *drc, UINT8 exception) +{ + emit_link link1, link2, link3; + + emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(&ppc.msr)); + emit_and_r32_imm(DRCTOP, REG_EAX, 0xff73); + emit_mov_m32_r32(DRCTOP, MABS(&SRR1), REG_EAX); + emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(&ppc.msr)); + + // Clear POW, EE, PR, FP, FE0, SE, BE, FE1, IR, DR, RI + emit_and_r32_imm(DRCTOP, REG_EAX, ~(MSR_POW | MSR_EE | MSR_PR | MSR_FP | MSR_FE0 | MSR_SE | MSR_BE | MSR_FE1 | MSR_IR | MSR_DR | MSR_RI)); + // Set LE to ILE + emit_and_r32_imm(DRCTOP, REG_EAX, ~MSR_LE); // clear LE first + emit_test_r32_imm(DRCTOP, REG_EAX, MSR_ILE); + emit_jcc_short_link(DRCTOP, COND_Z, &link1); // if Z == 0, bit == 1 + emit_or_r32_imm(DRCTOP, REG_EAX, MSR_LE); // set LE + resolve_link(DRCTOP, &link1); + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_push_r32(DRCTOP, REG_EAX); + emit_call(DRCTOP, (x86code *)ppc_set_msr); + emit_pop_r32(DRCTOP, REG_EDX); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + + if (ppc.is603) + { + emit_mov_r32_imm(DRCTOP, REG_EDI, exception_vector[exception]); // first move the exception handler offset + emit_test_r32_imm(DRCTOP, REG_EDX, MSR_IP); // test if the base should be 0xfff0 or EVPR + emit_jcc_short_link(DRCTOP, COND_Z, &link2); // if Z == 1, bit == 0 means base == 0x00000000 + emit_or_r32_imm(DRCTOP, REG_EDI, 0xfff00000); // else base == 0xfff00000 + resolve_link(DRCTOP, &link2); + } + else if (ppc.is602) + { + emit_mov_r32_imm(DRCTOP, REG_EDI, exception_vector[exception]); // first move the exception handler offset + emit_test_r32_imm(DRCTOP, REG_EDX, MSR_IP); // test if the base should be 0xfff0 or IBR + emit_jcc_short_link(DRCTOP, COND_NZ, &link2); // if Z == 0, bit == 1 means base == 0xfff00000 + emit_or_r32_m32(DRCTOP, REG_EDI, MABS(&ppc.ibr)); // else base == IBR + emit_jmp_short_link(DRCTOP, &link3); + resolve_link(DRCTOP, &link2); + emit_or_r32_imm(DRCTOP, REG_EDI, 0xfff00000); + resolve_link(DRCTOP, &link3); + } + else + { + emit_mov_r32_imm(DRCTOP, REG_EDI, exception_vector[exception]); // first move the exception handler offset + emit_test_r32_imm(DRCTOP, REG_EDX, MSR_IP); // test if the base should be 0xfff0 or EVPR + emit_jcc_short_link(DRCTOP, COND_NZ, &link2); // if Z == 0, bit == 1 means base == 0xfff00000 + emit_or_r32_m32(DRCTOP, REG_EDI, MABS(&EVPR)); // else base == EVPR + emit_jmp_short_link(DRCTOP, &link3); + resolve_link(DRCTOP, &link2); + emit_or_r32_imm(DRCTOP, REG_EDI, 0xfff00000); + resolve_link(DRCTOP, &link3); + } + + if (exception == EXCEPTION_IRQ) + { + emit_and_m32_imm(DRCTOP, MABS(&ppc.exception_pending), ~0x1); // clear pending irq + } + if (exception == EXCEPTION_DECREMENTER) + { + emit_and_m32_imm(DRCTOP, MABS(&ppc.exception_pending), ~0x2); // clear pending decrementer exception + } + if (exception == EXCEPTION_FIXED_INTERVAL_TIMER) + { + emit_and_m32_imm(DRCTOP, MABS(&ppc.exception_pending), ~0x4); // clear pending fit exception + } + + drc_append_dispatcher(drc); +} + +static void append_check_interrupts(drc_core *drc, int inline_generate) +{ + if (ppc.is602 || ppc.is603) + { + emit_link link1, link2, link3, link4; + emit_test_m32_imm(DRCTOP, MABS(&ppc.msr), MSR_EE); /* no interrupt if external interrupts are not enabled */ + emit_jcc_short_link(DRCTOP, COND_Z, &link1); /* ZF = 1 if bit == 0 */ + + /* else check if any interrupt are pending */ + emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(&ppc.exception_pending)); + emit_cmp_r32_imm(DRCTOP, REG_EAX, 0); + emit_jcc_short_link(DRCTOP, COND_Z, &link2); /* reg == 0, no exceptions are pending */ + + /* else handle the first pending exception */ + emit_test_r32_imm(DRCTOP, REG_EAX, 0x1); /* is it a IRQ? */ + emit_jcc_short_link(DRCTOP, COND_Z, &link3); + + emit_mov_m32_r32(DRCTOP, MABS(&SRR0), REG_EDI); /* save return address */ + emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(&ppc.generate_interrupt_exception)); + emit_jmp_r32(DRCTOP, REG_EAX); + resolve_link(DRCTOP, &link3); + + emit_test_r32_imm(DRCTOP, REG_EAX, 0x2); /* is it a decrementer exception */ + emit_jcc_short_link(DRCTOP, COND_Z, &link4); + emit_mov_m32_r32(DRCTOP, MABS(&SRR0), REG_EDI); /* save return address */ + emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(&ppc.generate_decrementer_exception)); + emit_jmp_r32(DRCTOP, REG_EAX); + resolve_link(DRCTOP, &link4); + + resolve_link(DRCTOP, &link1); + resolve_link(DRCTOP, &link2); + } + else + { + emit_link link1, link2, link3, link4, link5, link6; + emit_test_m32_imm(DRCTOP, MABS(&ppc.msr), MSR_EE); /* no interrupt if external interrupts are not enabled */ + emit_jcc_short_link(DRCTOP, COND_Z, &link1); /* ZF = 1 if bit == 0 */ + + /* else check if any interrupt are pending */ + emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(&ppc.exception_pending)); + emit_cmp_r32_imm(DRCTOP, REG_EAX, 0); + emit_jcc_short_link(DRCTOP, COND_Z, &link2); /* reg == 0, no exceptions are pending */ + + /* else handle the first pending exception */ + emit_test_r32_imm(DRCTOP, REG_EAX, 0x1); /* is it a IRQ? */ + emit_jcc_short_link(DRCTOP, COND_Z, &link3); + + emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(&ppc.exisr)); + emit_and_r32_m32(DRCTOP, REG_EAX, MABS(&ppc.exier)); + emit_cmp_r32_imm(DRCTOP, REG_EAX, 0); + emit_jcc_short_link(DRCTOP, COND_Z, &link4); + + emit_mov_m32_r32(DRCTOP, MABS(&SRR0), REG_EDI); /* save return address */ + emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(&ppc.generate_interrupt_exception)); + emit_jmp_r32(DRCTOP, REG_EAX); + + /* check if it's FIT exception */ + resolve_link(DRCTOP, &link3); + emit_test_r32_imm(DRCTOP, REG_EAX, 0x4); + emit_jcc_short_link(DRCTOP, COND_Z, &link5); + + // check if FIT interrupts are enabled + emit_test_m32_imm(DRCTOP, MABS(&ppc.fit_int_enable), 0x1); + emit_jcc_short_link(DRCTOP, COND_Z, &link6); + + // calculate the next trigger cycle for FIT + emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(&ppc_fit_trigger_cycle)); + emit_sub_r32_m32(DRCTOP, REG_EAX, MABS(&ppc.fit_bit)); + emit_mov_m32_r32(DRCTOP, MABS(&ppc_fit_trigger_cycle), REG_EAX); + + emit_mov_m32_r32(DRCTOP, MABS(&SRR0), REG_EDI); /* save return address */ + emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(&ppc.generate_fit_exception)); + emit_jmp_r32(DRCTOP, REG_EAX); + + resolve_link(DRCTOP, &link1); + resolve_link(DRCTOP, &link2); + resolve_link(DRCTOP, &link4); + resolve_link(DRCTOP, &link5); + resolve_link(DRCTOP, &link6); + } +} + +static void append_branch_or_dispatch(drc_core *drc, UINT32 newpc, int cycles) +{ + void *code = drc_get_code_at_pc(drc, newpc); + emit_mov_r32_imm(DRCTOP, REG_EDI, newpc); + + update_counters(drc); + append_check_interrupts(drc, 0); + + drc_append_standard_epilogue(drc, cycles, 0, 1); + + + if (code) + emit_jmp(DRCTOP, code); + else + drc_append_tentative_fixed_dispatcher(drc, newpc); +} + +/* +// this table translates x86 SF and ZF flags to PPC CR values +static const UINT8 condition_table[4] = +{ + 0x4, // x86 SF == 0, ZF == 0 --> PPC GT (positive) + 0x2, // x86 SF == 0, ZF == 1 --> PPC EQ (zero) + 0x8, // x86 SF == 1, ZF == 0 --> PPC LT (negative) + 0x0, // x86 SF == 1, ZF == 1 (impossible) +}; +*/ + +// expects the result value in EDX!!! +static void append_set_cr0(drc_core *drc) +{ + emit_xor_r32_r32(DRCTOP, REG_EBX, REG_EBX); + emit_xor_r32_r32(DRCTOP, REG_EAX, REG_EAX); + emit_cmp_r32_imm(DRCTOP, REG_EDX, 0); +/* + _lahf(); + + _shr_r32_imm(REG_EAX, 14); + + _add_r32_imm(REG_EAX, &condition_table); + _mov_r8_m8bd(REG_BL, REG_EAX, 0); +*/ + emit_setcc_r8(DRCTOP, COND_Z, REG_AL); + emit_setcc_r8(DRCTOP, COND_L, REG_AH); + emit_setcc_r8(DRCTOP, COND_G, REG_BL); + emit_shl_r8_imm(DRCTOP, REG_AL, 1); + emit_shl_r8_imm(DRCTOP, REG_AH, 3); + emit_shl_r8_imm(DRCTOP, REG_BL, 2); + emit_or_r8_r8(DRCTOP, REG_BL, REG_AH); + emit_or_r8_r8(DRCTOP, REG_BL, REG_AL); + + emit_bt_m32_imm(DRCTOP, MABS(&XER), 31); // set XER SO bit to carry + emit_adc_r32_imm(DRCTOP, REG_EBX, 0); // effectively sets bit 0 to carry + + emit_mov_m8_r8(DRCTOP, MABS(&ppc.cr[0]), REG_BL); +} + +#ifdef UNUSED_FUNCTION +static void append_set_cr1(drc_core *drc) +{ + emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(&ppc.fpscr)); + emit_shr_r32_imm(DRCTOP, REG_EAX, 28); + emit_and_r32_imm(DRCTOP, REG_EAX, 0xf); + emit_mov_m8_r8(DRCTOP, MABS(&ppc.cr[1]), REG_AL); +} +#endif + +static UINT32 recompile_addx(drc_core *drc, UINT32 op) +{ + emit_mov_r32_m32(DRCTOP, REG_EDX, MABS(®(RA))); + emit_add_r32_m32(DRCTOP, REG_EDX, MABS(®(RB))); + emit_mov_m32_r32(DRCTOP, MABS(®(RT)), REG_EDX); + + if (OEBIT) { + osd_printf_debug("recompile_addx: OE bit set !\n"); + return RECOMPILE_UNIMPLEMENTED; + } + if (RCBIT) { + append_set_cr0(drc); + } + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_addcx(drc_core *drc, UINT32 op) +{ + emit_xor_r32_r32(DRCTOP, REG_EAX, REG_EAX); + emit_mov_r32_m32(DRCTOP, REG_EBX, MABS(&XER)); + emit_and_r32_imm(DRCTOP, REG_EBX, ~0x20000000); // clear carry + emit_mov_r32_m32(DRCTOP, REG_EDX, MABS(®(RA))); + emit_add_r32_m32(DRCTOP, REG_EDX, MABS(®(RB))); + emit_mov_m32_r32(DRCTOP, MABS(®(RT)), REG_EDX); + + emit_setcc_r8(DRCTOP, COND_C, REG_AL); // carry to AL + emit_shl_r32_imm(DRCTOP, REG_EAX, 29); // shift to carry bit + emit_or_r32_r32(DRCTOP, REG_EBX, REG_EAX); + emit_mov_m32_r32(DRCTOP, MABS(&XER), REG_EBX); + + if (OEBIT) { + osd_printf_debug("recompile_addcx: OE bit set !\n"); + return RECOMPILE_UNIMPLEMENTED; + } + if (RCBIT) { + append_set_cr0(drc); + } + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_addex(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_push_imm(DRCTOP, op); + emit_call(DRCTOP, (x86code *)ppc_addex); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_addi(drc_core *drc, UINT32 op) +{ + if (RA == 0) + { + emit_mov_m32_imm(DRCTOP, MABS(®(RT)), SIMM16); + } + else + { + emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(®(RA))); + emit_add_r32_imm(DRCTOP, REG_EAX, SIMM16); + emit_mov_m32_r32(DRCTOP, MABS(®(RT)), REG_EAX); + } + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_addic(drc_core *drc, UINT32 op) +{ + emit_xor_r32_r32(DRCTOP, REG_EAX, REG_EAX); + emit_mov_r32_m32(DRCTOP, REG_EBX, MABS(&XER)); + emit_and_r32_imm(DRCTOP, REG_EBX, ~0x20000000); // clear carry bit + emit_mov_r32_m32(DRCTOP, REG_EDX, MABS(®(RA))); + emit_add_r32_imm(DRCTOP, REG_EDX, SIMM16); + emit_mov_m32_r32(DRCTOP, MABS(®(RT)), REG_EDX); + + emit_setcc_r8(DRCTOP, COND_C, REG_AL); // carry to AL + emit_shl_r32_imm(DRCTOP, REG_EAX, 29); // shift to carry bit + emit_or_r32_r32(DRCTOP, REG_EBX, REG_EAX); + emit_mov_m32_r32(DRCTOP, MABS(&XER), REG_EBX); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_addic_rc(drc_core *drc, UINT32 op) +{ + emit_xor_r32_r32(DRCTOP, REG_EAX, REG_EAX); + emit_mov_r32_m32(DRCTOP, REG_EBX, MABS(&XER)); + emit_and_r32_imm(DRCTOP, REG_EBX, ~0x20000000); // clear carry bit + emit_mov_r32_m32(DRCTOP, REG_EDX, MABS(®(RA))); + emit_add_r32_imm(DRCTOP, REG_EDX, SIMM16); + emit_mov_m32_r32(DRCTOP, MABS(®(RT)), REG_EDX); + + emit_setcc_r8(DRCTOP, COND_C, REG_AL); // carry to AL + emit_shl_r32_imm(DRCTOP, REG_EAX, 29); // shift to carry bit + emit_or_r32_r32(DRCTOP, REG_EBX, REG_EAX); + emit_mov_m32_r32(DRCTOP, MABS(&XER), REG_EBX); + + append_set_cr0(drc); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_addis(drc_core *drc, UINT32 op) +{ + if (RA == 0) + { + emit_mov_m32_imm(DRCTOP, MABS(®(RT)), UIMM16 << 16); + } + else + { + emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(®(RA))); + emit_add_r32_imm(DRCTOP, REG_EAX, UIMM16 << 16); + emit_mov_m32_r32(DRCTOP, MABS(®(RT)), REG_EAX); + } + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_addmex(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_push_imm(DRCTOP, op); + emit_call(DRCTOP, (x86code *)ppc_addmex); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_addzex(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_push_imm(DRCTOP, op); + emit_call(DRCTOP, (x86code *)ppc_addzex); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_andx(drc_core *drc, UINT32 op) +{ + emit_mov_r32_m32(DRCTOP, REG_EDX, MABS(®(RS))); + emit_and_r32_m32(DRCTOP, REG_EDX, MABS(®(RB))); + emit_mov_m32_r32(DRCTOP, MABS(®(RA)), REG_EDX); + + if (RCBIT) { + append_set_cr0(drc); + } + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_andcx(drc_core *drc, UINT32 op) +{ + emit_mov_r32_m32(DRCTOP, REG_EDX, MABS(®(RS))); + emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(®(RB))); + emit_not_r32(DRCTOP, REG_EAX); + emit_and_r32_r32(DRCTOP, REG_EDX, REG_EAX); + emit_mov_m32_r32(DRCTOP, MABS(®(RA)), REG_EDX); + + if (RCBIT) { + append_set_cr0(drc); + } + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_andi_rc(drc_core *drc, UINT32 op) +{ + emit_mov_r32_m32(DRCTOP, REG_EDX, MABS(®(RS))); + emit_and_r32_imm(DRCTOP, REG_EDX, UIMM16); + emit_mov_m32_r32(DRCTOP, MABS(®(RA)), REG_EDX); + + append_set_cr0(drc); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_andis_rc(drc_core *drc, UINT32 op) +{ + emit_mov_r32_m32(DRCTOP, REG_EDX, MABS(®(RS))); + emit_and_r32_imm(DRCTOP, REG_EDX, UIMM16 << 16); + emit_mov_m32_r32(DRCTOP, MABS(®(RA)), REG_EDX); + + append_set_cr0(drc); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_bx(drc_core *drc, UINT32 op) +{ + UINT32 newpc; + INT32 li = op & 0x3fffffc; + if( li & 0x2000000 ) + li |= 0xfc000000; + + if( AABIT ) { + newpc = li; + } else { + newpc = temp_ppc_pc + li; + } + + if( LKBIT ) { + emit_mov_m32_imm(DRCTOP, MABS(&LR), temp_ppc_pc + 4); + } + + append_branch_or_dispatch(drc, newpc, 1); + + return RECOMPILE_SUCCESSFUL_CP(0,0) | RECOMPILE_END_OF_STRING; +} + +static UINT32 recompile_bcx(drc_core *drc, UINT32 op) +{ + emit_link link1 = {0}, link2 = {0}; + int do_link1 = 0, do_link2 = 0; + UINT32 newpc; + + if( AABIT ) { + newpc = SIMM16 & ~0x3; + } else { + newpc = temp_ppc_pc + (SIMM16 & ~0x3); + } + + if( LKBIT ) { + emit_mov_m32_imm(DRCTOP, MABS(&LR), temp_ppc_pc + 4); + } + + if (BO == 20) /* condition is always true, so the basic block ends here */ + { + append_branch_or_dispatch(drc, newpc, 1); + + return RECOMPILE_SUCCESSFUL_CP(0,0) | RECOMPILE_END_OF_STRING; + } + else + { + // if BO[2] == 0, update CTR and check CTR condition + if ((BO & 0x4) == 0) + { + do_link1 = 1; + //_dec_m32abs(&CTR); + emit_sub_m32_imm(DRCTOP, MABS(&CTR), 1); + + // if BO[1] == 0, branch if CTR != 0 + if ((BO & 0x2) == 0) + { + emit_jcc_near_link(DRCTOP, COND_Z, &link1); + } + else + { + emit_jcc_near_link(DRCTOP, COND_NZ, &link1); + } + } + + // if BO[0] == 0, check condition + if ((BO & 0x10) == 0) + { + do_link2 = 1; + emit_movzx_r32_m8(DRCTOP, REG_EAX, MABS(&ppc.cr[(BI)/4])); + emit_test_r32_imm(DRCTOP, REG_EAX, 1 << (3 - ((BI) & 0x3))); // test if condition register bit is set + + // if BO[3] == 0, branch if condition == FALSE (bit zero) + if ((BO & 0x8) == 0) + { + emit_jcc_near_link(DRCTOP, COND_NZ, &link2); // bit not zero, skip branch + } + // if BO[3] == 1, branch if condition == TRUE (bit not zero) + else + { + emit_jcc_near_link(DRCTOP, COND_Z, &link2); // bit zero, skip branch + } + } + + // take the branch + append_branch_or_dispatch(drc, newpc, 1); + + // skip the branch + if (do_link1) { + resolve_link(DRCTOP, &link1); + } + if (do_link2) { + resolve_link(DRCTOP, &link2); + } + + return RECOMPILE_SUCCESSFUL_CP(1,4); + } +} + +static UINT32 recompile_bcctrx(drc_core *drc, UINT32 op) +{ + emit_link link1 = {0} ,link2 = {0}; + int do_link1 = 0, do_link2 = 0; + + if (BO == 20) /* condition is always true, so the basic block ends here */ + { + emit_mov_r32_m32(DRCTOP, REG_EDI, MABS(&CTR)); // mov edi, CTR + + if( LKBIT ) { + emit_mov_m32_imm(DRCTOP, MABS(&LR), temp_ppc_pc + 4); + } + return RECOMPILE_SUCCESSFUL_CP(1,0) | RECOMPILE_END_OF_STRING | RECOMPILE_ADD_DISPATCH; + } + else + { + // if BO[2] == 0, update CTR and check CTR condition + if ((BO & 0x4) == 0) + { + do_link1 = 1; + //_dec_m32abs(&CTR); + emit_sub_m32_imm(DRCTOP, MABS(&CTR), 1); + + // if BO[1] == 0, branch if CTR != 0 + if ((BO & 0x2) == 0) + { + emit_jcc_near_link(DRCTOP, COND_Z, &link1); + } + else + { + emit_jcc_near_link(DRCTOP, COND_NZ, &link1); + } + } + + // if BO[0] == 0, check condition + if ((BO & 0x10) == 0) + { + do_link2 = 1; + emit_movzx_r32_m8(DRCTOP, REG_EAX, MABS(&ppc.cr[(BI)/4])); + emit_test_r32_imm(DRCTOP, REG_EAX, 1 << (3 - ((BI) & 0x3))); // test if condition register bit is set + + // if BO[3] == 0, branch if condition == FALSE (bit zero) + if ((BO & 0x8) == 0) + { + emit_jcc_near_link(DRCTOP, COND_NZ, &link2); // bit not zero, skip branch + } + // if BO[3] == 1, branch if condition == TRUE (bit not zero) + else + { + emit_jcc_near_link(DRCTOP, COND_Z, &link2); // bit zero, skip branch + } + } + + // take the branch + emit_mov_r32_m32(DRCTOP, REG_EDI, MABS(&CTR)); // mov edi, CTR + if( LKBIT ) { + emit_mov_m32_imm(DRCTOP, MABS(&LR), temp_ppc_pc + 4); + } + append_check_interrupts(drc, 0); + drc_append_standard_epilogue(drc, 1, 0, 1); + drc_append_dispatcher(drc); + + // skip the branch + if (do_link1) { + resolve_link(DRCTOP, &link1); + } + if (do_link2) { + resolve_link(DRCTOP, &link2); + } + if( LKBIT ) { + emit_mov_m32_imm(DRCTOP, MABS(&LR), temp_ppc_pc + 4); + } + + return RECOMPILE_SUCCESSFUL_CP(1,4); + } +} + +static UINT32 recompile_bclrx(drc_core *drc, UINT32 op) +{ + emit_link link1 = {0}, link2 = {0}; + int do_link1 = 0, do_link2 = 0; + + if (BO == 20) /* condition is always true, so the basic block ends here */ + { + emit_mov_r32_m32(DRCTOP, REG_EDI, MABS(&LR)); // mov edi, LR + + if( LKBIT ) { + emit_mov_m32_imm(DRCTOP, MABS(&LR), temp_ppc_pc + 4); + } + return RECOMPILE_SUCCESSFUL_CP(1,0) | RECOMPILE_END_OF_STRING | RECOMPILE_ADD_DISPATCH; + } + else + { + // if BO[2] == 0, update CTR and check CTR condition + if ((BO & 0x4) == 0) + { + do_link1 = 1; + //_dec_m32abs(&CTR); + emit_sub_m32_imm(DRCTOP, MABS(&CTR), 1); + + // if BO[1] == 0, branch if CTR != 0 + if ((BO & 0x2) == 0) + { + emit_jcc_near_link(DRCTOP, COND_Z, &link1); + } + else + { + emit_jcc_near_link(DRCTOP, COND_NZ, &link1); + } + } + + // if BO[0] == 0, check condition + if ((BO & 0x10) == 0) + { + do_link2 = 1; + emit_movzx_r32_m8(DRCTOP, REG_EAX, MABS(&ppc.cr[(BI)/4])); + emit_test_r32_imm(DRCTOP, REG_EAX, 1 << (3 - ((BI) & 0x3))); // test if condition register bit is set + + // if BO[3] == 0, branch if condition == FALSE (bit zero) + if ((BO & 0x8) == 0) + { + emit_jcc_near_link(DRCTOP, COND_NZ, &link2); // bit not zero, skip branch + } + // if BO[3] == 1, branch if condition == TRUE (bit not zero) + else + { + emit_jcc_near_link(DRCTOP, COND_Z, &link2); // bit zero, skip branch + } + } + + // take the branch + emit_mov_r32_m32(DRCTOP, REG_EDI, MABS(&LR)); // mov edi, LR + if( LKBIT ) { + emit_mov_m32_imm(DRCTOP, MABS(&LR), temp_ppc_pc + 4); + } + append_check_interrupts(drc, 0); + drc_append_standard_epilogue(drc, 1, 0, 1); + drc_append_dispatcher(drc); + + // skip the branch + if (do_link1) { + resolve_link(DRCTOP, &link1); + } + if (do_link2) { + resolve_link(DRCTOP, &link2); + } + if( LKBIT ) { + emit_mov_m32_imm(DRCTOP, MABS(&LR), temp_ppc_pc + 4); + } + + return RECOMPILE_SUCCESSFUL_CP(1,4); + } +} + +static UINT32 recompile_cmp(drc_core *drc, UINT32 op) +{ + emit_xor_r32_r32(DRCTOP, REG_EAX, REG_EAX); + emit_xor_r32_r32(DRCTOP, REG_EBX, REG_EBX); + emit_mov_r32_m32(DRCTOP, REG_ECX, MABS(®(RA))); + emit_cmp_r32_m32(DRCTOP, REG_ECX, MABS(®(RB))); + + emit_setcc_r8(DRCTOP, COND_Z, REG_AL); + emit_setcc_r8(DRCTOP, COND_L, REG_AH); + emit_setcc_r8(DRCTOP, COND_G, REG_BL); + emit_shl_r8_imm(DRCTOP, REG_AL, 1); + emit_shl_r8_imm(DRCTOP, REG_AH, 3); + emit_shl_r8_imm(DRCTOP, REG_BL, 2); + emit_or_r8_r8(DRCTOP, REG_BL, REG_AH); + emit_or_r8_r8(DRCTOP, REG_BL, REG_AL); + + emit_bt_m32_imm(DRCTOP, MABS(&XER), 31); // set XER SO bit to carry + emit_adc_r32_imm(DRCTOP, REG_EBX, 0); // effectively sets bit 0 to carry + emit_mov_m8_r8(DRCTOP, MABS(&ppc.cr[CRFD]), REG_BL); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_cmpi(drc_core *drc, UINT32 op) +{ + emit_xor_r32_r32(DRCTOP, REG_EAX, REG_EAX); + emit_xor_r32_r32(DRCTOP, REG_EBX, REG_EBX); + emit_mov_r32_m32(DRCTOP, REG_ECX, MABS(®(RA))); + emit_cmp_r32_imm(DRCTOP, REG_ECX, SIMM16); + + emit_setcc_r8(DRCTOP, COND_Z, REG_AL); + emit_setcc_r8(DRCTOP, COND_L, REG_AH); + emit_setcc_r8(DRCTOP, COND_G, REG_BL); + emit_shl_r8_imm(DRCTOP, REG_AL, 1); + emit_shl_r8_imm(DRCTOP, REG_AH, 3); + emit_shl_r8_imm(DRCTOP, REG_BL, 2); + emit_or_r8_r8(DRCTOP, REG_BL, REG_AH); + emit_or_r8_r8(DRCTOP, REG_BL, REG_AL); + + emit_bt_m32_imm(DRCTOP, MABS(&XER), 31); // set XER SO bit to carry + emit_adc_r32_imm(DRCTOP, REG_EBX, 0); // effectively sets bit 0 to carry + emit_mov_m8_r8(DRCTOP, MABS(&ppc.cr[CRFD]), REG_BL); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_cmpl(drc_core *drc, UINT32 op) +{ + emit_xor_r32_r32(DRCTOP, REG_EAX, REG_EAX); + emit_xor_r32_r32(DRCTOP, REG_EBX, REG_EBX); + emit_mov_r32_m32(DRCTOP, REG_ECX, MABS(®(RA))); + emit_cmp_r32_m32(DRCTOP, REG_ECX, MABS(®(RB))); + + emit_setcc_r8(DRCTOP, COND_Z, REG_AL); + emit_setcc_r8(DRCTOP, COND_B, REG_AH); + emit_setcc_r8(DRCTOP, COND_A, REG_BL); + emit_shl_r8_imm(DRCTOP, REG_AL, 1); + emit_shl_r8_imm(DRCTOP, REG_AH, 3); + emit_shl_r8_imm(DRCTOP, REG_BL, 2); + emit_or_r8_r8(DRCTOP, REG_BL, REG_AH); + emit_or_r8_r8(DRCTOP, REG_BL, REG_AL); + + emit_bt_m32_imm(DRCTOP, MABS(&XER), 31); // set XER SO bit to carry + emit_adc_r32_imm(DRCTOP, REG_EBX, 0); // effectively sets bit 0 to carry + emit_mov_m8_r8(DRCTOP, MABS(&ppc.cr[CRFD]), REG_BL); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_cmpli(drc_core *drc, UINT32 op) +{ + emit_xor_r32_r32(DRCTOP, REG_EAX, REG_EAX); + emit_xor_r32_r32(DRCTOP, REG_EBX, REG_EBX); + emit_mov_r32_m32(DRCTOP, REG_ECX, MABS(®(RA))); + emit_cmp_r32_imm(DRCTOP, REG_ECX, UIMM16); + + emit_setcc_r8(DRCTOP, COND_Z, REG_AL); + emit_setcc_r8(DRCTOP, COND_B, REG_AH); + emit_setcc_r8(DRCTOP, COND_A, REG_BL); + emit_shl_r8_imm(DRCTOP, REG_AL, 1); + emit_shl_r8_imm(DRCTOP, REG_AH, 3); + emit_shl_r8_imm(DRCTOP, REG_BL, 2); + emit_or_r8_r8(DRCTOP, REG_BL, REG_AH); + emit_or_r8_r8(DRCTOP, REG_BL, REG_AL); + + emit_bt_m32_imm(DRCTOP, MABS(&XER), 31); // set XER SO bit to carry + emit_adc_r32_imm(DRCTOP, REG_EBX, 0); // effectively sets bit 0 to carry + emit_mov_m8_r8(DRCTOP, MABS(&ppc.cr[CRFD]), REG_BL); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_cntlzw(drc_core *drc, UINT32 op) +{ + emit_xor_r32_r32(DRCTOP, REG_EBX, REG_EBX); + emit_mov_r32_imm(DRCTOP, REG_EDX, 31); + emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(®(RT))); + emit_bsr_r32_r32(DRCTOP, REG_EAX, REG_EAX); + emit_setcc_r8(DRCTOP, COND_Z, REG_BL); // if all zeros, set BL to 1, so result becomes 32 + emit_sub_r32_r32(DRCTOP, REG_EDX, REG_EAX); + emit_add_r32_r32(DRCTOP, REG_EDX, REG_EBX); + emit_mov_m32_r32(DRCTOP, MABS(®(RA)), REG_EDX); + + if (RCBIT) { + append_set_cr0(drc); + } + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_crand(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_push_imm(DRCTOP, op); + emit_call(DRCTOP, (x86code *)ppc_crand); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_crandc(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_push_imm(DRCTOP, op); + emit_call(DRCTOP, (x86code *)ppc_crandc); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_creqv(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_push_imm(DRCTOP, op); + emit_call(DRCTOP, (x86code *)ppc_creqv); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_crnand(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_push_imm(DRCTOP, op); + emit_call(DRCTOP, (x86code *)ppc_crnand); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_crnor(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_push_imm(DRCTOP, op); + emit_call(DRCTOP, (x86code *)ppc_crnor); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_cror(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_push_imm(DRCTOP, op); + emit_call(DRCTOP, (x86code *)ppc_cror); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_crorc(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_push_imm(DRCTOP, op); + emit_call(DRCTOP, (x86code *)ppc_crorc); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_crxor(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_push_imm(DRCTOP, op); + emit_call(DRCTOP, (x86code *)ppc_crxor); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_dcbf(drc_core *drc, UINT32 op) +{ + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_dcbi(drc_core *drc, UINT32 op) +{ + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_dcbst(drc_core *drc, UINT32 op) +{ + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_dcbt(drc_core *drc, UINT32 op) +{ + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_dcbtst(drc_core *drc, UINT32 op) +{ + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_dcbz(drc_core *drc, UINT32 op) +{ + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_divwx(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_push_imm(DRCTOP, op); + emit_call(DRCTOP, (x86code *)ppc_divwx); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_divwux(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_push_imm(DRCTOP, op); + emit_call(DRCTOP, (x86code *)ppc_divwux); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_eieio(drc_core *drc, UINT32 op) +{ + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_eqvx(drc_core *drc, UINT32 op) +{ + emit_mov_r32_m32(DRCTOP, REG_EDX, MABS(®(RS))); + emit_xor_r32_m32(DRCTOP, REG_EDX, MABS(®(RB))); + emit_not_r32(DRCTOP, REG_EDX); + emit_mov_m32_r32(DRCTOP, MABS(®(RA)), REG_EDX); + + if (RCBIT) { + append_set_cr0(drc); + } + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_extsbx(drc_core *drc, UINT32 op) +{ + emit_mov_r32_m32(DRCTOP, REG_EDX, MABS(®(RS))); + emit_movsx_r32_r8(DRCTOP, REG_EDX, REG_DL); + emit_mov_m32_r32(DRCTOP, MABS(®(RA)), REG_EDX); + + if (RCBIT) { + append_set_cr0(drc); + } + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_extshx(drc_core *drc, UINT32 op) +{ + emit_mov_r32_m32(DRCTOP, REG_EDX, MABS(®(RS))); + emit_movsx_r32_r16(DRCTOP, REG_EDX, REG_DX); + emit_mov_m32_r32(DRCTOP, MABS(®(RA)), REG_EDX); + + if (RCBIT) { + append_set_cr0(drc); + } + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_icbi(drc_core *drc, UINT32 op) +{ + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_isync(drc_core *drc, UINT32 op) +{ + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_lbz(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + if (RA == 0) + { + emit_push_imm(DRCTOP, SIMM16); + } + else + { + emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(®(RA))); + emit_add_r32_imm(DRCTOP, REG_EAX, SIMM16); + emit_push_r32(DRCTOP, REG_EAX); + } + emit_call(DRCTOP, (x86code *)READ8); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_movzx_r32_r8(DRCTOP, REG_EAX, REG_AL); + emit_mov_m32_r32(DRCTOP, MABS(®(RT)), REG_EAX); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_lbzu(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_mov_r32_m32(DRCTOP, REG_EDX, MABS(®(RA))); + emit_add_r32_imm(DRCTOP, REG_EDX, SIMM16); + emit_mov_m32_r32(DRCTOP, MABS(®(RA)), REG_EDX); + emit_push_r32(DRCTOP, REG_EDX); + emit_call(DRCTOP, (x86code *)READ8); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_movzx_r32_r8(DRCTOP, REG_EAX, REG_AL); + emit_mov_m32_r32(DRCTOP, MABS(®(RT)), REG_EAX); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_lbzux(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_mov_r32_m32(DRCTOP, REG_EDX, MABS(®(RA))); + emit_add_r32_m32(DRCTOP, REG_EDX, MABS(®(RB))); + emit_mov_m32_r32(DRCTOP, MABS(®(RA)), REG_EDX); + emit_push_r32(DRCTOP, REG_EDX); + emit_call(DRCTOP, (x86code *)READ8); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_movzx_r32_r8(DRCTOP, REG_EAX, REG_AL); + emit_mov_m32_r32(DRCTOP, MABS(®(RT)), REG_EAX); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_lbzx(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(®(RB))); + if (RA != 0) + { + emit_add_r32_m32(DRCTOP, REG_EAX, MABS(®(RA))); + } + emit_push_r32(DRCTOP, REG_EAX); + emit_call(DRCTOP, (x86code *)READ8); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_movzx_r32_r8(DRCTOP, REG_EAX, REG_AL); + emit_mov_m32_r32(DRCTOP, MABS(®(RT)), REG_EAX); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_lha(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + if (RA == 0) + { + emit_push_imm(DRCTOP, SIMM16); + } + else + { + emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(®(RA))); + emit_add_r32_imm(DRCTOP, REG_EAX, SIMM16); + emit_push_r32(DRCTOP, REG_EAX); + } + emit_call(DRCTOP, (x86code *)READ16); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_movsx_r32_r16(DRCTOP, REG_EAX, REG_AX); + emit_mov_m32_r32(DRCTOP, MABS(®(RT)), REG_EAX); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_lhau(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_mov_r32_m32(DRCTOP, REG_EDX, MABS(®(RA))); + emit_add_r32_imm(DRCTOP, REG_EDX, SIMM16); + emit_mov_m32_r32(DRCTOP, MABS(®(RA)), REG_EDX); + emit_push_r32(DRCTOP, REG_EDX); + emit_call(DRCTOP, (x86code *)READ16); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_movsx_r32_r16(DRCTOP, REG_EAX, REG_AX); + emit_mov_m32_r32(DRCTOP, MABS(®(RT)), REG_EAX); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_lhaux(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_mov_r32_m32(DRCTOP, REG_EDX, MABS(®(RA))); + emit_add_r32_m32(DRCTOP, REG_EDX, MABS(®(RB))); + emit_mov_m32_r32(DRCTOP, MABS(®(RA)), REG_EDX); + emit_push_r32(DRCTOP, REG_EDX); + emit_call(DRCTOP, (x86code *)READ16); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_movsx_r32_r16(DRCTOP, REG_EAX, REG_AX); + emit_mov_m32_r32(DRCTOP, MABS(®(RT)), REG_EAX); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_lhax(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(®(RB))); + if (RA != 0) + { + emit_add_r32_m32(DRCTOP, REG_EAX, MABS(®(RA))); + } + emit_push_r32(DRCTOP, REG_EAX); + emit_call(DRCTOP, (x86code *)READ16); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_movsx_r32_r16(DRCTOP, REG_EAX, REG_AX); + emit_mov_m32_r32(DRCTOP, MABS(®(RT)), REG_EAX); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_lhbrx(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(®(RB))); + if (RA != 0) + { + emit_add_r32_m32(DRCTOP, REG_EAX, MABS(®(RA))); + } + emit_push_r32(DRCTOP, REG_EAX); + emit_call(DRCTOP, (x86code *)READ16); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_mov_r32_imm(DRCTOP, REG_ECX, 8); + emit_rol_r16_cl(DRCTOP, REG_AX); + emit_mov_m32_r32(DRCTOP, MABS(®(RT)), REG_EAX); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_lhz(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + if (RA == 0) + { + emit_push_imm(DRCTOP, SIMM16); + } + else + { + emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(®(RA))); + emit_add_r32_imm(DRCTOP, REG_EAX, SIMM16); + emit_push_r32(DRCTOP, REG_EAX); + } + emit_call(DRCTOP, (x86code *)READ16); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_mov_m32_r32(DRCTOP, MABS(®(RT)), REG_EAX); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_lhzu(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_mov_r32_m32(DRCTOP, REG_EDX, MABS(®(RA))); + emit_add_r32_imm(DRCTOP, REG_EDX, SIMM16); + emit_mov_m32_r32(DRCTOP, MABS(®(RA)), REG_EDX); + emit_push_r32(DRCTOP, REG_EDX); + emit_call(DRCTOP, (x86code *)READ16); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_mov_m32_r32(DRCTOP, MABS(®(RT)), REG_EAX); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_lhzux(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_mov_r32_m32(DRCTOP, REG_EDX, MABS(®(RA))); + emit_add_r32_m32(DRCTOP, REG_EDX, MABS(®(RB))); + emit_mov_m32_r32(DRCTOP, MABS(®(RA)), REG_EDX); + emit_push_r32(DRCTOP, REG_EDX); + emit_call(DRCTOP, (x86code *)READ16); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_mov_m32_r32(DRCTOP, MABS(®(RT)), REG_EAX); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_lhzx(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(®(RB))); + if (RA != 0) + { + emit_add_r32_m32(DRCTOP, REG_EAX, MABS(®(RA))); + } + emit_push_r32(DRCTOP, REG_EAX); + emit_call(DRCTOP, (x86code *)READ16); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_mov_m32_r32(DRCTOP, MABS(®(RT)), REG_EAX); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_lmw(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_push_imm(DRCTOP, op); + emit_call(DRCTOP, (x86code *)ppc_lmw); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_lswi(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_push_imm(DRCTOP, op); + emit_call(DRCTOP, (x86code *)ppc_lswi); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_lswx(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_push_imm(DRCTOP, op); + emit_call(DRCTOP, (x86code *)ppc_lswx); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_lwarx(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_push_imm(DRCTOP, op); + emit_call(DRCTOP, (x86code *)ppc_lwarx); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_lwbrx(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(®(RB))); + if (RA != 0) + { + emit_add_r32_m32(DRCTOP, REG_EAX, MABS(®(RA))); + } + emit_push_r32(DRCTOP, REG_EAX); + emit_call(DRCTOP, (x86code *)READ32); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_bswap_r32(DRCTOP, REG_EAX); + emit_mov_m32_r32(DRCTOP, MABS(®(RT)), REG_EAX); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_lwz(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + if (RA == 0) + { + emit_push_imm(DRCTOP, SIMM16); + } + else + { + emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(®(RA))); + emit_add_r32_imm(DRCTOP, REG_EAX, SIMM16); + emit_push_r32(DRCTOP, REG_EAX); + } + emit_call(DRCTOP, (x86code *)READ32); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_mov_m32_r32(DRCTOP, MABS(®(RT)), REG_EAX); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_lwzu(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_mov_r32_m32(DRCTOP, REG_EDX, MABS(®(RA))); + emit_add_r32_imm(DRCTOP, REG_EDX, SIMM16); + emit_mov_m32_r32(DRCTOP, MABS(®(RA)), REG_EDX); + emit_push_r32(DRCTOP, REG_EDX); + emit_call(DRCTOP, (x86code *)READ32); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_mov_m32_r32(DRCTOP, MABS(®(RT)), REG_EAX); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_lwzux(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_mov_r32_m32(DRCTOP, REG_EDX, MABS(®(RA))); + emit_add_r32_m32(DRCTOP, REG_EDX, MABS(®(RB))); + emit_mov_m32_r32(DRCTOP, MABS(®(RA)), REG_EDX); + emit_push_r32(DRCTOP, REG_EDX); + emit_call(DRCTOP, (x86code *)READ32); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_mov_m32_r32(DRCTOP, MABS(®(RT)), REG_EAX); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_lwzx(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(®(RB))); + if (RA != 0) + { + emit_add_r32_m32(DRCTOP, REG_EAX, MABS(®(RA))); + } + emit_push_r32(DRCTOP, REG_EAX); + emit_call(DRCTOP, (x86code *)READ32); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_mov_m32_r32(DRCTOP, MABS(®(RT)), REG_EAX); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_mcrf(drc_core *drc, UINT32 op) +{ + emit_mov_r8_m8(DRCTOP, REG_AL, MABS(&ppc.cr[RA >> 2])); + emit_mov_m8_r8(DRCTOP, MABS(&ppc.cr[RT >> 2]), REG_AL); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_mcrxr(drc_core *drc, UINT32 op) +{ + osd_printf_debug("PPCDRC: recompile mcrxr\n"); + return RECOMPILE_UNIMPLEMENTED; +} + +static UINT32 recompile_mfcr(drc_core *drc, UINT32 op) +{ + int i; + emit_xor_r32_r32(DRCTOP, REG_EAX, REG_EAX); + + // generate code for each condition register + for (i=0; i < 8; i++) + { + emit_xor_r32_r32(DRCTOP, REG_EDX, REG_EDX); + emit_mov_r8_m8(DRCTOP, REG_DL, MABS(&ppc.cr[i])); + emit_shl_r32_imm(DRCTOP, REG_EDX, ((7-i) * 4)); + emit_or_r32_r32(DRCTOP, REG_EAX, REG_EDX); + } + emit_mov_m32_r32(DRCTOP, MABS(®(RT)), REG_EAX); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_mfmsr(drc_core *drc, UINT32 op) +{ + emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(&ppc.msr)); + emit_mov_m32_r32(DRCTOP, MABS(®(RT)), REG_EAX); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_mfspr(drc_core *drc, UINT32 op) +{ + if (SPR == SPR_LR) // optimized case, LR + { + emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(&LR)); + } + else if(SPR == SPR_CTR) // optimized case, CTR + { + emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(&CTR)); + } + else + { + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_push_imm(DRCTOP, SPR); + emit_call(DRCTOP, (x86code *)ppc_get_spr); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + } + emit_mov_m32_r32(DRCTOP, MABS(®(RT)), REG_EAX); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_mtcrf(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_push_imm(DRCTOP, op); + emit_call(DRCTOP, (x86code *)ppc_mtcrf); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_mtmsr(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(®(RS))); + emit_push_r32(DRCTOP, REG_EAX); + emit_call(DRCTOP, (x86code *)ppc_set_msr); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_mtspr(drc_core *drc, UINT32 op) +{ + emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(®(RS))); + if (SPR == SPR_LR) // optimized case, LR + { + emit_mov_m32_r32(DRCTOP, MABS(&LR), REG_EAX); + } + else if(SPR == SPR_CTR) // optimized case, CTR + { + emit_mov_m32_r32(DRCTOP, MABS(&CTR), REG_EAX); + } + else + { + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_push_r32(DRCTOP, REG_EAX); + emit_push_imm(DRCTOP, SPR); + emit_call(DRCTOP, (x86code *)ppc_set_spr); + emit_add_r32_imm(DRCTOP, REG_ESP, 8); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + } + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_mulhwx(drc_core *drc, UINT32 op) +{ + emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(®(RA))); + emit_mov_r32_m32(DRCTOP, REG_EBX, MABS(®(RB))); + emit_imul_r32(DRCTOP, REG_EBX); + emit_mov_m32_r32(DRCTOP, MABS(®(RT)), REG_EDX); + + if (RCBIT) { + append_set_cr0(drc); + } + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_mulhwux(drc_core *drc, UINT32 op) +{ + emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(®(RA))); + emit_mov_r32_m32(DRCTOP, REG_EBX, MABS(®(RB))); + emit_mul_r32(DRCTOP, REG_EBX); + emit_mov_m32_r32(DRCTOP, MABS(®(RT)), REG_EDX); + + if (RCBIT) { + append_set_cr0(drc); + } + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_mulli(drc_core *drc, UINT32 op) +{ + emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(®(RA))); + emit_mov_r32_imm(DRCTOP, REG_EBX, SIMM16); + emit_imul_r32(DRCTOP, REG_EBX); + emit_mov_m32_r32(DRCTOP, MABS(®(RT)), REG_EAX); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_mullwx(drc_core *drc, UINT32 op) +{ + emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(®(RA))); + emit_mov_r32_m32(DRCTOP, REG_EBX, MABS(®(RB))); + emit_mul_r32(DRCTOP, REG_EBX); + emit_mov_r32_r32(DRCTOP, REG_EDX, REG_EAX); + emit_mov_m32_r32(DRCTOP, MABS(®(RT)), REG_EDX); + + if (OEBIT) { + osd_printf_debug("recompile_mullwx: OEBIT set!\n"); + return RECOMPILE_UNIMPLEMENTED; + } + + if (RCBIT) { + append_set_cr0(drc); + } + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_nandx(drc_core *drc, UINT32 op) +{ + emit_mov_r32_m32(DRCTOP, REG_EDX, MABS(®(RS))); + emit_and_r32_m32(DRCTOP, REG_EDX, MABS(®(RB))); + emit_not_r32(DRCTOP, REG_EDX); + emit_mov_m32_r32(DRCTOP, MABS(®(RA)), REG_EDX); + + if (RCBIT) { + append_set_cr0(drc); + } + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_negx(drc_core *drc, UINT32 op) +{ + emit_mov_r32_m32(DRCTOP, REG_EDX, MABS(®(RA))); + emit_neg_r32(DRCTOP, REG_EDX); + emit_mov_m32_r32(DRCTOP, MABS(®(RT)), REG_EDX); + + if (RCBIT) { + append_set_cr0(drc); + } + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_norx(drc_core *drc, UINT32 op) +{ + emit_mov_r32_m32(DRCTOP, REG_EDX, MABS(®(RS))); + emit_or_r32_m32(DRCTOP, REG_EDX, MABS(®(RB))); + emit_not_r32(DRCTOP, REG_EDX); + emit_mov_m32_r32(DRCTOP, MABS(®(RA)), REG_EDX); + + if (RCBIT) { + append_set_cr0(drc); + } + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_orx(drc_core *drc, UINT32 op) +{ + emit_mov_r32_m32(DRCTOP, REG_EDX, MABS(®(RS))); + emit_or_r32_m32(DRCTOP, REG_EDX, MABS(®(RB))); + emit_mov_m32_r32(DRCTOP, MABS(®(RA)), REG_EDX); + + if (RCBIT) { + append_set_cr0(drc); + } + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_orcx(drc_core *drc, UINT32 op) +{ + emit_mov_r32_m32(DRCTOP, REG_EDX, MABS(®(RB))); + emit_not_r32(DRCTOP, REG_EDX); + emit_or_r32_m32(DRCTOP, REG_EDX, MABS(®(RS))); + emit_mov_m32_r32(DRCTOP, MABS(®(RA)), REG_EDX); + + if (RCBIT) { + append_set_cr0(drc); + } + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_ori(drc_core *drc, UINT32 op) +{ + emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(®(RS))); + emit_or_r32_imm(DRCTOP, REG_EAX, UIMM16); + emit_mov_m32_r32(DRCTOP, MABS(®(RA)), REG_EAX); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_oris(drc_core *drc, UINT32 op) +{ + emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(®(RS))); + emit_or_r32_imm(DRCTOP, REG_EAX, UIMM16 << 16); + emit_mov_m32_r32(DRCTOP, MABS(®(RA)), REG_EAX); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_rfi(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_mov_r32_m32(DRCTOP, REG_EDI, MABS(&ppc.srr0)); /* get saved PC from SRR0 */ + emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(&ppc.srr1)); /* get saved MSR from SRR1 */ + + emit_push_r32(DRCTOP, REG_EAX); + emit_call(DRCTOP, (x86code *)ppc_set_msr); /* set MSR */ + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + + return RECOMPILE_SUCCESSFUL_CP(1,0) | RECOMPILE_END_OF_STRING | RECOMPILE_ADD_DISPATCH; +} + +static UINT32 recompile_rlwimix(drc_core *drc, UINT32 op) +{ + UINT32 mask = GET_ROTATE_MASK(MB, ME); + + emit_mov_r32_m32(DRCTOP, REG_EDX, MABS(®(RS))); + emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(®(RA))); + emit_rol_r32_imm(DRCTOP, REG_EDX, (SH)); + emit_and_r32_imm(DRCTOP, REG_EDX, mask); + emit_and_r32_imm(DRCTOP, REG_EAX, ~mask); + emit_or_r32_r32(DRCTOP, REG_EDX, REG_EAX); + emit_mov_m32_r32(DRCTOP, MABS(®(RA)), REG_EDX); + + if (RCBIT) { + append_set_cr0(drc); + } + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_rlwinmx(drc_core *drc, UINT32 op) +{ + UINT32 mask = GET_ROTATE_MASK(MB, ME); + + emit_mov_r32_m32(DRCTOP, REG_EDX, MABS(®(RS))); + emit_rol_r32_imm(DRCTOP, REG_EDX, (SH)); + emit_and_r32_imm(DRCTOP, REG_EDX, mask); + emit_mov_m32_r32(DRCTOP, MABS(®(RA)), REG_EDX); + + if (RCBIT) { + append_set_cr0(drc); + } + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_rlwnmx(drc_core *drc, UINT32 op) +{ + UINT32 mask = GET_ROTATE_MASK(MB, ME); + + emit_mov_r32_m32(DRCTOP, REG_ECX, MABS(®(RB))); // x86 rotate instruction use only 5 bits, so no need to mask this + emit_mov_r32_m32(DRCTOP, REG_EDX, MABS(®(RS))); + emit_rol_r32_cl(DRCTOP, REG_EDX); + emit_and_r32_imm(DRCTOP, REG_EDX, mask); + emit_mov_m32_r32(DRCTOP, MABS(®(RA)), REG_EDX); + + if (RCBIT) { + append_set_cr0(drc); + } + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_sc(drc_core *drc, UINT32 op) +{ + emit_mov_m32_imm(DRCTOP, MABS(&SRR0), temp_ppc_pc + 4); + emit_jmp(DRCTOP, ppc.generate_syscall_exception); + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_slwx(drc_core *drc, UINT32 op) +{ +#if USE_SSE2 + emit_mov_r32_m32(DRCTOP, REG_ECX, MABS(®(RB))); + emit_and_r32_imm(DRCTOP, REG_ECX, 0x3f); + emit_movd_r128_m32(DRCTOP, REG_XMM0, MABS(®(RS))); + emit_movd_r128_r32(DRCTOP, REG_XMM1, REG_ECX); + emit_psllq_r128_r128(DRCTOP, REG_XMM0, REG_XMM1); + emit_movd_r32_r128(DRCTOP, REG_EDX, REG_XMM0); + emit_mov_m32_r32(DRCTOP, MABS(®(RA)), REG_EDX); + + if (RCBIT) { + append_set_cr0(drc); + } +#else + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_push_imm(DRCTOP, op); + emit_call(DRCTOP, (x86code *)ppc_slwx); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); +#endif + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_srawx(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_push_imm(DRCTOP, op); + emit_call(DRCTOP, (x86code *)ppc_srawx); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_srawix(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_push_imm(DRCTOP, op); + emit_call(DRCTOP, (x86code *)ppc_srawix); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_srwx(drc_core *drc, UINT32 op) +{ +#if USE_SSE2 + emit_mov_r32_m32(DRCTOP, REG_ECX, MABS(®(RB))); + emit_and_r32_imm(DRCTOP, REG_ECX, 0x3f); + emit_movd_r128_m32(DRCTOP, REG_XMM0, MABS(®(RS))); + emit_movd_r128_r32(DRCTOP, REG_XMM1, REG_ECX); + emit_psrlq_r128_r128(DRCTOP, REG_XMM0, REG_XMM1); + emit_movd_r32_r128(DRCTOP, REG_EDX, REG_XMM0); + emit_mov_m32_r32(DRCTOP, MABS(®(RA)), REG_EDX); + + if (RCBIT) { + append_set_cr0(drc); + } +#else + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_push_imm(DRCTOP, op); + emit_call(DRCTOP, (x86code *)ppc_srwx); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); +#endif + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_stb(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(®(RS))); + emit_movzx_r32_r8(DRCTOP, REG_EAX, REG_AL); + emit_push_r32(DRCTOP, REG_EAX); + + if (RA == 0) + { + emit_push_imm(DRCTOP, SIMM16); + } + else + { + emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(®(RA))); + emit_add_r32_imm(DRCTOP, REG_EAX, SIMM16); + emit_push_r32(DRCTOP, REG_EAX); + } + emit_call(DRCTOP, (x86code *)WRITE8); + emit_add_r32_imm(DRCTOP, REG_ESP, 8); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_stbu(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(®(RS))); + emit_movzx_r32_r8(DRCTOP, REG_EAX, REG_AL); + emit_push_r32(DRCTOP, REG_EAX); + + emit_mov_r32_m32(DRCTOP, REG_EDX, MABS(®(RA))); + emit_add_r32_imm(DRCTOP, REG_EDX, SIMM16); + emit_mov_m32_r32(DRCTOP, MABS(®(RA)), REG_EDX); + emit_push_r32(DRCTOP, REG_EDX); + emit_call(DRCTOP, (x86code *)WRITE8); + emit_add_r32_imm(DRCTOP, REG_ESP, 8); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_stbux(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(®(RS))); + emit_movzx_r32_r8(DRCTOP, REG_EAX, REG_AL); + emit_push_r32(DRCTOP, REG_EAX); + + emit_mov_r32_m32(DRCTOP, REG_EDX, MABS(®(RA))); + emit_add_r32_m32(DRCTOP, REG_EDX, MABS(®(RB))); + emit_mov_m32_r32(DRCTOP, MABS(®(RA)), REG_EDX); + emit_push_r32(DRCTOP, REG_EDX); + emit_call(DRCTOP, (x86code *)WRITE8); + emit_add_r32_imm(DRCTOP, REG_ESP, 8); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_stbx(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(®(RS))); + emit_movzx_r32_r8(DRCTOP, REG_EAX, REG_AL); + emit_push_r32(DRCTOP, REG_EAX); + + emit_mov_r32_m32(DRCTOP, REG_EDX, MABS(®(RB))); + if (RA != 0) + { + emit_add_r32_m32(DRCTOP, REG_EDX, MABS(®(RA))); + } + emit_push_r32(DRCTOP, REG_EDX); + emit_call(DRCTOP, (x86code *)WRITE8); + emit_add_r32_imm(DRCTOP, REG_ESP, 8); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_sth(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(®(RS))); + emit_movzx_r32_r16(DRCTOP, REG_EAX, REG_AX); + emit_push_r32(DRCTOP, REG_EAX); + + if (RA == 0) + { + emit_push_imm(DRCTOP, SIMM16); + } + else + { + emit_mov_r32_m32(DRCTOP, REG_EDX, MABS(®(RA))); + emit_add_r32_imm(DRCTOP, REG_EDX, SIMM16); + emit_push_r32(DRCTOP, REG_EDX); + } + emit_call(DRCTOP, (x86code *)WRITE16); + emit_add_r32_imm(DRCTOP, REG_ESP, 8); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_sthbrx(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(®(RS))); + emit_movzx_r32_r16(DRCTOP, REG_EAX, REG_AX); + emit_mov_r32_imm(DRCTOP, REG_ECX, 8); + emit_rol_r16_cl(DRCTOP, REG_AX); + emit_push_r32(DRCTOP, REG_EAX); + + emit_mov_r32_m32(DRCTOP, REG_EDX, MABS(®(RB))); + if (RA != 0) + { + emit_add_r32_m32(DRCTOP, REG_EDX, MABS(®(RA))); + } + emit_push_r32(DRCTOP, REG_EDX); + emit_call(DRCTOP, (x86code *)WRITE16); + emit_add_r32_imm(DRCTOP, REG_ESP, 8); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_sthu(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(®(RS))); + emit_movzx_r32_r16(DRCTOP, REG_EAX, REG_AX); + emit_push_r32(DRCTOP, REG_EAX); + + emit_mov_r32_m32(DRCTOP, REG_EDX, MABS(®(RA))); + emit_add_r32_imm(DRCTOP, REG_EDX, SIMM16); + emit_mov_m32_r32(DRCTOP, MABS(®(RA)), REG_EDX); + emit_push_r32(DRCTOP, REG_EDX); + emit_call(DRCTOP, (x86code *)WRITE16); + emit_add_r32_imm(DRCTOP, REG_ESP, 8); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_sthux(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(®(RS))); + emit_movzx_r32_r16(DRCTOP, REG_EAX, REG_AX); + emit_push_r32(DRCTOP, REG_EAX); + + emit_mov_r32_m32(DRCTOP, REG_EDX, MABS(®(RA))); + emit_add_r32_m32(DRCTOP, REG_EDX, MABS(®(RB))); + emit_mov_m32_r32(DRCTOP, MABS(®(RA)), REG_EDX); + emit_push_r32(DRCTOP, REG_EDX); + emit_call(DRCTOP, (x86code *)WRITE16); + emit_add_r32_imm(DRCTOP, REG_ESP, 8); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_sthx(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(®(RS))); + emit_movzx_r32_r16(DRCTOP, REG_EAX, REG_AX); + emit_push_r32(DRCTOP, REG_EAX); + + emit_mov_r32_m32(DRCTOP, REG_EDX, MABS(®(RB))); + if (RA != 0) + { + emit_add_r32_m32(DRCTOP, REG_EDX, MABS(®(RA))); + } + emit_push_r32(DRCTOP, REG_EDX); + emit_call(DRCTOP, (x86code *)WRITE16); + emit_add_r32_imm(DRCTOP, REG_ESP, 8); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_stmw(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_push_imm(DRCTOP, op); + emit_call(DRCTOP, (x86code *)ppc_stmw); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_stswi(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_push_imm(DRCTOP, op); + emit_call(DRCTOP, (x86code *)ppc_stswi); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_stswx(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_push_imm(DRCTOP, op); + emit_call(DRCTOP, (x86code *)ppc_stswx); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_stw(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_push_m32(DRCTOP, MABS(®(RS))); + if (RA == 0) + { + emit_push_imm(DRCTOP, SIMM16); + } + else + { + emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(®(RA))); + emit_add_r32_imm(DRCTOP, REG_EAX, SIMM16); + emit_push_r32(DRCTOP, REG_EAX); + } + emit_call(DRCTOP, (x86code *)WRITE32); + emit_add_r32_imm(DRCTOP, REG_ESP, 8); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_stwbrx(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(®(RS))); + emit_bswap_r32(DRCTOP, REG_EAX); + emit_push_r32(DRCTOP, REG_EAX); + + emit_mov_r32_m32(DRCTOP, REG_EDX, MABS(®(RB))); + if (RA != 0) + { + emit_add_r32_m32(DRCTOP, REG_EDX, MABS(®(RA))); + } + emit_push_r32(DRCTOP, REG_EDX); + emit_call(DRCTOP, (x86code *)WRITE32); + emit_add_r32_imm(DRCTOP, REG_ESP, 8); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_stwcx_rc(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_push_imm(DRCTOP, op); + emit_call(DRCTOP, (x86code *)ppc_stwcx_rc); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_stwu(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_push_m32(DRCTOP, MABS(®(RS))); + + emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(®(RA))); + emit_add_r32_imm(DRCTOP, REG_EAX, SIMM16); + emit_mov_m32_r32(DRCTOP, MABS(®(RA)), REG_EAX); + emit_push_r32(DRCTOP, REG_EAX); + emit_call(DRCTOP, (x86code *)WRITE32); + emit_add_r32_imm(DRCTOP, REG_ESP, 8); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_stwux(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_push_m32(DRCTOP, MABS(®(RS))); + + emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(®(RA))); + emit_add_r32_m32(DRCTOP, REG_EAX, MABS(®(RB))); + emit_mov_m32_r32(DRCTOP, MABS(®(RA)), REG_EAX); + emit_push_r32(DRCTOP, REG_EAX); + emit_call(DRCTOP, (x86code *)WRITE32); + emit_add_r32_imm(DRCTOP, REG_ESP, 8); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_stwx(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_push_m32(DRCTOP, MABS(®(RS))); + + emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(®(RB))); + if (RA != 0) + { + emit_add_r32_m32(DRCTOP, REG_EAX, MABS(®(RA))); + } + emit_push_r32(DRCTOP, REG_EAX); + emit_call(DRCTOP, (x86code *)WRITE32); + emit_add_r32_imm(DRCTOP, REG_ESP, 8); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_subfx(drc_core *drc, UINT32 op) +{ + emit_mov_r32_m32(DRCTOP, REG_EDX, MABS(®(RB))); + emit_sub_r32_m32(DRCTOP, REG_EDX, MABS(®(RA))); + emit_mov_m32_r32(DRCTOP, MABS(®(RT)), REG_EDX); + + if (OEBIT) { + osd_printf_debug("recompile_subfx: OEBIT set !\n"); + return RECOMPILE_UNIMPLEMENTED; + } + if (RCBIT) { + append_set_cr0(drc); + } + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_subfcx(drc_core *drc, UINT32 op) +{ + if (OEBIT) + { + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_push_imm(DRCTOP, op); + emit_call(DRCTOP, (x86code *)ppc_subfcx); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + } + else + { + emit_xor_r32_r32(DRCTOP, REG_EAX, REG_EAX); + emit_mov_r32_m32(DRCTOP, REG_EBX, MABS(&XER)); + emit_and_r32_imm(DRCTOP, REG_EBX, ~0x20000000); // clear carry + emit_mov_r32_m32(DRCTOP, REG_EDX, MABS(®(RB))); + emit_sub_r32_m32(DRCTOP, REG_EDX, MABS(®(RA))); + emit_mov_m32_r32(DRCTOP, MABS(®(RT)), REG_EDX); + emit_setcc_r8(DRCTOP, COND_NC, REG_AL); // subtract carry is inverse + emit_shl_r32_imm(DRCTOP, REG_EAX, 29); // move carry to correct location in XER + emit_or_r32_r32(DRCTOP, REG_EBX, REG_EAX); // insert carry to XER + emit_mov_m32_r32(DRCTOP, MABS(&XER), REG_EBX); + + //if (OEBIT) { + // osd_printf_debug("recompile_subfcx: OEBIT set !\n"); + // return RECOMPILE_UNIMPLEMENTED; + //} + if (RCBIT) { + append_set_cr0(drc); + } + } + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_subfex(drc_core *drc, UINT32 op) +{ + emit_xor_r32_r32(DRCTOP, REG_EAX, REG_EAX); + emit_mov_r32_m32(DRCTOP, REG_EBX, MABS(&XER)); + emit_mov_r32_m32(DRCTOP, REG_EDX, MABS(®(RB))); + emit_mov_r32_m32(DRCTOP, REG_ECX, MABS(®(RA))); + emit_bt_r32_imm(DRCTOP, REG_EBX, 29); // XER carry to carry flag + emit_cmc(DRCTOP); // invert carry + emit_adc_r32_imm(DRCTOP, REG_ECX, 0); + emit_sub_r32_r32(DRCTOP, REG_EDX, REG_ECX); + emit_mov_m32_r32(DRCTOP, MABS(®(RT)), REG_EDX); + emit_setcc_r8(DRCTOP, COND_NC, REG_AL); // subtract carry is inverse + emit_and_r32_imm(DRCTOP, REG_EBX, ~0x20000000); // clear carry + emit_shl_r32_imm(DRCTOP, REG_EAX, 29); // move carry to correct location in XER + emit_or_r32_r32(DRCTOP, REG_EBX, REG_EAX); // insert carry to XER + emit_mov_m32_r32(DRCTOP, MABS(&XER), REG_EBX); + + if (OEBIT) { + osd_printf_debug("recompile_subfex: OEBIT set !\n"); + return RECOMPILE_UNIMPLEMENTED; + } + if (RCBIT) { + append_set_cr0(drc); + } + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_subfic(drc_core *drc, UINT32 op) +{ + emit_xor_r32_r32(DRCTOP, REG_EAX, REG_EAX); + emit_mov_r32_m32(DRCTOP, REG_EBX, MABS(&XER)); + emit_and_r32_imm(DRCTOP, REG_EBX, ~0x20000000); // clear carry + emit_mov_r32_imm(DRCTOP, REG_EDX, SIMM16); + emit_sub_r32_m32(DRCTOP, REG_EDX, MABS(®(RA))); + emit_mov_m32_r32(DRCTOP, MABS(®(RT)), REG_EDX); + emit_setcc_r8(DRCTOP, COND_NC, REG_AL); // subtract carry is inverse + emit_shl_r32_imm(DRCTOP, REG_EAX, 29); // move carry to correct location in XER + emit_or_r32_r32(DRCTOP, REG_EBX, REG_EAX); // insert carry to XER + emit_mov_m32_r32(DRCTOP, MABS(&XER), REG_EBX); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_subfmex(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_push_imm(DRCTOP, op); + emit_call(DRCTOP, (x86code *)ppc_subfmex); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_subfzex(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_push_imm(DRCTOP, op); + emit_call(DRCTOP, (x86code *)ppc_subfzex); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_sync(drc_core *drc, UINT32 op) +{ + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_tw(drc_core *drc, UINT32 op) +{ + emit_link link1 = {0}, link2 = {0}, link3 = {0}, link4 = {0}, link5 = {0}, link6 = {0}; + int do_link1 = 0; + int do_link2 = 0; + int do_link3 = 0; + int do_link4 = 0; + int do_link5 = 0; + + emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(®(RA))); + emit_mov_r32_m32(DRCTOP, REG_EDX, MABS(®(RB))); + emit_cmp_r32_r32(DRCTOP, REG_EAX, REG_EDX); + + if (RT & 0x10) { + emit_jcc_near_link(DRCTOP, COND_L, &link1); // less than = signed < + do_link1 = 1; + } + if (RT & 0x08) { + emit_jcc_near_link(DRCTOP, COND_G, &link2); // greater = signed > + do_link2 = 1; + } + if (RT & 0x04) { + emit_jcc_near_link(DRCTOP, COND_E, &link3); // equal + do_link3 = 1; + } + if (RT & 0x02) { + emit_jcc_near_link(DRCTOP, COND_B, &link4); // below = unsigned < + do_link4 = 1; + } + if (RT & 0x01) { + emit_jcc_near_link(DRCTOP, COND_A, &link5); // above = unsigned > + do_link5 = 1; + } + emit_jmp_near_link(DRCTOP, &link6); + + if (do_link1) { + resolve_link(DRCTOP, &link1); + } + if (do_link2) { + resolve_link(DRCTOP, &link2); + } + if (do_link3) { + resolve_link(DRCTOP, &link3); + } + if (do_link4) { + resolve_link(DRCTOP, &link4); + } + if (do_link5) { + resolve_link(DRCTOP, &link5); + } + // generate exception + emit_mov_m32_imm(DRCTOP, MABS(&SRR0), temp_ppc_pc + 4); + emit_jmp(DRCTOP, ppc.generate_trap_exception); + + // no exception + resolve_link(DRCTOP, &link6); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_twi(drc_core *drc, UINT32 op) +{ + emit_link link1 = {0}, link2 = {0}, link3 = {0}, link4 = {0}, link5 = {0}, link6 = {0}; + int do_link1 = 0; + int do_link2 = 0; + int do_link3 = 0; + int do_link4 = 0; + int do_link5 = 0; + + emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(®(RA))); + emit_mov_r32_imm(DRCTOP, REG_EDX, SIMM16); + emit_cmp_r32_r32(DRCTOP, REG_EAX, REG_EDX); + + if (RT & 0x10) { + emit_jcc_near_link(DRCTOP, COND_L, &link1); // less than = signed < + do_link1 = 1; + } + if (RT & 0x08) { + emit_jcc_near_link(DRCTOP, COND_G, &link2); // greater = signed > + do_link2 = 1; + } + if (RT & 0x04) { + emit_jcc_near_link(DRCTOP, COND_E, &link3); // equal + do_link3 = 1; + } + if (RT & 0x02) { + emit_jcc_near_link(DRCTOP, COND_B, &link4); // below = unsigned < + do_link4 = 1; + } + if (RT & 0x01) { + emit_jcc_near_link(DRCTOP, COND_A, &link5); // above = unsigned > + do_link5 = 1; + } + emit_jmp_near_link(DRCTOP, &link6); + + if (do_link1) { + resolve_link(DRCTOP, &link1); + } + if (do_link2) { + resolve_link(DRCTOP, &link2); + } + if (do_link3) { + resolve_link(DRCTOP, &link3); + } + if (do_link4) { + resolve_link(DRCTOP, &link4); + } + if (do_link5) { + resolve_link(DRCTOP, &link5); + } + // generate exception + emit_mov_m32_imm(DRCTOP, MABS(&SRR0), temp_ppc_pc + 4); + emit_jmp(DRCTOP, ppc.generate_trap_exception); + + // no exception + resolve_link(DRCTOP, &link6); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_xorx(drc_core *drc, UINT32 op) +{ + emit_mov_r32_m32(DRCTOP, REG_EDX, MABS(®(RS))); + emit_xor_r32_m32(DRCTOP, REG_EDX, MABS(®(RB))); + emit_mov_m32_r32(DRCTOP, MABS(®(RA)), REG_EDX); + + if (RCBIT) { + append_set_cr0(drc); + } + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_xori(drc_core *drc, UINT32 op) +{ + emit_mov_r32_m32(DRCTOP, REG_EDX, MABS(®(RS))); + emit_xor_r32_imm(DRCTOP, REG_EDX, UIMM16); + emit_mov_m32_r32(DRCTOP, MABS(®(RA)), REG_EDX); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_xoris(drc_core *drc, UINT32 op) +{ + emit_mov_r32_m32(DRCTOP, REG_EDX, MABS(®(RS))); + emit_xor_r32_imm(DRCTOP, REG_EDX, UIMM16 << 16); + emit_mov_m32_r32(DRCTOP, MABS(®(RA)), REG_EDX); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_dccci(drc_core *drc, UINT32 op) +{ + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_dcread(drc_core *drc, UINT32 op) +{ + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_icbt(drc_core *drc, UINT32 op) +{ + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_iccci(drc_core *drc, UINT32 op) +{ + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_icread(drc_core *drc, UINT32 op) +{ + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_rfci(drc_core *drc, UINT32 op) +{ + osd_printf_debug("PPCDRC: recompile rfci\n"); + return RECOMPILE_UNIMPLEMENTED; +} + +static UINT32 recompile_mfdcr(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_push_imm(DRCTOP, op); + emit_call(DRCTOP, (x86code *)ppc_mfdcr); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_mtdcr(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_push_imm(DRCTOP, op); + emit_call(DRCTOP, (x86code *)ppc_mtdcr); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_wrtee(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_push_imm(DRCTOP, op); + emit_call(DRCTOP, (x86code *)ppc_wrtee); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_wrteei(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_push_imm(DRCTOP, op); + emit_call(DRCTOP, (x86code *)ppc_wrteei); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} +#endif + + + +static UINT32 recompile_invalid(drc_core *drc, UINT32 op) +{ + osd_printf_debug("PPCDRC: Invalid opcode %08X PC : %X\n", op, ppc.pc); + return RECOMPILE_UNIMPLEMENTED; +} + + + +/* PowerPC 60x Recompilers */ + +static UINT32 recompile_lfs(drc_core *drc,UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); +#if USE_SSE2 + if (RA == 0) + { + emit_push_imm(DRCTOP, SIMM16); + } + else + { + emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(®(RA))); + emit_add_r32_imm(DRCTOP, REG_EAX, SIMM16); + emit_push_r32(DRCTOP, REG_EAX); + } + emit_call(DRCTOP, (genf*)READ32); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_movd_r128_r32(DRCTOP, REG_XMM0, REG_EAX); + emit_cvtss2sd_r128_r128(DRCTOP, REG_XMM1, REG_XMM0); // convert float to double + emit_movq_m64_r128(DRCTOP, MABS(&FPR(RT)), REG_XMM1); +#else + emit_push_imm(DRCTOP, op); + emit_call(DRCTOP, (x86code *)ppc_lfs); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); +#endif + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_lfsu(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); +#if USE_SSE2 + emit_mov_r32_m32(DRCTOP, REG_EDX, MABS(®(RA))); + emit_add_r32_imm(DRCTOP, REG_EDX, SIMM16); + emit_mov_m32_r32(DRCTOP, MABS(®(RA)), REG_EDX); + emit_push_r32(DRCTOP, REG_EDX); + emit_call(DRCTOP, (x86code *)READ32); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_movd_r128_r32(DRCTOP, REG_XMM0, REG_EAX); + emit_cvtss2sd_r128_r128(DRCTOP, REG_XMM1, REG_XMM0); // convert float to double + emit_movq_m64_r128(DRCTOP, MABS(&FPR(RT)), REG_XMM1); +#else + emit_push_imm(DRCTOP, op); + emit_call(DRCTOP, (x86code *)ppc_lfsu); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); +#endif + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_lfd(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + if (RA == 0) + { + emit_push_imm(DRCTOP, SIMM16); + } + else + { + emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(®(RA))); + emit_add_r32_imm(DRCTOP, REG_EAX, SIMM16); + emit_push_r32(DRCTOP, REG_EAX); + } + emit_call(DRCTOP, (x86code *)READ64); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_mov_m64_r64(DRCTOP, MABS(&FPR(RT)), REG_EDX, REG_EAX); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_lfdu(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_mov_r32_m32(DRCTOP, REG_EDX, MABS(®(RA))); + emit_add_r32_imm(DRCTOP, REG_EDX, SIMM16); + emit_mov_m32_r32(DRCTOP, MABS(®(RA)), REG_EDX); + emit_push_r32(DRCTOP, REG_EDX); + emit_call(DRCTOP, (x86code *)READ64); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_mov_m64_r64(DRCTOP, MABS(&FPR(RT)), REG_EDX, REG_EAX); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_stfs(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); +#if USE_SSE2 + emit_movq_r128_m64(DRCTOP, REG_XMM0, MABS(&FPR(RT))); + emit_cvtsd2ss_r128_r128(DRCTOP, REG_XMM1, REG_XMM0); // convert double to float + emit_movd_r32_r128(DRCTOP, REG_EAX, REG_XMM1); + emit_push_r32(DRCTOP, REG_EAX); + if (RA == 0) + { + emit_push_imm(DRCTOP, SIMM16); + } + else + { + emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(®(RA))); + emit_add_r32_imm(DRCTOP, REG_EAX, SIMM16); + emit_push_r32(DRCTOP, REG_EAX); + } + emit_call(DRCTOP, (x86code *)WRITE32); + emit_add_r32_imm(DRCTOP, REG_ESP, 8); +#else + emit_push_imm(DRCTOP, op); + emit_call(DRCTOP, (x86code *)ppc_stfs); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); +#endif + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_stfsu(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); +#if USE_SSE2 + emit_movq_r128_m64(DRCTOP, REG_XMM0, MABS(&FPR(RT))); + emit_cvtsd2ss_r128_r128(DRCTOP, REG_XMM1, REG_XMM0); // convert double to float + emit_movd_r32_r128(DRCTOP, REG_EAX, REG_XMM1); + emit_push_r32(DRCTOP, REG_EAX); + + emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(®(RA))); + emit_add_r32_imm(DRCTOP, REG_EAX, SIMM16); + emit_mov_m32_r32(DRCTOP, MABS(®(RA)), REG_EAX); + emit_push_r32(DRCTOP, REG_EAX); + emit_call(DRCTOP, (x86code *)WRITE32); + emit_add_r32_imm(DRCTOP, REG_ESP, 8); +#else + emit_push_imm(DRCTOP, op); + emit_call(DRCTOP, (x86code *)ppc_stfsu); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); +#endif + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_stfd(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, MABS(&FPR(RT))); + emit_push_r32(DRCTOP, REG_EDX); + emit_push_r32(DRCTOP, REG_EAX); + if (RA == 0) + { + emit_push_imm(DRCTOP, SIMM16); + } + else + { + emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(®(RA))); + emit_add_r32_imm(DRCTOP, REG_EAX, SIMM16); + emit_push_r32(DRCTOP, REG_EAX); + } + emit_call(DRCTOP, (x86code *)WRITE64); + emit_add_r32_imm(DRCTOP, REG_ESP, 12); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_stfdu(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, MABS(&FPR(RT))); + emit_push_r32(DRCTOP, REG_EDX); + emit_push_r32(DRCTOP, REG_EAX); + + emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(®(RA))); + emit_add_r32_imm(DRCTOP, REG_EAX, SIMM16); + emit_mov_m32_r32(DRCTOP, MABS(®(RA)), REG_EAX); + emit_push_r32(DRCTOP, REG_EAX); + emit_call(DRCTOP, (x86code *)WRITE64); + emit_add_r32_imm(DRCTOP, REG_ESP, 12); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_lfdux(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_mov_r32_m32(DRCTOP, REG_EDX, MABS(®(RA))); + emit_add_r32_m32(DRCTOP, REG_EDX, MABS(®(RB))); + emit_mov_m32_r32(DRCTOP, MABS(®(RA)), REG_EDX); + emit_push_r32(DRCTOP, REG_EDX); + emit_call(DRCTOP, (x86code *)READ64); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_mov_m64_r64(DRCTOP, MABS(&FPR(RT)), REG_EDX, REG_EAX); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_lfdx(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(®(RB))); + if (RA != 0) + { + emit_add_r32_m32(DRCTOP, REG_EAX, MABS(®(RA))); + } + emit_push_r32(DRCTOP, REG_EAX); + emit_call(DRCTOP, (x86code *)READ64); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_mov_m64_r64(DRCTOP, MABS(&FPR(RT)), REG_EDX, REG_EAX); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_lfsux(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); +#if USE_SSE2 + emit_mov_r32_m32(DRCTOP, REG_EDX, MABS(®(RA))); + emit_add_r32_m32(DRCTOP, REG_EDX, MABS(®(RB))); + emit_mov_m32_r32(DRCTOP, MABS(®(RA)), REG_EDX); + emit_push_r32(DRCTOP, REG_EDX); + emit_call(DRCTOP, (x86code *)READ32); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_movd_r128_r32(DRCTOP, REG_XMM0, REG_EAX); + emit_cvtss2sd_r128_r128(DRCTOP, REG_XMM1, REG_XMM0); // convert float to double + emit_movq_m64_r128(DRCTOP, MABS(&FPR(RT)), REG_XMM1); +#else + emit_push_imm(DRCTOP, op); + emit_call(DRCTOP, (x86code *)ppc_lfsux); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); +#endif + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_lfsx(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); +#if USE_SSE2 + emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(®(RB))); + if (RA != 0) + { + emit_add_r32_m32(DRCTOP, REG_EAX, MABS(®(RA))); + } + emit_push_r32(DRCTOP, REG_EAX); + emit_call(DRCTOP, (x86code *)READ32); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_movd_r128_r32(DRCTOP, REG_XMM0, REG_EAX); + emit_cvtss2sd_r128_r128(DRCTOP, REG_XMM1, REG_XMM0); // convert float to double + emit_movq_m64_r128(DRCTOP, MABS(&FPR(RT)), REG_XMM1); +#else + emit_push_imm(DRCTOP, op); + emit_call(DRCTOP, (x86code *)ppc_lfsx); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); +#endif + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_mfsr(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_push_imm(DRCTOP, op); + emit_call(DRCTOP, (x86code *)ppc_mfsr); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_mfsrin(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_push_imm(DRCTOP, op); + emit_call(DRCTOP, (x86code *)ppc_mfsrin); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_mftb(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_push_imm(DRCTOP, op); + emit_call(DRCTOP, (x86code *)ppc_mftb); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_mtsr(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_push_imm(DRCTOP, op); + emit_call(DRCTOP, (x86code *)ppc_mtsr); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_mtsrin(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_push_imm(DRCTOP, op); + emit_call(DRCTOP, (x86code *)ppc_mtsrin); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_dcba(drc_core *drc, UINT32 op) +{ + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_stfdux(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, MABS(&FPR(RT))); + emit_push_r32(DRCTOP, REG_EDX); + emit_push_r32(DRCTOP, REG_EAX); + + emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(®(RA))); + emit_add_r32_m32(DRCTOP, REG_EAX, MABS(®(RB))); + emit_mov_m32_r32(DRCTOP, MABS(®(RA)), REG_EAX); + emit_push_r32(DRCTOP, REG_EAX); + emit_call(DRCTOP, (x86code *)WRITE64); + emit_add_r32_imm(DRCTOP, REG_ESP, 12); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_stfdx(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, MABS(&FPR(RT))); + emit_push_r32(DRCTOP, REG_EDX); + emit_push_r32(DRCTOP, REG_EAX); + + emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(®(RB))); + if (RA != 0) + { + emit_add_r32_m32(DRCTOP, REG_EAX, MABS(®(RA))); + } + emit_push_r32(DRCTOP, REG_EAX); + emit_call(DRCTOP, (x86code *)WRITE64); + emit_add_r32_imm(DRCTOP, REG_ESP, 12); + + emit_push_imm(DRCTOP, op); + emit_call(DRCTOP, (x86code *)ppc_stfdx); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_stfiwx(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); +#if USE_SSE2 + emit_movq_r128_m64(DRCTOP, REG_XMM0, MABS(&FPR(RT))); + emit_movd_r32_r128(DRCTOP, REG_EAX, REG_XMM0); + emit_push_r32(DRCTOP, REG_EAX); + + emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(®(RB))); + if (RA != 0) + { + emit_add_r32_m32(DRCTOP, REG_EAX, MABS(®(RA))); + } + emit_push_r32(DRCTOP, REG_EAX); + emit_call(DRCTOP, (x86code *)WRITE32); + emit_add_r32_imm(DRCTOP, REG_ESP, 8); +#else + emit_push_imm(DRCTOP, op); + emit_call(DRCTOP, (x86code *)ppc_stfiwx); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); +#endif + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_stfsux(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); +#if USE_SSE2 + emit_movq_r128_m64(DRCTOP, REG_XMM0, MABS(&FPR(RT))); + emit_cvtsd2ss_r128_r128(DRCTOP, REG_XMM1, REG_XMM0); // convert double to float + emit_movd_r32_r128(DRCTOP, REG_EAX, REG_XMM1); + emit_push_r32(DRCTOP, REG_EAX); + + emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(®(RA))); + emit_add_r32_m32(DRCTOP, REG_EAX, MABS(®(RB))); + emit_mov_m32_r32(DRCTOP, MABS(®(RA)), REG_EAX); + emit_push_r32(DRCTOP, REG_EAX); + emit_call(DRCTOP, (x86code *)WRITE32); + emit_add_r32_imm(DRCTOP, REG_ESP, 8); +#else + emit_push_imm(DRCTOP, op); + emit_call(DRCTOP, (x86code *)ppc_stfsux); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); +#endif + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_stfsx(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); +#if USE_SSE2 + emit_movq_r128_m64(DRCTOP, REG_XMM0, MABS(&FPR(RT))); + emit_cvtsd2ss_r128_r128(DRCTOP, REG_XMM1, REG_XMM0); // convert double to float + emit_movd_r32_r128(DRCTOP, REG_EAX, REG_XMM1); + emit_push_r32(DRCTOP, REG_EAX); + + emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(®(RB))); + if (RA != 0) + { + emit_add_r32_m32(DRCTOP, REG_EAX, MABS(®(RA))); + } + emit_push_r32(DRCTOP, REG_EAX); + emit_call(DRCTOP, (x86code *)WRITE32); + emit_add_r32_imm(DRCTOP, REG_ESP, 8); +#else + emit_push_imm(DRCTOP, op); + emit_call(DRCTOP, (x86code *)ppc_stfsx); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); +#endif + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_tlbia(drc_core *drc, UINT32 op) +{ + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_tlbie(drc_core *drc, UINT32 op) +{ + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_tlbsync(drc_core *drc, UINT32 op) +{ + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_eciwx(drc_core *drc, UINT32 op) +{ + osd_printf_debug("PPCDRC: eciwx unimplemented\n"); + return RECOMPILE_UNIMPLEMENTED; +} + +static UINT32 recompile_ecowx(drc_core *drc, UINT32 op) +{ + osd_printf_debug("PPCDRC: ecowx unimplemented\n"); + return RECOMPILE_UNIMPLEMENTED; +} + +static UINT32 recompile_fabsx(drc_core *drc, UINT32 op) +{ +#if !COMPILE_FPU || !USE_SSE2 + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_push_imm(DRCTOP, op); + emit_call(DRCTOP, (x86code *)ppc_fabsx); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); +#else + emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, MABS(&FPR(RB))); + emit_and_r32_imm(DRCTOP, REG_EDX, 0x7fffffff); + emit_mov_m64_r64(DRCTOP, MABS(&FPR(RT)), REG_EDX, REG_EAX); + + if (RCBIT) { + append_set_cr1(drc); + } +#endif + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_faddx(drc_core *drc, UINT32 op) +{ +#if !COMPILE_FPU || !USE_SSE2 + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_push_imm(DRCTOP, op); + emit_call(DRCTOP, (x86code *)ppc_faddx); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); +#else + emit_movq_r128_m64(DRCTOP, REG_XMM0, MABS(&FPR(RA))); + emit_movq_r128_m64(DRCTOP, REG_XMM1, MABS(&FPR(RB))); + emit_addsd_r128_r128(DRCTOP, REG_XMM0, REG_XMM1); + emit_movq_m64_r128(DRCTOP, MABS(&FPR(RT)), REG_XMM0); + + if (RCBIT) { + append_set_cr1(drc); + } +#endif + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_fcmpo(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_push_imm(DRCTOP, op); + emit_call(DRCTOP, (x86code *)ppc_fcmpo); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_fcmpu(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_push_imm(DRCTOP, op); + emit_call(DRCTOP, (x86code *)ppc_fcmpu); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_fctiwx(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_push_imm(DRCTOP, op); + emit_call(DRCTOP, (x86code *)ppc_fctiwx); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_fctiwzx(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_push_imm(DRCTOP, op); + emit_call(DRCTOP, (x86code *)ppc_fctiwzx); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_fdivx(drc_core *drc, UINT32 op) +{ +#if !COMPILE_FPU || !USE_SSE2 + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_push_imm(DRCTOP, op); + emit_call(DRCTOP, (x86code *)ppc_fdivx); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); +#else + emit_movq_r128_m64(DRCTOP, REG_XMM0, MABS(&FPR(RA))); + emit_movq_r128_m64(DRCTOP, REG_XMM1, MABS(&FPR(RB))); + emit_divsd_r128_r128(DRCTOP, REG_XMM0, REG_XMM1); + emit_movq_m64_r128(DRCTOP, MABS(&FPR(RT)), REG_XMM0); + + if (RCBIT) { + append_set_cr1(drc); + } +#endif + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_fmrx(drc_core *drc, UINT32 op) +{ +#if USE_SSE2 + emit_movq_r128_m64(DRCTOP, REG_XMM0, MABS(&FPR(RB))); + emit_movq_m64_r128(DRCTOP, MABS(&FPR(RT)), REG_XMM0); + + if (RCBIT) { + append_set_cr1(drc); + } +#else + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_push_imm(DRCTOP, op); + emit_call(DRCTOP, (x86code *)ppc_fmrx); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); +#endif + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_fnabsx(drc_core *drc, UINT32 op) +{ +#if !COMPILE_FPU || !USE_SSE2 + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_push_imm(DRCTOP, op); + emit_call(DRCTOP, (x86code *)ppc_fnabsx); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); +#else + emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, MABS(&FPR(RB))); + emit_or_r32_imm(DRCTOP, REG_EDX, 0x80000000); + emit_mov_m64_r64(DRCTOP, MABS(&FPR(RT)), REG_EDX, REG_EAX); + + if (RCBIT) { + append_set_cr1(drc); + } +#endif + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_fnegx(drc_core *drc, UINT32 op) +{ +#if !COMPILE_FPU || !USE_SSE2 + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_push_imm(DRCTOP, op); + emit_call(DRCTOP, (x86code *)ppc_fnegx); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); +#else + emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, MABS(&FPR(RB))); + emit_xor_r32_imm(DRCTOP, REG_EDX, 0x80000000); + emit_mov_m64_r64(DRCTOP, MABS(&FPR(RT)), REG_EDX, REG_EAX); + + if (RCBIT) { + append_set_cr1(drc); + } +#endif + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_frspx(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_push_imm(DRCTOP, op); + emit_call(DRCTOP, (x86code *)ppc_frspx); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); +/* + _movq_r128_m64(REG_XMM0, MABS(&FPR(RB))); + _movq_m64abs_r128(&FPR(RT), REG_XMM0); + + if (RCBIT) { + append_set_cr1(drc); + } +*/ + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_frsqrtex(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_push_imm(DRCTOP, op); + emit_call(DRCTOP, (x86code *)ppc_frsqrtex); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_fsqrtx(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_push_imm(DRCTOP, op); + emit_call(DRCTOP, (x86code *)ppc_fsqrtx); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_fsubx(drc_core *drc, UINT32 op) +{ +#if !COMPILE_FPU || !USE_SSE2 + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_push_imm(DRCTOP, op); + emit_call(DRCTOP, (x86code *)ppc_fsubx); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); +#else + emit_movq_r128_m64(DRCTOP, REG_XMM0, MABS(&FPR(RA))); + emit_movq_r128_m64(DRCTOP, REG_XMM1, MABS(&FPR(RB))); + emit_subsd_r128_r128(DRCTOP, REG_XMM0, REG_XMM1); + emit_movq_m64_r128(DRCTOP, MABS(&FPR(RT)), REG_XMM0); + + if (RCBIT) { + append_set_cr1(drc); + } +#endif + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_mffsx(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_push_imm(DRCTOP, op); + emit_call(DRCTOP, (x86code *)ppc_mffsx); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_mtfsb0x(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_push_imm(DRCTOP, op); + emit_call(DRCTOP, (x86code *)ppc_mtfsb0x); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_mtfsb1x(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_push_imm(DRCTOP, op); + emit_call(DRCTOP, (x86code *)ppc_mtfsb1x); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_mtfsfx(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_push_imm(DRCTOP, op); + emit_call(DRCTOP, (x86code *)ppc_mtfsfx); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_mtfsfix(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_push_imm(DRCTOP, op); + emit_call(DRCTOP, (x86code *)ppc_mtfsfix); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_mcrfs(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_push_imm(DRCTOP, op); + emit_call(DRCTOP, (x86code *)ppc_mcrfs); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_faddsx(drc_core *drc, UINT32 op) +{ +#if !COMPILE_FPU || !USE_SSE2 + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_push_imm(DRCTOP, op); + emit_call(DRCTOP, (x86code *)ppc_faddsx); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); +#else + emit_movq_r128_m64(DRCTOP, REG_XMM0, MABS(&FPR(RA))); + emit_movq_r128_m64(DRCTOP, REG_XMM1, MABS(&FPR(RB))); + emit_addsd_r128_r128(DRCTOP, REG_XMM0, REG_XMM1); + emit_movq_m64_r128(DRCTOP, MABS(&FPR(RT)), REG_XMM0); + + if (RCBIT) { + append_set_cr1(drc); + } +#endif + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_fdivsx(drc_core *drc, UINT32 op) +{ +#if !COMPILE_FPU || !USE_SSE2 + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_push_imm(DRCTOP, op); + emit_call(DRCTOP, (x86code *)ppc_fdivsx); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); +#else + emit_movq_r128_m64(DRCTOP, REG_XMM0, MABS(&FPR(RA))); + emit_movq_r128_m64(DRCTOP, REG_XMM1, MABS(&FPR(RB))); + emit_divsd_r128_r128(DRCTOP, REG_XMM0, REG_XMM1); + emit_movq_m64_r128(DRCTOP, MABS(&FPR(RT)), REG_XMM0); + + if (RCBIT) { + append_set_cr1(drc); + } +#endif + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_fresx(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_push_imm(DRCTOP, op); + emit_call(DRCTOP, (x86code *)ppc_fresx); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_fsqrtsx(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_push_imm(DRCTOP, op); + emit_call(DRCTOP, (x86code *)ppc_fsqrtsx); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_fsubsx(drc_core *drc, UINT32 op) +{ +#if !COMPILE_FPU || !USE_SSE2 + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_push_imm(DRCTOP, op); + emit_call(DRCTOP, (x86code *)ppc_fsubsx); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); +#else + emit_movq_r128_m64(DRCTOP, REG_XMM0, MABS(&FPR(RA))); + emit_movq_r128_m64(DRCTOP, REG_XMM1, MABS(&FPR(RB))); + emit_subsd_r128_r128(DRCTOP, REG_XMM0, REG_XMM1); + emit_movq_m64_r128(DRCTOP, MABS(&FPR(RT)), REG_XMM0); + + if (RCBIT) { + append_set_cr1(drc); + } +#endif + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_fmaddx(drc_core *drc, UINT32 op) +{ +#if !COMPILE_FPU || !USE_SSE2 + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_push_imm(DRCTOP, op); + emit_call(DRCTOP, (x86code *)ppc_fmaddx); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); +#else + emit_movq_r128_m64(DRCTOP, REG_XMM0, MABS(&FPR(RA))); + emit_movq_r128_m64(DRCTOP, REG_XMM1, MABS(&FPR(RC))); + emit_movq_r128_m64(DRCTOP, REG_XMM2, MABS(&FPR(RB))); + emit_mulsd_r128_r128(DRCTOP, REG_XMM0, REG_XMM1); + emit_addsd_r128_r128(DRCTOP, REG_XMM0, REG_XMM2); + emit_movq_m64_r128(DRCTOP, MABS(&FPR(RT)), REG_XMM0); + + if (RCBIT) { + append_set_cr1(drc); + } +#endif + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_fmsubx(drc_core *drc, UINT32 op) +{ +#if !COMPILE_FPU || !USE_SSE2 + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_push_imm(DRCTOP, op); + emit_call(DRCTOP, (x86code *)ppc_fmsubx); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); +#else + emit_movq_r128_m64(DRCTOP, REG_XMM0, MABS(&FPR(RA))); + emit_movq_r128_m64(DRCTOP, REG_XMM1, MABS(&FPR(RC))); + emit_movq_r128_m64(DRCTOP, REG_XMM2, MABS(&FPR(RB))); + emit_mulsd_r128_r128(DRCTOP, REG_XMM0, REG_XMM1); + emit_subsd_r128_r128(DRCTOP, REG_XMM0, REG_XMM2); + emit_movq_m64_r128(DRCTOP, MABS(&FPR(RT)), REG_XMM0); + + if (RCBIT) { + append_set_cr1(drc); + } +#endif + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_fmulx(drc_core *drc, UINT32 op) +{ +#if !COMPILE_FPU || !USE_SSE2 + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_push_imm(DRCTOP, op); + emit_call(DRCTOP, (x86code *)ppc_fmulx); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); +#else + emit_movq_r128_m64(DRCTOP, REG_XMM0, MABS(&FPR(RA))); + emit_movq_r128_m64(DRCTOP, REG_XMM1, MABS(&FPR(RC))); + emit_mulsd_r128_r128(DRCTOP, REG_XMM0, REG_XMM1); + emit_movq_m64_r128(DRCTOP, MABS(&FPR(RT)), REG_XMM0); + + if (RCBIT) { + append_set_cr1(drc); + } +#endif + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_fnmaddx(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_push_imm(DRCTOP, op); + emit_call(DRCTOP, (x86code *)ppc_fnmaddx); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_fnmsubx(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_push_imm(DRCTOP, op); + emit_call(DRCTOP, (x86code *)ppc_fnmsubx); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_fselx(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_push_imm(DRCTOP, op); + emit_call(DRCTOP, (x86code *)ppc_fselx); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_fmaddsx(drc_core *drc, UINT32 op) +{ +#if !COMPILE_FPU || !USE_SSE2 + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_push_imm(DRCTOP, op); + emit_call(DRCTOP, (x86code *)ppc_fmaddsx); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); +#else + emit_movq_r128_m64(DRCTOP, REG_XMM0, MABS(&FPR(RA))); + emit_movq_r128_m64(DRCTOP, REG_XMM1, MABS(&FPR(RC))); + emit_movq_r128_m64(DRCTOP, REG_XMM2, MABS(&FPR(RB))); + emit_mulsd_r128_r128(DRCTOP, REG_XMM0, REG_XMM1); + emit_addsd_r128_r128(DRCTOP, REG_XMM0, REG_XMM2); + emit_movq_m64_r128(DRCTOP, MABS(&FPR(RT)), REG_XMM0); + + if (RCBIT) { + append_set_cr1(drc); + } +#endif + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_fmsubsx(drc_core *drc, UINT32 op) +{ +#if !COMPILE_FPU || !USE_SSE2 + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_push_imm(DRCTOP, op); + emit_call(DRCTOP, (x86code *)ppc_fmsubsx); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); +#else + emit_movq_r128_m64(DRCTOP, REG_XMM0, MABS(&FPR(RA))); + emit_movq_r128_m64(DRCTOP, REG_XMM1, MABS(&FPR(RC))); + emit_movq_r128_m64(DRCTOP, REG_XMM2, MABS(&FPR(RB))); + emit_mulsd_r128_r128(DRCTOP, REG_XMM0, REG_XMM1); + emit_subsd_r128_r128(DRCTOP, REG_XMM0, REG_XMM2); + emit_movq_m64_r128(DRCTOP, MABS(&FPR(RT)), REG_XMM0); + + if (RCBIT) { + append_set_cr1(drc); + } +#endif + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_fmulsx(drc_core *drc, UINT32 op) +{ +#if !COMPILE_FPU || !USE_SSE2 + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_push_imm(DRCTOP, op); + emit_call(DRCTOP, (x86code *)ppc_fmulsx); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); +#else + emit_movq_r128_m64(DRCTOP, REG_XMM0, MABS(&FPR(RA))); + emit_movq_r128_m64(DRCTOP, REG_XMM1, MABS(&FPR(RC))); + emit_mulsd_r128_r128(DRCTOP, REG_XMM0, REG_XMM1); + emit_movq_m64_r128(DRCTOP, MABS(&FPR(RT)), REG_XMM0); + + if (RCBIT) { + append_set_cr1(drc); + } +#endif + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_fnmaddsx(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_push_imm(DRCTOP, op); + emit_call(DRCTOP, (x86code *)ppc_fnmaddsx); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_fnmsubsx(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_push_imm(DRCTOP, op); + emit_call(DRCTOP, (x86code *)ppc_fnmsubsx); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} +#endif + +// PPC602 + +static UINT32 recompile_esa(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_push_imm(DRCTOP, op); + emit_call(DRCTOP, (x86code *)ppc_esa); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_dsa(drc_core *drc, UINT32 op) +{ + emit_mov_m32_r32(DRCTOP, MABS(&ppc_icount), REG_EBP); + emit_push_imm(DRCTOP, op); + emit_call(DRCTOP, (x86code *)ppc_dsa); + emit_add_r32_imm(DRCTOP, REG_ESP, 4); + emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(&ppc_icount)); + + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_tlbli(drc_core *drc, UINT32 op) +{ + return RECOMPILE_SUCCESSFUL_CP(1,4); +} + +static UINT32 recompile_tlbld(drc_core *drc, UINT32 op) +{ + return RECOMPILE_SUCCESSFUL_CP(1,4); +} diff --git a/src/devices/cpu/powerpc/drc_ops.h b/src/devices/cpu/powerpc/drc_ops.h new file mode 100644 index 00000000000..792cdd6260a --- /dev/null +++ b/src/devices/cpu/powerpc/drc_ops.h @@ -0,0 +1,145 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +static const PPC_OPCODE ppcdrc_opcode_common[] = +{ + /*code subcode handler */ + { 31, 266, recompile_addx }, + { 31, 266 | 512, recompile_addx }, + { 31, 10, recompile_addcx }, + { 31, 10 | 512, recompile_addcx }, + { 31, 138, recompile_addex }, + { 31, 138 | 512, recompile_addex }, + { 14, -1, recompile_addi }, + { 12, -1, recompile_addic }, + { 13, -1, recompile_addic_rc }, + { 15, -1, recompile_addis }, + { 31, 234, recompile_addmex }, + { 31, 234 | 512, recompile_addmex }, + { 31, 202, recompile_addzex }, + { 31, 202 | 512, recompile_addzex }, + { 31, 28, recompile_andx }, + { 31, 28 | 512, recompile_andx }, + { 31, 60, recompile_andcx }, + { 28, -1, recompile_andi_rc }, + { 29, -1, recompile_andis_rc }, + { 18, -1, recompile_bx }, + { 16, -1, recompile_bcx }, + { 19, 528, recompile_bcctrx }, + { 19, 16, recompile_bclrx }, + { 31, 0, recompile_cmp }, + { 11, -1, recompile_cmpi }, + { 31, 32, recompile_cmpl }, + { 10, -1, recompile_cmpli }, + { 31, 26, recompile_cntlzw }, + { 19, 257, recompile_crand }, + { 19, 129, recompile_crandc }, + { 19, 289, recompile_creqv }, + { 19, 225, recompile_crnand }, + { 19, 33, recompile_crnor }, + { 19, 449, recompile_cror }, + { 19, 417, recompile_crorc }, + { 19, 193, recompile_crxor }, + { 31, 86, recompile_dcbf }, + { 31, 470, recompile_dcbi }, + { 31, 54, recompile_dcbst }, + { 31, 278, recompile_dcbt }, + { 31, 246, recompile_dcbtst }, + { 31, 1014, recompile_dcbz }, + { 31, 491, recompile_divwx }, + { 31, 491 | 512, recompile_divwx }, + { 31, 459, recompile_divwux }, + { 31, 459 | 512, recompile_divwux }, + { 31, 854, recompile_eieio }, + { 31, 284, recompile_eqvx }, + { 31, 954, recompile_extsbx }, + { 31, 922, recompile_extshx }, + { 31, 982, recompile_icbi }, + { 19, 150, recompile_isync }, + { 34, -1, recompile_lbz }, + { 35, -1, recompile_lbzu }, + { 31, 119, recompile_lbzux }, + { 31, 87, recompile_lbzx }, + { 42, -1, recompile_lha }, + { 43, -1, recompile_lhau }, + { 31, 375, recompile_lhaux }, + { 31, 343, recompile_lhax }, + { 31, 790, recompile_lhbrx }, + { 40, -1, recompile_lhz }, + { 41, -1, recompile_lhzu }, + { 31, 311, recompile_lhzux }, + { 31, 279, recompile_lhzx }, + { 46, -1, recompile_lmw }, + { 31, 597, recompile_lswi }, + { 31, 533, recompile_lswx }, + { 31, 20, recompile_lwarx }, + { 31, 534, recompile_lwbrx }, + { 32, -1, recompile_lwz }, + { 33, -1, recompile_lwzu }, + { 31, 55, recompile_lwzux }, + { 31, 23, recompile_lwzx }, + { 19, 0, recompile_mcrf }, + { 31, 512, recompile_mcrxr }, + { 31, 19, recompile_mfcr }, + { 31, 83, recompile_mfmsr }, + { 31, 339, recompile_mfspr }, + { 31, 144, recompile_mtcrf }, + { 31, 146, recompile_mtmsr }, + { 31, 467, recompile_mtspr }, + { 31, 75, recompile_mulhwx }, + { 31, 11, recompile_mulhwux }, + { 7, -1, recompile_mulli }, + { 31, 235, recompile_mullwx }, + { 31, 235 | 512, recompile_mullwx }, + { 31, 476, recompile_nandx }, + { 31, 104, recompile_negx }, + { 31, 104 | 512, recompile_negx }, + { 31, 124, recompile_norx }, + { 31, 444, recompile_orx }, + { 31, 412, recompile_orcx }, + { 24, -1, recompile_ori }, + { 25, -1, recompile_oris }, + { 19, 50, recompile_rfi }, + { 20, -1, recompile_rlwimix }, + { 21, -1, recompile_rlwinmx }, + { 23, -1, recompile_rlwnmx }, + { 17, -1, recompile_sc }, + { 31, 24, recompile_slwx }, + { 31, 792, recompile_srawx }, + { 31, 824, recompile_srawix }, + { 31, 536, recompile_srwx }, + { 38, -1, recompile_stb }, + { 39, -1, recompile_stbu }, + { 31, 247, recompile_stbux }, + { 31, 215, recompile_stbx }, + { 44, -1, recompile_sth }, + { 31, 918, recompile_sthbrx }, + { 45, -1, recompile_sthu }, + { 31, 439, recompile_sthux }, + { 31, 407, recompile_sthx }, + { 47, -1, recompile_stmw }, + { 31, 725, recompile_stswi }, + { 31, 661, recompile_stswx }, + { 36, -1, recompile_stw }, + { 31, 662, recompile_stwbrx }, + { 31, 150, recompile_stwcx_rc }, + { 37, -1, recompile_stwu }, + { 31, 183, recompile_stwux }, + { 31, 151, recompile_stwx }, + { 31, 40, recompile_subfx }, + { 31, 40 | 512, recompile_subfx }, + { 31, 8, recompile_subfcx }, + { 31, 8 | 512, recompile_subfcx }, + { 31, 136, recompile_subfex }, + { 31, 136 | 512, recompile_subfex }, + { 8, -1, recompile_subfic }, + { 31, 232, recompile_subfmex }, + { 31, 232 | 512, recompile_subfmex }, + { 31, 200, recompile_subfzex }, + { 31, 200 | 512, recompile_subfzex }, + { 31, 598, recompile_sync }, + { 31, 4, recompile_tw }, + { 3, -1, recompile_twi }, + { 31, 316, recompile_xorx }, + { 26, -1, recompile_xori }, + { 27, -1, recompile_xoris } +}; diff --git a/src/devices/cpu/powerpc/ppc.c b/src/devices/cpu/powerpc/ppc.c new file mode 100644 index 00000000000..cb85522177d --- /dev/null +++ b/src/devices/cpu/powerpc/ppc.c @@ -0,0 +1,2135 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/* IBM/Motorola PowerPC 4xx/6xx Emulator */ + +#include +#include "emu.h" +#include "debugger.h" + +/* avoid including setjmp.h and defining jump buffer if not included from here */ +#define PPC_H_INCLUDED_FROM_PPC_C +#include "ppc.h" + +// PLL Configuration based on the table in MPC603EUM page 7-31 +static const int mpc603e_pll_config[12][9] = +{ + // 16, 20, 25, 33, 40, 50, 60, 66, 75 + { -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { 0x2, 0x2, 0x2, 0x1, 0x1, 0x1, -1, 0x0, -1 }, + { -1, -1, -1, -1, -1, 0xc, -1, 0xc, -1 }, + { 0x5, 0x5, 0x5, 0x4, 0x4, 0x4, -1, -1, -1 }, + { -1, -1, -1, 0x6, 0x6, -1, -1, -1, -1 }, + { -1, -1, 0x8, 0x8, -1, -1, -1, -1, -1 }, + { -1, 0xe, 0xe, -1, -1, -1, -1, -1, -1 }, + { 0xa, 0xa, 0xa, -1, -1, -1, -1, -1, -1 }, + { -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { -1, -1, -1, -1, -1, -1, -1, -1, -1 }, +}; + +// PLL Configuration based on the table in MPC603E7VEC page 29 +static const int mpc603ev_pll_config[12][9] = +{ + // 16, 20, 25, 33, 40, 50, 60, 66, 75 + { -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + // 2:1 + { -1, -1, -1, -1, -1, -1, -1, 0x4, 0x4 }, + // 2.5:1 + { -1, -1, -1, -1, -1, 0x6, 0x6, 0x6, 0x6 }, + // 3:1 + { -1, -1, -1, -1, 0x8, 0x8, 0x8, 0x8, 0x8 }, + // 3.5:1 + { -1, -1, -1, -1, 0xe, 0xe, 0xe, 0xe, -1 }, + // 4:1 + { -1, -1, -1, 0xa, 0xa, 0xa, 0xa, -1, -1 }, + // 4.5:1 + { -1, -1, -1, 0x7, 0x7, 0x7, -1, -1, -1 }, + // 5:1 + { -1, -1, 0xb, 0xb, 0xb, -1, -1, -1, -1 }, + // 5.5:1 + { -1, -1, 0x9, 0x9, 0x9, -1, -1, -1, -1 }, + // 6:1 + { -1, -1, 0xd, 0xd, 0xd, -1, -1, -1, -1 } +}; + +// PLL Configuration based on the table in MPC603E7TEC page 23 +static const int mpc603r_pll_config[12][9] = +{ + // 16, 20, 25, 33, 40, 50, 60, 66, 75 + { -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + // 2:1 + { -1, -1, -1, -1, 0x5, 0x5, 0x5, 0x5, 0x5 }, + // 2.5:1 + { -1, -1, -1, -1, -1, -1, 0x6, 0x6, 0x6 }, + // 3:1 + { -1, -1, -1, -1, -1, 0x8, 0x8, 0x8, 0x8 }, + // 3.5:1 + { -1, -1, -1, -1, -1, 0xe, 0xe, 0xe, 0xe }, + // 4:1 + { -1, -1, -1, -1, 0xa, 0xa, 0xa, 0xa, 0xa }, + // 4.5:1 + { -1, -1, -1, 0x7, 0x7, 0x7, 0x7, 0x7, -1 }, + // 5:1 + { -1, -1, -1, 0xb, 0xb, 0xb, 0xb, -1, -1 }, + // 5.5:1 + { -1, -1, -1, 0x9, 0x9, 0x9, -1, -1, -1 }, + // 6:1 + { -1, -1, 0xd, 0xd, 0xd, 0xd, -1, -1, -1 }, +}; + + +static void ppc603_exception(int exception); +static void ppc602_exception(int exception); +static void ppc403_exception(int exception); +static UINT8 ppc403_spu_r(UINT32 a); +static void ppc403_spu_w(UINT32 a, UINT8 d); + +#define RD ((op >> 21) & 0x1F) +#define RT ((op >> 21) & 0x1f) +#define RS ((op >> 21) & 0x1f) +#define RA ((op >> 16) & 0x1f) +#define RB ((op >> 11) & 0x1f) +#define RC ((op >> 6) & 0x1f) + +#define MB ((op >> 6) & 0x1f) +#define ME ((op >> 1) & 0x1f) +#define SH ((op >> 11) & 0x1f) +#define BO ((op >> 21) & 0x1f) +#define BI ((op >> 16) & 0x1f) +#define CRFD ((op >> 23) & 0x7) +#define CRFA ((op >> 18) & 0x7) +#define FXM ((op >> 12) & 0xff) +#define SPR (((op >> 16) & 0x1f) | ((op >> 6) & 0x3e0)) + +#define SIMM16 (INT32)(INT16)(op & 0xffff) +#define UIMM16 (UINT32)(op & 0xffff) + +#define RCBIT (op & 0x1) +#define OEBIT (op & 0x400) +#define AABIT (op & 0x2) +#define LKBIT (op & 0x1) + +#define REG(x) (m_r[x]) +#define LR (m_lr) +#define CTR (m_ctr) +#define XER (m_xer) +#define CR(x) (m_cr[x]) +#define MSR (m_msr) +#define SRR0 (m_srr0) +#define SRR1 (m_srr1) +#define SRR2 (m_srr2) +#define SRR3 (m_srr3) +#define EVPR (m_evpr) +#define EXIER (m_exier) +#define EXISR (m_exisr) +#define DEC (m_dec) + + +// Stuff added for the 6xx +#define FPR(x) (m_fpr[x]) +#define FM ((op >> 17) & 0xFF) +#define SPRF (((op >> 6) & 0x3E0) | ((op >> 16) & 0x1F)) + + +#define CHECK_SUPERVISOR() \ + if((m_msr & 0x4000) != 0){ \ + } + +#define CHECK_FPU_AVAILABLE() \ + if((m_msr & 0x2000) == 0){ \ + } + +static UINT32 ppc_field_xlat[256]; + + + +#define FPSCR_FX 0x80000000 +#define FPSCR_FEX 0x40000000 +#define FPSCR_VX 0x20000000 +#define FPSCR_OX 0x10000000 +#define FPSCR_UX 0x08000000 +#define FPSCR_ZX 0x04000000 +#define FPSCR_XX 0x02000000 + + + +#define BITMASK_0(n) (UINT32)(((UINT64)1 << n) - 1) +#define CRBIT(x) ((m_cr[x / 4] & (1 << (3 - (x % 4)))) ? 1 : 0) +#define _BIT(n) (1 << (n)) +#define GET_ROTATE_MASK(mb,me) (ppc_rotate_mask[mb][me]) +#define ADD_CA(r,a,b) ((UINT32)r < (UINT32)a) +#define SUB_CA(r,a,b) (!((UINT32)a < (UINT32)b)) +#define ADD_OV(r,a,b) ((~((a) ^ (b)) & ((a) ^ (r))) & 0x80000000) +#define SUB_OV(r,a,b) (( ((a) ^ (b)) & ((a) ^ (r))) & 0x80000000) + +#define XER_SO 0x80000000 +#define XER_OV 0x40000000 +#define XER_CA 0x20000000 + +#define MSR_AP 0x00800000 /* Access privilege state (PPC602) */ +#define MSR_SA 0x00400000 /* Supervisor access mode (PPC602) */ +#define MSR_POW 0x00040000 /* Power Management Enable */ +#define MSR_WE 0x00040000 +#define MSR_CE 0x00020000 +#define MSR_ILE 0x00010000 /* Interrupt Little Endian Mode */ +#define MSR_EE 0x00008000 /* External Interrupt Enable */ +#define MSR_PR 0x00004000 /* Problem State */ +#define MSR_FP 0x00002000 /* Floating Point Available */ +#define MSR_ME 0x00001000 /* Machine Check Enable */ +#define MSR_FE0 0x00000800 +#define MSR_SE 0x00000400 /* Single Step Trace Enable */ +#define MSR_BE 0x00000200 /* Branch Trace Enable */ +#define MSR_DE 0x00000200 +#define MSR_FE1 0x00000100 +#define MSR_IP 0x00000040 /* Interrupt Prefix */ +#define MSR_IR 0x00000020 /* Instruction Relocate */ +#define MSR_DR 0x00000010 /* Data Relocate */ +#define MSR_PE 0x00000008 +#define MSR_PX 0x00000004 +#define MSR_RI 0x00000002 /* Recoverable Interrupt Enable */ +#define MSR_LE 0x00000001 + +#define TSR_ENW 0x80000000 +#define TSR_WIS 0x40000000 + +#define BYTE_REVERSE16(x) ((((x) >> 8) & 0xff) | (((x) << 8) & 0xff00)) +#define BYTE_REVERSE32(x) ((((x) >> 24) & 0xff) | (((x) >> 8) & 0xff00) | (((x) << 8) & 0xff0000) | (((x) << 24) & 0xff000000)) + + +const device_type PPC403 = &device_creator; +const device_type PPC405 = &device_creator; +const device_type PPC601 = &device_creator; +const device_type PPC602 = &device_creator; +const device_type PPC603 = &device_creator; +const device_type PPC603E = &device_creator; +const device_type PPC603R = &device_creator; +const device_type PPC604 = &device_creator; +const device_type MPC8240 = &device_creator; +const device_type PPC403GA = &device_creator; +const device_type PPC403GCX = &device_creator; +const device_type PPC405GP = &device_creator; + + +struct PPC_OPCODE { + int code; + int subcode; + void (* handler)(UINT32); +}; + + + +static UINT32 ppc_rotate_mask[32][32]; + +#define ROPCODE(pc) memory_decrypted_read_dword(m_program, pc) +#define ROPCODE64(pc) memory_decrypted_read_qword(m_program, DWORD_XOR_BE(pc)) + + +ppc_device::ppc_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, int address_bits, powerpc_flavor flavor, UINT32 cap, UINT32 tb_divisor) + : cpu_device(mconfig, type, name, tag, owner, clock, shortname, __FILE__) + , m_program_config("program", ENDIANNESS_BIG, address_bits, 32) + , m_core(NULL) + , c_bus_frequency(0) + , m_bus_freq_multiplier(1) + , m_flavor(flavor) + , m_cap(cap) + , m_tb_divisor(tb_divisor) + , m_vtlb(NULL) + , m_cache(CACHE_SIZE + sizeof(internal_ppc_state)) +{ +} + +//ppc403_device::ppc403_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) +// : ppc_device(mconfig, PPC403, "PPC403", tag, owner, clock, "ppc403", 32) +//{ +//} +// +//ppc405_device::ppc405_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) +// : ppc_device(mconfig, PPC405, "PPC405", tag, owner, clock, "ppc405", 32) +//{ +//} + +ppc603_device::ppc603_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : ppc_device(mconfig, PPC603, "PowerPC 603", tag, owner, clock, "ppc603", 64, PPC_MODEL_603, PPCCAP_OEA | PPCCAP_VEA | PPCCAP_FPU | PPCCAP_MISALIGNED | PPCCAP_603_MMU, 4) +{ +} + +ppc603e_device::ppc603e_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : ppc_device(mconfig, PPC603E, "PowerPC 603e", tag, owner, clock, "ppc603e", 64, PPC_MODEL_603E, PPCCAP_OEA | PPCCAP_VEA | PPCCAP_FPU | PPCCAP_MISALIGNED | PPCCAP_603_MMU, 4) +{ +} + +ppc603r_device::ppc603r_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : ppc_device(mconfig, PPC603R, "PowerPC 603R", tag, owner, clock, "ppc603r", 64, PPC_MODEL_603R, PPCCAP_OEA | PPCCAP_VEA | PPCCAP_FPU | PPCCAP_MISALIGNED | PPCCAP_603_MMU, 4) +{ +} + +ppc602_device::ppc602_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : ppc_device(mconfig, PPC602, "PowerPC 602", tag, owner, clock, "ppc602", 64, PPC_MODEL_602, PPCCAP_OEA | PPCCAP_VEA | PPCCAP_FPU | PPCCAP_MISALIGNED | PPCCAP_603_MMU, 4) +{ +} + +mpc8240_device::mpc8240_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : ppc_device(mconfig, MPC8240, "PowerPC MPC8240", tag, owner, clock, "mpc8240", 64, PPC_MODEL_MPC8240, PPCCAP_OEA | PPCCAP_VEA | PPCCAP_FPU | PPCCAP_MISALIGNED | PPCCAP_603_MMU, 4/* unknown */) +{ +} + +ppc601_device::ppc601_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : ppc_device(mconfig, PPC601, "PowerPC 601", tag, owner, clock, "ppc601", 64, PPC_MODEL_601, PPCCAP_OEA | PPCCAP_VEA | PPCCAP_FPU | PPCCAP_MISALIGNED | PPCCAP_MFIOC | PPCCAP_601BAT, 0/* no TB */) +{ +} + +ppc604_device::ppc604_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : ppc_device(mconfig, PPC604, "PowerPC 604", tag, owner, clock, "ppc604", 64, PPC_MODEL_604, PPCCAP_OEA | PPCCAP_VEA | PPCCAP_FPU | PPCCAP_MISALIGNED | PPCCAP_604_MMU, 4) +{ +} + +ppc4xx_device::ppc4xx_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, powerpc_flavor flavor, UINT32 cap, UINT32 tb_divisor) + : ppc_device(mconfig, type, name, tag, owner, clock, shortname, 64, flavor, cap, tb_divisor) // TODO address bits, ppccom has 31 address bits?? +{ +} + +ppc403ga_device::ppc403ga_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : ppc4xx_device(mconfig, PPC403GA, "PowerPC 403GA", tag, owner, clock, "ppc403ga", PPC_MODEL_403GA, PPCCAP_4XX, 1) +{ +} + +ppc403gcx_device::ppc403gcx_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : ppc4xx_device(mconfig, PPC403GCX, "PowerPC 403GCX", tag, owner, clock, "ppc403gcx", PPC_MODEL_403GCX, PPCCAP_4XX, 1) +{ +} + +ppc405gp_device::ppc405gp_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : ppc4xx_device(mconfig, PPC405GP, "PowerPC 405GP", tag, owner, clock, "ppc405gp", PPC_MODEL_405GP, PPCCAP_4XX | PPCCAP_VEA, 1) +{ +} + +/*********************************************************************/ + +inline int ppc_device::IS_PPC602(void) +{ + return m_is602; +} + +inline int ppc_device::IS_PPC603(void) +{ + return m_is603; +} + +inline int ppc_device::IS_PPC403(void) +{ + return !IS_PPC602() && !IS_PPC603(); +} + +/*********************************************************************/ + + +INLINE void SET_CR0(INT32 rd) +{ + if( rd < 0 ) { + CR(0) = 0x8; + } else if( rd > 0 ) { + CR(0) = 0x4; + } else { + CR(0) = 0x2; + } + + if( XER & XER_SO ) + CR(0) |= 0x1; +} + +INLINE void SET_CR1(void) +{ + CR(1) = (ppc.fpscr >> 28) & 0xf; +} + +INLINE void SET_ADD_OV(UINT32 rd, UINT32 ra, UINT32 rb) +{ + if( ADD_OV(rd, ra, rb) ) + XER |= XER_SO | XER_OV; + else + XER &= ~XER_OV; +} + +INLINE void SET_SUB_OV(UINT32 rd, UINT32 ra, UINT32 rb) +{ + if( SUB_OV(rd, ra, rb) ) + XER |= XER_SO | XER_OV; + else + XER &= ~XER_OV; +} + +INLINE void SET_ADD_CA(UINT32 rd, UINT32 ra, UINT32 rb) +{ + if( ADD_CA(rd, ra, rb) ) + XER |= XER_CA; + else + XER &= ~XER_CA; +} + +INLINE void SET_SUB_CA(UINT32 rd, UINT32 ra, UINT32 rb) +{ + if( SUB_CA(rd, ra, rb) ) + XER |= XER_CA; + else + XER &= ~XER_CA; +} + +INLINE UINT32 check_condition_code(UINT32 bo, UINT32 bi) +{ + UINT32 ctr_ok; + UINT32 condition_ok; + UINT32 bo0 = (bo & 0x10) ? 1 : 0; + UINT32 bo1 = (bo & 0x08) ? 1 : 0; + UINT32 bo2 = (bo & 0x04) ? 1 : 0; + UINT32 bo3 = (bo & 0x02) ? 1 : 0; + + if( bo2 == 0 ) + --CTR; + + ctr_ok = bo2 | ((CTR != 0) ^ bo3); + condition_ok = bo0 | (CRBIT(bi) ^ (~bo1 & 0x1)); + + return ctr_ok && condition_ok; +} + +INLINE UINT64 ppc_read_timebase(void) +{ + int cycles = ppc_tb_base_icount - ppc_icount; + + if (IS_PPC603() || IS_PPC602()) + { + // timebase is incremented once every four core clock cycles, so adjust the cycles accordingly + return ppc.tb + (cycles / 4); + } + else + { + // timebase is incremented once every core cycle on PPC403 + return ppc.tb + cycles; + } +} + +INLINE void ppc_write_timebase_l(UINT32 tbl) +{ + ppc_tb_base_icount = ppc_icount; + + ppc.tb &= ~0xffffffff; + ppc.tb |= tbl; +} + +INLINE void ppc_write_timebase_h(UINT32 tbh) +{ + ppc_tb_base_icount = ppc_icount; + + ppc.tb &= 0xffffffff; + ppc.tb |= (UINT64)(tbh) << 32; +} + +INLINE UINT32 read_decrementer(void) +{ + int cycles = ppc_dec_base_icount - ppc_icount; + + // decrementer is decremented once every four bus clock cycles, so adjust the cycles accordingly + return DEC - (cycles / (bus_freq_multiplier * 2)); +} + +INLINE void write_decrementer(UINT32 value) +{ + ppc_dec_base_icount = ppc_icount + (ppc_dec_base_icount - ppc_icount) % (bus_freq_multiplier * 2); + + DEC = value; + + // check if decrementer exception occurs during execution + if ((UINT32)(DEC - ppc_icount) > (UINT32)(DEC)) + { + ppc_dec_trigger_cycle = ppc_icount - DEC; + } + else + { + ppc_dec_trigger_cycle = 0x7fffffff; + } +} + +/*********************************************************************/ + +INLINE void ppc_set_spr(int spr, UINT32 value) +{ + switch (spr) + { + case SPR_LR: LR = value; return; + case SPR_CTR: CTR = value; return; + case SPR_XER: XER = value; return; + case SPR_SRR0: ppc.srr0 = value; return; + case SPR_SRR1: ppc.srr1 = value; return; + case SPR_SPRG0: ppc.sprg[0] = value; return; + case SPR_SPRG1: ppc.sprg[1] = value; return; + case SPR_SPRG2: ppc.sprg[2] = value; return; + case SPR_SPRG3: ppc.sprg[3] = value; return; + case SPR_PVR: return; + } + + if(IS_PPC602() || IS_PPC603()) { + switch(spr) + { + case SPR603E_DEC: + if((value & 0x80000000) && !(DEC & 0x80000000)) + { + /* trigger interrupt */ + if (IS_PPC602()) + ppc602_exception(EXCEPTION_DECREMENTER); + if (IS_PPC603()) + ppc603_exception(EXCEPTION_DECREMENTER); + } + write_decrementer(value); + return; + + case SPR603E_TBL_W: + case SPR603E_TBL_R: // special 603e case + ppc_write_timebase_l(value); + return; + + case SPR603E_TBU_R: + case SPR603E_TBU_W: // special 603e case + ppc_write_timebase_h(value); + return; + + case SPR603E_HID0: ppc.hid0 = value; return; + case SPR603E_HID1: ppc.hid1 = value; return; + case SPR603E_HID2: ppc.hid2 = value; return; + + case SPR603E_DSISR: ppc.dsisr = value; return; + case SPR603E_DAR: ppc.dar = value; return; + case SPR603E_EAR: ppc.ear = value; return; + case SPR603E_DMISS: ppc.dmiss = value; return; + case SPR603E_DCMP: ppc.dcmp = value; return; + case SPR603E_HASH1: ppc.hash1 = value; return; + case SPR603E_HASH2: ppc.hash2 = value; return; + case SPR603E_IMISS: ppc.imiss = value; return; + case SPR603E_ICMP: ppc.icmp = value; return; + case SPR603E_RPA: ppc.rpa = value; return; + + case SPR603E_IBAT0L: ppc.ibat[0].l = value; return; + case SPR603E_IBAT0U: ppc.ibat[0].u = value; return; + case SPR603E_IBAT1L: ppc.ibat[1].l = value; return; + case SPR603E_IBAT1U: ppc.ibat[1].u = value; return; + case SPR603E_IBAT2L: ppc.ibat[2].l = value; return; + case SPR603E_IBAT2U: ppc.ibat[2].u = value; return; + case SPR603E_IBAT3L: ppc.ibat[3].l = value; return; + case SPR603E_IBAT3U: ppc.ibat[3].u = value; return; + case SPR603E_DBAT0L: ppc.dbat[0].l = value; return; + case SPR603E_DBAT0U: ppc.dbat[0].u = value; return; + case SPR603E_DBAT1L: ppc.dbat[1].l = value; return; + case SPR603E_DBAT1U: ppc.dbat[1].u = value; return; + case SPR603E_DBAT2L: ppc.dbat[2].l = value; return; + case SPR603E_DBAT2U: ppc.dbat[2].u = value; return; + case SPR603E_DBAT3L: ppc.dbat[3].l = value; return; + case SPR603E_DBAT3U: ppc.dbat[3].u = value; return; + + case SPR603E_SDR1: + ppc.sdr1 = value; + return; + + case SPR603E_IABR: ppc.iabr = value; return; + } + } + + if (ppc.is602) { + switch(spr) + { + case SPR602_LT: ppc.lt = value; return; + case SPR602_IBR: ppc.ibr = value; return; + case SPR602_SEBR: ppc.sebr = value; return; + case SPR602_SER: ppc.ser = value; return; + case SPR602_SP: ppc.sp = value; return; + case SPR602_TCR: ppc.tcr = value; return; + } + } + + if (IS_PPC403()) { + switch(spr) + { + case SPR403_TBHI: ppc_write_timebase_h(value); return; + case SPR403_TBLO: ppc_write_timebase_l(value); return; + + case SPR403_TSR: + ppc.tsr &= ~value; // 1 clears, 0 does nothing + return; + + case SPR403_TCR: + switch((value >> 24) & 0x3) + { + case 0: ppc.fit_bit = 1 << 8; break; + case 1: ppc.fit_bit = 1 << 12; break; + case 2: ppc.fit_bit = 1 << 16; break; + case 3: ppc.fit_bit = 1 << 20; break; + } + switch((value >> 30) & 0x3) + { + case 0: ppc.wdt_bit = 1 << 16; break; + case 1: ppc.wdt_bit = 1 << 20; break; + case 2: ppc.wdt_bit = 1 << 24; break; + case 3: ppc.wdt_bit = 1 << 28; break; + } + ppc.fit_int_enable = (value >> 23) & 0x1; + ppc.wdt_int_enable = (value >> 27) & 0x1; + ppc.tcr = value; + + if (!ppc.fit_int_enable) + { + ppc.interrupt_pending &= ~0x4; + } + return; + + case SPR403_ESR: ppc.esr = value; return; + case SPR403_ICCR: ppc.iccr = value; return; + case SPR403_DCCR: ppc.dccr = value; return; + case SPR403_EVPR: EVPR = value & 0xffff0000; return; + case SPR403_PIT: ppc.pit = value; return; + case SPR403_SGR: ppc.sgr = value; return; + case SPR403_DBSR: ppc.dbsr = value; return; + case SPR403_DCWR: return; + case SPR403_PID: ppc.pid = value; return; + case SPR403_PBL1: ppc.pbl1 = value; return; + case SPR403_PBU1: ppc.pbu1 = value; return; + case SPR403_PBL2: ppc.pbl2 = value; return; + case SPR403_PBU2: ppc.pbu2 = value; return; + case SPR403_SRR2: ppc.srr2 = value; return; + case SPR403_SRR3: ppc.srr3 = value; return; + case SPR403_DAC1: ppc.dac1 = value; return; + case SPR403_DAC2: ppc.dac2 = value; return; + case SPR403_IAC1: ppc.iac1 = value; return; + case SPR403_IAC2: ppc.iac2 = value; return; + } + } + + fatalerror("ppc: set_spr: unknown spr %d (%03X)!\n", spr, spr); +} + +INLINE UINT32 ppc_get_spr(int spr) +{ + switch(spr) + { + case SPR_LR: return LR; + case SPR_CTR: return CTR; + case SPR_XER: return XER; + case SPR_SRR0: return ppc.srr0; + case SPR_SRR1: return ppc.srr1; + case SPR_SPRG0: return ppc.sprg[0]; + case SPR_SPRG1: return ppc.sprg[1]; + case SPR_SPRG2: return ppc.sprg[2]; + case SPR_SPRG3: return ppc.sprg[3]; + case SPR_PVR: return ppc.pvr; + } + + if (IS_PPC403()) + { + switch (spr) + { + case SPR403_TBLU: + case SPR403_TBLO: return (UINT32)(ppc_read_timebase()); + case SPR403_TBHU: + case SPR403_TBHI: return (UINT32)(ppc_read_timebase() >> 32); + + case SPR403_EVPR: return EVPR; + case SPR403_ESR: return ppc.esr; + case SPR403_TCR: return ppc.tcr; + case SPR403_ICCR: return ppc.iccr; + case SPR403_DCCR: return ppc.dccr; + case SPR403_PIT: return ppc.pit; + case SPR403_DBSR: return ppc.dbsr; + case SPR403_SGR: return ppc.sgr; + case SPR403_TSR: return ppc.tsr; + case SPR403_PBL1: return ppc.pbl1; + case SPR403_PBU1: return ppc.pbu1; + case SPR403_PBL2: return ppc.pbl2; + case SPR403_PBU2: return ppc.pbu2; + case SPR403_SRR2: return ppc.srr2; + case SPR403_SRR3: return ppc.srr3; + case SPR403_DAC1: return ppc.dac1; + case SPR403_DAC2: return ppc.dac2; + case SPR403_IAC1: return ppc.iac1; + case SPR403_IAC2: return ppc.iac2; + } + } + + if (ppc.is602) { + switch(spr) + { + case SPR602_LT: return ppc.lt; + case SPR602_IBR: return ppc.ibr; + case SPR602_ESASRR: return ppc.esasrr; + case SPR602_SEBR: return ppc.sebr; + case SPR602_SER: return ppc.ser; + case SPR602_SP: return ppc.sp; + case SPR602_TCR: return ppc.tcr; + } + } + + if (IS_PPC603() || IS_PPC602()) + { + switch (spr) + { + case SPR603E_TBL_R: + fatalerror("ppc: get_spr: TBL_R\n"); + break; + + case SPR603E_TBU_R: + fatalerror("ppc: get_spr: TBU_R\n"); + break; + + case SPR603E_TBL_W: return (UINT32)(ppc_read_timebase()); + case SPR603E_TBU_W: return (UINT32)(ppc_read_timebase() >> 32); + case SPR603E_HID0: return ppc.hid0; + case SPR603E_HID1: return ppc.hid1; + case SPR603E_HID2: return ppc.hid2; + case SPR603E_DEC: return read_decrementer(); + case SPR603E_SDR1: return ppc.sdr1; + case SPR603E_DSISR: return ppc.dsisr; + case SPR603E_DAR: return ppc.dar; + case SPR603E_EAR: return ppc.ear; + case SPR603E_DMISS: return ppc.dmiss; + case SPR603E_DCMP: return ppc.dcmp; + case SPR603E_HASH1: return ppc.hash1; + case SPR603E_HASH2: return ppc.hash2; + case SPR603E_IMISS: return ppc.imiss; + case SPR603E_ICMP: return ppc.icmp; + case SPR603E_RPA: return ppc.rpa; + case SPR603E_IBAT0L: return ppc.ibat[0].l; + case SPR603E_IBAT0U: return ppc.ibat[0].u; + case SPR603E_IBAT1L: return ppc.ibat[1].l; + case SPR603E_IBAT1U: return ppc.ibat[1].u; + case SPR603E_IBAT2L: return ppc.ibat[2].l; + case SPR603E_IBAT2U: return ppc.ibat[2].u; + case SPR603E_IBAT3L: return ppc.ibat[3].l; + case SPR603E_IBAT3U: return ppc.ibat[3].u; + case SPR603E_DBAT0L: return ppc.dbat[0].l; + case SPR603E_DBAT0U: return ppc.dbat[0].u; + case SPR603E_DBAT1L: return ppc.dbat[1].l; + case SPR603E_DBAT1U: return ppc.dbat[1].u; + case SPR603E_DBAT2L: return ppc.dbat[2].l; + case SPR603E_DBAT2U: return ppc.dbat[2].u; + case SPR603E_DBAT3L: return ppc.dbat[3].l; + case SPR603E_DBAT3U: return ppc.dbat[3].u; + } + } + + fatalerror("ppc: get_spr: unknown spr %d (%03X)!\n", spr, spr); + return 0; +} + +static UINT8 ppc_read8_translated(address_space &space, offs_t address); +static UINT16 ppc_read16_translated(address_space &space, offs_t address); +static UINT32 ppc_read32_translated(address_space &space, offs_t address); +static UINT64 ppc_read64_translated(address_space &space, offs_t address); +static void ppc_write8_translated(address_space &space, offs_t address, UINT8 data); +static void ppc_write16_translated(address_space &space, offs_t address, UINT16 data); +static void ppc_write32_translated(address_space &space, offs_t address, UINT32 data); +static void ppc_write64_translated(address_space &space, offs_t address, UINT64 data); + +INLINE void ppc_set_msr(UINT32 value) +{ + if( value & (MSR_ILE | MSR_LE) ) + fatalerror("ppc: set_msr: little_endian mode not supported!\n"); + + MSR = value; + + if (IS_PPC603() || IS_PPC602()) + { + if (!(MSR & MSR_DR)) + { + ppc.read8 = memory_read_byte_64be; + ppc.read16 = memory_read_word_64be; + ppc.read32 = memory_read_dword_64be; + ppc.read64 = memory_read_qword_64be; + ppc.write8 = memory_write_byte_64be; + ppc.write16 = memory_write_word_64be; + ppc.write32 = memory_write_dword_64be; + ppc.write64 = memory_write_qword_64be; + } + else + { + ppc.read8 = ppc_read8_translated; + ppc.read16 = ppc_read16_translated; + ppc.read32 = ppc_read32_translated; + ppc.read64 = ppc_read64_translated; + ppc.write8 = ppc_write8_translated; + ppc.write16 = ppc_write16_translated; + ppc.write32 = ppc_write32_translated; + ppc.write64 = ppc_write64_translated; + } + } +} + +INLINE UINT32 ppc_get_msr(void) +{ + return MSR; +} + +INLINE void ppc_set_cr(UINT32 value) +{ + CR(0) = (value >> 28) & 0xf; + CR(1) = (value >> 24) & 0xf; + CR(2) = (value >> 20) & 0xf; + CR(3) = (value >> 16) & 0xf; + CR(4) = (value >> 12) & 0xf; + CR(5) = (value >> 8) & 0xf; + CR(6) = (value >> 4) & 0xf; + CR(7) = (value >> 0) & 0xf; +} + +INLINE UINT32 ppc_get_cr(void) +{ + return CR(0) << 28 | CR(1) << 24 | CR(2) << 20 | CR(3) << 16 | CR(4) << 12 | CR(5) << 8 | CR(6) << 4 | CR(7); +} + +INLINE void ppc_exception(int exception_type) +{ + longjmp(ppc.exception_jmpbuf, exception_type); +} + +/***********************************************************************/ + +#include "ppc_mem.inc" + +#include "ppc403.inc" +#include "ppc602.inc" +#include "ppc603.inc" + +/********************************************************************/ + +#include "ppc_ops.inc" +#include "ppc_ops.h" + +/* Initialization and shutdown */ + +static void ppc_init(void) +{ + int i,j; + + memset(&ppc, 0, sizeof(ppc)); + + for( i=0; i < 64; i++ ) { + ppc.optable[i] = ppc_invalid; + } + for( i=0; i < 1024; i++ ) { + ppc.optable19[i] = ppc_invalid; + ppc.optable31[i] = ppc_invalid; + ppc.optable59[i] = ppc_invalid; + ppc.optable63[i] = ppc_invalid; + } + + /* Fill the opcode tables */ + for( i=0; i < (sizeof(ppc_opcode_common) / sizeof(PPC_OPCODE)); i++ ) { + switch(ppc_opcode_common[i].code) + { + case 19: + ppc.optable19[ppc_opcode_common[i].subcode] = ppc_opcode_common[i].handler; + break; + + case 31: + ppc.optable31[ppc_opcode_common[i].subcode] = ppc_opcode_common[i].handler; + break; + + case 59: + case 63: + break; + + default: + ppc.optable[ppc_opcode_common[i].code] = ppc_opcode_common[i].handler; + } + + } + + /* Calculate rotate mask table */ + for( i=0; i < 32; i++ ) { + for( j=0; j < 32; j++ ) { + UINT32 mask; + int mb = i; + int me = j; + mask = ((UINT32)0xFFFFFFFF >> mb) ^ ((me >= 31) ? 0 : ((UINT32)0xFFFFFFFF >> (me + 1))); + if( mb > me ) + mask = ~mask; + + ppc_rotate_mask[i][j] = mask; + } + } +} + + +// !!! probably should move this stuff elsewhere !!! +static CPU_INIT( ppc403 ) +{ + const ppc_config *configdata = device->static_config(); + + ppc_init(); + + /* PPC403 specific opcodes */ + ppc.optable31[454] = ppc_dccci; + ppc.optable31[486] = ppc_dcread; + ppc.optable31[262] = ppc_icbt; + ppc.optable31[966] = ppc_iccci; + ppc.optable31[998] = ppc_icread; + ppc.optable31[323] = ppc_mfdcr; + ppc.optable31[451] = ppc_mtdcr; + ppc.optable31[131] = ppc_wrtee; + ppc.optable31[163] = ppc_wrteei; + + // !!! why is rfci here !!! + ppc.optable19[51] = ppc_rfci; + + ppc.spu.rx_timer = device->machine().scheduler().timer_alloc(FUNC(ppc403_spu_rx_callback)); + ppc.spu.tx_timer = device->machine().scheduler().timer_alloc(FUNC(ppc403_spu_tx_callback)); + + ppc.read8 = ppc403_read8; + ppc.read16 = ppc403_read16; + ppc.read32 = ppc403_read32; + ppc.write8 = ppc403_write8; + ppc.write16 = ppc403_write16; + ppc.write32 = ppc403_write32; + ppc.read16_unaligned = ppc403_read16_unaligned; + ppc.read32_unaligned = ppc403_read32_unaligned; + ppc.write16_unaligned = ppc403_write16_unaligned; + ppc.write32_unaligned = ppc403_write32_unaligned; + + ppc.irq_callback = irqcallback; + ppc.device = device; + ppc.program = &device->space(AS_PROGRAM); + + ppc.pvr = configdata->pvr; +} + +static CPU_EXIT( ppc403 ) +{ +} + +static CPU_INIT( ppc405 ) +{ + const ppc_config *configdata = device->static_config(); + + ppc_init(); + + /* PPC403 specific opcodes */ + ppc.optable31[454] = ppc_dccci; + ppc.optable31[486] = ppc_dcread; + ppc.optable31[262] = ppc_icbt; + ppc.optable31[966] = ppc_iccci; + ppc.optable31[998] = ppc_icread; + ppc.optable31[323] = ppc_mfdcr; + ppc.optable31[451] = ppc_mtdcr; + ppc.optable31[131] = ppc_wrtee; + ppc.optable31[163] = ppc_wrteei; + + // !!! why is rfci here !!! + ppc.optable19[51] = ppc_rfci; + + ppc.spu.rx_timer = device->machine().scheduler().timer_alloc(FUNC(ppc403_spu_rx_callback)); + ppc.spu.tx_timer = device->machine().scheduler().timer_alloc(FUNC(ppc403_spu_tx_callback)); + + ppc.read8 = ppc403_read8; + ppc.read16 = ppc403_read16; + ppc.read32 = ppc403_read32; + ppc.write8 = ppc403_write8; + ppc.write16 = ppc403_write16; + ppc.write32 = ppc403_write32; + ppc.read16_unaligned = ppc403_read16_unaligned; + ppc.read32_unaligned = ppc403_read32_unaligned; + ppc.write16_unaligned = ppc403_write16_unaligned; + ppc.write32_unaligned = ppc403_write32_unaligned; + + ppc.irq_callback = irqcallback; + ppc.device = device; + ppc.program = &device->space(AS_PROGRAM); + + ppc.pvr = configdata->pvr; +} + +static CPU_EXIT( ppc405 ) +{ +} + +static CPU_INIT( ppc603 ) +{ + const ppc_config *configdata = device->static_config(); + int pll_config = 0; + float multiplier; + int i ; + + ppc_init() ; + + ppc.optable[48] = ppc_lfs; + ppc.optable[49] = ppc_lfsu; + ppc.optable[50] = ppc_lfd; + ppc.optable[51] = ppc_lfdu; + ppc.optable[52] = ppc_stfs; + ppc.optable[53] = ppc_stfsu; + ppc.optable[54] = ppc_stfd; + ppc.optable[55] = ppc_stfdu; + ppc.optable31[631] = ppc_lfdux; + ppc.optable31[599] = ppc_lfdx; + ppc.optable31[567] = ppc_lfsux; + ppc.optable31[535] = ppc_lfsx; + ppc.optable31[595] = ppc_mfsr; + ppc.optable31[659] = ppc_mfsrin; + ppc.optable31[371] = ppc_mftb; + ppc.optable31[210] = ppc_mtsr; + ppc.optable31[242] = ppc_mtsrin; + ppc.optable31[758] = ppc_dcba; + ppc.optable31[759] = ppc_stfdux; + ppc.optable31[727] = ppc_stfdx; + ppc.optable31[983] = ppc_stfiwx; + ppc.optable31[695] = ppc_stfsux; + ppc.optable31[663] = ppc_stfsx; + ppc.optable31[370] = ppc_tlbia; + ppc.optable31[306] = ppc_tlbie; + ppc.optable31[566] = ppc_tlbsync; + ppc.optable31[310] = ppc_eciwx; + ppc.optable31[438] = ppc_ecowx; + + ppc.optable63[264] = ppc_fabsx; + ppc.optable63[21] = ppc_faddx; + ppc.optable63[32] = ppc_fcmpo; + ppc.optable63[0] = ppc_fcmpu; + ppc.optable63[14] = ppc_fctiwx; + ppc.optable63[15] = ppc_fctiwzx; + ppc.optable63[18] = ppc_fdivx; + ppc.optable63[72] = ppc_fmrx; + ppc.optable63[136] = ppc_fnabsx; + ppc.optable63[40] = ppc_fnegx; + ppc.optable63[12] = ppc_frspx; + ppc.optable63[26] = ppc_frsqrtex; + ppc.optable63[22] = ppc_fsqrtx; + ppc.optable63[20] = ppc_fsubx; + ppc.optable63[583] = ppc_mffsx; + ppc.optable63[70] = ppc_mtfsb0x; + ppc.optable63[38] = ppc_mtfsb1x; + ppc.optable63[711] = ppc_mtfsfx; + ppc.optable63[134] = ppc_mtfsfix; + ppc.optable63[64] = ppc_mcrfs; + + ppc.optable59[21] = ppc_faddsx; + ppc.optable59[18] = ppc_fdivsx; + ppc.optable59[24] = ppc_fresx; + ppc.optable59[22] = ppc_fsqrtsx; + ppc.optable59[20] = ppc_fsubsx; + + for(i = 0; i < 32; i++) + { + ppc.optable63[i * 32 | 29] = ppc_fmaddx; + ppc.optable63[i * 32 | 28] = ppc_fmsubx; + ppc.optable63[i * 32 | 25] = ppc_fmulx; + ppc.optable63[i * 32 | 31] = ppc_fnmaddx; + ppc.optable63[i * 32 | 30] = ppc_fnmsubx; + ppc.optable63[i * 32 | 23] = ppc_fselx; + + ppc.optable59[i * 32 | 29] = ppc_fmaddsx; + ppc.optable59[i * 32 | 28] = ppc_fmsubsx; + ppc.optable59[i * 32 | 25] = ppc_fmulsx; + ppc.optable59[i * 32 | 31] = ppc_fnmaddsx; + ppc.optable59[i * 32 | 30] = ppc_fnmsubsx; + } + + ppc.optable31[978] = ppc_tlbld; + + for(i = 0; i < 256; i++) + { + ppc_field_xlat[i] = + ((i & 0x80) ? 0xF0000000 : 0) | + ((i & 0x40) ? 0x0F000000 : 0) | + ((i & 0x20) ? 0x00F00000 : 0) | + ((i & 0x10) ? 0x000F0000 : 0) | + ((i & 0x08) ? 0x0000F000 : 0) | + ((i & 0x04) ? 0x00000F00 : 0) | + ((i & 0x02) ? 0x000000F0 : 0) | + ((i & 0x01) ? 0x0000000F : 0); + } + + ppc.is603 = 1; + + ppc.read8 = memory_read_byte_64be; + ppc.read16 = memory_read_word_64be; + ppc.read32 = memory_read_dword_64be; + ppc.read64 = memory_read_qword_64be; + ppc.write8 = memory_write_byte_64be; + ppc.write16 = memory_write_word_64be; + ppc.write32 = memory_write_dword_64be; + ppc.write64 = memory_write_qword_64be; + ppc.read16_unaligned = ppc_read16_unaligned; + ppc.read32_unaligned = ppc_read32_unaligned; + ppc.read64_unaligned = ppc_read64_unaligned; + ppc.write16_unaligned = ppc_write16_unaligned; + ppc.write32_unaligned = ppc_write32_unaligned; + ppc.write64_unaligned = ppc_write64_unaligned; + + ppc.irq_callback = irqcallback; + ppc.device = device; + ppc.program = &device->space(AS_PROGRAM); + + ppc.pvr = configdata->pvr; + + multiplier = (float)((configdata->bus_frequency_multiplier >> 4) & 0xf) + + (float)(configdata->bus_frequency_multiplier & 0xf) / 10.0f; + bus_freq_multiplier = (int)(multiplier * 2); + + switch(config->pvr) + { + case PPC_MODEL_603E: pll_config = mpc603e_pll_config[bus_freq_multiplier-1][configdata->bus_frequency]; break; + case PPC_MODEL_603EV: pll_config = mpc603ev_pll_config[bus_freq_multiplier-1][configdata->bus_frequency]; break; + case PPC_MODEL_603R: pll_config = mpc603r_pll_config[bus_freq_multiplier-1][configdata->bus_frequency]; break; + default: break; + } + + if (pll_config == -1) + { + fatalerror("PPC: Invalid bus/multiplier combination (bus frequency = %d, multiplier = %1.1f)\n", config->bus_frequency, multiplier); + } + + ppc.hid1 = pll_config << 28; +} + +static CPU_EXIT( ppc603 ) +{ +} + +static CPU_INIT( ppc602 ) +{ + float multiplier; + const ppc_config *configdata = device->static_config(); + + int i ; + + ppc_init() ; + + ppc.optable[48] = ppc_lfs; + ppc.optable[49] = ppc_lfsu; + ppc.optable[50] = ppc_lfd; + ppc.optable[51] = ppc_lfdu; + ppc.optable[52] = ppc_stfs; + ppc.optable[53] = ppc_stfsu; + ppc.optable[54] = ppc_stfd; + ppc.optable[55] = ppc_stfdu; + ppc.optable31[631] = ppc_lfdux; + ppc.optable31[599] = ppc_lfdx; + ppc.optable31[567] = ppc_lfsux; + ppc.optable31[535] = ppc_lfsx; + ppc.optable31[595] = ppc_mfsr; + ppc.optable31[659] = ppc_mfsrin; + ppc.optable31[371] = ppc_mftb; + ppc.optable31[210] = ppc_mtsr; + ppc.optable31[242] = ppc_mtsrin; + ppc.optable31[758] = ppc_dcba; + ppc.optable31[759] = ppc_stfdux; + ppc.optable31[727] = ppc_stfdx; + ppc.optable31[983] = ppc_stfiwx; + ppc.optable31[695] = ppc_stfsux; + ppc.optable31[663] = ppc_stfsx; + ppc.optable31[370] = ppc_tlbia; + ppc.optable31[306] = ppc_tlbie; + ppc.optable31[566] = ppc_tlbsync; + ppc.optable31[310] = ppc_eciwx; + ppc.optable31[438] = ppc_ecowx; + + ppc.optable63[264] = ppc_fabsx; + ppc.optable63[21] = ppc_faddx; + ppc.optable63[32] = ppc_fcmpo; + ppc.optable63[0] = ppc_fcmpu; + ppc.optable63[14] = ppc_fctiwx; + ppc.optable63[15] = ppc_fctiwzx; + ppc.optable63[18] = ppc_fdivx; + ppc.optable63[72] = ppc_fmrx; + ppc.optable63[136] = ppc_fnabsx; + ppc.optable63[40] = ppc_fnegx; + ppc.optable63[12] = ppc_frspx; + ppc.optable63[26] = ppc_frsqrtex; + ppc.optable63[22] = ppc_fsqrtx; + ppc.optable63[20] = ppc_fsubx; + ppc.optable63[583] = ppc_mffsx; + ppc.optable63[70] = ppc_mtfsb0x; + ppc.optable63[38] = ppc_mtfsb1x; + ppc.optable63[711] = ppc_mtfsfx; + ppc.optable63[134] = ppc_mtfsfix; + ppc.optable63[64] = ppc_mcrfs; + + ppc.optable59[21] = ppc_faddsx; + ppc.optable59[18] = ppc_fdivsx; + ppc.optable59[24] = ppc_fresx; + ppc.optable59[22] = ppc_fsqrtsx; + ppc.optable59[20] = ppc_fsubsx; + + for(i = 0; i < 32; i++) + { + ppc.optable63[i * 32 | 29] = ppc_fmaddx; + ppc.optable63[i * 32 | 28] = ppc_fmsubx; + ppc.optable63[i * 32 | 25] = ppc_fmulx; + ppc.optable63[i * 32 | 31] = ppc_fnmaddx; + ppc.optable63[i * 32 | 30] = ppc_fnmsubx; + ppc.optable63[i * 32 | 23] = ppc_fselx; + + ppc.optable59[i * 32 | 29] = ppc_fmaddsx; + ppc.optable59[i * 32 | 28] = ppc_fmsubsx; + ppc.optable59[i * 32 | 25] = ppc_fmulsx; + ppc.optable59[i * 32 | 31] = ppc_fnmaddsx; + ppc.optable59[i * 32 | 30] = ppc_fnmsubsx; + } + + for(i = 0; i < 256; i++) + { + ppc_field_xlat[i] = + ((i & 0x80) ? 0xF0000000 : 0) | + ((i & 0x40) ? 0x0F000000 : 0) | + ((i & 0x20) ? 0x00F00000 : 0) | + ((i & 0x10) ? 0x000F0000 : 0) | + ((i & 0x08) ? 0x0000F000 : 0) | + ((i & 0x04) ? 0x00000F00 : 0) | + ((i & 0x02) ? 0x000000F0 : 0) | + ((i & 0x01) ? 0x0000000F : 0); + } + + // PPC602 specific opcodes + ppc.optable31[596] = ppc_esa; + ppc.optable31[628] = ppc_dsa; + ppc.optable31[1010] = ppc_tlbli; + ppc.optable31[978] = ppc_tlbld; + + ppc.is602 = 1; + + ppc.read8 = memory_read_byte_64be; + ppc.read16 = memory_read_word_64be; + ppc.read32 = memory_read_dword_64be; + ppc.read64 = memory_read_qword_64be; + ppc.write8 = memory_write_byte_64be; + ppc.write16 = memory_write_word_64be; + ppc.write32 = memory_write_dword_64be; + ppc.write64 = memory_write_qword_64be; + ppc.read16_unaligned = ppc_read16_unaligned; + ppc.read32_unaligned = ppc_read32_unaligned; + ppc.read64_unaligned = ppc_read64_unaligned; + ppc.write16_unaligned = ppc_write16_unaligned; + ppc.write32_unaligned = ppc_write32_unaligned; + ppc.write64_unaligned = ppc_write64_unaligned; + + ppc.irq_callback = irqcallback; + ppc.device = device; + ppc.program = &device->space(AS_PROGRAM); + + ppc.pvr = configdata->pvr; + + multiplier = (float)((configdata->bus_frequency_multiplier >> 4) & 0xf) + + (float)(configdata->bus_frequency_multiplier & 0xf) / 10.0f; + bus_freq_multiplier = (int)(multiplier * 2); +} + +static CPU_EXIT( ppc602 ) +{ +} + +static void mpc8240_tlbli(UINT32 op) +{ +} + +static void mpc8240_tlbld(UINT32 op) +{ +} + +static CPU_INIT( mpc8240 ) +{ + float multiplier; + const ppc_config *configdata = device->static_config(); + + int i ; + + ppc_init(); + + ppc.optable[48] = ppc_lfs; + ppc.optable[49] = ppc_lfsu; + ppc.optable[50] = ppc_lfd; + ppc.optable[51] = ppc_lfdu; + ppc.optable[52] = ppc_stfs; + ppc.optable[53] = ppc_stfsu; + ppc.optable[54] = ppc_stfd; + ppc.optable[55] = ppc_stfdu; + ppc.optable31[631] = ppc_lfdux; + ppc.optable31[599] = ppc_lfdx; + ppc.optable31[567] = ppc_lfsux; + ppc.optable31[535] = ppc_lfsx; + ppc.optable31[595] = ppc_mfsr; + ppc.optable31[659] = ppc_mfsrin; + ppc.optable31[371] = ppc_mftb; + ppc.optable31[210] = ppc_mtsr; + ppc.optable31[242] = ppc_mtsrin; + ppc.optable31[758] = ppc_dcba; + ppc.optable31[759] = ppc_stfdux; + ppc.optable31[727] = ppc_stfdx; + ppc.optable31[983] = ppc_stfiwx; + ppc.optable31[695] = ppc_stfsux; + ppc.optable31[663] = ppc_stfsx; + ppc.optable31[370] = ppc_tlbia; + ppc.optable31[306] = ppc_tlbie; + ppc.optable31[566] = ppc_tlbsync; + ppc.optable31[310] = ppc_eciwx; + ppc.optable31[438] = ppc_ecowx; + + ppc.optable63[264] = ppc_fabsx; + ppc.optable63[21] = ppc_faddx; + ppc.optable63[32] = ppc_fcmpo; + ppc.optable63[0] = ppc_fcmpu; + ppc.optable63[14] = ppc_fctiwx; + ppc.optable63[15] = ppc_fctiwzx; + ppc.optable63[18] = ppc_fdivx; + ppc.optable63[72] = ppc_fmrx; + ppc.optable63[136] = ppc_fnabsx; + ppc.optable63[40] = ppc_fnegx; + ppc.optable63[12] = ppc_frspx; + ppc.optable63[26] = ppc_frsqrtex; + ppc.optable63[22] = ppc_fsqrtx; + ppc.optable63[20] = ppc_fsubx; + ppc.optable63[583] = ppc_mffsx; + ppc.optable63[70] = ppc_mtfsb0x; + ppc.optable63[38] = ppc_mtfsb1x; + ppc.optable63[711] = ppc_mtfsfx; + ppc.optable63[134] = ppc_mtfsfix; + ppc.optable63[64] = ppc_mcrfs; + + ppc.optable59[21] = ppc_faddsx; + ppc.optable59[18] = ppc_fdivsx; + ppc.optable59[24] = ppc_fresx; + ppc.optable59[22] = ppc_fsqrtsx; + ppc.optable59[20] = ppc_fsubsx; + + for(i = 0; i < 32; i++) + { + ppc.optable63[i * 32 | 29] = ppc_fmaddx; + ppc.optable63[i * 32 | 28] = ppc_fmsubx; + ppc.optable63[i * 32 | 25] = ppc_fmulx; + ppc.optable63[i * 32 | 31] = ppc_fnmaddx; + ppc.optable63[i * 32 | 30] = ppc_fnmsubx; + ppc.optable63[i * 32 | 23] = ppc_fselx; + + ppc.optable59[i * 32 | 29] = ppc_fmaddsx; + ppc.optable59[i * 32 | 28] = ppc_fmsubsx; + ppc.optable59[i * 32 | 25] = ppc_fmulsx; + ppc.optable59[i * 32 | 31] = ppc_fnmaddsx; + ppc.optable59[i * 32 | 30] = ppc_fnmsubsx; + } + + for(i = 0; i < 256; i++) + { + ppc_field_xlat[i] = + ((i & 0x80) ? 0xF0000000 : 0) | + ((i & 0x40) ? 0x0F000000 : 0) | + ((i & 0x20) ? 0x00F00000 : 0) | + ((i & 0x10) ? 0x000F0000 : 0) | + ((i & 0x08) ? 0x0000F000 : 0) | + ((i & 0x04) ? 0x00000F00 : 0) | + ((i & 0x02) ? 0x000000F0 : 0) | + ((i & 0x01) ? 0x0000000F : 0); + } + + // MPC8240 specific opcodes + ppc.optable31[978] = mpc8240_tlbld; + ppc.optable31[1010] = mpc8240_tlbli; + + ppc.is603 = 1; + + ppc.read8 = memory_read_byte_64be; + ppc.read16 = memory_read_word_64be; + ppc.read32 = memory_read_dword_64be; + ppc.read64 = memory_read_qword_64be; + ppc.write8 = memory_write_byte_64be; + ppc.write16 = memory_write_word_64be; + ppc.write32 = memory_write_dword_64be; + ppc.write64 = memory_write_qword_64be; + ppc.read16_unaligned = ppc_read16_unaligned; + ppc.read32_unaligned = ppc_read32_unaligned; + ppc.read64_unaligned = ppc_read64_unaligned; + ppc.write16_unaligned = ppc_write16_unaligned; + ppc.write32_unaligned = ppc_write32_unaligned; + ppc.write64_unaligned = ppc_write64_unaligned; + + ppc.irq_callback = irqcallback; + ppc.device = device; + ppc.program = &device->space(AS_PROGRAM); + + ppc.pvr = configdata->pvr; + + multiplier = (float)((configdata->bus_frequency_multiplier >> 4) & 0xf) + + (float)(configdata->bus_frequency_multiplier & 0xf) / 10.0f; + bus_freq_multiplier = (int)(multiplier * 2); +} + +static CPU_EXIT( mpc8240 ) +{ +} + +static CPU_INIT( ppc601 ) +{ + const ppc_config *configdata = device->static_config(); + float multiplier; + int i ; + + ppc_init() ; + + ppc.optable[48] = ppc_lfs; + ppc.optable[49] = ppc_lfsu; + ppc.optable[50] = ppc_lfd; + ppc.optable[51] = ppc_lfdu; + ppc.optable[52] = ppc_stfs; + ppc.optable[53] = ppc_stfsu; + ppc.optable[54] = ppc_stfd; + ppc.optable[55] = ppc_stfdu; + ppc.optable31[631] = ppc_lfdux; + ppc.optable31[599] = ppc_lfdx; + ppc.optable31[567] = ppc_lfsux; + ppc.optable31[535] = ppc_lfsx; + ppc.optable31[595] = ppc_mfsr; + ppc.optable31[659] = ppc_mfsrin; + ppc.optable31[371] = ppc_mftb; + ppc.optable31[210] = ppc_mtsr; + ppc.optable31[242] = ppc_mtsrin; + ppc.optable31[758] = ppc_dcba; + ppc.optable31[759] = ppc_stfdux; + ppc.optable31[727] = ppc_stfdx; + ppc.optable31[983] = ppc_stfiwx; + ppc.optable31[695] = ppc_stfsux; + ppc.optable31[663] = ppc_stfsx; + ppc.optable31[370] = ppc_tlbia; + ppc.optable31[306] = ppc_tlbie; + ppc.optable31[566] = ppc_tlbsync; + ppc.optable31[310] = ppc_eciwx; + ppc.optable31[438] = ppc_ecowx; + + ppc.optable63[264] = ppc_fabsx; + ppc.optable63[21] = ppc_faddx; + ppc.optable63[32] = ppc_fcmpo; + ppc.optable63[0] = ppc_fcmpu; + ppc.optable63[14] = ppc_fctiwx; + ppc.optable63[15] = ppc_fctiwzx; + ppc.optable63[18] = ppc_fdivx; + ppc.optable63[72] = ppc_fmrx; + ppc.optable63[136] = ppc_fnabsx; + ppc.optable63[40] = ppc_fnegx; + ppc.optable63[12] = ppc_frspx; + ppc.optable63[26] = ppc_frsqrtex; + ppc.optable63[22] = ppc_fsqrtx; + ppc.optable63[20] = ppc_fsubx; + ppc.optable63[583] = ppc_mffsx; + ppc.optable63[70] = ppc_mtfsb0x; + ppc.optable63[38] = ppc_mtfsb1x; + ppc.optable63[711] = ppc_mtfsfx; + ppc.optable63[134] = ppc_mtfsfix; + ppc.optable63[64] = ppc_mcrfs; + + ppc.optable59[21] = ppc_faddsx; + ppc.optable59[18] = ppc_fdivsx; + ppc.optable59[24] = ppc_fresx; + ppc.optable59[22] = ppc_fsqrtsx; + ppc.optable59[20] = ppc_fsubsx; + + for(i = 0; i < 32; i++) + { + ppc.optable63[i * 32 | 29] = ppc_fmaddx; + ppc.optable63[i * 32 | 28] = ppc_fmsubx; + ppc.optable63[i * 32 | 25] = ppc_fmulx; + ppc.optable63[i * 32 | 31] = ppc_fnmaddx; + ppc.optable63[i * 32 | 30] = ppc_fnmsubx; + ppc.optable63[i * 32 | 23] = ppc_fselx; + + ppc.optable59[i * 32 | 29] = ppc_fmaddsx; + ppc.optable59[i * 32 | 28] = ppc_fmsubsx; + ppc.optable59[i * 32 | 25] = ppc_fmulsx; + ppc.optable59[i * 32 | 31] = ppc_fnmaddsx; + ppc.optable59[i * 32 | 30] = ppc_fnmsubsx; + } + + for(i = 0; i < 256; i++) + { + ppc_field_xlat[i] = + ((i & 0x80) ? 0xF0000000 : 0) | + ((i & 0x40) ? 0x0F000000 : 0) | + ((i & 0x20) ? 0x00F00000 : 0) | + ((i & 0x10) ? 0x000F0000 : 0) | + ((i & 0x08) ? 0x0000F000 : 0) | + ((i & 0x04) ? 0x00000F00 : 0) | + ((i & 0x02) ? 0x000000F0 : 0) | + ((i & 0x01) ? 0x0000000F : 0); + } + + ppc.is603 = 1; + + ppc.read8 = memory_read_byte_64be; + ppc.read16 = memory_read_word_64be; + ppc.read32 = memory_read_dword_64be; + ppc.read64 = memory_read_qword_64be; + ppc.write8 = memory_write_byte_64be; + ppc.write16 = memory_write_word_64be; + ppc.write32 = memory_write_dword_64be; + ppc.write64 = memory_write_qword_64be; + ppc.read16_unaligned = ppc_read16_unaligned; + ppc.read32_unaligned = ppc_read32_unaligned; + ppc.read64_unaligned = ppc_read64_unaligned; + ppc.write16_unaligned = ppc_write16_unaligned; + ppc.write32_unaligned = ppc_write32_unaligned; + ppc.write64_unaligned = ppc_write64_unaligned; + + ppc.irq_callback = irqcallback; + ppc.device = device; + ppc.program = &device->space(AS_PROGRAM); + + ppc.pvr = configdata->pvr; + + multiplier = (float)((configdata->bus_frequency_multiplier >> 4) & 0xf) + + (float)(configdata->bus_frequency_multiplier & 0xf) / 10.0f; + bus_freq_multiplier = (int)(multiplier * 2); + + ppc.hid1 = 0; +} + +static CPU_EXIT( ppc601 ) +{ +} + +static CPU_INIT( ppc604 ) +{ + const ppc_config *configdata = device->static_config(); + float multiplier; + int i ; + + ppc_init() ; + + ppc.optable[48] = ppc_lfs; + ppc.optable[49] = ppc_lfsu; + ppc.optable[50] = ppc_lfd; + ppc.optable[51] = ppc_lfdu; + ppc.optable[52] = ppc_stfs; + ppc.optable[53] = ppc_stfsu; + ppc.optable[54] = ppc_stfd; + ppc.optable[55] = ppc_stfdu; + ppc.optable31[631] = ppc_lfdux; + ppc.optable31[599] = ppc_lfdx; + ppc.optable31[567] = ppc_lfsux; + ppc.optable31[535] = ppc_lfsx; + ppc.optable31[595] = ppc_mfsr; + ppc.optable31[659] = ppc_mfsrin; + ppc.optable31[371] = ppc_mftb; + ppc.optable31[210] = ppc_mtsr; + ppc.optable31[242] = ppc_mtsrin; + ppc.optable31[758] = ppc_dcba; + ppc.optable31[759] = ppc_stfdux; + ppc.optable31[727] = ppc_stfdx; + ppc.optable31[983] = ppc_stfiwx; + ppc.optable31[695] = ppc_stfsux; + ppc.optable31[663] = ppc_stfsx; + ppc.optable31[370] = ppc_tlbia; + ppc.optable31[306] = ppc_tlbie; + ppc.optable31[566] = ppc_tlbsync; + ppc.optable31[310] = ppc_eciwx; + ppc.optable31[438] = ppc_ecowx; + + ppc.optable63[264] = ppc_fabsx; + ppc.optable63[21] = ppc_faddx; + ppc.optable63[32] = ppc_fcmpo; + ppc.optable63[0] = ppc_fcmpu; + ppc.optable63[14] = ppc_fctiwx; + ppc.optable63[15] = ppc_fctiwzx; + ppc.optable63[18] = ppc_fdivx; + ppc.optable63[72] = ppc_fmrx; + ppc.optable63[136] = ppc_fnabsx; + ppc.optable63[40] = ppc_fnegx; + ppc.optable63[12] = ppc_frspx; + ppc.optable63[26] = ppc_frsqrtex; + ppc.optable63[22] = ppc_fsqrtx; + ppc.optable63[20] = ppc_fsubx; + ppc.optable63[583] = ppc_mffsx; + ppc.optable63[70] = ppc_mtfsb0x; + ppc.optable63[38] = ppc_mtfsb1x; + ppc.optable63[711] = ppc_mtfsfx; + ppc.optable63[134] = ppc_mtfsfix; + ppc.optable63[64] = ppc_mcrfs; + + ppc.optable59[21] = ppc_faddsx; + ppc.optable59[18] = ppc_fdivsx; + ppc.optable59[24] = ppc_fresx; + ppc.optable59[22] = ppc_fsqrtsx; + ppc.optable59[20] = ppc_fsubsx; + + for(i = 0; i < 32; i++) + { + ppc.optable63[i * 32 | 29] = ppc_fmaddx; + ppc.optable63[i * 32 | 28] = ppc_fmsubx; + ppc.optable63[i * 32 | 25] = ppc_fmulx; + ppc.optable63[i * 32 | 31] = ppc_fnmaddx; + ppc.optable63[i * 32 | 30] = ppc_fnmsubx; + ppc.optable63[i * 32 | 23] = ppc_fselx; + + ppc.optable59[i * 32 | 29] = ppc_fmaddsx; + ppc.optable59[i * 32 | 28] = ppc_fmsubsx; + ppc.optable59[i * 32 | 25] = ppc_fmulsx; + ppc.optable59[i * 32 | 31] = ppc_fnmaddsx; + ppc.optable59[i * 32 | 30] = ppc_fnmsubsx; + } + + ppc.optable31[978] = ppc_tlbld; + + for(i = 0; i < 256; i++) + { + ppc_field_xlat[i] = + ((i & 0x80) ? 0xF0000000 : 0) | + ((i & 0x40) ? 0x0F000000 : 0) | + ((i & 0x20) ? 0x00F00000 : 0) | + ((i & 0x10) ? 0x000F0000 : 0) | + ((i & 0x08) ? 0x0000F000 : 0) | + ((i & 0x04) ? 0x00000F00 : 0) | + ((i & 0x02) ? 0x000000F0 : 0) | + ((i & 0x01) ? 0x0000000F : 0); + } + + ppc.is603 = 1; + + ppc.read8 = memory_read_byte_64be; + ppc.read16 = memory_read_word_64be; + ppc.read32 = memory_read_dword_64be; + ppc.read64 = memory_read_qword_64be; + ppc.write8 = memory_write_byte_64be; + ppc.write16 = memory_write_word_64be; + ppc.write32 = memory_write_dword_64be; + ppc.write64 = memory_write_qword_64be; + ppc.read16_unaligned = ppc_read16_unaligned; + ppc.read32_unaligned = ppc_read32_unaligned; + ppc.read64_unaligned = ppc_read64_unaligned; + ppc.write16_unaligned = ppc_write16_unaligned; + ppc.write32_unaligned = ppc_write32_unaligned; + ppc.write64_unaligned = ppc_write64_unaligned; + + ppc.irq_callback = irqcallback; + ppc.device = device; + ppc.program = &device->space(AS_PROGRAM); + + ppc.pvr = configdata->pvr; + + multiplier = (float)((configdata->bus_frequency_multiplier >> 4) & 0xf) + + (float)(configdata->bus_frequency_multiplier & 0xf) / 10.0f; + bus_freq_multiplier = (int)(multiplier * 2); + + ppc.hid1 = 0; +} + +static CPU_EXIT( ppc604 ) +{ +} + + + +/************************************************************************** + * Generic set_info + **************************************************************************/ + +static CPU_SET_INFO( ppc ) +{ + switch (state) + { + case CPUINFO_INT_PC: + case CPUINFO_INT_REGISTER + PPC_PC: ppc.pc = info->i; break; + case CPUINFO_INT_REGISTER + PPC_MSR: ppc_set_msr(info->i); break; + case CPUINFO_INT_REGISTER + PPC_CR: ppc_set_cr(info->i); break; + case CPUINFO_INT_REGISTER + PPC_LR: LR = info->i; break; + case CPUINFO_INT_REGISTER + PPC_CTR: CTR = info->i; break; + case CPUINFO_INT_REGISTER + PPC_XER: XER = info->i; break; + case CPUINFO_INT_REGISTER + PPC_SRR0: SRR0 = info->i; break; + case CPUINFO_INT_REGISTER + PPC_SRR1: SRR1 = info->i; break; + + case CPUINFO_INT_REGISTER + PPC_R0: ppc.r[0] = info->i; break; + case CPUINFO_INT_REGISTER + PPC_R1: ppc.r[1] = info->i; break; + case CPUINFO_INT_REGISTER + PPC_R2: ppc.r[2] = info->i; break; + case CPUINFO_INT_REGISTER + PPC_R3: ppc.r[3] = info->i; break; + case CPUINFO_INT_REGISTER + PPC_R4: ppc.r[4] = info->i; break; + case CPUINFO_INT_REGISTER + PPC_R5: ppc.r[5] = info->i; break; + case CPUINFO_INT_REGISTER + PPC_R6: ppc.r[6] = info->i; break; + case CPUINFO_INT_REGISTER + PPC_R7: ppc.r[7] = info->i; break; + case CPUINFO_INT_REGISTER + PPC_R8: ppc.r[8] = info->i; break; + case CPUINFO_INT_REGISTER + PPC_R9: ppc.r[9] = info->i; break; + case CPUINFO_INT_REGISTER + PPC_R10: ppc.r[10] = info->i; break; + case CPUINFO_INT_REGISTER + PPC_R11: ppc.r[11] = info->i; break; + case CPUINFO_INT_REGISTER + PPC_R12: ppc.r[12] = info->i; break; + case CPUINFO_INT_REGISTER + PPC_R13: ppc.r[13] = info->i; break; + case CPUINFO_INT_REGISTER + PPC_R14: ppc.r[14] = info->i; break; + case CPUINFO_INT_REGISTER + PPC_R15: ppc.r[15] = info->i; break; + case CPUINFO_INT_REGISTER + PPC_R16: ppc.r[16] = info->i; break; + case CPUINFO_INT_REGISTER + PPC_R17: ppc.r[17] = info->i; break; + case CPUINFO_INT_REGISTER + PPC_R18: ppc.r[18] = info->i; break; + case CPUINFO_INT_REGISTER + PPC_R19: ppc.r[19] = info->i; break; + case CPUINFO_INT_REGISTER + PPC_R20: ppc.r[20] = info->i; break; + case CPUINFO_INT_REGISTER + PPC_R21: ppc.r[21] = info->i; break; + case CPUINFO_INT_REGISTER + PPC_R22: ppc.r[22] = info->i; break; + case CPUINFO_INT_REGISTER + PPC_R23: ppc.r[23] = info->i; break; + case CPUINFO_INT_REGISTER + PPC_R24: ppc.r[24] = info->i; break; + case CPUINFO_INT_REGISTER + PPC_R25: ppc.r[25] = info->i; break; + case CPUINFO_INT_REGISTER + PPC_R26: ppc.r[26] = info->i; break; + case CPUINFO_INT_REGISTER + PPC_R27: ppc.r[27] = info->i; break; + case CPUINFO_INT_REGISTER + PPC_R28: ppc.r[28] = info->i; break; + case CPUINFO_INT_REGISTER + PPC_R29: ppc.r[29] = info->i; break; + case CPUINFO_INT_REGISTER + PPC_R30: ppc.r[30] = info->i; break; + case CPUINFO_INT_REGISTER + PPC_R31: ppc.r[31] = info->i; break; + } +} + +static CPU_SET_INFO( ppc403 ) +{ + if (state >= CPUINFO_INT_INPUT_STATE && state <= CPUINFO_INT_INPUT_STATE + 8) + { + ppc403_set_irq_line(state-CPUINFO_INT_INPUT_STATE, info->i); + return; + } + switch(state) + { + case CPUINFO_INT_REGISTER + PPC_EXIER: EXIER = info->i; break; + case CPUINFO_INT_REGISTER + PPC_EXISR: EXISR = info->i; break; + default: ppc_set_info(state, info); break; + } +} + +static CPU_SET_INFO( ppc603 ) +{ + if (state >= CPUINFO_INT_INPUT_STATE && state <= CPUINFO_INT_INPUT_STATE + 5) + { + ppc603_set_irq_line(state-CPUINFO_INT_INPUT_STATE, info->i); + return; + } + switch(state) + { + case CPUINFO_INT_REGISTER + PPC_DEC: write_decrementer(info->i); break; + case CPUINFO_INT_INPUT_STATE + PPC_INPUT_LINE_SMI: ppc603_set_smi_line(info->i); break; + default: ppc_set_info(state, info); break; + } +} + +static CPU_GET_INFO( ppc ) +{ + switch(state) + { + /* --- the following bits of info are returned as 64-bit signed integers --- */ + case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(ppc); break; + case CPUINFO_INT_INPUT_LINES: info->i = 1; break; + case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0; break; + case CPUINFO_INT_ENDIANNESS: info->i = ENDIANNESS_BIG; break; + case CPUINFO_INT_CLOCK_MULTIPLIER: info->i = 1; break; + case CPUINFO_INT_CLOCK_DIVIDER: info->i = 1; break; + case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 4; break; + case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 4; break; + case CPUINFO_INT_MIN_CYCLES: info->i = 1; break; + case CPUINFO_INT_MAX_CYCLES: info->i = 40; break; + + case CPUINFO_INT_DATABUS_WIDTH + AS_PROGRAM: info->i = 32; break; + case CPUINFO_INT_ADDRBUS_WIDTH + AS_PROGRAM: info->i = 32; break; + case CPUINFO_INT_ADDRBUS_SHIFT + AS_PROGRAM: info->i = 0; break; + case CPUINFO_INT_DATABUS_WIDTH + AS_DATA: info->i = 0; break; + case CPUINFO_INT_ADDRBUS_WIDTH + AS_DATA: info->i = 0; break; + case CPUINFO_INT_ADDRBUS_SHIFT + AS_DATA: info->i = 0; break; + case CPUINFO_INT_DATABUS_WIDTH + AS_IO: info->i = 0; break; + case CPUINFO_INT_ADDRBUS_WIDTH + AS_IO: info->i = 0; break; + case CPUINFO_INT_ADDRBUS_SHIFT + AS_IO: info->i = 0; break; + + case CPUINFO_INT_INPUT_STATE: info->i = CLEAR_LINE; break; + + case CPUINFO_INT_PREVIOUSPC: /* not implemented */ break; + + case CPUINFO_INT_PC: /* intentional fallthrough */ + case CPUINFO_INT_REGISTER + PPC_PC: info->i = ppc.pc; break; + case CPUINFO_INT_REGISTER + PPC_MSR: info->i = ppc_get_msr(); break; + case CPUINFO_INT_REGISTER + PPC_CR: info->i = ppc_get_cr(); break; + case CPUINFO_INT_REGISTER + PPC_LR: info->i = LR; break; + case CPUINFO_INT_REGISTER + PPC_CTR: info->i = CTR; break; + case CPUINFO_INT_REGISTER + PPC_XER: info->i = XER; break; + case CPUINFO_INT_REGISTER + PPC_SRR0: info->i = SRR0; break; + case CPUINFO_INT_REGISTER + PPC_SRR1: info->i = SRR1; break; + + case CPUINFO_INT_REGISTER + PPC_R0: info->i = ppc.r[0]; break; + case CPUINFO_INT_REGISTER + PPC_R1: info->i = ppc.r[1]; break; + case CPUINFO_INT_REGISTER + PPC_R2: info->i = ppc.r[2]; break; + case CPUINFO_INT_REGISTER + PPC_R3: info->i = ppc.r[3]; break; + case CPUINFO_INT_REGISTER + PPC_R4: info->i = ppc.r[4]; break; + case CPUINFO_INT_REGISTER + PPC_R5: info->i = ppc.r[5]; break; + case CPUINFO_INT_REGISTER + PPC_R6: info->i = ppc.r[6]; break; + case CPUINFO_INT_REGISTER + PPC_R7: info->i = ppc.r[7]; break; + case CPUINFO_INT_REGISTER + PPC_R8: info->i = ppc.r[8]; break; + case CPUINFO_INT_REGISTER + PPC_R9: info->i = ppc.r[9]; break; + case CPUINFO_INT_REGISTER + PPC_R10: info->i = ppc.r[10]; break; + case CPUINFO_INT_REGISTER + PPC_R11: info->i = ppc.r[11]; break; + case CPUINFO_INT_REGISTER + PPC_R12: info->i = ppc.r[12]; break; + case CPUINFO_INT_REGISTER + PPC_R13: info->i = ppc.r[13]; break; + case CPUINFO_INT_REGISTER + PPC_R14: info->i = ppc.r[14]; break; + case CPUINFO_INT_REGISTER + PPC_R15: info->i = ppc.r[15]; break; + case CPUINFO_INT_REGISTER + PPC_R16: info->i = ppc.r[16]; break; + case CPUINFO_INT_REGISTER + PPC_R17: info->i = ppc.r[17]; break; + case CPUINFO_INT_REGISTER + PPC_R18: info->i = ppc.r[18]; break; + case CPUINFO_INT_REGISTER + PPC_R19: info->i = ppc.r[19]; break; + case CPUINFO_INT_REGISTER + PPC_R20: info->i = ppc.r[20]; break; + case CPUINFO_INT_REGISTER + PPC_R21: info->i = ppc.r[21]; break; + case CPUINFO_INT_REGISTER + PPC_R22: info->i = ppc.r[22]; break; + case CPUINFO_INT_REGISTER + PPC_R23: info->i = ppc.r[23]; break; + case CPUINFO_INT_REGISTER + PPC_R24: info->i = ppc.r[24]; break; + case CPUINFO_INT_REGISTER + PPC_R25: info->i = ppc.r[25]; break; + case CPUINFO_INT_REGISTER + PPC_R26: info->i = ppc.r[26]; break; + case CPUINFO_INT_REGISTER + PPC_R27: info->i = ppc.r[27]; break; + case CPUINFO_INT_REGISTER + PPC_R28: info->i = ppc.r[28]; break; + case CPUINFO_INT_REGISTER + PPC_R29: info->i = ppc.r[29]; break; + case CPUINFO_INT_REGISTER + PPC_R30: info->i = ppc.r[30]; break; + case CPUINFO_INT_REGISTER + PPC_R31: info->i = ppc.r[31]; break; + + + + /* --- the following bits of info are returned as pointers to data or functions --- */ + case CPUINFO_FCT_BURN: info->burn = NULL; break; + case CPUINFO_FCT_DISASSEMBLE: info->disassemble = CPU_DISASSEMBLE_NAME(ppc); break; + case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &ppc_icount; break; + + /* --- the following bits of info are returned as NULL-terminated strings --- */ + case CPUINFO_STR_NAME: strcpy(info->s, "PPC403"); break; + case CPUINFO_STR_SHORTNAME: strcpy(info->s, "ppc403"); break; + case CPUINFO_STR_FAMILY: strcpy(info->s, "PowerPC"); break; + case CPUINFO_STR_VERSION: strcpy(info->s, "1.0"); break; + case CPUINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break; + case CPUINFO_STR_CREDITS: strcpy(info->s, "Copyright Nicola Salmoria and the MAME Team"); break; + + case CPUINFO_STR_FLAGS: strcpy(info->s, " "); break; + + case CPUINFO_STR_REGISTER + PPC_PC: sprintf(info->s, "PC: %08X", ppc.pc); break; + case CPUINFO_STR_REGISTER + PPC_MSR: sprintf(info->s, "MSR: %08X", ppc_get_msr()); break; + case CPUINFO_STR_REGISTER + PPC_CR: sprintf(info->s, "CR: %08X", ppc_get_cr()); break; + case CPUINFO_STR_REGISTER + PPC_LR: sprintf(info->s, "LR: %08X", LR); break; + case CPUINFO_STR_REGISTER + PPC_CTR: sprintf(info->s, "CTR: %08X", CTR); break; + case CPUINFO_STR_REGISTER + PPC_XER: sprintf(info->s, "XER: %08X", XER); break; + case CPUINFO_STR_REGISTER + PPC_SRR0: sprintf(info->s, "SRR0: %08X", SRR0); break; + case CPUINFO_STR_REGISTER + PPC_SRR1: sprintf(info->s, "SRR1: %08X", SRR1); break; + + case CPUINFO_STR_REGISTER + PPC_R0: sprintf(info->s, "R0: %08X", ppc.r[0]); break; + case CPUINFO_STR_REGISTER + PPC_R1: sprintf(info->s, "R1: %08X", ppc.r[1]); break; + case CPUINFO_STR_REGISTER + PPC_R2: sprintf(info->s, "R2: %08X", ppc.r[2]); break; + case CPUINFO_STR_REGISTER + PPC_R3: sprintf(info->s, "R3: %08X", ppc.r[3]); break; + case CPUINFO_STR_REGISTER + PPC_R4: sprintf(info->s, "R4: %08X", ppc.r[4]); break; + case CPUINFO_STR_REGISTER + PPC_R5: sprintf(info->s, "R5: %08X", ppc.r[5]); break; + case CPUINFO_STR_REGISTER + PPC_R6: sprintf(info->s, "R6: %08X", ppc.r[6]); break; + case CPUINFO_STR_REGISTER + PPC_R7: sprintf(info->s, "R7: %08X", ppc.r[7]); break; + case CPUINFO_STR_REGISTER + PPC_R8: sprintf(info->s, "R8: %08X", ppc.r[8]); break; + case CPUINFO_STR_REGISTER + PPC_R9: sprintf(info->s, "R9: %08X", ppc.r[9]); break; + case CPUINFO_STR_REGISTER + PPC_R10: sprintf(info->s, "R10: %08X", ppc.r[10]); break; + case CPUINFO_STR_REGISTER + PPC_R11: sprintf(info->s, "R11: %08X", ppc.r[11]); break; + case CPUINFO_STR_REGISTER + PPC_R12: sprintf(info->s, "R12: %08X", ppc.r[12]); break; + case CPUINFO_STR_REGISTER + PPC_R13: sprintf(info->s, "R13: %08X", ppc.r[13]); break; + case CPUINFO_STR_REGISTER + PPC_R14: sprintf(info->s, "R14: %08X", ppc.r[14]); break; + case CPUINFO_STR_REGISTER + PPC_R15: sprintf(info->s, "R15: %08X", ppc.r[15]); break; + case CPUINFO_STR_REGISTER + PPC_R16: sprintf(info->s, "R16: %08X", ppc.r[16]); break; + case CPUINFO_STR_REGISTER + PPC_R17: sprintf(info->s, "R17: %08X", ppc.r[17]); break; + case CPUINFO_STR_REGISTER + PPC_R18: sprintf(info->s, "R18: %08X", ppc.r[18]); break; + case CPUINFO_STR_REGISTER + PPC_R19: sprintf(info->s, "R19: %08X", ppc.r[19]); break; + case CPUINFO_STR_REGISTER + PPC_R20: sprintf(info->s, "R20: %08X", ppc.r[20]); break; + case CPUINFO_STR_REGISTER + PPC_R21: sprintf(info->s, "R21: %08X", ppc.r[21]); break; + case CPUINFO_STR_REGISTER + PPC_R22: sprintf(info->s, "R22: %08X", ppc.r[22]); break; + case CPUINFO_STR_REGISTER + PPC_R23: sprintf(info->s, "R23: %08X", ppc.r[23]); break; + case CPUINFO_STR_REGISTER + PPC_R24: sprintf(info->s, "R24: %08X", ppc.r[24]); break; + case CPUINFO_STR_REGISTER + PPC_R25: sprintf(info->s, "R25: %08X", ppc.r[25]); break; + case CPUINFO_STR_REGISTER + PPC_R26: sprintf(info->s, "R26: %08X", ppc.r[26]); break; + case CPUINFO_STR_REGISTER + PPC_R27: sprintf(info->s, "R27: %08X", ppc.r[27]); break; + case CPUINFO_STR_REGISTER + PPC_R28: sprintf(info->s, "R28: %08X", ppc.r[28]); break; + case CPUINFO_STR_REGISTER + PPC_R29: sprintf(info->s, "R29: %08X", ppc.r[29]); break; + case CPUINFO_STR_REGISTER + PPC_R30: sprintf(info->s, "R30: %08X", ppc.r[30]); break; + case CPUINFO_STR_REGISTER + PPC_R31: sprintf(info->s, "R31: %08X", ppc.r[31]); break; + } +} + +CPU_GET_INFO( ppc403 ) +{ + switch(state) + { + /* --- the following bits of info are returned as 64-bit signed integers --- */ + case CPUINFO_INT_INPUT_LINES: info->i = 8; break; + case CPUINFO_INT_ENDIANNESS: info->i = ENDIANNESS_BIG; break; + case CPUINFO_INT_REGISTER + PPC_EXIER: info->i = EXIER; break; + case CPUINFO_INT_REGISTER + PPC_EXISR: info->i = EXISR; break; + + /* --- the following bits of info are returned as pointers to data or functions --- */ + case CPUINFO_FCT_SET_INFO: info->setinfo = CPU_SET_INFO_NAME(ppc403); break; + case CPUINFO_FCT_INIT: info->init = CPU_INIT_NAME(ppc403); break; + case CPUINFO_FCT_RESET: info->reset = CPU_RESET_NAME(ppc403); break; + case CPUINFO_FCT_EXIT: info->exit = CPU_EXIT_NAME(ppc403); break; + case CPUINFO_FCT_EXECUTE: info->execute = CPU_EXECUTE_NAME(ppc403); break; + + /* --- the following bits of info are returned as NULL-terminated strings --- */ + case CPUINFO_STR_NAME: strcpy(info->s, "PPC403"); break; + case CPUINFO_STR_SHORTNAME: strcpy(info->s, "ppc403"); break; + case CPUINFO_STR_REGISTER + PPC_EXIER: sprintf(info->s, "EXIER: %08X", EXIER); break; + case CPUINFO_STR_REGISTER + PPC_EXISR: sprintf(info->s, "EXISR: %08X", EXISR); break; + + default: CPU_GET_INFO_CALL(ppc); break; + } +} + +CPU_GET_INFO( ppc405 ) +{ + switch(state) + { + /* --- the following bits of info are returned as 64-bit signed integers --- */ + case CPUINFO_INT_INPUT_LINES: info->i = 8; break; + case CPUINFO_INT_ENDIANNESS: info->i = ENDIANNESS_BIG; break; + case CPUINFO_INT_REGISTER + PPC_EXIER: info->i = EXIER; break; + case CPUINFO_INT_REGISTER + PPC_EXISR: info->i = EXISR; break; + + /* --- the following bits of info are returned as pointers to data or functions --- */ + case CPUINFO_FCT_SET_INFO: info->setinfo = CPU_SET_INFO_NAME(ppc405); break; + case CPUINFO_FCT_INIT: info->init = CPU_INIT_NAME(ppc405); break; + case CPUINFO_FCT_RESET: info->reset = CPU_RESET_NAME(ppc405); break; + case CPUINFO_FCT_EXIT: info->exit = CPU_EXIT_NAME(ppc405); break; + case CPUINFO_FCT_EXECUTE: info->execute = CPU_EXECUTE_NAME(ppc405); break; + + /* --- the following bits of info are returned as NULL-terminated strings --- */ + case CPUINFO_STR_NAME: strcpy(info->s, "PPC405"); break; + case CPUINFO_STR_SHORTNAME: strcpy(info->s, "ppc405"); break; + case CPUINFO_STR_REGISTER + PPC_EXIER: sprintf(info->s, "EXIER: %08X", EXIER); break; + case CPUINFO_STR_REGISTER + PPC_EXISR: sprintf(info->s, "EXISR: %08X", EXISR); break; + + default: CPU_GET_INFO_CALL(ppc); break; + } +} + +CPU_GET_INFO( ppc603 ) +{ + switch(state) + { + /* --- the following bits of info are returned as 64-bit signed integers --- */ + case CPUINFO_INT_INPUT_LINES: info->i = 5; break; + case CPUINFO_INT_ENDIANNESS: info->i = ENDIANNESS_BIG; break; + + case CPUINFO_INT_DATABUS_WIDTH + AS_PROGRAM: info->i = 64; break; + case CPUINFO_INT_ADDRBUS_WIDTH + AS_PROGRAM: info->i = 32; break; + case CPUINFO_INT_LOGADDR_WIDTH_PROGRAM: info->i = 32; break; + case CPUINFO_INT_PAGE_SHIFT_PROGRAM: info->i = 17; break; + case CPUINFO_INT_REGISTER + PPC_DEC: info->i = read_decrementer(); break; + + /* --- the following bits of info are returned as pointers to data or functions --- */ + case CPUINFO_FCT_SET_INFO: info->setinfo = CPU_SET_INFO_NAME(ppc603); break; + case CPUINFO_FCT_INIT: info->init = CPU_INIT_NAME(ppc603); break; + case CPUINFO_FCT_RESET: info->reset = CPU_RESET_NAME(ppc603); break; + case CPUINFO_FCT_EXIT: info->exit = CPU_EXIT_NAME(ppc603); break; + case CPUINFO_FCT_EXECUTE: info->execute = CPU_EXECUTE_NAME(ppc603); break; + case CPUINFO_FCT_READ: info->read = CPU_GET_READ_NAME(ppc); break; + case CPUINFO_FCT_WRITE: info->write = CPU_GET_WRITE_NAME(ppc); break; + case CPUINFO_FCT_READOP: info->readop = CPU_GET_READOP_NAME(ppc); break; + case CPUINFO_FCT_TRANSLATE: info->translate = ppc_translate_address_cb; break; + + /* --- the following bits of info are returned as NULL-terminated strings --- */ + case CPUINFO_STR_NAME: strcpy(info->s, "PPC603"); break; + case CPUINFO_STR_SHORTNAME: strcpy(info->s, "ppc603"); break; + case CPUINFO_STR_REGISTER + PPC_DEC: sprintf(info->s, "DEC: %08X", read_decrementer()); break; + + default: CPU_GET_INFO_CALL(ppc); break; + } +} + +static CPU_SET_INFO( ppc602 ) +{ + if (state >= CPUINFO_INT_INPUT_STATE && state <= CPUINFO_INT_INPUT_STATE + 5) + { + ppc602_set_irq_line(state-CPUINFO_INT_INPUT_STATE, info->i); + return; + } + switch(state) + { + case CPUINFO_INT_INPUT_STATE + PPC_INPUT_LINE_SMI: ppc602_set_smi_line(info->i); break; + default: ppc_set_info(state, info); break; + } +} + +CPU_GET_INFO( ppc602 ) +{ + switch(state) + { + /* --- the following bits of info are returned as 64-bit signed integers --- */ + case CPUINFO_INT_INPUT_LINES: info->i = 5; break; + case CPUINFO_INT_ENDIANNESS: info->i = ENDIANNESS_BIG; break; + case CPUINFO_INT_REGISTER + PPC_IBR: info->i = ppc.ibr; break; + + case CPUINFO_INT_DATABUS_WIDTH + AS_PROGRAM: info->i = 64; break; + case CPUINFO_INT_ADDRBUS_WIDTH + AS_PROGRAM: info->i = 32; break; + + /* --- the following bits of info are returned as pointers to data or functions --- */ + case CPUINFO_FCT_SET_INFO: info->setinfo = CPU_SET_INFO_NAME(ppc602); break; + case CPUINFO_FCT_INIT: info->init = CPU_INIT_NAME(ppc602); break; + case CPUINFO_FCT_RESET: info->reset = CPU_RESET_NAME(ppc602); break; + case CPUINFO_FCT_EXIT: info->exit = CPU_EXIT_NAME(ppc602); break; + case CPUINFO_FCT_EXECUTE: info->execute = CPU_EXECUTE_NAME(ppc602); break; + case CPUINFO_FCT_READ: info->read = CPU_GET_READ_NAME(ppc); break; + case CPUINFO_FCT_WRITE: info->write = CPU_GET_WRITE_NAME(ppc); break; + case CPUINFO_FCT_READOP: info->readop = CPU_GET_READOP_NAME(ppc); break; + case CPUINFO_FCT_TRANSLATE: info->translate = ppc_translate_address_cb; break; + + /* --- the following bits of info are returned as NULL-terminated strings --- */ + case CPUINFO_STR_NAME: strcpy(info->s, "PPC602"); break; + case CPUINFO_STR_SHORTNAME: strcpy(info->s, "ppc602"); break; + case CPUINFO_STR_REGISTER + PPC_IBR: sprintf(info->s, "IBR: %08X", ppc.ibr); break; + + default: CPU_GET_INFO_CALL(ppc); break; + } +} + + +static CPU_SET_INFO( mpc8240 ) +{ + if (state >= CPUINFO_INT_INPUT_STATE && state <= CPUINFO_INT_INPUT_STATE + 5) + { + ppc603_set_irq_line(state-CPUINFO_INT_INPUT_STATE, info->i); + return; + } + switch(state) + { + default: ppc_set_info(state, info); break; + } +} + +CPU_GET_INFO( mpc8240 ) +{ + switch(state) + { + /* --- the following bits of info are returned as 64-bit signed integers --- */ + case CPUINFO_INT_INPUT_LINES: info->i = 5; break; + case CPUINFO_INT_ENDIANNESS: info->i = ENDIANNESS_BIG; break; + + case CPUINFO_INT_DATABUS_WIDTH + AS_PROGRAM: info->i = 64; break; + case CPUINFO_INT_ADDRBUS_WIDTH + AS_PROGRAM: info->i = 32; break; + + /* --- the following bits of info are returned as pointers to data or functions --- */ + case CPUINFO_FCT_SET_INFO: info->setinfo = CPU_SET_INFO_NAME(mpc8240); break; + case CPUINFO_FCT_INIT: info->init = CPU_INIT_NAME(mpc8240); break; + case CPUINFO_FCT_RESET: info->reset = CPU_RESET_NAME(ppc603); break; + case CPUINFO_FCT_EXIT: info->exit = CPU_EXIT_NAME(mpc8240); break; + case CPUINFO_FCT_EXECUTE: info->execute = CPU_EXECUTE_NAME(ppc603); break; + case CPUINFO_FCT_READ: info->read = CPU_GET_READ_NAME(ppc); break; + case CPUINFO_FCT_WRITE: info->write = CPU_GET_WRITE_NAME(ppc); break; + case CPUINFO_FCT_READOP: info->readop = CPU_GET_READOP_NAME(ppc); break; + + /* --- the following bits of info are returned as NULL-terminated strings --- */ + case CPUINFO_STR_NAME: strcpy(info->s, "MPC8240"); break; + case CPUINFO_STR_SHORTNAME: strcpy(info->s, "mpc8240"); break; + + default: CPU_GET_INFO_CALL(ppc); break; + } +} + +static CPU_SET_INFO( ppc601 ) +{ + if (state >= CPUINFO_INT_INPUT_STATE && state <= CPUINFO_INT_INPUT_STATE + 5) + { + ppc603_set_irq_line(state-CPUINFO_INT_INPUT_STATE, info->i); + return; + } + switch(state) + { + default: ppc_set_info(state, info); break; + } +} + +CPU_GET_INFO( ppc601 ) +{ + switch(state) + { + /* --- the following bits of info are returned as 64-bit signed integers --- */ + case CPUINFO_INT_INPUT_LINES: info->i = 5; break; + case CPUINFO_INT_ENDIANNESS: info->i = ENDIANNESS_BIG; break; + + case CPUINFO_INT_DATABUS_WIDTH + AS_PROGRAM: info->i = 64; break; + case CPUINFO_INT_ADDRBUS_WIDTH + AS_PROGRAM: info->i = 32; break; + + /* --- the following bits of info are returned as pointers to data or functions --- */ + case CPUINFO_FCT_SET_INFO: info->setinfo = CPU_SET_INFO_NAME(ppc601); break; + case CPUINFO_FCT_INIT: info->init = CPU_INIT_NAME(ppc601); break; + case CPUINFO_FCT_RESET: info->reset = CPU_RESET_NAME(ppc603); break; + case CPUINFO_FCT_EXIT: info->exit = CPU_EXIT_NAME(ppc601); break; + case CPUINFO_FCT_EXECUTE: info->execute = CPU_EXECUTE_NAME(ppc603); break; + case CPUINFO_FCT_READ: info->read = CPU_GET_READ_NAME(ppc); break; + case CPUINFO_FCT_WRITE: info->write = CPU_GET_WRITE_NAME(ppc); break; + case CPUINFO_FCT_READOP: info->readop = CPU_GET_READOP_NAME(ppc); break; + + /* --- the following bits of info are returned as NULL-terminated strings --- */ + case CPUINFO_STR_NAME: strcpy(info->s, "PPC601"); break; + case CPUINFO_STR_SHORTNAME: strcpy(info->s, "ppc601"); break; + + default: CPU_GET_INFO_CALL(ppc); break; + } +} + +static CPU_SET_INFO( ppc604 ) +{ + if (state >= CPUINFO_INT_INPUT_STATE && state <= CPUINFO_INT_INPUT_STATE + 5) + { + ppc603_set_irq_line(state-CPUINFO_INT_INPUT_STATE, info->i); + return; + } + switch(state) + { + default: ppc_set_info(state, info); break; + } +} + +CPU_GET_INFO( ppc604 ) +{ + switch(state) + { + /* --- the following bits of info are returned as 64-bit signed integers --- */ + case CPUINFO_INT_INPUT_LINES: info->i = 5; break; + case CPUINFO_INT_ENDIANNESS: info->i = ENDIANNESS_BIG; break; + + case CPUINFO_INT_DATABUS_WIDTH + AS_PROGRAM: info->i = 64; break; + case CPUINFO_INT_ADDRBUS_WIDTH + AS_PROGRAM: info->i = 32; break; + + /* --- the following bits of info are returned as pointers to data or functions --- */ + case CPUINFO_FCT_SET_INFO: info->setinfo = CPU_SET_INFO_NAME(ppc604); break; + case CPUINFO_FCT_INIT: info->init = CPU_INIT_NAME(ppc604); break; + case CPUINFO_FCT_RESET: info->reset = CPU_RESET_NAME(ppc603); break; + case CPUINFO_FCT_EXIT: info->exit = CPU_EXIT_NAME(ppc604); break; + case CPUINFO_FCT_EXECUTE: info->execute = CPU_EXECUTE_NAME(ppc603); break; + case CPUINFO_FCT_READ: info->read = CPU_GET_READ_NAME(ppc); break; + case CPUINFO_FCT_WRITE: info->write = CPU_GET_WRITE_NAME(ppc); break; + case CPUINFO_FCT_READOP: info->readop = CPU_GET_READOP_NAME(ppc); break; + + /* --- the following bits of info are returned as NULL-terminated strings --- */ + case CPUINFO_STR_NAME: strcpy(info->s, "PPC604"); break; + case CPUINFO_STR_SHORTNAME: strcpy(info->s, "ppc604"); break; + + default: CPU_GET_INFO_CALL(ppc); break; + } +} + +ppc403ga_device::ppc403ga_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, UINT32 clock) + : ppc4xx_device(mconfig, type, tag, owner, clock, CPU_GET_INFO_NAME(ppc403ga)) +{ +} + +const device_type PPC403GA = &legacy_device_creator; + +ppc403gcx_device::ppc403gcx_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, UINT32 clock) + : ppc4xx_device(mconfig, type, tag, owner, clock, CPU_GET_INFO_NAME(ppc403gcx)) +{ +} + +const device_type PPC403GCX = &legacy_device_creator; + +ppc405gp_device::ppc405gp_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, UINT32 clock) + : ppc4xx_device(mconfig, type, tag, owner, clock, CPU_GET_INFO_NAME(ppc405gp)) +{ +} + +const device_type PPC405GP = &legacy_device_creator; + +ppc4xx_device::ppc4xx_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, UINT32 clock, cpu_get_info_func info) + : legacy_cpu_device(mconfig, type, tag, owner, clock, info) +{ +} + +DEFINE_LEGACY_CPU_DEVICE(PPC601, ppc601); +DEFINE_LEGACY_CPU_DEVICE(PPC602, ppc602); +DEFINE_LEGACY_CPU_DEVICE(PPC603, ppc603); +DEFINE_LEGACY_CPU_DEVICE(PPC603E, ppc603e); +DEFINE_LEGACY_CPU_DEVICE(PPC603R, ppc603r); +DEFINE_LEGACY_CPU_DEVICE(PPC604, ppc604); +DEFINE_LEGACY_CPU_DEVICE(MPC8240, mpc8240); diff --git a/src/devices/cpu/powerpc/ppc.h b/src/devices/cpu/powerpc/ppc.h new file mode 100644 index 00000000000..73bcb0b470b --- /dev/null +++ b/src/devices/cpu/powerpc/ppc.h @@ -0,0 +1,811 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + ppc.h + + Interface file for the universal machine language-based + PowerPC emulator. + +***************************************************************************/ + +#pragma once + +#ifndef __PPC_H__ +#define __PPC_H__ + +#ifdef PPC_H_INCLUDED_FROM_PPC_C +#include +#endif +#include "cpu/vtlb.h" +#include "cpu/drcfe.h" +#include "cpu/drcuml.h" +#include "cpu/drcumlsh.h" + + +/*************************************************************************** + CONSTANTS +***************************************************************************/ + +/* general constants */ +#define PPC_MAX_FASTRAM 4 +#define PPC_MAX_HOTSPOTS 16 + + +/* interrupt types */ +#define PPC_IRQ 0 /* external IRQ */ +#define PPC_IRQ_LINE_0 0 /* (4XX) external IRQ0 */ +#define PPC_IRQ_LINE_1 1 /* (4XX) external IRQ1 */ +#define PPC_IRQ_LINE_2 2 /* (4XX) external IRQ2 */ +#define PPC_IRQ_LINE_3 3 /* (4XX) external IRQ3 */ +#define PPC_IRQ_LINE_4 4 /* (4XX) external IRQ4 */ + + +/* register enumeration */ +enum +{ + PPC_PC = 1, + PPC_R0, + PPC_R1, + PPC_R2, + PPC_R3, + PPC_R4, + PPC_R5, + PPC_R6, + PPC_R7, + PPC_R8, + PPC_R9, + PPC_R10, + PPC_R11, + PPC_R12, + PPC_R13, + PPC_R14, + PPC_R15, + PPC_R16, + PPC_R17, + PPC_R18, + PPC_R19, + PPC_R20, + PPC_R21, + PPC_R22, + PPC_R23, + PPC_R24, + PPC_R25, + PPC_R26, + PPC_R27, + PPC_R28, + PPC_R29, + PPC_R30, + PPC_R31, + PPC_CR, + PPC_LR, + PPC_CTR, + PPC_XER, + + PPC_F0, + PPC_F1, + PPC_F2, + PPC_F3, + PPC_F4, + PPC_F5, + PPC_F6, + PPC_F7, + PPC_F8, + PPC_F9, + PPC_F10, + PPC_F11, + PPC_F12, + PPC_F13, + PPC_F14, + PPC_F15, + PPC_F16, + PPC_F17, + PPC_F18, + PPC_F19, + PPC_F20, + PPC_F21, + PPC_F22, + PPC_F23, + PPC_F24, + PPC_F25, + PPC_F26, + PPC_F27, + PPC_F28, + PPC_F29, + PPC_F30, + PPC_F31, + PPC_FPSCR, + + PPC_MSR, + PPC_SRR0, + PPC_SRR1, + PPC_SPRG0, + PPC_SPRG1, + PPC_SPRG2, + PPC_SPRG3, + PPC_SDR1, + PPC_EXIER, + PPC_EXISR, + PPC_EVPR, + PPC_IOCR, + PPC_TBL, + PPC_TBH, + PPC_DEC, + + PPC_SR0, + PPC_SR1, + PPC_SR2, + PPC_SR3, + PPC_SR4, + PPC_SR5, + PPC_SR6, + PPC_SR7, + PPC_SR8, + PPC_SR9, + PPC_SR10, + PPC_SR11, + PPC_SR12, + PPC_SR13, + PPC_SR14, + PPC_SR15 +}; + + +/* compiler-specific options */ +#define PPCDRC_STRICT_VERIFY 0x0001 /* verify all instructions */ +#define PPCDRC_FLUSH_PC 0x0002 /* flush the PC value before each memory access */ +#define PPCDRC_ACCURATE_SINGLES 0x0004 /* do excessive rounding to make single-precision results "accurate" */ + + +/* common sets of options */ +#define PPCDRC_COMPATIBLE_OPTIONS (PPCDRC_STRICT_VERIFY | PPCDRC_FLUSH_PC | PPCDRC_ACCURATE_SINGLES) +#define PPCDRC_FASTEST_OPTIONS (0) + + + +/*************************************************************************** + PUBLIC FUNCTIONS +***************************************************************************/ + +#define MCFG_PPC_BUS_FREQUENCY(_frequency) \ + ppc_device::set_bus_frequency(*device, _frequency); + + +class ppc_frontend; + + +class ppc_device : public cpu_device +{ + friend class ppc_frontend; + +protected: + /* PowerPC flavors */ + enum powerpc_flavor + { + PPC_MODEL_403GA = 0x00200000, + PPC_MODEL_403GB = 0x00200100, + PPC_MODEL_403GC = 0x00200200, + PPC_MODEL_403GCX = 0x00201400, + PPC_MODEL_405GP = 0x40110000, + PPC_MODEL_601 = 0x00010000, + PPC_MODEL_603 = 0x00030000, /* "Wart" */ + PPC_MODEL_604 = 0x00040000, /* "Zephyr" */ + PPC_MODEL_602 = 0x00050200, /* "Galahad" */ + PPC_MODEL_603E = 0x00060103, /* "Stretch", version 1.3 */ + PPC_MODEL_603EV = 0x00070000, /* "Valiant" */ + PPC_MODEL_603R = 0x00071202, /* "Goldeneye", version 2.1 */ + PPC_MODEL_740 = 0x00080301, /* "Arthur", version 3.1 */ + PPC_MODEL_750 = PPC_MODEL_740, + PPC_MODEL_740P = 0x00080202, /* "Conan Doyle", version 1.2 */ + PPC_MODEL_750P = PPC_MODEL_740P, + PPC_MODEL_755 = 0x00083203, /* "Goldfinger", version 2.3 */ + PPC_MODEL_7400 = 0x000c0209, /* "Max", version 2.9 */ + PPC_MODEL_7410 = 0x800c1104, /* "Nitro", version 3.4 */ + PPC_MODEL_7450 = 0x80000201, /* "Vger", version 2.1 */ + PPC_MODEL_7451 = 0x80000203, /* "Vger", version 2.3 */ + PPC_MODEL_7441 = PPC_MODEL_7451, + PPC_MODEL_7455 = 0x80010303, /* "Apollo 6", version 3.3 */ + PPC_MODEL_7445 = PPC_MODEL_7455, + PPC_MODEL_7457 = 0x80020101, /* "Apollo 7", version 1.1 */ + PPC_MODEL_MPC8240 = 0x00810101, /* "Kahlua" */ + PPC_MODEL_MPC8241 = 0x80811014, /* "Kahlua Lt" */ + PPC_MODEL_MPC8245 = 0x80811014 /* "Kahlua II" */ + }; + +public: + // construction/destruction + ppc_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, int address_bits, int data_bits, powerpc_flavor flavor, UINT32 cap, UINT32 tb_divisor, address_map_constructor internal_map); + + static void set_bus_frequency(device_t &device, UINT32 bus_frequency) { downcast(device).c_bus_frequency = bus_frequency; } + + void ppc_set_dcstore_callback(write32_delegate callback); + + void ppcdrc_set_options(UINT32 options); + void ppcdrc_add_fastram(offs_t start, offs_t end, UINT8 readonly, void *base); + void ppcdrc_add_hotspot(offs_t pc, UINT32 opcode, UINT32 cycles); + + TIMER_CALLBACK_MEMBER(decrementer_int_callback); + TIMER_CALLBACK_MEMBER(ppc4xx_buffered_dma_callback); + TIMER_CALLBACK_MEMBER(ppc4xx_fit_callback); + TIMER_CALLBACK_MEMBER(ppc4xx_pit_callback); + TIMER_CALLBACK_MEMBER(ppc4xx_spu_callback); + + void ppc_cfunc_printf_exception(); + void ppc_cfunc_printf_debug(); + void ppc_cfunc_printf_probe(); + void ppc_cfunc_unimplemented(); + void ppccom_tlb_fill(); + void ppccom_update_fprf(); + void ppccom_dcstore_callback(); + void ppccom_execute_tlbie(); + void ppccom_execute_tlbia(); + void ppccom_execute_tlbl(); + void ppccom_execute_mfspr(); + void ppccom_execute_mftb(); + void ppccom_execute_mtspr(); + void ppccom_tlb_flush(); + void ppccom_execute_mfdcr(); + void ppccom_execute_mtdcr(); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_stop(); + + // device_execute_interface overrides + virtual UINT32 execute_min_cycles() const { return 1; } + virtual UINT32 execute_max_cycles() const { return 40; } + virtual UINT32 execute_input_lines() const { return 1; } + virtual void execute_run(); + virtual void execute_set_input(int inputnum, int state); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const { return (spacenum == AS_PROGRAM) ? &m_program_config : NULL; } + virtual bool memory_translate(address_spacenum spacenum, int intention, offs_t &address); + + // device_state_interface overrides + virtual void state_export(const device_state_entry &entry); + virtual void state_import(const device_state_entry &entry); + virtual void state_string_export(const device_state_entry &entry, std::string &str); + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const { return 4; } + virtual UINT32 disasm_max_opcode_bytes() const { return 4; } + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + + /* exception types */ + enum + { + EXCEPTION_RESET = 1, + EXCEPTION_MACHCHECK = 2, + EXCEPTION_DSI = 3, /* PPCCAP_OEA */ + EXCEPTION_PROTECTION = 3, /* PPCCAP_4XX */ + EXCEPTION_ISI = 4, + EXCEPTION_EI = 5, + EXCEPTION_ALIGN = 6, + EXCEPTION_PROGRAM = 7, + EXCEPTION_NOFPU = 8, + EXCEPTION_DECREMENT = 9, + EXCEPTION_SYSCALL = 12, + EXCEPTION_TRACE = 13, + EXCEPTION_FPASSIST = 14, + EXCEPTION_ITLBMISS = 16, /* PPCCAP_603_MMU */ + EXCEPTION_DTLBMISSL = 17, /* PPCCAP_603_MMU */ + EXCEPTION_DTLBMISSS = 18, /* PPCCAP_603_MMU */ + EXCEPTION_COUNT + }; + + address_space_config m_program_config; + address_space *m_program; + UINT32 c_bus_frequency; + + struct internal_ppc_state + { + UINT32 pc; + UINT32 r[32]; + double f[32]; + UINT32 cr[8]; + UINT32 fpscr; + UINT32 msr; + UINT32 xerso; + UINT32 sr[16]; + UINT32 spr[1024]; + int icount; + UINT32 mode; /* current global mode */ + UINT32 irq_pending; + /* parameters for calls */ + UINT32 param0; + UINT32 param1; + /* PowerPC 603-specific state */ + UINT32 mmu603_cmp; + UINT32 mmu603_hash[2]; + UINT32 mmu603_r[4]; + /* parameters for subroutines */ + UINT32 tempaddr; /* temporary address storage */ + drcuml_ireg tempdata; /* temporary data storage */ + UINT32 updateaddr; /* update address storage */ + UINT32 swcount; /* counter for sw instructions */ + const char * format; /* format string for printing */ + UINT32 arg0; /* print_debug argument 1 */ + double fp0; /* floating point 0 */ + }; + + internal_ppc_state *m_core; + + int m_ppc_tb_base_icount; + int m_ppc_dec_base_icount; + int m_ppc_dec_trigger_cycle; + int m_bus_freq_multiplier; + + UINT32 m_npc; + UINT32 m_dcr[256]; + + UINT32 m_lr; + UINT32 m_ctr; + UINT32 m_xer; + UINT32 m_pvr; + UINT32 m_srr0; + UINT32 m_srr1; + UINT32 m_srr2; + UINT32 m_srr3; + UINT32 m_hid0; + UINT32 m_hid1; + UINT32 m_hid2; + UINT32 m_sdr1; + UINT32 m_sprg[4]; + + UINT32 m_dsisr; + UINT32 m_dar; + UINT32 m_ear; + UINT32 m_dmiss; + UINT32 m_dcmp; + UINT32 m_hash1; + UINT32 m_hash2; + UINT32 m_imiss; + UINT32 m_icmp; + UINT32 m_rpa; + + struct BATENT { + UINT32 u; + UINT32 l; + }; + + BATENT m_ibat[4]; + BATENT m_dbat[4]; + + UINT32 m_evpr; + UINT32 m_exier; + UINT32 m_exisr; + UINT32 m_bear; + UINT32 m_besr; + UINT32 m_iocr; + UINT32 m_br[8]; + UINT32 m_iabr; + UINT32 m_esr; + UINT32 m_iccr; + UINT32 m_dccr; + UINT32 m_pit; + UINT32 m_pit_counter; + UINT32 m_pit_int_enable; + UINT32 m_tsr; + UINT32 m_dbsr; + UINT32 m_sgr; + UINT32 m_pid; + UINT32 m_pbl1; + UINT32 m_pbl2; + UINT32 m_pbu1; + UINT32 m_pbu2; + UINT32 m_fit_bit; + UINT32 m_fit_int_enable; + UINT32 m_wdt_bit; + UINT32 m_wdt_int_enable; + UINT32 m_dac1; + UINT32 m_dac2; + UINT32 m_iac1; + UINT32 m_iac2; + + struct SPU_REGS { + UINT8 spls; + UINT8 sphs; + UINT16 brd; + UINT8 spctl; + UINT8 sprc; + UINT8 sptc; + UINT8 sprb; + UINT8 sptb; + emu_timer *rx_timer; + emu_timer *tx_timer; + }; + + SPU_REGS m_spu_old; + + struct DMA_REGS { + UINT32 cr; + UINT32 da; + UINT32 sa; + UINT32 ct; + UINT32 cc; + }; + + DMA_REGS m_dma[4]; + UINT32 m_dmasr; + + int m_reserved; + UINT32 m_reserved_address; + + int m_interrupt_pending; + + UINT64 m_tb; /* 56-bit timebase register */ + + // STUFF added for the 6xx series + UINT32 m_dec, m_dec_frac; + + union FPR { + UINT64 id; + double fd; + }; + + union FPR32 { + UINT32 i; + float f; + }; + + FPR m_fpr[32]; + + int m_is603; + int m_is602; + + /* PowerPC 602 specific registers */ + UINT32 m_lt; + UINT32 m_sp; + UINT32 m_tcr; + UINT32 m_ibr; + UINT32 m_esasrr; + UINT32 m_sebr; + UINT32 m_ser; + + /* MMU */ + vtlb_state *m_vtlb; + + /* architectural distinctions */ + powerpc_flavor m_flavor; + UINT32 m_cap; + UINT8 m_cache_line_size; + UINT32 m_tb_divisor; + + /* PowerPC 4xx-specific state */ + /* PowerPC 4XX-specific serial port state */ + struct ppc4xx_spu_state + { + UINT8 regs[9]; + UINT8 txbuf; + UINT8 rxbuf; + emu_timer * timer; + UINT8 rxbuffer[256]; + UINT32 rxin, rxout; + write8_delegate tx_cb; + }; + + ppc4xx_spu_state m_spu; + emu_timer * m_fit_timer; + emu_timer * m_pit_timer; + emu_timer * m_wdog_timer; + UINT32 m_pit_reload; + UINT32 m_irqstate; + emu_timer * m_buffered_dma_timer[4]; + int m_buffered_dma_rate[4]; + + /* internal stuff */ + direct_read_data *m_direct; + offs_t m_codexor; + UINT32 m_system_clock; + UINT32 m_cpu_clock; + UINT64 m_tb_zero_cycles; + UINT64 m_dec_zero_cycles; + emu_timer * m_decrementer_int_timer; + + read32_delegate m_dcr_read_func; + write32_delegate m_dcr_write_func; + + write32_delegate m_dcstore_cb; + + read32_delegate m_ext_dma_read_cb[4]; + write32_delegate m_ext_dma_write_cb[4]; + + /* PowerPC function pointers for memory accesses/exceptions */ +#ifdef PPC_H_INCLUDED_FROM_PPC_C + jmp_buf m_exception_jmpbuf; +#endif + UINT8 (*m_ppcread8)(address_space &space, offs_t address); + UINT16 (*m_ppcread16)(address_space &space, offs_t address); + UINT32 (*m_ppcread32)(address_space &space, offs_t address); + UINT64 (*m_ppcread64)(address_space &space, offs_t address); + void (*m_ppcwrite8)(address_space &space, offs_t address, UINT8 data); + void (*m_ppcwrite16)(address_space &space, offs_t address, UINT16 data); + void (*m_ppcwrite32)(address_space &space, offs_t address, UINT32 data); + void (*m_ppcwrite64)(address_space &space, offs_t address, UINT64 data); + UINT16 (*m_ppcread16_unaligned)(address_space &space, offs_t address); + UINT32 (*m_ppcread32_unaligned)(address_space &space, offs_t address); + UINT64 (*m_ppcread64_unaligned)(address_space &space, offs_t address); + void (*m_ppcwrite16_unaligned)(address_space &space, offs_t address, UINT16 data); + void (*m_ppcwrite32_unaligned)(address_space &space, offs_t address, UINT32 data); + void (*m_ppcwrite64_unaligned)(address_space &space, offs_t address, UINT64 data); + + void (*m_optable19[1024])(UINT32); + void (*m_optable31[1024])(UINT32); + void (*m_optable59[1024])(UINT32); + void (*m_optable63[1024])(UINT32); + void (*m_optable[64])(UINT32); + + /* core state */ + drc_cache m_cache; /* pointer to the DRC code cache */ + drcuml_state * m_drcuml; /* DRC UML generator state */ + ppc_frontend * m_drcfe; /* pointer to the DRC front-end state */ + UINT32 m_drcoptions; /* configurable DRC options */ + + /* parameters for subroutines */ + UINT32 m_arg1; /* print_debug argument 2 */ + + /* tables */ + UINT8 m_fpmode[4]; /* FPU mode table */ + UINT8 m_sz_cr_table[32]; /* SZ CR table */ + UINT8 m_cmp_cr_table[32]; /* CMP CR table */ + UINT8 m_cmpl_cr_table[32]; /* CMPL CR table */ + UINT8 m_fcmp_cr_table[32]; /* FCMP CR table */ + + /* internal stuff */ + UINT8 m_cache_dirty; /* true if we need to flush the cache */ + + /* register mappings */ + uml::parameter m_regmap[32]; /* parameter to register mappings for all 32 integer registers */ + uml::parameter m_fdregmap[32]; /* parameter to register mappings for all 32 floating point registers */ + + /* subroutines */ + uml::code_handle * m_entry; /* entry point */ + uml::code_handle * m_nocode; /* nocode exception handler */ + uml::code_handle * m_out_of_cycles; /* out of cycles exception handler */ + uml::code_handle * m_tlb_mismatch; /* tlb mismatch handler */ + uml::code_handle * m_swap_tgpr; /* swap TGPR handler */ + uml::code_handle * m_lsw[8][32]; /* lsw entries */ + uml::code_handle * m_stsw[8][32]; /* stsw entries */ + uml::code_handle * m_read8[8]; /* read byte */ + uml::code_handle * m_write8[8]; /* write byte */ + uml::code_handle * m_read16[8]; /* read half */ + uml::code_handle * m_read16mask[8]; /* read half */ + uml::code_handle * m_write16[8]; /* write half */ + uml::code_handle * m_write16mask[8]; /* write half */ + uml::code_handle * m_read32[8]; /* read word */ + uml::code_handle * m_read32align[8]; /* read word aligned */ + uml::code_handle * m_read32mask[8]; /* read word */ + uml::code_handle * m_write32[8]; /* write word */ + uml::code_handle * m_write32align[8]; /* write word aligned */ + uml::code_handle * m_write32mask[8]; /* write word */ + uml::code_handle * m_read64[8]; /* read double */ + uml::code_handle * m_read64mask[8]; /* read double */ + uml::code_handle * m_write64[8]; /* write double */ + uml::code_handle * m_write64mask[8]; /* write double */ + uml::code_handle * m_exception[EXCEPTION_COUNT]; /* array of exception handlers */ + uml::code_handle * m_exception_norecover[EXCEPTION_COUNT]; /* array of exception handlers */ + + /* fast RAM */ + /* fast RAM info */ + struct fast_ram_info + { + offs_t start; /* start of the RAM block */ + offs_t end; /* end of the RAM block */ + UINT8 readonly; /* TRUE if read-only */ + void * base; /* base in memory where the RAM lives */ + }; + + UINT32 m_fastram_select; + fast_ram_info m_fastram[PPC_MAX_FASTRAM]; + + /* hotspots */ + /* hotspot info */ + struct hotspot_info + { + offs_t pc; /* PC to consider */ + UINT32 opcode; /* required opcode at that PC */ + UINT32 cycles; /* number of cycles to eat when hit */ + }; + UINT32 m_hotspot_select; + hotspot_info m_hotspot[PPC_MAX_HOTSPOTS]; + + UINT64 m_debugger_temp; + + /* internal compiler state */ + struct compiler_state + { + UINT32 cycles; /* accumulated cycles */ + UINT8 checkints; /* need to check interrupts before next instruction */ + UINT8 checksoftints; /* need to check software interrupts before next instruction */ + uml::code_label labelnum; /* index for local labels */ + }; + + int IS_PPC602(void); + int IS_PPC603(void); + int IS_PPC403(void); + UINT32 get_cr(); + void set_cr(UINT32 value); + UINT32 get_xer(); + void set_xer(UINT32 value); + UINT64 get_timebase(); + void set_timebase(UINT64 newtb); + UINT32 get_decrementer(); + void set_decrementer(UINT32 newdec); + UINT32 ppccom_translate_address_internal(int intention, offs_t &address); + void ppc4xx_set_irq_line(UINT32 bitmask, int state); + int ppc4xx_get_irq_line(UINT32 bitmask); + void ppc4xx_dma_update_irq_states(); + int ppc4xx_dma_decrement_count(int dmachan); + int ppc4xx_dma_fetch_transmit_byte(int dmachan, UINT8 *byte); + int ppc4xx_dma_handle_receive_byte(int dmachan, UINT8 byte); + void ppc4xx_dma_exec(int dmachan); + void ppc4xx_spu_update_irq_states(); + void ppc4xx_spu_rx_data(UINT8 data); + void ppc4xx_spu_timer_reset(); + void alloc_handle(drcuml_state *drcuml, uml::code_handle **handleptr, const char *name); + void load_fast_iregs(drcuml_block *block); + void save_fast_iregs(drcuml_block *block); + UINT32 compute_rlw_mask(UINT8 mb, UINT8 me); + UINT32 compute_crf_mask(UINT8 crm); + UINT32 compute_spr(UINT32 spr); + void code_flush_cache(); + void code_compile_block(UINT8 mode, offs_t pc); + void static_generate_entry_point(); + void static_generate_nocode_handler(); + void static_generate_out_of_cycles(); + void static_generate_tlb_mismatch(); + void static_generate_exception(UINT8 exception, int recover, const char *name); + void static_generate_memory_accessor(int mode, int size, int iswrite, int ismasked, const char *name, uml::code_handle *&handleptr, uml::code_handle *masked); + void static_generate_swap_tgpr(); + void static_generate_lsw_entries(int mode); + void static_generate_stsw_entries(int mode); + void generate_update_mode(drcuml_block *block); + void generate_update_cycles(drcuml_block *block, compiler_state *compiler, uml::parameter param, int allow_exception); + void generate_checksum_block(drcuml_block *block, compiler_state *compiler, const opcode_desc *seqhead, const opcode_desc *seqlast); + void generate_sequence_instruction(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); + void generate_compute_flags(drcuml_block *block, const opcode_desc *desc, int updatecr, UINT32 xermask, int invertcarry); + void generate_shift_flags(drcuml_block *block, const opcode_desc *desc, UINT32 op); + void generate_fp_flags(drcuml_block *block, const opcode_desc *desc, int updatefprf); + void generate_branch(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, int source, UINT8 link); + void generate_branch_bo(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, UINT32 bo, UINT32 bi, int source, int link); + int generate_opcode(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); + int generate_instruction_13(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); + int generate_instruction_1f(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); + int generate_instruction_3b(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); + int generate_instruction_3f(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); + void log_add_disasm_comment(drcuml_block *block, UINT32 pc, UINT32 op); + const char *log_desc_flags_to_string(UINT32 flags); + void log_register_list(drcuml_state *drcuml, const char *string, const UINT32 *reglist, const UINT32 *regnostarlist); + void log_opcode_desc(drcuml_state *drcuml, const opcode_desc *desclist, int indent); + +}; + + +//class ppc403_device : public ppc_device +//{ +//public: +// ppc403_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +// +//protected: +// virtual UINT32 execute_input_lines() const { return 8; } +//}; +// +// +//class ppc405_device : public ppc_device +//{ +//public: +// ppc405_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +// +//protected: +// virtual UINT32 execute_input_lines() const { return 8; } +//}; + + +class ppc603_device : public ppc_device +{ +public: + ppc603_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +class ppc603e_device : public ppc_device +{ +public: + ppc603e_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +class ppc603r_device : public ppc_device +{ +public: + ppc603r_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +class ppc602_device : public ppc_device +{ +public: + ppc602_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +class mpc8240_device : public ppc_device +{ +public: + mpc8240_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +class ppc601_device : public ppc_device +{ +public: + ppc601_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +class ppc604_device : public ppc_device +{ +public: + ppc604_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +class ppc4xx_device : public ppc_device +{ +public: + ppc4xx_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, powerpc_flavor flavor, UINT32 cap, UINT32 tb_divisor); + + void ppc4xx_spu_set_tx_handler(write8_delegate callback); + void ppc4xx_spu_receive_byte(UINT8 byteval); + + void ppc4xx_set_dma_read_handler(int channel, read32_delegate callback, int rate); + void ppc4xx_set_dma_write_handler(int channel, write32_delegate callback, int rate); + void ppc4xx_set_dcr_read_handler(read32_delegate dcr_read_func); + void ppc4xx_set_dcr_write_handler(write32_delegate dcr_write_func); + + DECLARE_READ8_MEMBER( ppc4xx_spu_r ); + DECLARE_WRITE8_MEMBER( ppc4xx_spu_w ); + +protected: + virtual UINT32 execute_input_lines() const { return 5; } + virtual void execute_set_input(int inputnum, int state); +}; + + +class ppc403ga_device : public ppc4xx_device +{ +public: + ppc403ga_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +class ppc403gcx_device : public ppc4xx_device +{ +public: + ppc403gcx_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +class ppc405gp_device : public ppc4xx_device +{ +public: + ppc405gp_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +extern const device_type PPC601; +extern const device_type PPC602; +extern const device_type PPC603; +extern const device_type PPC603E; +extern const device_type PPC603R; +extern const device_type PPC604; +extern const device_type MPC8240; +extern const device_type PPC403GA; +extern const device_type PPC403GCX; +extern const device_type PPC405GP; + + +#endif /* __PPC_H__ */ diff --git a/src/devices/cpu/powerpc/ppc403.inc b/src/devices/cpu/powerpc/ppc403.inc new file mode 100644 index 00000000000..054c2657142 --- /dev/null +++ b/src/devices/cpu/powerpc/ppc403.inc @@ -0,0 +1,947 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/* PowerPC 403 specific functions */ + +static void ppc403_dma_exec(int ch); + +#define DMA_CE 0x80000000 +#define DMA_CIE 0x40000000 +#define DMA_TD 0x20000000 +#define DMA_PL 0x10000000 +#define DMA_DAI 0x02000000 +#define DMA_SAI 0x01000000 +#define DMA_CP 0x00800000 +#define DMA_ETD 0x00000200 +#define DMA_TCE 0x00000100 +#define DMA_CH 0x00000080 +#define DMA_BME 0x00000040 +#define DMA_ECE 0x00000020 +#define DMA_TCD 0x00000010 +#define DMA_PCE 0x00000008 + +static SPU_RX_HANDLER spu_rx_handler; +static SPU_TX_HANDLER spu_tx_handler; +static TIMER_CALLBACK( ppc403_spu_rx_callback ); +static TIMER_CALLBACK( ppc403_spu_tx_callback ); + +static PPC_DMA_HANDLER spu_rx_dma_handler; +static PPC_DMA_HANDLER spu_tx_dma_handler; +static UINT8 *spu_rx_dma_ptr; +static UINT8 *spu_tx_dma_ptr; + +static PPC_DMA_HANDLER dma_read_handler[4]; +static PPC_DMA_HANDLER dma_write_handler[4]; +static UINT8 *dma_read_ptr[4]; +static UINT8 *dma_write_ptr[4]; + +INLINE void ppc_set_dcr(int dcr, UINT32 value) +{ + switch(dcr) + { + case DCR_BEAR: ppc.bear = value; break; + case DCR_BESR: ppc.besr = value; break; + case DCR_BR0: ppc.br[0] = value; break; + case DCR_BR1: ppc.br[1] = value; break; + case DCR_BR2: ppc.br[2] = value; break; + case DCR_BR3: ppc.br[3] = value; break; + case DCR_BR4: ppc.br[4] = value; break; + case DCR_BR5: ppc.br[5] = value; break; + case DCR_BR6: ppc.br[6] = value; break; + case DCR_BR7: ppc.br[7] = value; break; + + case DCR_EXISR: ppc.exisr &= ~value; break; + case DCR_EXIER: EXIER = value; ppc.exisr &= EXIER; break; + case DCR_IOCR: ppc.iocr = value; break; + case DCR_DMASR: break; /* TODO */ + case DCR_DMADA0: ppc.dma[0].da = value; break; + case DCR_DMADA1: ppc.dma[1].da = value; break; + case DCR_DMADA2: ppc.dma[2].da = value; break; + case DCR_DMADA3: ppc.dma[3].da = value; break; + case DCR_DMASA0: ppc.dma[0].sa = value; break; + case DCR_DMASA1: ppc.dma[1].sa = value; break; + case DCR_DMASA2: ppc.dma[2].sa = value; break; + case DCR_DMASA3: ppc.dma[3].sa = value; break; + case DCR_DMACT0: ppc.dma[0].ct = value; break; + case DCR_DMACT1: ppc.dma[1].ct = value; break; + case DCR_DMACT2: ppc.dma[2].ct = value; break; + case DCR_DMACT3: ppc.dma[3].ct = value; break; + case DCR_DMACR0: ppc.dma[0].cr = value; ppc403_dma_exec(0); break; + case DCR_DMACR1: ppc.dma[1].cr = value; ppc403_dma_exec(1); break; + case DCR_DMACR2: ppc.dma[2].cr = value; ppc403_dma_exec(2); break; + case DCR_DMACR3: ppc.dma[3].cr = value; ppc403_dma_exec(3); break; + + default: + fatalerror("ppc: set_dcr: Unimplemented DCR %X\n", dcr); + break; + } +} + +INLINE UINT32 ppc_get_dcr(int dcr) +{ + switch(dcr) + { + case DCR_BEAR: return ppc.bear; + case DCR_BESR: return ppc.besr; + case DCR_BR0: return ppc.br[0]; + case DCR_BR1: return ppc.br[1]; + case DCR_BR2: return ppc.br[2]; + case DCR_BR3: return ppc.br[3]; + case DCR_BR4: return ppc.br[4]; + case DCR_BR5: return ppc.br[5]; + case DCR_BR6: return ppc.br[6]; + case DCR_BR7: return ppc.br[7]; + case DCR_EXISR: return EXISR; + case DCR_EXIER: return EXIER; + case DCR_IOCR: return ppc.iocr; + case DCR_DMASR: return ppc.dmasr; + case DCR_DMADA0: return ppc.dma[0].da; + case DCR_DMADA1: return ppc.dma[1].da; + case DCR_DMADA2: return ppc.dma[2].da; + case DCR_DMADA3: return ppc.dma[3].da; + case DCR_DMASA0: return ppc.dma[0].sa; + case DCR_DMASA1: return ppc.dma[1].sa; + case DCR_DMASA2: return ppc.dma[2].sa; + case DCR_DMASA3: return ppc.dma[3].sa; + case DCR_DMACT0: return ppc.dma[0].ct; + case DCR_DMACT1: return ppc.dma[1].ct; + case DCR_DMACT2: return ppc.dma[2].ct; + case DCR_DMACT3: return ppc.dma[3].ct; + case DCR_DMACR0: return ppc.dma[0].cr; + case DCR_DMACR1: return ppc.dma[1].cr; + case DCR_DMACR2: return ppc.dma[2].cr; + case DCR_DMACR3: return ppc.dma[3].cr; + + default: + fatalerror("ppc: get_dcr: Unimplemented DCR %X\n", dcr); + break; + } +} + + + +#ifndef PPC_DRC +INLINE void ppc403_check_interrupts(void) +{ + if (MSR & MSR_EE) + { + if (ppc.interrupt_pending != 0) + { + if (ppc.interrupt_pending & 0x1) + { + ppc403_exception(EXCEPTION_IRQ); + } + else if (ppc.interrupt_pending & 0x2) + { + ppc403_exception(EXCEPTION_PROGRAMMABLE_INTERVAL_TIMER); + } + else if (ppc.interrupt_pending & 0x4) + { + ppc403_exception(EXCEPTION_FIXED_INTERVAL_TIMER); + } + } + } +} + +static CPU_RESET( ppc403 ) +{ + ppc.pc = ppc.npc = 0xfffffffc; + + ppc_set_msr(0); +} + +static CPU_EXECUTE( ppc403 ) +{ + UINT32 fit_trigger_cycle; + ppc_tb_base_icount = cycles; + + fit_trigger_cycle = 0x7fffffff; + + if (ppc.fit_int_enable) + { + UINT32 tb = (UINT32)ppc.tb; + UINT32 fit_cycles = 0; + + if (ppc.tb & ppc.fit_bit) + { + fit_cycles += ppc.fit_bit; + tb += fit_cycles; + } + + fit_cycles += ppc.fit_bit - (tb & (ppc.fit_bit-1)); + + fit_trigger_cycle = ppc_icount - fit_cycles; + } + + while( ppc_icount > 0 ) + { + UINT32 opcode; + + debugger_instruction_hook(device, ppc.pc); + ppc.pc = ppc.npc; + ppc.npc += 4; + opcode = ROPCODE(ppc.pc); + + switch(opcode >> 26) + { + case 19: ppc.optable19[(opcode >> 1) & 0x3ff](opcode); break; + case 31: ppc.optable31[(opcode >> 1) & 0x3ff](opcode); break; + case 59: ppc.optable59[(opcode >> 1) & 0x3ff](opcode); break; + case 63: ppc.optable63[(opcode >> 1) & 0x3ff](opcode); break; + default: ppc.optable[opcode >> 26](opcode); break; + } + + ppc_icount--; + + /* Programmable Interval Timer (PIT) */ + if (ppc.pit_counter > 0) + { + ppc.pit_counter--; + if (ppc.pit_counter == 0) + { + if (ppc.pit_int_enable) { + ppc.interrupt_pending |= 0x2; + } + if (ppc.tcr & 0x00400000) // Automatic reload + { + ppc.pit_counter = ppc.pit; + } + } + } + + /* Fixed Interval Timer */ + if (fit_trigger_cycle != 0x7fffffff) + { + if (ppc_icount == fit_trigger_cycle) + { + if (ppc.fit_int_enable) + { + fit_trigger_cycle -= ppc.fit_bit; + ppc.interrupt_pending |= 0x4; + } + } + } + +#if 0 + /* Watchdog Timer */ + if (((UINT32)(ppc.tb) & ppc.wdt_bit) && (tblo & ppc.wdt_bit) == 0) { + switch((ppc.tsr >> 28) & 0x3) + { + case 0: ppc.tsr |= TSR_ENW; break; + case 1: ppc.tsr |= TSR_ENW; break; + case 2: + if (ppc.wdt_int_enable && (ppc.msr & MSR_CE)) { + ppc403_exception(EXCEPTION_WATCHDOG_TIMER); + } + break; + case 3: + fatalerror("PPC: Watchdog Timer caused reset\n"); + break; + } + } +#endif + + ppc403_check_interrupts(); + } + + // update timebase + ppc.tb += (ppc_tb_base_icount - ppc_icount); +} + +void ppc403_exception(int exception) +{ + switch( exception ) + { + case EXCEPTION_IRQ: /* External Interrupt */ + { + if( ppc_get_msr() & MSR_EE ) { + UINT32 msr = ppc_get_msr(); + + SRR0 = ppc.npc; + SRR1 = msr; + + msr &= ~(MSR_WE | MSR_PR | MSR_EE | MSR_PE); // Clear WE, PR, EE, PR + if( msr & MSR_LE ) + msr |= MSR_ILE; + else + msr &= ~MSR_ILE; + ppc_set_msr(msr); + + ppc.npc = EVPR | 0x0500; + + ppc.interrupt_pending &= ~0x1; + } + break; + } + + case EXCEPTION_TRAP: /* Program exception / Trap */ + { + UINT32 msr = ppc_get_msr(); + + SRR0 = ppc.pc; + SRR1 = msr; + + msr &= ~(MSR_WE | MSR_PR | MSR_EE | MSR_PE); // Clear WE, PR, EE, PR + if( msr & MSR_ILE ) + msr |= MSR_LE; + else + msr &= ~MSR_LE; + ppc_set_msr(msr); + + if( msr & MSR_IP ) + ppc.npc = 0xfff00000 | 0x0700; + else + ppc.npc = EVPR | 0x0700; + break; + } + + case EXCEPTION_SYSTEM_CALL: /* System call */ + { + UINT32 msr = ppc_get_msr(); + + SRR0 = ppc.npc; + SRR1 = msr; + + msr &= ~(MSR_WE | MSR_PR | MSR_EE | MSR_PE); // Clear WE, PR, EE, PR + if( msr & MSR_ILE ) + msr |= MSR_LE; + else + msr &= ~MSR_LE; + ppc_set_msr(msr); + + if( msr & MSR_IP ) + ppc.npc = 0xfff00000 | 0x0c00; + else + ppc.npc = EVPR | 0x0c00; + break; + } + + case EXCEPTION_PROGRAMMABLE_INTERVAL_TIMER: + { + if( ppc_get_msr() & MSR_EE ) { + UINT32 msr = ppc_get_msr(); + + SRR0 = ppc.npc; + SRR1 = msr; + + msr &= ~(MSR_WE | MSR_PR | MSR_EE | MSR_PE); // Clear WE, PR, EE, PR + if( msr & MSR_LE ) + msr |= MSR_ILE; + else + msr &= ~MSR_ILE; + ppc_set_msr(msr); + + ppc.npc = EVPR | 0x1000; + + ppc.tsr |= 0x08000000; // PIT interrupt + ppc.interrupt_pending &= ~0x2; + } + break; + } + + case EXCEPTION_FIXED_INTERVAL_TIMER: /* Fixed Interval Timer */ + { + if( ppc_get_msr() & MSR_EE ) { + UINT32 msr = ppc_get_msr(); + + SRR0 = ppc.npc; + SRR1 = msr; + + msr &= ~(MSR_WE | MSR_PR | MSR_EE | MSR_PE); // Clear WE, PR, EE, PR + if( msr & MSR_LE ) + msr |= MSR_ILE; + else + msr &= ~MSR_ILE; + ppc_set_msr(msr); + + ppc.npc = EVPR | 0x1010; + ppc.interrupt_pending &= ~0x4; + } + break; + } + + case EXCEPTION_WATCHDOG_TIMER: /* Watchdog Timer */ + { + UINT32 msr = ppc_get_msr(); + + SRR2 = ppc.npc; + SRR3 = msr; + + msr &= ~(MSR_WE | MSR_PR | MSR_CE | MSR_EE | MSR_DE | MSR_PE | MSR_DR | MSR_IR); + if (msr & MSR_LE) + msr |= MSR_ILE; + else + msr &= ~MSR_ILE; + ppc_set_msr(msr); + + ppc.npc = EVPR | 0x1020; + break; + } + + case EXCEPTION_CRITICAL_INTERRUPT: + { + UINT32 msr = ppc_get_msr(); + + SRR2 = ppc.npc; + SRR3 = msr; + + msr &= ~(MSR_WE | MSR_PR | MSR_CE | MSR_EE | MSR_DE | MSR_PE | MSR_DR | MSR_IR); + if (msr & MSR_LE) + msr |= MSR_ILE; + else + msr &= ~MSR_ILE; + ppc_set_msr(msr); + + EXISR |= 0x80000000; + ppc.npc = EVPR | 0x100; + break; + } + + default: + fatalerror("ppc: Unhandled exception %d\n", exception); + break; + } +} + +static void ppc403_set_irq_line(int irqline, int state) +{ + if (irqline >= INPUT_LINE_IRQ0 && irqline <= INPUT_LINE_IRQ4) + { + UINT32 mask = (1 << (4 - irqline)); + if( state == ASSERT_LINE) { + if( EXIER & mask ) { + ppc.exisr |= mask; + ppc.interrupt_pending |= 0x1; + + if (ppc.irq_callback) + { + ppc.irq_callback(ppc.device, irqline); + } + } + } + // clear line is used to clear the interrupt when the interrupts are level-sensitive + else if (state == CLEAR_LINE) + { + ppc.exisr &= ~mask; + } + } + else if (irqline == PPC_IRQ_SPU_RX) + { + UINT32 mask = 0x08000000; + if (state) { + if( EXIER & mask ) { + ppc.exisr |= mask; + ppc.interrupt_pending |= 0x1; + } + } + } + else if (irqline == PPC_IRQ_SPU_TX) + { + UINT32 mask = 0x04000000; + if (state) { + if( EXIER & mask ) { + ppc.exisr |= mask; + ppc.interrupt_pending |= 0x1; + } + } + } + else if (irqline == PPC_IRQ_CRITICAL) + { + if (state) { + if (EXIER & 0x80000000) { + ppc403_exception(EXCEPTION_CRITICAL_INTERRUPT); + } + } + } + else + { + fatalerror("PPC: Unknown IRQ line %d\n", irqline); + } +} + +static void ppc403_dma_set_irq_line(int dma, int state) +{ + UINT32 mask = (1 << (3 - dma)) << 20; + if( state ) { + if( EXIER & mask ) { + ppc.exisr |= mask; + ppc.interrupt_pending |= 0x1; + } + } +} +#endif + +#ifdef PPC_DRC +static void ppc403_dma_set_irq_line(int dma, int state) +{ + UINT32 mask = (1 << (3 - dma)) << 20; + if( state ) { + if( EXIER & mask ) { + ppc.exisr |= mask; + ppc.exception_pending |= 0x1; + } + } +} +#endif + + + + + + +#ifndef PPC_DRC +static void ppc_dccci(UINT32 op) +{ +} + +static void ppc_dcread(UINT32 op) +{ +} + +static void ppc_icbt(UINT32 op) +{ +} + +static void ppc_iccci(UINT32 op) +{ +} + +static void ppc_icread(UINT32 op) +{ +} + +static void ppc_rfci(UINT32 op) +{ + UINT32 msr; + ppc.npc = ppc.srr2; + msr = ppc.srr3; + ppc_set_msr( msr ); + +} +#endif + +static void ppc_mfdcr(UINT32 op) +{ + REG(RT) = ppc_get_dcr(SPR); +} + +static void ppc_mtdcr(UINT32 op) +{ + ppc_set_dcr(SPR, REG(RS)); +} + +static void ppc_wrtee(UINT32 op) +{ + if( REG(RS) & 0x8000 ) + ppc_set_msr( ppc_get_msr() | MSR_EE); + else + ppc_set_msr( ppc_get_msr() & ~MSR_EE); +} + +static void ppc_wrteei(UINT32 op) +{ + if( op & 0x8000 ) + ppc_set_msr( ppc_get_msr() | MSR_EE); + else + ppc_set_msr( ppc_get_msr() & ~MSR_EE); +} + + + +/**************************************************************************/ +/* PPC403 Serial Port */ + +static UINT8 ppc403_spu_r(UINT32 a) +{ + switch(a & 0xf) + { + case 0x0: return ppc.spu.spls | 0x6; /* transmit buffer is always empty */ + case 0x2: return ppc.spu.sphs; + case 0x4: return (ppc.spu.brd >> 8) & 0xf; + case 0x5: return (ppc.spu.brd & 0xff); + case 0x6: return ppc.spu.spctl; + case 0x7: return ppc.spu.sprc; + case 0x8: return ppc.spu.sptc; + case 0x9: return ppc.spu.sprb; + default: fatalerror("ppc: spu_r: %02X\n", a & 0xf); + } +} + +static void ppc403_spu_w(UINT32 a, UINT8 d) +{ + switch(a & 0xf) + { + case 0x0: + if( d & 0x80 ) ppc.spu.spls &= ~0x80; + if( d & 0x40 ) ppc.spu.spls &= ~0x40; + if( d & 0x20 ) ppc.spu.spls &= ~0x20; + if( d & 0x10 ) ppc.spu.spls &= ~0x10; + if( d & 0x08 ) ppc.spu.spls &= ~0x08; + break; + + case 0x2: + ppc.spu.sphs = d; + break; + + case 0x4: + ppc.spu.brd &= 0xff; + ppc.spu.brd |= (d << 8); + break; + + case 0x5: + ppc.spu.brd &= 0xff00; + ppc.spu.brd |= d; + if (ppc.iocr & 0x2) { + osd_printf_debug("ppc: SPU Baud rate: %d\n", (3686400 / (ppc.spu.brd + 1)) / 16); + } else { + osd_printf_debug("ppc: SPU Baud rate: %d\n", (33333333 / (ppc.spu.brd + 1)) / 16); + } + break; + + case 0x6: + ppc.spu.spctl = d; + break; + + case 0x7: + ppc.spu.sprc = d; + if (ppc.spu.sprc & 0x80) /* enable RX */ + { + /* + int baud_rate; + if (ppc.iocr & 0x2) { + baud_rate = (3686400 / (ppc.spu.brd + 1)) / 16; + } else { + baud_rate = (33333333 / (ppc.spu.brd + 1)) / 16; + } + */ + + /* check if serial port is hooked to a DMA channel */ + /* if so, do a DMA operation */ + if( ((((ppc.spu.sprc >> 5) & 0x3) == 2) && (ppc.dma[2].cr & DMA_CE)) || + ((((ppc.spu.sprc >> 5) & 0x3) == 3) && (ppc.dma[3].cr & DMA_CE)) ) + { + int i; + int ch = (ppc.spu.sprc >> 5) & 0x3; + // osd_printf_debug("ppc: DMA from serial port on channel %d (DA: %08X)\n", ch, ppc.dma[ch].da); + + if (spu_rx_dma_handler) + { + int length = ppc.dma[ch].ct; + + spu_rx_dma_handler(length); + + for (i=0; i < length; i++) + { + ppc.program->write_byte(ppc.dma[ch].da++, spu_rx_dma_ptr[i]); + } + } + + ppc.dmasr |= (1 << (27 - ch)); + + /* generate interrupts */ + if( ppc.dma[ch].cr & DMA_CIE ) + { + ppc403_dma_set_irq_line( ch, PULSE_LINE ); + } + + /* set receive buffer full */ + ppc.spu.spls = 0x80; + +#ifndef PPC_DRC + ppc403_set_irq_line(PPC_IRQ_SPU_RX, ASSERT_LINE); +#else + ppcdrc403_set_irq_line(PPC_IRQ_SPU_RX, ASSERT_LINE); +#endif + } + } + else /* disable RX */ + { + } + break; + + case 0x8: + ppc.spu.sptc = d; + break; + + case 0x9: + ppc.spu.sptb = d; + ppc403_spu_tx_callback(NULL/* Machine */, NULL, cpunum_get_active()); + break; + + default: + fatalerror("ppc: spu_w: %02X, %02X\n", a & 0xf, d); + break; + } + //osd_printf_debug("spu_w: %02X, %02X at %08X\n", a & 0xf, d, ppc.pc); +} + +void ppc403_spu_rx(UINT8 data) +{ + ppc.spu.sprb = data; + + /* set receive buffer full */ + ppc.spu.spls = 0x80; + + /* generate interrupt if DMA is disabled and RBR interrupt is enabled */ + if (((ppc.spu.sprc >> 5) & 0x3) == 0x01) { +#ifndef PPC_DRC + ppc403_set_irq_line(PPC_IRQ_SPU_RX, ASSERT_LINE); +#else + ppcdrc403_set_irq_line(PPC_IRQ_SPU_RX, ASSERT_LINE); +#endif + } +} + +static TIMER_CALLBACK( ppc403_spu_rx_callback ) +{ + if (spu_rx_handler != NULL) + { + ppc403_spu_rx(spu_rx_handler()); + } +} + +static TIMER_CALLBACK( ppc403_spu_tx_callback ) +{ + if (spu_tx_handler != NULL) + { + spu_tx_handler(ppc.spu.sptb); + + /* generate interrupt if DMA is disabled and TBR interrupt is enabled */ + if (((ppc.spu.sptc >> 5) & 0x3) == 0x01) { +#ifndef PPC_DRC + ppc403_set_irq_line(PPC_IRQ_SPU_TX, ASSERT_LINE); +#else + ppcdrc403_set_irq_line(PPC_IRQ_SPU_TX, ASSERT_LINE); +#endif + } + } +} + +void ppc403_install_spu_rx_handler(SPU_RX_HANDLER rx_handler) +{ + spu_rx_handler = rx_handler; +} + +void ppc403_install_spu_tx_handler(SPU_TX_HANDLER tx_handler) +{ + spu_tx_handler = tx_handler; +} + + +void ppc403_spu_rx_dma(UINT8 *data, int length) +{ +} + +void ppc403_install_spu_rx_dma_handler(PPC_DMA_HANDLER rx_dma_handler, UINT8 *buffer) +{ + spu_rx_dma_handler = rx_dma_handler; + spu_rx_dma_ptr = buffer; +} + +void ppc403_install_spu_tx_dma_handler(PPC_DMA_HANDLER tx_dma_handler, UINT8 *buffer) +{ + spu_tx_dma_handler = tx_dma_handler; + spu_tx_dma_ptr = buffer; +} + +/*********************************************************************************/ + +/* PPC 403 DMA */ + +static const int dma_transfer_width[4] = { 1, 2, 4, 16 }; + +void ppc403_install_dma_read_handler(int ch, PPC_DMA_HANDLER dma_handler, UINT8 *buffer) +{ + dma_read_handler[ch] = dma_handler; + dma_read_ptr[ch] = buffer; +} + +void ppc403_install_dma_write_handler(int ch, PPC_DMA_HANDLER dma_handler, UINT8 *buffer) +{ + dma_write_handler[ch] = dma_handler; + dma_write_ptr[ch] = buffer; +} + +static void ppc403_dma_exec(int ch) +{ + int i; + int dai, sai, width; + + /* Is the DMA channel enabled ? */ + if( ppc.dma[ch].cr & DMA_CE ) + { + /* transfer width */ + width = dma_transfer_width[(ppc.dma[ch].cr >> 26) & 0x3]; + + if( ppc.dma[ch].cr & DMA_DAI ) + dai = width; + else + dai = 0; /* DA not incremented */ + + if( ppc.dma[ch].cr & DMA_SAI ) + sai = width; + else + sai = 0; /* SA not incremented */ + + + /* transfer mode */ + switch( (ppc.dma[ch].cr >> 21) & 0x3 ) + { + case 0: /* buffered DMA */ + if( ppc.dma[ch].cr & DMA_TD ) /* peripheral to mem */ + { + // nothing to do for now */ + } + else /* mem to peripheral */ + { + /* check if the serial port is hooked to channel 2 or 3 */ + if( (ch == 2 && ((ppc.spu.sptc >> 5) & 0x3) == 2) || + (ch == 3 && ((ppc.spu.sptc >> 5) & 0x3) == 3) ) + { + osd_printf_debug("ppc: dma_exec: DMA to serial port on channel %d (DA: %08X)\n", ch, ppc.dma[ch].da); + + if (spu_tx_dma_handler) + { + int length = ppc.dma[ch].ct; + + for( i=0; i < length; i++ ) { + spu_tx_dma_ptr[i] = ppc.program->read_byte(ppc.dma[ch].da++); + } + spu_tx_dma_handler(length); + } + +#ifndef PPC_DRC + ppc403_set_irq_line(PPC_IRQ_SPU_TX, ASSERT_LINE); +#else + ppcdrc403_set_irq_line(PPC_IRQ_SPU_TX, ASSERT_LINE); +#endif + } + else { + fatalerror("ppc: dma_exec: buffered DMA to unknown peripheral ! (channel %d)\n", ch); + } + + } + break; + + case 1: /* fly-by DMA */ + fatalerror("ppc: dma_exec: fly-by DMA not implemented\n"); + break; + + case 2: /* software initiated mem-to-mem DMA */ + //osd_printf_debug("ppc: DMA (%d, SW mem-to-mem): SA = %08X, DA = %08X, CT = %08X\n", ch, ppc.dma[ch].sa, ppc.dma[ch].da, ppc.dma[ch].ct); + + switch(width) + { + case 1: /* Byte transfer */ + for (i=0; i < ppc.dma[ch].ct; i++) + { + UINT8 b = READ8(ppc.dma[ch].sa); + WRITE8(ppc.dma[ch].da, b); + ppc.dma[ch].sa += sai; + ppc.dma[ch].da += dai; + } + break; + case 2: /* Word transfer */ + for (i=0; i < ppc.dma[ch].ct; i++) + { + UINT16 w = READ16(ppc.dma[ch].sa); + WRITE16(ppc.dma[ch].da, w); + ppc.dma[ch].sa += sai; + ppc.dma[ch].da += dai; + } + break; + case 4: /* Double word transfer */ + for (i=0; i < ppc.dma[ch].ct; i++) + { + UINT32 d = READ32(ppc.dma[ch].sa); + WRITE32(ppc.dma[ch].da, d); + ppc.dma[ch].sa += sai; + ppc.dma[ch].da += dai; + } + break; + case 16: /* 16-byte transfer */ + for (i=0; i < ppc.dma[ch].ct; i++) + { + UINT32 d1 = READ32(ppc.dma[ch].sa+0); + UINT32 d2 = READ32(ppc.dma[ch].sa+4); + UINT32 d3 = READ32(ppc.dma[ch].sa+8); + UINT32 d4 = READ32(ppc.dma[ch].sa+12); + WRITE32(ppc.dma[ch].da+0, d1); + WRITE32(ppc.dma[ch].da+4, d2); + WRITE32(ppc.dma[ch].da+8, d3); + WRITE32(ppc.dma[ch].da+12, d4); + ppc.dma[ch].sa += 16; + ppc.dma[ch].da += 16; + } + break; + default: + fatalerror("dma: dma_exec: SW mem-to-mem DMA, width = %d\n", width); + } + break; + + case 3: /* hardware initiated mem-to-mem DMA */ + fatalerror("ppc: dma_exec: HW mem-to-mem DMA not implemented\n"); + break; + } + + ppc.dmasr |= (1 << (27 - ch)); + + /* DEBUG: check for not yet supported features */ + if( (ppc.dma[ch].cr & DMA_TCE) == 0 ) + fatalerror("ppc: dma_exec: DMA_TCE == 0\n"); + + if( ppc.dma[ch].cr & DMA_CH ) + fatalerror("ppc: dma_exec: DMA chaining not implemented\n"); + + /* generate interrupts */ + if( ppc.dma[ch].cr & DMA_CIE ) + ppc403_dma_set_irq_line( ch, PULSE_LINE ); + + } +} + +/*********************************************************************************/ + +static UINT8 ppc403_read8(address_space &space, UINT32 a) +{ + if(a >= 0x40000000 && a <= 0x4000000f) /* Serial Port */ + return ppc403_spu_r(a); + return space.read_byte(a); +} + +#define ppc403_read16 memory_read_word_32be +#define ppc403_read32 memory_read_dword_32be + +static void ppc403_write8(address_space &space, UINT32 a, UINT8 d) +{ + if( a >= 0x40000000 && a <= 0x4000000f ) /* Serial Port */ + { + ppc403_spu_w(a, d); + return; + } + space.write_byte(a, d); +} + +#define ppc403_write16 memory_write_word_32be +#define ppc403_write32 memory_write_dword_32be + +static UINT16 ppc403_read16_unaligned(address_space &space, UINT32 a) +{ + fatalerror("ppc: Unaligned read16 %08X at %08X\n", a, ppc.pc); + return 0; +} + +static UINT32 ppc403_read32_unaligned(address_space &space, UINT32 a) +{ + fatalerror("ppc: Unaligned read32 %08X at %08X\n", a, ppc.pc); + return 0; +} + +static void ppc403_write16_unaligned(address_space &space, UINT32 a, UINT16 d) +{ + fatalerror("ppc: Unaligned write16 %08X, %04X at %08X\n", a, d, ppc.pc); +} + +static void ppc403_write32_unaligned(address_space &space, UINT32 a, UINT32 d) +{ + fatalerror("ppc: Unaligned write32 %08X, %08X at %08X\n", a, d, ppc.pc); +} diff --git a/src/devices/cpu/powerpc/ppc602.inc b/src/devices/cpu/powerpc/ppc602.inc new file mode 100644 index 00000000000..6b1998201f7 --- /dev/null +++ b/src/devices/cpu/powerpc/ppc602.inc @@ -0,0 +1,279 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +static void ppc_dsa(UINT32 op) +{ + UINT32 msr = ppc_get_msr(); + + msr &= ~(MSR_SA | MSR_EE | MSR_PR | MSR_AP); + if (ppc.esasrr & 0x8) msr |= MSR_PR; + if (ppc.esasrr & 0x4) msr |= MSR_AP; + if (ppc.esasrr & 0x2) msr |= MSR_SA; + if (ppc.esasrr & 0x1) msr |= MSR_EE; + + ppc_set_msr(msr); +} + +static void ppc_esa(UINT32 op) +{ + int sa, ee, pr, ap; + UINT32 msr = ppc_get_msr(); + + sa = (msr & MSR_SA) ? 1 : 0; + ee = (msr & MSR_EE) ? 1 : 0; + pr = (msr & MSR_PR) ? 1 : 0; + ap = (msr & MSR_AP) ? 1 : 0; + + ppc.esasrr = (pr << 3) | (ap << 2) | (sa << 1) | (ee); + + msr &= ~(MSR_EE | MSR_PR | MSR_AP); + msr |= MSR_SA; + + ppc_set_msr(msr); +} + +#ifndef PPC_DRC +static void ppc_tlbli(UINT32 op) +{ +} + +static void ppc_tlbld(UINT32 op) +{ +} +#endif + +#ifndef PPC_DRC +void ppc602_exception(int exception) +{ + switch( exception ) + { + case EXCEPTION_IRQ: /* External Interrupt */ + if( ppc_get_msr() & MSR_EE ) { + UINT32 msr = ppc_get_msr(); + + SRR0 = ppc.npc; + SRR1 = msr & 0xff73; + + msr &= ~(MSR_POW | MSR_EE | MSR_PR | MSR_FP | MSR_FE0 | MSR_SE | MSR_BE | MSR_FE1 | MSR_IR | MSR_DR | MSR_RI); + if( msr & MSR_ILE ) + msr |= MSR_LE; + else + msr &= ~MSR_LE; + ppc_set_msr(msr); + + if( msr & MSR_IP ) + ppc.npc = 0xfff00000 | 0x0500; + else + ppc.npc = ppc.ibr | 0x0500; + + ppc.interrupt_pending &= ~0x1; + } + break; + + case EXCEPTION_DECREMENTER: /* Decrementer overflow exception */ + if( ppc_get_msr() & MSR_EE ) { + UINT32 msr = ppc_get_msr(); + + SRR0 = ppc.npc; + SRR1 = msr & 0xff73; + + msr &= ~(MSR_POW | MSR_EE | MSR_PR | MSR_FP | MSR_FE0 | MSR_SE | MSR_BE | MSR_FE1 | MSR_IR | MSR_DR | MSR_RI); + if( msr & MSR_ILE ) + msr |= MSR_LE; + else + msr &= ~MSR_LE; + ppc_set_msr(msr); + + if( msr & MSR_IP ) + ppc.npc = 0xfff00000 | 0x0900; + else + ppc.npc = ppc.ibr | 0x0900; + + ppc.interrupt_pending &= ~0x2; + } + break; + + case EXCEPTION_TRAP: /* Program exception / Trap */ + { + UINT32 msr = ppc_get_msr(); + + SRR0 = ppc.pc; + SRR1 = (msr & 0xff73) | 0x20000; /* 0x20000 = TRAP bit */ + + msr &= ~(MSR_POW | MSR_EE | MSR_PR | MSR_FP | MSR_FE0 | MSR_SE | MSR_BE | MSR_FE1 | MSR_IR | MSR_DR | MSR_RI); + if( msr & MSR_ILE ) + msr |= MSR_LE; + else + msr &= ~MSR_LE; + + if( msr & MSR_IP ) + ppc.npc = 0xfff00000 | 0x0700; + else + ppc.npc = ppc.ibr | 0x0700; + } + break; + + case EXCEPTION_SYSTEM_CALL: /* System call */ + { + UINT32 msr = ppc_get_msr(); + + SRR0 = ppc.npc; + SRR1 = (msr & 0xff73); + + msr &= ~(MSR_POW | MSR_EE | MSR_PR | MSR_FP | MSR_FE0 | MSR_SE | MSR_BE | MSR_FE1 | MSR_IR | MSR_DR | MSR_RI); + if( msr & MSR_ILE ) + msr |= MSR_LE; + else + msr &= ~MSR_LE; + + if( msr & MSR_IP ) + ppc.npc = 0xfff00000 | 0x0c00; + else + ppc.npc = ppc.ibr | 0x0c00; + } + break; + + case EXCEPTION_SMI: + if( ppc_get_msr() & MSR_EE ) { + UINT32 msr = ppc_get_msr(); + + SRR0 = ppc.npc; + SRR1 = msr & 0xff73; + + msr &= ~(MSR_POW | MSR_EE | MSR_PR | MSR_FP | MSR_FE0 | MSR_SE | MSR_BE | MSR_FE1 | MSR_IR | MSR_DR | MSR_RI); + if( msr & MSR_ILE ) + msr |= MSR_LE; + else + msr &= ~MSR_LE; + ppc_set_msr(msr); + + if( msr & MSR_IP ) + ppc.npc = 0xfff00000 | 0x1400; + else + ppc.npc = ppc.ibr | 0x1400; + + ppc.interrupt_pending &= ~0x4; + } + break; + + + default: + fatalerror("ppc: Unhandled exception %d\n", exception); + break; + } +} + +static void ppc602_set_irq_line(int irqline, int state) +{ + if( state ) { + ppc.interrupt_pending |= 0x1; + if (ppc.irq_callback) + { + ppc.irq_callback(ppc.device, irqline); + } + } +} + +static void ppc602_set_smi_line(int state) +{ + if( state ) { + ppc.interrupt_pending |= 0x4; + } +} + +INLINE void ppc602_check_interrupts(void) +{ + if (MSR & MSR_EE) + { + if (ppc.interrupt_pending != 0) + { + if (ppc.interrupt_pending & 0x1) + { + ppc602_exception(EXCEPTION_IRQ); + } + else if (ppc.interrupt_pending & 0x2) + { + ppc602_exception(EXCEPTION_DECREMENTER); + } + else if (ppc.interrupt_pending & 0x4) + { + ppc602_exception(EXCEPTION_SMI); + } + } + } +} + +static CPU_RESET( ppc602 ) +{ + ppc.pc = ppc.npc = 0xfff00100; + + ppc_set_msr(0x40); + + ppc.hid0 = 1; + + ppc.interrupt_pending = 0; +} + +static CPU_EXECUTE( ppc602 ) +{ + int exception_type; + UINT32 opcode; + ppc_tb_base_icount = ppc_icount; + ppc_dec_base_icount = ppc_icount; + + // check if decrementer exception occurs during execution + if ((UINT32)(DEC - ppc_icount) > (UINT32)(DEC)) + { + ppc_dec_trigger_cycle = ppc_icount - DEC; + } + else + { + ppc_dec_trigger_cycle = 0x7fffffff; + } + + // MinGW's optimizer kills setjmp()/longjmp() + SETJMP_GNUC_PROTECT(); + + exception_type = setjmp(ppc.exception_jmpbuf); + if (exception_type) + { + ppc.npc = ppc.pc; + ppc602_exception(exception_type); + } + + while( ppc_icount > 0 ) + { + ppc.pc = ppc.npc; + debugger_instruction_hook(device, ppc.pc); + + if (MSR & MSR_IR) + opcode = ppc_readop_translated(ppc.program, ppc.pc); + else + opcode = ROPCODE64(ppc.pc); + + ppc.npc = ppc.pc + 4; + switch(opcode >> 26) + { + case 19: ppc.optable19[(opcode >> 1) & 0x3ff](opcode); break; + case 31: ppc.optable31[(opcode >> 1) & 0x3ff](opcode); break; + case 59: ppc.optable59[(opcode >> 1) & 0x3ff](opcode); break; + case 63: ppc.optable63[(opcode >> 1) & 0x3ff](opcode); break; + default: ppc.optable[opcode >> 26](opcode); break; + } + + ppc_icount--; + + if(ppc_icount == ppc_dec_trigger_cycle) { + ppc.interrupt_pending |= 0x2; + } + + ppc602_check_interrupts(); + } + + // update timebase + // timebase is incremented once every four core clock cycles, so adjust the cycles accordingly + ppc.tb += ((ppc_tb_base_icount - ppc_icount) / 4); + + // update decrementer + DEC -= ((ppc_dec_base_icount - ppc_icount) / (bus_freq_multiplier * 2)); +} +#endif // PPC_DRC diff --git a/src/devices/cpu/powerpc/ppc603.inc b/src/devices/cpu/powerpc/ppc603.inc new file mode 100644 index 00000000000..114728d19ce --- /dev/null +++ b/src/devices/cpu/powerpc/ppc603.inc @@ -0,0 +1,285 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +void ppc603_exception(int exception) +{ + switch( exception ) + { + case EXCEPTION_IRQ: /* External Interrupt */ + if( ppc_get_msr() & MSR_EE ) { + UINT32 msr = ppc_get_msr(); + + SRR0 = ppc.npc; + SRR1 = msr & 0xff73; + + msr &= ~(MSR_POW | MSR_EE | MSR_PR | MSR_FP | MSR_FE0 | MSR_SE | MSR_BE | MSR_FE1 | MSR_IR | MSR_DR | MSR_RI); + if( msr & MSR_ILE ) + msr |= MSR_LE; + else + msr &= ~MSR_LE; + ppc_set_msr(msr); + + if( msr & MSR_IP ) + ppc.npc = 0xfff00000 | 0x0500; + else + ppc.npc = 0x00000000 | 0x0500; + + ppc.interrupt_pending &= ~0x1; + } + break; + + case EXCEPTION_DECREMENTER: /* Decrementer overflow exception */ + if( ppc_get_msr() & MSR_EE ) { + UINT32 msr = ppc_get_msr(); + + SRR0 = ppc.npc; + SRR1 = msr & 0xff73; + + msr &= ~(MSR_POW | MSR_EE | MSR_PR | MSR_FP | MSR_FE0 | MSR_SE | MSR_BE | MSR_FE1 | MSR_IR | MSR_DR | MSR_RI); + if( msr & MSR_ILE ) + msr |= MSR_LE; + else + msr &= ~MSR_LE; + ppc_set_msr(msr); + + if( msr & MSR_IP ) + ppc.npc = 0xfff00000 | 0x0900; + else + ppc.npc = 0x00000000 | 0x0900; + + ppc.interrupt_pending &= ~0x2; + } + break; + + case EXCEPTION_TRAP: /* Program exception / Trap */ + { + UINT32 msr = ppc_get_msr(); + + SRR0 = ppc.pc; + SRR1 = (msr & 0xff73) | 0x20000; /* 0x20000 = TRAP bit */ + + msr &= ~(MSR_POW | MSR_EE | MSR_PR | MSR_FP | MSR_FE0 | MSR_SE | MSR_BE | MSR_FE1 | MSR_IR | MSR_DR | MSR_RI); + if( msr & MSR_ILE ) + msr |= MSR_LE; + else + msr &= ~MSR_LE; + ppc_set_msr(msr); + + if( msr & MSR_IP ) + ppc.npc = 0xfff00000 | 0x0700; + else + ppc.npc = 0x00000000 | 0x0700; + } + break; + + case EXCEPTION_SYSTEM_CALL: /* System call */ + { + UINT32 msr = ppc_get_msr(); + + SRR0 = ppc.npc; + SRR1 = (msr & 0xff73); + + msr &= ~(MSR_POW | MSR_EE | MSR_PR | MSR_FP | MSR_FE0 | MSR_SE | MSR_BE | MSR_FE1 | MSR_IR | MSR_DR | MSR_RI); + if( msr & MSR_ILE ) + msr |= MSR_LE; + else + msr &= ~MSR_LE; + ppc_set_msr(msr); + + if( msr & MSR_IP ) + ppc.npc = 0xfff00000 | 0x0c00; + else + ppc.npc = 0x00000000 | 0x0c00; + } + break; + + case EXCEPTION_SMI: + if( ppc_get_msr() & MSR_EE ) { + UINT32 msr = ppc_get_msr(); + + SRR0 = ppc.npc; + SRR1 = msr & 0xff73; + + msr &= ~(MSR_POW | MSR_EE | MSR_PR | MSR_FP | MSR_FE0 | MSR_SE | MSR_BE | MSR_FE1 | MSR_IR | MSR_DR | MSR_RI); + if( msr & MSR_ILE ) + msr |= MSR_LE; + else + msr &= ~MSR_LE; + ppc_set_msr(msr); + + if( msr & MSR_IP ) + ppc.npc = 0xfff00000 | 0x1400; + else + ppc.npc = 0x00000000 | 0x1400; + + ppc.interrupt_pending &= ~0x4; + } + break; + + case EXCEPTION_DSI: + { + UINT32 msr = ppc_get_msr(); + + SRR0 = ppc.npc; + SRR1 = msr & 0xff73; + + msr &= ~(MSR_POW | MSR_EE | MSR_PR | MSR_FP | MSR_FE0 | MSR_SE | MSR_BE | MSR_FE1 | MSR_IR | MSR_DR | MSR_RI); + if( msr & MSR_ILE ) + msr |= MSR_LE; + else + msr &= ~MSR_LE; + ppc_set_msr(msr); + + if( msr & MSR_IP ) + ppc.npc = 0xfff00000 | 0x0300; + else + ppc.npc = 0x00000000 | 0x0300; + + ppc.interrupt_pending &= ~0x4; + } + break; + + case EXCEPTION_ISI: + { + UINT32 msr = ppc_get_msr(); + + SRR0 = ppc.npc; + SRR1 = msr & 0xff73; + + msr &= ~(MSR_POW | MSR_EE | MSR_PR | MSR_FP | MSR_FE0 | MSR_SE | MSR_BE | MSR_FE1 | MSR_IR | MSR_DR | MSR_RI); + if( msr & MSR_ILE ) + msr |= MSR_LE; + else + msr &= ~MSR_LE; + ppc_set_msr(msr); + + if( msr & MSR_IP ) + ppc.npc = 0xfff00000 | 0x0400; + else + ppc.npc = 0x00000000 | 0x0400; + + ppc.interrupt_pending &= ~0x4; + } + break; + + default: + fatalerror("ppc: Unhandled exception %d\n", exception); + break; + } +} + +static void ppc603_set_irq_line(int irqline, int state) +{ + if( state ) { + ppc.interrupt_pending |= 0x1; + if (ppc.irq_callback) + { + ppc.irq_callback(ppc.device, irqline); + } + } +} + +static void ppc603_set_smi_line(int state) +{ + if( state ) { + ppc.interrupt_pending |= 0x4; + } +} + +INLINE void ppc603_check_interrupts(void) +{ + if (MSR & MSR_EE) + { + if (ppc.interrupt_pending != 0) + { + if (ppc.interrupt_pending & 0x1) + { + ppc603_exception(EXCEPTION_IRQ); + } + else if (ppc.interrupt_pending & 0x2) + { + ppc603_exception(EXCEPTION_DECREMENTER); + } + else if (ppc.interrupt_pending & 0x4) + { + ppc603_exception(EXCEPTION_SMI); + } + } + } +} + +static CPU_RESET( ppc603 ) +{ + ppc.pc = ppc.npc = 0xfff00100; + + ppc_set_msr(0x40); + + ppc.hid0 = 1; + + ppc.interrupt_pending = 0; +} + + +static CPU_EXECUTE( ppc603 ) +{ + int exception_type; + UINT32 opcode; + ppc_tb_base_icount = ppc_icount; + ppc_dec_base_icount = ppc_icount + ppc.dec_frac; + + // check if decrementer exception occurs during execution + if ((UINT32)(DEC - ppc_icount) > (UINT32)(DEC)) + { + ppc_dec_trigger_cycle = ppc_icount - DEC; + } + else + { + ppc_dec_trigger_cycle = 0x7fffffff; + } + + // MinGW's optimizer kills setjmp()/longjmp() + SETJMP_GNUC_PROTECT(); + + exception_type = setjmp(ppc.exception_jmpbuf); + if (exception_type) + { + ppc.npc = ppc.pc; + ppc603_exception(exception_type); + } + + while( ppc_icount > 0 ) + { + ppc.pc = ppc.npc; + debugger_instruction_hook(device, ppc.pc); + + if (MSR & MSR_IR) + opcode = ppc_readop_translated(ppc.program, ppc.pc); + else + opcode = ROPCODE64(ppc.pc); + + ppc.npc = ppc.pc + 4; + switch(opcode >> 26) + { + case 19: ppc.optable19[(opcode >> 1) & 0x3ff](opcode); break; + case 31: ppc.optable31[(opcode >> 1) & 0x3ff](opcode); break; + case 59: ppc.optable59[(opcode >> 1) & 0x3ff](opcode); break; + case 63: ppc.optable63[(opcode >> 1) & 0x3ff](opcode); break; + default: ppc.optable[opcode >> 26](opcode); break; + } + + ppc_icount--; + + if(ppc_icount == ppc_dec_trigger_cycle) { + ppc.interrupt_pending |= 0x2; + } + + ppc603_check_interrupts(); + } + + // update timebase + // timebase is incremented once every four core clock cycles, so adjust the cycles accordingly + ppc.tb += ((ppc_tb_base_icount - ppc_icount) / 4); + + // update decrementer + ppc.dec_frac = ((ppc_dec_base_icount - ppc_icount) % (bus_freq_multiplier * 2)); + DEC -= ((ppc_dec_base_icount - ppc_icount) / (bus_freq_multiplier * 2)); +} diff --git a/src/devices/cpu/powerpc/ppc_dasm.c b/src/devices/cpu/powerpc/ppc_dasm.c new file mode 100644 index 00000000000..d80f800c89b --- /dev/null +++ b/src/devices/cpu/powerpc/ppc_dasm.c @@ -0,0 +1,1177 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/* + * disasm.c + * + * PowerPC 603e disassembler. + * + * When possible, invalid forms of instructions are checked for. To the best + * of my knowledge, all appropriate load/store instructions are checked. I'm + * not sure whether any other kinds of instructions need checking. + */ + +/* Originally written by Bart Trzynadlowski for Supermodel project + * + * PowerPC 403 opcodes and MAME conversion by Ville Linde + */ + +#include "emu.h" +#include "debugger.h" +#include "ppccom.h" + +/* + * Operand Formats + * + * These convey information on what operand fields are present and how they + * ought to be printed. + * + * I'm fairly certain all of these are used, but that is not guaranteed. + */ + +enum +{ + F_NONE, // + F_LI, // LI*4+PC if AA=0 else LI*4 + F_BCx, // BO, BI, target_addr used only by BCx + F_RT_RA_0_SIMM, // rT, rA|0, SIMM rA|0 means if rA == 0, print 0 + F_ADDIS, // rT, rA, SIMM (printed as unsigned) only used by ADDIS + F_RT_RA_SIMM, // rT, rA, SIMM + F_RA_RT_UIMM, // rA, rT, UIMM + F_CMP_SIMM, // crfD, L, A, SIMM + F_CMP_UIMM, // crfD, L, A, UIMM + F_RT_RA_0_RB, // rT, rA|0, rB + F_RT_RA_RB, // rT, rA, rB + F_RT_D_RA_0, // rT, d(rA|0) + F_RT_D_RA, // rT, d(rA) + F_RA_RT_RB, // rA, rT, rB + F_FRT_D_RA_0, // frT, d(RA|0) + F_FRT_D_RA, // frT, d(RA) + F_FRT_RA_0_RB, // frT, rA|0, rB + F_FRT_RA_RB, // frT, rA, rB + F_TWI, // TO, rA, SIMM only used by TWI instruction + F_CMP, // crfD, L, rA, rB + F_RA_RT, // rA, rT + F_RA_0_RB, // rA|0, rB + F_FRT_FRB, // frT, frB + F_FCMP, // crfD, frA, frB + F_CRFD_CRFS, // crfD, crfS + F_MCRXR, // crfD only used by MCRXR + F_RT, // rT + F_MFSR, // rT, SR only used by MFSR + F_MTSR, // SR, rT only used by MTSR + F_MFFSx, // frT only used by MFFSx + F_FCRBD, // crbD FPSCR[crbD] + F_MTFSFIx, // crfD, IMM only used by MTFSFIx + F_RB, // rB + F_TW, // TO, rA, rB only used by TW + F_RT_RA_0_NB, // rT, rA|0, NB print 32 if NB == 0 + F_SRAWIx, // rA, rT, SH only used by SRAWIx + F_BO_BI, // BO, BI + F_CRBD_CRBA_CRBB, // crbD, crbA, crbB + F_RT_SPR, // rT, SPR and TBR + F_MTSPR, // SPR, rT only used by MTSPR + F_MTCRF, // CRM, rT only used by MTCRF + F_MTFSFx, // FM, frB only used by MTFSFx + F_RT_DCR, // rT, DCR + F_MTDCR, // DCR, rT + F_RT_RA, // rT, rA + F_FRT_FRA_FRC_FRB, // frT, frA, frC, frB + F_FRT_FRA_FRB, // frT, frA, frB + F_FRT_FRA_FRC, // frT, frA, frC + F_RA_RT_SH_MB_ME, // rA, rT, SH, MB, ME + F_RLWNMx, // rT, rA, rB, MB, ME only used by RLWNMx + F_RT_RB // rT, rB +}; + +/* + * Flags + */ + +#define FL_OE (1 << 0) // if there is an OE field +#define FL_RC (1 << 1) // if there is an RC field +#define FL_LK (1 << 2) // if there is an LK field +#define FL_AA (1 << 3) // if there is an AA field +#define FL_CHECK_RA_RT (1 << 4) // assert rA!=0 and rA!=rT +#define FL_CHECK_RA (1 << 5) // assert rA!=0 +#define FL_CHECK_LSWI (1 << 6) // specific check for LSWI validity +#define FL_CHECK_LSWX (1 << 7) // specific check for LSWX validity +#define FL_SO (1 << 8) // use DASMFLAG_STEP_OUT + + +/* + * Instruction Descriptor + * + * Describes the layout of an instruction. + */ + +struct IDESCR +{ + char mnem[32]; // mnemonic + UINT32 match; // bit pattern of instruction after it has been masked + UINT32 mask; // mask of variable fields (AND with ~mask to compare w/ + // bit pattern to determine a match) + int format; // operand format + int flags; // flags +}; + +/* + * Instruction Table + * + * Table of instruction descriptors which allows the disassembler to decode + * and print instructions. + */ + +static const IDESCR itab[] = +{ + { "add", D_OP(31)|D_XO(266), M_RT|M_RA|M_RB|M_OE|M_RC, F_RT_RA_RB, FL_OE|FL_RC }, + { "addc", D_OP(31)|D_XO(10), M_RT|M_RA|M_RB|M_OE|M_RC, F_RT_RA_RB, FL_OE|FL_RC }, + { "adde", D_OP(31)|D_XO(138), M_RT|M_RA|M_RB|M_OE|M_RC, F_RT_RA_RB, FL_OE|FL_RC }, + { "addi", D_OP(14), M_RT|M_RA|M_SIMM, F_RT_RA_0_SIMM, 0 }, + { "addic", D_OP(12), M_RT|M_RA|M_SIMM, F_RT_RA_SIMM, 0 }, + { "addic.", D_OP(13), M_RT|M_RA|M_SIMM, F_RT_RA_SIMM, 0 }, + { "addis", D_OP(15), M_RT|M_RA|M_SIMM, F_ADDIS, 0 }, + { "addme", D_OP(31)|D_XO(234), M_RT|M_RA|M_OE|M_RC, F_RT_RA, FL_OE|FL_RC }, + { "addze", D_OP(31)|D_XO(202), M_RT|M_RA|M_OE|M_RC, F_RT_RA, FL_OE|FL_RC }, + { "and", D_OP(31)|D_XO(28), M_RT|M_RA|M_RB|M_RC, F_RA_RT_RB, FL_RC }, + { "andc", D_OP(31)|D_XO(60), M_RT|M_RA|M_RB|M_RC, F_RA_RT_RB, FL_RC }, + { "andi.", D_OP(28), M_RT|M_RA|M_UIMM, F_RA_RT_UIMM, 0 }, + { "andis.", D_OP(29), M_RT|M_RA|M_UIMM, F_RA_RT_UIMM, 0 }, + { "b", D_OP(18), M_LI|M_AA|M_LK, F_LI, FL_AA|FL_LK }, + { "bc", D_OP(16), M_BO|M_BI|M_BD|M_AA|M_LK, F_BCx, FL_AA|FL_LK }, + { "bcctr", D_OP(19)|D_XO(528), M_BO|M_BI|M_LK, F_BO_BI, FL_LK }, + { "bclr", D_OP(19)|D_XO(16), M_BO|M_BI|M_LK, F_BO_BI, FL_LK|FL_SO }, + { "cmp", D_OP(31)|D_XO(0), M_CRFD|M_RA|M_RB, F_CMP, 0 }, + { "cmpd", D_OP(31)|D_XO(0)|M_L,M_CRFD|M_RA|M_RB, F_CMP, 0 }, + { "cmpi", D_OP(11), M_CRFD|M_RA|M_SIMM, F_CMP_SIMM, 0 }, + { "cmpdi", D_OP(11)|M_L, M_CRFD|M_RA|M_SIMM, F_CMP_SIMM, 0 }, + { "cmpl", D_OP(31)|D_XO(32), M_CRFD|M_RA|M_RB, F_CMP, 0 }, + { "cmpld", D_OP(31)|D_XO(32)|M_L,M_CRFD|M_RA|M_RB, F_CMP, 0 }, + { "cmpli", D_OP(10), M_CRFD|M_RA|M_UIMM, F_CMP_UIMM, 0 }, + { "cmpldi", D_OP(10)|M_L, M_CRFD|M_RA|M_UIMM, F_CMP_UIMM, 0 }, + { "cntlzw", D_OP(31)|D_XO(26), M_RT|M_RA|M_RC, F_RA_RT, FL_RC }, + { "crand", D_OP(19)|D_XO(257), M_CRBD|M_CRBA|M_CRBB, F_CRBD_CRBA_CRBB, 0 }, + { "crandc", D_OP(19)|D_XO(129), M_CRBD|M_CRBA|M_CRBB, F_CRBD_CRBA_CRBB, 0 }, + { "creqv", D_OP(19)|D_XO(289), M_CRBD|M_CRBA|M_CRBB, F_CRBD_CRBA_CRBB, 0 }, + { "crnand", D_OP(19)|D_XO(225), M_CRBD|M_CRBA|M_CRBB, F_CRBD_CRBA_CRBB, 0 }, + { "crnor", D_OP(19)|D_XO(33), M_CRBD|M_CRBA|M_CRBB, F_CRBD_CRBA_CRBB, 0 }, + { "cror", D_OP(19)|D_XO(449), M_CRBD|M_CRBA|M_CRBB, F_CRBD_CRBA_CRBB, 0 }, + { "crorc", D_OP(19)|D_XO(417), M_CRBD|M_CRBA|M_CRBB, F_CRBD_CRBA_CRBB, 0 }, + { "crxor", D_OP(19)|D_XO(193), M_CRBD|M_CRBA|M_CRBB, F_CRBD_CRBA_CRBB, 0 }, + { "dcba", D_OP(31)|D_XO(758), M_RA|M_RB, F_RA_0_RB, 0 }, + { "dcbf", D_OP(31)|D_XO(86), M_RA|M_RB, F_RA_0_RB, 0 }, + { "dcbi", D_OP(31)|D_XO(470), M_RA|M_RB, F_RA_0_RB, 0 }, + { "dcbst", D_OP(31)|D_XO(54), M_RA|M_RB, F_RA_0_RB, 0 }, + { "dcbt", D_OP(31)|D_XO(278), M_RA|M_RB, F_RA_0_RB, 0 }, + { "dcbtst", D_OP(31)|D_XO(246), M_RA|M_RB, F_RA_0_RB, 0 }, + { "dcbz", D_OP(31)|D_XO(1014),M_RA|M_RB, F_RA_0_RB, 0 }, + { "dccci", D_OP(31)|D_XO(454), M_RA|M_RB, F_RA_0_RB, 0 }, + { "dcread", D_OP(31)|D_XO(486), M_RA|M_RB, F_RT_RA_RB, 0 }, + { "divw", D_OP(31)|D_XO(491), M_RT|M_RA|M_RB|M_OE|M_RC, F_RT_RA_RB, FL_OE|FL_RC }, + { "divwu", D_OP(31)|D_XO(459), M_RT|M_RA|M_RB|M_OE|M_RC, F_RT_RA_RB, FL_OE|FL_RC }, + { "dsa", D_OP(31)|D_XO(628), 0, 0, 0 }, + { "eciwx", D_OP(31)|D_XO(310), M_RT|M_RA|M_RB, F_RT_RA_0_RB, 0 }, + { "ecowx", D_OP(31)|D_XO(438), M_RT|M_RA|M_RB, F_RT_RA_0_RB, 0 }, + { "eieio", D_OP(31)|D_XO(854), 0, F_NONE, 0 }, + { "eqv", D_OP(31)|D_XO(284), M_RT|M_RA|M_RB|M_RC, F_RA_RT_RB, FL_RC }, + { "esa", D_OP(31)|D_XO(596), 0, 0, 0 }, + { "extsb", D_OP(31)|D_XO(954), M_RT|M_RA|M_RC, F_RA_RT, FL_RC }, + { "extsh", D_OP(31)|D_XO(922), M_RT|M_RA|M_RC, F_RA_RT, FL_RC }, + { "fabs", D_OP(63)|D_XO(264), M_RT|M_RB|M_RC, F_FRT_FRB, FL_RC }, + { "fadd", D_OP(63)|D_XO(21), M_RT|M_RA|M_RB|M_RC, F_FRT_FRA_FRB, FL_RC }, + { "fadds", D_OP(59)|D_XO(21), M_RT|M_RA|M_RB|M_RC, F_FRT_FRA_FRB, FL_RC }, + { "fcmpo", D_OP(63)|D_XO(32), M_CRFD|M_RA|M_RB, F_FCMP, 0 }, + { "fcmpu", D_OP(63)|D_XO(0), M_CRFD|M_RA|M_RB, F_FCMP, 0 }, + { "fctiw", D_OP(63)|D_XO(14), M_RT|M_RB|M_RC, F_FRT_FRB, FL_RC }, + { "fctiwz", D_OP(63)|D_XO(15), M_RT|M_RB|M_RC, F_FRT_FRB, FL_RC }, + { "fdiv", D_OP(63)|D_XO(18), M_RT|M_RA|M_RB|M_RC, F_FRT_FRA_FRB, FL_RC }, + { "fdivs", D_OP(59)|D_XO(18), M_RT|M_RA|M_RB|M_RC, F_FRT_FRA_FRB, FL_RC }, + { "fmadd", D_OP(63)|D_XO(29), M_RT|M_RA|M_RB|M_REGC|M_RC, F_FRT_FRA_FRC_FRB, FL_RC }, + { "fmadds", D_OP(59)|D_XO(29), M_RT|M_RA|M_RB|M_REGC|M_RC, F_FRT_FRA_FRC_FRB, FL_RC }, + { "fmr", D_OP(63)|D_XO(72), M_RT|M_RB|M_RC, F_FRT_FRB, FL_RC }, + { "fmsub", D_OP(63)|D_XO(28), M_RT|M_RA|M_RB|M_REGC|M_RC, F_FRT_FRA_FRC_FRB, FL_RC }, + { "fmsubs", D_OP(59)|D_XO(28), M_RT|M_RA|M_RB|M_REGC|M_RC, F_FRT_FRA_FRC_FRB, FL_RC }, + { "fmul", D_OP(63)|D_XO(25), M_RT|M_RA|M_REGC|M_RC, F_FRT_FRA_FRC, FL_RC }, + { "fmuls", D_OP(59)|D_XO(25), M_RT|M_RA|M_REGC|M_RC, F_FRT_FRA_FRC, FL_RC }, + { "fnabs", D_OP(63)|D_XO(136), M_RT|M_RB|M_RC, F_FRT_FRB, FL_RC }, + { "fneg", D_OP(63)|D_XO(40), M_RT|M_RB|M_RC, F_FRT_FRB, FL_RC }, + { "fnmadd", D_OP(63)|D_XO(31), M_RT|M_RA|M_RB|M_REGC|M_RC, F_FRT_FRA_FRC_FRB, FL_RC }, + { "fnmadds",D_OP(59)|D_XO(31), M_RT|M_RA|M_RB|M_REGC|M_RC, F_FRT_FRA_FRC_FRB, FL_RC }, + { "fnmsub", D_OP(63)|D_XO(30), M_RT|M_RA|M_RB|M_REGC|M_RC, F_FRT_FRA_FRC_FRB, FL_RC }, + { "fnmsubs",D_OP(59)|D_XO(30), M_RT|M_RA|M_RB|M_REGC|M_RC, F_FRT_FRA_FRC_FRB, FL_RC }, + { "fres", D_OP(59)|D_XO(24), M_RT|M_RB|M_RC, F_FRT_FRB, FL_RC }, + { "frsp", D_OP(63)|D_XO(12), M_RT|M_RB|M_RC, F_FRT_FRB, FL_RC }, + { "frsqrte",D_OP(63)|D_XO(26), M_RT|M_RB|M_RC, F_FRT_FRB, FL_RC }, + { "fsel", D_OP(63)|D_XO(23), M_RT|M_RA|M_RB|M_REGC|M_RC, F_FRT_FRA_FRC_FRB, FL_RC }, + { "fsqrt", D_OP(63)|D_XO(22), M_RT|M_RB|M_RC, F_FRT_FRB, FL_RC }, + { "fsqrts", D_OP(59)|D_XO(22), M_RT|M_RB|M_RC, F_FRT_FRB, FL_RC }, + { "fsub", D_OP(63)|D_XO(20), M_RT|M_RA|M_RB|M_RC, F_FRT_FRA_FRB, FL_RC }, + { "fsubs", D_OP(59)|D_XO(20), M_RT|M_RA|M_RB|M_RC, F_FRT_FRA_FRB, FL_RC }, + { "icbi", D_OP(31)|D_XO(982), M_RA|M_RB, F_RA_0_RB, 0 }, + { "icbt", D_OP(31)|D_XO(262), M_RA|M_RB, F_RA_0_RB, 0 }, + { "iccci", D_OP(31)|D_XO(966), M_RA|M_RB, F_RA_0_RB, 0 }, + { "icread", D_OP(31)|D_XO(998), M_RA|M_RB, F_RA_0_RB, 0 }, + { "isync", D_OP(19)|D_XO(150), 0, F_NONE, 0 }, + { "lbz", D_OP(34), M_RT|M_RA|M_D, F_RT_D_RA_0, 0 }, + { "lbzu", D_OP(35), M_RT|M_RA|M_D, F_RT_D_RA, FL_CHECK_RA_RT }, + { "lbzux", D_OP(31)|D_XO(119), M_RT|M_RA|M_RB, F_RT_RA_RB, FL_CHECK_RA_RT }, + { "lbzx", D_OP(31)|D_XO(87), M_RT|M_RA|M_RB, F_RT_RA_0_RB, 0 }, + { "lfd", D_OP(50), M_RT|M_RA|M_D, F_FRT_D_RA_0, 0 }, + { "lfdu", D_OP(51), M_RT|M_RA|M_D, F_FRT_D_RA, FL_CHECK_RA }, + { "lfdux", D_OP(31)|D_XO(631), M_RT|M_RA|M_RB, F_FRT_RA_RB, FL_CHECK_RA }, + { "lfdx", D_OP(31)|D_XO(599), M_RT|M_RA|M_RB, F_FRT_RA_0_RB, 0 }, + { "lfs", D_OP(48), M_RT|M_RA|M_D, F_FRT_D_RA_0, 0 }, + { "lfsu", D_OP(49), M_RT|M_RA|M_D, F_FRT_D_RA, FL_CHECK_RA }, + { "lfsux", D_OP(31)|D_XO(567), M_RT|M_RA|M_RB, F_FRT_RA_RB, FL_CHECK_RA }, + { "lfsx", D_OP(31)|D_XO(535), M_RT|M_RA|M_RB, F_FRT_RA_0_RB, 0 }, + { "lha", D_OP(42), M_RT|M_RA|M_D, F_RT_D_RA_0, 0 }, + { "lhau", D_OP(43), M_RT|M_RA|M_D, F_RT_D_RA, FL_CHECK_RA_RT }, + { "lhaux", D_OP(31)|D_XO(375), M_RT|M_RA|M_RB, F_RT_RA_RB, FL_CHECK_RA_RT }, + { "lhax", D_OP(31)|D_XO(343), M_RT|M_RA|M_RB, F_RT_RA_0_RB, 0 }, + { "lhbrx", D_OP(31)|D_XO(790), M_RT|M_RA|M_RB, F_RT_RA_0_RB, 0 }, + { "lhz", D_OP(40), M_RT|M_RA|M_D, F_RT_D_RA_0, 0 }, + { "lhzu", D_OP(41), M_RT|M_RA|M_D, F_RT_D_RA, FL_CHECK_RA_RT }, + { "lhzux", D_OP(31)|D_XO(311), M_RT|M_RA|M_RB, F_RT_RA_RB, FL_CHECK_RA_RT }, + { "lhzx", D_OP(31)|D_XO(279), M_RT|M_RA|M_RB, F_RT_RA_0_RB, 0 }, + { "lmw", D_OP(46), M_RT|M_RA|M_D, F_RT_D_RA_0, 0 }, + { "lswi", D_OP(31)|D_XO(597), M_RT|M_RA|M_NB, F_RT_RA_0_NB, FL_CHECK_LSWI }, + { "lswx", D_OP(31)|D_XO(533), M_RT|M_RA|M_RB, F_RT_RA_0_RB, FL_CHECK_LSWX }, + { "lwarx", D_OP(31)|D_XO(20), M_RT|M_RA|M_RB, F_RT_RA_0_RB, 0 }, + { "lwbrx", D_OP(31)|D_XO(534), M_RT|M_RA|M_RB, F_RT_RA_0_RB, 0 }, + { "lwz", D_OP(32), M_RT|M_RA|M_D, F_RT_D_RA_0, 0 }, + { "lwzu", D_OP(33), M_RT|M_RA|M_D, F_RT_D_RA, FL_CHECK_RA_RT }, + { "lwzux", D_OP(31)|D_XO(55), M_RT|M_RA|M_RB, F_RT_RA_RB, FL_CHECK_RA_RT }, + { "lwzx", D_OP(31)|D_XO(23), M_RT|M_RA|M_RB, F_RT_RA_0_RB, 0 }, + { "mcrf", D_OP(19)|D_XO(0), M_CRFD|M_CRFS, F_CRFD_CRFS, 0 }, + { "mcrfs", D_OP(63)|D_XO(64), M_CRFD|M_CRFS, F_CRFD_CRFS, 0 }, + { "mcrxr", D_OP(31)|D_XO(512), M_CRFD, F_MCRXR, 0 }, + { "mfcr", D_OP(31)|D_XO(19), M_RT, F_RT, 0 }, + { "mfdcr", D_OP(31)|D_XO(323), M_RT|M_DCR, F_RT_DCR, 0 }, + { "mffs", D_OP(63)|D_XO(583), M_RT|M_RC, F_MFFSx, FL_RC }, + { "mfmsr", D_OP(31)|D_XO(83), M_RT, F_RT, 0 }, + { "mfspr", D_OP(31)|D_XO(339), M_RT|M_SPR, F_RT_SPR, 0 }, + { "mfsr", D_OP(31)|D_XO(595), M_RT|M_SR, F_MFSR, 0 }, + { "mfsrin", D_OP(31)|D_XO(659), M_RT|M_RB, F_RT_RB, 0 }, + { "mftb", D_OP(31)|D_XO(371), M_RT|M_TBR, F_RT_SPR, 0 }, + { "mtcrf", D_OP(31)|D_XO(144), M_RT|M_CRM, F_MTCRF, 0 }, + { "mtdcr", D_OP(31)|D_XO(451), M_RT|M_DCR, F_MTDCR, 0 }, + { "mtfsb0", D_OP(63)|D_XO(70), M_CRBD|M_RC, F_FCRBD, FL_RC }, + { "mtfsb1", D_OP(63)|D_XO(38), M_CRBD|M_RC, F_FCRBD, FL_RC }, + { "mtfsf", D_OP(63)|D_XO(711), M_FM|M_RB|M_RC, F_MTFSFx, FL_RC }, + { "mtfsfi", D_OP(63)|D_XO(134), M_CRFD|M_IMM|M_RC, F_MTFSFIx, FL_RC }, + { "mtmsr", D_OP(31)|D_XO(146), M_RT, F_RT, 0 }, + { "mtspr", D_OP(31)|D_XO(467), M_RT|M_SPR, F_MTSPR, 0 }, + { "mtsr", D_OP(31)|D_XO(210), M_RT|M_SR, F_MTSR, 0 }, + { "mtsrin", D_OP(31)|D_XO(242), M_RT|M_RB, F_RT_RB, 0 }, + { "mulhw", D_OP(31)|D_XO(75), M_RT|M_RA|M_RB|M_RC, F_RT_RA_RB, FL_RC }, + { "mulhwu", D_OP(31)|D_XO(11), M_RT|M_RA|M_RB|M_RC, F_RT_RA_RB, FL_RC }, + { "mulli", D_OP(7), M_RT|M_RA|M_SIMM, F_RT_RA_SIMM, 0 }, + { "mullw", D_OP(31)|D_XO(235), M_RT|M_RA|M_RB|M_OE|M_RC, F_RT_RA_RB, FL_OE|FL_RC }, + { "nand", D_OP(31)|D_XO(476), M_RA|M_RT|M_RB|M_RC, F_RA_RT_RB, FL_RC }, + { "neg", D_OP(31)|D_XO(104), M_RT|M_RA|M_OE|M_RC, F_RT_RA, FL_OE|FL_RC }, + { "nor", D_OP(31)|D_XO(124), M_RT|M_RA|M_RB|M_RC, F_RA_RT_RB, FL_RC }, + { "or", D_OP(31)|D_XO(444), M_RT|M_RA|M_RB|M_RC, F_RA_RT_RB, FL_RC }, + { "orc", D_OP(31)|D_XO(412), M_RT|M_RA|M_RB|M_RC, F_RA_RT_RB, FL_RC }, + { "ori", D_OP(24), M_RT|M_RA|M_UIMM, F_RA_RT_UIMM, 0 }, + { "oris", D_OP(25), M_RT|M_RA|M_UIMM, F_RA_RT_UIMM, 0 }, + { "rfi", D_OP(19)|D_XO(50), 0, F_NONE, 0 }, + { "rfci", D_OP(19)|D_XO(51), 0, F_NONE, 0 }, + { "rlwimi", D_OP(20), M_RT|M_RA|M_SH|M_MB|M_ME|M_RC, F_RA_RT_SH_MB_ME, FL_RC }, + { "rlwinm", D_OP(21), M_RT|M_RA|M_SH|M_MB|M_ME|M_RC, F_RA_RT_SH_MB_ME, FL_RC }, + { "rlwnm", D_OP(23), M_RT|M_RA|M_RB|M_MB|M_ME|M_RC, F_RLWNMx, FL_RC }, + { "sc", D_OP(17)|2, 0, F_NONE, 0 }, + { "slw", D_OP(31)|D_XO(24), M_RT|M_RA|M_RB|M_RC, F_RA_RT_RB, FL_RC }, + { "sraw", D_OP(31)|D_XO(792), M_RT|M_RA|M_RB|M_RC, F_RA_RT_RB, FL_RC }, + { "srawi", D_OP(31)|D_XO(824), M_RT|M_RA|M_SH|M_RC, F_SRAWIx, FL_RC }, + { "srw", D_OP(31)|D_XO(536), M_RT|M_RA|M_RB|M_RC, F_RA_RT_RB, FL_RC }, + { "stb", D_OP(38), M_RT|M_RA|M_D, F_RT_D_RA_0, 0 }, + { "stbu", D_OP(39), M_RT|M_RA|M_D, F_RT_D_RA, FL_CHECK_RA }, + { "stbux", D_OP(31)|D_XO(247), M_RT|M_RA|M_RB, F_RT_RA_RB, FL_CHECK_RA }, + { "stbx", D_OP(31)|D_XO(215), M_RT|M_RA|M_RB, F_RT_RA_0_RB, 0 }, + { "stfd", D_OP(54), M_RT|M_RA|M_D, F_FRT_D_RA_0, 0 }, + { "stfdu", D_OP(55), M_RT|M_RA|M_D, F_FRT_D_RA, FL_CHECK_RA }, + { "stfdux", D_OP(31)|D_XO(759), M_RT|M_RA|M_RB, F_FRT_RA_RB, FL_CHECK_RA }, + { "stfdx", D_OP(31)|D_XO(727), M_RT|M_RA|M_RB, F_FRT_RA_0_RB, 0 }, + { "stfiwx", D_OP(31)|D_XO(983), M_RT|M_RA|M_RB, F_FRT_RA_0_RB, 0 }, + { "stfs", D_OP(52), M_RT|M_RA|M_D, F_FRT_D_RA_0, 0 }, + { "stfsu", D_OP(53), M_RT|M_RA|M_D, F_FRT_D_RA, FL_CHECK_RA }, + { "stfsux", D_OP(31)|D_XO(695), M_RT|M_RA|M_RB, F_FRT_RA_RB, FL_CHECK_RA }, + { "stfsx", D_OP(31)|D_XO(663), M_RT|M_RA|M_RB, F_FRT_RA_0_RB, 0 }, + { "sth", D_OP(44), M_RT|M_RA|M_D, F_RT_D_RA_0, 0 }, + { "sthbrx", D_OP(31)|D_XO(918), M_RT|M_RA|M_RB, F_RT_RA_0_RB, 0 }, + { "sthu", D_OP(45), M_RT|M_RA|M_D, F_RT_D_RA, FL_CHECK_RA }, + { "sthux", D_OP(31)|D_XO(439), M_RT|M_RA|M_RB, F_RT_RA_RB, FL_CHECK_RA }, + { "sthx", D_OP(31)|D_XO(407), M_RT|M_RA|M_RB, F_RT_RA_0_RB, 0 }, + { "stmw", D_OP(47), M_RT|M_RA|M_D, F_RT_D_RA_0, 0 }, + { "stswi", D_OP(31)|D_XO(725), M_RT|M_RA|M_NB, F_RT_RA_0_NB, 0 }, + { "stswx", D_OP(31)|D_XO(661), M_RT|M_RA|M_RB, F_RT_RA_0_RB, 0 }, + { "stw", D_OP(36), M_RT|M_RA|M_D, F_RT_D_RA_0, 0 }, + { "stwbrx", D_OP(31)|D_XO(662), M_RT|M_RA|M_RB, F_RT_RA_0_RB, 0 }, + { "stwcx.", D_OP(31)|D_XO(150)|1, M_RT|M_RA|M_RB, F_RT_RA_0_RB, 0 }, + { "stwu", D_OP(37), M_RT|M_RA|M_D, F_RT_D_RA, FL_CHECK_RA }, + { "stwux", D_OP(31)|D_XO(183), M_RT|M_RA|M_RB, F_RT_RA_RB, FL_CHECK_RA }, + { "stwx", D_OP(31)|D_XO(151), M_RT|M_RA|M_RB, F_RT_RA_0_RB, 0 }, + { "subf", D_OP(31)|D_XO(40), M_RT|M_RA|M_RB|M_OE|M_RC, F_RT_RA_RB, FL_OE|FL_RC }, + { "subfc", D_OP(31)|D_XO(8), M_RT|M_RA|M_RB|M_OE|M_RC, F_RT_RA_RB, FL_OE|FL_RC }, + { "subfe", D_OP(31)|D_XO(136), M_RT|M_RA|M_RB|M_OE|M_RC, F_RT_RA_RB, FL_OE|FL_RC }, + { "subfic", D_OP(8), M_RT|M_RA|M_SIMM, F_RT_RA_SIMM, 0 }, + { "subfme", D_OP(31)|D_XO(232), M_RT|M_RA|M_OE|M_RC, F_RT_RA, FL_OE|FL_RC }, + { "subfze", D_OP(31)|D_XO(200), M_RT|M_RA|M_OE|M_RC, F_RT_RA, FL_OE|FL_RC }, + { "sync", D_OP(31)|D_XO(598), 0, F_NONE, 0 }, + { "tlbia", D_OP(31)|D_XO(370), 0, F_NONE, 0 }, + { "tlbie", D_OP(31)|D_XO(306), M_RB, F_RB, 0 }, + { "tlbsync",D_OP(31)|D_XO(566), 0, F_NONE, 0 }, + { "tw", D_OP(31)|D_XO(4), M_TO|M_RA|M_RB, F_TW, 0 }, + { "twi", D_OP(3), M_TO|M_RA|M_SIMM, F_TWI, 0 }, + { "wrtee", D_OP(31)|D_XO(131), M_RT, F_RT, 0 }, + { "wrteei", D_OP(31)|D_XO(163), 0, 0, 0 }, + { "xor", D_OP(31)|D_XO(316), M_RT|M_RA|M_RB|M_RC, F_RA_RT_RB, FL_RC }, + { "xori", D_OP(26), M_RT|M_RA|M_UIMM, F_RA_RT_UIMM, 0 }, + { "xoris", D_OP(27), M_RT|M_RA|M_UIMM, F_RA_RT_UIMM, 0 }, + + /* + * PowerPC 603e/EC603e-specific instructions + */ + + { "tlbld", D_OP(31)|D_XO(978), M_RB, F_RB, 0 }, + { "tlbli", D_OP(31)|D_XO(1010),M_RB, F_RB, 0 } +}; + +/* + * CR Bits + * + * Use an index of BI&3 into this table to obtain the CR field bit name. + */ + +static const char *const crbit[4] = { "lt", "gt", "eq", "so" }; +static const char *const crnbit[4] = { "ge", "le", "ne", "nso" }; + + +/* + * SPR(): + * + * Decode the SPR (or TBR) field and append the register name to dest. If + * no name is associated with the field value, the value itself is printed. + */ + +static void SPR(char *dest, int spr_field) +{ + int spr; + + /* + * Construct the SPR number -- SPR field is 2 5-bit fields + */ + + spr = (spr_field >> 5) & 0x1f; + spr |= (spr_field & 0x1f) << 5; + + /* + * Append the SPR name to the destination string using strcat() + */ + + switch (spr) + { + /* UISA SPR register indexes */ + case SPR_XER: strcat(dest, "xer"); break; + case SPR_LR: strcat(dest, "lr"); break; + case SPR_CTR: strcat(dest, "ctr"); break; + + /* VEA SPR register indexes */ + case SPRVEA_TBL_R: strcat(dest, "tbl"); break; + case SPRVEA_TBU_R: strcat(dest, "tbu"); break; + + /* OEA SPR register indexes */ + case SPROEA_DSISR: strcat(dest, "dsisr"); break; + case SPROEA_DAR: strcat(dest, "dar"); break; + case SPROEA_DEC: strcat(dest, "dec"); break; + case SPROEA_SDR1: strcat(dest, "sdr1"); break; + case SPROEA_SRR0: strcat(dest, "srr0"); break; + case SPROEA_SRR1: strcat(dest, "srr1"); break; + case SPROEA_SPRG0: strcat(dest, "sprg0"); break; + case SPROEA_SPRG1: strcat(dest, "sprg1"); break; + case SPROEA_SPRG2: strcat(dest, "sprg2"); break; + case SPROEA_SPRG3: strcat(dest, "sprg3"); break; + case SPROEA_ASR: strcat(dest, "asr"); break; + case SPROEA_EAR: strcat(dest, "ear"); break; + case SPROEA_PVR: strcat(dest, "pvr"); break; + case SPROEA_IBAT0U: strcat(dest, "ibat0u"); break; + case SPROEA_IBAT0L: strcat(dest, "ibat0l"); break; + case SPROEA_IBAT1U: strcat(dest, "ibat1u"); break; + case SPROEA_IBAT1L: strcat(dest, "ibat1l"); break; + case SPROEA_IBAT2U: strcat(dest, "ibat2u"); break; + case SPROEA_IBAT2L: strcat(dest, "ibat2l"); break; + case SPROEA_IBAT3U: strcat(dest, "ibat3u"); break; + case SPROEA_IBAT3L: strcat(dest, "ibat3l"); break; + case SPROEA_DBAT0U: strcat(dest, "dbat0u"); break; + case SPROEA_DBAT0L: strcat(dest, "dbat0l"); break; + case SPROEA_DBAT1U: strcat(dest, "dbat1u"); break; + case SPROEA_DBAT1L: strcat(dest, "dbat1l"); break; + case SPROEA_DBAT2U: strcat(dest, "dbat2u"); break; + case SPROEA_DBAT2L: strcat(dest, "dbat2l"); break; + case SPROEA_DBAT3U: strcat(dest, "dbat3u"); break; + case SPROEA_DBAT3L: strcat(dest, "dbat3l"); break; + case SPROEA_DABR: strcat(dest, "dabr/iac2"); break; // unsupported on 603e/EC603e + + /* PowerPC 603E SPR register indexes */ + case SPR603_HID0: strcat(dest, "hid0/dbsr"); break; + case SPR603_HID1: strcat(dest, "hid1"); break; + case SPR603_DMISS: strcat(dest, "dmiss"); break; + case SPR603_DCMP: strcat(dest, "dcmp"); break; + case SPR603_HASH1: strcat(dest, "hash1"); break; + case SPR603_HASH2: strcat(dest, "hash2/icdbdr"); break; + case SPR603_IMISS: strcat(dest, "imiss"); break; + case SPR603_ICMP: strcat(dest, "icmp/dear"); break; + case SPR603_RPA: strcat(dest, "rpa/evpr"); break; + case SPR603_IABR: strcat(dest, "iabr/dbcr"); break; + + /* PowerPC 4XX SPR register indexes */ + case SPR4XX_SGR: strcat(dest, "sgr"); break; + case SPR4XX_DCWR: strcat(dest, "dcwr"); break; + case SPR4XX_PID: strcat(dest, "pid"); break; + case SPR4XX_TBHU: strcat(dest, "tbhu"); break; + case SPR4XX_TBLU: strcat(dest, "tblu"); break; +// case SPR4XX_ICDBDR: strcat(dest, "icdbdr"); break; // same as SPR603E_HASH2 +// case SPR4XX_DEAR: strcat(dest, "dear"); break; // same as SPR603E_ICMP +// case SPR4XX_EVPR: strcat(dest, "evpr"); break; // same as SPR603E_RPA + case SPR4XX_CDBCR: strcat(dest, "cdbcr"); break; + case SPR4XX_TSR: strcat(dest, "tsr"); break; + case SPR4XX_TCR: strcat(dest, "tcr"); break; + case SPR4XX_PIT: strcat(dest, "pit"); break; + case SPR4XX_TBHI: strcat(dest, "tbhi"); break; + case SPR4XX_TBLO: strcat(dest, "tblo"); break; + case SPR4XX_SRR2: strcat(dest, "srr2"); break; + case SPR4XX_SRR3: strcat(dest, "srr3"); break; +// case SPR4XX_DBSR: strcat(dest, "dbsr"); break; // same as SPR603E_HID0 +// case SPR4XX_DBCR: strcat(dest, "dbcr"); break; // same as SPR603E_IABR + case SPR4XX_IAC1: strcat(dest, "iac1"); break; +// case SPR4XX_IAC2: strcat(dest, "iac2"); break; // same as SPROEA_DABR + case SPR4XX_DAC1: strcat(dest, "dac1"); break; + case SPR4XX_DAC2: strcat(dest, "dac2"); break; + case SPR4XX_DCCR: strcat(dest, "dccr"); break; + case SPR4XX_ICCR: strcat(dest, "iccr"); break; + case SPR4XX_PBL1: strcat(dest, "pbl1"); break; + case SPR4XX_PBU1: strcat(dest, "pbu1"); break; + case SPR4XX_PBL2: strcat(dest, "pbl2"); break; + case SPR4XX_PBU2: strcat(dest, "pbu2"); break; + + default: sprintf(dest + strlen(dest), "%d", spr); break; + } +} + +static void DCR(char *dest, int dcr_field) +{ + int dcr; + + /* + * Construct the DCR number -- DCR field is 2 5-bit fields + */ + + dcr = (dcr_field >> 5) & 0x1f; + dcr |= (dcr_field & 0x1f) << 5; + + /* + * Append the DCR name to the destination string using strcat() + */ + + switch (dcr) + { + case 144: strcat(dest, "bear"); break; + case 145: strcat(dest, "besr"); break; + case 128: strcat(dest, "br0"); break; + case 129: strcat(dest, "br1"); break; + case 130: strcat(dest, "br2"); break; + case 131: strcat(dest, "br3"); break; + case 132: strcat(dest, "br4"); break; + case 133: strcat(dest, "br5"); break; + case 134: strcat(dest, "br6"); break; + case 135: strcat(dest, "br7"); break; + case 112: strcat(dest, "brh0"); break; + case 113: strcat(dest, "brh1"); break; + case 114: strcat(dest, "brh2"); break; + case 115: strcat(dest, "brh3"); break; + case 116: strcat(dest, "brh4"); break; + case 117: strcat(dest, "brh5"); break; + case 118: strcat(dest, "brh6"); break; + case 119: strcat(dest, "brh7"); break; + case 196: strcat(dest, "dmacc0"); break; + case 204: strcat(dest, "dmacc1"); break; + case 212: strcat(dest, "dmacc2"); break; + case 220: strcat(dest, "dmacc3"); break; + case 192: strcat(dest, "dmacr0"); break; + case 200: strcat(dest, "dmacr1"); break; + case 208: strcat(dest, "dmacr2"); break; + case 216: strcat(dest, "dmacr3"); break; + case 193: strcat(dest, "dmact0"); break; + case 201: strcat(dest, "dmact1"); break; + case 209: strcat(dest, "dmact2"); break; + case 217: strcat(dest, "dmact3"); break; + case 194: strcat(dest, "dmada0"); break; + case 202: strcat(dest, "dmada1"); break; + case 210: strcat(dest, "dmada2"); break; + case 218: strcat(dest, "dmada3"); break; + case 195: strcat(dest, "dmasa0"); break; + case 203: strcat(dest, "dmasa1"); break; + case 211: strcat(dest, "dmasa2"); break; + case 219: strcat(dest, "dmasa3"); break; + case 224: strcat(dest, "dmasr"); break; + case 66: strcat(dest, "exier"); break; + case 64: strcat(dest, "exisr"); break; + case 160: strcat(dest, "iocr"); break; + + default: sprintf(dest + strlen(dest), "%d", dcr); break; + } +} + + +/* + * DecodeSigned16(): + * + * Predecodes the SIMM field for us. If do_unsigned, it is printed as an + * unsigned 16-bit integer. + */ + +static void DecodeSigned16(char *outbuf, UINT32 op, int do_unsigned) +{ + INT16 s; + + s = G_SIMM(op); + if (do_unsigned) // sign extend to unsigned 32-bits + sprintf(outbuf, "0x%04X", (UINT32) s); + else // print as signed 16 bits + { + if (s < 0) + { + s *= -1; + sprintf(outbuf, "-0x%04X", s); + } + else + sprintf(outbuf, "0x%04X",s); + } +} + +/* + * Mask(): + * + * Generate a mask from bit MB through ME (PPC-style backwards bit numbering.) + */ + +static UINT32 Mask(int mb, int me) +{ + UINT32 i, mask; + + mb &= 31; + me &= 31; + + i = mb; + mask = 0; + while (1) + { + mask |= (1 << (31 - i)); + if (i == me) + break; + i = (i + 1) & 31; + } + + return mask; +} + +/* + * Check(): + * + * Perform checks on the instruction as required by the flags. Returns 1 if + * the instruction failed. + */ + +#if 0 +static int Check(UINT32 op, int flags) +{ + int nb, rt, ra; + + if( !flags ) return 0; // nothing to check for! + + rt = G_RT(op); + ra = G_RA(op); + + if (flags & FL_CHECK_RA_RT) // invalid if rA==0 or rA==rT + { + if ((G_RA(op) == 0) || (G_RA(op) == G_RT(op))) + return 1; + } + + if (flags & FL_CHECK_RA) // invalid if rA==0 + { + if (G_RA(op) == 0) + return 1; + } + + if (flags & FL_CHECK_LSWI) + { + /* + * Check that rA is not in the range of registers to be loaded (even + * if rA == 0) + */ + + nb = G_NB(op); + + if (ra >= rt && ra <= (rt + nb - 1)) return 1; + if ((rt + nb - 1) > 31) // register wrap-around! + { + if (ra < ((rt + nb - 1) - 31)) + return 1; + } + } + + if (flags & FL_CHECK_LSWX) + { + /* + * Check that rT != rA, rT != rB, and rD and rA both do not specify + * R0. + * + * We cannot check fully whether rA or rB are in the range of + * registers specified to be loaded because that depends on XER. + */ + + if (rt == ra || rt == G_RB(op) || ((rt == 0) && (ra == 0))) + return 1; + } + + return 0; // passed checks +} +#endif +/* + * Simplified(): + * + * Handles all simplified instruction forms. Returns 1 if one was decoded, + * otherwise 0 to indicate disassembly should carry on as normal. + */ + +static int Simplified(UINT32 op, UINT32 vpc, char *signed16, char *mnem, char *oprs) +{ + UINT32 value, disp; + + value = G_SIMM(op); // value is fully sign-extended SIMM field + if (value & 0x8000) + value |= 0xffff0000; + + if (op == (D_OP(24)|D_RT(0)|D_RA(0)|D_UIMM(0))) + strcat(mnem, "nop"); // ori r0,r0,0 -> nop + else if ((op & ~(M_RT|M_RA|M_RB|M_RC)) == (D_OP(31)|D_XO(444))) + { + if (G_RT(op) == G_RB(op)) + { + strcat(mnem, "mr"); // orx rA,rT,rT -> mrx rA,rT + if (op & M_RC) strcat(mnem, "."); + sprintf(oprs, "r%d,r%d", G_RA(op), G_RT(op)); + } + else + return 0; + } + else if ((op & ~(M_RT|M_RA|M_RB|M_RC)) == (D_OP(31)|D_XO(124))) + { + if (G_RT(op) == G_RB(op)) + { + strcat(mnem, "not"); // nor rA,rT,rT -> not rA,rT + if (op & M_RC) strcat(mnem, "."); + sprintf(oprs, "r%d,r%d", G_RA(op), G_RT(op)); + } + else + return 0; + } + else if ((op & ~(M_RT|M_RA|M_SIMM)) == D_OP(14)) + { + if (G_RA(op) == 0) + { + strcat(mnem, "li"); // addi rT,0,value -> li rT,value + sprintf(oprs, "r%d,0x%08X", G_RT(op), value); + } + else + return 0; + } + else if ((op & ~(M_RT|M_RA|M_SIMM)) == D_OP(15)) + { + if (G_RA(op) == 0) + { + strcat(mnem, "li"); // addis rT,0,value -> li rT,(value<<16) + sprintf(oprs, "r%d,0x%08X", G_RT(op), value << 16); + } + else + { + strcat(mnem, "addi"); // addis rT,rA,SIMM -> addi rT,rA,SIMM<<16 + sprintf(oprs, "r%d,r%d,0x%08X", G_RT(op), G_RA(op), value << 16); + } + } + else if ((op & ~(M_RT|M_RA|M_UIMM)) == D_OP(29)) + { + strcat(mnem, "andi."); // andis. rA,rT,UIMM -> andi. rA,rT,UIMM<<16 + sprintf(oprs, "r%d,r%d,0x%08X", G_RA(op), G_RT(op), G_UIMM(op) << 16); + } + else if ((op & ~(M_RT|M_RA|M_UIMM)) == D_OP(25)) + { + strcat(mnem, "ori"); // oris rA,rT,UIMM -> ori rA,rT,UIMM<<16 + sprintf(oprs, "r%d,r%d,0x%08X", G_RA(op), G_RT(op), G_UIMM(op) << 16); + } + else if ((op & ~(M_RT|M_RA|M_UIMM)) == D_OP(27)) + { + strcat(mnem, "xori"); // xoris rA,rT,UIMM -> xori rA,rT,UIMM<<16 + sprintf(oprs, "r%d,r%d,0x%08X", G_RA(op), G_RT(op), G_UIMM(op) << 16); + } + else if ((op & ~(M_RT|M_RA|M_SH|M_MB|M_ME|M_RC)) == D_OP(20)) + { + value = Mask(G_MB(op), G_ME(op)); + strcat(mnem, "rlwimi"); // rlwimi[.] rA,rT,SH,MB,ME -> rlwimi[.] rA,rT,SH,MASK + if (op & M_RC) strcat(mnem, "."); + sprintf(oprs, "r%d,r%d,%d,0x%08X", G_RA(op), G_RT(op), G_SH(op), value); + } + else if ((op & ~(M_RT|M_RA|M_SH|M_MB|M_ME|M_RC)) == D_OP(21)) + { + value = Mask(G_MB(op), G_ME(op)); + if (G_SH(op) == 0) // rlwinm[.] rA,rT,0,MB,ME -> and[.] rA,rT,MASK + { + strcat(mnem, "and"); + if (op & M_RC) strcat(mnem, "."); + sprintf(oprs, "r%d,r%d,0x%08X", G_RA(op), G_RT(op), value); + } + else // rlwinm[.] rA,rT,SH,MASK + { + strcat(mnem, "rlwinm"); + if (op & M_RC) strcat(mnem, "."); + sprintf(oprs, "r%d,r%d,%d,0x%08X", G_RA(op), G_RT(op), G_SH(op), value); + } + } + else if ((op & ~(M_RT|M_RA|M_RB|M_MB|M_ME|M_RC)) == D_OP(23)) + { + value = Mask(G_MB(op), G_ME(op)); + strcat(mnem, "rlwnm"); // rlwnm[.] rA,rT,SH,MB,ME -> rlwnm[.] rA,rT,SH,MASK + if (op & M_RC) strcat(mnem, "."); + sprintf(oprs, "r%d,r%d,r%d,0x%08X", G_RA(op), G_RT(op), G_RB(op), value); + } + else if ((op & ~(M_BO|M_BI|M_BD|M_AA|M_LK)) == D_OP(16)) + { + disp = G_BD(op) * 4; + if (disp & 0x00008000) + disp |= 0xffff0000; + + switch (G_BO(op)) + { + case 0x04: case 0x05: case 0x06: case 0x07: + strcat(mnem, "b"); + strcat(mnem, crnbit[G_BI(op) & 3]); + break; + case 0x0c: case 0x0d: case 0x0e: case 0x0f: + strcat(mnem, "b"); + strcat(mnem, crbit[G_BI(op) & 3]); + break; + case 0x10: case 0x11: case 0x18: case 0x19: + strcat(mnem, "bdnz"); + break; + case 0x12: case 0x13: case 0x1a: case 0x1b: + strcat(mnem, "bdz"); + break; + case 0x14: case 0x15: case 0x16: case 0x17: + case 0x1c: case 0x1d: case 0x1e: case 0x1f: + strcat(mnem, "b"); + break; + default: + return 0; + } + + if (op & M_LK) strcat(mnem, "l"); + if (op & M_AA) strcat(mnem, "a"); + + if (!(G_BO(op) & 0x10) && G_BI(op) / 4 != 0) + sprintf(oprs, "cr%d,0x%08X", G_BI(op) / 4, disp + ((op & M_AA) ? 0 : vpc)); + else + sprintf(oprs, "0x%08X", disp + ((op & M_AA) ? 0 : vpc)); + } + else if ((op & ~(M_BO|M_BI|M_LK)) == (D_OP(19)|D_XO(528)) || (op & ~(M_BO|M_BI|M_LK)) == (D_OP(19)|D_XO(16))) + { + switch (G_BO(op)) + { + case 0x04: case 0x05: case 0x06: case 0x07: + strcat(mnem, "b"); + strcat(mnem, crnbit[G_BI(op) & 3]); + break; + case 0x0c: case 0x0d: case 0x0e: case 0x0f: + strcat(mnem, "b"); + strcat(mnem, crbit[G_BI(op) & 3]); + break; + case 0x10: case 0x11: case 0x18: case 0x19: + strcat(mnem, "bdnz"); + break; + case 0x12: case 0x13: case 0x1a: case 0x1b: + strcat(mnem, "bdz"); + break; + case 0x14: case 0x15: case 0x16: case 0x17: + case 0x1c: case 0x1d: case 0x1e: case 0x1f: + strcat(mnem, "b"); + break; + default: + return 0; + } + + strcat(mnem, (G_XO(op) == 528) ? "ctr" : "lr"); + if (op & M_LK) strcat(mnem, "l"); + if (op & M_AA) strcat(mnem, "a"); + + if (!(G_BO(op) & 0x10) && G_BI(op) / 4 != 0) + sprintf(oprs, "cr%d", G_BI(op) / 4); + } + else if ((op & ~(M_RT|M_RA|M_RB|M_OE|M_RC)) == (D_OP(31)|D_XO(40))) + { + strcat(mnem, "sub"); + if (op & M_OE) strcat(mnem, "o"); + if (op & M_RC) strcat(mnem, "."); + sprintf(oprs, "r%d,r%d,r%d", G_RT(op), G_RB(op), G_RA(op)); + } + else if ((op & ~(M_RT|M_RA|M_RB|M_OE|M_RC)) == (D_OP(31)|D_XO(8))) + { + strcat(mnem, "subc"); + if (op & M_OE) strcat(mnem, "o"); + if (op & M_RC) strcat(mnem, "."); + sprintf(oprs, "r%d,r%d,r%d", G_RT(op), G_RB(op), G_RA(op)); + } + else + return 0; // no match + + return 1; +} + +offs_t ppc_dasm_one(char *buffer, UINT32 pc, UINT32 op) +{ + char signed16[12]; + UINT32 disp; + int i,j; + char mnem[200]; + char oprs[200]; + offs_t flags = DASMFLAG_SUPPORTED; + + mnem[0] = '\0'; // so we can use strcat() + oprs[0] = '\0'; + + /* + * Decode signed 16-bit fields (SIMM and d) to spare us the work later + */ + + DecodeSigned16(signed16, op, 0); + + /* + * Try simplified forms first, then real instructions + */ + + if( Simplified(op, pc, signed16, mnem, oprs) ) { + buffer += sprintf(buffer, "%s", mnem); + for( j = strlen(mnem); j < 10; j++ ) { + buffer += sprintf(buffer, " "); + } + buffer += sprintf(buffer, "%s", oprs); + return 4 | flags; + } + + /* + * Search for the instruction in the list and print it if there's a match + */ + + for (i = 0; i < sizeof(itab) / sizeof(IDESCR); i++) + { + if ((op & ~itab[i].mask) == itab[i].match) // check for match + { + /* + * Base mnemonic followed be O, ., L, A + */ + + strcat(mnem, itab[i].mnem); + if (itab[i].flags & FL_OE) if (op & M_OE) strcat(mnem, "o"); + if (itab[i].flags & FL_RC) if (op & M_RC) strcat(mnem, "."); + if (itab[i].flags & FL_LK) if (op & M_LK) strcat(mnem, "l"); + if (itab[i].flags & FL_AA) if (op & M_AA) strcat(mnem, "a"); + + /* + * Print operands + */ + + switch (itab[i].format) + { + case F_RT_RA_RB: + sprintf(oprs, "r%d,r%d,r%d", G_RT(op), G_RA(op), G_RB(op)); + break; + + case F_RT_RA_0_SIMM: + if (G_RA(op)) + sprintf(oprs, "r%d,r%d,%s", G_RT(op), G_RA(op), signed16); + else + sprintf(oprs, "r%d,0,%s", G_RT(op), signed16); + break; + + case F_ADDIS: + if (G_RA(op)) + sprintf(oprs, "r%d,r%d,0x%04X", G_RT(op), G_RA(op), G_SIMM(op)); + else + sprintf(oprs, "r%d,0,0x%04X", G_RT(op), G_SIMM(op)); + break; + + case F_RT_RA_SIMM: + sprintf(oprs, "r%d,r%d,%s", G_RT(op), G_RA(op), signed16); + break; + + case F_RT_RA: + sprintf(oprs, "r%d,r%d", G_RT(op), G_RA(op)); + break; + + case F_RA_RT_RB: + sprintf(oprs, "r%d,r%d,r%d", G_RA(op), G_RT(op), G_RB(op)); + break; + + case F_RA_RT_UIMM: + sprintf(oprs, "r%d,r%d,0x%04X", G_RA(op), G_RT(op), G_UIMM(op)); + break; + + case F_LI: + disp = G_LI(op) * 4; + if (disp & 0x02000000) // sign extend + disp |= 0xfc000000; + sprintf(oprs, "0x%08X", disp + ((op & M_AA) ? 0 : pc)); + break; + + case F_BCx: + disp = G_BD(op) * 4; + if (disp & 0x00008000) + disp |= 0xffff0000; + + if (G_BO(op) & 0x10) // BI is ignored (don't print CR bit) + sprintf(oprs, "0x%02X,%d,0x%08X", G_BO(op), G_BI(op), disp + ((op & M_AA) ? 0 : pc)); + else // BI gives us the condition bit + sprintf(oprs, "0x%02X,cr%d[%s],0x%08X", G_BO(op), G_BI(op) / 4, crbit[G_BI(op) & 3], disp + ((op & M_AA) ? 0 : pc)); + break; + + case F_BO_BI: + if (G_BO(op) & 0x10) // BI is ignored (don't print CR bit) + sprintf(oprs, "0x%02X,%d", G_BO(op), G_BI(op)); + else + sprintf(oprs, "0x%02X,cr%d[%s]", G_BO(op), G_BI(op) / 4, crbit[G_BI(op) & 3]); + break; + + case F_CMP: + if (G_L(op)) + strcat(mnem, "d"); + if (G_CRFD(op) == 0) + sprintf(oprs, "r%d,r%d", G_RA(op), G_RB(op)); + else + sprintf(oprs, "cr%d,r%d,r%d", G_CRFD(op), G_RA(op), G_RB(op)); + break; + + case F_CMP_SIMM: + if (G_L(op)) + strcat(mnem, "d"); + if (G_CRFD(op) == 0) + sprintf(oprs, "r%d,%s", G_RA(op), signed16); + else + sprintf(oprs, "cr%d,r%d,%s", G_CRFD(op), G_RA(op), signed16); + break; + + case F_CMP_UIMM: + if (G_L(op)) + strcat(mnem, "d"); + if (G_CRFD(op) == 0) + sprintf(oprs, "r%d,0x%04X", G_RA(op), G_UIMM(op)); + else + sprintf(oprs, "cr%d,r%d,0x%04X", G_CRFD(op), G_RA(op), G_UIMM(op)); + break; + + case F_RA_RT: + sprintf(oprs, "r%d,r%d", G_RA(op), G_RT(op)); + break; + + case F_CRBD_CRBA_CRBB: + sprintf(oprs, "cr%d[%s],cr%d[%s],cr%d[%s]", G_CRBD(op) / 4, crbit[G_CRBD(op) & 3], G_CRBA(op) / 4, crbit[G_CRBA(op) & 3], G_CRBB(op) / 4, crbit[G_CRBB(op) & 3]); + break; + + case F_RA_0_RB: + if (G_RA(op)) + sprintf(oprs, "r%d,r%d", G_RA(op), G_RB(op)); + else + sprintf(oprs, "0,r%d", G_RB(op)); + break; + + case F_RT_RA_0_RB: + if (G_RA(op)) + sprintf(oprs, "r%d,r%d,r%d", G_RT(op), G_RA(op), G_RB(op)); + else + sprintf(oprs, "r%d,0,r%d", G_RT(op), G_RB(op)); + break; + + case F_FRT_FRB: + sprintf(oprs, "f%d,f%d", G_RT(op), G_RB(op)); + break; + + case F_FRT_FRA_FRB: + sprintf(oprs, "f%d,f%d,f%d", G_RT(op), G_RA(op), G_RB(op)); + break; + + case F_FCMP: + sprintf(oprs, "cr%d,f%d,f%d", G_CRFD(op), G_RA(op), G_RB(op)); + break; + + case F_FRT_FRA_FRC_FRB: + sprintf(oprs, "f%d,f%d,f%d,f%d", G_RT(op), G_RA(op), G_REGC(op), G_RB(op)); + break; + + case F_FRT_FRA_FRC: + sprintf(oprs, "f%d,f%d,f%d", G_RT(op), G_RA(op), G_REGC(op)); + break; + + case F_RT_D_RA_0: + if (G_RA(op)) + sprintf(oprs, "r%d,%s(r%d)", G_RT(op), signed16, G_RA(op)); + else + sprintf(oprs, "r%d,0x%08X", G_RT(op), (UINT32) ((INT16) G_D(op))); + break; + + case F_RT_D_RA: + sprintf(oprs, "r%d,%s(r%d)", G_RT(op), signed16, G_RA(op)); + break; + + case F_FRT_D_RA_0: + if (G_RA(op)) + sprintf(oprs, "f%d,%s(r%d)", G_RT(op), signed16, G_RA(op)); + else + sprintf(oprs, "f%d,0x%08X", G_RT(op), (UINT32) ((INT16) G_D(op))); + break; + + case F_FRT_D_RA: + sprintf(oprs, "f%d,%s(r%d)", G_RT(op), signed16, G_RA(op)); + break; + + case F_FRT_RA_RB: + sprintf(oprs, "f%d,r%d,r%d", G_RT(op), G_RA(op), G_RB(op)); + break; + + case F_FRT_RA_0_RB: + if (G_RA(op)) + sprintf(oprs, "f%d,r%d,r%d", G_RT(op), G_RA(op), G_RB(op)); + else + sprintf(oprs, "f%d,0,r%d", G_RT(op), G_RB(op)); + break; + + case F_RT_RA_0_NB: + if (G_RA(op)) + sprintf(oprs, "r%d,r%d,%d", G_RT(op), G_RA(op), G_NB(op) ? G_NB(op) : 32); + else + sprintf(oprs, "r%d,0,%d", G_RT(op), G_NB(op) ? G_NB(op) : 32); + break; + + case F_CRFD_CRFS: + sprintf(oprs, "cr%d,cr%d", G_CRFD(op), G_CRFS(op)); + break; + + case F_MCRXR: + sprintf(oprs, "cr%d", G_CRFD(op)); + break; + + case F_RT: + sprintf(oprs, "r%d", G_RT(op)); + break; + + case F_MFFSx: + sprintf(oprs, "f%d", G_RT(op)); + break; + + case F_FCRBD: + sprintf(oprs, "fpscr[%d]", G_CRBD(op)); + break; + + case F_RT_SPR: + sprintf(oprs, "r%d,", G_RT(op)); + SPR(oprs, G_SPR(op)); + break; + + case F_RT_DCR: + sprintf(oprs, "r%d,", G_RT(op)); + DCR(oprs, G_DCR(op)); + break; + + case F_MFSR: + sprintf(oprs, "r%d,sr%d", G_RT(op), G_SR(op)); + break; + + case F_MTCRF: + sprintf(oprs, "0x%02X,r%d", G_CRM(op), G_RT(op)); + break; + + case F_MTFSFx: + sprintf(oprs, "0x%02X,f%d", G_FM(op), G_RB(op)); + break; + + case F_MTFSFIx: + sprintf(oprs, "cr%d,0x%X", G_CRFD(op), G_IMM(op)); + break; + + case F_MTSPR: + SPR(oprs, G_SPR(op)); + sprintf(oprs + strlen(oprs), ",r%d", G_RT(op)); + break; + + case F_MTDCR: + DCR(oprs, G_DCR(op)); + sprintf(oprs + strlen(oprs), ",r%d", G_RT(op)); + break; + + case F_MTSR: + sprintf(oprs, "sr%d,r%d", G_SR(op), G_RT(op)); + break; + + case F_RT_RB: + sprintf(oprs, "r%d,r%d", G_RT(op), G_RB(op)); + break; + + case F_RA_RT_SH_MB_ME: + sprintf(oprs, "r%d,r%d,%d,%d,%d", G_RA(op), G_RT(op), G_SH(op), G_MB(op), G_ME(op)); + break; + + case F_RLWNMx: + sprintf(oprs, "r%d,r%d,r%d,%d,%d", G_RA(op), G_RT(op), G_RB(op), G_MB(op), G_ME(op)); + break; + + case F_SRAWIx: + sprintf(oprs, "r%d,r%d,%d", G_RA(op), G_RT(op), G_SH(op)); + break; + + case F_RB: + sprintf(oprs, "r%d", G_RB(op)); + break; + + case F_TW: + sprintf(oprs, "%d,r%d,r%d", G_TO(op), G_RA(op), G_RB(op)); + break; + + case F_TWI: + sprintf(oprs, "%d,r%d,%s", G_TO(op), G_RA(op), signed16); + break; + + case F_NONE: + default: + break; + } + + if ((itab[i].flags & FL_LK) && (op & M_LK)) + flags |= DASMFLAG_STEP_OVER; + else if (itab[i].flags & FL_SO) + flags |= DASMFLAG_STEP_OUT; + + buffer += sprintf(buffer, "%s", mnem); + for( j = strlen(mnem); j < 10; j++ ) { + buffer += sprintf(buffer, " "); + } + buffer += sprintf(buffer, "%s", oprs); + return 4 | flags; + } + } + + sprintf(buffer, "?"); + return 4 | flags; +} + +CPU_DISASSEMBLE( powerpc ) +{ + UINT32 op = *(UINT32 *)oprom; + op = BIG_ENDIANIZE_INT32(op); + return ppc_dasm_one(buffer, pc, op); +} diff --git a/src/devices/cpu/powerpc/ppc_mem.inc b/src/devices/cpu/powerpc/ppc_mem.inc new file mode 100644 index 00000000000..0f8851e4c5c --- /dev/null +++ b/src/devices/cpu/powerpc/ppc_mem.inc @@ -0,0 +1,421 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +#define DUMP_PAGEFAULTS 0 + +INLINE UINT8 READ8(UINT32 a) +{ + return ppc.read8(ppc.program, a); +} + +INLINE UINT16 READ16(UINT32 a) +{ + if( a & 0x1 ) + return ppc.read16_unaligned(ppc.program, a); + else + return ppc.read16(ppc.program, a); +} + +INLINE UINT32 READ32(UINT32 a) +{ + if( a & 0x3 ) + return ppc.read32_unaligned(ppc.program, a); + else + return ppc.read32(ppc.program, a); +} + +INLINE UINT64 READ64(UINT32 a) +{ + if( a & 0x7 ) + return ppc.read64_unaligned(ppc.program, a); + else + return ppc.read64(ppc.program, a); +} + +INLINE void WRITE8(UINT32 a, UINT8 d) +{ + ppc.write8(ppc.program, a, d); +} + +INLINE void WRITE16(UINT32 a, UINT16 d) +{ + if( a & 0x1 ) + ppc.write16_unaligned(ppc.program, a, d); + else + ppc.write16(ppc.program, a, d); +} + +INLINE void WRITE32(UINT32 a, UINT32 d) +{ + if( ppc.reserved ) { + if( a == ppc.reserved_address ) { + ppc.reserved = 0; + } + } + + if( a & 0x3 ) + ppc.write32_unaligned(ppc.program, a, d); + else + ppc.write32(ppc.program, a, d); +} + +INLINE void WRITE64(UINT32 a, UINT64 d) +{ + if( a & 0x7 ) + ppc.write64_unaligned(ppc.program, a, d); + else + ppc.write64(ppc.program, a, d); +} + +/***********************************************************************/ + +static UINT16 ppc_read16_unaligned(address_space &space, UINT32 a) +{ + return ((UINT16)ppc.read8(space, a+0) << 8) | ((UINT16)ppc.read8(space, a+1) << 0); +} + +static UINT32 ppc_read32_unaligned(address_space &space, UINT32 a) +{ + return ((UINT32)ppc.read8(space, a+0) << 24) | ((UINT32)ppc.read8(space, a+1) << 16) | + ((UINT32)ppc.read8(space, a+2) << 8) | ((UINT32)ppc.read8(space, a+3) << 0); +} + +static UINT64 ppc_read64_unaligned(address_space &space, UINT32 a) +{ + return ((UINT64)READ32(space, a+0) << 32) | (UINT64)(READ32(space, a+4)); +} + +static void ppc_write16_unaligned(address_space &space, UINT32 a, UINT16 d) +{ + ppc.write8(space, a+0, (UINT8)(d >> 8)); + ppc.write8(space, a+1, (UINT8)(d)); +} + +static void ppc_write32_unaligned(address_space &space, UINT32 a, UINT32 d) +{ + ppc.write8(space, a+0, (UINT8)(d >> 24)); + ppc.write8(space, a+1, (UINT8)(d >> 16)); + ppc.write8(space, a+2, (UINT8)(d >> 8)); + ppc.write8(space, a+3, (UINT8)(d >> 0)); +} + +static void ppc_write64_unaligned(address_space &space, UINT32 a, UINT64 d) +{ + ppc.write32(space, a+0, (UINT32)(d >> 32)); + ppc.write32(space, a+4, (UINT32)(d)); +} + +/***********************************************************************/ + +#define DSISR_PAGE 0x40000000 +#define DSISR_PROT 0x08000000 +#define DSISR_STORE 0x02000000 + +enum +{ + PPC_TRANSLATE_DATA = 0x0000, + PPC_TRANSLATE_CODE = 0x0001, + + PPC_TRANSLATE_READ = 0x0000, + PPC_TRANSLATE_WRITE = 0x0002, + + PPC_TRANSLATE_NOEXCEPTION = 0x0004 +}; + +static int ppc_is_protected(UINT32 pp, int flags) +{ + if (flags & PPC_TRANSLATE_WRITE) + { + if ((pp & 0x00000003) != 0x00000002) + return TRUE; + } + else + { + if ((pp & 0x00000003) == 0x00000000) + return TRUE; + } + return FALSE; +} + +static int ppc_translate_address(offs_t *addr_ptr, int flags) +{ + const BATENT *bat; + UINT32 address; + UINT32 sr, vsid, hash; + UINT32 pteg_address; + UINT32 target_pte, bl, mask; + UINT64 pte; + UINT64 *pteg_ptr[2]; + int i, hash_type; + UINT32 dsisr = DSISR_PROT; + + bat = (flags & PPC_TRANSLATE_CODE) ? ppc.ibat : ppc.dbat; + + address = *addr_ptr; + + /* first check the block address translation table */ + for (i = 0; i < 4; i++) + { + if (bat[i].u & ((MSR & MSR_PR) ? 0x00000001 : 0x00000002)) + { + bl = bat[i].u & 0x00001FFC; + mask = (~bl << 15) & 0xFFFE0000; + + if ((address & mask) == (bat[i].u & 0xFFFE0000)) + { + if (ppc_is_protected(bat[i].l, flags)) + goto exception; + + *addr_ptr = (bat[i].l & 0xFFFE0000) + | (address & ((bl << 15) | 0x0001FFFF)); + return 1; + } + } + } + + /* now try page address translation */ + sr = ppc.sr[(address >> 28) & 0x0F]; + if (sr & 0x80000000) + { + /* direct store translation */ + if ((flags & PPC_TRANSLATE_NOEXCEPTION) == 0) + fatalerror("ppc: direct store translation not yet implemented\n"); + return 0; + } + else + { + /* is no execute is set? */ + if ((flags & PPC_TRANSLATE_CODE) && (sr & 0x10000000)) + goto exception; + + vsid = sr & 0x00FFFFFF; + hash = (vsid & 0x0007FFFF) ^ ((address >> 12) & 0xFFFF); + target_pte = (vsid << 7) | ((address >> 22) & 0x3F) | 0x80000000; + + /* we have to try both types of hashes */ + for (hash_type = 0; hash_type <= 1; hash_type++) + { + pteg_address = (ppc.sdr1 & 0xFFFF0000) + | (((ppc.sdr1 & 0x01FF) & (hash >> 10)) << 16) + | ((hash & 0x03FF) << 6); + + pteg_ptr[hash_type] = ppc->program->get_read_ptr(pteg_address); + if (pteg_ptr[hash_type]) + { + for (i = 0; i < 8; i++) + { + pte = pteg_ptr[hash_type][i]; + + /* is valid? */ + if (((pte >> 32) & 0xFFFFFFFF) == target_pte) + { + if (ppc_is_protected((UINT32) pte, flags)) + goto exception; + + *addr_ptr = ((UINT32) (pte & 0xFFFFF000)) + | (address & 0x0FFF); + return 1; + } + } + } + + hash ^= 0x7FFFF; + target_pte ^= 0x40; + } + + if (DUMP_PAGEFAULTS) + { + osd_printf_debug("PAGE FAULT: address=%08X PC=%08X SDR1=%08X MSR=%08X\n", address, ppc.pc, ppc.sdr1, ppc.msr); + osd_printf_debug("\n"); + + for (i = 0; i < 4; i++) + { + bl = bat[i].u & 0x00001FFC; + mask = (~bl << 15) & 0xFFFE0000; + osd_printf_debug(" BAT[%d]=%08X%08X (A & %08X = %08X)\n", i, bat[i].u, bat[i].l, + mask, bat[i].u & 0xFFFE0000); + } + osd_printf_debug("\n"); + osd_printf_debug(" VSID=%06X HASH=%05X HASH\'=%05X\n", vsid, hash, hash ^ 0x7FFFF); + + for (hash_type = 0; hash_type <= 1; hash_type++) + { + if (pteg_ptr[hash_type]) + { + for (i = 0; i < 8; i++) + { + pte = pteg_ptr[hash_type][i]; + osd_printf_debug(" PTE[%i%c]=%08X%08X\n", + i, + hash_type ? '\'' : ' ', + (unsigned) (pte >> 32), + (unsigned) (pte >> 0)); + } + } + } + } + } + + dsisr = DSISR_PAGE; + +exception: + /* lookup failure - exception */ + if ((flags & PPC_TRANSLATE_NOEXCEPTION) == 0) + { + if (flags & PPC_TRANSLATE_CODE) + { + ppc_exception(EXCEPTION_ISI); + } + else + { + ppc.dar = address; + if (flags & PPC_TRANSLATE_WRITE) + ppc.dsisr = dsisr | DSISR_STORE; + else + ppc.dsisr = dsisr; + + ppc_exception(EXCEPTION_DSI); + } + } + return 0; +} + +static int ppc_translate_address_cb(address_spacenum space, offs_t *addr) +{ + int success = 1; + + if (space == AS_PROGRAM) + { + if (MSR & MSR_DR) + success = ppc_translate_address(addr, PPC_TRANSLATE_CODE | PPC_TRANSLATE_READ | PPC_TRANSLATE_NOEXCEPTION); + } + return success; +} + +static UINT8 ppc_read8_translated(address_space &space, offs_t address) +{ + ppc_translate_address(&address, PPC_TRANSLATE_DATA | PPC_TRANSLATE_READ); + return space.read_byte(address); +} + +static UINT16 ppc_read16_translated(address_space &space, offs_t address) +{ + ppc_translate_address(&address, PPC_TRANSLATE_DATA | PPC_TRANSLATE_READ); + return space.read_word(address); +} + +static UINT32 ppc_read32_translated(address_space &space, offs_t address) +{ + ppc_translate_address(&address, PPC_TRANSLATE_DATA | PPC_TRANSLATE_READ); + return space.read_dword(address); +} + +static UINT64 ppc_read64_translated(address_space &space, offs_t address) +{ + ppc_translate_address(&address, PPC_TRANSLATE_DATA | PPC_TRANSLATE_READ); + return space.read_qword(address); +} + +static void ppc_write8_translated(address_space &space, offs_t address, UINT8 data) +{ + ppc_translate_address(&address, PPC_TRANSLATE_DATA | PPC_TRANSLATE_WRITE); + space.write_byte(address, data); +} + +static void ppc_write16_translated(address_space &space, offs_t address, UINT16 data) +{ + ppc_translate_address(&address, PPC_TRANSLATE_DATA | PPC_TRANSLATE_WRITE); + space.write_word(address, data); +} + +static void ppc_write32_translated(address_space &space, offs_t address, UINT32 data) +{ + ppc_translate_address(&address, PPC_TRANSLATE_DATA | PPC_TRANSLATE_WRITE); + space.write_dword(address, data); +} + +static void ppc_write64_translated(address_space &space, offs_t address, UINT64 data) +{ + ppc_translate_address(&address, PPC_TRANSLATE_DATA | PPC_TRANSLATE_WRITE); + space.write_qword(address, data); +} + +#ifndef PPC_DRC +static UINT32 ppc_readop_translated(address_space &space, offs_t address) +{ + ppc_translate_address(&address, PPC_TRANSLATE_CODE | PPC_TRANSLATE_READ); + return space.read_dword(address); +} +#endif + +/***********************************************************************/ + + +static CPU_DISASSEMBLE( ppc ) +{ + UINT32 op; + op = BIG_ENDIANIZE_INT32(*((UINT32 *) oprom)); + return ppc_dasm_one(buffer, pc, op); +} + +/***********************************************************************/ + +static CPU_READOP( ppc ) +{ + if (!(ppc.msr & MSR_IR)) + return 0; + + *value = 0; + + if (ppc_translate_address(&offset, PPC_TRANSLATE_CODE | PPC_TRANSLATE_READ | PPC_TRANSLATE_NOEXCEPTION)) + { + switch(size) + { + case 1: *value = ppc.program->read_byte(offset); break; + case 2: *value = ppc.program->read_word(offset); break; + case 4: *value = ppc.program->read_dword(offset); break; + case 8: *value = ppc.program->read_qword(offset); break; + } + } + + return 1; +} + +static CPU_READ( ppc ) +{ + if (!(ppc.msr & MSR_DR)) + return 0; + + *value = 0; + + if (ppc_translate_address(&offset, PPC_TRANSLATE_DATA | PPC_TRANSLATE_READ | PPC_TRANSLATE_NOEXCEPTION)) + { + switch(size) + { + case 1: *value = ppc.program->read_byte(offset); break; + case 2: *value = ppc.program->read_word(offset); break; + case 4: *value = ppc.program->read_dword(offset); break; + case 8: *value = ppc.program->read_qword(offset); break; + } + } + + return 1; +} + +static CPU_WRITE( ppc ) +{ + if (!(ppc.msr & MSR_DR)) + return 0; + + if (ppc_translate_address(&offset, PPC_TRANSLATE_DATA | PPC_TRANSLATE_WRITE | PPC_TRANSLATE_NOEXCEPTION)) + { + switch(size) + { + case 1: ppc.program->write_byte(offset, value); break; + case 2: ppc.program->write_word(offset, value); break; + case 4: ppc.program->write_dword(offset, value); break; + case 8: ppc.program->write_qword(offset, value); break; + } + } + + return 1; +} diff --git a/src/devices/cpu/powerpc/ppc_ops.h b/src/devices/cpu/powerpc/ppc_ops.h new file mode 100644 index 00000000000..b44e92a016b --- /dev/null +++ b/src/devices/cpu/powerpc/ppc_ops.h @@ -0,0 +1,152 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +#pragma once + +#ifndef __PPC_OPS_H__ +#define __PPC_OPS_H__ + +static PPC_OPCODE ppc_opcode_common[] = +{ + /*code subcode handler */ + { 31, 266, ppc_addx }, + { 31, 266 | 512, ppc_addx }, + { 31, 10, ppc_addcx }, + { 31, 10 | 512, ppc_addcx }, + { 31, 138, ppc_addex }, + { 31, 138 | 512, ppc_addex }, + { 14, -1, ppc_addi }, + { 12, -1, ppc_addic }, + { 13, -1, ppc_addic_rc }, + { 15, -1, ppc_addis }, + { 31, 234, ppc_addmex }, + { 31, 234 | 512, ppc_addmex }, + { 31, 202, ppc_addzex }, + { 31, 202 | 512, ppc_addzex }, + { 31, 28, ppc_andx }, + { 31, 28 | 512, ppc_andx }, + { 31, 60, ppc_andcx }, + { 28, -1, ppc_andi_rc }, + { 29, -1, ppc_andis_rc }, + { 18, -1, ppc_bx }, + { 16, -1, ppc_bcx }, + { 19, 528, ppc_bcctrx }, + { 19, 16, ppc_bclrx }, + { 31, 0, ppc_cmp }, + { 11, -1, ppc_cmpi }, + { 31, 32, ppc_cmpl }, + { 10, -1, ppc_cmpli }, + { 31, 26, ppc_cntlzw }, + { 19, 257, ppc_crand }, + { 19, 129, ppc_crandc }, + { 19, 289, ppc_creqv }, + { 19, 225, ppc_crnand }, + { 19, 33, ppc_crnor }, + { 19, 449, ppc_cror }, + { 19, 417, ppc_crorc }, + { 19, 193, ppc_crxor }, + { 31, 86, ppc_dcbf }, + { 31, 470, ppc_dcbi }, + { 31, 54, ppc_dcbst }, + { 31, 278, ppc_dcbt }, + { 31, 246, ppc_dcbtst }, + { 31, 1014, ppc_dcbz }, + { 31, 491, ppc_divwx }, + { 31, 491 | 512, ppc_divwx }, + { 31, 459, ppc_divwux }, + { 31, 459 | 512, ppc_divwux }, + { 31, 854, ppc_eieio }, + { 31, 284, ppc_eqvx }, + { 31, 954, ppc_extsbx }, + { 31, 922, ppc_extshx }, + { 31, 982, ppc_icbi }, + { 19, 150, ppc_isync }, + { 34, -1, ppc_lbz }, + { 35, -1, ppc_lbzu }, + { 31, 119, ppc_lbzux }, + { 31, 87, ppc_lbzx }, + { 42, -1, ppc_lha }, + { 43, -1, ppc_lhau }, + { 31, 375, ppc_lhaux }, + { 31, 343, ppc_lhax }, + { 31, 790, ppc_lhbrx }, + { 40, -1, ppc_lhz }, + { 41, -1, ppc_lhzu }, + { 31, 311, ppc_lhzux }, + { 31, 279, ppc_lhzx }, + { 46, -1, ppc_lmw }, + { 31, 597, ppc_lswi }, + { 31, 533, ppc_lswx }, + { 31, 20, ppc_lwarx }, + { 31, 534, ppc_lwbrx }, + { 32, -1, ppc_lwz }, + { 33, -1, ppc_lwzu }, + { 31, 55, ppc_lwzux }, + { 31, 23, ppc_lwzx }, + { 19, 0, ppc_mcrf }, + { 31, 512, ppc_mcrxr }, + { 31, 19, ppc_mfcr }, + { 31, 83, ppc_mfmsr }, + { 31, 339, ppc_mfspr }, + { 31, 144, ppc_mtcrf }, + { 31, 146, ppc_mtmsr }, + { 31, 467, ppc_mtspr }, + { 31, 75, ppc_mulhwx }, + { 31, 11, ppc_mulhwux }, + { 7, -1, ppc_mulli }, + { 31, 235, ppc_mullwx }, + { 31, 235 | 512, ppc_mullwx }, + { 31, 476, ppc_nandx }, + { 31, 104, ppc_negx }, + { 31, 104 | 512, ppc_negx }, + { 31, 124, ppc_norx }, + { 31, 444, ppc_orx }, + { 31, 412, ppc_orcx }, + { 24, -1, ppc_ori }, + { 25, -1, ppc_oris }, + { 19, 50, ppc_rfi }, + { 20, -1, ppc_rlwimix }, + { 21, -1, ppc_rlwinmx }, + { 23, -1, ppc_rlwnmx }, + { 17, -1, ppc_sc }, + { 31, 24, ppc_slwx }, + { 31, 792, ppc_srawx }, + { 31, 824, ppc_srawix }, + { 31, 536, ppc_srwx }, + { 38, -1, ppc_stb }, + { 39, -1, ppc_stbu }, + { 31, 247, ppc_stbux }, + { 31, 215, ppc_stbx }, + { 44, -1, ppc_sth }, + { 31, 918, ppc_sthbrx }, + { 45, -1, ppc_sthu }, + { 31, 439, ppc_sthux }, + { 31, 407, ppc_sthx }, + { 47, -1, ppc_stmw }, + { 31, 725, ppc_stswi }, + { 31, 661, ppc_stswx }, + { 36, -1, ppc_stw }, + { 31, 662, ppc_stwbrx }, + { 31, 150, ppc_stwcx_rc }, + { 37, -1, ppc_stwu }, + { 31, 183, ppc_stwux }, + { 31, 151, ppc_stwx }, + { 31, 40, ppc_subfx }, + { 31, 40 | 512, ppc_subfx }, + { 31, 8, ppc_subfcx }, + { 31, 8 | 512, ppc_subfcx }, + { 31, 136, ppc_subfex }, + { 31, 136 | 512, ppc_subfex }, + { 8, -1, ppc_subfic }, + { 31, 232, ppc_subfmex }, + { 31, 232 | 512, ppc_subfmex }, + { 31, 200, ppc_subfzex }, + { 31, 200 | 512, ppc_subfzex }, + { 31, 598, ppc_sync }, + { 31, 4, ppc_tw }, + { 3, -1, ppc_twi }, + { 31, 316, ppc_xorx }, + { 26, -1, ppc_xori }, + { 27, -1, ppc_xoris } +}; + +#endif /* __PPC_OPS_H__ */ diff --git a/src/devices/cpu/powerpc/ppc_ops.inc b/src/devices/cpu/powerpc/ppc_ops.inc new file mode 100644 index 00000000000..86ccd8e2225 --- /dev/null +++ b/src/devices/cpu/powerpc/ppc_ops.inc @@ -0,0 +1,2810 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/* PowerPC common opcodes */ + +// it really seems like this should be elsewhere - like maybe the floating point checks can hang out someplace else +#include + +#ifndef PPC_DRC +static void ppc_unimplemented(UINT32 op) +{ + fatalerror("ppc: Unimplemented opcode %08X at %08X\n", op, ppc.pc); +} + +static void ppc_addx(UINT32 op) +{ + UINT32 ra = REG(RA); + UINT32 rb = REG(RB); + + REG(RT) = ra + rb; + + if( OEBIT ) { + SET_ADD_OV(REG(RT), ra, rb); + } + if( RCBIT ) { + SET_CR0(REG(RT)); + } +} + +static void ppc_addcx(UINT32 op) +{ + UINT32 ra = REG(RA); + UINT32 rb = REG(RB); + + REG(RT) = ra + rb; + + SET_ADD_CA(REG(RT), ra, rb); + + if( OEBIT ) { + SET_ADD_OV(REG(RT), ra, rb); + } + if( RCBIT ) { + SET_CR0(REG(RT)); + } +} +#endif + +static void ppc_addex(UINT32 op) +{ + UINT32 ra = REG(RA); + UINT32 rb = REG(RB); + UINT32 carry = (XER >> 29) & 0x1; + UINT32 tmp; + + tmp = rb + carry; + REG(RT) = ra + tmp; + + if( ADD_CA(tmp, rb, carry) || ADD_CA(REG(RT), ra, tmp) ) + XER |= XER_CA; + else + XER &= ~XER_CA; + + if( OEBIT ) { + SET_ADD_OV(REG(RT), ra, rb); + } + if( RCBIT ) { + SET_CR0(REG(RT)); + } +} + +#ifndef PPC_DRC +static void ppc_addi(UINT32 op) +{ + UINT32 i = SIMM16; + UINT32 a = RA; + + if( a ) + i += REG(a); + + REG(RT) = i; +} + +static void ppc_addic(UINT32 op) +{ + UINT32 i = SIMM16; + UINT32 ra = REG(RA); + + REG(RT) = ra + i; + + if( ADD_CA(REG(RT), ra, i) ) + XER |= XER_CA; + else + XER &= ~XER_CA; +} + +static void ppc_addic_rc(UINT32 op) +{ + UINT32 i = SIMM16; + UINT32 ra = REG(RA); + + REG(RT) = ra + i; + + if( ADD_CA(REG(RT), ra, i) ) + XER |= XER_CA; + else + XER &= ~XER_CA; + + SET_CR0(REG(RT)); +} + +static void ppc_addis(UINT32 op) +{ + UINT32 i = UIMM16 << 16; + UINT32 a = RA; + + if( a ) + i += REG(a); + + REG(RT) = i; +} +#endif + +static void ppc_addmex(UINT32 op) +{ + UINT32 ra = REG(RA); + UINT32 carry = (XER >> 29) & 0x1; + UINT32 tmp; + + tmp = ra + carry; + REG(RT) = tmp + -1; + + if( ADD_CA(tmp, ra, carry) || ADD_CA(REG(RT), tmp, -1) ) + XER |= XER_CA; + else + XER &= ~XER_CA; + + if( OEBIT ) { + SET_ADD_OV(REG(RT), ra, carry - 1); + } + if( RCBIT ) { + SET_CR0(REG(RT)); + } +} + +static void ppc_addzex(UINT32 op) +{ + UINT32 ra = REG(RA); + UINT32 carry = (XER >> 29) & 0x1; + + REG(RT) = ra + carry; + + if( ADD_CA(REG(RT), ra, carry) ) + XER |= XER_CA; + else + XER &= ~XER_CA; + + if( OEBIT ) { + SET_ADD_OV(REG(RT), ra, carry); + } + if( RCBIT ) { + SET_CR0(REG(RT)); + } +} + +#ifndef PPC_DRC +static void ppc_andx(UINT32 op) +{ + REG(RA) = REG(RS) & REG(RB); + + if( RCBIT ) { + SET_CR0(REG(RA)); + } +} + +static void ppc_andcx(UINT32 op) +{ + REG(RA) = REG(RS) & ~REG(RB); + + if( RCBIT ) { + SET_CR0(REG(RA)); + } +} + +static void ppc_andi_rc(UINT32 op) +{ + UINT32 i = UIMM16; + + REG(RA) = REG(RS) & i; + + SET_CR0(REG(RA)); +} + +static void ppc_andis_rc(UINT32 op) +{ + UINT32 i = UIMM16 << 16; + + REG(RA) = REG(RS) & i; + + SET_CR0(REG(RA)); +} + +static void ppc_bx(UINT32 op) +{ + INT32 li = op & 0x3fffffc; + if( li & 0x2000000 ) + li |= 0xfc000000; + + if( AABIT ) { + ppc.npc = li; + } else { + ppc.npc = ppc.pc + li; + } + + if( LKBIT ) { + LR = ppc.pc + 4; + } +} + +static void ppc_bcx(UINT32 op) +{ + int condition = check_condition_code(BO, BI); + + if( condition ) { + if( AABIT ) { + ppc.npc = SIMM16 & ~0x3; + } else { + ppc.npc = ppc.pc + (SIMM16 & ~0x3); + } + } + + if( LKBIT ) { + LR = ppc.pc + 4; + } +} + +static void ppc_bcctrx(UINT32 op) +{ + int condition = check_condition_code(BO, BI); + + if( condition ) { + ppc.npc = CTR & ~0x3; + } + + if( LKBIT ) { + LR = ppc.pc + 4; + } +} + +static void ppc_bclrx(UINT32 op) +{ + int condition = check_condition_code(BO, BI); + + if( condition ) { + ppc.npc = LR & ~0x3; + } + + if( LKBIT ) { + LR = ppc.pc + 4; + } +} + +static void ppc_cmp(UINT32 op) +{ + INT32 ra = REG(RA); + INT32 rb = REG(RB); + int d = CRFD; + + if( ra < rb ) + CR(d) = 0x8; + else if( ra > rb ) + CR(d) = 0x4; + else + CR(d) = 0x2; + + if( XER & XER_SO ) + CR(d) |= 0x1; +} + +static void ppc_cmpi(UINT32 op) +{ + INT32 ra = REG(RA); + INT32 i = SIMM16; + int d = CRFD; + + if( ra < i ) + CR(d) = 0x8; + else if( ra > i ) + CR(d) = 0x4; + else + CR(d) = 0x2; + + if( XER & XER_SO ) + CR(d) |= 0x1; +} + +static void ppc_cmpl(UINT32 op) +{ + UINT32 ra = REG(RA); + UINT32 rb = REG(RB); + int d = CRFD; + + if( ra < rb ) + CR(d) = 0x8; + else if( ra > rb ) + CR(d) = 0x4; + else + CR(d) = 0x2; + + if( XER & XER_SO ) + CR(d) |= 0x1; +} + +static void ppc_cmpli(UINT32 op) +{ + UINT32 ra = REG(RA); + UINT32 i = UIMM16; + int d = CRFD; + + if( ra < i ) + CR(d) = 0x8; + else if( ra > i ) + CR(d) = 0x4; + else + CR(d) = 0x2; + + if( XER & XER_SO ) + CR(d) |= 0x1; +} + +static void ppc_cntlzw(UINT32 op) +{ + int n = 0; + int t = RT; + UINT32 m = 0x80000000; + + while(n < 32) + { + if( REG(t) & m ) + break; + m >>= 1; + n++; + } + + REG(RA) = n; + + if( RCBIT ) { + SET_CR0(REG(RA)); + } +} +#endif + +static void ppc_crand(UINT32 op) +{ + int bit = RT; + int b = CRBIT(RA) & CRBIT(RB); + if( b & 0x1 ) + CR(bit / 4) |= _BIT(3-(bit % 4)); + else + CR(bit / 4) &= ~_BIT(3-(bit % 4)); +} + +static void ppc_crandc(UINT32 op) +{ + int bit = RT; + int b = CRBIT(RA) & ~CRBIT(RB); + if( b & 0x1 ) + CR(bit / 4) |= _BIT(3-(bit % 4)); + else + CR(bit / 4) &= ~_BIT(3-(bit % 4)); +} + +static void ppc_creqv(UINT32 op) +{ + int bit = RT; + int b = ~(CRBIT(RA) ^ CRBIT(RB)); + if( b & 0x1 ) + CR(bit / 4) |= _BIT(3-(bit % 4)); + else + CR(bit / 4) &= ~_BIT(3-(bit % 4)); +} + +static void ppc_crnand(UINT32 op) +{ + int bit = RT; + int b = ~(CRBIT(RA) & CRBIT(RB)); + if( b & 0x1 ) + CR(bit / 4) |= _BIT(3-(bit % 4)); + else + CR(bit / 4) &= ~_BIT(3-(bit % 4)); +} + +static void ppc_crnor(UINT32 op) +{ + int bit = RT; + int b = ~(CRBIT(RA) | CRBIT(RB)); + if( b & 0x1 ) + CR(bit / 4) |= _BIT(3-(bit % 4)); + else + CR(bit / 4) &= ~_BIT(3-(bit % 4)); +} + +static void ppc_cror(UINT32 op) +{ + int bit = RT; + int b = CRBIT(RA) | CRBIT(RB); + if( b & 0x1 ) + CR(bit / 4) |= _BIT(3-(bit % 4)); + else + CR(bit / 4) &= ~_BIT(3-(bit % 4)); +} + +static void ppc_crorc(UINT32 op) +{ + int bit = RT; + int b = CRBIT(RA) | ~CRBIT(RB); + if( b & 0x1 ) + CR(bit / 4) |= _BIT(3-(bit % 4)); + else + CR(bit / 4) &= ~_BIT(3-(bit % 4)); +} + +static void ppc_crxor(UINT32 op) +{ + int bit = RT; + int b = CRBIT(RA) ^ CRBIT(RB); + if( b & 0x1 ) + CR(bit / 4) |= _BIT(3-(bit % 4)); + else + CR(bit / 4) &= ~_BIT(3-(bit % 4)); +} + +#ifndef PPC_DRC +static void ppc_dcbf(UINT32 op) +{ +} + +static void ppc_dcbi(UINT32 op) +{ +} + +static void ppc_dcbst(UINT32 op) +{ +} + +static void ppc_dcbt(UINT32 op) +{ +} + +static void ppc_dcbtst(UINT32 op) +{ +} + +static void ppc_dcbz(UINT32 op) +{ +} +#endif + +static void ppc_divwx(UINT32 op) +{ + if( REG(RB) == 0 && REG(RA) < 0x80000000 ) + { + REG(RT) = 0; + if( OEBIT ) { + XER |= XER_SO | XER_OV; + } + } + else if( REG(RB) == 0 || (REG(RB) == 0xffffffff && REG(RA) == 0x80000000) ) + { + REG(RT) = 0xffffffff; + if( OEBIT ) { + XER |= XER_SO | XER_OV; + } + } + else + { + REG(RT) = (INT32)REG(RA) / (INT32)REG(RB); + if( OEBIT ) { + XER &= ~XER_OV; + } + } + + if( RCBIT ) { + SET_CR0(REG(RT)); + } +} + +static void ppc_divwux(UINT32 op) +{ + if( REG(RB) == 0 ) + { + REG(RT) = 0; + if( OEBIT ) { + XER |= XER_SO | XER_OV; + } + } + else + { + REG(RT) = (UINT32)REG(RA) / (UINT32)REG(RB); + if( OEBIT ) { + XER &= ~XER_OV; + } + } + + if( RCBIT ) { + SET_CR0(REG(RT)); + } +} + +#ifndef PPC_DRC +static void ppc_eieio(UINT32 op) +{ +} + +static void ppc_eqvx(UINT32 op) +{ + REG(RA) = ~(REG(RS) ^ REG(RB)); + + if( RCBIT ) { + SET_CR0(REG(RA)); + } +} + +static void ppc_extsbx(UINT32 op) +{ + REG(RA) = (INT32)(INT8)REG(RS); + + if( RCBIT ) { + SET_CR0(REG(RA)); + } +} + +static void ppc_extshx(UINT32 op) +{ + REG(RA) = (INT32)(INT16)REG(RS); + + if( RCBIT ) { + SET_CR0(REG(RA)); + } +} + +static void ppc_icbi(UINT32 op) +{ +} + +static void ppc_isync(UINT32 op) +{ +} + +static void ppc_lbz(UINT32 op) +{ + UINT32 ea; + + if( RA == 0 ) + ea = SIMM16; + else + ea = REG(RA) + SIMM16; + + REG(RT) = (UINT32)READ8(ea); +} + +static void ppc_lbzu(UINT32 op) +{ + UINT32 ea = REG(RA) + SIMM16; + + REG(RT) = (UINT32)READ8(ea); + REG(RA) = ea; +} + +static void ppc_lbzux(UINT32 op) +{ + UINT32 ea = REG(RA) + REG(RB); + + REG(RT) = (UINT32)READ8(ea); + REG(RA) = ea; +} + +static void ppc_lbzx(UINT32 op) +{ + UINT32 ea; + + if( RA == 0 ) + ea = REG(RB); + else + ea = REG(RA) + REG(RB); + + REG(RT) = (UINT32)READ8(ea); +} + +static void ppc_lha(UINT32 op) +{ + UINT32 ea; + + if( RA == 0 ) + ea = SIMM16; + else + ea = REG(RA) + SIMM16; + + REG(RT) = (INT32)(INT16)READ16(ea); +} + +static void ppc_lhau(UINT32 op) +{ + UINT32 ea = REG(RA) + SIMM16; + + REG(RT) = (INT32)(INT16)READ16(ea); + REG(RA) = ea; +} + +static void ppc_lhaux(UINT32 op) +{ + UINT32 ea = REG(RA) + REG(RB); + + REG(RT) = (INT32)(INT16)READ16(ea); + REG(RA) = ea; +} + +static void ppc_lhax(UINT32 op) +{ + UINT32 ea; + + if( RA == 0 ) + ea = REG(RB); + else + ea = REG(RA) + REG(RB); + + REG(RT) = (INT32)(INT16)READ16(ea); +} + +static void ppc_lhbrx(UINT32 op) +{ + UINT32 ea; + UINT16 w; + + if( RA == 0 ) + ea = REG(RB); + else + ea = REG(RA) + REG(RB); + + w = READ16(ea); + REG(RT) = (UINT32)BYTE_REVERSE16(w); +} + +static void ppc_lhz(UINT32 op) +{ + UINT32 ea; + + if( RA == 0 ) + ea = SIMM16; + else + ea = REG(RA) + SIMM16; + + REG(RT) = (UINT32)READ16(ea); +} + +static void ppc_lhzu(UINT32 op) +{ + UINT32 ea = REG(RA) + SIMM16; + + REG(RT) = (UINT32)READ16(ea); + REG(RA) = ea; +} + +static void ppc_lhzux(UINT32 op) +{ + UINT32 ea = REG(RA) + REG(RB); + + REG(RT) = (UINT32)READ16(ea); + REG(RA) = ea; +} + +static void ppc_lhzx(UINT32 op) +{ + UINT32 ea; + + if( RA == 0 ) + ea = REG(RB); + else + ea = REG(RA) + REG(RB); + + REG(RT) = (UINT32)READ16(ea); +} +#endif + +static void ppc_lmw(UINT32 op) +{ + int r = RT; + UINT32 ea; + + if( RA == 0 ) + ea = SIMM16; + else + ea = REG(RA) + SIMM16; + + while( r <= 31 ) + { + REG(r) = READ32(ea); + ea += 4; + r++; + } +} + +static void ppc_lswi(UINT32 op) +{ + int n, r, i; + UINT32 ea = 0; + if( RA != 0 ) + ea = REG(RA); + + if( RB == 0 ) + n = 32; + else + n = RB; + + r = RT - 1; + i = 0; + + while(n > 0) + { + if (i == 0) { + r = (r + 1) % 32; + REG(r) = 0; + } + REG(r) |= ((READ8(ea) & 0xff) << (24 - i)); + i += 8; + if (i == 32) { + i = 0; + } + ea++; + n--; + } +} + +static void ppc_lswx(UINT32 op) +{ + int n, r, i; + UINT32 ea = 0; + if( RA != 0 ) + ea = REG(RA); + + ea += REG(RB); + + n = ppc.xer & 0x7f; + + r = RT - 1; + i = 0; + + while(n > 0) + { + if (i == 0) { + r = (r + 1) % 32; + REG(r) = 0; + } + REG(r) |= ((READ8(ea) & 0xff) << (24 - i)); + i += 8; + if (i == 32) { + i = 0; + } + ea++; + n--; + } +} + +static void ppc_lwarx(UINT32 op) +{ + UINT32 ea; + + if( RA == 0 ) + ea = REG(RB); + else + ea = REG(RA) + REG(RB); + + ppc.reserved_address = ea; + ppc.reserved = 1; + + REG(RT) = READ32(ea); +} + +#ifndef PPC_DRC +static void ppc_lwbrx(UINT32 op) +{ + UINT32 ea; + UINT32 w; + + if( RA == 0 ) + ea = REG(RB); + else + ea = REG(RA) + REG(RB); + + w = READ32(ea); + REG(RT) = BYTE_REVERSE32(w); +} + +static void ppc_lwz(UINT32 op) +{ + UINT32 ea; + + if( RA == 0 ) + ea = SIMM16; + else + ea = REG(RA) + SIMM16; + + REG(RT) = READ32(ea); +} + +static void ppc_lwzu(UINT32 op) +{ + UINT32 ea = REG(RA) + SIMM16; + + REG(RT) = READ32(ea); + REG(RA) = ea; +} + +static void ppc_lwzux(UINT32 op) +{ + UINT32 ea = REG(RA) + REG(RB); + + REG(RT) = READ32(ea); + REG(RA) = ea; +} + +static void ppc_lwzx(UINT32 op) +{ + UINT32 ea; + + if( RA == 0 ) + ea = REG(RB); + else + ea = REG(RA) + REG(RB); + + REG(RT) = READ32(ea); +} + +static void ppc_mcrf(UINT32 op) +{ + CR(RT >> 2) = CR(RA >> 2); +} + +static void ppc_mcrxr(UINT32 op) +{ + CR(RT >> 2) = (XER >> 28) & 0x0F; + XER &= ~0xf0000000; +} + +static void ppc_mfcr(UINT32 op) +{ + REG(RT) = ppc_get_cr(); +} + +static void ppc_mfmsr(UINT32 op) +{ + REG(RT) = ppc_get_msr(); +} + +static void ppc_mfspr(UINT32 op) +{ + REG(RT) = ppc_get_spr(SPR); +} +#endif + +static void ppc_mtcrf(UINT32 op) +{ + int fxm = FXM; + int t = RT; + + if( fxm & 0x80 ) CR(0) = (REG(t) >> 28) & 0xf; + if( fxm & 0x40 ) CR(1) = (REG(t) >> 24) & 0xf; + if( fxm & 0x20 ) CR(2) = (REG(t) >> 20) & 0xf; + if( fxm & 0x10 ) CR(3) = (REG(t) >> 16) & 0xf; + if( fxm & 0x08 ) CR(4) = (REG(t) >> 12) & 0xf; + if( fxm & 0x04 ) CR(5) = (REG(t) >> 8) & 0xf; + if( fxm & 0x02 ) CR(6) = (REG(t) >> 4) & 0xf; + if( fxm & 0x01 ) CR(7) = (REG(t) >> 0) & 0xf; +} + +#ifndef PPC_DRC +static void ppc_mtmsr(UINT32 op) +{ + ppc_set_msr(REG(RS)); +} + +static void ppc_mtspr(UINT32 op) +{ + ppc_set_spr(SPR, REG(RS)); +} + +static void ppc_mulhwx(UINT32 op) +{ + INT64 ra = (INT64)(INT32)REG(RA); + INT64 rb = (INT64)(INT32)REG(RB); + + REG(RT) = (UINT32)((ra * rb) >> 32); + + if( RCBIT ) { + SET_CR0(REG(RT)); + } +} + +static void ppc_mulhwux(UINT32 op) +{ + UINT64 ra = (UINT64)REG(RA); + UINT64 rb = (UINT64)REG(RB); + + REG(RT) = (UINT32)((ra * rb) >> 32); + + if( RCBIT ) { + SET_CR0(REG(RT)); + } +} + +static void ppc_mulli(UINT32 op) +{ + INT32 ra = (INT32)REG(RA); + INT32 i = SIMM16; + + REG(RT) = ra * i; +} + +static void ppc_mullwx(UINT32 op) +{ + INT64 ra = (INT64)(INT32)REG(RA); + INT64 rb = (INT64)(INT32)REG(RB); + INT64 r; + + r = ra * rb; + REG(RT) = (UINT32)r; + + if( OEBIT ) { + XER &= ~XER_OV; + + if( r != (INT64)(INT32)r ) + XER |= XER_OV | XER_SO; + } + + if( RCBIT ) { + SET_CR0(REG(RT)); + } +} + +static void ppc_nandx(UINT32 op) +{ + REG(RA) = ~(REG(RS) & REG(RB)); + + if( RCBIT ) { + SET_CR0(REG(RA)); + } +} + +static void ppc_negx(UINT32 op) +{ + REG(RT) = -REG(RA); + + if( OEBIT ) { + if( REG(RT) == 0x80000000 ) + XER |= XER_OV | XER_SO; + else + XER &= ~XER_OV; + } + + if( RCBIT ) { + SET_CR0(REG(RT)); + } +} + +static void ppc_norx(UINT32 op) +{ + REG(RA) = ~(REG(RS) | REG(RB)); + + if( RCBIT ) { + SET_CR0(REG(RA)); + } +} + +static void ppc_orx(UINT32 op) +{ + REG(RA) = REG(RS) | REG(RB); + + if( RCBIT ) { + SET_CR0(REG(RA)); + } +} + +static void ppc_orcx(UINT32 op) +{ + REG(RA) = REG(RS) | ~REG(RB); + + if( RCBIT ) { + SET_CR0(REG(RA)); + } +} + +static void ppc_ori(UINT32 op) +{ + REG(RA) = REG(RS) | UIMM16; +} + +static void ppc_oris(UINT32 op) +{ + REG(RA) = REG(RS) | (UIMM16 << 16); +} + +static void ppc_rfi(UINT32 op) +{ + UINT32 msr; + ppc.npc = ppc_get_spr(SPR_SRR0); + msr = ppc_get_spr(SPR_SRR1); + ppc_set_msr( msr ); +} + +static void ppc_rlwimix(UINT32 op) +{ + UINT32 r; + UINT32 mask = GET_ROTATE_MASK(MB, ME); + UINT32 rs = REG(RS); + int sh = SH; + + r = (rs << sh) | (rs >> (32-sh)); + REG(RA) = (REG(RA) & ~mask) | (r & mask); + + if( RCBIT ) { + SET_CR0(REG(RA)); + } +} + +static void ppc_rlwinmx(UINT32 op) +{ + UINT32 r; + UINT32 mask = GET_ROTATE_MASK(MB, ME); + UINT32 rs = REG(RS); + int sh = SH; + + r = (rs << sh) | (rs >> (32-sh)); + REG(RA) = r & mask; + + if( RCBIT ) { + SET_CR0(REG(RA)); + } +} + +static void ppc_rlwnmx(UINT32 op) +{ + UINT32 r; + UINT32 mask = GET_ROTATE_MASK(MB, ME); + UINT32 rs = REG(RS); + int sh = REG(RB) & 0x1f; + + r = (rs << sh) | (rs >> (32-sh)); + REG(RA) = r & mask; + + if( RCBIT ) { + SET_CR0(REG(RA)); + } +} +#endif + +#ifndef PPC_DRC +static void ppc_sc(UINT32 op) +{ + if (ppc.is603) { + ppc603_exception(EXCEPTION_SYSTEM_CALL); + } + if (ppc.is602) { + ppc602_exception(EXCEPTION_SYSTEM_CALL); + } + if (IS_PPC403()) { + ppc403_exception(EXCEPTION_SYSTEM_CALL); + } +} +#endif + +static void ppc_slwx(UINT32 op) +{ + int sh = REG(RB) & 0x3f; + + if( sh > 31 ) { + REG(RA) = 0; + } + else { + REG(RA) = REG(RS) << sh; + } + + if( RCBIT ) { + SET_CR0(REG(RA)); + } +} + +static void ppc_srawx(UINT32 op) +{ + int sh = REG(RB) & 0x3f; + + XER &= ~XER_CA; + + if( sh > 31 ) { + if (REG(RS) & 0x80000000) + REG(RA) = 0xffffffff; + else + REG(RA) = 0; + if( REG(RA) ) + XER |= XER_CA; + } + else { + REG(RA) = (INT32)(REG(RS)) >> sh; + if( ((INT32)(REG(RS)) < 0) && (REG(RS) & BITMASK_0(sh)) ) + XER |= XER_CA; + } + + if( RCBIT ) { + SET_CR0(REG(RA)); + } +} + +static void ppc_srawix(UINT32 op) +{ + int sh = SH; + + XER &= ~XER_CA; + if( ((INT32)(REG(RS)) < 0) && (REG(RS) & BITMASK_0(sh)) ) + XER |= XER_CA; + + REG(RA) = (INT32)(REG(RS)) >> sh; + + if( RCBIT ) { + SET_CR0(REG(RA)); + } +} + +static void ppc_srwx(UINT32 op) +{ + int sh = REG(RB) & 0x3f; + + if( sh > 31 ) { + REG(RA) = 0; + } + else { + REG(RA) = REG(RS) >> sh; + } + + if( RCBIT ) { + SET_CR0(REG(RA)); + } +} + +#ifndef PPC_DRC +static void ppc_stb(UINT32 op) +{ + UINT32 ea; + + if( RA == 0 ) + ea = SIMM16; + else + ea = REG(RA) + SIMM16; + + WRITE8(ea, (UINT8)REG(RS)); +} + +static void ppc_stbu(UINT32 op) +{ + UINT32 ea = REG(RA) + SIMM16; + + WRITE8(ea, (UINT8)REG(RS)); + REG(RA) = ea; +} + +static void ppc_stbux(UINT32 op) +{ + UINT32 ea = REG(RA) + REG(RB); + + WRITE8(ea, (UINT8)REG(RS)); + REG(RA) = ea; +} + +static void ppc_stbx(UINT32 op) +{ + UINT32 ea; + + if( RA == 0 ) + ea = REG(RB); + else + ea = REG(RA) + REG(RB); + + WRITE8(ea, (UINT8)REG(RS)); +} + +static void ppc_sth(UINT32 op) +{ + UINT32 ea; + + if( RA == 0 ) + ea = SIMM16; + else + ea = REG(RA) + SIMM16; + + WRITE16(ea, (UINT16)REG(RS)); +} + +static void ppc_sthbrx(UINT32 op) +{ + UINT32 ea; + UINT16 w; + + if( RA == 0 ) + ea = REG(RB); + else + ea = REG(RA) + REG(RB); + + w = REG(RS); + WRITE16(ea, (UINT16)BYTE_REVERSE16(w)); +} + +static void ppc_sthu(UINT32 op) +{ + UINT32 ea = REG(RA) + SIMM16; + + WRITE16(ea, (UINT16)REG(RS)); + REG(RA) = ea; +} + +static void ppc_sthux(UINT32 op) +{ + UINT32 ea = REG(RA) + REG(RB); + + WRITE16(ea, (UINT16)REG(RS)); + REG(RA) = ea; +} + +static void ppc_sthx(UINT32 op) +{ + UINT32 ea; + + if( RA == 0 ) + ea = REG(RB); + else + ea = REG(RA) + REG(RB); + + WRITE16(ea, (UINT16)REG(RS)); +} +#endif + +static void ppc_stmw(UINT32 op) +{ + UINT32 ea; + int r = RS; + + if( RA == 0 ) + ea = SIMM16; + else + ea = REG(RA) + SIMM16; + + while( r <= 31 ) + { + WRITE32(ea, REG(r)); + ea += 4; + r++; + } +} + +static void ppc_stswi(UINT32 op) +{ + int n, r, i; + UINT32 ea = 0; + if( RA != 0 ) + ea = REG(RA); + + if( RB == 0 ) + n = 32; + else + n = RB; + + r = RT - 1; + i = 0; + + while(n > 0) + { + if (i == 0) { + r = (r + 1) % 32; + } + WRITE8(ea, (REG(r) >> (24-i)) & 0xff); + i += 8; + if (i == 32) { + i = 0; + } + ea++; + n--; + } +} + +static void ppc_stswx(UINT32 op) +{ + int n, r, i; + UINT32 ea = 0; + if( RA != 0 ) + ea = REG(RA); + + ea += REG(RB); + + n = ppc.xer & 0x7f; + + r = RT - 1; + i = 0; + + while(n > 0) + { + if (i == 0) { + r = (r + 1) % 32; + } + WRITE8(ea, (REG(r) >> (24-i)) & 0xff); + i += 8; + if (i == 32) { + i = 0; + } + ea++; + n--; + } +} + +#ifndef PPC_DRC +static void ppc_stw(UINT32 op) +{ + UINT32 ea; + + if( RA == 0 ) + ea = SIMM16; + else + ea = REG(RA) + SIMM16; + + WRITE32(ea, REG(RS)); +} + +static void ppc_stwbrx(UINT32 op) +{ + UINT32 ea; + UINT32 w; + + if( RA == 0 ) + ea = REG(RB); + else + ea = REG(RA) + REG(RB); + + w = REG(RS); + WRITE32(ea, BYTE_REVERSE32(w)); +} +#endif + +static void ppc_stwcx_rc(UINT32 op) +{ + UINT32 ea; + + if( RA == 0 ) + ea = REG(RB); + else + ea = REG(RA) + REG(RB); + + if( ppc.reserved ) { + WRITE32(ea, REG(RS)); + + ppc.reserved = 0; + ppc.reserved_address = 0; + + CR(0) = 0x2; + if( XER & XER_SO ) + CR(0) |= 0x1; + } else { + CR(0) = 0; + if( XER & XER_SO ) + CR(0) |= 0x1; + } +} + +#ifndef PPC_DRC +static void ppc_stwu(UINT32 op) +{ + UINT32 ea = REG(RA) + SIMM16; + + WRITE32(ea, REG(RS)); + REG(RA) = ea; +} + +static void ppc_stwux(UINT32 op) +{ + UINT32 ea = REG(RA) + REG(RB); + + WRITE32(ea, REG(RS)); + REG(RA) = ea; +} + +static void ppc_stwx(UINT32 op) +{ + UINT32 ea; + + if( RA == 0 ) + ea = REG(RB); + else + ea = REG(RA) + REG(RB); + + WRITE32(ea, REG(RS)); +} + +static void ppc_subfx(UINT32 op) +{ + UINT32 ra = REG(RA); + UINT32 rb = REG(RB); + REG(RT) = rb - ra; + + if( OEBIT ) { + SET_SUB_OV(REG(RT), rb, ra); + } + if( RCBIT ) { + SET_CR0(REG(RT)); + } +} +#endif + +static void ppc_subfcx(UINT32 op) +{ + UINT32 ra = REG(RA); + UINT32 rb = REG(RB); + REG(RT) = rb - ra; + + SET_SUB_CA(REG(RT), rb, ra); + + if( OEBIT ) { + SET_SUB_OV(REG(RT), rb, ra); + } + if( RCBIT ) { + SET_CR0(REG(RT)); + } +} + +#ifndef PPC_DRC +static void ppc_subfex(UINT32 op) +{ + UINT32 ra = REG(RA); + UINT32 rb = REG(RB); + UINT32 carry = (XER >> 29) & 0x1; + UINT32 r; + + r = ~ra + carry; + REG(RT) = rb + r; + + SET_ADD_CA(r, ~ra, carry); /* step 1 carry */ + if( REG(RT) < r ) /* step 2 carry */ + XER |= XER_CA; + + if( OEBIT ) { + SET_SUB_OV(REG(RT), rb, ra); + } + if( RCBIT ) { + SET_CR0(REG(RT)); + } +} + +static void ppc_subfic(UINT32 op) +{ + UINT32 i = SIMM16; + UINT32 ra = REG(RA); + + REG(RT) = i - ra; + + SET_SUB_CA(REG(RT), i, ra); +} +#endif + +static void ppc_subfmex(UINT32 op) +{ + UINT32 ra = REG(RA); + UINT32 carry = (XER >> 29) & 0x1; + UINT32 r; + + r = ~ra + carry; + REG(RT) = r - 1; + + SET_SUB_CA(r, ~ra, carry); /* step 1 carry */ + if( REG(RT) < r ) + XER |= XER_CA; /* step 2 carry */ + + if( OEBIT ) { + SET_SUB_OV(REG(RT), -1, ra); + } + if( RCBIT ) { + SET_CR0(REG(RT)); + } +} + +static void ppc_subfzex(UINT32 op) +{ + UINT32 ra = REG(RA); + UINT32 carry = (XER >> 29) & 0x1; + + REG(RT) = ~ra + carry; + + SET_ADD_CA(REG(RT), ~ra, carry); + + if( OEBIT ) { + SET_SUB_OV(REG(RT), 0, REG(RA)); + } + if( RCBIT ) { + SET_CR0(REG(RT)); + } +} + +#ifndef PPC_DRC +static void ppc_sync(UINT32 op) +{ +} +#endif + +#ifndef PPC_DRC +static void ppc_tw(UINT32 op) +{ + int exception = 0; + INT32 a = REG(RA); + INT32 b = REG(RB); + int to = RT; + + if( (a < b) && (to & 0x10) ) { + exception = 1; + } + if( (a > b) && (to & 0x08) ) { + exception = 1; + } + if( (a == b) && (to & 0x04) ) { + exception = 1; + } + if( ((UINT32)a < (UINT32)b) && (to & 0x02) ) { + exception = 1; + } + if( ((UINT32)a > (UINT32)b) && (to & 0x01) ) { + exception = 1; + } + + if (exception) { + if (ppc.is603) { + ppc603_exception(EXCEPTION_TRAP); + } + if (ppc.is602) { + ppc602_exception(EXCEPTION_TRAP); + } + if (IS_PPC403()) { + ppc403_exception(EXCEPTION_TRAP); + } + } +} +#endif + +#ifndef PPC_DRC +static void ppc_twi(UINT32 op) +{ + int exception = 0; + INT32 a = REG(RA); + INT32 i = SIMM16; + int to = RT; + + if( (a < i) && (to & 0x10) ) { + exception = 1; + } + if( (a > i) && (to & 0x08) ) { + exception = 1; + } + if( (a == i) && (to & 0x04) ) { + exception = 1; + } + if( ((UINT32)a < (UINT32)i) && (to & 0x02) ) { + exception = 1; + } + if( ((UINT32)a > (UINT32)i) && (to & 0x01) ) { + exception = 1; + } + + if (exception) { + if (ppc.is603) { + ppc603_exception(EXCEPTION_TRAP); + } + if (ppc.is602) { + ppc602_exception(EXCEPTION_TRAP); + } + if (IS_PPC403()) { + ppc403_exception(EXCEPTION_TRAP); + } + } +} +#endif + +#ifndef PPC_DRC +static void ppc_xorx(UINT32 op) +{ + REG(RA) = REG(RS) ^ REG(RB); + + if( RCBIT ) { + SET_CR0(REG(RA)); + } +} + +static void ppc_xori(UINT32 op) +{ + REG(RA) = REG(RS) ^ UIMM16; +} + +static void ppc_xoris(UINT32 op) +{ + REG(RA) = REG(RS) ^ (UIMM16 << 16); +} + + + +static void ppc_invalid(UINT32 op) +{ + fatalerror("ppc: Invalid opcode %08X PC : %X\n", op, ppc.pc); +} +#endif + + +// Everything below is new from AJG + +//////////////////////////// +// !here are the 6xx ops! // +//////////////////////////// + +#define DOUBLE_SIGN (U64(0x8000000000000000)) +#define DOUBLE_EXP (U64(0x7ff0000000000000)) +#define DOUBLE_FRAC (U64(0x000fffffffffffff)) +#define DOUBLE_ZERO (0) + +/* + Floating point operations. +*/ + +INLINE int is_nan_double(FPR x) +{ + return( ((x.id & DOUBLE_EXP) == DOUBLE_EXP) && + ((x.id & DOUBLE_FRAC) != DOUBLE_ZERO) ); +} + +INLINE int is_qnan_double(FPR x) +{ + return( ((x.id & DOUBLE_EXP) == DOUBLE_EXP) && + ((x.id & U64(0x0007fffffffffff)) == U64(0x000000000000000)) && + ((x.id & U64(0x000800000000000)) == U64(0x000800000000000)) ); +} + +INLINE int is_snan_double(FPR x) +{ + return( ((x.id & DOUBLE_EXP) == DOUBLE_EXP) && + ((x.id & DOUBLE_FRAC) != DOUBLE_ZERO) && + ((x.id & U64(0x0008000000000000)) == DOUBLE_ZERO) ); +} + +INLINE int is_infinity_double(FPR x) +{ + return( ((x.id & DOUBLE_EXP) == DOUBLE_EXP) && + ((x.id & DOUBLE_FRAC) == DOUBLE_ZERO) ); +} + +INLINE int is_normalized_double(FPR x) +{ + UINT64 exp; + + exp = (x.id & DOUBLE_EXP) >> 52; + + return (exp >= 1) && (exp <= 2046); +} + +INLINE int is_denormalized_double(FPR x) +{ + return( ((x.id & DOUBLE_EXP) == 0) && + ((x.id & DOUBLE_FRAC) != DOUBLE_ZERO) ); +} + +INLINE int sign_double(FPR x) +{ + return ((x.id & DOUBLE_SIGN) != 0); +} + +INLINE INT64 round_to_nearest(FPR f) +{ + if (f.fd >= 0) + { + return (INT64)(f.fd + 0.5); + } + else + { + return -(INT64)(-f.fd + 0.5); + } +} + +INLINE INT64 round_toward_zero(FPR f) +{ + return (INT64)(f.fd); +} + +INLINE INT64 round_toward_positive_infinity(FPR f) +{ + double r = ceil(f.fd); + return (INT64)(r); +} + +INLINE INT64 round_toward_negative_infinity(FPR f) +{ + double r = floor(f.fd); + return (INT64)(r); +} + + +INLINE void set_fprf(FPR f) +{ + UINT32 fprf; + + // see page 3-30, 3-31 + + if (is_qnan_double(f)) + { + fprf = 0x11; + } + else if (is_infinity_double(f)) + { + if (sign_double(f)) // -INF + fprf = 0x09; + else // +INF + fprf = 0x05; + } + else if (is_normalized_double(f)) + { + if (sign_double(f)) // -Normalized + fprf = 0x08; + else // +Normalized + fprf = 0x04; + } + else if (is_denormalized_double(f)) + { + if (sign_double(f)) // -Denormalized + fprf = 0x18; + else // +Denormalized + fprf = 0x14; + } + else // Zero + { + if (sign_double(f)) // -Zero + fprf = 0x12; + else // +Zero + fprf = 0x02; + } + + ppc.fpscr &= ~0x0001f000; + ppc.fpscr |= (fprf << 12); +} + + + +#define SET_VXSNAN(a, b) if (is_snan_double(a) || is_snan_double(b)) ppc.fpscr |= 0x80000000 +#define SET_VXSNAN_1(c) if (is_snan_double(c)) ppc.fpscr |= 0x80000000 + + + + +static void ppc_lfs(UINT32 op) +{ + UINT32 ea = SIMM16; + UINT32 a = RA; + UINT32 t = RT; + FPR32 f; + + if(a) + ea += REG(a); + + f.i = READ32(ea); + FPR(t).fd = (double)(f.f); +} + +static void ppc_lfsu(UINT32 op) +{ + UINT32 ea = SIMM16; + UINT32 a = RA; + UINT32 t = RT; + FPR32 f; + + ea += REG(a); + + f.i = READ32(ea); + FPR(t).fd = (double)(f.f); + + REG(a) = ea; +} + +#ifndef PPC_DRC +static void ppc_lfd(UINT32 op) +{ + UINT32 ea = SIMM16; + UINT32 a = RA; + UINT32 t = RT; + + if(a) + ea += REG(a); + + FPR(t).id = READ64(ea); +} + +static void ppc_lfdu(UINT32 op) +{ + UINT32 ea = SIMM16; + UINT32 a = RA; + UINT32 d = RD; + + ea += REG(a); + + FPR(d).id = READ64(ea); + + REG(a) = ea; +} +#endif + +static void ppc_stfs(UINT32 op) +{ + UINT32 ea = SIMM16; + UINT32 a = RA; + UINT32 t = RT; + FPR32 f; + + if(a) + ea += REG(a); + + f.f = (float)(FPR(t).fd); + WRITE32(ea, f.i); +} + +static void ppc_stfsu(UINT32 op) +{ + UINT32 ea = SIMM16; + UINT32 a = RA; + UINT32 t = RT; + FPR32 f; + + ea += REG(a); + + f.f = (float)(FPR(t).fd); + WRITE32(ea, f.i); + + REG(a) = ea; +} + +#ifndef PPC_DRC +static void ppc_stfd(UINT32 op) +{ + UINT32 ea = SIMM16; + UINT32 a = RA; + UINT32 t = RT; + + if(a) + ea += REG(a); + + WRITE64(ea, FPR(t).id); +} + +static void ppc_stfdu(UINT32 op) +{ + UINT32 ea = SIMM16; + UINT32 a = RA; + UINT32 t = RT; + + ea += REG(a); + + WRITE64(ea, FPR(t).id); + + REG(a) = ea; +} + +static void ppc_lfdux(UINT32 op) +{ + UINT32 ea = REG(RB); + UINT32 a = RA; + UINT32 d = RD; + + ea += REG(a); + + FPR(d).id = READ64(ea); + + REG(a) = ea; +} + +static void ppc_lfdx(UINT32 op) +{ + UINT32 ea = REG(RB); + UINT32 a = RA; + UINT32 d = RD; + + if(a) + ea += REG(a); + + FPR(d).id = READ64(ea); +} +#endif + +static void ppc_lfsux(UINT32 op) +{ + UINT32 ea = REG(RB); + UINT32 a = RA; + UINT32 t = RT; + FPR32 f; + + ea += REG(a); + + f.i = READ32(ea); + FPR(t).fd = (double)(f.f); + + REG(a) = ea; +} + +static void ppc_lfsx(UINT32 op) +{ + UINT32 ea = REG(RB); + UINT32 a = RA; + UINT32 t = RT; + FPR32 f; + + if(a) + ea += REG(a); + + f.i = READ32(ea); + FPR(t).fd = (double)(f.f); +} + +static void ppc_mfsr(UINT32 op) +{ + UINT32 sr = (op >> 16) & 15; + UINT32 t = RT; + + CHECK_SUPERVISOR(); + + REG(t) = ppc.sr[sr]; +} + +static void ppc_mfsrin(UINT32 op) +{ + UINT32 b = RB; + UINT32 t = RT; + + CHECK_SUPERVISOR(); + + REG(t) = ppc.sr[REG(b) >> 28]; +} + +static void ppc_mftb(UINT32 op) +{ + UINT32 x = SPRF; + + switch(x) + { + case 268: REG(RT) = (UINT32)(ppc_read_timebase()); break; + case 269: REG(RT) = (UINT32)(ppc_read_timebase() >> 32); break; + default: fatalerror("ppc: Invalid timebase register %d at %08X\n", x, ppc.pc); break; + } +} + +static void ppc_mtsr(UINT32 op) +{ + UINT32 sr = (op >> 16) & 15; + UINT32 t = RT; + + CHECK_SUPERVISOR(); + + ppc.sr[sr] = REG(t); +} + +static void ppc_mtsrin(UINT32 op) +{ + UINT32 b = RB; + UINT32 t = RT; + + CHECK_SUPERVISOR(); + + ppc.sr[REG(b) >> 28] = REG(t); +} + +#ifndef PPC_DRC +static void ppc_dcba(UINT32 op) +{ + /* TODO: Cache not emulated so this opcode doesn't need to be implemented */ +} + +static void ppc_stfdux(UINT32 op) +{ + UINT32 ea = REG(RB); + UINT32 a = RA; + UINT32 t = RT; + + ea += REG(a); + + WRITE64(ea, FPR(t).id); + + REG(a) = ea; +} +#endif + +static void ppc_stfdx(UINT32 op) +{ + UINT32 ea = REG(RB); + UINT32 a = RA; + UINT32 t = RT; + + if(a) + ea += REG(a); + + WRITE64(ea, FPR(t).id); +} + +static void ppc_stfiwx(UINT32 op) +{ + UINT32 ea = REG(RB); + UINT32 a = RA; + UINT32 t = RT; + + if(a) + ea += REG(a); + + WRITE32(ea, (UINT32)FPR(t).id); +} + +static void ppc_stfsux(UINT32 op) +{ + UINT32 ea = REG(RB); + UINT32 a = RA; + UINT32 t = RT; + FPR32 f; + + ea += REG(a); + + f.f = (float)(FPR(t).fd); + WRITE32(ea, f.i); + + REG(a) = ea; +} + +static void ppc_stfsx(UINT32 op) +{ + UINT32 ea = REG(RB); + UINT32 a = RA; + UINT32 t = RT; + FPR32 f; + + if(a) + ea += REG(a); + + f.f = (float)(FPR(t).fd); + + WRITE32(ea, f.i); +} + +#ifndef PPC_DRC +static void ppc_tlbia(UINT32 op) +{ + /* TODO: TLB not emulated so this opcode doesn't need to implemented */ +} + +static void ppc_tlbie(UINT32 op) +{ + /* TODO: TLB not emulated so this opcode doesn't need to implemented */ +} + +static void ppc_tlbsync(UINT32 op) +{ + /* TODO: TLB not emulated so this opcode doesn't need to implemented */ +} + +static void ppc_eciwx(UINT32 op) +{ + ppc_unimplemented(op); +} + +static void ppc_ecowx(UINT32 op) +{ + ppc_unimplemented(op); +} +#endif + +static void ppc_fabsx(UINT32 op) +{ + UINT32 b = RB; + UINT32 t = RT; + + CHECK_FPU_AVAILABLE(); + + FPR(t).id = FPR(b).id & ~DOUBLE_SIGN; + + if( RCBIT ) { + SET_CR1(); + } +} + +static void ppc_faddx(UINT32 op) +{ + UINT32 b = RB; + UINT32 a = RA; + UINT32 t = RT; + + CHECK_FPU_AVAILABLE(); + + SET_VXSNAN(FPR(a), FPR(b)); + + FPR(t).fd = FPR(a).fd + FPR(b).fd; + + set_fprf(FPR(t)); + if( RCBIT ) { + SET_CR1(); + } +} + +static void ppc_fcmpo(UINT32 op) +{ + UINT32 b = RB; + UINT32 a = RA; + UINT32 t = (RT >> 2); + UINT32 c; + + CHECK_FPU_AVAILABLE(); + + SET_VXSNAN(FPR(a), FPR(b)); + + if(is_nan_double(FPR(a)) || is_nan_double(FPR(b))) + { + c = 1; /* OX */ + if(is_snan_double(FPR(a)) || is_snan_double(FPR(b))) { + ppc.fpscr |= 0x01000000; /* VXSNAN */ + + if(!(ppc.fpscr & 0x40000000) || is_qnan_double(FPR(a)) || is_qnan_double(FPR(b))) + ppc.fpscr |= 0x00080000; /* VXVC */ + } + } + else if(FPR(a).fd < FPR(b).fd){ + c = 8; /* FX */ + } + else if(FPR(a).fd > FPR(b).fd){ + c = 4; /* FEX */ + } + else { + c = 2; /* VX */ + } + + CR(t) = c; + + ppc.fpscr &= ~0x0001F000; + ppc.fpscr |= (c << 12); +} + +static void ppc_fcmpu(UINT32 op) +{ + UINT32 b = RB; + UINT32 a = RA; + UINT32 t = (RT >> 2); + UINT32 c; + + CHECK_FPU_AVAILABLE(); + + SET_VXSNAN(FPR(a), FPR(b)); + + if(is_nan_double(FPR(a)) || is_nan_double(FPR(b))) + { + c = 1; /* OX */ + if(is_snan_double(FPR(a)) || is_snan_double(FPR(b))) { + ppc.fpscr |= 0x01000000; /* VXSNAN */ + } + } + else if(FPR(a).fd < FPR(b).fd){ + c = 8; /* FX */ + } + else if(FPR(a).fd > FPR(b).fd){ + c = 4; /* FEX */ + } + else { + c = 2; /* VX */ + } + + CR(t) = c; + + ppc.fpscr &= ~0x0001F000; + ppc.fpscr |= (c << 12); +} + +static void ppc_fctiwx(UINT32 op) +{ + UINT32 b = RB; + UINT32 t = RT; + INT64 r = 0; + + // TODO: fix FPSCR flags FX,VXSNAN,VXCVI + + CHECK_FPU_AVAILABLE(); + + SET_VXSNAN_1(FPR(b)); + + switch(ppc.fpscr & 3) + { + case 0: r = (INT64)round_to_nearest(FPR(b)); break; + case 1: r = (INT64)round_toward_zero(FPR(b)); break; + case 2: r = (INT64)round_toward_positive_infinity(FPR(b)); break; + case 3: r = (INT64)round_toward_negative_infinity(FPR(b)); break; + } + + if(r > (INT64)((INT32)0x7FFFFFFF)) + { + FPR(t).id = 0x7FFFFFFF; + // FPSCR[FR] = 0 + // FPSCR[FI] = 1 + // FPSCR[XX] = 1 + } + else if(FPR(b).fd < (INT64)((INT32)0x80000000)) + { + FPR(t).id = 0x80000000; + // FPSCR[FR] = 1 + // FPSCR[FI] = 1 + // FPSCR[XX] = 1 + } + else + { + FPR(t).id = (UINT32)r; + // FPSCR[FR] = t.iw > t.fd + // FPSCR[FI] = t.iw == t.fd + // FPSCR[XX] = ? + } + + // FPSCR[FPRF] = undefined (leave it as is) + if( RCBIT ) { + SET_CR1(); + } +} + +static void ppc_fctiwzx(UINT32 op) +{ + UINT32 b = RB; + UINT32 t = RT; + INT64 r; + + // TODO: fix FPSCR flags FX,VXSNAN,VXCVI + + CHECK_FPU_AVAILABLE(); + + SET_VXSNAN_1(FPR(b)); + r = round_toward_zero(FPR(b)); + + if(r > (INT64)((INT32)0x7fffffff)) + { + FPR(t).id = 0x7fffffff; + // FPSCR[FR] = 0 + // FPSCR[FI] = 1 + // FPSCR[XX] = 1 + + } + else if(r < (INT64)((INT32)0x80000000)) + { + FPR(t).id = 0x80000000; + // FPSCR[FR] = 1 + // FPSCR[FI] = 1 + // FPSCR[XX] = 1 + } + else + { + FPR(t).id = (UINT32)r; + // FPSCR[FR] = t.iw > t.fd + // FPSCR[FI] = t.iw == t.fd + // FPSCR[XX] = ? + } + + // FPSCR[FPRF] = undefined (leave it as is) + if( RCBIT ) { + SET_CR1(); + } +} + +static void ppc_fdivx(UINT32 op) +{ + UINT32 b = RB; + UINT32 a = RA; + UINT32 t = RT; + + CHECK_FPU_AVAILABLE(); + + SET_VXSNAN(FPR(a), FPR(b)); + + FPR(t).fd = FPR(a).fd / FPR(b).fd; + + set_fprf(FPR(t)); + if( RCBIT ) { + SET_CR1(); + } +} + +static void ppc_fmrx(UINT32 op) +{ + UINT32 b = RB; + UINT32 t = RT; + + CHECK_FPU_AVAILABLE(); + + FPR(t).fd = FPR(b).fd; + + if( RCBIT ) { + SET_CR1(); + } +} + +static void ppc_fnabsx(UINT32 op) +{ + UINT32 b = RB; + UINT32 t = RT; + + CHECK_FPU_AVAILABLE(); + + FPR(t).id = FPR(b).id | DOUBLE_SIGN; + + if( RCBIT ) { + SET_CR1(); + } +} + +static void ppc_fnegx(UINT32 op) +{ + UINT32 b = RB; + UINT32 t = RT; + + CHECK_FPU_AVAILABLE(); + + FPR(t).id = FPR(b).id ^ DOUBLE_SIGN; + + if( RCBIT ) { + SET_CR1(); + } +} + +static void ppc_frspx(UINT32 op) +{ + UINT32 b = RB; + UINT32 t = RT; + + CHECK_FPU_AVAILABLE(); + + SET_VXSNAN_1(FPR(b)); + + FPR(t).fd = (float)FPR(b).fd; + + set_fprf(FPR(t)); + if( RCBIT ) { + SET_CR1(); + } +} + +static void ppc_frsqrtex(UINT32 op) +{ + UINT32 b = RB; + UINT32 t = RT; + + CHECK_FPU_AVAILABLE(); + + SET_VXSNAN_1(FPR(b)); + + FPR(t).fd = 1.0 / sqrt(FPR(b).fd); /* verify this */ + + set_fprf(FPR(t)); + if( RCBIT ) { + SET_CR1(); + } +} + +static void ppc_fsqrtx(UINT32 op) +{ + /* NOTE: PPC603e doesn't support this opcode */ + UINT32 b = RB; + UINT32 t = RT; + + CHECK_FPU_AVAILABLE(); + + SET_VXSNAN_1(FPR(b)); + + FPR(t).fd = (double)(sqrt(FPR(b).fd)); + + set_fprf(FPR(t)); + if( RCBIT ) { + SET_CR1(); + } +} + +static void ppc_fsubx(UINT32 op) +{ + UINT32 b = RB; + UINT32 a = RA; + UINT32 t = RT; + + CHECK_FPU_AVAILABLE(); + + SET_VXSNAN(FPR(a), FPR(b)); + + FPR(t).fd = FPR(a).fd - FPR(b).fd; + + set_fprf(FPR(t)); + if( RCBIT ) { + SET_CR1(); + } +} + +static void ppc_mffsx(UINT32 op) +{ + FPR(RT).id = (UINT32)ppc.fpscr; + + if( RCBIT ) { + SET_CR1(); + } +} + +static void ppc_mtfsb0x(UINT32 op) +{ + UINT32 crbD; + + crbD = (op >> 21) & 0x1F; + + if (crbD != 1 && crbD != 2) // these bits cannot be explicitly cleared + ppc.fpscr &= ~(1 << (31 - crbD)); + + if( RCBIT ) { + SET_CR1(); + } +} + +static void ppc_mtfsb1x(UINT32 op) +{ + UINT32 crbD; + + crbD = (op >> 21) & 0x1F; + + if (crbD != 1 && crbD != 2) // these bits cannot be explicitly cleared + ppc.fpscr |= (1 << (31 - crbD)); + + if( RCBIT ) { + SET_CR1(); + } +} + +static void ppc_mtfsfx(UINT32 op) +{ + UINT32 b = RB; + UINT32 f = FM; + + f = ppc_field_xlat[FM]; + + ppc.fpscr &= (~f) | ~(FPSCR_FEX | FPSCR_VX); + ppc.fpscr |= (UINT32)(FPR(b).id) & ~(FPSCR_FEX | FPSCR_VX); + + // FEX, VX + + if( RCBIT ) { + SET_CR1(); + } +} + +static void ppc_mtfsfix(UINT32 op) +{ + UINT32 crfd = CRFD; + UINT32 imm = (op >> 12) & 0xF; + + /* + * According to the manual: + * + * If bits 0 and 3 of FPSCR are to be modified, they take the immediate + * value specified. Bits 1 and 2 (FEX and VX) are set according to the + * "usual rule" and not from IMM[1-2]. + * + * The "usual rule" is not emulated, so these bits simply aren't modified + * at all here. + */ + + crfd = (7 - crfd) * 4; // calculate LSB position of field + + if (crfd == 28) // field containing FEX and VX is special... + { // bits 1 and 2 of FPSCR must not be altered + ppc.fpscr &= 0x9fffffff; + ppc.fpscr |= (imm & 0x9fffffff); + } + + ppc.fpscr &= ~(0xf << crfd); // clear field + ppc.fpscr |= (imm << crfd); // insert new data + + if( RCBIT ) { + SET_CR1(); + } +} + +static void ppc_mcrfs(UINT32 op) +{ + UINT32 crfs, f; + crfs = CRFA; + + f = ppc.fpscr >> ((7 - crfs) * 4); // get crfS field from FPSCR + f &= 0xf; + + switch(crfs) // determine which exception bits to clear in FPSCR + { + case 0: // FX, OX + ppc.fpscr &= ~0x90000000; + break; + case 1: // UX, ZX, XX, VXSNAN + ppc.fpscr &= ~0x0f000000; + break; + case 2: // VXISI, VXIDI, VXZDZ, VXIMZ + ppc.fpscr &= ~0x00F00000; + break; + case 3: // VXVC + ppc.fpscr &= ~0x00080000; + break; + case 5: // VXSOFT, VXSQRT, VXCVI + ppc.fpscr &= ~0x00000e00; + break; + default: + break; + } + + CR(CRFD) = f; +} + +static void ppc_faddsx(UINT32 op) +{ + UINT32 b = RB; + UINT32 a = RA; + UINT32 t = RT; + + CHECK_FPU_AVAILABLE(); + + SET_VXSNAN(FPR(a), FPR(b)); + + FPR(t).fd = (float)(FPR(a).fd + FPR(b).fd); + + set_fprf(FPR(t)); + if( RCBIT ) { + SET_CR1(); + } +} + +static void ppc_fdivsx(UINT32 op) +{ + UINT32 b = RB; + UINT32 a = RA; + UINT32 t = RT; + + CHECK_FPU_AVAILABLE(); + + SET_VXSNAN(FPR(a), FPR(b)); + + FPR(t).fd = (float)(FPR(a).fd / FPR(b).fd); + + set_fprf(FPR(t)); + if( RCBIT ) { + SET_CR1(); + } +} + +static void ppc_fresx(UINT32 op) +{ + UINT32 b = RB; + UINT32 t = RT; + + CHECK_FPU_AVAILABLE(); + + SET_VXSNAN_1(FPR(b)); + + FPR(t).fd = 1.0 / FPR(b).fd; /* ??? */ + + set_fprf(FPR(t)); + if( RCBIT ) { + SET_CR1(); + } +} + +static void ppc_fsqrtsx(UINT32 op) +{ + /* NOTE: This opcode is not supported in PPC603e */ + UINT32 b = RB; + UINT32 t = RT; + + CHECK_FPU_AVAILABLE(); + + SET_VXSNAN_1(FPR(b)); + + FPR(t).fd = (float)(sqrt(FPR(b).fd)); + + set_fprf(FPR(t)); + if( RCBIT ) { + SET_CR1(); + } +} + +static void ppc_fsubsx(UINT32 op) +{ + UINT32 b = RB; + UINT32 a = RA; + UINT32 t = RT; + + CHECK_FPU_AVAILABLE(); + + SET_VXSNAN(FPR(a), FPR(b)); + + FPR(t).fd = (float)(FPR(a).fd - FPR(b).fd); + + set_fprf(FPR(t)); + if( RCBIT ) { + SET_CR1(); + } +} + +static void ppc_fmaddx(UINT32 op) +{ + UINT32 c = RC; + UINT32 b = RB; + UINT32 a = RA; + UINT32 t = RT; + + CHECK_FPU_AVAILABLE(); + + SET_VXSNAN(FPR(a), FPR(b)); + SET_VXSNAN_1(FPR(c)); + + FPR(t).fd = ((FPR(a).fd * FPR(c).fd) + FPR(b).fd); + + set_fprf(FPR(t)); + if( RCBIT ) { + SET_CR1(); + } +} + +static void ppc_fmsubx(UINT32 op) +{ + UINT32 c = RC; + UINT32 b = RB; + UINT32 a = RA; + UINT32 t = RT; + + CHECK_FPU_AVAILABLE(); + + SET_VXSNAN(FPR(a), FPR(b)); + SET_VXSNAN_1(FPR(c)); + + FPR(t).fd = ((FPR(a).fd * FPR(c).fd) - FPR(b).fd); + + set_fprf(FPR(t)); + if( RCBIT ) { + SET_CR1(); + } +} + +static void ppc_fmulx(UINT32 op) +{ + UINT32 c = RC; + UINT32 a = RA; + UINT32 t = RT; + + CHECK_FPU_AVAILABLE(); + + SET_VXSNAN(FPR(a), FPR(c)); + + FPR(t).fd = (FPR(a).fd * FPR(c).fd); + + set_fprf(FPR(t)); + if( RCBIT ) { + SET_CR1(); + } +} + +static void ppc_fnmaddx(UINT32 op) +{ + UINT32 c = RC; + UINT32 b = RB; + UINT32 a = RA; + UINT32 t = RT; + + CHECK_FPU_AVAILABLE(); + + SET_VXSNAN(FPR(a), FPR(b)); + SET_VXSNAN_1(FPR(c)); + + FPR(t).fd = (-((FPR(a).fd * FPR(c).fd) + FPR(b).fd)); + + set_fprf(FPR(t)); + if( RCBIT ) { + SET_CR1(); + } +} + +static void ppc_fnmsubx(UINT32 op) +{ + UINT32 c = RC; + UINT32 b = RB; + UINT32 a = RA; + UINT32 t = RT; + + CHECK_FPU_AVAILABLE(); + + SET_VXSNAN(FPR(a), FPR(b)); + SET_VXSNAN_1(FPR(c)); + + FPR(t).fd = (-((FPR(a).fd * FPR(c).fd) - FPR(b).fd)); + + set_fprf(FPR(t)); + if( RCBIT ) { + SET_CR1(); + } +} + +static void ppc_fselx(UINT32 op) +{ + UINT32 c = RC; + UINT32 b = RB; + UINT32 a = RA; + UINT32 t = RT; + + CHECK_FPU_AVAILABLE(); + + FPR(t).fd = (FPR(a).fd >= 0.0) ? FPR(c).fd : FPR(b).fd; + + if( RCBIT ) { + SET_CR1(); + } +} + +static void ppc_fmaddsx(UINT32 op) +{ + UINT32 c = RC; + UINT32 b = RB; + UINT32 a = RA; + UINT32 t = RT; + + CHECK_FPU_AVAILABLE(); + + SET_VXSNAN(FPR(a), FPR(b)); + SET_VXSNAN_1(FPR(c)); + + FPR(t).fd = (float)((FPR(a).fd * FPR(c).fd) + FPR(b).fd); + + set_fprf(FPR(t)); + if( RCBIT ) { + SET_CR1(); + } +} + +static void ppc_fmsubsx(UINT32 op) +{ + UINT32 c = RC; + UINT32 b = RB; + UINT32 a = RA; + UINT32 t = RT; + + CHECK_FPU_AVAILABLE(); + + SET_VXSNAN(FPR(a), FPR(b)); + SET_VXSNAN_1(FPR(c)); + + FPR(t).fd = (float)((FPR(a).fd * FPR(c).fd) - FPR(b).fd); + + set_fprf(FPR(t)); + if( RCBIT ) { + SET_CR1(); + } +} + +static void ppc_fmulsx(UINT32 op) +{ + UINT32 c = RC; + UINT32 a = RA; + UINT32 t = RT; + + CHECK_FPU_AVAILABLE(); + SET_VXSNAN(FPR(a), FPR(c)); + + FPR(t).fd = (float)(FPR(a).fd * FPR(c).fd); + + set_fprf(FPR(t)); + if( RCBIT ) { + SET_CR1(); + } +} + +static void ppc_fnmaddsx(UINT32 op) +{ + UINT32 c = RC; + UINT32 b = RB; + UINT32 a = RA; + UINT32 t = RT; + + CHECK_FPU_AVAILABLE(); + + SET_VXSNAN(FPR(a), FPR(b)); + SET_VXSNAN_1(FPR(c)); + + FPR(t).fd = (float)(-((FPR(a).fd * FPR(c).fd) + FPR(b).fd)); + + set_fprf(FPR(t)); + if( RCBIT ) { + SET_CR1(); + } +} + +static void ppc_fnmsubsx(UINT32 op) +{ + UINT32 c = RC; + UINT32 b = RB; + UINT32 a = RA; + UINT32 t = RT; + + CHECK_FPU_AVAILABLE(); + + SET_VXSNAN(FPR(a), FPR(b)); + SET_VXSNAN_1(FPR(c)); + + FPR(t).fd = (float)(-((FPR(a).fd * FPR(c).fd) - FPR(b).fd)); + + set_fprf(FPR(t)); + if( RCBIT ) { + SET_CR1(); + } +} diff --git a/src/devices/cpu/powerpc/ppccom.c b/src/devices/cpu/powerpc/ppccom.c new file mode 100644 index 00000000000..a98872029ec --- /dev/null +++ b/src/devices/cpu/powerpc/ppccom.c @@ -0,0 +1,2879 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + ppccom.c + + Common PowerPC definitions and functions + +***************************************************************************/ + +#include "emu.h" +#include "ppccom.h" +#include "ppcfe.h" + + +/*************************************************************************** + DEBUGGING +***************************************************************************/ + +#define PRINTF_SPU (0) +#define PRINTF_DECREMENTER (0) + + + +/*************************************************************************** + CONSTANTS +***************************************************************************/ + +#define DOUBLE_SIGN (U64(0x8000000000000000)) +#define DOUBLE_EXP (U64(0x7ff0000000000000)) +#define DOUBLE_FRAC (U64(0x000fffffffffffff)) +#define DOUBLE_ZERO (0) + + + +/*************************************************************************** + PRIVATE GLOBAL VARIABLES +***************************************************************************/ + +/* lookup table for FP modes */ +static const UINT8 fpmode_source[4] = +{ + uml::ROUND_ROUND, + uml::ROUND_TRUNC, + uml::ROUND_CEIL, + uml::ROUND_FLOOR +}; + +/* flag lookup table for SZ */ +static const UINT8 sz_cr_table_source[32] = +{ + /* ..... */ 0x4, + /* ....C */ 0x4, + /* ...V. */ 0x4, + /* ...VC */ 0x4, + /* ..Z.. */ 0x2, + /* ..Z.C */ 0x2, + /* ..ZV. */ 0x2, + /* ..ZVC */ 0x2, + /* .S... */ 0x8, + /* .S..C */ 0x8, + /* .S.V. */ 0x8, + /* .S.VC */ 0x8, + /* .SZ.. */ 0x2, + /* .SZ.C */ 0x2, + /* .SZV. */ 0x2, + /* .SZVC */ 0x2, + /* U.... */ 0x4, + /* U...C */ 0x4, + /* U..V. */ 0x4, + /* U..VC */ 0x4, + /* U.Z.. */ 0x2, + /* U.Z.C */ 0x2, + /* U.ZV. */ 0x2, + /* U.ZVC */ 0x2, + /* US... */ 0x8, + /* US..C */ 0x8, + /* US.V. */ 0x8, + /* US.VC */ 0x8, + /* USZ.. */ 0x2, + /* USZ.C */ 0x2, + /* USZV. */ 0x2, + /* USZVC */ 0x2 +}; + +/* flag lookup table for CMP */ +static const UINT8 cmp_cr_table_source[32] = +{ + /* ..... */ 0x4, + /* ....C */ 0x4, + /* ...V. */ 0x8, + /* ...VC */ 0x8, + /* ..Z.. */ 0x2, + /* ..Z.C */ 0x2, + /* ..ZV. */ 0x2, + /* ..ZVC */ 0x2, + /* .S... */ 0x8, + /* .S..C */ 0x8, + /* .S.V. */ 0x4, + /* .S.VC */ 0x4, + /* .SZ.. */ 0x2, + /* .SZ.C */ 0x2, + /* .SZV. */ 0x2, + /* .SZVC */ 0x2, + /* U.... */ 0x4, + /* U...C */ 0x4, + /* U..V. */ 0x8, + /* U..VC */ 0x8, + /* U.Z.. */ 0x2, + /* U.Z.C */ 0x2, + /* U.ZV. */ 0x2, + /* U.ZVC */ 0x2, + /* US... */ 0x8, + /* US..C */ 0x8, + /* US.V. */ 0x4, + /* US.VC */ 0x4, + /* USZ.. */ 0x2, + /* USZ.C */ 0x2, + /* USZV. */ 0x2, + /* USZVC */ 0x2 +}; + +/* flag lookup table for CMPL */ +static const UINT8 cmpl_cr_table_source[32] = +{ + /* ..... */ 0x4, + /* ....C */ 0x8, + /* ...V. */ 0x4, + /* ...VC */ 0x8, + /* ..Z.. */ 0x2, + /* ..Z.C */ 0x2, + /* ..ZV. */ 0x2, + /* ..ZVC */ 0x2, + /* .S... */ 0x4, + /* .S..C */ 0x8, + /* .S.V. */ 0x4, + /* .S.VC */ 0x8, + /* .SZ.. */ 0x2, + /* .SZ.C */ 0x2, + /* .SZV. */ 0x2, + /* .SZVC */ 0x2, + /* U.... */ 0x4, + /* U...C */ 0x8, + /* U..V. */ 0x4, + /* U..VC */ 0x8, + /* U.Z.. */ 0x2, + /* U.Z.C */ 0x2, + /* U.ZV. */ 0x2, + /* U.ZVC */ 0x2, + /* US... */ 0x4, + /* US..C */ 0x8, + /* US.V. */ 0x4, + /* US.VC */ 0x8, + /* USZ.. */ 0x2, + /* USZ.C */ 0x2, + /* USZV. */ 0x2, + /* USZVC */ 0x2 +}; + +/* flag lookup table for FCMP */ +static const UINT8 fcmp_cr_table_source[32] = +{ + /* ..... */ 0x4, + /* ....C */ 0x8, + /* ...V. */ 0x4, + /* ...VC */ 0x8, + /* ..Z.. */ 0x2, + /* ..Z.C */ 0xa, + /* ..ZV. */ 0x2, + /* ..ZVC */ 0xa, + /* .S... */ 0x4, + /* .S..C */ 0x8, + /* .S.V. */ 0x4, + /* .S.VC */ 0x8, + /* .SZ.. */ 0x2, + /* .SZ.C */ 0xa, + /* .SZV. */ 0x2, + /* .SZVC */ 0xa, + /* U.... */ 0x5, + /* U...C */ 0x9, + /* U..V. */ 0x5, + /* U..VC */ 0x9, + /* U.Z.. */ 0x3, + /* U.Z.C */ 0xb, + /* U.ZV. */ 0x3, + /* U.ZVC */ 0xb, + /* US... */ 0x5, + /* US..C */ 0x9, + /* US.V. */ 0x5, + /* US.VC */ 0x9, + /* USZ.. */ 0x3, + /* USZ.C */ 0xb, + /* USZV. */ 0x3, + /* USZVC */ 0xb +}; + + +const device_type PPC601 = &device_creator; +const device_type PPC602 = &device_creator; +const device_type PPC603 = &device_creator; +const device_type PPC603E = &device_creator; +const device_type PPC603R = &device_creator; +const device_type PPC604 = &device_creator; +const device_type MPC8240 = &device_creator; +const device_type PPC403GA = &device_creator; +const device_type PPC403GCX = &device_creator; +const device_type PPC405GP = &device_creator; + + +ppc_device::ppc_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, int address_bits, int data_bits, powerpc_flavor flavor, UINT32 cap, UINT32 tb_divisor, address_map_constructor internal_map) + : cpu_device(mconfig, type, name, tag, owner, clock, shortname, __FILE__) + , m_program_config("program", ENDIANNESS_BIG, data_bits, address_bits, 0, internal_map) + , c_bus_frequency(0) + , m_core(NULL) + , m_bus_freq_multiplier(1) + , m_vtlb(NULL) + , m_flavor(flavor) + , m_cap(cap) + , m_tb_divisor(tb_divisor) + , m_cache(CACHE_SIZE + sizeof(internal_ppc_state)) + , m_drcuml(NULL) + , m_drcfe(NULL) + , m_drcoptions(0) +{ + m_program_config.m_logaddr_width = 32; + m_program_config.m_page_shift = POWERPC_MIN_PAGE_SHIFT; +} + +//ppc403_device::ppc403_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) +// : ppc_device(mconfig, PPC403, "PPC403", tag, owner, clock, "ppc403", 32?, 64?) +//{ +//} +// +//ppc405_device::ppc405_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) +// : ppc_device(mconfig, PPC405, "PPC405", tag, owner, clock, "ppc405", 32?, 64?) +//{ +//} + +ppc603_device::ppc603_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : ppc_device(mconfig, PPC603, "PowerPC 603", tag, owner, clock, "ppc603", 32, 64, PPC_MODEL_603, PPCCAP_OEA | PPCCAP_VEA | PPCCAP_FPU | PPCCAP_MISALIGNED | PPCCAP_603_MMU, 4, NULL) +{ +} + +ppc603e_device::ppc603e_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : ppc_device(mconfig, PPC603E, "PowerPC 603e", tag, owner, clock, "ppc603e", 32, 64, PPC_MODEL_603E, PPCCAP_OEA | PPCCAP_VEA | PPCCAP_FPU | PPCCAP_MISALIGNED | PPCCAP_603_MMU, 4, NULL) +{ +} + +ppc603r_device::ppc603r_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : ppc_device(mconfig, PPC603R, "PowerPC 603R", tag, owner, clock, "ppc603r", 32, 64, PPC_MODEL_603R, PPCCAP_OEA | PPCCAP_VEA | PPCCAP_FPU | PPCCAP_MISALIGNED | PPCCAP_603_MMU, 4, NULL) +{ +} + +ppc602_device::ppc602_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : ppc_device(mconfig, PPC602, "PowerPC 602", tag, owner, clock, "ppc602", 32, 64, PPC_MODEL_602, PPCCAP_OEA | PPCCAP_VEA | PPCCAP_FPU | PPCCAP_MISALIGNED | PPCCAP_603_MMU, 4, NULL) +{ +} + +mpc8240_device::mpc8240_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : ppc_device(mconfig, MPC8240, "PowerPC MPC8240", tag, owner, clock, "mpc8240", 32, 64, PPC_MODEL_MPC8240, PPCCAP_OEA | PPCCAP_VEA | PPCCAP_FPU | PPCCAP_MISALIGNED | PPCCAP_603_MMU, 4/* unknown */, NULL) +{ +} + +ppc601_device::ppc601_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : ppc_device(mconfig, PPC601, "PowerPC 601", tag, owner, clock, "ppc601", 32, 64, PPC_MODEL_601, PPCCAP_OEA | PPCCAP_VEA | PPCCAP_FPU | PPCCAP_MISALIGNED | PPCCAP_MFIOC | PPCCAP_601BAT, 0/* no TB */, NULL) +{ +} + +ppc604_device::ppc604_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : ppc_device(mconfig, PPC604, "PowerPC 604", tag, owner, clock, "ppc604", 32, 64, PPC_MODEL_604, PPCCAP_OEA | PPCCAP_VEA | PPCCAP_FPU | PPCCAP_MISALIGNED | PPCCAP_604_MMU, 4, NULL) +{ +} + +static ADDRESS_MAP_START( internal_ppc4xx, AS_PROGRAM, 32, ppc4xx_device ) + AM_RANGE(0x40000000, 0x4000000f) AM_READWRITE8(ppc4xx_spu_r, ppc4xx_spu_w, 0xffffffff) +ADDRESS_MAP_END + +ppc4xx_device::ppc4xx_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, powerpc_flavor flavor, UINT32 cap, UINT32 tb_divisor) + : ppc_device(mconfig, type, name, tag, owner, clock, shortname, 31, 32, flavor, cap, tb_divisor, ADDRESS_MAP_NAME(internal_ppc4xx)) +{ +} + +ppc403ga_device::ppc403ga_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : ppc4xx_device(mconfig, PPC403GA, "PowerPC 403GA", tag, owner, clock, "ppc403ga", PPC_MODEL_403GA, PPCCAP_4XX, 1) +{ +} + +ppc403gcx_device::ppc403gcx_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : ppc4xx_device(mconfig, PPC403GCX, "PowerPC 403GCX", tag, owner, clock, "ppc403gcx", PPC_MODEL_403GCX, PPCCAP_4XX, 1) +{ +} + +ppc405gp_device::ppc405gp_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : ppc4xx_device(mconfig, PPC405GP, "PowerPC 405GP", tag, owner, clock, "ppc405gp", PPC_MODEL_405GP, PPCCAP_4XX | PPCCAP_VEA, 1) +{ +} + + +/*************************************************************************** + INLINE FUNCTIONS +***************************************************************************/ + +/*------------------------------------------------- + page_access_allowed - return true if we are + allowed to access memory based on the type + of access and the protection bits +-------------------------------------------------*/ + +INLINE int page_access_allowed(int transtype, UINT8 key, UINT8 protbits) +{ + if (key == 0) + return (transtype == TRANSLATE_WRITE) ? (protbits != 3) : TRUE; + else + return (transtype == TRANSLATE_WRITE) ? (protbits == 2) : (protbits != 0); +} + + +/*------------------------------------------------- + get_cr - return the current CR value +-------------------------------------------------*/ + +inline UINT32 ppc_device::get_cr() +{ + return ((m_core->cr[0] & 0x0f) << 28) | + ((m_core->cr[1] & 0x0f) << 24) | + ((m_core->cr[2] & 0x0f) << 20) | + ((m_core->cr[3] & 0x0f) << 16) | + ((m_core->cr[4] & 0x0f) << 12) | + ((m_core->cr[5] & 0x0f) << 8) | + ((m_core->cr[6] & 0x0f) << 4) | + ((m_core->cr[7] & 0x0f) << 0); +} + + +/*------------------------------------------------- + set_cr - set the current CR value +-------------------------------------------------*/ + +inline void ppc_device::set_cr(UINT32 value) +{ + m_core->cr[0] = value >> 28; + m_core->cr[1] = value >> 24; + m_core->cr[2] = value >> 20; + m_core->cr[3] = value >> 16; + m_core->cr[4] = value >> 12; + m_core->cr[5] = value >> 8; + m_core->cr[6] = value >> 4; + m_core->cr[7] = value >> 0; +} + + +/*------------------------------------------------- + get_xer - return the current XER value +-------------------------------------------------*/ + +inline UINT32 ppc_device::get_xer() +{ + return m_core->spr[SPR_XER] | (m_core->xerso << 31); +} + + +/*------------------------------------------------- + set_xer - set the current XER value +-------------------------------------------------*/ + +inline void ppc_device::set_xer(UINT32 value) +{ + m_core->spr[SPR_XER] = value & ~XER_SO; + m_core->xerso = value >> 31; +} + + +/*------------------------------------------------- + get_timebase - return the current timebase + value +-------------------------------------------------*/ + +inline UINT64 ppc_device::get_timebase() +{ + if (!m_tb_divisor) + { + return (total_cycles() - m_tb_zero_cycles); + } + + return (total_cycles() - m_tb_zero_cycles) / m_tb_divisor; +} + + +/*------------------------------------------------- + set_timebase - set the timebase +-------------------------------------------------*/ + +inline void ppc_device::set_timebase(UINT64 newtb) +{ + m_tb_zero_cycles = total_cycles() - newtb * m_tb_divisor; +} + + +/*------------------------------------------------- + get_decremeter - return the current + decrementer value +-------------------------------------------------*/ + +inline UINT32 ppc_device::get_decrementer() +{ + INT64 cycles_until_zero = m_dec_zero_cycles - total_cycles(); + cycles_until_zero = MAX(cycles_until_zero, 0); + + if (!m_tb_divisor) + { + return 0; + } + + return cycles_until_zero / m_tb_divisor; +} + + +/*------------------------------------------------- + set_decrementer - set the decremeter +-------------------------------------------------*/ + +inline void ppc_device::set_decrementer(UINT32 newdec) +{ + UINT64 cycles_until_done = ((UINT64)newdec + 1) * m_tb_divisor; + UINT32 curdec = get_decrementer(); + + if (!m_tb_divisor) + { + return; + } + + if (PRINTF_DECREMENTER) + { + UINT64 total = total_cycles(); + osd_printf_debug("set_decrementer: olddec=%08X newdec=%08X divisor=%d totalcyc=%08X%08X timer=%08X%08X\n", + curdec, newdec, m_tb_divisor, + (UINT32)(total >> 32), (UINT32)total, (UINT32)(cycles_until_done >> 32), (UINT32)cycles_until_done); + } + + m_dec_zero_cycles = total_cycles() + cycles_until_done; + m_decrementer_int_timer->adjust(cycles_to_attotime(cycles_until_done)); + + if ((INT32)curdec >= 0 && (INT32)newdec < 0) + m_core->irq_pending |= 0x02; +} + + +#if 0 +/*------------------------------------------------- + is_nan_double - is a double value a NaN +-------------------------------------------------*/ + +INLINE int is_nan_double(double x) +{ + UINT64 xi = *(UINT64*)&x; + return( ((xi & DOUBLE_EXP) == DOUBLE_EXP) && + ((xi & DOUBLE_FRAC) != DOUBLE_ZERO) ); +} +#endif + + +/*------------------------------------------------- + is_qnan_double - is a double value a + quiet NaN +-------------------------------------------------*/ + +INLINE int is_qnan_double(double x) +{ + UINT64 xi = *(UINT64*)&x; + return( ((xi & DOUBLE_EXP) == DOUBLE_EXP) && + ((xi & U64(0x0007fffffffffff)) == U64(0x000000000000000)) && + ((xi & U64(0x000800000000000)) == U64(0x000800000000000)) ); +} + + +#if 0 +/*------------------------------------------------- + is_snan_double - is a double value a + signaling NaN +-------------------------------------------------*/ + +INLINE int is_snan_double(double x) +{ + UINT64 xi = *(UINT64*)&x; + return( ((xi & DOUBLE_EXP) == DOUBLE_EXP) && + ((xi & DOUBLE_FRAC) != DOUBLE_ZERO) && + ((xi & U64(0x0008000000000000)) == DOUBLE_ZERO) ); +} +#endif + + +/*------------------------------------------------- + is_infinity_double - is a double value + infinity +-------------------------------------------------*/ + +INLINE int is_infinity_double(double x) +{ + UINT64 xi = *(UINT64*)&x; + return( ((xi & DOUBLE_EXP) == DOUBLE_EXP) && + ((xi & DOUBLE_FRAC) == DOUBLE_ZERO) ); +} + + +/*------------------------------------------------- + is_normalized_double - is a double value + normalized +-------------------------------------------------*/ + +INLINE int is_normalized_double(double x) +{ + UINT64 exp; + UINT64 xi = *(UINT64*)&x; + exp = (xi & DOUBLE_EXP) >> 52; + + return (exp >= 1) && (exp <= 2046); +} + + +/*------------------------------------------------- + is_denormalized_double - is a double value + denormalized +-------------------------------------------------*/ + +INLINE int is_denormalized_double(double x) +{ + UINT64 xi = *(UINT64*)&x; + return( ((xi & DOUBLE_EXP) == 0) && + ((xi & DOUBLE_FRAC) != DOUBLE_ZERO) ); +} + + +/*------------------------------------------------- + sign_double - return sign of a double value +-------------------------------------------------*/ + +INLINE int sign_double(double x) +{ + UINT64 xi = *(UINT64*)&x; + return ((xi & DOUBLE_SIGN) != 0); +} + + + +/*************************************************************************** + INITIALIZATION AND SHUTDOWN +***************************************************************************/ + +/*------------------------------------------------- + device_start - initialize the powerpc_state + structure based on the configured type +-------------------------------------------------*/ + +void ppc_device::device_start() +{ + /* allocate the core from the near cache */ + m_core = (internal_ppc_state *)m_cache.alloc_near(sizeof(internal_ppc_state)); + memset(m_core, 0, sizeof(internal_ppc_state)); + + m_entry = NULL; + m_nocode = NULL; + m_out_of_cycles = NULL; + m_tlb_mismatch = NULL; + m_swap_tgpr = NULL; + memset(m_lsw, 0, sizeof(m_lsw)); + memset(m_stsw, 0, sizeof(m_stsw)); + memset(m_read8, 0, sizeof(m_read8)); + memset(m_write8, 0, sizeof(m_write8)); + memset(m_read16, 0, sizeof(m_read16)); + memset(m_read16mask, 0, sizeof(m_read16mask)); + memset(m_write16, 0, sizeof(m_write16)); + memset(m_write16mask, 0, sizeof(m_write16mask)); + memset(m_read32, 0, sizeof(m_read32)); + memset(m_read32align, 0, sizeof(m_read32align)); + memset(m_read32mask, 0, sizeof(m_read32mask)); + memset(m_write32, 0, sizeof(m_write32)); + memset(m_write32align, 0, sizeof(m_write32align)); + memset(m_write32mask, 0, sizeof(m_write32mask)); + memset(m_read64, 0, sizeof(m_read64)); + memset(m_read64mask, 0, sizeof(m_read64mask)); + memset(m_write64, 0, sizeof(m_write64)); + memset(m_write64mask, 0, sizeof(m_write64mask)); + memset(m_exception, 0, sizeof(m_exception)); + memset(m_exception_norecover, 0, sizeof(m_exception_norecover)); + + /* initialize the implementation state tables */ + memcpy(m_fpmode, fpmode_source, sizeof(fpmode_source)); + memcpy(m_sz_cr_table, sz_cr_table_source, sizeof(sz_cr_table_source)); + memcpy(m_cmp_cr_table, cmp_cr_table_source, sizeof(cmp_cr_table_source)); + memcpy(m_cmpl_cr_table, cmpl_cr_table_source, sizeof(cmpl_cr_table_source)); + memcpy(m_fcmp_cr_table, fcmp_cr_table_source, sizeof(fcmp_cr_table_source)); + + /* initialize based on the config */ + m_ppc_tb_base_icount = 0; + m_ppc_dec_base_icount = 0; + m_ppc_dec_trigger_cycle = 0; + m_bus_freq_multiplier = 0; + + m_npc = 0; + memset(m_dcr, 0, sizeof(m_dcr)); + + m_lr = 0; + m_ctr = 0; + m_xer = 0; + m_pvr = 0; + m_srr0 = 0; + m_srr1 = 0; + m_srr2 = 0; + m_srr3 = 0; + m_hid0 = 0; + m_hid1 = 0; + m_hid2 = 0; + m_sdr1 = 0; + memset(m_sprg, 0, sizeof(m_sprg)); + + m_dsisr = 0; + m_dar = 0; + m_ear = 0; + m_dmiss = 0; + m_dcmp = 0; + m_hash1 = 0; + m_hash2 = 0; + m_imiss = 0; + m_icmp = 0; + m_rpa = 0; + + memset(m_ibat, 0, sizeof(m_ibat)); + memset(m_dbat, 0, sizeof(m_dbat)); + + m_evpr = 0; + m_exier = 0; + m_exisr = 0; + m_bear = 0; + m_besr = 0; + m_iocr = 0; + memset(m_br, 0, sizeof(m_br)); + m_iabr = 0; + m_esr = 0; + m_iccr = 0; + m_dccr = 0; + m_pit = 0; + m_pit_counter = 0; + m_pit_int_enable = 0; + m_tsr = 0; + m_dbsr = 0; + m_sgr = 0; + m_pid = 0; + m_pbl1 = 0; + m_pbl2 = 0; + m_pbu1 = 0; + m_pbu2 = 0; + m_fit_bit = 0; + m_fit_int_enable = 0; + m_wdt_bit = 0; + m_wdt_int_enable = 0; + m_dac1 = 0; + m_dac2 = 0; + m_iac1 = 0; + m_iac2 = 0; + + memset(&m_spu_old, 0, sizeof(m_spu_old)); + memset(m_dma, 0, sizeof(m_dma)); + m_dmasr = 0; + + m_reserved = 0; + m_reserved_address = 0; + m_interrupt_pending = 0; + m_tb = 0; + m_dec = 0; + m_dec_frac = 0; + memset(m_fpr, 0, sizeof(m_fpr)); + m_lt = 0; + m_sp = 0; + m_tcr = 0; + m_ibr = 0; + m_esasrr = 0; + m_sebr = 0; + m_ser = 0; + + memset(&m_spu, 0, sizeof(m_spu)); + m_pit_reload = 0; + m_irqstate = 0; + memset(m_buffered_dma_rate, 0, sizeof(m_buffered_dma_rate)); + m_codexor = 0; + m_system_clock = 0; + m_cpu_clock = 0; + m_tb_zero_cycles = 0; + m_dec_zero_cycles = 0; + + m_arg1 = 0; + m_fastram_select = 0; + memset(m_fastram, 0, sizeof(m_fastram)); + m_hotspot_select = 0; + memset(m_hotspot, 0, sizeof(m_hotspot)); + + m_debugger_temp = 0; + + m_cache_line_size = 32; + m_cpu_clock = clock(); + m_program = &space(AS_PROGRAM); + m_direct = &m_program->direct(); + m_system_clock = c_bus_frequency != 0 ? c_bus_frequency : clock(); + m_dcr_read_func = read32_delegate(); + m_dcr_write_func = write32_delegate(); + + m_tb_divisor = (m_tb_divisor * clock() + m_system_clock / 2 - 1) / m_system_clock; + m_codexor = 0; + if (!(m_cap & PPCCAP_4XX) && space_config()->m_endianness != ENDIANNESS_NATIVE) + m_codexor = 4; + + /* allocate the virtual TLB */ + m_vtlb = vtlb_alloc(this, AS_PROGRAM, (m_cap & PPCCAP_603_MMU) ? PPC603_FIXED_TLB_ENTRIES : 0, POWERPC_TLB_ENTRIES); + + /* allocate a timer for the compare interrupt */ + if ((m_cap & PPCCAP_OEA) && (m_tb_divisor)) + m_decrementer_int_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(ppc_device::decrementer_int_callback), this)); + + /* and for the 4XX interrupts if needed */ + if (m_cap & PPCCAP_4XX) + { + m_fit_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(ppc_device::ppc4xx_fit_callback), this)); + m_pit_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(ppc_device::ppc4xx_pit_callback), this)); + m_spu.timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(ppc_device::ppc4xx_spu_callback), this)); + } + + if (m_cap & PPCCAP_4XX) + { + m_buffered_dma_timer[0] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(ppc_device::ppc4xx_buffered_dma_callback), this)); + m_buffered_dma_timer[1] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(ppc_device::ppc4xx_buffered_dma_callback), this)); + m_buffered_dma_timer[2] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(ppc_device::ppc4xx_buffered_dma_callback), this)); + m_buffered_dma_timer[3] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(ppc_device::ppc4xx_buffered_dma_callback), this)); + + m_buffered_dma_rate[0] = 10000; + m_buffered_dma_rate[1] = 10000; + m_buffered_dma_rate[2] = 10000; + m_buffered_dma_rate[3] = 10000; + } + + /* register for save states */ + save_item(NAME(m_core->pc)); + save_item(NAME(m_core->r)); + save_item(NAME(m_core->f)); + save_item(NAME(m_core->cr)); + save_item(NAME(m_core->xerso)); + save_item(NAME(m_core->fpscr)); + save_item(NAME(m_core->msr)); + save_item(NAME(m_core->sr)); + save_item(NAME(m_core->spr)); + save_item(NAME(m_dcr)); + if (m_cap & PPCCAP_4XX) + { + save_item(NAME(m_spu.regs)); + save_item(NAME(m_spu.txbuf)); + save_item(NAME(m_spu.rxbuf)); + save_item(NAME(m_spu.rxbuffer)); + save_item(NAME(m_spu.rxin)); + save_item(NAME(m_spu.rxout)); + save_item(NAME(m_pit_reload)); + save_item(NAME(m_irqstate)); + } + if (m_cap & PPCCAP_603_MMU) + { + save_item(NAME(m_core->mmu603_cmp)); + save_item(NAME(m_core->mmu603_hash)); + save_item(NAME(m_core->mmu603_r)); + } + save_item(NAME(m_core->irq_pending)); + save_item(NAME(m_tb_zero_cycles)); + save_item(NAME(m_dec_zero_cycles)); + + // Register debugger state + state_add(PPC_PC, "PC", m_core->pc).formatstr("%08X"); + state_add(PPC_MSR, "MSR", m_core->msr).formatstr("%08X"); + state_add(PPC_CR, "CR", m_debugger_temp).callimport().callexport().formatstr("%08X"); + state_add(PPC_LR, "LR", m_core->spr[SPR_LR]).formatstr("%08X"); + state_add(PPC_CTR, "CTR", m_core->spr[SPR_CTR]).formatstr("%08X"); + state_add(PPC_XER, "XER", m_debugger_temp).callimport().callexport().formatstr("%08X"); + state_add(PPC_SRR0, "SRR0", m_core->spr[SPROEA_SRR0]).formatstr("%08X"); + state_add(PPC_SRR1, "SRR1", m_core->spr[SPROEA_SRR1]).formatstr("%08X"); + state_add(PPC_SPRG0, "SPRG0", m_core->spr[SPROEA_SPRG0]).formatstr("%08X"); + state_add(PPC_SPRG1, "SPRG1", m_core->spr[SPROEA_SPRG1]).formatstr("%08X"); + state_add(PPC_SPRG2, "SPRG2", m_core->spr[SPROEA_SPRG2]).formatstr("%08X"); + state_add(PPC_SPRG3, "SPRG3", m_core->spr[SPROEA_SPRG3]).formatstr("%08X"); + state_add(PPC_SDR1, "SDR1", m_core->spr[SPROEA_SDR1]).formatstr("%08X"); + state_add(PPC_EXIER, "EXIER", m_dcr[DCR4XX_EXIER]).formatstr("%08X"); + state_add(PPC_EXISR, "EXISR", m_dcr[DCR4XX_EXISR]).formatstr("%08X"); + state_add(PPC_EVPR, "EVPR", m_core->spr[SPR4XX_EVPR]).formatstr("%08X"); + state_add(PPC_IOCR, "IOCR", m_dcr[DCR4XX_EXISR]).formatstr("%08X"); + state_add(PPC_TBH, "TBH", m_debugger_temp).callimport().callexport().formatstr("%08X"); + state_add(PPC_TBL, "TBL", m_debugger_temp).callimport().callexport().formatstr("%08X"); + state_add(PPC_DEC, "DEC", m_debugger_temp).callimport().callexport().formatstr("%08X"); + + state_add(PPC_SR0, "SR0", m_core->sr[0]).formatstr("%08X"); + state_add(PPC_SR1, "SR1", m_core->sr[1]).formatstr("%08X"); + state_add(PPC_SR2, "SR2", m_core->sr[2]).formatstr("%08X"); + state_add(PPC_SR3, "SR3", m_core->sr[3]).formatstr("%08X"); + state_add(PPC_SR4, "SR4", m_core->sr[4]).formatstr("%08X"); + state_add(PPC_SR5, "SR5", m_core->sr[5]).formatstr("%08X"); + state_add(PPC_SR6, "SR6", m_core->sr[6]).formatstr("%08X"); + state_add(PPC_SR7, "SR7", m_core->sr[7]).formatstr("%08X"); + state_add(PPC_SR8, "SR8", m_core->sr[8]).formatstr("%08X"); + state_add(PPC_SR9, "SR9", m_core->sr[9]).formatstr("%08X"); + state_add(PPC_SR10, "SR10", m_core->sr[10]).formatstr("%08X"); + state_add(PPC_SR11, "SR11", m_core->sr[11]).formatstr("%08X"); + state_add(PPC_SR12, "SR12", m_core->sr[12]).formatstr("%08X"); + state_add(PPC_SR13, "SR13", m_core->sr[13]).formatstr("%08X"); + state_add(PPC_SR14, "SR14", m_core->sr[14]).formatstr("%08X"); + state_add(PPC_SR15, "SR15", m_core->sr[15]).formatstr("%08X"); + + state_add(PPC_R0, "R0", m_core->r[0]).formatstr("%08X"); + state_add(PPC_R1, "R1", m_core->r[1]).formatstr("%08X"); + state_add(PPC_R2, "R2", m_core->r[2]).formatstr("%08X"); + state_add(PPC_R3, "R3", m_core->r[3]).formatstr("%08X"); + state_add(PPC_R4, "R4", m_core->r[4]).formatstr("%08X"); + state_add(PPC_R5, "R5", m_core->r[5]).formatstr("%08X"); + state_add(PPC_R6, "R6", m_core->r[6]).formatstr("%08X"); + state_add(PPC_R7, "R7", m_core->r[7]).formatstr("%08X"); + state_add(PPC_R8, "R8", m_core->r[8]).formatstr("%08X"); + state_add(PPC_R9, "R9", m_core->r[9]).formatstr("%08X"); + state_add(PPC_R10, "R10", m_core->r[10]).formatstr("%08X"); + state_add(PPC_R11, "R11", m_core->r[11]).formatstr("%08X"); + state_add(PPC_R12, "R12", m_core->r[12]).formatstr("%08X"); + state_add(PPC_R13, "R13", m_core->r[13]).formatstr("%08X"); + state_add(PPC_R14, "R14", m_core->r[14]).formatstr("%08X"); + state_add(PPC_R15, "R15", m_core->r[15]).formatstr("%08X"); + state_add(PPC_R16, "R16", m_core->r[16]).formatstr("%08X"); + state_add(PPC_R17, "R17", m_core->r[17]).formatstr("%08X"); + state_add(PPC_R18, "R18", m_core->r[18]).formatstr("%08X"); + state_add(PPC_R19, "R19", m_core->r[19]).formatstr("%08X"); + state_add(PPC_R20, "R20", m_core->r[20]).formatstr("%08X"); + state_add(PPC_R21, "R21", m_core->r[21]).formatstr("%08X"); + state_add(PPC_R22, "R22", m_core->r[22]).formatstr("%08X"); + state_add(PPC_R23, "R23", m_core->r[23]).formatstr("%08X"); + state_add(PPC_R24, "R24", m_core->r[24]).formatstr("%08X"); + state_add(PPC_R25, "R25", m_core->r[25]).formatstr("%08X"); + state_add(PPC_R26, "R26", m_core->r[26]).formatstr("%08X"); + state_add(PPC_R27, "R27", m_core->r[27]).formatstr("%08X"); + state_add(PPC_R28, "R28", m_core->r[28]).formatstr("%08X"); + state_add(PPC_R29, "R29", m_core->r[29]).formatstr("%08X"); + state_add(PPC_R30, "R30", m_core->r[30]).formatstr("%08X"); + state_add(PPC_R31, "R31", m_core->r[31]).formatstr("%08X"); + + state_add(PPC_F0, "F0", m_core->f[0]).formatstr("%12s"); + state_add(PPC_F1, "F1", m_core->f[1]).formatstr("%12s"); + state_add(PPC_F2, "F2", m_core->f[2]).formatstr("%12s"); + state_add(PPC_F3, "F3", m_core->f[3]).formatstr("%12s"); + state_add(PPC_F4, "F4", m_core->f[4]).formatstr("%12s"); + state_add(PPC_F5, "F5", m_core->f[5]).formatstr("%12s"); + state_add(PPC_F6, "F6", m_core->f[6]).formatstr("%12s"); + state_add(PPC_F7, "F7", m_core->f[7]).formatstr("%12s"); + state_add(PPC_F8, "F8", m_core->f[8]).formatstr("%12s"); + state_add(PPC_F9, "F9", m_core->f[9]).formatstr("%12s"); + state_add(PPC_F10, "F10", m_core->f[10]).formatstr("%12s"); + state_add(PPC_F11, "F11", m_core->f[11]).formatstr("%12s"); + state_add(PPC_F12, "F12", m_core->f[12]).formatstr("%12s"); + state_add(PPC_F13, "F13", m_core->f[13]).formatstr("%12s"); + state_add(PPC_F14, "F14", m_core->f[14]).formatstr("%12s"); + state_add(PPC_F15, "F15", m_core->f[15]).formatstr("%12s"); + state_add(PPC_F16, "F16", m_core->f[16]).formatstr("%12s"); + state_add(PPC_F17, "F17", m_core->f[17]).formatstr("%12s"); + state_add(PPC_F18, "F18", m_core->f[18]).formatstr("%12s"); + state_add(PPC_F19, "F19", m_core->f[19]).formatstr("%12s"); + state_add(PPC_F20, "F20", m_core->f[20]).formatstr("%12s"); + state_add(PPC_F21, "F21", m_core->f[21]).formatstr("%12s"); + state_add(PPC_F22, "F22", m_core->f[22]).formatstr("%12s"); + state_add(PPC_F23, "F23", m_core->f[23]).formatstr("%12s"); + state_add(PPC_F24, "F24", m_core->f[24]).formatstr("%12s"); + state_add(PPC_F25, "F25", m_core->f[25]).formatstr("%12s"); + state_add(PPC_F26, "F26", m_core->f[26]).formatstr("%12s"); + state_add(PPC_F27, "F27", m_core->f[27]).formatstr("%12s"); + state_add(PPC_F28, "F28", m_core->f[28]).formatstr("%12s"); + state_add(PPC_F29, "F29", m_core->f[29]).formatstr("%12s"); + state_add(PPC_F30, "F30", m_core->f[30]).formatstr("%12s"); + state_add(PPC_F31, "F31", m_core->f[31]).formatstr("%12s"); + state_add(PPC_FPSCR, "FPSCR", m_core->fpscr).formatstr("%08X"); + + state_add(STATE_GENPC, "GENPC", m_core->pc).noshow(); + state_add(STATE_GENSP, "GENSP", m_core->r[31]).noshow(); + state_add(STATE_GENFLAGS, "GENFLAGS", m_debugger_temp).noshow().formatstr("%1s"); + + m_icountptr = &m_core->icount; + + UINT32 flags = 0; + /* initialize the UML generator */ + m_drcuml = auto_alloc(machine(), drcuml_state(*this, m_cache, flags, 8, 32, 2)); + + /* add symbols for our stuff */ + m_drcuml->symbol_add(&m_core->pc, sizeof(m_core->pc), "pc"); + m_drcuml->symbol_add(&m_core->icount, sizeof(m_core->icount), "icount"); + for (int regnum = 0; regnum < 32; regnum++) + { + char buf[10]; + sprintf(buf, "r%d", regnum); + m_drcuml->symbol_add(&m_core->r[regnum], sizeof(m_core->r[regnum]), buf); + sprintf(buf, "fpr%d", regnum); + m_drcuml->symbol_add(&m_core->f[regnum], sizeof(m_core->f[regnum]), buf); + } + for (int regnum = 0; regnum < 8; regnum++) + { + char buf[10]; + sprintf(buf, "cr%d", regnum); + m_drcuml->symbol_add(&m_core->cr[regnum], sizeof(m_core->cr[regnum]), buf); + } + m_drcuml->symbol_add(&m_core->xerso, sizeof(m_core->xerso), "xerso"); + m_drcuml->symbol_add(&m_core->fpscr, sizeof(m_core->fpscr), "fpscr"); + m_drcuml->symbol_add(&m_core->msr, sizeof(m_core->msr), "msr"); + m_drcuml->symbol_add(&m_core->sr, sizeof(m_core->sr), "sr"); + m_drcuml->symbol_add(&m_core->spr[SPR_XER], sizeof(m_core->spr[SPR_XER]), "xer"); + m_drcuml->symbol_add(&m_core->spr[SPR_LR], sizeof(m_core->spr[SPR_LR]), "lr"); + m_drcuml->symbol_add(&m_core->spr[SPR_CTR], sizeof(m_core->spr[SPR_CTR]), "ctr"); + m_drcuml->symbol_add(&m_core->spr, sizeof(m_core->spr), "spr"); + m_drcuml->symbol_add(&m_dcr, sizeof(m_dcr), "dcr"); + m_drcuml->symbol_add(&m_core->param0, sizeof(m_core->param0), "param0"); + m_drcuml->symbol_add(&m_core->param1, sizeof(m_core->param1), "param1"); + m_drcuml->symbol_add(&m_core->irq_pending, sizeof(m_core->irq_pending), "irq_pending"); + m_drcuml->symbol_add(&m_core->mode, sizeof(m_core->mode), "mode"); + m_drcuml->symbol_add(&m_core->arg0, sizeof(m_core->arg0), "arg0"); + m_drcuml->symbol_add(&m_arg1, sizeof(m_arg1), "arg1"); + m_drcuml->symbol_add(&m_core->updateaddr, sizeof(m_core->updateaddr), "updateaddr"); + m_drcuml->symbol_add(&m_core->swcount, sizeof(m_core->swcount), "swcount"); + m_drcuml->symbol_add(&m_core->tempaddr, sizeof(m_core->tempaddr), "tempaddr"); + m_drcuml->symbol_add(&m_core->tempdata, sizeof(m_core->tempdata), "tempdata"); + m_drcuml->symbol_add(&m_core->fp0, sizeof(m_core->fp0), "fp0"); + m_drcuml->symbol_add(&m_fpmode, sizeof(m_fpmode), "fpmode"); + m_drcuml->symbol_add(&m_sz_cr_table, sizeof(m_sz_cr_table), "sz_cr_table"); + m_drcuml->symbol_add(&m_cmp_cr_table, sizeof(m_cmp_cr_table), "cmp_cr_table"); + m_drcuml->symbol_add(&m_cmpl_cr_table, sizeof(m_cmpl_cr_table), "cmpl_cr_table"); + m_drcuml->symbol_add(&m_fcmp_cr_table, sizeof(m_fcmp_cr_table), "fcmp_cr_table"); + + /* initialize the front-end helper */ + m_drcfe = auto_alloc(machine(), ppc_frontend(this, COMPILE_BACKWARDS_BYTES, COMPILE_FORWARDS_BYTES, SINGLE_INSTRUCTION_MODE ? 1 : COMPILE_MAX_SEQUENCE)); + + /* compute the register parameters */ + for (int regnum = 0; regnum < 32; regnum++) + { + m_regmap[regnum] = uml::mem(&m_core->r[regnum]); + m_fdregmap[regnum] = uml::mem(&m_core->f[regnum]); + } + + /* if we have registers to spare, assign r0, r1, r2 to leftovers */ + if (!DISABLE_FAST_REGISTERS) + { + drcbe_info beinfo; + m_drcuml->get_backend_info(beinfo); + if (beinfo.direct_iregs > 5) + m_regmap[0] = uml::I5; + if (beinfo.direct_iregs > 6) + m_regmap[1] = uml::I6; + if (beinfo.direct_iregs > 7) + m_regmap[2] = uml::I7; + } + + /* mark the cache dirty so it is updated on next execute */ + m_cache_dirty = TRUE; +} + +void ppc_device::state_export(const device_state_entry &entry) +{ + switch (entry.index()) + { + case PPC_CR: + m_debugger_temp = get_cr(); + break; + + case PPC_XER: + m_debugger_temp = get_xer(); + break; + + case PPC_TBH: + m_debugger_temp = get_timebase() >> 32; + break; + + case PPC_TBL: + m_debugger_temp = (UINT32)get_timebase(); + break; + + case PPC_DEC: + m_debugger_temp = get_decrementer(); + break; + } +} + +void ppc_device::state_import(const device_state_entry &entry) +{ + switch (entry.index()) + { + case PPC_CR: + set_cr(m_debugger_temp); + break; + + case PPC_XER: + set_xer(m_debugger_temp); + break; + + case PPC_TBL: + set_timebase((get_timebase() & ~U64(0x00ffffff00000000)) | m_debugger_temp); + break; + + case PPC_TBH: + set_timebase((get_timebase() & ~U64(0x00000000ffffffff)) | ((UINT64)(m_debugger_temp & 0x00ffffff) << 32)); + break; + + case PPC_DEC: + set_decrementer(m_debugger_temp); + break; + } +} + + +void ppc_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + switch (entry.index()) + { + case PPC_F0: + strprintf(str, "%12f", m_core->f[0]); + break; + + case PPC_F1: + strprintf(str, "%12f", m_core->f[1]); + break; + + case PPC_F2: + strprintf(str, "%12f", m_core->f[2]); + break; + + case PPC_F3: + strprintf(str, "%12f", m_core->f[3]); + break; + + case PPC_F4: + strprintf(str, "%12f", m_core->f[4]); + break; + + case PPC_F5: + strprintf(str, "%12f", m_core->f[5]); + break; + + case PPC_F6: + strprintf(str, "%12f", m_core->f[6]); + break; + + case PPC_F7: + strprintf(str, "%12f", m_core->f[7]); + break; + + case PPC_F8: + strprintf(str, "%12f", m_core->f[8]); + break; + + case PPC_F9: + strprintf(str, "%12f", m_core->f[9]); + break; + + case PPC_F10: + strprintf(str, "%12f", m_core->f[10]); + break; + + case PPC_F11: + strprintf(str, "%12f", m_core->f[11]); + break; + + case PPC_F12: + strprintf(str, "%12f", m_core->f[12]); + break; + + case PPC_F13: + strprintf(str, "%12f", m_core->f[13]); + break; + + case PPC_F14: + strprintf(str, "%12f", m_core->f[14]); + break; + + case PPC_F15: + strprintf(str, "%12f", m_core->f[15]); + break; + + case PPC_F16: + strprintf(str, "%12f", m_core->f[16]); + break; + + case PPC_F17: + strprintf(str, "%12f", m_core->f[17]); + break; + + case PPC_F18: + strprintf(str, "%12f", m_core->f[18]); + break; + + case PPC_F19: + strprintf(str, "%12f", m_core->f[19]); + break; + + case PPC_F20: + strprintf(str, "%12f", m_core->f[20]); + break; + + case PPC_F21: + strprintf(str, "%12f", m_core->f[21]); + break; + + case PPC_F22: + strprintf(str, "%12f", m_core->f[22]); + break; + + case PPC_F23: + strprintf(str, "%12f", m_core->f[23]); + break; + + case PPC_F24: + strprintf(str, "%12f", m_core->f[24]); + break; + + case PPC_F25: + strprintf(str, "%12f", m_core->f[25]); + break; + + case PPC_F26: + strprintf(str, "%12f", m_core->f[26]); + break; + + case PPC_F27: + strprintf(str, "%12f", m_core->f[27]); + break; + + case PPC_F28: + strprintf(str, "%12f", m_core->f[28]); + break; + + case PPC_F29: + strprintf(str, "%12f", m_core->f[29]); + break; + + case PPC_F30: + strprintf(str, "%12f", m_core->f[30]); + break; + + case PPC_F31: + strprintf(str, "%12f", m_core->f[31]); + break; + } +} + + +/*------------------------------------------------- + ppccom_exit - common cleanup/exit +-------------------------------------------------*/ + +void ppc_device::device_stop() +{ + if (m_vtlb != NULL) + vtlb_free(m_vtlb); + m_vtlb = NULL; + + /* clean up the DRC */ + auto_free(machine(), m_drcfe); + auto_free(machine(), m_drcuml); +} + + +/*------------------------------------------------- + ppccom_reset - reset the state of all the + registers +-------------------------------------------------*/ + +void ppc_device::device_reset() +{ + /* initialize the OEA state */ + if (m_cap & PPCCAP_OEA) + { + /* PC to the reset vector; MSR has IP set to start */ + m_core->pc = 0xfff00100; + m_core->msr = MSROEA_IP; + + /* reset the decrementer */ + m_dec_zero_cycles = total_cycles(); + if (m_tb_divisor) + { + decrementer_int_callback(NULL, 0); + } + } + + /* initialize the 4XX state */ + if (m_cap & PPCCAP_4XX) + { + /* PC to the last word; MSR to 0 */ + m_core->pc = 0xfffffffc; + m_core->msr = 0; + + /* reset the SPU status */ + m_core->spr[SPR4XX_TCR] &= ~PPC4XX_TCR_WRC_MASK; + m_spu.regs[SPU4XX_LINE_STATUS] = 0x06; + } + + /* initialize the 602 HID0 register */ + if (m_flavor == PPC_MODEL_602) + m_core->spr[SPR603_HID0] = 1; + + /* time base starts here */ + m_tb_zero_cycles = total_cycles(); + + /* clear interrupts */ + m_core->irq_pending = 0; + + /* flush the TLB */ + vtlb_flush_dynamic(m_vtlb); + if (m_cap & PPCCAP_603_MMU) + { + for (int tlbindex = 0; tlbindex < PPC603_FIXED_TLB_ENTRIES; tlbindex++) + { + vtlb_load(m_vtlb, tlbindex, 0, 0, 0); + } + } + + /* Mark the cache dirty */ + m_core->mode = 0; + m_cache_dirty = TRUE; +} + + +/*------------------------------------------------- + ppccom_dasm - handle disassembly for a + CPU +-------------------------------------------------*/ + +offs_t ppc_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern offs_t ppc_dasm_one(char *buffer, UINT32 pc, UINT32 op); + UINT32 op = *(UINT32 *)oprom; + op = BIG_ENDIANIZE_INT32(op); + return ppc_dasm_one(buffer, pc, op); +} + + +/*------------------------------------------------- + ppccom_dcstore_callback - call the dcstore + callback if installed +-------------------------------------------------*/ + +void ppc_device::ppccom_dcstore_callback() +{ + if (!m_dcstore_cb.isnull()) + { + m_dcstore_cb(*m_program, m_core->param0, 0, 0xffffffff); + } +} + + +/*************************************************************************** + TLB HANDLING +***************************************************************************/ + +/*------------------------------------------------- + ppccom_translate_address_internal - translate + an address from logical to physical; shared + between external requests and internal TLB + filling +-------------------------------------------------*/ + +UINT32 ppc_device::ppccom_translate_address_internal(int intention, offs_t &address) +{ + int transpriv = ((intention & TRANSLATE_USER_MASK) == 0); // 1 for supervisor, 0 for user + int transtype = intention & TRANSLATE_TYPE_MASK; + offs_t hash, hashbase, hashmask; + int batbase, batnum, hashnum; + UINT32 segreg; + + /* 4xx case: "TLB" really just caches writes and checks compare registers */ + if (m_cap & PPCCAP_4XX) + { + /* we don't support the MMU of the 403GCX */ + if (m_flavor == PPC_MODEL_403GCX && (m_core->msr & MSROEA_DR)) + fatalerror("MMU enabled but not supported!\n"); + + /* only check if PE is enabled */ + if (transtype == TRANSLATE_WRITE && (m_core->msr & MSR4XX_PE)) + { + /* are we within one of the protection ranges? */ + int inrange1 = ((address >> 12) >= (m_core->spr[SPR4XX_PBL1] >> 12) && (address >> 12) < (m_core->spr[SPR4XX_PBU1] >> 12)); + int inrange2 = ((address >> 12) >= (m_core->spr[SPR4XX_PBL2] >> 12) && (address >> 12) < (m_core->spr[SPR4XX_PBU2] >> 12)); + + /* if PX == 1, writes are only allowed OUTSIDE of the bounds */ + if (((m_core->msr & MSR4XX_PX) && (inrange1 || inrange2)) || (!(m_core->msr & MSR4XX_PX) && (!inrange1 && !inrange2))) + return 0x002; + } + address &= 0x7fffffff; + return 0x001; + } + + /* only applies if we support the OEA */ + if (!(m_cap & PPCCAP_OEA)) + return 0x001; + + /* also no translation necessary if translation is disabled */ + if ((transtype == TRANSLATE_FETCH && (m_core->msr & MSROEA_IR) == 0) || (transtype != TRANSLATE_FETCH && (m_core->msr & MSROEA_DR) == 0)) + return 0x001; + + /* first scan the appropriate BAT */ + if (m_cap & PPCCAP_601BAT) + { + for (batnum = 0; batnum < 4; batnum++) + { + UINT32 upper = m_core->spr[SPROEA_IBAT0U + 2*batnum + 0]; + UINT32 lower = m_core->spr[SPROEA_IBAT0U + 2*batnum + 1]; + int privbit = ((intention & TRANSLATE_USER_MASK) == 0) ? 3 : 2; + +// printf("bat %d upper = %08x privbit %d\n", batnum, upper, privbit); + + // is this pair valid? + if (lower & 0x40) + { + UINT32 mask = ((lower & 0x3f) << 17) ^ 0xfffe0000; + UINT32 addrout; + UINT32 key = (upper >> privbit) & 1; + + /* check for a hit against this bucket */ + if ((address & mask) == (upper & mask)) + { + /* verify protection; if we fail, return false and indicate a protection violation */ + if (!page_access_allowed(transtype, key, upper & 3)) + { + return DSISR_PROTECTED | ((transtype == TRANSLATE_WRITE) ? DSISR_STORE : 0); + } + + /* otherwise we're good */ + addrout = (lower & mask) | (address & ~mask); + address = addrout; // top 9 bits from top 9 of PBN + return 0x001; + } + } + } + } + else + { + batbase = (transtype == TRANSLATE_FETCH) ? SPROEA_IBAT0U : SPROEA_DBAT0U; + + for (batnum = 0; batnum < 4; batnum++) + { + UINT32 upper = m_core->spr[batbase + 2*batnum + 0]; + + /* check user/supervisor valid bit */ + if ((upper >> transpriv) & 0x01) + { + UINT32 mask = (~upper << 15) & 0xfffe0000; + + /* check for a hit against this bucket */ + if ((address & mask) == (upper & mask)) + { + UINT32 lower = m_core->spr[batbase + 2*batnum + 1]; + + /* verify protection; if we fail, return false and indicate a protection violation */ + if (!page_access_allowed(transtype, 1, lower & 3)) + { + return DSISR_PROTECTED | ((transtype == TRANSLATE_WRITE) ? DSISR_STORE : 0); + } + + /* otherwise we're good */ + address = (lower & mask) | (address & ~mask); + return 0x001; + } + } + } + } + + /* look up the segment register */ + segreg = m_core->sr[address >> 28]; + if (transtype == TRANSLATE_FETCH && (segreg & 0x10000000)) + return DSISR_PROTECTED | ((transtype == TRANSLATE_WRITE) ? DSISR_STORE : 0); + + /* check for memory-forced I/O */ + if (m_cap & PPCCAP_MFIOC) + { + if ((transtype != TRANSLATE_FETCH) && ((segreg & 0x87f00000) == 0x87f00000)) + { + address = ((segreg & 0xf)<<28) | (address & 0x0fffffff); + return 1; + } + else if (segreg & 0x80000000) + { + fatalerror("PPC: Unhandled segment register %08x with T=1\n", segreg); + } + } + + /* get hash table information from SD1 */ + hashbase = m_core->spr[SPROEA_SDR1] & 0xffff0000; + hashmask = ((m_core->spr[SPROEA_SDR1] & 0x1ff) << 16) | 0xffff; + hash = (segreg & 0x7ffff) ^ ((address >> 12) & 0xffff); + + /* if we're simulating the 603 MMU, fill in the data and stop here */ + if (m_cap & PPCCAP_603_MMU) + { + UINT32 entry = vtlb_table(m_vtlb)[address >> 12]; + m_core->mmu603_cmp = 0x80000000 | ((segreg & 0xffffff) << 7) | (0 << 6) | ((address >> 22) & 0x3f); + m_core->mmu603_hash[0] = hashbase | ((hash << 6) & hashmask); + m_core->mmu603_hash[1] = hashbase | ((~hash << 6) & hashmask); + if ((entry & (VTLB_FLAG_FIXED | VTLB_FLAG_VALID)) == (VTLB_FLAG_FIXED | VTLB_FLAG_VALID)) + { + address = (entry & 0xfffff000) | (address & 0x00000fff); + return 0x001; + } + return DSISR_NOT_FOUND | ((transtype == TRANSLATE_WRITE) ? DSISR_STORE : 0); + } + + /* loop twice over hashes */ + for (hashnum = 0; hashnum < 2; hashnum++) + { + offs_t ptegaddr = hashbase | ((hash << 6) & hashmask); + UINT32 *ptegptr = (UINT32 *)m_program->get_read_ptr(ptegaddr); + + /* should only have valid memory here, but make sure */ + if (ptegptr != NULL) + { + UINT32 targetupper = 0x80000000 | ((segreg & 0xffffff) << 7) | (hashnum << 6) | ((address >> 22) & 0x3f); + int ptenum; + + /* scan PTEs */ + for (ptenum = 0; ptenum < 8; ptenum++) + if (ptegptr[BYTE_XOR_BE(ptenum * 2)] == targetupper) + { + UINT32 pteglower = ptegptr[BYTE_XOR_BE(ptenum * 2 + 1)]; + + /* verify protection; if we fail, return false and indicate a protection violation */ + if (!page_access_allowed(transtype, (segreg >> (29 + transpriv)) & 1, pteglower & 3)) + return DSISR_PROTECTED | ((transtype == TRANSLATE_WRITE) ? DSISR_STORE : 0); + + /* update page table bits */ + if (!(intention & TRANSLATE_DEBUG_MASK)) + { + pteglower |= 0x100; + if (transtype == TRANSLATE_WRITE) + pteglower |= 0x080; + ptegptr[BYTE_XOR_BE(ptenum * 2 + 1)] = pteglower; + } + + /* otherwise we're good */ + address = (pteglower & 0xfffff000) | (address & 0x00000fff); + return (pteglower >> 7) & 1; + } + } + + /* invert the hash after the first round */ + hash = ~hash; + } + + /* we failed to find any match: not found */ + return DSISR_NOT_FOUND | ((transtype == TRANSLATE_WRITE) ? DSISR_STORE : 0); +} + + +/*------------------------------------------------- + ppccom_translate_address - translate an address + from logical to physical +-------------------------------------------------*/ + +bool ppc_device::memory_translate(address_spacenum spacenum, int intention, offs_t &address) +{ + /* only applies to the program address space */ + if (spacenum != AS_PROGRAM) + return TRUE; + + /* translation is successful if the internal routine returns 0 or 1 */ + return (ppccom_translate_address_internal(intention, address) <= 1); +} + + +/*------------------------------------------------- + ppccom_tlb_fill - handle a missing TLB entry +-------------------------------------------------*/ + +void ppc_device::ppccom_tlb_fill() +{ + vtlb_fill(m_vtlb, m_core->param0, m_core->param1); +} + + +/*------------------------------------------------- + ppccom_tlb_flush - flush the entire TLB, + including fixed entries +-------------------------------------------------*/ + +void ppc_device::ppccom_tlb_flush() +{ + vtlb_flush_dynamic(m_vtlb); +} + + + +/*************************************************************************** + OPCODE HANDLING +***************************************************************************/ + +/*------------------------------------------------- + ppccom_execute_tlbie - execute a TLBIE + instruction +-------------------------------------------------*/ + +void ppc_device::ppccom_execute_tlbie() +{ + vtlb_flush_address(m_vtlb, m_core->param0); +} + + +/*------------------------------------------------- + ppccom_execute_tlbia - execute a TLBIA + instruction +-------------------------------------------------*/ + +void ppc_device::ppccom_execute_tlbia() +{ + vtlb_flush_dynamic(m_vtlb); +} + + +/*------------------------------------------------- + ppccom_execute_tlbl - execute a TLBLD/TLBLI + instruction +-------------------------------------------------*/ + +void ppc_device::ppccom_execute_tlbl() +{ + UINT32 address = m_core->param0; + int isitlb = m_core->param1; + vtlb_entry flags = 0; + int entrynum; + + /* determine entry number; we use rand() for associativity */ + entrynum = ((address >> 12) & 0x1f) | (machine().rand() & 0x20) | (isitlb ? 0x40 : 0); + + /* determine the flags */ + flags = VTLB_FLAG_VALID | VTLB_READ_ALLOWED | VTLB_FETCH_ALLOWED; + if (m_core->spr[SPR603_RPA] & 0x80) + flags |= VTLB_WRITE_ALLOWED; + if (isitlb) + flags |= VTLB_FETCH_ALLOWED; + + /* load the entry */ + vtlb_load(m_vtlb, entrynum, 1, address, (m_core->spr[SPR603_RPA] & 0xfffff000) | flags); +} + + +/*------------------------------------------------- + ppccom_execute_mftb - execute an MFTB + instruction +-------------------------------------------------*/ + +void ppc_device::ppccom_execute_mftb() +{ + switch (m_core->param0) + { + /* user mode timebase read */ + case SPRVEA_TBL_R: + m_core->param1 = get_timebase(); + break; + case SPRVEA_TBU_R: + m_core->param1 = get_timebase() >> 32; + break; + } +} + + +/*------------------------------------------------- + ppccom_execute_mfspr - execute an MFSPR + instruction +-------------------------------------------------*/ + +void ppc_device::ppccom_execute_mfspr() +{ + /* handle OEA SPRs */ + if (m_cap & PPCCAP_OEA) + { + switch (m_core->param0) + { + /* read-through no-ops */ + case SPROEA_DSISR: + case SPROEA_DAR: + case SPROEA_SDR1: + case SPROEA_SRR0: + case SPROEA_SRR1: + case SPROEA_EAR: + case SPROEA_IBAT0L: + case SPROEA_IBAT0U: + case SPROEA_IBAT1L: + case SPROEA_IBAT1U: + case SPROEA_IBAT2L: + case SPROEA_IBAT2U: + case SPROEA_IBAT3L: + case SPROEA_IBAT3U: + case SPROEA_DBAT0L: + case SPROEA_DBAT0U: + case SPROEA_DBAT1L: + case SPROEA_DBAT1U: + case SPROEA_DBAT2L: + case SPROEA_DBAT2U: + case SPROEA_DBAT3L: + case SPROEA_DBAT3U: + case SPROEA_DABR: + m_core->param1 = m_core->spr[m_core->param0]; + return; + + /* decrementer */ + case SPROEA_DEC: + m_core->param1 = get_decrementer(); + return; + } + } + + /* handle 603 SPRs */ + if (m_cap & PPCCAP_603_MMU) + { + switch (m_core->param0) + { + /* read-through no-ops */ + case SPR603_DMISS: + case SPR603_DCMP: + case SPR603_HASH1: + case SPR603_HASH2: + case SPR603_IMISS: + case SPR603_ICMP: + case SPR603_RPA: + case SPR603_HID0: + case SPR603_HID1: + case SPR603_IABR: + case SPR603_HID2: + m_core->param1 = m_core->spr[m_core->param0]; + return; + + /* timebase */ + case SPR603_TBL_R: + m_core->param1 = get_timebase(); + return; + case SPR603_TBU_R: + m_core->param1 = (get_timebase() >> 32) & 0xffffff; + return; + } + } + + /* handle 4XX SPRs */ + if (m_cap & PPCCAP_4XX) + { + switch (m_core->param0) + { + /* read-through no-ops */ + case SPR4XX_EVPR: + case SPR4XX_ESR: + case SPR4XX_SRR0: + case SPR4XX_SRR1: + case SPR4XX_SRR2: + case SPR4XX_SRR3: + case SPR4XX_TCR: + case SPR4XX_TSR: + case SPR4XX_IAC1: + case SPR4XX_IAC2: + case SPR4XX_DAC1: + case SPR4XX_DAC2: + case SPR4XX_DCCR: + case SPR4XX_ICCR: + case SPR4XX_PBL1: + case SPR4XX_PBU1: + case SPR4XX_PBL2: + case SPR4XX_PBU2: + m_core->param1 = m_core->spr[m_core->param0]; + return; + + /* timebase */ + case SPR4XX_TBLO: + case SPR4XX_TBLU: + m_core->param1 = get_timebase(); + return; + case SPR4XX_TBHI: + case SPR4XX_TBHU: + m_core->param1 = (get_timebase() >> 32) & 0xffffff; + return; + } + } + + /* default handling */ + osd_printf_debug("SPR %03X read\n", m_core->param0); + m_core->param1 = m_core->spr[m_core->param0]; +} + + +/*------------------------------------------------- + ppccom_execute_mtspr - execute an MTSPR + instruction +-------------------------------------------------*/ + +void ppc_device::ppccom_execute_mtspr() +{ + /* handle OEA SPRs */ + if (m_cap & PPCCAP_OEA) + { + switch (m_core->param0) + { + /* write-through no-ops */ + case SPROEA_DSISR: + case SPROEA_DAR: + case SPROEA_SRR0: + case SPROEA_SRR1: + case SPROEA_EAR: + case SPROEA_DABR: + m_core->spr[m_core->param0] = m_core->param1; + return; + + /* registers that affect the memory map */ + case SPROEA_SDR1: + case SPROEA_IBAT0L: + case SPROEA_IBAT0U: + case SPROEA_IBAT1L: + case SPROEA_IBAT1U: + case SPROEA_IBAT2L: + case SPROEA_IBAT2U: + case SPROEA_IBAT3L: + case SPROEA_IBAT3U: + case SPROEA_DBAT0L: + case SPROEA_DBAT0U: + case SPROEA_DBAT1L: + case SPROEA_DBAT1U: + case SPROEA_DBAT2L: + case SPROEA_DBAT2U: + case SPROEA_DBAT3L: + case SPROEA_DBAT3U: + m_core->spr[m_core->param0] = m_core->param1; + ppccom_tlb_flush(); + return; + + /* decrementer */ + case SPROEA_DEC: + set_decrementer(m_core->param1); + return; + } + } + + /* handle 603 SPRs */ + if (m_cap & PPCCAP_603_MMU) + { + switch (m_core->param0) + { + /* read-only */ + case SPR603_DMISS: + case SPR603_DCMP: + case SPR603_HASH1: + case SPR603_HASH2: + case SPR603_IMISS: + case SPR603_ICMP: + return; + + /* write-through no-ops */ + case SPR603_RPA: + case SPR603_HID0: + case SPR603_HID1: + case SPR603_IABR: + case SPR603_HID2: + m_core->spr[m_core->param0] = m_core->param1; + return; + + /* timebase */ + case SPR603_TBL_W: + set_timebase((get_timebase() & ~U64(0xffffffff00000000)) | m_core->param1); + return; + case SPR603_TBU_W: + set_timebase((get_timebase() & ~U64(0x00000000ffffffff)) | ((UINT64)m_core->param1 << 32)); + return; + } + } + + /* handle 4XX SPRs */ + if (m_cap & PPCCAP_4XX) + { + UINT32 oldval = m_core->spr[m_core->param0]; + switch (m_core->param0) + { + /* write-through no-ops */ + case SPR4XX_EVPR: + case SPR4XX_ESR: + case SPR4XX_DCCR: + case SPR4XX_ICCR: + case SPR4XX_SRR0: + case SPR4XX_SRR1: + case SPR4XX_SRR2: + case SPR4XX_SRR3: + m_core->spr[m_core->param0] = m_core->param1; + return; + + /* registers that affect the memory map */ + case SPR4XX_PBL1: + case SPR4XX_PBU1: + case SPR4XX_PBL2: + case SPR4XX_PBU2: + m_core->spr[m_core->param0] = m_core->param1; + ppccom_tlb_flush(); + return; + + /* timer control register */ + case SPR4XX_TCR: + m_core->spr[SPR4XX_TCR] = m_core->param1 | (oldval & PPC4XX_TCR_WRC_MASK); + if ((oldval ^ m_core->spr[SPR4XX_TCR]) & PPC4XX_TCR_FIE) + ppc4xx_fit_callback(NULL, FALSE); + if ((oldval ^ m_core->spr[SPR4XX_TCR]) & PPC4XX_TCR_PIE) + ppc4xx_pit_callback(NULL, FALSE); + return; + + /* timer status register */ + case SPR4XX_TSR: + m_core->spr[SPR4XX_TSR] &= ~m_core->param1; + ppc4xx_set_irq_line(0, 0); + return; + + /* PIT */ + case SPR4XX_PIT: + m_core->spr[SPR4XX_PIT] = m_core->param1; + m_pit_reload = m_core->param1; + ppc4xx_pit_callback(NULL, FALSE); + return; + + /* timebase */ + case SPR4XX_TBLO: + set_timebase((get_timebase() & ~U64(0x00ffffff00000000)) | m_core->param1); + return; + case SPR4XX_TBHI: + set_timebase((get_timebase() & ~U64(0x00000000ffffffff)) | ((UINT64)(m_core->param1 & 0x00ffffff) << 32)); + return; + } + } + + /* default handling */ + osd_printf_debug("SPR %03X write = %08X\n", m_core->param0, m_core->param1); + m_core->spr[m_core->param0] = m_core->param1; +} + + +/*------------------------------------------------- + ppccom_execute_mfdcr - execute an MFDCR + instruction +-------------------------------------------------*/ + +void ppc_device::ppccom_execute_mfdcr() +{ + /* handle various DCRs */ + switch (m_core->param0) + { + /* read-through no-ops */ + case DCR4XX_BR0: + case DCR4XX_BR1: + case DCR4XX_BR2: + case DCR4XX_BR3: + case DCR4XX_BR4: + case DCR4XX_BR5: + case DCR4XX_BR6: + case DCR4XX_BR7: + case DCR4XX_BESR: + case DCR4XX_DMASR: + case DCR4XX_DMACT0: + case DCR4XX_DMADA0: + case DCR4XX_DMASA0: + case DCR4XX_DMACC0: + case DCR4XX_DMACR0: + case DCR4XX_DMACT1: + case DCR4XX_DMADA1: + case DCR4XX_DMASA1: + case DCR4XX_DMACC1: + case DCR4XX_DMACR1: + case DCR4XX_DMACT2: + case DCR4XX_DMADA2: + case DCR4XX_DMASA2: + case DCR4XX_DMACC2: + case DCR4XX_DMACR2: + case DCR4XX_DMACT3: + case DCR4XX_DMADA3: + case DCR4XX_DMASA3: + case DCR4XX_DMACC3: + case DCR4XX_DMACR3: + case DCR4XX_EXIER: + case DCR4XX_EXISR: + case DCR4XX_IOCR: + m_core->param1 = m_dcr[m_core->param0]; + return; + } + + /* default handling */ + if (m_dcr_read_func.isnull()) { + osd_printf_debug("DCR %03X read\n", m_core->param0); + if (m_core->param0 < ARRAY_LENGTH(m_dcr)) + m_core->param1 = m_dcr[m_core->param0]; + else + m_core->param1 = 0; + } else { + m_core->param1 = m_dcr_read_func(*m_program,m_core->param0,0xffffffff); + } +} + + +/*------------------------------------------------- + ppccom_execute_mtdcr - execute an MTDCR + instruction +-------------------------------------------------*/ + +void ppc_device::ppccom_execute_mtdcr() +{ + UINT8 oldval; + + /* handle various DCRs */ + switch (m_core->param0) + { + /* write-through no-ops */ + case DCR4XX_BR0: + case DCR4XX_BR1: + case DCR4XX_BR2: + case DCR4XX_BR3: + case DCR4XX_BR4: + case DCR4XX_BR5: + case DCR4XX_BR6: + case DCR4XX_BR7: + case DCR4XX_BESR: + case DCR4XX_DMACT0: + case DCR4XX_DMADA0: + case DCR4XX_DMASA0: + case DCR4XX_DMACC0: + case DCR4XX_DMACT1: + case DCR4XX_DMADA1: + case DCR4XX_DMASA1: + case DCR4XX_DMACC1: + case DCR4XX_DMACT2: + case DCR4XX_DMADA2: + case DCR4XX_DMASA2: + case DCR4XX_DMACC2: + case DCR4XX_DMACT3: + case DCR4XX_DMADA3: + case DCR4XX_DMASA3: + case DCR4XX_DMACC3: + m_dcr[m_core->param0] = m_core->param1; + return; + + /* DMA status */ + case DCR4XX_DMASR: + m_dcr[DCR4XX_DMASR] &= ~(m_core->param1 & 0xfff80070); + ppc4xx_dma_update_irq_states(); + return; + + /* interrupt enables */ + case DCR4XX_EXIER: + m_dcr[DCR4XX_EXIER] = m_core->param1; + ppc4xx_set_irq_line(0, 0); + return; + + /* interrupt clear */ + case DCR4XX_EXISR: + m_dcr[m_core->param0] &= ~m_core->param1; + ppc4xx_set_irq_line(0, 0); + return; + + /* DMA controls */ + case DCR4XX_DMACR0: + case DCR4XX_DMACR1: + case DCR4XX_DMACR2: + case DCR4XX_DMACR3: + m_dcr[m_core->param0] = m_core->param1; + if (m_core->param1 & PPC4XX_DMACR_CE) + ppc4xx_dma_exec((m_core->param0 - DCR4XX_DMACR0) / 8); + ppc4xx_dma_update_irq_states(); + return; + + /* I/O control */ + case DCR4XX_IOCR: + oldval = m_dcr[m_core->param0]; + m_dcr[m_core->param0] = m_core->param1; + if ((oldval ^ m_core->param1) & 0x02) + ppc4xx_spu_timer_reset(); + return; + } + + /* default handling */ + if (m_dcr_write_func.isnull()) { + osd_printf_debug("DCR %03X write = %08X\n", m_core->param0, m_core->param1); + if (m_core->param0 < ARRAY_LENGTH(m_dcr)) + m_dcr[m_core->param0] = m_core->param1; + } else { + m_dcr_write_func(*m_program,m_core->param0,m_core->param1,0xffffffff); + } +} + + + +/*************************************************************************** + FLOATING POINT STATUS FLAGS HANDLING +***************************************************************************/ + +/*------------------------------------------------- + ppccom_update_fprf - update the FPRF field + of the FPSCR register +-------------------------------------------------*/ + +void ppc_device::ppccom_update_fprf() +{ + UINT32 fprf; + double f = m_core->f[m_core->param0]; + + if (is_qnan_double(f)) + { + fprf = 0x11; + } + else if (is_infinity_double(f)) + { + if (sign_double(f)) /* -Infinity */ + fprf = 0x09; + else /* +Infinity */ + fprf = 0x05; + } + else if (is_normalized_double(f)) + { + if (sign_double(f)) /* -Normalized */ + fprf = 0x08; + else /* +Normalized */ + fprf = 0x04; + } + else if (is_denormalized_double(f)) + { + if (sign_double(f)) /* -Denormalized */ + fprf = 0x18; + else /* +Denormalized */ + fprf = 0x14; + } + else + { + if (sign_double(f)) /* -Zero */ + fprf = 0x12; + else /* +Zero */ + fprf = 0x02; + } + + m_core->fpscr &= ~0x0001f000; + m_core->fpscr |= fprf << 12; +} + + +/*************************************************************************** + OEA HELPERS +***************************************************************************/ + +/*------------------------------------------------- + decrementer_int_callback - callback that fires + whenever a decrementer interrupt is generated +-------------------------------------------------*/ + +TIMER_CALLBACK_MEMBER( ppc_device::decrementer_int_callback ) +{ + UINT64 cycles_until_next; + + /* set the decrementer IRQ state */ + m_core->irq_pending |= 0x02; + + /* advance by another full rev */ + m_dec_zero_cycles += (UINT64)m_tb_divisor << 32; + cycles_until_next = m_dec_zero_cycles - total_cycles(); + m_decrementer_int_timer->adjust(cycles_to_attotime(cycles_until_next)); +} + +/*------------------------------------------------- + ppc_set_dcstore_callback - installs a callback + for detecting datacache stores with dcbst +-------------------------------------------------*/ + +void ppc_device::ppc_set_dcstore_callback(write32_delegate callback) +{ + m_dcstore_cb = callback; +} + + +void ppc_device::execute_set_input(int inputnum, int state) +{ + switch (inputnum) + { + case PPC_IRQ: + m_core->irq_pending = (m_core->irq_pending & ~1) | ((state != CLEAR_LINE) ? 1 : 0); + break; + } +} + + +void ppc4xx_device::execute_set_input(int inputnum, int state) +{ + switch (inputnum) + { + case PPC_IRQ_LINE_0: + ppc4xx_set_irq_line(PPC4XX_IRQ_BIT_EXT0, state); + break; + + case PPC_IRQ_LINE_1: + ppc4xx_set_irq_line(PPC4XX_IRQ_BIT_EXT1, state); + break; + + case PPC_IRQ_LINE_2: + ppc4xx_set_irq_line(PPC4XX_IRQ_BIT_EXT2, state); + break; + + case PPC_IRQ_LINE_3: + ppc4xx_set_irq_line(PPC4XX_IRQ_BIT_EXT3, state); + break; + + case PPC_IRQ_LINE_4: + ppc4xx_set_irq_line(PPC4XX_IRQ_BIT_EXT4, state); + break; + } +} + + +/*************************************************************************** + EMBEDDED 4XX HELPERS +***************************************************************************/ + +/*------------------------------------------------- + ppc4xx_set_irq_line - PowerPC 4XX-specific + IRQ line management +-------------------------------------------------*/ + +void ppc_device::ppc4xx_set_irq_line(UINT32 bitmask, int state) +{ + UINT32 oldstate = m_irqstate; + UINT32 levelmask; + + /* set or clear the appropriate bit */ + if (state != CLEAR_LINE) + m_irqstate |= bitmask; + else + m_irqstate &= ~bitmask; + + /* if the state changed to on, edge trigger the interrupt */ + if (((m_irqstate ^ oldstate) & bitmask) && (m_irqstate & bitmask)) + m_dcr[DCR4XX_EXISR] |= bitmask; + + /* pass through all level-triggered interrupts */ + levelmask = PPC4XX_IRQ_BIT_CRITICAL | PPC4XX_IRQ_BIT_SPUR | PPC4XX_IRQ_BIT_SPUT; + levelmask |= PPC4XX_IRQ_BIT_JTAGR | PPC4XX_IRQ_BIT_JTAGT; + levelmask |= PPC4XX_IRQ_BIT_DMA0 | PPC4XX_IRQ_BIT_DMA1 | PPC4XX_IRQ_BIT_DMA2 | PPC4XX_IRQ_BIT_DMA3; + if (!(m_dcr[DCR4XX_IOCR] & 0x80000000)) levelmask |= PPC4XX_IRQ_BIT_EXT0; + if (!(m_dcr[DCR4XX_IOCR] & 0x20000000)) levelmask |= PPC4XX_IRQ_BIT_EXT1; + if (!(m_dcr[DCR4XX_IOCR] & 0x08000000)) levelmask |= PPC4XX_IRQ_BIT_EXT2; + if (!(m_dcr[DCR4XX_IOCR] & 0x02000000)) levelmask |= PPC4XX_IRQ_BIT_EXT3; + if (!(m_dcr[DCR4XX_IOCR] & 0x00800000)) levelmask |= PPC4XX_IRQ_BIT_EXT4; + m_dcr[DCR4XX_EXISR] = (m_dcr[DCR4XX_EXISR] & ~levelmask) | (m_irqstate & levelmask); + + /* update the IRQ status */ + m_core->irq_pending = ((m_dcr[DCR4XX_EXISR] & m_dcr[DCR4XX_EXIER]) != 0); + if ((m_core->spr[SPR4XX_TCR] & PPC4XX_TCR_FIE) && (m_core->spr[SPR4XX_TSR] & PPC4XX_TSR_FIS)) + m_core->irq_pending = TRUE; + if ((m_core->spr[SPR4XX_TCR] & PPC4XX_TCR_PIE) && (m_core->spr[SPR4XX_TSR] & PPC4XX_TSR_PIS)) + m_core->irq_pending = TRUE; +} + + +/*------------------------------------------------- + ppc4xx_get_irq_line - PowerPC 4XX-specific + IRQ line state getter +-------------------------------------------------*/ + +int ppc_device::ppc4xx_get_irq_line(UINT32 bitmask) +{ + return (m_irqstate & bitmask) ? ASSERT_LINE : CLEAR_LINE; +} + + +/*------------------------------------------------- + ppc4xx_dma_update_irq_states - update the IRQ + state for each DMA channel +-------------------------------------------------*/ + +void ppc_device::ppc4xx_dma_update_irq_states() +{ + /* update the IRQ state for each DMA channel */ + for (int dmachan = 0; dmachan < 4; dmachan++) + { + bool irq_pending = false; + + // Channel interrupt enabled? + if ((m_dcr[DCR4XX_DMACR0 + 8 * dmachan] & PPC4XX_DMACR_CIE)) + { + // Terminal count and end-of-transfer status bits + int bitmask = 0x11 << (27 - dmachan); + + // Chained transfer status bit + switch (dmachan) + { + case 0: + bitmask |= 0x00080000; + break; + + case 1: + case 2: + case 3: + bitmask |= 1 << (7 - dmachan); + break; + } + + irq_pending = (m_dcr[DCR4XX_DMASR] & bitmask) != 0; + } + + ppc4xx_set_irq_line(PPC4XX_IRQ_BIT_DMA(dmachan), irq_pending ? ASSERT_LINE : CLEAR_LINE); + } +} + + +/*------------------------------------------------- + ppc4xx_dma_decrement_count - decrement the + count on a channel and interrupt if configured + to do so +-------------------------------------------------*/ + +int ppc_device::ppc4xx_dma_decrement_count(int dmachan) +{ + UINT32 *dmaregs = &m_dcr[8 * dmachan]; + + /* decrement the counter */ + dmaregs[DCR4XX_DMACT0]--; + + /* if non-zero, we keep going */ + if ((dmaregs[DCR4XX_DMACT0] & 0xffff) != 0) + return FALSE; + + // if chained mode + if (dmaregs[DCR4XX_DMACR0] & PPC4XX_DMACR_CH) + { + dmaregs[DCR4XX_DMADA0] = dmaregs[DCR4XX_DMASA0]; + dmaregs[DCR4XX_DMACT0] = dmaregs[DCR4XX_DMACC0]; + dmaregs[DCR4XX_DMACR0] &= ~PPC4XX_DMACR_CH; + + switch (dmachan) + { + case 0: + m_dcr[DCR4XX_DMASR] |= 0x00080000; + break; + + case 1: + case 2: + case 3: + m_dcr[DCR4XX_DMASR] |= 1 << (7 - dmachan); + break; + } + + ppc4xx_dma_update_irq_states(); + + INT64 numdata = dmaregs[DCR4XX_DMACT0]; + if (numdata == 0) + numdata = 65536; + + INT64 time = (numdata * 1000000) / m_buffered_dma_rate[dmachan]; + + m_buffered_dma_timer[dmachan]->adjust(attotime::from_usec(time), dmachan); + } + else + { + /* set the complete bit and handle interrupts */ + m_dcr[DCR4XX_DMASR] |= 1 << (31 - dmachan); + // m_dcr[DCR4XX_DMASR] |= 1 << (27 - dmachan); + ppc4xx_dma_update_irq_states(); + + m_buffered_dma_timer[dmachan]->adjust(attotime::never, FALSE); + } + return TRUE; +} + + +/*------------------------------------------------- + buffered_dma_callback - callback that fires + when buffered DMA transfer is ready +-------------------------------------------------*/ + +TIMER_CALLBACK_MEMBER( ppc_device::ppc4xx_buffered_dma_callback ) +{ + int dmachan = param; + + static const UINT8 dma_transfer_width[4] = { 1, 2, 4, 16 }; + UINT32 *dmaregs = &m_dcr[8 * dmachan]; + INT32 destinc; + UINT8 width; + + width = dma_transfer_width[(dmaregs[DCR4XX_DMACR0] & PPC4XX_DMACR_PW_MASK) >> 26]; + destinc = (dmaregs[DCR4XX_DMACR0] & PPC4XX_DMACR_DAI) ? width : 0; + + if (dmaregs[DCR4XX_DMACR0] & PPC4XX_DMACR_TD) + { + /* peripheral to memory */ + + switch (width) + { + /* byte transfer */ + case 1: + do + { + UINT8 data = 0; + if (!m_ext_dma_read_cb[dmachan].isnull()) + data = (m_ext_dma_read_cb[dmachan])(*m_program, 1, 0xffffffff); + m_program->write_byte(dmaregs[DCR4XX_DMADA0], data); + dmaregs[DCR4XX_DMADA0] += destinc; + } while (!ppc4xx_dma_decrement_count(dmachan)); + break; + + /* word transfer */ + case 2: + do + { + UINT16 data = 0; + if (!m_ext_dma_read_cb[dmachan].isnull()) + data = (m_ext_dma_read_cb[dmachan])(*m_program, 2, 0xffffffff); + m_program->write_word(dmaregs[DCR4XX_DMADA0], data); + dmaregs[DCR4XX_DMADA0] += destinc; + } while (!ppc4xx_dma_decrement_count(dmachan)); + break; + + /* dword transfer */ + case 4: + do + { + UINT32 data = 0; + if (!m_ext_dma_read_cb[dmachan].isnull()) + data = (m_ext_dma_read_cb[dmachan])(*m_program, 4, 0xffffffff); + m_program->write_dword(dmaregs[DCR4XX_DMADA0], data); + dmaregs[DCR4XX_DMADA0] += destinc; + } while (!ppc4xx_dma_decrement_count(dmachan)); + break; + } + } + else + { + /* memory to peripheral */ + + // data is read from destination address! + switch (width) + { + /* byte transfer */ + case 1: + do + { + UINT8 data = m_program->read_byte(dmaregs[DCR4XX_DMADA0]); + if (!m_ext_dma_write_cb[dmachan].isnull()) + (m_ext_dma_write_cb[dmachan])(*m_program, 1, data, 0xffffffff); + dmaregs[DCR4XX_DMADA0] += destinc; + } while (!ppc4xx_dma_decrement_count(dmachan)); + break; + + /* word transfer */ + case 2: + do + { + UINT16 data = m_program->read_word(dmaregs[DCR4XX_DMADA0]); + if (!m_ext_dma_write_cb[dmachan].isnull()) + (m_ext_dma_write_cb[dmachan])(*m_program, 2, data, 0xffffffff); + dmaregs[DCR4XX_DMADA0] += destinc; + } while (!ppc4xx_dma_decrement_count(dmachan)); + break; + + /* dword transfer */ + case 4: + do + { + UINT32 data = m_program->read_dword(dmaregs[DCR4XX_DMADA0]); + if (!m_ext_dma_write_cb[dmachan].isnull()) + (m_ext_dma_write_cb[dmachan])(*m_program, 4, data, 0xffffffff); + dmaregs[DCR4XX_DMADA0] += destinc; + } while (!ppc4xx_dma_decrement_count(dmachan)); + break; + } + } +} + + +/*------------------------------------------------- + ppc4xx_dma_fetch_transmit_byte - fetch a byte + to send to a peripheral +-------------------------------------------------*/ + +int ppc_device::ppc4xx_dma_fetch_transmit_byte(int dmachan, UINT8 *byte) +{ + UINT32 *dmaregs = &m_dcr[8 * dmachan]; + + /* if the channel is not enabled, fail */ + if (!(dmaregs[DCR4XX_DMACR0] & PPC4XX_DMACR_CE)) + return FALSE; + + /* if no transfers remaining, fail */ + if ((dmaregs[DCR4XX_DMACT0] & 0xffff) == 0) + return FALSE; + + /* fetch the data */ + *byte = m_program->read_byte(dmaregs[DCR4XX_DMADA0]++); + ppc4xx_dma_decrement_count(dmachan); + return TRUE; +} + + +/*------------------------------------------------- + ppc4xx_dma_handle_receive_byte - receive a byte + transmitted by a peripheral +-------------------------------------------------*/ + +int ppc_device::ppc4xx_dma_handle_receive_byte(int dmachan, UINT8 byte) +{ + UINT32 *dmaregs = &m_dcr[8 * dmachan]; + + /* if the channel is not enabled, fail */ + if (!(dmaregs[DCR4XX_DMACR0] & PPC4XX_DMACR_CE)) + return FALSE; + + /* if no transfers remaining, fail */ + if ((dmaregs[DCR4XX_DMACT0] & 0xffff) == 0) + return FALSE; + + /* store the data */ + m_program->write_byte(dmaregs[DCR4XX_DMADA0]++, byte); + ppc4xx_dma_decrement_count(dmachan); + return TRUE; +} + + +/*------------------------------------------------- + ppc4xx_dma_execute - execute a DMA operation + if one is pending +-------------------------------------------------*/ + +void ppc_device::ppc4xx_dma_exec(int dmachan) +{ + static const UINT8 dma_transfer_width[4] = { 1, 2, 4, 16 }; + UINT32 *dmaregs = &m_dcr[8 * dmachan]; + INT32 destinc, srcinc; + UINT8 width; + + /* skip if not enabled */ + if (!(dmaregs[DCR4XX_DMACR0] & PPC4XX_DMACR_CE)) + return; + + /* check for unsupported features */ + if (!(dmaregs[DCR4XX_DMACR0] & PPC4XX_DMACR_TCE)) + fatalerror("ppc4xx_dma_exec: DMA_TCE == 0\n"); + + /* transfer mode */ + switch ((dmaregs[DCR4XX_DMACR0] & PPC4XX_DMACR_TM_MASK) >> 21) + { + /* buffered mode DMA */ + case 0: + if (((dmaregs[DCR4XX_DMACR0] & PPC4XX_DMACR_PL) >> 28) == 0) + { + /* buffered DMA with external peripheral */ + + INT64 numdata = dmaregs[DCR4XX_DMACT0]; + if (numdata == 0) + numdata = 65536; + + INT64 time; + if (numdata > 100) + { + time = (numdata * 1000000) / m_buffered_dma_rate[dmachan]; + } + else + { + time = 0; // let very short transfers occur instantly + } + + m_buffered_dma_timer[dmachan]->adjust(attotime::from_usec(time), dmachan); + } + else /* buffered DMA with internal peripheral (SPU) */ + { + /* nothing to do; this happens asynchronously and is driven by the SPU */ + } + break; + + /* fly-by mode DMA */ + case 1: + fatalerror("ppc4xx_dma_exec: fly-by DMA not implemented\n"); + + /* software initiated memory-to-memory mode DMA */ + case 2: + width = dma_transfer_width[(dmaregs[DCR4XX_DMACR0] & PPC4XX_DMACR_PW_MASK) >> 26]; + srcinc = (dmaregs[DCR4XX_DMACR0] & PPC4XX_DMACR_SAI) ? width : 0; + destinc = (dmaregs[DCR4XX_DMACR0] & PPC4XX_DMACR_DAI) ? width : 0; + + switch (width) + { + /* byte transfer */ + case 1: + do + { + m_program->write_byte(dmaregs[DCR4XX_DMADA0], m_program->read_byte(dmaregs[DCR4XX_DMASA0])); + dmaregs[DCR4XX_DMASA0] += srcinc; + dmaregs[DCR4XX_DMADA0] += destinc; + } while (!ppc4xx_dma_decrement_count(dmachan)); + break; + + /* word transfer */ + case 2: + do + { + m_program->write_word(dmaregs[DCR4XX_DMADA0], m_program->read_word(dmaregs[DCR4XX_DMASA0])); + dmaregs[DCR4XX_DMASA0] += srcinc; + dmaregs[DCR4XX_DMADA0] += destinc; + } while (!ppc4xx_dma_decrement_count(dmachan)); + break; + + /* dword transfer */ + case 4: + do + { + m_program->write_dword(dmaregs[DCR4XX_DMADA0], m_program->read_dword(dmaregs[DCR4XX_DMASA0])); + dmaregs[DCR4XX_DMASA0] += srcinc; + dmaregs[DCR4XX_DMADA0] += destinc; + } while (!ppc4xx_dma_decrement_count(dmachan)); + break; + + /* 16-byte transfer */ + case 16: + do + { + m_program->write_qword(dmaregs[DCR4XX_DMADA0], m_program->read_qword(dmaregs[DCR4XX_DMASA0])); + m_program->write_qword(dmaregs[DCR4XX_DMADA0] + 8, m_program->read_qword(dmaregs[DCR4XX_DMASA0] + 8)); + dmaregs[DCR4XX_DMASA0] += srcinc; + dmaregs[DCR4XX_DMADA0] += destinc; + } while (!ppc4xx_dma_decrement_count(dmachan)); + break; + } + break; + + /* hardware initiated memory-to-memory mode DMA */ + case 3: + fatalerror("ppc4xx_dma_exec: HW mem-to-mem DMA not implemented\n"); + } +} + + +/*------------------------------------------------- + ppc4xx_fit_callback - FIT timer callback +-------------------------------------------------*/ + +TIMER_CALLBACK_MEMBER( ppc_device::ppc4xx_fit_callback ) +{ + /* if this is a real callback and we are enabled, signal an interrupt */ + if (param) + { + m_core->spr[SPR4XX_TSR] |= PPC4XX_TSR_FIS; + ppc4xx_set_irq_line(0, 0); + } + + /* update ourself for the next interval if we are enabled */ + if (m_core->spr[SPR4XX_TCR] & PPC4XX_TCR_FIE) + { + UINT32 timebase = get_timebase(); + UINT32 interval = 0x200 << (4 * ((m_core->spr[SPR4XX_TCR] & PPC4XX_TCR_FP_MASK) >> 24)); + UINT32 target = (timebase + interval) & ~(interval - 1); + m_fit_timer->adjust(cycles_to_attotime((target + 1 - timebase) / m_tb_divisor), TRUE); + } + + /* otherwise, turn ourself off */ + else + m_fit_timer->adjust(attotime::never, FALSE); +} + + +/*------------------------------------------------- + ppc4xx_pit_callback - PIT timer callback +-------------------------------------------------*/ + +TIMER_CALLBACK_MEMBER( ppc_device::ppc4xx_pit_callback ) +{ + /* if this is a real callback and we are enabled, signal an interrupt */ + if (param) + { + m_core->spr[SPR4XX_TSR] |= PPC4XX_TSR_PIS; + ppc4xx_set_irq_line(0, 0); + } + + /* update ourself for the next interval if we are enabled and we are either being + forced to update, or we are in auto-reload mode */ + if ((m_core->spr[SPR4XX_TCR] & PPC4XX_TCR_PIE) && m_pit_reload != 0 && (!param || (m_core->spr[SPR4XX_TCR] & PPC4XX_TCR_ARE))) + { + UINT32 timebase = get_timebase(); + UINT32 interval = m_pit_reload; + UINT32 target = timebase + interval; + m_pit_timer->adjust(cycles_to_attotime((target + 1 - timebase) / m_tb_divisor), TRUE); + } + + /* otherwise, turn ourself off */ + else + m_pit_timer->adjust(attotime::never, FALSE); +} + + +/*------------------------------------------------- + ppc4xx_spu_update_irq_states - update the IRQ + state for the SPU +-------------------------------------------------*/ + +void ppc_device::ppc4xx_spu_update_irq_states() +{ + /* check for receive buffer full interrupt */ + if ((m_spu.regs[SPU4XX_RX_COMMAND] & 0x60) == 0x20 && (m_spu.regs[SPU4XX_LINE_STATUS] & 0x80)) + ppc4xx_set_irq_line(PPC4XX_IRQ_BIT_SPUR, ASSERT_LINE); + + /* check for receive error interrupt */ + else if ((m_spu.regs[SPU4XX_RX_COMMAND] & 0x10) && (m_spu.regs[SPU4XX_LINE_STATUS] & 0x78)) + ppc4xx_set_irq_line(PPC4XX_IRQ_BIT_SPUR, ASSERT_LINE); + + /* clear otherwise */ + else + ppc4xx_set_irq_line(PPC4XX_IRQ_BIT_SPUR, CLEAR_LINE); + + /* check for transmit buffer empty interrupt */ + if ((m_spu.regs[SPU4XX_TX_COMMAND] & 0x60) == 0x20 && (m_spu.regs[SPU4XX_LINE_STATUS] & 0x04)) + ppc4xx_set_irq_line(PPC4XX_IRQ_BIT_SPUT, ASSERT_LINE); + + /* check for shift register empty interrupt */ + else if ((m_spu.regs[SPU4XX_TX_COMMAND] & 0x10) && (m_spu.regs[SPU4XX_LINE_STATUS] & 0x02)) + ppc4xx_set_irq_line(PPC4XX_IRQ_BIT_SPUT, ASSERT_LINE); + + /* clear otherwise */ + else + ppc4xx_set_irq_line(PPC4XX_IRQ_BIT_SPUT, CLEAR_LINE); +} + + +/*------------------------------------------------- + ppc4xx_spu_rx_data - serial port data receive +-------------------------------------------------*/ + +void ppc_device::ppc4xx_spu_rx_data(UINT8 data) +{ + UINT32 new_rxin; + + /* fail if we are going to overflow */ + new_rxin = (m_spu.rxin + 1) % ARRAY_LENGTH(m_spu.rxbuffer); + if (new_rxin == m_spu.rxout) + fatalerror("ppc4xx_spu_rx_data: buffer overrun!\n"); + + /* store the data and accept the new in index */ + m_spu.rxbuffer[m_spu.rxin] = data; + m_spu.rxin = new_rxin; +} + + +/*------------------------------------------------- + ppc4xx_spu_timer_reset - reset and recompute + the transmit/receive timer +-------------------------------------------------*/ + +void ppc_device::ppc4xx_spu_timer_reset() +{ + UINT8 enabled = (m_spu.regs[SPU4XX_RX_COMMAND] | m_spu.regs[SPU4XX_TX_COMMAND]) & 0x80; + + /* if we're enabled, reset at the current baud rate */ + if (enabled) + { + attotime clockperiod = attotime::from_hz((m_dcr[DCR4XX_IOCR] & 0x02) ? 3686400 : 33333333); + int divisor = ((m_spu.regs[SPU4XX_BAUD_DIVISOR_H] * 256 + m_spu.regs[SPU4XX_BAUD_DIVISOR_L]) & 0xfff) + 1; + int bpc = 7 + ((m_spu.regs[SPU4XX_CONTROL] & 8) >> 3) + 1 + (m_spu.regs[SPU4XX_CONTROL] & 1); + attotime charperiod = clockperiod * (divisor * 16 * bpc); + m_spu.timer->adjust(charperiod, 0, charperiod); + if (PRINTF_SPU) + printf("ppc4xx_spu_timer_reset: baud rate = %.0f\n", ATTOSECONDS_TO_HZ(charperiod.attoseconds()) * bpc); + } + + /* otherwise, disable the timer */ + else + m_spu.timer->adjust(attotime::never); +} + + +/*------------------------------------------------- + ppc4xx_spu_callback - serial port send/receive + timer +-------------------------------------------------*/ + +TIMER_CALLBACK_MEMBER( ppc_device::ppc4xx_spu_callback ) +{ + /* transmit enabled? */ + if (m_spu.regs[SPU4XX_TX_COMMAND] & 0x80) + { + int operation = (m_spu.regs[SPU4XX_TX_COMMAND] >> 5) & 3; + + /* if we have data to transmit, do it now */ + if (!(m_spu.regs[SPU4XX_LINE_STATUS] & 0x04)) + { + /* if we have a transmit handler, send it that way */ + if (!m_spu.tx_cb.isnull()) + (m_spu.tx_cb)(*m_program, 0, m_spu.txbuf, 0xff); + + /* indicate that we have moved it to the shift register */ + m_spu.regs[SPU4XX_LINE_STATUS] |= 0x04; + m_spu.regs[SPU4XX_LINE_STATUS] &= ~0x02; + } + + /* otherwise, clear the shift register */ + else if (!(m_spu.regs[SPU4XX_LINE_STATUS] & 0x02)) + m_spu.regs[SPU4XX_LINE_STATUS] |= 0x02; + + /* handle DMA */ + if (operation >= 2 && ppc4xx_dma_fetch_transmit_byte(operation, &m_spu.txbuf)) + m_spu.regs[SPU4XX_LINE_STATUS] &= ~0x04; + } + + /* receive enabled? */ + if (m_spu.regs[SPU4XX_RX_COMMAND] & 0x80) + if (m_spu.rxout != m_spu.rxin) + { + int operation = (m_spu.regs[SPU4XX_RX_COMMAND] >> 5) & 3; + UINT8 rxbyte; + + /* consume the byte and advance the out pointer */ + rxbyte = m_spu.rxbuffer[m_spu.rxout]; + m_spu.rxout = (m_spu.rxout + 1) % ARRAY_LENGTH(m_spu.rxbuffer); + + /* if we're not full, copy data to the buffer and update the line status */ + if (!(m_spu.regs[SPU4XX_LINE_STATUS] & 0x80)) + { + m_spu.rxbuf = rxbyte; + m_spu.regs[SPU4XX_LINE_STATUS] |= 0x80; + } + + /* otherwise signal an overrun */ + else + { + m_spu.regs[SPU4XX_LINE_STATUS] |= 0x20; + goto updateirq; + } + + /* handle DMA */ + if (operation >= 2 && ppc4xx_dma_handle_receive_byte(operation, m_spu.rxbuf)) + m_spu.regs[SPU4XX_LINE_STATUS] &= ~0x80; + } + + /* update the final IRQ states */ +updateirq: + ppc4xx_spu_update_irq_states(); +} + + +/*------------------------------------------------- + ppc4xx_spu_r - serial port read handler +-------------------------------------------------*/ + +READ8_MEMBER( ppc4xx_device::ppc4xx_spu_r ) +{ + UINT8 result = 0xff; + + switch (offset) + { + case SPU4XX_BUFFER: + result = m_spu.rxbuf; + m_spu.regs[SPU4XX_LINE_STATUS] &= ~0x80; + break; + + default: + if (offset < ARRAY_LENGTH(m_spu.regs)) + result = m_spu.regs[offset]; + break; + } + if (PRINTF_SPU) + printf("spu_r(%d) = %02X\n", offset, result); + return result; +} + + +/*------------------------------------------------- + ppc4xx_spu_w - serial port write handler +-------------------------------------------------*/ + +WRITE8_MEMBER( ppc4xx_device::ppc4xx_spu_w ) +{ + UINT8 oldstate, newstate; + + if (PRINTF_SPU) + printf("spu_w(%d) = %02X\n", offset, data); + switch (offset) + { + /* clear error bits */ + case SPU4XX_LINE_STATUS: + m_spu.regs[SPU4XX_LINE_STATUS] &= ~(data & 0xf8); + ppc4xx_spu_update_irq_states(); + break; + + /* enable/disable the timer if one of these is enabled */ + case SPU4XX_RX_COMMAND: + case SPU4XX_TX_COMMAND: + oldstate = m_spu.regs[SPU4XX_RX_COMMAND] | m_spu.regs[SPU4XX_TX_COMMAND]; + m_spu.regs[offset] = data; + newstate = m_spu.regs[SPU4XX_RX_COMMAND] | m_spu.regs[SPU4XX_TX_COMMAND]; + if ((oldstate ^ newstate) & 0x80) + ppc4xx_spu_timer_reset(); + ppc4xx_spu_update_irq_states(); + break; + + /* if the divisor changes, we need to update the timer */ + case SPU4XX_BAUD_DIVISOR_H: + case SPU4XX_BAUD_DIVISOR_L: + if (data != m_spu.regs[offset]) + { + m_spu.regs[offset] = data; + ppc4xx_spu_timer_reset(); + } + break; + + /* if the number of data bits or stop bits changes, we need to update the timer */ + case SPU4XX_CONTROL: + oldstate = m_spu.regs[offset]; + m_spu.regs[offset] = data; + if ((oldstate ^ data) & 0x09) + ppc4xx_spu_timer_reset(); + break; + + case SPU4XX_BUFFER: + /* write to the transmit buffer and mark it full */ + m_spu.txbuf = data; + m_spu.regs[SPU4XX_LINE_STATUS] &= ~0x04; + break; + + default: + if (offset < ARRAY_LENGTH(m_spu.regs)) + m_spu.regs[offset] = data; + break; + } +} + + + +/*------------------------------------------------- + ppc4xx_spu_set_tx_handler - PowerPC 4XX- + specific TX handler configuration +-------------------------------------------------*/ + +void ppc4xx_device::ppc4xx_spu_set_tx_handler(write8_delegate callback) +{ + m_spu.tx_cb = callback; +} + + +/*------------------------------------------------- + ppc4xx_spu_receive_byte - PowerPC 4XX- + specific serial byte receive +-------------------------------------------------*/ + +void ppc4xx_device::ppc4xx_spu_receive_byte(UINT8 byteval) +{ + ppc4xx_spu_rx_data(byteval); +} + +/*------------------------------------------------- + ppc4xx_set_dma_read_handler - PowerPC 4XX- + specific external DMA read handler configuration +-------------------------------------------------*/ + +void ppc4xx_device::ppc4xx_set_dma_read_handler(int channel, read32_delegate callback, int rate) +{ + m_ext_dma_read_cb[channel] = callback; + m_buffered_dma_rate[channel] = rate; +} + +/*------------------------------------------------- + ppc4xx_set_dma_write_handler - PowerPC 4XX- + specific external DMA write handler configuration +-------------------------------------------------*/ + +void ppc4xx_device::ppc4xx_set_dma_write_handler(int channel, write32_delegate callback, int rate) +{ + m_ext_dma_write_cb[channel] = callback; + m_buffered_dma_rate[channel] = rate; +} + +/*------------------------------------------------- + ppc4xx_set_dcr_read_handler +-------------------------------------------------*/ + +void ppc4xx_device::ppc4xx_set_dcr_read_handler(read32_delegate dcr_read_func) +{ + m_dcr_read_func = dcr_read_func; + +} + +/*------------------------------------------------- + ppc4xx_set_dcr_write_handler +-------------------------------------------------*/ + +void ppc4xx_device::ppc4xx_set_dcr_write_handler(write32_delegate dcr_write_func) +{ + m_dcr_write_func = dcr_write_func; +} diff --git a/src/devices/cpu/powerpc/ppccom.h b/src/devices/cpu/powerpc/ppccom.h new file mode 100644 index 00000000000..b978aa4101b --- /dev/null +++ b/src/devices/cpu/powerpc/ppccom.h @@ -0,0 +1,480 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + ppccom.h + + Common PowerPC definitions and functions + +***************************************************************************/ + +#pragma once + +#ifndef __PPCCOM_H__ +#define __PPCCOM_H__ + +#include "ppc.h" + + +/*************************************************************************** + DEBUGGING +***************************************************************************/ + +#define DISABLE_FLAG_OPTIMIZATIONS (0) +#define DISABLE_FAST_REGISTERS (0) +#define SINGLE_INSTRUCTION_MODE (0) + +#define PRINTF_EXCEPTIONS (0) +#define PRINTF_MMU (0) + +#define PROBE_ADDRESS ~0 + + +/*************************************************************************** + CONSTANTS +***************************************************************************/ + +/* size of the execution code cache */ +#define CACHE_SIZE (32 * 1024 * 1024) + +/* compilation boundaries -- how far back/forward does the analysis extend? */ +#define COMPILE_BACKWARDS_BYTES 128 +#define COMPILE_FORWARDS_BYTES 512 +#define COMPILE_MAX_INSTRUCTIONS ((COMPILE_BACKWARDS_BYTES/4) + (COMPILE_FORWARDS_BYTES/4)) +#define COMPILE_MAX_SEQUENCE 64 + + +/* core parameters */ +#define POWERPC_MIN_PAGE_SHIFT 12 +#define POWERPC_MIN_PAGE_SIZE (1 << POWERPC_MIN_PAGE_SHIFT) +#define POWERPC_MIN_PAGE_MASK (POWERPC_MIN_PAGE_SIZE - 1) +#define POWERPC_TLB_ENTRIES 128 +#define PPC603_FIXED_TLB_ENTRIES 128 + + +/* cycle parameters */ +#define POWERPC_COUNT_READ_TBL 100 +#define POWERPC_COUNT_READ_DEC 100 + + +/* internal capabilities flags */ +#define PPCCAP_OEA 0x01 /* TRUE if we conform to the OEA */ +#define PPCCAP_VEA 0x02 /* TRUE if we conform to the VEA */ +#define PPCCAP_FPU 0x04 /* TRUE if we have an FPU */ +#define PPCCAP_MISALIGNED 0x08 /* TRUE if misaligned accesses are supported */ +#define PPCCAP_4XX 0x10 /* TRUE if we are a non-OEA 4XX class chip */ +#define PPCCAP_603_MMU 0x20 /* TRUE if we have 603-class MMU features */ +#define PPCCAP_MFIOC 0x40 /* TRUE if we have memory-forced I/O controller interface accesses */ +#define PPCCAP_601BAT 0x80 /* TRUE if we're doing 601-style BATs (unified I/D, different bit layout) */ +#define PPCCAP_604_MMU 0x100 /* TRUE if we have 604-class MMU features */ + + +/* exception types */ +enum +{ + EXCEPTION_RESET = 1, + EXCEPTION_MACHCHECK = 2, + EXCEPTION_DSI = 3, /* PPCCAP_OEA */ + EXCEPTION_PROTECTION = 3, /* PPCCAP_4XX */ + EXCEPTION_ISI = 4, + EXCEPTION_EI = 5, + EXCEPTION_ALIGN = 6, + EXCEPTION_PROGRAM = 7, + EXCEPTION_NOFPU = 8, + EXCEPTION_DECREMENT = 9, + EXCEPTION_SYSCALL = 12, + EXCEPTION_TRACE = 13, + EXCEPTION_FPASSIST = 14, + EXCEPTION_ITLBMISS = 16, /* PPCCAP_603_MMU */ + EXCEPTION_DTLBMISSL = 17, /* PPCCAP_603_MMU */ + EXCEPTION_DTLBMISSS = 18, /* PPCCAP_603_MMU */ + EXCEPTION_COUNT +}; + + +/* SPRs */ +enum +{ + /* UISA SPR register indexes */ + SPR_XER = 0x001, /* R/W Fixed Point Exception Register */ + SPR_LR = 0x008, /* R/W Link Register */ + SPR_CTR = 0x009, /* R/W Count Register */ + + /* VEA SPR register indexes */ + SPRVEA_TBL_R = 0x10c, /* R Time Base Low */ + SPRVEA_TBU_R = 0x10d, /* R Time Base High */ + + /* OEA SPR register indexes */ + SPROEA_DSISR = 0x012, /* R/W DSI Status Register */ + SPROEA_DAR = 0x013, /* R/W Data Address Register */ + SPROEA_DEC = 0x016, /* R/W Decrementer Register */ + SPROEA_SDR1 = 0x019, /* R/W Page Table Configuration */ + SPROEA_SRR0 = 0x01a, /* R/W Machine Status Save/Restore Register 0 */ + SPROEA_SRR1 = 0x01b, /* R/W Machine Status Save/Restore Register 1 */ + SPROEA_SPRG0 = 0x110, /* R/W SPR General 0 */ + SPROEA_SPRG1 = 0x111, /* R/W SPR General 1 */ + SPROEA_SPRG2 = 0x112, /* R/W SPR General 2 */ + SPROEA_SPRG3 = 0x113, /* R/W SPR General 3 */ + SPROEA_ASR = 0x118, /* R/W Address Space Register (64-bit only) */ + SPROEA_EAR = 0x11a, /* R/W External Access Register */ + SPROEA_PVR = 0x11f, /* R Processor Version Number */ + SPROEA_IBAT0U = 0x210, /* R/W Instruction BAT 0 Upper */ + SPROEA_IBAT0L = 0x211, /* R/W Instruction BAT 0 Lower */ + SPROEA_IBAT1U = 0x212, /* R/W Instruction BAT 1 Upper */ + SPROEA_IBAT1L = 0x213, /* R/W Instruction BAT 1 Lower */ + SPROEA_IBAT2U = 0x214, /* R/W Instruction BAT 2 Upper */ + SPROEA_IBAT2L = 0x215, /* R/W Instruction BAT 2 Lower */ + SPROEA_IBAT3U = 0x216, /* R/W Instruction BAT 3 Upper */ + SPROEA_IBAT3L = 0x217, /* R/W Instruction BAT 3 Lower */ + SPROEA_DBAT0U = 0x218, /* R/W Data BAT 0 Upper */ + SPROEA_DBAT0L = 0x219, /* R/W Data BAT 0 Lower */ + SPROEA_DBAT1U = 0x21a, /* R/W Data BAT 1 Upper */ + SPROEA_DBAT1L = 0x21b, /* R/W Data BAT 1 Lower */ + SPROEA_DBAT2U = 0x21c, /* R/W Data BAT 2 Upper */ + SPROEA_DBAT2L = 0x21d, /* R/W Data BAT 2 Lower */ + SPROEA_DBAT3U = 0x21e, /* R/W Data BAT 3 Upper */ + SPROEA_DBAT3L = 0x21f, /* R/W Data BAT 3 Lower */ + SPROEA_DABR = 0x3f5, /* R/W Data Address Breakpoint Register */ + + /* PowerPC 4XX SPR register indexes */ + SPR4XX_SRR0 = 0x01a, /* R/W 403GA Machine Status Save/Restore Register 0 */ + SPR4XX_SRR1 = 0x01b, /* R/W 403GA Machine Status Save/Restore Register 1 */ + SPR4XX_SPRG0 = 0x110, /* R/W 403GA SPR General 0 */ + SPR4XX_SPRG1 = 0x111, /* R/W 403GA SPR General 1 */ + SPR4XX_SPRG2 = 0x112, /* R/W 403GA SPR General 2 */ + SPR4XX_SPRG3 = 0x113, /* R/W 403GA SPR General 3 */ + SPR4XX_PVR = 0x11f, /* R 403GA Processor Version Number */ + SPR4XX_PID = 0x3b1, /* R/W 403GCX Process ID */ + SPR4XX_SGR = 0x3b9, /* R/W 403GCX Storage Guarded Register */ + SPR4XX_DCWR = 0x3ba, /* R/W 403GCX Data Cache Write Through */ + SPR4XX_TBHU = 0x3cc, /* R/W 403GCX Time Base High User-mode */ + SPR4XX_TBLU = 0x3cd, /* R/W 403GCX Time Base Low User-mode */ + SPR4XX_ICDBDR = 0x3d3, /* R 403GA 406GA Instruction Cache Debug Data Register */ + SPR4XX_ESR = 0x3d4, /* R/W 403GA 406GA Exception Syndrome Register */ + SPR4XX_DEAR = 0x3d5, /* R 403GA 406GA Data Exception Address Register */ + SPR4XX_EVPR = 0x3d6, /* R/W 403GA 406GA Exception Vector Prefix Register */ + SPR4XX_CDBCR = 0x3d7, /* R/W 403GA 406GA Cache Debug Control Register */ + SPR4XX_TSR = 0x3d8, /* R/C 403GA 406GA Timer Status Register */ + SPR4XX_TCR = 0x3da, /* R/W 403GA 406GA Timer Control Register */ + SPR4XX_PIT = 0x3db, /* R/W 403GA 406GA Programmable Interval Timer */ + SPR4XX_TBHI = 0x3dc, /* R/W 403GA 406GA Time Base High */ + SPR4XX_TBLO = 0x3dd, /* R/W 403GA 406GA Time Base Low */ + SPR4XX_SRR2 = 0x3de, /* R/W 403GA 406GA Machine Status Save/Restore Register 2 */ + SPR4XX_SRR3 = 0x3df, /* R/W 403GA 406GA Machine Status Save/Restore Register 3 */ + SPR4XX_DBSR = 0x3f0, /* R/C 403GA 406GA Debug Status Register */ + SPR4XX_DBCR = 0x3f2, /* R/W 403GA 406GA Debug Control Register */ + SPR4XX_IAC1 = 0x3f4, /* R/W 403GA 406GA Instruction Address Compare 1 */ + SPR4XX_IAC2 = 0x3f5, /* R/W 403GA 406GA Instruction Address Compare 2 */ + SPR4XX_DAC1 = 0x3f6, /* R/W 403GA 406GA Data Address Compare 1 */ + SPR4XX_DAC2 = 0x3f7, /* R/W 403GA 406GA Data Address Compare 2 */ + SPR4XX_DCCR = 0x3fa, /* R/W 403GA 406GA Data Cache Cacheability Register */ + SPR4XX_ICCR = 0x3fb, /* R/W 403GA 406GA Instruction Cache Cacheability Registe */ + SPR4XX_PBL1 = 0x3fc, /* R/W 403GA 406GA Protection Bound Lower 1 */ + SPR4XX_PBU1 = 0x3fd, /* R/W 403GA 406GA Protection Bound Upper 1 */ + SPR4XX_PBL2 = 0x3fe, /* R/W 403GA 406GA Protection Bound Lower 2 */ + SPR4XX_PBU2 = 0x3ff, /* R/W 403GA 406GA Protection Bound Upper 2 */ + + /* PowerPC 602 SPR register indexes */ + SPR602_TCR = 0x3d8, /* 602 */ + SPR602_IBR = 0x3da, /* 602 */ + SPR602_ESASRR = 0x3db, /* 602 */ + SPR602_SEBR = 0x3de, /* 602 */ + SPR602_SER = 0x3df, /* 602 */ + SPR602_SP = 0x3fd, /* 602 */ + SPR602_LT = 0x3fe, /* 602 */ + + /* PowerPC 603 SPR register indexes */ + SPR603_TBL_R = 0x10c, /* R 603 Time Base Low (Read-only) */ + SPR603_TBU_R = 0x10d, /* R 603 Time Base High (Read-only) */ + SPR603_TBL_W = 0x11c, /* W 603 Time Base Low (Write-only) */ + SPR603_TBU_W = 0x11d, /* W 603 Time Base Hight (Write-only) */ + SPR603_DMISS = 0x3d0, /* R 603 Data TLB Miss Address Register */ + SPR603_DCMP = 0x3d1, /* R 603 Data TLB Compare Register */ + SPR603_HASH1 = 0x3d2, /* R 603 Primary Hash Address Register */ + SPR603_HASH2 = 0x3d3, /* R 603 Secondary Hash Address Register */ + SPR603_IMISS = 0x3d4, /* R 603 Instruction TLB Miss Address Register */ + SPR603_ICMP = 0x3d5, /* R 603 Instruction TLB Compare Register */ + SPR603_RPA = 0x3d6, /* R/W 603 Required Physical Address Register */ + SPR603_HID0 = 0x3f0, /* R/W 603 Hardware Implementation Register 0 */ + SPR603_HID1 = 0x3f1, /* R/W 603 Hardware Implementation Register 1 */ + SPR603_IABR = 0x3f2, /* R/W 603 Instruction Address Breakpoint Register */ + SPR603_HID2 = 0x3f3 /* R/W 603 */ +}; + + +/* PowerPC 4XX DCR register indexes */ +enum +{ + DCR4XX_EXISR = 0x040, /* external interrupt status */ + DCR4XX_EXIER = 0x042, /* external interrupt enable */ + DCR4XX_BR0 = 0x080, /* bank */ + DCR4XX_BR1 = 0x081, /* bank */ + DCR4XX_BR2 = 0x082, /* bank */ + DCR4XX_BR3 = 0x083, /* bank */ + DCR4XX_BR4 = 0x084, /* bank */ + DCR4XX_BR5 = 0x085, /* bank */ + DCR4XX_BR6 = 0x086, /* bank */ + DCR4XX_BR7 = 0x087, /* bank */ + DCR4XX_BEAR = 0x090, /* bus error address */ + DCR4XX_BESR = 0x091, /* bus error syndrome */ + DCR4XX_IOCR = 0x0a0, /* io configuration */ + DCR4XX_DMACR0 = 0x0c0, /* dma channel control */ + DCR4XX_DMACT0 = 0x0c1, /* dma destination address */ + DCR4XX_DMADA0 = 0x0c2, /* dma destination address */ + DCR4XX_DMASA0 = 0x0c3, /* dma source address */ + DCR4XX_DMACC0 = 0x0c4, /* dma chained count */ + DCR4XX_DMACR1 = 0x0c8, /* dma channel control */ + DCR4XX_DMACT1 = 0x0c9, /* dma destination address */ + DCR4XX_DMADA1 = 0x0ca, /* dma destination address */ + DCR4XX_DMASA1 = 0x0cb, /* dma source address */ + DCR4XX_DMACC1 = 0x0cc, /* dma chained count */ + DCR4XX_DMACR2 = 0x0d0, /* dma channel control */ + DCR4XX_DMACT2 = 0x0d1, /* dma destination address */ + DCR4XX_DMADA2 = 0x0d2, /* dma source address */ + DCR4XX_DMASA2 = 0x0d3, /* dma source address */ + DCR4XX_DMACC2 = 0x0d4, /* dma chained count */ + DCR4XX_DMACR3 = 0x0d8, /* dma channel control */ + DCR4XX_DMACT3 = 0x0d9, /* dma destination address */ + DCR4XX_DMADA3 = 0x0da, /* dma source address */ + DCR4XX_DMASA3 = 0x0db, /* dma source address */ + DCR4XX_DMACC3 = 0x0dc, /* dma chained count */ + DCR4XX_DMASR = 0x0e0 /* dma status */ +}; + + +/* PowerPC 4XX SPU register indexes */ +enum +{ + SPU4XX_LINE_STATUS = 0x00, + SPU4XX_HANDSHAKE_STATUS = 0x02, + SPU4XX_BAUD_DIVISOR_H = 0x04, + SPU4XX_BAUD_DIVISOR_L = 0x05, + SPU4XX_CONTROL = 0x06, + SPU4XX_RX_COMMAND = 0x07, + SPU4XX_TX_COMMAND = 0x08, + SPU4XX_BUFFER = 0x09 +}; + + +/* FPSCR register bits */ +#define FPSCR_FX 0x80000000 +#define FPSCR_FEX 0x40000000 +#define FPSCR_VX 0x20000000 +#define FPSCR_OX 0x10000000 +#define FPSCR_UX 0x08000000 +#define FPSCR_ZX 0x04000000 +#define FPSCR_XX 0x02000000 + + +/* XER register bits */ +#define XER_SO 0x80000000 +#define XER_OV 0x40000000 +#define XER_CA 0x20000000 + + +/* Machine State Register bits - common */ +#define MSR_ILE 0x00010000 /* Interrupt Little Endian Mode */ +#define MSR_EE 0x00008000 /* External Interrupt Enable */ +#define MSR_PR 0x00004000 /* Problem State */ +#define MSR_ME 0x00001000 /* Machine Check Enable */ +#define MSR_LE 0x00000001 /* Little Endian */ + +/* Machine State Register bits - OEA */ +#define MSROEA_POW 0x00040000 /* Power Management Enable */ +#define MSROEA_FP 0x00002000 /* Floating Point Available */ +#define MSROEA_FE0 0x00000800 /* FP Exception Mode 0 */ +#define MSROEA_SE 0x00000400 /* Single Step Trace Enable */ +#define MSROEA_BE 0x00000200 /* Branch Trace Enable */ +#define MSROEA_FE1 0x00000100 /* FP Exception Mode 1 */ +#define MSROEA_IP 0x00000040 /* Interrupt Prefix */ +#define MSROEA_IR 0x00000020 /* Instruction Relocate */ +#define MSROEA_DR 0x00000010 /* Data Relocate */ +#define MSROEA_RI 0x00000002 /* Recoverable Interrupt Enable */ + +/* Machine State Register bits - 4XX */ +#define MSR4XX_WE 0x00040000 /* Wait State Enable */ +#define MSR4XX_CE 0x00020000 /* Critical Interrupt Enable */ +#define MSR4XX_DE 0x00000200 /* Debug Exception Enable */ +#define MSR4XX_PE 0x00000008 /* Protection Enable (reserved for others) */ +#define MSR4XX_PX 0x00000004 /* Protection Exclusive Mode (reserved for others) */ + +/* Machine State Register bits - 602 */ +#define MSR602_AP 0x00800000 /* Access privilege state */ +#define MSR602_SA 0x00400000 /* Supervisor access mode */ + +/* Machine State Register bits - 603 */ +#define MSR603_TGPR 0x00020000 /* Temporary GPR Remapping */ + + +/* DSISR bits for DSI/alignment exceptions */ +#define DSISR_DIRECT 0x00000001 /* DSI: direct-store exception? */ +#define DSISR_NOT_FOUND 0x00000002 /* DSI: not found in HTEG or DBAT */ +#define DSISR_PROTECTED 0x00000010 /* DSI: exception due to protection */ +#define DSISR_CACHE_ERROR 0x00000020 /* DSI: operation on incorrect cache type */ +#define DSISR_STORE 0x00000040 /* DSI: store (1) or load (0) */ +#define DSISR_DABR 0x00000200 /* DSI: DABR match occurred */ +#define DSISR_NO_SEGMENT 0x00000400 /* DSI: no segment match found (64-bit only) */ +#define DSISR_INVALID_ECWX 0x00000800 /* DSI: ECIWX or ECOWX used with EAR[E] = 0 */ +#define DSISR_INSTRUCTION 0xfffff000 /* align: instruction decoding bits */ + + +/* PowerPC 4XX IRQ bits */ +#define PPC4XX_IRQ_BIT_CRITICAL (0x80000000 >> 0) +#define PPC4XX_IRQ_BIT_SPUR (0x80000000 >> 4) +#define PPC4XX_IRQ_BIT_SPUT (0x80000000 >> 5) +#define PPC4XX_IRQ_BIT_JTAGR (0x80000000 >> 6) +#define PPC4XX_IRQ_BIT_JTAGT (0x80000000 >> 7) +#define PPC4XX_IRQ_BIT_DMA0 (0x80000000 >> 8) +#define PPC4XX_IRQ_BIT_DMA1 (0x80000000 >> 9) +#define PPC4XX_IRQ_BIT_DMA2 (0x80000000 >> 10) +#define PPC4XX_IRQ_BIT_DMA3 (0x80000000 >> 11) +#define PPC4XX_IRQ_BIT_EXT0 (0x80000000 >> 27) +#define PPC4XX_IRQ_BIT_EXT1 (0x80000000 >> 28) +#define PPC4XX_IRQ_BIT_EXT2 (0x80000000 >> 29) +#define PPC4XX_IRQ_BIT_EXT3 (0x80000000 >> 30) +#define PPC4XX_IRQ_BIT_EXT4 (0x80000000 >> 31) + +#define PPC4XX_IRQ_BIT_EXT(n) (PPC4XX_IRQ_BIT_EXT0 >> (n)) +#define PPC4XX_IRQ_BIT_DMA(n) (PPC4XX_IRQ_BIT_DMA0 >> (n)) + + +/* PowerPC 4XX DMA control bits */ +#define PPC4XX_DMACR_CE 0x80000000 /* channel enable */ +#define PPC4XX_DMACR_CIE 0x40000000 /* channel interrupt enable */ +#define PPC4XX_DMACR_TD 0x20000000 /* transfer direction */ +#define PPC4XX_DMACR_PL 0x10000000 /* peripheral location */ +#define PPC4XX_DMACR_PW_MASK 0x0c000000 /* peripheral width */ +#define PPC4XX_DMACR_DAI 0x02000000 /* destination address increment */ +#define PPC4XX_DMACR_SAI 0x01000000 /* source address increment */ +#define PPC4XX_DMACR_CP 0x00800000 /* channel priority */ +#define PPC4XX_DMACR_TM_MASK 0x00600000 /* transfer mode */ +#define PPC4XX_DMACR_PSC_MASK 0x00180000 /* peripheral setup cycles */ +#define PPC4XX_DMACR_PWC_MASK 0x0007e000 /* peripheral wait cycles */ +#define PPC4XX_DMACR_PHC_MASK 0x00001c00 /* peripheral hold cycles */ +#define PPC4XX_DMACR_ETD 0x00000200 /* end-of-transfer pin direction */ +#define PPC4XX_DMACR_TCE 0x00000100 /* terminal count enable */ +#define PPC4XX_DMACR_CH 0x00000080 /* chaining enable */ +#define PPC4XX_DMACR_BME 0x00000040 /* burst mode enable */ +#define PPC4XX_DMACR_ECE 0x00000020 /* EOT chain mode enable */ +#define PPC4XX_DMACR_TCD 0x00000010 /* TC chain mode disable */ +#define PPC4XX_DMACR_PCE 0x00000008 + + +/* PowerPC 4XX Timer control register bits */ +#define PPC4XX_TCR_WP_MASK 0xc0000000 /* watchdog period */ +#define PPC4XX_TCR_WRC_MASK 0x30000000 /* watchdog reset control */ +#define PPC4XX_TCR_WIE 0x08000000 /* watchdog interrupt enable */ +#define PPC4XX_TCR_PIE 0x04000000 /* PIT interrupt enable */ +#define PPC4XX_TCR_FP_MASK 0x03000000 /* FIT period */ +#define PPC4XX_TCR_FIE 0x00800000 /* FIT interrupt enable */ +#define PPC4XX_TCR_ARE 0x00400000 /* auto reload enable */ + + +/* PowerPC 4XX Timer status register bits */ +#define PPC4XX_TSR_ENW 0x80000000 /* enable next watchdog */ +#define PPC4XX_TSR_WIS 0x40000000 /* watchdog interrupt status */ +#define PPC4XX_TSR_WRS_MASK 0x30000000 /* watchdog reset status */ +#define PPC4XX_TSR_PIS 0x08000000 /* PIT interrupt status */ +#define PPC4XX_TSR_FIS 0x04000000 /* FIT interrupt status */ + + +/* instruction decoding masks */ +#define M_LI 0x03fffffc +#define M_AA 0x00000002 +#define M_LK 0x00000001 +#define M_BO 0x03e00000 +#define M_BI 0x001f0000 +#define M_BD 0x0000fffc +#define M_RT 0x03e00000 +#define M_RD 0x03e00000 +#define M_RS 0x03e00000 +#define M_RA 0x001f0000 +#define M_RB 0x0000f800 +#define M_CRFD 0x03800000 +#define M_L 0x00200000 +#define M_TO 0x03e00000 +#define M_D 0x0000ffff +#define M_SIMM 0x0000ffff +#define M_UIMM 0x0000ffff +#define M_NB 0x0000f800 +#define M_SR 0x000f0000 +#define M_SH 0x0000f800 +#define M_CRFS 0x001c0000 +#define M_IMM 0x0000f000 +#define M_CRBD 0x03e00000 +#define M_RC 0x00000001 +#define M_CRBA 0x001f0000 +#define M_CRBB 0x0000f800 +#define M_SPR 0x001FF800 +#define M_TBR 0x001FF800 +#define M_CRM 0x000FF000 +#define M_DCR 0x001FF800 +#define M_FM 0x01FE0000 +#define M_OE 0x00000400 +#define M_REGC 0x000007c0 +#define M_MB 0x000007c0 +#define M_ME 0x0000003e +#define M_XO 0x000007fe + + + +/*************************************************************************** + HELPER MACROS +***************************************************************************/ + +/* + * Field Defining Macros + * + * These macros generate instruction words with their associated fields filled + * in with the passed value. + */ + +#define D_OP(op) (UINT32)((op & 0x3f) << 26) +#define D_XO(xo) (UINT32)((xo & 0x3ff) << 1) +#define D_RT(r) (UINT32)((r & 0x1f) << (31 - 10)) +#define D_RA(r) (UINT32)((r & 0x1f) << (31 - 15)) +#define D_UIMM(u) (UINT32)(u & 0xffff) + +/* + * Macros to Get Field Values + * + * These macros return the values of fields in an opcode. They all return + * unsigned values and do not perform any sign extensions. + */ + +#define G_RT(op) ((op & M_RT) >> (31 - 10)) +#define G_RD(op) ((op & M_RD) >> (31 - 10)) +#define G_RS(op) ((op & M_RS) >> (31 - 10)) +#define G_RA(op) ((op & M_RA) >> (31 - 15)) +#define G_RB(op) ((op & M_RB) >> (31 - 20)) +#define G_SIMM(op) (op & M_SIMM) +#define G_UIMM(op) (op & M_UIMM) +#define G_LI(op) ((op & M_LI) >> 2) +#define G_BO(op) ((op & M_BO) >> (31 - 10)) +#define G_BI(op) ((op & M_BI) >> (31 - 15)) +#define G_BD(op) ((op & M_BD) >> 2) +#define G_CRFD(op) ((op & M_CRFD) >> (31 - 8)) +#define G_L(op) ((op & M_L) >> (31 - 10)) +#define G_CRBD(op) ((op & M_CRBD) >> (31 - 10)) +#define G_CRBA(op) ((op & M_CRBA) >> (31 - 15)) +#define G_CRBB(op) ((op & M_CRBB) >> (31 - 20)) +#define G_REGC(op) ((op & M_REGC) >> (31 - 25)) +#define G_D(op) (op & M_D) +#define G_NB(op) ((op & M_NB) >> (31 - 20)) +#define G_CRFS(op) ((op & M_CRFS) >> (31 - 13)) +#define G_SPR(op) ((op & M_SPR) >> (31 - 20)) +#define G_TBR(op) ((op & M_TBR) >> (31 - 20)) +#define G_DCR(op) ((op & M_DCR) >> (31 - 20)) +#define G_SR(op) ((op & M_SR) >> (31 - 15)) +#define G_CRM(op) ((op & M_CRM) >> (31 - 19)) +#define G_FM(op) ((op & M_FM) >> (31 - 14)) +#define G_IMM(op) ((op & M_IMM) >> (31 - 19)) +#define G_SH(op) ((op & M_SH) >> (31 - 20)) +#define G_MB(op) ((op & M_MB) >> (31 - 25)) +#define G_ME(op) ((op & M_ME) >> 1) +#define G_TO(op) ((op & M_TO) >> (31 - 10)) +#define G_XO(op) ((op & M_XO) >> (31 - 30)) + + + +#endif /* __PPCCOM_H__ */ diff --git a/src/devices/cpu/powerpc/ppcdrc.c b/src/devices/cpu/powerpc/ppcdrc.c new file mode 100644 index 00000000000..088eab855aa --- /dev/null +++ b/src/devices/cpu/powerpc/ppcdrc.c @@ -0,0 +1,3923 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + ppcdrc.c + + Universal machine language-based PowerPC emulator. + +**************************************************************************** + + Future improvements/changes: + + * crxor a,a,a / creqv a,a,a / cror a,a,a + +***************************************************************************/ + +#include "emu.h" +#include "debugger.h" +#include "ppc.h" +#include "ppccom.h" +#include "ppcfe.h" +#include "cpu/drcfe.h" +#include "cpu/drcuml.h" +#include "cpu/drcumlsh.h" + +using namespace uml; + +extern offs_t ppc_dasm_one(char *buffer, UINT32 pc, UINT32 op); + + + +/*************************************************************************** + CONSTANTS +***************************************************************************/ + +/* map variables */ +#define MAPVAR_PC M0 +#define MAPVAR_CYCLES M1 +#define MAPVAR_DSISR M2 + +/* mode bits */ +#define MODE_LITTLE_ENDIAN 0x01 +#define MODE_DATA_TRANSLATION 0x02 /* OEA */ +#define MODE_PROTECTION 0x02 /* 4XX */ +#define MODE_USER 0x04 + +/* exit codes */ +#define EXECUTE_OUT_OF_CYCLES 0 +#define EXECUTE_MISSING_CODE 1 +#define EXECUTE_UNMAPPED_CODE 2 +#define EXECUTE_RESET_CACHE 3 + + + +/*************************************************************************** + MACROS +***************************************************************************/ + +#define R32(reg) m_regmap[reg] +#define R32Z(reg) (((reg) == 0) ? uml::parameter(0) : m_regmap[reg]) +#define F64(reg) m_fdregmap[reg] +#define CR32(reg) mem(&m_core->cr[reg]) +#define FPSCR32 mem(&m_core->fpscr) +#define MSR32 mem(&m_core->msr) +#define XERSO32 mem(&m_core->xerso) +#define SR32(reg) mem(&m_core->sr[reg]) +#define SPR32(reg) mem(&m_core->spr[reg]) + +#define CRMASK(reg) (0xf0000000 >> ((reg) * 4)) + +/* DSISR values for various addressing types */ +#define DSISR_IMM(op) ((0) | /* bits 15-16: cleared */ \ + ((((op) >> (31- 5)) & 0x01) << (31-17)) | /* bit 17: opcode bit 5 */ \ + ((((op) >> (31- 4)) & 0x0f) << (31-21)) | /* bits 18-21: opcode bits 1-4 */ \ + ((((op) >> (31-10)) & 0x1f) << (31-26)) | /* bits 22-26: opcode bits 6-10 */ \ + (0)) /* bits 27-31: undefined */ + +#define DSISR_IMMU(op) ((0) | /* bits 15-16: cleared */ \ + ((((op) >> (31- 5)) & 0x01) << (31-17)) | /* bit 17: opcode bit 5 */ \ + ((((op) >> (31- 4)) & 0x0f) << (31-21)) | /* bits 18-21: opcode bits 1-4 */ \ + ((((op) >> (31-10)) & 0x1f) << (31-26)) | /* bits 22-26: opcode bits 6-10 */ \ + ((((op) >> (31-15)) & 0x1f) << (31-31))) /* bits 27-31: opcode bits 11-15 */ + +#define DSISR_IDX(op) (((((op) >> (31-30)) & 0x03) << (31-16)) | /* bits 15-16: opcode bits 29-30 */ \ + ((((op) >> (31-25)) & 0x01) << (31-17)) | /* bit 17: opcode bit 25 */ \ + ((((op) >> (31-24)) & 0x0f) << (31-21)) | /* bits 18-21: opcode bits 21-24 */ \ + ((((op) >> (31-10)) & 0x1f) << (31-26)) | /* bits 22-26: opcode bits 6-10 */ \ + (0)) /* bits 27-31: undefined */ + +#define DSISR_IDXU(op) (((((op) >> (31-30)) & 0x03) << (31-16)) | /* bits 15-16: opcode bits 29-30 */ \ + ((((op) >> (31-25)) & 0x01) << (31-17)) | /* bit 17: opcode bit 25 */ \ + ((((op) >> (31-24)) & 0x0f) << (31-21)) | /* bits 18-21: opcode bits 21-24 */ \ + ((((op) >> (31-10)) & 0x1f) << (31-26)) | /* bits 22-26: opcode bits 6-10 */ \ + ((((op) >> (31-15)) & 0x1f) << (31-31))) /* bits 27-31: opcode bits 11-15 */ + + + +/*************************************************************************** + INLINE FUNCTIONS +***************************************************************************/ + +/*------------------------------------------------- + alloc_handle - allocate a handle if not + already allocated +-------------------------------------------------*/ + +inline void ppc_device::alloc_handle(drcuml_state *drcuml, code_handle **handleptr, const char *name) +{ + if (*handleptr == NULL) + *handleptr = drcuml->handle_alloc(name); +} + + +/*------------------------------------------------- + load_fast_iregs - load any fast integer + registers +-------------------------------------------------*/ + +inline void ppc_device::load_fast_iregs(drcuml_block *block) +{ + int regnum; + + for (regnum = 0; regnum < ARRAY_LENGTH(m_regmap); regnum++) + { + if (m_regmap[regnum].is_int_register()) + { + UML_MOV(block, ireg(m_regmap[regnum].ireg() - REG_I0), mem(&m_core->r[regnum])); + } + } +} + + +/*------------------------------------------------- + save_fast_iregs - save any fast integer + registers +-------------------------------------------------*/ + +void ppc_device::save_fast_iregs(drcuml_block *block) +{ + int regnum; + + for (regnum = 0; regnum < ARRAY_LENGTH(m_regmap); regnum++) + { + if (m_regmap[regnum].is_int_register()) + { + UML_MOV(block, mem(&m_core->r[regnum]), ireg(m_regmap[regnum].ireg() - REG_I0)); + } + } +} + + +/*------------------------------------------------- + compute_rlw_mask - compute the 32-bit mask + for an rlw* instruction +-------------------------------------------------*/ + +inline UINT32 ppc_device::compute_rlw_mask(UINT8 mb, UINT8 me) +{ + if (mb <= me) + return (0xffffffff >> mb) & (0xffffffff << (31 - me)); + else + return (0xffffffff >> mb) | (0xffffffff << (31 - me)); +} + + +/*------------------------------------------------- + compute_crf_mask - compute the 32-bit mask + for a mtcrf/mfcrf instruction +-------------------------------------------------*/ + +inline UINT32 ppc_device::compute_crf_mask(UINT8 crm) +{ + UINT32 mask = 0; + if (crm & 0x80) mask |= 0xf0000000; + if (crm & 0x40) mask |= 0x0f000000; + if (crm & 0x20) mask |= 0x00f00000; + if (crm & 0x10) mask |= 0x000f0000; + if (crm & 0x08) mask |= 0x0000f000; + if (crm & 0x04) mask |= 0x00000f00; + if (crm & 0x02) mask |= 0x000000f0; + if (crm & 0x01) mask |= 0x0000000f; + return mask; +} + + +/*------------------------------------------------- + compute_spr - compute the SPR index from the + SPR field of an opcode +-------------------------------------------------*/ + +inline UINT32 ppc_device::compute_spr(UINT32 spr) +{ + return ((spr >> 5) | (spr << 5)) & 0x3ff; +} + + + +/*************************************************************************** + CORE CALLBACKS +***************************************************************************/ + +/*------------------------------------------------- + ppcdrc_execute - execute the CPU for the + specified number of cycles +-------------------------------------------------*/ + +void ppc_device::execute_run() +{ + int execute_result; + + /* reset the cache if dirty */ + if (m_cache_dirty) + code_flush_cache(); + m_cache_dirty = FALSE; + + /* execute */ + do + { + /* run as much as we can */ + execute_result = m_drcuml->execute(*m_entry); + + /* if we need to recompile, do it */ + if (execute_result == EXECUTE_MISSING_CODE) + code_compile_block(m_core->mode, m_core->pc); + else if (execute_result == EXECUTE_UNMAPPED_CODE) + fatalerror("Attempted to execute unmapped code at PC=%08X\n", m_core->pc); + else if (execute_result == EXECUTE_RESET_CACHE) + code_flush_cache(); + + } while (execute_result != EXECUTE_OUT_OF_CYCLES); +} + + +/*------------------------------------------------- + ppcdrc_set_options - configure DRC options +-------------------------------------------------*/ + +void ppc_device::ppcdrc_set_options(UINT32 options) +{ + m_drcoptions = options; +} + + +/*------------------------------------------------- + ppcdrc_add_fastram - add a new fastram + region +-------------------------------------------------*/ + +void ppc_device::ppcdrc_add_fastram(offs_t start, offs_t end, UINT8 readonly, void *base) +{ + if (m_fastram_select < ARRAY_LENGTH(m_fastram)) + { + m_fastram[m_fastram_select].start = start; + m_fastram[m_fastram_select].end = end; + m_fastram[m_fastram_select].readonly = readonly; + m_fastram[m_fastram_select].base = base; + m_fastram_select++; + } +} + + +/*------------------------------------------------- + ppcdrc_add_hotspot - add a new hotspot +-------------------------------------------------*/ + +void ppc_device::ppcdrc_add_hotspot(offs_t pc, UINT32 opcode, UINT32 cycles) +{ + if (m_hotspot_select < ARRAY_LENGTH(m_hotspot)) + { + m_hotspot[m_hotspot_select].pc = pc; + m_hotspot[m_hotspot_select].opcode = opcode; + m_hotspot[m_hotspot_select].cycles = cycles; + m_hotspot_select++; + } +} + + + +/*************************************************************************** + CACHE MANAGEMENT +***************************************************************************/ + +/*------------------------------------------------- + code_flush_cache - flush the cache and + regenerate static code +-------------------------------------------------*/ + +void ppc_device::code_flush_cache() +{ + /* empty the transient cache contents */ + m_drcuml->reset(); + + try + { + /* generate the entry point and out-of-cycles handlers */ + static_generate_entry_point(); + static_generate_nocode_handler(); + static_generate_out_of_cycles(); + static_generate_tlb_mismatch(); + if (m_cap & PPCCAP_603_MMU) + static_generate_swap_tgpr(); + + /* append exception handlers for various types */ + static_generate_exception(EXCEPTION_RESET, TRUE, "exception_reset"); + static_generate_exception(EXCEPTION_MACHCHECK, TRUE, "exception_machine_check"); + static_generate_exception(EXCEPTION_DSI, TRUE, "exception_dsi"); + static_generate_exception(EXCEPTION_ISI, TRUE, "exception_isi"); + static_generate_exception(EXCEPTION_EI, TRUE, "exception_ei"); + static_generate_exception(EXCEPTION_EI, FALSE, "exception_ei_norecover"); + static_generate_exception(EXCEPTION_ALIGN, TRUE, "exception_align"); + static_generate_exception(EXCEPTION_PROGRAM, TRUE, "exception_program"); + static_generate_exception(EXCEPTION_NOFPU, TRUE, "exception_fpu_unavailable"); + static_generate_exception(EXCEPTION_DECREMENT, TRUE, "exception_decrementer"); + static_generate_exception(EXCEPTION_SYSCALL, TRUE, "exception_syscall"); + static_generate_exception(EXCEPTION_TRACE, TRUE, "exception_trace"); + static_generate_exception(EXCEPTION_FPASSIST, TRUE, "exception_floating_point_assist"); + if (m_cap & PPCCAP_603_MMU) + { + static_generate_exception(EXCEPTION_ITLBMISS, TRUE, "exception_itlb_miss"); + static_generate_exception(EXCEPTION_DTLBMISSL, TRUE, "exception_dtlb_miss_load"); + static_generate_exception(EXCEPTION_DTLBMISSS, TRUE, "exception_dtlb_miss_store"); + } + + /* add subroutines for memory accesses */ + for (int mode = 0; mode < 8; mode++) + { + static_generate_memory_accessor(mode, 1, FALSE, FALSE, "read8", m_read8[mode], NULL); + static_generate_memory_accessor(mode, 1, TRUE, FALSE, "write8", m_write8[mode], NULL); + static_generate_memory_accessor(mode, 2, FALSE, TRUE, "read16mask", m_read16mask[mode], NULL); + static_generate_memory_accessor(mode, 2, FALSE, FALSE, "read16", m_read16[mode], m_read16mask[mode]); + static_generate_memory_accessor(mode, 2, TRUE, TRUE, "write16mask", m_write16mask[mode], NULL); + static_generate_memory_accessor(mode, 2, TRUE, FALSE, "write16", m_write16[mode], m_write16mask[mode]); + static_generate_memory_accessor(mode, 4, FALSE, TRUE, "read32mask", m_read32mask[mode], NULL); + static_generate_memory_accessor(mode, 4, FALSE, FALSE, "read32align", m_read32align[mode], NULL); + static_generate_memory_accessor(mode, 4, FALSE, FALSE, "read32", m_read32[mode], m_read32mask[mode]); + static_generate_memory_accessor(mode, 4, TRUE, TRUE, "write32mask", m_write32mask[mode], NULL); + static_generate_memory_accessor(mode, 4, TRUE, FALSE, "write32align",m_write32align[mode],NULL); + static_generate_memory_accessor(mode, 4, TRUE, FALSE, "write32", m_write32[mode], m_write32mask[mode]); + static_generate_memory_accessor(mode, 8, FALSE, TRUE, "read64mask", m_read64mask[mode], NULL); + static_generate_memory_accessor(mode, 8, FALSE, FALSE, "read64", m_read64[mode], m_read64mask[mode]); + static_generate_memory_accessor(mode, 8, TRUE, TRUE, "write64mask", m_write64mask[mode], NULL); + static_generate_memory_accessor(mode, 8, TRUE, FALSE, "write64", m_write64[mode], m_write64mask[mode]); + static_generate_lsw_entries(mode); + static_generate_stsw_entries(mode); + } + } + catch (drcuml_block::abort_compilation &) + { + fatalerror("Error generating PPC static handlers\n"); + } +} + + +/*------------------------------------------------- + code_compile_block - compile a block of the + given mode at the specified pc +-------------------------------------------------*/ + +void ppc_device::code_compile_block(UINT8 mode, offs_t pc) +{ + compiler_state compiler = { 0 }; + const opcode_desc *seqhead, *seqlast; + const opcode_desc *desclist; + int override = FALSE; + drcuml_block *block; + + g_profiler.start(PROFILER_DRC_COMPILE); + + /* get a description of this sequence */ + desclist = m_drcfe->describe_code(pc); + if (m_drcuml->logging() || m_drcuml->logging_native()) + log_opcode_desc(m_drcuml, desclist, 0); + + bool succeeded = false; + while (!succeeded) + { + try + { + /* start the block */ + block = m_drcuml->begin_block(4096); + + /* loop until we get through all instruction sequences */ + for (seqhead = desclist; seqhead != NULL; seqhead = seqlast->next()) + { + const opcode_desc *curdesc; + UINT32 nextpc; + + /* add a code log entry */ + if (m_drcuml->logging()) + block->append_comment("-------------------------"); // comment + + /* determine the last instruction in this sequence */ + for (seqlast = seqhead; seqlast != NULL; seqlast = seqlast->next()) + if (seqlast->flags & OPFLAG_END_SEQUENCE) + break; + assert(seqlast != NULL); + + /* if we don't have a hash for this mode/pc, or if we are overriding all, add one */ + if (override || !m_drcuml->hash_exists(mode, seqhead->pc)) + UML_HASH(block, mode, seqhead->pc); // hash mode,pc + + /* if we already have a hash, and this is the first sequence, assume that we */ + /* are recompiling due to being out of sync and allow future overrides */ + else if (seqhead == desclist) + { + override = TRUE; + UML_HASH(block, mode, seqhead->pc); // hash mode,pc + } + + /* otherwise, redispatch to that fixed PC and skip the rest of the processing */ + else + { + UML_LABEL(block, seqhead->pc | 0x80000000); // label seqhead->pc | 0x80000000 + UML_HASHJMP(block, m_core->mode, seqhead->pc, *m_nocode); + // hashjmp ,seqhead->pc,nocode + continue; + } + + /* validate this code block if we're not pointing into ROM */ + if (m_program->get_write_ptr(seqhead->physpc) != NULL) + generate_checksum_block(block, &compiler, seqhead, seqlast); // + + /* label this instruction, if it may be jumped to locally */ + if (seqhead->flags & OPFLAG_IS_BRANCH_TARGET) + UML_LABEL(block, seqhead->pc | 0x80000000); // label seqhead->pc | 0x80000000 + + /* iterate over instructions in the sequence and compile them */ + for (curdesc = seqhead; curdesc != seqlast->next(); curdesc = curdesc->next()) + generate_sequence_instruction(block, &compiler, curdesc); // + + /* if we need to return to the start, do it */ + if (seqlast->flags & OPFLAG_RETURN_TO_START) + nextpc = pc; + + /* otherwise we just go to the next instruction */ + else + nextpc = seqlast->pc + (seqlast->skipslots + 1) * 4; + + /* count off cycles and go there */ + generate_update_cycles(block, &compiler, nextpc, TRUE); // + + /* if the last instruction can change modes, use a variable mode; otherwise, assume the same mode */ + if (seqlast->flags & OPFLAG_CAN_CHANGE_MODES) + UML_HASHJMP(block, mem(&m_core->mode), nextpc, *m_nocode);// hashjmp ,nextpc,nocode + else if (seqlast->next() == NULL || seqlast->next()->pc != nextpc) + UML_HASHJMP(block, m_core->mode, nextpc, *m_nocode);// hashjmp ,nextpc,nocode + } + + /* end the sequence */ + block->end(); + g_profiler.stop(); + succeeded = true; + } + catch (drcuml_block::abort_compilation &) + { + // flush the cache and try again + code_flush_cache(); + } + } +} + + + +/*************************************************************************** + C FUNCTION CALLBACKS +***************************************************************************/ + +/*------------------------------------------------- + cfunc_printf_exception - log any exceptions that + aren't interrupts +-------------------------------------------------*/ + +static void cfunc_printf_exception(void *param) +{ + ppc_device *ppc = (ppc_device *)param; + ppc->ppc_cfunc_printf_exception(); +} + +void ppc_device::ppc_cfunc_printf_exception() +{ + printf("Exception: type=%2d EPC=%08X MSR=%08X\n", m_core->param0, m_core->spr[SPROEA_SRR0], m_core->spr[SPROEA_SRR1]); + ppc_cfunc_printf_probe(); +} + + +/*------------------------------------------------- + cfunc_printf_debug - generic printf for + debugging +-------------------------------------------------*/ + +static void cfunc_printf_debug(void *param) +{ + ppc_device *ppc = (ppc_device *)param; + ppc->ppc_cfunc_printf_debug(); +} + +void ppc_device::ppc_cfunc_printf_debug() +{ + printf(m_core->format, m_core->arg0, m_arg1); +} + + +/*------------------------------------------------- + cfunc_printf_probe - print the current CPU + state and return +-------------------------------------------------*/ + +static void cfunc_printf_probe(void *param) +{ + ppc_device *ppc = (ppc_device *)param; + ppc->ppc_cfunc_printf_probe(); +} + +void ppc_device::ppc_cfunc_printf_probe() +{ + printf(" PC=%08X\n", m_core->pc); + printf(" r0=%08X r1=%08X r2=%08X r3=%08X\n", + m_core->r[0], m_core->r[1], m_core->r[2], m_core->r[3]); + printf(" r4=%08X r5=%08X r6=%08X r7=%08X\n", + m_core->r[4], m_core->r[5], m_core->r[6], m_core->r[7]); + printf(" r8=%08X r9=%08X r10=%08X r11=%08X\n", + m_core->r[8], m_core->r[9], m_core->r[10], m_core->r[11]); + printf("r12=%08X r13=%08X r14=%08X r15=%08X\n", + m_core->r[12], m_core->r[13], m_core->r[14], m_core->r[15]); + printf("r16=%08X r17=%08X r18=%08X r19=%08X\n", + m_core->r[16], m_core->r[17], m_core->r[18], m_core->r[19]); + printf("r20=%08X r21=%08X r22=%08X r23=%08X\n", + m_core->r[20], m_core->r[21], m_core->r[22], m_core->r[23]); + printf("r24=%08X r25=%08X r26=%08X r27=%08X\n", + m_core->r[24], m_core->r[25], m_core->r[26], m_core->r[27]); + printf("r28=%08X r29=%08X r30=%08X r31=%08X\n", + m_core->r[28], m_core->r[29], m_core->r[30], m_core->r[31]); +} + + +/*------------------------------------------------- + cfunc_unimplemented - handler for + unimplemented opcdes +-------------------------------------------------*/ + +static void cfunc_unimplemented(void *param) +{ + ppc_device *ppc = (ppc_device *)param; + ppc->ppc_cfunc_unimplemented(); +} + +void ppc_device::ppc_cfunc_unimplemented() +{ + UINT32 opcode = m_core->arg0; + fatalerror("PC=%08X: Unimplemented op %08X\n", m_core->pc, opcode); +} + +static void cfunc_ppccom_tlb_fill(void *param) +{ + ppc_device *ppc = (ppc_device *)param; + ppc->ppccom_tlb_fill(); +} + +static void cfunc_ppccom_update_fprf(void *param) +{ + ppc_device *ppc = (ppc_device *)param; + ppc->ppccom_update_fprf(); +} + +static void cfunc_ppccom_dcstore_callback(void *param) +{ + ppc_device *ppc = (ppc_device *)param; + ppc->ppccom_dcstore_callback(); +} + +static void cfunc_ppccom_execute_tlbie(void *param) +{ + ppc_device *ppc = (ppc_device *)param; + ppc->ppccom_execute_tlbie(); +} + +static void cfunc_ppccom_execute_tlbia(void *param) +{ + ppc_device *ppc = (ppc_device *)param; + ppc->ppccom_execute_tlbia(); +} + +static void cfunc_ppccom_execute_tlbl(void *param) +{ + ppc_device *ppc = (ppc_device *)param; + ppc->ppccom_execute_tlbl(); +} + +static void cfunc_ppccom_execute_mfspr(void *param) +{ + ppc_device *ppc = (ppc_device *)param; + ppc->ppccom_execute_mfspr(); +} + +static void cfunc_ppccom_execute_mftb(void *param) +{ + ppc_device *ppc = (ppc_device *)param; + ppc->ppccom_execute_mftb(); +} + +static void cfunc_ppccom_execute_mtspr(void *param) +{ + ppc_device *ppc = (ppc_device *)param; + ppc->ppccom_execute_mtspr(); +} + +static void cfunc_ppccom_tlb_flush(void *param) +{ + ppc_device *ppc = (ppc_device *)param; + ppc->ppccom_tlb_flush(); +} + +static void cfunc_ppccom_execute_mfdcr(void *param) +{ + ppc_device *ppc = (ppc_device *)param; + ppc->ppccom_execute_mfdcr(); +} + +static void cfunc_ppccom_execute_mtdcr(void *param) +{ + ppc_device *ppc = (ppc_device *)param; + ppc->ppccom_execute_mtdcr(); +} + + +/*************************************************************************** + STATIC CODEGEN +***************************************************************************/ + +/*------------------------------------------------- + static_generate_entry_point - generate a + static entry point +-------------------------------------------------*/ + +void ppc_device::static_generate_entry_point() +{ + code_label skip = 1; + drcuml_block *block; + + /* begin generating */ + block = m_drcuml->begin_block(20); + + /* forward references */ + alloc_handle(m_drcuml, &m_nocode, "nocode"); + alloc_handle(m_drcuml, &m_exception_norecover[EXCEPTION_EI], "exception_ei_norecover"); + + alloc_handle(m_drcuml, &m_entry, "entry"); + UML_HANDLE(block, *m_entry); // handle entry + + /* reset the FPU mode */ + UML_AND(block, I0, FPSCR32, 3); // and i0,fpscr,3 + UML_LOAD(block, I0, &m_fpmode[0], I0, SIZE_BYTE, SCALE_x1); // load i0,fpmode,i0,byte + UML_SETFMOD(block, I0); // setfmod i0 + + /* load fast integer registers */ + load_fast_iregs(block); // + + /* check for interrupts */ + UML_TEST(block, mem(&m_core->irq_pending), ~0); // test [irq_pending],0 + UML_JMPc(block, COND_Z, skip); // jmp skip,Z + UML_TEST(block, MSR32, MSR_EE); // test msr,MSR_EE + UML_JMPc(block, COND_Z, skip); // jmp skip,Z + UML_MOV(block, I0, mem(&m_core->pc)); // mov i0,pc + UML_MOV(block, I1, 0); // mov i1,0 + UML_CALLH(block, *m_exception_norecover[EXCEPTION_EI]); // callh exception_norecover + UML_LABEL(block, skip); // skip: + + /* generate a hash jump via the current mode and PC */ + UML_HASHJMP(block, mem(&m_core->mode), mem(&m_core->pc), *m_nocode); // hashjmp ,,nocode + + block->end(); +} + + +/*------------------------------------------------- + static_generate_nocode_handler - generate an + exception handler for "out of code" +-------------------------------------------------*/ + +void ppc_device::static_generate_nocode_handler() +{ + drcuml_block *block; + + /* begin generating */ + block = m_drcuml->begin_block(10); + + /* generate a hash jump via the current mode and PC */ + alloc_handle(m_drcuml, &m_nocode, "nocode"); + UML_HANDLE(block, *m_nocode); // handle nocode + UML_GETEXP(block, I0); // getexp i0 + UML_MOV(block, mem(&m_core->pc), I0); // mov [pc],i0 + save_fast_iregs(block); // + UML_EXIT(block, EXECUTE_MISSING_CODE); // exit EXECUTE_MISSING_CODE + + block->end(); +} + + +/*------------------------------------------------- + static_generate_out_of_cycles - generate an + out of cycles exception handler +-------------------------------------------------*/ + +void ppc_device::static_generate_out_of_cycles() +{ + drcuml_block *block; + + /* begin generating */ + block = m_drcuml->begin_block(10); + + /* generate a hash jump via the current mode and PC */ + alloc_handle(m_drcuml, &m_out_of_cycles, "out_of_cycles"); + UML_HANDLE(block, *m_out_of_cycles); // handle out_of_cycles + UML_GETEXP(block, I0); // getexp i0 + UML_MOV(block, mem(&m_core->pc), I0); // mov ,i0 + save_fast_iregs(block); // + UML_EXIT(block, EXECUTE_OUT_OF_CYCLES); // exit EXECUTE_OUT_OF_CYCLES + + block->end(); +} + + +/*------------------------------------------------- + static_generate_tlb_mismatch - generate a + TLB mismatch handler +-------------------------------------------------*/ + +void ppc_device::static_generate_tlb_mismatch() +{ + drcuml_block *block; + int isi, exit, label = 1; + + /* forward references */ + alloc_handle(m_drcuml, &m_exception[EXCEPTION_ISI], "exception_isi"); + if (m_cap & PPCCAP_603_MMU) + alloc_handle(m_drcuml, &m_exception[EXCEPTION_ITLBMISS], "exception_itlb_miss"); + + /* begin generating */ + block = m_drcuml->begin_block(20); + + /* generate a hash jump via the current mode and PC */ + alloc_handle(m_drcuml, &m_tlb_mismatch, "tlb_mismatch"); + UML_HANDLE(block, *m_tlb_mismatch); // handle tlb_mismatch + UML_RECOVER(block, I0, MAPVAR_PC); // recover i0,PC + UML_SHR(block, I1, I0, 12); // shr i1,i0,12 + UML_LOAD(block, I2, (void *)vtlb_table(m_vtlb), I1, SIZE_DWORD, SCALE_x4); // load i2,[vtlb],i1,dword + UML_MOV(block, mem(&m_core->param0), I0); // mov [param0],i0 + UML_MOV(block, mem(&m_core->param1), TRANSLATE_FETCH); // mov [param1],TRANSLATE_FETCH + UML_CALLC(block, (c_function)cfunc_ppccom_tlb_fill, this); // callc tlbfill,ppc + UML_LOAD(block, I1, (void *)vtlb_table(m_vtlb), I1, SIZE_DWORD, SCALE_x4); // load i1,[vtlb],i1,dword + UML_TEST(block, I1, VTLB_FETCH_ALLOWED); // test i1,VTLB_FETCH_ALLOWED + UML_JMPc(block, COND_Z, isi = label++); // jmp isi,z + UML_CMP(block, I2, 0); // cmp i2,0 + UML_JMPc(block, COND_NZ, exit = label++); // jmp exit,nz + UML_HASHJMP(block, mem(&m_core->mode), I0, *m_nocode); // hashjmp ,i0,nocode + UML_LABEL(block, exit); // exit: + UML_MOV(block, mem(&m_core->pc), I0); // mov ,i0 + save_fast_iregs(block); // + UML_EXIT(block, EXECUTE_MISSING_CODE); // exit EXECUTE_MISSING_CODE + UML_LABEL(block, isi); // isi: + if (!(m_cap & PPCCAP_603_MMU)) + { + UML_MOV(block, SPR32(SPROEA_DSISR), mem(&m_core->param0)); // mov [dsisr],[param0] + UML_EXH(block, *m_exception[EXCEPTION_ISI], I0); // exh isi,i0 + } + else + { + UML_MOV(block, SPR32(SPR603_IMISS), I0); // mov [imiss],i0 + UML_MOV(block, SPR32(SPR603_ICMP), mem(&m_core->mmu603_cmp)); // mov [icmp],[mmu603_cmp] + UML_MOV(block, SPR32(SPR603_HASH1), mem(&m_core->mmu603_hash[0])); // mov [hash1],[mmu603_hash][0] + UML_MOV(block, SPR32(SPR603_HASH2), mem(&m_core->mmu603_hash[1])); // mov [hash2],[mmu603_hash][1] + UML_EXH(block, *m_exception[EXCEPTION_ITLBMISS], I0); // exh itlbmiss,i0 + } + + block->end(); +} + + +/*------------------------------------------------- + static_generate_exception - generate a static + exception handler +-------------------------------------------------*/ + +void ppc_device::static_generate_exception(UINT8 exception, int recover, const char *name) +{ + code_handle *&exception_handle = recover ? m_exception[exception] : m_exception_norecover[exception]; + UINT32 vector = exception << 8; + code_label label = 1; + drcuml_block *block; + + /* begin generating */ + block = m_drcuml->begin_block(1024); + + /* add a global entry for this */ + alloc_handle(m_drcuml, &exception_handle, name); + UML_HANDLE(block, *exception_handle); // handle name + + /* exception parameter is expected to be the fault address in this case */ + if (exception == EXCEPTION_ISI || exception == EXCEPTION_DSI) + { + UML_GETEXP(block, I0); // getexp i0 + UML_MOV(block, SPR32(SPROEA_DAR), I0); // mov [dar],i0 + } + + /* fetch the PC and uncounted cycles */ + if (recover) + { + UML_RECOVER(block, I0, MAPVAR_PC); // recover i0,PC + UML_RECOVER(block, I1, MAPVAR_CYCLES); // recover i1,CYCLES + } + + /* OEA handling of SRR exceptions */ + if (m_cap & PPCCAP_OEA) + { + UINT32 msrandmask = MSROEA_POW | MSR_EE | MSR_PR | MSROEA_FP | MSROEA_FE0 | MSROEA_SE | MSROEA_BE | MSROEA_FE1 | MSROEA_IR | MSROEA_DR | MSROEA_RI | MSR_LE; + UINT32 msrormask = 0; + + /* check registers to see the real source of our exception (EI exceptions only) */ + UML_MOV(block, I3, vector); // mov i3,vector + if (exception == EXCEPTION_EI) + { + code_label not_decrementer; + + UML_TEST(block, mem(&m_core->irq_pending), 0x01); // test [irq_pending],0x01 + UML_JMPc(block, COND_NZ, not_decrementer = label++); // jmp not_decrementer,nz + UML_MOV(block, I3, EXCEPTION_DECREMENT << 8); // mov i3,EXCEPTION_DECREMENT << 8 + UML_AND(block, mem(&m_core->irq_pending), mem(&m_core->irq_pending), ~0x02); // and [irq_pending],[irq_pending],~0x02 + UML_LABEL(block, not_decrementer); // not_decrementer: + } + + /* exception PC goes into SRR0 */ + UML_MOV(block, SPR32(SPROEA_SRR0), I0); // mov [srr0],i0 + + /* MSR bits go into SRR1, along with some exception-specific data */ + UML_AND(block, SPR32(SPROEA_SRR1), MSR32, 0x87c0ffff); // and [srr1],[msr],0x87c0ffff + if (exception == EXCEPTION_PROGRAM) + { + UML_GETEXP(block, I1); // getexp i1 + UML_OR(block, SPR32(SPROEA_SRR1), SPR32(SPROEA_SRR1), I1); // or [srr1],[srr1],i1 + } + if (m_cap & PPCCAP_603_MMU) + { + if (exception == EXCEPTION_ITLBMISS) + UML_OR(block, SPR32(SPROEA_SRR1), SPR32(SPROEA_SRR1), 0x00040000); // or [srr1],0x00040000 + else if (exception == EXCEPTION_DTLBMISSL) + UML_OR(block, SPR32(SPROEA_SRR1), SPR32(SPROEA_SRR1), 0x00010000); // or [srr1],0x00010000 + if (exception == EXCEPTION_ITLBMISS || exception == EXCEPTION_DTLBMISSL || exception == EXCEPTION_DTLBMISSS) + UML_ROLINS(block, SPR32(SPROEA_SRR1), CR32(0), 28, CRMASK(0)); // rolins [srr1],[cr0],28,crmask(0) + } + + /* update MSR */ + if (m_cap & PPCCAP_603_MMU) + { + if (exception == EXCEPTION_ITLBMISS || exception == EXCEPTION_DTLBMISSL || exception == EXCEPTION_DTLBMISSS) + msrormask |= MSR603_TGPR; + else + msrandmask |= MSR603_TGPR; + UML_MOV(block, I0, MSR32); // mov i0,[msr] + } + UML_AND(block, I2, MSR32, ~msrandmask); // and i2,[msr],~andmask + UML_OR(block, I2, I2, msrormask); // or i2,i2,ormask + UML_ROLINS(block, I2, I2, 16, MSR_LE); // rolins i2,u2,16,MSR_LE + UML_MOV(block, MSR32, I2); // mov [msr],i2 + if (m_cap & PPCCAP_603_MMU) + { + UML_XOR(block, I0, I0, I2); // xor i0,i0,i2 + UML_TEST(block, I0, MSR603_TGPR); // test i0,tgpr + UML_CALLHc(block, COND_NZ, *m_swap_tgpr); // callh swap_tgpr,nz + } + generate_update_mode(block); // + + /* determine our target PC */ + if (m_flavor == PPC_MODEL_602) + UML_MOV(block, I0, SPR32(SPR602_IBR)); // mov i0,[ibr] + else + UML_MOV(block, I0, 0x00000000); // mov i0,0x00000000 + UML_TEST(block, MSR32, MSROEA_IP); // test [msr],IP + UML_MOVc(block, COND_NZ, I0, 0xfff00000); // mov i0,0xfff00000,nz + UML_OR(block, I0, I0, I3); // or i0,i0,i3 + } + + /* 4XX handling of exceptions */ + if (m_cap & PPCCAP_4XX) + { + /* check registers to see the real source of our exception (EI exceptions only) */ + UML_MOV(block, I3, vector); // mov i3,vector + if (exception == EXCEPTION_EI) + { + code_label notwdog, common; + + UML_TEST(block, SPR32(SPR4XX_TSR), PPC4XX_TSR_PIS); // test [tsr],PIS + UML_MOVc(block, COND_NZ, I3, 0x1000); // mov i3,0x1000,NZ + UML_TEST(block, SPR32(SPR4XX_TSR), PPC4XX_TSR_FIS); // test [tsr],FIS + UML_MOVc(block, COND_NZ, I3, 0x1010); // mov i3,0x1010,NZ + UML_TEST(block, SPR32(DCR4XX_EXISR), SPR32(DCR4XX_EXIER)); // test [exisr],[exier] + UML_MOVc(block, COND_NZ, I3, vector); // mov i3,vector,NZ + UML_TEST(block, SPR32(SPR4XX_TSR), PPC4XX_TSR_WIS); // test [tsr],WIS + UML_JMPc(block, COND_Z, notwdog = label++); // jz notwdog + UML_MOV(block, I3, 0x1020); // mov i3,0x1020 + + /* exception PC goes into SRR2, MSR goes to SRR3 */ + UML_MOV(block, SPR32(SPR4XX_SRR2), I0); // mov [srr2],i0 + UML_MOV(block, SPR32(SPR4XX_SRR3), MSR32); // mov [srr3],[msr] + UML_AND(block, I2, MSR32, ~(MSR4XX_WE | MSR_PR | MSR4XX_CE | MSR_EE | MSR4XX_DE | MSR4XX_PE)); + UML_JMP(block, common = label++); // jmp common + + /* exception PC goes into SRR0, MSR goes to SRR1 */ + UML_LABEL(block, notwdog); // notwdog: + UML_MOV(block, SPR32(SPR4XX_SRR0), I0); // mov [srr0],i0 + UML_MOV(block, SPR32(SPR4XX_SRR1), MSR32); // mov [srr1],[msr] + UML_AND(block, I2, MSR32, ~(MSR4XX_WE | MSR_PR | MSR_EE | MSR4XX_PE));// and i2,[msr],~(bunch-o-flags) + UML_LABEL(block, common); // common: + } + else + { + /* exception PC goes into SRR0, MSR goes to SRR1 */ + UML_MOV(block, SPR32(SPR4XX_SRR0), I0); // mov [srr0],i0 + UML_MOV(block, SPR32(SPR4XX_SRR1), MSR32); // mov [srr1],[msr] + UML_AND(block, I2, MSR32, ~(MSR4XX_WE | MSR_PR | MSR_EE | MSR4XX_PE));// and i2,[msr],~(bunch-o-flags) + } + + /* finish updating MSR */ + UML_ROLINS(block, I2, I2, 16, MSR_LE); // rolins i2,u2,16,MSR_LE + UML_MOV(block, MSR32, I2); // mov [msr],i2 + generate_update_mode(block); // + + /* program exception flags go to ESR */ + if (exception == EXCEPTION_PROGRAM) + { + UML_GETEXP(block, I1); // getexp i1 + UML_SHL(block, SPR32(SPR4XX_ESR), I1, 8); // shl [esr],i1,8 + } + + /* determine our target PC */ + UML_ROLINS(block, I3, SPR32(SPR4XX_EVPR), 0, 0xffff0000); // rolins i3,[evpr],0,0xffff0000 + UML_MOV(block, I0, I3); // mov i0,i3 + } + + /* optionally print exceptions */ + if ((PRINTF_EXCEPTIONS && exception != EXCEPTION_EI && exception != EXCEPTION_SYSCALL) || + (PRINTF_MMU && (exception == EXCEPTION_ISI || exception == EXCEPTION_DSI))) + { + UML_MOV(block, mem(&m_core->param0), exception); // mov [param0],exception + UML_CALLC(block, cfunc_printf_exception, this); // callc cfunc_printf_exception,ppc + } + + /* adjust cycles */ + UML_SUB(block, mem(&m_core->icount), mem(&m_core->icount), I1); // sub icount,icount,cycles + UML_EXHc(block, COND_S, *m_out_of_cycles, I0); // exh out_of_cycles,i0 + UML_HASHJMP(block, mem(&m_core->mode), I0, *m_nocode); // hashjmp ,i0,nocode + + block->end(); +} + + +/*------------------------------------------------------------------ + static_generate_memory_accessor +------------------------------------------------------------------*/ + +void ppc_device::static_generate_memory_accessor(int mode, int size, int iswrite, int ismasked, const char *name, code_handle *&handleptr, code_handle *masked) +{ + /* on entry, address is in I0; data for writes is in I1; masks are in I2 */ + /* on exit, read result is in I0 */ + /* routine trashes I0-I3 */ + int fastxor = BYTE8_XOR_BE(0) >> (int)(space_config(AS_PROGRAM)->m_databus_width < 64); + drcuml_block *block; + int translate_type; + int tlbreturn = 0; + int unaligned = 0; + int alignex = 0; + int tlbmiss = 0; + int label = 1; + int ramnum; + + if (mode & MODE_USER) + translate_type = iswrite ? TRANSLATE_WRITE_USER : TRANSLATE_READ_USER; + else + translate_type = iswrite ? TRANSLATE_WRITE : TRANSLATE_READ; + + /* begin generating */ + block = m_drcuml->begin_block(1024); + + /* add a global entry for this */ + alloc_handle(m_drcuml, &handleptr, name); + UML_HANDLE(block, *handleptr); // handle *handleptr + + /* check for unaligned accesses and break into two */ + if (!ismasked && size != 1) + { + /* in little-endian mode, anything misaligned generates an exception */ + if ((mode & MODE_LITTLE_ENDIAN) || masked == NULL || !(m_cap & PPCCAP_MISALIGNED)) + { + UML_TEST(block, I0, size - 1); // test i0,size-1 + UML_JMPc(block, COND_NZ, alignex = label++); // jmp alignex,nz + } + + /* in big-endian mode, it's more complicated */ + else + { + /* 8-byte accesses must be word-aligned */ + if (size == 8) + { + UML_TEST(block, I0, 3); // test i0,3 + UML_JMPc(block, COND_NZ, alignex = label++); // jmp alignex,nz + + /* word aligned accesses need to be broken up */ + UML_TEST(block, I0, 4); // test i0,4 + UML_JMPc(block, COND_NZ, unaligned = label++); // jmp unaligned, nz + } + + /* unaligned 2 and 4 byte accesses need to be broken up */ + else + { + UML_TEST(block, I0, size - 1); // test i0,size-1 + UML_JMPc(block, COND_NZ, unaligned = label++); // jmp unaligned,nz + } + } + } + + /* general case: assume paging and perform a translation */ + if (((m_cap & PPCCAP_OEA) && (mode & MODE_DATA_TRANSLATION)) || (iswrite && (m_cap & PPCCAP_4XX) && (mode & MODE_PROTECTION))) + { + UML_SHR(block, I3, I0, 12); // shr i3,i0,12 + UML_LOAD(block, I3, (void *)vtlb_table(m_vtlb), I3, SIZE_DWORD, SCALE_x4);// load i3,[vtlb],i3,dword + UML_TEST(block, I3, (UINT64)1 << translate_type); // test i3,1 << translate_type + UML_JMPc(block, COND_Z, tlbmiss = label++); // jmp tlbmiss,z + UML_LABEL(block, tlbreturn = label++); // tlbreturn: + UML_ROLINS(block, I0, I3, 0, 0xfffff000); // rolins i0,i3,0,0xfffff000 + } + else if (m_cap & PPCCAP_4XX) + UML_AND(block, I0, I0, 0x7fffffff); // and i0,i0,0x7fffffff + UML_XOR(block, I0, I0, (mode & MODE_LITTLE_ENDIAN) ? (8 - size) : 0); // xor i0,i0,8-size + + if ((machine().debug_flags & DEBUG_FLAG_ENABLED) != 0) + for (ramnum = 0; ramnum < PPC_MAX_FASTRAM; ramnum++) + if (m_fastram[ramnum].base != NULL && (!iswrite || !m_fastram[ramnum].readonly)) + { + void *fastbase = (UINT8 *)m_fastram[ramnum].base - m_fastram[ramnum].start; + UINT32 skip = label++; + + if (m_fastram[ramnum].end != 0xffffffff) + { + UML_CMP(block, I0, m_fastram[ramnum].end); // cmp i0,end + UML_JMPc(block, COND_A, skip); // ja skip + } + if (m_fastram[ramnum].start != 0x00000000) + { + UML_CMP(block, I0, m_fastram[ramnum].start); // cmp i0,fastram_start + UML_JMPc(block, COND_B, skip); // jb skip + } + + if (!iswrite) + { + if (size == 1) + { + UML_XOR(block, I0, I0, fastxor & 7); // xor i0,i0,fastxor & 7 + UML_LOAD(block, I0, fastbase, I0, SIZE_BYTE, SCALE_x1); // load i0,fastbase,i0,byte + } + else if (size == 2) + { + UML_XOR(block, I0, I0, fastxor & 6); // xor i0,i0,fastxor & 6 + UML_LOAD(block, I0, fastbase, I0, SIZE_WORD, SCALE_x1); // load i0,fastbase,i0,word_x1 + } + else if (size == 4) + { + UML_XOR(block, I0, I0, fastxor & 4); // xor i0,i0,fastxor & 4 + UML_LOAD(block, I0, fastbase, I0, SIZE_DWORD, SCALE_x1); // load i0,fastbase,i0,dword_x1 + } + else if (size == 8) + { + UML_DLOAD(block, I0, fastbase, I0, SIZE_QWORD, SCALE_x1); // dload i0,fastbase,i0,qword + } + UML_RET(block); // ret + } + else + { + if (size == 1) + { + UML_XOR(block, I0, I0, fastxor & 7); // xor i0,i0,fastxor & 7 + UML_STORE(block, fastbase, I0, I1, SIZE_BYTE, SCALE_x1); // store fastbase,i0,i1,byte + } + else if (size == 2) + { + UML_XOR(block, I0, I0, fastxor & 6); // xor i0,i0,fastxor & 6 + UML_STORE(block, fastbase, I0, I1, SIZE_WORD, SCALE_x1); // store fastbase,i0,i1,word_x1 + } + else if (size == 4) + { + UML_XOR(block, I0, I0, fastxor & 4); // xor i0,i0,fastxor & 4 + if (ismasked) + { + UML_LOAD(block, I3, fastbase, I0, SIZE_DWORD, SCALE_x1); // load i3,fastbase,i0,dword_x1 + UML_AND(block, I1, I1, I2); // and i1,i1,i2 + UML_XOR(block, I2, I2, 0xffffffff); // xor i2,i2,0xfffffffff + UML_AND(block, I3, I3, I2); // and i3,i3,i2 + UML_OR(block, I1, I1, I3); // or i1,i1,i3 + } + UML_STORE(block, fastbase, I0, I1, SIZE_DWORD, SCALE_x1); // store fastbase,i0,i1,dword_x1 + } + else if (size == 8) + { + if (ismasked) + { + UML_DLOAD(block, I3, fastbase, I0, SIZE_QWORD, SCALE_x1); // dload i3,fastbase,i0,qword_x1 + UML_DAND(block, I1, I1, I2); // dand i1,i1,i2 + UML_DXOR(block, I2, I2, U64(0xffffffffffffffff)); // dxor i2,i2,0xfffffffffffffffff + UML_DAND(block, I3, I3, I2); // dand i3,i3,i2 + UML_DOR(block, I1, I1, I3); // dor i1,i1,i3 + } + UML_DSTORE(block, fastbase, I0, I1, SIZE_QWORD, SCALE_x1); // dstore fastbase,i0,i1,qword_x1 + } + UML_RET(block); // ret + } + + UML_LABEL(block, skip); // skip: + } + + switch (size) + { + case 1: + if (iswrite) + UML_WRITE(block, I0, I1, SIZE_BYTE, SPACE_PROGRAM); // write i0,i1,program_byte + else + UML_READ(block, I0, I0, SIZE_BYTE, SPACE_PROGRAM); // read i0,i0,program_byte + break; + + case 2: + if (iswrite) + { + if (!ismasked) + UML_WRITE(block, I0, I1, SIZE_WORD, SPACE_PROGRAM); // write i0,i1,program_word + else + UML_WRITEM(block, I0, I1, I2, SIZE_WORD, SPACE_PROGRAM); // writem i0,i2,i1,program_word + } + else + { + if (!ismasked) + UML_READ(block, I0, I0, SIZE_WORD, SPACE_PROGRAM); // read i0,i0,program_word + else + UML_READM(block, I0, I0, I2, SIZE_WORD, SPACE_PROGRAM); // readm i0,i0,i2,program_word + } + break; + + case 4: + if (iswrite) + { + if (!ismasked) + UML_WRITE(block, I0, I1, SIZE_DWORD, SPACE_PROGRAM); // write i0,i1,program_dword + else + UML_WRITEM(block, I0, I1, I2, SIZE_DWORD, SPACE_PROGRAM); // writem i0,i2,i1,program_dword + } + else + { + if (!ismasked) + UML_READ(block, I0, I0, SIZE_DWORD, SPACE_PROGRAM); // read i0,i0,program_dword + else + UML_READM(block, I0, I0, I2, SIZE_DWORD, SPACE_PROGRAM); // readm i0,i0,i2,program_dword + } + break; + + case 8: + if (iswrite) + { + if (!ismasked) + UML_DWRITE(block, I0, I1, SIZE_QWORD, SPACE_PROGRAM); // dwrite i0,i1,program_qword + else + UML_DWRITEM(block, I0, I1, I2, SIZE_QWORD, SPACE_PROGRAM); // dwritem i0,i2,i1,program_qword + } + else + { + if (!ismasked) + UML_DREAD(block, I0, I0, SIZE_QWORD, SPACE_PROGRAM); // dread i0,i0,program_qword + else + UML_DREADM(block, I0, I0, I2, SIZE_QWORD, SPACE_PROGRAM); // dreadm i0,i0,i2,program_qword + } + break; + } + UML_RET(block); // ret + + /* handle unaligned accesses */ + if (unaligned != 0) + { + UML_LABEL(block, unaligned); // unaligned: + if (size == 2) + { + if (iswrite) + { + UML_MOV(block, mem(&m_core->tempaddr), I0); // mov [tempaddr],i0 + UML_MOV(block, mem(&m_core->tempdata.w.l), I1); // mov [tempdata],i1 + UML_SUB(block, I0, I0, 1); // sub i0,i0,1 + UML_SHR(block, I1, I1, 8); // shr i1,i1,8 + UML_MOV(block, I2, 0x00ff); // mov i2,0x00ff + UML_CALLH(block, *masked); // callh masked + UML_ADD(block, I0, mem(&m_core->tempaddr), 1); // add i0,[tempaddr],1 + UML_SHL(block, I1, mem(&m_core->tempdata.w.l), 8); // shl i1,[tempdata],8 + UML_MOV(block, I2, 0xff00); // mov i2,0xff00 + UML_CALLH(block, *masked); // callh masked + } + else + { + UML_MOV(block, mem(&m_core->tempaddr), I0); // mov [tempaddr],i0 + UML_SUB(block, I0, I0, 1); // sub i0,i0,1 + UML_MOV(block, I2, 0x00ff); // mov i2,0x00ff + UML_CALLH(block, *masked); // callh masked + UML_SHL(block, mem(&m_core->tempdata.w.l), I0, 8); // shl [tempdata],i0,8 + UML_ADD(block, I0, mem(&m_core->tempaddr), 1); // add i0,[tempaddr],1 + UML_MOV(block, I2, 0xff00); // mov i2,0xff00 + UML_CALLH(block, *masked); // callh masked + UML_SHR(block, I0, I0, 8); // shr i0,i0,8 + UML_OR(block, I0, I0, mem(&m_core->tempdata.w.l)); // or i0,i0,[tempdata] + } + } + else if (size == 4) + { + int offs2, offs3; + if (iswrite) + { + UML_MOV(block, mem(&m_core->tempaddr), I0); // mov [tempaddr],i0 + UML_MOV(block, mem(&m_core->tempdata.w.l), I1); // mov [tempdata],i1 + UML_TEST(block, I0, 2); // test i0,i0,2 + UML_JMPc(block, COND_NZ, offs2 = label++); // jnz offs2 + UML_SUB(block, I0, I0, 1); // sub i0,i0,1 + UML_SHR(block, I1, I1, 8); // shr i1,i1,8 + UML_MOV(block, I2, 0x00ffffff); // mov i2,0x00ffffff + UML_CALLH(block, *masked); // callh masked + UML_ADD(block, I0, mem(&m_core->tempaddr), 3); // add i0,[tempaddr],3 + UML_SHL(block, I1, mem(&m_core->tempdata.w.l), 24); // shl i1,[tempdata],24 + UML_MOV(block, I2, 0xff000000); // mov i2,0xff000000 + UML_CALLH(block, *masked); // callh masked + UML_RET(block); // ret + UML_LABEL(block, offs2); // offs2: + UML_TEST(block, I0, 1); // test i0,i0,1 + UML_JMPc(block, COND_NZ, offs3 = label++); // jnz offs3 + UML_SUB(block, I0, I0, 2); // sub i0,i0,2 + UML_SHR(block, I1, I1, 16); // shr i1,i1,16 + UML_MOV(block, I2, 0x0000ffff); // mov i2,0x0000ffff + UML_CALLH(block, *masked); // callh masked + UML_ADD(block, I0, mem(&m_core->tempaddr), 2); // add i0,[tempaddr],2 + UML_SHL(block, I1, mem(&m_core->tempdata.w.l), 16); // shl i1,[tempdata],16 + UML_MOV(block, I2, 0xffff0000); // mov i2,0xffff0000 + UML_CALLH(block, *masked); // callh masked + UML_RET(block); // ret + UML_LABEL(block, offs3); // offs3: + UML_SUB(block, I0, I0, 3); // sub i0,i0,3 + UML_SHR(block, I1, I1, 24); // shr i1,i1,24 + UML_MOV(block, I2, 0x000000ff); // mov i2,0x000000ff + UML_CALLH(block, *masked); // callh masked + UML_ADD(block, I0, mem(&m_core->tempaddr), 1); // add i0,[tempaddr],1 + UML_SHL(block, I1, mem(&m_core->tempdata.w.l), 8); // shl i1,[tempdata],8 + UML_MOV(block, I2, 0xffffff00); // mov i2,0xffffff00 + UML_CALLH(block, *masked); // callh masked + } + else + { + UML_MOV(block, mem(&m_core->tempaddr), I0); // mov [tempaddr],i0 + UML_TEST(block, I0, 2); // test i0,i0,2 + UML_JMPc(block, COND_NZ, offs2 = label++); // jnz offs2 + UML_SUB(block, I0, I0, 1); // sub i0,i0,1 + UML_MOV(block, I2, 0x00ffffff); // mov i2,0x00ffffff + UML_CALLH(block, *masked); // callh masked + UML_SHL(block, mem(&m_core->tempdata.w.l), I0, 8); // shl [tempdata],i0,8 + UML_ADD(block, I0, mem(&m_core->tempaddr), 3); // add i0,[tempaddr],3 + UML_MOV(block, I2, 0xff000000); // mov i2,0xff000000 + UML_CALLH(block, *masked); // callh masked + UML_SHR(block, I0, I0, 24); // shr i0,i0,24 + UML_OR(block, I0, I0, mem(&m_core->tempdata.w.l)); // or i0,i0,[tempdata] + UML_RET(block); // ret + UML_LABEL(block, offs2); // offs2: + UML_TEST(block, I0, 1); // test i0,i0,1 + UML_JMPc(block, COND_NZ, offs3 = label++); // jnz offs3 + UML_SUB(block, I0, I0, 2); // sub i0,i0,2 + UML_MOV(block, I2, 0x0000ffff); // mov i2,0x0000ffff + UML_CALLH(block, *masked); // callh masked + UML_SHL(block, mem(&m_core->tempdata.w.l), I0, 16); // shl [tempdata],i0,16 + UML_ADD(block, I0, mem(&m_core->tempaddr), 2); // add i0,[tempaddr],2 + UML_MOV(block, I2, 0xffff0000); // mov i2,0xffff0000 + UML_CALLH(block, *masked); // callh masked + UML_SHR(block, I0, I0, 16); // shr i0,i0,16 + UML_OR(block, I0, I0, mem(&m_core->tempdata.w.l)); // or i0,i0,[tempdata] + UML_RET(block); // ret + UML_LABEL(block, offs3); // offs3: + UML_SUB(block, I0, I0, 3); // sub i0,i0,3 + UML_MOV(block, I2, 0x000000ff); // mov i2,0x000000ff + UML_CALLH(block, *masked); // callh masked + UML_SHL(block, mem(&m_core->tempdata.w.l), I0, 24); // shl [tempdata],i0,24 + UML_ADD(block, I0, mem(&m_core->tempaddr), 1); // add i0,[tempaddr],1 + UML_MOV(block, I2, 0xffffff00); // mov i2,0xffffff00 + UML_CALLH(block, *masked); // callh masked + UML_SHR(block, I0, I0, 8); // shr i0,i0,8 + UML_OR(block, I0, I0, mem(&m_core->tempdata.w.l)); // or i0,i0,[tempdata] + } + } + else if (size == 8) + { + if (iswrite) + { + UML_MOV(block, mem(&m_core->tempaddr), I0); // mov [tempaddr],i0 + UML_DMOV(block, mem(&m_core->tempdata.d), I1); // dmov [tempdata],i1 + UML_DSHR(block, I1, I1, 32); // dshr i1,i1,32 + UML_AND(block, I0, I0, ~7); // and i0,i0,~7 + UML_DMOV(block, I2, U64(0x00000000ffffffff)); // dmov i2,0x00000000ffffffff + UML_CALLH(block, *masked); // callh masked + UML_ADD(block, I0, mem(&m_core->tempaddr), 4); // add i0,[tempaddr],4 + UML_DSHL(block, I1, mem(&m_core->tempdata.d), 32); // dshl i1,[tempdata],32 + UML_DMOV(block, I2, U64(0xffffffff00000000)); // dmov i2,0xffffffff00000000 + UML_CALLH(block, *masked); // callh masked + } + else + { + UML_MOV(block, mem(&m_core->tempaddr), I0); // mov [tempaddr],i0 + UML_DMOV(block, I2, U64(0x00000000ffffffff)); // mov i2,0x00000000ffffffff + UML_AND(block, I0, I0, ~7); // and i0,i0,~7 + UML_CALLH(block, *masked); // callh masked + UML_DSHL(block, mem(&m_core->tempdata.d), I0, 32); // dshl [tempdata],i0,32 + UML_ADD(block, I0, mem(&m_core->tempaddr), 4); // add i0,[tempaddr],4 + UML_DMOV(block, I2, U64(0xffffffff00000000)); // dmov i2,0xffffffff00000000 + UML_CALLH(block, *masked); // callh masked + UML_DSHR(block, I0, I0, 32); // dshr i0,i0,32 + UML_DOR(block, I0, I0, mem(&m_core->tempdata.d)); // dor i0,i0,[tempdata] + } + } + UML_RET(block); // ret + } + + /* handle an alignment exception */ + if (alignex != 0) + { + UML_LABEL(block, alignex); // alignex: + UML_RECOVER(block, SPR32(SPROEA_DSISR), MAPVAR_DSISR); // recover [dsisr],DSISR + UML_EXH(block, *m_exception[EXCEPTION_ALIGN], I0); // exh align,i0 + } + + /* handle a TLB miss */ + if (tlbmiss != 0) + { + UML_LABEL(block, tlbmiss); // tlbmiss: + UML_MOV(block, mem(&m_core->param0), I0); // mov [param0],i0 + UML_MOV(block, mem(&m_core->param1), translate_type); // mov [param1],translate_type + UML_CALLC(block, (c_function)cfunc_ppccom_tlb_fill, this); // callc tlbfill,ppc + UML_SHR(block, I3, I0, 12); // shr i3,i0,12 + UML_LOAD(block, I3, (void *)vtlb_table(m_vtlb), I3, SIZE_DWORD, SCALE_x4);// load i3,[vtlb],i3,dword + UML_TEST(block, I3, (UINT64)1 << translate_type); // test i3,1 << translate_type + UML_JMPc(block, COND_NZ, tlbreturn); // jmp tlbreturn,nz + + /* 4XX case: protection exception */ + if (m_cap & PPCCAP_4XX) + { + UML_MOV(block, SPR32(SPR4XX_DEAR), I0); // mov [dear],i0 + UML_EXH(block, *m_exception[EXCEPTION_DSI], I0); // exh dsi,i0 + } + + /* 603 case: TLBMISS exception */ + else if (m_cap & PPCCAP_603_MMU) + { + UML_MOV(block, SPR32(SPR603_DMISS), I0); // mov [dmiss],i0 + UML_MOV(block, SPR32(SPR603_DCMP), mem(&m_core->mmu603_cmp)); // mov [dcmp],[mmu603_cmp] + UML_MOV(block, SPR32(SPR603_HASH1), mem(&m_core->mmu603_hash[0])); // mov [hash1],[mmu603_hash][0] + UML_MOV(block, SPR32(SPR603_HASH2), mem(&m_core->mmu603_hash[1])); // mov [hash2],[mmu603_hash][1] + if (iswrite) + UML_EXH(block, *m_exception[EXCEPTION_DTLBMISSS], I0); // exh dtlbmisss,i0 + else + UML_EXH(block, *m_exception[EXCEPTION_DTLBMISSL], I0); // exh dtlbmissl,i0 + } + + /* general case: DSI exception */ + else + { + UML_MOV(block, SPR32(SPROEA_DSISR), mem(&m_core->param0)); // mov [dsisr],[param0] + UML_EXH(block, *m_exception[EXCEPTION_DSI], I0); // exh dsi,i0 + } + } + + block->end(); +} + + +/*------------------------------------------------- + static_generate_swap_tgpr - generate a + subroutine to swap GPR0-3 with TGPR0-3 +-------------------------------------------------*/ + +void ppc_device::static_generate_swap_tgpr() +{ + drcuml_block *block; + int regnum; + + /* begin generating */ + block = m_drcuml->begin_block(30); + + /* generate a hash jump via the current mode and PC */ + alloc_handle(m_drcuml, &m_swap_tgpr, "swap_tgpr"); + UML_HANDLE(block, *m_swap_tgpr); // handle swap_tgpr + for (regnum = 0; regnum < 4; regnum++) + { + UML_MOV(block, I1, R32(regnum)); // mov i1,r[regnum] + UML_MOV(block, R32(regnum), mem(&m_core->mmu603_r[regnum])); // mov r[regnum],mmu603_r[regnum] + UML_MOV(block, mem(&m_core->mmu603_r[regnum]), I1); // mov mmu603_r[regnum],i1 + } + UML_RET(block); // ret + + block->end(); +} + + +/*------------------------------------------------- + static_generate_lsw_entries - generate a + subroutine to perform LSWI/LSWX; one handle + for each possible register +-------------------------------------------------*/ + +void ppc_device::static_generate_lsw_entries(int mode) +{ + drcuml_block *block; + int regnum; + + /* begin generating */ + block = m_drcuml->begin_block(32 * 30); + + /* iterate over all possible registers */ + for (regnum = 0; regnum < 32; regnum++) + { + char temp[20]; + + /* allocate a handle */ + sprintf(temp, "lsw%d", regnum); + alloc_handle(m_drcuml, &m_lsw[mode][regnum], temp); + UML_HANDLE(block, *m_lsw[mode][regnum]); // handle lsw + UML_LABEL(block, regnum); // regnum: + UML_ADD(block, I0, mem(&m_core->updateaddr), 0); // add i0,[updateaddr],0 + UML_CALLH(block, *m_read8[mode]); // callh read8 + UML_ROLAND(block, R32(regnum), I0, 24, 0xff000000); // roland reg,i0,24,0xff000000 + UML_SUB(block, mem(&m_core->swcount), mem(&m_core->swcount), 1); // sub [swcount],[swcount],1 + UML_RETc(block, COND_Z); // ret z + UML_ADD(block, I0, mem(&m_core->updateaddr), 1); // add i0,[updateaddr],1 + UML_CALLH(block, *m_read8[mode]); // callh read8 + UML_ROLAND(block, I0, I0, 16, 0x00ff0000); // roland i0,i0,16,0x00ff0000 + UML_OR(block, R32(regnum), R32(regnum), I0); // or reg,i0 + UML_SUB(block, mem(&m_core->swcount), mem(&m_core->swcount), 1); // sub [swcount],[swcount],1 + UML_RETc(block, COND_Z); // ret z + UML_ADD(block, I0, mem(&m_core->updateaddr), 2); // add i0,[updateaddr],2 + UML_CALLH(block, *m_read8[mode]); // callh read8 + UML_ROLAND(block, I0, I0, 8, 0x0000ff00); // roland i0,i0,8,0x0000ff00 + UML_OR(block, R32(regnum), R32(regnum), I0); // or reg,i0 + UML_SUB(block, mem(&m_core->swcount), mem(&m_core->swcount), 1); // sub [swcount],[swcount],1 + UML_RETc(block, COND_Z); // ret z + UML_ADD(block, I0, mem(&m_core->updateaddr), 3); // add i0,[updateaddr],3 + UML_ADD(block, mem(&m_core->updateaddr), I0, 1); // add [updateaddr],i0,1 + UML_CALLH(block, *m_read8[mode]); // callh read8 + UML_ROLAND(block, I0, I0, 0, 0x000000ff); // roland i0,i0,0,0x000000ff + UML_OR(block, R32(regnum), R32(regnum), I0); // or reg,i0 + UML_SUB(block, mem(&m_core->swcount), mem(&m_core->swcount), 1); // sub [swcount],[swcount],1 + UML_RETc(block, COND_Z); // ret z + UML_JMP(block, (regnum + 1) % 32); // jmp nextreg + } + + block->end(); +} + + +/*------------------------------------------------- + static_generate_stsw_entries - generate a + subroutine to perform LSWI/LSWX; one handle + for each possible register +-------------------------------------------------*/ + +void ppc_device::static_generate_stsw_entries(int mode) +{ + drcuml_block *block; + + /* begin generating */ + block = m_drcuml->begin_block(32 * 30); + + /* iterate over all possible registers */ + for (int regnum = 0; regnum < 32; regnum++) + { + char temp[20]; + + /* allocate a handle */ + sprintf(temp, "stsw%d", regnum); + alloc_handle(m_drcuml, &m_stsw[mode][regnum], temp); + UML_HANDLE(block, *m_stsw[mode][regnum]); // handle stsw + UML_LABEL(block, regnum); // regnum: + UML_ADD(block, I0, mem(&m_core->updateaddr), 0); // add i0,[updateaddr],0 + UML_ROLAND(block, I1, R32(regnum), 8, 0xff); // roland i1,regnum,8,0xff + UML_CALLH(block, *m_write8[mode]); // callh write8 + UML_SUB(block, mem(&m_core->swcount), mem(&m_core->swcount), 1); // sub [swcount],[swcount],1 + UML_RETc(block, COND_Z); // ret z + UML_ADD(block, I0, mem(&m_core->updateaddr), 1); // add i0,[updateaddr],1 + UML_ROLAND(block, I1, R32(regnum), 16, 0xff); // roland i1,regnum,16,0xff + UML_CALLH(block, *m_write8[mode]); // callh write8 + UML_SUB(block, mem(&m_core->swcount), mem(&m_core->swcount), 1); // sub [swcount],[swcount],1 + UML_RETc(block, COND_Z); // ret z + UML_ADD(block, I0, mem(&m_core->updateaddr), 2); // add i0,[updateaddr],2 + UML_ROLAND(block, I1, R32(regnum), 24, 0xff); // roland i1,regnum,24,0xff + UML_CALLH(block, *m_write8[mode]); // callh write8 + UML_SUB(block, mem(&m_core->swcount), mem(&m_core->swcount), 1); // sub [swcount],[swcount],1 + UML_RETc(block, COND_Z); // ret z + UML_ADD(block, I0, mem(&m_core->updateaddr), 3); // add i0,[updateaddr],3 + UML_ADD(block, mem(&m_core->updateaddr), I0, 1); // add [updateaddr],i0,1 + UML_ROLAND(block, I1, R32(regnum), 0, 0xff); // roland i1,regnum,0,0xff + UML_CALLH(block, *m_write8[mode]); // callh write8 + UML_SUB(block, mem(&m_core->swcount), mem(&m_core->swcount), 1); // sub [swcount],[swcount],1 + UML_RETc(block, COND_Z); // ret z + UML_JMP(block, (regnum + 1) % 32); // jmp nextreg + } + + block->end(); +} + + + +/*************************************************************************** + CODE GENERATION +***************************************************************************/ + +/*------------------------------------------------- + generate_update_mode - update the mode based + on the MSR +-------------------------------------------------*/ + +void ppc_device::generate_update_mode(drcuml_block *block) +{ + /* LE in bit 0 of mode */ + UML_AND(block, I0, MSR32, MSR_LE); // and i0,msr,MSR_LE + + /* DR (OEA and 403GCX) in bit 1 of mode */ + if ((m_cap & PPCCAP_OEA) || m_flavor == PPC_MODEL_403GCX) + { + UML_ROLAND(block, I1, MSR32, 29, 0x02); // roland i1,[msr],29,0x02 + UML_OR(block, I0, I0, I1); // or i0,i0,i1 + } + + /* (4XX) in bit 1 of mode */ + if (m_cap & PPCCAP_4XX) + { + UML_ROLAND(block, I1, MSR32, 30, 0x02); // roland i1,[msr],30,0x02 + UML_OR(block, I0, I0, I1); // or i0,i0,i1 + } + + /* PR in bit 2 of mode */ + UML_ROLAND(block, I1, MSR32, 20, 0x04); // roland i1,[msr],20,0x04 + UML_OR(block, mem(&m_core->mode), I0, I1); // or [mode],i0,i1 +} + + +/*------------------------------------------------- + generate_update_cycles - generate code to + subtract cycles from the icount and generate + an exception if out +-------------------------------------------------*/ + +void ppc_device::generate_update_cycles(drcuml_block *block, compiler_state *compiler, uml::parameter param, int allow_exception) +{ + /* check full interrupts if pending */ + if (compiler->checkints) + { + code_label skip; + + compiler->checkints = FALSE; + UML_TEST(block, mem(&m_core->irq_pending), ~0); // test [irq_pending],0 + UML_JMPc(block, COND_Z, skip = compiler->labelnum++); // jmp skip,Z + UML_TEST(block, MSR32, MSR_EE); // test [msr],MSR_EE + UML_JMPc(block, COND_Z, skip); // jmp skip,Z + UML_MOV(block, I0, param); // mov i0,nextpc + UML_MOV(block, I1, compiler->cycles); // mov i1,cycles + UML_CALLH(block, *m_exception_norecover[EXCEPTION_EI]); // callh interrupt_norecover + UML_LABEL(block, skip); // skip: + } + + /* account for cycles */ + if (compiler->cycles > 0) + { + UML_SUB(block, mem(&m_core->icount), mem(&m_core->icount), MAPVAR_CYCLES); // sub icount,icount,cycles + UML_MAPVAR(block, MAPVAR_CYCLES, 0); // mapvar cycles,0 + if (allow_exception) + UML_EXHc(block, COND_S, *m_out_of_cycles, param); // exh out_of_cycles,nextpc + } + compiler->cycles = 0; +} + + +/*------------------------------------------------- + generate_checksum_block - generate code to + validate a sequence of opcodes +-------------------------------------------------*/ + +void ppc_device::generate_checksum_block(drcuml_block *block, compiler_state *compiler, const opcode_desc *seqhead, const opcode_desc *seqlast) +{ + const opcode_desc *curdesc; + if (m_drcuml->logging()) + block->append_comment("[Validation for %08X]", seqhead->pc); // comment + + /* loose verify or single instruction: just compare and fail */ + if (!(m_drcoptions & PPCDRC_STRICT_VERIFY) || seqhead->next() == NULL) + { + if (!(seqhead->flags & OPFLAG_VIRTUAL_NOOP)) + { + void *base = m_direct->read_ptr(seqhead->physpc, m_codexor); + UML_LOAD(block, I0, base, 0, SIZE_DWORD, SCALE_x4); // load i0,base,dword + UML_CMP(block, I0, seqhead->opptr.l[0]); // cmp i0,*opptr + UML_EXHc(block, COND_NE, *m_nocode, seqhead->pc); // exne nocode,seqhead->pc + } + } + + /* full verification; sum up everything */ + else + { +#if 0 + for (curdesc = seqhead->next(); curdesc != seqlast->next(); curdesc = curdesc->next()) + if (!(curdesc->flags & OPFLAG_VIRTUAL_NOOP)) + { + void *base = m_direct->read_ptr(seqhead->physpc, m_codexor); + UML_LOAD(block, I0, base, 0, SIZE_DWORD, SCALE_x4); // load i0,base,dword + UML_CMP(block, I0, curdesc->opptr.l[0]); // cmp i0,*opptr + UML_EXHc(block, COND_NE, *m_nocode, seqhead->pc); // exne nocode,seqhead->pc + } +#else + UINT32 sum = 0; + void *base = m_direct->read_ptr(seqhead->physpc, m_codexor); + UML_LOAD(block, I0, base, 0, SIZE_DWORD, SCALE_x4); // load i0,base,dword + sum += seqhead->opptr.l[0]; + for (curdesc = seqhead->next(); curdesc != seqlast->next(); curdesc = curdesc->next()) + if (!(curdesc->flags & OPFLAG_VIRTUAL_NOOP)) + { + base = m_direct->read_ptr(curdesc->physpc, m_codexor); + UML_LOAD(block, I1, base, 0, SIZE_DWORD, SCALE_x4); // load i1,base,dword + UML_ADD(block, I0, I0, I1); // add i0,i0,i1 + sum += curdesc->opptr.l[0]; + } + UML_CMP(block, I0, sum); // cmp i0,sum + UML_EXHc(block, COND_NE, *m_nocode, seqhead->pc); // exne nocode,seqhead->pc +#endif + } +} + + +/*------------------------------------------------- + generate_sequence_instruction - generate code + for a single instruction in a sequence +-------------------------------------------------*/ + +void ppc_device::generate_sequence_instruction(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) +{ + int hotnum; + + /* add an entry for the log */ + if (m_drcuml->logging() && !(desc->flags & OPFLAG_VIRTUAL_NOOP)) + log_add_disasm_comment(block, desc->pc, desc->opptr.l[0]); + + /* set the PC map variable */ + UML_MAPVAR(block, MAPVAR_PC, desc->pc); // mapvar PC,desc->pc + + /* accumulate total cycles */ + compiler->cycles += desc->cycles; + + /* is this a hotspot? */ + for (hotnum = 0; hotnum < PPC_MAX_HOTSPOTS; hotnum++) + if (m_hotspot[hotnum].pc != 0 && desc->pc == m_hotspot[hotnum].pc && desc->opptr.l[0] == m_hotspot[hotnum].opcode) + { + compiler->cycles += m_hotspot[hotnum].cycles; + break; + } + + /* update the icount map variable */ + UML_MAPVAR(block, MAPVAR_CYCLES, compiler->cycles); // mapvar CYCLES,compiler->cycles + + /* if we want a probe, add it here */ + if (desc->pc == PROBE_ADDRESS) + { + UML_MOV(block, mem(&m_core->pc), desc->pc); // mov [pc],desc->pc + UML_CALLC(block, cfunc_printf_probe, (void *)(FPTR)desc->pc); // callc cfunc_printf_probe,desc->pc + } + + /* if we are debugging, call the debugger */ + if ((machine().debug_flags & DEBUG_FLAG_ENABLED) != 0) + { + UML_MOV(block, mem(&m_core->pc), desc->pc); // mov [pc],desc->pc + save_fast_iregs(block); // + UML_DEBUG(block, desc->pc); // debug desc->pc + } + + /* if we hit an unmapped address, fatal error */ + if (desc->flags & OPFLAG_COMPILER_UNMAPPED) + { + UML_MOV(block, mem(&m_core->pc), desc->pc); // mov [pc],desc->pc + save_fast_iregs(block); // + UML_EXIT(block, EXECUTE_UNMAPPED_CODE); // exit EXECUTE_UNMAPPED_CODE + } + + /* if we hit a compiler page fault, it's just like a TLB mismatch */ + if (desc->flags & OPFLAG_COMPILER_PAGE_FAULT) + { + if (PRINTF_MMU) + { + const char *text = "Compiler page fault @ %08X\n"; + UML_MOV(block, mem(&m_core->format), (FPTR)text); // mov [format],text + UML_MOV(block, mem(&m_core->arg0), desc->pc); // mov [arg0],desc->pc + UML_CALLC(block, cfunc_printf_debug, this); // callc printf_debug + } + UML_EXH(block, *m_tlb_mismatch, 0); // exh tlb_mismatch,0 + } + + /* validate our TLB entry at this PC; if we fail, we need to handle it */ + if ((desc->flags & OPFLAG_VALIDATE_TLB) && (m_core->mode & MODE_DATA_TRANSLATION)) + { + const vtlb_entry *tlbtable = vtlb_table(m_vtlb); + + /* if we currently have a valid TLB read entry, we just verify */ + if (tlbtable[desc->pc >> 12] != 0) + { + if (PRINTF_MMU) + { + const char *text = "Checking TLB at @ %08X\n"; + UML_MOV(block, mem(&m_core->format), (FPTR)text); // mov [format],text + UML_MOV(block, mem(&m_core->arg0), desc->pc); // mov [arg0],desc->pc + UML_CALLC(block, cfunc_printf_debug, this); // callc printf_debug + } + UML_LOAD(block, I0, &tlbtable[desc->pc >> 12], 0, SIZE_DWORD, SCALE_x4);// load i0,tlbtable[desc->pc >> 12],dword + UML_CMP(block, I0, tlbtable[desc->pc >> 12]); // cmp i0,*tlbentry + UML_EXHc(block, COND_NE, *m_tlb_mismatch, 0); // exh tlb_mismatch,0,NE + } + + /* otherwise, we generate an unconditional exception */ + else + { + if (PRINTF_MMU) + { + const char *text = "No valid TLB @ %08X\n"; + UML_MOV(block, mem(&m_core->format), (FPTR)text); // mov [format],text + UML_MOV(block, mem(&m_core->arg0), desc->pc); // mov [arg0],desc->pc + UML_CALLC(block, cfunc_printf_debug, this); // callc printf_debug + } + UML_EXH(block, *m_tlb_mismatch, 0); // exh tlb_mismatch,0 + } + } + + /* if this is an invalid opcode, generate the exception now */ + if (desc->flags & OPFLAG_INVALID_OPCODE) + UML_EXH(block, *m_exception[EXCEPTION_PROGRAM], 0x80000); // exh exception_program,0x80000 + + /* if this is a privileged opcode in user mode, generate the exception */ + else if ((desc->flags & OPFLAG_PRIVILEGED) && (m_core->mode & MODE_USER)) + UML_EXH(block, *m_exception[EXCEPTION_PROGRAM], 0x40000); // exh exception_program,0x40000 + + /* otherwise, unless this is a virtual no-op, it's a regular instruction */ + else if (!(desc->flags & OPFLAG_VIRTUAL_NOOP)) + { + /* compile the instruction */ + if (!generate_opcode(block, compiler, desc)) + { + UML_MOV(block, mem(&m_core->pc), desc->pc); // mov [pc],desc->pc + UML_MOV(block, mem(&m_core->arg0), desc->opptr.l[0]); // mov [arg0],*desc->opptr.l + UML_CALLC(block, cfunc_unimplemented, this); // callc cfunc_unimplemented,ppc + } + } +} + + +/*------------------------------------------------------------------ + generate_compute_flags - compute CR0 and/or XER flags +------------------------------------------------------------------*/ + +void ppc_device::generate_compute_flags(drcuml_block *block, const opcode_desc *desc, int updatecr, UINT32 xermask, int invertcarry) +{ + UINT32 xerflags; + + /* modify inputs based on required flags */ + if (!DISABLE_FLAG_OPTIMIZATIONS) + { + if (!(desc->regreq[3] & REGFLAG_XER_CA)) + xermask &= ~XER_CA; + if (!(desc->regreq[2] & REGFLAG_CR(0))) + updatecr = 0; + } + xerflags = ((xermask & XER_OV) ? FLAG_V : 0) | ((xermask & XER_CA) ? FLAG_C : 0); + + /* easy case: nothing to do */ + if (!updatecr && xermask == 0) + return; + + /* semi-easy case: crfield only */ + if (xermask == 0) + { + UML_GETFLGS(block, I0, FLAG_S | FLAG_Z); // getflgs i0,sz + UML_LOAD(block, I0, m_sz_cr_table, I0, SIZE_BYTE, SCALE_x1); // load i0,sz_cr_table,i0,byte + UML_OR(block, CR32(0), I0, XERSO32); // or [cr0],i0,[xerso] + return; + } + + /* semi-easy case: xer only */ + if (!updatecr) + { + if (xermask & XER_OV) + { + UML_GETFLGS(block, I0, xerflags); // getflgs i0,xerflags + if (invertcarry && (xermask & XER_CA)) + UML_XOR(block, I0, I0, FLAG_C); // xor i0,i0,FLAG_C + UML_ROLINS(block, SPR32(SPR_XER), I0, 29, xermask); // rolins [xer],i0,29,xermask + UML_SHR(block, I0, I0, 1); // shr i0,i0,1 + UML_OR(block, XERSO32, XERSO32, I0); // or [xerso],i0 + } + else + { + UML_SETc(block, invertcarry ? COND_NC : COND_C, I0); // setc i0,nc/c + UML_ROLINS(block, SPR32(SPR_XER), I0, 29, XER_CA); // rolins [xer],i0,29,XER_CA + } + return; + } + + /* tricky case: both */ + UML_GETFLGS(block, I0, FLAG_S | FLAG_Z | xerflags); // getflgs i0,SZ | xerflags + UML_LOAD(block, I1, m_sz_cr_table, I0, SIZE_BYTE, SCALE_x1); // load i1,sz_cr_table,i0,byte + if (invertcarry && (xermask & XER_CA)) + UML_XOR(block, I0, I0, FLAG_C); // xor i0,i0,FLAG_C + UML_ROLINS(block, SPR32(SPR_XER), I0, 29, xermask); // rolins [xer],i0,29,xermask + if (xermask & XER_OV) + { + UML_ROLAND(block, I0, I0, 31, 1); // roland i0,i0,31,0x0001 + UML_OR(block, XERSO32, XERSO32, I0); // or [xerso],i0 + UML_AND(block, CR32(0), CR32(0), 0xfffffffe); // and [cr0], [cr0], 0xfffffffe (clear SO copy in CR32) + UML_OR(block, CR32(0), I1, XERSO32); // or [cr0],i1,[xerso] + } + else + { + UML_AND(block, CR32(0), CR32(0), 0xfffffffe); // and [cr0], [cr0], 0xfffffffe (clear SO copy in CR32) + UML_OR(block, CR32(0), I1, XERSO32); // or [cr0],i1,[xerso] (OR in new value from XERSO) + } +} + +/*----------------------------------------------------- + generate_shift_flags - compute S/Z flags for shifts +-------------------------------------------------------*/ + +void ppc_device::generate_shift_flags(drcuml_block *block, const opcode_desc *desc, UINT32 op) +{ + UML_CMP(block, R32(G_RA(op)), 0); // cmp ra, #0 + UML_SETc(block, COND_Z, I1); // set Z, i1 + UML_SHL(block, I1, I1, 2); // shl i1, i1, #2 (i1 now = FLAG_Z) + + UML_SHR(block, I2, R32(G_RA(op)), 28); // shr i2, ra, #28 + UML_AND(block, I2, I2, FLAG_S); // and i2, i2, FLAG_S (i2 now = FLAG_S) + UML_OR(block, I1, I1, I2); // or i1, i1, i2 + UML_LOAD(block, I0, m_sz_cr_table, I1, SIZE_BYTE, SCALE_x1); // load i0,sz_cr_table,i0,byte + UML_OR(block, CR32(0), I0, XERSO32); // or [cr0],i0,[xerso] +} + +/*------------------------------------------------- + generate_fp_flags - compute FPSCR floating + point status flags +-------------------------------------------------*/ + +void ppc_device::generate_fp_flags(drcuml_block *block, const opcode_desc *desc, int updatefprf) +{ + /* for now, only handle the FPRF field */ + if (updatefprf) + { + UML_MOV(block, mem(&m_core->param0), G_RD(desc->opptr.l[0])); + UML_CALLC(block, (c_function)cfunc_ppccom_update_fprf, this); + } +} + +/*------------------------------------------------- + generate_branch - generate an unconditional + branch +-------------------------------------------------*/ + +void ppc_device::generate_branch(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, int source, UINT8 link) +{ + compiler_state compiler_temp = *compiler; + UINT32 *srcptr = &m_core->spr[source]; + + /* set the link if needed */ + if (link) + { + if (desc->targetpc == BRANCH_TARGET_DYNAMIC && source == SPR_LR) + { + UML_MOV(block, mem(&m_core->tempaddr), mem(srcptr)); // mov [tempaddr],[lr] + srcptr = &m_core->tempaddr; + } + UML_MOV(block, SPR32(SPR_LR), desc->pc + 4); // mov [lr],desc->pc + 4 + } + + /* update the cycles and jump through the hash table to the target */ + if (desc->targetpc != BRANCH_TARGET_DYNAMIC) + { + generate_update_cycles(block, &compiler_temp, desc->targetpc, TRUE); // + if (desc->flags & OPFLAG_INTRABLOCK_BRANCH) + UML_JMP(block, desc->targetpc | 0x80000000); // jmp desc->targetpc | 0x80000000 + else + UML_HASHJMP(block, m_core->mode, desc->targetpc, *m_nocode); + // hashjmp ,desc->targetpc,nocode + } + else + { + generate_update_cycles(block, &compiler_temp, mem(srcptr), TRUE); // + UML_HASHJMP(block, m_core->mode, mem(srcptr), *m_nocode); // hashjmp ,,nocode + } + + /* update the label */ + compiler->labelnum = compiler_temp.labelnum; + + /* reset the mapvar to the current cycles */ + UML_MAPVAR(block, MAPVAR_CYCLES, compiler->cycles); // mapvar CYCLES,compiler->cycles +} + + +/*------------------------------------------------- + generate_branch_bo - generate a conditional + branch based on the BO and BI fields +-------------------------------------------------*/ + +void ppc_device::generate_branch_bo(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, UINT32 bo, UINT32 bi, int source, int link) +{ + int skip = compiler->labelnum++; + + if (!(bo & 0x04)) + { + UML_SUB(block, SPR32(SPR_CTR), SPR32(SPR_CTR), 1); // sub [ctr],[ctr],1 + UML_JMPc(block, (bo & 0x02) ? COND_NZ : COND_Z, skip); // jmp skip,nz/z + } + if (!(bo & 0x10)) + { + UML_TEST(block, CR32(bi / 4), 8 >> (bi % 4)); // test cr32(bi/4),8 >> (bi % 4) + UML_JMPc(block, (bo & 0x08) ? COND_Z : COND_NZ, skip); // jmp skip,z/nz + } + generate_branch(block, compiler, desc, source, link); // + UML_LABEL(block, skip); // skip: +} + + +/*------------------------------------------------- + generate_opcode - generate code for a specific + opcode +-------------------------------------------------*/ + +int ppc_device::generate_opcode(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) +{ + UINT32 op = desc->opptr.l[0]; + UINT32 opswitch = op >> 26; + + switch (opswitch) + { + case 0x02: /* TDI - 64-bit only */ + case 0x1e: /* 0x1e group - 64-bit only */ + case 0x3a: /* 0x3a group - 64-bit only */ + case 0x3e: /* 0x3e group - 64-bit only */ + return FALSE; + + case 0x03: /* TWI */ + UML_CMP(block, R32(G_RA(op)), (INT16)G_SIMM(op)); // cmp ra,simm + if (G_TO(op) & 0x10) + UML_EXHc(block, COND_L, *m_exception[EXCEPTION_PROGRAM], 0x20000);// exh program,0x20000,l + if (G_TO(op) & 0x08) + UML_EXHc(block, COND_G, *m_exception[EXCEPTION_PROGRAM], 0x20000);// exh program,0x20000,g + if (G_TO(op) & 0x04) + UML_EXHc(block, COND_E, *m_exception[EXCEPTION_PROGRAM], 0x20000);// exh program,0x20000,e + if (G_TO(op) & 0x02) + UML_EXHc(block, COND_B, *m_exception[EXCEPTION_PROGRAM], 0x20000);// exh program,0x20000,b + if (G_TO(op) & 0x01) + UML_EXHc(block, COND_A, *m_exception[EXCEPTION_PROGRAM], 0x20000);// exh program,0x20000,a + return TRUE; + + case 0x07: /* MULLI */ + UML_MULS(block, R32(G_RD(op)), R32(G_RD(op)), R32(G_RA(op)), (INT16)G_SIMM(op)); + // muls rd,rd,ra,simm + return TRUE; + + case 0x0e: /* ADDI */ + UML_ADD(block, R32(G_RD(op)), R32Z(G_RA(op)), (INT16)G_SIMM(op)); // add rd,ra,simm + return TRUE; + + case 0x0f: /* ADDIS */ + UML_ADD(block, R32(G_RD(op)), R32Z(G_RA(op)), G_SIMM(op) << 16); // add rd,ra,simm << 16 + return TRUE; + + case 0x0a: /* CMPLI */ + UML_CMP(block, R32(G_RA(op)), G_UIMM(op)); // cmp ra,uimm + UML_GETFLGS(block, I0, FLAG_Z | FLAG_C); // getflgs i0,zc + UML_LOAD(block, I0, m_cmpl_cr_table, I0, SIZE_BYTE, SCALE_x1);// load i0,cmpl_cr_table,i0,byte + UML_OR(block, CR32(G_CRFD(op)), I0, XERSO32); // or [crn],i0,[xerso] + return TRUE; + + case 0x0b: /* CMPI */ + UML_CMP(block, R32(G_RA(op)), (INT16)G_SIMM(op)); // cmp ra,uimm + UML_GETFLGS(block, I0, FLAG_Z | FLAG_V | FLAG_C | FLAG_S); // getflgs i0,zvcs + UML_LOAD(block, I0, m_cmp_cr_table, I0, SIZE_BYTE, SCALE_x1);// load i0,cmp_cr_table,i0,byte + UML_OR(block, CR32(G_CRFD(op)), I0, XERSO32); // or [crn],i0,[xerso] + return TRUE; + + case 0x08: /* SUBFIC */ + UML_SUB(block, R32(G_RD(op)), (INT16)G_SIMM(op), R32(G_RA(op))); // sub rd,simm,ra + generate_compute_flags(block, desc, FALSE, XER_CA, TRUE); // + return TRUE; + + case 0x0c: /* ADDIC */ + UML_ADD(block, R32(G_RD(op)), R32(G_RA(op)), (INT16)G_SIMM(op)); // add rd,ra,simm + generate_compute_flags(block, desc, FALSE, XER_CA, FALSE); // + return TRUE; + + case 0x0d: /* ADDIC. */ + UML_ADD(block, R32(G_RD(op)), R32(G_RA(op)), (INT16)G_SIMM(op)); // add rd,ra,simm + generate_compute_flags(block, desc, TRUE, XER_CA, FALSE); // + return TRUE; + + case 0x10: /* BCx */ + generate_branch_bo(block, compiler, desc, G_BO(op), G_BI(op), 0, op & M_LK);// + return TRUE; + + case 0x11: /* SC */ + UML_MAPVAR(block, MAPVAR_PC, desc->pc + 4); // mapvar PC,desc->pc+4 + UML_EXH(block, *m_exception[EXCEPTION_SYSCALL], 0); // exh syscall,0 + return TRUE; + + case 0x12: /* Bx */ + generate_branch(block, compiler, desc, 0, op & M_LK); // + return TRUE; + + case 0x13: /* 0x13 group */ + return generate_instruction_13(block, compiler, desc); // + + case 0x14: /* RLWIMIx */ + UML_ROLINS(block, R32(G_RA(op)), R32(G_RS(op)), G_SH(op), compute_rlw_mask(G_MB(op), G_ME(op))); + // rolins ra,rs,sh,mask + if (op & M_RC) + generate_compute_flags(block, desc, TRUE, 0, FALSE); // + return TRUE; + + case 0x15: /* RLWINMx */ + UML_ROLAND(block, R32(G_RA(op)), R32(G_RS(op)), G_SH(op), compute_rlw_mask(G_MB(op), G_ME(op))); + // roland ra,rs,sh,mask + if (op & M_RC) + generate_compute_flags(block, desc, TRUE, 0, FALSE); // + return TRUE; + + case 0x17: /* RLWNMx */ + UML_ROLAND(block, R32(G_RA(op)), R32(G_RS(op)), R32(G_RB(op)), compute_rlw_mask(G_MB(op), G_ME(op))); + // roland ra,rs,rb,mask + if (op & M_RC) + generate_compute_flags(block, desc, TRUE, 0, FALSE); // + return TRUE; + + case 0x18: /* ORI */ + UML_OR(block, R32(G_RA(op)), R32(G_RS(op)), G_UIMM(op)); // or ra,rs,uimm + return TRUE; + + case 0x19: /* ORIS */ + UML_OR(block, R32(G_RA(op)), R32(G_RS(op)), G_UIMM(op) << 16); // or ra,rs,uimm << 16 + return TRUE; + + case 0x1a: /* XORI */ + UML_XOR(block, R32(G_RA(op)), R32(G_RS(op)), G_UIMM(op)); // xor ra,rs,uimm + return TRUE; + + case 0x1b: /* XORIS */ + UML_XOR(block, R32(G_RA(op)), R32(G_RS(op)), G_UIMM(op) << 16); // xor ra,rs,uimm << 16 + return TRUE; + + case 0x1c: /* ANDI. */ + UML_AND(block, R32(G_RA(op)), R32(G_RS(op)), G_UIMM(op)); // and ra,rs,uimm + generate_compute_flags(block, desc, TRUE, 0, FALSE); // + return TRUE; + + case 0x1d: /* ANDIS. */ + UML_AND(block, R32(G_RA(op)), R32(G_RS(op)), G_UIMM(op) << 16); // and ra,rs,uimm << 16 + generate_compute_flags(block, desc, TRUE, 0, FALSE); // + return TRUE; + + case 0x1f: /* 0x1f group */ + return generate_instruction_1f(block, compiler, desc); // + + case 0x22: /* LBZ */ + UML_ADD(block, I0, R32Z(G_RA(op)), (INT16)G_SIMM(op)); // add i0,ra,simm + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMM(op)); // mapvar dsisr,DSISR_IMM(op) + UML_CALLH(block, *m_read8[m_core->mode]); // callh read8 + UML_AND(block, R32(G_RD(op)), I0, 0xff); // and rd,i0,0xff + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // + return TRUE; + + case 0x28: /* LHZ */ + UML_ADD(block, I0, R32Z(G_RA(op)), (INT16)G_SIMM(op)); // add i0,ra,simm + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMM(op)); // mapvar dsisr,DSISR_IMM(op) + UML_CALLH(block, *m_read16[m_core->mode]); // callh read16 + UML_AND(block, R32(G_RD(op)), I0, 0xffff); // and rd,i0,0xffff + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // + return TRUE; + + case 0x2a: /* LHA */ + UML_ADD(block, I0, R32Z(G_RA(op)), (INT16)G_SIMM(op)); // add i0,ra,simm + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMM(op)); // mapvar dsisr,DSISR_IMM(op) + UML_CALLH(block, *m_read16[m_core->mode]); // callh read16 + UML_SEXT(block, R32(G_RD(op)), I0, SIZE_WORD); // sext rd,i0,word + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // + return TRUE; + + case 0x20: /* LWZ */ + UML_ADD(block, I0, R32Z(G_RA(op)), (INT16)G_SIMM(op)); // add i0,ra,simm + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMM(op)); // mapvar dsisr,DSISR_IMM(op) + UML_CALLH(block, *m_read32[m_core->mode]); // callh read32 + UML_MOV(block, R32(G_RD(op)), I0); // mov rd,i0 + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // + return TRUE; + + case 0x23: /* LBZU */ + UML_ADD(block, I0, R32(G_RA(op)), (INT16)G_SIMM(op)); // add i0,ra,simm + UML_MOV(block, mem(&m_core->updateaddr), I0); // mov [updateaddr],i0 + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMMU(op)); // mapvar dsisr,DSISR_IMMU(op) + UML_CALLH(block, *m_read8[m_core->mode]); // callh read8 + UML_AND(block, R32(G_RD(op)), I0, 0xff); // and rd,i0,0xff + UML_MOV(block, R32(G_RA(op)), mem(&m_core->updateaddr)); // mov ra,[updateaddr] + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // + return TRUE; + + case 0x29: /* LHZU */ + UML_ADD(block, I0, R32(G_RA(op)), (INT16)G_SIMM(op)); // add i0,ra,simm + UML_MOV(block, mem(&m_core->updateaddr), I0); // mov [updateaddr],i0 + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMMU(op)); // mapvar dsisr,DSISR_IMMU(op) + UML_CALLH(block, *m_read16[m_core->mode]); // callh read16 + UML_AND(block, R32(G_RD(op)), I0, 0xffff); // and rd,i0,0xffff + UML_MOV(block, R32(G_RA(op)), mem(&m_core->updateaddr)); // mov ra,[updateaddr] + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // + return TRUE; + + case 0x2b: /* LHAU */ + UML_ADD(block, I0, R32(G_RA(op)), (INT16)G_SIMM(op)); // add i0,ra,simm + UML_MOV(block, mem(&m_core->updateaddr), I0); // mov [updateaddr],i0 + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMMU(op)); // mapvar dsisr,DSISR_IMMU(op) + UML_CALLH(block, *m_read16[m_core->mode]); // callh read16 + UML_SEXT(block, R32(G_RD(op)), I0, SIZE_WORD); // sext rd,i0,word + UML_MOV(block, R32(G_RA(op)), mem(&m_core->updateaddr)); // mov ra,[updateaddr] + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // + return TRUE; + + case 0x21: /* LWZU */ + UML_ADD(block, I0, R32(G_RA(op)), (INT16)G_SIMM(op)); // add i0,ra,simm + UML_MOV(block, mem(&m_core->updateaddr), I0); // mov [updateaddr],i0 + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMMU(op)); // mapvar dsisr,DSISR_IMMU(op) + UML_CALLH(block, *m_read32[m_core->mode]); // callh read32 + UML_MOV(block, R32(G_RD(op)), I0); // mov rd,i0 + UML_MOV(block, R32(G_RA(op)), mem(&m_core->updateaddr)); // mov ra,[updateaddr] + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // + return TRUE; + + case 0x26: /* STB */ + UML_ADD(block, I0, R32Z(G_RA(op)), (INT16)G_SIMM(op)); // add i0,ra,simm + UML_AND(block, I1, R32(G_RS(op)), 0xff); // and i1,rs,0xff + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMM(op)); // mapvar dsisr,DSISR_IMM(op) + UML_CALLH(block, *m_write8[m_core->mode]); // callh write8 + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // + return TRUE; + + case 0x2c: /* STH */ + UML_ADD(block, I0, R32Z(G_RA(op)), (INT16)G_SIMM(op)); // add i0,ra,simm + UML_AND(block, I1, R32(G_RS(op)), 0xffff); // and i1,rs,0xffff + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMM(op)); // mapvar dsisr,DSISR_IMM(op) + UML_CALLH(block, *m_write16[m_core->mode]); // callh write16 + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // + return TRUE; + + case 0x24: /* STW */ + UML_ADD(block, I0, R32Z(G_RA(op)), (INT16)G_SIMM(op)); // add i0,ra,simm + UML_MOV(block, I1, R32(G_RS(op))); // mov i1,rs + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMM(op)); // mapvar dsisr,DSISR_IMM(op) + UML_CALLH(block, *m_write32[m_core->mode]); // callh write32 + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // + return TRUE; + + case 0x27: /* STBU */ + UML_ADD(block, I0, R32(G_RA(op)), (INT16)G_SIMM(op)); // add i0,ra,simm + UML_AND(block, I1, R32(G_RS(op)), 0xff); // and i1,rs,0xff + UML_MOV(block, mem(&m_core->updateaddr), I0); // mov [updateaddr],i0 + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMMU(op)); // mapvar dsisr,DSISR_IMMU(op) + UML_CALLH(block, *m_write8[m_core->mode]); // callh write8 + UML_MOV(block, R32(G_RA(op)), mem(&m_core->updateaddr)); // mov ra,[updateaddr] + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // + return TRUE; + + case 0x2d: /* STHU */ + UML_ADD(block, I0, R32(G_RA(op)), (INT16)G_SIMM(op)); // add i0,ra,simm + UML_AND(block, I1, R32(G_RS(op)), 0xffff); // and i1,rs,0xffff + UML_MOV(block, mem(&m_core->updateaddr), I0); // mov [updateaddr],i0 + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMMU(op)); // mapvar dsisr,DSISR_IMMU(op) + UML_CALLH(block, *m_write16[m_core->mode]); // callh write16 + UML_MOV(block, R32(G_RA(op)), mem(&m_core->updateaddr)); // mov ra,[updateaddr] + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // + return TRUE; + + case 0x25: /* STWU */ + UML_ADD(block, I0, R32(G_RA(op)), (INT16)G_SIMM(op)); // add i0,ra,simm + UML_MOV(block, I1, R32(G_RS(op))); // mov i1,rs + UML_MOV(block, mem(&m_core->updateaddr), I0); // mov [updateaddr],i0 + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMMU(op)); // mapvar dsisr,DSISR_IMMU(op) + UML_CALLH(block, *m_write32[m_core->mode]); // callh write32 + UML_MOV(block, R32(G_RA(op)), mem(&m_core->updateaddr)); // mov ra,[updateaddr] + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // + return TRUE; + + case 0x2e: /* LMW */ + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMMU(op)); // mapvar dsisr,DSISR_IMMU(op) + UML_MOV(block, mem(&m_core->tempaddr), R32Z(G_RA(op))); // mov [tempaddr],ra + for (int regnum = G_RD(op); regnum < 32; regnum++) + { + UML_ADD(block, I0, mem(&m_core->tempaddr), (INT16)G_SIMM(op) + 4 * (regnum - G_RD(op))); + // add i0,[tempaddr],simm + 4*(regnum-rd) + UML_CALLH(block, *m_read32align[m_core->mode]); // callh read32align + UML_MOV(block, R32(regnum), I0); // mov regnum,i0 + } + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // + return TRUE; + + case 0x2f: /* STMW */ + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMMU(op)); // mapvar dsisr,DSISR_IMMU(op) + UML_MOV(block, mem(&m_core->tempaddr), R32Z(G_RA(op))); // mov [tempaddr],ra + for (int regnum = G_RS(op); regnum < 32; regnum++) + { + UML_ADD(block, I0, mem(&m_core->tempaddr), (INT16)G_SIMM(op) + 4 * (regnum - G_RS(op))); + // add i0,[tempaddr],simm + 4*(regnum-rs) + UML_MOV(block, I1, R32(regnum)); // mov i1,regnum + UML_CALLH(block, *m_write32align[m_core->mode]); // callh write32align + } + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // + return TRUE; + + case 0x30: /* LFS */ + UML_ADD(block, I0, R32Z(G_RA(op)), (INT16)G_SIMM(op)); // add i0,ra,simm + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMM(op)); // mapvar dsisr,DSISR_IMM(op) + UML_CALLH(block, *m_read32[m_core->mode]); // callh read32 + UML_MOV(block, mem(&m_core->tempdata.w.l), I0); // mov [tempdata],i0 + UML_FDFRFLT(block, F64(G_RD(op)), mem(&m_core->tempdata.w.l), SIZE_DWORD); // fdfrflt fd,[tempdata],dword + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // + return TRUE; + + case 0x32: /* LFD */ + UML_ADD(block, I0, R32Z(G_RA(op)), (INT16)G_SIMM(op)); // add i0,ra,simm + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMM(op)); // mapvar dsisr,DSISR_IMM(op) + UML_CALLH(block, *m_read64[m_core->mode]); // callh read64 + UML_DMOV(block, mem(&m_core->tempdata.d), I0); // dmov [tempdata],i0 + UML_FDMOV(block, F64(G_RD(op)), mem(&m_core->tempdata.d)); // fdmov fd,[tempdata] + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // + return TRUE; + + case 0x31: /* LFSU */ + UML_ADD(block, I0, R32(G_RA(op)), (INT16)G_SIMM(op)); // add i0,ra,simm + UML_MOV(block, mem(&m_core->updateaddr), I0); // mov [updateaddr],i0 + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMMU(op)); // mapvar dsisr,DSISR_IMMU(op) + UML_CALLH(block, *m_read32[m_core->mode]); // callh read32 + UML_MOV(block, mem(&m_core->tempdata.w.l), I0); // mov [tempdata],i0 + UML_FDFRFLT(block, F64(G_RD(op)), mem(&m_core->tempdata.w.l), SIZE_DWORD); // fdfrflt fd,[tempdata],dword + UML_MOV(block, R32(G_RA(op)), mem(&m_core->updateaddr)); // mov ra,[updateaddr] + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // + return TRUE; + + case 0x33: /* LFDU */ + UML_ADD(block, I0, R32(G_RA(op)), (INT16)G_SIMM(op)); // add i0,ra,simm + UML_MOV(block, mem(&m_core->updateaddr), I0); // mov [updateaddr],i0 + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMMU(op)); // mapvar dsisr,DSISR_IMMU(op) + UML_CALLH(block, *m_read64[m_core->mode]); // callh read64 + UML_DMOV(block, mem(&m_core->tempdata.d), I0); // dmov [tempdata],i0 + UML_FDMOV(block, F64(G_RD(op)), mem(&m_core->tempdata.d)); // fdmov fd,[tempdata] + UML_MOV(block, R32(G_RA(op)), mem(&m_core->updateaddr)); // mov ra,[updateaddr] + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // + return TRUE; + + case 0x34: /* STFS */ + UML_ADD(block, I0, R32Z(G_RA(op)), (INT16)G_SIMM(op)); // add i0,ra,simm + UML_FSFRFLT(block, mem(&m_core->tempdata.w.l), F64(G_RS(op)), SIZE_QWORD); // fsfrflt [tempdata],rs,qword + UML_MOV(block, I1, mem(&m_core->tempdata.w.l)); // mov i1,[tempdata] + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMM(op)); // mapvar dsisr,DSISR_IMM(op) + UML_CALLH(block, *m_write32[m_core->mode]); // callh write32 + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // + return TRUE; + + case 0x36: /* STFD */ + UML_ADD(block, I0, R32Z(G_RA(op)), (INT16)G_SIMM(op)); // add i0,ra,simm + UML_FDMOV(block, mem(&m_core->tempdata.d), F64(G_RS(op))); // fdmov [tempdata],rs + UML_DMOV(block, I1, mem(&m_core->tempdata.d)); // dmov i1,[tempdata] + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMM(op)); // mapvar dsisr,DSISR_IMM(op) + UML_CALLH(block, *m_write64[m_core->mode]); // callh write64 + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // + return TRUE; + + case 0x35: /* STFSU */ + UML_ADD(block, I0, R32(G_RA(op)), (INT16)G_SIMM(op)); // add i0,ra,simm + UML_FSFRFLT(block, mem(&m_core->tempdata.w.l), F64(G_RS(op)), SIZE_QWORD); // fsfrflt [tempdata],rs,qword + UML_MOV(block, I1, mem(&m_core->tempdata.w.l)); // mov i1,[tempdata] + UML_MOV(block, mem(&m_core->updateaddr), I0); // mov [updateaddr],i0 + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMMU(op)); // mapvar dsisr,DSISR_IMMU(op) + UML_CALLH(block, *m_write32[m_core->mode]); // callh write32 + UML_MOV(block, R32(G_RA(op)), mem(&m_core->updateaddr)); // mov ra,[updateaddr] + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // + return TRUE; + + case 0x37: /* STFDU */ + UML_ADD(block, I0, R32(G_RA(op)), (INT16)G_SIMM(op)); // add i0,ra,simm + UML_FDMOV(block, mem(&m_core->tempdata.d), F64(G_RS(op))); // fdmov [tempdata],rs + UML_DMOV(block, I1, mem(&m_core->tempdata.d)); // dmov i1,[tempdata] + UML_MOV(block, mem(&m_core->updateaddr), I0); // mov [updateaddr],i0 + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMMU(op)); // mapvar dsisr,DSISR_IMMU(op) + UML_CALLH(block, *m_write64[m_core->mode]); // callh write64 + UML_MOV(block, R32(G_RA(op)), mem(&m_core->updateaddr)); // mov ra,[updateaddr] + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // + return TRUE; + + case 0x3b: /* 0x3b group */ + return generate_instruction_3b(block, compiler, desc); // + + case 0x3f: /* 0x3f group */ + return generate_instruction_3f(block, compiler, desc); // + } + + return FALSE; +} + + +/*------------------------------------------------- + generate_instruction_13 - compile opcodes in + the 0x13 group +-------------------------------------------------*/ + +int ppc_device::generate_instruction_13(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) +{ + UINT32 op = desc->opptr.l[0]; + UINT32 opswitch = (op >> 1) & 0x3ff; + + switch (opswitch) + { + case 0x010: /* BCLRx */ + generate_branch_bo(block, compiler, desc, G_BO(op), G_BI(op), SPR_LR, op & M_LK);// + return TRUE; + + case 0x210: /* BCCTRx */ + generate_branch_bo(block, compiler, desc, G_BO(op), G_BI(op), SPR_CTR, op & M_LK); + // + return TRUE; + + case 0x000: /* MCRF */ + UML_MOV(block, CR32(G_CRFD(op)), CR32(G_CRFS(op))); // mov [crd],[crs] + return TRUE; + + case 0x101: /* CRAND */ + UML_SHL(block, I0, CR32(G_CRBA(op) / 4), G_CRBA(op) % 4); // shl i0,cr(a / 4),a % 4 + UML_SHL(block, I1, CR32(G_CRBB(op) / 4), G_CRBB(op) % 4); // shl i1,cr(b / 4),b % 4 + UML_AND(block, I0, I0, I1); // and i0,i1 + UML_ROLINS(block, CR32(G_CRBD(op) / 4), I0, 32 - G_CRBD(op) % 4, 8 >> (G_CRBD(op) % 4)); + // rolins cr(d / 4),i0,32-(d % 4),8 >> (d % 4) + return TRUE; + + case 0x081: /* CRANDC */ + UML_SHL(block, I0, CR32(G_CRBA(op) / 4), G_CRBA(op) % 4); // shl i0,cr(a / 4),a % 4 + UML_SHL(block, I1, CR32(G_CRBB(op) / 4), G_CRBB(op) % 4); // shl i1,cr(b / 4),b % 4 + UML_XOR(block, I1, I1, ~0); // xor i1,~0 + UML_AND(block, I0, I0, I1); // and i0,i1 + UML_ROLINS(block, CR32(G_CRBD(op) / 4), I0, 32 - G_CRBD(op) % 4, 8 >> (G_CRBD(op) % 4)); + // rolins cr(d / 4),i0,32-(d % 4),8 >> (d % 4) + return TRUE; + + case 0x0e1: /* CRNAND */ + UML_SHL(block, I0, CR32(G_CRBA(op) / 4), G_CRBA(op) % 4); // shl i0,cr(a / 4),a % 4 + UML_SHL(block, I1, CR32(G_CRBB(op) / 4), G_CRBB(op) % 4); // shl i1,cr(b / 4),b % 4 + UML_AND(block, I0, I0, I1); // and i0,i1 + UML_XOR(block, I0, I0, ~0); // xor i0,~0 + UML_ROLINS(block, CR32(G_CRBD(op) / 4), I0, 32 - G_CRBD(op) % 4, 8 >> (G_CRBD(op) % 4)); + // rolins cr(d / 4),i0,32-(d % 4),8 >> (d % 4) + return TRUE; + + case 0x1c1: /* CROR */ + UML_SHL(block, I0, CR32(G_CRBA(op) / 4), G_CRBA(op) % 4); // shl i0,cr(a / 4),a % 4 + UML_SHL(block, I1, CR32(G_CRBB(op) / 4), G_CRBB(op) % 4); // shl i1,cr(b / 4),b % 4 + UML_OR(block, I0, I0, I1); // or i0,i1 + UML_ROLINS(block, CR32(G_CRBD(op) / 4), I0, 32 - G_CRBD(op) % 4, 8 >> (G_CRBD(op) % 4)); + // rolins cr(d / 4),i0,32-(d % 4),8 >> (d % 4) + return TRUE; + + case 0x1a1: /* CRORC */ + UML_SHL(block, I0, CR32(G_CRBA(op) / 4), G_CRBA(op) % 4); // shl i0,cr(a / 4),a % 4 + UML_SHL(block, I1, CR32(G_CRBB(op) / 4), G_CRBB(op) % 4); // shl i1,cr(b / 4),b % 4 + UML_XOR(block, I1, I1, ~0); // xor i1,~0 + UML_OR(block, I0, I0, I1); // or i0,i1 + UML_ROLINS(block, CR32(G_CRBD(op) / 4), I0, 32 - G_CRBD(op) % 4, 8 >> (G_CRBD(op) % 4)); + // rolins cr(d / 4),i0,32-(d % 4),8 >> (d % 4) + return TRUE; + + case 0x021: /* CRNOR */ + UML_SHL(block, I0, CR32(G_CRBA(op) / 4), G_CRBA(op) % 4); // shl i0,cr(a / 4),a % 4 + UML_SHL(block, I1, CR32(G_CRBB(op) / 4), G_CRBB(op) % 4); // shl i1,cr(b / 4),b % 4 + UML_OR(block, I0, I0, I1); // or i0,i1 + UML_XOR(block, I0, I0, ~0); // xor i0,~0 + UML_ROLINS(block, CR32(G_CRBD(op) / 4), I0, 32 - G_CRBD(op) % 4, 8 >> (G_CRBD(op) % 4)); + // rolins cr(d / 4),i0,32-(d % 4),8 >> (d % 4) + return TRUE; + + case 0x0c1: /* CRXOR */ + UML_SHL(block, I0, CR32(G_CRBA(op) / 4), G_CRBA(op) % 4); // shl i0,cr(a / 4),a % 4 + UML_SHL(block, I1, CR32(G_CRBB(op) / 4), G_CRBB(op) % 4); // shl i1,cr(b / 4),b % 4 + UML_XOR(block, I0, I0, I1); // xor i0,i1 + UML_ROLINS(block, CR32(G_CRBD(op) / 4), I0, 32 - G_CRBD(op) % 4, 8 >> (G_CRBD(op) % 4)); + // rolins cr(d / 4),i0,32-(d % 4),8 >> (d % 4) + return TRUE; + + case 0x121: /* CREQV */ + UML_SHL(block, I0, CR32(G_CRBA(op) / 4), G_CRBA(op) % 4); // shl i0,cr(a / 4),a % 4 + UML_SHL(block, I1, CR32(G_CRBB(op) / 4), G_CRBB(op) % 4); // shl i1,cr(b / 4),b % 4 + UML_XOR(block, I0, I0, I1); // xor i0,i1 + UML_XOR(block, I0, I0, ~0); // xor i0,~0 + UML_ROLINS(block, CR32(G_CRBD(op) / 4), I0, 32 - G_CRBD(op) % 4, 8 >> (G_CRBD(op) % 4)); + // rolins cr(d / 4),i0,32-(d % 4),8 >> (d % 4) + return TRUE; + + case 0x032: /* RFI */ + if (m_cap & PPCCAP_OEA) + { + if (!(m_cap & PPCCAP_603_MMU)) + UML_ROLINS(block, MSR32, SPR32(SPROEA_SRR1), 0, 0x87c0ffff); // rolins [msr],[srr1],0,0x87c0ffff + else + { + UML_MOV(block, I0, MSR32); // mov i0,[msr] + UML_ROLINS(block, MSR32, SPR32(SPROEA_SRR1), 0, 0x87c0ffff | MSR603_TGPR); + // rolins [msr],[srr1],0,0x87c0ffff | MSR603_TGPR + UML_XOR(block, I0, I0, MSR32); // xor i0,i0,[msr] + UML_TEST(block, I0, MSR603_TGPR); // test i0,tgpr + UML_CALLHc(block, COND_NZ, *m_swap_tgpr); // callh swap_tgpr,nz + } + } + else if (m_cap & PPCCAP_4XX) + UML_MOV(block, MSR32, SPR32(SPR4XX_SRR1)); // mov [msr],[srr1] + generate_update_mode(block); // + compiler->checkints = TRUE; + generate_update_cycles(block, compiler, SPR32(SPROEA_SRR0), TRUE); // + UML_HASHJMP(block, mem(&m_core->mode), SPR32(SPROEA_SRR0), *m_nocode); + // hashjmp mode,[srr0],nocode + return TRUE; + + case 0x033: /* RFCI */ + assert(m_cap & PPCCAP_4XX); + UML_MOV(block, MSR32, SPR32(SPR4XX_SRR3)); // mov [msr],[srr3] + generate_update_mode(block); // + compiler->checkints = TRUE; + generate_update_cycles(block, compiler, SPR32(SPR4XX_SRR2), TRUE); // + UML_HASHJMP(block, mem(&m_core->mode), SPR32(SPR4XX_SRR2), *m_nocode); + // hashjmp mode,[srr2],nocode + return TRUE; + + case 0x096: /* ISYNC */ + /* effective no-op */ + return TRUE; + } + + return FALSE; +} + + +/*------------------------------------------------- + generate_instruction_1f - compile opcodes in + the 0x1f group +-------------------------------------------------*/ + +int ppc_device::generate_instruction_1f(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) +{ + UINT32 op = desc->opptr.l[0]; + UINT32 opswitch = (op >> 1) & 0x3ff; + int item; + + switch (opswitch) + { + case 0x009: /* MULHDUx - 64-bit only */ + case 0x015: /* LDX - 64-bit only */ + case 0x01b: /* SLDx - 64-bit only */ + case 0x035: /* LDUX - 64-bit only */ + case 0x03a: /* CNTLZDx - 64-bit only */ + case 0x044: /* TD - 64-bit only */ + case 0x049: /* MULHDx - 64-bit only */ + case 0x054: /* LDARX - 64-bit only */ + case 0x095: /* STDX - 64-bit only */ + case 0x0b5: /* STDUX - 64-bit only */ + case 0x0d6: /* STDCX. - 64-bit only */ + case 0x0e9: /* MULLD - 64-bit only */ + case 0x2e9: /* MULLDO - 64-bit only */ + case 0x155: /* LWAX - 64-bit only */ + case 0x175: /* LWAUX - 64-bit only */ + case 0x33a: /* SRADIx - 64-bit only */ + case 0x33b: /* SRADIx - 64-bit only */ + case 0x1b2: /* SLBIE - 64-bit only */ + case 0x1c9: /* DIVDUx - 64-bit only */ + case 0x3c9: /* DIVDUOx - 64-bit only */ + case 0x1e9: /* DIVDx - 64-bit only */ + case 0x3e9: /* DIVDOx - 64-bit only */ + case 0x1f2: /* SLBIA - 64-bit only */ + case 0x21b: /* SRDx - 64-bit only */ + case 0x31a: /* SRADx - 64-bit only */ + case 0x3da: /* EXTSW - 64-bit only */ + return FALSE; + + case 0x004: /* TW */ + UML_CMP(block, R32(G_RA(op)), R32(G_RB(op))); // cmp ra,rb + if (G_TO(op) & 0x10) + UML_EXHc(block, COND_L, *m_exception[EXCEPTION_PROGRAM], 0x20000);// exh program,0x20000,l + if (G_TO(op) & 0x08) + UML_EXHc(block, COND_G, *m_exception[EXCEPTION_PROGRAM], 0x20000);// exh program,0x20000,g + if (G_TO(op) & 0x04) + UML_EXHc(block, COND_E, *m_exception[EXCEPTION_PROGRAM], 0x20000);// exh program,0x20000,e + if (G_TO(op) & 0x02) + UML_EXHc(block, COND_B, *m_exception[EXCEPTION_PROGRAM], 0x20000);// exh program,0x20000,b + if (G_TO(op) & 0x01) + UML_EXHc(block, COND_A, *m_exception[EXCEPTION_PROGRAM], 0x20000);// exh program,0x20000,a + return TRUE; + + case 0x10a: /* ADDx */ + case 0x30a: /* ADDOx */ + UML_ADD(block, R32(G_RD(op)), R32(G_RA(op)), R32(G_RB(op))); // add rd,ra,rb + generate_compute_flags(block, desc, op & M_RC, ((op & M_OE) ? XER_OV : 0), FALSE); + // + return TRUE; + + case 0x00a: /* ADDCx */ + case 0x20a: /* ADDCOx */ + UML_ADD(block, R32(G_RD(op)), R32(G_RA(op)), R32(G_RB(op))); // add rd,ra,rb + generate_compute_flags(block, desc, op & M_RC, XER_CA | ((op & M_OE) ? XER_OV : 0), FALSE); + // + return TRUE; + + case 0x08a: /* ADDEx */ + case 0x28a: /* ADDEOx */ + UML_CARRY(block, SPR32(SPR_XER), 29); // carry [xer],XER_CA + UML_ADDC(block, R32(G_RD(op)), R32(G_RA(op)), R32(G_RB(op))); // addc rd,ra,rb + generate_compute_flags(block, desc, op & M_RC, XER_CA | ((op & M_OE) ? XER_OV : 0), FALSE); + // + return TRUE; + + case 0x0ca: /* ADDZEx */ + case 0x2ca: /* ADDZEOx */ + UML_CARRY(block, SPR32(SPR_XER), 29); // carry [xer],XER_CA + UML_ADDC(block, R32(G_RD(op)), R32(G_RA(op)), 0); // addc rd,ra,0 + generate_compute_flags(block, desc, op & M_RC, XER_CA | ((op & M_OE) ? XER_OV : 0), FALSE); + // + return TRUE; + + case 0x0ea: /* ADDMEx */ + case 0x2ea: /* ADDMEOx */ + UML_CARRY(block, SPR32(SPR_XER), 29); // carry [xer],XER_CA + UML_ADDC(block, R32(G_RD(op)), R32(G_RA(op)), (UINT32)-1); // addc rd,ra,-1 + generate_compute_flags(block, desc, op & M_RC, XER_CA | ((op & M_OE) ? XER_OV : 0), FALSE); + // + return TRUE; + + case 0x028: /* SUBFx */ + case 0x228: /* SUBFOx */ + UML_SUB(block, R32(G_RD(op)), R32(G_RB(op)), R32(G_RA(op))); // sub rd,rb,ra + generate_compute_flags(block, desc, op & M_RC, (op & M_OE) ? XER_OV : 0, TRUE); + // + return TRUE; + + case 0x008: /* SUBFCx */ + case 0x208: /* SUBFCOx */ + UML_SUB(block, R32(G_RD(op)), R32(G_RB(op)), R32(G_RA(op))); // sub rd,rb,ra + generate_compute_flags(block, desc, op & M_RC, XER_CA | ((op & M_OE) ? XER_OV : 0), TRUE); + // + return TRUE; + + case 0x088: /* SUBFEx */ + case 0x288: /* SUBFEOx */ + UML_XOR(block, I0, SPR32(SPR_XER), XER_CA); // xor i0,[xer],XER_CA + UML_CARRY(block, I0, 29); // carry i0,XER_CA + UML_SUBB(block, R32(G_RD(op)), R32(G_RB(op)), R32(G_RA(op))); // subc rd,rb,ra + generate_compute_flags(block, desc, op & M_RC, XER_CA | ((op & M_OE) ? XER_OV : 0), TRUE); + // + return TRUE; + + case 0x0c8: /* SUBFZEx */ + case 0x2c8: /* SUBFZEOx */ + UML_XOR(block, I0, SPR32(SPR_XER), XER_CA); // xor i0,[xer],XER_CA + UML_CARRY(block, I0, 29); // carry i0,XER_CA + UML_SUBB(block, R32(G_RD(op)), 0, R32(G_RA(op))); // subc rd,0,ra + generate_compute_flags(block, desc, op & M_RC, XER_CA | ((op & M_OE) ? XER_OV : 0), TRUE); + // + return TRUE; + + case 0x0e8: /* SUBFMEx */ + case 0x2e8: /* SUBFMEOx */ + UML_XOR(block, I0, SPR32(SPR_XER), XER_CA); // xor i0,[xer],XER_CA + UML_CARRY(block, I0, 29); // carry i0,XER_CA + UML_SUBB(block, R32(G_RD(op)), (UINT32)-1, R32(G_RA(op))); // subc rd,-1,ra + generate_compute_flags(block, desc, op & M_RC, XER_CA | ((op & M_OE) ? XER_OV : 0), TRUE); + // + return TRUE; + + case 0x068: /* NEGx */ + case 0x268: /* NEGOx */ + UML_SUB(block, R32(G_RD(op)), 0, R32(G_RA(op))); // sub rd,0,ra + generate_compute_flags(block, desc, op & M_RC, (op & M_OE) ? XER_OV : 0, TRUE); + // + return TRUE; + + case 0x000: /* CMP */ + UML_CMP(block, R32(G_RA(op)), R32(G_RB(op))); // cmp ra,rb + UML_GETFLGS(block, I0, FLAG_Z | FLAG_V | FLAG_C | FLAG_S); // getflgs i0,zvcs + UML_LOAD(block, I0, m_cmp_cr_table, I0, SIZE_BYTE, SCALE_x1);// load i0,cmp_cr_table,i0,byte + UML_OR(block, CR32(G_CRFD(op)), I0, XERSO32); // or [crn],i0,[xerso] + return TRUE; + + case 0x020: /* CMPL */ + UML_CMP(block, R32(G_RA(op)), R32(G_RB(op))); // cmp ra,rb + UML_GETFLGS(block, I0, FLAG_Z | FLAG_C); // getflgs i0,zc + UML_LOAD(block, I0, m_cmpl_cr_table, I0, SIZE_BYTE, SCALE_x1);// load i0,cmpl_cr_table,i0,byte + UML_OR(block, CR32(G_CRFD(op)), I0, XERSO32); // or [crn],i0,[xerso] + return TRUE; + + case 0x00b: /* MULHWUx */ + UML_MULU(block, I0, R32(G_RD(op)), R32(G_RA(op)), R32(G_RB(op))); // mulu i0,rd,ra,rb + if (op & M_RC) + { + UML_TEST(block, R32(G_RD(op)), ~0); // test rd,~0 + generate_compute_flags(block, desc, op & M_RC, 0, FALSE); // + } + return TRUE; + + case 0x04b: /* MULHWx */ + UML_MULS(block, I0, R32(G_RD(op)), R32(G_RA(op)), R32(G_RB(op))); // muls i0,rd,ra,rb + if (op & M_RC) + { + UML_TEST(block, R32(G_RD(op)), ~0); // test rd,~0 + generate_compute_flags(block, desc, op & M_RC, 0, FALSE); // + } + return TRUE; + + case 0x0eb: /* MULLWx */ + case 0x2eb: /* MULLWOx */ + UML_MULS(block, R32(G_RD(op)), R32(G_RD(op)), R32(G_RA(op)), R32(G_RB(op))); // muls rd,rd,ra,rb + generate_compute_flags(block, desc, op & M_RC, ((op & M_OE) ? XER_OV : 0), FALSE);// + return TRUE; + + case 0x1cb: /* DIVWUx */ + case 0x3cb: /* DIVWUOx */ + UML_CMP(block, R32(G_RB(op)), 0x0); // cmp rb, #0 + UML_JMPc(block, COND_NZ, compiler->labelnum); // bne 0: + + UML_MOV(block, R32(G_RD(op)), 0x0); // mov rd, #0 + if (op & M_OE) + { + UML_OR(block, XERSO32, XERSO32, 0x1); // SO |= 1 + UML_OR(block, SPR32(SPR_XER), SPR32(SPR_XER), XER_OV); // OV |= 1 + } + if (op & M_RC) + { + UML_MOV(block, CR32(0), 0x2); // CR = EQ + UML_AND(block, CR32(0), CR32(0), ~0x1); + UML_OR(block, CR32(0), CR32(0), XERSO32); + } + + UML_JMP(block, compiler->labelnum+1); // jmp 1: + + UML_LABEL(block, compiler->labelnum++); // 0: + UML_DIVU(block, R32(G_RD(op)), R32(G_RD(op)), R32(G_RA(op)), R32(G_RB(op))); // divu rd,rd,ra,rb + generate_compute_flags(block, desc, op & M_RC, ((op & M_OE) ? XER_OV : 0), FALSE);// + + UML_LABEL(block, compiler->labelnum++); // 1: + return TRUE; + + case 0x1eb: /* DIVWx */ + case 0x3eb: /* DIVWOx */ + UML_CMP(block, R32(G_RB(op)), 0x0); // cmp rb, #0 + UML_JMPc(block, COND_NZ, compiler->labelnum); // bne 0: + UML_CMP(block, R32(G_RA(op)), 0x80000000); // cmp rb, #80000000 + UML_JMPc(block, COND_AE, compiler->labelnum); // bae 0: + + UML_MOV(block, R32(G_RD(op)), 0x0); // move rd, #0 + if (op & M_OE) + { + UML_OR(block, XERSO32, XERSO32, 0x1); // SO |= 1 + UML_OR(block, SPR32(SPR_XER), SPR32(SPR_XER), XER_OV); // OV |= 1 + } + if (op & M_RC) + { + UML_MOV(block, CR32(0), 0x2); // CR = EQ + UML_AND(block, CR32(0), CR32(0), ~0x1); + UML_OR(block, CR32(0), CR32(0), XERSO32); + } + + UML_JMP(block, compiler->labelnum+3); // jmp 3: + + UML_LABEL(block, compiler->labelnum++); // 0: + UML_CMP(block, R32(G_RB(op)), 0x0); // cmp rb, #0 + UML_JMPc(block, COND_Z, compiler->labelnum); // beq 1: + + UML_CMP(block, R32(G_RB(op)), 0xffffffff); // cmp rb, #ffffffff + UML_JMPc(block, COND_NZ, compiler->labelnum+1); // bne 2: + UML_CMP(block, R32(G_RA(op)), 0x80000000); // cmp ra, #80000000 + UML_JMPc(block, COND_NZ, compiler->labelnum+1); // bne 2: + + UML_LABEL(block, compiler->labelnum++); // 1: + UML_MOV(block, R32(G_RD(op)), 0xffffffff); // move rd, #ffffffff + if (op & M_OE) + { + UML_OR(block, XERSO32, XERSO32, 0x1); // SO |= 1 + UML_OR(block, SPR32(SPR_XER), SPR32(SPR_XER), XER_OV); // OV |= 1 + } + if (op & M_RC) + { + UML_MOV(block, CR32(0), 0x8); // CR = LT + UML_AND(block, CR32(0), CR32(0), ~0x1); + UML_OR(block, CR32(0), CR32(0), XERSO32); + } + UML_JMP(block, compiler->labelnum+1); // jmp 3: + + UML_LABEL(block, compiler->labelnum++); // 2: + UML_DIVS(block, R32(G_RD(op)), R32(G_RD(op)), R32(G_RA(op)), R32(G_RB(op))); // divs rd,rd,ra,rb + generate_compute_flags(block, desc, op & M_RC, ((op & M_OE) ? XER_OV : 0), FALSE);// + + UML_LABEL(block, compiler->labelnum++); // 3: + return TRUE; + + case 0x01c: /* ANDx */ + UML_AND(block, R32(G_RA(op)), R32(G_RS(op)), R32(G_RB(op))); // and ra,rs,rb + generate_compute_flags(block, desc, op & M_RC, 0, FALSE); // + return TRUE; + + case 0x03c: /* ANDCx */ + UML_XOR(block, I0, R32(G_RB(op)), ~0); // xor i0,rb,~0 + UML_AND(block, R32(G_RA(op)), R32(G_RS(op)), I0); // and ra,rs,i0 + generate_compute_flags(block, desc, op & M_RC, 0, FALSE); // + return TRUE; + + case 0x1dc: /* NANDx */ + UML_AND(block, I0, R32(G_RS(op)), R32(G_RB(op))); // and i0,rs,rb + UML_XOR(block, R32(G_RA(op)), I0, ~0); // xor ra,i0,~0 + generate_compute_flags(block, desc, op & M_RC, 0, FALSE); // + return TRUE; + + case 0x1bc: /* ORx */ + UML_OR(block, R32(G_RA(op)), R32(G_RS(op)), R32(G_RB(op))); // or ra,rs,rb + generate_compute_flags(block, desc, op & M_RC, 0, FALSE); // + return TRUE; + + case 0x19c: /* ORCx */ + UML_XOR(block, I0, R32(G_RB(op)), ~0); // xor i0,rb,~0 + UML_OR(block, R32(G_RA(op)), R32(G_RS(op)), I0); // or ra,rs,i0 + generate_compute_flags(block, desc, op & M_RC, 0, FALSE); // + return TRUE; + + case 0x07c: /* NORx */ + UML_OR(block, I0, R32(G_RS(op)), R32(G_RB(op))); // or i0,rs,rb + UML_XOR(block, R32(G_RA(op)), I0, ~0); // xor ra,i0,~0 + generate_compute_flags(block, desc, op & M_RC, 0, FALSE); // + return TRUE; + + case 0x13c: /* XORx */ + UML_XOR(block, R32(G_RA(op)), R32(G_RS(op)), R32(G_RB(op))); // xor ra,rs,rb + generate_compute_flags(block, desc, op & M_RC, 0, FALSE); // + return TRUE; + + case 0x11c: /* EQVx */ + UML_XOR(block, I0, R32(G_RS(op)), R32(G_RB(op))); // xor i0,rs,rb + UML_XOR(block, R32(G_RA(op)), I0, ~0); // xor ra,i0,~0 + generate_compute_flags(block, desc, op & M_RC, 0, FALSE); // + return TRUE; + + case 0x018: /* SLWx */ + UML_AND(block, I0, R32(G_RB(op)), 0x3f); // and i0, rb, 0x3f + UML_CMP(block, I0, 31); // cmp i0, #31 + UML_JMPc(block, COND_BE, compiler->labelnum); // be 0: + + UML_MOV(block, R32(G_RA(op)), 0x0); // mov ra, #0 + if (op & M_RC) + { + UML_MOV(block, CR32(0), 0x2); // CR = EQ + UML_AND(block, CR32(0), CR32(0), ~0x1); + UML_OR(block, CR32(0), CR32(0), XERSO32); + } + UML_JMP(block, compiler->labelnum+1); // jmp 1: + + UML_LABEL(block, compiler->labelnum++); // 0: + UML_SHL(block, R32(G_RA(op)), R32(G_RS(op)), R32(G_RB(op))); // shl ra,rs,rb + // calculate S and Z flags + if (op & M_RC) + { + generate_shift_flags(block, desc, op); + } + + UML_LABEL(block, compiler->labelnum++); // 1: + return TRUE; + + case 0x218: /* SRWx */ + UML_AND(block, I0, R32(G_RB(op)), 0x3f); // and i0, rb, 0x3f + UML_CMP(block, I0, 31); // cmp i0, #31 + UML_JMPc(block, COND_BE, compiler->labelnum); // be 0: + + UML_MOV(block, R32(G_RA(op)), 0x0); // mov ra, #0 + if (op & M_RC) + { + UML_MOV(block, CR32(0), 0x2); // CR = EQ + UML_AND(block, CR32(0), CR32(0), ~0x1); + UML_OR(block, CR32(0), CR32(0), XERSO32); + } + UML_JMP(block, compiler->labelnum+1); // jmp 1: + + UML_LABEL(block, compiler->labelnum++); // 0: + UML_SHR(block, R32(G_RA(op)), R32(G_RS(op)), R32(G_RB(op))); // shr ra,i0,rb + // calculate S and Z flags + if (op & M_RC) + { + generate_shift_flags(block, desc, op); + } + + UML_LABEL(block, compiler->labelnum++); // 1: + return TRUE; + + case 0x318: /* SRAWx */ + UML_AND(block, I2, R32(G_RB(op)), 0x3f); // and i2,rb,0x3f + UML_CMP(block, I2, 0x00000020); // cmp rb,0x20 + UML_JMPc(block, COND_S, compiler->labelnum); // bs 1: + + if (DISABLE_FLAG_OPTIMIZATIONS || (desc->regreq[3] & REGFLAG_XER_CA)) + { + // for shift amt > 32, carry flag is the sign bit of Rs and the sign bit fills all bit positions + UML_TEST(block, R32(G_RS(op)), 0x80000000); + UML_SETc(block, COND_NZ, I0); + UML_ROLINS(block, SPR32(SPR_XER), I0, 29, XER_CA); // rolins [xer],i0,29,XER_CA + UML_SAR(block, R32(G_RA(op)), R32(G_RS(op)), 31); // sar ra,rs,31 + } + UML_JMP(block, compiler->labelnum+1); // bra 2: + + UML_LABEL(block, compiler->labelnum++); // 1: + if (DISABLE_FLAG_OPTIMIZATIONS || (desc->regreq[3] & REGFLAG_XER_CA)) + { + UML_SHL(block, I1, 0xffffffff, I2); // shl i1,0xffffffff,i2 + UML_XOR(block, I1, I1, ~0); // xor i1,i1,~0 + UML_AND(block, I0, R32(G_RS(op)), I1); // and i0,rs,i1 + UML_SAR(block, I1, R32(G_RS(op)), 31); // sar i1,rs,31 + UML_TEST(block, I0, I1); // test i0,i1 + UML_SETc(block, COND_NZ, I0); // set i0,nz + UML_ROLINS(block, SPR32(SPR_XER), I0, 29, XER_CA); // rolins [xer],i0,29,XER_CA + } + UML_SAR(block, R32(G_RA(op)), R32(G_RS(op)), I2); // sar ra,rs,i2 + + UML_LABEL(block, compiler->labelnum++); // 2: + // calculate S and Z flags + if (op & M_RC) + { + generate_shift_flags(block, desc, op); + } + return TRUE; + + case 0x338: /* SRAWIx */ + if (DISABLE_FLAG_OPTIMIZATIONS || (desc->regreq[3] & REGFLAG_XER_CA)) + { + UML_AND(block, I0, R32(G_RS(op)), ~(0xffffffff << (G_SH(op) & 31)));// and i0,rs,~(0xffffffff << (sh & 31)) + UML_SAR(block, I1, R32(G_RS(op)), 31); // sar i1,rs,31 + UML_TEST(block, I0, I1); // test i0,i1 + UML_SETc(block, COND_NZ, I0); // set i0,nz + UML_ROLINS(block, SPR32(SPR_XER), I0, 29, XER_CA); // rolins [xer],i0,29,XER_CA + } + UML_SAR(block, R32(G_RA(op)), R32(G_RS(op)), G_SH(op)); // sar ra,rs,sh + // calculate S and Z flags + if (op & M_RC) + { + generate_shift_flags(block, desc, op); + } + return TRUE; + + case 0x01a: /* CNTLZWx */ + UML_LZCNT(block, R32(G_RA(op)), R32(G_RS(op))); // lzcnt ra,rs + if (op & M_RC) + generate_compute_flags(block, desc, op & M_RC, 0, FALSE); // + return TRUE; + + case 0x3ba: /* EXTSBx */ + UML_SEXT(block, R32(G_RA(op)), R32(G_RS(op)), SIZE_BYTE); // sext ra,rs,byte + if (op & M_RC) + generate_compute_flags(block, desc, op & M_RC, 0, FALSE); // + return TRUE; + + case 0x39a: /* EXTSHx */ + UML_SEXT(block, R32(G_RA(op)), R32(G_RS(op)), SIZE_WORD); // sext ra,rs,word + if (op & M_RC) + generate_compute_flags(block, desc, op & M_RC, 0, FALSE); // + return TRUE; + + case 0x057: /* LBZX */ + UML_ADD(block, I0, R32Z(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op) + UML_CALLH(block, *m_read8[m_core->mode]); // callh read8 + UML_AND(block, R32(G_RD(op)), I0, 0xff); // and rd,i0,0xff + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // + return TRUE; + + case 0x117: /* LHZX */ + UML_ADD(block, I0, R32Z(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op) + UML_CALLH(block, *m_read16[m_core->mode]); // callh read16 + UML_AND(block, R32(G_RD(op)), I0, 0xffff); // and rd,i0,0xffff + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // + return TRUE; + + case 0x157: /* LHAX */ + UML_ADD(block, I0, R32Z(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op) + UML_CALLH(block, *m_read16[m_core->mode]); // callh read16 + UML_SEXT(block, R32(G_RD(op)), I0, SIZE_WORD); // sext rd,i0,word + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // + return TRUE; + + case 0x017: /* LWZX */ + UML_ADD(block, I0, R32Z(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op) + UML_CALLH(block, *m_read32[m_core->mode]); // callh read32 + UML_MOV(block, R32(G_RD(op)), I0); // mov rd,i0 + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // + return TRUE; + + case 0x217: /* LFSX */ + UML_ADD(block, I0, R32Z(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op) + UML_CALLH(block, *m_read32[m_core->mode]); // callh read32 + UML_MOV(block, mem(&m_core->tempdata.w.l), I0); // mov [tempdata],i0 + UML_FDFRFLT(block, F64(G_RD(op)), mem(&m_core->tempdata.w.l), SIZE_DWORD); // fdfrflt fd,[tempdata],dword + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // + return TRUE; + + case 0x257: /* LFDX */ + UML_ADD(block, I0, R32Z(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op) + UML_CALLH(block, *m_read64[m_core->mode]); // callh read64 + UML_DMOV(block, mem(&m_core->tempdata.d), I0); // dmov [tempdata],i0 + UML_FDMOV(block, F64(G_RD(op)), mem(&m_core->tempdata.d)); // fdmov fd,[tempdata] + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // + return TRUE; + + case 0x316: /* LHBRX */ + UML_ADD(block, I0, R32Z(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op) + UML_CALLH(block, *m_read16[m_core->mode]); // callh read16 + UML_BSWAP(block, I0, I0); // bswap i0,i0 + UML_SHR(block, R32(G_RD(op)), I0, 16); // shr rd,i0,16 + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // + return TRUE; + + case 0x216: /* LWBRX */ + UML_ADD(block, I0, R32Z(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op) + UML_CALLH(block, *m_read32align[m_core->mode]); // callh read32align + UML_BSWAP(block, R32(G_RD(op)), I0); // bswap rd,i0 + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // + return TRUE; + + case 0x077: /* LBZUX */ + UML_ADD(block, I0, R32(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb + UML_MOV(block, mem(&m_core->updateaddr), I0); // mov [updateaddr],i0 + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDXU(op)); // mapvar dsisr,DSISR_IDXU(op) + UML_CALLH(block, *m_read8[m_core->mode]); // callh read8 + UML_AND(block, R32(G_RD(op)), I0, 0xff); // and rd,i0,0xff + UML_MOV(block, R32(G_RA(op)), mem(&m_core->updateaddr)); // mov ra,[updateaddr] + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // + return TRUE; + + case 0x137: /* LHZUX */ + UML_ADD(block, I0, R32(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb + UML_MOV(block, mem(&m_core->updateaddr), I0); // mov [updateaddr],i0 + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDXU(op)); // mapvar dsisr,DSISR_IDXU(op) + UML_CALLH(block, *m_read16[m_core->mode]); // callh read16 + UML_AND(block, R32(G_RD(op)), I0, 0xffff); // and rd,i0,0xffff + UML_MOV(block, R32(G_RA(op)), mem(&m_core->updateaddr)); // mov ra,[updateaddr] + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // + return TRUE; + + case 0x177: /* LHAUX */ + UML_ADD(block, I0, R32(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb + UML_MOV(block, mem(&m_core->updateaddr), I0); // mov [updateaddr],i0 + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDXU(op)); // mapvar dsisr,DSISR_IDXU(op) + UML_CALLH(block, *m_read16[m_core->mode]); // callh read16 + UML_SEXT(block, R32(G_RD(op)), I0, SIZE_WORD); // sext rd,i0,word + UML_MOV(block, R32(G_RA(op)), mem(&m_core->updateaddr)); // mov ra,[updateaddr] + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // + return TRUE; + + case 0x037: /* LWZUX */ + UML_ADD(block, I0, R32(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb + UML_MOV(block, mem(&m_core->updateaddr), I0); // mov [updateaddr],i0 + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDXU(op)); // mapvar dsisr,DSISR_IDXU(op) + UML_CALLH(block, *m_read32[m_core->mode]); // callh read32 + UML_MOV(block, R32(G_RD(op)), I0); // mov rd,i0 + UML_MOV(block, R32(G_RA(op)), mem(&m_core->updateaddr)); // mov ra,[updateaddr] + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // + return TRUE; + + case 0x237: /* LFSUX */ + UML_ADD(block, I0, R32(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb + UML_MOV(block, mem(&m_core->updateaddr), I0); // mov [updateaddr],i0 + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op) + UML_CALLH(block, *m_read32[m_core->mode]); // callh read32 + UML_MOV(block, mem(&m_core->tempdata.w.l), I0); // mov [tempdata],i0 + UML_FDFRFLT(block, F64(G_RD(op)), mem(&m_core->tempdata.w.l), SIZE_DWORD); // fdfrflt fd,[tempdata],dword + UML_MOV(block, R32(G_RA(op)), mem(&m_core->updateaddr)); // mov ra,[updateaddr] + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // + return TRUE; + + case 0x277: /* LFDUX */ + UML_ADD(block, I0, R32(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb + UML_MOV(block, mem(&m_core->updateaddr), I0); // mov [updateaddr],i0 + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op) + UML_CALLH(block, *m_read64[m_core->mode]); // callh read64 + UML_DMOV(block, mem(&m_core->tempdata.d), I0); // dmov [tempdata],i0 + UML_FDMOV(block, F64(G_RD(op)), mem(&m_core->tempdata.d)); // fdmov fd,[tempdata] + UML_MOV(block, R32(G_RA(op)), mem(&m_core->updateaddr)); // mov ra,[updateaddr] + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // + return TRUE; + + case 0x014: /* LWARX */ + UML_ADD(block, I0, R32Z(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op) + UML_CALLH(block, *m_read32align[m_core->mode]); // callh read32align + UML_MOV(block, R32(G_RD(op)), I0); // mov rd,i0 + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // + return TRUE; + + case 0x255: /* LSWI */ + UML_MOV(block, mem(&m_core->updateaddr), R32Z(G_RA(op))); // mov [updateaddr],ra + UML_MOV(block, mem(&m_core->swcount), ((G_NB(op) - 1) & 0x1f) + 1); // mov [swcount],G_NB + UML_CALLH(block, *m_lsw[m_core->mode][G_RD(op)]); // call lsw[rd] + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // + return TRUE; + + case 0x215: /* LSWX */ + UML_ADD(block, mem(&m_core->updateaddr), R32Z(G_RA(op)), R32(G_RB(op))); // add [updateaddr],ra,rb + UML_AND(block, mem(&m_core->swcount), SPR32(SPR_XER), 0x7f); // and [swcount],[xer],0x7f + UML_SUB(block, mem(&m_core->icount), mem(&m_core->icount), mem(&m_core->swcount));// sub icount,icount,[swcount] + UML_CALLHc(block, COND_NZ, *m_lsw[m_core->mode][G_RD(op)]); // call lsw[rd],nz + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // + return TRUE; + + case 0x136: /* ECIWX */ + /* not implemented */ + return FALSE; + + case 0x0d7: /* STBX */ + UML_ADD(block, I0, R32Z(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb + UML_AND(block, I1, R32(G_RS(op)), 0xff); // and i1,rs,0xff + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op) + UML_CALLH(block, *m_write8[m_core->mode]); // callh write8 + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // + return TRUE; + + case 0x197: /* STHX */ + UML_ADD(block, I0, R32Z(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb + UML_AND(block, I1, R32(G_RS(op)), 0xffff); // and i1,rs + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op) + UML_CALLH(block, *m_write16[m_core->mode]); // callh write16 + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // + return TRUE; + + case 0x097: /* STWX */ + UML_ADD(block, I0, R32Z(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb + UML_MOV(block, I1, R32(G_RS(op))); // mov i1,rs + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op) + UML_CALLH(block, *m_write32[m_core->mode]); // callh write32 + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // + return TRUE; + + case 0x297: /* STFSX */ + UML_ADD(block, I0, R32Z(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb + UML_FSFRFLT(block, mem(&m_core->tempdata.w.l), F64(G_RS(op)), SIZE_QWORD); // fsfrflt [tempdata],rs,qword + UML_MOV(block, I1, mem(&m_core->tempdata.w.l)); // mov i1,[tempdata] + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op) + UML_CALLH(block, *m_write32[m_core->mode]); // callh write32 + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // + return TRUE; + + case 0x3d7: /* STFIWX */ + UML_ADD(block, I0, R32Z(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb + UML_FDMOV(block, mem(&m_core->tempdata.d), F64(G_RS(op))); // fdmov [tempdata],rs + UML_MOV(block, I1, mem(&m_core->tempdata.w.l)); // mov i1,[tempdata.lo] + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op) + UML_CALLH(block, *m_write32[m_core->mode]); // callh write32 + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // + return TRUE; + + case 0x2d7: /* STFDX */ + UML_ADD(block, I0, R32Z(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb + UML_FDMOV(block, mem(&m_core->tempdata.d), F64(G_RS(op))); // fdmov [tempdata],rs + UML_DMOV(block, I1, mem(&m_core->tempdata.d)); // dmov i1,[tempdata] + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op) + UML_CALLH(block, *m_write64[m_core->mode]); // callh write64 + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // + return TRUE; + + case 0x396: /* STHBRX */ + UML_ADD(block, I0, R32Z(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb + UML_BSWAP(block, I1, R32(G_RS(op))); // bswap i1,rs + UML_SHR(block, I1, I1, 16); // shr i1,i1,16 + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op) + UML_CALLH(block, *m_write16[m_core->mode]); // callh write16 + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // + return TRUE; + + case 0x296: /* STWBRX */ + UML_ADD(block, I0, R32Z(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb + UML_BSWAP(block, I1, R32(G_RS(op))); // bswap i1,rs + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op) + UML_CALLH(block, *m_write32[m_core->mode]); // callh write32 + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // + return TRUE; + + case 0x0f7: /* STBUX */ + UML_ADD(block, I0, R32(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb + UML_AND(block, I1, R32(G_RS(op)), 0xff); // and i1,rs,0xff + UML_MOV(block, mem(&m_core->updateaddr), I0); // mov [updateaddr],i0 + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op) + UML_CALLH(block, *m_write8[m_core->mode]); // callh write8 + UML_MOV(block, R32(G_RA(op)), mem(&m_core->updateaddr)); // mov ra,[updateaddr] + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // + return TRUE; + + case 0x1b7: /* STHUX */ + UML_ADD(block, I0, R32(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb + UML_AND(block, I1, R32(G_RS(op)), 0xffff); // and i1,rs,0xffff + UML_MOV(block, mem(&m_core->updateaddr), I0); // mov [updateaddr],i0 + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op) + UML_CALLH(block, *m_write16[m_core->mode]); // callh write16 + UML_MOV(block, R32(G_RA(op)), mem(&m_core->updateaddr)); // mov ra,[updateaddr] + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // + return TRUE; + + case 0x0b7: /* STWUX */ + UML_ADD(block, I0, R32(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb + UML_MOV(block, I1, R32(G_RS(op))); // mov i1,rs + UML_MOV(block, mem(&m_core->updateaddr), I0); // mov [updateaddr],i0 + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDXU(op)); // mapvar dsisr,DSISR_IDXU(op) + UML_CALLH(block, *m_write32[m_core->mode]); // callh write32 + UML_MOV(block, R32(G_RA(op)), mem(&m_core->updateaddr)); // mov ra,[updateaddr] + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // + return TRUE; + + case 0x2b7: /* STFSUX */ + UML_ADD(block, I0, R32(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb + UML_FSFRFLT(block, mem(&m_core->tempdata.w.l), F64(G_RS(op)), SIZE_QWORD); // fsfrflt [tempdata],rs,qword + UML_MOV(block, I1, mem(&m_core->tempdata.w.l)); // mov i1,[tempdata] + UML_MOV(block, mem(&m_core->updateaddr), I0); // mov [updateaddr],i0 + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op) + UML_CALLH(block, *m_write32[m_core->mode]); // callh write32 + UML_MOV(block, R32(G_RA(op)), mem(&m_core->updateaddr)); // mov ra,[updateaddr] + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // + return TRUE; + + case 0x2f7: /* STFDUX */ + UML_ADD(block, I0, R32(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb + UML_FDMOV(block, mem(&m_core->tempdata.d), F64(G_RS(op))); // fdmov [tempdata],rs + UML_DMOV(block, I1, mem(&m_core->tempdata.d)); // dmov i1,[tempdata] + UML_MOV(block, mem(&m_core->updateaddr), I0); // mov [updateaddr],i0 + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op) + UML_CALLH(block, *m_write64[m_core->mode]); // callh write64 + UML_MOV(block, R32(G_RA(op)), mem(&m_core->updateaddr)); // mov ra,[updateaddr] + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // + return TRUE; + + case 0x096: /* STWCX. */ + UML_ADD(block, I0, R32Z(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb + UML_MOV(block, I1, R32(G_RS(op))); // mov i1,rs + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op) + UML_CALLH(block, *m_write32align[m_core->mode]); // callh write32align + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // + + UML_CMP(block, I0, I0); // cmp i0,i0 + UML_GETFLGS(block, I0, FLAG_Z | FLAG_C | FLAG_S); // getflgs i0,zcs + UML_LOAD(block, I0, m_cmp_cr_table, I0, SIZE_BYTE, SCALE_x1);// load i0,cmp_cr_table,i0,byte + UML_OR(block, CR32(0), I0, XERSO32); // or [cr0],i0,[xerso] + + generate_compute_flags(block, desc, TRUE, 0, FALSE); // + return TRUE; + + case 0x2d5: /* STSWI */ + UML_MOV(block, mem(&m_core->updateaddr), R32Z(G_RA(op))); // mov [updateaddr],ra + UML_MOV(block, mem(&m_core->swcount), ((G_NB(op) - 1) & 0x1f) + 1); // mov [swcount],G_NB + UML_CALLH(block, *m_stsw[m_core->mode][G_RD(op)]); // call stsw[rd] + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // + return TRUE; + + case 0x295: /* STSWX */ + UML_ADD(block, mem(&m_core->updateaddr), R32Z(G_RA(op)), R32(G_RB(op))); // add [updateaddr],ra,rb + UML_AND(block, mem(&m_core->swcount), SPR32(SPR_XER), 0x7f); // and [swcount],[xer],0x7f + UML_SUB(block, mem(&m_core->icount), mem(&m_core->icount), mem(&m_core->swcount));// sub icount,icount,[swcount] + UML_CALLHc(block, COND_NZ, *m_stsw[m_core->mode][G_RD(op)]); // call stsw[rd] + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // + return TRUE; + + case 0x1b6: /* ECOWX */ + /* not implemented */ + return FALSE; + + case 0x036: /* DCBST */ + UML_ADD(block, I0, R32Z(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb + UML_MOV(block, mem(&m_core->param0), I0); // mov [param0],i0 + UML_CALLC(block, (c_function)cfunc_ppccom_dcstore_callback, this); + return TRUE; + + case 0x056: /* DCBF */ + case 0x0f6: /* DCBTST */ + case 0x116: /* DCBT */ + case 0x3d6: /* ICBI */ + case 0x256: /* SYNC */ + case 0x356: /* EIEIO */ + case 0x1d6: /* DCBI */ + case 0x236: /* TLBSYNC */ + /* effective no-ops */ + return TRUE; + + case 0x3f6: /* DCBZ */ + UML_ADD(block, I0, R32Z(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb + UML_AND(block, mem(&m_core->tempaddr), I0, ~(m_cache_line_size - 1)); + // and [tempaddr],i0,~(cache_line_size - 1) + for (item = 0; item < m_cache_line_size / 8; item++) + { + UML_ADD(block, I0, mem(&m_core->tempaddr), 8 * item); // add i0,[tempaddr],8*item + UML_DMOV(block, I1, 0); // dmov i1,0 + UML_CALLH(block, *m_write64[m_core->mode]); // callh write64 + } + return TRUE; + + case 0x132: /* TLBIE */ + UML_MOV(block, mem(&m_core->param0), R32(G_RB(op))); // mov [param0],rb + UML_CALLC(block, (c_function)cfunc_ppccom_execute_tlbie, this); // callc ppccom_execute_tlbie,ppc + return TRUE; + + case 0x172: /* TLBIA */ + UML_CALLC(block, (c_function)cfunc_ppccom_execute_tlbia, this); // callc ppccom_execute_tlbia,ppc + return TRUE; + + case 0x3d2: /* TLBLD */ + assert(m_cap & PPCCAP_603_MMU); + UML_MOV(block, mem(&m_core->param0), R32(G_RB(op))); // mov [param0],rb + UML_MOV(block, mem(&m_core->param1), 0); // mov [param1],0 + UML_CALLC(block, (c_function)cfunc_ppccom_execute_tlbl, this); // callc ppccom_execute_tlbl,ppc + return TRUE; + + case 0x3f2: /* TLBLI */ + assert(m_cap & PPCCAP_603_MMU); + UML_MOV(block, mem(&m_core->param0), R32(G_RB(op))); // mov [param0],rb + UML_MOV(block, mem(&m_core->param1), 1); // mov [param1],1 + UML_CALLC(block, (c_function)cfunc_ppccom_execute_tlbl, this); // callc ppccom_execute_tlbl,ppc + return TRUE; + + case 0x013: /* MFCR */ + UML_SHL(block, I0, CR32(0), 28); // shl i0,cr(0),28 + UML_ROLAND(block, I1, CR32(1), 24, 0x0f000000); // roland i1,cr(1),24,0x0f000000 + UML_OR(block, I0, I0, I1); // or i0,i0,i1 + UML_ROLAND(block, I1, CR32(2), 20, 0x00f00000); // roland i1,cr(2),20,0x00f00000 + UML_OR(block, I0, I0, I1); // or i0,i0,i1 + UML_ROLAND(block, I1, CR32(3), 16, 0x000f0000); // roland i1,cr(3),16,0x000f0000 + UML_OR(block, I0, I0, I1); // or i0,i0,i1 + UML_ROLAND(block, I1, CR32(4), 12, 0x0000f000); // roland i1,cr(4),12,0x0000f000 + UML_OR(block, I0, I0, I1); // or i0,i0,i1 + UML_ROLAND(block, I1, CR32(5), 8, 0x00000f00); // roland i1,cr(5),8,0x00000f00 + UML_OR(block, I0, I0, I1); // or i0,i0,i1 + UML_ROLAND(block, I1, CR32(6), 4, 0x000000f0); // roland i1,cr(6),4,0x000000f0 + UML_OR(block, I0, I0, I1); // or i0,i0,i1 + UML_ROLAND(block, I1, CR32(7), 0, 0x0000000f); // roland i1,cr(7),0,0x0000000f + UML_OR(block, R32(G_RD(op)), I0, I1); // or rd,i0,i1 + return TRUE; + + case 0x053: /* MFMSR */ + UML_MOV(block, R32(G_RD(op)), MSR32); // mov rd,msr + return TRUE; + + case 0x153: /* MFSPR */ + { + UINT32 spr = compute_spr(G_SPR(op)); + if (spr == SPR_LR || spr == SPR_CTR || (spr >= SPROEA_SPRG0 && spr <= SPROEA_SPRG3)) + UML_MOV(block, R32(G_RD(op)), SPR32(spr)); // mov rd,spr + else if (spr == SPR_XER) + { + UML_SHL(block, I0, XERSO32, 31); // shl i0,[xerso],31 + UML_OR(block, R32(G_RD(op)), SPR32(spr), I0); // or [rd],[xer],i0 + } + else if (spr == SPROEA_PVR) + UML_MOV(block, R32(G_RD(op)), m_flavor); // mov rd,flavor + else + { + generate_update_cycles(block, compiler, desc->pc, TRUE); // + UML_MOV(block, mem(&m_core->param0), spr); // mov [param0],spr + UML_CALLC(block, (c_function)cfunc_ppccom_execute_mfspr, this); // callc ppccom_execute_mfspr,ppc + UML_MOV(block, R32(G_RD(op)), mem(&m_core->param1)); // mov rd,[param1] + } + return TRUE; + } + + case 0x253: /* MFSR */ + UML_MOV(block, R32(G_RD(op)), SR32(G_SR(op))); // mov rd,sr + return TRUE; + + case 0x293: /* MFSRIN */ + UML_SHR(block, I0, R32(G_RB(op)), 28); // shr i0,G_RB,28 + UML_LOAD(block, R32(G_RD(op)), &m_core->sr[0], I0, SIZE_DWORD, SCALE_x4); // load rd,sr,i0,dword + return TRUE; + + case 0x173: /* MFTB */ + { + UINT32 tbr = compute_spr(G_SPR(op)); + if (tbr != SPRVEA_TBL_R && tbr != SPRVEA_TBU_R) + return FALSE; + generate_update_cycles(block, compiler, desc->pc, TRUE); // + UML_MOV(block, mem(&m_core->param0), tbr); // mov [param0],tbr + UML_CALLC(block, (c_function)cfunc_ppccom_execute_mftb, this); // callc ppccom_execute_mftb,ppc + UML_MOV(block, R32(G_RD(op)), mem(&m_core->param1)); // mov rd,[param1] + return TRUE; + } + + case 0x090: /* MTCRF */ + UML_MOV(block, I0, R32(G_RS(op))); // mov i0,rs + if (G_CRM(op) & 0x80) UML_ROLAND(block, CR32(0), I0, 4, 0xf); // roland cr(0),i0,4,0x0f + if (G_CRM(op) & 0x40) UML_ROLAND(block, CR32(1), I0, 8, 0xf); // roland cr(1),i0,8,0x0f + if (G_CRM(op) & 0x20) UML_ROLAND(block, CR32(2), I0, 12, 0xf); // roland cr(2),i0,12,0x0f + if (G_CRM(op) & 0x10) UML_ROLAND(block, CR32(3), I0, 16, 0xf); // roland cr(3),i0,16,0x0f + if (G_CRM(op) & 0x08) UML_ROLAND(block, CR32(4), I0, 20, 0xf); // roland cr(4),i0,20,0x0f + if (G_CRM(op) & 0x04) UML_ROLAND(block, CR32(5), I0, 24, 0xf); // roland cr(5),i0,24,0x0f + if (G_CRM(op) & 0x02) UML_ROLAND(block, CR32(6), I0, 28, 0xf); // roland cr(6),i0,28,0x0f + if (G_CRM(op) & 0x01) UML_ROLAND(block, CR32(7), I0, 0, 0xf); // roland cr(7),i0,0,0x0f + return TRUE; + + case 0x092: /* MTMSR */ + if (m_cap & PPCCAP_603_MMU) + UML_XOR(block, I0, MSR32, R32(G_RS(op))); // xor i0,msr32,rs + UML_MOV(block, MSR32, R32(G_RS(op))); // mov msr,rs + if (m_cap & PPCCAP_603_MMU) + { + UML_TEST(block, I0, MSR603_TGPR); // test i0,tgpr + UML_CALLHc(block, COND_NZ, *m_swap_tgpr); // callh swap_tgpr,nz + } + generate_update_mode(block); // + return TRUE; + + case 0x1d3: /* MTSPR */ + { + UINT32 spr = compute_spr(G_SPR(op)); + if (spr == SPR_LR || spr == SPR_CTR || (spr >= SPROEA_SPRG0 && spr <= SPROEA_SPRG3)) + UML_MOV(block, SPR32(spr), R32(G_RS(op))); // mov spr,rs + else if (spr == SPR_XER) + { + UML_AND(block, SPR32(spr), R32(G_RS(op)), ~XER_SO); // and spr,rs,~XER_SO + UML_SHR(block, XERSO32, R32(G_RS(op)), 31); // shr [xerso],rs,31 + } + else if (spr == SPROEA_PVR) + ; // read only + else + { + generate_update_cycles(block, compiler, desc->pc, TRUE); // + UML_MOV(block, mem(&m_core->param0), spr); // mov [param0],spr + UML_MOV(block, mem(&m_core->param1), R32(G_RS(op))); // mov [param1],rs + UML_CALLC(block, (c_function)cfunc_ppccom_execute_mtspr, this); // callc ppccom_execute_mtspr,ppc + compiler->checkints = TRUE; + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // + } + return TRUE; + } + + case 0x0d2: /* MTSR */ + UML_MOV(block, SR32(G_SR(op)), R32(G_RS(op))); // mov sr[G_SR],rs + UML_CALLC(block, (c_function)cfunc_ppccom_tlb_flush, this); // callc ppccom_tlb_flush,ppc + return TRUE; + + case 0x0f2: /* MTSRIN */ + UML_SHR(block, I0, R32(G_RB(op)), 28); // shr i0,G_RB,28 + UML_STORE(block, &m_core->sr[0], I0, R32(G_RS(op)), SIZE_DWORD, SCALE_x4); // store sr,i0,rs,dword + UML_CALLC(block, (c_function)cfunc_ppccom_tlb_flush, this); // callc ppccom_tlb_flush,ppc + return TRUE; + + case 0x200: /* MCRXR */ + UML_ROLAND(block, I0, SPR32(SPR_XER), 28, 0x0f); // roland i0,[xer],28,0x0f + UML_SHL(block, I1, XERSO32, 3); // shl i1,[xerso],3 + UML_OR(block, CR32(G_CRFD(op)), I0, I1); // or [crd],i0,i1 + UML_AND(block, SPR32(SPR_XER), SPR32(SPR_XER), ~0xf0000000); // and [xer],[xer],~0xf0000000 + UML_MOV(block, XERSO32, 0); // mov [xerso],0 + return TRUE; + + case 0x106: /* ICBT */ + case 0x1c6: /* DCCCI */ + case 0x3c6: /* ICCCI */ + assert(m_cap & PPCCAP_4XX); + /* effective no-nop */ + return TRUE; + + case 0x1e6: /* DCREAD */ + case 0x3e6: /* ICREAD */ + assert(m_cap & PPCCAP_4XX); + UML_MOV(block, R32(G_RT(op)), 0); // mov rt,0 + return TRUE; + + case 0x143: /* MFDCR */ + { + UINT32 spr = compute_spr(G_SPR(op)); + assert(m_cap & PPCCAP_4XX); + generate_update_cycles(block, compiler, desc->pc, TRUE); // + UML_MOV(block, mem(&m_core->param0), spr); // mov [param0],spr + UML_CALLC(block, (c_function)cfunc_ppccom_execute_mfdcr, this); // callc ppccom_execute_mfdcr,ppc + UML_MOV(block, R32(G_RD(op)), mem(&m_core->param1)); // mov rd,[param1] + return TRUE; + } + + case 0x1c3: /* MTDCR */ + { + UINT32 spr = compute_spr(G_SPR(op)); + assert(m_cap & PPCCAP_4XX); + generate_update_cycles(block, compiler, desc->pc, TRUE); // + UML_MOV(block, mem(&m_core->param0), spr); // mov [param0],spr + UML_MOV(block, mem(&m_core->param1), R32(G_RS(op))); // mov [param1],rs + UML_CALLC(block, (c_function)cfunc_ppccom_execute_mtdcr, this); // callc ppccom_execute_mtdcr,ppc + compiler->checkints = TRUE; + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // + return TRUE; + } + + case 0x083: /* WRTEE */ + assert(m_cap & PPCCAP_4XX); + UML_ROLINS(block, MSR32, R32(G_RS(op)), 0, MSR_EE); // rolins msr,rs,0,MSR_EE + compiler->checkints = TRUE; + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // + return TRUE; + + case 0x0a3: /* WRTEEI */ + assert(m_cap & PPCCAP_4XX); + if (op & MSR_EE) + { + UML_OR(block, MSR32, MSR32, MSR_EE); // or msr,msr,MSR_EE + compiler->checkints = TRUE; + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); // + } + else + UML_AND(block, MSR32, MSR32, ~MSR_EE); // and msr,msr,~MSR_EE + return TRUE; + + case 0x254: /* ESA */ + case 0x274: /* DSA */ + /* no-op for now */ + return TRUE; + } + + return FALSE; +} + + +/*------------------------------------------------- + generate_instruction_3b - compile opcodes in + the 0x3b group +-------------------------------------------------*/ + +int ppc_device::generate_instruction_3b(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) +{ + UINT32 op = desc->opptr.l[0]; + UINT32 opswitch = (op >> 1) & 0x1f; + + switch (opswitch) + { + case 0x15: /* FADDSx */ + if (!(m_drcoptions & PPCDRC_ACCURATE_SINGLES)) + return generate_instruction_3f(block, compiler, desc); + UML_FDADD(block, F0, F64(G_RA(op)), F64(G_RB(op))); // fdadd f0,ra,rb + UML_FDRNDS(block, F64(G_RD(op)), F0); // fdrnds rd,f0 + generate_fp_flags(block, desc, TRUE); + return TRUE; + + case 0x14: /* FSUBSx */ + if (!(m_drcoptions & PPCDRC_ACCURATE_SINGLES)) + return generate_instruction_3f(block, compiler, desc); + UML_FDSUB(block, F0, F64(G_RA(op)), F64(G_RB(op))); // fdsub f0,ra,rb + UML_FDRNDS(block, F64(G_RD(op)), F0); // fdrnds rd,f0 + generate_fp_flags(block, desc, TRUE); + return TRUE; + + case 0x19: /* FMULSx */ + if (!(m_drcoptions & PPCDRC_ACCURATE_SINGLES)) + return generate_instruction_3f(block, compiler, desc); + UML_FDMUL(block, F0, F64(G_RA(op)), F64(G_REGC(op))); // fdmul f0,ra,rc + UML_FDRNDS(block, F64(G_RD(op)), F0); // fdrnds rd,f0 + generate_fp_flags(block, desc, TRUE); + return TRUE; + + case 0x12: /* FDIVSx */ + if (!(m_drcoptions & PPCDRC_ACCURATE_SINGLES)) + return generate_instruction_3f(block, compiler, desc); + UML_FDDIV(block, F0, F64(G_RA(op)), F64(G_RB(op))); // fddiv f0,ra,rb + UML_FDRNDS(block, F64(G_RD(op)), F0); // fdrnds rd,f0 + generate_fp_flags(block, desc, TRUE); + return TRUE; + + case 0x16: /* FSQRTSx */ + if (!(m_drcoptions & PPCDRC_ACCURATE_SINGLES)) + return generate_instruction_3f(block, compiler, desc); + UML_FDSQRT(block, F0, F64(G_RB(op))); // fdsqrt f0,rb + UML_FDRNDS(block, F64(G_RD(op)), F0); // fdrnds rd,f0 + generate_fp_flags(block, desc, TRUE); + return TRUE; + + case 0x18: /* FRESx */ + UML_FSFRFLT(block, F0, F64(G_RB(op)), SIZE_QWORD); // fsfrlt f0,rb,qword + UML_FSRECIP(block, F0, F0); // fsrecip f0,f0 + UML_FDFRFLT(block, F64(G_RD(op)), F0, SIZE_DWORD); // fdfrflt rd,f0,dword + generate_fp_flags(block, desc, TRUE); + return TRUE; + + case 0x1d: /* FMADDSx */ + if (!(m_drcoptions & PPCDRC_ACCURATE_SINGLES)) + return generate_instruction_3f(block, compiler, desc); + UML_FDMUL(block, F0, F64(G_RA(op)), F64(G_REGC(op))); // fdmul f0,ra,rc + UML_FDADD(block, F0, F0, F64(G_RB(op))); // fdadd f0,f0,rb + UML_FDRNDS(block, F64(G_RD(op)), F0); // fdrnds rd,f0 + generate_fp_flags(block, desc, TRUE); + return TRUE; + + case 0x1c: /* FMSUBSx */ + if (!(m_drcoptions & PPCDRC_ACCURATE_SINGLES)) + return generate_instruction_3f(block, compiler, desc); + UML_FDMUL(block, F0, F64(G_RA(op)), F64(G_REGC(op))); // fdmul f0,ra,rc + UML_FDSUB(block, F0, F0, F64(G_RB(op))); // fdsub f0,f0,rb + UML_FDRNDS(block, F64(G_RD(op)), F0); // fdrnds rd,f0 + generate_fp_flags(block, desc, TRUE); + return TRUE; + + case 0x1f: /* FNMADDSx */ + if (!(m_drcoptions & PPCDRC_ACCURATE_SINGLES)) + return generate_instruction_3f(block, compiler, desc); + UML_FDMUL(block, F0, F64(G_RA(op)), F64(G_REGC(op))); // fdmul f0,ra,rc + UML_FDADD(block, F0, F0, F64(G_RB(op))); // fdadd f0,f0,rb + UML_FDNEG(block, F0, F0); // fdneg f0,f0 + UML_FDRNDS(block, F64(G_RD(op)), F0); // fdrnds rd,f0 + generate_fp_flags(block, desc, TRUE); + return TRUE; + + case 0x1e: /* FNMSUBSx */ + if (!(m_drcoptions & PPCDRC_ACCURATE_SINGLES)) + return generate_instruction_3f(block, compiler, desc); + UML_FDMUL(block, F0, F64(G_RA(op)), F64(G_REGC(op))); // fdmul f0,ra,rc + UML_FDSUB(block, F0, F64(G_RB(op)), F0); // fdsub f0,rb,f0 + UML_FDRNDS(block, F64(G_RD(op)), F0); // fdrnds rd,f0 + generate_fp_flags(block, desc, TRUE); + return TRUE; + } + + return FALSE; +} + + + +/*------------------------------------------------- + generate_instruction_3f - compile opcodes in + the 0x3f group +-------------------------------------------------*/ + +int ppc_device::generate_instruction_3f(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) +{ + UINT32 op = desc->opptr.l[0]; + UINT32 opswitch = (op >> 1) & 0x3ff; + + if (opswitch & 0x10) + { + opswitch &= 0x1f; + switch (opswitch) + { + case 0x15: /* FADDx */ + UML_FDADD(block, F64(G_RD(op)), F64(G_RA(op)), F64(G_RB(op))); // fdadd rd,ra,rb + generate_fp_flags(block, desc, TRUE); + return TRUE; + + case 0x14: /* FSUBx */ + UML_FDSUB(block, F64(G_RD(op)), F64(G_RA(op)), F64(G_RB(op))); // fdsub rd,ra,rb + generate_fp_flags(block, desc, TRUE); + return TRUE; + + case 0x19: /* FMULx */ + UML_FDMUL(block, F64(G_RD(op)), F64(G_RA(op)), F64(G_REGC(op))); // fdmul rd,ra,rc + generate_fp_flags(block, desc, TRUE); + return TRUE; + + case 0x12: /* FDIVx */ + UML_FDDIV(block, F64(G_RD(op)), F64(G_RA(op)), F64(G_RB(op))); // fddiv rd,ra,rb + generate_fp_flags(block, desc, TRUE); + return TRUE; + + case 0x16: /* FSQRTx */ + UML_FDSQRT(block, F64(G_RD(op)), F64(G_RB(op))); // fdsqrt rd,rb + generate_fp_flags(block, desc, TRUE); + return TRUE; + + case 0x1a: /* FRSQRTEx */ + UML_FDRSQRT(block, F64(G_RD(op)), F64(G_RB(op))); // fdrsqrt rd,rb + generate_fp_flags(block, desc, TRUE); + return TRUE; + + case 0x17: /* FSELx */ + UML_FDCMP(block, F64(G_RA(op)), mem(&m_core->fp0)); // fdcmp f0,ra,[fp0] + UML_FDMOVc(block, COND_AE, F64(G_RD(op)), F64(G_REGC(op))); // fdmov rd,rc,AE + UML_FDMOVc(block, COND_B, F64(G_RD(op)), F64(G_RB(op))); // fdmov rd,rb,B + return TRUE; + + case 0x1d: /* FMADDx */ + UML_FDMUL(block, F0, F64(G_RA(op)), F64(G_REGC(op))); // fdmul f0,ra,rc + UML_FDADD(block, F64(G_RD(op)), F0, F64(G_RB(op))); // fdadd rd,f0,rb + generate_fp_flags(block, desc, TRUE); + return TRUE; + + case 0x1f: /* FNMADDx */ + UML_FDMUL(block, F0, F64(G_RA(op)), F64(G_REGC(op))); // fdmul f0,ra,rc + UML_FDADD(block, F0, F0, F64(G_RB(op))); // fdadd f0,f0,rb + UML_FDNEG(block, F64(G_RD(op)), F0); // fdneg rd,f0 + generate_fp_flags(block, desc, TRUE); + return TRUE; + + case 0x1c: /* FMSUBx */ + UML_FDMUL(block, F0, F64(G_RA(op)), F64(G_REGC(op))); // fdmul f0,ra,rc + UML_FDSUB(block, F64(G_RD(op)), F0, F64(G_RB(op))); // fdsub rd,f0,rb + generate_fp_flags(block, desc, TRUE); + return TRUE; + + case 0x1e: /* FNMSUBx */ + UML_FDMUL(block, F0, F64(G_RA(op)), F64(G_REGC(op))); // fdmul f0,ra,rc + UML_FDSUB(block, F64(G_RD(op)), F64(G_RB(op)), F0); // fdsub rd,rb,f0 + generate_fp_flags(block, desc, TRUE); + return TRUE; + } + } + else + { + switch (opswitch) + { + case 0x32e: /* FCTIDx - 64-bit only */ + case 0x32f: /* FCTIDZx - 64-bit only */ + case 0x34e: /* FCFIDx - 64-bit only */ + return FALSE; + + case 0x000: /* FCMPU */ + case 0x020: /* FCMPO */ + UML_FDCMP(block, F64(G_RA(op)), F64(G_RB(op))); // fdcmp ra,rb + UML_GETFLGS(block, I0, FLAG_C | FLAG_Z | FLAG_U); // getflgs i0,czu + UML_LOAD(block, I0, m_fcmp_cr_table, I0, SIZE_BYTE, SCALE_x1);// load i0,fcmp_cr_table,i0,byte + UML_OR(block, CR32(G_CRFD(op)), I0, XERSO32); // or [crn],i0,[xerso] + return TRUE; + + case 0x00c: /* FRSPx */ + UML_FDRNDS(block, F64(G_RD(op)), F64(G_RB(op))); // fdrnds rd,rb + generate_fp_flags(block, desc, TRUE); + return TRUE; + + case 0x00e: /* FCTIWx */ + UML_FDTOINT(block, I0, F64(G_RB(op)), SIZE_DWORD, ROUND_DEFAULT); // fdtoint i0,rb,dword,default + UML_DAND(block, mem(&m_core->tempdata.w.l), I0, 0xffffffff);// dand i0,i0,0xffffffff + UML_FDMOV(block, F64(G_RD(op)), mem(&m_core->tempdata.w.l)); // fdmovr rd,i0 + return TRUE; + + case 0x00f: /* FCTIWZx */ + UML_FDTOINT(block, I0, F64(G_RB(op)), SIZE_DWORD, ROUND_TRUNC); // fdtoint i0,rb,dword,default + UML_DAND(block, mem(&m_core->tempdata.w.l), I0, 0xffffffff);// dand i0,i0,0xffffffff + UML_FDMOV(block, F64(G_RD(op)), mem(&m_core->tempdata.w.l)); // fdmovr rd,i0 + return TRUE; + + case 0x028: /* FNEGx */ + UML_FDNEG(block, F64(G_RD(op)), F64(G_RB(op))); // fdneg rd,rb + return TRUE; + + case 0x048: /* FMRx */ + UML_FDMOV(block, F64(G_RD(op)), F64(G_RB(op))); // fdmov rd,rb + return TRUE; + + case 0x088: /* FNABSx */ + UML_FDABS(block, F0, F64(G_RB(op))); // fdabs f0,rb + UML_FDNEG(block, F64(G_RD(op)), F0); // fdneg rd,f0 + return TRUE; + + case 0x108: /* FABSx */ + UML_FDABS(block, F64(G_RD(op)), F64(G_RB(op))); // fdabs rd,rb + return TRUE; + + case 0x046: /* MTFSB0x */ + UML_AND(block, FPSCR32, FPSCR32, ~(0x80000000 >> G_CRBD(op))); // and fpscr32,fpscr32,~(0x80000000 >> G_CRBD) + return TRUE; + + case 0x026: /* MTFSB1x */ + UML_OR(block, FPSCR32, FPSCR32, 0x80000000 >> G_CRBD(op)); // or fpscr32,fpscr32,(0x80000000 >> G_CRBD) + return TRUE; + + case 0x040: /* MCRFS */ + UML_ROLAND(block, CR32(G_CRFD(op)), FPSCR32, ((G_CRFS(op) - 7) & 7) * 4, 0x0f); + // roland [crd],[fpscr],shift,0x0f + UML_AND(block, FPSCR32, FPSCR32, ~CRMASK(G_CRFS(op))); // and fpscr,fpscr,~crmask[crfs] + return TRUE; + + case 0x247: /* MFFSx */ + UML_MOV(block, mem(&m_core->tempdata.w.l), FPSCR32); // mov [tempdata],fpscr + UML_FSMOV(block, F64(G_RD(op)), mem(&m_core->tempdata.d)); // fsmov rd,fpscr + return TRUE; + + case 0x2c7: /* MTFSFx */ + UML_FDMOV(block, mem(&m_core->tempdata.d), F64(G_RB(op))); // fdmov [tempdata],fb + UML_ROLINS(block, FPSCR32, mem(&m_core->tempdata.w.l), 0, compute_crf_mask(G_FM(op))); + // rolins fpscr,rb,0,crf_mask + return TRUE; + + case 0x086: /* MTFSFIx */ + UML_ROLINS(block, FPSCR32, G_IMM(op), 28 - 4 * G_CRFD(op), CRMASK(G_CRFD(op))); + // rolins fpscr,rb,0,crf_mask + return TRUE; + } + } + + return FALSE; +} + + + +/*************************************************************************** + CODE LOGGING HELPERS +***************************************************************************/ + +/*------------------------------------------------- + log_add_disasm_comment - add a comment + including disassembly of a PowerPC instruction +-------------------------------------------------*/ + +void ppc_device::log_add_disasm_comment(drcuml_block *block, UINT32 pc, UINT32 op) +{ + char buffer[100]; + if (m_drcuml->logging()) + { + ppc_dasm_one(buffer, pc, op); + block->append_comment("%08X: %s", pc, buffer); // comment + } +} + + +/*------------------------------------------------- + log_desc_flags_to_string - generate a string + representing the instruction description + flags +-------------------------------------------------*/ + +const char *ppc_device::log_desc_flags_to_string(UINT32 flags) +{ + static char tempbuf[30]; + char *dest = tempbuf; + + /* branches */ + if (flags & OPFLAG_IS_UNCONDITIONAL_BRANCH) + *dest++ = 'U'; + else if (flags & OPFLAG_IS_CONDITIONAL_BRANCH) + *dest++ = 'C'; + else + *dest++ = '.'; + + /* intrablock branches */ + *dest++ = (flags & OPFLAG_INTRABLOCK_BRANCH) ? 'i' : '.'; + + /* branch targets */ + *dest++ = (flags & OPFLAG_IS_BRANCH_TARGET) ? 'B' : '.'; + + /* delay slots */ + *dest++ = (flags & OPFLAG_IN_DELAY_SLOT) ? 'D' : '.'; + + /* exceptions */ + if (flags & OPFLAG_WILL_CAUSE_EXCEPTION) + *dest++ = 'E'; + else if (flags & OPFLAG_CAN_CAUSE_EXCEPTION) + *dest++ = 'e'; + else + *dest++ = '.'; + + /* read/write */ + if (flags & OPFLAG_READS_MEMORY) + *dest++ = 'R'; + else if (flags & OPFLAG_WRITES_MEMORY) + *dest++ = 'W'; + else + *dest++ = '.'; + + /* TLB validation */ + *dest++ = (flags & OPFLAG_VALIDATE_TLB) ? 'V' : '.'; + + /* TLB modification */ + *dest++ = (flags & OPFLAG_MODIFIES_TRANSLATION) ? 'T' : '.'; + + /* redispatch */ + *dest++ = (flags & OPFLAG_REDISPATCH) ? 'R' : '.'; + return tempbuf; +} + + +/*------------------------------------------------- + log_register_list - log a list of GPR registers +-------------------------------------------------*/ + +void ppc_device::log_register_list(drcuml_state *drcuml, const char *string, const UINT32 *reglist, const UINT32 *regnostarlist) +{ + static const char *const crtext[4] = { "lt", "gt", "eq", "so" }; + int count = 0; + int regnum; + int crnum; + + /* skip if nothing */ + if (reglist[0] == 0 && reglist[1] == 0 && reglist[2] == 0 && reglist[3] == 0) + return; + + drcuml->log_printf("[%s:", string); + + for (regnum = 0; regnum < 32; regnum++) + if (reglist[0] & REGFLAG_R(regnum)) + { + drcuml->log_printf("%sr%d", (count++ == 0) ? "" : ",", regnum); + if (regnostarlist != NULL && !(regnostarlist[0] & REGFLAG_R(regnum))) + drcuml->log_printf("*"); + } + + for (regnum = 0; regnum < 32; regnum++) + if (reglist[1] & REGFLAG_FR(regnum)) + { + drcuml->log_printf("%sfr%d", (count++ == 0) ? "" : ",", regnum); + if (regnostarlist != NULL && !(regnostarlist[1] & REGFLAG_FR(regnum))) + drcuml->log_printf("*"); + } + + for (regnum = 0; regnum < 8; regnum++) + if (reglist[2] & REGFLAG_CR(regnum)) + { + if ((reglist[2] & REGFLAG_CR(regnum)) == REGFLAG_CR(regnum) && (regnostarlist == NULL || (regnostarlist[2] & REGFLAG_CR(regnum)) == REGFLAG_CR(regnum))) + { + drcuml->log_printf("%scr%d", (count++ == 0) ? "" : ",", regnum); + if (regnostarlist != NULL && !(regnostarlist[2] & REGFLAG_CR(regnum))) + drcuml->log_printf("*"); + } + else + { + for (crnum = 0; crnum < 4; crnum++) + if (reglist[2] & REGFLAG_CR_BIT(regnum * 4 + crnum)) + { + drcuml->log_printf("%scr%d[%s]", (count++ == 0) ? "" : ",", regnum, crtext[crnum]); + if (regnostarlist != NULL && !(regnostarlist[2] & REGFLAG_CR_BIT(regnum * 4 + crnum))) + drcuml->log_printf("*"); + } + } + } + + if (reglist[3] & REGFLAG_XER_CA) + { + drcuml->log_printf("%sxer_ca", (count++ == 0) ? "" : ","); + if (regnostarlist != NULL && !(regnostarlist[3] & REGFLAG_XER_CA)) + drcuml->log_printf("*"); + } + if (reglist[3] & REGFLAG_XER_OV) + { + drcuml->log_printf("%sxer_ov", (count++ == 0) ? "" : ","); + if (regnostarlist != NULL && !(regnostarlist[3] & REGFLAG_XER_OV)) + drcuml->log_printf("*"); + } + if (reglist[3] & REGFLAG_XER_SO) + { + drcuml->log_printf("%sxer_so", (count++ == 0) ? "" : ","); + if (regnostarlist != NULL && !(regnostarlist[3] & REGFLAG_XER_SO)) + drcuml->log_printf("*"); + } + if (reglist[3] & REGFLAG_XER_COUNT) + { + drcuml->log_printf("%sxer_count", (count++ == 0) ? "" : ","); + if (regnostarlist != NULL && !(regnostarlist[3] & REGFLAG_XER_COUNT)) + drcuml->log_printf("*"); + } + if (reglist[3] & REGFLAG_CTR) + { + drcuml->log_printf("%sctr", (count++ == 0) ? "" : ","); + if (regnostarlist != NULL && !(regnostarlist[3] & REGFLAG_CTR)) + drcuml->log_printf("*"); + } + if (reglist[3] & REGFLAG_LR) + { + drcuml->log_printf("%slr", (count++ == 0) ? "" : ","); + if (regnostarlist != NULL && !(regnostarlist[3] & REGFLAG_LR)) + drcuml->log_printf("*"); + } + + for (regnum = 0; regnum < 8; regnum++) + if (reglist[3] & REGFLAG_FPSCR(regnum)) + { + drcuml->log_printf("%sfpscr%d", (count++ == 0) ? "" : ",", regnum); + if (regnostarlist != NULL && !(regnostarlist[3] & REGFLAG_FPSCR(regnum))) + drcuml->log_printf("*"); + } + + drcuml->log_printf("] "); +} + + +/*------------------------------------------------- + log_opcode_desc - log a list of descriptions +-------------------------------------------------*/ + +void ppc_device::log_opcode_desc(drcuml_state *drcuml, const opcode_desc *desclist, int indent) +{ + /* open the file, creating it if necessary */ + if (indent == 0) + drcuml->log_printf("\nDescriptor list @ %08X\n", desclist->pc); + + /* output each descriptor */ + for ( ; desclist != NULL; desclist = desclist->next()) + { + char buffer[100]; + + /* disassemle the current instruction and output it to the log */ + if (drcuml->logging() || drcuml->logging_native()) + { + if (desclist->flags & OPFLAG_VIRTUAL_NOOP) + strcpy(buffer, ""); + else + ppc_dasm_one(buffer, desclist->pc, desclist->opptr.l[0]); + } + else + strcpy(buffer, "???"); + + drcuml->log_printf("%08X [%08X] t:%08X f:%s: %-30s", desclist->pc, desclist->physpc, desclist->targetpc, log_desc_flags_to_string(desclist->flags), buffer); + + /* output register states */ + log_register_list(drcuml, "use", desclist->regin, NULL); + log_register_list(drcuml, "mod", desclist->regout, desclist->regreq); + drcuml->log_printf("\n"); + + /* if we have a delay slot, output it recursively */ + if (desclist->delay.first() != NULL) + log_opcode_desc(drcuml, desclist->delay.first(), indent + 1); + + /* at the end of a sequence add a dividing line */ + if (desclist->flags & OPFLAG_END_SEQUENCE) + drcuml->log_printf("-----\n"); + } +} diff --git a/src/devices/cpu/powerpc/ppcfe.c b/src/devices/cpu/powerpc/ppcfe.c new file mode 100644 index 00000000000..8ba5a90eb4e --- /dev/null +++ b/src/devices/cpu/powerpc/ppcfe.c @@ -0,0 +1,1393 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + ppcfe.c + + Front-end for PowerPC recompiler + +***************************************************************************/ + +#include "emu.h" +#include "ppcfe.h" +#include "ppccom.h" + + +//************************************************************************** +// MACROS +//************************************************************************** + +#define GPR_USED(desc, x) do { (desc).regin[0] |= REGFLAG_R(x); } while (0) +#define GPR_USED_OR_ZERO(desc, x) do { (desc).regin[0] |= ((x) == 0 ? 0 : REGFLAG_R(x)); } while (0) +#define GPR_MODIFIED(desc, x) do { (desc).regout[0] |= REGFLAG_R(x); } while (0) + +#define FPR_USED(desc, x) do { (desc).regin[1] |= REGFLAG_FR(x); } while (0) +#define FPR_MODIFIED(desc, x) do { (desc).regout[1] |= REGFLAG_FR(x); } while (0) + +#define CR_USED(desc, x) do { (desc).regin[2] |= REGFLAG_CR(x); } while (0) +#define CR_BIT_USED(desc, x) do { (desc).regin[2] |= REGFLAG_CR_BIT(x); } while (0) +#define CR_MODIFIED(desc, x) do { (desc).regout[2] |= REGFLAG_CR(x); } while (0) +#define CR_BIT_MODIFIED(desc, x) do { (desc).regout[2] |= REGFLAG_CR_BIT(x); } while (0) + +#define XER_CA_USED(desc) do { (desc).regin[3] |= REGFLAG_XER_CA; } while (0) +#define XER_OV_USED(desc) do { (desc).regin[3] |= REGFLAG_XER_OV; } while (0) +#define XER_SO_USED(desc) do { (desc).regin[3] |= REGFLAG_XER_SO; } while (0) +#define XER_COUNT_USED(desc) do { (desc).regin[3] |= REGFLAG_XER_COUNT; } while (0) +#define XER_CA_MODIFIED(desc) do { (desc).regout[3] |= REGFLAG_XER_CA; } while (0) +#define XER_OV_MODIFIED(desc) do { (desc).regout[3] |= REGFLAG_XER_OV; } while (0) +#define XER_SO_MODIFIED(desc) do { (desc).regout[3] |= REGFLAG_XER_SO; } while (0) +#define XER_COUNT_MODIFIED(desc) do { (desc).regout[3] |= REGFLAG_XER_COUNT; } while (0) + +#define CTR_USED(desc) do { (desc).regin[3] |= REGFLAG_CTR; } while (0) +#define CTR_MODIFIED(desc) do { (desc).regout[3] |= REGFLAG_CTR; } while (0) +#define LR_USED(desc) do { (desc).regin[3] |= REGFLAG_LR; } while (0) +#define LR_MODIFIED(desc) do { (desc).regout[3] |= REGFLAG_LR; } while (0) + +#define FPSCR_USED(desc, x) do { (desc).regin[3] |= REGFLAG_FPSCR(x); } while (0) +#define FPSCR_MODIFIED(desc, x) do { (desc).regout[3] |= REGFLAG_FPSCR(x); } while (0) + + + +//************************************************************************** +// PPC FRONTEND +//************************************************************************** + +//------------------------------------------------- +// ppc_frontend - constructor +//------------------------------------------------- + +ppc_frontend::ppc_frontend(ppc_device *ppc, UINT32 window_start, UINT32 window_end, UINT32 max_sequence) + : drc_frontend(*ppc, window_start, window_end, max_sequence), + m_ppc(ppc) +{ +} + + +//------------------------------------------------- +// describe - build a description of a single +// instruction +//------------------------------------------------- + +bool ppc_frontend::describe(opcode_desc &desc, const opcode_desc *prev) +{ + UINT32 op, opswitch; + int regnum; + + // compute the physical PC + if (!m_ppc->memory_translate(AS_PROGRAM, TRANSLATE_FETCH, desc.physpc)) + { + // uh-oh: a page fault; leave the description empty and just if this is the first instruction, leave it empty and + // mark as needing to validate; otherwise, just end the sequence here + desc.flags |= OPFLAG_VALIDATE_TLB | OPFLAG_CAN_CAUSE_EXCEPTION | OPFLAG_COMPILER_PAGE_FAULT | OPFLAG_VIRTUAL_NOOP | OPFLAG_END_SEQUENCE; + return true; + } + + // fetch the opcode + op = desc.opptr.l[0] = m_ppc->m_direct->read_dword(desc.physpc, m_ppc->m_codexor); + + // all instructions are 4 bytes and default to a single cycle each + desc.length = 4; + desc.cycles = 1; + + // parse the instruction + opswitch = op >> 26; + switch (opswitch) + { + case 0x02: // TDI - 64-bit only + case 0x1e: // 0x1e group - 64-bit only + case 0x3a: // 0x3a group - 64-bit only + case 0x3e: // 0x3e group - 64-bit only + return false; + + case 0x03: // TWI + GPR_USED(desc, G_RA(op)); + desc.flags |= OPFLAG_CAN_CAUSE_EXCEPTION; + if (is_603_class()) + desc.cycles = 2; // 603 + return true; + + case 0x07: // MULLI + GPR_USED(desc, G_RA(op)); + GPR_MODIFIED(desc, G_RD(op)); + if (is_403_class()) + desc.cycles = 4; // 4XX + else if (is_601_class()) + desc.cycles = 5; // 601 + else if (is_603_class()) + desc.cycles = 2; // 603: 2-3 + else + desc.cycles = 2; // ??? + return true; + + case 0x0e: // ADDI + case 0x0f: // ADDIS + GPR_USED_OR_ZERO(desc, G_RA(op)); + GPR_MODIFIED(desc, G_RD(op)); + return true; + + case 0x0a: // CMPLI + case 0x0b: // CMPI + GPR_USED(desc, G_RA(op)); + XER_SO_USED(desc); + CR_MODIFIED(desc, G_CRFD(op)); + return true; + + case 0x08: // SUBFIC + case 0x0c: // ADDIC + GPR_USED(desc, G_RA(op)); + GPR_MODIFIED(desc, G_RD(op)); + XER_CA_MODIFIED(desc); + return true; + + case 0x0d: // ADDIC. + GPR_USED(desc, G_RA(op)); + XER_SO_USED(desc); + GPR_MODIFIED(desc, G_RT(op)); + XER_CA_MODIFIED(desc); + CR_MODIFIED(desc, 0); + return true; + + case 0x10: // BCx + if (!(G_BO(op) & 0x10)) + { + CR_BIT_USED(desc, G_BI(op)); + // branch folding + if (prev == NULL || prev->regout[2] == 0) + desc.cycles = 0; + } + if (!(G_BO(op) & 0x04)) + { + CTR_USED(desc); + CTR_MODIFIED(desc); + } + if (op & M_LK) + LR_MODIFIED(desc); + if ((G_BO(op) & 0x14) == 0x14) + desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; + else + desc.flags |= OPFLAG_IS_CONDITIONAL_BRANCH; + desc.targetpc = (INT16)(G_BD(op) << 2) + ((op & M_AA) ? 0 : desc.pc); + if (desc.targetpc == desc.pc && desc.cycles == 0) + desc.cycles = 1; + return true; + + case 0x11: // SC + if (!(m_ppc->m_cap & (PPCCAP_OEA | PPCCAP_4XX))) + return false; + desc.flags |= OPFLAG_WILL_CAUSE_EXCEPTION; + if (is_601_class()) + desc.cycles = 16; // 601 + else if (is_603_class()) + desc.cycles = 3; // 603 + else + desc.cycles = 3; // ??? + return true; + + case 0x12: // Bx + if (op & M_LK) + LR_MODIFIED(desc); + desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; + desc.targetpc = ((INT32)(G_LI(op) << 8) >> 6) + ((op & M_AA) ? 0 : desc.pc); + // branch folding + if (desc.targetpc != desc.pc) + desc.cycles = 0; + return true; + + case 0x13: // 0x13 group + return describe_13(op, desc, prev); + + case 0x14: // RLWIMIx + GPR_USED(desc, G_RS(op)); + GPR_USED(desc, G_RA(op)); + GPR_MODIFIED(desc, G_RA(op)); + if (op & M_RC) + { + XER_SO_USED(desc); + CR_MODIFIED(desc, 0); + } + return true; + + case 0x15: // RLWINMx + GPR_USED(desc, G_RS(op)); + GPR_MODIFIED(desc, G_RA(op)); + if (op & M_RC) + { + XER_SO_USED(desc); + CR_MODIFIED(desc, 0); + } + return true; + + case 0x17: // RLWNMx + GPR_USED(desc, G_RS(op)); + GPR_USED(desc, G_RB(op)); + GPR_MODIFIED(desc, G_RA(op)); + if (op & M_RC) + { + XER_SO_USED(desc); + CR_MODIFIED(desc, 0); + } + return true; + + case 0x18: // ORI + case 0x19: // ORIS + case 0x1a: // XORI + case 0x1b: // XORIS + GPR_USED(desc, G_RS(op)); + GPR_MODIFIED(desc, G_RA(op)); + return true; + + case 0x1c: // ANDI. + case 0x1d: // ANDIS. + GPR_USED(desc, G_RS(op)); + XER_SO_USED(desc); + GPR_MODIFIED(desc, G_RA(op)); + CR_MODIFIED(desc, 0); + return true; + + case 0x1f: // 0x1f group + return describe_1f(op, desc, prev); + + case 0x20: // LWZ + case 0x22: // LBZ + case 0x28: // LHZ + case 0x2a: // LHA + GPR_USED_OR_ZERO(desc, G_RA(op)); + GPR_MODIFIED(desc, G_RD(op)); + desc.flags |= OPFLAG_READS_MEMORY; + return true; + + case 0x21: // LWZU + case 0x23: // LBZU + case 0x29: // LHZU + case 0x2b: // LHAU + if (G_RA(op) == 0 || G_RA(op) == G_RD(op)) + return false; + GPR_USED(desc, G_RA(op)); + GPR_MODIFIED(desc, G_RD(op)); + GPR_MODIFIED(desc, G_RA(op)); + desc.flags |= OPFLAG_READS_MEMORY; + return true; + + case 0x24: // STW + case 0x26: // STB + case 0x2c: // STH + GPR_USED_OR_ZERO(desc, G_RA(op)); + GPR_USED(desc, G_RS(op)); + desc.flags |= OPFLAG_WRITES_MEMORY; + return true; + + case 0x25: // STWU + case 0x27: // STBU + case 0x2d: // STHU + if (G_RA(op) == 0) + return false; + GPR_USED(desc, G_RA(op)); + GPR_USED(desc, G_RS(op)); + GPR_MODIFIED(desc, G_RA(op)); + desc.flags |= OPFLAG_WRITES_MEMORY; + return true; + + case 0x2e: // LMW + GPR_USED_OR_ZERO(desc, G_RA(op)); + for (regnum = G_RD(op); regnum < 32; regnum++) + GPR_MODIFIED(desc, regnum); + desc.flags |= OPFLAG_READS_MEMORY; + desc.cycles = 32 - G_RD(op); + return true; + + case 0x2f: // STMW + GPR_USED_OR_ZERO(desc, G_RA(op)); + for (regnum = G_RS(op); regnum < 32; regnum++) + GPR_USED(desc, regnum); + desc.flags |= OPFLAG_WRITES_MEMORY; + desc.cycles = 32 - G_RS(op); + return true; + + case 0x30: // LFS + case 0x32: // LFD + if (!(m_ppc->m_cap & PPCCAP_FPU)) + return false; + GPR_USED_OR_ZERO(desc, G_RA(op)); + FPR_MODIFIED(desc, G_RD(op)); + desc.flags |= OPFLAG_READS_MEMORY; + return true; + + case 0x31: // LFSU + case 0x33: // LFDU + if (!(m_ppc->m_cap & PPCCAP_FPU)) + return false; + if (G_RA(op) == 0) + return false; + GPR_USED(desc, G_RA(op)); + GPR_MODIFIED(desc, G_RA(op)); + FPR_MODIFIED(desc, G_RD(op)); + desc.flags |= OPFLAG_READS_MEMORY; + return true; + + case 0x34: // STFS + case 0x36: // STFD + if (!(m_ppc->m_cap & PPCCAP_FPU)) + return false; + GPR_USED_OR_ZERO(desc, G_RA(op)); + FPR_USED(desc, G_RS(op)); + desc.flags |= OPFLAG_WRITES_MEMORY; + return true; + + case 0x35: // STFSU + case 0x37: // STFDU + if (!(m_ppc->m_cap & PPCCAP_FPU)) + return false; + if (G_RA(op) == 0) + return false; + GPR_USED(desc, G_RA(op)); + GPR_MODIFIED(desc, G_RA(op)); + FPR_USED(desc, G_RS(op)); + desc.flags |= OPFLAG_WRITES_MEMORY; + return true; + + case 0x3b: // 0x3b group + return describe_3b(op, desc, prev); + + case 0x3f: // 0x3f group + return describe_3f(op, desc, prev); + } + + return false; +} + + +/*------------------------------------------------- + describe_instruction_13 - build a + description of a single instruction in the + 0x13 group +-------------------------------------------------*/ + +bool ppc_frontend::describe_13(UINT32 op, opcode_desc &desc, const opcode_desc *prev) +{ + UINT32 opswitch = (op >> 1) & 0x3ff; + + switch (opswitch) + { + case 0x000: // MTCRF + CR_USED(desc, G_CRFS(op)); + CR_MODIFIED(desc, G_CRFD(op)); + // CR logical folding + if (prev == NULL || prev->regout[2] == 0) + desc.cycles = 0; + return true; + + case 0x010: // BCLRx + LR_USED(desc); + if (!(G_BO(op) & 0x10)) + CR_BIT_USED(desc, G_BI(op)); + if (!(G_BO(op) & 0x04)) + { + CTR_USED(desc); + CTR_MODIFIED(desc); + } + if (op & M_LK) + LR_MODIFIED(desc); + if ((G_BO(op) & 0x14) == 0x14) + desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; + else + desc.flags |= OPFLAG_IS_CONDITIONAL_BRANCH; + desc.targetpc = BRANCH_TARGET_DYNAMIC; + return true; + + case 0x021: // CRNOR + case 0x081: // CRANDC + case 0x0c1: // CRXOR + case 0x0e1: // CRNAND + case 0x101: // CRAND + case 0x121: // CREQV + case 0x1a1: // CRORC + case 0x1c1: // CROR + CR_BIT_USED(desc, G_CRBA(op)); + CR_BIT_USED(desc, G_CRBB(op)); + CR_BIT_MODIFIED(desc, G_CRBD(op)); + // CR logical folding + if (prev == NULL || prev->regout[2] == 0) + desc.cycles = 0; + return true; + + case 0x032: // RFI + if (!(m_ppc->m_cap & (PPCCAP_OEA | PPCCAP_4XX))) + return false; + desc.flags |= OPFLAG_PRIVILEGED | OPFLAG_CAN_CHANGE_MODES | OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE | OPFLAG_CAN_CAUSE_EXCEPTION; + desc.targetpc = BRANCH_TARGET_DYNAMIC; + if (is_601_class()) + desc.cycles = 13; // 601 + else if (is_603_class()) + desc.cycles = 3; // 603 + else + desc.cycles = 3; // ??? + return true; + + case 0x033: // RFCI + if (!(m_ppc->m_cap & PPCCAP_4XX)) + return false; + desc.flags |= OPFLAG_PRIVILEGED | OPFLAG_CAN_CHANGE_MODES | OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE | OPFLAG_CAN_CAUSE_EXCEPTION; + desc.targetpc = BRANCH_TARGET_DYNAMIC; + return true; + + case 0x096: // ISYNC + if (!(m_ppc->m_cap & (PPCCAP_VEA | PPCCAP_4XX))) + return false; + if (is_601_class()) + desc.cycles = 6; // 601 + return true; + + case 0x210: // BCCTRx + CTR_USED(desc); + if (!(G_BO(op) & 0x10)) + CR_BIT_USED(desc, G_BI(op)); + if (!(G_BO(op) & 0x04)) + return false; + if (op & M_LK) + LR_MODIFIED(desc); + if ((G_BO(op) & 0x14) == 0x14) + desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; + else + desc.flags |= OPFLAG_IS_CONDITIONAL_BRANCH; + desc.targetpc = BRANCH_TARGET_DYNAMIC; + return true; + } + + return false; +} + + +/*------------------------------------------------- + describe_instruction_1f - build a + description of a single instruction in the + 0x1f group +-------------------------------------------------*/ + +bool ppc_frontend::describe_1f(UINT32 op, opcode_desc &desc, const opcode_desc *prev) +{ + UINT32 opswitch = (op >> 1) & 0x3ff; + int spr, regnum; + + switch (opswitch) + { + case 0x009: // MULHDUx - 64-bit only + case 0x015: // LDX - 64-bit only + case 0x01b: // SLDx - 64-bit only + case 0x035: // LDUX - 64-bit only + case 0x03a: // CNTLZDx - 64-bit only + case 0x044: // TD - 64-bit only + case 0x049: // MULHDx - 64-bit only + case 0x054: // LDARX - 64-bit only + case 0x095: // STDX - 64-bit only + case 0x0b5: // STDUX - 64-bit only + case 0x0d6: // STDCX. - 64-bit only + case 0x0e9: // MULLD - 64-bit only + case 0x2e9: // MULLDO - 64-bit only + case 0x155: // LWAX - 64-bit only + case 0x175: // LWAUX - 64-bit only + case 0x33a: // SRADIx - 64-bit only + case 0x33b: // SRADIx - 64-bit only + case 0x1b2: // SLBIE - 64-bit only + case 0x1c9: // DIVDUx - 64-bit only + case 0x3c9: // DIVDUOx - 64-bit only + case 0x1e9: // DIVDx - 64-bit only + case 0x3e9: // DIVDOx - 64-bit only + case 0x1f2: // SLBIA - 64-bit only + case 0x21b: // SRDx - 64-bit only + case 0x31a: // SRADx - 64-bit only + case 0x3da: // EXTSW - 64-bit only + return false; + + case 0x000: // CMP + case 0x020: // CMPL + GPR_USED(desc, G_RA(op)); + GPR_USED(desc, G_RB(op)); + XER_SO_USED(desc); + CR_MODIFIED(desc, G_CRFD(op)); + return true; + + case 0x004: // TW + GPR_USED(desc, G_RA(op)); + GPR_USED(desc, G_RB(op)); + desc.flags |= OPFLAG_CAN_CAUSE_EXCEPTION; + if (is_603_class()) + desc.cycles = 2; // 603 + return true; + + case 0x008: // SUBFCx + case 0x00a: // ADDCx + GPR_USED(desc, G_RA(op)); + GPR_USED(desc, G_RB(op)); + GPR_MODIFIED(desc, G_RD(op)); + XER_CA_MODIFIED(desc); + if (op & M_RC) + { + XER_SO_USED(desc); + CR_MODIFIED(desc, 0); + } + return true; + + case 0x088: // SUBFEx + case 0x08a: // ADDEx + GPR_USED(desc, G_RA(op)); + GPR_USED(desc, G_RB(op)); + XER_CA_USED(desc); + GPR_MODIFIED(desc, G_RD(op)); + XER_CA_MODIFIED(desc); + if (op & M_RC) + { + XER_SO_USED(desc); + CR_MODIFIED(desc, 0); + } + return true; + + case 0x0c8: // SUBFZEx + case 0x0ca: // ADDZEx + case 0x0e8: // SUBFMEx + case 0x0ea: // ADDMEx + GPR_USED(desc, G_RA(op)); + XER_CA_USED(desc); + GPR_MODIFIED(desc, G_RD(op)); + XER_CA_MODIFIED(desc); + if (op & M_RC) + { + XER_SO_USED(desc); + CR_MODIFIED(desc, 0); + } + return true; + + case 0x00b: // MULHWUx + case 0x04b: // MULHWx + case 0x0eb: // MULLWx + GPR_USED(desc, G_RA(op)); + GPR_USED(desc, G_RB(op)); + GPR_MODIFIED(desc, G_RD(op)); + if (op & M_RC) + { + XER_SO_USED(desc); + CR_MODIFIED(desc, 0); + } + if (is_403_class()) + desc.cycles = 4; // 4XX + else if (is_601_class()) + desc.cycles = 5; // 601: 5/9/10 + else if (is_603_class()) + desc.cycles = 2; // 603: 2,3,4,5,6 + else + desc.cycles = 2; // ??? + return true; + + case 0x1cb: // DIVWUx + case 0x1eb: // DIVWx + GPR_USED(desc, G_RA(op)); + GPR_USED(desc, G_RB(op)); + GPR_MODIFIED(desc, G_RD(op)); + if (op & M_RC) + { + XER_SO_USED(desc); + CR_MODIFIED(desc, 0); + } + if (is_403_class()) + desc.cycles = 33; // 4XX + else if (is_601_class()) + desc.cycles = 36; // 601 + else if (is_603_class()) + desc.cycles = 37; // 603 + else + desc.cycles = 33; // ??? + return true; + + case 0x028: // SUBFx + case 0x10a: // ADDx + GPR_USED(desc, G_RA(op)); + GPR_USED(desc, G_RB(op)); + GPR_MODIFIED(desc, G_RD(op)); + if (op & M_RC) + { + XER_SO_USED(desc); + CR_MODIFIED(desc, 0); + } + return true; + + case 0x208: // SUBFCOx + case 0x20a: // ADDCOx + GPR_USED(desc, G_RA(op)); + GPR_USED(desc, G_RB(op)); + GPR_MODIFIED(desc, G_RD(op)); + XER_OV_MODIFIED(desc); + XER_SO_MODIFIED(desc); + XER_CA_MODIFIED(desc); + if (op & M_RC) + CR_MODIFIED(desc, 0); + return true; + + case 0x288: // SUBFEOx + case 0x28a: // ADDEOx + GPR_USED(desc, G_RA(op)); + GPR_USED(desc, G_RB(op)); + XER_CA_USED(desc); + GPR_MODIFIED(desc, G_RD(op)); + XER_OV_MODIFIED(desc); + XER_SO_MODIFIED(desc); + XER_CA_MODIFIED(desc); + if (op & M_RC) + CR_MODIFIED(desc, 0); + return true; + + case 0x2c8: // SUBFZEOx + case 0x2ca: // ADDZEOx + case 0x2e8: // SUBFMEOx + case 0x2ea: // ADDMEOx + GPR_USED(desc, G_RA(op)); + XER_CA_USED(desc); + GPR_MODIFIED(desc, G_RD(op)); + XER_OV_MODIFIED(desc); + XER_SO_MODIFIED(desc); + XER_CA_MODIFIED(desc); + if (op & M_RC) + CR_MODIFIED(desc, 0); + return true; + + case 0x2eb: // MULLWOx + GPR_USED(desc, G_RA(op)); + GPR_USED(desc, G_RB(op)); + GPR_MODIFIED(desc, G_RD(op)); + XER_OV_MODIFIED(desc); + XER_SO_MODIFIED(desc); + if (op & M_RC) + CR_MODIFIED(desc, 0); + if (is_403_class()) + desc.cycles = 4; // 4XX + else if (is_601_class()) + desc.cycles = 5; // 601: 5/9/10 + else if (is_603_class()) + desc.cycles = 2; // 603: 2,3,4,5,6 + else + desc.cycles = 2; // ??? + return true; + + case 0x3cb: // DIVWUOx + case 0x3eb: // DIVWOx + GPR_USED(desc, G_RA(op)); + GPR_USED(desc, G_RB(op)); + GPR_MODIFIED(desc, G_RD(op)); + XER_OV_MODIFIED(desc); + XER_SO_MODIFIED(desc); + if (op & M_RC) + CR_MODIFIED(desc, 0); + if (is_403_class()) + desc.cycles = 33; // 4XX + else if (is_601_class()) + desc.cycles = 36; // 601 + else if (is_603_class()) + desc.cycles = 37; // 603 + else + desc.cycles = 33; // ??? + return true; + + case 0x228: // SUBFOx + case 0x30a: // ADDOx + GPR_USED(desc, G_RA(op)); + GPR_USED(desc, G_RB(op)); + GPR_MODIFIED(desc, G_RD(op)); + XER_OV_MODIFIED(desc); + XER_SO_MODIFIED(desc); + if (op & M_RC) + CR_MODIFIED(desc, 0); + return true; + + case 0x013: // MFCR + CR_USED(desc, 0); + CR_USED(desc, 1); + CR_USED(desc, 2); + CR_USED(desc, 3); + CR_USED(desc, 4); + CR_USED(desc, 5); + CR_USED(desc, 6); + CR_USED(desc, 7); + GPR_MODIFIED(desc, G_RD(op)); + return true; + + case 0x136: // ECIWX + if (!(m_ppc->m_cap & PPCCAP_VEA)) + return false; + case 0x014: // LWARX + case 0x017: // LWZX + case 0x057: // LBZX + case 0x117: // LHZX + case 0x157: // LHAX + case 0x216: // LWBRX + case 0x316: // LHBRX + GPR_USED_OR_ZERO(desc, G_RA(op)); + GPR_USED(desc, G_RB(op)); + GPR_MODIFIED(desc, G_RD(op)); + desc.flags |= OPFLAG_READS_MEMORY; + return true; + + case 0x018: // SLWx + case 0x01c: // ANDx + case 0x03c: // ANDCx + case 0x07c: // NORx + case 0x11c: // EQVx + case 0x13c: // XORx + case 0x19c: // ORCx + case 0x1bc: // ORx + case 0x1dc: // NANDx + GPR_USED(desc, G_RS(op)); + GPR_USED(desc, G_RB(op)); + GPR_MODIFIED(desc, G_RA(op)); + if (op & M_RC) + { + XER_SO_USED(desc); + CR_MODIFIED(desc, 0); + } + return true; + + case 0x218: // SRWx + case 0x318: // SRAWx + GPR_USED(desc, G_RS(op)); + GPR_USED(desc, G_RB(op)); + GPR_MODIFIED(desc, G_RA(op)); + XER_CA_MODIFIED(desc); + if (op & M_RC) + { + XER_SO_USED(desc); + CR_MODIFIED(desc, 0); + } + return true; + + case 0x01a: // CNTLZWx + case 0x39a: // EXTSHx + case 0x3ba: // EXTSBx + GPR_USED(desc, G_RS(op)); + GPR_MODIFIED(desc, G_RA(op)); + if (op & M_RC) + { + XER_SO_USED(desc); + CR_MODIFIED(desc, 0); + } + return true; + + case 0x036: // DCBST + case 0x056: // DCBF + case 0x0f6: // DCBTST + case 0x116: // DCBT + case 0x2f6: // DCBA + case 0x3d6: // ICBI + if (!(m_ppc->m_cap & (PPCCAP_VEA | PPCCAP_4XX))) + return false; + GPR_USED_OR_ZERO(desc, G_RA(op)); + GPR_USED(desc, G_RB(op)); + return true; + + case 0x1d6: // DCBI + if (!(m_ppc->m_cap & (PPCCAP_OEA | PPCCAP_4XX))) + return false; + GPR_USED_OR_ZERO(desc, G_RA(op)); + GPR_USED(desc, G_RB(op)); + desc.flags |= OPFLAG_PRIVILEGED | OPFLAG_CAN_CAUSE_EXCEPTION; + return true; + + case 0x037: // LWZUX + case 0x077: // LBZUX + case 0x137: // LHZUX + case 0x177: // LHAUX + if (G_RA(op) == 0 || G_RA(op) == G_RD(op)) + return false; + GPR_USED(desc, G_RA(op)); + GPR_USED(desc, G_RB(op)); + GPR_MODIFIED(desc, G_RD(op)); + GPR_MODIFIED(desc, G_RA(op)); + desc.flags |= OPFLAG_READS_MEMORY; + return true; + + case 0x153: // MFSPR + GPR_MODIFIED(desc, G_RD(op)); + spr = compute_spr(G_SPR(op)); + if (spr == SPR_LR) + LR_USED(desc); + if (spr == SPR_CTR) + CTR_USED(desc); + if (spr == SPR_XER) + { + XER_COUNT_USED(desc); + XER_CA_USED(desc); + XER_OV_USED(desc); + XER_SO_USED(desc); + } + if (spr & 0x010) + desc.flags |= OPFLAG_PRIVILEGED | OPFLAG_CAN_CAUSE_EXCEPTION; + if ((m_ppc->m_cap & PPCCAP_4XX) && spr == SPR4XX_TBLU) + desc.cycles = POWERPC_COUNT_READ_TBL; + else if ((m_ppc->m_cap & PPCCAP_VEA) && spr == SPRVEA_TBL_R) + desc.cycles = POWERPC_COUNT_READ_TBL; + else if ((m_ppc->m_cap & PPCCAP_OEA) && spr == SPROEA_DEC) + desc.cycles = POWERPC_COUNT_READ_DEC; + return true; + + case 0x053: // MFMSR + GPR_MODIFIED(desc, G_RD(op)); + desc.flags |= OPFLAG_PRIVILEGED | OPFLAG_CAN_CAUSE_EXCEPTION | OPFLAG_CAN_EXPOSE_EXTERNAL_INT; + if (is_601_class()) + desc.cycles = 2; // 601 + return true; + + case 0x253: // MFSR + GPR_MODIFIED(desc, G_RD(op)); + desc.flags |= OPFLAG_PRIVILEGED | OPFLAG_CAN_CAUSE_EXCEPTION; + return true; + + case 0x293: // MFSRIN + GPR_USED(desc, G_RB(op)); + GPR_MODIFIED(desc, G_RD(op)); + desc.flags |= OPFLAG_PRIVILEGED | OPFLAG_CAN_CAUSE_EXCEPTION; + return true; + + case 0x173: // MFTB + if (!(m_ppc->m_cap & PPCCAP_VEA)) + return false; + GPR_MODIFIED(desc, G_RD(op)); + spr = compute_spr(G_SPR(op)); + if (spr == SPRVEA_TBL_R) + desc.cycles = POWERPC_COUNT_READ_TBL; + return true; + + case 0x068: // NEGx + GPR_USED(desc, G_RA(op)); + GPR_MODIFIED(desc, G_RD(op)); + if (op & M_RC) + { + XER_SO_USED(desc); + CR_MODIFIED(desc, 0); + } + return true; + + case 0x268: // NEGOx + GPR_USED(desc, G_RA(op)); + GPR_MODIFIED(desc, G_RD(op)); + XER_OV_MODIFIED(desc); + XER_SO_MODIFIED(desc); + if (op & M_RC) + CR_MODIFIED(desc, 0); + return true; + + case 0x090: // MTCRF + GPR_USED(desc, G_RS(op)); + if (G_CRM(op) & 0x80) CR_MODIFIED(desc, 0); + if (G_CRM(op) & 0x40) CR_MODIFIED(desc, 1); + if (G_CRM(op) & 0x20) CR_MODIFIED(desc, 2); + if (G_CRM(op) & 0x10) CR_MODIFIED(desc, 3); + if (G_CRM(op) & 0x08) CR_MODIFIED(desc, 4); + if (G_CRM(op) & 0x04) CR_MODIFIED(desc, 5); + if (G_CRM(op) & 0x02) CR_MODIFIED(desc, 6); + if (G_CRM(op) & 0x01) CR_MODIFIED(desc, 7); + return true; + + case 0x092: // MTMSR + GPR_USED(desc, G_RS(op)); + desc.flags |= OPFLAG_PRIVILEGED | OPFLAG_CAN_CAUSE_EXCEPTION | OPFLAG_CAN_CHANGE_MODES | OPFLAG_END_SEQUENCE; + if (is_601_class()) + desc.cycles = 17; // 601 + else if (is_603_class()) + desc.cycles = 2; // 603 + return true; + + case 0x0d2: // MTSR + if (!(m_ppc->m_cap & PPCCAP_OEA)) + return false; + GPR_USED(desc, G_RS(op)); + desc.flags |= OPFLAG_PRIVILEGED | OPFLAG_CAN_CAUSE_EXCEPTION; + return true; + + case 0x1d3: // MTSPR + GPR_USED(desc, G_RS(op)); + spr = compute_spr(G_SPR(op)); + if (spr == SPR_LR) + LR_MODIFIED(desc); + if (spr == SPR_CTR) + CTR_MODIFIED(desc); + if (spr == SPR_XER) + { + XER_COUNT_MODIFIED(desc); + XER_CA_MODIFIED(desc); + XER_OV_MODIFIED(desc); + XER_SO_MODIFIED(desc); + } + if (spr & 0x010) + desc.flags |= OPFLAG_PRIVILEGED | OPFLAG_CAN_CAUSE_EXCEPTION; + return true; + + case 0x1b6: // ECOWX + if (!(m_ppc->m_cap & PPCCAP_VEA)) + return false; + case 0x096: // STWCX. + case 0x097: // STWX + case 0x0d7: // STBX + case 0x197: // STHX + case 0x296: // STWBRX + case 0x396: // STHBRX + GPR_USED_OR_ZERO(desc, G_RA(op)); + GPR_USED(desc, G_RB(op)); + GPR_USED(desc, G_RS(op)); + desc.flags |= OPFLAG_WRITES_MEMORY; + return true; + + case 0x0b7: // STWUX + case 0x0f7: // STBUX + case 0x1b7: // STHUX + if (G_RA(op) == 0) + return false; + GPR_USED(desc, G_RA(op)); + GPR_USED(desc, G_RB(op)); + GPR_USED(desc, G_RS(op)); + GPR_MODIFIED(desc, G_RA(op)); + desc.flags |= OPFLAG_WRITES_MEMORY; + return true; + + case 0x0f2: // MTSRIN + if (!(m_ppc->m_cap & PPCCAP_OEA)) + return false; + GPR_USED(desc, G_RS(op)); + GPR_USED(desc, G_RB(op)); + desc.flags |= OPFLAG_PRIVILEGED | OPFLAG_CAN_CAUSE_EXCEPTION; + return true; + + case 0x132: // TLBIE + if (!(m_ppc->m_cap & PPCCAP_OEA)) + return false; + GPR_USED(desc, G_RB(op)); + desc.flags |= OPFLAG_PRIVILEGED | OPFLAG_CAN_CAUSE_EXCEPTION; + return true; + + case 0x172: // TLBIA + if (!(m_ppc->m_cap & PPCCAP_OEA) || (m_ppc->m_cap & PPCCAP_603_MMU)) + return false; + desc.flags |= OPFLAG_PRIVILEGED | OPFLAG_CAN_CAUSE_EXCEPTION; + return true; + + case 0x3d2: // TLBLD + case 0x3f2: // TLBLI + if (!(m_ppc->m_cap & PPCCAP_603_MMU) && !is_602_class()) + return false; + desc.flags |= OPFLAG_PRIVILEGED | OPFLAG_CAN_CAUSE_EXCEPTION; + return true; + + case 0x200: // MCRXR + XER_CA_USED(desc); + XER_OV_USED(desc); + XER_SO_USED(desc); + CR_MODIFIED(desc, G_CRFD(op)); + XER_CA_MODIFIED(desc); + XER_OV_MODIFIED(desc); + XER_SO_MODIFIED(desc); + return true; + + case 0x215: // LSWX + GPR_USED_OR_ZERO(desc, G_RA(op)); + GPR_USED(desc, G_RB(op)); + XER_COUNT_USED(desc); + for (regnum = 0; regnum < 32; regnum++) + GPR_MODIFIED(desc, regnum); + desc.flags |= OPFLAG_READS_MEMORY; + return true; + + case 0x217: // LFSX + case 0x257: // LFDX + if (!(m_ppc->m_cap & PPCCAP_FPU)) + return false; + GPR_USED_OR_ZERO(desc, G_RA(op)); + GPR_USED(desc, G_RB(op)); + FPR_MODIFIED(desc, G_RD(op)); + desc.flags |= OPFLAG_READS_MEMORY; + return true; + + case 0x236: // TLBSYNC + if (!(m_ppc->m_cap & PPCCAP_OEA)) + return false; + desc.flags |= OPFLAG_PRIVILEGED | OPFLAG_CAN_CAUSE_EXCEPTION; + return true; + + case 0x256: // SYNC + return true; + + case 0x356: // EIEIO + if (!(m_ppc->m_cap & (PPCCAP_VEA | PPCCAP_4XX))) + return false; + return true; + + case 0x237: // LFSUX + case 0x277: // LFDUX + if (!(m_ppc->m_cap & PPCCAP_FPU)) + return false; + if (G_RA(op) == 0) + return false; + GPR_USED(desc, G_RA(op)); + GPR_USED(desc, G_RB(op)); + GPR_MODIFIED(desc, G_RA(op)); + FPR_MODIFIED(desc, G_RD(op)); + desc.flags |= OPFLAG_READS_MEMORY; + return true; + + case 0x255: // LSWI + GPR_USED_OR_ZERO(desc, G_RA(op)); + for (regnum = 0; regnum < ((G_NB(op) - 1) & 0x1f) + 1; regnum += 4) + GPR_MODIFIED(desc, (G_RD(op) + regnum / 4) % 32); + desc.flags |= OPFLAG_READS_MEMORY; + desc.cycles = (((G_NB(op) - 1) & 0x1f) + 1 + 3) / 4; + return true; + + case 0x295: // STSWX + GPR_USED_OR_ZERO(desc, G_RA(op)); + GPR_USED(desc, G_RB(op)); + XER_COUNT_USED(desc); + for (regnum = 0; regnum < 32; regnum++) + GPR_USED(desc, regnum); + desc.flags |= OPFLAG_WRITES_MEMORY; + return true; + + case 0x2d5: // STSWI + GPR_USED_OR_ZERO(desc, G_RA(op)); + for (regnum = 0; regnum < ((G_NB(op) - 1) & 0x1f) + 1; regnum += 4) + GPR_USED(desc, (G_RD(op) + regnum / 4) % 32); + desc.flags |= OPFLAG_WRITES_MEMORY; + desc.cycles = (((G_NB(op) - 1) & 0x1f) + 1 + 3) / 4; + return true; + + case 0x297: // STFSX + case 0x2d7: // STFDX + case 0x3d7: // STFIWX + if (!(m_ppc->m_cap & PPCCAP_FPU)) + return false; + GPR_USED_OR_ZERO(desc, G_RA(op)); + GPR_USED(desc, G_RB(op)); + FPR_USED(desc, G_RS(op)); + desc.flags |= OPFLAG_WRITES_MEMORY; + return true; + + case 0x2b7: // STFSUX + case 0x2f7: // STFDUX + if (!(m_ppc->m_cap & PPCCAP_FPU)) + return false; + if (G_RA(op) == 0) + return false; + GPR_USED_OR_ZERO(desc, G_RA(op)); + GPR_USED(desc, G_RB(op)); + GPR_MODIFIED(desc, G_RA(op)); + FPR_USED(desc, G_RS(op)); + desc.flags |= OPFLAG_WRITES_MEMORY; + return true; + + case 0x338: // SRAWIx + GPR_USED(desc, G_RS(op)); + GPR_MODIFIED(desc, G_RA(op)); + XER_CA_MODIFIED(desc); + if (op & M_RC) + { + XER_SO_USED(desc); + CR_MODIFIED(desc, 0); + } + return true; + + case 0x3f6: // DCBZ + if (!(m_ppc->m_cap & (PPCCAP_VEA | PPCCAP_4XX))) + return false; + GPR_USED_OR_ZERO(desc, G_RA(op)); + GPR_USED(desc, G_RB(op)); + desc.flags |= OPFLAG_WRITES_MEMORY; + return true; + + case 0x106: // ICBT + case 0x1c6: // DCCCI + case 0x3c6: // ICCCI + if (!(m_ppc->m_cap & PPCCAP_4XX)) + return false; + GPR_USED_OR_ZERO(desc, G_RA(op)); + GPR_USED(desc, G_RB(op)); + desc.flags |= OPFLAG_PRIVILEGED | OPFLAG_CAN_CAUSE_EXCEPTION; + return true; + + case 0x1e6: // DCREAD + case 0x3e6: // ICREAD + if (!(m_ppc->m_cap & PPCCAP_4XX)) + return false; + GPR_USED_OR_ZERO(desc, G_RA(op)); + GPR_USED(desc, G_RB(op)); + GPR_MODIFIED(desc, G_RT(op)); + desc.flags |= OPFLAG_PRIVILEGED | OPFLAG_CAN_CAUSE_EXCEPTION; + return true; + + case 0x143: // MFDCR + if (!(m_ppc->m_cap & PPCCAP_4XX)) + return false; + GPR_MODIFIED(desc, G_RD(op)); + desc.flags |= OPFLAG_PRIVILEGED | OPFLAG_CAN_CAUSE_EXCEPTION; + return true; + + case 0x1c3: // MTDCR + if (!(m_ppc->m_cap & PPCCAP_4XX)) + return false; + GPR_USED(desc, G_RS(op)); + desc.flags |= OPFLAG_PRIVILEGED | OPFLAG_CAN_CAUSE_EXCEPTION | OPFLAG_CAN_EXPOSE_EXTERNAL_INT; + return true; + + case 0x083: // WRTEE + if (!(m_ppc->m_cap & PPCCAP_4XX)) + return false; + GPR_USED(desc, G_RS(op)); + desc.flags |= OPFLAG_CAN_EXPOSE_EXTERNAL_INT; + return true; + + case 0x0a3: // WRTEEI + if (!(m_ppc->m_cap & PPCCAP_4XX)) + return false; + if (op & MSR_EE) + desc.flags |= OPFLAG_CAN_EXPOSE_EXTERNAL_INT; + return true; + + case 0x254: // ESA + case 0x274: // DSA + if (!is_602_class()) + return false; + desc.flags |= OPFLAG_PRIVILEGED | OPFLAG_CAN_CAUSE_EXCEPTION; + return true; + } + + return false; +} + + +/*------------------------------------------------- + describe_instruction_3b - build a + description of a single instruction in the + 0x3b group +-------------------------------------------------*/ + +bool ppc_frontend::describe_3b(UINT32 op, opcode_desc &desc, const opcode_desc *prev) +{ + UINT32 opswitch = (op >> 1) & 0x1f; + + if (!(m_ppc->m_cap & PPCCAP_FPU)) + return false; + + switch (opswitch) + { + case 0x12: // FDIVSx + FPR_USED(desc, G_RA(op)); + FPR_USED(desc, G_RB(op)); + FPR_MODIFIED(desc, G_RD(op)); + if (op & M_RC) + CR_MODIFIED(desc, 1); + if (is_601_class()) + desc.cycles = 17; // 601 + else if (is_603_class()) + desc.cycles = 18; // 603 + else + desc.cycles = 17; // ??? + FPSCR_MODIFIED(desc, 4); + return true; + + case 0x14: // FSUBSx + case 0x15: // FADDSx + FPR_USED(desc, G_RA(op)); + FPR_USED(desc, G_RB(op)); + FPR_MODIFIED(desc, G_RD(op)); + if (op & M_RC) + CR_MODIFIED(desc, 1); + FPSCR_MODIFIED(desc, 4); + return true; + + case 0x19: // FMULSx - not the same form as FSUB/FADD! + FPR_USED(desc, G_RA(op)); + FPR_USED(desc, G_REGC(op)); + FPR_MODIFIED(desc, G_RD(op)); + if (op & M_RC) + CR_MODIFIED(desc, 1); + FPSCR_MODIFIED(desc, 4); + return true; + + case 0x16: // FSQRTSx + case 0x18: // FRESx + FPR_USED(desc, G_RB(op)); + FPR_MODIFIED(desc, G_RD(op)); + if (op & M_RC) + CR_MODIFIED(desc, 1); + FPSCR_MODIFIED(desc, 4); + return true; + + case 0x1c: // FMSUBSx + case 0x1d: // FMADDSx + case 0x1e: // FNMSUBSx + case 0x1f: // FNMADDSx + FPR_USED(desc, G_RA(op)); + FPR_USED(desc, G_RB(op)); + FPR_USED(desc, G_REGC(op)); + FPR_MODIFIED(desc, G_RD(op)); + if (op & M_RC) + CR_MODIFIED(desc, 1); + FPSCR_MODIFIED(desc, 4); + return true; + } + + return false; +} + + +/*------------------------------------------------- + describe_instruction_3f - build a + description of a single instruction in the + 0x3f group +-------------------------------------------------*/ + +bool ppc_frontend::describe_3f(UINT32 op, opcode_desc &desc, const opcode_desc *prev) +{ + UINT32 opswitch = (op >> 1) & 0x3ff; + + if (!(m_ppc->m_cap & PPCCAP_FPU)) + return false; + + if (opswitch & 0x10) + { + opswitch &= 0x1f; + switch (opswitch) + { + case 0x12: // FDIVx + FPR_USED(desc, G_RA(op)); + FPR_USED(desc, G_RB(op)); + FPR_MODIFIED(desc, G_RD(op)); + if (op & M_RC) + CR_MODIFIED(desc, 1); + if (is_601_class()) + desc.cycles = 31; // 601 + else if (is_603_class()) + desc.cycles = 33; // 603 + else + desc.cycles = 31; // ??? + FPSCR_MODIFIED(desc, 4); + return true; + + case 0x19: // FMULx + FPR_USED(desc, G_RA(op)); + FPR_USED(desc, G_REGC(op)); + FPR_MODIFIED(desc, G_RD(op)); + if (op & M_RC) + CR_MODIFIED(desc, 1); + desc.cycles = 2; // 601/603 + FPSCR_MODIFIED(desc, 4); + return true; + + case 0x14: // FSUBx + case 0x15: // FADDx + FPR_USED(desc, G_RA(op)); + FPR_USED(desc, G_RB(op)); + FPR_MODIFIED(desc, G_RD(op)); + if (op & M_RC) + CR_MODIFIED(desc, 1); + FPSCR_MODIFIED(desc, 4); + return true; + + case 0x16: // FSQRTx + case 0x1a: // FSQRTEx + FPR_USED(desc, G_RB(op)); + FPR_MODIFIED(desc, G_RD(op)); + if (op & M_RC) + CR_MODIFIED(desc, 1); + FPSCR_MODIFIED(desc, 4); + return true; + + case 0x17: // FSELx + FPR_USED(desc, G_RA(op)); + FPR_USED(desc, G_RB(op)); + FPR_USED(desc, G_REGC(op)); + FPR_MODIFIED(desc, G_RD(op)); + if (op & M_RC) + CR_MODIFIED(desc, 1); + desc.cycles = 2; // 601/603 + return true; + + case 0x1c: // FMSUBx + case 0x1d: // FMADDx + case 0x1e: // FNMSUBx + case 0x1f: // FNMADDx + FPR_USED(desc, G_RA(op)); + FPR_USED(desc, G_RB(op)); + FPR_USED(desc, G_REGC(op)); + FPR_MODIFIED(desc, G_RD(op)); + if (op & M_RC) + CR_MODIFIED(desc, 1); + desc.cycles = 2; // 601/603 + FPSCR_MODIFIED(desc, 4); + return true; + } + } + else + { + switch (opswitch) + { + case 0x32e: // FCTIDx - 64-bit only + case 0x32f: // FCTIDZx - 64-bit only + case 0x34e: // FCFIDx - 64-bit only + return false; + + case 0x000: // FCMPU + case 0x020: // FCMPO + FPR_USED(desc, G_RA(op)); + FPR_USED(desc, G_RB(op)); + CR_MODIFIED(desc, G_CRFD(op)); + return true; + + case 0x00c: // FRSPx + case 0x00e: // FCTIWx + case 0x00f: // FCTIWZx + FPSCR_MODIFIED(desc, 4); + case 0x028: // FNEGx + case 0x048: // FMRx + case 0x088: // FNABSx + case 0x108: // FABSx + FPR_USED(desc, G_RB(op)); + FPR_MODIFIED(desc, G_RD(op)); + if (op & M_RC) + CR_MODIFIED(desc, 1); + return true; + + case 0x026: // MTFSB1x + case 0x046: // MTFSB0x + FPSCR_MODIFIED(desc, G_CRBD(op) / 4); + return true; + + case 0x040: // MCRFS + FPSCR_USED(desc, G_CRFS(op)); + CR_MODIFIED(desc, G_CRFD(op)); + return true; + + case 0x086: // MTFSFIx + FPSCR_MODIFIED(desc, G_CRFD(op)); + return true; + + case 0x247: // MFFSx + FPSCR_USED(desc, 0); + FPSCR_USED(desc, 1); + FPSCR_USED(desc, 2); + FPSCR_USED(desc, 3); + FPSCR_USED(desc, 4); + FPSCR_USED(desc, 5); + FPSCR_USED(desc, 6); + FPSCR_USED(desc, 7); + FPR_MODIFIED(desc, G_RD(op)); + return true; + + case 0x2c7: // MTFSFx + FPR_USED(desc, G_RB(op)); + if (G_CRM(op) & 0x80) FPSCR_MODIFIED(desc, 0); + if (G_CRM(op) & 0x40) FPSCR_MODIFIED(desc, 1); + if (G_CRM(op) & 0x20) FPSCR_MODIFIED(desc, 2); + if (G_CRM(op) & 0x10) FPSCR_MODIFIED(desc, 3); + if (G_CRM(op) & 0x08) FPSCR_MODIFIED(desc, 4); + if (G_CRM(op) & 0x04) FPSCR_MODIFIED(desc, 5); + if (G_CRM(op) & 0x02) FPSCR_MODIFIED(desc, 6); + if (G_CRM(op) & 0x01) FPSCR_MODIFIED(desc, 7); + return true; + } + } + + return false; +} diff --git a/src/devices/cpu/powerpc/ppcfe.h b/src/devices/cpu/powerpc/ppcfe.h new file mode 100644 index 00000000000..5ba2f53dbb1 --- /dev/null +++ b/src/devices/cpu/powerpc/ppcfe.h @@ -0,0 +1,77 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + ppcfe.h + + Front-end for PowerPC recompiler + +***************************************************************************/ + +#ifndef __PPCFE_H__ +#define __PPCFE_H__ + +#include "ppc.h" +#include "cpu/drcfe.h" + + +//************************************************************************** +// MACROS +//************************************************************************** + +// register flags 0 +#define REGFLAG_R(n) (1 << (n)) +#define REGFLAG_RZ(n) (((n) == 0) ? 0 : REGFLAG_R(n)) + +// register flags 1 +#define REGFLAG_FR(n) (1 << (n)) + +// register flags 2 +#define REGFLAG_CR(n) (0xf0000000 >> (4 * (n))) +#define REGFLAG_CR_BIT(n) (0x80000000 >> (n)) + +// register flags 3 +#define REGFLAG_XER_CA (1 << 0) +#define REGFLAG_XER_OV (1 << 1) +#define REGFLAG_XER_SO (1 << 2) +#define REGFLAG_XER_COUNT (1 << 3) +#define REGFLAG_CTR (1 << 4) +#define REGFLAG_LR (1 << 5) +#define REGFLAG_FPSCR(n) (1 << (6 + (n))) + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class ppc_frontend : public drc_frontend +{ +public: + // construction/destruction + ppc_frontend(ppc_device *ppc, UINT32 window_start, UINT32 window_end, UINT32 max_sequence); + +protected: + // required overrides + virtual bool describe(opcode_desc &desc, const opcode_desc *prev); + +private: + // inlines + UINT32 compute_spr(UINT32 spr) const { return ((spr >> 5) | (spr << 5)) & 0x3ff; } + bool is_403_class() const { return (m_ppc->m_flavor == ppc_device::PPC_MODEL_403GA || m_ppc->m_flavor == ppc_device::PPC_MODEL_403GB || m_ppc->m_flavor == ppc_device::PPC_MODEL_403GC || m_ppc->m_flavor == ppc_device::PPC_MODEL_403GCX || m_ppc->m_flavor == ppc_device::PPC_MODEL_405GP); } + bool is_601_class() const { return (m_ppc->m_flavor == ppc_device::PPC_MODEL_601); } + bool is_602_class() const { return (m_ppc->m_flavor == ppc_device::PPC_MODEL_602); } + bool is_603_class() const { return (m_ppc->m_flavor == ppc_device::PPC_MODEL_603 || m_ppc->m_flavor == ppc_device::PPC_MODEL_603E || m_ppc->m_flavor == ppc_device::PPC_MODEL_603EV || m_ppc->m_flavor == ppc_device::PPC_MODEL_603R); } + + // internal helpers + bool describe_13(UINT32 op, opcode_desc &desc, const opcode_desc *prev); + bool describe_1f(UINT32 op, opcode_desc &desc, const opcode_desc *prev); + bool describe_3b(UINT32 op, opcode_desc &desc, const opcode_desc *prev); + bool describe_3f(UINT32 op, opcode_desc &desc, const opcode_desc *prev); + + // internal state + ppc_device *m_ppc; +}; + + +#endif /* __PPCFE_H__ */ diff --git a/src/devices/cpu/pps4/pps4.c b/src/devices/cpu/pps4/pps4.c new file mode 100644 index 00000000000..5be986f2c3d --- /dev/null +++ b/src/devices/cpu/pps4/pps4.c @@ -0,0 +1,1587 @@ +// license:BSD-3-Clause +// copyright-holders:Juergen Buchmueller + +/***************************************************************************** + * + * pps4.c + * + * Rockwell PPS-4 CPU + * Introduced in 1972, it ran at 256kHz. An improved version was released + * in 1975, but could only manage 200kHz. The chipset continued to be + * produced through the 1980s, but never found much acceptance. Chip + * numbers are 10660 (original), 11660, 12660. + * + * List of support / peripheral chips: + * 10706 Clock generator + * 10738 Bus interface + * 11049 Interval timer + * 10686 General purpose I/O + * 10696 General purpose I/O + * 10731 Telecommunications data interface + * 10736 dot matrix printer controller + * 10788 keyboard/display controller + * 10789 printer controller + * 10815 keyboard/printer controller + * 10930 Serial data controller + * 15380 dot matrix printer controller + * + * Note: External clock should be divided by 18 (not implemented). + * + * Pinouts: + * 10660 11660 + * + * +--------\ /--------+ +--------\ /--------+ + * 1 [| DIB-3 ++ DIA-3 |] 42 1 [| DIO-4 DIO-3 |] 42 + * 2 [-| DIA-2 DIB-4 |-] 41 2 [-| DIA-4 DIO-2 |-] 41 + * 3 [| DIB-2 DIA-4 |] 40 3 [| DIA-3 DIO-1 |] 40 + * 4 [-| DIA-1 NC |-] 39 4 [-| DIA-2 Vdd |-] 39 + * 5 [| DIB-1 A/B-1 |] 38 5 [| DIA-1 A/B-1 |] 38 + * 6 [-| Vdd A/B-2 |-] 37 6 [-| I/O-5 A/B-2 |-] 37 + * 7 [| I/D-5 A/B-3 |] 36 7 [| I/O-6 A/B-3 |] 36 + * 8 [-| I/D-6 A/B-4 |-] 35 8 [-| I/O-7 A/B-4 |-] 35 + * 9 [| I/D-7 A/B-5 |] 34 9 [| I/O-8 A/B-5 |] 34 + * 10 [-| I/D-8 A/B-6 |-] 33 10 [-| I/O-1 A/B-6 |-] 33 + * 11 [| I/D-1 A/B-7 |] 32 11 [| I/O-4 A/B-7 |] 32 + * 12 [-| I/D-4 A/B-8 |-] 31 12 [-| I/O-2 A/B-8 |-] 31 + * 13 [| I/D-2 A/B-9 |] 30 13 [| I/O-3 A/B-9 |] 30 + * 14 [-| I/D-3 A/B-10 |-] 29 14 [-| W/IO A/B-10 |-] 29 + * 15 [| W/IO A/B-11 |] 28 15 [| CLK ~B A/B-11 |] 28 + * 16 [-| CLK ~B A/B-12 |-] 27 16 [-| CLK A A/B-12 |-] 27 + * 17 [| CLK A NC |] 26 17 [| VCLK DO-4 |] 26 + * 18 [-| PO DO-3 |-] 25 18 [-| Xtal1 DO-3 |-] 25 + * 19 [| SPO DO-4 |] 24 19 [| Xtal2 DO-2 |] 24 + * 20 [-| DO-2 NC |-] 23 20 [-| Vss DO-1 |-] 23 + * 21 [| DO-1 Vss |] 22 21 [| SPO TC1-14 |] 22 + * +--------------------+ +--------------------+ + * + *****************************************************************************/ +#include "emu.h" +#include "debugger.h" +#include "pps4.h" + + +#define VERBOSE 0 //!< set to 1 to log certain instruction conditions + +#if VERBOSE +#define LOG(x) logerror x +#else +#define LOG(x) +#endif + +const device_type PPS4 = &device_creator; + +pps4_device::pps4_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : cpu_device(mconfig, PPS4, "PPS4", tag, owner, clock, "pps4", __FILE__ ) + , m_program_config("program", ENDIANNESS_LITTLE, 8, 12) + , m_data_config("data", ENDIANNESS_LITTLE, 8, 12) // 4bit RAM + , m_io_config("io", ENDIANNESS_LITTLE, 8, 8) // 4bit IO +{ +} + +/** + * @brief pps4_device::M Return the memory at address B + * @return ROM/RAM(B) + */ +UINT8 pps4_device::M() +{ + UINT8 ret = m_data->read_byte(m_B & ~m_SAG); + m_SAG = 0; + return ret; +} + + +/** + * @brief pps4_device::W Write to the memory address at B + * @return ROM/RAM(B) + */ +void pps4_device::W(UINT8 data) +{ + m_data->write_byte(m_B & ~m_SAG, data); + m_SAG = 0; +} + +offs_t pps4_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( pps4 ); + return CPU_DISASSEMBLE_NAME(pps4)(this, buffer, pc, oprom, opram, options); +} + +/** + * @brief pps4_device::ROP Read the next opcode (instruction) + * The previous opcode mask (upper four bits) is set from the + * previous instruction. The new opcode is fetched and the + * program counter is incremented. The icount is decremented. + * @return m_I the next opcode + */ +inline UINT8 pps4_device::ROP() +{ + const UINT8 op = m_direct->read_byte(m_P & 0xFFF); + m_Ip = m_I1; // save previous opcode + m_P = (m_P + 1) & 0xFFF; + m_icount -= 1; + return op; +} + +/** + * @brief pps4_device::ARG Read the next argument (instruction 2) + * The byte at program counter is read from the unencrypted + * direct space. The program count is incremented and the + * icount is decremented. + * @return m_I2 the next argument + */ +inline UINT8 pps4_device::ARG() +{ + const UINT8 arg = m_direct->read_byte(m_P & 0xFFF); + m_P = (m_P + 1) & 0xFFF; + m_icount -= 1; + return arg; +} + +/** + * @brief Note3 + * + * Instructions ADI, LD, EX, EXD, LDI, LB and LBL have a numeric + * value coded as part of the instruction in the immediate field. + * This numeric value must be in complementary form on the bus. + * All of these immediate fields which are inverted are shown + * in brackets. + * For example: ADI 1, as written by the programmer who wishes + * to add one to the value in the accumulator, is converted to + * 0x6E = 01001 [1110]; the bracketed binary value is the value + * as seen on the data bus. + * If the programmer is using the Rockwell Assembler he does not + * have to manually determine the proper inverted value as the + * assembler does this for him. + * + * [And we do in MAME as well :-] + */ + +/** + * @brief pps4_device::iAD Add + * HEX BINARY CYCLES MNEMONIC + * ---------------------------------- + * 0x0b 0000 1011 1 AD + * + * Symbolic equation + * ---------------------------------- + * C, A <- A + M + * + * The result of the binary addition of contents of accumulator + * and 4-bit contents of RAM currently addressed by B register, + * replaces the contents of the accumulator. The resulting + * carry-out is loaded into C flip-flop. + */ +void pps4_device::iAD() +{ + m_A = m_A + M(); + m_C = (m_A >> 4) & 1; + m_A = m_A & 15; +} + +/** + * @brief pps4_device::iADC Add with carry-in + * HEX BINARY CYCLES MNEMONIC + * ---------------------------------- + * 0x0a 0000 1010 1 ADC + * + * Symbolic equation + * ---------------------------------- + * C, A <- A + M + C + * + * Same as AD except the C flip-flop serves as a carry-in + * to the adder. + */ +void pps4_device::iADC() +{ + m_A = m_A + M() + m_C; + m_C = m_A >> 4; + m_A = m_A & 15; +} + +/** + * @brief pps4_device::iADSK Add and skip if carry-out + * HEX BINARY CYCLES MNEMONIC + * ---------------------------------- + * 0x09 0000 1001 1 ADSK + * + * Symbolic equation + * ---------------------------------- + * C, A <- A + M + * Skip if C = 1 + * + * Same as AD except the next ROM word will be + * skipped (ignored) if a carry-out is generated. + */ +void pps4_device::iADSK() +{ + m_A = m_A + M(); + m_C = m_A >> 4; + m_Skip = m_C; + m_A = m_A & 15; +} + +/** + * @brief pps4_device::iADCSK Add with carry-in and skip if carry-out + * HEX BINARY CYCLES MNEMONIC + * ---------------------------------- + * 0x08 0000 1000 1 ADCSK + * + * Symbolic equation + * ---------------------------------- + * C, A <- A + M + C + * Skip if C = 1 + * + * Same as ADC except the next ROM word will be + * skipped (ignored) if a carry-out is generated. + */ +void pps4_device::iADCSK() +{ + m_A = m_A + M() + m_C; + m_C = m_A >> 4; + m_Skip = m_C; + m_A = m_A & 15; +} + +/** + * @brief pps4_device::iADI Add immediate + * HEX BINARY CYCLES MNEMONIC + * ---------------------------------- + * 0x6* 0110 xxxx 1 ADI x + * + * Symbolic equation + * ---------------------------------- + * A <- A + [I(4:1)] + * + * The result of the binary addition of contents of + * accumulator and 4-bit immediate field of instruction + * word replaces the contents of accumulator. + * The next ROM word will be skipped (ignored) if a + * carry-out is generated. + * __ The instruction does not use or change the C flip-flop. __ + * The immediate field I(4:1) of this instruction may not + * be equal to binary 0 (CYS) or 0101 (DC) + * + * See %Note3 + */ +void pps4_device::iADI() +{ + const UINT8 imm = ~m_I1 & 15; + m_A = m_A + imm; + m_Skip = (m_A >> 4) & 1; + m_A = m_A & 15; +} + +/** + * @brief pps4_device::iDC Decimal correction + * HEX BINARY CYCLES MNEMONIC + * ---------------------------------- + * 0x65 0110 0101 1 DC + * + * Symbolic equation + * ---------------------------------- + * A <- A + 1010 + * + * Decimal correction of accumulator. + * Binary 1010 is added to the contents of the accumulator. + * Result is stored in accumulator. Instruction does not + * use or change carry flip-flop or skip. + */ +void pps4_device::iDC() +{ + m_A = m_A + 10; +} + +/** + * @brief pps4_device::iAND Logical AND + * HEX BINARY CYCLES MNEMONIC + * ---------------------------------- + * 0x0d 0000 1101 1 AND + * + * Symbolic equation + * ---------------------------------- + * A <- A & M + * + * The result of logical AND of accumulator and + * 4-bit contents of RAM currently addressed by + * B register replaces contents of accumulator. + */ +void pps4_device::iAND() +{ + m_A = m_A & M(); +} + +/** + * @brief pps4_device::iOR Logical OR + * HEX BINARY CYCLES MNEMONIC + * ---------------------------------- + * 0x0f 0000 1111 1 OR + * + * Symbolic equation + * ---------------------------------- + * A <- A | M + * + * The result of logical OR of accumulator and + * 4-bit contents of RAM currently addressed by + * B register replaces contents of accumulator. + */ +void pps4_device::iOR() +{ + m_A = m_A | M(); +} + +/** + * @brief pps4_device::iEOR Logical exclusive-OR + * HEX BINARY CYCLES MNEMONIC + * ---------------------------------- + * 0x0c 0000 1100 1 EOR + * + * Symbolic equation + * ---------------------------------- + * A <- A ^ M + * + * The result of logical exclusive-OR of + * accumulator and 4-bit contents of RAM + * currently addressed by B register + * replaces contents of accumulator. + */ +void pps4_device::iEOR() +{ + m_A = m_A ^ M(); +} + +/** + * @brief pps4_device::iCOMP Complement + * HEX BINARY CYCLES MNEMONIC + * ---------------------------------- + * 0x0e 0000 1110 1 COMP + * + * Symbolic equation + * ---------------------------------- + * A <- ~A + * + * Each bit of the accumulator is logically + * complemented and placed in accumulator. + */ +void pps4_device::iCOMP() +{ + m_A = m_A ^ 15; +} + +/** + * @brief pps4_device::iSC Set carry flip-flop + * HEX BINARY CYCLES MNEMONIC + * ---------------------------------- + * 0x20 0010 0000 1 SC + * + * Symbolic equation + * ---------------------------------- + * C <- 1 + * + * The C flip-flop is set to 1. + */ +void pps4_device::iSC() +{ + m_C = 1; +} + +/** + * @brief pps4_device::iRC Reset carry flip-flop + * HEX BINARY CYCLES MNEMONIC + * ---------------------------------- + * 0x28 0010 0100 1 RC + * + * Symbolic equation + * ---------------------------------- + * C <- 0 + * + * The C flip-flop is set to 0. + */ +void pps4_device::iRC() +{ + m_C = 0; +} + +/** + * @brief pps4_device::iSF1 Set flip-flop FF1 + * HEX BINARY CYCLES MNEMONIC + * ---------------------------------- + * 0x22 0010 0010 1 SF1 + * + * Symbolic equation + * ---------------------------------- + * FF1 <- 1 + * + * The Flip-flop FF1 is set to 1. + */ +void pps4_device::iSF1() +{ + m_FF1 = 1; +} + +/** + * @brief pps4_device::iRF1 Reset flip-flop FF1 + * HEX BINARY CYCLES MNEMONIC + * ---------------------------------- + * 0x26 0010 0110 1 RF1 + * + * Symbolic equation + * ---------------------------------- + * FF1 <- 0 + * + * The Flip-flop FF1 is set to 0. + */ +void pps4_device::iRF1() +{ + m_FF1 = 0; +} + +/** + * @brief pps4_device::iSF2 Set flip-flop FF2 + * HEX BINARY CYCLES MNEMONIC + * ---------------------------------- + * 0x21 0010 0001 1 SF2 + * + * Symbolic equation + * ---------------------------------- + * FF2 <- 1 + * + * The Flip-flop FF2 is set to 1. + */ +void pps4_device::iSF2() +{ + m_FF2 = 1; +} + +/** + * @brief pps4_device::iRF2 Reset flip-flop FF2 + * HEX BINARY CYCLES MNEMONIC + * ---------------------------------- + * 0x25 0010 0101 1 RF2 + * + * Symbolic equation + * ---------------------------------- + * FF2 <- 0 + * + * The flip-flop FF2 is set to 0. + */ +void pps4_device::iRF2() +{ + m_FF2 = 0; +} + +/** + * @brief pps4_device::iLD Load accumulator from memory + * HEX BINARY CYCLES MNEMONIC + * ---------------------------------- + * 0x30+ 0011 0xxx 1 LD x + * + * Symbolic equation + * ---------------------------------- + * A <- M + * B(7:5) <- B(7:5) ^ [I(3:1)] + * + * The 4-bit contents of RAM currently addressed + * by B register are placed in the accumulator. + * The RAM address in the B register is then + * modified by the result of an exclusive-OR of + * the 3-b it immediate field I(3:1) and B(7:5) + * + * See %Note3 + */ +void pps4_device::iLD() +{ + const UINT16 i3c = ~m_I1 & 7; + m_A = M(); + m_B = m_B ^ (i3c << 4); +} + +/** + * @brief pps4_device::iEX Exchange accumulator and memory + * HEX BINARY CYCLES MNEMONIC + * ---------------------------------- + * 0x38+ 0011 1xxx 1 EX x + * + * Symbolic equation + * ---------------------------------- + * A <-> M + * B(7:5) <- B(7:5) ^ [I(3:1)] + * + * The same as LD except the contents of accumulator + * are also placed in currently addressed RAM location. + * + * See %Note3 + */ +void pps4_device::iEX() +{ + const UINT16 i3c = ~m_I1 & 7; + const UINT8 mem = M(); + W(m_A); + m_A = mem; + m_B = m_B ^ (i3c << 4); +} + +/** + * @brief pps4_device::iEXD Exchange accumulator and memory and decrement BL + * HEX BINARY CYCLES MNEMONIC + * ---------------------------------- + * 0x28+ 0010 1xxx 1 EXD x + * + * Symbolic equation + * ---------------------------------- + * A <-> M + * B(7:5) <- B(7:5) ^ [I(3:1)] + * BL <- BL - 1 + * Skip on BL = 1111b + * + * The same as EX except RAM address in B register + * is further modified by decrementing BL by 1. + * If the new contents of BL is 1111, the next + * ROM word will be ignored. + * + * See %Note3 + */ +void pps4_device::iEXD() +{ + const UINT8 i3c = ~m_I1 & 7; + const UINT8 mem = M(); + UINT8 bl = m_B & 15; + W(m_A); + m_A = mem; + m_B = m_B ^ (i3c << 4); + // if decrement BL wraps to 1111b + if (0 == bl) { + bl = 15; + m_Skip = 1; + } else { + bl = bl - 1; + } + m_B = (m_B & ~15) | bl; +} + +/** + * @brief pps4_device::iLDI Load accumualtor immediate + * HEX BINARY CYCLES MNEMONIC + * ---------------------------------- + * 0x7* 0111 xxxx 1 LDI x + * + * Symbolic equation + * ---------------------------------- + * A <- [I(4:1)] + * + * The 4-bit contents, immediate field I(4:1), + * of the instruction are placed in the accumulator. + * + * Note: Only the first occurrence of an LDI in a consecutive + * string of LDIs will be executed. The program will ignore + * remaining LDIs and execute next valid instruction. + * + * See %Note3 + */ +void pps4_device::iLDI() +{ + // previous LDI instruction? + if (0x70 == (m_Ip & 0xf0)) { + LOG(("%s: skip prev:%02x op:%02x\n", __FUNCTION__, m_Ip, m_I1)); + return; + } + m_A = ~m_I1 & 15; +} + +/** + * @brief pps4_device::iLAX + * HEX BINARY CYCLES MNEMONIC + * ---------------------------------- + * 0x12 0001 0010 1 LAX + * + * Symbolic equation + * ---------------------------------- + * A <- X + * + * The 4-bit contents of the X register are + * placed in the accumulator. + */ +void pps4_device::iLAX() +{ + m_A = m_X; +} + +/** + * @brief pps4_device::iLXA + * HEX BINARY CYCLES MNEMONIC + * ---------------------------------- + * 0x1b 0001 1011 1 LXA + * + * Symbolic equation + * ---------------------------------- + * X <- A + * + * The contents of the accumulator are + * tansferred to the X register. + */ +void pps4_device::iLXA() +{ + m_X = m_A; +} + +/** + * @brief pps4_device::iLABL + * HEX BINARY CYCLES MNEMONIC + * ---------------------------------- + * 0x11 0001 0001 1 LABL + * + * Symbolic equation + * ---------------------------------- + * A <- BL + * + * The contents of BL register are + * tansferred to the accumulator. + */ +void pps4_device::iLABL() +{ + m_A = m_B & 15; +} + +/** + * @brief pps4_device::iLBMX + * HEX BINARY CYCLES MNEMONIC + * ---------------------------------- + * 0x10 0001 0000 1 LBMX + * + * Symbolic equation + * ---------------------------------- + * BM <- X + * + * The contents of X register are + * tansferred to BM register. + */ +void pps4_device::iLBMX() +{ + m_B = (m_B & ~(15 << 4)) | (m_X << 4); +} + +/** + * @brief pps4_device::iLBUA + * HEX BINARY CYCLES MNEMONIC + * ---------------------------------- + * 0x08 0000 0100 1 LBUA + * + * Symbolic equation + * ---------------------------------- + * BU <- A + * A <- M + * + * The contents of accumulator are tansferred to + * BU register. Also, the contents of the currently + * addressed RAM are transferred to accumulator. + */ +void pps4_device::iLBUA() +{ + m_B = (m_B & ~(15 << 8)) | (m_A << 8); + m_A = M(); +} + +/** + * @brief pps4_device::iXABL + * HEX BINARY CYCLES MNEMONIC + * ---------------------------------- + * 0x19 0001 1001 1 XABL + * + * Symbolic equation + * ---------------------------------- + * A <-> BL + * + * The contents of accumulator and BL register + * are exchanged. + */ +void pps4_device::iXABL() +{ + // swap A and BL + UINT8 bl = m_B & 15; + m_B = (m_B & ~15) | m_A; + m_A = bl; +} + +/** + * @brief pps4_device::iXMBX + * HEX BINARY CYCLES MNEMONIC + * ---------------------------------- + * 0x18 0001 1000 1 XMBX + * + * Symbolic equation + * ---------------------------------- + * X <-> BM + * + * The contents of accumulator and BL register + * are exchanged. + */ +void pps4_device::iXBMX() +{ + // swap X and BM + const UINT8 bm = (m_B >> 4) & 15; + m_B = (m_B & ~(15 << 4)) | (m_X << 4); + m_X = bm; +} + +/** + * @brief pps4_device::iXAX + * HEX BINARY CYCLES MNEMONIC + * ---------------------------------- + * 0x1a 0001 1010 1 XAX + * + * Symbolic equation + * ---------------------------------- + * A <-> X + * + * The contents of accumulator and X register + * are exchanged. + */ +void pps4_device::iXAX() +{ + // swap A and X + m_A ^= m_X; + m_X ^= m_A; + m_A ^= m_X; +} + +/** + * @brief pps4_device::iXS + * HEX BINARY CYCLES MNEMONIC + * ---------------------------------- + * 0x06 0000 0110 1 XS + * + * Symbolic equation + * ---------------------------------- + * SA <-> SB + * + * The 12-bit contents of SA and SB register + * are exchanged. + */ +void pps4_device::iXS() +{ + // swap SA and SB + m_SA ^= m_SB; + m_SB ^= m_SA; + m_SA ^= m_SB; +} + +/** + * @brief pps4_device::iCYS + * HEX BINARY CYCLES MNEMONIC + * ---------------------------------- + * 0x6f 0110 1111 1 CYS + * + * Symbolic equation + * ---------------------------------- + * A <- SA(4:1) + * SA(4:1) <- SA(8:5) + * SA(8:5) <- SA(12:9) + * SA(12:9) <- A + * + * A 4-bit right shift of the SA register takes place + * with the four bits which are shifted off the end + * of SA being transferred into the accumulator. + * The contents of the accumulator are placed in the + * left end of the SA register + * + */ +void pps4_device::iCYS() +{ + const UINT16 sa = (m_SA >> 4) | (m_A << 8); + m_A = m_SA & 15; + m_SA = sa; +} + +/** + * @brief pps4_device::iLB Load B indirect + * HEX BINARY CYCLES MNEMONIC + * ---------------------------------- + * 0xc* 1100 xxxx 2 LB x + * + * Symbolic equation + * ---------------------------------- + * SB <- SA, SA <- P + * P(12:5) <- 0000 1100 + * P(4:1) <- I(4:1) + * + * BU <- 0000 + * B(8:1) <- [I2(8:1)] + * P <- SA, SA <-> SB + * + * Sixteen consecutive locations on ROM page 3 (I2) contain + * data which can be loaded into the eight least significant + * bits of the B register by use of any LB instruction. + * The four most significant bits of B register will be loaded + * with zeros. The contents of the SB register will be destroyed. + * This instruction takes two cycles to execute but occupies + * only one ROM word. (Automatic return) + * + * Only the first occurrence of an LB or LBL instruction in a + * consecutive string of LB or LBL will be executed. The + * program will ignore the remaining LB or LBL and execute + * the next valid instruction. Within subroutines the LB + * instruction must be used with caution because the contents + * of SB have been modified. + * + * See %Note3 and %Note4 + */ +void pps4_device::iLB() +{ + // previous LB or LBL instruction? + if (0xc0 == (m_Ip & 0xf0) || 0x00 == m_Ip) { + LOG(("%s: skip prev:%02x op:%02x\n", __FUNCTION__, m_Ip, m_I1)); + return; + } + m_SB = m_SA; + m_SA = (m_P + 1) & 0xFFF; + m_P = (3 << 6) | (m_I1 & 15); + m_B = ~ARG() & 255; + m_P = m_SA; + // swap SA and SB + m_SA ^= m_SB; + m_SB ^= m_SA; + m_SA ^= m_SB; +} + +/** + * @brief pps4_device::iLBL Load B long + * HEX BINARY CYCLES MNEMONIC + * ---------------------------------- + * 0x00 0000 0000 2 LBL + * + * Symbolic equation + * ---------------------------------- + * BU <- 0000 + * B(8:1) <- [I2(8:1)] + * + * This instruction occupies two ROM words, the second of + * which will be loaded into the eight least significant + * bits of the B register. The four most significant bits + * of B (BU) will be loaded with zeroes. + * + * Only the first occurrence of an LB or LBL instruction in a + * consecutive string of LB or LBL will be executed. The + * program will ignore the remaining LB or LBL and execute + * the next valid instruction. + * + * See %Note3 + */ +void pps4_device::iLBL() +{ + m_I2 = ARG(); + // previous LB or LBL instruction? + if (0xc0 == (m_Ip & 0xf0) || 0x00 == m_Ip) { + LOG(("%s: skip prev:%02x op:%02x\n", __FUNCTION__, m_Ip, m_I1)); + return; + } + m_B = ~m_I2 & 255; // Note: immediate is 1's complement +} + +/** + * @brief pps4_device::INCB Increment B lower, skip if 0000 + * HEX BINARY CYCLES MNEMONIC + * ---------------------------------- + * 0x17 0001 0111 1 INCB + * + * Symbolic equation + * ---------------------------------- + * BL <- BL + 1 + * Skip on BL = 0000 + * + * BL register (least significant four bits of B register) + * is incremented by 1. If the new contents of BL is 0000b, + * then the next ROM word will be ignored. + */ +void pps4_device::iINCB() +{ + UINT8 bl = m_B & 15; + bl = (bl + 1) & 15; + if (0 == bl) { + LOG(("%s: skip BL=%x\n", __FUNCTION__, bl)); + m_Skip = 1; + } + m_B = (m_B & ~15) | bl; +} + +/** + * @brief pps4_device::iDECB Decrement B lower, skip if 1111 + * HEX BINARY CYCLES MNEMONIC + * ---------------------------------- + * 0x1f 0001 1111 1 DECB + * + * Symbolic equation + * ---------------------------------- + * BL <- BL - 1 + * Skip on BL = 1111 + * + * BL register is decremented by 1. If the new + * contents of BL is 1111b, then the next ROM + * word will be ignored. + */ +void pps4_device::iDECB() +{ + UINT8 bl = m_B & 15; + bl = (bl - 1) & 15; + if (15 == bl) { + LOG(("%s: skip BL=%x\n", __FUNCTION__, bl)); + m_Skip = 1; + } + m_B = (m_B & ~15) | bl; +} + +/** + * @brief pps4_device::iT Transfer + * HEX BINARY CYCLES MNEMONIC + * ---------------------------------- + * 0x80+ 10xx xxxx 1 T *xx + * + * Symbolic equation + * ---------------------------------- + * P(6:1) <- I(6:1) + * + * An unconditional transfer to a ROM word on the current + * page takes place. The least significant 6-bits of P + * register P(6:1) are replaced by six bit immediate + * field I(6:1) + */ +void pps4_device::iT() +{ + const UINT16 p = (m_P & ~63) | (m_I1 & 63); + LOG(("%s: P=%03x I=%02x -> P=%03x\n", __FUNCTION__, m_P, m_I1, p)); + m_P = p; +} + +/** + * @brief pps4_device::iTM Transfer and mark indirect + * HEX BINARY CYCLES MNEMONIC + * ---------------------------------- + * 0xc0+ 11xx xxxx 2 TM x + * yyyy yyyy from page 3 + * + * Symbolic equation + * ---------------------------------- + * SB <- SA, SA <- P + * P(12:7) <- 000011 + * P(6:1) <- I1(6:1) + * + * P(12:9) <- 0001 + * P(8:1) <- I2(8:1) + * + * 48 consecutive locations on ROM page 3 contains pointer data + * which indentify subroutine entry addresses. These subroutine + * entry addresses are limited to pages 4 through 7. This TM + * instruction will save the address of the next ROM word in + * the SA register after loading the original contents of SA + * into SB. A transfer then occurs to one of the subroutine + * entry addresses. This instruction occupies one ROM word + * but takes two cycles for execution. + */ +void pps4_device::iTM() +{ + m_SB = m_SA; + m_SA = m_P; + m_P = (3 << 6) | (m_I1 & 63); + m_I2 = ARG(); + m_P = (1 << 8) | m_I2; +} + +/** + * @brief pps4_device::iTL Transfer long + * HEX BINARY CYCLES MNEMONIC + * ---------------------------------- + * 0x5x 0101 xxxx 2 TL xyy + * yyyy yyyy + * + * Symbolic equation + * ---------------------------------- + * P(12:9) <- I1(4:1) + * P(8:1) <- I2(8:1) + * + * The instruction executes a transfer to any ROM word on any + * page. It occupies two ROM words an requires two cycles for + * execution. The first byte loads P(12:9) with field I1(4:1) + * and then the second byte I2(8:1) is placed in P(8:1). + */ +void pps4_device::iTL() +{ + m_I2 = ARG(); + m_P = ((m_I1 & 15) << 8) | m_I2; +} + +/** + * @brief pps4_device::iTML Transfer and mark long + * HEX BINARY CYCLES MNEMONIC + * ---------------------------------- + * 0x0* 0000 xxxx 2 TML xyy + * yyyy yyyy + * + * Symbolic equation + * ---------------------------------- + * SB <- SA, SA <- P + * P(12:9) <- I1(4:1) + * P(8:1) <- I2(8:1) + * + * Note I1(2:1) != 00 + * + * This instruction executes a transfer and mark to any + * location on ROM pages 4 through 15. It occupies two + * ROM words and requires two cycle times for execution. + */ +void pps4_device::iTML() +{ + m_I2 = ARG(); + m_SB = m_SA; + m_SA = m_P; + m_P = ((m_I1 & 15) << 8) | m_I2; +} + +/** + * @brief pps4_device::iSKC Skip on carry flip-flop + * HEX BINARY CYCLES MNEMONIC + * ---------------------------------- + * 0x15 0001 0101 1 SKC + * + * Symbolic equation + * ---------------------------------- + * Skip if C = 1 + * + * The next ROM word will be ignored if C flip-flop is 1. + */ +void pps4_device::iSKC() +{ + m_Skip = m_C; +} + +/** + * @brief pps4_device::iSKC Skip on carry flip-flop + * HEX BINARY CYCLES MNEMONIC + * ---------------------------------- + * 0x1e 0001 1110 1 SKZ + * + * Symbolic equation + * ---------------------------------- + * Skip if A = 0 + * + * The next ROM word will be ignored if C flip-flop is 1. + */ +void pps4_device::iSKZ() +{ + m_Skip = (0 == m_A) ? 1 : 0; +} + +/** + * @brief pps4_device::iSKBI Skip if BL equal to immediate + * HEX BINARY CYCLES MNEMONIC + * ---------------------------------- + * 0x4* 0100 xxxx 1 SKBI x + * + * Symbolic equation + * ---------------------------------- + * Skip if BL = I(4:1) + * + * The next ROM word will be ignored if the least significant + * four bits of B register (BL) is equal to the 4-bit immediate + * field I(4:1) of instruction. + */ +void pps4_device::iSKBI() +{ + const UINT8 i4 = m_I1 & 15; + const UINT8 bl = m_B & 15; + m_Skip = bl == i4 ? 1 : 0; +} + +/** + * @brief pps4_device::iSKF1 Skip if FF1 equals 1 + * HEX BINARY CYCLES MNEMONIC + * ---------------------------------- + * 0x16 0001 0110 1 SKF1 + * + * Symbolic equation + * ---------------------------------- + * Skip if FF1 = 1 + */ +void pps4_device::iSKF1() +{ + m_Skip = m_FF1; +} + +/** + * @brief pps4_device::iSKF2 Skip if FF2 equals 1 + * HEX BINARY CYCLES MNEMONIC + * ---------------------------------- + * 0x14 0001 0100 1 SKF2 + * + * Symbolic equation + * ---------------------------------- + * Skip if FF2 = 1 + */ +void pps4_device::iSKF2() +{ + m_Skip = m_FF2; +} + +/** + * @brief pps4_device::iRTN Return + * HEX BINARY CYCLES MNEMONIC + * ---------------------------------- + * 0x05 0000 0101 1 RTN + * + * Symbolic equation + * ---------------------------------- + * P <- SA, SA <-> SB + * + * This instruction executes a return from subroutine + * by loading contents of SA register into P register + * and interchanges the SB and SA registers. + */ +void pps4_device::iRTN() +{ + m_P = m_SA & 0xFFF; + // swap SA and SB + m_SA ^= m_SB; + m_SB ^= m_SA; + m_SA ^= m_SB; +} + +/** + * @brief pps4_device::iRTNSK Return and skip + * HEX BINARY CYCLES MNEMONIC + * ---------------------------------- + * 0x07 0000 0111 1 RTNSK + * + * Symbolic equation + * ---------------------------------- + * P <- SA, SA <-> SB + * P <- P + 1 + * + * Same as RTN except the first ROM word encountered + * after the return from subroutine is skipped. + */ +void pps4_device::iRTNSK() +{ + m_P = m_SA & 0xFFF; + // swap SA and SB + m_SA ^= m_SB; + m_SB ^= m_SA; + m_SA ^= m_SB; + m_Skip = 1; // next opcode is ignored +} + +/** + * @brief pps4_device::IOL Input / Output Long + * HEX BINARY CYCLES MNEMONIC + * ---------------------------------- + * 0x1c 0001 1100 2 IOL yy + * yyyy yyyy + * + * Symbolic equation + * ---------------------------------- + * ~A -> Data Bus + * A <- ~Data Bus + * I2 -> I/O device + * + * This instruction occupies two ROM words and requires two + * cycles for execution. The first ROM word is received by + * the CPU and sets up the I/O enable signal. The second + * ROM word is then received by the I/O devices and decoded + * for address and command. The contents of the accumulator + * inverted are placed on the data lines for acceptance by + * the I/O. At the same time, input data received by the I/O + * device is transferred to the accumulator inverted. + * + * FIXME: Is BL on the I/D:8-5 lines during the I/O cycle? + * The ROM, RAM, I/O chips A17xx suggest this, because they + * expect the value of BL to address one of the sixteen + * input/output lines. + */ +void pps4_device::iIOL() +{ + UINT8 ac = ((m_B & 15) << 4) | (~m_A & 15); + m_I2 = ARG(); + m_io->write_byte(m_I2, ac); + LOG(("%s: port:%02x <- %x\n", __FUNCTION__, m_I2, ac)); + ac = m_io->read_byte(m_I2) & 15; + LOG(("%s: port:%02x -> %x\n", __FUNCTION__, m_I2, ac)); + m_A = ~ac & 15; +} + +/** + * @brief pps4_device::iDIA Discrete input group A + * HEX BINARY CYCLES MNEMONIC + * ---------------------------------- + * 0x27 0010 0111 1 DIA + * + * Symbolic equation + * ---------------------------------- + * A <- DIA + * + * Data at the inputs to discrete group A is + * transferred to the accumulator. + */ +void pps4_device::iDIA() +{ + m_A = m_io->read_byte(PPS4_PORT_A) & 15; +} + +/** + * @brief pps4_device::iDIB Discrete input group B + * HEX BINARY CYCLES MNEMONIC + * ---------------------------------- + * 0x23 0010 0011 1 DIB + * + * Symbolic equation + * ---------------------------------- + * A <- DIB + * + * Data at the inputs to discrete group B is + * transferred to the accumulator. + */ +void pps4_device::iDIB() +{ + m_A = m_io->read_byte(PPS4_PORT_B) & 15; +} + +/** + * @brief pps4_device::iDOA Discrete output + * HEX BINARY CYCLES MNEMONIC + * ---------------------------------- + * 0x1d 0001 1101 1 DOA + * + * Symbolic equation + * ---------------------------------- + * DOA <- A + * + * The contents of the accumulator are transferred + * to the discrete output register. + */ +void pps4_device::iDOA() +{ + m_io->write_byte(PPS4_PORT_A, m_A); +} + +/** + * @brief pps4_device::iSAG Special address generation + * HEX BINARY CYCLES MNEMONIC + * ---------------------------------- + * 0x2d 0001 0011 1 SAG + * + * Symbolic equation + * ---------------------------------- + * A/B Bus (12:5) <- 0000 0000 + * A/B Bus (4:1) <- BL(4:1) + * Contents of B remains unchanged + * + * The instruction causes the eight most significant bits + * of the RAM address output to be zeroed during the next + * cycle only. Note that this instruction does not alter + * the contents of the B register. + */ +void pps4_device::iSAG() +{ + // mask bits 12:5 on next memory access + m_SAG = 0xff0; +} + +/*************************************************************************** + COMMON EXECUTION +***************************************************************************/ +void pps4_device::execute_one() +{ + m_I1 = ROP(); + if (m_Skip) { + m_Skip = 0; + LOG(("%s: skip op:%02x\n", __FUNCTION__, m_I1)); + return; + } + switch (m_I1) { + case 0x00: + iLBL(); + break; + case 0x01: + iTML(); + break; + case 0x02: + iTML(); + break; + case 0x03: + iTML(); + break; + case 0x04: + iLBUA(); + break; + case 0x05: + iRTN(); + break; + case 0x06: + iXS(); + break; + case 0x07: + iRTNSK(); + break; + case 0x08: + iADCSK(); + break; + case 0x09: + iADSK(); + break; + case 0x0a: + iADC(); + break; + case 0x0b: + iAD(); + break; + case 0x0c: + iEOR(); + break; + case 0x0d: + iAND(); + break; + case 0x0e: + iCOMP(); + break; + case 0x0f: + iOR(); + break; + + case 0x10: + iLBMX(); + break; + case 0x11: + iLABL(); + break; + case 0x12: + iLAX(); + break; + case 0x13: + iSAG(); + break; + case 0x14: + iSKF2(); + break; + case 0x15: + iSKC(); + break; + case 0x16: + iSKF1(); + break; + case 0x17: + iINCB(); + break; + case 0x18: + iXBMX(); + break; + case 0x19: + iXABL(); + break; + case 0x1a: + iXAX(); + break; + case 0x1b: + iLXA(); + break; + case 0x1c: + iIOL(); + break; + case 0x1d: + iDOA(); + break; + case 0x1e: + iSKZ(); + break; + case 0x1f: + iDECB(); + break; + + case 0x20: + iSC(); + break; + case 0x21: + iSF2(); + break; + case 0x22: + iSF1(); + break; + case 0x23: + iDIB(); + break; + case 0x24: + iRC(); + break; + case 0x25: + iRF2(); + break; + case 0x26: + iRF1(); + break; + case 0x27: + iDIA(); + break; + + case 0x28: case 0x29: case 0x2a: case 0x2b: + case 0x2c: case 0x2d: case 0x2e: case 0x2f: + iEXD(); + break; + + case 0x30: case 0x31: case 0x32: case 0x33: + case 0x34: case 0x35: case 0x36: case 0x37: + iLD(); + break; + + case 0x38: case 0x39: case 0x3a: case 0x3b: + case 0x3c: case 0x3d: case 0x3e: case 0x3f: + iEX(); + break; + + case 0x40: case 0x41: case 0x42: case 0x43: + case 0x44: case 0x45: case 0x46: case 0x47: + case 0x48: case 0x49: case 0x4a: case 0x4b: + case 0x4c: case 0x4d: case 0x4e: case 0x4f: + iSKBI(); + break; + + case 0x50: case 0x51: case 0x52: case 0x53: + case 0x54: case 0x55: case 0x56: case 0x57: + case 0x58: case 0x59: case 0x5a: case 0x5b: + case 0x5c: case 0x5d: case 0x5e: case 0x5f: + iTL(); + break; + + case 0x65: + iDC(); + break; + + case 0x60: case 0x61: case 0x62: case 0x63: + case 0x64: case 0x66: case 0x67: + case 0x68: case 0x69: case 0x6a: case 0x6b: + case 0x6c: case 0x6d: case 0x6e: + iADI(); + break; + + case 0x6f: + iCYS(); + 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: + iLDI(); + break; + + case 0x80: case 0x81: case 0x82: case 0x83: + case 0x84: case 0x85: case 0x86: case 0x87: + case 0x88: case 0x89: case 0x8a: case 0x8b: + case 0x8c: case 0x8d: case 0x8e: case 0x8f: + case 0x90: case 0x91: case 0x92: case 0x93: + case 0x94: case 0x95: case 0x96: case 0x97: + case 0x98: case 0x99: case 0x9a: case 0x9b: + case 0x9c: case 0x9d: case 0x9e: case 0x9f: + case 0xa0: case 0xa1: case 0xa2: case 0xa3: + case 0xa4: case 0xa5: case 0xa6: case 0xa7: + case 0xa8: case 0xa9: case 0xaa: case 0xab: + case 0xac: case 0xad: case 0xae: case 0xaf: + case 0xb0: case 0xb1: case 0xb2: case 0xb3: + case 0xb4: case 0xb5: case 0xb6: case 0xb7: + case 0xb8: case 0xb9: case 0xba: case 0xbb: + case 0xbc: case 0xbd: case 0xbe: case 0xbf: + iT(); + break; + + + case 0xc0: case 0xc1: case 0xc2: case 0xc3: + case 0xc4: case 0xc5: case 0xc6: case 0xc7: + case 0xc8: case 0xc9: case 0xca: case 0xcb: + case 0xcc: case 0xcd: case 0xce: case 0xcf: + iLB(); + break; + + default: + iTM(); + } +} + +void pps4_device::execute_run() +{ + do + { + debugger_instruction_hook(this, m_P); + execute_one(); + + } while (m_icount > 0); +} + +/*************************************************************************** + CORE INITIALIZATION +***************************************************************************/ + +void pps4_device::device_start() +{ + m_program = &space(AS_PROGRAM); + m_direct = &m_program->direct(); + m_data = &space(AS_DATA); + m_io = &space(AS_IO); + + save_item(NAME(m_A)); + save_item(NAME(m_X)); + save_item(NAME(m_P)); + save_item(NAME(m_SA)); + save_item(NAME(m_SB)); + save_item(NAME(m_Skip)); + save_item(NAME(m_SAG)); + save_item(NAME(m_B)); + save_item(NAME(m_C)); + save_item(NAME(m_FF1)); + save_item(NAME(m_FF2)); + save_item(NAME(m_I1)); + save_item(NAME(m_I2)); + save_item(NAME(m_Ip)); + + state_add( PPS4_PC, "PC", m_P ).mask(0xFFF).formatstr("%03X"); + state_add( PPS4_A, "A", m_A ).formatstr("%01X"); + state_add( PPS4_X, "X", m_X ).formatstr("%01X"); + state_add( PPS4_SA, "SA", m_SA ).formatstr("%03X"); + state_add( PPS4_SB, "SB", m_SB ).formatstr("%03X"); + state_add( PPS4_Skip, "Skip", m_Skip ).formatstr("%01X"); + state_add( PPS4_SAG, "SAG", m_SAG ).formatstr("%03X"); + state_add( PPS4_B, "B", m_B ).formatstr("%03X"); + state_add( PPS4_I1, "I1", m_I1 ).formatstr("%02X").noshow(); + state_add( PPS4_I2, "I2", m_I2 ).formatstr("%02X").noshow(); + state_add( PPS4_Ip, "Ip", m_Ip ).formatstr("%02X").noshow(); + state_add( STATE_GENPC, "GENPC", m_P ).noshow(); + state_add( STATE_GENFLAGS, "GENFLAGS", m_C).formatstr("%3s").noshow(); + + m_icountptr = &m_icount; +} + +void pps4_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + switch (entry.index()) + { + case STATE_GENFLAGS: + strprintf(str, "%c%c%c", + m_C ? 'C':'.', + m_FF1 ? '1':'.', + m_FF2 ? '2':'.'); + break; + } +} + +/*************************************************************************** + COMMON RESET +***************************************************************************/ + +void pps4_device::device_reset() +{ + m_A = 0; // Accumulator A(4:1) + m_X = 0; // X register X(4:1) + m_P = 0; // program counter P(12:1) + m_SA = 0; // Shift register SA(12:1) + m_SB = 0; // Shift register SB(12:1) + m_SAG = 0; // Special address generation mask + m_B = 0; // B address register B(12:1) (BL, BM and BU) + m_C = 0; // Carry flip-flop + m_FF1 = 0; // Flip-flop 1 + m_FF2 = 0; // Flip-flop 2 + m_I1 = 0; // Most recent instruction I(8:1) + m_I2 = 0; // Most recent parameter I2(8:1) + m_Ip = 0; // Previous instruction I(8:1) +} diff --git a/src/devices/cpu/pps4/pps4.h b/src/devices/cpu/pps4/pps4.h new file mode 100644 index 00000000000..8c115745cbb --- /dev/null +++ b/src/devices/cpu/pps4/pps4.h @@ -0,0 +1,167 @@ +// license:BSD-3-Clause +// copyright-holders:Juergen Buchmueller +#ifndef __PPS4_H__ +#define __PPS4_H__ + + +/*************************************************************************** + CONSTANTS +***************************************************************************/ +enum +{ + PPS4_PC, + PPS4_A, + PPS4_X, + PPS4_SA, + PPS4_SB, + PPS4_B, + PPS4_Skip, + PPS4_SAG, + PPS4_I1, + PPS4_I2, + PPS4_Ip, + PPS4_GENPC = STATE_GENPC, + PPS4_GENSP = STATE_GENSP, + PPS4_GENPCBASE = STATE_GENPCBASE, + PPS4_PORT_A = 256, + PPS4_PORT_B = 257 +}; + +/*************************************************************************** + TYPE DEFINITIONS +***************************************************************************/ + +/*************************************************************************** + FUNCTION PROTOTYPES +***************************************************************************/ + +extern const device_type PPS4; + +class pps4_device : public cpu_device +{ +public: + // construction/destruction + pps4_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_execute_interface overrides + virtual UINT32 execute_min_cycles() const { return 1; } + virtual UINT32 execute_max_cycles() const { return 3; } + virtual UINT32 execute_input_lines() const { return 0; } + virtual UINT32 execute_default_irq_vector() const { return 0; } + virtual void execute_run(); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const + { + return (spacenum == AS_PROGRAM) ? &m_program_config : ( (spacenum == AS_IO) ? &m_io_config : ( (spacenum == AS_DATA) ? &m_data_config : NULL ) ); + } + + // device_state_interface overrides + void state_string_export(const device_state_entry &entry, std::string &str); + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const { return 1; } + virtual UINT32 disasm_max_opcode_bytes() const { return 2; } + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + +private: + address_space_config m_program_config; + address_space_config m_data_config; + address_space_config m_io_config; + + address_space *m_program; + direct_read_data *m_direct; + address_space *m_data; + address_space *m_io; + int m_icount; + + UINT8 m_A; //!< Accumulator A(4:1) + UINT8 m_X; //!< X register X(4:1) + UINT16 m_P; //!< program counter P(12:1) + UINT16 m_SA; //!< Shift register SA(12:1) + UINT16 m_SB; //!< Shift register SB(12:1) + UINT8 m_Skip; //!< Skip next instruction + UINT16 m_SAG; //!< Special address generation mask + UINT16 m_B; //!< B register B(12:1) (BL, BM and BH) + UINT8 m_C; //!< Carry flip-flop + UINT8 m_FF1; //!< Flip-flop 1 + UINT8 m_FF2; //!< Flip-flop 2 + UINT8 m_I1; //!< Most recent instruction I(8:1) + UINT8 m_I2; //!< Most recent parameter I2(8:1) + UINT8 m_Ip; //!< Previous instruction I(8:1) + + //! return the contents of B register (made of BU, BM and BL) + inline UINT16 B() const; + + //! return memory at address B(12:1) + inline UINT8 M(); + + //! write to memory at address B(12:1) + inline void W(UINT8 data); + + //! return the next opcode (also in m_I) + inline UINT8 ROP(); + + //! return the next argument (also in m_I2) + inline UINT8 ARG(); + + void iAD(); //!< Add + void iADC(); //!< Add with carry-in + void iADSK(); //!< Add and skip on carry-out + void iADCSK(); //!< Add with carry-in and skip on carry-out + void iADI(); //!< Add immediate + void iDC(); //!< Decimal correction + void iAND(); //!< Logical AND + void iOR(); //!< Logical OR + void iEOR(); //!< Logical Exclusive-OR + void iCOMP(); //!< Complement + void iSC(); //!< Set Carry flip-flop + void iRC(); //!< Reset Carry flip-flop + void iSF1(); //!< Set FF1 + void iRF1(); //!< Reset FF1 + void iSF2(); //!< Set FF2 + void iRF2(); //!< Reset FF2 + void iLD(); //!< Load accumulator from memory + void iEX(); //!< Exchange accumulator and memory + void iEXD(); //!< Exchange accumulator and memory and decrement BL + void iLDI(); //!< Load accumulator immediate + void iLAX(); //!< Load accumulator from X register + void iLXA(); //!< Load X register from accumulator + void iLABL(); //!< Load accumulator with BL + void iLBMX(); //!< Load BM with X + void iLBUA(); //!< Load BU with A + void iXABL(); //!< Exchange accumulator and BL + void iXBMX(); //!< Exchange BM and X registers + void iXAX(); //!< Exchange accumulator and X + void iXS(); //!< Eychange SA and SB registers + void iCYS(); //!< Cycle SA register and accumulaor + void iLB(); //!< Load B indirect + void iLBL(); //!< Load B long + void iINCB(); //!< Increment BL + void iDECB(); //!< Decrement BL + void iT(); //!< Transfer + void iTM(); //!< Transfer and mark indirect + void iTL(); //!< Transfer long + void iTML(); //!< Transfer and mark long + void iSKC(); //!< Skip on carry flip-flop + void iSKZ(); //!< Skip on accumulator zero + void iSKBI(); //!< Skip if BL equal to immediate + void iSKF1(); //!< Skip if FF1 equals 1 + void iSKF2(); //!< Skip if FF2 equals 1 + void iRTN(); //!< Return + void iRTNSK(); //!< Return and skip + void iIOL(); //!< Input/Output long + void iDIA(); //!< Discrete input group A + void iDIB(); //!< Discrete input group B + void iDOA(); //!< Discrete output group A + void iSAG(); //!< Special address generation + + void execute_one(); //!< execute one instruction +}; + +#endif // __PPS4_H__ diff --git a/src/devices/cpu/pps4/pps4dasm.c b/src/devices/cpu/pps4/pps4dasm.c new file mode 100644 index 00000000000..4ee5079ee91 --- /dev/null +++ b/src/devices/cpu/pps4/pps4dasm.c @@ -0,0 +1,443 @@ +// license:BSD-3-Clause +// copyright-holders:Juergen Buchmueller +/***************************************************************************** + * + * pps4dasm.c + * + * Rockwell PPS-4 CPU Disassembly + * + * + * TODO: double verify all opcodes with t_Ixx flags + * + *****************************************************************************/ +#include "emu.h" + +#define OP(A) oprom[(A) - PC] +#define ARG(A) opram[(A) - PC] + +typedef enum pps4_token_e { + t_AD, t_ADC, t_ADSK, t_ADCSK, t_ADI, + t_DC, t_AND, t_OR, t_EOR, t_COMP, + t_SC, t_RC, t_SF1, t_RF1, t_SF2, + t_RF2, t_LD, t_EX, t_EXD, t_LDI, + t_LAX, t_LXA, t_LABL, t_LBMX, t_LBUA, + t_XABL, t_XBMX, t_XAX, t_XS, t_CYS, + t_LB, t_LBL, t_INCB, t_DECB, t_T, + t_TM, t_TL, t_TML, t_SKC, t_SKZ, + t_SKBI, t_SKF1, t_SKF2, t_RTN, t_RTNSK, + t_IOL, t_DIA, t_DIB, t_DOA, t_SAG, + t_COUNT, + t_MASK = (1 << 6) - 1, + t_I3c = 1 << 6, /* immediate 3 bit constant, complemented */ + t_I4 = 1 << 7, /* immediate 4 bit constant */ + t_I4c = 1 << 8, /* immediate 4 bit constant, complemented */ + t_I4p = 1 << 9, /* immediate 4 bit offset into page 3 */ + t_I6p = 1 << 10, /* immediate 6 bit constant; address in current page */ + t_I6i = 1 << 11, /* immediate 6 bit indirect page 3 offset (16 ... 63) + followed by page 1 address */ + t_I8 = 1 << 12, /* immediate 8 bit constant (I/O port number) */ + t_I8c = 1 << 13, /* immediate 8 bit constant inverted */ + t_OVER = 1 << 14, /* Debugger step over (CALL) */ + t_OUT = 1 << 15 /* Debugger step out (RETURN) */ +} pps4_token_e; + +static const char *token_str[t_COUNT] = { + "ad", /* add */ + "adc", /* add with carry-in */ + "adsk", /* add and skip on carry-out */ + "adcsk", /* add with carry-in and skip on carry-out */ + "adi", /* add immediate */ + "dc", /* decimal correction */ + "and", /* logical and */ + "or", /* logical or */ + "eor", /* logical exclusive-orf */ + "comp", /* complement */ + "sc", /* set C flip-flop */ + "rc", /* reset C flip-flop */ + "sf1", /* set FF1 flip-flop */ + "rf1", /* reset FF1 flip-flop */ + "sf2", /* set FF2 flip-flop */ + "rf2", /* reset FF2 flip-flop */ + "ld", /* load accumulator from memory */ + "ex", /* exchange accumulator and memory */ + "exd", /* exchange accumulator and memory and decrement BL */ + "ldi", /* load accumulator immediate */ + "lax", /* load accumulator from X register */ + "lxa", /* load X register from accumulator */ + "labl", /* load accumulator with BL */ + "lbmx", /* load BM with X */ + "lbua", /* load BU with A */ + "xabl", /* exchange accumulator and BL */ + "xbmx", /* exchange BM and X */ + "xax", /* exchange accumulator and X */ + "xs", /* exchange SA and SB */ + "cys", /* cycle SA register and accumulator */ + "lb", /* load B indirect */ + "lbl", /* load B long */ + "incb", /* increment BL */ + "decb", /* decrement BL */ + "t", /* transfer */ + "tm", /* transfer and mark indirect */ + "tl", /* transfer long */ + "tml", /* transfer and mark long */ + "skc", /* skip on C flip-flop equals 1 */ + "skz", /* skip on accumulator zero */ + "skbi", /* skip on BL equal to immediate */ + "skf1", /* skip on FF1 flip-flop equals 1 */ + "skf2", /* skip on FF2 flip-flop equals 1 */ + "rtn", /* return */ + "rtnsk", /* return and skip */ + "iol", /* input/output long */ + "dia", /* discrete input group A */ + "dib", /* discrete input group B */ + "doa", /* discrete output */ + "sag" /* special address generation */ +}; + +static const UINT16 table[] = { +/* 00 */ t_LBL | t_I8c, +/* 01 */ t_TML | t_I4 | t_I8, +/* 02 */ t_TML | t_I4 | t_I8, +/* 03 */ t_TML | t_I4 | t_I8, +/* 04 */ t_LBUA, +/* 05 */ t_RTN | t_OUT, +/* 06 */ t_XS, +/* 07 */ t_RTNSK | t_OUT, +/* 08 */ t_ADCSK, +/* 09 */ t_ADSK, +/* 0a */ t_ADC, +/* 0b */ t_AD, +/* 0c */ t_EOR, +/* 0d */ t_AND, +/* 0e */ t_COMP, +/* 0f */ t_OR, + +/* 10 */ t_LBMX, +/* 11 */ t_LABL, +/* 12 */ t_LAX, +/* 13 */ t_SAG, +/* 14 */ t_SKF2, +/* 15 */ t_SKC, +/* 16 */ t_SKF1, +/* 17 */ t_INCB, +/* 18 */ t_XBMX, +/* 19 */ t_XABL, +/* 1a */ t_XAX, +/* 1b */ t_LXA, +/* 1c */ t_IOL | t_I8, +/* 1d */ t_DOA, +/* 1e */ t_SKZ, +/* 1f */ t_DECB, + +/* 20 */ t_SC, +/* 21 */ t_SF2, +/* 22 */ t_SF1, +/* 23 */ t_DIB, +/* 24 */ t_RC, +/* 25 */ t_RF2, +/* 26 */ t_RF1, +/* 27 */ t_DIA, +/* 28 */ t_EXD | t_I3c, +/* 29 */ t_EXD | t_I3c, +/* 2a */ t_EXD | t_I3c, +/* 2b */ t_EXD | t_I3c, +/* 2c */ t_EXD | t_I3c, +/* 2d */ t_EXD | t_I3c, +/* 2e */ t_EXD | t_I3c, +/* 2f */ t_EXD | t_I3c, + +/* 30 */ t_LD | t_I3c, +/* 31 */ t_LD | t_I3c, +/* 32 */ t_LD | t_I3c, +/* 33 */ t_LD | t_I3c, +/* 34 */ t_LD | t_I3c, +/* 35 */ t_LD | t_I3c, +/* 36 */ t_LD | t_I3c, +/* 37 */ t_LD | t_I3c, +/* 38 */ t_EX | t_I3c, +/* 39 */ t_EX | t_I3c, +/* 3a */ t_EX | t_I3c, +/* 3b */ t_EX | t_I3c, +/* 3c */ t_EX | t_I3c, +/* 3d */ t_EX | t_I3c, +/* 3e */ t_EX | t_I3c, +/* 3f */ t_EX | t_I3c, + +/* 40 */ t_SKBI | t_I4, +/* 41 */ t_SKBI | t_I4, +/* 42 */ t_SKBI | t_I4, +/* 43 */ t_SKBI | t_I4, +/* 44 */ t_SKBI | t_I4, +/* 45 */ t_SKBI | t_I4, +/* 46 */ t_SKBI | t_I4, +/* 47 */ t_SKBI | t_I4, +/* 48 */ t_SKBI | t_I4, +/* 49 */ t_SKBI | t_I4, +/* 4a */ t_SKBI | t_I4, +/* 4b */ t_SKBI | t_I4, +/* 4c */ t_SKBI | t_I4, +/* 4d */ t_SKBI | t_I4, +/* 4e */ t_SKBI | t_I4, +/* 4f */ t_SKBI | t_I4, + +/* 50 */ t_TL | t_I4 | t_I8 | t_OVER, +/* 51 */ t_TL | t_I4 | t_I8 | t_OVER, +/* 52 */ t_TL | t_I4 | t_I8 | t_OVER, +/* 53 */ t_TL | t_I4 | t_I8 | t_OVER, +/* 54 */ t_TL | t_I4 | t_I8 | t_OVER, +/* 55 */ t_TL | t_I4 | t_I8 | t_OVER, +/* 56 */ t_TL | t_I4 | t_I8 | t_OVER, +/* 57 */ t_TL | t_I4 | t_I8 | t_OVER, +/* 58 */ t_TL | t_I4 | t_I8 | t_OVER, +/* 59 */ t_TL | t_I4 | t_I8 | t_OVER, +/* 5a */ t_TL | t_I4 | t_I8 | t_OVER, +/* 5b */ t_TL | t_I4 | t_I8 | t_OVER, +/* 5c */ t_TL | t_I4 | t_I8 | t_OVER, +/* 5d */ t_TL | t_I4 | t_I8 | t_OVER, +/* 5e */ t_TL | t_I4 | t_I8 | t_OVER, +/* 5f */ t_TL | t_I4 | t_I8 | t_OVER, + +/* 60 */ t_ADI | t_I4c, +/* 61 */ t_ADI | t_I4c, +/* 62 */ t_ADI | t_I4c, +/* 63 */ t_ADI | t_I4c, +/* 64 */ t_ADI | t_I4c, +/* 65 */ t_DC, +/* 66 */ t_ADI | t_I4c, +/* 67 */ t_ADI | t_I4c, +/* 68 */ t_ADI | t_I4c, +/* 69 */ t_ADI | t_I4c, +/* 6a */ t_ADI | t_I4c, +/* 6b */ t_ADI | t_I4c, +/* 6c */ t_ADI | t_I4c, +/* 6d */ t_ADI | t_I4c, +/* 6e */ t_ADI | t_I4c, +/* 6f */ t_CYS, + +/* 70 */ t_LDI | t_I4c, +/* 71 */ t_LDI | t_I4c, +/* 72 */ t_LDI | t_I4c, +/* 73 */ t_LDI | t_I4c, +/* 74 */ t_LDI | t_I4c, +/* 75 */ t_LDI | t_I4c, +/* 76 */ t_LDI | t_I4c, +/* 77 */ t_LDI | t_I4c, +/* 78 */ t_LDI | t_I4c, +/* 79 */ t_LDI | t_I4c, +/* 7a */ t_LDI | t_I4c, +/* 7b */ t_LDI | t_I4c, +/* 7c */ t_LDI | t_I4c, +/* 7d */ t_LDI | t_I4c, +/* 7e */ t_LDI | t_I4c, +/* 7f */ t_LDI | t_I4c, + +/* 80 */ t_T | t_I6p, +/* 81 */ t_T | t_I6p, +/* 82 */ t_T | t_I6p, +/* 83 */ t_T | t_I6p, +/* 84 */ t_T | t_I6p, +/* 85 */ t_T | t_I6p, +/* 86 */ t_T | t_I6p, +/* 87 */ t_T | t_I6p, +/* 88 */ t_T | t_I6p, +/* 89 */ t_T | t_I6p, +/* 8a */ t_T | t_I6p, +/* 8b */ t_T | t_I6p, +/* 8c */ t_T | t_I6p, +/* 8d */ t_T | t_I6p, +/* 8e */ t_T | t_I6p, +/* 8f */ t_T | t_I6p, + +/* 90 */ t_T | t_I6p, +/* 91 */ t_T | t_I6p, +/* 92 */ t_T | t_I6p, +/* 93 */ t_T | t_I6p, +/* 94 */ t_T | t_I6p, +/* 95 */ t_T | t_I6p, +/* 96 */ t_T | t_I6p, +/* 97 */ t_T | t_I6p, +/* 98 */ t_T | t_I6p, +/* 99 */ t_T | t_I6p, +/* 9a */ t_T | t_I6p, +/* 9b */ t_T | t_I6p, +/* 9c */ t_T | t_I6p, +/* 9d */ t_T | t_I6p, +/* 9e */ t_T | t_I6p, +/* 9f */ t_T | t_I6p, + +/* a0 */ t_T | t_I6p, +/* a1 */ t_T | t_I6p, +/* a2 */ t_T | t_I6p, +/* a3 */ t_T | t_I6p, +/* a4 */ t_T | t_I6p, +/* a5 */ t_T | t_I6p, +/* a6 */ t_T | t_I6p, +/* a7 */ t_T | t_I6p, +/* a8 */ t_T | t_I6p, +/* a9 */ t_T | t_I6p, +/* aa */ t_T | t_I6p, +/* ab */ t_T | t_I6p, +/* ac */ t_T | t_I6p, +/* ad */ t_T | t_I6p, +/* ae */ t_T | t_I6p, +/* af */ t_T | t_I6p, + +/* b0 */ t_T | t_I6p, +/* b1 */ t_T | t_I6p, +/* b2 */ t_T | t_I6p, +/* b3 */ t_T | t_I6p, +/* b4 */ t_T | t_I6p, +/* b5 */ t_T | t_I6p, +/* b6 */ t_T | t_I6p, +/* b7 */ t_T | t_I6p, +/* b8 */ t_T | t_I6p, +/* b9 */ t_T | t_I6p, +/* ba */ t_T | t_I6p, +/* bb */ t_T | t_I6p, +/* bc */ t_T | t_I6p, +/* bd */ t_T | t_I6p, +/* be */ t_T | t_I6p, +/* bf */ t_T | t_I6p, + +/* c0 */ t_LB | t_I4p, +/* c1 */ t_LB | t_I4p, +/* c2 */ t_LB | t_I4p, +/* c3 */ t_LB | t_I4p, +/* c4 */ t_LB | t_I4p, +/* c5 */ t_LB | t_I4p, +/* c6 */ t_LB | t_I4p, +/* c7 */ t_LB | t_I4p, +/* c8 */ t_LB | t_I4p, +/* c9 */ t_LB | t_I4p, +/* ca */ t_LB | t_I4p, +/* cb */ t_LB | t_I4p, +/* cc */ t_LB | t_I4p, +/* cd */ t_LB | t_I4p, +/* ce */ t_LB | t_I4p, +/* cf */ t_LB | t_I4p, + +/* d0 */ t_TM | t_I6i | t_OVER, +/* d1 */ t_TM | t_I6i | t_OVER, +/* d2 */ t_TM | t_I6i | t_OVER, +/* d3 */ t_TM | t_I6i | t_OVER, +/* d4 */ t_TM | t_I6i | t_OVER, +/* d5 */ t_TM | t_I6i | t_OVER, +/* d6 */ t_TM | t_I6i | t_OVER, +/* d7 */ t_TM | t_I6i | t_OVER, +/* d8 */ t_TM | t_I6i | t_OVER, +/* d9 */ t_TM | t_I6i | t_OVER, +/* da */ t_TM | t_I6i | t_OVER, +/* db */ t_TM | t_I6i | t_OVER, +/* dc */ t_TM | t_I6i | t_OVER, +/* dd */ t_TM | t_I6i | t_OVER, +/* de */ t_TM | t_I6i | t_OVER, +/* df */ t_TM | t_I6i | t_OVER, + +/* e0 */ t_TM | t_I6i | t_OVER, +/* e1 */ t_TM | t_I6i | t_OVER, +/* e2 */ t_TM | t_I6i | t_OVER, +/* e3 */ t_TM | t_I6i | t_OVER, +/* e4 */ t_TM | t_I6i | t_OVER, +/* e5 */ t_TM | t_I6i | t_OVER, +/* e6 */ t_TM | t_I6i | t_OVER, +/* e7 */ t_TM | t_I6i | t_OVER, +/* e8 */ t_TM | t_I6i | t_OVER, +/* e9 */ t_TM | t_I6i | t_OVER, +/* ea */ t_TM | t_I6i | t_OVER, +/* eb */ t_TM | t_I6i | t_OVER, +/* ec */ t_TM | t_I6i | t_OVER, +/* ed */ t_TM | t_I6i | t_OVER, +/* ee */ t_TM | t_I6i | t_OVER, +/* ef */ t_TM | t_I6i | t_OVER, + +/* f0 */ t_TM | t_I6i | t_OVER, +/* f1 */ t_TM | t_I6i | t_OVER, +/* f2 */ t_TM | t_I6i | t_OVER, +/* f3 */ t_TM | t_I6i | t_OVER, +/* f4 */ t_TM | t_I6i | t_OVER, +/* f5 */ t_TM | t_I6i | t_OVER, +/* f6 */ t_TM | t_I6i | t_OVER, +/* f7 */ t_TM | t_I6i | t_OVER, +/* f8 */ t_TM | t_I6i | t_OVER, +/* f9 */ t_TM | t_I6i | t_OVER, +/* fa */ t_TM | t_I6i | t_OVER, +/* fb */ t_TM | t_I6i | t_OVER, +/* fc */ t_TM | t_I6i | t_OVER, +/* fd */ t_TM | t_I6i | t_OVER, +/* fe */ t_TM | t_I6i | t_OVER, +/* ff */ t_TM | t_I6i | t_OVER +}; + +CPU_DISASSEMBLE( pps4 ) +{ + UINT32 flags = 0; + unsigned PC = pc; + UINT8 op = OP(pc++); + UINT32 tok = table[op]; + char *dst = 0; + + if (0 == (tok & t_MASK)) { + sprintf(buffer, "%s", token_str[tok & t_MASK]); + } else { + dst = buffer + sprintf(buffer, "%-7s", token_str[tok & t_MASK]); + } + + if (tok & t_I3c) { + // 3 bit immediate, complemented + UINT8 i = ~op & 7; + if (0 != i) // only print if non-zero + dst += sprintf(dst, "%x", i); + } + + if (tok & t_I4) { + // 4 bit immediate + UINT8 i = op & 15; + dst += sprintf(dst, "%x", i); + } + + if (tok & t_I4c) { + // 4 bit immediate, complemented + UINT8 i = ~op & 15; + dst += sprintf(dst, "%x", i); + } + + if (tok & t_I4p) { + // 4 bit immediate offset into page 3 + UINT8 i = op & 15; + dst += sprintf(dst, "[%x]", 0x0c0 | i); + } + + if (tok & t_I6p) { + // 6 bit immediate offset into current page + UINT8 i = op & 63; + dst += sprintf(dst, "%x", (PC & ~63) | i); + } + + if (tok & t_I6i) { + // 6 bit immediate offset into page 3 + UINT16 i6p3 = (3 << 6) | (op & 63); + // 8 bit absolute offset at 0x0100 + UINT16 addr = (1 << 8) | 0; // ROM[ip3] can't be reached!? + (void)addr; // avoid unused variable warning + dst += sprintf(dst, "[%x]", i6p3); + } + + if (tok & t_I8) { + // 8 bit immediate I/O port address + UINT8 arg = ARG(pc++); + dst += sprintf(dst, "%02x", arg); + } + + if (tok & t_I8c) { + // 8 bit immediate offset into page + UINT16 arg = ~ARG(pc++) & 255; + dst += sprintf(dst, "%02x", arg); + } + + if (tok & t_OVER) // TL or TML + flags |= DASMFLAG_STEP_OVER; + + if (tok & t_OUT) // RTN or RTNSK + flags |= DASMFLAG_STEP_OUT; + + return (pc - PC) | flags | DASMFLAG_SUPPORTED; +} diff --git a/src/devices/cpu/psx/dismips.c b/src/devices/cpu/psx/dismips.c new file mode 100644 index 00000000000..76f67fba2cf --- /dev/null +++ b/src/devices/cpu/psx/dismips.c @@ -0,0 +1,361 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/* + * standalone MIPS disassembler by smf + * + * based on DIS68k by Aaron Giles + * + */ + +#include "emu.h" +#include "psx.h" + +extern CPU_DISASSEMBLE( r3000le ); +extern unsigned dasmmips3(char *,unsigned, UINT32); + +static struct +{ + UINT8 id[ 8 ]; + UINT32 text; /* SCE only */ + UINT32 data; /* SCE only */ + UINT32 pc0; + UINT32 gp0; /* SCE only */ + UINT32 t_addr; + UINT32 t_size; + UINT32 d_addr; /* SCE only */ + UINT32 d_size; /* SCE only */ + UINT32 b_addr; /* SCE only */ + UINT32 b_size; /* SCE only */ + UINT32 s_addr; + UINT32 s_size; + UINT32 SavedSP; + UINT32 SavedFP; + UINT32 SavedGP; + UINT32 SavedRA; + UINT32 SavedS0; + UINT8 dummy[ 0x800 - 76 ]; +} m_psxexe_header; + +#define FORMAT_BIN ( 0 ) +#define FORMAT_PSX ( 1 ) + +#define CPU_PSX ( 0 ) +#define CPU_R3000 ( 1 ) +#define CPU_R4000 ( 2 ) + +static UINT8 *filebuf; +static UINT32 offset; +static UINT8 order[] = { 0, 1, 2, 3 }; + +static const char *const Options[]= +{ + "begin", "end", "offset", "order", "format", "cpu", 0 +}; + +static void usage (void) +{ + fprintf( stderr, + "Usage: DISMIPS [options] \n\n" + "Available options are:\n" + " -begin - Specify begin offset in file to disassemble in bytes [0]\n" + " -end - Specify end offset in file to disassemble in bytes [none]\n" + " -offset - Specify address to load program in bytes [0]\n" + " -order - Specify byte order [0123]\n" + " -format - Specify file format bin|psx [bin]\n" + " -cpu - Specify cpu psx|r3000|r4000 [psx]\n\n" + "All values should be entered in hexadecimal\n" ); + exit( 1 ); +} + +int main( int argc, char *argv[] ) +{ + FILE *f; + UINT8 i; + UINT8 j; + UINT8 n; + UINT8 p; + UINT32 begin; + UINT32 end; + UINT32 filelen; + UINT32 len; + UINT32 pc; + char buffer[ 80 ]; + char *filename; + UINT32 format; + UINT32 cpu; + + filename = NULL; + begin = 0; + end = 0xffffffff; + format = FORMAT_BIN; + cpu = CPU_PSX; + + n = 0; + for( i = 1; i < argc; i++ ) + { + if( argv[ i ][ 0 ] != '-' ) + { + switch( n ) + { + case 0: + filename = argv[ i ]; + break; + default: + usage(); + break; + } + n++; + } + else + { + for( j = 0; Options[ j ]; j++ ) + { + if( strcmp( argv[ i ] + 1, Options[ j ] ) == 0 ) + { + break; + } + } + switch( j ) + { + case 0: + i++; + if( i > argc ) + { + usage(); + } + begin = strtoul( argv[ i ], 0, 16 ); + break; + case 1: + i++; + if( i > argc ) + { + usage(); + } + end = strtoul( argv[ i ], 0, 16 ); + break; + case 2: + i++; + if( i > argc ) + { + usage(); + } + offset = strtoul( argv[ i ], 0, 16 ); + break; + case 3: + i++; + if( i > argc ) + { + usage(); + } + if( strlen( argv[ i ] ) != 4 ) + { + usage(); + } + for( p = 0; p < 4; p++ ) + { + if( argv[ i ][ p ] < '0' || argv[ i ][ p ] > '3' ) + { + usage(); + } + order[ p ] = argv[ i ][ p ] - '0'; + } + break; + case 4: + i++; + if( i > argc ) + { + usage(); + } + if( core_stricmp( argv[ i ], "bin" ) == 0 ) + { + format = FORMAT_BIN; + } + else if( core_stricmp( argv[ i ], "psx" ) == 0 ) + { + format = FORMAT_PSX; + } + else + { + usage(); + } + break; + case 5: + i++; + if( i > argc ) + { + usage(); + } + if( core_stricmp( argv[ i ], "psx" ) == 0 ) + { + cpu = CPU_PSX; + } + else if( core_stricmp( argv[ i ], "r3000" ) == 0 ) + { + cpu = CPU_R3000; + } + else if( core_stricmp( argv[ i ], "r4000" ) == 0 ) + { + cpu = CPU_R4000; + } + else + { + usage(); + } + break; + default: + usage(); + break; + } + } + } + + if (!filename) + { + usage(); + return 1; + } + f=fopen (filename,"rb"); + if (!f) + { + printf ("Unable to open %s\n",filename); + return 2; + } + fseek (f,0,SEEK_END); + filelen=ftell (f); + + if( format == FORMAT_PSX ) + { + fseek( f, 0, SEEK_SET ); + if( fread( &m_psxexe_header, 1, sizeof( m_psxexe_header ), f ) != sizeof( m_psxexe_header ) ) + { + fprintf( stderr, "error reading ps-x exe header\n" ); + fclose( f ); + return 3; + } + if( memcmp( m_psxexe_header.id, "PS-X EXE", sizeof( m_psxexe_header.id ) ) != 0 ) + { + fprintf( stderr, "invalid ps-x exe header\n" ); + fclose( f ); + return 3; + } + printf( "_start = $%08x\n\n", m_psxexe_header.pc0 ); + if( offset == 0 ) + { + offset = m_psxexe_header.t_addr; + } + if( begin == 0 ) + { + begin = sizeof( m_psxexe_header ); + } + if( end == 0xffffffff ) + { + end = sizeof( m_psxexe_header ) + m_psxexe_header.t_size; + } + } + + fseek (f,begin,SEEK_SET); + len=(filelen>end)? (end-begin+1):(filelen-begin); + filebuf=(UINT8 *)malloc(len+16); + if (!filebuf) + { + printf ("Memory allocation error\n"); + fclose (f); + return 3; + } + memset (filebuf,0,len+16); + if (fread(filebuf,1,len,f)!=len) + { + printf ("Read error\n"); + fclose (f); + free (filebuf); + return 4; + } + fclose (f); + + pc = 0; + while( pc < len ) + { + UINT8 op0 = filebuf[ pc + order[ 0 ] ]; + UINT8 op1 = filebuf[ pc + order[ 1 ] ]; + UINT8 op2 = filebuf[ pc + order[ 2 ] ]; + UINT8 op3 = filebuf[ pc + order[ 3 ] ]; + filebuf[ pc + 0 ] = op0; + filebuf[ pc + 1 ] = op1; + filebuf[ pc + 2 ] = op2; + filebuf[ pc + 3 ] = op3; + + pc += 4; + } + + pc = 0; + while( pc < len ) + { + switch( cpu ) + { + case CPU_PSX: + i = DasmPSXCPU( NULL, buffer, pc + offset, filebuf + pc ); + break; + case CPU_R3000: + { + legacy_cpu_device *device = NULL; + int options = 0; + UINT8 *opram = filebuf + pc; + UINT8 *oprom = opram; + i = CPU_DISASSEMBLE_CALL( r3000le ); + } + break; + case CPU_R4000: + { + UINT8 *opram = filebuf + pc; + UINT32 op = ( opram[ 3 ] << 24 ) | ( opram[ 2 ] << 16 ) | ( opram[ 1 ] << 8 ) | ( opram[ 0 ] << 0 ); + i = dasmmips3( buffer, pc + offset, op ); + } + break; + } + + i &= DASMFLAG_LENGTHMASK; + + printf( "%08x: ", pc + offset ); + for( j = 0; j < i; j++ ) + { + printf( "%02x ", filebuf[ pc ] ); + pc++; + } + while( j < 10 ) + { + printf( " " ); + j++; + } + printf( "%s\n", buffer ); + } + free (filebuf); + return 0; +} + +void *osd_malloc_array(size_t size) +{ + return osd_malloc(size); +} + +void *malloc_array_file_line(size_t size, const char *file, int line) +{ + // allocate the memory and fail if we can't + return osd_malloc_array(size); +} + +void free_file_line( void *memory, const char *file, int line ) +{ + osd_free( memory ); +} + +void osd_free( void *memory ) +{ +#undef free + free( memory ); +} + +void *osd_malloc( size_t size ) +{ +#undef malloc + return malloc( size ); +} diff --git a/src/devices/cpu/psx/dismips.mak b/src/devices/cpu/psx/dismips.mak new file mode 100644 index 00000000000..306d6f53788 --- /dev/null +++ b/src/devices/cpu/psx/dismips.mak @@ -0,0 +1,2 @@ +..\..\..\..\dismips.exe: dismips.c psxdasm.c ..\mips\r3kdasm.c ..\mips\mips3dsm.c ../../../lib/util/corestr.c + gcc -O3 -x c++ -Wall -Wno-sign-compare -I../../../emu -I../../../osd -I../../../lib/util -I../../../lib/expat -DINLINE="static __inline__" -DSTANDALONE -DLSB_FIRST dismips.c psxdasm.c ..\mips\r3kdasm.c ..\mips\mips3dsm.c ../../../lib/util/corestr.c -o../../../../dismips diff --git a/src/devices/cpu/psx/dma.c b/src/devices/cpu/psx/dma.c new file mode 100644 index 00000000000..5f3386a188e --- /dev/null +++ b/src/devices/cpu/psx/dma.c @@ -0,0 +1,424 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/* + * PlayStation DMA emulator + * + * Copyright 2003-2011 smf + * + */ + +#include "emu.h" +#include "dma.h" + +#define VERBOSE_LEVEL ( 0 ) + +INLINE void ATTR_PRINTF(3,4) verboselog( running_machine& machine, int n_level, const char *s_fmt, ... ) +{ + if( VERBOSE_LEVEL >= n_level ) + { + va_list v; + char buf[ 32768 ]; + va_start( v, s_fmt ); + vsprintf( buf, s_fmt, v ); + va_end( v ); + logerror( "%s: %s", machine.describe_context(), buf ); + } +} + +const device_type PSX_DMA = &device_creator; + +psxdma_device::psxdma_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, PSX_DMA, "Sony PSX DMA", tag, owner, clock, "psxdma", __FILE__), + m_irq_handler(*this) +{ +} + +void psxdma_device::device_reset() +{ + int n; + + m_dpcp = 0; + m_dicr = 0; + + for( n = 0; n < 7; n++ ) + { + dma_stop_timer( n ); + } +} + +void psxdma_device::device_post_load() +{ + int n; + + for( n = 0; n < 7; n++ ) + { + dma_timer_adjust( n ); + } +} + +void psxdma_device::device_start() +{ + m_irq_handler.resolve_safe(); + + for( int index = 0; index < 7; index++ ) + { + psx_dma_channel *dma = &m_channel[ index ]; + + dma->timer = timer_alloc(index); + + save_item( NAME( dma->n_base ), index ); + save_item( NAME( dma->n_blockcontrol ), index ); + save_item( NAME( dma->n_channelcontrol ), index ); + save_item( NAME( dma->n_ticks ), index ); + save_item( NAME( dma->b_running ), index ); + } + + save_item( NAME(m_dpcp) ); + save_item( NAME(m_dicr) ); +} + +void psxdma_device::dma_start_timer( int index, UINT32 n_ticks ) +{ + psx_dma_channel *dma = &m_channel[ index ]; + + dma->timer->adjust( attotime::from_hz(33868800) * n_ticks, index); + dma->n_ticks = n_ticks; + dma->b_running = 1; +} + +void psxdma_device::dma_stop_timer( int index ) +{ + psx_dma_channel *dma = &m_channel[ index ]; + + dma->timer->adjust( attotime::never); + dma->b_running = 0; +} + +void psxdma_device::dma_timer_adjust( int index ) +{ + psx_dma_channel *dma = &m_channel[ index ]; + + if( dma->b_running ) + { + dma_start_timer( index, dma->n_ticks ); + } + else + { + dma_stop_timer( index ); + } +} + +void psxdma_device::dma_interrupt_update() +{ + int n_int; + int n_mask; + + n_int = ( m_dicr >> 24 ) & 0x7f; + n_mask = ( m_dicr >> 16 ) & 0xff; + + if( ( n_mask & 0x80 ) != 0 && ( n_int & n_mask ) != 0 ) + { + verboselog( machine(), 2, "dma_interrupt_update( %02x, %02x ) interrupt triggered\n", n_int, n_mask ); + m_dicr |= 0x80000000; + m_irq_handler(1); + } + else if( n_int != 0 ) + { + verboselog( machine(), 2, "dma_interrupt_update( %02x, %02x ) interrupt not enabled\n", n_int, n_mask ); + } + m_dicr &= 0x00ffffff | ( m_dicr << 8 ); +} + +void psxdma_device::dma_finished( int index ) +{ + psx_dma_channel *dma = &m_channel[ index ]; + + if( dma->n_channelcontrol == 0x01000401 && index == 2 ) + { + UINT32 n_size; + UINT32 n_total; + UINT32 n_address = ( dma->n_base & 0xffffff ); + UINT32 n_adrmask = m_ramsize - 1; + UINT32 n_nextaddress; + + if( n_address != 0xffffff ) + { + n_total = 0; + for( ;; ) + { + if( n_address == 0xffffff ) + { + dma->n_base = n_address; + //HACK: fixes pse bios 2.x & other texture uploading issues, breaks kdeadeye test mode, gtrfrk7m & gtrkfrk8m loading + //dma_start_timer( index, 19000 ); + dma_start_timer( index, 500 ); + return; + } + if( n_total > 65535 ) + { + dma->n_base = n_address; + //FIXME: + // 16000 below is based on try and error. + // Mametesters.org: sfex20103red + //dma_start_timer( index, 16 ); + dma_start_timer( index, 16000 ); + return; + } + n_address &= n_adrmask; + n_nextaddress = m_ram[ n_address / 4 ]; + n_size = n_nextaddress >> 24; + dma->fn_write( m_ram, n_address + 4, n_size ); + //FIXME: + // The following conditions will cause an endless loop. + // If stopping the transfer is correct I cannot judge + // The patch is meant as a hint for somebody who knows + // the hardware. + // Mametesters.org: psyforce0105u5red, raystorm0111u1red + if ((n_nextaddress & 0xffffff) != 0xffffff) + { + if (n_address == m_ram[ (n_nextaddress & n_adrmask) / 4] || + n_address == (n_nextaddress & n_adrmask) ) + { + break; + } + } + n_address = ( n_nextaddress & 0xffffff ); + + n_total += ( n_size + 1 ); + } + } + } + + dma->n_channelcontrol &= ~( ( 1L << 0x18 ) | ( 1L << 0x1c ) ); + + m_dicr |= 1 << ( 24 + index ); + dma_interrupt_update(); + dma_stop_timer( index ); +} + +void psxdma_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + dma_finished(id); +} + +void psxdma_device::install_read_handler( int index, psx_dma_read_delegate p_fn_dma_read ) +{ + m_channel[ index ].fn_read = p_fn_dma_read; +} + +void psxdma_device::install_write_handler( int index, psx_dma_read_delegate p_fn_dma_write ) +{ + m_channel[ index ].fn_write = p_fn_dma_write; +} + +WRITE32_MEMBER( psxdma_device::write ) +{ + int index = offset / 4; + psx_dma_channel *dma = &m_channel[ index ]; + + if( index < 7 ) + { + switch( offset % 4 ) + { + case 0: + verboselog( machine(), 2, "dmabase( %d ) = %08x\n", index, data ); + dma->n_base = data; + break; + case 1: + verboselog( machine(), 2, "dmablockcontrol( %d ) = %08x\n", index, data ); + dma->n_blockcontrol = data; + break; + case 2: + verboselog( machine(), 2, "dmachannelcontrol( %d ) = %08x\n", index, data ); + dma->n_channelcontrol = data; + if( ( dma->n_channelcontrol & ( 1L << 0x18 ) ) != 0 && ( m_dpcp & ( 1 << ( 3 + ( index * 4 ) ) ) ) != 0 ) + { + INT32 n_size; + UINT32 n_address; + UINT32 n_nextaddress; + UINT32 n_adrmask; + + n_adrmask = m_ramsize - 1; + + n_address = ( dma->n_base & n_adrmask ); + n_size = dma->n_blockcontrol; + if( ( dma->n_channelcontrol & 0x200 ) != 0 ) + { + UINT32 n_ba; + n_ba = dma->n_blockcontrol >> 16; + if( n_ba == 0 ) + { + n_ba = 0x10000; + } + n_size = ( n_size & 0xffff ) * n_ba; + } + + if( dma->n_channelcontrol == 0x01000000 && + !dma->fn_read.isnull() ) + { + verboselog( machine(), 1, "dma %d read block %08x %08x\n", index, n_address, n_size ); + dma->fn_read( m_ram, n_address, n_size ); + dma_finished( index ); + } + else if ((dma->n_channelcontrol & 0xffbffeff) == 0x11000000 && // CD DMA + !dma->fn_read.isnull() ) + { + verboselog( machine(), 1, "dma %d read block %08x %08x\n", index, n_address, n_size ); + + // pSX's CD DMA size calc formula + int oursize = (dma->n_blockcontrol>>16); + oursize = (oursize > 1) ? oursize : 1; + oursize *= (dma->n_blockcontrol&0xffff); + + dma->fn_read( m_ram, n_address, oursize ); + dma_finished( index ); + } + else if( dma->n_channelcontrol == 0x01000200 && + !dma->fn_read.isnull() ) + { + verboselog( machine(), 1, "dma %d read block %08x %08x\n", index, n_address, n_size ); + dma->fn_read( m_ram, n_address, n_size ); + if( index == 1 ) + { + dma_start_timer( index, 26000 ); + } + else + { + dma_finished( index ); + } + } + else if( dma->n_channelcontrol == 0x01000201 && + !dma->fn_write.isnull() ) + { + verboselog( machine(), 1, "dma %d write block %08x %08x\n", index, n_address, n_size ); + dma->fn_write( m_ram, n_address, n_size ); + dma_finished( index ); + } + else if( dma->n_channelcontrol == 0x11050100 && + !dma->fn_write.isnull() ) + { + /* todo: check this is a write not a read... */ + verboselog( machine(), 1, "dma %d write block %08x %08x\n", index, n_address, n_size ); + dma->fn_write( m_ram, n_address, n_size ); + dma_finished( index ); + } + else if( dma->n_channelcontrol == 0x11150100 && + !dma->fn_write.isnull() ) + { + /* todo: check this is a write not a read... */ + verboselog( machine(), 1, "dma %d write block %08x %08x\n", index, n_address, n_size ); + dma->fn_write( m_ram, n_address, n_size ); + dma_finished( index ); + } + else if( dma->n_channelcontrol == 0x01000401 && + index == 2 && + !dma->fn_write.isnull() ) + { + verboselog( machine(), 1, "dma %d write linked list %08x\n", + index, dma->n_base ); + + dma_finished( index ); + } + else if( dma->n_channelcontrol == 0x11000002 && + index == 6 ) + { + verboselog( machine(), 1, "dma 6 reverse clear %08x %08x\n", + dma->n_base, dma->n_blockcontrol ); + if( n_size > 0 ) + { + n_size--; + while( n_size > 0 ) + { + n_nextaddress = ( n_address - 4 ) & 0xffffff; + m_ram[ n_address / 4 ] = n_nextaddress; + n_address = n_nextaddress; + n_size--; + } + m_ram[ n_address / 4 ] = 0xffffff; + } + dma_start_timer( index, 2150 ); + } + else + { + verboselog( machine(), 1, "dma %d unknown mode %08x\n", index, dma->n_channelcontrol ); + } + } + else if( dma->n_channelcontrol != 0 ) + { + verboselog( machine(), 1, "psx_dma_w( %04x, %08x, %08x ) channel not enabled\n", offset, dma->n_channelcontrol, mem_mask ); + } + break; + default: + verboselog( machine(), 1, "psx_dma_w( %04x, %08x, %08x ) Unknown dma channel register\n", offset, data, mem_mask ); + break; + } + } + else + { + switch( offset % 4 ) + { + case 0x0: + verboselog( machine(), 1, "psx_dma_w( %04x, %08x, %08x ) dpcp\n", offset, data, mem_mask ); + m_dpcp = ( m_dpcp & ~mem_mask ) | data; + break; + case 0x1: + + m_dicr = ( m_dicr & ( 0x80000000 | ~mem_mask ) ) | + ( m_dicr & ~data & 0x7f000000 & mem_mask ) | + ( data & 0x00ffffff & mem_mask ); + + if( ( m_dicr & 0x80000000 ) != 0 && ( m_dicr & 0x7f000000 ) == 0 ) + { + verboselog( machine(), 2, "dma interrupt cleared\n" ); + m_dicr &= ~0x80000000; + } + + verboselog( machine(), 1, "psx_dma_w( %04x, %08x, %08x ) dicr -> %08x\n", offset, data, mem_mask, m_dicr ); + break; + default: + verboselog( machine(), 0, "psx_dma_w( %04x, %08x, %08x ) Unknown dma control register\n", offset, data, mem_mask ); + break; + } + } +} + +READ32_MEMBER( psxdma_device::read ) +{ + int index = offset / 4; + psx_dma_channel *dma = &m_channel[ index ]; + + if( index < 7 ) + { + switch( offset % 4 ) + { + case 0: + verboselog( machine(), 1, "psx_dma_r dmabase[ %d ] ( %08x )\n", index, dma->n_base ); + return dma->n_base; + case 1: + verboselog( machine(), 1, "psx_dma_r dmablockcontrol[ %d ] ( %08x )\n", index, dma->n_blockcontrol ); + return dma->n_blockcontrol; + case 2: + verboselog( machine(), 1, "psx_dma_r dmachannelcontrol[ %d ] ( %08x )\n", index, dma->n_channelcontrol ); + return dma->n_channelcontrol; + default: + verboselog( machine(), 0, "psx_dma_r( %08x, %08x ) Unknown dma channel register\n", offset, mem_mask ); + break; + } + } + else + { + switch( offset % 4 ) + { + case 0x0: + verboselog( machine(), 1, "psx_dma_r dpcp ( %08x )\n", m_dpcp ); + return m_dpcp; + case 0x1: + verboselog( machine(), 1, "psx_dma_r dicr ( %08x )\n", m_dicr ); + return m_dicr; + default: + verboselog( machine(), 0, "psx_dma_r( %08x, %08x ) Unknown dma control register\n", offset, mem_mask ); + break; + } + } + return 0; +} diff --git a/src/devices/cpu/psx/dma.h b/src/devices/cpu/psx/dma.h new file mode 100644 index 00000000000..3e99583ca60 --- /dev/null +++ b/src/devices/cpu/psx/dma.h @@ -0,0 +1,76 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/* + * PlayStation DMA emulator + * + * Copyright 2003-2011 smf + * + */ + +#pragma once + +#ifndef __PSXDMA_H__ +#define __PSXDMA_H__ + +#include "emu.h" + +extern const device_type PSX_DMA; + +#define MCFG_PSX_DMA_IRQ_HANDLER(_devcb) \ + devcb = &psxdma_device::set_irq_handler(*device, DEVCB_##_devcb); + +typedef delegate psx_dma_read_delegate; +typedef delegate psx_dma_write_delegate; + +struct psx_dma_channel +{ + UINT32 n_base; + UINT32 n_blockcontrol; + UINT32 n_channelcontrol; + emu_timer *timer; + psx_dma_read_delegate fn_read; + psx_dma_write_delegate fn_write; + UINT32 n_ticks; + UINT32 b_running; +}; + +class psxdma_device : public device_t +{ +public: + psxdma_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // static configuration helpers + template static devcb_base &set_irq_handler(device_t &device, _Object object) { return downcast(device).m_irq_handler.set_callback(object); } + + void install_read_handler( int n_channel, psx_dma_read_delegate p_fn_dma_read ); + void install_write_handler( int n_channel, psx_dma_read_delegate p_fn_dma_write ); + + DECLARE_WRITE32_MEMBER( write ); + DECLARE_READ32_MEMBER( read ); + + UINT32 *m_ram; + size_t m_ramsize; + +protected: + virtual void device_start(); + virtual void device_reset(); + virtual void device_post_load(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + +private: + void dma_start_timer( int n_channel, UINT32 n_ticks ); + void dma_stop_timer( int n_channel ); + void dma_timer_adjust( int n_channel ); + void dma_interrupt_update(); + void dma_finished( int n_channel ); + void write( offs_t offset, UINT32 data, UINT32 mem_mask ); + UINT32 read( offs_t offset, UINT32 mem_mask ); + + psx_dma_channel m_channel[7]; + UINT32 m_dpcp; + UINT32 m_dicr; + + devcb_write_line m_irq_handler; +}; + +#endif diff --git a/src/devices/cpu/psx/gte.c b/src/devices/cpu/psx/gte.c new file mode 100644 index 00000000000..ce50afba6a4 --- /dev/null +++ b/src/devices/cpu/psx/gte.c @@ -0,0 +1,946 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/* + * PlayStation Geometry Transformation Engine emulator + * + * Copyright 2003-2013 smf + * + */ + +#include "emu.h" +#include "gte.h" + +#if 0 +void ATTR_PRINTF(2,3) GTELOG( UINT32 pc, const char *a, ...) +{ + va_list va; + char s_text[ 1024 ]; + va_start( va, a ); + vsprintf( s_text, a, va ); + va_end( va ); + logerror( "%08x: GTE: %s\n", pc, s_text ); +} +#else +INLINE void ATTR_PRINTF(2,3) GTELOG( UINT32 pc, const char *a, ...) {} +#endif + + +#define VX0 ( m_cp2dr[ 0 ].sw.l ) +#define VY0 ( m_cp2dr[ 0 ].sw.h ) +#define VZ0 ( m_cp2dr[ 1 ].sw.l ) +#define VX1 ( m_cp2dr[ 2 ].w.l ) +#define VY1 ( m_cp2dr[ 2 ].w.h ) +#define VZ1 ( m_cp2dr[ 3 ].w.l ) +#define VX2 ( m_cp2dr[ 4 ].w.l ) +#define VY2 ( m_cp2dr[ 4 ].w.h ) +#define VZ2 ( m_cp2dr[ 5 ].w.l ) +#define R ( m_cp2dr[ 6 ].b.l ) +#define G ( m_cp2dr[ 6 ].b.h ) +#define B ( m_cp2dr[ 6 ].b.h2 ) +#define CODE ( m_cp2dr[ 6 ].b.h3 ) +#define OTZ ( m_cp2dr[ 7 ].w.l ) +#define IR0 ( m_cp2dr[ 8 ].sw.l ) +#define IR1 ( m_cp2dr[ 9 ].sw.l ) +#define IR2 ( m_cp2dr[ 10 ].sw.l ) +#define IR3 ( m_cp2dr[ 11 ].sw.l ) +#define SXY0 ( m_cp2dr[ 12 ].d ) +#define SX0 ( m_cp2dr[ 12 ].sw.l ) +#define SY0 ( m_cp2dr[ 12 ].sw.h ) +#define SXY1 ( m_cp2dr[ 13 ].d ) +#define SX1 ( m_cp2dr[ 13 ].sw.l ) +#define SY1 ( m_cp2dr[ 13 ].sw.h ) +#define SXY2 ( m_cp2dr[ 14 ].d ) +#define SX2 ( m_cp2dr[ 14 ].sw.l ) +#define SY2 ( m_cp2dr[ 14 ].sw.h ) +#define SXYP ( m_cp2dr[ 15 ].d ) +#define SXP ( m_cp2dr[ 15 ].sw.l ) +#define SYP ( m_cp2dr[ 15 ].sw.h ) +#define SZ0 ( m_cp2dr[ 16 ].w.l ) +#define SZ1 ( m_cp2dr[ 17 ].w.l ) +#define SZ2 ( m_cp2dr[ 18 ].w.l ) +#define SZ3 ( m_cp2dr[ 19 ].w.l ) +#define RGB0 ( m_cp2dr[ 20 ].d ) +#define R0 ( m_cp2dr[ 20 ].b.l ) +#define G0 ( m_cp2dr[ 20 ].b.h ) +#define B0 ( m_cp2dr[ 20 ].b.h2 ) +#define CD0 ( m_cp2dr[ 20 ].b.h3 ) +#define RGB1 ( m_cp2dr[ 21 ].d ) +#define R1 ( m_cp2dr[ 21 ].b.l ) +#define G1 ( m_cp2dr[ 21 ].b.h ) +#define B1 ( m_cp2dr[ 21 ].b.h2 ) +#define CD1 ( m_cp2dr[ 21 ].b.h3 ) +#define RGB2 ( m_cp2dr[ 22 ].d ) +#define R2 ( m_cp2dr[ 22 ].b.l ) +#define G2 ( m_cp2dr[ 22 ].b.h ) +#define B2 ( m_cp2dr[ 22 ].b.h2 ) +#define CD2 ( m_cp2dr[ 22 ].b.h3 ) +#define RES1 ( m_cp2dr[ 23 ].d ) +#define MAC0 ( m_cp2dr[ 24 ].sd ) +#define MAC1 ( m_cp2dr[ 25 ].sd ) +#define MAC2 ( m_cp2dr[ 26 ].sd ) +#define MAC3 ( m_cp2dr[ 27 ].sd ) +#define IRGB ( m_cp2dr[ 28 ].d ) +#define ORGB ( m_cp2dr[ 29 ].d ) +#define LZCS ( m_cp2dr[ 30 ].d ) +#define LZCR ( m_cp2dr[ 31 ].d ) + +#define R11 ( m_cp2cr[ 0 ].sw.l ) +#define R12 ( m_cp2cr[ 0 ].sw.h ) +#define R13 ( m_cp2cr[ 1 ].sw.l ) +#define R21 ( m_cp2cr[ 1 ].sw.h ) +#define R22 ( m_cp2cr[ 2 ].sw.l ) +#define R23 ( m_cp2cr[ 2 ].sw.h ) +#define R31 ( m_cp2cr[ 3 ].sw.l ) +#define R32 ( m_cp2cr[ 3 ].sw.h ) +#define R33 ( m_cp2cr[ 4 ].sw.l ) +#define TRX ( m_cp2cr[ 5 ].sd ) +#define TRY ( m_cp2cr[ 6 ].sd ) +#define TRZ ( m_cp2cr[ 7 ].sd ) +#define L11 ( m_cp2cr[ 8 ].sw.l ) +#define L12 ( m_cp2cr[ 8 ].sw.h ) +#define L13 ( m_cp2cr[ 9 ].sw.l ) +#define L21 ( m_cp2cr[ 9 ].sw.h ) +#define L22 ( m_cp2cr[ 10 ].sw.l ) +#define L23 ( m_cp2cr[ 10 ].sw.h ) +#define L31 ( m_cp2cr[ 11 ].sw.l ) +#define L32 ( m_cp2cr[ 11 ].sw.h ) +#define L33 ( m_cp2cr[ 12 ].sw.l ) +#define RBK ( m_cp2cr[ 13 ].sd ) +#define GBK ( m_cp2cr[ 14 ].sd ) +#define BBK ( m_cp2cr[ 15 ].sd ) +#define LR1 ( m_cp2cr[ 16 ].sw.l ) +#define LR2 ( m_cp2cr[ 16 ].sw.h ) +#define LR3 ( m_cp2cr[ 17 ].sw.l ) +#define LG1 ( m_cp2cr[ 17 ].sw.h ) +#define LG2 ( m_cp2cr[ 18 ].sw.l ) +#define LG3 ( m_cp2cr[ 18 ].sw.h ) +#define LB1 ( m_cp2cr[ 19 ].sw.l ) +#define LB2 ( m_cp2cr[ 19 ].sw.h ) +#define LB3 ( m_cp2cr[ 20 ].sw.l ) +#define RFC ( m_cp2cr[ 21 ].sd ) +#define GFC ( m_cp2cr[ 22 ].sd ) +#define BFC ( m_cp2cr[ 23 ].sd ) +#define OFX ( m_cp2cr[ 24 ].sd ) +#define OFY ( m_cp2cr[ 25 ].sd ) +#define H ( m_cp2cr[ 26 ].sw.l ) +#define DQA ( m_cp2cr[ 27 ].sw.l ) +#define DQB ( m_cp2cr[ 28 ].sd ) +#define ZSF3 ( m_cp2cr[ 29 ].sw.l ) +#define ZSF4 ( m_cp2cr[ 30 ].sw.l ) +#define FLAG ( m_cp2cr[ 31 ].d ) + +#define VX( n ) ( n < 3 ? m_cp2dr[ n << 1 ].sw.l : IR1 ) +#define VY( n ) ( n < 3 ? m_cp2dr[ n << 1 ].sw.h : IR2 ) +#define VZ( n ) ( n < 3 ? m_cp2dr[ ( n << 1 ) + 1 ].sw.l : IR3 ) +#define MX11( n ) ( n < 3 ? m_cp2cr[ ( n << 3 ) ].sw.l : -R << 4 ) +#define MX12( n ) ( n < 3 ? m_cp2cr[ ( n << 3 ) ].sw.h : R << 4 ) +#define MX13( n ) ( n < 3 ? m_cp2cr[ ( n << 3 ) + 1 ].sw.l : IR0 ) +#define MX21( n ) ( n < 3 ? m_cp2cr[ ( n << 3 ) + 1 ].sw.h : R13 ) +#define MX22( n ) ( n < 3 ? m_cp2cr[ ( n << 3 ) + 2 ].sw.l : R13 ) +#define MX23( n ) ( n < 3 ? m_cp2cr[ ( n << 3 ) + 2 ].sw.h : R13 ) +#define MX31( n ) ( n < 3 ? m_cp2cr[ ( n << 3 ) + 3 ].sw.l : R22 ) +#define MX32( n ) ( n < 3 ? m_cp2cr[ ( n << 3 ) + 3 ].sw.h : R22 ) +#define MX33( n ) ( n < 3 ? m_cp2cr[ ( n << 3 ) + 4 ].sw.l : R22 ) +#define CV1( n ) ( n < 3 ? m_cp2cr[ ( n << 3 ) + 5 ].sd : 0 ) +#define CV2( n ) ( n < 3 ? m_cp2cr[ ( n << 3 ) + 6 ].sd : 0 ) +#define CV3( n ) ( n < 3 ? m_cp2cr[ ( n << 3 ) + 7 ].sd : 0 ) + +static UINT32 gte_leadingzerocount( UINT32 lzcs ) +{ + UINT32 lzcr = 0; + + if( ( lzcs & 0x80000000 ) == 0 ) + { + lzcs = ~lzcs; + } + + while( ( lzcs & 0x80000000 ) != 0 ) + { + lzcr++; + lzcs <<= 1; + } + + return lzcr; +} + +INT32 gte::LIM( INT32 value, INT32 max, INT32 min, UINT32 flag ) +{ + if( value > max ) + { + FLAG |= flag; + return max; + } + else if( value < min ) + { + FLAG |= flag; + return min; + } + return value; +} + +UINT32 gte::getcp2dr( UINT32 pc, int reg ) +{ + switch( reg ) + { + case 1: + case 3: + case 5: + case 8: + case 9: + case 10: + case 11: + m_cp2dr[ reg ].d = (INT32)m_cp2dr[ reg ].sw.l; + break; + + case 7: + case 16: + case 17: + case 18: + case 19: + m_cp2dr[ reg ].d = (UINT32)m_cp2dr[ reg ].w.l; + break; + + case 15: + m_cp2dr[ reg ].d = SXY2; + break; + + case 28: + case 29: + m_cp2dr[ reg ].d = LIM( IR1 >> 7, 0x1f, 0, 0 ) | ( LIM( IR2 >> 7, 0x1f, 0, 0 ) << 5 ) | ( LIM( IR3 >> 7, 0x1f, 0, 0 ) << 10 ); + break; + } + + GTELOG( pc, "get CP2DR%u=%08x", reg, m_cp2dr[ reg ].d ); + return m_cp2dr[ reg ].d; +} + +void gte::setcp2dr( UINT32 pc, int reg, UINT32 value ) +{ + GTELOG( pc, "set CP2DR%u=%08x", reg, value ); + + switch( reg ) + { + case 15: + SXY0 = SXY1; + SXY1 = SXY2; + SXY2 = value; + break; + + case 28: + IR1 = ( value & 0x1f ) << 7; + IR2 = ( value & 0x3e0 ) << 2; + IR3 = ( value & 0x7c00 ) >> 3; + break; + + case 30: + LZCR = gte_leadingzerocount( value ); + break; + + case 31: + return; + } + + m_cp2dr[ reg ].d = value; +} + +UINT32 gte::getcp2cr( UINT32 pc, int reg ) +{ + GTELOG( pc, "get CP2CR%u=%08x", reg, m_cp2cr[ reg ].d ); + + return m_cp2cr[ reg ].d; +} + +void gte::setcp2cr( UINT32 pc, int reg, UINT32 value ) +{ + GTELOG( pc, "set CP2CR%u=%08x", reg, value ); + + switch( reg ) + { + case 4: + case 12: + case 20: + case 26: + case 27: + case 29: + case 30: + value = (INT32)(INT16) value; + break; + + case 31: + value = value & 0x7ffff000; + if( ( value & 0x7f87e000 ) != 0 ) + { + value |= 0x80000000; + } + break; + } + + m_cp2cr[ reg ].d = value; +} + +INLINE INT64 gte_shift( INT64 a, int sf ) +{ + if( sf > 0 ) + { + return a >> 12; + } + else if( sf < 0 ) + { + return a << 12; + } + + return a; +} + +INT32 gte::BOUNDS( int44 value, int max_flag, int min_flag ) +{ + if( value.positive_overflow() ) + { + FLAG |= max_flag; + } + + if( value.negative_overflow() ) + { + FLAG |= min_flag; + } + + return gte_shift( value.value(), m_sf ); +} + +INLINE UINT32 gte_divide( UINT16 numerator, UINT16 denominator ) +{ + if( numerator < ( denominator * 2 ) ) + { + static UINT8 table[] = + { + 0xff, 0xfd, 0xfb, 0xf9, 0xf7, 0xf5, 0xf3, 0xf1, 0xef, 0xee, 0xec, 0xea, 0xe8, 0xe6, 0xe4, 0xe3, + 0xe1, 0xdf, 0xdd, 0xdc, 0xda, 0xd8, 0xd6, 0xd5, 0xd3, 0xd1, 0xd0, 0xce, 0xcd, 0xcb, 0xc9, 0xc8, + 0xc6, 0xc5, 0xc3, 0xc1, 0xc0, 0xbe, 0xbd, 0xbb, 0xba, 0xb8, 0xb7, 0xb5, 0xb4, 0xb2, 0xb1, 0xb0, + 0xae, 0xad, 0xab, 0xaa, 0xa9, 0xa7, 0xa6, 0xa4, 0xa3, 0xa2, 0xa0, 0x9f, 0x9e, 0x9c, 0x9b, 0x9a, + 0x99, 0x97, 0x96, 0x95, 0x94, 0x92, 0x91, 0x90, 0x8f, 0x8d, 0x8c, 0x8b, 0x8a, 0x89, 0x87, 0x86, + 0x85, 0x84, 0x83, 0x82, 0x81, 0x7f, 0x7e, 0x7d, 0x7c, 0x7b, 0x7a, 0x79, 0x78, 0x77, 0x75, 0x74, + 0x73, 0x72, 0x71, 0x70, 0x6f, 0x6e, 0x6d, 0x6c, 0x6b, 0x6a, 0x69, 0x68, 0x67, 0x66, 0x65, 0x64, + 0x63, 0x62, 0x61, 0x60, 0x5f, 0x5e, 0x5d, 0x5d, 0x5c, 0x5b, 0x5a, 0x59, 0x58, 0x57, 0x56, 0x55, + 0x54, 0x53, 0x53, 0x52, 0x51, 0x50, 0x4f, 0x4e, 0x4d, 0x4d, 0x4c, 0x4b, 0x4a, 0x49, 0x48, 0x48, + 0x47, 0x46, 0x45, 0x44, 0x43, 0x43, 0x42, 0x41, 0x40, 0x3f, 0x3f, 0x3e, 0x3d, 0x3c, 0x3c, 0x3b, + 0x3a, 0x39, 0x39, 0x38, 0x37, 0x36, 0x36, 0x35, 0x34, 0x33, 0x33, 0x32, 0x31, 0x31, 0x30, 0x2f, + 0x2e, 0x2e, 0x2d, 0x2c, 0x2c, 0x2b, 0x2a, 0x2a, 0x29, 0x28, 0x28, 0x27, 0x26, 0x26, 0x25, 0x24, + 0x24, 0x23, 0x22, 0x22, 0x21, 0x20, 0x20, 0x1f, 0x1e, 0x1e, 0x1d, 0x1d, 0x1c, 0x1b, 0x1b, 0x1a, + 0x19, 0x19, 0x18, 0x18, 0x17, 0x16, 0x16, 0x15, 0x15, 0x14, 0x14, 0x13, 0x12, 0x12, 0x11, 0x11, + 0x10, 0x0f, 0x0f, 0x0e, 0x0e, 0x0d, 0x0d, 0x0c, 0x0c, 0x0b, 0x0a, 0x0a, 0x09, 0x09, 0x08, 0x08, + 0x07, 0x07, 0x06, 0x06, 0x05, 0x05, 0x04, 0x04, 0x03, 0x03, 0x02, 0x02, 0x01, 0x01, 0x00, 0x00, + 0x00 + }; + + int shift = gte_leadingzerocount( denominator ) - 16; + + int r1 = ( denominator << shift ) & 0x7fff; + int r2 = table[ ( ( r1 + 0x40 ) >> 7 ) ] + 0x101; + int r3 = ( ( 0x80 - ( r2 * ( r1 + 0x8000 ) ) ) >> 8 ) & 0x1ffff; + UINT32 reciprocal = ( ( r2 * r3 ) + 0x80 ) >> 8; + + return (UINT32)( ( ( (UINT64) reciprocal * ( numerator << shift ) ) + 0x8000 ) >> 16 ); + } + + return 0xffffffff; +} + +/* Setting bits 12 & 19-22 in FLAG does not set bit 31 */ + +INT32 gte::A1( int44 a ) { m_mac1 = a.value(); return BOUNDS( a, ( 1 << 31 ) | ( 1 << 30 ), ( 1 << 31 ) | ( 1 << 27 ) ); } +INT32 gte::A2( int44 a ) { m_mac2 = a.value(); return BOUNDS( a, ( 1 << 31 ) | ( 1 << 29 ), ( 1 << 31 ) | ( 1 << 26 ) ); } +INT32 gte::A3( int44 a ) { m_mac3 = a.value(); return BOUNDS( a, ( 1 << 31 ) | ( 1 << 28 ), ( 1 << 31 ) | ( 1 << 25 ) ); } +INT32 gte::Lm_B1( INT32 a, int lm ) { return LIM( a, 0x7fff, -0x8000 * !lm, ( 1 << 31 ) | ( 1 << 24 ) ); } +INT32 gte::Lm_B2( INT32 a, int lm ) { return LIM( a, 0x7fff, -0x8000 * !lm, ( 1 << 31 ) | ( 1 << 23 ) ); } +INT32 gte::Lm_B3( INT32 a, int lm ) { return LIM( a, 0x7fff, -0x8000 * !lm, ( 1 << 22 ) ); } + +INT32 gte::Lm_B3_sf( INT64 value, int sf, int lm ) +{ + INT32 value_sf = gte_shift( value, sf ); + INT32 value_12 = gte_shift( value, 1 ); + int max = 0x7fff; + int min = 0; + if( lm == 0 ) + { + min = -0x8000; + } + + if( value_12 < -0x8000 || value_12 > 0x7fff ) + { + FLAG |= ( 1 << 22 ); + } + + if( value_sf > max ) + { + return max; + } + else if( value_sf < min ) + { + return min; + } + + return value_sf; +} + +INT32 gte::Lm_C1( INT32 a ) { return LIM( a, 0x00ff, 0x0000, ( 1 << 21 ) ); } +INT32 gte::Lm_C2( INT32 a ) { return LIM( a, 0x00ff, 0x0000, ( 1 << 20 ) ); } +INT32 gte::Lm_C3( INT32 a ) { return LIM( a, 0x00ff, 0x0000, ( 1 << 19 ) ); } +INT32 gte::Lm_D( INT64 a, int sf ) { return LIM( gte_shift( a, sf ), 0xffff, 0x0000, ( 1 << 31 ) | ( 1 << 18 ) ); } + +UINT32 gte::Lm_E( UINT32 result ) +{ + if( result == 0xffffffff ) + { + FLAG |= ( 1 << 31 ) | ( 1 << 17 ); + return 0x1ffff; + } + + if( result > 0x1ffff ) + { + return 0x1ffff; + } + + return result; +} + +INT64 gte::F( INT64 a ) +{ + m_mac0 = a; + + if( a > 0x7fffffff ) + { + FLAG |= ( 1 << 31 ) | ( 1 << 16 ); + } + + if( a < (INT32) -0x80000000 ) + { + FLAG |= ( 1 << 31 ) | ( 1 << 15 ); + } + + return a; +} + +INT32 gte::Lm_G1( INT64 a ) +{ + if( a > 0x3ff ) + { + FLAG |= ( 1 << 31 ) | ( 1 << 14 ); + return 0x3ff; + } + + if( a < -0x400 ) + { + FLAG |= ( 1 << 31 ) | ( 1 << 14 ); + return -0x400; + } + + return a; +} + +INT32 gte::Lm_G2( INT64 a ) +{ + if( a > 0x3ff ) + { + FLAG |= ( 1 << 31 ) | ( 1 << 13 ); + return 0x3ff; + } + + if( a < -0x400 ) + { + FLAG |= ( 1 << 31 ) | ( 1 << 13 ); + return -0x400; + } + + return a; +} + +INT32 gte::Lm_H( INT64 value, int sf ) +{ + INT64 value_sf = gte_shift( value, sf ); + INT32 value_12 = gte_shift( value, 1 ); + int max = 0x1000; + int min = 0x0000; + + if( value_sf < min || value_sf > max ) + { + FLAG |= ( 1 << 12 ); + } + + if( value_12 > max ) + { + return max; + } + + if( value_12 < min ) + { + return min; + } + + return value_12; +} + +int gte::docop2( UINT32 pc, int gteop ) +{ + int v; + int lm; + int cv; + int mx; + INT32 h_over_sz3 = 0; + + lm = GTE_LM( gteop ); + m_sf = GTE_SF( gteop ); + + FLAG = 0; + + switch( GTE_FUNCT( gteop ) ) + { + case 0x00: // drop through to RTPS + case 0x01: + GTELOG( pc, "%08x RTPS", gteop ); + + MAC1 = A1( int44( (INT64) TRX << 12 ) + ( R11 * VX0 ) + ( R12 * VY0 ) + ( R13 * VZ0 ) ); + MAC2 = A2( int44( (INT64) TRY << 12 ) + ( R21 * VX0 ) + ( R22 * VY0 ) + ( R23 * VZ0 ) ); + MAC3 = A3( int44( (INT64) TRZ << 12 ) + ( R31 * VX0 ) + ( R32 * VY0 ) + ( R33 * VZ0 ) ); + IR1 = Lm_B1( MAC1, lm ); + IR2 = Lm_B2( MAC2, lm ); + IR3 = Lm_B3_sf( m_mac3, m_sf, lm ); + SZ0 = SZ1; + SZ1 = SZ2; + SZ2 = SZ3; + SZ3 = Lm_D( m_mac3, 1 ); + h_over_sz3 = Lm_E( gte_divide( H, SZ3 ) ); + SXY0 = SXY1; + SXY1 = SXY2; + SX2 = Lm_G1( F( (INT64) OFX + ( (INT64) IR1 * h_over_sz3 ) ) >> 16 ); + SY2 = Lm_G2( F( (INT64) OFY + ( (INT64) IR2 * h_over_sz3 ) ) >> 16 ); + MAC0 = F( (INT64) DQB + ( (INT64) DQA * h_over_sz3 ) ); + IR0 = Lm_H( m_mac0, 1 ); + return 1; + + case 0x06: + GTELOG( pc, "%08x NCLIP", gteop ); + + MAC0 = F( (INT64) ( SX0 * SY1 ) + ( SX1 * SY2 ) + ( SX2 * SY0 ) - ( SX0 * SY2 ) - ( SX1 * SY0 ) - ( SX2 * SY1 ) ); + return 1; + + case 0x0c: + GTELOG( pc, "%08x OP", gteop ); + + MAC1 = A1( (INT64) ( R22 * IR3 ) - ( R33 * IR2 ) ); + MAC2 = A2( (INT64) ( R33 * IR1 ) - ( R11 * IR3 ) ); + MAC3 = A3( (INT64) ( R11 * IR2 ) - ( R22 * IR1 ) ); + IR1 = Lm_B1( MAC1, lm ); + IR2 = Lm_B2( MAC2, lm ); + IR3 = Lm_B3( MAC3, lm ); + return 1; + + case 0x10: + GTELOG( pc, "%08x DPCS", gteop ); + + MAC1 = A1( ( R << 16 ) + ( IR0 * Lm_B1( A1( ( (INT64) RFC << 12 ) - ( R << 16 ) ), 0 ) ) ); + MAC2 = A2( ( G << 16 ) + ( IR0 * Lm_B2( A2( ( (INT64) GFC << 12 ) - ( G << 16 ) ), 0 ) ) ); + MAC3 = A3( ( B << 16 ) + ( IR0 * Lm_B3( A3( ( (INT64) BFC << 12 ) - ( B << 16 ) ), 0 ) ) ); + IR1 = Lm_B1( MAC1, lm ); + IR2 = Lm_B2( MAC2, lm ); + IR3 = Lm_B3( MAC3, lm ); + RGB0 = RGB1; + RGB1 = RGB2; + CD2 = CODE; + R2 = Lm_C1( MAC1 >> 4 ); + G2 = Lm_C2( MAC2 >> 4 ); + B2 = Lm_C3( MAC3 >> 4 ); + return 1; + + case 0x11: + GTELOG( pc, "%08x INTPL", gteop ); + + MAC1 = A1( ( IR1 << 12 ) + ( IR0 * Lm_B1( A1( ( (INT64) RFC << 12 ) - ( IR1 << 12 ) ), 0 ) ) ); + MAC2 = A2( ( IR2 << 12 ) + ( IR0 * Lm_B2( A2( ( (INT64) GFC << 12 ) - ( IR2 << 12 ) ), 0 ) ) ); + MAC3 = A3( ( IR3 << 12 ) + ( IR0 * Lm_B3( A3( ( (INT64) BFC << 12 ) - ( IR3 << 12 ) ), 0 ) ) ); + IR1 = Lm_B1( MAC1, lm ); + IR2 = Lm_B2( MAC2, lm ); + IR3 = Lm_B3( MAC3, lm ); + RGB0 = RGB1; + RGB1 = RGB2; + CD2 = CODE; + R2 = Lm_C1( MAC1 >> 4 ); + G2 = Lm_C2( MAC2 >> 4 ); + B2 = Lm_C3( MAC3 >> 4 ); + return 1; + + case 0x12: + GTELOG( pc, "%08x MVMVA", gteop ); + + mx = GTE_MX( gteop ); + v = GTE_V( gteop ); + cv = GTE_CV( gteop ); + + switch( cv ) + { + case 2: + MAC1 = A1( (INT64) ( MX12( mx ) * VY( v ) ) + ( MX13( mx ) * VZ( v ) ) ); + MAC2 = A2( (INT64) ( MX22( mx ) * VY( v ) ) + ( MX23( mx ) * VZ( v ) ) ); + MAC3 = A3( (INT64) ( MX32( mx ) * VY( v ) ) + ( MX33( mx ) * VZ( v ) ) ); + Lm_B1( A1( ( (INT64) CV1( cv ) << 12 ) + ( MX11( mx ) * VX( v ) ) ), 0 ); + Lm_B2( A2( ( (INT64) CV2( cv ) << 12 ) + ( MX21( mx ) * VX( v ) ) ), 0 ); + Lm_B3( A3( ( (INT64) CV3( cv ) << 12 ) + ( MX31( mx ) * VX( v ) ) ), 0 ); + break; + + default: + MAC1 = A1( int44( (INT64) CV1( cv ) << 12 ) + ( MX11( mx ) * VX( v ) ) + ( MX12( mx ) * VY( v ) ) + ( MX13( mx ) * VZ( v ) ) ); + MAC2 = A2( int44( (INT64) CV2( cv ) << 12 ) + ( MX21( mx ) * VX( v ) ) + ( MX22( mx ) * VY( v ) ) + ( MX23( mx ) * VZ( v ) ) ); + MAC3 = A3( int44( (INT64) CV3( cv ) << 12 ) + ( MX31( mx ) * VX( v ) ) + ( MX32( mx ) * VY( v ) ) + ( MX33( mx ) * VZ( v ) ) ); + break; + } + + IR1 = Lm_B1( MAC1, lm ); + IR2 = Lm_B2( MAC2, lm ); + IR3 = Lm_B3( MAC3, lm ); + return 1; + + case 0x13: + GTELOG( pc, "%08x NCDS", gteop ); + + MAC1 = A1( (INT64) ( L11 * VX0 ) + ( L12 * VY0 ) + ( L13 * VZ0 ) ); + MAC2 = A2( (INT64) ( L21 * VX0 ) + ( L22 * VY0 ) + ( L23 * VZ0 ) ); + MAC3 = A3( (INT64) ( L31 * VX0 ) + ( L32 * VY0 ) + ( L33 * VZ0 ) ); + IR1 = Lm_B1( MAC1, lm ); + IR2 = Lm_B2( MAC2, lm ); + IR3 = Lm_B3( MAC3, lm ); + MAC1 = A1( int44( (INT64) RBK << 12 ) + ( LR1 * IR1 ) + ( LR2 * IR2 ) + ( LR3 * IR3 ) ); + MAC2 = A2( int44( (INT64) GBK << 12 ) + ( LG1 * IR1 ) + ( LG2 * IR2 ) + ( LG3 * IR3 ) ); + MAC3 = A3( int44( (INT64) BBK << 12 ) + ( LB1 * IR1 ) + ( LB2 * IR2 ) + ( LB3 * IR3 ) ); + IR1 = Lm_B1( MAC1, lm ); + IR2 = Lm_B2( MAC2, lm ); + IR3 = Lm_B3( MAC3, lm ); + MAC1 = A1( ( ( R << 4 ) * IR1 ) + ( IR0 * Lm_B1( A1( ( (INT64) RFC << 12 ) - ( ( R << 4 ) * IR1 ) ), 0 ) ) ); + MAC2 = A2( ( ( G << 4 ) * IR2 ) + ( IR0 * Lm_B2( A2( ( (INT64) GFC << 12 ) - ( ( G << 4 ) * IR2 ) ), 0 ) ) ); + MAC3 = A3( ( ( B << 4 ) * IR3 ) + ( IR0 * Lm_B3( A3( ( (INT64) BFC << 12 ) - ( ( B << 4 ) * IR3 ) ), 0 ) ) ); + IR1 = Lm_B1( MAC1, lm ); + IR2 = Lm_B2( MAC2, lm ); + IR3 = Lm_B3( MAC3, lm ); + RGB0 = RGB1; + RGB1 = RGB2; + CD2 = CODE; + R2 = Lm_C1( MAC1 >> 4 ); + G2 = Lm_C2( MAC2 >> 4 ); + B2 = Lm_C3( MAC3 >> 4 ); + return 1; + + case 0x14: + GTELOG( pc, "%08x CDP", gteop ); + + MAC1 = A1( int44( (INT64) RBK << 12 ) + ( LR1 * IR1 ) + ( LR2 * IR2 ) + ( LR3 * IR3 ) ); + MAC2 = A2( int44( (INT64) GBK << 12 ) + ( LG1 * IR1 ) + ( LG2 * IR2 ) + ( LG3 * IR3 ) ); + MAC3 = A3( int44( (INT64) BBK << 12 ) + ( LB1 * IR1 ) + ( LB2 * IR2 ) + ( LB3 * IR3 ) ); + IR1 = Lm_B1( MAC1, lm ); + IR2 = Lm_B2( MAC2, lm ); + IR3 = Lm_B3( MAC3, lm ); + MAC1 = A1( ( ( R << 4 ) * IR1 ) + ( IR0 * Lm_B1( A1( ( (INT64) RFC << 12 ) - ( ( R << 4 ) * IR1 ) ), 0 ) ) ); + MAC2 = A2( ( ( G << 4 ) * IR2 ) + ( IR0 * Lm_B2( A2( ( (INT64) GFC << 12 ) - ( ( G << 4 ) * IR2 ) ), 0 ) ) ); + MAC3 = A3( ( ( B << 4 ) * IR3 ) + ( IR0 * Lm_B3( A3( ( (INT64) BFC << 12 ) - ( ( B << 4 ) * IR3 ) ), 0 ) ) ); + IR1 = Lm_B1( MAC1, lm ); + IR2 = Lm_B2( MAC2, lm ); + IR3 = Lm_B3( MAC3, lm ); + RGB0 = RGB1; + RGB1 = RGB2; + CD2 = CODE; + R2 = Lm_C1( MAC1 >> 4 ); + G2 = Lm_C2( MAC2 >> 4 ); + B2 = Lm_C3( MAC3 >> 4 ); + return 1; + + case 0x16: + GTELOG( pc, "%08x NCDT", gteop ); + + for( v = 0; v < 3; v++ ) + { + MAC1 = A1( (INT64) ( L11 * VX( v ) ) + ( L12 * VY( v ) ) + ( L13 * VZ( v ) ) ); + MAC2 = A2( (INT64) ( L21 * VX( v ) ) + ( L22 * VY( v ) ) + ( L23 * VZ( v ) ) ); + MAC3 = A3( (INT64) ( L31 * VX( v ) ) + ( L32 * VY( v ) ) + ( L33 * VZ( v ) ) ); + IR1 = Lm_B1( MAC1, lm ); + IR2 = Lm_B2( MAC2, lm ); + IR3 = Lm_B3( MAC3, lm ); + MAC1 = A1( int44( (INT64) RBK << 12 ) + ( LR1 * IR1 ) + ( LR2 * IR2 ) + ( LR3 * IR3 ) ); + MAC2 = A2( int44( (INT64) GBK << 12 ) + ( LG1 * IR1 ) + ( LG2 * IR2 ) + ( LG3 * IR3 ) ); + MAC3 = A3( int44( (INT64) BBK << 12 ) + ( LB1 * IR1 ) + ( LB2 * IR2 ) + ( LB3 * IR3 ) ); + IR1 = Lm_B1( MAC1, lm ); + IR2 = Lm_B2( MAC2, lm ); + IR3 = Lm_B3( MAC3, lm ); + MAC1 = A1( ( ( R << 4 ) * IR1 ) + ( IR0 * Lm_B1( A1( ( (INT64) RFC << 12 ) - ( ( R << 4 ) * IR1 ) ), 0 ) ) ); + MAC2 = A2( ( ( G << 4 ) * IR2 ) + ( IR0 * Lm_B2( A2( ( (INT64) GFC << 12 ) - ( ( G << 4 ) * IR2 ) ), 0 ) ) ); + MAC3 = A3( ( ( B << 4 ) * IR3 ) + ( IR0 * Lm_B3( A3( ( (INT64) BFC << 12 ) - ( ( B << 4 ) * IR3 ) ), 0 ) ) ); + IR1 = Lm_B1( MAC1, lm ); + IR2 = Lm_B2( MAC2, lm ); + IR3 = Lm_B3( MAC3, lm ); + RGB0 = RGB1; + RGB1 = RGB2; + CD2 = CODE; + R2 = Lm_C1( MAC1 >> 4 ); + G2 = Lm_C2( MAC2 >> 4 ); + B2 = Lm_C3( MAC3 >> 4 ); + } + return 1; + + case 0x1b: + GTELOG( pc, "%08x NCCS", gteop ); + + MAC1 = A1( (INT64) ( L11 * VX0 ) + ( L12 * VY0 ) + ( L13 * VZ0 ) ); + MAC2 = A2( (INT64) ( L21 * VX0 ) + ( L22 * VY0 ) + ( L23 * VZ0 ) ); + MAC3 = A3( (INT64) ( L31 * VX0 ) + ( L32 * VY0 ) + ( L33 * VZ0 ) ); + IR1 = Lm_B1( MAC1, lm ); + IR2 = Lm_B2( MAC2, lm ); + IR3 = Lm_B3( MAC3, lm ); + MAC1 = A1( int44( (INT64) RBK << 12 ) + ( LR1 * IR1 ) + ( LR2 * IR2 ) + ( LR3 * IR3 ) ); + MAC2 = A2( int44( (INT64) GBK << 12 ) + ( LG1 * IR1 ) + ( LG2 * IR2 ) + ( LG3 * IR3 ) ); + MAC3 = A3( int44( (INT64) BBK << 12 ) + ( LB1 * IR1 ) + ( LB2 * IR2 ) + ( LB3 * IR3 ) ); + IR1 = Lm_B1( MAC1, lm ); + IR2 = Lm_B2( MAC2, lm ); + IR3 = Lm_B3( MAC3, lm ); + MAC1 = A1( ( R << 4 ) * IR1 ); + MAC2 = A2( ( G << 4 ) * IR2 ); + MAC3 = A3( ( B << 4 ) * IR3 ); + IR1 = Lm_B1( MAC1, lm ); + IR2 = Lm_B2( MAC2, lm ); + IR3 = Lm_B3( MAC3, lm ); + RGB0 = RGB1; + RGB1 = RGB2; + CD2 = CODE; + R2 = Lm_C1( MAC1 >> 4 ); + G2 = Lm_C2( MAC2 >> 4 ); + B2 = Lm_C3( MAC3 >> 4 ); + return 1; + + case 0x1c: + GTELOG( pc, "%08x CC", gteop ); + + MAC1 = A1( int44( ( (INT64) RBK ) << 12 ) + ( LR1 * IR1 ) + ( LR2 * IR2 ) + ( LR3 * IR3 ) ); + MAC2 = A2( int44( ( (INT64) GBK ) << 12 ) + ( LG1 * IR1 ) + ( LG2 * IR2 ) + ( LG3 * IR3 ) ); + MAC3 = A3( int44( ( (INT64) BBK ) << 12 ) + ( LB1 * IR1 ) + ( LB2 * IR2 ) + ( LB3 * IR3 ) ); + IR1 = Lm_B1( MAC1, lm ); + IR2 = Lm_B2( MAC2, lm ); + IR3 = Lm_B3( MAC3, lm ); + MAC1 = A1( ( R << 4 ) * IR1 ); + MAC2 = A2( ( G << 4 ) * IR2 ); + MAC3 = A3( ( B << 4 ) * IR3 ); + IR1 = Lm_B1( MAC1, lm ); + IR2 = Lm_B2( MAC2, lm ); + IR3 = Lm_B3( MAC3, lm ); + RGB0 = RGB1; + RGB1 = RGB2; + CD2 = CODE; + R2 = Lm_C1( MAC1 >> 4 ); + G2 = Lm_C2( MAC2 >> 4 ); + B2 = Lm_C3( MAC3 >> 4 ); + return 1; + + case 0x1e: + GTELOG( pc, "%08x NCS", gteop ); + + MAC1 = A1( (INT64) ( L11 * VX0 ) + ( L12 * VY0 ) + ( L13 * VZ0 ) ); + MAC2 = A2( (INT64) ( L21 * VX0 ) + ( L22 * VY0 ) + ( L23 * VZ0 ) ); + MAC3 = A3( (INT64) ( L31 * VX0 ) + ( L32 * VY0 ) + ( L33 * VZ0 ) ); + IR1 = Lm_B1( MAC1, lm ); + IR2 = Lm_B2( MAC2, lm ); + IR3 = Lm_B3( MAC3, lm ); + MAC1 = A1( int44( (INT64) RBK << 12 ) + ( LR1 * IR1 ) + ( LR2 * IR2 ) + ( LR3 * IR3 ) ); + MAC2 = A2( int44( (INT64) GBK << 12 ) + ( LG1 * IR1 ) + ( LG2 * IR2 ) + ( LG3 * IR3 ) ); + MAC3 = A3( int44( (INT64) BBK << 12 ) + ( LB1 * IR1 ) + ( LB2 * IR2 ) + ( LB3 * IR3 ) ); + IR1 = Lm_B1( MAC1, lm ); + IR2 = Lm_B2( MAC2, lm ); + IR3 = Lm_B3( MAC3, lm ); + RGB0 = RGB1; + RGB1 = RGB2; + CD2 = CODE; + R2 = Lm_C1( MAC1 >> 4 ); + G2 = Lm_C2( MAC2 >> 4 ); + B2 = Lm_C3( MAC3 >> 4 ); + return 1; + + case 0x20: + GTELOG( pc, "%08x NCT", gteop ); + + for( v = 0; v < 3; v++ ) + { + MAC1 = A1( (INT64) ( L11 * VX( v ) ) + ( L12 * VY( v ) ) + ( L13 * VZ( v ) ) ); + MAC2 = A2( (INT64) ( L21 * VX( v ) ) + ( L22 * VY( v ) ) + ( L23 * VZ( v ) ) ); + MAC3 = A3( (INT64) ( L31 * VX( v ) ) + ( L32 * VY( v ) ) + ( L33 * VZ( v ) ) ); + IR1 = Lm_B1( MAC1, lm ); + IR2 = Lm_B2( MAC2, lm ); + IR3 = Lm_B3( MAC3, lm ); + MAC1 = A1( int44( (INT64) RBK << 12 ) + ( LR1 * IR1 ) + ( LR2 * IR2 ) + ( LR3 * IR3 ) ); + MAC2 = A2( int44( (INT64) GBK << 12 ) + ( LG1 * IR1 ) + ( LG2 * IR2 ) + ( LG3 * IR3 ) ); + MAC3 = A3( int44( (INT64) BBK << 12 ) + ( LB1 * IR1 ) + ( LB2 * IR2 ) + ( LB3 * IR3 ) ); + IR1 = Lm_B1( MAC1, lm ); + IR2 = Lm_B2( MAC2, lm ); + IR3 = Lm_B3( MAC3, lm ); + RGB0 = RGB1; + RGB1 = RGB2; + CD2 = CODE; + R2 = Lm_C1( MAC1 >> 4 ); + G2 = Lm_C2( MAC2 >> 4 ); + B2 = Lm_C3( MAC3 >> 4 ); + } + return 1; + + case 0x28: + GTELOG( pc, "%08x SQR", gteop ); + + MAC1 = A1( IR1 * IR1 ); + MAC2 = A2( IR2 * IR2 ); + MAC3 = A3( IR3 * IR3 ); + IR1 = Lm_B1( MAC1, lm ); + IR2 = Lm_B2( MAC2, lm ); + IR3 = Lm_B3( MAC3, lm ); + return 1; + + case 0x1a: // end of NCDT + case 0x29: + GTELOG( pc, "%08x DPCL", gteop ); + + MAC1 = A1( ( ( R << 4 ) * IR1 ) + ( IR0 * Lm_B1( A1( ( (INT64) RFC << 12 ) - ( ( R << 4 ) * IR1 ) ), 0 ) ) ); + MAC2 = A2( ( ( G << 4 ) * IR2 ) + ( IR0 * Lm_B2( A2( ( (INT64) GFC << 12 ) - ( ( G << 4 ) * IR2 ) ), 0 ) ) ); + MAC3 = A3( ( ( B << 4 ) * IR3 ) + ( IR0 * Lm_B3( A3( ( (INT64) BFC << 12 ) - ( ( B << 4 ) * IR3 ) ), 0 ) ) ); + IR1 = Lm_B1( MAC1, lm ); + IR2 = Lm_B2( MAC2, lm ); + IR3 = Lm_B3( MAC3, lm ); + RGB0 = RGB1; + RGB1 = RGB2; + CD2 = CODE; + R2 = Lm_C1( MAC1 >> 4 ); + G2 = Lm_C2( MAC2 >> 4 ); + B2 = Lm_C3( MAC3 >> 4 ); + return 1; + + case 0x2a: + GTELOG( pc, "%08x DPCT", gteop ); + + for( v = 0; v < 3; v++ ) + { + MAC1 = A1( ( R0 << 16 ) + ( IR0 * Lm_B1( A1( ( (INT64) RFC << 12 ) - ( R0 << 16 ) ), 0 ) ) ); + MAC2 = A2( ( G0 << 16 ) + ( IR0 * Lm_B2( A2( ( (INT64) GFC << 12 ) - ( G0 << 16 ) ), 0 ) ) ); + MAC3 = A3( ( B0 << 16 ) + ( IR0 * Lm_B3( A3( ( (INT64) BFC << 12 ) - ( B0 << 16 ) ), 0 ) ) ); + IR1 = Lm_B1( MAC1, lm ); + IR2 = Lm_B2( MAC2, lm ); + IR3 = Lm_B3( MAC3, lm ); + RGB0 = RGB1; + RGB1 = RGB2; + CD2 = CODE; + R2 = Lm_C1( MAC1 >> 4 ); + G2 = Lm_C2( MAC2 >> 4 ); + B2 = Lm_C3( MAC3 >> 4 ); + } + return 1; + + case 0x2d: + GTELOG( pc, "%08x AVSZ3", gteop ); + + MAC0 = F( (INT64) ( ZSF3 * SZ1 ) + ( ZSF3 * SZ2 ) + ( ZSF3 * SZ3 ) ); + OTZ = Lm_D( m_mac0, 1 ); + return 1; + + case 0x2e: + GTELOG( pc, "%08x AVSZ4", gteop ); + + MAC0 = F( (INT64) ( ZSF4 * SZ0 ) + ( ZSF4 * SZ1 ) + ( ZSF4 * SZ2 ) + ( ZSF4 * SZ3 ) ); + OTZ = Lm_D( m_mac0, 1 ); + return 1; + + case 0x30: + GTELOG( pc, "%08x RTPT", gteop ); + + for( v = 0; v < 3; v++ ) + { + MAC1 = A1( int44( (INT64) TRX << 12 ) + ( R11 * VX( v ) ) + ( R12 * VY( v ) ) + ( R13 * VZ( v ) ) ); + MAC2 = A2( int44( (INT64) TRY << 12 ) + ( R21 * VX( v ) ) + ( R22 * VY( v ) ) + ( R23 * VZ( v ) ) ); + MAC3 = A3( int44( (INT64) TRZ << 12 ) + ( R31 * VX( v ) ) + ( R32 * VY( v ) ) + ( R33 * VZ( v ) ) ); + IR1 = Lm_B1( MAC1, lm ); + IR2 = Lm_B2( MAC2, lm ); + IR3 = Lm_B3_sf( m_mac3, m_sf, lm ); + SZ0 = SZ1; + SZ1 = SZ2; + SZ2 = SZ3; + SZ3 = Lm_D( m_mac3, 1 ); + h_over_sz3 = Lm_E( gte_divide( H, SZ3 ) ); + SXY0 = SXY1; + SXY1 = SXY2; + SX2 = Lm_G1( F( (INT64) OFX + ( (INT64) IR1 * h_over_sz3 ) ) >> 16 ); + SY2 = Lm_G2( F( (INT64) OFY + ( (INT64) IR2 * h_over_sz3 ) ) >> 16 ); + } + + MAC0 = F( (INT64) DQB + ( (INT64) DQA * h_over_sz3 ) ); + IR0 = Lm_H( m_mac0, 1 ); + return 1; + + case 0x3d: + GTELOG( pc, "%08x GPF", gteop ); + + MAC1 = A1( IR0 * IR1 ); + MAC2 = A2( IR0 * IR2 ); + MAC3 = A3( IR0 * IR3 ); + IR1 = Lm_B1( MAC1, lm ); + IR2 = Lm_B2( MAC2, lm ); + IR3 = Lm_B3( MAC3, lm ); + RGB0 = RGB1; + RGB1 = RGB2; + CD2 = CODE; + R2 = Lm_C1( MAC1 >> 4 ); + G2 = Lm_C2( MAC2 >> 4 ); + B2 = Lm_C3( MAC3 >> 4 ); + return 1; + + case 0x3e: + GTELOG( pc, "%08x GPL", gteop ); + + MAC1 = A1( gte_shift( MAC1, -m_sf ) + ( IR0 * IR1 ) ); + MAC2 = A2( gte_shift( MAC2, -m_sf ) + ( IR0 * IR2 ) ); + MAC3 = A3( gte_shift( MAC3, -m_sf ) + ( IR0 * IR3 ) ); + IR1 = Lm_B1( MAC1, lm ); + IR2 = Lm_B2( MAC2, lm ); + IR3 = Lm_B3( MAC3, lm ); + RGB0 = RGB1; + RGB1 = RGB2; + CD2 = CODE; + R2 = Lm_C1( MAC1 >> 4 ); + G2 = Lm_C2( MAC2 >> 4 ); + B2 = Lm_C3( MAC3 >> 4 ); + return 1; + + case 0x3f: + GTELOG( pc, "%08x NCCT", gteop ); + + for( v = 0; v < 3; v++ ) + { + MAC1 = A1( (INT64) ( L11 * VX( v ) ) + ( L12 * VY( v ) ) + ( L13 * VZ( v ) ) ); + MAC2 = A2( (INT64) ( L21 * VX( v ) ) + ( L22 * VY( v ) ) + ( L23 * VZ( v ) ) ); + MAC3 = A3( (INT64) ( L31 * VX( v ) ) + ( L32 * VY( v ) ) + ( L33 * VZ( v ) ) ); + IR1 = Lm_B1( MAC1, lm ); + IR2 = Lm_B2( MAC2, lm ); + IR3 = Lm_B3( MAC3, lm ); + MAC1 = A1( int44( (INT64) RBK << 12 ) + ( LR1 * IR1 ) + ( LR2 * IR2 ) + ( LR3 * IR3 ) ); + MAC2 = A2( int44( (INT64) GBK << 12 ) + ( LG1 * IR1 ) + ( LG2 * IR2 ) + ( LG3 * IR3 ) ); + MAC3 = A3( int44( (INT64) BBK << 12 ) + ( LB1 * IR1 ) + ( LB2 * IR2 ) + ( LB3 * IR3 ) ); + IR1 = Lm_B1( MAC1, lm ); + IR2 = Lm_B2( MAC2, lm ); + IR3 = Lm_B3( MAC3, lm ); + MAC1 = A1( ( R << 4 ) * IR1 ); + MAC2 = A2( ( G << 4 ) * IR2 ); + MAC3 = A3( ( B << 4 ) * IR3 ); + IR1 = Lm_B1( MAC1, lm ); + IR2 = Lm_B2( MAC2, lm ); + IR3 = Lm_B3( MAC3, lm ); + RGB0 = RGB1; + RGB1 = RGB2; + CD2 = CODE; + R2 = Lm_C1( MAC1 >> 4 ); + G2 = Lm_C2( MAC2 >> 4 ); + B2 = Lm_C3( MAC3 >> 4 ); + } + return 1; + } + + popmessage( "unknown GTE op %08x", gteop ); + logerror( "%08x: unknown GTE op %08x\n", pc, gteop ); + + return 0; +} diff --git a/src/devices/cpu/psx/gte.h b/src/devices/cpu/psx/gte.h new file mode 100644 index 00000000000..3fc7075a81d --- /dev/null +++ b/src/devices/cpu/psx/gte.h @@ -0,0 +1,110 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/* + * PlayStation Geometry Transformation Engine emulator + * + * Copyright 2003-2013 smf + * + */ + +#pragma once + +#ifndef __PSXGTE_H__ +#define __PSXGTE_H__ + +#include "emu.h" + +#define GTE_SF( op ) ( ( op >> 19 ) & 1 ) +#define GTE_MX( op ) ( ( op >> 17 ) & 3 ) +#define GTE_V( op ) ( ( op >> 15 ) & 3 ) +#define GTE_CV( op ) ( ( op >> 13 ) & 3 ) +#define GTE_LM( op ) ( ( op >> 10 ) & 1 ) +#define GTE_FUNCT( op ) ( op & 63 ) + +class gte +{ +public: + PAIR m_cp2cr[ 32 ]; + PAIR m_cp2dr[ 32 ]; + + UINT32 getcp2dr( UINT32 pc, int reg ); + void setcp2dr( UINT32 pc, int reg, UINT32 value ); + UINT32 getcp2cr( UINT32 pc, int reg ); + void setcp2cr( UINT32 pc, int reg, UINT32 value ); + int docop2( UINT32 pc, int gteop ); + +protected: + class int44 + { + public: + int44( INT64 value ) : + m_value( value ), + m_positive_overflow( value > S64( 0x7ffffffffff ) ), + m_negative_overflow( value < S64( -0x80000000000 ) ) + { + } + + int44( INT64 value, bool positive_overflow, bool negative_overflow ) : + m_value( value ), + m_positive_overflow( positive_overflow ), + m_negative_overflow( negative_overflow ) + { + } + + int44 operator+( INT64 add ) + { + INT64 value = ( ( m_value + add ) << 20 ) >> 20; + + return int44( value, + m_positive_overflow || ( value < 0 && m_value >= 0 && add >= 0 ), + m_negative_overflow || ( value >= 0 && m_value < 0 && add < 0 ) ); + } + + bool positive_overflow() + { + return m_positive_overflow; + } + + bool negative_overflow() + { + return m_negative_overflow; + } + + INT64 value() + { + return m_value; + } + + private: + INT64 m_value; + bool m_positive_overflow; + bool m_negative_overflow; + }; + + INT32 LIM( INT32 value, INT32 max, INT32 min, UINT32 flag ); + INT32 BOUNDS( int44 a, int max_flag, int min_flag ); + INT32 A1( int44 a ); + INT32 A2( int44 a ); + INT32 A3( int44 a ); + INT32 Lm_B1( INT32 a, int lm ); + INT32 Lm_B2( INT32 a, int lm ); + INT32 Lm_B3( INT32 a, int lm ); + INT32 Lm_B3_sf( INT64 value, int sf, int lm ); + INT32 Lm_C1( INT32 a ); + INT32 Lm_C2( INT32 a ); + INT32 Lm_C3( INT32 a ); + INT32 Lm_D( INT64 a, int sf ); + UINT32 Lm_E( UINT32 result ); + INT64 F( INT64 a ); + INT32 Lm_G1( INT64 a ); + INT32 Lm_G2( INT64 a ); + INT32 Lm_H( INT64 value, int sf ); + + int m_sf; + INT64 m_mac0; + INT64 m_mac1; + INT64 m_mac2; + INT64 m_mac3; +}; + +#endif diff --git a/src/devices/cpu/psx/irq.c b/src/devices/cpu/psx/irq.c new file mode 100644 index 00000000000..51b55cd2639 --- /dev/null +++ b/src/devices/cpu/psx/irq.c @@ -0,0 +1,207 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/* + * PlayStation IRQ emulator + * + * Copyright 2003-2011 smf + * + */ + +#include "psx.h" +#include "irq.h" + +#define VERBOSE_LEVEL ( 0 ) + +#define PSX_IRQ_MASK ( 0x7fd ) + +INLINE void ATTR_PRINTF(3,4) verboselog( running_machine& machine, int n_level, const char *s_fmt, ... ) +{ + if( VERBOSE_LEVEL >= n_level ) + { + va_list v; + char buf[ 32768 ]; + va_start( v, s_fmt ); + vsprintf( buf, s_fmt, v ); + va_end( v ); + logerror( "%s: %s", machine.describe_context(), buf ); + } +} + +const device_type PSX_IRQ = &device_creator; + +psxirq_device::psxirq_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, PSX_IRQ, "Sony PSX IRQ", tag, owner, clock, "psxirq", __FILE__), + m_irq_handler(*this) +{ +} + +void psxirq_device::device_reset() +{ + n_irqdata = 0; + n_irqmask = 0; + + psx_irq_update(); +} + +void psxirq_device::device_post_load() +{ + psx_irq_update(); +} + +void psxirq_device::device_start() +{ + m_irq_handler.resolve_safe(); + + save_item( NAME( n_irqdata ) ); + save_item( NAME( n_irqmask ) ); +} + +void psxirq_device::set( UINT32 bitmask ) +{ + verboselog( machine(), 2, "psx_irq_set %08x\n", bitmask ); + n_irqdata |= bitmask; + psx_irq_update(); +} + +void psxirq_device::psx_irq_update( void ) +{ + if( ( n_irqdata & n_irqmask ) != 0 ) + { + verboselog( machine(), 2, "psx irq assert\n" ); + m_irq_handler( ASSERT_LINE ); + } + else + { + verboselog( machine(), 2, "psx irq clear\n" ); + m_irq_handler( CLEAR_LINE ); + } +} + +WRITE32_MEMBER( psxirq_device::write ) +{ + switch( offset ) + { + case 0x00: + verboselog( machine(), 2, "psx irq data ( %08x, %08x ) %08x -> %08x\n", data, mem_mask, n_irqdata, ( n_irqdata & ~mem_mask ) | ( n_irqdata & n_irqmask & data ) ); + n_irqdata = ( n_irqdata & ~mem_mask ) | ( n_irqdata & n_irqmask & data ); + psx_irq_update(); + break; + case 0x01: + verboselog( machine(), 2, "psx irq mask ( %08x, %08x ) %08x -> %08x\n", data, mem_mask, n_irqmask, ( n_irqmask & ~mem_mask ) | data ); + n_irqmask = ( n_irqmask & ~mem_mask ) | data; + if( ( n_irqmask &~ PSX_IRQ_MASK ) != 0 ) + { + verboselog( machine(), 0, "psx_irq_w( %08x, %08x, %08x ) unknown irq\n", offset, data, mem_mask ); + } + psx_irq_update(); + break; + default: + verboselog( machine(), 0, "psx_irq_w( %08x, %08x, %08x ) unknown register\n", offset, data, mem_mask ); + break; + } +} + +READ32_MEMBER( psxirq_device::read ) +{ + switch( offset ) + { + case 0x00: + verboselog( machine(), 1, "psx_irq_r irq data %08x\n", n_irqdata ); + return n_irqdata; + case 0x01: + verboselog( machine(), 1, "psx_irq_r irq mask %08x\n", n_irqmask ); + return n_irqmask; + default: + verboselog( machine(), 0, "psx_irq_r unknown register %d\n", offset ); + break; + } + return 0; +} + +WRITE_LINE_MEMBER( psxirq_device::intin0 ) +{ + if( state ) + { + set( 1 << 0 ); + } +} + +WRITE_LINE_MEMBER( psxirq_device::intin1 ) +{ + if( state ) + { + set( 1 << 1 ); + } +} + +WRITE_LINE_MEMBER( psxirq_device::intin2 ) +{ + if( state ) + { + set( 1 << 2 ); + } +} + +WRITE_LINE_MEMBER( psxirq_device::intin3 ) +{ + if( state ) + { + set( 1 << 3 ); + } +} + +WRITE_LINE_MEMBER( psxirq_device::intin4 ) +{ + if( state ) + { + set( 1 << 4 ); + } +} + +WRITE_LINE_MEMBER( psxirq_device::intin5 ) +{ + if( state ) + { + set( 1 << 5 ); + } +} + +WRITE_LINE_MEMBER( psxirq_device::intin6 ) +{ + if( state ) + { + set( 1 << 6 ); + } +} + +WRITE_LINE_MEMBER( psxirq_device::intin7 ) +{ + if( state ) + { + set( 1 << 7 ); + } +} + +WRITE_LINE_MEMBER( psxirq_device::intin8 ) +{ + if( state ) + { + set( 1 << 8 ); + } +} + +WRITE_LINE_MEMBER( psxirq_device::intin9 ) +{ + if( state ) + { + set( 1 << 9 ); + } +} + +WRITE_LINE_MEMBER( psxirq_device::intin10 ) +{ + if( state ) + { + set( 1 << 10 ); + } +} diff --git a/src/devices/cpu/psx/irq.h b/src/devices/cpu/psx/irq.h new file mode 100644 index 00000000000..041aa90f26c --- /dev/null +++ b/src/devices/cpu/psx/irq.h @@ -0,0 +1,60 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/* + * PlayStation IRQ emulator + * + * Copyright 2003-2011 smf + * + */ + +#pragma once + +#ifndef __PSXIRQ_H__ +#define __PSXIRQ_H__ + +#include "emu.h" + +extern const device_type PSX_IRQ; + +#define MCFG_PSX_IRQ_HANDLER(_devcb) \ + devcb = &psxirq_device::set_irq_handler(*device, DEVCB_##_devcb); + +class psxirq_device : public device_t +{ +public: + psxirq_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // static configuration helpers + template static devcb_base &set_irq_handler(device_t &device, _Object object) { return downcast(device).m_irq_handler.set_callback(object); } + + DECLARE_READ32_MEMBER( read ); + DECLARE_WRITE32_MEMBER( write ); + + DECLARE_WRITE_LINE_MEMBER( intin0 ); + DECLARE_WRITE_LINE_MEMBER( intin1 ); + DECLARE_WRITE_LINE_MEMBER( intin2 ); + DECLARE_WRITE_LINE_MEMBER( intin3 ); + DECLARE_WRITE_LINE_MEMBER( intin4 ); + DECLARE_WRITE_LINE_MEMBER( intin5 ); + DECLARE_WRITE_LINE_MEMBER( intin6 ); + DECLARE_WRITE_LINE_MEMBER( intin7 ); + DECLARE_WRITE_LINE_MEMBER( intin8 ); + DECLARE_WRITE_LINE_MEMBER( intin9 ); + DECLARE_WRITE_LINE_MEMBER( intin10 ); + +protected: + virtual void device_start(); + virtual void device_reset(); + virtual void device_post_load(); + +private: + void psx_irq_update( void ); + void set( UINT32 bitmask ); + + UINT32 n_irqdata; + UINT32 n_irqmask; + + devcb_write_line m_irq_handler; +}; + +#endif diff --git a/src/devices/cpu/psx/mdec.c b/src/devices/cpu/psx/mdec.c new file mode 100644 index 00000000000..57c6b3393b4 --- /dev/null +++ b/src/devices/cpu/psx/mdec.c @@ -0,0 +1,572 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/* + * PlayStation Motion Decoder emulator + * + * Copyright 2003-2011 smf + * + * Thanks to Oliver Galibert for help figuring out IDCT + * + */ + +#include "emu.h" +#include "dma.h" +#include "mdec.h" + +#define VERBOSE_LEVEL ( 0 ) + +INLINE void ATTR_PRINTF(3,4) verboselog( running_machine& machine, int n_level, const char *s_fmt, ... ) +{ + if( VERBOSE_LEVEL >= n_level ) + { + va_list v; + char buf[ 32768 ]; + va_start( v, s_fmt ); + vsprintf( buf, s_fmt, v ); + va_end( v ); + logerror( "%s: %s", machine.describe_context(), buf ); + } +} + +const device_type PSX_MDEC = &device_creator; + +psxmdec_device::psxmdec_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, PSX_MDEC, "Sony PSX MDEC", tag, owner, clock, "psxmdec", __FILE__) +{ +} + +void psxmdec_device::device_reset() +{ + n_0_command = 0; + n_0_address = 0; + n_0_size = 0; + n_1_command = 0; + n_1_status = 0; + n_offset = 0; + n_decoded = 0; +} + +void psxmdec_device::device_post_load() +{ + mdec_cos_precalc(); +} + +void psxmdec_device::device_start() +{ + for( int n = 0; n < 256; n++ ) + { + p_n_clamp8[ n ] = 0; + p_n_clamp8[ n + 256 ] = n; + p_n_clamp8[ n + 512 ] = 255; + + p_n_r5[ n ] = 0; + p_n_r5[ n + 256 ] = ( n >> 3 ); + p_n_r5[ n + 512 ] = ( 255 >> 3 ); + + p_n_g5[ n ] = 0; + p_n_g5[ n + 256 ] = ( n >> 3 ) << 5; + p_n_g5[ n + 512 ] = ( 255 >> 3 ) << 5; + + p_n_b5[ n ] = 0; + p_n_b5[ n + 256 ] = ( n >> 3 ) << 10; + p_n_b5[ n + 512 ] = ( 255 >> 3 ) << 10; + } + + save_item( NAME( n_0_command ) ); + save_item( NAME( n_0_address ) ); + save_item( NAME( n_0_size ) ); + save_item( NAME( n_1_command ) ); + save_item( NAME( n_1_status ) ); + save_item( NAME( p_n_quantize_y ) ); + save_item( NAME( p_n_quantize_uv ) ); + save_item( NAME( p_n_cos ) ); +} + +#ifdef UNUSED_FUNCTION +INLINE void psxwriteword( UINT32 *p_n_psxram, UINT32 n_address, UINT16 n_data ) +{ + *( (UINT16 *)( (UINT8 *)p_n_psxram + WORD_XOR_LE( n_address ) ) ) = n_data; +} +#endif + +INLINE UINT16 psxreadword( UINT32 *p_n_psxram, UINT32 n_address ) +{ + return *( (UINT16 *)( (UINT8 *)p_n_psxram + WORD_XOR_LE( n_address ) ) ); +} + +static const UINT32 m_p_n_mdec_zigzag[ DCTSIZE2 ] = +{ + 0, 1, 8, 16, 9, 2, 3, 10, + 17, 24, 32, 25, 18, 11, 4, 5, + 12, 19, 26, 33, 40, 48, 41, 34, + 27, 20, 13, 6, 7, 14, 21, 28, + 35, 42, 49, 56, 57, 50, 43, 36, + 29, 22, 15, 23, 30, 37, 44, 51, + 58, 59, 52, 45, 38, 31, 39, 46, + 53, 60, 61, 54, 47, 55, 62, 63 +}; + +void psxmdec_device::mdec_cos_precalc() +{ + UINT32 n_x; + UINT32 n_y; + UINT32 n_u; + UINT32 n_v; + INT32 *p_n_precalc = p_n_cos_precalc; + + for( n_y = 0; n_y < 8; n_y++ ) + { + for( n_x = 0; n_x < 8; n_x++ ) + { + for( n_v = 0; n_v < 8; n_v++ ) + { + for( n_u = 0; n_u < 8; n_u++ ) + { + *( p_n_precalc++ ) = + ( ( p_n_cos[ ( n_u * 8 ) + n_x ] * + p_n_cos[ ( n_v * 8 ) + n_y ] ) >> ( 30 - MDEC_COS_PRECALC_BITS ) ); + } + } + } + } +} + +void psxmdec_device::mdec_idct( INT32 *p_n_src, INT32 *p_n_dst ) +{ + INT32 *p_n_precalc = p_n_cos_precalc; + + for( UINT32 n_yx = 0; n_yx < DCTSIZE2; n_yx++ ) + { + INT32 p_n_z[ 8 ]; + INT32 *p_n_data = p_n_src; + + memset( p_n_z, 0, sizeof( p_n_z ) ); + + for( UINT32 n_vu = 0; n_vu < DCTSIZE2 / 8; n_vu++ ) + { + p_n_z[ 0 ] += p_n_data[ 0 ] * p_n_precalc[ 0 ]; + p_n_z[ 1 ] += p_n_data[ 1 ] * p_n_precalc[ 1 ]; + p_n_z[ 2 ] += p_n_data[ 2 ] * p_n_precalc[ 2 ]; + p_n_z[ 3 ] += p_n_data[ 3 ] * p_n_precalc[ 3 ]; + p_n_z[ 4 ] += p_n_data[ 4 ] * p_n_precalc[ 4 ]; + p_n_z[ 5 ] += p_n_data[ 5 ] * p_n_precalc[ 5 ]; + p_n_z[ 6 ] += p_n_data[ 6 ] * p_n_precalc[ 6 ]; + p_n_z[ 7 ] += p_n_data[ 7 ] * p_n_precalc[ 7 ]; + p_n_data += 8; + p_n_precalc += 8; + } + + *( p_n_dst++ ) = ( p_n_z[ 0 ] + p_n_z[ 1 ] + p_n_z[ 2 ] + p_n_z[ 3 ] + + p_n_z[ 4 ] + p_n_z[ 5 ] + p_n_z[ 6 ] + p_n_z[ 7 ] ) >> ( MDEC_COS_PRECALC_BITS + 2 ); + } +} + +INLINE UINT16 mdec_unpack_run( UINT16 n_packed ) +{ + return n_packed >> 10; +} + +INLINE INT32 mdec_unpack_val( UINT16 n_packed ) +{ + return ( ( (INT32)n_packed ) << 22 ) >> 22; +} + +UINT32 psxmdec_device::mdec_unpack( UINT32 *p_n_psxram, UINT32 n_address ) +{ + UINT8 n_z; + INT32 n_qscale; + UINT16 n_packed; + INT32 *p_n_block; + INT32 p_n_unpacked[ 64 ]; + INT32 *p_n_q; + + p_n_q = p_n_quantize_uv; + p_n_block = m_p_n_unpacked; + + for( UINT32 n_block = 0; n_block < 6; n_block++ ) + { + memset( p_n_unpacked, 0, sizeof( p_n_unpacked ) ); + + if( n_block == 2 ) + { + p_n_q = p_n_quantize_y; + } + n_packed = psxreadword( p_n_psxram, n_address ); + n_address += 2; + if( n_packed == 0xfe00 ) + { + break; + } + + n_qscale = mdec_unpack_run( n_packed ); + p_n_unpacked[ 0 ] = mdec_unpack_val( n_packed ) * p_n_q[ 0 ]; + + n_z = 0; + for( ;; ) + { + n_packed = psxreadword( p_n_psxram, n_address ); + n_address += 2; + + if( n_packed == 0xfe00 ) + { + break; + } + n_z += mdec_unpack_run( n_packed ) + 1; + if( n_z > 63 ) + { + break; + } + p_n_unpacked[ m_p_n_mdec_zigzag[ n_z ] ] = ( mdec_unpack_val( n_packed ) * p_n_q[ n_z ] * n_qscale ) / 8; + } + mdec_idct( p_n_unpacked, p_n_block ); + p_n_block += DCTSIZE2; + } + return n_address; +} + +INLINE INT32 mdec_cr_to_r( INT32 n_cr ) +{ + return ( 1435 * n_cr ) >> 10; +} + +INLINE INT32 mdec_cr_to_g( INT32 n_cr ) +{ + return ( -731 * n_cr ) >> 10; +} + +INLINE INT32 mdec_cb_to_g( INT32 n_cb ) +{ + return ( -351 * n_cb ) >> 10; +} + +INLINE INT32 mdec_cb_to_b( INT32 n_cb ) +{ + return ( 1814 * n_cb ) >> 10; +} + +UINT16 psxmdec_device::mdec_clamp_r5( INT32 n_r ) const +{ + return p_n_r5[ n_r + 128 + 256 ]; +} + +UINT16 psxmdec_device::mdec_clamp_g5( INT32 n_g ) const +{ + return p_n_g5[ n_g + 128 + 256 ]; +} + +UINT16 psxmdec_device::mdec_clamp_b5( INT32 n_b ) const +{ + return p_n_b5[ n_b + 128 + 256 ]; +} + +void psxmdec_device::mdec_makergb15( UINT32 n_address, INT32 n_r, INT32 n_g, INT32 n_b, INT32 *p_n_y, UINT16 n_stp ) +{ + p_n_output[ WORD_XOR_LE( n_address + 0 ) / 2 ] = n_stp | + mdec_clamp_r5( p_n_y[ 0 ] + n_r ) | + mdec_clamp_g5( p_n_y[ 0 ] + n_g ) | + mdec_clamp_b5( p_n_y[ 0 ] + n_b ); + + p_n_output[ WORD_XOR_LE( n_address + 2 ) / 2 ] = n_stp | + mdec_clamp_r5( p_n_y[ 1 ] + n_r ) | + mdec_clamp_g5( p_n_y[ 1 ] + n_g ) | + mdec_clamp_b5( p_n_y[ 1 ] + n_b ); +} + +void psxmdec_device::mdec_yuv2_to_rgb15( void ) +{ + INT32 n_r; + INT32 n_g; + INT32 n_b; + INT32 n_cb; + INT32 n_cr; + INT32 *p_n_cb; + INT32 *p_n_cr; + INT32 *p_n_y; + UINT32 n_x; + UINT32 n_y; + UINT32 n_z; + UINT16 n_stp; + int n_address = 0; + + if( ( n_0_command & ( 1L << 25 ) ) != 0 ) + { + n_stp = 0x8000; + } + else + { + n_stp = 0x0000; + } + + p_n_cr = &m_p_n_unpacked[ 0 ]; + p_n_cb = &m_p_n_unpacked[ DCTSIZE2 ]; + p_n_y = &m_p_n_unpacked[ DCTSIZE2 * 2 ]; + + for( n_z = 0; n_z < 2; n_z++ ) + { + for( n_y = 0; n_y < 4; n_y++ ) + { + for( n_x = 0; n_x < 4; n_x++ ) + { + n_cr = *( p_n_cr ); + n_cb = *( p_n_cb ); + n_r = mdec_cr_to_r( n_cr ); + n_g = mdec_cr_to_g( n_cr ) + mdec_cb_to_g( n_cb ); + n_b = mdec_cb_to_b( n_cb ); + + mdec_makergb15( ( n_address + 0 ), n_r, n_g, n_b, p_n_y, n_stp ); + mdec_makergb15( ( n_address + 32 ), n_r, n_g, n_b, p_n_y + 8, n_stp ); + + n_cr = *( p_n_cr + 4 ); + n_cb = *( p_n_cb + 4 ); + n_r = mdec_cr_to_r( n_cr ); + n_g = mdec_cr_to_g( n_cr ) + mdec_cb_to_g( n_cb ); + n_b = mdec_cb_to_b( n_cb ); + + mdec_makergb15( ( n_address + 16 ), n_r, n_g, n_b, p_n_y + DCTSIZE2, n_stp ); + mdec_makergb15( ( n_address + 48 ), n_r, n_g, n_b, p_n_y + DCTSIZE2 + 8, n_stp ); + + p_n_cr++; + p_n_cb++; + p_n_y += 2; + n_address += 4; + } + p_n_cr += 4; + p_n_cb += 4; + p_n_y += 8; + n_address += 48; + } + p_n_y += DCTSIZE2; + } + n_decoded = ( 16 * 16 ) / 2; +} + +UINT16 psxmdec_device::mdec_clamp8( INT32 n_r ) const +{ + return p_n_clamp8[ n_r + 128 + 256 ]; +} + +void psxmdec_device::mdec_makergb24( UINT32 n_address, INT32 n_r, INT32 n_g, INT32 n_b, INT32 *p_n_y, UINT32 n_stp ) +{ + p_n_output[ WORD_XOR_LE( n_address + 0 ) / 2 ] = ( mdec_clamp8( p_n_y[ 0 ] + n_g ) << 8 ) | mdec_clamp8( p_n_y[ 0 ] + n_r ); + p_n_output[ WORD_XOR_LE( n_address + 2 ) / 2 ] = ( mdec_clamp8( p_n_y[ 1 ] + n_r ) << 8 ) | mdec_clamp8( p_n_y[ 0 ] + n_b ); + p_n_output[ WORD_XOR_LE( n_address + 4 ) / 2 ] = ( mdec_clamp8( p_n_y[ 1 ] + n_b ) << 8 ) | mdec_clamp8( p_n_y[ 1 ] + n_g ); +} + +void psxmdec_device::mdec_yuv2_to_rgb24( void ) +{ + INT32 n_r; + INT32 n_g; + INT32 n_b; + INT32 n_cb; + INT32 n_cr; + INT32 *p_n_cb; + INT32 *p_n_cr; + INT32 *p_n_y; + UINT32 n_x; + UINT32 n_y; + UINT32 n_z; + UINT32 n_stp; + int n_address = 0; + + if( ( n_0_command & ( 1L << 25 ) ) != 0 ) + { + n_stp = 0x80008000; + } + else + { + n_stp = 0x00000000; + } + + p_n_cr = &m_p_n_unpacked[ 0 ]; + p_n_cb = &m_p_n_unpacked[ DCTSIZE2 ]; + p_n_y = &m_p_n_unpacked[ DCTSIZE2 * 2 ]; + + for( n_z = 0; n_z < 2; n_z++ ) + { + for( n_y = 0; n_y < 4; n_y++ ) + { + for( n_x = 0; n_x < 4; n_x++ ) + { + n_cr = *( p_n_cr ); + n_cb = *( p_n_cb ); + n_r = mdec_cr_to_r( n_cr ); + n_g = mdec_cr_to_g( n_cr ) + mdec_cb_to_g( n_cb ); + n_b = mdec_cb_to_b( n_cb ); + + mdec_makergb24( ( n_address + 0 ), n_r, n_g, n_b, p_n_y, n_stp ); + mdec_makergb24( ( n_address + 48 ), n_r, n_g, n_b, p_n_y + 8, n_stp ); + + n_cr = *( p_n_cr + 4 ); + n_cb = *( p_n_cb + 4 ); + n_r = mdec_cr_to_r( n_cr ); + n_g = mdec_cr_to_g( n_cr ) + mdec_cb_to_g( n_cb ); + n_b = mdec_cb_to_b( n_cb ); + + mdec_makergb24( ( n_address + 24 ), n_r, n_g, n_b, p_n_y + DCTSIZE2, n_stp ); + mdec_makergb24( ( n_address + 72 ), n_r, n_g, n_b, p_n_y + DCTSIZE2 + 8, n_stp ); + + p_n_cr++; + p_n_cb++; + p_n_y += 2; + n_address += 6; + } + p_n_cr += 4; + p_n_cb += 4; + p_n_y += 8; + n_address += 72; + } + p_n_y += DCTSIZE2; + } + n_decoded = ( 24 * 16 ) / 2; +} + +void psxmdec_device::dma_write( UINT32 *p_n_psxram, UINT32 n_address, INT32 n_size ) +{ + int n_index; + + verboselog( machine(), 2, "mdec0_write( %08x, %08x )\n", n_address, n_size ); + + switch( n_0_command >> 28 ) + { + case 0x3: + verboselog( machine(), 1, "mdec decode %08x %08x %08x\n", n_0_command, n_address, n_size ); + n_0_address = n_address; + n_0_size = n_size * 4; + n_1_status |= ( 1L << 29 ); + break; + case 0x4: + verboselog( machine(), 1, "mdec quantize table %08x %08x %08x\n", n_0_command, n_address, n_size ); + n_index = 0; + while( n_size > 0 ) + { + if( n_index < DCTSIZE2 ) + { + p_n_quantize_y[ n_index + 0 ] = ( p_n_psxram[ n_address / 4 ] >> 0 ) & 0xff; + p_n_quantize_y[ n_index + 1 ] = ( p_n_psxram[ n_address / 4 ] >> 8 ) & 0xff; + p_n_quantize_y[ n_index + 2 ] = ( p_n_psxram[ n_address / 4 ] >> 16 ) & 0xff; + p_n_quantize_y[ n_index + 3 ] = ( p_n_psxram[ n_address / 4 ] >> 24 ) & 0xff; + } + else if( n_index < DCTSIZE2 * 2 ) + { + p_n_quantize_uv[ n_index + 0 - DCTSIZE2 ] = ( p_n_psxram[ n_address / 4 ] >> 0 ) & 0xff; + p_n_quantize_uv[ n_index + 1 - DCTSIZE2 ] = ( p_n_psxram[ n_address / 4 ] >> 8 ) & 0xff; + p_n_quantize_uv[ n_index + 2 - DCTSIZE2 ] = ( p_n_psxram[ n_address / 4 ] >> 16 ) & 0xff; + p_n_quantize_uv[ n_index + 3 - DCTSIZE2 ] = ( p_n_psxram[ n_address / 4 ] >> 24 ) & 0xff; + } + n_index += 4; + n_address += 4; + n_size--; + } + break; + case 0x6: + verboselog( machine(), 1, "mdec cosine table %08x %08x %08x\n", n_0_command, n_address, n_size ); + n_index = 0; + while( n_size > 0 ) + { + p_n_cos[ n_index + 0 ] = (INT16)( ( p_n_psxram[ n_address / 4 ] >> 0 ) & 0xffff ); + p_n_cos[ n_index + 1 ] = (INT16)( ( p_n_psxram[ n_address / 4 ] >> 16 ) & 0xffff ); + n_index += 2; + n_address += 4; + n_size--; + } + mdec_cos_precalc(); + break; + default: + verboselog( machine(), 0, "mdec unknown command %08x %08x %08x\n", n_0_command, n_address, n_size ); + break; + } +} + +void psxmdec_device::dma_read( UINT32 *p_n_psxram, UINT32 n_address, INT32 n_size ) +{ + UINT32 n_this; + UINT32 n_nextaddress; + + verboselog( machine(), 2, "mdec1_read( %08x, %08x )\n", n_address, n_size ); + if( ( n_0_command & ( 1L << 29 ) ) != 0 && n_0_size != 0 ) + { + while( n_size > 0 ) + { + if( n_decoded == 0 ) + { + if( (int)n_0_size <= 0 ) + { + osd_printf_debug( "ran out of data %08x\n", n_size ); + n_0_size = 0; + break; + } + + n_nextaddress = mdec_unpack( p_n_psxram, n_0_address ); + n_0_size -= n_nextaddress - n_0_address; + n_0_address = n_nextaddress; + + if( ( n_0_command & ( 1L << 27 ) ) != 0 ) + { + mdec_yuv2_to_rgb15(); + } + else + { + mdec_yuv2_to_rgb24(); + } + n_offset = 0; + while((psxreadword( p_n_psxram, n_0_address ) == 0xfe00) && n_0_size) + { + n_0_address += 2; // eat up 0xfe00 + n_0_size -= 2; + } + } + + n_this = n_decoded; + if( n_this > n_size ) + { + n_this = n_size; + } + n_decoded -= n_this; + + memcpy( (UINT8 *)p_n_psxram + n_address, (UINT8 *)p_n_output + n_offset, n_this * 4 ); + n_offset += n_this * 4; + n_address += n_this * 4; + n_size -= n_this; + } + + if( (int)n_0_size < 0 ) + { + osd_printf_debug( "ran out of data %d\n", n_0_size ); + } + } + else + { + osd_printf_debug( "mdec1_read no conversion :%08x:%08x:\n", n_0_command, n_0_size ); + } + if((int)n_0_size <= 0) + n_1_status &= ~( 1L << 29 ); +} + +WRITE32_MEMBER( psxmdec_device::write ) +{ + switch( offset ) + { + case 0: + verboselog( machine(), 2, "mdec 0 command %08x\n", data ); + n_0_command = data; + break; + case 1: + verboselog( machine(), 2, "mdec 1 command %08x\n", data ); + n_1_command = data; + break; + } +} + +READ32_MEMBER( psxmdec_device::read ) +{ + switch( offset ) + { + case 0: + verboselog( machine(), 2, "mdec 0 status %08x\n", 0 ); + return 0; + case 1: + verboselog( machine(), 2, "mdec 1 status %08x\n", n_1_status ); + return n_1_status; + } + return 0; +} diff --git a/src/devices/cpu/psx/mdec.h b/src/devices/cpu/psx/mdec.h new file mode 100644 index 00000000000..097f43c0d5d --- /dev/null +++ b/src/devices/cpu/psx/mdec.h @@ -0,0 +1,76 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/* + * PlayStation DMA emulator + * + * Copyright 2003-2011 smf + * + */ + +#pragma once + +#ifndef __PSXMDEC_H__ +#define __PSXMDEC_H__ + +#include "emu.h" + +extern const device_type PSX_MDEC; + +#define DCTSIZE ( 8 ) +#define DCTSIZE2 ( DCTSIZE * DCTSIZE ) + +#define MDEC_COS_PRECALC_BITS ( 21 ) + +class psxmdec_device : public device_t +{ +public: + psxmdec_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + DECLARE_WRITE32_MEMBER( write ); + DECLARE_READ32_MEMBER( read ); + + void dma_write( UINT32 *ram, UINT32 n_address, INT32 n_size ); + void dma_read( UINT32 *ram, UINT32 n_address, INT32 n_size ); + +protected: + virtual void device_start(); + virtual void device_reset(); + virtual void device_post_load(); + +private: + void mdec_cos_precalc(); + void mdec_idct( INT32 *p_n_src, INT32 *p_n_dst ); + UINT32 mdec_unpack( UINT32 *ram, UINT32 n_address ); + UINT16 mdec_clamp_r5( INT32 n_r ) const; + UINT16 mdec_clamp_g5( INT32 n_g ) const; + UINT16 mdec_clamp_b5( INT32 n_b ) const; + UINT16 mdec_clamp8( INT32 n_r ) const; + void mdec_yuv2_to_rgb15( void ); + void mdec_yuv2_to_rgb24( void ); + void mdec_makergb15( UINT32 n_address, INT32 n_r, INT32 n_g, INT32 n_b, INT32 *p_n_y, UINT16 n_stp ); + void mdec_makergb24( UINT32 n_address, INT32 n_r, INT32 n_g, INT32 n_b, INT32 *p_n_y, UINT32 n_stp ); + + UINT32 n_decoded; + UINT32 n_offset; + UINT16 p_n_output[ 24 * 16 ]; + + INT32 p_n_quantize_y[ DCTSIZE2 ]; + INT32 p_n_quantize_uv[ DCTSIZE2 ]; + INT32 p_n_cos[ DCTSIZE2 ]; + INT32 p_n_cos_precalc[ DCTSIZE2 * DCTSIZE2 ]; + + UINT32 n_0_command; + UINT32 n_0_address; + UINT32 n_0_size; + UINT32 n_1_command; + UINT32 n_1_status; + + UINT16 p_n_clamp8[ 256 * 3 ]; + UINT16 p_n_r5[ 256 * 3 ]; + UINT16 p_n_g5[ 256 * 3 ]; + UINT16 p_n_b5[ 256 * 3 ]; + + INT32 m_p_n_unpacked[ DCTSIZE2 * 6 * 2 ]; +}; + +#endif diff --git a/src/devices/cpu/psx/psx.c b/src/devices/cpu/psx/psx.c new file mode 100644 index 00000000000..a262c9bd42c --- /dev/null +++ b/src/devices/cpu/psx/psx.c @@ -0,0 +1,3417 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/* + * PlayStation CPU emulator + * + * Copyright 2003-2013 smf + * + * Known chip id's + * CXD8530AQ + * CXD8530BQ + * CXD8530CQ + * CXD8661R + * CXD8606BQ + * CXD8606CQ + * + * The PlayStation CPU is based on the LSI LR33300. + * + * Differences from the LR33300: + * + * There is only 1k of data cache ram ( the LR33300 has 2k ) + * + * There is no data cache tag ram, so the data cache ram can only be used as a fast area + * of ram ( which is a standard LR33300 feature ). + * + * If COP0 is disabled in user mode you get a coprocessor unusable exception, while + * the LR33300 is documented to generate a reserved instruction exception. + * + * Known limitations of the emulation: + * + * Only read & write break points are emulated, trace and program counter breakpoints are not. + * + * Load/Store timings are based on load scheduling turned off & no write cache. This affects when + * bus error exceptions occur and also when the read & write handlers are called. A scheduled + * load will complete if a load breakpoint fires, but an unscheduled load will not. + * + * Reading from the data and instruction cache at the same time causes a bus conflict that + * corrupts the data in a reliable but strange way, which is not emulated. + * + * Values written to COP1 & COP3 can be read back by the next instruction, which is not emulated. + * Because of loadscheduling the value loaded with LWC1/LWC3 can be read by more than the next + * instruction. + * + * SWC0 writes stale data from a previous operation, this is only partially emulated as the timing + * is complicated. Left over instruction fetches are currently emulated as they are the most + * 'interesting' and have no impact on the rest of the emulation. + * + * MTC0 timing is not emulated, switching to user mode while in kernel space continues + * execution for another two instructions before taking an exception. Using RFE to do the same + * thing causes the exception straight away, unless the RFE is the first instruction that follows + * an MTC0 instruction. + * + * The PRId register should be 1 on some revisions of the CPU ( there might be other values too ). + * + * Moving to the HI/LO register after a multiply or divide, but before reading the results will + * always abort the operation as if you did it immediately. In reality it should complete on it's + * own, and aborting before it completes would result in returning the working results. + * + * Running code in cached address space does not use or update the instruction cache. + * + * Wait states are not emulated. + * + * Bus errors caused by instruction fetches are not supported. + * + */ + +#include "emu.h" +#include "debugger.h" +#include "psx.h" +#include "mdec.h" +#include "rcnt.h" +#include "sound/spu.h" + +#define LOG_BIOSCALL ( 0 ) + +#define EXC_INT ( 0 ) +#define EXC_ADEL ( 4 ) +#define EXC_ADES ( 5 ) +#define EXC_IBE ( 6 ) +#define EXC_DBE ( 7 ) +#define EXC_SYS ( 8 ) +#define EXC_BP ( 9 ) +#define EXC_RI ( 10 ) +#define EXC_CPU ( 11 ) +#define EXC_OVF ( 12 ) + +#define CP0_INDEX ( 0 ) +#define CP0_RANDOM ( 1 ) +#define CP0_ENTRYLO ( 2 ) +#define CP0_CONTEXT ( 4 ) +#define CP0_ENTRYHI ( 10 ) + +#define CP0_BPC ( 3 ) +#define CP0_BDA ( 5 ) +#define CP0_TAR ( 6 ) +#define CP0_DCIC ( 7 ) +#define CP0_BADA ( 8 ) +#define CP0_BDAM ( 9 ) +#define CP0_BPCM ( 11 ) +#define CP0_SR ( 12 ) +#define CP0_CAUSE ( 13 ) +#define CP0_EPC ( 14 ) +#define CP0_PRID ( 15 ) + +#define DCIC_STATUS ( 0x3f ) +#define DCIC_DB ( 1L << 0 ) +#define DCIC_DA ( 1L << 2 ) +#define DCIC_R ( 1L << 3 ) +#define DCIC_W ( 1L << 4 ) +#define DCIC_DE ( 1L << 23 ) +#define DCIC_DAE ( 1L << 25 ) +#define DCIC_DR ( 1L << 26 ) +#define DCIC_DW ( 1L << 27 ) +#define DCIC_KD ( 1L << 29 ) +#define DCIC_UD ( 1L << 30 ) +#define DCIC_TR ( 1L << 31 ) + +#define SR_IEC ( 1L << 0 ) +#define SR_KUC ( 1L << 1 ) +#define SR_ISC ( 1L << 16 ) +#define SR_SWC ( 1L << 17 ) +#define SR_BEV ( 1L << 22 ) +#define SR_CU0 ( 1L << 28 ) +#define SR_CU1 ( 1L << 29 ) +#define SR_CU2 ( 1L << 30 ) +#define SR_CU3 ( 1L << 31 ) + +#define CAUSE_EXC ( 31L << 2 ) +#define CAUSE_IP ( 255L << 8 ) +#define CAUSE_IP2 ( 1L << 10 ) +#define CAUSE_IP3 ( 1L << 11 ) +#define CAUSE_IP4 ( 1L << 12 ) +#define CAUSE_IP5 ( 1L << 13 ) +#define CAUSE_IP6 ( 1L << 14 ) +#define CAUSE_IP7 ( 1L << 15 ) +#define CAUSE_CE ( 3L << 28 ) +#define CAUSE_BT ( 1L << 30 ) +#define CAUSE_BD ( 1L << 31 ) + +#define BIU_LOCK ( 0x00000001 ) +#define BIU_INV ( 0x00000002 ) +#define BIU_TAG ( 0x00000004 ) +#define BIU_RAM ( 0x00000008 ) +#define BIU_DS ( 0x00000080 ) +#define BIU_IS1 ( 0x00000800 ) + +#define TAG_MATCH_MASK ( 0 - ( ICACHE_ENTRIES * 4 ) ) +#define TAG_MATCH ( 0x10 ) +#define TAG_VALID ( 0x0f ) + +#define MULTIPLIER_OPERATION_IDLE ( 0 ) +#define MULTIPLIER_OPERATION_MULT ( 1 ) +#define MULTIPLIER_OPERATION_MULTU ( 2 ) +#define MULTIPLIER_OPERATION_DIV ( 3 ) +#define MULTIPLIER_OPERATION_DIVU ( 4 ) + +static const char *const delayn[] = +{ + "", "at", "v0", "v1", "a0", "a1", "a2", "a3", + "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", + "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", + "t8", "t9", "k0", "k1", "gp", "sp", "fp", "ra", + "pc", "!pc" +}; + +// device type definition +const device_type CXD8530AQ = &device_creator; +const device_type CXD8530BQ = &device_creator; +const device_type CXD8530CQ = &device_creator; +const device_type CXD8661R = &device_creator; +const device_type CXD8606BQ = &device_creator; +const device_type CXD8606CQ = &device_creator; + +static const UINT32 mtc0_writemask[]= +{ + 0x00000000, /* !INDEX */ + 0x00000000, /* !RANDOM */ + 0x00000000, /* !ENTRYLO */ + 0xffffffff, /* BPC */ + 0x00000000, /* !CONTEXT */ + 0xffffffff, /* BDA */ + 0x00000000, /* TAR */ + 0xff80f03f, /* DCIC */ + 0x00000000, /* BADA */ + 0xffffffff, /* BDAM */ + 0x00000000, /* !ENTRYHI */ + 0xffffffff, /* BPCM */ + 0xf04fff3f, /* SR */ + 0x00000300, /* CAUSE */ + 0x00000000, /* EPC */ + 0x00000000 /* PRID */ +}; + +READ32_MEMBER( psxcpu_device::berr_r ) +{ + if( !space.debugger_access() ) + m_berr = 1; + return 0; +} + +WRITE32_MEMBER( psxcpu_device::berr_w ) +{ + if( !space.debugger_access() ) + m_berr = 1; +} + +READ32_MEMBER( psxcpu_device::exp_base_r ) +{ + return m_exp_base; +} + +WRITE32_MEMBER( psxcpu_device::exp_base_w ) +{ + COMBINE_DATA( &m_exp_base ); // TODO: check byte writes + + m_exp_base = 0x1f000000 | ( m_exp_base & 0xffffff ); +} + +UINT32 psxcpu_device::exp_base() +{ + return m_exp_base; +} + +READ32_MEMBER( psxcpu_device::exp_config_r ) +{ + return m_exp_config; +} + +WRITE32_MEMBER( psxcpu_device::exp_config_w ) +{ + COMBINE_DATA( &m_exp_config ); // TODO: check byte writes + + m_exp_config &= 0xaf1fffff; +} + +READ32_MEMBER( psxcpu_device::ram_config_r ) +{ + return m_ram_config; +} + +WRITE32_MEMBER( psxcpu_device::ram_config_w ) +{ + UINT32 old = m_ram_config; + + COMBINE_DATA( &m_ram_config ); // TODO: check byte writes + + if( ( ( m_ram_config ^ old ) & 0xff00 ) != 0 ) + { + update_ram_config(); + } +} + +READ32_MEMBER( psxcpu_device::rom_config_r ) +{ + return m_rom_config; +} + +WRITE32_MEMBER( psxcpu_device::rom_config_w ) +{ + UINT32 old = m_rom_config; + + COMBINE_DATA( &m_rom_config ); // TODO: check byte writes + + if( ( ( m_rom_config ^ old ) & 0x001f0000 ) != 0 ) + { + update_rom_config(); + } +} + +READ32_MEMBER( psxcpu_device::com_delay_r ) +{ + //verboselog( p_psx, 1, "psx_com_delay_r( %08x )\n", mem_mask ); + return m_com_delay; +} + +WRITE32_MEMBER( psxcpu_device::com_delay_w ) +{ + COMBINE_DATA( &m_com_delay ); // TODO: check byte writes + //verboselog( p_psx, 1, "psx_com_delay_w( %08x %08x )\n", data, mem_mask ); +} + +READ32_MEMBER( psxcpu_device::biu_r ) +{ + return m_biu; +} + +WRITE32_MEMBER( psxcpu_device::biu_w ) +{ + UINT32 old = m_biu; + + COMBINE_DATA( &m_biu ); // TODO: check byte writes + + if( ( old & ( BIU_RAM | BIU_DS ) ) != ( m_biu & ( BIU_RAM | BIU_DS ) ) ) + { + update_scratchpad(); + } +} + +void psxcpu_device::stop() +{ + debugger_break( machine() ); + debugger_instruction_hook( this, m_pc ); +} + +UINT32 psxcpu_device::cache_readword( UINT32 offset ) +{ + UINT32 data = 0; + + if( ( m_biu & BIU_TAG ) != 0 ) + { + if( ( m_biu & BIU_IS1 ) != 0 ) + { + UINT32 tag = m_icacheTag[ ( offset / 16 ) % ( ICACHE_ENTRIES / 4 ) ]; + data |= tag & TAG_VALID; + + if( ( ( tag ^ offset ) & TAG_MATCH_MASK ) == 0 ) + { + data |= TAG_MATCH; + } + } + } + else if( ( m_biu & ( BIU_LOCK | BIU_INV ) ) != 0 ) + { + } + else + { + if( ( m_biu & BIU_IS1 ) == BIU_IS1 ) + { + data |= m_icache[ ( offset / 4 ) % ICACHE_ENTRIES ]; + } + + if( ( m_biu & BIU_DS ) == BIU_DS ) + { + data |= m_dcache[ ( offset / 4 ) % DCACHE_ENTRIES ]; + } + } + + return data; +} + +void psxcpu_device::cache_writeword( UINT32 offset, UINT32 data ) +{ + if( ( m_biu & BIU_TAG ) != 0 ) + { + if( ( m_biu & BIU_IS1 ) != 0 ) + { + m_icacheTag[ ( offset / 16 ) % ( ICACHE_ENTRIES / 4 ) ] = ( data & TAG_VALID ) | ( offset & TAG_MATCH_MASK ); + } + } + else if( ( m_biu & ( BIU_LOCK | BIU_INV ) ) != 0 ) + { + if( ( m_biu & BIU_IS1 ) != 0 ) + { + m_icacheTag[ ( offset / 16 ) % ( ICACHE_ENTRIES / 4 ) ] = ( offset & TAG_MATCH_MASK ); + } + } + else + { + if( ( m_biu & BIU_IS1 ) != 0 ) + { + m_icache[ ( offset / 4 ) % ICACHE_ENTRIES ] = data; + } + + if( ( m_biu & BIU_DS ) != 0 ) + { + m_dcache[ ( offset / 4 ) % DCACHE_ENTRIES ] = data; + } + } +} + +UINT8 psxcpu_device::readbyte( UINT32 address ) +{ + if( m_bus_attached ) + { + return m_program->read_byte( address ); + } + + return cache_readword( address ) >> ( ( address & 3 ) * 8 ); +} + +UINT16 psxcpu_device::readhalf( UINT32 address ) +{ + if( m_bus_attached ) + { + return m_program->read_word( address ); + } + + return cache_readword( address ) >> ( ( address & 2 ) * 8 ); +} + +UINT32 psxcpu_device::readword( UINT32 address ) +{ + if( m_bus_attached ) + { + return m_program->read_dword( address ); + } + + return cache_readword( address ); +} + +UINT32 psxcpu_device::readword_masked( UINT32 address, UINT32 mask ) +{ + if( m_bus_attached ) + { + return m_program->read_dword( address, mask ); + } + + return cache_readword( address ); +} + +void psxcpu_device::writeword( UINT32 address, UINT32 data ) +{ + if( m_bus_attached ) + { + m_program->write_dword( address, data ); + } + else + { + cache_writeword( address, data ); + } +} + +void psxcpu_device::writeword_masked( UINT32 address, UINT32 data, UINT32 mask ) +{ + if( m_bus_attached ) + { + m_program->write_dword( address, data, mask ); + } + else + { + cache_writeword( address, data ); + } +} + + +static const struct +{ + int address; + int operation; + const char *prototype; +} bioscalls[] = +{ + { 0xa0, 0x00, "int open(const char *name, int mode)" }, + { 0xa0, 0x01, "int lseek(int fd, int offset, int whence)" }, + { 0xa0, 0x02, "int read(int fd, void *buf, int nbytes)" }, + { 0xa0, 0x03, "int write(int fd, void *buf, int nbytes)" }, + { 0xa0, 0x04, "int close(int fd)" }, + { 0xa0, 0x05, "int ioctl(int fd, int cmd, int arg)" }, + { 0xa0, 0x06, "void exit(int code)" }, + { 0xa0, 0x07, "sys_a0_07()" }, + { 0xa0, 0x08, "char getc(int fd)" }, + { 0xa0, 0x09, "void putc(char c, int fd)" }, + { 0xa0, 0x0a, "todigit()" }, + { 0xa0, 0x0b, "double atof(const char *s)" }, + { 0xa0, 0x0c, "long strtoul(const char *s, char **ptr, int base)" }, + { 0xa0, 0x0d, "unsigned long strtol(const char *s, char **ptr, int base)" }, + { 0xa0, 0x0e, "int abs(int val)" }, + { 0xa0, 0x0f, "long labs(long lval)" }, + { 0xa0, 0x10, "long atoi(const char *s)" }, + { 0xa0, 0x11, "int atol(const char *s)" }, + { 0xa0, 0x12, "atob()" }, + { 0xa0, 0x13, "int setjmp(jmp_buf *ctx)" }, + { 0xa0, 0x14, "void longjmp(jmp_buf *ctx, int value)" }, + { 0xa0, 0x15, "char *strcat(char *dst, const char *src)" }, + { 0xa0, 0x16, "char *strncat(char *dst, const char *src, size_t n)" }, + { 0xa0, 0x17, "int strcmp(const char *dst, const char *src)" }, + { 0xa0, 0x18, "int strncmp(const char *dst, const char *src, size_t n)" }, + { 0xa0, 0x19, "char *strcpy(char *dst, const char *src)" }, + { 0xa0, 0x1a, "char *strncpy(char *dst, const char *src, size_t n)" }, + { 0xa0, 0x1b, "size_t strlen(const char *s)" }, + { 0xa0, 0x1c, "int index(const char *s, int c)" }, + { 0xa0, 0x1d, "int rindex(const char *s, int c)" }, + { 0xa0, 0x1e, "char *strchr(const char *s, int c)" }, + { 0xa0, 0x1f, "char *strrchr(const char *s, int c)" }, + { 0xa0, 0x20, "char *strpbrk(const char *dst, const char *src)" }, + { 0xa0, 0x21, "size_t strspn(const char *s, const char *set)" }, + { 0xa0, 0x22, "size_t strcspn(const char *s, const char *set)" }, + { 0xa0, 0x23, "char *strtok(char *s, const char *set)" }, + { 0xa0, 0x24, "char *strstr(const char *s, const char *set)" }, + { 0xa0, 0x25, "int toupper(int c)" }, + { 0xa0, 0x26, "int tolower(int c)" }, + { 0xa0, 0x27, "void bcopy(const void *src, void *dst, size_t len)" }, + { 0xa0, 0x28, "void bzero(void *ptr, size_t len)" }, + { 0xa0, 0x29, "int bcmp(const void *ptr1, const void *ptr2, int len)" }, + { 0xa0, 0x2a, "void *memcpy(void *dst, const void *src, size_t n)" }, + { 0xa0, 0x2b, "void *memset(void *dst, char c, size_t n)" }, + { 0xa0, 0x2c, "void *memmove(void *dst, const void *src, size_t n)" }, + { 0xa0, 0x2d, "int memcmp(const void *dst, const void *src, size_t n)" }, + { 0xa0, 0x2e, "void *memchr(const void *s, int c, size_t n)" }, + { 0xa0, 0x2f, "int rand()" }, + { 0xa0, 0x30, "void srand(unsigned int seed)" }, + { 0xa0, 0x31, "void qsort(void *base, int nel, int width, int (*cmp)(void *, void *))" }, + { 0xa0, 0x32, "double strtod(const char *s, char **endptr)" }, + { 0xa0, 0x33, "void *malloc(int size)" }, + { 0xa0, 0x34, "void free(void *buf)" }, + { 0xa0, 0x35, "void *lsearch(void *key, void *base, int belp, int width, int (*cmp)(void *, void *))" }, + { 0xa0, 0x36, "void *bsearch(void *key, void *base, int nel, int size, int (*cmp)(void *, void *))" }, + { 0xa0, 0x37, "void *calloc(int size, int n)" }, + { 0xa0, 0x38, "void *realloc(void *buf, int n)" }, + { 0xa0, 0x39, "InitHeap(void *block, int size)" }, + { 0xa0, 0x3a, "void _exit(int code)" }, + { 0xa0, 0x3b, "char getchar(void)" }, + { 0xa0, 0x3c, "void putchar(char c)" }, + { 0xa0, 0x3d, "char *gets(char *s)" }, + { 0xa0, 0x3e, "void puts(const char *s)" }, + { 0xa0, 0x3f, "int printf(const char *fmt, ...)" }, + { 0xa0, 0x40, "sys_a0_40()" }, + { 0xa0, 0x41, "int LoadTest(const char *name, struct EXEC *header)" }, + { 0xa0, 0x42, "int Load(const char *name, struct EXEC *header)" }, + { 0xa0, 0x43, "int Exec(struct EXEC *header, int argc, char **argv)" }, + { 0xa0, 0x44, "void FlushCache()" }, + { 0xa0, 0x45, "void InstallInterruptHandler()" }, + { 0xa0, 0x46, "GPU_dw(int x, int y, int w, int h, long *data)" }, + { 0xa0, 0x47, "mem2vram(int x, int y, int w, int h, long *data)" }, + { 0xa0, 0x48, "SendGPU(int status)" }, + { 0xa0, 0x49, "GPU_cw(long cw)" }, + { 0xa0, 0x4a, "GPU_cwb(long *pkt, int len)" }, + { 0xa0, 0x4b, "SendPackets(void *ptr)" }, + { 0xa0, 0x4c, "sys_a0_4c()" }, + { 0xa0, 0x4d, "int GetGPUStatus()" }, + { 0xa0, 0x4e, "GPU_sync()" }, + { 0xa0, 0x4f, "sys_a0_4f()" }, + { 0xa0, 0x50, "sys_a0_50()" }, + { 0xa0, 0x51, "int LoadExec(const char *name, int, int)" }, + { 0xa0, 0x52, "GetSysSp()" }, + { 0xa0, 0x53, "sys_a0_53()" }, + { 0xa0, 0x54, "_96_init()" }, + { 0xa0, 0x55, "_bu_init()" }, + { 0xa0, 0x56, "_96_remove()" }, + { 0xa0, 0x57, "sys_a0_57()" }, + { 0xa0, 0x58, "sys_a0_58()" }, + { 0xa0, 0x59, "sys_a0_59()" }, + { 0xa0, 0x5a, "sys_a0_5a()" }, + { 0xa0, 0x5b, "dev_tty_init()" }, + { 0xa0, 0x5c, "dev_tty_open()" }, + { 0xa0, 0x5d, "dev_tty_5d()" }, + { 0xa0, 0x5e, "dev_tty_ioctl()" }, + { 0xa0, 0x5f, "dev_cd_open()" }, + { 0xa0, 0x60, "dev_cd_read()" }, + { 0xa0, 0x61, "dev_cd_close()" }, + { 0xa0, 0x62, "dev_cd_firstfile()" }, + { 0xa0, 0x63, "dev_cd_nextfile()" }, + { 0xa0, 0x64, "dev_cd_chdir()" }, + { 0xa0, 0x65, "dev_card_open()" }, + { 0xa0, 0x66, "dev_card_read()" }, + { 0xa0, 0x67, "dev_card_write()" }, + { 0xa0, 0x68, "dev_card_close()" }, + { 0xa0, 0x69, "dev_card_firstfile()" }, + { 0xa0, 0x6a, "dev_card_nextfile()" }, + { 0xa0, 0x6b, "dev_card_erase()" }, + { 0xa0, 0x6c, "dev_card_undelete()" }, + { 0xa0, 0x6d, "dev_card_format()" }, + { 0xa0, 0x6e, "dev_card_rename()" }, + { 0xa0, 0x6f, "dev_card_6f()" }, + { 0xa0, 0x70, "_bu_init()" }, + { 0xa0, 0x71, "_96_init()" }, + { 0xa0, 0x72, "_96_remove()" }, + { 0xa0, 0x73, "sys_a0_73()" }, + { 0xa0, 0x74, "sys_a0_74()" }, + { 0xa0, 0x75, "sys_a0_75()" }, + { 0xa0, 0x76, "sys_a0_76()" }, + { 0xa0, 0x77, "sys_a0_77()" }, + { 0xa0, 0x78, "_96_CdSeekL()" }, + { 0xa0, 0x79, "sys_a0_79()" }, + { 0xa0, 0x7a, "sys_a0_7a()" }, + { 0xa0, 0x7b, "sys_a0_7b()" }, + { 0xa0, 0x7c, "_96_CdGetStatus()" }, + { 0xa0, 0x7d, "sys_a0_7d()" }, + { 0xa0, 0x7e, "_96_CdRead()" }, + { 0xa0, 0x7f, "sys_a0_7f()" }, + { 0xa0, 0x80, "sys_a0_80()" }, + { 0xa0, 0x81, "sys_a0_81()" }, + { 0xa0, 0x82, "sys_a0_82()" }, + { 0xa0, 0x83, "sys_a0_83()" }, + { 0xa0, 0x84, "sys_a0_84()" }, + { 0xa0, 0x85, "_96_CdStop()" }, + { 0xa0, 0x84, "sys_a0_84()" }, + { 0xa0, 0x85, "sys_a0_85()" }, + { 0xa0, 0x86, "sys_a0_86()" }, + { 0xa0, 0x87, "sys_a0_87()" }, + { 0xa0, 0x88, "sys_a0_88()" }, + { 0xa0, 0x89, "sys_a0_89()" }, + { 0xa0, 0x8a, "sys_a0_8a()" }, + { 0xa0, 0x8b, "sys_a0_8b()" }, + { 0xa0, 0x8c, "sys_a0_8c()" }, + { 0xa0, 0x8d, "sys_a0_8d()" }, + { 0xa0, 0x8e, "sys_a0_8e()" }, + { 0xa0, 0x8f, "sys_a0_8f()" }, + { 0xa0, 0x90, "sys_a0_90()" }, + { 0xa0, 0x91, "sys_a0_91()" }, + { 0xa0, 0x92, "sys_a0_92()" }, + { 0xa0, 0x93, "sys_a0_93()" }, + { 0xa0, 0x94, "sys_a0_94()" }, + { 0xa0, 0x95, "sys_a0_95()" }, + { 0xa0, 0x96, "AddCDROMDevice()" }, + { 0xa0, 0x97, "AddMemCardDevice()" }, + { 0xa0, 0x98, "DisableKernelIORedirection()" }, + { 0xa0, 0x99, "EnableKernelIORedirection()" }, + { 0xa0, 0x9a, "sys_a0_9a()" }, + { 0xa0, 0x9b, "sys_a0_9b()" }, + { 0xa0, 0x9c, "void SetConf(int Event, int TCB, int Stack)" }, + { 0xa0, 0x9d, "void GetConf(int *Event, int *TCB, int *Stack)" }, + { 0xa0, 0x9e, "sys_a0_9e()" }, + { 0xa0, 0x9f, "void SetMem(int size)" }, + { 0xa0, 0xa0, "_boot()" }, + { 0xa0, 0xa1, "SystemError()" }, + { 0xa0, 0xa2, "EnqueueCdIntr()" }, + { 0xa0, 0xa3, "DequeueCdIntr()" }, + { 0xa0, 0xa4, "sys_a0_a4()" }, + { 0xa0, 0xa5, "ReadSector(int count, int sector, void *buffer)" }, + { 0xa0, 0xa6, "get_cd_status()" }, + { 0xa0, 0xa7, "bufs_cb_0()" }, + { 0xa0, 0xa8, "bufs_cb_1()" }, + { 0xa0, 0xa9, "bufs_cb_2()" }, + { 0xa0, 0xaa, "bufs_cb_3()" }, + { 0xa0, 0xab, "_card_info()" }, + { 0xa0, 0xac, "_card_load()" }, + { 0xa0, 0xad, "_card_auto()" }, + { 0xa0, 0xae, "bufs_cb_4()" }, + { 0xa0, 0xaf, "sys_a0_af()" }, + { 0xa0, 0xb0, "sys_a0_b0()" }, + { 0xa0, 0xb1, "sys_a0_b1()" }, + { 0xa0, 0xb2, "do_a_long_jmp()" }, + { 0xa0, 0xb3, "sys_a0_b3()" }, + { 0xa0, 0xb4, "GetKernelInfo(int sub_function)" }, + { 0xb0, 0x00, "SysMalloc()" }, + { 0xb0, 0x01, "sys_b0_01()" }, + { 0xb0, 0x02, "sys_b0_02()" }, + { 0xb0, 0x03, "sys_b0_03()" }, + { 0xb0, 0x04, "sys_b0_04()" }, + { 0xb0, 0x05, "sys_b0_05()" }, + { 0xb0, 0x06, "sys_b0_06()" }, + { 0xb0, 0x07, "void DeliverEvent(u_long class, u_long event)" }, + { 0xb0, 0x08, "long OpenEvent(u_long class, long spec, long mode, long (*func)())" }, + { 0xb0, 0x09, "long CloseEvent(long event)" }, + { 0xb0, 0x0a, "long WaitEvent(long event)" }, + { 0xb0, 0x0b, "long TestEvent(long event)" }, + { 0xb0, 0x0c, "long EnableEvent(long event)" }, + { 0xb0, 0x0d, "long DisableEvent(long event)" }, + { 0xb0, 0x0e, "OpenTh()" }, + { 0xb0, 0x0f, "CloseTh()" }, + { 0xb0, 0x10, "ChangeTh()" }, + { 0xb0, 0x11, "sys_b0_11()" }, + { 0xb0, 0x12, "int InitPAD(char *buf1, int len1, char *buf2, int len2)" }, + { 0xb0, 0x13, "int StartPAD(void)" }, + { 0xb0, 0x14, "int StopPAD(void)" }, + { 0xb0, 0x15, "PAD_init(u_long nazo, u_long *pad_buf)" }, + { 0xb0, 0x16, "u_long PAD_dr()" }, + { 0xb0, 0x17, "void ReturnFromException(void)" }, + { 0xb0, 0x18, "ResetEntryInt()" }, + { 0xb0, 0x19, "HookEntryInt()" }, + { 0xb0, 0x1a, "sys_b0_1a()" }, + { 0xb0, 0x1b, "sys_b0_1b()" }, + { 0xb0, 0x1c, "sys_b0_1c()" }, + { 0xb0, 0x1d, "sys_b0_1d()" }, + { 0xb0, 0x1e, "sys_b0_1e()" }, + { 0xb0, 0x1f, "sys_b0_1f()" }, + { 0xb0, 0x20, "UnDeliverEvent(int class, int event)" }, + { 0xb0, 0x21, "sys_b0_21()" }, + { 0xb0, 0x22, "sys_b0_22()" }, + { 0xb0, 0x23, "sys_b0_23()" }, + { 0xb0, 0x24, "sys_b0_24()" }, + { 0xb0, 0x25, "sys_b0_25()" }, + { 0xb0, 0x26, "sys_b0_26()" }, + { 0xb0, 0x27, "sys_b0_27()" }, + { 0xb0, 0x28, "sys_b0_28()" }, + { 0xb0, 0x29, "sys_b0_29()" }, + { 0xb0, 0x2a, "sys_b0_2a()" }, + { 0xb0, 0x2b, "sys_b0_2b()" }, + { 0xb0, 0x2c, "sys_b0_2c()" }, + { 0xb0, 0x2d, "sys_b0_2d()" }, + { 0xb0, 0x2e, "sys_b0_2e()" }, + { 0xb0, 0x2f, "sys_b0_2f()" }, + { 0xb0, 0x2f, "sys_b0_30()" }, + { 0xb0, 0x31, "sys_b0_31()" }, + { 0xb0, 0x32, "int open(const char *name, int access)" }, + { 0xb0, 0x33, "int lseek(int fd, long pos, int seektype)" }, + { 0xb0, 0x34, "int read(int fd, void *buf, int nbytes)" }, + { 0xb0, 0x35, "int write(int fd, void *buf, int nbytes)" }, + { 0xb0, 0x36, "close(int fd)" }, + { 0xb0, 0x37, "int ioctl(int fd, int cmd, int arg)" }, + { 0xb0, 0x38, "exit(int exitcode)" }, + { 0xb0, 0x39, "sys_b0_39()" }, + { 0xb0, 0x3a, "char getc(int fd)" }, + { 0xb0, 0x3b, "putc(int fd, char ch)" }, + { 0xb0, 0x3c, "char getchar(void)" }, + { 0xb0, 0x3d, "putchar(char ch)" }, + { 0xb0, 0x3e, "char *gets(char *s)" }, + { 0xb0, 0x3f, "puts(const char *s)" }, + { 0xb0, 0x40, "int cd(const char *path)" }, + { 0xb0, 0x41, "int format(const char *fs)" }, + { 0xb0, 0x42, "struct DIRENTRY* firstfile(const char *name, struct DIRENTRY *dir)" }, + { 0xb0, 0x43, "struct DIRENTRY* nextfile(struct DIRENTRY *dir)" }, + { 0xb0, 0x44, "int rename(const char *oldname, const char *newname)" }, + { 0xb0, 0x45, "int delete(const char *name)" }, + { 0xb0, 0x46, "undelete()" }, + { 0xb0, 0x47, "AddDevice()" }, + { 0xb0, 0x48, "RemoveDevice()" }, + { 0xb0, 0x49, "PrintInstalledDevices()" }, + { 0xb0, 0x4a, "InitCARD()" }, + { 0xb0, 0x4b, "StartCARD()" }, + { 0xb0, 0x4c, "StopCARD()" }, + { 0xb0, 0x4d, "sys_b0_4d()" }, + { 0xb0, 0x4e, "_card_write()" }, + { 0xb0, 0x4f, "_card_read()" }, + { 0xb0, 0x50, "_new_card()" }, + { 0xb0, 0x51, "void *Krom2RawAdd(int code)" }, + { 0xb0, 0x52, "sys_b0_52()" }, + { 0xb0, 0x53, "sys_b0_53()" }, + { 0xb0, 0x54, "long _get_errno(void)" }, + { 0xb0, 0x55, "long _get_error(long fd)" }, + { 0xb0, 0x56, "GetC0Table()" }, + { 0xb0, 0x57, "GetB0Table()" }, + { 0xb0, 0x58, "_card_chan()" }, + { 0xb0, 0x59, "sys_b0_59()" }, + { 0xb0, 0x5a, "sys_b0_5a()" }, + { 0xb0, 0x5b, "ChangeClearPAD(int, int)" }, + { 0xb0, 0x5c, "_card_status()" }, + { 0xb0, 0x5d, "_card_wait()" }, + { 0xc0, 0x00, "InitRCnt()" }, + { 0xc0, 0x01, "InitException()" }, + { 0xc0, 0x02, "SysEnqIntRP(int index, long *queue)" }, + { 0xc0, 0x03, "SysDeqIntRP(int index, long *queue)" }, + { 0xc0, 0x04, "int get_free_EvCB_slot(void)" }, + { 0xc0, 0x05, "get_free_TCB_slot()" }, + { 0xc0, 0x06, "ExceptionHandler()" }, + { 0xc0, 0x07, "InstallExceptionHandlers()" }, + { 0xc0, 0x08, "SysInitMemory()" }, + { 0xc0, 0x09, "SysInitKMem()" }, + { 0xc0, 0x0a, "ChangeClearRCnt()" }, + { 0xc0, 0x0b, "SystemError()" }, + { 0xc0, 0x0c, "InitDefInt()" }, + { 0xc0, 0x0d, "sys_c0_0d()" }, + { 0xc0, 0x0e, "sys_c0_0e()" }, + { 0xc0, 0x0f, "sys_c0_0f()" }, + { 0xc0, 0x10, "sys_c0_10()" }, + { 0xc0, 0x11, "sys_c0_11()" }, + { 0xc0, 0x12, "InstallDevices()" }, + { 0xc0, 0x13, "FlushStdInOutPut()" }, + { 0xc0, 0x14, "sys_c0_14()" }, + { 0xc0, 0x15, "_cdevinput()" }, + { 0xc0, 0x16, "_cdevscan()" }, + { 0xc0, 0x17, "char _circgetc(struct device_buf *circ)" }, + { 0xc0, 0x18, "_circputc(char c, struct device_buf *circ)" }, + { 0xc0, 0x19, "ioabort(const char *str)" }, + { 0xc0, 0x1a, "sys_c0_1a()" }, + { 0xc0, 0x1b, "KernelRedirect(int flag)" }, + { 0xc0, 0x1c, "PatchA0Table()" }, + { 0x00, 0x00, NULL } +}; + +UINT32 psxcpu_device::log_bioscall_parameter( int parm ) +{ + if( parm < 4 ) + { + return m_r[ 4 + parm ]; + } + + return readword( m_r[ 29 ] + ( parm * 4 ) ); +} + +const char *psxcpu_device::log_bioscall_string( int parm ) +{ + int pos; + UINT32 address; + static char string[ 1024 ]; + + address = log_bioscall_parameter( parm ); + if( address == 0 ) + { + return "NULL"; + } + + pos = 0; + string[ pos++ ] = '\"'; + + for( ;; ) + { + UINT8 c = readbyte( address ); + if( c == 0 ) + { + break; + } + else if( c == '\t' ) + { + string[ pos++ ] = '\\'; + string[ pos++ ] = 't'; + } + else if( c == '\r' ) + { + string[ pos++ ] = '\\'; + string[ pos++ ] = 'r'; + } + else if( c == '\n' ) + { + string[ pos++ ] = '\\'; + string[ pos++ ] = 'n'; + } + else if( c < 32 || c > 127 ) + { + string[ pos++ ] = '\\'; + string[ pos++ ] = ( ( c / 64 ) % 8 ) + '0'; + string[ pos++ ] = ( ( c / 8 ) % 8 ) + '0'; + string[ pos++ ] = ( ( c / 1 ) % 8 ) + '0'; + } + else + { + string[ pos++ ] = c; + } + address++; + } + + string[ pos++ ] = '\"'; + string[ pos++ ] = 0; + + return string; +} + +const char *psxcpu_device::log_bioscall_hex( int parm ) +{ + static char string[ 1024 ]; + + sprintf( string, "0x%08x", log_bioscall_parameter( parm ) ); + + return string; +} + +const char *psxcpu_device::log_bioscall_char( int parm ) +{ + int c; + static char string[ 1024 ]; + + c = log_bioscall_parameter( parm ); + if( c < 32 || c > 127 ) + { + sprintf( string, "0x%02x", c ); + } + else + { + sprintf( string, "'%c'", c ); + } + + return string; +} + +void psxcpu_device::log_bioscall() +{ + int address = m_pc - 0x04; + if( address == 0xa0 || + address == 0xb0 || + address == 0xc0 ) + { + char buf[ 1024 ]; + int operation = m_r[ 9 ] & 0xff; + int bioscall = 0; + + if( ( address == 0xa0 && operation == 0x3c ) || + ( address == 0xb0 && operation == 0x3d ) ) + { + putchar( log_bioscall_parameter( 0 ) ); + } + + if( ( address == 0xa0 && operation == 0x03 ) || + ( address == 0xb0 && operation == 0x35 ) ) + { + int fd = log_bioscall_parameter( 0 ); + int buffer = log_bioscall_parameter( 1 ); + int nbytes = log_bioscall_parameter( 2 ); + + if( fd == 1 ) + { + while( nbytes > 0 ) + { + UINT8 c = readbyte( buffer ); + putchar( c ); + nbytes--; + buffer++; + } + } + } + + while( bioscalls[ bioscall ].prototype != NULL && + ( bioscalls[ bioscall ].address != address || + bioscalls[ bioscall ].operation != operation ) ) + { + bioscall++; + } + + if( bioscalls[ bioscall ].prototype != NULL ) + { + const char *prototype = bioscalls[ bioscall ].prototype; + const char *parmstart = NULL; + int parm = 0; + int parmlen = -1; + int brackets = 0; + int pos = 0; + + while( *( prototype ) != 0 ) + { + int ch = *( prototype ); + + switch( ch ) + { + case '(': + brackets++; + prototype++; + if( brackets == 1 ) + { + buf[ pos++ ] = ch; + parmstart = prototype; + } + break; + + case ')': + if( brackets == 1 ) + { + parmlen = prototype - parmstart; + } + prototype++; + brackets--; + break; + + case ',': + if( brackets == 1 ) + { + parmlen = prototype - parmstart; + } + prototype++; + break; + + default: + if( brackets == 0 ) + { + buf[ pos++ ] = ch; + } + prototype++; + break; + } + + if( parmlen >= 0 ) + { + while( parmlen > 0 && parmstart[ 0 ] == ' ' ) + { + parmstart++; + parmlen--; + } + while( parmlen > 0 && parmstart[ parmlen - 1 ] == ' ' ) + { + parmlen--; + } + + if( parmlen == 0 || + ( parmlen == 4 && memcmp( parmstart, "void", 4 ) == 0 ) ) + { + parm = -1; + } + else if( parmlen == 3 && memcmp( parmstart, "...", 3 ) == 0 ) + { + if( parm > 0 ) + { + UINT32 format = log_bioscall_parameter( parm - 1 ); + const char *parmstr = NULL; + int percent = 0; + + for( ;; ) + { + UINT8 c = readbyte( format ); + if( c == 0 ) + { + break; + } + if( percent == 0 ) + { + if( c == '%' ) + { + percent = 1; + } + } + else + { + if( c == '%' ) + { + percent = 0; + } + else if( c == '*' ) + { + parmstr = log_bioscall_hex( parm ); + } + else if( c == 's' ) + { + parmstr = log_bioscall_string( parm ); + percent = 0; + } + else if( c == 'c' ) + { + parmstr = log_bioscall_char( parm ); + percent = 0; + } + else if( c != '-' && c != '.' && c != 'l' && ( c < '0' || c > '9' ) ) + { + parmstr = log_bioscall_hex( parm ); + percent = 0; + } + } + + if( parmstr != NULL ) + { + if( parm > 0 ) + { + buf[ pos++ ] = ','; + } + buf[ pos++ ] = ' '; + + strcpy( &buf[ pos ], parmstr ); + pos += strlen( parmstr ); + parmstr = NULL; + + parm++; + } + format++; + } + } + } + else if( parmlen > 0 ) + { + const char *parmstr; + + int typelen = parmlen; + while( typelen > 0 && parmstart[ typelen - 1 ] != ' ' && parmstart[ typelen - 1 ] != '*' ) + { + typelen--; + } + + if( typelen == 5 && memcmp( parmstart, "char ", 5 ) == 0 ) + { + parmstr = log_bioscall_char( parm ); + } + else if( typelen == 12 && memcmp( parmstart, "const char *", 12 ) == 0 ) + { + parmstr = log_bioscall_string( parm ); + } + else + { + parmstr = log_bioscall_hex( parm ); + } + + if( parm > 0 ) + { + buf[ pos++ ] = ','; + } + buf[ pos++ ] = ' '; + + strcpy( &buf[ pos ], parmstr ); + pos += strlen( parmstr ); + } + + parmlen = -1; + parm++; + + if( ch == ',' ) + { + parmstart = prototype; + } + else + { + if( parm > 0 ) + { + buf[ pos++ ] = ' '; + } + buf[ pos++ ] = ch; + } + } + } + buf[ pos ] = 0; + } + else + { + sprintf( buf, "unknown_%02x_%02x", address, operation ); + } + logerror( "%08x: bioscall %s\n", (unsigned int)m_r[ 31 ] - 8, buf ); + } +} + +void psxcpu_device::log_syscall() +{ + char buf[ 1024 ]; + int operation = m_r[ 4 ]; + + switch( operation ) + { + case 0: + strcpy( buf, "void Exception()" ); + break; + + case 1: + strcpy( buf, "void EnterCriticalSection()" ); + break; + + case 2: + strcpy( buf, "void ExitCriticalSection()" ); + break; + + default: + sprintf( buf, "unknown_%02x", operation ); + break; + } + logerror( "%08x: syscall %s\n", (unsigned int)m_r[ 31 ] - 8, buf ); +} + +void psxcpu_device::update_memory_handlers() +{ + if( ( m_cp0r[ CP0_SR ] & SR_ISC ) != 0 ) + { + m_bus_attached = 0; + } + else + { + m_bus_attached = 1; + } +} + +void psxcpu_device::funct_mthi() +{ + m_multiplier_operation = MULTIPLIER_OPERATION_IDLE; + m_hi = m_r[ INS_RS( m_op ) ]; +} + +void psxcpu_device::funct_mtlo() +{ + m_multiplier_operation = MULTIPLIER_OPERATION_IDLE; + m_lo = m_r[ INS_RS( m_op ) ]; +} + +void psxcpu_device::funct_mult() +{ + m_multiplier_operation = MULTIPLIER_OPERATION_MULT; + m_multiplier_operand1 = m_r[ INS_RS( m_op ) ]; + m_multiplier_operand2 = m_r[ INS_RT( m_op ) ]; + m_lo = m_multiplier_operand1; +} + +void psxcpu_device::funct_multu() +{ + m_multiplier_operation = MULTIPLIER_OPERATION_MULTU; + m_multiplier_operand1 = m_r[ INS_RS( m_op ) ]; + m_multiplier_operand2 = m_r[ INS_RT( m_op ) ]; + m_lo = m_multiplier_operand1; +} + +void psxcpu_device::funct_div() +{ + m_multiplier_operation = MULTIPLIER_OPERATION_DIV; + m_multiplier_operand1 = m_r[ INS_RS( m_op ) ]; + m_multiplier_operand2 = m_r[ INS_RT( m_op ) ]; + m_lo = m_multiplier_operand1; + m_hi = 0; +} + +void psxcpu_device::funct_divu() +{ + m_multiplier_operation = MULTIPLIER_OPERATION_DIVU; + m_multiplier_operand1 = m_r[ INS_RS( m_op ) ]; + m_multiplier_operand2 = m_r[ INS_RT( m_op ) ]; + m_lo = m_multiplier_operand1; + m_hi = 0; +} + +void psxcpu_device::multiplier_update() +{ + switch( m_multiplier_operation ) + { + case MULTIPLIER_OPERATION_MULT: + { + INT64 result = mul_32x32( (INT32)m_multiplier_operand1, (INT32)m_multiplier_operand2 ); + m_lo = EXTRACT_64LO( result ); + m_hi = EXTRACT_64HI( result ); + } + break; + + case MULTIPLIER_OPERATION_MULTU: + { + UINT64 result = mulu_32x32( m_multiplier_operand1, m_multiplier_operand2 ); + m_lo = EXTRACT_64LO( result ); + m_hi = EXTRACT_64HI( result ); + } + break; + + case MULTIPLIER_OPERATION_DIV: + if( m_multiplier_operand1 == 0x80000000 && m_multiplier_operand2 == 0xffffffff) + { + m_hi = 0x00000000; + m_lo = 0x80000000; + } + else if( m_multiplier_operand2 == 0 ) + { + if( (INT32)m_multiplier_operand1 < 0 ) + { + m_lo = 1; + } + else + { + m_lo = 0xffffffff; + } + + m_hi = m_multiplier_operand1; + } + else + { + m_lo = (INT32)m_multiplier_operand1 / (INT32)m_multiplier_operand2; + m_hi = (INT32)m_multiplier_operand1 % (INT32)m_multiplier_operand2; + } + break; + + case MULTIPLIER_OPERATION_DIVU: + if( m_multiplier_operand2 == 0 ) + { + m_lo = 0xffffffff; + m_hi = m_multiplier_operand1; + } + else + { + m_lo = m_multiplier_operand1 / m_multiplier_operand2; + m_hi = m_multiplier_operand1 % m_multiplier_operand2; + } + break; + } + + m_multiplier_operation = MULTIPLIER_OPERATION_IDLE; +} + +UINT32 psxcpu_device::get_hi() +{ + if( m_multiplier_operation != MULTIPLIER_OPERATION_IDLE ) + { + multiplier_update(); + } + + return m_hi; +} + +UINT32 psxcpu_device::get_lo() +{ + if( m_multiplier_operation != MULTIPLIER_OPERATION_IDLE ) + { + multiplier_update(); + } + + return m_lo; +} + +int psxcpu_device::execute_unstoppable_instructions( int executeCop2 ) +{ + switch( INS_OP( m_op ) ) + { + case OP_SPECIAL: + switch( INS_FUNCT( m_op ) ) + { + case FUNCT_MTHI: + funct_mthi(); + break; + + case FUNCT_MTLO: + funct_mtlo(); + break; + + case FUNCT_MULT: + funct_mult(); + break; + + case FUNCT_MULTU: + funct_multu(); + break; + + case FUNCT_DIV: + funct_div(); + break; + + case FUNCT_DIVU: + funct_divu(); + break; + } + break; + + case OP_COP2: + if( executeCop2 ) + { + switch( INS_CO( m_op ) ) + { + case 1: + if( ( m_cp0r[ CP0_SR ] & SR_CU2 ) == 0 ) + { + return 0; + } + + if( !m_gte.docop2( m_pc, INS_COFUN( m_op ) ) ) + { + stop(); + } + break; + } + } + } + + return 1; +} + +void psxcpu_device::update_address_masks() +{ + if( ( m_cp0r[ CP0_SR ] & SR_KUC ) != 0 ) + { + m_bad_byte_address_mask = 0x80000000; + m_bad_half_address_mask = 0x80000001; + m_bad_word_address_mask = 0x80000003; + } + else + { + m_bad_byte_address_mask = 0; + m_bad_half_address_mask = 1; + m_bad_word_address_mask = 3; + } +} + +void psxcpu_device::update_scratchpad() +{ + if( ( m_biu & BIU_RAM ) == 0 ) + { + m_program->install_readwrite_handler( 0x1f800000, 0x1f8003ff, read32_delegate( FUNC( psxcpu_device::berr_r ), this ), write32_delegate( FUNC( psxcpu_device::berr_w ), this ) ); + } + else if( ( m_biu & BIU_DS ) == 0 ) + { + m_program->install_read_handler( 0x1f800000, 0x1f8003ff, read32_delegate( FUNC( psxcpu_device::berr_r ), this ) ); + m_program->nop_write( 0x1f800000, 0x1f8003ff ); + } + else + { + m_program->install_ram( 0x1f800000, 0x1f8003ff, m_dcache ); + } +} + +void psxcpu_device::update_ram_config() +{ + /// TODO: find out what these values really control and confirm they are the same on each cpu type. + + int window_size = 0; + switch( ( m_ram_config >> 8 ) & 0xf ) + { + case 0x8: // konami gv + window_size = 0x0200000; + break; + + case 0xc: // zn1/konami gq/namco system 11/twinkle/system 573 + window_size = 0x0400000; + break; + + case 0x3: // zn2 + case 0xb: // console/primal rage 2 + window_size = 0x0800000; + break; + + case 0xf: // namco system 10/namco system 12 + window_size = 0x1000000; + break; + } + + UINT32 ram_size = m_ram->size(); + UINT8 *pointer = m_ram->pointer(); + + if( ram_size > window_size ) + { + ram_size = window_size; + } + + if( ram_size > 0 ) + { + int start = 0; + while( start < window_size ) + { + m_program->install_ram( start + 0x00000000, start + 0x00000000 + ram_size - 1, pointer ); + m_program->install_ram( start + 0x80000000, start + 0x80000000 + ram_size - 1, pointer ); + m_program->install_ram( start + 0xa0000000, start + 0xa0000000 + ram_size - 1, pointer ); + + start += ram_size; + } + } + + m_program->install_readwrite_handler( 0x00000000 + window_size, 0x1effffff, read32_delegate( FUNC( psxcpu_device::berr_r ), this ), write32_delegate( FUNC( psxcpu_device::berr_w ), this ) ); + m_program->install_readwrite_handler( 0x80000000 + window_size, 0x9effffff, read32_delegate( FUNC( psxcpu_device::berr_r ), this ), write32_delegate( FUNC( psxcpu_device::berr_w ), this ) ); + m_program->install_readwrite_handler( 0xa0000000 + window_size, 0xbeffffff, read32_delegate( FUNC( psxcpu_device::berr_r ), this ), write32_delegate( FUNC( psxcpu_device::berr_w ), this ) ); +} + +void psxcpu_device::update_rom_config() +{ + int window_size = 1 << ( ( m_rom_config >> 16 ) & 0x1f ); + int max_window_size = 0x400000; + if( window_size > max_window_size ) + { + window_size = max_window_size; + } + + UINT32 rom_size = m_rom->bytes(); + UINT8 *pointer = m_rom->base(); + + if( rom_size > window_size ) + { + rom_size = window_size; + } + + if( rom_size > 0 ) + { + int start = 0; + while( start < window_size ) + { + m_program->install_rom( start + 0x1fc00000, start + 0x1fc00000 + rom_size - 1, pointer ); + m_program->install_rom( start + 0x9fc00000, start + 0x9fc00000 + rom_size - 1, pointer ); + m_program->install_rom( start + 0xbfc00000, start + 0xbfc00000 + rom_size - 1, pointer ); + + start += rom_size; + } + } + + if( window_size < max_window_size && !m_disable_rom_berr) + { + m_program->install_readwrite_handler( 0x1fc00000 + window_size, 0x1fffffff, read32_delegate( FUNC( psxcpu_device::berr_r ), this ), write32_delegate( FUNC( psxcpu_device::berr_w ), this ) ); + m_program->install_readwrite_handler( 0x9fc00000 + window_size, 0x9fffffff, read32_delegate( FUNC( psxcpu_device::berr_r ), this ), write32_delegate( FUNC( psxcpu_device::berr_w ), this ) ); + m_program->install_readwrite_handler( 0xbfc00000 + window_size, 0xbfffffff, read32_delegate( FUNC( psxcpu_device::berr_r ), this ), write32_delegate( FUNC( psxcpu_device::berr_w ), this ) ); + } +} + +void psxcpu_device::update_cop0( int reg ) +{ + if( reg == CP0_SR ) + { + update_memory_handlers(); + update_address_masks(); + } + + if( ( reg == CP0_SR || reg == CP0_CAUSE ) && + ( m_cp0r[ CP0_SR ] & SR_IEC ) != 0 && + ( m_cp0r[ CP0_SR ] & m_cp0r[ CP0_CAUSE ] & CAUSE_IP ) != 0 ) + { + m_op = m_direct->read_dword( m_pc ); + execute_unstoppable_instructions( 1 ); + exception( EXC_INT ); + } + else if( reg == CP0_SR && + m_delayr != PSXCPU_DELAYR_PC && + ( m_pc & m_bad_word_address_mask ) != 0 ) + { + load_bad_address( m_pc ); + } +} + +void psxcpu_device::commit_delayed_load() +{ + if( m_delayr != 0 ) + { + m_r[ m_delayr ] = m_delayv; + m_delayr = 0; + m_delayv = 0; + } +} + +void psxcpu_device::set_pc( unsigned pc ) +{ + m_pc = pc; +} + +void psxcpu_device::fetch_next_op() +{ + if( m_delayr == PSXCPU_DELAYR_PC ) + { + UINT32 safepc = m_delayv & ~m_bad_word_address_mask; + + m_op = m_direct->read_dword( safepc ); + } + else + { + m_op = m_direct->read_dword( m_pc + 4 ); + } +} + +int psxcpu_device::advance_pc() +{ + if( m_delayr == PSXCPU_DELAYR_PC ) + { + m_pc = m_delayv; + m_delayr = 0; + m_delayv = 0; + + if( ( m_pc & m_bad_word_address_mask ) != 0 ) + { + load_bad_address( m_pc ); + return 0; + } + } + else if( m_delayr == PSXCPU_DELAYR_NOTPC ) + { + m_delayr = 0; + m_delayv = 0; + m_pc += 4; + } + else + { + commit_delayed_load(); + m_pc += 4; + } + + return 1; +} + +void psxcpu_device::load( UINT32 reg, UINT32 value ) +{ + advance_pc(); + + if( reg != 0 ) + { + m_r[ reg ] = value; + } +} + +void psxcpu_device::delayed_load( UINT32 reg, UINT32 value ) +{ + if( m_delayr == reg ) + { + m_delayr = 0; + m_delayv = 0; + } + + advance_pc(); + + m_delayr = reg; + m_delayv = value; +} + +void psxcpu_device::branch( UINT32 address ) +{ + advance_pc(); + + m_delayr = PSXCPU_DELAYR_PC; + m_delayv = address; +} + +void psxcpu_device::conditional_branch( int takeBranch ) +{ + advance_pc(); + + if( takeBranch ) + { + m_delayr = PSXCPU_DELAYR_PC; + m_delayv = m_pc + ( PSXCPU_WORD_EXTEND( INS_IMMEDIATE( m_op ) ) << 2 ); + } + else + { + m_delayr = PSXCPU_DELAYR_NOTPC; + m_delayv = 0; + } +} + +void psxcpu_device::unconditional_branch() +{ + advance_pc(); + + m_delayr = PSXCPU_DELAYR_PC; + m_delayv = ( m_pc & 0xf0000000 ) + ( INS_TARGET( m_op ) << 2 ); +} + +void psxcpu_device::common_exception( int exception, UINT32 romOffset, UINT32 ramOffset ) +{ + int cause = ( exception << 2 ) | ( ( ( m_op >> 26 ) & 3 ) << 28 ); + + if( m_delayr == PSXCPU_DELAYR_PC ) + { + cause |= CAUSE_BT; + m_cp0r[ CP0_TAR ] = m_delayv; + } + else if( m_delayr == PSXCPU_DELAYR_NOTPC ) + { + m_cp0r[ CP0_TAR ] = m_pc + 4; + } + else + { + commit_delayed_load(); + } + + if( m_delayr == PSXCPU_DELAYR_PC || m_delayr == PSXCPU_DELAYR_NOTPC ) + { + cause |= CAUSE_BD; + m_cp0r[ CP0_EPC ] = m_pc - 4; + } + else + { + m_cp0r[ CP0_EPC ] = m_pc; + } + + if( LOG_BIOSCALL && exception != EXC_INT ) + { + logerror( "%08x: Exception %d\n", m_pc, exception ); + } + + m_delayr = 0; + m_delayv = 0; + m_berr = 0; + + if( m_cp0r[ CP0_SR ] & SR_BEV ) + { + set_pc( romOffset ); + } + else + { + set_pc( ramOffset ); + } + + m_cp0r[ CP0_SR ] = ( m_cp0r[ CP0_SR ] & ~0x3f ) | ( ( m_cp0r[ CP0_SR ] << 2 ) & 0x3f ); + m_cp0r[ CP0_CAUSE ] = ( m_cp0r[ CP0_CAUSE ] & ~( CAUSE_EXC | CAUSE_BD | CAUSE_BT | CAUSE_CE ) ) | cause; + update_cop0( CP0_SR ); +} + +void psxcpu_device::exception( int exception ) +{ + common_exception( exception, 0xbfc00180, 0x80000080 ); +} + +void psxcpu_device::breakpoint_exception() +{ + fetch_next_op(); + execute_unstoppable_instructions( 1 ); + common_exception( EXC_BP, 0xbfc00140, 0x80000040 ); +} + +void psxcpu_device::fetch_bus_error_exception() +{ + common_exception( EXC_IBE, 0xbfc00180, 0x80000080 ); +} + +void psxcpu_device::load_bus_error_exception() +{ + fetch_next_op(); + execute_unstoppable_instructions( 0 ); + common_exception( EXC_DBE, 0xbfc00180, 0x80000080 ); +} + +void psxcpu_device::store_bus_error_exception() +{ + fetch_next_op(); + + if( execute_unstoppable_instructions( 1 ) ) + { + if( !advance_pc() ) + { + return; + } + + fetch_next_op(); + execute_unstoppable_instructions( 0 ); + } + + common_exception( EXC_DBE, 0xbfc00180, 0x80000080 ); +} + +void psxcpu_device::load_bad_address( UINT32 address ) +{ + m_cp0r[ CP0_BADA ] = address; + exception( EXC_ADEL ); +} + +void psxcpu_device::store_bad_address( UINT32 address ) +{ + m_cp0r[ CP0_BADA ] = address; + exception( EXC_ADES ); +} + +int psxcpu_device::data_address_breakpoint( int dcic_rw, int dcic_status, UINT32 address ) +{ + if( address < 0x1f000000 || address > 0x1fffffff ) + { + if( ( m_cp0r[ CP0_DCIC ] & DCIC_DE ) != 0 && + ( ( ( m_cp0r[ CP0_DCIC ] & DCIC_KD ) != 0 && ( m_cp0r[ CP0_SR ] & SR_KUC ) == 0 ) || + ( ( m_cp0r[ CP0_DCIC ] & DCIC_UD ) != 0 && ( m_cp0r[ CP0_SR ] & SR_KUC ) != 0 ) ) ) + { + if( ( m_cp0r[ CP0_DCIC ] & dcic_rw ) == dcic_rw && + ( address & m_cp0r[ CP0_BDAM ] ) == ( m_cp0r[ CP0_BDA ] & m_cp0r[ CP0_BDAM ] ) ) + { + m_cp0r[ CP0_DCIC ] = ( m_cp0r[ CP0_DCIC ] & ~DCIC_STATUS ) | dcic_status; + + if( ( m_cp0r[ CP0_DCIC ] & DCIC_TR ) != 0 ) + { + return 1; + } + } + } + } + + return 0; +} + +int psxcpu_device::load_data_address_breakpoint( UINT32 address ) +{ + return data_address_breakpoint( DCIC_DR | DCIC_DAE, DCIC_DB | DCIC_DA | DCIC_R, address ); +} + +int psxcpu_device::store_data_address_breakpoint( UINT32 address ) +{ + return data_address_breakpoint( DCIC_DW | DCIC_DAE, DCIC_DB | DCIC_DA | DCIC_W, address ); +} + +// On-board RAM and peripherals +static ADDRESS_MAP_START( psxcpu_internal_map, AS_PROGRAM, 32, psxcpu_device ) + AM_RANGE( 0x1f800000, 0x1f8003ff ) AM_NOP /* scratchpad */ + AM_RANGE( 0x1f800400, 0x1f800fff ) AM_READWRITE( berr_r, berr_w ) + AM_RANGE( 0x1f801000, 0x1f801003 ) AM_READWRITE( exp_base_r, exp_base_w ) + AM_RANGE( 0x1f801004, 0x1f801007 ) AM_RAM + AM_RANGE( 0x1f801008, 0x1f80100b ) AM_READWRITE( exp_config_r, exp_config_w ) + AM_RANGE( 0x1f80100c, 0x1f80100f ) AM_RAM + AM_RANGE( 0x1f801010, 0x1f801013 ) AM_READWRITE( rom_config_r, rom_config_w ) + AM_RANGE( 0x1f801014, 0x1f80101f ) AM_RAM + /* 1f801014 spu delay */ + /* 1f801018 dv delay */ + AM_RANGE( 0x1f801020, 0x1f801023 ) AM_READWRITE( com_delay_r, com_delay_w ) + AM_RANGE( 0x1f801024, 0x1f80102f ) AM_RAM + AM_RANGE( 0x1f801040, 0x1f80104f ) AM_DEVREADWRITE( "sio0", psxsio_device, read, write ) + AM_RANGE( 0x1f801050, 0x1f80105f ) AM_DEVREADWRITE( "sio1", psxsio_device, read, write ) + AM_RANGE( 0x1f801060, 0x1f801063 ) AM_READWRITE( ram_config_r, ram_config_w ) + AM_RANGE( 0x1f801064, 0x1f80106f ) AM_RAM + AM_RANGE( 0x1f801070, 0x1f801077 ) AM_DEVREADWRITE( "irq", psxirq_device, read, write ) + AM_RANGE( 0x1f801080, 0x1f8010ff ) AM_DEVREADWRITE( "dma", psxdma_device, read, write ) + AM_RANGE( 0x1f801100, 0x1f80112f ) AM_DEVREADWRITE( "rcnt", psxrcnt_device, read, write ) + AM_RANGE( 0x1f801800, 0x1f801803 ) AM_READWRITE8( cd_r, cd_w, 0xffffffff ) + AM_RANGE( 0x1f801810, 0x1f801817 ) AM_READWRITE( gpu_r, gpu_w ) + AM_RANGE( 0x1f801820, 0x1f801827 ) AM_DEVREADWRITE( "mdec", psxmdec_device, read, write ) + AM_RANGE( 0x1f801c00, 0x1f801dff ) AM_READWRITE16( spu_r, spu_w, 0xffffffff ) + AM_RANGE( 0x1f802020, 0x1f802033 ) AM_RAM /* ?? */ + /* 1f802030 int 2000 */ + /* 1f802040 dip switches */ + AM_RANGE( 0x1f802040, 0x1f802043 ) AM_WRITENOP + AM_RANGE( 0x20000000, 0x7fffffff ) AM_READWRITE( berr_r, berr_w ) + AM_RANGE( 0xc0000000, 0xfffdffff ) AM_READWRITE( berr_r, berr_w ) + AM_RANGE( 0xfffe0130, 0xfffe0133 ) AM_READWRITE( biu_r, biu_w ) +ADDRESS_MAP_END + + +//************************************************************************** +// DEVICE INTERFACE +//************************************************************************** + +//------------------------------------------------- +// psxcpu_device - constructor +//------------------------------------------------- + +psxcpu_device::psxcpu_device( const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source ) : + cpu_device( mconfig, type, name, tag, owner, clock, shortname, source ), + m_program_config( "program", ENDIANNESS_LITTLE, 32, 32, 0, ADDRESS_MAP_NAME( psxcpu_internal_map ) ), + m_gpu_read_handler( *this ), + m_gpu_write_handler( *this ), + m_spu_read_handler( *this ), + m_spu_write_handler( *this ), + m_cd_read_handler( *this ), + m_cd_write_handler( *this ), + m_ram( *this, "ram" ) +{ + m_disable_rom_berr = false; +} + +cxd8530aq_device::cxd8530aq_device( const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock ) + : psxcpu_device( mconfig, CXD8661R, "CXD8530AQ", tag, owner, clock, "cxd8530aq", __FILE__ ) +{ +} + +cxd8530bq_device::cxd8530bq_device( const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock ) + : psxcpu_device( mconfig, CXD8661R, "CXD8530BQ", tag, owner, clock, "cxd8530bq", __FILE__ ) +{ +} + +cxd8530cq_device::cxd8530cq_device( const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock ) + : psxcpu_device( mconfig, CXD8661R, "CXD8530CQ", tag, owner, clock, "cxd8530cq", __FILE__ ) +{ +} + +cxd8661r_device::cxd8661r_device( const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock ) + : psxcpu_device( mconfig, CXD8661R, "CXD8661R", tag, owner, clock, "cxd8661r", __FILE__ ) +{ +} + +cxd8606bq_device::cxd8606bq_device( const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock ) + : psxcpu_device( mconfig, CXD8606BQ, "CXD8606BQ", tag, owner, clock, "cxd8606bq", __FILE__ ) +{ +} + +cxd8606cq_device::cxd8606cq_device( const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock ) + : psxcpu_device( mconfig, CXD8606CQ, "CXD8606CQ", tag, owner, clock, "cxd8606cq", __FILE__ ) +{ +} + +//------------------------------------------------- +// device_start - start up the device +//------------------------------------------------- + +void psxcpu_device::device_start() +{ + // get our address spaces + m_program = &space( AS_PROGRAM ); + m_direct = &m_program->direct(); + + save_item( NAME( m_op ) ); + save_item( NAME( m_pc ) ); + save_item( NAME( m_delayv ) ); + save_item( NAME( m_delayr ) ); + save_item( NAME( m_hi ) ); + save_item( NAME( m_lo ) ); + save_item( NAME( m_biu ) ); + save_item( NAME( m_r ) ); + save_item( NAME( m_cp0r ) ); + save_item( NAME( m_gte.m_cp2cr ) ); + save_item( NAME( m_gte.m_cp2dr ) ); + save_item( NAME( m_icacheTag ) ); + save_item( NAME( m_icache ) ); + save_item( NAME( m_dcache ) ); + save_item( NAME( m_multiplier_operation ) ); + save_item( NAME( m_multiplier_operand1 ) ); + save_item( NAME( m_multiplier_operand2 ) ); + + state_add( STATE_GENPC, "GENPC", m_pc ).noshow(); + state_add( PSXCPU_PC, "pc", m_pc ); + state_add( PSXCPU_DELAYR, "delayr", m_delayr ).formatstr("%8s"); + state_add( PSXCPU_DELAYV, "delayv", m_delayv ); + state_add( PSXCPU_HI, "hi", m_hi ); + state_add( PSXCPU_LO, "lo", m_lo ); + state_add( PSXCPU_BIU, "biu", m_biu ); + state_add( PSXCPU_R0, "zero", m_r[ 0 ] ); + state_add( PSXCPU_R1, "at", m_r[ 1 ] ); + state_add( PSXCPU_R2, "v0", m_r[ 2 ] ); + state_add( PSXCPU_R3, "v1", m_r[ 3 ] ); + state_add( PSXCPU_R4, "a0", m_r[ 4 ] ); + state_add( PSXCPU_R5, "a1", m_r[ 5 ] ); + state_add( PSXCPU_R6, "a2", m_r[ 6 ] ); + state_add( PSXCPU_R7, "a3", m_r[ 7 ] ); + state_add( PSXCPU_R8, "t0", m_r[ 8 ] ); + state_add( PSXCPU_R9, "t1", m_r[ 9 ] ); + state_add( PSXCPU_R10, "t2", m_r[ 10 ] ); + state_add( PSXCPU_R11, "t3", m_r[ 11 ] ); + state_add( PSXCPU_R12, "t4", m_r[ 12 ] ); + state_add( PSXCPU_R13, "t5", m_r[ 13 ] ); + state_add( PSXCPU_R14, "t6", m_r[ 14 ] ); + state_add( PSXCPU_R15, "t7", m_r[ 15 ] ); + state_add( PSXCPU_R16, "s0", m_r[ 16 ] ); + state_add( PSXCPU_R17, "s1", m_r[ 17 ] ); + state_add( PSXCPU_R18, "s2", m_r[ 18 ] ); + state_add( PSXCPU_R19, "s3", m_r[ 19 ] ); + state_add( PSXCPU_R20, "s4", m_r[ 20 ] ); + state_add( PSXCPU_R21, "s5", m_r[ 21 ] ); + state_add( PSXCPU_R22, "s6", m_r[ 22 ] ); + state_add( PSXCPU_R23, "s7", m_r[ 23 ] ); + state_add( PSXCPU_R24, "t8", m_r[ 24 ] ); + state_add( PSXCPU_R25, "t9", m_r[ 25 ] ); + state_add( PSXCPU_R26, "k0", m_r[ 26 ] ); + state_add( PSXCPU_R27, "k1", m_r[ 27 ] ); + state_add( PSXCPU_R28, "gp", m_r[ 28 ] ); + state_add( PSXCPU_R29, "sp", m_r[ 29 ] ); + state_add( PSXCPU_R30, "fp", m_r[ 30 ] ); + state_add( PSXCPU_R31, "ra", m_r[ 31 ] ); + state_add( PSXCPU_CP0R0, "!Index", m_cp0r[ 0 ] ); + state_add( PSXCPU_CP0R1, "!Random", m_cp0r[ 1 ] ); + state_add( PSXCPU_CP0R2, "!EntryLo", m_cp0r[ 2 ] ); + state_add( PSXCPU_CP0R3, "BPC", m_cp0r[ 3 ] ); + state_add( PSXCPU_CP0R4, "!Context", m_cp0r[ 4 ] ); + state_add( PSXCPU_CP0R5, "BDA", m_cp0r[ 5 ] ); + state_add( PSXCPU_CP0R6, "TAR", m_cp0r[ 6 ] ); + state_add( PSXCPU_CP0R7, "DCIC", m_cp0r[ 7 ] ); + state_add( PSXCPU_CP0R8, "BadA", m_cp0r[ 8 ] ); + state_add( PSXCPU_CP0R9, "BDAM", m_cp0r[ 9 ] ); + state_add( PSXCPU_CP0R10, "!EntryHi", m_cp0r[ 10 ] ); + state_add( PSXCPU_CP0R11, "BPCM", m_cp0r[ 11 ] ); + state_add( PSXCPU_CP0R12, "SR", m_cp0r[ 12 ] ).callimport(); + state_add( PSXCPU_CP0R13, "Cause", m_cp0r[ 13 ] ).callimport(); + state_add( PSXCPU_CP0R14, "EPC", m_cp0r[ 14 ] ); + state_add( PSXCPU_CP0R15, "PRId", m_cp0r[ 15 ] ); + state_add( PSXCPU_CP2DR0, "vxy0", m_gte.m_cp2dr[ 0 ].d ); + state_add( PSXCPU_CP2DR1, "vz0", m_gte.m_cp2dr[ 1 ].d ); + state_add( PSXCPU_CP2DR2, "vxy1", m_gte.m_cp2dr[ 2 ].d ); + state_add( PSXCPU_CP2DR3, "vz1", m_gte.m_cp2dr[ 3 ].d ); + state_add( PSXCPU_CP2DR4, "vxy2", m_gte.m_cp2dr[ 4 ].d ); + state_add( PSXCPU_CP2DR5, "vz2", m_gte.m_cp2dr[ 5 ].d ); + state_add( PSXCPU_CP2DR6, "rgb", m_gte.m_cp2dr[ 6 ].d ); + state_add( PSXCPU_CP2DR7, "otz", m_gte.m_cp2dr[ 7 ].d ); + state_add( PSXCPU_CP2DR8, "ir0", m_gte.m_cp2dr[ 8 ].d ); + state_add( PSXCPU_CP2DR9, "ir1", m_gte.m_cp2dr[ 9 ].d ); + state_add( PSXCPU_CP2DR10, "ir2", m_gte.m_cp2dr[ 10 ].d ); + state_add( PSXCPU_CP2DR11, "ir3", m_gte.m_cp2dr[ 11 ].d ); + state_add( PSXCPU_CP2DR12, "sxy0", m_gte.m_cp2dr[ 12 ].d ); + state_add( PSXCPU_CP2DR13, "sxy1", m_gte.m_cp2dr[ 13 ].d ); + state_add( PSXCPU_CP2DR14, "sxy2", m_gte.m_cp2dr[ 14 ].d ); + state_add( PSXCPU_CP2DR15, "sxyp", m_gte.m_cp2dr[ 15 ].d ); + state_add( PSXCPU_CP2DR16, "sz0", m_gte.m_cp2dr[ 16 ].d ); + state_add( PSXCPU_CP2DR17, "sz1", m_gte.m_cp2dr[ 17 ].d ); + state_add( PSXCPU_CP2DR18, "sz2", m_gte.m_cp2dr[ 18 ].d ); + state_add( PSXCPU_CP2DR19, "sz3", m_gte.m_cp2dr[ 19 ].d ); + state_add( PSXCPU_CP2DR20, "rgb0", m_gte.m_cp2dr[ 20 ].d ); + state_add( PSXCPU_CP2DR21, "rgb1", m_gte.m_cp2dr[ 21 ].d ); + state_add( PSXCPU_CP2DR22, "rgb2", m_gte.m_cp2dr[ 22 ].d ); + state_add( PSXCPU_CP2DR23, "res1", m_gte.m_cp2dr[ 23 ].d ); + state_add( PSXCPU_CP2DR24, "mac0", m_gte.m_cp2dr[ 24 ].d ); + state_add( PSXCPU_CP2DR25, "mac1", m_gte.m_cp2dr[ 25 ].d ); + state_add( PSXCPU_CP2DR26, "mac2", m_gte.m_cp2dr[ 26 ].d ); + state_add( PSXCPU_CP2DR27, "mac3", m_gte.m_cp2dr[ 27 ].d ); + state_add( PSXCPU_CP2DR28, "irgb", m_gte.m_cp2dr[ 28 ].d ); + state_add( PSXCPU_CP2DR29, "orgb", m_gte.m_cp2dr[ 29 ].d ); + state_add( PSXCPU_CP2DR30, "lzcs", m_gte.m_cp2dr[ 30 ].d ); + state_add( PSXCPU_CP2DR31, "lzcr", m_gte.m_cp2dr[ 31 ].d ); + state_add( PSXCPU_CP2CR0, "r11r12", m_gte.m_cp2cr[ 0 ].d ); + state_add( PSXCPU_CP2CR1, "r13r21", m_gte.m_cp2cr[ 1 ].d ); + state_add( PSXCPU_CP2CR2, "r22r23", m_gte.m_cp2cr[ 2 ].d ); + state_add( PSXCPU_CP2CR3, "r31r32", m_gte.m_cp2cr[ 3 ].d ); + state_add( PSXCPU_CP2CR4, "r33", m_gte.m_cp2cr[ 4 ].d ); + state_add( PSXCPU_CP2CR5, "trx", m_gte.m_cp2cr[ 5 ].d ); + state_add( PSXCPU_CP2CR6, "try", m_gte.m_cp2cr[ 6 ].d ); + state_add( PSXCPU_CP2CR7, "trz", m_gte.m_cp2cr[ 7 ].d ); + state_add( PSXCPU_CP2CR8, "l11l12", m_gte.m_cp2cr[ 8 ].d ); + state_add( PSXCPU_CP2CR9, "l13l21", m_gte.m_cp2cr[ 9 ].d ); + state_add( PSXCPU_CP2CR10, "l22l23", m_gte.m_cp2cr[ 10 ].d ); + state_add( PSXCPU_CP2CR11, "l31l32", m_gte.m_cp2cr[ 11 ].d ); + state_add( PSXCPU_CP2CR12, "l33", m_gte.m_cp2cr[ 12 ].d ); + state_add( PSXCPU_CP2CR13, "rbk", m_gte.m_cp2cr[ 13 ].d ); + state_add( PSXCPU_CP2CR14, "gbk", m_gte.m_cp2cr[ 14 ].d ); + state_add( PSXCPU_CP2CR15, "bbk", m_gte.m_cp2cr[ 15 ].d ); + state_add( PSXCPU_CP2CR16, "lr1lr2", m_gte.m_cp2cr[ 16 ].d ); + state_add( PSXCPU_CP2CR17, "lr31g1", m_gte.m_cp2cr[ 17 ].d ); + state_add( PSXCPU_CP2CR18, "lg2lg3", m_gte.m_cp2cr[ 18 ].d ); + state_add( PSXCPU_CP2CR19, "lb1lb2", m_gte.m_cp2cr[ 19 ].d ); + state_add( PSXCPU_CP2CR20, "lb3", m_gte.m_cp2cr[ 20 ].d ); + state_add( PSXCPU_CP2CR21, "rfc", m_gte.m_cp2cr[ 21 ].d ); + state_add( PSXCPU_CP2CR22, "gfc", m_gte.m_cp2cr[ 22 ].d ); + state_add( PSXCPU_CP2CR23, "bfc", m_gte.m_cp2cr[ 23 ].d ); + state_add( PSXCPU_CP2CR24, "ofx", m_gte.m_cp2cr[ 24 ].d ); + state_add( PSXCPU_CP2CR25, "ofy", m_gte.m_cp2cr[ 25 ].d ); + state_add( PSXCPU_CP2CR26, "h", m_gte.m_cp2cr[ 26 ].d ); + state_add( PSXCPU_CP2CR27, "dqa", m_gte.m_cp2cr[ 27 ].d ); + state_add( PSXCPU_CP2CR28, "dqb", m_gte.m_cp2cr[ 28 ].d ); + state_add( PSXCPU_CP2CR29, "zsf3", m_gte.m_cp2cr[ 29 ].d ); + state_add( PSXCPU_CP2CR30, "zsf4", m_gte.m_cp2cr[ 30 ].d ); + state_add( PSXCPU_CP2CR31, "flag", m_gte.m_cp2cr[ 31 ].d ); + + // set our instruction counter + m_icountptr = &m_icount; + + m_gpu_read_handler.resolve_safe( 0 ); + m_gpu_write_handler.resolve_safe(); + m_spu_read_handler.resolve_safe( 0 ); + m_spu_write_handler.resolve_safe(); + m_cd_read_handler.resolve_safe( 0 ); + m_cd_write_handler.resolve_safe(); + + m_rom = memregion( "rom" ); +} + + +//------------------------------------------------- +// device_reset - reset the device +//------------------------------------------------- + +void psxcpu_device::device_reset() +{ + m_ram_config = 0x800; + update_ram_config(); + + m_rom_config = 0x00130000; + update_rom_config(); + + /// TODO: get dma to access ram through the memory map? + psxdma_device *psxdma = subdevice( "dma" ); + psxdma->m_ram = (UINT32 *)m_ram->pointer(); + psxdma->m_ramsize = m_ram->size(); + + m_delayr = 0; + m_delayv = 0; + m_berr = 0; + m_biu = 0; + + m_multiplier_operation = MULTIPLIER_OPERATION_IDLE; + + m_r[ 0 ] = 0; + + m_cp0r[ CP0_SR ] = SR_BEV; + m_cp0r[ CP0_CAUSE ] = 0x00000000; + m_cp0r[ CP0_PRID ] = 0x00000002; + m_cp0r[ CP0_DCIC ] = 0x00000000; + m_cp0r[ CP0_BPCM ] = 0xffffffff; + m_cp0r[ CP0_BDAM ] = 0xffffffff; + + update_memory_handlers(); + update_address_masks(); + update_scratchpad(); + + set_pc( 0xbfc00000 ); +} + + +//------------------------------------------------- +// device_post_load - device-specific post-load +//------------------------------------------------- + +void psxcpu_device::device_post_load() +{ + update_memory_handlers(); + update_address_masks(); + update_scratchpad(); +} + + +//------------------------------------------------- +// state_import - import state into the device, +// after it has been set +//------------------------------------------------- + +void psxcpu_device::state_import( const device_state_entry &entry ) +{ + switch( entry.index() ) + { + case PSXCPU_CP0R12: // SR + case PSXCPU_CP0R13: // CAUSE + update_cop0( entry.index() - PSXCPU_CP0R0 ); + break; + } +} + + +//------------------------------------------------- +// state_string_export - export state as a string +// for the debugger +//------------------------------------------------- + +void psxcpu_device::state_string_export( const device_state_entry &entry, std::string &str ) +{ + switch( entry.index() ) + { + case PSXCPU_DELAYR: + if( m_delayr <= PSXCPU_DELAYR_NOTPC ) + { + strprintf(str, "%02x %-3s", m_delayr, delayn[m_delayr]); + } + else + { + strprintf(str, "%02x ---", m_delayr); + } + break; + } +} + + +//------------------------------------------------- +// disasm_disassemble - call the disassembly +// helper function +//------------------------------------------------- + +offs_t psxcpu_device::disasm_disassemble( char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options ) +{ + return DasmPSXCPU( this, buffer, pc, opram ); +} + + +UINT32 psxcpu_device::get_register_from_pipeline( int reg ) +{ + if( m_delayr == reg ) + { + return m_delayv; + } + + return m_r[ reg ]; +} + +int psxcpu_device::cop0_usable() +{ + if( ( m_cp0r[ CP0_SR ] & SR_KUC ) != 0 && ( m_cp0r[ CP0_SR ] & SR_CU0 ) == 0 ) + { + exception( EXC_CPU ); + + return 0; + } + + return 1; +} + +void psxcpu_device::lwc( int cop, int sr_cu ) +{ + UINT32 address = m_r[ INS_RS( m_op ) ] + PSXCPU_WORD_EXTEND( INS_IMMEDIATE( m_op ) ); + int breakpoint = load_data_address_breakpoint( address ); + + if( ( m_cp0r[ CP0_SR ] & sr_cu ) == 0 ) + { + exception( EXC_CPU ); + } + else if( ( address & m_bad_word_address_mask ) != 0 ) + { + load_bad_address( address ); + } + else if( breakpoint ) + { + breakpoint_exception(); + } + else + { + UINT32 data = readword( address ); + + if( m_berr ) + { + load_bus_error_exception(); + } + else + { + int reg = INS_RT( m_op ); + + advance_pc(); + + switch( cop ) + { + case 0: + /* lwc0 doesn't update any cop0 registers */ + break; + + case 1: + setcp1dr( reg, data ); + break; + + case 2: + m_gte.setcp2dr( m_pc, reg, data ); + break; + + case 3: + setcp3dr( reg, data ); + break; + } + } + } +} + +void psxcpu_device::swc( int cop, int sr_cu ) +{ + UINT32 address = m_r[ INS_RS( m_op ) ] + PSXCPU_WORD_EXTEND( INS_IMMEDIATE( m_op ) ); + int breakpoint = store_data_address_breakpoint( address ); + + if( ( m_cp0r[ CP0_SR ] & sr_cu ) == 0 ) + { + exception( EXC_CPU ); + } + else if( ( address & m_bad_word_address_mask ) != 0 ) + { + store_bad_address( address ); + } + else + { + UINT32 data = 0; + + switch( cop ) + { + case 0: + { + int address; + + if( m_delayr == PSXCPU_DELAYR_PC ) + { + switch( m_delayv & 0x0c ) + { + case 0x0c: + address = m_delayv; + break; + + default: + address = m_delayv + 4; + break; + } + } + else + { + switch( m_pc & 0x0c ) + { + case 0x0: + case 0xc: + address = m_pc + 0x08; + break; + + default: + address = m_pc | 0x0c; + break; + } + } + + data = m_program->read_dword( address ); + } + break; + + case 1: + data = getcp1dr( INS_RT( m_op ) ); + break; + + case 2: + data = m_gte.getcp2dr( m_pc, INS_RT( m_op ) ); + break; + + case 3: + data = getcp3dr( INS_RT( m_op ) ); + break; + } + + writeword( address, data ); + + if( breakpoint ) + { + breakpoint_exception(); + } + else if( m_berr ) + { + store_bus_error_exception(); + } + else + { + advance_pc(); + } + } +} + +void psxcpu_device::bc( int cop, int sr_cu, int condition ) +{ + if( ( m_cp0r[ CP0_SR ] & sr_cu ) == 0 ) + { + exception( EXC_CPU ); + } + else + { + conditional_branch( !condition ); + } +} + + + +/*************************************************************************** + CORE EXECUTION LOOP +***************************************************************************/ + + +void psxcpu_device::execute_set_input( int inputnum, int state ) +{ + UINT32 ip; + + switch( inputnum ) + { + case PSXCPU_IRQ0: + ip = CAUSE_IP2; + break; + + case PSXCPU_IRQ1: + ip = CAUSE_IP3; + break; + + case PSXCPU_IRQ2: + ip = CAUSE_IP4; + break; + + case PSXCPU_IRQ3: + ip = CAUSE_IP5; + break; + + case PSXCPU_IRQ4: + ip = CAUSE_IP6; + break; + + case PSXCPU_IRQ5: + ip = CAUSE_IP7; + break; + + default: + return; + } + + switch( state ) + { + case CLEAR_LINE: + m_cp0r[ CP0_CAUSE ] &= ~ip; + break; + + case ASSERT_LINE: + m_cp0r[ CP0_CAUSE ] |= ip; + break; + } + + update_cop0( CP0_CAUSE ); +} + + +void psxcpu_device::execute_run() +{ + do + { + if( LOG_BIOSCALL ) log_bioscall(); + debugger_instruction_hook( this, m_pc ); + + m_op = m_direct->read_dword( m_pc ); + + if( m_berr ) + { + fetch_bus_error_exception(); + } + else + { + switch( INS_OP( m_op ) ) + { + case OP_SPECIAL: + switch( INS_FUNCT( m_op ) ) + { + case FUNCT_SLL: + load( INS_RD( m_op ), m_r[ INS_RT( m_op ) ] << INS_SHAMT( m_op ) ); + break; + + case FUNCT_SRL: + load( INS_RD( m_op ), m_r[ INS_RT( m_op ) ] >> INS_SHAMT( m_op ) ); + break; + + case FUNCT_SRA: + load( INS_RD( m_op ), (INT32)m_r[ INS_RT( m_op ) ] >> INS_SHAMT( m_op ) ); + break; + + case FUNCT_SLLV: + load( INS_RD( m_op ), m_r[ INS_RT( m_op ) ] << ( m_r[ INS_RS( m_op ) ] & 31 ) ); + break; + + case FUNCT_SRLV: + load( INS_RD( m_op ), m_r[ INS_RT( m_op ) ] >> ( m_r[ INS_RS( m_op ) ] & 31 ) ); + break; + + case FUNCT_SRAV: + load( INS_RD( m_op ), (INT32)m_r[ INS_RT( m_op ) ] >> ( m_r[ INS_RS( m_op ) ] & 31 ) ); + break; + + case FUNCT_JR: + branch( m_r[ INS_RS( m_op ) ] ); + break; + + case FUNCT_JALR: + branch( m_r[ INS_RS( m_op ) ] ); + if( INS_RD( m_op ) != 0 ) + { + m_r[ INS_RD( m_op ) ] = m_pc + 4; + } + break; + + case FUNCT_SYSCALL: + if( LOG_BIOSCALL ) log_syscall(); + exception( EXC_SYS ); + break; + + case FUNCT_BREAK: + exception( EXC_BP ); + break; + + case FUNCT_MFHI: + load( INS_RD( m_op ), get_hi() ); + break; + + case FUNCT_MTHI: + funct_mthi(); + advance_pc(); + break; + + case FUNCT_MFLO: + load( INS_RD( m_op ), get_lo() ); + break; + + case FUNCT_MTLO: + funct_mtlo(); + advance_pc(); + break; + + case FUNCT_MULT: + funct_mult(); + advance_pc(); + break; + + case FUNCT_MULTU: + funct_multu(); + advance_pc(); + break; + + case FUNCT_DIV: + funct_div(); + advance_pc(); + break; + + case FUNCT_DIVU: + funct_divu(); + advance_pc(); + break; + + case FUNCT_ADD: + { + UINT32 result = m_r[ INS_RS( m_op ) ] + m_r[ INS_RT( m_op ) ]; + if( (INT32)( ~( m_r[ INS_RS( m_op ) ] ^ m_r[ INS_RT( m_op ) ] ) & ( m_r[ INS_RS( m_op ) ] ^ result ) ) < 0 ) + { + exception( EXC_OVF ); + } + else + { + load( INS_RD( m_op ), result ); + } + } + break; + + case FUNCT_ADDU: + load( INS_RD( m_op ), m_r[ INS_RS( m_op ) ] + m_r[ INS_RT( m_op ) ] ); + break; + + case FUNCT_SUB: + { + UINT32 result = m_r[ INS_RS( m_op ) ] - m_r[ INS_RT( m_op ) ]; + if( (INT32)( ( m_r[ INS_RS( m_op ) ] ^ m_r[ INS_RT( m_op ) ] ) & ( m_r[ INS_RS( m_op ) ] ^ result ) ) < 0 ) + { + exception( EXC_OVF ); + } + else + { + load( INS_RD( m_op ), result ); + } + } + break; + + case FUNCT_SUBU: + load( INS_RD( m_op ), m_r[ INS_RS( m_op ) ] - m_r[ INS_RT( m_op ) ] ); + break; + + case FUNCT_AND: + load( INS_RD( m_op ), m_r[ INS_RS( m_op ) ] & m_r[ INS_RT( m_op ) ] ); + break; + + case FUNCT_OR: + load( INS_RD( m_op ), m_r[ INS_RS( m_op ) ] | m_r[ INS_RT( m_op ) ] ); + break; + + case FUNCT_XOR: + load( INS_RD( m_op ), m_r[ INS_RS( m_op ) ] ^ m_r[ INS_RT( m_op ) ] ); + break; + + case FUNCT_NOR: + load( INS_RD( m_op ), ~( m_r[ INS_RS( m_op ) ] | m_r[ INS_RT( m_op ) ] ) ); + break; + + case FUNCT_SLT: + load( INS_RD( m_op ), (INT32)m_r[ INS_RS( m_op ) ] < (INT32)m_r[ INS_RT( m_op ) ] ); + break; + + case FUNCT_SLTU: + load( INS_RD( m_op ), m_r[ INS_RS( m_op ) ] < m_r[ INS_RT( m_op ) ] ); + break; + + default: + exception( EXC_RI ); + break; + } + break; + + case OP_REGIMM: + switch( INS_RT_REGIMM( m_op ) ) + { + case RT_BLTZ: + conditional_branch( (INT32)m_r[ INS_RS( m_op ) ] < 0 ); + + if( INS_RT( m_op ) == RT_BLTZAL ) + { + m_r[ 31 ] = m_pc + 4; + } + break; + + case RT_BGEZ: + conditional_branch( (INT32)m_r[ INS_RS( m_op ) ] >= 0 ); + + if( INS_RT( m_op ) == RT_BGEZAL ) + { + m_r[ 31 ] = m_pc + 4; + } + break; + } + break; + + case OP_J: + unconditional_branch(); + break; + + case OP_JAL: + unconditional_branch(); + m_r[ 31 ] = m_pc + 4; + break; + + case OP_BEQ: + conditional_branch( m_r[ INS_RS( m_op ) ] == m_r[ INS_RT( m_op ) ] ); + break; + + case OP_BNE: + conditional_branch( m_r[ INS_RS( m_op ) ] != m_r[ INS_RT( m_op ) ] ); + break; + + case OP_BLEZ: + conditional_branch( (INT32)m_r[ INS_RS( m_op ) ] < 0 || m_r[ INS_RS( m_op ) ] == m_r[ INS_RT( m_op ) ] ); + break; + + case OP_BGTZ: + conditional_branch( (INT32)m_r[ INS_RS( m_op ) ] >= 0 && m_r[ INS_RS( m_op ) ] != m_r[ INS_RT( m_op ) ] ); + break; + + case OP_ADDI: + { + UINT32 immediate = PSXCPU_WORD_EXTEND( INS_IMMEDIATE( m_op ) ); + UINT32 result = m_r[ INS_RS( m_op ) ] + immediate; + if( (INT32)( ~( m_r[ INS_RS( m_op ) ] ^ immediate ) & ( m_r[ INS_RS( m_op ) ] ^ result ) ) < 0 ) + { + exception( EXC_OVF ); + } + else + { + load( INS_RT( m_op ), result ); + } + } + break; + + case OP_ADDIU: + load( INS_RT( m_op ), m_r[ INS_RS( m_op ) ] + PSXCPU_WORD_EXTEND( INS_IMMEDIATE( m_op ) ) ); + break; + + case OP_SLTI: + load( INS_RT( m_op ), (INT32)m_r[ INS_RS( m_op ) ] < PSXCPU_WORD_EXTEND( INS_IMMEDIATE( m_op ) ) ); + break; + + case OP_SLTIU: + load( INS_RT( m_op ), m_r[ INS_RS( m_op ) ] < (UINT32)PSXCPU_WORD_EXTEND( INS_IMMEDIATE( m_op ) ) ); + break; + + case OP_ANDI: + load( INS_RT( m_op ), m_r[ INS_RS( m_op ) ] & INS_IMMEDIATE( m_op ) ); + break; + + case OP_ORI: + load( INS_RT( m_op ), m_r[ INS_RS( m_op ) ] | INS_IMMEDIATE( m_op ) ); + break; + + case OP_XORI: + load( INS_RT( m_op ), m_r[ INS_RS( m_op ) ] ^ INS_IMMEDIATE( m_op ) ); + break; + + case OP_LUI: + load( INS_RT( m_op ), INS_IMMEDIATE( m_op ) << 16 ); + break; + + case OP_COP0: + switch( INS_RS( m_op ) ) + { + case RS_MFC: + { + int reg = INS_RD( m_op ); + + if( reg == CP0_INDEX || + reg == CP0_RANDOM || + reg == CP0_ENTRYLO || + reg == CP0_CONTEXT || + reg == CP0_ENTRYHI ) + { + exception( EXC_RI ); + } + else if( reg < 16 ) + { + if( cop0_usable() ) + { + delayed_load( INS_RT( m_op ), m_cp0r[ reg ] ); + } + } + else + { + advance_pc(); + } + } + break; + + case RS_CFC: + exception( EXC_RI ); + break; + + case RS_MTC: + { + int reg = INS_RD( m_op ); + + if( reg == CP0_INDEX || + reg == CP0_RANDOM || + reg == CP0_ENTRYLO || + reg == CP0_CONTEXT || + reg == CP0_ENTRYHI ) + { + exception( EXC_RI ); + } + else if( reg < 16 ) + { + if( cop0_usable() ) + { + UINT32 data = ( m_cp0r[ reg ] & ~mtc0_writemask[ reg ] ) | + ( m_r[ INS_RT( m_op ) ] & mtc0_writemask[ reg ] ); + advance_pc(); + + m_cp0r[ reg ] = data; + update_cop0( reg ); + } + } + else + { + advance_pc(); + } + } + break; + + case RS_CTC: + exception( EXC_RI ); + break; + + case RS_BC: + case RS_BC_ALT: + switch( INS_BC( m_op ) ) + { + case BC_BCF: + bc( 0, SR_CU0, 0 ); + break; + + case BC_BCT: + bc( 0, SR_CU0, 1 ); + break; + } + break; + + default: + switch( INS_CO( m_op ) ) + { + case 1: + switch( INS_CF( m_op ) ) + { + case CF_TLBR: + case CF_TLBWI: + case CF_TLBWR: + case CF_TLBP: + exception( EXC_RI ); + break; + + case CF_RFE: + if( cop0_usable() ) + { + advance_pc(); + m_cp0r[ CP0_SR ] = ( m_cp0r[ CP0_SR ] & ~0xf ) | ( ( m_cp0r[ CP0_SR ] >> 2 ) & 0xf ); + update_cop0( CP0_SR ); + } + break; + + default: + advance_pc(); + break; + } + break; + + default: + advance_pc(); + break; + } + break; + } + break; + + case OP_COP1: + if( ( m_cp0r[ CP0_SR ] & SR_CU1 ) == 0 ) + { + exception( EXC_CPU ); + } + else + { + switch( INS_RS( m_op ) ) + { + case RS_MFC: + delayed_load( INS_RT( m_op ), getcp1dr( INS_RD( m_op ) ) ); + break; + + case RS_CFC: + delayed_load( INS_RT( m_op ), getcp1cr( INS_RD( m_op ) ) ); + break; + + case RS_MTC: + setcp1dr( INS_RD( m_op ), m_r[ INS_RT( m_op ) ] ); + advance_pc(); + break; + + case RS_CTC: + setcp1cr( INS_RD( m_op ), m_r[ INS_RT( m_op ) ] ); + advance_pc(); + break; + + case RS_BC: + case RS_BC_ALT: + switch( INS_BC( m_op ) ) + { + case BC_BCF: + bc( 1, SR_CU1, 0 ); + break; + + case BC_BCT: + bc( 1, SR_CU1, 1 ); + break; + } + break; + + default: + advance_pc(); + break; + } + } + break; + + case OP_COP2: + if( ( m_cp0r[ CP0_SR ] & SR_CU2 ) == 0 ) + { + exception( EXC_CPU ); + } + else + { + switch( INS_RS( m_op ) ) + { + case RS_MFC: + delayed_load( INS_RT( m_op ), m_gte.getcp2dr( m_pc, INS_RD( m_op ) ) ); + break; + + case RS_CFC: + delayed_load( INS_RT( m_op ), m_gte.getcp2cr( m_pc, INS_RD( m_op ) ) ); + break; + + case RS_MTC: + m_gte.setcp2dr( m_pc, INS_RD( m_op ), m_r[ INS_RT( m_op ) ] ); + advance_pc(); + break; + + case RS_CTC: + m_gte.setcp2cr( m_pc, INS_RD( m_op ), m_r[ INS_RT( m_op ) ] ); + advance_pc(); + break; + + case RS_BC: + case RS_BC_ALT: + switch( INS_BC( m_op ) ) + { + case BC_BCF: + bc( 2, SR_CU2, 0 ); + break; + + case BC_BCT: + bc( 2, SR_CU2, 1 ); + break; + } + break; + + default: + switch( INS_CO( m_op ) ) + { + case 1: + if( !m_gte.docop2( m_pc, INS_COFUN( m_op ) ) ) + { + stop(); + } + + advance_pc(); + break; + + default: + advance_pc(); + break; + } + break; + } + } + break; + + case OP_COP3: + if( ( m_cp0r[ CP0_SR ] & SR_CU3 ) == 0 ) + { + exception( EXC_CPU ); + } + else + { + switch( INS_RS( m_op ) ) + { + case RS_MFC: + delayed_load( INS_RT( m_op ), getcp3dr( INS_RD( m_op ) ) ); + break; + + case RS_CFC: + delayed_load( INS_RT( m_op ), getcp3cr( INS_RD( m_op ) ) ); + break; + + case RS_MTC: + setcp3dr( INS_RD( m_op ), m_r[ INS_RT( m_op ) ] ); + advance_pc(); + break; + + case RS_CTC: + setcp3cr( INS_RD( m_op ), m_r[ INS_RT( m_op ) ] ); + advance_pc(); + break; + + case RS_BC: + case RS_BC_ALT: + switch( INS_BC( m_op ) ) + { + case BC_BCF: + bc( 3, SR_CU3, 0 ); + break; + + case BC_BCT: + bc( 3, SR_CU3, 1 ); + break; + } + break; + + default: + advance_pc(); + break; + } + } + break; + + case OP_LB: + { + UINT32 address = m_r[ INS_RS( m_op ) ] + PSXCPU_WORD_EXTEND( INS_IMMEDIATE( m_op ) ); + int breakpoint = load_data_address_breakpoint( address ); + + if( ( address & m_bad_byte_address_mask ) != 0 ) + { + load_bad_address( address ); + } + else if( breakpoint ) + { + breakpoint_exception(); + } + else + { + UINT32 data = PSXCPU_BYTE_EXTEND( readbyte( address ) ); + + if( m_berr ) + { + load_bus_error_exception(); + } + else + { + delayed_load( INS_RT( m_op ), data ); + } + } + } + break; + + case OP_LH: + { + UINT32 address = m_r[ INS_RS( m_op ) ] + PSXCPU_WORD_EXTEND( INS_IMMEDIATE( m_op ) ); + int breakpoint = load_data_address_breakpoint( address ); + + if( ( address & m_bad_half_address_mask ) != 0 ) + { + load_bad_address( address ); + } + else if( breakpoint ) + { + breakpoint_exception(); + } + else + { + UINT32 data = PSXCPU_WORD_EXTEND( readhalf( address ) ); + + if( m_berr ) + { + load_bus_error_exception(); + } + else + { + delayed_load( INS_RT( m_op ), data ); + } + } + } + break; + + case OP_LWL: + { + UINT32 address = m_r[ INS_RS( m_op ) ] + PSXCPU_WORD_EXTEND( INS_IMMEDIATE( m_op ) ); + int load_type = address & 3; + int breakpoint; + + address &= ~3; + breakpoint = load_data_address_breakpoint( address ); + + if( ( address & m_bad_byte_address_mask ) != 0 ) + { + load_bad_address( address ); + } + else if( breakpoint ) + { + breakpoint_exception(); + } + else + { + UINT32 data = get_register_from_pipeline( INS_RT( m_op ) ); + + switch( load_type ) + { + case 0: + data = ( data & 0x00ffffff ) | ( readword_masked( address, 0x000000ff ) << 24 ); + break; + + case 1: + data = ( data & 0x0000ffff ) | ( readword_masked( address, 0x0000ffff ) << 16 ); + break; + + case 2: + data = ( data & 0x000000ff ) | ( readword_masked( address, 0x00ffffff ) << 8 ); + break; + + case 3: + data = readword( address ); + break; + } + + if( m_berr ) + { + load_bus_error_exception(); + } + else + { + delayed_load( INS_RT( m_op ), data ); + } + } + } + break; + + case OP_LW: + { + UINT32 address = m_r[ INS_RS( m_op ) ] + PSXCPU_WORD_EXTEND( INS_IMMEDIATE( m_op ) ); + int breakpoint = load_data_address_breakpoint( address ); + + if( ( address & m_bad_word_address_mask ) != 0 ) + { + load_bad_address( address ); + } + else if( breakpoint ) + { + breakpoint_exception(); + } + else + { + UINT32 data = readword( address ); + + if( m_berr ) + { + load_bus_error_exception(); + } + else + { + delayed_load( INS_RT( m_op ), data ); + } + } + } + break; + + case OP_LBU: + { + UINT32 address = m_r[ INS_RS( m_op ) ] + PSXCPU_WORD_EXTEND( INS_IMMEDIATE( m_op ) ); + int breakpoint = load_data_address_breakpoint( address ); + + if( ( address & m_bad_byte_address_mask ) != 0 ) + { + load_bad_address( address ); + } + else if( breakpoint ) + { + breakpoint_exception(); + } + else + { + UINT32 data = readbyte( address ); + + if( m_berr ) + { + load_bus_error_exception(); + } + else + { + delayed_load( INS_RT( m_op ), data ); + } + } + } + break; + + case OP_LHU: + { + UINT32 address = m_r[ INS_RS( m_op ) ] + PSXCPU_WORD_EXTEND( INS_IMMEDIATE( m_op ) ); + int breakpoint = load_data_address_breakpoint( address ); + + if( ( address & m_bad_half_address_mask ) != 0 ) + { + load_bad_address( address ); + } + else if( breakpoint ) + { + breakpoint_exception(); + } + else + { + UINT32 data = readhalf( address ); + + if( m_berr ) + { + load_bus_error_exception(); + } + else + { + delayed_load( INS_RT( m_op ), data ); + } + } + } + break; + + case OP_LWR: + { + UINT32 address = m_r[ INS_RS( m_op ) ] + PSXCPU_WORD_EXTEND( INS_IMMEDIATE( m_op ) ); + int breakpoint = load_data_address_breakpoint( address ); + + if( ( address & m_bad_byte_address_mask ) != 0 ) + { + load_bad_address( address ); + } + else if( breakpoint ) + { + breakpoint_exception(); + } + else + { + UINT32 data = get_register_from_pipeline( INS_RT( m_op ) ); + + switch( address & 3 ) + { + case 0: + data = readword( address ); + break; + + case 1: + data = ( data & 0xff000000 ) | ( readword_masked( address, 0xffffff00 ) >> 8 ); + break; + + case 2: + data = ( data & 0xffff0000 ) | ( readword_masked( address, 0xffff0000 ) >> 16 ); + break; + + case 3: + data = ( data & 0xffffff00 ) | ( readword_masked( address, 0xff000000 ) >> 24 ); + break; + } + + if( m_berr ) + { + load_bus_error_exception(); + } + else + { + delayed_load( INS_RT( m_op ), data ); + } + } + } + break; + + case OP_SB: + { + UINT32 address = m_r[ INS_RS( m_op ) ] + PSXCPU_WORD_EXTEND( INS_IMMEDIATE( m_op ) ); + int breakpoint = store_data_address_breakpoint( address ); + + if( ( address & m_bad_byte_address_mask ) != 0 ) + { + store_bad_address( address ); + } + else + { + int shift = 8 * ( address & 3 ); + writeword_masked( address, m_r[ INS_RT( m_op ) ] << shift, 0xff << shift ); + + if( breakpoint ) + { + breakpoint_exception(); + } + else if( m_berr ) + { + store_bus_error_exception(); + } + else + { + advance_pc(); + } + } + } + break; + + case OP_SH: + { + UINT32 address = m_r[ INS_RS( m_op ) ] + PSXCPU_WORD_EXTEND( INS_IMMEDIATE( m_op ) ); + int breakpoint = store_data_address_breakpoint( address ); + + if( ( address & m_bad_half_address_mask ) != 0 ) + { + store_bad_address( address ); + } + else + { + int shift = 8 * ( address & 2 ); + writeword_masked( address, m_r[ INS_RT( m_op ) ] << shift, 0xffff << shift ); + + if( breakpoint ) + { + breakpoint_exception(); + } + else if( m_berr ) + { + store_bus_error_exception(); + } + else + { + advance_pc(); + } + } + } + break; + + case OP_SWL: + { + UINT32 address = m_r[ INS_RS( m_op ) ] + PSXCPU_WORD_EXTEND( INS_IMMEDIATE( m_op ) ); + int save_type = address & 3; + int breakpoint; + + address &= ~3; + breakpoint = store_data_address_breakpoint( address ); + + if( ( address & m_bad_byte_address_mask ) != 0 ) + { + store_bad_address( address ); + } + else + { + switch( save_type ) + { + case 0: + writeword_masked( address, m_r[ INS_RT( m_op ) ] >> 24, 0x000000ff ); + break; + + case 1: + writeword_masked( address, m_r[ INS_RT( m_op ) ] >> 16, 0x0000ffff ); + break; + + case 2: + writeword_masked( address, m_r[ INS_RT( m_op ) ] >> 8, 0x00ffffff ); + break; + + case 3: + writeword( address, m_r[ INS_RT( m_op ) ] ); + break; + } + + if( breakpoint ) + { + breakpoint_exception(); + } + else if( m_berr ) + { + store_bus_error_exception(); + } + else + { + advance_pc(); + } + } + } + break; + + case OP_SW: + { + UINT32 address = m_r[ INS_RS( m_op ) ] + PSXCPU_WORD_EXTEND( INS_IMMEDIATE( m_op ) ); + int breakpoint = store_data_address_breakpoint( address ); + + if( ( address & m_bad_word_address_mask ) != 0 ) + { + store_bad_address( address ); + } + else + { + writeword( address, m_r[ INS_RT( m_op ) ] ); + + if( breakpoint ) + { + breakpoint_exception(); + } + else if( m_berr ) + { + store_bus_error_exception(); + } + else + { + advance_pc(); + } + } + } + break; + + case OP_SWR: + { + UINT32 address = m_r[ INS_RS( m_op ) ] + PSXCPU_WORD_EXTEND( INS_IMMEDIATE( m_op ) ); + int breakpoint = store_data_address_breakpoint( address ); + + if( ( address & m_bad_byte_address_mask ) != 0 ) + { + store_bad_address( address ); + } + else + { + switch( address & 3 ) + { + case 0: + writeword( address, m_r[ INS_RT( m_op ) ] ); + break; + + case 1: + writeword_masked( address, m_r[ INS_RT( m_op ) ] << 8, 0xffffff00 ); + break; + + case 2: + writeword_masked( address, m_r[ INS_RT( m_op ) ] << 16, 0xffff0000 ); + break; + + case 3: + writeword_masked( address, m_r[ INS_RT( m_op ) ] << 24, 0xff000000 ); + break; + } + + if( breakpoint ) + { + breakpoint_exception(); + } + else if( m_berr ) + { + store_bus_error_exception(); + } + else + { + advance_pc(); + } + } + } + break; + + case OP_LWC0: + lwc( 0, SR_CU0 ); + break; + + case OP_LWC1: + lwc( 1, SR_CU1 ); + break; + + case OP_LWC2: + lwc( 2, SR_CU2 ); + break; + + case OP_LWC3: + lwc( 3, SR_CU3 ); + break; + + case OP_SWC0: + swc( 0, SR_CU0 ); + break; + + case OP_SWC1: + swc( 1, SR_CU1 ); + break; + + case OP_SWC2: + swc( 2, SR_CU2 ); + break; + + case OP_SWC3: + swc( 3, SR_CU3 ); + break; + + default: + logerror( "%08x: unknown opcode %08x\n", m_pc, m_op ); + stop(); + exception( EXC_RI ); + break; + } + } + + m_icount--; + } while( m_icount > 0 ); +} + +UINT32 psxcpu_device::getcp1dr( int reg ) +{ + /* if a mtc/ctc precedes then this will get the value moved (which cop1 register is irrelevant). */ + /* if a mfc/cfc follows then it will get the same value as this one. */ + return m_program->read_dword( m_pc + 4 ); +} + +void psxcpu_device::setcp1dr( int reg, UINT32 value ) +{ +} + +UINT32 psxcpu_device::getcp1cr( int reg ) +{ + /* if a mtc/ctc precedes then this will get the value moved (which cop1 register is irrelevant). */ + /* if a mfc/cfc follows then it will get the same value as this one. */ + return m_program->read_dword( m_pc + 4 ); +} + +void psxcpu_device::setcp1cr( int reg, UINT32 value ) +{ +} + + +UINT32 psxcpu_device::getcp3dr( int reg ) +{ + /* if you have mtc/ctc with an mfc/cfc directly afterwards then you get the value that was moved. */ + /* if you have an lwc with an mfc/cfc somewhere after it then you get the value that is loaded */ + /* otherwise you get the next opcode. which register you transfer to or from is irrelevant. */ + return m_program->read_dword( m_pc + 4 ); +} + +void psxcpu_device::setcp3dr( int reg, UINT32 value ) +{ +} + +UINT32 psxcpu_device::getcp3cr( int reg ) +{ + /* if you have mtc/ctc with an mfc/cfc directly afterwards then you get the value that was moved. */ + /* if you have an lwc with an mfc/cfc somewhere after it then you get the value that is loaded */ + /* otherwise you get the next opcode. which register you transfer to or from is irrelevant. */ + return m_program->read_dword( m_pc + 4 ); +} + +void psxcpu_device::setcp3cr( int reg, UINT32 value ) +{ +} + +psxcpu_device *psxcpu_device::getcpu( device_t &device, const char *cputag ) +{ + return downcast( device.subdevice( cputag ) ); +} + +READ32_MEMBER( psxcpu_device::gpu_r ) +{ + return m_gpu_read_handler( space, offset, mem_mask ); +} + +WRITE32_MEMBER( psxcpu_device::gpu_w ) +{ + m_gpu_write_handler( space, offset, data, mem_mask ); +} + +READ16_MEMBER( psxcpu_device::spu_r ) +{ + return m_spu_read_handler( space, offset, mem_mask ); +} + +WRITE16_MEMBER( psxcpu_device::spu_w ) +{ + m_spu_write_handler( space, offset, data, mem_mask ); +} + +READ8_MEMBER( psxcpu_device::cd_r ) +{ + return m_cd_read_handler( space, offset, mem_mask ); +} + +WRITE8_MEMBER( psxcpu_device::cd_w ) +{ + m_cd_write_handler( space, offset, data, mem_mask ); +} + +void psxcpu_device::set_disable_rom_berr(bool mode) +{ + m_disable_rom_berr = mode; +} + +static MACHINE_CONFIG_FRAGMENT( psx ) + MCFG_DEVICE_ADD( "irq", PSX_IRQ, 0 ) + MCFG_PSX_IRQ_HANDLER( INPUTLINE( DEVICE_SELF, PSXCPU_IRQ0 ) ) + + MCFG_DEVICE_ADD( "dma", PSX_DMA, 0 ) + MCFG_PSX_DMA_IRQ_HANDLER( DEVWRITELINE("irq", psxirq_device, intin3 ) ) + + MCFG_DEVICE_ADD( "mdec", PSX_MDEC, 0 ) + MCFG_PSX_DMA_CHANNEL_WRITE( DEVICE_SELF, 0, psx_dma_write_delegate( FUNC( psxmdec_device::dma_write ), (psxmdec_device *) device ) ) + MCFG_PSX_DMA_CHANNEL_READ( DEVICE_SELF, 1, psx_dma_read_delegate( FUNC( psxmdec_device::dma_read ), (psxmdec_device *) device ) ) + + MCFG_DEVICE_ADD( "rcnt", PSX_RCNT, 0 ) + MCFG_PSX_RCNT_IRQ0_HANDLER( DEVWRITELINE( "irq", psxirq_device, intin4 ) ) + MCFG_PSX_RCNT_IRQ1_HANDLER( DEVWRITELINE( "irq", psxirq_device, intin5 ) ) + MCFG_PSX_RCNT_IRQ2_HANDLER( DEVWRITELINE( "irq", psxirq_device, intin6 ) ) + + MCFG_DEVICE_ADD( "sio0", PSX_SIO0, 0 ) + MCFG_PSX_SIO_IRQ_HANDLER( DEVWRITELINE( "irq", psxirq_device, intin7 ) ) + + MCFG_DEVICE_ADD( "sio1", PSX_SIO1, 0 ) + MCFG_PSX_SIO_IRQ_HANDLER( DEVWRITELINE( "irq", psxirq_device, intin8 ) ) + + MCFG_RAM_ADD( "ram" ) + MCFG_RAM_DEFAULT_VALUE( 0x00 ) +MACHINE_CONFIG_END + +//------------------------------------------------- +// machine_config_additions - return a pointer to +// the device's machine fragment +//------------------------------------------------- + +machine_config_constructor psxcpu_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( psx ); +} diff --git a/src/devices/cpu/psx/psx.h b/src/devices/cpu/psx/psx.h new file mode 100644 index 00000000000..21b6d8adc55 --- /dev/null +++ b/src/devices/cpu/psx/psx.h @@ -0,0 +1,533 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/* + * PlayStation CPU emulator + * + * Copyright 2003-2013 smf + * + */ + +#pragma once + +#ifndef __PSXCPU_H__ +#define __PSXCPU_H__ + +#include "emu.h" +#include "machine/ram.h" +#include "dma.h" +#include "gte.h" +#include "irq.h" +#include "sio.h" + +//************************************************************************** +// CONSTANTS +//************************************************************************** + +// cache + +#define ICACHE_ENTRIES ( 0x400 ) +#define DCACHE_ENTRIES ( 0x100 ) + +// interrupts + +#define PSXCPU_IRQ0 ( 0 ) +#define PSXCPU_IRQ1 ( 1 ) +#define PSXCPU_IRQ2 ( 2 ) +#define PSXCPU_IRQ3 ( 3 ) +#define PSXCPU_IRQ4 ( 4 ) +#define PSXCPU_IRQ5 ( 5 ) + +// register enumeration + +enum +{ + PSXCPU_PC = 1, + PSXCPU_DELAYV, PSXCPU_DELAYR, + PSXCPU_HI, PSXCPU_LO, + PSXCPU_BIU, + PSXCPU_R0, PSXCPU_R1, + PSXCPU_R2, PSXCPU_R3, + PSXCPU_R4, PSXCPU_R5, + PSXCPU_R6, PSXCPU_R7, + PSXCPU_R8, PSXCPU_R9, + PSXCPU_R10, PSXCPU_R11, + PSXCPU_R12, PSXCPU_R13, + PSXCPU_R14, PSXCPU_R15, + PSXCPU_R16, PSXCPU_R17, + PSXCPU_R18, PSXCPU_R19, + PSXCPU_R20, PSXCPU_R21, + PSXCPU_R22, PSXCPU_R23, + PSXCPU_R24, PSXCPU_R25, + PSXCPU_R26, PSXCPU_R27, + PSXCPU_R28, PSXCPU_R29, + PSXCPU_R30, PSXCPU_R31, + PSXCPU_CP0R0, PSXCPU_CP0R1, + PSXCPU_CP0R2, PSXCPU_CP0R3, + PSXCPU_CP0R4, PSXCPU_CP0R5, + PSXCPU_CP0R6, PSXCPU_CP0R7, + PSXCPU_CP0R8, PSXCPU_CP0R9, + PSXCPU_CP0R10, PSXCPU_CP0R11, + PSXCPU_CP0R12, PSXCPU_CP0R13, + PSXCPU_CP0R14, PSXCPU_CP0R15, + PSXCPU_CP2DR0, PSXCPU_CP2DR1, + PSXCPU_CP2DR2, PSXCPU_CP2DR3, + PSXCPU_CP2DR4, PSXCPU_CP2DR5, + PSXCPU_CP2DR6, PSXCPU_CP2DR7, + PSXCPU_CP2DR8, PSXCPU_CP2DR9, + PSXCPU_CP2DR10, PSXCPU_CP2DR11, + PSXCPU_CP2DR12, PSXCPU_CP2DR13, + PSXCPU_CP2DR14, PSXCPU_CP2DR15, + PSXCPU_CP2DR16, PSXCPU_CP2DR17, + PSXCPU_CP2DR18, PSXCPU_CP2DR19, + PSXCPU_CP2DR20, PSXCPU_CP2DR21, + PSXCPU_CP2DR22, PSXCPU_CP2DR23, + PSXCPU_CP2DR24, PSXCPU_CP2DR25, + PSXCPU_CP2DR26, PSXCPU_CP2DR27, + PSXCPU_CP2DR28, PSXCPU_CP2DR29, + PSXCPU_CP2DR30, PSXCPU_CP2DR31, + PSXCPU_CP2CR0, PSXCPU_CP2CR1, + PSXCPU_CP2CR2, PSXCPU_CP2CR3, + PSXCPU_CP2CR4, PSXCPU_CP2CR5, + PSXCPU_CP2CR6, PSXCPU_CP2CR7, + PSXCPU_CP2CR8, PSXCPU_CP2CR9, + PSXCPU_CP2CR10, PSXCPU_CP2CR11, + PSXCPU_CP2CR12, PSXCPU_CP2CR13, + PSXCPU_CP2CR14, PSXCPU_CP2CR15, + PSXCPU_CP2CR16, PSXCPU_CP2CR17, + PSXCPU_CP2CR18, PSXCPU_CP2CR19, + PSXCPU_CP2CR20, PSXCPU_CP2CR21, + PSXCPU_CP2CR22, PSXCPU_CP2CR23, + PSXCPU_CP2CR24, PSXCPU_CP2CR25, + PSXCPU_CP2CR26, PSXCPU_CP2CR27, + PSXCPU_CP2CR28, PSXCPU_CP2CR29, + PSXCPU_CP2CR30, PSXCPU_CP2CR31 +}; + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_PSX_DMA_CHANNEL_READ( cputag, channel, handler ) \ + psxcpu_device::getcpu( *owner, cputag )->subdevice("dma")->install_read_handler( channel, handler ); + +#define MCFG_PSX_DMA_CHANNEL_WRITE( cputag, channel, handler ) \ + psxcpu_device::getcpu( *owner, cputag )->subdevice("dma")->install_write_handler( channel, handler ); + +#define MCFG_PSX_GPU_READ_HANDLER(_devcb) \ + devcb = &psxcpu_device::set_gpu_read_handler(*device, DEVCB_##_devcb); +#define MCFG_PSX_GPU_WRITE_HANDLER(_devcb) \ + devcb = &psxcpu_device::set_gpu_write_handler(*device, DEVCB_##_devcb); + +#define MCFG_PSX_SPU_READ_HANDLER(_devcb) \ + devcb = &psxcpu_device::set_spu_read_handler(*device, DEVCB_##_devcb); +#define MCFG_PSX_SPU_WRITE_HANDLER(_devcb) \ + devcb = &psxcpu_device::set_spu_write_handler(*device, DEVCB_##_devcb); + +#define MCFG_PSX_CD_READ_HANDLER(_devcb) \ + devcb = &psxcpu_device::set_cd_read_handler(*device, DEVCB_##_devcb); +#define MCFG_PSX_CD_WRITE_HANDLER(_devcb) \ + devcb = &psxcpu_device::set_cd_write_handler(*device, DEVCB_##_devcb); +#define MCFG_PSX_DISABLE_ROM_BERR \ + downcast(device)->set_disable_rom_berr(true); + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class psxcpu_state +{ +public: + virtual ~psxcpu_state() {}; + + virtual UINT32 pc() = 0; + virtual UINT32 delayr() = 0; + virtual UINT32 delayv() = 0; + virtual UINT32 r(int i) = 0; +}; + +// ======================> psxcpu_device + +class psxcpu_device : public cpu_device, + psxcpu_state +{ +public: + // construction/destruction + psxcpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual ~psxcpu_device() {}; + + // static configuration helpers + template static devcb_base &set_gpu_read_handler(device_t &device, _Object object) { return downcast(device).m_gpu_read_handler.set_callback(object); } + template static devcb_base &set_gpu_write_handler(device_t &device, _Object object) { return downcast(device).m_gpu_write_handler.set_callback(object); } + template static devcb_base &set_spu_read_handler(device_t &device, _Object object) { return downcast(device).m_spu_read_handler.set_callback(object); } + template static devcb_base &set_spu_write_handler(device_t &device, _Object object) { return downcast(device).m_spu_write_handler.set_callback(object); } + template static devcb_base &set_cd_read_handler(device_t &device, _Object object) { return downcast(device).m_cd_read_handler.set_callback(object); } + template static devcb_base &set_cd_write_handler(device_t &device, _Object object) { return downcast(device).m_cd_write_handler.set_callback(object); } + + // public interfaces + DECLARE_WRITE32_MEMBER( berr_w ); + DECLARE_READ32_MEMBER( berr_r ); + + UINT32 exp_base(); + + DECLARE_WRITE32_MEMBER( exp_base_w ); + DECLARE_READ32_MEMBER( exp_base_r ); + + DECLARE_WRITE32_MEMBER( exp_config_w ); + DECLARE_READ32_MEMBER( exp_config_r ); + + DECLARE_WRITE32_MEMBER( ram_config_w ); + DECLARE_READ32_MEMBER( ram_config_r ); + + DECLARE_WRITE32_MEMBER( rom_config_w ); + DECLARE_READ32_MEMBER( rom_config_r ); + + DECLARE_WRITE32_MEMBER( biu_w ); + DECLARE_READ32_MEMBER( biu_r ); + + DECLARE_WRITE32_MEMBER( gpu_w ); + DECLARE_READ32_MEMBER( gpu_r ); + + DECLARE_WRITE16_MEMBER( spu_w ); + DECLARE_READ16_MEMBER( spu_r ); + + DECLARE_WRITE8_MEMBER( cd_w ); + DECLARE_READ8_MEMBER( cd_r ); + + DECLARE_WRITE32_MEMBER( com_delay_w ); + DECLARE_READ32_MEMBER( com_delay_r ); + + static psxcpu_device *getcpu( device_t &device, const char *cputag ); + void set_disable_rom_berr(bool mode); + +protected: + psxcpu_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_post_load(); + virtual machine_config_constructor device_mconfig_additions() const; + + // device_execute_interface overrides + virtual UINT32 execute_min_cycles() const { return 1; } + virtual UINT32 execute_max_cycles() const { return 40; } + virtual UINT32 execute_input_lines() const { return 6; } + virtual UINT64 execute_clocks_to_cycles(UINT64 clocks) const { return ( clocks + 3 ) / 4; } + virtual UINT64 execute_cycles_to_clocks(UINT64 cycles) const { return cycles * 4; } + virtual void execute_run(); + virtual void execute_set_input(int inputnum, int state); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const { return (spacenum == AS_PROGRAM) ? &m_program_config : NULL; } + + // device_state_interface overrides + virtual void state_import(const device_state_entry &entry); + virtual void state_string_export(const device_state_entry &entry, std::string &str); + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const { return 4; } + virtual UINT32 disasm_max_opcode_bytes() const { return 8; } + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + + // CPU registers + UINT32 m_pc; + UINT32 m_r[ 32 ]; + UINT32 m_cp0r[ 16 ]; + UINT32 m_hi; + UINT32 m_lo; + + // internal stuff + UINT32 m_op; + + // memory access + inline UINT32 program_read(UINT32 addr); + inline void program_write(UINT32 addr, UINT32 data); + inline UINT32 opcode_read(); + + // address spaces + const address_space_config m_program_config; + address_space *m_program; + direct_read_data *m_direct; + + // other internal states + int m_icount; + UINT32 m_com_delay; + UINT32 m_delayv; + UINT32 m_delayr; + UINT32 m_berr; + UINT32 m_biu; + UINT32 m_icacheTag[ ICACHE_ENTRIES / 4 ]; + UINT32 m_icache[ ICACHE_ENTRIES ]; + UINT32 m_dcache[ DCACHE_ENTRIES ]; + int m_multiplier_operation; + UINT32 m_multiplier_operand1; + UINT32 m_multiplier_operand2; + int m_bus_attached; + UINT32 m_bad_byte_address_mask; + UINT32 m_bad_half_address_mask; + UINT32 m_bad_word_address_mask; + UINT32 m_exp_base; + UINT32 m_exp_config; + UINT32 m_ram_config; + UINT32 m_rom_config; + + void stop(); + UINT32 cache_readword( UINT32 offset ); + void cache_writeword( UINT32 offset, UINT32 data ); + UINT8 readbyte( UINT32 address ); + UINT16 readhalf( UINT32 address ); + UINT32 readword( UINT32 address ); + UINT32 readword_masked( UINT32 address, UINT32 mask ); + void writeword( UINT32 address, UINT32 data ); + void writeword_masked( UINT32 address, UINT32 data, UINT32 mask ); + UINT32 log_bioscall_parameter( int parm ); + const char *log_bioscall_string( int parm ); + const char *log_bioscall_hex( int parm ); + const char *log_bioscall_char( int parm ); + void log_bioscall(); + void log_syscall(); + void update_memory_handlers(); + void funct_mthi(); + void funct_mtlo(); + void funct_mult(); + void funct_multu(); + void funct_div(); + void funct_divu(); + void multiplier_update(); + UINT32 get_hi(); + UINT32 get_lo(); + int execute_unstoppable_instructions( int executeCop2 ); + void update_address_masks(); + void update_scratchpad(); + void update_ram_config(); + void update_rom_config(); + void update_cop0( int reg ); + void commit_delayed_load(); + void set_pc( unsigned pc ); + void fetch_next_op(); + int advance_pc(); + void load( UINT32 reg, UINT32 value ); + void delayed_load( UINT32 reg, UINT32 value ); + void branch( UINT32 address ); + void conditional_branch( int takeBranch ); + void unconditional_branch(); + void common_exception( int exception, UINT32 romOffset, UINT32 ramOffset ); + void exception( int exception ); + void breakpoint_exception(); + void fetch_bus_error_exception(); + void load_bus_error_exception(); + void store_bus_error_exception(); + void load_bad_address( UINT32 address ); + void store_bad_address( UINT32 address ); + int data_address_breakpoint( int dcic_rw, int dcic_status, UINT32 address ); + int load_data_address_breakpoint( UINT32 address ); + int store_data_address_breakpoint( UINT32 address ); + + UINT32 get_register_from_pipeline( int reg ); + int cop0_usable(); + void lwc( int cop, int sr_cu ); + void swc( int cop, int sr_cu ); + void bc( int cop, int sr_cu, int condition ); + + UINT32 getcp1dr( int reg ); + void setcp1dr( int reg, UINT32 value ); + UINT32 getcp1cr( int reg ); + void setcp1cr( int reg, UINT32 value ); + UINT32 getcp3dr( int reg ); + void setcp3dr( int reg, UINT32 value ); + UINT32 getcp3cr( int reg ); + void setcp3cr( int reg, UINT32 value ); + + gte m_gte; + + devcb_read32 m_gpu_read_handler; + devcb_write32 m_gpu_write_handler; + devcb_read16 m_spu_read_handler; + devcb_write16 m_spu_write_handler; + devcb_read8 m_cd_read_handler; + devcb_write8 m_cd_write_handler; + required_device m_ram; + memory_region *m_rom; + bool m_disable_rom_berr; + +private: + // disassembler interface + virtual UINT32 pc() { return m_pc; } + virtual UINT32 delayr() { return m_delayr; } + virtual UINT32 delayv() { return m_delayv; } + virtual UINT32 r(int i) { return m_r[ i ]; } +}; + +class cxd8530aq_device : public psxcpu_device +{ +public: + // construction/destruction + cxd8530aq_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class cxd8530bq_device : public psxcpu_device +{ +public: + // construction/destruction + cxd8530bq_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class cxd8530cq_device : public psxcpu_device +{ +public: + // construction/destruction + cxd8530cq_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class cxd8661r_device : public psxcpu_device +{ +public: + // construction/destruction + cxd8661r_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class cxd8606bq_device : public psxcpu_device +{ +public: + // construction/destruction + cxd8606bq_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class cxd8606cq_device : public psxcpu_device +{ +public: + // construction/destruction + cxd8606cq_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +// device type definition +extern const device_type CXD8530AQ; +extern const device_type CXD8530BQ; +extern const device_type CXD8530CQ; +extern const device_type CXD8661R; +extern const device_type CXD8606BQ; +extern const device_type CXD8606CQ; + + + +#define PSXCPU_DELAYR_PC ( 32 ) +#define PSXCPU_DELAYR_NOTPC ( 33 ) + +#define PSXCPU_BYTE_EXTEND( a ) ( (INT32)(INT8)a ) +#define PSXCPU_WORD_EXTEND( a ) ( (INT32)(INT16)a ) + +#define INS_OP( op ) ( ( op >> 26 ) & 63 ) +#define INS_RS( op ) ( ( op >> 21 ) & 31 ) +#define INS_RT( op ) ( ( op >> 16 ) & 31 ) +#define INS_IMMEDIATE( op ) ( op & 0xffff ) +#define INS_TARGET( op ) ( op & 0x3ffffff ) +#define INS_RD( op ) ( ( op >> 11 ) & 31 ) +#define INS_SHAMT( op ) ( ( op >> 6 ) & 31 ) +#define INS_FUNCT( op ) ( op & 63 ) +#define INS_CODE( op ) ( ( op >> 6 ) & 0xfffff ) +#define INS_CO( op ) ( ( op >> 25 ) & 1 ) +#define INS_COFUN( op ) ( op & 0x1ffffff ) +#define INS_CF( op ) ( op & 31 ) +#define INS_BC( op ) ( ( op >> 16 ) & 1 ) +#define INS_RT_REGIMM( op ) ( ( op >> 16 ) & 1 ) + +#define OP_SPECIAL ( 0 ) +#define OP_REGIMM ( 1 ) +#define OP_J ( 2 ) +#define OP_JAL ( 3 ) +#define OP_BEQ ( 4 ) +#define OP_BNE ( 5 ) +#define OP_BLEZ ( 6 ) +#define OP_BGTZ ( 7 ) +#define OP_ADDI ( 8 ) +#define OP_ADDIU ( 9 ) +#define OP_SLTI ( 10 ) +#define OP_SLTIU ( 11 ) +#define OP_ANDI ( 12 ) +#define OP_ORI ( 13 ) +#define OP_XORI ( 14 ) +#define OP_LUI ( 15 ) +#define OP_COP0 ( 16 ) +#define OP_COP1 ( 17 ) +#define OP_COP2 ( 18 ) +#define OP_COP3 ( 19 ) +#define OP_LB ( 32 ) +#define OP_LH ( 33 ) +#define OP_LWL ( 34 ) +#define OP_LW ( 35 ) +#define OP_LBU ( 36 ) +#define OP_LHU ( 37 ) +#define OP_LWR ( 38 ) +#define OP_SB ( 40 ) +#define OP_SH ( 41 ) +#define OP_SWL ( 42 ) +#define OP_SW ( 43 ) +#define OP_SWR ( 46 ) +#define OP_LWC0 ( 48 ) +#define OP_LWC1 ( 49 ) +#define OP_LWC2 ( 50 ) +#define OP_LWC3 ( 51 ) +#define OP_SWC0 ( 56 ) +#define OP_SWC1 ( 57 ) +#define OP_SWC2 ( 58 ) +#define OP_SWC3 ( 59 ) + +/* OP_SPECIAL */ +#define FUNCT_SLL ( 0 ) +#define FUNCT_SRL ( 2 ) +#define FUNCT_SRA ( 3 ) +#define FUNCT_SLLV ( 4 ) +#define FUNCT_SRLV ( 6 ) +#define FUNCT_SRAV ( 7 ) +#define FUNCT_JR ( 8 ) +#define FUNCT_JALR ( 9 ) +#define FUNCT_SYSCALL ( 12 ) +#define FUNCT_BREAK ( 13 ) +#define FUNCT_MFHI ( 16 ) +#define FUNCT_MTHI ( 17 ) +#define FUNCT_MFLO ( 18 ) +#define FUNCT_MTLO ( 19 ) +#define FUNCT_MULT ( 24 ) +#define FUNCT_MULTU ( 25 ) +#define FUNCT_DIV ( 26 ) +#define FUNCT_DIVU ( 27 ) +#define FUNCT_ADD ( 32 ) +#define FUNCT_ADDU ( 33 ) +#define FUNCT_SUB ( 34 ) +#define FUNCT_SUBU ( 35 ) +#define FUNCT_AND ( 36 ) +#define FUNCT_OR ( 37 ) +#define FUNCT_XOR ( 38 ) +#define FUNCT_NOR ( 39 ) +#define FUNCT_SLT ( 42 ) +#define FUNCT_SLTU ( 43 ) + +/* OP_REGIMM */ +#define RT_BLTZ ( 0 ) +#define RT_BGEZ ( 1 ) +#define RT_BLTZAL ( 16 ) +#define RT_BGEZAL ( 17 ) + +/* OP_COP0/OP_COP1/OP_COP2 */ +#define RS_MFC ( 0 ) +#define RS_CFC ( 2 ) +#define RS_MTC ( 4 ) +#define RS_CTC ( 6 ) +#define RS_BC ( 8 ) +#define RS_BC_ALT ( 12 ) + +/* BC_BC */ +#define BC_BCF ( 0 ) +#define BC_BCT ( 1 ) + +/* OP_COP0 */ +#define CF_TLBR ( 1 ) +#define CF_TLBWI ( 2 ) +#define CF_TLBWR ( 6 ) +#define CF_TLBP ( 8 ) +#define CF_RFE ( 16 ) + +extern unsigned DasmPSXCPU( psxcpu_state *state, char *buffer, UINT32 pc, const UINT8 *opram ); + +#endif /* __PSXCPU_H__ */ diff --git a/src/devices/cpu/psx/psxdasm.c b/src/devices/cpu/psx/psxdasm.c new file mode 100644 index 00000000000..dabb4da9413 --- /dev/null +++ b/src/devices/cpu/psx/psxdasm.c @@ -0,0 +1,680 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/* + * PSXCPU disassembler for the MAME project written by smf + * + */ + +#include "emu.h" +#include "psx.h" +#include "gte.h" + +static char *make_signed_hex_str_16( UINT32 value ) +{ + static char s_hex[ 20 ]; + + if( value & 0x8000 ) + { + sprintf( s_hex, "-$%x", -value & 0xffff ); + } + else + { + sprintf( s_hex, "$%x", value & 0xffff ); + } + + return s_hex; +} + +static const char *const s_cpugenreg[] = +{ + "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3", + "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", + "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", + "t8", "t9", "k0", "k1", "gp", "sp", "fp", "ra" +}; + +static const char *const s_cp0genreg[] = +{ + "!Index", "!Random", "!EntryLo", "BPC", "!Context", "BDA", "TAR", "DCIC", + "BadA", "BDAM", "!EntryHi", "BPCM", "SR", "Cause", "EPC", "PRId", + "cp0r16", "cp0r17", "cp0r18", "cp0r19", "cp0r20", "cp0r21", "cp0r22", "cp0r23", + "cp0r24", "cp0r25", "cp0r26", "cp0r27", "cp0r28", "cp0r29", "cp0r30", "cp0r31" +}; + +static const char *const s_cp0ctlreg[] = +{ + "cp0cr0", "cp0cr1", "cp0cr2", "cp0cr3", "cp0cr4", "cp0cr5", "cp0cr6", "cp0cr7", + "cp0cr8", "cp0cr9", "cp0cr10", "cp0cr11", "cp0cr12", "cp0cr13", "cp0cr14", "cp0cr15", + "cp0cr16", "cp0cr17", "cp0cr18", "cp0cr19", "cp0cr20", "cp0cr21", "cp0cr22", "cp0cr23", + "cp0cr24", "cp0cr25", "cp0cr26", "cp0cr27", "cp0cr28", "cp0cr29", "cp0cr30", "cp0cr31" +}; + +static const char *const s_cp1genreg[] = +{ + "cp1r0", "cp1r1", "cp1r2", "cp1r3", "cp1r4", "cp1r5", "cp1r6", "cp1r7", + "cp1r8", "cp1r9", "cp1r10", "cp1r11", "cp1r12", "cp1r13", "cp1r14", "cp1r15", + "cp1r16", "cp1r17", "cp1r18", "cp1r19", "cp1r20", "cp1r21", "cp1r22", "cp1r22", + "cp1r23", "cp1r24", "cp1r25", "cp1r26", "cp1r27", "cp1r28", "cp1r29", "cp1r30" +}; + +static const char *const s_cp1ctlreg[] = +{ + "cp1cr0", "cp1cr1", "cp1cr2", "cp1cr3", "cp1cr4", "cp1cr5", "cp1cr6", "cp1cr7", + "cp1cr8", "cp1cr9", "cp1cr10", "cp1cr11", "cp1cr12", "cp1cr13", "cp1cr14", "cp1cr15", + "cp1cr16", "cp1cr17", "cp1cr18", "cp1cr19", "cp1cr20", "cp1cr21", "cp1cr22", "cp1cr23", + "cp1cr24", "cp1cr25", "cp1cr26", "cp1cr27", "cp1cr28", "cp1cr29", "cp1cr30", "cp1cr31" +}; + +static const char *const s_cp2genreg[] = +{ + "vxy0", "vz0", "vxy1", "vz1", "vxy2", "vz2", "rgb", "otz", + "ir0", "ir1", "ir2", "ir3", "sxy0", "sxy1", "sxy2", "sxyp", + "sz0", "sz1", "sz2", "sz3", "rgb0", "rgb1", "rgb2", "cp2cr23", + "mac0", "mac1", "mac2", "mac3", "irgb", "orgb", "lzcs", "lzcr" +}; + +static const char *const s_cp2ctlreg[] = +{ + "r11r12", "r13r21", "r22r23", "r31r32", "r33", "trx", "try", "trz", + "l11l12", "l13l21", "l22l23", "l31l32", "l33", "rbk", "gbk", "bbk", + "lr1lr2", "lr3lg1", "lg2lg3", "lb1lb2", "lb3", "rfc", "gfc", "bfc", + "ofx", "ofy", "h", "dqa", "dqb", "zsf3", "zsf4", "flag" +}; + +static const char *const s_cp3genreg[] = +{ + "cp3r0", "cp3r1", "cp3r2", "cp3r3", "cp3r4", "cp3r5", "cp3r6", "cp3r7", + "cp3r8", "cp3r9", "cp3r10", "cp3r11", "cp3r12", "cp3r13", "cp3r14", "cp3r15", + "cp3r16", "cp3r17", "cp3r18", "cp3r19", "cp3r20", "cp3r21", "cp3r22", "cp3r22", + "cp3r23", "cp3r24", "cp3r25", "cp3r26", "cp3r27", "cp3r28", "cp3r29", "cp3r30" +}; + +static const char *const s_cp3ctlreg[] = +{ + "cp3cr0", "cp3cr1", "cp3cr2", "cp3cr3", "cp3cr4", "cp3cr5", "cp3cr6", "cp3cr7", + "cp3cr8", "cp3cr9", "cp3cr10", "cp3cr11", "cp3cr12", "cp3cr13", "cp3cr14", "cp3cr15", + "cp3cr16", "cp3cr17", "cp3cr18", "cp3cr19", "cp3cr20", "cp3cr21", "cp3cr22", "cp3cr23", + "cp3cr24", "cp3cr25", "cp3cr26", "cp3cr27", "cp3cr28", "cp3cr29", "cp3cr30", "cp3cr31" +}; + +static const char *const s_gtesf[] = +{ + " sf=0", " sf=12" +}; + +static const char *const s_gtemx[] = +{ + "rm", "lm", "cm", "0" +}; + +static const char *const s_gtev[] = +{ + "v0", "v1", "v2", "ir" +}; + +static const char *const s_gtecv[] = +{ + "tr", "bk", "fc", "0" +}; + +static const char *const s_gtelm[] = +{ + " lm=s16", " lm=u15" +}; + +static char *effective_address( psxcpu_state *state, UINT32 pc, UINT32 op ) +{ + static char s_address[ 20 ]; + + if( state != NULL && state->pc() == pc ) + { + sprintf( s_address, "%s(%s) ; 0x%08x", make_signed_hex_str_16( INS_IMMEDIATE( op ) ), s_cpugenreg[ INS_RS( op ) ], + (UINT32)( state->r( INS_RS( op ) ) + (INT16)INS_IMMEDIATE( op ) ) ); + return s_address; + } + sprintf( s_address, "%s(%s)", make_signed_hex_str_16( INS_IMMEDIATE( op ) ), s_cpugenreg[ INS_RS( op ) ] ); + return s_address; +} + +static UINT32 relative_address( psxcpu_state *state, UINT32 pc, UINT32 op ) +{ + UINT32 nextpc = pc + 4; + if( state != NULL && state->pc() == pc && state->delayr() == PSXCPU_DELAYR_PC ) + { + nextpc = state->delayv(); + } + + return nextpc + ( PSXCPU_WORD_EXTEND( INS_IMMEDIATE( op ) ) << 2 ); +} + +static UINT32 jump_address( psxcpu_state *state, UINT32 pc, UINT32 op ) +{ + UINT32 nextpc = pc + 4; + if( state != NULL && state->pc() == pc && state->delayr() == PSXCPU_DELAYR_PC ) + { + nextpc = state->delayv(); + } + return ( nextpc & 0xf0000000 ) + ( INS_TARGET( op ) << 2 ); +} + +static UINT32 fetch_op( const UINT8 *opram ) +{ + return ( opram[ 3 ] << 24 ) | ( opram[ 2 ] << 16 ) | ( opram[ 1 ] << 8 ) | ( opram[ 0 ] << 0 ); +} + +static char *upper_address( UINT32 op, const UINT8 *opram ) +{ + static char s_address[ 20 ]; + UINT32 nextop = fetch_op( opram ); + + if( INS_OP( nextop ) == OP_ORI && INS_RT( op ) == INS_RS( nextop ) ) + { + sprintf( s_address, "$%04x ; 0x%08x", INS_IMMEDIATE( op ), ( INS_IMMEDIATE( op ) << 16 ) | INS_IMMEDIATE( nextop ) ); + } + else if( INS_OP( nextop ) == OP_ADDIU && INS_RT( op ) == INS_RS( nextop ) ) + { + sprintf( s_address, "$%04x ; 0x%08x", INS_IMMEDIATE( op ), ( INS_IMMEDIATE( op ) << 16 ) + (INT16) INS_IMMEDIATE( nextop ) ); + } + else + { + sprintf( s_address, "$%04x", INS_IMMEDIATE( op ) ); + } + + return s_address; +} + +unsigned DasmPSXCPU( psxcpu_state *state, char *buffer, UINT32 pc, const UINT8 *opram ) +{ + UINT32 op; + const UINT8 *oldopram; + UINT32 flags = 0; + + oldopram = opram; + op = fetch_op( opram ); + opram += 4; + + sprintf( buffer, "dw $%08x", op ); + + switch( INS_OP( op ) ) + { + case OP_SPECIAL: + switch( INS_FUNCT( op ) ) + { + case FUNCT_SLL: + if( op == 0 ) + { + /* the standard nop is "sll zero,zero,$0000" */ + sprintf( buffer, "nop" ); + } + else + { + sprintf( buffer, "sll %s,%s,$%02x", s_cpugenreg[ INS_RD( op ) ], s_cpugenreg[ INS_RT( op ) ], INS_SHAMT( op ) ); + } + break; + case FUNCT_SRL: + sprintf( buffer, "srl %s,%s,$%02x", s_cpugenreg[ INS_RD( op ) ], s_cpugenreg[ INS_RT( op ) ], INS_SHAMT( op ) ); + break; + case FUNCT_SRA: + sprintf( buffer, "sra %s,%s,$%02x", s_cpugenreg[ INS_RD( op ) ], s_cpugenreg[ INS_RT( op ) ], INS_SHAMT( op ) ); + break; + case FUNCT_SLLV: + sprintf( buffer, "sllv %s,%s,%s", s_cpugenreg[ INS_RD( op ) ], s_cpugenreg[ INS_RT( op ) ], s_cpugenreg[ INS_RS( op ) ] ); + break; + case FUNCT_SRLV: + sprintf( buffer, "srlv %s,%s,%s", s_cpugenreg[ INS_RD( op ) ], s_cpugenreg[ INS_RT( op ) ], s_cpugenreg[ INS_RS( op ) ] ); + break; + case FUNCT_SRAV: + sprintf( buffer, "srav %s,%s,%s", s_cpugenreg[ INS_RD( op ) ], s_cpugenreg[ INS_RT( op ) ], s_cpugenreg[ INS_RS( op ) ] ); + break; + case FUNCT_JR: + sprintf( buffer, "jr %s", s_cpugenreg[ INS_RS( op ) ] ); + if( INS_RS( op ) == 31 ) + { + flags = DASMFLAG_STEP_OUT; + } + break; + case FUNCT_JALR: + sprintf( buffer, "jalr %s,%s", s_cpugenreg[ INS_RD( op ) ], s_cpugenreg[ INS_RS( op ) ] ); + flags = DASMFLAG_STEP_OVER | DASMFLAG_STEP_OVER_EXTRA( 1 ); + break; + case FUNCT_SYSCALL: + sprintf( buffer, "syscall $%05x", INS_CODE( op ) ); + flags = DASMFLAG_STEP_OVER; + break; + case FUNCT_BREAK: + sprintf( buffer, "break $%05x", INS_CODE( op ) ); + flags = DASMFLAG_STEP_OVER; + break; + case FUNCT_MFHI: + sprintf( buffer, "mfhi %s", s_cpugenreg[ INS_RD( op ) ] ); + break; + case FUNCT_MTHI: + sprintf( buffer, "mthi %s", s_cpugenreg[ INS_RS( op ) ] ); + break; + case FUNCT_MFLO: + sprintf( buffer, "mflo %s", s_cpugenreg[ INS_RD( op ) ] ); + break; + case FUNCT_MTLO: + sprintf( buffer, "mtlo %s", s_cpugenreg[ INS_RS( op ) ] ); + break; + case FUNCT_MULT: + sprintf( buffer, "mult %s,%s", s_cpugenreg[ INS_RS( op ) ], s_cpugenreg[ INS_RT( op ) ] ); + break; + case FUNCT_MULTU: + sprintf( buffer, "multu %s,%s", s_cpugenreg[ INS_RS( op ) ], s_cpugenreg[ INS_RT( op ) ] ); + break; + case FUNCT_DIV: + sprintf( buffer, "div %s,%s", s_cpugenreg[ INS_RS( op ) ], s_cpugenreg[ INS_RT( op ) ] ); + break; + case FUNCT_DIVU: + sprintf( buffer, "divu %s,%s", s_cpugenreg[ INS_RS( op ) ], s_cpugenreg[ INS_RT( op ) ] ); + break; + case FUNCT_ADD: + sprintf( buffer, "add %s,%s,%s", s_cpugenreg[ INS_RD( op ) ], s_cpugenreg[ INS_RS( op ) ], s_cpugenreg[ INS_RT( op ) ] ); + break; + case FUNCT_ADDU: + sprintf( buffer, "addu %s,%s,%s", s_cpugenreg[ INS_RD( op ) ], s_cpugenreg[ INS_RS( op ) ], s_cpugenreg[ INS_RT( op ) ] ); + break; + case FUNCT_SUB: + sprintf( buffer, "sub %s,%s,%s", s_cpugenreg[ INS_RD( op ) ], s_cpugenreg[ INS_RS( op ) ], s_cpugenreg[ INS_RT( op ) ] ); + break; + case FUNCT_SUBU: + sprintf( buffer, "subu %s,%s,%s", s_cpugenreg[ INS_RD( op ) ], s_cpugenreg[ INS_RS( op ) ], s_cpugenreg[ INS_RT( op ) ] ); + break; + case FUNCT_AND: + sprintf( buffer, "and %s,%s,%s", s_cpugenreg[ INS_RD( op ) ], s_cpugenreg[ INS_RS( op ) ], s_cpugenreg[ INS_RT( op ) ] ); + break; + case FUNCT_OR: + sprintf( buffer, "or %s,%s,%s", s_cpugenreg[ INS_RD( op ) ], s_cpugenreg[ INS_RS( op ) ], s_cpugenreg[ INS_RT( op ) ] ); + break; + case FUNCT_XOR: + sprintf( buffer, "xor %s,%s,%s", s_cpugenreg[ INS_RD( op ) ], s_cpugenreg[ INS_RS( op ) ], s_cpugenreg[ INS_RT( op ) ] ); + break; + case FUNCT_NOR: + sprintf( buffer, "nor %s,%s,%s", s_cpugenreg[ INS_RD( op ) ], s_cpugenreg[ INS_RS( op ) ], s_cpugenreg[ INS_RT( op ) ] ); + break; + case FUNCT_SLT: + sprintf( buffer, "slt %s,%s,%s", s_cpugenreg[ INS_RD( op ) ], s_cpugenreg[ INS_RS( op ) ], s_cpugenreg[ INS_RT( op ) ] ); + break; + case FUNCT_SLTU: + sprintf( buffer, "sltu %s,%s,%s", s_cpugenreg[ INS_RD( op ) ], s_cpugenreg[ INS_RS( op ) ], s_cpugenreg[ INS_RT( op ) ] ); + break; + } + break; + case OP_REGIMM: + switch( INS_RT_REGIMM( op ) ) + { + case RT_BLTZ: + if( INS_RT( op ) == RT_BLTZAL ) + { + sprintf( buffer, "bltzal %s,$%08x", s_cpugenreg[ INS_RS( op ) ], relative_address( state, pc, op ) ); + flags = DASMFLAG_STEP_OVER | DASMFLAG_STEP_OVER_EXTRA( 1 ); + } + else + { + sprintf( buffer, "bltz %s,$%08x", s_cpugenreg[ INS_RS( op ) ], relative_address( state, pc, op ) ); + } + break; + case RT_BGEZ: + if( INS_RT( op ) == RT_BGEZAL ) + { + sprintf( buffer, "bgezal %s,$%08x", s_cpugenreg[ INS_RS( op ) ], relative_address( state, pc, op ) ); + flags = DASMFLAG_STEP_OVER | DASMFLAG_STEP_OVER_EXTRA( 1 ); + } + else + { + sprintf( buffer, "bgez %s,$%08x", s_cpugenreg[ INS_RS( op ) ], relative_address( state, pc, op ) ); + } + break; + } + break; + case OP_J: + sprintf( buffer, "j $%08x", jump_address( state, pc, op ) ); + break; + case OP_JAL: + sprintf( buffer, "jal $%08x", jump_address( state, pc, op ) ); + flags = DASMFLAG_STEP_OVER | DASMFLAG_STEP_OVER_EXTRA( 1 ); + break; + case OP_BEQ: + sprintf( buffer, "beq %s,%s,$%08x", s_cpugenreg[ INS_RS( op ) ], s_cpugenreg[ INS_RT( op ) ], relative_address( state, pc, op ) ); + break; + case OP_BNE: + sprintf( buffer, "bne %s,%s,$%08x", s_cpugenreg[ INS_RS( op ) ], s_cpugenreg[ INS_RT( op ) ], relative_address( state, pc, op ) ); + break; + case OP_BLEZ: + sprintf( buffer, "blez %s,%s,$%08x", s_cpugenreg[ INS_RS( op ) ], s_cpugenreg[ INS_RT( op ) ], relative_address( state, pc, op ) ); + break; + case OP_BGTZ: + sprintf( buffer, "bgtz %s,%s,$%08x", s_cpugenreg[ INS_RS( op ) ], s_cpugenreg[ INS_RT( op ) ], relative_address( state, pc, op ) ); + break; + case OP_ADDI: + sprintf( buffer, "addi %s,%s,%s", s_cpugenreg[ INS_RT( op ) ], s_cpugenreg[ INS_RS( op ) ], make_signed_hex_str_16( INS_IMMEDIATE( op ) ) ); + break; + case OP_ADDIU: + sprintf( buffer, "addiu %s,%s,%s", s_cpugenreg[ INS_RT( op ) ], s_cpugenreg[ INS_RS( op ) ], make_signed_hex_str_16( INS_IMMEDIATE( op ) ) ); + break; + case OP_SLTI: + sprintf( buffer, "slti %s,%s,%s", s_cpugenreg[ INS_RT( op ) ], s_cpugenreg[ INS_RS( op ) ], make_signed_hex_str_16( INS_IMMEDIATE( op ) ) ); + break; + case OP_SLTIU: + sprintf( buffer, "sltiu %s,%s,%s", s_cpugenreg[ INS_RT( op ) ], s_cpugenreg[ INS_RS( op ) ], make_signed_hex_str_16( INS_IMMEDIATE( op ) ) ); + break; + case OP_ANDI: + sprintf( buffer, "andi %s,%s,$%04x", s_cpugenreg[ INS_RT( op ) ], s_cpugenreg[ INS_RS( op ) ], INS_IMMEDIATE( op ) ); + break; + case OP_ORI: + sprintf( buffer, "ori %s,%s,$%04x", s_cpugenreg[ INS_RT( op ) ], s_cpugenreg[ INS_RS( op ) ], INS_IMMEDIATE( op ) ); + break; + case OP_XORI: + sprintf( buffer, "xori %s,%s,$%04x", s_cpugenreg[ INS_RT( op ) ], s_cpugenreg[ INS_RS( op ) ], INS_IMMEDIATE( op ) ); + break; + case OP_LUI: + sprintf( buffer, "lui %s,%s", s_cpugenreg[ INS_RT( op ) ], upper_address( op, opram ) ); + break; + case OP_COP0: + switch( INS_RS( op ) ) + { + case RS_MFC: + sprintf( buffer, "mfc0 %s,%s", s_cpugenreg[ INS_RT( op ) ], s_cp0genreg[ INS_RD( op ) ] ); + break; + case RS_CFC: + sprintf( buffer, "!cfc0 %s,%s", s_cpugenreg[ INS_RT( op ) ], s_cp0ctlreg[ INS_RD( op ) ] ); + break; + case RS_MTC: + sprintf( buffer, "mtc0 %s,%s", s_cpugenreg[ INS_RT( op ) ], s_cp0genreg[ INS_RD( op ) ] ); + break; + case RS_CTC: + sprintf( buffer, "!ctc0 %s,%s", s_cpugenreg[ INS_RT( op ) ], s_cp0ctlreg[ INS_RD( op ) ] ); + break; + case RS_BC: + case RS_BC_ALT: + switch( INS_BC( op ) ) + { + case BC_BCF: + sprintf( buffer, "bc0f $%08x", relative_address( state, pc, op ) ); + break; + case BC_BCT: + sprintf( buffer, "bc0t $%08x", relative_address( state, pc, op ) ); + break; + } + break; + default: + switch( INS_CO( op ) ) + { + case 1: + sprintf( buffer, "cop0 $%07x", INS_COFUN( op ) ); + + switch( INS_CF( op ) ) + { + case CF_TLBR: + sprintf( buffer, "!tlbr" ); + break; + case CF_TLBWI: + sprintf( buffer, "!tlbwi" ); + break; + case CF_TLBWR: + sprintf( buffer, "!tlbwr" ); + break; + case CF_TLBP: + sprintf( buffer, "!tlbp" ); + break; + case CF_RFE: + sprintf( buffer, "rfe" ); + break; + } + break; + } + break; + } + break; + case OP_COP1: + switch( INS_RS( op ) ) + { + case RS_MFC: + sprintf( buffer, "mfc1 %s,%s", s_cpugenreg[ INS_RT( op ) ], s_cp1genreg[ INS_RD( op ) ] ); + break; + case RS_CFC: + sprintf( buffer, "cfc1 %s,%s", s_cpugenreg[ INS_RT( op ) ], s_cp1ctlreg[ INS_RD( op ) ] ); + break; + case RS_MTC: + sprintf( buffer, "mtc1 %s,%s", s_cpugenreg[ INS_RT( op ) ], s_cp1genreg[ INS_RD( op ) ] ); + break; + case RS_CTC: + sprintf( buffer, "ctc1 %s,%s", s_cpugenreg[ INS_RT( op ) ], s_cp1ctlreg[ INS_RD( op ) ] ); + break; + case RS_BC: + case RS_BC_ALT: + switch( INS_BC( op ) ) + { + case BC_BCF: + sprintf( buffer, "bc1f $%08x", relative_address( state, pc, op ) ); + break; + case BC_BCT: + sprintf( buffer, "bc1t $%08x", relative_address( state, pc, op ) ); + break; + } + break; + default: + switch( INS_CO( op ) ) + { + case 1: + sprintf( buffer, "cop1 $%07x", INS_COFUN( op ) ); + break; + } + break; + } + break; + case OP_COP2: + switch( INS_RS( op ) ) + { + case RS_MFC: + sprintf( buffer, "mfc2 %s,%s", s_cpugenreg[ INS_RT( op ) ], s_cp2genreg[ INS_RD( op ) ] ); + break; + case RS_CFC: + sprintf( buffer, "cfc2 %s,%s", s_cpugenreg[ INS_RT( op ) ], s_cp2ctlreg[ INS_RD( op ) ] ); + break; + case RS_MTC: + sprintf( buffer, "mtc2 %s,%s", s_cpugenreg[ INS_RT( op ) ], s_cp2genreg[ INS_RD( op ) ] ); + break; + case RS_CTC: + sprintf( buffer, "ctc2 %s,%s", s_cpugenreg[ INS_RT( op ) ], s_cp2ctlreg[ INS_RD( op ) ] ); + break; + case RS_BC: + case RS_BC_ALT: + switch( INS_BC( op ) ) + { + case BC_BCF: + sprintf( buffer, "bc2f $%08x", relative_address( state, pc, op ) ); + break; + case BC_BCT: + sprintf( buffer, "bc2t $%08x", relative_address( state, pc, op ) ); + break; + } + break; + default: + switch( INS_CO( op ) ) + { + case 1: + sprintf( buffer, "cop2 $%07x", INS_COFUN( op ) ); + + switch( GTE_FUNCT( op ) ) + { + case 0x00: // drop through to RTPS + case 0x01: + sprintf( buffer, "rtps%s%s", s_gtesf[ GTE_SF( op ) ], s_gtelm[ GTE_LM( op ) ] ); + break; + case 0x06: + sprintf( buffer, "nclip" ); + break; + case 0x0c: + sprintf( buffer, "op%s%s", s_gtesf[ GTE_SF( op ) ], s_gtelm[ GTE_LM( op ) ] ); + break; + case 0x10: + sprintf( buffer, "dpcs%s%s", s_gtesf[ GTE_SF( op ) ], s_gtelm[ GTE_LM( op ) ] ); + break; + case 0x11: + sprintf( buffer, "intpl%s%s", s_gtesf[ GTE_SF( op ) ], s_gtelm[ GTE_LM( op ) ] ); + break; + case 0x12: + sprintf( buffer, "mvmva%s%s %s + %s * %s", s_gtesf[ GTE_SF( op ) ], s_gtelm[ GTE_LM( op ) ], + s_gtecv[ GTE_CV( op ) ], s_gtemx[ GTE_MX( op ) ], s_gtev[ GTE_V( op ) ] ); + break; + case 0x13: + sprintf( buffer, "ncds%s%s", s_gtesf[ GTE_SF( op ) ], s_gtelm[ GTE_LM( op ) ] ); + break; + case 0x14: + sprintf( buffer, "cdp%s%s", s_gtesf[ GTE_SF( op ) ], s_gtelm[ GTE_LM( op ) ] ); + break; + case 0x16: + sprintf( buffer, "ncdt%s%s", s_gtesf[ GTE_SF( op ) ], s_gtelm[ GTE_LM( op ) ] ); + break; + case 0x1b: + sprintf( buffer, "nccs%s%s", s_gtesf[ GTE_SF( op ) ], s_gtelm[ GTE_LM( op ) ] ); + break; + case 0x1c: + sprintf( buffer, "cc%s%s", s_gtesf[ GTE_SF( op ) ], s_gtelm[ GTE_LM( op ) ] ); + break; + case 0x1e: + sprintf( buffer, "ncs%s%s", s_gtesf[ GTE_SF( op ) ], s_gtelm[ GTE_LM( op ) ] ); + break; + case 0x20: + sprintf( buffer, "nct%s%s", s_gtesf[ GTE_SF( op ) ], s_gtelm[ GTE_LM( op ) ] ); + break; + case 0x28: + sprintf( buffer, "sqr%s%s", s_gtesf[ GTE_SF( op ) ], s_gtelm[ GTE_LM( op ) ] ); + break; + case 0x1a: // end of NCDT + case 0x29: + sprintf( buffer, "dpcl%s%s", s_gtesf[ GTE_SF( op ) ], s_gtelm[ GTE_LM( op ) ] ); + break; + case 0x2a: + sprintf( buffer, "dpct%s%s", s_gtesf[ GTE_SF( op ) ], s_gtelm[ GTE_LM( op ) ] ); + break; + case 0x2d: + sprintf( buffer, "avsz3" ); + break; + case 0x2e: + sprintf( buffer, "avsz4" ); + break; + case 0x30: + sprintf( buffer, "rtpt%s%s", s_gtesf[ GTE_SF( op ) ], s_gtelm[ GTE_LM( op ) ] ); + break; + case 0x3d: + sprintf( buffer, "gpf%s%s", s_gtesf[ GTE_SF( op ) ], s_gtelm[ GTE_LM( op ) ] ); + break; + case 0x3e: + sprintf( buffer, "gpl%s%s", s_gtesf[ GTE_SF( op ) ], s_gtelm[ GTE_LM( op ) ] ); + break; + case 0x3f: + sprintf( buffer, "ncct%s%s", s_gtesf[ GTE_SF( op ) ], s_gtelm[ GTE_LM( op ) ] ); + break; + } + } + break; + } + break; + case OP_COP3: + switch( INS_RS( op ) ) + { + case RS_MFC: + sprintf( buffer, "mfc3 %s,%s", s_cpugenreg[ INS_RT( op ) ], s_cp3genreg[ INS_RD( op ) ] ); + break; + case RS_CFC: + sprintf( buffer, "cfc3 %s,%s", s_cpugenreg[ INS_RT( op ) ], s_cp3ctlreg[ INS_RD( op ) ] ); + break; + case RS_MTC: + sprintf( buffer, "mtc3 %s,%s", s_cpugenreg[ INS_RT( op ) ], s_cp3genreg[ INS_RD( op ) ] ); + break; + case RS_CTC: + sprintf( buffer, "ctc3 %s,%s", s_cpugenreg[ INS_RT( op ) ], s_cp3ctlreg[ INS_RD( op ) ] ); + break; + case RS_BC: + case RS_BC_ALT: + switch( INS_BC( op ) ) + { + case BC_BCF: + sprintf( buffer, "bc3f $%08x", relative_address( state, pc, op ) ); + break; + case BC_BCT: + sprintf( buffer, "bc3t $%08x", relative_address( state, pc, op ) ); + break; + } + break; + default: + switch( INS_CO( op ) ) + { + case 1: + sprintf( buffer, "cop3 $%07x", INS_COFUN( op ) ); + break; + } + break; + } + break; + case OP_LB: + sprintf( buffer, "lb %s,%s", s_cpugenreg[ INS_RT( op ) ], effective_address( state, pc, op ) ); + break; + case OP_LH: + sprintf( buffer, "lh %s,%s", s_cpugenreg[ INS_RT( op ) ], effective_address( state, pc, op ) ); + break; + case OP_LWL: + sprintf( buffer, "lwl %s,%s", s_cpugenreg[ INS_RT( op ) ], effective_address( state, pc, op ) ); + break; + case OP_LW: + sprintf( buffer, "lw %s,%s", s_cpugenreg[ INS_RT( op ) ], effective_address( state, pc, op ) ); + break; + case OP_LBU: + sprintf( buffer, "lbu %s,%s", s_cpugenreg[ INS_RT( op ) ], effective_address( state, pc, op ) ); + break; + case OP_LHU: + sprintf( buffer, "lhu %s,%s", s_cpugenreg[ INS_RT( op ) ], effective_address( state, pc, op ) ); + break; + case OP_LWR: + sprintf( buffer, "lwr %s,%s", s_cpugenreg[ INS_RT( op ) ], effective_address( state, pc, op ) ); + break; + case OP_SB: + sprintf( buffer, "sb %s,%s", s_cpugenreg[ INS_RT( op ) ], effective_address( state, pc, op ) ); + break; + case OP_SH: + sprintf( buffer, "sh %s,%s", s_cpugenreg[ INS_RT( op ) ], effective_address( state, pc, op ) ); + break; + case OP_SWL: + sprintf( buffer, "swl %s,%s", s_cpugenreg[ INS_RT( op ) ], effective_address( state, pc, op ) ); + break; + case OP_SW: + sprintf( buffer, "sw %s,%s", s_cpugenreg[ INS_RT( op ) ], effective_address( state, pc, op ) ); + break; + case OP_SWR: + sprintf( buffer, "swr %s,%s", s_cpugenreg[ INS_RT( op ) ], effective_address( state, pc, op ) ); + break; + case OP_LWC0: + sprintf( buffer, "lwc0 %s,%s", s_cp0genreg[ INS_RT( op ) ], effective_address( state, pc, op ) ); + break; + case OP_LWC1: + sprintf( buffer, "lwc1 %s,%s", s_cp1genreg[ INS_RT( op ) ], effective_address( state, pc, op ) ); + break; + case OP_LWC2: + sprintf( buffer, "lwc2 %s,%s", s_cp2genreg[ INS_RT( op ) ], effective_address( state, pc, op ) ); + break; + case OP_LWC3: + sprintf( buffer, "lwc3 %s,%s", s_cp2genreg[ INS_RT( op ) ], effective_address( state, pc, op ) ); + break; + case OP_SWC0: + sprintf( buffer, "swc0 %s,%s", s_cp0genreg[ INS_RT( op ) ], effective_address( state, pc, op ) ); + break; + case OP_SWC1: + sprintf( buffer, "swc1 %s,%s", s_cp1genreg[ INS_RT( op ) ], effective_address( state, pc, op ) ); + break; + case OP_SWC2: + sprintf( buffer, "swc2 %s,%s", s_cp2genreg[ INS_RT( op ) ], effective_address( state, pc, op ) ); + break; + case OP_SWC3: + sprintf( buffer, "swc3 %s,%s", s_cp2genreg[ INS_RT( op ) ], effective_address( state, pc, op ) ); + break; + } + return ( opram - oldopram ) | flags | DASMFLAG_SUPPORTED; +} + +CPU_DISASSEMBLE( psxcpu_generic ) +{ + return DasmPSXCPU( NULL, buffer, pc, opram ); +} diff --git a/src/devices/cpu/psx/rcnt.c b/src/devices/cpu/psx/rcnt.c new file mode 100644 index 00000000000..31d3eb468e9 --- /dev/null +++ b/src/devices/cpu/psx/rcnt.c @@ -0,0 +1,261 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/* + * PlayStation Root Counter emulator + * + * Copyright 2003-2011 smf + * + */ + +#include "rcnt.h" + +#define VERBOSE_LEVEL ( 0 ) + +INLINE void ATTR_PRINTF(3,4) verboselog( running_machine& machine, int n_level, const char *s_fmt, ... ) +{ + if( VERBOSE_LEVEL >= n_level ) + { + va_list v; + char buf[ 32768 ]; + va_start( v, s_fmt ); + vsprintf( buf, s_fmt, v ); + va_end( v ); + logerror( "%s: %s", machine.describe_context(), buf ); + } +} + +const device_type PSX_RCNT = &device_creator; + +psxrcnt_device::psxrcnt_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, PSX_RCNT, "Sony PSX RCNT", tag, owner, clock, "psxrcnt", __FILE__), + m_irq0_handler(*this), + m_irq1_handler(*this), + m_irq2_handler(*this) +{ +} + +void psxrcnt_device::device_reset() +{ +} + +void psxrcnt_device::device_post_load() +{ + int n; + for( n = 0; n < 3; n++ ) + { + root_timer_adjust( n ); + } +} + +void psxrcnt_device::device_start() +{ + int n; + + m_irq0_handler.resolve_safe(); + m_irq1_handler.resolve_safe(); + m_irq2_handler.resolve_safe(); + + for( n = 0; n < 3; n++ ) + { + root_counter[ n ].timer = timer_alloc(n); + save_item(NAME(root_counter[ n ].n_count), n); + save_item(NAME(root_counter[ n ].n_mode), n); + save_item(NAME(root_counter[ n ].n_target), n); + save_item(NAME(root_counter[ n ].n_start), n); + root_counter[ n ].n_count = 0; + root_counter[ n ].n_mode = 0; + root_counter[ n ].n_target = 0; + root_counter[ n ].n_start = 0; + } +} + +WRITE32_MEMBER( psxrcnt_device::write ) +{ + int n_counter = offset / 4; + psx_root *root = &root_counter[ n_counter ]; + + verboselog( machine(), 1, "psx_counter_w ( %08x, %08x, %08x )\n", offset, data, mem_mask ); + + switch( offset % 4 ) + { + case 0: + root->n_count = data; + root->n_start = gettotalcycles(); + break; + case 1: + root->n_count = root_current( n_counter ); + root->n_start = gettotalcycles(); + + if( ( data & PSX_RC_RESET ) != 0 ) + { + data &= ~( PSX_RC_RESET | PSX_RC_STOP ); + root->n_count = 0; + } + + root->n_mode = data; + +#if 0 + if( ( data & 0xfca6 ) != 0 || + ( ( data & 0x0100 ) != 0 && n_counter != 0 && n_counter != 1 ) || + ( ( data & 0x0200 ) != 0 && n_counter != 2 ) ) + { + osd_printf_debug( "mode %d 0x%04x\n", n_counter, data & 0xfca6 ); + } +#endif + break; + case 2: + root->n_target = data; + break; + default: + verboselog( machine(), 0, "psx_counter_w( %08x, %08x, %08x ) unknown register\n", offset, mem_mask, data ); + return; + } + + root_timer_adjust( n_counter ); +} + +READ32_MEMBER( psxrcnt_device::read ) +{ + int n_counter = offset / 4; + psx_root *root = &root_counter[ n_counter ]; + UINT32 data; + + switch( offset % 4 ) + { + case 0: + data = root_current( n_counter ); + break; + case 1: + data = root->n_mode; + break; + case 2: + data = root->n_target; + break; + default: + verboselog( machine(), 0, "psx_counter_r( %08x, %08x ) unknown register\n", offset, mem_mask ); + return 0; + } + verboselog( machine(), 1, "psx_counter_r ( %08x, %08x ) %08x\n", offset, mem_mask, data ); + return data; +} + +UINT64 psxrcnt_device::gettotalcycles( void ) +{ + /* TODO: should return the start of the current tick. */ + return ((cpu_device *)owner())->total_cycles() * 2; +} + +int psxrcnt_device::root_divider( int n_counter ) +{ + psx_root *root = &root_counter[ n_counter ]; + + if( n_counter == 0 && ( root->n_mode & PSX_RC_CLC ) != 0 ) + { + /* TODO: pixel clock, probably based on resolution */ + return 5; + } + else if( n_counter == 1 && ( root->n_mode & PSX_RC_CLC ) != 0 ) + { + return 2150; + } + else if( n_counter == 2 && ( root->n_mode & PSX_RC_DIV ) != 0 ) + { + return 8; + } + return 1; +} + +UINT16 psxrcnt_device::root_current( int n_counter ) +{ + psx_root *root = &root_counter[ n_counter ]; + + if( ( root->n_mode & PSX_RC_STOP ) != 0 ) + { + return root->n_count; + } + else + { + UINT64 n_current; + n_current = gettotalcycles() - root->n_start; + n_current /= root_divider( n_counter ); + n_current += root->n_count; + if( n_current > 0xffff ) + { + /* TODO: use timer for wrap on 0x10000. */ + root->n_count = n_current; + root->n_start = gettotalcycles(); + } + return n_current; + } +} + +int psxrcnt_device::root_target( int n_counter ) +{ + psx_root *root = &root_counter[ n_counter ]; + + if( ( root->n_mode & PSX_RC_COUNTTARGET ) != 0 || + ( root->n_mode & PSX_RC_IRQTARGET ) != 0 ) + { + return root->n_target; + } + return 0x10000; +} + +void psxrcnt_device::root_timer_adjust( int n_counter ) +{ + psx_root *root = &root_counter[ n_counter ]; + + if( ( root->n_mode & PSX_RC_STOP ) != 0 ) + { + root->timer->adjust( attotime::never, n_counter); + } + else + { + int n_duration; + + n_duration = root_target( n_counter ) - root_current( n_counter ); + if( n_duration < 1 ) + { + n_duration += 0x10000; + } + + n_duration *= root_divider( n_counter ); + + // TODO: figure out if this should be calculated from the cpu clock for 50mhz boards? + root->timer->adjust( attotime::from_hz(33868800) * n_duration, n_counter); + } +} + +void psxrcnt_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + int n_counter = id; + psx_root *root = &root_counter[ n_counter ]; + + verboselog( machine(), 2, "root_finished( %d ) %04x\n", n_counter, root_current( n_counter ) ); + //if( ( root->n_mode & PSX_RC_COUNTTARGET ) != 0 ) + { + /* TODO: wrap should be handled differently as PSX_RC_COUNTTARGET & PSX_RC_IRQTARGET don't have to be the same. */ + root->n_count = 0; + root->n_start = gettotalcycles(); + } + if( ( root->n_mode & PSX_RC_REPEAT ) != 0 ) + { + root_timer_adjust( n_counter ); + } + if( ( root->n_mode & PSX_RC_IRQOVERFLOW ) != 0 || + ( root->n_mode & PSX_RC_IRQTARGET ) != 0 ) + { + switch( n_counter ) + { + case 0: + m_irq0_handler(1); + break; + case 1: + m_irq1_handler(1); + break; + case 2: + m_irq2_handler(1); + break; + } + } +} diff --git a/src/devices/cpu/psx/rcnt.h b/src/devices/cpu/psx/rcnt.h new file mode 100644 index 00000000000..4cdae90276a --- /dev/null +++ b/src/devices/cpu/psx/rcnt.h @@ -0,0 +1,76 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/* + * PlayStation Root Counter emulator + * + * Copyright 2003-2011 smf + * + */ + +#pragma once + +#ifndef __PSXRCNT_H__ +#define __PSXRCNT_H__ + +#include "emu.h" + +extern const device_type PSX_RCNT; + +#define MCFG_PSX_RCNT_IRQ0_HANDLER(_devcb) \ + devcb = &psxrcnt_device::set_irq0_handler(*device, DEVCB_##_devcb); +#define MCFG_PSX_RCNT_IRQ1_HANDLER(_devcb) \ + devcb = &psxrcnt_device::set_irq1_handler(*device, DEVCB_##_devcb); +#define MCFG_PSX_RCNT_IRQ2_HANDLER(_devcb) \ + devcb = &psxrcnt_device::set_irq2_handler(*device, DEVCB_##_devcb); +#define PSX_RC_STOP ( 0x01 ) +#define PSX_RC_RESET ( 0x04 ) /* guess */ +#define PSX_RC_COUNTTARGET ( 0x08 ) +#define PSX_RC_IRQTARGET ( 0x10 ) +#define PSX_RC_IRQOVERFLOW ( 0x20 ) +#define PSX_RC_REPEAT ( 0x40 ) +#define PSX_RC_CLC ( 0x100 ) +#define PSX_RC_DIV ( 0x200 ) + +struct psx_root +{ + emu_timer *timer; + UINT16 n_count; + UINT16 n_mode; + UINT16 n_target; + UINT64 n_start; +}; + +class psxrcnt_device : public device_t +{ +public: + psxrcnt_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // static configuration helpers + template static devcb_base &set_irq0_handler(device_t &device, _Object object) { return downcast(device).m_irq0_handler.set_callback(object); } + template static devcb_base &set_irq1_handler(device_t &device, _Object object) { return downcast(device).m_irq1_handler.set_callback(object); } + template static devcb_base &set_irq2_handler(device_t &device, _Object object) { return downcast(device).m_irq2_handler.set_callback(object); } + + DECLARE_WRITE32_MEMBER( write ); + DECLARE_READ32_MEMBER( read ); + +protected: + virtual void device_start(); + virtual void device_reset(); + virtual void device_post_load(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + +private: + psx_root root_counter[ 3 ]; + + UINT64 gettotalcycles( void ); + int root_divider( int n_counter ); + UINT16 root_current( int n_counter ); + int root_target( int n_counter ); + void root_timer_adjust( int n_counter ); + + devcb_write_line m_irq0_handler; + devcb_write_line m_irq1_handler; + devcb_write_line m_irq2_handler; +}; + +#endif diff --git a/src/devices/cpu/psx/sio.c b/src/devices/cpu/psx/sio.c new file mode 100644 index 00000000000..abf3c4b8bf1 --- /dev/null +++ b/src/devices/cpu/psx/sio.c @@ -0,0 +1,360 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/* + * PlayStation Serial I/O emulator + * + * Copyright 2003-2011 smf + * + */ + +#include "sio.h" + +#define VERBOSE_LEVEL ( 0 ) + +INLINE void ATTR_PRINTF(3,4) verboselog( running_machine& machine, int n_level, const char *s_fmt, ... ) +{ + if( VERBOSE_LEVEL >= n_level ) + { + va_list v; + char buf[ 32768 ]; + va_start( v, s_fmt ); + vsprintf( buf, s_fmt, v ); + va_end( v ); + logerror( "%s: %s", machine.describe_context(), buf ); + } +} + +const device_type PSX_SIO0 = &device_creator; +const device_type PSX_SIO1 = &device_creator; + +psxsio0_device::psxsio0_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + psxsio_device(mconfig, PSX_SIO0, "Sony PSX SIO-0", tag, owner, clock, "psxsio0", __FILE__) +{ +} + +psxsio1_device::psxsio1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + psxsio_device(mconfig, PSX_SIO1, "Sony PSX SIO-1", tag, owner, clock, "psxsio1", __FILE__) +{ +} + +psxsio_device::psxsio_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + m_status(SIO_STATUS_TX_EMPTY | SIO_STATUS_TX_RDY), + m_rxd(1), + m_irq_handler(*this), + m_sck_handler(*this), + m_txd_handler(*this), + m_dtr_handler(*this), + m_rts_handler(*this) +{ +} + +void psxsio_device::device_post_load() +{ + sio_timer_adjust(); +} + +void psxsio_device::device_start() +{ + m_irq_handler.resolve_safe(); + m_sck_handler.resolve_safe(); + m_txd_handler.resolve_safe(); + m_dtr_handler.resolve_safe(); + m_rts_handler.resolve_safe(); + + m_timer = timer_alloc( 0 ); + m_mode = 0; + m_control = 0; + m_baud = 0; + m_rx_data = 0; + m_tx_data = 0; + m_rx_shift = 0; + m_tx_shift = 0; + m_rx_bits = 0; + m_tx_bits = 0; + + save_item( NAME( m_status ) ); + save_item( NAME( m_mode ) ); + save_item( NAME( m_control ) ); + save_item( NAME( m_baud ) ); + save_item( NAME( m_rxd ) ); + save_item( NAME( m_rx_data ) ); + save_item( NAME( m_tx_data ) ); + save_item( NAME( m_rx_shift ) ); + save_item( NAME( m_tx_shift ) ); + save_item( NAME( m_rx_bits ) ); + save_item( NAME( m_tx_bits ) ); +} + +void psxsio_device::sio_interrupt() +{ + verboselog( machine(), 1, "sio_interrupt( %s )\n", tag() ); + m_status |= SIO_STATUS_IRQ; + m_irq_handler(1); +} + +void psxsio_device::sio_timer_adjust() +{ + attotime n_time; + + if( ( m_status & SIO_STATUS_TX_EMPTY ) == 0 || m_tx_bits != 0 ) + { + int n_prescaler; + + switch( m_mode & 3 ) + { + case 1: + n_prescaler = 1; + break; + case 2: + n_prescaler = 16; + break; + case 3: + n_prescaler = 64; + break; + default: + n_prescaler = 0; + break; + } + + if( m_baud != 0 && n_prescaler != 0 ) + { + n_time = attotime::from_hz(33868800) * (n_prescaler * m_baud); + verboselog( machine(), 2, "sio_timer_adjust( %s ) = %s ( %d x %d )\n", tag(), n_time.as_string(), n_prescaler, m_baud ); + } + else + { + n_time = attotime::never; + verboselog( machine(), 0, "sio_timer_adjust( %s ) invalid baud rate ( %d x %d )\n", tag(), n_prescaler, m_baud ); + } + } + else + { + n_time = attotime::never; + verboselog( machine(), 2, "sio_timer_adjust( %s ) finished\n", tag() ); + } + + m_timer->adjust( n_time ); +} + +void psxsio_device::device_timer(emu_timer &timer, device_timer_id tid, int param, void *ptr) +{ + verboselog( machine(), 2, "sio tick\n" ); + + if( m_tx_bits == 0 && + ( m_control & SIO_CONTROL_TX_ENA ) != 0 && + ( m_status & SIO_STATUS_TX_EMPTY ) == 0 ) + { + m_tx_bits = 8; + m_tx_shift = m_tx_data; + + if( type() == PSX_SIO0 ) + { + m_rx_bits = 8; + m_rx_shift = 0; + } + + m_status |= SIO_STATUS_TX_EMPTY; + m_status |= SIO_STATUS_TX_RDY; + } + + if( m_tx_bits != 0 ) + { + if( type() == PSX_SIO0 ) + { + m_sck_handler(0); + } + + m_txd_handler( m_tx_shift & 1 ); + m_tx_shift >>= 1; + m_tx_bits--; + + if( type() == PSX_SIO0 ) + { + m_sck_handler(1); + } + + if( m_tx_bits == 0 && + ( m_control & SIO_CONTROL_TX_IENA ) != 0 ) + { + sio_interrupt(); + } + } + + if( m_rx_bits != 0 ) + { + m_rx_shift = ( m_rx_shift >> 1 ) | ( m_rxd << 7 ); + m_rx_bits--; + + if( m_rx_bits == 0 ) + { + if( ( m_status & SIO_STATUS_RX_RDY ) != 0 ) + { + m_status |= SIO_STATUS_OVERRUN; + } + else + { + m_rx_data = m_rx_shift; + m_status |= SIO_STATUS_RX_RDY; + } + + if( ( m_control & SIO_CONTROL_RX_IENA ) != 0 ) + { + sio_interrupt(); + } + } + } + + sio_timer_adjust(); +} + +WRITE32_MEMBER( psxsio_device::write ) +{ + switch( offset % 4 ) + { + case 0: + verboselog( machine(), 1, "psx_sio_w %s data %02x (%08x)\n", tag(), data, mem_mask ); + m_tx_data = data; + m_status &= ~( SIO_STATUS_TX_RDY ); + m_status &= ~( SIO_STATUS_TX_EMPTY ); + sio_timer_adjust(); + break; + case 1: + verboselog( machine(), 0, "psx_sio_w( %08x, %08x, %08x )\n", offset, data, mem_mask ); + break; + case 2: + if( ACCESSING_BITS_0_15 ) + { + m_mode = data & 0xffff; + verboselog( machine(), 1, "psx_sio_w %s mode %04x\n", tag(), data & 0xffff ); + } + if( ACCESSING_BITS_16_31 ) + { + verboselog( machine(), 1, "psx_sio_w %s control %04x\n", tag(), data >> 16 ); + m_control = data >> 16; + + if( ( m_control & SIO_CONTROL_RESET ) != 0 ) + { + verboselog( machine(), 1, "psx_sio_w reset\n" ); + m_status |= SIO_STATUS_TX_EMPTY | SIO_STATUS_TX_RDY; + m_status &= ~( SIO_STATUS_RX_RDY | SIO_STATUS_OVERRUN | SIO_STATUS_IRQ ); + m_irq_handler(0); + + // toggle DTR to reset controllers, Star Ocean 2, at least, requires it + // the precise mechanism of the reset is unknown + // maybe it's related to the bottom 2 bits of control which are usually set + m_dtr_handler(0); + m_dtr_handler(1); + + m_tx_bits = 0; + m_rx_bits = 0; + m_txd_handler(1); + } + if( ( m_control & SIO_CONTROL_IACK ) != 0 ) + { + verboselog( machine(), 1, "psx_sio_w iack\n" ); + m_status &= ~( SIO_STATUS_IRQ ); + m_control &= ~( SIO_CONTROL_IACK ); + m_irq_handler(0); + } + if( ( m_control & SIO_CONTROL_DTR ) != 0 ) + { + m_dtr_handler(0); + } + else + { + m_dtr_handler(1); + } + } + break; + case 3: + if( ACCESSING_BITS_0_15 ) + { + verboselog( machine(), 0, "psx_sio_w( %08x, %08x, %08x )\n", offset, data, mem_mask ); + } + if( ACCESSING_BITS_16_31 ) + { + m_baud = data >> 16; + verboselog( machine(), 1, "psx_sio_w %s baud %04x\n", tag(), data >> 16 ); + } + break; + default: + verboselog( machine(), 0, "psx_sio_w( %08x, %08x, %08x )\n", offset, data, mem_mask ); + break; + } +} + +READ32_MEMBER( psxsio_device::read ) +{ + UINT32 data; + + switch( offset % 4 ) + { + case 0: + data = m_rx_data; + m_status &= ~( SIO_STATUS_RX_RDY ); + m_rx_data = 0xff; + verboselog( machine(), 1, "psx_sio_r %s data %02x (%08x)\n", tag(), data, mem_mask ); + break; + case 1: + data = m_status; + if( ACCESSING_BITS_0_15 ) + { + verboselog( machine(), 1, "psx_sio_r %s status %04x\n", tag(), data & 0xffff ); + } + if( ACCESSING_BITS_16_31 ) + { + verboselog( machine(), 0, "psx_sio_r( %08x, %08x ) %08x\n", offset, mem_mask, data ); + } + break; + case 2: + data = ( m_control << 16 ) | m_mode; + if( ACCESSING_BITS_0_15 ) + { + verboselog( machine(), 1, "psx_sio_r %s mode %04x\n", tag(), data & 0xffff ); + } + if( ACCESSING_BITS_16_31 ) + { + verboselog( machine(), 1, "psx_sio_r %s control %04x\n", tag(), data >> 16 ); + } + break; + case 3: + data = m_baud << 16; + if( ACCESSING_BITS_0_15 ) + { + verboselog( machine(), 0, "psx_sio_r( %08x, %08x ) %08x\n", offset, mem_mask, data ); + } + if( ACCESSING_BITS_16_31 ) + { + verboselog( machine(), 1, "psx_sio_r %s baud %04x\n", tag(), data >> 16 ); + } + break; + default: + data = 0; + verboselog( machine(), 0, "psx_sio_r( %08x, %08x ) %08x\n", offset, mem_mask, data ); + break; + } + return data; +} + +WRITE_LINE_MEMBER(psxsio_device::write_rxd) +{ + m_rxd = state; +} + +WRITE_LINE_MEMBER(psxsio_device::write_dsr) +{ + if (state) + { + m_status &= ~SIO_STATUS_DSR; + } + else if ((m_status & SIO_STATUS_DSR) == 0) + { + m_status |= SIO_STATUS_DSR; + + if( ( m_control & SIO_CONTROL_DSR_IENA ) != 0 ) + { + sio_interrupt(); + } + } +} diff --git a/src/devices/cpu/psx/sio.h b/src/devices/cpu/psx/sio.h new file mode 100644 index 00000000000..ebae81d5a93 --- /dev/null +++ b/src/devices/cpu/psx/sio.h @@ -0,0 +1,114 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/* + * PlayStation Serial I/O emulator + * + * Copyright 2003-2011 smf + * + */ + +#pragma once + +#ifndef __PSXSIO_H__ +#define __PSXSIO_H__ + +#include "emu.h" + +extern const device_type PSX_SIO0; +extern const device_type PSX_SIO1; + +#define MCFG_PSX_SIO_IRQ_HANDLER(_devcb) \ + devcb = &psxsio_device::set_irq_handler(*device, DEVCB_##_devcb); + +#define MCFG_PSX_SIO_SCK_HANDLER(_devcb) \ + devcb = &psxsio_device::set_sck_handler(*device, DEVCB_##_devcb); + +#define MCFG_PSX_SIO_TXD_HANDLER(_devcb) \ + devcb = &psxsio_device::set_txd_handler(*device, DEVCB_##_devcb); + +#define MCFG_PSX_SIO_DTR_HANDLER(_devcb) \ + devcb = &psxsio_device::set_dtr_handler(*device, DEVCB_##_devcb); + +#define MCFG_PSX_SIO_RTS_HANDLER(_devcb) \ + devcb = &psxsio_device::set_rts_handler(*device, DEVCB_##_devcb); + +#define SIO_BUF_SIZE ( 8 ) + +#define SIO_STATUS_TX_RDY ( 1 << 0 ) +#define SIO_STATUS_RX_RDY ( 1 << 1 ) +#define SIO_STATUS_TX_EMPTY ( 1 << 2 ) +#define SIO_STATUS_OVERRUN ( 1 << 4 ) +#define SIO_STATUS_DSR ( 1 << 7 ) +#define SIO_STATUS_IRQ ( 1 << 9 ) + +#define SIO_CONTROL_TX_ENA ( 1 << 0 ) +#define SIO_CONTROL_IACK ( 1 << 4 ) +#define SIO_CONTROL_RESET ( 1 << 6 ) +#define SIO_CONTROL_TX_IENA ( 1 << 10 ) +#define SIO_CONTROL_RX_IENA ( 1 << 11 ) +#define SIO_CONTROL_DSR_IENA ( 1 << 12 ) +#define SIO_CONTROL_DTR ( 1 << 13 ) + +class psxsio_device : public device_t +{ +public: + psxsio_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + // static configuration helpers + template static devcb_base &set_irq_handler(device_t &device, _Object object) { return downcast(device).m_irq_handler.set_callback(object); } + template static devcb_base &set_sck_handler(device_t &device, _Object object) { return downcast(device).m_sck_handler.set_callback(object); } + template static devcb_base &set_txd_handler(device_t &device, _Object object) { return downcast(device).m_txd_handler.set_callback(object); } + template static devcb_base &set_dtr_handler(device_t &device, _Object object) { return downcast(device).m_dtr_handler.set_callback(object); } + template static devcb_base &set_rts_handler(device_t &device, _Object object) { return downcast(device).m_rts_handler.set_callback(object); } + + DECLARE_WRITE32_MEMBER( write ); + DECLARE_READ32_MEMBER( read ); + + DECLARE_WRITE_LINE_MEMBER(write_rxd); + DECLARE_WRITE_LINE_MEMBER(write_dsr); + DECLARE_WRITE_LINE_MEMBER(write_cts); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + virtual void device_post_load(); + +private: + void sio_interrupt(); + void sio_timer_adjust(); + + UINT32 m_status; + UINT32 m_mode; + UINT32 m_control; + UINT32 m_baud; + int m_rxd; + UINT32 m_tx_data; + UINT32 m_rx_data; + UINT32 m_tx_shift; + UINT32 m_rx_shift; + UINT32 m_tx_bits; + UINT32 m_rx_bits; + + emu_timer *m_timer; + + devcb_write_line m_irq_handler; + devcb_write_line m_sck_handler; + devcb_write_line m_txd_handler; + devcb_write_line m_dtr_handler; + devcb_write_line m_rts_handler; +}; + +class psxsio0_device : public psxsio_device +{ +public: + psxsio0_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class psxsio1_device : public psxsio_device +{ +public: + psxsio1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +#endif diff --git a/src/devices/cpu/rsp/clamp.h b/src/devices/cpu/rsp/clamp.h new file mode 100644 index 00000000000..5b69b746a7d --- /dev/null +++ b/src/devices/cpu/rsp/clamp.h @@ -0,0 +1,37 @@ +// license:BSD-3-Clause +// copyright-holders:Tyler J. Stachecki,Ryan Holtz + +static inline rsp_vec_t sclamp_acc_to_mid(rsp_vec_t acc_mid, rsp_vec_t acc_hi) +{ + return _mm_packs_epi32( + _mm_unpacklo_epi16(acc_mid, acc_hi), + _mm_unpackhi_epi16(acc_mid, acc_hi) + ); +} + +static inline rsp_vec_t uclamp_acc(rsp_vec_t val, rsp_vec_t acc_mid, rsp_vec_t acc_hi, rsp_vec_t zero) +{ + rsp_vec_t hi_negative = _mm_srai_epi16(acc_hi, 15); // 0x0000 + rsp_vec_t mid_negative = _mm_srai_epi16(acc_mid, 15); // 0xffff + + // We don't have to clamp if the HI part of the + // accumulator is sign-extended down to the MD part. + rsp_vec_t hi_sign_check = _mm_cmpeq_epi16(hi_negative, acc_hi); // 0x0000 + rsp_vec_t mid_sign_check = _mm_cmpeq_epi16(hi_negative, mid_negative); // 0x0000 + rsp_vec_t clamp_mask = _mm_and_si128(mid_sign_check, hi_sign_check); // 0x0000 + + // Generate the value in the event we need to clamp. + // * hi_negative, mid_sign => xxxx + // * hi_negative, !mid_sign => 0000 + // * !hi_negative, mid_sign => FFFF + // * !hi_negative, !mid_sign => xxxx + rsp_vec_t clamped_val = _mm_cmpeq_epi16(hi_negative, zero); // 0xffff + +#if (defined(__SSE4_1__) || defined(_MSC_VER)) + return _mm_blendv_epi8(clamped_val, val, clamp_mask); +#else + clamped_val = _mm_and_si128(clamp_mask, val); + val = _mm_andnot_si128(clamp_mask, clamped_val); + return _mm_or_si128(val, clamped_val); +#endif +} diff --git a/src/devices/cpu/rsp/rsp.c b/src/devices/cpu/rsp/rsp.c new file mode 100644 index 00000000000..6419282a598 --- /dev/null +++ b/src/devices/cpu/rsp/rsp.c @@ -0,0 +1,809 @@ +// license:BSD-3-Clause +// copyright-holders:Ville Linde, Ryan Holtz +/* + Nintendo/SGI Reality Signal Processor (RSP) emulator + + Written by Ville Linde +*/ + +#include "emu.h" +#include "debugger.h" +#include "rsp.h" +#include "rspfe.h" +#include "rspcp2.h" +#include "rspcp2d.h" + + +const device_type RSP = &device_creator; + + +#define LOG_INSTRUCTION_EXECUTION 0 +#define SAVE_DISASM 0 +#define SAVE_DMEM 0 +#define RSP_TEST_SYNC 0 + +#define PRINT_VECREG(x) osd_printf_debug("V%d: %04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X\n", (x), \ + (UINT16)VREG_S((x),0), (UINT16)VREG_S((x),1), \ + (UINT16)VREG_S((x),2), (UINT16)VREG_S((x),3), \ + (UINT16)VREG_S((x),4), (UINT16)VREG_S((x),5), \ + (UINT16)VREG_S((x),6), (UINT16)VREG_S((x),7)) + +#define PRINT_ACCUM(x) osd_printf_debug("A%d: %08X|%08X\n", (x), \ + (UINT32)( ( ACCUM(x) >> 32 ) & 0x00000000ffffffff ), \ + (UINT32)( ACCUM(x) & 0x00000000ffffffff )) + +extern offs_t rsp_dasm_one(char *buffer, offs_t pc, UINT32 op); + + +#define SIMM16 ((INT32)(INT16)(op)) +#define UIMM16 ((UINT16)(op)) +#define UIMM26 (op & 0x03ffffff) + +#define RSVAL (m_rsp_state->r[RSREG]) +#define RTVAL (m_rsp_state->r[RTREG]) +#define RDVAL (m_rsp_state->r[RDREG]) + +#define JUMP_ABS(addr) { m_nextpc = 0x04001000 | (((addr) << 2) & 0xfff); } +#define JUMP_ABS_L(addr,l) { m_nextpc = 0x04001000 | (((addr) << 2) & 0xfff); m_rsp_state->r[l] = m_rsp_state->pc + 4; } +#define JUMP_REL(offset) { m_nextpc = 0x04001000 | ((m_rsp_state->pc + ((offset) << 2)) & 0xfff); } +#define JUMP_REL_L(offset,l) { m_nextpc = 0x04001000 | ((m_rsp_state->pc + ((offset) << 2)) & 0xfff); m_rsp_state->r[l] = m_rsp_state->pc + 4; } +#define JUMP_PC(addr) { m_nextpc = 0x04001000 | ((addr) & 0xfff); } +#define JUMP_PC_L(addr,l) { m_nextpc = 0x04001000 | ((addr) & 0xfff); m_rsp_state->r[l] = m_rsp_state->pc + 4; } +#define LINK(l) { m_rsp_state->r[l] = m_rsp_state->pc + 4; } + +#define CARRY_FLAG(x) (m_vflag[CARRY][x & 7] != 0 ? 0xffff : 0) +#define COMPARE_FLAG(x) (m_vflag[COMPARE][x & 7] != 0 ? 0xffff : 0) +#define CLIP1_FLAG(x) (m_vflag[CLIP1][x & 7] != 0 ? 0xffff : 0) +#define ZERO_FLAG(x) (m_vflag[ZERO][x & 7] != 0 ? 0xffff : 0) +#define CLIP2_FLAG(x) (m_vflag[CLIP2][x & 7] != 0 ? 0xffff : 0) + +#define CLEAR_CARRY_FLAGS() { memset(m_vflag[CARRY], 0, 16); } +#define CLEAR_COMPARE_FLAGS() { memset(m_vflag[COMPARE], 0, 16); } +#define CLEAR_CLIP1_FLAGS() { memset(m_vflag[CLIP1], 0, 16); } +#define CLEAR_ZERO_FLAGS() { memset(m_vflag[ZERO], 0, 16); } +#define CLEAR_CLIP2_FLAGS() { memset(m_vflag[CLIP2], 0, 16); } + +#define SET_CARRY_FLAG(x) { m_vflag[CARRY][x & 7] = 0xffff; } +#define SET_COMPARE_FLAG(x) { m_vflag[COMPARE][x & 7] = 0xffff; } +#define SET_CLIP1_FLAG(x) { m_vflag[CLIP1][x & 7] = 0xffff; } +#define SET_ZERO_FLAG(x) { m_vflag[ZERO][x & 7] = 0xffff; } +#define SET_CLIP2_FLAG(x) { m_vflag[CLIP2][x & 7] = 0xffff; } + +#define CLEAR_CARRY_FLAG(x) { m_vflag[CARRY][x & 7] = 0; } +#define CLEAR_COMPARE_FLAG(x) { m_vflag[COMPARE][x & 7] = 0; } +#define CLEAR_CLIP1_FLAG(x) { m_vflag[CLIP1][x & 7] = 0; } +#define CLEAR_ZERO_FLAG(x) { m_vflag[ZERO][x & 7] = 0; } +#define CLEAR_CLIP2_FLAG(x) { m_vflag[CLIP2][x & 7] = 0; } + +#define ROPCODE(pc) m_program->read_dword(pc) + + +/*************************************************************************** + DEBUGGING +***************************************************************************/ + +#define SINGLE_INSTRUCTION_MODE (0) + +/*************************************************************************** + CONSTANTS +***************************************************************************/ + +/* compilation boundaries -- how far back/forward does the analysis extend? */ +#define COMPILE_BACKWARDS_BYTES 128 +#define COMPILE_FORWARDS_BYTES 512 +#define COMPILE_MAX_INSTRUCTIONS ((COMPILE_BACKWARDS_BYTES/4) + (COMPILE_FORWARDS_BYTES/4)) +#define COMPILE_MAX_SEQUENCE 64 + +/* size of the execution code cache */ +#define CACHE_SIZE (32 * 1024 * 1024) + + +rsp_device::rsp_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : cpu_device(mconfig, RSP, "RSP", tag, owner, clock, "rsp", __FILE__) + , m_program_config("program", ENDIANNESS_BIG, 32, 32) + , m_cache(CACHE_SIZE + sizeof(internal_rsp_state)) + , m_drcuml(NULL) +// , m_drcuml(*this, m_cache, 0, 8, 32, 2) + , m_drcfe(NULL) + , m_drcoptions(0) + , m_cache_dirty(TRUE) + , m_numcycles(0) + , m_format(NULL) + , m_arg2(0) + , m_arg3(0) + , m_entry(NULL) + , m_nocode(NULL) + , m_out_of_cycles(NULL) + , m_read8(NULL) + , m_write8(NULL) + , m_read16(NULL) + , m_write16(NULL) + , m_read32(NULL) + , m_write32(NULL) + , m_rsp_state(NULL) + , m_exec_output(NULL) + , m_sr(0) + , m_step_count(0) + , m_ppc(0) + , m_nextpc(0) + , m_dmem32(NULL) + , m_dmem16(NULL) + , m_dmem8(NULL) + , m_imem32(NULL) + , m_imem16(NULL) + , m_imem8(NULL) + , m_debugger_temp(0) + , m_dp_reg_r_func(*this) + , m_dp_reg_w_func(*this) + , m_sp_reg_r_func(*this) + , m_sp_reg_w_func(*this) + , m_sp_set_status_func(*this) +{ +} + +offs_t rsp_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( rsp ); + return CPU_DISASSEMBLE_NAME( rsp )(this, buffer, pc, oprom, opram, options); +} + +void rsp_device::rsp_add_imem(UINT32 *base) +{ + m_imem32 = base; + m_imem16 = (UINT16*)base; + m_imem8 = (UINT8*)base; +} + +void rsp_device::rsp_add_dmem(UINT32 *base) +{ + m_dmem32 = base; + m_dmem16 = (UINT16*)base; + m_dmem8 = (UINT8*)base; +} + +UINT8 rsp_device::DM_READ8(UINT32 address) +{ + UINT8 ret = m_dmem8[BYTE4_XOR_BE(address & 0xfff)]; + //printf("R8:%08x=%02x\n", address, ret); + return ret; +} + +UINT16 rsp_device::DM_READ16(UINT32 address) +{ + UINT16 ret; + address &= 0xfff; + ret = m_dmem8[BYTE4_XOR_BE(address)] << 8; + ret |= m_dmem8[BYTE4_XOR_BE(address + 1)]; + //printf("R16:%08x=%04x\n", address, ret); + return ret; +} + +UINT32 rsp_device::DM_READ32(UINT32 address) +{ + UINT32 ret; + address &= 0xfff; + ret = m_dmem8[BYTE4_XOR_BE(address)] << 24; + ret |= m_dmem8[BYTE4_XOR_BE(address + 1)] << 16; + ret |= m_dmem8[BYTE4_XOR_BE(address + 2)] << 8; + ret |= m_dmem8[BYTE4_XOR_BE(address + 3)]; + //printf("R32:%08x=%08x\n", address, ret); + return ret; +} + +void rsp_device::DM_WRITE8(UINT32 address, UINT8 data) +{ + address &= 0xfff; + m_dmem8[BYTE4_XOR_BE(address)] = data; + //printf("W8:%08x=%02x\n", address, data); +} + +void rsp_device::DM_WRITE16(UINT32 address, UINT16 data) +{ + address &= 0xfff; + m_dmem8[BYTE4_XOR_BE(address)] = data >> 8; + m_dmem8[BYTE4_XOR_BE(address + 1)] = data & 0xff; + //printf("W16:%08x=%04x\n", address, data); +} + +void rsp_device::DM_WRITE32(UINT32 address, UINT32 data) +{ + address &= 0xfff; + m_dmem8[BYTE4_XOR_BE(address)] = data >> 24; + m_dmem8[BYTE4_XOR_BE(address + 1)] = (data >> 16) & 0xff; + m_dmem8[BYTE4_XOR_BE(address + 2)] = (data >> 8) & 0xff; + m_dmem8[BYTE4_XOR_BE(address + 3)] = data & 0xff; + //printf("W32:%08x=%08x\n", address, data); +} + +UINT8 rsp_device::READ8(UINT32 address) +{ + UINT8 ret; + address &= 0xfff; + ret = m_program->read_byte(address); + //printf("R8:%08x=%02x\n", address, ret); + return ret; +} + +UINT16 rsp_device::READ16(UINT32 address) +{ + UINT16 ret; + address &= 0xfff; + + ret = (m_program->read_byte(address) << 8) | (m_program->read_byte(address + 1) & 0xff); + + //printf("R16:%08x=%04x\n", address, ret); + return ret; +} + +UINT32 rsp_device::READ32(UINT32 address) +{ + UINT32 ret; + address &= 0xfff; + + ret = (m_program->read_byte(address) << 24) | + (m_program->read_byte(address + 1) << 16) | + (m_program->read_byte(address + 2) << 8) | + (m_program->read_byte(address + 3) << 0); + + //printf("R32:%08x=%08x\n", address, ret); + return ret; +} + +void rsp_device::WRITE8(UINT32 address, UINT8 data) +{ + address &= 0xfff; + m_program->write_byte(address, data); + //printf("W8:%08x=%02x\n", address, data); +} + +void rsp_device::WRITE16(UINT32 address, UINT16 data) +{ + address &= 0xfff; + + m_program->write_byte(address, data >> 8); + m_program->write_byte(address + 1, data & 0xff); + //printf("W16:%08x=%04x\n", address, data); +} + +void rsp_device::WRITE32(UINT32 address, UINT32 data) +{ + address &= 0xfff; + + m_program->write_byte(address, data >> 24); + m_program->write_byte(address + 1, (data >> 16) & 0xff); + m_program->write_byte(address + 2, (data >> 8) & 0xff); + m_program->write_byte(address + 3, data & 0xff); + //printf("W32:%08x=%08x\n", address, data); +} + +/*****************************************************************************/ + +UINT32 rsp_device::get_cop0_reg(int reg) +{ + reg &= 0xf; + if (reg < 8) + { + return m_sp_reg_r_func(reg, 0xffffffff); + } + else if (reg >= 8 && reg < 16) + { + return m_dp_reg_r_func(reg - 8, 0xffffffff); + } + + return 0; +} + +void rsp_device::set_cop0_reg(int reg, UINT32 data) +{ + reg &= 0xf; + if (reg < 8) + { + m_sp_reg_w_func(reg, data, 0xffffffff); + } + else if (reg >= 8 && reg < 16) + { + m_dp_reg_w_func(reg - 8, data, 0xffffffff); + } +} + +void rsp_device::unimplemented_opcode(UINT32 op) +{ + if ((machine().debug_flags & DEBUG_FLAG_ENABLED) != 0) + { + char string[200]; + rsp_dasm_one(string, m_ppc, op); + osd_printf_debug("%08X: %s\n", m_ppc, string); + } + +#if SAVE_DISASM + { + char string[200]; + int i; + FILE *dasm; + dasm = fopen("rsp_disasm.txt", "wt"); + + for (i=0; i < 0x1000; i+=4) + { + UINT32 opcode = ROPCODE(0x04001000 + i); + rsp_dasm_one(string, 0x04001000 + i, opcode); + fprintf(dasm, "%08X: %08X %s\n", 0x04001000 + i, opcode, string); + } + fclose(dasm); + } +#endif +#if SAVE_DMEM + { + int i; + FILE *dmem; + dmem = fopen("rsp_dmem.bin", "wb"); + + for (i=0; i < 0x1000; i++) + { + fputc(READ8(rsp, 0x04000000 + i), dmem); + } + fclose(dmem); + } +#endif + + fatalerror("RSP: unknown opcode %02X (%08X) at %08X\n", op >> 26, op, m_ppc); +} + +/*****************************************************************************/ + +void rsp_device::resolve_cb() +{ + m_dp_reg_r_func.resolve(); + m_dp_reg_w_func.resolve(); + m_sp_reg_r_func.resolve(); + m_sp_reg_w_func.resolve(); + m_sp_set_status_func.resolve(); +} + +void rsp_device::device_start() +{ + m_isdrc = (mconfig().options().drc() && !mconfig().m_force_no_drc) ? true : false; + m_rsp_state = (internal_rsp_state *)m_cache.alloc_near(sizeof(internal_rsp_state)); + + if (LOG_INSTRUCTION_EXECUTION) + m_exec_output = fopen("rsp_execute.txt", "wt"); + + m_program = &space(AS_PROGRAM); + m_direct = &m_program->direct(); + resolve_cb(); + + if (m_isdrc) + { + m_cop2 = auto_alloc(machine(), rsp_cop2_drc(*this, machine())); + } + else + { + m_cop2 = auto_alloc(machine(), rsp_cop2(*this, machine())); + } + m_cop2->init(); + m_cop2->start(); + + // RSP registers should power on to a random state + for(int regIdx = 0; regIdx < 32; regIdx++ ) + { + m_rsp_state->r[regIdx] = 0; + } + + m_sr = RSP_STATUS_HALT; + m_step_count = 0; + + /* initialize the UML generator */ + UINT32 drc_flags = 0; + m_drcuml = auto_alloc(machine(), drcuml_state(*this, m_cache, drc_flags, 8, 32, 2)); + + /* add symbols for our stuff */ + m_drcuml->symbol_add(&m_rsp_state->pc, sizeof(m_rsp_state->pc), "pc"); + m_drcuml->symbol_add(&m_rsp_state->icount, sizeof(m_rsp_state->icount), "icount"); + for (int regnum = 0; regnum < 32; regnum++) + { + char buf[10]; + sprintf(buf, "r%d", regnum); + m_drcuml->symbol_add(&m_rsp_state->r[regnum], sizeof(m_rsp_state->r[regnum]), buf); + } + m_drcuml->symbol_add(&m_rsp_state->arg0, sizeof(m_rsp_state->arg0), "arg0"); + m_drcuml->symbol_add(&m_rsp_state->arg1, sizeof(m_rsp_state->arg1), "arg1"); + m_drcuml->symbol_add(&m_arg2, sizeof(m_arg2), "arg2"); + m_drcuml->symbol_add(&m_arg3, sizeof(m_arg3), "arg3"); + m_drcuml->symbol_add(&m_numcycles, sizeof(m_numcycles), "numcycles"); + + /* initialize the front-end helper */ + m_drcfe = auto_alloc(machine(), rsp_frontend(*this, COMPILE_BACKWARDS_BYTES, COMPILE_FORWARDS_BYTES, SINGLE_INSTRUCTION_MODE ? 1 : COMPILE_MAX_SEQUENCE)); + + /* compute the register parameters */ + for (int regnum = 0; regnum < 32; regnum++) + { + m_regmap[regnum] = (regnum == 0) ? uml::parameter(0) : uml::parameter::make_memory(&m_rsp_state->r[regnum]); + } + + /* mark the cache dirty so it is updated on next execute */ + m_cache_dirty = TRUE; + + state_add( RSP_PC, "PC", m_debugger_temp).callimport().callexport().formatstr("%08X"); + state_add( RSP_R0, "R0", m_rsp_state->r[0]).formatstr("%08X"); + state_add( RSP_R1, "R1", m_rsp_state->r[1]).formatstr("%08X"); + state_add( RSP_R2, "R2", m_rsp_state->r[2]).formatstr("%08X"); + state_add( RSP_R3, "R3", m_rsp_state->r[3]).formatstr("%08X"); + state_add( RSP_R4, "R4", m_rsp_state->r[4]).formatstr("%08X"); + state_add( RSP_R5, "R5", m_rsp_state->r[5]).formatstr("%08X"); + state_add( RSP_R6, "R6", m_rsp_state->r[6]).formatstr("%08X"); + state_add( RSP_R7, "R7", m_rsp_state->r[7]).formatstr("%08X"); + state_add( RSP_R8, "R8", m_rsp_state->r[8]).formatstr("%08X"); + state_add( RSP_R9, "R9", m_rsp_state->r[9]).formatstr("%08X"); + state_add( RSP_R10, "R10", m_rsp_state->r[10]).formatstr("%08X"); + state_add( RSP_R11, "R11", m_rsp_state->r[11]).formatstr("%08X"); + state_add( RSP_R12, "R12", m_rsp_state->r[12]).formatstr("%08X"); + state_add( RSP_R13, "R13", m_rsp_state->r[13]).formatstr("%08X"); + state_add( RSP_R14, "R14", m_rsp_state->r[14]).formatstr("%08X"); + state_add( RSP_R15, "R15", m_rsp_state->r[15]).formatstr("%08X"); + state_add( RSP_R16, "R16", m_rsp_state->r[16]).formatstr("%08X"); + state_add( RSP_R17, "R17", m_rsp_state->r[17]).formatstr("%08X"); + state_add( RSP_R18, "R18", m_rsp_state->r[18]).formatstr("%08X"); + state_add( RSP_R19, "R19", m_rsp_state->r[19]).formatstr("%08X"); + state_add( RSP_R20, "R20", m_rsp_state->r[20]).formatstr("%08X"); + state_add( RSP_R21, "R21", m_rsp_state->r[21]).formatstr("%08X"); + state_add( RSP_R22, "R22", m_rsp_state->r[22]).formatstr("%08X"); + state_add( RSP_R23, "R23", m_rsp_state->r[23]).formatstr("%08X"); + state_add( RSP_R24, "R24", m_rsp_state->r[24]).formatstr("%08X"); + state_add( RSP_R25, "R25", m_rsp_state->r[25]).formatstr("%08X"); + state_add( RSP_R26, "R26", m_rsp_state->r[26]).formatstr("%08X"); + state_add( RSP_R27, "R27", m_rsp_state->r[27]).formatstr("%08X"); + state_add( RSP_R28, "R28", m_rsp_state->r[28]).formatstr("%08X"); + state_add( RSP_R29, "R29", m_rsp_state->r[29]).formatstr("%08X"); + state_add( RSP_R30, "R30", m_rsp_state->r[30]).formatstr("%08X"); + state_add( RSP_R31, "R31", m_rsp_state->r[31]).formatstr("%08X"); + state_add( RSP_SR, "SR", m_sr).formatstr("%08X"); + state_add( RSP_NEXTPC, "NPC", m_debugger_temp).callimport().callexport().formatstr("%08X"); + state_add( RSP_STEPCNT, "STEP", m_step_count).formatstr("%08X"); + + state_add( RSP_V0, "V0", m_debugger_temp).formatstr("%39s"); + state_add( RSP_V1, "V1", m_debugger_temp).formatstr("%39s"); + state_add( RSP_V2, "V2", m_debugger_temp).formatstr("%39s"); + state_add( RSP_V3, "V3", m_debugger_temp).formatstr("%39s"); + state_add( RSP_V4, "V4", m_debugger_temp).formatstr("%39s"); + state_add( RSP_V5, "V5", m_debugger_temp).formatstr("%39s"); + state_add( RSP_V6, "V6", m_debugger_temp).formatstr("%39s"); + state_add( RSP_V7, "V7", m_debugger_temp).formatstr("%39s"); + state_add( RSP_V8, "V8", m_debugger_temp).formatstr("%39s"); + state_add( RSP_V9, "V9", m_debugger_temp).formatstr("%39s"); + state_add( RSP_V10, "V10", m_debugger_temp).formatstr("%39s"); + state_add( RSP_V11, "V11", m_debugger_temp).formatstr("%39s"); + state_add( RSP_V12, "V12", m_debugger_temp).formatstr("%39s"); + state_add( RSP_V13, "V13", m_debugger_temp).formatstr("%39s"); + state_add( RSP_V14, "V14", m_debugger_temp).formatstr("%39s"); + state_add( RSP_V15, "V15", m_debugger_temp).formatstr("%39s"); + state_add( RSP_V16, "V16", m_debugger_temp).formatstr("%39s"); + state_add( RSP_V17, "V17", m_debugger_temp).formatstr("%39s"); + state_add( RSP_V18, "V18", m_debugger_temp).formatstr("%39s"); + state_add( RSP_V19, "V19", m_debugger_temp).formatstr("%39s"); + state_add( RSP_V20, "V20", m_debugger_temp).formatstr("%39s"); + state_add( RSP_V21, "V21", m_debugger_temp).formatstr("%39s"); + state_add( RSP_V22, "V22", m_debugger_temp).formatstr("%39s"); + state_add( RSP_V23, "V23", m_debugger_temp).formatstr("%39s"); + state_add( RSP_V24, "V24", m_debugger_temp).formatstr("%39s"); + state_add( RSP_V25, "V25", m_debugger_temp).formatstr("%39s"); + state_add( RSP_V26, "V26", m_debugger_temp).formatstr("%39s"); + state_add( RSP_V27, "V27", m_debugger_temp).formatstr("%39s"); + state_add( RSP_V28, "V28", m_debugger_temp).formatstr("%39s"); + state_add( RSP_V29, "V29", m_debugger_temp).formatstr("%39s"); + state_add( RSP_V30, "V30", m_debugger_temp).formatstr("%39s"); + state_add( RSP_V31, "V31", m_debugger_temp).formatstr("%39s"); + + state_add( STATE_GENPC, "GENPC", m_debugger_temp).callimport().callexport().noshow(); + state_add( STATE_GENFLAGS, "GENFLAGS", m_debugger_temp).formatstr("%1s").noshow(); + state_add( STATE_GENSP, "GENSP", m_rsp_state->r[31]).noshow(); + state_add( STATE_GENPCBASE, "GENPCBASE", m_debugger_temp).callimport().callexport().noshow(); + + m_icountptr = &m_rsp_state->icount; +} + +void rsp_device::state_import(const device_state_entry &entry) +{ + switch (entry.index()) + { + case STATE_GENPC: + case RSP_PC: + m_rsp_state->pc = m_debugger_temp; + break; + + case STATE_GENPCBASE: + m_ppc = m_debugger_temp; + break; + + case RSP_NEXTPC: + m_nextpc = m_debugger_temp; + break; + } +} + + +void rsp_device::state_export(const device_state_entry &entry) +{ + switch (entry.index()) + { + case STATE_GENPC: + case RSP_PC: + m_debugger_temp = m_rsp_state->pc | 0x04000000; + break; + + case STATE_GENPCBASE: + m_debugger_temp = m_ppc | 0x04000000; + break; + + case RSP_NEXTPC: + m_debugger_temp = m_nextpc | 0x04000000; + break; + } +} + +void rsp_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + const int index = entry.index(); + if (index >= RSP_V0 && index <= RSP_V31) + { + m_cop2->state_string_export(index, str); + } + else if (index == STATE_GENFLAGS) + { + strprintf(str, "%s", ""); + } +} + +void rsp_device::device_stop() +{ +#if SAVE_DISASM + { + char string[200]; + int i; + FILE *dasm; + dasm = fopen("rsp_disasm.txt", "wt"); + + for (i=0; i < 0x1000; i+=4) + { + UINT32 opcode = ROPCODE(0x04001000 + i); + rsp_dasm_one(string, 0x04001000 + i, opcode); + fprintf(dasm, "%08X: %08X %s\n", 0x04001000 + i, opcode, string); + } + fclose(dasm); + } +#endif +#if SAVE_DMEM + { + int i; + FILE *dmem; +#if 0 + dmem = fopen("rsp_dmem.txt", "wt"); + + for (i=0; i < 0x1000; i+=4) + { + fprintf(dmem, "%08X: %08X\n", 0x04000000 + i, READ32(0x04000000 + i)); + } + fclose(dmem); +#endif + dmem = fopen("rsp_dmem.bin", "wb"); + + for (i=0; i < 0x1000; i++) + { + fputc(READ8(0x04000000 + i), dmem); + } + fclose(dmem); + } +#endif + + if (m_exec_output) + fclose(m_exec_output); + m_exec_output = NULL; + + /* clean up the DRC */ + if (m_drcuml) + { + auto_free(machine(), m_drcuml); + } + if (m_drcfe) + { + auto_free(machine(), m_drcfe); + } + + if (m_cop2) + { + auto_free(machine(), m_cop2); + } +} + +void rsp_device::device_reset() +{ + m_nextpc = ~0; +} + +void rsp_device::execute_run() +{ + if (m_isdrc) + { + execute_run_drc(); + return; + } + + m_rsp_state->pc = 0x4001000 | (m_rsp_state->pc & 0xfff); + + if( m_sr & ( RSP_STATUS_HALT | RSP_STATUS_BROKE ) ) + { + m_rsp_state->icount = MIN(m_rsp_state->icount, 0); + } + + while (m_rsp_state->icount > 0) + { + m_ppc = m_rsp_state->pc; + debugger_instruction_hook(this, m_rsp_state->pc); + + UINT32 op = ROPCODE(m_rsp_state->pc); + if (m_nextpc != ~0) + { + m_rsp_state->pc = m_nextpc; + m_nextpc = ~0; + } + else + { + m_rsp_state->pc += 4; + } + + switch (op >> 26) + { + case 0x00: /* SPECIAL */ + { + switch (op & 0x3f) + { + case 0x00: /* SLL */ if (RDREG) RDVAL = (UINT32)RTVAL << SHIFT; break; + case 0x02: /* SRL */ if (RDREG) RDVAL = (UINT32)RTVAL >> SHIFT; break; + case 0x03: /* SRA */ if (RDREG) RDVAL = (INT32)RTVAL >> SHIFT; break; + case 0x04: /* SLLV */ if (RDREG) RDVAL = (UINT32)RTVAL << (RSVAL & 0x1f); break; + case 0x06: /* SRLV */ if (RDREG) RDVAL = (UINT32)RTVAL >> (RSVAL & 0x1f); break; + case 0x07: /* SRAV */ if (RDREG) RDVAL = (INT32)RTVAL >> (RSVAL & 0x1f); break; + case 0x08: /* JR */ JUMP_PC(RSVAL); break; + case 0x09: /* JALR */ JUMP_PC_L(RSVAL, RDREG); break; + case 0x0d: /* BREAK */ + { + m_sp_set_status_func(0, 0x3, 0xffffffff); + m_rsp_state->icount = MIN(m_rsp_state->icount, 1); + break; + } + case 0x20: /* ADD */ if (RDREG) RDVAL = (INT32)(RSVAL + RTVAL); break; + case 0x21: /* ADDU */ if (RDREG) RDVAL = (INT32)(RSVAL + RTVAL); break; + case 0x22: /* SUB */ if (RDREG) RDVAL = (INT32)(RSVAL - RTVAL); break; + case 0x23: /* SUBU */ if (RDREG) RDVAL = (INT32)(RSVAL - RTVAL); break; + case 0x24: /* AND */ if (RDREG) RDVAL = RSVAL & RTVAL; break; + case 0x25: /* OR */ if (RDREG) RDVAL = RSVAL | RTVAL; break; + case 0x26: /* XOR */ if (RDREG) RDVAL = RSVAL ^ RTVAL; break; + case 0x27: /* NOR */ if (RDREG) RDVAL = ~(RSVAL | RTVAL); break; + case 0x2a: /* SLT */ if (RDREG) RDVAL = (INT32)RSVAL < (INT32)RTVAL; break; + case 0x2b: /* SLTU */ if (RDREG) RDVAL = (UINT32)RSVAL < (UINT32)RTVAL; break; + default: unimplemented_opcode(op); break; + } + break; + } + + case 0x01: /* REGIMM */ + { + switch (RTREG) + { + case 0x00: /* BLTZ */ if ((INT32)(RSVAL) < 0) JUMP_REL(SIMM16); break; + case 0x01: /* BGEZ */ if ((INT32)(RSVAL) >= 0) JUMP_REL(SIMM16); break; + case 0x10: /* BLTZAL */ if ((INT32)(RSVAL) < 0) JUMP_REL_L(SIMM16, 31); break; + case 0x11: /* BGEZAL */ if ((INT32)(RSVAL) >= 0) JUMP_REL_L(SIMM16, 31); break; + default: unimplemented_opcode(op); break; + } + break; + } + + case 0x02: /* J */ JUMP_ABS(UIMM26); break; + case 0x03: /* JAL */ JUMP_ABS_L(UIMM26, 31); break; + case 0x04: /* BEQ */ if (RSVAL == RTVAL) JUMP_REL(SIMM16); break; + case 0x05: /* BNE */ if (RSVAL != RTVAL) JUMP_REL(SIMM16); break; + case 0x06: /* BLEZ */ if ((INT32)RSVAL <= 0) JUMP_REL(SIMM16); break; + case 0x07: /* BGTZ */ if ((INT32)RSVAL > 0) JUMP_REL(SIMM16); break; + case 0x08: /* ADDI */ if (RTREG) RTVAL = (INT32)(RSVAL + SIMM16); break; + case 0x09: /* ADDIU */ if (RTREG) RTVAL = (INT32)(RSVAL + SIMM16); break; + case 0x0a: /* SLTI */ if (RTREG) RTVAL = (INT32)(RSVAL) < ((INT32)SIMM16); break; + case 0x0b: /* SLTIU */ if (RTREG) RTVAL = (UINT32)(RSVAL) < (UINT32)((INT32)SIMM16); break; + case 0x0c: /* ANDI */ if (RTREG) RTVAL = RSVAL & UIMM16; break; + case 0x0d: /* ORI */ if (RTREG) RTVAL = RSVAL | UIMM16; break; + case 0x0e: /* XORI */ if (RTREG) RTVAL = RSVAL ^ UIMM16; break; + case 0x0f: /* LUI */ if (RTREG) RTVAL = UIMM16 << 16; break; + + case 0x10: /* COP0 */ + { + switch ((op >> 21) & 0x1f) + { + case 0x00: /* MFC0 */ if (RTREG) RTVAL = get_cop0_reg(RDREG); break; + case 0x04: /* MTC0 */ set_cop0_reg(RDREG, RTVAL); break; + default: unimplemented_opcode(op); break; + } + break; + } + + case 0x12: /* COP2 */ + { + m_cop2->handle_cop2(op); + break; + } + + case 0x20: /* LB */ if (RTREG) RTVAL = (INT32)(INT8)READ8(RSVAL + SIMM16); break; + case 0x21: /* LH */ if (RTREG) RTVAL = (INT32)(INT16)READ16(RSVAL + SIMM16); break; + case 0x23: /* LW */ if (RTREG) RTVAL = READ32(RSVAL + SIMM16); break; + case 0x24: /* LBU */ if (RTREG) RTVAL = (UINT8)READ8(RSVAL + SIMM16); break; + case 0x25: /* LHU */ if (RTREG) RTVAL = (UINT16)READ16(RSVAL + SIMM16); break; + case 0x28: /* SB */ WRITE8(RSVAL + SIMM16, RTVAL); break; + case 0x29: /* SH */ WRITE16(RSVAL + SIMM16, RTVAL); break; + case 0x2b: /* SW */ WRITE32(RSVAL + SIMM16, RTVAL); break; + case 0x32: /* LWC2 */ m_cop2->handle_lwc2(op); break; + case 0x3a: /* SWC2 */ m_cop2->handle_swc2(op); break; + + default: + { + unimplemented_opcode(op); + break; + } + } + + if (LOG_INSTRUCTION_EXECUTION) + { + int i, l; + static UINT32 prev_regs[32]; + char string[200]; + rsp_dasm_one(string, m_ppc, op); + + fprintf(m_exec_output, "%08X: %s", m_ppc, string); + + l = strlen(string); + if (l < 36) + { + for (i=l; i < 36; i++) + { + fprintf(m_exec_output, " "); + } + } + + fprintf(m_exec_output, "| "); + + for (i=0; i < 32; i++) + { + if (m_rsp_state->r[i] != prev_regs[i]) + { + fprintf(m_exec_output, "R%d: %08X ", i, m_rsp_state->r[i]); + } + prev_regs[i] = m_rsp_state->r[i]; + } + + m_cop2->log_instruction_execution(); + + fprintf(m_exec_output, "\n"); + + } + + --m_rsp_state->icount; + + if( m_sr & RSP_STATUS_SSTEP ) + { + if( m_step_count ) + { + m_step_count--; + } + else + { + m_sr |= RSP_STATUS_BROKE; + } + } + + if( m_sr & ( RSP_STATUS_HALT | RSP_STATUS_BROKE ) ) + { + m_rsp_state->icount = MIN(m_rsp_state->icount, 0); + } + /*m_cop2->dump(op); + if (((op >> 26) & 0x3f) == 0x3a) + { + m_cop2->dump_dmem(); + }*/ + } +} diff --git a/src/devices/cpu/rsp/rsp.h b/src/devices/cpu/rsp/rsp.h new file mode 100644 index 00000000000..6bc588c2f01 --- /dev/null +++ b/src/devices/cpu/rsp/rsp.h @@ -0,0 +1,333 @@ +// license:BSD-3-Clause +// copyright-holders:Ville Linde, Ryan Holtz +/*************************************************************************** + + rsp.h + + Interface file for the universal machine language-based + Reality Signal Processor (RSP) emulator. + +***************************************************************************/ + +#pragma once + +#ifndef __RSP_H__ +#define __RSP_H__ + +#include "emu.h" +#include "cpu/drcfe.h" +#include "cpu/drcuml.h" + +/*************************************************************************** + REGISTER ENUMERATION +***************************************************************************/ + +enum +{ + RSP_PC = 1, + RSP_R0, + RSP_R1, + RSP_R2, + RSP_R3, + RSP_R4, + RSP_R5, + RSP_R6, + RSP_R7, + RSP_R8, + RSP_R9, + RSP_R10, + RSP_R11, + RSP_R12, + RSP_R13, + RSP_R14, + RSP_R15, + RSP_R16, + RSP_R17, + RSP_R18, + RSP_R19, + RSP_R20, + RSP_R21, + RSP_R22, + RSP_R23, + RSP_R24, + RSP_R25, + RSP_R26, + RSP_R27, + RSP_R28, + RSP_R29, + RSP_R30, + RSP_R31, + RSP_SR, + RSP_NEXTPC, + RSP_STEPCNT, + RSP_V0, RSP_V1, RSP_V2, RSP_V3, RSP_V4, RSP_V5, RSP_V6, RSP_V7, + RSP_V8, RSP_V9, RSP_V10, RSP_V11, RSP_V12, RSP_V13, RSP_V14, RSP_V15, + RSP_V16, RSP_V17, RSP_V18, RSP_V19, RSP_V20, RSP_V21, RSP_V22, RSP_V23, + RSP_V24, RSP_V25, RSP_V26, RSP_V27, RSP_V28, RSP_V29, RSP_V30, RSP_V31 +}; + +/*************************************************************************** + HELPER MACROS +***************************************************************************/ + +#define REG_LO 32 +#define REG_HI 33 + +#define RSREG ((op >> 21) & 31) +#define RTREG ((op >> 16) & 31) +#define RDREG ((op >> 11) & 31) +#define SHIFT ((op >> 6) & 31) + +#define FRREG ((op >> 21) & 31) +#define FTREG ((op >> 16) & 31) +#define FSREG ((op >> 11) & 31) +#define FDREG ((op >> 6) & 31) + +#define IS_SINGLE(o) (((o) & (1 << 21)) == 0) +#define IS_DOUBLE(o) (((o) & (1 << 21)) != 0) +#define IS_FLOAT(o) (((o) & (1 << 23)) == 0) +#define IS_INTEGRAL(o) (((o) & (1 << 23)) != 0) + +#define SIMMVAL ((INT16)op) +#define UIMMVAL ((UINT16)op) +#define LIMMVAL (op & 0x03ffffff) + +#define RSP_STATUS_HALT 0x0001 +#define RSP_STATUS_BROKE 0x0002 +#define RSP_STATUS_DMABUSY 0x0004 +#define RSP_STATUS_DMAFULL 0x0008 +#define RSP_STATUS_IOFULL 0x0010 +#define RSP_STATUS_SSTEP 0x0020 +#define RSP_STATUS_INTR_BREAK 0x0040 +#define RSP_STATUS_SIGNAL0 0x0080 +#define RSP_STATUS_SIGNAL1 0x0100 +#define RSP_STATUS_SIGNAL2 0x0200 +#define RSP_STATUS_SIGNAL3 0x0400 +#define RSP_STATUS_SIGNAL4 0x0800 +#define RSP_STATUS_SIGNAL5 0x1000 +#define RSP_STATUS_SIGNAL6 0x2000 +#define RSP_STATUS_SIGNAL7 0x4000 + +#define RSPDRC_STRICT_VERIFY 0x0001 /* verify all instructions */ + +#define MCFG_RSP_DP_REG_R_CB(_devcb) \ + devcb = &rsp_device::static_set_dp_reg_r_callback(*device, DEVCB_##_devcb); + +#define MCFG_RSP_DP_REG_W_CB(_devcb) \ + devcb = &rsp_device::static_set_dp_reg_w_callback(*device, DEVCB_##_devcb); + +#define MCFG_RSP_SP_REG_R_CB(_devcb) \ + devcb = &rsp_device::static_set_sp_reg_r_callback(*device, DEVCB_##_devcb); + +#define MCFG_RSP_SP_REG_W_CB(_devcb) \ + devcb = &rsp_device::static_set_sp_reg_w_callback(*device, DEVCB_##_devcb); + +#define MCFG_RSP_SP_SET_STATUS_CB(_devcb) \ + devcb = &rsp_device::static_set_status_callback(*device, DEVCB_##_devcb); + + +class rsp_frontend; +class rsp_cop2; + +class rsp_device : public cpu_device +{ + friend class rsp_frontend; + friend class rsp_cop2; + friend class rsp_cop2_drc; + +public: + // construction/destruction + rsp_device(const machine_config &mconfig, const char *_tag, device_t *_owner, UINT32 _clock); + + void resolve_cb(); + template static devcb_base &static_set_dp_reg_r_callback(device_t &device, _Object object) { return downcast(device).m_dp_reg_r_func.set_callback(object); } + template static devcb_base &static_set_dp_reg_w_callback(device_t &device, _Object object) { return downcast(device).m_dp_reg_w_func.set_callback(object); } + template static devcb_base &static_set_sp_reg_r_callback(device_t &device, _Object object) { return downcast(device).m_sp_reg_r_func.set_callback(object); } + template static devcb_base &static_set_sp_reg_w_callback(device_t &device, _Object object) { return downcast(device).m_sp_reg_w_func.set_callback(object); } + template static devcb_base &static_set_status_callback(device_t &device, _Object object) { return downcast(device).m_sp_set_status_func.set_callback(object); } + + void rspdrc_flush_drc_cache(); + void rspdrc_set_options(UINT32 options); + void rsp_add_dmem(UINT32 *base); + void rsp_add_imem(UINT32 *base); + + void ccfunc_read8(); + void ccfunc_read16(); + void ccfunc_read32(); + void ccfunc_write8(); + void ccfunc_write16(); + void ccfunc_write32(); + void ccfunc_get_cop0_reg(); + void ccfunc_set_cop0_reg(); + void ccfunc_unimplemented_opcode(); + void ccfunc_sp_set_status_cb(); + void ccfunc_unimplemented(); + + UINT8* get_dmem() { return m_dmem8; } + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_stop(); + + // device_execute_interface overrides + virtual UINT32 execute_min_cycles() const { return 1; } + virtual UINT32 execute_max_cycles() const { return 1; } + virtual UINT32 execute_input_lines() const { return 1; } + virtual UINT32 execute_default_irq_vector() const { return 0; } + virtual void execute_run(); + virtual void execute_set_input(int inputnum, int state) { } + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const { return (spacenum == AS_PROGRAM) ? &m_program_config : NULL; } + + // device_state_interface overrides + virtual void state_import(const device_state_entry &entry); + virtual void state_export(const device_state_entry &entry); + void state_string_export(const device_state_entry &entry, std::string &str); + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const { return 4; } + virtual UINT32 disasm_max_opcode_bytes() const { return 4; } + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + + void unimplemented_opcode(UINT32 op); + + /* internal compiler state */ + struct compiler_state + { + UINT32 cycles; /* accumulated cycles */ + UINT8 checkints; /* need to check interrupts before next instruction */ + UINT8 checksoftints; /* need to check software interrupts before next instruction */ + uml::code_label labelnum; /* index for local labels */ + }; + +private: + address_space_config m_program_config; + + /* fast RAM info */ + struct fast_ram_info + { + offs_t start; /* start of the RAM block */ + offs_t end; /* end of the RAM block */ + UINT8 readonly; /* TRUE if read-only */ + void * base; /* base in memory where the RAM lives */ + }; + + /* core state */ + drc_cache m_cache; /* pointer to the DRC code cache */ + drcuml_state * m_drcuml; /* DRC UML generator state */ + rsp_frontend * m_drcfe; /* pointer to the DRC front-end state */ + UINT32 m_drcoptions; /* configurable DRC options */ + + /* internal stuff */ + UINT8 m_cache_dirty; /* true if we need to flush the cache */ + + /* parameters for subroutines */ + UINT64 m_numcycles; /* return value from gettotalcycles */ + const char * m_format; /* format string for print_debug */ + UINT32 m_arg2; /* print_debug argument 3 */ + UINT32 m_arg3; /* print_debug argument 4 */ + + /* register mappings */ + uml::parameter m_regmap[34]; /* parameter to register mappings for all 32 integer registers */ + + /* subroutines */ + uml::code_handle * m_entry; /* entry point */ + uml::code_handle * m_nocode; /* nocode exception handler */ + uml::code_handle * m_out_of_cycles; /* out of cycles exception handler */ + uml::code_handle * m_read8; /* read byte */ + uml::code_handle * m_write8; /* write byte */ + uml::code_handle * m_read16; /* read half */ + uml::code_handle * m_write16; /* write half */ + uml::code_handle * m_read32; /* read word */ + uml::code_handle * m_write32; /* write word */ + + struct internal_rsp_state + { + UINT32 pc; + UINT32 r[35]; + UINT32 arg0; + UINT32 arg1; + UINT32 jmpdest; + int icount; + }; + + internal_rsp_state *m_rsp_state; + + FILE *m_exec_output; + + UINT32 m_sr; + UINT32 m_step_count; + + UINT32 m_ppc; + UINT32 m_nextpc; + + address_space *m_program; +protected: + direct_read_data *m_direct; + +private: + rsp_cop2 *m_cop2; + + UINT32 *m_dmem32; + UINT16 *m_dmem16; + UINT8 *m_dmem8; + + UINT32 *m_imem32; + UINT16 *m_imem16; + UINT8 *m_imem8; + + UINT32 m_debugger_temp; + bool m_isdrc; + + devcb_read32 m_dp_reg_r_func; + devcb_write32 m_dp_reg_w_func; + devcb_read32 m_sp_reg_r_func; + devcb_write32 m_sp_reg_w_func; + devcb_write32 m_sp_set_status_func; + + UINT8 READ8(UINT32 address); + UINT16 READ16(UINT32 address); + UINT32 READ32(UINT32 address); + void WRITE8(UINT32 address, UINT8 data); + void WRITE16(UINT32 address, UINT16 data); + void WRITE32(UINT32 address, UINT32 data); + UINT32 get_cop0_reg(int reg); + void set_cop0_reg(int reg, UINT32 data); + void load_fast_iregs(drcuml_block *block); + void save_fast_iregs(drcuml_block *block); + UINT8 DM_READ8(UINT32 address); + UINT16 DM_READ16(UINT32 address); + UINT32 DM_READ32(UINT32 address); + void DM_WRITE8(UINT32 address, UINT8 data); + void DM_WRITE16(UINT32 address, UINT16 data); + void DM_WRITE32(UINT32 address, UINT32 data); + void rspcom_init(); + void execute_run_drc(); + void code_flush_cache(); + void code_compile_block(offs_t pc); + void static_generate_entry_point(); + void static_generate_nocode_handler(); + void static_generate_out_of_cycles(); + void static_generate_memory_accessor(int size, int iswrite, const char *name, uml::code_handle *&handleptr); + void generate_update_cycles(drcuml_block *block, compiler_state *compiler, uml::parameter param, int allow_exception); + void generate_checksum_block(drcuml_block *block, compiler_state *compiler, const opcode_desc *seqhead, const opcode_desc *seqlast); + void generate_sequence_instruction(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); + void generate_delay_slot_and_branch(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, UINT8 linkreg); + void generate_branch(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); + int generate_vector_opcode(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); + int generate_opcode(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); + int generate_special(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); + int generate_regimm(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); + int generate_cop2(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); + int generate_cop0(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); + void log_add_disasm_comment(drcuml_block *block, UINT32 pc, UINT32 op); +}; + + +extern const device_type RSP; + + +#endif /* __RSP_H__ */ diff --git a/src/devices/cpu/rsp/rsp_dasm.c b/src/devices/cpu/rsp/rsp_dasm.c new file mode 100644 index 00000000000..2f455567588 --- /dev/null +++ b/src/devices/cpu/rsp/rsp_dasm.c @@ -0,0 +1,355 @@ +// license:BSD-3-Clause +// copyright-holders:Ville Linde, Ryan Holtz +/* + Nintendo/SGI RSP Disassembler + + Written by Ville Linde +*/ + +#include "emu.h" + +static const char *const reg[32] = +{ + "0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", + "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", + "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", + "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31" +}; + +static const char *const vreg[32] = +{ + " v0", " v1", " v2", " v3", " v4", " v5", " v6", " v7", + " v8", " v9", "v10", "v11", "v12", "v13", "v14", "v15", + "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", + "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31" +}; + +static const char *const cop0_regs[32] = +{ + "SP_MEM_ADDR", "SP_DRAM_ADDR", "SP_RD_LEN", "SP_WR_LEN", + "SP_STATUS", "SP_DMA_FULL", "SP_DMA_BUSY", "SP_SEMAPHORE", + "DPC_START", "DPC_END", "DPC_CURRENT", "DPC_STATUS", + "DPC_CLOCK", "DPC_BUFBUSY", "DPC_PIPEBUSY", "DPC_TMEM", + "???", "???", "???", "???", + "???", "???", "???", "???", + "???", "???", "???", "???", + "???", "???", "???", "???" +}; + +static const char *const element[16] = +{ + "", "[???]", "[00224466]", "[11335577]", "[00004444]", "[11115555]", "[22226666]", "[33337777]", + "[00000000]", "[11111111]", "[22222222]", "[33333333]", "[44444444]", "[55555555]", "[66666666]", "[77777777]" +}; + +static const char *const element2[16] = +{ + "01234567", "????????", "00224466", "11335577", "00004444", "11115555", "22226666", "33337777", + "00000000", "11111111", "22222222", "33333333", "44444444", "55555555", "66666666", "77777777" +}; + +INLINE char *signed_imm16(UINT32 op) +{ + static char temp[10]; + INT16 value = op & 0xffff; + + if (value < 0) + { + sprintf(temp, "-$%04x", -value); + } + else + { + sprintf(temp, "$%04x", value); + } + return temp; +} + + +static char *output; + +static void ATTR_PRINTF(1,2) print(const char *fmt, ...) +{ + va_list vl; + + va_start(vl, fmt); + output += vsprintf(output, fmt, vl); + va_end(vl); +} + +static void disasm_cop0(UINT32 op) +{ + int rt = (op >> 16) & 31; + int rd = (op >> 11) & 31; + + switch ((op >> 21) & 0x1f) + { + case 0x00: print("mfc0 %s, %s", reg[rt], cop0_regs[rd]); break; + case 0x04: print("mtc0 %s, %s", reg[rt], cop0_regs[rd]); break; + + default: print("??? (COP0)"); break; + } +} + +static void disasm_cop2(UINT32 op) +{ + int rt = (op >> 16) & 31; + int rd = (op >> 11) & 31; + int el = (op >> 21) & 0xf; + int dest = (op >> 6) & 0x1f; + int s1 = rd; + int s2 = rt; + + switch ((op >> 21) & 0x1f) + { + case 0x00: print("mfc2 %s, %s[%d]", reg[rt], vreg[rd], dest); break; + case 0x02: print("cfc2 %s, FLAG%d", reg[rt], rd); break; + case 0x04: print("mtc2 %s, %s[%d]", reg[rt], vreg[rd], dest); break; + case 0x06: print("ctc2 %s, FLAG%d", reg[rt], rd); break; + + case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17: + case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f: + { + switch (op & 0x3f) + { + case 0x00: print("vmulf %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break; + case 0x01: print("vmulu %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break; + case 0x02: print("vrndp %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break; + case 0x03: print("vmulq %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break; + case 0x04: print("vmudl %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break; + case 0x05: print("vmudm %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break; + case 0x06: print("vmudn %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break; + case 0x07: print("vmudh %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break; + case 0x08: print("vmacf %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break; + case 0x09: print("vmacu %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break; + case 0x0a: print("vrndn %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break; + case 0x0b: print("vmacq %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break; + case 0x0c: print("vmadl %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break; + case 0x0d: print("vmadm %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break; + case 0x0e: print("vmadn %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break; + case 0x0f: print("vmadh %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break; + case 0x10: print("vadd %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break; + case 0x11: print("vsub %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break; + case 0x12: print("vsut???"); break; + case 0x13: print("vabs %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break; + case 0x14: print("vaddc %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break; + case 0x15: print("vsubc %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break; + + case 0x1d: + { + switch (el) + { + case 8: print("vsaw %s, ACCUM_H", vreg[dest]); break; + case 9: print("vsaw %s, ACCUM_M", vreg[dest]); break; + case 10: print("vsaw %s, ACCUM_L", vreg[dest]); break; + default: print("vsaw %s, ???", vreg[dest]); break; + } + break; + } + + case 0x20: print("vlt %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break; + case 0x21: print("veq %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break; + case 0x22: print("vne %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break; + case 0x23: print("vge %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break; + case 0x24: print("vcl %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break; + case 0x25: print("vch %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break; + case 0x26: print("vcr %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break; + case 0x27: print("vmrg %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break; + case 0x28: print("vand %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break; + case 0x29: print("vnand %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break; + case 0x2a: print("vor %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break; + case 0x2b: print("vnor %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break; + case 0x2c: print("vxor %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break; + case 0x2d: print("vnxor %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break; + case 0x30: print("vrcp %s[%d], %s[%c]", vreg[dest], s1 & 7, vreg[s2], element2[el][7-(s1 & 7)]); break; + case 0x31: print("vrcpl %s[%d], %s[%c]", vreg[dest], s1 & 7, vreg[s2], element2[el][7-(s1 & 7)]); break; + case 0x32: print("vrcph %s[%d], %s[%c]", vreg[dest], s1 & 7, vreg[s2], element2[el][7-(s1 & 7)]); break; + case 0x33: print("vmov %s[%d], %s[%c]", vreg[dest], s1 & 7, vreg[s2], element2[el][7-(s1 & 7)]); break; + case 0x34: print("vrsq %s[%d], %s[%c]", vreg[dest], s1 & 7, vreg[s2], element2[el][7-(s1 & 7)]); break; + case 0x35: print("vrsql %s[%d], %s[%c]", vreg[dest], s1 & 7, vreg[s2], element2[el][7-(s1 & 7)]); break; + case 0x36: print("vrsqh %s[%d], %s[%c]", vreg[dest], s1 & 7, vreg[s2], element2[el][7-(s1 & 7)]); break; + case 0x37: print("vnop"); break; + default: print("??? (VECTOR OP)"); break; + } + break; + } + + default: print("??? (COP2)"); break; + } +} + +static void disasm_lwc2(UINT32 op) +{ + int dest = (op >> 16) & 0x1f; + int base = (op >> 21) & 0x1f; + int del = (op >> 7) & 0xf; + int offset = (op & 0x7f); + if (offset & 0x40) + offset |= 0xffffff80; + + switch ((op >> 11) & 0x1f) + { + case 0x00: print("lbv %s[%d], %s(%s)", vreg[dest], del, signed_imm16(offset * 1), reg[base]); break; + case 0x01: print("lsv %s[%d], %s(%s)", vreg[dest], del, signed_imm16(offset * 2), reg[base]); break; + case 0x02: print("llv %s[%d], %s(%s)", vreg[dest], del, signed_imm16(offset * 4), reg[base]); break; + case 0x03: print("ldv %s[%d], %s(%s)", vreg[dest], del, signed_imm16(offset * 8), reg[base]); break; + case 0x04: print("lqv %s[%d], %s(%s)", vreg[dest], del, signed_imm16(offset * 16), reg[base]); break; + case 0x05: print("lrv %s[%d], %s(%s)", vreg[dest], del, signed_imm16(offset * 16), reg[base]); break; + case 0x06: print("lpv %s[%d], %s(%s)", vreg[dest], del, signed_imm16(offset * 8), reg[base]); break; + case 0x07: print("luv %s[%d], %s(%s)", vreg[dest], del, signed_imm16(offset * 8), reg[base]); break; + case 0x08: print("lhv %s[%d], %s(%s)", vreg[dest], del, signed_imm16(offset * 16), reg[base]); break; + case 0x09: print("lfv %s[%d], %s(%s)", vreg[dest], del, signed_imm16(offset * 16), reg[base]); break; + case 0x0a: print("lwv %s[%d], %s(%s)", vreg[dest], del, signed_imm16(offset * 16), reg[base]); break; + case 0x0b: print("ltv %s[%d], %s(%s)", vreg[dest], del, signed_imm16(offset * 16), reg[base]); break; + default: print("??? (LWC2)"); break; + } +} + +static void disasm_swc2(UINT32 op) +{ + int dest = (op >> 16) & 0x1f; + int base = (op >> 21) & 0x1f; + int del = (op >> 7) & 0xf; + int offset = (op & 0x7f); + if (offset & 0x40) + offset |= 0xffffff80; + + switch ((op >> 11) & 0x1f) + { + case 0x00: print("sbv %s[%d], %s(%s)", vreg[dest], del, signed_imm16(offset * 1), reg[base]); break; + case 0x01: print("ssv %s[%d], %s(%s)", vreg[dest], del, signed_imm16(offset * 2), reg[base]); break; + case 0x02: print("slv %s[%d], %s(%s)", vreg[dest], del, signed_imm16(offset * 4), reg[base]); break; + case 0x03: print("sdv %s[%d], %s(%s)", vreg[dest], del, signed_imm16(offset * 8), reg[base]); break; + case 0x04: print("sqv %s[%d], %s(%s)", vreg[dest], del, signed_imm16(offset * 16), reg[base]); break; + case 0x05: print("srv %s[%d], %s(%s)", vreg[dest], del, signed_imm16(offset * 16), reg[base]); break; + case 0x06: print("spv %s[%d], %s(%s)", vreg[dest], del, signed_imm16(offset * 8), reg[base]); break; + case 0x07: print("suv %s[%d], %s(%s)", vreg[dest], del, signed_imm16(offset * 8), reg[base]); break; + case 0x08: print("shv %s[%d], %s(%s)", vreg[dest], del, signed_imm16(offset * 16), reg[base]); break; + case 0x09: print("sfv %s[%d], %s(%s)", vreg[dest], del, signed_imm16(offset * 16), reg[base]); break; + case 0x0a: print("swv %s[%d], %s(%s)", vreg[dest], del, signed_imm16(offset * 16), reg[base]); break; + case 0x0b: print("stv %s[%d], %s(%s)", vreg[dest], del, signed_imm16(offset * 16), reg[base]); break; + default: print("??? (SWC2)"); break; + } +} + +offs_t rsp_dasm_one(char *buffer, offs_t pc, UINT32 op) +{ + int rs = (op >> 21) & 31; + int rt = (op >> 16) & 31; + int rd = (op >> 11) & 31; + int shift = (op >> 6) & 31; + UINT32 flags = 0; + + output = buffer; + + switch (op >> 26) + { + case 0x00: // SPECIAL + { + switch (op & 0x3f) + { + case 0x00: + { + if (op == 0) + { + print("nop"); + } + else + { + print("sll %s, %s, %d", reg[rd], reg[rt], shift); + } + break; + } + case 0x02: print("srl %s, %s, %d", reg[rd], reg[rt], shift); break; + case 0x03: print("sra %s, %s, %d", reg[rd], reg[rt], shift); break; + case 0x04: print("sllv %s, %s, %s", reg[rd], reg[rt], reg[rs]); break; + case 0x06: print("srlv %s, %s, %s", reg[rd], reg[rt], reg[rs]); break; + case 0x07: print("srav %s, %s, %s", reg[rd], reg[rt], reg[rs]); break; + case 0x08: print("jr %s", reg[rs]); if (rs == 31) flags = DASMFLAG_STEP_OUT; break; + case 0x09: + { + if (rd == 31) + { + print("jalr %s", reg[rs]); + } + else + { + print("jalr %s, %s", reg[rs], reg[rd]); + } + flags = DASMFLAG_STEP_OVER | DASMFLAG_STEP_OVER_EXTRA(1); + break; + } + case 0x0d: print("break"); flags = DASMFLAG_STEP_OVER; break; + case 0x20: print("add %s, %s, %s", reg[rd], reg[rs], reg[rt]); break; + case 0x21: print("addu %s, %s, %s", reg[rd], reg[rs], reg[rt]); break; + case 0x22: print("sub %s, %s, %s", reg[rd], reg[rs], reg[rt]); break; + case 0x23: print("subu %s, %s, %s", reg[rd], reg[rs], reg[rt]); break; + case 0x24: print("and %s, %s, %s", reg[rd], reg[rs], reg[rt]); break; + case 0x25: print("or %s, %s, %s", reg[rd], reg[rs], reg[rt]); break; + case 0x26: print("xor %s, %s, %s", reg[rd], reg[rs], reg[rt]); break; + case 0x27: print("nor %s, %s, %s", reg[rd], reg[rs], reg[rt]); break; + case 0x2a: print("slt %s, %s, %s", reg[rd], reg[rs], reg[rt]); break; + case 0x2b: print("sltu %s, %s, %s", reg[rd], reg[rs], reg[rt]); break; + + default: print("???"); break; + } + break; + } + + case 0x01: // REGIMM + { + switch ((op >> 16) & 0x1f) + { + case 0x00: print("bltz %s, $%08X", reg[rs], pc + 4 + ((INT16)op << 2)); break; + case 0x01: print("bgez %s, $%08X", reg[rs], pc + 4 + ((INT16)op << 2)); break; + case 0x10: print("bltzal %s, $%08X", reg[rs], pc + 4 + ((INT16)op << 2)); break; + case 0x11: print("bgezal %s, $%08X", reg[rs], pc + 4 + ((INT16)op << 2)); break; + + default: print("???"); break; + } + break; + } + + case 0x02: print("j $%08X", (op & 0x03ffffff) << 2); break; + case 0x03: print("jal $%08X", (op & 0x03ffffff) << 2); break; + case 0x04: print("beq %s, %s, $%08X", reg[rs], reg[rt], pc + 4 + ((INT16)(op) << 2)); break; + case 0x05: print("bne %s, %s, $%08X", reg[rs], reg[rt], pc + 4 + ((INT16)(op) << 2)); break; + case 0x06: print("blez %s, $%08X", reg[rs], pc + 4 + ((INT16)(op) << 2)); break; + case 0x07: print("bgtz %s, $%08X", reg[rs], pc + 4 + ((INT16)(op) << 2)); break; + case 0x08: print("addi %s, %s, %s", reg[rt], reg[rs], signed_imm16(op)); break; + case 0x09: print("addiu %s, %s, %s", reg[rt], reg[rs], signed_imm16(op)); break; + case 0x0a: print("slti %s, %s, %s", reg[rt], reg[rs], signed_imm16(op)); break; + case 0x0b: print("sltiu %s, %s, %s", reg[rt], reg[rs], signed_imm16(op)); break; + case 0x0c: print("andi %s, %s, $%04X", reg[rt], reg[rs], (UINT16)(op)); break; + case 0x0d: print("ori %s, %s, $%04X", reg[rt], reg[rs], (UINT16)(op)); break; + case 0x0e: print("xori %s, %s, $%04X", reg[rt], reg[rs], (UINT16)(op)); break; + case 0x0f: print("lui %s, %s, $%04X", reg[rt], reg[rs], (UINT16)(op)); break; + + case 0x10: disasm_cop0(op); break; + case 0x12: disasm_cop2(op); break; + + case 0x20: print("lb %s, %s(%s)", reg[rt], signed_imm16(op), reg[rs]); break; + case 0x21: print("lh %s, %s(%s)", reg[rt], signed_imm16(op), reg[rs]); break; + case 0x23: print("lw %s, %s(%s)", reg[rt], signed_imm16(op), reg[rs]); break; + case 0x24: print("lbu %s, %s(%s)", reg[rt], signed_imm16(op), reg[rs]); break; + case 0x25: print("lhu %s, %s(%s)", reg[rt], signed_imm16(op), reg[rs]); break; + case 0x28: print("sb %s, %s(%s)", reg[rt], signed_imm16(op), reg[rs]); break; + case 0x29: print("sh %s, %s(%s)", reg[rt], signed_imm16(op), reg[rs]); break; + case 0x2b: print("sw %s, %s(%s)", reg[rt], signed_imm16(op), reg[rs]); break; + + case 0x32: disasm_lwc2(op); break; + case 0x3a: disasm_swc2(op); break; + + default: print("???"); break; + } + + return 4 | flags | DASMFLAG_SUPPORTED; +} + +/*****************************************************************************/ + +CPU_DISASSEMBLE( rsp ) +{ + UINT32 op = *(UINT32 *)opram; + op = BIG_ENDIANIZE_INT32(op); + return rsp_dasm_one(buffer, pc, op); +} diff --git a/src/devices/cpu/rsp/rspcp2.c b/src/devices/cpu/rsp/rspcp2.c new file mode 100644 index 00000000000..ab6afed4cbc --- /dev/null +++ b/src/devices/cpu/rsp/rspcp2.c @@ -0,0 +1,4222 @@ +// license:BSD-3-Clause +// copyright-holders:Ryan Holtz,Tyler J. Stachecki +/*************************************************************************** + + rspcp2.c + + Universal machine language-based Nintendo/SGI RSP COP2 emulator. + Written by Ryan Holtz of the MAME team. + +***************************************************************************/ + +#include "emu.h" +#include "rsp.h" +#include "rspcp2.h" + +#if USE_SIMD +#include + +const rsp_cop2::vec_helpers_t rsp_cop2::m_vec_helpers = { + { 0 }, + { // logic_mask + { 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff } + }, + { // vrsq_mask_table + { 0xffff, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0xffff, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0xffff, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0xffff, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0xffff, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0xffff, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0xffff, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0xffff } + }, + { // shuffle_keys + { 0x0100, 0x0302, 0x0504, 0x0706, 0x0908, 0x0b0a, 0x0d0c, 0x0f0e }, /* -- */ + { 0x0100, 0x0302, 0x0504, 0x0706, 0x0908, 0x0b0a, 0x0d0c, 0x0f0e }, /* -- */ + + { 0x0100, 0x0100, 0x0504, 0x0504, 0x0908, 0x0908, 0x0d0c, 0x0d0c }, /* 0q */ + { 0x0302, 0x0302, 0x0706, 0x0706, 0x0b0a, 0x0b0a, 0x0f0e, 0x0f0e }, /* 1q */ + + { 0x0100, 0x0100, 0x0100, 0x0100, 0x0908, 0x0908, 0x0908, 0x0908 }, /* 0h */ + { 0x0302, 0x0302, 0x0302, 0x0302, 0x0b0a, 0x0b0a, 0x0b0a, 0x0b0a }, /* 1h */ + { 0x0504, 0x0504, 0x0504, 0x0504, 0x0d0c, 0x0d0c, 0x0d0c, 0x0d0c }, /* 2h */ + { 0x0706, 0x0706, 0x0706, 0x0706, 0x0f0e, 0x0f0e, 0x0f0e, 0x0f0e }, /* 3h */ + + { 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100 }, /* 0w */ + { 0x0302, 0x0302, 0x0302, 0x0302, 0x0302, 0x0302, 0x0302, 0x0302 }, /* 1w */ + { 0x0504, 0x0504, 0x0504, 0x0504, 0x0504, 0x0504, 0x0504, 0x0504 }, /* 2w */ + { 0x0706, 0x0706, 0x0706, 0x0706, 0x0706, 0x0706, 0x0706, 0x0706 }, /* 3w */ + { 0x0908, 0x0908, 0x0908, 0x0908, 0x0908, 0x0908, 0x0908, 0x0908 }, /* 4w */ + { 0x0b0a, 0x0b0a, 0x0b0a, 0x0b0a, 0x0b0a, 0x0b0a, 0x0b0a, 0x0b0a }, /* 5w */ + { 0x0d0c, 0x0d0c, 0x0d0c, 0x0d0c, 0x0d0c, 0x0d0c, 0x0d0c, 0x0d0c }, /* 6w */ + { 0x0f0e, 0x0f0e, 0x0f0e, 0x0f0e, 0x0f0e, 0x0f0e, 0x0f0e, 0x0f0e } /* 7w */ + }, + { // sll_b2l_keys + { 0x0302, 0x0100, 0x0706, 0x0504, 0x0b0a, 0x0908, 0x0f0e, 0x0d0c }, + { 0x8003, 0x0201, 0x0007, 0x0605, 0x040b, 0x0a09, 0x080f, 0x0e0d }, + { 0x8080, 0x0302, 0x0100, 0x0706, 0x0504, 0x0b0a, 0x0908, 0x0f0e }, + { 0x8080, 0x8003, 0x0201, 0x0007, 0x0605, 0x040b, 0x0a09, 0x080f }, + + { 0x8080, 0x8080, 0x0302, 0x0100, 0x0706, 0x0504, 0x0b0a, 0x0908 }, + { 0x8080, 0x8080, 0x8003, 0x0201, 0x0007, 0x0605, 0x040b, 0x0a09 }, + { 0x8080, 0x8080, 0x8080, 0x0302, 0x0100, 0x0706, 0x0504, 0x0b0a }, + { 0x8080, 0x8080, 0x8080, 0x8003, 0x0201, 0x0007, 0x0605, 0x040b }, + + { 0x8080, 0x8080, 0x8080, 0x8080, 0x0302, 0x0100, 0x0706, 0x0504 }, + { 0x8080, 0x8080, 0x8080, 0x8080, 0x8003, 0x0201, 0x0007, 0x0605 }, + { 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x0302, 0x0100, 0x0706 }, + { 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8003, 0x0201, 0x0007 }, + + { 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x0302, 0x0100 }, + { 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8003, 0x0201 }, + { 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x0302 }, + { 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8003 }, + }, + { // sll_l2b_keys + { 0x0100, 0x0302, 0x0504, 0x0706, 0x0908, 0x0b0a, 0x0d0c, 0x0f0e }, + { 0x0201, 0x8003, 0x0605, 0x0007, 0x0a09, 0x040b, 0x0e0d, 0x080f }, + { 0x0302, 0x8080, 0x0706, 0x0100, 0x0b0a, 0x0504, 0x0f0e, 0x0908 }, + { 0x8003, 0x8080, 0x0007, 0x0201, 0x040b, 0x0605, 0x080f, 0x0a09 }, + + { 0x8080, 0x8080, 0x0100, 0x0302, 0x0504, 0x0706, 0x0908, 0x0b0a }, + { 0x8080, 0x8080, 0x0201, 0x8003, 0x0605, 0x0007, 0x0a09, 0x040b }, + { 0x8080, 0x8080, 0x0302, 0x8080, 0x0706, 0x0100, 0x0b0a, 0x0504 }, + { 0x8080, 0x8080, 0x8003, 0x8080, 0x0007, 0x0201, 0x040b, 0x0605 }, + + { 0x8080, 0x8080, 0x8080, 0x8080, 0x0100, 0x0302, 0x0504, 0x0706 }, + { 0x8080, 0x8080, 0x8080, 0x8080, 0x0201, 0x8003, 0x0605, 0x0007 }, + { 0x8080, 0x8080, 0x8080, 0x8080, 0x0302, 0x8080, 0x0706, 0x0100 }, + { 0x8080, 0x8080, 0x8080, 0x8080, 0x8003, 0x8080, 0x0007, 0x0201 }, + + { 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x0100, 0x0302 }, + { 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x0201, 0x8003 }, + { 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x0302, 0x8080 }, + { 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8003, 0x8080 }, + }, + { // srl_b2l_keys + { 0x0302, 0x0100, 0x0706, 0x0504, 0x0b0a, 0x0908, 0x0f0e, 0x0d0c }, + { 0x0201, 0x0007, 0x0605, 0x040b, 0x0a09, 0x080f, 0x0e0d, 0x0c80 }, + { 0x0100, 0x0706, 0x0504, 0x0b0a, 0x0908, 0x0f0e, 0x0d0c, 0x8080 }, + { 0x0007, 0x0605, 0x040b, 0x0a09, 0x080f, 0x0e0d, 0x0c80, 0x8080 }, + + { 0x0706, 0x0504, 0x0b0a, 0x0908, 0x0f0e, 0x0d0c, 0x8080, 0x8080 }, + { 0x0605, 0x040b, 0x0a09, 0x080f, 0x0e0d, 0x0c80, 0x8080, 0x8080 }, + { 0x0504, 0x0b0a, 0x0908, 0x0f0e, 0x0d0c, 0x8080, 0x8080, 0x8080 }, + { 0x040b, 0x0a09, 0x080f, 0x0e0d, 0x0c80, 0x8080, 0x8080, 0x8080 }, + + { 0x0b0a, 0x0908, 0x0f0e, 0x0d0c, 0x8080, 0x8080, 0x8080, 0x8080 }, + { 0x0a09, 0x080f, 0x0e0d, 0x0c80, 0x8080, 0x8080, 0x8080, 0x8080 }, + { 0x0908, 0x0f0e, 0x0d0c, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080 }, + { 0x080f, 0x0e0d, 0x0c80, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080 }, + + { 0x0f0e, 0x0d0c, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080 }, + { 0x0e0d, 0x0c80, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080 }, + { 0x0d0c, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080 }, + { 0x0c80, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080 }, + }, + { // ror_b2l_keys + { 0x0302, 0x0100, 0x0706, 0x0504, 0x0b0a, 0x0908, 0x0f0e, 0x0d0c }, + { 0x0201, 0x0007, 0x0605, 0x040b, 0x0a09, 0x080f, 0x0e0d, 0x0c03 }, + { 0x0100, 0x0706, 0x0504, 0x0b0a, 0x0908, 0x0f0e, 0x0d0c, 0x0302 }, + { 0x0007, 0x0605, 0x040b, 0x0a09, 0x080f, 0x0e0d, 0x0c03, 0x0201 }, + + { 0x0706, 0x0504, 0x0b0a, 0x0908, 0x0f0e, 0x0d0c, 0x0302, 0x0100 }, + { 0x0605, 0x040b, 0x0a09, 0x080f, 0x0e0d, 0x0c03, 0x0201, 0x0007 }, + { 0x0504, 0x0b0a, 0x0908, 0x0f0e, 0x0d0c, 0x0302, 0x0100, 0x0706 }, + { 0x040b, 0x0a09, 0x080f, 0x0e0d, 0x0c03, 0x0201, 0x0007, 0x0605 }, + + { 0x0b0a, 0x0908, 0x0f0e, 0x0d0c, 0x0302, 0x0100, 0x0706, 0x0504 }, + { 0x0a09, 0x080f, 0x0e0d, 0x0c03, 0x0201, 0x0007, 0x0605, 0x040b }, + { 0x0908, 0x0f0e, 0x0d0c, 0x0302, 0x0100, 0x0706, 0x0504, 0x0b0a }, + { 0x080f, 0x0e0d, 0x0c03, 0x0201, 0x0007, 0x0605, 0x040b, 0x0a09 }, + + { 0x0f0e, 0x0d0c, 0x0302, 0x0100, 0x0706, 0x0504, 0x0b0a, 0x0908 }, + { 0x0e0d, 0x0c03, 0x0201, 0x0007, 0x0605, 0x040b, 0x0a09, 0x080f }, + { 0x0d0c, 0x0302, 0x0100, 0x0706, 0x0504, 0x0b0a, 0x0908, 0x0f0e }, + { 0x0c03, 0x0201, 0x0007, 0x0605, 0x040b, 0x0a09, 0x080f, 0x0e0d }, + }, + { // rol_l2b_keys + { 0x0302, 0x0100, 0x0706, 0x0504, 0x0b0a, 0x0908, 0x0f0e, 0x0d0c }, + { 0x0003, 0x0e01, 0x0407, 0x0205, 0x080b, 0x0609, 0x0c0f, 0x0a0d }, + { 0x0100, 0x0f0e, 0x0504, 0x0302, 0x0908, 0x0706, 0x0d0c, 0x0b0a }, + { 0x0e01, 0x0c0f, 0x0205, 0x0003, 0x0609, 0x0407, 0x0a0d, 0x080b }, + + { 0x0f0e, 0x0d0c, 0x0302, 0x0100, 0x0706, 0x0504, 0x0b0a, 0x0908 }, + { 0x0c0f, 0x0a0d, 0x0003, 0x0e01, 0x0407, 0x0205, 0x080b, 0x0609 }, + { 0x0d0c, 0x0b0a, 0x0100, 0x0f0e, 0x0504, 0x0302, 0x0908, 0x0706 }, + { 0x0a0d, 0x080b, 0x0e01, 0x0c0f, 0x0205, 0x0003, 0x0609, 0x0407 }, + + { 0x0b0a, 0x0908, 0x0f0e, 0x0d0c, 0x0302, 0x0100, 0x0706, 0x0504 }, + { 0x080b, 0x0609, 0x0c0f, 0x0a0d, 0x0003, 0x0e01, 0x0407, 0x0205 }, + { 0x0908, 0x0706, 0x0d0c, 0x0b0a, 0x0100, 0x0f0e, 0x0504, 0x0302 }, + { 0x0609, 0x0407, 0x0a0d, 0x080b, 0x0e01, 0x0c0f, 0x0205, 0x0003 }, + + { 0x0706, 0x0504, 0x0b0a, 0x0908, 0x0f0e, 0x0d0c, 0x0302, 0x0100 }, + { 0x0407, 0x0205, 0x080b, 0x0609, 0x0c0f, 0x0a0d, 0x0003, 0x0e01 }, + { 0x0504, 0x0302, 0x0908, 0x0706, 0x0d0c, 0x0b0a, 0x0100, 0x0f0e }, + { 0x0205, 0x0003, 0x0609, 0x0407, 0x0a0d, 0x080b, 0x0e01, 0x0c0f }, + }, + { // ror_l2b_keys + { 0x0302, 0x0100, 0x0706, 0x0504, 0x0b0a, 0x0908, 0x0f0e, 0x0d0c }, + { 0x0205, 0x0003, 0x0609, 0x0407, 0x0a0d, 0x080b, 0x0e01, 0x0c0f }, + { 0x0504, 0x0302, 0x0908, 0x0706, 0x0d0c, 0x0b0a, 0x0100, 0x0f0e }, + { 0x0407, 0x0205, 0x080b, 0x0609, 0x0c0f, 0x0a0d, 0x0003, 0x0e01 }, + + { 0x0706, 0x0504, 0x0b0a, 0x0908, 0x0f0e, 0x0d0c, 0x0302, 0x0100 }, + { 0x0609, 0x0407, 0x0a0d, 0x080b, 0x0e01, 0x0c0f, 0x0205, 0x0003 }, + { 0x0908, 0x0706, 0x0d0c, 0x0b0a, 0x0100, 0x0f0e, 0x0504, 0x0302 }, + { 0x080b, 0x0609, 0x0c0f, 0x0a0d, 0x0003, 0x0e01, 0x0407, 0x0205 }, + + { 0x0b0a, 0x0908, 0x0f0e, 0x0d0c, 0x0302, 0x0100, 0x0706, 0x0504 }, + { 0x0a0d, 0x080b, 0x0e01, 0x0c0f, 0x0205, 0x0003, 0x0609, 0x0407 }, + { 0x0d0c, 0x0b0a, 0x0100, 0x0f0e, 0x0504, 0x0302, 0x0908, 0x0706 }, + { 0x0c0f, 0x0a0d, 0x0003, 0x0e01, 0x0407, 0x0205, 0x080b, 0x0609 }, + + { 0x0f0e, 0x0d0c, 0x0302, 0x0100, 0x0706, 0x0504, 0x0b0a, 0x0908 }, + { 0x0e01, 0x0c0f, 0x0205, 0x0003, 0x0609, 0x0407, 0x0a0d, 0x080b }, + { 0x0100, 0x0f0e, 0x0504, 0x0302, 0x0908, 0x0706, 0x0d0c, 0x0b0a }, + { 0x0003, 0x0e01, 0x0407, 0x0205, 0x080b, 0x0609, 0x0c0f, 0x0a0d }, + }, + { // qr_lut + { 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff }, + { 0xffff, 0xff00, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff }, + { 0xffff, 0x0000, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff }, + { 0xff00, 0x0000, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff }, + + { 0x0000, 0x0000, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, + { 0x0000, 0x0000, 0xffff, 0xff00, 0xffff, 0xffff, 0xffff, 0xffff }, + { 0x0000, 0x0000, 0xffff, 0x0000, 0xffff, 0xffff, 0xffff, 0xffff }, + { 0x0000, 0x0000, 0xff00, 0x0000, 0xffff, 0xffff, 0xffff, 0xffff }, + + { 0x0000, 0x0000, 0x0000, 0x0000, 0xffff, 0xffff, 0xffff, 0xffff }, + { 0x0000, 0x0000, 0x0000, 0x0000, 0xffff, 0xff00, 0xffff, 0xffff }, + { 0x0000, 0x0000, 0x0000, 0x0000, 0xffff, 0x0000, 0xffff, 0xffff }, + { 0x0000, 0x0000, 0x0000, 0x0000, 0xff00, 0x0000, 0xffff, 0xffff }, + + { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xffff, 0xffff }, + { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xffff, 0xff00 }, + { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xffff, 0x0000 }, + { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xff00, 0x0000 } + }, + { // bdls_lut - mask to denote which part of the vector to load/store. + { 0x0000, 0xff00, 0x0000, 0x0000 }, // B + { 0x0000, 0xffff, 0x0000, 0x0000 }, // S + { 0xffff, 0xffff, 0x0000, 0x0000 }, // L + { 0xffff, 0xffff, 0xffff, 0xffff } // D + }, + { // word_reverse + 0x0203, 0x0001, 0x0607, 0x0405, 0x0a0b, 0x0809, 0x0e0f, 0x0c0d + } +}; + +#if !(defined(__SSSE3__) || defined(_MSC_VER)) +// TODO: Highly optimized. More of a stopgap measure. +static inline rsp_vec_t sse2_pshufb(rsp_vec_t v, const UINT16 *keys) +{ + UINT8 dest[16]; + UINT8 temp[16]; + + _mm_storeu_si128((rsp_vec_t *) temp, v); + + for (UINT32 j = 0; j < 8; j++) + { + UINT16 key = keys[j]; + UINT8 key_hi = key >> 8; + UINT8 key_lo = key >> 0; + + dest[(j << 1) + 1] = key_hi == 0x80 ? 0x00 : temp[key_hi]; + dest[(j << 1) + 0] = key_lo == 0x80 ? 0x00 : temp[key_lo]; + } + + return _mm_loadu_si128((rsp_vec_t *) dest); +} + +rsp_vec_t rsp_cop2::vec_load_and_shuffle_operand(const UINT16* src, UINT32 element) +{ + if (element >= 8) // element => 0w ... 7w + { + UINT16 word_lo; + + memcpy(&word_lo, src + (element - 8), sizeof(word_lo)); + UINT64 dword = word_lo | ((UINT32) word_lo << 16); + + return _mm_shuffle_epi32(_mm_loadl_epi64((rsp_vec_t*) &dword), _MM_SHUFFLE(0,0,0,0)); + } + else if (element >= 4) // element => 0h ... 3h + { + UINT16 word_lo; + UINT16 word_hi; + + memcpy(&word_hi, src + element - 0, sizeof(word_hi)); + memcpy(&word_lo, src + element - 4, sizeof(word_lo)); + UINT64 dword = word_lo | ((UINT32) word_hi << 16); + + rsp_vec_t v = _mm_loadl_epi64((rsp_vec_t*) &dword); + v = _mm_shufflelo_epi16(v, _MM_SHUFFLE(1,1,0,0)); + return _mm_shuffle_epi32(v, _MM_SHUFFLE(1,1,0,0)); + } + else if (element >= 2) // element => 0q ... 1q + { + rsp_vec_t v = vec_load_unshuffled_operand(src); + + if (element == 2) { + v = _mm_shufflelo_epi16(v, _MM_SHUFFLE(3,3,1,1)); + v = _mm_shufflehi_epi16(v, _MM_SHUFFLE(3,3,1,1)); + } + else + { + v = _mm_shufflelo_epi16(v, _MM_SHUFFLE(2,2,0,0)); + v = _mm_shufflehi_epi16(v, _MM_SHUFFLE(2,2,0,0)); + } + + return v; + } + + return vec_load_unshuffled_operand(src); +} +#else +rsp_vec_t rsp_cop2::vec_load_and_shuffle_operand(const UINT16* src, UINT32 element) +{ + rsp_vec_t operand = _mm_load_si128((rsp_vec_t*) src); + rsp_vec_t key = _mm_load_si128((rsp_vec_t*) m_vec_helpers.shuffle_keys[element]); + + return _mm_shuffle_epi8(operand, key); +} +#endif +// +// SSSE3+ accelerated loads for group I. Byteswap big-endian to 2-byte +// little-endian vector. Start at vector element offset, discarding any +// wraparound as necessary. +// +// TODO: Reverse-engineer what happens when loads to vector elements must +// wraparound. Do we just discard the data, as below, or does the +// data effectively get rotated around the edge of the vector? +// +void rsp_cop2::vec_load_group1(UINT32 addr, UINT32 element, UINT16 *regp, rsp_vec_t reg, rsp_vec_t dqm) +{ + UINT32 offset = addr & 0x7; + UINT32 ror = offset - element; + + // Always load in 8-byte chunks to emulate wraparound. + rsp_vec_t data; + if (offset) { + UINT32 aligned_addr_lo = addr & ~0x7; + UINT32 aligned_addr_hi = (aligned_addr_lo + 8) & 0xFFF; + + data = _mm_loadl_epi64((rsp_vec_t *) (m_rsp.get_dmem() + aligned_addr_lo)); + rsp_vec_t temp = _mm_loadl_epi64((rsp_vec_t *) (m_rsp.get_dmem() + aligned_addr_hi)); + data = _mm_unpacklo_epi64(data, temp); + } + else + { + data = _mm_loadl_epi64((rsp_vec_t *) (m_rsp.get_dmem() + addr)); + } + + // Shift the DQM up to the point where we mux in the data. +#if !(defined(__SSSE3__) || defined(_MSC_VER)) + dqm = sse2_pshufb(dqm, m_vec_helpers.sll_b2l_keys[element]); +#else + rsp_vec_t ekey = _mm_load_si128((rsp_vec_t *) (m_vec_helpers.sll_b2l_keys[element])); + dqm = _mm_shuffle_epi8(dqm, ekey); +#endif + + // Align the data to the DQM so we can mask it in. +#if !(defined(__SSSE3__) || defined(_MSC_VER)) + data = sse2_pshufb(data, m_vec_helpers.ror_b2l_keys[ror & 0xF]); +#else + ekey = _mm_load_si128((rsp_vec_t *) (m_vec_helpers.ror_b2l_keys[ror & 0xF])); + data = _mm_shuffle_epi8(data, ekey); +#endif + + // Mask and mux in the data. +#if (defined(__SSE4_1__) || defined(_MSC_VER)) + reg = _mm_blendv_epi8(reg, data, dqm); +#else + data = _mm_and_si128(dqm, data); + reg = _mm_andnot_si128(dqm, reg); + reg = _mm_or_si128(data, reg); +#endif + + _mm_store_si128((rsp_vec_t *) regp, reg); +} + +// +// SSSE3+ accelerated loads for group II. +// +// TODO: Reverse-engineer what happens when loads to vector elements must +// wraparound. Do we just discard the data, as below, or does the +// data effectively get rotated around the edge of the vector? +// +// TODO: Reverse-engineer what happens when element != 0. +// +void rsp_cop2::vec_load_group2(UINT32 addr, UINT32 element, UINT16 *regp, rsp_vec_t reg, rsp_vec_t dqm, rsp_mem_request_type request_type) { + UINT32 offset = addr & 0x7; + rsp_vec_t data; + + // Always load in 8-byte chunks to emulate wraparound. + if (offset) { + UINT32 aligned_addr_lo = addr & ~0x7; + UINT32 aligned_addr_hi = (aligned_addr_lo + 8) & 0xFFF; + UINT64 datalow, datahigh; + + memcpy(&datalow, m_rsp.get_dmem() + aligned_addr_lo, sizeof(datalow)); + memcpy(&datahigh, m_rsp.get_dmem() + aligned_addr_hi, sizeof(datahigh)); + + // TODO: Test for endian issues? + datahigh >>= ((8 - offset) << 3); + datalow <<= (offset << 3); + datalow = datahigh | datalow; + + data = _mm_loadl_epi64((rsp_vec_t *) &datalow); + } + else + { + data = _mm_loadl_epi64((rsp_vec_t *) (m_rsp.get_dmem() + addr)); + } + + // "Unpack" the data. + rsp_vec_t zero = _mm_setzero_si128(); + data = _mm_unpacklo_epi8(zero, data); + + if (request_type != RSP_MEM_REQUEST_PACK) + { + data = _mm_srli_epi16(data, 1); + } + + data = _mm_shufflehi_epi16(data, _MM_SHUFFLE(0, 1, 2, 3)); + data = _mm_shufflelo_epi16(data, _MM_SHUFFLE(0, 1, 2, 3)); + + _mm_store_si128((rsp_vec_t *) regp, data); +} + +// +// SSSE3+ accelerated loads for group IV. Byteswap big-endian to 2-byte +// little-endian vector. Stop loading at quadword boundaries. +// +// TODO: Reverse-engineer what happens when loads from vector elements +// must wraparound (i.e., the address offset is small, starting +// element is large). +// +void rsp_cop2::vec_load_group4(UINT32 addr, UINT32 element, UINT16 *regp, rsp_vec_t reg, rsp_vec_t dqm, rsp_mem_request_type request_type) +{ + UINT32 aligned_addr = addr & 0xFF0; + UINT32 offset = addr & 0xF; + static UINT32 call_count = 0; + + rsp_vec_t data = _mm_load_si128((rsp_vec_t *) (m_rsp.get_dmem() + aligned_addr)); + + UINT32 ror; + if (request_type == RSP_MEM_REQUEST_QUAD) + { + ror = 16 - element + offset; + } + else + { + // TODO: How is this adjusted for LRV when e != 0? + dqm = _mm_cmpeq_epi8(_mm_setzero_si128(), dqm); + ror = 16 - offset; + } + +#if !(defined(__SSSE3__) || defined(_MSC_VER)) + data = sse2_pshufb(data, m_vec_helpers.ror_b2l_keys[ror & 0xF]); + dqm = sse2_pshufb(dqm, m_vec_helpers.ror_b2l_keys[ror & 0xF]); +#else + rsp_vec_t dkey = _mm_load_si128((rsp_vec_t *) (m_vec_helpers.ror_b2l_keys[ror & 0xF])); + data = _mm_shuffle_epi8(data, dkey); + dqm = _mm_shuffle_epi8(dqm, dkey); +#endif + + // Mask and mux in the data. +#if (defined(__SSE4_1__) || defined(_MSC_VER)) + data = _mm_blendv_epi8(reg, data, dqm); +#else + data = _mm_and_si128(dqm, data); + reg = _mm_andnot_si128(dqm, reg); + data = _mm_or_si128(data, reg); +#endif + + _mm_store_si128((rsp_vec_t *) regp, data); + + call_count++; +} + +// +// SSE3+ accelerated stores for group I. Byteswap 2-byte little-endian +// vector back to big-endian. Start at vector element offset, wrapping +// around the edge of the vector as necessary. +// +// TODO: Reverse-engineer what happens when stores from vector elements +// must wraparound. Do we just stop storing the data, or do we +// continue storing from the front of the vector, as below? +// +void rsp_cop2::vec_store_group1(UINT32 addr, UINT32 element, UINT16 *regp, rsp_vec_t reg, rsp_vec_t dqm) +{ + UINT32 offset = addr & 0x7; + UINT32 ror = element - offset; + + // Shift the DQM up to the point where we mux in the data. +#if !(defined(__SSSE3__) || defined(_MSC_VER)) + dqm = sse2_pshufb(dqm, m_vec_helpers.sll_l2b_keys[offset]); +#else + rsp_vec_t ekey = _mm_load_si128((rsp_vec_t *) (m_vec_helpers.sll_l2b_keys[offset])); + dqm = _mm_shuffle_epi8(dqm, ekey); +#endif + + // Rotate the reg to align with the DQM. +#if !(defined(__SSSE3__) || defined(_MSC_VER)) + reg = sse2_pshufb(reg, m_vec_helpers.ror_l2b_keys[ror & 0xF]); +#else + ekey = _mm_load_si128((rsp_vec_t *) (m_vec_helpers.ror_l2b_keys[ror & 0xF])); + reg = _mm_shuffle_epi8(reg, ekey); +#endif + + // Always load in 8-byte chunks to emulate wraparound. + rsp_vec_t data; + if (offset) + { + UINT32 aligned_addr_lo = addr & ~0x7; + UINT32 aligned_addr_hi = (aligned_addr_lo + 8) & 0xFFF; + + data = _mm_loadl_epi64((rsp_vec_t *) (m_rsp.get_dmem() + aligned_addr_lo)); + rsp_vec_t temp = _mm_loadl_epi64((rsp_vec_t *) (m_rsp.get_dmem() + aligned_addr_hi)); + data = _mm_unpacklo_epi64(data, temp); + + // Mask and mux in the data. +#if (defined(__SSE4_1__) || defined(_MSC_VER)) + data = _mm_blendv_epi8(data, reg, dqm); +#else + data = _mm_andnot_si128(dqm, data); + reg = _mm_and_si128(dqm, reg); + data = _mm_or_si128(data, reg); +#endif + + _mm_storel_epi64((rsp_vec_t *) (m_rsp.get_dmem() + aligned_addr_lo), data); + + data = _mm_srli_si128(data, 8); + _mm_storel_epi64((rsp_vec_t *) (m_rsp.get_dmem() + aligned_addr_hi), data); + } + else + { + data = _mm_loadl_epi64((rsp_vec_t *) (m_rsp.get_dmem() + addr)); + + // Mask and mux in the data. +#if (defined(__SSE4_1__) || defined(_MSC_VER)) + data = _mm_blendv_epi8(data, reg, dqm); +#else + data = _mm_andnot_si128(dqm, data); + reg = _mm_and_si128(dqm, reg); + data = _mm_or_si128(data, reg); +#endif + + _mm_storel_epi64((rsp_vec_t *) (m_rsp.get_dmem() + addr), data); + } +} + +// +// SSE3+ accelerated stores for group II. Byteswap 2-byte little-endian +// vector back to big-endian. Start at vector element offset, wrapping +// around the edge of the vector as necessary. +// +// TODO: Reverse-engineer what happens when stores from vector elements +// must wraparound. Do we just stop storing the data, or do we +// continue storing from the front of the vector, as below? +// +// TODO: Reverse-engineer what happens when element != 0. +// +void rsp_cop2::vec_store_group2(UINT32 addr, UINT32 element, UINT16 *regp, rsp_vec_t reg, rsp_vec_t dqm, rsp_mem_request_type request_type) { + // "Pack" the data. + if (request_type != RSP_MEM_REQUEST_PACK) + { + reg = _mm_slli_epi16(reg, 1); + } + + reg = _mm_srai_epi16(reg, 8); + reg = _mm_packs_epi16(reg, reg); + +#if !(defined(__SSSE3__) || defined(_MSC_VER)) + reg = sse2_pshufb(reg, m_vec_helpers.word_reverse); +#else + rsp_vec_t dkey = _mm_load_si128((rsp_vec_t *) (m_vec_helpers.word_reverse)); + reg = _mm_shuffle_epi8(reg, dkey); +#endif + + // TODO: Always store in 8-byte chunks to emulate wraparound. + _mm_storel_epi64((rsp_vec_t *) (m_rsp.get_dmem() + addr), reg); +} + +// +// SSE3+ accelerated stores for group IV. Byteswap 2-byte little-endian +// vector back to big-endian. Stop storing at quadword boundaries. +// +void rsp_cop2::vec_store_group4(UINT32 addr, UINT32 element, UINT16 *regp, rsp_vec_t reg, rsp_vec_t dqm, rsp_mem_request_type request_type) { + UINT32 aligned_addr = addr & 0xFF0; + UINT32 offset = addr & 0xF; + UINT32 rol = offset; + + rsp_vec_t data = _mm_load_si128((rsp_vec_t *) (m_rsp.get_dmem() + aligned_addr)); + + if (request_type == RSP_MEM_REQUEST_QUAD) + { + rol -= element; + } + else + { + // TODO: How is this adjusted for SRV when e != 0? + dqm = _mm_cmpeq_epi8(_mm_setzero_si128(), dqm); + } + +#if !(defined(__SSSE3__) || defined(_MSC_VER)) + reg = sse2_pshufb(reg, m_vec_helpers.rol_l2b_keys[rol & 0xF]); +#else + rsp_vec_t ekey = _mm_load_si128((rsp_vec_t *) (m_vec_helpers.rol_l2b_keys[rol & 0xF])); + reg = _mm_shuffle_epi8(reg, ekey); +#endif + + // Mask and mux out the data, write. +#if (defined(__SSE4_1__) || defined(_MSC_VER)) + data = _mm_blendv_epi8(data, reg, dqm); +#else + reg = _mm_and_si128(dqm, reg); + data = _mm_andnot_si128(dqm, data); + data = _mm_or_si128(data, reg); +#endif + + _mm_store_si128((rsp_vec_t *) (m_rsp.get_dmem() + aligned_addr), data); +} +#endif + +extern offs_t rsp_dasm_one(char *buffer, offs_t pc, UINT32 op); + +/*************************************************************************** + Helpful Defines +***************************************************************************/ + +#define VDREG ((op >> 6) & 0x1f) +#define VS1REG ((op >> 11) & 0x1f) +#define VS2REG ((op >> 16) & 0x1f) +#define EL ((op >> 21) & 0xf) + +#define RSVAL (m_rsp.m_rsp_state->r[RSREG]) +#define RTVAL (m_rsp.m_rsp_state->r[RTREG]) +#define RDVAL (m_rsp.m_rsp_state->r[RDREG]) + +#define VREG_B(reg, offset) m_v[(reg)].b[(offset)^1] +#define VREG_S(reg, offset) m_v[(reg)].s[(offset)] +#define VREG_L(reg, offset) m_v[(reg)].l[(offset)] + +#define R_VREG_B(reg, offset) m_v[(reg)].b[(offset)^1] +#define R_VREG_S(reg, offset) (INT16)m_v[(reg)].s[(offset)] +#define R_VREG_L(reg, offset) m_v[(reg)].l[(offset)] + +#define W_VREG_B(reg, offset, val) (m_v[(reg)].b[(offset)^1] = val) +#define W_VREG_S(reg, offset, val) (m_v[(reg)].s[(offset)] = val) +#define W_VREG_L(reg, offset, val) (m_v[(reg)].l[(offset)] = val) + +#define VEC_EL_2(x,z) (vector_elements_2[(x)][(z)]) + +#define CARRY 0 +#define COMPARE 1 +#define CLIP1 2 +#define ZERO 3 +#define CLIP2 4 + +#define ACCUM(x) m_accum[x].q +#define ACCUM_H(x) (UINT16)m_accum[x].w[3] +#define ACCUM_M(x) (UINT16)m_accum[x].w[2] +#define ACCUM_L(x) (UINT16)m_accum[x].w[1] +#define ACCUM_LL(x) (UINT16)m_accum[x].w[0] + +#define SET_ACCUM_H(v, x) m_accum[x].w[3] = v; +#define SET_ACCUM_M(v, x) m_accum[x].w[2] = v; +#define SET_ACCUM_L(v, x) m_accum[x].w[1] = v; +#define SET_ACCUM_LL(v, x) m_accum[x].w[0] = v; + +#define CARRY_FLAG(x) (m_vflag[CARRY][x & 7] != 0 ? 0xffff : 0) +#define COMPARE_FLAG(x) (m_vflag[COMPARE][x & 7] != 0 ? 0xffff : 0) +#define CLIP1_FLAG(x) (m_vflag[CLIP1][x & 7] != 0 ? 0xffff : 0) +#define ZERO_FLAG(x) (m_vflag[ZERO][x & 7] != 0 ? 0xffff : 0) +#define CLIP2_FLAG(x) (m_vflag[CLIP2][x & 7] != 0 ? 0xffff : 0) + +#define CLEAR_CARRY_FLAGS() { memset(m_vflag[CARRY], 0, 16); } +#define CLEAR_COMPARE_FLAGS() { memset(m_vflag[COMPARE], 0, 16); } +#define CLEAR_CLIP1_FLAGS() { memset(m_vflag[CLIP1], 0, 16); } +#define CLEAR_ZERO_FLAGS() { memset(m_vflag[ZERO], 0, 16); } +#define CLEAR_CLIP2_FLAGS() { memset(m_vflag[CLIP2], 0, 16); } + +#define SET_CARRY_FLAG(x) { m_vflag[CARRY][x & 7] = 0xffff; } +#define SET_COMPARE_FLAG(x) { m_vflag[COMPARE][x & 7] = 0xffff; } +#define SET_CLIP1_FLAG(x) { m_vflag[CLIP1][x & 7] = 0xffff; } +#define SET_ZERO_FLAG(x) { m_vflag[ZERO][x & 7] = 0xffff; } +#define SET_CLIP2_FLAG(x) { m_vflag[CLIP2][x & 7] = 0xffff; } + +#define CLEAR_CARRY_FLAG(x) { m_vflag[CARRY][x & 7] = 0; } +#define CLEAR_COMPARE_FLAG(x) { m_vflag[COMPARE][x & 7] = 0; } +#define CLEAR_CLIP1_FLAG(x) { m_vflag[CLIP1][x & 7] = 0; } +#define CLEAR_ZERO_FLAG(x) { m_vflag[ZERO][x & 7] = 0; } +#define CLEAR_CLIP2_FLAG(x) { m_vflag[CLIP2][x & 7] = 0; } + +#define WRITEBACK_RESULT() { \ + VREG_S(VDREG, 0) = m_vres[0]; \ + VREG_S(VDREG, 1) = m_vres[1]; \ + VREG_S(VDREG, 2) = m_vres[2]; \ + VREG_S(VDREG, 3) = m_vres[3]; \ + VREG_S(VDREG, 4) = m_vres[4]; \ + VREG_S(VDREG, 5) = m_vres[5]; \ + VREG_S(VDREG, 6) = m_vres[6]; \ + VREG_S(VDREG, 7) = m_vres[7]; \ +} + +#if !USE_SIMD +static const int vector_elements_2[16][8] = +{ + { 0, 1, 2, 3, 4, 5, 6, 7 }, // none + { 0, 1, 2, 3, 4, 5, 6, 7 }, // ??? + { 0, 0, 2, 2, 4, 4, 6, 6 }, // 0q + { 1, 1, 3, 3, 5, 5, 7, 7 }, // 1q + { 0, 0, 0, 0, 4, 4, 4, 4 }, // 0h + { 1, 1, 1, 1, 5, 5, 5, 5 }, // 1h + { 2, 2, 2, 2, 6, 6, 6, 6 }, // 2h + { 3, 3, 3, 3, 7, 7, 7, 7 }, // 3h + { 0, 0, 0, 0, 0, 0, 0, 0 }, // 0 + { 1, 1, 1, 1, 1, 1, 1, 1 }, // 1 + { 2, 2, 2, 2, 2, 2, 2, 2 }, // 2 + { 3, 3, 3, 3, 3, 3, 3, 3 }, // 3 + { 4, 4, 4, 4, 4, 4, 4, 4 }, // 4 + { 5, 5, 5, 5, 5, 5, 5, 5 }, // 5 + { 6, 6, 6, 6, 6, 6, 6, 6 }, // 6 + { 7, 7, 7, 7, 7, 7, 7, 7 }, // 7 +}; +#endif + +rsp_cop2::rsp_cop2(rsp_device &rsp, running_machine &machine) + : m_rsp(rsp) + , m_machine(machine) + , m_reciprocal_res(0) + , m_reciprocal_high(0) + , m_dp_allowed(0) +{ + memset(m_vres, 0, sizeof(m_vres)); + memset(m_v, 0, sizeof(m_v)); + memset(m_vflag, 0, sizeof(m_vflag)); + memset(m_accum, 0, sizeof(m_accum)); +#if USE_SIMD + memset(&m_acc, 0, sizeof(m_acc)); + memset(&m_flags, 0, sizeof(aligned_rsp_2vect_t) * 3); + m_div_out = 0; + m_div_in = 0; +#endif + m_rspcop2_state = (internal_rspcop2_state *)rsp.m_cache.alloc_near(sizeof(internal_rspcop2_state)); +} + +rsp_cop2::~rsp_cop2() +{ +} + +void rsp_cop2::init() +{ + CLEAR_CARRY_FLAGS(); + CLEAR_COMPARE_FLAGS(); + CLEAR_CLIP1_FLAGS(); + CLEAR_ZERO_FLAGS(); + CLEAR_CLIP2_FLAGS(); +} + +void rsp_cop2::start() +{ + for(int regIdx = 0; regIdx < 32; regIdx++ ) + { + m_v[regIdx].d[0] = 0; + m_v[regIdx].d[1] = 0; + } + + CLEAR_CARRY_FLAGS(); + CLEAR_COMPARE_FLAGS(); + CLEAR_CLIP1_FLAGS(); + CLEAR_ZERO_FLAGS(); + CLEAR_CLIP2_FLAGS(); + m_reciprocal_res = 0; + m_reciprocal_high = 0; + + // Accumulators do not power on to a random state + for(int accumIdx = 0; accumIdx < 8; accumIdx++ ) + { + m_accum[accumIdx].q = 0; + } +} + +void rsp_cop2::state_string_export(const int index, std::string &str) +{ + switch (index) + { + case RSP_V0: + strprintf(str, "%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S( 0, 0), (UINT16)VREG_S( 0, 1), (UINT16)VREG_S( 0, 2), (UINT16)VREG_S( 0, 3), (UINT16)VREG_S( 0, 4), (UINT16)VREG_S( 0, 5), (UINT16)VREG_S( 0, 6), (UINT16)VREG_S( 0, 7)); + break; + case RSP_V1: + strprintf(str, "%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S( 1, 0), (UINT16)VREG_S( 1, 1), (UINT16)VREG_S( 1, 2), (UINT16)VREG_S( 1, 3), (UINT16)VREG_S( 1, 4), (UINT16)VREG_S( 1, 5), (UINT16)VREG_S( 1, 6), (UINT16)VREG_S( 1, 7)); + break; + case RSP_V2: + strprintf(str, "%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S( 2, 0), (UINT16)VREG_S( 2, 1), (UINT16)VREG_S( 2, 2), (UINT16)VREG_S( 2, 3), (UINT16)VREG_S( 2, 4), (UINT16)VREG_S( 2, 5), (UINT16)VREG_S( 2, 6), (UINT16)VREG_S( 2, 7)); + break; + case RSP_V3: + strprintf(str, "%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S( 3, 0), (UINT16)VREG_S( 3, 1), (UINT16)VREG_S( 3, 2), (UINT16)VREG_S( 3, 3), (UINT16)VREG_S( 3, 4), (UINT16)VREG_S( 3, 5), (UINT16)VREG_S( 3, 6), (UINT16)VREG_S( 3, 7)); + break; + case RSP_V4: + strprintf(str, "%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S( 4, 0), (UINT16)VREG_S( 4, 1), (UINT16)VREG_S( 4, 2), (UINT16)VREG_S( 4, 3), (UINT16)VREG_S( 4, 4), (UINT16)VREG_S( 4, 5), (UINT16)VREG_S( 4, 6), (UINT16)VREG_S( 4, 7)); + break; + case RSP_V5: + strprintf(str, "%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S( 5, 0), (UINT16)VREG_S( 5, 1), (UINT16)VREG_S( 5, 2), (UINT16)VREG_S( 5, 3), (UINT16)VREG_S( 5, 4), (UINT16)VREG_S( 5, 5), (UINT16)VREG_S( 5, 6), (UINT16)VREG_S( 5, 7)); + break; + case RSP_V6: + strprintf(str, "%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S( 6, 0), (UINT16)VREG_S( 6, 1), (UINT16)VREG_S( 6, 2), (UINT16)VREG_S( 6, 3), (UINT16)VREG_S( 6, 4), (UINT16)VREG_S( 6, 5), (UINT16)VREG_S( 6, 6), (UINT16)VREG_S( 6, 7)); + break; + case RSP_V7: + strprintf(str, "%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S( 7, 0), (UINT16)VREG_S( 7, 1), (UINT16)VREG_S( 7, 2), (UINT16)VREG_S( 7, 3), (UINT16)VREG_S( 7, 4), (UINT16)VREG_S( 7, 5), (UINT16)VREG_S( 7, 6), (UINT16)VREG_S( 7, 7)); + break; + case RSP_V8: + strprintf(str, "%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S( 8, 0), (UINT16)VREG_S( 8, 1), (UINT16)VREG_S( 8, 2), (UINT16)VREG_S( 8, 3), (UINT16)VREG_S( 8, 4), (UINT16)VREG_S( 8, 5), (UINT16)VREG_S( 8, 6), (UINT16)VREG_S( 8, 7)); + break; + case RSP_V9: + strprintf(str, "%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S( 9, 0), (UINT16)VREG_S( 9, 1), (UINT16)VREG_S( 9, 2), (UINT16)VREG_S( 9, 3), (UINT16)VREG_S( 9, 4), (UINT16)VREG_S( 9, 5), (UINT16)VREG_S( 9, 6), (UINT16)VREG_S( 9, 7)); + break; + case RSP_V10: + strprintf(str, "%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(10, 0), (UINT16)VREG_S(10, 1), (UINT16)VREG_S(10, 2), (UINT16)VREG_S(10, 3), (UINT16)VREG_S(10, 4), (UINT16)VREG_S(10, 5), (UINT16)VREG_S(10, 6), (UINT16)VREG_S(10, 7)); + break; + case RSP_V11: + strprintf(str, "%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(11, 0), (UINT16)VREG_S(11, 1), (UINT16)VREG_S(11, 2), (UINT16)VREG_S(11, 3), (UINT16)VREG_S(11, 4), (UINT16)VREG_S(11, 5), (UINT16)VREG_S(11, 6), (UINT16)VREG_S(11, 7)); + break; + case RSP_V12: + strprintf(str, "%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(12, 0), (UINT16)VREG_S(12, 1), (UINT16)VREG_S(12, 2), (UINT16)VREG_S(12, 3), (UINT16)VREG_S(12, 4), (UINT16)VREG_S(12, 5), (UINT16)VREG_S(12, 6), (UINT16)VREG_S(12, 7)); + break; + case RSP_V13: + strprintf(str, "%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(13, 0), (UINT16)VREG_S(13, 1), (UINT16)VREG_S(13, 2), (UINT16)VREG_S(13, 3), (UINT16)VREG_S(13, 4), (UINT16)VREG_S(13, 5), (UINT16)VREG_S(13, 6), (UINT16)VREG_S(13, 7)); + break; + case RSP_V14: + strprintf(str, "%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(14, 0), (UINT16)VREG_S(14, 1), (UINT16)VREG_S(14, 2), (UINT16)VREG_S(14, 3), (UINT16)VREG_S(14, 4), (UINT16)VREG_S(14, 5), (UINT16)VREG_S(14, 6), (UINT16)VREG_S(14, 7)); + break; + case RSP_V15: + strprintf(str, "%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(15, 0), (UINT16)VREG_S(15, 1), (UINT16)VREG_S(15, 2), (UINT16)VREG_S(15, 3), (UINT16)VREG_S(15, 4), (UINT16)VREG_S(15, 5), (UINT16)VREG_S(15, 6), (UINT16)VREG_S(15, 7)); + break; + case RSP_V16: + strprintf(str, "%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(16, 0), (UINT16)VREG_S(16, 1), (UINT16)VREG_S(16, 2), (UINT16)VREG_S(16, 3), (UINT16)VREG_S(16, 4), (UINT16)VREG_S(16, 5), (UINT16)VREG_S(16, 6), (UINT16)VREG_S(16, 7)); + break; + case RSP_V17: + strprintf(str, "%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(17, 0), (UINT16)VREG_S(17, 1), (UINT16)VREG_S(17, 2), (UINT16)VREG_S(17, 3), (UINT16)VREG_S(17, 4), (UINT16)VREG_S(17, 5), (UINT16)VREG_S(17, 6), (UINT16)VREG_S(17, 7)); + break; + case RSP_V18: + strprintf(str, "%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(18, 0), (UINT16)VREG_S(18, 1), (UINT16)VREG_S(18, 2), (UINT16)VREG_S(18, 3), (UINT16)VREG_S(18, 4), (UINT16)VREG_S(18, 5), (UINT16)VREG_S(18, 6), (UINT16)VREG_S(18, 7)); + break; + case RSP_V19: + strprintf(str, "%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(19, 0), (UINT16)VREG_S(19, 1), (UINT16)VREG_S(19, 2), (UINT16)VREG_S(19, 3), (UINT16)VREG_S(19, 4), (UINT16)VREG_S(19, 5), (UINT16)VREG_S(19, 6), (UINT16)VREG_S(19, 7)); + break; + case RSP_V20: + strprintf(str, "%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(20, 0), (UINT16)VREG_S(20, 1), (UINT16)VREG_S(20, 2), (UINT16)VREG_S(20, 3), (UINT16)VREG_S(20, 4), (UINT16)VREG_S(20, 5), (UINT16)VREG_S(20, 6), (UINT16)VREG_S(20, 7)); + break; + case RSP_V21: + strprintf(str, "%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(21, 0), (UINT16)VREG_S(21, 1), (UINT16)VREG_S(21, 2), (UINT16)VREG_S(21, 3), (UINT16)VREG_S(21, 4), (UINT16)VREG_S(21, 5), (UINT16)VREG_S(21, 6), (UINT16)VREG_S(21, 7)); + break; + case RSP_V22: + strprintf(str, "%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(22, 0), (UINT16)VREG_S(22, 1), (UINT16)VREG_S(22, 2), (UINT16)VREG_S(22, 3), (UINT16)VREG_S(22, 4), (UINT16)VREG_S(22, 5), (UINT16)VREG_S(22, 6), (UINT16)VREG_S(22, 7)); + break; + case RSP_V23: + strprintf(str, "%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(23, 0), (UINT16)VREG_S(23, 1), (UINT16)VREG_S(23, 2), (UINT16)VREG_S(23, 3), (UINT16)VREG_S(23, 4), (UINT16)VREG_S(23, 5), (UINT16)VREG_S(23, 6), (UINT16)VREG_S(23, 7)); + break; + case RSP_V24: + strprintf(str, "%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(24, 0), (UINT16)VREG_S(24, 1), (UINT16)VREG_S(24, 2), (UINT16)VREG_S(24, 3), (UINT16)VREG_S(24, 4), (UINT16)VREG_S(24, 5), (UINT16)VREG_S(24, 6), (UINT16)VREG_S(24, 7)); + break; + case RSP_V25: + strprintf(str, "%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(25, 0), (UINT16)VREG_S(25, 1), (UINT16)VREG_S(25, 2), (UINT16)VREG_S(25, 3), (UINT16)VREG_S(25, 4), (UINT16)VREG_S(25, 5), (UINT16)VREG_S(25, 6), (UINT16)VREG_S(25, 7)); + break; + case RSP_V26: + strprintf(str, "%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(26, 0), (UINT16)VREG_S(26, 1), (UINT16)VREG_S(26, 2), (UINT16)VREG_S(26, 3), (UINT16)VREG_S(26, 4), (UINT16)VREG_S(26, 5), (UINT16)VREG_S(26, 6), (UINT16)VREG_S(26, 7)); + break; + case RSP_V27: + strprintf(str, "%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(27, 0), (UINT16)VREG_S(27, 1), (UINT16)VREG_S(27, 2), (UINT16)VREG_S(27, 3), (UINT16)VREG_S(27, 4), (UINT16)VREG_S(27, 5), (UINT16)VREG_S(27, 6), (UINT16)VREG_S(27, 7)); + break; + case RSP_V28: + strprintf(str, "%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(28, 0), (UINT16)VREG_S(28, 1), (UINT16)VREG_S(28, 2), (UINT16)VREG_S(28, 3), (UINT16)VREG_S(28, 4), (UINT16)VREG_S(28, 5), (UINT16)VREG_S(28, 6), (UINT16)VREG_S(28, 7)); + break; + case RSP_V29: + strprintf(str, "%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(29, 0), (UINT16)VREG_S(29, 1), (UINT16)VREG_S(29, 2), (UINT16)VREG_S(29, 3), (UINT16)VREG_S(29, 4), (UINT16)VREG_S(29, 5), (UINT16)VREG_S(29, 6), (UINT16)VREG_S(29, 7)); + break; + case RSP_V30: + strprintf(str, "%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(30, 0), (UINT16)VREG_S(30, 1), (UINT16)VREG_S(30, 2), (UINT16)VREG_S(30, 3), (UINT16)VREG_S(30, 4), (UINT16)VREG_S(30, 5), (UINT16)VREG_S(30, 6), (UINT16)VREG_S(30, 7)); + break; + case RSP_V31: + strprintf(str, "%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(31, 0), (UINT16)VREG_S(31, 1), (UINT16)VREG_S(31, 2), (UINT16)VREG_S(31, 3), (UINT16)VREG_S(31, 4), (UINT16)VREG_S(31, 5), (UINT16)VREG_S(31, 6), (UINT16)VREG_S(31, 7)); + break; + } +} + +/*************************************************************************** + Vector Load Instructions +***************************************************************************/ + +void rsp_cop2::handle_lwc2(UINT32 op) +{ + int base = (op >> 21) & 0x1f; +#if !USE_SIMD + int i, end; + UINT32 ea; + int dest = (op >> 16) & 0x1f; + int index = (op >> 7) & 0xf; + int offset = (op & 0x7f); + if (offset & 0x40) + offset |= 0xffffffc0; +#endif + + switch ((op >> 11) & 0x1f) + { + case 0x00: /* LBV */ + { + // 31 25 20 15 10 6 0 + // -------------------------------------------------- + // | 110010 | BBBBB | TTTTT | 00000 | IIII | Offset | + // -------------------------------------------------- + // + // Load 1 byte to vector byte index + + //printf("LBV "); +#if USE_SIMD + vec_lbdlsv_sbdlsv(op, m_rsp.m_rsp_state->r[base]); +#else + ea = (base) ? m_rsp.m_rsp_state->r[base] + offset : offset; + VREG_B(dest, index) = m_rsp.READ8(ea); +#endif + // + break; + } + case 0x01: /* LSV */ + { + // 31 25 20 15 10 6 0 + // -------------------------------------------------- + // | 110010 | BBBBB | TTTTT | 00001 | IIII | Offset | + // -------------------------------------------------- + // + // Loads 2 bytes starting from vector byte index + + //printf("LSV "); +#if USE_SIMD + vec_lbdlsv_sbdlsv(op, m_rsp.m_rsp_state->r[base]); +#else + ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 2) : (offset * 2); + + end = index + 2; + + for (i=index; i < end; i++) + { + VREG_B(dest, i) = m_rsp.READ8(ea); + ea++; + } +#endif + // + break; + } + case 0x02: /* LLV */ + { + // 31 25 20 15 10 6 0 + // -------------------------------------------------- + // | 110010 | BBBBB | TTTTT | 00010 | IIII | Offset | + // -------------------------------------------------- + // + // Loads 4 bytes starting from vector byte index + + //printf("LLV "); +#if USE_SIMD + vec_lbdlsv_sbdlsv(op, m_rsp.m_rsp_state->r[base]); +#else + ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 4) : (offset * 4); + + end = index + 4; + + for (i=index; i < end; i++) + { + VREG_B(dest, i) = m_rsp.READ8(ea); + ea++; + } +#endif + // + break; + } + case 0x03: /* LDV */ + { + // 31 25 20 15 10 6 0 + // -------------------------------------------------- + // | 110010 | BBBBB | TTTTT | 00011 | IIII | Offset | + // -------------------------------------------------- + // + // Loads 8 bytes starting from vector byte index + + //printf("LDV "); +#if USE_SIMD + vec_lbdlsv_sbdlsv(op, m_rsp.m_rsp_state->r[base]); +#else + ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 8) : (offset * 8); + + end = index + 8; + + for (i=index; i < end; i++) + { + VREG_B(dest, i) = m_rsp.READ8(ea); + ea++; + } +#endif + // + break; + } + case 0x04: /* LQV */ + { + // 31 25 20 15 10 6 0 + // -------------------------------------------------- + // | 110010 | BBBBB | TTTTT | 00100 | IIII | Offset | + // -------------------------------------------------- + // + // Loads up to 16 bytes starting from vector byte index + + //printf("LQV "); +#if USE_SIMD + vec_lqrv_sqrv(op, m_rsp.m_rsp_state->r[base]); +#else + ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 16) : (offset * 16); + + end = index + (16 - (ea & 0xf)); + if (end > 16) end = 16; + + for (i=index; i < end; i++) + { + VREG_B(dest, i) = m_rsp.READ8(ea); + ea++; + } +#endif + // + break; + } + case 0x05: /* LRV */ + { + // 31 25 20 15 10 6 0 + // -------------------------------------------------- + // | 110010 | BBBBB | TTTTT | 00101 | IIII | Offset | + // -------------------------------------------------- + // + // Stores up to 16 bytes starting from right side until 16-byte boundary + + //printf("LRV "); +#if USE_SIMD + vec_lqrv_sqrv(op, m_rsp.m_rsp_state->r[base]); +#else + ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 16) : (offset * 16); + + index = 16 - ((ea & 0xf) - index); + end = 16; + ea &= ~0xf; + + for (i=index; i < end; i++) + { + VREG_B(dest, i) = m_rsp.READ8(ea); + ea++; + } +#endif + // + break; + } + case 0x06: /* LPV */ + { + // 31 25 20 15 10 6 0 + // -------------------------------------------------- + // | 110010 | BBBBB | TTTTT | 00110 | IIII | Offset | + // -------------------------------------------------- + // + // Loads a byte as the upper 8 bits of each element + + //printf("LPV "); +#if USE_SIMD + vec_lfhpuv_sfhpuv(op, m_rsp.m_rsp_state->r[base]); +#else + ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 8) : (offset * 8); + + for (i=0; i < 8; i++) + { + VREG_S(dest, i) = m_rsp.READ8(ea + (((16-index) + i) & 0xf)) << 8; + } +#endif + // + break; + } + case 0x07: /* LUV */ + { + // 31 25 20 15 10 6 0 + // -------------------------------------------------- + // | 110010 | BBBBB | TTTTT | 00111 | IIII | Offset | + // -------------------------------------------------- + // + // Loads a byte as the bits 14-7 of each element + + //printf("LUV "); +#if USE_SIMD + vec_lfhpuv_sfhpuv(op, m_rsp.m_rsp_state->r[base]); +#else + ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 8) : (offset * 8); + + for (i=0; i < 8; i++) + { + VREG_S(dest, i) = m_rsp.READ8(ea + (((16-index) + i) & 0xf)) << 7; + } +#endif + // + break; + } + case 0x08: /* LHV */ + { + // 31 25 20 15 10 6 0 + // -------------------------------------------------- + // | 110010 | BBBBB | TTTTT | 01000 | IIII | Offset | + // -------------------------------------------------- + // + // Loads a byte as the bits 14-7 of each element, with 2-byte stride + + //printf("LHV "); +#if USE_SIMD + vec_lfhpuv_sfhpuv(op, m_rsp.m_rsp_state->r[base]); +#else + ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 16) : (offset * 16); + + for (i=0; i < 8; i++) + { + VREG_S(dest, i) = m_rsp.READ8(ea + (((16-index) + (i<<1)) & 0xf)) << 7; + } +#endif + // + break; + } + case 0x09: /* LFV */ + { + // 31 25 20 15 10 6 0 + // -------------------------------------------------- + // | 110010 | BBBBB | TTTTT | 01001 | IIII | Offset | + // -------------------------------------------------- + // + // Loads a byte as the bits 14-7 of upper or lower quad, with 4-byte stride + + //printf("LFV "); +#if USE_SIMD + vec_lfhpuv_sfhpuv(op, m_rsp.m_rsp_state->r[base]); +#else + ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 16) : (offset * 16); + + // not sure what happens if 16-byte boundary is crossed... + + end = (index >> 1) + 4; + + for (i=index >> 1; i < end; i++) + { + VREG_S(dest, i) = m_rsp.READ8(ea) << 7; + ea += 4; + } +#endif + // + break; + } + case 0x0a: /* LWV */ + { + // 31 25 20 15 10 6 0 + // -------------------------------------------------- + // | 110010 | BBBBB | TTTTT | 01010 | IIII | Offset | + // -------------------------------------------------- + // + // Loads the full 128-bit vector starting from vector byte index and wrapping to index 0 + // after byte index 15 + + //printf("LWV "); +#if USE_SIMD +#else + ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 16) : (offset * 16); + + end = (16 - index) + 16; + + for (i=(16 - index); i < end; i++) + { + VREG_B(dest, i & 0xf) = m_rsp.READ8(ea); + ea += 4; + } +#endif + // + break; + } + case 0x0b: /* LTV */ + { + // 31 25 20 15 10 6 0 + // -------------------------------------------------- + // | 110010 | BBBBB | TTTTT | 01011 | IIII | Offset | + // -------------------------------------------------- + // + // Loads one element to maximum of 8 vectors, while incrementing element index + + // FIXME: has a small problem with odd indices + + //printf("LTV "); +#if 0 +#else + INT32 index = (op >> 7) & 0xf; + INT32 offset = (op & 0x7f); + if (offset & 0x40) + offset |= 0xffffffc0; + + INT32 vs = (op >> 16) & 0x1f; + INT32 ve = vs + 8; + if (ve > 32) + ve = 32; + + INT32 element = 7 - (index >> 1); + + if (index & 1) fatalerror("RSP: LTV: index = %d\n", index); + + UINT32 ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 16) : (offset * 16); + + ea = ((ea + 8) & ~0xf) + (index & 1); + for (INT32 i = vs; i < ve; i++) + { + element = ((8 - (index >> 1) + (i-vs)) << 1); + VREG_B(i, (element & 0xf)) = m_rsp.READ8(ea); + VREG_B(i, ((element + 1) & 0xf)) = m_rsp.READ8(ea + 1); + + ea += 2; + } +#endif + // + break; + } + + default: + { + m_rsp.unimplemented_opcode(op); + break; + } + } +} + + +/*************************************************************************** + Vector Store Instructions +***************************************************************************/ + +void rsp_cop2::handle_swc2(UINT32 op) +{ + int base = (op >> 21) & 0x1f; +#if !USE_SIMD + int i, end; + int eaoffset; + UINT32 ea; + int dest = (op >> 16) & 0x1f; + int index = (op >> 7) & 0xf; + int offset = (op & 0x7f); + if (offset & 0x40) + offset |= 0xffffffc0; +#endif + + switch ((op >> 11) & 0x1f) + { + case 0x00: /* SBV */ + { + // 31 25 20 15 10 6 0 + // -------------------------------------------------- + // | 111010 | BBBBB | TTTTT | 00000 | IIII | Offset | + // -------------------------------------------------- + // + // Stores 1 byte from vector byte index + + //printf("SBV "); +#if USE_SIMD + vec_lbdlsv_sbdlsv(op, m_rsp.m_rsp_state->r[base]); +#else + ea = (base) ? m_rsp.m_rsp_state->r[base] + offset : offset; + m_rsp.WRITE8(ea, VREG_B(dest, index)); +#endif + // + break; + } + case 0x01: /* SSV */ + { + // 31 25 20 15 10 6 0 + // -------------------------------------------------- + // | 111010 | BBBBB | TTTTT | 00001 | IIII | Offset | + // -------------------------------------------------- + // + // Stores 2 bytes starting from vector byte index + + //printf("SSV "); +#if USE_SIMD + vec_lbdlsv_sbdlsv(op, m_rsp.m_rsp_state->r[base]); +#else + ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 2) : (offset * 2); + + end = index + 2; + + for (i=index; i < end; i++) + { + m_rsp.WRITE8(ea, VREG_B(dest, i)); + ea++; + } +#endif + // + break; + } + case 0x02: /* SLV */ + { + // 31 25 20 15 10 6 0 + // -------------------------------------------------- + // | 111010 | BBBBB | TTTTT | 00010 | IIII | Offset | + // -------------------------------------------------- + // + // Stores 4 bytes starting from vector byte index + + //printf("SLV "); +#if USE_SIMD + vec_lbdlsv_sbdlsv(op, m_rsp.m_rsp_state->r[base]); +#else + ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 4) : (offset * 4); + + end = index + 4; + + for (i=index; i < end; i++) + { + m_rsp.WRITE8(ea, VREG_B(dest, i)); + ea++; + } +#endif + // + break; + } + case 0x03: /* SDV */ + { + // 31 25 20 15 10 6 0 + // -------------------------------------------------- + // | 111010 | BBBBB | TTTTT | 00011 | IIII | Offset | + // -------------------------------------------------- + // + // Stores 8 bytes starting from vector byte index + + //printf("SDV "); +#if USE_SIMD + vec_lbdlsv_sbdlsv(op, m_rsp.m_rsp_state->r[base]); +#else + ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 8) : (offset * 8); + + end = index + 8; + + for (i=index; i < end; i++) + { + m_rsp.WRITE8(ea, VREG_B(dest, i)); + ea++; + } +#endif + // + break; + } + case 0x04: /* SQV */ + { + // 31 25 20 15 10 6 0 + // -------------------------------------------------- + // | 111010 | BBBBB | TTTTT | 00100 | IIII | Offset | + // -------------------------------------------------- + // + // Stores up to 16 bytes starting from vector byte index until 16-byte boundary + + //printf("SQV "); +#if USE_SIMD + vec_lqrv_sqrv(op, m_rsp.m_rsp_state->r[base]); +#else + ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 16) : (offset * 16); + + end = index + (16 - (ea & 0xf)); + + for (i=index; i < end; i++) + { + m_rsp.WRITE8(ea, VREG_B(dest, i & 0xf)); + ea++; + } +#endif + // + break; + } + case 0x05: /* SRV */ + { + // 31 25 20 15 10 6 0 + // -------------------------------------------------- + // | 111010 | BBBBB | TTTTT | 00101 | IIII | Offset | + // -------------------------------------------------- + // + // Stores up to 16 bytes starting from right side until 16-byte boundary + + //printf("SRV "); +#if USE_SIMD + vec_lqrv_sqrv(op, m_rsp.m_rsp_state->r[base]); +#else + int o; + ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 16) : (offset * 16); + + end = index + (ea & 0xf); + o = (16 - (ea & 0xf)) & 0xf; + ea &= ~0xf; + + for (i=index; i < end; i++) + { + m_rsp.WRITE8(ea, VREG_B(dest, ((i + o) & 0xf))); + ea++; + } +#endif + // + break; + } + case 0x06: /* SPV */ + { + // 31 25 20 15 10 6 0 + // -------------------------------------------------- + // | 111010 | BBBBB | TTTTT | 00110 | IIII | Offset | + // -------------------------------------------------- + // + // Stores upper 8 bits of each element + + //printf("SPV "); +#if USE_SIMD + vec_lfhpuv_sfhpuv(op, m_rsp.m_rsp_state->r[base]); +#else + ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 8) : (offset * 8); + end = index + 8; + + for (i=index; i < end; i++) + { + if ((i & 0xf) < 8) + { + m_rsp.WRITE8(ea, VREG_B(dest, ((i & 0xf) << 1))); + } + else + { + m_rsp.WRITE8(ea, VREG_S(dest, (i & 0x7)) >> 7); + } + ea++; + } +#endif + // + break; + } + case 0x07: /* SUV */ + { + // 31 25 20 15 10 6 0 + // -------------------------------------------------- + // | 111010 | BBBBB | TTTTT | 00111 | IIII | Offset | + // -------------------------------------------------- + // + // Stores bits 14-7 of each element + + //printf("SUV "); +#if USE_SIMD + vec_lfhpuv_sfhpuv(op, m_rsp.m_rsp_state->r[base]); +#else + ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 8) : (offset * 8); + end = index + 8; + + for (i=index; i < end; i++) + { + if ((i & 0xf) < 8) + { + m_rsp.WRITE8(ea, VREG_S(dest, (i & 0x7)) >> 7); + } + else + { + m_rsp.WRITE8(ea, VREG_B(dest, ((i & 0x7) << 1))); + } + ea++; + } +#endif + // + break; + } + case 0x08: /* SHV */ + { + // 31 25 20 15 10 6 0 + // -------------------------------------------------- + // | 111010 | BBBBB | TTTTT | 01000 | IIII | Offset | + // -------------------------------------------------- + // + // Stores bits 14-7 of each element, with 2-byte stride + + //printf("SHV "); +#if USE_SIMD + vec_lfhpuv_sfhpuv(op, m_rsp.m_rsp_state->r[base]); +#else + ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 16) : (offset * 16); + + for (i=0; i < 8; i++) + { + UINT8 d = ((VREG_B(dest, ((index + (i << 1) + 0) & 0xf))) << 1) | + ((VREG_B(dest, ((index + (i << 1) + 1) & 0xf))) >> 7); + + m_rsp.WRITE8(ea, d); + ea += 2; + } +#endif + // + break; + } + case 0x09: /* SFV */ + { + // 31 25 20 15 10 6 0 + // -------------------------------------------------- + // | 111010 | BBBBB | TTTTT | 01001 | IIII | Offset | + // -------------------------------------------------- + // + // Stores bits 14-7 of upper or lower quad, with 4-byte stride + + // FIXME: only works for index 0 and index 8 + + //printf("SFV "); +#if USE_SIMD + vec_lfhpuv_sfhpuv(op, m_rsp.m_rsp_state->r[base]); +#else + ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 16) : (offset * 16); + + eaoffset = ea & 0xf; + ea &= ~0xf; + + end = (index >> 1) + 4; + + for (i=index >> 1; i < end; i++) + { + m_rsp.WRITE8(ea + (eaoffset & 0xf), VREG_S(dest, i) >> 7); + eaoffset += 4; + } +#endif + // + break; + } + case 0x0a: /* SWV */ + { + // 31 25 20 15 10 6 0 + // -------------------------------------------------- + // | 111010 | BBBBB | TTTTT | 01010 | IIII | Offset | + // -------------------------------------------------- + // + // Stores the full 128-bit vector starting from vector byte index and wrapping to index 0 + // after byte index 15 + + //printf("SWV "); +#if USE_SIMD +#else + ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 16) : (offset * 16); + + eaoffset = ea & 0xf; + ea &= ~0xf; + + end = index + 16; + + for (i=index; i < end; i++) + { + m_rsp.WRITE8(ea + (eaoffset & 0xf), VREG_B(dest, i & 0xf)); + eaoffset++; + } +#endif + // + break; + } + case 0x0b: /* STV */ + { + // 31 25 20 15 10 6 0 + // -------------------------------------------------- + // | 111010 | BBBBB | TTTTT | 01011 | IIII | Offset | + // -------------------------------------------------- + // + // Stores one element from maximum of 8 vectors, while incrementing element index + + //printf("STV "); +#if 0 +#else + INT32 index = (op >> 7) & 0xf; + INT32 offset = (op & 0x7f); + if (offset & 0x40) + offset |= 0xffffffc0; + + INT32 vs = (op >> 16) & 0x1f; + INT32 ve = vs + 8; + if (ve > 32) + ve = 32; + + INT32 element = 8 - (index >> 1); + + UINT32 ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 16) : (offset * 16); + + INT32 eaoffset = (ea & 0xf) + (element * 2); + ea &= ~0xf; + + for (INT32 i = vs; i < ve; i++) + { + m_rsp.WRITE16(ea + (eaoffset & 0xf), VREG_S(i, element & 0x7)); + eaoffset += 2; + element++; + } +#endif + // + break; + } + + default: + { + m_rsp.unimplemented_opcode(op); + break; + } + } +} + +/*************************************************************************** + Vector Accumulator Helpers +***************************************************************************/ + +UINT16 rsp_cop2::SATURATE_ACCUM(int accum, int slice, UINT16 negative, UINT16 positive) +{ + if ((INT16)ACCUM_H(accum) < 0) + { + if ((UINT16)(ACCUM_H(accum)) != 0xffff) + { + return negative; + } + else + { + if ((INT16)ACCUM_M(accum) >= 0) + { + return negative; + } + else + { + if (slice == 0) + { + return ACCUM_L(accum); + } + else if (slice == 1) + { + return ACCUM_M(accum); + } + } + } + } + else + { + if ((UINT16)(ACCUM_H(accum)) != 0) + { + return positive; + } + else + { + if ((INT16)ACCUM_M(accum) < 0) + { + return positive; + } + else + { + if (slice == 0) + { + return ACCUM_L(accum); + } + else + { + return ACCUM_M(accum); + } + } + } + } + return 0; +} + + +/*************************************************************************** + Vector Opcodes +***************************************************************************/ + +void rsp_cop2::handle_vector_ops(UINT32 op) +{ +#if !USE_SIMD + int i; +#endif + + // Opcode legend: + // E = VS2 element type + // S = VS1, Source vector 1 + // T = VS2, Source vector 2 + // D = Destination vector + + switch (op & 0x3f) + { + case 0x00: /* VMULF */ + { + // 31 25 24 20 15 10 5 0 + // ------------------------------------------------------ + // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 000000 | + // ------------------------------------------------------ + // + // Multiplies signed integer by signed integer * 2 + + //printf("MULF "); +#if USE_SIMD + UINT16 *acc = m_acc.s; + rsp_vec_t acc_lo, acc_mid, acc_hi; + + rsp_vec_t vs = vec_load_unshuffled_operand(m_v[VS1REG].s); + rsp_vec_t vt_shuffle = vec_load_and_shuffle_operand(m_v[VS2REG].s, EL); + + m_v[VDREG].v = vec_vmulf_vmulu(op, vs, vt_shuffle, vec_zero(), &acc_lo, &acc_mid, &acc_hi); + + write_acc_lo(acc, acc_lo); + write_acc_mid(acc, acc_mid); + write_acc_hi(acc, acc_hi); +#else + for (i=0; i < 8; i++) + { + INT32 s1 = (INT32)(INT16)VREG_S(VS1REG, i); + INT32 s2 = (INT32)(INT16)VREG_S(VS2REG, VEC_EL_2(EL, i)); + + if (s1 == -32768 && s2 == -32768) + { + // overflow + SET_ACCUM_H(0, i); + SET_ACCUM_M(-32768, i); + SET_ACCUM_L(-32768, i); + m_vres[i] = 0x7fff; + } + else + { + INT64 r = s1 * s2 * 2; + r += 0x8000; // rounding ? + SET_ACCUM_H((r < 0) ? 0xffff : 0, i); // sign-extend to 48-bit + SET_ACCUM_M((INT16)(r >> 16), i); + SET_ACCUM_L((UINT16)(r), i); + m_vres[i] = ACCUM_M(i); + } + } + WRITEBACK_RESULT(); +#endif + // + break; + + } + + case 0x01: /* VMULU */ + { + // 31 25 24 20 15 10 5 0 + // ------------------------------------------------------ + // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 000001 | + // ------------------------------------------------------ + // + + //printf("MULU "); +#if USE_SIMD + UINT16 *acc = m_acc.s; + rsp_vec_t acc_lo, acc_mid, acc_hi; + + rsp_vec_t vs = vec_load_unshuffled_operand(m_v[VS1REG].s); + rsp_vec_t vt_shuffle = vec_load_and_shuffle_operand(m_v[VS2REG].s, EL); + + m_v[VDREG].v = vec_vmulf_vmulu(op, vs, vt_shuffle, vec_zero(), &acc_lo, &acc_mid, &acc_hi); + + write_acc_lo(acc, acc_lo); + write_acc_mid(acc, acc_mid); + write_acc_hi(acc, acc_hi); +#else + for (i=0; i < 8; i++) + { + INT32 s1 = (INT32)(INT16)VREG_S(VS1REG, i); + INT32 s2 = (INT32)(INT16)VREG_S(VS2REG, VEC_EL_2(EL, i)); + + INT64 r = s1 * s2 * 2; + r += 0x8000; // rounding ? + + SET_ACCUM_H((UINT16)(r >> 32), i); + SET_ACCUM_M((UINT16)(r >> 16), i); + SET_ACCUM_L((UINT16)(r), i); + + if (r < 0) + { + m_vres[i] = 0; + } + else if (((INT16)(ACCUM_H(i)) ^ (INT16)(ACCUM_M(i))) < 0) + { + m_vres[i] = -1; + } + else + { + m_vres[i] = ACCUM_M(i); + } + } + WRITEBACK_RESULT(); +#endif + // + break; + } + + case 0x04: /* VMUDL */ + { + // 31 25 24 20 15 10 5 0 + // ------------------------------------------------------ + // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 000100 | + // ------------------------------------------------------ + // + // Multiplies unsigned fraction by unsigned fraction + // Stores the higher 16 bits of the 32-bit result to accumulator + // The low slice of accumulator is stored into destination element + + //printf("MUDL "); +#if USE_SIMD + UINT16 *acc = m_acc.s; + rsp_vec_t acc_lo, acc_mid, acc_hi; + + acc_lo = read_acc_lo(acc); + acc_mid = read_acc_mid(acc); + acc_hi = read_acc_hi(acc); + + rsp_vec_t vs = vec_load_unshuffled_operand(m_v[VS1REG].s); + rsp_vec_t vt_shuffle = vec_load_and_shuffle_operand(m_v[VS2REG].s, EL); + + m_v[VDREG].v = vec_vmadl_vmudl(op, vs, vt_shuffle, vec_zero(), &acc_lo, &acc_mid, &acc_hi); + + write_acc_lo(acc, acc_lo); + write_acc_mid(acc, acc_mid); + write_acc_hi(acc, acc_hi); +#else + for (i=0; i < 8; i++) + { + UINT32 s1 = (UINT32)(UINT16)VREG_S(VS1REG, i); + UINT32 s2 = (UINT32)(UINT16)VREG_S(VS2REG, VEC_EL_2(EL, i)); + UINT32 r = s1 * s2; + + SET_ACCUM_H(0, i); + SET_ACCUM_M(0, i); + SET_ACCUM_L((UINT16)(r >> 16), i); + + m_vres[i] = ACCUM_L(i); + } + WRITEBACK_RESULT(); +#endif + // + break; + } + + case 0x05: /* VMUDM */ + { + // 31 25 24 20 15 10 5 0 + // ------------------------------------------------------ + // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 000101 | + // ------------------------------------------------------ + // + // Multiplies signed integer by unsigned fraction + // The result is stored into accumulator + // The middle slice of accumulator is stored into destination element + + //printf("MUDM "); +#if USE_SIMD + UINT16 *acc = m_acc.s; + rsp_vec_t acc_lo, acc_mid, acc_hi; + + acc_lo = read_acc_lo(acc); + acc_mid = read_acc_mid(acc); + acc_hi = read_acc_hi(acc); + + rsp_vec_t vs = vec_load_unshuffled_operand(m_v[VS1REG].s); + rsp_vec_t vt_shuffle = vec_load_and_shuffle_operand(m_v[VS2REG].s, EL); + + m_v[VDREG].v = vec_vmadm_vmudm(op, vs, vt_shuffle, vec_zero(), &acc_lo, &acc_mid, &acc_hi); + + write_acc_lo(acc, acc_lo); + write_acc_mid(acc, acc_mid); + write_acc_hi(acc, acc_hi); +#else + for (i=0; i < 8; i++) + { + INT32 s1 = (INT32)(INT16)VREG_S(VS1REG, i); + INT32 s2 = (UINT16)VREG_S(VS2REG, VEC_EL_2(EL, i)); // not sign-extended + INT32 r = s1 * s2; + + SET_ACCUM_H((r < 0) ? 0xffff : 0, i); // sign-extend to 48-bit + SET_ACCUM_M((INT16)(r >> 16), i); + SET_ACCUM_L((UINT16)(r), i); + + m_vres[i] = ACCUM_M(i); + } + WRITEBACK_RESULT(); +#endif + // + break; + + } + + case 0x06: /* VMUDN */ + { + // 31 25 24 20 15 10 5 0 + // ------------------------------------------------------ + // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 000110 | + // ------------------------------------------------------ + // + // Multiplies unsigned fraction by signed integer + // The result is stored into accumulator + // The low slice of accumulator is stored into destination element + + //printf("MUDN "); +#if USE_SIMD + UINT16 *acc = m_acc.s; + rsp_vec_t acc_lo = read_acc_lo(acc); + rsp_vec_t acc_mid = read_acc_mid(acc); + rsp_vec_t acc_hi = read_acc_hi(acc); + + rsp_vec_t vs = vec_load_unshuffled_operand(m_v[VS1REG].s); + rsp_vec_t vt_shuffle = vec_load_and_shuffle_operand(m_v[VS2REG].s, EL); + + m_v[VDREG].v = vec_vmadn_vmudn(op, vs, vt_shuffle, vec_zero(), &acc_lo, &acc_mid, &acc_hi); + + write_acc_lo(acc, acc_lo); + write_acc_mid(acc, acc_mid); + write_acc_hi(acc, acc_hi); +#else + for (i=0; i < 8; i++) + { + INT32 s1 = (UINT16)VREG_S(VS1REG, i); // not sign-extended + INT32 s2 = (INT32)(INT16)VREG_S(VS2REG, VEC_EL_2(EL, i)); + INT32 r = s1 * s2; + + SET_ACCUM_H((r < 0) ? 0xffff : 0, i); // sign-extend to 48-bit + SET_ACCUM_M((INT16)(r >> 16), i); + SET_ACCUM_L((UINT16)(r), i); + + m_vres[i] = ACCUM_L(i); + } + WRITEBACK_RESULT(); +#endif + // + break; + } + + case 0x07: /* VMUDH */ + { + // 31 25 24 20 15 10 5 0 + // ------------------------------------------------------ + // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 000111 | + // ------------------------------------------------------ + // + // Multiplies signed integer by signed integer + // The result is stored into highest 32 bits of accumulator, the low slice is zero + // The highest 32 bits of accumulator is saturated into destination element + + //printf("MUDH "); +#if USE_SIMD + UINT16 *acc = m_acc.s; + rsp_vec_t acc_lo, acc_mid, acc_hi; + + acc_lo = read_acc_lo(acc); + acc_mid = read_acc_mid(acc); + acc_hi = read_acc_hi(acc); + + rsp_vec_t vs = vec_load_unshuffled_operand(m_v[VS1REG].s); + rsp_vec_t vt_shuffle = vec_load_and_shuffle_operand(m_v[VS2REG].s, EL); + + m_v[VDREG].v = vec_vmadh_vmudh(op, vs, vt_shuffle, vec_zero(), &acc_lo, &acc_mid, &acc_hi); + + write_acc_lo(acc, acc_lo); + write_acc_mid(acc, acc_mid); + write_acc_hi(acc, acc_hi); +#else + for (i=0; i < 8; i++) + { + INT32 s1 = (INT32)(INT16)VREG_S(VS1REG, i); + INT32 s2 = (INT32)(INT16)VREG_S(VS2REG, VEC_EL_2(EL, i)); + INT32 r = s1 * s2; + + SET_ACCUM_H((INT16)(r >> 16), i); + SET_ACCUM_M((UINT16)(r), i); + SET_ACCUM_L(0, i); + + if (r < -32768) r = -32768; + if (r > 32767) r = 32767; + m_vres[i] = (INT16)(r); + } + WRITEBACK_RESULT(); +#endif + // + break; + } + + case 0x08: /* VMACF */ + { + // 31 25 24 20 15 10 5 0 + // ------------------------------------------------------ + // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 001000 | + // ------------------------------------------------------ + // + // Multiplies signed integer by signed integer * 2 + // The result is added to accumulator + + //printf("MACF "); +#if USE_SIMD + UINT16 *acc = m_acc.s; + rsp_vec_t acc_lo, acc_mid, acc_hi; + + acc_lo = read_acc_lo(acc); + acc_mid = read_acc_mid(acc); + acc_hi = read_acc_hi(acc); + + rsp_vec_t vs = vec_load_unshuffled_operand(m_v[VS1REG].s); + rsp_vec_t vt_shuffle = vec_load_and_shuffle_operand(m_v[VS2REG].s, EL); + + m_v[VDREG].v = vec_vmacf_vmacu(op, vs, vt_shuffle, vec_zero(), &acc_lo, &acc_mid, &acc_hi); + + write_acc_lo(acc, acc_lo); + write_acc_mid(acc, acc_mid); + write_acc_hi(acc, acc_hi); +#else + for (i=0; i < 8; i++) + { + INT32 s1 = (INT32)(INT16)VREG_S(VS1REG, i); + INT32 s2 = (INT32)(INT16)VREG_S(VS2REG, VEC_EL_2(EL, i)); + INT32 r = s1 * s2; + + UINT64 q = (UINT64)(UINT16)ACCUM_LL(i); + q |= (((UINT64)(UINT16)ACCUM_L(i)) << 16); + q |= (((UINT64)(UINT16)ACCUM_M(i)) << 32); + q |= (((UINT64)(UINT16)ACCUM_H(i)) << 48); + + q += (INT64)(r) << 17; + + SET_ACCUM_LL((UINT16)q, i); + SET_ACCUM_L((UINT16)(q >> 16), i); + SET_ACCUM_M((UINT16)(q >> 32), i); + SET_ACCUM_H((UINT16)(q >> 48), i); + + m_vres[i] = SATURATE_ACCUM(i, 1, 0x8000, 0x7fff); + } + WRITEBACK_RESULT(); +#endif + // + break; + } + case 0x09: /* VMACU */ + { + // 31 25 24 20 15 10 5 0 + // ------------------------------------------------------ + // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 001001 | + // ------------------------------------------------------ + // + + //printf("MACU "); +#if USE_SIMD + UINT16 *acc = m_acc.s; + rsp_vec_t acc_lo, acc_mid, acc_hi; + + acc_lo = read_acc_lo(acc); + acc_mid = read_acc_mid(acc); + acc_hi = read_acc_hi(acc); + + rsp_vec_t vs = vec_load_unshuffled_operand(m_v[VS1REG].s); + rsp_vec_t vt_shuffle = vec_load_and_shuffle_operand(m_v[VS2REG].s, EL); + + m_v[VDREG].v = vec_vmacf_vmacu(op, vs, vt_shuffle, vec_zero(), &acc_lo, &acc_mid, &acc_hi); + + write_acc_lo(acc, acc_lo); + write_acc_mid(acc, acc_mid); + write_acc_hi(acc, acc_hi); +#else + for (i = 0; i < 8; i++) + { + INT32 s1 = (INT32)(INT16)VREG_S(VS1REG, i); + INT32 s2 = (INT32)(INT16)VREG_S(VS2REG, VEC_EL_2(EL, i)); + INT32 r1 = s1 * s2; + UINT32 r2 = (UINT16)ACCUM_L(i) + ((UINT16)(r1) * 2); + UINT32 r3 = (UINT16)ACCUM_M(i) + (UINT16)((r1 >> 16) * 2) + (UINT16)(r2 >> 16); + + SET_ACCUM_L((UINT16)(r2), i); + SET_ACCUM_M((UINT16)(r3), i); + SET_ACCUM_H(ACCUM_H(i) + (UINT16)(r3 >> 16) + (UINT16)(r1 >> 31), i); + + if ((INT16)ACCUM_H(i) < 0) + { + m_vres[i] = 0; + } + else + { + if (ACCUM_H(i) != 0) + { + m_vres[i] = 0xffff; + } + else + { + if ((INT16)ACCUM_M(i) < 0) + { + m_vres[i] = 0xffff; + } + else + { + m_vres[i] = ACCUM_M(i); + } + } + } + } + WRITEBACK_RESULT(); +#endif + // + break; + } + + case 0x0c: /* VMADL */ + { + // 31 25 24 20 15 10 5 0 + // ------------------------------------------------------ + // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 001100 | + // ------------------------------------------------------ + // + // Multiplies unsigned fraction by unsigned fraction + // Adds the higher 16 bits of the 32-bit result to accumulator + // The low slice of accumulator is stored into destination element + + //printf("MADL "); +#if USE_SIMD + UINT16 *acc = m_acc.s; + rsp_vec_t acc_lo, acc_mid, acc_hi; + + acc_lo = read_acc_lo(acc); + acc_mid = read_acc_mid(acc); + acc_hi = read_acc_hi(acc); + + rsp_vec_t vs = vec_load_unshuffled_operand(m_v[VS1REG].s); + rsp_vec_t vt_shuffle = vec_load_and_shuffle_operand(m_v[VS2REG].s, EL); + + m_v[VDREG].v = vec_vmadl_vmudl(op, vs, vt_shuffle, vec_zero(), &acc_lo, &acc_mid, &acc_hi); + + write_acc_lo(acc, acc_lo); + write_acc_mid(acc, acc_mid); + write_acc_hi(acc, acc_hi); +#else + for (i = 0; i < 8; i++) + { + UINT32 s1 = (UINT32)(UINT16)VREG_S(VS1REG, i); + UINT32 s2 = (UINT32)(UINT16)VREG_S(VS2REG, VEC_EL_2(EL, i)); + UINT32 r1 = s1 * s2; + UINT32 r2 = (UINT16)ACCUM_L(i) + (r1 >> 16); + UINT32 r3 = (UINT16)ACCUM_M(i) + (r2 >> 16); + + SET_ACCUM_L((UINT16)(r2), i); + SET_ACCUM_M((UINT16)(r3), i); + SET_ACCUM_H(ACCUM_H(i) + (INT16)(r3 >> 16), i); + + m_vres[i] = SATURATE_ACCUM(i, 0, 0x0000, 0xffff); + } + WRITEBACK_RESULT(); +#endif + // + break; + } + + case 0x0d: /* VMADM */ + { + // 31 25 24 20 15 10 5 0 + // ------------------------------------------------------ + // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 001101 | + // ------------------------------------------------------ + // + // Multiplies signed integer by unsigned fraction + // The result is added into accumulator + // The middle slice of accumulator is stored into destination element + + //printf("MADM "); +#if USE_SIMD + UINT16 *acc = m_acc.s; + rsp_vec_t acc_lo, acc_mid, acc_hi; + + acc_lo = read_acc_lo(acc); + acc_mid = read_acc_mid(acc); + acc_hi = read_acc_hi(acc); + + rsp_vec_t vs = vec_load_unshuffled_operand(m_v[VS1REG].s); + rsp_vec_t vt_shuffle = vec_load_and_shuffle_operand(m_v[VS2REG].s, EL); + + m_v[VDREG].v = vec_vmadm_vmudm(op, vs, vt_shuffle, vec_zero(), &acc_lo, &acc_mid, &acc_hi); + + write_acc_lo(acc, acc_lo); + write_acc_mid(acc, acc_mid); + write_acc_hi(acc, acc_hi); +#else + for (i=0; i < 8; i++) + { + UINT32 s1 = (INT32)(INT16)VREG_S(VS1REG, i); + UINT32 s2 = (UINT16)VREG_S(VS2REG, VEC_EL_2(EL, i)); // not sign-extended + UINT32 r1 = s1 * s2; + UINT32 r2 = (UINT16)ACCUM_L(i) + (UINT16)(r1); + UINT32 r3 = (UINT16)ACCUM_M(i) + (r1 >> 16) + (r2 >> 16); + + SET_ACCUM_L((UINT16)(r2), i); + SET_ACCUM_M((UINT16)(r3), i); + SET_ACCUM_H(ACCUM_H(i) + (UINT16)(r3 >> 16), i); + if ((INT32)(r1) < 0) + SET_ACCUM_H(ACCUM_H(i) - 1, i); + + m_vres[i] = SATURATE_ACCUM(i, 1, 0x8000, 0x7fff); + } + WRITEBACK_RESULT(); +#endif + // + break; + } + + case 0x0e: /* VMADN */ + { + // 31 25 24 20 15 10 5 0 + // ------------------------------------------------------ + // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 001110 | + // ------------------------------------------------------ + // + // Multiplies unsigned fraction by signed integer + // The result is added into accumulator + // The low slice of accumulator is stored into destination element + + //printf("MADN "); +#if USE_SIMD + UINT16 *acc = m_acc.s; + rsp_vec_t acc_lo, acc_mid, acc_hi; + + acc_lo = read_acc_lo(acc); + acc_mid = read_acc_mid(acc); + acc_hi = read_acc_hi(acc); + + rsp_vec_t vs = vec_load_unshuffled_operand(m_v[VS1REG].s); + rsp_vec_t vt_shuffle = vec_load_and_shuffle_operand(m_v[VS2REG].s, EL); + + m_v[VDREG].v = vec_vmadn_vmudn(op, vs, vt_shuffle, vec_zero(), &acc_lo, &acc_mid, &acc_hi); + + write_acc_lo(acc, acc_lo); + write_acc_mid(acc, acc_mid); + write_acc_hi(acc, acc_hi); +#else + for (i=0; i < 8; i++) + { + INT32 s1 = (UINT16)VREG_S(VS1REG, i); // not sign-extended + INT32 s2 = (INT32)(INT16)VREG_S(VS2REG, VEC_EL_2(EL, i)); + + UINT64 q = (UINT64)ACCUM_LL(i); + q |= (((UINT64)ACCUM_L(i)) << 16); + q |= (((UINT64)ACCUM_M(i)) << 32); + q |= (((UINT64)ACCUM_H(i)) << 48); + q += (INT64)(s1*s2) << 16; + + SET_ACCUM_LL((UINT16)q, i); + SET_ACCUM_L((UINT16)(q >> 16), i); + SET_ACCUM_M((UINT16)(q >> 32), i); + SET_ACCUM_H((UINT16)(q >> 48), i); + + m_vres[i] = SATURATE_ACCUM(i, 0, 0x0000, 0xffff); + } + WRITEBACK_RESULT(); + +#endif + // + break; + } + + case 0x0f: /* VMADH */ + { + // 31 25 24 20 15 10 5 0 + // ------------------------------------------------------ + // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 001111 | + // ------------------------------------------------------ + // + // Multiplies signed integer by signed integer + // The result is added into highest 32 bits of accumulator, the low slice is zero + // The highest 32 bits of accumulator is saturated into destination element + + //printf("MADH "); +#if USE_SIMD + UINT16 *acc = m_acc.s; + rsp_vec_t acc_lo, acc_mid, acc_hi; + + acc_lo = read_acc_lo(acc); + acc_mid = read_acc_mid(acc); + acc_hi = read_acc_hi(acc); + + rsp_vec_t vs = vec_load_unshuffled_operand(m_v[VS1REG].s); + rsp_vec_t vt_shuffle = vec_load_and_shuffle_operand(m_v[VS2REG].s, EL); + + m_v[VDREG].v = vec_vmadh_vmudh(op, vs, vt_shuffle, vec_zero(), &acc_lo, &acc_mid, &acc_hi); + + write_acc_lo(acc, acc_lo); + write_acc_mid(acc, acc_mid); + write_acc_hi(acc, acc_hi); +#else + for (i = 0; i < 8; i++) + { + INT32 s1 = (INT32)(INT16)VREG_S(VS1REG, i); + INT32 s2 = (INT32)(INT16)VREG_S(VS2REG, VEC_EL_2(EL, i)); + + INT32 accum = (UINT32)(UINT16)ACCUM_M(i); + accum |= ((UINT32)((UINT16)ACCUM_H(i))) << 16; + accum += s1 * s2; + + SET_ACCUM_H((UINT16)(accum >> 16), i); + SET_ACCUM_M((UINT16)accum, i); + + m_vres[i] = SATURATE_ACCUM(i, 1, 0x8000, 0x7fff); + } + WRITEBACK_RESULT(); + +#endif + // + break; + } + + case 0x10: /* VADD */ + { + // 31 25 24 20 15 10 5 0 + // ------------------------------------------------------ + // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 010000 | + // ------------------------------------------------------ + // + // Adds two vector registers and carry flag, the result is saturated to 32767 + + // TODO: check VS2REG == VDREG + + //printf("ADD "); +#if USE_SIMD + rsp_vec_t acc_lo; + UINT16 *acc = m_acc.s; + rsp_vec_t carry = read_vco_lo(m_flags[RSP_VCO].s); + + rsp_vec_t vs = vec_load_unshuffled_operand(m_v[VS1REG].s); + rsp_vec_t vt_shuffle = vec_load_and_shuffle_operand(m_v[VS2REG].s, EL); + + m_v[VDREG].v = vec_vadd(vs, vt_shuffle, carry, &acc_lo); + + write_vco_hi(m_flags[RSP_VCO].s, vec_zero()); + write_vco_lo(m_flags[RSP_VCO].s, vec_zero()); + write_acc_lo(acc, acc_lo); +#else + for (i=0; i < 8; i++) + { + INT32 s1 = (INT32)(INT16)VREG_S(VS1REG, i); + INT32 s2 = (INT32)(INT16)VREG_S(VS2REG, VEC_EL_2(EL, i)); + INT32 r = s1 + s2 + (CARRY_FLAG(i) != 0 ? 1 : 0); + + SET_ACCUM_L((INT16)(r), i); + + if (r > 32767) r = 32767; + if (r < -32768) r = -32768; + m_vres[i] = (INT16)(r); + } + CLEAR_ZERO_FLAGS(); + CLEAR_CARRY_FLAGS(); + WRITEBACK_RESULT(); +#endif + // + break; + } + + case 0x11: /* VSUB */ + { + // 31 25 24 20 15 10 5 0 + // ------------------------------------------------------ + // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 010001 | + // ------------------------------------------------------ + // + // Subtracts two vector registers and carry flag, the result is saturated to -32768 + + // TODO: check VS2REG == VDREG + + //printf("SUB "); +#if USE_SIMD + rsp_vec_t acc_lo; + UINT16 *acc = m_acc.s; + rsp_vec_t carry = read_vco_lo(m_flags[RSP_VCO].s); + + rsp_vec_t vs = vec_load_unshuffled_operand(m_v[VS1REG].s); + rsp_vec_t vt_shuffle = vec_load_and_shuffle_operand(m_v[VS2REG].s, EL); + + m_v[VDREG].v = vec_vsub(vs, vt_shuffle, carry, &acc_lo); + + write_vco_hi(m_flags[RSP_VCO].s, vec_zero()); + write_vco_lo(m_flags[RSP_VCO].s, vec_zero()); + write_acc_lo(acc, acc_lo); +#else + for (i = 0; i < 8; i++) + { + INT32 s1 = (INT32)(INT16)VREG_S(VS1REG, i); + INT32 s2 = (INT32)(INT16)VREG_S(VS2REG, VEC_EL_2(EL, i)); + INT32 r = s1 - s2 - (CARRY_FLAG(i) != 0 ? 1 : 0); + + SET_ACCUM_L((INT16)(r), i); + + if (r > 32767) r = 32767; + if (r < -32768) r = -32768; + + m_vres[i] = (INT16)(r); + } + CLEAR_ZERO_FLAGS(); + CLEAR_CARRY_FLAGS(); + WRITEBACK_RESULT(); +#endif + // + break; + } + + case 0x13: /* VABS */ + { + // 31 25 24 20 15 10 5 0 + // ------------------------------------------------------ + // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 010011 | + // ------------------------------------------------------ + // + // Changes the sign of source register 2 if source register 1 is negative and stores + // the result to destination register + + //printf("ABS "); +#if USE_SIMD + rsp_vec_t acc_lo; + UINT16 *acc = m_acc.s; + + rsp_vec_t vs = vec_load_unshuffled_operand(m_v[VS1REG].s); + rsp_vec_t vt_shuffle = vec_load_and_shuffle_operand(m_v[VS2REG].s, EL); + + m_v[VDREG].v = vec_vabs(vs, vt_shuffle, vec_zero(), &acc_lo); + + write_acc_lo(acc, acc_lo); +#else + for (i=0; i < 8; i++) + { + INT16 s1 = (INT16)VREG_S(VS1REG, i); + INT16 s2 = (INT16)VREG_S(VS2REG, VEC_EL_2(EL, i)); + + if (s1 < 0) + { + if (s2 == -32768) + { + m_vres[i] = 32767; + } + else + { + m_vres[i] = -s2; + } + } + else if (s1 > 0) + { + m_vres[i] = s2; + } + else + { + m_vres[i] = 0; + } + + SET_ACCUM_L(m_vres[i], i); + } + WRITEBACK_RESULT(); +#endif + // + break; + } + + case 0x14: /* VADDC */ + { + // 31 25 24 20 15 10 5 0 + // ------------------------------------------------------ + // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 010100 | + // ------------------------------------------------------ + // + // Adds two vector registers, the carry out is stored into carry register + + // TODO: check VS2REG = VDREG + + //printf("ADDC "); +#if USE_SIMD + UINT16 *acc = m_acc.s; + rsp_vec_t sn; + + rsp_vec_t vs = vec_load_unshuffled_operand(m_v[VS1REG].s); + rsp_vec_t vt_shuffle = vec_load_and_shuffle_operand(m_v[VS2REG].s, EL); + + m_v[VDREG].v = vec_vaddc(vs, vt_shuffle, vec_zero(), &sn); + + write_vco_hi(m_flags[RSP_VCO].s, vec_zero()); + write_vco_lo(m_flags[RSP_VCO].s, sn); + write_acc_lo(acc, m_v[VDREG].v); +#else + CLEAR_ZERO_FLAGS(); + CLEAR_CARRY_FLAGS(); + + for (i=0; i < 8; i++) + { + INT32 s1 = (UINT32)(UINT16)VREG_S(VS1REG, i); + INT32 s2 = (UINT32)(UINT16)VREG_S(VS2REG, VEC_EL_2(EL, i)); + INT32 r = s1 + s2; + + m_vres[i] = (INT16)(r); + SET_ACCUM_L((INT16)(r), i); + + if (r & 0xffff0000) + { + SET_CARRY_FLAG(i); + } + } + WRITEBACK_RESULT(); +#endif + // + break; + } + + case 0x15: /* VSUBC */ + { + // 31 25 24 20 15 10 5 0 + // ------------------------------------------------------ + // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 010101 | + // ------------------------------------------------------ + // + // Subtracts two vector registers, the carry out is stored into carry register + + // TODO: check VS2REG = VDREG + + //printf("SUBC "); +#if USE_SIMD + UINT16 *acc = m_acc.s; + rsp_vec_t eq, sn; + + rsp_vec_t vs = vec_load_unshuffled_operand(m_v[VS1REG].s); + rsp_vec_t vt_shuffle = vec_load_and_shuffle_operand(m_v[VS2REG].s, EL); + + m_v[VDREG].v = vec_vsubc(vs, vt_shuffle, vec_zero(), &eq, &sn); + + write_vco_hi(m_flags[RSP_VCO].s, eq); + write_vco_lo(m_flags[RSP_VCO].s, sn); + write_acc_lo(acc, m_v[VDREG].v); +#else + CLEAR_ZERO_FLAGS(); + CLEAR_CARRY_FLAGS(); + + for (i=0; i < 8; i++) + { + INT32 s1 = (UINT32)(UINT16)VREG_S(VS1REG, i); + INT32 s2 = (UINT32)(UINT16)VREG_S(VS2REG, VEC_EL_2(EL, i)); + INT32 r = s1 - s2; + + m_vres[i] = (INT16)(r); + SET_ACCUM_L((UINT16)(r), i); + + if ((UINT16)(r) != 0) + { + SET_ZERO_FLAG(i); + } + if (r & 0xffff0000) + { + SET_CARRY_FLAG(i); + } + } + WRITEBACK_RESULT(); +#endif + // + break; + } + + case 0x1d: /* VSAW */ + { + // 31 25 24 20 15 10 5 0 + // ------------------------------------------------------ + // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 011101 | + // ------------------------------------------------------ + // + // Stores high, middle or low slice of accumulator to destination vector + + //printf("SAW "); +#if USE_SIMD + UINT16 *acc = m_acc.s; + switch (EL) + { + case 8: + m_v[VDREG].v = read_acc_hi(acc); + break; + case 9: + m_v[VDREG].v = read_acc_mid(acc); + break; + case 10: + m_v[VDREG].v = read_acc_lo(acc); + break; + + default: + m_v[VDREG].v = _mm_setzero_si128(); + break; + } +#else + switch (EL) + { + case 0x08: // VSAWH + { + for (i=0; i < 8; i++) + { + VREG_S(VDREG, i) = ACCUM_H(i); + } + break; + } + case 0x09: // VSAWM + { + for (i=0; i < 8; i++) + { + VREG_S(VDREG, i) = ACCUM_M(i); + } + break; + } + case 0x0a: // VSAWL + { + for (i=0; i < 8; i++) + { + VREG_S(VDREG, i) = ACCUM_L(i); + } + break; + } + default: //fatalerror("RSP: VSAW: el = %d\n", EL);//??????? + printf("RSP: VSAW: el = %d\n", EL);//??? ??? + exit(0); + } +#endif + // + break; + } + + case 0x20: /* VLT */ + { + // 31 25 24 20 15 10 5 0 + // ------------------------------------------------------ + // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 100000 | + // ------------------------------------------------------ + // + // Sets compare flags if elements in VS1 are less than VS2 + // Moves the element in VS2 to destination vector + + //printf("LT "); +#if USE_SIMD + UINT16 *acc = m_acc.s; + rsp_vec_t le; + + rsp_vec_t eq = read_vco_hi(m_flags[RSP_VCO].s); + rsp_vec_t sign = read_vco_lo(m_flags[RSP_VCO].s); + + rsp_vec_t vs = vec_load_unshuffled_operand(m_v[VS1REG].s); + rsp_vec_t vt_shuffle = vec_load_and_shuffle_operand(m_v[VS2REG].s, EL); + + m_v[VDREG].v = vec_veq_vge_vlt_vne(op, vs, vt_shuffle, vec_zero(), &le, eq, sign); + + write_vcc_hi(m_flags[RSP_VCC].s, vec_zero()); + write_vcc_lo(m_flags[RSP_VCC].s, le); + write_vco_hi(m_flags[RSP_VCO].s, vec_zero()); + write_vco_lo(m_flags[RSP_VCO].s, vec_zero()); + write_acc_lo(acc, m_v[VDREG].v); +#else + CLEAR_COMPARE_FLAGS(); + CLEAR_CLIP2_FLAGS(); + + for (i=0; i < 8; i++) + { + INT16 s1, s2; + s1 = VREG_S(VS1REG, i); + s2 = VREG_S(VS2REG, VEC_EL_2(EL, i)); + if (s1 < s2) + { + SET_COMPARE_FLAG(i); + } + else if (s1 == s2) + { + if (ZERO_FLAG(i) != 0 && CARRY_FLAG(i) != 0) + { + SET_COMPARE_FLAG(i); + } + } + + if (COMPARE_FLAG(i) != 0) + { + m_vres[i] = s1; + } + else + { + m_vres[i] = s2; + } + + SET_ACCUM_L(m_vres[i], i); + } + + CLEAR_CARRY_FLAGS(); + CLEAR_ZERO_FLAGS(); + WRITEBACK_RESULT(); +#endif + // + break; + } + + case 0x21: /* VEQ */ + { + // 31 25 24 20 15 10 5 0 + // ------------------------------------------------------ + // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 100001 | + // ------------------------------------------------------ + // + // Sets compare flags if elements in VS1 are equal with VS2 + // Moves the element in VS2 to destination vector + + //printf("EQ "); +#if USE_SIMD + UINT16 *acc = m_acc.s; + rsp_vec_t le; + + rsp_vec_t eq = read_vco_hi(m_flags[RSP_VCO].s); + rsp_vec_t sign = read_vco_lo(m_flags[RSP_VCO].s); + + rsp_vec_t vs = vec_load_unshuffled_operand(m_v[VS1REG].s); + rsp_vec_t vt_shuffle = vec_load_and_shuffle_operand(m_v[VS2REG].s, EL); + + m_v[VDREG].v = vec_veq_vge_vlt_vne(op, vs, vt_shuffle, vec_zero(), &le, eq, sign); + + write_vcc_hi(m_flags[RSP_VCC].s, vec_zero()); + write_vcc_lo(m_flags[RSP_VCC].s, le); + write_vco_hi(m_flags[RSP_VCO].s, vec_zero()); + write_vco_lo(m_flags[RSP_VCO].s, vec_zero()); + write_acc_lo(acc, m_v[VDREG].v); +#else + CLEAR_COMPARE_FLAGS(); + CLEAR_CLIP2_FLAGS(); + + for (i = 0; i < 8; i++) + { + INT16 s1 = VREG_S(VS1REG, i); + INT16 s2 = VREG_S(VS2REG, VEC_EL_2(EL, i)); + + if ((s1 == s2) && ZERO_FLAG(i) == 0) + { + SET_COMPARE_FLAG(i); + m_vres[i] = s1; + } + else + { + m_vres[i] = s2; + } + SET_ACCUM_L(m_vres[i], i); + } + + CLEAR_ZERO_FLAGS(); + CLEAR_CARRY_FLAGS(); + WRITEBACK_RESULT(); +#endif + // + break; + } + + case 0x22: /* VNE */ + { + // 31 25 24 20 15 10 5 0 + // ------------------------------------------------------ + // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 100010 | + // ------------------------------------------------------ + // + // Sets compare flags if elements in VS1 are not equal with VS2 + // Moves the element in VS2 to destination vector + + //printf("NE "); +#if USE_SIMD + UINT16 *acc = m_acc.s; + rsp_vec_t le; + + rsp_vec_t eq = read_vco_hi(m_flags[RSP_VCO].s); + rsp_vec_t sign = read_vco_lo(m_flags[RSP_VCO].s); + + rsp_vec_t vs = vec_load_unshuffled_operand(m_v[VS1REG].s); + rsp_vec_t vt_shuffle = vec_load_and_shuffle_operand(m_v[VS2REG].s, EL); + + m_v[VDREG].v = vec_veq_vge_vlt_vne(op, vs, vt_shuffle, vec_zero(), &le, eq, sign); + + write_vcc_hi(m_flags[RSP_VCC].s, vec_zero()); + write_vcc_lo(m_flags[RSP_VCC].s, le); + write_vco_hi(m_flags[RSP_VCO].s, vec_zero()); + write_vco_lo(m_flags[RSP_VCO].s, vec_zero()); + write_acc_lo(acc, m_v[VDREG].v); +#else + CLEAR_COMPARE_FLAGS(); + CLEAR_CLIP2_FLAGS(); + + for (i = 0; i < 8; i++) + { + INT16 s1 = VREG_S(VS1REG, i); + INT16 s2 = VREG_S(VS2REG, VEC_EL_2(EL, i)); + + if (s1 != s2 || ZERO_FLAG(i) != 0) + { + SET_COMPARE_FLAG(i); + m_vres[i] = s1; + } + else + { + m_vres[i] = s2; + } + + SET_ACCUM_L(m_vres[i], i); + } + + CLEAR_CARRY_FLAGS(); + CLEAR_ZERO_FLAGS(); + WRITEBACK_RESULT(); +#endif + // + break; + } + + case 0x23: /* VGE */ + { + // 31 25 24 20 15 10 5 0 + // ------------------------------------------------------ + // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 100011 | + // ------------------------------------------------------ + // + // Sets compare flags if elements in VS1 are greater or equal with VS2 + // Moves the element in VS2 to destination vector + + //printf("GE "); +#if USE_SIMD + UINT16 *acc = m_acc.s; + rsp_vec_t le; + + rsp_vec_t eq = read_vco_hi(m_flags[RSP_VCO].s); + rsp_vec_t sign = read_vco_lo(m_flags[RSP_VCO].s); + + rsp_vec_t vs = vec_load_unshuffled_operand(m_v[VS1REG].s); + rsp_vec_t vt_shuffle = vec_load_and_shuffle_operand(m_v[VS2REG].s, EL); + + m_v[VDREG].v = vec_veq_vge_vlt_vne(op, vs, vt_shuffle, vec_zero(), &le, eq, sign); + + write_vcc_hi(m_flags[RSP_VCC].s, vec_zero()); + write_vcc_lo(m_flags[RSP_VCC].s, le); + write_vco_hi(m_flags[RSP_VCO].s, vec_zero()); + write_vco_lo(m_flags[RSP_VCO].s, vec_zero()); + write_acc_lo(acc, m_v[VDREG].v); +#else + CLEAR_COMPARE_FLAGS(); + CLEAR_CLIP2_FLAGS(); + + for (i=0; i < 8; i++) + { + INT16 s1 = VREG_S(VS1REG, i); + INT16 s2 = VREG_S(VS2REG, VEC_EL_2(EL, i)); + + if ((s1 == s2 && (ZERO_FLAG(i) == 0 || CARRY_FLAG(i) == 0)) || s1 > s2) + { + SET_COMPARE_FLAG(i); + m_vres[i] = s1; + } + else + { + m_vres[i] = s2; + } + + SET_ACCUM_L(m_vres[i], i); + } + + CLEAR_CARRY_FLAGS(); + CLEAR_ZERO_FLAGS(); + WRITEBACK_RESULT(); +#endif + // + break; + } + + case 0x24: /* VCL */ + { + // 31 25 24 20 15 10 5 0 + // ------------------------------------------------------ + // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 100100 | + // ------------------------------------------------------ + // + // Vector clip low + + //printf("CL "); +#if USE_SIMD + UINT16 *acc = m_acc.s; + + rsp_vec_t ge = read_vcc_hi(m_flags[RSP_VCC].s); + rsp_vec_t le = read_vcc_lo(m_flags[RSP_VCC].s); + rsp_vec_t eq = read_vco_hi(m_flags[RSP_VCO].s); + rsp_vec_t sign = read_vco_lo(m_flags[RSP_VCO].s); + rsp_vec_t vce = read_vce(m_flags[RSP_VCE].s); + + rsp_vec_t vs = vec_load_unshuffled_operand(m_v[VS1REG].s); + rsp_vec_t vt_shuffle = vec_load_and_shuffle_operand(m_v[VS2REG].s, EL); + m_v[VDREG].v = vec_vcl(vs, vt_shuffle, vec_zero(), &ge, &le, eq, sign, vce); + + write_vcc_hi(m_flags[RSP_VCC].s, ge); + write_vcc_lo(m_flags[RSP_VCC].s, le); + write_vco_hi(m_flags[RSP_VCO].s, vec_zero()); + write_vco_lo(m_flags[RSP_VCO].s, vec_zero()); + write_vce(m_flags[RSP_VCE].s, vec_zero()); + write_acc_lo(acc, m_v[VDREG].v); +#else + for (i = 0; i < 8; i++) + { + INT16 s1 = VREG_S(VS1REG, i); + INT16 s2 = VREG_S(VS2REG, VEC_EL_2(EL, i)); + + if (CARRY_FLAG(i) != 0) // vco_lo + { + if (ZERO_FLAG(i) != 0) // vco_hi + { + if (COMPARE_FLAG(i) != 0) // vcc_lo + { + SET_ACCUM_L(-(UINT16)s2, i); + } + else + { + SET_ACCUM_L(s1, i); + } + } + else + { + if (CLIP1_FLAG(i) != 0) // vce + { + if (((UINT32)(UINT16)(s1) + (UINT32)(UINT16)(s2)) > 0x10000) + { + SET_ACCUM_L(s1, i); + CLEAR_COMPARE_FLAG(i); + } + else + { + SET_ACCUM_L(-((UINT16)s2), i); + SET_COMPARE_FLAG(i); + } + } + else + { + if (((UINT32)(UINT16)(s1) + (UINT32)(UINT16)(s2)) != 0) + { + SET_ACCUM_L(s1, i); + CLEAR_COMPARE_FLAG(i); + } + else + { + SET_ACCUM_L(-((UINT16)s2), i); + SET_COMPARE_FLAG(i); + } + } + } + } + else + { + if (ZERO_FLAG(i) != 0) // vco_hi + { + if (CLIP2_FLAG(i) != 0) // vcc_hi + { + SET_ACCUM_L(s2, i); + } + else + { + SET_ACCUM_L(s1, i); + } + } + else + { + if (((INT32)(UINT16)s1 - (INT32)(UINT16)s2) >= 0) + { + SET_ACCUM_L(s2, i); + SET_CLIP2_FLAG(i); + } + else + { + SET_ACCUM_L(s1, i); + CLEAR_CLIP2_FLAG(i); + } + } + } + + m_vres[i] = ACCUM_L(i); + } + CLEAR_CARRY_FLAGS(); // vco_lo + CLEAR_ZERO_FLAGS(); // vco_hi + CLEAR_CLIP1_FLAGS(); // vce + WRITEBACK_RESULT(); +#endif + // + break; + } + + case 0x25: /* VCH */ + { + // 31 25 24 20 15 10 5 0 + // ------------------------------------------------------ + // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 100101 | + // ------------------------------------------------------ + // + // Vector clip high + + //printf("CH "); +#if USE_SIMD + UINT16 *acc = m_acc.s; + rsp_vec_t ge, le, sign, eq, vce; + + rsp_vec_t vs = vec_load_unshuffled_operand(m_v[VS1REG].s); + rsp_vec_t vt_shuffle = vec_load_and_shuffle_operand(m_v[VS2REG].s, EL); + + m_v[VDREG].v = vec_vch(vs, vt_shuffle, vec_zero(), &ge, &le, &eq, &sign, &vce); + + write_vcc_hi(m_flags[RSP_VCC].s, ge); + write_vcc_lo(m_flags[RSP_VCC].s, le); + write_vco_hi(m_flags[RSP_VCO].s, eq); + write_vco_lo(m_flags[RSP_VCO].s, sign); + write_vce(m_flags[RSP_VCE].s, vce); + write_acc_lo(acc, m_v[VDREG].v); +#else + CLEAR_CARRY_FLAGS(); + CLEAR_COMPARE_FLAGS(); + CLEAR_CLIP1_FLAGS(); + CLEAR_ZERO_FLAGS(); + CLEAR_CLIP2_FLAGS(); + UINT32 vce = 0; + + for (i=0; i < 8; i++) + { + INT16 s1 = VREG_S(VS1REG, i); + INT16 s2 = VREG_S(VS2REG, VEC_EL_2(EL, i)); + + if ((s1 ^ s2) < 0) + { + vce = (s1 + s2 == -1); + SET_CARRY_FLAG(i); + if (s2 < 0) + { + SET_CLIP2_FLAG(i); + } + + if (s1 + s2 <= 0) + { + SET_COMPARE_FLAG(i); + m_vres[i] = -((UINT16)s2); + } + else + { + m_vres[i] = s1; + } + + if (s1 + s2 != 0) + { + if (s1 != ~s2) + { + SET_ZERO_FLAG(i); + } + } + } + else + { + vce = 0; + if (s2 < 0) + { + SET_COMPARE_FLAG(i); + } + if (s1 - s2 >= 0) + { + SET_CLIP2_FLAG(i); + m_vres[i] = s2; + } + else + { + m_vres[i] = s1; + } + + if ((s1 - s2) != 0) + { + if (s1 != ~s2) + { + SET_ZERO_FLAG(i); + } + } + } + if (vce != 0) + { + SET_CLIP1_FLAG(i); + } + + SET_ACCUM_L(m_vres[i], i); + } + WRITEBACK_RESULT(); +#endif + // + break; + } + + case 0x26: /* VCR */ + { + // 31 25 24 20 15 10 5 0 + // ------------------------------------------------------ + // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 100110 | + // ------------------------------------------------------ + // + // Vector clip reverse + + //printf("CR "); +#if USE_SIMD + UINT16 *acc = m_acc.s; + rsp_vec_t ge, le; + + rsp_vec_t vs = vec_load_unshuffled_operand(m_v[VS1REG].s); + rsp_vec_t vt_shuffle = vec_load_and_shuffle_operand(m_v[VS2REG].s, EL); + + m_v[VDREG].v = vec_vcr(vs, vt_shuffle, vec_zero(), &ge, &le); + + write_vcc_hi(m_flags[RSP_VCC].s, ge); + write_vcc_lo(m_flags[RSP_VCC].s, le); + write_vco_hi(m_flags[RSP_VCO].s, vec_zero()); + write_vco_lo(m_flags[RSP_VCO].s, vec_zero()); + write_vce(m_flags[RSP_VCE].s, vec_zero()); + write_acc_lo(acc, m_v[VDREG].v); +#else + CLEAR_CARRY_FLAGS(); + CLEAR_COMPARE_FLAGS(); + CLEAR_CLIP1_FLAGS(); + CLEAR_ZERO_FLAGS(); + CLEAR_CLIP2_FLAGS(); + + for (i=0; i < 8; i++) + { + INT16 s1 = VREG_S(VS1REG, i); + INT16 s2 = VREG_S(VS2REG, VEC_EL_2(EL, i)); + + if ((INT16)(s1 ^ s2) < 0) + { + if (s2 < 0) + { + SET_CLIP2_FLAG(i); + } + if ((s1 + s2) <= 0) + { + SET_ACCUM_L(~((UINT16)s2), i); + SET_COMPARE_FLAG(i); + } + else + { + SET_ACCUM_L(s1, i); + } + } + else + { + if (s2 < 0) + { + SET_COMPARE_FLAG(i); + } + if ((s1 - s2) >= 0) + { + SET_ACCUM_L(s2, i); + SET_CLIP2_FLAG(i); + } + else + { + SET_ACCUM_L(s1, i); + } + } + + m_vres[i] = ACCUM_L(i); + } + WRITEBACK_RESULT(); +#endif + // + break; + } + + case 0x27: /* VMRG */ + { + // 31 25 24 20 15 10 5 0 + // ------------------------------------------------------ + // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 100111 | + // ------------------------------------------------------ + // + // Merges two vectors according to compare flags + + //printf("MRG "); +#if USE_SIMD + UINT16 *acc = m_acc.s; + rsp_vec_t le = read_vcc_lo(m_flags[RSP_VCC].s); + + rsp_vec_t vs = vec_load_unshuffled_operand(m_v[VS1REG].s); + rsp_vec_t vt_shuffle = vec_load_and_shuffle_operand(m_v[VS2REG].s, EL); + + m_v[VDREG].v = vec_vmrg(vs, vt_shuffle, le); + + write_vco_hi(m_flags[RSP_VCO].s, vec_zero()); + write_vco_lo(m_flags[RSP_VCO].s, vec_zero()); + write_acc_lo(acc, m_v[VDREG].v); +#else + for (i = 0; i < 8; i++) + { + if (COMPARE_FLAG(i) != 0) + { + m_vres[i] = VREG_S(VS1REG, i); + } + else + { + m_vres[i] = VREG_S(VS2REG, VEC_EL_2(EL, i)); + } + + SET_ACCUM_L(m_vres[i], i); + } + WRITEBACK_RESULT(); +#endif + // + break; + } + case 0x28: /* VAND */ + { + // 31 25 24 20 15 10 5 0 + // ------------------------------------------------------ + // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 101000 | + // ------------------------------------------------------ + // + // Bitwise AND of two vector registers + + //printf("AND "); +#if USE_SIMD + UINT16 *acc = m_acc.s; + + rsp_vec_t vs = vec_load_unshuffled_operand(m_v[VS1REG].s); + rsp_vec_t vt_shuffle = vec_load_and_shuffle_operand(m_v[VS2REG].s, EL); + + m_v[VDREG].v = vec_vand_vnand(op, vs, vt_shuffle); + + write_acc_lo(acc, m_v[VDREG].v); +#else + for (i = 0; i < 8; i++) + { + m_vres[i] = VREG_S(VS1REG, i) & VREG_S(VS2REG, VEC_EL_2(EL, i)); + SET_ACCUM_L(m_vres[i], i); + } + WRITEBACK_RESULT(); +#endif + // + break; + } + case 0x29: /* VNAND */ + { + // 31 25 24 20 15 10 5 0 + // ------------------------------------------------------ + // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 101001 | + // ------------------------------------------------------ + // + // Bitwise NOT AND of two vector registers + + //printf("NAND "); +#if USE_SIMD + UINT16 *acc = m_acc.s; + + rsp_vec_t vs = vec_load_unshuffled_operand(m_v[VS1REG].s); + rsp_vec_t vt_shuffle = vec_load_and_shuffle_operand(m_v[VS2REG].s, EL); + + m_v[VDREG].v = vec_vand_vnand(op, vs, vt_shuffle); + + write_acc_lo(acc, m_v[VDREG].v); +#else + for (i = 0; i < 8; i++) + { + m_vres[i] = ~((VREG_S(VS1REG, i) & VREG_S(VS2REG, VEC_EL_2(EL, i)))); + SET_ACCUM_L(m_vres[i], i); + } + WRITEBACK_RESULT(); +#endif + // + break; + } + case 0x2a: /* VOR */ + { + // 31 25 24 20 15 10 5 0 + // ------------------------------------------------------ + // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 101010 | + // ------------------------------------------------------ + // + // Bitwise OR of two vector registers + + //printf("OR "); +#if USE_SIMD + UINT16 *acc = m_acc.s; + + rsp_vec_t vs = vec_load_unshuffled_operand(m_v[VS1REG].s); + rsp_vec_t vt_shuffle = vec_load_and_shuffle_operand(m_v[VS2REG].s, EL); + + m_v[VDREG].v = vec_vor_vnor(op, vs, vt_shuffle); + + write_acc_lo(acc, m_v[VDREG].v); +#else + for (i = 0; i < 8; i++) + { + m_vres[i] = VREG_S(VS1REG, i) | VREG_S(VS2REG, VEC_EL_2(EL, i)); + SET_ACCUM_L(m_vres[i], i); + } + WRITEBACK_RESULT(); +#endif + // + break; + } + case 0x2b: /* VNOR */ + { + // 31 25 24 20 15 10 5 0 + // ------------------------------------------------------ + // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 101011 | + // ------------------------------------------------------ + // + // Bitwise NOT OR of two vector registers + + //printf("NOR "); +#if USE_SIMD + UINT16 *acc = m_acc.s; + + rsp_vec_t vs = vec_load_unshuffled_operand(m_v[VS1REG].s); + rsp_vec_t vt_shuffle = vec_load_and_shuffle_operand(m_v[VS2REG].s, EL); + + m_v[VDREG].v = vec_vor_vnor(op, vs, vt_shuffle); + + write_acc_lo(acc, m_v[VDREG].v); +#else + for (i=0; i < 8; i++) + { + m_vres[i] = ~((VREG_S(VS1REG, i) | VREG_S(VS2REG, VEC_EL_2(EL, i)))); + SET_ACCUM_L(m_vres[i], i); + } + WRITEBACK_RESULT(); +#endif + // + break; + } + case 0x2c: /* VXOR */ + { + // 31 25 24 20 15 10 5 0 + // ------------------------------------------------------ + // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 101100 | + // ------------------------------------------------------ + // + // Bitwise XOR of two vector registers + + //printf("XOR "); +#if USE_SIMD + UINT16 *acc = m_acc.s; + + rsp_vec_t vs = vec_load_unshuffled_operand(m_v[VS1REG].s); + rsp_vec_t vt_shuffle = vec_load_and_shuffle_operand(m_v[VS2REG].s, EL); + + m_v[VDREG].v = vec_vxor_vnxor(op, vs, vt_shuffle); + + write_acc_lo(acc, m_v[VDREG].v); +#else + for (i=0; i < 8; i++) + { + m_vres[i] = VREG_S(VS1REG, i) ^ VREG_S(VS2REG, VEC_EL_2(EL, i)); + SET_ACCUM_L(m_vres[i], i); + } + WRITEBACK_RESULT(); +#endif + // + break; + } + case 0x2d: /* VNXOR */ + { + // 31 25 24 20 15 10 5 0 + // ------------------------------------------------------ + // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 101101 | + // ------------------------------------------------------ + // + // Bitwise NOT XOR of two vector registers + + //printf("NXOR "); +#if USE_SIMD + UINT16 *acc = m_acc.s; + + rsp_vec_t vs = vec_load_unshuffled_operand(m_v[VS1REG].s); + rsp_vec_t vt_shuffle = vec_load_and_shuffle_operand(m_v[VS2REG].s, EL); + + m_v[VDREG].v = vec_vxor_vnxor(op, vs, vt_shuffle); + + write_acc_lo(acc, m_v[VDREG].v); +#else + for (i=0; i < 8; i++) + { + m_vres[i] = ~((VREG_S(VS1REG, i) ^ VREG_S(VS2REG, VEC_EL_2(EL, i)))); + SET_ACCUM_L(m_vres[i], i); + } + WRITEBACK_RESULT(); +#endif + // + break; + } + + case 0x30: /* VRCP */ + { + // 31 25 24 20 15 10 5 0 + // ------------------------------------------------------ + // | 010010 | 1 | EEEE | SSSSS | ?FFFF | DDDDD | 110000 | + // ------------------------------------------------------ + // + // Calculates reciprocal + + //printf("RCP "); +#if USE_SIMD + write_acc_lo(m_acc.s, vec_load_and_shuffle_operand(m_v[VS2REG].s, EL)); + + INT32 dp = op & m_dp_flag; + m_dp_flag = 0; + + m_v[VDREG].v = vec_vrcp_vrsq(op, dp, VS2REG, EL, VDREG, VS1REG); +#else + INT32 shifter = 0; + + INT32 rec = (INT16)(VREG_S(VS2REG, EL & 7)); + INT32 datainput = (rec < 0) ? (-rec) : rec; + if (datainput) + { + for (i = 0; i < 32; i++) + { + if (datainput & (1 << ((~i) & 0x1f))) + { + shifter = i; + break; + } + } + } + else + { + shifter = 0x10; + } + + INT32 address = ((datainput << shifter) & 0x7fc00000) >> 22; + INT32 fetchval = rsp_divtable[address]; + INT32 temp = (0x40000000 | (fetchval << 14)) >> ((~shifter) & 0x1f); + if (rec < 0) + { + temp = ~temp; + } + if (!rec) + { + temp = 0x7fffffff; + } + else if (rec == 0xffff8000) + { + temp = 0xffff0000; + } + rec = temp; + + m_reciprocal_res = rec; + m_dp_allowed = 0; + + VREG_S(VDREG, VS1REG & 7) = (UINT16)(rec & 0xffff); + + for (i = 0; i < 8; i++) + { + SET_ACCUM_L(VREG_S(VS2REG, VEC_EL_2(EL, i)), i); + } + + +#endif + // + break; + } + + case 0x31: /* VRCPL */ + { + // 31 25 24 20 15 10 5 0 + // ------------------------------------------------------ + // | 010010 | 1 | EEEE | SSSSS | ?FFFF | DDDDD | 110001 | + // ------------------------------------------------------ + // + // Calculates reciprocal low part + + //printf("RCPL "); +#if USE_SIMD + write_acc_lo(m_acc.s, vec_load_and_shuffle_operand(m_v[VS2REG].s, EL)); + + INT32 dp = op & m_dp_flag; + m_dp_flag = 0; + + m_v[VDREG].v = vec_vrcp_vrsq(op, dp, VS2REG, EL, VDREG, VS1REG); +#else + INT32 shifter = 0; + + INT32 rec = (INT16)VREG_S(VS2REG, EL & 7); + INT32 datainput = rec; + + if (m_dp_allowed) + { + rec = (rec & 0x0000ffff) | m_reciprocal_high; + datainput = rec; + + if (rec < 0) + { + if (rec < -32768) + { + datainput = ~datainput; + } + else + { + datainput = -datainput; + } + } + } + else if (datainput < 0) + { + datainput = -datainput; + + shifter = 0x10; + } + + + for (i = 0; i < 32; i++) + { + if (datainput & (1 << ((~i) & 0x1f))) + { + shifter = i; + break; + } + } + + INT32 address = ((datainput << shifter) & 0x7fc00000) >> 22; + INT32 fetchval = rsp_divtable[address]; + INT32 temp = (0x40000000 | (fetchval << 14)) >> ((~shifter) & 0x1f); + temp ^= rec >> 31; + + if (!rec) + { + temp = 0x7fffffff; + } + else if (rec == 0xffff8000) + { + temp = 0xffff0000; + } + rec = temp; + + m_reciprocal_res = rec; + m_dp_allowed = 0; + + VREG_S(VDREG, VS1REG & 7) = (UINT16)(rec & 0xffff); + + for (i = 0; i < 8; i++) + { + SET_ACCUM_L(VREG_S(VS2REG, VEC_EL_2(EL, i)), i); + } + +#endif + // + break; + } + + case 0x32: /* VRCPH */ + { + // 31 25 24 20 15 10 5 0 + // ------------------------------------------------------ + // | 010010 | 1 | EEEE | SSSSS | ?FFFF | DDDDD | 110010 | + // ------------------------------------------------------ + // + // Calculates reciprocal high part + + //printf("RCPH "); +#if USE_SIMD + write_acc_lo(m_acc.s, vec_load_and_shuffle_operand(m_v[VS2REG].s, EL)); + + m_dp_flag = 1; + + m_v[VDREG].v = vec_vdivh(VS2REG, EL, VDREG, VS1REG); +#else + m_reciprocal_high = (VREG_S(VS2REG, EL & 7)) << 16; + m_dp_allowed = 1; + + for (i = 0; i < 8; i++) + { + SET_ACCUM_L(VREG_S(VS2REG, VEC_EL_2(EL, i)), i); + } + + VREG_S(VDREG, VS1REG & 7) = (INT16)(m_reciprocal_res >> 16); + +#endif + // + break; + } + + case 0x33: /* VMOV */ + { + // 31 25 24 20 15 10 5 0 + // ------------------------------------------------------ + // | 010010 | 1 | EEEE | SSSSS | ?FFFF | DDDDD | 110011 | + // ------------------------------------------------------ + // + // Moves element from vector to destination vector + + //printf("MOV "); +#if USE_SIMD + write_acc_lo(m_acc.s, vec_load_and_shuffle_operand(m_v[VS2REG].s, EL)); + m_v[VDREG].v = vec_vmov(VS2REG, EL, VDREG, VS1REG); +#else + VREG_S(VDREG, VS1REG & 7) = VREG_S(VS2REG, EL & 7); + for (i = 0; i < 8; i++) + { + SET_ACCUM_L(VREG_S(VS2REG, VEC_EL_2(EL, i)), i); + } +#endif + // + break; + } + + case 0x34: /* VRSQ */ + { + // 31 25 24 20 15 10 5 0 + // ------------------------------------------------------ + // | 010010 | 1 | EEEE | SSSSS | ?FFFF | DDDDD | 110100 | + // ------------------------------------------------------ + // + // Calculates reciprocal square-root + + //printf("RSQ "); +#if USE_SIMD + write_acc_lo(m_acc.s, vec_load_and_shuffle_operand(m_v[VS2REG].s, EL)); + + INT32 dp = op & m_dp_flag; + m_dp_flag = 0; + + m_v[VDREG].v = vec_vrcp_vrsq(op, dp, VS2REG, EL, VDREG, VS1REG); +#else + INT32 shifter = 0; + + INT32 rec = (INT16)(VREG_S(VS2REG, EL & 7)); + INT32 datainput = (rec < 0) ? (-rec) : rec; + if (datainput) + { + for (i = 0; i < 32; i++) + { + if (datainput & (1 << ((~i) & 0x1f)))//?.?.??? 31 - i + { + shifter = i; + break; + } + } + } + else + { + shifter = 0x10; + } + + INT32 address = ((datainput << shifter) & 0x7fc00000) >> 22; + address = ((address | 0x200) & 0x3fe) | (shifter & 1); + + INT32 fetchval = rsp_divtable[address]; + INT32 temp = (0x40000000 | (fetchval << 14)) >> (((~shifter) & 0x1f) >> 1); + if (rec < 0) + { + temp = ~temp; + } + if (!rec) + { + temp = 0x7fffffff; + } + else if (rec == 0xffff8000) + { + temp = 0xffff0000; + } + rec = temp; + + m_reciprocal_res = rec; + m_dp_allowed = 0; + + VREG_S(VDREG, VS1REG & 7) = (UINT16)(rec & 0xffff); + + for (i = 0; i < 8; i++) + { + SET_ACCUM_L(VREG_S(VS2REG, VEC_EL_2(EL, i)), i); + } + +#endif + // + break; + } + + case 0x35: /* VRSQL */ + { + // 31 25 24 20 15 10 5 0 + // ------------------------------------------------------ + // | 010010 | 1 | EEEE | SSSSS | ?FFFF | DDDDD | 110101 | + // ------------------------------------------------------ + // + // Calculates reciprocal square-root low part + + //printf("RSQL "); +#if USE_SIMD + write_acc_lo(m_acc.s, vec_load_and_shuffle_operand(m_v[VS2REG].s, EL)); + + INT32 dp = op & m_dp_flag; + m_dp_flag = 0; + + m_v[VDREG].v = vec_vrcp_vrsq(op, dp, VS2REG, EL, VDREG, VS1REG); +#else + INT32 shifter = 0; + INT32 rec = (INT16)VREG_S(VS2REG, EL & 7); + INT32 datainput = rec; + + if (m_dp_allowed) + { + rec = (rec & 0x0000ffff) | m_reciprocal_high; + datainput = rec; + + if (rec < 0) + { + if (rec < -32768) + { + datainput = ~datainput; + } + else + { + datainput = -datainput; + } + } + } + else if (datainput < 0) + { + datainput = -datainput; + + shifter = 0x10; + } + + if (datainput) + { + for (i = 0; i < 32; i++) + { + if (datainput & (1 << ((~i) & 0x1f))) + { + shifter = i; + break; + } + } + } + + INT32 address = ((datainput << shifter) & 0x7fc00000) >> 22; + address = ((address | 0x200) & 0x3fe) | (shifter & 1); + + INT32 fetchval = rsp_divtable[address]; + INT32 temp = (0x40000000 | (fetchval << 14)) >> (((~shifter) & 0x1f) >> 1); + temp ^= rec >> 31; + + if (!rec) + { + temp = 0x7fffffff; + } + else if (rec == 0xffff8000) + { + temp = 0xffff0000; + } + rec = temp; + + m_reciprocal_res = rec; + m_dp_allowed = 0; + + VREG_S(VDREG, VS1REG & 7) = (UINT16)(rec & 0xffff); + + for (i = 0; i < 8; i++) + { + SET_ACCUM_L(VREG_S(VS2REG, VEC_EL_2(EL, i)), i); + } + +#endif + // + break; + } + + case 0x36: /* VRSQH */ + { + // 31 25 24 20 15 10 5 0 + // ------------------------------------------------------ + // | 010010 | 1 | EEEE | SSSSS | ?FFFF | DDDDD | 110110 | + // ------------------------------------------------------ + // + // Calculates reciprocal square-root high part + + //printf("RSQH "); +#if USE_SIMD + write_acc_lo(m_acc.s, vec_load_and_shuffle_operand(m_v[VS2REG].s, EL)); + + m_dp_flag = 1; + + m_v[VDREG].v = vec_vdivh(VS2REG, EL, VDREG, VS1REG); +#else + m_reciprocal_high = (VREG_S(VS2REG, EL & 7)) << 16; + m_dp_allowed = 1; + + for (i=0; i < 8; i++) + { + SET_ACCUM_L(VREG_S(VS2REG, VEC_EL_2(EL, i)), i); + } + + VREG_S(VDREG, VS1REG & 7) = (INT16)(m_reciprocal_res >> 16); // store high part +#endif + // + break; + } + + case 0x37: /* VNOP */ + { + // 31 25 24 20 15 10 5 0 + // ------------------------------------------------------ + // | 010010 | 1 | EEEE | SSSSS | ?FFFF | DDDDD | 110111 | + // ------------------------------------------------------ + // + // Vector null instruction + + //printf("NOP "); + break; + } + + default: m_rsp.unimplemented_opcode(op); break; + } +} + +/*************************************************************************** + Vector Flag Reading/Writing +***************************************************************************/ + +void rsp_cop2::handle_cop2(UINT32 op) +{ + switch ((op >> 21) & 0x1f) + { + case 0x00: /* MFC2 */ + { + // 31 25 20 15 10 6 0 + // --------------------------------------------------- + // | 010010 | 00000 | TTTTT | DDDDD | IIII | 0000000 | + // --------------------------------------------------- + // + //printf("MFC2 "); + int el = (op >> 7) & 0xf; + UINT16 b1 = VREG_B(RDREG, (el+0) & 0xf); + UINT16 b2 = VREG_B(RDREG, (el+1) & 0xf); + if (RTREG) RTVAL = (INT32)(INT16)((b1 << 8) | (b2)); + break; + } + + case 0x02: /* CFC2 */ + { + // 31 25 20 15 10 0 + // ------------------------------------------------ + // | 010010 | 00010 | TTTTT | DDDDD | 00000000000 | + // ------------------------------------------------ + // + //printf("CFC2 "); + if (RTREG) + { +#if USE_SIMD + INT32 src = RDREG & 3; + if (src == 3) { + src = 2; + } + RTVAL = get_flags(m_flags[src].s); +#else + switch(RDREG) + { + case 0: + RTVAL = ((CARRY_FLAG(0) & 1) << 0) | + ((CARRY_FLAG(1) & 1) << 1) | + ((CARRY_FLAG(2) & 1) << 2) | + ((CARRY_FLAG(3) & 1) << 3) | + ((CARRY_FLAG(4) & 1) << 4) | + ((CARRY_FLAG(5) & 1) << 5) | + ((CARRY_FLAG(6) & 1) << 6) | + ((CARRY_FLAG(7) & 1) << 7) | + ((ZERO_FLAG(0) & 1) << 8) | + ((ZERO_FLAG(1) & 1) << 9) | + ((ZERO_FLAG(2) & 1) << 10) | + ((ZERO_FLAG(3) & 1) << 11) | + ((ZERO_FLAG(4) & 1) << 12) | + ((ZERO_FLAG(5) & 1) << 13) | + ((ZERO_FLAG(6) & 1) << 14) | + ((ZERO_FLAG(7) & 1) << 15); + if (RTVAL & 0x8000) RTVAL |= 0xffff0000; + break; + case 1: + RTVAL = ((COMPARE_FLAG(0) & 1) << 0) | + ((COMPARE_FLAG(1) & 1) << 1) | + ((COMPARE_FLAG(2) & 1) << 2) | + ((COMPARE_FLAG(3) & 1) << 3) | + ((COMPARE_FLAG(4) & 1) << 4) | + ((COMPARE_FLAG(5) & 1) << 5) | + ((COMPARE_FLAG(6) & 1) << 6) | + ((COMPARE_FLAG(7) & 1) << 7) | + ((CLIP2_FLAG(0) & 1) << 8) | + ((CLIP2_FLAG(1) & 1) << 9) | + ((CLIP2_FLAG(2) & 1) << 10) | + ((CLIP2_FLAG(3) & 1) << 11) | + ((CLIP2_FLAG(4) & 1) << 12) | + ((CLIP2_FLAG(5) & 1) << 13) | + ((CLIP2_FLAG(6) & 1) << 14) | + ((CLIP2_FLAG(7) & 1) << 15); + if (RTVAL & 0x8000) RTVAL |= 0xffff0000; + break; + case 2: + // Anciliary clipping flags + RTVAL = ((CLIP1_FLAG(0) & 1) << 0) | + ((CLIP1_FLAG(1) & 1) << 1) | + ((CLIP1_FLAG(2) & 1) << 2) | + ((CLIP1_FLAG(3) & 1) << 3) | + ((CLIP1_FLAG(4) & 1) << 4) | + ((CLIP1_FLAG(5) & 1) << 5) | + ((CLIP1_FLAG(6) & 1) << 6) | + ((CLIP1_FLAG(7) & 1) << 7); + } +#endif + } + break; + } + + case 0x04: /* MTC2 */ + { + // 31 25 20 15 10 6 0 + // --------------------------------------------------- + // | 010010 | 00100 | TTTTT | DDDDD | IIII | 0000000 | + // --------------------------------------------------- + // + //printf("MTC2 "); + int el = (op >> 7) & 0xf; + W_VREG_B(RDREG, (el+0) & 0xf, (RTVAL >> 8) & 0xff); + W_VREG_B(RDREG, (el+1) & 0xf, (RTVAL >> 0) & 0xff); + break; + } + + case 0x06: /* CTC2 */ + { + // 31 25 20 15 10 0 + // ------------------------------------------------ + // | 010010 | 00110 | TTTTT | DDDDD | 00000000000 | + // ------------------------------------------------ + // + switch(RDREG) + { +#if USE_SIMD + case 0: + case 1: + case 2: + UINT16 r0 = (RTVAL & (1 << 0)) ? 0xffff : 0; + UINT16 r1 = (RTVAL & (1 << 1)) ? 0xffff : 0; + UINT16 r2 = (RTVAL & (1 << 2)) ? 0xffff : 0; + UINT16 r3 = (RTVAL & (1 << 3)) ? 0xffff : 0; + UINT16 r4 = (RTVAL & (1 << 4)) ? 0xffff : 0; + UINT16 r5 = (RTVAL & (1 << 5)) ? 0xffff : 0; + UINT16 r6 = (RTVAL & (1 << 6)) ? 0xffff : 0; + UINT16 r7 = (RTVAL & (1 << 7)) ? 0xffff : 0; + m_flags[RDREG].__align[0] = _mm_set_epi16(r7, r6, r5, r4, r3, r2, r1, r0); + r0 = (RTVAL & (1 << 8)) ? 0xffff : 0; + r1 = (RTVAL & (1 << 9)) ? 0xffff : 0; + r2 = (RTVAL & (1 << 10)) ? 0xffff : 0; + r3 = (RTVAL & (1 << 11)) ? 0xffff : 0; + r4 = (RTVAL & (1 << 12)) ? 0xffff : 0; + r5 = (RTVAL & (1 << 13)) ? 0xffff : 0; + r6 = (RTVAL & (1 << 14)) ? 0xffff : 0; + r7 = (RTVAL & (1 << 15)) ? 0xffff : 0; + m_flags[RDREG].__align[1] = _mm_set_epi16(r7, r6, r5, r4, r3, r2, r1, r0); + break; +#else + case 0: + CLEAR_CARRY_FLAGS(); + CLEAR_ZERO_FLAGS(); + if (RTVAL & (1 << 0)) { SET_CARRY_FLAG(0); } + if (RTVAL & (1 << 1)) { SET_CARRY_FLAG(1); } + if (RTVAL & (1 << 2)) { SET_CARRY_FLAG(2); } + if (RTVAL & (1 << 3)) { SET_CARRY_FLAG(3); } + if (RTVAL & (1 << 4)) { SET_CARRY_FLAG(4); } + if (RTVAL & (1 << 5)) { SET_CARRY_FLAG(5); } + if (RTVAL & (1 << 6)) { SET_CARRY_FLAG(6); } + if (RTVAL & (1 << 7)) { SET_CARRY_FLAG(7); } + if (RTVAL & (1 << 8)) { SET_ZERO_FLAG(0); } + if (RTVAL & (1 << 9)) { SET_ZERO_FLAG(1); } + if (RTVAL & (1 << 10)) { SET_ZERO_FLAG(2); } + if (RTVAL & (1 << 11)) { SET_ZERO_FLAG(3); } + if (RTVAL & (1 << 12)) { SET_ZERO_FLAG(4); } + if (RTVAL & (1 << 13)) { SET_ZERO_FLAG(5); } + if (RTVAL & (1 << 14)) { SET_ZERO_FLAG(6); } + if (RTVAL & (1 << 15)) { SET_ZERO_FLAG(7); } + break; + + case 1: + CLEAR_COMPARE_FLAGS(); + CLEAR_CLIP2_FLAGS(); + if (RTVAL & (1 << 0)) { SET_COMPARE_FLAG(0); } + if (RTVAL & (1 << 1)) { SET_COMPARE_FLAG(1); } + if (RTVAL & (1 << 2)) { SET_COMPARE_FLAG(2); } + if (RTVAL & (1 << 3)) { SET_COMPARE_FLAG(3); } + if (RTVAL & (1 << 4)) { SET_COMPARE_FLAG(4); } + if (RTVAL & (1 << 5)) { SET_COMPARE_FLAG(5); } + if (RTVAL & (1 << 6)) { SET_COMPARE_FLAG(6); } + if (RTVAL & (1 << 7)) { SET_COMPARE_FLAG(7); } + if (RTVAL & (1 << 8)) { SET_CLIP2_FLAG(0); } + if (RTVAL & (1 << 9)) { SET_CLIP2_FLAG(1); } + if (RTVAL & (1 << 10)) { SET_CLIP2_FLAG(2); } + if (RTVAL & (1 << 11)) { SET_CLIP2_FLAG(3); } + if (RTVAL & (1 << 12)) { SET_CLIP2_FLAG(4); } + if (RTVAL & (1 << 13)) { SET_CLIP2_FLAG(5); } + if (RTVAL & (1 << 14)) { SET_CLIP2_FLAG(6); } + if (RTVAL & (1 << 15)) { SET_CLIP2_FLAG(7); } + break; + + case 2: + CLEAR_CLIP1_FLAGS(); + if (RTVAL & (1 << 0)) { SET_CLIP1_FLAG(0); } + if (RTVAL & (1 << 1)) { SET_CLIP1_FLAG(1); } + if (RTVAL & (1 << 2)) { SET_CLIP1_FLAG(2); } + if (RTVAL & (1 << 3)) { SET_CLIP1_FLAG(3); } + if (RTVAL & (1 << 4)) { SET_CLIP1_FLAG(4); } + if (RTVAL & (1 << 5)) { SET_CLIP1_FLAG(5); } + if (RTVAL & (1 << 6)) { SET_CLIP1_FLAG(6); } + if (RTVAL & (1 << 7)) { SET_CLIP1_FLAG(7); } + break; +#endif + } + break; + } + + case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17: + case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f: + { + //printf("V"); + handle_vector_ops(op); + break; + } + + default: + m_rsp.unimplemented_opcode(op); + break; + } + //dump(op); +} + +inline void rsp_cop2::mfc2() +{ + UINT32 op = m_rspcop2_state->op; + int el = (op >> 7) & 0xf; + + UINT16 b1 = VREG_B(VS1REG, (el+0) & 0xf); + UINT16 b2 = VREG_B(VS1REG, (el+1) & 0xf); + if (RTREG) RTVAL = (INT32)(INT16)((b1 << 8) | (b2)); +} + +inline void rsp_cop2::cfc2() +{ + UINT32 op = m_rspcop2_state->op; + if (RTREG) + { + switch(RDREG) + { + case 0: + RTVAL = ((CARRY_FLAG(0) & 1) << 0) | + ((CARRY_FLAG(1) & 1) << 1) | + ((CARRY_FLAG(2) & 1) << 2) | + ((CARRY_FLAG(3) & 1) << 3) | + ((CARRY_FLAG(4) & 1) << 4) | + ((CARRY_FLAG(5) & 1) << 5) | + ((CARRY_FLAG(6) & 1) << 6) | + ((CARRY_FLAG(7) & 1) << 7) | + ((ZERO_FLAG(0) & 1) << 8) | + ((ZERO_FLAG(1) & 1) << 9) | + ((ZERO_FLAG(2) & 1) << 10) | + ((ZERO_FLAG(3) & 1) << 11) | + ((ZERO_FLAG(4) & 1) << 12) | + ((ZERO_FLAG(5) & 1) << 13) | + ((ZERO_FLAG(6) & 1) << 14) | + ((ZERO_FLAG(7) & 1) << 15); + if (RTVAL & 0x8000) RTVAL |= 0xffff0000; + break; + case 1: + RTVAL = ((COMPARE_FLAG(0) & 1) << 0) | + ((COMPARE_FLAG(1) & 1) << 1) | + ((COMPARE_FLAG(2) & 1) << 2) | + ((COMPARE_FLAG(3) & 1) << 3) | + ((COMPARE_FLAG(4) & 1) << 4) | + ((COMPARE_FLAG(5) & 1) << 5) | + ((COMPARE_FLAG(6) & 1) << 6) | + ((COMPARE_FLAG(7) & 1) << 7) | + ((CLIP2_FLAG(0) & 1) << 8) | + ((CLIP2_FLAG(1) & 1) << 9) | + ((CLIP2_FLAG(2) & 1) << 10) | + ((CLIP2_FLAG(3) & 1) << 11) | + ((CLIP2_FLAG(4) & 1) << 12) | + ((CLIP2_FLAG(5) & 1) << 13) | + ((CLIP2_FLAG(6) & 1) << 14) | + ((CLIP2_FLAG(7) & 1) << 15); + if (RTVAL & 0x8000) RTVAL |= 0xffff0000; + break; + case 2: + RTVAL = ((CLIP1_FLAG(0) & 1) << 0) | + ((CLIP1_FLAG(1) & 1) << 1) | + ((CLIP1_FLAG(2) & 1) << 2) | + ((CLIP1_FLAG(3) & 1) << 3) | + ((CLIP1_FLAG(4) & 1) << 4) | + ((CLIP1_FLAG(5) & 1) << 5) | + ((CLIP1_FLAG(6) & 1) << 6) | + ((CLIP1_FLAG(7) & 1) << 7); + break; + } + } +} + +inline void rsp_cop2::mtc2() +{ + UINT32 op = m_rspcop2_state->op; + int el = (op >> 7) & 0xf; + VREG_B(VS1REG, (el+0) & 0xf) = (RTVAL >> 8) & 0xff; + VREG_B(VS1REG, (el+1) & 0xf) = (RTVAL >> 0) & 0xff; +} + +inline void rsp_cop2::ctc2() +{ + UINT32 op = m_rspcop2_state->op; + switch(RDREG) + { + case 0: + CLEAR_CARRY_FLAGS(); + CLEAR_ZERO_FLAGS(); + m_vflag[0][0] = ((RTVAL >> 0) & 1) ? 0xffff : 0; + m_vflag[0][1] = ((RTVAL >> 1) & 1) ? 0xffff : 0; + m_vflag[0][2] = ((RTVAL >> 2) & 1) ? 0xffff : 0; + m_vflag[0][3] = ((RTVAL >> 3) & 1) ? 0xffff : 0; + m_vflag[0][4] = ((RTVAL >> 4) & 1) ? 0xffff : 0; + m_vflag[0][5] = ((RTVAL >> 5) & 1) ? 0xffff : 0; + m_vflag[0][6] = ((RTVAL >> 6) & 1) ? 0xffff : 0; + m_vflag[0][7] = ((RTVAL >> 7) & 1) ? 0xffff : 0; + if (RTVAL & (1 << 0)) { SET_CARRY_FLAG(0); } + if (RTVAL & (1 << 1)) { SET_CARRY_FLAG(1); } + if (RTVAL & (1 << 2)) { SET_CARRY_FLAG(2); } + if (RTVAL & (1 << 3)) { SET_CARRY_FLAG(3); } + if (RTVAL & (1 << 4)) { SET_CARRY_FLAG(4); } + if (RTVAL & (1 << 5)) { SET_CARRY_FLAG(5); } + if (RTVAL & (1 << 6)) { SET_CARRY_FLAG(6); } + if (RTVAL & (1 << 7)) { SET_CARRY_FLAG(7); } + m_vflag[3][0] = ((RTVAL >> 8) & 1) ? 0xffff : 0; + m_vflag[3][1] = ((RTVAL >> 9) & 1) ? 0xffff : 0; + m_vflag[3][2] = ((RTVAL >> 10) & 1) ? 0xffff : 0; + m_vflag[3][3] = ((RTVAL >> 11) & 1) ? 0xffff : 0; + m_vflag[3][4] = ((RTVAL >> 12) & 1) ? 0xffff : 0; + m_vflag[3][5] = ((RTVAL >> 13) & 1) ? 0xffff : 0; + m_vflag[3][6] = ((RTVAL >> 14) & 1) ? 0xffff : 0; + m_vflag[3][7] = ((RTVAL >> 15) & 1) ? 0xffff : 0; + if (RTVAL & (1 << 8)) { SET_ZERO_FLAG(0); } + if (RTVAL & (1 << 9)) { SET_ZERO_FLAG(1); } + if (RTVAL & (1 << 10)) { SET_ZERO_FLAG(2); } + if (RTVAL & (1 << 11)) { SET_ZERO_FLAG(3); } + if (RTVAL & (1 << 12)) { SET_ZERO_FLAG(4); } + if (RTVAL & (1 << 13)) { SET_ZERO_FLAG(5); } + if (RTVAL & (1 << 14)) { SET_ZERO_FLAG(6); } + if (RTVAL & (1 << 15)) { SET_ZERO_FLAG(7); } + break; + case 1: + CLEAR_COMPARE_FLAGS(); + CLEAR_CLIP2_FLAGS(); + m_vflag[1][0] = ((RTVAL >> 0) & 1) ? 0xffff : 0; + m_vflag[1][1] = ((RTVAL >> 1) & 1) ? 0xffff : 0; + m_vflag[1][2] = ((RTVAL >> 2) & 1) ? 0xffff : 0; + m_vflag[1][3] = ((RTVAL >> 3) & 1) ? 0xffff : 0; + m_vflag[1][4] = ((RTVAL >> 4) & 1) ? 0xffff : 0; + m_vflag[1][5] = ((RTVAL >> 5) & 1) ? 0xffff : 0; + m_vflag[1][6] = ((RTVAL >> 6) & 1) ? 0xffff : 0; + m_vflag[1][7] = ((RTVAL >> 7) & 1) ? 0xffff : 0; + if (RTVAL & (1 << 0)) { SET_COMPARE_FLAG(0); } + if (RTVAL & (1 << 1)) { SET_COMPARE_FLAG(1); } + if (RTVAL & (1 << 2)) { SET_COMPARE_FLAG(2); } + if (RTVAL & (1 << 3)) { SET_COMPARE_FLAG(3); } + if (RTVAL & (1 << 4)) { SET_COMPARE_FLAG(4); } + if (RTVAL & (1 << 5)) { SET_COMPARE_FLAG(5); } + if (RTVAL & (1 << 6)) { SET_COMPARE_FLAG(6); } + if (RTVAL & (1 << 7)) { SET_COMPARE_FLAG(7); } + m_vflag[4][0] = ((RTVAL >> 8) & 1) ? 0xffff : 0; + m_vflag[4][1] = ((RTVAL >> 9) & 1) ? 0xffff : 0; + m_vflag[4][2] = ((RTVAL >> 10) & 1) ? 0xffff : 0; + m_vflag[4][3] = ((RTVAL >> 11) & 1) ? 0xffff : 0; + m_vflag[4][4] = ((RTVAL >> 12) & 1) ? 0xffff : 0; + m_vflag[4][5] = ((RTVAL >> 13) & 1) ? 0xffff : 0; + m_vflag[4][6] = ((RTVAL >> 14) & 1) ? 0xffff : 0; + m_vflag[4][7] = ((RTVAL >> 15) & 1) ? 0xffff : 0; + if (RTVAL & (1 << 8)) { SET_CLIP2_FLAG(0); } + if (RTVAL & (1 << 9)) { SET_CLIP2_FLAG(1); } + if (RTVAL & (1 << 10)) { SET_CLIP2_FLAG(2); } + if (RTVAL & (1 << 11)) { SET_CLIP2_FLAG(3); } + if (RTVAL & (1 << 12)) { SET_CLIP2_FLAG(4); } + if (RTVAL & (1 << 13)) { SET_CLIP2_FLAG(5); } + if (RTVAL & (1 << 14)) { SET_CLIP2_FLAG(6); } + if (RTVAL & (1 << 15)) { SET_CLIP2_FLAG(7); } + break; + case 2: + CLEAR_CLIP1_FLAGS(); + m_vflag[2][0] = ((RTVAL >> 0) & 1) ? 0xffff : 0; + m_vflag[2][1] = ((RTVAL >> 1) & 1) ? 0xffff : 0; + m_vflag[2][2] = ((RTVAL >> 2) & 1) ? 0xffff : 0; + m_vflag[2][3] = ((RTVAL >> 3) & 1) ? 0xffff : 0; + m_vflag[2][4] = ((RTVAL >> 4) & 1) ? 0xffff : 0; + m_vflag[2][5] = ((RTVAL >> 5) & 1) ? 0xffff : 0; + m_vflag[2][6] = ((RTVAL >> 6) & 1) ? 0xffff : 0; + m_vflag[2][7] = ((RTVAL >> 7) & 1) ? 0xffff : 0; + if (RTVAL & (1 << 0)) { SET_CLIP1_FLAG(0); } + if (RTVAL & (1 << 1)) { SET_CLIP1_FLAG(1); } + if (RTVAL & (1 << 2)) { SET_CLIP1_FLAG(2); } + if (RTVAL & (1 << 3)) { SET_CLIP1_FLAG(3); } + if (RTVAL & (1 << 4)) { SET_CLIP1_FLAG(4); } + if (RTVAL & (1 << 5)) { SET_CLIP1_FLAG(5); } + if (RTVAL & (1 << 6)) { SET_CLIP1_FLAG(6); } + if (RTVAL & (1 << 7)) { SET_CLIP1_FLAG(7); } + break; + } +} + +void rsp_cop2::log_instruction_execution() +{ + static VECTOR_REG prev_vecs[32]; + + for (int i = 0; i < 32; i++) + { + if (m_v[i].d[0] != prev_vecs[i].d[0] || m_v[i].d[1] != prev_vecs[i].d[1]) + { + fprintf(m_rsp.m_exec_output, "V%d: %04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X ", i, + (UINT16)VREG_S(i,0), (UINT16)VREG_S(i,1), (UINT16)VREG_S(i,2), (UINT16)VREG_S(i,3), (UINT16)VREG_S(i,4), (UINT16)VREG_S(i,5), (UINT16)VREG_S(i,6), (UINT16)VREG_S(i,7)); + } + prev_vecs[i].d[0] = m_v[i].d[0]; + prev_vecs[i].d[1] = m_v[i].d[1]; + } +} + +void rsp_cop2::dump(UINT32 op) +{ + printf("%08x ", op); + for (int i = 0; i < 32; i++) + { + printf("%08x ", m_rsp.m_rsp_state->r[i]); + } + printf("\n"); + + for (int i = 0; i < 32; i++) + { + printf("%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", VREG_B(i, 0), VREG_B(i, 1), VREG_B(i, 2), VREG_B(i, 3), VREG_B(i, 4), VREG_B(i, 5), VREG_B(i, 6), VREG_B(i, 7), VREG_B(i, 8), VREG_B(i, 9), VREG_B(i, 10), VREG_B(i, 11), VREG_B(i, 12), VREG_B(i, 13), VREG_B(i, 14), VREG_B(i, 15)); + } + +#if USE_SIMD + printf("acc_h: %04x|%04x|%04x|%04x|%04x|%04x|%04x|%04x\n", m_acc.s[0], m_acc.s[1], m_acc.s[2], m_acc.s[3], m_acc.s[4], m_acc.s[5], m_acc.s[6], m_acc.s[7]); + printf("acc_m: %04x|%04x|%04x|%04x|%04x|%04x|%04x|%04x\n", m_acc.s[8], m_acc.s[9], m_acc.s[10], m_acc.s[11], m_acc.s[12], m_acc.s[13], m_acc.s[14], m_acc.s[15]); + printf("acc_l: %04x|%04x|%04x|%04x|%04x|%04x|%04x|%04x\n", m_acc.s[16], m_acc.s[17], m_acc.s[18], m_acc.s[19], m_acc.s[20], m_acc.s[21], m_acc.s[22], m_acc.s[23]); + printf("vcc_hi: %04x|%04x|%04x|%04x|%04x|%04x|%04x|%04x\n", m_flags[RSP_VCC].s[0], m_flags[RSP_VCC].s[1], m_flags[RSP_VCC].s[2], m_flags[RSP_VCC].s[3], m_flags[RSP_VCC].s[4], m_flags[RSP_VCC].s[5], m_flags[RSP_VCC].s[6], m_flags[RSP_VCC].s[7]); + printf("vcc_lo: %04x|%04x|%04x|%04x|%04x|%04x|%04x|%04x\n", m_flags[RSP_VCC].s[8], m_flags[RSP_VCC].s[9], m_flags[RSP_VCC].s[10], m_flags[RSP_VCC].s[11], m_flags[RSP_VCC].s[12], m_flags[RSP_VCC].s[13], m_flags[RSP_VCC].s[14], m_flags[RSP_VCC].s[15]); + printf("vco_hi: %04x|%04x|%04x|%04x|%04x|%04x|%04x|%04x\n", m_flags[RSP_VCO].s[0], m_flags[RSP_VCO].s[1], m_flags[RSP_VCO].s[2], m_flags[RSP_VCO].s[3], m_flags[RSP_VCO].s[4], m_flags[RSP_VCO].s[5], m_flags[RSP_VCO].s[6], m_flags[RSP_VCO].s[7]); + printf("vco_lo: %04x|%04x|%04x|%04x|%04x|%04x|%04x|%04x\n", m_flags[RSP_VCO].s[8], m_flags[RSP_VCO].s[9], m_flags[RSP_VCO].s[10], m_flags[RSP_VCO].s[11], m_flags[RSP_VCO].s[12], m_flags[RSP_VCO].s[13], m_flags[RSP_VCO].s[14], m_flags[RSP_VCO].s[15]); + printf("vce: %04x|%04x|%04x|%04x|%04x|%04x|%04x|%04x\n", m_flags[RSP_VCE].s[0], m_flags[RSP_VCE].s[1], m_flags[RSP_VCE].s[2], m_flags[RSP_VCE].s[3], m_flags[RSP_VCE].s[4], m_flags[RSP_VCE].s[5], m_flags[RSP_VCE].s[6], m_flags[RSP_VCE].s[7]); +#else + printf("acc_h: %04x|%04x|%04x|%04x|%04x|%04x|%04x|%04x\n", ACCUM_H(0), ACCUM_H(1), ACCUM_H(2), ACCUM_H(3), ACCUM_H(4), ACCUM_H(5), ACCUM_H(6), ACCUM_H(7)); + printf("acc_m: %04x|%04x|%04x|%04x|%04x|%04x|%04x|%04x\n", ACCUM_M(0), ACCUM_M(1), ACCUM_M(2), ACCUM_M(3), ACCUM_M(4), ACCUM_M(5), ACCUM_M(6), ACCUM_M(7)); + printf("acc_l: %04x|%04x|%04x|%04x|%04x|%04x|%04x|%04x\n", ACCUM_L(0), ACCUM_L(1), ACCUM_L(2), ACCUM_L(3), ACCUM_L(4), ACCUM_L(5), ACCUM_L(6), ACCUM_L(7)); + printf("vcc_hi: %04x|%04x|%04x|%04x|%04x|%04x|%04x|%04x\n", m_vflag[4][0], m_vflag[4][1], m_vflag[4][2], m_vflag[4][3], m_vflag[4][4], m_vflag[4][5], m_vflag[4][6], m_vflag[4][7]); + printf("vcc_lo: %04x|%04x|%04x|%04x|%04x|%04x|%04x|%04x\n", m_vflag[1][0], m_vflag[1][1], m_vflag[1][2], m_vflag[1][3], m_vflag[1][4], m_vflag[1][5], m_vflag[1][6], m_vflag[1][7]); + printf("vco_hi: %04x|%04x|%04x|%04x|%04x|%04x|%04x|%04x\n", m_vflag[3][0], m_vflag[3][1], m_vflag[3][2], m_vflag[3][3], m_vflag[3][4], m_vflag[3][5], m_vflag[3][6], m_vflag[3][7]); + printf("vco_lo: %04x|%04x|%04x|%04x|%04x|%04x|%04x|%04x\n", m_vflag[0][0], m_vflag[0][1], m_vflag[0][2], m_vflag[0][3], m_vflag[0][4], m_vflag[0][5], m_vflag[0][6], m_vflag[0][7]); + printf("vce: %04x|%04x|%04x|%04x|%04x|%04x|%04x|%04x\n", m_vflag[2][0], m_vflag[2][1], m_vflag[2][2], m_vflag[2][3], m_vflag[2][4], m_vflag[2][5], m_vflag[2][6], m_vflag[2][7]); +#endif +} + +void rsp_cop2::dump_dmem() +{ + UINT8* dmem = m_rsp.get_dmem(); + printf("\n"); + for (int i = 0; i < 0x1000; i += 32) + { + printf("%04x: ", i); + for (int j = 0; j < 32; j++) + { + printf("%02x ", dmem[i + j]); + } + printf("\n"); + } + printf("\n"); +} diff --git a/src/devices/cpu/rsp/rspcp2.h b/src/devices/cpu/rsp/rspcp2.h new file mode 100644 index 00000000000..909b0ae4172 --- /dev/null +++ b/src/devices/cpu/rsp/rspcp2.h @@ -0,0 +1,396 @@ +// license:BSD-3-Clause +// copyright-holders:Ryan Holtz,Tyler J. Stachecki +/*************************************************************************** + + rspcp2.h + + Interface file for Reality Signal Processor (RSP) vector extensions. + +***************************************************************************/ + +#pragma once + +#ifndef __RSPCP2_H__ +#define __RSPCP2_H__ + +#include "cpu/drcuml.h" +#include "rsp.h" +#include "rspdiv.h" + +#define SIMD_OFF (1) + +#if (defined(__SSE2__) || defined(__SSE3__) || defined(__SSSE3__) || defined(__SSE4_1__) || defined(__SSE4_2__)) +#define SSE_AVAILABLE (1) +#else +#define SSE_AVAILABLE (0) +#endif + +#if (SSE_AVAILABLE || defined(_MSC_VER)) && defined(PTR64) && !SIMD_OFF +#define USE_SIMD (1) +#else +#define USE_SIMD (0) +#endif + +#if USE_SIMD + +#ifdef _MSC_VER +#define __align16 __declspec(align(16)) +#else +#define __align16 __attribute__((aligned(16))) +#endif + +#if (defined(__SSE4_2__) || defined(_MSC_VER)) +#include +#elif (defined(__SSE4_1__) || defined(_MSC_VER)) +#include +#elif (defined(__SSSE3__) || defined(_MSC_VER)) +#include +#elif (defined(__SSE3__ ) || defined(_MSC_VER)) +#include +#else +#include +#endif + +typedef __m128i rsp_vec_t; +#endif + +union VECTOR_REG +{ + UINT64 d[2]; + UINT32 l[4]; + UINT16 s[8]; + UINT8 b[16]; +#if USE_SIMD + rsp_vec_t v; +#endif +}; + +union ACCUMULATOR_REG +{ + UINT64 q; + UINT32 l[2]; + UINT16 w[4]; +}; + +struct compiler_state; + +class rsp_cop2 +{ + friend class rsp_device; + +protected: + rsp_cop2(rsp_device &rsp, running_machine &machine); + + virtual void init(); + virtual void start(); + + virtual int generate_cop2(drcuml_block *block, rsp_device::compiler_state *compiler, const opcode_desc *desc) { return TRUE; } + virtual int generate_lwc2(drcuml_block *block, rsp_device::compiler_state *compiler, const opcode_desc *desc) { return TRUE; } + virtual int generate_swc2(drcuml_block *block, rsp_device::compiler_state *compiler, const opcode_desc *desc) { return TRUE; } + + virtual void state_string_export(const int index, std::string &str); + +public: + virtual ~rsp_cop2(); + + virtual void lbv() { } + virtual void lsv() { } + virtual void llv() { } + virtual void ldv() { } + virtual void lqv() { } + virtual void lrv() { } + virtual void lpv() { } + virtual void luv() { } + virtual void lhv() { } + virtual void lfv() { } + virtual void lwv() { } + virtual void ltv() { } + virtual void sbv() { } + virtual void ssv() { } + virtual void slv() { } + virtual void sdv() { } + virtual void sqv() { } + virtual void srv() { } + virtual void spv() { } + virtual void suv() { } + virtual void shv() { } + virtual void sfv() { } + virtual void swv() { } + virtual void stv() { } + virtual void vmulf() { } + virtual void vmulu() { } + virtual void vmudl() { } + virtual void vmudm() { } + virtual void vmudn() { } + virtual void vmudh() { } + virtual void vmacf() { } + virtual void vmacu() { } + virtual void vmadl() { } + virtual void vmadm() { } + virtual void vmadn() { } + virtual void vmadh() { } + virtual void vadd() { } + virtual void vsub() { } + virtual void vabs() { } + virtual void vaddc() { } + virtual void vsubc() { } + virtual void vaddb() { } + virtual void vsaw() { } + virtual void vlt() { } + virtual void veq() { } + virtual void vne() { } + virtual void vge() { } + virtual void vcl() { } + virtual void vch() { } + virtual void vcr() { } + virtual void vmrg() { } + virtual void vand() { } + virtual void vnand() { } + virtual void vor() { } + virtual void vnor() { } + virtual void vxor() { } + virtual void vnxor() { } + virtual void vrcp() { } + virtual void vrcpl() { } + virtual void vrcph() { } + virtual void vmov() { } + virtual void vrsql() { } + virtual void vrsqh() { } + virtual void vrsq() { } + virtual void mfc2(); + virtual void cfc2(); + virtual void mtc2(); + virtual void ctc2(); + + virtual void handle_cop2(UINT32 op); + + void log_instruction_execution(); + virtual void cfunc_unimplemented_opcode() { } + + void dump(UINT32 op); + void dump_dmem(); + +protected: + virtual int generate_vector_opcode(drcuml_block *block, rsp_device::compiler_state *compiler, const opcode_desc *desc) { return TRUE; } + + UINT16 SATURATE_ACCUM(int accum, int slice, UINT16 negative, UINT16 positive); + UINT16 SATURATE_ACCUM1(int accum, UINT16 negative, UINT16 positive); + + // Data that needs to be stored close to the generated DRC code + struct internal_rspcop2_state + { + UINT32 op; + }; + + internal_rspcop2_state *m_rspcop2_state; + rsp_device& m_rsp; + running_machine& m_machine; + UINT32 m_vres[8]; /* used for temporary vector results */ + +#if USE_SIMD + __align16 VECTOR_REG m_v[32]; +#else + VECTOR_REG m_v[32]; +#endif + ACCUMULATOR_REG m_accum[8]; + UINT16 m_vflag[6][8]; + + INT32 m_reciprocal_res; + UINT32 m_reciprocal_high; + INT32 m_dp_allowed; + +#if USE_SIMD + enum rsp_flags_t { + RSP_VCO = 0, + RSP_VCC = 1, + RSP_VCE = 2 + }; + + enum rsp_acc_t { + RSP_ACC_LO = 16, + RSP_ACC_MD = 8, + RSP_ACC_HI = 0, + }; + + enum rsp_mem_request_type { + RSP_MEM_REQUEST_NONE, + RSP_MEM_REQUEST_INT_MEM, + RSP_MEM_REQUEST_VECTOR, + RSP_MEM_REQUEST_FOURTH, + RSP_MEM_REQUEST_HALF, + RSP_MEM_REQUEST_PACK, + RSP_MEM_REQUEST_QUAD, + RSP_MEM_REQUEST_REST, + RSP_MEM_REQUEST_UPACK + }; + + union aligned_rsp_1vect_t { + rsp_vec_t __align; + UINT16 s[8]; + }; + + union aligned_rsp_2vect_t { + rsp_vec_t __align[2]; + UINT16 s[16]; + }; + + union aligned_rsp_3vect_t { + rsp_vec_t __align[3]; + UINT16 s[24]; + }; + + __align16 aligned_rsp_1vect_t m_vdqm; + __align16 aligned_rsp_2vect_t m_flags[3]; + __align16 aligned_rsp_3vect_t m_acc; + UINT32 m_dp_flag; + + typedef struct + { + rsp_vec_t dummy_for_alignment; + const UINT16 logic_mask[2][8]; + const UINT16 vrsq_mask_table[8][8]; + const UINT16 shuffle_keys[16][8]; + const UINT16 sll_b2l_keys[16][8]; + const UINT16 sll_l2b_keys[16][8]; + const UINT16 srl_b2l_keys[16][8]; + const UINT16 ror_b2l_keys[16][8]; + const UINT16 rol_l2b_keys[16][8]; + const UINT16 ror_l2b_keys[16][8]; + const UINT16 qr_lut[16][8]; + const UINT16 bdls_lut[4][4]; + const UINT16 word_reverse[8]; + } vec_helpers_t; + + static const vec_helpers_t m_vec_helpers; + + rsp_vec_t vec_load_and_shuffle_operand(const UINT16* src, UINT32 element); + static inline UINT32 sign_extend_6(INT32 i) { + return ((i << (32 - 7)) >> (32 - 7)) & 0xfff; + } + static inline rsp_vec_t vec_load_unshuffled_operand(const void* src) + { + return _mm_load_si128((rsp_vec_t*) src); + } + static inline void vec_write_operand(UINT16* dest, rsp_vec_t src) + { + _mm_store_si128((rsp_vec_t*) dest, src); + } + static inline rsp_vec_t read_acc_lo(const UINT16* acc) + { + return vec_load_unshuffled_operand(acc + sizeof(rsp_vec_t)); + } + static inline rsp_vec_t read_acc_mid(const UINT16* acc) + { + return vec_load_unshuffled_operand(acc + (sizeof(rsp_vec_t) >> 1)); + } + static inline rsp_vec_t read_acc_hi(const void* acc) + { + return vec_load_unshuffled_operand(acc); + } + static inline rsp_vec_t read_vcc_lo(const UINT16 *vcc) + { + return vec_load_unshuffled_operand(vcc + (sizeof(rsp_vec_t) >> 1)); + } + static inline rsp_vec_t read_vcc_hi(const UINT16 *vcc) + { + return vec_load_unshuffled_operand(vcc); + } + static inline rsp_vec_t read_vco_lo(const UINT16 *vco) + { + return vec_load_unshuffled_operand(vco + (sizeof(rsp_vec_t) >> 1)); + } + static inline rsp_vec_t read_vco_hi(const UINT16 *vco) + { + return vec_load_unshuffled_operand(vco); + } + static inline rsp_vec_t read_vce(const UINT16 *vce) + { + return vec_load_unshuffled_operand(vce + (sizeof(rsp_vec_t) >> 1)); + } + static inline void write_acc_lo(UINT16 *acc, rsp_vec_t acc_lo) + { + return vec_write_operand(acc + sizeof(rsp_vec_t), acc_lo); + } + static inline void write_acc_mid(UINT16 *acc, rsp_vec_t acc_mid) + { + return vec_write_operand(acc + (sizeof(rsp_vec_t) >> 1), acc_mid); + } + static inline void write_acc_hi(UINT16 *acc, rsp_vec_t acc_hi) + { + return vec_write_operand(acc, acc_hi); + } + static inline void write_vcc_lo(UINT16 *vcc, rsp_vec_t vcc_lo) + { + return vec_write_operand(vcc + (sizeof(rsp_vec_t) >> 1), vcc_lo); + } + static inline void write_vcc_hi(UINT16 *vcc, rsp_vec_t vcc_hi) + { + return vec_write_operand(vcc, vcc_hi); + } + static inline void write_vco_lo(UINT16 *vcc, rsp_vec_t vco_lo) + { + return vec_write_operand(vcc + (sizeof(rsp_vec_t) >> 1), vco_lo); + } + static inline void write_vco_hi(UINT16 *vcc, rsp_vec_t vco_hi) + { + return vec_write_operand(vcc, vco_hi); + } + static inline void write_vce(UINT16 *vce, rsp_vec_t vce_r) + { + return vec_write_operand(vce + (sizeof(rsp_vec_t) >> 1), vce_r); + } + + static inline INT16 get_flags(const UINT16 *flags) + { + return _mm_movemask_epi8(_mm_packs_epi16(_mm_load_si128((rsp_vec_t*) (flags + (sizeof(rsp_vec_t) >> 1))), _mm_load_si128((rsp_vec_t*) flags))); + } + + static inline rsp_vec_t vec_zero() + { + return _mm_setzero_si128(); + } + + void vec_load_group1(UINT32 addr, UINT32 element, UINT16* regp, rsp_vec_t reg, rsp_vec_t dqm); + void vec_load_group2(UINT32 addr, UINT32 element, UINT16* regp, rsp_vec_t reg, rsp_vec_t dqm, rsp_mem_request_type request_type); + void vec_load_group4(UINT32 addr, UINT32 element, UINT16* regp, rsp_vec_t reg, rsp_vec_t dqm, rsp_mem_request_type request_type); + void vec_store_group1(UINT32 addr, UINT32 element, UINT16* regp, rsp_vec_t reg, rsp_vec_t dqm); + void vec_store_group2(UINT32 addr, UINT32 element, UINT16* regp, rsp_vec_t reg, rsp_vec_t dqm, rsp_mem_request_type request_type); + void vec_store_group4(UINT32 addr, UINT32 element, UINT16* regp, rsp_vec_t reg, rsp_vec_t dqm, rsp_mem_request_type request_type); + +#include "clamp.h" +#include "vabs.h" +#include "vadd.h" +#include "vaddc.h" +#include "vand.h" +#include "vch.h" +#include "vcmp.h" +#include "vcl.h" +#include "vcr.h" +#include "vdivh.h" +#include "vmac.h" +#include "vmov.h" +#include "vmrg.h" +#include "vmul.h" +#include "vmulh.h" +#include "vmull.h" +#include "vmulm.h" +#include "vmuln.h" +#include "vor.h" +#include "vrcpsq.h" +#include "vrsq.h" +#include "vsub.h" +#include "vsubc.h" +#include "vxor.h" +#include "vldst.h" +#endif + +private: + void handle_lwc2(UINT32 op); + void handle_swc2(UINT32 op); + void handle_vector_ops(UINT32 op); + + UINT32 m_div_in; + UINT32 m_div_out; +}; + +#endif /* __RSPCP2_H__ */ diff --git a/src/devices/cpu/rsp/rspcp2d.c b/src/devices/cpu/rsp/rspcp2d.c new file mode 100644 index 00000000000..d7844be717c --- /dev/null +++ b/src/devices/cpu/rsp/rspcp2d.c @@ -0,0 +1,3736 @@ +// license:BSD-3-Clause +// copyright-holders:Ryan Holtz +/*************************************************************************** + + rspcp2d.c + + Universal machine language-based Nintendo/SGI RSP COP2 emulator. + Written by Harmony of the MESS team. + +***************************************************************************/ + +#include "emu.h" +#include "rsp.h" +#include "rspcp2.h" +#include "rspcp2d.h" +#include "cpu/drcfe.h" +#include "cpu/drcuml.h" +#include "cpu/drcumlsh.h" + +using namespace uml; + +extern offs_t rsp_dasm_one(char *buffer, offs_t pc, UINT32 op); + +/*************************************************************************** + Helpful Defines +***************************************************************************/ + +#define VDREG ((op >> 6) & 0x1f) +#define VS1REG ((op >> 11) & 0x1f) +#define VS2REG ((op >> 16) & 0x1f) +#define EL ((op >> 21) & 0xf) + +#define RSVAL (m_rsp.m_rsp_state->r[RSREG]) +#define RTVAL (m_rsp.m_rsp_state->r[RTREG]) +#define RDVAL (m_rsp.m_rsp_state->r[RDREG]) + +#define VREG_B(reg, offset) m_v[(reg)].b[(offset)^1] +#define W_VREG_S(reg, offset) m_v[(reg)].s[(offset)] +#define VREG_S(reg, offset) (INT16)m_v[(reg)].s[(offset)] + +#define VEC_EL_2(x,z) (vector_elements_2[(x)][(z)]) + +#define ACCUM(x) m_accum[x].q + +#define CARRY 0 +#define COMPARE 1 +#define CLIP1 2 +#define ZERO 3 +#define CLIP2 4 + +static void cfunc_mfc2(void *param); +static void cfunc_cfc2(void *param); +static void cfunc_mtc2(void *param); +static void cfunc_ctc2(void *param); + +#define ACCUM_H(x) (UINT16)m_accum[x].w[3] +#define ACCUM_M(x) (UINT16)m_accum[x].w[2] +#define ACCUM_L(x) (UINT16)m_accum[x].w[1] +#define ACCUM_LL(x) (UINT16)m_accum[x].w[0] +#define ACCUM(x) m_accum[x].q + +#define SET_ACCUM_H(v, x) m_accum[x].w[3] = v; +#define SET_ACCUM_M(v, x) m_accum[x].w[2] = v; +#define SET_ACCUM_L(v, x) m_accum[x].w[1] = v; +#define SET_ACCUM_LL(v, x) m_accum[x].w[0] = v; +#define SET_ACCUM(v, x) m_accum[x].q = v; + +#define GET_VS1(out, i) out = VREG_S(vs1reg, i) +#define GET_VS2(out, i) out = VREG_S(vs2reg, VEC_EL_2(el, i)) + +#define CARRY_FLAG(x) (m_vflag[CARRY][x & 7] != 0 ? 0xffff : 0) +#define COMPARE_FLAG(x) (m_vflag[COMPARE][x & 7] != 0 ? 0xffff : 0) +#define CLIP1_FLAG(x) (m_vflag[CLIP1][x & 7] != 0 ? 0xffff : 0) +#define ZERO_FLAG(x) (m_vflag[ZERO][x & 7] != 0 ? 0xffff : 0) +#define CLIP2_FLAG(x) (m_vflag[CLIP2][x & 7] != 0 ? 0xffff : 0) + +#define CLEAR_CARRY_FLAGS() { memset(m_vflag[CARRY], 0, 16); } +#define CLEAR_COMPARE_FLAGS() { memset(m_vflag[COMPARE], 0, 16); } +#define CLEAR_CLIP1_FLAGS() { memset(m_vflag[CLIP1], 0, 16); } +#define CLEAR_ZERO_FLAGS() { memset(m_vflag[ZERO], 0, 16); } +#define CLEAR_CLIP2_FLAGS() { memset(m_vflag[CLIP2], 0, 16); } + +#define SET_CARRY_FLAG(x) { m_vflag[CARRY][x & 7] = 0xffff; } +#define SET_COMPARE_FLAG(x) { m_vflag[COMPARE][x & 7] = 0xffff; } +#define SET_CLIP1_FLAG(x) { m_vflag[CLIP1][x & 7] = 0xffff; } +#define SET_ZERO_FLAG(x) { m_vflag[ZERO][x & 7] = 0xffff; } +#define SET_CLIP2_FLAG(x) { m_vflag[CLIP2][x & 7] = 0xffff; } + +#define CLEAR_CARRY_FLAG(x) { m_vflag[CARRY][x & 7] = 0; } +#define CLEAR_COMPARE_FLAG(x) { m_vflag[COMPARE][x & 7] = 0; } +#define CLEAR_CLIP1_FLAG(x) { m_vflag[CLIP1][x & 7] = 0; } +#define CLEAR_ZERO_FLAG(x) { m_vflag[ZERO][x & 7] = 0; } +#define CLEAR_CLIP2_FLAG(x) { m_vflag[CLIP2][x & 7] = 0; } + +#define CACHE_VALUES() \ + const int op = m_rspcop2_state->op; \ + const int vdreg = VDREG; \ + const int vs1reg = VS1REG; \ + const int vs2reg = VS2REG; \ + const int el = EL; + +#define WRITEBACK_RESULT() { \ + W_VREG_S(vdreg, 0) = m_vres[0]; \ + W_VREG_S(vdreg, 1) = m_vres[1]; \ + W_VREG_S(vdreg, 2) = m_vres[2]; \ + W_VREG_S(vdreg, 3) = m_vres[3]; \ + W_VREG_S(vdreg, 4) = m_vres[4]; \ + W_VREG_S(vdreg, 5) = m_vres[5]; \ + W_VREG_S(vdreg, 6) = m_vres[6]; \ + W_VREG_S(vdreg, 7) = m_vres[7]; \ +} + +static const int vector_elements_2[16][8] = +{ + { 0, 1, 2, 3, 4, 5, 6, 7 }, // none + { 0, 1, 2, 3, 4, 5, 6, 7 }, // ??? + { 0, 0, 2, 2, 4, 4, 6, 6 }, // 0q + { 1, 1, 3, 3, 5, 5, 7, 7 }, // 1q + { 0, 0, 0, 0, 4, 4, 4, 4 }, // 0h + { 1, 1, 1, 1, 5, 5, 5, 5 }, // 1h + { 2, 2, 2, 2, 6, 6, 6, 6 }, // 2h + { 3, 3, 3, 3, 7, 7, 7, 7 }, // 3h + { 0, 0, 0, 0, 0, 0, 0, 0 }, // 0 + { 1, 1, 1, 1, 1, 1, 1, 1 }, // 1 + { 2, 2, 2, 2, 2, 2, 2, 2 }, // 2 + { 3, 3, 3, 3, 3, 3, 3, 3 }, // 3 + { 4, 4, 4, 4, 4, 4, 4, 4 }, // 4 + { 5, 5, 5, 5, 5, 5, 5, 5 }, // 5 + { 6, 6, 6, 6, 6, 6, 6, 6 }, // 6 + { 7, 7, 7, 7, 7, 7, 7, 7 }, // 7 +}; + +void rsp_cop2_drc::cfunc_unimplemented_opcode() +{ + const UINT32 ppc = m_rsp.m_ppc; + if ((m_machine.debug_flags & DEBUG_FLAG_ENABLED) != 0) + { + char string[200]; + rsp_dasm_one(string, ppc, m_rspcop2_state->op); + osd_printf_debug("%08X: %s\n", ppc, string); + } + fatalerror("RSP: unknown opcode %02X (%08X) at %08X\n", m_rspcop2_state->op >> 26, m_rspcop2_state->op, ppc); +} + +static void unimplemented_opcode(void *param) +{ + ((rsp_cop2 *)param)->cfunc_unimplemented_opcode(); +} + +void rsp_cop2_drc::state_string_export(const int index, std::string &str) +{ + switch (index) + { + case RSP_V0: + strprintf(str, "%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S( 0, 0), (UINT16)VREG_S( 0, 1), (UINT16)VREG_S( 0, 2), (UINT16)VREG_S( 0, 3), (UINT16)VREG_S( 0, 4), (UINT16)VREG_S( 0, 5), (UINT16)VREG_S( 0, 6), (UINT16)VREG_S( 0, 7)); + break; + case RSP_V1: + strprintf(str, "%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S( 1, 0), (UINT16)VREG_S( 1, 1), (UINT16)VREG_S( 1, 2), (UINT16)VREG_S( 1, 3), (UINT16)VREG_S( 1, 4), (UINT16)VREG_S( 1, 5), (UINT16)VREG_S( 1, 6), (UINT16)VREG_S( 1, 7)); + break; + case RSP_V2: + strprintf(str, "%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S( 2, 0), (UINT16)VREG_S( 2, 1), (UINT16)VREG_S( 2, 2), (UINT16)VREG_S( 2, 3), (UINT16)VREG_S( 2, 4), (UINT16)VREG_S( 2, 5), (UINT16)VREG_S( 2, 6), (UINT16)VREG_S( 2, 7)); + break; + case RSP_V3: + strprintf(str, "%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S( 3, 0), (UINT16)VREG_S( 3, 1), (UINT16)VREG_S( 3, 2), (UINT16)VREG_S( 3, 3), (UINT16)VREG_S( 3, 4), (UINT16)VREG_S( 3, 5), (UINT16)VREG_S( 3, 6), (UINT16)VREG_S( 3, 7)); + break; + case RSP_V4: + strprintf(str, "%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S( 4, 0), (UINT16)VREG_S( 4, 1), (UINT16)VREG_S( 4, 2), (UINT16)VREG_S( 4, 3), (UINT16)VREG_S( 4, 4), (UINT16)VREG_S( 4, 5), (UINT16)VREG_S( 4, 6), (UINT16)VREG_S( 4, 7)); + break; + case RSP_V5: + strprintf(str, "%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S( 5, 0), (UINT16)VREG_S( 5, 1), (UINT16)VREG_S( 5, 2), (UINT16)VREG_S( 5, 3), (UINT16)VREG_S( 5, 4), (UINT16)VREG_S( 5, 5), (UINT16)VREG_S( 5, 6), (UINT16)VREG_S( 5, 7)); + break; + case RSP_V6: + strprintf(str, "%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S( 6, 0), (UINT16)VREG_S( 6, 1), (UINT16)VREG_S( 6, 2), (UINT16)VREG_S( 6, 3), (UINT16)VREG_S( 6, 4), (UINT16)VREG_S( 6, 5), (UINT16)VREG_S( 6, 6), (UINT16)VREG_S( 6, 7)); + break; + case RSP_V7: + strprintf(str, "%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S( 7, 0), (UINT16)VREG_S( 7, 1), (UINT16)VREG_S( 7, 2), (UINT16)VREG_S( 7, 3), (UINT16)VREG_S( 7, 4), (UINT16)VREG_S( 7, 5), (UINT16)VREG_S( 7, 6), (UINT16)VREG_S( 7, 7)); + break; + case RSP_V8: + strprintf(str, "%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S( 8, 0), (UINT16)VREG_S( 8, 1), (UINT16)VREG_S( 8, 2), (UINT16)VREG_S( 8, 3), (UINT16)VREG_S( 8, 4), (UINT16)VREG_S( 8, 5), (UINT16)VREG_S( 8, 6), (UINT16)VREG_S( 8, 7)); + break; + case RSP_V9: + strprintf(str, "%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S( 9, 0), (UINT16)VREG_S( 9, 1), (UINT16)VREG_S( 9, 2), (UINT16)VREG_S( 9, 3), (UINT16)VREG_S( 9, 4), (UINT16)VREG_S( 9, 5), (UINT16)VREG_S( 9, 6), (UINT16)VREG_S( 9, 7)); + break; + case RSP_V10: + strprintf(str, "%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(10, 0), (UINT16)VREG_S(10, 1), (UINT16)VREG_S(10, 2), (UINT16)VREG_S(10, 3), (UINT16)VREG_S(10, 4), (UINT16)VREG_S(10, 5), (UINT16)VREG_S(10, 6), (UINT16)VREG_S(10, 7)); + break; + case RSP_V11: + strprintf(str, "%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(11, 0), (UINT16)VREG_S(11, 1), (UINT16)VREG_S(11, 2), (UINT16)VREG_S(11, 3), (UINT16)VREG_S(11, 4), (UINT16)VREG_S(11, 5), (UINT16)VREG_S(11, 6), (UINT16)VREG_S(11, 7)); + break; + case RSP_V12: + strprintf(str, "%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(12, 0), (UINT16)VREG_S(12, 1), (UINT16)VREG_S(12, 2), (UINT16)VREG_S(12, 3), (UINT16)VREG_S(12, 4), (UINT16)VREG_S(12, 5), (UINT16)VREG_S(12, 6), (UINT16)VREG_S(12, 7)); + break; + case RSP_V13: + strprintf(str, "%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(13, 0), (UINT16)VREG_S(13, 1), (UINT16)VREG_S(13, 2), (UINT16)VREG_S(13, 3), (UINT16)VREG_S(13, 4), (UINT16)VREG_S(13, 5), (UINT16)VREG_S(13, 6), (UINT16)VREG_S(13, 7)); + break; + case RSP_V14: + strprintf(str, "%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(14, 0), (UINT16)VREG_S(14, 1), (UINT16)VREG_S(14, 2), (UINT16)VREG_S(14, 3), (UINT16)VREG_S(14, 4), (UINT16)VREG_S(14, 5), (UINT16)VREG_S(14, 6), (UINT16)VREG_S(14, 7)); + break; + case RSP_V15: + strprintf(str, "%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(15, 0), (UINT16)VREG_S(15, 1), (UINT16)VREG_S(15, 2), (UINT16)VREG_S(15, 3), (UINT16)VREG_S(15, 4), (UINT16)VREG_S(15, 5), (UINT16)VREG_S(15, 6), (UINT16)VREG_S(15, 7)); + break; + case RSP_V16: + strprintf(str, "%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(16, 0), (UINT16)VREG_S(16, 1), (UINT16)VREG_S(16, 2), (UINT16)VREG_S(16, 3), (UINT16)VREG_S(16, 4), (UINT16)VREG_S(16, 5), (UINT16)VREG_S(16, 6), (UINT16)VREG_S(16, 7)); + break; + case RSP_V17: + strprintf(str, "%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(17, 0), (UINT16)VREG_S(17, 1), (UINT16)VREG_S(17, 2), (UINT16)VREG_S(17, 3), (UINT16)VREG_S(17, 4), (UINT16)VREG_S(17, 5), (UINT16)VREG_S(17, 6), (UINT16)VREG_S(17, 7)); + break; + case RSP_V18: + strprintf(str, "%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(18, 0), (UINT16)VREG_S(18, 1), (UINT16)VREG_S(18, 2), (UINT16)VREG_S(18, 3), (UINT16)VREG_S(18, 4), (UINT16)VREG_S(18, 5), (UINT16)VREG_S(18, 6), (UINT16)VREG_S(18, 7)); + break; + case RSP_V19: + strprintf(str, "%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(19, 0), (UINT16)VREG_S(19, 1), (UINT16)VREG_S(19, 2), (UINT16)VREG_S(19, 3), (UINT16)VREG_S(19, 4), (UINT16)VREG_S(19, 5), (UINT16)VREG_S(19, 6), (UINT16)VREG_S(19, 7)); + break; + case RSP_V20: + strprintf(str, "%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(20, 0), (UINT16)VREG_S(20, 1), (UINT16)VREG_S(20, 2), (UINT16)VREG_S(20, 3), (UINT16)VREG_S(20, 4), (UINT16)VREG_S(20, 5), (UINT16)VREG_S(20, 6), (UINT16)VREG_S(20, 7)); + break; + case RSP_V21: + strprintf(str, "%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(21, 0), (UINT16)VREG_S(21, 1), (UINT16)VREG_S(21, 2), (UINT16)VREG_S(21, 3), (UINT16)VREG_S(21, 4), (UINT16)VREG_S(21, 5), (UINT16)VREG_S(21, 6), (UINT16)VREG_S(21, 7)); + break; + case RSP_V22: + strprintf(str, "%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(22, 0), (UINT16)VREG_S(22, 1), (UINT16)VREG_S(22, 2), (UINT16)VREG_S(22, 3), (UINT16)VREG_S(22, 4), (UINT16)VREG_S(22, 5), (UINT16)VREG_S(22, 6), (UINT16)VREG_S(22, 7)); + break; + case RSP_V23: + strprintf(str, "%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(23, 0), (UINT16)VREG_S(23, 1), (UINT16)VREG_S(23, 2), (UINT16)VREG_S(23, 3), (UINT16)VREG_S(23, 4), (UINT16)VREG_S(23, 5), (UINT16)VREG_S(23, 6), (UINT16)VREG_S(23, 7)); + break; + case RSP_V24: + strprintf(str, "%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(24, 0), (UINT16)VREG_S(24, 1), (UINT16)VREG_S(24, 2), (UINT16)VREG_S(24, 3), (UINT16)VREG_S(24, 4), (UINT16)VREG_S(24, 5), (UINT16)VREG_S(24, 6), (UINT16)VREG_S(24, 7)); + break; + case RSP_V25: + strprintf(str, "%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(25, 0), (UINT16)VREG_S(25, 1), (UINT16)VREG_S(25, 2), (UINT16)VREG_S(25, 3), (UINT16)VREG_S(25, 4), (UINT16)VREG_S(25, 5), (UINT16)VREG_S(25, 6), (UINT16)VREG_S(25, 7)); + break; + case RSP_V26: + strprintf(str, "%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(26, 0), (UINT16)VREG_S(26, 1), (UINT16)VREG_S(26, 2), (UINT16)VREG_S(26, 3), (UINT16)VREG_S(26, 4), (UINT16)VREG_S(26, 5), (UINT16)VREG_S(26, 6), (UINT16)VREG_S(26, 7)); + break; + case RSP_V27: + strprintf(str, "%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(27, 0), (UINT16)VREG_S(27, 1), (UINT16)VREG_S(27, 2), (UINT16)VREG_S(27, 3), (UINT16)VREG_S(27, 4), (UINT16)VREG_S(27, 5), (UINT16)VREG_S(27, 6), (UINT16)VREG_S(27, 7)); + break; + case RSP_V28: + strprintf(str, "%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(28, 0), (UINT16)VREG_S(28, 1), (UINT16)VREG_S(28, 2), (UINT16)VREG_S(28, 3), (UINT16)VREG_S(28, 4), (UINT16)VREG_S(28, 5), (UINT16)VREG_S(28, 6), (UINT16)VREG_S(28, 7)); + break; + case RSP_V29: + strprintf(str, "%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(29, 0), (UINT16)VREG_S(29, 1), (UINT16)VREG_S(29, 2), (UINT16)VREG_S(29, 3), (UINT16)VREG_S(29, 4), (UINT16)VREG_S(29, 5), (UINT16)VREG_S(29, 6), (UINT16)VREG_S(29, 7)); + break; + case RSP_V30: + strprintf(str, "%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(30, 0), (UINT16)VREG_S(30, 1), (UINT16)VREG_S(30, 2), (UINT16)VREG_S(30, 3), (UINT16)VREG_S(30, 4), (UINT16)VREG_S(30, 5), (UINT16)VREG_S(30, 6), (UINT16)VREG_S(30, 7)); + break; + case RSP_V31: + strprintf(str, "%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(31, 0), (UINT16)VREG_S(31, 1), (UINT16)VREG_S(31, 2), (UINT16)VREG_S(31, 3), (UINT16)VREG_S(31, 4), (UINT16)VREG_S(31, 5), (UINT16)VREG_S(31, 6), (UINT16)VREG_S(31, 7)); + break; + } +} + + +/*************************************************************************** + Vector Load Instructions +***************************************************************************/ + +// LBV +// +// 31 25 20 15 10 6 0 +// -------------------------------------------------- +// | 110010 | BBBBB | TTTTT | 00000 | IIII | Offset | +// -------------------------------------------------- +// +// Load 1 byte to vector byte index + +void rsp_cop2_drc::lbv() +{ + UINT32 op = m_rspcop2_state->op; + + UINT32 ea = 0; + int dest = (op >> 16) & 0x1f; + int base = (op >> 21) & 0x1f; + int index = (op >> 7) & 0xf; + int offset = (op & 0x7f); + if (offset & 0x40) + { + offset |= 0xffffffc0; + } + + ea = (base) ? m_rsp.m_rsp_state->r[base] + offset : offset; + VREG_B(dest, index) = m_rsp.DM_READ8(ea); +} + +static void cfunc_lbv(void *param) +{ + ((rsp_cop2 *)param)->lbv(); +} + + +// LSV +// +// 31 25 20 15 10 6 0 +// -------------------------------------------------- +// | 110010 | BBBBB | TTTTT | 00001 | IIII | Offset | +// -------------------------------------------------- +// +// Loads 2 bytes starting from vector byte index + +void rsp_cop2_drc::lsv() +{ + UINT32 op = m_rspcop2_state->op; + int dest = (op >> 16) & 0x1f; + int base = (op >> 21) & 0x1f; + int index = (op >> 7) & 0xe; + int offset = (op & 0x7f); + if (offset & 0x40) + { + offset |= 0xffffffc0; + } + + UINT32 ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 2) : (offset * 2); + int end = index + 2; + for (int i = index; i < end; i++) + { + VREG_B(dest, i) = m_rsp.DM_READ8(ea); + ea++; + } +} + +static void cfunc_lsv(void *param) +{ + ((rsp_cop2 *)param)->lsv(); +} + + +// LLV +// +// 31 25 20 15 10 6 0 +// -------------------------------------------------- +// | 110010 | BBBBB | TTTTT | 00010 | IIII | Offset | +// -------------------------------------------------- +// +// Loads 4 bytes starting from vector byte index + +void rsp_cop2_drc::llv() +{ + UINT32 op = m_rspcop2_state->op; + UINT32 ea = 0; + int dest = (op >> 16) & 0x1f; + int base = (op >> 21) & 0x1f; + int index = (op >> 7) & 0xc; + int offset = (op & 0x7f); + if (offset & 0x40) + { + offset |= 0xffffffc0; + } + + ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 4) : (offset * 4); + + int end = index + 4; + + for (int i = index; i < end; i++) + { + VREG_B(dest, i) = m_rsp.DM_READ8(ea); + ea++; + } +} + +static void cfunc_llv(void *param) +{ + ((rsp_cop2 *)param)->llv(); +} + + +// LDV +// +// 31 25 20 15 10 6 0 +// -------------------------------------------------- +// | 110010 | BBBBB | TTTTT | 00011 | IIII | Offset | +// -------------------------------------------------- +// +// Loads 8 bytes starting from vector byte index + +void rsp_cop2_drc::ldv() +{ + UINT32 op = m_rspcop2_state->op; + UINT32 ea = 0; + int dest = (op >> 16) & 0x1f; + int base = (op >> 21) & 0x1f; + int index = (op >> 7) & 0x8; + int offset = (op & 0x7f); + if (offset & 0x40) + { + offset |= 0xffffffc0; + } + + ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 8) : (offset * 8); + + int end = index + 8; + + for (int i = index; i < end; i++) + { + VREG_B(dest, i) = m_rsp.DM_READ8(ea); + ea++; + } +} + +static void cfunc_ldv(void *param) +{ + ((rsp_cop2 *)param)->ldv(); +} + + +// LQV +// +// 31 25 20 15 10 6 0 +// -------------------------------------------------- +// | 110010 | BBBBB | TTTTT | 00100 | IIII | Offset | +// -------------------------------------------------- +// +// Loads up to 16 bytes starting from vector byte index + +void rsp_cop2_drc::lqv() +{ + UINT32 op = m_rspcop2_state->op; + int dest = (op >> 16) & 0x1f; + int base = (op >> 21) & 0x1f; + int offset = (op & 0x7f); + if (offset & 0x40) + { + offset |= 0xffffffc0; + } + + UINT32 ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 16) : (offset * 16); + + int end = 16 - (ea & 0xf); + if (end > 16) end = 16; + + for (int i = 0; i < end; i++) + { + VREG_B(dest, i) = m_rsp.DM_READ8(ea); + ea++; + } +} + +static void cfunc_lqv(void *param) +{ + ((rsp_cop2 *)param)->lqv(); +} + + +// LRV +// +// 31 25 20 15 10 6 0 +// -------------------------------------------------- +// | 110010 | BBBBB | TTTTT | 00101 | IIII | Offset | +// -------------------------------------------------- +// +// Stores up to 16 bytes starting from right side until 16-byte boundary + +void rsp_cop2_drc::lrv() +{ + UINT32 op = m_rspcop2_state->op; + int dest = (op >> 16) & 0x1f; + int base = (op >> 21) & 0x1f; + int index = (op >> 7) & 0xf; + int offset = (op & 0x7f); + if (offset & 0x40) + { + offset |= 0xffffffc0; + } + + UINT32 ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 16) : (offset * 16); + + index = 16 - ((ea & 0xf) - index); + ea &= ~0xf; + + for (int i = index; i < 16; i++) + { + VREG_B(dest, i) = m_rsp.DM_READ8(ea); + ea++; + } +} + +static void cfunc_lrv(void *param) +{ + ((rsp_cop2 *)param)->lrv(); +} + + +// LPV +// +// 31 25 20 15 10 6 0 +// -------------------------------------------------- +// | 110010 | BBBBB | TTTTT | 00110 | IIII | Offset | +// -------------------------------------------------- +// +// Loads a byte as the upper 8 bits of each element + +void rsp_cop2_drc::lpv() +{ + UINT32 op = m_rspcop2_state->op; + int dest = (op >> 16) & 0x1f; + int base = (op >> 21) & 0x1f; + int index = (op >> 7) & 0xf; + int offset = (op & 0x7f); + if (offset & 0x40) + { + offset |= 0xffffffc0; + } + + UINT32 ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 8) : (offset * 8); + + for (int i = 0; i < 8; i++) + { + W_VREG_S(dest, i) = m_rsp.DM_READ8(ea + (((16-index) + i) & 0xf)) << 8; + } +} + +static void cfunc_lpv(void *param) +{ + ((rsp_cop2 *)param)->lpv(); +} + + +// LUV +// +// 31 25 20 15 10 6 0 +// -------------------------------------------------- +// | 110010 | BBBBB | TTTTT | 00111 | IIII | Offset | +// -------------------------------------------------- +// +// Loads a byte as the bits 14-7 of each element + +void rsp_cop2_drc::luv() +{ + UINT32 op = m_rspcop2_state->op; + int dest = (op >> 16) & 0x1f; + int base = (op >> 21) & 0x1f; + int index = (op >> 7) & 0xf; + int offset = (op & 0x7f); + if (offset & 0x40) + { + offset |= 0xffffffc0; + } + + UINT32 ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 8) : (offset * 8); + + for (int i = 0; i < 8; i++) + { + W_VREG_S(dest, i) = m_rsp.DM_READ8(ea + (((16-index) + i) & 0xf)) << 7; + } +} + +static void cfunc_luv(void *param) +{ + ((rsp_cop2 *)param)->luv(); +} + + +// LHV +// +// 31 25 20 15 10 6 0 +// -------------------------------------------------- +// | 110010 | BBBBB | TTTTT | 01000 | IIII | Offset | +// -------------------------------------------------- +// +// Loads a byte as the bits 14-7 of each element, with 2-byte stride + +void rsp_cop2_drc::lhv() +{ + UINT32 op = m_rspcop2_state->op; + int dest = (op >> 16) & 0x1f; + int base = (op >> 21) & 0x1f; + int index = (op >> 7) & 0xf; + int offset = (op & 0x7f); + if (offset & 0x40) + { + offset |= 0xffffffc0; + } + + UINT32 ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 16) : (offset * 16); + + for (int i = 0; i < 8; i++) + { + W_VREG_S(dest, i) = m_rsp.DM_READ8(ea + (((16-index) + (i<<1)) & 0xf)) << 7; + } +} + +static void cfunc_lhv(void *param) +{ + ((rsp_cop2 *)param)->lhv(); +} + + +// LFV +// 31 25 20 15 10 6 0 +// -------------------------------------------------- +// | 110010 | BBBBB | TTTTT | 01001 | IIII | Offset | +// -------------------------------------------------- +// +// Loads a byte as the bits 14-7 of upper or lower quad, with 4-byte stride + +void rsp_cop2_drc::lfv() +{ + UINT32 op = m_rspcop2_state->op; + int dest = (op >> 16) & 0x1f; + int base = (op >> 21) & 0x1f; + int index = (op >> 7) & 0xf; + int offset = (op & 0x7f); + if (offset & 0x40) + { + offset |= 0xffffffc0; + } + + UINT32 ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 16) : (offset * 16); + + // not sure what happens if 16-byte boundary is crossed... + + int end = (index >> 1) + 4; + + for (int i = index >> 1; i < end; i++) + { + W_VREG_S(dest, i) = m_rsp.DM_READ8(ea) << 7; + ea += 4; + } +} + +static void cfunc_lfv(void *param) +{ + ((rsp_cop2 *)param)->lfv(); +} + + +// LWV +// +// 31 25 20 15 10 6 0 +// -------------------------------------------------- +// | 110010 | BBBBB | TTTTT | 01010 | IIII | Offset | +// -------------------------------------------------- +// +// Loads the full 128-bit vector starting from vector byte index and wrapping to index 0 +// after byte index 15 + +void rsp_cop2_drc::lwv() +{ + UINT32 op = m_rspcop2_state->op; + int dest = (op >> 16) & 0x1f; + int base = (op >> 21) & 0x1f; + int index = (op >> 7) & 0xf; + int offset = (op & 0x7f); + if (offset & 0x40) + { + offset |= 0xffffffc0; + } + + UINT32 ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 16) : (offset * 16); + int end = (16 - index) + 16; + + for (int i = (16 - index); i < end; i++) + { + VREG_B(dest, i & 0xf) = m_rsp.DM_READ8(ea); + ea += 4; + } +} + +static void cfunc_lwv(void *param) +{ + ((rsp_cop2 *)param)->lwv(); +} + + +// LTV +// +// 31 25 20 15 10 6 0 +// -------------------------------------------------- +// | 110010 | BBBBB | TTTTT | 01011 | IIII | Offset | +// -------------------------------------------------- +// +// Loads one element to maximum of 8 vectors, while incrementing element index + +void rsp_cop2_drc::ltv() +{ + UINT32 op = m_rspcop2_state->op; + int dest = (op >> 16) & 0x1f; + int base = (op >> 21) & 0x1f; + int index = (op >> 7) & 0xf; + int offset = (op & 0x7f); + + // FIXME: has a small problem with odd indices + + int vs = dest; + int ve = dest + 8; + if (ve > 32) + { + ve = 32; + } + + int element = 7 - (index >> 1); + + UINT32 ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 16) : (offset * 16); + + ea = ((ea + 8) & ~0xf) + (index & 1); + for (int i = vs; i < ve; i++) + { + element = (8 - (index >> 1) + (i - vs)) << 1; + VREG_B(i, (element & 0xf)) = m_rsp.DM_READ8(ea); + VREG_B(i, ((element + 1) & 0xf)) = m_rsp.DM_READ8(ea + 1); + ea += 2; + } +} + +static void cfunc_ltv(void *param) +{ + ((rsp_cop2 *)param)->ltv(); +} + + +int rsp_cop2_drc::generate_lwc2(drcuml_block *block, rsp_device::compiler_state *compiler, const opcode_desc *desc) +{ + UINT32 op = desc->opptr.l[0]; + int offset = (op & 0x7f); + if (offset & 0x40) + { + offset |= 0xffffffc0; + } + + switch ((op >> 11) & 0x1f) + { + case 0x00: /* LBV */ + UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [m_rspcop2_state->op],desc->opptr.l + UML_CALLC(block, cfunc_lbv, this); + return TRUE; + + case 0x01: /* LSV */ + UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [m_rspcop2_state->op],desc->opptr.l + UML_CALLC(block, cfunc_lsv, this); + return TRUE; + + case 0x02: /* LLV */ + UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [m_rspcop2_state->op],desc->opptr.l + UML_CALLC(block, cfunc_llv, this); + return TRUE; + + case 0x03: /* LDV */ + UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [m_rspcop2_state->op],desc->opptr.l + UML_CALLC(block, cfunc_ldv, this); + return TRUE; + + case 0x04: /* LQV */ + UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [m_rspcop2_state->op],desc->opptr.l + UML_CALLC(block, cfunc_lqv, this); + return TRUE; + + case 0x05: /* LRV */ + UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [m_rspcop2_state->op],desc->opptr.l + UML_CALLC(block, cfunc_lrv, this); + return TRUE; + + case 0x06: /* LPV */ + UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [m_rspcop2_state->op],desc->opptr.l + UML_CALLC(block, cfunc_lpv, this); + return TRUE; + + case 0x07: /* LUV */ + UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [m_rspcop2_state->op],desc->opptr.l + UML_CALLC(block, cfunc_luv, this); + return TRUE; + + case 0x08: /* LHV */ + UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [m_rspcop2_state->op],desc->opptr.l + UML_CALLC(block, cfunc_lhv, this); + return TRUE; + + case 0x09: /* LFV */ + UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [m_rspcop2_state->op],desc->opptr.l + UML_CALLC(block, cfunc_lfv, this); + return TRUE; + + case 0x0a: /* LWV */ + UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [m_rspcop2_state->op],desc->opptr.l + UML_CALLC(block, cfunc_lwv, this); + return TRUE; + + case 0x0b: /* LTV */ + UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [m_rspcop2_state->op],desc->opptr.l + UML_CALLC(block, cfunc_ltv, this); + return TRUE; + + default: + return FALSE; + } +} + + +/*************************************************************************** + Vector Store Instructions +***************************************************************************/ + +// SBV +// +// 31 25 20 15 10 6 0 +// -------------------------------------------------- +// | 111010 | BBBBB | TTTTT | 00000 | IIII | Offset | +// -------------------------------------------------- +// +// Stores 1 byte from vector byte index + +void rsp_cop2_drc::sbv() +{ + UINT32 op = m_rspcop2_state->op; + int dest = (op >> 16) & 0x1f; + int base = (op >> 21) & 0x1f; + int index = (op >> 7) & 0xf; + int offset = (op & 0x7f); + if (offset & 0x40) + { + offset |= 0xffffffc0; + } + + UINT32 ea = (base) ? m_rsp.m_rsp_state->r[base] + offset : offset; + m_rsp.DM_WRITE8(ea, VREG_B(dest, index)); +} + +static void cfunc_sbv(void *param) +{ + ((rsp_cop2 *)param)->sbv(); +} + + +// SSV +// +// 31 25 20 15 10 6 0 +// -------------------------------------------------- +// | 111010 | BBBBB | TTTTT | 00001 | IIII | Offset | +// -------------------------------------------------- +// +// Stores 2 bytes starting from vector byte index + +void rsp_cop2_drc::ssv() +{ + UINT32 op = m_rspcop2_state->op; + int dest = (op >> 16) & 0x1f; + int base = (op >> 21) & 0x1f; + int index = (op >> 7) & 0xf; + int offset = (op & 0x7f); + if (offset & 0x40) + { + offset |= 0xffffffc0; + } + + UINT32 ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 2) : (offset * 2); + + int end = index + 2; + for (int i = index; i < end; i++) + { + m_rsp.DM_WRITE8(ea, VREG_B(dest, i)); + ea++; + } +} + +static void cfunc_ssv(void *param) +{ + ((rsp_cop2 *)param)->ssv(); +} + + +// SLV +// +// 31 25 20 15 10 6 0 +// -------------------------------------------------- +// | 111010 | BBBBB | TTTTT | 00010 | IIII | Offset | +// -------------------------------------------------- +// +// Stores 4 bytes starting from vector byte index + +void rsp_cop2_drc::slv() +{ + UINT32 op = m_rspcop2_state->op; + int dest = (op >> 16) & 0x1f; + int base = (op >> 21) & 0x1f; + int index = (op >> 7) & 0xf; + int offset = (op & 0x7f); + if (offset & 0x40) + { + offset |= 0xffffffc0; + } + + UINT32 ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 4) : (offset * 4); + + int end = index + 4; + for (int i = index; i < end; i++) + { + m_rsp.DM_WRITE8(ea, VREG_B(dest, i)); + ea++; + } +} + +static void cfunc_slv(void *param) +{ + ((rsp_cop2 *)param)->slv(); +} + + +// SDV +// +// 31 25 20 15 10 6 0 +// -------------------------------------------------- +// | 111010 | BBBBB | TTTTT | 00011 | IIII | Offset | +// -------------------------------------------------- +// +// Stores 8 bytes starting from vector byte index + +void rsp_cop2_drc::sdv() +{ + UINT32 op = m_rspcop2_state->op; + int dest = (op >> 16) & 0x1f; + int base = (op >> 21) & 0x1f; + int index = (op >> 7) & 0x8; + int offset = (op & 0x7f); + if (offset & 0x40) + { + offset |= 0xffffffc0; + } + UINT32 ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 8) : (offset * 8); + + int end = index + 8; + for (int i = index; i < end; i++) + { + m_rsp.DM_WRITE8(ea, VREG_B(dest, i)); + ea++; + } +} + +static void cfunc_sdv(void *param) +{ + ((rsp_cop2 *)param)->sdv(); +} + + +// SQV +// +// 31 25 20 15 10 6 0 +// -------------------------------------------------- +// | 111010 | BBBBB | TTTTT | 00100 | IIII | Offset | +// -------------------------------------------------- +// +// Stores up to 16 bytes starting from vector byte index until 16-byte boundary + +void rsp_cop2_drc::sqv() +{ + UINT32 op = m_rspcop2_state->op; + int dest = (op >> 16) & 0x1f; + int base = (op >> 21) & 0x1f; + int index = (op >> 7) & 0xf; + int offset = (op & 0x7f); + if (offset & 0x40) + { + offset |= 0xffffffc0; + } + + UINT32 ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 16) : (offset * 16); + int end = index + (16 - (ea & 0xf)); + for (int i=index; i < end; i++) + { + m_rsp.DM_WRITE8(ea, VREG_B(dest, i & 0xf)); + ea++; + } +} + +static void cfunc_sqv(void *param) +{ + ((rsp_cop2 *)param)->sqv(); +} + + +// SRV +// +// 31 25 20 15 10 6 0 +// -------------------------------------------------- +// | 111010 | BBBBB | TTTTT | 00101 | IIII | Offset | +// -------------------------------------------------- +// +// Stores up to 16 bytes starting from right side until 16-byte boundary + +void rsp_cop2_drc::srv() +{ + UINT32 op = m_rspcop2_state->op; + int dest = (op >> 16) & 0x1f; + int base = (op >> 21) & 0x1f; + int index = (op >> 7) & 0xf; + int offset = (op & 0x7f); + if (offset & 0x40) + { + offset |= 0xffffffc0; + } + + UINT32 ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 16) : (offset * 16); + + int end = index + (ea & 0xf); + int o = (16 - (ea & 0xf)) & 0xf; + ea &= ~0xf; + + for (int i = index; i < end; i++) + { + m_rsp.DM_WRITE8(ea, VREG_B(dest, ((i + o) & 0xf))); + ea++; + } +} + +static void cfunc_srv(void *param) +{ + ((rsp_cop2 *)param)->srv(); +} + + +// SPV +// +// 31 25 20 15 10 6 0 +// -------------------------------------------------- +// | 111010 | BBBBB | TTTTT | 00110 | IIII | Offset | +// -------------------------------------------------- +// +// Stores upper 8 bits of each element + +void rsp_cop2_drc::spv() +{ + UINT32 op = m_rspcop2_state->op; + int dest = (op >> 16) & 0x1f; + int base = (op >> 21) & 0x1f; + int index = (op >> 7) & 0xf; + int offset = (op & 0x7f); + if (offset & 0x40) + { + offset |= 0xffffffc0; + } + + UINT32 ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 8) : (offset * 8); + int end = index + 8; + for (int i=index; i < end; i++) + { + if ((i & 0xf) < 8) + { + m_rsp.DM_WRITE8(ea, VREG_B(dest, (i & 0xf) << 1)); + } + else + { + m_rsp.DM_WRITE8(ea, VREG_S(dest, (i & 0x7)) >> 7); + } + ea++; + } +} + +static void cfunc_spv(void *param) +{ + ((rsp_cop2 *)param)->spv(); +} + + +// SUV +// +// 31 25 20 15 10 6 0 +// -------------------------------------------------- +// | 111010 | BBBBB | TTTTT | 00111 | IIII | Offset | +// -------------------------------------------------- +// +// Stores bits 14-7 of each element + +void rsp_cop2_drc::suv() +{ + UINT32 op = m_rspcop2_state->op; + int dest = (op >> 16) & 0x1f; + int base = (op >> 21) & 0x1f; + int index = (op >> 7) & 0xf; + int offset = (op & 0x7f); + if (offset & 0x40) + { + offset |= 0xffffffc0; + } + + UINT32 ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 8) : (offset * 8); + int end = index + 8; + for (int i=index; i < end; i++) + { + if ((i & 0xf) < 8) + { + m_rsp.DM_WRITE8(ea, VREG_S(dest, (i & 0x7)) >> 7); + } + else + { + m_rsp.DM_WRITE8(ea, VREG_B(dest, ((i & 0x7) << 1))); + } + ea++; + } +} + +static void cfunc_suv(void *param) +{ + ((rsp_cop2 *)param)->suv(); +} + + +// SHV +// +// 31 25 20 15 10 6 0 +// -------------------------------------------------- +// | 111010 | BBBBB | TTTTT | 01000 | IIII | Offset | +// -------------------------------------------------- +// +// Stores bits 14-7 of each element, with 2-byte stride + +void rsp_cop2_drc::shv() +{ + UINT32 op = m_rspcop2_state->op; + int dest = (op >> 16) & 0x1f; + int base = (op >> 21) & 0x1f; + int index = (op >> 7) & 0xf; + int offset = (op & 0x7f); + if (offset & 0x40) + { + offset |= 0xffffffc0; + } + + UINT32 ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 16) : (offset * 16); + for (int i=0; i < 8; i++) + { + int element = index + (i << 1); + UINT8 d = (VREG_B(dest, (element & 0xf)) << 1) | + (VREG_B(dest, ((element + 1) & 0xf)) >> 7); + m_rsp.DM_WRITE8(ea, d); + ea += 2; + } +} + +static void cfunc_shv(void *param) +{ + ((rsp_cop2 *)param)->shv(); +} + + +// SFV +// +// 31 25 20 15 10 6 0 +// -------------------------------------------------- +// | 111010 | BBBBB | TTTTT | 01001 | IIII | Offset | +// -------------------------------------------------- +// +// Stores bits 14-7 of upper or lower quad, with 4-byte stride + +void rsp_cop2_drc::sfv() +{ + UINT32 op = m_rspcop2_state->op; + int dest = (op >> 16) & 0x1f; + int base = (op >> 21) & 0x1f; + int index = (op >> 7) & 0xf; + int offset = (op & 0x7f); + if (offset & 0x40) + { + offset |= 0xffffffc0; + } + + UINT32 ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 16) : (offset * 16); + int eaoffset = ea & 0xf; + ea &= ~0xf; + + int end = (index >> 1) + 4; + + for (int i = index>>1; i < end; i++) + { + m_rsp.DM_WRITE8(ea + (eaoffset & 0xf), VREG_S(dest, i) >> 7); + eaoffset += 4; + } +} + +static void cfunc_sfv(void *param) +{ + ((rsp_cop2 *)param)->sfv(); +} + + +// SWV +// +// 31 25 20 15 10 6 0 +// -------------------------------------------------- +// | 111010 | BBBBB | TTTTT | 01010 | IIII | Offset | +// -------------------------------------------------- +// +// Stores the full 128-bit vector starting from vector byte index and wrapping to index 0 +// after byte index 15 + +void rsp_cop2_drc::swv() +{ + UINT32 op = m_rspcop2_state->op; + int dest = (op >> 16) & 0x1f; + int base = (op >> 21) & 0x1f; + int index = (op >> 7) & 0xf; + int offset = (op & 0x7f); + if (offset & 0x40) + { + offset |= 0xffffffc0; + } + + UINT32 ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 16) : (offset * 16); + int eaoffset = ea & 0xf; + ea &= ~0xf; + + int end = index + 16; + for (int i = index; i < end; i++) + { + m_rsp.DM_WRITE8(ea + (eaoffset & 0xf), VREG_B(dest, i & 0xf)); + eaoffset++; + } +} + +static void cfunc_swv(void *param) +{ + ((rsp_cop2 *)param)->swv(); +} + + +// STV +// +// 31 25 20 15 10 6 0 +// -------------------------------------------------- +// | 111010 | BBBBB | TTTTT | 01011 | IIII | Offset | +// -------------------------------------------------- +// +// Stores one element from maximum of 8 vectors, while incrementing element index + +void rsp_cop2_drc::stv() +{ + UINT32 op = m_rspcop2_state->op; + int dest = (op >> 16) & 0x1f; + int base = (op >> 21) & 0x1f; + int index = (op >> 7) & 0xf; + int offset = (op & 0x7f); + + if (offset & 0x40) + { + offset |= 0xffffffc0; + } + + int vs = dest; + int ve = dest + 8; + if (ve > 32) + { + ve = 32; + } + + int element = 8 - (index >> 1); + + UINT32 ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 16) : (offset * 16); + int eaoffset = (ea & 0xf) + (element * 2); + ea &= ~0xf; + + for (int i = vs; i < ve; i++) + { + m_rsp.DM_WRITE16(ea + (eaoffset & 0xf), VREG_S(i, element & 0x7)); + eaoffset += 2; + element++; + } +} + +static void cfunc_stv(void *param) +{ + ((rsp_cop2 *)param)->stv(); +} + +int rsp_cop2_drc::generate_swc2(drcuml_block *block, rsp_device::compiler_state *compiler, const opcode_desc *desc) +{ + UINT32 op = desc->opptr.l[0]; + int offset = (op & 0x7f); + if (offset & 0x40) + { + offset |= 0xffffffc0; + } + + switch ((op >> 11) & 0x1f) + { + case 0x00: /* SBV */ + UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_sbv, this); + return TRUE; + + case 0x01: /* SSV */ + UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_ssv, this); + return TRUE; + + case 0x02: /* SLV */ + UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_slv, this); + return TRUE; + + case 0x03: /* SDV */ + UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_sdv, this); + return TRUE; + + case 0x04: /* SQV */ + UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_sqv, this); + return TRUE; + + case 0x05: /* SRV */ + UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_srv, this); + return TRUE; + + case 0x06: /* SPV */ + UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_spv, this); + return TRUE; + + case 0x07: /* SUV */ + UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_suv, this); + return TRUE; + + case 0x08: /* SHV */ + UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_shv, this); + return TRUE; + + case 0x09: /* SFV */ + UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_sfv, this); + return TRUE; + + case 0x0a: /* SWV */ + UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_swv, this); + return TRUE; + + case 0x0b: /* STV */ + UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_stv, this); + return TRUE; + + default: + m_rsp.unimplemented_opcode(op); + return FALSE; + } + + return TRUE; +} + + +/*************************************************************************** + Vector Opcodes +***************************************************************************/ + +// VMULF +// +// 31 25 24 20 15 10 5 0 +// ------------------------------------------------------ +// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 000000 | +// ------------------------------------------------------ +// +// Multiplies signed integer by signed integer * 2 + +void rsp_cop2_drc::vmulf() +{ + CACHE_VALUES(); + + for (int i = 0; i < 8; i++) + { + UINT16 w1, w2; + GET_VS1(w1, i); + GET_VS2(w2, i); + INT32 s1 = (INT32)(INT16)w1; + INT32 s2 = (INT32)(INT16)w2; + + if (s1 == -32768 && s2 == -32768) + { + // overflow + ACCUM(i) = S64(0x0000800080000000); + m_vres[i] = 0x7fff; + } + else + { + ACCUM(i) = (INT64)(s1 * s2 * 2 + 0x8000) << 16; // rounding? + m_vres[i] = ACCUM_M(i); + } + } + WRITEBACK_RESULT(); +} + +static void cfunc_vmulf(void *param) +{ + ((rsp_cop2 *)param)->vmulf(); +} + + +// VMULU +// +// 31 25 24 20 15 10 5 0 +// ------------------------------------------------------ +// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 000001 | +// ------------------------------------------------------ +// + +void rsp_cop2_drc::vmulu() +{ + CACHE_VALUES(); + + for (int i = 0; i < 8; i++) + { + UINT16 w1, w2; + GET_VS1(w1, i); + GET_VS2(w2, i); + INT32 s1 = (INT32)(INT16)w1; + INT32 s2 = (INT32)(INT16)w2; + + INT64 r = s1 * s2 * 2 + 0x8000; // rounding? + + ACCUM(i) = r << 16; + + if (r < 0) + { + m_vres[i] = 0; + } + else if (((INT16)(ACCUM_H(i)) ^ (INT16)(ACCUM_M(i))) < 0) + { + m_vres[i] = -1; + } + else + { + m_vres[i] = ACCUM_M(i); + } + } + WRITEBACK_RESULT(); +} + +static void cfunc_vmulu(void *param) +{ + ((rsp_cop2 *)param)->vmulu(); +} + + +// VMUDL +// +// 31 25 24 20 15 10 5 0 +// ------------------------------------------------------ +// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 001101 | +// ------------------------------------------------------ +// +// Multiplies signed integer by unsigned fraction +// The result is added into accumulator +// The middle slice of accumulator is stored into destination element + +void rsp_cop2_drc::vmudl() +{ + CACHE_VALUES(); + + for (int i = 0; i < 8; i++) + { + UINT16 w1, w2; + GET_VS1(w1, i); + GET_VS2(w2, i); + UINT32 s1 = (UINT32)(UINT16)w1; + UINT32 s2 = (UINT32)(UINT16)w2; + + ACCUM(i) = s1 * s2; + + m_vres[i] = ACCUM_L(i); + } + WRITEBACK_RESULT(); +} + +static void cfunc_vmudl(void *param) +{ + ((rsp_cop2 *)param)->vmudl(); +} + + +// VMUDM +// +// 31 25 24 20 15 10 5 0 +// ------------------------------------------------------ +// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 000101 | +// ------------------------------------------------------ +// +// Multiplies signed integer by unsigned fraction +// The result is stored into accumulator +// The middle slice of accumulator is stored into destination element + +void rsp_cop2_drc::vmudm() +{ + CACHE_VALUES(); + + for (int i = 0; i < 8; i++) + { + UINT16 w1, w2; + GET_VS1(w1, i); + GET_VS2(w2, i); + INT32 s1 = (INT32)(INT16)w1; + INT32 s2 = (UINT16)w2; + + ACCUM(i) = (INT64)(s1 * s2) << 16; + + m_vres[i] = ACCUM_M(i); + } + WRITEBACK_RESULT(); +} + +static void cfunc_vmudm(void *param) +{ + ((rsp_cop2 *)param)->vmudm(); +} + + +// VMUDN +// +// 31 25 24 20 15 10 5 0 +// ------------------------------------------------------ +// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 000110 | +// ------------------------------------------------------ +// +// Multiplies unsigned fraction by signed integer +// The result is stored into accumulator +// The low slice of accumulator is stored into destination element + +void rsp_cop2_drc::vmudn() +{ + CACHE_VALUES(); + + for (int i = 0; i < 8; i++) + { + UINT16 w1, w2; + GET_VS1(w1, i); + GET_VS2(w2, i); + INT32 s1 = (UINT16)w1; + INT32 s2 = (INT32)(INT16)w2; + + INT32 r = s1 * s2; + + ACCUM(i) = (INT64)(s1 * s2) << 16; + + m_vres[i] = (UINT16)(r); + } + WRITEBACK_RESULT(); +} + +static void cfunc_vmudn(void *param) +{ + ((rsp_cop2 *)param)->vmudn(); +} + + +// VMUDH +// +// 31 25 24 20 15 10 5 0 +// ------------------------------------------------------ +// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 000111 | +// ------------------------------------------------------ +// +// Multiplies signed integer by signed integer +// The result is stored into highest 32 bits of accumulator, the low slice is zero +// The highest 32 bits of accumulator is saturated into destination element + +void rsp_cop2_drc::vmudh() +{ + CACHE_VALUES(); + + for (int i = 0; i < 8; i++) + { + UINT16 w1, w2; + GET_VS1(w1, i); + GET_VS2(w2, i); + INT32 s1 = (INT32)(INT16)w1; + INT32 s2 = (INT32)(INT16)w2; + + INT32 r = s1 * s2; + + ACCUM(i) = (INT64)r << 32; + + if (r < -32768) r = -32768; + if (r > 32767) r = 32767; + m_vres[i] = (INT16)(r); + } + WRITEBACK_RESULT(); +} + +static void cfunc_vmudh(void *param) +{ + ((rsp_cop2 *)param)->vmudh(); +} + + +// VMACF +// +// 31 25 24 20 15 10 5 0 +// ------------------------------------------------------ +// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 001000 | +// ------------------------------------------------------ +// + +void rsp_cop2_drc::vmacf() +{ + CACHE_VALUES(); + + for (int i = 0; i < 8; i++) + { + UINT16 w1, w2; + GET_VS1(w1, i); + GET_VS2(w2, i); + INT32 s1 = (INT32)(INT16)w1; + INT32 s2 = (INT32)(INT16)w2; + + ACCUM(i) += (INT64)(s1 * s2 * 2) << 16; + + m_vres[i] = SATURATE_ACCUM(i, 1, 0x8000, 0x7fff); + } + WRITEBACK_RESULT(); +} + +static void cfunc_vmacf(void *param) +{ + ((rsp_cop2 *)param)->vmacf(); +} + + +// VMACU +// +// 31 25 24 20 15 10 5 0 +// ------------------------------------------------------ +// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 001001 | +// ------------------------------------------------------ +// + +void rsp_cop2_drc::vmacu() +{ + CACHE_VALUES(); + + for (int i = 0; i < 8; i++) + { + UINT16 w1, w2; + GET_VS1(w1, i); + GET_VS2(w2, i); + INT32 s1 = (INT32)(INT16)w1; + INT32 s2 = (INT32)(INT16)w2; + + ACCUM(i) += (INT64)(s1 * s2 * 2) << 16; + + if ((INT16)ACCUM_H(i) < 0) + { + m_vres[i] = 0; + } + else + { + if (ACCUM_H(i) != 0) + { + m_vres[i] = (INT16)0xffff; + } + else + { + if ((INT16)ACCUM_M(i) < 0) + { + m_vres[i] = (INT16)0xffff; + } + else + { + m_vres[i] = ACCUM_M(i); + } + } + } + } + WRITEBACK_RESULT(); +} + +static void cfunc_vmacu(void *param) +{ + ((rsp_cop2 *)param)->vmacu(); +} + + +// VMADL +// +// 31 25 24 20 15 10 5 0 +// ------------------------------------------------------ +// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 001100 | +// ------------------------------------------------------ +// +// Multiplies unsigned fraction by unsigned fraction +// Adds the higher 16 bits of the 32-bit result to accumulator +// The low slice of accumulator is stored into destination element + +void rsp_cop2_drc::vmadl() +{ + CACHE_VALUES(); + + for (int i = 0; i < 8; i++) + { + UINT16 w1, w2; + GET_VS1(w1, i); + GET_VS2(w2, i); + UINT32 s1 = w1; + UINT32 s2 = w2; + + ACCUM(i) += (s1 * s2) & 0xffff0000; + + m_vres[i] = SATURATE_ACCUM(i, 0, 0x0000, 0xffff); + } + WRITEBACK_RESULT(); +} + +static void cfunc_vmadl(void *param) +{ + ((rsp_cop2 *)param)->vmadl(); +} + + +// VMADM +// + +void rsp_cop2_drc::vmadm() +{ + CACHE_VALUES(); + + for (int i = 0; i < 8; i++) + { + UINT16 w1, w2; + GET_VS1(w1, i); + GET_VS2(w2, i); + UINT32 s1 = (INT32)(INT16)w1; + UINT32 s2 = (UINT16)w2; + + ACCUM(i) += (INT64)(INT32)(s1 * s2) << 16; + + m_vres[i] = SATURATE_ACCUM(i, 1, 0x8000, 0x7fff); + } + WRITEBACK_RESULT(); +} + +static void cfunc_vmadm(void *param) +{ + ((rsp_cop2 *)param)->vmadm(); +} + + +// VMADN +// + +void rsp_cop2_drc::vmadn() +{ + CACHE_VALUES(); + + for (int i = 0; i < 8; i++) + { + UINT16 w1, w2; + GET_VS1(w1, i); + GET_VS2(w2, i); + INT32 s1 = (UINT16)w1; + INT32 s2 = (INT32)(INT16)w2; + + ACCUM(i) += (INT64)(s1 * s2) << 16; + + m_vres[i] = SATURATE_ACCUM(i, 0, 0x0000, 0xffff); + } + WRITEBACK_RESULT(); +} + +static void cfunc_vmadn(void *param) +{ + ((rsp_cop2 *)param)->vmadn(); +} + + +// VMADH +// +// 31 25 24 20 15 10 5 0 +// ------------------------------------------------------ +// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 001111 | +// ------------------------------------------------------ +// +// Multiplies signed integer by signed integer +// The result is added into highest 32 bits of accumulator, the low slice is zero +// The highest 32 bits of accumulator is saturated into destination element + +void rsp_cop2_drc::vmadh() +{ + CACHE_VALUES(); + + for (int i = 0; i < 8; i++) + { + INT16 w1, w2; + GET_VS1(w1, i); + GET_VS2(w2, i); + INT32 s1 = (INT32)(INT16)w1; + INT32 s2 = (INT32)(INT16)w2; + + ACCUM(i) += (INT64)(s1 * s2) << 32; + + m_vres[i] = SATURATE_ACCUM(i, 1, 0x8000, 0x7fff); + } + WRITEBACK_RESULT(); +} + +static void cfunc_vmadh(void *param) +{ + ((rsp_cop2 *)param)->vmadh(); +} + + +// VADD +// 31 25 24 20 15 10 5 0 +// ------------------------------------------------------ +// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 010000 | +// ------------------------------------------------------ +// +// Adds two vector registers and carry flag, the result is saturated to 32767 + +void rsp_cop2_drc::vadd() +{ + CACHE_VALUES(); + + for (int i = 0; i < 8; i++) + { + INT16 w1, w2; + GET_VS1(w1, i); + GET_VS2(w2, i); + INT32 s1 = (INT32)(INT16)w1; + INT32 s2 = (INT32)(INT16)w2; + INT32 r = s1 + s2 + (((CARRY_FLAG(i)) != 0) ? 1 : 0); + + SET_ACCUM_L((INT16)(r), i); + + if (r > 32767) r = 32767; + if (r < -32768) r = -32768; + m_vres[i] = (INT16)(r); + } + CLEAR_ZERO_FLAGS(); + CLEAR_CARRY_FLAGS(); + WRITEBACK_RESULT(); +} + +static void cfunc_vadd(void *param) +{ + ((rsp_cop2 *)param)->vadd(); +} + + +// VSUB +// +// 31 25 24 20 15 10 5 0 +// ------------------------------------------------------ +// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 010001 | +// ------------------------------------------------------ +// +// Subtracts two vector registers and carry flag, the result is saturated to -32768 +// TODO: check VS2REG == VDREG + +void rsp_cop2_drc::vsub() +{ + CACHE_VALUES(); + + for (int i = 0; i < 8; i++) + { + INT16 w1, w2; + GET_VS1(w1, i); + GET_VS2(w2, i); + INT32 s1 = (INT32)(INT16)w1; + INT32 s2 = (INT32)(INT16)w2; + INT32 r = s1 - s2 - (((CARRY_FLAG(i)) != 0) ? 1 : 0); + + SET_ACCUM_L((INT16)(r), i); + + if (r > 32767) r = 32767; + if (r < -32768) r = -32768; + + m_vres[i] = (INT16)(r); + } + CLEAR_ZERO_FLAGS(); + CLEAR_CARRY_FLAGS(); + WRITEBACK_RESULT(); +} + +static void cfunc_vsub(void *param) +{ + ((rsp_cop2 *)param)->vsub(); +} + + +// VABS +// +// 31 25 24 20 15 10 5 0 +// ------------------------------------------------------ +// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 010011 | +// ------------------------------------------------------ +// +// Changes the sign of source register 2 if source register 1 is negative and stores the result to destination register + +void rsp_cop2_drc::vabs() +{ + CACHE_VALUES(); + + for (int i = 0; i < 8; i++) + { + INT16 s1, s2; + GET_VS1(s1, i); + GET_VS2(s2, i); + + if (s1 < 0) + { + if (s2 == -32768) + { + m_vres[i] = 32767; + } + else + { + m_vres[i] = -s2; + } + } + else if (s1 > 0) + { + m_vres[i] = s2; + } + else + { + m_vres[i] = 0; + } + + SET_ACCUM_L(m_vres[i], i); + } + WRITEBACK_RESULT(); +} + +static void cfunc_vabs(void *param) +{ + ((rsp_cop2 *)param)->vabs(); +} + + +// VADDC +// +// 31 25 24 20 15 10 5 0 +// ------------------------------------------------------ +// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 010100 | +// ------------------------------------------------------ +// +// Adds two vector registers, the carry out is stored into carry register +// TODO: check VS2REG = VDREG + +void rsp_cop2_drc::vaddc() +{ + CACHE_VALUES(); + + CLEAR_ZERO_FLAGS(); + CLEAR_CARRY_FLAGS(); + + for (int i = 0; i < 8; i++) + { + INT16 w1, w2; + GET_VS1(w1, i); + GET_VS2(w2, i); + INT32 s1 = (UINT32)(UINT16)w1; + INT32 s2 = (UINT32)(UINT16)w2; + INT32 r = s1 + s2; + + m_vres[i] = (INT16)(r); + SET_ACCUM_L((INT16)r, i); + + if (r & 0xffff0000) + { + SET_CARRY_FLAG(i); + } + } + WRITEBACK_RESULT(); +} + +static void cfunc_vaddc(void *param) +{ + ((rsp_cop2 *)param)->vaddc(); +} + + +// VSUBC +// +// 31 25 24 20 15 10 5 0 +// ------------------------------------------------------ +// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 010101 | +// ------------------------------------------------------ +// +// Subtracts two vector registers, the carry out is stored into carry register +// TODO: check VS2REG = VDREG + +void rsp_cop2_drc::vsubc() +{ + CACHE_VALUES(); + + CLEAR_ZERO_FLAGS(); + CLEAR_CARRY_FLAGS(); + + for (int i = 0; i < 8; i++) + { + INT16 w1, w2; + GET_VS1(w1, i); + GET_VS2(w2, i); + INT32 s1 = (UINT32)(UINT16)w1; + INT32 s2 = (UINT32)(UINT16)w2; + INT32 r = s1 - s2; + + m_vres[i] = (INT16)(r); + SET_ACCUM_L((UINT16)r, i); + + if ((UINT16)(r) != 0) + { + SET_ZERO_FLAG(i); + } + if (r & 0xffff0000) + { + SET_CARRY_FLAG(i); + } + } + WRITEBACK_RESULT(); +} + +static void cfunc_vsubc(void *param) +{ + ((rsp_cop2 *)param)->vsubc(); +} + + +// VADDB +// +// 31 25 24 20 15 10 5 0 +// ------------------------------------------------------ +// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 010110 | +// ------------------------------------------------------ +// +// Adds two vector registers bytewise with rounding + +void rsp_cop2_drc::vaddb() +{ + CACHE_VALUES(); + const int round = (el == 0) ? 0 : (1 << (el - 1)); + + for (int i = 0; i < 8; i++) + { + UINT16 w1, w2; + GET_VS1(w1, i); + GET_VS2(w2, i); + + UINT8 hb1 = w1 >> 8; + UINT8 lb1 = w1 & 0xff; + UINT8 hb2 = w2 >> 8; + UINT8 lb2 = w2 & 0xff; + + UINT16 hs = hb1 + hb2 + round; + UINT16 ls = lb1 + lb2 + round; + + SET_ACCUM_L((hs << 8) | ls, i); + + hs >>= EL; + if (hs > 255) + { + hs = 255; + } + + ls >>= EL; + if (ls > 255) + { + ls = 255; + } + + m_vres[i] = 0; // VD writeback disabled on production hardware + // m_vres[i] = (hs << 8) | ls; + } + WRITEBACK_RESULT(); +} + +static void cfunc_vaddb(void *param) +{ + ((rsp_cop2 *)param)->vaddb(); +} + + +// VSAW +// +// 31 25 24 20 15 10 5 0 +// ------------------------------------------------------ +// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 011101 | +// ------------------------------------------------------ +// +// Stores high, middle or low slice of accumulator to destination vector + +void rsp_cop2_drc::vsaw() +{ + const int op = m_rspcop2_state->op; + const int vdreg = VDREG; + const int el = EL; + + switch (el) + { + case 0x08: // VSAWH + for (int i = 0; i < 8; i++) + { + W_VREG_S(vdreg, i) = ACCUM_H(i); + } + break; + case 0x09: // VSAWM + for (int i = 0; i < 8; i++) + { + W_VREG_S(vdreg, i) = ACCUM_M(i); + } + break; + case 0x0a: // VSAWL + for (int i = 0; i < 8; i++) + { + W_VREG_S(vdreg, i) = ACCUM_L(i); + } + break; + default: // Unsupported + { + for (int i = 0; i < 8; i++) + { + W_VREG_S(vdreg, i) = 0; + } + } + } +} + +static void cfunc_vsaw(void *param) +{ + ((rsp_cop2 *)param)->vsaw(); +} + + +// VLT +// +// 31 25 24 20 15 10 5 0 +// ------------------------------------------------------ +// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 100000 | +// ------------------------------------------------------ +// +// Sets compare flags if elements in VS1 are less than VS2 +// Moves the element in VS2 to destination vector + +void rsp_cop2_drc::vlt() +{ + CACHE_VALUES(); + + CLEAR_COMPARE_FLAGS(); + CLEAR_CLIP2_FLAGS(); + + for (int i = 0; i < 8; i++) + { + INT16 s1, s2; + GET_VS1(s1, i); + GET_VS2(s2, i); + + if (s1 < s2) + { + SET_COMPARE_FLAG(i); + } + else if (s1 == s2) + { + if (ZERO_FLAG(i) != 0 && CARRY_FLAG(i) != 0) + { + SET_COMPARE_FLAG(i); + } + } + + if (COMPARE_FLAG(i) != 0) + { + m_vres[i] = s1; + } + else + { + m_vres[i] = s2; + } + + SET_ACCUM_L(m_vres[i], i); + } + + CLEAR_ZERO_FLAGS(); + CLEAR_CARRY_FLAGS(); + WRITEBACK_RESULT(); +} + +static void cfunc_vlt(void *param) +{ + ((rsp_cop2 *)param)->vlt(); +} + + +// VEQ +// +// 31 25 24 20 15 10 5 0 +// ------------------------------------------------------ +// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 100001 | +// ------------------------------------------------------ +// +// Sets compare flags if elements in VS1 are equal with VS2 +// Moves the element in VS2 to destination vector + +void rsp_cop2_drc::veq() +{ + CACHE_VALUES(); + + CLEAR_COMPARE_FLAGS(); + CLEAR_CLIP2_FLAGS(); + + for (int i = 0; i < 8; i++) + { + INT16 s1, s2; + GET_VS1(s1, i); + GET_VS2(s2, i); + + if ((s1 == s2) && ZERO_FLAG(i) == 0) + { + SET_COMPARE_FLAG(i); + m_vres[i] = s1; + } + else + { + m_vres[i] = s2; + } + + SET_ACCUM_L(m_vres[i], i); + } + + CLEAR_ZERO_FLAGS(); + CLEAR_CARRY_FLAGS(); + WRITEBACK_RESULT(); +} + +static void cfunc_veq(void *param) +{ + ((rsp_cop2 *)param)->veq(); +} + + +// VNE +// +// 31 25 24 20 15 10 5 0 +// ------------------------------------------------------ +// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 100010 | +// ------------------------------------------------------ +// +// Sets compare flags if elements in VS1 are not equal with VS2 +// Moves the element in VS2 to destination vector + +void rsp_cop2_drc::vne() +{ + CACHE_VALUES(); + + CLEAR_COMPARE_FLAGS(); + CLEAR_CLIP2_FLAGS(); + + for (int i = 0; i < 8; i++) + { + INT16 s1, s2; + GET_VS1(s1, i); + GET_VS2(s2, i); + + if (s1 != s2 || ZERO_FLAG(i) != 0) + { + SET_COMPARE_FLAG(i); + m_vres[i] = s1; + } + else + { + m_vres[i] = s2; + } + + SET_ACCUM_L(m_vres[i], i); + } + + CLEAR_ZERO_FLAGS(); + CLEAR_CARRY_FLAGS(); + WRITEBACK_RESULT(); +} + +static void cfunc_vne(void *param) +{ + ((rsp_cop2 *)param)->vne(); +} + + +// VGE +// +// 31 25 24 20 15 10 5 0 +// ------------------------------------------------------ +// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 100011 | +// ------------------------------------------------------ +// +// Sets compare flags if elements in VS1 are greater or equal with VS2 +// Moves the element in VS2 to destination vector + +void rsp_cop2_drc::vge() +{ + CACHE_VALUES(); + + CLEAR_COMPARE_FLAGS(); + CLEAR_CLIP2_FLAGS(); + + for (int i = 0; i < 8; i++) + { + INT16 s1, s2; + GET_VS1(s1, i); + GET_VS2(s2, i); + if ((s1 == s2 && (ZERO_FLAG(i) == 0 || CARRY_FLAG(i) == 0)) || s1 > s2) + { + SET_COMPARE_FLAG(i); + m_vres[i] = s1; + } + else + { + m_vres[i] = s2; + } + + SET_ACCUM_L(m_vres[i], i); + } + + CLEAR_ZERO_FLAGS(); + CLEAR_CARRY_FLAGS(); + WRITEBACK_RESULT(); +} + +static void cfunc_vge(void *param) +{ + ((rsp_cop2 *)param)->vge(); +} + + +// VCL +// +// 31 25 24 20 15 10 5 0 +// ------------------------------------------------------ +// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 100100 | +// ------------------------------------------------------ +// +// Vector clip low + +void rsp_cop2_drc::vcl() +{ + CACHE_VALUES(); + + for (int i = 0; i < 8; i++) + { + INT16 s1, s2; + GET_VS1(s1, i); + GET_VS2(s2, i); + + if (CARRY_FLAG(i) != 0) + { + if (ZERO_FLAG(i) != 0) + { + if (COMPARE_FLAG(i) != 0) + { + SET_ACCUM_L(-(UINT16)s2, i); + } + else + { + SET_ACCUM_L(s1, i); + } + } + else + { + if (CLIP1_FLAG(i) != 0) + { + if (((UINT32)(UINT16)(s1) + (UINT32)(UINT16)(s2)) > 0x10000) + { + SET_ACCUM_L(s1, i); + CLEAR_COMPARE_FLAG(i); + } + else + { + SET_ACCUM_L(-((UINT16)s2), i); + SET_COMPARE_FLAG(i); + } + } + else + { + if (((UINT32)(UINT16)(s1) + (UINT32)(UINT16)(s2)) != 0) + { + SET_ACCUM_L(s1, i); + CLEAR_COMPARE_FLAG(i); + } + else + { + SET_ACCUM_L(-((UINT16)s2), i); + SET_COMPARE_FLAG(i); + } + } + } + } + else + { + if (ZERO_FLAG(i) != 0) + { + if (CLIP2_FLAG(i) != 0) + { + SET_ACCUM_L(s2, i); + } + else + { + SET_ACCUM_L(s1, i); + } + } + else + { + if (((INT32)(UINT16)s1 - (INT32)(UINT16)s2) >= 0) + { + SET_ACCUM_L(s2, i); + SET_CLIP2_FLAG(i); + } + else + { + SET_ACCUM_L(s1, i); + CLEAR_CLIP2_FLAG(i); + } + } + } + m_vres[i] = ACCUM_L(i); + } + CLEAR_ZERO_FLAGS(); + CLEAR_CARRY_FLAGS(); + CLEAR_CLIP1_FLAGS(); + WRITEBACK_RESULT(); +} + +static void cfunc_vcl(void *param) +{ + ((rsp_cop2 *)param)->vcl(); +} + + +// VCH +// +// 31 25 24 20 15 10 5 0 +// ------------------------------------------------------ +// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 100101 | +// ------------------------------------------------------ +// +// Vector clip high + +void rsp_cop2_drc::vch() +{ + CACHE_VALUES(); + + CLEAR_CARRY_FLAGS(); + CLEAR_COMPARE_FLAGS(); + CLEAR_CLIP1_FLAGS(); + CLEAR_ZERO_FLAGS(); + CLEAR_CLIP2_FLAGS(); + + UINT32 vce = 0; + for (int i = 0; i < 8; i++) + { + INT16 s1, s2; + GET_VS1(s1, i); + GET_VS2(s2, i); + + if ((s1 ^ s2) < 0) + { + vce = (s1 + s2 == -1); + SET_CARRY_FLAG(i); + if (s2 < 0) + { + SET_CLIP2_FLAG(i); + } + + if ((s1 + s2) <= 0) + { + SET_COMPARE_FLAG(i); + m_vres[i] = -((UINT16)s2); + } + else + { + m_vres[i] = s1; + } + + if ((s1 + s2) != 0 && s1 != ~s2) + { + SET_ZERO_FLAG(i); + } + }//sign + else + { + vce = 0; + if (s2 < 0) + { + SET_COMPARE_FLAG(i); + } + if ((s1 - s2) >= 0) + { + SET_CLIP2_FLAG(i); + m_vres[i] = s2; + } + else + { + m_vres[i] = s1; + } + + if ((s1 - s2) != 0 && s1 != ~s2) + { + SET_ZERO_FLAG(i); + } + } + if (vce) + { + SET_CLIP1_FLAG(i); + } + SET_ACCUM_L(m_vres[i], i); + } + WRITEBACK_RESULT(); +} + +static void cfunc_vch(void *param) +{ + ((rsp_cop2 *)param)->vch(); +} + + +// VCR +// +// 31 25 24 20 15 10 5 0 +// ------------------------------------------------------ +// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 100110 | +// ------------------------------------------------------ +// +// Vector clip reverse + +void rsp_cop2_drc::vcr() +{ + CACHE_VALUES(); + + CLEAR_CARRY_FLAGS(); + CLEAR_COMPARE_FLAGS(); + CLEAR_CLIP1_FLAGS(); + CLEAR_ZERO_FLAGS(); + CLEAR_CLIP2_FLAGS(); + + for (int i = 0; i < 8; i++) + { + INT16 s1, s2; + GET_VS1(s1, i); + GET_VS2(s2, i); + + if ((INT16)(s1 ^ s2) < 0) + { + if (s2 < 0) + { + SET_CLIP2_FLAG(i); + } + if ((s1 + s2) <= 0) + { + SET_ACCUM_L(~((UINT16)s2), i); + SET_COMPARE_FLAG(i); + } + else + { + SET_ACCUM_L(s1, i); + } + } + else + { + if (s2 < 0) + { + SET_COMPARE_FLAG(i); + } + if ((s1 - s2) >= 0) + { + SET_ACCUM_L(s2, i); + SET_CLIP2_FLAG(i); + } + else + { + SET_ACCUM_L(s1, i); + } + } + + m_vres[i] = ACCUM_L(i); + } + WRITEBACK_RESULT(); +} + +static void cfunc_vcr(void *param) +{ + ((rsp_cop2 *)param)->vcr(); +} + + +// VMRG +// +// 31 25 24 20 15 10 5 0 +// ------------------------------------------------------ +// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 100111 | +// ------------------------------------------------------ +// +// Merges two vectors according to compare flags + +void rsp_cop2_drc::vmrg() +{ + CACHE_VALUES(); + + for (int i = 0; i < 8; i++) + { + INT16 s1, s2; + GET_VS1(s1, i); + GET_VS2(s2, i); + if (COMPARE_FLAG(i) != 0) + { + m_vres[i] = s1; + } + else + { + m_vres[i] = s2; + } + + SET_ACCUM_L(m_vres[i], i); + } + WRITEBACK_RESULT(); +} + +static void cfunc_vmrg(void *param) +{ + ((rsp_cop2 *)param)->vmrg(); +} + + +// VAND +// +// 31 25 24 20 15 10 5 0 +// ------------------------------------------------------ +// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 101000 | +// ------------------------------------------------------ +// +// Bitwise AND of two vector registers + +void rsp_cop2_drc::vand() +{ + CACHE_VALUES(); + + for (int i = 0; i < 8; i++) + { + UINT16 s1, s2; + GET_VS1(s1, i); + GET_VS2(s2, i); + m_vres[i] = s1 & s2; + SET_ACCUM_L(m_vres[i], i); + } + WRITEBACK_RESULT(); +} + +static void cfunc_vand(void *param) +{ + ((rsp_cop2 *)param)->vand(); +} + + +// VNAND +// +// 31 25 24 20 15 10 5 0 +// ------------------------------------------------------ +// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 101001 | +// ------------------------------------------------------ +// +// Bitwise NOT AND of two vector registers + +void rsp_cop2_drc::vnand() +{ + CACHE_VALUES(); + + for (int i = 0; i < 8; i++) + { + UINT16 s1, s2; + GET_VS1(s1, i); + GET_VS2(s2, i); + m_vres[i] = ~((s1 & s2)); + SET_ACCUM_L(m_vres[i], i); + } + WRITEBACK_RESULT(); +} + +static void cfunc_vnand(void *param) +{ + ((rsp_cop2 *)param)->vnand(); +} + + +// VOR +// +// 31 25 24 20 15 10 5 0 +// ------------------------------------------------------ +// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 101010 | +// ------------------------------------------------------ +// +// Bitwise OR of two vector registers + +void rsp_cop2_drc::vor() +{ + CACHE_VALUES(); + + for (int i = 0; i < 8; i++) + { + UINT16 s1, s2; + GET_VS1(s1, i); + GET_VS2(s2, i); + m_vres[i] = s1 | s2; + SET_ACCUM_L(m_vres[i], i); + } + WRITEBACK_RESULT(); +} + +static void cfunc_vor(void *param) +{ + ((rsp_cop2 *)param)->vor(); +} + + +// VNOR +// +// 31 25 24 20 15 10 5 0 +// ------------------------------------------------------ +// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 101011 | +// ------------------------------------------------------ +// +// Bitwise NOT OR of two vector registers + +void rsp_cop2_drc::vnor() +{ + CACHE_VALUES(); + + for (int i = 0; i < 8; i++) + { + UINT16 s1, s2; + GET_VS1(s1, i); + GET_VS2(s2, i); + m_vres[i] = ~(s1 | s2); + SET_ACCUM_L(m_vres[i], i); + } + WRITEBACK_RESULT(); +} + +static void cfunc_vnor(void *param) +{ + ((rsp_cop2 *)param)->vnor(); +} + + +// VXOR +// +// 31 25 24 20 15 10 5 0 +// ------------------------------------------------------ +// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 101100 | +// ------------------------------------------------------ +// +// Bitwise XOR of two vector registers + +void rsp_cop2_drc::vxor() +{ + CACHE_VALUES(); + + for (int i = 0; i < 8; i++) + { + UINT16 s1, s2; + GET_VS1(s1, i); + GET_VS2(s2, i); + m_vres[i] = s1 ^ s2; + SET_ACCUM_L(m_vres[i], i); + } + WRITEBACK_RESULT(); +} + +static void cfunc_vxor(void *param) +{ + ((rsp_cop2 *)param)->vxor(); +} + + +// VNXOR +// +// 31 25 24 20 15 10 5 0 +// ------------------------------------------------------ +// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 101101 | +// ------------------------------------------------------ +// +// Bitwise NOT XOR of two vector registers + +void rsp_cop2_drc::vnxor() +{ + CACHE_VALUES(); + + for (int i = 0; i < 8; i++) + { + UINT16 s1, s2; + GET_VS1(s1, i); + GET_VS2(s2, i); + m_vres[i] = ~(s1 ^ s2); + SET_ACCUM_L(m_vres[i], i); + } + WRITEBACK_RESULT(); +} + +static void cfunc_vnxor(void *param) +{ + ((rsp_cop2 *)param)->vnxor(); +} + + +// VRCP +// +// 31 25 24 20 15 10 5 0 +// ------------------------------------------------------ +// | 010010 | 1 | EEEE | SSSSS | ?FFFF | DDDDD | 110000 | +// ------------------------------------------------------ +// +// Calculates reciprocal + +void rsp_cop2_drc::vrcp() +{ + CACHE_VALUES(); + + INT32 shifter = 0; + INT32 rec = (INT16)(VREG_S(vs2reg, el & 7)); + INT32 datainput = (rec < 0) ? (-rec) : rec; + if (datainput) + { + for (int i = 0; i < 32; i++) + { + if (datainput & (1 << ((~i) & 0x1f))) + { + shifter = i; + break; + } + } + } + else + { + shifter = 0x10; + } + + INT32 address = ((datainput << shifter) & 0x7fc00000) >> 22; + INT32 fetchval = rsp_divtable[address]; + INT32 temp = (0x40000000 | (fetchval << 14)) >> ((~shifter) & 0x1f); + if (rec < 0) + { + temp = ~temp; + } + if (!rec) + { + temp = 0x7fffffff; + } + else if (rec == 0xffff8000) + { + temp = 0xffff0000; + } + rec = temp; + + m_reciprocal_res = rec; + m_dp_allowed = 0; + + W_VREG_S(vdreg, vs1reg & 7) = (UINT16)rec; + for (int i = 0; i < 8; i++) + { + SET_ACCUM_L(VREG_S(vs2reg, VEC_EL_2(el, i)), i); + } +} + +static void cfunc_vrcp(void *param) +{ + ((rsp_cop2 *)param)->vrcp(); +} + + +// VRCPL +// +// 31 25 24 20 15 10 5 0 +// ------------------------------------------------------ +// | 010010 | 1 | EEEE | SSSSS | ?FFFF | DDDDD | 110001 | +// ------------------------------------------------------ +// +// Calculates reciprocal low part + +void rsp_cop2_drc::vrcpl() +{ + CACHE_VALUES(); + + INT32 shifter = 0; + INT32 rec = (INT16)VREG_S(vs2reg, el & 7); + INT32 datainput = rec; + + if (m_dp_allowed) + { + rec = (rec & 0x0000ffff) | m_reciprocal_high; + datainput = rec; + + if (rec < 0) + { + if (rec < -32768) + { + datainput = ~datainput; + } + else + { + datainput = -datainput; + } + } + } + else if (datainput < 0) + { + datainput = -datainput; + + shifter = 0x10; + } + + if (datainput) + { + for (int i = 0; i < 32; i++) + { + if (datainput & (1 << ((~i) & 0x1f))) + { + shifter = i; + break; + } + } + } + + UINT32 address = (datainput << shifter) >> 22; + INT32 fetchval = rsp_divtable[address & 0x1ff]; + INT32 temp = (0x40000000 | (fetchval << 14)) >> ((~shifter) & 0x1f); + temp ^= rec >> 31; + + if (!rec) + { + temp = 0x7fffffff; + } + else if (rec == 0xffff8000) + { + temp = 0xffff0000; + } + rec = temp; + + m_reciprocal_res = rec; + m_dp_allowed = 0; + + W_VREG_S(vdreg, vs1reg & 7) = (UINT16)rec; + + for (int i = 0; i < 8; i++) + { + SET_ACCUM_L(VREG_S(vs2reg, VEC_EL_2(el, i)), i); + } +} + +static void cfunc_vrcpl(void *param) +{ + ((rsp_cop2 *)param)->vrcpl(); +} + + +// VRCPH +// +// 31 25 24 20 15 10 5 0 +// ------------------------------------------------------ +// | 010010 | 1 | EEEE | SSSSS | ?FFFF | DDDDD | 110010 | +// ------------------------------------------------------ +// +// Calculates reciprocal high part + +void rsp_cop2_drc::vrcph() +{ + CACHE_VALUES(); + + m_reciprocal_high = (VREG_S(vs2reg, el & 7)) << 16; + m_dp_allowed = 1; + + for (int i = 0; i < 8; i++) + { + SET_ACCUM_L(VREG_S(vs2reg, VEC_EL_2(el, i)), i); + } + + W_VREG_S(vdreg, vs1reg & 7) = (INT16)(m_reciprocal_res >> 16); +} + +static void cfunc_vrcph(void *param) +{ + ((rsp_cop2 *)param)->vrcph(); +} + + +// VMOV +// +// 31 25 24 20 15 10 5 0 +// ------------------------------------------------------ +// | 010010 | 1 | EEEE | SSSSS | ?FFFF | DDDDD | 110011 | +// ------------------------------------------------------ +// +// Moves element from vector to destination vector + +void rsp_cop2_drc::vmov() +{ + CACHE_VALUES(); + + W_VREG_S(vdreg, vs1reg & 7) = VREG_S(vs2reg, el & 7); + for (int i = 0; i < 8; i++) + { + SET_ACCUM_L(VREG_S(vs2reg, VEC_EL_2(el, i)), i); + } +} + +static void cfunc_vmov(void *param) +{ + ((rsp_cop2 *)param)->vmov(); +} + + +// VRSQ +// +// 31 25 24 20 15 10 5 0 +// ------------------------------------------------------ +// | 010010 | 1 | EEEE | SSSSS | ?FFFF | DDDDD | 110100 | +// ------------------------------------------------------ +// +// Calculates reciprocal square-root + +void rsp_cop2_drc::vrsq() +{ + CACHE_VALUES(); + + INT32 shifter = 0; + INT32 rec = (INT16)VREG_S(vs2reg, el & 7); + INT32 datainput = (rec < 0) ? (-rec) : (rec); + + if (rec < 0) + { + if (rec < -32768) + { + datainput = ~datainput; + } + else + { + datainput = -datainput; + } + } + + if (datainput) + { + for (int i = 0; i < 32; i++) + { + if (datainput & (1 << ((~i) & 0x1f))) + { + shifter = i; + break; + } + } + } + else + { + shifter = 0; + } + + INT32 address = ((datainput << shifter) & 0x7fc00000) >> 22; + address = ((address | 0x200) & 0x3fe) | (shifter & 1); + + INT32 fetchval = rsp_divtable[address]; + INT32 temp = (0x40000000 | (fetchval << 14)) >> (((~shifter) & 0x1f) >> 1); + if (rec < 0) + { + temp = ~temp; + } + if (!rec) + { + temp = 0x7fffffff; + } + else if (rec == 0xffff8000) + { + temp = 0xffff0000; + } + rec = temp; + + if (rec < 0) + { + if (m_dp_allowed) + { + if (rec < -32768) + { + datainput = ~datainput; + } + else + { + datainput = -datainput; + } + } + else + { + datainput = -datainput; + } + } + + if (datainput) + { + for (int i = 0; i < 32; i++) + { + if (datainput & (1 << ((~i) & 0x1f))) + { + shifter = i; + break; + } + } + } + else + { + shifter = 0; + } + + address = ((datainput << shifter) & 0x7fc00000) >> 22; + address = ((address | 0x200) & 0x3fe) | (shifter & 1); + + fetchval = rsp_divtable[address]; + temp = (0x40000000 | (fetchval << 14)) >> (((~shifter) & 0x1f) >> 1); + if (rec < 0) + { + temp = ~temp; + } + if (!rec) + { + temp = 0x7fff; + } + else if (rec == 0xffff8000) + { + temp = 0x0000; + } + rec = temp; + + W_VREG_S(vdreg, vs1reg & 7) = (UINT16)rec; + for (int i = 0; i < 8; i++) + { + SET_ACCUM_L(VREG_S(vs2reg, VEC_EL_2(el, i)), i); + } +} + +static void cfunc_vrsq(void *param) +{ + ((rsp_cop2 *)param)->vrsq(); +} + + +// VRSQL +// +// 31 25 24 20 15 10 5 0 +// ------------------------------------------------------ +// | 010010 | 1 | EEEE | SSSSS | ?FFFF | DDDDD | 110101 | +// ------------------------------------------------------ +// +// Calculates reciprocal square-root low part + +void rsp_cop2_drc::vrsql() +{ + CACHE_VALUES(); + + INT32 shifter = 0; + INT32 rec = (INT16)VREG_S(vs2reg, el & 7); + INT32 datainput = rec; + + if (m_dp_allowed) + { + rec = (rec & 0x0000ffff) | m_reciprocal_high; + datainput = rec; + + if (rec < 0) + { + if (rec < -32768) + { + datainput = ~datainput; + } + else + { + datainput = -datainput; + } + } + } + else if (datainput < 0) + { + datainput = -datainput; + + shifter = 0x10; + } + + if (datainput) + { + for (int i = 0; i < 32; i++) + { + if (datainput & (1 << ((~i) & 0x1f))) + { + shifter = i; + break; + } + } + } + + INT32 address = ((datainput << shifter) & 0x7fc00000) >> 22; + address = ((address | 0x200) & 0x3fe) | (shifter & 1); + + INT32 fetchval = rsp_divtable[address]; + INT32 temp = (0x40000000 | (fetchval << 14)) >> (((~shifter) & 0x1f) >> 1); + temp ^= rec >> 31; + + if (!rec) + { + temp = 0x7fffffff; + } + else if (rec == 0xffff8000) + { + temp = 0xffff0000; + } + rec = temp; + + m_reciprocal_res = rec; + m_dp_allowed = 0; + + W_VREG_S(vdreg, vs1reg & 7) = (UINT16)(rec & 0xffff); + for (int i = 0; i < 8; i++) + { + SET_ACCUM_L(VREG_S(vs2reg, VEC_EL_2(el, i)), i); + } +} + +static void cfunc_vrsql(void *param) +{ + ((rsp_cop2 *)param)->vrsql(); +} + + +// VRSQH +// +// 31 25 24 20 15 10 5 0 +// ------------------------------------------------------ +// | 010010 | 1 | EEEE | SSSSS | ?FFFF | DDDDD | 110110 | +// ------------------------------------------------------ +// +// Calculates reciprocal square-root high part + +void rsp_cop2_drc::vrsqh() +{ + CACHE_VALUES(); + + m_reciprocal_high = (VREG_S(vs2reg, el & 7)) << 16; + m_dp_allowed = 1; + + for (int i = 0; i < 8; i++) + { + SET_ACCUM_L(VREG_S(vs2reg, VEC_EL_2(el, i)), i); + } + + W_VREG_S(vdreg, vs1reg & 7) = (INT16)(m_reciprocal_res >> 16); // store high part +} + +static void cfunc_vrsqh(void *param) +{ + ((rsp_cop2 *)param)->vrsqh(); +} + + +/*------------------------------------------------- + generate_vector_opcode - generate code for a + vector opcode +-------------------------------------------------*/ + +int rsp_cop2_drc::generate_vector_opcode(drcuml_block *block, rsp_device::compiler_state *compiler, const opcode_desc *desc) +{ + UINT32 op = desc->opptr.l[0]; + // Opcode legend: + // E = VS2 element type + // S = VS1, Source vector 1 + // T = VS2, Source vector 2 + // D = Destination vector + + switch (op & 0x3f) + { + case 0x00: /* VMULF */ + UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_vmulf, this); + return TRUE; + + case 0x01: /* VMULU */ + UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_vmulu, this); + return TRUE; + + case 0x04: /* VMUDL */ + UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_vmudl, this); + return TRUE; + + case 0x05: /* VMUDM */ + UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_vmudm, this); + return TRUE; + + case 0x06: /* VMUDN */ + UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_vmudn, this); + return TRUE; + + case 0x07: /* VMUDH */ + UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_vmudh, this); + return TRUE; + + case 0x08: /* VMACF */ + UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_vmacf, this); + return TRUE; + + case 0x09: /* VMACU */ + UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_vmacu, this); + return TRUE; + + case 0x0c: /* VMADL */ + UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_vmadl, this); + return TRUE; + + case 0x0d: /* VMADM */ + UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_vmadm, this); + return TRUE; + + case 0x0e: /* VMADN */ + UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_vmadn, this); + return TRUE; + + case 0x0f: /* VMADH */ + UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_vmadh, this); + return TRUE; + + case 0x10: /* VADD */ + UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_vadd, this); + return TRUE; + + case 0x11: /* VSUB */ + UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_vsub, this); + return TRUE; + + case 0x13: /* VABS */ + UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_vabs, this); + return TRUE; + + case 0x14: /* VADDC */ + UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_vaddc, this); + return TRUE; + + case 0x15: /* VSUBC */ + UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_vsubc, this); + return TRUE; + + case 0x16: /* VADDB */ + UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_vaddb, this); + return TRUE; + + case 0x17: /* VSUBB (reserved, functionally identical to VADDB) */ + UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_vaddb, this); + return TRUE; + + case 0x18: /* VACCB (reserved, functionally identical to VADDB) */ + UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_vaddb, this); + return TRUE; + + case 0x19: /* VSUCB (reserved, functionally identical to VADDB) */ + UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_vaddb, this); + return TRUE; + + case 0x1d: /* VSAW */ + UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_vsaw, this); + return TRUE; + + case 0x20: /* VLT */ + UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_vlt, this); + return TRUE; + + case 0x21: /* VEQ */ + UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_veq, this); + return TRUE; + + case 0x22: /* VNE */ + UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_vne, this); + return TRUE; + + case 0x23: /* VGE */ + UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_vge, this); + return TRUE; + + case 0x24: /* VCL */ + UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_vcl, this); + return TRUE; + + case 0x25: /* VCH */ + UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_vch, this); + return TRUE; + + case 0x26: /* VCR */ + UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_vcr, this); + return TRUE; + + case 0x27: /* VMRG */ + UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_vmrg, this); + return TRUE; + + case 0x28: /* VAND */ + UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_vand, this); + return TRUE; + + case 0x29: /* VNAND */ + UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_vnand, this); + return TRUE; + + case 0x2a: /* VOR */ + UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_vor, this); + return TRUE; + + case 0x2b: /* VNOR */ + UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_vnor, this); + return TRUE; + + case 0x2c: /* VXOR */ + UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_vxor, this); + return TRUE; + + case 0x2d: /* VNXOR */ + UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_vnxor, this); + return TRUE; + + case 0x30: /* VRCP */ + UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_vrcp, this); + return TRUE; + + case 0x31: /* VRCPL */ + UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_vrcpl, this); + return TRUE; + + case 0x32: /* VRCPH */ + UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_vrcph, this); + return TRUE; + + case 0x33: /* VMOV */ + UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_vmov, this); + return TRUE; + + case 0x34: /* VRSQ */ + UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_vrsq, this); + return TRUE; + + case 0x35: /* VRSQL */ + UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_vrsql, this); + return TRUE; + + case 0x36: /* VRSQH */ + UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_vrsqh, this); + return TRUE; + + case 0x37: /* VNOP */ + case 0x3F: /* VNULL */ + return TRUE; + + default: + UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, unimplemented_opcode, &m_rsp); + return FALSE; + } +} + + +/*************************************************************************** + Vector Flag Reading/Writing +***************************************************************************/ + +void rsp_cop2_drc::mfc2() +{ + UINT32 op = m_rspcop2_state->op; + int el = (op >> 7) & 0xf; + + UINT16 b1 = VREG_B(VS1REG, (el+0) & 0xf); + UINT16 b2 = VREG_B(VS1REG, (el+1) & 0xf); + if (RTREG) RTVAL = (INT32)(INT16)((b1 << 8) | (b2)); +} + +static void cfunc_mfc2(void *param) +{ + ((rsp_cop2 *)param)->mfc2(); +} + +void rsp_cop2_drc::cfc2() +{ + UINT32 op = m_rspcop2_state->op; + if (RTREG) + { + switch(RDREG) + { + case 0: + RTVAL = ((CARRY_FLAG(0) & 1) << 0) | + ((CARRY_FLAG(1) & 1) << 1) | + ((CARRY_FLAG(2) & 1) << 2) | + ((CARRY_FLAG(3) & 1) << 3) | + ((CARRY_FLAG(4) & 1) << 4) | + ((CARRY_FLAG(5) & 1) << 5) | + ((CARRY_FLAG(6) & 1) << 6) | + ((CARRY_FLAG(7) & 1) << 7) | + ((ZERO_FLAG(0) & 1) << 8) | + ((ZERO_FLAG(1) & 1) << 9) | + ((ZERO_FLAG(2) & 1) << 10) | + ((ZERO_FLAG(3) & 1) << 11) | + ((ZERO_FLAG(4) & 1) << 12) | + ((ZERO_FLAG(5) & 1) << 13) | + ((ZERO_FLAG(6) & 1) << 14) | + ((ZERO_FLAG(7) & 1) << 15); + if (RTVAL & 0x8000) RTVAL |= 0xffff0000; + break; + case 1: + RTVAL = ((COMPARE_FLAG(0) & 1) << 0) | + ((COMPARE_FLAG(1) & 1) << 1) | + ((COMPARE_FLAG(2) & 1) << 2) | + ((COMPARE_FLAG(3) & 1) << 3) | + ((COMPARE_FLAG(4) & 1) << 4) | + ((COMPARE_FLAG(5) & 1) << 5) | + ((COMPARE_FLAG(6) & 1) << 6) | + ((COMPARE_FLAG(7) & 1) << 7) | + ((CLIP2_FLAG(0) & 1) << 8) | + ((CLIP2_FLAG(1) & 1) << 9) | + ((CLIP2_FLAG(2) & 1) << 10) | + ((CLIP2_FLAG(3) & 1) << 11) | + ((CLIP2_FLAG(4) & 1) << 12) | + ((CLIP2_FLAG(5) & 1) << 13) | + ((CLIP2_FLAG(6) & 1) << 14) | + ((CLIP2_FLAG(7) & 1) << 15); + if (RTVAL & 0x8000) RTVAL |= 0xffff0000; + break; + case 2: + RTVAL = ((CLIP1_FLAG(0) & 1) << 0) | + ((CLIP1_FLAG(1) & 1) << 1) | + ((CLIP1_FLAG(2) & 1) << 2) | + ((CLIP1_FLAG(3) & 1) << 3) | + ((CLIP1_FLAG(4) & 1) << 4) | + ((CLIP1_FLAG(5) & 1) << 5) | + ((CLIP1_FLAG(6) & 1) << 6) | + ((CLIP1_FLAG(7) & 1) << 7); + break; + } + } +} + +static void cfunc_cfc2(void *param) +{ + ((rsp_cop2 *)param)->cfc2(); +} + + +void rsp_cop2_drc::mtc2() +{ + UINT32 op = m_rspcop2_state->op; + int el = (op >> 7) & 0xf; + VREG_B(VS1REG, (el+0) & 0xf) = (RTVAL >> 8) & 0xff; + VREG_B(VS1REG, (el+1) & 0xf) = (RTVAL >> 0) & 0xff; +} + +static void cfunc_mtc2(void *param) +{ + ((rsp_cop2 *)param)->mtc2(); +} + + +void rsp_cop2_drc::ctc2() +{ + UINT32 op = m_rspcop2_state->op; + switch(RDREG) + { + case 0: + CLEAR_CARRY_FLAGS(); + CLEAR_ZERO_FLAGS(); + m_vflag[0][0] = ((RTVAL >> 0) & 1) ? 0xffff : 0; + m_vflag[0][1] = ((RTVAL >> 1) & 1) ? 0xffff : 0; + m_vflag[0][2] = ((RTVAL >> 2) & 1) ? 0xffff : 0; + m_vflag[0][3] = ((RTVAL >> 3) & 1) ? 0xffff : 0; + m_vflag[0][4] = ((RTVAL >> 4) & 1) ? 0xffff : 0; + m_vflag[0][5] = ((RTVAL >> 5) & 1) ? 0xffff : 0; + m_vflag[0][6] = ((RTVAL >> 6) & 1) ? 0xffff : 0; + m_vflag[0][7] = ((RTVAL >> 7) & 1) ? 0xffff : 0; + if (RTVAL & (1 << 0)) { SET_CARRY_FLAG(0); } + if (RTVAL & (1 << 1)) { SET_CARRY_FLAG(1); } + if (RTVAL & (1 << 2)) { SET_CARRY_FLAG(2); } + if (RTVAL & (1 << 3)) { SET_CARRY_FLAG(3); } + if (RTVAL & (1 << 4)) { SET_CARRY_FLAG(4); } + if (RTVAL & (1 << 5)) { SET_CARRY_FLAG(5); } + if (RTVAL & (1 << 6)) { SET_CARRY_FLAG(6); } + if (RTVAL & (1 << 7)) { SET_CARRY_FLAG(7); } + m_vflag[3][0] = ((RTVAL >> 8) & 1) ? 0xffff : 0; + m_vflag[3][1] = ((RTVAL >> 9) & 1) ? 0xffff : 0; + m_vflag[3][2] = ((RTVAL >> 10) & 1) ? 0xffff : 0; + m_vflag[3][3] = ((RTVAL >> 11) & 1) ? 0xffff : 0; + m_vflag[3][4] = ((RTVAL >> 12) & 1) ? 0xffff : 0; + m_vflag[3][5] = ((RTVAL >> 13) & 1) ? 0xffff : 0; + m_vflag[3][6] = ((RTVAL >> 14) & 1) ? 0xffff : 0; + m_vflag[3][7] = ((RTVAL >> 15) & 1) ? 0xffff : 0; + if (RTVAL & (1 << 8)) { SET_ZERO_FLAG(0); } + if (RTVAL & (1 << 9)) { SET_ZERO_FLAG(1); } + if (RTVAL & (1 << 10)) { SET_ZERO_FLAG(2); } + if (RTVAL & (1 << 11)) { SET_ZERO_FLAG(3); } + if (RTVAL & (1 << 12)) { SET_ZERO_FLAG(4); } + if (RTVAL & (1 << 13)) { SET_ZERO_FLAG(5); } + if (RTVAL & (1 << 14)) { SET_ZERO_FLAG(6); } + if (RTVAL & (1 << 15)) { SET_ZERO_FLAG(7); } + break; + case 1: + CLEAR_COMPARE_FLAGS(); + CLEAR_CLIP2_FLAGS(); + m_vflag[1][0] = ((RTVAL >> 0) & 1) ? 0xffff : 0; + m_vflag[1][1] = ((RTVAL >> 1) & 1) ? 0xffff : 0; + m_vflag[1][2] = ((RTVAL >> 2) & 1) ? 0xffff : 0; + m_vflag[1][3] = ((RTVAL >> 3) & 1) ? 0xffff : 0; + m_vflag[1][4] = ((RTVAL >> 4) & 1) ? 0xffff : 0; + m_vflag[1][5] = ((RTVAL >> 5) & 1) ? 0xffff : 0; + m_vflag[1][6] = ((RTVAL >> 6) & 1) ? 0xffff : 0; + m_vflag[1][7] = ((RTVAL >> 7) & 1) ? 0xffff : 0; + if (RTVAL & (1 << 0)) { SET_COMPARE_FLAG(0); } + if (RTVAL & (1 << 1)) { SET_COMPARE_FLAG(1); } + if (RTVAL & (1 << 2)) { SET_COMPARE_FLAG(2); } + if (RTVAL & (1 << 3)) { SET_COMPARE_FLAG(3); } + if (RTVAL & (1 << 4)) { SET_COMPARE_FLAG(4); } + if (RTVAL & (1 << 5)) { SET_COMPARE_FLAG(5); } + if (RTVAL & (1 << 6)) { SET_COMPARE_FLAG(6); } + if (RTVAL & (1 << 7)) { SET_COMPARE_FLAG(7); } + m_vflag[4][0] = ((RTVAL >> 8) & 1) ? 0xffff : 0; + m_vflag[4][1] = ((RTVAL >> 9) & 1) ? 0xffff : 0; + m_vflag[4][2] = ((RTVAL >> 10) & 1) ? 0xffff : 0; + m_vflag[4][3] = ((RTVAL >> 11) & 1) ? 0xffff : 0; + m_vflag[4][4] = ((RTVAL >> 12) & 1) ? 0xffff : 0; + m_vflag[4][5] = ((RTVAL >> 13) & 1) ? 0xffff : 0; + m_vflag[4][6] = ((RTVAL >> 14) & 1) ? 0xffff : 0; + m_vflag[4][7] = ((RTVAL >> 15) & 1) ? 0xffff : 0; + if (RTVAL & (1 << 8)) { SET_CLIP2_FLAG(0); } + if (RTVAL & (1 << 9)) { SET_CLIP2_FLAG(1); } + if (RTVAL & (1 << 10)) { SET_CLIP2_FLAG(2); } + if (RTVAL & (1 << 11)) { SET_CLIP2_FLAG(3); } + if (RTVAL & (1 << 12)) { SET_CLIP2_FLAG(4); } + if (RTVAL & (1 << 13)) { SET_CLIP2_FLAG(5); } + if (RTVAL & (1 << 14)) { SET_CLIP2_FLAG(6); } + if (RTVAL & (1 << 15)) { SET_CLIP2_FLAG(7); } + break; + case 2: + CLEAR_CLIP1_FLAGS(); + m_vflag[2][0] = ((RTVAL >> 0) & 1) ? 0xffff : 0; + m_vflag[2][1] = ((RTVAL >> 1) & 1) ? 0xffff : 0; + m_vflag[2][2] = ((RTVAL >> 2) & 1) ? 0xffff : 0; + m_vflag[2][3] = ((RTVAL >> 3) & 1) ? 0xffff : 0; + m_vflag[2][4] = ((RTVAL >> 4) & 1) ? 0xffff : 0; + m_vflag[2][5] = ((RTVAL >> 5) & 1) ? 0xffff : 0; + m_vflag[2][6] = ((RTVAL >> 6) & 1) ? 0xffff : 0; + m_vflag[2][7] = ((RTVAL >> 7) & 1) ? 0xffff : 0; + if (RTVAL & (1 << 0)) { SET_CLIP1_FLAG(0); } + if (RTVAL & (1 << 1)) { SET_CLIP1_FLAG(1); } + if (RTVAL & (1 << 2)) { SET_CLIP1_FLAG(2); } + if (RTVAL & (1 << 3)) { SET_CLIP1_FLAG(3); } + if (RTVAL & (1 << 4)) { SET_CLIP1_FLAG(4); } + if (RTVAL & (1 << 5)) { SET_CLIP1_FLAG(5); } + if (RTVAL & (1 << 6)) { SET_CLIP1_FLAG(6); } + if (RTVAL & (1 << 7)) { SET_CLIP1_FLAG(7); } + break; + } +} + +static void cfunc_ctc2(void *param) +{ + ((rsp_cop2 *)param)->ctc2(); +} + +/*************************************************************************** + COP2 Opcode Compilation +***************************************************************************/ + +int rsp_cop2_drc::generate_cop2(drcuml_block *block, rsp_device::compiler_state *compiler, const opcode_desc *desc) +{ + UINT32 op = desc->opptr.l[0]; + UINT8 opswitch = RSREG; + + switch (opswitch) + { + case 0x00: /* MFCz */ + if (RTREG != 0) + { + UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_mfc2, this); // callc mfc2 + } + return TRUE; + + case 0x02: /* CFCz */ + if (RTREG != 0) + { + UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_cfc2, this); // callc cfc2 + } + return TRUE; + + case 0x04: /* MTCz */ + UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_mtc2, this); // callc mtc2 + return TRUE; + + case 0x06: /* CTCz */ + UML_MOV(block, mem(&m_rspcop2_state->op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_ctc2, this); // callc ctc2 + return TRUE; + + case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17: + case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f: + return generate_vector_opcode(block, compiler, desc); + } + return FALSE; +} diff --git a/src/devices/cpu/rsp/rspcp2d.h b/src/devices/cpu/rsp/rspcp2d.h new file mode 100644 index 00000000000..831773d5c66 --- /dev/null +++ b/src/devices/cpu/rsp/rspcp2d.h @@ -0,0 +1,109 @@ +// license:BSD-3-Clause +// copyright-holders:Ryan Holtz +/*************************************************************************** + + rspcp2d.h + + Interface file for Reality Signal Processor (RSP) vector extensions + using Universal Machine Language (UML) dynamic recompilation. + +***************************************************************************/ + +#pragma once + +#ifndef __RSPCP2D_H__ +#define __RSPCP2D_H__ + +#include "cpu/drcuml.h" +#include "rsp.h" +#include "rspcp2.h" + +class rsp_cop2_drc : public rsp_cop2 +{ + friend class rsp_device; + + rsp_cop2_drc(rsp_device &rsp, running_machine &machine) : rsp_cop2(rsp, machine) { } + + virtual int generate_cop2(drcuml_block *block, rsp_device::compiler_state *compiler, const opcode_desc *desc); + virtual int generate_lwc2(drcuml_block *block, rsp_device::compiler_state *compiler, const opcode_desc *desc); + virtual int generate_swc2(drcuml_block *block, rsp_device::compiler_state *compiler, const opcode_desc *desc); + + virtual void state_string_export(const int index, std::string &str); + + void cfunc_unimplemented_opcode(); + +public: + virtual void lbv(); + virtual void lsv(); + virtual void llv(); + virtual void ldv(); + virtual void lqv(); + virtual void lrv(); + virtual void lpv(); + virtual void luv(); + virtual void lhv(); + virtual void lfv(); + virtual void lwv(); + virtual void ltv(); + virtual void sbv(); + virtual void ssv(); + virtual void slv(); + virtual void sdv(); + virtual void sqv(); + virtual void srv(); + virtual void spv(); + virtual void suv(); + virtual void shv(); + virtual void sfv(); + virtual void swv(); + virtual void stv(); + virtual void vmulf(); + virtual void vmulu(); + virtual void vmudl(); + virtual void vmudm(); + virtual void vmudn(); + virtual void vmudh(); + virtual void vmacf(); + virtual void vmacu(); + virtual void vmadl(); + virtual void vmadm(); + virtual void vmadn(); + virtual void vmadh(); + virtual void vadd(); + virtual void vsub(); + virtual void vabs(); + virtual void vaddc(); + virtual void vsubc(); + virtual void vaddb(); + virtual void vsaw(); + virtual void vlt(); + virtual void veq(); + virtual void vne(); + virtual void vge(); + virtual void vcl(); + virtual void vch(); + virtual void vcr(); + virtual void vmrg(); + virtual void vand(); + virtual void vnand(); + virtual void vor(); + virtual void vnor(); + virtual void vxor(); + virtual void vnxor(); + virtual void vrcp(); + virtual void vrcpl(); + virtual void vrcph(); + virtual void vmov(); + virtual void vrsql(); + virtual void vrsqh(); + virtual void vrsq(); + virtual void mfc2(); + virtual void cfc2(); + virtual void mtc2(); + virtual void ctc2(); + +private: + virtual int generate_vector_opcode(drcuml_block *block, rsp_device::compiler_state *compiler, const opcode_desc *desc); +}; + +#endif /* __RSPCP2D_H__ */ diff --git a/src/devices/cpu/rsp/rspdiv.h b/src/devices/cpu/rsp/rspdiv.h new file mode 100644 index 00000000000..67e4afacd01 --- /dev/null +++ b/src/devices/cpu/rsp/rspdiv.h @@ -0,0 +1,1029 @@ +// license:BSD-3-Clause +// copyright-holders:Ryan Holtz +static const UINT16 rsp_divtable[1024] = +{ + 0xffff, + 0xff00, + 0xfe01, + 0xfd04, + 0xfc07, + 0xfb0c, + 0xfa11, + 0xf918, + 0xf81f, + 0xf727, + 0xf631, + 0xf53b, + 0xf446, + 0xf352, + 0xf25f, + 0xf16d, + 0xf07c, + 0xef8b, + 0xee9c, + 0xedae, + 0xecc0, + 0xebd3, + 0xeae8, + 0xe9fd, + 0xe913, + 0xe829, + 0xe741, + 0xe65a, + 0xe573, + 0xe48d, + 0xe3a9, + 0xe2c5, + 0xe1e1, + 0xe0ff, + 0xe01e, + 0xdf3d, + 0xde5d, + 0xdd7e, + 0xdca0, + 0xdbc2, + 0xdae6, + 0xda0a, + 0xd92f, + 0xd854, + 0xd77b, + 0xd6a2, + 0xd5ca, + 0xd4f3, + 0xd41d, + 0xd347, + 0xd272, + 0xd19e, + 0xd0cb, + 0xcff8, + 0xcf26, + 0xce55, + 0xcd85, + 0xccb5, + 0xcbe6, + 0xcb18, + 0xca4b, + 0xc97e, + 0xc8b2, + 0xc7e7, + 0xc71c, + 0xc652, + 0xc589, + 0xc4c0, + 0xc3f8, + 0xc331, + 0xc26b, + 0xc1a5, + 0xc0e0, + 0xc01c, + 0xbf58, + 0xbe95, + 0xbdd2, + 0xbd10, + 0xbc4f, + 0xbb8f, + 0xbacf, + 0xba10, + 0xb951, + 0xb894, + 0xb7d6, + 0xb71a, + 0xb65e, + 0xb5a2, + 0xb4e8, + 0xb42e, + 0xb374, + 0xb2bb, + 0xb203, + 0xb14b, + 0xb094, + 0xafde, + 0xaf28, + 0xae73, + 0xadbe, + 0xad0a, + 0xac57, + 0xaba4, + 0xaaf1, + 0xaa40, + 0xa98e, + 0xa8de, + 0xa82e, + 0xa77e, + 0xa6d0, + 0xa621, + 0xa574, + 0xa4c6, + 0xa41a, + 0xa36e, + 0xa2c2, + 0xa217, + 0xa16d, + 0xa0c3, + 0xa01a, + 0x9f71, + 0x9ec8, + 0x9e21, + 0x9d79, + 0x9cd3, + 0x9c2d, + 0x9b87, + 0x9ae2, + 0x9a3d, + 0x9999, + 0x98f6, + 0x9852, + 0x97b0, + 0x970e, + 0x966c, + 0x95cb, + 0x952b, + 0x948b, + 0x93eb, + 0x934c, + 0x92ad, + 0x920f, + 0x9172, + 0x90d4, + 0x9038, + 0x8f9c, + 0x8f00, + 0x8e65, + 0x8dca, + 0x8d30, + 0x8c96, + 0x8bfc, + 0x8b64, + 0x8acb, + 0x8a33, + 0x899c, + 0x8904, + 0x886e, + 0x87d8, + 0x8742, + 0x86ad, + 0x8618, + 0x8583, + 0x84f0, + 0x845c, + 0x83c9, + 0x8336, + 0x82a4, + 0x8212, + 0x8181, + 0x80f0, + 0x8060, + 0x7fd0, + 0x7f40, + 0x7eb1, + 0x7e22, + 0x7d93, + 0x7d05, + 0x7c78, + 0x7beb, + 0x7b5e, + 0x7ad2, + 0x7a46, + 0x79ba, + 0x792f, + 0x78a4, + 0x781a, + 0x7790, + 0x7706, + 0x767d, + 0x75f5, + 0x756c, + 0x74e4, + 0x745d, + 0x73d5, + 0x734f, + 0x72c8, + 0x7242, + 0x71bc, + 0x7137, + 0x70b2, + 0x702e, + 0x6fa9, + 0x6f26, + 0x6ea2, + 0x6e1f, + 0x6d9c, + 0x6d1a, + 0x6c98, + 0x6c16, + 0x6b95, + 0x6b14, + 0x6a94, + 0x6a13, + 0x6993, + 0x6914, + 0x6895, + 0x6816, + 0x6798, + 0x6719, + 0x669c, + 0x661e, + 0x65a1, + 0x6524, + 0x64a8, + 0x642c, + 0x63b0, + 0x6335, + 0x62ba, + 0x623f, + 0x61c5, + 0x614b, + 0x60d1, + 0x6058, + 0x5fdf, + 0x5f66, + 0x5eed, + 0x5e75, + 0x5dfd, + 0x5d86, + 0x5d0f, + 0x5c98, + 0x5c22, + 0x5bab, + 0x5b35, + 0x5ac0, + 0x5a4b, + 0x59d6, + 0x5961, + 0x58ed, + 0x5879, + 0x5805, + 0x5791, + 0x571e, + 0x56ac, + 0x5639, + 0x55c7, + 0x5555, + 0x54e3, + 0x5472, + 0x5401, + 0x5390, + 0x5320, + 0x52af, + 0x5240, + 0x51d0, + 0x5161, + 0x50f2, + 0x5083, + 0x5015, + 0x4fa6, + 0x4f38, + 0x4ecb, + 0x4e5e, + 0x4df1, + 0x4d84, + 0x4d17, + 0x4cab, + 0x4c3f, + 0x4bd3, + 0x4b68, + 0x4afd, + 0x4a92, + 0x4a27, + 0x49bd, + 0x4953, + 0x48e9, + 0x4880, + 0x4817, + 0x47ae, + 0x4745, + 0x46dc, + 0x4674, + 0x460c, + 0x45a5, + 0x453d, + 0x44d6, + 0x446f, + 0x4408, + 0x43a2, + 0x433c, + 0x42d6, + 0x4270, + 0x420b, + 0x41a6, + 0x4141, + 0x40dc, + 0x4078, + 0x4014, + 0x3fb0, + 0x3f4c, + 0x3ee8, + 0x3e85, + 0x3e22, + 0x3dc0, + 0x3d5d, + 0x3cfb, + 0x3c99, + 0x3c37, + 0x3bd6, + 0x3b74, + 0x3b13, + 0x3ab2, + 0x3a52, + 0x39f1, + 0x3991, + 0x3931, + 0x38d2, + 0x3872, + 0x3813, + 0x37b4, + 0x3755, + 0x36f7, + 0x3698, + 0x363a, + 0x35dc, + 0x357f, + 0x3521, + 0x34c4, + 0x3467, + 0x340a, + 0x33ae, + 0x3351, + 0x32f5, + 0x3299, + 0x323e, + 0x31e2, + 0x3187, + 0x312c, + 0x30d1, + 0x3076, + 0x301c, + 0x2fc2, + 0x2f68, + 0x2f0e, + 0x2eb4, + 0x2e5b, + 0x2e02, + 0x2da9, + 0x2d50, + 0x2cf8, + 0x2c9f, + 0x2c47, + 0x2bef, + 0x2b97, + 0x2b40, + 0x2ae8, + 0x2a91, + 0x2a3a, + 0x29e4, + 0x298d, + 0x2937, + 0x28e0, + 0x288b, + 0x2835, + 0x27df, + 0x278a, + 0x2735, + 0x26e0, + 0x268b, + 0x2636, + 0x25e2, + 0x258d, + 0x2539, + 0x24e5, + 0x2492, + 0x243e, + 0x23eb, + 0x2398, + 0x2345, + 0x22f2, + 0x22a0, + 0x224d, + 0x21fb, + 0x21a9, + 0x2157, + 0x2105, + 0x20b4, + 0x2063, + 0x2012, + 0x1fc1, + 0x1f70, + 0x1f1f, + 0x1ecf, + 0x1e7f, + 0x1e2e, + 0x1ddf, + 0x1d8f, + 0x1d3f, + 0x1cf0, + 0x1ca1, + 0x1c52, + 0x1c03, + 0x1bb4, + 0x1b66, + 0x1b17, + 0x1ac9, + 0x1a7b, + 0x1a2d, + 0x19e0, + 0x1992, + 0x1945, + 0x18f8, + 0x18ab, + 0x185e, + 0x1811, + 0x17c4, + 0x1778, + 0x172c, + 0x16e0, + 0x1694, + 0x1648, + 0x15fd, + 0x15b1, + 0x1566, + 0x151b, + 0x14d0, + 0x1485, + 0x143b, + 0x13f0, + 0x13a6, + 0x135c, + 0x1312, + 0x12c8, + 0x127f, + 0x1235, + 0x11ec, + 0x11a3, + 0x1159, + 0x1111, + 0x10c8, + 0x107f, + 0x1037, + 0x0fef, + 0x0fa6, + 0x0f5e, + 0x0f17, + 0x0ecf, + 0x0e87, + 0x0e40, + 0x0df9, + 0x0db2, + 0x0d6b, + 0x0d24, + 0x0cdd, + 0x0c97, + 0x0c50, + 0x0c0a, + 0x0bc4, + 0x0b7e, + 0x0b38, + 0x0af2, + 0x0aad, + 0x0a68, + 0x0a22, + 0x09dd, + 0x0998, + 0x0953, + 0x090f, + 0x08ca, + 0x0886, + 0x0842, + 0x07fd, + 0x07b9, + 0x0776, + 0x0732, + 0x06ee, + 0x06ab, + 0x0668, + 0x0624, + 0x05e1, + 0x059e, + 0x055c, + 0x0519, + 0x04d6, + 0x0494, + 0x0452, + 0x0410, + 0x03ce, + 0x038c, + 0x034a, + 0x0309, + 0x02c7, + 0x0286, + 0x0245, + 0x0204, + 0x01c3, + 0x0182, + 0x0141, + 0x0101, + 0x00c0, + 0x0080, + 0x0040, + 0x6a09, + 0xffff, + 0x6955, + 0xff00, + 0x68a1, + 0xfe02, + 0x67ef, + 0xfd06, + 0x673e, + 0xfc0b, + 0x668d, + 0xfb12, + 0x65de, + 0xfa1a, + 0x6530, + 0xf923, + 0x6482, + 0xf82e, + 0x63d6, + 0xf73b, + 0x632b, + 0xf648, + 0x6280, + 0xf557, + 0x61d7, + 0xf467, + 0x612e, + 0xf379, + 0x6087, + 0xf28c, + 0x5fe0, + 0xf1a0, + 0x5f3a, + 0xf0b6, + 0x5e95, + 0xefcd, + 0x5df1, + 0xeee5, + 0x5d4e, + 0xedff, + 0x5cac, + 0xed19, + 0x5c0b, + 0xec35, + 0x5b6b, + 0xeb52, + 0x5acb, + 0xea71, + 0x5a2c, + 0xe990, + 0x598f, + 0xe8b1, + 0x58f2, + 0xe7d3, + 0x5855, + 0xe6f6, + 0x57ba, + 0xe61b, + 0x5720, + 0xe540, + 0x5686, + 0xe467, + 0x55ed, + 0xe38e, + 0x5555, + 0xe2b7, + 0x54be, + 0xe1e1, + 0x5427, + 0xe10d, + 0x5391, + 0xe039, + 0x52fc, + 0xdf66, + 0x5268, + 0xde94, + 0x51d5, + 0xddc4, + 0x5142, + 0xdcf4, + 0x50b0, + 0xdc26, + 0x501f, + 0xdb59, + 0x4f8e, + 0xda8c, + 0x4efe, + 0xd9c1, + 0x4e6f, + 0xd8f7, + 0x4de1, + 0xd82d, + 0x4d53, + 0xd765, + 0x4cc6, + 0xd69e, + 0x4c3a, + 0xd5d7, + 0x4baf, + 0xd512, + 0x4b24, + 0xd44e, + 0x4a9a, + 0xd38a, + 0x4a10, + 0xd2c8, + 0x4987, + 0xd206, + 0x48ff, + 0xd146, + 0x4878, + 0xd086, + 0x47f1, + 0xcfc7, + 0x476b, + 0xcf0a, + 0x46e5, + 0xce4d, + 0x4660, + 0xcd91, + 0x45dc, + 0xccd6, + 0x4558, + 0xcc1b, + 0x44d5, + 0xcb62, + 0x4453, + 0xcaa9, + 0x43d1, + 0xc9f2, + 0x434f, + 0xc93b, + 0x42cf, + 0xc885, + 0x424f, + 0xc7d0, + 0x41cf, + 0xc71c, + 0x4151, + 0xc669, + 0x40d2, + 0xc5b6, + 0x4055, + 0xc504, + 0x3fd8, + 0xc453, + 0x3f5b, + 0xc3a3, + 0x3edf, + 0xc2f4, + 0x3e64, + 0xc245, + 0x3de9, + 0xc198, + 0x3d6e, + 0xc0eb, + 0x3cf5, + 0xc03f, + 0x3c7c, + 0xbf93, + 0x3c03, + 0xbee9, + 0x3b8b, + 0xbe3f, + 0x3b13, + 0xbd96, + 0x3a9c, + 0xbced, + 0x3a26, + 0xbc46, + 0x39b0, + 0xbb9f, + 0x393a, + 0xbaf8, + 0x38c5, + 0xba53, + 0x3851, + 0xb9ae, + 0x37dd, + 0xb90a, + 0x3769, + 0xb867, + 0x36f6, + 0xb7c5, + 0x3684, + 0xb723, + 0x3612, + 0xb681, + 0x35a0, + 0xb5e1, + 0x352f, + 0xb541, + 0x34bf, + 0xb4a2, + 0x344f, + 0xb404, + 0x33df, + 0xb366, + 0x3370, + 0xb2c9, + 0x3302, + 0xb22c, + 0x3293, + 0xb191, + 0x3226, + 0xb0f5, + 0x31b9, + 0xb05b, + 0x314c, + 0xafc1, + 0x30df, + 0xaf28, + 0x3074, + 0xae8f, + 0x3008, + 0xadf7, + 0x2f9d, + 0xad60, + 0x2f33, + 0xacc9, + 0x2ec8, + 0xac33, + 0x2e5f, + 0xab9e, + 0x2df6, + 0xab09, + 0x2d8d, + 0xaa75, + 0x2d24, + 0xa9e1, + 0x2cbc, + 0xa94e, + 0x2c55, + 0xa8bc, + 0x2bee, + 0xa82a, + 0x2b87, + 0xa799, + 0x2b21, + 0xa708, + 0x2abb, + 0xa678, + 0x2a55, + 0xa5e8, + 0x29f0, + 0xa559, + 0x298b, + 0xa4cb, + 0x2927, + 0xa43d, + 0x28c3, + 0xa3b0, + 0x2860, + 0xa323, + 0x27fd, + 0xa297, + 0x279a, + 0xa20b, + 0x2738, + 0xa180, + 0x26d6, + 0xa0f6, + 0x2674, + 0xa06c, + 0x2613, + 0x9fe2, + 0x25b2, + 0x9f59, + 0x2552, + 0x9ed1, + 0x24f2, + 0x9e49, + 0x2492, + 0x9dc2, + 0x2432, + 0x9d3b, + 0x23d3, + 0x9cb4, + 0x2375, + 0x9c2f, + 0x2317, + 0x9ba9, + 0x22b9, + 0x9b25, + 0x225b, + 0x9aa0, + 0x21fe, + 0x9a1c, + 0x21a1, + 0x9999, + 0x2145, + 0x9916, + 0x20e8, + 0x9894, + 0x208d, + 0x9812, + 0x2031, + 0x9791, + 0x1fd6, + 0x9710, + 0x1f7b, + 0x968f, + 0x1f21, + 0x960f, + 0x1ec7, + 0x9590, + 0x1e6d, + 0x9511, + 0x1e13, + 0x9492, + 0x1dba, + 0x9414, + 0x1d61, + 0x9397, + 0x1d09, + 0x931a, + 0x1cb1, + 0x929d, + 0x1c59, + 0x9221, + 0x1c01, + 0x91a5, + 0x1baa, + 0x9129, + 0x1b53, + 0x90af, + 0x1afc, + 0x9034, + 0x1aa6, + 0x8fba, + 0x1a50, + 0x8f40, + 0x19fa, + 0x8ec7, + 0x19a5, + 0x8e4f, + 0x1950, + 0x8dd6, + 0x18fb, + 0x8d5e, + 0x18a7, + 0x8ce7, + 0x1853, + 0x8c70, + 0x17ff, + 0x8bf9, + 0x17ab, + 0x8b83, + 0x1758, + 0x8b0d, + 0x1705, + 0x8a98, + 0x16b2, + 0x8a23, + 0x1660, + 0x89ae, + 0x160d, + 0x893a, + 0x15bc, + 0x88c6, + 0x156a, + 0x8853, + 0x1519, + 0x87e0, + 0x14c8, + 0x876d, + 0x1477, + 0x86fb, + 0x1426, + 0x8689, + 0x13d6, + 0x8618, + 0x1386, + 0x85a7, + 0x1337, + 0x8536, + 0x12e7, + 0x84c6, + 0x1298, + 0x8456, + 0x1249, + 0x83e7, + 0x11fb, + 0x8377, + 0x11ac, + 0x8309, + 0x115e, + 0x829a, + 0x1111, + 0x822c, + 0x10c3, + 0x81bf, + 0x1076, + 0x8151, + 0x1029, + 0x80e4, + 0x0fdc, + 0x8078, + 0x0f8f, + 0x800c, + 0x0f43, + 0x7fa0, + 0x0ef7, + 0x7f34, + 0x0eab, + 0x7ec9, + 0x0e60, + 0x7e5e, + 0x0e15, + 0x7df4, + 0x0dca, + 0x7d8a, + 0x0d7f, + 0x7d20, + 0x0d34, + 0x7cb6, + 0x0cea, + 0x7c4d, + 0x0ca0, + 0x7be5, + 0x0c56, + 0x7b7c, + 0x0c0c, + 0x7b14, + 0x0bc3, + 0x7aac, + 0x0b7a, + 0x7a45, + 0x0b31, + 0x79de, + 0x0ae8, + 0x7977, + 0x0aa0, + 0x7911, + 0x0a58, + 0x78ab, + 0x0a10, + 0x7845, + 0x09c8, + 0x77df, + 0x0981, + 0x777a, + 0x0939, + 0x7715, + 0x08f2, + 0x76b1, + 0x08ab, + 0x764d, + 0x0865, + 0x75e9, + 0x081e, + 0x7585, + 0x07d8, + 0x7522, + 0x0792, + 0x74bf, + 0x074d, + 0x745d, + 0x0707, + 0x73fa, + 0x06c2, + 0x7398, + 0x067d, + 0x7337, + 0x0638, + 0x72d5, + 0x05f3, + 0x7274, + 0x05af, + 0x7213, + 0x056a, + 0x71b3, + 0x0526, + 0x7152, + 0x04e2, + 0x70f2, + 0x049f, + 0x7093, + 0x045b, + 0x7033, + 0x0418, + 0x6fd4, + 0x03d5, + 0x6f76, + 0x0392, + 0x6f17, + 0x0350, + 0x6eb9, + 0x030d, + 0x6e5b, + 0x02cb, + 0x6dfd, + 0x0289, + 0x6da0, + 0x0247, + 0x6d43, + 0x0206, + 0x6ce6, + 0x01c4, + 0x6c8a, + 0x0183, + 0x6c2d, + 0x0142, + 0x6bd1, + 0x0101, + 0x6b76, + 0x00c0, + 0x6b1a, + 0x0080, + 0x6abf, + 0x0040, + 0x6a64 +}; diff --git a/src/devices/cpu/rsp/rspdrc.c b/src/devices/cpu/rsp/rspdrc.c new file mode 100644 index 00000000000..ae719af5959 --- /dev/null +++ b/src/devices/cpu/rsp/rspdrc.c @@ -0,0 +1,1292 @@ +// license:BSD-3-Clause +// copyright-holders:Ryan Holtz +/*************************************************************************** + + rspdrc.c + + Universal machine language-based Nintendo/SGI RSP emulator. + Written by Harmony of the MESS team. + SIMD versions of vector multiplication opcodes provided by Marathon Man + of the CEN64 team. + +**************************************************************************** + + Future improvements/changes: + + * Confer with Aaron Giles about adding a memory hash-based caching + system and static recompilation for maximum overhead minimization + +***************************************************************************/ + +#include "emu.h" +#include "debugger.h" +#include "rsp.h" +#include "rspfe.h" +#include "rspcp2.h" +#include "cpu/drcfe.h" +#include "cpu/drcuml.h" +#include "cpu/drcumlsh.h" + +using namespace uml; + +CPU_DISASSEMBLE( rsp ); + +extern offs_t rsp_dasm_one(char *buffer, offs_t pc, UINT32 op); + +/*************************************************************************** + CONSTANTS +***************************************************************************/ + +/* map variables */ +#define MAPVAR_PC M0 +#define MAPVAR_CYCLES M1 + +/* exit codes */ +#define EXECUTE_OUT_OF_CYCLES 0 +#define EXECUTE_MISSING_CODE 1 +#define EXECUTE_UNMAPPED_CODE 2 +#define EXECUTE_RESET_CACHE 3 + + + +/*************************************************************************** + Macros +***************************************************************************/ + +#define R32(reg) m_regmap[reg] + +/*************************************************************************** + Inline Functions +***************************************************************************/ + +/*------------------------------------------------- + epc - compute the exception PC from a + descriptor +-------------------------------------------------*/ + +INLINE UINT32 epc(const opcode_desc *desc) +{ + return ((desc->flags & OPFLAG_IN_DELAY_SLOT) ? (desc->pc - 3) : desc->pc) | 0x1000; +} + + +/*------------------------------------------------- + alloc_handle - allocate a handle if not + already allocated +-------------------------------------------------*/ + +INLINE void alloc_handle(drcuml_state *drcuml, code_handle **handleptr, const char *name) +{ + if (*handleptr == NULL) + *handleptr = drcuml->handle_alloc(name); +} + + +/*------------------------------------------------- + load_fast_iregs - load any fast integer + registers +-------------------------------------------------*/ + +inline void rsp_device::load_fast_iregs(drcuml_block *block) +{ + int regnum; + + for (regnum = 0; regnum < ARRAY_LENGTH(m_regmap); regnum++) + if (m_regmap[regnum].is_int_register()) + UML_MOV(block, ireg(m_regmap[regnum].ireg() - REG_I0), mem(&m_rsp_state->r[regnum])); +} + + +/*------------------------------------------------- + save_fast_iregs - save any fast integer + registers +-------------------------------------------------*/ + +inline void rsp_device::save_fast_iregs(drcuml_block *block) +{ + int regnum; + + for (regnum = 0; regnum < ARRAY_LENGTH(m_regmap); regnum++) + if (m_regmap[regnum].is_int_register()) + UML_MOV(block, mem(&m_rsp_state->r[regnum]), ireg(m_regmap[regnum].ireg() - REG_I0)); +} + +/*************************************************************************** + CORE CALLBACKS +***************************************************************************/ + +inline void rsp_device::ccfunc_read8() +{ + m_rsp_state->arg0 = DM_READ8(m_rsp_state->arg0); +} + +static void cfunc_read8(void *param) +{ + ((rsp_device *)param)->ccfunc_read8(); +} + +inline void rsp_device::ccfunc_read16() +{ + m_rsp_state->arg0 = DM_READ16(m_rsp_state->arg0); +} + +static void cfunc_read16(void *param) +{ + ((rsp_device *)param)->ccfunc_read16(); +} + +inline void rsp_device::ccfunc_read32() +{ + m_rsp_state->arg0 = DM_READ32(m_rsp_state->arg0); +} + +static void cfunc_read32(void *param) +{ + ((rsp_device *)param)->ccfunc_read32();; +} + +inline void rsp_device::ccfunc_write8() +{ + DM_WRITE8(m_rsp_state->arg0, m_rsp_state->arg1); +} + +static void cfunc_write8(void *param) +{ + ((rsp_device *)param)->ccfunc_write8();; +} + +inline void rsp_device::ccfunc_write16() +{ + DM_WRITE16(m_rsp_state->arg0, m_rsp_state->arg1); +} + +static void cfunc_write16(void *param) +{ + ((rsp_device *)param)->ccfunc_write16();; +} + +inline void rsp_device::ccfunc_write32() +{ + DM_WRITE32(m_rsp_state->arg0, m_rsp_state->arg1); +} + +static void cfunc_write32(void *param) +{ + ((rsp_device *)param)->ccfunc_write32();; +} + +/*****************************************************************************/ + +/*------------------------------------------------- + rspdrc_set_options - configure DRC options +-------------------------------------------------*/ + +void rsp_device::rspdrc_set_options(UINT32 options) +{ + if (!(mconfig().options().drc() && !mconfig().m_force_no_drc)) return; + m_drcoptions = options; +} + + +inline void rsp_device::ccfunc_get_cop0_reg() +{ + int reg = m_rsp_state->arg0; + int dest = m_rsp_state->arg1; + + if (reg >= 0 && reg < 8) + { + if(dest) + { + m_rsp_state->r[dest] = m_sp_reg_r_func(reg, 0xffffffff); + } + } + else if (reg >= 8 && reg < 16) + { + if(dest) + { + m_rsp_state->r[dest] = m_dp_reg_r_func(reg - 8, 0xffffffff); + } + } + else + { + fatalerror("RSP: cfunc_get_cop0_reg: %d\n", reg); + } +} + +static void cfunc_get_cop0_reg(void *param) +{ + ((rsp_device *)param)->ccfunc_get_cop0_reg(); +} + +inline void rsp_device::ccfunc_set_cop0_reg() +{ + int reg = m_rsp_state->arg0; + UINT32 data = m_rsp_state->arg1; + + if (reg >= 0 && reg < 8) + { + m_sp_reg_w_func(reg, data, 0xffffffff); + } + else if (reg >= 8 && reg < 16) + { + m_dp_reg_w_func(reg - 8, data, 0xffffffff); + } + else + { + fatalerror("RSP: set_cop0_reg: %d, %08X\n", reg, data); + } +} + +static void cfunc_set_cop0_reg(void *param) +{ + ((rsp_device *)param)->ccfunc_set_cop0_reg(); +} + +/*****************************************************************************/ + +void rsp_device::rspcom_init() +{ +} + +inline void rsp_device::ccfunc_sp_set_status_cb() +{ + m_sp_set_status_func(0, m_rsp_state->arg0, 0xffffffff); +} + +void cfunc_sp_set_status_cb(void *param) +{ + ((rsp_device *)param)->ccfunc_sp_set_status_cb(); +} + +void rsp_device::execute_run_drc() +{ + drcuml_state *drcuml = m_drcuml; + int execute_result; + + /* reset the cache if dirty */ + if (m_cache_dirty) + code_flush_cache(); + m_cache_dirty = FALSE; + + /* execute */ + do + { + if( m_sr & ( RSP_STATUS_HALT | RSP_STATUS_BROKE ) ) + { + m_rsp_state->icount = MIN(m_rsp_state->icount, 0); + break; + } + + /* run as much as we can */ + execute_result = drcuml->execute(*m_entry); + + /* if we need to recompile, do it */ + if (execute_result == EXECUTE_MISSING_CODE) + { + code_compile_block(m_rsp_state->pc); + } + else if (execute_result == EXECUTE_UNMAPPED_CODE) + { + fatalerror("Attempted to execute unmapped code at PC=%08X\n", m_rsp_state->pc); + } + else if (execute_result == EXECUTE_RESET_CACHE) + { + code_flush_cache(); + } + } while (execute_result != EXECUTE_OUT_OF_CYCLES); +} + +/*************************************************************************** + CACHE MANAGEMENT +***************************************************************************/ + +/*------------------------------------------------- + rspdrc_flush_drc_cache - outward-facing + accessor to code_flush_cache +-------------------------------------------------*/ + +void rsp_device::rspdrc_flush_drc_cache() +{ + if (!(mconfig().options().drc() && !mconfig().m_force_no_drc)) return; + m_cache_dirty = TRUE; +} + +/*------------------------------------------------- + code_flush_cache - flush the cache and + regenerate static code +-------------------------------------------------*/ + +void rsp_device::code_flush_cache() +{ + /* empty the transient cache contents */ + m_drcuml->reset(); + + try + { + /* generate the entry point and out-of-cycles handlers */ + static_generate_entry_point(); + static_generate_nocode_handler(); + static_generate_out_of_cycles(); + + /* add subroutines for memory accesses */ + static_generate_memory_accessor(1, FALSE, "read8", m_read8); + static_generate_memory_accessor(1, TRUE, "write8", m_write8); + static_generate_memory_accessor(2, FALSE, "read16", m_read16); + static_generate_memory_accessor(2, TRUE, "write16", m_write16); + static_generate_memory_accessor(4, FALSE, "read32", m_read32); + static_generate_memory_accessor(4, TRUE, "write32", m_write32); + } + catch (drcuml_block::abort_compilation &) + { + fatalerror("Unable to generate static RSP code\n"); + } +} + + +/*------------------------------------------------- + code_compile_block - compile a block of the + given mode at the specified pc +-------------------------------------------------*/ + +void rsp_device::code_compile_block(offs_t pc) +{ + drcuml_state *drcuml = m_drcuml; + compiler_state compiler = { 0 }; + const opcode_desc *seqhead, *seqlast; + const opcode_desc *desclist; + int override = FALSE; + drcuml_block *block; + + g_profiler.start(PROFILER_DRC_COMPILE); + + /* get a description of this sequence */ + desclist = m_drcfe->describe_code(pc); + + bool succeeded = false; + while (!succeeded) + { + try + { + /* start the block */ + block = drcuml->begin_block(4096); + + /* loop until we get through all instruction sequences */ + for (seqhead = desclist; seqhead != NULL; seqhead = seqlast->next()) + { + const opcode_desc *curdesc; + UINT32 nextpc; + + /* add a code log entry */ + if (drcuml->logging()) + block->append_comment("-------------------------"); // comment + + /* determine the last instruction in this sequence */ + for (seqlast = seqhead; seqlast != NULL; seqlast = seqlast->next()) + if (seqlast->flags & OPFLAG_END_SEQUENCE) + break; + assert(seqlast != NULL); + + /* if we don't have a hash for this mode/pc, or if we are overriding all, add one */ + if (override || !drcuml->hash_exists(0, seqhead->pc)) + UML_HASH(block, 0, seqhead->pc); // hash mode,pc + + /* if we already have a hash, and this is the first sequence, assume that we */ + /* are recompiling due to being out of sync and allow future overrides */ + else if (seqhead == desclist) + { + override = TRUE; + UML_HASH(block, 0, seqhead->pc); // hash mode,pc + } + + /* otherwise, redispatch to that fixed PC and skip the rest of the processing */ + else + { + UML_LABEL(block, seqhead->pc | 0x80000000); // label seqhead->pc + UML_HASHJMP(block, 0, seqhead->pc, *m_nocode); + // hashjmp <0>,seqhead->pc,nocode + continue; + } + + /* validate this code block if we're not pointing into ROM */ + if (m_program->get_write_ptr(seqhead->physpc) != NULL) + generate_checksum_block(block, &compiler, seqhead, seqlast); + + /* label this instruction, if it may be jumped to locally */ + if (seqhead->flags & OPFLAG_IS_BRANCH_TARGET) + UML_LABEL(block, seqhead->pc | 0x80000000); // label seqhead->pc + + /* iterate over instructions in the sequence and compile them */ + for (curdesc = seqhead; curdesc != seqlast->next(); curdesc = curdesc->next()) + generate_sequence_instruction(block, &compiler, curdesc); + + /* if we need to return to the start, do it */ + if (seqlast->flags & OPFLAG_RETURN_TO_START) + nextpc = pc; + + /* otherwise we just go to the next instruction */ + else + nextpc = seqlast->pc + (seqlast->skipslots + 1) * 4; + + /* count off cycles and go there */ + generate_update_cycles(block, &compiler, nextpc, TRUE); // + + /* if the last instruction can change modes, use a variable mode; otherwise, assume the same mode */ + if (seqlast->next() == NULL || seqlast->next()->pc != nextpc) + UML_HASHJMP(block, 0, nextpc, *m_nocode); // hashjmp ,nextpc,nocode + } + + /* end the sequence */ + block->end(); + g_profiler.stop(); + succeeded = true; + } + catch (drcuml_block::abort_compilation &) + { + code_flush_cache(); + } + } +} + +/*************************************************************************** + C FUNCTION CALLBACKS +***************************************************************************/ + +/*------------------------------------------------- + cfunc_unimplemented - handler for + unimplemented opcdes +-------------------------------------------------*/ + +inline void rsp_device::ccfunc_unimplemented() +{ + UINT32 opcode = m_rsp_state->arg0; + fatalerror("PC=%08X: Unimplemented op %08X (%02X,%02X)\n", m_rsp_state->pc, opcode, opcode >> 26, opcode & 0x3f); +} + +static void cfunc_unimplemented(void *param) +{ + ((rsp_device *)param)->ccfunc_unimplemented(); +} + +/*------------------------------------------------- + cfunc_fatalerror - a generic fatalerror call +-------------------------------------------------*/ + +#ifdef UNUSED_CODE +static void cfunc_fatalerror(void *param) +{ + fatalerror("fatalerror\n"); +} +#endif + + +/*************************************************************************** + STATIC CODEGEN +***************************************************************************/ + +/*------------------------------------------------- + ferate_entry_point - generate a + static entry point +-------------------------------------------------*/ + +void rsp_device::static_generate_entry_point() +{ + drcuml_state *drcuml = m_drcuml; + drcuml_block *block; + + /* begin generating */ + block = drcuml->begin_block(20); + + /* forward references */ + alloc_handle(drcuml, &m_nocode, "nocode"); + + alloc_handle(drcuml, &m_entry, "entry"); + UML_HANDLE(block, *m_entry); // handle entry + + /* load fast integer registers */ + load_fast_iregs(block); + + /* generate a hash jump via the current mode and PC */ + UML_HASHJMP(block, 0, mem(&m_rsp_state->pc), *m_nocode); // hashjmp ,,nocode + block->end(); +} + + +/*------------------------------------------------- + static_generate_nocode_handler - generate an + exception handler for "out of code" +-------------------------------------------------*/ + +void rsp_device::static_generate_nocode_handler() +{ + drcuml_state *drcuml = m_drcuml; + drcuml_block *block; + + /* begin generating */ + block = drcuml->begin_block(10); + + /* generate a hash jump via the current mode and PC */ + alloc_handle(drcuml, &m_nocode, "nocode"); + UML_HANDLE(block, *m_nocode); // handle nocode + UML_GETEXP(block, I0); // getexp i0 + UML_MOV(block, mem(&m_rsp_state->pc), I0); // mov [pc],i0 + save_fast_iregs(block); + UML_EXIT(block, EXECUTE_MISSING_CODE); // exit EXECUTE_MISSING_CODE + + block->end(); +} + + +/*------------------------------------------------- + static_generate_out_of_cycles - generate an + out of cycles exception handler +-------------------------------------------------*/ + +void rsp_device::static_generate_out_of_cycles() +{ + drcuml_state *drcuml = m_drcuml; + drcuml_block *block; + + /* begin generating */ + block = drcuml->begin_block(10); + + /* generate a hash jump via the current mode and PC */ + alloc_handle(drcuml, &m_out_of_cycles, "out_of_cycles"); + UML_HANDLE(block, *m_out_of_cycles); // handle out_of_cycles + UML_GETEXP(block, I0); // getexp i0 + UML_MOV(block, mem(&m_rsp_state->pc), I0); // mov ,i0 + save_fast_iregs(block); + UML_EXIT(block, EXECUTE_OUT_OF_CYCLES); // exit EXECUTE_OUT_OF_CYCLES + + block->end(); +} + +/*------------------------------------------------------------------ + static_generate_memory_accessor +------------------------------------------------------------------*/ + +void rsp_device::static_generate_memory_accessor(int size, int iswrite, const char *name, code_handle *&handleptr) +{ + /* on entry, address is in I0; data for writes is in I1 */ + /* on exit, read result is in I0 */ + /* routine trashes I0-I1 */ + drcuml_state *drcuml = m_drcuml; + drcuml_block *block; + + /* begin generating */ + block = drcuml->begin_block(1024); + + /* add a global entry for this */ + alloc_handle(drcuml, &handleptr, name); + UML_HANDLE(block, *handleptr); // handle *handleptr + + // write: + if (iswrite) + { + if (size == 1) + { + UML_MOV(block, mem(&m_rsp_state->arg0), I0); // mov [arg0],i0 ; address + UML_MOV(block, mem(&m_rsp_state->arg1), I1); // mov [arg1],i1 ; data + UML_CALLC(block, cfunc_write8, this); // callc cfunc_write8 + } + else if (size == 2) + { + UML_MOV(block, mem(&m_rsp_state->arg0), I0); // mov [arg0],i0 ; address + UML_MOV(block, mem(&m_rsp_state->arg1), I1); // mov [arg1],i1 ; data + UML_CALLC(block, cfunc_write16, this); // callc cfunc_write16 + } + else if (size == 4) + { + UML_MOV(block, mem(&m_rsp_state->arg0), I0); // mov [arg0],i0 ; address + UML_MOV(block, mem(&m_rsp_state->arg1), I1); // mov [arg1],i1 ; data + UML_CALLC(block, cfunc_write32, this); // callc cfunc_write32 + } + } + else + { + if (size == 1) + { + UML_MOV(block, mem(&m_rsp_state->arg0), I0); // mov [arg0],i0 ; address + UML_CALLC(block, cfunc_read8, this); // callc read8 + UML_MOV(block, I0, mem(&m_rsp_state->arg0)); // mov i0,[arg0],i0 ; result + } + else if (size == 2) + { + UML_MOV(block, mem(&m_rsp_state->arg0), I0); // mov [arg0],i0 ; address + UML_CALLC(block, cfunc_read16, this); // callc cfunc_read16 + UML_MOV(block, I0, mem(&m_rsp_state->arg0)); // mov i0,[arg0],i0 ; result + } + else if (size == 4) + { + UML_MOV(block, mem(&m_rsp_state->arg0), I0); // mov [arg0],i0 ; address + UML_CALLC(block, cfunc_read32, this); // callc cfunc_read32 + UML_MOV(block, I0, mem(&m_rsp_state->arg0)); // mov i0,[arg0],i0 ; result + } + } + UML_RET(block); + + block->end(); +} + + + +/*************************************************************************** + CODE GENERATION +***************************************************************************/ + +/*------------------------------------------------- + generate_update_cycles - generate code to + subtract cycles from the icount and generate + an exception if out +-------------------------------------------------*/ +void rsp_device::generate_update_cycles(drcuml_block *block, compiler_state *compiler, uml::parameter param, int allow_exception) +{ + /* account for cycles */ + if (compiler->cycles > 0) + { + UML_SUB(block, mem(&m_rsp_state->icount), mem(&m_rsp_state->icount), MAPVAR_CYCLES); // sub icount,icount,cycles + UML_MAPVAR(block, MAPVAR_CYCLES, 0); // mapvar cycles,0 + UML_EXHc(block, COND_S, *m_out_of_cycles, param); + } + compiler->cycles = 0; +} + +/*------------------------------------------------- + generate_checksum_block - generate code to + validate a sequence of opcodes +-------------------------------------------------*/ + +void rsp_device::generate_checksum_block(drcuml_block *block, compiler_state *compiler, const opcode_desc *seqhead, const opcode_desc *seqlast) +{ + const opcode_desc *curdesc; + if (m_drcuml->logging()) + { + block->append_comment("[Validation for %08X]", seqhead->pc | 0x1000); // comment + } + /* loose verify or single instruction: just compare and fail */ + if (!(m_drcoptions & RSPDRC_STRICT_VERIFY) || seqhead->next() == NULL) + { + if (!(seqhead->flags & OPFLAG_VIRTUAL_NOOP)) + { + UINT32 sum = seqhead->opptr.l[0]; + void *base = m_direct->read_ptr(seqhead->physpc | 0x1000); + UML_LOAD(block, I0, base, 0, SIZE_DWORD, SCALE_x4); // load i0,base,0,dword + + if (seqhead->delay.first() != NULL && seqhead->physpc != seqhead->delay.first()->physpc) + { + base = m_direct->read_ptr(seqhead->delay.first()->physpc | 0x1000); + assert(base != NULL); + UML_LOAD(block, I1, base, 0, SIZE_DWORD, SCALE_x4); // load i1,base,dword + UML_ADD(block, I0, I0, I1); // add i0,i0,i1 + + sum += seqhead->delay.first()->opptr.l[0]; + } + + UML_CMP(block, I0, sum); // cmp i0,opptr[0] + UML_EXHc(block, COND_NE, *m_nocode, epc(seqhead)); // exne nocode,seqhead->pc + } + } + + /* full verification; sum up everything */ + else + { + UINT32 sum = 0; + void *base = m_direct->read_ptr(seqhead->physpc | 0x1000); + UML_LOAD(block, I0, base, 0, SIZE_DWORD, SCALE_x4); // load i0,base,0,dword + sum += seqhead->opptr.l[0]; + for (curdesc = seqhead->next(); curdesc != seqlast->next(); curdesc = curdesc->next()) + if (!(curdesc->flags & OPFLAG_VIRTUAL_NOOP)) + { + base = m_direct->read_ptr(curdesc->physpc | 0x1000); + assert(base != NULL); + UML_LOAD(block, I1, base, 0, SIZE_DWORD, SCALE_x4); // load i1,base,dword + UML_ADD(block, I0, I0, I1); // add i0,i0,i1 + sum += curdesc->opptr.l[0]; + + if (curdesc->delay.first() != NULL && (curdesc == seqlast || (curdesc->next() != NULL && curdesc->next()->physpc != curdesc->delay.first()->physpc))) + { + base = m_direct->read_ptr(curdesc->delay.first()->physpc | 0x1000); + assert(base != NULL); + UML_LOAD(block, I1, base, 0, SIZE_DWORD, SCALE_x4); // load i1,base,dword + UML_ADD(block, I0, I0, I1); // add i0,i0,i1 + + sum += curdesc->delay.first()->opptr.l[0]; + } + } + UML_CMP(block, I0, sum); // cmp i0,sum + UML_EXHc(block, COND_NE, *m_nocode, epc(seqhead)); // exne nocode,seqhead->pc + } +} + + +/*------------------------------------------------- + generate_sequence_instruction - generate code + for a single instruction in a sequence +-------------------------------------------------*/ + +void rsp_device::generate_sequence_instruction(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) +{ + offs_t expc; + + /* add an entry for the log */ + if (m_drcuml->logging() && !(desc->flags & OPFLAG_VIRTUAL_NOOP)) + log_add_disasm_comment(block, desc->pc, desc->opptr.l[0]); + + /* set the PC map variable */ + expc = (desc->flags & OPFLAG_IN_DELAY_SLOT) ? desc->pc - 3 : desc->pc; + UML_MAPVAR(block, MAPVAR_PC, expc); // mapvar PC,expc + + /* accumulate total cycles */ + compiler->cycles += desc->cycles; + + /* update the icount map variable */ + UML_MAPVAR(block, MAPVAR_CYCLES, compiler->cycles); // mapvar CYCLES,compiler->cycles + + /* if we are debugging, call the debugger */ + if ((machine().debug_flags & DEBUG_FLAG_ENABLED) != 0) + { + UML_MOV(block, mem(&m_rsp_state->pc), desc->pc); // mov [pc],desc->pc + save_fast_iregs(block); + UML_DEBUG(block, desc->pc); // debug desc->pc + } + + /* if we hit an unmapped address, fatal error */ +#if 0 + if (desc->flags & OPFLAG_COMPILER_UNMAPPED) + { + UML_MOV(block, mem(&m_rsp_state->pc), desc->pc); // mov [pc],desc->pc + save_fast_iregs(block); + UML_EXIT(block, EXECUTE_UNMAPPED_CODE); // exit EXECUTE_UNMAPPED_CODE + } +#endif + + /* otherwise, unless this is a virtual no-op, it's a regular instruction */ + /*else*/ if (!(desc->flags & OPFLAG_VIRTUAL_NOOP)) + { + /* compile the instruction */ + if (!generate_opcode(block, compiler, desc)) + { + UML_MOV(block, mem(&m_rsp_state->pc), desc->pc); // mov [pc],desc->pc + UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_unimplemented, this); // callc cfunc_unimplemented + } + } +} + +/*------------------------------------------------------------------ + generate_branch +------------------------------------------------------------------*/ + +void rsp_device::generate_branch(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) +{ + compiler_state compiler_temp = *compiler; + + /* update the cycles and jump through the hash table to the target */ + if (desc->targetpc != BRANCH_TARGET_DYNAMIC) + { + generate_update_cycles(block, &compiler_temp, desc->targetpc, TRUE); // + if (desc->flags & OPFLAG_INTRABLOCK_BRANCH) + UML_JMP(block, desc->targetpc | 0x80000000); // jmp desc->targetpc + else + UML_HASHJMP(block, 0, desc->targetpc, *m_nocode); // hashjmp ,desc->targetpc,nocode + } + else + { + generate_update_cycles(block, &compiler_temp, mem(&m_rsp_state->jmpdest), TRUE); // + UML_HASHJMP(block, 0, mem(&m_rsp_state->jmpdest), *m_nocode); // hashjmp ,,nocode + } +} + +/*------------------------------------------------------------------ + generate_delay_slot_and_branch +------------------------------------------------------------------*/ + +void rsp_device::generate_delay_slot_and_branch(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, UINT8 linkreg) +{ + compiler_state compiler_temp = *compiler; + UINT32 op = desc->opptr.l[0]; + + /* fetch the target register if dynamic, in case it is modified by the delay slot */ + if (desc->targetpc == BRANCH_TARGET_DYNAMIC) + { + UML_AND(block, mem(&m_rsp_state->jmpdest), R32(RSREG), 0x00000fff); + UML_OR(block, mem(&m_rsp_state->jmpdest), mem(&m_rsp_state->jmpdest), 0x1000); + } + + /* set the link if needed -- before the delay slot */ + if (linkreg != 0) + { + UML_MOV(block, R32(linkreg), (INT32)(desc->pc + 8)); // mov ,desc->pc + 8 + } + + /* compile the delay slot using temporary compiler state */ + assert(desc->delay.first() != NULL); + generate_sequence_instruction(block, &compiler_temp, desc->delay.first()); // + + generate_branch(block, compiler, desc); + + /* update the label */ + compiler->labelnum = compiler_temp.labelnum; + + /* reset the mapvar to the current cycles and account for skipped slots */ + compiler->cycles += desc->skipslots; + UML_MAPVAR(block, MAPVAR_CYCLES, compiler->cycles); // mapvar CYCLES,compiler->cycles +} + +int rsp_device::generate_opcode(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) +{ + int in_delay_slot = ((desc->flags & OPFLAG_IN_DELAY_SLOT) != 0); + UINT32 op = desc->opptr.l[0]; + UINT8 opswitch = op >> 26; + code_label skip; + + switch (opswitch) + { + /* ----- sub-groups ----- */ + + case 0x00: /* SPECIAL - MIPS I */ + return generate_special(block, compiler, desc); + + case 0x01: /* REGIMM - MIPS I */ + return generate_regimm(block, compiler, desc); + + /* ----- jumps and branches ----- */ + + case 0x02: /* J - MIPS I */ + generate_delay_slot_and_branch(block, compiler, desc, 0); // + return TRUE; + + case 0x03: /* JAL - MIPS I */ + generate_delay_slot_and_branch(block, compiler, desc, 31); // + return TRUE; + + case 0x04: /* BEQ - MIPS I */ + UML_CMP(block, R32(RSREG), R32(RTREG)); // cmp , + UML_JMPc(block, COND_NE, skip = compiler->labelnum++); // jmp skip,NE + generate_delay_slot_and_branch(block, compiler, desc, 0); // + UML_LABEL(block, skip); // skip: + return TRUE; + + case 0x05: /* BNE - MIPS I */ + UML_CMP(block, R32(RSREG), R32(RTREG)); // dcmp , + UML_JMPc(block, COND_E, skip = compiler->labelnum++); // jmp skip,E + generate_delay_slot_and_branch(block, compiler, desc, 0); // + UML_LABEL(block, skip); // skip: + return TRUE; + + case 0x06: /* BLEZ - MIPS I */ + if (RSREG != 0) + { + UML_CMP(block, R32(RSREG), 0); // dcmp ,0 + UML_JMPc(block, COND_G, skip = compiler->labelnum++); // jmp skip,G + generate_delay_slot_and_branch(block, compiler, desc, 0); // + UML_LABEL(block, skip); // skip: + } + else + generate_delay_slot_and_branch(block, compiler, desc, 0); // + return TRUE; + + case 0x07: /* BGTZ - MIPS I */ + UML_CMP(block, R32(RSREG), 0); // dcmp ,0 + UML_JMPc(block, COND_LE, skip = compiler->labelnum++); // jmp skip,LE + generate_delay_slot_and_branch(block, compiler, desc, 0); // + UML_LABEL(block, skip); // skip: + return TRUE; + + + /* ----- immediate arithmetic ----- */ + + case 0x0f: /* LUI - MIPS I */ + if (RTREG != 0) + UML_MOV(block, R32(RTREG), SIMMVAL << 16); // dmov ,SIMMVAL << 16 + return TRUE; + + case 0x08: /* ADDI - MIPS I */ + case 0x09: /* ADDIU - MIPS I */ + if (RTREG != 0) + { + UML_ADD(block, R32(RTREG), R32(RSREG), SIMMVAL); // add i0,,SIMMVAL,V + } + return TRUE; + + case 0x0a: /* SLTI - MIPS I */ + if (RTREG != 0) + { + UML_CMP(block, R32(RSREG), SIMMVAL); // dcmp ,SIMMVAL + UML_SETc(block, COND_L, R32(RTREG)); // dset ,l + } + return TRUE; + + case 0x0b: /* SLTIU - MIPS I */ + if (RTREG != 0) + { + UML_CMP(block, R32(RSREG), SIMMVAL); // dcmp ,SIMMVAL + UML_SETc(block, COND_B, R32(RTREG)); // dset ,b + } + return TRUE; + + + case 0x0c: /* ANDI - MIPS I */ + if (RTREG != 0) + UML_AND(block, R32(RTREG), R32(RSREG), UIMMVAL); // dand ,,UIMMVAL + return TRUE; + + case 0x0d: /* ORI - MIPS I */ + if (RTREG != 0) + UML_OR(block, R32(RTREG), R32(RSREG), UIMMVAL); // dor ,,UIMMVAL + return TRUE; + + case 0x0e: /* XORI - MIPS I */ + if (RTREG != 0) + UML_XOR(block, R32(RTREG), R32(RSREG), UIMMVAL); // dxor ,,UIMMVAL + return TRUE; + + /* ----- memory load operations ----- */ + + case 0x20: /* LB - MIPS I */ + UML_ADD(block, I0, R32(RSREG), SIMMVAL); // add i0,,SIMMVAL + UML_CALLH(block, *m_read8); // callh read8 + if (RTREG != 0) + UML_SEXT(block, R32(RTREG), I0, SIZE_BYTE); // dsext ,i0,byte + if (!in_delay_slot) + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); + return TRUE; + + case 0x21: /* LH - MIPS I */ + UML_ADD(block, I0, R32(RSREG), SIMMVAL); // add i0,,SIMMVAL + UML_CALLH(block, *m_read16); // callh read16 + if (RTREG != 0) + UML_SEXT(block, R32(RTREG), I0, SIZE_WORD); // dsext ,i0,word + if (!in_delay_slot) + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); + return TRUE; + + case 0x23: /* LW - MIPS I */ + UML_ADD(block, I0, R32(RSREG), SIMMVAL); // add i0,,SIMMVAL + UML_CALLH(block, *m_read32); // callh read32 + if (RTREG != 0) + UML_MOV(block, R32(RTREG), I0); + if (!in_delay_slot) + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); + return TRUE; + + case 0x24: /* LBU - MIPS I */ + UML_ADD(block, I0, R32(RSREG), SIMMVAL); // add i0,,SIMMVAL + UML_CALLH(block, *m_read8); // callh read8 + if (RTREG != 0) + UML_AND(block, R32(RTREG), I0, 0xff); // dand ,i0,0xff + if (!in_delay_slot) + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); + return TRUE; + + case 0x25: /* LHU - MIPS I */ + UML_ADD(block, I0, R32(RSREG), SIMMVAL); // add i0,,SIMMVAL + UML_CALLH(block, *m_read16); // callh read16 + if (RTREG != 0) + UML_AND(block, R32(RTREG), I0, 0xffff); // dand ,i0,0xffff + if (!in_delay_slot) + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); + return TRUE; + + case 0x32: /* LWC2 - MIPS I */ + return m_cop2->generate_lwc2(block, compiler, desc); + + + /* ----- memory store operations ----- */ + + case 0x28: /* SB - MIPS I */ + UML_ADD(block, I0, R32(RSREG), SIMMVAL); // add i0,,SIMMVAL + UML_MOV(block, I1, R32(RTREG)); // mov i1, + UML_CALLH(block, *m_write8); // callh write8 + if (!in_delay_slot) + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); + return TRUE; + + case 0x29: /* SH - MIPS I */ + UML_ADD(block, I0, R32(RSREG), SIMMVAL); // add i0,,SIMMVAL + UML_MOV(block, I1, R32(RTREG)); // mov i1, + UML_CALLH(block, *m_write16); // callh write16 + if (!in_delay_slot) + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); + return TRUE; + + case 0x2b: /* SW - MIPS I */ + UML_ADD(block, I0, R32(RSREG), SIMMVAL); // add i0,,SIMMVAL + UML_MOV(block, I1, R32(RTREG)); // mov i1, + UML_CALLH(block, *m_write32); // callh write32 + if (!in_delay_slot) + generate_update_cycles(block, compiler, desc->pc + 4, TRUE); + return TRUE; + + case 0x3a: /* SWC2 - MIPS I */ + return m_cop2->generate_swc2(block, compiler, desc); + + /* ----- coprocessor instructions ----- */ + + case 0x10: /* COP0 - MIPS I */ + return generate_cop0(block, compiler, desc); + + case 0x12: /* COP2 - MIPS I */ + return m_cop2->generate_cop2(block, compiler, desc); + + + /* ----- unimplemented/illegal instructions ----- */ + + //default: /* ??? */ invalid_instruction(op); break; + } + + return FALSE; +} + + +/*------------------------------------------------- + generate_special - compile opcodes in the + 'SPECIAL' group +-------------------------------------------------*/ + +int rsp_device::generate_special(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) +{ + UINT32 op = desc->opptr.l[0]; + UINT8 opswitch = op & 63; + //code_label skip; + + switch (opswitch) + { + /* ----- shift instructions ----- */ + + case 0x00: /* SLL - MIPS I */ + if (RDREG != 0) + { + UML_SHL(block, R32(RDREG), R32(RTREG), SHIFT); + } + return TRUE; + + case 0x02: /* SRL - MIPS I */ + if (RDREG != 0) + { + UML_SHR(block, R32(RDREG), R32(RTREG), SHIFT); + } + return TRUE; + + case 0x03: /* SRA - MIPS I */ + if (RDREG != 0) + { + UML_SAR(block, R32(RDREG), R32(RTREG), SHIFT); + } + return TRUE; + + case 0x04: /* SLLV - MIPS I */ + if (RDREG != 0) + { + UML_SHL(block, R32(RDREG), R32(RTREG), R32(RSREG)); + } + return TRUE; + + case 0x06: /* SRLV - MIPS I */ + if (RDREG != 0) + { + UML_SHR(block, R32(RDREG), R32(RTREG), R32(RSREG)); + } + return TRUE; + + case 0x07: /* SRAV - MIPS I */ + if (RDREG != 0) + { + UML_SAR(block, R32(RDREG), R32(RTREG), R32(RSREG)); + } + return TRUE; + + /* ----- basic arithmetic ----- */ + + case 0x20: /* ADD - MIPS I */ + case 0x21: /* ADDU - MIPS I */ + if (RDREG != 0) + { + UML_ADD(block, R32(RDREG), R32(RSREG), R32(RTREG)); + } + return TRUE; + + case 0x22: /* SUB - MIPS I */ + case 0x23: /* SUBU - MIPS I */ + if (RDREG != 0) + { + UML_SUB(block, R32(RDREG), R32(RSREG), R32(RTREG)); + } + return TRUE; + + /* ----- basic logical ops ----- */ + + case 0x24: /* AND - MIPS I */ + if (RDREG != 0) + { + UML_AND(block, R32(RDREG), R32(RSREG), R32(RTREG)); // dand ,, + } + return TRUE; + + case 0x25: /* OR - MIPS I */ + if (RDREG != 0) + { + UML_OR(block, R32(RDREG), R32(RSREG), R32(RTREG)); // dor ,, + } + return TRUE; + + case 0x26: /* XOR - MIPS I */ + if (RDREG != 0) + { + UML_XOR(block, R32(RDREG), R32(RSREG), R32(RTREG)); // dxor ,, + } + return TRUE; + + case 0x27: /* NOR - MIPS I */ + if (RDREG != 0) + { + UML_OR(block, I0, R32(RSREG), R32(RTREG)); // dor i0,, + UML_XOR(block, R32(RDREG), I0, (UINT64)~0); // dxor ,i0,~0 + } + return TRUE; + + + /* ----- basic comparisons ----- */ + + case 0x2a: /* SLT - MIPS I */ + if (RDREG != 0) + { + UML_CMP(block, R32(RSREG), R32(RTREG)); // dcmp , + UML_SETc(block, COND_L, R32(RDREG)); // dset ,l + } + return TRUE; + + case 0x2b: /* SLTU - MIPS I */ + if (RDREG != 0) + { + UML_CMP(block, R32(RSREG), R32(RTREG)); // dcmp , + UML_SETc(block, COND_B, R32(RDREG)); // dset ,b + } + return TRUE; + + + /* ----- jumps and branches ----- */ + + case 0x08: /* JR - MIPS I */ + generate_delay_slot_and_branch(block, compiler, desc, 0); // + return TRUE; + + case 0x09: /* JALR - MIPS I */ + generate_delay_slot_and_branch(block, compiler, desc, RDREG); // + return TRUE; + + + /* ----- system calls ----- */ + + case 0x0d: /* BREAK - MIPS I */ + UML_MOV(block, mem(&m_rsp_state->arg0), 3); // mov [arg0],3 + UML_CALLC(block, cfunc_sp_set_status_cb, this); // callc cfunc_sp_set_status_cb + UML_MOV(block, mem(&m_rsp_state->icount), 0); // mov icount, #0 + UML_MOV(block, mem(&m_rsp_state->jmpdest), desc->targetpc); + + generate_branch(block, compiler, desc); + + UML_EXIT(block, EXECUTE_OUT_OF_CYCLES); + return TRUE; + } + return FALSE; +} + + + +/*------------------------------------------------- + generate_regimm - compile opcodes in the + 'REGIMM' group +-------------------------------------------------*/ + +int rsp_device::generate_regimm(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) +{ + UINT32 op = desc->opptr.l[0]; + UINT8 opswitch = RTREG; + code_label skip; + + switch (opswitch) + { + case 0x00: /* BLTZ */ + case 0x10: /* BLTZAL */ + if (RSREG != 0) + { + UML_CMP(block, R32(RSREG), 0); // dcmp ,0 + UML_JMPc(block, COND_GE, skip = compiler->labelnum++); // jmp skip,GE + generate_delay_slot_and_branch(block, compiler, desc, (opswitch & 0x10) ? 31 : 0); + // + UML_LABEL(block, skip); // skip: + } + return TRUE; + + case 0x01: /* BGEZ */ + case 0x11: /* BGEZAL */ + if (RSREG != 0) + { + UML_CMP(block, R32(RSREG), 0); // dcmp ,0 + UML_JMPc(block, COND_L, skip = compiler->labelnum++); // jmp skip,L + generate_delay_slot_and_branch(block, compiler, desc, (opswitch & 0x10) ? 31 : 0); + // + UML_LABEL(block, skip); // skip: + } + else + generate_delay_slot_and_branch(block, compiler, desc, (opswitch & 0x10) ? 31 : 0); + // + return TRUE; + } + return FALSE; +} + + +/*------------------------------------------------- + generate_cop0 - compile COP0 opcodes +-------------------------------------------------*/ + +int rsp_device::generate_cop0(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) +{ + UINT32 op = desc->opptr.l[0]; + UINT8 opswitch = RSREG; + + switch (opswitch) + { + case 0x00: /* MFCz */ + if (RTREG != 0) + { + UML_MOV(block, mem(&m_rsp_state->arg0), RDREG); // mov [arg0], + UML_MOV(block, mem(&m_rsp_state->arg1), RTREG); // mov [arg1], + UML_CALLC(block, cfunc_get_cop0_reg, this); // callc cfunc_get_cop0_reg + if(RDREG == 2) + { + generate_update_cycles(block, compiler, mem(&m_rsp_state->pc), TRUE); + UML_HASHJMP(block, 0, mem(&m_rsp_state->pc), *m_nocode); + } + } + return TRUE; + + case 0x04: /* MTCz */ + UML_MOV(block, mem(&m_rsp_state->arg0), RDREG); // mov [arg0], + UML_MOV(block, mem(&m_rsp_state->arg1), R32(RTREG)); // mov [arg1],rtreg + UML_CALLC(block, cfunc_set_cop0_reg, this); // callc cfunc_set_cop0_reg + return TRUE; + } + + return FALSE; +} + +/*************************************************************************** + CODE LOGGING HELPERS +***************************************************************************/ + +/*------------------------------------------------- + log_add_disasm_comment - add a comment + including disassembly of a RSP instruction +-------------------------------------------------*/ + +void rsp_device::log_add_disasm_comment(drcuml_block *block, UINT32 pc, UINT32 op) +{ + if (m_drcuml->logging()) + { + char buffer[100]; + rsp_dasm_one(buffer, pc, op); + block->append_comment("%08X: %s", pc, buffer); // comment + } +} diff --git a/src/devices/cpu/rsp/rspfe.c b/src/devices/cpu/rsp/rspfe.c new file mode 100644 index 00000000000..7a80fb6347b --- /dev/null +++ b/src/devices/cpu/rsp/rspfe.c @@ -0,0 +1,306 @@ +// license:BSD-3-Clause +// copyright-holders:Ryan Holtz +/*************************************************************************** + + rspfe.c + + Front-end for RSP recompiler + +***************************************************************************/ + +#include "emu.h" +#include "rspfe.h" +#include "rsp.h" + +//************************************************************************** +// RSP FRONTEND +//************************************************************************** + +//------------------------------------------------- +// rsp_frontend - constructor +//------------------------------------------------- + +rsp_frontend::rsp_frontend(rsp_device &rsp, UINT32 window_start, UINT32 window_end, UINT32 max_sequence) + : drc_frontend(rsp, window_start, window_end, max_sequence), + m_rsp(rsp) +{ +} + + +//------------------------------------------------- +// describe - build a description of a single +// instruction +//------------------------------------------------- + +bool rsp_frontend::describe(opcode_desc &desc, const opcode_desc *prev) +{ + UINT32 op, opswitch; + + // fetch the opcode + op = desc.opptr.l[0] = m_rsp.m_direct->read_dword(desc.physpc | 0x1000); + + // all instructions are 4 bytes and default to a single cycle each + desc.length = 4; + desc.cycles = 1; + + // parse the instruction + opswitch = op >> 26; + switch (opswitch) + { + case 0x00: // SPECIAL + return describe_special(op, desc); + + case 0x01: // REGIMM + return describe_regimm(op, desc); + + case 0x10: // COP0 + return describe_cop0(op, desc); + + case 0x12: // COP2 + return describe_cop2(op, desc); + + case 0x02: // J + desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; + desc.targetpc = ((LIMMVAL << 2) & 0x00000fff) | 0x1000; + desc.delayslots = 1; + return true; + + case 0x03: // JAL + desc.regout[0] |= REGFLAG_R(31); + desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; + desc.targetpc = ((LIMMVAL << 2) & 0x00000fff) | 0x1000; + desc.delayslots = 1; + return true; + + case 0x04: // BEQ + case 0x05: // BNE + if ((opswitch == 0x04 || opswitch == 0x14) && RSREG == RTREG) + desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; + else + { + desc.regin[0] |= REGFLAG_R(RSREG) | REGFLAG_R(RTREG); + desc.flags |= OPFLAG_IS_CONDITIONAL_BRANCH; + } + desc.targetpc = ((desc.pc + 4 + SIMMVAL * 4) & 0x00000fff) | 0x1000; + desc.delayslots = 1; + desc.skipslots = (opswitch & 0x10) ? 1 : 0; + return true; + + case 0x06: // BLEZ + case 0x07: // BGTZ + if ((opswitch == 0x06 || opswitch == 0x16) && RSREG == 0) + desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; + else + { + desc.regin[0] |= REGFLAG_R(RSREG); + desc.flags |= OPFLAG_IS_CONDITIONAL_BRANCH; + } + desc.targetpc = ((desc.pc + 4 + SIMMVAL * 4) & 0x00000fff) | 0x1000; + desc.delayslots = 1; + desc.skipslots = (opswitch & 0x10) ? 1 : 0; + return true; + + case 0x08: // ADDI + desc.regin[0] |= REGFLAG_R(RSREG); + desc.regout[0] |= REGFLAG_R(RTREG); + return true; + + case 0x09: // ADDIU + case 0x0a: // SLTI + case 0x0b: // SLTIU + case 0x0c: // ANDI + case 0x0d: // ORI + case 0x0e: // XORI + desc.regin[0] |= REGFLAG_R(RSREG); + desc.regout[0] |= REGFLAG_R(RTREG); + return true; + + case 0x0f: // LUI + desc.regout[0] |= REGFLAG_R(RTREG); + return true; + + case 0x20: // LB + case 0x21: // LH + case 0x23: // LW + case 0x24: // LBU + case 0x25: // LHU + case 0x27: // LWU + desc.regin[0] |= REGFLAG_R(RSREG); + desc.regout[0] |= REGFLAG_R(RTREG); + desc.flags |= OPFLAG_READS_MEMORY; + return true; + + case 0x28: // SB + case 0x29: // SH + case 0x2b: // SW + desc.regin[0] |= REGFLAG_R(RSREG) | REGFLAG_R(RTREG); + desc.flags |= OPFLAG_WRITES_MEMORY; + return true; + + case 0x32: // LWC2 + desc.regin[0] |= REGFLAG_R(RSREG); + desc.flags |= OPFLAG_READS_MEMORY; + return true; + + case 0x3a: // SWC2 + desc.regin[0] |= REGFLAG_R(RSREG); + desc.flags |= OPFLAG_WRITES_MEMORY; + return true; + } + + return false; +} + + +//------------------------------------------------- +// describe_special - build a description of a +// single instruction in the 'special' group +//------------------------------------------------- + +bool rsp_frontend::describe_special(UINT32 op, opcode_desc &desc) +{ + switch (op & 63) + { + case 0x00: // SLL + case 0x02: // SRL + case 0x03: // SRA + desc.regin[0] |= REGFLAG_R(RTREG); + desc.regout[0] |= REGFLAG_R(RDREG); + return true; + + case 0x04: // SLLV + case 0x06: // SRLV + case 0x07: // SRAV + case 0x21: // ADDU + case 0x23: // SUBU + case 0x24: // AND + case 0x25: // OR + case 0x26: // XOR + case 0x27: // NOR + case 0x2a: // SLT + case 0x2b: // SLTU + desc.regin[0] |= REGFLAG_R(RSREG) | REGFLAG_R(RTREG); + desc.regout[0] |= REGFLAG_R(RDREG); + return true; + + case 0x20: // ADD + case 0x22: // SUB + desc.regin[0] |= REGFLAG_R(RSREG) | REGFLAG_R(RTREG); + desc.regout[0] |= REGFLAG_R(RDREG); + return true; + + case 0x08: // JR + desc.regin[0] |= REGFLAG_R(RSREG); + desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; + desc.targetpc = BRANCH_TARGET_DYNAMIC; + desc.delayslots = 1; + return true; + + case 0x09: // JALR + desc.regin[0] |= REGFLAG_R(RSREG); + desc.regout[0] |= REGFLAG_R(RDREG); + desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; + desc.targetpc = BRANCH_TARGET_DYNAMIC; + desc.delayslots = 1; + return true; + + case 0x0d: // BREAK + desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; + desc.targetpc = (op >> 5) & 0x000fffff; + return true; + } + + return false; +} + + +//------------------------------------------------- +// describe_regimm - build a description of a +// single instruction in the 'regimm' group +//------------------------------------------------- + +bool rsp_frontend::describe_regimm(UINT32 op, opcode_desc &desc) +{ + switch (RTREG) + { + case 0x00: // BLTZ + case 0x01: // BGEZ + if (RTREG == 0x01 && RSREG == 0) + desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; + else + { + desc.regin[0] |= REGFLAG_R(RSREG); + desc.flags |= OPFLAG_IS_CONDITIONAL_BRANCH; + } + desc.targetpc = ((desc.pc + 4 + SIMMVAL * 4) & 0x00000fff) | 0x1000; + desc.delayslots = 1; + desc.skipslots = (RTREG & 0x02) ? 1 : 0; + return true; + + case 0x10: // BLTZAL + case 0x11: // BGEZAL + if (RTREG == 0x11 && RSREG == 0) + desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; + else + { + desc.regin[0] |= REGFLAG_R(RSREG); + desc.flags |= OPFLAG_IS_CONDITIONAL_BRANCH; + } + desc.regout[0] |= REGFLAG_R(31); + desc.targetpc = ((desc.pc + 4 + SIMMVAL * 4) & 0x00000fff) | 0x1000; + desc.delayslots = 1; + desc.skipslots = (RTREG & 0x02) ? 1 : 0; + return true; + } + + return false; +} + + +//------------------------------------------------- +// describe_cop0 - build a description of a +// single instruction in the COP0 group +//------------------------------------------------- + +bool rsp_frontend::describe_cop0(UINT32 op, opcode_desc &desc) +{ + switch (RSREG) + { + case 0x00: // MFCz + desc.regout[0] |= REGFLAG_R(RTREG); + return true; + + case 0x04: // MTCz + desc.regin[0] |= REGFLAG_R(RTREG); + if(RDREG == 2) // SP_RD_LEN, initiating DMA + { + desc.flags |= OPFLAG_END_SEQUENCE; + } + return true; + } + + return false; +} + +//------------------------------------------------- +// describe_cop2 - build a description of a +// single instruction in the COP2 group +//------------------------------------------------- + +bool rsp_frontend::describe_cop2(UINT32 op, opcode_desc &desc) +{ + switch (RSREG) + { + case 0x00: // MFCz + case 0x02: // CFCz + desc.regout[0] |= REGFLAG_R(RTREG); + return true; + + case 0x04: // MTCz + case 0x06: // CTCz + desc.regin[0] |= REGFLAG_R(RTREG); + return true; + } + + return false; +} diff --git a/src/devices/cpu/rsp/rspfe.h b/src/devices/cpu/rsp/rspfe.h new file mode 100644 index 00000000000..bdfd7a83fb7 --- /dev/null +++ b/src/devices/cpu/rsp/rspfe.h @@ -0,0 +1,56 @@ +// license:BSD-3-Clause +// copyright-holders:Ryan Holtz +/*************************************************************************** + + rspfe.h + + Front-end for RSP recompiler + +***************************************************************************/ + +#pragma once + +#ifndef __RSPFE_H__ +#define __RSPFE_H__ + +#include "rsp.h" +#include "cpu/drcfe.h" + + +//************************************************************************** +// CONSTANTS +//************************************************************************** + +// register flags 0 +#define REGFLAG_R(n) (((n) == 0) ? 0 : (1 << (n))) + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class rsp_frontend : public drc_frontend +{ +public: + // construction/destruction + rsp_frontend(rsp_device &rsp, UINT32 window_start, UINT32 window_end, UINT32 max_sequence); + +protected: + // required overrides + virtual bool describe(opcode_desc &desc, const opcode_desc *prev); + +private: + // internal helpers + bool describe_special(UINT32 op, opcode_desc &desc); + bool describe_regimm(UINT32 op, opcode_desc &desc); + bool describe_cop0(UINT32 op, opcode_desc &desc); + bool describe_cop2(UINT32 op, opcode_desc &desc); + + // internal state + rsp_device &m_rsp; +}; + + + +#endif /* __RSPFE_H__ */ diff --git a/src/devices/cpu/rsp/vabs.h b/src/devices/cpu/rsp/vabs.h new file mode 100644 index 00000000000..273841b9610 --- /dev/null +++ b/src/devices/cpu/rsp/vabs.h @@ -0,0 +1,15 @@ +// license:BSD-3-Clause +// copyright-holders:Tyler J. Stachecki,Ryan Holtz + +inline rsp_vec_t vec_vabs(rsp_vec_t vs, rsp_vec_t vt, rsp_vec_t zero, rsp_vec_t *acc_lo) +{ + rsp_vec_t vs_zero = _mm_cmpeq_epi16(vs, zero); + rsp_vec_t sign_lt = _mm_srai_epi16(vs, 15); + rsp_vec_t vd = _mm_andnot_si128(vs_zero, vt); + + // Careful: if VT = 0x8000 and VS is negative, + // acc_lo will be 0x8000 but vd will be 0x7FFF. + vd = _mm_xor_si128(vd, sign_lt); + *acc_lo = _mm_sub_epi16(vd, sign_lt); + return _mm_subs_epi16(vd, sign_lt); +} diff --git a/src/devices/cpu/rsp/vadd.h b/src/devices/cpu/rsp/vadd.h new file mode 100644 index 00000000000..16009e53287 --- /dev/null +++ b/src/devices/cpu/rsp/vadd.h @@ -0,0 +1,16 @@ +// license:BSD-3-Clause +// copyright-holders:Tyler J. Stachecki,Ryan Holtz + +inline rsp_vec_t vec_vadd(rsp_vec_t vs, rsp_vec_t vt, rsp_vec_t carry, rsp_vec_t *acc_lo) +{ + // VCC uses unsaturated arithmetic. + rsp_vec_t vd = _mm_add_epi16(vs, vt); + *acc_lo = _mm_sub_epi16(vd, carry); + + // VD is the signed sum of the two sources and the carry. Since we + // have to saturate the sum of all three, we have to be clever. + rsp_vec_t minimum = _mm_min_epi16(vs, vt); + rsp_vec_t maximum = _mm_max_epi16(vs, vt); + minimum = _mm_subs_epi16(minimum, carry); + return _mm_adds_epi16(minimum, maximum); +} diff --git a/src/devices/cpu/rsp/vaddc.h b/src/devices/cpu/rsp/vaddc.h new file mode 100644 index 00000000000..0ebd30cbd31 --- /dev/null +++ b/src/devices/cpu/rsp/vaddc.h @@ -0,0 +1,13 @@ +// license:BSD-3-Clause +// copyright-holders:Tyler J. Stachecki,Ryan Holtz + +inline rsp_vec_t vec_vaddc(rsp_vec_t vs, rsp_vec_t vt, rsp_vec_t zero, rsp_vec_t *sn) +{ + rsp_vec_t sat_sum = _mm_adds_epu16(vs, vt); + rsp_vec_t unsat_sum = _mm_add_epi16(vs, vt); + + *sn = _mm_cmpeq_epi16(sat_sum, unsat_sum); + *sn = _mm_cmpeq_epi16(*sn, zero); + + return unsat_sum; +} diff --git a/src/devices/cpu/rsp/vand.h b/src/devices/cpu/rsp/vand.h new file mode 100644 index 00000000000..4349227fdd3 --- /dev/null +++ b/src/devices/cpu/rsp/vand.h @@ -0,0 +1,9 @@ +// license:BSD-3-Clause +// copyright-holders:Tyler J. Stachecki,Ryan Holtz + +inline rsp_vec_t vec_vand_vnand(UINT32 iw, rsp_vec_t vs, rsp_vec_t vt) { + rsp_vec_t vmask = _mm_load_si128((rsp_vec_t *) m_vec_helpers.logic_mask[iw & 0x1]); + + rsp_vec_t vd = _mm_and_si128(vs, vt); + return _mm_xor_si128(vd, vmask); +} diff --git a/src/devices/cpu/rsp/vch.h b/src/devices/cpu/rsp/vch.h new file mode 100644 index 00000000000..6abac437a2c --- /dev/null +++ b/src/devices/cpu/rsp/vch.h @@ -0,0 +1,57 @@ +// license:BSD-3-Clause +// copyright-holders:Tyler J. Stachecki,Ryan Holtz + +inline rsp_vec_t vec_vch(rsp_vec_t vs, rsp_vec_t vt, rsp_vec_t zero, rsp_vec_t *ge, rsp_vec_t *le, rsp_vec_t *eq, rsp_vec_t *sign, rsp_vec_t *vce) { + // sign = (vs ^ vt) < 0 + *sign = _mm_xor_si128(vs, vt); + *sign = _mm_cmplt_epi16(*sign, zero); + + // sign_negvt = sign ? -vt : vt + rsp_vec_t sign_negvt = _mm_xor_si128(vt, *sign); + sign_negvt = _mm_sub_epi16(sign_negvt, *sign); + + // Compute diff, diff_zero: + rsp_vec_t diff = _mm_sub_epi16(vs, sign_negvt); + rsp_vec_t diff_zero = _mm_cmpeq_epi16(diff, zero); + + // Compute le/ge: + rsp_vec_t vt_neg = _mm_cmplt_epi16(vt, zero); + rsp_vec_t diff_lez = _mm_cmpgt_epi16(diff, zero); + rsp_vec_t diff_gez = _mm_or_si128(diff_lez, diff_zero); + diff_lez = _mm_cmpeq_epi16(zero, diff_lez); + +#if (defined(__SSE4_1__) || defined(_MSC_VER)) + *ge = _mm_blendv_epi8(diff_gez, vt_neg, *sign); + *le = _mm_blendv_epi8(vt_neg, diff_lez, *sign); +#else + *ge = _mm_and_si128(*sign, vt_neg); + diff_gez = _mm_andnot_si128(*sign, diff_gez); + *ge = _mm_or_si128(*ge, diff_gez); + + *le = _mm_and_si128(*sign, diff_lez); + diff_lez = _mm_andnot_si128(*sign, vt_neg); + *le = _mm_or_si128(*le, diff_lez); +#endif + + // Compute vce: + *vce = _mm_cmpeq_epi16(diff, *sign); + *vce = _mm_and_si128(*vce, *sign); + + // Compute !eq: + *eq = _mm_or_si128(diff_zero, *vce); + *eq = _mm_cmpeq_epi16(*eq, zero); + + // Compute result: +#if (defined(__SSE4_1__) || defined(_MSC_VER)) + rsp_vec_t diff_sel_mask = _mm_blendv_epi8(*ge, *le, *sign); + return _mm_blendv_epi8(vs, sign_negvt, diff_sel_mask); +#else + diff_lez = _mm_and_si128(*sign, *le); + diff_gez = _mm_andnot_si128(*sign, *ge); + rsp_vec_t diff_sel_mask = _mm_or_si128(diff_lez, diff_gez); + + diff_lez = _mm_and_si128(diff_sel_mask, sign_negvt); + diff_gez = _mm_andnot_si128(diff_sel_mask, vs); + return _mm_or_si128(diff_lez, diff_gez); +#endif +} diff --git a/src/devices/cpu/rsp/vcl.h b/src/devices/cpu/rsp/vcl.h new file mode 100644 index 00000000000..e09a13d5a8e --- /dev/null +++ b/src/devices/cpu/rsp/vcl.h @@ -0,0 +1,65 @@ +// license:BSD-3-Clause +// copyright-holders:Tyler J. Stachecki,Ryan Holtz + +inline rsp_vec_t vec_vcl(rsp_vec_t vs, rsp_vec_t vt, rsp_vec_t zero, rsp_vec_t *ge, rsp_vec_t *le, rsp_vec_t eq, rsp_vec_t sign, rsp_vec_t vce) +{ + // sign_negvt = sign ? -vt : vt + rsp_vec_t sign_negvt = _mm_xor_si128(vt, sign); + sign_negvt = _mm_sub_epi16(sign_negvt, sign); + + // Compute diff, diff_zero, ncarry, and nvce: + // Note: diff = sign ? (vs + vt) : (vs - vt). + rsp_vec_t diff = _mm_sub_epi16(vs, sign_negvt); + rsp_vec_t ncarry = _mm_adds_epu16(vs, vt); + ncarry = _mm_cmpeq_epi16(diff, ncarry); + rsp_vec_t nvce = _mm_cmpeq_epi16(vce, zero); + rsp_vec_t diff_zero = _mm_cmpeq_epi16(diff, zero); + + // Compute results for if (sign && ne): + rsp_vec_t le_case1 = _mm_and_si128(diff_zero, ncarry); + le_case1 = _mm_and_si128(nvce, le_case1); + rsp_vec_t le_case2 = _mm_or_si128(diff_zero, ncarry); + le_case2 = _mm_and_si128(vce, le_case2); + rsp_vec_t le_eq = _mm_or_si128(le_case1, le_case2); + + // Compute results for if (!sign && ne): + rsp_vec_t ge_eq = _mm_subs_epu16(vt, vs); + ge_eq = _mm_cmpeq_epi16(ge_eq, zero); + + // Blend everything together. Caveat: we don't update + // the results of ge/le if ne is false, so be careful. + rsp_vec_t do_le = _mm_andnot_si128(eq, sign); +#if (defined(__SSE4_1__) || defined(_MSC_VER)) + *le = _mm_blendv_epi8(*le, le_eq, do_le); +#else + le_eq = _mm_and_si128(do_le, le_eq); + *le = _mm_andnot_si128(do_le, *le); + *le = _mm_or_si128(le_eq, *le); +#endif + + rsp_vec_t do_ge = _mm_or_si128(sign, eq); +#if (defined(__SSE4_1__) || defined(_MSC_VER)) + *ge = _mm_blendv_epi8(ge_eq, *ge, do_ge); +#else + *ge = _mm_and_si128(do_ge, *ge); + ge_eq = _mm_andnot_si128(do_ge, ge_eq); + *ge = _mm_or_si128(ge_eq, *ge); +#endif + + // Mux the result based on the value of sign. +#if (defined(__SSE4_1__) || defined(_MSC_VER)) + rsp_vec_t mux_mask = _mm_blendv_epi8(*ge, *le, sign); +#else + do_le = _mm_and_si128(sign, *le); + do_ge = _mm_andnot_si128(sign, *ge); + rsp_vec_t mux_mask = _mm_or_si128(do_le, do_ge); +#endif + +#if (defined(__SSE4_1__) || defined(_MSC_VER)) + return _mm_blendv_epi8(vs, sign_negvt, mux_mask); +#else + sign_negvt = _mm_and_si128(mux_mask, sign_negvt); + vs = _mm_andnot_si128(mux_mask, vs); + return _mm_or_si128(sign_negvt, vs); +#endif +} diff --git a/src/devices/cpu/rsp/vcmp.h b/src/devices/cpu/rsp/vcmp.h new file mode 100644 index 00000000000..7ae4dc4c444 --- /dev/null +++ b/src/devices/cpu/rsp/vcmp.h @@ -0,0 +1,49 @@ +// license:BSD-3-Clause +// copyright-holders:Tyler J. Stachecki,Ryan Holtz + +inline rsp_vec_t vec_veq_vge_vlt_vne(UINT32 iw, rsp_vec_t vs, rsp_vec_t vt, rsp_vec_t zero, rsp_vec_t *le, rsp_vec_t eq, rsp_vec_t sign) +{ + rsp_vec_t equal = _mm_cmpeq_epi16(vs, vt); + + if (iw & 0x2) // VNE & VGE + { + if (iw & 0x1) // VGE + { + rsp_vec_t gt = _mm_cmpgt_epi16(vs, vt); + rsp_vec_t equalsign = _mm_and_si128(eq, sign); + + equal = _mm_andnot_si128(equalsign, equal); + *le = _mm_or_si128(gt, equal); + } + else // VNE + { + rsp_vec_t nequal = _mm_cmpeq_epi16(equal, zero); + + *le = _mm_and_si128(eq, equal); + *le = _mm_or_si128(*le, nequal); + } + } + else // VEQ & VLT + { + if (iw & 0x1) // VEQ + { + *le = _mm_andnot_si128(eq, equal); + } + else // VLT + { + rsp_vec_t lt = _mm_cmplt_epi16(vs, vt); + + equal = _mm_and_si128(eq, equal); + equal = _mm_and_si128(sign, equal); + *le = _mm_or_si128(lt, equal); + } + } + +#if (defined(__SSE4_1__) || defined(_MSC_VER)) + return _mm_blendv_epi8(vt, vs, *le); +#else + vs = _mm_and_si128(*le, vs); + vt = _mm_andnot_si128(*le, vt); + return _mm_or_si128(vs, vt); +#endif +} diff --git a/src/devices/cpu/rsp/vcr.h b/src/devices/cpu/rsp/vcr.h new file mode 100644 index 00000000000..78f78c66244 --- /dev/null +++ b/src/devices/cpu/rsp/vcr.h @@ -0,0 +1,35 @@ +// license:BSD-3-Clause +// copyright-holders:Tyler J. Stachecki,Ryan Holtz + +inline rsp_vec_t vec_vcr(rsp_vec_t vs, rsp_vec_t vt, rsp_vec_t zero, rsp_vec_t *ge, rsp_vec_t *le) { + // sign = (vs ^ vt) < 0 + rsp_vec_t sign = _mm_xor_si128(vs, vt); + sign = _mm_srai_epi16(sign, 15); + + // Compute le + rsp_vec_t diff_lez = _mm_and_si128(vs, sign); + diff_lez = _mm_add_epi16(diff_lez, vt); + *le = _mm_srai_epi16(diff_lez, 15); + + // Compute ge + rsp_vec_t diff_gez = _mm_or_si128(vs, sign); + diff_gez = _mm_min_epi16(diff_gez, vt); + *ge = _mm_cmpeq_epi16(diff_gez, vt); + + // sign_notvt = sn ? ~vt : vt + rsp_vec_t sign_notvt = _mm_xor_si128(vt, sign); + + // Compute result: +#if (defined(__SSE4_1__) || defined(_MSC_VER)) + rsp_vec_t diff_sel_mask = _mm_blendv_epi8(*ge, *le, sign); + return _mm_blendv_epi8(vs, sign_notvt, diff_sel_mask); +#else + rsp_vec_t diff_sel_mask = _mm_sub_epi16(*le, *ge); + diff_sel_mask = _mm_and_si128(diff_sel_mask, sign); + diff_sel_mask = _mm_add_epi16(diff_sel_mask, *ge); + + zero = _mm_sub_epi16(sign_notvt, vs); + zero = _mm_and_si128(zero, diff_sel_mask); + return _mm_add_epi16(zero, vs); +#endif +} diff --git a/src/devices/cpu/rsp/vdivh.h b/src/devices/cpu/rsp/vdivh.h new file mode 100644 index 00000000000..286aa8a3ca7 --- /dev/null +++ b/src/devices/cpu/rsp/vdivh.h @@ -0,0 +1,12 @@ +// license:BSD-3-Clause +// copyright-holders:Tyler J. Stachecki,Ryan Holtz + +inline rsp_vec_t vec_vdivh(UINT32 src, UINT32 e, UINT32 dest, UINT32 de) +{ + // Get the element from VT. + m_div_in = m_v[src].s[e & 0x7]; + + // Write out the upper part of the result. + m_v[dest].s[de & 0x7] = m_div_out; + return vec_load_unshuffled_operand(m_v[dest].s); +} diff --git a/src/devices/cpu/rsp/vldst.h b/src/devices/cpu/rsp/vldst.h new file mode 100644 index 00000000000..4a38af029d4 --- /dev/null +++ b/src/devices/cpu/rsp/vldst.h @@ -0,0 +1,69 @@ +// license:BSD-3-Clause +// copyright-holders:Tyler J. Stachecki,Ryan Holtz + +// LBV, LDV, LLV, LSV, SBV, SDV, SLV, SSV +inline void vec_lbdlsv_sbdlsv(UINT32 iw, UINT32 rs) +{ + const UINT32 shift_and_idx = (iw >> 11) & 0x3; + rsp_vec_t dqm = _mm_loadl_epi64((rsp_vec_t *) (m_vec_helpers.bdls_lut[shift_and_idx])); + + const UINT32 addr = (rs + (sign_extend_6(iw) << shift_and_idx)) & 0xfff; + const UINT32 element = (iw >> 7) & 0xf; + UINT16* regp = m_v[(iw >> 16) & 0x1f].s; + + if (iw >> 29 & 0x1) + { + vec_store_group1(addr, element, regp, vec_load_unshuffled_operand(regp), dqm); + } + else + { + vec_load_group1(addr, element, regp, vec_load_unshuffled_operand(regp), dqm); + } +} + +// LPV, LUV, SPV, SUV +inline void vec_lfhpuv_sfhpuv(UINT32 iw, UINT32 rs) +{ + static const enum rsp_mem_request_type fhpu_type_lut[4] = { + RSP_MEM_REQUEST_PACK, + RSP_MEM_REQUEST_UPACK, + RSP_MEM_REQUEST_HALF, + RSP_MEM_REQUEST_FOURTH + }; + + const UINT32 addr = (rs + (sign_extend_6(iw) << 3)) & 0xfff; + const UINT32 element = (iw >> 7) & 0xf; + UINT16* regp = m_v[(iw >> 16) & 0x1f].s; + + rsp_mem_request_type request_type = fhpu_type_lut[((iw >> 11) & 0x1f) - 6]; + if ((iw >> 29) & 0x1) + { + vec_store_group2(addr, element, regp, vec_load_unshuffled_operand(regp), _mm_setzero_si128(), request_type); + } + else + { + vec_load_group2(addr, element, regp, vec_load_unshuffled_operand(regp), _mm_setzero_si128(), request_type); + } +} + +// LQV, LRV, SQV, SRV +inline void vec_lqrv_sqrv(UINT32 iw, UINT32 rs) +{ + rs &= 0xfff; + + const UINT32 addr = rs + (sign_extend_6(iw) << 4); + const UINT32 element = (iw >> 7) & 0xf; + UINT16* regp = m_v[(iw >> 16) & 0x1f].s; + + memcpy(m_vdqm.s, m_vec_helpers.qr_lut[addr & 0xf], sizeof(m_vdqm.s)); + + rsp_mem_request_type request_type = (iw >> 11 & 0x1) ? RSP_MEM_REQUEST_REST : RSP_MEM_REQUEST_QUAD; + if ((iw >> 29) & 0x1) + { + vec_store_group4(addr, element, regp, vec_load_unshuffled_operand(regp), vec_load_unshuffled_operand(m_vdqm.s), request_type); + } + else + { + vec_load_group4(addr, element, regp, vec_load_unshuffled_operand(regp), vec_load_unshuffled_operand(m_vdqm.s), request_type); + } +} diff --git a/src/devices/cpu/rsp/vmac.h b/src/devices/cpu/rsp/vmac.h new file mode 100644 index 00000000000..ecf921a261c --- /dev/null +++ b/src/devices/cpu/rsp/vmac.h @@ -0,0 +1,57 @@ +// license:BSD-3-Clause +// copyright-holders:Tyler J. Stachecki,Ryan Holtz + +inline rsp_vec_t vec_vmacf_vmacu(UINT32 iw, rsp_vec_t vs, rsp_vec_t vt, rsp_vec_t zero, rsp_vec_t *acc_lo, rsp_vec_t *acc_mid, rsp_vec_t *acc_hi) +{ + // Get the product and shift it over + // being sure to save the carries. + rsp_vec_t lo = _mm_mullo_epi16(vs, vt); + rsp_vec_t hi = _mm_mulhi_epi16(vs, vt); + + rsp_vec_t mid = _mm_slli_epi16(hi, 1); + rsp_vec_t carry = _mm_srli_epi16(lo, 15); + hi = _mm_srai_epi16(hi, 15); + mid = _mm_or_si128(mid, carry); + lo = _mm_slli_epi16(lo, 1); + + // Tricky part: start accumulating everything. + // Get/keep the carry as we'll add it in later. + rsp_vec_t overflow_mask = _mm_adds_epu16(*acc_lo, lo); + *acc_lo = _mm_add_epi16(*acc_lo, lo); + + overflow_mask = _mm_cmpeq_epi16(*acc_lo, overflow_mask); + overflow_mask = _mm_cmpeq_epi16(overflow_mask, zero); + + // Add in the carry. If the middle portion is + // already 0xFFFF and we have a carry, we have + // to carry the all the way up to hi. + mid = _mm_sub_epi16(mid, overflow_mask); + carry = _mm_cmpeq_epi16(mid, zero); + carry = _mm_and_si128(carry, overflow_mask); + hi = _mm_sub_epi16(hi, carry); + + // Accumulate the middle portion. + overflow_mask = _mm_adds_epu16(*acc_mid, mid); + *acc_mid = _mm_add_epi16(*acc_mid, mid); + + overflow_mask = _mm_cmpeq_epi16(*acc_mid, overflow_mask); + overflow_mask = _mm_cmpeq_epi16(overflow_mask, zero); + + // Finish up the accumulation of the... accumulator. + *acc_hi = _mm_add_epi16(*acc_hi, hi); + *acc_hi = _mm_sub_epi16(*acc_hi, overflow_mask); + + if (iw & 0x1) // VMACU + { + rsp_vec_t overflow_hi_mask = _mm_srai_epi16(*acc_hi, 15); + rsp_vec_t overflow_mid_mask = _mm_srai_epi16(*acc_mid, 15); + mid = _mm_or_si128(overflow_mid_mask, *acc_mid); + overflow_mask = _mm_cmpgt_epi16(*acc_hi, zero); + mid = _mm_andnot_si128(overflow_hi_mask, mid); + return _mm_or_si128(overflow_mask, mid); + } + else // VMACF + { + return sclamp_acc_to_mid(*acc_mid, *acc_hi); + } +} diff --git a/src/devices/cpu/rsp/vmov.h b/src/devices/cpu/rsp/vmov.h new file mode 100644 index 00000000000..10a7b1df85f --- /dev/null +++ b/src/devices/cpu/rsp/vmov.h @@ -0,0 +1,9 @@ +// license:BSD-3-Clause +// copyright-holders:Tyler J. Stachecki,Ryan Holtz + +inline rsp_vec_t vec_vmov(UINT32 src, UINT32 e, UINT32 dest, UINT32 de) +{ + // Get the element from VT and write out the upper part of the result. + m_v[dest].s[de & 0x7] = m_v[src].s[e & 0x7]; + return vec_load_unshuffled_operand(m_v[dest].s); +} diff --git a/src/devices/cpu/rsp/vmrg.h b/src/devices/cpu/rsp/vmrg.h new file mode 100644 index 00000000000..ab9be63ef16 --- /dev/null +++ b/src/devices/cpu/rsp/vmrg.h @@ -0,0 +1,13 @@ +// license:BSD-3-Clause +// copyright-holders:Tyler J. Stachecki,Ryan Holtz + +inline rsp_vec_t vec_vmrg(rsp_vec_t vs, rsp_vec_t vt, rsp_vec_t le) +{ +#if (defined(__SSE4_1__) || defined(_MSC_VER)) + return _mm_blendv_epi8(vt, vs, le); +#else + vs = _mm_and_si128(le, vs); + vt = _mm_andnot_si128(le, vt); + return _mm_or_si128(vs, vt); +#endif +} diff --git a/src/devices/cpu/rsp/vmudh.h b/src/devices/cpu/rsp/vmudh.h new file mode 100644 index 00000000000..71c3a38f4fb --- /dev/null +++ b/src/devices/cpu/rsp/vmudh.h @@ -0,0 +1,10 @@ +// license:BSD-3-Clause +// copyright-holders:Tyler J. Stachecki,Ryan Holtz + +inline rsp_vec_t rsp_vmudh(rsp_vec_t vs, rsp_vec_t vt, rsp_vec_t *acc_md, rsp_vec_t *acc_hi) +{ + *acc_md = _mm_mullo_epi16(vs, vt); + *acc_hi = _mm_mulhi_epi16(vs, vt); + + return sclamp_acc_to_mid(*acc_md, *acc_hi); +} diff --git a/src/devices/cpu/rsp/vmul.h b/src/devices/cpu/rsp/vmul.h new file mode 100644 index 00000000000..c8bfc1bbb14 --- /dev/null +++ b/src/devices/cpu/rsp/vmul.h @@ -0,0 +1,39 @@ +// license:BSD-3-Clause +// copyright-holders:Tyler J. Stachecki,Ryan Holtz + +// +// TODO: CHECK ME. +// + +inline rsp_vec_t vec_vmulf_vmulu(UINT32 iw, rsp_vec_t vs, rsp_vec_t vt, rsp_vec_t zero, rsp_vec_t *acc_lo, rsp_vec_t *acc_md, rsp_vec_t *acc_hi) +{ + rsp_vec_t lo = _mm_mullo_epi16(vs, vt); + rsp_vec_t round = _mm_cmpeq_epi16(zero, zero); + rsp_vec_t sign1 = _mm_srli_epi16(lo, 15); + lo = _mm_add_epi16(lo, lo); + round = _mm_slli_epi16(round, 15); + rsp_vec_t hi = _mm_mulhi_epi16(vs, vt); + rsp_vec_t sign2 = _mm_srli_epi16(lo, 15); + *acc_lo = _mm_add_epi16(round, lo); + sign1 = _mm_add_epi16(sign1, sign2); + + hi = _mm_slli_epi16(hi, 1); + rsp_vec_t eq = _mm_cmpeq_epi16(vs, vt); + rsp_vec_t neq = eq; + *acc_md = _mm_add_epi16(hi, sign1); + + rsp_vec_t neg = _mm_srai_epi16(*acc_md, 15); + + if (iw & 0x1) // VMULU + { + *acc_hi = _mm_andnot_si128(eq, neg); + hi =_mm_or_si128(*acc_md, neg); + return _mm_andnot_si128(*acc_hi, hi); + } + else // VMULF + { + eq = _mm_and_si128(eq, neg); + *acc_hi = _mm_andnot_si128(neq, neg); + return _mm_add_epi16(*acc_md, eq); + } +} diff --git a/src/devices/cpu/rsp/vmulh.h b/src/devices/cpu/rsp/vmulh.h new file mode 100644 index 00000000000..aaccf9d41b3 --- /dev/null +++ b/src/devices/cpu/rsp/vmulh.h @@ -0,0 +1,30 @@ +// license:BSD-3-Clause +// copyright-holders:Tyler J. Stachecki,Ryan Holtz + +inline rsp_vec_t vec_vmadh_vmudh(UINT32 iw, rsp_vec_t vs, rsp_vec_t vt, rsp_vec_t zero, rsp_vec_t *acc_lo, rsp_vec_t *acc_md, rsp_vec_t *acc_hi) +{ + rsp_vec_t lo = _mm_mullo_epi16(vs, vt); + rsp_vec_t hi = _mm_mulhi_epi16(vs, vt); + + if (iw & 0x8) // VMADH + { + // Tricky part: start accumulating everything. + // Get/keep the carry as we'll add it in later. + rsp_vec_t overflow_mask = _mm_adds_epu16(*acc_md, lo); + *acc_md = _mm_add_epi16(*acc_md, lo); + + overflow_mask = _mm_cmpeq_epi16(*acc_md, overflow_mask); + overflow_mask = _mm_cmpeq_epi16(overflow_mask, zero); + + hi = _mm_sub_epi16(hi, overflow_mask); + *acc_hi = _mm_add_epi16(*acc_hi, hi); + } + else // VMUDH + { + *acc_lo = zero; + *acc_md = lo; + *acc_hi = hi; + } + + return sclamp_acc_to_mid(*acc_md, *acc_hi); +} diff --git a/src/devices/cpu/rsp/vmull.h b/src/devices/cpu/rsp/vmull.h new file mode 100644 index 00000000000..2052d537aa8 --- /dev/null +++ b/src/devices/cpu/rsp/vmull.h @@ -0,0 +1,44 @@ +// license:BSD-3-Clause +// copyright-holders:Tyler J. Stachecki,Ryan Holtz + +inline rsp_vec_t vec_vmadl_vmudl(UINT32 iw, rsp_vec_t vs, rsp_vec_t vt, rsp_vec_t zero, rsp_vec_t *acc_lo, rsp_vec_t *acc_md, rsp_vec_t *acc_hi) +{ + rsp_vec_t hi = _mm_mulhi_epu16(vs, vt); + + if (iw & 0x8) // VMADL + { + // Tricky part: start accumulating everything. + // Get/keep the carry as we'll add it in later. + rsp_vec_t overflow_mask = _mm_adds_epu16(*acc_lo, hi); + *acc_lo = _mm_add_epi16(*acc_lo, hi); + + overflow_mask = _mm_cmpeq_epi16(*acc_lo, overflow_mask); + overflow_mask = _mm_cmpeq_epi16(overflow_mask, zero); + hi = _mm_sub_epi16(zero, overflow_mask); + + // Check for overflow of the upper sum. + // + // TODO: Since hi can only be {0,1}, we should + // be able to generalize this for performance. + overflow_mask = _mm_adds_epu16(*acc_md, hi); + *acc_md = _mm_add_epi16(*acc_md, hi); + + overflow_mask = _mm_cmpeq_epi16(*acc_md, overflow_mask); + overflow_mask = _mm_cmpeq_epi16(overflow_mask, zero); + + // Finish up the accumulation of the... accumulator. + // Since the product was unsigned, only worry about + // positive overflow (i.e.: borrowing not possible). + *acc_hi = _mm_sub_epi16(*acc_hi, overflow_mask); + + return uclamp_acc(*acc_lo, *acc_md, *acc_hi, zero); + } + else // VMUDL + { + *acc_lo = hi; + *acc_md = zero; + *acc_hi = zero; + + return hi; + } +} diff --git a/src/devices/cpu/rsp/vmulm.h b/src/devices/cpu/rsp/vmulm.h new file mode 100644 index 00000000000..0319a2f6dcc --- /dev/null +++ b/src/devices/cpu/rsp/vmulm.h @@ -0,0 +1,56 @@ +// license:BSD-3-Clause +// copyright-holders:Tyler J. Stachecki,Ryan Holtz + +inline rsp_vec_t vec_vmadm_vmudm(UINT32 iw, rsp_vec_t vs, rsp_vec_t vt, rsp_vec_t zero, rsp_vec_t *acc_lo, rsp_vec_t *acc_md, rsp_vec_t *acc_hi) +{ + rsp_vec_t lo = _mm_mullo_epi16(vs, vt); + rsp_vec_t hi = _mm_mulhi_epu16(vs, vt); + + // What we really want to do is unsigned vs * signed vt. + // However, we have no such instructions to do so. + // + // There's a trick to "fix" an unsigned product, though: + // If vt was negative, take the upper 16-bits of the product + // and subtract vs. + rsp_vec_t sign = _mm_srai_epi16(vs, 15); + vt = _mm_and_si128(vt, sign); + hi = _mm_sub_epi16(hi, vt); + + if (iw & 0x8) // VMADM + { + // Tricky part: start accumulating everything. + // Get/keep the carry as we'll add it in later. + rsp_vec_t overflow_mask = _mm_adds_epu16(*acc_lo, lo); + *acc_lo = _mm_add_epi16(*acc_lo, lo); + + overflow_mask = _mm_cmpeq_epi16(*acc_lo, overflow_mask); + overflow_mask = _mm_cmpeq_epi16(overflow_mask, zero); + + // This is REALLY clever. Since the product results from + // two 16-bit components, one positive and one negative, + // we don't have to worry about carrying the 1 (we can + // only borrow) past 32-bits. So we can just add it here. + hi = _mm_sub_epi16(hi, overflow_mask); + + // Check for overflow of the upper sum. + overflow_mask = _mm_adds_epu16(*acc_md, hi); + *acc_md = _mm_add_epi16(*acc_md, hi); + + overflow_mask = _mm_cmpeq_epi16(*acc_md, overflow_mask); + overflow_mask = _mm_cmpeq_epi16(overflow_mask, zero); + + // Finish up the accumulation of the... accumulator. + *acc_hi = _mm_add_epi16(*acc_hi, _mm_srai_epi16(hi, 15)); + *acc_hi = _mm_sub_epi16(*acc_hi, overflow_mask); + + return sclamp_acc_to_mid(*acc_md, *acc_hi); + } + else // VMUDM + { + *acc_lo = lo; + *acc_md = hi; + *acc_hi = _mm_srai_epi16(hi, 15); + + return hi; + } +} diff --git a/src/devices/cpu/rsp/vmuln.h b/src/devices/cpu/rsp/vmuln.h new file mode 100644 index 00000000000..b9e012622fc --- /dev/null +++ b/src/devices/cpu/rsp/vmuln.h @@ -0,0 +1,55 @@ +// license:BSD-3-Clause +// copyright-holders:Tyler J. Stachecki,Ryan Holtz + +inline rsp_vec_t vec_vmadn_vmudn(UINT32 iw, rsp_vec_t vs, rsp_vec_t vt, rsp_vec_t zero, rsp_vec_t *acc_lo, rsp_vec_t *acc_md, rsp_vec_t *acc_hi) +{ + rsp_vec_t lo = _mm_mullo_epi16(vs, vt); + rsp_vec_t hi = _mm_mulhi_epu16(vs, vt); + + // What we really want to do is unsigned vs * signed vt. + // However, we have no such instructions to do so. + // + // There's a trick to "fix" an unsigned product, though: + // If vt was negative, take the upper 16-bits of the product + // and subtract vs. + rsp_vec_t sign = _mm_srai_epi16(vt, 15); + vs = _mm_and_si128(vs, sign); + hi = _mm_sub_epi16(hi, vs); + + if (iw & 0x8) // VMADN + { + // Tricky part: start accumulating everything. + // Get/keep the carry as we'll add it in later. + rsp_vec_t overflow_mask = _mm_adds_epu16(*acc_lo, lo); + *acc_lo = _mm_add_epi16(*acc_lo, lo); + + overflow_mask = _mm_cmpeq_epi16(*acc_lo, overflow_mask); + overflow_mask = _mm_cmpeq_epi16(overflow_mask, zero); + + // This is REALLY clever. Since the product results from + // two 16-bit components, one positive and one negative, + // we don't have to worry about carrying the 1 (we can + // only borrow) past 32-bits. So we can just add it here. + hi = _mm_sub_epi16(hi, overflow_mask); + + // Check for overflow of the upper sum. + overflow_mask = _mm_adds_epu16(*acc_md, hi); + *acc_md = _mm_add_epi16(*acc_md, hi); + + overflow_mask = _mm_cmpeq_epi16(*acc_md, overflow_mask); + overflow_mask = _mm_cmpeq_epi16(overflow_mask, zero); + + // Finish up the accumulation of the... accumulator. + *acc_hi = _mm_add_epi16(*acc_hi, _mm_srai_epi16(hi, 15)); + *acc_hi = _mm_sub_epi16(*acc_hi, overflow_mask); + return uclamp_acc(*acc_lo, *acc_md, *acc_hi, zero); + } + else // VMUDN + { + *acc_lo = lo; + *acc_md = hi; + *acc_hi = _mm_srai_epi16(hi, 15); + + return lo; + } +} diff --git a/src/devices/cpu/rsp/vor.h b/src/devices/cpu/rsp/vor.h new file mode 100644 index 00000000000..9f946df7ca9 --- /dev/null +++ b/src/devices/cpu/rsp/vor.h @@ -0,0 +1,10 @@ +// license:BSD-3-Clause +// copyright-holders:Tyler J. Stachecki,Ryan Holtz + +inline rsp_vec_t vec_vor_vnor(UINT32 iw, rsp_vec_t vs, rsp_vec_t vt) +{ + rsp_vec_t vmask = _mm_load_si128((rsp_vec_t *) m_vec_helpers.logic_mask[iw & 0x1]); + + rsp_vec_t vd = _mm_or_si128(vs, vt); + return _mm_xor_si128(vd, vmask); +} diff --git a/src/devices/cpu/rsp/vrcpsq.h b/src/devices/cpu/rsp/vrcpsq.h new file mode 100644 index 00000000000..930d8237853 --- /dev/null +++ b/src/devices/cpu/rsp/vrcpsq.h @@ -0,0 +1,58 @@ +// license:BSD-3-Clause +// copyright-holders:Tyler J. Stachecki,Ryan Holtz + +inline rsp_vec_t vec_vrcp_vrsq(UINT32 iw, INT32 dp, UINT32 src, UINT32 e, UINT32 dest, UINT32 de) +{ + // Get the element from VT. + INT16 vt = m_v[src].s[e & 0x7]; + + UINT32 dp_input = ((UINT32) m_div_in << 16) | (UINT16) vt; + UINT32 sp_input = vt; + + INT32 input = (dp) ? dp_input : sp_input; + INT32 input_mask = input >> 31; + INT32 data = input ^ input_mask; + + if (input > -32768) + { + data -= input_mask; + } + + // Handle edge cases. + INT32 result; + if (data == 0) + { + result = 0x7fffffff; + } + else if (input == -32768) + { + result = 0xffff0000; + } + else // Main case: compute the reciprocal. + { + UINT32 shift = count_leading_zeros(data); + UINT32 idx = (((UINT64) data << shift) & 0x7FC00000) >> 22; + + if (iw & 0x4) // VRSQ + { + idx = ((idx | 0x200) & 0x3fe) | (shift % 2); + result = rsp_divtable[idx]; + + result = ((0x10000 | result) << 14) >> ((31 - shift) >> 1); + } + else // VRCP + { + result = rsp_divtable[idx]; + + result = ((0x10000 | result) << 14) >> (31 - shift); + } + + result = result ^ input_mask; + } + + // Write out the results. + m_div_out = result >> 16; + m_v[dest].s[de & 0x7] = result; + + return vec_load_unshuffled_operand(m_v[dest].s); +} diff --git a/src/devices/cpu/rsp/vrsq.h b/src/devices/cpu/rsp/vrsq.h new file mode 100644 index 00000000000..f657bc42554 --- /dev/null +++ b/src/devices/cpu/rsp/vrsq.h @@ -0,0 +1,66 @@ +// license:BSD-3-Clause +// copyright-holders:Tyler J. Stachecki,Ryan Holtz + +rsp_vec_t vec_vrsq(INT32 dp, UINT32 src, UINT32 e, UINT32 dest, UINT32 de) +{ + // Get the element from VT. + INT16 vt = m_v[src].s[e & 0x7]; + + UINT32 dp_input = ((UINT32) m_div_in << 16) | (UINT16) vt; + UINT32 sp_input = vt; + + INT32 input = (dp) ? dp_input : sp_input; + INT32 input_mask = input >> 31; + INT32 data = input ^ input_mask; + + if (input > -32768) + { + data -= input_mask; + } + + // Handle edge cases. + INT32 result; + if (data == 0) + { + result = 0x7fffffff; + } + else if (input == -32768) + { + result = 0xffff0000; + } + else // Main case: compute the reciprocal. + { + UINT32 shift = count_leading_zeros(data); + + UINT32 idx = (((UINT64) data << shift) & 0x7fc00000) >> 22; + idx = ((idx | 0x200) & 0x3fe) | (shift % 2); + result = rsp_divtable[idx]; + + result = ((0x10000 | result) << 14) >> ((31 - shift) >> 1); + result = result ^ input_mask; + } + + // Write out the results. + m_div_out = result >> 16; + m_v[dest].s[de & 0x7] = result; + + return vec_load_unshuffled_operand(m_v[dest].s); +} + +rsp_vec_t vec_vrsqh(UINT32 src, UINT32 e, UINT32 dest, UINT32 de) +{ + INT16 elements[8]; + + // Get the element from VT. + memcpy(elements, &m_v[src], sizeof(rsp_vec_t)); + m_div_in = elements[e]; + + // Write out the upper part of the result. + rsp_vec_t vd_mask = _mm_load_si128((rsp_vec_t *) m_vec_helpers.vrsq_mask_table[de]); + rsp_vec_t vd = _mm_load_si128((rsp_vec_t *) &m_v[dest]); + vd = _mm_andnot_si128(vd_mask, vd); + + rsp_vec_t b_result = _mm_set1_epi16(m_div_out); + b_result = _mm_and_si128(vd_mask, b_result); + return _mm_or_si128(b_result, vd); +} diff --git a/src/devices/cpu/rsp/vsub.h b/src/devices/cpu/rsp/vsub.h new file mode 100644 index 00000000000..c3df93627c8 --- /dev/null +++ b/src/devices/cpu/rsp/vsub.h @@ -0,0 +1,17 @@ +// license:BSD-3-Clause +// copyright-holders:Tyler J. Stachecki,Ryan Holtz + +inline rsp_vec_t vec_vsub(rsp_vec_t vs, rsp_vec_t vt, rsp_vec_t carry, rsp_vec_t *acc_lo) +{ + // acc_lo uses saturated arithmetic. + rsp_vec_t unsat_diff = _mm_sub_epi16(vt, carry); + rsp_vec_t sat_diff = _mm_subs_epi16(vt, carry); + + *acc_lo = _mm_sub_epi16(vs, unsat_diff); + rsp_vec_t vd = _mm_subs_epi16(vs, sat_diff); + + // VD is the signed diff of the two sources and the carry. Since we + // have to saturate the diff of all three, we have to be clever. + rsp_vec_t overflow = _mm_cmpgt_epi16(sat_diff, unsat_diff); + return _mm_adds_epi16(vd, overflow); +} diff --git a/src/devices/cpu/rsp/vsubc.h b/src/devices/cpu/rsp/vsubc.h new file mode 100644 index 00000000000..8632b9462d9 --- /dev/null +++ b/src/devices/cpu/rsp/vsubc.h @@ -0,0 +1,14 @@ +// license:BSD-3-Clause +// copyright-holders:Tyler J. Stachecki,Ryan Holtz + +inline rsp_vec_t vec_vsubc(rsp_vec_t vs, rsp_vec_t vt, rsp_vec_t zero, rsp_vec_t *eq, rsp_vec_t *sn) +{ + rsp_vec_t sat_udiff = _mm_subs_epu16(vs, vt); + rsp_vec_t equal = _mm_cmpeq_epi16(vs, vt); + rsp_vec_t sat_udiff_zero = _mm_cmpeq_epi16(sat_udiff, zero); + + *eq = _mm_cmpeq_epi16(equal, zero); + *sn = _mm_andnot_si128(equal, sat_udiff_zero); + + return _mm_sub_epi16(vs, vt); +} diff --git a/src/devices/cpu/rsp/vxor.h b/src/devices/cpu/rsp/vxor.h new file mode 100644 index 00000000000..b11e1b96bc1 --- /dev/null +++ b/src/devices/cpu/rsp/vxor.h @@ -0,0 +1,10 @@ +// license:BSD-3-Clause +// copyright-holders:Tyler J. Stachecki,Ryan Holtz + +inline rsp_vec_t vec_vxor_vnxor(UINT32 iw, rsp_vec_t vs, rsp_vec_t vt) +{ + rsp_vec_t vmask = _mm_load_si128((rsp_vec_t *) m_vec_helpers.logic_mask[iw & 0x1]); + + rsp_vec_t vd = _mm_xor_si128(vs, vt); + return _mm_xor_si128(vd, vmask); +} diff --git a/src/devices/cpu/s2650/2650dasm.c b/src/devices/cpu/s2650/2650dasm.c new file mode 100644 index 00000000000..6a6f9b1a00c --- /dev/null +++ b/src/devices/cpu/s2650/2650dasm.c @@ -0,0 +1,868 @@ +// license:BSD-3-Clause +// copyright-holders:Juergen Buchmueller +/*************************************************************************** + * + * Portable Signetics 2650 disassembler + * + * Written by J. Buchmueller (pullmoll@t-online.de) + * for the MAME project + * + **************************************************************************/ + +#include "emu.h" + +static const UINT8 *rambase; +static offs_t pcbase; + +#define readarg(A) (rambase[(A) - pcbase]) + +/* Set this to 1 to disassemble using Z80 style mnemonics */ +#define HJB 0 + +/* Set this to 1 to give names to condition codes and flag bits */ +#define MNEMO 1 + +/* handy table to build relative offsets from HR (holding register) */ +static const int rel[0x100] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + -64,-63,-62,-61,-60,-59,-58,-57,-56,-55,-54,-53,-52,-51,-50,-49, + -48,-47,-46,-45,-44,-43,-42,-41,-40,-39,-38,-37,-36,-35,-34,-33, + -32,-31,-30,-29,-28,-27,-26,-25,-24,-23,-22,-21,-20,-19,-18,-17, + -16,-15,-14,-13,-12,-11,-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + -64,-63,-62,-61,-60,-59,-58,-57,-56,-55,-54,-53,-52,-51,-50,-49, + -48,-47,-46,-45,-44,-43,-42,-41,-40,-39,-38,-37,-36,-35,-34,-33, + -32,-31,-30,-29,-28,-27,-26,-25,-24,-23,-22,-21,-20,-19,-18,-17, + -16,-15,-14,-13,-12,-11,-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, +}; + +typedef char* (*callback) (int addr); +static callback find_symbol = 0; + +static char *SYM(int addr) +{ + static char buff[8+1]; + char * s = NULL; + + if (find_symbol) s = (*find_symbol)(addr); + if (s) return s; + + sprintf(buff, "$%04x", addr); + return buff; +} + +/* format an immediate */ +static char *IMM(int pc) +{ + static char buff[32]; + + sprintf(buff, "$%02x", readarg(pc)); + return buff; +} + +#if MNEMO +static const char cc[4] = { 'z', 'p', 'm', 'a' }; + +/* format an immediate for PSL */ +static char *IMM_PSL(int pc) +{ + static char buff[32]; + char *p = buff; + int v = readarg(pc); + + if (v == 0xff) { + p += sprintf(p, "all"); + } else { + switch (v & 0xc0) + { + case 0x40: p += sprintf(p, "p+"); break; + case 0x80: p += sprintf(p, "m+"); break; + case 0xc0: p += sprintf(p, "cc+"); break; + } + if (v & 0x20) /* inter digit carry */ + p += sprintf(p, "idc+"); + if (v & 0x10) /* register select */ + p += sprintf(p, "rs+"); + if (v & 0x08) /* with carry */ + p += sprintf(p, "wc+"); + if (v & 0x04) /* overflow */ + p += sprintf(p, "ovf+"); + if (v & 0x02) /* 2's complement comparisons */ + p += sprintf(p, "com+"); + if (v & 0x01) /* carry */ + p += sprintf(p, "c+"); + if (p > buff) + *--p = '\0'; + } + return buff; +} + +/* format an immediate for PSU (processor status upper) */ +static char *IMM_PSU(int pc) +{ + static char buff[32]; + char *p = buff; + int v = readarg(pc); + + if (v == 0xff) { + p += sprintf(p, "all"); + + } else { + if (v & 0x80) /* sense input */ + p += sprintf(p, "si+"); + if (v & 0x40) /* flag output */ + p += sprintf(p, "fo+"); + if (v & 0x20) /* interrupt inhibit */ + p += sprintf(p, "ii+"); + if (v & 0x10) /* unused bit 4 */ + p += sprintf(p, "4+"); + if (v & 0x08) /* unused bit 3 */ + p += sprintf(p, "3+"); + if (v & 0x04) /* stack pointer bit 2 */ + p += sprintf(p, "sp2+"); + if (v & 0x02) /* stack pointer bit 1 */ + p += sprintf(p, "sp1+"); + if (v & 0x01) /* stack pointer bit 0 */ + p += sprintf(p, "sp0+"); + if (p > buff) + *--p = '\0'; + } + return buff; +} +#else +static const char cc[4] = { '0', '1', '2', '3' }; +#define IMM_PSL IMM +#define IMM_PSU IMM +#endif + +/* format an relative address */ +static char *REL(int pc) +{ +static char buff[32]; +int o = readarg(pc); + sprintf(buff, "%s%s", (o&0x80)?"*":"", SYM((pc&0x6000)+((pc+1+rel[o])&0x1fff))); + return buff; +} + +/* format an relative address (implicit page 0) */ +static char *REL0(int pc) +{ +static char buff[32]; +int o = readarg(pc); + sprintf(buff, "%s%s", (o&0x80)?"*":"", SYM((rel[o]) & 0x1fff)); + return buff; +} + +/* format a destination register and an absolute address */ +static char *ABS(int load, int r, int pc) +{ + static char buff[32]; + int h = readarg(pc); + int l = readarg((pc&0x6000)+((pc+1)&0x1fff)); + int a = (pc & 0x6000) + ((h & 0x1f) << 8) + l; + +#if HJB + if (load) { + switch (h >> 5) { + case 0: sprintf(buff, "r%d,(%s)", r, SYM(a)); break; + case 1: sprintf(buff, "r0,(%s,r%d++)", SYM(a), r); break; + case 2: sprintf(buff, "r0,(%s,r%d--)", SYM(a), r); break; + case 3: sprintf(buff, "r0,(%s,r%d)", SYM(a), r); break; + case 4: sprintf(buff, "r%d,*(%s)", r, SYM(a)); break; + case 5: sprintf(buff, "r0,*(%s,r%d++)", SYM(a), r); break; + case 6: sprintf(buff, "r0,*(%s,r%d--)", SYM(a), r); break; + case 7: sprintf(buff, "r0,*(%s,r%d)", SYM(a), r); break; + } + } else { + switch (h >> 5) { + case 0: sprintf(buff, "(%s),r%d", SYM(a), r); break; + case 1: sprintf(buff, "(%s,r%d++),r0", SYM(a), r); break; + case 2: sprintf(buff, "(%s,r%d--),r0", SYM(a), r); break; + case 3: sprintf(buff, "(%s,r%d),r0", SYM(a), r); break; + case 4: sprintf(buff, "*(%s),r%d", SYM(a), r); break; + case 5: sprintf(buff, "*(%s,r%d++),r0", SYM(a), r); break; + case 6: sprintf(buff, "*(%s,r%d--),r0", SYM(a), r); break; + case 7: sprintf(buff, "*(%s,r%d),r0", SYM(a), r); break; + } + } +#else + switch (h >> 5) { + case 0: sprintf(buff, "%d %s", r, SYM(a)); break; + case 1: sprintf(buff, "0 %s,r%d+", SYM(a), r); break; + case 2: sprintf(buff, "0 %s,r%d-", SYM(a), r); break; + case 3: sprintf(buff, "0 %s,r%d", SYM(a), r); break; + case 4: sprintf(buff, "%d *%s", r, SYM(a)); break; + case 5: sprintf(buff, "0 *%s,r%d+", SYM(a), r); break; + case 6: sprintf(buff, "0 *%s,r%d-", SYM(a), r); break; + case 7: sprintf(buff, "0 *%s,r%d", SYM(a), r); break; + } +#endif + return buff; +} + +/* format an (branch) absolute address */ +static char *ADR(int pc) +{ + static char buff[32]; + int h = readarg(pc); + int l = readarg((pc&0x6000)+((pc+1)&0x1fff)); + int a = ((h & 0x7f) << 8) + l; + if (h & 0x80) + sprintf(buff, "*%s", SYM(a)); + else + sprintf(buff, "%s", SYM(a)); + return buff; +} + +/* disassemble one instruction at PC into buff. return byte size of instr */ +CPU_DISASSEMBLE( s2650 ) +{ + UINT32 flags = 0; + int PC = pc; + int op = oprom[0]; + int rv = op & 3; + + rambase = opram; + pcbase = PC; + + pc += 1; + switch (op) + { + case 0x00: case 0x01: case 0x02: case 0x03: +#if HJB + sprintf(buffer, "ld r0,r%d", rv); +#else + sprintf(buffer, "lodz,%d", rv); +#endif + break; + case 0x04: case 0x05: case 0x06: case 0x07: +#if HJB + sprintf(buffer, "ld r%d,%s", rv, IMM(pc)); +#else + sprintf(buffer, "lodi,%d %s", rv, IMM(pc)); +#endif + pc+=1; + break; + case 0x08: case 0x09: case 0x0a: case 0x0b: +#if HJB + sprintf(buffer, "ld r%d,(%s)", rv, REL(pc)); +#else + sprintf(buffer, "lodr,%d %s", rv, REL(pc)); +#endif + pc+=1; + break; + case 0x0c: case 0x0d: case 0x0e: case 0x0f: +#if HJB + sprintf(buffer, "ld %s", ABS(1,rv,pc)); +#else + sprintf(buffer, "loda,%s", ABS(1,rv,pc)); +#endif + pc+=2; + break; + case 0x10: case 0x11: +#if HJB + sprintf(buffer, "**** $%02X",op); +#else + sprintf(buffer, "**** $%02X",op); +#endif + break; + case 0x12: +#if HJB + sprintf(buffer, "ld r0,psu"); +#else + sprintf(buffer, "spsu"); +#endif + break; + case 0x13: +#if HJB + sprintf(buffer, "ld r0,psl"); +#else + sprintf(buffer, "spsl"); +#endif + break; + case 0x14: case 0x15: case 0x16: case 0x17: +#if HJB + if (rv == 3) + sprintf(buffer, "ret"); + else + sprintf(buffer, "ret %c", cc[rv]); +#else + sprintf(buffer, "retc %c", cc[rv]); +#endif + flags = DASMFLAG_STEP_OUT; + break; + case 0x18: case 0x19: case 0x1a: case 0x1b: +#if HJB + if (rv == 3) + sprintf(buffer, "jr %s", REL(pc)); + else + sprintf(buffer, "jr %c,%s", cc[rv], REL(pc)); +#else + sprintf(buffer, "bctr,%c %s", cc[rv], REL(pc)); +#endif + pc+=1; + break; + case 0x1c: case 0x1d: case 0x1e: case 0x1f: +#if HJB + if (rv == 3) + sprintf(buffer, "jp %s", ADR(pc)); + else + sprintf(buffer, "jp %c,%s", cc[rv], ADR(pc)); +#else + sprintf(buffer, "bcta,%c %s", cc[rv], ADR(pc)); +#endif + pc+=2; + break; + case 0x20: case 0x21: case 0x22: case 0x23: +#if HJB + sprintf(buffer, "xor r0,r%d", rv); +#else + sprintf(buffer, "eorz,%d", rv); +#endif + break; + case 0x24: case 0x25: case 0x26: case 0x27: +#if HJB + sprintf(buffer, "xor r%d,%s", rv, IMM(pc)); +#else + sprintf(buffer, "eori,%d %s", rv, IMM(pc)); +#endif + pc+=1; + break; + case 0x28: case 0x29: case 0x2a: case 0x2b: +#if HJB + sprintf(buffer, "xor r%d,(%s)", rv, REL(pc)); +#else + sprintf(buffer, "eorr,%d %s", rv, REL(pc)); +#endif + pc+=1; + break; + case 0x2c: case 0x2d: case 0x2e: case 0x2f: +#if HJB + sprintf(buffer, "xor %s", ABS(1,rv,pc)); +#else + sprintf(buffer, "eora,%s", ABS(1,rv,pc)); +#endif + pc+=2; + break; + case 0x30: case 0x31: case 0x32: case 0x33: +#if HJB + sprintf(buffer, "in r%d,(ctrl)", rv); +#else + sprintf(buffer, "redc,%d", rv); +#endif + break; + case 0x34: case 0x35: case 0x36: case 0x37: +#if HJB + if (rv == 3) + sprintf(buffer, "iret"); + else + sprintf(buffer, "iret %c", cc[rv]); +#else + sprintf(buffer, "rete %c", cc[rv]); +#endif + flags = DASMFLAG_STEP_OUT; + break; + case 0x38: case 0x39: case 0x3a: case 0x3b: +#if HJB + if (rv == 3) + sprintf(buffer, "calr %s", REL(pc)); + else + sprintf(buffer, "calr %c,%s", cc[rv], REL(pc)); +#else + sprintf(buffer, "bstr,%c %s", cc[rv], REL(pc)); +#endif + pc+=1; + flags = DASMFLAG_STEP_OVER; + break; + case 0x3c: case 0x3d: case 0x3e: case 0x3f: +#if HJB + if (rv == 3) + sprintf(buffer, "call %s", ADR(pc)); + else + sprintf(buffer, "call %c,%s", cc[rv], ADR(pc)); +#else + sprintf(buffer, "bsta,%c %s", cc[rv], ADR(pc)); +#endif + pc+=2; + flags = DASMFLAG_STEP_OVER; + break; + case 0x40: + sprintf(buffer, "halt"); + break; + case 0x41: case 0x42: case 0x43: +#if HJB + sprintf(buffer, "and r0,r%d", rv); +#else + sprintf(buffer, "andz,%d", rv); +#endif + break; + case 0x44: case 0x45: case 0x46: case 0x47: +#if HJB + sprintf(buffer, "and r%d,%s", rv, IMM(pc)); +#else + sprintf(buffer, "andi,%d %s", rv, IMM(pc)); +#endif + pc+=1; + break; + case 0x48: case 0x49: case 0x4a: case 0x4b: +#if HJB + sprintf(buffer, "and r%d,(%s)", rv, REL(pc)); +#else + sprintf(buffer, "andr,%d %s", rv, REL(pc)); +#endif + pc+=1; + break; + case 0x4c: case 0x4d: case 0x4e: case 0x4f: +#if HJB + sprintf(buffer, "and %s", ABS(1,rv,pc)); +#else + sprintf(buffer, "anda,%s", ABS(1,rv,pc)); +#endif + pc+=2; + break; + case 0x50: case 0x51: case 0x52: case 0x53: +#if HJB + sprintf(buffer, "ror r%d", rv); +#else + sprintf(buffer, "rrr,%d", rv); +#endif + break; + case 0x54: case 0x55: case 0x56: case 0x57: +#if HJB + sprintf(buffer, "in r%d,(%s)", rv, IMM(pc)); +#else + sprintf(buffer, "rede,%d %s", rv, IMM(pc)); +#endif + pc+=1; + break; + case 0x58: case 0x59: case 0x5a: case 0x5b: +#if HJB + sprintf(buffer, "jrnz r%d,%s", rv, REL(pc)); +#else + sprintf(buffer, "brnr,%d %s", rv, REL(pc)); +#endif + pc+=1; + break; + case 0x5c: case 0x5d: case 0x5e: case 0x5f: +#if HJB + sprintf(buffer, "jpnz r%d,%s", rv, ADR(pc)); +#else + sprintf(buffer, "brna,%d %s", rv, ADR(pc)); +#endif + pc+=2; + break; + case 0x60: case 0x61: case 0x62: case 0x63: +#if HJB + sprintf(buffer, "or r0,r%d", rv); +#else + sprintf(buffer, "iorz,%d", rv); +#endif + break; + case 0x64: case 0x65: case 0x66: case 0x67: +#if HJB + sprintf(buffer, "or r%d,%s", rv, IMM(pc)); +#else + sprintf(buffer, "iori,%d %s", rv, IMM(pc)); +#endif + pc+=1; + break; + case 0x68: case 0x69: case 0x6a: case 0x6b: +#if HJB + sprintf(buffer, "or r%d,(%s)", rv, REL(pc)); +#else + sprintf(buffer, "iorr,%d %s", rv, REL(pc)); +#endif + pc+=1; + break; + case 0x6c: case 0x6d: case 0x6e: case 0x6f: +#if HJB + sprintf(buffer, "or %s", ABS(1,rv,pc)); +#else + sprintf(buffer, "iora,%s", ABS(1,rv,pc)); +#endif + pc+=2; + break; + case 0x70: case 0x71: case 0x72: case 0x73: +#if HJB + sprintf(buffer, "in r%d,(data)", rv); +#else + sprintf(buffer, "redd,%d", rv); +#endif + break; + case 0x74: +#if HJB + sprintf(buffer, "res psu,%s", IMM_PSU(pc)); +#else + sprintf(buffer, "cpsu %s", IMM_PSU(pc)); +#endif + pc+=1; + break; + case 0x75: +#if HJB + sprintf(buffer, "res psl,%s", IMM_PSL(pc)); +#else + sprintf(buffer, "cpsl %s", IMM_PSL(pc)); +#endif + pc+=1; + break; + case 0x76: +#if HJB + sprintf(buffer, "set psu,%s", IMM_PSU(pc)); +#else + sprintf(buffer, "ppsu %s", IMM_PSU(pc)); +#endif + pc+=1; + break; + case 0x77: +#if HJB + sprintf(buffer, "set psl,%s", IMM_PSL(pc)); +#else + sprintf(buffer, "ppsl %s", IMM_PSL(pc)); +#endif + pc+=1; + break; + case 0x78: case 0x79: case 0x7a: case 0x7b: +#if HJB + sprintf(buffer, "call r%d-nz,%s", rv, REL(pc)); +#else + sprintf(buffer, "bsnr,%d %s", rv, REL(pc)); +#endif + pc+=1; + flags = DASMFLAG_STEP_OVER; + break; + case 0x7c: case 0x7d: case 0x7e: case 0x7f: +#if HJB + sprintf(buffer, "call r%d-nz,%s", rv, ADR(pc)); +#else + sprintf(buffer, "bsna,%d %s", rv, ADR(pc)); +#endif + pc+=2; + flags = DASMFLAG_STEP_OVER; + break; + case 0x80: case 0x81: case 0x82: case 0x83: +#if HJB + sprintf(buffer, "add r0,r%d", rv); +#else + sprintf(buffer, "addz,%d", rv); +#endif + break; + case 0x84: case 0x85: case 0x86: case 0x87: +#if HJB + sprintf(buffer, "add r%d,%s", rv, IMM(pc)); +#else + sprintf(buffer, "addi,%d %s", rv, IMM(pc)); +#endif + pc+=1; + break; + case 0x88: case 0x89: case 0x8a: case 0x8b: +#if HJB + sprintf(buffer, "add r%d,(%s)", rv, REL(pc)); +#else + sprintf(buffer, "addr,%d %s", rv, REL(pc)); +#endif + pc+=1; + break; + case 0x8c: case 0x8d: case 0x8e: case 0x8f: +#if HJB + sprintf(buffer, "add %s", ABS(1,rv,pc)); +#else + sprintf(buffer, "adda,%s", ABS(1,rv,pc)); +#endif + pc+=2; + break; + case 0x90: case 0x91: +#if HJB + sprintf(buffer, "**** $%02X",op); +#else + sprintf(buffer, "**** $%02X",op); +#endif + break; + case 0x92: +#if HJB + sprintf(buffer, "ld psu,r0"); +#else + sprintf(buffer, "lpsu"); +#endif + break; + case 0x93: +#if HJB + sprintf(buffer, "ld psl,r0"); +#else + sprintf(buffer, "lpsl"); +#endif + break; + case 0x94: case 0x95: case 0x96: case 0x97: +#if HJB + sprintf(buffer, "daa r%d", rv); +#else + sprintf(buffer, "dar,%d", rv); +#endif + break; + case 0x98: case 0x99: case 0x9a: +#if HJB + sprintf(buffer, "jr n%c,%s", cc[rv], REL(pc)); +#else + sprintf(buffer, "bcfr,%c %s", cc[rv], REL(pc)); +#endif + pc+=1; + break; + case 0x9b: +#if HJB + sprintf(buffer, "jr0 %s", REL0(pc)); +#else + sprintf(buffer, "zbrr %s", REL0(pc)); +#endif + pc+=1; + break; + case 0x9c: case 0x9d: case 0x9e: +#if HJB + sprintf(buffer, "jp n%c,%s", cc[rv], ADR(pc)); +#else + sprintf(buffer, "bcfa,%c %s", cc[rv], ADR(pc)); +#endif + pc+=2; + break; + case 0x9f: +#if HJB + sprintf(buffer, "jp %s+r3", ADR(pc)); +#else + sprintf(buffer, "bxa %s", ADR(pc)); +#endif + pc+=2; + break; + case 0xa0: case 0xa1: case 0xa2: case 0xa3: +#if HJB + sprintf(buffer, "sub r0,r%d", rv); +#else + sprintf(buffer, "subz,%d", rv); +#endif + break; + case 0xa4: case 0xa5: case 0xa6: case 0xa7: +#if HJB + sprintf(buffer, "sub r%d,%s", rv, IMM(pc)); +#else + sprintf(buffer, "subi,%d %s", rv, IMM(pc)); +#endif + pc+=1; + break; + case 0xa8: case 0xa9: case 0xaa: case 0xab: +#if HJB + sprintf(buffer, "sub r%d,(%s)", rv, REL(pc)); +#else + sprintf(buffer, "subr,%d %s", rv, REL(pc)); +#endif + pc+=1; + break; + case 0xac: case 0xad: case 0xae: case 0xaf: +#if HJB + sprintf(buffer, "sub %s", ABS(1,rv,pc)); +#else + sprintf(buffer, "suba,%s", ABS(1,rv,pc)); +#endif + pc+=2; + break; + case 0xb0: case 0xb1: case 0xb2: case 0xb3: +#if HJB + sprintf(buffer, "out (ctrl),r%d", rv); +#else + sprintf(buffer, "wrtc,%d", rv); +#endif + break; + case 0xb4: +#if HJB + sprintf(buffer, "bit psu,%s", IMM_PSU(pc)); +#else + sprintf(buffer, "tpsu %s", IMM_PSU(pc)); +#endif + pc+=1; + break; + case 0xb5: +#if HJB + sprintf(buffer, "bit psl,%s", IMM_PSL(pc)); +#else + sprintf(buffer, "tpsl %s", IMM_PSL(pc)); +#endif + pc+=1; + break; + case 0xb6: case 0xb7: +#if HJB + sprintf(buffer, "**** $%02X",op); +#else + sprintf(buffer, "**** $%02X",op); +#endif + break; + case 0xb8: case 0xb9: case 0xba: +#if HJB + sprintf(buffer, "calr n%c,%s", cc[rv], REL(pc)); +#else + sprintf(buffer, "bsfr,%c %s", cc[rv], REL(pc)); +#endif + pc+=1; + flags = DASMFLAG_STEP_OVER; + break; + case 0xbb: +#if HJB + sprintf(buffer, "cal0 %s", REL0(pc)); +#else + sprintf(buffer, "zbsr %s", REL0(pc)); +#endif + pc+=1; + flags = DASMFLAG_STEP_OVER; + break; + case 0xbc: case 0xbd: case 0xbe: +#if HJB + sprintf(buffer, "call n%c,%s", cc[rv], ADR(pc)); +#else + sprintf(buffer, "bsfa,%c %s", cc[rv], ADR(pc)); +#endif + pc+=2; + flags = DASMFLAG_STEP_OVER; + break; + case 0xbf: +#if HJB + sprintf(buffer, "call %s+r3", ADR(pc)); +#else + sprintf(buffer, "bsxa %s", ADR(pc)); +#endif + pc+=2; + flags = DASMFLAG_STEP_OVER; + break; + case 0xc0: + sprintf(buffer, "nop"); + break; + case 0xc1: case 0xc2: case 0xc3: +#if HJB + sprintf(buffer, "ld r%d,r0", rv); +#else + sprintf(buffer, "strz,%d", rv); +#endif + break; + case 0xc4: case 0xc5: case 0xc6: case 0xc7: +#if HJB + sprintf(buffer, "**** $%02X",op); +#else + sprintf(buffer, "**** $%02X",op); +#endif + break; + case 0xc8: case 0xc9: case 0xca: case 0xcb: +#if HJB + sprintf(buffer, "ld (%s),r%d", REL(pc), rv); +#else + sprintf(buffer, "strr,%d %s", rv, REL(pc)); +#endif + pc+=1; + break; + case 0xcc: case 0xcd: case 0xce: case 0xcf: +#if HJB + sprintf(buffer, "ld %s", ABS(0,rv,pc)); +#else + sprintf(buffer, "stra,%s", ABS(1,rv,pc)); +#endif + pc+=2; + break; + case 0xd0: case 0xd1: case 0xd2: case 0xd3: +#if HJB + sprintf(buffer, "rol r%d", rv); +#else + sprintf(buffer, "rrl,%d", rv); +#endif + break; + case 0xd4: case 0xd5: case 0xd6: case 0xd7: +#if HJB + sprintf(buffer, "out (%s),r%d", IMM(pc), rv); +#else + sprintf(buffer, "wrte,%d %s", rv, IMM(pc)); +#endif + pc+=1; + break; + case 0xd8: case 0xd9: case 0xda: case 0xdb: +#if HJB + sprintf(buffer, "ijnz r%d,%s", rv, REL(pc)); +#else + sprintf(buffer, "birr,%d %s", rv, REL(pc)); +#endif + pc+=1; + flags = DASMFLAG_STEP_OVER; + break; + case 0xdc: case 0xdd: case 0xde: case 0xdf: +#if HJB + sprintf(buffer, "ijnz r%d,%s", rv, ADR(pc)); +#else + sprintf(buffer, "bira,%d %s", rv, ADR(pc)); +#endif + pc+=2; + flags = DASMFLAG_STEP_OVER; + break; + case 0xe0: case 0xe1: case 0xe2: case 0xe3: +#if HJB + sprintf(buffer, "cp r0,%d", rv); +#else + sprintf(buffer, "comz,%d", rv); +#endif + break; + case 0xe4: case 0xe5: case 0xe6: case 0xe7: +#if HJB + sprintf(buffer, "cp r%d,%s", rv, IMM(pc)); +#else + sprintf(buffer, "comi,%d %s", rv, IMM(pc)); +#endif + pc+=1; + break; + case 0xe8: case 0xe9: case 0xea: case 0xeb: +#if HJB + sprintf(buffer, "cp r%d,(%s)", rv, REL(pc)); +#else + sprintf(buffer, "comr,%d %s", rv, REL(pc)); +#endif + pc+=1; + break; + case 0xec: case 0xed: case 0xee: case 0xef: +#if HJB + sprintf(buffer, "cp %s", ABS(1,rv,pc)); +#else + sprintf(buffer, "coma,%s", ABS(1,rv,pc)); +#endif + pc+=2; + break; + case 0xf0: case 0xf1: case 0xf2: case 0xf3: +#if HJB + sprintf(buffer, "out (data),r%d", rv); +#else + sprintf(buffer, "wrtd,%d", rv); +#endif + break; + case 0xf4: case 0xf5: case 0xf6: case 0xf7: +#if HJB + sprintf(buffer, "test r%d,%s", rv, IMM(pc)); +#else + sprintf(buffer, "tmi,%d %s", rv, IMM(pc)); +#endif + pc+=1; + break; + case 0xf8: case 0xf9: case 0xfa: case 0xfb: +#if HJB + sprintf(buffer, "djnz r%d,%s", rv, REL(pc)); +#else + sprintf(buffer, "bdrr,%d %s", rv, REL(pc)); +#endif + pc+=1; + flags = DASMFLAG_STEP_OVER; + break; + case 0xfc: case 0xfd: case 0xfe: case 0xff: +#if HJB + sprintf(buffer, "djnz r%d,%s", rv, ADR(pc)); +#else + sprintf(buffer, "bdra,%d %s", rv, ADR(pc)); +#endif + pc+=2; + flags = DASMFLAG_STEP_OVER; + break; + } + return (pc - PC) | flags | DASMFLAG_SUPPORTED; +} diff --git a/src/devices/cpu/s2650/s2650.c b/src/devices/cpu/s2650/s2650.c new file mode 100644 index 00000000000..a67bc2ce5fe --- /dev/null +++ b/src/devices/cpu/s2650/s2650.c @@ -0,0 +1,1576 @@ +// license:BSD-3-Clause +// copyright-holders:Juergen Buchmueller +/************************************************************************* + * + * Portable Signetics 2650 cpu emulation + * + * Version 1.2 + * - changed to clock cycle counts from machine cycles + * - replaced cycle table with inline code (M_RET conditional case) + * - removed wrong distinct add/sub CC and OVF handling + * - cosmetics, readability + * + *************************************************************************/ + +#include "emu.h" +#include "debugger.h" +#include "s2650.h" +#include "s2650cpu.h" + +#define S2650_SENSE_LINE INPUT_LINE_IRQ1 + +/* define this to have some interrupt information logged */ +#define VERBOSE 0 + +#define LOG(x) do { if (VERBOSE) logerror x; } while (0) + +/* define this to expand all EA calculations inline */ +#define INLINE_EA 1 + + +const device_type S2650 = &device_creator; + + +s2650_device::s2650_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : cpu_device(mconfig, S2650, "S2650", tag, owner, clock, "s2650", __FILE__ ) + , m_program_config("program", ENDIANNESS_LITTLE, 8, 15) + , m_io_config("io", ENDIANNESS_LITTLE, 8, 9) + , m_flag_handler(*this) + , m_halt(0) + , m_debugger_temp(0) +{ + memset(m_reg, 0x00, sizeof(m_reg)); +} + + +offs_t s2650_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( s2650 ); + return CPU_DISASSEMBLE_NAME(s2650)(this, buffer, pc, oprom, opram, options); +} + + +/* condition code changes for a byte */ +static const UINT8 ccc[0x200] = { + 0x00,0x40,0x40,0x40,0x40,0x40,0x40,0x40, + 0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, + 0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, + 0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, + 0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, + 0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, + 0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, + 0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, + 0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, + 0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, + 0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, + 0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, + 0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, + 0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, + 0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, + 0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x04,0x44,0x44,0x44,0x44,0x44,0x44,0x44, + 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44, + 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44, + 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44, + 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44, + 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44, + 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44, + 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44, + 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44, + 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44, + 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44, + 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44, + 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44, + 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44, + 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44, + 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44, + 0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84, + 0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84, + 0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84, + 0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84, + 0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84, + 0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84, + 0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84, + 0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84, + 0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84, + 0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84, + 0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84, + 0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84, + 0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84, + 0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84, + 0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84, + 0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84 +}; + +/*************************************************************** + * handy table to build PC relative offsets + * from HR (holding register) + ***************************************************************/ +static const int S2650_relative[0x100] = +{ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + -64,-63,-62,-61,-60,-59,-58,-57,-56,-55,-54,-53,-52,-51,-50,-49, + -48,-47,-46,-45,-44,-43,-42,-41,-40,-39,-38,-37,-36,-35,-34,-33, + -32,-31,-30,-29,-28,-27,-26,-25,-24,-23,-22,-21,-20,-19,-18,-17, + -16,-15,-14,-13,-12,-11,-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + -64,-63,-62,-61,-60,-59,-58,-57,-56,-55,-54,-53,-52,-51,-50,-49, + -48,-47,-46,-45,-44,-43,-42,-41,-40,-39,-38,-37,-36,-35,-34,-33, + -32,-31,-30,-29,-28,-27,-26,-25,-24,-23,-22,-21,-20,-19,-18,-17, + -16,-15,-14,-13,-12,-11,-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, +}; + + +/*************************************************************** + * RDMEM + * read memory byte from addr + ***************************************************************/ +#define RDMEM(addr) m_program->read_byte(addr) + +inline void s2650_device::set_psu(UINT8 new_val) +{ + UINT8 old = m_psu; + + m_psu = new_val; + if ((new_val ^ old) & FO) + m_flag_handler((new_val & FO) ? 1 : 0); +} + +inline UINT8 s2650_device::get_sp() +{ + return (m_psu & SP); +} + +inline void s2650_device::set_sp(UINT8 new_sp) +{ + m_psu = (m_psu & ~SP) | (new_sp & SP); +} + +inline int s2650_device::check_irq_line() +{ + int cycles = 0; + + if (m_irq_state != CLEAR_LINE) + { + if( (m_psu & II) == 0 ) + { + int vector; + if (m_halt) + { + m_halt = 0; + m_iar = (m_iar + 1) & PMSK; + } + vector = standard_irq_callback(0) & 0xff; + /* build effective address within first 8K page */ + m_ea = S2650_relative[vector] & PMSK; + if (vector & 0x80) /* indirect bit set ? */ + { + int addr = m_ea; + cycles += 6; + /* build indirect 32K address */ + m_ea = RDMEM(addr) << 8; + if (!(++addr & PMSK)) addr -= PLEN; + m_ea = (m_ea + RDMEM(addr)) & AMSK; + } + LOG(("S2650 interrupt to $%04x\n", m_ea)); + set_sp(get_sp() + 1); + set_psu(m_psu | II); + m_ras[get_sp()] = m_page + m_iar; + m_page = m_ea & PAGE; + m_iar = m_ea & PMSK; + } + } + return cycles; +} + +/*************************************************************** + * + * set condition code (zero,plus,minus) from result + ***************************************************************/ +#define SET_CC(result) \ + m_psl = (m_psl & ~CC) | ccc[result] + +/*************************************************************** + * + * set condition code (zero,plus,minus) and overflow + ***************************************************************/ +#define SET_CC_OVF(result,value) \ + m_psl = (m_psl & ~(OVF+CC)) | \ + ccc[result + (((value) & 0x80) << 1)] + +#define SET_CC_OVF_ADD(result,value1,value2) SET_CC_OVF(result,~((value1) ^ (value2)) & ((value1) ^ (result))) +#define SET_CC_OVF_SUB(result,value1,value2) SET_CC_OVF(result,~((value1) ^ (value2)) & ((value1) ^ (result))) + +/*************************************************************** + * ROP + * read next opcode + ***************************************************************/ +inline UINT8 s2650_device::ROP() +{ + UINT8 result = m_direct->read_byte(m_page + m_iar); + m_iar = (m_iar + 1) & PMSK; + return result; +} + +/*************************************************************** + * ARG + * read next opcode argument + ***************************************************************/ +inline UINT8 s2650_device::ARG() +{ + UINT8 result = m_direct->read_byte(m_page + m_iar); + m_iar = (m_iar + 1) & PMSK; + return result; +} + +/*************************************************************** + * _REL_EA + * build effective address with relative addressing + ***************************************************************/ +#define _REL_EA(page) \ +{ \ + UINT8 hr = ARG(); /* get 'holding register' */ \ + /* build effective address within current 8K page */ \ + m_ea = page + ((m_iar + S2650_relative[hr]) & PMSK); \ + if (hr & 0x80) { /* indirect bit set ? */ \ + int addr = m_ea; \ + m_icount -= 6; \ + /* build indirect 32K address */ \ + m_ea = RDMEM(addr) << 8; \ + if( (++addr & PMSK) == 0 ) addr -= PLEN; /* page wrap */\ + m_ea = (m_ea + RDMEM(addr)) & AMSK; \ + } \ +} + +/*************************************************************** + * _REL_ZERO + * build effective address with zero relative addressing + ***************************************************************/ +#define _REL_ZERO(page) \ +{ \ + UINT8 hr = ARG(); /* get 'holding register' */ \ + /* build effective address from 0 */ \ + m_ea = (S2650_relative[hr] & PMSK); \ + if (hr & 0x80) { /* indirect bit set ? */ \ + int addr = m_ea; \ + m_icount -= 6; \ + /* build indirect 32K address */ \ + m_ea = RDMEM(addr) << 8; \ + if( (++addr & PMSK) == 0 ) addr -= PLEN; /* page wrap */\ + m_ea = (m_ea + RDMEM(addr)) & AMSK; \ + } \ +} + +/*************************************************************** + * _ABS_EA + * build effective address with absolute addressing + ***************************************************************/ +#define _ABS_EA() \ +{ \ + UINT8 hr, dr; \ + hr = ARG(); /* get 'holding register' */ \ + dr = ARG(); /* get 'data bus register' */ \ + /* build effective address within current 8K page */ \ + m_ea = m_page + (((hr << 8) + dr) & PMSK); \ + /* indirect addressing ? */ \ + if (hr & 0x80) { \ + int addr = m_ea; \ + m_icount -= 6; \ + /* build indirect 32K address */ \ + /* build indirect 32K address */ \ + m_ea = RDMEM(addr) << 8; \ + if( (++addr & PMSK) == 0 ) addr -= PLEN; /* page wrap */\ + m_ea = (m_ea + RDMEM(addr)) & AMSK; \ + } \ + /* check indexed addressing modes */ \ + switch (hr & 0x60) { \ + case 0x00: /* not indexed */ \ + break; \ + case 0x20: /* auto increment indexed */ \ + m_reg[m_r] += 1; \ + m_ea = (m_ea & PAGE)+((m_ea+m_reg[m_r]) & PMSK); \ + m_r = 0; /* absolute addressing reg is R0 */ \ + break; \ + case 0x40: /* auto decrement indexed */ \ + m_reg[m_r] -= 1; \ + m_ea = (m_ea & PAGE)+((m_ea+m_reg[m_r]) & PMSK); \ + m_r = 0; /* absolute addressing reg is R0 */ \ + break; \ + case 0x60: /* indexed */ \ + m_ea = (m_ea & PAGE)+((m_ea+m_reg[m_r]) & PMSK); \ + m_r = 0; /* absolute addressing reg is R0 */ \ + break; \ + } \ +} + +/*************************************************************** + * _BRA_EA + * build effective address with absolute addressing (branch) + ***************************************************************/ +#define _BRA_EA() \ +{ \ + UINT8 hr, dr; \ + hr = ARG(); /* get 'holding register' */ \ + dr = ARG(); /* get 'data bus register' */ \ + /* build address in 32K address space */ \ + m_ea = ((hr << 8) + dr) & AMSK; \ + /* indirect addressing ? */ \ + if (hr & 0x80) { \ + int addr = m_ea; \ + m_icount -= 6; \ + /* build indirect 32K address */ \ + m_ea = RDMEM(addr) << 8; \ + if( (++addr & PMSK) == 0 ) addr -= PLEN; /* page wrap */\ + m_ea = (m_ea + RDMEM(addr)) & AMSK; \ + } \ +} + +/*************************************************************** + * SWAP_REGS + * Swap registers r1-r3 with r4-r6 (the second set) + * This is done everytime the RS bit in PSL changes + ***************************************************************/ +#define SWAP_REGS \ +{ \ + UINT8 tmp; \ + tmp = m_reg[1]; \ + m_reg[1] = m_reg[4]; \ + m_reg[4] = tmp; \ + tmp = m_reg[2]; \ + m_reg[2] = m_reg[5]; \ + m_reg[5] = tmp; \ + tmp = m_reg[3]; \ + m_reg[3] = m_reg[6]; \ + m_reg[6] = tmp; \ +} + +/*************************************************************** + * M_BRR + * Branch relative if cond is true + ***************************************************************/ +#define M_BRR(cond) \ +{ \ + if (cond) \ + { \ + REL_EA( m_page ); \ + m_page = m_ea & PAGE; \ + m_iar = m_ea & PMSK; \ + } else m_iar = (m_iar + 1) & PMSK; \ +} + +/*************************************************************** + * M_ZBRR + * Branch relative to page zero + ***************************************************************/ +#define M_ZBRR() \ +{ \ + REL_ZERO( 0 ); \ + m_page = m_ea & PAGE; \ + m_iar = m_ea & PMSK; \ +} + +/*************************************************************** + * M_BRA + * Branch absolute if cond is true + ***************************************************************/ +#define M_BRA(cond) \ +{ \ + if( cond ) \ + { \ + BRA_EA(); \ + m_page = m_ea & PAGE; \ + m_iar = m_ea & PMSK; \ + } else m_iar = (m_iar + 2) & PMSK; \ +} + +/*************************************************************** + * M_BXA + * Branch indexed absolute (EA + R3) + ***************************************************************/ +#define M_BXA() \ +{ \ + BRA_EA(); \ + m_ea = (m_ea + m_reg[3]) & AMSK; \ + m_page = m_ea & PAGE; \ + m_iar = m_ea & PMSK; \ +} + +/*************************************************************** + * M_BSR + * Branch to subroutine relative if cond is true + ***************************************************************/ +#define M_BSR(cond) \ +{ \ + if( cond ) \ + { \ + REL_EA(m_page); \ + set_sp(get_sp() + 1); \ + m_ras[get_sp()] = m_page + m_iar; \ + m_page = m_ea & PAGE; \ + m_iar = m_ea & PMSK; \ + } else m_iar = (m_iar + 1) & PMSK; \ +} + +/*************************************************************** + * M_ZBSR + * Branch to subroutine relative to page zero + ***************************************************************/ +#define M_ZBSR() \ +{ \ + REL_ZERO(0); \ + set_sp(get_sp() + 1); \ + m_ras[get_sp()] = m_page + m_iar; \ + m_page = m_ea & PAGE; \ + m_iar = m_ea & PMSK; \ +} + +/*************************************************************** + * M_BSA + * Branch to subroutine absolute + ***************************************************************/ +#define M_BSA(cond) \ +{ \ + if( cond ) \ + { \ + BRA_EA(); \ + set_sp(get_sp() + 1); \ + m_ras[get_sp()] = m_page + m_iar; \ + m_page = m_ea & PAGE; \ + m_iar = m_ea & PMSK; \ + } else m_iar = (m_iar + 2) & PMSK; \ +} + +/*************************************************************** + * M_BSXA + * Branch to subroutine indexed absolute (EA + R3) + ***************************************************************/ +#define M_BSXA() \ +{ \ + BRA_EA(); \ + m_ea = (m_ea + m_reg[3]) & AMSK; \ + set_sp(get_sp() + 1); \ + m_ras[get_sp()] = m_page + m_iar; \ + m_page = m_ea & PAGE; \ + m_iar = m_ea & PMSK; \ +} + +/*************************************************************** + * M_RET + * Return from subroutine if cond is true + ***************************************************************/ +#define M_RET(cond) \ +{ \ + if( cond ) \ + { \ + m_icount -= 6; \ + m_ea = m_ras[get_sp()]; \ + set_sp(get_sp() - 1); \ + m_page = m_ea & PAGE; \ + m_iar = m_ea & PMSK; \ + } \ +} + +/*************************************************************** + * M_RETE + * Return from subroutine if cond is true + * and enable interrupts; afterwards check IRQ line + * state and eventually take next interrupt + ***************************************************************/ +#define M_RETE(cond) \ +{ \ + if( cond ) \ + { \ + m_ea = m_ras[get_sp()]; \ + set_sp(get_sp() - 1); \ + m_page = m_ea & PAGE; \ + m_iar = m_ea & PMSK; \ + set_psu(m_psu & ~II); \ + m_icount -= check_irq_line(); \ + } \ +} + +/*************************************************************** + * M_LOD + * Load destination with source register + ***************************************************************/ +#define M_LOD(dest,source) \ +{ \ + dest = source; \ + SET_CC(dest); \ +} + +/*************************************************************** + * M_STR + * Store source register to memory addr (CC unchanged) + ***************************************************************/ +#define M_STR(address,source) \ + m_program->write_byte(address, source) + +/*************************************************************** + * M_AND + * Logical and destination with source + ***************************************************************/ +#define M_AND(dest,source) \ +{ \ + dest &= source; \ + SET_CC(dest); \ +} + +/*************************************************************** + * M_IOR + * Logical inclusive or destination with source + ***************************************************************/ +#define M_IOR(dest,source) \ +{ \ + dest |= source; \ + SET_CC(dest); \ +} + +/*************************************************************** + * M_EOR + * Logical exclusive or destination with source + ***************************************************************/ +#define M_EOR(dest,source) \ +{ \ + dest ^= source; \ + SET_CC(dest); \ +} + +/*************************************************************** + * M_ADD + * Add source to destination + * Add with carry if WC flag of PSL is set + ***************************************************************/ +#define M_ADD(dest,_source) \ +{ \ + UINT8 source = _source; \ + UINT8 before = dest; \ + /* add source; carry only if WC is set */ \ + UINT16 res = dest + source + ((m_psl >> 3) & m_psl & C); \ + m_psl &= ~(C | OVF | IDC); \ + if(res & 0x100) m_psl |= C; \ + dest = res & 0xff; \ + if( (dest & 15) < (before & 15) ) m_psl |= IDC; \ + SET_CC_OVF_ADD(dest,before,source); \ +} + +/*************************************************************** + * M_SUB + * Subtract source from destination + * Subtract with borrow if WC flag of PSL is set + ***************************************************************/ +#define M_SUB(dest,_source) \ +{ \ + UINT8 source = _source; \ + UINT8 before = dest; \ + /* subtract source; borrow only if WC is set */ \ + UINT16 res = dest - source - ((m_psl >> 3) & (m_psl ^ C) & C); \ + m_psl &= ~(C | OVF | IDC); \ + if((res & 0x100)==0) m_psl |= C; \ + dest = res & 0xff; \ + if( (dest & 15) <= (before & 15) ) m_psl |= IDC; \ + SET_CC_OVF_SUB(dest,before,source); \ +} + +/*************************************************************** + * M_COM + * Compare register against value. If COM of PSL is set, + * use unsigned, else signed comparison + ***************************************************************/ +#define M_COM(reg,val) \ +{ \ + int d; \ + m_psl &= ~CC; \ + if (m_psl & COM) d = (UINT8)reg - (UINT8)val; \ + else d = (INT8)reg - (INT8)val; \ + if( d < 0 ) m_psl |= 0x80; \ + else \ + if( d > 0 ) m_psl |= 0x40; \ +} + +/*************************************************************** + * M_DAR + * Decimal adjust register + ***************************************************************/ +#define M_DAR(dest) \ +{ \ + if ((m_psl & C) == 0) dest += 0xA0; \ + if ((m_psl & IDC) == 0) dest = (dest & 0xF0) | ((dest + 0x0A) & 0x0F);\ +} + +/*************************************************************** + * M_RRL + * Rotate register left; If WC of PSL is set, rotate + * through carry, else rotate circular + ***************************************************************/ +#define M_RRL(dest) \ +{ \ + UINT8 before = dest; \ + if( m_psl & WC ) \ + { \ + UINT8 c = m_psl & C; \ + m_psl &= ~(C + IDC); \ + dest = (before << 1) | c; \ + m_psl |= (before >> 7) + (dest & IDC); \ + } \ + else \ + { \ + dest = (before << 1) | (before >> 7); \ + } \ + SET_CC(dest); \ + m_psl = (m_psl & ~OVF) | (((dest ^ before) >> 5) & OVF); \ +} + +/*************************************************************** + * M_RRR + * Rotate register right; If WC of PSL is set, rotate + * through carry, else rotate circular + ***************************************************************/ +#define M_RRR(dest) \ +{ \ + UINT8 before = dest; \ + if (m_psl & WC) \ + { \ + UINT8 c = m_psl & C; \ + m_psl &= ~(C + IDC); \ + dest = (before >> 1) | (c << 7); \ + m_psl |= (before & C) + (dest & IDC); \ + } else dest = (before >> 1) | (before << 7); \ + SET_CC(dest); \ + m_psl = (m_psl & ~OVF) | (((dest ^ before) >> 5) & OVF); \ +} + +// bxd() not necessary + +/*************************************************************** + * M_SPSU + * Store processor status upper (PSU) to register R0 + * Checks for External Sense IO port + ***************************************************************/ +#define M_SPSU() \ +{ \ + R0 = ((m_psu & ~PSU34) | (m_io->read_byte(S2650_SENSE_PORT) ? SI : 0)); \ + SET_CC(R0); \ +} + +/*************************************************************** + * M_SPSL + * Store processor status lower (PSL) to register R0 + ***************************************************************/ +#define M_SPSL() \ +{ \ + R0 = m_psl; \ + SET_CC(R0); \ +} + +/*************************************************************** + * M_CPSU + * Clear processor status upper (PSU), selective + ***************************************************************/ +#define M_CPSU() \ +{ \ + UINT8 cpsu = ARG(); \ + set_psu(m_psu & ~cpsu); \ + m_icount -= check_irq_line(); \ +} + +/*************************************************************** + * M_CPSL + * Clear processor status lower (PSL), selective + ***************************************************************/ +#define M_CPSL() \ +{ \ + UINT8 cpsl = ARG(); \ + /* select other register set now ? */ \ + if( (cpsl & RS) && (m_psl & RS) ) \ + SWAP_REGS; \ + m_psl = m_psl & ~cpsl; \ +} + +/*************************************************************** + * M_PPSU + * Preset processor status upper (PSU), selective + * Unused bits 3 and 4 can't be set + ***************************************************************/ +#define M_PPSU() \ +{ \ + UINT8 ppsu = (ARG() & ~PSU34) & ~SI; \ + set_psu(m_psu | ppsu); \ +} + +/*************************************************************** + * M_PPSL + * Preset processor status lower (PSL), selective + ***************************************************************/ +#define M_PPSL() \ +{ \ + UINT8 ppsl = ARG(); \ + /* select 2nd register set now ? */ \ + if ((ppsl & RS) && !(m_psl & RS)) \ + SWAP_REGS; \ + m_psl = m_psl | ppsl; \ +} + +/*************************************************************** + * M_TPSU + * Test processor status upper (PSU) + ***************************************************************/ +#define M_TPSU() \ +{ \ + UINT8 tpsu = ARG(); \ + UINT8 rpsu = (m_psu | (m_io->read_byte(S2650_SENSE_PORT) ? SI : 0)); \ + m_psl &= ~CC; \ + if( (rpsu & tpsu) != tpsu ) \ + m_psl |= 0x80; \ +} + +/*************************************************************** + * M_TPSL + * Test processor status lower (PSL) + ***************************************************************/ +#define M_TPSL() \ +{ \ + UINT8 tpsl = ARG(); \ + if( (m_psl & tpsl) != tpsl ) \ + m_psl = (m_psl & ~CC) | 0x80; \ + else \ + m_psl &= ~CC; \ +} + +/*************************************************************** + * M_TMI + * Test under mask immediate + ***************************************************************/ +#define M_TMI(value) \ +{ \ + UINT8 tmi = ARG(); \ + m_psl &= ~CC; \ + if( (value & tmi) != tmi ) \ + m_psl |= 0x80; \ +} + +#if INLINE_EA +#define REL_EA(page) _REL_EA(page) +#define REL_ZERO(page) _REL_ZERO(page) +#define ABS_EA() _ABS_EA() +#define BRA_EA() _BRA_EA() +#else +static void REL_EA(unsigned short page) _REL_EA(page) +static void REL_ZERO(unsigned short page) _REL_ZERO(page) +static void ABS_EA(void) _ABS_EA() +static void BRA_EA(void) _BRA_EA() +#endif + +void s2650_device::device_start() +{ + m_flag_handler.resolve_safe(); + + m_program = &space(AS_PROGRAM); + m_direct = &m_program->direct(); + m_io = &space(AS_IO); + + save_item(NAME(m_ppc)); + save_item(NAME(m_page)); + save_item(NAME(m_iar)); + save_item(NAME(m_ea)); + save_item(NAME(m_psl)); + save_item(NAME(m_psu)); + save_item(NAME(m_r)); + save_item(NAME(m_reg)); + save_item(NAME(m_halt)); + save_item(NAME(m_ir)); + save_item(NAME(m_ras)); + save_item(NAME(m_irq_state)); + + state_add( S2650_PC, "PC", m_debugger_temp).callimport().callexport().formatstr("%04X"); + state_add( S2650_PS, "PS", m_debugger_temp).callimport().callexport().formatstr("%04X"); + state_add( S2650_R0, "R0", m_reg[0]).formatstr("%02X"); + state_add( S2650_R1, "R1", m_reg[1]).formatstr("%02X"); + state_add( S2650_R2, "R2", m_reg[2]).formatstr("%02X"); + state_add( S2650_R3, "R3", m_reg[3]).formatstr("%02X"); + state_add( S2650_R1A, "R1'", m_reg[4]).formatstr("%02X"); + state_add( S2650_R2A, "R2'", m_reg[5]).formatstr("%02X"); + state_add( S2650_R3A, "R3'", m_reg[6]).formatstr("%02X"); + state_add( S2650_HALT, "HALT", m_halt).formatstr("%01X"); + state_add( S2650_SI, "SI", m_debugger_temp).mask(0x01).callimport().callexport().formatstr("%01X"); + state_add( S2650_FO, "FO", m_debugger_temp).mask(0x01).callimport().callexport().formatstr("%01X"); + + state_add( STATE_GENPC, "GENPC", m_debugger_temp).callexport().noshow(); + state_add( STATE_GENFLAGS, "GENFLAGS", m_debugger_temp).formatstr("%16s").noshow(); + + m_icountptr = &m_icount; +} + +void s2650_device::state_import(const device_state_entry &entry) +{ + switch (entry.index()) + { + case S2650_PC: + m_page = m_debugger_temp & PAGE; + m_iar = m_debugger_temp & PMSK; + break; + + case S2650_PS: + m_psl = m_debugger_temp & 0xff; + set_psu(m_debugger_temp >> 8); + break; + + case S2650_SI: + s2650_set_sense(m_debugger_temp); + break; + + case S2650_FO: + s2650_set_flag(m_debugger_temp); + break; + } +} + +void s2650_device::state_export(const device_state_entry &entry) +{ + switch (entry.index()) + { + case STATE_GENPC: + case S2650_PC: + m_debugger_temp = m_page + m_iar; + break; + + case S2650_PS: + m_debugger_temp = (m_psu << 8) | m_psl; + break; + + case S2650_SI: + m_debugger_temp = (m_psu & SI) ? 1 : 0; + break; + + case S2650_FO: + m_debugger_temp = (m_psu & FO) ? 1 : 0; + break; + } +} + +void s2650_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + switch (entry.index()) + { + case STATE_GENFLAGS: + strprintf(str, "%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c", + m_psu & 0x80 ? 'S':'.', + m_psu & 0x40 ? 'O':'.', + m_psu & 0x20 ? 'I':'.', + m_psu & 0x10 ? '?':'.', + m_psu & 0x08 ? '?':'.', + m_psu & 0x04 ? 's':'.', + m_psu & 0x02 ? 's':'.', + m_psu & 0x01 ? 's':'.', + m_psl & 0x80 ? 'M':'.', + m_psl & 0x40 ? 'P':'.', + m_psl & 0x20 ? 'H':'.', + m_psl & 0x10 ? 'R':'.', + m_psl & 0x08 ? 'W':'.', + m_psl & 0x04 ? 'V':'.', + m_psl & 0x02 ? '2':'.', + m_psl & 0x01 ? 'C':'.'); + break; + } +} + +void s2650_device::device_reset() +{ + m_ppc = 0; + m_page = 0, + m_iar = 0; + m_ea = 0; + m_r = 0; + m_halt = 0; + m_ir = 0; + m_irq_state = CLEAR_LINE; + memset(m_reg, 0, sizeof(m_reg)); + memset(m_ras, 0, sizeof(m_ras)); + + m_program = &space(AS_PROGRAM); + m_direct = &m_program->direct(); + m_io = &space(AS_IO); + m_psl = COM | WC; + /* force write */ + m_psu = 0xff; + set_psu(0); +} + + +void s2650_device::execute_set_input(int irqline, int state) +{ + switch (irqline) + { + case INPUT_LINE_IRQ0: + m_irq_state = state; + break; + + case S2650_SENSE_LINE: + if (state == CLEAR_LINE) + s2650_set_sense(0); + else + s2650_set_sense(1); + break; + } +} + +void s2650_device::s2650_set_flag(int state) +{ + if (state) + set_psu(m_psu | FO); + else + set_psu(m_psu & ~FO); +} + +int s2650_device::s2650_get_flag() +{ + return (m_psu & FO) ? 1 : 0; +} + +void s2650_device::s2650_set_sense(int state) +{ + if (state) + set_psu(m_psu | SI); + else + set_psu(m_psu & ~SI); +} + +WRITE_LINE_MEMBER(s2650_device::write_sense) +{ + set_input_line(S2650_SENSE_LINE, state); +} + +void s2650_device::execute_run() +{ + /* check for external irqs */ + int cycles = check_irq_line(); + m_icount -= cycles; + + do + { + m_ppc = m_page + m_iar; + + debugger_instruction_hook(this, m_page + m_iar); + + m_ir = ROP(); + m_r = m_ir & 3; /* register / value */ + switch (m_ir) { + case 0x00: /* LODZ,0 */ + case 0x01: /* LODZ,1 */ + case 0x02: /* LODZ,2 */ + case 0x03: /* LODZ,3 */ + m_icount -= 6; + M_LOD( R0, m_reg[m_r] ); + break; + + case 0x04: /* LODI,0 v */ + case 0x05: /* LODI,1 v */ + case 0x06: /* LODI,2 v */ + case 0x07: /* LODI,3 v */ + m_icount -= 6; + M_LOD( m_reg[m_r], ARG() ); + break; + + case 0x08: /* LODR,0 (*)a */ + case 0x09: /* LODR,1 (*)a */ + case 0x0a: /* LODR,2 (*)a */ + case 0x0b: /* LODR,3 (*)a */ + m_icount -= 9; + REL_EA( m_page ); + M_LOD( m_reg[m_r], RDMEM(m_ea) ); + break; + + case 0x0c: /* LODA,0 (*)a(,X) */ + case 0x0d: /* LODA,1 (*)a(,X) */ + case 0x0e: /* LODA,2 (*)a(,X) */ + case 0x0f: /* LODA,3 (*)a(,X) */ + m_icount -= 12; + ABS_EA(); + M_LOD( m_reg[m_r], RDMEM(m_ea) ); + break; + + case 0x10: /* illegal */ + case 0x11: /* illegal */ + m_icount -= 7; + break; + case 0x12: /* SPSU */ + m_icount -= 6; + M_SPSU(); + break; + case 0x13: /* SPSL */ + m_icount -= 6; + M_SPSL(); + break; + + case 0x14: /* RETC,0 (zero) */ + case 0x15: /* RETC,1 (plus) */ + case 0x16: /* RETC,2 (minus) */ + m_icount -= 9; /* +2 cycles if condition is true */ + M_RET( (m_psl >> 6) == m_r ); + break; + case 0x17: /* RETC,3 (always) */ + m_icount -= 9; /* +2 cycles if condition is true */ + M_RET( 1 ); + break; + + case 0x18: /* BCTR,0 (*)a */ + case 0x19: /* BCTR,1 (*)a */ + case 0x1a: /* BCTR,2 (*)a */ + m_icount -= 9; + M_BRR( (m_psl >> 6) == m_r ); + break; + case 0x1b: /* BCTR,3 (*)a */ + m_icount -= 9; + M_BRR( 1 ); + break; + + case 0x1c: /* BCTA,0 (*)a */ + case 0x1d: /* BCTA,1 (*)a */ + case 0x1e: /* BCTA,2 (*)a */ + m_icount -= 9; + M_BRA( (m_psl >> 6) == m_r ); + break; + case 0x1f: /* BCTA,3 (*)a */ + m_icount -= 9; + M_BRA( 1 ); + break; + + case 0x20: /* EORZ,0 */ + case 0x21: /* EORZ,1 */ + case 0x22: /* EORZ,2 */ + case 0x23: /* EORZ,3 */ + m_icount -= 6; + M_EOR( R0, m_reg[m_r] ); + break; + + case 0x24: /* EORI,0 v */ + case 0x25: /* EORI,1 v */ + case 0x26: /* EORI,2 v */ + case 0x27: /* EORI,3 v */ + m_icount -= 6; + M_EOR( m_reg[m_r], ARG() ); + break; + + case 0x28: /* EORR,0 (*)a */ + case 0x29: /* EORR,1 (*)a */ + case 0x2a: /* EORR,2 (*)a */ + case 0x2b: /* EORR,3 (*)a */ + m_icount -= 9; + REL_EA( m_page ); + M_EOR( m_reg[m_r], RDMEM(m_ea) ); + break; + + case 0x2c: /* EORA,0 (*)a(,X) */ + case 0x2d: /* EORA,1 (*)a(,X) */ + case 0x2e: /* EORA,2 (*)a(,X) */ + case 0x2f: /* EORA,3 (*)a(,X) */ + m_icount -= 12; + ABS_EA(); + M_EOR( m_reg[m_r], RDMEM(m_ea) ); + break; + + case 0x30: /* REDC,0 */ + case 0x31: /* REDC,1 */ + case 0x32: /* REDC,2 */ + case 0x33: /* REDC,3 */ + m_icount -= 6; + m_reg[m_r] = m_io->read_byte(S2650_CTRL_PORT); + SET_CC( m_reg[m_r] ); + break; + + case 0x34: /* RETE,0 */ + case 0x35: /* RETE,1 */ + case 0x36: /* RETE,2 */ + m_icount -= 9; + M_RETE( (m_psl >> 6) == m_r ); + break; + case 0x37: /* RETE,3 */ + m_icount -= 9; + M_RETE( 1 ); + break; + + case 0x38: /* BSTR,0 (*)a */ + case 0x39: /* BSTR,1 (*)a */ + case 0x3a: /* BSTR,2 (*)a */ + m_icount -= 9; + M_BSR( (m_psl >> 6) == m_r ); + break; + case 0x3b: /* BSTR,R3 (*)a */ + m_icount -= 9; + M_BSR( 1 ); + break; + + case 0x3c: /* BSTA,0 (*)a */ + case 0x3d: /* BSTA,1 (*)a */ + case 0x3e: /* BSTA,2 (*)a */ + m_icount -= 9; + M_BSA( (m_psl >> 6) == m_r ); + break; + case 0x3f: /* BSTA,3 (*)a */ + m_icount -= 9; + M_BSA( 1 ); + break; + + case 0x40: /* HALT */ + m_icount -= 6; + m_iar = (m_iar - 1) & PMSK; + m_halt = 1; + if (m_icount > 0) + m_icount = 0; + break; + case 0x41: /* ANDZ,1 */ + case 0x42: /* ANDZ,2 */ + case 0x43: /* ANDZ,3 */ + m_icount -= 6; + M_AND( R0, m_reg[m_r] ); + break; + + case 0x44: /* ANDI,0 v */ + case 0x45: /* ANDI,1 v */ + case 0x46: /* ANDI,2 v */ + case 0x47: /* ANDI,3 v */ + m_icount -= 6; + M_AND( m_reg[m_r], ARG() ); + break; + + case 0x48: /* ANDR,0 (*)a */ + case 0x49: /* ANDR,1 (*)a */ + case 0x4a: /* ANDR,2 (*)a */ + case 0x4b: /* ANDR,3 (*)a */ + m_icount -= 9; + REL_EA( m_page ); + M_AND( m_reg[m_r], RDMEM(m_ea) ); + break; + + case 0x4c: /* ANDA,0 (*)a(,X) */ + case 0x4d: /* ANDA,1 (*)a(,X) */ + case 0x4e: /* ANDA,2 (*)a(,X) */ + case 0x4f: /* ANDA,3 (*)a(,X) */ + m_icount -= 12; + ABS_EA(); + M_AND( m_reg[m_r], RDMEM(m_ea) ); + break; + + case 0x50: /* RRR,0 */ + case 0x51: /* RRR,1 */ + case 0x52: /* RRR,2 */ + case 0x53: /* RRR,3 */ + m_icount -= 6; + M_RRR( m_reg[m_r] ); + break; + + case 0x54: /* REDE,0 v */ + case 0x55: /* REDE,1 v */ + case 0x56: /* REDE,2 v */ + case 0x57: /* REDE,3 v */ + m_icount -= 9; + m_reg[m_r] = m_io->read_byte( ARG() ); + SET_CC(m_reg[m_r]); + break; + + case 0x58: /* BRNR,0 (*)a */ + case 0x59: /* BRNR,1 (*)a */ + case 0x5a: /* BRNR,2 (*)a */ + case 0x5b: /* BRNR,3 (*)a */ + m_icount -= 9; + M_BRR( m_reg[m_r] ); + break; + + case 0x5c: /* BRNA,0 (*)a */ + case 0x5d: /* BRNA,1 (*)a */ + case 0x5e: /* BRNA,2 (*)a */ + case 0x5f: /* BRNA,3 (*)a */ + m_icount -= 9; + M_BRA( m_reg[m_r] ); + break; + + case 0x60: /* IORZ,0 */ + case 0x61: /* IORZ,1 */ + case 0x62: /* IORZ,2 */ + case 0x63: /* IORZ,3 */ + m_icount -= 6; + M_IOR( R0, m_reg[m_r] ); + break; + + case 0x64: /* IORI,0 v */ + case 0x65: /* IORI,1 v */ + case 0x66: /* IORI,2 v */ + case 0x67: /* IORI,3 v */ + m_icount -= 6; + M_IOR( m_reg[m_r], ARG() ); + break; + + case 0x68: /* IORR,0 (*)a */ + case 0x69: /* IORR,1 (*)a */ + case 0x6a: /* IORR,2 (*)a */ + case 0x6b: /* IORR,3 (*)a */ + m_icount -= 9; + REL_EA( m_page ); + M_IOR( m_reg[m_r],RDMEM(m_ea) ); + break; + + case 0x6c: /* IORA,0 (*)a(,X) */ + case 0x6d: /* IORA,1 (*)a(,X) */ + case 0x6e: /* IORA,2 (*)a(,X) */ + case 0x6f: /* IORA,3 (*)a(,X) */ + m_icount -= 12; + ABS_EA(); + M_IOR( m_reg[m_r], RDMEM(m_ea) ); + break; + + case 0x70: /* REDD,0 */ + case 0x71: /* REDD,1 */ + case 0x72: /* REDD,2 */ + case 0x73: /* REDD,3 */ + m_icount -= 6; + m_reg[m_r] = m_io->read_byte(S2650_DATA_PORT); + SET_CC(m_reg[m_r]); + break; + + case 0x74: /* CPSU */ + m_icount -= 9; + M_CPSU(); + break; + case 0x75: /* CPSL */ + m_icount -= 9; + M_CPSL(); + break; + case 0x76: /* PPSU */ + m_icount -= 9; + M_PPSU(); + break; + case 0x77: /* PPSL */ + m_icount -= 9; + M_PPSL(); + break; + + case 0x78: /* BSNR,0 (*)a */ + case 0x79: /* BSNR,1 (*)a */ + case 0x7a: /* BSNR,2 (*)a */ + case 0x7b: /* BSNR,3 (*)a */ + m_icount -= 9; + M_BSR( m_reg[m_r] ); + break; + + case 0x7c: /* BSNA,0 (*)a */ + case 0x7d: /* BSNA,1 (*)a */ + case 0x7e: /* BSNA,2 (*)a */ + case 0x7f: /* BSNA,3 (*)a */ + m_icount -= 9; + M_BSA( m_reg[m_r] ); + break; + + case 0x80: /* ADDZ,0 */ + case 0x81: /* ADDZ,1 */ + case 0x82: /* ADDZ,2 */ + case 0x83: /* ADDZ,3 */ + m_icount -= 6; + M_ADD( R0,m_reg[m_r] ); + break; + + case 0x84: /* ADDI,0 v */ + case 0x85: /* ADDI,1 v */ + case 0x86: /* ADDI,2 v */ + case 0x87: /* ADDI,3 v */ + m_icount -= 6; + M_ADD( m_reg[m_r], ARG() ); + break; + + case 0x88: /* ADDR,0 (*)a */ + case 0x89: /* ADDR,1 (*)a */ + case 0x8a: /* ADDR,2 (*)a */ + case 0x8b: /* ADDR,3 (*)a */ + m_icount -= 9; + REL_EA(m_page); + M_ADD( m_reg[m_r], RDMEM(m_ea) ); + break; + + case 0x8c: /* ADDA,0 (*)a(,X) */ + case 0x8d: /* ADDA,1 (*)a(,X) */ + case 0x8e: /* ADDA,2 (*)a(,X) */ + case 0x8f: /* ADDA,3 (*)a(,X) */ + m_icount -= 12; + ABS_EA(); + M_ADD( m_reg[m_r], RDMEM(m_ea) ); + break; + + case 0x90: /* illegal */ + case 0x91: /* illegal */ + m_icount -= 7; + break; + case 0x92: /* LPSU */ + m_icount -= 6; + set_psu((R0 & ~PSU34) & ~SI); + break; + case 0x93: /* LPSL */ + m_icount -= 6; + /* change register set ? */ + if ((m_psl ^ R0) & RS) + SWAP_REGS; + m_psl = R0; + break; + + case 0x94: /* DAR,0 */ + case 0x95: /* DAR,1 */ + case 0x96: /* DAR,2 */ + case 0x97: /* DAR,3 */ + m_icount -= 9; + M_DAR( m_reg[m_r] ); + break; + + case 0x98: /* BCFR,0 (*)a */ + case 0x99: /* BCFR,1 (*)a */ + case 0x9a: /* BCFR,2 (*)a */ + m_icount -= 9; + M_BRR( (m_psl >> 6) != m_r ); + break; + case 0x9b: /* ZBRR (*)a */ + m_icount -= 9; + M_ZBRR(); + break; + + case 0x9c: /* BCFA,0 (*)a */ + case 0x9d: /* BCFA,1 (*)a */ + case 0x9e: /* BCFA,2 (*)a */ + m_icount -= 9; + M_BRA( (m_psl >> 6) != m_r ); + break; + case 0x9f: /* BXA (*)a */ + m_icount -= 9; + M_BXA(); + break; + + case 0xa0: /* SUBZ,0 */ + case 0xa1: /* SUBZ,1 */ + case 0xa2: /* SUBZ,2 */ + case 0xa3: /* SUBZ,3 */ + m_icount -= 6; + M_SUB( R0, m_reg[m_r] ); + break; + + case 0xa4: /* SUBI,0 v */ + case 0xa5: /* SUBI,1 v */ + case 0xa6: /* SUBI,2 v */ + case 0xa7: /* SUBI,3 v */ + m_icount -= 6; + M_SUB( m_reg[m_r], ARG() ); + break; + + case 0xa8: /* SUBR,0 (*)a */ + case 0xa9: /* SUBR,1 (*)a */ + case 0xaa: /* SUBR,2 (*)a */ + case 0xab: /* SUBR,3 (*)a */ + m_icount -= 9; + REL_EA(m_page); + M_SUB( m_reg[m_r], RDMEM(m_ea) ); + break; + + case 0xac: /* SUBA,0 (*)a(,X) */ + case 0xad: /* SUBA,1 (*)a(,X) */ + case 0xae: /* SUBA,2 (*)a(,X) */ + case 0xaf: /* SUBA,3 (*)a(,X) */ + m_icount -= 12; + ABS_EA(); + M_SUB( m_reg[m_r], RDMEM(m_ea) ); + break; + + case 0xb0: /* WRTC,0 */ + case 0xb1: /* WRTC,1 */ + case 0xb2: /* WRTC,2 */ + case 0xb3: /* WRTC,3 */ + m_icount -= 6; + m_io->write_byte(S2650_CTRL_PORT,m_reg[m_r]); + break; + + case 0xb4: /* TPSU */ + m_icount -= 9; + M_TPSU(); + break; + case 0xb5: /* TPSL */ + m_icount -= 9; + M_TPSL(); + break; + case 0xb6: /* illegal */ + case 0xb7: /* illegal */ + m_icount -= 7; + break; + + case 0xb8: /* BSFR,0 (*)a */ + case 0xb9: /* BSFR,1 (*)a */ + case 0xba: /* BSFR,2 (*)a */ + m_icount -= 9; + M_BSR( (m_psl >> 6) != m_r ); + break; + case 0xbb: /* ZBSR (*)a */ + m_icount -= 9; + M_ZBSR(); + break; + + case 0xbc: /* BSFA,0 (*)a */ + case 0xbd: /* BSFA,1 (*)a */ + case 0xbe: /* BSFA,2 (*)a */ + m_icount -= 9; + M_BSA( (m_psl >> 6) != m_r ); + break; + case 0xbf: /* BSXA (*)a */ + m_icount -= 9; + M_BSXA(); + break; + + case 0xc0: /* NOP */ + m_icount -= 6; + break; + case 0xc1: /* STRZ,1 */ + case 0xc2: /* STRZ,2 */ + case 0xc3: /* STRZ,3 */ + m_icount -= 6; + M_LOD( m_reg[m_r], R0 ); + break; + + case 0xc4: /* illegal */ + case 0xc5: /* illegal */ + case 0xc6: /* illegal */ + case 0xc7: /* illegal */ + m_icount -= 7; + break; + + case 0xc8: /* STRR,0 (*)a */ + case 0xc9: /* STRR,1 (*)a */ + case 0xca: /* STRR,2 (*)a */ + case 0xcb: /* STRR,3 (*)a */ + m_icount -= 9; + REL_EA(m_page); + M_STR( m_ea, m_reg[m_r] ); + break; + + case 0xcc: /* STRA,0 (*)a(,X) */ + case 0xcd: /* STRA,1 (*)a(,X) */ + case 0xce: /* STRA,2 (*)a(,X) */ + case 0xcf: /* STRA,3 (*)a(,X) */ + m_icount -= 12; + ABS_EA(); + M_STR( m_ea, m_reg[m_r] ); + break; + + case 0xd0: /* RRL,0 */ + case 0xd1: /* RRL,1 */ + case 0xd2: /* RRL,2 */ + case 0xd3: /* RRL,3 */ + m_icount -= 6; + M_RRL( m_reg[m_r] ); + break; + + case 0xd4: /* WRTE,0 v */ + case 0xd5: /* WRTE,1 v */ + case 0xd6: /* WRTE,2 v */ + case 0xd7: /* WRTE,3 v */ + m_icount -= 9; + m_io->write_byte( ARG(), m_reg[m_r] ); + break; + + case 0xd8: /* BIRR,0 (*)a */ + case 0xd9: /* BIRR,1 (*)a */ + case 0xda: /* BIRR,2 (*)a */ + case 0xdb: /* BIRR,3 (*)a */ + m_icount -= 9; + M_BRR( ++m_reg[m_r] ); + break; + + case 0xdc: /* BIRA,0 (*)a */ + case 0xdd: /* BIRA,1 (*)a */ + case 0xde: /* BIRA,2 (*)a */ + case 0xdf: /* BIRA,3 (*)a */ + m_icount -= 9; + M_BRA( ++m_reg[m_r] ); + break; + + case 0xe0: /* COMZ,0 */ + case 0xe1: /* COMZ,1 */ + case 0xe2: /* COMZ,2 */ + case 0xe3: /* COMZ,3 */ + m_icount -= 6; + M_COM( R0, m_reg[m_r] ); + break; + + case 0xe4: /* COMI,0 v */ + case 0xe5: /* COMI,1 v */ + case 0xe6: /* COMI,2 v */ + case 0xe7: /* COMI,3 v */ + m_icount -= 6; + M_COM( m_reg[m_r], ARG() ); + break; + + case 0xe8: /* COMR,0 (*)a */ + case 0xe9: /* COMR,1 (*)a */ + case 0xea: /* COMR,2 (*)a */ + case 0xeb: /* COMR,3 (*)a */ + m_icount -= 9; + REL_EA(m_page); + M_COM( m_reg[m_r], RDMEM(m_ea) ); + break; + + case 0xec: /* COMA,0 (*)a(,X) */ + case 0xed: /* COMA,1 (*)a(,X) */ + case 0xee: /* COMA,2 (*)a(,X) */ + case 0xef: /* COMA,3 (*)a(,X) */ + m_icount -= 12; + ABS_EA(); + M_COM( m_reg[m_r], RDMEM(m_ea) ); + break; + + case 0xf0: /* WRTD,0 */ + case 0xf1: /* WRTD,1 */ + case 0xf2: /* WRTD,2 */ + case 0xf3: /* WRTD,3 */ + m_icount -= 6; + m_io->write_byte(S2650_DATA_PORT, m_reg[m_r]); + break; + + case 0xf4: /* TMI,0 v */ + case 0xf5: /* TMI,1 v */ + case 0xf6: /* TMI,2 v */ + case 0xf7: /* TMI,3 v */ + m_icount -= 9; + M_TMI( m_reg[m_r] ); + break; + + case 0xf8: /* BDRR,0 (*)a */ + case 0xf9: /* BDRR,1 (*)a */ + case 0xfa: /* BDRR,2 (*)a */ + case 0xfb: /* BDRR,3 (*)a */ + m_icount -= 9; + M_BRR( --m_reg[m_r] ); + break; + + case 0xfc: /* BDRA,0 (*)a */ + case 0xfd: /* BDRA,1 (*)a */ + case 0xfe: /* BDRA,2 (*)a */ + case 0xff: /* BDRA,3 (*)a */ + m_icount -= 9; + M_BRA( --m_reg[m_r] ); + break; + } + } while( m_icount > 0 ); +} diff --git a/src/devices/cpu/s2650/s2650.h b/src/devices/cpu/s2650/s2650.h new file mode 100644 index 00000000000..e9a0a01c3b9 --- /dev/null +++ b/src/devices/cpu/s2650/s2650.h @@ -0,0 +1,111 @@ +// license:BSD-3-Clause +// copyright-holders:Juergen Buchmueller +#pragma once + +#ifndef __S2650_H__ +#define __S2650_H__ + + +enum +{ + S2650_PC=1, S2650_PS, S2650_R0, S2650_R1, S2650_R2, S2650_R3, + S2650_R1A, S2650_R2A, S2650_R3A, + S2650_HALT, S2650_SI, S2650_FO +}; + +/* fake I/O space ports */ +enum +{ + S2650_EXT_PORT = 0x00ff, /* M/~IO=0 D/~C=x E/~NE=1 */ + S2650_CTRL_PORT = 0x0100, /* M/~IO=0 D/~C=0 E/~NE=0 */ + S2650_DATA_PORT = 0x0101, /* M/~IO=0 D/~C=1 E/~NE=0 */ + S2650_SENSE_PORT = 0x0102 /* Fake Sense Line */ +}; + + +extern const device_type S2650; + + +#define MCFG_S2650_FLAG_HANDLER(_devcb) \ + devcb = &s2650_device::set_flag_handler(*device, DEVCB_##_devcb); + +class s2650_device : public cpu_device +{ +public: + // construction/destruction + s2650_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + DECLARE_WRITE_LINE_MEMBER(write_sense); + + // static configuration helpers + template static devcb_base &set_flag_handler(device_t &device, _Object object) { return downcast(device).m_flag_handler.set_callback(object); } + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_execute_interface overrides + virtual UINT32 execute_min_cycles() const { return 5; } + virtual UINT32 execute_max_cycles() const { return 13; } + virtual UINT32 execute_input_lines() const { return 2; } + virtual UINT32 execute_default_irq_vector() const { return 0; } + virtual void execute_run(); + virtual void execute_set_input(int inputnum, int state); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const + { + return (spacenum == AS_PROGRAM) ? &m_program_config : ( (spacenum == AS_IO) ? &m_io_config : NULL ); + } + + // device_state_interface overrides + virtual void state_import(const device_state_entry &entry); + virtual void state_export(const device_state_entry &entry); + void state_string_export(const device_state_entry &entry, std::string &str); + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const { return 1; } + virtual UINT32 disasm_max_opcode_bytes() const { return 3; } + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + +private: + address_space_config m_program_config; + address_space_config m_io_config; + + devcb_write_line m_flag_handler; + + UINT16 m_ppc; /* previous program counter (page + iar) */ + UINT16 m_page; /* 8K page select register (A14..A13) */ + UINT16 m_iar; /* instruction address register (A12..A0) */ + UINT16 m_ea; /* effective address (A14..A0) */ + UINT8 m_psl; /* processor status lower */ + UINT8 m_psu; /* processor status upper */ + UINT8 m_r; /* absolute addressing dst/src register */ + UINT8 m_reg[7]; /* 7 general purpose registers */ + UINT8 m_halt; /* 1 if cpu is halted */ + UINT8 m_ir; /* instruction register */ + UINT16 m_ras[8]; /* 8 return address stack entries */ + UINT8 m_irq_state; + + int m_icount; + address_space *m_program; + direct_read_data *m_direct; + address_space *m_io; + + // For debugger + UINT16 m_debugger_temp; + + inline void set_psu(UINT8 new_val); + inline UINT8 get_sp(); + inline void set_sp(UINT8 new_sp); + inline int check_irq_line(); + inline UINT8 ROP(); + inline UINT8 ARG(); + void s2650_set_flag(int state); + int s2650_get_flag(); + void s2650_set_sense(int state); +}; + + +#endif /* __S2650_H__ */ diff --git a/src/devices/cpu/s2650/s2650cpu.h b/src/devices/cpu/s2650/s2650cpu.h new file mode 100644 index 00000000000..c4ff88f7aff --- /dev/null +++ b/src/devices/cpu/s2650/s2650cpu.h @@ -0,0 +1,33 @@ +// license:BSD-3-Clause +// copyright-holders:Juergen Buchmueller +/******************************************************* + * + * Portable Signetics 2650 cpu emulation + * + *******************************************************/ + +#define PMSK 0x1fff /* mask page offset */ +#define PLEN 0x2000 /* page length */ +#define PAGE 0x6000 /* mask page */ +#define AMSK 0x7fff /* mask address range */ + +/* processor status lower */ +#define C 0x01 /* carry flag */ +#define COM 0x02 /* compare: 0 binary, 1 2s complement */ +#define OVF 0x04 /* 2s complement overflow */ +#define WC 0x08 /* with carry: use carry in arithmetic / rotate ops */ +#define RS 0x10 /* register select 0: R0/R1/R2/R3 1: R0/R4/R5/R6 */ +#define IDC 0x20 /* inter digit carry: bit-3-to-bit-4 carry */ +#define CC 0xc0 /* condition code */ + +/* processor status upper */ +#define SP 0x07 /* stack pointer: indexing 8 15bit words */ +#define PSU34 0x18 /* unused bits */ +#define II 0x20 /* interrupt inhibit 0: allow, 1: inhibit */ +#define FO 0x40 /* flag output */ +#define SI 0x80 /* sense input */ + +#define R0 m_reg[0] +#define R1 m_reg[1] +#define R2 m_reg[2] +#define R3 m_reg[3] diff --git a/src/devices/cpu/saturn/satops.inc b/src/devices/cpu/saturn/satops.inc new file mode 100644 index 00000000000..8f7420584e3 --- /dev/null +++ b/src/devices/cpu/saturn/satops.inc @@ -0,0 +1,1151 @@ +// license:BSD-3-Clause +// copyright-holders:Peter Trauner,Antoine Mine +#define IRQ_ADDRESS 0xf + +#define saturn_assert(x) \ + do { if (!(x)) logerror("SATURN '%s' assertion failed: %s at %s:%i, pc=%05x\n", tag(), #x, __FILE__, __LINE__, m_pc); } while (0) + +int saturn_device::READ_OP() +{ + UINT8 data; + m_icount-=3; + data=m_direct->read_byte(m_pc); + saturn_assert(data<0x10); + m_pc=(m_pc+1)&0xfffff; + return data; +} + +int saturn_device::READ_OP_ARG() +{ + UINT8 data; + m_icount-=3; + data=m_direct->read_byte(m_pc); + saturn_assert(data<0x10); + m_pc=(m_pc+1)&0xfffff; + return data; +} + +int saturn_device::READ_OP_ARG8() +{ + int n0=READ_OP_ARG(); + int n1=READ_OP_ARG(); + return n0|(n1<<4); +} + +INT8 saturn_device::READ_OP_DIS8() +{ + return (INT8)READ_OP_ARG8(); +} + +int saturn_device::READ_OP_ARG12() +{ + int n0=READ_OP_ARG(); + int n1=READ_OP_ARG(); + int n2=READ_OP_ARG(); + return n0|(n1<<4)|(n2<<8); +} + +int saturn_device::READ_OP_DIS12() +{ + int temp=READ_OP_ARG12(); + if (temp&0x800) temp-=0x1000; + return temp; +} + +int saturn_device::READ_OP_ARG16() +{ + int n0=READ_OP_ARG(); + int n1=READ_OP_ARG(); + int n2=READ_OP_ARG(); + int n3=READ_OP_ARG(); + return n0|(n1<<4)|(n2<<8)|(n3<<12); +} + +INT16 saturn_device::READ_OP_DIS16() +{ + return (INT16)READ_OP_ARG16(); +} + +int saturn_device::READ_OP_ARG20() +{ + int n0=READ_OP_ARG(); + int n1=READ_OP_ARG(); + int n2=READ_OP_ARG(); + int n3=READ_OP_ARG(); + int n4=READ_OP_ARG(); + return n0|(n1<<4)|(n2<<8)|(n3<<12)|(n4<<16); +} + +int saturn_device::READ_NIBBLE(UINT32 adr) +{ + UINT8 data; + m_icount-=3; + data=m_program->read_byte(adr&0xfffff); + saturn_assert(data<0x10); + m_crc_func(adr&0xfffff, data, 0xffffffff); + return data; +} + +int saturn_device::READ_8(UINT32 adr) +{ + int n0=READ_NIBBLE(adr); + int n1=READ_NIBBLE(adr+1); + return n0|(n1<<4); +} + +int saturn_device::READ_12(UINT32 adr) +{ + int n0=READ_NIBBLE(adr); + int n1=READ_NIBBLE(adr+1); + int n2=READ_NIBBLE(adr+2); + return n0|(n1<<4)|(n2<<8); +} + +int saturn_device::READ_16(UINT32 adr) +{ + int n0=READ_NIBBLE(adr); + int n1=READ_NIBBLE(adr+1); + int n2=READ_NIBBLE(adr+2); + int n3=READ_NIBBLE(adr+3); + return n0|(n1<<4)|(n2<<8)|(n3<<12); +} + +int saturn_device::READ_20(UINT32 adr) +{ + int n0=READ_NIBBLE(adr); + int n1=READ_NIBBLE(adr+1); + int n2=READ_NIBBLE(adr+2); + int n3=READ_NIBBLE(adr+3); + int n4=READ_NIBBLE(adr+4); + return n0|(n1<<4)|(n2<<8)|(n3<<12)|(n4<<16); +} + +void saturn_device::WRITE_NIBBLE(UINT32 adr, UINT8 nib) +{ + m_icount-=3; + saturn_assert(nib<0x10); + m_program->write_byte(adr&0xfffff,nib); +} + +#define BEGIN_B 0 +#define COUNT_B 2 +#define BEGIN_X 0 +#define COUNT_X 3 +#define BEGIN_XS 2 +#define COUNT_XS 1 +#define BEGIN_A 0 +#define COUNT_A 5 +#define BEGIN_M 3 +#define COUNT_M 12 +#define BEGIN_S 15 +#define COUNT_S 1 +#define BEGIN_W 0 +#define COUNT_W 16 + + +int saturn_device::S64_READ_X(int r) +{ + return m_reg[r][0]|(m_reg[r][1]<<4)|(m_reg[r][2]<<8); +} + +int saturn_device::S64_READ_WORD(int r) +{ + return m_reg[r][0]|(m_reg[r][1]<<4)|(m_reg[r][2]<<8)|(m_reg[r][3]<<12); +} + +int saturn_device::S64_READ_A(int r) +{ + return m_reg[r][0]|(m_reg[r][1]<<4)|(m_reg[r][2]<<8)|(m_reg[r][3]<<12)|(m_reg[r][4]<<16); +} + +void saturn_device::S64_WRITE_X(int r, int v) +{ + m_reg[r][0]=v&0xf; + m_reg[r][1]=(v>>4)&0xf; + m_reg[r][2]=(v>>8)&0xf; +} + +void saturn_device::S64_WRITE_WORD(int r, int v) +{ + m_reg[r][0]=v&0xf; + m_reg[r][1]=(v>>4)&0xf; + m_reg[r][2]=(v>>8)&0xf; + m_reg[r][3]=(v>>12)&0xf; +} + +void saturn_device::S64_WRITE_A(int r, int v) +{ + m_reg[r][0]=v&0xf; + m_reg[r][1]=(v>>4)&0xf; + m_reg[r][2]=(v>>8)&0xf; + m_reg[r][3]=(v>>12)&0xf; + m_reg[r][4]=(v>>16)&0xf; +} + + + + + +UINT32 saturn_device::saturn_pop() +{ + UINT32 temp=m_rstk[0]; + memmove(m_rstk, m_rstk+1, sizeof(m_rstk)-sizeof(m_rstk[0])); + m_rstk[7]=0; + return temp; +} + +void saturn_device::saturn_push(UINT32 adr) +{ + memmove(m_rstk+1, m_rstk, sizeof(m_rstk)-sizeof(m_rstk[0])); + m_rstk[0]=adr; +} + +void saturn_device::saturn_interrupt_on() +{ + LOG(( "SATURN '%s' at %05x: INTON\n", tag(), m_pc-4 )); + m_irq_enable=1; + if (m_irq_state) + { + LOG(( "SATURN '%s' set_irq_line(ASSERT)\n", tag())); + m_pending_irq=1; + } +} + +void saturn_device::saturn_interrupt_off() +{ + LOG(( "SATURN '%s' at %05x: INTOFF\n", tag(), m_pc-4 )); + m_irq_enable=0; +} + +void saturn_device::saturn_reset_interrupt() +{ + LOG(( "SATURN '%s' at %05x: RSI\n", tag(), m_pc-5 )); + m_rsi_func(ASSERT_LINE); +} + +void saturn_device::saturn_mem_reset() +{ + m_reset_func(ASSERT_LINE); +} + +void saturn_device::saturn_mem_config() +{ + m_config_func(S64_READ_A(C)); +} + +void saturn_device::saturn_mem_unconfig() +{ + m_unconfig_func(S64_READ_A(C)); +} + +void saturn_device::saturn_mem_id() +{ + int id=0; + id = m_id_func(); + S64_WRITE_A(C,id); + m_monitor_id = id; +} + +void saturn_device::saturn_shutdown() +{ + m_sleeping=1; + m_irq_enable=1; + LOG(( "SATURN '%s' at %05x: SHUTDN\n", tag(), m_pc-3 )); +} + +void saturn_device::saturn_bus_command_b() +{ + logerror( "SATURN '%s' at %05x: BUSCB opcode not handled\n", tag(), m_pc-4 ); +} + +void saturn_device::saturn_bus_command_c() +{ + logerror( "SATURN '%s' at %05x: BUSCC opcode not handled\n", tag(), m_pc-3 ); +} + +void saturn_device::saturn_bus_command_d() +{ + logerror( "SATURN '%s' at %05x: BUSCD opcode not handled\n", tag(), m_pc-4 ); +} + +void saturn_device::saturn_serial_request() +{ + logerror( "SATURN '%s' at %05x: SREQ? opcode not handled\n", tag(), m_pc-3 ); +} + +void saturn_device::saturn_out_c() +{ + m_out=S64_READ_X(C); + m_out_func(m_out); +} + +void saturn_device::saturn_out_cs() +{ + m_out=(m_out&0xff0)|m_reg[C][0]; + m_out_func(m_out); +} + +void saturn_device::saturn_in(int reg) +{ + int in = 0; + saturn_assert(reg>=0 && reg<9); + if (!(m_pc&1)) + logerror( "SATURN '%s' at %05x: reg=IN opcode at odd addresse\n", + tag(), m_pc-3 ); + in = m_in_func(); + S64_WRITE_WORD(reg,in); + m_monitor_in = in; +} + + +/* st related */ +void saturn_device::saturn_clear_st() +{ + m_st&=0xf000; +} + +void saturn_device::saturn_st_to_c() +{ + S64_WRITE_X(C,m_st); +} + +void saturn_device::saturn_c_to_st() +{ + m_st=(m_st&0xf000)|(S64_READ_X(C)); +} + +void saturn_device::saturn_exchange_c_st() +{ + int t=m_st; + m_st=(t&0xf000)|(S64_READ_X(C)); + S64_WRITE_X(C,t); +} + +void saturn_device::saturn_jump_after_test() +{ + int adr=READ_OP_DIS8(); + if (m_carry) { + if (adr==0) { + m_pc=saturn_pop(); + } else { + m_pc=(m_pc+adr-2)&0xfffff; + } + } +} +void saturn_device::saturn_st_clear_bit() +{ + m_st &= ~(1<<(READ_OP_ARG())); +} + +void saturn_device::saturn_st_set_bit() +{ + m_st |= (1<<(READ_OP_ARG())); +} + +void saturn_device::saturn_st_jump_bit_clear() +{ + m_carry=!((m_st>>(READ_OP_ARG()))&1); + saturn_jump_after_test(); +} + +void saturn_device::saturn_st_jump_bit_set() +{ + m_carry=(m_st>>(READ_OP_ARG()))&1; + saturn_jump_after_test(); +} + +void saturn_device::saturn_hst_clear_bits() +{ + m_hst&=~(READ_OP_ARG()); +} + +void saturn_device::saturn_hst_bits_cleared() +{ + m_carry=!(m_hst&(READ_OP_ARG())); + saturn_jump_after_test(); +} + +/* p related */ +void saturn_device::saturn_exchange_p() +{ + int nr=READ_OP_ARG(); + int t=m_p; + m_p=m_reg[C][nr]; + m_reg[C][nr]=t; +} + +void saturn_device::saturn_p_to_c() +{ + int nr=READ_OP_ARG(); + m_reg[C][nr]=m_p; +} + +void saturn_device::saturn_c_to_p() +{ + int nr=READ_OP_ARG(); + m_p=m_reg[C][nr]; +} + +void saturn_device::saturn_dec_p() +{ + m_carry=m_p==0; + m_p=(m_p-1)&0xf; +} + +void saturn_device::saturn_inc_p() +{ + m_p=(m_p+1)&0xf; + m_carry=m_p==0; +} + +void saturn_device::saturn_load_p() +{ + m_p=READ_OP_ARG(); +} + +void saturn_device::saturn_p_equals() +{ + m_carry=m_p==(READ_OP_ARG()); + saturn_jump_after_test(); +} + +void saturn_device::saturn_p_not_equals() +{ + m_carry=m_p!=(READ_OP_ARG()); + saturn_jump_after_test(); +} + +void saturn_device::saturn_ca_p_1() +{ + int a=(S64_READ_A(C))+1+m_p; + m_carry=a>=0x100000; + S64_WRITE_A(C,a&0xfffff); +} + +void saturn_device::saturn_load_reg(int reg) +{ + int count=READ_OP_ARG(); + int pos=m_p; + saturn_assert(reg>=0 && reg<9); + for (; count>=0; count--, pos=(pos+1)&0xf ) { + m_reg[reg][pos]=READ_OP_ARG(); + } +} + +void saturn_device::saturn_jump(int adr, int jump) +{ + saturn_assert(adr>=0 && adr<0x100000); + if (jump) { + m_pc=adr; + m_icount-=10; + } +} + +void saturn_device::saturn_call(int adr) +{ + saturn_assert(adr>=0 && adr<0x100000); + saturn_push(m_pc); + m_pc=adr; +// m_icount-=10; +} + +void saturn_device::saturn_return(int yes) +{ + if (yes) { + m_pc=saturn_pop(); +// m_icount-=10; + } +} + +void saturn_device::saturn_return_carry_set() +{ + m_pc=saturn_pop(); +// m_icount-=10; + m_carry=1; +} + +void saturn_device::saturn_return_carry_clear() +{ + m_pc=saturn_pop(); +// m_icount-=10; + m_carry=0; +} + +void saturn_device::saturn_return_interrupt() +{ + LOG(( "SATURN '%s' at %05x: RTI\n", tag(), m_pc-2 )); + m_in_irq=0; /* set to 1 when an IRQ is taken */ + m_pc=saturn_pop(); +// m_icount-=10; +} + +void saturn_device::saturn_return_xm_set() +{ + m_pc=saturn_pop(); + m_hst|=XM; +// m_icount-=10; +} + +void saturn_device::saturn_pop_c() +{ + S64_WRITE_A(C,saturn_pop()); +} + +void saturn_device::saturn_push_c() +{ + saturn_push(S64_READ_A(C)); +} + +void saturn_device::saturn_indirect_jump(int reg) +{ + saturn_assert(reg>=0 && reg<9); + m_pc=READ_20(S64_READ_A(reg)); +} + +void saturn_device::saturn_equals_zero(int reg, int begin, int count) +{ + int i, t; + saturn_assert(reg>=0 && reg<9); + saturn_assert(begin>=0 && count>0 && begin+count<=16); + m_carry=1; + for (i=0; i=0 && reg<9); + saturn_assert(right>=0 && right<9); + saturn_assert(begin>=0 && count>0 && begin+count<=16); + m_carry=1; + for (i=0; i=0 && reg<9); + saturn_assert(begin>=0 && count>0 && begin+count<=16); + m_carry=0; + for (i=0; i=0 && reg<9); + saturn_assert(right>=0 && right<9); + saturn_assert(begin>=0 && count>0 && begin+count<=16); + m_carry=0; + for (i=0; i=0 && reg<9); + saturn_assert(right>=0 && right<9); + saturn_assert(begin>=0 && count>0 && begin+count<=16); + m_carry=0; + for (i=count-1; i>=0; i--) { + t=m_reg[reg][begin+i]; + t2=m_reg[right][begin+i]; + if (t>t2) { m_carry=1; break; } + if (t=0 && reg<9); + saturn_assert(right>=0 && right<9); + saturn_assert(begin>=0 && count>0 && begin+count<=16); + m_carry=1; + for (i=count-1; i>=0; i--) { + t=m_reg[reg][begin+i]; + t2=m_reg[right][begin+i]; + if (tt2) break; + m_icount-=2; + } + saturn_jump_after_test(); +} + +void saturn_device::saturn_smaller_equals(int reg, int begin, int count, int right) +{ + int i, t,t2; + saturn_assert(reg>=0 && reg<9); + saturn_assert(right>=0 && right<9); + saturn_assert(begin>=0 && count>0 && begin+count<=16); + m_carry=1; + for (i=count-1; i>=0; i--) { + t=m_reg[reg][begin+i]; + t2=m_reg[right][begin+i]; + if (t>t2) { m_carry=0; break; } + if (t=0 && reg<9); + saturn_assert(right>=0 && right<9); + saturn_assert(begin>=0 && count>0 && begin+count<=16); + m_carry=0; + for (i=count-1; i>=0; i--) { + t=m_reg[reg][begin+i]; + t2=m_reg[right][begin+i]; + if (tt2) break; + m_icount-=2; + } + saturn_jump_after_test(); +} + +void saturn_device::saturn_jump_bit_clear(int reg) +{ + int op=READ_OP_ARG(); + saturn_assert(reg>=0 && reg<9); + m_carry=!((m_reg[reg][op>>2]>>(op&3))&1); + saturn_jump_after_test(); +} + +void saturn_device::saturn_jump_bit_set(int reg) +{ + int op=READ_OP_ARG(); + saturn_assert(reg>=0 && reg<9); + m_carry=(m_reg[reg][op>>2]>>(op&3))&1; + saturn_jump_after_test(); +} + +void saturn_device::saturn_load_pc(int reg) +{ + saturn_assert(reg>=0 && reg<9); + m_pc=S64_READ_A(reg); +} + +void saturn_device::saturn_store_pc(int reg) +{ + saturn_assert(reg>=0 && reg<9); + S64_WRITE_A(reg,m_pc); +} + +void saturn_device::saturn_exchange_pc(int reg) +{ + int temp=m_pc; + saturn_assert(reg>=0 && reg<9); + m_pc=S64_READ_A(reg); + S64_WRITE_A(reg, temp); +} + +/************************************************************************************* + address register related +*************************************************************************************/ +void saturn_device::saturn_load_adr(int reg, int nibbles) +{ + saturn_assert(reg>=0 && reg<2); + saturn_assert(nibbles==2 || nibbles==4 || nibbles==5); + switch (nibbles) { + case 5: + m_d[reg]=READ_OP_ARG20(); + break; + case 4: + m_d[reg]=(m_d[reg]&0xf0000)|READ_OP_ARG16(); + break; + case 2: + m_d[reg]=(m_d[reg]&0xfff00)|READ_OP_ARG8(); + break; + } +} + +void saturn_device::saturn_add_adr(int reg) +{ + int t=m_d[reg]+READ_OP_ARG()+1; + saturn_assert(reg>=0 && reg<2); + m_d[reg]=t&0xfffff; + m_carry=t>=0x100000; +} + +void saturn_device::saturn_sub_adr(int reg) +{ + int t=m_d[reg]-READ_OP_ARG()-1; + saturn_assert(reg>=0 && reg<2); + m_d[reg]=t&0xfffff; + m_carry=t<0; +} + +void saturn_device::saturn_adr_to_reg(int adr, int reg) +{ + saturn_assert(reg>=0 && reg<9); + saturn_assert(adr>=0 && adr<2); + S64_WRITE_A(reg,m_d[adr]); +} + +void saturn_device::saturn_reg_to_adr(int reg, int adr) +{ + saturn_assert(reg>=0 && reg<9); + saturn_assert(adr>=0 && adr<2); + m_d[adr]=S64_READ_A(reg); +} + +void saturn_device::saturn_adr_to_reg_word(int adr, int reg) +{ + saturn_assert(reg>=0 && reg<9); + saturn_assert(adr>=0 && adr<2); + S64_WRITE_WORD(reg,m_d[adr]&0xffff); +} + +void saturn_device::saturn_reg_to_adr_word(int reg, int adr) +{ + saturn_assert(reg>=0 && reg<9); + saturn_assert(adr>=0 && adr<2); + m_d[adr]=(m_d[adr]&0xf0000)|S64_READ_WORD(reg); +} + +void saturn_device::saturn_exchange_adr_reg(int adr, int reg) +{ + int temp=m_d[adr]; + saturn_assert(reg>=0 && reg<9); + saturn_assert(adr>=0 && adr<2); + m_d[adr]=S64_READ_A(reg); + S64_WRITE_A(reg,temp); +} + +void saturn_device::saturn_exchange_adr_reg_word(int adr, int reg) +{ + int temp=m_d[adr]&0xffff; + saturn_assert(reg>=0 && reg<9); + saturn_assert(adr>=0 && adr<2); + m_d[adr]=(m_d[adr]&0xf0000)|S64_READ_WORD(reg); + S64_WRITE_WORD(reg,temp); +} + +void saturn_device::saturn_load_nibbles(int reg, int begin, int count, int adr) +{ + int i; + saturn_assert(reg>=0 && reg<9); + saturn_assert(adr>=0 && adr<2); + saturn_assert(begin>=0 && count>0 && begin+count<=16); + for (i=0; i=0 && reg<9); + saturn_assert(adr>=0 && adr<2); + saturn_assert(begin>=0 && count>0 && begin+count<=16); + for (i=0; i=0 && reg<9); + m_reg[reg][arg>>2]&=~(1<<(arg&3)); +} + +void saturn_device::saturn_set_bit(int reg) +{ + int arg=READ_OP_ARG(); + saturn_assert(reg>=0 && reg<9); + m_reg[reg][arg>>2]|=1<<(arg&3); +} + +/**************************************************************************** + clear opers + ****************************************************************************/ +void saturn_device::saturn_clear(int reg, int begin, int count) +{ + int i; + saturn_assert(reg>=0 && reg<9); + saturn_assert(begin>=0 && count>0 && begin+count<=16); + for (i=0; i=0 && left<9); + saturn_assert(right>=0 && right<9); + saturn_assert(begin>=0 && count>0 && begin+count<=16); + for (i=0; i=0 && dest<9); + saturn_assert(src>=0 && src<9); + saturn_assert(begin>=0 && count>0 && begin+count<=16); + for (i=0; i=0 && reg<9); + saturn_assert(right>=0 && right<9); + saturn_assert(begin>=0 && count>0 && begin+count<=16); + m_carry=0; + for (i=0; i=base) { + m_carry=1; + t-=base; + } + else m_carry=0; + saturn_assert(t>=0); saturn_assert(t=0 && reg<9); + saturn_assert(begin>=0 && count>0 && begin+count<=16); + saturn_assert(count>1 || !m_decimal); /* SATURN bug */ + for (i=0; i>=4; + if (t>=base) { + right++; + t-=base; + } + saturn_assert(t>=0); saturn_assert(t0; +} + +/**************************************************************************** + sub opers + ****************************************************************************/ +void saturn_device::saturn_sub(int reg, int begin, int count, int right) +{ + int i, t; + int base=m_decimal?10:16; + saturn_assert(reg>=0 && reg<9); + saturn_assert(right>=0 && right<9); + saturn_assert(begin>=0 && count>0 && begin+count<=16); + m_carry=0; + for (i=0; i=0); saturn_assert(t=0 && reg<9); + saturn_assert(begin>=0 && count>0 && begin+count<=16); + saturn_assert(count>1 || !m_decimal); /* SATURN bug */ + for (i=0; i>=4; + if (t<0) { + right++; + t+=base; + } + saturn_assert(t>=0); saturn_assert(t0; +} + +/**************************************************************************** + sub2 opers (a=b-a) + ****************************************************************************/ +void saturn_device::saturn_sub2(int reg, int begin, int count, int right) +{ + int i, t; + int base=m_decimal?10:16; + saturn_assert(reg>=0 && reg<9); + saturn_assert(right>=0 && right<9); + saturn_assert(begin>=0 && count>0 && begin+count<=16); + m_carry=0; + for (i=0; i=0); saturn_assert(t=0 && reg<9); + saturn_assert(begin>=0 && count>0 && begin+count<=16); + for (i=0; i=base) m_reg[reg][begin+i]=t-base; + else { m_reg[reg][begin+i]=t; break; } + } + m_carry=t>=base; +} + +/**************************************************************************** + decrement opers + ****************************************************************************/ +void saturn_device::saturn_decrement(int reg, int begin, int count) +{ + int i, t=0; + int base=m_decimal?10:16; + saturn_assert(reg>=0 && reg<9); + saturn_assert(begin>=0 && count>0 && begin+count<=16); + for (i=0; i=0 && reg<9); + saturn_assert(begin>=0 && count>0 && begin+count<=16); + m_carry=0; + for (i=0; i=0 && reg<9); + saturn_assert(begin>=0 && count>0 && begin+count<=16); + c=1; + m_carry=0; + for (i=0; imax) n-=max+1; + else c=0; + saturn_assert(n>=0); saturn_assert(n<=max); + m_reg[reg][begin+i]=n&0xf; + m_icount-=2; + } +} + +/**************************************************************************** + or opers + ****************************************************************************/ +void saturn_device::saturn_or(int dest, int begin, int count, int src) +{ + int i; + saturn_assert(dest>=0 && dest<9); + saturn_assert(src>=0 && src<9); + saturn_assert(begin>=0 && count>0 && begin+count<=16); + for (i=0; i=0 && dest<9); + saturn_assert(src>=0 && src<9); + saturn_assert(begin>=0 && count>0 && begin+count<=16); + for (i=0; i=0 && reg<9); + saturn_assert(begin>=0 && count>0 && begin+count<=16); + if (m_reg[reg][begin+count-1]) m_hst|=SB; + for (i=count-1; i>=1; i--) { + m_reg[reg][begin+i]=m_reg[reg][begin+i-1]; + m_icount-=2; + } + m_reg[reg][begin]=0; + m_icount-=2; +} + +/**************************************************************************** + shift nibbles right opers + ****************************************************************************/ +void saturn_device::saturn_shift_nibble_right(int reg, int begin, int count) +{ + int i; + saturn_assert(reg>=0 && reg<9); + saturn_assert(begin>=0 && count>0 && begin+count<=16); + if (m_reg[reg][begin]) m_hst|=SB; + for (i=1; i=0 && reg<9); + for (i=15; i>=1; i--) { + m_reg[reg][i]=m_reg[reg][i-1]; + m_icount-=2; + } + m_reg[reg][0]=x; + m_icount-=2; +} + +/**************************************************************************** + rotate nibbles right opers + ****************************************************************************/ +void saturn_device::saturn_rotate_nibble_right_w(int reg) +{ + int i, x=m_reg[reg][0]; + saturn_assert(reg>=0 && reg<9); + for (i=1; i<16; i++) { + m_reg[reg][i-1]=m_reg[reg][i]; + m_icount-=2; + } + m_reg[reg][15]=x; + if (x) m_hst|=SB; + m_icount-=2; +} + + +/**************************************************************************** + shift right opers + ****************************************************************************/ +void saturn_device::saturn_shift_right(int reg, int begin, int count) +{ + int i, t, c=0; + saturn_assert(reg>=0 && reg<9); + saturn_assert(begin>=0 && count>0 && begin+count<=16); + for (i=count-1; i>=0; i--) { + t=m_reg[reg][begin+i]; + t|=(c<<4); + c=t&1; + m_reg[reg][begin+i]=t>>1; + m_icount-=2; + } + if (c) m_hst|=SB; + m_icount-=2; +} diff --git a/src/devices/cpu/saturn/sattable.inc b/src/devices/cpu/saturn/sattable.inc new file mode 100644 index 00000000000..f8b5398973c --- /dev/null +++ b/src/devices/cpu/saturn/sattable.inc @@ -0,0 +1,1039 @@ +// license:BSD-3-Clause +// copyright-holders:Peter Trauner,Antoine Mine +static const int adr_a_begin[]={ +-1, -1, BEGIN_XS, BEGIN_X, BEGIN_S, BEGIN_M, BEGIN_B, BEGIN_W, +-1, -1, -1, -1, -1, -1, -1, -1, +}; + +static const int adr_a_count[]={ +-1, -1, COUNT_XS, COUNT_X, COUNT_S, COUNT_M, COUNT_B, COUNT_W, +-1, -1, -1, -1, -1, -1, -1, -1, +}; + +static const int adr_b_begin[]={ +-1, -1, -1, -1, -1, -1, -1, -1, +-1, -1, BEGIN_XS, BEGIN_X, BEGIN_S, BEGIN_M, BEGIN_B, BEGIN_W, +}; + +static const int adr_b_count[]={ +-1, -1, -1, -1, -1, -1, -1, -1, +-1, -1, COUNT_XS, COUNT_X, COUNT_S, COUNT_M, COUNT_B, COUNT_W, +}; + +static const int adr_af_begin[]={ +-1, -1, BEGIN_XS, BEGIN_X, BEGIN_S, BEGIN_M, BEGIN_B, BEGIN_W, +-1, -1, -1, -1, -1, -1, -1, BEGIN_A +}; + +static const int adr_af_count[]={ +-1, -1, COUNT_XS, COUNT_X, COUNT_S, COUNT_M, COUNT_B, COUNT_W, +-1, -1, -1, -1, -1, -1, -1, COUNT_A +}; + +static const int reg_left[] ={A,B,C,D, B,C,A,C, I,I,I,I, I,I,I,I}; +static const int reg_right[]={B,C,A,C, A,B,C,D, I,I,I,I, I,I,I,I}; +static const int add_left[] ={A,B,C,D, I,I,I,I, B,C,A,C, I,I,I,I}; +static const int add_right[]={B,C,A,C, I,I,I,I, A,B,C,D, I,I,I,I}; +static const int sub_left[] ={A,B,C,D, I,I,I,I, B,C,A,C, A,B,C,D}; +static const int sub_right[]={B,C,A,C, I,I,I,I, A,B,C,D, B,C,A,C}; + +void saturn_device::saturn_invalid3( int op1, int op2, int op3 ) +{ + logerror( "SATURN '%s' invalid opcode %x%x%x at %05x\n", + tag(), op1, op2, op3, m_pc-3 ); +} + +void saturn_device::saturn_invalid4( int op1, int op2, int op3, int op4 ) +{ + logerror( "SATURN '%s' invalid opcode %x%x%x%x at %05x\n", + tag(), op1, op2, op3, op4, m_pc-4 ); +} + +void saturn_device::saturn_invalid5( int op1, int op2, int op3, int op4, int op5 ) +{ + logerror( "SATURN '%s' invalid opcode %x%x%x%x%x at %05x\n", + tag(), op1, op2, op3, op4, op5, m_pc-5 ); +} + +void saturn_device::saturn_invalid6( int op1, int op2, int op3, int op4, int op5, int op6 ) +{ + logerror( "SATURN '%s' invalid opcode %x%x%x%x%x%x at %05x\n", + tag(), op1, op2, op3, op4, op5, op6, m_pc-6 ); +} + + +void saturn_device::saturn_instruction_0e() +{ + int reg, adr; + + switch(adr=READ_OP()) { + case 0: + switch(reg=READ_OP()){ + case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: + saturn_and(reg_left[reg], m_p, 1, reg_right[reg]); + break; //A=A&B p + case 8: case 9: case 0xa: case 0xb: case 0xc: case 0xd: case 0xe: case 0xf: + saturn_or(reg_left[reg&7], m_p, 1, reg_right[reg&7]); + break; //A=A!B p + } + break; + case 1: + switch(reg=READ_OP()){ + case 0: case 1: case 2: case 3:case 4: case 5: case 6: case 7: + saturn_and(reg_left[reg], 0, m_p+1, reg_right[reg]); + break; //A=A&B wp + case 8: case 9: case 0xa: case 0xb: case 0xc: case 0xd: case 0xe: case 0xf: + saturn_or(reg_left[reg&7], 0, m_p+1, reg_right[reg&7]); + break; //A=A!B wp + } + break; + case 2: case 3: case 4: case 5: case 6: case 7: case 0xf: + switch(reg=READ_OP()){ + case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: + saturn_and(reg_left[reg], adr_af_begin[adr], adr_af_count[adr], reg_right[reg]); + break; //A=A&B xs + case 8: case 9: case 0xa: case 0xb: case 0xc: case 0xd: case 0xe: case 0xf: + saturn_or(reg_left[reg&7], adr_af_begin[adr], adr_af_count[adr], reg_right[reg&7]); + break; //A=A!B xs + } + break; + default: + saturn_invalid3( 0, 0xe, adr ); + break; + } +} + +void saturn_device::saturn_instruction_1() +{ + int reg, adr, oper; + + switch (adr=READ_OP()) { + case 0: + switch (reg=READ_OP()) { + case 0: case 1: case 2: case 3: case 4: + saturn_copy(R0+reg, BEGIN_W, COUNT_W, A); + break; // r0=a w + case 8: case 9: case 0xa: case 0xb: case 0xc: + saturn_copy(R0+(reg&7), BEGIN_W, COUNT_W, C); + break; // r0=c w + default: + saturn_invalid3( 1, adr, reg ); + break; + } + break; + case 1: + switch (reg=READ_OP()) { + case 0: case 1: case 2: case 3: case 4: + saturn_copy(A, BEGIN_W, COUNT_W, R0+reg); + break; // a=r0 w + case 8: case 9: case 0xa: case 0xb: case 0xc: + saturn_copy(C, BEGIN_W, COUNT_W, R0+(reg&7)); + break; // c=r0 w + default: + saturn_invalid3( 1, adr, reg ); + break; + } + break; + case 2: + switch (reg=READ_OP()) { + case 0: case 1: case 2: case 3: case 4: + saturn_exchange(A, BEGIN_W, COUNT_W, R0+reg); + break; // ar0ex w + case 8: case 9: case 0xa: case 0xb: case 0xc: + saturn_exchange(C, BEGIN_W, COUNT_W, R0+(reg&7)); + break; // cr0ex w + default: + saturn_invalid3( 2, adr, reg ); + break; + } + break; + case 3: + switch (READ_OP()) { + case 0: saturn_reg_to_adr(A,0);break; + case 1: saturn_reg_to_adr(A,1);break; + case 2: saturn_exchange_adr_reg(0,A);break; + case 3: saturn_exchange_adr_reg(1,A);break; + case 4: saturn_reg_to_adr(C,0);break; + case 5: saturn_reg_to_adr(C,1);break; + case 6: saturn_exchange_adr_reg(0,C);break; + case 7: saturn_exchange_adr_reg(1,C);break; + case 8: saturn_reg_to_adr_word(A,0);break; + case 9: saturn_reg_to_adr_word(A,1);break; + case 0xa: saturn_exchange_adr_reg_word(0,A);break; + case 0xb: saturn_exchange_adr_reg_word(1,A);break; + case 0xc: saturn_reg_to_adr_word(C,0);break; + case 0xd: saturn_reg_to_adr_word(C,1);break; + case 0xe: saturn_exchange_adr_reg_word(0,C);break; + case 0xf: saturn_exchange_adr_reg_word(1,C);break; + } + break; + case 4: + switch (READ_OP()) { + case 0: saturn_store_nibbles(A, BEGIN_A, COUNT_A, 0); break; + case 1: saturn_store_nibbles(A, BEGIN_A, COUNT_A, 1); break; + case 2: saturn_load_nibbles(A, BEGIN_A, COUNT_A, 0); break; + case 3: saturn_load_nibbles(A, BEGIN_A, COUNT_A, 1); break; + case 4: saturn_store_nibbles(C, BEGIN_A, COUNT_A, 0); break; + case 5: saturn_store_nibbles(C, BEGIN_A, COUNT_A, 1); break; + case 6: saturn_load_nibbles(C, BEGIN_A, COUNT_A, 0); break; + case 7: saturn_load_nibbles(C, BEGIN_A, COUNT_A, 1); break; + case 8: saturn_store_nibbles(A, BEGIN_B, COUNT_B, 0); break; + case 9: saturn_store_nibbles(A, BEGIN_B, COUNT_B, 1); break; + case 0xa: saturn_load_nibbles(A, BEGIN_B, COUNT_B, 0); break; + case 0xb: saturn_load_nibbles(A, BEGIN_B, COUNT_B, 1); break; + case 0xc: saturn_store_nibbles(C, BEGIN_B, COUNT_B, 0); break; + case 0xd: saturn_store_nibbles(C, BEGIN_B, COUNT_B, 1); break; + case 0xe: saturn_load_nibbles(C, BEGIN_B, COUNT_B, 0); break; + case 0xf: saturn_load_nibbles(C, BEGIN_B, COUNT_B, 1); break; + } + break; + case 5: + switch (oper=READ_OP()) { + case 0: case 1: case 4: case 5: + switch (adr=READ_OP()) { + case 0: + saturn_store_nibbles(oper&4?C:A,m_p,1,oper&1); + break; + case 1: + saturn_store_nibbles(oper&4?C:A,0,m_p+1,oper&1); + break; + case 2: case 3: case 4: case 5: case 6: case 7: + saturn_store_nibbles(oper&4?C:A,adr_a_begin[adr],adr_a_count[adr],oper&1); + break; + default: + saturn_invalid4( 1, 5, oper, adr ); + break; + } + break; + case 2: case 3: case 6: case 7: + switch (adr=READ_OP()) { + case 0: + saturn_load_nibbles(oper&4?C:A,m_p,1,oper&1); + break; + case 1: + saturn_load_nibbles(oper&4?C:A,0,m_p+1,oper&1); + break; + case 2: case 3: case 4: case 5: case 6: case 7: + saturn_load_nibbles(oper&4?C:A,adr_a_begin[adr],adr_a_count[adr],oper&1); + break; + default: + saturn_invalid4( 1, 5, oper, adr ); + break; + } + break; + case 8: saturn_store_nibbles(A, 0, READ_OP()+1, 0); break; + case 9: saturn_store_nibbles(A, 0, READ_OP()+1, 1); break; + case 0xa: saturn_load_nibbles(A, 0, READ_OP()+1, 0); break; + case 0xb: saturn_load_nibbles(A, 0, READ_OP()+1, 1); break; + case 0xc: saturn_store_nibbles(C, 0, READ_OP()+1, 0); break; + case 0xd: saturn_store_nibbles(C, 0, READ_OP()+1, 1); break; + case 0xe: saturn_load_nibbles(C, 0, READ_OP()+1, 0); break; + case 0xf: saturn_load_nibbles(C, 0, READ_OP()+1, 1); break; + } + break; + case 6: saturn_add_adr(0);break; + case 7: saturn_add_adr(1);break; + case 8: saturn_sub_adr(0);break; + case 9: saturn_load_adr(0,2);break; + case 0xa: saturn_load_adr(0,4);break; + case 0xb: saturn_load_adr(0,5);break; + case 0xc: saturn_sub_adr(1);break; + case 0xd: saturn_load_adr(1,2);break; + case 0xe: saturn_load_adr(1,4);break; + case 0xf: saturn_load_adr(1,5);break; + } +} + +void saturn_device::saturn_instruction_80() +{ + int op; + switch(READ_OP()) { + case 0: saturn_out_cs();break; + case 1: saturn_out_c();break; + case 2: saturn_in(A);break; + case 3: saturn_in(C);break; + case 4: saturn_mem_unconfig();break; + case 5: saturn_mem_config();break; + case 6: saturn_mem_id();break; + case 7: saturn_shutdown();break; + case 8: + switch(READ_OP()) { + case 0: saturn_interrupt_on();break; + case 1: + switch(op=READ_OP()) { + case 0: saturn_reset_interrupt();break; + default: saturn_invalid5( 8, 0, 8, 1, op ); break; + } + break; + case 2: saturn_load_reg(A);break; //la + case 3: saturn_bus_command_b();break; + case 4: saturn_clear_bit(A);break; // abit=0 + case 5: saturn_set_bit(A);break; // abit=1 + case 6: saturn_jump_bit_clear(A);break; + case 7: saturn_jump_bit_set(A);break; + case 8: saturn_clear_bit(C);break; // cbit=0 + case 9: saturn_set_bit(C);break; // cbit=1 + case 0xa: saturn_jump_bit_clear(C);break; + case 0xb: saturn_jump_bit_set(C);break; + case 0xc: saturn_indirect_jump(A);break; + case 0xd: saturn_bus_command_d();break; + case 0xe: saturn_indirect_jump(C);break; + case 0xf: saturn_interrupt_off();break; + } + break; + case 9: saturn_ca_p_1();break;//C+P+1 + case 0xa: saturn_mem_reset();break; + case 0xb: saturn_bus_command_b();break; + case 0xc: saturn_p_to_c();break; + case 0xd: saturn_c_to_p();break; + case 0xe: saturn_serial_request();break; + case 0xf: saturn_exchange_p();break; + } +} + +void saturn_device::saturn_instruction_81a() +{ + int reg, adr,op; + switch(adr=READ_OP()) { + case 0: + switch(op=READ_OP()) { + case 0: + switch(reg=READ_OP()) { + case 0: case 1: case 2: case 3: case 4: + saturn_copy(R0+reg,m_p,1,A); + break; //r0=a p + case 8: case 9: case 0xa: case 0xb: case 0xc: + saturn_copy(R0+(reg&7),m_p,1,C); + break; //r0=c p + default: + saturn_invalid6( 8, 1, 0xa, adr, op, reg); + break; + } + break; + case 1: + switch(reg=READ_OP()) { + case 0: case 1: case 2: case 3: case 4: + saturn_copy(A,m_p,1,R0+reg); + break; //a=r0 p + case 8: case 9: case 0xa: case 0xb: case 0xc: + saturn_copy(C,m_p,1,R0+(reg&7)); + break; //c=r0 p + default: + saturn_invalid6( 8, 1, 0xa, adr, op, reg); + break; + } + break; + case 2: + switch (reg=READ_OP()) { + case 0: case 1: case 2: case 3: case 4: + saturn_exchange(A, m_p,1,R0+reg); + break; // ar0ex p + case 8: case 9: case 0xa: case 0xb: case 0xc: + saturn_exchange(C, m_p,1,R0+(reg&7)); + break; // cr0ex p + default: + saturn_invalid6( 8, 1, 0xa, adr, op, reg); + break; + } + break; + default: + saturn_invalid5( 8, 1, 0xa, adr, op ); + break; + } + break; + case 1: + switch(op=READ_OP()) { + case 0: + switch(reg=READ_OP()) { + case 0: case 1: case 2: case 3: case 4: + saturn_copy(R0+reg,0,m_p+1,A); + break; //r0=a wp + case 8: case 9: case 0xa: case 0xb: case 0xc: + saturn_copy(R0+(reg&7),0,m_p+1,C); + break; //r0=c wp + default: + saturn_invalid6( 8, 1, 0xa, adr, op, reg); + break; + } + break; + case 1: + switch(reg=READ_OP()) { + case 0: case 1: case 2: case 3: case 4: + saturn_copy(A,0,m_p+1,R0+reg); + break; //a=r0 wp + case 8: case 9: case 0xa: case 0xb: case 0xc: + saturn_copy(C,0,m_p+1,R0+(reg&7)); + break; //c=r0 wp + default: + saturn_invalid6( 8, 1, 0xa, adr, op, reg); + break; + } + break; + case 2: + switch (reg=READ_OP()) { + case 0: case 1: case 2: case 3: case 4: + saturn_exchange(A, 0, m_p+1, R0+reg); + break; // ar0ex wp + case 8: case 9: case 0xa: case 0xb: case 0xc: + saturn_exchange(C, 0, m_p+1, R0+(reg&7)); + break; // cr0ex wp + default: + saturn_invalid6( 8, 1, 0xa, adr, op, reg); + break; + } + break; + default: + saturn_invalid5( 8, 1, 0xa, adr, op ); + break; + } + break; + case 2: case 3: case 4: case 5: case 6: case 7: case 0xf: + switch(op=READ_OP()) { + case 0: + switch(reg=READ_OP()) { + case 0: case 1: case 2: case 3: case 4: + saturn_copy(R0+reg,adr_af_begin[adr],adr_af_count[adr],A); + break; //r0=a xs + case 8: case 9: case 0xa: case 0xb: case 0xc: + saturn_copy(R0+(reg&7),adr_af_begin[adr], adr_af_count[adr],C); + break; //r0=c xs + default: + saturn_invalid6( 8, 1, 0xa, adr, op, reg); + break; + } + break; + case 1: + switch(reg=READ_OP()) { + case 0: case 1: case 2: case 3: case 4: + saturn_copy(A,adr_af_begin[adr],adr_af_count[adr],R0+reg); + break; //a=r0 xs + case 8: case 9: case 0xa: case 0xb: case 0xc: + saturn_copy(C,adr_af_begin[adr],adr_af_count[adr],R0+(reg&7)); + break; //c=r0 xs + default: + saturn_invalid6( 8, 1, 0xa, adr, op, reg); + break; + } + break; + case 2: + switch (reg=READ_OP()) { + case 0: case 1: case 2: case 3: case 4: + saturn_exchange(A, adr_af_begin[adr], adr_af_count[adr], R0+reg); + break; // ar0ex xs + case 8: case 9: case 0xa: case 0xb: case 0xc: + saturn_exchange(C, adr_af_begin[adr], adr_af_count[adr], R0+(reg&7)); + break; // cr0ex xs + default: + saturn_invalid6( 8, 1, 0xa, adr, op, reg); + break; + } + break; + default: + saturn_invalid5( 8, 1, 0xa, adr, op ); + break; + } + break; + default: + saturn_invalid4( 8, 1, 0xa, adr ); + break; + } +} + +void saturn_device::saturn_instruction_81() +{ + int reg, adr; + + switch(reg=READ_OP()) { + case 0: case 1: case 2: case 3: + saturn_rotate_nibble_left_w(A+reg); break; // aslc w + case 4: case 5: case 6: case 7: + saturn_rotate_nibble_right_w(A+(reg&3)); break; // asrc w + case 8: + switch(adr=READ_OP()) { + case 0: + switch (reg=READ_OP()) { + case 0: case 1: case 2: case 3: + saturn_add_const(A+reg, m_p, 1, READ_OP()+1); + break; + case 8: case 9: case 0xa: case 0xb: + saturn_sub_const(A+(reg&3), m_p, 1, READ_OP()+1); + break; + default: + saturn_invalid5( 8, 1, 8, adr, reg ); + break; + } + break; + case 1: + switch (reg=READ_OP()) { + case 0: case 1: case 2: case 3: + saturn_add_const(A+reg, 0, m_p+1, READ_OP()+1); + break; + case 8: case 9: case 0xa: case 0xb: + saturn_sub_const(A+(reg&3), 0, m_p+1, READ_OP()+1); + break; + default: + saturn_invalid5( 8, 1, 8, adr, reg ); + break; + } + break; + case 2: case 3: case 4: case 5: case 6: case 7: case 0xf: + switch (reg=READ_OP()) { + case 0: case 1: case 2: case 3: + saturn_add_const(A+reg, adr_af_begin[adr], adr_af_count[adr], READ_OP()+1); + break; + case 8: case 9: case 0xa: case 0xb: + saturn_sub_const(A+(reg&3), adr_af_begin[adr], adr_af_count[adr], READ_OP()+1); + break; + default: + saturn_invalid5( 8, 1, 8, adr, reg ); + break; + } + break; + default: + saturn_invalid4( 8, 1, 8, adr ); + break; + } + break; + case 9: + switch(adr=READ_OP()) { + case 0: + switch(reg=READ_OP()){ + case 0: case 1: case 2: case 3: + saturn_shift_right(A+reg,m_p,1); + break; // asrb p + default: + saturn_invalid5( 8, 1, 9, adr, reg ); + break; + } + break; + case 1: + switch(reg=READ_OP()){ + case 0: case 1: case 2: case 3: + saturn_shift_right(A+reg, 0,m_p+1); + break; // asrb wp + default: + saturn_invalid5( 8, 1, 9, adr, reg ); + break; + } + break; + case 2: case 3: case 4: case 5: case 6: case 7: case 0xf: + switch(reg=READ_OP()){ + case 0: case 1: case 2: case 3: + saturn_shift_right(A+reg, adr_af_begin[adr], adr_af_count[adr]); + break; // asrb xs + default: + saturn_invalid5( 8, 1, 9, adr, reg ); + break; + } + break; + default: + saturn_invalid4( 8, 1, 9, adr ); + break; + } + break; + case 0xa: + saturn_instruction_81a(); + break; + case 0xb: + switch(adr=READ_OP()) { + case 2: saturn_load_pc(A);break; + case 3: saturn_load_pc(C);break; + case 4: saturn_store_pc(A);break; + case 5: saturn_store_pc(C);break; + case 6: saturn_exchange_pc(A);break; + case 7: saturn_exchange_pc(C);break; + default: saturn_invalid4( 8, 1, reg, adr ); break; + } + break; + case 0xc: case 0xd: case 0xe: case 0xf: + saturn_shift_right(A+(reg&3), BEGIN_W, COUNT_W); + break; // asrb w + } +} + +void saturn_device::saturn_instruction_8() +{ + int oper, adr; + + switch(READ_OP()) { + case 0: + saturn_instruction_80(); + break; + case 1: + saturn_instruction_81(); + break; + case 2: saturn_hst_clear_bits();break; + case 3: saturn_hst_bits_cleared();break; + case 4: saturn_st_clear_bit();break; + case 5: saturn_st_set_bit();break; + case 6: saturn_st_jump_bit_clear();break; + case 7: saturn_st_jump_bit_set();break; + case 8: saturn_p_not_equals(); break; + case 9: saturn_p_equals(); break; + case 0xa: + switch(oper=READ_OP()) { + case 0: case 1: case 2: case 3: + saturn_equals(reg_left[oper&3] , BEGIN_A, COUNT_A, reg_right[oper&3]); + break; + case 4: case 5: case 6: case 7: + saturn_not_equals(reg_left[oper&3] , BEGIN_A, COUNT_A, reg_right[oper&3]); + break; + case 8: case 9: case 0xa: case 0xb: + saturn_equals_zero(A+(oper&3), BEGIN_A, COUNT_A); + break; + case 0xc: case 0xd: case 0xe: case 0xf: + saturn_not_equals_zero(A+(oper&3), BEGIN_A, COUNT_A); + break; + } + break; + case 0xb: + switch(oper=READ_OP()) { + case 0: case 1: case 2: case 3: + saturn_greater(reg_left[oper&3] , BEGIN_A, COUNT_A, reg_right[oper&3]); + break; + case 4: case 5: case 6: case 7: + saturn_smaller(reg_left[oper&3] , BEGIN_A, COUNT_A, reg_right[oper&3]); + break; + case 8: case 9: case 0xa: case 0xb: + saturn_greater_equals(reg_left[oper&3], BEGIN_A, COUNT_A, reg_right[oper&3]); + break; + case 0xc: case 0xd: case 0xe: case 0xf: + saturn_smaller_equals(reg_left[oper&3], BEGIN_A, COUNT_A, reg_right[oper&3]); + break; + } + break; + case 0xc: + adr=READ_OP_DIS16(); + saturn_jump((adr+m_pc-4)&0xfffff,1); + break; + case 0xd: + adr=READ_OP_ARG20(); + saturn_jump(adr,1); + break; + case 0xe: + adr=READ_OP_DIS16(); + saturn_call((adr+m_pc)&0xfffff); + break; + case 0xf: + adr=READ_OP_ARG20(); + saturn_call(adr); + break; + } +} + +void saturn_device::saturn_instruction_9() +{ + int adr, oper; + + switch(adr=READ_OP()) { + case 0: + switch(oper=READ_OP()) { + case 0: case 1: case 2: case 3: + saturn_equals(reg_left[oper&3] , m_p, 1, reg_right[oper&3]); + break; + case 4: case 5: case 6: case 7: + saturn_not_equals(reg_left[oper&3] ,m_p, 1, reg_right[oper&3]); + break; + case 8: case 9: case 0xa: case 0xb: + saturn_equals_zero(A+(oper&3), m_p, 1); + break; + case 0xc: case 0xd: case 0xe: case 0xf: + saturn_not_equals_zero(A+(oper&3), m_p, 1); + break; + } + break; + case 1: + switch(oper=READ_OP()) { + case 0: case 1: case 2: case 3: + saturn_equals(reg_left[oper&3] , 0, m_p+1, reg_right[oper&3]); + break; + case 4: case 5: case 6: case 7: + saturn_not_equals(reg_left[oper&3] , 0, m_p+1, reg_right[oper&3]); + break; + case 8: case 9: case 0xa: case 0xb: + saturn_equals_zero(A+(oper&3), 0, m_p+1); + break; + case 0xc: case 0xd: case 0xe: case 0xf: + saturn_not_equals_zero(A+(oper&3), 0, m_p+1); + break; + } + break; + case 2: case 3: case 4: case 5: case 6: case 7: + switch(oper=READ_OP()) { + case 0: case 1: case 2: case 3: + saturn_equals(reg_left[oper&3] ,adr_a_begin[adr], adr_a_count[adr], reg_right[oper&3]); + break; + case 4: case 5: case 6: case 7: + saturn_not_equals(reg_left[oper&3] ,adr_a_begin[adr], adr_a_count[adr], reg_right[oper&3]); + break; + case 8: case 9: case 0xa: case 0xb: + saturn_equals_zero(A+(oper&3),adr_a_begin[adr], adr_a_count[adr]); + break; + case 0xc: case 0xd: case 0xe: case 0xf: + saturn_not_equals_zero(A+(oper&3) ,adr_a_begin[adr], adr_a_count[adr]); + break; + } + break; + case 8: + switch(oper=READ_OP()) { + case 0: case 1: case 2: case 3: + saturn_greater(reg_left[oper&3] ,m_p, 1, reg_right[oper&3]); + break; + case 4: case 5: case 6: case 7: + saturn_smaller(reg_left[oper&3] ,m_p, 1, reg_right[oper&3]); + break; + case 8: case 9: case 0xa: case 0xb: + saturn_greater_equals(reg_left[oper&3] ,m_p, 1, reg_right[oper&3]); + break; + case 0xc: case 0xd: case 0xe: case 0xf: + saturn_smaller_equals(reg_left[oper&3] ,m_p, 1, reg_right[oper&3]); + break; + } + break; + case 9: + switch(oper=READ_OP()) { + case 0: case 1: case 2: case 3: + saturn_greater(reg_left[oper&3] , 0, m_p+1, reg_right[oper&3]); + break; + case 4: case 5: case 6: case 7: + saturn_smaller(reg_left[oper&3] , 0, m_p+1, reg_right[oper&3]); + break; + case 8: case 9: case 0xa: case 0xb: + saturn_greater_equals(reg_left[oper&3], 0, m_p+1, reg_right[oper&3]); + break; + case 0xc: case 0xd: case 0xe: case 0xf: + saturn_smaller_equals(reg_left[oper&3], 0, m_p+1, reg_right[oper&3]); + break; + } + break; + case 0xa: case 0xb: case 0xc: case 0xd: case 0xe: case 0xf: + switch(oper=READ_OP()) { + case 0: case 1: case 2: case 3: + saturn_greater(reg_left[oper&3] ,adr_b_begin[adr], adr_b_count[adr], reg_right[oper&3]); + break; + case 4: case 5: case 6: case 7: + saturn_smaller(reg_left[oper&3] ,adr_b_begin[adr], adr_b_count[adr], reg_right[oper&3]); + break; + case 8: case 9: case 0xa: case 0xb: + saturn_greater_equals(reg_left[oper&3] ,adr_b_begin[adr], adr_b_count[adr], reg_right[oper&3]); + break; + case 0xc: case 0xd: case 0xe: case 0xf: + saturn_smaller_equals(reg_left[oper&3] ,adr_b_begin[adr], adr_b_count[adr], reg_right[oper&3]); + break; + } + break; + } +} + +void saturn_device::saturn_instruction_a() +{ + int reg, adr; + + switch(adr=READ_OP()) { + case 0: + switch (reg=READ_OP()) { + case 0: case 1: case 2: case 3: + case 8: case 9: case 0xa: case 0xb: + saturn_add(add_left[reg], m_p, 1, add_right[reg]); + break; + case 4: case 5: case 6: case 7: + saturn_add(A+(reg&3), m_p, 1, A+(reg&3)); + break; + case 0xc: case 0xd: case 0xe: case 0xf: + saturn_decrement(A+(reg&3), m_p, 1); + break; + } + break; + case 1: + switch (reg=READ_OP()) { + case 0: case 1: case 2: case 3: + case 8: case 9: case 0xa: case 0xb: + saturn_add(add_left[reg], 0, m_p+1, add_right[reg]); + break; + case 4: case 5: case 6: case 7: + saturn_add(A+(reg&3), 0, m_p+1, A+(reg&3)); + break; + case 0xc: case 0xd: case 0xe: case 0xf: + saturn_decrement(A+(reg&3), 0, m_p+1); + break; + } + break; + case 2: case 3: case 4: case 5: case 6: case 7: + switch (reg=READ_OP()) { + case 0: case 1: case 2: case 3: + case 8: case 9: case 0xa: case 0xb: + saturn_add(add_left[reg], adr_a_begin[adr], adr_a_count[adr], add_right[reg]); + break; + case 4: case 5: case 6: case 7: + saturn_add(A+(reg&3), adr_a_begin[adr], adr_a_count[adr], A+(reg&3)); + break; + case 0xc: case 0xd: case 0xe: case 0xf: + saturn_decrement(A+(reg&3), adr_a_begin[adr], adr_a_count[adr]); + break; + } + break; + case 8: + switch(reg=READ_OP()) { + case 0: case 1: case 2: case 3: + saturn_clear(A+reg, m_p,1); + break; // a=0 p + case 4: case 5: case 6: case 7: + case 8: case 9: case 0xa: case 0xb: + saturn_copy(reg_right[reg&7], m_p,1,reg_left[reg&7]); + break; // a=b p + case 0xc: case 0xd: case 0xe: case 0xf: + saturn_exchange(reg_left[reg&3], m_p,1,reg_right[reg&3]); + break; // abex p + } + break; + case 9: + switch(reg=READ_OP()) { + case 0: case 1: case 2: case 3: + saturn_clear(A+reg,0,m_p+1); + break; // a=0 wp + case 4: case 5: case 6: case 7: + case 8: case 9: case 0xa: case 0xb: + saturn_copy(reg_right[reg&7], 0, m_p+1, reg_left[reg&7]); + break; // a=b wp + case 0xc: case 0xd: case 0xe: case 0xf: + saturn_exchange(reg_left[reg&3], 0, m_p+1, reg_right[reg&3]); + break; // abex wp + } + break; + case 0xa: case 0xb: case 0xc: case 0xd: case 0xe: case 0xf: + switch(reg=READ_OP()) { + case 0: case 1: case 2: case 3: + saturn_clear(A+reg, adr_b_begin[adr], adr_b_count[adr]); + break; // a=0 xs + case 4: case 5: case 6: case 7: + case 8: case 9: case 0xa: case 0xb: + saturn_copy(reg_right[reg&7], adr_b_begin[adr], adr_b_count[adr], reg_left[reg&7]); + break; // a=b xs + case 0xc: case 0xd: case 0xe: case 0xf: + saturn_exchange(reg_left[reg&3], adr_b_begin[adr], adr_b_count[adr], reg_right[reg&3]); + break; // abex xs + } + break; + } +} + +void saturn_device::saturn_instruction_b() +{ + int adr, reg; + + switch(adr=READ_OP()) { + case 0: + switch(reg=READ_OP()) { + case 0: case 1: case 2: case 3: + case 8: case 9: case 0xa: case 0xb: + saturn_sub(sub_left[reg], m_p, 1, sub_right[reg]); + break; + case 4: case 5: case 6: case 7: + saturn_increment(A+(reg&3), m_p, 1); break; // a=a+1 p + case 0xc: case 0xd: case 0xe: case 0xf: + saturn_sub2(sub_left[reg], m_p, 1, sub_right[reg]); + break; + } + break; + case 1: + switch(reg=READ_OP()) { + case 0: case 1: case 2: case 3: + case 8: case 9: case 0xa: case 0xb: + saturn_sub(sub_left[reg], 0, m_p+1, sub_right[reg]); + break; + case 4: case 5: case 6: case 7: + saturn_increment(A+(reg&3), 0, m_p+1); break; // a=a+1 wp + case 0xc: case 0xd: case 0xe: case 0xf: + saturn_sub2(sub_left[reg], 0, m_p+1, sub_right[reg]); + break; + } + break; + case 2: case 3: case 4: case 5: case 6: case 7: + switch(reg=READ_OP()) { + case 0: case 1: case 2: case 3: + case 8: case 9: case 0xa: case 0xb: + saturn_sub(sub_left[reg], adr_a_begin[adr], adr_a_count[adr], sub_right[reg]); + break; + case 4: case 5: case 6: case 7: + saturn_increment(A+(reg&3), adr_a_begin[adr], adr_a_count[adr]); + break; // a=a+1 xs + case 0xc: case 0xd: case 0xe: case 0xf: + saturn_sub2(sub_left[reg], adr_a_begin[adr], adr_a_count[adr], + sub_right[reg]); + break; + } + break; + case 8: + switch(reg=READ_OP()) { + case 0: case 1: case 2: case 3: + saturn_shift_nibble_left(A+reg, m_p, 1); break; // asl p + case 4: case 5: case 6: case 7: + saturn_shift_nibble_right(A+(reg&3), m_p, 1); break; // asr p + case 8: case 9: case 0xa: case 0xb: + saturn_negate(A+(reg&3), m_p, 1); break; // A=-A p + case 0xc: case 0xd: case 0xe: case 0xf: + saturn_invert(A+(reg&3), m_p, 1); break; // A=-A-1 p + } + break; + case 9: + switch(reg=READ_OP()) { + case 0: case 1: case 2: case 3: + saturn_shift_nibble_left(A+reg,0,m_p+1); break; // asl wp + case 4: case 5: case 6: case 7: + saturn_shift_nibble_right(A+(reg&3),0,m_p+1); break; // asr wp + case 8: case 9: case 0xa: case 0xb: + saturn_negate(A+(reg&3),0,m_p+1); break; // A=-A wp + case 0xc: case 0xd: case 0xe: case 0xf: + saturn_invert(A+(reg&3),0,m_p+1); break; // A=-A-1 wp + } + break; + case 0xa: case 0xb: case 0xc: case 0xd: case 0xe: case 0xf: + switch(reg=READ_OP()) { + case 0: case 1: case 2: case 3: + saturn_shift_nibble_left(A+reg,adr_b_begin[adr], adr_b_count[adr]); + break; + case 4: case 5: case 6: case 7: + saturn_shift_nibble_right(A+(reg&3), adr_b_begin[adr], adr_b_count[adr]); + break; + case 8: case 9: case 0xa: case 0xb: + saturn_negate(A+(reg&3), adr_b_begin[adr], adr_b_count[adr]); + break; + case 0xc: case 0xd: case 0xe: case 0xf: + saturn_invert(A+(reg&3), adr_b_begin[adr], adr_b_count[adr]); + break; + } + break; + } +} + + +void saturn_device::saturn_instruction() +{ + int reg, adr; + + switch(READ_OP()) { + case 0: + switch(READ_OP()) { + case 0: saturn_return_xm_set();break; + case 1: saturn_return(1);break; + case 2: saturn_return_carry_set();break; + case 3: saturn_return_carry_clear();break; + case 4: saturn_sethex();break; + case 5: saturn_setdec();break; + case 6: saturn_push_c();break; + case 7: saturn_pop_c();break; + case 8: saturn_clear_st();break; + case 9: saturn_st_to_c();break; + case 0xa: saturn_c_to_st();break; + case 0xb: saturn_exchange_c_st();break; + case 0xc: saturn_inc_p();break; + case 0xd: saturn_dec_p();break; + case 0xe: saturn_instruction_0e();break; + case 0xf: saturn_return_interrupt();break; + } + break; + case 1: + saturn_instruction_1(); + break; + case 2: + saturn_load_p(); + break; + case 3: + saturn_load_reg(C); + break; // lc + case 4: + adr=READ_OP_DIS8(); + if (adr==0) { + saturn_return(m_carry); + } + else { + saturn_jump((m_pc+adr-2)&0xfffff, m_carry); + } + break; + case 5: + adr=READ_OP_DIS8(); + if (adr==0) { + saturn_return(!m_carry); + } + else { + saturn_jump((m_pc+adr-2)&0xfffff,!m_carry); + } + break; + case 6: + adr=READ_OP_DIS12(); + saturn_jump((m_pc+adr-3)&0xfffff,1); break; + case 7: + adr=READ_OP_DIS12(); + saturn_call((adr+m_pc)&0xfffff); break; + case 8: + saturn_instruction_8(); + break; + case 9: + saturn_instruction_9(); + break; + case 0xa: + saturn_instruction_a(); + break; + case 0xb: + saturn_instruction_b(); + break; + case 0xc: + switch (reg=READ_OP()) { + case 0: case 1: case 2: case 3: + case 8: case 9: case 0xa: case 0xb: + saturn_add(add_left[reg], BEGIN_A, COUNT_A, add_right[reg]); + break; + case 4: case 5: case 6: case 7: + saturn_add(A+(reg&3), BEGIN_A, COUNT_A, A+(reg&3)); + break; + case 0xc: case 0xd: case 0xe: case 0xf: + saturn_decrement(A+(reg&3), BEGIN_A, COUNT_A); + break; + } + break; + case 0xd: + switch(reg=READ_OP()) { + case 0: case 1: case 2: case 3: + saturn_clear(A+reg, BEGIN_A, COUNT_A); + break; // a=0 a + case 4: case 5: case 6: case 7: + case 8: case 9: case 0xa: case 0xb: + saturn_copy(reg_right[reg&7], BEGIN_A, COUNT_A, reg_left[reg&7]); + break; // a=b a + case 0xc: case 0xd: case 0xe: case 0xf: + saturn_exchange(reg_left[reg&3], BEGIN_A, COUNT_A, reg_right[reg&3]); + break; // abex a + } + break; + case 0xe: + switch(reg=READ_OP()) { + case 0: case 1: case 2: case 3: + case 8: case 9: case 0xa: case 0xb: + saturn_sub(sub_left[reg], BEGIN_A, COUNT_A, sub_right[reg]); + break; + case 4: case 5: case 6: case 7: + saturn_increment(A+(reg&3), BEGIN_A, COUNT_A); + break; // a=a+1 a + case 0xc: case 0xd: case 0xe: case 0xf: + saturn_sub2(sub_left[reg], BEGIN_A, COUNT_A, sub_right[reg]); + break; + } + break; + case 0xf: + switch(reg=READ_OP()) { + case 0: case 1: case 2: case 3: + saturn_shift_nibble_left(A+reg,BEGIN_A, COUNT_A); + break; // asl a + case 4: case 5: case 6: case 7: + saturn_shift_nibble_right(A+(reg&3),BEGIN_A, COUNT_A); + break; // asr a + case 8: case 9: case 0xa: case 0xb: + saturn_negate(A+(reg&3),BEGIN_A, COUNT_A); + break; // A=-A a + case 0xc: case 0xd: case 0xe: case 0xf: + saturn_invert(A+(reg&3),BEGIN_A, COUNT_A); + break; // A=-A-1 a + } + break; + } +} diff --git a/src/devices/cpu/saturn/saturn.c b/src/devices/cpu/saturn/saturn.c new file mode 100644 index 00000000000..1d94a3a9ceb --- /dev/null +++ b/src/devices/cpu/saturn/saturn.c @@ -0,0 +1,410 @@ +// license:BSD-3-Clause +// copyright-holders:Peter Trauner,Antoine Mine +/***************************************************************************** + * + * saturn.c + * portable saturn emulator interface + * (hp calculators) + * + * + *****************************************************************************/ + +#include "emu.h" +#include "debugger.h" + +#include "saturn.h" + +#define R0 0 +#define R1 1 +#define R2 2 +#define R3 3 +#define R4 4 +#define A 5 +#define B 6 +#define C 7 +#define D 8 +#define I 9 // invalid + + +#define VERBOSE 0 + +#define LOG(x) do { if (VERBOSE) logerror x; } while (0) + + +// Hardware status bits +#define XM 1 // external Modules missing +#define SB 2 // Sticky bit +#define SR 4 // Service Request +#define MP 8 // Module Pulled + + + +const device_type SATURN = &device_creator; + + +saturn_device::saturn_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : cpu_device(mconfig, SATURN, "HP Saturn", tag, owner, clock, "saturn_cpu", __FILE__) + , m_program_config("program", ENDIANNESS_LITTLE, 8, 20, 0) + , m_out_func(*this) + , m_in_func(*this) + , m_reset_func(*this) + , m_config_func(*this) + , m_unconfig_func(*this) + , m_id_func(*this) + , m_crc_func(*this) + , m_rsi_func(*this) +{ +} + + +offs_t saturn_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( saturn ); + return CPU_DISASSEMBLE_NAME(saturn)(this, buffer, pc, oprom, opram, options); +} + + +/*************************************************************** + * include the opcode macros, functions and tables + ***************************************************************/ + +#include "satops.inc" +#include "sattable.inc" + +/***************************************************************************** + * + * Saturn CPU interface functions + * + *****************************************************************************/ + +void saturn_device::device_start() +{ + m_program = &space(AS_PROGRAM); + m_direct = &m_program->direct(); + + m_out_func.resolve_safe(); + m_in_func.resolve_safe(0); + m_reset_func.resolve_safe(); + m_config_func.resolve_safe(); + m_unconfig_func.resolve_safe(); + m_id_func.resolve_safe(0); + m_crc_func.resolve_safe(); + m_rsi_func.resolve_safe(); + + memset(m_reg, 0, sizeof(m_reg)); + memset(m_d, 0, sizeof(m_d)); + m_pc = 0; + m_oldpc = 0; + memset(m_rstk, 0, sizeof(m_rstk)); + m_out = 0; + m_carry = 0; + m_decimal = 0; + m_st = 0; + m_hst = 0; + m_nmi_state = 0; + m_irq_state = 0; + m_irq_enable = 0; + m_in_irq = 0; + m_pending_irq = 0; + m_sleeping = 0; + m_p = 0; + + save_item(NAME(m_reg[R0])); + save_item(NAME(m_reg[R1])); + save_item(NAME(m_reg[R2])); + save_item(NAME(m_reg[R3])); + save_item(NAME(m_reg[R4])); + save_item(NAME(m_reg[A])); + save_item(NAME(m_reg[B])); + save_item(NAME(m_reg[C])); + save_item(NAME(m_reg[D])); + save_item(NAME(m_d)); + save_item(NAME(m_pc)); + save_item(NAME(m_oldpc)); + save_item(NAME(m_rstk)); + save_item(NAME(m_out)); + save_item(NAME(m_carry)); + save_item(NAME(m_st)); + save_item(NAME(m_hst)); + save_item(NAME(m_nmi_state)); + save_item(NAME(m_irq_state)); + save_item(NAME(m_irq_enable)); + save_item(NAME(m_in_irq)); + save_item(NAME(m_pending_irq)); + save_item(NAME(m_sleeping)); + + // TODO: Register state + state_add( SATURN_PC, "PC", m_pc ).formatstr("%5X"); + state_add( SATURN_D0, "D0", m_d[0] ).formatstr("%5X"); + state_add( SATURN_D1, "D1", m_d[1] ).formatstr("%5X"); + state_add( SATURN_A, "A", m_debugger_temp ).formatstr("%19s"); + state_add( SATURN_B, "B", m_debugger_temp ).formatstr("%19s"); + state_add( SATURN_C, "C", m_debugger_temp ).formatstr("%19s"); + state_add( SATURN_D, "D", m_debugger_temp ).formatstr("%19s"); + state_add( SATURN_R0, "R0", m_debugger_temp ).formatstr("%19s"); + state_add( SATURN_R1, "R1", m_debugger_temp ).formatstr("%19s"); + state_add( SATURN_R2, "R2", m_debugger_temp ).formatstr("%19s"); + state_add( SATURN_R3, "R3", m_debugger_temp ).formatstr("%19s"); + state_add( SATURN_R4, "R4", m_debugger_temp ).formatstr("%19s"); + state_add( SATURN_P, "P", m_p).formatstr("%1X"); + state_add( SATURN_OUT, "OUTP", m_out).formatstr("%3X"); + state_add( SATURN_CARRY, "Carry", m_carry).formatstr("%1X"); + state_add( SATURN_ST, "ST", m_st).formatstr("%4X"); + state_add( SATURN_HST, "HST", m_hst).formatstr("%1X"); + state_add( SATURN_RSTK0, "RSTK0", m_rstk[0]).formatstr("%5X"); + state_add( SATURN_RSTK1, "RSTK1", m_rstk[1]).formatstr("%5X"); + state_add( SATURN_RSTK2, "RSTK2", m_rstk[2]).formatstr("%5X"); + state_add( SATURN_RSTK3, "RSTK3", m_rstk[3]).formatstr("%5X"); + state_add( SATURN_RSTK4, "RSTK4", m_rstk[4]).formatstr("%5X"); + state_add( SATURN_RSTK5, "RSTK5", m_rstk[5]).formatstr("%5X"); + state_add( SATURN_RSTK6, "RSTK6", m_rstk[6]).formatstr("%5X"); + state_add( SATURN_RSTK7, "RSTK7", m_rstk[7]).formatstr("%5X"); + state_add( SATURN_IRQ_STATE, "IRQ", m_debugger_temp).formatstr("%4s"); + state_add( SATURN_SLEEPING, "sleep", m_sleeping).formatstr("%1X"); + + state_add( STATE_GENPC, "GENPC", m_pc ).noshow(); + state_add( STATE_GENFLAGS, "GENFLAGS", m_debugger_temp).formatstr("%2s").noshow(); + + m_icountptr = &m_icount; +} + +void saturn_device::state_string_export(const device_state_entry &entry, std::string &str) +{ +#define Reg64Data(s) s[15],s[14],s[13],s[12],s[11],s[10],s[9],s[8],s[7],s[6],s[5],s[4],s[3],s[2],s[1],s[0] +#define Reg64Format "%x %x%x%x%x%x%x%x %x%x%x %x%x%x%x%x" + + switch (entry.index()) + { + case SATURN_A: + strprintf(str, Reg64Format, Reg64Data(m_reg[A]) ); + break; + + case SATURN_B: + strprintf(str, Reg64Format, Reg64Data(m_reg[B]) ); + break; + + case SATURN_C: + strprintf(str, Reg64Format, Reg64Data(m_reg[C]) ); + break; + + case SATURN_D: + strprintf(str, Reg64Format, Reg64Data(m_reg[D]) ); + break; + + case SATURN_R0: + strprintf(str, Reg64Format, Reg64Data(m_reg[R0]) ); + break; + + case SATURN_R1: + strprintf(str, Reg64Format, Reg64Data(m_reg[R1]) ); + break; + + case SATURN_R2: + strprintf(str, Reg64Format, Reg64Data(m_reg[R2]) ); + break; + + case SATURN_R3: + strprintf(str, Reg64Format, Reg64Data(m_reg[R3]) ); + break; + + case SATURN_R4: + strprintf(str, Reg64Format, Reg64Data(m_reg[R4]) ); + break; + + case SATURN_IRQ_STATE: + strprintf(str, "%c%c%c%i", m_in_irq?'S':'.', m_irq_enable?'e':'.', m_pending_irq?'p':'.', m_irq_state ); + break; + + case STATE_GENFLAGS: + strprintf(str, "%c%c", m_decimal?'D':'.', m_carry ? 'C':'.' ); + break; + } +} + + +void saturn_device::state_import(const device_state_entry &entry) +{ + switch (entry.index()) + { + case SATURN_A: + IntReg64(m_reg[A], m_debugger_temp); + break; + + case SATURN_B: + IntReg64(m_reg[B], m_debugger_temp); + break; + + case SATURN_C: + IntReg64(m_reg[C], m_debugger_temp); + break; + + case SATURN_D: + IntReg64(m_reg[D], m_debugger_temp); + break; + + case SATURN_R0: + IntReg64(m_reg[R0], m_debugger_temp); + break; + + case SATURN_R1: + IntReg64(m_reg[R1], m_debugger_temp); + break; + + case SATURN_R2: + IntReg64(m_reg[R2], m_debugger_temp); + break; + + case SATURN_R3: + IntReg64(m_reg[R3], m_debugger_temp); + break; + + case SATURN_R4: + IntReg64(m_reg[R4], m_debugger_temp); + break; + } +} + +void saturn_device::state_export(const device_state_entry &entry) +{ + switch (entry.index()) + { + case SATURN_A: + m_debugger_temp = Reg64Int(m_reg[A]); + break; + + case SATURN_B: + m_debugger_temp = Reg64Int(m_reg[B]); + break; + + case SATURN_C: + m_debugger_temp = Reg64Int(m_reg[C]); + break; + + case SATURN_D: + m_debugger_temp = Reg64Int(m_reg[D]); + break; + + case SATURN_R0: + m_debugger_temp = Reg64Int(m_reg[R0]); + break; + + case SATURN_R1: + m_debugger_temp = Reg64Int(m_reg[R1]); + break; + + case SATURN_R2: + m_debugger_temp = Reg64Int(m_reg[R2]); + break; + + case SATURN_R3: + m_debugger_temp = Reg64Int(m_reg[R3]); + break; + + case SATURN_R4: + m_debugger_temp = Reg64Int(m_reg[R4]); + break; + } +} + + +void saturn_device::device_reset() +{ + m_pc=0; + m_sleeping = 0; + m_irq_enable = 0; + m_in_irq = 0; +} + + +void saturn_device::saturn_take_irq() +{ + m_in_irq = 1; /* reset by software, using RTI */ + m_pending_irq = 0; + m_icount -= 7; + saturn_push(m_pc); + m_pc=IRQ_ADDRESS; + + LOG(("Saturn '%s' takes IRQ ($%04x)\n", tag(), m_pc)); + + standard_irq_callback(SATURN_IRQ_LINE); +} + +void saturn_device::execute_run() +{ + do + { + m_oldpc = m_pc; + + debugger_instruction_hook(this, m_pc); + + if ( m_sleeping ) + { + /* advance time when sleeping */ + m_icount -= 100; + } + else + { + /* takes irq */ + if ( m_pending_irq && (!m_in_irq) ) + saturn_take_irq(); + + /* execute one instruction */ + saturn_instruction(); + } + + } while (m_icount > 0); +} + + +void saturn_device::execute_set_input(int inputnum, int state) +{ + switch (inputnum) + { + case SATURN_NMI_LINE: + if ( state == m_nmi_state ) return; + m_nmi_state = state; + if ( state != CLEAR_LINE ) + { + LOG(( "SATURN '%s' set_nmi_line(ASSERT)\n", tag())); + m_pending_irq = 1; + } + break; + + case SATURN_IRQ_LINE: + if ( state == m_irq_state ) return; + m_irq_state = state; + if ( state != CLEAR_LINE && m_irq_enable ) + { + LOG(( "SATURN '%s' set_irq_line(ASSERT)\n", tag())); + m_pending_irq = 1; + } + break; + + case SATURN_WAKEUP_LINE: + if (m_sleeping && state==1) + { + LOG(( "SATURN '%s' set_wakeup_line(ASSERT)\n", tag())); + standard_irq_callback(SATURN_WAKEUP_LINE); + m_sleeping = 0; + } + break; + } +} + + +void saturn_device::IntReg64(Saturn64 r, INT64 d) +{ + int i; + for (i=0; i<16; i++) + r[i] = (d >> (4*i)) & 0xf; +} + + +INT64 saturn_device::Reg64Int(Saturn64 r) +{ + INT64 x = 0; + int i; + for (i=0; i<16; i++) + x |= (INT64) r[i] << (4*i); + return x; +} diff --git a/src/devices/cpu/saturn/saturn.h b/src/devices/cpu/saturn/saturn.h new file mode 100644 index 00000000000..836f832cbf6 --- /dev/null +++ b/src/devices/cpu/saturn/saturn.h @@ -0,0 +1,295 @@ +// license:BSD-3-Clause +// copyright-holders:Peter Trauner,Antoine Mine +/***************************************************************************** + * + * cpustate->h + * portable saturn emulator interface + * (hp calculators) + * + * + *****************************************************************************/ +/* +Calculator Release Date Chip Version Analog/Digital IC +HP71B (early) 02/01/84 1LF2 - +HP71B (later) ??/??/?? 1LK7 - +HP18C 06/01/86 1LK7 - +HP28C 01/05/87 1LK7 - +HP17B 01/04/88 1LT8 Lewis +HP19B 01/04/88 1LT8 Lewis +HP27S 01/04/88 1LT8 Lewis +HP28S 01/04/88 1LT8 Lewis +HP48SX 03/16/91 1LT8 Clarke +HP48S 04/02/91 1LT8 Clarke +HP48GX 06/01/93 1LT8 Yorke +HP48G 06/01/93 1LT8 Yorke +HP38G 09/??/95 1LT8 Yorke +*/ +/* 4 bit processor + 20 address lines */ + +#pragma once + +#ifndef __SATURN_H__ +#define _SATURN_H + + +#define SATURN_INT_NONE 0 +#define SATURN_INT_IRQ 1 +#define SATURN_INT_NMI 2 + + +enum +{ + SATURN_A=1, SATURN_B, SATURN_C, SATURN_D, + SATURN_R0, SATURN_R1, SATURN_R2, SATURN_R3, SATURN_R4, + SATURN_RSTK0, SATURN_RSTK1, SATURN_RSTK2, SATURN_RSTK3, + SATURN_RSTK4, SATURN_RSTK5, SATURN_RSTK6, SATURN_RSTK7, + SATURN_PC, SATURN_D0, SATURN_D1, + + SATURN_P, + SATURN_OUT, + SATURN_CARRY, + SATURN_ST, + SATURN_HST, + + SATURN_IRQ_STATE, + SATURN_SLEEPING +}; + +#define SATURN_IRQ_LINE 0 +#define SATURN_NMI_LINE 1 +#define SATURN_WAKEUP_LINE 2 + + +#define MCFG_SATURN_CONFIG(_out, _in, _reset, _config, _unconfig, _id, _crc, _rsi) \ + saturn_device::set_out_func(*device, DEVCB_##_out); \ + saturn_device::set_in_func(*device, DEVCB_##_in); \ + saturn_device::set_reset_func(*device, DEVCB_##_reset); \ + saturn_device::set_config_func(*device, DEVCB_##_config); \ + saturn_device::set_unconfig_func(*device, DEVCB_##_unconfig); \ + saturn_device::set_id_func(*device, DEVCB_##_id); \ + saturn_device::set_crc_func(*device, DEVCB_##_crc); \ + saturn_device::set_rsi_func(*device, DEVCB_##_rsi); + + +class saturn_device : public cpu_device +{ +public: + // construction/destruction + saturn_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // static configuration helpers + template static devcb_base &set_out_func(device_t &device, _Object object) { return downcast(device).m_out_func.set_callback(object); } + template static devcb_base &set_in_func(device_t &device, _Object object) { return downcast(device).m_in_func.set_callback(object); } + template static devcb_base &set_reset_func(device_t &device, _Object object) { return downcast(device).m_reset_func.set_callback(object); } + template static devcb_base &set_config_func(device_t &device, _Object object) { return downcast(device).m_config_func.set_callback(object); } + template static devcb_base &set_unconfig_func(device_t &device, _Object object) { return downcast(device).m_unconfig_func.set_callback(object); } + template static devcb_base &set_id_func(device_t &device, _Object object) { return downcast(device).m_id_func.set_callback(object); } + template static devcb_base &set_crc_func(device_t &device, _Object object) { return downcast(device).m_crc_func.set_callback(object); } + template static devcb_base &set_rsi_func(device_t &device, _Object object) { return downcast(device).m_rsi_func.set_callback(object); } + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_execute_interface overrides + virtual UINT32 execute_min_cycles() const { return 2; } + virtual UINT32 execute_max_cycles() const { return 21; } + virtual UINT32 execute_input_lines() const { return 1; } + virtual void execute_run(); + virtual void execute_set_input(int inputnum, int state); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const { return (spacenum == AS_PROGRAM) ? &m_program_config : NULL; } + + // device_state_interface overrides + void state_string_export(const device_state_entry &entry, std::string &str); + virtual void state_import(const device_state_entry &entry); + virtual void state_export(const device_state_entry &entry); + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const { return 1; } + virtual UINT32 disasm_max_opcode_bytes() const { return 20; } + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + +private: + address_space_config m_program_config; + + devcb_write32 m_out_func; + devcb_read32 m_in_func; + devcb_write_line m_reset_func; + devcb_write32 m_config_func; + devcb_write32 m_unconfig_func; + devcb_read32 m_id_func; + devcb_write32 m_crc_func; + devcb_write_line m_rsi_func; + +// 64 bit, unpacked (one nibble per byte) +typedef UINT8 Saturn64[16]; + + Saturn64 m_reg[9]; //r0,r1,r2,r3,r4,a,b,c,d + + UINT32 m_d[2], m_pc, m_oldpc, m_rstk[8]; // 20 bit, packed addresses + + UINT8 m_p; // 4 bit pointer + + UINT16 m_out; // 12 bit (packed) + UINT8 m_carry, m_decimal; + UINT16 m_st; // status 16 bit + + UINT8 m_hst; // hardware status 4 bit + + UINT8 m_nmi_state; + UINT8 m_irq_state; + UINT8 m_irq_enable; /* INTON / INTOFF */ + UINT8 m_in_irq; /* already servicing IRQ */ + UINT8 m_pending_irq; /* IRQ is pending */ + UINT8 m_sleeping; /* low-consumption state */ + int m_monitor_id; + int m_monitor_in; + address_space *m_program; + direct_read_data *m_direct; + int m_icount; + INT64 m_debugger_temp; + + void saturn_take_irq(); + void IntReg64(Saturn64 r, INT64 d); + INT64 Reg64Int(Saturn64 r); + + inline int READ_OP(); + inline int READ_OP_ARG(); + inline int READ_OP_ARG8(); + inline INT8 READ_OP_DIS8(); + inline int READ_OP_ARG12(); + inline int READ_OP_DIS12(); + inline int READ_OP_ARG16(); + inline INT16 READ_OP_DIS16(); + inline int READ_OP_ARG20(); + inline int READ_NIBBLE(UINT32 adr); + inline int READ_8(UINT32 adr); + inline int READ_12(UINT32 adr); + inline int READ_16(UINT32 adr); + inline int READ_20(UINT32 adr); + inline void WRITE_NIBBLE(UINT32 adr, UINT8 nib); + inline int S64_READ_X(int r); + inline int S64_READ_WORD(int r); + inline int S64_READ_A(int r); + inline void S64_WRITE_X(int r, int v); + inline void S64_WRITE_WORD(int r, int v); + inline void S64_WRITE_A(int r, int v); + inline UINT32 saturn_pop(); + inline void saturn_push(UINT32 adr); + inline void saturn_interrupt_on(); + inline void saturn_interrupt_off(); + inline void saturn_reset_interrupt(); + inline void saturn_mem_reset(); + inline void saturn_mem_config(); + inline void saturn_mem_unconfig(); + inline void saturn_mem_id(); + inline void saturn_shutdown(); + inline void saturn_bus_command_b(); + inline void saturn_bus_command_c(); + inline void saturn_bus_command_d(); + inline void saturn_serial_request(); + inline void saturn_out_c(); + inline void saturn_out_cs(); + inline void saturn_in(int reg); + inline void saturn_sethex() { m_decimal=0; } + inline void saturn_setdec() { m_decimal=1; } + inline void saturn_clear_st(); + inline void saturn_st_to_c(); + inline void saturn_c_to_st(); + inline void saturn_exchange_c_st(); + inline void saturn_jump_after_test(); + inline void saturn_st_clear_bit(); + inline void saturn_st_set_bit(); + inline void saturn_st_jump_bit_clear(); + inline void saturn_st_jump_bit_set(); + inline void saturn_hst_clear_bits(); + inline void saturn_hst_bits_cleared(); + inline void saturn_exchange_p(); + inline void saturn_p_to_c(); + inline void saturn_c_to_p(); + inline void saturn_dec_p(); + inline void saturn_inc_p(); + inline void saturn_load_p(); + inline void saturn_p_equals(); + inline void saturn_p_not_equals(); + inline void saturn_ca_p_1(); + inline void saturn_load_reg(int reg); + inline void saturn_jump(int adr, int jump); + inline void saturn_call(int adr); + inline void saturn_return(int yes); + inline void saturn_return_carry_set(); + inline void saturn_return_carry_clear(); + inline void saturn_return_interrupt(); + inline void saturn_return_xm_set(); + inline void saturn_pop_c(); + inline void saturn_push_c(); + inline void saturn_indirect_jump(int reg); + inline void saturn_equals_zero(int reg, int begin, int count); + inline void saturn_equals(int reg, int begin, int count, int right); + inline void saturn_not_equals_zero(int reg, int begin, int count); + inline void saturn_not_equals(int reg, int begin, int count, int right); + inline void saturn_greater(int reg, int begin, int count, int right); + inline void saturn_greater_equals(int reg, int begin, int count, int right); + inline void saturn_smaller_equals(int reg, int begin, int count, int right); + inline void saturn_smaller(int reg, int begin, int count, int right); + inline void saturn_jump_bit_clear(int reg); + inline void saturn_jump_bit_set(int reg); + inline void saturn_load_pc(int reg); + inline void saturn_store_pc(int reg); + inline void saturn_exchange_pc(int reg); + inline void saturn_load_adr(int reg, int nibbles); + inline void saturn_add_adr(int reg); + inline void saturn_sub_adr(int reg); + inline void saturn_adr_to_reg(int adr, int reg); + inline void saturn_reg_to_adr(int reg, int adr); + inline void saturn_adr_to_reg_word(int adr, int reg); + inline void saturn_reg_to_adr_word(int reg, int adr); + inline void saturn_exchange_adr_reg(int adr, int reg); + inline void saturn_exchange_adr_reg_word(int adr, int reg); + inline void saturn_load_nibbles(int reg, int begin, int count, int adr); + inline void saturn_store_nibbles(int reg, int begin, int count, int adr); + inline void saturn_clear_bit(int reg); + inline void saturn_set_bit(int reg); + inline void saturn_clear(int reg, int begin, int count); + inline void saturn_exchange(int left, int begin, int count, int right); + inline void saturn_copy(int dest, int begin, int count, int src); + inline void saturn_add(int reg, int begin, int count, int right); + inline void saturn_add_const(int reg, int begin, int count, UINT8 right); + inline void saturn_sub(int reg, int begin, int count, int right); + inline void saturn_sub_const(int reg, int begin, int count, int right); + inline void saturn_sub2(int reg, int begin, int count, int right); + inline void saturn_increment(int reg, int begin, int count); + inline void saturn_decrement(int reg, int begin, int count); + inline void saturn_invert(int reg, int begin, int count); + inline void saturn_negate(int reg, int begin, int count); + inline void saturn_or(int dest, int begin, int count, int src); + inline void saturn_and(int dest, int begin, int count, int src); + inline void saturn_shift_nibble_left(int reg, int begin, int count); + inline void saturn_shift_nibble_right(int reg, int begin, int count); + inline void saturn_rotate_nibble_left_w(int reg); + inline void saturn_rotate_nibble_right_w(int reg); + inline void saturn_shift_right(int reg, int begin, int count); + void saturn_invalid3( int op1, int op2, int op3 ); + void saturn_invalid4( int op1, int op2, int op3, int op4 ); + void saturn_invalid5( int op1, int op2, int op3, int op4, int op5 ); + void saturn_invalid6( int op1, int op2, int op3, int op4, int op5, int op6 ); + void saturn_instruction_0e(); + void saturn_instruction_1(); + void saturn_instruction_80(); + void saturn_instruction_81a(); + void saturn_instruction_81(); + void saturn_instruction_8(); + void saturn_instruction_9(); + void saturn_instruction_a(); + void saturn_instruction_b(); + void saturn_instruction(); +}; + +extern const device_type SATURN; + + +#endif /* __SATURN_H__ */ diff --git a/src/devices/cpu/saturn/saturnds.c b/src/devices/cpu/saturn/saturnds.c new file mode 100644 index 00000000000..1dc6eb3d622 --- /dev/null +++ b/src/devices/cpu/saturn/saturnds.c @@ -0,0 +1,1470 @@ +// license:BSD-3-Clause +// copyright-holders:Peter Trauner,Antoine Mine +/***************************************************************************** + * + * saturnds.c + * portable saturn emulator interface + * (hp calculators) + * + *****************************************************************************/ + +#include "emu.h" +#include "debugger.h" + +#include "saturn.h" + +#define SATURN_HP_MNEMONICS + +#if defined SATURN_HP_MNEMONICS +// class/hp mnemonics +static int set=0; +#else +// readable/normal mnemonics +static int set=1; +#endif + +#define P "P" +#define WP "WP" +#define XS "XS" +#define X "X" +#define S "S" +#define M "M" +#define B "B" +#define W "W" +#define A "A" + +static const char *const adr_b[]= +{ P, WP, XS, X, S, M, B, W }; + +static const char *const adr_af[]= +{ P, WP, XS, X, S, M, B, W, 0, 0, 0, 0, 0, 0, 0, A }; + +static const char *const adr_a[]= + { P, WP, XS, X, S, M, B, W }; + +static const char number_2_hex[]= +{ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; + +#define SATURN_PEEKOP_DIS8(v) v = (INT8)( oprom[pos] | ( oprom[pos+1] << 4 ) ); pos+= 2; + +#define SATURN_PEEKOP_DIS12(v) v = oprom[pos] | ( oprom[pos+1] << 4 ) | ( oprom[pos+2] << 8 ); \ + pos += 3; \ + if ( v & 0x0800 ) v = -0x1000 + v; + +#define SATURN_PEEKOP_DIS16(v) v = (INT16)( oprom[pos] | ( oprom[pos+1] << 4 ) | ( oprom[pos+2] << 8 ) | ( oprom[pos+3] << 12 ) ); pos += 4; + +#define SATURN_PEEKOP_ADR(v) v = oprom[pos] | ( oprom[pos+1] << 4 ) | ( oprom[pos+2] << 8 ) | ( oprom[pos+3] << 12 ) | ( oprom[pos+4] << 16 ); pos += 5; + + +// don't split branch and return, source relies on this ordering +enum MNEMONICS +{ + Return, ReturnSetXM, ReturnSetCarry, ReturnClearCarry, ReturnFromInterrupt, + jump3,jump4,jump, + call3,call4,call, + branchCarrySet, returnCarrySet, + branchCarryClear, returnCarryClear, + + outCS, outC, inA, inC, + unconfig, config, Cid, shutdown, cp1, reset, buscc, + CcopyP, PcopyC, sreq, CswapP, + + inton, AloadImm, buscb, + clearAbit, setAbit, + branchAbitclear, returnAbitclear, + branchAbitset, returnAbitset, + clearCbit, setCbit, + branchCbitclear, returnCbitclear, + branchCbitset, returnCbitset, + PCloadA, buscd, PCloadC, intoff, rsi, + + jumpA, jumpC, PCcopyA, PCcopyC, AcopyPC, CcopyPC, + + clearHST, + branchHSTclear, returnHSTclear, + + clearBitST, setBitST, + branchSTclear, returnSTclear, + branchSTset, returnSTset, + + + branchPdiffers, returnPdiffers, + branchPequals, returnPequals, + + branchAequalsB, returnAequalsB, + branchBequalsC, returnBequalsC, + branchAequalsC, returnAequalsC, + branchCequalsD, returnCequalsD, + branchAdiffersB, returnAdiffersB, + branchBdiffersC, returnBdiffersC, + branchAdiffersC, returnAdiffersC, + branchCdiffersD, returnCdiffersD, + branchAzero, returnAzero, + branchBzero, returnBzero, + branchCzero, returnCzero, + branchDzero, returnDzero, + branchAnotzero, returnAnotzero, + branchBnotzero, returnBnotzero, + branchCnotzero, returnCnotzero, + branchDnotzero, returnDnotzero, + + branchAgreaterB, returnAgreaterB, + branchBgreaterC, returnBgreaterC, + branchCgreaterA, returnCgreaterA, + branchDgreaterC, returnDgreaterC, + branchAlowerB, returnAlowerB, + branchBlowerC, returnBlowerC, + branchClowerA, returnClowerA, + branchDlowerC, returnDlowerC, + branchAnotlowerB, returnAnotlowerB, + branchBnotlowerC, returnBnotlowerC, + branchCnotlowerA, returnCnotlowerA, + branchDnotlowerC, returnDnotlowerC, + branchAnotgreaterB, returnAnotgreaterB, + branchBnotgreaterC, returnBnotgreaterC, + branchCnotgreaterA, returnCnotgreaterA, + branchDnotgreaterC, returnDnotgreaterC, + + SetHexMode, SetDecMode, + PushC, PopC, + + D0loadImm2, D0loadImm4, D0loadImm5, + D1loadImm2, D1loadImm4, D1loadImm5, + PloadImm, CloadImm, + + clearST, + CcopyST, STcopyC, + swapCST, + + incP, decP, + + R0copyA, R1copyA, R2copyA, R3copyA, R4copyA, + R0copyC, R1copyC, R2copyC, R3copyC, R4copyC, + + AcopyR0, AcopyR1, AcopyR2, AcopyR3, AcopyR4, + CcopyR0, CcopyR1, CcopyR2, CcopyR3, CcopyR4, + + D0copyA, D1copyA, D0copyC, D1copyC, + D0copyAShort, D1copyAShort, D0copyCShort, D1copyCShort, // other class mnemonic + + SwapAR0, SwapAR1, SwapAR2, SwapAR3, SwapAR4, + SwapCR0, SwapCR1, SwapCR2, SwapCR3, SwapCR4, + + SwapAD0, SwapAD1, SwapCD0, SwapCD1, + SwapAD0Short, SwapAD1Short, SwapCD0Short, SwapCD1Short, // other class mnemonic + + D0storeA, D1storeA, D0storeC, D1storeC, + AloadD0, AloadD1, CloadD0, CloadD1, + + D0addImm, D1addImm, D0subImm, D1subImm, + AaddImm, BaddImm, CaddImm, DaddImm, + AsubImm, BsubImm, CsubImm, DsubImm, + + AandB, BandC, CandA, DandC, BandA, CandB, AandC, CandD, + AorB, BorC, CorA, DorC, BorA, CorB, AorC, CorD, + + Ashiftrightbit, Bshiftrightbit, Cshiftrightbit, Dshiftrightbit, + + AshiftleftCarry, BshiftleftCarry, CshiftleftCarry, DshiftleftCarry, + AshiftrightCarry, BshiftrightCarry, CshiftrightCarry, DshiftrightCarry, + + AaddB, BaddC, CaddA, DaddC, AaddA, BaddB, CaddC, DaddD, + BaddA, CaddB, AaddC, CaddD, decA, decB, decC, decD, + + AsubB, BsubC, CsubA, DsubC, incA, incB, incC, incD, + BsubA, CsubB, AsubC, CsubD, AsubnB, BsubnC, CsubnA, DsubnC, + + clearA, clearB, clearC, clearD, + AcopyB, BcopyC, CcopyA, DcopyC, BcopyA, CcopyB, AcopyC, CcopyD, + AswapB, BswapC, CswapA, DswapC, + + Ashiftleft, Bshiftleft, Cshiftleft, Dshiftleft, + Ashiftright, Bshiftright, Cshiftright, Dshiftright, + negateA, negateB, negateC, negateD, + notA, notB, notC, notD + +}; + +static const struct { + const char *name[2]; +} mnemonics[]={ + { { "rtn", "RET" } }, + { { "rtnsXM", "RETSETXM" } }, + { { "rtnsC", "RETSETC" } }, + { { "rtncC", "RETCLRC" } }, + { { "rti", "RETI" } }, + { { "goto %05x", "JUMP.3 %05x" } }, + { { "goto %05x", "JUMP.4 %05x" } }, + { { "goto %05x", "JUMP %05x" } }, + { { "gosub %05x", "CALL.3 %05x" } }, + { { "gosub %05x", "CALL.4 %05x" } }, + { { "gosub %05x", "CALL %05x" } }, + { { "goC %05x", "BRCS %05x" } }, + { { "rtnC", "RETCS" } }, + { { "gonC %05x", "BRCC %05x" } }, + { { "rtnnC", "RETCC" } }, + + { { "OUT=CS", "OUT.S C" } }, + { { "OUT=C", "OUT.X C" } }, + { { "A=IN", "IN.4 A" } }, + { { "C=IN", "IN.4 C" } }, + { { "uncnfg", "UNCNFG" } }, + { { "config", "CONFIG" } }, + { { "C=id", "MOVE.A ID,C" } }, + { { "!shutdn", "!SHUTDN" } }, + { { "C+P+1", "ADD.A P+1,C" } }, + { { "reset", "RESET" } }, + { { "!buscc", "!BUSCC" } }, + { { "C=P %x", "MOVE.1 P,C,%x" } }, + { { "P=C %x", "MOVE.1 C,%x,P" } }, + { { "!sreq?", "!SREQ" } }, + { { "CPex %x", "SWAP.1 P,C,%x" } }, + + { { "!inton", "!INTON" } }, + { { "LA %-2x %s", "MOVE.P%-2x %s,A" } }, + { { "!buscb", "!BUSCB" } }, + { { "Abit=0 %x", "CLRB %x,A" } }, + { { "Abit=1 %x", "SETB %x,A" } }, + { { "?Abit=0 %x,%05x", "BRBC %x,A,%05x" } }, + { { "?Abit=0 %x,rtn", "RETBC %x,A" } }, + { { "?Abit=1 %x,%05x", "BRBS %x,A,%05x" } }, + { { "?Abit=1 %x,rtn", "RETBS %x,A" } }, + { { "Cbit=0 %x", "CLRB %x,C" } }, + { { "Cbit=1 %x", "SETB %x,C" } }, + { { "?Cbit=0 %x,%05x", "BRBC %x,C,%05x" } }, + { { "?Cbit=0 %x,rtn", "RETBC %x,C" } }, + { { "?Cbit=1 %x,%05x", "BRBS %x,C,%05x" } }, + { { "?Cbit=1 %x,rtn", "RETBS %x,C" } }, + { { "PC=(A)", "JUMP.A @A" } }, + { { "!buscd", "!BUSCD" } }, + { { "PC=(C)", "JUMP.A @C" } }, + { { "!intoff", "!INTOFF" } }, + { { "!rsi", "!RSI" } }, + + { { "PC=A", "JUMP.A A" } }, + { { "PC=C", "JUMP.A C" } }, + { { "A=PC", "MOVE.A PC,A" } }, + { { "C=PC", "MOVE.A PC,C" } }, + { { "APCex", "SWAP.A A,PC" } }, + { { "CPCex", "SWAP.A C,PC" } }, + + { { "HST=0 %x", "CLRHST %x" } }, + { { "?HST=0 %x,%05x", "BRBCHST %x,%05x" } }, + { { "?HST=0 %x,rtn", "RETBCHST %x" } }, + { { "ST=0 %x", "CLRB %x,ST" } }, + { { "ST=1 %x", "SETB %x,ST" } }, + { { "?ST=0 %x,%05x", "BRBC ST,%x,%05x" } }, + { { "?ST=0 %x,rtn", "RETBC ST,%x" } }, + { { "?ST=1 %x,%05x", "BRBS ST,%x,%05x" } }, + { { "?ST=1 %x,rtn", "RETBS ST,%x" } }, + { { "?P# %x,%05x", "BRNE P,%x,%05x" } }, + { { "?P# %x,rtn", "RETNE P,%x" } }, + { { "?P= %x,%05x", "BREQ P,%x,%05x" } }, + { { "?P= %x,rtn", "RETEQ P,%x" } }, + + { { "?A=B %s,%05x", "BREQ.%-2s A,B,%05x" } }, + { { "?A=B %s,rtn", "RETEQ.%-2s A,B" } }, + { { "?B=C %s,%05x", "BREQ.%-2s B,C,%05x" } }, + { { "?B=C %s,rtn", "RETEQ.%-2s B,C" } }, + { { "?A=C %s,%05x", "BREQ.%-2s A,C,%05x" } }, + { { "?A=C %s,rtn", "RETEQ.%-2s A,C" } }, + { { "?C=D %s,%05x", "BREQ.%-2s C,D,%05x" } }, + { { "?C=D %s,rtn", "RETEQ.%-2s C,D" } }, + { { "?A#B %s,%05x", "BRNE.%-2s A,B,%05x" } }, + { { "?A#B %s,rtn", "RETNE.%-2s A,B" } }, + { { "?B#C %s,%05x", "BRNE.%-2s B,C,%05x" } }, + { { "?B#C %s,rtn", "RETNE.%-2s B,C" } }, + { { "?A#C %s,%05x", "BRNE.%-2s A,C,%05x" } }, + { { "?A#C %s,rtn", "RETNE.%-2s A,C" } }, + { { "?C#D %s,%05x", "BRNE.%-2s C,D,%05x" } }, + { { "?C#D %s,rtn", "RETNE.%-2s C,D" } }, + { { "?A=0 %s,%05x", "BRZ.%-2s A,%05x" } }, + { { "?A=0 %s,rtn", "RETZ.%-2s A" } }, + { { "?B=0 %s,%05x", "BRZ.%-2s B,%05x" } }, + { { "?B=0 %s,rtn", "RETZ.%-2s B" } }, + { { "?C=0 %s,%05x", "BRZ.%-2s C,%05x" } }, + { { "?C=0 %s,rtn", "RETZ.%-2s C" } }, + { { "?D=0 %s,%05x", "BRZ.%-2s D,%05x" } }, + { { "?D=0 %s,rtn", "RETZ.%-2s D" } }, + { { "?A#0 %s,%05x", "BRNZ.%-2s A,%05x" } }, + { { "?A#0 %s,rtn", "RETNZ.%-2s A" } }, + { { "?B#0 %s,%05x", "BRNZ.%-2s B,%05x" } }, + { { "?B#0 %s,rtn", "RETNZ.%-2s B" } }, + { { "?C#0 %s,%05x", "BRNZ.%-2s C,%05x" } }, + { { "?C#0 %s,rtn", "RETNZ.%-2s C" } }, + { { "?D#0 %s,%05x", "BRNZ.%-2s D,%05x" } }, + { { "?D#0 %s,rtn", "RETNZ.%-2s D" } }, + + { { "?A>B %s,%05x", "BRGT.%-2s A,B,%05x" } }, + { { "?A>B %s,rtn", "RETGT.%-2s A,B" } }, + { { "?B>C %s,%05x", "BRGT.%-2s B,C,%05x" } }, + { { "?B>C %s,rtn", "RETGT.%-2s B,C" } }, + { { "?C>A %s,%05x", "BRGT.%-2s C,A,%05x" } }, + { { "?C>A %s,rtn", "RETGT.%-2s C,A" } }, + { { "?D>C %s,%05x", "BRGT.%-2s D,C,%05x" } }, + { { "?D>C %s,rtn", "RETGT.%-2s D,C" } }, + { { "?A=B %s,%05x", "BRGE.%-2s A,B,%05x" } }, + { { "?A>=B %s,rtn", "RETGE.%-2s A,B" } }, + { { "?B>=C %s,%05x", "BRGE.%-2s B,C,%05x" } }, + { { "?B>=C %s,rtn", "RETGE.%-2s B,C" } }, + { { "?C>=A %s,%05x", "BRGE.%-2s C,A,%05x" } }, + { { "?C>=A %s,rtn", "RETGE.%-2s C,A" } }, + { { "?D>=C %s,%05x", "BRGE.%-2s D,C,%05x" } }, + { { "?D>=C %s,rtn", "RETGE.%-2s D,C" } }, + { { "?A<=B %s,%05x", "BRLE.%-2s A,B,%05x" } }, + { { "?A<=B %s,rtn", "RETLE.%-2s A,B" } }, + { { "?B<=C %s,%05x", "BRLE.%-2s B,C,%05x" } }, + { { "?B<=C %s,rtn", "RETLE.%-2s B,C" } }, + { { "?C<=A %s,%05x", "BRLE.%-2s C,A,%05x" } }, + { { "?C<=A %s,rtn", "RETLE.%-2s C,A" } }, + { { "?D<=C %s,%05x", "BRLE.%-2s D,C,%05x" } }, + { { "?D<=C %s,rtn", "RETLE.%-2s D,C" } }, + + { { "sethex", "SETHEX" } }, + { { "setdec", "SETDEC" } }, + { { "RSTK=C", "PUSH.A C" } }, + { { "C=RSTK", "POP.A C" } }, + + // load immediate + { { "D0= %02x", "MOVE.2 %02x,D0" } }, + { { "D0= %04x", "MOVE.4 %04x,D0" } }, + { { "D0= %05x", "MOVE.5 %05x,D0" } }, + + { { "D1= %02x", "MOVE.2 %02x,D1" } }, + { { "D1= %04x", "MOVE.4 %04x,D1" } }, + { { "D1= %05x", "MOVE.5 %05x,D1" } }, + + { { "P= %x", "MOVE %x,P" } }, + { { "lC %-2x %s", "MOVE.P%-2x %s,C" } }, + + { { "clrST", "CLR.X ST" } }, + { { "C=ST", "MOVE.X ST,C" } }, + { { "ST=C", "MOVE.X C,ST" } }, + { { "CSTex", "SWAP.X C,ST" } }, + + { { "P=P+1", "INC P" } }, + { { "P=P-1", "DEC P" } }, + + // copy + { { "R0=A %s", "MOVE.%-2s A,R0" } }, + { { "R1=A %s", "MOVE.%-2s A,R1" } }, + { { "R2=A %s", "MOVE.%-2s A,R2" } }, + { { "R3=A %s", "MOVE.%-2s A,R3" } }, + { { "R4=A %s", "MOVE.%-2s A,R4" } }, + + { { "R0=C %s", "MOVE.%-2s C,R0" } }, + { { "R1=C %s", "MOVE.%-2s C,R1" } }, + { { "R2=C %s", "MOVE.%-2s C,R2" } }, + { { "R3=C %s", "MOVE.%-2s C,R3" } }, + { { "R4=C %s", "MOVE.%-2s C,R4" } }, + + { { "A=R0 %s", "MOVE.%-2s R0,A" } }, + { { "A=R1 %s", "MOVE.%-2s R1,A" } }, + { { "A=R2 %s", "MOVE.%-2s R2,A" } }, + { { "A=R3 %s", "MOVE.%-2s R3,A" } }, + { { "A=R4 %s", "MOVE.%-2s R4,A" } }, + + { { "C=R0 %s", "MOVE.%-2s R0,C" } }, + { { "C=R1 %s", "MOVE.%-2s R1,C" } }, + { { "C=R2 %s", "MOVE.%-2s R2,C" } }, + { { "C=R3 %s", "MOVE.%-2s R3,C" } }, + { { "C=R4 %s", "MOVE.%-2s R4,C" } }, + + { { "D0=A", "MOVE.A A,D0" } }, + { { "D1=A", "MOVE.A A,D1" } }, + { { "D0=C", "MOVE.A C,D0" } }, + { { "D1=C", "MOVE.A C,D1" } }, + { { "D0=As", "MOVE.S A,D0" } }, + { { "D1=As", "MOVE.S A,D1" } }, + { { "D0=Cs", "MOVE.S C,D0" } }, + { { "D1=Cs", "MOVE.S C,D1" } }, + + // swap operations + { { "AR0ex %s", "SWAP.%-2s A,R0" } }, + { { "AR1ex %s", "SWAP.%-2s A,R1" } }, + { { "AR2ex %s", "SWAP.%-2s A,R2" } }, + { { "AR3ex %s", "SWAP.%-2s A,R3" } }, + { { "AR4ex %s", "SWAP.%-2s A,R4" } }, + + { { "CR0ex %s", "SWAP.%-2s C,R0" } }, + { { "CR1ex %s", "SWAP.%-2s C,R1" } }, + { { "CR2ex %s", "SWAP.%-2s C,R2" } }, + { { "CR3ex %s", "SWAP.%-2s C,R3" } }, + { { "CR4ex %s", "SWAP.%-2s C,R4" } }, + + { { "AD0ex", "SWAP.A A,D0" } }, + { { "AD1ex", "SWAP.A A,D1" } }, + { { "CD0ex", "SWAP.A C,D0" } }, + { { "CD1ex", "SWAP.A C,D1" } }, + { { "AD0xs", "SWAP.S A,D0" } }, + { { "AD1xs", "SWAP.S A,D1" } }, + { { "CD0xs", "SWAP.S C,D0" } }, + { { "CD1xs", "SWAP.S C,D1" } }, + + // store + { { "Dat0=A %s", "MOVE.%-2s A,@D0" } }, + { { "Dat1=A %s", "MOVE.%-2s A,@D0" } }, + { { "Dat0=C %s", "MOVE.%-2s C,@D0" } }, + { { "Dat1=C %s", "MOVE.%-2s C,@D0" } }, + + // load + { { "A=Dat0 %s", "MOVE.%-2s @D0,A" } }, + { { "A=Dat1 %s", "MOVE.%-2s @D0,A" } }, + { { "C=Dat0 %s", "MOVE.%-2s @D0,C" } }, + { { "C=Dat1 %s", "MOVE.%-2s @D0,C" } }, + + // add/sub immediate + { { "D0=D0+ %x", "ADD.A %x,D0" } }, + { { "D1=D1+ %x", "ADD.A %x,D1" } }, + { { "D0=D0- %x", "SUB.A %x,D0" } }, + { { "D1=D1- %x", "SUB.A %x,D1" } }, + + { { "A=A+ %s,%x", "ADD.%-2s %x,A" } }, + { { "B=B+ %s,%x", "ADD.%-2s %x,B" } }, + { { "C=C+ %s,%x", "ADD.%-2s %x,C" } }, + { { "D=D+ %s,%x", "ADD.%-2s %x,D" } }, + { { "A=A- %s,%x", "SUB.%-2s %x,A" } }, + { { "B=B- %s,%x", "SUB.%-2s %x,B" } }, + { { "C=C- %s,%x", "SUB.%-2s %x,C" } }, + { { "D=D- %s,%x", "SUB.%-2s %x,D" } }, + + { { "A=A&B %s", "AND.%-2s B,A" } }, + { { "B=B&C %s", "AND.%-2s C,B" } }, + { { "C=C&A %s", "AND.%-2s A,C" } }, + { { "D=D&C %s", "AND.%-2s C,D" } }, + { { "B=B&A %s", "AND.%-2s A,B" } }, + { { "C=C&B %s", "AND.%-2s B,C" } }, + { { "A=A&C %s", "AND.%-2s C,A" } }, + { { "C=C&D %s", "AND.%-2s D,C" } }, + + { { "A=A!B %s", "OR.%-2s B,A" } }, + { { "B=B!C %s", "OR.%-2s C,B" } }, + { { "C=C!A %s", "OR.%-2s A,C" } }, + { { "D=D!C %s", "OR.%-2s C,D" } }, + { { "B=B!A %s", "OR.%-2s A,B" } }, + { { "C=C!B %s", "OR.%-2s B,C" } }, + { { "A=A!C %s", "OR.%-2s C,A" } }, + { { "C=C!D %s", "OR.%-2s D,C" } }, + + { { "Asrb %s", "SRB.%-2s A" } }, + { { "Bsrb %s", "SRB.%-2s B" } }, + { { "Csrb %s", "SRB.%-2s C" } }, + { { "Dsrb %s", "SRB.%-2s D" } }, + + { { "Aslc %s", "RLN.%-2s A" } }, + { { "Bslc %s", "RLN.%-2s B" } }, + { { "Cslc %s", "RLN.%-2s C" } }, + { { "Dslc %s", "RLN.%-2s D" } }, + { { "Asrc %s", "RRN.%-2s A" } }, + { { "Bsrc %s", "RRN.%-2s B" } }, + { { "Csrc %s", "RRN.%-2s C" } }, + { { "Dsrc %s", "RRN.%-2s D" } }, + + { { "A=A+B %s", "ADD.%-2s B,A" } }, + { { "B=B+C %s", "ADD.%-2s C,B" } }, + { { "C=C+A %s", "ADD.%-2s A,C" } }, + { { "D=D+C %s", "ADD.%-2s C,D" } }, + { { "A=A+A %s", "ADD.%-2s A,A" } }, + { { "B=B+B %s", "ADD.%-2s B,B" } }, + { { "C=C+C %s", "ADD.%-2s C,C" } }, + { { "D=D+C %s", "ADD.%-2s D,D" } }, + { { "B=B+A %s", "ADD.%-2s A,B" } }, + { { "C=C+B %s", "ADD.%-2s B,C" } }, + { { "A=A+C %s", "ADD.%-2s C,A" } }, + { { "C=C+D %s", "ADD.%-2s D,C" } }, + { { "A=A-1 %s", "DEC.%-2s A" } }, + { { "B=B-1 %s", "DEC.%-2s B" } }, + { { "C=C-1 %s", "DEC.%-2s C" } }, + { { "D=D-1 %s", "DEC.%-2s D" } }, + + { { "A=A-B %s", "ADD.%-2s B,A" } }, + { { "B=B-C %s", "ADD.%-2s C,B" } }, + { { "C=C-A %s", "ADD.%-2s A,C" } }, + { { "D=D-C %s", "ADD.%-2s C,D" } }, + { { "A=A+1 %s", "INC.%-2s A" } }, + { { "B=B+1 %s", "INC.%-2s B" } }, + { { "C=C+1 %s", "INC.%-2s C" } }, + { { "D=D+1 %s", "INC.%-2s D" } }, + { { "B=B-A %s", "SUB.%-2s A,B" } }, + { { "C=C-B %s", "SUB.%-2s B,C" } }, + { { "A=A-C %s", "SUB.%-2s C,A" } }, + { { "C=C-D %s", "SUB.%-2s D,C" } }, + { { "A=B-A %s", "SUBN.%-2s B,A" } }, + { { "B=C-B %s", "SUBN.%-2s C,B" } }, + { { "C=A-C %s", "SUBN.%-2s A,C" } }, + { { "D=C-D %s", "SUBN.%-2s C,D" } }, + + { { "A=0 %s", "CLR.%-2s A" } }, + { { "B=0 %s", "CLR.%-2s B" } }, + { { "C=0 %s", "CLR.%-2s C" } }, + { { "D=0 %s", "CLR.%-2s D" } }, + { { "A=B %s", "MOVE.%-2s B,A" } }, + { { "B=C %s", "MOVE.%-2s C,B" } }, + { { "C=A %s", "MOVE.%-2s A,C" } }, + { { "D=C %s", "MOVE.%-2s C,D" } }, + { { "B=A %s", "MOVE.%-2s A,B" } }, + { { "C=B %s", "MOVE.%-2s B,C" } }, + { { "A=C %s", "MOVE.%-2s C,A" } }, + { { "C=D %s", "MOVE.%-2s D,C" } }, + { { "ABex %s", "SWAP.%-2s A,B" } }, + { { "BCex %s", "SWAP.%-2s B,C" } }, + { { "ACex %s", "SWAP.%-2s A,C" } }, + { { "CDex %s", "SWAP.%-2s C,D" } }, + + { { "Asl %s", "SLN.%-2s A" } }, + { { "Bsl %s", "SLN.%-2s B" } }, + { { "Csl %s", "SLN.%-2s C" } }, + { { "Dsl %s", "SLN.%-2s D" } }, + { { "Asr %s", "SRN.%-2s A" } }, + { { "Bsr %s", "SRN.%-2s B" } }, + { { "Csr %s", "SRN.%-2s C" } }, + { { "Dsr %s", "SRN.%-2s D" } }, + { { "A=-A %s", "NEG.%-2s A" } }, + { { "B=-B %s", "NEG.%-2s B" } }, + { { "C=-C %s", "NEG.%-2s C" } }, + { { "D=-D %s", "NEG.%-2s D" } }, + { { "A=-A-1 %s", "NOT.%-2s A" } }, + { { "B=-B-1 %s", "NOT.%-2s B" } }, + { { "C=-C-1 %s", "NOT.%-2s C" } }, + { { "D=-D-1 %s", "NOT.%-2s D" } } + +}; + +enum opcode_sel +{ + Complete=-1, + Illegal, + Opcode0, Opcode0E, Opcode0Ea, + Opcode1, Opcode10, Opcode11, Opcode12, Opcode13, Opcode14, Opcode15, + Opcode8, Opcode80, Opcode808, Opcode8081, + Opcode81, Opcode818, Opcode818a, Opcode819, Opcode819a, + Opcode81A, Opcode81Aa, Opcode81Aa0,Opcode81Aa1, Opcode81Aa2, Opcode81B, + Opcode8A, Opcode8B, + Opcode9, Opcode9a, Opcode9b, + OpcodeA, OpcodeAa, OpcodeAb, + OpcodeB, OpcodeBa, OpcodeBb, + OpcodeC, + OpcodeD, + OpcodeE, + OpcodeF +}; + +enum opcode_adr +{ + AdrNone, + AdrAF, AdrA, AdrB, AdrCount, + BranchReturn, TestBranchRet, ImmBranch, + ABranchReturn, // address field A + xBranchReturn, // address field specified in previous opcode entry + Imm, ImmCount, ImmCload, Imm2, Imm4, Imm5, + Dis3, Dis3Call, Dis4, Dis4Call, Abs, + FieldP, FieldWP, FieldXS, FieldX, FieldS, FieldM, FieldB, FieldW, FieldA, + AdrImmCount +}; + +struct OPCODE +{ + opcode_sel sel; + opcode_adr adr; + MNEMONICS mnemonic; +}; + +static const char *field_2_string(int adr_enum) +{ + switch (adr_enum) { + case FieldP: return P; + case FieldWP: return WP; + case FieldXS: return XS; + case FieldX: return X; + case FieldS: return S; + case FieldM: return M; + case FieldB: return B; + case FieldW: return W; + case FieldA: return A; + } + return 0; +} + +static const OPCODE opcodes[][0x10]= { + { + // first digit + { Opcode0 }, + { Opcode1 }, + { Complete, Imm, PloadImm }, + { Complete, ImmCload, CloadImm }, + { Complete, BranchReturn, branchCarrySet}, + { Complete, BranchReturn, branchCarryClear }, + { Complete, Dis3, jump3 }, + { Complete, Dis3Call, call3 }, + { Opcode8 }, + { Opcode9 }, + { OpcodeA }, + { OpcodeB }, + { OpcodeC }, + { OpcodeD }, + { OpcodeE }, + { OpcodeF } + }, { // 0 + { Complete, AdrNone, ReturnSetXM }, + { Complete, AdrNone, Return }, + { Complete, AdrNone, ReturnSetCarry }, + { Complete, AdrNone, ReturnClearCarry }, + { Complete, AdrNone, SetHexMode }, + { Complete, AdrNone, SetDecMode }, + { Complete, AdrNone, PushC }, + { Complete, AdrNone, PopC }, + { Complete, AdrNone, clearST }, + { Complete, AdrNone, CcopyST }, + { Complete, AdrNone, STcopyC }, + { Complete, AdrNone, swapCST }, + { Complete, AdrNone, incP }, + { Complete, AdrNone, decP }, + { Opcode0E }, + { Complete, AdrNone, ReturnFromInterrupt } + }, { //0E + { Opcode0Ea, AdrAF }, + { Opcode0Ea, AdrAF }, + { Opcode0Ea, AdrAF }, + { Opcode0Ea, AdrAF }, + { Opcode0Ea, AdrAF }, + { Opcode0Ea, AdrAF }, + { Opcode0Ea, AdrAF }, + { Opcode0Ea, AdrAF }, + { Illegal }, + { Illegal }, + { Illegal }, + { Illegal }, + { Illegal }, + { Illegal }, + { Illegal }, + { Opcode0Ea, AdrAF } + }, { //0Ea + { Complete, AdrNone, AandB }, + { Complete, AdrNone, BandC }, + { Complete, AdrNone, CandA }, + { Complete, AdrNone, DandC }, + { Complete, AdrNone, BandA }, + { Complete, AdrNone, CandB }, + { Complete, AdrNone, AandC }, + { Complete, AdrNone, CandD }, + { Complete, AdrNone, AorB }, + { Complete, AdrNone, BorC }, + { Complete, AdrNone, CorA }, + { Complete, AdrNone, DorC }, + { Complete, AdrNone, BorA }, + { Complete, AdrNone, CorB }, + { Complete, AdrNone, AorC }, + { Complete, AdrNone, CorD } + }, { //1 + { Opcode10 }, + { Opcode11 }, + { Opcode12 }, + { Opcode13 }, + { Opcode14 }, + { Opcode15 }, + { Complete, ImmCount, D0addImm }, + { Complete, ImmCount, D1addImm }, + { Complete, ImmCount, D0subImm }, + { Complete, Imm2, D0loadImm2 }, + { Complete, Imm4, D0loadImm4 }, + { Complete, Imm5, D0loadImm5 }, + { Complete, ImmCount, D1subImm }, + { Complete, Imm2, D1loadImm2 }, + { Complete, Imm4, D1loadImm4 }, + { Complete, Imm5, D1loadImm5 } + }, { //10 + { Complete, FieldW, R0copyA }, + { Complete, FieldW, R1copyA }, + { Complete, FieldW, R2copyA }, + { Complete, FieldW, R3copyA }, + { Complete, FieldW, R4copyA }, + { Illegal }, + { Illegal }, + { Illegal }, + { Complete, FieldW, R0copyC }, + { Complete, FieldW, R1copyC }, + { Complete, FieldW, R2copyC }, + { Complete, FieldW, R3copyC }, + { Complete, FieldW, R4copyC }, + { Illegal }, + { Illegal }, + { Illegal } + }, { //11 + { Complete, FieldW, AcopyR0 }, + { Complete, FieldW, AcopyR1 }, + { Complete, FieldW, AcopyR2 }, + { Complete, FieldW, AcopyR3 }, + { Complete, FieldW, AcopyR4 }, + { Illegal }, + { Illegal }, + { Illegal }, + { Complete, FieldW, CcopyR0 }, + { Complete, FieldW, CcopyR1 }, + { Complete, FieldW, CcopyR2 }, + { Complete, FieldW, CcopyR3 }, + { Complete, FieldW, CcopyR4 }, + { Illegal }, + { Illegal }, + { Illegal } + }, { //12 + { Complete, FieldW, SwapAR0 }, + { Complete, FieldW, SwapAR1 }, + { Complete, FieldW, SwapAR2 }, + { Complete, FieldW, SwapAR3 }, + { Complete, FieldW, SwapAR4 }, + { Illegal }, + { Illegal }, + { Illegal }, + { Complete, FieldW, SwapCR0 }, + { Complete, FieldW, SwapCR1 }, + { Complete, FieldW, SwapCR2 }, + { Complete, FieldW, SwapCR3 }, + { Complete, FieldW, SwapCR4 }, + { Illegal }, + { Illegal }, + { Illegal } + }, { //13 + { Complete, FieldA, D0copyA }, + { Complete, FieldA, D1copyA }, + { Complete, FieldA, SwapAD0 }, + { Complete, FieldA, SwapAD1 }, + { Complete, FieldA, D0copyC }, + { Complete, FieldA, D1copyC }, + { Complete, FieldA, SwapCD0 }, + { Complete, FieldA, SwapCD1 }, + { Complete, FieldS, D0copyAShort }, + { Complete, FieldS, D1copyAShort }, + { Complete, FieldS, SwapAD0Short }, + { Complete, FieldS, SwapAD1Short }, + { Complete, FieldS, D0copyCShort }, + { Complete, FieldS, D1copyCShort }, + { Complete, FieldS, SwapCD0Short }, + { Complete, FieldS, SwapCD1Short } + }, { //14 + { Complete, FieldA, D0storeA }, + { Complete, FieldA, D1storeA }, + { Complete, FieldA, AloadD0 }, + { Complete, FieldA, AloadD1 }, + { Complete, FieldA, D0storeC }, + { Complete, FieldA, D1storeC }, + { Complete, FieldA, CloadD0 }, + { Complete, FieldA, CloadD1 }, + { Complete, FieldB, D0storeA }, + { Complete, FieldB, D1storeA }, + { Complete, FieldB, AloadD0 }, + { Complete, FieldB, AloadD1 }, + { Complete, FieldB, D0storeC }, + { Complete, FieldB, D1storeC }, + { Complete, FieldB, CloadD0 }, + { Complete, FieldB, CloadD1 } + }, { //15 + { Complete, AdrA, D0storeA }, + { Complete, AdrA, D1storeA }, + { Complete, AdrA, AloadD0 }, + { Complete, AdrA, AloadD1 }, + { Complete, AdrA, D0storeC }, + { Complete, AdrA, D1storeC }, + { Complete, AdrA, CloadD0 }, + { Complete, AdrA, CloadD1 }, + { Complete, AdrCount, D0storeA }, + { Complete, AdrCount, D1storeA }, + { Complete, AdrCount, AloadD0 }, + { Complete, AdrCount, AloadD1 }, + { Complete, AdrCount, D0storeC }, + { Complete, AdrCount, D1storeC }, + { Complete, AdrCount, CloadD0 }, + { Complete, AdrCount, CloadD1 }, + }, { //8 + { Opcode80 }, + { Opcode81 }, + { Complete, Imm, clearHST }, + { Complete, TestBranchRet, branchHSTclear }, + { Complete, Imm, clearBitST }, + { Complete, Imm, setBitST }, + { Complete, TestBranchRet, branchSTclear }, + { Complete, TestBranchRet, branchSTset }, + { Complete, TestBranchRet, branchPdiffers}, + { Complete, TestBranchRet, branchPequals}, + { Opcode8A }, + { Opcode8B }, + { Complete, Dis4, jump4 }, + { Complete, Abs, jump }, + { Complete, Dis4Call, call4 }, + { Complete, Abs, call } + }, { //80 + { Complete, AdrNone, outCS }, + { Complete, AdrNone, outC }, + { Complete, AdrNone, inA }, + { Complete, AdrNone, inC }, + { Complete, AdrNone, unconfig }, + { Complete, AdrNone, config }, + { Complete, AdrNone, Cid }, + { Complete, AdrNone, shutdown }, + { Opcode808 }, + { Complete, AdrNone, cp1 }, + { Complete, AdrNone, reset }, + { Complete, AdrNone, buscc }, + { Complete, Imm, CcopyP }, + { Complete, Imm, PcopyC }, + { Complete, AdrNone, sreq }, + { Complete, Imm, CswapP } + }, { //808 + { Complete, AdrNone, inton }, + { Opcode8081 }, + { Complete, ImmCload, AloadImm }, + { Complete, AdrNone, buscb }, + { Complete, Imm, clearAbit }, + { Complete, Imm, setAbit }, + { Complete, TestBranchRet, branchAbitclear }, + { Complete, TestBranchRet, branchAbitset }, + { Complete, Imm, clearCbit }, + { Complete, Imm, setCbit }, + { Complete, TestBranchRet, branchCbitclear }, + { Complete, TestBranchRet, branchCbitset }, + { Complete, AdrNone, PCloadA }, + { Complete, AdrNone, buscd }, + { Complete, AdrNone, PCloadC }, + { Complete, AdrNone, intoff } + }, { //8081 + { Complete, AdrNone, rsi }, + //! rest illegal + }, { //81 + { Complete, FieldW, AshiftleftCarry }, + { Complete, FieldW, BshiftleftCarry }, + { Complete, FieldW, CshiftleftCarry }, + { Complete, FieldW, DshiftleftCarry }, + { Complete, FieldW, AshiftrightCarry }, + { Complete, FieldW, BshiftrightCarry }, + { Complete, FieldW, CshiftrightCarry }, + { Complete, FieldW, DshiftrightCarry }, + { Opcode818 }, + { Opcode819 }, + { Opcode81A }, + { Opcode81B }, + { Complete, FieldW, Ashiftrightbit }, + { Complete, FieldW, Bshiftrightbit }, + { Complete, FieldW, Cshiftrightbit }, + { Complete, FieldW, Dshiftrightbit } + }, { //818 + { Opcode818a, AdrAF }, + { Opcode818a, AdrAF }, + { Opcode818a, AdrAF }, + { Opcode818a, AdrAF }, + { Opcode818a, AdrAF }, + { Opcode818a, AdrAF }, + { Opcode818a, AdrAF }, + { Opcode818a, AdrAF }, + { Illegal }, + { Illegal }, + { Illegal }, + { Illegal }, + { Illegal }, + { Illegal }, + { Illegal }, + { Opcode818a, AdrAF }, + }, { //818a + { Complete, AdrImmCount, AaddImm }, + { Complete, AdrImmCount, BaddImm }, + { Complete, AdrImmCount, CaddImm }, + { Complete, AdrImmCount, DaddImm }, + { Illegal }, + { Illegal }, + { Illegal }, + { Illegal }, + { Complete, AdrImmCount, AsubImm }, + { Complete, AdrImmCount, BsubImm }, + { Complete, AdrImmCount, CsubImm }, + { Complete, AdrImmCount, DsubImm }, + { Illegal }, + { Illegal }, + { Illegal }, + { Illegal }, + }, { //819 + { Opcode819a, AdrAF }, + { Opcode819a, AdrAF }, + { Opcode819a, AdrAF }, + { Opcode819a, AdrAF }, + { Opcode819a, AdrAF }, + { Opcode819a, AdrAF }, + { Opcode819a, AdrAF }, + { Opcode819a, AdrAF }, //? + { Illegal }, + { Illegal }, + { Illegal }, + { Illegal }, + { Illegal }, + { Illegal }, + { Illegal }, + { Opcode819a, AdrAF }, + }, { //819a } + { Complete, AdrNone, Ashiftright }, + { Complete, AdrNone, Bshiftright }, + { Complete, AdrNone, Cshiftright }, + { Complete, AdrNone, Dshiftright }, + //! rest illegal + }, { //81A + { Opcode81Aa, AdrAF }, + { Opcode81Aa, AdrAF }, + { Opcode81Aa, AdrAF }, + { Opcode81Aa, AdrAF }, + { Opcode81Aa, AdrAF }, + { Opcode81Aa, AdrAF }, + { Opcode81Aa, AdrAF }, + { Opcode81Aa, AdrAF }, + { Illegal }, + { Illegal }, + { Illegal }, + { Illegal }, + { Illegal }, + { Illegal }, + { Illegal }, + { Opcode81Aa, AdrAF }, + }, { //81Aa + { Opcode81Aa0 }, + { Opcode81Aa1 }, + { Opcode81Aa2 }, + //! rest illegal + }, { //81Aa0 + { Complete, AdrNone, R0copyA }, + { Complete, AdrNone, R1copyA }, + { Complete, AdrNone, R2copyA }, + { Complete, AdrNone, R3copyA }, + { Complete, AdrNone, R4copyA }, + { Illegal }, + { Illegal }, + { Illegal }, + { Complete, AdrNone, R0copyC }, + { Complete, AdrNone, R1copyC }, + { Complete, AdrNone, R2copyC }, + { Complete, AdrNone, R3copyC }, + { Complete, AdrNone, R4copyC }, + { Illegal }, + { Illegal }, + { Illegal } + }, { //81Aa1 + { Complete, AdrNone, AcopyR0 }, + { Complete, AdrNone, AcopyR1 }, + { Complete, AdrNone, AcopyR2 }, + { Complete, AdrNone, AcopyR3 }, + { Complete, AdrNone, AcopyR4 }, + { Illegal }, + { Illegal }, + { Illegal }, + { Complete, AdrNone, CcopyR0 }, + { Complete, AdrNone, CcopyR1 }, + { Complete, AdrNone, CcopyR2 }, + { Complete, AdrNone, CcopyR3 }, + { Complete, AdrNone, CcopyR4 }, + { Illegal }, + { Illegal }, + { Illegal } + }, { //81Aa2 + { Complete, AdrNone, SwapAR0 }, + { Complete, AdrNone, SwapAR1 }, + { Complete, AdrNone, SwapAR2 }, + { Complete, AdrNone, SwapAR3 }, + { Complete, AdrNone, SwapAR4 }, + { Illegal }, + { Illegal }, + { Illegal }, + { Complete, AdrNone, SwapCR0 }, + { Complete, AdrNone, SwapCR1 }, + { Complete, AdrNone, SwapCR2 }, + { Complete, AdrNone, SwapCR3 }, + { Complete, AdrNone, SwapCR4 }, + { Illegal }, + { Illegal }, + { Illegal } + }, { //81B + { Illegal }, + { Illegal }, + { Complete, AdrNone, jumpA }, + { Complete, AdrNone, jumpC }, + { Complete, AdrNone, PCcopyA }, + { Complete, AdrNone, PCcopyC }, + { Complete, AdrNone, AcopyPC }, + { Complete, AdrNone, CcopyPC }, + { Illegal }, + { Illegal }, + { Illegal }, + { Illegal }, + { Illegal }, + { Illegal }, + { Illegal }, + { Illegal } + }, { //8A + { Complete, ABranchReturn, branchAequalsB }, + { Complete, ABranchReturn, branchBequalsC }, + { Complete, ABranchReturn, branchAequalsC }, + { Complete, ABranchReturn, branchCequalsD }, + { Complete, ABranchReturn, branchAdiffersB }, + { Complete, ABranchReturn, branchBdiffersC }, + { Complete, ABranchReturn, branchAdiffersC }, + { Complete, ABranchReturn, branchCdiffersD }, + { Complete, ABranchReturn, branchAzero }, + { Complete, ABranchReturn, branchBzero }, + { Complete, ABranchReturn, branchCzero }, + { Complete, ABranchReturn, branchDzero }, + { Complete, ABranchReturn, branchAnotzero }, + { Complete, ABranchReturn, branchBnotzero }, + { Complete, ABranchReturn, branchCnotzero }, + { Complete, ABranchReturn, branchDnotzero } + }, { //8B + { Complete, ABranchReturn, branchAgreaterB }, + { Complete, ABranchReturn, branchBgreaterC }, + { Complete, ABranchReturn, branchCgreaterA }, + { Complete, ABranchReturn, branchDgreaterC }, + { Complete, ABranchReturn, branchAlowerB }, + { Complete, ABranchReturn, branchBlowerC }, + { Complete, ABranchReturn, branchClowerA }, + { Complete, ABranchReturn, branchDlowerC }, + { Complete, ABranchReturn, branchAnotlowerB }, + { Complete, ABranchReturn, branchBnotlowerC }, + { Complete, ABranchReturn, branchCnotlowerA }, + { Complete, ABranchReturn, branchDnotlowerC }, + { Complete, ABranchReturn, branchAnotgreaterB }, + { Complete, ABranchReturn, branchBnotgreaterC }, + { Complete, ABranchReturn, branchCnotgreaterA }, + { Complete, ABranchReturn, branchDnotgreaterC } + }, { //9 + { Opcode9a, AdrA }, + { Opcode9a, AdrA }, + { Opcode9a, AdrA }, + { Opcode9a, AdrA }, + { Opcode9a, AdrA }, + { Opcode9a, AdrA }, + { Opcode9a, AdrA }, + { Opcode9a, AdrA }, + { Opcode9b, AdrB }, + { Opcode9b, AdrB }, + { Opcode9b, AdrB }, + { Opcode9b, AdrB }, + { Opcode9b, AdrB }, + { Opcode9b, AdrB }, + { Opcode9b, AdrB }, + { Opcode9b, AdrB }, + }, { //9a + { Complete, xBranchReturn, branchAequalsB }, + { Complete, xBranchReturn, branchBequalsC }, + { Complete, xBranchReturn, branchAequalsC }, + { Complete, xBranchReturn, branchCequalsD }, + { Complete, xBranchReturn, branchAdiffersB }, + { Complete, xBranchReturn, branchBdiffersC }, + { Complete, xBranchReturn, branchAdiffersC }, + { Complete, xBranchReturn, branchCdiffersD }, + { Complete, xBranchReturn, branchAzero }, + { Complete, xBranchReturn, branchBzero }, + { Complete, xBranchReturn, branchCzero }, + { Complete, xBranchReturn, branchDzero }, + { Complete, xBranchReturn, branchAnotzero }, + { Complete, xBranchReturn, branchBnotzero }, + { Complete, xBranchReturn, branchCnotzero }, + { Complete, xBranchReturn, branchDnotzero } + }, { //9b + { Complete, xBranchReturn, branchAgreaterB }, + { Complete, xBranchReturn, branchBgreaterC }, + { Complete, xBranchReturn, branchCgreaterA }, + { Complete, xBranchReturn, branchDgreaterC }, + { Complete, xBranchReturn, branchAlowerB }, + { Complete, xBranchReturn, branchBlowerC }, + { Complete, xBranchReturn, branchClowerA }, + { Complete, xBranchReturn, branchDlowerC }, + { Complete, xBranchReturn, branchAnotlowerB }, + { Complete, xBranchReturn, branchBnotlowerC }, + { Complete, xBranchReturn, branchCnotlowerA }, + { Complete, xBranchReturn, branchDnotlowerC }, + { Complete, xBranchReturn, branchAnotgreaterB }, + { Complete, xBranchReturn, branchBnotgreaterC }, + { Complete, xBranchReturn, branchCnotgreaterA }, + { Complete, xBranchReturn, branchDnotgreaterC } + }, { //A + { OpcodeAa, AdrA }, + { OpcodeAa, AdrA }, + { OpcodeAa, AdrA }, + { OpcodeAa, AdrA }, + { OpcodeAa, AdrA }, + { OpcodeAa, AdrA }, + { OpcodeAa, AdrA }, + { OpcodeAa, AdrA }, + { OpcodeAb, AdrB }, + { OpcodeAb, AdrB }, + { OpcodeAb, AdrB }, + { OpcodeAb, AdrB }, + { OpcodeAb, AdrB }, + { OpcodeAb, AdrB }, + { OpcodeAb, AdrB }, + { OpcodeAb, AdrB }, + }, { //Aa + { Complete, AdrNone, AaddB }, + { Complete, AdrNone, BaddC }, + { Complete, AdrNone, CaddA }, + { Complete, AdrNone, DaddC }, + { Complete, AdrNone, AaddA }, + { Complete, AdrNone, BaddB }, + { Complete, AdrNone, CaddC }, + { Complete, AdrNone, DaddD }, + { Complete, AdrNone, BaddA }, + { Complete, AdrNone, CaddB }, + { Complete, AdrNone, AaddC }, + { Complete, AdrNone, CaddD }, + { Complete, AdrNone, decA }, + { Complete, AdrNone, decB }, + { Complete, AdrNone, decC }, + { Complete, AdrNone, decD }, + }, { //Ab + { Complete, AdrNone, clearA }, + { Complete, AdrNone, clearB }, + { Complete, AdrNone, clearC }, + { Complete, AdrNone, clearD }, + { Complete, AdrNone, AcopyB }, + { Complete, AdrNone, BcopyC }, + { Complete, AdrNone, CcopyA }, + { Complete, AdrNone, DcopyC }, + { Complete, AdrNone, BcopyA }, + { Complete, AdrNone, CcopyB }, + { Complete, AdrNone, AcopyC }, + { Complete, AdrNone, CcopyD }, + { Complete, AdrNone, AswapB }, + { Complete, AdrNone, BswapC }, + { Complete, AdrNone, CswapA }, + { Complete, AdrNone, DswapC } + }, { //B + { OpcodeBa, AdrA }, + { OpcodeBa, AdrA }, + { OpcodeBa, AdrA }, + { OpcodeBa, AdrA }, + { OpcodeBa, AdrA }, + { OpcodeBa, AdrA }, + { OpcodeBa, AdrA }, + { OpcodeBa, AdrA }, + { OpcodeBb, AdrB }, + { OpcodeBb, AdrB }, + { OpcodeBb, AdrB }, + { OpcodeBb, AdrB }, + { OpcodeBb, AdrB }, + { OpcodeBb, AdrB }, + { OpcodeBb, AdrB }, + { OpcodeBb, AdrB }, + }, { //Ba + { Complete, AdrNone, AsubB }, + { Complete, AdrNone, BsubC }, + { Complete, AdrNone, CsubA }, + { Complete, AdrNone, DsubC }, + { Complete, AdrNone, incA }, + { Complete, AdrNone, incB }, + { Complete, AdrNone, incC }, + { Complete, AdrNone, incD }, + { Complete, AdrNone, BsubA }, + { Complete, AdrNone, CsubB }, + { Complete, AdrNone, AsubC }, + { Complete, AdrNone, CsubD }, + { Complete, AdrNone, AsubnB }, + { Complete, AdrNone, BsubnC }, + { Complete, AdrNone, CsubnA }, + { Complete, AdrNone, DsubnC }, + }, { //Bb + { Complete, AdrNone, Ashiftleft }, + { Complete, AdrNone, Bshiftleft }, + { Complete, AdrNone, Cshiftleft }, + { Complete, AdrNone, Dshiftleft }, + { Complete, AdrNone, Ashiftright }, + { Complete, AdrNone, Bshiftright }, + { Complete, AdrNone, Cshiftright }, + { Complete, AdrNone, Dshiftright }, + { Complete, AdrNone, negateA }, + { Complete, AdrNone, negateB }, + { Complete, AdrNone, negateC }, + { Complete, AdrNone, negateD }, + { Complete, AdrNone, notA }, + { Complete, AdrNone, notB }, + { Complete, AdrNone, notC }, + { Complete, AdrNone, notD } + }, { //C + { Complete, FieldA, AaddB }, + { Complete, FieldA, BaddC }, + { Complete, FieldA, CaddA }, + { Complete, FieldA, DaddC }, + { Complete, FieldA, AaddA }, + { Complete, FieldA, BaddB }, + { Complete, FieldA, CaddC }, + { Complete, FieldA, DaddD }, + { Complete, FieldA, BaddA }, + { Complete, FieldA, CaddB }, + { Complete, FieldA, AaddC }, + { Complete, FieldA, CaddD }, + { Complete, FieldA, decA }, + { Complete, FieldA, decB }, + { Complete, FieldA, decC }, + { Complete, FieldA, decD } + }, { //D + { Complete, FieldA, clearA }, + { Complete, FieldA, clearB }, + { Complete, FieldA, clearC }, + { Complete, FieldA, clearD }, + { Complete, FieldA, AcopyB }, + { Complete, FieldA, BcopyC }, + { Complete, FieldA, CcopyA }, + { Complete, FieldA, DcopyC }, + { Complete, FieldA, BcopyA }, + { Complete, FieldA, CcopyB }, + { Complete, FieldA, AcopyC }, + { Complete, FieldA, CcopyD }, + { Complete, FieldA, AswapB }, + { Complete, FieldA, BswapC }, + { Complete, FieldA, CswapA }, + { Complete, FieldA, DswapC } + }, { //E + { Complete, FieldA, AsubB }, + { Complete, FieldA, BsubC }, + { Complete, FieldA, CsubA }, + { Complete, FieldA, DsubC }, + { Complete, FieldA, incA }, + { Complete, FieldA, incB }, + { Complete, FieldA, incC }, + { Complete, FieldA, incD }, + { Complete, FieldA, BsubA }, + { Complete, FieldA, CsubB }, + { Complete, FieldA, AsubC }, + { Complete, FieldA, CsubD }, + { Complete, FieldA, AsubnB }, + { Complete, FieldA, BsubnC }, + { Complete, FieldA, CsubnA }, + { Complete, FieldA, DsubnC } + }, { //F + { Complete, FieldA, Ashiftleft }, + { Complete, FieldA, Bshiftleft }, + { Complete, FieldA, Cshiftleft }, + { Complete, FieldA, Dshiftleft }, + { Complete, FieldA, Ashiftright }, + { Complete, FieldA, Bshiftright }, + { Complete, FieldA, Cshiftright }, + { Complete, FieldA, Dshiftright }, + { Complete, FieldA, negateA }, + { Complete, FieldA, negateB }, + { Complete, FieldA, negateC }, + { Complete, FieldA, negateD }, + { Complete, FieldA, notA }, + { Complete, FieldA, notB }, + { Complete, FieldA, notC }, + { Complete, FieldA, notD } + } +}; + +static const int field_adr_af[]= +{ FieldP, FieldWP, FieldXS, FieldX, FieldS, FieldM, FieldB, FieldW, 0, 0, 0, 0, 0, 0, 0, FieldA }; + +static const int field_adr_a[]= +{ FieldP, FieldWP, FieldXS, FieldX, FieldS, FieldM, FieldB, FieldW}; + +static const int field_adr_b[]= +{ FieldP, FieldWP, FieldXS, FieldX, FieldS, FieldM, FieldB, FieldW }; + +CPU_DISASSEMBLE( saturn ) +{ + int adr=0; + + int cont=1; // operation still not complete disassembled + char bin[10]; int binsize=0; // protocollizing fetched nibbles + char number[17]; + const OPCODE *level=opcodes[0]; //pointer to current digit + int op; // currently fetched nibble + int pos = 0; + + int i,c,v; + + while (cont) + { + op = oprom[pos++] & 0xf; + level+=op; + switch (level->sel) { + case Illegal: + cont=0; + bin[binsize++]=number_2_hex[op]; + bin[binsize]=0; + sprintf(buffer, "???%s",bin); + break; + default: + bin[binsize++]=number_2_hex[op]; + switch (level->adr) { + case AdrNone: break; + case AdrA: + adr=field_adr_a[op]; + break; + case AdrAF: + adr=field_adr_af[op]; + break; + case AdrB: + adr=field_adr_b[op&7]; + break; + default: + cont = 0; + bin[binsize++]=number_2_hex[op]; + bin[binsize]=0; + sprintf(buffer, "???%s",bin); + break; + } + break; + case Complete: + cont=0; + switch (level->adr==AdrNone?adr:level->adr) { + case AdrNone: + strcpy(buffer, mnemonics[level->mnemonic].name[set]); + break; + case Imm: + sprintf(buffer, mnemonics[level->mnemonic].name[set], oprom[pos++]); + break; + case ImmCount: + sprintf(buffer, mnemonics[level->mnemonic].name[set], oprom[pos++]+1); + break; + case AdrImmCount: + sprintf(buffer, mnemonics[level->mnemonic].name[set], field_2_string(adr), oprom[pos++]+1); + break; + case AdrCount: // mnemonics have string %s for address field + snprintf(number,sizeof(number),"%x",oprom[pos++]+1); + sprintf(buffer, mnemonics[level->mnemonic].name[set], number); + break; + case Imm2: + v=oprom[pos++]; + v|=oprom[pos++]<<4; + sprintf(buffer, mnemonics[level->mnemonic].name[set], v); + break; + case Imm4: + v=oprom[pos++]; + v|=oprom[pos++]<<4; + v|=oprom[pos++]<<8; + v|=oprom[pos++]<<12; + sprintf(buffer, mnemonics[level->mnemonic].name[set], v); + break; + case Imm5: + v=oprom[pos++]; + v|=oprom[pos++]<<4; + v|=oprom[pos++]<<8; + v|=oprom[pos++]<<12; + v|=oprom[pos++]<<16; + sprintf(buffer, mnemonics[level->mnemonic].name[set], v); + break; + case ImmCload: + c=i=oprom[pos++] & 0xf; + number[i+1]=0; + for (;i>=0; i--) number[i]=number_2_hex[oprom[pos++] & 0xf]; + sprintf(buffer, mnemonics[level->mnemonic].name[set], c+1, number); + break; + case Dis3: + SATURN_PEEKOP_DIS12(v); + c=(pc+pos-3+v)&0xfffff; + sprintf(buffer, mnemonics[level->mnemonic].name[set], c ); + break; + case Dis3Call: + SATURN_PEEKOP_DIS12(v); + c=(pc+pos+v)&0xfffff; + sprintf(buffer, mnemonics[level->mnemonic].name[set], c ); + break; + case Dis4: + SATURN_PEEKOP_DIS16(v); + c=(pc+pos-4+v)&0xfffff; + sprintf(buffer, mnemonics[level->mnemonic].name[set], c ); + break; + case Dis4Call: + SATURN_PEEKOP_DIS16(v); + c=(pc+pos+v)&0xfffff; + sprintf(buffer, mnemonics[level->mnemonic].name[set], c ); + break; + case Abs: + SATURN_PEEKOP_ADR(v); + sprintf(buffer, mnemonics[level->mnemonic].name[set], v ); + break; + case BranchReturn: + SATURN_PEEKOP_DIS8(v); + if (v==0) { + strcpy(buffer, mnemonics[level->mnemonic+1].name[set]); + } else { + c=(pc+pos-2+v)&0xfffff; + sprintf(buffer, mnemonics[level->mnemonic].name[set], c); + } + break; + case ABranchReturn: + SATURN_PEEKOP_DIS8(v); + if (v==0) { + sprintf(buffer, mnemonics[level->mnemonic+1].name[set], A); + } else { + c=(pc+pos-2+v)&0xfffff; + sprintf(buffer, mnemonics[level->mnemonic].name[set], A, c); + } + break; + case xBranchReturn: + SATURN_PEEKOP_DIS8(v); + if (v==0) { + sprintf(buffer, mnemonics[level->mnemonic+1].name[set], field_2_string(adr)); + } else { + c=(pc+pos-2+v)&0xfffff; + sprintf(buffer, mnemonics[level->mnemonic].name[set], field_2_string(adr), c); + } + break; + case TestBranchRet: + i=oprom[pos++]; + SATURN_PEEKOP_DIS8(v); + if (v==0) { + sprintf(buffer, mnemonics[level->mnemonic+1].name[set], i); + } else { + c=(pc+pos-2+v)&0xfffff; + sprintf(buffer, mnemonics[level->mnemonic].name[set], i, c); + } + break; + case ImmBranch: + i=oprom[pos++]; + SATURN_PEEKOP_DIS8(v); + c=(pc+pos-2+v)&0xfffff; + sprintf(buffer, mnemonics[level->mnemonic].name[set], i, c); + break; + case FieldP: + sprintf(buffer, mnemonics[level->mnemonic].name[set], P ); + break; + case FieldWP: + sprintf(buffer, mnemonics[level->mnemonic].name[set], WP ); + break; + case FieldXS: + sprintf(buffer, mnemonics[level->mnemonic].name[set], XS ); + break; + case FieldX: + sprintf(buffer, mnemonics[level->mnemonic].name[set], X ); + break; + case FieldS: + sprintf(buffer, mnemonics[level->mnemonic].name[set], S ); + break; + case FieldM: + sprintf(buffer, mnemonics[level->mnemonic].name[set], M ); + break; + case FieldB: + sprintf(buffer, mnemonics[level->mnemonic].name[set], B ); + break; + case FieldA: + sprintf(buffer, mnemonics[level->mnemonic].name[set], A ); + break; + case FieldW: + sprintf(buffer, mnemonics[level->mnemonic].name[set], W ); + break; + case AdrA: + sprintf(buffer, mnemonics[level->mnemonic].name[set], adr_a[oprom[pos++] & 0x7] ); + break; + case AdrAF: + sprintf(buffer, mnemonics[level->mnemonic].name[set], adr_af[oprom[pos++] & 0xf] ); + break; + case AdrB: + sprintf(buffer, mnemonics[level->mnemonic].name[set], adr_b[oprom[pos++] & 0x7] ); + break; + } + break; + } + level = opcodes[level->sel]; + } + + return pos; +} diff --git a/src/devices/cpu/sc61860/readpc.c b/src/devices/cpu/sc61860/readpc.c new file mode 100644 index 00000000000..46afbbf8a3e --- /dev/null +++ b/src/devices/cpu/sc61860/readpc.c @@ -0,0 +1,196 @@ +// license:BSD-3-Clause +// copyright-holders:Peter Trauner +#if 0 +#include +#include +#include +#include +#include +#endif +#include +#include + +// gcc -O +// important because of inb, outb + +/* + dumps data sent form sharp pc1401 into file + at sharp the following program must be started after + this dos program was started + simple dos utility + first arg (filename of file to be written) must be specified + + ct eprop needed + changing to parallel port should be easy + +nearly all sharp pocket pc's system roms should be readable +this way. + +for some early pocket pc's it would be necessary to load +this program into memory. +(they don't have poke/peek/call instructions, +so this program can't be typed in) + +adapter sharp - cteprommer + +1 +2 6v +3 gnd 8 bit textool gnd pin 20 +4 f0 data--> 8 bit textool data 0 pin 17 +5 f1 handshake --> 8 bit textool data 1 pin 18 +6 save +7 load +8 ib7 <--handshake 8 bit textool address 0 pin 16 +9 ib9 +10 +11 + +problems with the handshake in at the sharp +so I didn't use the handshake in the sharp side +but the pc side must not be interrupted with interrupt +(pure dos needed?) + +*/ + + +#define outb(v,adr) outportb(adr,v) +#define inb(adr) inportb(adr) + +#if 0 + /* this routine dump the memory (start 0) + in an endless loop, + the pc side must be started before this + actual version should be in mess/machine/pocketc.c + */ + +1 restore: for i=16384 to 16455:read a: poke i,a: next i +10 call 16384 +100 data +#if 1 + 18,4,//lip xl + 2,0,//lia 0 startaddress low + 219,//exam + 18,5,//lip xh + 2,0,//lia 0 startaddress high + 219,//exam +//400f x: + // dump internal rom + 18,5,//lip 4 + 89,//ldm + 218,//exab + 18,4,//lip 5 + 89,//ldm + 4,//ix for increasing x + 0,0,//lii,0 + 18,20,//lip 20 + 53, // + 18,20,// lip 20 + 219,//exam +#else + 18,4,//lip xl + 2,255,//lia 0 + 219,//exam + 18,5,//lip xh + 2,255,//lia 0 + 219,//exam +//400f x: + // dump external memory + 4, //ix + 87,// ldd +#endif + 218,//exab + + + + 0,4,//lii 4 + + //a: + 218,// exab + 90,// sl + 218,// exab + 18,94,// lip 94 + 96,252,// anma 252 + 2,2, //lia 2 + 196,// adcm + 95,// outf + //b: + 204,//inb + 102,128,//tsia 0x80 +#if 0 + 41,4,// jnzm b +#else + // input not working reliable! + // so handshake removed, PC side must run with disabled + // interrupt to not lose data + 78,20, //wait 20 +#endif + + 218,// exab + 90,// sl + 218,// exab + 18,94,// lip 94 + 96,252,//anma 252 + 2,0,// lia 0 + 196,//adcm + 95,// outf + //c: + 204,//inb + 102,128,//tsia 0x80 +#if 0 + 57,4,// jzm c +#else + 78,20, //wait 20 +#endif + + 65,//deci + 41,34,//jnzm a + + 41,41,//jnzm x: + + 55,// rtn +// fill up with several 55 +// so you don't have to calculate the exact end in the loop +#endif + +#define PORT_BASE 0x3e0 + +int main(int argc, char *argv[]) +{ + unsigned i,v,j,a; + char buffer[32768]; + FILE *out=fopen(argv[1],"wb"); + +#if 0 + ioperm(PORT_BASE,8,1); + nice(-256); +#endif + asm { cli } + + outb(0x18,PORT_BASE+3); // VCC ON + outb(0xc0, PORT_BASE+2); + outb(7,PORT_BASE+6); // VPP 12.5, reset off + + outb(0,PORT_BASE); + for(j=0;j<0x8000;j++) { + for (i=0,v=0;i<4;i++) { + for(;((a=inb(PORT_BASE+4))&2)==0; ) ; + v=(v<<1)|(a&1); + outb(1,PORT_BASE); + for(;((a=inb(PORT_BASE+4))&2)!=0; ) ; + v=(v<<1)|(a&1); + outb(0,PORT_BASE); + } + buffer[j]=v; +// printf("%.2x\n",v); + } + asm { sti } + fwrite(buffer,2,0x4000,out); + fclose(out); + +#if 0 + outb(8,PORT_BASE+2); // led off + outb(0,PORT_BASE+3); //VCC off + outb(0,PORT_BASE+6); //VPP off +#endif + return 0; +} diff --git a/src/devices/cpu/sc61860/sc61860.c b/src/devices/cpu/sc61860/sc61860.c new file mode 100644 index 00000000000..a36c02a658a --- /dev/null +++ b/src/devices/cpu/sc61860/sc61860.c @@ -0,0 +1,253 @@ +// license:BSD-3-Clause +// copyright-holders:Peter Trauner +/***************************************************************************** + * + * sc61860.c + * portable sharp 61860 emulator interface + * (sharp pocket computers) + * + * Copyright Peter Trauner, all rights reserved. + * + * History of changes: + * 29.7.2001 Several changes listed below taken by Mario Konegger + * (konegger@itp.tu-graz.ac.at) + * Added 0x7f to set_reg, to prevent p,q,r, overflow. + * Changed 512ms timerinterval from 256 to 128, thus the + * duration of one period is 512ms. + * Extended execute procudure with HLT-mode of CPU. + *****************************************************************************/ + +#include "emu.h" +#include "debugger.h" + +#include "sc61860.h" + + +#define I 0 +#define J 1 +#define A 2 +#define B 3 +#define XL 4 +#define XH 5 +#define YL 6 +#define YH 7 +#define K 8 +#define L 9 +#define V 10 // some docus m +#define W 11 // some docus n +#define IA 92 +#define IB 93 +#define F0 94 +#define C 95 + + +#define VERBOSE 0 + +#define LOG(x) do { if (VERBOSE) logerror x; } while (0) + + +const device_type SC61860 = &device_creator; + + +sc61860_device::sc61860_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : cpu_device(mconfig, SC61860, "SC61860", tag, owner, clock, "sc61860", __FILE__) + , m_program_config("program", ENDIANNESS_BIG, 8, 16, 0) + , m_reset(*this) + , m_brk(*this) + , m_x(*this) + , m_ina(*this) + , m_outa(*this) + , m_inb(*this) + , m_outb(*this) + , m_outc(*this) +{ +} + + +offs_t sc61860_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( sc61860 ); + return CPU_DISASSEMBLE_NAME(sc61860)(this, buffer, pc, oprom, opram, options); +} + + +UINT8 *sc61860_device::internal_ram() +{ + return m_ram; +} + +TIMER_CALLBACK_MEMBER(sc61860_device::sc61860_2ms_tick) +{ + if (--m_timer.count == 0) + { + m_timer.count = 128; + m_timer.t512ms = !m_timer.t512ms; + } + m_timer.t2ms = !m_timer.t2ms; +} + +/*************************************************************** + * include the opcode macros, functions and tables + ***************************************************************/ +#include "scops.inc" +#include "sctable.inc" + +void sc61860_device::device_reset() +{ + m_timer.t2ms=0; + m_timer.t512ms=0; + m_timer.count=256; + m_pc=0; +} + +void sc61860_device::device_start() +{ + machine().scheduler().timer_pulse(attotime::from_hz(500), timer_expired_delegate( FUNC(sc61860_device::sc61860_2ms_tick), this)); + + m_program = &space(AS_PROGRAM); + m_direct = &m_program->direct(); + m_reset.resolve(); + m_brk.resolve(); + m_x.resolve(); + m_ina.resolve_safe(0); + m_outa.resolve_safe(); + m_inb.resolve_safe(0); + m_outb.resolve_safe(); + m_outc.resolve_safe(); + + m_p = 0; + m_q = 0; + m_r = 0; + m_c = 0; + m_d = 0; + m_h = 0; + m_oldpc = 0; + m_dp = 0; + m_carry = 0; + m_zero = 0; + m_pc = 0; + m_debugger_temp = 0; + memset( m_ram, 0, sizeof(m_ram) ); + + save_item(NAME(m_p)); + save_item(NAME(m_q)); + save_item(NAME(m_r)); + save_item(NAME(m_c)); + save_item(NAME(m_d)); + save_item(NAME(m_h)); + save_item(NAME(m_pc)); + save_item(NAME(m_dp)); + save_item(NAME(m_carry)); + save_item(NAME(m_zero)); + save_item(NAME(m_timer.t2ms)); + save_item(NAME(m_timer.t512ms)); + save_item(NAME(m_timer.count)); + save_item(NAME(m_ram)); + + state_add( SC61860_PC, "PC", m_pc ).formatstr("%04X"); + state_add( SC61860_DP, "DP", m_dp ).formatstr("%04X"); + state_add( SC61860_P, "P", m_p ).mask(0x7f).formatstr("%02X"); + state_add( SC61860_Q, "Q", m_q ).mask(0x7f).formatstr("%02X"); + state_add( SC61860_R, "R", m_r ).mask(0x7f).formatstr("%02X"); + state_add( SC61860_I, "I", m_ram[I] ).formatstr("%02X"); + state_add( SC61860_J, "J", m_ram[J] ).formatstr("%02X"); + state_add( SC61860_K, "K", m_ram[K] ).formatstr("%02X"); + state_add( SC61860_L, "L", m_ram[L] ).formatstr("%02X"); + state_add( SC61860_V, "V", m_ram[V] ).formatstr("%02X"); + state_add( SC61860_W, "Wx", m_ram[W] ).formatstr("%02X"); + state_add( SC61860_H, "W", m_h ).formatstr("%02X"); + state_add( SC61860_BA, "BA", m_debugger_temp ).callimport().callexport().formatstr("%04X"); + state_add( SC61860_X, "X", m_debugger_temp ).callimport().callexport().formatstr("%04X"); + state_add( SC61860_Y, "Y", m_debugger_temp ).callimport().callexport().formatstr("%04X"); + state_add( SC61860_CARRY, "Carry", m_carry ).mask(1).formatstr("%1u"); + state_add( SC61860_ZERO, "Zero" , m_zero ).mask(1).formatstr("%1u"); + + state_add(STATE_GENPC, "GENPC", m_pc).formatstr("%04X").noshow(); + state_add(STATE_GENFLAGS, "GENFLAGS", m_debugger_temp).formatstr("%2s").noshow(); + state_add(STATE_GENSP, "GENSP", m_r).mask(0x7f).formatstr("%02X").noshow(); + state_add(STATE_GENPCBASE, "GENPCBASE", m_oldpc).formatstr("%04X").noshow(); + + m_icountptr = &m_icount; +} + + +void sc61860_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + switch (entry.index()) + { + case STATE_GENFLAGS: + strprintf(str, "%c%c", m_zero ? 'Z' : '.', m_carry ? 'C' : '.'); + break; + } +} + + +void sc61860_device::state_import(const device_state_entry &entry) +{ + switch (entry.index()) + { + case SC61860_BA: + m_ram[A] = m_debugger_temp & 0xff; + m_ram[B] = ( m_debugger_temp >> 8 ) & 0xff; + break; + + case SC61860_X: + m_ram[XL] = m_debugger_temp & 0xff; + m_ram[XH] = ( m_debugger_temp >> 8 ) & 0xff; + break; + + case SC61860_Y: + m_ram[YL] = m_debugger_temp & 0xff; + m_ram[YH] = ( m_debugger_temp >> 8 ) & 0xff; + break; + } +} + + +void sc61860_device::state_export(const device_state_entry &entry) +{ + switch (entry.index()) + { + case SC61860_BA: + m_debugger_temp = ( m_ram[B] << 8 ) | m_ram[A]; + break; + + case SC61860_X: + m_debugger_temp = ( m_ram[XH] << 8 ) | m_ram[XL]; + break; + + case SC61860_Y: + m_debugger_temp = ( m_ram[YH] << 8 ) | m_ram[YL]; + break; + } +} + + +void sc61860_device::execute_run() +{ + do + { + m_oldpc = m_pc; + + debugger_instruction_hook(this, m_pc); + + sc61860_instruction(); + +#if 0 + /* Are we in HLT-mode? */ + if (m_c & 4) + { + if (((m_ina()!=0)) || m_timer.t512ms) + { + m_c&=0xfb; + m_outc(m_c); + } + m_icount-=4; + } + else if(m_c & 8) {} + + else sc61860_instruction(); +#endif + + } while (m_icount > 0); +} diff --git a/src/devices/cpu/sc61860/sc61860.h b/src/devices/cpu/sc61860/sc61860.h new file mode 100644 index 00000000000..e34197f83f9 --- /dev/null +++ b/src/devices/cpu/sc61860/sc61860.h @@ -0,0 +1,236 @@ +// license:BSD-3-Clause +// copyright-holders:Peter Trauner +/***************************************************************************** + * + * sc61860.h + * portable sharp 61860 emulator interface + * (sharp pocket computers) + * + * Copyright Peter Trauner, all rights reserved. + * + *****************************************************************************/ + +#pragma once + +#ifndef __SC61860_H__ +#define __SC61860_H__ + +/* + official names seam to be + ESR-H, ESR-J + (ESR-L SC62015 ist complete different) + */ + +/* unsolved problems + the processor has 8 kbyte internal rom + only readable with special instructions and program execution + 64 kb external ram (first 8kbyte not seen for program execution?) */ + + +enum +{ + SC61860_PC=1, SC61860_DP, + SC61860_P, SC61860_Q, SC61860_R, + SC61860_CARRY, + SC61860_ZERO, + // the following are in the internal ram! + SC61860_BA, + SC61860_X, SC61860_Y, + SC61860_I, SC61860_J, SC61860_K, SC61860_L, SC61860_V, SC61860_W, + SC61860_H + +// SC61860_NMI_STATE, +// SC61860_IRQ_STATE +}; + + +#define MCFG_SC61860_READ_RESET_HANDLER(_devcb) \ + devcb = &sc61860_device::set_reset_cb(*device, DEVCB_##_devcb); + +#define MCFG_SC61860_READ_BRK_HANDLER(_devcb) \ + devcb = &sc61860_device::set_brk_cb(*device, DEVCB_##_devcb); + +#define MCFG_SC61860_READ_X_HANDLER(_devcb) \ + devcb = &sc61860_device::set_x_cb(*device, DEVCB_##_devcb); + +#define MCFG_SC61860_READ_A_HANDLER(_devcb) \ + devcb = &sc61860_device::set_ina_cb(*device, DEVCB_##_devcb); + +#define MCFG_SC61860_WRITE_A_HANDLER(_devcb) \ + devcb = &sc61860_device::set_outa_cb(*device, DEVCB_##_devcb); + +#define MCFG_SC61860_READ_B_HANDLER(_devcb) \ + devcb = &sc61860_device::set_inb_cb(*device, DEVCB_##_devcb); + +#define MCFG_SC61860_WRITE_B_HANDLER(_devcb) \ + devcb = &sc61860_device::set_outb_cb(*device, DEVCB_##_devcb); + +#define MCFG_SC61860_WRITE_C_HANDLER(_devcb) \ + devcb = &sc61860_device::set_outc_cb(*device, DEVCB_##_devcb); + +class sc61860_device : public cpu_device +{ +public: + // construction/destruction + sc61860_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // static configuration helpers + template static devcb_base &set_reset_cb(device_t &device, _Object object) { return downcast(device).m_reset.set_callback(object); } + template static devcb_base &set_brk_cb(device_t &device, _Object object) { return downcast(device).m_brk.set_callback(object); } + template static devcb_base &set_x_cb(device_t &device, _Object object) { return downcast(device).m_x.set_callback(object); } + template static devcb_base &set_ina_cb(device_t &device, _Object object) { return downcast(device).m_ina.set_callback(object); } + template static devcb_base &set_outa_cb(device_t &device, _Object object) { return downcast(device).m_outa.set_callback(object); } + template static devcb_base &set_inb_cb(device_t &device, _Object object) { return downcast(device).m_inb.set_callback(object); } + template static devcb_base &set_outb_cb(device_t &device, _Object object) { return downcast(device).m_outb.set_callback(object); } + template static devcb_base &set_outc_cb(device_t &device, _Object object) { return downcast(device).m_outc.set_callback(object); } + + /* this is though for power on/off of the sharps */ + UINT8 *internal_ram(); + + TIMER_CALLBACK_MEMBER(sc61860_2ms_tick); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_execute_interface overrides + virtual UINT32 execute_min_cycles() const { return 2; } + virtual UINT32 execute_max_cycles() const { return 4; } + virtual UINT32 execute_input_lines() const { return 0; } + virtual void execute_run(); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const { return (spacenum == AS_PROGRAM) ? &m_program_config : NULL; } + + // device_state_interface overrides + virtual void state_import(const device_state_entry &entry); + virtual void state_export(const device_state_entry &entry); + void state_string_export(const device_state_entry &entry, std::string &str); + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const { return 1; } + virtual UINT32 disasm_max_opcode_bytes() const { return 4; } + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + +private: + address_space_config m_program_config; + + devcb_read_line m_reset; + devcb_read_line m_brk; + devcb_read_line m_x; + devcb_read8 m_ina; + devcb_write8 m_outa; + devcb_read8 m_inb; + devcb_write8 m_outb; + devcb_write8 m_outc; + + UINT8 m_p, m_q, m_r; //7 bits only? + + UINT8 m_c; // port c, used for HLT. + UINT8 m_d, m_h; + UINT16 m_oldpc, m_pc, m_dp; + + int m_carry, m_zero; + + struct { int t2ms, t512ms; int count; } m_timer; + + address_space *m_program; + direct_read_data *m_direct; + int m_icount; + UINT8 m_ram[0x100]; // internal special ram, should be 0x60, 0x100 to avoid memory corruption for now + + UINT32 m_debugger_temp; + + inline UINT8 READ_OP(); + inline UINT8 READ_OP_ARG(); + inline UINT16 READ_OP_ARG_WORD(); + inline UINT8 READ_BYTE(UINT16 adr); + inline void WRITE_BYTE(UINT16 a, UINT8 v); + inline UINT8 READ_RAM(int r); + inline void WRITE_RAM(int r, UINT8 v); + inline void PUSH(UINT8 v); + inline UINT8 POP(); + inline void sc61860_load_imm(int r, UINT8 v); + inline void sc61860_load(); + inline void sc61860_load_imm_p(UINT8 v); + inline void sc61860_load_imm_q(UINT8 v); + inline void sc61860_load_r(); + inline void sc61860_load_ext(int r); + inline void sc61860_load_dp(); + inline void sc61860_load_dl(); + inline void sc61860_store_p(); + inline void sc61860_store_q(); + inline void sc61860_store_r(); + inline void sc61860_store_ext(int r); + inline void sc61860_exam(int a, int b); + inline void sc61860_test(int reg, UINT8 value); + inline void sc61860_test_ext(); + inline void sc61860_and(int reg, UINT8 value); + inline void sc61860_and_ext(); + inline void sc61860_or(int reg, UINT8 value); + inline void sc61860_or_ext(); + inline void sc61860_rotate_right(); + inline void sc61860_rotate_left(); + inline void sc61860_swap(); + inline void sc61860_inc(int reg); + inline void sc61860_inc_p(); + inline void sc61860_dec(int reg); + inline void sc61860_dec_p(); + inline void sc61860_add(int reg, UINT8 value); + inline void sc61860_add_carry(); + inline void sc61860_add_word(); + inline void sc61860_sub(int reg, UINT8 value); + inline void sc61860_sub_carry(); + inline void sc61860_sub_word(); + inline void sc61860_cmp(int reg, UINT8 value); + inline void sc61860_pop(); + inline void sc61860_push(); + inline void sc61860_prepare_table_call(); + inline void sc61860_execute_table_call(); + inline void sc61860_call(UINT16 adr); + inline void sc61860_return(); + inline void sc61860_jump(int yes); + inline void sc61860_jump_rel_plus(int yes); + inline void sc61860_jump_rel_minus(int yes); + inline void sc61860_loop(); + inline void sc61860_leave(); + inline void sc61860_wait(); + inline void sc61860_set_carry(); + inline void sc61860_reset_carry(); + inline void sc61860_out_a(); + inline void sc61860_out_b(); + inline void sc61860_out_f(); + inline void sc61860_out_c(); + inline void sc61860_in_a(); + inline void sc61860_in_b(); + inline void sc61860_test_special(); + inline void sc61860_add_bcd_a(); + inline void sc61860_add_bcd(); + inline void sc61860_sub_bcd_a(); + inline void sc61860_sub_bcd(); + inline void sc61860_shift_left_nibble(); + inline void sc61860_shift_right_nibble(); + inline void sc61860_inc_load_dp(int reg); + inline void sc61860_dec_load_dp(int reg); + inline void sc61860_inc_load_dp_load(); + inline void sc61860_dec_load_dp_load(); + inline void sc61860_inc_load_dp_store(); + inline void sc61860_dec_load_dp_store(); + inline void sc61860_fill(); + inline void sc61860_fill_ext(); + inline void sc61860_copy(int count); + inline void sc61860_copy_ext(int count); + inline void sc61860_copy_int(int count); + inline void sc61860_exchange(int count); + inline void sc61860_exchange_ext(int count); + inline void sc61860_wait_x(int level); + void sc61860_instruction(); + +}; + + +extern const device_type SC61860; + + +#endif /* __SC61860_H__ */ diff --git a/src/devices/cpu/sc61860/scdasm.c b/src/devices/cpu/sc61860/scdasm.c new file mode 100644 index 00000000000..047ba7fae30 --- /dev/null +++ b/src/devices/cpu/sc61860/scdasm.c @@ -0,0 +1,210 @@ +// license:BSD-3-Clause +// copyright-holders:Peter Trauner +/***************************************************************************** + * + * scdasm.c + * portable sharp 61860 emulator interface + * (sharp pocket computers) + * + * Copyright Peter Trauner, all rights reserved. + * + *****************************************************************************/ + +#include "emu.h" +#include "debugger.h" + +#include "sc61860.h" + +/* + new: + clra 0x23 + nopt 0x33 + nopt 0x68 + nopt 0x6a + rz n 0x72, 0x73, 0x76, 0x77 + tsma 0xc6 + nopw 0xcd + nopw 0xd3 + sz n 0xd7 + nopw 0xda + +! writ 211 nopw? +*/ + +/* explanations for the sharp mnemonics + d data: external memory + m memory: internal memory (address in p register) + p register (internal memory address) + q register (internal memory address), internally used in several opcodes!? + r stack pointer (internal memory) + c carry flag + z zero flag + + the following are special internal memory registers + a akkumulator: (2) + b b register: (3) + i,j,k,l,v,w counter + x external memory address + y external memory address + ia input/output (92) + ib input/output (93) + f0 output (94) + c output(95) + + li load immediate + ld load accu + st store accu + or + an and + inc + dec + ad add + sb sub + cp compare + jr jump relativ + jp jump absolut + mv move + ex exchange +*/ + + +enum Adr +{ + Ill, + Imp, + Imm, ImmW, + RelP, RelM, + Abs, + Ptc, + Etc, + Cal, + Lp +}; + +static const struct { const char *mnemonic; Adr adr; } table[]={ + { "LII", Imm }, { "LIJ", Imm }, { "LIA", Imm }, { "LIB", Imm }, + { "IX", Imp }, { "DX", Imp }, { "IY", Imp }, { "DY", Imp }, + { "MVW", Imp }, { "EXW", Imp }, { "MVB", Imp }, { "EXB", Imp }, + { "ADN", Imp }, { "SBN", Imp }, { "ADW", Imp }, { "SBW", Imp }, + + { "LIDP", ImmW}, { "LIDL", Imm }, { "LIP", Imm }, { "LIQ", Imm }, + { "ADB", Imp }, { "SBB", Imp }, { "LIDP", ImmW}, { "LIDL", Imm }, + { "MVWD", Imp }, { "EXWD", Imp }, { "MVBD", Imp }, { "EXBD", Imp }, + { "SRW", Imp }, { "SLW", Imp }, { "FILM", Imp }, { "FILD", Imp }, + + { "LDP", Imp }, { "LPQ", Imp }, { "LPR", Imp }, { 0, Ill }, + { "IXL", Imp }, { "DXL", Imp }, { "IYS", Imp }, { "DYS", Imp }, + { "JRNZP", RelP}, { "JRNZM", RelM}, { "JRNCP", RelP}, { "JRNCM", RelM}, + { "JRP", RelP}, { "JRM", RelM}, { 0, Ill }, { "LOOP", RelM}, + + { "STP", Imp }, { "STQ", Imp }, { "STR", Imp }, { 0, Ill }, + { "PUSH", Imp }, { "DATA", Imp }, { 0, Ill }, { "RTN", Imp }, + { "JRZP", RelP}, { "JRZM", RelM}, { "JRCP", RelP}, { "JRCM", RelM}, + { 0, Ill }, { 0, Ill }, { 0, Ill }, { 0, Ill }, + + { "INCI", Imp }, { "DECI", Imp }, { "INCA", Imp }, { "DECA", Imp }, + { "ADM", Imp }, { "SBM", Imp }, { "ANMA", Imp }, { "ORMA", Imp }, + { "INCK", Imp }, { "DECK", Imp }, { "INCV", Imp }, { "DECV", Imp }, + { "INA", Imp }, { "NOPW", Imp }, { "WAIT", Imm }, { "IPXL"/*CDN, lxn*/, Imp }, + + { "INCP", Imp }, { "DECP", Imp }, { "STD", Imp }, { "MVDM", Imp }, + { "READM",/*mvmp*/ Imp }, { "MVMD", Imp }, { "READ"/*ldpc*/, Imp }, { "LDD", Imp }, + { "SWP", Imp }, { "LDM", Imp }, { "SL", Imp }, { "POP", Imp }, + { 0, Ill }, { "OUTA", Imp }, { 0, Ill }, { "OUTF", Imp }, + + { "ANIM", Imm }, { "ORIM", Imm }, { "TSIM", Imm }, { "CPIM", Imm }, + { "ANIA", Imm }, { "ORIA", Imm }, { "TSIA", Imm }, { "CPIA", Imm }, + { 0, Ill }, { "ETC", Etc }, { 0, Ill }, { "TEST", Imm }, + { 0, Ill }, { 0, Ill }, { 0, Ill }, { "IPXH"/*CDN,lxp*/, Imp }, + + { "ADIM", Imm }, { "SBIM", Imm }, { 0, Ill }, { 0, Ill }, + { "ADIA", Imm }, { "SBIA", Imm }, { 0, Ill }, { 0, Ill }, + { "CALL", Abs }, { "JP", Abs }, { "PTC", Ptc }, { 0, Ill }, + { "JPNZ", Abs }, { "JPNC", Abs }, { "JPZ", Abs }, { "JPC", Abs }, + + + { "LP", Lp }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, + { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, + + { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, + { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, + + { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, + { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, + + { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, + { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, + + { "INCJ", Imp }, { "DECJ", Imp }, { "INCB", Imp }, { "DECB", Imp }, + { "ACDM", Imp }, { "SBCM", Imp }, { 0, Ill }, { "CPMA", Imp }, + { "INCL", Imp }, { "DECL", Imp }, { "INCW", Imp }, { "DECW", Imp }, + { "INB", Imp }, { 0, Ill }, { "NOPT", Imp }, { 0, Ill }, + + { "SC", Imp }, { "RC", Imp }, { "SR", Imp }, { 0, Ill }, + { "ANID", Imm }, { "ORID", Imm }, { "TSID", Imm }, { 0, Ill }, + { "LEAVE", Imp }, { 0, Ill }, { "EXAB", Imp }, { "EXAM", Imp }, + { 0, Ill }, { "OUTB", Imp }, { 0, Ill }, { "OUTC", Imp }, + + { "CAL", Imp }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, + { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, + + { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, + { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, +}; + +CPU_DISASSEMBLE( sc61860 ) +{ + const UINT8 *base_oprom = oprom; + int oper=*(oprom++); + int t; + UINT16 adr; + + switch(oper&0xc0) { + case 0x80: + sprintf(buffer,"%-6s%.2x",table[oper&0x80].mnemonic, oper&0x3f); + break; + default: + switch(oper&0xe0) { + case 0xe0: + sprintf(buffer,"%-6s%.4x",table[oper&0xe0].mnemonic, + *(oprom++)|((oper&0x1f)<<8)); + break; + default: + switch (table[oper].adr) { + case Ill: sprintf(buffer,"?%.2x",oper);break; + case Imp: sprintf(buffer,"%s",table[oper].mnemonic); break; + case Imm: sprintf(buffer,"%-6s%.2x",table[oper].mnemonic, *(oprom++)); break; + case ImmW: + adr=(oprom[0]<<8)|oprom[1];oprom+=2; + sprintf(buffer,"%-6s%.4x",table[oper].mnemonic, adr); + break; + case Abs: + adr=(oprom[0]<<8)|oprom[1];oprom+=2; + sprintf(buffer,"%-6s%.4x",table[oper].mnemonic, adr); + break; + case RelM: + adr=pc-*(oprom++); + sprintf(buffer,"%-6s%.4x",table[oper].mnemonic, adr&0xffff); + break; + case RelP: + adr=pc+*(oprom++); + sprintf(buffer,"%-6s%.4x",table[oper].mnemonic, adr&0xffff); + break; + case Ptc: + t=*(oprom++); + adr=(oprom[0]<<8)|oprom[1];oprom+=2; + sprintf(buffer,"%-6s%.2x,%.4x",table[oper].mnemonic,t, adr); + break; + case Etc: + sprintf(buffer,"%-6s",table[oper].mnemonic); + /*H imm, abs */ + /* abs */ + break; + case Cal: case Lp: break; + } + break; + } + break; + } + return oprom - base_oprom; +} diff --git a/src/devices/cpu/sc61860/scops.inc b/src/devices/cpu/sc61860/scops.inc new file mode 100644 index 00000000000..7bc5b05c987 --- /dev/null +++ b/src/devices/cpu/sc61860/scops.inc @@ -0,0 +1,760 @@ +// license:BSD-3-Clause +// copyright-holders:Peter Trauner +/***************************************************************************** + * + * scops.inc + * portable sharp 61860 emulator interface + * (sharp pocket computers) + * + * Copyright Peter Trauner, all rights reserved. + * + * History of changes: + * 21.07.2001 Several changes listed below were made by Mario Konegger + * (konegger@itp.tu-graz.ac.at) + * replaced buggy BCD-commands add_bcd, sub_bcd, add_bcd_a, + * sub_bcd_a and changed out_c, to implement HLT-mode of the CPU. + * + *****************************************************************************/ + +UINT8 sc61860_device::READ_OP() +{ + return m_direct->read_byte(m_pc++); +} + +UINT8 sc61860_device::READ_OP_ARG() +{ + return m_direct->read_byte(m_pc++); +} + +UINT16 sc61860_device::READ_OP_ARG_WORD() +{ + UINT16 t=m_direct->read_byte(m_pc++)<<8; + t|=m_direct->read_byte(m_pc++); + return t; +} + +UINT8 sc61860_device::READ_BYTE(UINT16 adr) +{ + return m_program->read_byte(adr); +} + +void sc61860_device::WRITE_BYTE(UINT16 a, UINT8 v) +{ + m_program->write_byte(a, v); +} + +UINT8 sc61860_device::READ_RAM(int r) +{ + return m_ram[r]; +} + +void sc61860_device::WRITE_RAM(int r, UINT8 v) +{ + m_ram[r] = v; +} + +void sc61860_device::PUSH(UINT8 v) +{ + m_r--; + WRITE_RAM(m_r, v); +} + +UINT8 sc61860_device::POP() +{ + UINT8 t = READ_RAM(m_r); + m_r++; + return t; +} + +void sc61860_device::sc61860_load_imm(int r, UINT8 v) +{ + WRITE_RAM(r, v); +} + +void sc61860_device::sc61860_load() +{ + WRITE_RAM(A, READ_RAM(m_p)); +} + +void sc61860_device::sc61860_load_imm_p(UINT8 v) +{ + m_p=v&0x7f; +} + +void sc61860_device::sc61860_load_imm_q(UINT8 v) +{ + m_q=v&0x7f; +} + +void sc61860_device::sc61860_load_r() +{ + m_r = READ_RAM(A) & 0x7f; +} + +void sc61860_device::sc61860_load_ext(int r) +{ + WRITE_RAM(r, READ_BYTE(m_dp)); +} + +void sc61860_device::sc61860_load_dp() +{ + m_dp=READ_OP_ARG_WORD(); +} + +void sc61860_device::sc61860_load_dl() +{ + m_dp=(m_dp&~0xff)|READ_OP_ARG(); +} + +void sc61860_device::sc61860_store_p() +{ + WRITE_RAM(A, m_p); +} + +void sc61860_device::sc61860_store_q() +{ + WRITE_RAM(A, m_q); +} + +void sc61860_device::sc61860_store_r() +{ + WRITE_RAM(A, m_r); +} + +void sc61860_device::sc61860_store_ext(int r) +{ + WRITE_BYTE(m_dp, READ_RAM(r)); +} + +void sc61860_device::sc61860_exam(int a, int b) +{ + UINT8 t = READ_RAM(a); + WRITE_RAM(a, READ_RAM(b)); + WRITE_RAM(b, t); +} + +void sc61860_device::sc61860_test(int reg, UINT8 value) +{ + m_zero=(READ_RAM(reg) & value)==0; +} + +void sc61860_device::sc61860_test_ext() +{ + m_zero=(READ_BYTE(m_dp)&READ_OP_ARG())==0; +} + +void sc61860_device::sc61860_and(int reg, UINT8 value) +{ + UINT8 t = READ_RAM(reg) & value; + WRITE_RAM(reg, t); + m_zero=t==0; +} + +void sc61860_device::sc61860_and_ext() +{ + UINT8 t = READ_BYTE(m_dp) & READ_OP_ARG(); + m_zero=t==0; + WRITE_BYTE(m_dp, t); +} + +void sc61860_device::sc61860_or(int reg, UINT8 value) +{ + UINT8 t = READ_RAM(reg) | value; + WRITE_RAM(reg, t); + m_zero=t==0; +} + +void sc61860_device::sc61860_or_ext() +{ + UINT8 t=READ_BYTE(m_dp)|READ_OP_ARG(); + m_zero=t==0; + WRITE_BYTE(m_dp, t); +} + +void sc61860_device::sc61860_rotate_right() +{ + int t = READ_RAM(A); + if (m_carry) t|=0x100; + m_carry=t&1; + WRITE_RAM(A, t>>1); +} + +void sc61860_device::sc61860_rotate_left() +{ + int t = READ_RAM(A) << 1; + if (m_carry) t|=1; + m_carry=t&0x100; + WRITE_RAM(A, t); +} + +void sc61860_device::sc61860_swap() +{ + int t = READ_RAM(A); + WRITE_RAM(A, (t<<4)|((t>>4)&0xf)); +} + +// q=reg sideeffect +void sc61860_device::sc61860_inc(int reg) +{ + UINT8 t = READ_RAM(reg) + 1; + m_q=reg; + WRITE_RAM(reg, t); + m_zero=t==0; + m_carry=t==0; +} + +void sc61860_device::sc61860_inc_p() +{ + m_p++; +} + +// q=reg sideeffect +void sc61860_device::sc61860_dec(int reg) +{ + UINT8 t = READ_RAM(reg) - 1; + m_q=reg; + WRITE_RAM(reg, t); + m_zero=t==0; + m_carry=t==0xff; +} + +void sc61860_device::sc61860_dec_p() +{ + m_p--; +} + +void sc61860_device::sc61860_add(int reg, UINT8 value) +{ + int t = READ_RAM(reg) + value; + WRITE_RAM(reg, t); + m_zero=(t&0xff)==0; + m_carry=t>=0x100; +} + +void sc61860_device::sc61860_add_carry() +{ + int t = READ_RAM(m_p) + READ_RAM(A); + if (m_carry) t++; + WRITE_RAM(m_p, t); + m_zero=(t&0xff)==0; + m_carry=t>=0x100; +} + +// p++ sideeffect +void sc61860_device::sc61860_add_word() +{ + int t = READ_RAM(m_p) + READ_RAM(A), t2; + WRITE_RAM(m_p, t); + m_p++; + t2 = READ_RAM(m_p) + READ_RAM(B); + if (t>=0x100) t2++; + WRITE_RAM(m_p, t2); + m_zero=(t2&0xff)==0 &&(t&0xff)==0; + m_carry=t2>=0x100; +} + + +void sc61860_device::sc61860_sub(int reg, UINT8 value) +{ + int t = READ_RAM(reg) - value; + WRITE_RAM(reg, t); + m_zero=(t&0xff)==0; + m_carry=t<0; +} + +void sc61860_device::sc61860_sub_carry() +{ + int t = READ_RAM(m_p) - READ_RAM(A); + if (m_carry) t--; + WRITE_RAM(m_p, t); + m_zero=(t&0xff)==0; + m_carry=t<0; +} + + +// p++ sideeffect +void sc61860_device::sc61860_sub_word() +{ + int t = READ_RAM(m_p) - READ_RAM(A), t2; + WRITE_RAM(m_p, t); + m_p++; + t2 = READ_RAM(m_p) - READ_RAM(B); + if (t<0) t2--; + WRITE_RAM(m_p, t2); + m_zero=(t2&0xff)==0 && (t&0xff)==0; + m_carry=t2<0; +} + +void sc61860_device::sc61860_cmp(int reg, UINT8 value) +{ + int t = READ_RAM(reg) - value; + m_zero=t==0; + m_carry=t<0; +} + +void sc61860_device::sc61860_pop() +{ + WRITE_RAM(A, POP()); +} + +void sc61860_device::sc61860_push() +{ + PUSH(READ_RAM(A)); +} + +void sc61860_device::sc61860_prepare_table_call() +{ + int adr; + m_h=READ_OP(); + adr=READ_OP_ARG_WORD(); + PUSH(adr>>8); + PUSH(adr&0xff); +} + +void sc61860_device::sc61860_execute_table_call() +{ + int i, v, adr; + for (i=0; i>8); + PUSH(m_pc&0xff); + m_pc=adr; +} + +void sc61860_device::sc61860_return() +{ + UINT16 t=POP(); + t|=POP()<<8; + m_pc=t; +} + +void sc61860_device::sc61860_jump(int yes) +{ + UINT16 adr = READ_OP_ARG_WORD(); + if (yes) { + m_pc=adr; + } +} + +void sc61860_device::sc61860_jump_rel_plus(int yes) +{ + UINT16 adr = m_pc + READ_OP_ARG(); + if (yes) { + m_pc=adr; + m_icount-=3; + } +} + +void sc61860_device::sc61860_jump_rel_minus(int yes) +{ + UINT16 adr = m_pc - READ_OP_ARG(); + if (yes) { + m_pc=adr; + m_icount-=3; + } +} + +void sc61860_device::sc61860_loop() +{ + UINT16 adr = m_pc - READ_OP_ARG(); + UINT8 t = READ_RAM(m_r) - 1; + WRITE_RAM(m_r, t); + m_zero=t==0; + m_carry=t==0xff; + if (!m_carry) { + m_pc=adr; + adr=POP(); + m_icount-=3; + } +} + +void sc61860_device::sc61860_leave() +{ + WRITE_RAM(m_r, 0); +} + +void sc61860_device::sc61860_wait() +{ + int t=READ_OP(); + m_icount-=t; + m_icount-=t; + m_icount-=3; +} + +void sc61860_device::sc61860_set_carry() +{ + m_carry=1; + m_zero=1; +} + +void sc61860_device::sc61860_reset_carry() +{ + m_carry=0; + m_zero=1; +} + +void sc61860_device::sc61860_out_a() +{ + m_q=IA; + m_outa(READ_RAM(IA)); +} + +void sc61860_device::sc61860_out_b() +{ + m_q=IB; + m_outb( READ_RAM(IB)); +} + +void sc61860_device::sc61860_out_f() +{ + m_q=F0; + /*READ_RAM(F0); */ +} + + +/* c0 display on + c1 counter reset + c2 cpu halt + c3 computer off + c4 beeper frequency (1 4khz, 0 2khz), or (c5=0) membran pos1/pos2 + c5 beeper on + c6 beeper steuerung*/ +void sc61860_device::sc61860_out_c() +{ + m_q=C; + m_outc( READ_RAM(C)); + m_c = READ_RAM(C); +} + +void sc61860_device::sc61860_in_a() +{ + int data=0; + data=m_ina(); + WRITE_RAM(A, data); + m_zero=data==0; +} + +void sc61860_device::sc61860_in_b() +{ + int data=0; + data=m_inb(); + WRITE_RAM(A, data); + m_zero=data==0; +} + +/* 0 systemclock 512ms + 1 systemclock 2ms + 2 ? + 3 brk/on key + 4 ? + 5 ? + 6 reset + 7 cassette input */ +void sc61860_device::sc61860_test_special() +{ + int t=0; + if (m_timer.t512ms) t|=1; + if (m_timer.t2ms) t|=2; + if (!m_brk.isnull()&&m_brk()) t|=8; + if (!m_reset.isnull()&&m_reset()) t|=0x40; + if (!m_x.isnull()&&m_x()) t|=0x80; + + m_zero=(t&READ_OP())==0; +} + +/************************************************************************************ + "string" operations +***********************************************************************************/ + +// p-=I+1 sideeffect +void sc61860_device::sc61860_add_bcd_a() +{ + UINT8 help = READ_RAM(A); + int i, hlp, hlp1 = 0; + m_zero=1; + for (i=0; i <= READ_RAM(I); i++) { + int t = READ_RAM(m_p); + hlp1 = (t & 0x0f) + (help & 0x0f) + hlp1; + if (hlp1 > 9) { hlp = hlp1 - 0x0a; hlp1 = 0x10; } + else { hlp = hlp1; hlp1 = 0x00; } + hlp1 = (t & 0xf0) + (help & 0xf0) + hlp1; + if (hlp1 > 0x90) { WRITE_RAM(m_p, hlp1 - 0xa0 + hlp); hlp1 = 1; } + else { WRITE_RAM(m_p, hlp1 + hlp); hlp1 = 0; } + if ( READ_RAM(m_p) != 0 ) m_zero = 0; + m_p--; + help = 0; + } + m_carry= ( hlp1 ) ? 1 : 0; + m_icount-=3*(READ_RAM(I)+1); +} + + +// p-=I+1, q-=I+2 sideeffect +void sc61860_device::sc61860_add_bcd() +{ + int i, hlp, hlp1 = 0; + m_zero=1; + for (i=0; i <= READ_RAM(I); i++) { + int t = READ_RAM(m_p); + int t2 = READ_RAM(m_q); + hlp1 = (t & 0x0f) + (t2 & 0x0f) + hlp1; + if (hlp1 > 9) { hlp = hlp1 - 0x0a; hlp1 = 0x10; } + else { hlp = hlp1; hlp1 = 0x00; } + hlp1 = (t & 0xf0) + (t2 & 0xf0) + hlp1; + m_q--; + if (hlp1 > 0x90) { WRITE_RAM(m_p, hlp1 - 0xa0 + hlp); hlp1 = 1; } + else { WRITE_RAM(m_p, hlp1 + hlp); hlp1 = 0; } + if ( READ_RAM(m_p) != 0 ) m_zero = 0; + m_p--; + } + m_carry= ( hlp1 ) ? 1 : 0; + m_icount-=3*(READ_RAM(I)+1); + m_q--; +} + + +// p-=I+1 sideeffect +void sc61860_device::sc61860_sub_bcd_a() +{ + UINT8 help = READ_RAM(A); + int i, hlp, hlp1 = 0; + m_zero=1; + for (i=0; i <= READ_RAM(I); i++) { + int t = READ_RAM(m_p); + hlp1 = (t & 0x0f) - (help & 0x0f) - hlp1; + if ( hlp1 < 0 ) { hlp = hlp1 + 0x0a; hlp1 = 0x10; } + else { hlp = hlp1; hlp1 = 0x00; } + hlp1 = (t & 0xf0) - (help & 0xf0) - hlp1; + if ( hlp1 < 0 ) { WRITE_RAM(m_p, hlp1 + 0xa0 + hlp); hlp1 = 1; } + else { WRITE_RAM(m_p, hlp1 + hlp); hlp1 = 0; } + if ( READ_RAM(m_p) != 0 ) m_zero = 0; + m_p--; + help = 0; + } + m_carry= ( hlp1 ) ? 1 : 0; + m_icount-=3*(READ_RAM(I)+1); +} + + +// p-=I+1, q-=I+2 sideeffect +void sc61860_device::sc61860_sub_bcd() +{ + int i, hlp, hlp1 = 0; + m_zero=1; + for (i=0; i <= READ_RAM(I); i++) { + int t = READ_RAM(m_p); + int t2 = READ_RAM(m_q); + hlp1 = (t & 0x0f) - (t2 & 0x0f) - hlp1; + if ( hlp1 < 0 ) { hlp = hlp1 + 0x0a; hlp1 = 0x10; } + else { hlp = hlp1; hlp1 = 0x00; } + hlp1 = (t & 0xf0) - (t2 & 0xf0) - hlp1; + m_q--; + if ( hlp1 < 0 ) { WRITE_RAM(m_p, hlp1 + 0xa0 + hlp); hlp1 = 1; } + else { WRITE_RAM(m_p, hlp1 + hlp); hlp1 = 0; } + if ( READ_RAM(m_p) != 0 ) m_zero = 0; + m_p--; + } + m_carry= ( hlp1 ) ? 1 : 0; + m_icount-=3*(READ_RAM(I)+1); + m_q--; +} + +/* side effect p-i-1 -> p correct! */ +void sc61860_device::sc61860_shift_left_nibble() +{ + int i,t=0; + for (i=0; i<=READ_RAM(I); i++) { + t |= READ_RAM(m_p)<<4; + WRITE_RAM(m_p, t); + m_p--; + t>>=8; + m_icount--; + } +} + +/* side effect p+i+1 -> p correct! */ +void sc61860_device::sc61860_shift_right_nibble() +{ + int i,t=0; + for (i=0; i<=READ_RAM(I); i++) { + t |= READ_RAM(m_p); + WRITE_RAM(m_p, t>>4); + m_p++; + t=(t<<8)&0xf00; + m_icount--; + } +} + +// q=reg+1 sideeffect +void sc61860_device::sc61860_inc_load_dp(int reg) +{ + UINT8 t = READ_RAM(reg) + 1; + UINT8 t2 = READ_RAM(reg + 1); + WRITE_RAM(reg, t); + if (t == 0) { t2++; WRITE_RAM(reg + 1, t2); } + m_dp=t|(t2<<8); + m_q=reg+1; +} + +// q=reg+1 sideeffect +void sc61860_device::sc61860_dec_load_dp(int reg) +{ + UINT8 t = READ_RAM(reg) - 1; + UINT8 t2 = READ_RAM(reg + 1); + WRITE_RAM(reg, t); + if (t == 0xff) { t2--; WRITE_RAM(reg + 1, t2); } + m_dp=t|(t2<<8); + m_q=reg+1; +} + +// q=XH sideeffect +void sc61860_device::sc61860_inc_load_dp_load() +{ + sc61860_inc_load_dp(XL); + WRITE_RAM(A, READ_BYTE(m_dp)); +} + +// q=XH sideeffect +void sc61860_device::sc61860_dec_load_dp_load() +{ + sc61860_dec_load_dp(XL); + WRITE_RAM(A, READ_BYTE(m_dp)); +} + +// q=YH sideeffect +void sc61860_device::sc61860_inc_load_dp_store() +{ + sc61860_inc_load_dp(YL); + WRITE_BYTE(m_dp, READ_RAM(A)); +} + +// q=YH sideeffect +void sc61860_device::sc61860_dec_load_dp_store() +{ + sc61860_dec_load_dp(YL); + WRITE_BYTE(m_dp, READ_RAM(A)); +} + +void sc61860_device::sc61860_fill() +{ + int i; + for (i=0;i<=READ_RAM(I);i++) { + WRITE_RAM(m_p, READ_RAM(A)); /* could be overwritten? */ + m_p++; + m_icount--; + } +} + +void sc61860_device::sc61860_fill_ext() +{ + int i; + for (i=0;i<=READ_RAM(I);i++) { + WRITE_BYTE(m_dp, READ_RAM(A)); + if (i!=READ_RAM(I)) m_dp++; + m_icount-=3; + } +} + +// p+=count+1, q+=count+1 sideeffects +void sc61860_device::sc61860_copy(int count) +{ + int i; + for (i=0; i<=count; i++) { + WRITE_RAM(m_p, READ_RAM(m_q)); + m_p++; + m_q++; + m_icount-=2; + } + +} + +// p+=count+1, dp+=count sideeffects +void sc61860_device::sc61860_copy_ext(int count) +{ + int i; + for (i=0; i<=count; i++) { + WRITE_RAM(m_p, READ_BYTE(m_dp)); + m_p++; + if (i!=count) m_dp++; + m_icount-=4; + } +} + +void sc61860_device::sc61860_copy_int(int count) +{ + int i; + for (i=0; i<=count; i++) { + UINT8 t = READ_BYTE((READ_RAM(A)|(READ_RAM(B)<<8))); /* internal rom! */ + WRITE_RAM(m_p, t); + m_p++; + if (i!=count) { + t = READ_RAM(A) + 1; + WRITE_RAM(A, t); + if (t==0) { + t = READ_RAM(B) + 1; + WRITE_RAM(B, t); + } + } + m_icount-=4; + } +} + +void sc61860_device::sc61860_exchange(int count) +{ + int i; + UINT8 t; + for (i=0; i<=count; i++) { + t = READ_RAM(m_p); + WRITE_RAM(m_p, READ_RAM(m_q)); + WRITE_RAM(m_q, t); + m_p++; + m_q++; + m_icount-=3; + } +} + +void sc61860_device::sc61860_exchange_ext(int count) +{ + int i; + UINT8 t; + for (i=0; i<=count; i++) { + t = READ_RAM(m_p); + WRITE_RAM(m_p, READ_BYTE(m_dp)); + m_p++; + WRITE_BYTE(m_dp, t); + if (i!=count) m_dp++; + m_icount-=6; + } +} + +// undocumented +// only 1 opcode working in pc1403 +// both opcodes working in pc1350 +void sc61860_device::sc61860_wait_x(int level) +{ + int c; + m_zero=level; + + if (!m_x.isnull()) { + for (c=READ_RAM(I); c>=0; c--) { + UINT8 t = (READ_RAM(m_p)+1)&0x7f; + WRITE_RAM(m_p, t); + m_zero=m_x(); + m_icount-=4; + if (level != m_zero) break; + } + } +} diff --git a/src/devices/cpu/sc61860/sctable.inc b/src/devices/cpu/sc61860/sctable.inc new file mode 100644 index 00000000000..2e16dc51033 --- /dev/null +++ b/src/devices/cpu/sc61860/sctable.inc @@ -0,0 +1,145 @@ +// license:BSD-3-Clause +// copyright-holders:Peter Trauner +void sc61860_device::sc61860_instruction() +{ + int oper=READ_OP(); + if ((oper&0xc0)==0x80) { + sc61860_load_imm_p(oper&0x3f);m_icount-=2; + } else if ((oper&0xe0)==0xe0) { + sc61860_call(READ_OP()|((oper&0x1f)<<8));m_icount-=7; + } else { + switch(oper) { + case 0: sc61860_load_imm(I, READ_OP());m_icount-=4;break; + case 1: sc61860_load_imm(J, READ_OP());m_icount-=4;break; + case 2: sc61860_load_imm(A, READ_OP());m_icount-=4;break; + case 3: sc61860_load_imm(B, READ_OP());m_icount-=4;break; + case 4: sc61860_inc_load_dp(XL);m_icount-=6;break; + case 5: sc61860_dec_load_dp(XL);m_icount-=6;break; + case 6: sc61860_inc_load_dp(YL);m_icount-=6;break; + case 7: sc61860_dec_load_dp(YL);m_icount-=6;break; + case 8: sc61860_copy(READ_RAM(I));break; + case 9: sc61860_exchange(READ_RAM(I));break; + case 10: sc61860_copy(READ_RAM(J));break; + case 11: sc61860_exchange(READ_RAM(J));break; + case 12: sc61860_add_bcd_a();m_icount-=7;break; + case 13: sc61860_sub_bcd_a();m_icount-=7;break; + case 14: sc61860_add_bcd();m_icount-=7;break; + case 15: sc61860_sub_bcd();m_icount-=7;break; + case 16: sc61860_load_dp();m_icount-=8;break; + case 17: sc61860_load_dl();m_icount-=5;break; + case 18: sc61860_load_imm_p(READ_OP());m_icount-=4;break; + case 19: sc61860_load_imm_q(READ_OP());m_icount-=4;break; + case 20: sc61860_add_word();m_icount-=5;break; + case 21: sc61860_sub_word();m_icount-=5;break; + case 24: sc61860_copy_ext(READ_RAM(I));break; + case 25: sc61860_exchange_ext(READ_RAM(I));break; + case 26: sc61860_copy_ext(READ_RAM(J));break; + case 27: sc61860_exchange_ext(READ_RAM(J));break; + case 28: sc61860_shift_right_nibble();m_icount-=5;break; + case 29: sc61860_shift_left_nibble();m_icount-=5;break; + case 30: sc61860_fill();m_icount-=5;break; + case 31: sc61860_fill_ext();m_icount-=4;break; + case 32: sc61860_store_p();m_icount-=2;break; + case 33: sc61860_store_q();m_icount-=2;break; + case 34: sc61860_store_r();m_icount-=2;break; + case 36: sc61860_inc_load_dp_load();m_icount-=7;break; + case 37: sc61860_dec_load_dp_load();m_icount-=7;break; + case 38: sc61860_inc_load_dp_store();m_icount-=7;break; + case 39: sc61860_dec_load_dp_store();m_icount-=7;break; + case 40: sc61860_jump_rel_plus(!m_zero);m_icount-=4;break; + case 41: sc61860_jump_rel_minus(!m_zero);m_icount-=4;break; + case 42: sc61860_jump_rel_plus(!m_carry);m_icount-=4;break; + case 43: sc61860_jump_rel_minus(!m_carry);m_icount-=4;break; + case 44: sc61860_jump_rel_plus(TRUE);m_icount-=4;break; + case 45: sc61860_jump_rel_minus(TRUE);m_icount-=4;break; + case 47: sc61860_loop();m_icount-=7;break; + case 48: sc61860_load_imm_p(READ_RAM(A));m_icount-=2;break; + case 49: sc61860_load_imm_q(READ_RAM(A));m_icount-=2;break; + case 50: sc61860_load_r();m_icount-=2;break; + case 52: sc61860_push();m_icount-=3;break; + case 53: sc61860_copy_int(READ_RAM(I));break; + case 55: sc61860_return();m_icount-=4;break; + case 56: sc61860_jump_rel_plus(m_zero);m_icount-=4;break; + case 57: sc61860_jump_rel_minus(m_zero);m_icount-=4;break; + case 58: sc61860_jump_rel_plus(m_carry);m_icount-=4;break; + case 59: sc61860_jump_rel_minus(m_carry);m_icount-=4;break; + case 64: sc61860_inc(I);m_icount-=4;break; + case 65: sc61860_dec(I);m_icount-=4;break; + case 66: sc61860_inc(A);m_icount-=4;break; + case 67: sc61860_dec(A);m_icount-=4;break; + case 68: sc61860_add(m_p, READ_RAM(A));m_icount-=3;break; + case 69: sc61860_sub(m_p, READ_RAM(A));m_icount-=3;break; + case 70: sc61860_and(m_p, READ_RAM(A));m_icount-=3;break; + case 71: sc61860_or(m_p, READ_RAM(A));m_icount-=3;break; + case 72: sc61860_inc(K);m_icount-=4;break; + case 73: sc61860_dec(K);m_icount-=4;break; + case 74: sc61860_inc(V);m_icount-=4;break; + case 75: sc61860_dec(V);m_icount-=4;break; + case 76: sc61860_in_a();m_icount-=2;break; + case 77: /*nopw*/;m_icount-=2;break; + case 78: sc61860_wait();m_icount-=6;break; + case 79: sc61860_wait_x(FALSE);m_icount-=1;break; + case 80: sc61860_inc_p();m_icount-=2;break; + case 81: sc61860_dec_p();m_icount-=2;break; + case 82: sc61860_store_ext(A);m_icount-=2;break; + case 83: sc61860_store_ext(m_p);m_icount-=2;break; + case 84: sc61860_load_imm(m_p, READ_OP());m_icount-=3/*?*/;break; // undocumented + case 85: sc61860_load_ext(m_p);m_icount-=3;break; + case 86: sc61860_load_imm(m_p, READ_OP());m_icount-=3/*?*/;break; // undocumented + case 87: sc61860_load_ext(A);m_icount-=3;break; + case 88: sc61860_swap();m_icount-=2;break; + case 89: sc61860_load();m_icount-=2;break; + case 90: sc61860_rotate_left();m_icount-=2;break; + case 91: sc61860_pop();m_icount-=2;break; + case 93: sc61860_out_a();m_icount-=3;break; + case 95: sc61860_out_f();m_icount-=3;break; + case 96: sc61860_and(m_p, READ_OP());m_icount-=4;break; + case 97: sc61860_or(m_p, READ_OP());m_icount-=4;break; + case 98: sc61860_test(m_p, READ_OP());m_icount-=4;break; + case 99: sc61860_cmp(m_p, READ_OP());m_icount-=4;break; + case 100: sc61860_and(A, READ_OP());m_icount-=4;break; + case 101: sc61860_or(A, READ_OP());m_icount-=4;break; + case 102: sc61860_test(A, READ_OP());m_icount-=4;break; + case 103: sc61860_cmp(A, READ_OP());m_icount-=4;break; + case 105: sc61860_execute_table_call();m_icount-=3;break; + case 107: sc61860_test_special();m_icount-=4;break; + case 111: sc61860_wait_x(TRUE);m_icount-=1;break; + case 112: sc61860_add(m_p, READ_OP());m_icount-=4;break; + case 113: sc61860_sub(m_p, READ_OP());m_icount-=4;break; + case 116: sc61860_add(A, READ_OP());m_icount-=4;break; + case 117: sc61860_sub(A, READ_OP());m_icount-=4;break; + case 120: sc61860_call(READ_OP_ARG_WORD());m_icount-=8;break; + case 121: sc61860_jump(1);m_icount-=6;break; + case 122: sc61860_prepare_table_call();m_icount-=9;break; + case 124: sc61860_jump(!m_zero);m_icount-=6;break; + case 125: sc61860_jump(!m_carry);m_icount-=6;break; + case 126: sc61860_jump(m_zero);m_icount-=6;break; + case 127: sc61860_jump(m_carry);m_icount-=6;break; + case 192: sc61860_inc(J);m_icount-=4;break; + case 193: sc61860_dec(J);m_icount-=4;break; + case 194: sc61860_inc(B);m_icount-=4;break; + case 195: sc61860_dec(B);m_icount-=4;break; + case 196: sc61860_add_carry();m_icount-=3;break; + case 197: sc61860_sub_carry();m_icount-=3;break; + case 199: sc61860_cmp(m_p, READ_RAM(A));m_icount-=3;break; + case 200: sc61860_inc(L);m_icount-=4;break; + case 201: sc61860_dec(L);m_icount-=4;break; + case 202: sc61860_inc(W);m_icount-=4;break; + case 203: sc61860_dec(W);m_icount-=4;break; + case 204: sc61860_in_b();m_icount-=2;break; + case 206: /*nopt*/;m_icount-=3;break; + case 208: sc61860_set_carry();m_icount-=2;break; + case 209: sc61860_reset_carry();m_icount-=4;break; + case 210: sc61860_rotate_right();m_icount-=2;break; + case 212: sc61860_and_ext();m_icount-=6;break; + case 213: sc61860_or_ext();m_icount-=6;break; + case 214: sc61860_test_ext();m_icount-=6;break; + case 216: sc61860_leave();m_icount-=2;break; + case 218: sc61860_exam(A, B);m_icount-=3;break; + case 219: sc61860_exam(A, m_p);m_icount-=3;break; + case 221: sc61860_out_b();m_icount-=2;break; + case 223: sc61860_out_c();m_icount-=2;break; + default: logerror("sc61860 illegal opcode at %.4x %.2x\n",m_pc-1, oper); + } + } +} diff --git a/src/devices/cpu/scmp/scmp.c b/src/devices/cpu/scmp/scmp.c new file mode 100644 index 00000000000..edd8502c1c5 --- /dev/null +++ b/src/devices/cpu/scmp/scmp.c @@ -0,0 +1,566 @@ +// license:BSD-3-Clause +// copyright-holders:Miodrag Milanovic +/***************************************************************************** + * + * scmp.c + * + * National Semiconductor SC/MP CPU Disassembly + * + *****************************************************************************/ + +#include "emu.h" +#include "debugger.h" +#include "scmp.h" + +#define VERBOSE 0 + +#define LOG(x) do { if (VERBOSE) logerror x; } while (0) + + +const device_type SCMP = &device_creator; +const device_type INS8060 = &device_creator; + + +scmp_device::scmp_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : cpu_device(mconfig, SCMP, "INS 8050 SC/MP", tag, owner, clock, "ins8050", __FILE__) + , m_program_config("program", ENDIANNESS_LITTLE, 8, 16, 0) + , m_flag_out_func(*this) + , m_sout_func(*this) + , m_sin_func(*this) + , m_sensea_func(*this) + , m_senseb_func(*this) + , m_halt_func(*this) +{ +} + + +scmp_device::scmp_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : cpu_device(mconfig, type, name, tag, owner, clock, shortname, source) + , m_program_config("program", ENDIANNESS_LITTLE, 8, 16, 0) + , m_flag_out_func(*this) + , m_sout_func(*this) + , m_sin_func(*this) + , m_sensea_func(*this) + , m_senseb_func(*this) + , m_halt_func(*this) +{ +} + + +ins8060_device::ins8060_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : scmp_device(mconfig, INS8060, "INS 8060 SC/MP II", tag, owner, clock, "ins8060", __FILE__) +{ +} + + +offs_t scmp_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( scmp ); + return CPU_DISASSEMBLE_NAME(scmp)(this, buffer, pc, oprom, opram, options); +} + + +UINT16 scmp_device::ADD12(UINT16 addr, INT8 val) +{ + return ((addr + val) & 0x0fff) | (addr & 0xf000); +} + +UINT8 scmp_device::ROP() +{ + UINT16 pc = m_PC.w.l; + m_PC.w.l = ADD12(m_PC.w.l,1); + return m_direct->read_byte( pc); +} + +UINT8 scmp_device::ARG() +{ + UINT16 pc = m_PC.w.l; + m_PC.w.l = ADD12(m_PC.w.l,1); + return m_direct->read_byte(pc); +} + +UINT8 scmp_device::RM(UINT32 a) +{ + return m_program->read_byte(a); +} + +void scmp_device::WM(UINT32 a, UINT8 v) +{ + m_program->write_byte(a, v); +} + +void scmp_device::illegal(UINT8 opcode) +{ +#if VERBOSE + UINT16 pc = m_PC.w.l; + LOG(("SC/MP illegal instruction %04X $%02X\n", pc-1, opcode)); +#endif +} + +PAIR *scmp_device::GET_PTR_REG(int num) +{ + switch(num) { + case 1: return &m_P1; + case 2: return &m_P2; + case 3: return &m_P3; + default : + return &m_PC; + } +} + +void scmp_device::BIN_ADD(UINT8 val) +{ + UINT16 tmp = m_AC + val + ((m_SR >> 7) & 1); + UINT8 ov = (((m_AC & 0x80)==(val & 0x80)) && ((m_AC & 0x80)!=(tmp & 0x80))) ? 0x40 : 0x00; + + m_AC = tmp & 0xff; + m_SR &= 0x3f; // clear CY/L and OV flag + m_SR |= (tmp & 0x100) ? 0x80 : 0x00; // set CY/L + m_SR |= ov; +} + +void scmp_device::DEC_ADD(UINT8 val) +{ + UINT16 tmp = m_AC + val + ((m_SR >> 7) & 1); + if ((tmp & 0x0f) > 9) tmp +=6; + m_AC = tmp % 0xa0; + m_SR &= 0x7f; // clear CY/L flag + m_SR |= (tmp > 0x99) ? 0x80 : 0x00; +} + +UINT16 scmp_device::GET_ADDR(UINT8 code) +{ + UINT16 addr = 0; + INT8 offset = 0; + UINT16 retVal = 0; + UINT16 ptr = GET_PTR_REG(code & 0x03)->w.l; + + UINT8 arg = ARG(); + if (arg == 0x80) { + offset = m_ER; + } else { + if (arg & 0x80) { + offset = (INT8)arg; + } else { + offset = arg; + } + } + + addr = ADD12(ptr,offset); + + if (code & 0x04) { + if (code & 0x03) { + // Auto-indexed + if (offset < 0) { + // pre decrement + GET_PTR_REG(code & 0x03)->w.l = addr; + retVal = addr; + } else { + // post increment + retVal = ptr; + GET_PTR_REG(code & 0x03)->w.l = addr; + } + } else { + // Immediate + } + } else { + // Indexed + retVal = addr; + } + return retVal; +} + +void scmp_device::execute_one(int opcode) +{ + UINT8 tmp; + UINT8 ptr = opcode & 3; + if (BIT(opcode,7)) { + // two bytes instructions + switch (opcode) + { + // Memory Reference Instructions + case 0xc0 : case 0xc1 : case 0xc2 : case 0xc3 : + case 0xc5 : case 0xc6 : case 0xc7 : + //LD + m_icount -= 18; + m_AC = RM(GET_ADDR(opcode)); + break; + case 0xc8 : case 0xc9 : case 0xca : case 0xcb : + case 0xcd : case 0xce : case 0xcf : + // ST + m_icount -= 18; + WM(GET_ADDR(opcode),m_AC); + break; + case 0xd0 : case 0xd1 : case 0xd2 : case 0xd3 : + case 0xd5 : case 0xd6 : case 0xd7 : + // AND + m_icount -= 18; + m_AC &= RM(GET_ADDR(opcode)); + break; + case 0xd8 : case 0xd9 : case 0xda : case 0xdb : + case 0xdd : case 0xde : case 0xdf : + //OR + m_icount -= 18; + m_AC |= RM(GET_ADDR(opcode)); + break; + case 0xe0 : case 0xe1 : case 0xe2 : case 0xe3 : + case 0xe5 : case 0xe6 : case 0xe7 : + // XOR + m_icount -= 18; + m_AC ^= RM(GET_ADDR(opcode)); + break; + case 0xe8 : case 0xe9 : case 0xea : case 0xeb : + case 0xed : case 0xee : case 0xef : + // DAD + m_icount -= 23; + DEC_ADD(RM(GET_ADDR(opcode))); + break; + case 0xf0 : case 0xf1 : case 0xf2 : case 0xf3 : + case 0xf5 : case 0xf6 : case 0xf7 : + // ADD + m_icount -= 19; + BIN_ADD(RM(GET_ADDR(opcode))); + break; + case 0xf8 : case 0xf9 : case 0xfa : case 0xfb : + case 0xfd : case 0xfe : case 0xff : + // CAD + m_icount -= 20; + BIN_ADD(~RM(GET_ADDR(opcode))); + break; + // Memory Increment/Decrement Instructions + case 0xa8 : case 0xa9 : case 0xaa : case 0xab : + // IDL + { + UINT16 addr = GET_ADDR(opcode); + m_icount -= 22; + m_AC = RM(addr) + 1; + WM(addr,m_AC); + } + break; + case 0xb8 : case 0xb9 : case 0xba : case 0xbb : + // DLD + { + UINT16 addr = GET_ADDR(opcode); + m_icount -= 22; + m_AC = RM(addr) - 1; + WM(addr,m_AC); + } + break; + // Immediate Instructions + case 0xc4 : // LDI + m_icount -= 10; + m_AC = ARG(); + break; + case 0xd4 : // ANI + m_icount -= 10; + m_AC &= ARG(); + break; + case 0xdc : // ORI + m_icount -= 10; + m_AC |= ARG(); + break; + case 0xe4 : // XRI + m_icount -= 10; + m_AC ^= ARG(); + break; + case 0xec : // DAI + m_icount -= 15; + DEC_ADD(ARG()); + break; + case 0xf4 : // ADI + m_icount -= 11; + BIN_ADD(ARG()); + break; + case 0xfc : // CAI + m_icount -= 12; + BIN_ADD(~ARG()); + break; + // Transfer Instructions + case 0x90 : case 0x91 : case 0x92 : case 0x93 :// JMP + m_icount -= 11; + m_PC.w.l = ADD12(GET_PTR_REG(ptr)->w.l,(INT8)ARG()); + break; + case 0x94 : case 0x95 : case 0x96 : case 0x97 : + // JP + m_icount -= 9; + tmp = ARG(); + if (!(m_AC & 0x80)) { + m_PC.w.l = ADD12(GET_PTR_REG(ptr)->w.l,(INT8)tmp); + m_icount -= 2; + } + break; + case 0x98 : case 0x99 : case 0x9a : case 0x9b : + // JZ + m_icount -= 9; + tmp = ARG(); + if (!m_AC) { + m_PC.w.l = ADD12(GET_PTR_REG(ptr)->w.l,(INT8)tmp); + m_icount -= 2; + } + break; + case 0x9c : case 0x9d : case 0x9e : case 0x9f : + // JNZ + m_icount -= 9; + tmp = ARG(); + if (m_AC) { + m_PC.w.l = ADD12(GET_PTR_REG(ptr)->w.l,(INT8)tmp); + m_icount -= 2; + } + break; + // Double-Byte Miscellaneous Instructions + case 0x8f: // DLY + tmp = ARG(); + m_icount -= 13 + (m_AC * 2) + (((UINT32)tmp) << 1) + (((UINT32)tmp) << 9); + m_AC = 0xff; + break; + // Others are illegal + default : m_icount -= 1; + illegal (opcode); + break; + } + } else { + // one byte instructions + switch (opcode) + { + // Extension Register Instructions + case 0x40: // LDE + m_icount -= 6; + m_AC = m_ER; + break; + case 0x01: // XAE + m_icount -= 7; + tmp = m_AC; + m_AC = m_ER; + m_ER = tmp; + break; + case 0x50: // ANE + m_icount -= 6; + m_AC &= m_ER; + break; + case 0x58: // ORE + m_icount -= 6; + m_AC |= m_ER; + break; + case 0x60: // XRE + m_icount -= 6; + m_AC ^= m_ER; + break; + case 0x68: // DAE + m_icount -= 11; + DEC_ADD(m_ER); + break; + case 0x70: // ADE + m_icount -= 7; + BIN_ADD(m_ER); + break; + case 0x78: // CAE + m_icount -= 8; + BIN_ADD(~m_ER); + break; + // Pointer Register Move Instructions + case 0x30: case 0x31: case 0x32: case 0x33: // XPAL + m_icount -= 8; + tmp = m_AC; + m_AC = GET_PTR_REG(ptr)->b.l; + GET_PTR_REG(ptr)->b.l = tmp; + break; + case 0x34: case 0x35 :case 0x36: case 0x37: + // XPAH + m_icount -= 8; + tmp = m_AC; + m_AC = GET_PTR_REG(ptr)->b.h; + GET_PTR_REG(ptr)->b.h = tmp; + break; + case 0x3c: case 0x3d :case 0x3e: case 0x3f: + // XPPC + { + UINT16 tmp16 = ADD12(m_PC.w.l,-1); // Since PC is incremented we need to fix it + m_icount -= 7; + m_PC.w.l = GET_PTR_REG(ptr)->w.l; + GET_PTR_REG(ptr)->w.l = tmp16; + // After exchange CPU increment PC + m_PC.w.l = ADD12(m_PC.w.l,1); + } + break; + // Shift, Rotate, Serial I/O Instructions + case 0x19: // SIO + m_icount -= 5; + m_sout_func(m_ER & 0x01); + m_ER >>= 1; + m_ER |= m_sin_func() ? 0x80 : 0x00; + break; + case 0x1c: // SR + m_icount -= 5; + m_AC >>= 1; + break; + case 0x1d: // SRL + m_icount -= 5; + m_AC >>= 1; + m_AC |= m_SR & 0x80; // add C/L flag + break; + case 0x1e: // RR + m_icount -= 5; + m_AC = (m_AC >> 1) | ((m_AC & 0x01) << 7); + break; + case 0x1f: // RRL + m_icount -= 5; + tmp = (m_AC & 0x01) << 7; + m_AC = (m_AC >> 1) | (m_SR & 0x80); + m_SR = (m_SR & 0x7f) | tmp; + break; + // Single Byte Miscellaneous Instructions + case 0x00: // HALT + m_icount -= 8; + m_halt_func(1); + m_halt_func(0); + break; + case 0x02: // CCL + m_icount -= 5; + m_SR &= 0x7f; + break; + case 0x03: // SCL + m_icount -= 5; + m_SR |= 0x80; + break; + case 0x04: // DINT + m_icount -= 6; + m_SR &= 0xf7; + break; + case 0x05: // IEN + m_icount -= 6; + m_SR |= 0x08; + break; + case 0x06: // CSA + m_icount -= 5; + m_SR &= 0xcf; // clear SA and SB flags + m_SR |= m_sensea_func() ? 0x10 : 0x00; + m_SR |= m_senseb_func() ? 0x20 : 0x00; + m_AC = m_SR; + break; + case 0x07: // CAS + m_icount -= 6; + m_SR = m_AC; + m_flag_out_func(m_SR & 0x07); + break; + case 0x08: // NOP + m_icount -= 5; + break; + // Others are illegal + default : m_icount -= 1; + illegal (opcode); + break; + } + } +} + + +/*************************************************************************** + COMMON EXECUTION +***************************************************************************/ +void scmp_device::take_interrupt() +{ + UINT16 tmp = ADD12(m_PC.w.l,-1); // We fix PC so at return it goes to current location + m_SR &= 0xf7; // clear IE flag + + m_icount -= 8; // assumption + // do XPPC 3 + m_PC.w.l = GET_PTR_REG(3)->w.l; + GET_PTR_REG(3)->w.l = tmp; + // After exchange CPU increment PC + m_PC.w.l = ADD12(m_PC.w.l,1); +} + +void scmp_device::execute_run() +{ + do + { + if ((m_SR & 0x08) && (m_sensea_func())) { + take_interrupt(); + } + debugger_instruction_hook(this, m_PC.d); + execute_one(ROP()); + + } while (m_icount > 0); +} + +/*************************************************************************** + CORE INITIALIZATION +***************************************************************************/ + +void scmp_device::device_start() +{ + /* set up the state table */ + { + state_add(SCMP_PC, "PC", m_PC.w.l); + state_add(STATE_GENPC, "GENPC", m_PC.w.l).noshow(); + state_add(STATE_GENFLAGS, "GENFLAGS", m_SR).noshow().formatstr("%8s"); + state_add(SCMP_P1, "P1", m_P1.w.l); + state_add(SCMP_P2, "P2", m_P2.w.l); + state_add(SCMP_P3, "P3", m_P3.w.l); + state_add(SCMP_AC, "AC", m_AC); + state_add(SCMP_ER, "ER", m_ER); + state_add(SCMP_SR, "SR", m_SR); + } + + m_program = &space(AS_PROGRAM); + m_direct = &m_program->direct(); + + /* resolve callbacks */ + m_flag_out_func.resolve_safe(); + m_sout_func.resolve_safe(); + m_sin_func.resolve_safe(0); + m_sensea_func.resolve_safe(0); + m_senseb_func.resolve_safe(0); + m_halt_func.resolve_safe(); + + save_item(NAME(m_PC)); + save_item(NAME(m_P1)); + save_item(NAME(m_P2)); + save_item(NAME(m_P3)); + save_item(NAME(m_AC)); + save_item(NAME(m_ER)); + save_item(NAME(m_SR)); + + m_icountptr = &m_icount; +} + + + +/*************************************************************************** + COMMON RESET +***************************************************************************/ + +void scmp_device::device_reset() +{ + m_PC.d = 0; + m_P1.d = 0; + m_P2.d = 0; + m_P3.d = 0; + m_AC = 0; + m_ER = 0; + m_SR = 0; +} + + + +/*************************************************************************** + COMMON STATE IMPORT/EXPORT +***************************************************************************/ + +void scmp_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + switch (entry.index()) + { + case STATE_GENFLAGS: + strprintf(str, "%c%c%c%c%c%c%c%c", + (m_SR & 0x80) ? 'C' : '.', + (m_SR & 0x40) ? 'V' : '.', + (m_SR & 0x20) ? 'B' : '.', + (m_SR & 0x10) ? 'A' : '.', + (m_SR & 0x08) ? 'I' : '.', + (m_SR & 0x04) ? '2' : '.', + (m_SR & 0x02) ? '1' : '.', + (m_SR & 0x01) ? '0' : '.'); + break; + } +} diff --git a/src/devices/cpu/scmp/scmp.h b/src/devices/cpu/scmp/scmp.h new file mode 100644 index 00000000000..86590f93546 --- /dev/null +++ b/src/devices/cpu/scmp/scmp.h @@ -0,0 +1,120 @@ +// license:BSD-3-Clause +// copyright-holders:Miodrag Milanovic +#ifndef __SCMP_H__ +#define __SCMP_H__ + + +/*************************************************************************** + CONSTANTS +***************************************************************************/ + +enum +{ + SCMP_PC, SCMP_P1, SCMP_P2, SCMP_P3, SCMP_AC, SCMP_ER, SCMP_SR, + SCMP_GENPC = STATE_GENPC, + SCMP_GENSP = STATE_GENSP, + SCMP_GENPCBASE = STATE_GENPCBASE +}; + + +#define MCFG_SCMP_CONFIG(_flag_out_devcb, _sout_devcb, _sin_devcb, _sensea_devcb, _senseb_devcb, _halt_devcb) \ + scmp_device::set_flag_out_cb(*device, DEVCB_##_flag_out_devcb); \ + scmp_device::set_sout_cb(*device, DEVCB_##_sout_devcb); \ + scmp_device::set_sin_cb(*device, DEVCB_##_sin_devcb); \ + scmp_device::set_sensea_cb(*device, DEVCB_##_sensea_devcb); \ + scmp_device::set_senseb_cb(*device, DEVCB_##_senseb_devcb); \ + scmp_device::set_halt_cb(*device, DEVCB_##_halt_devcb); + + +class scmp_device : public cpu_device +{ +public: + // construction/destruction + scmp_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + scmp_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + // static configuration helpers + template static devcb_base &set_flag_out_cb(device_t &device, _Object object) { return downcast(device).m_flag_out_func.set_callback(object); } + template static devcb_base &set_sout_cb(device_t &device, _Object object) { return downcast(device).m_sout_func.set_callback(object); } + template static devcb_base &set_sin_cb(device_t &device, _Object object) { return downcast(device).m_sin_func.set_callback(object); } + template static devcb_base &set_sensea_cb(device_t &device, _Object object) { return downcast(device).m_sensea_func.set_callback(object); } + template static devcb_base &set_senseb_cb(device_t &device, _Object object) { return downcast(device).m_senseb_func.set_callback(object); } + template static devcb_base &set_halt_cb(device_t &device, _Object object) { return downcast(device).m_halt_func.set_callback(object); } + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_execute_interface overrides + virtual UINT32 execute_min_cycles() const { return 5; } + virtual UINT32 execute_max_cycles() const { return 131593; } + virtual UINT32 execute_input_lines() const { return 0; } + virtual void execute_run(); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const { return (spacenum == AS_PROGRAM) ? &m_program_config : NULL; } + + // device_state_interface overrides + void state_string_export(const device_state_entry &entry, std::string &str); + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const { return 1; } + virtual UINT32 disasm_max_opcode_bytes() const { return 2; } + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + +private: + address_space_config m_program_config; + + PAIR m_PC; + PAIR m_P1; + PAIR m_P2; + PAIR m_P3; + UINT8 m_AC; + UINT8 m_ER; + UINT8 m_SR; + + address_space *m_program; + direct_read_data *m_direct; + int m_icount; + + devcb_write8 m_flag_out_func; + devcb_write_line m_sout_func; + devcb_read_line m_sin_func; + devcb_read_line m_sensea_func; + devcb_read_line m_senseb_func; + devcb_write_line m_halt_func; + + inline UINT16 ADD12(UINT16 addr, INT8 val); + inline UINT8 ROP(); + inline UINT8 ARG(); + inline UINT8 RM(UINT32 a); + inline void WM(UINT32 a, UINT8 v); + inline void illegal(UINT8 opcode); + inline PAIR *GET_PTR_REG(int num); + inline void BIN_ADD(UINT8 val); + inline void DEC_ADD(UINT8 val); + inline UINT16 GET_ADDR(UINT8 code); + void execute_one(int opcode); + void take_interrupt(); + +}; + + +class ins8060_device : public scmp_device +{ +public: + // construction/destruction + ins8060_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual UINT64 execute_clocks_to_cycles(UINT64 clocks) const { return (clocks + 2 - 1) / 2; } + virtual UINT64 execute_cycles_to_clocks(UINT64 cycles) const { return (cycles * 2); } +}; + + +extern const device_type SCMP; +extern const device_type INS8060; + + +#endif diff --git a/src/devices/cpu/scmp/scmpdasm.c b/src/devices/cpu/scmp/scmpdasm.c new file mode 100644 index 00000000000..f8bcc491ce4 --- /dev/null +++ b/src/devices/cpu/scmp/scmpdasm.c @@ -0,0 +1,153 @@ +// license:BSD-3-Clause +// copyright-holders:Miodrag Milanovic +/***************************************************************************** + * + * scmpdasm.c + * + * National Semiconductor SC/MP CPU Disassembly + * + *****************************************************************************/ + +#include "emu.h" + +#define OP(A) oprom[(A) - PC] +#define ARG(A) opram[(A) - PC] + +CPU_DISASSEMBLE( scmp ) +{ + unsigned PC = pc; + UINT8 op = OP(pc++); + UINT8 ptr = op & 3; + + if (BIT(op,7)) { + // two bytes instructions + char as[10]; + char aspr[10]; + UINT8 arg = ARG(pc); pc++; + if (arg==0x80) { + sprintf(as,"E"); + } else { + if (arg & 0x80) { + sprintf(as,"-$%02x",0x100-arg); + } else { + sprintf(as,"+$%02x",arg); + } + } + sprintf(aspr,"%s(%d)",as,ptr); + + switch (op) + { + // Memory Reference Instructions + case 0xc0 : sprintf (buffer,"ld %s",as); break; + case 0xc1 : case 0xc2 : case 0xc3 : + sprintf (buffer,"ld %s",aspr);break; + case 0xc5 : case 0xc6 : case 0xc7 : + sprintf (buffer,"ld @%s",aspr); break; + case 0xc8 : sprintf (buffer,"st %s",as); break; + case 0xc9 : case 0xca : case 0xcb : + sprintf (buffer,"st %s",aspr);break; + case 0xcd : case 0xce : case 0xcf : + sprintf (buffer,"st @%s",aspr); break; + case 0xd0 : sprintf (buffer,"and %s",as); break; + case 0xd1 : case 0xd2 : case 0xd3 : + sprintf (buffer,"and %s",aspr);break; + case 0xd5 : case 0xd6 : case 0xd7 : + sprintf (buffer,"and @%s",aspr); break; + case 0xd8 : sprintf (buffer,"or %s",as); break; + case 0xd9 : case 0xda : case 0xdb : + sprintf (buffer,"or %s",aspr);break; + case 0xdd : case 0xde : case 0xdf : + sprintf (buffer,"or @%s",aspr); break; + case 0xe0 : sprintf (buffer,"xor %s",as); break; + case 0xe1 : case 0xe2 : case 0xe3 : + sprintf (buffer,"xor %s",aspr);break; + case 0xe5 : case 0xe6 : case 0xe7 : + sprintf (buffer,"xor @%s",aspr); break; + case 0xe8 : sprintf (buffer,"dad %s",as); break; + case 0xe9 : case 0xea : case 0xeb : + sprintf (buffer,"dad %s",aspr);break; + case 0xed : case 0xee : case 0xef : + sprintf (buffer,"dad @%s",aspr); break; + case 0xf0 : sprintf (buffer,"add %s",as); break; + case 0xf1 : case 0xf2 : case 0xf3 : + sprintf (buffer,"add %s",aspr);break; + case 0xf5 : case 0xf6 : case 0xf7 : + sprintf (buffer,"add @%s",aspr); break; + case 0xf8 : sprintf (buffer,"cad %s",as); break; + case 0xf9 : case 0xfa : case 0xfb : + sprintf (buffer,"cad %s",aspr);break; + case 0xfd : case 0xfe : case 0xff : + sprintf (buffer,"cad @%s",aspr); break; + // Memory Increment/Decrement Instructions + case 0xa8 : case 0xa9 : case 0xaa : case 0xab : + sprintf (buffer,"ild %s",aspr); break; + case 0xb8 : case 0xb9 : case 0xba : case 0xbb : + sprintf (buffer,"dld %s",aspr); break; + // Immediate Instructions + case 0xc4 : sprintf (buffer,"ldi $%02x",arg); break; + case 0xd4 : sprintf (buffer,"ani $%02x",arg); break; + case 0xdc : sprintf (buffer,"ori $%02x",arg); break; + case 0xe4 : sprintf (buffer,"xri $%02x",arg); break; + case 0xec : sprintf (buffer,"dai $%02x",arg); break; + case 0xf4 : sprintf (buffer,"adi $%02x",arg); break; + case 0xfc : sprintf (buffer,"cai $%02x",arg); break; + // Transfer Instructions + case 0x90 : sprintf (buffer,"jmp %s",as);break; + case 0x91 : case 0x92 : case 0x93 : + sprintf (buffer,"jmp %s",aspr);break; + case 0x94 : sprintf (buffer,"jp %s",as); break; + case 0x95 : case 0x96 : case 0x97 : + sprintf (buffer,"jp %s",aspr); break; + case 0x98 : sprintf (buffer,"jz %s",as); break; + case 0x99 : case 0x9a : case 0x9b : + sprintf (buffer,"jz %s",aspr); break; + case 0x9c : sprintf (buffer,"jnz %s",as); break; + case 0x9d : case 0x9e : case 0x9f : + sprintf (buffer,"jnz %s",aspr); break; + // Double-Byte Miscellaneous Instructions + case 0x8f: sprintf (buffer,"dly $%02x",arg); break; + // Others are illegal + default : sprintf (buffer,"illegal"); pc--; break; // Illegal we consider without param + } + } else { + // one byte instructions + switch (op) + { + // Extension Register Instructions + case 0x40: sprintf (buffer,"lde"); break; + case 0x01: sprintf (buffer,"xae"); break; + case 0x50: sprintf (buffer,"ane"); break; + case 0x58: sprintf (buffer,"ore"); break; + case 0x60: sprintf (buffer,"xre"); break; + case 0x68: sprintf (buffer,"dae"); break; + case 0x70: sprintf (buffer,"ade"); break; + case 0x78: sprintf (buffer,"cae"); break; + // Pointer Register Move Instructions + case 0x30: case 0x31 :case 0x32: case 0x33: + sprintf (buffer,"xpal %d",ptr); break; + case 0x34: case 0x35 :case 0x36: case 0x37: + sprintf (buffer,"xpah %d",ptr); break; + case 0x3c: case 0x3d :case 0x3e: case 0x3f: + sprintf (buffer,"xppc %d",ptr); break; + // Shift, Rotate, Serial I/O Instructions + case 0x19: sprintf (buffer,"sio"); break; + case 0x1c: sprintf (buffer,"sr"); break; + case 0x1d: sprintf (buffer,"srl"); break; + case 0x1e: sprintf (buffer,"rr"); break; + case 0x1f: sprintf (buffer,"rrl"); break; + // Single Byte Miscellaneous Instructions + case 0x00: sprintf (buffer,"halt"); break; + case 0x02: sprintf (buffer,"ccl"); break; + case 0x03: sprintf (buffer,"scl"); break; + case 0x04: sprintf (buffer,"dint"); break; + case 0x05: sprintf (buffer,"ien"); break; + case 0x06: sprintf (buffer,"csa"); break; + case 0x07: sprintf (buffer,"cas"); break; + case 0x08: sprintf (buffer,"nop"); break; + // Others are illegal + default : sprintf (buffer,"illegal"); break; + } + } + + return (pc - PC); +} diff --git a/src/devices/cpu/score/score.c b/src/devices/cpu/score/score.c new file mode 100644 index 00000000000..a8e3dd210fc --- /dev/null +++ b/src/devices/cpu/score/score.c @@ -0,0 +1,1351 @@ +// license:BSD-3-Clause +// copyright-holders:Sandro Ronco +/****************************************************************************** + + Sunplus Technology S+core + by Sandro Ronco + +******************************************************************************/ + +#include "emu.h" +#include "debugger.h" +#include "score.h" + + +//************************************************************************** +// CONSTANTS +//************************************************************************** + +const device_type SCORE7 = &device_creator; + + +//************************************************************************** +// MACROS +//************************************************************************** + +#include "scorem.h" + + +//************************************************************************** +// Opcodes Tables +//************************************************************************** + +const score7_cpu_device::op_handler score7_cpu_device::s_opcode32_table[4*8] = +{ + &score7_cpu_device::op_specialform, &score7_cpu_device::op_iform1, &score7_cpu_device::op_jump , &score7_cpu_device::op_rixform1, &score7_cpu_device::op_branch, &score7_cpu_device::op_iform2, &score7_cpu_device::op_crform, &score7_cpu_device::op_rixform2, + &score7_cpu_device::op_addri , &score7_cpu_device::op_undef , &score7_cpu_device::op_undef, &score7_cpu_device::op_undef , &score7_cpu_device::op_andri , &score7_cpu_device::op_orri , &score7_cpu_device::op_undef , &score7_cpu_device::op_undef , + &score7_cpu_device::op_lw , &score7_cpu_device::op_lh , &score7_cpu_device::op_lhu , &score7_cpu_device::op_lb , &score7_cpu_device::op_sw , &score7_cpu_device::op_sh , &score7_cpu_device::op_lbu , &score7_cpu_device::op_sb , + &score7_cpu_device::op_cache , &score7_cpu_device::op_undef , &score7_cpu_device::op_undef, &score7_cpu_device::op_undef , &score7_cpu_device::op_cenew , &score7_cpu_device::op_undef , &score7_cpu_device::op_undef , &score7_cpu_device::op_undef +}; + +const score7_cpu_device::op_handler score7_cpu_device::s_opcode16_table[8] = +{ + &score7_cpu_device::op_rform1, &score7_cpu_device::op_undef, &score7_cpu_device::op_rform2, &score7_cpu_device::op_jform, &score7_cpu_device::op_branch16, &score7_cpu_device::op_ldiu, &score7_cpu_device::op_iform1a, &score7_cpu_device::op_iform1b +}; + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// score7_cpu_device - constructor +//------------------------------------------------- + +score7_cpu_device::score7_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : cpu_device(mconfig, SCORE7, "S+core 7", tag, owner, clock, "score7", __FILE__), + m_program_config("program", ENDIANNESS_LITTLE, 32, 32, 0), + m_pc(0), + m_ppc(0) +{ + memset(m_gpr, 0x00, sizeof(m_gpr)); + memset(m_cr, 0x00, sizeof(m_cr)); + memset(m_sr, 0x00, sizeof(m_sr)); + memset(m_ce, 0x00, sizeof(m_ce)); +} + +//------------------------------------------------- +// device_start - start up the device +//------------------------------------------------- + +void score7_cpu_device::device_start() +{ + // find address spaces + m_program = &space(AS_PROGRAM); + m_direct = &m_program->direct(); + + // set our instruction counter + m_icountptr = &m_icount; + + // register state for debugger + state_add(SCORE_PC , "PC" , m_pc).callimport().callexport().formatstr("%08X"); + + std::string tmp_string; + + for(int i=0; i<0x20; i++) + state_add(SCORE_GPR + i, strformat(tmp_string, "r%d", i).c_str(), m_gpr[i]).callimport().callexport().formatstr("%08X"); + + for(int i=0; i<0x20; i++) + state_add(SCORE_CR + i, strformat(tmp_string, "cr%d", i).c_str(), m_cr[i]).callimport().callexport().formatstr("%08X"); + + for(int i=0; i<3; i++) + state_add(SCORE_SR + i, strformat(tmp_string, "sr%d", i).c_str(), m_sr[i]).callimport().callexport().formatstr("%08X"); + + state_add(SCORE_CEH, "ceh", REG_CEH).callimport().callexport().formatstr("%08X"); + state_add(SCORE_CEL, "cel", REG_CEL).callimport().callexport().formatstr("%08X"); + + state_add(STATE_GENPC, "curpc", m_pc).callimport().callexport().formatstr("%08X").noshow(); + state_add(STATE_GENPCBASE, "curpcbase", m_ppc).callimport().callexport().formatstr("%8X").noshow(); + state_add(STATE_GENFLAGS, "GENFLAGS", m_ppc).formatstr("%5s").noshow(); + + // save state + save_item(NAME(m_pc)); + save_item(NAME(m_ppc)); + save_item(NAME(m_op)); + save_item(NAME(m_gpr)); + save_item(NAME(m_cr)); + save_item(NAME(m_sr)); + save_item(NAME(m_ce)); + save_item(NAME(m_pending_interrupt)); +} + + +//------------------------------------------------- +// device_reset - reset up the device +//------------------------------------------------- + +void score7_cpu_device::device_reset() +{ + // GPR are undefined at reset + memset(m_gpr,0, sizeof(m_gpr)); + memset(m_cr, 0, sizeof(m_cr)); + memset(m_sr, 0, sizeof(m_sr)); + memset(m_ce, 0, sizeof(m_ce)); + memset(m_pending_interrupt, 0, sizeof(m_pending_interrupt)); + + REG_EXCPVEC = m_pc = 0x9f000000; +} + + +//------------------------------------------------- +// state_string_export - export state as a string +// for the debugger +//------------------------------------------------- + +void score7_cpu_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + switch (entry.index()) + { + case STATE_GENFLAGS: + strprintf(str, "%s%s%s%s%s", + REG_CR & FLAG_V ? "V" : ".", + REG_CR & FLAG_C ? "C" : ".", + REG_CR & FLAG_Z ? "Z" : ".", + REG_CR & FLAG_N ? "N" : ".", + REG_CR & FLAG_T ? "T" : "." + ); + break; + } +} + + +//------------------------------------------------- +// memory_space_config - return the configuration +// of the specified address space, or NULL if +// the space doesn't exist +//------------------------------------------------- + +const address_space_config * score7_cpu_device::memory_space_config(address_spacenum spacenum) const +{ + return (spacenum == AS_PROGRAM) ? &m_program_config: NULL; +} + + +//------------------------------------------------- +// execute - execute for the provided number of +// cycles +//------------------------------------------------- + +void score7_cpu_device::execute_run() +{ + do + { + debugger_instruction_hook(this, m_pc); + + m_ppc = m_pc; + + check_irq(); + + UINT32 op = fetch(); + + switch(((op>>30) & 2) | ((op>>15) & 1)) + { + case 0: // 16-bit + 16-bit instruction + m_op = ((m_pc & 0x02) ? (op >> 16) : op) & 0x7fff; + m_pc += 2; + (this->*s_opcode16_table[(m_op >> 12) & 0x07])(); + break; + case 1: // undefined parity bit + m_pc += 4; + gen_exception(EXCEPTION_P_EL); + break; + case 2: // parallel conditional execution + m_op = (GET_T ? op: (op >> 16)) & 0x7fff; + m_pc += 4; + (this->*s_opcode16_table[(m_op >> 12) & 0x07])(); + break; + case 3: // 32-bit instruction + m_op = (op & 0x7fff) | ((op >> 1) & 0x3fff8000); + m_pc += 4; + (this->*s_opcode32_table[(m_op >> 25) & 0x01f])(); + break; + } + + m_icount -= 3; // FIXME: if available use correct cycles per instructions + } + while (m_icount > 0); +} + + +//------------------------------------------------- +// execute_set_input +//------------------------------------------------- + +void score7_cpu_device::execute_set_input(int inputnum, int state) +{ + switch (inputnum) + { + case 0: + if(state) + { + int vector = standard_irq_callback(0); + if (vector > 0 && vector < 64) + { + if((REG_PSR & 0x01) && state) + m_pending_interrupt[vector] = true; + } + } + break; + } +} + +//************************************************************************** +// HELPERS +//************************************************************************** + + +bool score7_cpu_device::check_condition_branch(UINT8 bc) +{ + if ((bc & 0x0f) == 14) // CNT>0, CNT-- + { + if (REG_CNT > 0) + { + REG_CNT--; + return true; + } + return false; + } + else + return check_condition(bc); +} + +bool score7_cpu_device::check_condition(UINT8 bc) +{ + switch(bc & 0x0f) + { + case 0: return GET_C; // carry set + case 1: return !GET_C; // carry clear + case 2: return GET_C && !GET_Z; // C & ~Z + case 3: return !GET_C || GET_Z; // ~C | Z + case 4: return GET_Z; // Z + case 5: return !GET_Z; // ~Z + case 6: return !GET_Z && (GET_N == GET_V); // (Z = 0) & (N = V) + case 7: return GET_Z || (GET_N != GET_V); // (Z = 1) | (N != V) + case 8: return (GET_N == GET_V); // N = V + case 9: return (GET_N != GET_V); // N != V + case 10: return GET_N; // N + case 11: return !GET_N; // ~N + case 12: return GET_V; // overflow V + case 13: return !GET_V; // no overflow ~V + case 14: return REG_CNT > 0; // CNT>0 + case 15: return true; // always + } + + return false; +} + +INT32 score7_cpu_device::sign_extend(UINT32 data, UINT8 len) +{ + data &= (1 << len) - 1; + UINT32 sign = 1 << (len - 1); + return (data ^ sign) - sign; +} + +UINT32 score7_cpu_device::fetch() +{ + return m_direct->read_dword(m_pc & ~3); +} + +UINT8 score7_cpu_device::read_byte(offs_t offset) +{ + return m_program->read_byte(offset); +} + +UINT16 score7_cpu_device::read_word(offs_t offset) +{ + return m_program->read_word(offset & ~1); +} + +UINT32 score7_cpu_device::read_dword(offs_t offset) +{ + return m_program->read_dword(offset & ~3); +} + +void score7_cpu_device::write_byte(offs_t offset, UINT8 data) +{ + m_program->write_byte(offset, data); +} + +void score7_cpu_device::write_word(offs_t offset, UINT16 data) +{ + m_program->write_word(offset & ~1, data); +} + +void score7_cpu_device::write_dword(offs_t offset, UINT32 data) +{ + m_program->write_dword(offset & ~3, data); +} + +void score7_cpu_device::check_irq() +{ + if(REG_PSR & 0x01) + { + for (int i=63; i>0; i--) + { + if (m_pending_interrupt[i]) + { + m_pending_interrupt[i] = false; + debugger_interrupt_hook(this, i); + gen_exception(EXCEPTION_INTERRUPT, i); + return; + } + } + } +} + +void score7_cpu_device::gen_exception(int cause, UINT32 param) +{ + debugger_exception_hook(this, cause); + + REG_ECR = (REG_ECR & ~0x0000001f) | (cause & 0x1f); // set exception cause + REG_PSR = (REG_PSR & ~0x0000000f) | ((REG_PSR << 2) & 0x0c); // push status bits + REG_CR = (REG_CR & ~0x000003ff) | ((REG_CR << 5) & 0x3e0); // push flag bits + REG_EPC = m_ppc & 0xfffffffe; // set return address + + switch(cause) + { + case EXCEPTION_P_EL: + REG_EMA = REG_EPC; + // intentional fallthrough + case EXCEPTION_NMI: + case EXCEPTION_CEE: + case EXCEPTION_SYSCALL: + case EXCEPTION_TRAP: + case EXCEPTION_RI: + m_pc = (REG_EXCPVEC & 0xffff0000) + 0x200; + break; + + case EXCEPTION_SWI: + case EXCEPTION_INTERRUPT: + REG_ECR = (REG_ECR & ~0x00fc0000) | ((param & 0x3f) << 18); // set irq source + m_pc = (REG_EXCPVEC & 0xffff0000) + 0x200 + (param << (REG_EXCPVEC & 1 ? 4 : 2)); + break; + + case EXCEPTION_ADEL_INSTRUCTION: + case EXCEPTION_BUSEL_INSTRUCTION: + case EXCEPTION_CCU: + case EXCEPTION_ADEL_DATA: + case EXCEPTION_ADES_DATA: + case EXCEPTION_CPE: + case EXCEPTION_BUSEL_DATA: + fatalerror("unhandled exception: %d 0x%08x (PC=0x%08x)\n", cause, param, m_ppc); + } +} + + +//************************************************************************** +// 32-bit opcodes +//************************************************************************** + +void score7_cpu_device::op_specialform() +{ + UINT8 ra = GET_S_RA(m_op); + UINT8 rb = GET_S_RB(m_op); + UINT8 rd = GET_S_RD(m_op); + UINT8 cu = GET_S_CU(m_op); + UINT32 r; + + switch(GET_S_FUNC6(m_op)) + { + case 0x00: // nop + break; + case 0x01: // syscall + gen_exception(EXCEPTION_SYSCALL); + break; + case 0x02: // trap + if (check_condition(rb)) + gen_exception(EXCEPTION_TRAP); + break; + case 0x03: // sdbbp + unemulated_op("sdbbp"); + break; + case 0x04: // br + if (check_condition_branch(rb)) + { + if (GET_S_LK(m_op)) + REG_LNK = m_pc; + + m_pc = m_gpr[ra]; + } + break; + case 0x05: // pflush + unemulated_op("pflush"); + break; + case 0x08: // add + r = m_gpr[ra] + m_gpr[rb]; + if (cu) + { + CHECK_Z(r); + CHECK_N(r); + CHECK_V_ADD(m_gpr[ra], m_gpr[rb], r); + CHECK_C_ADD(m_gpr[ra], m_gpr[rb]); + } + m_gpr[rd] = r; + break; + case 0x09: // addc + r = m_gpr[ra] + m_gpr[rb] + GET_C; + if (cu) + { + CHECK_Z(r); + CHECK_N(r); + CHECK_V_ADD(m_gpr[ra] + GET_C, m_gpr[rb], r); + CHECK_C_ADD(m_gpr[ra] + GET_C, m_gpr[rb]); + } + m_gpr[rd] = r; + break; + case 0x0a: // sub + r = m_gpr[ra] - m_gpr[rb]; + if (cu) + { + CHECK_Z(r); + CHECK_N(r); + CHECK_V_SUB(m_gpr[ra], m_gpr[rb], r); + CHECK_C_SUB(m_gpr[ra], m_gpr[rb]); + } + m_gpr[rd] = r; + break; + case 0x0b: // subc + r = m_gpr[ra] - m_gpr[rb] - (GET_C ^ 1); + if (cu) + { + CHECK_Z(r); + CHECK_N(r); + CHECK_V_SUB(m_gpr[ra] - (GET_C ^ 1), m_gpr[rb], r); + CHECK_C_SUB(m_gpr[ra] - (GET_C ^ 1), m_gpr[rb]); + } + m_gpr[rd] = r; + break; + case 0x0c: // cmp + if (cu) + { + r = m_gpr[ra] - m_gpr[rb]; + CHECK_Z(r); + CHECK_N(r); + CHECK_V_SUB(m_gpr[ra], m_gpr[rb], r); + CHECK_C_SUB(m_gpr[ra], m_gpr[rb]); + switch(rd & 0x03) + { + case 0: SET_T(GET_Z); break; + case 1: SET_T(GET_N); break; + } + } + break; + case 0x0d: // cmpz + if (cu) + { + r = m_gpr[ra] - 0; + CHECK_Z(r); + CHECK_N(r); + CHECK_V_SUB(m_gpr[ra], 0, r); + CHECK_C_SUB(m_gpr[ra], 0); + switch(rd & 0x03) + { + case 0: SET_T(GET_Z); break; + case 1: SET_T(GET_N); break; + } + } + break; + case 0x0f: // neg + r = 0 - m_gpr[rb]; + if (cu) + { + CHECK_Z(r); + CHECK_N(r); + CHECK_V_SUB(0, m_gpr[rb], r); + CHECK_C_SUB(0, m_gpr[rb]); + } + m_gpr[rd] = r; + break; + case 0x10: // and + m_gpr[rd] = m_gpr[ra] & m_gpr[rb]; + if (cu) + { + CHECK_Z(m_gpr[rd]); + CHECK_N(m_gpr[rd]); + } + break; + case 0x11: // or + m_gpr[rd] = m_gpr[ra] | m_gpr[rb]; + if (cu) + { + CHECK_Z(m_gpr[rd]); + CHECK_N(m_gpr[rd]); + } + break; + case 0x12: // not + r = ~m_gpr[ra]; + if (cu) + { + CHECK_Z(r); + CHECK_N(r); + } + m_gpr[rd] = r; + break; + case 0x13: // xor + m_gpr[rd] = m_gpr[ra] ^ m_gpr[rb]; + if (cu) + { + CHECK_Z(m_gpr[rd]); + CHECK_N(m_gpr[rd]); + } + break; + case 0x14: // bitclr + m_gpr[rd] = m_gpr[ra] & ~(1 << rb); + if (cu) + { + CHECK_Z(m_gpr[rd]); + CHECK_N(m_gpr[rd]); + } + break; + case 0x15: // bitset + m_gpr[rd] = m_gpr[ra] | (1 << rb); + if (cu) + { + CHECK_Z(m_gpr[rd]); + CHECK_N(m_gpr[rd]); + } + break; + case 0x16: // bittst + if (cu) + { + r = m_gpr[ra] & (1 << rb); + CHECK_N(m_gpr[ra]); + CHECK_Z(r); + } + break; + case 0x17: // bittgl + m_gpr[rd] = m_gpr[ra] ^ (1 << rb); + if (cu) + { + CHECK_Z(m_gpr[rd]); + CHECK_N(m_gpr[rd]); + } + break; + case 0x18: // sll + m_gpr[rd] = m_gpr[ra] << (m_gpr[rb] & 0x1f); + if (cu) + { + CHECK_Z(m_gpr[rd]); + CHECK_N(m_gpr[rd]); + SET_C(BIT(m_gpr[ra], 32 - (m_gpr[rb] & 0x1f))); + } + break; + case 0x1a: // srl + m_gpr[rd] = m_gpr[ra] >> (m_gpr[rb] & 0x1f); + if (cu) + { + CHECK_Z(m_gpr[rd]); + CHECK_N(m_gpr[rd]); + SET_C(BIT(m_gpr[ra], (m_gpr[rb] & 0x1f) - 1)); + } + break; + case 0x1b: // sra + m_gpr[rd] = sign_extend(m_gpr[ra] >> (m_gpr[rb] & 0x1f), 32 - (m_gpr[rb] & 0x1f)); + if (cu) + { + CHECK_Z(m_gpr[rd]); + CHECK_N(m_gpr[rd]); + SET_C(BIT(m_gpr[ra], (m_gpr[rb] & 0x1f) - 1)); + } + break; + case 0x1c: // ror + unemulated_op("ror"); + break; + case 0x1d: // rorc + unemulated_op("rorc"); + break; + case 0x1e: // rol + unemulated_op("rol"); + break; + case 0x1f: // rolc + unemulated_op("rolc"); + break; + case 0x20: // mul + { + INT64 a = (INT32)m_gpr[ra]; + INT64 b = (INT32)m_gpr[rb]; + UINT64 d = a * b; + REG_CEL = d & 0xffffffff; + REG_CEH = (d >> 32) & 0xffffffff; + break; + } + case 0x21: // mulu + { + UINT64 a = (UINT32)m_gpr[ra]; + UINT64 b = (UINT32)m_gpr[rb]; + UINT64 d = a * b; + REG_CEL = d & 0xffffffff; + REG_CEH = (d >> 32) & 0xffffffff; + break; + } + case 0x22: // div + if (m_gpr[rb]) + { + INT32 a = (INT32)m_gpr[ra]; + INT32 b = (INT32)m_gpr[rb]; + REG_CEL = a / b; + REG_CEH = a % b; + } + else + { + gen_exception(EXCEPTION_CEE); // divide by zero exception + } + break; + case 0x23: // divu + if (m_gpr[rb]) + { + UINT32 a = (UINT32)m_gpr[ra]; + UINT32 b = (UINT32)m_gpr[rb]; + REG_CEL = a / b; + REG_CEH = a % b; + } + else + { + gen_exception(EXCEPTION_CEE); // divide by zero exception + } + break; + case 0x24: // mfce + switch(rb & 3) + { + case 1: m_gpr[rd] = REG_CEL; break; + case 2: m_gpr[rd] = REG_CEH; break; + case 3: m_gpr[rd] = REG_CEH; m_gpr[ra] = REG_CEL; break; + } + break; + case 0x25: // mtce + switch(rb & 3) + { + case 1: REG_CEL = m_gpr[rd]; break; + case 2: REG_CEH = m_gpr[rd]; break; + case 3: REG_CEH = m_gpr[rd]; REG_CEL = m_gpr[ra]; break; + } + break; + case 0x28: // mfsr + if (rb < 3) + m_gpr[rd] = m_sr[rb]; + break; + case 0x29: // mtsr + if (rb < 3) + m_sr[rb] = m_gpr[ra]; + break; + case 0x2a: // t + SET_T(check_condition(rb)); + break; + case 0x2b: // mv + if ((rb & 0x0f) != 14 && check_condition(rb)) + m_gpr[rd] = m_gpr[ra]; + break; + case 0x2c: // extsb + case 0x2d: // extsh + m_gpr[rd] = sign_extend(m_gpr[ra], (GET_S_FUNC6(m_op) & 1) ? 16 : 8); + if (cu) + { + CHECK_N(m_gpr[rd]); + CHECK_Z(m_gpr[rd]); // undefined + } + break; + case 0x2e: // extzb + case 0x2f: // extzh + m_gpr[rd] = m_gpr[ra] & ((GET_S_FUNC6(m_op) & 1) ? 0xffff : 0x00ff); + if (cu) + { + CHECK_N(m_gpr[rd]); + CHECK_Z(m_gpr[rd]); // undefined + } + break; + case 0x30: // lcb + unemulated_op("lcb"); + break; + case 0x31: // lcw + unemulated_op("lcw"); + break; + case 0x33: // lce + unemulated_op("lce"); + break; + case 0x34: // scb + unemulated_op("scb"); + break; + case 0x35: // scw + unemulated_op("scw"); + break; + case 0x37: // sce + unemulated_op("sce"); + break; + case 0x38: // slli + m_gpr[rd] = m_gpr[ra] << rb; + if (cu) + { + CHECK_Z(m_gpr[rd]); + CHECK_N(m_gpr[rd]); + SET_C(BIT(m_gpr[ra], 32 - rb)); + } + break; + case 0x3a: // srli + m_gpr[rd] = m_gpr[ra] >> rb; + if (cu) + { + CHECK_Z(m_gpr[rd]); + CHECK_N(m_gpr[rd]); + SET_C(BIT(m_gpr[ra], rb - 1)); + } + break; + case 0x3b: // srai + m_gpr[rd] = sign_extend(m_gpr[ra] >> rb, 32 - rb); + if (cu) + { + CHECK_Z(m_gpr[rd]); + CHECK_N(m_gpr[rd]); + SET_C(BIT(m_gpr[ra], rb - 1)); + } + break; + case 0x3c: // rori + unemulated_op("rori"); + break; + case 0x3d: // roric + unemulated_op("roric"); + break; + case 0x3e: // roli + unemulated_op("roli"); + break; + case 0x3f: // rolic + unemulated_op("rolic"); + break; + default: + op_undef(); + } +} + +void score7_cpu_device::op_iform1() +{ + UINT8 rd = GET_I_RD(m_op); + UINT32 imm16 = GET_I_IMM16(m_op); + INT32 simm16 = sign_extend(imm16, 16); + UINT8 cu = GET_I_CU(m_op); + UINT32 r; + + switch(GET_I_FUNC3(m_op)) + { + case 0: // addi + r = m_gpr[rd] + simm16; + if (cu) + { + CHECK_Z(r); + CHECK_N(r); + CHECK_V_ADD(m_gpr[rd], (UINT32)simm16, r); + CHECK_C_ADD(m_gpr[rd], (UINT32)simm16); + } + m_gpr[rd] = r; + break; + case 2: // cmpi + if (cu) + { + r = m_gpr[rd] - simm16; + CHECK_Z(r); + CHECK_N(r); + CHECK_V_SUB(m_gpr[rd], (UINT32)simm16, r); + CHECK_C_SUB(m_gpr[rd], (UINT32)simm16); + } + break; + case 4: // andi + m_gpr[rd] = m_gpr[rd] & imm16; + if (cu) + { + CHECK_Z(m_gpr[rd]); + CHECK_N(m_gpr[rd]); + } + break; + case 5: // ori + m_gpr[rd] = m_gpr[rd] | imm16; + if (cu) + { + CHECK_Z(m_gpr[rd]); + CHECK_N(m_gpr[rd]); + } + break; + case 6: // ldi + m_gpr[rd] = simm16; + break; + default: + op_undef(); + } +} + +void score7_cpu_device::op_jump() +{ + if(GET_J_LK(m_op)) + REG_LNK = m_pc; + + m_pc = (m_ppc & 0xfe000000) | (GET_J_DISP24(m_op) << 1); +} + +void score7_cpu_device::op_rixform1() +{ + UINT8 ra = GET_RIX_RA(m_op); + UINT8 rd = GET_RIX_RD(m_op); + + // pre-increment + m_gpr[ra] += sign_extend(GET_RIX_IMM12(m_op), 12); + + switch(GET_RIX_FUNC3(m_op)) + { + case 0: // lw + m_gpr[rd] = read_dword(m_gpr[ra]); + break; + case 1: // lh + m_gpr[rd] = sign_extend(read_word(m_gpr[ra]), 16); + break; + case 2: // lhu + m_gpr[rd] = read_word(m_gpr[ra]); + break; + case 3: // lb + m_gpr[rd] = sign_extend(read_byte(m_gpr[ra]), 8); + break; + case 4: // sw + write_dword(m_gpr[ra], m_gpr[rd]); + break; + case 5: // sh + write_word(m_gpr[ra], m_gpr[rd] & 0xffff); + break; + case 6: // lbu + m_gpr[rd] = read_byte(m_gpr[ra]); + break; + case 7: // sb + write_byte(m_gpr[ra], m_gpr[rd] & 0xff); + break; + } +} + +void score7_cpu_device::op_branch() +{ + if (check_condition_branch(GET_BC_BC(m_op))) + { + INT32 disp = sign_extend(GET_BC_DISP19(m_op), 19) << 1; + if (GET_BC_LK(m_op)) + REG_LNK = m_pc; + + m_pc = m_ppc + disp; + } +} + +void score7_cpu_device::op_iform2() +{ + UINT8 rd = GET_I_RD(m_op); + UINT32 imm16 = GET_I_IMM16(m_op) << 16; + INT32 simm16 = (INT32)imm16; + UINT8 cu = GET_I_CU(m_op); + UINT32 r; + + switch(GET_I_FUNC3(m_op)) + { + case 0: // addis + r = m_gpr[rd] + simm16; + if (cu) + { + CHECK_Z(r); + CHECK_N(r); + CHECK_V_ADD(m_gpr[rd], imm16, r); + CHECK_C_ADD(m_gpr[rd], imm16); + } + m_gpr[rd] = r; + break; + case 2: // cmpis + if (cu) + { + r = m_gpr[rd] - simm16; + CHECK_Z(r); + CHECK_N(r); + CHECK_V_SUB(m_gpr[rd], imm16, r); + CHECK_C_SUB(m_gpr[rd], imm16); + } + break; + case 4: // andis + m_gpr[rd] = m_gpr[rd] & imm16; + if (cu) + { + CHECK_Z(m_gpr[rd]); + CHECK_N(m_gpr[rd]); + } + break; + case 5: // oris + m_gpr[rd] = m_gpr[rd] | imm16; + if (cu) + { + CHECK_Z(m_gpr[rd]); + CHECK_N(m_gpr[rd]); + } + break; + case 6: // ldis + m_gpr[rd] = imm16; + break; + default: + op_undef(); + } + +} + +void score7_cpu_device::op_crform() +{ + if ((REG_PSR & 0x08) && !(REG_PSR & 0x10000000)) + return; + + UINT8 cr = GET_CR_CR(m_op); + UINT8 rd = GET_CR_RD(m_op); + + switch(GET_CR_OP(m_op)) + { + case 0x00: // mtcr + m_cr[cr] = m_gpr[rd]; + break; + case 0x01: // mfcr + m_gpr[rd] = m_cr[cr]; + break; + case 0x84: // rte + REG_PSR = (REG_PSR & ~ 0x03) | ((REG_PSR >> 2) & 0x03); + REG_CR = (REG_CR & ~0x1f) | ((REG_CR >> 5) & 0x1f); + m_pc = REG_EPC; + break; + default: + if ((GET_CR_OP(m_op) & 0xc0) == 0) + fatalerror("%s: unemulated Coprocessor 0x%x (PC=0x%08x)\n", tag(), GET_CR_OP(m_op) & 0x07, m_ppc); + else + op_undef(); + } +} + +void score7_cpu_device::op_rixform2() +{ + UINT8 ra = GET_RIX_RA(m_op); + UINT8 rd = GET_RIX_RD(m_op); + + switch(GET_RIX_FUNC3(m_op)) + { + case 0: // lw + m_gpr[rd] = read_dword(m_gpr[ra]); + break; + case 1: // lh + m_gpr[rd] = sign_extend(read_word(m_gpr[ra]), 16); + break; + case 2: // lhu + m_gpr[rd] = read_word(m_gpr[ra]); + break; + case 3: // lb + m_gpr[rd] = sign_extend(read_byte(m_gpr[ra]), 8); + break; + case 4: // sw + write_dword(m_gpr[ra], m_gpr[rd]); + break; + case 5: // sh + write_word(m_gpr[ra], m_gpr[rd] & 0xffff); + break; + case 6: // lbu + m_gpr[rd] = read_byte(m_gpr[ra]); + break; + case 7: // sb + write_byte(m_gpr[ra], m_gpr[rd] & 0xff); + break; + } + + // post-increment + m_gpr[ra] += sign_extend(GET_RIX_IMM12(m_op), 12); +} + +void score7_cpu_device::op_addri() +{ + UINT8 ra = GET_RI_RA(m_op); + UINT8 rd = GET_RI_RD(m_op); + INT32 simm14 = sign_extend(GET_RI_IMM14(m_op), 14); + UINT8 cu = GET_RI_CU(m_op); + + UINT32 r = m_gpr[ra] + simm14; + if (cu) + { + CHECK_Z(r); + CHECK_N(r); + CHECK_V_ADD(m_gpr[ra], (UINT32)simm14, r); + CHECK_C_ADD(m_gpr[ra], (UINT32)simm14); + } + m_gpr[rd] = r; +} + +void score7_cpu_device::op_andri() +{ + UINT8 ra = GET_RI_RA(m_op); + UINT8 rd = GET_RI_RD(m_op); + UINT32 imm14 = GET_RI_IMM14(m_op); + + m_gpr[rd] = m_gpr[ra] & imm14; + + if (GET_RI_CU(m_op)) + { + CHECK_Z(m_gpr[rd]); + CHECK_N(m_gpr[rd]); + } +} + +void score7_cpu_device::op_orri() +{ + UINT8 ra = GET_RI_RA(m_op); + UINT8 rd = GET_RI_RD(m_op); + UINT32 imm14 = GET_RI_IMM14(m_op); + + m_gpr[rd] = m_gpr[ra] | imm14; + + if (GET_RI_CU(m_op)) + { + CHECK_Z(m_gpr[rd]); + CHECK_N(m_gpr[rd]); + } +} + +void score7_cpu_device::op_lw() +{ + UINT8 rd = GET_LS_RD(m_op); + UINT8 ra = GET_LS_RA(m_op); + INT32 simm15 = sign_extend(GET_LS_IMM15(m_op), 15); + + m_gpr[rd] = read_dword(m_gpr[ra] + simm15); +} + +void score7_cpu_device::op_lh() +{ + UINT8 rd = GET_LS_RD(m_op); + UINT8 ra = GET_LS_RA(m_op); + INT32 simm15 = sign_extend(GET_LS_IMM15(m_op), 15); + + m_gpr[rd] = sign_extend(read_word(m_gpr[ra] + simm15), 16); +} + +void score7_cpu_device::op_lhu() +{ + UINT8 rd = GET_LS_RD(m_op); + UINT8 ra = GET_LS_RA(m_op); + INT32 simm15 = sign_extend(GET_LS_IMM15(m_op), 15); + + m_gpr[rd] = read_word(m_gpr[ra] + simm15); +} + +void score7_cpu_device::op_lb() +{ + UINT8 rd = GET_LS_RD(m_op); + UINT8 ra = GET_LS_RA(m_op); + INT32 simm15 = sign_extend(GET_LS_IMM15(m_op), 15); + + m_gpr[rd] = sign_extend(read_byte(m_gpr[ra] + simm15), 8); +} + +void score7_cpu_device::op_sw() +{ + UINT8 rd = GET_LS_RD(m_op); + UINT8 ra = GET_LS_RA(m_op); + INT32 simm15 = sign_extend(GET_LS_IMM15(m_op), 15); + + write_dword(m_gpr[ra] + simm15, m_gpr[rd]); +} + +void score7_cpu_device::op_sh() +{ + UINT8 rd = GET_LS_RD(m_op); + UINT8 ra = GET_LS_RA(m_op); + INT32 simm15 = sign_extend(GET_LS_IMM15(m_op), 15); + + write_word(m_gpr[ra] + simm15, m_gpr[rd] & 0xffff); +} + +void score7_cpu_device::op_lbu() +{ + UINT8 rd = GET_LS_RD(m_op); + UINT8 ra = GET_LS_RA(m_op); + INT32 simm15 = sign_extend(GET_LS_IMM15(m_op), 15); + + m_gpr[rd] = read_byte(m_gpr[ra] + simm15); +} + +void score7_cpu_device::op_sb() +{ + UINT8 rd = GET_LS_RD(m_op); + UINT8 ra = GET_LS_RA(m_op); + INT32 simm15 = sign_extend(GET_LS_IMM15(m_op), 15); + + write_byte(m_gpr[ra] + simm15, m_gpr[rd] & 0xff); +} + +void score7_cpu_device::op_cache() +{ + //unemulated_op("CACHE"); +} + +void score7_cpu_device::op_cenew() +{ + unemulated_op("CENew"); +} + + +//************************************************************************** +// 16-bit opcodes +//************************************************************************** + +void score7_cpu_device::op_rform1() +{ + UINT8 rd = GET_R_RD(m_op); + UINT8 ra = GET_R_RA(m_op); + + switch(GET_R_FUNC4(m_op)) + { + case 0x00: // nop! + break; + case 0x01: // mlfh! + m_gpr[rd] = m_gpr[0x10 + ra]; + break; + case 0x02: // mhfl! + m_gpr[0x10 + rd] = m_gpr[ra]; + break; + case 0x03: // mv! + m_gpr[rd] = m_gpr[ra]; + break; + case 0x04: // br! + if (check_condition_branch(rd)) + m_pc = m_gpr[ra]; + break; + case 0x05: // t! + SET_T(check_condition(rd)); + break; + case 0x0c: // brl! + if (check_condition_branch(rd)) + { + REG_LNK = m_pc; + m_pc = m_gpr[ra]; + } + break; + default: + op_undef(); + } +} + +void score7_cpu_device::op_rform2() +{ + UINT8 rd = GET_R_RD(m_op); + UINT8 ra = GET_R_RA(m_op); + UINT32 r; + + switch(GET_R_FUNC4(m_op)) + { + case 0x00: // add! + r = m_gpr[rd] + m_gpr[ra]; + CHECK_Z(r); + CHECK_N(r); + CHECK_V_ADD(m_gpr[rd], m_gpr[ra], r); + CHECK_C_ADD(m_gpr[rd], m_gpr[ra]); + m_gpr[rd] = r; + break; + case 0x01: // sub! + r = m_gpr[rd] - m_gpr[ra]; + CHECK_Z(r); + CHECK_N(r); + CHECK_V_SUB(m_gpr[rd], m_gpr[ra], r); + CHECK_C_SUB(m_gpr[rd], m_gpr[ra]); + m_gpr[rd] = r; + break; + case 0x02: // neg! + m_gpr[rd] = 0 - m_gpr[ra]; + CHECK_Z(m_gpr[rd]); + CHECK_N(m_gpr[rd]); + CHECK_V_SUB(0, m_gpr[ra], m_gpr[rd]); + CHECK_C_SUB(0, m_gpr[ra]); + break; + case 0x03: // cmp! + r = m_gpr[rd] - m_gpr[ra]; + CHECK_Z(r); + CHECK_N(r); + CHECK_V_SUB(m_gpr[rd], m_gpr[ra], r); + CHECK_C_SUB(m_gpr[rd], m_gpr[ra]); + break; + case 0x04: // and! + m_gpr[rd] &= m_gpr[ra]; + CHECK_Z(m_gpr[rd]); + CHECK_N(m_gpr[rd]); + break; + case 0x05: // or! + m_gpr[rd] |= m_gpr[ra]; + CHECK_Z(m_gpr[rd]); + CHECK_N(m_gpr[rd]); + break; + case 0x06: // not! + m_gpr[rd] = ~m_gpr[ra]; + CHECK_Z(m_gpr[rd]); + CHECK_N(m_gpr[rd]); + break; + case 0x07: // xor! + m_gpr[rd] ^= m_gpr[ra]; + CHECK_Z(m_gpr[rd]); + CHECK_N(m_gpr[rd]); + break; + case 0x08: // lw! + m_gpr[rd] = read_dword(m_gpr[ra]); + break; + case 0x09: // lh! + m_gpr[rd] = sign_extend(read_word(m_gpr[ra]), 16); + break; + case 0x0a: // pop! + m_gpr[GET_P_RDG(m_op)] = read_dword(m_gpr[GET_P_RAG(m_op)]); + m_gpr[GET_P_RAG(m_op)] += 0x04; + break; + case 0x0b: // lbu! + m_gpr[rd] = read_byte(m_gpr[ra]); + break; + case 0x0c: // sw! + write_dword(m_gpr[ra], m_gpr[rd]); + break; + case 0x0d: // sh! + write_word(m_gpr[ra], m_gpr[rd] & 0xffff); + break; + case 0x0e: // push + m_gpr[GET_P_RAG(m_op)] -= 0x04; + write_dword(m_gpr[GET_P_RAG(m_op)], m_gpr[GET_P_RDG(m_op)]); + break; + case 0x0f: // sb! + write_byte(m_gpr[ra], m_gpr[rd] & 0xff); + break; + } +} + +void score7_cpu_device::op_jform() +{ + if(GET_J_LK(m_op)) + REG_LNK = m_pc; + + m_pc = (m_ppc & 0xfffff000) | (GET_J_DISP11(m_op) << 1); +} + +void score7_cpu_device::op_branch16() +{ + if(check_condition_branch(GET_BX_EC(m_op))) + m_pc = m_ppc + (sign_extend(GET_BX_DISP8(m_op), 8) << 1); +} + +void score7_cpu_device::op_ldiu() +{ + m_gpr[GET_I2_RD(m_op)] = GET_I2_IMM8(m_op); +} + +void score7_cpu_device::op_iform1a() +{ + UINT8 rd = GET_I16_RD(m_op); + UINT8 imm5 = GET_I16_IMM5(m_op); + + switch(GET_I16_FUNC3(m_op)) + { + case 0x00: // addei! + unemulated_op("addei!"); + break; + case 0x01: // slli! + m_gpr[rd] <<= imm5; + CHECK_Z(m_gpr[rd]); + CHECK_N(m_gpr[rd]); + break; + case 0x02: // sdbbp! + unemulated_op("sdbbp!"); + break; + case 0x03: // srli! + m_gpr[rd] >>= imm5; + CHECK_Z(m_gpr[rd]); + CHECK_N(m_gpr[rd]); + break; + case 0x04: // bitclr! + m_gpr[rd] &= ~(1 << imm5); + CHECK_Z(m_gpr[rd]); + CHECK_N(m_gpr[rd]); + break; + case 0x05: // bitset! + m_gpr[rd] |= (1 << imm5); + CHECK_Z(m_gpr[rd]); + CHECK_N(m_gpr[rd]); + break; + case 0x06: // bittst! + CHECK_N(m_gpr[rd]); + CHECK_Z(m_gpr[rd] & (1 << imm5)); + break; + default: + op_undef(); + } +} + +void score7_cpu_device::op_iform1b() +{ + UINT8 rd = GET_I16_RD(m_op); + UINT16 imm5 = GET_I16_IMM5(m_op); + + switch(GET_I16_FUNC3(m_op)) + { + case 0x00: // lwp! + m_gpr[rd] = read_dword(REG_BP + (imm5<<2)); + break; + case 0x01: // lhp! + m_gpr[rd] = sign_extend(read_word(REG_BP + (imm5<<1)), 16); + break; + case 0x03: // lbup! + m_gpr[rd] = read_byte(REG_BP + imm5); + break; + case 0x04: // swp! + write_dword(REG_BP + (imm5<<2), m_gpr[rd]); + break; + case 0x05: // shp! + write_word(REG_BP + (imm5<<1), m_gpr[rd] & 0xffff); + break; + case 0x07: // sbp! + write_byte(REG_BP + imm5, m_gpr[rd] & 0xff); + break; + default: + op_undef(); + } +} + +void score7_cpu_device::op_undef() +{ + logerror("%s: undefined instruction 0x%x (PC=0x%08x)\n", tag(), m_op, m_ppc); + gen_exception(EXCEPTION_RI); +} + +void score7_cpu_device::unemulated_op(const char * op) +{ + fatalerror("%s: unemulated %s (PC=0x%08x)\n", tag(), op, m_ppc); +} diff --git a/src/devices/cpu/score/score.h b/src/devices/cpu/score/score.h new file mode 100644 index 00000000000..e2c6dc15fef --- /dev/null +++ b/src/devices/cpu/score/score.h @@ -0,0 +1,150 @@ +// license:BSD-3-Clause +// copyright-holders:Sandro Ronco +/********************************************************************** + + Sunplus Technology S+core + +**********************************************************************/ + +#pragma once + +#ifndef __SCORE_H__ +#define __SCORE_H__ + + +//************************************************************************** +// DEFINITION +//************************************************************************** + +enum +{ + SCORE_PC = 1, + SCORE_CEH, + SCORE_CEL, + SCORE_GPR, + SCORE_CR = SCORE_GPR + 0x20, + SCORE_SR = SCORE_CR + 0x20 +}; + + +// ======================> score7_cpu_device + +class score7_cpu_device : public cpu_device +{ +public: + // construction/destruction + score7_cpu_device(const machine_config &mconfig, const char *_tag, device_t *_owner, UINT32 _clock); +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_execute_interface overrides + virtual UINT32 execute_min_cycles() const { return 1; } + virtual UINT32 execute_max_cycles() const { return 1; } + virtual UINT32 execute_input_lines() const { return 64; } + virtual void execute_run(); + virtual void execute_set_input(int inputnum, int state); + + // device_state_interface overrides + void state_string_export(const device_state_entry &entry, std::string &str); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const; + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const { return 2; } + virtual UINT32 disasm_max_opcode_bytes() const { return 4; } + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + +private: + // helpers + bool check_condition_branch(UINT8 bc); + bool check_condition(UINT8 bc); + INT32 sign_extend(UINT32 data, UINT8 len); + UINT32 fetch(); + UINT8 read_byte(offs_t offset); + UINT16 read_word(offs_t offset); + UINT32 read_dword(offs_t offset); + void write_byte(offs_t offset, UINT8 data); + void write_word(offs_t offset, UINT16 data); + void write_dword(offs_t offset, UINT32 data); + void check_irq(); + void gen_exception(int cause, UINT32 param = 0); + + offs_t disasm(char *buffer, offs_t pc, UINT32 opcode); + char *disasm32(char *buffer, offs_t pc, UINT32 opcode); + char *disasm16(char *buffer, offs_t pc, UINT16 opcode); + void unemulated_op(const char * op); + + // 32-bit opcodes + void op_specialform(); + void op_iform1(); + void op_jump(); + void op_rixform1(); + void op_branch(); + void op_iform2(); + void op_crform(); + void op_rixform2(); + void op_addri(); + void op_andri(); + void op_orri(); + void op_lw(); + void op_lh(); + void op_lhu(); + void op_lb(); + void op_sw(); + void op_sh(); + void op_lbu(); + void op_sb(); + void op_cache(); + void op_cenew(); + void op_undef(); + + // 16-bit opcodes + void op_rform1(); + void op_rform2(); + void op_jform(); + void op_branch16(); + void op_ldiu(); + void op_iform1a(); + void op_iform1b(); + +private: + address_space_config m_program_config; + address_space * m_program; + direct_read_data * m_direct; + + // internal state + int m_icount; + UINT32 m_pc; + UINT32 m_ppc; + UINT32 m_op; + UINT32 m_gpr[0x20]; + UINT32 m_cr[0x20]; + UINT32 m_sr[3]; + UINT32 m_ce[2]; + bool m_pending_interrupt[64]; + + // opcodes tables + typedef void (score7_cpu_device::*op_handler)(); + static const op_handler s_opcode32_table[4*8]; + static const op_handler s_opcode16_table[8]; + + // mnemonics + static const char *const m_cond[16]; + static const char *const m_tcs[4]; + static const char *const m_rix1_op[8]; + static const char *const m_rix2_op[8]; + static const char *const m_r2_op[16]; + static const char *const m_i1_op[8]; + static const char *const m_i2_op[8]; + static const char *const m_ls_op[8]; + static const char *const m_i1a_op[8]; + static const char *const m_i1b_op[8]; + static const char *const m_cr_op[2]; +}; + +extern const device_type SCORE7; + +#endif /* __SCORE_H__ */ diff --git a/src/devices/cpu/score/scoredsm.c b/src/devices/cpu/score/scoredsm.c new file mode 100644 index 00000000000..faac8140e51 --- /dev/null +++ b/src/devices/cpu/score/scoredsm.c @@ -0,0 +1,294 @@ +// license:BSD-3-Clause +// copyright-holders:Sandro Ronco +/****************************************************************************** + + Sunplus Technology S+core disassembler + +******************************************************************************/ + +#include "emu.h" +#include "score.h" +#include "scorem.h" + +const char *const score7_cpu_device::m_cond[16] = { "cs", "cc", "gtu", "leu", "eq", "ne", "gt", "le", "ge", "lt", "mi", "pl", "vs", "vc", "cnz", "" }; +const char *const score7_cpu_device::m_tcs[4] = { "teq", "tmi", "", ""}; +const char *const score7_cpu_device::m_rix1_op[8] = { "lw" ,"lh" ,"lhu" ,"lb" ,"sw" ,"sh" ,"lbu" ,"sb" }; +const char *const score7_cpu_device::m_rix2_op[8] = { "lw", "lh", "lhu", "lb", "sw", "sh", "lbu", "sb" }; +const char *const score7_cpu_device::m_r2_op[16] = { "add", "sub", "neg", "cmp", "and", "or", "not", "xor", "lw", "lh", "pop", "lbu", "sw", "sh", "push", "sb" }; +const char *const score7_cpu_device::m_i1_op[8] = { "addi", "", "cmpi", "", "andi", "ori", "ldi", "" }; +const char *const score7_cpu_device::m_i2_op[8] = { "addis", "", "cmpis", "", "andis", "oris", "ldis", "" }; +const char *const score7_cpu_device::m_ls_op[8] = { "lw", "lh", "lhu", "lb", "sw", "sh", "lbu", "sb" }; +const char *const score7_cpu_device::m_i1a_op[8] = { "addei", "slli", "sdbbp", "srli", "bitclr", "bitset", "bittst", "" }; +const char *const score7_cpu_device::m_i1b_op[8] = { "lwp", "lhp", "", "lbup", "swp", "shp", "", "sbp" }; +const char *const score7_cpu_device::m_cr_op[2] = { "mtcr", "mfcr" }; + + +char *score7_cpu_device::disasm32(char *buffer, offs_t pc, UINT32 opcode) +{ + switch((opcode >> 25) & 0x1f) + { + case 0x00: // Special-form + { + UINT8 ra = GET_S_RA(opcode); + UINT8 rb = GET_S_RB(opcode); + UINT8 rd = GET_S_RD(opcode); + const char *cu = GET_S_CU(opcode) ? ".c": ""; + const char *lk = GET_S_LK(opcode) ? "l": ""; + + switch(GET_S_FUNC6(opcode)) + { + case 0x00: buffer += sprintf(buffer, "nop"); break; + case 0x01: buffer += sprintf(buffer, "syscall 0x%04x", (rd<<10) | (ra << 5) | rb); break; + case 0x02: buffer += sprintf(buffer, "trap%s 0x%02x", m_cond[rb & 0x0f], ra); break; + case 0x03: buffer += sprintf(buffer, "sdbbp 0x%02x", ra); break; + case 0x04: buffer += sprintf(buffer, "br%s%s r%d", m_cond[rb & 0x0f], lk, ra); break; + case 0x05: buffer += sprintf(buffer, "pflush"); break; + case 0x08: buffer += sprintf(buffer, "add%s r%d, r%d, r%d", cu, rd, ra, rb); break; + case 0x09: buffer += sprintf(buffer, "addc%s r%d, r%d, r%d", cu, rd, ra, rb); break; + case 0x0a: buffer += sprintf(buffer, "sub%s r%d, r%d, r%d", cu, rd, ra, rb); break; + case 0x0b: buffer += sprintf(buffer, "subc%s r%d, r%d, r%d", cu, rd, ra, rb); break; + case 0x0c: buffer += sprintf(buffer, "cmp%s%s r%d, r%d", m_tcs[rd & 3], cu, ra, rb); break; + case 0x0d: buffer += sprintf(buffer, "cmpz%s%s r%d, r%d", m_tcs[rd & 3], cu, ra, rb); break; + case 0x0f: buffer += sprintf(buffer, "neg%s r%d, r%d", cu, rd, rb); break; + case 0x10: buffer += sprintf(buffer, "and%s r%d, r%d, r%d", cu, rd, ra, rb); break; + case 0x11: buffer += sprintf(buffer, "or%s r%d, r%d, r%d", cu, rd, ra, rb); break; + case 0x12: buffer += sprintf(buffer, "not%s r%d, r%d", cu, rd, ra); break; + case 0x13: buffer += sprintf(buffer, "xor%s r%d, r%d, r%d", cu, rd, ra, rb); break; + case 0x14: buffer += sprintf(buffer, "bitclr%s r%d, %d", cu, ra, rb); break; + case 0x15: buffer += sprintf(buffer, "bitset%s r%d, %d", cu, ra, rb); break; + case 0x16: buffer += sprintf(buffer, "bittst%s r%d, %d", cu, ra, rb); break; + case 0x17: buffer += sprintf(buffer, "bittgl%s r%d, %d", cu, ra, rb); break; + case 0x18: buffer += sprintf(buffer, "sll%s r%d, r%d, r%d", cu, rd, ra, rb); break; + case 0x1a: buffer += sprintf(buffer, "srl%s r%d, r%d, r%d", cu, rd, ra, rb); break; + case 0x1b: buffer += sprintf(buffer, "sra%s r%d, r%d, r%d", cu, rd, ra, rb); break; + case 0x1c: buffer += sprintf(buffer, "ror%s r%d, r%d, r%d", cu, rd, ra, rb); break; + case 0x1d: buffer += sprintf(buffer, "rorc%s r%d, r%d, r%d", cu, rd, ra, rb); break; + case 0x1e: buffer += sprintf(buffer, "rol%s r%d, r%d, r%d", cu, rd, ra, rb); break; + case 0x1f: buffer += sprintf(buffer, "rolc%s r%d, r%d, r%d", cu, rd, ra, rb); break; + case 0x20: buffer += sprintf(buffer, "mul r%d, r%d", ra, rb); break; + case 0x21: buffer += sprintf(buffer, "mulu r%d, r%d", ra, rb); break; + case 0x22: buffer += sprintf(buffer, "div r%d, r%d", ra, rb); break; + case 0x23: buffer += sprintf(buffer, "divu r%d, r%d", ra, rb); break; + case 0x24: + buffer += sprintf(buffer, "mfce%s%s r%d", rb & 2 ? "h" : "", rb & 1 ? "l" : "", rd); + if ((rb & 3) == 3) buffer += sprintf(buffer, ", r%d", ra); + break; + case 0x25: + buffer += sprintf(buffer, "mtce%s%s r%d", rb & 2 ? "h" : "", rb & 1 ? "l" : "", rd); + if ((rb & 3) == 3) buffer += sprintf(buffer, ", r%d", ra); + break; + case 0x28: buffer += sprintf(buffer, "mfsr sr%d, r%d", rb, ra); break; + case 0x29: buffer += sprintf(buffer, "mtsr r%d, sr%d", ra, rb); break; + case 0x2a: buffer += sprintf(buffer, "t%s r%d", m_cond[rb & 0x0f], rb); break; + case 0x2b: buffer += sprintf(buffer, "mv%s r%d, r%d", m_cond[rb & 0x0f], rd, ra); break; + case 0x2c: buffer += sprintf(buffer, "extsb%s r%d, r%d", cu, rd, ra); break; + case 0x2d: buffer += sprintf(buffer, "extsh%s r%d, r%d", cu, rd, ra); break; + case 0x2e: buffer += sprintf(buffer, "extzb%s r%d, r%d", cu, rd, ra); break; + case 0x2f: buffer += sprintf(buffer, "extzh%s r%d, r%d", cu, rd, ra); break; + case 0x30: buffer += sprintf(buffer, "lcb [r%d]+", ra); break; + case 0x31: buffer += sprintf(buffer, "lcw r%d, [r%d]+", rd, ra); break; + case 0x33: buffer += sprintf(buffer, "lce r%d, [r%d]+", rd, ra); break; + case 0x34: buffer += sprintf(buffer, "scb r%d, [r%d]+", rd, ra); break; + case 0x35: buffer += sprintf(buffer, "scw r%d, [r%d]+", rd, ra); break; + case 0x37: buffer += sprintf(buffer, "sce [r%d]+", ra); break; + case 0x38: buffer += sprintf(buffer, "slli r%d, r%d, %d", rd, ra, rb); break; + case 0x3a: buffer += sprintf(buffer, "srli r%d, r%d, %d", rd, ra, rb); break; + case 0x3b: buffer += sprintf(buffer, "srai r%d, r%d, %d", rd, ra, rb); break; + case 0x3c: buffer += sprintf(buffer, "rori%s r%d, r%d, %d", cu, rd, ra, rb); break; + case 0x3d: buffer += sprintf(buffer, "roric%s r%d, r%d, %d", cu, rd, ra, rb); break; + case 0x3e: buffer += sprintf(buffer, "roli%s r%d, r%d, %d", cu, rd, ra, rb); break; + case 0x3f: buffer += sprintf(buffer, "rolic%s r%d, r%d, %d", cu, rd, ra, rb); break; + default: buffer += sprintf(buffer, "", GET_S_FUNC6(opcode)); + } + break; + } + case 0x01: // I-form-1 + switch(GET_I_FUNC3(opcode)) + { + case 0x00: + buffer += sprintf(buffer, "%s%s r%d, %d", m_i1_op[GET_I_FUNC3(opcode)], GET_I_CU(opcode) ? ".c": "", GET_I_RD(opcode), sign_extend(GET_I_IMM16(opcode), 16)); + break; + case 0x02: case 0x04: case 0x05: case 0x06: + buffer += sprintf(buffer, "%s%s r%d, 0x%04x", m_i1_op[GET_I_FUNC3(opcode)], GET_I_CU(opcode) ? ".c": "", GET_I_RD(opcode), GET_I_IMM16(opcode)); + break; + default: + buffer += sprintf(buffer, "", GET_I_FUNC3(opcode)); + } + break; + case 0x02: + buffer += sprintf(buffer, "j%s 0x%08x", GET_J_LK(opcode) ? "l": "", (pc & 0xfc000000) | (GET_J_DISP24(opcode) << 1)); + break; + case 0x03: // RIX-form-1 + buffer += sprintf(buffer, "%s r%d, [R%d, %d]+", m_rix1_op[GET_RIX_FUNC3(opcode)], GET_RIX_RD(opcode), GET_RIX_RA(opcode), sign_extend(GET_RIX_IMM12(opcode), 12)); + break; + case 0x04: + buffer += sprintf(buffer, "b%s%s 0x%08x", m_cond[GET_BC_BC(opcode) & 0x0f], GET_BC_LK(opcode) ? "l": "", pc + (sign_extend(GET_BC_DISP19(opcode), 19) << 1)); + break; + case 0x05: // I-form-2 + switch(GET_I_FUNC3(opcode)) + { + case 0x00: case 0x02: + case 0x04: case 0x05: case 0x06: + buffer += sprintf(buffer, "%s%s r%d, 0x%04x", m_i2_op[GET_I_FUNC3(opcode)], GET_I_CU(opcode) ? ".c": "", GET_I_RD(opcode), GET_I_IMM16(opcode)); + break; + default: + buffer += sprintf(buffer, "", GET_I_FUNC3(opcode)); + } + break; + case 0x06: // CR-form + switch(GET_CR_OP(opcode)) + { + case 0x00: case 0x01: + buffer += sprintf(buffer, "%s r%d, cr%d", m_cr_op[GET_CR_OP(opcode)], GET_CR_RD(opcode), GET_CR_CR(opcode)); + break; + case 0x84: + buffer += sprintf(buffer, "rte"); + break; + default: + if ((GET_CR_OP(opcode) & 0xc0) == 0) + buffer += sprintf(buffer, "", GET_CR_OP(opcode) & 0x07); + else + buffer += sprintf(buffer, "", GET_S_FUNC6(opcode)); + } + break; + case 0x07: // RIX-form-2 + buffer += sprintf(buffer, "%s r%d, [R%d]+, %d", m_rix2_op[GET_RIX_FUNC3(opcode)], GET_RIX_RD(opcode), GET_RIX_RA(opcode), sign_extend(GET_RIX_IMM12(opcode), 12)); + break; + case 0x08: + buffer += sprintf(buffer, "addri%s r%d, r%d, %d", GET_RI_CU(opcode) ? ".c": "", GET_RI_RD(opcode), GET_RI_RA(opcode), sign_extend(GET_RI_IMM14(opcode), 14)); + break; + case 0x0c: + buffer += sprintf(buffer, "andri%s r%d, r%d, 0x%04x", GET_RI_CU(opcode) ? ".c": "", GET_RI_RD(opcode), GET_RI_RA(opcode), GET_RI_IMM14(opcode)); + break; + case 0x0d: + buffer += sprintf(buffer, "orri%s r%d, r%d, 0x%04x", GET_RI_CU(opcode) ? ".c": "", GET_RI_RD(opcode), GET_RI_RA(opcode), GET_RI_IMM14(opcode)); + break; + case 0x10: case 0x11: case 0x12: case 0x13: + case 0x14: case 0x15: case 0x16: case 0x17: + buffer += sprintf(buffer, "%s r%d, [r%d, %d]", m_ls_op[(opcode >> 25) & 0x07], GET_LS_RD(opcode), GET_LS_RA(opcode), sign_extend(GET_LS_IMM15(opcode), 15)); + break; + case 0x18: + buffer += sprintf(buffer, "cache 0x%02x, [r%d, %d]", GET_LS_RD(opcode), GET_LS_RA(opcode), sign_extend(GET_LS_IMM15(opcode), 15)); + break; + case 0x1c: + sprintf(buffer,"", opcode); + break; + default: + buffer += sprintf(buffer, "", opcode); + } + + return buffer; +} + +char *score7_cpu_device::disasm16(char *buffer, offs_t pc, UINT16 opcode) +{ + switch((opcode >> 12) & 0x07) + { + case 0x00: // R-form-1 + { + UINT8 rd = GET_R_RD(opcode); + UINT8 ra = GET_R_RA(opcode); + + switch(GET_R_FUNC4(opcode)) + { + case 0x00: buffer += sprintf(buffer, "nop!"); break; + case 0x01: buffer += sprintf(buffer, "mlfh! r%d, r%d", rd, 0x10 + ra); break; + case 0x02: buffer += sprintf(buffer, "mhfl! r%d, r%d", 0x10 + rd, ra); break; + case 0x03: buffer += sprintf(buffer, "mv! r%d, r%d", rd, ra); break; + case 0x04: buffer += sprintf(buffer, "br%s! r%d", m_cond[rd & 0x0f], ra); break; + case 0x05: buffer += sprintf(buffer, "t%s!", m_cond[rd & 0x0f]); break; + case 0x08: buffer += sprintf(buffer, "sll! r%d, r%d", rd, ra); break; + case 0x09: buffer += sprintf(buffer, "addc! r%d, r%d", rd, ra); break; + case 0x0a: buffer += sprintf(buffer, "srl! r%d, r%d", rd, ra); break; + case 0x0b: buffer += sprintf(buffer, "sra! r%d, r%d", rd, ra); break; + case 0x0c: buffer += sprintf(buffer, "br%sl! r%d", m_cond[rd & 0x0f], ra); break; + default: buffer += sprintf(buffer, "", GET_R_FUNC4(opcode)); + } + break; + } + case 0x02: // R-form-2 + switch(GET_R_FUNC4(opcode)) + { + case 0: case 1: case 2: case 3: + case 4: case 5: case 6: case 7: + buffer += sprintf(buffer, "%s! r%d, r%d", m_r2_op[GET_R_FUNC4(opcode)], GET_R_RD(opcode), GET_R_RA(opcode)); + break; + case 0x0a: case 0x0e: + buffer += sprintf(buffer, "%s! r%d, [r%d]", m_r2_op[GET_R_FUNC4(opcode)], GET_P_RDG(opcode), GET_P_RAG(opcode)); + break; + default: + buffer += sprintf(buffer, "%s! r%d, [r%d]", m_r2_op[GET_R_FUNC4(opcode)], GET_R_RD(opcode), GET_R_RA(opcode)); + } + break; + case 0x03: + buffer += sprintf(buffer, "j%s! 0x%08x", GET_J_LK(opcode) ? "l": "", (pc & 0xfffff000) | (GET_J_DISP11(opcode) << 1)); + break; + case 0x04: + buffer += sprintf(buffer, "b%s! 0x%08x", m_cond[GET_BX_EC(opcode) & 0x0f], pc + sign_extend(GET_BX_DISP8(opcode) << 1, 9)); + break; + case 0x05: + buffer += sprintf(buffer, "ldiu! r%d, 0x%02x", GET_I2_RD(opcode), GET_I2_IMM8(opcode)); + break; + case 0x06: // I-form-1a + if (GET_I16_FUNC3(opcode) != 7) + buffer += sprintf(buffer, "%s! r%d, %d", m_i1a_op[GET_I16_FUNC3(opcode)], GET_I16_RD(opcode), GET_I16_IMM5(opcode)); + else + buffer += sprintf(buffer, "", GET_I16_FUNC3(opcode)); + break; + case 0x07: // I-form-1b + switch(GET_I16_FUNC3(opcode)) + { + case 0: case 4: + buffer += sprintf(buffer, "%s! r%d, %d", m_i1b_op[GET_I16_FUNC3(opcode)], GET_I16_RD(opcode), GET_I16_IMM5(opcode)<<2); + break; + case 1: case 5: + buffer += sprintf(buffer, "%s! r%d, %d", m_i1b_op[GET_I16_FUNC3(opcode)], GET_I16_RD(opcode), GET_I16_IMM5(opcode)<<1); + break; + case 3: case 7: + buffer += sprintf(buffer, "%s! r%d, %d", m_i1b_op[GET_I16_FUNC3(opcode)], GET_I16_RD(opcode), GET_I16_IMM5(opcode)); + break; + default: + buffer += sprintf(buffer, "", GET_I16_FUNC3(opcode)); + } + break; + } + + return buffer; +} + +offs_t score7_cpu_device::disasm(char *buffer, offs_t pc, UINT32 opcode) +{ + UINT8 p = (pc & 0x02) ? 0 : (((opcode>>30) & 2) | ((opcode>>15) & 1)); + + switch(p) + { + case 0: // 16-bit + 16-bit instruction + buffer = disasm16(buffer, pc, opcode & 0x7fff); + break; + case 1: // undefined + buffer += sprintf(buffer,"", opcode); + break; + case 2: // parallel conditional execution + buffer = disasm16(buffer, pc, opcode & 0x7fff); + buffer += sprintf(buffer, " ||"); + break; + case 3: // 32-bit instruction + buffer = disasm32(buffer, pc, (opcode & 0x7fff) | ((opcode >> 1) & 0x3fff8000)); + break; + } + + return (p & 0x01) ? 4 : 2; +} + + +//------------------------------------------------- +// disasm_disassemble - call the disassembly +// helper function +//------------------------------------------------- + +offs_t score7_cpu_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + UINT32 opcode = oprom[0] | (oprom[1] << 8) | (oprom[2] << 16) | (oprom[3] << 24); + + return disasm(buffer, pc, opcode); +} diff --git a/src/devices/cpu/score/scorem.h b/src/devices/cpu/score/scorem.h new file mode 100644 index 00000000000..0f809e817fe --- /dev/null +++ b/src/devices/cpu/score/scorem.h @@ -0,0 +1,146 @@ +// license:BSD-3-Clause +// copyright-holders:Sandro Ronco + +// Special-form +#define GET_S_FUNC6(op) ((op >> 1) & 0x3f) +#define GET_S_RB(op) ((op >> 10) & 0x1f) +#define GET_S_RA(op) ((op >> 15) & 0x1f) +#define GET_S_RD(op) ((op >> 20) & 0x1f) +#define GET_S_CU(op) (op & 0x01) +#define GET_S_LK(op) (op & 0x01) + +// I-form +#define GET_I_FUNC3(op) ((op >> 17) & 0x07) +#define GET_I_IMM16(op) ((op >> 1) & 0xffff) +#define GET_I_RD(op) ((op >> 20) & 0x1f) +#define GET_I_CU(op) (op & 0x01) + +// RI-form +#define GET_RI_IMM14(op) ((op >> 1) & 0x3fff) +#define GET_RI_RA(op) ((op >> 15) & 0x1f) +#define GET_RI_RD(op) ((op >> 20) & 0x1f) +#define GET_RI_CU(op) (op & 0x01) + +// J-form +#define GET_J_DISP24(op) ((op >> 1) & 0x00ffffff) +#define GET_J_DISP11(op) ((op >> 1) & 0x000007ff) +#define GET_J_LK(op) (op & 0x01) + +// BC-form +#define GET_BC_DISP19(op) (((op >> 6) & 0x07fe00) | ((op >> 1) & 0x0001ff)) +#define GET_BC_BC(op) ((op >> 10) & 0x1f) +#define GET_BC_LK(op) (op & 0x01) + +// RIX-form +#define GET_RIX_FUNC3(op) (op & 0x07) +#define GET_RIX_IMM12(op) ((op >> 3) & 0x0fff) +#define GET_RIX_RA(op) ((op >> 15) & 0x1f) +#define GET_RIX_RD(op) ((op >> 20) & 0x1f) + +// R-form +#define GET_R_FUNC4(op) (op & 0x0f) +#define GET_R_RA(op) ((op >> 4) & 0x0f) +#define GET_R_RD(op) ((op >> 8) & 0x0f) + +// BX-form +#define GET_BX_DISP8(op) (op & 0xff) +#define GET_BX_EC(op) ((op >> 8) & 0x0f) + +// LS-form +#define GET_LS_RD(op) ((op >> 20) & 0x1f) +#define GET_LS_RA(op) ((op >> 15) & 0x1f) +#define GET_LS_IMM15(op) (op & 0x7fff) + +// I2-form +#define GET_I2_RD(op) ((op >> 8) & 0x0f) +#define GET_I2_IMM8(op) (op & 0xff) + +// I-form +#define GET_I16_FUNC3(op) (op & 0x07) +#define GET_I16_RD(op) ((op >> 8) & 0x0f) +#define GET_I16_IMM5(op) ((op >> 3) & 0x1f) + +// CR-form +#define GET_CR_OP(op) (op & 0xff) +#define GET_CR_IMM10(op) ((op >> 5) & 0x3ff) +#define GET_CR_CR(op) ((op >> 15) & 0x1f) +#define GET_CR_RD(op) ((op >> 20) & 0x1f) + +// PUSH/POP-form +#define GET_P_RAG(op) ((op >> 4) & 0x07) +#define GET_P_RDG(op) (((op >> 8) & 0x0f) | ((op >> 3) & 0x10)) + + +// flags +#define FLAG_V 0x01 +#define FLAG_C 0x02 +#define FLAG_Z 0x04 +#define FLAG_N 0x08 +#define FLAG_T 0x10 + +#define GET_V ((REG_CR & FLAG_V)>>0) +#define GET_C ((REG_CR & FLAG_C)>>1) +#define GET_Z ((REG_CR & FLAG_Z)>>2) +#define GET_N ((REG_CR & FLAG_N)>>3) +#define GET_T ((REG_CR & FLAG_T)>>4) + +#define SET_V(f) if (f) REG_CR |= FLAG_V; else REG_CR &= ~FLAG_V; +#define SET_C(f) if (f) REG_CR |= FLAG_C; else REG_CR &= ~FLAG_C; +#define SET_Z(f) if (f) REG_CR |= FLAG_Z; else REG_CR &= ~FLAG_Z; +#define SET_N(f) if (f) REG_CR |= FLAG_N; else REG_CR &= ~FLAG_N; +#define SET_T(f) if (f) REG_CR |= FLAG_T; else REG_CR &= ~FLAG_T; + +#define CHECK_Z(r) SET_Z((r)==0) +#define CHECK_N(r) SET_N((INT32)(r) < 0) +#define CHECK_C_ADD(a,b) SET_C((a) > (0xffffffffu - (b))) +#define CHECK_C_SUB(a,b) SET_C((a) >= (b)) +#define CHECK_V_ADD(a,b,d) SET_V((INT32)(((a) ^ (d)) & ((b) ^ (d))) < 0) +#define CHECK_V_SUB(a,b,d) SET_V((INT32)(((a) ^ (b)) & ((a) ^ (d))) < 0) + + +// registers +#define REG_BP m_gpr[2] +#define REG_LNK m_gpr[3] +#define REG_PSR m_cr[0] +#define REG_CR m_cr[1] +#define REG_ECR m_cr[2] +#define REG_EXCPVEC m_cr[3] +#define REG_CCR m_cr[4] +#define REG_EPC m_cr[5] +#define REG_EMA m_cr[6] +#define REG_TLBLOCK m_cr[7] +#define REG_TLBPT m_cr[8] +#define REG_PEADDR m_cr[9] +#define REG_TLBRPT m_cr[10] +#define REG_PEVN m_cr[11] +#define REG_PECTX m_cr[12] +#define REG_LIMPFN m_cr[15] +#define REG_LDMPFN m_cr[16] +#define REG_PREV m_cr[18] +#define REG_DREG m_cr[29] +#define REG_DEPC m_cr[30] +#define REG_DSAVE m_cr[31] +#define REG_CNT m_sr[0] +#define REG_LCR m_sr[1] +#define REG_SCR m_sr[2] +#define REG_CEH m_ce[0] +#define REG_CEL m_ce[1] + + +// exceptions causes +#define EXCEPTION_RESET 0 +#define EXCEPTION_NMI 1 +#define EXCEPTION_ADEL_INSTRUCTION 2 +#define EXCEPTION_BUSEL_INSTRUCTION 5 +#define EXCEPTION_P_EL 6 +#define EXCEPTION_SYSCALL 7 +#define EXCEPTION_CCU 8 +#define EXCEPTION_RI 9 +#define EXCEPTION_TRAP 10 +#define EXCEPTION_ADEL_DATA 11 +#define EXCEPTION_ADES_DATA 12 +#define EXCEPTION_CEE 16 +#define EXCEPTION_CPE 17 +#define EXCEPTION_BUSEL_DATA 18 +#define EXCEPTION_SWI 19 +#define EXCEPTION_INTERRUPT 20 diff --git a/src/devices/cpu/scudsp/scudsp.c b/src/devices/cpu/scudsp/scudsp.c new file mode 100644 index 00000000000..14d1565caa2 --- /dev/null +++ b/src/devices/cpu/scudsp/scudsp.c @@ -0,0 +1,1039 @@ +// license:BSD-3-Clause +// copyright-holders:Angelo Salese, Mariusz Wojcieszek +/***************************************************************************** + * + * scudsp.c + * Sega SCUDSP emulator version 1.00 + * + * copyright Angelo Salese & Mariusz Wojcieszek, all rights reserved + * + * Changelog: + * 131010: Angelo Salese + * - Converted to CPU structure + * + * 110807: Angelo Salese + * - Allow the Program Counter to be read-backable from SH-2, needed by Virtua Fighter to not + * get stuck on "round 1" announcement; + * + * 110806: Angelo Salese + * - Allows reading from non-work ram h areas; + * - Fixed DMA add values; + * - Fixed a MVI condition shift flag bug, now Sega Saturn produces sound during splash screen; + * - Removed left-over IRQ; + * + * 110722: Angelo Salese + * - Added DSP IRQ command, tested with "The King of Boxing" + * + * 110527: Angelo Salese + * - Fixed incorrectly setted execute flag clearance, allows animation of the Sega Saturn + * splash screen; + * + * 051129: Mariusz Wojcieszek + * - Fixed parallel instructions which increment CT registers to update CT register only + * once, after dsp operation is finished. This fixes instructions like + * MOV MC0,X MOV MC0,Y used by vfremix + * - Changed ALU 32bit instructions to not sign extend their result when loaded to ALU. + * This matches Sega's dspsim behaviour. + * - Changed DMA addnumber handling to match Sega's dspsim. + * + * 050813: Mariusz Wojcieszek + * - Fixed add number in DSP DMA + * + * 050412: Angelo Salese + * - Fixed the T0F behaviour in the DMA operation,it was causing an hang in Treasure Hunt + * due of that. + * - Removed the dsp.log file creation when you are not using the debug build + * + * 041114: Angelo Salese + * - Finished flags in ALU opcodes + * - SR opcode: MSB does not change. + * + * 040328: Mariusz Wojcieszek + * - rewritten ALU and MUL operations using signed arithmetics + * - improved DMA + * - fixed MOV ALH,x + * + * 031211: Mariusz Wojcieszek + * - result of ALU command is stored into ALU register + * - X-Bus command: MOV [s],X can be executed in parallel to other X-Bus commands + * - Y-Bus command: MOV [s],Y can be executed in parallel to other Y-Bus commands + * - Jump and LPS/BTM support: + * jump addresses are absolute, + * prefetched instructions are executed before jump is taken + * - after each instruction, X and Y is multiplied and contents are loaded into MUL register + * - fixed RL8 + * - fixed MVI + * - flags computation in MVI and JMP is partly guessed (because of errors in docs) + * - added reading DSP mem from SH2 side + * - overworked disassembler + * + * TODO: + * - Fix INSTA_DMA hack + * - Fix disassembler + * - Fix timings (no info available so far) + * - Add control flags + * - Croc: has a bug somewhere that never allows it to trip the ENDI opcode. + * Snippet of interest is: + * 08 00823500 CLR A MOV M0,PL + * 09 08040000 OR MOV ALU,A + * 0A D208000D JMP NZ,$D + * 0B 00000000 NOP + * 0C F8000000 ENDI + * + * 40 00863502 MOV M0,A MOV M2,PL + * 41 10003009 ADD MOV ALL,MC0 + * 42 D3400042 JMP T0,$42 + * 43 00000000 NOP + * 44 D0000007 JMP $7 + * + * + * + *****************************************************************************/ + +#include "emu.h" +#include "debugger.h" +#include "scudsp.h" + + +const device_type SCUDSP = &device_creator; + +/* FLAGS */ +#define PRF m_flags & 0x04000000 +#define EPF m_flags & 0x02000000 +#define T0F m_flags & 0x00800000 +#define SF (m_flags & 0x00400000) +#define ZF (m_flags & 0x00200000) +#define CF m_flags & 0x00100000 +#define VF m_flags & 0x00080000 +#define EF m_flags & 0x00040000 +#define ESF m_flags & 0x00020000 +#define EXF m_flags & 0x00010000 // execute flag (basically tied to RESET pin) +#define LEF m_flags & 0x00008000 // change PC value +#define T0F_1 m_flags|=0x00800000 +#define T0F_0 m_flags&=~0x00800000 +#define EXF_0 m_flags&=~0x00010000 +#define EF_1 m_flags|=0x00040000 + +#define SET_C(_val) (m_flags = ((m_flags & ~0x00100000) | ((_val) ? 0x00100000 : 0))) +#define SET_S(_val) (m_flags = ((m_flags & ~0x00400000) | ((_val) ? 0x00400000 : 0))) +#define SET_Z(_val) (m_flags = ((m_flags & ~0x00200000) | ((_val) ? 0x00200000 : 0))) +#define SET_V(_val) (m_flags = ((m_flags & ~0x00080000) | ((_val) ? 0x00080000 : 0))) + + +#define FLAGS_MASK 0x06ff8000 +#define INSTA_DMA 1 + +#define scudsp_readop(A) m_program->read_dword(A << 2) +#define scudsp_writeop(A, B) m_program->write_dword(A << 2, B) +#define scudsp_readmem(A,MD) m_data->read_dword((A | (MD << 6)) << 2) +#define scudsp_writemem(A,MD,B) m_data->write_dword((A | (MD << 6)) << 2, B) + +UINT32 scudsp_cpu_device::scudsp_get_source_mem_reg_value( UINT32 mode ) +{ + if ( mode < 0x8 ) + { + return scudsp_get_source_mem_value( mode ); + } + else + { + switch( mode ) + { + case 0x9: + return (UINT32)((m_alu & U64(0x00000000ffffffff)) >> 0); + case 0xA: + return (UINT32)((m_alu & U64(0x0000ffffffff0000)) >> 16); + } + } + return 0; +} + +UINT32 scudsp_cpu_device::scudsp_get_source_mem_value(UINT8 mode) +{ + UINT32 value = 0; + + switch( mode ) + { + case 0x0: /* M0 */ + value = scudsp_readmem(m_ct0,0); + break; + case 0x1: /* M1 */ + value = scudsp_readmem(m_ct1,1); + break; + case 0x2: /* M2 */ + value = scudsp_readmem(m_ct2,2); + break; + case 0x3: /* M3 */ + value = scudsp_readmem(m_ct3,3); + break; + case 0x4: /* MC0 */ + value = scudsp_readmem(m_ct0++,0); + m_ct0 &= 0x3f; + break; + case 0x5: /* MC1 */ + value = scudsp_readmem(m_ct1++,1); + m_ct1 &= 0x3f; + break; + case 0x6: /* MC2 */ + value = scudsp_readmem(m_ct2++,2); + m_ct2 &= 0x3f; + break; + case 0x7: /* MC3 */ + value = scudsp_readmem(m_ct3++,3); + m_ct3 &= 0x3f; + break; + } + + return value; +} + +void scudsp_cpu_device::scudsp_set_dest_mem_reg( UINT32 mode, UINT32 value ) +{ + switch( mode ) + { + case 0x0: /* MC0 */ + scudsp_writemem(m_ct0++,0,value); + m_ct0 &= 0x3f; + break; + case 0x1: /* MC1 */ + scudsp_writemem(m_ct1++,1,value); + m_ct1 &= 0x3f; + break; + case 0x2: /* MC2 */ + scudsp_writemem(m_ct2++,2,value); + m_ct2 &= 0x3f; + break; + case 0x3: /* MC3 */ + scudsp_writemem(m_ct3++,3,value); + m_ct3 &= 0x3f; + break; + case 0x4: /* RX */ + m_rx.ui = value; + break; + case 0x5: /* PL */ + m_pl.ui = value; + m_ph.si = (m_pl.si < 0) ? -1 : 0; + break; + case 0x6: /* RA0 */ + m_ra0 = value; + break; + case 0x7: /* WA0 */ + m_wa0 = value; + break; + case 0x8: + case 0x9: + /* ??? */ + break; + case 0xa: /* LOP */ + m_lop = value; + break; + case 0xb: /* TOP */ + m_top = value; + break; + case 0xc: /* CT0 */ + m_ct0 = value & 0x3f; + break; + case 0xd: /* CT1 */ + m_ct1 = value & 0x3f; + break; + case 0xe: /* CT2 */ + m_ct2 = value & 0x3f; + break; + case 0xf: /* CT3 */ + m_ct3 = value & 0x3f; + break; + } +} + +void scudsp_cpu_device::scudsp_set_dest_mem_reg_2( UINT32 mode, UINT32 value ) +{ + if ( mode < 0xb ) + { + scudsp_set_dest_mem_reg( mode, value ); + } + else + { + switch( mode ) + { + case 0xc: /* PC */ + m_delay = m_pc; /* address next after this command will be executed twice */ + m_top = m_pc; + m_pc = value; + break; + } + } +} + +UINT32 scudsp_cpu_device::scudsp_compute_condition( UINT32 condition ) +{ + UINT32 result = 0; + + switch( condition & 0xf ) + { + case 0x1: /* Z */ + result = ZF; + break; + case 0x2: /* S */ + result = SF; + break; + case 0x3: /* ZS */ + result = ZF | SF; + break; + case 0x4: /* C */ + result = CF; + break; + case 0x8: /* T0 */ + result = T0F; + break; + } + if ( !(condition & 0x20) ) + { + result = !result; + } + + return result; +} + +void scudsp_cpu_device::scudsp_set_dest_dma_mem( UINT32 memcode, UINT32 value, UINT32 counter ) +{ + if ( memcode < 4 ) + { + switch(memcode) + { + case 0x0: /* MC0 */ + scudsp_writemem(((m_ct0 + counter) & 0x3f),0,value); + break; + case 0x1: /* MC1 */ + scudsp_writemem(((m_ct1 + counter) & 0x3f),1,value); + break; + case 0x2: /* MC2 */ + scudsp_writemem(((m_ct2 + counter) & 0x3f),2,value); + break; + case 0x3: /* MC3 */ + scudsp_writemem(((m_ct3 + counter) & 0x3f),3,value); + break; + } + } + else if ( memcode == 4 ) + { + fatalerror("scudsp_set_dest_dma_mem == 4"); + /* caused a stack overflow for sure ... */ + //dsp_reg.internal_prg[ counter & 0x100 ] = value; + } +} + +UINT32 scudsp_cpu_device::scudsp_get_mem_source_dma( UINT32 memcode, UINT32 counter ) +{ + switch( memcode & 0x3 ) + { + case 0x0: + return scudsp_readmem(((m_ct0 + counter) & 0x3f),0); + case 0x1: + return scudsp_readmem(((m_ct1 + counter) & 0x3f),1); + case 0x2: + return scudsp_readmem(((m_ct2 + counter) & 0x3f),2); + case 0x3: + return scudsp_readmem(((m_ct3 + counter) & 0x3f),3); + } + return 0; +} + + +READ32_MEMBER( scudsp_cpu_device::program_control_r ) +{ + return (m_pc & 0xff) | (m_flags & FLAGS_MASK); +} + +WRITE32_MEMBER( scudsp_cpu_device::program_control_w ) +{ + UINT32 oldval, newval; + + oldval = (m_flags & 0xffffff00) | (m_pc & 0xff); + newval = oldval; + COMBINE_DATA(&newval); + + m_flags = newval & FLAGS_MASK; + + if(LEF) + m_pc = newval & 0xff; + + //printf("%08x PRG CTRL\n",data); + set_input_line(INPUT_LINE_RESET, (EXF) ? CLEAR_LINE : ASSERT_LINE); +} + +WRITE32_MEMBER( scudsp_cpu_device::program_w ) +{ + //printf("%02x %08x PRG\n",m_pc,data); + scudsp_writeop(m_pc++, data); +} + +WRITE32_MEMBER( scudsp_cpu_device::ram_address_control_w ) +{ + //printf("%02x %08x PRG\n",m_pc,data); + m_ra = data & 0xff; + + switch((m_ra & 0xc0) >> 6) + { + case 0: m_ct0 = (m_ra & 0x3f); break; + case 1: m_ct1 = (m_ra & 0x3f); break; + case 2: m_ct2 = (m_ra & 0x3f); break; + case 3: m_ct3 = (m_ra & 0x3f); break; + } +} + +READ32_MEMBER( scudsp_cpu_device::ram_address_r ) +{ + UINT32 data; + + data = scudsp_get_source_mem_value( ((m_ra & 0xc0) >> 6) + 4 ); + + return data; +} + +WRITE32_MEMBER( scudsp_cpu_device::ram_address_w ) +{ + scudsp_set_dest_mem_reg( (m_ra & 0xc0) >> 6, data ); +} + +void scudsp_cpu_device::scudsp_operation(UINT32 opcode) +{ + INT64 i1,i2; + INT32 i3; + int update_ct[4] = {0,0,0,0}; + int dsp_mem; + + + /* ALU */ + switch( (opcode & 0x3c000000) >> 26 ) + { + case 0x0: /* NOP */ + break; + case 0x1: /* AND */ + i3 = m_acl.si & m_pl.si; + m_alu = (UINT64)(UINT32)i3; + SET_Z(i3 == 0); + SET_C(0); + SET_S(i3 < 0); + break; + case 0x2: /* OR */ + i3 = m_acl.si | m_pl.si; + m_alu = (UINT64)(UINT32)i3; + SET_C(0); + SET_S(i3 < 0); + /* TODO: Croc and some early Psygnosis games wants Z to be 1 when the result of this one is negative. + Needs HW tests ... */ + if(i3 < 0) + i3 = 0; + SET_Z(i3 == 0); + break; + case 0x3: /* XOR */ + i3 = m_acl.si ^ m_pl.si; + m_alu = (UINT64)(UINT32)i3; + SET_Z(i3 == 0); + SET_C(0); + SET_S(i3 < 0); + break; + case 0x4: /* ADD */ + i3 = m_acl.si + m_pl.si; + m_alu = (UINT64)(UINT32)i3; + //SET_Z(i3 == 0); + SET_Z( (i3 & S64(0xffffffffffff)) == 0 ); + //SET_S(i3 < 0); + SET_S( i3 & S64(0x1000000000000)); + SET_C(i3 & S64(0x100000000)); + SET_V(((i3) ^ (m_acl.si)) & ((i3) ^ (m_pl.si)) & 0x80000000); + break; + case 0x5: /* SUB */ + i3 = m_acl.si - m_pl.si; + m_alu = (UINT64)(UINT32)i3; + SET_Z(i3 == 0); + SET_C(i3 & S64(0x100000000)); + SET_S(i3 < 0); + SET_V(((m_pl.si) ^ (m_acl.si)) & ((m_pl.si) ^ (i3)) & 0x80000000); + break; + case 0x6: /* AD2 */ + i1 = CONCAT_64((INT32)m_ph.si,m_pl.si); + i2 = CONCAT_64((INT32)m_ach.si,m_acl.si); + m_alu = i1 + i2; + SET_Z((m_alu & S64(0xffffffffffff)) == 0); + SET_S((m_alu & S64(0x800000000000)) > 0); + SET_C((m_alu) & S64(0x1000000000000)); + SET_V(((m_alu) ^ (i1)) & ((m_alu) ^ (i2)) & S64(0x800000000000)); + break; + case 0x7: /* ??? */ + /* Unrecognized opcode */ + break; + case 0x8: /* SR */ + i3 = (m_acl.si >> 1) | (m_acl.si & 0x80000000);/*MSB does not change*/ + m_alu = (UINT64)(UINT32)i3; + SET_Z(i3 == 0); + SET_S(i3 < 0); + SET_C(m_acl.ui & 0x80000000); + break; + case 0x9: /* RR */ + i3 = ((m_acl.ui >> 1) & 0x7fffffff) | ((m_acl.ui << 31) & 0x80000000); + m_alu = (UINT64)(UINT32)i3; + SET_Z( i3 == 0 ); + SET_S( i3 < 0 ); + SET_C( m_acl.ui & 0x1 ); + break; + case 0xa: /* SL */ + i3 = m_acl.si << 1; + m_alu = (UINT64)(UINT32)i3; + SET_Z( i3 == 0 ); + SET_S( i3 < 0 ); + SET_C( m_acl.ui & 0x80000000 ); + break; + case 0xB: /* RL */ + i3 = ((m_acl.si << 1) & 0xfffffffe) | ((m_acl.si >> 31) & 0x1); + m_alu = (UINT64)(UINT32)i3; + SET_Z( i3 == 0 ); + SET_S( i3 < 0 ); + SET_C( m_acl.ui & 0x80000000 ); + break; + case 0xc: + case 0xd: + case 0xe: + /* Unrecognized opcode */ + break; + case 0xF: /* RL8 */ + i3 = ((m_acl.si << 8) & 0xffffff00) | ((m_acl.si >> 24) & 0xff); + m_alu = i3; + SET_Z( i3 == 0 ); + SET_S( i3 < 0 ); + SET_C( m_acl.si & 0x01000000 ); + break; + } + + /* X-Bus */ + if ( opcode & 0x2000000 ) + { + /* MOV [s],X */ + dsp_mem = (opcode & 0x700000) >> 20; + if ( dsp_mem & 4 ) + { + dsp_mem &= 3; + update_ct[dsp_mem] = 1; + } + m_rx.ui = scudsp_get_source_mem_value( dsp_mem ); + m_update_mul = 1; + } + switch( (opcode & 0x1800000) >> 23 ) + { + case 0x0: /* NOP */ + case 0x1: /* NOP ? */ + break; + case 0x2: /* MOV MUL,P */ + m_ph.ui = (UINT16)((m_mul & U64(0x0000ffff00000000)) >> 32); + m_pl.ui = (UINT32)((m_mul & U64(0x00000000ffffffff)) >> 0); + break; + case 0x3: /* MOV [s],P */ + dsp_mem = (opcode & 0x700000) >> 20; + if ( dsp_mem & 4 ) + { + dsp_mem &= 3; + update_ct[dsp_mem] = 1; + } + m_pl.ui = scudsp_get_source_mem_value( dsp_mem ); + m_ph.si = (m_pl.si < 0) ? -1 : 0; + break; + } + + /* Y-Bus */ + if ( opcode & 0x80000 ) + { + /* MOV [s],Y */ + dsp_mem = (opcode & 0x1C000 ) >> 14; + if (dsp_mem & 4) + { + dsp_mem &= 3; + update_ct[dsp_mem] = 1; + } + m_ry.ui = scudsp_get_source_mem_value( dsp_mem ); + m_update_mul = 1; + } + switch( (opcode & 0x60000) >> 17 ) + { + case 0x0: /* NOP */ + break; + case 0x1: /* CLR A */ + m_acl.ui = 0; + m_ach.ui = 0; + break; + case 0x2: /* MOV ALU,A */ + m_ach.ui = (UINT16)((m_alu & U64(0x0000ffff00000000)) >> 32); + m_acl.ui = (UINT32)((m_alu & U64(0x00000000ffffffff)) >> 0); + break; + case 0x3: /* MOV [s], A */ + dsp_mem = (opcode & 0x1C000 ) >> 14; + if (dsp_mem & 4) + { + dsp_mem &= 3; + update_ct[dsp_mem] = 1; + } + m_acl.ui = scudsp_get_source_mem_value( dsp_mem ); + m_ach.si = ((m_acl.si < 0) ? -1 : 0); + break; + } + + /* update CT registers */ + if ( update_ct[0] ) { m_ct0++; m_ct0 &= 0x3f; }; + if ( update_ct[1] ) { m_ct1++; m_ct1 &= 0x3f; }; + if ( update_ct[2] ) { m_ct2++; m_ct2 &= 0x3f; }; + if ( update_ct[3] ) { m_ct3++; m_ct3 &= 0x3f; }; + + + /* D1-Bus */ + switch( (opcode & 0x3000) >> 12 ) + { + case 0x0: /* NOP */ + break; + case 0x1: /* MOV SImm,[d] */ + scudsp_set_dest_mem_reg( (opcode & 0xf00) >> 8, (INT32)(INT8)(opcode & 0xff) ); + break; + case 0x2: + /* ??? */ + break; + case 0x3: /* MOV [s],[d] */ + scudsp_set_dest_mem_reg( (opcode & 0xf00) >> 8, scudsp_get_source_mem_reg_value( opcode & 0xf ) ); + break; + } + + m_icount -= 1; +} + +void scudsp_cpu_device::scudsp_move_immediate( UINT32 opcode ) +{ + UINT32 value; + + if ( opcode & 0x2000000 ) + { + if ( scudsp_compute_condition( (opcode & 0x3F80000 ) >> 19 ) ) + { + value = opcode & 0x7ffff; + if ( value & 0x40000 ) value |= 0xfff80000; + scudsp_set_dest_mem_reg_2( (opcode & 0x3C000000) >> 26, value ); + } + } + else + { + value = opcode & 0x1ffffff; + if ( value & 0x1000000 ) value |= 0xfe000000; + scudsp_set_dest_mem_reg_2( (opcode & 0x3C000000) >> 26, value ); + } + m_icount -= 1; +} + +void scudsp_cpu_device::scudsp_dma( UINT32 opcode ) +{ + UINT8 hold = (opcode & 0x4000) >> 14; + UINT32 add = (opcode & 0x38000) >> 15; + UINT32 dir_from_D0 = (opcode & 0x1000 ) >> 12; + UINT32 dsp_mem = (opcode & 0x300) >> 8; + + T0F_1; + + if ( opcode & 0x2000 ) + { + m_dma.size = scudsp_get_source_mem_value( opcode & 0xf ); + switch ( add & 0x7 ) + { + case 0: m_dma.add = 0; break; + case 1: m_dma.add = 4; break; + default: m_dma.add = 4; break; + } + } + else + { + m_dma.size = opcode & 0xff; + switch( add ) + { + case 0: m_dma.add = 0; break; /* 0 */ + case 1: m_dma.add = 4; break; /* 1 */ + case 2: m_dma.add = 4; break; /* 2 */ + case 3: m_dma.add = 16; break; /* 4 */ + case 4: m_dma.add = 16; break; /* 8 */ + case 5: m_dma.add = 64; break; /* 16 */ + case 6: m_dma.add = 128; break; /* 32 */ + case 7: m_dma.add = 256; break; /* 64 */ + } + } + + m_dma.dir = dir_from_D0; + if ( m_dma.dir == 0 ) + { + m_dma.src = (m_ra0 << 2) & 0x07ffffff; + m_dma.dst = dsp_mem; + } + else + { + m_dma.src = dsp_mem; + m_dma.dst = (m_wa0 << 2) & 0x07ffffff; + } + + m_dma.update = ( hold == 0 ); + m_dma.ex = 1; + m_dma.count = 0; + /* HACK ALERT: It looks like that scheduling craps out the m_dma parameters, why this happens I don't know ... */ + #if INSTA_DMA + { + UINT32 data; + if ( m_dma.dir == 0 ) + { + for(m_dma.count = 0;m_dma.count < m_dma.size; m_dma.count++) + { + data = (m_in_dma_cb(m_dma.src)<<16) | m_in_dma_cb(m_dma.src+2); + scudsp_set_dest_dma_mem( m_dma.dst, data, m_dma.count ); + + m_dma.src += m_dma.add; + + if ( m_dma.update ) + { + m_ra0 += ((1 * m_dma.add) >> 2); + } + } + } + else + { + for(m_dma.count = 0;m_dma.count < m_dma.size; m_dma.count++) + { + data = scudsp_get_mem_source_dma( m_dma.src, m_dma.count ); + + m_out_dma_cb(m_dma.dst, data >> 16 ); + m_out_dma_cb(m_dma.dst+2, data & 0xffff ); + + m_dma.dst += m_dma.add; + + if ( m_dma.update ) + { + m_wa0 += ((1 * m_dma.add) >> 2); + } + } + } + + //if(m_dma.count >= m_dma.size) + { + m_dma.ex = 0; + T0F_0; + } + + m_icount -= m_dma.size; + } + #endif + + + //printf("SRC %08x DST %08x SIZE %08x UPDATE %08x DIR %08x ADD %08x\n",m_dma.src,m_dma.dst,m_dma.size,m_dma.update,m_dma.dir,m_dma.add); + + m_icount -= 1; +} + +void scudsp_cpu_device::scudsp_jump( UINT32 opcode ) +{ + if ( opcode & 0x3f80000 ) + { + if ( scudsp_compute_condition( (opcode & 0x3f80000) >> 19 ) ) + { + m_delay = m_pc; + m_pc = opcode & 0xff; + } + } + else + { + m_delay = m_pc; + m_pc = opcode & 0xff; + } + + m_icount -= 1; +} + +void scudsp_cpu_device::scudsp_loop(UINT32 opcode) +{ + if ( opcode & 0x8000000 ) + { + /* LPS */ + if ( m_lop != 0 ) + { + m_lop--; + m_delay = m_pc; + m_pc--; + } + } + else + { + /* BTM */ + if ( m_lop != 0 ) + { + m_lop--; + m_delay = m_pc; + m_pc = m_top; + } + } + m_icount -= 1; +} + +void scudsp_cpu_device::scudsp_end(UINT32 opcode) +{ + if(opcode & 0x08000000) + { + /*ENDI*/ + EF_1; + m_out_irq_cb(1); + } + + EXF_0; /* END / ENDI */ + set_input_line(INPUT_LINE_RESET, ASSERT_LINE); + m_icount -= 1; +} + +void scudsp_cpu_device::scudsp_illegal(UINT32 opcode) +{ + fatalerror("scudsp illegal opcode at 0x%04x\n", m_pc); + m_icount -= 1; +} + +void scudsp_cpu_device::scudsp_exec_dma() +{ + UINT32 data; + if ( m_dma.dir == 0 ) + { + data = (m_in_dma_cb(m_dma.src)<<16) | m_in_dma_cb(m_dma.src+2); + scudsp_set_dest_dma_mem( m_dma.dst, data, m_dma.count ); + + m_dma.src += m_dma.add; + + if ( m_dma.update ) + { + m_ra0 += ((1 * m_dma.add) >> 2); + } + } + else + { + data = scudsp_get_mem_source_dma( m_dma.src, m_dma.count ); + + m_out_dma_cb(m_dma.dst, data >> 16 ); + m_out_dma_cb(m_dma.dst+2, data & 0xffff ); + + m_dma.dst += m_dma.add; + + if ( m_dma.update ) + { + m_wa0 += ((1 * m_dma.add) >> 2); + } + } + + m_dma.count++; + if(m_dma.count >= m_dma.size) + { + m_dma.ex = 0; + T0F_0; + } + + m_icount -= 1; +} + +/* Execute cycles */ +void scudsp_cpu_device::execute_run() +{ + UINT32 opcode; + + do + { + m_update_mul = 0; + + debugger_instruction_hook(this, m_pc); + + if ( m_delay ) + { + opcode = scudsp_readop(m_delay); + m_delay = 0; + } + else + { + opcode = scudsp_readop(m_pc); + m_pc++; + } + + switch( (opcode & 0xc0000000) >> 30 ) + { + case 0x00: /* 00 */ + scudsp_operation(opcode); + break; + case 0x01: /* 01 */ + scudsp_illegal(opcode); + break; + case 0x02: /* 10 */ + scudsp_move_immediate(opcode); + break; + case 0x03: /* 11 */ + switch( (opcode & 0x30000000) >> 28 ) + { + case 0x00: + scudsp_dma(opcode); + break; + case 0x01: + scudsp_jump(opcode); + break; + case 0x02: + scudsp_loop(opcode); + break; + case 0x03: + scudsp_end(opcode); + break; + } + break; + } + + if ( m_update_mul == 1 ) + { + m_mul = (INT64)m_rx.si * (INT64)m_ry.si; + m_update_mul = 0; + } + + if (m_dma.ex == 1) + { + scudsp_exec_dma(); + } + + } while( m_icount > 0 ); +} + +void scudsp_cpu_device::device_start() +{ + m_pc = 0; + m_flags = 0; + m_delay = 0; + m_top = 0; + m_lop = 0; + memset(&m_rx, 0x00, sizeof(m_rx)); + m_mul = 0; + memset(&m_ry, 0x00, sizeof(m_ry)); + m_alu = 0; + memset(&m_ph, 0x00, sizeof(m_ph)); + memset(&m_pl, 0x00, sizeof(m_pl)); + memset(&m_ach, 0x00, sizeof(m_ach)); + memset(&m_acl, 0x00, sizeof(m_acl)); + m_ra0 = 0; + m_wa0 = 0; + m_ra = 0; + m_ct0 = 0; + m_ct1 = 0; + m_ct2 = 0; + m_ct3 = 0; + memset(&m_dma, 0x00, sizeof(m_dma)); + + m_program = &space(AS_PROGRAM); + m_data = &space(AS_DATA); + + save_item(NAME(m_pc)); + save_item(NAME(m_ra)); + + save_item(NAME(m_ct0)); + save_item(NAME(m_ct1)); + save_item(NAME(m_ct2)); + save_item(NAME(m_ct3)); + + save_item(NAME(m_flags)); + save_item(NAME(m_delay)); + + save_item(NAME(m_top)); + save_item(NAME(m_lop)); + save_item(NAME(m_rx.ui)); + + save_item(NAME(m_mul)); + + save_item(NAME(m_ry.ui)); + + save_item(NAME(m_alu)); + save_item(NAME(m_ph.ui)); + save_item(NAME(m_pl.ui)); + save_item(NAME(m_ach.ui)); + save_item(NAME(m_acl.ui)); + save_item(NAME(m_ra0)); + save_item(NAME(m_wa0)); + + save_item(NAME(m_dma.src)); + save_item(NAME(m_dma.dst)); + save_item(NAME(m_dma.size)); + + // Register state for debugger + state_add( SCUDSP_PC, "PC", m_pc ).formatstr("%02X"); + state_add( SCUDSP_FLAGS, "SR", m_flags ).formatstr("%08X"); + state_add( SCUDSP_DELAY, "DELAY", m_delay ).formatstr("%02X").noshow(); + state_add( SCUDSP_TOP, "TOP", m_top).formatstr("%02X"); + state_add( SCUDSP_LOP, "LOP", m_lop).formatstr("%03X"); + state_add( SCUDSP_RX, "RX", m_rx).formatstr("%08X"); + state_add( SCUDSP_MUL, "MUL", m_mul).formatstr("%012X"); + state_add( SCUDSP_RY, "RY", m_ry).formatstr("%08X"); + state_add( SCUDSP_ALU, "ALU", m_alu).formatstr("%012X"); + state_add( SCUDSP_PH, "PH", m_ph).formatstr("%04X"); + state_add( SCUDSP_PL, "PL", m_pl).formatstr("%08X"); + state_add( SCUDSP_ACH, "ACH", m_ach).formatstr("%04X"); + state_add( SCUDSP_ACL, "ACL", m_acl).formatstr("%08X"); + state_add( SCUDSP_RA0, "RA0", m_ra0).formatstr("%08X"); + state_add( SCUDSP_WA0, "WA0", m_wa0).formatstr("%08X"); + state_add( SCUDSP_RA, "RA", m_ra ).formatstr("%02X"); + state_add( SCUDSP_CT0, "CT0", m_ct0 ).formatstr("%02X"); + state_add( SCUDSP_CT1, "CT1", m_ct1 ).formatstr("%02X"); + state_add( SCUDSP_CT2, "CT2", m_ct2 ).formatstr("%02X"); + state_add( SCUDSP_CT3, "CT3", m_ct3 ).formatstr("%02X"); + state_add( STATE_GENPC, "curpc", m_pc ).noshow(); + state_add( STATE_GENFLAGS, "GENFLAGS", m_flags ).formatstr("%17s").noshow(); + + m_out_irq_cb.resolve_safe(); + m_in_dma_cb.resolve_safe(0); + m_out_dma_cb.resolve_safe(); + + m_icountptr = &m_icount; +} + +void scudsp_cpu_device::device_reset() +{ +} + +void scudsp_cpu_device::execute_set_input(int irqline, int state) +{ + switch(irqline) + { + case SCUDSP_RESET: + //m_reset_state = state; + break; + } +} + +scudsp_cpu_device::scudsp_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : cpu_device(mconfig, SCUDSP, "SCUDSP", tag, owner, clock, "scudsp", __FILE__) + , m_out_irq_cb(*this) + , m_in_dma_cb(*this) + , m_out_dma_cb(*this) + , m_program_config("program", ENDIANNESS_BIG, 32, 8, -2) + , m_data_config("data", ENDIANNESS_BIG, 32, 8, -2) +{ +} + + +void scudsp_cpu_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + switch (entry.index()) + { + case STATE_GENFLAGS: + strprintf(str, "%s%s%s%c%c%c%c%c%s%s%s", + m_flags & 0x4000000 ? "PR":"..", + m_flags & 0x2000000 ? "EP":"..", + m_flags & 0x800000 ? "T0":"..", + m_flags & 0x400000 ? 'S':'.', + m_flags & 0x200000 ? 'Z':'.', + m_flags & 0x100000 ? 'C':'.', + m_flags & 0x80000 ? 'V':'.', + m_flags & 0x40000 ? 'E':'.', + m_flags & 0x20000 ? "ES":"..", + m_flags & 0x10000 ? "EX":"..", + m_flags & 0x8000 ? "LE":".."); + break; + } +} + + +offs_t scudsp_cpu_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( scudsp ); + return CPU_DISASSEMBLE_NAME(scudsp)(this, buffer, pc, oprom, opram, options); +} diff --git a/src/devices/cpu/scudsp/scudsp.h b/src/devices/cpu/scudsp/scudsp.h new file mode 100644 index 00000000000..ac46450a9d4 --- /dev/null +++ b/src/devices/cpu/scudsp/scudsp.h @@ -0,0 +1,164 @@ +// license:BSD-3-Clause +// copyright-holders:Angelo Salese, Mariusz Wojcieszek +/***************************************************************************** + * + * Sega SCUDSP emulator + * + *****************************************************************************/ + +#pragma once + +#ifndef __SCUDSP_H__ +#define __SCUDSP_H__ + +enum +{ + SCUDSP_PC=1, + SCUDSP_FLAGS, + SCUDSP_DELAY, + SCUDSP_TOP, + SCUDSP_LOP, + SCUDSP_RX, + SCUDSP_MUL, + SCUDSP_RY, + SCUDSP_ALU, + SCUDSP_PH, + SCUDSP_PL, + SCUDSP_ACH, + SCUDSP_ACL, + SCUDSP_RA0, + SCUDSP_WA0, + SCUDSP_RA, + SCUDSP_CT0, + SCUDSP_CT1, + SCUDSP_CT2, + SCUDSP_CT3 +}; + + +#define MCFG_SCUDSP_OUT_IRQ_CB(_devcb) \ + devcb = &scudsp_cpu_device::set_out_irq_callback(*device, DEVCB_##_devcb); + +#define MCFG_SCUDSP_IN_DMA_CB(_devcb) \ + devcb = &scudsp_cpu_device::set_in_dma_callback(*device, DEVCB_##_devcb); + +#define MCFG_SCUDSP_OUT_DMA_CB(_devcb) \ + devcb = &scudsp_cpu_device::set_out_dma_callback(*device, DEVCB_##_devcb); + + +#define SCUDSP_RESET INPUT_LINE_RESET /* Non-Maskable */ + +union SCUDSPREG32 { + INT32 si; + UINT32 ui; +}; + +union SCUDSPREG16 { + INT16 si; + UINT16 ui; +}; + +class scudsp_cpu_device : public cpu_device +{ +public: + // construction/destruction + scudsp_cpu_device(const machine_config &mconfig, const char *_tag, device_t *_owner, UINT32 _clock); + + template static devcb_base &set_out_irq_callback(device_t &device, _Object object) { return downcast(device).m_out_irq_cb.set_callback(object); } + template static devcb_base &set_in_dma_callback(device_t &device, _Object object) { return downcast(device).m_in_dma_cb.set_callback(object); } + template static devcb_base &set_out_dma_callback(device_t &device, _Object object) { return downcast(device).m_out_dma_cb.set_callback(object); } + + /* port 0 */ + DECLARE_READ32_MEMBER( program_control_r ); + DECLARE_WRITE32_MEMBER( program_control_w ); + /* port 1 */ + DECLARE_WRITE32_MEMBER( program_w ); + /* port 2 */ + DECLARE_WRITE32_MEMBER( ram_address_control_w ); + /* port 3 */ + DECLARE_READ32_MEMBER( ram_address_r ); + DECLARE_WRITE32_MEMBER( ram_address_w ); +// virtual DECLARE_ADDRESS_MAP(map, 32) = 0; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_execute_interface overrides + virtual UINT32 execute_min_cycles() const { return 1; } + virtual UINT32 execute_max_cycles() const { return 7; } + virtual UINT32 execute_input_lines() const { return 0; } + virtual void execute_run(); + virtual void execute_set_input(int inputnum, int state); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const { return (spacenum == AS_PROGRAM) ? &m_program_config : ( (spacenum == AS_DATA) ? &m_data_config : NULL ); } + + // device_state_interface overrides + void state_string_export(const device_state_entry &entry, std::string &str); + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const { return 4; } + virtual UINT32 disasm_max_opcode_bytes() const { return 4; } + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + + devcb_write_line m_out_irq_cb; + devcb_read16 m_in_dma_cb; + devcb_write16 m_out_dma_cb; + +private: + address_space_config m_program_config; + address_space_config m_data_config; + + UINT8 m_pc; /* registers */ + UINT32 m_flags; /* flags */ + UINT8 m_ra; + UINT8 m_ct0,m_ct1,m_ct2,m_ct3; + UINT8 m_delay; /* Delay */ + UINT8 m_top; /*Jump Command memory*/ + UINT16 m_lop; /*Counter Register*/ /*12-bits*/ + SCUDSPREG32 m_rx; /*X-Bus register*/ + INT64 m_mul; /*Multiplier register*//*48-bits*/ + SCUDSPREG32 m_ry; /*Y-Bus register*/ + INT64 m_alu; /*ALU register*/ /*48-bits*/ + SCUDSPREG16 m_ph; /*ALU high register*/ + SCUDSPREG32 m_pl; /*ALU low register*/ + SCUDSPREG16 m_ach; /*ALU external high register*/ + SCUDSPREG32 m_acl; /*ALU external low register*/ + UINT32 m_ra0,m_wa0; /*DSP DMA registers*/ + struct{ + UINT32 src, dst; + UINT16 add; + UINT16 size, update, ex, dir, count; + }m_dma; + address_space *m_program; + address_space *m_data; + int m_icount; + UINT8 m_update_mul; + + UINT32 scudsp_get_source_mem_reg_value( UINT32 mode ); + UINT32 scudsp_get_source_mem_value(UINT8 mode); + void scudsp_set_dest_mem_reg( UINT32 mode, UINT32 value ); + void scudsp_set_dest_mem_reg_2( UINT32 mode, UINT32 value ); + UINT32 scudsp_compute_condition( UINT32 condition ); + UINT32 scudsp_get_mem_source_dma( UINT32 memcode, UINT32 counter ); + void scudsp_set_dest_dma_mem( UINT32 memcode, UINT32 value, UINT32 counter ); + + void scudsp_illegal(UINT32 opcode); + void scudsp_operation(UINT32 opcode); + void scudsp_move_immediate(UINT32 opcode); + void scudsp_dma(UINT32 opcode); + void scudsp_jump(UINT32 opcode); + void scudsp_loop(UINT32 opcode); + void scudsp_end(UINT32 opcode); + void scudsp_exec_dma(); +}; + + +extern const device_type SCUDSP; + + +CPU_DISASSEMBLE( scudsp ); + +#endif /* __SCUDSP_H__ */ diff --git a/src/devices/cpu/scudsp/scudspdasm.c b/src/devices/cpu/scudsp/scudspdasm.c new file mode 100644 index 00000000000..d5e79a2cbd7 --- /dev/null +++ b/src/devices/cpu/scudsp/scudspdasm.c @@ -0,0 +1,364 @@ +// license:BSD-3-Clause +// copyright-holders:Angelo Salese, Mariusz Wojcieszek +#include "emu.h" +#include "debugger.h" +#include "scudsp.h" + +static const char *const ALU_Commands[] = +{ + " ", /* 0000 */ + "AND ", /* 0001 */ + "OR ", /* 0010 */ + "XOR ", /* 0011 */ + "ADD ", /* 0100 */ + "SUB ", /* 0101 */ + "AD2 ", /* 0110 */ + "ALU?", /* 0111 */ + "SR ", /* 1000 */ + "RR ", /* 1001 */ + "SL ", /* 1010 */ + "RL ", /* 1011 */ + "ALU?", /* 1100 */ + "ALU?", /* 1101 */ + "ALU?", /* 1110 */ + "RL8 ", /* 1111 */ +}; + +static const char *const X_Commands[] = +{ + "", /* 000 */ + "", /* 001 */ /* NOP? check instruction @ 0x0B */ + "MOV MUL,P", /* 010 */ + "MOV %s,P", /* 011 */ + "MOV %s,X", /* 100 */ +}; + +static const char *const Y_Commands[] = +{ + "", /* 000 */ + "CLR A", /* 001 */ + "MOV ALU,A", /* 010 */ + "MOV %s,A", /* 011 */ + "MOV %s,Y", /* 100 */ +}; + +static const char *const D1_Commands[] = +{ + "", /* 00 */ + "MOV %I8,%d", /* 01 */ + "???", /* 10 */ + "MOV %S,%d", /* 11 */ +}; + +static const char *const SourceMemory[] = +{ + "M0", /* 000 */ + "M1", /* 001 */ + "M2", /* 010 */ + "M3", /* 011 */ + "MC0", /* 100 */ + "MC1", /* 101 */ + "MC2", /* 110 */ + "MC3", /* 111 */ +}; + +static const char *const SourceMemory2[] = +{ + "M0", /* 0000 */ + "M1", /* 0001 */ + "M2", /* 0010 */ + "M3", /* 0011 */ + "MC0", /* 0100 */ + "MC1", /* 0101 */ + "MC2", /* 0110 */ + "MC3", /* 0111 */ + "???", /* 1000 */ + "ALL", /* 1001 */ + "ALH", /* 1010 */ + "???", /* 1011 */ + "???", /* 1100 */ + "???", /* 1101 */ + "???", /* 1110 */ + "???", /* 1111 */ +}; + +static const char *const DestMemory[] = +{ + "MC0", /* 0000 */ + "MC1", /* 0001 */ + "MC2", /* 0010 */ + "MC3", /* 0011 */ + "RX", /* 0100 */ + "PL", /* 0101 */ + "RA0", /* 0110 */ + "WA0", /* 0111 */ + "???", /* 1000 */ + "???", /* 1001 */ + "LOP", /* 1010 */ + "TOP", /* 1011 */ + "CT0", /* 1100 */ + "CT1", /* 1101 */ + "CT2", /* 1110 */ + "CT3", /* 1111 */ +}; + +static const char *const DestDMAMemory[] = +{ + "M0", /* 000 */ + "M1", /* 001 */ + "M2", /* 010 */ + "M3", /* 011 */ + "PRG", /* 100 */ + "???", /* 101 */ + "???", /* 110 */ + "???", /* 111 */ +}; + +static const char *const MVI_Command[] = +{ + "MVI %I,%d", /* 0 */ + "MVI %I,%d,%f", /* 1 */ +}; + +static const char *const JMP_Command[] = +{ + "JMP %IA", + "JMP %f,%IA", +}; + +static const char *const DMA_Command[] = +{ + "DMA%H%A D0,%M,%I", + "DMA%H%A %s,D0,%I", + "DMA%H%A D0,%M,%s", + "DMA%H%A %s,D0,%s", +}; + + +static void scudsp_dasm_prefix( const char* format, char* buffer, UINT32 *data ) +{ + for ( ; *format; format++ ) + { + if ( *format == '%' ) + { + switch( *++format ) + { + case 'H': + if ( *data ) + { + strcpy( buffer, "H" ); + } + else + { + *buffer = 0; + } + break; + case 'A': + if ( *data == 0 ) + { + strcpy( buffer, "0" ); + } + else if ( *data == 1 ) + { + *buffer = 0; + } + else + { + sprintf( buffer, "%d", 1 << (*data - 1) ); + } + break; + case 's': + strcpy( buffer, SourceMemory[ *data & 0x7 ] ); + break; + case 'd': + strcpy( buffer, DestMemory[ *data & 0xf ] ); + break; + case 'S': + strcpy( buffer, SourceMemory2[ *data & 0xf ] ); + break; + case 'I': + ++format; + if ( *format == '8' ) + { + sprintf( buffer, "#$%x", *data ); + } + else if ( *format == 'A' ) + { + sprintf( buffer, "$%X", *data ); + } + else + { + --format; + sprintf( buffer, "#$%X", *data ); + } + break; + case 'f': + if ( !(*data & 0x20) ) + { + strcpy( buffer, "N" ); + buffer++; + } + switch( *data & 0xf ) + { + case 0x3: + strcpy( buffer, "ZS" ); + break; + case 0x2: + strcpy( buffer, "S" ); + break; + case 0x4: + strcpy( buffer, "C" ); + break; + case 0x8: + strcpy( buffer, "T0" ); + break; + case 0x1: + strcpy( buffer, "Z" ); + break; + default: + strcpy( buffer, "?" ); + break; + } + break; + case 'M': + strcpy( buffer, DestDMAMemory[ *data ] ); + break; + + } + data++; + buffer += strlen( buffer ); + } + else + { + *buffer++ = *format; + } + } + *buffer = 0; +} + + +CPU_DISASSEMBLE( scudsp ) +{ + UINT32 op = oprom[0]<<24|oprom[1]<<16|oprom[2]<<8|oprom[3]<<0; + unsigned size = 1; +// const char *sym, *sym2; + char *my_buffer = buffer; + char temp_buffer[64]; + UINT32 data[4]; + + switch( op >> 30 ) + { + case 0: + if ( (op & 0x3F8E3000) == 0 ) + { + sprintf( buffer, "%-10s", "NOP" ); + break; + } + + /* ALU */ + sprintf(my_buffer, "%s", ALU_Commands[ (op & 0x3c000000) >> 26] ); + my_buffer += strlen( my_buffer ); + + /* X-Bus */ + data[0] = (op & 0x700000) >> 20; + if ( op & 0x2000000 ) + { + scudsp_dasm_prefix( X_Commands[ 4 ], temp_buffer, data ); + } + else + { + *temp_buffer = 0; + } + sprintf( my_buffer, "%s", temp_buffer ); + my_buffer += strlen( my_buffer ); + + scudsp_dasm_prefix( X_Commands[ (op & 0x1800000) >> 23 ], temp_buffer, data ); + sprintf( my_buffer, "%s", temp_buffer ); + my_buffer += strlen( my_buffer ); + + data[0] = (op & 0x1C000 ) >> 14 ; + if ( op & 0x80000 ) + { + scudsp_dasm_prefix( Y_Commands[4], temp_buffer, data ); + } + else + { + *temp_buffer = 0; + } + sprintf( my_buffer, "%s", temp_buffer ); + my_buffer += strlen( my_buffer ); + + scudsp_dasm_prefix( Y_Commands[ (op & 0x60000) >> 17 ], temp_buffer, data ); + sprintf( my_buffer, "%s", temp_buffer ); + my_buffer += strlen( my_buffer ); + + /* D1-Bus */ + switch( (op & 0x3000) >> 12 ) + { + case 0x1: + data[0] = (op & 0xFF); + data[1] = ((op & 0xF00) >> 8); + break; + case 0x3: + data[0] = (op & 0xF); + data[1] = ((op & 0xF00) >> 8); + break; + } + + scudsp_dasm_prefix( D1_Commands[ (op & 0x3000) >> 12 ], temp_buffer, data ); + sprintf( my_buffer, "%s", temp_buffer ); + break; + case 2: + if ( (op & 0x2000000) ) + { + data[0] = op & 0x7FFFF; + data[1] = (op & 0x3C000000) >> 26; + data[2] = (op & 0x3F80000 ) >> 19; + scudsp_dasm_prefix( MVI_Command[1], buffer, data ); /* TODO: bad mem*/ + } + else + { + data[0] = op & 0x1FFFFFF; + data[1] = (op & 0x3C000000) >> 26; + scudsp_dasm_prefix( MVI_Command[0], buffer, data ); /* TODO: bad mem*/ + } + break; + case 3: + switch((op >> 28) & 3) + { + case 0: + data[0] = (op & 0x4000) >> 14; /* H */ + data[1] = (op & 0x38000) >> 15; /* A */ + data[2] = (op & 0x700) >> 8; /* Mem */ + data[3] = (op & 0xff); + scudsp_dasm_prefix( DMA_Command[(op & 0x3000) >> 12], buffer, data ); + break; + case 1: + if ( op & 0x3F80000 ) + { + data[0] = (op & 0x3F80000) >> 19; + data[1] = op & 0xff; + scudsp_dasm_prefix( JMP_Command[1], buffer, data ); + } + else + { + data[0] = op & 0xff; + scudsp_dasm_prefix( JMP_Command[0], buffer, data ); + } + break; + case 2: + sprintf(buffer, op & 0x8000000 ? "LPS" : "BTM"); + break; + case 3: + sprintf(buffer, op & 0x8000000 ? "ENDI" : "END"); + break; + } + break; + + default: + sprintf(buffer, "???"); + break; + } + + return size; +} diff --git a/src/devices/cpu/se3208/se3208.c b/src/devices/cpu/se3208/se3208.c new file mode 100644 index 00000000000..98a87335d33 --- /dev/null +++ b/src/devices/cpu/se3208/se3208.c @@ -0,0 +1,1833 @@ +// license:BSD-3-Clause +// copyright-holders:ElSemi +#include "emu.h" +#include "debugger.h" +#include "se3208.h" + +/* + SE3208 CPU Emulator by ElSemi + + For information about this CPU: + www.adc.co.kr + +*/ + + +#define FLAG_C 0x0080 +#define FLAG_V 0x0010 +#define FLAG_S 0x0020 +#define FLAG_Z 0x0040 + +#define FLAG_M 0x0200 +#define FLAG_E 0x0800 +#define FLAG_AUT 0x1000 +#define FLAG_ENI 0x2000 +#define FLAG_NMI 0x4000 + +#define CLRFLAG(f) m_SR&=~(f); +#define SETFLAG(f) m_SR|=(f); +#define TESTFLAG(f) (m_SR&(f)) + +#define EXTRACT(val,sbit,ebit) (((val)>>sbit)&((1<<((ebit-sbit)+1))-1)) +#define SEX8(val) ((val&0x80)?(val|0xFFFFFF00):(val&0xFF)) +#define SEX16(val) ((val&0x8000)?(val|0xFFFF0000):(val&0xFFFF)) +#define ZEX8(val) ((val)&0xFF) +#define ZEX16(val) ((val)&0xFFFF) +#define SEX(bits,val) ((val)&(1<<(bits-1))?((val)|(~((1<; + + +se3208_device::se3208_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : cpu_device(mconfig, SE3208, "SE3208", tag, owner, clock, "se3208", __FILE__) + , m_program_config("program", ENDIANNESS_LITTLE, 32, 32, 0) +{ +} + + +UINT32 se3208_device::read_dword_unaligned(address_space &space, UINT32 address) +{ + if (address & 3) + return space.read_byte(address) | space.read_byte(address+1)<<8 | space.read_byte(address+2)<<16 | space.read_byte(address+3)<<24; + else + return space.read_dword(address); +} + +UINT16 se3208_device::read_word_unaligned(address_space &space, UINT32 address) +{ + if (address & 1) + return space.read_byte(address) | space.read_byte(address+1)<<8; + else + return space.read_word(address); +} + +void se3208_device::write_dword_unaligned(address_space &space, UINT32 address, UINT32 data) +{ + if (address & 3) + { + space.write_byte(address, data & 0xff); + space.write_byte(address+1, (data>>8)&0xff); + space.write_byte(address+2, (data>>16)&0xff); + space.write_byte(address+3, (data>>24)&0xff); + } + else + { + space.write_dword(address, data); + } +} + +void se3208_device::write_word_unaligned(address_space &space, UINT32 address, UINT16 data) +{ + if (address & 1) + { + space.write_byte(address, data & 0xff); + space.write_byte(address+1, (data>>8)&0xff); + } + else + { + space.write_word(address, data); + } +} + + +UINT8 se3208_device::SE3208_Read8(UINT32 addr) +{ + return m_program->read_byte(addr); +} + +UINT16 se3208_device::SE3208_Read16(UINT32 addr) +{ + return read_word_unaligned(*m_program,addr); +} + +UINT32 se3208_device::SE3208_Read32(UINT32 addr) +{ + return read_dword_unaligned(*m_program,addr); +} + +void se3208_device::SE3208_Write8(UINT32 addr,UINT8 val) +{ + m_program->write_byte(addr,val); +} + +void se3208_device::SE3208_Write16(UINT32 addr,UINT16 val) +{ + write_word_unaligned(*m_program,addr,val); +} + +void se3208_device::SE3208_Write32(UINT32 addr,UINT32 val) +{ + write_dword_unaligned(*m_program,addr,val); +} + + + +UINT32 se3208_device::AddWithFlags(UINT32 a,UINT32 b) +{ + UINT32 r=a+b; + CLRFLAG(FLAG_Z|FLAG_C|FLAG_V|FLAG_S); + if(!r) + SETFLAG(FLAG_Z); + if(r&0x80000000) + SETFLAG(FLAG_S); + if(((((a&b)|(~r&(a|b)))>>31))&1) + SETFLAG(FLAG_C); + if(((((a^r)&(b^r))>>31))&1) + SETFLAG(FLAG_V); + return r; +} + +UINT32 se3208_device::SubWithFlags(UINT32 a,UINT32 b) //a-b +{ + UINT32 r=a-b; + CLRFLAG(FLAG_Z|FLAG_C|FLAG_V|FLAG_S); + if(!r) + SETFLAG(FLAG_Z); + if(r&0x80000000) + SETFLAG(FLAG_S); + if((((b&r)|(~a&(b|r)))>>31)&1) + SETFLAG(FLAG_C); + if((((b^a)&(r^a))>>31)&1) + SETFLAG(FLAG_V); + return r; +} + +UINT32 se3208_device::AdcWithFlags(UINT32 a,UINT32 b) +{ + UINT32 C=(m_SR&FLAG_C)?1:0; + UINT32 r=a+b+C; + CLRFLAG(FLAG_Z|FLAG_C|FLAG_V|FLAG_S); + if(!r) + SETFLAG(FLAG_Z); + if(r&0x80000000) + SETFLAG(FLAG_S); + if(((((a&b)|(~r&(a|b)))>>31))&1) + SETFLAG(FLAG_C); + if(((((a^r)&(b^r))>>31))&1) + SETFLAG(FLAG_V); + return r; + +} + +UINT32 se3208_device::SbcWithFlags(UINT32 a,UINT32 b) +{ + UINT32 C=(m_SR&FLAG_C)?1:0; + UINT32 r=a-b-C; + CLRFLAG(FLAG_Z|FLAG_C|FLAG_V|FLAG_S); + if(!r) + SETFLAG(FLAG_Z); + if(r&0x80000000) + SETFLAG(FLAG_S); + if((((b&r)|(~a&(b|r)))>>31)&1) + SETFLAG(FLAG_C); + if((((b^a)&(r^a))>>31)&1) + SETFLAG(FLAG_V); + return r; +} + +UINT32 se3208_device::MulWithFlags(UINT32 a,UINT32 b) +{ + INT64 r=(INT64) a*(INT64) b; + CLRFLAG(FLAG_V); + if(r>>32) + SETFLAG(FLAG_V); + return (UINT32) (r&0xffffffff); +} + +UINT32 se3208_device::NegWithFlags(UINT32 a) +{ + return SubWithFlags(0,a); +} + +UINT32 se3208_device::AsrWithFlags(UINT32 Val, UINT8 By) +{ + signed int v=(signed int) Val; + v>>=By; + CLRFLAG(FLAG_Z|FLAG_C|FLAG_V|FLAG_S); + if(!v) + SETFLAG(FLAG_Z); + if(v&0x80000000) + SETFLAG(FLAG_S); + if(Val&(1<<(By-1))) + SETFLAG(FLAG_C); + return (UINT32) v; +} + +UINT32 se3208_device::LsrWithFlags(UINT32 Val, UINT8 By) +{ + UINT32 v=Val; + v>>=By; + CLRFLAG(FLAG_Z|FLAG_C|FLAG_V|FLAG_S); + if(!v) + SETFLAG(FLAG_Z); + if(v&0x80000000) + SETFLAG(FLAG_S); + if(Val&(1<<(By-1))) + SETFLAG(FLAG_C); + return v; +} + +UINT32 se3208_device::AslWithFlags(UINT32 Val, UINT8 By) +{ + UINT32 v=Val; + v<<=By; + CLRFLAG(FLAG_Z|FLAG_C|FLAG_V|FLAG_S); + if(!v) + SETFLAG(FLAG_Z); + if(v&0x80000000) + SETFLAG(FLAG_S); + if(Val&(1<<(32-By))) + SETFLAG(FLAG_C); + return v; +} + + +INST(INVALIDOP) +{ + //assert(false); +} + +INST(LDB) +{ + UINT32 Offset=EXTRACT(Opcode,0,4); + UINT32 Index=EXTRACT(Opcode,5,7); + UINT32 SrcDst=EXTRACT(Opcode,8,10); + UINT32 Val; + + if(Index) + Index=m_R[Index]; + else + Index=0; + + if(TESTFLAG(FLAG_E)) + Offset=(EXTRACT(m_ER,0,27)<<4)|(Offset&0xf); + + Val=SE3208_Read8(Index+Offset); + m_R[SrcDst]=SEX8(Val); + + CLRFLAG(FLAG_E); +} + +INST(STB) +{ + UINT32 Offset=EXTRACT(Opcode,0,4); + UINT32 Index=EXTRACT(Opcode,5,7); + UINT32 SrcDst=EXTRACT(Opcode,8,10); + + if(Index) + Index=m_R[Index]; + else + Index=0; + + if(TESTFLAG(FLAG_E)) + Offset=(EXTRACT(m_ER,0,27)<<4)|(Offset&0xf); + + SE3208_Write8(Index+Offset,ZEX8(m_R[SrcDst])); + + CLRFLAG(FLAG_E); +} + +INST(LDS) +{ + UINT32 Offset=EXTRACT(Opcode,0,4); + UINT32 Index=EXTRACT(Opcode,5,7); + UINT32 SrcDst=EXTRACT(Opcode,8,10); + UINT32 Val; + + Offset<<=1; + + if(Index) + Index=m_R[Index]; + else + Index=0; + + if(TESTFLAG(FLAG_E)) + Offset=(EXTRACT(m_ER,0,27)<<4)|(Offset&0xf); + + Val=SE3208_Read16(Index+Offset); + m_R[SrcDst]=SEX16(Val); + + CLRFLAG(FLAG_E); +} + +INST(STS) +{ + UINT32 Offset=EXTRACT(Opcode,0,4); + UINT32 Index=EXTRACT(Opcode,5,7); + UINT32 SrcDst=EXTRACT(Opcode,8,10); + + Offset<<=1; + + if(Index) + Index=m_R[Index]; + else + Index=0; + + if(TESTFLAG(FLAG_E)) + Offset=(EXTRACT(m_ER,0,27)<<4)|(Offset&0xf); + + SE3208_Write16(Index+Offset,ZEX16(m_R[SrcDst])); + + CLRFLAG(FLAG_E); +} + +INST(LD) +{ + UINT32 Offset=EXTRACT(Opcode,0,4); + UINT32 Index=EXTRACT(Opcode,5,7); + UINT32 SrcDst=EXTRACT(Opcode,8,10); + + Offset<<=2; + + if(Index) + Index=m_R[Index]; + else + Index=0; + + if(TESTFLAG(FLAG_E)) + Offset=(EXTRACT(m_ER,0,27)<<4)|(Offset&0xf); + + m_R[SrcDst]=SE3208_Read32(Index+Offset); + + CLRFLAG(FLAG_E); +} + +INST(ST) +{ + UINT32 Offset=EXTRACT(Opcode,0,4); + UINT32 Index=EXTRACT(Opcode,5,7); + UINT32 SrcDst=EXTRACT(Opcode,8,10); + + Offset<<=2; + + if(Index) + Index=m_R[Index]; + else + Index=0; + + if(TESTFLAG(FLAG_E)) + Offset=(EXTRACT(m_ER,0,27)<<4)|(Offset&0xf); + + SE3208_Write32(Index+Offset,m_R[SrcDst]); + + CLRFLAG(FLAG_E); +} + +INST(LDBU) +{ + UINT32 Offset=EXTRACT(Opcode,0,4); + UINT32 Index=EXTRACT(Opcode,5,7); + UINT32 SrcDst=EXTRACT(Opcode,8,10); + UINT32 Val; + + if(Index) + Index=m_R[Index]; + else + Index=0; + + if(TESTFLAG(FLAG_E)) + Offset=(EXTRACT(m_ER,0,27)<<4)|(Offset&0xf); + + Val=SE3208_Read8(Index+Offset); + m_R[SrcDst]=ZEX8(Val); + + CLRFLAG(FLAG_E); +} + +INST(LDSU) +{ + UINT32 Offset=EXTRACT(Opcode,0,4); + UINT32 Index=EXTRACT(Opcode,5,7); + UINT32 SrcDst=EXTRACT(Opcode,8,10); + UINT32 Val; + + Offset<<=1; + + if(Index) + Index=m_R[Index]; + else + Index=0; + + if(TESTFLAG(FLAG_E)) + Offset=(EXTRACT(m_ER,0,27)<<4)|(Offset&0xf); + + Val=SE3208_Read16(Index+Offset); + m_R[SrcDst]=ZEX16(Val); + + CLRFLAG(FLAG_E); +} + + +INST(LERI) +{ + UINT32 Imm=EXTRACT(Opcode,0,13); + if(TESTFLAG(FLAG_E)) + m_ER=(EXTRACT(m_ER,0,17)<<14)|Imm; + else + m_ER=SEX(14,Imm); + + + SETFLAG(FLAG_E); +} + +INST(LDSP) +{ + UINT32 Offset=EXTRACT(Opcode,0,7); + UINT32 Index=m_SP; + UINT32 SrcDst=EXTRACT(Opcode,8,10); + + Offset<<=2; + + if(TESTFLAG(FLAG_E)) + Offset=(EXTRACT(m_ER,0,27)<<4)|(Offset&0xf); + + m_R[SrcDst]=SE3208_Read32(Index+Offset); + + CLRFLAG(FLAG_E); +} + +INST(STSP) +{ + UINT32 Offset=EXTRACT(Opcode,0,7); + UINT32 Index=m_SP; + UINT32 SrcDst=EXTRACT(Opcode,8,10); + + Offset<<=2; + + if(TESTFLAG(FLAG_E)) + Offset=(EXTRACT(m_ER,0,27)<<4)|(Offset&0xf); + + SE3208_Write32(Index+Offset,m_R[SrcDst]); + + CLRFLAG(FLAG_E); +} + +void se3208_device::PushVal(UINT32 Val) +{ + m_SP-=4; + SE3208_Write32(m_SP,Val); +} + +UINT32 se3208_device::PopVal() +{ + UINT32 Val=SE3208_Read32(m_SP); + m_SP+=4; + return Val; +} + +INST(PUSH) +{ + UINT32 Set=EXTRACT(Opcode,0,10); + if(Set&(1<<10)) + PushVal(m_PC); + if(Set&(1<<9)) + PushVal(m_SR); + if(Set&(1<<8)) + PushVal(m_ER); + if(Set&(1<<7)) + PushVal(m_R[7]); + if(Set&(1<<6)) + PushVal(m_R[6]); + if(Set&(1<<5)) + PushVal(m_R[5]); + if(Set&(1<<4)) + PushVal(m_R[4]); + if(Set&(1<<3)) + PushVal(m_R[3]); + if(Set&(1<<2)) + PushVal(m_R[2]); + if(Set&(1<<1)) + PushVal(m_R[1]); + if(Set&(1<<0)) + PushVal(m_R[0]); +} + +INST(POP) +{ + UINT32 Set=EXTRACT(Opcode,0,10); + if(Set&(1<<0)) + m_R[0]=PopVal(); + if(Set&(1<<1)) + m_R[1]=PopVal(); + if(Set&(1<<2)) + m_R[2]=PopVal(); + if(Set&(1<<3)) + m_R[3]=PopVal(); + if(Set&(1<<4)) + m_R[4]=PopVal(); + if(Set&(1<<5)) + m_R[5]=PopVal(); + if(Set&(1<<6)) + m_R[6]=PopVal(); + if(Set&(1<<7)) + m_R[7]=PopVal(); + if(Set&(1<<8)) + m_ER=PopVal(); + if(Set&(1<<9)) + m_SR=PopVal(); + if(Set&(1<<10)) + { + m_PC=PopVal()-2; //PC automatically incresases by 2 + } +} + +INST(LEATOSP) +{ + UINT32 Offset=EXTRACT(Opcode,9,12); + UINT32 Index=EXTRACT(Opcode,3,5); + + if(Index) + Index=m_R[Index]; + else + Index=0; + + if(TESTFLAG(FLAG_E)) + Offset=(EXTRACT(m_ER,0,27)<<4)|(Offset&0xf); + else + Offset=SEX(4,Offset); + + m_SP=Index+Offset; + + CLRFLAG(FLAG_E); +} + +INST(LEAFROMSP) +{ + UINT32 Offset=EXTRACT(Opcode,9,12); + UINT32 Index=EXTRACT(Opcode,3,5); + + if(TESTFLAG(FLAG_E)) + Offset=(EXTRACT(m_ER,0,27)<<4)|(Offset&0xf); + else + Offset=SEX(4,Offset); + + m_R[Index]=m_SP+Offset; + + CLRFLAG(FLAG_E); +} + +INST(LEASPTOSP) +{ + UINT32 Offset=EXTRACT(Opcode,0,7); + + Offset<<=2; + + if(TESTFLAG(FLAG_E)) + Offset=(EXTRACT(m_ER,0,23)<<8)|(Offset&0xff); + else + Offset=SEX(10,Offset); + + m_SP=m_SP+Offset; + + CLRFLAG(FLAG_E); +} + +INST(MOV) +{ + UINT32 Src=EXTRACT(Opcode,3,5); + UINT32 Dst=EXTRACT(Opcode,9,11); + + m_R[Dst]=m_R[Src]; +} + +INST(LDI) +{ + UINT32 Dst=EXTRACT(Opcode,8,10); + UINT32 Imm=EXTRACT(Opcode,0,7); + + if(TESTFLAG(FLAG_E)) + Imm=(EXTRACT(m_ER,0,27)<<4)|(Imm&0xf); + else + Imm=SEX8(Imm); + + m_R[Dst]=Imm; + + CLRFLAG(FLAG_E); +} + +INST(LDBSP) +{ + UINT32 Offset=EXTRACT(Opcode,0,3); + UINT32 Index=m_SP; + UINT32 SrcDst=EXTRACT(Opcode,4,6); + UINT32 Val; + + if(TESTFLAG(FLAG_E)) + Offset=(EXTRACT(m_ER,0,27)<<4)|(Offset&0xf); + + Val=SE3208_Read8(Index+Offset); + m_R[SrcDst]=SEX8(Val); + + CLRFLAG(FLAG_E); +} + +INST(STBSP) +{ + UINT32 Offset=EXTRACT(Opcode,0,3); + UINT32 Index=m_SP; + UINT32 SrcDst=EXTRACT(Opcode,4,6); + + if(TESTFLAG(FLAG_E)) + Offset=(EXTRACT(m_ER,0,27)<<4)|(Offset&0xf); + + SE3208_Write8(Index+Offset,ZEX8(m_R[SrcDst])); + + CLRFLAG(FLAG_E); +} + +INST(LDSSP) +{ + UINT32 Offset=EXTRACT(Opcode,0,3); + UINT32 Index=m_SP; + UINT32 SrcDst=EXTRACT(Opcode,4,6); + UINT32 Val; + + Offset<<=1; + + if(TESTFLAG(FLAG_E)) + Offset=(EXTRACT(m_ER,0,27)<<4)|(Offset&0xf); + + Val=SE3208_Read16(Index+Offset); + m_R[SrcDst]=SEX16(Val); + + CLRFLAG(FLAG_E); +} + +INST(STSSP) +{ + UINT32 Offset=EXTRACT(Opcode,0,3); + UINT32 Index=m_SP; + UINT32 SrcDst=EXTRACT(Opcode,4,6); + + Offset<<=1; + + if(TESTFLAG(FLAG_E)) + Offset=(EXTRACT(m_ER,0,27)<<4)|(Offset&0xf); + + SE3208_Write16(Index+Offset,ZEX16(m_R[SrcDst])); + + CLRFLAG(FLAG_E); +} + +INST(LDBUSP) +{ + UINT32 Offset=EXTRACT(Opcode,0,3); + UINT32 Index=m_SP; + UINT32 SrcDst=EXTRACT(Opcode,4,6); + UINT32 Val; + + if(TESTFLAG(FLAG_E)) + Offset=(EXTRACT(m_ER,0,27)<<4)|(Offset&0xf); + + Val=SE3208_Read8(Index+Offset); + m_R[SrcDst]=ZEX8(Val); + + CLRFLAG(FLAG_E); +} + +INST(LDSUSP) +{ + UINT32 Offset=EXTRACT(Opcode,0,3); + UINT32 Index=m_SP; + UINT32 SrcDst=EXTRACT(Opcode,4,6); + UINT32 Val; + + Offset<<=1; + + if(TESTFLAG(FLAG_E)) + Offset=(EXTRACT(m_ER,0,27)<<4)|(Offset&0xf); + + Val=SE3208_Read16(Index+Offset); + m_R[SrcDst]=ZEX16(Val); + + CLRFLAG(FLAG_E); +} + +INST(ADDI) +{ + UINT32 Imm=EXTRACT(Opcode,9,12); + UINT32 Src=EXTRACT(Opcode,3,5); + UINT32 Dst=EXTRACT(Opcode,0,2); + + if(TESTFLAG(FLAG_E)) + Imm=(EXTRACT(m_ER,0,27)<<4)|(Imm&0xf); + else + Imm=SEX(4,Imm); + + m_R[Dst]=AddWithFlags(m_R[Src],Imm); + + CLRFLAG(FLAG_E); +} + +INST(SUBI) +{ + UINT32 Imm=EXTRACT(Opcode,9,12); + UINT32 Src=EXTRACT(Opcode,3,5); + UINT32 Dst=EXTRACT(Opcode,0,2); + + if(TESTFLAG(FLAG_E)) + Imm=(EXTRACT(m_ER,0,27)<<4)|(Imm&0xf); + else + Imm=SEX(4,Imm); + + m_R[Dst]=SubWithFlags(m_R[Src],Imm); + + CLRFLAG(FLAG_E); +} + +INST(ADCI) +{ + UINT32 Imm=EXTRACT(Opcode,9,12); + UINT32 Src=EXTRACT(Opcode,3,5); + UINT32 Dst=EXTRACT(Opcode,0,2); + + if(TESTFLAG(FLAG_E)) + Imm=(EXTRACT(m_ER,0,27)<<4)|(Imm&0xf); + else + Imm=SEX(4,Imm); + + m_R[Dst]=AdcWithFlags(m_R[Src],Imm); + + CLRFLAG(FLAG_E); +} + +INST(SBCI) +{ + UINT32 Imm=EXTRACT(Opcode,9,12); + UINT32 Src=EXTRACT(Opcode,3,5); + UINT32 Dst=EXTRACT(Opcode,0,2); + + if(TESTFLAG(FLAG_E)) + Imm=(EXTRACT(m_ER,0,27)<<4)|(Imm&0xf); + else + Imm=SEX(4,Imm); + + m_R[Dst]=SbcWithFlags(m_R[Src],Imm); + + CLRFLAG(FLAG_E); +} + +INST(ANDI) +{ + UINT32 Imm=EXTRACT(Opcode,9,12); + UINT32 Src=EXTRACT(Opcode,3,5); + UINT32 Dst=EXTRACT(Opcode,0,2); + + if(TESTFLAG(FLAG_E)) + Imm=(EXTRACT(m_ER,0,27)<<4)|(Imm&0xf); + else + Imm=SEX(4,Imm); + + m_R[Dst]=m_R[Src]&Imm; + + CLRFLAG(FLAG_S|FLAG_Z|FLAG_E); + if(!m_R[Dst]) + SETFLAG(FLAG_Z); + if(m_R[Dst]&0x80000000) + SETFLAG(FLAG_S); +} + +INST(ORI) +{ + UINT32 Imm=EXTRACT(Opcode,9,12); + UINT32 Src=EXTRACT(Opcode,3,5); + UINT32 Dst=EXTRACT(Opcode,0,2); + + if(TESTFLAG(FLAG_E)) + Imm=(EXTRACT(m_ER,0,27)<<4)|(Imm&0xf); + else + Imm=SEX(4,Imm); + + m_R[Dst]=m_R[Src]|Imm; + + CLRFLAG(FLAG_S|FLAG_Z|FLAG_E); + if(!m_R[Dst]) + SETFLAG(FLAG_Z); + if(m_R[Dst]&0x80000000) + SETFLAG(FLAG_S); +} + +INST(XORI) +{ + UINT32 Imm=EXTRACT(Opcode,9,12); + UINT32 Src=EXTRACT(Opcode,3,5); + UINT32 Dst=EXTRACT(Opcode,0,2); + + if(TESTFLAG(FLAG_E)) + Imm=(EXTRACT(m_ER,0,27)<<4)|(Imm&0xf); + else + Imm=SEX(4,Imm); + + m_R[Dst]=m_R[Src]^Imm; + + CLRFLAG(FLAG_S|FLAG_Z|FLAG_E); + if(!m_R[Dst]) + SETFLAG(FLAG_Z); + if(m_R[Dst]&0x80000000) + SETFLAG(FLAG_S); +} + +INST(CMPI) +{ + UINT32 Imm=EXTRACT(Opcode,9,12); + UINT32 Src=EXTRACT(Opcode,3,5); + + if(TESTFLAG(FLAG_E)) + Imm=(EXTRACT(m_ER,0,27)<<4)|(Imm&0xf); + else + Imm=SEX(4,Imm); + + SubWithFlags(m_R[Src],Imm); + + CLRFLAG(FLAG_E); +} + +INST(TSTI) +{ + UINT32 Imm=EXTRACT(Opcode,9,12); + UINT32 Src=EXTRACT(Opcode,3,5); + UINT32 Dst; + + if(TESTFLAG(FLAG_E)) + Imm=(EXTRACT(m_ER,0,27)<<4)|(Imm&0xf); + else + Imm=SEX(4,Imm); + + Dst=m_R[Src]&Imm; + + CLRFLAG(FLAG_S|FLAG_Z|FLAG_E); + if(!Dst) + SETFLAG(FLAG_Z); + if(Dst&0x80000000) + SETFLAG(FLAG_S); +} + +INST(ADD) +{ + UINT32 Src2=EXTRACT(Opcode,9,11); + UINT32 Src1=EXTRACT(Opcode,3,5); + UINT32 Dst=EXTRACT(Opcode,0,2); + + m_R[Dst]=AddWithFlags(m_R[Src1],m_R[Src2]); +} + +INST(SUB) +{ + UINT32 Src2=EXTRACT(Opcode,9,11); + UINT32 Src1=EXTRACT(Opcode,3,5); + UINT32 Dst=EXTRACT(Opcode,0,2); + + m_R[Dst]=SubWithFlags(m_R[Src1],m_R[Src2]); +} + +INST(ADC) +{ + UINT32 Src2=EXTRACT(Opcode,9,11); + UINT32 Src1=EXTRACT(Opcode,3,5); + UINT32 Dst=EXTRACT(Opcode,0,2); + + m_R[Dst]=AdcWithFlags(m_R[Src1],m_R[Src2]); +} + +INST(SBC) +{ + UINT32 Src2=EXTRACT(Opcode,9,11); + UINT32 Src1=EXTRACT(Opcode,3,5); + UINT32 Dst=EXTRACT(Opcode,0,2); + + m_R[Dst]=SbcWithFlags(m_R[Src1],m_R[Src2]); +} + +INST(AND) +{ + UINT32 Src2=EXTRACT(Opcode,9,11); + UINT32 Src1=EXTRACT(Opcode,3,5); + UINT32 Dst=EXTRACT(Opcode,0,2); + + m_R[Dst]=m_R[Src1]&m_R[Src2]; + + CLRFLAG(FLAG_S|FLAG_Z); + if(!m_R[Dst]) + SETFLAG(FLAG_Z); + if(m_R[Dst]&0x80000000) + SETFLAG(FLAG_S); +} + +INST(OR) +{ + UINT32 Src2=EXTRACT(Opcode,9,11); + UINT32 Src1=EXTRACT(Opcode,3,5); + UINT32 Dst=EXTRACT(Opcode,0,2); + + m_R[Dst]=m_R[Src1]|m_R[Src2]; + + CLRFLAG(FLAG_S|FLAG_Z); + if(!m_R[Dst]) + SETFLAG(FLAG_Z); + if(m_R[Dst]&0x80000000) + SETFLAG(FLAG_S); + +} + +INST(XOR) +{ + UINT32 Src2=EXTRACT(Opcode,9,11); + UINT32 Src1=EXTRACT(Opcode,3,5); + UINT32 Dst=EXTRACT(Opcode,0,2); + + m_R[Dst]=m_R[Src1]^m_R[Src2]; + + CLRFLAG(FLAG_S|FLAG_Z); + if(!m_R[Dst]) + SETFLAG(FLAG_Z); + if(m_R[Dst]&0x80000000) + SETFLAG(FLAG_S); + +} + +INST(CMP) +{ + UINT32 Src2=EXTRACT(Opcode,9,11); + UINT32 Src1=EXTRACT(Opcode,3,5); + + SubWithFlags(m_R[Src1],m_R[Src2]); +} + +INST(TST) +{ + UINT32 Src2=EXTRACT(Opcode,9,11); + UINT32 Src1=EXTRACT(Opcode,3,5); + UINT32 Dst; + + Dst=m_R[Src1]&m_R[Src2]; + + CLRFLAG(FLAG_S|FLAG_Z); + if(!Dst) + SETFLAG(FLAG_Z); + if(Dst&0x80000000) + SETFLAG(FLAG_S); +} + +INST(MULS) +{ + UINT32 Src2=EXTRACT(Opcode,6,8); + UINT32 Src1=EXTRACT(Opcode,3,5); + UINT32 Dst=EXTRACT(Opcode,0,2); + + m_R[Dst]=MulWithFlags(m_R[Src1],m_R[Src2]); + + CLRFLAG(FLAG_E); +} + +INST(NEG) +{ + UINT32 Dst=EXTRACT(Opcode,9,11); + UINT32 Src=EXTRACT(Opcode,3,5); + + m_R[Dst]=NegWithFlags(m_R[Src]); +} + +INST(CALL) +{ + UINT32 Offset=EXTRACT(Opcode,0,7); + + if(TESTFLAG(FLAG_E)) + Offset=(EXTRACT(m_ER,0,22)<<8)|Offset; + else + Offset=SEX(8,Offset); + Offset<<=1; + PushVal(m_PC+2); + m_PC=m_PC+Offset; + + CLRFLAG(FLAG_E); +} + +INST(JV) +{ + UINT32 Offset=EXTRACT(Opcode,0,7); + + if(TESTFLAG(FLAG_E)) + Offset=(EXTRACT(m_ER,0,22)<<8)|Offset; + else + Offset=SEX(8,Offset); + Offset<<=1; + + if(TESTFLAG(FLAG_V)) + { + m_PC=m_PC+Offset; + } + + CLRFLAG(FLAG_E); + +} + +INST(JNV) +{ + UINT32 Offset=EXTRACT(Opcode,0,7); + + if(TESTFLAG(FLAG_E)) + Offset=(EXTRACT(m_ER,0,22)<<8)|Offset; + else + Offset=SEX(8,Offset); + Offset<<=1; + + if(!TESTFLAG(FLAG_V)) + { + m_PC=m_PC+Offset; + } + + CLRFLAG(FLAG_E); +} + +INST(JC) +{ + UINT32 Offset=EXTRACT(Opcode,0,7); + + if(TESTFLAG(FLAG_E)) + Offset=(EXTRACT(m_ER,0,22)<<8)|Offset; + else + Offset=SEX(8,Offset); + Offset<<=1; + + if(TESTFLAG(FLAG_C)) + { + m_PC=m_PC+Offset; + } + + CLRFLAG(FLAG_E); +} + +INST(JNC) +{ + UINT32 Offset=EXTRACT(Opcode,0,7); + + if(TESTFLAG(FLAG_E)) + Offset=(EXTRACT(m_ER,0,22)<<8)|Offset; + else + Offset=SEX(8,Offset); + Offset<<=1; + + if(!TESTFLAG(FLAG_C)) + { + m_PC=m_PC+Offset; + } + + CLRFLAG(FLAG_E); +} + +INST(JP) +{ + UINT32 Offset=EXTRACT(Opcode,0,7); + + if(TESTFLAG(FLAG_E)) + Offset=(EXTRACT(m_ER,0,22)<<8)|Offset; + else + Offset=SEX(8,Offset); + Offset<<=1; + + if(!TESTFLAG(FLAG_S)) + { + m_PC=m_PC+Offset; + } + + CLRFLAG(FLAG_E); +} + +INST(JM) +{ + UINT32 Offset=EXTRACT(Opcode,0,7); + + if(TESTFLAG(FLAG_E)) + Offset=(EXTRACT(m_ER,0,22)<<8)|Offset; + else + Offset=SEX(8,Offset); + Offset<<=1; + + if(TESTFLAG(FLAG_S)) + { + m_PC=m_PC+Offset; + } + + CLRFLAG(FLAG_E); +} + +INST(JNZ) +{ + UINT32 Offset=EXTRACT(Opcode,0,7); + + if(TESTFLAG(FLAG_E)) + Offset=(EXTRACT(m_ER,0,22)<<8)|Offset; + else + Offset=SEX(8,Offset); + Offset<<=1; + + if(!TESTFLAG(FLAG_Z)) + { + m_PC=m_PC+Offset; + } + + CLRFLAG(FLAG_E); +} + +INST(JZ) +{ + UINT32 Offset=EXTRACT(Opcode,0,7); + + if(TESTFLAG(FLAG_E)) + Offset=(EXTRACT(m_ER,0,22)<<8)|Offset; + else + Offset=SEX(8,Offset); + Offset<<=1; + + if(TESTFLAG(FLAG_Z)) + { + m_PC=m_PC+Offset; + } + + CLRFLAG(FLAG_E); +} + +INST(JGE) +{ + UINT32 Offset=EXTRACT(Opcode,0,7); + UINT32 S=TESTFLAG(FLAG_S)?1:0; + UINT32 V=TESTFLAG(FLAG_V)?1:0; + + if(TESTFLAG(FLAG_E)) + Offset=(EXTRACT(m_ER,0,22)<<8)|Offset; + else + Offset=SEX(8,Offset); + Offset<<=1; + + if(!(S^V)) + { + m_PC=m_PC+Offset; + } + + CLRFLAG(FLAG_E); +} + +INST(JLE) +{ + UINT32 Offset=EXTRACT(Opcode,0,7); + UINT32 S=TESTFLAG(FLAG_S)?1:0; + UINT32 V=TESTFLAG(FLAG_V)?1:0; + + if(TESTFLAG(FLAG_E)) + Offset=(EXTRACT(m_ER,0,22)<<8)|Offset; + else + Offset=SEX(8,Offset); + Offset<<=1; + + if(TESTFLAG(FLAG_Z) || (S^V)) + { + m_PC=m_PC+Offset; + } + CLRFLAG(FLAG_E); +} + +INST(JHI) +{ + UINT32 Offset=EXTRACT(Opcode,0,7); + + if(TESTFLAG(FLAG_E)) + Offset=(EXTRACT(m_ER,0,22)<<8)|Offset; + else + Offset=SEX(8,Offset); + Offset<<=1; + + if(!(TESTFLAG(FLAG_Z) || TESTFLAG(FLAG_C))) + { + m_PC=m_PC+Offset; + } + + CLRFLAG(FLAG_E); +} + +INST(JLS) +{ + UINT32 Offset=EXTRACT(Opcode,0,7); + + if(TESTFLAG(FLAG_E)) + Offset=(EXTRACT(m_ER,0,22)<<8)|Offset; + else + Offset=SEX(8,Offset); + Offset<<=1; + + if(TESTFLAG(FLAG_Z) || TESTFLAG(FLAG_C)) + { + m_PC=m_PC+Offset; + } + + CLRFLAG(FLAG_E); +} + +INST(JGT) +{ + UINT32 Offset=EXTRACT(Opcode,0,7); + UINT32 S=TESTFLAG(FLAG_S)?1:0; + UINT32 V=TESTFLAG(FLAG_V)?1:0; + + if(TESTFLAG(FLAG_E)) + Offset=(EXTRACT(m_ER,0,22)<<8)|Offset; + else + Offset=SEX(8,Offset); + Offset<<=1; + + if(!(TESTFLAG(FLAG_Z) || (S^V))) + { + m_PC=m_PC+Offset; + } + + CLRFLAG(FLAG_E); +} + +INST(JLT) +{ + UINT32 Offset=EXTRACT(Opcode,0,7); + UINT32 S=TESTFLAG(FLAG_S)?1:0; + UINT32 V=TESTFLAG(FLAG_V)?1:0; + + if(TESTFLAG(FLAG_E)) + Offset=(EXTRACT(m_ER,0,22)<<8)|Offset; + else + Offset=SEX(8,Offset); + Offset<<=1; + + if(S^V) + { + m_PC=m_PC+Offset; + } + + CLRFLAG(FLAG_E); +} + + + +INST(JMP) +{ + UINT32 Offset=EXTRACT(Opcode,0,7); + + if(TESTFLAG(FLAG_E)) + Offset=(EXTRACT(m_ER,0,22)<<8)|Offset; + else + Offset=SEX(8,Offset); + + Offset<<=1; + + m_PC=m_PC+Offset; + + CLRFLAG(FLAG_E); +} + +INST(JR) +{ + UINT32 Src=EXTRACT(Opcode,0,3); + + m_PC=m_R[Src]-2; + + CLRFLAG(FLAG_E); +} + +INST(CALLR) +{ + UINT32 Src=EXTRACT(Opcode,0,3); + PushVal(m_PC+2); + m_PC=m_R[Src]-2; + + CLRFLAG(FLAG_E); +} + +INST(ASR) +{ + UINT32 CS=Opcode&(1<<10); + UINT32 Dst=EXTRACT(Opcode,0,2); + UINT32 Imm=EXTRACT(Opcode,5,9); + UINT32 Cnt=EXTRACT(Opcode,5,7); + + if(CS) + m_R[Dst]=AsrWithFlags(m_R[Dst],m_R[Cnt]&0x1f); + else + m_R[Dst]=AsrWithFlags(m_R[Dst],Imm&0x1f); + + CLRFLAG(FLAG_E); +} + +INST(LSR) +{ + UINT32 CS=Opcode&(1<<10); + UINT32 Dst=EXTRACT(Opcode,0,2); + UINT32 Imm=EXTRACT(Opcode,5,9); + UINT32 Cnt=EXTRACT(Opcode,5,7); + + if(CS) + m_R[Dst]=LsrWithFlags(m_R[Dst],m_R[Cnt]&0x1f); + else + m_R[Dst]=LsrWithFlags(m_R[Dst],Imm&0x1f); + + CLRFLAG(FLAG_E); +} + +INST(ASL) +{ + UINT32 CS=Opcode&(1<<10); + UINT32 Dst=EXTRACT(Opcode,0,2); + UINT32 Imm=EXTRACT(Opcode,5,9); + UINT32 Cnt=EXTRACT(Opcode,5,7); + + if(CS) + m_R[Dst]=AslWithFlags(m_R[Dst],m_R[Cnt]&0x1f); + else + m_R[Dst]=AslWithFlags(m_R[Dst],Imm&0x1f); + + CLRFLAG(FLAG_E); +} + +INST(EXTB) +{ + UINT32 Dst=EXTRACT(Opcode,0,3); + UINT32 Val=m_R[Dst]; + + m_R[Dst]=SEX8(Val); + + CLRFLAG(FLAG_S|FLAG_Z|FLAG_E); + if(!m_R[Dst]) + SETFLAG(FLAG_Z); + if(m_R[Dst]&0x80000000) + SETFLAG(FLAG_S); + +} + +INST(EXTS) +{ + UINT32 Dst=EXTRACT(Opcode,0,3); + UINT32 Val=m_R[Dst]; + + m_R[Dst]=SEX16(Val); + + CLRFLAG(FLAG_S|FLAG_Z|FLAG_E); + if(!m_R[Dst]) + SETFLAG(FLAG_Z); + if(m_R[Dst]&0x80000000) + SETFLAG(FLAG_S); +} + +INST(SET) +{ + UINT32 Imm=EXTRACT(Opcode,0,3); + + m_SR|=(1<direct(); + m_PC=SE3208_Read32(0); + m_SR=0; + m_IRQ=CLEAR_LINE; + m_NMI=CLEAR_LINE; +} + +void se3208_device::SE3208_NMI() +{ + PushVal(m_PC); + PushVal(m_SR); + + CLRFLAG(FLAG_NMI|FLAG_ENI|FLAG_E|FLAG_M); + + m_PC=SE3208_Read32(4); +} + +void se3208_device::SE3208_Interrupt() +{ + if(!TESTFLAG(FLAG_ENI)) + return; + + PushVal(m_PC); + PushVal(m_SR); + + CLRFLAG(FLAG_ENI|FLAG_E|FLAG_M); + + + if(!(TESTFLAG(FLAG_AUT))) + m_PC=SE3208_Read32(8); + else + m_PC=SE3208_Read32(4*standard_irq_callback(0)); +} + + +void se3208_device::execute_run() +{ + do + { + UINT16 Opcode=m_direct->read_word(m_PC, WORD_XOR_LE(0)); + + debugger_instruction_hook(this, m_PC); + + (this->*OpTable[Opcode])(Opcode); + m_PPC=m_PC; + m_PC+=2; + //Check interrupts + if(m_NMI==ASSERT_LINE) + { + SE3208_NMI(); + m_NMI=CLEAR_LINE; + } + else if(m_IRQ==ASSERT_LINE && TESTFLAG(FLAG_ENI)) + { + SE3208_Interrupt(); + } + --(m_icount); + } while(m_icount>0); +} + +void se3208_device::device_start() +{ + BuildTable(); + + m_program = &space(AS_PROGRAM); + m_direct = &m_program->direct(); + + save_item(NAME(m_R)); + save_item(NAME(m_PC)); + save_item(NAME(m_SR)); + save_item(NAME(m_SP)); + save_item(NAME(m_ER)); + save_item(NAME(m_IRQ)); + save_item(NAME(m_NMI)); + + state_add( SE3208_PC, "PC", m_PC).formatstr("%08X"); + state_add( SE3208_SR, "SR", m_SR).formatstr("%08X"); + state_add( SE3208_ER, "ER", m_ER).formatstr("%08X"); + state_add( SE3208_SP, "SP", m_SP).formatstr("%08X"); + state_add( SE3208_R0, "R0", m_R[ 0]).formatstr("%08X"); + state_add( SE3208_R1, "R1", m_R[ 1]).formatstr("%08X"); + state_add( SE3208_R2, "R2", m_R[ 2]).formatstr("%08X"); + state_add( SE3208_R3, "R3", m_R[ 3]).formatstr("%08X"); + state_add( SE3208_R4, "R4", m_R[ 4]).formatstr("%08X"); + state_add( SE3208_R5, "R5", m_R[ 5]).formatstr("%08X"); + state_add( SE3208_R6, "R6", m_R[ 6]).formatstr("%08X"); + state_add( SE3208_R7, "R7", m_R[ 7]).formatstr("%08X"); + state_add( SE3208_PPC, "PPC", m_PPC).formatstr("%08X"); + + state_add(STATE_GENPC, "GENPC", m_PC).noshow(); + state_add(STATE_GENSP, "GENSP", m_SP).noshow(); + state_add(STATE_GENFLAGS, "GENFLAGS", m_SR).formatstr("%10s").noshow(); + state_add(STATE_GENPCBASE, "GENPCBASE", m_PPC).noshow(); + + m_icountptr = &m_icount; +} + + +void se3208_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + switch (entry.index()) + { + case STATE_GENFLAGS: + strprintf(str, "%c%c%c%c %c%c%c%c%c", + m_SR&FLAG_C?'C':'.', + m_SR&FLAG_V?'V':'.', + m_SR&FLAG_S?'S':'.', + m_SR&FLAG_Z?'Z':'.', + + m_SR&FLAG_M?'M':'.', + m_SR&FLAG_E?'E':'.', + m_SR&FLAG_AUT?'A':'.', + m_SR&FLAG_ENI?'I':'.', + m_SR&FLAG_NMI?'N':'.' + ); + break; + } +} + +void se3208_device::execute_set_input( int line, int state ) +{ + if(line==INPUT_LINE_NMI) //NMI + m_NMI=state; + else + m_IRQ=state; +} + +offs_t se3208_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( se3208 ); + return CPU_DISASSEMBLE_NAME(se3208)(this, buffer, pc, oprom, opram, options); +} diff --git a/src/devices/cpu/se3208/se3208.h b/src/devices/cpu/se3208/se3208.h new file mode 100644 index 00000000000..696d53affa8 --- /dev/null +++ b/src/devices/cpu/se3208/se3208.h @@ -0,0 +1,169 @@ +// license:BSD-3-Clause +// copyright-holders:ElSemi + +enum +{ + SE3208_PC=1, SE3208_SR, SE3208_ER, SE3208_SP,SE3208_PPC, + SE3208_R0, SE3208_R1, SE3208_R2, SE3208_R3, SE3208_R4, SE3208_R5, SE3208_R6, SE3208_R7 +}; + +#define SE3208_INT 0 + + +class se3208_device : public cpu_device +{ +public: + // construction/destruction + se3208_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_execute_interface overrides + virtual UINT32 execute_min_cycles() const { return 1; } + virtual UINT32 execute_max_cycles() const { return 1; } + virtual UINT32 execute_input_lines() const { return 1; } + virtual void execute_run(); + virtual void execute_set_input(int inputnum, int state); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const { return (spacenum == AS_PROGRAM) ? &m_program_config : NULL; } + + // device_state_interface overrides + void state_string_export(const device_state_entry &entry, std::string &str); + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const { return 2; } + virtual UINT32 disasm_max_opcode_bytes() const { return 2; } + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + +private: + address_space_config m_program_config; + + //GPR + UINT32 m_R[8]; + //SPR + UINT32 m_PC; + UINT32 m_SR; + UINT32 m_SP; + UINT32 m_ER; + UINT32 m_PPC; + + address_space *m_program; + direct_read_data *m_direct; + UINT8 m_IRQ; + UINT8 m_NMI; + + int m_icount; + + inline UINT32 read_dword_unaligned(address_space &space, UINT32 address); + inline UINT16 read_word_unaligned(address_space &space, UINT32 address); + inline void write_dword_unaligned(address_space &space, UINT32 address, UINT32 data); + inline void write_word_unaligned(address_space &space, UINT32 address, UINT16 data); + inline UINT8 SE3208_Read8(UINT32 addr); + inline UINT16 SE3208_Read16(UINT32 addr); + inline UINT32 SE3208_Read32(UINT32 addr); + inline void SE3208_Write8(UINT32 addr,UINT8 val); + inline void SE3208_Write16(UINT32 addr,UINT16 val); + inline void SE3208_Write32(UINT32 addr,UINT32 val); + inline UINT32 AddWithFlags(UINT32 a,UINT32 b); + inline UINT32 SubWithFlags(UINT32 a,UINT32 b); + inline UINT32 AdcWithFlags(UINT32 a,UINT32 b); + inline UINT32 SbcWithFlags(UINT32 a,UINT32 b); + inline UINT32 MulWithFlags(UINT32 a,UINT32 b); + inline UINT32 NegWithFlags(UINT32 a); + inline UINT32 AsrWithFlags(UINT32 Val, UINT8 By); + inline UINT32 LsrWithFlags(UINT32 Val, UINT8 By); + inline UINT32 AslWithFlags(UINT32 Val, UINT8 By); + inline void PushVal(UINT32 Val); + inline UINT32 PopVal(); + + typedef void (se3208_device::*_OP)(UINT16 Opcode); + _OP OpTable[0x10000]; + + void INVALIDOP(UINT16 Opcode); + void LDB(UINT16 Opcode); + void STB(UINT16 Opcode); + void LDS(UINT16 Opcode); + void STS(UINT16 Opcode); + void LD(UINT16 Opcode); + void ST(UINT16 Opcode); + void LDBU(UINT16 Opcode); + void LDSU(UINT16 Opcode); + void LERI(UINT16 Opcode); + void LDSP(UINT16 Opcode); + void STSP(UINT16 Opcode); + void PUSH(UINT16 Opcode); + void POP(UINT16 Opcode); + void LEATOSP(UINT16 Opcode); + void LEAFROMSP(UINT16 Opcode); + void LEASPTOSP(UINT16 Opcode); + void MOV(UINT16 Opcode); + void LDI(UINT16 Opcode); + void LDBSP(UINT16 Opcode); + void STBSP(UINT16 Opcode); + void LDSSP(UINT16 Opcode); + void STSSP(UINT16 Opcode); + void LDBUSP(UINT16 Opcode); + void LDSUSP(UINT16 Opcode); + void ADDI(UINT16 Opcode); + void SUBI(UINT16 Opcode); + void ADCI(UINT16 Opcode); + void SBCI(UINT16 Opcode); + void ANDI(UINT16 Opcode); + void ORI(UINT16 Opcode); + void XORI(UINT16 Opcode); + void CMPI(UINT16 Opcode); + void TSTI(UINT16 Opcode); + void ADD(UINT16 Opcode); + void SUB(UINT16 Opcode); + void ADC(UINT16 Opcode); + void SBC(UINT16 Opcode); + void AND(UINT16 Opcode); + void OR(UINT16 Opcode); + void XOR(UINT16 Opcode); + void CMP(UINT16 Opcode); + void TST(UINT16 Opcode); + void MULS(UINT16 Opcode); + void NEG(UINT16 Opcode); + void CALL(UINT16 Opcode); + void JV(UINT16 Opcode); + void JNV(UINT16 Opcode); + void JC(UINT16 Opcode); + void JNC(UINT16 Opcode); + void JP(UINT16 Opcode); + void JM(UINT16 Opcode); + void JNZ(UINT16 Opcode); + void JZ(UINT16 Opcode); + void JGE(UINT16 Opcode); + void JLE(UINT16 Opcode); + void JHI(UINT16 Opcode); + void JLS(UINT16 Opcode); + void JGT(UINT16 Opcode); + void JLT(UINT16 Opcode); + void JMP(UINT16 Opcode); + void JR(UINT16 Opcode); + void CALLR(UINT16 Opcode); + void ASR(UINT16 Opcode); + void LSR(UINT16 Opcode); + void ASL(UINT16 Opcode); + void EXTB(UINT16 Opcode); + void EXTS(UINT16 Opcode); + void SET(UINT16 Opcode); + void CLR(UINT16 Opcode); + void SWI(UINT16 Opcode); + void HALT(UINT16 Opcode); + void MVTC(UINT16 Opcode); + void MVFC(UINT16 Opcode); + + void BuildTable(void); + _OP DecodeOp(UINT16 Opcode); + void SE3208_NMI(); + void SE3208_Interrupt(); + +}; + + +extern const device_type SE3208; diff --git a/src/devices/cpu/se3208/se3208dis.c b/src/devices/cpu/se3208/se3208dis.c new file mode 100644 index 00000000000..9de811f846a --- /dev/null +++ b/src/devices/cpu/se3208/se3208dis.c @@ -0,0 +1,1413 @@ +// license:BSD-3-Clause +// copyright-holders:ElSemi +#include "emu.h" +#include "debugger.h" +#include "se3208.h" + + +static struct +{ + UINT32 PC; + UINT32 SR; + UINT32 ER; +} Context; + +#define FLAG_E 0x0800 + +#define CLRFLAG(f) Context.SR&=~(f); +#define SETFLAG(f) Context.SR|=(f); +#define TESTFLAG(f) (Context.SR&(f)) + +#define EXTRACT(val,sbit,ebit) (((val)>>sbit)&((1<<((ebit-sbit)+1))-1)) +#define SEX8(val) ((val&0x80)?(val|0xFFFFFF00):(val&0xFF)) +#define SEX16(val) ((val&0x8000)?(val|0xFFFF0000):(val&0xFFFF)) +#define ZEX8(val) ((val)&0xFF) +#define ZEX16(val) ((val)&0xFFFF) +#define SEX(bits,val) ((val)&(1<<(bits-1))?((val)|(~((1< C/C++ implementation of + * the SH-2 CPU core and was adapted to the MAME CPU core requirements. + * Thanks also go to Chuck Mason and Olivier Galibert + * for letting me peek into their SEMU code :-) + * + *****************************************************************************/ + +/***************************************************************************** + Changes + 20130129 Angelo Salese + - added illegal opcode exception handling, side effect of some Saturn games + on loading like Feda or Falcom Classics Vol. 1 + (i.e. Master CPU Incautiously transfers memory from CD to work RAM H, and + wipes out Slave CPU program code too while at it). + + 20051129 Mariusz Wojcieszek + - introduced memory_decrypted_read_word() for opcode fetching + + 20050813 Mariusz Wojcieszek + - fixed 64 bit / 32 bit division in division unit + + 20031015 O. Galibert + - dma fixes, thanks to sthief + + 20031013 O. Galibert, A. Giles + - timer fixes + - multi-cpu simplifications + + 20030915 O. Galibert + - fix DMA1 irq vector + - ignore writes to DRCRx + - fix cpu number issues + - fix slave/master recognition + - fix wrong-cpu-in-context problem with the timers + + 20021020 O. Galibert + - DMA implementation, lightly tested + - delay slot in debugger fixed + - add divide box mirrors + - Nicola-ify the indentation + - Uncrapify sh2_internal_* + - Put back nmi support that had been lost somehow + + 20020914 R. Belmont + - Initial SH2 internal timers implementation, based on code by O. Galibert. + Makes music work in galspanic4/s/s2, panic street, cyvern, other SKNS games. + - Fix to external division, thanks to "spice" on the E2J board. + Corrects behavior of s1945ii turret boss. + + 20020302 Olivier Galibert (galibert@mame.net) + - Fixed interrupt in delay slot + - Fixed rotcr + - Fixed div1 + - Fixed mulu + - Fixed negc + + 20020301 R. Belmont + - Fixed external division + + 20020225 Olivier Galibert (galibert@mame.net) + - Fixed interrupt handling + + 20010207 Sylvain Glaize (mokona@puupuu.org) + + - Bug fix in void MOVBM(UINT32 m, UINT32 n) (see comment) + - Support of full 32 bit addressing (RB, RW, RL and WB, WW, WL functions) + reason : when the two high bits of the address are set, access is + done directly in the cache data array. The SUPER KANEKO NOVA SYSTEM + sets the stack pointer here, using these addresses as usual RAM access. + + No real cache support has been added. + - Read/Write memory format correction (_bew to _bedw) (see also SH2 + definition in cpuintrf.c and DasmSH2(..) in sh2dasm.c ) + + 20010623 James Forshaw (TyRaNiD@totalise.net) + + - Modified operation of sh2_exception. Done cause mame irq system is stupid, and + doesnt really seem designed for any more than 8 interrupt lines. + + 20010701 James Forshaw (TyRaNiD@totalise.net) + + - Fixed DIV1 operation. Q bit now correctly generated + + 20020218 Added save states (mokona@puupuu.org) + + *****************************************************************************/ + +#include "emu.h" +#include "debugger.h" +#include "sh2.h" +#include "sh2comn.h" + + +/*************************************************************************** + DEBUGGING +***************************************************************************/ + +#define DISABLE_FAST_REGISTERS (0) // set to 1 to turn off usage of register caching +#define SINGLE_INSTRUCTION_MODE (0) + +#define VERBOSE 0 +#define LOG(x) do { if (VERBOSE) logerror x; } while (0) + +/*************************************************************************** + CONSTANTS +***************************************************************************/ + +/* size of the execution code cache */ +#define CACHE_SIZE (32 * 1024 * 1024) + +/* compilation boundaries -- how far back/forward does the analysis extend? */ +#define COMPILE_BACKWARDS_BYTES 64 +#define COMPILE_FORWARDS_BYTES 256 +#define COMPILE_MAX_INSTRUCTIONS ((COMPILE_BACKWARDS_BYTES/2) + (COMPILE_FORWARDS_BYTES/2)) +#define COMPILE_MAX_SEQUENCE 64 + + +const device_type SH1 = &device_creator; +const device_type SH2 = &device_creator; +const device_type SH2A = &device_creator; + +/*------------------------------------------------- + sh2_internal_a5 - read handler for + SH2 internal map +-------------------------------------------------*/ + +READ32_MEMBER(sh2_device::sh2_internal_a5) +{ + return 0xa5a5a5a5; +} + + +/*------------------------------------------------- + sh2_internal_map - maps SH2 built-ins +-------------------------------------------------*/ + +static ADDRESS_MAP_START( sh7604_map, AS_PROGRAM, 32, sh2_device ) + AM_RANGE(0x40000000, 0xbfffffff) AM_READ(sh2_internal_a5) +/*! + @todo: cps3boot breaks with this enabled. Needs customization ... + */ +// AM_RANGE(0xc0000000, 0xc0000fff) AM_RAM // cache data array +// AM_RANGE(0xffffff88, 0xffffff8b) AM_READWRITE(dma_dtcr0_r,dma_dtcr0_w) + AM_RANGE(0xe0000000, 0xe00001ff) AM_MIRROR(0x1ffffe00) AM_READWRITE(sh7604_r, sh7604_w) +ADDRESS_MAP_END + +static ADDRESS_MAP_START( sh7021_map, AS_PROGRAM, 32, sh2a_device ) +// overrides + AM_RANGE(0x05ffff40, 0x05ffff43) AM_READWRITE(dma_sar0_r, dma_sar0_w) + AM_RANGE(0x05ffff44, 0x05ffff47) AM_READWRITE(dma_dar0_r, dma_dar0_w) + AM_RANGE(0x05ffff48, 0x05ffff4b) AM_READWRITE16(dmaor_r, dmaor_w,0xffff0000) + AM_RANGE(0x05ffff48, 0x05ffff4b) AM_READWRITE16(dma_tcr0_r, dma_tcr0_w,0x0000ffff) + AM_RANGE(0x05ffff4c, 0x05ffff4f) AM_READWRITE16(dma_chcr0_r, dma_chcr0_w, 0x0000ffff) +// fall-back + AM_RANGE(0x05fffe00, 0x05ffffff) AM_READWRITE16(sh7021_r,sh7021_w,0xffffffff) // SH-7032H internal i/o +// AM_RANGE(0x07000000, 0x070003ff) AM_RAM AM_SHARE("oram")// on-chip RAM, actually at 0xf000000 (1 kb) +// AM_RANGE(0x0f000000, 0x0f0003ff) AM_RAM AM_SHARE("oram")// on-chip RAM, actually at 0xf000000 (1 kb) +ADDRESS_MAP_END + +static ADDRESS_MAP_START( sh7032_map, AS_PROGRAM, 32, sh1_device ) +// fall-back + AM_RANGE(0x05fffe00, 0x05ffffff) AM_READWRITE16(sh7032_r,sh7032_w,0xffffffff) // SH-7032H internal i/o +ADDRESS_MAP_END + +sh2_device::sh2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : cpu_device(mconfig, SH2, "SH-2", tag, owner, clock, "sh2", __FILE__) + , m_program_config("program", ENDIANNESS_BIG, 32, 32, 0, ADDRESS_MAP_NAME(sh7604_map)) + , m_decrypted_program_config("decrypted_opcodes", ENDIANNESS_BIG, 32, 32, 0) + , m_is_slave(0) + , m_cpu_type(CPU_TYPE_SH2) + , m_cache(CACHE_SIZE + sizeof(internal_sh2_state)) + , m_drcuml(NULL) +// , m_drcuml(*this, m_cache, 0, 1, 32, 1) + , m_drcfe(NULL) + , m_drcoptions(0) + , m_sh2_state(NULL) + , m_entry(NULL) + , m_read8(NULL) + , m_write8(NULL) + , m_read16(NULL) + , m_write16(NULL) + , m_read32(NULL) + , m_write32(NULL) + , m_interrupt(NULL) + , m_nocode(NULL) + , m_out_of_cycles(NULL) + , m_debugger_temp(0) +{ + m_isdrc = (mconfig.options().drc() && !mconfig.m_force_no_drc) ? true : false; +} + + +void sh2_device::device_stop() +{ + /* clean up the DRC */ + if ( m_drcuml ) + { + auto_free(machine(), m_drcuml); + } +} + + +sh2_device::sh2_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source, int cpu_type, address_map_constructor internal_map, int addrlines ) + : cpu_device(mconfig, type, name, tag, owner, clock, shortname, source) + , m_program_config("program", ENDIANNESS_BIG, 32, addrlines, 0, internal_map) + , m_decrypted_program_config("decrypted_opcodes", ENDIANNESS_BIG, 32, addrlines, 0) + , m_is_slave(0) + , m_cpu_type(cpu_type) + , m_cache(CACHE_SIZE + sizeof(internal_sh2_state)) + , m_drcuml(NULL) +// , m_drcuml(*this, m_cache, 0, 1, 32, 1) + , m_drcfe(NULL) + , m_drcoptions(0) + , m_sh2_state(NULL) + , m_entry(NULL) + , m_read8(NULL) + , m_write8(NULL) + , m_read16(NULL) + , m_write16(NULL) + , m_read32(NULL) + , m_write32(NULL) + , m_interrupt(NULL) + , m_nocode(NULL) + , m_out_of_cycles(NULL) +{ + m_isdrc = (mconfig.options().drc() && !mconfig.m_force_no_drc) ? true : false; +} + +sh2a_device::sh2a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : sh2_device(mconfig, SH1, "SH-2A", tag, owner, clock, "sh2a", __FILE__, CPU_TYPE_SH2, ADDRESS_MAP_NAME(sh7021_map), 28 ) +{ +} + +sh1_device::sh1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : sh2_device(mconfig, SH1, "SH-1", tag, owner, clock, "sh1", __FILE__, CPU_TYPE_SH1, ADDRESS_MAP_NAME(sh7032_map), 28 ) +{ +} + +const address_space_config *sh2_device::memory_space_config(address_spacenum spacenum) const +{ + switch(spacenum) + { + case AS_PROGRAM: return &m_program_config; + case AS_DECRYPTED_OPCODES: return has_configured_map(AS_DECRYPTED_OPCODES) ? &m_decrypted_program_config : NULL; + default: return NULL; + } +} + +offs_t sh2_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( sh2 ); + return CPU_DISASSEMBLE_NAME( sh2 )(this, buffer, pc, oprom, opram, options); +} + + +/* speed up delay loops, bail out of tight loops */ +#define BUSY_LOOP_HACKS 1 + +#define VERBOSE 0 + +#define LOG(x) do { if (VERBOSE) logerror x; } while (0) + +UINT8 sh2_device::RB(offs_t A) +{ + if((A & 0xf0000000) == 0 || (A & 0xf0000000) == 0x20000000) + return m_program->read_byte(A & AM); + + return m_program->read_byte(A); +} + +UINT16 sh2_device::RW(offs_t A) +{ + if((A & 0xf0000000) == 0 || (A & 0xf0000000) == 0x20000000) + return m_program->read_word(A & AM); + + return m_program->read_word(A); +} + +UINT32 sh2_device::RL(offs_t A) +{ + /* 0x20000000 no Cache */ + /* 0x00000000 read thru Cache if CE bit is 1 */ + if((A & 0xf0000000) == 0 || (A & 0xf0000000) == 0x20000000) + return m_program->read_dword(A & AM); + + return m_program->read_dword(A); +} + +void sh2_device::WB(offs_t A, UINT8 V) +{ + if((A & 0xf0000000) == 0 || (A & 0xf0000000) == 0x20000000) + { + m_program->write_byte(A & AM,V); + return; + } + + m_program->write_byte(A,V); +} + +void sh2_device::WW(offs_t A, UINT16 V) +{ + if((A & 0xf0000000) == 0 || (A & 0xf0000000) == 0x20000000) + { + m_program->write_word(A & AM,V); + return; + } + + m_program->write_word(A,V); +} + +void sh2_device::WL(offs_t A, UINT32 V) +{ + if((A & 0xf0000000) == 0 || (A & 0xf0000000) == 0x20000000) + { + m_program->write_dword(A & AM,V); + return; + } + + /* 0x20000000 no Cache */ + /* 0x00000000 read thru Cache if CE bit is 1 */ + m_program->write_dword(A,V); +} + +/* code cycles t-bit + * 0011 nnnn mmmm 1100 1 - + * ADD Rm,Rn + */ +void sh2_device::ADD(UINT32 m, UINT32 n) +{ + m_sh2_state->r[n] += m_sh2_state->r[m]; +} + +/* code cycles t-bit + * 0111 nnnn iiii iiii 1 - + * ADD #imm,Rn + */ +void sh2_device::ADDI(UINT32 i, UINT32 n) +{ + m_sh2_state->r[n] += (INT32)(INT16)(INT8)i; +} + +/* code cycles t-bit + * 0011 nnnn mmmm 1110 1 carry + * ADDC Rm,Rn + */ +void sh2_device::ADDC(UINT32 m, UINT32 n) +{ + UINT32 tmp0, tmp1; + + tmp1 = m_sh2_state->r[n] + m_sh2_state->r[m]; + tmp0 = m_sh2_state->r[n]; + m_sh2_state->r[n] = tmp1 + (m_sh2_state->sr & T); + if (tmp0 > tmp1) + m_sh2_state->sr |= T; + else + m_sh2_state->sr &= ~T; + if (tmp1 > m_sh2_state->r[n]) + m_sh2_state->sr |= T; +} + +/* code cycles t-bit + * 0011 nnnn mmmm 1111 1 overflow + * ADDV Rm,Rn + */ +void sh2_device::ADDV(UINT32 m, UINT32 n) +{ + INT32 dest, src, ans; + + if ((INT32) m_sh2_state->r[n] >= 0) + dest = 0; + else + dest = 1; + if ((INT32) m_sh2_state->r[m] >= 0) + src = 0; + else + src = 1; + src += dest; + m_sh2_state->r[n] += m_sh2_state->r[m]; + if ((INT32) m_sh2_state->r[n] >= 0) + ans = 0; + else + ans = 1; + ans += dest; + if (src == 0 || src == 2) + { + if (ans == 1) + m_sh2_state->sr |= T; + else + m_sh2_state->sr &= ~T; + } + else + m_sh2_state->sr &= ~T; +} + +/* code cycles t-bit + * 0010 nnnn mmmm 1001 1 - + * AND Rm,Rn + */ +void sh2_device::AND(UINT32 m, UINT32 n) +{ + m_sh2_state->r[n] &= m_sh2_state->r[m]; +} + + +/* code cycles t-bit + * 1100 1001 iiii iiii 1 - + * AND #imm,R0 + */ +void sh2_device::ANDI(UINT32 i) +{ + m_sh2_state->r[0] &= i; +} + +/* code cycles t-bit + * 1100 1101 iiii iiii 1 - + * AND.B #imm,@(R0,GBR) + */ +void sh2_device::ANDM(UINT32 i) +{ + UINT32 temp; + + m_sh2_state->ea = m_sh2_state->gbr + m_sh2_state->r[0]; + temp = i & RB( m_sh2_state->ea ); + WB( m_sh2_state->ea, temp ); + m_sh2_state->icount -= 2; +} + +/* code cycles t-bit + * 1000 1011 dddd dddd 3/1 - + * BF disp8 + */ +void sh2_device::BF(UINT32 d) +{ + if ((m_sh2_state->sr & T) == 0) + { + INT32 disp = ((INT32)d << 24) >> 24; + m_sh2_state->pc = m_sh2_state->ea = m_sh2_state->pc + disp * 2 + 2; + m_sh2_state->icount -= 2; + } +} + +/* code cycles t-bit + * 1000 1111 dddd dddd 3/1 - + * BFS disp8 + */ +void sh2_device::BFS(UINT32 d) +{ + if ((m_sh2_state->sr & T) == 0) + { + INT32 disp = ((INT32)d << 24) >> 24; + m_delay = m_sh2_state->pc; + m_sh2_state->pc = m_sh2_state->ea = m_sh2_state->pc + disp * 2 + 2; + m_sh2_state->icount--; + } +} + +/* code cycles t-bit + * 1010 dddd dddd dddd 2 - + * BRA disp12 + */ +void sh2_device::BRA(UINT32 d) +{ + INT32 disp = ((INT32)d << 20) >> 20; + +#if BUSY_LOOP_HACKS + if (disp == -2) + { + UINT32 next_opcode = RW( m_sh2_state->ppc & AM ); + /* BRA $ + * NOP + */ + if (next_opcode == 0x0009) + m_sh2_state->icount %= 3; /* cycles for BRA $ and NOP taken (3) */ + } +#endif + m_delay = m_sh2_state->pc; + m_sh2_state->pc = m_sh2_state->ea = m_sh2_state->pc + disp * 2 + 2; + m_sh2_state->icount--; +} + +/* code cycles t-bit + * 0000 mmmm 0010 0011 2 - + * BRAF Rm + */ +void sh2_device::BRAF(UINT32 m) +{ + m_delay = m_sh2_state->pc; + m_sh2_state->pc += m_sh2_state->r[m] + 2; + m_sh2_state->icount--; +} + +/* code cycles t-bit + * 1011 dddd dddd dddd 2 - + * BSR disp12 + */ +void sh2_device::BSR(UINT32 d) +{ + INT32 disp = ((INT32)d << 20) >> 20; + + m_sh2_state->pr = m_sh2_state->pc + 2; + m_delay = m_sh2_state->pc; + m_sh2_state->pc = m_sh2_state->ea = m_sh2_state->pc + disp * 2 + 2; + m_sh2_state->icount--; +} + +/* code cycles t-bit + * 0000 mmmm 0000 0011 2 - + * BSRF Rm + */ +void sh2_device::BSRF(UINT32 m) +{ + m_sh2_state->pr = m_sh2_state->pc + 2; + m_delay = m_sh2_state->pc; + m_sh2_state->pc += m_sh2_state->r[m] + 2; + m_sh2_state->icount--; +} + +/* code cycles t-bit + * 1000 1001 dddd dddd 3/1 - + * BT disp8 + */ +void sh2_device::BT(UINT32 d) +{ + if ((m_sh2_state->sr & T) != 0) + { + INT32 disp = ((INT32)d << 24) >> 24; + m_sh2_state->pc = m_sh2_state->ea = m_sh2_state->pc + disp * 2 + 2; + m_sh2_state->icount -= 2; + } +} + +/* code cycles t-bit + * 1000 1101 dddd dddd 2/1 - + * BTS disp8 + */ +void sh2_device::BTS(UINT32 d) +{ + if ((m_sh2_state->sr & T) != 0) + { + INT32 disp = ((INT32)d << 24) >> 24; + m_delay = m_sh2_state->pc; + m_sh2_state->pc = m_sh2_state->ea = m_sh2_state->pc + disp * 2 + 2; + m_sh2_state->icount--; + } +} + +/* code cycles t-bit + * 0000 0000 0010 1000 1 - + * CLRMAC + */ +void sh2_device::CLRMAC() +{ + m_sh2_state->mach = 0; + m_sh2_state->macl = 0; +} + +/* code cycles t-bit + * 0000 0000 0000 1000 1 - + * CLRT + */ +void sh2_device::CLRT() +{ + m_sh2_state->sr &= ~T; +} + +/* code cycles t-bit + * 0011 nnnn mmmm 0000 1 comparison result + * CMP_EQ Rm,Rn + */ +void sh2_device::CMPEQ(UINT32 m, UINT32 n) +{ + if (m_sh2_state->r[n] == m_sh2_state->r[m]) + m_sh2_state->sr |= T; + else + m_sh2_state->sr &= ~T; +} + +/* code cycles t-bit + * 0011 nnnn mmmm 0011 1 comparison result + * CMP_GE Rm,Rn + */ +void sh2_device::CMPGE(UINT32 m, UINT32 n) +{ + if ((INT32) m_sh2_state->r[n] >= (INT32) m_sh2_state->r[m]) + m_sh2_state->sr |= T; + else + m_sh2_state->sr &= ~T; +} + +/* code cycles t-bit + * 0011 nnnn mmmm 0111 1 comparison result + * CMP_GT Rm,Rn + */ +void sh2_device::CMPGT(UINT32 m, UINT32 n) +{ + if ((INT32) m_sh2_state->r[n] > (INT32) m_sh2_state->r[m]) + m_sh2_state->sr |= T; + else + m_sh2_state->sr &= ~T; +} + +/* code cycles t-bit + * 0011 nnnn mmmm 0110 1 comparison result + * CMP_HI Rm,Rn + */ +void sh2_device::CMPHI(UINT32 m, UINT32 n) +{ + if ((UINT32) m_sh2_state->r[n] > (UINT32) m_sh2_state->r[m]) + m_sh2_state->sr |= T; + else + m_sh2_state->sr &= ~T; +} + +/* code cycles t-bit + * 0011 nnnn mmmm 0010 1 comparison result + * CMP_HS Rm,Rn + */ +void sh2_device::CMPHS(UINT32 m, UINT32 n) +{ + if ((UINT32) m_sh2_state->r[n] >= (UINT32) m_sh2_state->r[m]) + m_sh2_state->sr |= T; + else + m_sh2_state->sr &= ~T; +} + + +/* code cycles t-bit + * 0100 nnnn 0001 0101 1 comparison result + * CMP_PL Rn + */ +void sh2_device::CMPPL(UINT32 n) +{ + if ((INT32) m_sh2_state->r[n] > 0) + m_sh2_state->sr |= T; + else + m_sh2_state->sr &= ~T; +} + +/* code cycles t-bit + * 0100 nnnn 0001 0001 1 comparison result + * CMP_PZ Rn + */ +void sh2_device::CMPPZ(UINT32 n) +{ + if ((INT32) m_sh2_state->r[n] >= 0) + m_sh2_state->sr |= T; + else + m_sh2_state->sr &= ~T; +} + +/* code cycles t-bit + * 0010 nnnn mmmm 1100 1 comparison result + * CMP_STR Rm,Rn + */ +void sh2_device::CMPSTR(UINT32 m, UINT32 n) + { + UINT32 temp; + INT32 HH, HL, LH, LL; + temp = m_sh2_state->r[n] ^ m_sh2_state->r[m]; + HH = (temp >> 24) & 0xff; + HL = (temp >> 16) & 0xff; + LH = (temp >> 8) & 0xff; + LL = temp & 0xff; + if (HH && HL && LH && LL) + m_sh2_state->sr &= ~T; + else + m_sh2_state->sr |= T; + } + + +/* code cycles t-bit + * 1000 1000 iiii iiii 1 comparison result + * CMP/EQ #imm,R0 + */ +void sh2_device::CMPIM(UINT32 i) +{ + UINT32 imm = (UINT32)(INT32)(INT16)(INT8)i; + + if (m_sh2_state->r[0] == imm) + m_sh2_state->sr |= T; + else + m_sh2_state->sr &= ~T; +} + +/* code cycles t-bit + * 0010 nnnn mmmm 0111 1 calculation result + * DIV0S Rm,Rn + */ +void sh2_device::DIV0S(UINT32 m, UINT32 n) +{ + if ((m_sh2_state->r[n] & 0x80000000) == 0) + m_sh2_state->sr &= ~Q; + else + m_sh2_state->sr |= Q; + if ((m_sh2_state->r[m] & 0x80000000) == 0) + m_sh2_state->sr &= ~M; + else + m_sh2_state->sr |= M; + if ((m_sh2_state->r[m] ^ m_sh2_state->r[n]) & 0x80000000) + m_sh2_state->sr |= T; + else + m_sh2_state->sr &= ~T; +} + +/* code cycles t-bit + * 0000 0000 0001 1001 1 0 + * DIV0U + */ +void sh2_device::DIV0U() +{ + m_sh2_state->sr &= ~(M | Q | T); +} + +/* code cycles t-bit + * 0011 nnnn mmmm 0100 1 calculation result + * DIV1 Rm,Rn + */ +void sh2_device::DIV1(UINT32 m, UINT32 n) +{ + UINT32 tmp0; + UINT32 old_q; + + old_q = m_sh2_state->sr & Q; + if (0x80000000 & m_sh2_state->r[n]) + m_sh2_state->sr |= Q; + else + m_sh2_state->sr &= ~Q; + + m_sh2_state->r[n] = (m_sh2_state->r[n] << 1) | (m_sh2_state->sr & T); + + if (!old_q) + { + if (!(m_sh2_state->sr & M)) + { + tmp0 = m_sh2_state->r[n]; + m_sh2_state->r[n] -= m_sh2_state->r[m]; + if(!(m_sh2_state->sr & Q)) + if(m_sh2_state->r[n] > tmp0) + m_sh2_state->sr |= Q; + else + m_sh2_state->sr &= ~Q; + else + if(m_sh2_state->r[n] > tmp0) + m_sh2_state->sr &= ~Q; + else + m_sh2_state->sr |= Q; + } + else + { + tmp0 = m_sh2_state->r[n]; + m_sh2_state->r[n] += m_sh2_state->r[m]; + if(!(m_sh2_state->sr & Q)) + { + if(m_sh2_state->r[n] < tmp0) + m_sh2_state->sr &= ~Q; + else + m_sh2_state->sr |= Q; + } + else + { + if(m_sh2_state->r[n] < tmp0) + m_sh2_state->sr |= Q; + else + m_sh2_state->sr &= ~Q; + } + } + } + else + { + if (!(m_sh2_state->sr & M)) + { + tmp0 = m_sh2_state->r[n]; + m_sh2_state->r[n] += m_sh2_state->r[m]; + if(!(m_sh2_state->sr & Q)) + if(m_sh2_state->r[n] < tmp0) + m_sh2_state->sr |= Q; + else + m_sh2_state->sr &= ~Q; + else + if(m_sh2_state->r[n] < tmp0) + m_sh2_state->sr &= ~Q; + else + m_sh2_state->sr |= Q; + } + else + { + tmp0 = m_sh2_state->r[n]; + m_sh2_state->r[n] -= m_sh2_state->r[m]; + if(!(m_sh2_state->sr & Q)) + if(m_sh2_state->r[n] > tmp0) + m_sh2_state->sr &= ~Q; + else + m_sh2_state->sr |= Q; + else + if(m_sh2_state->r[n] > tmp0) + m_sh2_state->sr |= Q; + else + m_sh2_state->sr &= ~Q; + } + } + + tmp0 = (m_sh2_state->sr & (Q | M)); + if((!tmp0) || (tmp0 == 0x300)) /* if Q == M set T else clear T */ + m_sh2_state->sr |= T; + else + m_sh2_state->sr &= ~T; +} + +/* DMULS.L Rm,Rn */ +void sh2_device::DMULS(UINT32 m, UINT32 n) +{ + UINT32 RnL, RnH, RmL, RmH, Res0, Res1, Res2; + UINT32 temp0, temp1, temp2, temp3; + INT32 tempm, tempn, fnLmL; + + tempn = (INT32) m_sh2_state->r[n]; + tempm = (INT32) m_sh2_state->r[m]; + if (tempn < 0) + tempn = 0 - tempn; + if (tempm < 0) + tempm = 0 - tempm; + if ((INT32) (m_sh2_state->r[n] ^ m_sh2_state->r[m]) < 0) + fnLmL = -1; + else + fnLmL = 0; + temp1 = (UINT32) tempn; + temp2 = (UINT32) tempm; + RnL = temp1 & 0x0000ffff; + RnH = (temp1 >> 16) & 0x0000ffff; + RmL = temp2 & 0x0000ffff; + RmH = (temp2 >> 16) & 0x0000ffff; + temp0 = RmL * RnL; + temp1 = RmH * RnL; + temp2 = RmL * RnH; + temp3 = RmH * RnH; + Res2 = 0; + Res1 = temp1 + temp2; + if (Res1 < temp1) + Res2 += 0x00010000; + temp1 = (Res1 << 16) & 0xffff0000; + Res0 = temp0 + temp1; + if (Res0 < temp0) + Res2++; + Res2 = Res2 + ((Res1 >> 16) & 0x0000ffff) + temp3; + if (fnLmL < 0) + { + Res2 = ~Res2; + if (Res0 == 0) + Res2++; + else + Res0 = (~Res0) + 1; + } + m_sh2_state->mach = Res2; + m_sh2_state->macl = Res0; + m_sh2_state->icount--; +} + +/* DMULU.L Rm,Rn */ +void sh2_device::DMULU(UINT32 m, UINT32 n) +{ + UINT32 RnL, RnH, RmL, RmH, Res0, Res1, Res2; + UINT32 temp0, temp1, temp2, temp3; + + RnL = m_sh2_state->r[n] & 0x0000ffff; + RnH = (m_sh2_state->r[n] >> 16) & 0x0000ffff; + RmL = m_sh2_state->r[m] & 0x0000ffff; + RmH = (m_sh2_state->r[m] >> 16) & 0x0000ffff; + temp0 = RmL * RnL; + temp1 = RmH * RnL; + temp2 = RmL * RnH; + temp3 = RmH * RnH; + Res2 = 0; + Res1 = temp1 + temp2; + if (Res1 < temp1) + Res2 += 0x00010000; + temp1 = (Res1 << 16) & 0xffff0000; + Res0 = temp0 + temp1; + if (Res0 < temp0) + Res2++; + Res2 = Res2 + ((Res1 >> 16) & 0x0000ffff) + temp3; + m_sh2_state->mach = Res2; + m_sh2_state->macl = Res0; + m_sh2_state->icount--; +} + +/* DT Rn */ +void sh2_device::DT(UINT32 n) +{ + m_sh2_state->r[n]--; + if (m_sh2_state->r[n] == 0) + m_sh2_state->sr |= T; + else + m_sh2_state->sr &= ~T; +#if BUSY_LOOP_HACKS + { + UINT32 next_opcode = RW( m_sh2_state->ppc & AM ); + /* DT Rn + * BF $-2 + */ + if (next_opcode == 0x8bfd) + { + while (m_sh2_state->r[n] > 1 && m_sh2_state->icount > 4) + { + m_sh2_state->r[n]--; + m_sh2_state->icount -= 4; /* cycles for DT (1) and BF taken (3) */ + } + } + } +#endif +} + +/* EXTS.B Rm,Rn */ +void sh2_device::EXTSB(UINT32 m, UINT32 n) +{ + m_sh2_state->r[n] = ((INT32)m_sh2_state->r[m] << 24) >> 24; +} + +/* EXTS.W Rm,Rn */ +void sh2_device::EXTSW(UINT32 m, UINT32 n) +{ + m_sh2_state->r[n] = ((INT32)m_sh2_state->r[m] << 16) >> 16; +} + +/* EXTU.B Rm,Rn */ +void sh2_device::EXTUB(UINT32 m, UINT32 n) +{ + m_sh2_state->r[n] = m_sh2_state->r[m] & 0x000000ff; +} + +/* EXTU.W Rm,Rn */ +void sh2_device::EXTUW(UINT32 m, UINT32 n) +{ + m_sh2_state->r[n] = m_sh2_state->r[m] & 0x0000ffff; +} + +/* ILLEGAL */ +void sh2_device::ILLEGAL() +{ + logerror("SH2.%s: Illegal opcode at %08x\n", tag(), m_sh2_state->pc - 2); + m_sh2_state->r[15] -= 4; + WL( m_sh2_state->r[15], m_sh2_state->sr ); /* push SR onto stack */ + m_sh2_state->r[15] -= 4; + WL( m_sh2_state->r[15], m_sh2_state->pc - 2 ); /* push PC onto stack */ + + /* fetch PC */ + m_sh2_state->pc = RL( m_sh2_state->vbr + 4 * 4 ); + + /* TODO: timing is a guess */ + m_sh2_state->icount -= 5; +} + + +/* JMP @Rm */ +void sh2_device::JMP(UINT32 m) +{ + m_delay = m_sh2_state->pc; + m_sh2_state->pc = m_sh2_state->ea = m_sh2_state->r[m]; + m_sh2_state->icount--; +} + +/* JSR @Rm */ +void sh2_device::JSR(UINT32 m) +{ + m_delay = m_sh2_state->pc; + m_sh2_state->pr = m_sh2_state->pc + 2; + m_sh2_state->pc = m_sh2_state->ea = m_sh2_state->r[m]; + m_sh2_state->icount--; +} + + +/* LDC Rm,SR */ +void sh2_device::LDCSR(UINT32 m) +{ + m_sh2_state->sr = m_sh2_state->r[m] & FLAGS; + m_test_irq = 1; +} + +/* LDC Rm,GBR */ +void sh2_device::LDCGBR(UINT32 m) +{ + m_sh2_state->gbr = m_sh2_state->r[m]; +} + +/* LDC Rm,VBR */ +void sh2_device::LDCVBR(UINT32 m) +{ + m_sh2_state->vbr = m_sh2_state->r[m]; +} + +/* LDC.L @Rm+,SR */ +void sh2_device::LDCMSR(UINT32 m) +{ + m_sh2_state->ea = m_sh2_state->r[m]; + m_sh2_state->sr = RL( m_sh2_state->ea ) & FLAGS; + m_sh2_state->r[m] += 4; + m_sh2_state->icount -= 2; + m_test_irq = 1; +} + +/* LDC.L @Rm+,GBR */ +void sh2_device::LDCMGBR(UINT32 m) +{ + m_sh2_state->ea = m_sh2_state->r[m]; + m_sh2_state->gbr = RL( m_sh2_state->ea ); + m_sh2_state->r[m] += 4; + m_sh2_state->icount -= 2; +} + +/* LDC.L @Rm+,VBR */ +void sh2_device::LDCMVBR(UINT32 m) +{ + m_sh2_state->ea = m_sh2_state->r[m]; + m_sh2_state->vbr = RL( m_sh2_state->ea ); + m_sh2_state->r[m] += 4; + m_sh2_state->icount -= 2; +} + +/* LDS Rm,MACH */ +void sh2_device::LDSMACH(UINT32 m) +{ + m_sh2_state->mach = m_sh2_state->r[m]; +} + +/* LDS Rm,MACL */ +void sh2_device::LDSMACL(UINT32 m) +{ + m_sh2_state->macl = m_sh2_state->r[m]; +} + +/* LDS Rm,PR */ +void sh2_device::LDSPR(UINT32 m) +{ + m_sh2_state->pr = m_sh2_state->r[m]; +} + +/* LDS.L @Rm+,MACH */ +void sh2_device::LDSMMACH(UINT32 m) +{ + m_sh2_state->ea = m_sh2_state->r[m]; + m_sh2_state->mach = RL( m_sh2_state->ea ); + m_sh2_state->r[m] += 4; +} + +/* LDS.L @Rm+,MACL */ +void sh2_device::LDSMMACL(UINT32 m) +{ + m_sh2_state->ea = m_sh2_state->r[m]; + m_sh2_state->macl = RL( m_sh2_state->ea ); + m_sh2_state->r[m] += 4; +} + +/* LDS.L @Rm+,PR */ +void sh2_device::LDSMPR(UINT32 m) +{ + m_sh2_state->ea = m_sh2_state->r[m]; + m_sh2_state->pr = RL( m_sh2_state->ea ); + m_sh2_state->r[m] += 4; +} + +/* MAC.L @Rm+,@Rn+ */ +void sh2_device::MAC_L(UINT32 m, UINT32 n) +{ + UINT32 RnL, RnH, RmL, RmH, Res0, Res1, Res2; + UINT32 temp0, temp1, temp2, temp3; + INT32 tempm, tempn, fnLmL; + + tempn = (INT32) RL( m_sh2_state->r[n] ); + m_sh2_state->r[n] += 4; + tempm = (INT32) RL( m_sh2_state->r[m] ); + m_sh2_state->r[m] += 4; + if ((INT32) (tempn ^ tempm) < 0) + fnLmL = -1; + else + fnLmL = 0; + if (tempn < 0) + tempn = 0 - tempn; + if (tempm < 0) + tempm = 0 - tempm; + temp1 = (UINT32) tempn; + temp2 = (UINT32) tempm; + RnL = temp1 & 0x0000ffff; + RnH = (temp1 >> 16) & 0x0000ffff; + RmL = temp2 & 0x0000ffff; + RmH = (temp2 >> 16) & 0x0000ffff; + temp0 = RmL * RnL; + temp1 = RmH * RnL; + temp2 = RmL * RnH; + temp3 = RmH * RnH; + Res2 = 0; + Res1 = temp1 + temp2; + if (Res1 < temp1) + Res2 += 0x00010000; + temp1 = (Res1 << 16) & 0xffff0000; + Res0 = temp0 + temp1; + if (Res0 < temp0) + Res2++; + Res2 = Res2 + ((Res1 >> 16) & 0x0000ffff) + temp3; + if (fnLmL < 0) + { + Res2 = ~Res2; + if (Res0 == 0) + Res2++; + else + Res0 = (~Res0) + 1; + } + if (m_sh2_state->sr & S) + { + Res0 = m_sh2_state->macl + Res0; + if (m_sh2_state->macl > Res0) + Res2++; + Res2 += (m_sh2_state->mach & 0x0000ffff); + if (((INT32) Res2 < 0) && (Res2 < 0xffff8000)) + { + Res2 = 0x00008000; + Res0 = 0x00000000; + } + else if (((INT32) Res2 > 0) && (Res2 > 0x00007fff)) + { + Res2 = 0x00007fff; + Res0 = 0xffffffff; + } + m_sh2_state->mach = Res2; + m_sh2_state->macl = Res0; + } + else + { + Res0 = m_sh2_state->macl + Res0; + if (m_sh2_state->macl > Res0) + Res2++; + Res2 += m_sh2_state->mach; + m_sh2_state->mach = Res2; + m_sh2_state->macl = Res0; + } + m_sh2_state->icount -= 2; +} + +/* MAC.W @Rm+,@Rn+ */ +void sh2_device::MAC_W(UINT32 m, UINT32 n) +{ + INT32 tempm, tempn, dest, src, ans; + UINT32 templ; + + tempn = (INT32) RW( m_sh2_state->r[n] ); + m_sh2_state->r[n] += 2; + tempm = (INT32) RW( m_sh2_state->r[m] ); + m_sh2_state->r[m] += 2; + templ = m_sh2_state->macl; + tempm = ((INT32) (short) tempn * (INT32) (short) tempm); + if ((INT32) m_sh2_state->macl >= 0) + dest = 0; + else + dest = 1; + if ((INT32) tempm >= 0) + { + src = 0; + tempn = 0; + } + else + { + src = 1; + tempn = 0xffffffff; + } + src += dest; + m_sh2_state->macl += tempm; + if ((INT32) m_sh2_state->macl >= 0) + ans = 0; + else + ans = 1; + ans += dest; + if (m_sh2_state->sr & S) + { + if (ans == 1) + { + if (src == 0) + m_sh2_state->macl = 0x7fffffff; + if (src == 2) + m_sh2_state->macl = 0x80000000; + } + } + else + { + m_sh2_state->mach += tempn; + if (templ > m_sh2_state->macl) + m_sh2_state->mach += 1; + } + m_sh2_state->icount -= 2; +} + +/* MOV Rm,Rn */ +void sh2_device::MOV(UINT32 m, UINT32 n) +{ + m_sh2_state->r[n] = m_sh2_state->r[m]; +} + +/* MOV.B Rm,@Rn */ +void sh2_device::MOVBS(UINT32 m, UINT32 n) +{ + m_sh2_state->ea = m_sh2_state->r[n]; + WB( m_sh2_state->ea, m_sh2_state->r[m] & 0x000000ff); +} + +/* MOV.W Rm,@Rn */ +void sh2_device::MOVWS(UINT32 m, UINT32 n) +{ + m_sh2_state->ea = m_sh2_state->r[n]; + WW( m_sh2_state->ea, m_sh2_state->r[m] & 0x0000ffff); +} + +/* MOV.L Rm,@Rn */ +void sh2_device::MOVLS(UINT32 m, UINT32 n) +{ + m_sh2_state->ea = m_sh2_state->r[n]; + WL( m_sh2_state->ea, m_sh2_state->r[m] ); +} + +/* MOV.B @Rm,Rn */ +void sh2_device::MOVBL(UINT32 m, UINT32 n) +{ + m_sh2_state->ea = m_sh2_state->r[m]; + m_sh2_state->r[n] = (UINT32)(INT32)(INT16)(INT8) RB( m_sh2_state->ea ); +} + +/* MOV.W @Rm,Rn */ +void sh2_device::MOVWL(UINT32 m, UINT32 n) +{ + m_sh2_state->ea = m_sh2_state->r[m]; + m_sh2_state->r[n] = (UINT32)(INT32)(INT16) RW( m_sh2_state->ea ); +} + +/* MOV.L @Rm,Rn */ +void sh2_device::MOVLL(UINT32 m, UINT32 n) +{ + m_sh2_state->ea = m_sh2_state->r[m]; + m_sh2_state->r[n] = RL( m_sh2_state->ea ); +} + +/* MOV.B Rm,@-Rn */ +void sh2_device::MOVBM(UINT32 m, UINT32 n) +{ + /* SMG : bug fix, was reading m_sh2_state->r[n] */ + UINT32 data = m_sh2_state->r[m] & 0x000000ff; + + m_sh2_state->r[n] -= 1; + WB( m_sh2_state->r[n], data ); +} + +/* MOV.W Rm,@-Rn */ +void sh2_device::MOVWM(UINT32 m, UINT32 n) +{ + UINT32 data = m_sh2_state->r[m] & 0x0000ffff; + + m_sh2_state->r[n] -= 2; + WW( m_sh2_state->r[n], data ); +} + +/* MOV.L Rm,@-Rn */ +void sh2_device::MOVLM(UINT32 m, UINT32 n) +{ + UINT32 data = m_sh2_state->r[m]; + + m_sh2_state->r[n] -= 4; + WL( m_sh2_state->r[n], data ); +} + +/* MOV.B @Rm+,Rn */ +void sh2_device::MOVBP(UINT32 m, UINT32 n) +{ + m_sh2_state->r[n] = (UINT32)(INT32)(INT16)(INT8) RB( m_sh2_state->r[m] ); + if (n != m) + m_sh2_state->r[m] += 1; +} + +/* MOV.W @Rm+,Rn */ +void sh2_device::MOVWP(UINT32 m, UINT32 n) +{ + m_sh2_state->r[n] = (UINT32)(INT32)(INT16) RW( m_sh2_state->r[m] ); + if (n != m) + m_sh2_state->r[m] += 2; +} + +/* MOV.L @Rm+,Rn */ +void sh2_device::MOVLP(UINT32 m, UINT32 n) +{ + m_sh2_state->r[n] = RL( m_sh2_state->r[m] ); + if (n != m) + m_sh2_state->r[m] += 4; +} + +/* MOV.B Rm,@(R0,Rn) */ +void sh2_device::MOVBS0(UINT32 m, UINT32 n) +{ + m_sh2_state->ea = m_sh2_state->r[n] + m_sh2_state->r[0]; + WB( m_sh2_state->ea, m_sh2_state->r[m] & 0x000000ff ); +} + +/* MOV.W Rm,@(R0,Rn) */ +void sh2_device::MOVWS0(UINT32 m, UINT32 n) +{ + m_sh2_state->ea = m_sh2_state->r[n] + m_sh2_state->r[0]; + WW( m_sh2_state->ea, m_sh2_state->r[m] & 0x0000ffff ); +} + +/* MOV.L Rm,@(R0,Rn) */ +void sh2_device::MOVLS0(UINT32 m, UINT32 n) +{ + m_sh2_state->ea = m_sh2_state->r[n] + m_sh2_state->r[0]; + WL( m_sh2_state->ea, m_sh2_state->r[m] ); +} + +/* MOV.B @(R0,Rm),Rn */ +void sh2_device::MOVBL0(UINT32 m, UINT32 n) +{ + m_sh2_state->ea = m_sh2_state->r[m] + m_sh2_state->r[0]; + m_sh2_state->r[n] = (UINT32)(INT32)(INT16)(INT8) RB( m_sh2_state->ea ); +} + +/* MOV.W @(R0,Rm),Rn */ +void sh2_device::MOVWL0(UINT32 m, UINT32 n) +{ + m_sh2_state->ea = m_sh2_state->r[m] + m_sh2_state->r[0]; + m_sh2_state->r[n] = (UINT32)(INT32)(INT16) RW( m_sh2_state->ea ); +} + +/* MOV.L @(R0,Rm),Rn */ +void sh2_device::MOVLL0(UINT32 m, UINT32 n) +{ + m_sh2_state->ea = m_sh2_state->r[m] + m_sh2_state->r[0]; + m_sh2_state->r[n] = RL( m_sh2_state->ea ); +} + +/* MOV #imm,Rn */ +void sh2_device::MOVI(UINT32 i, UINT32 n) +{ + m_sh2_state->r[n] = (UINT32)(INT32)(INT16)(INT8) i; +} + +/* MOV.W @(disp8,PC),Rn */ +void sh2_device::MOVWI(UINT32 d, UINT32 n) +{ + UINT32 disp = d & 0xff; + m_sh2_state->ea = m_sh2_state->pc + disp * 2 + 2; + m_sh2_state->r[n] = (UINT32)(INT32)(INT16) RW( m_sh2_state->ea ); +} + +/* MOV.L @(disp8,PC),Rn */ +void sh2_device::MOVLI(UINT32 d, UINT32 n) +{ + UINT32 disp = d & 0xff; + m_sh2_state->ea = ((m_sh2_state->pc + 2) & ~3) + disp * 4; + m_sh2_state->r[n] = RL( m_sh2_state->ea ); +} + +/* MOV.B @(disp8,GBR),R0 */ +void sh2_device::MOVBLG(UINT32 d) +{ + UINT32 disp = d & 0xff; + m_sh2_state->ea = m_sh2_state->gbr + disp; + m_sh2_state->r[0] = (UINT32)(INT32)(INT16)(INT8) RB( m_sh2_state->ea ); +} + +/* MOV.W @(disp8,GBR),R0 */ +void sh2_device::MOVWLG(UINT32 d) +{ + UINT32 disp = d & 0xff; + m_sh2_state->ea = m_sh2_state->gbr + disp * 2; + m_sh2_state->r[0] = (INT32)(INT16) RW( m_sh2_state->ea ); +} + +/* MOV.L @(disp8,GBR),R0 */ +void sh2_device::MOVLLG(UINT32 d) +{ + UINT32 disp = d & 0xff; + m_sh2_state->ea = m_sh2_state->gbr + disp * 4; + m_sh2_state->r[0] = RL( m_sh2_state->ea ); +} + +/* MOV.B R0,@(disp8,GBR) */ +void sh2_device::MOVBSG(UINT32 d) +{ + UINT32 disp = d & 0xff; + m_sh2_state->ea = m_sh2_state->gbr + disp; + WB( m_sh2_state->ea, m_sh2_state->r[0] & 0x000000ff ); +} + +/* MOV.W R0,@(disp8,GBR) */ +void sh2_device::MOVWSG(UINT32 d) +{ + UINT32 disp = d & 0xff; + m_sh2_state->ea = m_sh2_state->gbr + disp * 2; + WW( m_sh2_state->ea, m_sh2_state->r[0] & 0x0000ffff ); +} + +/* MOV.L R0,@(disp8,GBR) */ +void sh2_device::MOVLSG(UINT32 d) +{ + UINT32 disp = d & 0xff; + m_sh2_state->ea = m_sh2_state->gbr + disp * 4; + WL( m_sh2_state->ea, m_sh2_state->r[0] ); +} + +/* MOV.B R0,@(disp4,Rn) */ +void sh2_device::MOVBS4(UINT32 d, UINT32 n) +{ + UINT32 disp = d & 0x0f; + m_sh2_state->ea = m_sh2_state->r[n] + disp; + WB( m_sh2_state->ea, m_sh2_state->r[0] & 0x000000ff ); +} + +/* MOV.W R0,@(disp4,Rn) */ +void sh2_device::MOVWS4(UINT32 d, UINT32 n) +{ + UINT32 disp = d & 0x0f; + m_sh2_state->ea = m_sh2_state->r[n] + disp * 2; + WW( m_sh2_state->ea, m_sh2_state->r[0] & 0x0000ffff ); +} + +/* MOV.L Rm,@(disp4,Rn) */ +void sh2_device::MOVLS4(UINT32 m, UINT32 d, UINT32 n) +{ + UINT32 disp = d & 0x0f; + m_sh2_state->ea = m_sh2_state->r[n] + disp * 4; + WL( m_sh2_state->ea, m_sh2_state->r[m] ); +} + +/* MOV.B @(disp4,Rm),R0 */ +void sh2_device::MOVBL4(UINT32 m, UINT32 d) +{ + UINT32 disp = d & 0x0f; + m_sh2_state->ea = m_sh2_state->r[m] + disp; + m_sh2_state->r[0] = (UINT32)(INT32)(INT16)(INT8) RB( m_sh2_state->ea ); +} + +/* MOV.W @(disp4,Rm),R0 */ +void sh2_device::MOVWL4(UINT32 m, UINT32 d) +{ + UINT32 disp = d & 0x0f; + m_sh2_state->ea = m_sh2_state->r[m] + disp * 2; + m_sh2_state->r[0] = (UINT32)(INT32)(INT16) RW( m_sh2_state->ea ); +} + +/* MOV.L @(disp4,Rm),Rn */ +void sh2_device::MOVLL4(UINT32 m, UINT32 d, UINT32 n) +{ + UINT32 disp = d & 0x0f; + m_sh2_state->ea = m_sh2_state->r[m] + disp * 4; + m_sh2_state->r[n] = RL( m_sh2_state->ea ); +} + +/* MOVA @(disp8,PC),R0 */ +void sh2_device::MOVA(UINT32 d) +{ + UINT32 disp = d & 0xff; + m_sh2_state->ea = ((m_sh2_state->pc + 2) & ~3) + disp * 4; + m_sh2_state->r[0] = m_sh2_state->ea; +} + +/* MOVT Rn */ +void sh2_device::MOVT(UINT32 n) +{ + m_sh2_state->r[n] = m_sh2_state->sr & T; +} + +/* MUL.L Rm,Rn */ +void sh2_device::MULL(UINT32 m, UINT32 n) +{ + m_sh2_state->macl = m_sh2_state->r[n] * m_sh2_state->r[m]; + m_sh2_state->icount--; +} + +/* MULS Rm,Rn */ +void sh2_device::MULS(UINT32 m, UINT32 n) +{ + m_sh2_state->macl = (INT16) m_sh2_state->r[n] * (INT16) m_sh2_state->r[m]; +} + +/* MULU Rm,Rn */ +void sh2_device::MULU(UINT32 m, UINT32 n) +{ + m_sh2_state->macl = (UINT16) m_sh2_state->r[n] * (UINT16) m_sh2_state->r[m]; +} + +/* NEG Rm,Rn */ +void sh2_device::NEG(UINT32 m, UINT32 n) +{ + m_sh2_state->r[n] = 0 - m_sh2_state->r[m]; +} + +/* NEGC Rm,Rn */ +void sh2_device::NEGC(UINT32 m, UINT32 n) +{ + UINT32 temp; + + temp = m_sh2_state->r[m]; + m_sh2_state->r[n] = -temp - (m_sh2_state->sr & T); + if (temp || (m_sh2_state->sr & T)) + m_sh2_state->sr |= T; + else + m_sh2_state->sr &= ~T; +} + +/* NOP */ +void sh2_device::NOP(void) +{ +} + +/* NOT Rm,Rn */ +void sh2_device::NOT(UINT32 m, UINT32 n) +{ + m_sh2_state->r[n] = ~m_sh2_state->r[m]; +} + +/* OR Rm,Rn */ +void sh2_device::OR(UINT32 m, UINT32 n) +{ + m_sh2_state->r[n] |= m_sh2_state->r[m]; +} + +/* OR #imm,R0 */ +void sh2_device::ORI(UINT32 i) +{ + m_sh2_state->r[0] |= i; +} + +/* OR.B #imm,@(R0,GBR) */ +void sh2_device::ORM(UINT32 i) +{ + UINT32 temp; + + m_sh2_state->ea = m_sh2_state->gbr + m_sh2_state->r[0]; + temp = RB( m_sh2_state->ea ); + temp |= i; + WB( m_sh2_state->ea, temp ); + m_sh2_state->icount -= 2; +} + +/* ROTCL Rn */ +void sh2_device::ROTCL(UINT32 n) +{ + UINT32 temp; + + temp = (m_sh2_state->r[n] >> 31) & T; + m_sh2_state->r[n] = (m_sh2_state->r[n] << 1) | (m_sh2_state->sr & T); + m_sh2_state->sr = (m_sh2_state->sr & ~T) | temp; +} + +/* ROTCR Rn */ +void sh2_device::ROTCR(UINT32 n) +{ + UINT32 temp; + temp = (m_sh2_state->sr & T) << 31; + if (m_sh2_state->r[n] & T) + m_sh2_state->sr |= T; + else + m_sh2_state->sr &= ~T; + m_sh2_state->r[n] = (m_sh2_state->r[n] >> 1) | temp; +} + +/* ROTL Rn */ +void sh2_device::ROTL(UINT32 n) +{ + m_sh2_state->sr = (m_sh2_state->sr & ~T) | ((m_sh2_state->r[n] >> 31) & T); + m_sh2_state->r[n] = (m_sh2_state->r[n] << 1) | (m_sh2_state->r[n] >> 31); +} + +/* ROTR Rn */ +void sh2_device::ROTR(UINT32 n) +{ + m_sh2_state->sr = (m_sh2_state->sr & ~T) | (m_sh2_state->r[n] & T); + m_sh2_state->r[n] = (m_sh2_state->r[n] >> 1) | (m_sh2_state->r[n] << 31); +} + +/* RTE */ +void sh2_device::RTE() +{ + m_sh2_state->ea = m_sh2_state->r[15]; + m_delay = m_sh2_state->pc; + m_sh2_state->pc = RL( m_sh2_state->ea ); + m_sh2_state->r[15] += 4; + m_sh2_state->ea = m_sh2_state->r[15]; + m_sh2_state->sr = RL( m_sh2_state->ea ) & FLAGS; + m_sh2_state->r[15] += 4; + m_sh2_state->icount -= 3; + m_test_irq = 1; +} + +/* RTS */ +void sh2_device::RTS() +{ + m_delay = m_sh2_state->pc; + m_sh2_state->pc = m_sh2_state->ea = m_sh2_state->pr; + m_sh2_state->icount--; +} + +/* SETT */ +void sh2_device::SETT() +{ + m_sh2_state->sr |= T; +} + +/* SHAL Rn (same as SHLL) */ +void sh2_device::SHAL(UINT32 n) +{ + m_sh2_state->sr = (m_sh2_state->sr & ~T) | ((m_sh2_state->r[n] >> 31) & T); + m_sh2_state->r[n] <<= 1; +} + +/* SHAR Rn */ +void sh2_device::SHAR(UINT32 n) +{ + m_sh2_state->sr = (m_sh2_state->sr & ~T) | (m_sh2_state->r[n] & T); + m_sh2_state->r[n] = (UINT32)((INT32)m_sh2_state->r[n] >> 1); +} + +/* SHLL Rn (same as SHAL) */ +void sh2_device::SHLL(UINT32 n) +{ + m_sh2_state->sr = (m_sh2_state->sr & ~T) | ((m_sh2_state->r[n] >> 31) & T); + m_sh2_state->r[n] <<= 1; +} + +/* SHLL2 Rn */ +void sh2_device::SHLL2(UINT32 n) +{ + m_sh2_state->r[n] <<= 2; +} + +/* SHLL8 Rn */ +void sh2_device::SHLL8(UINT32 n) +{ + m_sh2_state->r[n] <<= 8; +} + +/* SHLL16 Rn */ +void sh2_device::SHLL16(UINT32 n) +{ + m_sh2_state->r[n] <<= 16; +} + +/* SHLR Rn */ +void sh2_device::SHLR(UINT32 n) +{ + m_sh2_state->sr = (m_sh2_state->sr & ~T) | (m_sh2_state->r[n] & T); + m_sh2_state->r[n] >>= 1; +} + +/* SHLR2 Rn */ +void sh2_device::SHLR2(UINT32 n) +{ + m_sh2_state->r[n] >>= 2; +} + +/* SHLR8 Rn */ +void sh2_device::SHLR8(UINT32 n) +{ + m_sh2_state->r[n] >>= 8; +} + +/* SHLR16 Rn */ +void sh2_device::SHLR16(UINT32 n) +{ + m_sh2_state->r[n] >>= 16; +} + +/* SLEEP */ +void sh2_device::SLEEP() +{ + if(m_sh2_state->sleep_mode != 2) + m_sh2_state->pc -= 2; + m_sh2_state->icount -= 2; + /* Wait_for_exception; */ + if(m_sh2_state->sleep_mode == 0) + m_sh2_state->sleep_mode = 1; + else if(m_sh2_state->sleep_mode == 2) + m_sh2_state->sleep_mode = 0; +} + +/* STC SR,Rn */ +void sh2_device::STCSR(UINT32 n) +{ + m_sh2_state->r[n] = m_sh2_state->sr; +} + +/* STC GBR,Rn */ +void sh2_device::STCGBR(UINT32 n) +{ + m_sh2_state->r[n] = m_sh2_state->gbr; +} + +/* STC VBR,Rn */ +void sh2_device::STCVBR(UINT32 n) +{ + m_sh2_state->r[n] = m_sh2_state->vbr; +} + +/* STC.L SR,@-Rn */ +void sh2_device::STCMSR(UINT32 n) +{ + m_sh2_state->r[n] -= 4; + m_sh2_state->ea = m_sh2_state->r[n]; + WL( m_sh2_state->ea, m_sh2_state->sr ); + m_sh2_state->icount--; +} + +/* STC.L GBR,@-Rn */ +void sh2_device::STCMGBR(UINT32 n) +{ + m_sh2_state->r[n] -= 4; + m_sh2_state->ea = m_sh2_state->r[n]; + WL( m_sh2_state->ea, m_sh2_state->gbr ); + m_sh2_state->icount--; +} + +/* STC.L VBR,@-Rn */ +void sh2_device::STCMVBR(UINT32 n) +{ + m_sh2_state->r[n] -= 4; + m_sh2_state->ea = m_sh2_state->r[n]; + WL( m_sh2_state->ea, m_sh2_state->vbr ); + m_sh2_state->icount--; +} + +/* STS MACH,Rn */ +void sh2_device::STSMACH(UINT32 n) +{ + m_sh2_state->r[n] = m_sh2_state->mach; +} + +/* STS MACL,Rn */ +void sh2_device::STSMACL(UINT32 n) +{ + m_sh2_state->r[n] = m_sh2_state->macl; +} + +/* STS PR,Rn */ +void sh2_device::STSPR(UINT32 n) +{ + m_sh2_state->r[n] = m_sh2_state->pr; +} + +/* STS.L MACH,@-Rn */ +void sh2_device::STSMMACH(UINT32 n) +{ + m_sh2_state->r[n] -= 4; + m_sh2_state->ea = m_sh2_state->r[n]; + WL( m_sh2_state->ea, m_sh2_state->mach ); +} + +/* STS.L MACL,@-Rn */ +void sh2_device::STSMMACL(UINT32 n) +{ + m_sh2_state->r[n] -= 4; + m_sh2_state->ea = m_sh2_state->r[n]; + WL( m_sh2_state->ea, m_sh2_state->macl ); +} + +/* STS.L PR,@-Rn */ +void sh2_device::STSMPR(UINT32 n) +{ + m_sh2_state->r[n] -= 4; + m_sh2_state->ea = m_sh2_state->r[n]; + WL( m_sh2_state->ea, m_sh2_state->pr ); +} + +/* SUB Rm,Rn */ +void sh2_device::SUB(UINT32 m, UINT32 n) +{ + m_sh2_state->r[n] -= m_sh2_state->r[m]; +} + +/* SUBC Rm,Rn */ +void sh2_device::SUBC(UINT32 m, UINT32 n) +{ + UINT32 tmp0, tmp1; + + tmp1 = m_sh2_state->r[n] - m_sh2_state->r[m]; + tmp0 = m_sh2_state->r[n]; + m_sh2_state->r[n] = tmp1 - (m_sh2_state->sr & T); + if (tmp0 < tmp1) + m_sh2_state->sr |= T; + else + m_sh2_state->sr &= ~T; + if (tmp1 < m_sh2_state->r[n]) + m_sh2_state->sr |= T; +} + +/* SUBV Rm,Rn */ +void sh2_device::SUBV(UINT32 m, UINT32 n) +{ + INT32 dest, src, ans; + + if ((INT32) m_sh2_state->r[n] >= 0) + dest = 0; + else + dest = 1; + if ((INT32) m_sh2_state->r[m] >= 0) + src = 0; + else + src = 1; + src += dest; + m_sh2_state->r[n] -= m_sh2_state->r[m]; + if ((INT32) m_sh2_state->r[n] >= 0) + ans = 0; + else + ans = 1; + ans += dest; + if (src == 1) + { + if (ans == 1) + m_sh2_state->sr |= T; + else + m_sh2_state->sr &= ~T; + } + else + m_sh2_state->sr &= ~T; +} + +/* SWAP.B Rm,Rn */ +void sh2_device::SWAPB(UINT32 m, UINT32 n) +{ + UINT32 temp0, temp1; + + temp0 = m_sh2_state->r[m] & 0xffff0000; + temp1 = (m_sh2_state->r[m] & 0x000000ff) << 8; + m_sh2_state->r[n] = (m_sh2_state->r[m] >> 8) & 0x000000ff; + m_sh2_state->r[n] = m_sh2_state->r[n] | temp1 | temp0; +} + +/* SWAP.W Rm,Rn */ +void sh2_device::SWAPW(UINT32 m, UINT32 n) +{ + UINT32 temp; + + temp = (m_sh2_state->r[m] >> 16) & 0x0000ffff; + m_sh2_state->r[n] = (m_sh2_state->r[m] << 16) | temp; +} + +/* TAS.B @Rn */ +void sh2_device::TAS(UINT32 n) +{ + UINT32 temp; + m_sh2_state->ea = m_sh2_state->r[n]; + /* Bus Lock enable */ + temp = RB( m_sh2_state->ea ); + if (temp == 0) + m_sh2_state->sr |= T; + else + m_sh2_state->sr &= ~T; + temp |= 0x80; + /* Bus Lock disable */ + WB( m_sh2_state->ea, temp ); + m_sh2_state->icount -= 3; +} + +/* TRAPA #imm */ +void sh2_device::TRAPA(UINT32 i) +{ + UINT32 imm = i & 0xff; + + m_sh2_state->ea = m_sh2_state->vbr + imm * 4; + + m_sh2_state->r[15] -= 4; + WL( m_sh2_state->r[15], m_sh2_state->sr ); + m_sh2_state->r[15] -= 4; + WL( m_sh2_state->r[15], m_sh2_state->pc ); + + m_sh2_state->pc = RL( m_sh2_state->ea ); + + m_sh2_state->icount -= 7; +} + +/* TST Rm,Rn */ +void sh2_device::TST(UINT32 m, UINT32 n) +{ + if ((m_sh2_state->r[n] & m_sh2_state->r[m]) == 0) + m_sh2_state->sr |= T; + else + m_sh2_state->sr &= ~T; +} + +/* TST #imm,R0 */ +void sh2_device::TSTI(UINT32 i) +{ + UINT32 imm = i & 0xff; + + if ((imm & m_sh2_state->r[0]) == 0) + m_sh2_state->sr |= T; + else + m_sh2_state->sr &= ~T; +} + +/* TST.B #imm,@(R0,GBR) */ +void sh2_device::TSTM(UINT32 i) +{ + UINT32 imm = i & 0xff; + + m_sh2_state->ea = m_sh2_state->gbr + m_sh2_state->r[0]; + if ((imm & RB( m_sh2_state->ea )) == 0) + m_sh2_state->sr |= T; + else + m_sh2_state->sr &= ~T; + m_sh2_state->icount -= 2; +} + +/* XOR Rm,Rn */ +void sh2_device::XOR(UINT32 m, UINT32 n) +{ + m_sh2_state->r[n] ^= m_sh2_state->r[m]; +} + +/* XOR #imm,R0 */ +void sh2_device::XORI(UINT32 i) +{ + UINT32 imm = i & 0xff; + m_sh2_state->r[0] ^= imm; +} + +/* XOR.B #imm,@(R0,GBR) */ +void sh2_device::XORM(UINT32 i) +{ + UINT32 imm = i & 0xff; + UINT32 temp; + + m_sh2_state->ea = m_sh2_state->gbr + m_sh2_state->r[0]; + temp = RB( m_sh2_state->ea ); + temp ^= imm; + WB( m_sh2_state->ea, temp ); + m_sh2_state->icount -= 2; +} + +/* XTRCT Rm,Rn */ +void sh2_device::XTRCT(UINT32 m, UINT32 n) +{ + UINT32 temp; + + temp = (m_sh2_state->r[m] << 16) & 0xffff0000; + m_sh2_state->r[n] = (m_sh2_state->r[n] >> 16) & 0x0000ffff; + m_sh2_state->r[n] |= temp; +} + +/***************************************************************************** + * OPCODE DISPATCHERS + *****************************************************************************/ + +void sh2_device::op0000(UINT16 opcode) +{ + switch (opcode & 0x3F) + { + case 0x00: ILLEGAL(); break; + case 0x01: ILLEGAL(); break; + case 0x02: STCSR(Rn); break; + case 0x03: BSRF(Rn); break; + case 0x04: MOVBS0(Rm, Rn); break; + case 0x05: MOVWS0(Rm, Rn); break; + case 0x06: MOVLS0(Rm, Rn); break; + case 0x07: MULL(Rm, Rn); break; + case 0x08: CLRT(); break; + case 0x09: NOP(); break; + case 0x0a: STSMACH(Rn); break; + case 0x0b: RTS(); break; + case 0x0c: MOVBL0(Rm, Rn); break; + case 0x0d: MOVWL0(Rm, Rn); break; + case 0x0e: MOVLL0(Rm, Rn); break; + case 0x0f: MAC_L(Rm, Rn); break; + + case 0x10: ILLEGAL(); break; + case 0x11: ILLEGAL(); break; + case 0x12: STCGBR(Rn); break; + case 0x13: ILLEGAL(); break; + case 0x14: MOVBS0(Rm, Rn); break; + case 0x15: MOVWS0(Rm, Rn); break; + case 0x16: MOVLS0(Rm, Rn); break; + case 0x17: MULL(Rm, Rn); break; + case 0x18: SETT(); break; + case 0x19: DIV0U(); break; + case 0x1a: STSMACL(Rn); break; + case 0x1b: SLEEP(); break; + case 0x1c: MOVBL0(Rm, Rn); break; + case 0x1d: MOVWL0(Rm, Rn); break; + case 0x1e: MOVLL0(Rm, Rn); break; + case 0x1f: MAC_L(Rm, Rn); break; + + case 0x20: ILLEGAL(); break; + case 0x21: ILLEGAL(); break; + case 0x22: STCVBR(Rn); break; + case 0x23: BRAF(Rn); break; + case 0x24: MOVBS0(Rm, Rn); break; + case 0x25: MOVWS0(Rm, Rn); break; + case 0x26: MOVLS0(Rm, Rn); break; + case 0x27: MULL(Rm, Rn); break; + case 0x28: CLRMAC(); break; + case 0x29: MOVT(Rn); break; + case 0x2a: STSPR(Rn); break; + case 0x2b: RTE(); break; + case 0x2c: MOVBL0(Rm, Rn); break; + case 0x2d: MOVWL0(Rm, Rn); break; + case 0x2e: MOVLL0(Rm, Rn); break; + case 0x2f: MAC_L(Rm, Rn); break; + + case 0x30: ILLEGAL(); break; + case 0x31: ILLEGAL(); break; + case 0x32: ILLEGAL(); break; + case 0x33: ILLEGAL(); break; + case 0x34: MOVBS0(Rm, Rn); break; + case 0x35: MOVWS0(Rm, Rn); break; + case 0x36: MOVLS0(Rm, Rn); break; + case 0x37: MULL(Rm, Rn); break; + case 0x38: ILLEGAL(); break; + case 0x39: ILLEGAL(); break; + case 0x3c: MOVBL0(Rm, Rn); break; + case 0x3d: MOVWL0(Rm, Rn); break; + case 0x3e: MOVLL0(Rm, Rn); break; + case 0x3f: MAC_L(Rm, Rn); break; + case 0x3a: ILLEGAL(); break; + case 0x3b: ILLEGAL(); break; + + + + } +} + +void sh2_device::op0001(UINT16 opcode) +{ + MOVLS4(Rm, opcode & 0x0f, Rn); +} + +void sh2_device::op0010(UINT16 opcode) +{ + switch (opcode & 15) + { + case 0: MOVBS(Rm, Rn); break; + case 1: MOVWS(Rm, Rn); break; + case 2: MOVLS(Rm, Rn); break; + case 3: ILLEGAL(); break; + case 4: MOVBM(Rm, Rn); break; + case 5: MOVWM(Rm, Rn); break; + case 6: MOVLM(Rm, Rn); break; + case 7: DIV0S(Rm, Rn); break; + case 8: TST(Rm, Rn); break; + case 9: AND(Rm, Rn); break; + case 10: XOR(Rm, Rn); break; + case 11: OR(Rm, Rn); break; + case 12: CMPSTR(Rm, Rn); break; + case 13: XTRCT(Rm, Rn); break; + case 14: MULU(Rm, Rn); break; + case 15: MULS(Rm, Rn); break; + } +} + +void sh2_device::op0011(UINT16 opcode) +{ + switch (opcode & 15) + { + case 0: CMPEQ(Rm, Rn); break; + case 1: ILLEGAL(); break; + case 2: CMPHS(Rm, Rn); break; + case 3: CMPGE(Rm, Rn); break; + case 4: DIV1(Rm, Rn); break; + case 5: DMULU(Rm, Rn); break; + case 6: CMPHI(Rm, Rn); break; + case 7: CMPGT(Rm, Rn); break; + case 8: SUB(Rm, Rn); break; + case 9: ILLEGAL(); break; + case 10: SUBC(Rm, Rn); break; + case 11: SUBV(Rm, Rn); break; + case 12: ADD(Rm, Rn); break; + case 13: DMULS(Rm, Rn); break; + case 14: ADDC(Rm, Rn); break; + case 15: ADDV(Rm, Rn); break; + } +} + +void sh2_device::op0100(UINT16 opcode) +{ + switch (opcode & 0x3F) + { + case 0x00: SHLL(Rn); break; + case 0x01: SHLR(Rn); break; + case 0x02: STSMMACH(Rn); break; + case 0x03: STCMSR(Rn); break; + case 0x04: ROTL(Rn); break; + case 0x05: ROTR(Rn); break; + case 0x06: LDSMMACH(Rn); break; + case 0x07: LDCMSR(Rn); break; + case 0x08: SHLL2(Rn); break; + case 0x09: SHLR2(Rn); break; + case 0x0a: LDSMACH(Rn); break; + case 0x0b: JSR(Rn); break; + case 0x0c: ILLEGAL(); break; + case 0x0d: ILLEGAL(); break; + case 0x0e: LDCSR(Rn); break; + case 0x0f: MAC_W(Rm, Rn); break; + + case 0x10: DT(Rn); break; + case 0x11: CMPPZ(Rn); break; + case 0x12: STSMMACL(Rn); break; + case 0x13: STCMGBR(Rn); break; + case 0x14: ILLEGAL(); break; + case 0x15: CMPPL(Rn); break; + case 0x16: LDSMMACL(Rn); break; + case 0x17: LDCMGBR(Rn); break; + case 0x18: SHLL8(Rn); break; + case 0x19: SHLR8(Rn); break; + case 0x1a: LDSMACL(Rn); break; + case 0x1b: TAS(Rn); break; + case 0x1c: ILLEGAL(); break; + case 0x1d: ILLEGAL(); break; + case 0x1e: LDCGBR(Rn); break; + case 0x1f: MAC_W(Rm, Rn); break; + + case 0x20: SHAL(Rn); break; + case 0x21: SHAR(Rn); break; + case 0x22: STSMPR(Rn); break; + case 0x23: STCMVBR(Rn); break; + case 0x24: ROTCL(Rn); break; + case 0x25: ROTCR(Rn); break; + case 0x26: LDSMPR(Rn); break; + case 0x27: LDCMVBR(Rn); break; + case 0x28: SHLL16(Rn); break; + case 0x29: SHLR16(Rn); break; + case 0x2a: LDSPR(Rn); break; + case 0x2b: JMP(Rn); break; + case 0x2c: ILLEGAL(); break; + case 0x2d: ILLEGAL(); break; + case 0x2e: LDCVBR(Rn); break; + case 0x2f: MAC_W(Rm, Rn); break; + + case 0x30: ILLEGAL(); break; + case 0x31: ILLEGAL(); break; + case 0x32: ILLEGAL(); break; + case 0x33: ILLEGAL(); break; + case 0x34: ILLEGAL(); break; + case 0x35: ILLEGAL(); break; + case 0x36: ILLEGAL(); break; + case 0x37: ILLEGAL(); break; + case 0x38: ILLEGAL(); break; + case 0x39: ILLEGAL(); break; + case 0x3a: ILLEGAL(); break; + case 0x3b: ILLEGAL(); break; + case 0x3c: ILLEGAL(); break; + case 0x3d: ILLEGAL(); break; + case 0x3e: ILLEGAL(); break; + case 0x3f: MAC_W(Rm, Rn); break; + + } +} + +void sh2_device::op0101(UINT16 opcode) +{ + MOVLL4(Rm, opcode & 0x0f, Rn); +} + +void sh2_device::op0110(UINT16 opcode) +{ + switch (opcode & 15) + { + case 0: MOVBL(Rm, Rn); break; + case 1: MOVWL(Rm, Rn); break; + case 2: MOVLL(Rm, Rn); break; + case 3: MOV(Rm, Rn); break; + case 4: MOVBP(Rm, Rn); break; + case 5: MOVWP(Rm, Rn); break; + case 6: MOVLP(Rm, Rn); break; + case 7: NOT(Rm, Rn); break; + case 8: SWAPB(Rm, Rn); break; + case 9: SWAPW(Rm, Rn); break; + case 10: NEGC(Rm, Rn); break; + case 11: NEG(Rm, Rn); break; + case 12: EXTUB(Rm, Rn); break; + case 13: EXTUW(Rm, Rn); break; + case 14: EXTSB(Rm, Rn); break; + case 15: EXTSW(Rm, Rn); break; + } +} + +void sh2_device::op0111(UINT16 opcode) +{ + ADDI(opcode & 0xff, Rn); +} + +void sh2_device::op1000(UINT16 opcode) +{ + switch ( opcode & (15<<8) ) + { + case 0 << 8: MOVBS4(opcode & 0x0f, Rm); break; + case 1 << 8: MOVWS4(opcode & 0x0f, Rm); break; + case 2<< 8: ILLEGAL(); break; + case 3<< 8: ILLEGAL(); break; + case 4<< 8: MOVBL4(Rm, opcode & 0x0f); break; + case 5<< 8: MOVWL4(Rm, opcode & 0x0f); break; + case 6<< 8: ILLEGAL(); break; + case 7<< 8: ILLEGAL(); break; + case 8<< 8: CMPIM(opcode & 0xff); break; + case 9<< 8: BT(opcode & 0xff); break; + case 10<< 8: ILLEGAL(); break; + case 11<< 8: BF(opcode & 0xff); break; + case 12<< 8: ILLEGAL(); break; + case 13<< 8: BTS(opcode & 0xff); break; + case 14<< 8: ILLEGAL(); break; + case 15<< 8: BFS(opcode & 0xff); break; + } +} + + +void sh2_device::op1001(UINT16 opcode) +{ + MOVWI(opcode & 0xff, Rn); +} + +void sh2_device::op1010(UINT16 opcode) +{ + BRA(opcode & 0xfff); +} + +void sh2_device::op1011(UINT16 opcode) +{ + BSR(opcode & 0xfff); +} + +void sh2_device::op1100(UINT16 opcode) +{ + switch (opcode & (15<<8)) + { + case 0<<8: MOVBSG(opcode & 0xff); break; + case 1<<8: MOVWSG(opcode & 0xff); break; + case 2<<8: MOVLSG(opcode & 0xff); break; + case 3<<8: TRAPA(opcode & 0xff); break; + case 4<<8: MOVBLG(opcode & 0xff); break; + case 5<<8: MOVWLG(opcode & 0xff); break; + case 6<<8: MOVLLG(opcode & 0xff); break; + case 7<<8: MOVA(opcode & 0xff); break; + case 8<<8: TSTI(opcode & 0xff); break; + case 9<<8: ANDI(opcode & 0xff); break; + case 10<<8: XORI(opcode & 0xff); break; + case 11<<8: ORI(opcode & 0xff); break; + case 12<<8: TSTM(opcode & 0xff); break; + case 13<<8: ANDM(opcode & 0xff); break; + case 14<<8: XORM(opcode & 0xff); break; + case 15<<8: ORM(opcode & 0xff); break; + } +} + +void sh2_device::op1101(UINT16 opcode) +{ + MOVLI(opcode & 0xff, Rn); +} + +void sh2_device::op1110(UINT16 opcode) +{ + MOVI(opcode & 0xff, Rn); +} + +void sh2_device::op1111(UINT16 opcode) +{ + ILLEGAL(); +} + +/***************************************************************************** + * MAME CPU INTERFACE + *****************************************************************************/ + +void sh2_device::device_reset() +{ + m_sh2_state->ppc = m_sh2_state->pc = m_sh2_state->pr = m_sh2_state->sr = m_sh2_state->gbr = m_sh2_state->vbr = m_sh2_state->mach = m_sh2_state->macl = 0; + m_sh2_state->evec = m_sh2_state->irqsr = 0; + memset(&m_sh2_state->r[0], 0, sizeof(m_sh2_state->r[0])*16); + m_sh2_state->ea = m_delay = m_cpu_off = m_dvsr = m_dvdnth = m_dvdntl = m_dvcr = 0; + m_sh2_state->pending_irq = m_test_irq = 0; + memset(&m_irq_queue[0], 0, sizeof(m_irq_queue[0])*16); + memset(&m_irq_line_state[0], 0, sizeof(m_irq_line_state[0])*17); + m_frc = m_ocra = m_ocrb = m_icr = 0; + m_frc_base = 0; + m_frt_input = m_sh2_state->internal_irq_level = m_internal_irq_vector = 0; + m_dma_timer_active[0] = m_dma_timer_active[1] = 0; + m_dma_irq[0] = m_dma_irq[1] = 0; + + memset(m_m, 0, 0x200); + + m_sh2_state->pc = RL(0); + m_sh2_state->r[15] = RL(4); + m_sh2_state->sr = I; + m_sh2_state->sleep_mode = 0; + + m_sh2_state->internal_irq_level = -1; + + m_cache_dirty = TRUE; +} + + +/* Execute cycles - returns number of cycles actually run */ +void sh2_device::execute_run() +{ + if ( m_isdrc ) + { + execute_run_drc(); + return; + } + + if (m_cpu_off) + { + m_sh2_state->icount = 0; + return; + } + + // run any active DMAs now +#ifndef USE_TIMER_FOR_DMA + for ( int i = 0; i < m_sh2_state->icount ; i++) + { + for( int dma=0;dma<1;dma++) + { + if (m_dma_timer_active[dma]) + sh2_do_dma(dma); + } + } +#endif + + do + { + UINT32 opcode; + + if (m_delay) + { + opcode = m_program->read_word(((UINT32)(m_delay & AM))); + m_sh2_state->pc -= 2; + } + else + opcode = m_program->read_word(((UINT32)(m_sh2_state->pc & AM))); + + debugger_instruction_hook(this, m_sh2_state->pc); + + m_delay = 0; + m_sh2_state->pc += 2; + m_sh2_state->ppc = m_sh2_state->pc; + + switch (opcode & ( 15 << 12)) + { + case 0<<12: op0000(opcode); break; + case 1<<12: op0001(opcode); break; + case 2<<12: op0010(opcode); break; + case 3<<12: op0011(opcode); break; + case 4<<12: op0100(opcode); break; + case 5<<12: op0101(opcode); break; + case 6<<12: op0110(opcode); break; + case 7<<12: op0111(opcode); break; + case 8<<12: op1000(opcode); break; + case 9<<12: op1001(opcode); break; + case 10<<12: op1010(opcode); break; + case 11<<12: op1011(opcode); break; + case 12<<12: op1100(opcode); break; + case 13<<12: op1101(opcode); break; + case 14<<12: op1110(opcode); break; + default: op1111(opcode); break; + } + + if(m_test_irq && !m_delay) + { + CHECK_PENDING_IRQ("mame_sh2_execute"); + m_test_irq = 0; + } + m_sh2_state->icount--; + } while( m_sh2_state->icount > 0 ); +} + +void sh2_device::device_start() +{ + /* allocate the implementation-specific state from the full cache */ + m_sh2_state = (internal_sh2_state *)m_cache.alloc_near(sizeof(internal_sh2_state)); + + m_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(sh2_device::sh2_timer_callback), this)); + m_timer->adjust(attotime::never); + + m_dma_current_active_timer[0] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(sh2_device::sh2_dma_current_active_callback), this)); + m_dma_current_active_timer[0]->adjust(attotime::never); + + m_dma_current_active_timer[1] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(sh2_device::sh2_dma_current_active_callback), this)); + m_dma_current_active_timer[1]->adjust(attotime::never); + + /* resolve callbacks */ + m_dma_kludge_cb.bind_relative_to(*owner()); + m_dma_fifo_data_available_cb.bind_relative_to(*owner()); + m_ftcsr_read_cb.bind_relative_to(*owner()); + + m_program = &space(AS_PROGRAM); + m_decrypted_program = has_space(AS_DECRYPTED_OPCODES) ? &space(AS_DECRYPTED_OPCODES) : &space(AS_PROGRAM); + m_direct = &m_decrypted_program->direct(); + m_internal = &space(AS_PROGRAM); + + save_item(NAME(m_sh2_state->pc)); + save_item(NAME(m_sh2_state->sr)); + save_item(NAME(m_sh2_state->pr)); + save_item(NAME(m_sh2_state->gbr)); + save_item(NAME(m_sh2_state->vbr)); + save_item(NAME(m_sh2_state->mach)); + save_item(NAME(m_sh2_state->macl)); + save_item(NAME(m_sh2_state->r)); + save_item(NAME(m_sh2_state->ea)); + save_item(NAME(m_delay)); + save_item(NAME(m_cpu_off)); + save_item(NAME(m_dvsr)); + save_item(NAME(m_dvdnth)); + save_item(NAME(m_dvdntl)); + save_item(NAME(m_dvcr)); + save_item(NAME(m_sh2_state->pending_irq)); + save_item(NAME(m_test_irq)); + save_item(NAME(m_sh2_state->pending_nmi)); + save_item(NAME(m_sh2_state->irqline)); + save_item(NAME(m_sh2_state->evec)); + save_item(NAME(m_sh2_state->irqsr)); + save_item(NAME(m_sh2_state->target)); + for (int i = 0; i < 16; ++i) + { + save_item(NAME(m_irq_queue[i].irq_vector), i); + save_item(NAME(m_irq_queue[i].irq_priority), i); + } + save_item(NAME(m_pcfsel)); + save_item(NAME(m_maxpcfsel)); + save_item(NAME(m_pcflushes)); + save_item(NAME(m_irq_line_state)); + save_item(NAME(m_m)); + save_item(NAME(m_nmi_line_state)); + save_item(NAME(m_frc)); + save_item(NAME(m_ocra)); + save_item(NAME(m_ocrb)); + save_item(NAME(m_icr)); + save_item(NAME(m_frc_base)); + save_item(NAME(m_frt_input)); + save_item(NAME(m_sh2_state->internal_irq_level)); + save_item(NAME(m_internal_irq_vector)); + save_item(NAME(m_dma_timer_active)); + save_item(NAME(m_dma_irq)); + save_item(NAME(m_wtcnt)); + save_item(NAME(m_wtcsr)); + save_item(NAME(m_sh2_state->sleep_mode)); + + state_add( SH2_PC, "PC", m_debugger_temp).callimport().callexport().formatstr("%08X"); + state_add( SH2_SR, "SR", m_sh2_state->sr).callimport().formatstr("%08X"); + state_add( SH2_PR, "PR", m_sh2_state->pr).formatstr("%08X"); + state_add( SH2_GBR, "GBR", m_sh2_state->gbr).formatstr("%08X"); + state_add( SH2_VBR, "VBR", m_sh2_state->vbr).formatstr("%08X"); + state_add( SH2_MACH, "MACH", m_sh2_state->mach).formatstr("%08X"); + state_add( SH2_MACL, "MACL", m_sh2_state->macl).formatstr("%08X"); + state_add( SH2_R0, "R0", m_sh2_state->r[ 0]).formatstr("%08X"); + state_add( SH2_R1, "R1", m_sh2_state->r[ 1]).formatstr("%08X"); + state_add( SH2_R2, "R2", m_sh2_state->r[ 2]).formatstr("%08X"); + state_add( SH2_R3, "R3", m_sh2_state->r[ 3]).formatstr("%08X"); + state_add( SH2_R4, "R4", m_sh2_state->r[ 4]).formatstr("%08X"); + state_add( SH2_R5, "R5", m_sh2_state->r[ 5]).formatstr("%08X"); + state_add( SH2_R6, "R6", m_sh2_state->r[ 6]).formatstr("%08X"); + state_add( SH2_R7, "R7", m_sh2_state->r[ 7]).formatstr("%08X"); + state_add( SH2_R8, "R8", m_sh2_state->r[ 8]).formatstr("%08X"); + state_add( SH2_R9, "R9", m_sh2_state->r[ 9]).formatstr("%08X"); + state_add( SH2_R10, "R10", m_sh2_state->r[10]).formatstr("%08X"); + state_add( SH2_R11, "R11", m_sh2_state->r[11]).formatstr("%08X"); + state_add( SH2_R12, "R12", m_sh2_state->r[12]).formatstr("%08X"); + state_add( SH2_R13, "R13", m_sh2_state->r[13]).formatstr("%08X"); + state_add( SH2_R14, "R14", m_sh2_state->r[14]).formatstr("%08X"); + state_add( SH2_R15, "R15", m_sh2_state->r[15]).formatstr("%08X"); + state_add( SH2_EA, "EA", m_sh2_state->ea).formatstr("%08X"); + + state_add( STATE_GENPC, "GENPC", m_sh2_state->pc ).noshow(); + state_add( STATE_GENSP, "GENSP", m_sh2_state->r[15] ).noshow(); + state_add( STATE_GENPCBASE, "GENPCBASE", m_sh2_state->ppc ).noshow(); + state_add( STATE_GENFLAGS, "GENFLAGS", m_sh2_state->sr ).formatstr("%6s").noshow(); + + m_icountptr = &m_sh2_state->icount; + + // Clear state + m_sh2_state->ppc = 0; + m_sh2_state->pc = 0; + m_sh2_state->pr = 0; + m_sh2_state->sr = 0; + m_sh2_state->gbr = 0; + m_sh2_state->vbr = 0; + m_sh2_state->mach = 0; + m_sh2_state->macl = 0; + memset(m_sh2_state->r, 0, sizeof(m_sh2_state->r)); + m_sh2_state->ea = 0; + m_delay = 0; + m_cpu_off = 0; + m_dvsr = 0; + m_dvdnth = 0; + m_dvdntl = 0; + m_dvcr = 0; + m_sh2_state->pending_irq = 0; + m_test_irq = 0; + m_sh2_state->pending_nmi = 0; + m_sh2_state->irqline = 0; + m_sh2_state->evec = 0; + m_sh2_state->irqsr = 0; + m_sh2_state->target = 0; + memset(m_irq_queue, 0, sizeof(m_irq_queue)); + m_maxpcfsel = 0; + memset(m_pcflushes, 0, sizeof(m_pcflushes)); + memset(m_irq_line_state, 0, sizeof(m_irq_line_state)); + memset(m_m, 0, sizeof(m_m)); + m_nmi_line_state = 0; + m_frc = 0; + m_ocra = 0; + m_ocrb = 0; + m_icr = 0; + m_frc_base = 0; + m_frt_input = 0; + m_sh2_state->internal_irq_level = 0; + m_internal_irq_vector = 0; + m_sh2_state->icount = 0; + for ( int i = 0; i < 2; i++ ) + { + m_dma_timer_active[i] = 0; + m_dma_irq[i] = 0; + m_active_dma_incs[i] = 0; + m_active_dma_incd[i] = 0; + m_active_dma_size[i] = 0; + m_active_dma_steal[i] = 0; + m_active_dma_src[i] = 0; + m_active_dma_dst[i] = 0; + m_active_dma_count[i] = 0; + } + m_wtcnt = 0; + m_wtcsr = 0; + m_sh2_state->sleep_mode = 0; + m_numcycles = 0; + m_sh2_state->arg0 = 0; + m_arg1 = 0; + m_irq = 0; + m_fastram_select = 0; + memset(m_fastram, 0, sizeof(m_fastram)); + + /* reset per-driver pcflushes */ + m_pcfsel = 0; + + /* initialize the UML generator */ + UINT32 flags = 0; + m_drcuml = auto_alloc(machine(), drcuml_state(*this, m_cache, flags, 1, 32, 1)); + + /* add symbols for our stuff */ + m_drcuml->symbol_add(&m_sh2_state->pc, sizeof(m_sh2_state->pc), "pc"); + m_drcuml->symbol_add(&m_sh2_state->icount, sizeof(m_sh2_state->icount), "icount"); + for (int regnum = 0; regnum < 16; regnum++) + { + char buf[10]; + sprintf(buf, "r%d", regnum); + m_drcuml->symbol_add(&m_sh2_state->r[regnum], sizeof(m_sh2_state->r[regnum]), buf); + } + m_drcuml->symbol_add(&m_sh2_state->pr, sizeof(m_sh2_state->pr), "pr"); + m_drcuml->symbol_add(&m_sh2_state->sr, sizeof(m_sh2_state->sr), "sr"); + m_drcuml->symbol_add(&m_sh2_state->gbr, sizeof(m_sh2_state->gbr), "gbr"); + m_drcuml->symbol_add(&m_sh2_state->vbr, sizeof(m_sh2_state->vbr), "vbr"); + m_drcuml->symbol_add(&m_sh2_state->macl, sizeof(m_sh2_state->macl), "macl"); + m_drcuml->symbol_add(&m_sh2_state->mach, sizeof(m_sh2_state->macl), "mach"); + + /* initialize the front-end helper */ + m_drcfe = auto_alloc(machine(), sh2_frontend(this, COMPILE_BACKWARDS_BYTES, COMPILE_FORWARDS_BYTES, SINGLE_INSTRUCTION_MODE ? 1 : COMPILE_MAX_SEQUENCE)); + + /* compute the register parameters */ + for (int regnum = 0; regnum < 16; regnum++) + { + m_regmap[regnum] = uml::mem(&m_sh2_state->r[regnum]); + } + + /* if we have registers to spare, assign r0, r1, r2 to leftovers */ + /* WARNING: do not use synthetic registers that are mapped here! */ + if (!DISABLE_FAST_REGISTERS) + { + drcbe_info beinfo; + m_drcuml->get_backend_info(beinfo); + if (beinfo.direct_iregs > 4) + { + m_regmap[0] = uml::I4; + } + if (beinfo.direct_iregs > 5) + { + m_regmap[1] = uml::I5; + } + if (beinfo.direct_iregs > 6) + { + m_regmap[2] = uml::I6; + } + } + + /* mark the cache dirty so it is updated on next execute */ + m_cache_dirty = TRUE; +} + + +void sh2_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + switch (entry.index()) + { + case STATE_GENFLAGS: + strprintf(str, "%c%c%d%c%c", + m_sh2_state->sr & M ? 'M':'.', + m_sh2_state->sr & Q ? 'Q':'.', + (m_sh2_state->sr & I) >> 4, + m_sh2_state->sr & S ? 'S':'.', + m_sh2_state->sr & T ? 'T':'.'); + break; + } +} + + +void sh2_device::state_import(const device_state_entry &entry) +{ + switch (entry.index()) + { + case SH2_PC: + m_sh2_state->pc = m_debugger_temp; + m_delay = 0; + break; + + case SH2_SR: + CHECK_PENDING_IRQ("sh2_set_reg"); + break; + } +} + + +void sh2_device::state_export(const device_state_entry &entry) +{ + switch (entry.index()) + { + case SH2_PC: + m_debugger_temp = (m_delay) ? (m_delay & AM) : (m_sh2_state->pc & AM); + break; + } +} + + +void sh2_device::execute_set_input(int irqline, int state) +{ + if (irqline == INPUT_LINE_NMI) + { + if (m_nmi_line_state == state) + return; + m_nmi_line_state = state; + + if( state == CLEAR_LINE ) + { + LOG(("SH-2 '%s' cleared nmi\n", tag())); + } + else + { + LOG(("SH-2 '%s' assert nmi\n", tag())); + + sh2_exception("Set IRQ line", 16); + + if (m_isdrc) + m_sh2_state->pending_nmi = 1; + } + } + else + { + if (m_irq_line_state[irqline] == state) + return; + m_irq_line_state[irqline] = state; + + if( state == CLEAR_LINE ) + { + LOG(("SH-2 '%s' cleared irq #%d\n", tag(), irqline)); + m_sh2_state->pending_irq &= ~(1 << irqline); + } + else + { + LOG(("SH-2 '%s' assert irq #%d\n", tag(), irqline)); + m_sh2_state->pending_irq |= 1 << irqline; + if (m_isdrc) + { + m_test_irq = 1; + } else { + if(m_delay) + m_test_irq = 1; + else + CHECK_PENDING_IRQ("sh2_set_irq_line"); + } + } + } +} + +#include "sh2comn.c" +#include "sh2drc.c" diff --git a/src/devices/cpu/sh2/sh2.h b/src/devices/cpu/sh2/sh2.h new file mode 100644 index 00000000000..9724c1f51b0 --- /dev/null +++ b/src/devices/cpu/sh2/sh2.h @@ -0,0 +1,569 @@ +// license:BSD-3-Clause +// copyright-holders:Juergen Buchmueller +/***************************************************************************** + * + * sh2.h + * Portable Hitachi SH-2 (SH7600 family) emulator interface + * + * This work is based on C/C++ implementation of + * the SH-2 CPU core and was heavily changed to the MAME CPU requirements. + * Thanks also go to Chuck Mason and Olivier Galibert + * for letting me peek into their SEMU code :-) + * + *****************************************************************************/ + +#pragma once + +#ifndef __SH2_H__ +#define __SH2_H__ + +#include "cpu/drcfe.h" +#include "cpu/drcuml.h" + + +#define SH2_INT_NONE -1 +#define SH2_INT_VBLIN 0 +#define SH2_INT_VBLOUT 1 +#define SH2_INT_HBLIN 2 +#define SH2_INT_TIMER0 3 +#define SH2_INT_TIMER1 4 +#define SH2_INT_DSP 5 +#define SH2_INT_SOUND 6 +#define SH2_INT_SMPC 7 +#define SH2_INT_PAD 8 +#define SH2_INT_DMA2 9 +#define SH2_INT_DMA1 10 +#define SH2_INT_DMA0 11 +#define SH2_INT_DMAILL 12 +#define SH2_INT_SPRITE 13 +#define SH2_INT_14 14 +#define SH2_INT_15 15 +#define SH2_INT_ABUS 16 + +enum +{ + SH2_PC=1, SH2_SR, SH2_PR, SH2_GBR, SH2_VBR, SH2_MACH, SH2_MACL, + SH2_R0, SH2_R1, SH2_R2, SH2_R3, SH2_R4, SH2_R5, SH2_R6, SH2_R7, + SH2_R8, SH2_R9, SH2_R10, SH2_R11, SH2_R12, SH2_R13, SH2_R14, SH2_R15, SH2_EA +}; + + +typedef device_delegate sh2_dma_kludge_delegate; +#define SH2_DMA_KLUDGE_CB(name) int name(UINT32 src, UINT32 dst, UINT32 data, int size) + +typedef device_delegate sh2_dma_fifo_data_available_delegate; +#define SH2_DMA_FIFO_DATA_AVAILABLE_CB(name) int name(UINT32 src, UINT32 dst, UINT32 data, int size) + +typedef device_delegate sh2_ftcsr_read_delegate; +#define SH2_FTCSR_READ_CB(name) void name(UINT32 data) + + +#define MCFG_SH2_IS_SLAVE(_slave) \ + sh2_device::set_is_slave(*device, _slave); + +#define MCFG_SH2_DMA_KLUDGE_CB(_class, _method) \ + sh2_device::set_dma_kludge_callback(*device, sh2_dma_kludge_delegate(&_class::_method, #_class "::" #_method, downcast<_class *>(owner))); + +#define MCFG_SH2_FIFO_DATA_AVAIL_CB(_class, _method) \ + sh2_device::set_dma_fifo_data_available_callback(*device, sh2_dma_fifo_data_available_delegate(&_class::_method, #_class "::" #_method, downcast<_class *>(owner))); + +#define MCFG_SH2_FTCSR_READ_CB(_class, _method) \ + sh2_device::set_ftcsr_read_callback(*device, sh2_ftcsr_read_delegate(&_class::_method, #_class "::" #_method, downcast<_class *>(owner))); + + +/*************************************************************************** + COMPILER-SPECIFIC OPTIONS +***************************************************************************/ + +#define SH2DRC_STRICT_VERIFY 0x0001 /* verify all instructions */ +#define SH2DRC_FLUSH_PC 0x0002 /* flush the PC value before each memory access */ +#define SH2DRC_STRICT_PCREL 0x0004 /* do actual loads on MOVLI/MOVWI instead of collapsing to immediates */ + +#define SH2DRC_COMPATIBLE_OPTIONS (SH2DRC_STRICT_VERIFY | SH2DRC_FLUSH_PC | SH2DRC_STRICT_PCREL) +#define SH2DRC_FASTEST_OPTIONS (0) + +enum +{ + CPUINFO_INT_SH2_DRC_OPTIONS = CPUINFO_INT_CPU_SPECIFIC, + + CPUINFO_INT_SH2_FASTRAM_SELECT, + CPUINFO_INT_SH2_FASTRAM_START, + CPUINFO_INT_SH2_FASTRAM_END, + CPUINFO_INT_SH2_FASTRAM_READONLY, + + CPUINFO_PTR_SH2_FASTRAM_BASE = CPUINFO_PTR_CPU_SPECIFIC +}; + +#define SH2_MAX_FASTRAM 4 + +class sh2_frontend; + +class sh2_device : public cpu_device +{ + friend class sh2_frontend; + +public: + // construction/destruction + sh2_device(const machine_config &mconfig, const char *_tag, device_t *_owner, UINT32 _clock); + sh2_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source, int cpu_type,address_map_constructor internal_map, int addrlines); + + static void set_is_slave(device_t &device, int slave) { downcast(device).m_is_slave = slave; } + static void set_dma_kludge_callback(device_t &device, sh2_dma_kludge_delegate callback) { downcast(device).m_dma_kludge_cb = callback; } + static void set_dma_fifo_data_available_callback(device_t &device, sh2_dma_fifo_data_available_delegate callback) { downcast(device).m_dma_fifo_data_available_cb = callback; } + static void set_ftcsr_read_callback(device_t &device, sh2_ftcsr_read_delegate callback) { downcast(device).m_ftcsr_read_cb = callback; } + + DECLARE_WRITE32_MEMBER( sh7604_w ); + DECLARE_READ32_MEMBER( sh7604_r ); + DECLARE_READ32_MEMBER(sh2_internal_a5); + + void sh2_set_frt_input(int state); + void sh2drc_set_options(UINT32 options); + void sh2drc_add_pcflush(offs_t address); + void sh2drc_add_fastram(offs_t start, offs_t end, UINT8 readonly, void *base); + + void sh2_notify_dma_data_available(); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_stop(); + + // device_execute_interface overrides + virtual UINT32 execute_min_cycles() const { return 1; } + virtual UINT32 execute_max_cycles() const { return 4; } + virtual UINT32 execute_input_lines() const { return 16; } + virtual UINT32 execute_default_irq_vector() const { return 0; } + virtual void execute_run(); + virtual void execute_set_input(int inputnum, int state); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const; + + // device_state_interface overrides + virtual void state_import(const device_state_entry &entry); + virtual void state_export(const device_state_entry &entry); + void state_string_export(const device_state_entry &entry, std::string &str); + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const { return 2; } + virtual UINT32 disasm_max_opcode_bytes() const { return 2; } + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + address_space *m_program, *m_decrypted_program; + +private: + address_space_config m_program_config, m_decrypted_program_config; + + // Data that needs to be stored close to the generated DRC code + struct internal_sh2_state + { + UINT32 ppc; + UINT32 pc; + UINT32 pr; + UINT32 sr; + UINT32 gbr; + UINT32 vbr; + UINT32 mach; + UINT32 macl; + UINT32 r[16]; + UINT32 ea; + UINT32 pending_irq; + UINT32 pending_nmi; + INT32 irqline; + UINT32 evec; // exception vector for DRC + UINT32 irqsr; // IRQ-time old SR for DRC + UINT32 target; // target for jmp/jsr/etc so the delay slot can't kill it + int internal_irq_level; + int icount; + UINT8 sleep_mode; + UINT32 arg0; /* print_debug argument 1 */ + }; + + UINT32 m_delay; + UINT32 m_cpu_off; + UINT32 m_dvsr, m_dvdnth, m_dvdntl, m_dvcr; + UINT32 m_test_irq; + struct + { + int irq_vector; + int irq_priority; + } m_irq_queue[16]; + + bool m_isdrc; + + int m_pcfsel; // last pcflush entry set + int m_maxpcfsel; // highest valid pcflush entry + UINT32 m_pcflushes[16]; // pcflush entries + + INT8 m_irq_line_state[17]; +protected: + direct_read_data *m_direct; +private: + address_space *m_internal; + UINT32 m_m[0x200/4]; + INT8 m_nmi_line_state; + + UINT16 m_frc; + UINT16 m_ocra, m_ocrb, m_icr; + UINT64 m_frc_base; + + int m_frt_input; + int m_internal_irq_vector; + + emu_timer *m_timer; + emu_timer *m_dma_current_active_timer[2]; + int m_dma_timer_active[2]; + UINT8 m_dma_irq[2]; + + int m_active_dma_incs[2]; + int m_active_dma_incd[2]; + int m_active_dma_size[2]; + int m_active_dma_steal[2]; + UINT32 m_active_dma_src[2]; + UINT32 m_active_dma_dst[2]; + UINT32 m_active_dma_count[2]; + UINT16 m_wtcnt; + UINT8 m_wtcsr; + + int m_is_slave, m_cpu_type; + sh2_dma_kludge_delegate m_dma_kludge_cb; + sh2_dma_fifo_data_available_delegate m_dma_fifo_data_available_cb; + sh2_ftcsr_read_delegate m_ftcsr_read_cb; + + drc_cache m_cache; /* pointer to the DRC code cache */ + drcuml_state * m_drcuml; /* DRC UML generator state */ + sh2_frontend * m_drcfe; /* pointer to the DRC front-end state */ + UINT32 m_drcoptions; /* configurable DRC options */ + + internal_sh2_state *m_sh2_state; + + /* internal stuff */ + UINT8 m_cache_dirty; /* true if we need to flush the cache */ + + /* parameters for subroutines */ + UINT64 m_numcycles; /* return value from gettotalcycles */ + UINT32 m_arg1; /* print_debug argument 2 */ + UINT32 m_irq; /* irq we're taking */ + + /* register mappings */ + uml::parameter m_regmap[16]; /* parameter to register mappings for all 16 integer registers */ + + uml::code_handle * m_entry; /* entry point */ + uml::code_handle * m_read8; /* read byte */ + uml::code_handle * m_write8; /* write byte */ + uml::code_handle * m_read16; /* read half */ + uml::code_handle * m_write16; /* write half */ + uml::code_handle * m_read32; /* read word */ + uml::code_handle * m_write32; /* write word */ + + uml::code_handle * m_interrupt; /* interrupt */ + uml::code_handle * m_nocode; /* nocode */ + uml::code_handle * m_out_of_cycles; /* out of cycles exception handler */ + + /* fast RAM */ + UINT32 m_fastram_select; + struct + { + offs_t start; /* start of the RAM block */ + offs_t end; /* end of the RAM block */ + UINT8 readonly; /* TRUE if read-only */ + void * base; /* base in memory where the RAM lives */ + } m_fastram[SH2_MAX_FASTRAM]; + + UINT32 m_debugger_temp; + + inline UINT8 RB(offs_t A); + inline UINT16 RW(offs_t A); + inline UINT32 RL(offs_t A); + inline void WB(offs_t A, UINT8 V); + inline void WW(offs_t A, UINT16 V); + inline void WL(offs_t A, UINT32 V); + inline void ADD(UINT32 m, UINT32 n); + inline void ADDI(UINT32 i, UINT32 n); + inline void ADDC(UINT32 m, UINT32 n); + inline void ADDV(UINT32 m, UINT32 n); + inline void AND(UINT32 m, UINT32 n); + inline void ANDI(UINT32 i); + inline void ANDM(UINT32 i); + inline void BF(UINT32 d); + inline void BFS(UINT32 d); + inline void BRA(UINT32 d); + inline void BRAF(UINT32 m); + inline void BSR(UINT32 d); + inline void BSRF(UINT32 m); + inline void BT(UINT32 d); + inline void BTS(UINT32 d); + inline void CLRMAC(); + inline void CLRT(); + inline void CMPEQ(UINT32 m, UINT32 n); + inline void CMPGE(UINT32 m, UINT32 n); + inline void CMPGT(UINT32 m, UINT32 n); + inline void CMPHI(UINT32 m, UINT32 n); + inline void CMPHS(UINT32 m, UINT32 n); + inline void CMPPL(UINT32 n); + inline void CMPPZ(UINT32 n); + inline void CMPSTR(UINT32 m, UINT32 n); + inline void CMPIM(UINT32 i); + inline void DIV0S(UINT32 m, UINT32 n); + inline void DIV0U(); + inline void DIV1(UINT32 m, UINT32 n); + inline void DMULS(UINT32 m, UINT32 n); + inline void DMULU(UINT32 m, UINT32 n); + inline void DT(UINT32 n); + inline void EXTSB(UINT32 m, UINT32 n); + inline void EXTSW(UINT32 m, UINT32 n); + inline void EXTUB(UINT32 m, UINT32 n); + inline void EXTUW(UINT32 m, UINT32 n); + inline void ILLEGAL(); + inline void JMP(UINT32 m); + inline void JSR(UINT32 m); + inline void LDCSR(UINT32 m); + inline void LDCGBR(UINT32 m); + inline void LDCVBR(UINT32 m); + inline void LDCMSR(UINT32 m); + inline void LDCMGBR(UINT32 m); + inline void LDCMVBR(UINT32 m); + inline void LDSMACH(UINT32 m); + inline void LDSMACL(UINT32 m); + inline void LDSPR(UINT32 m); + inline void LDSMMACH(UINT32 m); + inline void LDSMMACL(UINT32 m); + inline void LDSMPR(UINT32 m); + inline void MAC_L(UINT32 m, UINT32 n); + inline void MAC_W(UINT32 m, UINT32 n); + inline void MOV(UINT32 m, UINT32 n); + inline void MOVBS(UINT32 m, UINT32 n); + inline void MOVWS(UINT32 m, UINT32 n); + inline void MOVLS(UINT32 m, UINT32 n); + inline void MOVBL(UINT32 m, UINT32 n); + inline void MOVWL(UINT32 m, UINT32 n); + inline void MOVLL(UINT32 m, UINT32 n); + inline void MOVBM(UINT32 m, UINT32 n); + inline void MOVWM(UINT32 m, UINT32 n); + inline void MOVLM(UINT32 m, UINT32 n); + inline void MOVBP(UINT32 m, UINT32 n); + inline void MOVWP(UINT32 m, UINT32 n); + inline void MOVLP(UINT32 m, UINT32 n); + inline void MOVBS0(UINT32 m, UINT32 n); + inline void MOVWS0(UINT32 m, UINT32 n); + inline void MOVLS0(UINT32 m, UINT32 n); + inline void MOVBL0(UINT32 m, UINT32 n); + inline void MOVWL0(UINT32 m, UINT32 n); + inline void MOVLL0(UINT32 m, UINT32 n); + inline void MOVI(UINT32 i, UINT32 n); + inline void MOVWI(UINT32 d, UINT32 n); + inline void MOVLI(UINT32 d, UINT32 n); + inline void MOVBLG(UINT32 d); + inline void MOVWLG(UINT32 d); + inline void MOVLLG(UINT32 d); + inline void MOVBSG(UINT32 d); + inline void MOVWSG(UINT32 d); + inline void MOVLSG(UINT32 d); + inline void MOVBS4(UINT32 d, UINT32 n); + inline void MOVWS4(UINT32 d, UINT32 n); + inline void MOVLS4(UINT32 m, UINT32 d, UINT32 n); + inline void MOVBL4(UINT32 m, UINT32 d); + inline void MOVWL4(UINT32 m, UINT32 d); + inline void MOVLL4(UINT32 m, UINT32 d, UINT32 n); + inline void MOVA(UINT32 d); + inline void MOVT(UINT32 n); + inline void MULL(UINT32 m, UINT32 n); + inline void MULS(UINT32 m, UINT32 n); + inline void MULU(UINT32 m, UINT32 n); + inline void NEG(UINT32 m, UINT32 n); + inline void NEGC(UINT32 m, UINT32 n); + inline void NOP(void); + inline void NOT(UINT32 m, UINT32 n); + inline void OR(UINT32 m, UINT32 n); + inline void ORI(UINT32 i); + inline void ORM(UINT32 i); + inline void ROTCL(UINT32 n); + inline void ROTCR(UINT32 n); + inline void ROTL(UINT32 n); + inline void ROTR(UINT32 n); + inline void RTE(); + inline void RTS(); + inline void SETT(); + inline void SHAL(UINT32 n); + inline void SHAR(UINT32 n); + inline void SHLL(UINT32 n); + inline void SHLL2(UINT32 n); + inline void SHLL8(UINT32 n); + inline void SHLL16(UINT32 n); + inline void SHLR(UINT32 n); + inline void SHLR2(UINT32 n); + inline void SHLR8(UINT32 n); + inline void SHLR16(UINT32 n); + inline void SLEEP(); + inline void STCSR(UINT32 n); + inline void STCGBR(UINT32 n); + inline void STCVBR(UINT32 n); + inline void STCMSR(UINT32 n); + inline void STCMGBR(UINT32 n); + inline void STCMVBR(UINT32 n); + inline void STSMACH(UINT32 n); + inline void STSMACL(UINT32 n); + inline void STSPR(UINT32 n); + inline void STSMMACH(UINT32 n); + inline void STSMMACL(UINT32 n); + inline void STSMPR(UINT32 n); + inline void SUB(UINT32 m, UINT32 n); + inline void SUBC(UINT32 m, UINT32 n); + inline void SUBV(UINT32 m, UINT32 n); + inline void SWAPB(UINT32 m, UINT32 n); + inline void SWAPW(UINT32 m, UINT32 n); + inline void TAS(UINT32 n); + inline void TRAPA(UINT32 i); + inline void TST(UINT32 m, UINT32 n); + inline void TSTI(UINT32 i); + inline void TSTM(UINT32 i); + inline void XOR(UINT32 m, UINT32 n); + inline void XORI(UINT32 i); + inline void XORM(UINT32 i); + inline void XTRCT(UINT32 m, UINT32 n); + inline void op0000(UINT16 opcode); + inline void op0001(UINT16 opcode); + inline void op0010(UINT16 opcode); + inline void op0011(UINT16 opcode); + inline void op0100(UINT16 opcode); + inline void op0101(UINT16 opcode); + inline void op0110(UINT16 opcode); + inline void op0111(UINT16 opcode); + inline void op1000(UINT16 opcode); + inline void op1001(UINT16 opcode); + inline void op1010(UINT16 opcode); + inline void op1011(UINT16 opcode); + inline void op1100(UINT16 opcode); + inline void op1101(UINT16 opcode); + inline void op1110(UINT16 opcode); + inline void op1111(UINT16 opcode); + TIMER_CALLBACK_MEMBER( sh2_timer_callback ); + TIMER_CALLBACK_MEMBER( sh2_dma_current_active_callback ); + void sh2_timer_resync(); + void sh2_timer_activate(); + void sh2_do_dma(int dma); + void sh2_exception(const char *message, int irqline); + void sh2_dmac_check(int dma); + void sh2_recalc_irq(); + + /* internal compiler state */ + struct compiler_state + { + UINT32 cycles; /* accumulated cycles */ + UINT8 checkints; /* need to check interrupts before next instruction */ + uml::code_label labelnum; /* index for local labels */ + }; + + inline UINT32 epc(const opcode_desc *desc); + inline void alloc_handle(drcuml_state *drcuml, uml::code_handle **handleptr, const char *name); + inline void load_fast_iregs(drcuml_block *block); + inline void save_fast_iregs(drcuml_block *block); + + void code_flush_cache(); + void execute_run_drc(); + void code_compile_block(UINT8 mode, offs_t pc); + void static_generate_entry_point(); + void static_generate_nocode_handler(); + void static_generate_out_of_cycles(); + void static_generate_memory_accessor(int size, int iswrite, const char *name, uml::code_handle **handleptr); + const char *log_desc_flags_to_string(UINT32 flags); + void log_register_list(drcuml_state *drcuml, const char *string, const UINT32 *reglist, const UINT32 *regnostarlist); + void log_opcode_desc(drcuml_state *drcuml, const opcode_desc *desclist, int indent); + void log_add_disasm_comment(drcuml_block *block, UINT32 pc, UINT32 op); + void generate_update_cycles(drcuml_block *block, compiler_state *compiler, uml::parameter param, int allow_exception); + void generate_checksum_block(drcuml_block *block, compiler_state *compiler, const opcode_desc *seqhead, const opcode_desc *seqlast); + void generate_sequence_instruction(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, UINT32 ovrpc); + void generate_delay_slot(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, UINT32 ovrpc); + int generate_opcode(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, UINT32 ovrpc); + int generate_group_0(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, UINT16 opcode, int in_delay_slot, UINT32 ovrpc); + int generate_group_2(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, UINT16 opcode, int in_delay_slot, UINT32 ovrpc); + int generate_group_3(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, UINT16 opcode, UINT32 ovrpc); + int generate_group_4(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, UINT16 opcode, int in_delay_slot, UINT32 ovrpc); + int generate_group_6(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, UINT16 opcode, int in_delay_slot, UINT32 ovrpc); + int generate_group_8(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, UINT16 opcode, int in_delay_slot, UINT32 ovrpc); + int generate_group_12(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, UINT16 opcode, int in_delay_slot, UINT32 ovrpc); + +public: + void func_printf_probe(); + void func_unimplemented(); + void func_fastirq(); + void func_MAC_W(); + void func_MAC_L(); + void func_DIV1(); + void func_ADDV(); + void func_SUBV(); +}; + +class sh2a_device : public sh2_device +{ +public: + // construction/destruction + sh2a_device(const machine_config &mconfig, const char *_tag, device_t *_owner, UINT32 _clock); + + DECLARE_READ32_MEMBER(dma_sar0_r); + DECLARE_WRITE32_MEMBER(dma_sar0_w); + DECLARE_READ32_MEMBER(dma_dar0_r); + DECLARE_WRITE32_MEMBER(dma_dar0_w); + DECLARE_READ16_MEMBER(dmaor_r); + DECLARE_WRITE16_MEMBER(dmaor_w); + DECLARE_READ16_MEMBER(dma_tcr0_r); + DECLARE_WRITE16_MEMBER(dma_tcr0_w); + DECLARE_READ16_MEMBER(dma_chcr0_r); + DECLARE_WRITE16_MEMBER(dma_chcr0_w); + DECLARE_READ16_MEMBER(sh7021_r); + DECLARE_WRITE16_MEMBER(sh7021_w); + void sh7032_dma_exec(int ch); + +private: + UINT16 m_sh7021_regs[0x200]; + struct + { + UINT32 sar; /**< Source Address Register */ + UINT32 dar; /**< Destination Address Register */ + UINT16 tcr; /**< Transfer Count Register */ + UINT16 chcr; /**< Channel Control Register */ + } m_dma[4]; + UINT16 m_dmaor; /**< DMA Operation Register (status flags) */ + +}; + +class sh1_device : public sh2_device +{ +public: + // construction/destruction + sh1_device(const machine_config &mconfig, const char *_tag, device_t *_owner, UINT32 _clock); + + DECLARE_READ16_MEMBER(sh7032_r); + DECLARE_WRITE16_MEMBER(sh7032_w); +private: + UINT16 m_sh7032_regs[0x200]; +}; + + +class sh2_frontend : public drc_frontend +{ +public: + sh2_frontend(sh2_device *device, UINT32 window_start, UINT32 window_end, UINT32 max_sequence); + +protected: + virtual bool describe(opcode_desc &desc, const opcode_desc *prev); + +private: + bool describe_group_0(opcode_desc &desc, const opcode_desc *prev, UINT16 opcode); + bool describe_group_2(opcode_desc &desc, const opcode_desc *prev, UINT16 opcode); + bool describe_group_3(opcode_desc &desc, const opcode_desc *prev, UINT16 opcode); + bool describe_group_4(opcode_desc &desc, const opcode_desc *prev, UINT16 opcode); + bool describe_group_6(opcode_desc &desc, const opcode_desc *prev, UINT16 opcode); + bool describe_group_8(opcode_desc &desc, const opcode_desc *prev, UINT16 opcode); + bool describe_group_12(opcode_desc &desc, const opcode_desc *prev, UINT16 opcode); + + sh2_device *m_sh2; +}; + + +extern const device_type SH1; +extern const device_type SH2; +extern const device_type SH2A; + + +#endif /* __SH2_H__ */ diff --git a/src/devices/cpu/sh2/sh2comn.c b/src/devices/cpu/sh2/sh2comn.c new file mode 100644 index 00000000000..1080203494f --- /dev/null +++ b/src/devices/cpu/sh2/sh2comn.c @@ -0,0 +1,1027 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/***************************************************************************** + * + * sh2common.c + * + * SH-2 non-specific components + * + *****************************************************************************/ + +#include "emu.h" +#include "debugger.h" +#include "sh2.h" +#include "sh2comn.h" + + +// for now, make buggy GCC/Mingw STFU about I64FMT +#if (defined(__MINGW32__) && (__GNUC__ >= 5)) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wformat" +#pragma GCC diagnostic ignored "-Wformat-extra-args" +#endif + +#define VERBOSE 0 + +#define LOG(x) do { if (VERBOSE) logerror x; } while (0) + +static const int div_tab[4] = { 3, 5, 7, 0 }; + + +void sh2_device::sh2_timer_resync() +{ + int divider = div_tab[(m_m[5] >> 8) & 3]; + UINT64 cur_time = total_cycles(); + UINT64 add = (cur_time - m_frc_base) >> divider; + + if (add > 0) + { + if(divider) + m_frc += add; + + m_frc_base = cur_time; + } +} + +void sh2_device::sh2_timer_activate() +{ + int max_delta = 0xfffff; + UINT16 frc; + + m_timer->adjust(attotime::never); + + frc = m_frc; + if(!(m_m[4] & OCFA)) { + UINT16 delta = m_ocra - frc; + if(delta < max_delta) + max_delta = delta; + } + + if(!(m_m[4] & OCFB) && (m_ocra <= m_ocrb || !(m_m[4] & 0x010000))) { + UINT16 delta = m_ocrb - frc; + if(delta < max_delta) + max_delta = delta; + } + + if(!(m_m[4] & OVF) && !(m_m[4] & 0x010000)) { + int delta = 0x10000 - frc; + if(delta < max_delta) + max_delta = delta; + } + + if(max_delta != 0xfffff) { + int divider = div_tab[(m_m[5] >> 8) & 3]; + if(divider) { + max_delta <<= divider; + m_frc_base = total_cycles(); + m_timer->adjust(cycles_to_attotime(max_delta)); + } else { + logerror("SH2.%s: Timer event in %d cycles of external clock", tag(), max_delta); + } + } +} + +TIMER_CALLBACK_MEMBER( sh2_device::sh2_timer_callback ) +{ + UINT16 frc; + + sh2_timer_resync(); + + frc = m_frc; + + if(frc == m_ocrb) + m_m[4] |= OCFB; + + if(frc == 0x0000) + m_m[4] |= OVF; + + if(frc == m_ocra) + { + m_m[4] |= OCFA; + + if(m_m[4] & 0x010000) + m_frc = 0; + } + + sh2_recalc_irq(); + sh2_timer_activate(); +} + + +/* + We have to do DMA on a timer (or at least, in chunks) due to the way some systems use it. + The 32x is a difficult case, they set the SOURCE of the DMA to a FIFO buffer, which at most + can have 8 words in it. Attempting to do an 'instant DMA' in this scenario is impossible + because the game is expecting the 68k of the system to feed data into the FIFO at the same + time as the SH2 is transfering it out via DMA + + There are two ways we can do this + + a) with a high frequency timer (more accurate, but a large performance hit) + + or + + b) in the CPU_EXECUTE loop + + + we're currently doing a) + + b) causes problems with ST-V games + +*/ + + + +void sh2_device::sh2_notify_dma_data_available() +{ + //printf("call notify\n"); + + for (int dma=0;dma<2;dma++) + { + //printf("m_dma_timer_active[dma] %04x\n",m_dma_timer_active[dma]); + + if (m_dma_timer_active[dma]==2) // 2 = stalled + { + // printf("resuming stalled dma\n"); + m_dma_timer_active[dma]=1; + m_dma_current_active_timer[dma]->adjust(attotime::zero, dma); + } + } + +} + +void sh2_device::sh2_do_dma(int dma) +{ + UINT32 dmadata; + + UINT32 tempsrc, tempdst; + + if (m_active_dma_count[dma] > 0) + { + // process current DMA + switch(m_active_dma_size[dma]) + { + case 0: + { + // we need to know the src / dest ahead of time without changing them + // to allow for the callback to check if we can process the DMA at this + // time (we need to know where we're reading / writing to/from) + + if(m_active_dma_incs[dma] == 2) + tempsrc = m_active_dma_src[dma] - 1; + else + tempsrc = m_active_dma_src[dma]; + + if(m_active_dma_incd[dma] == 2) + tempdst = m_active_dma_dst[dma] - 1; + else + tempdst = m_active_dma_dst[dma]; + + if (!m_dma_fifo_data_available_cb.isnull()) + { + int available = m_dma_fifo_data_available_cb(tempsrc, tempdst, 0, m_active_dma_size[dma]); + + if (!available) + { + //printf("dma stalled\n"); + m_dma_timer_active[dma]=2;// mark as stalled + return; + } + } + + #ifdef USE_TIMER_FOR_DMA + //schedule next DMA callback + m_dma_current_active_timer[dma]->adjust(cycles_to_attotime(2), dma); + #endif + + + dmadata = m_program->read_byte(tempsrc); + if (!m_dma_kludge_cb.isnull()) dmadata = m_dma_kludge_cb(tempsrc, tempdst, dmadata, m_active_dma_size[dma]); + m_program->write_byte(tempdst, dmadata); + + if(m_active_dma_incs[dma] == 2) + m_active_dma_src[dma] --; + if(m_active_dma_incd[dma] == 2) + m_active_dma_dst[dma] --; + + + if(m_active_dma_incs[dma] == 1) + m_active_dma_src[dma] ++; + if(m_active_dma_incd[dma] == 1) + m_active_dma_dst[dma] ++; + + m_active_dma_count[dma] --; + } + break; + case 1: + { + if(m_active_dma_incs[dma] == 2) + tempsrc = m_active_dma_src[dma] - 2; + else + tempsrc = m_active_dma_src[dma]; + + if(m_active_dma_incd[dma] == 2) + tempdst = m_active_dma_dst[dma] - 2; + else + tempdst = m_active_dma_dst[dma]; + + if (!m_dma_fifo_data_available_cb.isnull()) + { + int available = m_dma_fifo_data_available_cb(tempsrc, tempdst, 0, m_active_dma_size[dma]); + + if (!available) + { + //printf("dma stalled\n"); + m_dma_timer_active[dma]=2;// mark as stalled + return; + } + } + + #ifdef USE_TIMER_FOR_DMA + //schedule next DMA callback + m_dma_current_active_timer[dma]->adjust(cycles_to_attotime(2), dma); + #endif + + // check: should this really be using read_word_32 / write_word_32? + dmadata = m_program->read_word(tempsrc); + if (!m_dma_kludge_cb.isnull()) dmadata = m_dma_kludge_cb(tempsrc, tempdst, dmadata, m_active_dma_size[dma]); + m_program->write_word(tempdst, dmadata); + + if(m_active_dma_incs[dma] == 2) + m_active_dma_src[dma] -= 2; + if(m_active_dma_incd[dma] == 2) + m_active_dma_dst[dma] -= 2; + + if(m_active_dma_incs[dma] == 1) + m_active_dma_src[dma] += 2; + if(m_active_dma_incd[dma] == 1) + m_active_dma_dst[dma] += 2; + + m_active_dma_count[dma] --; + } + break; + case 2: + { + if(m_active_dma_incs[dma] == 2) + tempsrc = m_active_dma_src[dma] - 4; + else + tempsrc = m_active_dma_src[dma]; + + if(m_active_dma_incd[dma] == 2) + tempdst = m_active_dma_dst[dma] - 4; + else + tempdst = m_active_dma_dst[dma]; + + if (!m_dma_fifo_data_available_cb.isnull()) + { + int available = m_dma_fifo_data_available_cb(tempsrc, tempdst, 0, m_active_dma_size[dma]); + + if (!available) + { + //printf("dma stalled\n"); + m_dma_timer_active[dma]=2;// mark as stalled + return; + } + } + + #ifdef USE_TIMER_FOR_DMA + //schedule next DMA callback + m_dma_current_active_timer[dma]->adjust(cycles_to_attotime(2), dma); + #endif + + dmadata = m_program->read_dword(tempsrc); + if (!m_dma_kludge_cb.isnull()) dmadata = m_dma_kludge_cb(tempsrc, tempdst, dmadata, m_active_dma_size[dma]); + m_program->write_dword(tempdst, dmadata); + + if(m_active_dma_incs[dma] == 2) + m_active_dma_src[dma] -= 4; + if(m_active_dma_incd[dma] == 2) + m_active_dma_dst[dma] -= 4; + + if(m_active_dma_incs[dma] == 1) + m_active_dma_src[dma] += 4; + if(m_active_dma_incd[dma] == 1) + m_active_dma_dst[dma] += 4; + + m_active_dma_count[dma] --; + } + break; + case 3: + { + // shouldn't this really be 4 calls here instead? + + tempsrc = m_active_dma_src[dma]; + + if(m_active_dma_incd[dma] == 2) + tempdst = m_active_dma_dst[dma] - 16; + else + tempdst = m_active_dma_dst[dma]; + + if (!m_dma_fifo_data_available_cb.isnull()) + { + int available = m_dma_fifo_data_available_cb(tempsrc, tempdst, 0, m_active_dma_size[dma]); + + if (!available) + { + //printf("dma stalled\n"); + m_dma_timer_active[dma]=2;// mark as stalled + fatalerror("SH2 dma_callback_fifo_data_available == 0 in unsupported mode\n"); + } + } + + #ifdef USE_TIMER_FOR_DMA + //schedule next DMA callback + m_dma_current_active_timer[dma]->adjust(cycles_to_attotime(2), dma); + #endif + + dmadata = m_program->read_dword(tempsrc); + if (!m_dma_kludge_cb.isnull()) dmadata = m_dma_kludge_cb(tempsrc, tempdst, dmadata, m_active_dma_size[dma]); + m_program->write_dword(tempdst, dmadata); + + dmadata = m_program->read_dword(tempsrc+4); + if (!m_dma_kludge_cb.isnull()) dmadata = m_dma_kludge_cb(tempsrc, tempdst, dmadata, m_active_dma_size[dma]); + m_program->write_dword(tempdst+4, dmadata); + + dmadata = m_program->read_dword(tempsrc+8); + if (!m_dma_kludge_cb.isnull()) dmadata = m_dma_kludge_cb(tempsrc, tempdst, dmadata, m_active_dma_size[dma]); + m_program->write_dword(tempdst+8, dmadata); + + dmadata = m_program->read_dword(tempsrc+12); + if (!m_dma_kludge_cb.isnull()) dmadata = m_dma_kludge_cb(tempsrc, tempdst, dmadata, m_active_dma_size[dma]); + m_program->write_dword(tempdst+12, dmadata); + + if(m_active_dma_incd[dma] == 2) + m_active_dma_dst[dma] -= 16; + + m_active_dma_src[dma] += 16; + if(m_active_dma_incd[dma] == 1) + m_active_dma_dst[dma] += 16; + + m_active_dma_count[dma]-=4; + } + break; + } + } + else // the dma is complete + { + // int dma = param & 1; + + // fever soccer uses cycle-stealing mode, resume the CPU now DMA has finished + if (m_active_dma_steal[dma]) + { + resume(SUSPEND_REASON_HALT ); + } + + + LOG(("SH2.%s: DMA %d complete\n", tag(), dma)); + m_m[0x62+4*dma] = 0; + m_m[0x63+4*dma] |= 2; + m_dma_timer_active[dma] = 0; + m_dma_irq[dma] |= 1; + sh2_recalc_irq(); + + } +} + +TIMER_CALLBACK_MEMBER( sh2_device::sh2_dma_current_active_callback ) +{ + int dma = param & 1; + + sh2_do_dma(dma); +} + + +void sh2_device::sh2_dmac_check(int dma) +{ + if(m_m[0x63+4*dma] & m_m[0x6c] & 1) + { + if(!m_dma_timer_active[dma] && !(m_m[0x63+4*dma] & 2)) + { + m_active_dma_incd[dma] = (m_m[0x63+4*dma] >> 14) & 3; + m_active_dma_incs[dma] = (m_m[0x63+4*dma] >> 12) & 3; + m_active_dma_size[dma] = (m_m[0x63+4*dma] >> 10) & 3; + m_active_dma_steal[dma] = (m_m[0x63+4*dma] &0x10); + + if(m_active_dma_incd[dma] == 3 || m_active_dma_incs[dma] == 3) + { + logerror("SH2: DMA: bad increment values (%d, %d, %d, %04x)\n", m_active_dma_incd[dma], m_active_dma_incs[dma], m_active_dma_size[dma], m_m[0x63+4*dma]); + return; + } + m_active_dma_src[dma] = m_m[0x60+4*dma]; + m_active_dma_dst[dma] = m_m[0x61+4*dma]; + m_active_dma_count[dma] = m_m[0x62+4*dma]; + if(!m_active_dma_count[dma]) + m_active_dma_count[dma] = 0x1000000; + + LOG(("SH2: DMA %d start %x, %x, %x, %04x, %d, %d, %d\n", dma, m_active_dma_src[dma], m_active_dma_dst[dma], m_active_dma_count[dma], m_m[0x63+4*dma], m_active_dma_incs[dma], m_active_dma_incd[dma], m_active_dma_size[dma])); + + m_dma_timer_active[dma] = 1; + + m_active_dma_src[dma] &= AM; + m_active_dma_dst[dma] &= AM; + + switch(m_active_dma_size[dma]) + { + case 0: + break; + case 1: + m_active_dma_src[dma] &= ~1; + m_active_dma_dst[dma] &= ~1; + break; + case 2: + m_active_dma_src[dma] &= ~3; + m_active_dma_dst[dma] &= ~3; + break; + case 3: + m_active_dma_src[dma] &= ~3; + m_active_dma_dst[dma] &= ~3; + m_active_dma_count[dma] &= ~3; + break; + } + + + + +#ifdef USE_TIMER_FOR_DMA + // start DMA timer + + // fever soccer uses cycle-stealing mode, requiring the CPU to be halted + if (m_active_dma_steal[dma]) + { + //printf("cycle stealing DMA\n"); + suspend(SUSPEND_REASON_HALT, 1 ); + } + + m_dma_current_active_timer[dma]->adjust(cycles_to_attotime(2), dma); +#endif + + } + } + else + { + if(m_dma_timer_active[dma]) + { + logerror("SH2: DMA %d cancelled in-flight\n", dma); + //m_dma_complete_timer[dma]->adjust(attotime::never); + m_dma_current_active_timer[dma]->adjust(attotime::never); + + m_dma_timer_active[dma] = 0; + } + } +} + + +WRITE32_MEMBER( sh2_device::sh7604_w ) +{ + UINT32 old; + + old = m_m[offset]; + COMBINE_DATA(m_m+offset); + + // if(offset != 0x20) + // logerror("sh2_internal_w: Write %08x (%x), %08x @ %08x\n", 0xfffffe00+offset*4, offset, data, mem_mask); + +// if(offset != 0x20) +// printf("sh2_internal_w: Write %08x (%x), %08x @ %08x (PC %x)\n", 0xfffffe00+offset*4, offset, data, mem_mask, space.device().safe_pc()); + + switch( offset ) + { + case 0x00: + //if(mem_mask == 0xff) + // printf("%c",data & 0xff); + break; + case 0x01: + //printf("%08x %02x %02x\n",mem_mask,offset,data); + break; + // Timers + case 0x04: // TIER, FTCSR, FRC + if((mem_mask & 0x00ffffff) != 0) + { + sh2_timer_resync(); + } +// printf("SH2.%s: TIER write %04x @ %04x\n", m_device->tag(), data >> 16, mem_mask>>16); + m_m[4] = (m_m[4] & ~(ICF|OCFA|OCFB|OVF)) | (old & m_m[4] & (ICF|OCFA|OCFB|OVF)); + COMBINE_DATA(&m_frc); + if((mem_mask & 0x00ffffff) != 0) + sh2_timer_activate(); + sh2_recalc_irq(); + break; + case 0x05: // OCRx, TCR, TOCR +// printf("SH2.%s: TCR write %08x @ %08x\n", m_device->tag(), data, mem_mask); + sh2_timer_resync(); + if(m_m[5] & 0x10) + m_ocrb = (m_ocrb & (~mem_mask >> 16)) | ((data & mem_mask) >> 16); + else + m_ocra = (m_ocra & (~mem_mask >> 16)) | ((data & mem_mask) >> 16); + sh2_timer_activate(); + break; + + case 0x06: // ICR + break; + + // Interrupt vectors + case 0x18: // IPRB, VCRA + case 0x19: // VCRB, VCRC + case 0x1a: // VCRD + sh2_recalc_irq(); + break; + + // DMA + case 0x1c: // DRCR0, DRCR1 + break; + + // Watchdog + case 0x20: // WTCNT, RSTCSR + if((m_m[0x20] & 0xff000000) == 0x5a000000) + m_wtcnt = (m_m[0x20] >> 16) & 0xff; + + if((m_m[0x20] & 0xff000000) == 0xa5000000) + { + /* + WTCSR + x--- ---- Overflow in IT mode + -x-- ---- Timer mode (0: IT 1: watchdog) + --x- ---- Timer enable + ---1 1--- + ---- -xxx Clock select + */ + + m_wtcsr = (m_m[0x20] >> 16) & 0xff; + } + + if((m_m[0x20] & 0x0000ff00) == 0x00005a00) + { + // -x-- ---- RSTE (1: resets wtcnt when overflows 0: no reset) + // --x- ---- RSTS (0: power-on reset 1: Manual reset) + // ... + } + + if((m_m[0x20] & 0x0000ff00) == 0x0000a500) + { + // clear WOVF + // ... + } + + + + break; + + // Standby and cache + case 0x24: // SBYCR, CCR + /* + CCR + xx-- ---- ---- ---- Way 0/1 + ---x ---- ---- ---- Cache Purge (CP) + ---- x--- ---- ---- Two-Way Mode (TW) + ---- -x-- ---- ---- Data Replacement Disable (OD) + ---- --x- ---- ---- Instruction Replacement Disable (ID) + ---- ---x ---- ---- Cache Enable (CE) + */ + break; + + // Interrupt vectors cont. + case 0x38: // ICR, IRPA + break; + case 0x39: // VCRWDT + break; + + // Division box + case 0x40: // DVSR + break; + case 0x41: // DVDNT + { + INT32 a = m_m[0x41]; + INT32 b = m_m[0x40]; + LOG(("SH2 '%s' div+mod %d/%d\n", tag(), a, b)); + if (b) + { + m_m[0x45] = a / b; + m_m[0x44] = a % b; + } + else + { + m_m[0x42] |= 0x00010000; + m_m[0x45] = 0x7fffffff; + m_m[0x44] = 0x7fffffff; + sh2_recalc_irq(); + } + break; + } + case 0x42: // DVCR + m_m[0x42] = (m_m[0x42] & ~0x00001000) | (old & m_m[0x42] & 0x00010000); + sh2_recalc_irq(); + break; + case 0x43: // VCRDIV + sh2_recalc_irq(); + break; + case 0x44: // DVDNTH + break; + case 0x45: // DVDNTL + { + INT64 a = m_m[0x45] | ((UINT64)(m_m[0x44]) << 32); + INT64 b = (INT32)m_m[0x40]; + LOG(("SH2 '%s' div+mod %" I64FMT "d/%" I64FMT "d\n", tag(), a, b)); + if (b) + { + INT64 q = a / b; + if (q != (INT32)q) + { + m_m[0x42] |= 0x00010000; + m_m[0x45] = 0x7fffffff; + m_m[0x44] = 0x7fffffff; + sh2_recalc_irq(); + } + else + { + m_m[0x45] = q; + m_m[0x44] = a % b; + } + } + else + { + m_m[0x42] |= 0x00010000; + m_m[0x45] = 0x7fffffff; + m_m[0x44] = 0x7fffffff; + sh2_recalc_irq(); + } + break; + } + + // DMA controller + case 0x60: // SAR0 + case 0x61: // DAR0 + break; + case 0x62: // DTCR0 + m_m[0x62] &= 0xffffff; + break; + case 0x63: // CHCR0 + m_m[0x63] = (m_m[0x63] & ~2) | (old & m_m[0x63] & 2); + sh2_dmac_check(0); + break; + case 0x64: // SAR1 + case 0x65: // DAR1 + break; + case 0x66: // DTCR1 + m_m[0x66] &= 0xffffff; + break; + case 0x67: // CHCR1 + m_m[0x67] = (m_m[0x67] & ~2) | (old & m_m[0x67] & 2); + sh2_dmac_check(1); + break; + case 0x68: // VCRDMA0 + case 0x6a: // VCRDMA1 + sh2_recalc_irq(); + break; + case 0x6c: // DMAOR + m_m[0x6c] = (m_m[0x6c] & ~6) | (old & m_m[0x6c] & 6); + sh2_dmac_check(0); + sh2_dmac_check(1); + break; + + // Bus controller + case 0x78: // BCR1 + case 0x79: // BCR2 + case 0x7a: // WCR + case 0x7b: // MCR + case 0x7c: // RTCSR + case 0x7d: // RTCNT + case 0x7e: // RTCOR + break; + + default: + logerror("sh2_internal_w: Unmapped write %08x, %08x @ %08x\n", 0xfffffe00+offset*4, data, mem_mask); + break; + } +} + +READ32_MEMBER( sh2_device::sh7604_r ) +{ +// logerror("sh2_internal_r: Read %08x (%x) @ %08x\n", 0xfffffe00+offset*4, offset, mem_mask); + switch( offset ) + { + case 0x00: + break; + case 0x01: +// return m_m[1] | 0; // bit31 is TDRE: Trasmit Data Register Empty. Forcing it to be '1' breaks Saturn ... + return m_m[1] | (0x84 << 24); // ... but this is actually needed to make EGWord on SS to boot? + + case 0x04: // TIER, FTCSR, FRC + if ( mem_mask == 0x00ff0000 ) + { + if (!m_ftcsr_read_cb.isnull()) + { + m_ftcsr_read_cb((m_m[4] & 0xffff0000) | m_frc); + } + } + sh2_timer_resync(); + return (m_m[4] & 0xffff0000) | m_frc; + case 0x05: // OCRx, TCR, TOCR + if(m_m[5] & 0x10) + return (m_ocrb << 16) | (m_m[5] & 0xffff); + else + return (m_ocra << 16) | (m_m[5] & 0xffff); + case 0x06: // ICR + return m_icr << 16; + + case 0x20: + return (((m_wtcsr | 0x18) & 0xff) << 24) | ((m_wtcnt & 0xff) << 16); + + case 0x24: // SBYCR, CCR + return m_m[0x24] & ~0x3000; /* bit 4-5 of CCR are always zero */ + + case 0x38: // ICR, IPRA + return (m_m[0x38] & 0x7fffffff) | (m_nmi_line_state == ASSERT_LINE ? 0 : 0x80000000); + + case 0x78: // BCR1 + return m_is_slave ? 0x00008000 : 0; + + case 0x41: // dvdntl mirrors + case 0x47: + return m_m[0x45]; + + case 0x46: // dvdnth mirror + return m_m[0x44]; + } + return m_m[offset]; +} + +void sh2_device::sh2_set_frt_input(int state) +{ + if(state == PULSE_LINE) + { + sh2_set_frt_input(ASSERT_LINE); + sh2_set_frt_input(CLEAR_LINE); + return; + } + + if(m_frt_input == state) { + return; + } + + m_frt_input = state; + + if(m_m[5] & 0x8000) { + if(state == CLEAR_LINE) { + return; + } + } else { + if(state == ASSERT_LINE) { + return; + } + } + + sh2_timer_resync(); + m_icr = m_frc; + m_m[4] |= ICF; + //logerror("SH2.%s: ICF activated (%x)\n", tag(), m_sh2_state->pc & AM); + sh2_recalc_irq(); +} + +void sh2_device::sh2_recalc_irq() +{ + int irq = 0, vector = -1; + int level; + + // Timer irqs + if((m_m[4]>>8) & m_m[4] & (ICF|OCFA|OCFB|OVF)) + { + level = (m_m[0x18] >> 24) & 15; + if(level > irq) + { + int mask = (m_m[4]>>8) & m_m[4]; + irq = level; + if(mask & ICF) + vector = (m_m[0x19] >> 8) & 0x7f; + else if(mask & (OCFA|OCFB)) + vector = m_m[0x19] & 0x7f; + else + vector = (m_m[0x1a] >> 24) & 0x7f; + } + } + + // DMA irqs + if((m_m[0x63] & 6) == 6 && m_dma_irq[0]) { + level = (m_m[0x38] >> 8) & 15; + if(level > irq) { + irq = level; + m_dma_irq[0] &= ~1; + vector = (m_m[0x68]) & 0x7f; + } + } + else if((m_m[0x67] & 6) == 6 && m_dma_irq[1]) { + level = (m_m[0x38] >> 8) & 15; + if(level > irq) { + irq = level; + m_dma_irq[1] &= ~1; + vector = (m_m[0x6a]) & 0x7f; + } + } + + m_sh2_state->internal_irq_level = irq; + m_internal_irq_vector = vector; + m_test_irq = 1; +} + +void sh2_device::sh2_exception(const char *message, int irqline) +{ + int vector; + + if (irqline != 16) + { + if (irqline <= ((m_sh2_state->sr >> 4) & 15)) /* If the cpu forbids this interrupt */ + return; + + // if this is an sh2 internal irq, use its vector + if (m_sh2_state->internal_irq_level == irqline) + { + vector = m_internal_irq_vector; + /* avoid spurious irqs with this (TODO: needs a better fix) */ + m_sh2_state->internal_irq_level = -1; + LOG(("SH-2 '%s' exception #%d (internal vector: $%x) after [%s]\n", tag(), irqline, vector, message)); + } + else + { + if(m_m[0x38] & 0x00010000) + { + vector = standard_irq_callback(irqline); + LOG(("SH-2 '%s' exception #%d (external vector: $%x) after [%s]\n", tag(), irqline, vector, message)); + } + else + { + standard_irq_callback(irqline); + vector = 64 + irqline/2; + LOG(("SH-2 '%s' exception #%d (autovector: $%x) after [%s]\n", tag(), irqline, vector, message)); + } + } + } + else + { + vector = 11; + LOG(("SH-2 '%s' nmi exception (autovector: $%x) after [%s]\n", tag(), vector, message)); + } + + if (m_isdrc) + { + m_sh2_state->evec = RL( m_sh2_state->vbr + vector * 4 ); + m_sh2_state->evec &= AM; + m_sh2_state->irqsr = m_sh2_state->sr; + + /* set I flags in SR */ + if (irqline > SH2_INT_15) + m_sh2_state->sr = m_sh2_state->sr | I; + else + m_sh2_state->sr = (m_sh2_state->sr & ~I) | (irqline << 4); + +// printf("sh2_exception [%s] irqline %x evec %x save SR %x new SR %x\n", message, irqline, m_sh2_state->evec, m_sh2_state->irqsr, m_sh2_state->sr); + } else { + m_sh2_state->r[15] -= 4; + WL( m_sh2_state->r[15], m_sh2_state->sr ); /* push SR onto stack */ + m_sh2_state->r[15] -= 4; + WL( m_sh2_state->r[15], m_sh2_state->pc ); /* push PC onto stack */ + + /* set I flags in SR */ + if (irqline > SH2_INT_15) + m_sh2_state->sr = m_sh2_state->sr | I; + else + m_sh2_state->sr = (m_sh2_state->sr & ~I) | (irqline << 4); + + /* fetch PC */ + m_sh2_state->pc = RL( m_sh2_state->vbr + vector * 4 ); + } + + if(m_sh2_state->sleep_mode == 1) { m_sh2_state->sleep_mode = 2; } +} + +/* + SH-7021 on-chip device + */ + +void sh2a_device::sh7032_dma_exec(int ch) +{ + const short dma_word_size[4] = { 0, +1, -1, 0 }; + UINT8 rs = (m_dma[ch].chcr >> 8) & 0xf; /**< Resource Select bits */ + if(rs != 0xc) // Auto-Request + { + logerror("Warning: SH7032 DMA enables non auto-request transfer\n"); + return; + } + + // channel enable & master enable + if((m_dma[ch].chcr & 1) == 0 || (m_dmaor & 1) == 0) + return; + + printf("%08x %08x %04x\n",m_dma[ch].sar,m_dma[ch].dar,m_dma[ch].chcr); + UINT8 dm = (m_dma[ch].chcr >> 14) & 3; /**< Destination Address Mode bits */ + UINT8 sm = (m_dma[ch].chcr >> 12) & 3; /**< Source Address Mode bits */ + bool ts = (m_dma[ch].chcr & 8); /**< Transfer Size bit */ + int src_word_size = dma_word_size[sm] * ((ts == true) ? 2 : 1); + int dst_word_size = dma_word_size[dm] * ((ts == true) ? 2 : 1); + UINT32 src_addr = m_dma[ch].sar; + UINT32 dst_addr = m_dma[ch].dar; + UINT32 size_index = m_dma[ch].tcr; + if(size_index == 0) + size_index = 0x10000; + + if(ts == false) + logerror("SH7032: DMA byte mode check\n"); + + for(int index = size_index;index>-1;index--) + { + if(ts == true) + m_program->write_word(dst_addr,m_program->read_word(src_addr)); + else + m_program->write_byte(dst_addr,m_program->read_byte(src_addr)); + + src_addr += src_word_size; + dst_addr += dst_word_size; + } + + m_dma[ch].chcr &= ~1; /**< @todo non-instant DMA */ + printf("%02x %02x %02x %1d\n",sm,dm,rs,ts); +} + +READ32_MEMBER(sh2a_device::dma_sar0_r) +{ + return m_dma[0].sar; +} + +WRITE32_MEMBER(sh2a_device::dma_sar0_w) +{ + COMBINE_DATA(&m_dma[0].sar); +} + +READ32_MEMBER(sh2a_device::dma_dar0_r) +{ + return m_dma[0].dar; +} + +WRITE32_MEMBER(sh2a_device::dma_dar0_w) +{ + COMBINE_DATA(&m_dma[0].dar); +} + +READ16_MEMBER(sh2a_device::dma_tcr0_r) +{ + return m_dma[0].tcr; +} + +WRITE16_MEMBER(sh2a_device::dma_tcr0_w) +{ + //printf("%04x\n",data); + COMBINE_DATA(&m_dma[0].tcr); +} + +READ16_MEMBER(sh2a_device::dma_chcr0_r) +{ + return m_dma[0].chcr; +} + +WRITE16_MEMBER(sh2a_device::dma_chcr0_w) +{ + //printf("%04x CHCR0\n",data); + COMBINE_DATA(&m_dma[0].chcr); + sh7032_dma_exec(0); +} + +READ16_MEMBER(sh2a_device::dmaor_r) +{ + return m_dmaor; +} + +WRITE16_MEMBER(sh2a_device::dmaor_w) +{ + COMBINE_DATA(&m_dmaor); + sh7032_dma_exec(0); +} + +/*! + @brief Dummy debug interface + */ +READ16_MEMBER(sh1_device::sh7032_r) +{ + return m_sh7032_regs[offset]; +} + +/*! + @brief Dummy debug interface + */ +WRITE16_MEMBER(sh1_device::sh7032_w) +{ + COMBINE_DATA(&m_sh7032_regs[offset]); +} + +READ16_MEMBER(sh2a_device::sh7021_r) +{ + return m_sh7021_regs[offset]; +} + +/*! + @brief Dummy debug interface + */ +WRITE16_MEMBER(sh2a_device::sh7021_w) +{ + COMBINE_DATA(&m_sh7021_regs[offset]); +} +#if (defined(__MINGW32__) && (__GNUC__ >= 5)) +#pragma GCC diagnostic pop +#endif diff --git a/src/devices/cpu/sh2/sh2comn.h b/src/devices/cpu/sh2/sh2comn.h new file mode 100644 index 00000000000..79d06547462 --- /dev/null +++ b/src/devices/cpu/sh2/sh2comn.h @@ -0,0 +1,85 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/***************************************************************************** + * + * sh2common.h + * + * SH-2 non-specific components + * + *****************************************************************************/ + +#pragma once + +#ifndef __SH2COMN_H__ +#define __SH2COMN_H__ + + + +// do we use a timer for the DMA, or have it in CPU_EXECUTE +#define USE_TIMER_FOR_DMA + +#include "cpu/drcuml.h" +#include "cpu/drcumlsh.h" + +#define SH2_CODE_XOR(a) ((a) ^ NATIVE_ENDIAN_VALUE_LE_BE(2,0)) + +enum +{ + ICF = 0x00800000, + OCFA = 0x00080000, + OCFB = 0x00040000, + OVF = 0x00020000 +}; + +#define T 0x00000001 +#define S 0x00000002 +#define I 0x000000f0 +#define Q 0x00000100 +#define M 0x00000200 + +#define AM 0xc7ffffff + +#define FLAGS (M|Q|I|S|T) + +#define Rn ((opcode>>8)&15) +#define Rm ((opcode>>4)&15) + +#define CPU_TYPE_SH1 (0) +#define CPU_TYPE_SH2 (1) + +#define REGFLAG_R(n) (1 << (n)) + +/* register flags 1 */ +#define REGFLAG_PR (1 << 0) +#define REGFLAG_MACL (1 << 1) +#define REGFLAG_MACH (1 << 2) +#define REGFLAG_GBR (1 << 3) +#define REGFLAG_VBR (1 << 4) +#define REGFLAG_SR (1 << 5) + +#define CHECK_PENDING_IRQ(message) \ +do { \ + int irq = -1; \ + if (m_sh2_state->pending_irq & (1 << 0)) irq = 0; \ + if (m_sh2_state->pending_irq & (1 << 1)) irq = 1; \ + if (m_sh2_state->pending_irq & (1 << 2)) irq = 2; \ + if (m_sh2_state->pending_irq & (1 << 3)) irq = 3; \ + if (m_sh2_state->pending_irq & (1 << 4)) irq = 4; \ + if (m_sh2_state->pending_irq & (1 << 5)) irq = 5; \ + if (m_sh2_state->pending_irq & (1 << 6)) irq = 6; \ + if (m_sh2_state->pending_irq & (1 << 7)) irq = 7; \ + if (m_sh2_state->pending_irq & (1 << 8)) irq = 8; \ + if (m_sh2_state->pending_irq & (1 << 9)) irq = 9; \ + if (m_sh2_state->pending_irq & (1 << 10)) irq = 10; \ + if (m_sh2_state->pending_irq & (1 << 11)) irq = 11; \ + if (m_sh2_state->pending_irq & (1 << 12)) irq = 12; \ + if (m_sh2_state->pending_irq & (1 << 13)) irq = 13; \ + if (m_sh2_state->pending_irq & (1 << 14)) irq = 14; \ + if (m_sh2_state->pending_irq & (1 << 15)) irq = 15; \ + if ((m_sh2_state->internal_irq_level != -1) && (m_sh2_state->internal_irq_level > irq)) irq = m_sh2_state->internal_irq_level; \ + if (irq >= 0) \ + sh2_exception(message,irq); \ +} while(0) + + +#endif /* __SH2COMN_H__ */ diff --git a/src/devices/cpu/sh2/sh2dasm.c b/src/devices/cpu/sh2/sh2dasm.c new file mode 100644 index 00000000000..e37611b9d28 --- /dev/null +++ b/src/devices/cpu/sh2/sh2dasm.c @@ -0,0 +1,610 @@ +// license:BSD-3-Clause +// copyright-holders:Juergen Buchmueller +#include "emu.h" +#include "debugger.h" +#include "sh2.h" + +#define SIGNX8(x) (((INT32)(x) << 24) >> 24) +#define SIGNX12(x) (((INT32)(x) << 20) >> 20) + +#define Rn ((opcode >> 8) & 15) +#define Rm ((opcode >> 4) & 15) + +static const char *const regname[16] = { + "R0", "R1", "R2", "R3", "R4", "R5", "R6", "R7", + "R8", "R9", "R10","R11","R12","R13","R14","SP" +}; + +static UINT32 op0000(char *buffer, UINT32 pc, UINT16 opcode) +{ + UINT32 flags = 0; + switch(opcode & 0x3f) + { + case 0x02: + sprintf(buffer,"STC SR,%s", regname[Rn]); + break; + case 0x03: + sprintf(buffer,"BSRF %s", regname[Rn]); + break; + case 0x08: + sprintf(buffer,"CLRT"); + break; + case 0x09: + sprintf(buffer,"NOP"); + break; + case 0x0A: + sprintf(buffer,"STS MACH,%s", regname[Rn]); + break; + case 0x0B: + sprintf(buffer,"RTS"); + flags = DASMFLAG_STEP_OUT; + break; + case 0x12: + sprintf(buffer,"STS GBR,%s", regname[Rn]); + break; + case 0x18: + sprintf(buffer,"SETT"); + break; + case 0x19: + sprintf(buffer,"DIV0U"); + break; + case 0x1A: + sprintf(buffer,"STS MACL,%s", regname[Rn]); + break; + case 0x1B: + sprintf(buffer,"SLEEP"); + break; + case 0x22: + sprintf(buffer,"STC VBR,%s", regname[Rn]); + break; + case 0x23: + sprintf(buffer,"BRAF %s", regname[Rn]); + break; + case 0x28: + sprintf(buffer,"CLRMAC"); + break; + case 0x29: + sprintf(buffer,"MOVT %s", regname[Rn]); + break; + case 0x2A: + sprintf(buffer,"STS PR,%s", regname[Rn]); + break; + case 0x2B: + sprintf(buffer,"RTE"); + flags = DASMFLAG_STEP_OUT; + break; + default: + switch(opcode & 15) + { + case 0: + sprintf(buffer, "?????? $%04X", opcode); + break; + case 1: + sprintf(buffer, "?????? $%04X", opcode); + break; + case 2: + sprintf(buffer, "?????? $%04X", opcode); + break; + case 3: + sprintf(buffer, "?????? $%04X", opcode); + break; + case 4: + sprintf(buffer, "MOV.B %s,@(R0,%s)", regname[Rm], regname[Rn]); + break; + case 5: + sprintf(buffer, "MOV.W %s,@(R0,%s)", regname[Rm], regname[Rn]); + break; + case 6: + sprintf(buffer, "MOV.L %s,@(R0,%s)", regname[Rm], regname[Rn]); + break; + case 7: + sprintf(buffer, "MUL.L %s,%s", regname[Rm], regname[Rn]); + break; + case 8: + sprintf(buffer, "?????? $%04X", opcode); + break; + case 9: + sprintf(buffer, "?????? $%04X", opcode); + break; + case 10: + sprintf(buffer, "?????? $%04X", opcode); + break; + case 11: + sprintf(buffer, "?????? $%04X", opcode); + break; + case 12: + sprintf(buffer, "MOV.B @(R0,%s),%s", regname[Rm], regname[Rn]); + break; + case 13: + sprintf(buffer, "MOV.W @(R0,%s),%s", regname[Rm], regname[Rn]); + break; + case 14: + sprintf(buffer, "MOV.L @(R0,%s),%s", regname[Rm], regname[Rn]); + break; + case 15: + sprintf(buffer, "MAC.L @%s+,@%s+", regname[Rn], regname[Rm]); + break; + } + } + return flags; +} + +static UINT32 op0001(char *buffer, UINT32 pc, UINT16 opcode) +{ + sprintf(buffer, "MOV.L %s,@($%02X,%s)", regname[Rm], (opcode & 15) * 4, regname[Rn]); + return 0; +} + +static UINT32 op0010(char *buffer, UINT32 pc, UINT16 opcode) +{ + switch (opcode & 15) + { + case 0: + sprintf(buffer, "MOV.B %s,@%s", regname[Rm], regname[Rn]); + break; + case 1: + sprintf(buffer, "MOV.W %s,@%s", regname[Rm], regname[Rn]); + break; + case 2: + sprintf(buffer, "MOV.L %s,@%s", regname[Rm], regname[Rn]); + break; + case 3: + sprintf(buffer, "?????? $%04X", opcode); + break; + case 4: + sprintf(buffer, "MOV.B %s,@-%s", regname[Rm], regname[Rn]); + break; + case 5: + sprintf(buffer, "MOV.W %s,@-%s", regname[Rm], regname[Rn]); + break; + case 6: + sprintf(buffer, "MOV.L %s,@-%s", regname[Rm], regname[Rn]); + break; + case 7: + sprintf(buffer, "DIV0S %s,%s", regname[Rm], regname[Rn]); + break; + case 8: + sprintf(buffer, "TST %s,%s", regname[Rm], regname[Rn]); + break; + case 9: + sprintf(buffer, "AND %s,%s", regname[Rm], regname[Rn]); + break; + case 10: + sprintf(buffer, "XOR %s,%s", regname[Rm], regname[Rn]); + break; + case 11: + sprintf(buffer, "OR %s,%s", regname[Rm], regname[Rn]); + break; + case 12: + sprintf(buffer, "CMP/STR %s,%s", regname[Rm], regname[Rn]); + break; + case 13: + sprintf(buffer, "XTRCT %s,%s", regname[Rm], regname[Rn]); + break; + case 14: + sprintf(buffer, "MULU.W %s,%s", regname[Rm], regname[Rn]); + break; + case 15: + sprintf(buffer, "MULS.W %s,%s", regname[Rm], regname[Rn]); + break; + } + return 0; +} + +static UINT32 op0011(char *buffer, UINT32 pc, UINT16 opcode) +{ + switch (opcode & 15) + { + case 0: + sprintf(buffer, "CMP/EQ %s,%s", regname[Rm], regname[Rn]); + break; + case 1: + sprintf(buffer, "?????? %s,%s", regname[Rm], regname[Rn]); + break; + case 2: + sprintf(buffer, "CMP/HS %s,%s", regname[Rm], regname[Rn]); + break; + case 3: + sprintf(buffer, "CMP/GE %s,%s", regname[Rm], regname[Rn]); + break; + case 4: + sprintf(buffer, "DIV1 %s,%s", regname[Rm], regname[Rn]); + break; + case 5: + sprintf(buffer, "DMULU.L %s,%s", regname[Rm], regname[Rn]); + break; + case 6: + sprintf(buffer, "CMP/HI %s,%s", regname[Rm], regname[Rn]); + break; + case 7: + sprintf(buffer, "CMP/GT %s,%s", regname[Rm], regname[Rn]); + break; + case 8: + sprintf(buffer, "SUB %s,%s", regname[Rm], regname[Rn]); + break; + case 9: + sprintf(buffer, "?????? %s,%s", regname[Rm], regname[Rn]); + break; + case 10: + sprintf(buffer, "SUBC %s,%s", regname[Rm], regname[Rn]); + break; + case 11: + sprintf(buffer, "SUBV %s,%s", regname[Rm], regname[Rn]); + break; + case 12: + sprintf(buffer, "ADD %s,%s", regname[Rm], regname[Rn]); + break; + case 13: + sprintf(buffer, "DMULS.L %s,%s", regname[Rm], regname[Rn]); + break; + case 14: + sprintf(buffer, "ADDC %s,%s", regname[Rm], regname[Rn]); + break; + case 15: + sprintf(buffer, "ADDV %s,%s", regname[Rm], regname[Rn]); + break; + } + return 0; +} + +static UINT32 op0100(char *buffer, UINT32 pc, UINT16 opcode) +{ + UINT32 flags = 0; + switch(opcode & 0x3F) + { + case 0x00: + sprintf(buffer, "SHLL %s", regname[Rn]); + break; + case 0x01: + sprintf(buffer, "SHLR %s", regname[Rn]); + break; + case 0x02: + sprintf(buffer, "STS.L MACH,@-%s", regname[Rn]); + break; + case 0x03: + sprintf(buffer, "STC.L SR,@-%s", regname[Rn]); + break; + case 0x04: + sprintf(buffer, "ROTL %s", regname[Rn]); + break; + case 0x05: + sprintf(buffer, "ROTR %s", regname[Rn]); + break; + case 0x06: + sprintf(buffer, "LDS.L @%s+,MACH", regname[Rn]); + break; + case 0x07: + sprintf(buffer, "LDC.L @%s+,SR", regname[Rn]); + break; + case 0x08: + sprintf(buffer, "SHLL2 %s", regname[Rn]); + break; + case 0x09: + sprintf(buffer, "SHLR2 %s", regname[Rn]); + break; + case 0x0a: + sprintf(buffer, "LDS %s,MACH", regname[Rn]); + break; + case 0x0b: + sprintf(buffer, "JSR %s", regname[Rn]); + flags = DASMFLAG_STEP_OVER | DASMFLAG_STEP_OVER_EXTRA(1); + break; + case 0x0e: + sprintf(buffer, "LDC %s,SR", regname[Rn]); + break; + case 0x10: + sprintf(buffer, "DT %s", regname[Rn]); + break; + case 0x11: + sprintf(buffer, "CMP/PZ %s", regname[Rn]); + break; + case 0x12: + sprintf(buffer, "STS.L MACL,@-%s", regname[Rn]); + break; + case 0x13: + sprintf(buffer, "STC.L GBR,@-%s", regname[Rn]); + break; + case 0x15: + sprintf(buffer, "CMP/PL %s", regname[Rn]); + break; + case 0x16: + sprintf(buffer, "LDS.L @%s+,MACL", regname[Rn]); + break; + case 0x17: + sprintf(buffer, "LDC.L @%s+,GBR", regname[Rn]); + break; + case 0x18: + sprintf(buffer, "SHLL8 %s", regname[Rn]); + break; + case 0x19: + sprintf(buffer, "SHLR8 %s", regname[Rn]); + break; + case 0x1a: + sprintf(buffer, "LDS %s,MACL", regname[Rn]); + break; + case 0x1b: + sprintf(buffer, "TAS %s", regname[Rn]); + break; + case 0x1e: + sprintf(buffer, "LDC %s,GBR", regname[Rn]); + break; + case 0x20: + sprintf(buffer, "SHAL %s", regname[Rn]); + break; + case 0x21: + sprintf(buffer, "SHAR %s", regname[Rn]); + break; + case 0x22: + sprintf(buffer, "STS.L PR,@-%s", regname[Rn]); + break; + case 0x23: + sprintf(buffer, "STC.L VBR,@-%s", regname[Rn]); + break; + case 0x24: + sprintf(buffer, "ROTCL %s", regname[Rn]); + break; + case 0x25: + sprintf(buffer, "ROTCR %s", regname[Rn]); + break; + case 0x26: + sprintf(buffer, "LDS.L @%s+,PR", regname[Rn]); + break; + case 0x27: + sprintf(buffer, "LDC.L @%s+,VBR", regname[Rn]); + break; + case 0x28: + sprintf(buffer, "SHLL16 %s", regname[Rn]); + break; + case 0x29: + sprintf(buffer, "SHLR16 %s", regname[Rn]); + break; + case 0x2a: + sprintf(buffer, "LDS %s,PR", regname[Rn]); + break; + case 0x2b: + sprintf(buffer, "JMP %s", regname[Rn]); + break; + case 0x2e: + sprintf(buffer, "LDC %s,VBR", regname[Rn]); + break; + default: + if ((opcode & 15) == 15) + sprintf(buffer, "MAC.W @%s+,@%s+", regname[Rm], regname[Rn]); + else + sprintf(buffer, "?????? $%04X", opcode); + } + return flags; +} + +static UINT32 op0101(char *buffer, UINT32 pc, UINT16 opcode) +{ + sprintf(buffer, "MOV.L @($%02X,%s),%s", (opcode & 15) * 4, regname[Rm], regname[Rn]); + return 0; +} + +static UINT32 op0110(char *buffer, UINT32 pc, UINT16 opcode) + +{ + switch(opcode & 0xF) + { + case 0x00: + sprintf(buffer, "MOV.B @%s,%s", regname[Rm], regname[Rn]); + break; + case 0x01: + sprintf(buffer, "MOV.W @%s,%s", regname[Rm], regname[Rn]); + break; + case 0x02: + sprintf(buffer, "MOV.L @%s,%s", regname[Rm], regname[Rn]); + break; + case 0x03: + sprintf(buffer, "MOV %s,%s", regname[Rm], regname[Rn]); + break; + case 0x04: + sprintf(buffer, "MOV.B @%s+,%s", regname[Rm], regname[Rn]); + break; + case 0x05: + sprintf(buffer, "MOV.W @%s+,%s", regname[Rm], regname[Rn]); + break; + case 0x06: + sprintf(buffer, "MOV.L @%s+,%s", regname[Rm], regname[Rn]); + break; + case 0x07: + sprintf(buffer, "NOT %s,%s", regname[Rm], regname[Rn]); + break; + case 0x08: + sprintf(buffer, "SWAP.B %s,%s", regname[Rm], regname[Rn]); + break; + case 0x09: + sprintf(buffer, "SWAP.W %s,%s", regname[Rm], regname[Rn]); + break; + case 0x0a: + sprintf(buffer, "NEGC %s,%s", regname[Rm], regname[Rn]); + break; + case 0x0b: + sprintf(buffer, "NEG %s,%s", regname[Rm], regname[Rn]); + break; + case 0x0c: + sprintf(buffer, "EXTU.B %s,%s", regname[Rm], regname[Rn]); + break; + case 0x0d: + sprintf(buffer, "EXTU.W %s,%s", regname[Rm], regname[Rn]); + break; + case 0x0e: + sprintf(buffer, "EXTS.B %s,%s", regname[Rm], regname[Rn]); + break; + case 0x0f: + sprintf(buffer, "EXTS.W %s,%s", regname[Rm], regname[Rn]); + break; + } + return 0; +} + +static UINT32 op0111(char *buffer, UINT32 pc, UINT16 opcode) +{ + sprintf(buffer, "ADD #$%02X,%s", opcode & 0xff, regname[Rn]); + return 0; +} + +static UINT32 op1000(char *buffer, UINT32 pc, UINT16 opcode) +{ + switch((opcode >> 8) & 15) + { + case 0: + sprintf(buffer, "MOV.B R0,@($%02X,%s)", (opcode & 15), regname[Rm]); + break; + case 1: + sprintf(buffer, "MOV.W R0,@($%02X,%s)", (opcode & 15) * 2, regname[Rm]); + break; + case 4: + sprintf(buffer, "MOV.B @($%02X,%s),R0", (opcode & 15), regname[Rm]); + break; + case 5: + sprintf(buffer, "MOV.W @($%02X,%s),R0", (opcode & 15), regname[Rm]); + break; + case 8: + sprintf(buffer, "CMP/EQ #$%02X,R0", (opcode & 0xff)); + break; + case 9: + sprintf(buffer, "BT $%08X", pc + SIGNX8(opcode & 0xff) * 2 + 2); + break; + case 11: + sprintf(buffer, "BF $%08X", pc + SIGNX8(opcode & 0xff) * 2 + 2); + break; + case 13: + sprintf(buffer, "BTS $%08X", pc + SIGNX8(opcode & 0xff) * 2 + 2); + break; + case 15: + sprintf(buffer, "BFS $%08X", pc + SIGNX8(opcode & 0xff) * 2 + 2); + break; + default : + sprintf(buffer, "invalid $%04X", opcode); + } + return 0; +} + +static UINT32 op1001(char *buffer, UINT32 pc, UINT16 opcode) +{ + sprintf(buffer, "MOV.W @($%04X,PC),%s [%08X]", (opcode & 0xff) * 2, regname[Rn], pc+((opcode & 0xff) * 2)+2); + return 0; +} + +static UINT32 op1010(char *buffer, UINT32 pc, UINT16 opcode) +{ + sprintf(buffer, "BRA $%08X", SIGNX12(opcode & 0xfff) * 2 + pc + 2); + return 0; +} + +static UINT32 op1011(char *buffer, UINT32 pc, UINT16 opcode) +{ + sprintf(buffer, "BSR $%08X", SIGNX12(opcode & 0xfff) * 2 + pc + 2); + return DASMFLAG_STEP_OVER | DASMFLAG_STEP_OVER_EXTRA(1); +} + +static UINT32 op1100(char *buffer, UINT32 pc, UINT16 opcode) +{ + UINT32 flags = 0; + switch((opcode >> 8) & 15) + { + case 0: + sprintf(buffer, "MOV.B R0,@($%02X,GBR)", opcode & 0xff); + break; + case 1: + sprintf(buffer, "MOV.W R0,@($%04X,GBR)", (opcode & 0xff) * 2); + break; + case 2: + sprintf(buffer, "MOV.L R0,@($%04X,GBR)", (opcode & 0xff) * 4); + break; + case 3: + sprintf(buffer, "TRAPA #$%02X", opcode & 0xff); + flags = DASMFLAG_STEP_OVER; + break; + case 4: + sprintf(buffer, "MOV.B @($%02X,GBR),R0", opcode & 0xff); + break; + case 5: + sprintf(buffer, "MOV.W @($%04X,GBR),R0", (opcode & 0xff) * 2); + break; + case 6: + sprintf(buffer, "MOV.L @($%04X,GBR),R0", (opcode & 0xff) * 4); + break; + case 7: + sprintf(buffer, "MOVA @($%04X,PC),R0 [%08X]", (opcode & 0xff) * 4, ((pc + 2) & ~3) + (opcode & 0xff) * 4); + break; + case 8: + sprintf(buffer, "TST #$%02X,R0", opcode & 0xff); + break; + case 9: + sprintf(buffer, "AND #$%02X,R0", opcode & 0xff); + break; + case 10: + sprintf(buffer, "XOR #$%02X,R0", opcode & 0xff); + break; + case 11: + sprintf(buffer, "OR #$%02X,R0", opcode & 0xff); + break; + case 12: + sprintf(buffer, "TST.B #$%02X,@(R0,GBR)", opcode & 0xff); + break; + case 13: + sprintf(buffer, "AND.B #$%02X,@(R0,GBR)", opcode & 0xff); + break; + case 14: + sprintf(buffer, "XOR.B #$%02X,@(R0,GBR)", opcode & 0xff); + break; + case 15: + sprintf(buffer, "OR.B #$%02X,@(R0,GBR)", opcode & 0xff); + break; + } + return flags; +} + +static UINT32 op1101(char *buffer, UINT32 pc, UINT16 opcode) +{ + sprintf(buffer, "MOV.L @($%02X,PC),%s [%08X]", (opcode * 4) & 0xff, regname[Rn], ((pc + 2) & ~3) + (opcode & 0xff) * 4); + return 0; +} + +static UINT32 op1110(char *buffer, UINT32 pc, UINT16 opcode) +{ + sprintf(buffer, "MOV #$%02X,%s", (opcode & 0xff), regname[Rn]); + return 0; +} + +static UINT32 op1111(char *buffer, UINT32 pc, UINT16 opcode) +{ + sprintf(buffer, "unknown $%04X", opcode); + return 0; +} + +unsigned DasmSH2(char *buffer, unsigned pc, UINT16 opcode) +{ + UINT32 flags; + + pc += 2; + + switch((opcode >> 12) & 15) + { + case 0: flags = op0000(buffer,pc,opcode); break; + case 1: flags = op0001(buffer,pc,opcode); break; + case 2: flags = op0010(buffer,pc,opcode); break; + case 3: flags = op0011(buffer,pc,opcode); break; + case 4: flags = op0100(buffer,pc,opcode); break; + case 5: flags = op0101(buffer,pc,opcode); break; + case 6: flags = op0110(buffer,pc,opcode); break; + case 7: flags = op0111(buffer,pc,opcode); break; + case 8: flags = op1000(buffer,pc,opcode); break; + case 9: flags = op1001(buffer,pc,opcode); break; + case 10: flags = op1010(buffer,pc,opcode); break; + case 11: flags = op1011(buffer,pc,opcode); break; + case 12: flags = op1100(buffer,pc,opcode); break; + case 13: flags = op1101(buffer,pc,opcode); break; + case 14: flags = op1110(buffer,pc,opcode); break; + default: flags = op1111(buffer,pc,opcode); break; + } + return 2 | flags | DASMFLAG_SUPPORTED; +} + +CPU_DISASSEMBLE( sh2 ) +{ + return DasmSH2( buffer, pc, (oprom[0] << 8) | oprom[1] ); +} diff --git a/src/devices/cpu/sh2/sh2drc.c b/src/devices/cpu/sh2/sh2drc.c new file mode 100644 index 00000000000..4069f3287c7 --- /dev/null +++ b/src/devices/cpu/sh2/sh2drc.c @@ -0,0 +1,2983 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/*************************************************************************** + + sh2drc.c + Universal machine language-based SH-2 emulator. + +***************************************************************************/ + +#include "emu.h" +#include "debugger.h" +#include "sh2.h" +#include "sh2comn.h" +#include "mconfig.h" + +extern unsigned DasmSH2(char *buffer, unsigned pc, UINT16 opcode); + +using namespace uml; + +/*************************************************************************** + DEBUGGING +***************************************************************************/ + +#define SET_EA (0) // makes slower but "shows work" in the EA fake register like the interpreter + +#define ADDSUBV_DIRECT (0) + +#if SET_EA +#define SETEA(x) UML_MOV(block, mem(&m_sh2_state->ea), ireg(x)) +#else +#define SETEA(x) +#endif + +/*************************************************************************** + CONSTANTS +***************************************************************************/ + +/* map variables */ +#define MAPVAR_PC M0 +#define MAPVAR_CYCLES M1 + +/* exit codes */ +#define EXECUTE_OUT_OF_CYCLES 0 +#define EXECUTE_MISSING_CODE 1 +#define EXECUTE_UNMAPPED_CODE 2 +#define EXECUTE_RESET_CACHE 3 + +#define PROBE_ADDRESS ~0 + + +/*************************************************************************** + MACROS +***************************************************************************/ + +#define R32(reg) m_regmap[reg] + +/*************************************************************************** + INLINE FUNCTIONS +***************************************************************************/ + +/*------------------------------------------------- + epc - compute the exception PC from a + descriptor +-------------------------------------------------*/ + +UINT32 sh2_device::epc(const opcode_desc *desc) +{ + return (desc->flags & OPFLAG_IN_DELAY_SLOT) ? (desc->pc - 1) : desc->pc; +} + +/*------------------------------------------------- + alloc_handle - allocate a handle if not + already allocated +-------------------------------------------------*/ + +void sh2_device::alloc_handle(drcuml_state *drcuml, code_handle **handleptr, const char *name) +{ + if (*handleptr == NULL) + *handleptr = drcuml->handle_alloc(name); +} + +/*------------------------------------------------- + load_fast_iregs - load any fast integer + registers +-------------------------------------------------*/ + +void sh2_device::load_fast_iregs(drcuml_block *block) +{ + int regnum; + + for (regnum = 0; regnum < ARRAY_LENGTH(m_regmap); regnum++) + { + if (m_regmap[regnum].is_int_register()) + { + UML_MOV(block, uml::parameter::make_ireg(m_regmap[regnum].ireg()), mem(&m_sh2_state->r[regnum])); + } + } +} + + +/*------------------------------------------------- + save_fast_iregs - save any fast integer + registers +-------------------------------------------------*/ + +void sh2_device::save_fast_iregs(drcuml_block *block) +{ + int regnum; + + for (regnum = 0; regnum < ARRAY_LENGTH(m_regmap); regnum++) + { + if (m_regmap[regnum].is_int_register()) + { + UML_MOV(block, mem(&m_sh2_state->r[regnum]), uml::parameter::make_ireg(m_regmap[regnum].ireg())); + } + } +} + +/*------------------------------------------------- + cfunc_printf_probe - print the current CPU + state and return +-------------------------------------------------*/ + +static void cfunc_printf_probe(void *param) +{ + ((sh2_device *)param)->func_printf_probe(); +} + +void sh2_device::func_printf_probe() +{ + UINT32 pc = m_sh2_state->pc; + + printf(" PC=%08X r0=%08X r1=%08X r2=%08X\n", + pc, + (UINT32)m_sh2_state->r[0], + (UINT32)m_sh2_state->r[1], + (UINT32)m_sh2_state->r[2]); + printf(" r3=%08X r4=%08X r5=%08X r6=%08X\n", + (UINT32)m_sh2_state->r[3], + (UINT32)m_sh2_state->r[4], + (UINT32)m_sh2_state->r[5], + (UINT32)m_sh2_state->r[6]); + printf(" r7=%08X r8=%08X r9=%08X r10=%08X\n", + (UINT32)m_sh2_state->r[7], + (UINT32)m_sh2_state->r[8], + (UINT32)m_sh2_state->r[9], + (UINT32)m_sh2_state->r[10]); + printf(" r11=%08X r12=%08X r13=%08X r14=%08X\n", + (UINT32)m_sh2_state->r[11], + (UINT32)m_sh2_state->r[12], + (UINT32)m_sh2_state->r[13], + (UINT32)m_sh2_state->r[14]); + printf(" r15=%08X macl=%08X mach=%08X gbr=%08X\n", + (UINT32)m_sh2_state->r[15], + (UINT32)m_sh2_state->macl, + (UINT32)m_sh2_state->mach, + (UINT32)m_sh2_state->gbr); + printf(" evec %x irqsr %x pc=%08x\n", + (UINT32)m_sh2_state->evec, + (UINT32)m_sh2_state->irqsr, (UINT32)m_sh2_state->pc); +} + +/*------------------------------------------------- + cfunc_unimplemented - handler for + unimplemented opcdes +-------------------------------------------------*/ + +static void cfunc_unimplemented(void *param) +{ + ((sh2_device *)param)->func_unimplemented(); +} + +void sh2_device::func_unimplemented() +{ + // set up an invalid opcode exception + m_sh2_state->evec = RL( m_sh2_state->vbr + 4 * 4 ); + m_sh2_state->evec &= AM; + m_sh2_state->irqsr = m_sh2_state->sr; + // claim it's an NMI, because it pretty much is + m_sh2_state->pending_nmi = 1; +} + +/*------------------------------------------------- + cfunc_fastirq - checks for pending IRQs +-------------------------------------------------*/ +static void cfunc_fastirq(void *param) +{ + ((sh2_device *)param)->func_fastirq(); +} + +void sh2_device::func_fastirq() +{ + sh2_exception("fastirq",m_sh2_state->irqline); +} + +/*------------------------------------------------- + cfunc_MAC_W - implementation of MAC_W Rm,Rn +-------------------------------------------------*/ +static void cfunc_MAC_W(void *param) +{ + ((sh2_device *)param)->func_MAC_W(); +} + +void sh2_device::func_MAC_W() +{ + INT32 tempm, tempn, dest, src, ans; + UINT32 templ; + UINT16 opcode; + int n, m; + + // recover the opcode + opcode = m_sh2_state->arg0; + + // extract the operands + n = Rn; + m = Rm; + + tempn = (INT32) RW( m_sh2_state->r[n] ); + m_sh2_state->r[n] += 2; + tempm = (INT32) RW( m_sh2_state->r[m] ); + m_sh2_state->r[m] += 2; + templ = m_sh2_state->macl; + tempm = ((INT32) (short) tempn * (INT32) (short) tempm); + if ((INT32) m_sh2_state->macl >= 0) + dest = 0; + else + dest = 1; + if ((INT32) tempm >= 0) + { + src = 0; + tempn = 0; + } + else + { + src = 1; + tempn = 0xffffffff; + } + src += dest; + m_sh2_state->macl += tempm; + if ((INT32) m_sh2_state->macl >= 0) + ans = 0; + else + ans = 1; + ans += dest; + if (m_sh2_state->sr & S) + { + if (ans == 1) + { + if ((m_cpu_type == CPU_TYPE_SH1) && ((src == 0) || (src == 2))) + { + m_sh2_state->mach |= 0x00000001; + } + + if (src == 0) + m_sh2_state->macl = 0x7fffffff; + if (src == 2) + m_sh2_state->macl = 0x80000000; + } + } + else + { + m_sh2_state->mach += tempn; + if (templ > m_sh2_state->macl) + m_sh2_state->mach += 1; + + // SH-1 has limited precision + if (m_cpu_type == CPU_TYPE_SH1) + { + if ((m_sh2_state->mach & 0x200) == 0) + { + m_sh2_state->mach &= 0x3ff; + } + else + { + m_sh2_state->mach |= 0xfffffc00; + } + } + + + } +} + +/*------------------------------------------------- + cfunc_MAC_L - implementation of MAC_L Rm,Rn +-------------------------------------------------*/ +static void cfunc_MAC_L(void *param) +{ + ((sh2_device *)param)->func_MAC_L(); +} + +void sh2_device::func_MAC_L() +{ + UINT32 RnL, RnH, RmL, RmH, Res0, Res1, Res2; + UINT32 temp0, temp1, temp2, temp3; + INT32 tempm, tempn, fnLmL; + UINT16 opcode; + int n, m; + + // recover the opcode + opcode = m_sh2_state->arg0; + + // extract the operands + n = Rn; + m = Rm; + + tempn = (INT32) RL( m_sh2_state->r[n] ); + m_sh2_state->r[n] += 4; + tempm = (INT32) RL( m_sh2_state->r[m] ); + m_sh2_state->r[m] += 4; + if ((INT32) (tempn ^ tempm) < 0) + fnLmL = -1; + else + fnLmL = 0; + if (tempn < 0) + tempn = 0 - tempn; + if (tempm < 0) + tempm = 0 - tempm; + temp1 = (UINT32) tempn; + temp2 = (UINT32) tempm; + RnL = temp1 & 0x0000ffff; + RnH = (temp1 >> 16) & 0x0000ffff; + RmL = temp2 & 0x0000ffff; + RmH = (temp2 >> 16) & 0x0000ffff; + temp0 = RmL * RnL; + temp1 = RmH * RnL; + temp2 = RmL * RnH; + temp3 = RmH * RnH; + Res2 = 0; + Res1 = temp1 + temp2; + if (Res1 < temp1) + Res2 += 0x00010000; + temp1 = (Res1 << 16) & 0xffff0000; + Res0 = temp0 + temp1; + if (Res0 < temp0) + Res2++; + Res2 = Res2 + ((Res1 >> 16) & 0x0000ffff) + temp3; + if (fnLmL < 0) + { + Res2 = ~Res2; + if (Res0 == 0) + Res2++; + else + Res0 = (~Res0) + 1; + } + if (m_sh2_state->sr & S) + { + Res0 = m_sh2_state->macl + Res0; + if (m_sh2_state->macl > Res0) + Res2++; + Res2 += (m_sh2_state->mach & 0x0000ffff); + if (((INT32) Res2 < 0) && (Res2 < 0xffff8000)) + { + Res2 = 0x00008000; + Res0 = 0x00000000; + } + else if (((INT32) Res2 > 0) && (Res2 > 0x00007fff)) + { + Res2 = 0x00007fff; + Res0 = 0xffffffff; + } + m_sh2_state->mach = Res2; + m_sh2_state->macl = Res0; + } + else + { + Res0 = m_sh2_state->macl + Res0; + if (m_sh2_state->macl > Res0) + Res2++; + Res2 += m_sh2_state->mach; + m_sh2_state->mach = Res2; + m_sh2_state->macl = Res0; + } +} + +/*------------------------------------------------- + cfunc_DIV1 - implementation of DIV1 Rm,Rn +-------------------------------------------------*/ +static void cfunc_DIV1(void *param) +{ + ((sh2_device *)param)->func_DIV1(); +} + +void sh2_device::func_DIV1() +{ + UINT32 tmp0; + UINT32 old_q; + UINT16 opcode; + int n, m; + + // recover the opcode + opcode = m_sh2_state->arg0; + + // extract the operands + n = Rn; + m = Rm; + + old_q = m_sh2_state->sr & Q; + if (0x80000000 & m_sh2_state->r[n]) + m_sh2_state->sr |= Q; + else + m_sh2_state->sr &= ~Q; + + m_sh2_state->r[n] = (m_sh2_state->r[n] << 1) | (m_sh2_state->sr & T); + + if (!old_q) + { + if (!(m_sh2_state->sr & M)) + { + tmp0 = m_sh2_state->r[n]; + m_sh2_state->r[n] -= m_sh2_state->r[m]; + if(!(m_sh2_state->sr & Q)) + if(m_sh2_state->r[n] > tmp0) + m_sh2_state->sr |= Q; + else + m_sh2_state->sr &= ~Q; + else + if(m_sh2_state->r[n] > tmp0) + m_sh2_state->sr &= ~Q; + else + m_sh2_state->sr |= Q; + } + else + { + tmp0 = m_sh2_state->r[n]; + m_sh2_state->r[n] += m_sh2_state->r[m]; + if(!(m_sh2_state->sr & Q)) + { + if(m_sh2_state->r[n] < tmp0) + m_sh2_state->sr &= ~Q; + else + m_sh2_state->sr |= Q; + } + else + { + if(m_sh2_state->r[n] < tmp0) + m_sh2_state->sr |= Q; + else + m_sh2_state->sr &= ~Q; + } + } + } + else + { + if (!(m_sh2_state->sr & M)) + { + tmp0 = m_sh2_state->r[n]; + m_sh2_state->r[n] += m_sh2_state->r[m]; + if(!(m_sh2_state->sr & Q)) + if(m_sh2_state->r[n] < tmp0) + m_sh2_state->sr |= Q; + else + m_sh2_state->sr &= ~Q; + else + if(m_sh2_state->r[n] < tmp0) + m_sh2_state->sr &= ~Q; + else + m_sh2_state->sr |= Q; + } + else + { + tmp0 = m_sh2_state->r[n]; + m_sh2_state->r[n] -= m_sh2_state->r[m]; + if(!(m_sh2_state->sr & Q)) + if(m_sh2_state->r[n] > tmp0) + m_sh2_state->sr &= ~Q; + else + m_sh2_state->sr |= Q; + else + if(m_sh2_state->r[n] > tmp0) + m_sh2_state->sr |= Q; + else + m_sh2_state->sr &= ~Q; + } + } + + tmp0 = (m_sh2_state->sr & (Q | M)); + if((!tmp0) || (tmp0 == 0x300)) /* if Q == M set T else clear T */ + m_sh2_state->sr |= T; + else + m_sh2_state->sr &= ~T; +} + +#if (!ADDSUBV_DIRECT) +/*------------------------------------------------- + cfunc_ADDV - implementation of ADDV Rm,Rn +-------------------------------------------------*/ +static void cfunc_ADDV(void *param) +{ + ((sh2_device *)param)->func_ADDV(); +} + +void sh2_device::func_ADDV() +{ + INT32 dest, src, ans; + UINT16 opcode; + int n, m; + + // recover the opcode + opcode = m_sh2_state->arg0; + + // extract the operands + n = Rn; + m = Rm; + + if ((INT32) m_sh2_state->r[n] >= 0) + dest = 0; + else + dest = 1; + if ((INT32) m_sh2_state->r[m] >= 0) + src = 0; + else + src = 1; + src += dest; + m_sh2_state->r[n] += m_sh2_state->r[m]; + if ((INT32) m_sh2_state->r[n] >= 0) + ans = 0; + else + ans = 1; + ans += dest; + if (src == 0 || src == 2) + { + if (ans == 1) + m_sh2_state->sr |= T; + else + m_sh2_state->sr &= ~T; + } + else + m_sh2_state->sr &= ~T; +} + +/*------------------------------------------------- + cfunc_SUBV - implementation of SUBV Rm,Rn +-------------------------------------------------*/ +static void cfunc_SUBV(void *param) +{ + ((sh2_device *)param)->func_SUBV(); +} + +void sh2_device::func_SUBV() +{ + INT32 dest, src, ans; + UINT16 opcode; + int n, m; + + // recover the opcode + opcode = m_sh2_state->arg0; + + // extract the operands + n = Rn; + m = Rm; + + if ((INT32) m_sh2_state->r[n] >= 0) + dest = 0; + else + dest = 1; + if ((INT32) m_sh2_state->r[m] >= 0) + src = 0; + else + src = 1; + src += dest; + m_sh2_state->r[n] -= m_sh2_state->r[m]; + if ((INT32) m_sh2_state->r[n] >= 0) + ans = 0; + else + ans = 1; + ans += dest; + if (src == 1) + { + if (ans == 1) + m_sh2_state->sr |= T; + else + m_sh2_state->sr &= ~T; + } + else + m_sh2_state->sr &= ~T; +} +#else +void sh2_device::func_ADDV() {} +void sh2_device::func_SUBV() {} +#endif + +/*------------------------------------------------- + code_flush_cache - flush the cache and + regenerate static code +-------------------------------------------------*/ + +void sh2_device::code_flush_cache() +{ + drcuml_state *drcuml = m_drcuml; + + /* empty the transient cache contents */ + drcuml->reset(); + + try + { + /* generate the entry point and out-of-cycles handlers */ + static_generate_nocode_handler(); + static_generate_out_of_cycles(); + static_generate_entry_point(); + + /* add subroutines for memory accesses */ + static_generate_memory_accessor(1, FALSE, "read8", &m_read8); + static_generate_memory_accessor(1, TRUE, "write8", &m_write8); + static_generate_memory_accessor(2, FALSE, "read16", &m_read16); + static_generate_memory_accessor(2, TRUE, "write16", &m_write16); + static_generate_memory_accessor(4, FALSE, "read32", &m_read32); + static_generate_memory_accessor(4, TRUE, "write32", &m_write32); + } + catch (drcuml_block::abort_compilation &) + { + fatalerror("Unable to generate SH2 static code\n"); + } + + m_cache_dirty = FALSE; +} + +/* Execute cycles - returns number of cycles actually run */ +void sh2_device::execute_run_drc() +{ + drcuml_state *drcuml = m_drcuml; + int execute_result; + + // run any active DMAs now +#ifndef USE_TIMER_FOR_DMA + for ( int i = 0; i < m_sh2_state->icount ; i++) + { + for( int dma=0;dma<1;dma++) + { + if (m_dma_timer_active[dma]) + sh2_do_dma(dma); + } + } +#endif + + /* reset the cache if dirty */ + if (m_cache_dirty) + code_flush_cache(); + + /* execute */ + do + { + /* run as much as we can */ + execute_result = drcuml->execute(*m_entry); + + /* if we need to recompile, do it */ + if (execute_result == EXECUTE_MISSING_CODE) + { + code_compile_block(0, m_sh2_state->pc); + } + else if (execute_result == EXECUTE_UNMAPPED_CODE) + { + fatalerror("Attempted to execute unmapped code at PC=%08X\n", m_sh2_state->pc); + } + else if (execute_result == EXECUTE_RESET_CACHE) + { + code_flush_cache(); + } + } while (execute_result != EXECUTE_OUT_OF_CYCLES); +} + +/*------------------------------------------------- + code_compile_block - compile a block of the + given mode at the specified pc +-------------------------------------------------*/ + +void sh2_device::code_compile_block(UINT8 mode, offs_t pc) +{ + drcuml_state *drcuml = m_drcuml; + compiler_state compiler = { 0 }; + const opcode_desc *seqhead, *seqlast; + const opcode_desc *desclist; + int override = FALSE; + drcuml_block *block; + + g_profiler.start(PROFILER_DRC_COMPILE); + + /* get a description of this sequence */ + desclist = m_drcfe->describe_code(pc); + if (drcuml->logging() || drcuml->logging_native()) + log_opcode_desc(drcuml, desclist, 0); + + bool succeeded = false; + while (!succeeded) + { + try + { + /* start the block */ + block = drcuml->begin_block(4096); + + /* loop until we get through all instruction sequences */ + for (seqhead = desclist; seqhead != NULL; seqhead = seqlast->next()) + { + const opcode_desc *curdesc; + UINT32 nextpc; + + /* add a code log entry */ + if (drcuml->logging()) + block->append_comment("-------------------------"); // comment + + /* determine the last instruction in this sequence */ + for (seqlast = seqhead; seqlast != NULL; seqlast = seqlast->next()) + if (seqlast->flags & OPFLAG_END_SEQUENCE) + break; + assert(seqlast != NULL); + + /* if we don't have a hash for this mode/pc, or if we are overriding all, add one */ + if (override || !drcuml->hash_exists(mode, seqhead->pc)) + UML_HASH(block, mode, seqhead->pc); // hash mode,pc + + /* if we already have a hash, and this is the first sequence, assume that we */ + /* are recompiling due to being out of sync and allow future overrides */ + else if (seqhead == desclist) + { + override = TRUE; + UML_HASH(block, mode, seqhead->pc); // hash mode,pc + } + + /* otherwise, redispatch to that fixed PC and skip the rest of the processing */ + else + { + UML_LABEL(block, seqhead->pc | 0x80000000); // label seqhead->pc | 0x80000000 + UML_HASHJMP(block, 0, seqhead->pc, *m_nocode); + // hashjmp ,seqhead->pc,nocode + continue; + } + + /* validate this code block if we're not pointing into ROM */ + if (m_program->get_write_ptr(seqhead->physpc) != NULL) + generate_checksum_block(block, &compiler, seqhead, seqlast); + + /* label this instruction, if it may be jumped to locally */ + if (seqhead->flags & OPFLAG_IS_BRANCH_TARGET) + { + UML_LABEL(block, seqhead->pc | 0x80000000); // label seqhead->pc | 0x80000000 + } + + /* iterate over instructions in the sequence and compile them */ + for (curdesc = seqhead; curdesc != seqlast->next(); curdesc = curdesc->next()) + { + generate_sequence_instruction(block, &compiler, curdesc, 0xffffffff); + } + + /* if we need to return to the start, do it */ + if (seqlast->flags & OPFLAG_RETURN_TO_START) + { + nextpc = pc; + } + /* otherwise we just go to the next instruction */ + else + { + nextpc = seqlast->pc + (seqlast->skipslots + 1) * 2; + } + + /* count off cycles and go there */ + generate_update_cycles(block, &compiler, nextpc, TRUE); // + + /* SH2 has no modes */ + if (seqlast->next() == NULL || seqlast->next()->pc != nextpc) + { + UML_HASHJMP(block, 0, nextpc, *m_nocode); + } + // hashjmp ,nextpc,nocode + } + + /* end the sequence */ + block->end(); + g_profiler.stop(); + succeeded = true; + } + catch (drcuml_block::abort_compilation &) + { + code_flush_cache(); + } + } +} + +/*------------------------------------------------- + static_generate_entry_point - generate a + static entry point +-------------------------------------------------*/ + +void sh2_device::static_generate_entry_point() +{ + drcuml_state *drcuml = m_drcuml; + code_label skip = 1; + drcuml_block *block; + + /* begin generating */ + block = drcuml->begin_block(200); + + /* forward references */ + alloc_handle(drcuml, &m_nocode, "nocode"); + alloc_handle(drcuml, &m_write32, "write32"); // necessary? + alloc_handle(drcuml, &m_entry, "entry"); + UML_HANDLE(block, *m_entry); // handle entry + + /* load fast integer registers */ + load_fast_iregs(block); + + /* check for interrupts */ + UML_MOV(block, mem(&m_sh2_state->irqline), 0xffffffff); // mov irqline, #-1 + UML_CMP(block, mem(&m_sh2_state->pending_nmi), 0); // cmp pending_nmi, #0 + UML_JMPc(block, COND_Z, skip+2); // jz skip+2 + + UML_MOV(block, mem(&m_sh2_state->pending_nmi), 0); // zap pending_nmi + UML_JMP(block, skip+1); // and then go take it (evec is already set) + + UML_LABEL(block, skip+2); // skip+2: + UML_MOV(block, mem(&m_sh2_state->evec), 0xffffffff); // mov evec, -1 + UML_MOV(block, I0, 0xffffffff); // mov r0, -1 (r0 = irq) + UML_AND(block, I1, I0, 0xffff); // and r1, 0xffff + + UML_LZCNT(block, I1, mem(&m_sh2_state->pending_irq)); // lzcnt r1, r1 + UML_CMP(block, I1, 32); // cmp r1, #32 + UML_JMPc(block, COND_Z, skip+4); // jz skip+4 + + UML_SUB(block, mem(&m_sh2_state->irqline), 31, I1); // sub irqline, #31, r1 + + UML_LABEL(block, skip+4); // skip+4: + UML_CMP(block, mem(&m_sh2_state->internal_irq_level), 0xffffffff); // cmp internal_irq_level, #-1 + UML_JMPc(block, COND_Z, skip+3); // jz skip+3 + UML_CMP(block, mem(&m_sh2_state->internal_irq_level), mem(&m_sh2_state->irqline)); // cmp internal_irq_level, irqline + UML_JMPc(block, COND_LE, skip+3); // jle skip+3 + + UML_MOV(block, mem(&m_sh2_state->irqline), mem(&m_sh2_state->internal_irq_level)); // mov r0, internal_irq_level + + UML_LABEL(block, skip+3); // skip+3: + UML_CMP(block, mem(&m_sh2_state->irqline), 0xffffffff); // cmp irqline, #-1 + UML_JMPc(block, COND_Z, skip+1); // jz skip+1 + UML_CALLC(block, cfunc_fastirq, this); // callc fastirq + + UML_LABEL(block, skip+1); // skip+1: + + UML_CMP(block, mem(&m_sh2_state->evec), 0xffffffff); // cmp evec, 0xffffffff + UML_JMPc(block, COND_Z, skip); // jz skip + + UML_SUB(block, R32(15), R32(15), 4); // sub R15, R15, #4 + UML_MOV(block, I0, R32(15)); // mov r0, R15 + UML_MOV(block, I1, mem(&m_sh2_state->irqsr)); // mov r1, irqsr + UML_CALLH(block, *m_write32); // call write32 + + UML_SUB(block, R32(15), R32(15), 4); // sub R15, R15, #4 + UML_MOV(block, I0, R32(15)); // mov r0, R15 + UML_MOV(block, I1, mem(&m_sh2_state->pc)); // mov r1, pc + UML_CALLH(block, *m_write32); // call write32 + + UML_MOV(block, mem(&m_sh2_state->pc), mem(&m_sh2_state->evec)); // mov pc, evec + + UML_LABEL(block, skip); // skip: + + /* generate a hash jump via the current mode and PC */ + UML_HASHJMP(block, 0, mem(&m_sh2_state->pc), *m_nocode); // hashjmp ,,nocode + + block->end(); +} + +/*------------------------------------------------- + static_generate_nocode_handler - generate an + exception handler for "out of code" +-------------------------------------------------*/ + +void sh2_device::static_generate_nocode_handler() +{ + drcuml_state *drcuml = m_drcuml; + drcuml_block *block; + + /* begin generating */ + block = drcuml->begin_block(10); + + /* generate a hash jump via the current mode and PC */ + alloc_handle(drcuml, &m_nocode, "nocode"); + UML_HANDLE(block, *m_nocode); // handle nocode + UML_GETEXP(block, I0); // getexp i0 + UML_MOV(block, mem(&m_sh2_state->pc), I0); // mov [pc],i0 + save_fast_iregs(block); + UML_EXIT(block, EXECUTE_MISSING_CODE); // exit EXECUTE_MISSING_CODE + + block->end(); +} + + +/*------------------------------------------------- + static_generate_out_of_cycles - generate an + out of cycles exception handler +-------------------------------------------------*/ + +void sh2_device::static_generate_out_of_cycles() +{ + drcuml_state *drcuml = m_drcuml; + drcuml_block *block; + + /* begin generating */ + block = drcuml->begin_block(10); + + /* generate a hash jump via the current mode and PC */ + alloc_handle(drcuml, &m_out_of_cycles, "out_of_cycles"); + UML_HANDLE(block, *m_out_of_cycles); // handle out_of_cycles + UML_GETEXP(block, I0); // getexp i0 + UML_MOV(block, mem(&m_sh2_state->pc), I0); // mov ,i0 + save_fast_iregs(block); + UML_EXIT(block, EXECUTE_OUT_OF_CYCLES); // exit EXECUTE_OUT_OF_CYCLES + + block->end(); +} + +/*------------------------------------------------------------------ + static_generate_memory_accessor +------------------------------------------------------------------*/ + +void sh2_device::static_generate_memory_accessor(int size, int iswrite, const char *name, code_handle **handleptr) +{ + /* on entry, address is in I0; data for writes is in I1 */ + /* on exit, read result is in I0 */ + /* routine trashes I0 */ + drcuml_state *drcuml = m_drcuml; + drcuml_block *block; + int label = 1; + + /* begin generating */ + block = drcuml->begin_block(1024); + + /* add a global entry for this */ + alloc_handle(drcuml, handleptr, name); + UML_HANDLE(block, **handleptr); // handle *handleptr + + // with internal handlers this becomes easier. + // if addr < 0x40000000 AND it with AM and do the read/write, else just do the read/write + UML_TEST(block, I0, 0x80000000); // test r0, #0x80000000 + UML_JMPc(block, COND_NZ, label); // if high bit is set, don't mask + + UML_CMP(block, I0, 0x40000000); // cmp #0x40000000, r0 + UML_JMPc(block, COND_AE, label); // bae label + + UML_AND(block, I0, I0, AM); // and r0, r0, #AM (0xc7ffffff) + + UML_LABEL(block, label++); // label: + + for (int ramnum = 0; ramnum < SH2_MAX_FASTRAM; ramnum++) + { + if (m_fastram[ramnum].base != NULL && (!iswrite || !m_fastram[ramnum].readonly)) + { + void *fastbase = (UINT8 *)m_fastram[ramnum].base - m_fastram[ramnum].start; + UINT32 skip = label++; + if (m_fastram[ramnum].end != 0xffffffff) + { + UML_CMP(block, I0, m_fastram[ramnum].end); // cmp i0,end + UML_JMPc(block, COND_A, skip); // ja skip + } + if (m_fastram[ramnum].start != 0x00000000) + { + UML_CMP(block, I0, m_fastram[ramnum].start);// cmp i0,fastram_start + UML_JMPc(block, COND_B, skip); // jb skip + } + + if (!iswrite) + { + if (size == 1) + { + UML_XOR(block, I0, I0, BYTE4_XOR_BE(0)); + UML_LOAD(block, I0, fastbase, I0, SIZE_BYTE, SCALE_x1); // load i0,fastbase,i0,byte + } + else if (size == 2) + { + UML_XOR(block, I0, I0, WORD_XOR_BE(0)); + UML_LOAD(block, I0, fastbase, I0, SIZE_WORD, SCALE_x1); // load i0,fastbase,i0,word_x1 + } + else if (size == 4) + { + UML_LOAD(block, I0, fastbase, I0, SIZE_DWORD, SCALE_x1); // load i0,fastbase,i0,dword_x1 + } + UML_RET(block); // ret + } + else + { + if (size == 1) + { + UML_XOR(block, I0, I0, BYTE4_XOR_BE(0)); + UML_STORE(block, fastbase, I0, I1, SIZE_BYTE, SCALE_x1);// store fastbase,i0,i1,byte + } + else if (size == 2) + { + UML_XOR(block, I0, I0, WORD_XOR_BE(0)); + UML_STORE(block, fastbase, I0, I1, SIZE_WORD, SCALE_x1);// store fastbase,i0,i1,word_x1 + } + else if (size == 4) + { + UML_STORE(block, fastbase, I0, I1, SIZE_DWORD, SCALE_x1); // store fastbase,i0,i1,dword_x1 + } + UML_RET(block); // ret + } + + UML_LABEL(block, skip); // skip: + } + } + + if (iswrite) + { + switch (size) + { + case 1: + UML_WRITE(block, I0, I1, SIZE_BYTE, SPACE_PROGRAM); // write r0, r1, program_byte + break; + + case 2: + UML_WRITE(block, I0, I1, SIZE_WORD, SPACE_PROGRAM); // write r0, r1, program_word + break; + + case 4: + UML_WRITE(block, I0, I1, SIZE_DWORD, SPACE_PROGRAM); // write r0, r1, program_dword + break; + } + } + else + { + switch (size) + { + case 1: + UML_READ(block, I0, I0, SIZE_BYTE, SPACE_PROGRAM); // read r0, program_byte + break; + + case 2: + UML_READ(block, I0, I0, SIZE_WORD, SPACE_PROGRAM); // read r0, program_word + break; + + case 4: + UML_READ(block, I0, I0, SIZE_DWORD, SPACE_PROGRAM); // read r0, program_dword + break; + } + } + + UML_RET(block); // ret + + block->end(); +} + +/*------------------------------------------------- + log_desc_flags_to_string - generate a string + representing the instruction description + flags +-------------------------------------------------*/ + +const char *sh2_device::log_desc_flags_to_string(UINT32 flags) +{ + static char tempbuf[30]; + char *dest = tempbuf; + + /* branches */ + if (flags & OPFLAG_IS_UNCONDITIONAL_BRANCH) + *dest++ = 'U'; + else if (flags & OPFLAG_IS_CONDITIONAL_BRANCH) + *dest++ = 'C'; + else + *dest++ = '.'; + + /* intrablock branches */ + *dest++ = (flags & OPFLAG_INTRABLOCK_BRANCH) ? 'i' : '.'; + + /* branch targets */ + *dest++ = (flags & OPFLAG_IS_BRANCH_TARGET) ? 'B' : '.'; + + /* delay slots */ + *dest++ = (flags & OPFLAG_IN_DELAY_SLOT) ? 'D' : '.'; + + /* exceptions */ + if (flags & OPFLAG_WILL_CAUSE_EXCEPTION) + *dest++ = 'E'; + else if (flags & OPFLAG_CAN_CAUSE_EXCEPTION) + *dest++ = 'e'; + else + *dest++ = '.'; + + /* read/write */ + if (flags & OPFLAG_READS_MEMORY) + *dest++ = 'R'; + else if (flags & OPFLAG_WRITES_MEMORY) + *dest++ = 'W'; + else + *dest++ = '.'; + + /* TLB validation */ + *dest++ = (flags & OPFLAG_VALIDATE_TLB) ? 'V' : '.'; + + /* TLB modification */ + *dest++ = (flags & OPFLAG_MODIFIES_TRANSLATION) ? 'T' : '.'; + + /* redispatch */ + *dest++ = (flags & OPFLAG_REDISPATCH) ? 'R' : '.'; + return tempbuf; +} + + +/*------------------------------------------------- + log_register_list - log a list of GPR registers +-------------------------------------------------*/ + +void sh2_device::log_register_list(drcuml_state *drcuml, const char *string, const UINT32 *reglist, const UINT32 *regnostarlist) +{ + int count = 0; + int regnum; + + /* skip if nothing */ + if (reglist[0] == 0 && reglist[1] == 0 && reglist[2] == 0) + return; + + drcuml->log_printf("[%s:", string); + + for (regnum = 0; regnum < 16; regnum++) + { + if (reglist[0] & REGFLAG_R(regnum)) + { + drcuml->log_printf("%sr%d", (count++ == 0) ? "" : ",", regnum); + if (regnostarlist != NULL && !(regnostarlist[0] & REGFLAG_R(regnum))) + drcuml->log_printf("*"); + } + } + + if (reglist[1] & REGFLAG_PR) + { + drcuml->log_printf("%spr", (count++ == 0) ? "" : ","); + if (regnostarlist != NULL && !(regnostarlist[1] & REGFLAG_PR)) + drcuml->log_printf("*"); + } + + if (reglist[1] & REGFLAG_SR) + { + drcuml->log_printf("%ssr", (count++ == 0) ? "" : ","); + if (regnostarlist != NULL && !(regnostarlist[1] & REGFLAG_SR)) + drcuml->log_printf("*"); + } + + if (reglist[1] & REGFLAG_MACL) + { + drcuml->log_printf("%smacl", (count++ == 0) ? "" : ","); + if (regnostarlist != NULL && !(regnostarlist[1] & REGFLAG_MACL)) + drcuml->log_printf("*"); + } + + if (reglist[1] & REGFLAG_MACH) + { + drcuml->log_printf("%smach", (count++ == 0) ? "" : ","); + if (regnostarlist != NULL && !(regnostarlist[1] & REGFLAG_MACH)) + drcuml->log_printf("*"); + } + + if (reglist[1] & REGFLAG_GBR) + { + drcuml->log_printf("%sgbr", (count++ == 0) ? "" : ","); + if (regnostarlist != NULL && !(regnostarlist[1] & REGFLAG_GBR)) + drcuml->log_printf("*"); + } + + if (reglist[1] & REGFLAG_VBR) + { + drcuml->log_printf("%svbr", (count++ == 0) ? "" : ","); + if (regnostarlist != NULL && !(regnostarlist[1] & REGFLAG_VBR)) + drcuml->log_printf("*"); + } + + drcuml->log_printf("] "); +} + +/*------------------------------------------------- + log_opcode_desc - log a list of descriptions +-------------------------------------------------*/ + +void sh2_device::log_opcode_desc(drcuml_state *drcuml, const opcode_desc *desclist, int indent) +{ + /* open the file, creating it if necessary */ + if (indent == 0) + drcuml->log_printf("\nDescriptor list @ %08X\n", desclist->pc); + + /* output each descriptor */ + for ( ; desclist != NULL; desclist = desclist->next()) + { + char buffer[100]; + + /* disassemle the current instruction and output it to the log */ + if (drcuml->logging() || drcuml->logging_native()) + { + if (desclist->flags & OPFLAG_VIRTUAL_NOOP) + strcpy(buffer, ""); + else + DasmSH2(buffer, desclist->pc, desclist->opptr.w[0]); + } + else + strcpy(buffer, "???"); + drcuml->log_printf("%08X [%08X] t:%08X f:%s: %-30s", desclist->pc, desclist->physpc, desclist->targetpc, log_desc_flags_to_string(desclist->flags), buffer); + + /* output register states */ + log_register_list(drcuml, "use", desclist->regin, NULL); + log_register_list(drcuml, "mod", desclist->regout, desclist->regreq); + drcuml->log_printf("\n"); + + /* if we have a delay slot, output it recursively */ + if (desclist->delay.first() != NULL) + log_opcode_desc(drcuml, desclist->delay.first(), indent + 1); + + /* at the end of a sequence add a dividing line */ + if (desclist->flags & OPFLAG_END_SEQUENCE) + drcuml->log_printf("-----\n"); + } +} + +/*------------------------------------------------- + log_add_disasm_comment - add a comment + including disassembly of an SH2 instruction +-------------------------------------------------*/ + +void sh2_device::log_add_disasm_comment(drcuml_block *block, UINT32 pc, UINT32 op) +{ + if (m_drcuml->logging()) + { + char buffer[100]; + DasmSH2(buffer, pc, op); + block->append_comment("%08X: %s", pc, buffer); // comment + } +} + +/*------------------------------------------------- + generate_update_cycles - generate code to + subtract cycles from the icount and generate + an exception if out +-------------------------------------------------*/ +void sh2_device::generate_update_cycles(drcuml_block *block, compiler_state *compiler, uml::parameter param, int allow_exception) +{ + /* check full interrupts if pending */ + if (compiler->checkints) + { + code_label skip = compiler->labelnum++; + + compiler->checkints = FALSE; + compiler->labelnum += 4; + + /* check for interrupts */ + UML_MOV(block, mem(&m_sh2_state->irqline), 0xffffffff); // mov irqline, #-1 + UML_CMP(block, mem(&m_sh2_state->pending_nmi), 0); // cmp pending_nmi, #0 + UML_JMPc(block, COND_Z, skip+2); // jz skip+2 + + UML_MOV(block, mem(&m_sh2_state->pending_nmi), 0); // zap pending_nmi + UML_JMP(block, skip+1); // and then go take it (evec is already set) + + UML_LABEL(block, skip+2); // skip+2: + UML_MOV(block, mem(&m_sh2_state->evec), 0xffffffff); // mov evec, -1 + UML_MOV(block, I0, 0xffffffff); // mov r0, -1 (r0 = irq) + UML_AND(block, I1, I0, 0xffff); // and r1, r0, 0xffff + + UML_LZCNT(block, I1, mem(&m_sh2_state->pending_irq)); // lzcnt r1, pending_irq + UML_CMP(block, I1, 32); // cmp r1, #32 + UML_JMPc(block, COND_Z, skip+4); // jz skip+4 + + UML_SUB(block, mem(&m_sh2_state->irqline), 31, I1); // sub irqline, #31, r1 + + UML_LABEL(block, skip+4); // skip+4: + UML_CMP(block, mem(&m_sh2_state->internal_irq_level), 0xffffffff); // cmp internal_irq_level, #-1 + UML_JMPc(block, COND_Z, skip+3); // jz skip+3 + UML_CMP(block, mem(&m_sh2_state->internal_irq_level), mem(&m_sh2_state->irqline)); // cmp internal_irq_level, irqline + UML_JMPc(block, COND_LE, skip+3); // jle skip+3 + + UML_MOV(block, mem(&m_sh2_state->irqline), mem(&m_sh2_state->internal_irq_level)); // mov r0, internal_irq_level + + UML_LABEL(block, skip+3); // skip+3: + UML_CMP(block, mem(&m_sh2_state->irqline), 0xffffffff); // cmp irqline, #-1 + UML_JMPc(block, COND_Z, skip+1); // jz skip+1 + UML_CALLC(block, cfunc_fastirq, this); // callc fastirq + + UML_LABEL(block, skip+1); // skip+1: + UML_CMP(block, mem(&m_sh2_state->evec), 0xffffffff); // cmp evec, 0xffffffff + UML_JMPc(block, COND_Z, skip); // jz skip + + UML_SUB(block, R32(15), R32(15), 4); // sub R15, R15, #4 + UML_MOV(block, I0, R32(15)); // mov r0, R15 + UML_MOV(block, I1, mem(&m_sh2_state->irqsr)); // mov r1, irqsr + UML_CALLH(block, *m_write32); // call write32 + + UML_SUB(block, R32(15), R32(15), 4); // sub R15, R15, #4 + UML_MOV(block, I0, R32(15)); // mov r0, R15 + UML_MOV(block, I1, param); // mov r1, nextpc + UML_CALLH(block, *m_write32); // call write32 + + UML_HASHJMP(block, 0, mem(&m_sh2_state->evec), *m_nocode); // hashjmp m_sh2_state->evec + + UML_LABEL(block, skip); // skip: + } + + /* account for cycles */ + if (compiler->cycles > 0) + { + UML_SUB(block, mem(&m_sh2_state->icount), mem(&m_sh2_state->icount), MAPVAR_CYCLES); // sub icount,icount,cycles + UML_MAPVAR(block, MAPVAR_CYCLES, 0); // mapvar cycles,0 + if (allow_exception) + UML_EXHc(block, COND_S, *m_out_of_cycles, param); + // exh out_of_cycles,nextpc + } + compiler->cycles = 0; +} + +/*------------------------------------------------- + generate_checksum_block - generate code to + validate a sequence of opcodes +-------------------------------------------------*/ + +void sh2_device::generate_checksum_block(drcuml_block *block, compiler_state *compiler, const opcode_desc *seqhead, const opcode_desc *seqlast) +{ + const opcode_desc *curdesc; + if (m_drcuml->logging()) + block->append_comment("[Validation for %08X]", seqhead->pc); // comment + + /* loose verify or single instruction: just compare and fail */ + if (!(m_drcoptions & SH2DRC_STRICT_VERIFY) || seqhead->next() == NULL) + { + if (!(seqhead->flags & OPFLAG_VIRTUAL_NOOP)) + { + void *base = m_direct->read_ptr(seqhead->physpc, SH2_CODE_XOR(0)); + UML_LOAD(block, I0, base, 0, SIZE_WORD, SCALE_x2); // load i0,base,word + UML_CMP(block, I0, seqhead->opptr.w[0]); // cmp i0,*opptr + UML_EXHc(block, COND_NE, *m_nocode, epc(seqhead)); // exne nocode,seqhead->pc + } + } + + /* full verification; sum up everything */ + else + { +#if 0 + for (curdesc = seqhead->next(); curdesc != seqlast->next(); curdesc = curdesc->next()) + if (!(curdesc->flags & OPFLAG_VIRTUAL_NOOP)) + { + base = m_direct->read_ptr(curdesc->physpc, SH2_CODE_XOR(0)); + UML_LOAD(block, I0, curdesc->opptr.w, 0, SIZE_WORD, SCALE_x2); // load i0,*opptr,0,word + UML_CMP(block, I0, curdesc->opptr.w[0]); // cmp i0,*opptr + UML_EXHc(block, COND_NE, *m_nocode, epc(seqhead)); // exne nocode,seqhead->pc + } +#else + UINT32 sum = 0; + void *base = m_direct->read_ptr(seqhead->physpc, SH2_CODE_XOR(0)); + UML_LOAD(block, I0, base, 0, SIZE_WORD, SCALE_x4); // load i0,base,word + sum += seqhead->opptr.w[0]; + for (curdesc = seqhead->next(); curdesc != seqlast->next(); curdesc = curdesc->next()) + if (!(curdesc->flags & OPFLAG_VIRTUAL_NOOP)) + { + base = m_direct->read_ptr(curdesc->physpc, SH2_CODE_XOR(0)); + UML_LOAD(block, I1, base, 0, SIZE_WORD, SCALE_x2); // load i1,*opptr,word + UML_ADD(block, I0, I0, I1); // add i0,i0,i1 + sum += curdesc->opptr.w[0]; + } + UML_CMP(block, I0, sum); // cmp i0,sum + UML_EXHc(block, COND_NE, *m_nocode, epc(seqhead)); // exne nocode,seqhead->pc +#endif + } +} + + +/*------------------------------------------------- + generate_sequence_instruction - generate code + for a single instruction in a sequence +-------------------------------------------------*/ + +void sh2_device::generate_sequence_instruction(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, UINT32 ovrpc) +{ + offs_t expc; + + /* add an entry for the log */ + if (m_drcuml->logging() && !(desc->flags & OPFLAG_VIRTUAL_NOOP)) + log_add_disasm_comment(block, desc->pc, desc->opptr.w[0]); + + /* set the PC map variable */ + expc = (desc->flags & OPFLAG_IN_DELAY_SLOT) ? desc->pc - 1 : desc->pc; + UML_MAPVAR(block, MAPVAR_PC, expc); // mapvar PC,expc + + /* accumulate total cycles */ + compiler->cycles += desc->cycles; + + /* update the icount map variable */ + UML_MAPVAR(block, MAPVAR_CYCLES, compiler->cycles); // mapvar CYCLES,compiler->cycles + + /* if we want a probe, add it here */ + if (desc->pc == PROBE_ADDRESS) + { + UML_MOV(block, mem(&m_sh2_state->pc), desc->pc); // mov [pc],desc->pc + UML_CALLC(block, cfunc_printf_probe, this); // callc cfunc_printf_probe,sh2 + } + + /* if we are debugging, call the debugger */ + if ((machine().debug_flags & DEBUG_FLAG_ENABLED) != 0) + { + UML_MOV(block, mem(&m_sh2_state->pc), desc->pc); // mov [pc],desc->pc + save_fast_iregs(block); + UML_DEBUG(block, desc->pc); // debug desc->pc + } + else // not debug, see what other reasons there are for flushing the PC + { + if (m_drcoptions & SH2DRC_FLUSH_PC) // always flush? + { + UML_MOV(block, mem(&m_sh2_state->pc), desc->pc); // mov m_sh2_state->pc, desc->pc + } + else // check for driver-selected flushes + { + int pcflush; + + for (pcflush = 0; pcflush < m_pcfsel; pcflush++) + { + if (desc->pc == m_pcflushes[pcflush]) + { + UML_MOV(block, mem(&m_sh2_state->pc), desc->pc); // mov m_sh2_state->pc, desc->pc + } + } + } + } + + + /* if we hit an unmapped address, fatal error */ + if (desc->flags & OPFLAG_COMPILER_UNMAPPED) + { + UML_MOV(block, mem(&m_sh2_state->pc), desc->pc); // mov [pc],desc->pc + save_fast_iregs(block); + UML_EXIT(block, EXECUTE_UNMAPPED_CODE); // exit EXECUTE_UNMAPPED_CODE + } + + /* if this is an invalid opcode, die */ + if (desc->flags & OPFLAG_INVALID_OPCODE) + { + fatalerror("SH2DRC: invalid opcode!\n"); + } + + /* otherwise, unless this is a virtual no-op, it's a regular instruction */ + else if (!(desc->flags & OPFLAG_VIRTUAL_NOOP)) + { + /* compile the instruction */ + if (!generate_opcode(block, compiler, desc, ovrpc)) + { + // handle an illegal op + UML_MOV(block, mem(&m_sh2_state->pc), desc->pc); // mov [pc],desc->pc + UML_MOV(block, mem(&m_sh2_state->arg0), desc->opptr.w[0]); // mov [arg0],opcode + UML_CALLC(block, cfunc_unimplemented, this); // callc cfunc_unimplemented + } + } +} + +/*------------------------------------------------------------------ + generate_delay_slot +------------------------------------------------------------------*/ + +void sh2_device::generate_delay_slot(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, UINT32 ovrpc) +{ + compiler_state compiler_temp = *compiler; + + /* compile the delay slot using temporary compiler state */ + assert(desc->delay.first() != NULL); + generate_sequence_instruction(block, &compiler_temp, desc->delay.first(), ovrpc); // + + /* update the label */ + compiler->labelnum = compiler_temp.labelnum; +} + +/*------------------------------------------------- + generate_opcode - generate code for a specific + opcode +-------------------------------------------------*/ + +int sh2_device::generate_opcode(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, UINT32 ovrpc) +{ + UINT32 scratch, scratch2; + INT32 disp; + UINT16 opcode = desc->opptr.w[0]; + UINT8 opswitch = opcode >> 12; + int in_delay_slot = ((desc->flags & OPFLAG_IN_DELAY_SLOT) != 0); + + switch (opswitch) + { + case 0: + return generate_group_0(block, compiler, desc, opcode, in_delay_slot, ovrpc); + + case 1: // MOVLS4 + scratch = (opcode & 0x0f) * 4; + UML_ADD(block, I0, R32(Rn), scratch); // add r0, Rn, scratch + UML_MOV(block, I1, R32(Rm)); // mov r1, Rm + SETEA(0); // set ea for debug + UML_CALLH(block, *m_write32); + + if (!in_delay_slot) + generate_update_cycles(block, compiler, desc->pc + 2, TRUE); + return TRUE; + + case 2: + return generate_group_2(block, compiler, desc, opcode, in_delay_slot, ovrpc); + case 3: + return generate_group_3(block, compiler, desc, opcode, ovrpc); + case 4: + return generate_group_4(block, compiler, desc, opcode, in_delay_slot, ovrpc); + + case 5: // MOVLL4 + scratch = (opcode & 0x0f) * 4; + UML_ADD(block, I0, R32(Rm), scratch); // add r0, Rm, scratch + SETEA(0); // set ea for debug + UML_CALLH(block, *m_read32); // call read32 + UML_MOV(block, R32(Rn), I0); // mov Rn, r0 + + if (!in_delay_slot) + generate_update_cycles(block, compiler, desc->pc + 2, TRUE); + return TRUE; + + case 6: + return generate_group_6(block, compiler, desc, opcode, in_delay_slot, ovrpc); + + case 7: // ADDI + scratch = opcode & 0xff; + scratch2 = (UINT32)(INT32)(INT16)(INT8)scratch; + UML_ADD(block, R32(Rn), R32(Rn), scratch2); // add Rn, Rn, scratch2 + return TRUE; + + case 8: + return generate_group_8(block, compiler, desc, opcode, in_delay_slot, ovrpc); + + case 9: // MOVWI + if (ovrpc == 0xffffffff) + { + scratch = (desc->pc + 2) + ((opcode & 0xff) * 2) + 2; + } + else + { + scratch = (ovrpc + 2) + ((opcode & 0xff) * 2) + 2; + } + + if (m_drcoptions & SH2DRC_STRICT_PCREL) + { + UML_MOV(block, I0, scratch); // mov r0, scratch + SETEA(0); // set ea for debug + UML_CALLH(block, *m_read16); // read16(r0, r1) + UML_SEXT(block, R32(Rn), I0, SIZE_WORD); // sext Rn, r0, WORD + } + else + { + scratch2 = (UINT32)(INT32)(INT16) RW(scratch); + UML_MOV(block, R32(Rn), scratch2); // mov Rn, scratch2 + } + + if (!in_delay_slot) + generate_update_cycles(block, compiler, desc->pc + 2, TRUE); + return TRUE; + + case 10: // BRA + disp = ((INT32)opcode << 20) >> 20; + m_sh2_state->ea = (desc->pc + 2) + disp * 2 + 2; // m_sh2_state->ea = pc+4 + disp*2 + 2 + + generate_delay_slot(block, compiler, desc, m_sh2_state->ea-2); + + generate_update_cycles(block, compiler, m_sh2_state->ea, TRUE); // + UML_HASHJMP(block, 0, m_sh2_state->ea, *m_nocode); // hashjmp m_sh2_state->ea + return TRUE; + + case 11: // BSR + // panicstr @ 403da22 relies on the delay slot clobbering the PR set by a BSR, so + // do this before running the delay slot + UML_ADD(block, mem(&m_sh2_state->pr), desc->pc, 4); // add m_pr, desc->pc, #4 (skip the current insn & delay slot) + + disp = ((INT32)opcode << 20) >> 20; + m_sh2_state->ea = (desc->pc + 2) + disp * 2 + 2; // m_sh2_state->ea = pc+4 + disp*2 + 2 + + generate_delay_slot(block, compiler, desc, m_sh2_state->ea-2); + + generate_update_cycles(block, compiler, m_sh2_state->ea, TRUE); // + UML_HASHJMP(block, 0, m_sh2_state->ea, *m_nocode); // hashjmp m_sh2_state->ea + return TRUE; + + case 12: + return generate_group_12(block, compiler, desc, opcode, in_delay_slot, ovrpc); + + case 13: // MOVLI + if (ovrpc == 0xffffffff) + { + scratch = ((desc->pc + 4) & ~3) + ((opcode & 0xff) * 4); + } + else + { + scratch = ((ovrpc + 4) & ~3) + ((opcode & 0xff) * 4); + } + + if (m_drcoptions & SH2DRC_STRICT_PCREL) + { + UML_MOV(block, I0, scratch); // mov r0, scratch + UML_CALLH(block, *m_read32); // read32(r0, r1) + UML_MOV(block, R32(Rn), I0); // mov Rn, r0 + } + else + { + scratch2 = RL(scratch); + UML_MOV(block, R32(Rn), scratch2); // mov Rn, scratch2 + } + + if (!in_delay_slot) + generate_update_cycles(block, compiler, desc->pc + 2, TRUE); + return TRUE; + + case 14: // MOVI + scratch = opcode & 0xff; + scratch2 = (UINT32)(INT32)(INT16)(INT8)scratch; + UML_MOV(block, R32(Rn), scratch2); + return TRUE; + + case 15: + return FALSE; + } + + return FALSE; +} + +int sh2_device::generate_group_0(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, UINT16 opcode, int in_delay_slot, UINT32 ovrpc) +{ + switch (opcode & 0x3F) + { + case 0x00: // these are all illegal + case 0x01: + case 0x10: + case 0x11: + case 0x13: + case 0x20: + case 0x21: + case 0x30: + case 0x31: + case 0x32: + case 0x33: + case 0x38: + case 0x39: + case 0x3a: + case 0x3b: + return FALSE; + + case 0x09: // NOP(); + return TRUE; + + case 0x02: // STCSR(Rn); + UML_MOV(block, R32(Rn), mem(&m_sh2_state->sr)); + return TRUE; + + case 0x03: // BSRF(Rn); + if (m_cpu_type > CPU_TYPE_SH1) + { + UML_ADD(block, mem(&m_sh2_state->target), R32(Rn), 4); // add target, Rm, #4 + UML_ADD(block, mem(&m_sh2_state->target), mem(&m_sh2_state->target), desc->pc); // add target, target, pc + + // 32x Cosmic Carnage @ 6002cb0 relies on the delay slot + // clobbering the calculated PR, so do it first + UML_ADD(block, mem(&m_sh2_state->pr), desc->pc, 4); // add m_pr, desc->pc, #4 (skip the current insn & delay slot) + + generate_delay_slot(block, compiler, desc, m_sh2_state->target); + + generate_update_cycles(block, compiler, mem(&m_sh2_state->target), TRUE); // + UML_HASHJMP(block, 0, mem(&m_sh2_state->target), *m_nocode); // jmp target + return TRUE; + } + break; + + case 0x04: // MOVBS0(Rm, Rn); + case 0x14: // MOVBS0(Rm, Rn); + case 0x24: // MOVBS0(Rm, Rn); + case 0x34: // MOVBS0(Rm, Rn); + UML_ADD(block, I0, R32(0), R32(Rn)); // add r0, R0, Rn + UML_AND(block, I1, R32(Rm), 0x000000ff); // and r1, Rm, 0xff + UML_CALLH(block, *m_write8); // call write8 + + if (!in_delay_slot) + generate_update_cycles(block, compiler, desc->pc + 2, TRUE); + return TRUE; + + case 0x05: // MOVWS0(Rm, Rn); + case 0x15: // MOVWS0(Rm, Rn); + case 0x25: // MOVWS0(Rm, Rn); + case 0x35: // MOVWS0(Rm, Rn); + UML_ADD(block, I0, R32(0), R32(Rn)); // add r0, R0, Rn + UML_AND(block, I1, R32(Rm), 0x0000ffff); // and r1, Rm, 0xffff + UML_CALLH(block, *m_write16); // call write16 + + if (!in_delay_slot) + generate_update_cycles(block, compiler, desc->pc + 2, TRUE); + return TRUE; + + case 0x06: // MOVLS0(Rm, Rn); + case 0x16: // MOVLS0(Rm, Rn); + case 0x26: // MOVLS0(Rm, Rn); + case 0x36: // MOVLS0(Rm, Rn); + UML_ADD(block, I0, R32(0), R32(Rn)); // add r0, R0, Rn + UML_MOV(block, I1, R32(Rm)); // mov r1, Rm + UML_CALLH(block, *m_write32); // call write32 + + if (!in_delay_slot) + generate_update_cycles(block, compiler, desc->pc + 2, TRUE); + return TRUE; + + case 0x07: // MULL(Rm, Rn); + case 0x17: // MULL(Rm, Rn); + case 0x27: // MULL(Rm, Rn); + case 0x37: // MULL(Rm, Rn); + if (m_cpu_type > CPU_TYPE_SH1) + { + UML_MULU(block, mem(&m_sh2_state->macl), mem(&m_sh2_state->ea), R32(Rn), R32(Rm)); // mulu macl, ea, Rn, Rm + return TRUE; + } + break; + + case 0x08: // CLRT(); + UML_AND(block, mem(&m_sh2_state->sr), mem(&m_sh2_state->sr), ~T); // and r0, sr, ~T (clear the T bit) + return TRUE; + + case 0x0a: // STSMACH(Rn); + UML_MOV(block, R32(Rn), mem(&m_sh2_state->mach)); // mov Rn, mach + return TRUE; + + case 0x0b: // RTS(); + UML_MOV(block, mem(&m_sh2_state->target), mem(&m_sh2_state->pr)); // mov target, pr (in case of d-slot shenanigans) + + generate_delay_slot(block, compiler, desc, m_sh2_state->target); + + generate_update_cycles(block, compiler, mem(&m_sh2_state->target), TRUE); // + UML_HASHJMP(block, 0, mem(&m_sh2_state->target), *m_nocode); + return TRUE; + + case 0x0c: // MOVBL0(Rm, Rn); + case 0x1c: // MOVBL0(Rm, Rn); + case 0x2c: // MOVBL0(Rm, Rn); + case 0x3c: // MOVBL0(Rm, Rn); + UML_ADD(block, I0, R32(0), R32(Rm)); // add r0, R0, Rm + UML_CALLH(block, *m_read8); // call read8 + UML_SEXT(block, R32(Rn), I0, SIZE_BYTE); // sext Rn, r0, BYTE + + if (!in_delay_slot) + generate_update_cycles(block, compiler, desc->pc + 2, TRUE); + return TRUE; + + case 0x0d: // MOVWL0(Rm, Rn); + case 0x1d: // MOVWL0(Rm, Rn); + case 0x2d: // MOVWL0(Rm, Rn); + case 0x3d: // MOVWL0(Rm, Rn); + UML_ADD(block, I0, R32(0), R32(Rm)); // add r0, R0, Rm + UML_CALLH(block, *m_read16); // call read16 + UML_SEXT(block, R32(Rn), I0, SIZE_WORD); // sext Rn, r0, WORD + + if (!in_delay_slot) + generate_update_cycles(block, compiler, desc->pc + 2, TRUE); + return TRUE; + + case 0x0e: // MOVLL0(Rm, Rn); + case 0x1e: // MOVLL0(Rm, Rn); + case 0x2e: // MOVLL0(Rm, Rn); + case 0x3e: // MOVLL0(Rm, Rn); + UML_ADD(block, I0, R32(0), R32(Rm)); // add r0, R0, Rm + UML_CALLH(block, *m_read32); // call read32 + UML_MOV(block, R32(Rn), I0); // mov Rn, r0 + + if (!in_delay_slot) + generate_update_cycles(block, compiler, desc->pc + 2, TRUE); + return TRUE; + + case 0x0f: // MAC_L(Rm, Rn); + case 0x1f: // MAC_L(Rm, Rn); + case 0x2f: // MAC_L(Rm, Rn); + case 0x3f: // MAC_L(Rm, Rn); + if (m_cpu_type > CPU_TYPE_SH1) + { + save_fast_iregs(block); + UML_MOV(block, mem(&m_sh2_state->arg0), desc->opptr.w[0]); + UML_CALLC(block, cfunc_MAC_L, this); + load_fast_iregs(block); + return TRUE; + } + break; + + case 0x12: // STCGBR(Rn); + UML_MOV(block, R32(Rn), mem(&m_sh2_state->gbr)); // mov Rn, gbr + return TRUE; + + case 0x18: // SETT(); + UML_OR(block, mem(&m_sh2_state->sr), mem(&m_sh2_state->sr), T); // or sr, sr, T + return TRUE; + + case 0x19: // DIV0U(); + UML_AND(block, mem(&m_sh2_state->sr), mem(&m_sh2_state->sr), ~(M|Q|T)); // and sr, sr, ~(M|Q|T) + return TRUE; + + case 0x1a: // STSMACL(Rn); + UML_MOV(block, R32(Rn), mem(&m_sh2_state->macl)); // mov Rn, macl + return TRUE; + + case 0x1b: // SLEEP(); + UML_MOV(block, I0, mem(&m_sh2_state->sleep_mode)); // mov i0, sleep_mode + UML_CMP(block, I0, 0x2); // cmp i0, #2 + UML_JMPc(block, COND_E, compiler->labelnum); // beq labelnum + // sleep mode != 2 + UML_MOV(block, mem(&m_sh2_state->sleep_mode), 0x1); // mov sleep_mode, #1 + generate_update_cycles(block, compiler, desc->pc, TRUE); // repeat this insn + UML_JMP(block, compiler->labelnum+1); // jmp labelnum+1 + + UML_LABEL(block, compiler->labelnum++); // labelnum: + // sleep_mode == 2 + UML_MOV(block, mem(&m_sh2_state->sleep_mode), 0x0); // sleep_mode = 0 + generate_update_cycles(block, compiler, desc->pc+2, TRUE); // go to next insn + + UML_LABEL(block, compiler->labelnum++); // labelnum+1: + return TRUE; + + case 0x22: // STCVBR(Rn); + UML_MOV(block, R32(Rn), mem(&m_sh2_state->vbr)); // mov Rn, vbr + return TRUE; + + case 0x23: // BRAF(Rn); + if (m_cpu_type > CPU_TYPE_SH1) + { + UML_ADD(block, mem(&m_sh2_state->target), R32(Rn), desc->pc+4); // add target, Rn, pc+4 + + generate_delay_slot(block, compiler, desc, m_sh2_state->target); + + generate_update_cycles(block, compiler, mem(&m_sh2_state->target), TRUE); // + UML_HASHJMP(block, 0, mem(&m_sh2_state->target), *m_nocode); // jmp target + return TRUE; + } + break; + + case 0x28: // CLRMAC(); + UML_MOV(block, mem(&m_sh2_state->macl), 0); // mov macl, #0 + UML_MOV(block, mem(&m_sh2_state->mach), 0); // mov mach, #0 + return TRUE; + + case 0x29: // MOVT(Rn); + UML_AND(block, R32(Rn), mem(&m_sh2_state->sr), T); // and Rn, sr, T + return TRUE; + + case 0x2a: // STSPR(Rn); + UML_MOV(block, R32(Rn), mem(&m_sh2_state->pr)); // mov Rn, pr + return TRUE; + + case 0x2b: // RTE(); + generate_delay_slot(block, compiler, desc, 0xffffffff); + + UML_MOV(block, I0, R32(15)); // mov r0, R15 + UML_CALLH(block, *m_read32); // call read32 + UML_MOV(block, mem(&m_sh2_state->pc), I0); // mov pc, r0 + UML_ADD(block, R32(15), R32(15), 4); // add R15, R15, #4 + + UML_MOV(block, I0, R32(15)); // mov r0, R15 + UML_CALLH(block, *m_read32); // call read32 + UML_MOV(block, mem(&m_sh2_state->sr), I0); // mov sr, r0 + UML_ADD(block, R32(15), R32(15), 4); // add R15, R15, #4 + + compiler->checkints = TRUE; + UML_MOV(block, mem(&m_sh2_state->ea), mem(&m_sh2_state->pc)); // mov ea, pc + generate_update_cycles(block, compiler, mem(&m_sh2_state->ea), TRUE); // + UML_HASHJMP(block, 0, mem(&m_sh2_state->pc), *m_nocode); // and jump to the "resume PC" + + return TRUE; + } + + return FALSE; +} + +int sh2_device::generate_group_2(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, UINT16 opcode, int in_delay_slot, UINT32 ovrpc) +{ + switch (opcode & 15) + { + case 0: // MOVBS(Rm, Rn); + UML_MOV(block, I0, R32(Rn)); // mov r0, Rn + UML_AND(block, I1, R32(Rm), 0xff); // and r1, Rm, 0xff + UML_CALLH(block, *m_write8); + + if (!in_delay_slot) + generate_update_cycles(block, compiler, desc->pc + 2, TRUE); + return TRUE; + + case 1: // MOVWS(Rm, Rn); + UML_MOV(block, I0, R32(Rn)); // mov r0, Rn + UML_AND(block, I1, R32(Rm), 0xffff); // and r1, Rm, 0xffff + UML_CALLH(block, *m_write16); + + if (!in_delay_slot) + generate_update_cycles(block, compiler, desc->pc + 2, TRUE); + return TRUE; + + case 2: // MOVLS(Rm, Rn); + UML_MOV(block, I0, R32(Rn)); // mov r0, Rn + UML_MOV(block, I1, R32(Rm)); // mov r1, Rm + UML_CALLH(block, *m_write32); + + if (!in_delay_slot) + generate_update_cycles(block, compiler, desc->pc + 2, TRUE); + return TRUE; + + case 3: + return FALSE; + + case 4: // MOVBM(Rm, Rn); + UML_MOV(block, I1, R32(Rm)); // mov r1, Rm + UML_SUB(block, R32(Rn), R32(Rn), 1); // sub Rn, Rn, 1 + UML_MOV(block, I0, R32(Rn)); // mov r0, Rn + UML_CALLH(block, *m_write8); // call write8 + + if (!in_delay_slot) + generate_update_cycles(block, compiler, desc->pc + 2, TRUE); + return TRUE; + + case 5: // MOVWM(Rm, Rn); + UML_MOV(block, I1, R32(Rm)); // mov r1, Rm + UML_SUB(block, R32(Rn), R32(Rn), 2); // sub Rn, Rn, 2 + UML_MOV(block, I0, R32(Rn)); // mov r0, Rn + UML_CALLH(block, *m_write16); // call write16 + + if (!in_delay_slot) + generate_update_cycles(block, compiler, desc->pc + 2, TRUE); + return TRUE; + + case 6: // MOVLM(Rm, Rn); + UML_MOV(block, I1, R32(Rm)); // mov r1, Rm + UML_SUB(block, R32(Rn), R32(Rn), 4); // sub Rn, Rn, 4 + UML_MOV(block, I0, R32(Rn)); // mov r0, Rn + UML_CALLH(block, *m_write32); // call write32 + + if (!in_delay_slot) + generate_update_cycles(block, compiler, desc->pc + 2, TRUE); + return TRUE; + + case 13: // XTRCT(Rm, Rn); + UML_SHL(block, I0, R32(Rm), 16); // shl r0, Rm, #16 + UML_AND(block, I0, I0, 0xffff0000); // and r0, r0, #0xffff0000 + + UML_SHR(block, I1, R32(Rn), 16); // shr, r1, Rn, #16 + UML_AND(block, I1, I1, 0xffff); // and r1, r1, #0x0000ffff + + UML_OR(block, R32(Rn), I0, I1); // or Rn, r0, r1 + return TRUE; + + case 7: // DIV0S(Rm, Rn); + UML_MOV(block, I0, mem(&m_sh2_state->sr)); // move r0, sr + UML_AND(block, I0, I0, ~(Q|M|T)); // and r0, r0, ~(Q|M|T) (clear the Q,M, and T bits) + + UML_TEST(block, R32(Rn), 0x80000000); // test Rn, #0x80000000 + UML_JMPc(block, COND_Z, compiler->labelnum); // jz labelnum + + UML_OR(block, I0, I0, Q); // or r0, r0, Q + UML_LABEL(block, compiler->labelnum++); // labelnum: + + UML_TEST(block, R32(Rm), 0x80000000); // test Rm, #0x80000000 + UML_JMPc(block, COND_Z, compiler->labelnum); // jz labelnum + + UML_OR(block, I0, I0, M); // or r0, r0, M + UML_LABEL(block, compiler->labelnum++); // labelnum: + + UML_XOR(block, I1, R32(Rn), R32(Rm)); // xor r1, Rn, Rm + UML_TEST(block, I1, 0x80000000); // test r1, #0x80000000 + UML_JMPc(block, COND_Z, compiler->labelnum); // jz labelnum + + UML_OR(block, I0, I0, T); // or r0, r0, T + UML_LABEL(block, compiler->labelnum++); // labelnum: + UML_MOV(block, mem(&m_sh2_state->sr), I0); // mov sr, r0 + return TRUE; + + case 8: // TST(Rm, Rn); + UML_AND(block, I0, mem(&m_sh2_state->sr), ~T); // and r0, sr, ~T (clear the T bit) + UML_TEST(block, R32(Rm), R32(Rn)); // test Rm, Rn + UML_JMPc(block, COND_NZ, compiler->labelnum); // jnz compiler->labelnum + + UML_OR(block, I0, I0, T); // or r0, r0, T + UML_LABEL(block, compiler->labelnum++); // desc->pc: + + UML_MOV(block, mem(&m_sh2_state->sr), I0); // mov m_sh2_state->sr, r0 + return TRUE; + + case 12: // CMPSTR(Rm, Rn); + UML_XOR(block, I0, R32(Rn), R32(Rm)); // xor r0, Rn, Rm (temp) + + UML_SHR(block, I1, I0, 24); // shr r1, r0, #24 (HH) + UML_AND(block, I1, I1, 0xff); // and r1, r1, #0xff + + UML_SHR(block, I2, I0, 16); // shr r2, r0, #16 (HL) + UML_AND(block, I2, I2, 0xff); // and r2, r2, #0xff + + UML_SHR(block, I3, I0, 8); // shr r3, r0, #8 (LH) + UML_AND(block, I3, I3, 0xff); // and r3, r3, #0xff + + UML_AND(block, I7, I0, 0xff); // and r7, r0, #0xff (LL) + + UML_AND(block, mem(&m_sh2_state->sr), mem(&m_sh2_state->sr), ~T); // and sr, sr, ~T (clear the T bit) + + UML_CMP(block, I1, 0); // cmp r1, #0 + UML_JMPc(block, COND_Z, compiler->labelnum); // jnz labelnum + UML_CMP(block, I2, 0); // cmp r2, #0 + UML_JMPc(block, COND_Z, compiler->labelnum); // jnz labelnum + UML_CMP(block, I3, 0); // cmp r3, #0 + UML_JMPc(block, COND_Z, compiler->labelnum); // jnz labelnum + UML_CMP(block, I7, 0); // cmp r7, #0 + UML_JMPc(block, COND_NZ, compiler->labelnum+1); // jnz labelnum + + UML_LABEL(block, compiler->labelnum++); // labelnum: + UML_OR(block, mem(&m_sh2_state->sr), mem(&m_sh2_state->sr), T); // or sr, sr, T + + UML_LABEL(block, compiler->labelnum++); // labelnum+1: + return TRUE; + + case 9: // AND(Rm, Rn); + UML_AND(block, R32(Rn), R32(Rn), R32(Rm)); // and Rn, Rn, Rm + return TRUE; + + case 10: // XOR(Rm, Rn); + UML_XOR(block, R32(Rn), R32(Rn), R32(Rm)); // xor Rn, Rn, Rm + return TRUE; + + case 11: // OR(Rm, Rn); + UML_OR(block, R32(Rn), R32(Rn), R32(Rm)); // or Rn, Rn, Rm + return TRUE; + + case 14: // MULU(Rm, Rn); + UML_AND(block, I0, R32(Rm), 0xffff); // and r0, Rm, 0xffff + UML_AND(block, I1, R32(Rn), 0xffff); // and r1, Rn, 0xffff + UML_MULU(block, mem(&m_sh2_state->macl), mem(&m_sh2_state->ea), I0, I1); // mulu macl, ea, r0, r1 + return TRUE; + + case 15: // MULS(Rm, Rn); + UML_SEXT(block, I0, R32(Rm), SIZE_WORD); // sext r0, Rm + UML_SEXT(block, I1, R32(Rn), SIZE_WORD); // sext r1, Rn + UML_MULS(block, mem(&m_sh2_state->macl), mem(&m_sh2_state->ea), I0, I1); // muls macl, ea, r0, r1 + return TRUE; + } + + return FALSE; +} + +int sh2_device::generate_group_3(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, UINT16 opcode, UINT32 ovrpc) +{ + switch (opcode & 15) + { + case 0: // CMPEQ(Rm, Rn); (equality) + UML_CMP(block, R32(Rn), R32(Rm)); // cmp Rn, Rm + UML_SETc(block, COND_E, I0); // set E, r0 + UML_ROLINS(block, mem(&m_sh2_state->sr), I0, 0, 1); // rolins sr, r0, 0, 1 + return TRUE; + + case 2: // CMPHS(Rm, Rn); (unsigned greater than or equal) + UML_CMP(block, R32(Rn), R32(Rm)); // cmp Rn, Rm + UML_SETc(block, COND_AE, I0); // set AE, r0 + UML_ROLINS(block, mem(&m_sh2_state->sr), I0, 0, 1); // rolins sr, r0, 0, 1 + return TRUE; + + case 3: // CMPGE(Rm, Rn); (signed greater than or equal) + UML_CMP(block, R32(Rn), R32(Rm)); // cmp Rn, Rm + UML_SETc(block, COND_GE, I0); // set GE, r0 + UML_ROLINS(block, mem(&m_sh2_state->sr), I0, 0, 1); // rolins sr, r0, 0, 1 + return TRUE; + + case 6: // CMPHI(Rm, Rn); (unsigned greater than) + UML_CMP(block, R32(Rn), R32(Rm)); // cmp Rn, Rm + UML_SETc(block, COND_A, I0); // set A, r0 + UML_ROLINS(block, mem(&m_sh2_state->sr), I0, 0, 1); // rolins sr, r0, 0, 1 + return TRUE; + + case 7: // CMPGT(Rm, Rn); (signed greater than) + UML_CMP(block, R32(Rn), R32(Rm)); // cmp Rn, Rm + UML_SETc(block, COND_G, I0); // set G, r0 + UML_ROLINS(block, mem(&m_sh2_state->sr), I0, 0, 1); // rolins sr, r0, 0, 1 + return TRUE; + + case 1: + case 9: + return FALSE; + + case 4: // DIV1(Rm, Rn); + save_fast_iregs(block); + UML_MOV(block, mem(&m_sh2_state->arg0), desc->opptr.w[0]); + UML_CALLC(block, cfunc_DIV1, this); + load_fast_iregs(block); + return TRUE; + + case 5: // DMULU(Rm, Rn); + if (m_cpu_type > CPU_TYPE_SH1) + { + UML_MULU(block, mem(&m_sh2_state->macl), mem(&m_sh2_state->mach), R32(Rn), R32(Rm)); + return TRUE; + } + break; + + case 13: // DMULS(Rm, Rn); + if (m_cpu_type > CPU_TYPE_SH1) + { + UML_MULS(block, mem(&m_sh2_state->macl), mem(&m_sh2_state->mach), R32(Rn), R32(Rm)); + return TRUE; + } + break; + + case 8: // SUB(Rm, Rn); + UML_SUB(block, R32(Rn), R32(Rn), R32(Rm)); // sub Rn, Rn, Rm + return TRUE; + + case 12: // ADD(Rm, Rn); + UML_ADD(block, R32(Rn), R32(Rn), R32(Rm)); // add Rn, Rn, Rm + return TRUE; + + case 10: // SUBC(Rm, Rn); + UML_CARRY(block, mem(&m_sh2_state->sr), 0); // carry = T (T is bit 0 of SR) + UML_SUBB(block, R32(Rn), R32(Rn), R32(Rm)); // addc Rn, Rn, Rm + UML_SETc(block, COND_C, I0); // setc i0, C + UML_ROLINS(block, mem(&m_sh2_state->sr), I0, 0, T); // rolins sr,i0,0,T + return TRUE; + + case 11: // SUBV(Rm, Rn); +#if ADDSUBV_DIRECT + UML_SUB(block, R32(Rn), R32(Rn), R32(Rm)); // sub Rn, Rn, Rm + UML_SETc(block, COND_V, I0); // setc i0, V + UML_ROLINS(block, mem(&m_sh2_state->sr), I0, 0, T); // rolins [sr],i0,0,T +#else + save_fast_iregs(block); + UML_MOV(block, mem(&m_sh2_state->arg0), desc->opptr.w[0]); + UML_CALLC(block, cfunc_SUBV, this); + load_fast_iregs(block); +#endif + return TRUE; + + case 14: // ADDC(Rm, Rn); + UML_CARRY(block, mem(&m_sh2_state->sr), 0); // carry = T (T is bit 0 of SR) + UML_ADDC(block, R32(Rn), R32(Rn), R32(Rm)); // addc Rn, Rn, Rm + UML_SETc(block, COND_C, I0); // setc i0, C + UML_ROLINS(block, mem(&m_sh2_state->sr), I0, 0, T); // rolins sr,i0,0,T + return TRUE; + + case 15: // ADDV(Rm, Rn); +#if ADDSUBV_DIRECT + UML_ADD(block, R32(Rn), R32(Rn), R32(Rm)); // add Rn, Rn, Rm + UML_SETc(block, COND_V, I0); // setc i0, V + UML_ROLINS(block, mem(&m_sh2_state->sr), I0, 0, T); // rolins [sr],i0,0,T +#else + save_fast_iregs(block); + UML_MOV(block, mem(&m_sh2_state->arg0), desc->opptr.w[0]); + UML_CALLC(block, cfunc_ADDV, this); + load_fast_iregs(block); +#endif + return TRUE; + } + return FALSE; +} + +int sh2_device::generate_group_4(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, UINT16 opcode, int in_delay_slot, UINT32 ovrpc) +{ + switch (opcode & 0x3F) + { + case 0x00: // SHLL(Rn); + UML_SHL(block, R32(Rn), R32(Rn), 1); // shl Rn, Rn, 1 + UML_SETc(block, COND_C, I0); // set i0,C + UML_ROLINS(block, mem(&m_sh2_state->sr), I0, 0, T); // rolins [sr],i0,0,T + return TRUE; + + case 0x01: // SHLR(Rn); + UML_SHR(block, R32(Rn), R32(Rn), 1); // shr Rn, Rn, 1 + UML_SETc(block, COND_C, I0); // set i0,C + UML_ROLINS(block, mem(&m_sh2_state->sr), I0, 0, T); // rolins [sr],i0,0,T + return TRUE; + + case 0x04: // ROTL(Rn); + UML_ROL(block, R32(Rn), R32(Rn), 1); // rol Rn, Rn, 1 + UML_SETc(block, COND_C, I0); // set i0,C + UML_ROLINS(block, mem(&m_sh2_state->sr), I0, 0, T); // rolins [sr],i0,0,T + return TRUE; + + case 0x05: // ROTR(Rn); + UML_ROR(block, R32(Rn), R32(Rn), 1); // ror Rn, Rn, 1 + UML_SETc(block, COND_C, I0); // set i0,C + UML_ROLINS(block, mem(&m_sh2_state->sr), I0, 0, T); // rolins [sr],i0,0,T + return TRUE; + + case 0x02: // STSMMACH(Rn); + UML_SUB(block, R32(Rn), R32(Rn), 4); // sub Rn, Rn, #4 + UML_MOV(block, I0, R32(Rn)); // mov r0, Rn + UML_MOV(block, I1, mem(&m_sh2_state->mach)); // mov r1, mach + SETEA(0); // set ea for debug + UML_CALLH(block, *m_write32); // call write32 + + if (!in_delay_slot) + generate_update_cycles(block, compiler, desc->pc + 2, TRUE); + return TRUE; + + case 0x03: // STCMSR(Rn); + UML_SUB(block, R32(Rn), R32(Rn), 4); // sub Rn, Rn, #4 + UML_MOV(block, I0, R32(Rn)); // mov r0, Rn + UML_MOV(block, I1, mem(&m_sh2_state->sr)); // mov r1, sr + SETEA(0); // set ea for debug + UML_CALLH(block, *m_write32); // call write32 + + if (!in_delay_slot) + generate_update_cycles(block, compiler, desc->pc + 2, TRUE); + return TRUE; + + case 0x06: // LDSMMACH(Rn); + UML_MOV(block, I0, R32(Rn)); // mov r0, Rn + SETEA(0); + UML_CALLH(block, *m_read32); // call read32 + UML_ADD(block, R32(Rn), R32(Rn), 4); // add Rn, #4 + UML_MOV(block, mem(&m_sh2_state->mach), I0); // mov mach, r0 + + if (!in_delay_slot) + generate_update_cycles(block, compiler, desc->pc + 2, TRUE); + return TRUE; + + case 0x07: // LDCMSR(Rn); + UML_MOV(block, I0, R32(Rn)); // mov r0, Rn + SETEA(0); + UML_CALLH(block, *m_read32); // call read32 + UML_ADD(block, R32(Rn), R32(Rn), 4); // add Rn, #4 + UML_MOV(block, mem(&m_sh2_state->sr), I0); // mov sr, r0 + + compiler->checkints = TRUE; + if (!in_delay_slot) + generate_update_cycles(block, compiler, desc->pc + 2, TRUE); + return TRUE; + + + case 0x08: // SHLL2(Rn); + UML_SHL(block, R32(Rn), R32(Rn), 2); + return TRUE; + + case 0x09: // SHLR2(Rn); + UML_SHR(block, R32(Rn), R32(Rn), 2); + return TRUE; + + case 0x18: // SHLL8(Rn); + UML_SHL(block, R32(Rn), R32(Rn), 8); + return TRUE; + + case 0x19: // SHLR8(Rn); + UML_SHR(block, R32(Rn), R32(Rn), 8); + return TRUE; + + case 0x28: // SHLL16(Rn); + UML_SHL(block, R32(Rn), R32(Rn), 16); + return TRUE; + + case 0x29: // SHLR16(Rn); + UML_SHR(block, R32(Rn), R32(Rn), 16); + return TRUE; + + case 0x0a: // LDSMACH(Rn); + UML_MOV(block, mem(&m_sh2_state->mach), R32(Rn)); // mov mach, Rn + return TRUE; + + case 0x0b: // JSR(Rn); + UML_MOV(block, mem(&m_sh2_state->target), R32(Rn)); // mov target, Rn + + UML_ADD(block, mem(&m_sh2_state->pr), desc->pc, 4); // add m_pr, desc->pc, #4 (skip the current insn & delay slot) + + generate_delay_slot(block, compiler, desc, m_sh2_state->target-4); + + generate_update_cycles(block, compiler, mem(&m_sh2_state->target), TRUE); // + UML_HASHJMP(block, 0, mem(&m_sh2_state->target), *m_nocode); // and do the jump + return TRUE; + + case 0x0e: // LDCSR(Rn); + UML_MOV(block, I0, R32(Rn)); // mov r0, Rn + UML_AND(block, I0, I0, FLAGS); // and r0, r0, FLAGS + UML_MOV(block, mem(&m_sh2_state->sr), I0); + + compiler->checkints = TRUE; + return TRUE; + + case 0x0f: // MAC_W(Rm, Rn); + case 0x1f: // MAC_W(Rm, Rn); + case 0x2f: // MAC_W(Rm, Rn); + case 0x3f: // MAC_W(Rm, Rn); + save_fast_iregs(block); + UML_MOV(block, mem(&m_sh2_state->arg0), desc->opptr.w[0]); + UML_CALLC(block, cfunc_MAC_W, this); + load_fast_iregs(block); + return TRUE; + + case 0x10: // DT(Rn); + if (m_cpu_type > CPU_TYPE_SH1) + { + UML_AND(block, I0, mem(&m_sh2_state->sr), ~T); // and r0, sr, ~T (clear the T bit) + UML_SUB(block, R32(Rn), R32(Rn), 1); // sub Rn, Rn, 1 + UML_JMPc(block, COND_NZ, compiler->labelnum); // jz compiler->labelnum + + UML_OR(block, I0, I0, T); // or r0, r0, T + UML_LABEL(block, compiler->labelnum++); // desc->pc: + + UML_MOV(block, mem(&m_sh2_state->sr), I0); // mov m_sh2_state->sr, r0 + return TRUE; + } + break; + + case 0x11: // CMPPZ(Rn); + UML_AND(block, I0, mem(&m_sh2_state->sr), ~T); // and r0, sr, ~T (clear the T bit) + + UML_CMP(block, R32(Rn), 0); // cmp Rn, 0 + UML_JMPc(block, COND_S, compiler->labelnum); // js compiler->labelnum (if negative) + + UML_OR(block, I0, I0, T); // or r0, r0, T + UML_LABEL(block, compiler->labelnum++); // desc->pc: + + UML_MOV(block, mem(&m_sh2_state->sr), I0); // mov m_sh2_state->sr, r0 + return TRUE; + + case 0x15: // CMPPL(Rn); + UML_AND(block, I0, mem(&m_sh2_state->sr), ~T); // and r0, sr, ~T (clear the T bit) + + UML_CMP(block, R32(Rn), 0); // cmp Rn, 0 + + UML_JMPc(block, COND_S, compiler->labelnum); // js compiler->labelnum (if negative) + UML_JMPc(block, COND_Z, compiler->labelnum); // jz compiler->labelnum (if zero) + + UML_OR(block, I0, I0, T); // or r0, r0, T + + UML_LABEL(block, compiler->labelnum++); // desc->pc: + UML_MOV(block, mem(&m_sh2_state->sr), I0); // mov m_sh2_state->sr, r0 + return TRUE; + + case 0x12: // STSMMACL(Rn); + UML_SUB(block, R32(Rn), R32(Rn), 4); // sub Rn, Rn, #4 + UML_MOV(block, I0, R32(Rn)); // mov r0, Rn + UML_MOV(block, I1, mem(&m_sh2_state->macl)); // mov r1, macl + SETEA(0); // set ea for debug + UML_CALLH(block, *m_write32); // call write32 + + if (!in_delay_slot) + generate_update_cycles(block, compiler, desc->pc + 2, TRUE); + return TRUE; + + case 0x13: // STCMGBR(Rn); + UML_SUB(block, R32(Rn), R32(Rn), 4); // sub Rn, Rn, #4 + UML_MOV(block, I0, R32(Rn)); // mov r0, Rn + UML_MOV(block, I1, mem(&m_sh2_state->gbr)); // mov r1, gbr + SETEA(0); // set ea for debug + UML_CALLH(block, *m_write32); // call write32 + + if (!in_delay_slot) + generate_update_cycles(block, compiler, desc->pc + 2, TRUE); + return TRUE; + + case 0x16: // LDSMMACL(Rn); + UML_MOV(block, I0, R32(Rn)); // mov r0, Rn + SETEA(0); + UML_CALLH(block, *m_read32); // call read32 + UML_ADD(block, R32(Rn), R32(Rn), 4); // add Rn, #4 + UML_MOV(block, mem(&m_sh2_state->macl), I0); // mov macl, r0 + + if (!in_delay_slot) + generate_update_cycles(block, compiler, desc->pc + 2, TRUE); + return TRUE; + + case 0x17: // LDCMGBR(Rn); + UML_MOV(block, I0, R32(Rn)); // mov r0, Rn + SETEA(0); + UML_CALLH(block, *m_read32); // call read32 + UML_ADD(block, R32(Rn), R32(Rn), 4); // add Rn, #4 + UML_MOV(block, mem(&m_sh2_state->gbr), I0); // mov gbr, r0 + + if (!in_delay_slot) + generate_update_cycles(block, compiler, desc->pc + 2, TRUE); + return TRUE; + + case 0x1a: // LDSMACL(Rn); + UML_MOV(block, mem(&m_sh2_state->macl), R32(Rn)); // mov macl, Rn + return TRUE; + + case 0x1b: // TAS(Rn); + UML_MOV(block, I0, R32(Rn)); // mov r0, Rn + SETEA(0); + UML_CALLH(block, *m_read8); // call read8 + + UML_AND(block, mem(&m_sh2_state->sr), mem(&m_sh2_state->sr), ~T); // and sr, sr, ~T + + UML_CMP(block, I0, 0); // cmp r0, #0 + UML_JMPc(block, COND_NZ, compiler->labelnum); // jnz labelnum + + UML_OR(block, mem(&m_sh2_state->sr), mem(&m_sh2_state->sr), T); // or sr, sr, T + + UML_LABEL(block, compiler->labelnum++); // labelnum: + + UML_OR(block, I1, I0, 0x80); // or r1, r0, #0x80 + + UML_MOV(block, I0, R32(Rn)); // mov r0, Rn + UML_CALLH(block, *m_write8); // write the value back + + if (!in_delay_slot) + generate_update_cycles(block, compiler, desc->pc + 2, TRUE); + return TRUE; + + case 0x1e: // LDCGBR(Rn); + UML_MOV(block, mem(&m_sh2_state->gbr), R32(Rn)); // mov gbr, Rn + return TRUE; + + case 0x20: // SHAL(Rn); + UML_AND(block, mem(&m_sh2_state->sr), mem(&m_sh2_state->sr), ~T); // and sr, sr, ~T + UML_SHR(block, I0, R32(Rn), 31); // shr r0, Rn, 31 + UML_AND(block, I0, I0, T); // and r0, r0, T + UML_OR(block, mem(&m_sh2_state->sr), mem(&m_sh2_state->sr), I0); // or sr, sr, r0 + UML_SHL(block, R32(Rn), R32(Rn), 1); // shl Rn, Rn, 1 + return TRUE; + + case 0x21: // SHAR(Rn); + UML_AND(block, mem(&m_sh2_state->sr), mem(&m_sh2_state->sr), ~T); // and sr, sr, ~T + UML_AND(block, I0, R32(Rn), T); // and r0, Rn, T + UML_OR(block, mem(&m_sh2_state->sr), mem(&m_sh2_state->sr), I0); // or sr, sr, r0 + UML_SAR(block, R32(Rn), R32(Rn), 1); // sar Rn, Rn, 1 + return TRUE; + + case 0x22: // STSMPR(Rn); + UML_SUB(block, R32(Rn), R32(Rn), 4); // sub Rn, Rn, 4 + UML_MOV(block, I0, R32(Rn)); // mov r0, Rn + SETEA(0); + UML_MOV(block, I1, mem(&m_sh2_state->pr)); // mov r1, pr + UML_CALLH(block, *m_write32); // call write32 + + if (!in_delay_slot) + generate_update_cycles(block, compiler, desc->pc + 2, TRUE); + return TRUE; + + case 0x23: // STCMVBR(Rn); + UML_SUB(block, R32(Rn), R32(Rn), 4); // sub Rn, Rn, 4 + UML_MOV(block, I0, R32(Rn)); // mov r0, Rn + SETEA(0); + UML_MOV(block, I1, mem(&m_sh2_state->vbr)); // mov r1, vbr + UML_CALLH(block, *m_write32); // call write32 + + if (!in_delay_slot) + generate_update_cycles(block, compiler, desc->pc + 2, TRUE); + return TRUE; + + case 0x24: // ROTCL(Rn); + UML_CARRY(block, mem(&m_sh2_state->sr), 0); // carry sr,0 + UML_ROLC(block, R32(Rn), R32(Rn), 1); // rolc Rn,Rn,1 + UML_SETc(block, COND_C, I0); // set i0,C + UML_ROLINS(block, mem(&m_sh2_state->sr), I0, 0, T); // rolins sr,i0,0,T + return TRUE; + + case 0x25: // ROTCR(Rn); + UML_CARRY(block, mem(&m_sh2_state->sr), 0); // carry sr,0 + UML_RORC(block, R32(Rn), R32(Rn), 1); // rorc Rn,Rn,1 + UML_SETc(block, COND_C, I0); // set i0,C + UML_ROLINS(block, mem(&m_sh2_state->sr), I0, 0, T); // rolins sr,i0,0,T + return TRUE; + + case 0x26: // LDSMPR(Rn); + UML_MOV(block, I0, R32(Rn)); // mov r0, Rn + SETEA(0); + UML_CALLH(block, *m_read32); // call read32 + UML_MOV(block, mem(&m_sh2_state->pr), I0); // mov m_pr, r0 + UML_ADD(block, R32(Rn), R32(Rn), 4); // add Rn, Rn, #4 + + if (!in_delay_slot) + generate_update_cycles(block, compiler, desc->pc + 2, TRUE); + return TRUE; + + case 0x27: // LDCMVBR(Rn); + UML_MOV(block, I0, R32(Rn)); // mov r0, Rn + SETEA(0); + UML_CALLH(block, *m_read32); // call read32 + UML_MOV(block, mem(&m_sh2_state->vbr), I0); // mov m_sh2_state->vbr, r0 + UML_ADD(block, R32(Rn), R32(Rn), 4); // add Rn, Rn, #4 + + if (!in_delay_slot) + generate_update_cycles(block, compiler, desc->pc + 2, TRUE); + return TRUE; + + case 0x2a: // LDSPR(Rn); + UML_MOV(block, mem(&m_sh2_state->pr), R32(Rn)); // mov m_pr, Rn + return TRUE; + + case 0x2b: // JMP(Rn); + UML_MOV(block, mem(&m_sh2_state->target), R32(Rn)); // mov target, Rn + + generate_delay_slot(block, compiler, desc, m_sh2_state->target); + + generate_update_cycles(block, compiler, mem(&m_sh2_state->target), TRUE); // + UML_HASHJMP(block, 0, mem(&m_sh2_state->target), *m_nocode); // jmp (target) + return TRUE; + + case 0x2e: // LDCVBR(Rn); + UML_MOV(block, mem(&m_sh2_state->vbr), R32(Rn)); // mov vbr, Rn + return TRUE; + + case 0x0c: + case 0x0d: + case 0x14: + case 0x1c: + case 0x1d: + case 0x2c: + case 0x2d: + 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: + return FALSE; + } + + return FALSE; +} + +int sh2_device::generate_group_6(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, UINT16 opcode, int in_delay_slot, UINT32 ovrpc) +{ + switch (opcode & 15) + { + case 0: // MOVBL(Rm, Rn); + UML_MOV(block, I0, R32(Rm)); // mov r0, Rm + SETEA(0); // debug: ea = r0 + UML_CALLH(block, *m_read8); // call read8 + UML_SEXT(block, R32(Rn), I0, SIZE_BYTE); // sext Rn, r0, BYTE + + if (!in_delay_slot) + generate_update_cycles(block, compiler, desc->pc + 2, TRUE); + return TRUE; + + case 1: // MOVWL(Rm, Rn); + UML_MOV(block, I0, R32(Rm)); // mov r0, Rm + SETEA(0); // debug: ea = r0 + UML_CALLH(block, *m_read16); // call read16 + UML_SEXT(block, R32(Rn), I0, SIZE_WORD); // sext Rn, r0, WORD + + if (!in_delay_slot) + generate_update_cycles(block, compiler, desc->pc + 2, TRUE); + return TRUE; + + case 2: // MOVLL(Rm, Rn); + UML_MOV(block, I0, R32(Rm)); // mov r0, Rm + SETEA(0); // debug: ea = r0 + UML_CALLH(block, *m_read32); // call read32 + UML_MOV(block, R32(Rn), I0); // mov Rn, r0 + + if (!in_delay_slot) + generate_update_cycles(block, compiler, desc->pc + 2, TRUE); + return TRUE; + + case 3: // MOV(Rm, Rn); + UML_MOV(block, R32(Rn), R32(Rm)); // mov Rn, Rm + return TRUE; + + case 7: // NOT(Rm, Rn); + UML_XOR(block, R32(Rn), R32(Rm), 0xffffffff); // xor Rn, Rm, 0xffffffff + return TRUE; + + case 9: // SWAPW(Rm, Rn); + UML_ROL(block, R32(Rn), R32(Rm), 16); // rol Rn, Rm, 16 + return TRUE; + + case 11: // NEG(Rm, Rn); + UML_SUB(block, R32(Rn), 0, R32(Rm)); // sub Rn, 0, Rm + return TRUE; + + case 12: // EXTUB(Rm, Rn); + UML_AND(block, R32(Rn), R32(Rm), 0x000000ff); // and Rn, Rm, 0xff + return TRUE; + + case 13: // EXTUW(Rm, Rn); + UML_AND(block, R32(Rn), R32(Rm), 0x0000ffff); // and Rn, Rm, 0xffff + return TRUE; + + case 14: // EXTSB(Rm, Rn); + UML_SEXT(block, R32(Rn), R32(Rm), SIZE_BYTE); // sext Rn, Rm, BYTE + return TRUE; + + case 15: // EXTSW(Rm, Rn); + UML_SEXT(block, R32(Rn), R32(Rm), SIZE_WORD); // sext Rn, Rm, WORD + return TRUE; + + case 4: // MOVBP(Rm, Rn); + UML_MOV(block, I0, R32(Rm)); // mov r0, Rm + UML_CALLH(block, *m_read8); // call read8 + UML_SEXT(block, R32(Rn), I0, SIZE_BYTE); // sext Rn, r0, BYTE + + if (Rm != Rn) + UML_ADD(block, R32(Rm), R32(Rm), 1); // add Rm, Rm, #1 + + if (!in_delay_slot) + generate_update_cycles(block, compiler, desc->pc + 2, TRUE); + return TRUE; + + case 5: // MOVWP(Rm, Rn); + UML_MOV(block, I0, R32(Rm)); // mov r0, Rm + UML_CALLH(block, *m_read16); // call read16 + UML_SEXT(block, R32(Rn), I0, SIZE_WORD); // sext Rn, r0, WORD + + if (Rm != Rn) + UML_ADD(block, R32(Rm), R32(Rm), 2); // add Rm, Rm, #2 + + if (!in_delay_slot) + generate_update_cycles(block, compiler, desc->pc + 2, TRUE); + return TRUE; + + case 6: // MOVLP(Rm, Rn); + UML_MOV(block, I0, R32(Rm)); // mov r0, Rm + UML_CALLH(block, *m_read32); // call read32 + UML_MOV(block, R32(Rn), I0); // mov Rn, r0 + + if (Rm != Rn) + UML_ADD(block, R32(Rm), R32(Rm), 4); // add Rm, Rm, #4 + + if (!in_delay_slot) + generate_update_cycles(block, compiler, desc->pc + 2, TRUE); + return TRUE; + + case 8: // SWAPB(Rm, Rn); + UML_AND(block, I0, R32(Rm), 0xffff0000); // and r0, Rm, #0xffff0000 + UML_AND(block, I1, R32(Rm), 0x000000ff); // and r0, Rm, #0x000000ff + UML_AND(block, I2, R32(Rm), 0x0000ff00); // and r0, Rm, #0x0000ff00 + UML_SHL(block, I1, I1, 8); // shl r1, r1, #8 + UML_SHR(block, I2, I2, 8); // shr r2, r2, #8 + UML_OR(block, I0, I0, I1); // or r0, r0, r1 + UML_OR(block, R32(Rn), I0, I2); // or Rn, r0, r2 + return TRUE; + + case 10: // NEGC(Rm, Rn); + UML_MOV(block, I0, mem(&m_sh2_state->sr)); // mov r0, sr (save SR) + UML_AND(block, mem(&m_sh2_state->sr), mem(&m_sh2_state->sr), ~T); // and sr, sr, ~T (clear the T bit) + UML_CARRY(block, I0, 0); // carry = T (T is bit 0 of SR) + UML_SUBB(block, R32(Rn), 0, R32(Rm)); // subb Rn, #0, Rm + + UML_JMPc(block, COND_NC, compiler->labelnum); // jnc labelnum + + UML_OR(block, mem(&m_sh2_state->sr), mem(&m_sh2_state->sr), T); // or sr, sr, T + + UML_LABEL(block, compiler->labelnum++); // labelnum: + + return TRUE; + } + + return FALSE; +} + +int sh2_device::generate_group_8(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, UINT16 opcode, int in_delay_slot, UINT32 ovrpc) +{ + INT32 disp; + UINT32 udisp; + code_label templabel; + + switch ( opcode & (15<<8) ) + { + case 0 << 8: // MOVBS4(opcode & 0x0f, Rm); + udisp = (opcode & 0x0f); + UML_ADD(block, I0, R32(Rm), udisp); // add r0, Rm, udisp + UML_MOV(block, I1, R32(0)); // mov r1, R0 + UML_CALLH(block, *m_write8); // call write8 + + if (!in_delay_slot) + generate_update_cycles(block, compiler, desc->pc + 2, TRUE); + return TRUE; + + case 1 << 8: // MOVWS4(opcode & 0x0f, Rm); + udisp = (opcode & 0x0f) * 2; + UML_ADD(block, I0, R32(Rm), udisp); // add r0, Rm, udisp + UML_MOV(block, I1, R32(0)); // mov r1, R0 + UML_CALLH(block, *m_write16); // call write16 + + if (!in_delay_slot) + generate_update_cycles(block, compiler, desc->pc + 2, TRUE); + return TRUE; + + case 2<< 8: + case 3<< 8: + case 6<< 8: + case 7<< 8: + case 10<< 8: + case 12<< 8: + case 14<< 8: + return FALSE; + + case 4<< 8: // MOVBL4(Rm, opcode & 0x0f); + udisp = opcode & 0x0f; + UML_ADD(block, I0, R32(Rm), udisp); // add r0, Rm, udisp + SETEA(0); + UML_CALLH(block, *m_read8); // call read8 + UML_SEXT(block, R32(0), I0, SIZE_BYTE); // sext R0, r0, BYTE + + if (!in_delay_slot) + generate_update_cycles(block, compiler, desc->pc + 2, TRUE); + return TRUE; + + case 5<< 8: // MOVWL4(Rm, opcode & 0x0f); + udisp = (opcode & 0x0f)*2; + UML_ADD(block, I0, R32(Rm), udisp); // add r0, Rm, udisp + SETEA(0); + UML_CALLH(block, *m_read16); // call read16 + UML_SEXT(block, R32(0), I0, SIZE_WORD); // sext R0, r0, WORD + + if (!in_delay_slot) + generate_update_cycles(block, compiler, desc->pc + 2, TRUE); + return TRUE; + + case 8<< 8: // CMPIM(opcode & 0xff); + UML_AND(block, I0, mem(&m_sh2_state->sr), ~T); // and r0, sr, ~T (clear the T bit) + + UML_SEXT(block, I1, opcode&0xff, SIZE_BYTE); // sext r1, opcode&0xff, BYTE + UML_CMP(block, I1, R32(0)); // cmp r1, R0 + UML_JMPc(block, COND_NZ, compiler->labelnum); // jnz compiler->labelnum (if negative) + + UML_OR(block, I0, I0, T); // or r0, r0, T + + UML_LABEL(block, compiler->labelnum++); // labelnum: + UML_MOV(block, mem(&m_sh2_state->sr), I0); // mov m_sh2_state->sr, r0 + return TRUE; + + case 9<< 8: // BT(opcode & 0xff); + UML_TEST(block, mem(&m_sh2_state->sr), T); // test m_sh2_state->sr, T + UML_JMPc(block, COND_Z, compiler->labelnum); // jz compiler->labelnum + + disp = ((INT32)opcode << 24) >> 24; + m_sh2_state->ea = (desc->pc + 2) + disp * 2 + 2; // m_sh2_state->ea = destination + + generate_update_cycles(block, compiler, m_sh2_state->ea, TRUE); // + UML_HASHJMP(block, 0, m_sh2_state->ea, *m_nocode); // jmp m_sh2_state->ea + + UML_LABEL(block, compiler->labelnum++); // labelnum: + return TRUE; + + case 11<< 8: // BF(opcode & 0xff); + UML_TEST(block, mem(&m_sh2_state->sr), T); // test m_sh2_state->sr, T + UML_JMPc(block, COND_NZ, compiler->labelnum); // jnz compiler->labelnum + + disp = ((INT32)opcode << 24) >> 24; + m_sh2_state->ea = (desc->pc + 2) + disp * 2 + 2; // m_sh2_state->ea = destination + + generate_update_cycles(block, compiler, m_sh2_state->ea, TRUE); // + UML_HASHJMP(block, 0, m_sh2_state->ea, *m_nocode); // jmp m_sh2_state->ea + + UML_LABEL(block, compiler->labelnum++); // labelnum: + return TRUE; + + case 13<< 8: // BTS(opcode & 0xff); + if (m_cpu_type > CPU_TYPE_SH1) + { + UML_TEST(block, mem(&m_sh2_state->sr), T); // test m_sh2_state->sr, T + UML_JMPc(block, COND_Z, compiler->labelnum); // jz compiler->labelnum + + disp = ((INT32)opcode << 24) >> 24; + m_sh2_state->ea = (desc->pc + 2) + disp * 2 + 2; // m_sh2_state->ea = destination + + templabel = compiler->labelnum; // save our label + compiler->labelnum++; // make sure the delay slot doesn't use it + generate_delay_slot(block, compiler, desc, m_sh2_state->ea-2); + + generate_update_cycles(block, compiler, m_sh2_state->ea, TRUE); // + UML_HASHJMP(block, 0, m_sh2_state->ea, *m_nocode); // jmp m_sh2_state->ea + + UML_LABEL(block, templabel); // labelnum: + return TRUE; + } + break; + + case 15<< 8: // BFS(opcode & 0xff); + if (m_cpu_type > CPU_TYPE_SH1) + { + UML_TEST(block, mem(&m_sh2_state->sr), T); // test m_sh2_state->sr, T + UML_JMPc(block, COND_NZ, compiler->labelnum); // jnz compiler->labelnum + + disp = ((INT32)opcode << 24) >> 24; + m_sh2_state->ea = (desc->pc + 2) + disp * 2 + 2; // m_sh2_state->ea = destination + + templabel = compiler->labelnum; // save our label + compiler->labelnum++; // make sure the delay slot doesn't use it + generate_delay_slot(block, compiler, desc, m_sh2_state->ea-2); // delay slot only if the branch is taken + + generate_update_cycles(block, compiler, m_sh2_state->ea, TRUE); // + UML_HASHJMP(block, 0, m_sh2_state->ea, *m_nocode); // jmp m_sh2_state->ea + + UML_LABEL(block, templabel); // labelnum: + return TRUE; + } + break; + } + + return FALSE; +} + +int sh2_device::generate_group_12(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, UINT16 opcode, int in_delay_slot, UINT32 ovrpc) +{ + UINT32 scratch; + + switch (opcode & (15<<8)) + { + case 0<<8: // MOVBSG(opcode & 0xff); + scratch = (opcode & 0xff); + UML_ADD(block, I0, mem(&m_sh2_state->gbr), scratch); // add r0, gbr, scratch + UML_AND(block, I1, R32(0), 0xff); // and r1, R0, 0xff + UML_CALLH(block, *m_write8); // call write8 + + if (!in_delay_slot) + generate_update_cycles(block, compiler, desc->pc + 2, TRUE); + return TRUE; + + case 1<<8: // MOVWSG(opcode & 0xff); + scratch = (opcode & 0xff) * 2; + UML_ADD(block, I0, mem(&m_sh2_state->gbr), scratch); // add r0, gbr, scratch + UML_AND(block, I1, R32(0), 0xffff); // and r1, R0, 0xffff + UML_CALLH(block, *m_write16); // call write16 + + if (!in_delay_slot) + generate_update_cycles(block, compiler, desc->pc + 2, TRUE); + return TRUE; + + case 2<<8: // MOVLSG(opcode & 0xff); + scratch = (opcode & 0xff) * 4; + UML_ADD(block, I0, mem(&m_sh2_state->gbr), scratch); // add r0, gbr, scratch + UML_MOV(block, I1, R32(0)); // mov r1, R0 + UML_CALLH(block, *m_write32); // call write32 + + if (!in_delay_slot) + generate_update_cycles(block, compiler, desc->pc + 2, TRUE); + return TRUE; + + case 3<<8: // TRAPA(opcode & 0xff); + scratch = (opcode & 0xff) * 4; + UML_ADD(block, mem(&m_sh2_state->ea), mem(&m_sh2_state->vbr), scratch); // add ea, vbr, scratch + + UML_SUB(block, R32(15), R32(15), 4); // sub R15, R15, #4 + UML_MOV(block, I0, R32(15)); // mov r0, R15 + UML_MOV(block, I1, mem(&m_sh2_state->sr)); // mov r1, sr + UML_CALLH(block, *m_write32); // write32 + + UML_SUB(block, R32(15), R32(15), 4); // sub R15, R15, #4 + UML_MOV(block, I0, R32(15)); // mov r0, R15 + UML_MOV(block, I1, desc->pc+2); // mov r1, pc+2 + UML_CALLH(block, *m_write32); // write32 + + UML_MOV(block, I0, mem(&m_sh2_state->ea)); // mov r0, ea + UML_CALLH(block, *m_read32); // read32 + UML_HASHJMP(block, 0, I0, *m_nocode); // jmp (r0) + + return TRUE; + + case 4<<8: // MOVBLG(opcode & 0xff); + scratch = (opcode & 0xff); + UML_ADD(block, I0, mem(&m_sh2_state->gbr), scratch); // add r0, gbr, scratch + UML_CALLH(block, *m_read8); // call read16 + UML_SEXT(block, R32(0), I0, SIZE_BYTE); // sext R0, r0, BYTE + + if (!in_delay_slot) + generate_update_cycles(block, compiler, desc->pc + 2, TRUE); + return TRUE; + + case 5<<8: // MOVWLG(opcode & 0xff); + scratch = (opcode & 0xff) * 2; + UML_ADD(block, I0, mem(&m_sh2_state->gbr), scratch); // add r0, gbr, scratch + UML_CALLH(block, *m_read16); // call read16 + UML_SEXT(block, R32(0), I0, SIZE_WORD); // sext R0, r0, WORD + + if (!in_delay_slot) + generate_update_cycles(block, compiler, desc->pc + 2, TRUE); + return TRUE; + + case 6<<8: // MOVLLG(opcode & 0xff); + scratch = (opcode & 0xff) * 4; + UML_ADD(block, I0, mem(&m_sh2_state->gbr), scratch); // add r0, gbr, scratch + UML_CALLH(block, *m_read32); // call read32 + UML_MOV(block, R32(0), I0); // mov R0, r0 + + if (!in_delay_slot) + generate_update_cycles(block, compiler, desc->pc + 2, TRUE); + return TRUE; + + case 7<<8: // MOVA(opcode & 0xff); + scratch = (opcode & 0xff) * 4; + scratch += ((desc->pc + 4) & ~3); + + UML_MOV(block, R32(0), scratch); // mov R0, scratch + return TRUE; + + case 8<<8: // TSTI(opcode & 0xff); + scratch = opcode & 0xff; + + UML_AND(block, mem(&m_sh2_state->sr), mem(&m_sh2_state->sr), ~T); // and sr, sr, ~T (clear the T bit) + UML_AND(block, I0, R32(0), scratch); // and r0, R0, scratch + UML_CMP(block, I0, 0); // cmp r0, #0 + UML_JMPc(block, COND_NZ, compiler->labelnum); // jnz labelnum + + UML_OR(block, mem(&m_sh2_state->sr), mem(&m_sh2_state->sr), T); // or sr, sr, T + + UML_LABEL(block, compiler->labelnum++); // labelnum: + return TRUE; + + case 9<<8: // ANDI(opcode & 0xff); + UML_AND(block, R32(0), R32(0), opcode & 0xff); // and r0, r0, opcode & 0xff + return TRUE; + + case 10<<8: // XORI(opcode & 0xff); + UML_XOR(block, R32(0), R32(0), opcode & 0xff); // xor r0, r0, opcode & 0xff + return TRUE; + + case 11<<8: // ORI(opcode & 0xff); + UML_OR(block, R32(0), R32(0), opcode & 0xff); // or r0, r0, opcode & 0xff + return TRUE; + + case 12<<8: // TSTM(opcode & 0xff); + UML_AND(block, mem(&m_sh2_state->sr), mem(&m_sh2_state->sr), ~T); // and sr, sr, ~T (clear the T bit) + UML_ADD(block, I0, R32(0), mem(&m_sh2_state->gbr)); // add r0, R0, gbr + UML_CALLH(block, *m_read8); // read8 + + UML_AND(block, I0, I0, opcode & 0xff); + UML_CMP(block, I0, 0); // cmp r0, #0 + UML_JMPc(block, COND_NZ, compiler->labelnum); // jnz labelnum + + UML_OR(block, mem(&m_sh2_state->sr), mem(&m_sh2_state->sr), T); // or sr, sr, T + + UML_LABEL(block, compiler->labelnum++); // labelnum: + return TRUE; + + case 13<<8: // ANDM(opcode & 0xff); + UML_ADD(block, I0, R32(0), mem(&m_sh2_state->gbr)); // add r0, R0, gbr + UML_CALLH(block, *m_read8); // read8 + + UML_AND(block, I1, I0, opcode&0xff); // and r1, r0, #opcode&0xff + UML_ADD(block, I0, R32(0), mem(&m_sh2_state->gbr)); // add r0, R0, gbr + SETEA(0); + UML_CALLH(block, *m_write8); // write8 + return TRUE; + + case 14<<8: // XORM(opcode & 0xff); + UML_ADD(block, I0, R32(0), mem(&m_sh2_state->gbr)); // add r0, R0, gbr + UML_CALLH(block, *m_read8); // read8 + + UML_XOR(block, I1, I0, opcode&0xff); // xor r1, r0, #opcode&0xff + UML_ADD(block, I0, R32(0), mem(&m_sh2_state->gbr)); // add r0, R0, gbr + SETEA(0); + UML_CALLH(block, *m_write8); // write8 + return TRUE; + + case 15<<8: // ORM(opcode & 0xff); + UML_ADD(block, I0, R32(0), mem(&m_sh2_state->gbr)); // add r0, R0, gbr + UML_CALLH(block, *m_read8); // read8 + + UML_OR(block, I1, I0, opcode&0xff); // or r1, r0, #opcode&0xff + UML_ADD(block, I0, R32(0), mem(&m_sh2_state->gbr)); // add r0, R0, gbr + SETEA(0); + UML_CALLH(block, *m_write8); // write8 + return TRUE; + } + + return FALSE; +} + +/*************************************************************************** + CORE CALLBACKS +***************************************************************************/ + +/*------------------------------------------------- + sh2drc_set_options - configure DRC options +-------------------------------------------------*/ + +void sh2_device::sh2drc_set_options(UINT32 options) +{ + if (!(mconfig().options().drc() && !mconfig().m_force_no_drc)) return; + m_drcoptions = options; +} + + +/*------------------------------------------------- + sh2drc_add_pcflush - add a new address where + the PC must be flushed for speedups to work +-------------------------------------------------*/ + +void sh2_device::sh2drc_add_pcflush(offs_t address) +{ + if (!(mconfig().options().drc() && !mconfig().m_force_no_drc)) return; + + if (m_pcfsel < ARRAY_LENGTH(m_pcflushes)) + m_pcflushes[m_pcfsel++] = address; +} + + +/*------------------------------------------------- + sh2drc_add_fastram - add a new fastram + region +-------------------------------------------------*/ + +void sh2_device::sh2drc_add_fastram(offs_t start, offs_t end, UINT8 readonly, void *base) +{ + if (m_fastram_select < ARRAY_LENGTH(m_fastram)) + { + m_fastram[m_fastram_select].start = start; + m_fastram[m_fastram_select].end = end; + m_fastram[m_fastram_select].readonly = readonly; + m_fastram[m_fastram_select].base = base; + m_fastram_select++; + } +} diff --git a/src/devices/cpu/sh2/sh2fe.c b/src/devices/cpu/sh2/sh2fe.c new file mode 100644 index 00000000000..8ea8ccb82d3 --- /dev/null +++ b/src/devices/cpu/sh2/sh2fe.c @@ -0,0 +1,762 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/*************************************************************************** + + sh2fe.c + + Front end for SH-2 recompiler + +***************************************************************************/ + +#include "emu.h" +#include "sh2.h" +#include "sh2comn.h" +#include "cpu/drcfe.h" + + +/*************************************************************************** + INSTRUCTION PARSERS +***************************************************************************/ + +sh2_frontend::sh2_frontend(sh2_device *device, UINT32 window_start, UINT32 window_end, UINT32 max_sequence) + : drc_frontend(*device, window_start, window_end, max_sequence) + , m_sh2(device) +{ +} + +/*------------------------------------------------- + describe_instruction - build a description + of a single instruction +-------------------------------------------------*/ + +bool sh2_frontend::describe(opcode_desc &desc, const opcode_desc *prev) +{ + UINT16 opcode; + + /* fetch the opcode */ + opcode = desc.opptr.w[0] = m_sh2->m_direct->read_word(desc.physpc, SH2_CODE_XOR(0)); + + /* all instructions are 2 bytes and most are a single cycle */ + desc.length = 2; + desc.cycles = 1; + + switch (opcode>>12) + { + case 0: + return describe_group_0(desc, prev, opcode); + + case 1: // MOVLS4 + desc.regin[0] |= REGFLAG_R(Rn) | REGFLAG_R(Rm); + desc.flags |= OPFLAG_WRITES_MEMORY; + return true; + + case 2: + return describe_group_2(desc, prev, opcode); + + case 3: + return describe_group_3(desc, prev, opcode); + + case 4: + return describe_group_4(desc, prev, opcode); + + case 5: // MOVLL4 + desc.regin[0] |= REGFLAG_R(Rm); + desc.regout[0] |= REGFLAG_R(Rn); + desc.flags |= OPFLAG_READS_MEMORY; + return true; + + case 6: + return describe_group_6(desc, prev, opcode); + + case 7: // ADDI + desc.regin[0] |= REGFLAG_R(Rn); + desc.regout[0] |= REGFLAG_R(Rn); + return true; + + case 8: + return describe_group_8(desc, prev, opcode); + + case 9: // MOVWI + desc.regout[0] |= REGFLAG_R(Rn); + desc.flags |= OPFLAG_READS_MEMORY; + return true; + + case 11: // BSR + desc.regout[1] |= REGFLAG_PR; + // (intentional fallthrough - BSR is BRA with the addition of PR = the return address) + case 10: // BRA + { + INT32 disp = ((INT32)opcode << 20) >> 20; + + desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; + desc.targetpc = (desc.pc + 2) + disp * 2 + 2; + desc.delayslots = 1; + desc.cycles = 2; + return true; + } + + case 12: + return describe_group_12(desc, prev, opcode); + + case 13: // MOVLI + desc.regout[0] |= REGFLAG_R(Rn); + desc.flags |= OPFLAG_READS_MEMORY; + return true; + + case 14: // MOVI + desc.regout[0] |= REGFLAG_R(Rn); + return true; + + case 15: // NOP + return true; + } + + return false; +} + +bool sh2_frontend::describe_group_0(opcode_desc &desc, const opcode_desc *prev, UINT16 opcode) +{ + switch (opcode & 0x3F) + { + case 0x00: // NOP(); + case 0x01: // NOP(); + case 0x09: // NOP(); + case 0x10: // NOP(); + case 0x11: // NOP(); + case 0x13: // NOP(); + case 0x20: // NOP(); + case 0x21: // NOP(); + case 0x30: // NOP(); + case 0x31: // NOP(); + case 0x32: // NOP(); + case 0x33: // NOP(); + case 0x38: // NOP(); + case 0x39: // NOP(); + case 0x3a: // NOP(); + case 0x3b: // NOP(); + return true; + + case 0x02: // STCSR(Rn); + desc.regout[0] |= REGFLAG_R(Rn); + return true; + + case 0x03: // BSRF(Rn); + desc.regout[1] |= REGFLAG_PR; + + desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; + desc.targetpc = BRANCH_TARGET_DYNAMIC; + desc.delayslots = 1; + + return true; + + case 0x04: // MOVBS0(Rm, Rn); + case 0x05: // MOVWS0(Rm, Rn); + case 0x06: // MOVLS0(Rm, Rn); + case 0x14: // MOVBS0(Rm, Rn); + case 0x15: // MOVWS0(Rm, Rn); + case 0x16: // MOVLS0(Rm, Rn); + case 0x24: // MOVBS0(Rm, Rn); + case 0x25: // MOVWS0(Rm, Rn); + case 0x26: // MOVLS0(Rm, Rn); + case 0x34: // MOVBS0(Rm, Rn); + case 0x35: // MOVWS0(Rm, Rn); + case 0x36: // MOVLS0(Rm, Rn); + desc.regin[0] |= REGFLAG_R(Rm) | REGFLAG_R(Rn) | REGFLAG_R(0); + desc.flags |= OPFLAG_READS_MEMORY; + return true; + + case 0x07: // MULL(Rm, Rn); + case 0x17: // MULL(Rm, Rn); + case 0x27: // MULL(Rm, Rn); + case 0x37: // MULL(Rm, Rn); + desc.regin[0] |= REGFLAG_R(Rn) | REGFLAG_R(Rm); + desc.regout[1] |= REGFLAG_MACL; + desc.cycles = 2; + return true; + + case 0x08: // CLRT(); + desc.regout[1] |= REGFLAG_SR; + return true; + + case 0x0a: // STSMACH(Rn); + desc.regout[0] |= REGFLAG_R(Rn); + desc.regout[1] |= REGFLAG_MACH; + return true; + + case 0x0b: // RTS(); + desc.regin[1] |= REGFLAG_PR; + + desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; + desc.targetpc = BRANCH_TARGET_DYNAMIC; + desc.delayslots = 1; + desc.cycles = 2; + + return true; + + case 0x0c: // MOVBL0(Rm, Rn); + case 0x0d: // MOVWL0(Rm, Rn); + case 0x0e: // MOVLL0(Rm, Rn); + case 0x1c: // MOVBL0(Rm, Rn); + case 0x1d: // MOVWL0(Rm, Rn); + case 0x1e: // MOVLL0(Rm, Rn); + case 0x2c: // MOVBL0(Rm, Rn); + case 0x2d: // MOVWL0(Rm, Rn); + case 0x2e: // MOVLL0(Rm, Rn); + case 0x3c: // MOVBL0(Rm, Rn); + case 0x3d: // MOVWL0(Rm, Rn); + case 0x3e: // MOVLL0(Rm, Rn); + desc.regin[0] |= REGFLAG_R(Rm) | REGFLAG_R(0); + desc.regout[0] |= REGFLAG_R(Rn); + desc.flags |= OPFLAG_READS_MEMORY; + return true; + + case 0x0f: // MAC_L(Rm, Rn); + case 0x1f: // MAC_L(Rm, Rn); + case 0x2f: // MAC_L(Rm, Rn); + case 0x3f: // MAC_L(Rm, Rn); + desc.regin[0] |= REGFLAG_R(Rm) | REGFLAG_R(Rn); + desc.regout[1] |= REGFLAG_MACL | REGFLAG_MACH; + desc.cycles = 3; + return true; + + case 0x12: // STCGBR(Rn); + desc.regout[0] |= REGFLAG_R(Rn); + desc.regin[1] |= REGFLAG_GBR; + return true; + + case 0x18: // SETT(); + desc.regout[1] |= REGFLAG_SR; + return true; + + case 0x19: // DIV0U(); + desc.regout[1] |= REGFLAG_SR; + return true; + + case 0x1a: // STSMACL(Rn); + desc.regin[1] |= REGFLAG_MACL; + desc.regout[0] |= REGFLAG_R(Rn); + return true; + + case 0x1b: // SLEEP(); + desc.cycles = 3; + return true; + + case 0x22: // STCVBR(Rn); + desc.regin[0] |= REGFLAG_R(Rn); + desc.regout[1] |= REGFLAG_VBR; + return true; + + case 0x23: // BRAF(Rn); + desc.regin[0] |= REGFLAG_R(Rm); + desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; + desc.targetpc = BRANCH_TARGET_DYNAMIC; + desc.delayslots = 1; + desc.cycles = 2; + return true; + + case 0x28: // CLRMAC(); + desc.regout[1] |= REGFLAG_MACL | REGFLAG_MACH; + return true; + + case 0x29: // MOVT(Rn); + desc.regin[1] |= REGFLAG_SR; + desc.regout[0] |= REGFLAG_R(Rn); + return true; + + case 0x2a: // STSPR(Rn); + desc.regin[1] |= REGFLAG_PR; + desc.regout[0] |= REGFLAG_R(Rn); + return true; + + case 0x2b: // RTE(); + desc.regin[0] |= REGFLAG_R(15); + desc.regout[0] |= REGFLAG_R(15); + + desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE | OPFLAG_CAN_EXPOSE_EXTERNAL_INT; + desc.targetpc = BRANCH_TARGET_DYNAMIC; + desc.delayslots = 1; + desc.cycles = 4; + + return true; + } + + return false; +} + +bool sh2_frontend::describe_group_2(opcode_desc &desc, const opcode_desc *prev, UINT16 opcode) +{ + switch (opcode & 15) + { + case 0: // MOVBS(Rm, Rn); + case 1: // MOVWS(Rm, Rn); + case 2: // MOVLS(Rm, Rn); + desc.regin[0] |= REGFLAG_R(Rm) | REGFLAG_R(Rn); + desc.flags |= OPFLAG_WRITES_MEMORY; + return true; + + case 3: // NOP(); + return true; + + case 4: // MOVBM(Rm, Rn); + case 5: // MOVWM(Rm, Rn); + case 6: // MOVLM(Rm, Rn); + case 13: // XTRCT(Rm, Rn); + desc.regin[0] |= REGFLAG_R(Rm) | REGFLAG_R(Rn); + desc.regout[0] |= REGFLAG_R(Rn); + desc.flags |= OPFLAG_WRITES_MEMORY; + return true; + + case 7: // DIV0S(Rm, Rn); + case 8: // TST(Rm, Rn); + case 12: // CMPSTR(Rm, Rn); + desc.regin[0] |= REGFLAG_R(Rm) | REGFLAG_R(Rn); + desc.regout[1] |= REGFLAG_SR; + return true; + + case 9: // AND(Rm, Rn); + case 10: // XOR(Rm, Rn); + case 11: // OR(Rm, Rn); + desc.regin[0] |= REGFLAG_R(Rm) | REGFLAG_R(Rn); + desc.regout[0] |= REGFLAG_R(Rn); + return true; + + case 14: // MULU(Rm, Rn); + case 15: // MULS(Rm, Rn); + desc.regin[0] |= REGFLAG_R(Rm) | REGFLAG_R(Rn); + desc.regout[1] |= REGFLAG_MACL | REGFLAG_MACH; + desc.cycles = 2; + return true; + } + + return false; +} + +bool sh2_frontend::describe_group_3(opcode_desc &desc, const opcode_desc *prev, UINT16 opcode) +{ + switch (opcode & 15) + { + case 0: // CMPEQ(Rm, Rn); + case 2: // CMPHS(Rm, Rn); + case 3: // CMPGE(Rm, Rn); + case 6: // CMPHI(Rm, Rn); + case 7: // CMPGT(Rm, Rn); + desc.regin[0] |= REGFLAG_R(Rm) | REGFLAG_R(Rn); + desc.regout[1] |= REGFLAG_SR; + return true; + + case 1: // NOP(); + case 9: // NOP(); + return true; + + case 4: // DIV1(Rm, Rn); + desc.regin[0] |= REGFLAG_R(Rm) | REGFLAG_R(Rn); + desc.regout[0] |= REGFLAG_R(Rn); + desc.regout[1] |= REGFLAG_SR; + return true; + + case 5: // DMULU(Rm, Rn); + case 13: // DMULS(Rm, Rn); + desc.regin[0] |= REGFLAG_R(Rm) | REGFLAG_R(Rn); + desc.regout[1] |= REGFLAG_MACL | REGFLAG_MACH; + desc.cycles = 2; + return true; + + case 8: // SUB(Rm, Rn); + case 12: // ADD(Rm, Rn); + desc.regin[0] |= REGFLAG_R(Rm) | REGFLAG_R(Rn); + desc.regout[0] |= REGFLAG_R(Rn); + return true; + + case 10: // SUBC(Rm, Rn); + case 11: // SUBV(Rm, Rn); + case 14: // ADDC(Rm, Rn); + case 15: // ADDV(Rm, Rn); + desc.regin[0] |= REGFLAG_R(Rm) | REGFLAG_R(Rn); + desc.regin[1] |= REGFLAG_SR; + desc.regout[0] |= REGFLAG_R(Rn); + desc.regout[1] |= REGFLAG_SR; + return true; + } + return false; +} + +bool sh2_frontend::describe_group_4(opcode_desc &desc, const opcode_desc *prev, UINT16 opcode) +{ + switch (opcode & 0x3F) + { + case 0x00: // SHLL(Rn); + case 0x01: // SHLR(Rn); + case 0x04: // ROTL(Rn); + case 0x05: // ROTR(Rn); + desc.regin[0] |= REGFLAG_R(Rn); + desc.regout[0] |= REGFLAG_R(Rn); + desc.regout[1] |= REGFLAG_SR; + return true; + + case 0x02: // STSMMACH(Rn); + desc.regin[0] |= REGFLAG_R(Rn); + desc.regin[1] |= REGFLAG_MACH; + desc.regout[0] |= REGFLAG_R(Rn); + desc.flags |= OPFLAG_WRITES_MEMORY; + return true; + + case 0x03: // STCMSR(Rn); + desc.regin[0] |= REGFLAG_R(Rn); + desc.regout[0] |= REGFLAG_R(Rn); + desc.cycles = 2; + desc.flags |= OPFLAG_WRITES_MEMORY; + return true; + + case 0x06: // LDSMMACH(Rn); + desc.regin[0] |= REGFLAG_R(Rn); + desc.regout[0] |= REGFLAG_R(Rn); + desc.regout[1] |= REGFLAG_MACH; + desc.flags |= OPFLAG_READS_MEMORY; + return true; + + case 0x07: // LDCMSR(Rn); + desc.regin[0] |= REGFLAG_R(Rn); + desc.regout[0] |= REGFLAG_R(Rn); + desc.regout[1] |= REGFLAG_SR; + desc.cycles = 3; + desc.flags |= OPFLAG_READS_MEMORY | OPFLAG_CAN_EXPOSE_EXTERNAL_INT | OPFLAG_END_SEQUENCE; + return true; + + case 0x08: // SHLL2(Rn); + case 0x09: // SHLR2(Rn); + case 0x18: // SHLL8(Rn); + case 0x19: // SHLR8(Rn); + case 0x28: // SHLL16(Rn); + case 0x29: // SHLR16(Rn); + desc.regin[0] |= REGFLAG_R(Rn); + desc.regout[0] |= REGFLAG_R(Rn); + return true; + + case 0x0a: // LDSMACH(Rn); + desc.regin[0] |= REGFLAG_R(Rn); + desc.regout[1] |= REGFLAG_MACH; + return true; + + case 0x0b: // JSR(Rn); + desc.regin[0] |= REGFLAG_R(Rn); + desc.regout[1] |= REGFLAG_PR; + desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; + desc.targetpc = BRANCH_TARGET_DYNAMIC; + desc.delayslots = 1; + return true; + + case 0x0e: // LDCSR(Rn); + desc.regin[0] |= REGFLAG_R(Rn); + desc.regout[1] |= REGFLAG_SR; + desc.flags |= OPFLAG_CAN_EXPOSE_EXTERNAL_INT | OPFLAG_END_SEQUENCE; + return true; + + case 0x0f: // MAC_W(Rm, Rn); + case 0x1f: // MAC_W(Rm, Rn); + case 0x2f: // MAC_W(Rm, Rn); + case 0x3f: // MAC_W(Rm, Rn); + desc.regin[0] |= REGFLAG_R(Rm) | REGFLAG_R(Rn); + desc.regin[1] |= REGFLAG_MACL | REGFLAG_MACH; + desc.regout[0] |= REGFLAG_R(Rm) | REGFLAG_R(Rn); + desc.regout[1] |= REGFLAG_MACL | REGFLAG_MACH; + desc.cycles = 3; + return true; + + case 0x10: // DT(Rn); + desc.regin[0] |= REGFLAG_R(Rn); + desc.regin[1] |= REGFLAG_SR; + desc.regout[0] |= REGFLAG_R(Rn); + desc.regout[1] |= REGFLAG_SR; + return true; + + case 0x11: // CMPPZ(Rn); + case 0x15: // CMPPL(Rn); + desc.regin[0] |= REGFLAG_R(Rn); + desc.regin[1] |= REGFLAG_SR; + desc.regout[1] |= REGFLAG_SR; + return true; + + case 0x12: // STSMMACL(Rn); + desc.regin[0] |= REGFLAG_R(Rn); + desc.regin[1] |= REGFLAG_MACL; + desc.regout[0] |= REGFLAG_R(Rn); + desc.flags |= OPFLAG_WRITES_MEMORY; + return true; + + case 0x13: // STCMGBR(Rn); + desc.regin[0] |= REGFLAG_R(Rn); + desc.regin[1] |= REGFLAG_GBR; + desc.regout[0] |= REGFLAG_R(Rn); + desc.flags |= OPFLAG_WRITES_MEMORY; + return true; + + case 0x16: // LDSMMACL(Rn); + desc.regin[0] |= REGFLAG_R(Rm) | REGFLAG_R(Rn); + desc.regout[0] |= REGFLAG_R(Rm) | REGFLAG_R(Rn); + desc.regout[1] |= REGFLAG_MACL; + desc.flags |= OPFLAG_READS_MEMORY; + return true; + + case 0x17: // LDCMGBR(Rn); + desc.regin[0] |= REGFLAG_R(Rn); + desc.regout[0] |= REGFLAG_R(Rn); + desc.regout[1] |= REGFLAG_GBR; + desc.flags |= OPFLAG_READS_MEMORY; + return true; + + case 0x1a: // LDSMACL(Rn); + desc.regin[0] |= REGFLAG_R(Rn); + desc.regout[1] |= REGFLAG_MACL; + return true; + + case 0x1b: // TAS(Rn); + desc.regin[0] |= REGFLAG_R(Rn); + desc.regin[1] |= REGFLAG_SR; + desc.regout[1] |= REGFLAG_SR; + desc.cycles = 4; + desc.flags |= OPFLAG_READS_MEMORY | OPFLAG_WRITES_MEMORY; + return true; + + case 0x1e: // LDCGBR(Rn); + desc.regin[0] |= REGFLAG_R(Rn); + desc.regout[1] |= REGFLAG_GBR; + return true; + + case 0x20: // SHAL(Rn); + case 0x21: // SHAR(Rn); + desc.regin[0] |= REGFLAG_R(Rn); + desc.regout[0] |= REGFLAG_R(Rn); + desc.regout[1] |= REGFLAG_SR; + return true; + + case 0x22: // STSMPR(Rn); + desc.regin[0] |= REGFLAG_R(Rn); + desc.regin[1] |= REGFLAG_PR; + desc.regout[0] |= REGFLAG_R(Rn); + desc.flags |= OPFLAG_WRITES_MEMORY; + return true; + + case 0x23: // STCMVBR(Rn); + desc.regin[0] |= REGFLAG_R(Rn); + desc.regin[1] |= REGFLAG_VBR; + desc.regout[0] |= REGFLAG_R(Rn); + desc.flags |= OPFLAG_WRITES_MEMORY; + return true; + + case 0x24: // ROTCL(Rn); + case 0x25: // ROTCR(Rn); + desc.regin[0] |= REGFLAG_R(Rn); + desc.regin[1] |= REGFLAG_SR; + desc.regout[0] |= REGFLAG_R(Rn); + desc.regout[1] |= REGFLAG_SR; + return true; + + case 0x26: // LDSMPR(Rn); + desc.regin[0] |= REGFLAG_R(Rn); + desc.regout[0] |= REGFLAG_R(Rn); + desc.regout[1] |= REGFLAG_PR; + desc.flags |= OPFLAG_READS_MEMORY; + return true; + + case 0x27: // LDCMVBR(Rn); + desc.regin[0] |= REGFLAG_R(Rn); + desc.regout[0] |= REGFLAG_R(Rn); + desc.regout[1] |= REGFLAG_VBR; + desc.flags |= OPFLAG_READS_MEMORY; + return true; + + case 0x2a: // LDSPR(Rn); + desc.regin[0] |= REGFLAG_R(Rn); + desc.regout[1] |= REGFLAG_PR; + return true; + + case 0x2b: // JMP(Rm); + desc.regin[0] |= REGFLAG_R(Rm); + desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; + desc.targetpc = BRANCH_TARGET_DYNAMIC; + desc.delayslots = 1; + return true; + + case 0x2e: // LDCVBR(Rn); + desc.regin[0] |= REGFLAG_R(Rn); + desc.regout[1] |= REGFLAG_VBR; + return true; + + case 0x0c: // NOP(); + case 0x0d: // NOP(); + case 0x14: // NOP(); + case 0x1c: // NOP(); + case 0x1d: // NOP(); + case 0x2c: // NOP(); + case 0x2d: // NOP(); + case 0x30: // NOP(); + case 0x31: // NOP(); + case 0x32: // NOP(); + case 0x33: // NOP(); + case 0x34: // NOP(); + case 0x35: // NOP(); + case 0x36: // NOP(); + case 0x37: // NOP(); + case 0x38: // NOP(); + case 0x39: // NOP(); + case 0x3a: // NOP(); + case 0x3b: // NOP(); + case 0x3c: // NOP(); + case 0x3d: // NOP(); + case 0x3e: // NOP(); + return true; + } + + return false; +} + +bool sh2_frontend::describe_group_6(opcode_desc &desc, const opcode_desc *prev, UINT16 opcode) +{ + switch (opcode & 15) + { + case 0: // MOVBL(Rm, Rn); + case 1: // MOVWL(Rm, Rn); + case 2: // MOVLL(Rm, Rn); + case 3: // MOV(Rm, Rn); + case 7: // NOT(Rm, Rn); + case 9: // SWAPW(Rm, Rn); + case 11: // NEG(Rm, Rn); + case 12: // EXTUB(Rm, Rn); + case 13: // EXTUW(Rm, Rn); + case 14: // EXTSB(Rm, Rn); + case 15: // EXTSW(Rm, Rn); + desc.regin[0] |= REGFLAG_R(Rm); + desc.regout[0] |= REGFLAG_R(Rn); + return true; + + case 4: // MOVBP(Rm, Rn); + case 5: // MOVWP(Rm, Rn); + case 6: // MOVLP(Rm, Rn); + desc.regin[0] |= REGFLAG_R(Rm) | REGFLAG_R(Rn); + desc.regout[0] |= REGFLAG_R(Rn); + desc.flags |= OPFLAG_READS_MEMORY; + return true; + + case 8: // SWAPB(Rm, Rn); + desc.regin[0] |= REGFLAG_R(Rm) | REGFLAG_R(Rn); + desc.regout[0] |= REGFLAG_R(Rn); + return true; + + case 10: // NEGC(Rm, Rn); + desc.regin[0] |= REGFLAG_R(Rm); + desc.regout[0] |= REGFLAG_R(Rn); + desc.regout[1] |= REGFLAG_SR; + return true; + } + return false; +} + +bool sh2_frontend::describe_group_8(opcode_desc &desc, const opcode_desc *prev, UINT16 opcode) +{ + INT32 disp; + + switch ( opcode & (15<<8) ) + { + case 0 << 8: // MOVBS4(opcode & 0x0f, Rm); + case 1 << 8: // MOVWS4(opcode & 0x0f, Rm); + desc.regin[0] |= REGFLAG_R(Rm) | REGFLAG_R(0); + desc.flags |= OPFLAG_WRITES_MEMORY; + return true; + + case 2<< 8: // NOP(); + case 3<< 8: // NOP(); + case 6<< 8: // NOP(); + case 7<< 8: // NOP(); + case 10<< 8: // NOP(); + case 12<< 8: // NOP(); + case 14<< 8: // NOP(); + return true; + + case 4<< 8: // MOVBL4(Rm, opcode & 0x0f); + case 5<< 8: // MOVWL4(Rm, opcode & 0x0f); + desc.regin[0] |= REGFLAG_R(Rm); + desc.regout[0] |= REGFLAG_R(0); + desc.flags |= OPFLAG_READS_MEMORY; + return true; + + case 8<< 8: // CMPIM(opcode & 0xff); + desc.regin[0] |= REGFLAG_R(Rm); + desc.regin[1] |= REGFLAG_SR; + desc.regout[1] |= REGFLAG_SR; + return true; + + case 9<< 8: // BT(opcode & 0xff); + case 11<< 8: // BF(opcode & 0xff); + desc.flags |= OPFLAG_IS_CONDITIONAL_BRANCH; + desc.cycles = 3; + disp = ((INT32)opcode << 24) >> 24; + desc.targetpc = (desc.pc + 2) + disp * 2 + 2; + return true; + + case 13<< 8: // BTS(opcode & 0xff); + case 15<< 8: // BFS(opcode & 0xff); + desc.flags |= OPFLAG_IS_CONDITIONAL_BRANCH; + desc.cycles = 2; + disp = ((INT32)opcode << 24) >> 24; + desc.targetpc = (desc.pc + 2) + disp * 2 + 2; + desc.delayslots = 1; + return true; + } + + return false; +} + +bool sh2_frontend::describe_group_12(opcode_desc &desc, const opcode_desc *prev, UINT16 opcode) +{ + switch (opcode & (15<<8)) + { + case 0<<8: // MOVBSG(opcode & 0xff); + case 1<<8: // MOVWSG(opcode & 0xff); + case 2<<8: // MOVLSG(opcode & 0xff); + desc.regin[0] |= REGFLAG_R(0); + desc.flags |= OPFLAG_WRITES_MEMORY; + return true; + + case 3<<8: // TRAPA(opcode & 0xff); + desc.regin[0] |= REGFLAG_R(15); + desc.regin[1] |= REGFLAG_VBR; + desc.regout[0] |= REGFLAG_R(15); + desc.cycles = 8; + desc.targetpc = BRANCH_TARGET_DYNAMIC; + desc.flags |= OPFLAG_READS_MEMORY | OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; + return true; + + case 4<<8: // MOVBLG(opcode & 0xff); + case 5<<8: // MOVWLG(opcode & 0xff); + case 6<<8: // MOVLLG(opcode & 0xff); + case 7<<8: // MOVA(opcode & 0xff); + desc.regout[0] |= REGFLAG_R(0); + desc.flags |= OPFLAG_READS_MEMORY; + return true; + + case 8<<8: // TSTI(opcode & 0xff); + desc.regin[0] |= REGFLAG_R(0); + desc.regin[1] |= REGFLAG_SR; + desc.regout[1] |= REGFLAG_SR; + return true; + + case 9<<8: // ANDI(opcode & 0xff); + case 10<<8: // XORI(opcode & 0xff); + case 11<<8: // ORI(opcode & 0xff); + desc.regin[0] |= REGFLAG_R(0); + desc.regout[0] |= REGFLAG_R(0); + return true; + + case 12<<8: // TSTM(opcode & 0xff); + case 13<<8: // ANDM(opcode & 0xff); + case 14<<8: // XORM(opcode & 0xff); + case 15<<8: // ORM(opcode & 0xff); + desc.regin[0] |= REGFLAG_R(0); + desc.regin[1] |= REGFLAG_SR | REGFLAG_GBR; + desc.regout[1] |= REGFLAG_SR; + desc.flags |= OPFLAG_READS_MEMORY; + return true; + } + + return false; +} diff --git a/src/devices/cpu/sh4/sh3comn.c b/src/devices/cpu/sh4/sh3comn.c new file mode 100644 index 00000000000..1fcacaa9165 --- /dev/null +++ b/src/devices/cpu/sh4/sh3comn.c @@ -0,0 +1,681 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/* Handlers for SH3 internals */ + +#include "emu.h" +#include "debugger.h" +#include "sh4.h" +#include "sh4comn.h" +#include "sh3comn.h" +#include "sh4tmu.h" +#include "sh4dmac.h" + +/* High internal area (ffffxxxx) */ + +WRITE32_MEMBER( sh3_base_device::sh3_internal_high_w ) +{ + COMBINE_DATA(&m_sh3internal_upper[offset]); + + switch (offset) + { + case SH3_ICR0_IPRA_ADDR: + if (mem_mask & 0xffff0000) + { + logerror("'%s' (%08x): INTC internal write to %08x = %08x & %08x (SH3_ICR0_IPRA_ADDR - ICR0)\n",tag(), m_pc & AM,(offset *4)+SH3_UPPER_REGBASE,data,mem_mask); + } + + if (mem_mask & 0x0000ffff) + { + logerror("'%s' (%08x): INTC internal write to %08x = %08x & %08x (SH3_ICR0_IPRA_ADDR - IPRA)\n",tag(), m_pc & AM,(offset *4)+SH3_UPPER_REGBASE,data,mem_mask); + sh4_handler_ipra_w(data&0xffff,mem_mask&0xffff); + } + + break; + + case SH3_IPRB_ADDR: + logerror("'%s' (%08x): INTC internal write to %08x = %08x & %08x (SH3_IPRB_ADDR)\n",tag(), m_pc & AM,(offset *4)+SH3_UPPER_REGBASE,data,mem_mask); + break; + + case SH3_TOCR_TSTR_ADDR: + logerror("'%s' (%08x): TMU internal write to %08x = %08x & %08x (SH3_TOCR_TSTR_ADDR)\n",tag(), m_pc & AM,(offset *4)+SH3_UPPER_REGBASE,data,mem_mask); + if (mem_mask&0xff000000) + { + sh4_handle_tocr_addr_w((data>>24)&0xffff, (mem_mask>>24)&0xff); + } + if (mem_mask&0x0000ff00) + { + sh4_handle_tstr_addr_w((data>>8)&0xff, (mem_mask>>8)&0xff); + } + if (mem_mask&0x00ff00ff) + { + fatalerror("SH3_TOCR_TSTR_ADDR unused bits accessed (write)\n"); + } + break; + case SH3_TCOR0_ADDR: sh4_handle_tcor0_addr_w(data, mem_mask);break; + case SH3_TCOR1_ADDR: sh4_handle_tcor1_addr_w(data, mem_mask);break; + case SH3_TCOR2_ADDR: sh4_handle_tcor2_addr_w(data, mem_mask);break; + case SH3_TCNT0_ADDR: sh4_handle_tcnt0_addr_w(data, mem_mask);break; + case SH3_TCNT1_ADDR: sh4_handle_tcnt1_addr_w(data, mem_mask);break; + case SH3_TCNT2_ADDR: sh4_handle_tcnt2_addr_w(data, mem_mask);break; + case SH3_TCR0_ADDR: sh4_handle_tcr0_addr_w(data>>16, mem_mask>>16);break; + case SH3_TCR1_ADDR: sh4_handle_tcr1_addr_w(data>>16, mem_mask>>16);break; + case SH3_TCR2_ADDR: sh4_handle_tcr2_addr_w(data>>16, mem_mask>>16);break; + case SH3_TCPR2_ADDR: sh4_handle_tcpr2_addr_w(data, mem_mask);break; + + default: + logerror("'%s' (%08x): unmapped internal write to %08x = %08x & %08x (unk)\n",tag(), m_pc & AM,(offset *4)+SH3_UPPER_REGBASE,data,mem_mask); + break; + + } + + + + +} + +READ32_MEMBER( sh3_base_device::sh3_internal_high_r ) +{ + UINT32 ret = 0; + + switch (offset) + { + case SH3_ICR0_IPRA_ADDR: + logerror("'%s' (%08x): INTC internal read from %08x mask %08x (SH3_ICR0_IPRA_ADDR - %08x)\n",tag(), m_pc & AM,(offset *4)+SH3_UPPER_REGBASE,mem_mask, m_sh3internal_upper[offset]); + return (m_sh3internal_upper[offset] & 0xffff0000) | (m_SH4_IPRA & 0xffff); + + case SH3_IPRB_ADDR: + logerror("'%s' (%08x): INTC internal read from %08x mask %08x (SH3_IPRB_ADDR - %08x)\n",tag(), m_pc & AM,(offset *4)+SH3_UPPER_REGBASE,mem_mask, m_sh3internal_upper[offset]); + return m_sh3internal_upper[offset]; + + case SH3_TOCR_TSTR_ADDR: + + if (mem_mask&0xff00000) + { + ret |= (sh4_handle_tocr_addr_r(mem_mask)&0xff)<<24; + } + if (mem_mask&0x0000ff00) + { + ret |= (sh4_handle_tstr_addr_r(mem_mask)&0xff)<<8; + } + if (mem_mask&0x00ff00ff) + { + fatalerror("SH3_TOCR_TSTR_ADDR unused bits accessed (read)\n"); + } + return ret; + case SH3_TCOR0_ADDR: return sh4_handle_tcor0_addr_r(mem_mask); + case SH3_TCOR1_ADDR: return sh4_handle_tcor1_addr_r(mem_mask); + case SH3_TCOR2_ADDR: return sh4_handle_tcor2_addr_r(mem_mask); + case SH3_TCNT0_ADDR: return sh4_handle_tcnt0_addr_r(mem_mask); + case SH3_TCNT1_ADDR: return sh4_handle_tcnt1_addr_r(mem_mask); + case SH3_TCNT2_ADDR: return sh4_handle_tcnt2_addr_r(mem_mask); + case SH3_TCR0_ADDR: return sh4_handle_tcr0_addr_r(mem_mask)<<16; + case SH3_TCR1_ADDR: return sh4_handle_tcr1_addr_r(mem_mask)<<16; + case SH3_TCR2_ADDR: return sh4_handle_tcr2_addr_r(mem_mask)<<16; + case SH3_TCPR2_ADDR: return sh4_handle_tcpr2_addr_r(mem_mask); + + + case SH3_TRA_ADDR: + logerror("'%s' (%08x): unmapped internal read from %08x mask %08x (SH3 TRA - %08x)\n",tag(), m_pc & AM,(offset *4)+SH3_UPPER_REGBASE,mem_mask, m_sh3internal_upper[offset]); + return m_sh3internal_upper[offset]; + + case SH3_EXPEVT_ADDR: + logerror("'%s' (%08x): unmapped internal read from %08x mask %08x (SH3 EXPEVT - %08x)\n",tag(), m_pc & AM,(offset *4)+SH3_UPPER_REGBASE,mem_mask, m_sh3internal_upper[offset]); + return m_sh3internal_upper[offset]; + + case SH3_INTEVT_ADDR: + logerror("'%s' (%08x): unmapped internal read from %08x mask %08x (SH3 INTEVT - %08x)\n",tag(), m_pc & AM,(offset *4)+SH3_UPPER_REGBASE,mem_mask, m_sh3internal_upper[offset]); + fatalerror("INTEVT unsupported on SH3\n"); + // never executed + //return m_sh3internal_upper[offset]; + + + default: + logerror("'%s' (%08x): unmapped internal read from %08x mask %08x\n",tag(), m_pc & AM,(offset *4)+SH3_UPPER_REGBASE,mem_mask); + return m_sh3internal_upper[offset]; + } +} + + +READ32_MEMBER( sh3_base_device::sh3_internal_r ) +{ + if (offset<0x1000) + { + switch (offset) + { + case SH3_SAR0_ADDR: return sh4_handle_sar0_addr_r(mem_mask); + case SH3_SAR1_ADDR: return sh4_handle_sar1_addr_r(mem_mask); + case SH3_SAR2_ADDR: return sh4_handle_sar2_addr_r(mem_mask); + case SH3_SAR3_ADDR: return sh4_handle_sar3_addr_r(mem_mask); + case SH3_DAR0_ADDR: return sh4_handle_dar0_addr_r(mem_mask); + case SH3_DAR1_ADDR: return sh4_handle_dar1_addr_r(mem_mask); + case SH3_DAR2_ADDR: return sh4_handle_dar2_addr_r(mem_mask); + case SH3_DAR3_ADDR: return sh4_handle_dar3_addr_r(mem_mask); + case SH3_DMATCR0_ADDR: return sh4_handle_dmatcr0_addr_r(mem_mask); + case SH3_DMATCR1_ADDR: return sh4_handle_dmatcr1_addr_r(mem_mask); + case SH3_DMATCR2_ADDR: return sh4_handle_dmatcr2_addr_r(mem_mask); + case SH3_DMATCR3_ADDR: return sh4_handle_dmatcr3_addr_r(mem_mask); + case SH3_CHCR0_ADDR: return sh4_handle_chcr0_addr_r(mem_mask); + case SH3_CHCR1_ADDR: return sh4_handle_chcr1_addr_r(mem_mask); + case SH3_CHCR2_ADDR: return sh4_handle_chcr2_addr_r(mem_mask); + case SH3_CHCR3_ADDR: return sh4_handle_chcr3_addr_r(mem_mask); + case SH3_DMAOR_ADDR: return sh4_handle_dmaor_addr_r(mem_mask)<<16; + + + case INTEVT2: + { + // logerror("'%s' (%08x): unmapped internal read from %08x mask %08x (INTEVT2)\n",tag(), m_pc & AM,(offset *4)+0x4000000,mem_mask); + return m_sh3internal_lower[offset]; + } + + + case IRR0_IRR1: + { + { + if (mem_mask & 0xff000000) + { + logerror("'%s' (%08x): unmapped internal read from %08x mask %08x (IRR0)\n",tag(), m_pc & AM,(offset *4)+0x4000000,mem_mask); + return m_sh3internal_lower[offset]; + } + + if (mem_mask & 0x0000ff00) + { + logerror("'%s' (%08x): unmapped internal read from %08x mask %08x (IRR1)\n",tag(), m_pc & AM,(offset *4)+0x4000000,mem_mask); + return m_sh3internal_lower[offset]; + } + + fatalerror("'%s' (%08x): unmapped internal read from %08x mask %08x (IRR0/1 unused bits)\n",tag(), m_pc & AM,(offset *4)+0x4000000,mem_mask); + } + } + + case PADR_PBDR: + { + if (mem_mask & 0xffff0000) + { + //logerror("'%s' (%08x): unmapped internal read from %08x mask %08x (PADR)\n",tag(), m_pc & AM,(offset *4)+0x4000000,mem_mask); + return m_io->read_qword(SH3_PORT_A)<<24; + } + + if (mem_mask & 0x0000ffff) + { + //logerror("'%s' (%08x): unmapped internal read from %08x mask %08x (PBDR)\n",tag(), m_pc & AM,(offset *4)+0x4000000,mem_mask); + return m_io->read_qword(SH3_PORT_B)<<8; + } + } + break; + + case PCDR_PDDR: + { + if (mem_mask & 0xffff0000) + { + //logerror("'%s' (%08x): unmapped internal read from %08x mask %08x (PCDR)\n",tag(), m_pc & AM,(offset *4)+0x4000000,mem_mask); + return m_io->read_qword(SH3_PORT_C)<<24; + } + + if (mem_mask & 0x0000ffff) + { + //logerror("'%s' (%08x): unmapped internal read from %08x mask %08x (PDDR)\n",tag(), m_pc & AM,(offset *4)+0x4000000,mem_mask); + return m_io->read_qword(SH3_PORT_D)<<8; + } + } + break; + + case PEDR_PFDR: + { + if (mem_mask & 0xffff0000) + { + //logerror("'%s' (%08x): unmapped internal read from %08x mask %08x (PEDR)\n",tag(), m_pc & AM,(offset *4)+0x4000000,mem_mask); + return m_io->read_qword(SH3_PORT_E)<<24; + } + + if (mem_mask & 0x0000ffff) + { + //logerror("'%s' (%08x): unmapped internal read from %08x mask %08x (PFDR)\n",tag(), m_pc & AM,(offset *4)+0x4000000,mem_mask); + return m_io->read_qword(SH3_PORT_F)<<8; + } + } + break; + + case PGDR_PHDR: + { + if (mem_mask & 0xffff0000) + { + //logerror("'%s' (%08x): unmapped internal read from %08x mask %08x (PGDR)\n",tag(), m_pc & AM,(offset *4)+0x4000000,mem_mask); + return m_io->read_qword(SH3_PORT_G)<<24; + } + + if (mem_mask & 0x0000ffff) + { + //logerror("'%s' (%08x): unmapped internal read from %08x mask %08x (PHDR)\n",tag(), m_pc & AM,(offset *4)+0x4000000,mem_mask); + return m_io->read_qword(SH3_PORT_H)<<8; + } + } + break; + + case PJDR_PKDR: + { + if (mem_mask & 0xffff0000) + { + //logerror("'%s' (%08x): unmapped internal read from %08x mask %08x (PJDR)\n",tag(), m_pc & AM,(offset *4)+0x4000000,mem_mask); + return m_io->read_qword(SH3_PORT_J)<<24; + } + + if (mem_mask & 0x0000ffff) + { + //logerror("'%s' (%08x): unmapped internal read from %08x mask %08x (PKDR)\n",tag(), m_pc & AM,(offset *4)+0x4000000,mem_mask); + return m_io->read_qword(SH3_PORT_K)<<8; + } + } + break; + + case PLDR_SCPDR: + { + if (mem_mask & 0xffff0000) + { + //logerror("'%s' (%08x): unmapped internal read from %08x mask %08x (PLDR)\n",tag(), m_pc & AM,(offset *4)+0x4000000,mem_mask); + return m_io->read_qword(SH3_PORT_L)<<24; + } + + if (mem_mask & 0x0000ffff) + { + logerror("'%s' (%08x): unmapped internal read from %08x mask %08x (SCPDR)\n",tag(), m_pc & AM,(offset *4)+0x4000000,mem_mask); + //return m_io->read_qword(SH3_PORT_K)<<8; + } + } + break; + + + case SCSMR2_SCBRR2: + { + if (mem_mask & 0xff000000) + { + logerror("'%s' (%08x): SCIF internal read from %08x mask %08x (SCSMR2 - Serial Mode Register 2)\n",tag(), m_pc & AM,(offset *4)+0x4000000,mem_mask); + return m_sh3internal_lower[offset]; + } + + if (mem_mask & 0x0000ff00) + { + logerror("'%s' (%08x): SCIF internal read from %08x mask %08x (SCBRR2 - Bit Rate Register 2)\n",tag(), m_pc & AM,(offset *4)+0x4000000,mem_mask); + return m_sh3internal_lower[offset]; + } + } + break; + + case SCSCR2_SCFTDR2: + { + if (mem_mask & 0xff000000) + { + logerror("'%s' (%08x): SCIF internal read from %08x mask %08x (SCSCR2 - Serial Control Register 2)\n",tag(), m_pc & AM,(offset *4)+0x4000000,mem_mask); + return m_sh3internal_lower[offset]; + } + + if (mem_mask & 0x0000ff00) + { + logerror("'%s' (%08x): SCIF internal read from %08x mask %08x (SCFTDR2 - Transmit FIFO Data Register 2)\n",tag(), m_pc & AM,(offset *4)+0x4000000,mem_mask); + return m_sh3internal_lower[offset]; + } + } + break; + + case SCSSR2_SCFRDR2: + { + if (mem_mask & 0xffff0000) + { + logerror("'%s' (%08x): SCIF internal read from %08x mask %08x (SCSSR2 - Serial Status Register 2)\n",tag(), m_pc & AM,(offset *4)+0x4000000,mem_mask); + return m_sh3internal_lower[offset]; + } + + if (mem_mask & 0x0000ff00) + { + logerror("'%s' (%08x): SCIF internal read from %08x mask %08x (SCFRDR2 - Receive FIFO Data Register 2)\n",tag(), m_pc & AM,(offset *4)+0x4000000,mem_mask); + return m_sh3internal_lower[offset]; + } + } + break; + + case SCFCR2_SCFDR2: + { + if (mem_mask & 0xff000000) + { + logerror("'%s' (%08x): SCIF internal read from %08x mask %08x (SCFCR2 - Fifo Control Register 2)\n",tag(), m_pc & AM,(offset *4)+0x4000000,mem_mask); + return m_sh3internal_lower[offset]; + } + + if (mem_mask & 0x0000ffff) + { + logerror("'%s' (%08x): SCIF internal read from %08x mask %08x (SCFDR2 - Fifo Data Count Register 2)\n",tag(), m_pc & AM,(offset *4)+0x4000000,mem_mask); + return m_sh3internal_lower[offset]; + } + } + break; + + + default: + { + logerror("'%s' (%08x): unmapped internal read from %08x mask %08x\n", + tag(), m_pc & AM, + (offset *4)+0x4000000, + mem_mask); + } + break; + + } + + } + else + { + logerror("'%s' (%08x): unmapped internal read from %08x mask %08x\n", + tag(), m_pc & AM, + (offset *4)+0x4000000, + mem_mask); + } + + return 0; +} + +/* Lower internal area */ + +WRITE32_MEMBER( sh3_base_device::sh3_internal_w ) +{ + if (offset<0x1000) + { + //UINT32 old = m_sh3internal_lower[offset]; + COMBINE_DATA(&m_sh3internal_lower[offset]); + + switch (offset) + { + case SH3_SAR0_ADDR: sh4_handle_sar0_addr_w(data,mem_mask); break; + case SH3_SAR1_ADDR: sh4_handle_sar1_addr_w(data,mem_mask); break; + case SH3_SAR2_ADDR: sh4_handle_sar2_addr_w(data,mem_mask); break; + case SH3_SAR3_ADDR: sh4_handle_sar3_addr_w(data,mem_mask); break; + case SH3_DAR0_ADDR: sh4_handle_dar0_addr_w(data,mem_mask); break; + case SH3_DAR1_ADDR: sh4_handle_dar1_addr_w(data,mem_mask); break; + case SH3_DAR2_ADDR: sh4_handle_dar2_addr_w(data,mem_mask); break; + case SH3_DAR3_ADDR: sh4_handle_dar3_addr_w(data,mem_mask); break; + case SH3_DMATCR0_ADDR: sh4_handle_dmatcr0_addr_w(data,mem_mask); break; + case SH3_DMATCR1_ADDR: sh4_handle_dmatcr1_addr_w(data,mem_mask); break; + case SH3_DMATCR2_ADDR: sh4_handle_dmatcr2_addr_w(data,mem_mask); break; + case SH3_DMATCR3_ADDR: sh4_handle_dmatcr3_addr_w(data,mem_mask); break; + case SH3_CHCR0_ADDR: sh4_handle_chcr0_addr_w(data,mem_mask); break; + case SH3_CHCR1_ADDR: sh4_handle_chcr1_addr_w(data,mem_mask); break; + case SH3_CHCR2_ADDR: sh4_handle_chcr2_addr_w(data,mem_mask); break; + case SH3_CHCR3_ADDR: sh4_handle_chcr3_addr_w(data,mem_mask); break; + case SH3_DMAOR_ADDR: sh4_handle_dmaor_addr_w(data>>16,mem_mask>>16); break; + + + case IRR0_IRR1: + { + { + if (mem_mask & 0xff000000) + { + logerror("'%s' (%08x): unmapped internal write to %08x = %08x & %08x (IRR0)\n",tag(), m_pc & AM,(offset *4)+0x4000000,data,mem_mask); + // not sure if this is how we should clear lines in this core... + if (!(data & 0x01000000)) execute_set_input(0, CLEAR_LINE); + if (!(data & 0x02000000)) execute_set_input(1, CLEAR_LINE); + if (!(data & 0x04000000)) execute_set_input(2, CLEAR_LINE); + if (!(data & 0x08000000)) execute_set_input(3, CLEAR_LINE); + + } + if (mem_mask & 0x0000ff00) + { + logerror("'%s' (%08x): unmapped internal write to %08x = %08x & %08x (IRR1)\n",tag(), m_pc & AM,(offset *4)+0x4000000,data,mem_mask); + } + if (mem_mask & 0x00ff00ff) + { + fatalerror("'%s' (%08x): unmapped internal write to %08x = %08x & %08x (IRR0/1 unused bits)\n",tag(), m_pc & AM,(offset *4)+0x4000000,data,mem_mask); + } + } + } + break; + + case PINTER_IPRC: + { + if (mem_mask & 0xffff0000) + { + logerror("'%s' (%08x): unmapped internal write to %08x = %08x & %08x (PINTER)\n",tag(), m_pc & AM,(offset *4)+0x4000000,data,mem_mask); + } + + if (mem_mask & 0x0000ffff) + { + data &= 0xffff; mem_mask &= 0xffff; + COMBINE_DATA(&m_SH4_IPRC); + logerror("'%s' (%08x): INTC internal write to %08x = %08x & %08x (IPRC)\n",tag(), m_pc & AM,(offset *4)+0x4000000,data,mem_mask); + m_exception_priority[SH4_INTC_IRL0] = INTPRI((m_SH4_IPRC & 0x000f)>>0, SH4_INTC_IRL0); + m_exception_priority[SH4_INTC_IRL1] = INTPRI((m_SH4_IPRC & 0x00f0)>>4, SH4_INTC_IRL1); + m_exception_priority[SH4_INTC_IRL2] = INTPRI((m_SH4_IPRC & 0x0f00)>>8, SH4_INTC_IRL2); + m_exception_priority[SH4_INTC_IRL3] = INTPRI((m_SH4_IPRC & 0xf000)>>12,SH4_INTC_IRL3); + sh4_exception_recompute(); + } + } + break; + + case PCCR_PDCR: + { + if (mem_mask & 0xffff0000) + { + logerror("'%s' (%08x): unmapped internal write to %08x = %08x & %08x (PCCR)\n",tag(), m_pc & AM,(offset *4)+0x4000000,data,mem_mask); + } + + if (mem_mask & 0x0000ffff) + { + logerror("'%s' (%08x): unmapped internal write to %08x = %08x & %08x (PDCR)\n",tag(), m_pc & AM,(offset *4)+0x4000000,data,mem_mask); + } + } + break; + + case PECR_PFCR: + { + if (mem_mask & 0xffff0000) + { + logerror("'%s' (%08x): unmapped internal write to %08x = %08x & %08x (PECR)\n",tag(), m_pc & AM,(offset *4)+0x4000000,data,mem_mask); + } + + if (mem_mask & 0x0000ffff) + { + logerror("'%s' (%08x): unmapped internal write to %08x = %08x & %08x (PFCR)\n",tag(), m_pc & AM,(offset *4)+0x4000000,data,mem_mask); + } + } + break; + + + case PGCR_PHCR: + { + if (mem_mask & 0xffff0000) + { + logerror("'%s' (%08x): unmapped internal write to %08x = %08x & %08x (PGCR)\n",tag(), m_pc & AM,(offset *4)+0x4000000,data,mem_mask); + } + + if (mem_mask & 0x0000ffff) + { + logerror("'%s' (%08x): unmapped internal write to %08x = %08x & %08x (PHCR)\n",tag(), m_pc & AM,(offset *4)+0x4000000,data,mem_mask); + } + } + break; + + + case PJCR_PKCR: + { + if (mem_mask & 0xffff0000) + { + logerror("'%s' (%08x): unmapped internal write to %08x = %08x & %08x (PJCR)\n",tag(), m_pc & AM,(offset *4)+0x4000000,data,mem_mask); + } + + if (mem_mask & 0x0000ffff) + { + logerror("'%s' (%08x): unmapped internal write to %08x = %08x & %08x (PKCR)\n",tag(), m_pc & AM,(offset *4)+0x4000000,data,mem_mask); + } + } + break; + + + case PLCR_SCPCR: + { + if (mem_mask & 0xffff0000) + { + logerror("'%s' (%08x): unmapped internal write to %08x = %08x & %08x (PLCR)\n",tag(), m_pc & AM,(offset *4)+0x4000000,data,mem_mask); + } + + if (mem_mask & 0x0000ffff) + { + logerror("'%s' (%08x): unmapped internal write to %08x = %08x & %08x (SCPCR)\n",tag(), m_pc & AM,(offset *4)+0x4000000,data,mem_mask); + } + } + break; + + case PADR_PBDR: + { + if (mem_mask & 0xffff0000) + { + m_io->write_qword(SH3_PORT_A, (data>>24)&0xff); + // logerror("'%s' (%08x): unmapped internal write to %08x = %08x & %08x (PADR)\n",tag(), m_pc & AM,(offset *4)+0x4000000,data,mem_mask); + } + + if (mem_mask & 0x0000ffff) + { + m_io->write_qword(SH3_PORT_B, (data>>8)&0xff); + // logerror("'%s' (%08x): unmapped internal write to %08x = %08x & %08x (PBDR)\n",tag(), m_pc & AM,(offset *4)+0x4000000,data,mem_mask); + } + } + break; + + case PCDR_PDDR: + { + if (mem_mask & 0xffff0000) + { + m_io->write_qword(SH3_PORT_C, (data>>24)&0xff); + // logerror("'%s' (%08x): unmapped internal write to %08x = %08x & %08x (PADR)\n",tag(), m_pc & AM,(offset *4)+0x4000000,data,mem_mask); + } + + if (mem_mask & 0x0000ffff) + { + m_io->write_qword(SH3_PORT_D, (data>>8)&0xff); + // logerror("'%s' (%08x): unmapped internal write to %08x = %08x & %08x (PBDR)\n",tag(), m_pc & AM,(offset *4)+0x4000000,data,mem_mask); + } + } + break; + case PEDR_PFDR: + { + if (mem_mask & 0xffff0000) + { + m_io->write_qword(SH3_PORT_E, (data>>24)&0xff); + // logerror("'%s' (%08x): unmapped internal write to %08x = %08x & %08x (PEDR)\n",tag(), m_pc & AM,(offset *4)+0x4000000,data,mem_mask); + } + + if (mem_mask & 0x0000ffff) + { + m_io->write_qword(SH3_PORT_F, (data>>8)&0xff); + // logerror("'%s' (%08x): unmapped internal write to %08x = %08x & %08x (PFDR)\n",tag(), m_pc & AM,(offset *4)+0x4000000,data,mem_mask); + } + } + break; + + case PGDR_PHDR: + { + if (mem_mask & 0xffff0000) + { + m_io->write_qword(SH3_PORT_G, (data>>24)&0xff); + // logerror("'%s' (%08x): unmapped internal write to %08x = %08x & %08x (PGDR)\n",tag(), m_pc & AM,(offset *4)+0x4000000,data,mem_mask); + } + + if (mem_mask & 0x0000ffff) + { + m_io->write_qword(SH3_PORT_H, (data>>8)&0xff); + // logerror("'%s' (%08x): unmapped internal write to %08x = %08x & %08x (PHDR)\n",tag(), m_pc & AM,(offset *4)+0x4000000,data,mem_mask); + } + } + break; + + + case PJDR_PKDR: + { + if (mem_mask & 0xffff0000) + { + m_io->write_qword(SH3_PORT_J, (data>>24)&0xff); + // logerror("'%s' (%08x): unmapped internal write to %08x = %08x & %08x (PJDR)\n",tag(), m_pc & AM,(offset *4)+0x4000000,data,mem_mask); + } + + if (mem_mask & 0x0000ffff) + { + m_io->write_qword(SH3_PORT_K, (data>>8)&0xff); + //logerror("'%s' (%08x): unmapped internal write to %08x = %08x & %08x (PKDR)\n",tag(), m_pc & AM,(offset *4)+0x4000000,data,mem_mask); + } + } + break; + + case SCSMR2_SCBRR2: + { + if (mem_mask & 0xff000000) + { + logerror("'%s' (%08x): SCIF internal write to %08x = %08x & %08x (SCSMR2 - Serial Mode Register 2)\n",tag(), m_pc & AM,(offset *4)+0x4000000,data,mem_mask); + } + + if (mem_mask & 0x0000ff00) + { + logerror("'%s' (%08x): SCIF internal write to %08x = %08x & %08x (SCBRR2 - Bit Rate Register 2)\n",tag(), m_pc & AM,(offset *4)+0x4000000,data,mem_mask); + } + } + break; + + case SCSCR2_SCFTDR2: + { + if (mem_mask & 0xff000000) + { + logerror("'%s' (%08x): SCIF internal write to %08x = %08x & %08x (SCSCR2 - Serial Control Register 2)\n",tag(), m_pc & AM,(offset *4)+0x4000000,data,mem_mask); + } + + if (mem_mask & 0x0000ff00) + { + logerror("'%s' (%08x): SCIF internal write to %08x = %08x & %08x (SCFTDR2 - Transmit FIFO Data Register 2)\n",tag(), m_pc & AM,(offset *4)+0x4000000,data,mem_mask); + } + } + break; + + case SCSSR2_SCFRDR2: + { + if (mem_mask & 0xffff0000) + { + logerror("'%s' (%08x): SCIF internal write to %08x = %08x & %08x (SCSSR2 - Serial Status Register 2)\n",tag(), m_pc & AM,(offset *4)+0x4000000,data,mem_mask); + } + + if (mem_mask & 0x0000ff00) + { + logerror("'%s' (%08x): SCIF internal write to %08x = %08x & %08x (SCFRDR2 - Receive FIFO Data Register 2)\n",tag(), m_pc & AM,(offset *4)+0x4000000,data,mem_mask); + } + } + break; + + case SCFCR2_SCFDR2: + { + if (mem_mask & 0xff000000) + { + logerror("'%s' (%08x): SCIF internal write to %08x = %08x & %08x (SCFCR2 - Fifo Control Register 2)\n",tag(), m_pc & AM,(offset *4)+0x4000000,data,mem_mask); + } + + if (mem_mask & 0x0000ffff) + { + logerror("'%s' (%08x): SCIF internal write to %08x = %08x & %08x (SCFDR2 - Fifo Data Count Register 2)\n",tag(), m_pc & AM,(offset *4)+0x4000000,data,mem_mask); + } + } + break; + + default: + { + logerror("'%s' (%08x): unmapped internal write to %08x = %08x & %08x\n", + tag(), m_pc & AM, + (offset *4)+0x4000000, + data, + mem_mask); + } + break; + } + + } + else + { + logerror("'%s' (%08x): unmapped internal write to %08x = %08x & %08x\n", + tag(), m_pc & AM, + (offset *4)+0x4000000, + data, + mem_mask); + } + +} diff --git a/src/devices/cpu/sh4/sh3comn.h b/src/devices/cpu/sh4/sh3comn.h new file mode 100644 index 00000000000..8aa68c27b26 --- /dev/null +++ b/src/devices/cpu/sh4/sh3comn.h @@ -0,0 +1,96 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +#pragma once + +#ifndef __SH3COMN_H__ +#define __SH3COMN_H__ + + +// actual port handling is more complex than this +// which should be considered a temporary solution +// just used some arbitrary port nubmers +#define SH3_PORT_A (0x10*8) +#define SH3_PORT_B (0x11*8) +#define SH3_PORT_C (0x12*8) +#define SH3_PORT_D (0x13*8) +#define SH3_PORT_E (0x14*8) +#define SH3_PORT_F (0x15*8) +#define SH3_PORT_G (0x16*8) +#define SH3_PORT_H (0x17*8) +/* no I */ +#define SH3_PORT_J (0x18*8) +#define SH3_PORT_K (0x19*8) +#define SH3_PORT_L (0x1a*8) + +/* SH3 lower area regs */ + +#define SH3_LOWER_REGBASE (0x04000000) +#define SH3_LOWER_REGEND (0x07ffffff) + +#define INTEVT2 ((0x4000000 - SH3_LOWER_REGBASE)/4) +#define IRR0_IRR1 ((0x4000004 - SH3_LOWER_REGBASE)/4) +#define PINTER_IPRC ((0x4000014 - SH3_LOWER_REGBASE)/4) + +#define SH3_SAR0_ADDR ((0x4000020 - SH3_LOWER_REGBASE)/4) +#define SH3_DAR0_ADDR ((0x4000024 - SH3_LOWER_REGBASE)/4) +#define SH3_DMATCR0_ADDR ((0x4000028 - SH3_LOWER_REGBASE)/4) +#define SH3_CHCR0_ADDR ((0x400002c - SH3_LOWER_REGBASE)/4) +#define SH3_SAR1_ADDR ((0x4000030 - SH3_LOWER_REGBASE)/4) +#define SH3_DAR1_ADDR ((0x4000034 - SH3_LOWER_REGBASE)/4) +#define SH3_DMATCR1_ADDR ((0x4000038 - SH3_LOWER_REGBASE)/4) +#define SH3_CHCR1_ADDR ((0x400003c - SH3_LOWER_REGBASE)/4) +#define SH3_SAR2_ADDR ((0x4000040 - SH3_LOWER_REGBASE)/4) +#define SH3_DAR2_ADDR ((0x4000044 - SH3_LOWER_REGBASE)/4) +#define SH3_DMATCR2_ADDR ((0x4000048 - SH3_LOWER_REGBASE)/4) +#define SH3_CHCR2_ADDR ((0x400004c - SH3_LOWER_REGBASE)/4) +#define SH3_SAR3_ADDR ((0x4000050 - SH3_LOWER_REGBASE)/4) +#define SH3_DAR3_ADDR ((0x4000054 - SH3_LOWER_REGBASE)/4) +#define SH3_DMATCR3_ADDR ((0x4000058 - SH3_LOWER_REGBASE)/4) +#define SH3_CHCR3_ADDR ((0x400005c - SH3_LOWER_REGBASE)/4) +#define SH3_DMAOR_ADDR ((0x4000060 - SH3_LOWER_REGBASE)/4) + + +#define PCCR_PDCR ((0x4000104 - SH3_LOWER_REGBASE)/4) +#define PECR_PFCR ((0x4000108 - SH3_LOWER_REGBASE)/4) +#define PGCR_PHCR ((0x400010c - SH3_LOWER_REGBASE)/4) +#define PJCR_PKCR ((0x4000110 - SH3_LOWER_REGBASE)/4) +#define PLCR_SCPCR ((0x4000114 - SH3_LOWER_REGBASE)/4) + +#define PADR_PBDR ((0x4000120 - SH3_LOWER_REGBASE)/4) +#define PCDR_PDDR ((0x4000124 - SH3_LOWER_REGBASE)/4) +#define PEDR_PFDR ((0x4000128 - SH3_LOWER_REGBASE)/4) +#define PGDR_PHDR ((0x400012c - SH3_LOWER_REGBASE)/4) +#define PJDR_PKDR ((0x4000130 - SH3_LOWER_REGBASE)/4) +#define PLDR_SCPDR ((0x4000134 - SH3_LOWER_REGBASE)/4) + +#define SCSMR2_SCBRR2 ((0x4000150 - SH3_LOWER_REGBASE)/4) +#define SCSCR2_SCFTDR2 ((0x4000154 - SH3_LOWER_REGBASE)/4) +#define SCSSR2_SCFRDR2 ((0x4000158 - SH3_LOWER_REGBASE)/4) +#define SCFCR2_SCFDR2 ((0x400015c - SH3_LOWER_REGBASE)/4) + + +/* SH3 upper area */ + + +#define SH3_UPPER_REGBASE (0xffffd000) +#define SH3_UPPER_REGEND (0xffffffff) + +#define SH3_ICR0_IPRA_ADDR ((0xfffffee0 - SH3_UPPER_REGBASE)/4) +#define SH3_IPRB_ADDR ((0xfffffee4 - SH3_UPPER_REGBASE)/4) + +#define SH3_TOCR_TSTR_ADDR ((0xfffffe90 - SH3_UPPER_REGBASE)/4) +#define SH3_TCOR0_ADDR ((0xfffffe94 - SH3_UPPER_REGBASE)/4) +#define SH3_TCNT0_ADDR ((0xfffffe98 - SH3_UPPER_REGBASE)/4) +#define SH3_TCR0_ADDR ((0xfffffe9c - SH3_UPPER_REGBASE)/4) +#define SH3_TCOR1_ADDR ((0xfffffea0 - SH3_UPPER_REGBASE)/4) +#define SH3_TCNT1_ADDR ((0xfffffea4 - SH3_UPPER_REGBASE)/4) +#define SH3_TCR1_ADDR ((0xfffffea8 - SH3_UPPER_REGBASE)/4) +#define SH3_TCOR2_ADDR ((0xfffffeac - SH3_UPPER_REGBASE)/4) +#define SH3_TCNT2_ADDR ((0xfffffeb0 - SH3_UPPER_REGBASE)/4) +#define SH3_TCR2_ADDR ((0xfffffeb4 - SH3_UPPER_REGBASE)/4) +#define SH3_TCPR2_ADDR ((0xfffffeb8 - SH3_UPPER_REGBASE)/4) +#define SH3_TRA_ADDR ((0xffffffd0 - SH3_UPPER_REGBASE)/4) +#define SH3_EXPEVT_ADDR ((0xffffffd4 - SH3_UPPER_REGBASE)/4) +#define SH3_INTEVT_ADDR ((0xffffffd8 - SH3_UPPER_REGBASE)/4) + +#endif /* __SH3COMN_H__ */ diff --git a/src/devices/cpu/sh4/sh4.c b/src/devices/cpu/sh4/sh4.c new file mode 100644 index 00000000000..e0835b1f9c0 --- /dev/null +++ b/src/devices/cpu/sh4/sh4.c @@ -0,0 +1,4608 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/***************************************************************************** + * + * sh4.c + * Portable Hitachi SH-4 (SH7750 family) emulator + * + * By R. Belmont, based on sh2.c by Juergen Buchmueller, Mariusz Wojcieszek, + * Olivier Galibert, Sylvain Glaize, and James Forshaw. + * + * + * TODO: FPU + * DMA + * on-board peripherals + * + * DONE: boot/reset setup + * 64-bit data bus + * banked registers + * additional registers for supervisor mode + * FPU status and data registers + * state save for the new registers + * interrupts + * store queues + * + *****************************************************************************/ + +#include "emu.h" +#include "debugger.h" +#include "sh4.h" +#include "sh4regs.h" +#include "sh4comn.h" +#include "sh3comn.h" +#include "sh4tmu.h" + +#if SH4_USE_FASTRAM_OPTIMIZATION +void sh34_base_device::add_fastram(offs_t start, offs_t end, UINT8 readonly, void *base) +{ + if (m_fastram_select < ARRAY_LENGTH(m_fastram)) + { + m_fastram[m_fastram_select].start = start; + m_fastram[m_fastram_select].end = end; + m_fastram[m_fastram_select].readonly = readonly; + m_fastram[m_fastram_select].base = base; + m_fastram_select++; + } +} +#else +void sh34_base_device::add_fastram(offs_t start, offs_t end, UINT8 readonly, void *base) +{ +} +#endif + + +CPU_DISASSEMBLE( sh4 ); +CPU_DISASSEMBLE( sh4be ); + + +const device_type SH3LE = &device_creator; +const device_type SH3BE = &device_creator; +const device_type SH4LE = &device_creator; +const device_type SH4BE = &device_creator; + + +#if 0 +/*When OC index mode is off (CCR.OIX = 0)*/ +static ADDRESS_MAP_START( sh4_internal_map, AS_PROGRAM, 64, sh4_base_device ) + AM_RANGE(0x1C000000, 0x1C000FFF) AM_RAM AM_MIRROR(0x03FFD000) + AM_RANGE(0x1C002000, 0x1C002FFF) AM_RAM AM_MIRROR(0x03FFD000) + AM_RANGE(0xE0000000, 0xE000003F) AM_RAM AM_MIRROR(0x03FFFFC0) +ADDRESS_MAP_END +#endif + +/*When OC index mode is on (CCR.OIX = 1)*/ +static ADDRESS_MAP_START( sh4_internal_map, AS_PROGRAM, 64, sh4_base_device ) + AM_RANGE(0x1C000000, 0x1C000FFF) AM_RAM AM_MIRROR(0x01FFF000) + AM_RANGE(0x1E000000, 0x1E000FFF) AM_RAM AM_MIRROR(0x01FFF000) + AM_RANGE(0xE0000000, 0xE000003F) AM_RAM AM_MIRROR(0x03FFFFC0) // todo: store queues should be write only on DC's SH4, executing PREFM shouldn't cause an actual memory read access! + AM_RANGE(0xF6000000, 0xF7FFFFFF) AM_READWRITE(sh4_tlb_r,sh4_tlb_w) + AM_RANGE(0xFE000000, 0xFFFFFFFF) AM_READWRITE32(sh4_internal_r, sh4_internal_w, U64(0xffffffffffffffff)) +ADDRESS_MAP_END + +static ADDRESS_MAP_START( sh3_internal_map, AS_PROGRAM, 64, sh3_base_device ) + AM_RANGE(SH3_LOWER_REGBASE, SH3_LOWER_REGEND) AM_READWRITE32(sh3_internal_r, sh3_internal_w, U64(0xffffffffffffffff)) + AM_RANGE(SH3_UPPER_REGBASE, SH3_UPPER_REGEND) AM_READWRITE32(sh3_internal_high_r, sh3_internal_high_w, U64(0xffffffffffffffff)) +ADDRESS_MAP_END + + +sh34_base_device::sh34_base_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, endianness_t endianness, address_map_constructor internal) + : cpu_device(mconfig, type, name, tag, owner, clock, shortname, __FILE__) + , m_program_config("program", endianness, 64, 32, 0, internal) + , m_io_config("io", endianness, 64, 8) + , c_md2(0) + , c_md1(0) + , c_md0(0) + , c_md6(0) + , c_md4(0) + , c_md3(0) + , c_md5(0) + , c_md7(0) + , c_md8(0) + , c_clock(0) +#if SH4_USE_FASTRAM_OPTIMIZATION + , m_bigendian(endianness == ENDIANNESS_BIG) + , m_byte_xor(m_bigendian ? BYTE8_XOR_BE(0) : BYTE8_XOR_LE(0)) + , m_word_xor(m_bigendian ? WORD2_XOR_BE(0) : WORD2_XOR_LE(0)) + , m_dword_xor(m_bigendian ? DWORD_XOR_BE(0) : DWORD_XOR_LE(0)) + , m_fastram_select(0) +#endif +{ +#if SH4_USE_FASTRAM_OPTIMIZATION + memset(m_fastram, 0, sizeof(m_fastram)); +#endif +} + + +sh3_base_device::sh3_base_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, endianness_t endianness) + : sh34_base_device(mconfig, type, name, tag, owner, clock, shortname, endianness, ADDRESS_MAP_NAME(sh3_internal_map)) +{ + m_cpu_type = CPU_TYPE_SH3; +} + + +sh4_base_device::sh4_base_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, endianness_t endianness) + : sh34_base_device(mconfig, type, name, tag, owner, clock, shortname, endianness, ADDRESS_MAP_NAME(sh4_internal_map)) +{ + m_cpu_type = CPU_TYPE_SH4; +} + + +sh3_device::sh3_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : sh3_base_device(mconfig, SH3LE, "SH-3 (little)", tag, owner, clock, "sh3", ENDIANNESS_LITTLE) +{ +} + + +sh3be_device::sh3be_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : sh3_base_device(mconfig, SH3BE, "SH-3 (big)", tag, owner, clock, "sh3be", ENDIANNESS_BIG) +{ +} + + +sh4_device::sh4_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : sh4_base_device(mconfig, SH4LE, "SH-4 (little)", tag, owner, clock, "sh4", ENDIANNESS_LITTLE) +{ +} + + +sh4be_device::sh4be_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : sh4_base_device(mconfig, SH4BE, "SH-4 (big)", tag, owner, clock, "sh4be", ENDIANNESS_BIG) +{ +} + + +offs_t sh34_base_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( sh4 ); + + return CPU_DISASSEMBLE_NAME(sh4)(this, buffer, pc, oprom, opram, options); +} + + +offs_t sh3be_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( sh4be ); + + return CPU_DISASSEMBLE_NAME(sh4be)(this, buffer, pc, oprom, opram, options); +} + + +offs_t sh4be_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( sh4be ); + + return CPU_DISASSEMBLE_NAME(sh4be)(this, buffer, pc, oprom, opram, options); +} + + +/* Called for unimplemented opcodes */ +void sh34_base_device::TODO(const UINT16 opcode) +{ +} + +#if 0 +int sign_of(int n) +{ + return(m_fr[n]>>31); +} + +void zero(int n,int sign) +{ +if (sign == 0) + m_fr[n] = 0x00000000; +else + m_fr[n] = 0x80000000; +if ((m_fpscr & PR) == 1) + m_fr[n+1] = 0x00000000; +} + +int data_type_of(int n) +{ +UINT32 abs; + + abs = m_fr[n] & 0x7fffffff; + if ((m_fpscr & PR) == 0) { /* Single-precision */ + if (abs < 0x00800000) { + if (((m_fpscr & DN) == 1) || (abs == 0x00000000)) { + if (sign_of(n) == 0) { + zero(n, 0); + return(SH4_FPU_PZERO); + } else { + zero(n, 1); + return(SH4_FPU_NZERO); + } + } else + return(SH4_FPU_DENORM); + } else + if (abs < 0x7f800000) + return(SH4_FPU_NORM); + else + if (abs == 0x7f800000) { + if (sign_of(n) == 0) + return(SH4_FPU_PINF); + else + return(SH4_FPU_NINF); + } else + if (abs < 0x7fc00000) + return(SH4_FPU_qNaN); + else + return(SH4_FPU_sNaN); + } else { /* Double-precision */ + if (abs < 0x00100000) { + if (((m_fpscr & DN) == 1) || ((abs == 0x00000000) && (m_fr[n+1] == 0x00000000))) { + if(sign_of(n) == 0) { + zero(n, 0); + return(SH4_FPU_PZERO); + } else { + zero(n, 1); + return(SH4_FPU_NZERO); + } + } else + return(SH4_FPU_DENORM); + } else + if (abs < 0x7ff00000) + return(SH4_FPU_NORM); + else + if ((abs == 0x7ff00000) && (m_fr[n+1] == 0x00000000)) { + if (sign_of(n) == 0) + return(SH4_FPU_PINF); + else + return(SH4_FPU_NINF); + } else + if (abs < 0x7ff80000) + return(SH4_FPU_qNaN); + else + return(SH4_FPU_sNaN); + } + return(SH4_FPU_NORM); +} +#endif + +inline UINT8 sh34_base_device::RB(offs_t A) +{ + if (A >= 0xe0000000) + return m_program->read_byte(A); + +#if SH4_USE_FASTRAM_OPTIMIZATION + const offs_t _A = A & AM; + for (int ramnum = 0; ramnum < m_fastram_select; ramnum++) + { + if (_A < m_fastram[ramnum].start || _A > m_fastram[ramnum].end) + { + continue; + } + UINT8 *fastbase = (UINT8*)m_fastram[ramnum].base - m_fastram[ramnum].start; + return fastbase[_A ^ m_byte_xor]; + } + return m_program->read_byte(_A); +#else + return m_program->read_byte(A & AM); +#endif + +} + +inline UINT16 sh34_base_device::RW(offs_t A) +{ + if (A >= 0xe0000000) + return m_program->read_word(A); + +#if SH4_USE_FASTRAM_OPTIMIZATION + const offs_t _A = A & AM; + for (int ramnum = 0; ramnum < m_fastram_select; ramnum++) + { + if (_A < m_fastram[ramnum].start || _A > m_fastram[ramnum].end) + { + continue; + } + UINT8 *fastbase = (UINT8*)m_fastram[ramnum].base - m_fastram[ramnum].start; + return ((UINT16*)fastbase)[(_A ^ m_word_xor) >> 1]; + } + return m_program->read_word(_A); +#else + return m_program->read_word(A & AM); +#endif + +} + +inline UINT32 sh34_base_device::RL(offs_t A) +{ + if (A >= 0xe0000000) + return m_program->read_dword(A); + +#if SH4_USE_FASTRAM_OPTIMIZATION + const offs_t _A = A & AM; + for (int ramnum = 0; ramnum < m_fastram_select; ramnum++) + { + if (_A < m_fastram[ramnum].start || _A > m_fastram[ramnum].end) + { + continue; + } + UINT8 *fastbase = (UINT8*)m_fastram[ramnum].base - m_fastram[ramnum].start; + return ((UINT32*)fastbase)[(_A^m_dword_xor) >> 2]; + } + return m_program->read_dword(_A); +#else + return m_program->read_dword(A & AM); +#endif + +} + +inline void sh34_base_device::WB(offs_t A, UINT8 V) +{ + if (A >= 0xe0000000) + { + m_program->write_byte(A,V); + return; + } +#if SH4_USE_FASTRAM_OPTIMIZATION + const offs_t _A = A & AM; + for (int ramnum = 0; ramnum < m_fastram_select; ramnum++) + { + if (m_fastram[ramnum].readonly == TRUE || _A < m_fastram[ramnum].start || _A > m_fastram[ramnum].end) + { + continue; + } + UINT8 *fastbase = (UINT8*)m_fastram[ramnum].base - m_fastram[ramnum].start; + fastbase[_A ^ m_byte_xor] = V; + return; + } + m_program->write_byte(_A,V); +#else + m_program->write_byte(A & AM,V); +#endif + +} + +inline void sh34_base_device::WW(offs_t A, UINT16 V) +{ + if (A >= 0xe0000000) + { + m_program->write_word(A,V); + return; + } +#if SH4_USE_FASTRAM_OPTIMIZATION + const offs_t _A = A & AM; + for (int ramnum = 0; ramnum < m_fastram_select; ramnum++) + { + if (m_fastram[ramnum].readonly == TRUE || _A < m_fastram[ramnum].start || _A > m_fastram[ramnum].end) + { + continue; + } + void *fastbase = (UINT8*)m_fastram[ramnum].base - m_fastram[ramnum].start; + ((UINT16*)fastbase)[(_A ^ m_word_xor) >> 1] = V; + return; + } + m_program->write_word(_A,V); +#else + m_program->write_word(A & AM,V); +#endif + +} + +inline void sh34_base_device::WL(offs_t A, UINT32 V) +{ + if (A >= 0xe0000000) + { + m_program->write_dword(A,V); + return; + } +#if SH4_USE_FASTRAM_OPTIMIZATION + const offs_t _A = A & AM; + for (int ramnum = 0; ramnum < m_fastram_select; ramnum++) + { + if (m_fastram[ramnum].readonly == TRUE || _A < m_fastram[ramnum].start || _A > m_fastram[ramnum].end) + { + continue; + } + void *fastbase = (UINT8*)m_fastram[ramnum].base - m_fastram[ramnum].start; + ((UINT32*)fastbase)[(_A ^ m_dword_xor) >> 2] = V; + return; + } + m_program->write_dword(_A,V); +#else + m_program->write_dword(A & AM,V); +#endif +} + +/* code cycles t-bit + * 0011 nnnn mmmm 1100 1 - + * ADD Rm,Rn + */ +inline void sh34_base_device::ADD(const UINT16 opcode) +{ + m_r[Rn] += m_r[Rm]; +} + +/* code cycles t-bit + * 0111 nnnn iiii iiii 1 - + * ADD #imm,Rn + */ +inline void sh34_base_device::ADDI(const UINT16 opcode) +{ + m_r[Rn] += (INT32)(INT16)(INT8)(opcode&0xff); +} + +/* code cycles t-bit + * 0011 nnnn mmmm 1110 1 carry + * ADDC Rm,Rn + */ +inline void sh34_base_device::ADDC(const UINT16 opcode) +{ + UINT32 m = Rm; UINT32 n = Rn; + UINT32 tmp0, tmp1; + + tmp1 = m_r[n] + m_r[m]; + tmp0 = m_r[n]; + m_r[n] = tmp1 + (m_sr & T); + if (tmp0 > tmp1) + m_sr |= T; + else + m_sr &= ~T; + if (tmp1 > m_r[n]) + m_sr |= T; +} + +/* code cycles t-bit + * 0011 nnnn mmmm 1111 1 overflow + * ADDV Rm,Rn + */ +inline void sh34_base_device::ADDV(const UINT16 opcode) +{ + UINT32 m = Rm; UINT32 n = Rn; + INT32 dest, src, ans; + + if ((INT32) m_r[n] >= 0) + dest = 0; + else + dest = 1; + if ((INT32) m_r[m] >= 0) + src = 0; + else + src = 1; + src += dest; + m_r[n] += m_r[m]; + if ((INT32) m_r[n] >= 0) + ans = 0; + else + ans = 1; + ans += dest; + if (src == 0 || src == 2) + { + if (ans == 1) + m_sr |= T; + else + m_sr &= ~T; + } + else + m_sr &= ~T; +} + +/* code cycles t-bit + * 0010 nnnn mmmm 1001 1 - + * AND Rm,Rn + */ +inline void sh34_base_device::AND(const UINT16 opcode) +{ + m_r[Rn] &= m_r[Rm]; +} + + +/* code cycles t-bit + * 1100 1001 iiii iiii 1 - + * AND #imm,R0 + */ +inline void sh34_base_device::ANDI(const UINT16 opcode) +{ + m_r[0] &= (opcode&0xff); +} + +/* code cycles t-bit + * 1100 1101 iiii iiii 1 - + * AND.B #imm,@(R0,GBR) + */ +inline void sh34_base_device::ANDM(const UINT16 opcode) +{ + UINT32 temp; + + m_ea = m_gbr + m_r[0]; + temp = (opcode&0xff) & RB( m_ea ); + WB(m_ea, temp ); + m_sh4_icount -= 2; +} + +/* code cycles t-bit + * 1000 1011 dddd dddd 3/1 - + * BF disp8 + */ +inline void sh34_base_device::BF(const UINT16 opcode) +{ + if ((m_sr & T) == 0) + { + INT32 disp = ((INT32)(opcode&0xff) << 24) >> 24; + m_pc = m_ea = m_pc + disp * 2 + 2; + m_sh4_icount -= 2; + } +} + +/* code cycles t-bit + * 1000 1111 dddd dddd 3/1 - + * BFS disp8 + */ +inline void sh34_base_device::BFS(const UINT16 opcode) +{ + if ((m_sr & T) == 0) + { + INT32 disp = ((INT32)(opcode&0xff) << 24) >> 24; + m_delay = m_pc; + m_pc = m_ea = m_pc + disp * 2 + 2; + m_sh4_icount--; + } +} + +/* code cycles t-bit + * 1010 dddd dddd dddd 2 - + * BRA disp12 + */ +inline void sh34_base_device::BRA(const UINT16 opcode) +{ + INT32 disp = ((INT32)(opcode&0xfff) << 20) >> 20; + +#if BUSY_LOOP_HACKS + if (disp == -2) + { + UINT32 next_opcode = RW(m_ppc & AM); + /* BRA $ + * NOP + */ + if (next_opcode == 0x0009) + m_sh4_icount %= 3; /* cycles for BRA $ and NOP taken (3) */ + } +#endif + m_delay = m_pc; + m_pc = m_ea = m_pc + disp * 2 + 2; + m_sh4_icount--; +} + +/* code cycles t-bit + * 0000 mmmm 0010 0011 2 - + * BRAF Rm + */ +inline void sh34_base_device::BRAF(const UINT16 opcode) +{ + m_delay = m_pc; + m_pc += m_r[Rn] + 2; + m_sh4_icount--; +} + +/* code cycles t-bit + * 1011 dddd dddd dddd 2 - + * BSR disp12 + */ +inline void sh34_base_device::BSR(const UINT16 opcode) +{ + INT32 disp = ((INT32)(opcode&0xfff) << 20) >> 20; + + m_pr = m_pc + 2; + m_delay = m_pc; + m_pc = m_ea = m_pc + disp * 2 + 2; + m_sh4_icount--; +} + +/* code cycles t-bit + * 0000 mmmm 0000 0011 2 - + * BSRF Rm + */ +inline void sh34_base_device::BSRF(const UINT16 opcode) +{ + m_pr = m_pc + 2; + m_delay = m_pc; + m_pc += m_r[Rn] + 2; + m_sh4_icount--; +} + +/* code cycles t-bit + * 1000 1001 dddd dddd 3/1 - + * BT disp8 + */ +inline void sh34_base_device::BT(const UINT16 opcode) +{ + if ((m_sr & T) != 0) + { + INT32 disp = ((INT32)(opcode&0xff) << 24) >> 24; + m_pc = m_ea = m_pc + disp * 2 + 2; + m_sh4_icount -= 2; + } +} + +/* code cycles t-bit + * 1000 1101 dddd dddd 2/1 - + * BTS disp8 + */ +inline void sh34_base_device::BTS(const UINT16 opcode) +{ + if ((m_sr & T) != 0) + { + INT32 disp = ((INT32)(opcode&0xff) << 24) >> 24; + m_delay = m_pc; + m_pc = m_ea = m_pc + disp * 2 + 2; + m_sh4_icount--; + } +} + +/* code cycles t-bit + * 0000 0000 0010 1000 1 - + * CLRMAC + */ +inline void sh34_base_device::CLRMAC(const UINT16 opcode) +{ + m_mach = 0; + m_macl = 0; +} + +/* code cycles t-bit + * 0000 0000 0000 1000 1 - + * CLRT + */ +inline void sh34_base_device::CLRT(const UINT16 opcode) +{ + m_sr &= ~T; +} + +/* code cycles t-bit + * 0011 nnnn mmmm 0000 1 comparison result + * CMP_EQ Rm,Rn + */ +inline void sh34_base_device::CMPEQ(const UINT16 opcode) +{ + if (m_r[Rn] == m_r[Rm]) + m_sr |= T; + else + m_sr &= ~T; +} + +/* code cycles t-bit + * 0011 nnnn mmmm 0011 1 comparison result + * CMP_GE Rm,Rn + */ +inline void sh34_base_device::CMPGE(const UINT16 opcode) +{ + if ((INT32) m_r[Rn] >= (INT32) m_r[Rm]) + m_sr |= T; + else + m_sr &= ~T; +} + +/* code cycles t-bit + * 0011 nnnn mmmm 0111 1 comparison result + * CMP_GT Rm,Rn + */ +inline void sh34_base_device::CMPGT(const UINT16 opcode) +{ + if ((INT32) m_r[Rn] > (INT32) m_r[Rm]) + m_sr |= T; + else + m_sr &= ~T; +} + +/* code cycles t-bit + * 0011 nnnn mmmm 0110 1 comparison result + * CMP_HI Rm,Rn + */ +inline void sh34_base_device::CMPHI(const UINT16 opcode) +{ + if ((UINT32) m_r[Rn] > (UINT32) m_r[Rm]) + m_sr |= T; + else + m_sr &= ~T; +} + +/* code cycles t-bit + * 0011 nnnn mmmm 0010 1 comparison result + * CMP_HS Rm,Rn + */ +inline void sh34_base_device::CMPHS(const UINT16 opcode) +{ + if ((UINT32) m_r[Rn] >= (UINT32) m_r[Rm]) + m_sr |= T; + else + m_sr &= ~T; +} + + +/* code cycles t-bit + * 0100 nnnn 0001 0101 1 comparison result + * CMP_PL Rn + */ +inline void sh34_base_device::CMPPL(const UINT16 opcode) +{ + if ((INT32) m_r[Rn] > 0) + m_sr |= T; + else + m_sr &= ~T; +} + +/* code cycles t-bit + * 0100 nnnn 0001 0001 1 comparison result + * CMP_PZ Rn + */ +inline void sh34_base_device::CMPPZ(const UINT16 opcode) +{ + if ((INT32) m_r[Rn] >= 0) + m_sr |= T; + else + m_sr &= ~T; +} + +/* code cycles t-bit + * 0010 nnnn mmmm 1100 1 comparison result + * CMP_STR Rm,Rn + */ +inline void sh34_base_device::CMPSTR(const UINT16 opcode) +{ + UINT32 temp; + INT32 HH, HL, LH, LL; + temp = m_r[Rn] ^ m_r[Rm]; + HH = (temp >> 24) & 0xff; + HL = (temp >> 16) & 0xff; + LH = (temp >> 8) & 0xff; + LL = temp & 0xff; + if (HH && HL && LH && LL) + m_sr &= ~T; + else + m_sr |= T; + } + + +/* code cycles t-bit + * 1000 1000 iiii iiii 1 comparison result + * CMP/EQ #imm,R0 + */ +inline void sh34_base_device::CMPIM(const UINT16 opcode) +{ + UINT32 imm = (UINT32)(INT32)(INT16)(INT8)(opcode&0xff); + + if (m_r[0] == imm) + m_sr |= T; + else + m_sr &= ~T; +} + +/* code cycles t-bit + * 0010 nnnn mmmm 0111 1 calculation result + * DIV0S Rm,Rn + */ +inline void sh34_base_device::DIV0S(const UINT16 opcode) +{ + UINT32 m = Rm; UINT32 n = Rn; + + if ((m_r[n] & 0x80000000) == 0) + m_sr &= ~Q; + else + m_sr |= Q; + if ((m_r[m] & 0x80000000) == 0) + m_sr &= ~M; + else + m_sr |= M; + if ((m_r[m] ^ m_r[n]) & 0x80000000) + m_sr |= T; + else + m_sr &= ~T; +} + +/* code cycles t-bit + * 0000 0000 0001 1001 1 0 + * DIV0U + */ +inline void sh34_base_device::DIV0U(const UINT16 opcode) +{ + m_sr &= ~(M | Q | T); +} + +/* code cycles t-bit + * 0011 nnnn mmmm 0100 1 calculation result + * DIV1 Rm,Rn + */ +inline void sh34_base_device::DIV1(const UINT16 opcode) +{ + UINT32 m = Rm; UINT32 n = Rn; + + UINT32 tmp0; + UINT32 old_q; + + old_q = m_sr & Q; + if (0x80000000 & m_r[n]) + m_sr |= Q; + else + m_sr &= ~Q; + + m_r[n] = (m_r[n] << 1) | (m_sr & T); + + if (!old_q) + { + if (!(m_sr & M)) + { + tmp0 = m_r[n]; + m_r[n] -= m_r[m]; + if(!(m_sr & Q)) + if(m_r[n] > tmp0) + m_sr |= Q; + else + m_sr &= ~Q; + else + if(m_r[n] > tmp0) + m_sr &= ~Q; + else + m_sr |= Q; + } + else + { + tmp0 = m_r[n]; + m_r[n] += m_r[m]; + if(!(m_sr & Q)) + { + if(m_r[n] < tmp0) + m_sr &= ~Q; + else + m_sr |= Q; + } + else + { + if(m_r[n] < tmp0) + m_sr |= Q; + else + m_sr &= ~Q; + } + } + } + else + { + if (!(m_sr & M)) + { + tmp0 = m_r[n]; + m_r[n] += m_r[m]; + if(!(m_sr & Q)) + if(m_r[n] < tmp0) + m_sr |= Q; + else + m_sr &= ~Q; + else + if(m_r[n] < tmp0) + m_sr &= ~Q; + else + m_sr |= Q; + } + else + { + tmp0 = m_r[n]; + m_r[n] -= m_r[m]; + if(!(m_sr & Q)) + if(m_r[n] > tmp0) + m_sr &= ~Q; + else + m_sr |= Q; + else + if(m_r[n] > tmp0) + m_sr |= Q; + else + m_sr &= ~Q; + } + } + + tmp0 = (m_sr & (Q | M)); + if((!tmp0) || (tmp0 == 0x300)) /* if Q == M set T else clear T */ + m_sr |= T; + else + m_sr &= ~T; +} + +/* DMULS.L Rm,Rn */ +inline void sh34_base_device::DMULS(const UINT16 opcode) +{ + UINT32 m = Rm; UINT32 n = Rn; + + UINT32 RnL, RnH, RmL, RmH, Res0, Res1, Res2; + UINT32 temp0, temp1, temp2, temp3; + INT32 tempm, tempn, fnLmL; + + tempn = (INT32) m_r[n]; + tempm = (INT32) m_r[m]; + if (tempn < 0) + tempn = 0 - tempn; + if (tempm < 0) + tempm = 0 - tempm; + if ((INT32) (m_r[n] ^ m_r[m]) < 0) + fnLmL = -1; + else + fnLmL = 0; + temp1 = (UINT32) tempn; + temp2 = (UINT32) tempm; + RnL = temp1 & 0x0000ffff; + RnH = (temp1 >> 16) & 0x0000ffff; + RmL = temp2 & 0x0000ffff; + RmH = (temp2 >> 16) & 0x0000ffff; + temp0 = RmL * RnL; + temp1 = RmH * RnL; + temp2 = RmL * RnH; + temp3 = RmH * RnH; + Res2 = 0; + Res1 = temp1 + temp2; + if (Res1 < temp1) + Res2 += 0x00010000; + temp1 = (Res1 << 16) & 0xffff0000; + Res0 = temp0 + temp1; + if (Res0 < temp0) + Res2++; + Res2 = Res2 + ((Res1 >> 16) & 0x0000ffff) + temp3; + if (fnLmL < 0) + { + Res2 = ~Res2; + if (Res0 == 0) + Res2++; + else + Res0 = (~Res0) + 1; + } + m_mach = Res2; + m_macl = Res0; + m_sh4_icount--; +} + +/* DMULU.L Rm,Rn */ +inline void sh34_base_device::DMULU(const UINT16 opcode) +{ + UINT32 m = Rm; UINT32 n = Rn; + + UINT32 RnL, RnH, RmL, RmH, Res0, Res1, Res2; + UINT32 temp0, temp1, temp2, temp3; + + RnL = m_r[n] & 0x0000ffff; + RnH = (m_r[n] >> 16) & 0x0000ffff; + RmL = m_r[m] & 0x0000ffff; + RmH = (m_r[m] >> 16) & 0x0000ffff; + temp0 = RmL * RnL; + temp1 = RmH * RnL; + temp2 = RmL * RnH; + temp3 = RmH * RnH; + Res2 = 0; + Res1 = temp1 + temp2; + if (Res1 < temp1) + Res2 += 0x00010000; + temp1 = (Res1 << 16) & 0xffff0000; + Res0 = temp0 + temp1; + if (Res0 < temp0) + Res2++; + Res2 = Res2 + ((Res1 >> 16) & 0x0000ffff) + temp3; + m_mach = Res2; + m_macl = Res0; + m_sh4_icount--; +} + +/* DT Rn */ +inline void sh34_base_device::DT(const UINT16 opcode) +{ + UINT32 n = Rn; + + m_r[n]--; + if (m_r[n] == 0) + m_sr |= T; + else + m_sr &= ~T; +#if BUSY_LOOP_HACKS + { + UINT32 next_opcode = RW(m_ppc & AM); + /* DT Rn + * BF $-2 + */ + if (next_opcode == 0x8bfd) + { + while (m_r[n] > 1 && m_sh4_icount > 4) + { + m_r[n]--; + m_sh4_icount -= 4; /* cycles for DT (1) and BF taken (3) */ + } + } + } +#endif +} + +/* EXTS.B Rm,Rn */ +inline void sh34_base_device::EXTSB(const UINT16 opcode) +{ + m_r[Rn] = ((INT32)m_r[Rm] << 24) >> 24; +} + +/* EXTS.W Rm,Rn */ +inline void sh34_base_device::EXTSW(const UINT16 opcode) +{ + m_r[Rn] = ((INT32)m_r[Rm] << 16) >> 16; +} + +/* EXTU.B Rm,Rn */ +inline void sh34_base_device::EXTUB(const UINT16 opcode) +{ + m_r[Rn] = m_r[Rm] & 0x000000ff; +} + +/* EXTU.W Rm,Rn */ +inline void sh34_base_device::EXTUW(const UINT16 opcode) +{ + m_r[Rn] = m_r[Rm] & 0x0000ffff; +} + +/* JMP @Rm */ +inline void sh34_base_device::JMP(const UINT16 opcode) +{ + m_delay = m_pc; + m_pc = m_ea = m_r[Rn]; +} + +/* JSR @Rm */ +inline void sh34_base_device::JSR(const UINT16 opcode) +{ + m_delay = m_pc; + m_pr = m_pc + 2; + m_pc = m_ea = m_r[Rn]; + m_sh4_icount--; +} + + +/* LDC Rm,SR */ +inline void sh34_base_device::LDCSR(const UINT16 opcode) +{ + UINT32 reg; + + reg = m_r[Rn]; + if ((machine().debug_flags & DEBUG_FLAG_ENABLED) != 0) + sh4_syncronize_register_bank((m_sr & sRB) >> 29); + if ((m_r[Rn] & sRB) != (m_sr & sRB)) + sh4_change_register_bank(m_r[Rn] & sRB ? 1 : 0); + m_sr = reg & FLAGS; + sh4_exception_recompute(); +} + +/* LDC Rm,GBR */ +inline void sh34_base_device::LDCGBR(const UINT16 opcode) +{ + m_gbr = m_r[Rn]; +} + +/* LDC Rm,VBR */ +inline void sh34_base_device::LDCVBR(const UINT16 opcode) +{ + m_vbr = m_r[Rn]; +} + +/* LDC.L @Rm+,SR */ +inline void sh34_base_device::LDCMSR(const UINT16 opcode) +{ + UINT32 old; + + old = m_sr; + m_ea = m_r[Rn]; + m_sr = RL(m_ea ) & FLAGS; + if ((machine().debug_flags & DEBUG_FLAG_ENABLED) != 0) + sh4_syncronize_register_bank((old & sRB) >> 29); + if ((old & sRB) != (m_sr & sRB)) + sh4_change_register_bank(m_sr & sRB ? 1 : 0); + m_r[Rn] += 4; + m_sh4_icount -= 2; + sh4_exception_recompute(); +} + +/* LDC.L @Rm+,GBR */ +inline void sh34_base_device::LDCMGBR(const UINT16 opcode) +{ + m_ea = m_r[Rn]; + m_gbr = RL(m_ea ); + m_r[Rn] += 4; + m_sh4_icount -= 2; +} + +/* LDC.L @Rm+,VBR */ +inline void sh34_base_device::LDCMVBR(const UINT16 opcode) +{ + m_ea = m_r[Rn]; + m_vbr = RL(m_ea ); + m_r[Rn] += 4; + m_sh4_icount -= 2; +} + +/* LDS Rm,MACH */ +inline void sh34_base_device::LDSMACH(const UINT16 opcode) +{ + m_mach = m_r[Rn]; +} + +/* LDS Rm,MACL */ +inline void sh34_base_device::LDSMACL(const UINT16 opcode) +{ + m_macl = m_r[Rn]; +} + +/* LDS Rm,PR */ +inline void sh34_base_device::LDSPR(const UINT16 opcode) +{ + m_pr = m_r[Rn]; +} + +/* LDS.L @Rm+,MACH */ +inline void sh34_base_device::LDSMMACH(const UINT16 opcode) +{ + m_ea = m_r[Rn]; + m_mach = RL(m_ea ); + m_r[Rn] += 4; +} + +/* LDS.L @Rm+,MACL */ +inline void sh34_base_device::LDSMMACL(const UINT16 opcode) +{ + m_ea = m_r[Rn]; + m_macl = RL(m_ea ); + m_r[Rn] += 4; +} + +/* LDS.L @Rm+,PR */ +inline void sh34_base_device::LDSMPR(const UINT16 opcode) +{ + m_ea = m_r[Rn]; + m_pr = RL(m_ea ); + m_r[Rn] += 4; +} + +/* MAC.L @Rm+,@Rn+ */ +inline void sh34_base_device::MAC_L(const UINT16 opcode) +{ + UINT32 m = Rm; UINT32 n = Rn; + + UINT32 RnL, RnH, RmL, RmH, Res0, Res1, Res2; + UINT32 temp0, temp1, temp2, temp3; + INT32 tempm, tempn, fnLmL; + + tempn = (INT32) RL(m_r[n] ); + m_r[n] += 4; + tempm = (INT32) RL(m_r[m] ); + m_r[m] += 4; + if ((INT32) (tempn ^ tempm) < 0) + fnLmL = -1; + else + fnLmL = 0; + if (tempn < 0) + tempn = 0 - tempn; + if (tempm < 0) + tempm = 0 - tempm; + temp1 = (UINT32) tempn; + temp2 = (UINT32) tempm; + RnL = temp1 & 0x0000ffff; + RnH = (temp1 >> 16) & 0x0000ffff; + RmL = temp2 & 0x0000ffff; + RmH = (temp2 >> 16) & 0x0000ffff; + temp0 = RmL * RnL; + temp1 = RmH * RnL; + temp2 = RmL * RnH; + temp3 = RmH * RnH; + Res2 = 0; + Res1 = temp1 + temp2; + if (Res1 < temp1) + Res2 += 0x00010000; + temp1 = (Res1 << 16) & 0xffff0000; + Res0 = temp0 + temp1; + if (Res0 < temp0) + Res2++; + Res2 = Res2 + ((Res1 >> 16) & 0x0000ffff) + temp3; + if (fnLmL < 0) + { + Res2 = ~Res2; + if (Res0 == 0) + Res2++; + else + Res0 = (~Res0) + 1; + } + if (m_sr & S) + { + Res0 = m_macl + Res0; + if (m_macl > Res0) + Res2++; + Res2 += (m_mach & 0x0000ffff); + if (((INT32) Res2 < 0) && (Res2 < 0xffff8000)) + { + Res2 = 0x00008000; + Res0 = 0x00000000; + } + else if (((INT32) Res2 > 0) && (Res2 > 0x00007fff)) + { + Res2 = 0x00007fff; + Res0 = 0xffffffff; + } + m_mach = Res2; + m_macl = Res0; + } + else + { + Res0 = m_macl + Res0; + if (m_macl > Res0) + Res2++; + Res2 += m_mach; + m_mach = Res2; + m_macl = Res0; + } + m_sh4_icount -= 2; +} + +/* MAC.W @Rm+,@Rn+ */ +inline void sh34_base_device::MAC_W(const UINT16 opcode) +{ + UINT32 m = Rm; UINT32 n = Rn; + + INT32 tempm, tempn, dest, src, ans; + UINT32 templ; + + tempn = (INT32) RW(m_r[n] ); + m_r[n] += 2; + tempm = (INT32) RW(m_r[m] ); + m_r[m] += 2; + templ = m_macl; + tempm = ((INT32) (short) tempn * (INT32) (short) tempm); + if ((INT32) m_macl >= 0) + dest = 0; + else + dest = 1; + if ((INT32) tempm >= 0) + { + src = 0; + tempn = 0; + } + else + { + src = 1; + tempn = 0xffffffff; + } + src += dest; + m_macl += tempm; + if ((INT32) m_macl >= 0) + ans = 0; + else + ans = 1; + ans += dest; + if (m_sr & S) + { + if (ans == 1) + { + if (src == 0) + m_macl = 0x7fffffff; + if (src == 2) + m_macl = 0x80000000; + } + } + else + { + m_mach += tempn; + if (templ > m_macl) + m_mach += 1; + } + m_sh4_icount -= 2; +} + +/* MOV Rm,Rn */ +inline void sh34_base_device::MOV(const UINT16 opcode) +{ + m_r[Rn] = m_r[Rm]; +} + +/* MOV.B Rm,@Rn */ +inline void sh34_base_device::MOVBS(const UINT16 opcode) +{ + m_ea = m_r[Rn]; + WB(m_ea, m_r[Rm] & 0x000000ff); +} + +/* MOV.W Rm,@Rn */ +inline void sh34_base_device::MOVWS(const UINT16 opcode) +{ + m_ea = m_r[Rn]; + WW(m_ea, m_r[Rm] & 0x0000ffff); +} + +/* MOV.L Rm,@Rn */ +inline void sh34_base_device::MOVLS(const UINT16 opcode) +{ + m_ea = m_r[Rn]; + WL(m_ea, m_r[Rm] ); +} + +/* MOV.B @Rm,Rn */ +inline void sh34_base_device::MOVBL(const UINT16 opcode) +{ + m_ea = m_r[Rm]; + m_r[Rn] = (UINT32)(INT32)(INT16)(INT8) RB( m_ea ); +} + +/* MOV.W @Rm,Rn */ +inline void sh34_base_device::MOVWL(const UINT16 opcode) +{ + m_ea = m_r[Rm]; + m_r[Rn] = (UINT32)(INT32)(INT16) RW(m_ea ); +} + +/* MOV.L @Rm,Rn */ +inline void sh34_base_device::MOVLL(const UINT16 opcode) +{ + m_ea = m_r[Rm]; + m_r[Rn] = RL(m_ea ); +} + +/* MOV.B Rm,@-Rn */ +inline void sh34_base_device::MOVBM(const UINT16 opcode) +{ + UINT32 data = m_r[Rm] & 0x000000ff; + + m_r[Rn] -= 1; + WB(m_r[Rn], data ); +} + +/* MOV.W Rm,@-Rn */ +inline void sh34_base_device::MOVWM(const UINT16 opcode) +{ + UINT32 data = m_r[Rm] & 0x0000ffff; + + m_r[Rn] -= 2; + WW(m_r[Rn], data ); +} + +/* MOV.L Rm,@-Rn */ +inline void sh34_base_device::MOVLM(const UINT16 opcode) +{ + UINT32 data = m_r[Rm]; + + m_r[Rn] -= 4; + WL(m_r[Rn], data ); +} + +/* MOV.B @Rm+,Rn */ +inline void sh34_base_device::MOVBP(const UINT16 opcode) +{ + UINT32 m = Rm; UINT32 n = Rn; + + m_r[n] = (UINT32)(INT32)(INT16)(INT8) RB( m_r[m] ); + if (n != m) + m_r[m] += 1; +} + +/* MOV.W @Rm+,Rn */ +inline void sh34_base_device::MOVWP(const UINT16 opcode) +{ + UINT32 m = Rm; UINT32 n = Rn; + + m_r[n] = (UINT32)(INT32)(INT16) RW(m_r[m] ); + if (n != m) + m_r[m] += 2; +} + +/* MOV.L @Rm+,Rn */ +inline void sh34_base_device::MOVLP(const UINT16 opcode) +{ + UINT32 m = Rm; UINT32 n = Rn; + + m_r[n] = RL(m_r[m] ); + if (n != m) + m_r[m] += 4; +} + +/* MOV.B Rm,@(R0,Rn) */ +inline void sh34_base_device::MOVBS0(const UINT16 opcode) +{ + m_ea = m_r[Rn] + m_r[0]; + WB(m_ea, m_r[Rm] & 0x000000ff ); +} + +/* MOV.W Rm,@(R0,Rn) */ +inline void sh34_base_device::MOVWS0(const UINT16 opcode) +{ + m_ea = m_r[Rn] + m_r[0]; + WW(m_ea, m_r[Rm] & 0x0000ffff ); +} + +/* MOV.L Rm,@(R0,Rn) */ +inline void sh34_base_device::MOVLS0(const UINT16 opcode) +{ + m_ea = m_r[Rn] + m_r[0]; + WL(m_ea, m_r[Rm] ); +} + +/* MOV.B @(R0,Rm),Rn */ +inline void sh34_base_device::MOVBL0(const UINT16 opcode) +{ + m_ea = m_r[Rm] + m_r[0]; + m_r[Rn] = (UINT32)(INT32)(INT16)(INT8) RB( m_ea ); +} + +/* MOV.W @(R0,Rm),Rn */ +inline void sh34_base_device::MOVWL0(const UINT16 opcode) +{ + m_ea = m_r[Rm] + m_r[0]; + m_r[Rn] = (UINT32)(INT32)(INT16) RW(m_ea ); +} + +/* MOV.L @(R0,Rm),Rn */ +inline void sh34_base_device::MOVLL0(const UINT16 opcode) +{ + m_ea = m_r[Rm] + m_r[0]; + m_r[Rn] = RL(m_ea ); +} + +/* MOV #imm,Rn */ +inline void sh34_base_device::MOVI(const UINT16 opcode) +{ + m_r[Rn] = (UINT32)(INT32)(INT16)(INT8)(opcode&0xff); +} + +/* MOV.W @(disp8,PC),Rn */ +inline void sh34_base_device::MOVWI(const UINT16 opcode) +{ + UINT32 disp = opcode & 0xff; + m_ea = m_pc + disp * 2 + 2; + m_r[Rn] = (UINT32)(INT32)(INT16) RW(m_ea ); +} + +/* MOV.L @(disp8,PC),Rn */ +inline void sh34_base_device::MOVLI(const UINT16 opcode) +{ + UINT32 disp = opcode & 0xff; + m_ea = ((m_pc + 2) & ~3) + disp * 4; + m_r[Rn] = RL(m_ea ); +} + +/* MOV.B @(disp8,GBR),R0 */ +inline void sh34_base_device::MOVBLG(const UINT16 opcode) +{ + UINT32 disp = opcode & 0xff; + m_ea = m_gbr + disp; + m_r[0] = (UINT32)(INT32)(INT16)(INT8) RB( m_ea ); +} + +/* MOV.W @(disp8,GBR),R0 */ +inline void sh34_base_device::MOVWLG(const UINT16 opcode) +{ + UINT32 disp = opcode & 0xff; + m_ea = m_gbr + disp * 2; + m_r[0] = (INT32)(INT16) RW(m_ea ); +} + +/* MOV.L @(disp8,GBR),R0 */ +inline void sh34_base_device::MOVLLG(const UINT16 opcode) +{ + UINT32 disp = opcode & 0xff; + m_ea = m_gbr + disp * 4; + m_r[0] = RL(m_ea ); +} + +/* MOV.B R0,@(disp8,GBR) */ +inline void sh34_base_device::MOVBSG(const UINT16 opcode) +{ + UINT32 disp = opcode & 0xff; + m_ea = m_gbr + disp; + WB(m_ea, m_r[0] & 0x000000ff ); +} + +/* MOV.W R0,@(disp8,GBR) */ +inline void sh34_base_device::MOVWSG(const UINT16 opcode) +{ + UINT32 disp = opcode & 0xff; + m_ea = m_gbr + disp * 2; + WW(m_ea, m_r[0] & 0x0000ffff ); +} + +/* MOV.L R0,@(disp8,GBR) */ +inline void sh34_base_device::MOVLSG(const UINT16 opcode) +{ + UINT32 disp = opcode & 0xff; + m_ea = m_gbr + disp * 4; + WL(m_ea, m_r[0] ); +} + +/* MOV.B R0,@(disp4,Rm) */ +inline void sh34_base_device::MOVBS4(const UINT16 opcode) +{ + UINT32 disp = opcode & 0x0f; + m_ea = m_r[Rm] + disp; + WB(m_ea, m_r[0] & 0x000000ff ); +} + +/* MOV.W R0,@(disp4,Rm) */ +inline void sh34_base_device::MOVWS4(const UINT16 opcode) +{ + UINT32 disp = opcode & 0x0f; + m_ea = m_r[Rm] + disp * 2; + WW(m_ea, m_r[0] & 0x0000ffff ); +} + +/* MOV.L Rm,@(disp4,Rn) */ +inline void sh34_base_device::MOVLS4(const UINT16 opcode) +{ + UINT32 disp = opcode & 0x0f; + m_ea = m_r[Rn] + disp * 4; + WL(m_ea, m_r[Rm] ); +} + +/* MOV.B @(disp4,Rm),R0 */ +inline void sh34_base_device::MOVBL4(const UINT16 opcode) +{ + UINT32 disp = opcode & 0x0f; + m_ea = m_r[Rm] + disp; + m_r[0] = (UINT32)(INT32)(INT16)(INT8) RB( m_ea ); +} + +/* MOV.W @(disp4,Rm),R0 */ +inline void sh34_base_device::MOVWL4(const UINT16 opcode) +{ + UINT32 disp = opcode & 0x0f; + m_ea = m_r[Rm] + disp * 2; + m_r[0] = (UINT32)(INT32)(INT16) RW(m_ea ); +} + +/* MOV.L @(disp4,Rm),Rn */ +inline void sh34_base_device::MOVLL4(const UINT16 opcode) +{ + UINT32 disp = opcode & 0x0f; + m_ea = m_r[Rm] + disp * 4; + m_r[Rn] = RL(m_ea ); +} + +/* MOVA @(disp8,PC),R0 */ +inline void sh34_base_device::MOVA(const UINT16 opcode) +{ + UINT32 disp = opcode & 0xff; + m_ea = ((m_pc + 2) & ~3) + disp * 4; + m_r[0] = m_ea; +} + +/* MOVT Rn */ +void sh34_base_device::MOVT(const UINT16 opcode) +{ + m_r[Rn] = m_sr & T; +} + +/* MUL.L Rm,Rn */ +inline void sh34_base_device::MULL(const UINT16 opcode) +{ + m_macl = m_r[Rn] * m_r[Rm]; + m_sh4_icount--; +} + +/* MULS Rm,Rn */ +inline void sh34_base_device::MULS(const UINT16 opcode) +{ + m_macl = (INT16) m_r[Rn] * (INT16) m_r[Rm]; +} + +/* MULU Rm,Rn */ +inline void sh34_base_device::MULU(const UINT16 opcode) +{ + m_macl = (UINT16) m_r[Rn] * (UINT16) m_r[Rm]; +} + +/* NEG Rm,Rn */ +inline void sh34_base_device::NEG(const UINT16 opcode) +{ + m_r[Rn] = 0 - m_r[Rm]; +} + +/* NEGC Rm,Rn */ +inline void sh34_base_device::NEGC(const UINT16 opcode) +{ + UINT32 temp; + + temp = m_r[Rm]; + m_r[Rn] = -temp - (m_sr & T); + if (temp || (m_sr & T)) + m_sr |= T; + else + m_sr &= ~T; +} + +/* NOP */ +inline void sh34_base_device::NOP(const UINT16 opcode) +{ +} + +/* NOT Rm,Rn */ +inline void sh34_base_device::NOT(const UINT16 opcode) +{ + m_r[Rn] = ~m_r[Rm]; +} + +/* OR Rm,Rn */ +inline void sh34_base_device::OR(const UINT16 opcode) +{ + m_r[Rn] |= m_r[Rm]; +} + +/* OR #imm,R0 */ +inline void sh34_base_device::ORI(const UINT16 opcode) +{ + m_r[0] |= (opcode&0xff); + m_sh4_icount -= 2; +} + +/* OR.B #imm,@(R0,GBR) */ +inline void sh34_base_device::ORM(const UINT16 opcode) +{ + UINT32 temp; + + m_ea = m_gbr + m_r[0]; + temp = RB( m_ea ); + temp |= (opcode&0xff); + WB(m_ea, temp ); +} + +/* ROTCL Rn */ +inline void sh34_base_device::ROTCL(const UINT16 opcode) +{ + UINT32 n = Rn; + + UINT32 temp; + + temp = (m_r[n] >> 31) & T; + m_r[n] = (m_r[n] << 1) | (m_sr & T); + m_sr = (m_sr & ~T) | temp; +} + +/* ROTCR Rn */ +inline void sh34_base_device::ROTCR(const UINT16 opcode) +{ + UINT32 n = Rn; + + UINT32 temp; + temp = (m_sr & T) << 31; + if (m_r[n] & T) + m_sr |= T; + else + m_sr &= ~T; + m_r[n] = (m_r[n] >> 1) | temp; +} + +/* ROTL Rn */ +inline void sh34_base_device::ROTL(const UINT16 opcode) +{ + UINT32 n = Rn; + + m_sr = (m_sr & ~T) | ((m_r[n] >> 31) & T); + m_r[n] = (m_r[n] << 1) | (m_r[n] >> 31); +} + +/* ROTR Rn */ +inline void sh34_base_device::ROTR(const UINT16 opcode) +{ + UINT32 n = Rn; + + m_sr = (m_sr & ~T) | (m_r[n] & T); + m_r[n] = (m_r[n] >> 1) | (m_r[n] << 31); +} + +/* RTE */ +inline void sh34_base_device::RTE(const UINT16 opcode) +{ + m_delay = m_pc; + m_pc = m_ea = m_spc; + if ((machine().debug_flags & DEBUG_FLAG_ENABLED) != 0) + sh4_syncronize_register_bank((m_sr & sRB) >> 29); + if ((m_ssr & sRB) != (m_sr & sRB)) + sh4_change_register_bank(m_ssr & sRB ? 1 : 0); + m_sr = m_ssr; + m_sh4_icount--; + sh4_exception_recompute(); +} + +/* RTS */ +inline void sh34_base_device::RTS(const UINT16 opcode) +{ + m_delay = m_pc; + m_pc = m_ea = m_pr; + m_sh4_icount--; +} + +/* SETT */ +inline void sh34_base_device::SETT(const UINT16 opcode) +{ + m_sr |= T; +} + +/* SHAL Rn (same as SHLL) */ +inline void sh34_base_device::SHAL(const UINT16 opcode) +{ + UINT32 n = Rn; + + m_sr = (m_sr & ~T) | ((m_r[n] >> 31) & T); + m_r[n] <<= 1; +} + +/* SHAR Rn */ +inline void sh34_base_device::SHAR(const UINT16 opcode) +{ + UINT32 n = Rn; + + m_sr = (m_sr & ~T) | (m_r[n] & T); + m_r[n] = (UINT32)((INT32)m_r[n] >> 1); +} + +/* SHLL Rn (same as SHAL) */ +inline void sh34_base_device::SHLL(const UINT16 opcode) +{ + UINT32 n = Rn; + + m_sr = (m_sr & ~T) | ((m_r[n] >> 31) & T); + m_r[n] <<= 1; +} + +/* SHLL2 Rn */ +inline void sh34_base_device::SHLL2(const UINT16 opcode) +{ + m_r[Rn] <<= 2; +} + +/* SHLL8 Rn */ +inline void sh34_base_device::SHLL8(const UINT16 opcode) +{ + m_r[Rn] <<= 8; +} + +/* SHLL16 Rn */ +inline void sh34_base_device::SHLL16(const UINT16 opcode) +{ + m_r[Rn] <<= 16; +} + +/* SHLR Rn */ +inline void sh34_base_device::SHLR(const UINT16 opcode) +{ + UINT32 n = Rn; + + m_sr = (m_sr & ~T) | (m_r[n] & T); + m_r[n] >>= 1; +} + +/* SHLR2 Rn */ +inline void sh34_base_device::SHLR2(const UINT16 opcode) +{ + m_r[Rn] >>= 2; +} + +/* SHLR8 Rn */ +inline void sh34_base_device::SHLR8(const UINT16 opcode) +{ + m_r[Rn] >>= 8; +} + +/* SHLR16 Rn */ +inline void sh34_base_device::SHLR16(const UINT16 opcode) +{ + m_r[Rn] >>= 16; +} + +/* SLEEP */ +inline void sh34_base_device::SLEEP(const UINT16 opcode) +{ + /* 0 = normal mode */ + /* 1 = enters into power-down mode */ + /* 2 = go out the power-down mode after an exception */ + if(m_sleep_mode != 2) + m_pc -= 2; + m_sh4_icount -= 2; + /* Wait_for_exception; */ + if(m_sleep_mode == 0) + m_sleep_mode = 1; + else if(m_sleep_mode == 2) + m_sleep_mode = 0; +} + +/* STC SR,Rn */ +inline void sh34_base_device::STCSR(const UINT16 opcode) +{ + m_r[Rn] = m_sr; +} + +/* STC GBR,Rn */ +inline void sh34_base_device::STCGBR(const UINT16 opcode) +{ + m_r[Rn] = m_gbr; +} + +/* STC VBR,Rn */ +inline void sh34_base_device::STCVBR(const UINT16 opcode) +{ + m_r[Rn] = m_vbr; +} + +/* STC.L SR,@-Rn */ +inline void sh34_base_device::STCMSR(const UINT16 opcode) +{ + UINT32 n = Rn; + + m_r[n] -= 4; + m_ea = m_r[n]; + WL(m_ea, m_sr ); + m_sh4_icount--; +} + +/* STC.L GBR,@-Rn */ +inline void sh34_base_device::STCMGBR(const UINT16 opcode) +{ + UINT32 n = Rn; + + m_r[n] -= 4; + m_ea = m_r[n]; + WL(m_ea, m_gbr ); + m_sh4_icount--; +} + +/* STC.L VBR,@-Rn */ +inline void sh34_base_device::STCMVBR(const UINT16 opcode) +{ + UINT32 n = Rn; + + m_r[n] -= 4; + m_ea = m_r[n]; + WL(m_ea, m_vbr ); + m_sh4_icount--; +} + +/* STS MACH,Rn */ +inline void sh34_base_device::STSMACH(const UINT16 opcode) +{ + m_r[Rn] = m_mach; +} + +/* STS MACL,Rn */ +inline void sh34_base_device::STSMACL(const UINT16 opcode) +{ + m_r[Rn] = m_macl; +} + +/* STS PR,Rn */ +inline void sh34_base_device::STSPR(const UINT16 opcode) +{ + m_r[Rn] = m_pr; +} + +/* STS.L MACH,@-Rn */ +inline void sh34_base_device::STSMMACH(const UINT16 opcode) +{ + UINT32 n = Rn; + + m_r[n] -= 4; + m_ea = m_r[n]; + WL(m_ea, m_mach ); +} + +/* STS.L MACL,@-Rn */ +inline void sh34_base_device::STSMMACL(const UINT16 opcode) +{ + UINT32 n = Rn; + + m_r[n] -= 4; + m_ea = m_r[n]; + WL(m_ea, m_macl ); +} + +/* STS.L PR,@-Rn */ +inline void sh34_base_device::STSMPR(const UINT16 opcode) +{ + UINT32 n = Rn; + + m_r[n] -= 4; + m_ea = m_r[n]; + WL(m_ea, m_pr ); +} + +/* SUB Rm,Rn */ +inline void sh34_base_device::SUB(const UINT16 opcode) +{ + m_r[Rn] -= m_r[Rm]; +} + +/* SUBC Rm,Rn */ +inline void sh34_base_device::SUBC(const UINT16 opcode) +{ + UINT32 m = Rm; UINT32 n = Rn; + + UINT32 tmp0, tmp1; + + tmp1 = m_r[n] - m_r[m]; + tmp0 = m_r[n]; + m_r[n] = tmp1 - (m_sr & T); + if (tmp0 < tmp1) + m_sr |= T; + else + m_sr &= ~T; + if (tmp1 < m_r[n]) + m_sr |= T; +} + +/* SUBV Rm,Rn */ +inline void sh34_base_device::SUBV(const UINT16 opcode) +{ + UINT32 m = Rm; UINT32 n = Rn; + + INT32 dest, src, ans; + + if ((INT32) m_r[n] >= 0) + dest = 0; + else + dest = 1; + if ((INT32) m_r[m] >= 0) + src = 0; + else + src = 1; + src += dest; + m_r[n] -= m_r[m]; + if ((INT32) m_r[n] >= 0) + ans = 0; + else + ans = 1; + ans += dest; + if (src == 1) + { + if (ans == 1) + m_sr |= T; + else + m_sr &= ~T; + } + else + m_sr &= ~T; +} + +/* SWAP.B Rm,Rn */ +inline void sh34_base_device::SWAPB(const UINT16 opcode) +{ + UINT32 m = Rm; UINT32 n = Rn; + + UINT32 temp0, temp1; + + temp0 = m_r[m] & 0xffff0000; + temp1 = (m_r[m] & 0x000000ff) << 8; + m_r[n] = (m_r[m] >> 8) & 0x000000ff; + m_r[n] = m_r[n] | temp1 | temp0; +} + +/* SWAP.W Rm,Rn */ +inline void sh34_base_device::SWAPW(const UINT16 opcode) +{ + UINT32 m = Rm; UINT32 n = Rn; + + UINT32 temp; + + temp = (m_r[m] >> 16) & 0x0000ffff; + m_r[n] = (m_r[m] << 16) | temp; +} + +/* TAS.B @Rn */ +inline void sh34_base_device::TAS(const UINT16 opcode) +{ + UINT32 n = Rn; + + UINT32 temp; + m_ea = m_r[n]; + /* Bus Lock enable */ + temp = RB( m_ea ); + if (temp == 0) + m_sr |= T; + else + m_sr &= ~T; + temp |= 0x80; + /* Bus Lock disable */ + WB(m_ea, temp ); + m_sh4_icount -= 3; +} + +/* TRAPA #imm */ +inline void sh34_base_device::TRAPA(const UINT16 opcode) +{ + UINT32 imm = opcode & 0xff; + + if (m_cpu_type == CPU_TYPE_SH4) + { + m_m[TRA] = imm << 2; + } + else /* SH3 */ + { + m_sh3internal_upper[SH3_TRA_ADDR] = imm << 2; + } + + + m_ssr = m_sr; + m_spc = m_pc; + m_sgr = m_r[15]; + + m_sr |= MD; + if ((machine().debug_flags & DEBUG_FLAG_ENABLED) != 0) + sh4_syncronize_register_bank((m_sr & sRB) >> 29); + if (!(m_sr & sRB)) + sh4_change_register_bank(1); + m_sr |= sRB; + m_sr |= BL; + sh4_exception_recompute(); + + if (m_cpu_type == CPU_TYPE_SH4) + { + m_m[EXPEVT] = 0x00000160; + } + else /* SH3 */ + { + m_sh3internal_upper[SH3_EXPEVT_ADDR] = 0x00000160; + } + + m_pc = m_vbr + 0x00000100; + + m_sh4_icount -= 7; +} + +/* TST Rm,Rn */ +inline void sh34_base_device::TST(const UINT16 opcode) +{ + if ((m_r[Rn] & m_r[Rm]) == 0) + m_sr |= T; + else + m_sr &= ~T; +} + +/* TST #imm,R0 */ +inline void sh34_base_device::TSTI(const UINT16 opcode) +{ + UINT32 imm = opcode & 0xff; + + if ((imm & m_r[0]) == 0) + m_sr |= T; + else + m_sr &= ~T; +} + +/* TST.B #imm,@(R0,GBR) */ +inline void sh34_base_device::TSTM(const UINT16 opcode) +{ + UINT32 imm = opcode & 0xff; + + m_ea = m_gbr + m_r[0]; + if ((imm & RB( m_ea )) == 0) + m_sr |= T; + else + m_sr &= ~T; + m_sh4_icount -= 2; +} + +/* XOR Rm,Rn */ +inline void sh34_base_device::XOR(const UINT16 opcode) +{ + m_r[Rn] ^= m_r[Rm]; +} + +/* XOR #imm,R0 */ +inline void sh34_base_device::XORI(const UINT16 opcode) +{ + UINT32 imm = opcode & 0xff; + m_r[0] ^= imm; +} + +/* XOR.B #imm,@(R0,GBR) */ +inline void sh34_base_device::XORM(const UINT16 opcode) +{ + UINT32 imm = opcode & 0xff; + UINT32 temp; + + m_ea = m_gbr + m_r[0]; + temp = RB( m_ea ); + temp ^= imm; + WB(m_ea, temp ); + m_sh4_icount -= 2; +} + +/* XTRCT Rm,Rn */ +inline void sh34_base_device::XTRCT(const UINT16 opcode) +{ + UINT32 m = Rm; UINT32 n = Rn; + + UINT32 temp; + + temp = (m_r[m] << 16) & 0xffff0000; + m_r[n] = (m_r[n] >> 16) & 0x0000ffff; + m_r[n] |= temp; +} + +/* STC SSR,Rn */ +inline void sh34_base_device::STCSSR(const UINT16 opcode) +{ + m_r[Rn] = m_ssr; +} + +/* STC SPC,Rn */ +inline void sh34_base_device::STCSPC(const UINT16 opcode) +{ + m_r[Rn] = m_spc; +} + +/* STC SGR,Rn */ +inline void sh34_base_device::STCSGR(const UINT16 opcode) +{ + m_r[Rn] = m_sgr; +} + +/* STS FPUL,Rn */ +inline void sh34_base_device::STSFPUL(const UINT16 opcode) +{ + m_r[Rn] = m_fpul; +} + +/* STS FPSCR,Rn */ +inline void sh34_base_device::STSFPSCR(const UINT16 opcode) +{ + m_r[Rn] = m_fpscr & 0x003FFFFF; +} + +/* STC DBR,Rn */ +inline void sh34_base_device::STCDBR(const UINT16 opcode) +{ + m_r[Rn] = m_dbr; +} + +/* STCRBANK Rm_BANK,Rn */ +inline void sh34_base_device::STCRBANK(const UINT16 opcode) +{ + UINT32 m = Rm; + + m_r[Rn] = m_rbnk[m_sr&sRB ? 0 : 1][m & 7]; +} + +/* STCMRBANK Rm_BANK,@-Rn */ +inline void sh34_base_device::STCMRBANK(const UINT16 opcode) +{ + UINT32 m = Rm; UINT32 n = Rn; + + m_r[n] -= 4; + m_ea = m_r[n]; + WL(m_ea, m_rbnk[m_sr&sRB ? 0 : 1][m & 7]); + m_sh4_icount--; +} + +/* MOVCA.L R0,@Rn */ +inline void sh34_base_device::MOVCAL(const UINT16 opcode) +{ + m_ea = m_r[Rn]; + WL(m_ea, m_r[0] ); +} + +inline void sh34_base_device::CLRS(const UINT16 opcode) +{ + m_sr &= ~S; +} + +inline void sh34_base_device::SETS(const UINT16 opcode) +{ + m_sr |= S; +} + +/* STS.L SGR,@-Rn */ +inline void sh34_base_device::STCMSGR(const UINT16 opcode) +{ + UINT32 n = Rn; + + m_r[n] -= 4; + m_ea = m_r[n]; + WL(m_ea, m_sgr ); +} + +/* STS.L FPUL,@-Rn */ +inline void sh34_base_device::STSMFPUL(const UINT16 opcode) +{ + UINT32 n = Rn; + + m_r[n] -= 4; + m_ea = m_r[n]; + WL(m_ea, m_fpul ); +} + +/* STS.L FPSCR,@-Rn */ +inline void sh34_base_device::STSMFPSCR(const UINT16 opcode) +{ + UINT32 n = Rn; + + m_r[n] -= 4; + m_ea = m_r[n]; + WL(m_ea, m_fpscr & 0x003FFFFF); +} + +/* STC.L DBR,@-Rn */ +inline void sh34_base_device::STCMDBR(const UINT16 opcode) +{ + UINT32 n = Rn; + + m_r[n] -= 4; + m_ea = m_r[n]; + WL(m_ea, m_dbr ); +} + +/* STC.L SSR,@-Rn */ +inline void sh34_base_device::STCMSSR(const UINT16 opcode) +{ + UINT32 n = Rn; + + m_r[n] -= 4; + m_ea = m_r[n]; + WL(m_ea, m_ssr ); +} + +/* STC.L SPC,@-Rn */ +inline void sh34_base_device::STCMSPC(const UINT16 opcode) +{ + UINT32 n = Rn; + + m_r[n] -= 4; + m_ea = m_r[n]; + WL(m_ea, m_spc ); +} + +/* LDS.L @Rm+,FPUL */ +inline void sh34_base_device::LDSMFPUL(const UINT16 opcode) +{ + m_ea = m_r[Rn]; + m_fpul = RL(m_ea ); + m_r[Rn] += 4; +} + +/* LDS.L @Rm+,FPSCR */ +inline void sh34_base_device::LDSMFPSCR(const UINT16 opcode) +{ + UINT32 s; + + s = m_fpscr; + m_ea = m_r[Rn]; + m_fpscr = RL(m_ea ); + m_fpscr &= 0x003FFFFF; + m_r[Rn] += 4; + if ((s & FR) != (m_fpscr & FR)) + sh4_swap_fp_registers(); +#ifdef LSB_FIRST + if ((s & PR) != (m_fpscr & PR)) + sh4_swap_fp_couples(); +#endif + m_fpu_sz = (m_fpscr & SZ) ? 1 : 0; + m_fpu_pr = (m_fpscr & PR) ? 1 : 0; +} + +/* LDC.L @Rm+,DBR */ +inline void sh34_base_device::LDCMDBR(const UINT16 opcode) +{ + m_ea = m_r[Rn]; + m_dbr = RL(m_ea ); + m_r[Rn] += 4; +} + +/* LDC.L @Rn+,Rm_BANK */ +inline void sh34_base_device::LDCMRBANK(const UINT16 opcode) +{ + UINT32 m = Rm; UINT32 n = Rn; + + m_ea = m_r[n]; + m_rbnk[m_sr&sRB ? 0 : 1][m & 7] = RL(m_ea ); + m_r[n] += 4; +} + +/* LDC.L @Rm+,SSR */ +inline void sh34_base_device::LDCMSSR(const UINT16 opcode) +{ + m_ea = m_r[Rn]; + m_ssr = RL(m_ea ); + m_r[Rn] += 4; +} + +/* LDC.L @Rm+,SPC */ +inline void sh34_base_device::LDCMSPC(const UINT16 opcode) +{ + m_ea = m_r[Rn]; + m_spc = RL(m_ea ); + m_r[Rn] += 4; +} + +/* LDS Rm,FPUL */ +inline void sh34_base_device::LDSFPUL(const UINT16 opcode) +{ + m_fpul = m_r[Rn]; +} + +/* LDS Rm,FPSCR */ +inline void sh34_base_device::LDSFPSCR(const UINT16 opcode) +{ + UINT32 s; + + s = m_fpscr; + m_fpscr = m_r[Rn] & 0x003FFFFF; + if ((s & FR) != (m_fpscr & FR)) + sh4_swap_fp_registers(); +#ifdef LSB_FIRST + if ((s & PR) != (m_fpscr & PR)) + sh4_swap_fp_couples(); +#endif + m_fpu_sz = (m_fpscr & SZ) ? 1 : 0; + m_fpu_pr = (m_fpscr & PR) ? 1 : 0; +} + +/* LDC Rm,DBR */ +inline void sh34_base_device::LDCDBR(const UINT16 opcode) +{ + m_dbr = m_r[Rn]; +} + +/* SHAD Rm,Rn */ +inline void sh34_base_device::SHAD(const UINT16 opcode) +{ + UINT32 m = Rm; UINT32 n = Rn; + + if ((m_r[m] & 0x80000000) == 0) + m_r[n] = m_r[n] << (m_r[m] & 0x1F); + else if ((m_r[m] & 0x1F) == 0) { + if ((m_r[n] & 0x80000000) == 0) + m_r[n] = 0; + else + m_r[n] = 0xFFFFFFFF; + } else + m_r[n]=(INT32)m_r[n] >> ((~m_r[m] & 0x1F)+1); +} + +/* SHLD Rm,Rn */ +inline void sh34_base_device::SHLD(const UINT16 opcode) +{ + UINT32 m = Rm; UINT32 n = Rn; + + if ((m_r[m] & 0x80000000) == 0) + m_r[n] = m_r[n] << (m_r[m] & 0x1F); + else if ((m_r[m] & 0x1F) == 0) + m_r[n] = 0; + else + m_r[n] = m_r[n] >> ((~m_r[m] & 0x1F)+1); +} + +/* LDCRBANK Rn,Rm_BANK */ +inline void sh34_base_device::LDCRBANK(const UINT16 opcode) +{ + UINT32 m = Rm; + + m_rbnk[m_sr&sRB ? 0 : 1][m & 7] = m_r[Rn]; +} + +/* LDC Rm,SSR */ +inline void sh34_base_device::LDCSSR(const UINT16 opcode) +{ + m_ssr = m_r[Rn]; +} + +/* LDC Rm,SPC */ +inline void sh34_base_device::LDCSPC(const UINT16 opcode) +{ + m_spc = m_r[Rn]; +} + +/* PREF @Rn */ +inline void sh34_base_device::PREFM(const UINT16 opcode) +{ + int a; + UINT32 addr,dest,sq; + + addr = m_r[Rn]; // address + if ((addr >= 0xE0000000) && (addr <= 0xE3FFFFFF)) + { + if (m_sh4_mmu_enabled) + { + addr = addr & 0xFFFFFFE0; + dest = sh4_getsqremap(addr); // good enough for naomi-gd rom, probably not much else + + } + else + { + sq = (addr & 0x20) >> 5; + dest = addr & 0x03FFFFE0; + if (sq == 0) + { + if (m_cpu_type == CPU_TYPE_SH4) + { + dest |= (m_m[QACR0] & 0x1C) << 24; + } + else + { + fatalerror("m_cpu_type != CPU_TYPE_SH4 but access internal regs\n"); + } + } + else + { + if (m_cpu_type == CPU_TYPE_SH4) + { + dest |= (m_m[QACR1] & 0x1C) << 24; + } + else + { + fatalerror("m_cpu_type != CPU_TYPE_SH4 but access internal regs\n"); + } + + } + addr = addr & 0xFFFFFFE0; + } + + for (a = 0;a < 4;a++) + { + // shouldn't be causing a memory read, should store sq writes in registers. + m_program->write_qword(dest, m_program->read_qword(addr)); + addr += 8; + dest += 8; + } + } +} + +/***************************************************************************** + * OPCODE DISPATCHERS + *****************************************************************************/ + + + + + + + + + + + + + + + + + +/* FMOV.S @Rm+,FRn PR=0 SZ=0 1111nnnnmmmm1001 */ +/* FMOV @Rm+,DRn PR=0 SZ=1 1111nnn0mmmm1001 */ +/* FMOV @Rm+,XDn PR=0 SZ=1 1111nnn1mmmm1001 */ +/* FMOV @Rm+,XDn PR=1 1111nnn1mmmm1001 */ +inline void sh34_base_device::FMOVMRIFR(const UINT16 opcode) +{ + UINT32 m = Rm; UINT32 n = Rn; + + if (m_fpu_pr) { /* PR = 1 */ + n = n & 14; + m_ea = m_r[m]; + m_r[m] += 8; + m_xf[n+NATIVE_ENDIAN_VALUE_LE_BE(1,0)] = RL(m_ea ); + m_xf[n+NATIVE_ENDIAN_VALUE_LE_BE(0,1)] = RL(m_ea+4 ); + } else { /* PR = 0 */ + if (m_fpu_sz) { /* SZ = 1 */ + if (n & 1) { + n = n & 14; + m_ea = m_r[m]; + m_xf[n] = RL(m_ea ); + m_r[m] += 4; + m_xf[n+1] = RL(m_ea+4 ); + m_r[m] += 4; + } else { + m_ea = m_r[m]; + m_fr[n] = RL(m_ea ); + m_r[m] += 4; + m_fr[n+1] = RL(m_ea+4 ); + m_r[m] += 4; + } + } else { /* SZ = 0 */ + m_ea = m_r[m]; + m_fr[n] = RL(m_ea ); + m_r[m] += 4; + } + } +} + +/* FMOV.S FRm,@Rn PR=0 SZ=0 1111nnnnmmmm1010 */ +/* FMOV DRm,@Rn PR=0 SZ=1 1111nnnnmmm01010 */ +/* FMOV XDm,@Rn PR=0 SZ=1 1111nnnnmmm11010 */ +/* FMOV XDm,@Rn PR=1 1111nnnnmmm11010 */ +inline void sh34_base_device::FMOVFRMR(const UINT16 opcode) +{ + UINT32 m = Rm; UINT32 n = Rn; + + if (m_fpu_pr) { /* PR = 1 */ + m= m & 14; + m_ea = m_r[n]; + WL(m_ea,m_xf[m+NATIVE_ENDIAN_VALUE_LE_BE(1,0)] ); + WL(m_ea+4,m_xf[m+NATIVE_ENDIAN_VALUE_LE_BE(0,1)] ); + } else { /* PR = 0 */ + if (m_fpu_sz) { /* SZ = 1 */ + if (m & 1) { + m= m & 14; + m_ea = m_r[n]; + WL(m_ea,m_xf[m] ); + WL(m_ea+4,m_xf[m+1] ); + } else { + m_ea = m_r[n]; + WL(m_ea,m_fr[m] ); + WL(m_ea+4,m_fr[m+1] ); + } + } else { /* SZ = 0 */ + m_ea = m_r[n]; + WL(m_ea,m_fr[m] ); + } + } +} + +/* FMOV.S FRm,@-Rn PR=0 SZ=0 1111nnnnmmmm1011 */ +/* FMOV DRm,@-Rn PR=0 SZ=1 1111nnnnmmm01011 */ +/* FMOV XDm,@-Rn PR=0 SZ=1 1111nnnnmmm11011 */ +/* FMOV XDm,@-Rn PR=1 1111nnnnmmm11011 */ +inline void sh34_base_device::FMOVFRMDR(const UINT16 opcode) +{ + UINT32 m = Rm; UINT32 n = Rn; + + if (m_fpu_pr) { /* PR = 1 */ + m= m & 14; + m_r[n] -= 8; + m_ea = m_r[n]; + WL(m_ea,m_xf[m+NATIVE_ENDIAN_VALUE_LE_BE(1,0)] ); + WL(m_ea+4,m_xf[m+NATIVE_ENDIAN_VALUE_LE_BE(0,1)] ); + } else { /* PR = 0 */ + if (m_fpu_sz) { /* SZ = 1 */ + if (m & 1) { + m= m & 14; + m_r[n] -= 8; + m_ea = m_r[n]; + WL(m_ea,m_xf[m] ); + WL(m_ea+4,m_xf[m+1] ); + } else { + m_r[n] -= 8; + m_ea = m_r[n]; + WL(m_ea,m_fr[m] ); + WL(m_ea+4,m_fr[m+1] ); + } + } else { /* SZ = 0 */ + m_r[n] -= 4; + m_ea = m_r[n]; + WL(m_ea,m_fr[m] ); + } + } +} + +/* FMOV.S FRm,@(R0,Rn) PR=0 SZ=0 1111nnnnmmmm0111 */ +/* FMOV DRm,@(R0,Rn) PR=0 SZ=1 1111nnnnmmm00111 */ +/* FMOV XDm,@(R0,Rn) PR=0 SZ=1 1111nnnnmmm10111 */ +/* FMOV XDm,@(R0,Rn) PR=1 1111nnnnmmm10111 */ +inline void sh34_base_device::FMOVFRS0(const UINT16 opcode) +{ + UINT32 m = Rm; UINT32 n = Rn; + + if (m_fpu_pr) { /* PR = 1 */ + m= m & 14; + m_ea = m_r[0] + m_r[n]; + WL(m_ea,m_xf[m+NATIVE_ENDIAN_VALUE_LE_BE(1,0)] ); + WL(m_ea+4,m_xf[m+NATIVE_ENDIAN_VALUE_LE_BE(0,1)] ); + } else { /* PR = 0 */ + if (m_fpu_sz) { /* SZ = 1 */ + if (m & 1) { + m= m & 14; + m_ea = m_r[0] + m_r[n]; + WL(m_ea,m_xf[m] ); + WL(m_ea+4,m_xf[m+1] ); + } else { + m_ea = m_r[0] + m_r[n]; + WL(m_ea,m_fr[m] ); + WL(m_ea+4,m_fr[m+1] ); + } + } else { /* SZ = 0 */ + m_ea = m_r[0] + m_r[n]; + WL(m_ea,m_fr[m] ); + } + } +} + +/* FMOV.S @(R0,Rm),FRn PR=0 SZ=0 1111nnnnmmmm0110 */ +/* FMOV @(R0,Rm),DRn PR=0 SZ=1 1111nnn0mmmm0110 */ +/* FMOV @(R0,Rm),XDn PR=0 SZ=1 1111nnn1mmmm0110 */ +/* FMOV @(R0,Rm),XDn PR=1 1111nnn1mmmm0110 */ +inline void sh34_base_device::FMOVS0FR(const UINT16 opcode) +{ + UINT32 m = Rm; UINT32 n = Rn; + + if (m_fpu_pr) { /* PR = 1 */ + n= n & 14; + m_ea = m_r[0] + m_r[m]; + m_xf[n+NATIVE_ENDIAN_VALUE_LE_BE(1,0)] = RL(m_ea ); + m_xf[n+NATIVE_ENDIAN_VALUE_LE_BE(0,1)] = RL(m_ea+4 ); + } else { /* PR = 0 */ + if (m_fpu_sz) { /* SZ = 1 */ + if (n & 1) { + n= n & 14; + m_ea = m_r[0] + m_r[m]; + m_xf[n] = RL(m_ea ); + m_xf[n+1] = RL(m_ea+4 ); + } else { + m_ea = m_r[0] + m_r[m]; + m_fr[n] = RL(m_ea ); + m_fr[n+1] = RL(m_ea+4 ); + } + } else { /* SZ = 0 */ + m_ea = m_r[0] + m_r[m]; + m_fr[n] = RL(m_ea ); + } + } +} + +/* FMOV.S @Rm,FRn PR=0 SZ=0 1111nnnnmmmm1000 */ +/* FMOV @Rm,DRn PR=0 SZ=1 1111nnn0mmmm1000 */ +/* FMOV @Rm,XDn PR=0 SZ=1 1111nnn1mmmm1000 */ +/* FMOV @Rm,XDn PR=1 1111nnn1mmmm1000 */ +/* FMOV @Rm,DRn PR=1 1111nnn0mmmm1000 */ +inline void sh34_base_device::FMOVMRFR(const UINT16 opcode) +{ + UINT32 m = Rm; UINT32 n = Rn; + + if (m_fpu_pr) { /* PR = 1 */ + if (n & 1) { + n= n & 14; + m_ea = m_r[m]; + m_xf[n+NATIVE_ENDIAN_VALUE_LE_BE(1,0)] = RL(m_ea ); + m_xf[n+NATIVE_ENDIAN_VALUE_LE_BE(0,1)] = RL(m_ea+4 ); + } else { + n= n & 14; + m_ea = m_r[m]; + m_fr[n+NATIVE_ENDIAN_VALUE_LE_BE(1,0)] = RL(m_ea ); + m_fr[n+NATIVE_ENDIAN_VALUE_LE_BE(0,1)] = RL(m_ea+4 ); + } + } else { /* PR = 0 */ + if (m_fpu_sz) { /* SZ = 1 */ + if (n & 1) { + n= n & 14; + m_ea = m_r[m]; + m_xf[n] = RL(m_ea ); + m_xf[n+1] = RL(m_ea+4 ); + } else { + n= n & 14; + m_ea = m_r[m]; + m_fr[n] = RL(m_ea ); + m_fr[n+1] = RL(m_ea+4 ); + } + } else { /* SZ = 0 */ + m_ea = m_r[m]; + m_fr[n] = RL(m_ea ); + } + } +} + +/* FMOV FRm,FRn PR=0 SZ=0 FRm -> FRn 1111nnnnmmmm1100 */ +/* FMOV DRm,DRn PR=0 SZ=1 DRm -> DRn 1111nnn0mmm01100 */ +/* FMOV XDm,DRn PR=1 XDm -> DRn 1111nnn0mmm11100 */ +/* FMOV DRm,XDn PR=1 DRm -> XDn 1111nnn1mmm01100 */ +/* FMOV XDm,XDn PR=1 XDm -> XDn 1111nnn1mmm11100 */ +inline void sh34_base_device::FMOVFR(const UINT16 opcode) +{ + UINT32 m = Rm; UINT32 n = Rn; + + if ((m_fpu_sz == 0) && (m_fpu_pr == 0)) /* SZ = 0 */ + m_fr[n] = m_fr[m]; + else { /* SZ = 1 or PR = 1 */ + if (m & 1) { + if (n & 1) { + m_xf[n & 14] = m_xf[m & 14]; + m_xf[n | 1] = m_xf[m | 1]; + } else { + m_fr[n] = m_xf[m & 14]; + m_fr[n | 1] = m_xf[m | 1]; + } + } else { + if (n & 1) { + m_xf[n & 14] = m_fr[m]; + m_xf[n | 1] = m_fr[m | 1]; // (a&14)+1 -> a|1 + } else { + m_fr[n] = m_fr[m]; + m_fr[n | 1] = m_fr[m | 1]; + } + } + } +} + +/* FLDI1 FRn 1111nnnn10011101 */ +inline void sh34_base_device::FLDI1(const UINT16 opcode) +{ + m_fr[Rn] = 0x3F800000; +} + +/* FLDI0 FRn 1111nnnn10001101 */ +inline void sh34_base_device::FLDI0(const UINT16 opcode) +{ + m_fr[Rn] = 0; +} + +/* FLDS FRm,FPUL 1111mmmm00011101 */ +inline void sh34_base_device:: FLDS(const UINT16 opcode) +{ + m_fpul = m_fr[Rn]; +} + +/* FSTS FPUL,FRn 1111nnnn00001101 */ +inline void sh34_base_device:: FSTS(const UINT16 opcode) +{ + m_fr[Rn] = m_fpul; +} + +/* FRCHG 1111101111111101 */ +void sh34_base_device::FRCHG() +{ + m_fpscr ^= FR; + sh4_swap_fp_registers(); +} + +/* FSCHG 1111001111111101 */ +void sh34_base_device::FSCHG() +{ + m_fpscr ^= SZ; + m_fpu_sz = (m_fpscr & SZ) ? 1 : 0; +} + +/* FTRC FRm,FPUL PR=0 1111mmmm00111101 */ +/* FTRC DRm,FPUL PR=1 1111mmm000111101 */ +inline void sh34_base_device::FTRC(const UINT16 opcode) +{ + UINT32 n = Rn; + + if (m_fpu_pr) { /* PR = 1 */ + if(n & 1) + fatalerror("SH-4: FTRC opcode used with n %d",n); + + n = n & 14; + *((INT32 *)&m_fpul) = (INT32)FP_RFD(n); + } else { /* PR = 0 */ + /* read m_fr[n] as float -> truncate -> fpul(32) */ + *((INT32 *)&m_fpul) = (INT32)FP_RFS(n); + } +} + +/* FLOAT FPUL,FRn PR=0 1111nnnn00101101 */ +/* FLOAT FPUL,DRn PR=1 1111nnn000101101 */ +inline void sh34_base_device::FLOAT(const UINT16 opcode) +{ + UINT32 n = Rn; + + if (m_fpu_pr) { /* PR = 1 */ + if(n & 1) + fatalerror("SH-4: FLOAT opcode used with n %d",n); + + n = n & 14; + FP_RFD(n) = (double)*((INT32 *)&m_fpul); + } else { /* PR = 0 */ + FP_RFS(n) = (float)*((INT32 *)&m_fpul); + } +} + +/* FNEG FRn PR=0 1111nnnn01001101 */ +/* FNEG DRn PR=1 1111nnn001001101 */ +inline void sh34_base_device::FNEG(const UINT16 opcode) +{ + UINT32 n = Rn; + + if (m_fpu_pr) { /* PR = 1 */ + FP_RFD(n) = -FP_RFD(n); + } else { /* PR = 0 */ + FP_RFS(n) = -FP_RFS(n); + } +} + +/* FABS FRn PR=0 1111nnnn01011101 */ +/* FABS DRn PR=1 1111nnn001011101 */ +inline void sh34_base_device::FABS(const UINT16 opcode) +{ + UINT32 n = Rn; + + if (m_fpu_pr) { /* PR = 1 */ +#ifdef LSB_FIRST + n = n | 1; // n & 14 + 1 + m_fr[n] = m_fr[n] & 0x7fffffff; +#else + n = n & 14; + m_fr[n] = m_fr[n] & 0x7fffffff; +#endif + } else { /* PR = 0 */ + m_fr[n] = m_fr[n] & 0x7fffffff; + } +} + +/* FCMP/EQ FRm,FRn PR=0 1111nnnnmmmm0100 */ +/* FCMP/EQ DRm,DRn PR=1 1111nnn0mmm00100 */ +inline void sh34_base_device::FCMP_EQ(const UINT16 opcode) +{ + UINT32 m = Rm; UINT32 n = Rn; + + if (m_fpu_pr) { /* PR = 1 */ + n = n & 14; + m = m & 14; + if (FP_RFD(n) == FP_RFD(m)) + m_sr |= T; + else + m_sr &= ~T; + } else { /* PR = 0 */ + if (FP_RFS(n) == FP_RFS(m)) + m_sr |= T; + else + m_sr &= ~T; + } +} + +/* FCMP/GT FRm,FRn PR=0 1111nnnnmmmm0101 */ +/* FCMP/GT DRm,DRn PR=1 1111nnn0mmm00101 */ +inline void sh34_base_device::FCMP_GT(const UINT16 opcode) +{ + UINT32 m = Rm; UINT32 n = Rn; + + if (m_fpu_pr) { /* PR = 1 */ + n = n & 14; + m = m & 14; + if (FP_RFD(n) > FP_RFD(m)) + m_sr |= T; + else + m_sr &= ~T; + } else { /* PR = 0 */ + if (FP_RFS(n) > FP_RFS(m)) + m_sr |= T; + else + m_sr &= ~T; + } +} + +/* FCNVDS DRm,FPUL PR=1 1111mmm010111101 */ +inline void sh34_base_device::FCNVDS(const UINT16 opcode) +{ + UINT32 n = Rn; + + if (m_fpu_pr) { /* PR = 1 */ + n = n & 14; + if (m_fpscr & RM) + m_fr[n | NATIVE_ENDIAN_VALUE_LE_BE(0,1)] &= 0xe0000000; /* round toward zero*/ + *((float *)&m_fpul) = (float)FP_RFD(n); + } +} + +/* FCNVSD FPUL, DRn PR=1 1111nnn010101101 */ +inline void sh34_base_device::FCNVSD(const UINT16 opcode) +{ + UINT32 n = Rn; + + if (m_fpu_pr) { /* PR = 1 */ + n = n & 14; + FP_RFD(n) = (double)*((float *)&m_fpul); + } +} + +/* FADD FRm,FRn PR=0 1111nnnnmmmm0000 */ +/* FADD DRm,DRn PR=1 1111nnn0mmm00000 */ +inline void sh34_base_device::FADD(const UINT16 opcode) +{ + UINT32 m = Rm; UINT32 n = Rn; + + if (m_fpu_pr) { /* PR = 1 */ + n = n & 14; + m = m & 14; + FP_RFD(n) = FP_RFD(n) + FP_RFD(m); + } else { /* PR = 0 */ + FP_RFS(n) = FP_RFS(n) + FP_RFS(m); + } +} + +/* FSUB FRm,FRn PR=0 1111nnnnmmmm0001 */ +/* FSUB DRm,DRn PR=1 1111nnn0mmm00001 */ +inline void sh34_base_device::FSUB(const UINT16 opcode) +{ + UINT32 m = Rm; UINT32 n = Rn; + + if (m_fpu_pr) { /* PR = 1 */ + n = n & 14; + m = m & 14; + FP_RFD(n) = FP_RFD(n) - FP_RFD(m); + } else { /* PR = 0 */ + FP_RFS(n) = FP_RFS(n) - FP_RFS(m); + } +} + + +/* FMUL FRm,FRn PR=0 1111nnnnmmmm0010 */ +/* FMUL DRm,DRn PR=1 1111nnn0mmm00010 */ +inline void sh34_base_device::FMUL(const UINT16 opcode) +{ + UINT32 m = Rm; UINT32 n = Rn; + + if (m_fpu_pr) { /* PR = 1 */ + n = n & 14; + m = m & 14; + FP_RFD(n) = FP_RFD(n) * FP_RFD(m); + } else { /* PR = 0 */ + FP_RFS(n) = FP_RFS(n) * FP_RFS(m); + } +} + +/* FDIV FRm,FRn PR=0 1111nnnnmmmm0011 */ +/* FDIV DRm,DRn PR=1 1111nnn0mmm00011 */ +inline void sh34_base_device::FDIV(const UINT16 opcode) +{ + UINT32 m = Rm; UINT32 n = Rn; + + if (m_fpu_pr) { /* PR = 1 */ + n = n & 14; + m = m & 14; + if (FP_RFD(m) == 0) + return; + FP_RFD(n) = FP_RFD(n) / FP_RFD(m); + } else { /* PR = 0 */ + if (FP_RFS(m) == 0) + return; + FP_RFS(n) = FP_RFS(n) / FP_RFS(m); + } +} + +/* FMAC FR0,FRm,FRn PR=0 1111nnnnmmmm1110 */ +inline void sh34_base_device::FMAC(const UINT16 opcode) +{ + UINT32 m = Rm; UINT32 n = Rn; + + if (m_fpu_pr == 0) { /* PR = 0 */ + FP_RFS(n) = (FP_RFS(0) * FP_RFS(m)) + FP_RFS(n); + } +} + +/* FSQRT FRn PR=0 1111nnnn01101101 */ +/* FSQRT DRn PR=1 1111nnnn01101101 */ +inline void sh34_base_device::FSQRT(const UINT16 opcode) +{ + UINT32 n = Rn; + + if (m_fpu_pr) { /* PR = 1 */ + n = n & 14; + if (FP_RFD(n) < 0) + return; + FP_RFD(n) = sqrtf(FP_RFD(n)); + } else { /* PR = 0 */ + if (FP_RFS(n) < 0) + return; + FP_RFS(n) = sqrtf(FP_RFS(n)); + } +} + +/* FSRRA FRn PR=0 1111nnnn01111101 */ +inline void sh34_base_device::FSRRA(const UINT16 opcode) +{ + UINT32 n = Rn; + + if (FP_RFS(n) < 0) + return; + FP_RFS(n) = 1.0f / sqrtf(FP_RFS(n)); +} + +/* FSSCA FPUL,FRn PR=0 1111nnn011111101 */ +void sh34_base_device::FSSCA(const UINT16 opcode) +{ + UINT32 n = Rn; + + float angle; + + angle = (((float)(m_fpul & 0xFFFF)) / 65536.0f) * 2.0f * (float) M_PI; + FP_RFS(n) = sinf(angle); + FP_RFS(n+1) = cosf(angle); +} + +/* FIPR FVm,FVn PR=0 1111nnmm11101101 */ +inline void sh34_base_device::FIPR(const UINT16 opcode) +{ + UINT32 n = Rn; + +UINT32 m; +float ml[4]; +int a; + + m = (n & 3) << 2; + n = n & 12; + for (a = 0;a < 4;a++) + ml[a] = FP_RFS(n+a) * FP_RFS(m+a); + FP_RFS(n+3) = ml[0] + ml[1] + ml[2] + ml[3]; +} + +/* FTRV XMTRX,FVn PR=0 1111nn0111111101 */ +void sh34_base_device::FTRV(const UINT16 opcode) +{ + UINT32 n = Rn; + +int i,j; +float sum[4]; + + n = n & 12; + for (i = 0;i < 4;i++) { + sum[i] = 0; + for (j=0;j < 4;j++) + sum[i] += FP_XFS((j << 2) + i)*FP_RFS(n + j); + } + for (i = 0;i < 4;i++) + FP_RFS(n + i) = sum[i]; +} + +inline void sh34_base_device::op1111_0xf13(const UINT16 opcode) +{ + if (opcode & 0x100) { + if (opcode & 0x200) { + switch (opcode & 0xC00) + { + case 0x000: + FSCHG(); + break; + case 0x800: + FRCHG(); + break; + default: + debugger_break(machine()); + break; + } + } else { + FTRV(opcode); + } + } else { + FSSCA(opcode); + } +} + +void sh34_base_device::dbreak(const UINT16 opcode) +{ + debugger_break(machine()); +} + + +inline void sh34_base_device::op1111_0x13(UINT16 opcode) +{ + switch((opcode >> 4) & 0x0f) + { + case 0x00: FSTS(opcode); break; + case 0x01: FLDS(opcode); break; + case 0x02: FLOAT(opcode); break; + case 0x03: FTRC(opcode); break; + case 0x04: FNEG(opcode); break; + case 0x05: FABS(opcode); break; + case 0x06: FSQRT(opcode); break; + case 0x07: FSRRA(opcode); break; + case 0x08: FLDI0(opcode); break; + case 0x09: FLDI1(opcode); break; + case 0x0a: FCNVSD(opcode); break; + case 0x0b: FCNVDS(opcode); break; + case 0x0c: dbreak(opcode); break; + case 0x0d: dbreak(opcode); break; + case 0x0e: FIPR(opcode); break; + case 0x0f: op1111_0xf13(opcode); break; + } +} + + +/***************************************************************************** + * MAME CPU INTERFACE + *****************************************************************************/ + +void sh34_base_device::device_reset() +{ + m_ppc = 0; + m_spc = 0; + m_pr = 0; + m_sr = 0; + m_ssr = 0; + m_gbr = 0; + m_vbr = 0; + m_mach = 0; + m_macl = 0; + memset(m_r, 0, sizeof(m_r)); + memset(m_rbnk, 0, sizeof(m_rbnk)); + m_sgr = 0; + memset(m_fr, 0, sizeof(m_fr)); + memset(m_xf, 0, sizeof(m_xf)); + m_ea = 0; + m_delay = 0; + m_cpu_off = 0; + m_pending_irq = 0; + m_test_irq = 0; + memset(m_exception_priority, 0, sizeof(m_exception_priority)); + memset(m_exception_requesting, 0, sizeof(m_exception_requesting)); + memset(m_m, 0, sizeof(m_m)); + memset(m_sh3internal_upper, 0, sizeof(m_sh3internal_upper)); + memset(m_sh3internal_lower, 0, sizeof(m_sh3internal_lower)); + memset(m_irq_line_state, 0, sizeof(m_irq_line_state)); + m_SH4_TSTR = 0; + m_SH4_TCNT0 = 0; + m_SH4_TCNT1 = 0; + m_SH4_TCNT2 = 0; + m_SH4_TCR0 = 0; + m_SH4_TCR1 = 0; + m_SH4_TCR2 = 0; + m_SH4_TCOR0 = 0; + m_SH4_TCOR1 = 0; + m_SH4_TCOR2 = 0; + m_SH4_TOCR = 0; + m_SH4_TCPR2 = 0; + m_SH4_IPRA = 0; + m_SH4_IPRC = 0; + m_SH4_SAR0 = 0; + m_SH4_SAR1 = 0; + m_SH4_SAR2 = 0; + m_SH4_SAR3 = 0; + m_SH4_DAR0 = 0; + m_SH4_DAR1 = 0; + m_SH4_DAR2 = 0; + m_SH4_DAR3 = 0; + m_SH4_CHCR0 = 0; + m_SH4_CHCR1 = 0; + m_SH4_CHCR2 = 0; + m_SH4_CHCR3 = 0; + m_SH4_DMATCR0 = 0; + m_SH4_DMATCR1 = 0; + m_SH4_DMATCR2 = 0; + m_SH4_DMATCR3 = 0; + m_SH4_DMAOR = 0; + m_nmi_line_state = 0; + m_frt_input = 0; + m_internal_irq_vector = 0; + m_refresh_timer_base = 0; + memset(m_dma_timer_active, 0, sizeof(m_dma_timer_active)); + memset(m_dma_source, 0, sizeof(m_dma_source)); + memset(m_dma_destination, 0, sizeof(m_dma_destination)); + memset(m_dma_count, 0, sizeof(m_dma_count)); + memset(m_dma_wordsize, 0, sizeof(m_dma_wordsize)); + memset(m_dma_source_increment, 0, sizeof(m_dma_source_increment)); + memset(m_dma_destination_increment, 0, sizeof(m_dma_destination_increment)); + memset(m_dma_mode, 0, sizeof(m_dma_mode)); + m_ioport16_pullup = 0; + m_ioport16_direction = 0; + m_ioport4_pullup = 0; + m_ioport4_direction = 0; + + sh4_default_exception_priorities(); + + m_rtc_timer->adjust(attotime::from_hz(128)); + + m_pc = 0xa0000000; + m_r[15] = RL(4); + m_sr = 0x700000f0; + m_fpscr = 0x00040001; + m_fpu_sz = (m_fpscr & SZ) ? 1 : 0; + m_fpu_pr = (m_fpscr & PR) ? 1 : 0; + m_fpul = 0; + m_dbr = 0; + + m_internal_irq_level = -1; + m_irln = 15; + m_sleep_mode = 0; + + m_sh4_mmu_enabled = 0; +} + +/*------------------------------------------------- + sh3_reset - reset the processor +-------------------------------------------------*/ + +void sh3_base_device::device_reset() +{ + sh34_base_device::device_reset(); + + m_SH4_TCOR0 = 0xffffffff; + m_SH4_TCNT0 = 0xffffffff; + m_SH4_TCOR1 = 0xffffffff; + m_SH4_TCNT1 = 0xffffffff; + m_SH4_TCOR2 = 0xffffffff; + m_SH4_TCNT2 = 0xffffffff; +} + +void sh4_base_device::device_reset() +{ + sh34_base_device::device_reset(); + + m_m[RCR2] = 0x09; + m_SH4_TCOR0 = 0xffffffff; + m_SH4_TCNT0 = 0xffffffff; + m_SH4_TCOR1 = 0xffffffff; + m_SH4_TCNT1 = 0xffffffff; + m_SH4_TCOR2 = 0xffffffff; + m_SH4_TCNT2 = 0xffffffff; +} + +inline void sh34_base_device::execute_one_0000(const UINT16 opcode) +{ + switch(opcode & 0xff) + { + // 0x00 + case 0x00: NOP(opcode); break; + case 0x10: NOP(opcode); break; + case 0x20: NOP(opcode); break; + case 0x30: NOP(opcode); break; + case 0x40: NOP(opcode); break; + case 0x50: NOP(opcode); break; + case 0x60: NOP(opcode); break; + case 0x70: NOP(opcode); break; + case 0x80: NOP(opcode); break; + case 0x90: NOP(opcode); break; + case 0xa0: NOP(opcode); break; + case 0xb0: NOP(opcode); break; + case 0xc0: NOP(opcode); break; + case 0xd0: NOP(opcode); break; + case 0xe0: NOP(opcode); break; + case 0xf0: NOP(opcode); break; + // 0x10 + case 0x01: NOP(opcode); break; + case 0x11: NOP(opcode); break; + case 0x21: NOP(opcode); break; + case 0x31: NOP(opcode); break; + case 0x41: NOP(opcode); break; + case 0x51: NOP(opcode); break; + case 0x61: NOP(opcode); break; + case 0x71: NOP(opcode); break; + case 0x81: NOP(opcode); break; + case 0x91: NOP(opcode); break; + case 0xa1: NOP(opcode); break; + case 0xb1: NOP(opcode); break; + case 0xc1: NOP(opcode); break; + case 0xd1: NOP(opcode); break; + case 0xe1: NOP(opcode); break; + case 0xf1: NOP(opcode); break; + // 0x20 + case 0x02: STCSR(opcode); break; + case 0x12: STCGBR(opcode); break; + case 0x22: STCVBR(opcode); break; + case 0x32: STCSSR(opcode); break; + case 0x42: STCSPC(opcode); break; + case 0x52: NOP(opcode); break; + case 0x62: NOP(opcode); break; + case 0x72: NOP(opcode); break; + case 0x82: STCRBANK(opcode); break; + case 0x92: STCRBANK(opcode); break; + case 0xa2: STCRBANK(opcode); break; + case 0xb2: STCRBANK(opcode); break; + case 0xc2: STCRBANK(opcode); break; + case 0xd2: STCRBANK(opcode); break; + case 0xe2: STCRBANK(opcode); break; + case 0xf2: STCRBANK(opcode); break; + // 0x30 + case 0x03: BSRF(opcode); break; + case 0x13: NOP(opcode); break; + case 0x23: BRAF(opcode); break; + case 0x33: NOP(opcode); break; + case 0x43: NOP(opcode); break; + case 0x53: NOP(opcode); break; + case 0x63: NOP(opcode); break; + case 0x73: NOP(opcode); break; + case 0x83: PREFM(opcode); break; + case 0x93: TODO(opcode); break; + case 0xa3: TODO(opcode); break; + case 0xb3: TODO(opcode); break; + case 0xc3: MOVCAL(opcode); break; + case 0xd3: NOP(opcode); break; + case 0xe3: NOP(opcode); break; + case 0xf3: NOP(opcode); break; + // 0x40 + case 0x04: MOVBS0(opcode); break; + case 0x14: MOVBS0(opcode); break; + case 0x24: MOVBS0(opcode); break; + case 0x34: MOVBS0(opcode); break; + case 0x44: MOVBS0(opcode); break; + case 0x54: MOVBS0(opcode); break; + case 0x64: MOVBS0(opcode); break; + case 0x74: MOVBS0(opcode); break; + case 0x84: MOVBS0(opcode); break; + case 0x94: MOVBS0(opcode); break; + case 0xa4: MOVBS0(opcode); break; + case 0xb4: MOVBS0(opcode); break; + case 0xc4: MOVBS0(opcode); break; + case 0xd4: MOVBS0(opcode); break; + case 0xe4: MOVBS0(opcode); break; + case 0xf4: MOVBS0(opcode); break; + // 0x50 + case 0x05: MOVWS0(opcode); break; + case 0x15: MOVWS0(opcode); break; + case 0x25: MOVWS0(opcode); break; + case 0x35: MOVWS0(opcode); break; + case 0x45: MOVWS0(opcode); break; + case 0x55: MOVWS0(opcode); break; + case 0x65: MOVWS0(opcode); break; + case 0x75: MOVWS0(opcode); break; + case 0x85: MOVWS0(opcode); break; + case 0x95: MOVWS0(opcode); break; + case 0xa5: MOVWS0(opcode); break; + case 0xb5: MOVWS0(opcode); break; + case 0xc5: MOVWS0(opcode); break; + case 0xd5: MOVWS0(opcode); break; + case 0xe5: MOVWS0(opcode); break; + case 0xf5: MOVWS0(opcode); break; + // 0x60 + case 0x06: MOVLS0(opcode); break; + case 0x16: MOVLS0(opcode); break; + case 0x26: MOVLS0(opcode); break; + case 0x36: MOVLS0(opcode); break; + case 0x46: MOVLS0(opcode); break; + case 0x56: MOVLS0(opcode); break; + case 0x66: MOVLS0(opcode); break; + case 0x76: MOVLS0(opcode); break; + case 0x86: MOVLS0(opcode); break; + case 0x96: MOVLS0(opcode); break; + case 0xa6: MOVLS0(opcode); break; + case 0xb6: MOVLS0(opcode); break; + case 0xc6: MOVLS0(opcode); break; + case 0xd6: MOVLS0(opcode); break; + case 0xe6: MOVLS0(opcode); break; + case 0xf6: MOVLS0(opcode); break; + // 0x70 + case 0x07: MULL(opcode); break; + case 0x17: MULL(opcode); break; + case 0x27: MULL(opcode); break; + case 0x37: MULL(opcode); break; + case 0x47: MULL(opcode); break; + case 0x57: MULL(opcode); break; + case 0x67: MULL(opcode); break; + case 0x77: MULL(opcode); break; + case 0x87: MULL(opcode); break; + case 0x97: MULL(opcode); break; + case 0xa7: MULL(opcode); break; + case 0xb7: MULL(opcode); break; + case 0xc7: MULL(opcode); break; + case 0xd7: MULL(opcode); break; + case 0xe7: MULL(opcode); break; + case 0xf7: MULL(opcode); break; + // 0x80 + case 0x08: CLRT(opcode); break; + case 0x18: SETT(opcode); break; + case 0x28: CLRMAC(opcode); break; + case 0x38: TODO(opcode); break; + case 0x48: CLRS(opcode); break; + case 0x58: SETS(opcode); break; + case 0x68: NOP(opcode); break; + case 0x78: NOP(opcode); break; + case 0x88: CLRT(opcode); break; + case 0x98: SETT(opcode); break; + case 0xa8: CLRMAC(opcode); break; + case 0xb8: TODO(opcode); break; + case 0xc8: CLRS(opcode); break; + case 0xd8: SETS(opcode); break; + case 0xe8: NOP(opcode); break; + case 0xf8: NOP(opcode); break; + // 0x90 + case 0x09: NOP(opcode); break; + case 0x19: DIV0U(opcode); break; + case 0x29: MOVT(opcode); break; + case 0x39: NOP(opcode); break; + case 0x49: NOP(opcode); break; + case 0x59: DIV0U(opcode); break; + case 0x69: MOVT(opcode); break; + case 0x79: NOP(opcode); break; + case 0x89: NOP(opcode); break; + case 0x99: DIV0U(opcode); break; + case 0xa9: MOVT(opcode); break; + case 0xb9: NOP(opcode); break; + case 0xc9: NOP(opcode); break; + case 0xd9: DIV0U(opcode); break; + case 0xe9: MOVT(opcode); break; + case 0xf9: NOP(opcode); break; + // 0xa0 + case 0x0a: STSMACH(opcode); break; + case 0x1a: STSMACL(opcode); break; + case 0x2a: STSPR(opcode); break; + case 0x3a: STCSGR(opcode); break; + case 0x4a: NOP(opcode); break; + case 0x5a: STSFPUL(opcode); break; + case 0x6a: STSFPSCR(opcode); break; + case 0x7a: STCDBR(opcode); break; + case 0x8a: STSMACH(opcode); break; + case 0x9a: STSMACL(opcode); break; + case 0xaa: STSPR(opcode); break; + case 0xba: STCSGR(opcode); break; + case 0xca: NOP(opcode); break; + case 0xda: STSFPUL(opcode); break; + case 0xea: STSFPSCR(opcode); break; + case 0xfa: STCDBR(opcode); break; + // 0xb0 + case 0x0b: RTS(opcode); break; + case 0x1b: SLEEP(opcode); break; + case 0x2b: RTE(opcode); break; + case 0x3b: NOP(opcode); break; + case 0x4b: RTS(opcode); break; + case 0x5b: SLEEP(opcode); break; + case 0x6b: RTE(opcode); break; + case 0x7b: NOP(opcode); break; + case 0x8b: RTS(opcode); break; + case 0x9b: SLEEP(opcode); break; + case 0xab: RTE(opcode); break; + case 0xbb: NOP(opcode); break; + case 0xcb: RTS(opcode); break; + case 0xdb: SLEEP(opcode); break; + case 0xeb: RTE(opcode); break; + case 0xfb: NOP(opcode); break; + // 0xc0 + case 0x0c: MOVBL0(opcode); break; + case 0x1c: MOVBL0(opcode); break; + case 0x2c: MOVBL0(opcode); break; + case 0x3c: MOVBL0(opcode); break; + case 0x4c: MOVBL0(opcode); break; + case 0x5c: MOVBL0(opcode); break; + case 0x6c: MOVBL0(opcode); break; + case 0x7c: MOVBL0(opcode); break; + case 0x8c: MOVBL0(opcode); break; + case 0x9c: MOVBL0(opcode); break; + case 0xac: MOVBL0(opcode); break; + case 0xbc: MOVBL0(opcode); break; + case 0xcc: MOVBL0(opcode); break; + case 0xdc: MOVBL0(opcode); break; + case 0xec: MOVBL0(opcode); break; + case 0xfc: MOVBL0(opcode); break; + // 0xd0 + case 0x0d: MOVWL0(opcode); break; + case 0x1d: MOVWL0(opcode); break; + case 0x2d: MOVWL0(opcode); break; + case 0x3d: MOVWL0(opcode); break; + case 0x4d: MOVWL0(opcode); break; + case 0x5d: MOVWL0(opcode); break; + case 0x6d: MOVWL0(opcode); break; + case 0x7d: MOVWL0(opcode); break; + case 0x8d: MOVWL0(opcode); break; + case 0x9d: MOVWL0(opcode); break; + case 0xad: MOVWL0(opcode); break; + case 0xbd: MOVWL0(opcode); break; + case 0xcd: MOVWL0(opcode); break; + case 0xdd: MOVWL0(opcode); break; + case 0xed: MOVWL0(opcode); break; + case 0xfd: MOVWL0(opcode); break; + // 0xe0 + case 0x0e: MOVLL0(opcode); break; + case 0x1e: MOVLL0(opcode); break; + case 0x2e: MOVLL0(opcode); break; + case 0x3e: MOVLL0(opcode); break; + case 0x4e: MOVLL0(opcode); break; + case 0x5e: MOVLL0(opcode); break; + case 0x6e: MOVLL0(opcode); break; + case 0x7e: MOVLL0(opcode); break; + case 0x8e: MOVLL0(opcode); break; + case 0x9e: MOVLL0(opcode); break; + case 0xae: MOVLL0(opcode); break; + case 0xbe: MOVLL0(opcode); break; + case 0xce: MOVLL0(opcode); break; + case 0xde: MOVLL0(opcode); break; + case 0xee: MOVLL0(opcode); break; + case 0xfe: MOVLL0(opcode); break; + // 0xf0 + case 0x0f: MAC_L(opcode); break; + case 0x1f: MAC_L(opcode); break; + case 0x2f: MAC_L(opcode); break; + case 0x3f: MAC_L(opcode); break; + case 0x4f: MAC_L(opcode); break; + case 0x5f: MAC_L(opcode); break; + case 0x6f: MAC_L(opcode); break; + case 0x7f: MAC_L(opcode); break; + case 0x8f: MAC_L(opcode); break; + case 0x9f: MAC_L(opcode); break; + case 0xaf: MAC_L(opcode); break; + case 0xbf: MAC_L(opcode); break; + case 0xcf: MAC_L(opcode); break; + case 0xdf: MAC_L(opcode); break; + case 0xef: MAC_L(opcode); break; + case 0xff: MAC_L(opcode); break; + } +} + +inline void sh34_base_device::execute_one_4000(const UINT16 opcode) +{ + switch(opcode & 0xff) + { + // 0x00 + case 0x00: SHLL(opcode); break; + case 0x10: DT(opcode); break; + case 0x20: SHAL(opcode); break; + case 0x30: NOP(opcode); break; + case 0x40: SHLL(opcode); break; + case 0x50: DT(opcode); break; + case 0x60: SHAL(opcode); break; + case 0x70: NOP(opcode); break; + case 0x80: SHLL(opcode); break; + case 0x90: DT(opcode); break; + case 0xa0: SHAL(opcode); break; + case 0xb0: NOP(opcode); break; + case 0xc0: SHLL(opcode); break; + case 0xd0: DT(opcode); break; + case 0xe0: SHAL(opcode); break; + case 0xf0: NOP(opcode); break; + // 0x10 + case 0x01: SHLR(opcode); break; + case 0x11: CMPPZ(opcode); break; + case 0x21: SHAR(opcode); break; + case 0x31: NOP(opcode); break; + case 0x41: SHLR(opcode); break; + case 0x51: CMPPZ(opcode); break; + case 0x61: SHAR(opcode); break; + case 0x71: NOP(opcode); break; + case 0x81: SHLR(opcode); break; + case 0x91: CMPPZ(opcode); break; + case 0xa1: SHAR(opcode); break; + case 0xb1: NOP(opcode); break; + case 0xc1: SHLR(opcode); break; + case 0xd1: CMPPZ(opcode); break; + case 0xe1: SHAR(opcode); break; + case 0xf1: NOP(opcode); break; + // 0x20 + case 0x02: STSMMACH(opcode); break; + case 0x12: STSMMACL(opcode); break; + case 0x22: STSMPR(opcode); break; + case 0x32: STCMSGR(opcode); break; + case 0x42: NOP(opcode); break; + case 0x52: STSMFPUL(opcode); break; + case 0x62: STSMFPSCR(opcode); break; + case 0x72: NOP(opcode); break; + case 0x82: NOP(opcode); break; + case 0x92: NOP(opcode); break; + case 0xa2: NOP(opcode); break; + case 0xb2: NOP(opcode); break; + case 0xc2: NOP(opcode); break; + case 0xd2: NOP(opcode); break; + case 0xe2: NOP(opcode); break; + case 0xf2: STCMDBR(opcode); break; + // 0x30 + case 0x03: STCMSR(opcode); break; + case 0x13: STCMGBR(opcode); break; + case 0x23: STCMVBR(opcode); break; + case 0x33: STCMSSR(opcode); break; + case 0x43: STCMSPC(opcode); break; + case 0x53: NOP(opcode); break; + case 0x63: NOP(opcode); break; + case 0x73: NOP(opcode); break; + case 0x83: STCMRBANK(opcode); break; + case 0x93: STCMRBANK(opcode); break; + case 0xa3: STCMRBANK(opcode); break; + case 0xb3: STCMRBANK(opcode); break; + case 0xc3: STCMRBANK(opcode); break; + case 0xd3: STCMRBANK(opcode); break; + case 0xe3: STCMRBANK(opcode); break; + case 0xf3: STCMRBANK(opcode); break; + // 0x40 + case 0x04: ROTL(opcode); break; + case 0x14: NOP(opcode); break; + case 0x24: ROTCL(opcode); break; + case 0x34: NOP(opcode); break; + case 0x44: ROTL(opcode); break; + case 0x54: NOP(opcode); break; + case 0x64: ROTCL(opcode); break; + case 0x74: NOP(opcode); break; + case 0x84: ROTL(opcode); break; + case 0x94: NOP(opcode); break; + case 0xa4: ROTCL(opcode); break; + case 0xb4: NOP(opcode); break; + case 0xc4: ROTL(opcode); break; + case 0xd4: NOP(opcode); break; + case 0xe4: ROTCL(opcode); break; + case 0xf4: NOP(opcode); break; + // 0x50 + case 0x05: ROTR(opcode); break; + case 0x15: CMPPL(opcode); break; + case 0x25: ROTCR(opcode); break; + case 0x35: NOP(opcode); break; + case 0x45: ROTR(opcode); break; + case 0x55: CMPPL(opcode); break; + case 0x65: ROTCR(opcode); break; + case 0x75: NOP(opcode); break; + case 0x85: ROTR(opcode); break; + case 0x95: CMPPL(opcode); break; + case 0xa5: ROTCR(opcode); break; + case 0xb5: NOP(opcode); break; + case 0xc5: ROTR(opcode); break; + case 0xd5: CMPPL(opcode); break; + case 0xe5: ROTCR(opcode); break; + case 0xf5: NOP(opcode); break; + // 0x60 + case 0x06: LDSMMACH(opcode); break; + case 0x16: LDSMMACL(opcode); break; + case 0x26: LDSMPR(opcode); break; + case 0x36: NOP(opcode); break; + case 0x46: NOP(opcode); break; + case 0x56: LDSMFPUL(opcode); break; + case 0x66: LDSMFPSCR(opcode); break; + case 0x76: NOP(opcode); break; + case 0x86: NOP(opcode); break; + case 0x96: NOP(opcode); break; + case 0xa6: NOP(opcode); break; + case 0xb6: NOP(opcode); break; + case 0xc6: NOP(opcode); break; + case 0xd6: NOP(opcode); break; + case 0xe6: NOP(opcode); break; + case 0xf6: LDCMDBR(opcode); break; + // 0x70 + case 0x07: LDCMSR(opcode); break; + case 0x17: LDCMGBR(opcode); break; + case 0x27: LDCMVBR(opcode); break; + case 0x37: LDCMSSR(opcode); break; + case 0x47: LDCMSPC(opcode); break; + case 0x57: NOP(opcode); break; + case 0x67: NOP(opcode); break; + case 0x77: NOP(opcode); break; + case 0x87: LDCMRBANK(opcode); break; + case 0x97: LDCMRBANK(opcode); break; + case 0xa7: LDCMRBANK(opcode); break; + case 0xb7: LDCMRBANK(opcode); break; + case 0xc7: LDCMRBANK(opcode); break; + case 0xd7: LDCMRBANK(opcode); break; + case 0xe7: LDCMRBANK(opcode); break; + case 0xf7: LDCMRBANK(opcode); break; + // 0x80 + case 0x08: SHLL2(opcode); break; + case 0x18: SHLL8(opcode); break; + case 0x28: SHLL16(opcode); break; + case 0x38: NOP(opcode); break; + case 0x48: SHLL2(opcode); break; + case 0x58: SHLL8(opcode); break; + case 0x68: SHLL16(opcode); break; + case 0x78: NOP(opcode); break; + case 0x88: SHLL2(opcode); break; + case 0x98: SHLL8(opcode); break; + case 0xa8: SHLL16(opcode); break; + case 0xb8: NOP(opcode); break; + case 0xc8: SHLL2(opcode); break; + case 0xd8: SHLL8(opcode); break; + case 0xe8: SHLL16(opcode); break; + case 0xf8: NOP(opcode); break; + // 0x90 + case 0x09: SHLR2(opcode); break; + case 0x19: SHLR8(opcode); break; + case 0x29: SHLR16(opcode); break; + case 0x39: NOP(opcode); break; + case 0x49: SHLR2(opcode); break; + case 0x59: SHLR8(opcode); break; + case 0x69: SHLR16(opcode); break; + case 0x79: NOP(opcode); break; + case 0x89: SHLR2(opcode); break; + case 0x99: SHLR8(opcode); break; + case 0xa9: SHLR16(opcode); break; + case 0xb9: NOP(opcode); break; + case 0xc9: SHLR2(opcode); break; + case 0xd9: SHLR8(opcode); break; + case 0xe9: SHLR16(opcode); break; + case 0xf9: NOP(opcode); break; + // 0xa0 + case 0x0a: LDSMACH(opcode); break; + case 0x1a: LDSMACL(opcode); break; + case 0x2a: LDSPR(opcode); break; + case 0x3a: NOP(opcode); break; + case 0x4a: NOP(opcode); break; + case 0x5a: LDSFPUL(opcode); break; + case 0x6a: LDSFPSCR(opcode); break; + case 0x7a: NOP(opcode); break; + case 0x8a: NOP(opcode); break; + case 0x9a: NOP(opcode); break; + case 0xaa: NOP(opcode); break; + case 0xba: NOP(opcode); break; + case 0xca: NOP(opcode); break; + case 0xda: NOP(opcode); break; + case 0xea: NOP(opcode); break; + case 0xfa: LDCDBR(opcode); break; + // 0xb0 + case 0x0b: JSR(opcode); break; + case 0x1b: TAS(opcode); break; + case 0x2b: JMP(opcode); break; + case 0x3b: NOP(opcode); break; + case 0x4b: JSR(opcode); break; + case 0x5b: TAS(opcode); break; + case 0x6b: JMP(opcode); break; + case 0x7b: NOP(opcode); break; + case 0x8b: JSR(opcode); break; + case 0x9b: TAS(opcode); break; + case 0xab: JMP(opcode); break; + case 0xbb: NOP(opcode); break; + case 0xcb: JSR(opcode); break; + case 0xdb: TAS(opcode); break; + case 0xeb: JMP(opcode); break; + case 0xfb: NOP(opcode); break; + // 0xc0 + case 0x0c: SHAD(opcode); break; + case 0x1c: SHAD(opcode); break; + case 0x2c: SHAD(opcode); break; + case 0x3c: SHAD(opcode); break; + case 0x4c: SHAD(opcode); break; + case 0x5c: SHAD(opcode); break; + case 0x6c: SHAD(opcode); break; + case 0x7c: SHAD(opcode); break; + case 0x8c: SHAD(opcode); break; + case 0x9c: SHAD(opcode); break; + case 0xac: SHAD(opcode); break; + case 0xbc: SHAD(opcode); break; + case 0xcc: SHAD(opcode); break; + case 0xdc: SHAD(opcode); break; + case 0xec: SHAD(opcode); break; + case 0xfc: SHAD(opcode); break; + // 0xd0 + case 0x0d: SHLD(opcode); break; + case 0x1d: SHLD(opcode); break; + case 0x2d: SHLD(opcode); break; + case 0x3d: SHLD(opcode); break; + case 0x4d: SHLD(opcode); break; + case 0x5d: SHLD(opcode); break; + case 0x6d: SHLD(opcode); break; + case 0x7d: SHLD(opcode); break; + case 0x8d: SHLD(opcode); break; + case 0x9d: SHLD(opcode); break; + case 0xad: SHLD(opcode); break; + case 0xbd: SHLD(opcode); break; + case 0xcd: SHLD(opcode); break; + case 0xdd: SHLD(opcode); break; + case 0xed: SHLD(opcode); break; + case 0xfd: SHLD(opcode); break; + // 0xe0 + case 0x0e: LDCSR(opcode); break; + case 0x1e: LDCGBR(opcode); break; + case 0x2e: LDCVBR(opcode); break; + case 0x3e: LDCSSR(opcode); break; + case 0x4e: LDCSPC(opcode); break; + case 0x5e: NOP(opcode); break; + case 0x6e: NOP(opcode); break; + case 0x7e: NOP(opcode); break; + case 0x8e: LDCRBANK(opcode); break; + case 0x9e: LDCRBANK(opcode); break; + case 0xae: LDCRBANK(opcode); break; + case 0xbe: LDCRBANK(opcode); break; + case 0xce: LDCRBANK(opcode); break; + case 0xde: LDCRBANK(opcode); break; + case 0xee: LDCRBANK(opcode); break; + case 0xfe: LDCRBANK(opcode); break; + // 0xf0 + case 0x0f: MAC_W(opcode); break; + case 0x1f: MAC_W(opcode); break; + case 0x2f: MAC_W(opcode); break; + case 0x3f: MAC_W(opcode); break; + case 0x4f: MAC_W(opcode); break; + case 0x5f: MAC_W(opcode); break; + case 0x6f: MAC_W(opcode); break; + case 0x7f: MAC_W(opcode); break; + case 0x8f: MAC_W(opcode); break; + case 0x9f: MAC_W(opcode); break; + case 0xaf: MAC_W(opcode); break; + case 0xbf: MAC_W(opcode); break; + case 0xcf: MAC_W(opcode); break; + case 0xdf: MAC_W(opcode); break; + case 0xef: MAC_W(opcode); break; + case 0xff: MAC_W(opcode); break; + } +} + + +inline void sh34_base_device::execute_one(const UINT16 opcode) +{ + switch(opcode & 0xf000) + { + case 0x0000: + execute_one_0000(opcode); + break; + + case 0x1000: + MOVLS4(opcode); + break; + + case 0x2000: + switch(opcode & 0x0f) + { + case 0x00: MOVBS(opcode); break; + case 0x01: MOVWS(opcode); break; + case 0x02: MOVLS(opcode); break; + case 0x03: NOP(opcode); break; + case 0x04: MOVBM(opcode); break; + case 0x05: MOVWM(opcode); break; + case 0x06: MOVLM(opcode); break; + case 0x07: DIV0S(opcode); break; + case 0x08: TST(opcode); break; + case 0x09: AND(opcode); break; + case 0x0a: XOR(opcode); break; + case 0x0b: OR(opcode); break; + case 0x0c: CMPSTR(opcode); break; + case 0x0d: XTRCT(opcode); break; + case 0x0e: MULU(opcode); break; + case 0x0f: MULS(opcode); break; + } + break; + + case 0x3000: + switch(opcode & 0x0f) + { + case 0x00: CMPEQ(opcode); break; + case 0x01: NOP(opcode); break; + case 0x02: CMPHS(opcode); break; + case 0x03: CMPGE(opcode); break; + case 0x04: DIV1(opcode); break; + case 0x05: DMULU(opcode); break; + case 0x06: CMPHI(opcode); break; + case 0x07: CMPGT(opcode); break; + case 0x08: SUB(opcode); break; + case 0x09: NOP(opcode); break; + case 0x0a: SUBC(opcode); break; + case 0x0b: SUBV(opcode); break; + case 0x0c: ADD(opcode); break; + case 0x0d: DMULS(opcode); break; + case 0x0e: ADDC(opcode); break; + case 0x0f: ADDV(opcode); break; + } + break; + + case 0x4000: + execute_one_4000(opcode); + break; + + case 0x5000: + MOVLL4(opcode); + break; + + case 0x6000: + switch(opcode & 0x0f) + { + case 0x00: MOVBL(opcode); break; + case 0x01: MOVWL(opcode); break; + case 0x02: MOVLL(opcode); break; + case 0x03: MOV(opcode); break; + case 0x04: MOVBP(opcode); break; + case 0x05: MOVWP(opcode); break; + case 0x06: MOVLP(opcode); break; + case 0x07: NOT(opcode); break; + case 0x08: SWAPB(opcode); break; + case 0x09: SWAPW(opcode); break; + case 0x0a: NEGC(opcode); break; + case 0x0b: NEG(opcode); break; + case 0x0c: EXTUB(opcode); break; + case 0x0d: EXTUW(opcode); break; + case 0x0e: EXTSB(opcode); break; + case 0x0f: EXTSW(opcode); break; + } + break; + + case 0x7000: + ADDI(opcode); + break; + + case 0x8000: + switch((opcode >> 8) & 0x0f) + { + case 0x00: MOVBS4(opcode); break; + case 0x01: MOVWS4(opcode); break; + case 0x02: NOP(opcode); break; + case 0x03: NOP(opcode); break; + case 0x04: MOVBL4(opcode); break; + case 0x05: MOVWL4(opcode); break; + case 0x06: NOP(opcode); break; + case 0x07: NOP(opcode); break; + case 0x08: CMPIM(opcode); break; + case 0x09: BT(opcode); break; + case 0x0a: NOP(opcode); break; + case 0x0b: BF(opcode); break; + case 0x0c: NOP(opcode); break; + case 0x0d: BTS(opcode); break; + case 0x0e: NOP(opcode); break; + case 0x0f: BFS(opcode); break; + } + break; + + case 0x9000: + MOVWI(opcode); + break; + + case 0xa000: + BRA(opcode); + break; + + case 0xb000: + BSR(opcode); + break; + + case 0xc000: + switch((opcode >> 8) & 0x0f) + { + case 0x00: MOVBSG(opcode); break; + case 0x01: MOVWSG(opcode); break; + case 0x02: MOVLSG(opcode); break; + case 0x03: TRAPA(opcode); break; + case 0x04: MOVBLG(opcode); break; + case 0x05: MOVWLG(opcode); break; + case 0x06: MOVLLG(opcode); break; + case 0x07: MOVA(opcode); break; + case 0x08: TSTI(opcode); break; + case 0x09: ANDI(opcode); break; + case 0x0a: XORI(opcode); break; + case 0x0b: ORI(opcode); break; + case 0x0c: TSTM(opcode); break; + case 0x0d: ANDM(opcode); break; + case 0x0e: XORM(opcode); break; + case 0x0f: ORM(opcode); break; + } + break; + + case 0xd000: + MOVLI(opcode); + break; + + case 0xe000: + MOVI(opcode); + break; + + case 0xf000: + switch(opcode & 0x0f) + { + case 0x00: FADD(opcode); break; + case 0x01: FSUB(opcode); break; + case 0x02: FMUL(opcode); break; + case 0x03: FDIV(opcode); break; + case 0x04: FCMP_EQ(opcode); break; + case 0x05: FCMP_GT(opcode); break; + case 0x06: FMOVS0FR(opcode); break; + case 0x07: FMOVFRS0(opcode); break; + case 0x08: FMOVMRFR(opcode); break; + case 0x09: FMOVMRIFR(opcode); break; + case 0x0a: FMOVFRMR(opcode); break; + case 0x0b: FMOVFRMDR(opcode); break; + case 0x0c: FMOVFR(opcode); break; + case 0x0d: op1111_0x13(opcode); break; + case 0x0e: FMAC(opcode); break; + case 0x0f: dbreak(opcode); break; + } + break; + } +} + + +/* Execute cycles - returns number of cycles actually run */ +void sh34_base_device::execute_run() +{ + if (m_cpu_off) + { + m_sh4_icount = 0; + return; + } + + do + { + if (m_delay) + { + const UINT16 opcode = m_direct->read_word((UINT32)(m_delay & AM), WORD2_XOR_LE(0)); + + debugger_instruction_hook(this, (m_pc-2) & AM); + + m_delay = 0; + m_ppc = m_pc; + + execute_one(opcode); + + if (m_test_irq && !m_delay) + { + sh4_check_pending_irq("mame_sh4_execute"); + } + } + else + { + const UINT16 opcode = m_direct->read_word((UINT32)(m_pc & AM), WORD2_XOR_LE(0)); + + debugger_instruction_hook(this, m_pc & AM); + + m_pc += 2; + m_ppc = m_pc; + + execute_one(opcode); + + if (m_test_irq && !m_delay) + { + sh4_check_pending_irq("mame_sh4_execute"); + } + } + + m_sh4_icount--; + } while( m_sh4_icount > 0 ); +} + +void sh3be_device::execute_run() +{ + if (m_cpu_off) + { + m_sh4_icount = 0; + return; + } + + do + { + if (m_delay) + { + const UINT16 opcode = m_direct->read_word((UINT32)(m_delay & AM), WORD_XOR_LE(6)); + + debugger_instruction_hook(this, m_delay & AM); + + m_delay = 0; + m_ppc = m_pc; + + execute_one(opcode); + + + if (m_test_irq && !m_delay) + { + sh4_check_pending_irq("mame_sh4_execute"); + } + + + } + else + { + const UINT16 opcode = m_direct->read_word((UINT32)(m_pc & AM), WORD_XOR_LE(6)); + + debugger_instruction_hook(this, m_pc & AM); + + m_pc += 2; + m_ppc = m_pc; + + execute_one(opcode); + + if (m_test_irq && !m_delay) + { + sh4_check_pending_irq("mame_sh4_execute"); + } + } + + m_sh4_icount--; + } while( m_sh4_icount > 0 ); +} + +void sh4be_device::execute_run() +{ + if (m_cpu_off) + { + m_sh4_icount = 0; + return; + } + + do + { + if (m_delay) + { + const UINT16 opcode = m_direct->read_word((UINT32)(m_delay & AM), WORD_XOR_LE(6)); + + debugger_instruction_hook(this, m_delay & AM); + + m_delay = 0; + m_ppc = m_pc; + + execute_one(opcode); + + + if (m_test_irq && !m_delay) + { + sh4_check_pending_irq("mame_sh4_execute"); + } + + + } + else + { + const UINT16 opcode = m_direct->read_word((UINT32)(m_pc & AM), WORD_XOR_LE(6)); + + debugger_instruction_hook(this, m_pc & AM); + + m_pc += 2; + m_ppc = m_pc; + + execute_one(opcode); + + if (m_test_irq && !m_delay) + { + sh4_check_pending_irq("mame_sh4_execute"); + } + } + + m_sh4_icount--; + } while( m_sh4_icount > 0 ); +} + +void sh34_base_device::device_start() +{ + for (int i=0; i<3; i++) + { + m_timer[i] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(sh34_base_device::sh4_timer_callback), this)); + m_timer[i]->adjust(attotime::never, i); + } + + for (int i=0; i<4; i++) + { + m_dma_timer[i] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(sh34_base_device::sh4_dmac_callback), this)); + m_dma_timer[i]->adjust(attotime::never, i); + } + + m_refresh_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(sh34_base_device::sh4_refresh_timer_callback), this)); + m_refresh_timer->adjust(attotime::never); + m_refresh_timer_base = 0; + + m_rtc_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(sh34_base_device::sh4_rtc_timer_callback), this)); + m_rtc_timer->adjust(attotime::never); + + sh4_parse_configuration(); + + m_internal = &space(AS_PROGRAM); + m_program = &space(AS_PROGRAM); + m_io = &space(AS_IO); + m_direct = &m_program->direct(); + sh4_default_exception_priorities(); + m_irln = 15; + m_test_irq = 0; + + save_item(NAME(m_pc)); + save_item(NAME(m_r[15])); + save_item(NAME(m_sr)); + save_item(NAME(m_pr)); + save_item(NAME(m_gbr)); + save_item(NAME(m_vbr)); + save_item(NAME(m_mach)); + save_item(NAME(m_macl)); + save_item(NAME(m_spc)); + save_item(NAME(m_ssr)); + save_item(NAME(m_sgr)); + save_item(NAME(m_fpscr)); + save_item(NAME(m_r[ 0])); + save_item(NAME(m_r[ 1])); + save_item(NAME(m_r[ 2])); + save_item(NAME(m_r[ 3])); + save_item(NAME(m_r[ 4])); + save_item(NAME(m_r[ 5])); + save_item(NAME(m_r[ 6])); + save_item(NAME(m_r[ 7])); + save_item(NAME(m_r[ 8])); + save_item(NAME(m_r[ 9])); + save_item(NAME(m_r[10])); + save_item(NAME(m_r[11])); + save_item(NAME(m_r[12])); + save_item(NAME(m_r[13])); + save_item(NAME(m_r[14])); + save_item(NAME(m_fr[ 0])); + save_item(NAME(m_fr[ 1])); + save_item(NAME(m_fr[ 2])); + save_item(NAME(m_fr[ 3])); + save_item(NAME(m_fr[ 4])); + save_item(NAME(m_fr[ 5])); + save_item(NAME(m_fr[ 6])); + save_item(NAME(m_fr[ 7])); + save_item(NAME(m_fr[ 8])); + save_item(NAME(m_fr[ 9])); + save_item(NAME(m_fr[10])); + save_item(NAME(m_fr[11])); + save_item(NAME(m_fr[12])); + save_item(NAME(m_fr[13])); + save_item(NAME(m_fr[14])); + save_item(NAME(m_fr[15])); + save_item(NAME(m_xf[ 0])); + save_item(NAME(m_xf[ 1])); + save_item(NAME(m_xf[ 2])); + save_item(NAME(m_xf[ 3])); + save_item(NAME(m_xf[ 4])); + save_item(NAME(m_xf[ 5])); + save_item(NAME(m_xf[ 6])); + save_item(NAME(m_xf[ 7])); + save_item(NAME(m_xf[ 8])); + save_item(NAME(m_xf[ 9])); + save_item(NAME(m_xf[10])); + save_item(NAME(m_xf[11])); + save_item(NAME(m_xf[12])); + save_item(NAME(m_xf[13])); + save_item(NAME(m_xf[14])); + save_item(NAME(m_xf[15])); + save_item(NAME(m_ea)); + save_item(NAME(m_fpul)); + save_item(NAME(m_dbr)); + save_item(NAME(m_exception_priority)); + save_item(NAME(m_exception_requesting)); + + save_item(NAME(m_SH4_TSTR)); + save_item(NAME(m_SH4_TCNT0)); + save_item(NAME(m_SH4_TCNT1)); + save_item(NAME(m_SH4_TCNT2)); + save_item(NAME(m_SH4_TCR0)); + save_item(NAME(m_SH4_TCR1)); + save_item(NAME(m_SH4_TCR2)); + save_item(NAME(m_SH4_TCOR0)); + save_item(NAME(m_SH4_TCOR1)); + save_item(NAME(m_SH4_TCOR2)); + save_item(NAME(m_SH4_TOCR)); + save_item(NAME(m_SH4_TCPR2)); + + save_item(NAME(m_SH4_IPRA)); + + save_item(NAME(m_SH4_IPRC)); + + // Debugger state + + state_add(SH4_PC, "PC", m_pc).formatstr("%08X").callimport(); + state_add(SH4_SR, "SR", m_sr).formatstr("%08X").callimport(); + state_add(SH4_PR, "PR", m_pr).formatstr("%08X"); + state_add(SH4_GBR, "GBR", m_gbr).formatstr("%08X"); + state_add(SH4_VBR, "VBR", m_vbr).formatstr("%08X"); + state_add(SH4_DBR, "DBR", m_dbr).formatstr("%08X"); + state_add(SH4_MACH, "MACH", m_mach).formatstr("%08X"); + state_add(SH4_MACL, "MACL", m_macl).formatstr("%08X"); + state_add(SH4_R0, "R0", m_r[ 0]).formatstr("%08X"); + state_add(SH4_R1, "R1", m_r[ 1]).formatstr("%08X"); + state_add(SH4_R2, "R2", m_r[ 2]).formatstr("%08X"); + state_add(SH4_R3, "R3", m_r[ 3]).formatstr("%08X"); + state_add(SH4_R4, "R4", m_r[ 4]).formatstr("%08X"); + state_add(SH4_R5, "R5", m_r[ 5]).formatstr("%08X"); + state_add(SH4_R6, "R6", m_r[ 6]).formatstr("%08X"); + state_add(SH4_R7, "R7", m_r[ 7]).formatstr("%08X"); + state_add(SH4_R8, "R8", m_r[ 8]).formatstr("%08X"); + state_add(SH4_R9, "R9", m_r[ 9]).formatstr("%08X"); + state_add(SH4_R10, "R10", m_r[10]).formatstr("%08X"); + state_add(SH4_R11, "R11", m_r[11]).formatstr("%08X"); + state_add(SH4_R12, "R12", m_r[12]).formatstr("%08X"); + state_add(SH4_R13, "R13", m_r[13]).formatstr("%08X"); + state_add(SH4_R14, "R14", m_r[14]).formatstr("%08X"); + state_add(SH4_R15, "R15", m_r[15]).formatstr("%08X"); + state_add(SH4_EA, "EA", m_ea).formatstr("%08X"); + state_add(SH4_R0_BK0, "R0 BK 0", m_rbnk[0][0]).formatstr("%08X"); + state_add(SH4_R1_BK0, "R1 BK 0", m_rbnk[0][1]).formatstr("%08X"); + state_add(SH4_R2_BK0, "R2 BK 0", m_rbnk[0][2]).formatstr("%08X"); + state_add(SH4_R3_BK0, "R3 BK 0", m_rbnk[0][3]).formatstr("%08X"); + state_add(SH4_R4_BK0, "R4 BK 0", m_rbnk[0][4]).formatstr("%08X"); + state_add(SH4_R5_BK0, "R5 BK 0", m_rbnk[0][5]).formatstr("%08X"); + state_add(SH4_R6_BK0, "R6 BK 0", m_rbnk[0][6]).formatstr("%08X"); + state_add(SH4_R7_BK0, "R7 BK 0", m_rbnk[0][7]).formatstr("%08X"); + state_add(SH4_R0_BK1, "R0 BK 1", m_rbnk[1][0]).formatstr("%08X"); + state_add(SH4_R1_BK1, "R1 BK 1", m_rbnk[1][1]).formatstr("%08X"); + state_add(SH4_R2_BK1, "R2 BK 1", m_rbnk[1][2]).formatstr("%08X"); + state_add(SH4_R3_BK1, "R3 BK 1", m_rbnk[1][3]).formatstr("%08X"); + state_add(SH4_R4_BK1, "R4 BK 1", m_rbnk[1][4]).formatstr("%08X"); + state_add(SH4_R5_BK1, "R5 BK 1", m_rbnk[1][5]).formatstr("%08X"); + state_add(SH4_R6_BK1, "R6 BK 1", m_rbnk[1][6]).formatstr("%08X"); + state_add(SH4_R7_BK1, "R7 BK 1", m_rbnk[1][7]).formatstr("%08X"); + state_add(SH4_SPC, "SPC", m_spc).formatstr("%08X"); + state_add(SH4_SSR, "SSR", m_ssr).formatstr("%08X"); + state_add(SH4_SGR, "SGR", m_sgr).formatstr("%08X"); + state_add(SH4_FPSCR, "FPSCR", m_fpscr).formatstr("%08X"); + state_add(SH4_FPUL, "FPUL", m_fpul).formatstr("%08X"); + + state_add(SH4_FR0, "FR0", m_debugger_temp).callimport().formatstr("%25s"); + state_add(SH4_FR1, "FR1", m_debugger_temp).callimport().formatstr("%25s"); + state_add(SH4_FR2, "FR2", m_debugger_temp).callimport().formatstr("%25s"); + state_add(SH4_FR3, "FR3", m_debugger_temp).callimport().formatstr("%25s"); + state_add(SH4_FR4, "FR4", m_debugger_temp).callimport().formatstr("%25s"); + state_add(SH4_FR5, "FR5", m_debugger_temp).callimport().formatstr("%25s"); + state_add(SH4_FR6, "FR6", m_debugger_temp).callimport().formatstr("%25s"); + state_add(SH4_FR7, "FR7", m_debugger_temp).callimport().formatstr("%25s"); + state_add(SH4_FR8, "FR8", m_debugger_temp).callimport().formatstr("%25s"); + state_add(SH4_FR9, "FR9", m_debugger_temp).callimport().formatstr("%25s"); + state_add(SH4_FR10, "FR10", m_debugger_temp).callimport().formatstr("%25s"); + state_add(SH4_FR11, "FR11", m_debugger_temp).callimport().formatstr("%25s"); + state_add(SH4_FR12, "FR12", m_debugger_temp).callimport().formatstr("%25s"); + state_add(SH4_FR13, "FR13", m_debugger_temp).callimport().formatstr("%25s"); + state_add(SH4_FR14, "FR14", m_debugger_temp).callimport().formatstr("%25s"); + state_add(SH4_FR15, "FR15", m_debugger_temp).callimport().formatstr("%25s"); + state_add(SH4_XF0, "XF0", m_debugger_temp).callimport().formatstr("%25s"); + state_add(SH4_XF1, "XF1", m_debugger_temp).callimport().formatstr("%25s"); + state_add(SH4_XF2, "XF2", m_debugger_temp).callimport().formatstr("%25s"); + state_add(SH4_XF3, "XF3", m_debugger_temp).callimport().formatstr("%25s"); + state_add(SH4_XF4, "XF4", m_debugger_temp).callimport().formatstr("%25s"); + state_add(SH4_XF5, "XF5", m_debugger_temp).callimport().formatstr("%25s"); + state_add(SH4_XF6, "XF6", m_debugger_temp).callimport().formatstr("%25s"); + state_add(SH4_XF7, "XF7", m_debugger_temp).callimport().formatstr("%25s"); + state_add(SH4_XF8, "XF8", m_debugger_temp).callimport().formatstr("%25s"); + state_add(SH4_XF9, "XF9", m_debugger_temp).callimport().formatstr("%25s"); + state_add(SH4_XF10, "XF10", m_debugger_temp).callimport().formatstr("%25s"); + state_add(SH4_XF11, "XF11", m_debugger_temp).callimport().formatstr("%25s"); + state_add(SH4_XF12, "XF12", m_debugger_temp).callimport().formatstr("%25s"); + state_add(SH4_XF13, "XF13", m_debugger_temp).callimport().formatstr("%25s"); + state_add(SH4_XF14, "XF14", m_debugger_temp).callimport().formatstr("%25s"); + state_add(SH4_XF15, "XF15", m_debugger_temp).callimport().formatstr("%25s"); + + state_add(STATE_GENPC, "GENPC", m_debugger_temp).callimport().callexport().noshow(); + state_add(STATE_GENSP, "GENSP", m_r[15]).noshow(); + state_add(STATE_GENPCBASE, "GENPCBASE", m_ppc).noshow(); + state_add(STATE_GENFLAGS, "GENFLAGS", m_sr).formatstr("%20s").noshow(); + + m_icountptr = &m_sh4_icount; +} + +void sh34_base_device::state_import(const device_state_entry &entry) +{ +#ifdef LSB_FIRST + UINT8 fpu_xor = m_fpu_pr; +#else + UINT8 fpu_xor = 0; +#endif + + switch (entry.index()) + { + case STATE_GENPC: + m_pc = m_debugger_temp; + case SH4_PC: + m_delay = 0; + break; + + case SH4_SR: + sh4_exception_recompute(); + sh4_check_pending_irq("sh4_set_info"); + break; + + case SH4_FR0: + m_fr[0 ^ fpu_xor] = m_debugger_temp; + break; + + case SH4_FR1: + m_fr[1 ^ fpu_xor] = m_debugger_temp; + break; + + case SH4_FR2: + m_fr[2 ^ fpu_xor] = m_debugger_temp; + break; + + case SH4_FR3: + m_fr[3 ^ fpu_xor] = m_debugger_temp; + break; + + case SH4_FR4: + m_fr[4 ^ fpu_xor] = m_debugger_temp; + break; + + case SH4_FR5: + m_fr[5 ^ fpu_xor] = m_debugger_temp; + break; + + case SH4_FR6: + m_fr[6 ^ fpu_xor] = m_debugger_temp; + break; + + case SH4_FR7: + m_fr[7 ^ fpu_xor] = m_debugger_temp; + break; + + case SH4_FR8: + m_fr[8 ^ fpu_xor] = m_debugger_temp; + break; + + case SH4_FR9: + m_fr[9 ^ fpu_xor] = m_debugger_temp; + break; + + case SH4_FR10: + m_fr[10 ^ fpu_xor] = m_debugger_temp; + break; + + case SH4_FR11: + m_fr[11 ^ fpu_xor] = m_debugger_temp; + break; + + case SH4_FR12: + m_fr[12 ^ fpu_xor] = m_debugger_temp; + break; + + case SH4_FR13: + m_fr[13 ^ fpu_xor] = m_debugger_temp; + break; + + case SH4_FR14: + m_fr[14 ^ fpu_xor] = m_debugger_temp; + break; + + case SH4_FR15: + m_fr[15 ^ fpu_xor] = m_debugger_temp; + break; + + case SH4_XF0: + m_xf[0 ^ fpu_xor] = m_debugger_temp; + break; + + case SH4_XF1: + m_xf[1 ^ fpu_xor] = m_debugger_temp; + break; + + case SH4_XF2: + m_xf[2 ^ fpu_xor] = m_debugger_temp; + break; + + case SH4_XF3: + m_xf[3 ^ fpu_xor] = m_debugger_temp; + break; + + case SH4_XF4: + m_xf[4 ^ fpu_xor] = m_debugger_temp; + break; + + case SH4_XF5: + m_xf[5 ^ fpu_xor] = m_debugger_temp; + break; + + case SH4_XF6: + m_xf[6 ^ fpu_xor] = m_debugger_temp; + break; + + case SH4_XF7: + m_xf[7 ^ fpu_xor] = m_debugger_temp; + break; + + case SH4_XF8: + m_xf[8 ^ fpu_xor] = m_debugger_temp; + break; + + case SH4_XF9: + m_xf[9 ^ fpu_xor] = m_debugger_temp; + break; + + case SH4_XF10: + m_xf[10 ^ fpu_xor] = m_debugger_temp; + break; + + case SH4_XF11: + m_xf[11 ^ fpu_xor] = m_debugger_temp; + break; + + case SH4_XF12: + m_xf[12 ^ fpu_xor] = m_debugger_temp; + break; + + case SH4_XF13: + m_xf[13 ^ fpu_xor] = m_debugger_temp; + break; + + case SH4_XF14: + m_xf[14 ^ fpu_xor] = m_debugger_temp; + break; + + case SH4_XF15: + m_xf[15 ^ fpu_xor] = m_debugger_temp; + break; + } +} + +void sh34_base_device::state_export(const device_state_entry &entry) +{ + switch (entry.index()) + { + case STATE_GENPC: + m_debugger_temp = (m_delay) ? (m_delay & AM) : (m_pc & AM); + break; + } +} + +void sh34_base_device::state_string_export(const device_state_entry &entry, std::string &str) +{ +#ifdef LSB_FIRST + UINT8 fpu_xor = m_fpu_pr; +#else + UINT8 fpu_xor = 0; +#endif + + switch (entry.index()) + { + case STATE_GENFLAGS: + strprintf(str, "%s%s%s%s%c%c%d%c%c", + m_sr & MD ? "MD ":" ", + m_sr & sRB ? "RB ":" ", + m_sr & BL ? "BL ":" ", + m_sr & FD ? "FD ":" ", + m_sr & M ? 'M':'.', + m_sr & Q ? 'Q':'.', + (m_sr & I) >> 4, + m_sr & S ? 'S':'.', + m_sr & T ? 'T':'.'); + break; + + case SH4_FR0: + strprintf(str, "%08X %f", m_fr[0 ^ fpu_xor], (double)FP_RFS(0 ^ fpu_xor)); + break; + + case SH4_FR1: + strprintf(str, "%08X %f", m_fr[1 ^ fpu_xor], (double)FP_RFS(1 ^ fpu_xor)); + break; + + case SH4_FR2: + strprintf(str, "%08X %f", m_fr[2 ^ fpu_xor], (double)FP_RFS(2 ^ fpu_xor)); + break; + + case SH4_FR3: + strprintf(str, "%08X %f", m_fr[3 ^ fpu_xor], (double)FP_RFS(3 ^ fpu_xor)); + break; + + case SH4_FR4: + strprintf(str, "%08X %f", m_fr[4 ^ fpu_xor], (double)FP_RFS(4 ^ fpu_xor)); + break; + + case SH4_FR5: + strprintf(str, "%08X %f", m_fr[5 ^ fpu_xor], (double)FP_RFS(5 ^ fpu_xor)); + break; + + case SH4_FR6: + strprintf(str, "%08X %f", m_fr[6 ^ fpu_xor], (double)FP_RFS(6 ^ fpu_xor)); + break; + + case SH4_FR7: + strprintf(str, "%08X %f", m_fr[7 ^ fpu_xor], (double)FP_RFS(7 ^ fpu_xor)); + break; + + case SH4_FR8: + strprintf(str, "%08X %f", m_fr[8 ^ fpu_xor], (double)FP_RFS(8 ^ fpu_xor)); + break; + + case SH4_FR9: + strprintf(str, "%08X %f", m_fr[9 ^ fpu_xor], (double)FP_RFS(9 ^ fpu_xor)); + break; + + case SH4_FR10: + strprintf(str, "%08X %f", m_fr[10 ^ fpu_xor], (double)FP_RFS(10 ^ fpu_xor)); + break; + + case SH4_FR11: + strprintf(str, "%08X %f", m_fr[11 ^ fpu_xor], (double)FP_RFS(11 ^ fpu_xor)); + break; + + case SH4_FR12: + strprintf(str, "%08X %f", m_fr[12 ^ fpu_xor], (double)FP_RFS(12 ^ fpu_xor)); + break; + + case SH4_FR13: + strprintf(str, "%08X %f", m_fr[13 ^ fpu_xor], (double)FP_RFS(13 ^ fpu_xor)); + break; + + case SH4_FR14: + strprintf(str, "%08X %f", m_fr[14 ^ fpu_xor], (double)FP_RFS(14 ^ fpu_xor)); + break; + + case SH4_FR15: + strprintf(str, "%08X %f", m_fr[15 ^ fpu_xor], (double)FP_RFS(15 ^ fpu_xor)); + break; + + case SH4_XF0: + strprintf(str, "%08X %f", m_xf[0 ^ fpu_xor], (double)FP_XFS(0 ^ fpu_xor)); + break; + + case SH4_XF1: + strprintf(str, "%08X %f", m_xf[1 ^ fpu_xor], (double)FP_XFS(1 ^ fpu_xor)); + break; + + case SH4_XF2: + strprintf(str, "%08X %f", m_xf[2 ^ fpu_xor], (double)FP_XFS(2 ^ fpu_xor)); + break; + + case SH4_XF3: + strprintf(str, "%08X %f", m_xf[3 ^ fpu_xor], (double)FP_XFS(3 ^ fpu_xor)); + break; + + case SH4_XF4: + strprintf(str, "%08X %f", m_xf[4 ^ fpu_xor], (double)FP_XFS(4 ^ fpu_xor)); + break; + + case SH4_XF5: + strprintf(str, "%08X %f", m_xf[5 ^ fpu_xor], (double)FP_XFS(5 ^ fpu_xor)); + break; + + case SH4_XF6: + strprintf(str, "%08X %f", m_xf[6 ^ fpu_xor], (double)FP_XFS(6 ^ fpu_xor)); + break; + + case SH4_XF7: + strprintf(str, "%08X %f", m_xf[7 ^ fpu_xor], (double)FP_XFS(7 ^ fpu_xor)); + break; + + case SH4_XF8: + strprintf(str, "%08X %f", m_xf[8 ^ fpu_xor], (double)FP_XFS(8 ^ fpu_xor)); + break; + + case SH4_XF9: + strprintf(str, "%08X %f", m_xf[9 ^ fpu_xor], (double)FP_XFS(9 ^ fpu_xor)); + break; + + case SH4_XF10: + strprintf(str, "%08X %f", m_xf[10 ^ fpu_xor], (double)FP_XFS(10 ^ fpu_xor)); + break; + + case SH4_XF11: + strprintf(str, "%08X %f", m_xf[11 ^ fpu_xor], (double)FP_XFS(11 ^ fpu_xor)); + break; + + case SH4_XF12: + strprintf(str, "%08X %f", m_xf[12 ^ fpu_xor], (double)FP_XFS(12 ^ fpu_xor)); + break; + + case SH4_XF13: + strprintf(str, "%08X %f", m_xf[13 ^ fpu_xor], (double)FP_XFS(13 ^ fpu_xor)); + break; + + case SH4_XF14: + strprintf(str, "%08X %f", m_xf[14 ^ fpu_xor], (double)FP_XFS(14 ^ fpu_xor)); + break; + + case SH4_XF15: + strprintf(str, "%08X %f", m_xf[15 ^ fpu_xor], (double)FP_XFS(15 ^ fpu_xor)); + break; + + } +} + + +void sh34_base_device::sh4_set_ftcsr_callback(sh4_ftcsr_callback callback) +{ + m_ftcsr_read_callback = callback; +} diff --git a/src/devices/cpu/sh4/sh4.h b/src/devices/cpu/sh4/sh4.h new file mode 100644 index 00000000000..2078d1e6435 --- /dev/null +++ b/src/devices/cpu/sh4/sh4.h @@ -0,0 +1,803 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/***************************************************************************** + * + * sh4->h + * Portable Hitachi SH-4 (SH7750 family) emulator interface + * + * By R. Belmont, based on sh2.c by Juergen Buchmueller, Mariusz Wojcieszek, + * Olivier Galibert, Sylvain Glaize, and James Forshaw. + * + *****************************************************************************/ + +#ifndef __SH4_H__ +#define __SH4_H__ + +// doesn't actually seem to improve performance at all +#define SH4_USE_FASTRAM_OPTIMIZATION 0 +#define SH4_MAX_FASTRAM 3 + +#define SH4_INT_NONE -1 +enum +{ + SH4_IRL0=0, SH4_IRL1, SH4_IRL2, SH4_IRL3, SH4_IRLn +}; + +enum +{ + SH4_PC=1, SH4_SR, SH4_PR, SH4_GBR, SH4_VBR, SH4_DBR, SH4_MACH, SH4_MACL, + SH4_R0, SH4_R1, SH4_R2, SH4_R3, SH4_R4, SH4_R5, SH4_R6, SH4_R7, + SH4_R8, SH4_R9, SH4_R10, SH4_R11, SH4_R12, SH4_R13, SH4_R14, SH4_R15, SH4_EA, + SH4_R0_BK0, SH4_R1_BK0, SH4_R2_BK0, SH4_R3_BK0, SH4_R4_BK0, SH4_R5_BK0, SH4_R6_BK0, SH4_R7_BK0, + SH4_R0_BK1, SH4_R1_BK1, SH4_R2_BK1, SH4_R3_BK1, SH4_R4_BK1, SH4_R5_BK1, SH4_R6_BK1, SH4_R7_BK1, + SH4_SPC, SH4_SSR, SH4_SGR, SH4_FPSCR, SH4_FPUL, SH4_FR0, SH4_FR1, SH4_FR2, SH4_FR3, SH4_FR4, SH4_FR5, + SH4_FR6, SH4_FR7, SH4_FR8, SH4_FR9, SH4_FR10, SH4_FR11, SH4_FR12, SH4_FR13, SH4_FR14, SH4_FR15, + SH4_XF0, SH4_XF1, SH4_XF2, SH4_XF3, SH4_XF4, SH4_XF5, SH4_XF6, SH4_XF7, + SH4_XF8, SH4_XF9, SH4_XF10, SH4_XF11, SH4_XF12, SH4_XF13, SH4_XF14, SH4_XF15 +}; + +enum +{ + SH4_INTC_NMI=23, + SH4_INTC_IRLn0, + SH4_INTC_IRLn1, + SH4_INTC_IRLn2, + SH4_INTC_IRLn3, + SH4_INTC_IRLn4, + SH4_INTC_IRLn5, + SH4_INTC_IRLn6, + SH4_INTC_IRLn7, + SH4_INTC_IRLn8, + SH4_INTC_IRLn9, + SH4_INTC_IRLnA, + SH4_INTC_IRLnB, + SH4_INTC_IRLnC, + SH4_INTC_IRLnD, + SH4_INTC_IRLnE, + + SH4_INTC_IRL0, + SH4_INTC_IRL1, + SH4_INTC_IRL2, + SH4_INTC_IRL3, + + SH4_INTC_HUDI, + SH4_INTC_GPOI, + + SH4_INTC_DMTE0, + SH4_INTC_DMTE1, + SH4_INTC_DMTE2, + SH4_INTC_DMTE3, + SH4_INTC_DMTE4, + SH4_INTC_DMTE5, + SH4_INTC_DMTE6, + SH4_INTC_DMTE7, + + SH4_INTC_DMAE, + + SH4_INTC_TUNI3, + SH4_INTC_TUNI4, + SH4_INTC_TUNI0, + SH4_INTC_TUNI1, + SH4_INTC_TUNI2, + SH4_INTC_TICPI2, + SH4_INTC_ATI, + SH4_INTC_PRI, + SH4_INTC_CUI, + SH4_INTC_SCI1ERI, + SH4_INTC_SCI1RXI, + + SH4_INTC_SCI1TXI, + SH4_INTC_SCI1TEI, + SH4_INTC_SCIFERI, + SH4_INTC_SCIFRXI, + SH4_INTC_SCIFBRI, + SH4_INTC_SCIFTXI, + SH4_INTC_ITI, + SH4_INTC_RCMI, + SH4_INTC_ROVI +}; + +#define SH4_FPU_PZERO 0 +#define SH4_FPU_NZERO 1 +#define SH4_FPU_DENORM 2 +#define SH4_FPU_NORM 3 +#define SH4_FPU_PINF 4 +#define SH4_FPU_NINF 5 +#define SH4_FPU_qNaN 6 +#define SH4_FPU_sNaN 7 + +enum +{ + SH4_IOPORT_16=8*0, + SH4_IOPORT_4=8*1, + SH4_IOPORT_DMA=8*2, + // future use + SH4_IOPORT_SCI=8*3, + SH4_IOPORT_SCIF=8*4 +}; + +struct sh4_device_dma +{ + UINT32 length; + UINT32 size; + void *buffer; + int channel; +}; + +struct sh4_ddt_dma +{ + UINT32 source; + UINT32 length; + UINT32 size; + UINT32 destination; + void *buffer; + int direction; + int channel; + int mode; +}; + +typedef void (*sh4_ftcsr_callback)(UINT32); + + +#define MCFG_SH4_MD0(_md0) \ + sh34_base_device::set_md0(*device, _md0); + +#define MCFG_SH4_MD1(_md1) \ + sh34_base_device::set_md1(*device, _md1); + +#define MCFG_SH4_MD2(_md2) \ + sh34_base_device::set_md2(*device, _md2); + +#define MCFG_SH4_MD3(_md3) \ + sh34_base_device::set_md3(*device, _md3); + +#define MCFG_SH4_MD4(_md4) \ + sh34_base_device::set_md4(*device, _md4); + +#define MCFG_SH4_MD5(_md5) \ + sh34_base_device::set_md5(*device, _md5); + +#define MCFG_SH4_MD6(_md6) \ + sh34_base_device::set_md6(*device, _md6); + +#define MCFG_SH4_MD7(_md7) \ + sh34_base_device::set_md7(*device, _md7); + +#define MCFG_SH4_MD8(_md8) \ + sh34_base_device::set_md8(*device, _md8); + +#define MCFG_SH4_CLOCK(_clock) \ + sh34_base_device::set_sh4_clock(*device, _clock); + + +class sh34_base_device : public cpu_device +{ +public: + // construction/destruction + sh34_base_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, endianness_t endianness, address_map_constructor internal); + +//#if SH4_USE_FASTRAM_OPTIMIZATION + void add_fastram(offs_t start, offs_t end, UINT8 readonly, void *base); +//#endif + + static void set_md0(device_t &device, int md0) { downcast(device).c_md0 = md0; } + static void set_md1(device_t &device, int md0) { downcast(device).c_md1 = md0; } + static void set_md2(device_t &device, int md0) { downcast(device).c_md2 = md0; } + static void set_md3(device_t &device, int md0) { downcast(device).c_md3 = md0; } + static void set_md4(device_t &device, int md0) { downcast(device).c_md4 = md0; } + static void set_md5(device_t &device, int md0) { downcast(device).c_md5 = md0; } + static void set_md6(device_t &device, int md0) { downcast(device).c_md6 = md0; } + static void set_md7(device_t &device, int md0) { downcast(device).c_md7 = md0; } + static void set_md8(device_t &device, int md0) { downcast(device).c_md8 = md0; } + static void set_sh4_clock(device_t &device, int clock) { downcast(device).c_clock = clock; } + + TIMER_CALLBACK_MEMBER( sh4_refresh_timer_callback ); + TIMER_CALLBACK_MEMBER( sh4_rtc_timer_callback ); + TIMER_CALLBACK_MEMBER( sh4_timer_callback ); + TIMER_CALLBACK_MEMBER( sh4_dmac_callback ); + + void sh4_set_frt_input(int state); + void sh4_set_irln_input(int value); + void sh4_set_ftcsr_callback(sh4_ftcsr_callback callback); + int sh4_dma_data(struct sh4_device_dma *s); + void sh4_dma_ddt(struct sh4_ddt_dma *s); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_execute_interface overrides + virtual UINT32 execute_min_cycles() const { return 1; } + virtual UINT32 execute_max_cycles() const { return 4; } + virtual UINT32 execute_input_lines() const { return 5; } + virtual void execute_run(); + virtual void execute_set_input(int inputnum, int state); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const { return (spacenum == AS_PROGRAM) ? &m_program_config : ((spacenum == AS_IO) ? &m_io_config : NULL); } + + // device_state_interface overrides + virtual void state_import(const device_state_entry &entry); + virtual void state_export(const device_state_entry &entry); + virtual void state_string_export(const device_state_entry &entry, std::string &str); + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const { return 2; } + virtual UINT32 disasm_max_opcode_bytes() const { return 2; } + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + +protected: + address_space_config m_program_config; + address_space_config m_io_config; + + int c_md2; + int c_md1; + int c_md0; + int c_md6; + int c_md4; + int c_md3; + int c_md5; + int c_md7; + int c_md8; + int c_clock; + + UINT32 m_ppc; + UINT32 m_pc; + UINT32 m_spc; + UINT32 m_pr; + UINT32 m_sr; + UINT32 m_ssr; + UINT32 m_gbr; + UINT32 m_vbr; + UINT32 m_mach; + UINT32 m_macl; + UINT32 m_r[16]; + UINT32 m_rbnk[2][8]; + UINT32 m_sgr; + UINT32 m_fr[16]; + UINT32 m_xf[16]; + UINT32 m_ea; + UINT32 m_delay; + UINT32 m_cpu_off; + UINT32 m_pending_irq; + UINT32 m_test_irq; + UINT32 m_fpscr; + UINT32 m_fpul; + UINT32 m_dbr; + + UINT32 m_exception_priority[128]; + int m_exception_requesting[128]; + + INT8 m_irq_line_state[17]; + address_space *m_internal; + address_space *m_program; + direct_read_data *m_direct; + address_space *m_io; + + // sh4 internal + UINT32 m_m[16384]; + + // timer regs handled manually for reuse + UINT32 m_SH4_TSTR; + UINT32 m_SH4_TCNT0; + UINT32 m_SH4_TCNT1; + UINT32 m_SH4_TCNT2; + UINT32 m_SH4_TCR0; + UINT32 m_SH4_TCR1; + UINT32 m_SH4_TCR2; + UINT32 m_SH4_TCOR0; + UINT32 m_SH4_TCOR1; + UINT32 m_SH4_TCOR2; + UINT32 m_SH4_TOCR; + UINT32 m_SH4_TCPR2; + + // INTC regs + UINT32 m_SH4_IPRA; + + UINT32 m_SH4_IPRC; + + // DMAC regs + UINT32 m_SH4_SAR0; + UINT32 m_SH4_SAR1; + UINT32 m_SH4_SAR2; + UINT32 m_SH4_SAR3; + + UINT32 m_SH4_DAR0; + UINT32 m_SH4_DAR1; + UINT32 m_SH4_DAR2; + UINT32 m_SH4_DAR3; + + UINT32 m_SH4_CHCR0; + UINT32 m_SH4_CHCR1; + UINT32 m_SH4_CHCR2; + UINT32 m_SH4_CHCR3; + + UINT32 m_SH4_DMATCR0; + UINT32 m_SH4_DMATCR1; + UINT32 m_SH4_DMATCR2; + UINT32 m_SH4_DMATCR3; + + UINT32 m_SH4_DMAOR; + + INT8 m_nmi_line_state; + + UINT8 m_sleep_mode; + + int m_frt_input; + int m_irln; + int m_internal_irq_level; + int m_internal_irq_vector; + + emu_timer *m_dma_timer[4]; + emu_timer *m_refresh_timer; + emu_timer *m_rtc_timer; + emu_timer *m_timer[3]; + UINT32 m_refresh_timer_base; + int m_dma_timer_active[4]; + UINT32 m_dma_source[4]; + UINT32 m_dma_destination[4]; + UINT32 m_dma_count[4]; + int m_dma_wordsize[4]; + int m_dma_source_increment[4]; + int m_dma_destination_increment[4]; + int m_dma_mode[4]; + + int m_sh4_icount; + int m_is_slave; + int m_cpu_clock; + int m_bus_clock; + int m_pm_clock; + int m_fpu_sz; + int m_fpu_pr; + int m_ioport16_pullup; + int m_ioport16_direction; + int m_ioport4_pullup; + int m_ioport4_direction; + + void (*m_ftcsr_read_callback)(UINT32 data); + + /* This MMU simulation is good for the simple remap used on Naomi GD-ROM SQ access *ONLY* */ + UINT32 m_sh4_tlb_address[64]; + UINT32 m_sh4_tlb_data[64]; + UINT8 m_sh4_mmu_enabled; + + int m_cpu_type; + + // sh3 internal + UINT32 m_sh3internal_upper[0x3000/4]; + UINT32 m_sh3internal_lower[0x1000]; + + UINT64 m_debugger_temp; + + + void execute_one_0000(const UINT16 opcode); + void execute_one_4000(const UINT16 opcode); + void execute_one(const UINT16 opcode); + inline void sh4_check_pending_irq(const char *message) // look for highest priority active exception and handle it + { + int a,irq,z; + + irq = 0; + z = -1; + for (a=0;a <= SH4_INTC_ROVI;a++) + { + if (m_exception_requesting[a]) + { + if ((int)m_exception_priority[a] > z) + { + z = m_exception_priority[a]; + irq = a; + } + } + } + if (z >= 0) + { + sh4_exception(message, irq); + } + } + + void TODO(const UINT16 opcode); + void WB(offs_t A, UINT8 V); + void WW(offs_t A, UINT16 V); + void WL(offs_t A, UINT32 V); + void ADD(const UINT16 opcode); + void ADDI(const UINT16 opcode); + void ADDC(const UINT16 opcode); + void ADDV(const UINT16 opcode); + void AND(const UINT16 opcode); + void ANDI(const UINT16 opcode); + void ANDM(const UINT16 opcode); + void BF(const UINT16 opcode); + void BFS(const UINT16 opcode); + void BRA(const UINT16 opcode); + void BRAF(const UINT16 opcode); + void BSR(const UINT16 opcode); + void BSRF(const UINT16 opcode); + void BT(const UINT16 opcode); + void BTS(const UINT16 opcode); + void CLRMAC(const UINT16 opcode); + void CLRT(const UINT16 opcode); + void CMPEQ(const UINT16 opcode); + void CMPGE(const UINT16 opcode); + void CMPGT(const UINT16 opcode); + void CMPHI(const UINT16 opcode); + void CMPHS(const UINT16 opcode); + void CMPPL(const UINT16 opcode); + void CMPPZ(const UINT16 opcode); + void CMPSTR(const UINT16 opcode); + void CMPIM(const UINT16 opcode); + void DIV0S(const UINT16 opcode); + void DIV0U(const UINT16 opcode); + void DIV1(const UINT16 opcode); + void DMULS(const UINT16 opcode); + void DMULU(const UINT16 opcode); + void DT(const UINT16 opcode); + void EXTSB(const UINT16 opcode); + void EXTSW(const UINT16 opcode); + void EXTUB(const UINT16 opcode); + void EXTUW(const UINT16 opcode); + void JMP(const UINT16 opcode); + void JSR(const UINT16 opcode); + void LDCSR(const UINT16 opcode); + void LDCGBR(const UINT16 opcode); + void LDCVBR(const UINT16 opcode); + void LDCMSR(const UINT16 opcode); + void LDCMGBR(const UINT16 opcode); + void LDCMVBR(const UINT16 opcode); + void LDSMACH(const UINT16 opcode); + void LDSMACL(const UINT16 opcode); + void LDSPR(const UINT16 opcode); + void LDSMMACH(const UINT16 opcode); + void LDSMMACL(const UINT16 opcode); + void LDSMPR(const UINT16 opcode); + void MAC_L(const UINT16 opcode); + void MAC_W(const UINT16 opcode); + void MOV(const UINT16 opcode); + void MOVBS(const UINT16 opcode); + void MOVWS(const UINT16 opcode); + void MOVLS(const UINT16 opcode); + void MOVBL(const UINT16 opcode); + void MOVWL(const UINT16 opcode); + void MOVLL(const UINT16 opcode); + void MOVBM(const UINT16 opcode); + void MOVWM(const UINT16 opcode); + void MOVLM(const UINT16 opcode); + void MOVBP(const UINT16 opcode); + void MOVWP(const UINT16 opcode); + void MOVLP(const UINT16 opcode); + void MOVBS0(const UINT16 opcode); + void MOVWS0(const UINT16 opcode); + void MOVLS0(const UINT16 opcode); + void MOVBL0(const UINT16 opcode); + void MOVWL0(const UINT16 opcode); + void MOVLL0(const UINT16 opcode); + void MOVI(const UINT16 opcode); + void MOVWI(const UINT16 opcode); + void MOVLI(const UINT16 opcode); + void MOVBLG(const UINT16 opcode); + void MOVWLG(const UINT16 opcode); + void MOVLLG(const UINT16 opcode); + void MOVBSG(const UINT16 opcode); + void MOVWSG(const UINT16 opcode); + void MOVLSG(const UINT16 opcode); + void MOVBS4(const UINT16 opcode); + void MOVWS4(const UINT16 opcode); + void MOVLS4(const UINT16 opcode); + void MOVBL4(const UINT16 opcode); + void MOVWL4(const UINT16 opcode); + void MOVLL4(const UINT16 opcode); + void MOVA(const UINT16 opcode); + void MOVT(const UINT16 opcode); + void MULL(const UINT16 opcode); + void MULS(const UINT16 opcode); + void MULU(const UINT16 opcode); + void NEG(const UINT16 opcode); + void NEGC(const UINT16 opcode); + void NOP(const UINT16 opcode); + void NOT(const UINT16 opcode); + void OR(const UINT16 opcode); + void ORI(const UINT16 opcode); + void ORM(const UINT16 opcode); + void ROTCL(const UINT16 opcode); + void ROTCR(const UINT16 opcode); + void ROTL(const UINT16 opcode); + void ROTR(const UINT16 opcode); + void RTE(const UINT16 opcode); + void RTS(const UINT16 opcode); + void SETT(const UINT16 opcode); + void SHAL(const UINT16 opcode); + void SHAR(const UINT16 opcode); + void SHLL(const UINT16 opcode); + void SHLL2(const UINT16 opcode); + void SHLL8(const UINT16 opcode); + void SHLL16(const UINT16 opcode); + void SHLR(const UINT16 opcode); + void SHLR2(const UINT16 opcode); + void SHLR8(const UINT16 opcode); + void SHLR16(const UINT16 opcode); + void SLEEP(const UINT16 opcode); + void STCSR(const UINT16 opcode); + void STCGBR(const UINT16 opcode); + void STCVBR(const UINT16 opcode); + void STCMSR(const UINT16 opcode); + void STCMGBR(const UINT16 opcode); + void STCMVBR(const UINT16 opcode); + void STSMACH(const UINT16 opcode); + void STSMACL(const UINT16 opcode); + void STSPR(const UINT16 opcode); + void STSMMACH(const UINT16 opcode); + void STSMMACL(const UINT16 opcode); + void STSMPR(const UINT16 opcode); + void SUB(const UINT16 opcode); + void SUBC(const UINT16 opcode); + void SUBV(const UINT16 opcode); + void SWAPB(const UINT16 opcode); + void SWAPW(const UINT16 opcode); + void TAS(const UINT16 opcode); + void TRAPA(const UINT16 opcode); + void TST(const UINT16 opcode); + void TSTI(const UINT16 opcode); + void TSTM(const UINT16 opcode); + void XOR(const UINT16 opcode); + void XORI(const UINT16 opcode); + void XORM(const UINT16 opcode); + void XTRCT(const UINT16 opcode); + void STCSSR(const UINT16 opcode); + void STCSPC(const UINT16 opcode); + void STCSGR(const UINT16 opcode); + void STSFPUL(const UINT16 opcode); + void STSFPSCR(const UINT16 opcode); + void STCDBR(const UINT16 opcode); + void STCRBANK(const UINT16 opcode); + void STCMRBANK(const UINT16 opcode); + void MOVCAL(const UINT16 opcode); + void CLRS(const UINT16 opcode); + void SETS(const UINT16 opcode); + void STCMSGR(const UINT16 opcode); + void STSMFPUL(const UINT16 opcode); + void STSMFPSCR(const UINT16 opcode); + void STCMDBR(const UINT16 opcode); + void STCMSSR(const UINT16 opcode); + void STCMSPC(const UINT16 opcode); + void LDSMFPUL(const UINT16 opcode); + void LDSMFPSCR(const UINT16 opcode); + void LDCMDBR(const UINT16 opcode); + void LDCMRBANK(const UINT16 opcode); + void LDCMSSR(const UINT16 opcode); + void LDCMSPC(const UINT16 opcode); + void LDSFPUL(const UINT16 opcode); + void LDSFPSCR(const UINT16 opcode); + void LDCDBR(const UINT16 opcode); + void SHAD(const UINT16 opcode); + void SHLD(const UINT16 opcode); + void LDCRBANK(const UINT16 opcode); + void LDCSSR(const UINT16 opcode); + void LDCSPC(const UINT16 opcode); + void PREFM(const UINT16 opcode); + void FMOVMRIFR(const UINT16 opcode); + void FMOVFRMR(const UINT16 opcode); + void FMOVFRMDR(const UINT16 opcode); + void FMOVFRS0(const UINT16 opcode); + void FMOVS0FR(const UINT16 opcode); + void FMOVMRFR(const UINT16 opcode); + void FMOVFR(const UINT16 opcode); + void FLDI1(const UINT16 opcode); + void FLDI0(const UINT16 opcode); + void FLDS(const UINT16 opcode); + void FSTS(const UINT16 opcode); + void FRCHG(); + void FSCHG(); + void FTRC(const UINT16 opcode); + void FLOAT(const UINT16 opcode); + void FNEG(const UINT16 opcode); + void FABS(const UINT16 opcode); + void FCMP_EQ(const UINT16 opcode); + void FCMP_GT(const UINT16 opcode); + void FCNVDS(const UINT16 opcode); + void FCNVSD(const UINT16 opcode); + void FADD(const UINT16 opcode); + void FSUB(const UINT16 opcode); + void FMUL(const UINT16 opcode); + void FDIV(const UINT16 opcode); + void FMAC(const UINT16 opcode); + void FSQRT(const UINT16 opcode); + void FSRRA(const UINT16 opcode); + void FSSCA(const UINT16 opcode); + void FIPR(const UINT16 opcode); + void FTRV(const UINT16 opcode); + void op1111_0xf13(const UINT16 opcode); + void dbreak(const UINT16 opcode); + void op1111_0x13(UINT16 opcode); + UINT8 RB(offs_t A); + UINT16 RW(offs_t A); + UINT32 RL(offs_t A); + void sh4_change_register_bank(int to); + void sh4_swap_fp_registers(); + void sh4_swap_fp_couples(); + void sh4_syncronize_register_bank(int to); + void sh4_default_exception_priorities(); + void sh4_exception_recompute(); + void sh4_exception_request(int exception); + void sh4_exception_unrequest(int exception); + void sh4_exception_checkunrequest(int exception); + void sh4_exception(const char *message, int exception); + UINT32 compute_ticks_refresh_timer(emu_timer *timer, int hertz, int base, int divisor); + void sh4_refresh_timer_recompute(); + void increment_rtc_time(int mode); + void sh4_dmac_nmi(); + void sh4_handler_ipra_w(UINT32 data, UINT32 mem_mask); + UINT32 sh4_getsqremap(UINT32 address); + void sh4_parse_configuration(); + void sh4_timer_recompute(int which); + UINT32 sh4_handle_tcnt0_addr_r(UINT32 mem_mask); + UINT32 sh4_handle_tcnt1_addr_r(UINT32 mem_mask); + UINT32 sh4_handle_tcnt2_addr_r(UINT32 mem_mask); + UINT32 sh4_handle_tcor0_addr_r(UINT32 mem_mask); + UINT32 sh4_handle_tcor1_addr_r(UINT32 mem_mask); + UINT32 sh4_handle_tcor2_addr_r(UINT32 mem_mask); + UINT32 sh4_handle_tcr0_addr_r(UINT32 mem_mask); + UINT32 sh4_handle_tcr1_addr_r(UINT32 mem_mask); + UINT32 sh4_handle_tcr2_addr_r(UINT32 mem_mask); + UINT32 sh4_handle_tstr_addr_r(UINT32 mem_mask); + UINT32 sh4_handle_tocr_addr_r(UINT32 mem_mask); + UINT32 sh4_handle_tcpr2_addr_r(UINT32 mem_mask); + void sh4_handle_tstr_addr_w(UINT32 data, UINT32 mem_mask); + void sh4_handle_tcr0_addr_w(UINT32 data, UINT32 mem_mask); + void sh4_handle_tcr1_addr_w(UINT32 data, UINT32 mem_mask); + void sh4_handle_tcr2_addr_w(UINT32 data, UINT32 mem_mask); + void sh4_handle_tcor0_addr_w(UINT32 data, UINT32 mem_mask); + void sh4_handle_tcor1_addr_w(UINT32 data, UINT32 mem_mask); + void sh4_handle_tcor2_addr_w(UINT32 data, UINT32 mem_mask); + void sh4_handle_tcnt0_addr_w(UINT32 data, UINT32 mem_mask); + void sh4_handle_tcnt1_addr_w(UINT32 data, UINT32 mem_mask); + void sh4_handle_tcnt2_addr_w(UINT32 data, UINT32 mem_mask); + void sh4_handle_tocr_addr_w(UINT32 data, UINT32 mem_mask); + void sh4_handle_tcpr2_addr_w(UINT32 data, UINT32 mem_mask); + int sh4_dma_transfer(int channel, int timermode, UINT32 chcr, UINT32 *sar, UINT32 *dar, UINT32 *dmatcr); + int sh4_dma_transfer_device(int channel, UINT32 chcr, UINT32 *sar, UINT32 *dar, UINT32 *dmatcr); + void sh4_dmac_check(int channel); + void sh4_handle_sar0_addr_w(UINT32 data, UINT32 mem_mask); + void sh4_handle_sar1_addr_w(UINT32 data, UINT32 mem_mask); + void sh4_handle_sar2_addr_w(UINT32 data, UINT32 mem_mask); + void sh4_handle_sar3_addr_w(UINT32 data, UINT32 mem_mask); + void sh4_handle_dar0_addr_w(UINT32 data, UINT32 mem_mask); + void sh4_handle_dar1_addr_w(UINT32 data, UINT32 mem_mask); + void sh4_handle_dar2_addr_w(UINT32 data, UINT32 mem_mask); + void sh4_handle_dar3_addr_w(UINT32 data, UINT32 mem_mask); + void sh4_handle_dmatcr0_addr_w(UINT32 data, UINT32 mem_mask); + void sh4_handle_dmatcr1_addr_w(UINT32 data, UINT32 mem_mask); + void sh4_handle_dmatcr2_addr_w(UINT32 data, UINT32 mem_mask); + void sh4_handle_dmatcr3_addr_w(UINT32 data, UINT32 mem_mask); + void sh4_handle_chcr0_addr_w(UINT32 data, UINT32 mem_mask); + void sh4_handle_chcr1_addr_w(UINT32 data, UINT32 mem_mask); + void sh4_handle_chcr2_addr_w(UINT32 data, UINT32 mem_mask); + void sh4_handle_chcr3_addr_w(UINT32 data, UINT32 mem_mask); + void sh4_handle_dmaor_addr_w(UINT32 data, UINT32 mem_mask); + UINT32 sh4_handle_sar0_addr_r(UINT32 mem_mask) { return m_SH4_SAR0; } + UINT32 sh4_handle_sar1_addr_r(UINT32 mem_mask) { return m_SH4_SAR1; } + UINT32 sh4_handle_sar2_addr_r(UINT32 mem_mask) { return m_SH4_SAR2; } + UINT32 sh4_handle_sar3_addr_r(UINT32 mem_mask) { return m_SH4_SAR3; } + UINT32 sh4_handle_dar0_addr_r(UINT32 mem_mask) { return m_SH4_DAR0; } + UINT32 sh4_handle_dar1_addr_r(UINT32 mem_mask) { return m_SH4_DAR1; } + UINT32 sh4_handle_dar2_addr_r(UINT32 mem_mask) { return m_SH4_DAR2; } + UINT32 sh4_handle_dar3_addr_r(UINT32 mem_mask) { return m_SH4_DAR3; } + UINT32 sh4_handle_dmatcr0_addr_r(UINT32 mem_mask) { return m_SH4_DMATCR0; } + UINT32 sh4_handle_dmatcr1_addr_r(UINT32 mem_mask) { return m_SH4_DMATCR1; } + UINT32 sh4_handle_dmatcr2_addr_r(UINT32 mem_mask) { return m_SH4_DMATCR2; } + UINT32 sh4_handle_dmatcr3_addr_r(UINT32 mem_mask) { return m_SH4_DMATCR3; } + UINT32 sh4_handle_chcr0_addr_r(UINT32 mem_mask) { return m_SH4_CHCR0; } + UINT32 sh4_handle_chcr1_addr_r(UINT32 mem_mask) { return m_SH4_CHCR1; } + UINT32 sh4_handle_chcr2_addr_r(UINT32 mem_mask) { return m_SH4_CHCR2; } + UINT32 sh4_handle_chcr3_addr_r(UINT32 mem_mask) { return m_SH4_CHCR3; } + UINT32 sh4_handle_dmaor_addr_r(UINT32 mem_mask) { return m_SH4_DMAOR; } + +#if SH4_USE_FASTRAM_OPTIMIZATION + /* fast RAM */ + bool m_bigendian; + UINT32 m_byte_xor; + UINT32 m_word_xor; + UINT32 m_dword_xor; + UINT32 m_fastram_select; + struct + { + offs_t start; /* start of the RAM block */ + offs_t end; /* end of the RAM block */ + UINT8 readonly; /* TRUE if read-only */ + void * base; /* base in memory where the RAM lives */ + } m_fastram[SH4_MAX_FASTRAM]; +#endif +}; + + +class sh3_base_device : public sh34_base_device +{ +public: + // construction/destruction + sh3_base_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, endianness_t endianness); + + DECLARE_WRITE32_MEMBER( sh3_internal_w ); + DECLARE_READ32_MEMBER( sh3_internal_r ); + + DECLARE_WRITE32_MEMBER( sh3_internal_high_w ); + DECLARE_READ32_MEMBER( sh3_internal_high_r ); + +protected: + virtual void device_reset(); +}; + + +class sh4_base_device : public sh34_base_device +{ +public: + // construction/destruction + sh4_base_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, endianness_t endianness); + + DECLARE_WRITE32_MEMBER( sh4_internal_w ); + DECLARE_READ32_MEMBER( sh4_internal_r ); + + DECLARE_READ64_MEMBER( sh4_tlb_r ); + DECLARE_WRITE64_MEMBER( sh4_tlb_w ); + +protected: + virtual void device_reset(); +}; + + +class sh3_device : public sh3_base_device +{ +public: + sh3_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +class sh3be_device : public sh3_base_device +{ +public: + sh3be_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual void execute_run(); + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); +}; + + +class sh4_device : public sh4_base_device +{ +public: + sh4_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +class sh4be_device : public sh4_base_device +{ +public: + sh4be_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual void execute_run(); + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); +}; + + +extern const device_type SH3LE; +extern const device_type SH3BE; +extern const device_type SH4LE; +extern const device_type SH4BE; + + +/*************************************************************************** + COMPILER-SPECIFIC OPTIONS +***************************************************************************/ + +#define SH4DRC_STRICT_VERIFY 0x0001 /* verify all instructions */ +#define SH4DRC_FLUSH_PC 0x0002 /* flush the PC value before each memory access */ +#define SH4DRC_STRICT_PCREL 0x0004 /* do actual loads on MOVLI/MOVWI instead of collapsing to immediates */ + +#define SH4DRC_COMPATIBLE_OPTIONS (SH4DRC_STRICT_VERIFY | SH4DRC_FLUSH_PC | SH4DRC_STRICT_PCREL) +#define SH4DRC_FASTEST_OPTIONS (0) + +void sh4drc_set_options(device_t *device, UINT32 options); +void sh4drc_add_pcflush(device_t *device, offs_t address); + +#endif /* __SH4_H__ */ diff --git a/src/devices/cpu/sh4/sh4comn.c b/src/devices/cpu/sh4/sh4comn.c new file mode 100644 index 00000000000..5052622e2d4 --- /dev/null +++ b/src/devices/cpu/sh4/sh4comn.c @@ -0,0 +1,1238 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/***************************************************************************** + * + * sh4comn.c + * + * SH-4 non-specific components + * + *****************************************************************************/ + +#include "emu.h" +#include "debugger.h" +#include "sh4.h" +#include "sh4regs.h" +#include "sh4comn.h" +#include "sh3comn.h" +#include "sh4tmu.h" +#include "sh4dmac.h" + +static const int rtcnt_div[8] = { 0, 4, 16, 64, 256, 1024, 2048, 4096 }; +static const int daysmonth[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; + + + +static const UINT32 exception_priority_default[] = { + EXPPRI(1,1,0,0), /* Power-on Reset */ + EXPPRI(1,2,0,1), /* Manual Reset */ + EXPPRI(1,1,0,2), /* H-UDI Reset */ + EXPPRI(1,3,0,3), /* Inst TLB Multiple Hit */ + EXPPRI(1,4,0,4), /* Data TLB Multiple Hit */ + + EXPPRI(2,0,0,5), /* User break Before Instruction */ + EXPPRI(2,1,0,6), /* Inst Address Error */ + EXPPRI(2,2,0,7), /* Inst TLB Miss */ + EXPPRI(2,3,0,8), /* Inst TLB Protection Violation */ + EXPPRI(2,4,0,9), /* Illegal Instruction */ + EXPPRI(2,4,0,10), /* Slot Illegal Instruction */ + EXPPRI(2,4,0,11), /* FPU Disable */ + EXPPRI(2,4,0,12), /* Slot FPU Disable */ + EXPPRI(2,5,0,13), /* Data Address Error (Read) */ + EXPPRI(2,5,0,14), /* Data Address Error (Write) */ + EXPPRI(2,6,0,15), /* Data TBL Miss Read */ + EXPPRI(2,6,0,16), /* Data TBL Miss Write */ + EXPPRI(2,7,0,17), /* Data TBL Protection Violation Read */ + EXPPRI(2,7,0,18), /* Data TBL Protection Violation Write */ + EXPPRI(2,8,0,19), /* FPU Exception */ + EXPPRI(2,9,0,20), /* Initial Page Write exception */ + + EXPPRI(2,4,0,21), /* Unconditional TRAP */ + EXPPRI(2,10,0,22), /* User break After Instruction */ + + EXPPRI(3,0,16,SH4_INTC_NMI) /* NMI */ + /* This is copied to a table, and the IRQ priorities filled in later */ +}; + +static const int exception_codes[] = + +{ 0x000, /* Power-on Reset */ + 0x020, /* Manual Reset */ + 0x000, /* H-UDI Reset */ + 0x140, /* Inst TLB Multiple Hit */ + 0x140, /* Data TLB Multiple Hit */ + + 0x1E0, /* User break Before Instruction */ + 0x0E0, /* Inst Address Error */ + 0x040, /* Inst TLB Miss */ + 0x0A0, /* Inst TLB Protection Violation */ + 0x180, /* Illegal Instruction */ + 0x1A0, /* Slot Illegal Instruction */ + 0x800, /* FPU Disable */ + 0x820, /* Slot FPU Disable */ + 0x0E0, /* Data Address Error (Read) */ + 0x100, /* Data Address Error (Write) */ + 0x040, /* Data TBL Miss Read */ + 0x060, /* Data TBL Miss Write */ + 0x0A0, /* Data TBL Protection Violation Read */ + 0x0C0, /* Data TBL Protection Violation Write */ + 0x120, /* FPU Exception */ + 0x080, /* Initial Page Write exception */ + + 0x160, /* Unconditional TRAP */ + 0x1E0, /* User break After Instruction */ + + 0x1C0, /* NMI */ /* SH4_INTC_NMI=23 represents this location in this list.. */ + + 0x200, /* EX Irq 0 */ + 0x220, /* 1 */ + 0x240, /* 2 */ + 0x260, /* 3 */ + 0x280, /* 4 */ + 0x2A0, /* 5 */ + 0x2C0, /* 6 */ + 0x2E0, /* 7 */ + 0x300, /* 8 */ + 0x320, /* 9 */ + 0x340, /* A */ + 0x360, /* B */ + 0x380, /* C */ + 0x3A0, /* D */ + 0x3C0, /* E */ + + 0x240, /* SH4_INTC_IRL0 */ + 0x2A0, /* SH4_INTC_IRL1 */ + 0x300, /* SH4_INTC_IRL2 */ + 0x360, /* SH4_INTC_IRL3 */ + + 0x600, /* HUDI */ + 0x620, /* SH4_INTC_GPOI */ + 0x640, /* SH4_INTC_DMTE0 */ + 0x660, /* SH4_INTC_DMTE1 */ + 0x680, /* SH4_INTC_DMTE2 */ + 0x6A0, /* SH4_INTC_DMTE3 */ + + 0x780, /* SH4_INTC_DMTE4 */ + 0x7A0, /* SH4_INTC_DMTE5 */ + 0x7C0, /* SH4_INTC_DMTE6 */ + 0x7E0, /* SH4_INTC_DMTE7 */ + + 0x6C0, /* SH4_INTC_DMAE */ + + 0xB00, /* SH4_INTC_TUNI3 */ + 0xB80, /* SH4_INTC_TUNI4 */ + 0x400, /* SH4_INTC_TUNI0 */ + 0x420, /* SH4_INTC_TUNI1 */ + 0x440, /* SH4_INTC_TUNI2 */ + 0x460, /* SH4_INTC_TICPI2 */ + 0x480, /* SH4_INTC_ATI */ + 0x4A0, /* SH4_INTC_PRI */ + 0x4C0, /* SH4_INTC_CUI */ + 0x4E0, /* SH4_INTC_SCI1ERI */ + 0x500, /* SH4_INTC_SCI1RXI */ + 0x520, /* SH4_INTC_SCI1TXI */ + 0x540, /* SH4_INTC_SCI1TEI */ + + 0x700, /* SH4_INTC_SCIFERI */ + 0x720, /* SH4_INTC_SCIFRXI */ + 0x740, /* SH4_INTC_SCIFBRI */ + 0x760, /* SH4_INTC_SCIFTXI */ + 0x560, /* SH4_INTC_ITI */ + 0x580, /* SH4_INTC_RCMI */ + 0x5A0 /* SH4_INTC_ROVI */ +}; + +/* SH3 INTEVT2 uses a different table - values of -1 aren't filled in yet, some may not exist on the sh3. */ +/* The above table should differ too, some things depend on the interrupt level rather than beign fixed values */ + +static const int sh3_intevt2_exception_codes[] = + +{ 0x000, /* Power-on Reset */ + -1, /* Manual Reset */ + -1, /* H-UDI Reset */ + -1, /* Inst TLB Multiple Hit */ + -1, /* Data TLB Multiple Hit */ + + -1, /* User break Before Instruction */ + -1, /* Inst Address Error */ + -1, /* Inst TLB Miss */ + -1, /* Inst TLB Protection Violation */ + -1, /* Illegal Instruction */ + -1, /* Slot Illegal Instruction */ + -1, /* FPU Disable */ + -1, /* Slot FPU Disable */ + -1, /* Data Address Error (Read) */ + -1, /* Data Address Error (Write) */ + -1, /* Data TBL Miss Read */ + -1, /* Data TBL Miss Write */ + -1, /* Data TBL Protection Violation Read */ + -1, /* Data TBL Protection Violation Write */ + -1, /* FPU Exception */ + -1, /* Initial Page Write exception */ + + -1, /* Unconditional TRAP */ + -1, /* User break After Instruction */ + + -1, /* NMI */ /* SH4_INTC_NMI=23 represents this location in this list.. */ + + -1, /* EX Irq 0 */ + -1, /* 1 */ + -1, /* 2 */ + -1, /* 3 */ + -1, /* 4 */ + -1, /* 5 */ + -1, /* 6 */ + -1, /* 7 */ + -1, /* 8 */ + -1, /* 9 */ + -1, /* A */ + -1, /* B */ + -1, /* C */ + -1, /* D */ + -1, /* E */ + + 0x600, /* SH4_INTC_IRL0 */ + 0x620, /* SH4_INTC_IRL1 */ + 0x640, /* SH4_INTC_IRL2 */ + 0x660, /* SH4_INTC_IRL3 */ + /* todo: SH3 should have lines 4+5 too? */ + + -1, /* HUDI */ + -1, /* SH4_INTC_GPOI */ + -1, /* SH4_INTC_DMTE0 */ + -1, /* SH4_INTC_DMTE1 */ + -1, /* SH4_INTC_DMTE2 */ + -1, /* SH4_INTC_DMTE3 */ + + -1, /* SH4_INTC_DMTE4 */ + -1, /* SH4_INTC_DMTE5 */ + -1, /* SH4_INTC_DMTE6 */ + -1, /* SH4_INTC_DMTE7 */ + + -1, /* SH4_INTC_DMAE */ + + -1, /* SH4_INTC_TUNI3 */ + -1, /* SH4_INTC_TUNI4 */ + 0x400, /* SH4_INTC_TUNI0 */ + 0x420, /* SH4_INTC_TUNI1 */ + 0x440, /* SH4_INTC_TUNI2 */ + 0x460, /* SH4_INTC_TICPI2 */ + -1, /* SH4_INTC_ATI */ + -1, /* SH4_INTC_PRI */ + -1, /* SH4_INTC_CUI */ + -1, /* SH4_INTC_SCI1ERI */ + -1, /* SH4_INTC_SCI1RXI */ + -1, /* SH4_INTC_SCI1TXI */ + -1, /* SH4_INTC_SCI1TEI */ + + -1, /* SH4_INTC_SCIFERI */ + -1, /* SH4_INTC_SCIFRXI */ + -1, /* SH4_INTC_SCIFBRI */ + -1, /* SH4_INTC_SCIFTXI */ + -1, /* SH4_INTC_ITI */ + -1, /* SH4_INTC_RCMI */ + -1 /* SH4_INTC_ROVI */ +}; + + + +void sh34_base_device::sh4_change_register_bank(int to) +{ + int s; + + if (to) // 0 -> 1 + { + for (s = 0;s < 8;s++) + { + m_rbnk[0][s] = m_r[s]; + m_r[s] = m_rbnk[1][s]; + } + } + else // 1 -> 0 + { + for (s = 0;s < 8;s++) + { + m_rbnk[1][s] = m_r[s]; + m_r[s] = m_rbnk[0][s]; + } + } +} + +void sh34_base_device::sh4_swap_fp_registers() +{ + int s; + UINT32 z; + + for (s = 0;s <= 15;s++) + { + z = m_fr[s]; + m_fr[s] = m_xf[s]; + m_xf[s] = z; + } +} + +void sh34_base_device::sh4_swap_fp_couples() +{ + int s; + UINT32 z; + + for (s = 0;s <= 15;s = s+2) + { + z = m_fr[s]; + m_fr[s] = m_fr[s + 1]; + m_fr[s + 1] = z; + z = m_xf[s]; + m_xf[s] = m_xf[s + 1]; + m_xf[s + 1] = z; + } +} + +void sh34_base_device::sh4_syncronize_register_bank(int to) +{ + int s; + + for (s = 0;s < 8;s++) + { + m_rbnk[to][s] = m_r[s]; + } +} + +void sh34_base_device::sh4_default_exception_priorities() // setup default priorities for exceptions +{ + int a; + + for (a=0;a <= SH4_INTC_NMI;a++) + m_exception_priority[a] = exception_priority_default[a]; + for (a=SH4_INTC_IRLn0;a <= SH4_INTC_IRLnE;a++) + m_exception_priority[a] = INTPRI(15-(a-SH4_INTC_IRLn0), a); + m_exception_priority[SH4_INTC_IRL0] = INTPRI(13, SH4_INTC_IRL0); + m_exception_priority[SH4_INTC_IRL1] = INTPRI(10, SH4_INTC_IRL1); + m_exception_priority[SH4_INTC_IRL2] = INTPRI(7, SH4_INTC_IRL2); + m_exception_priority[SH4_INTC_IRL3] = INTPRI(4, SH4_INTC_IRL3); + for (a=SH4_INTC_HUDI;a <= SH4_INTC_ROVI;a++) + m_exception_priority[a] = INTPRI(0, a); +} + +void sh34_base_device::sh4_exception_recompute() // checks if there is any interrupt with high enough priority +{ + int a,z; + + m_test_irq = 0; + if ((!m_pending_irq) || ((m_sr & BL) && (m_exception_requesting[SH4_INTC_NMI] == 0))) + return; + z = (m_sr >> 4) & 15; + for (a=0;a <= SH4_INTC_ROVI;a++) + { + if (m_exception_requesting[a]) + { + int pri = (((int)m_exception_priority[a] >> 8) & 255); + //logerror("pri is %02x z is %02x\n",pri,z); + if (pri > z) + { + //logerror("will test\n"); + m_test_irq = 1; // will check for exception at end of instructions + break; + } + } + } +} + +void sh34_base_device::sh4_exception_request(int exception) // start requesting an exception +{ + //logerror("sh4_exception_request a\n"); + if (!m_exception_requesting[exception]) + { + //logerror("sh4_exception_request b\n"); + m_exception_requesting[exception] = 1; + m_pending_irq++; + sh4_exception_recompute(); + } +} + +void sh34_base_device::sh4_exception_unrequest(int exception) // stop requesting an exception +{ + if (m_exception_requesting[exception]) + { + m_exception_requesting[exception] = 0; + m_pending_irq--; + sh4_exception_recompute(); + } +} + +void sh34_base_device::sh4_exception_checkunrequest(int exception) +{ + if (exception == SH4_INTC_NMI) + sh4_exception_unrequest(exception); + if ((exception == SH4_INTC_DMTE0) || (exception == SH4_INTC_DMTE1) || + (exception == SH4_INTC_DMTE2) || (exception == SH4_INTC_DMTE3)) + sh4_exception_unrequest(exception); +} + +void sh34_base_device::sh4_exception(const char *message, int exception) // handle exception +{ + UINT32 vector; + + + if (m_cpu_type == CPU_TYPE_SH4) + { + if (exception < SH4_INTC_NMI) + return; // Not yet supported + if (exception == SH4_INTC_NMI) { + if ((m_sr & BL) && (!(m_m[ICR] & 0x200))) + return; + + m_m[ICR] &= ~0x200; + m_m[INTEVT] = 0x1c0; + + + vector = 0x600; + standard_irq_callback(INPUT_LINE_NMI); + LOG(("SH-4 '%s' nmi exception after [%s]\n", tag(), message)); + } else { + // if ((m_m[ICR] & 0x4000) && (m_nmi_line_state == ASSERT_LINE)) + // return; + if (m_sr & BL) + return; + if (((m_exception_priority[exception] >> 8) & 255) <= ((m_sr >> 4) & 15)) + return; + m_m[INTEVT] = exception_codes[exception]; + vector = 0x600; + if ((exception >= SH4_INTC_IRL0) && (exception <= SH4_INTC_IRL3)) + standard_irq_callback((exception-SH4_INTC_IRL0)+SH4_IRL0); + else + standard_irq_callback(SH4_IRL3+1); + LOG(("SH-4 '%s' interrupt exception #%d after [%s]\n", tag(), exception, message)); + } + } + else /* SH3 exceptions */ + { + /***** ASSUME THIS TO BE WRONG FOR NOW *****/ + + if (exception < SH4_INTC_NMI) + return; // Not yet supported + if (exception == SH4_INTC_NMI) + { + return; + } + else + { + if (m_sr & BL) + return; + if (((m_exception_priority[exception] >> 8) & 255) <= ((m_sr >> 4) & 15)) + return; + + + vector = 0x600; + + if ((exception >= SH4_INTC_IRL0) && (exception <= SH4_INTC_IRL3)) + standard_irq_callback((exception-SH4_INTC_IRL0)+SH4_IRL0); + else + standard_irq_callback(SH4_IRL3+1); + + if (sh3_intevt2_exception_codes[exception]==-1) + fatalerror("sh3_intevt2_exception_codes unpopulated for exception %02x\n", exception); + + m_sh3internal_lower[INTEVT2] = sh3_intevt2_exception_codes[exception]; + m_sh3internal_upper[SH3_EXPEVT_ADDR] = exception_codes[exception]; + + + LOG(("SH-3 '%s' interrupt exception #%d after [%s]\n", tag(), exception, message)); + } + + /***** END ASSUME THIS TO BE WRONG FOR NOW *****/ + } + sh4_exception_checkunrequest(exception); + + m_spc = m_pc; + m_ssr = m_sr; + m_sgr = m_r[15]; + + m_sr |= MD; + if ((machine().debug_flags & DEBUG_FLAG_ENABLED) != 0) + sh4_syncronize_register_bank((m_sr & sRB) >> 29); + if (!(m_sr & sRB)) + sh4_change_register_bank(1); + m_sr |= sRB; + m_sr |= BL; + sh4_exception_recompute(); + + /* fetch PC */ + m_pc = m_vbr + vector; + /* wake up if a sleep opcode is triggered */ + if(m_sleep_mode == 1) { m_sleep_mode = 2; } +} + + +UINT32 sh34_base_device::compute_ticks_refresh_timer(emu_timer *timer, int hertz, int base, int divisor) +{ + // elapsed:total = x : ticks + // x=elapsed*tics/total -> x=elapsed*(double)100000000/rtcnt_div[(m_m[RTCSR] >> 3) & 7] + // ticks/total=ticks / ((rtcnt_div[(m_m[RTCSR] >> 3) & 7] * ticks) / 100000000)=1/((rtcnt_div[(m_m[RTCSR] >> 3) & 7] / 100000000)=100000000/rtcnt_div[(m_m[RTCSR] >> 3) & 7] + return base + (UINT32)((timer->elapsed().as_double() * (double)hertz) / (double)divisor); +} + +void sh34_base_device::sh4_refresh_timer_recompute() +{ + UINT32 ticks; + + if (m_cpu_type != CPU_TYPE_SH4) + fatalerror("sh4_refresh_timer_recompute uses m_m[] with SH3\n"); + + + //if rtcnt < rtcor then rtcor-rtcnt + //if rtcnt >= rtcor then 256-rtcnt+rtcor=256+rtcor-rtcnt + ticks = m_m[RTCOR]-m_m[RTCNT]; + if (ticks <= 0) + ticks = 256 + ticks; + m_refresh_timer->adjust(attotime::from_hz(m_bus_clock) * rtcnt_div[(m_m[RTCSR] >> 3) & 7] * ticks); + m_refresh_timer_base = m_m[RTCNT]; +} + + +TIMER_CALLBACK_MEMBER( sh34_base_device::sh4_refresh_timer_callback ) +{ + if (m_cpu_type != CPU_TYPE_SH4) + fatalerror("sh4_refresh_timer_callback uses m_m[] with SH3\n"); + + m_m[RTCNT] = 0; + sh4_refresh_timer_recompute(); + m_m[RTCSR] |= 128; + if ((m_m[MCR] & 4) && !(m_m[MCR] & 2)) + { + m_m[RFCR] = (m_m[RFCR] + 1) & 1023; + if (((m_m[RTCSR] & 1) && (m_m[RFCR] == 512)) || (m_m[RFCR] == 0)) + { + m_m[RFCR] = 0; + m_m[RTCSR] |= 4; + } + } +} + +void sh34_base_device::increment_rtc_time(int mode) +{ + int carry, year, leap, days; + + if (m_cpu_type != CPU_TYPE_SH4) + fatalerror("increment_rtc_time uses m_m[] with SH3\n"); + + if (mode == 0) + { + carry = 0; + m_m[RSECCNT] = m_m[RSECCNT] + 1; + if ((m_m[RSECCNT] & 0xf) == 0xa) + m_m[RSECCNT] = m_m[RSECCNT] + 6; + if (m_m[RSECCNT] == 0x60) + { + m_m[RSECCNT] = 0; + carry=1; + } + else + return; + } + else + carry = 1; + + m_m[RMINCNT] = m_m[RMINCNT] + carry; + if ((m_m[RMINCNT] & 0xf) == 0xa) + m_m[RMINCNT] = m_m[RMINCNT] + 6; + carry=0; + if (m_m[RMINCNT] == 0x60) + { + m_m[RMINCNT] = 0; + carry = 1; + } + + m_m[RHRCNT] = m_m[RHRCNT] + carry; + if ((m_m[RHRCNT] & 0xf) == 0xa) + m_m[RHRCNT] = m_m[RHRCNT] + 6; + carry = 0; + if (m_m[RHRCNT] == 0x24) + { + m_m[RHRCNT] = 0; + carry = 1; + } + + m_m[RWKCNT] = m_m[RWKCNT] + carry; + if (m_m[RWKCNT] == 0x7) + { + m_m[RWKCNT] = 0; + } + + days = 0; + year = (m_m[RYRCNT] & 0xf) + ((m_m[RYRCNT] & 0xf0) >> 4)*10 + ((m_m[RYRCNT] & 0xf00) >> 8)*100 + ((m_m[RYRCNT] & 0xf000) >> 12)*1000; + leap = 0; + if (!(year%100)) + { + if (!(year%400)) + leap = 1; + } + else if (!(year%4)) + leap = 1; + if (m_m[RMONCNT] != 2) + leap = 0; + if (m_m[RMONCNT]) + days = daysmonth[(m_m[RMONCNT] & 0xf) + ((m_m[RMONCNT] & 0xf0) >> 4)*10 - 1]; + + m_m[RDAYCNT] = m_m[RDAYCNT] + carry; + if ((m_m[RDAYCNT] & 0xf) == 0xa) + m_m[RDAYCNT] = m_m[RDAYCNT] + 6; + carry = 0; + if (m_m[RDAYCNT] > (days+leap)) + { + m_m[RDAYCNT] = 1; + carry = 1; + } + + m_m[RMONCNT] = m_m[RMONCNT] + carry; + if ((m_m[RMONCNT] & 0xf) == 0xa) + m_m[RMONCNT] = m_m[RMONCNT] + 6; + carry=0; + if (m_m[RMONCNT] == 0x13) + { + m_m[RMONCNT] = 1; + carry = 1; + } + + m_m[RYRCNT] = m_m[RYRCNT] + carry; + if ((m_m[RYRCNT] & 0xf) >= 0xa) + m_m[RYRCNT] = m_m[RYRCNT] + 6; + if ((m_m[RYRCNT] & 0xf0) >= 0xa0) + m_m[RYRCNT] = m_m[RYRCNT] + 0x60; + if ((m_m[RYRCNT] & 0xf00) >= 0xa00) + m_m[RYRCNT] = m_m[RYRCNT] + 0x600; + if ((m_m[RYRCNT] & 0xf000) >= 0xa000) + m_m[RYRCNT] = 0; +} + +TIMER_CALLBACK_MEMBER( sh34_base_device::sh4_rtc_timer_callback ) +{ + if (m_cpu_type != CPU_TYPE_SH4) + { + logerror("sh4_rtc_timer_callback uses m_m[] with SH3\n"); + return; + } + + m_rtc_timer->adjust(attotime::from_hz(128)); + m_m[R64CNT] = (m_m[R64CNT]+1) & 0x7f; + if (m_m[R64CNT] == 64) + { + m_m[RCR1] |= 0x80; + increment_rtc_time(0); + //sh4_exception_request(SH4_INTC_NMI); // TEST + } +} + + +void sh34_base_device::sh4_dmac_nmi() // manage dma when nmi gets asserted +{ + int s; + + m_SH4_DMAOR |= DMAOR_NMIF; + for (s = 0;s < 4;s++) + { + if (m_dma_timer_active[s]) + { + logerror("SH4: DMA %d cancelled due to NMI but all data transferred", s); + m_dma_timer[s]->adjust(attotime::never, s); + m_dma_timer_active[s] = 0; + } + } +} + +void sh34_base_device::sh4_handler_ipra_w(UINT32 data, UINT32 mem_mask) +{ + COMBINE_DATA(&m_SH4_IPRA); + /* 15 - 12 TMU0 */ + /* 11 - 8 TMU1 */ + /* 7 - 4 TMU2 */ + /* 3 - 0 RTC */ + m_exception_priority[SH4_INTC_ATI] = INTPRI(m_SH4_IPRA & 0x000f, SH4_INTC_ATI); + m_exception_priority[SH4_INTC_PRI] = INTPRI(m_SH4_IPRA & 0x000f, SH4_INTC_PRI); + m_exception_priority[SH4_INTC_CUI] = INTPRI(m_SH4_IPRA & 0x000f, SH4_INTC_CUI); + + m_exception_priority[SH4_INTC_TUNI2] = INTPRI((m_SH4_IPRA & 0x00f0) >> 4, SH4_INTC_TUNI2); + m_exception_priority[SH4_INTC_TICPI2] = INTPRI((m_SH4_IPRA & 0x00f0) >> 4, SH4_INTC_TICPI2); + + m_exception_priority[SH4_INTC_TUNI1] = INTPRI((m_SH4_IPRA & 0x0f00) >> 8, SH4_INTC_TUNI1); + + m_exception_priority[SH4_INTC_TUNI0] = INTPRI((m_SH4_IPRA & 0xf000) >> 12, SH4_INTC_TUNI0); + + logerror("setting priorities TMU0 %01x TMU1 %01x TMU2 %01x RTC %01x\n", (m_SH4_IPRA & 0xf000)>>12, (m_SH4_IPRA & 0x0f00)>>8, (m_SH4_IPRA & 0x00f0)>>4, (m_SH4_IPRA & 0x000f)>>0); + + sh4_exception_recompute(); +} + + +WRITE32_MEMBER( sh4_base_device::sh4_internal_w ) +{ + int a; + UINT32 addr = (offset << 2) + 0xfe000000; + offset = ((addr & 0xfc) >> 2) | ((addr & 0x1fe0000) >> 11); + + if (m_cpu_type != CPU_TYPE_SH4) + fatalerror("sh4_internal_w uses m_m[] with SH3\n"); + + UINT32 old = m_m[offset]; + COMBINE_DATA(m_m+offset); + +// printf("sh4_internal_w: Write %08x (%x), %08x @ %08x\n", 0xfe000000+((offset & 0x3fc0) << 11)+((offset & 0x3f) << 2), offset, data, mem_mask); + + switch( offset ) + { + case MMUCR: // MMU Control + if (data & MMUCR_AT) + { + printf("SH4 MMU Enabled\n"); + printf("If you're seeing this, but running something other than a Naomi GD-ROM game then chances are it won't work\n"); + printf("The MMU emulation is a hack specific to that system\n"); + m_sh4_mmu_enabled = 1; + + // should be a different bit! + { + int i; + for (i=0;i<64;i++) + { + m_sh4_tlb_address[i] = 0; + m_sh4_tlb_data[i] = 0; + } + + } + } + else + { + m_sh4_mmu_enabled = 0; + } + + break; + + // Memory refresh + case RTCSR: + m_m[RTCSR] &= 255; + if ((old >> 3) & 7) + m_m[RTCNT] = compute_ticks_refresh_timer(m_refresh_timer, m_bus_clock, m_refresh_timer_base, rtcnt_div[(old >> 3) & 7]) & 0xff; + if ((m_m[RTCSR] >> 3) & 7) + { // activated + sh4_refresh_timer_recompute(); + } + else + { + m_refresh_timer->adjust(attotime::never); + } + break; + + case RTCNT: + m_m[RTCNT] &= 255; + if ((m_m[RTCSR] >> 3) & 7) + { // active + sh4_refresh_timer_recompute(); + } + break; + + case RTCOR: + m_m[RTCOR] &= 255; + if ((m_m[RTCSR] >> 3) & 7) + { // active + m_m[RTCNT] = compute_ticks_refresh_timer(m_refresh_timer, m_bus_clock, m_refresh_timer_base, rtcnt_div[(m_m[RTCSR] >> 3) & 7]) & 0xff; + sh4_refresh_timer_recompute(); + } + break; + + case RFCR: + m_m[RFCR] &= 1023; + break; + + // RTC + case RCR1: + if ((m_m[RCR1] & 8) && (~old & 8)) // 0 -> 1 + m_m[RCR1] ^= 1; + break; + + case RCR2: + if (m_m[RCR2] & 2) + { + m_m[R64CNT] = 0; + m_m[RCR2] ^= 2; + } + if (m_m[RCR2] & 4) + { + m_m[R64CNT] = 0; + if (m_m[RSECCNT] >= 30) + increment_rtc_time(1); + m_m[RSECCNT] = 0; + } + if ((m_m[RCR2] & 8) && (~old & 8)) + { // 0 -> 1 + m_rtc_timer->adjust(attotime::from_hz(128)); + } + else if (~(m_m[RCR2]) & 8) + { // 0 + m_rtc_timer->adjust(attotime::never); + } + break; + +/********************************************************************************************************************* + TMU (Timer Unit) +*********************************************************************************************************************/ + case SH4_TSTR_ADDR: sh4_handle_tstr_addr_w(data,mem_mask); break; + case SH4_TCR0_ADDR: sh4_handle_tcr0_addr_w(data,mem_mask); break; + case SH4_TCR1_ADDR: sh4_handle_tcr1_addr_w(data,mem_mask); break; + case SH4_TCR2_ADDR: sh4_handle_tcr2_addr_w(data,mem_mask); break; + case SH4_TCOR0_ADDR: sh4_handle_tcor0_addr_w(data,mem_mask); break; + case SH4_TCNT0_ADDR: sh4_handle_tcnt0_addr_w(data,mem_mask); break; + case SH4_TCOR1_ADDR: sh4_handle_tcor1_addr_w(data,mem_mask); break; + case SH4_TCNT1_ADDR: sh4_handle_tcnt1_addr_w(data,mem_mask); break; + case SH4_TCOR2_ADDR: sh4_handle_tcor2_addr_w(data,mem_mask); break; + case SH4_TCNT2_ADDR: sh4_handle_tcnt2_addr_w(data,mem_mask); break; + case SH4_TOCR_ADDR: sh4_handle_tocr_addr_w(data,mem_mask); break; // not supported + case SH4_TCPR2_ADDR: sh4_handle_tcpr2_addr_w(data,mem_mask); break; // not supported +/********************************************************************************************************************* + INTC (Interrupt Controller) +*********************************************************************************************************************/ + case ICR: + m_m[ICR] = (m_m[ICR] & 0x7fff) | (old & 0x8000); + break; + case IPRA: sh4_handler_ipra_w(data, mem_mask); break; + case IPRB: + m_exception_priority[SH4_INTC_SCI1ERI] = INTPRI((m_m[IPRB] & 0x00f0) >> 4, SH4_INTC_SCI1ERI); + m_exception_priority[SH4_INTC_SCI1RXI] = INTPRI((m_m[IPRB] & 0x00f0) >> 4, SH4_INTC_SCI1RXI); + m_exception_priority[SH4_INTC_SCI1TXI] = INTPRI((m_m[IPRB] & 0x00f0) >> 4, SH4_INTC_SCI1TXI); + m_exception_priority[SH4_INTC_SCI1TEI] = INTPRI((m_m[IPRB] & 0x00f0) >> 4, SH4_INTC_SCI1TEI); + m_exception_priority[SH4_INTC_RCMI] = INTPRI((m_m[IPRB] & 0x0f00) >> 8, SH4_INTC_RCMI); + m_exception_priority[SH4_INTC_ROVI] = INTPRI((m_m[IPRB] & 0x0f00) >> 8, SH4_INTC_ROVI); + m_exception_priority[SH4_INTC_ITI] = INTPRI((m_m[IPRB] & 0xf000) >> 12, SH4_INTC_ITI); + sh4_exception_recompute(); + break; + case IPRC: + m_exception_priority[SH4_INTC_HUDI] = INTPRI(m_m[IPRC] & 0x000f, SH4_INTC_HUDI); + m_exception_priority[SH4_INTC_SCIFERI] = INTPRI((m_m[IPRC] & 0x00f0) >> 4, SH4_INTC_SCIFERI); + m_exception_priority[SH4_INTC_SCIFRXI] = INTPRI((m_m[IPRC] & 0x00f0) >> 4, SH4_INTC_SCIFRXI); + m_exception_priority[SH4_INTC_SCIFBRI] = INTPRI((m_m[IPRC] & 0x00f0) >> 4, SH4_INTC_SCIFBRI); + m_exception_priority[SH4_INTC_SCIFTXI] = INTPRI((m_m[IPRC] & 0x00f0) >> 4, SH4_INTC_SCIFTXI); + m_exception_priority[SH4_INTC_DMTE0] = INTPRI((m_m[IPRC] & 0x0f00) >> 8, SH4_INTC_DMTE0); + m_exception_priority[SH4_INTC_DMTE1] = INTPRI((m_m[IPRC] & 0x0f00) >> 8, SH4_INTC_DMTE1); + m_exception_priority[SH4_INTC_DMTE2] = INTPRI((m_m[IPRC] & 0x0f00) >> 8, SH4_INTC_DMTE2); + m_exception_priority[SH4_INTC_DMTE3] = INTPRI((m_m[IPRC] & 0x0f00) >> 8, SH4_INTC_DMTE3); + m_exception_priority[SH4_INTC_DMAE] = INTPRI((m_m[IPRC] & 0x0f00) >> 8, SH4_INTC_DMAE); + m_exception_priority[SH4_INTC_GPOI] = INTPRI((m_m[IPRC] & 0xf000) >> 12, SH4_INTC_GPOI); + sh4_exception_recompute(); + break; +/********************************************************************************************************************* + DMAC (DMA Controller) +*********************************************************************************************************************/ + case SH4_SAR0_ADDR: sh4_handle_sar0_addr_w(data,mem_mask); break; + case SH4_SAR1_ADDR: sh4_handle_sar1_addr_w(data,mem_mask); break; + case SH4_SAR2_ADDR: sh4_handle_sar2_addr_w(data,mem_mask); break; + case SH4_SAR3_ADDR: sh4_handle_sar3_addr_w(data,mem_mask); break; + case SH4_DAR0_ADDR: sh4_handle_dar0_addr_w(data,mem_mask); break; + case SH4_DAR1_ADDR: sh4_handle_dar1_addr_w(data,mem_mask); break; + case SH4_DAR2_ADDR: sh4_handle_dar2_addr_w(data,mem_mask); break; + case SH4_DAR3_ADDR: sh4_handle_dar3_addr_w(data,mem_mask); break; + case SH4_DMATCR0_ADDR: sh4_handle_dmatcr0_addr_w(data,mem_mask); break; + case SH4_DMATCR1_ADDR: sh4_handle_dmatcr1_addr_w(data,mem_mask); break; + case SH4_DMATCR2_ADDR: sh4_handle_dmatcr2_addr_w(data,mem_mask); break; + case SH4_DMATCR3_ADDR: sh4_handle_dmatcr3_addr_w(data,mem_mask); break; + case SH4_CHCR0_ADDR: sh4_handle_chcr0_addr_w(data,mem_mask); break; + case SH4_CHCR1_ADDR: sh4_handle_chcr1_addr_w(data,mem_mask); break; + case SH4_CHCR2_ADDR: sh4_handle_chcr2_addr_w(data,mem_mask); break; + case SH4_CHCR3_ADDR: sh4_handle_chcr3_addr_w(data,mem_mask); break; + case SH4_DMAOR_ADDR: sh4_handle_dmaor_addr_w(data,mem_mask); break; +/********************************************************************************************************************* + Store Queues +*********************************************************************************************************************/ + case QACR0: + case QACR1: + break; +/********************************************************************************************************************* + I/O +*********************************************************************************************************************/ + case PCTRA: + m_ioport16_pullup = 0; + m_ioport16_direction = 0; + for (a=0;a < 16;a++) { + m_ioport16_direction |= (m_m[PCTRA] & (1 << (a*2))) >> a; + m_ioport16_pullup |= (m_m[PCTRA] & (1 << (a*2+1))) >> (a+1); + } + m_ioport16_direction &= 0xffff; + m_ioport16_pullup = (m_ioport16_pullup | m_ioport16_direction) ^ 0xffff; + if (m_m[BCR2] & 1) + m_io->write_dword(SH4_IOPORT_16, (UINT64)(m_m[PDTRA] & m_ioport16_direction) | ((UINT64)m_m[PCTRA] << 16)); + break; + case PDTRA: + if (m_m[BCR2] & 1) + m_io->write_dword(SH4_IOPORT_16, (UINT64)(m_m[PDTRA] & m_ioport16_direction) | ((UINT64)m_m[PCTRA] << 16)); + break; + case PCTRB: + m_ioport4_pullup = 0; + m_ioport4_direction = 0; + for (a=0;a < 4;a++) { + m_ioport4_direction |= (m_m[PCTRB] & (1 << (a*2))) >> a; + m_ioport4_pullup |= (m_m[PCTRB] & (1 << (a*2+1))) >> (a+1); + } + m_ioport4_direction &= 0xf; + m_ioport4_pullup = (m_ioport4_pullup | m_ioport4_direction) ^ 0xf; + if (m_m[BCR2] & 1) + m_io->write_dword(SH4_IOPORT_4, (m_m[PDTRB] & m_ioport4_direction) | (m_m[PCTRB] << 16)); + break; + case PDTRB: + if (m_m[BCR2] & 1) + m_io->write_dword(SH4_IOPORT_4, (m_m[PDTRB] & m_ioport4_direction) | (m_m[PCTRB] << 16)); + break; + + case SCBRR2: + break; + + case SCSPTR2: //trips often in aristocrat mk-6 + break; + + default: + logerror("sh4_internal_w: Unmapped write %08x, %08x @ %08x\n", 0xfe000000+((offset & 0x3fc0) << 11)+((offset & 0x3f) << 2), data, mem_mask); + break; + } +} + +READ32_MEMBER( sh4_base_device::sh4_internal_r ) +{ + if (m_cpu_type != CPU_TYPE_SH4) + fatalerror("sh4_internal_r uses m_m[] with SH3\n"); + + UINT32 addr = (offset << 2) + 0xfe000000; + offset = ((addr & 0xfc) >> 2) | ((addr & 0x1fe0000) >> 11); + +// printf("sh4_internal_r: Read %08x (%x) @ %08x\n", 0xfe000000+((offset & 0x3fc0) << 11)+((offset & 0x3f) << 2), offset, mem_mask); + + switch( offset ) + { + case VERSION: + return PVR_SH7091; // 0x040205c1, this is what a real SH7091 in a Dreamcast returns - the later Naomi BIOSes check and care! + case PRR: + return 0; + case IPRD: + return 0x00000000; // SH7750 ignores writes here and always returns zero + case RTCNT: + if ((m_m[RTCSR] >> 3) & 7) + { // activated + //((double)rtcnt_div[(m_m[RTCSR] >> 3) & 7] / (double)100000000) + //return (refresh_timer_base + (m_refresh_timer->elapsed() * (double)100000000) / (double)rtcnt_div[(m_m[RTCSR] >> 3) & 7]) & 0xff; + return compute_ticks_refresh_timer(m_refresh_timer, m_bus_clock, m_refresh_timer_base, rtcnt_div[(m_m[RTCSR] >> 3) & 7]) & 0xff; + } + else + return m_m[RTCNT]; + +/********************************************************************************************************************* + INTC (Interrupt Controller) +*********************************************************************************************************************/ + + case IPRA: + return m_SH4_IPRA; + +/********************************************************************************************************************* + TMU (Timer Unit) +*********************************************************************************************************************/ + case SH4_TSTR_ADDR: return sh4_handle_tstr_addr_r(mem_mask); + case SH4_TCR0_ADDR: return sh4_handle_tcr0_addr_r(mem_mask); + case SH4_TCR1_ADDR: return sh4_handle_tcr1_addr_r(mem_mask); + case SH4_TCR2_ADDR: return sh4_handle_tcr2_addr_r(mem_mask); + case SH4_TCNT0_ADDR: return sh4_handle_tcnt0_addr_r(mem_mask); + case SH4_TCNT1_ADDR: return sh4_handle_tcnt1_addr_r(mem_mask); + case SH4_TCNT2_ADDR: return sh4_handle_tcnt2_addr_r(mem_mask); + case SH4_TCOR0_ADDR: return sh4_handle_tcor0_addr_r(mem_mask); + case SH4_TCOR1_ADDR: return sh4_handle_tcor1_addr_r(mem_mask); + case SH4_TCOR2_ADDR: return sh4_handle_tcor2_addr_r(mem_mask); + case SH4_TOCR_ADDR: return sh4_handle_tocr_addr_r(mem_mask); // not supported + case SH4_TCPR2_ADDR: return sh4_handle_tcpr2_addr_r(mem_mask); // not supported +/********************************************************************************************************************* + DMAC (DMA Controller) +*********************************************************************************************************************/ + case SH4_SAR0_ADDR: return sh4_handle_sar0_addr_r(mem_mask); + case SH4_SAR1_ADDR: return sh4_handle_sar1_addr_r(mem_mask); + case SH4_SAR2_ADDR: return sh4_handle_sar2_addr_r(mem_mask); + case SH4_SAR3_ADDR: return sh4_handle_sar3_addr_r(mem_mask); + case SH4_DAR0_ADDR: return sh4_handle_dar0_addr_r(mem_mask); + case SH4_DAR1_ADDR: return sh4_handle_dar1_addr_r(mem_mask); + case SH4_DAR2_ADDR: return sh4_handle_dar2_addr_r(mem_mask); + case SH4_DAR3_ADDR: return sh4_handle_dar3_addr_r(mem_mask); + case SH4_DMATCR0_ADDR: return sh4_handle_dmatcr0_addr_r(mem_mask); + case SH4_DMATCR1_ADDR: return sh4_handle_dmatcr1_addr_r(mem_mask); + case SH4_DMATCR2_ADDR: return sh4_handle_dmatcr2_addr_r(mem_mask); + case SH4_DMATCR3_ADDR: return sh4_handle_dmatcr3_addr_r(mem_mask); + case SH4_CHCR0_ADDR: return sh4_handle_chcr0_addr_r(mem_mask); + case SH4_CHCR1_ADDR: return sh4_handle_chcr1_addr_r(mem_mask); + case SH4_CHCR2_ADDR: return sh4_handle_chcr2_addr_r(mem_mask); + case SH4_CHCR3_ADDR: return sh4_handle_chcr3_addr_r(mem_mask); + case SH4_DMAOR_ADDR: return sh4_handle_dmaor_addr_r(mem_mask); +/********************************************************************************************************************* + I/O Ports +*********************************************************************************************************************/ + + case PDTRA: + if (m_m[BCR2] & 1) + return (m_io->read_dword(SH4_IOPORT_16) & ~m_ioport16_direction) | (m_m[PDTRA] & m_ioport16_direction); + break; + case PDTRB: + if (m_m[BCR2] & 1) + return (m_io->read_dword(SH4_IOPORT_4) & ~m_ioport4_direction) | (m_m[PDTRB] & m_ioport4_direction); + break; + + // SCIF (UART with FIFO) + case SCFSR2: + return 0x60; //read-only status register + } + return m_m[offset]; +} + +void sh34_base_device::sh4_set_frt_input(int state) +{ + if (m_cpu_type != CPU_TYPE_SH4) + fatalerror("sh4_set_frt_input uses m_m[] with SH3\n"); + + if(state == PULSE_LINE) + { + sh4_set_frt_input(ASSERT_LINE); + sh4_set_frt_input(CLEAR_LINE); + return; + } + + if(m_frt_input == state) { + return; + } + + m_frt_input = state; + + if (m_cpu_type == CPU_TYPE_SH4) + { + if(m_m[5] & 0x8000) { + if(state == CLEAR_LINE) { + return; + } + } else { + if(state == ASSERT_LINE) { + return; + } + } + } + else + { + fatalerror("sh4_set_frt_input uses m_m[] with SH3\n"); + } + +#if 0 + sh4_timer_resync(); + m_icr = m_frc; + m_m[4] |= ICF; + logerror("SH4 '%s': ICF activated (%x)\n", tag(), m_pc & AM); + sh4_recalc_irq(); +#endif +} + +void sh34_base_device::sh4_set_irln_input(int value) +{ + if (m_irln == value) + return; + m_irln = value; + set_input_line(SH4_IRLn, ASSERT_LINE); + set_input_line(SH4_IRLn, CLEAR_LINE); +} + +void sh34_base_device::execute_set_input(int irqline, int state) // set state of external interrupt line +{ + if (m_cpu_type == CPU_TYPE_SH3) + { + /***** ASSUME THIS TO BE WRONG FOR NOW *****/ + + if (irqline == INPUT_LINE_NMI) + { + fatalerror("SH3 NMI Unimplemented\n"); + } + else + { + //if (irqline > SH4_IRL3) + // return; + if (m_irq_line_state[irqline] == state) + return; + m_irq_line_state[irqline] = state; + + if( state == CLEAR_LINE ) + { + LOG(("SH-4 '%s' cleared external irq IRL%d\n", tag(), irqline)); + sh4_exception_unrequest(SH4_INTC_IRL0+irqline-SH4_IRL0); + } + else + { + LOG(("SH-4 '%s' assert external irq IRL%d\n", tag(), irqline)); + sh4_exception_request(SH4_INTC_IRL0+irqline-SH4_IRL0); + } + + } + + /***** END ASSUME THIS TO BE WRONG FOR NOW *****/ + } + else + { + int s; + + if (irqline == INPUT_LINE_NMI) + { + if (m_nmi_line_state == state) + return; + if (m_m[ICR] & 0x100) + { + if ((state == CLEAR_LINE) && (m_nmi_line_state == ASSERT_LINE)) // rising + { + LOG(("SH-4 '%s' assert nmi\n", tag())); + sh4_exception_request(SH4_INTC_NMI); + sh4_dmac_nmi(); + } + } + else + { + if ((state == ASSERT_LINE) && (m_nmi_line_state == CLEAR_LINE)) // falling + { + LOG(("SH-4 '%s' assert nmi\n", tag())); + sh4_exception_request(SH4_INTC_NMI); + sh4_dmac_nmi(); + } + } + if (state == CLEAR_LINE) + m_m[ICR] ^= 0x8000; + else + m_m[ICR] |= 0x8000; + m_nmi_line_state = state; + } + else + { + if (m_m[ICR] & 0x80) // four independent external interrupt sources + { + if (irqline > SH4_IRL3) + return; + if (m_irq_line_state[irqline] == state) + return; + m_irq_line_state[irqline] = state; + + if( state == CLEAR_LINE ) + { + LOG(("SH-4 '%s' cleared external irq IRL%d\n", tag(), irqline)); + sh4_exception_unrequest(SH4_INTC_IRL0+irqline-SH4_IRL0); + } + else + { + LOG(("SH-4 '%s' assert external irq IRL%d\n", tag(), irqline)); + sh4_exception_request(SH4_INTC_IRL0+irqline-SH4_IRL0); + } + } + else // level-encoded interrupt + { + if (irqline != SH4_IRLn) + return; + if ((m_irln > 15) || (m_irln < 0)) + return; + for (s = 0; s < 15; s++) + sh4_exception_unrequest(SH4_INTC_IRLn0+s); + if (m_irln < 15) + sh4_exception_request(SH4_INTC_IRLn0+m_irln); + LOG(("SH-4 '%s' IRLn0-IRLn3 level #%d\n", tag(), m_irln)); + } + } + if (m_test_irq && (!m_delay)) + sh4_check_pending_irq("sh4_set_irq_line"); + } +} + +void sh34_base_device::sh4_parse_configuration() +{ + if(c_clock > 0) + { + switch((c_md2 << 2) | (c_md1 << 1) | (c_md0)) + { + case 0: + m_cpu_clock = c_clock; + m_bus_clock = c_clock / 4; + m_pm_clock = c_clock / 4; + break; + case 1: + m_cpu_clock = c_clock; + m_bus_clock = c_clock / 6; + m_pm_clock = c_clock / 6; + break; + case 2: + m_cpu_clock = c_clock; + m_bus_clock = c_clock / 3; + m_pm_clock = c_clock / 6; + break; + case 3: + m_cpu_clock = c_clock; + m_bus_clock = c_clock / 3; + m_pm_clock = c_clock / 6; + break; + case 4: + m_cpu_clock = c_clock; + m_bus_clock = c_clock / 2; + m_pm_clock = c_clock / 4; + break; + case 5: + m_cpu_clock = c_clock; + m_bus_clock = c_clock / 2; + m_pm_clock = c_clock / 4; + break; + } + m_is_slave = (~(c_md7)) & 1; + } + else + { + m_cpu_clock = 200000000; + m_bus_clock = 100000000; + m_pm_clock = 50000000; + m_is_slave = 0; + } +} + +UINT32 sh34_base_device::sh4_getsqremap(UINT32 address) +{ + if (!m_sh4_mmu_enabled) + return address; + else + { + int i; + UINT32 topaddr = address&0xfff00000; + + for (i=0;i<64;i++) + { + UINT32 topcmp = m_sh4_tlb_address[i]&0xfff00000; + if (topcmp==topaddr) + return (address&0x000fffff) | ((m_sh4_tlb_data[i])&0xfff00000); + } + + } + + return address; +} + +READ64_MEMBER( sh4_base_device::sh4_tlb_r ) +{ + int offs = offset*8; + + if (offs >= 0x01000000) + { + UINT8 i = (offs>>8)&63; + return m_sh4_tlb_data[i]; + } + else + { + UINT8 i = (offs>>8)&63; + return m_sh4_tlb_address[i]; + } +} + +WRITE64_MEMBER( sh4_base_device::sh4_tlb_w ) +{ + int offs = offset*8; + + if (offs >= 0x01000000) + { + UINT8 i = (offs>>8)&63; + m_sh4_tlb_data[i] = data&0xffffffff; + } + else + { + UINT8 i = (offs>>8)&63; + m_sh4_tlb_address[i] = data&0xffffffff; + } +} diff --git a/src/devices/cpu/sh4/sh4comn.h b/src/devices/cpu/sh4/sh4comn.h new file mode 100644 index 00000000000..3aaec85692f --- /dev/null +++ b/src/devices/cpu/sh4/sh4comn.h @@ -0,0 +1,174 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/***************************************************************************** + * + * sh4comn.h + * + * SH-4 non-specific components + * + *****************************************************************************/ + +#pragma once + +#ifndef __SH4COMN_H__ +#define __SH4COMN_H__ + +//#define USE_SH4DRC + +/* speed up delay loops, bail out of tight loops */ +#define BUSY_LOOP_HACKS 0 + +#define VERBOSE 0 + +#ifdef USE_SH4DRC +#include "cpu/drcfe.h" +#include "cpu/drcuml.h" +#include "cpu/drcumlsh.h" + +class sh4_frontend; +#endif + +#define CPU_TYPE_SH3 (2) +#define CPU_TYPE_SH4 (3) + +#define LOG(x) do { if (VERBOSE) logerror x; } while (0) + +#define EXPPRI(pl,po,p,n) (((4-(pl)) << 24) | ((15-(po)) << 16) | ((p) << 8) | (255-(n))) +#define NMIPRI() EXPPRI(3,0,16,SH4_INTC_NMI) +#define INTPRI(p,n) EXPPRI(4,2,p,n) + +#define FP_RS(r) m_fr[(r)] // binary representation of single precision floating point register r +#define FP_RFS(r) *( (float *)(m_fr+(r)) ) // single precision floating point register r +#define FP_RFD(r) *( (double *)(m_fr+(r)) ) // double precision floating point register r +#define FP_XS(r) m_xf[(r)] // binary representation of extended single precision floating point register r +#define FP_XFS(r) *( (float *)(m_xf+(r)) ) // single precision extended floating point register r +#define FP_XFD(r) *( (double *)(m_xf+(r)) ) // double precision extended floating point register r +#ifdef LSB_FIRST +#define FP_RS2(r) m_fr[(r) ^ m_fpu_pr] +#define FP_RFS2(r) *( (float *)(m_fr+((r) ^ m_fpu_pr)) ) +#define FP_XS2(r) m_xf[(r) ^ m_fpu_pr] +#define FP_XFS2(r) *( (float *)(m_xf+((r) ^ m_fpu_pr)) ) +#endif + + +#ifdef USE_SH4DRC +struct sh4_state +{ + int icount; + + int pcfsel; // last pcflush entry set + int maxpcfsel; // highest valid pcflush entry + UINT32 pcflushes[16]; // pcflush entries + + drc_cache * cache; /* pointer to the DRC code cache */ + drcuml_state * drcuml; /* DRC UML generator state */ + sh4_frontend * drcfe; /* pointer to the DRC front-end class */ + UINT32 drcoptions; /* configurable DRC options */ + + /* internal stuff */ + UINT8 cache_dirty; /* true if we need to flush the cache */ + + /* parameters for subroutines */ + UINT64 numcycles; /* return value from gettotalcycles */ + UINT32 arg0; /* print_debug argument 1 */ + UINT32 arg1; /* print_debug argument 2 */ + UINT32 irq; /* irq we're taking */ + + /* register mappings */ + uml::parameter regmap[16]; /* parameter to register mappings for all 16 integer registers */ + + uml::code_handle * entry; /* entry point */ + uml::code_handle * read8; /* read byte */ + uml::code_handle * write8; /* write byte */ + uml::code_handle * read16; /* read half */ + uml::code_handle * write16; /* write half */ + uml::code_handle * read32; /* read word */ + uml::code_handle * write32; /* write word */ + + uml::code_handle * interrupt; /* interrupt */ + uml::code_handle * nocode; /* nocode */ + uml::code_handle * out_of_cycles; /* out of cycles exception handler */ + + UINT32 prefadr; + UINT32 target; +}; +#endif + +#ifdef USE_SH4DRC +class sh4_frontend : public drc_frontend +{ +public: + sh4_frontend(sh4_state &state, UINT32 window_start, UINT32 window_end, UINT32 max_sequence); + +protected: + virtual bool describe(opcode_desc &desc, const opcode_desc *prev); + +private: + bool describe_group_0(opcode_desc &desc, const opcode_desc *prev, UINT16 opcode); + bool describe_group_2(opcode_desc &desc, const opcode_desc *prev, UINT16 opcode); + bool describe_group_3(opcode_desc &desc, const opcode_desc *prev, UINT16 opcode); + bool describe_group_4(opcode_desc &desc, const opcode_desc *prev, UINT16 opcode); + bool describe_group_6(opcode_desc &desc, const opcode_desc *prev, UINT16 opcode); + bool describe_group_8(opcode_desc &desc, const opcode_desc *prev, UINT16 opcode); + bool describe_group_12(opcode_desc &desc, const opcode_desc *prev, UINT16 opcode); + bool describe_group_15(opcode_desc &desc, const opcode_desc *prev, UINT16 opcode); + + sh4_state &m_context; +}; +#endif + + +enum +{ + ICF = 0x00800000, + OCFA = 0x00080000, + OCFB = 0x00040000, + OVF = 0x00020000 +}; + +/* Bits in SR */ +#define T 0x00000001 +#define S 0x00000002 +#define I 0x000000f0 +#define Q 0x00000100 +#define M 0x00000200 +#define FD 0x00008000 +#define BL 0x10000000 +#define sRB 0x20000000 +#define MD 0x40000000 + +/* 29 bits */ +#define AM 0x1fffffff + +#define FLAGS (MD|sRB|BL|FD|M|Q|I|S|T) + +/* Bits in FPSCR */ +#define RM 0x00000003 +#define DN 0x00040000 +#define PR 0x00080000 +#define SZ 0x00100000 +#define FR 0x00200000 + +#define Rn ((opcode>>8)&15) +#define Rm ((opcode>>4)&15) + +#define REGFLAG_R(n) (1 << (n)) +#define REGFLAG_FR(n) (1 << (n)) +#define REGFLAG_XR(n) (1 << (n)) + +/* register flags 1 */ +#define REGFLAG_PR (1 << 0) +#define REGFLAG_MACL (1 << 1) +#define REGFLAG_MACH (1 << 2) +#define REGFLAG_GBR (1 << 3) +#define REGFLAG_VBR (1 << 4) +#define REGFLAG_SR (1 << 5) +#define REGFLAG_SGR (1 << 6) +#define REGFLAG_FPUL (1 << 7) +#define REGFLAG_FPSCR (1 << 8) +#define REGFLAG_DBR (1 << 9) +#define REGFLAG_SSR (1 << 10) +#define REGFLAG_SPC (1 << 11) + + +#endif /* __SH4COMN_H__ */ diff --git a/src/devices/cpu/sh4/sh4dasm.c b/src/devices/cpu/sh4/sh4dasm.c new file mode 100644 index 00000000000..cba1bea7bd5 --- /dev/null +++ b/src/devices/cpu/sh4/sh4dasm.c @@ -0,0 +1,824 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +#include "emu.h" +#include "debugger.h" +#include "sh4.h" + +#define SIGNX8(x) (((INT32)(x) << 24) >> 24) +#define SIGNX12(x) (((INT32)(x) << 20) >> 20) + +#define Rn ((opcode >> 8) & 15) +#define Rm ((opcode >> 4) & 15) + +static const char *const regname[16] = { + "R0", "R1", "R2", "R3", "R4", "R5", "R6", "R7", + "R8", "R9", "R10","R11","R12","R13","R14","R15" +}; + +static UINT32 op0000(char *buffer, UINT32 pc, UINT16 opcode) +{ + UINT32 flags = 0; + switch (opcode & 0xF) + { + case 0x0: + case 0x1: + sprintf(buffer, "?????? $%04X", opcode); break; + case 0x2: + if (opcode & 0x80) { + sprintf(buffer,"STC %s_BANK,%s", regname[(Rm) & 7],regname[Rn]); + return flags; + } + switch (opcode & 0x70) + { + case 0x00: + sprintf(buffer,"STC SR,%s", regname[Rn]); break; + case 0x10: + sprintf(buffer,"STC GBR,%s", regname[Rn]); break; + case 0x20: + sprintf(buffer,"STC VBR,%s", regname[Rn]); break; + case 0x30: + sprintf(buffer,"STC SSR,%s", regname[Rn]); break; + case 0x40: + sprintf(buffer,"STC SPC,%s", regname[Rn]); break; + } + break; + case 0x3: + switch (opcode & 0xF0) + { + case 0x00: + sprintf(buffer,"BSRF %s", regname[Rn]); break; + case 0x20: + sprintf(buffer,"BRAF %s", regname[Rn]); break; + case 0x80: + sprintf(buffer,"PREF @%s", regname[Rn]); break; + case 0x90: + sprintf(buffer,"OCBI @%s", regname[Rn]); break; + case 0xA0: + sprintf(buffer,"OCBP @%s", regname[Rn]); break; + case 0xB0: + sprintf(buffer,"OCBWB @%s", regname[Rn]); break; + case 0xC0: + sprintf(buffer,"MOVCA.L R0,@%s", regname[Rn]); break; + } + break; + case 0x4: + sprintf(buffer, "MOV.B %s,@(R0,%s)", regname[Rm], regname[Rn]); break; + case 0x5: + sprintf(buffer, "MOV.W %s,@(R0,%s)", regname[Rm], regname[Rn]); break; + case 0x6: + sprintf(buffer, "MOV.L %s,@(R0,%s)", regname[Rm], regname[Rn]); break; + case 0x7: + sprintf(buffer, "MUL.L %s,%s", regname[Rm], regname[Rn]); break; + case 0x8: + switch (opcode & 0x70) + { + case 0x00: + sprintf(buffer,"CLRT"); break; + case 0x10: + sprintf(buffer,"SETT"); break; + case 0x20: + sprintf(buffer,"CLRMAC"); break; + case 0x30: + sprintf(buffer,"LDTLB"); break; + case 0x40: + sprintf(buffer,"CLRS"); break; + case 0x50: + sprintf(buffer,"SETS"); break; + } + break; + case 0x9: + switch (opcode & 0x30) + { + case 0x00: + sprintf(buffer,"NOP"); break; + case 0x10: + sprintf(buffer,"DIV0U"); break; + case 0x20: + sprintf(buffer,"MOVT %s", regname[Rn]); break; + } + break; + case 0xA: + switch (opcode & 0x70) + { + case 0x00: + sprintf(buffer,"STS MACH,%s", regname[Rn]); break; + case 0x10: + sprintf(buffer,"STS MACL,%s", regname[Rn]); break; + case 0x20: + sprintf(buffer,"STS PR,%s", regname[Rn]); break; + case 0x30: + sprintf(buffer,"STC SGR,%s", regname[Rn]); break; + case 0x50: + sprintf(buffer,"STS FPUL,%s", regname[Rn]); break; + case 0x60: + sprintf(buffer,"STS FPSCR,%s", regname[Rn]); break; + case 0x70: + sprintf(buffer,"STC DBR,%s", regname[Rn]); break; + } + break; + case 0xB: + switch (opcode & 0x30) + { + case 0x00: + sprintf(buffer,"RTS"); + flags = DASMFLAG_STEP_OUT; + break; + case 0x10: + sprintf(buffer,"SLEEP"); break; + case 0x20: + sprintf(buffer,"RTE"); + flags = DASMFLAG_STEP_OUT; + break; + } + break; + case 0xC: + sprintf(buffer, "MOV.B @(R0,%s),%s", regname[Rm], regname[Rn]); break; + case 0xD: + sprintf(buffer, "MOV.W @(R0,%s),%s", regname[Rm], regname[Rn]); break; + case 0xE: + sprintf(buffer, "MOV.L @(R0,%s),%s", regname[Rm], regname[Rn]); break; + case 0xF: + sprintf(buffer, "MAC.L @%s+,@%s+", regname[Rn], regname[Rm]); break; + } + return flags; +} + +static UINT32 op0001(char *buffer, UINT32 pc, UINT16 opcode) +{ + sprintf(buffer, "MOV.L %s,@($%02X,%s)", regname[Rm], (opcode & 15) * 4, regname[Rn]); + return 0; +} + +static UINT32 op0010(char *buffer, UINT32 pc, UINT16 opcode) +{ + switch (opcode & 15) + { + case 0: + sprintf(buffer, "MOV.B %s,@%s", regname[Rm], regname[Rn]); + break; + case 1: + sprintf(buffer, "MOV.W %s,@%s", regname[Rm], regname[Rn]); + break; + case 2: + sprintf(buffer, "MOV.L %s,@%s", regname[Rm], regname[Rn]); + break; + case 3: + sprintf(buffer, "?????? $%04X", opcode); + break; + case 4: + sprintf(buffer, "MOV.B %s,@-%s", regname[Rm], regname[Rn]); + break; + case 5: + sprintf(buffer, "MOV.W %s,@-%s", regname[Rm], regname[Rn]); + break; + case 6: + sprintf(buffer, "MOV.L %s,@-%s", regname[Rm], regname[Rn]); + break; + case 7: + sprintf(buffer, "DIV0S %s,%s", regname[Rm], regname[Rn]); + break; + case 8: + sprintf(buffer, "TST %s,%s", regname[Rm], regname[Rn]); + break; + case 9: + sprintf(buffer, "AND %s,%s", regname[Rm], regname[Rn]); + break; + case 10: + sprintf(buffer, "XOR %s,%s", regname[Rm], regname[Rn]); + break; + case 11: + sprintf(buffer, "OR %s,%s", regname[Rm], regname[Rn]); + break; + case 12: + sprintf(buffer, "CMP/STR %s,%s", regname[Rm], regname[Rn]); + break; + case 13: + sprintf(buffer, "XTRCT %s,%s", regname[Rm], regname[Rn]); + break; + case 14: + sprintf(buffer, "MULU.W %s,%s", regname[Rm], regname[Rn]); + break; + case 15: + sprintf(buffer, "MULS.W %s,%s", regname[Rm], regname[Rn]); + break; + } + return 0; +} + +static UINT32 op0011(char *buffer, UINT32 pc, UINT16 opcode) +{ + switch (opcode & 15) + { + case 0: + sprintf(buffer, "CMP/EQ %s,%s", regname[Rm], regname[Rn]); + break; + case 1: + sprintf(buffer, "?????? %s,%s", regname[Rm], regname[Rn]); + break; + case 2: + sprintf(buffer, "CMP/HS %s,%s", regname[Rm], regname[Rn]); + break; + case 3: + sprintf(buffer, "CMP/GE %s,%s", regname[Rm], regname[Rn]); + break; + case 4: + sprintf(buffer, "DIV1 %s,%s", regname[Rm], regname[Rn]); + break; + case 5: + sprintf(buffer, "DMULU.L %s,%s", regname[Rm], regname[Rn]); + break; + case 6: + sprintf(buffer, "CMP/HI %s,%s", regname[Rm], regname[Rn]); + break; + case 7: + sprintf(buffer, "CMP/GT %s,%s", regname[Rm], regname[Rn]); + break; + case 8: + sprintf(buffer, "SUB %s,%s", regname[Rm], regname[Rn]); + break; + case 9: + sprintf(buffer, "?????? %s,%s", regname[Rm], regname[Rn]); + break; + case 10: + sprintf(buffer, "SUBC %s,%s", regname[Rm], regname[Rn]); + break; + case 11: + sprintf(buffer, "SUBV %s,%s", regname[Rm], regname[Rn]); + break; + case 12: + sprintf(buffer, "ADD %s,%s", regname[Rm], regname[Rn]); + break; + case 13: + sprintf(buffer, "DMULS.L %s,%s", regname[Rm], regname[Rn]); + break; + case 14: + sprintf(buffer, "ADDC %s,%s", regname[Rm], regname[Rn]); + break; + case 15: + sprintf(buffer, "ADDV %s,%s", regname[Rm], regname[Rn]); + break; + } + return 0; +} + +static UINT32 op0100(char *buffer, UINT32 pc, UINT16 opcode) +{ + UINT32 flags = 0; + switch (opcode & 0xF) + { + case 0x0: + switch (opcode & 0x30) + { + case 0x00: + sprintf(buffer, "SHLL %s", regname[Rn]); break; + case 0x10: + sprintf(buffer, "DT %s", regname[Rn]); break; + case 0x20: + sprintf(buffer, "SHAL %s", regname[Rn]); break; + } + break; + case 0x1: + switch (opcode & 0x30) + { + case 0x00: + sprintf(buffer, "SHLR %s", regname[Rn]); break; + case 0x10: + sprintf(buffer, "CMP/PZ %s", regname[Rn]); break; + case 0x20: + sprintf(buffer, "SHAR %s", regname[Rn]); break; + } + break; + case 0x2: + switch (opcode & 0xF0) + { + case 0x00: + sprintf(buffer, "STS.L MACH,@-%s", regname[Rn]); break; + case 0x10: + sprintf(buffer, "STS.L MACL,@-%s", regname[Rn]); break; + case 0x20: + sprintf(buffer, "STS.L PR,@-%s", regname[Rn]); break; + case 0x30: + sprintf(buffer, "STC.L SGR,@-%s", regname[Rn]); break; + case 0x50: + sprintf(buffer, "STS.L FPUL,@-%s", regname[Rn]); break; + case 0x60: + sprintf(buffer, "STS.L FPSCR,@-%s", regname[Rn]); break; + case 0xF0: + sprintf(buffer, "STC.L DBR,@-%s", regname[Rn]); break; + } + break; + case 0x3: + if (opcode & 0x80) { + sprintf(buffer, "STC.L %s_BANK,@-%s", regname[(Rm) & 7],regname[Rn]); + return flags; + } + switch (opcode & 0x70) + { + case 0x00: + sprintf(buffer, "STC.L SR,@-%s", regname[Rn]); break; + case 0x10: + sprintf(buffer, "STC.L GBR,@-%s", regname[Rn]); break; + case 0x20: + sprintf(buffer, "STC.L VBR,@-%s", regname[Rn]); break; + case 0x30: + sprintf(buffer, "STC.L SSR,@-%s", regname[Rn]); break; + case 0x40: + sprintf(buffer, "STC.L SPC,@-%s", regname[Rn]); break; + } + break; + case 0x4: + switch (opcode & 0x30) + { + case 0x00: + sprintf(buffer, "ROTL %s", regname[Rn]); break; + case 0x20: + sprintf(buffer, "ROTCL %s", regname[Rn]); break; + } + break; + case 0x5: + switch (opcode & 0x30) + { + case 0x00: + sprintf(buffer, "ROTR %s", regname[Rn]); break; + case 0x10: + sprintf(buffer, "CMP/PL %s", regname[Rn]); break; + case 0x20: + sprintf(buffer, "ROTCR %s", regname[Rn]); break; + } + break; + case 0x6: + switch (opcode & 0xF0) + { + case 0x00: + sprintf(buffer, "LDS.L @%s+,MACH", regname[Rn]); break; + case 0x10: + sprintf(buffer, "LDS.L @%s+,MACL", regname[Rn]); break; + case 0x20: + sprintf(buffer, "LDS.L @%s+,PR", regname[Rn]); break; + case 0x50: + sprintf(buffer, "LDS.L @%s+,FPUL", regname[Rn]); break; + case 0x60: + sprintf(buffer, "LDS.L @%s+,FPSCR", regname[Rn]); break; + case 0xF0: + sprintf(buffer, "LDC.L @%s+,DBR", regname[Rn]); break; + } + break; + case 0x7: + if (opcode & 0x80) { + sprintf(buffer, "LDC.L @%s+,%s_BANK", regname[Rn],regname[(Rm) & 7]); + return flags; + } + switch (opcode & 0x70) + { + case 0x00: + sprintf(buffer, "LDC.L @%s+,SR", regname[Rn]); break; + case 0x10: + sprintf(buffer, "LDC.L @%s+,GBR", regname[Rn]); break; + case 0x20: + sprintf(buffer, "LDC.L @%s+,VBR", regname[Rn]); break; + case 0x30: + sprintf(buffer, "LDC.L @%s+,SSR", regname[Rn]); break; + case 0x40: + sprintf(buffer, "LDC.L @%s+,SPC", regname[Rn]); break; + } + break; + case 0x8: + switch (opcode & 0x30) + { + case 0x00: + sprintf(buffer, "SHLL2 %s", regname[Rn]); break; + case 0x10: + sprintf(buffer, "SHLL8 %s", regname[Rn]); break; + case 0x20: + sprintf(buffer, "SHLL16 %s", regname[Rn]); break; + } + break; + case 0x9: + switch (opcode & 0x30) + { + case 0x00: + sprintf(buffer, "SHLR2 %s", regname[Rn]); break; + case 0x10: + sprintf(buffer, "SHLR8 %s", regname[Rn]); break; + case 0x20: + sprintf(buffer, "SHLR16 %s", regname[Rn]); break; + } + break; + case 0xA: + switch (opcode & 0xF0) + { + case 0x00: + sprintf(buffer, "LDS %s,MACH", regname[Rn]); break; + case 0x10: + sprintf(buffer, "LDS %s,MACL", regname[Rn]); break; + case 0x20: + sprintf(buffer, "LDS %s,PR", regname[Rn]); break; + case 0x50: + sprintf(buffer, "LDS %s,FPUL", regname[Rn]); break; + case 0x60: + sprintf(buffer, "LDS %s,FPSCR", regname[Rn]); break; + case 0xF0: + sprintf(buffer, "LDC %s,DBR", regname[Rn]); break; + } + break; + case 0xB: + switch (opcode & 0x30) + { + case 0x00: + sprintf(buffer, "JSR %s", regname[Rn]); + flags = DASMFLAG_STEP_OVER | DASMFLAG_STEP_OVER_EXTRA(1); + break; + case 0x10: + sprintf(buffer, "TAS %s", regname[Rn]); break; + case 0x20: + sprintf(buffer, "JMP %s", regname[Rn]); break; + } + break; + case 0xC: + sprintf(buffer, "SHAD %s,%s", regname[Rm], regname[Rn]); break; + case 0xD: + sprintf(buffer, "SHLD %s,%s", regname[Rm], regname[Rn]); break; + case 0xE: + if (opcode & 0x80) { + sprintf(buffer, "LDC %s,%s_BANK", regname[Rn],regname[(Rm) & 7]); + return flags; + } + switch (opcode & 0x70) + { + case 0x00: + sprintf(buffer, "LDC %s,SR", regname[Rn]); break; + case 0x10: + sprintf(buffer, "LDC %s,GBR", regname[Rn]); break; + case 0x20: + sprintf(buffer, "LDC %s,VBR", regname[Rn]); break; + case 0x30: + sprintf(buffer, "LDC %s,SSR", regname[Rn]); break; + case 0x40: + sprintf(buffer, "LDC %s,SPC", regname[Rn]); break; + } + break; + case 0xF: + sprintf(buffer, "MAC.W @%s+,@%s+", regname[Rm], regname[Rn]); break; + } + return flags; +} + +static UINT32 op0101(char *buffer, UINT32 pc, UINT16 opcode) +{ + sprintf(buffer, "MOV.L @($%02X,%s),%s", (opcode & 15) * 4, regname[Rm], regname[Rn]); + return 0; +} + +static UINT32 op0110(char *buffer, UINT32 pc, UINT16 opcode) + +{ + switch(opcode & 0xF) + { + case 0x00: + sprintf(buffer, "MOV.B @%s,%s", regname[Rm], regname[Rn]); + break; + case 0x01: + sprintf(buffer, "MOV.W @%s,%s", regname[Rm], regname[Rn]); + break; + case 0x02: + sprintf(buffer, "MOV.L @%s,%s", regname[Rm], regname[Rn]); + break; + case 0x03: + sprintf(buffer, "MOV %s,%s", regname[Rm], regname[Rn]); + break; + case 0x04: + sprintf(buffer, "MOV.B @%s+,%s", regname[Rm], regname[Rn]); + break; + case 0x05: + sprintf(buffer, "MOV.W @%s+,%s", regname[Rm], regname[Rn]); + break; + case 0x06: + sprintf(buffer, "MOV.L @%s+,%s", regname[Rm], regname[Rn]); + break; + case 0x07: + sprintf(buffer, "NOT %s,%s", regname[Rm], regname[Rn]); + break; + case 0x08: + sprintf(buffer, "SWAP.B %s,%s", regname[Rm], regname[Rn]); + break; + case 0x09: + sprintf(buffer, "SWAP.W %s,%s", regname[Rm], regname[Rn]); + break; + case 0x0a: + sprintf(buffer, "NEGC %s,%s", regname[Rm], regname[Rn]); + break; + case 0x0b: + sprintf(buffer, "NEG %s,%s", regname[Rm], regname[Rn]); + break; + case 0x0c: + sprintf(buffer, "EXTU.B %s,%s", regname[Rm], regname[Rn]); + break; + case 0x0d: + sprintf(buffer, "EXTU.W %s,%s", regname[Rm], regname[Rn]); + break; + case 0x0e: + sprintf(buffer, "EXTS.B %s,%s", regname[Rm], regname[Rn]); + break; + case 0x0f: + sprintf(buffer, "EXTS.W %s,%s", regname[Rm], regname[Rn]); + break; + } + return 0; +} + +static UINT32 op0111(char *buffer, UINT32 pc, UINT16 opcode) +{ + sprintf(buffer, "ADD #$%02X,%s", opcode & 0xff, regname[Rn]); + return 0; +} + +static UINT32 op1000(char *buffer, UINT32 pc, UINT16 opcode) +{ + switch((opcode >> 8) & 15) + { + case 0: + sprintf(buffer, "MOV.B R0,@($%02X,%s)", (opcode & 15), regname[Rm]); + break; + case 1: + sprintf(buffer, "MOV.W R0,@($%02X,%s)", (opcode & 15) * 2, regname[Rm]); + break; + case 4: + sprintf(buffer, "MOV.B @($%02X,%s),R0", (opcode & 15), regname[Rm]); + break; + case 5: + sprintf(buffer, "MOV.W @($%02X,%s),R0", (opcode & 15) * 2, regname[Rm]); + break; + case 8: + sprintf(buffer, "CMP/EQ #$%02X,R0", (opcode & 0xff)); + break; + case 9: + sprintf(buffer, "BT $%08X", pc + SIGNX8(opcode & 0xff) * 2 + 2); + break; + case 11: + sprintf(buffer, "BF $%08X", pc + SIGNX8(opcode & 0xff) * 2 + 2); + break; + case 13: + sprintf(buffer, "BTS $%08X", pc + SIGNX8(opcode & 0xff) * 2 + 2); + break; + case 15: + sprintf(buffer, "BFS $%08X", pc + SIGNX8(opcode & 0xff) * 2 + 2); + break; + default : + sprintf(buffer, "invalid $%04X", opcode); + } + return 0; +} + +static UINT32 op1001(char *buffer, UINT32 pc, UINT16 opcode) +{ +UINT32 ea=(pc+((opcode & 0xff) * 2)+2); + + sprintf(buffer, "MOV.W @($%04X,PC),%s [%08X]", (opcode & 0xff) * 2, regname[Rn], ea); + return 0; +} + +static UINT32 op1010(char *buffer, UINT32 pc, UINT16 opcode) +{ + sprintf(buffer, "BRA $%08X", SIGNX12(opcode & 0xfff) * 2 + pc + 2); + return 0; +} + +static UINT32 op1011(char *buffer, UINT32 pc, UINT16 opcode) +{ + sprintf(buffer, "BSR $%08X", SIGNX12(opcode & 0xfff) * 2 + pc + 2); + return DASMFLAG_STEP_OVER | DASMFLAG_STEP_OVER_EXTRA(1); +} + +static UINT32 op1100(char *buffer, UINT32 pc, UINT16 opcode) +{ + UINT32 flags = 0; + switch((opcode >> 8) & 15) + { + case 0: + sprintf(buffer, "MOV.B R0,@($%02X,GBR)", opcode & 0xff); + break; + case 1: + sprintf(buffer, "MOV.W R0,@($%04X,GBR)", (opcode & 0xff) * 2); + break; + case 2: + sprintf(buffer, "MOV.L R0,@($%04X,GBR)", (opcode & 0xff) * 4); + break; + case 3: + sprintf(buffer, "TRAPA #$%02X", opcode & 0xff); + flags = DASMFLAG_STEP_OVER; + break; + case 4: + sprintf(buffer, "MOV.B @($%02X,GBR),R0", opcode & 0xff); + break; + case 5: + sprintf(buffer, "MOV.W @($%04X,GBR),R0", (opcode & 0xff) * 2); + break; + case 6: + sprintf(buffer, "MOV.L @($%04X,GBR),R0", (opcode & 0xff) * 4); + break; + case 7: + sprintf(buffer, "MOVA @($%04X,PC),R0 [%08X]", (opcode & 0xff) * 4, ((pc + 2) & ~3) + (opcode & 0xff) * 4); + break; + case 8: + sprintf(buffer, "TST #$%02X,R0", opcode & 0xff); + break; + case 9: + sprintf(buffer, "AND #$%02X,R0", opcode & 0xff); + break; + case 10: + sprintf(buffer, "XOR #$%02X,R0", opcode & 0xff); + break; + case 11: + sprintf(buffer, "OR #$%02X,R0", opcode & 0xff); + break; + case 12: + sprintf(buffer, "TST.B #$%02X,@(R0,GBR)", opcode & 0xff); + break; + case 13: + sprintf(buffer, "AND.B #$%02X,@(R0,GBR)", opcode & 0xff); + break; + case 14: + sprintf(buffer, "XOR.B #$%02X,@(R0,GBR)", opcode & 0xff); + break; + case 15: + sprintf(buffer, "OR.B #$%02X,@(R0,GBR)", opcode & 0xff); + break; + } + return flags; +} + +static UINT32 op1101(char *buffer, UINT32 pc, UINT16 opcode) +{ +UINT32 ea=((pc + 2) & ~3) + (opcode & 0xff) * 4; + + sprintf(buffer, "MOV.L @($%04X,PC),%s [%08X]", (opcode & 0xff) * 4, regname[Rn], ea); + return 0; +} + +static UINT32 op1110(char *buffer, UINT32 pc, UINT16 opcode) +{ + sprintf(buffer, "MOV #$%02X,%s", (opcode & 0xff), regname[Rn]); + return 0; +} + +static UINT32 op1111(char *buffer, UINT32 pc, UINT16 opcode) +{ + switch (opcode & 0xf) + { + case 0: + sprintf(buffer, "FADD F%s, F%s", regname[Rm], regname[Rn]); + break; + case 1: + sprintf(buffer, "FSUB F%s, F%s", regname[Rm], regname[Rn]); + break; + case 2: + sprintf(buffer, "FMUL F%s, F%s", regname[Rm], regname[Rn]); + break; + case 3: + sprintf(buffer, "FDIV F%s, F%s", regname[Rm], regname[Rn]); + break; + case 4: + sprintf(buffer, "FCMP/EQ F%s, F%s", regname[Rm], regname[Rn]); + break; + case 5: + sprintf(buffer, "FCMP/GT F%s, F%s", regname[Rm], regname[Rn]); + break; + case 6: + sprintf(buffer, "FMOV.S @(R0,%s),F%s", regname[Rm], regname[Rn]); + break; + case 7: + sprintf(buffer, "FMOV.S F%s, @(R0,%s)", regname[Rm], regname[Rn]); + break; + case 8: + sprintf(buffer, "FMOV.S @%s, F%s", regname[Rm], regname[Rn]); + break; + case 9: + sprintf(buffer, "FMOV.S @%s+, F%s", regname[Rm], regname[Rn]); + break; + case 10: + sprintf(buffer, "FMOV.S F%s, @%s", regname[Rm], regname[Rn]); + break; + case 11: + sprintf(buffer, "FMOV.S F%s, @-%s", regname[Rm], regname[Rn]); + break; + case 12: + sprintf(buffer, "FMOV.S F%s, F%s", regname[Rm], regname[Rn]); + break; + case 13: + switch (opcode & 0xF0) + { + case 0x00: + sprintf(buffer, "FSTS FPUL, F%s", regname[Rn]); + break; + case 0x10: + sprintf(buffer, "FLDS F%s, FPUL", regname[Rn]); + break; + case 0x20: + sprintf(buffer, "FLOAT FPUL, F%s", regname[Rn]); + break; + case 0x30: + sprintf(buffer, "FTRC F%s, FPUL", regname[Rn]); + break; + case 0x40: + sprintf(buffer, "FNEG F%s", regname[Rn]); + break; + case 0x50: + sprintf(buffer, "FABS F%s", regname[Rn]); + break; + case 0x60: + sprintf(buffer, "FSQRT F%s", regname[Rn]); + break; + case 0x70: + sprintf(buffer, "FSRRA F%s", regname[Rn]); + break; + case 0x80: + sprintf(buffer, "FLDI0 F%s", regname[Rn]); + break; + case 0x90: + sprintf(buffer, "FLDI1 F%s", regname[Rn]); + break; + case 0xA0: + sprintf(buffer, "FCNVSD FPUL, D%s", regname[Rn]); + break; + case 0xB0: + sprintf(buffer, "FCNVDS D%s, FPUL", regname[Rn]); + break; + case 0xE0: + sprintf(buffer, "FIPR FV%d, FV%d", (Rn & 3) << 2, Rn & 12); + break; + case 0xF0: + if (opcode & 0x100) { + if (opcode & 0x200) { + switch (opcode & 0xC00) + { + case 0x000: + sprintf(buffer, "FSCHG"); + break; + case 0x800: + sprintf(buffer, "FRCHG"); + break; + default: + sprintf(buffer, "Funknown $%04X", opcode); + break; + } + } else { + sprintf(buffer, "FTRV XMTRX, FV%d", Rn & 12); + } + } else { + sprintf(buffer, "FSCA FPUL, F%s", regname[Rn & 14]); + } + break; + default: + sprintf(buffer, "Funknown $%04X", opcode); + break; + } + break; + case 14: + sprintf(buffer, "FMAC FR0, F%s,F%s", regname[Rm], regname[Rn]); + break; + default: + sprintf(buffer, "Funknown $%04X", opcode); + break; + + } + + return 0; +} + +unsigned DasmSH4(char *buffer, unsigned pc, UINT16 opcode) +{ + UINT32 flags; + + pc += 2; + + switch((opcode >> 12) & 15) + { + case 0: flags = op0000(buffer,pc,opcode); break; + case 1: flags = op0001(buffer,pc,opcode); break; + case 2: flags = op0010(buffer,pc,opcode); break; + case 3: flags = op0011(buffer,pc,opcode); break; + case 4: flags = op0100(buffer,pc,opcode); break; + case 5: flags = op0101(buffer,pc,opcode); break; + case 6: flags = op0110(buffer,pc,opcode); break; + case 7: flags = op0111(buffer,pc,opcode); break; + case 8: flags = op1000(buffer,pc,opcode); break; + case 9: flags = op1001(buffer,pc,opcode); break; + case 10: flags = op1010(buffer,pc,opcode); break; + case 11: flags = op1011(buffer,pc,opcode); break; + case 12: flags = op1100(buffer,pc,opcode); break; + case 13: flags = op1101(buffer,pc,opcode); break; + case 14: flags = op1110(buffer,pc,opcode); break; + default: flags = op1111(buffer,pc,opcode); break; + } + return 2 | flags | DASMFLAG_SUPPORTED; +} + +CPU_DISASSEMBLE( sh4 ) +{ + return DasmSH4( buffer, pc, (oprom[1] << 8) | oprom[0] ); +} + +CPU_DISASSEMBLE( sh4be ) +{ + return DasmSH4( buffer, pc, (oprom[0] << 8) | oprom[1] ); +} diff --git a/src/devices/cpu/sh4/sh4dmac.c b/src/devices/cpu/sh4/sh4dmac.c new file mode 100644 index 00000000000..6d3fef194ba --- /dev/null +++ b/src/devices/cpu/sh4/sh4dmac.c @@ -0,0 +1,666 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/* SHA3/4 DMA Controller */ + +#include "emu.h" +#include "debugger.h" +#include "sh4.h" +#include "sh4comn.h" +#include "sh3comn.h" +#include "sh4dmac.h" + +static const int dmasize[8] = { 8, 1, 2, 4, 32, 0, 0, 0 }; + +static const int sh3_dmasize[4] = { 1, 2, 4, 16 }; + +TIMER_CALLBACK_MEMBER( sh34_base_device::sh4_dmac_callback ) +{ + int channel = param; + + LOG(("SH4 '%s': DMA %d complete\n", tag(), channel)); + m_dma_timer_active[channel] = 0; + switch (channel) + { + case 0: + m_SH4_DMATCR0 = 0; + m_SH4_CHCR0 |= CHCR_TE; + if (m_SH4_CHCR0 & CHCR_IE) + sh4_exception_request(SH4_INTC_DMTE0); + break; + case 1: + m_SH4_DMATCR1 = 0; + m_SH4_CHCR1 |= CHCR_TE; + if (m_SH4_CHCR1 & CHCR_IE) + sh4_exception_request(SH4_INTC_DMTE1); + break; + case 2: + m_SH4_DMATCR2 = 0; + m_SH4_CHCR2 |= CHCR_TE; + if (m_SH4_CHCR2 & CHCR_IE) + sh4_exception_request(SH4_INTC_DMTE2); + break; + case 3: + m_SH4_DMATCR3 = 0; + m_SH4_CHCR3 |= CHCR_TE; + if (m_SH4_CHCR3 & CHCR_IE) + sh4_exception_request(SH4_INTC_DMTE3); + break; + } +} + +int sh34_base_device::sh4_dma_transfer(int channel, int timermode, UINT32 chcr, UINT32 *sar, UINT32 *dar, UINT32 *dmatcr) +{ + int incs, incd, size; + UINT32 src, dst, count; + + incd = (chcr & CHCR_DM) >> 14; + incs = (chcr & CHCR_SM) >> 12; + + if (m_cpu_type == CPU_TYPE_SH4) + { + size = dmasize[(chcr & CHCR_TS) >> 4]; + } + else + { + size = sh3_dmasize[(chcr >> 3) & 3]; + } + + if(incd == 3 || incs == 3) + { + logerror("SH4: DMA: bad increment values (%d, %d, %d, %04x)\n", incd, incs, size, chcr); + return 0; + } + src = *sar; + dst = *dar; + count = *dmatcr; + if (!count) + count = 0x1000000; + + LOG(("SH4: DMA %d start %x, %x, %x, %04x, %d, %d, %d\n", channel, src, dst, count, chcr, incs, incd, size)); + + if (timermode == 1) // timer actvated after a time based on the number of words to transfer + { + m_dma_timer_active[channel] = 1; + m_dma_timer[channel]->adjust(cycles_to_attotime(2*count+1), channel); + } + else if (timermode == 2) // timer activated immediately + { + m_dma_timer_active[channel] = 1; + m_dma_timer[channel]->adjust(attotime::zero, channel); + } + + src &= AM; + dst &= AM; + + switch(size) + { + case 1: // 8 bit + for(;count > 0; count --) + { + if(incs == 2) + src --; + if(incd == 2) + dst --; + m_program->write_byte(dst, m_program->read_byte(src)); + if(incs == 1) + src ++; + if(incd == 1) + dst ++; + } + break; + case 2: // 16 bit + src &= ~1; + dst &= ~1; + for(;count > 0; count --) + { + if(incs == 2) + src -= 2; + if(incd == 2) + dst -= 2; + m_program->write_word(dst, m_program->read_word(src)); + if(incs == 1) + src += 2; + if(incd == 1) + dst += 2; + } + break; + case 8: // 64 bit + src &= ~7; + dst &= ~7; + for(;count > 0; count --) + { + if(incs == 2) + src -= 8; + if(incd == 2) + dst -= 8; + m_program->write_qword(dst, m_program->read_qword(src)); + if(incs == 1) + src += 8; + if(incd == 1) + dst += 8; + + } + break; + case 4: // 32 bit + src &= ~3; + dst &= ~3; + for(;count > 0; count --) + { + if(incs == 2) + src -= 4; + if(incd == 2) + dst -= 4; + m_program->write_dword(dst, m_program->read_dword(src)); + if(incs == 1) + src += 4; + if(incd == 1) + dst += 4; + + } + break; + case 32: + src &= ~31; + dst &= ~31; + for(;count > 0; count --) + { + if(incs == 2) + src -= 32; + if(incd == 2) + dst -= 32; + m_program->write_qword(dst, m_program->read_qword(src)); + m_program->write_qword(dst+8, m_program->read_qword(src+8)); + m_program->write_qword(dst+16, m_program->read_qword(src+16)); + m_program->write_qword(dst+24, m_program->read_qword(src+24)); + if(incs == 1) + src += 32; + if(incd == 1) + dst += 32; + } + break; + } + *sar = (*sar & !AM) | src; + *dar = (*dar & !AM) | dst; + *dmatcr = count; + return 1; +} + +int sh34_base_device::sh4_dma_transfer_device(int channel, UINT32 chcr, UINT32 *sar, UINT32 *dar, UINT32 *dmatcr) +{ + int incs, incd, size, mod; + UINT32 src, dst, count; + + incd = (chcr & CHCR_DM) >> 14; + incs = (chcr & CHCR_SM) >> 12; + + + if (m_cpu_type == CPU_TYPE_SH4) + { + size = dmasize[(chcr & CHCR_TS) >> 4]; + } + else + { + size = sh3_dmasize[(chcr >> 3) & 3]; + } + + mod = ((chcr & CHCR_RS) >> 8); + if (incd == 3 || incs == 3) + { + logerror("SH4: DMA: bad increment values (%d, %d, %d, %04x)\n", incd, incs, size, chcr); + return 0; + } + src = *sar; + dst = *dar; + count = *dmatcr; + if (!count) + count = 0x1000000; + + LOG(("SH4: DMA %d start device<->memory %x, %x, %x, %04x, %d, %d, %d\n", channel, src, dst, count, chcr, incs, incd, size)); + + m_dma_timer_active[channel] = 1; + + src &= AM; + dst &= AM; + + // remember parameters + m_dma_source[channel]=src; + m_dma_destination[channel]=dst; + m_dma_count[channel]=count; + m_dma_wordsize[channel]=size; + m_dma_source_increment[channel]=incs; + m_dma_destination_increment[channel]=incd; + m_dma_mode[channel]=mod; + + // inform device its ready to transfer + m_io->write_dword(SH4_IOPORT_DMA, channel | (mod << 16)); + return 1; +} + +void sh34_base_device::sh4_dmac_check(int channel) +{ + UINT32 dmatcr, chcr, sar, dar; + + switch (channel) + { + case 0: + sar = m_SH4_SAR0; + dar = m_SH4_DAR0; + chcr = m_SH4_CHCR0; + dmatcr = m_SH4_DMATCR0; + break; + case 1: + sar = m_SH4_SAR1; + dar = m_SH4_DAR1; + chcr = m_SH4_CHCR1; + dmatcr = m_SH4_DMATCR1; + break; + case 2: + sar = m_SH4_SAR2; + dar = m_SH4_DAR2; + chcr = m_SH4_CHCR2; + dmatcr = m_SH4_DMATCR2; + break; + case 3: + sar = m_SH4_SAR3; + dar = m_SH4_DAR3; + chcr = m_SH4_CHCR3; + dmatcr = m_SH4_DMATCR3; + break; + default: + return; + } + if (chcr & m_SH4_DMAOR & DMAOR_DME) + { + if ((((chcr & CHCR_RS) >> 8) < 2) || (((chcr & CHCR_RS) >> 8) > 6)) + return; + if (!m_dma_timer_active[channel] && !(chcr & CHCR_TE) && !(m_SH4_DMAOR & (DMAOR_AE | DMAOR_NMIF))) + { + if (((chcr & CHCR_RS) >> 8) > 3) + sh4_dma_transfer(channel, 1, chcr, &sar, &dar, &dmatcr); + else if ((m_SH4_DMAOR & DMAOR_DDT) == 0) + sh4_dma_transfer_device(channel, chcr, &sar, &dar, &dmatcr); // tell device we are ready to transfer + } + } + else + { + if (m_dma_timer_active[channel]) + { + logerror("SH4: DMA %d cancelled in-flight but all data transferred", channel); + m_dma_timer[channel]->adjust(attotime::never, channel); + m_dma_timer_active[channel] = 0; + } + } +} + + +// called by drivers to transfer data in a cpu<->device dma. 'device' must be a SH4 cpu +int sh34_base_device::sh4_dma_data(struct sh4_device_dma *s) +{ + UINT32 pos, len, siz; + int channel = s->channel; + void *data = s->buffer; + + if (!m_dma_timer_active[channel]) + return 0; + + if (m_dma_mode[channel] == 2) + { + // device receives data + len = m_dma_count[channel]; + if (s->length < len) + len = s->length; + siz = m_dma_wordsize[channel]; + for (pos = 0;pos < len;pos++) { + switch (siz) + { + case 8: + if (m_dma_source_increment[channel] == 2) + m_dma_source[channel] -= 8; + *(UINT64 *)data = m_program->read_qword(m_dma_source[channel] & ~7); + if (m_dma_source_increment[channel] == 1) + m_dma_source[channel] += 8; + break; + case 1: + if (m_dma_source_increment[channel] == 2) + m_dma_source[channel]--; + *(UINT8 *)data = m_program->read_byte(m_dma_source[channel]); + if (m_dma_source_increment[channel] == 1) + m_dma_source[channel]++; + break; + case 2: + if (m_dma_source_increment[channel] == 2) + m_dma_source[channel] -= 2; + *(UINT16 *)data = m_program->read_word(m_dma_source[channel] & ~1); + if (m_dma_source_increment[channel] == 1) + m_dma_source[channel] += 2; + break; + case 4: + if (m_dma_source_increment[channel] == 2) + m_dma_source[channel] -= 4; + *(UINT32 *)data = m_program->read_dword(m_dma_source[channel] & ~3); + if (m_dma_source_increment[channel] == 1) + m_dma_source[channel] += 4; + break; + case 32: + if (m_dma_source_increment[channel] == 2) + m_dma_source[channel] -= 32; + *(UINT64 *)data = m_program->read_qword(m_dma_source[channel] & ~31); + *((UINT64 *)data+1) = m_program->read_qword((m_dma_source[channel] & ~31)+8); + *((UINT64 *)data+2) = m_program->read_qword((m_dma_source[channel] & ~31)+16); + *((UINT64 *)data+3) = m_program->read_qword((m_dma_source[channel] & ~31)+24); + if (m_dma_source_increment[channel] == 1) + m_dma_source[channel] += 32; + break; + } + m_dma_count[channel]--; + } + if (m_dma_count[channel] == 0) // all data transferred ? + { + m_dma_timer[channel]->adjust(attotime::zero, channel); + return 2; + } + return 1; + } + else if (m_dma_mode[channel] == 3) + { + // device sends data + len = m_dma_count[channel]; + if (s->length < len) + len = s->length; + siz = m_dma_wordsize[channel]; + for (pos = 0;pos < len;pos++) { + switch (siz) + { + case 8: + if (m_dma_destination_increment[channel] == 2) + m_dma_destination[channel]-=8; + m_program->write_qword(m_dma_destination[channel] & ~7, *(UINT64 *)data); + if (m_dma_destination_increment[channel] == 1) + m_dma_destination[channel]+=8; + break; + case 1: + if (m_dma_destination_increment[channel] == 2) + m_dma_destination[channel]--; + m_program->write_byte(m_dma_destination[channel], *(UINT8 *)data); + if (m_dma_destination_increment[channel] == 1) + m_dma_destination[channel]++; + break; + case 2: + if (m_dma_destination_increment[channel] == 2) + m_dma_destination[channel]-=2; + m_program->write_word(m_dma_destination[channel] & ~1, *(UINT16 *)data); + if (m_dma_destination_increment[channel] == 1) + m_dma_destination[channel]+=2; + break; + case 4: + if (m_dma_destination_increment[channel] == 2) + m_dma_destination[channel]-=4; + m_program->write_dword(m_dma_destination[channel] & ~3, *(UINT32 *)data); + if (m_dma_destination_increment[channel] == 1) + m_dma_destination[channel]+=4; + break; + case 32: + if (m_dma_destination_increment[channel] == 2) + m_dma_destination[channel]-=32; + m_program->write_qword(m_dma_destination[channel] & ~31, *(UINT64 *)data); + m_program->write_qword((m_dma_destination[channel] & ~31)+8, *((UINT64 *)data+1)); + m_program->write_qword((m_dma_destination[channel] & ~31)+16, *((UINT64 *)data+2)); + m_program->write_qword((m_dma_destination[channel] & ~31)+24, *((UINT64 *)data+3)); + if (m_dma_destination_increment[channel] == 1) + m_dma_destination[channel]+=32; + break; + } + m_dma_count[channel]--; + } + + if (m_dma_count[channel] == 0) // all data transferred ? + { + m_dma_timer[channel]->adjust(attotime::zero, channel); + return 2; + } + return 1; + } + else + return 0; +} + +// called by drivers to transfer data in a DDT dma. +void sh34_base_device::sh4_dma_ddt(struct sh4_ddt_dma *s) +{ + UINT32 chcr; + UINT32 *p32bits; + UINT64 *p32bytes; + UINT32 pos,len,siz; + + if (m_cpu_type != CPU_TYPE_SH4) + fatalerror("sh4_dma_ddt uses m_m[] with SH3\n"); + + if (m_dma_timer_active[s->channel]) + return; + if (s->mode >= 0) { + switch (s->channel) + { + case 0: + if (s->mode & 1) + s->source = m_SH4_SAR0; + if (s->mode & 2) + m_SH4_SAR0 = s->source; + if (s->mode & 4) + s->destination = m_SH4_DAR0; + if (s->mode & 8) + m_SH4_DAR0 = s->destination; + break; + case 1: + if (s->mode & 1) + s->source = m_SH4_SAR1; + if (s->mode & 2) + m_SH4_SAR1 = s->source; + if (s->mode & 4) + s->destination = m_SH4_DAR1; + if (s->mode & 8) + m_SH4_DAR1 = s->destination; + break; + case 2: + if (s->mode & 1) + s->source = m_SH4_SAR2; + if (s->mode & 2) + m_SH4_SAR2 = s->source; + if (s->mode & 4) + s->destination = m_SH4_DAR2; + if (s->mode & 8) + m_SH4_DAR2 = s->destination; + break; + case 3: + default: + if (s->mode & 1) + s->source = m_SH4_SAR3; + if (s->mode & 2) + m_SH4_SAR3 = s->source; + if (s->mode & 4) + s->destination = m_SH4_DAR3; + if (s->mode & 8) + m_SH4_DAR3 = s->destination; + break; + } + switch (s->channel) + { + case 0: + chcr = m_SH4_CHCR0; + len = m_SH4_DMATCR0; + break; + case 1: + chcr = m_SH4_CHCR1; + len = m_SH4_DMATCR1; + break; + case 2: + chcr = m_SH4_CHCR2; + len = m_SH4_DMATCR2; + break; + case 3: + default: + chcr = m_SH4_CHCR3; + len = m_SH4_DMATCR3; + break; + } + if ((s->direction) == 0) { + chcr = (chcr & 0xffff3fff) | ((s->mode & 0x30) << 10); + } else { + chcr = (chcr & 0xffffcfff) | ((s->mode & 0x30) << 8); + } + + + if (m_cpu_type == CPU_TYPE_SH4) + { + //siz = dmasize[(chcr & CHCR_TS) >> 4]; + siz = dmasize[(chcr >> 4) & 7]; + } + else + { + siz = sh3_dmasize[(chcr >> 3) & 3]; + } + + + if (siz && (s->size)) + if ((len * siz) != (s->length * s->size)) + return; + sh4_dma_transfer(s->channel, 0, chcr, &s->source, &s->destination, &len); + } else { + if (s->size == 4) { + if ((s->direction) == 0) { + len = s->length; + p32bits = (UINT32 *)(s->buffer); + for (pos = 0;pos < len;pos++) { + *p32bits = m_program->read_dword(s->source); + p32bits++; + s->source = s->source + 4; + } + } else { + len = s->length; + p32bits = (UINT32 *)(s->buffer); + for (pos = 0;pos < len;pos++) { + m_program->write_dword(s->destination, *p32bits); + p32bits++; + s->destination = s->destination + 4; + } + } + } + if (s->size == 32) { + if ((s->direction) == 0) { + len = s->length * 4; + p32bytes = (UINT64 *)(s->buffer); + for (pos = 0;pos < len;pos++) { + *p32bytes = m_program->read_qword(s->source); + p32bytes++; + s->destination = s->destination + 8; + } + } else { + len = s->length * 4; + p32bytes = (UINT64 *)(s->buffer); + for (pos = 0;pos < len;pos++) { + m_program->write_qword(s->destination, *p32bytes); + p32bytes++; + s->destination = s->destination + 8; + } + } + } + } +} + + + void sh34_base_device::sh4_handle_sar0_addr_w(UINT32 data, UINT32 mem_mask) +{ + COMBINE_DATA(&m_SH4_SAR0); +} + + void sh34_base_device::sh4_handle_sar1_addr_w(UINT32 data, UINT32 mem_mask) +{ + COMBINE_DATA(&m_SH4_SAR1); +} + + void sh34_base_device::sh4_handle_sar2_addr_w(UINT32 data, UINT32 mem_mask) +{ + COMBINE_DATA(&m_SH4_SAR2); +} + + void sh34_base_device::sh4_handle_sar3_addr_w(UINT32 data, UINT32 mem_mask) +{ + COMBINE_DATA(&m_SH4_SAR3); +} + + void sh34_base_device::sh4_handle_dar0_addr_w(UINT32 data, UINT32 mem_mask) +{ + COMBINE_DATA(&m_SH4_DAR0); +} + + void sh34_base_device::sh4_handle_dar1_addr_w(UINT32 data, UINT32 mem_mask) +{ + COMBINE_DATA(&m_SH4_DAR1); +} + + void sh34_base_device::sh4_handle_dar2_addr_w(UINT32 data, UINT32 mem_mask) +{ + COMBINE_DATA(&m_SH4_DAR2); +} + + void sh34_base_device::sh4_handle_dar3_addr_w(UINT32 data, UINT32 mem_mask) +{ + COMBINE_DATA(&m_SH4_DAR3); +} + + void sh34_base_device::sh4_handle_dmatcr0_addr_w(UINT32 data, UINT32 mem_mask) +{ + COMBINE_DATA(&m_SH4_DMATCR0); +} + + void sh34_base_device::sh4_handle_dmatcr1_addr_w(UINT32 data, UINT32 mem_mask) +{ + COMBINE_DATA(&m_SH4_DMATCR1); +} + + void sh34_base_device::sh4_handle_dmatcr2_addr_w(UINT32 data, UINT32 mem_mask) +{ + COMBINE_DATA(&m_SH4_DMATCR2); +} + + void sh34_base_device::sh4_handle_dmatcr3_addr_w(UINT32 data, UINT32 mem_mask) +{ + COMBINE_DATA(&m_SH4_DMATCR3); +} + + void sh34_base_device::sh4_handle_chcr0_addr_w(UINT32 data, UINT32 mem_mask) +{ + COMBINE_DATA(&m_SH4_CHCR0); + sh4_dmac_check(0); +} + + void sh34_base_device::sh4_handle_chcr1_addr_w(UINT32 data, UINT32 mem_mask) +{ + COMBINE_DATA(&m_SH4_CHCR1); + sh4_dmac_check(1); +} + + void sh34_base_device::sh4_handle_chcr2_addr_w(UINT32 data, UINT32 mem_mask) +{ + COMBINE_DATA(&m_SH4_CHCR2); + sh4_dmac_check(2); +} + + void sh34_base_device::sh4_handle_chcr3_addr_w(UINT32 data, UINT32 mem_mask) +{ + COMBINE_DATA(&m_SH4_CHCR3); + sh4_dmac_check(3); +} + + void sh34_base_device::sh4_handle_dmaor_addr_w(UINT32 data, UINT32 mem_mask) +{ + UINT32 old = m_SH4_DMAOR; + COMBINE_DATA(&m_SH4_DMAOR); + + if ((m_SH4_DMAOR & DMAOR_AE) && (~old & DMAOR_AE)) + m_SH4_DMAOR &= ~DMAOR_AE; + if ((m_SH4_DMAOR & DMAOR_NMIF) && (~old & DMAOR_NMIF)) + m_SH4_DMAOR &= ~DMAOR_NMIF; + sh4_dmac_check(0); + sh4_dmac_check(1); + sh4_dmac_check(2); + sh4_dmac_check(3); +} diff --git a/src/devices/cpu/sh4/sh4dmac.h b/src/devices/cpu/sh4/sh4dmac.h new file mode 100644 index 00000000000..60148653c2b --- /dev/null +++ b/src/devices/cpu/sh4/sh4dmac.h @@ -0,0 +1,65 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/* SHA3/4 DMA Controller */ + +/* bit definitions */ +#define CHCR_SSA 0xe0000000 +#define CHCR_STC 0x10000000 +#define CHCR_DSA 0x0e000000 +#define CHCR_DTC 0x01000000 +#define CHCR_DS 0x00080000 +#define CHCR_RL 0x00040000 +#define CHCR_AM 0x00020000 +#define CHCR_AL 0x00010000 +#define CHCR_DM 0x0000c000 +#define CHCR_SM 0x00003000 +#define CHCR_RS 0x00000f00 +#define CHCR_TM 0x00000080 +#define CHCR_TS 0x00000070 +#define CHCR_IE 0x00000004 +#define CHCR_TE 0x00000002 +#define CHCR_DE 0x00000001 + +#define DMAOR_DDT 0x8000 +#define DMAOR_PR 0x0300 +#define DMAOR_COD 0x0010 +#define DMAOR_AE 0x0004 +#define DMAOR_NMIF 0x0002 +#define DMAOR_DME 0x0001 + +TIMER_CALLBACK( sh4_dmac_callback ); + +void sh4_handle_sar0_addr_w(UINT32 data, UINT32 mem_mask); +void sh4_handle_sar1_addr_w(UINT32 data, UINT32 mem_mask); +void sh4_handle_sar2_addr_w(UINT32 data, UINT32 mem_mask); +void sh4_handle_sar3_addr_w(UINT32 data, UINT32 mem_mask); +void sh4_handle_dar0_addr_w(UINT32 data, UINT32 mem_mask); +void sh4_handle_dar1_addr_w(UINT32 data, UINT32 mem_mask); +void sh4_handle_dar2_addr_w(UINT32 data, UINT32 mem_mask); +void sh4_handle_dar3_addr_w(UINT32 data, UINT32 mem_mask); +void sh4_handle_dmatcr0_addr_w(UINT32 data, UINT32 mem_mask); +void sh4_handle_dmatcr1_addr_w(UINT32 data, UINT32 mem_mask); +void sh4_handle_dmatcr2_addr_w(UINT32 data, UINT32 mem_mask); +void sh4_handle_dmatcr3_addr_w(UINT32 data, UINT32 mem_mask); +void sh4_handle_chcr0_addr_w(UINT32 data, UINT32 mem_mask); +void sh4_handle_chcr1_addr_w(UINT32 data, UINT32 mem_mask); +void sh4_handle_chcr2_addr_w(UINT32 data, UINT32 mem_mask); +void sh4_handle_chcr3_addr_w(UINT32 data, UINT32 mem_mask); +void sh4_handle_dmaor_addr_w(UINT32 data, UINT32 mem_mask); +UINT32 sh4_handle_sar0_addr_r(UINT32 mem_mask); +UINT32 sh4_handle_sar1_addr_r(UINT32 mem_mask); +UINT32 sh4_handle_sar2_addr_r(UINT32 mem_mask); +UINT32 sh4_handle_sar3_addr_r(UINT32 mem_mask); +UINT32 sh4_handle_dar0_addr_r(UINT32 mem_mask); +UINT32 sh4_handle_dar1_addr_r(UINT32 mem_mask); +UINT32 sh4_handle_dar2_addr_r(UINT32 mem_mask); +UINT32 sh4_handle_dar3_addr_r(UINT32 mem_mask); +UINT32 sh4_handle_dmatcr0_addr_r(UINT32 mem_mask); +UINT32 sh4_handle_dmatcr1_addr_r(UINT32 mem_mask); +UINT32 sh4_handle_dmatcr2_addr_r(UINT32 mem_mask); +UINT32 sh4_handle_dmatcr3_addr_r(UINT32 mem_mask); +UINT32 sh4_handle_chcr0_addr_r(UINT32 mem_mask); +UINT32 sh4_handle_chcr1_addr_r(UINT32 mem_mask); +UINT32 sh4_handle_chcr2_addr_r(UINT32 mem_mask); +UINT32 sh4_handle_chcr3_addr_r(UINT32 mem_mask); +UINT32 sh4_handle_dmaor_addr_r(UINT32 mem_mask); diff --git a/src/devices/cpu/sh4/sh4regs.h b/src/devices/cpu/sh4/sh4regs.h new file mode 100644 index 00000000000..384f062858e --- /dev/null +++ b/src/devices/cpu/sh4/sh4regs.h @@ -0,0 +1,183 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +#pragma once + +#ifndef __SH4REGS_H__ +#define __SH4REGS_H__ + +/* 00000001111111100000000011111100 */ +#define PTEH 0x2000 /* FF000000 */ +#define PTEL 0x2001 /* FF000004 */ +#define TTB 0x2002 /* FF000008 */ +#define TEA 0x2003 /* FF00000C */ +#define MMUCR 0x2004 /* FF000010 */ +#define BASRA 0x2005 /* FF000014 */ +#define BASRB 0x2006 /* FF000018 */ +#define CCR 0x2007 /* FF00001C */ +#define TRA 0x2008 /* FF000020 */ +#define EXPEVT 0x2009 /* FF000024 */ +#define INTEVT 0x200A /* FF000028 */ +#define VERSION 0x200C /* FF000030 */ +#define PTEA 0x200D /* FF000034 */ +#define QACR0 0x200E /* FF000038 */ +#define QACR1 0x200F /* FF00003C */ +#define PRR 0x2011 /* FF000044 */ +#define BARA 0x2400 /* FF200000 */ +#define BAMRA 0x2401 /* FF200004 */ +#define BBRA 0x2402 /* FF200008 */ +#define BARB 0x2403 /* FF20000C */ +#define BAMRB 0x2404 /* FF200010 */ +#define BBRB 0x2405 /* FF200014 */ +#define BDRB 0x2406 /* FF200018 */ +#define BDMRB 0x2407 /* FF20001C */ +#define BRCR 0x2408 /* FF200020 */ +#define BCR1 0x3000 /* FF800000 */ +#define BCR2 0x3001 /* FF800004 */ +#define BCR3 0x3014 /* FF800050 */ +#define BCR4 0x17C /* FE0A00F0 */ +#define WCR1 0x3002 /* FF800008 */ +#define WCR2 0x3003 /* FF80000C */ +#define WCR3 0x3004 /* FF800010 */ +#define MCR 0x3005 /* FF800014 */ +#define PCR 0x3006 /* FF800018 */ +#define RTCSR 0x3007 /* FF80001C */ +#define RTCNT 0x3008 /* FF800020 */ +#define RTCOR 0x3009 /* FF800024 */ +#define RFCR 0x300A /* FF800028 */ +#define PCTRA 0x300B /* FF80002C */ +#define PDTRA 0x300C /* FF800030 */ +#define PCTRB 0x3010 /* FF800040 */ +#define PDTRB 0x3011 /* FF800044 */ +#define GPIOIC 0x3012 /* FF800048 */ +#define SDMR2 0x3200 /* FF900000 */ +#define SDMR3 0x3280 /* FF940000 */ +#define SH4_SAR0_ADDR 0x3400 /* FFA00000 */ +#define SH4_DAR0_ADDR 0x3401 /* FFA00004 */ +#define SH4_DMATCR0_ADDR 0x3402 /* FFA00008 */ +#define SH4_CHCR0_ADDR 0x3403 /* FFA0000C */ +#define SH4_SAR1_ADDR 0x3404 /* FFA00010 */ +#define SH4_DAR1_ADDR 0x3405 /* FFA00014 */ +#define SH4_DMATCR1_ADDR 0x3406 /* FFA00018 */ +#define SH4_CHCR1_ADDR 0x3407 /* FFA0001C */ +#define SH4_SAR2_ADDR 0x3408 /* FFA00020 */ +#define SH4_DAR2_ADDR 0x3409 /* FFA00024 */ +#define SH4_DMATCR2_ADDR 0x340A /* FFA00028 */ +#define SH4_CHCR2_ADDR 0x340B /* FFA0002C */ +#define SH4_SAR3_ADDR 0x340C /* FFA00030 */ +#define SH4_DAR3_ADDR 0x340D /* FFA00034 */ +#define SH4_DMATCR3_ADDR 0x340E /* FFA00038 */ +#define SH4_CHCR3_ADDR 0x340F /* FFA0003C */ +#define SH4_DMAOR_ADDR 0x3410 /* FFA00040 */ +#define SAR4 0x3414 /* FFA00050 */ +#define DAR4 0x3415 /* FFA00054 */ +#define DMATCR4 0x3416 /* FFA00058 */ +#define CHCR4 0x3417 /* FFA0005C */ +#define SAR5 0x3418 /* FFA00060 */ +#define DAR5 0x3419 /* FFA00064 */ +#define DMATCR5 0x341A /* FFA00068 */ +#define CHCR5 0x341B /* FFA0006C */ +#define SAR6 0x341C /* FFA00070 */ +#define DAR6 0x341D /* FFA00074 */ +#define DMATCR6 0x341E /* FFA00078 */ +#define CHCR6 0x341F /* FFA0007C */ +#define SAR7 0x3420 /* FFA00080 */ +#define DAR7 0x3421 /* FFA00084 */ +#define DMATCR7 0x3422 /* FFA00088 */ +#define CHCR7 0x3423 /* FFA0008C */ +#define FRQCR 0x3800 /* FFC00000 */ +#define STBCR 0x3801 /* FFC00004 */ +#define WTCNT 0x3802 /* FFC00008 */ +#define WTCSR 0x3803 /* FFC0000C */ +#define STBCR2 0x3804 /* FFC00010 */ +#define R64CNT 0x3900 /* FFC80000 */ +#define RSECCNT 0x3901 /* FFC80004 */ +#define RMINCNT 0x3902 /* FFC80008 */ +#define RHRCNT 0x3903 /* FFC8000C */ +#define RWKCNT 0x3904 /* FFC80010 */ +#define RDAYCNT 0x3905 /* FFC80014 */ +#define RMONCNT 0x3906 /* FFC80018 */ +#define RYRCNT 0x3907 /* FFC8001C */ +#define RSECAR 0x3908 /* FFC80020 */ +#define RMINAR 0x3909 /* FFC80024 */ +#define RHRAR 0x390A /* FFC80028 */ +#define RWKAR 0x390B /* FFC8002C */ +#define RDAYAR 0x390C /* FFC80030 */ +#define RMONAR 0x390D /* FFC80034 */ +#define RCR1 0x390E /* FFC80038 */ +#define RCR2 0x390F /* FFC8003C */ +#define RCR3 0x3914 /* FFC80050 */ +#define RYRAR 0x3915 /* FFC80054 */ +#define ICR 0x3A00 /* FFD00000 */ +#define IPRA 0x3A01 /* FFD00004 */ +#define IPRB 0x3A02 /* FFD00008 */ +#define IPRC 0x3A03 /* FFD0000C */ +#define IPRD 0x3A04 /* FFD00010 */ +#define INTPRI00 0x100 /* FE080000 */ +#define INTREQ00 0x108 /* FE080020 */ +#define INTMSK00 0x110 /* FE080040 */ +#define INTMSKCLR00 0x118 /* FE080060 */ +#define CLKSTP00 0x140 /* FE0A0000 */ +#define CLKSTPCLR00 0x142 /* FE0A0008 */ +#define TSTR2 0x201 /* FE100004 */ +#define TCOR3 0x202 /* FE100008 */ +#define TCNT3 0x203 /* FE10000C */ +#define TCR3 0x204 /* FE100010 */ +#define TCOR4 0x205 /* FE100014 */ +#define TCNT4 0x206 /* FE100018 */ +#define TCR4 0x207 /* FE10001C */ +#define SH4_TOCR_ADDR 0x3B00 /* FFD80000 */ +#define SH4_TSTR_ADDR 0x3B01 /* FFD80004 */ +#define SH4_TCOR0_ADDR 0x3B02 /* FFD80008 */ +#define SH4_TCNT0_ADDR 0x3B03 /* FFD8000C */ +#define SH4_TCR0_ADDR 0x3B04 /* FFD80010 */ +#define SH4_TCOR1_ADDR 0x3B05 /* FFD80014 */ +#define SH4_TCNT1_ADDR 0x3B06 /* FFD80018 */ +#define SH4_TCR1_ADDR 0x3B07 /* FFD8001C */ +#define SH4_TCOR2_ADDR 0x3B08 /* FFD80020 */ +#define SH4_TCNT2_ADDR 0x3B09 /* FFD80024 */ +#define SH4_TCR2_ADDR 0x3B0A /* FFD80028 */ +#define SH4_TCPR2_ADDR 0x3B0B /* FFD8002C */ +#define SCSMR1 0x3C00 /* FFE00000 */ +#define SCBRR1 0x3C01 /* FFE00004 */ +#define SCSCR1 0x3C02 /* FFE00008 */ +#define SCTDR1 0x3C03 /* FFE0000C */ +#define SCSSR1 0x3C04 /* FFE00010 */ +#define SCRDR1 0x3C05 /* FFE00014 */ +#define SCSCMR1 0x3C06 /* FFE00018 */ +#define SCSPTR1 0x3C07 /* FFE0001C */ +#define SCSMR2 0x3D00 /* FFE80000 */ +#define SCBRR2 0x3D01 /* FFE80004 */ +#define SCSCR2 0x3D02 /* FFE80008 */ +#define SCFTDR2 0x3D03 /* FFE8000C */ +#define SCFSR2 0x3D04 /* FFE80010 */ +#define SCFRDR2 0x3D05 /* FFE80014 */ +#define SCFCR2 0x3D06 /* FFE80018 */ +#define SCFDR2 0x3D07 /* FFE8001C */ +#define SCSPTR2 0x3D08 /* FFE80020 */ +#define SCLSR2 0x3D09 /* FFE80024 */ +#define SDIR 0x3E00 /* FFF00000 */ +#define SDDR 0x3E02 /* FFF00008 */ +#define SDINT 0x3E05 /* FFF00014 */ +#define SIZEREGS 15878 + + + +#define MMUCR_LRUI 0xfc000000 +#define MMUCR_URB 0x00fc0000 +#define MMUCR_URC 0x0000fc00 +#define MMUCR_SQMD 0x00000200 +#define MMUCR_SV 0x00000100 +#define MMUCR_TI 0x00000004 +#define MMUCR_AT 0x00000001 + +/* constants */ +#define PVR_SH7091 0x040205c1 +#define PVR_SH7750 0x04020500 // from TN-SH7-361B/E +#define PVR_SH7750S 0x04020600 +#define PVR_SH7750R 0x04050000 +#define PRR_SH7750R 0x00000100 +#define PVR_SH7751 0x04110000 +#define PVR_SH7751R 0x04050000 +#define PRR_SH7751R 0x00000110 + +#endif /* __SH4REGS_H__ */ diff --git a/src/devices/cpu/sh4/sh4tmu.c b/src/devices/cpu/sh4/sh4tmu.c new file mode 100644 index 00000000000..89b59ac42ee --- /dev/null +++ b/src/devices/cpu/sh4/sh4tmu.c @@ -0,0 +1,324 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/* SH3/4 Timer Unit */ + +#include "emu.h" +#include "debugger.h" +#include "sh4.h" +#include "sh4comn.h" +#include "sh3comn.h" +#include "sh4tmu.h" + +static const int tcnt_div[8] = { 4, 16, 64, 256, 1024, 1, 1, 1 }; + +/*------------------------------------------------- + sh4_scale_up_mame_time - multiply a attotime by + a (constant+1) where 0 <= constant < 2^32 +-------------------------------------------------*/ + +INLINE attotime sh4_scale_up_mame_time(const attotime &_time1, UINT32 factor1) +{ + return _time1 * factor1 + _time1; +} + +static UINT32 compute_ticks_timer(emu_timer *timer, int hertz, int divisor) +{ + double ret; + + ret=((timer->remaining().as_double() * (double)hertz) / (double)divisor) - 1; + return (UINT32)ret; +} + +void sh34_base_device::sh4_timer_recompute(int which) +{ + double ticks; + + UINT32 tcnt = 0; + UINT32 tcr = 0; + switch (which) + { + case 0: + tcr = m_SH4_TCR0; + tcnt = m_SH4_TCNT0; + break; + + case 1: + tcr = m_SH4_TCR1; + tcnt = m_SH4_TCNT1; + break; + + case 2: + tcr = m_SH4_TCR2; + tcnt = m_SH4_TCNT2; + break; + } + + ticks = tcnt; + m_timer[which]->adjust(sh4_scale_up_mame_time(attotime::from_hz(m_pm_clock) * tcnt_div[tcr & 7], ticks), which); +} + + +TIMER_CALLBACK_MEMBER( sh34_base_device::sh4_timer_callback ) +{ + int which = param; + + switch (which) + { + case 0: + m_SH4_TCNT0 = m_SH4_TCOR0; + break; + + case 1: + m_SH4_TCNT1 = m_SH4_TCOR1; + break; + + case 2: + m_SH4_TCNT2 = m_SH4_TCOR2; + break; + + } + + sh4_timer_recompute(which); + + switch (which) + { + case 0: + m_SH4_TCR0 |= 0x100; + break; + + case 1: + m_SH4_TCR1 |= 0x100; + break; + + case 2: + m_SH4_TCR2 |= 0x100; + break; + + } + + switch (which) + { + case 0: + if (m_SH4_TCR0 & 0x20) + { + sh4_exception_request(SH4_INTC_TUNI0); + // logerror("SH4_INTC_TUNI0 requested\n"); + } + break; + + case 1: + if (m_SH4_TCR1 & 0x20) + { + sh4_exception_request(SH4_INTC_TUNI1); + // logerror("SH4_INTC_TUNI1 requested\n"); + } + break; + + case 2: + if (m_SH4_TCR2 & 0x20) + { + sh4_exception_request(SH4_INTC_TUNI2); + // logerror("SH4_INTC_TUNI2 requested\n"); + } + break; + + } +} + + +UINT32 sh34_base_device::sh4_handle_tcnt0_addr_r(UINT32 mem_mask) +{ + if (m_SH4_TSTR & 1) + return compute_ticks_timer(m_timer[0], m_pm_clock, tcnt_div[m_SH4_TCR0 & 7]); + else + return m_SH4_TCNT0; +} + +UINT32 sh34_base_device::sh4_handle_tcnt1_addr_r(UINT32 mem_mask) +{ + if (m_SH4_TSTR & 2) + return compute_ticks_timer(m_timer[1], m_pm_clock, tcnt_div[m_SH4_TCR1 & 7]); + else + return m_SH4_TCNT1; +} + +UINT32 sh34_base_device::sh4_handle_tcnt2_addr_r(UINT32 mem_mask) +{ + if (m_SH4_TSTR & 4) + return compute_ticks_timer(m_timer[2], m_pm_clock, tcnt_div[m_SH4_TCR2 & 7]); + else + return m_SH4_TCNT2; +} + +UINT32 sh34_base_device::sh4_handle_tcor0_addr_r(UINT32 mem_mask) +{ + return m_SH4_TCOR0; +} + +UINT32 sh34_base_device::sh4_handle_tcor1_addr_r(UINT32 mem_mask) +{ + return m_SH4_TCOR1; +} + +UINT32 sh34_base_device::sh4_handle_tcor2_addr_r(UINT32 mem_mask) +{ + return m_SH4_TCOR2; +} + +UINT32 sh34_base_device::sh4_handle_tcr0_addr_r(UINT32 mem_mask) +{ + return m_SH4_TCR0; +} + +UINT32 sh34_base_device::sh4_handle_tcr1_addr_r(UINT32 mem_mask) +{ + return m_SH4_TCR1; +} + +UINT32 sh34_base_device::sh4_handle_tcr2_addr_r(UINT32 mem_mask) +{ + return m_SH4_TCR2; +} + +UINT32 sh34_base_device::sh4_handle_tstr_addr_r(UINT32 mem_mask) +{ + return m_SH4_TSTR; +} + +UINT32 sh34_base_device::sh4_handle_tocr_addr_r(UINT32 mem_mask) +{ + return m_SH4_TOCR; +} + +UINT32 sh34_base_device::sh4_handle_tcpr2_addr_r(UINT32 mem_mask) +{ + return m_SH4_TCPR2; +} + + +void sh34_base_device::sh4_handle_tstr_addr_w(UINT32 data, UINT32 mem_mask) +{ + UINT32 old2 = m_SH4_TSTR; + COMBINE_DATA(&m_SH4_TSTR); + + if (old2 & 1) + m_SH4_TCNT0 = compute_ticks_timer(m_timer[0], m_pm_clock, tcnt_div[m_SH4_TCR0 & 7]); + if ((m_SH4_TSTR & 1) == 0) { + m_timer[0]->adjust(attotime::never); + } else + sh4_timer_recompute(0); + + if (old2 & 2) + m_SH4_TCNT1 = compute_ticks_timer(m_timer[1], m_pm_clock, tcnt_div[m_SH4_TCR1 & 7]); + if ((m_SH4_TSTR & 2) == 0) { + m_timer[1]->adjust(attotime::never); + } else + sh4_timer_recompute(1); + + if (old2 & 4) + m_SH4_TCNT2 = compute_ticks_timer(m_timer[2], m_pm_clock, tcnt_div[m_SH4_TCR2 & 7]); + if ((m_SH4_TSTR & 4) == 0) { + m_timer[2]->adjust(attotime::never); + } else + sh4_timer_recompute(2); +} + +void sh34_base_device::sh4_handle_tcr0_addr_w(UINT32 data, UINT32 mem_mask) +{ + UINT32 old2 = m_SH4_TCR0; + COMBINE_DATA(&m_SH4_TCR0); + if (m_SH4_TSTR & 1) + { + m_SH4_TCNT0 = compute_ticks_timer(m_timer[0], m_pm_clock, tcnt_div[old2 & 7]); + sh4_timer_recompute(0); + } + if (!(m_SH4_TCR0 & 0x20) || !(m_SH4_TCR0 & 0x100)) + sh4_exception_unrequest(SH4_INTC_TUNI0); +} + +void sh34_base_device::sh4_handle_tcr1_addr_w(UINT32 data, UINT32 mem_mask) +{ + UINT32 old2 = m_SH4_TCR1; + COMBINE_DATA(&m_SH4_TCR1); + if (m_SH4_TSTR & 2) + { + m_SH4_TCNT1 = compute_ticks_timer(m_timer[1], m_pm_clock, tcnt_div[old2 & 7]); + sh4_timer_recompute(1); + } + if (!(m_SH4_TCR1 & 0x20) || !(m_SH4_TCR1 & 0x100)) + sh4_exception_unrequest(SH4_INTC_TUNI1); +} + +void sh34_base_device::sh4_handle_tcr2_addr_w(UINT32 data, UINT32 mem_mask) +{ + UINT32 old2 = m_SH4_TCR2; + COMBINE_DATA(&m_SH4_TCR2); + if (m_SH4_TSTR & 4) + { + m_SH4_TCNT2 = compute_ticks_timer(m_timer[2], m_pm_clock, tcnt_div[old2 & 7]); + sh4_timer_recompute(2); + } + if (!(m_SH4_TCR2 & 0x20) || !(m_SH4_TCR2 & 0x100)) + sh4_exception_unrequest(SH4_INTC_TUNI2); +} + +void sh34_base_device::sh4_handle_tcor0_addr_w(UINT32 data, UINT32 mem_mask) +{ + COMBINE_DATA(&m_SH4_TCOR0); + if (m_SH4_TSTR & 1) + { + m_SH4_TCNT0 = compute_ticks_timer(m_timer[0], m_pm_clock, tcnt_div[m_SH4_TCR0 & 7]); + sh4_timer_recompute(0); + } +} + +void sh34_base_device::sh4_handle_tcor1_addr_w(UINT32 data, UINT32 mem_mask) +{ + COMBINE_DATA(&m_SH4_TCOR1); + if (m_SH4_TSTR & 2) + { + m_SH4_TCNT1 = compute_ticks_timer(m_timer[1], m_pm_clock, tcnt_div[m_SH4_TCR1 & 7]); + sh4_timer_recompute(1); + } +} + +void sh34_base_device::sh4_handle_tcor2_addr_w(UINT32 data, UINT32 mem_mask) +{ + COMBINE_DATA(&m_SH4_TCOR2); + if (m_SH4_TSTR & 4) + { + m_SH4_TCNT2 = compute_ticks_timer(m_timer[2], m_pm_clock, tcnt_div[m_SH4_TCR2 & 7]); + sh4_timer_recompute(2); + } +} + +void sh34_base_device::sh4_handle_tcnt0_addr_w(UINT32 data, UINT32 mem_mask) +{ + COMBINE_DATA(&m_SH4_TCNT0); + if (m_SH4_TSTR & 1) + sh4_timer_recompute(0); +} + +void sh34_base_device::sh4_handle_tcnt1_addr_w(UINT32 data, UINT32 mem_mask) +{ + COMBINE_DATA(&m_SH4_TCNT1); + if (m_SH4_TSTR & 2) + sh4_timer_recompute(1); +} + +void sh34_base_device::sh4_handle_tcnt2_addr_w(UINT32 data, UINT32 mem_mask) +{ + COMBINE_DATA(&m_SH4_TCNT2); + if (m_SH4_TSTR & 4) + sh4_timer_recompute(2); +} + +void sh34_base_device::sh4_handle_tocr_addr_w(UINT32 data, UINT32 mem_mask) +{ + COMBINE_DATA(&m_SH4_TOCR); +} + +void sh34_base_device::sh4_handle_tcpr2_addr_w(UINT32 data, UINT32 mem_mask) +{ + COMBINE_DATA(&m_SH4_TCPR2); +} diff --git a/src/devices/cpu/sh4/sh4tmu.h b/src/devices/cpu/sh4/sh4tmu.h new file mode 100644 index 00000000000..7bbad37a0c1 --- /dev/null +++ b/src/devices/cpu/sh4/sh4tmu.h @@ -0,0 +1,3 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/* SH3/4 Timer Unit */ diff --git a/src/devices/cpu/sharc/compute.inc b/src/devices/cpu/sharc/compute.inc new file mode 100644 index 00000000000..880b368ad1f --- /dev/null +++ b/src/devices/cpu/sharc/compute.inc @@ -0,0 +1,1400 @@ +// license:BSD-3-Clause +// copyright-holders:Ville Linde +/* compute operations */ + +#include + +#define CLEAR_ALU_FLAGS() (m_astat &= ~(AZ|AN|AV|AC|AS|AI)) + +#define SET_FLAG_AZ(r) { m_astat |= (((r) == 0) ? AZ : 0); } +#define SET_FLAG_AN(r) { m_astat |= (((r) & 0x80000000) ? AN : 0); } +#define SET_FLAG_AC_ADD(r,a,b) { m_astat |= (((UINT32)r < (UINT32)a) ? AC : 0); } +#define SET_FLAG_AV_ADD(r,a,b) { m_astat |= (((~((a) ^ (b)) & ((a) ^ (r))) & 0x80000000) ? AV : 0); } +#define SET_FLAG_AC_SUB(r,a,b) { m_astat |= ((!((UINT32)a < (UINT32)b)) ? AC : 0); } +#define SET_FLAG_AV_SUB(r,a,b) { m_astat |= ((( ((a) ^ (b)) & ((a) ^ (r))) & 0x80000000) ? AV : 0); } + +#define IS_FLOAT_ZERO(r) ((((r) & 0x7fffffff) == 0)) +#define IS_FLOAT_DENORMAL(r) ((((r) & 0x7f800000) == 0) && (((r) & 0x7fffff) != 0)) +#define IS_FLOAT_NAN(r) ((((r) & 0x7f800000) == 0x7f800000) && (((r) & 0x7fffff) != 0)) +#define IS_FLOAT_INFINITY(r) (((r) & 0x7fffffff) == 0x7f800000) + +#define CLEAR_MULTIPLIER_FLAGS() (m_astat &= ~(MN|MV|MU|MI)) + +#define SET_FLAG_MN(r) { m_astat |= (((r) & 0x80000000) ? MN : 0); } +#define SET_FLAG_MV(r) { m_astat |= ((((UINT32)((r) >> 32) != 0) && ((UINT32)((r) >> 32) != 0xffffffff)) ? MV : 0); } + +/* TODO: MU needs 80-bit result */ +#define SET_FLAG_MU(r) { m_astat |= ((((UINT32)((r) >> 32) == 0) && ((UINT32)(r)) != 0) ? MU : 0); } + + +#define FLOAT_SIGN 0x80000000 +#define FLOAT_INFINITY 0x7f800000 +#define FLOAT_MANTISSA 0x007fffff + +/*****************************************************************************/ + +// Mantissa lookup-table for RECIPS opcode +static const UINT32 recips_mantissa_lookup[128] = +{ + 0x007F8000, 0x007E0000, 0x007C0000, 0x007A0000, + 0x00780000, 0x00760000, 0x00740000, 0x00720000, + 0x00700000, 0x006F0000, 0x006D0000, 0x006B0000, + 0x006A0000, 0x00680000, 0x00660000, 0x00650000, + 0x00630000, 0x00610000, 0x00600000, 0x005E0000, + 0x005D0000, 0x005B0000, 0x005A0000, 0x00590000, + 0x00570000, 0x00560000, 0x00540000, 0x00530000, + 0x00520000, 0x00500000, 0x004F0000, 0x004E0000, + 0x004C0000, 0x004B0000, 0x004A0000, 0x00490000, + 0x00470000, 0x00460000, 0x00450000, 0x00440000, + 0x00430000, 0x00410000, 0x00400000, 0x003F0000, + 0x003E0000, 0x003D0000, 0x003C0000, 0x003B0000, + 0x003A0000, 0x00390000, 0x00380000, 0x00370000, + 0x00360000, 0x00350000, 0x00340000, 0x00330000, + 0x00320000, 0x00310000, 0x00300000, 0x002F0000, + 0x002E0000, 0x002D0000, 0x002C0000, 0x002B0000, + 0x002A0000, 0x00290000, 0x00280000, 0x00280000, + 0x00270000, 0x00260000, 0x00250000, 0x00240000, + 0x00230000, 0x00230000, 0x00220000, 0x00210000, + 0x00200000, 0x001F0000, 0x001F0000, 0x001E0000, + 0x001D0000, 0x001C0000, 0x001C0000, 0x001B0000, + 0x001A0000, 0x00190000, 0x00190000, 0x00180000, + 0x00170000, 0x00170000, 0x00160000, 0x00150000, + 0x00140000, 0x00140000, 0x00130000, 0x00120000, + 0x00120000, 0x00110000, 0x00100000, 0x00100000, + 0x000F0000, 0x000F0000, 0x000E0000, 0x000D0000, + 0x000D0000, 0x000C0000, 0x000C0000, 0x000B0000, + 0x000A0000, 0x000A0000, 0x00090000, 0x00090000, + 0x00080000, 0x00070000, 0x00070000, 0x00060000, + 0x00060000, 0x00050000, 0x00050000, 0x00040000, + 0x00040000, 0x00030000, 0x00030000, 0x00020000, + 0x00020000, 0x00010000, 0x00010000, 0x00000000, +}; + +// Mantissa lookup-table for RSQRTS opcode +static const UINT32 rsqrts_mantissa_lookup[128] = +{ + 0x00350000, 0x00330000, 0x00320000, 0x00300000, + 0x002F0000, 0x002E0000, 0x002D0000, 0x002B0000, + 0x002A0000, 0x00290000, 0x00280000, 0x00270000, + 0x00260000, 0x00250000, 0x00230000, 0x00220000, + 0x00210000, 0x00200000, 0x001F0000, 0x001E0000, + 0x001E0000, 0x001D0000, 0x001C0000, 0x001B0000, + 0x001A0000, 0x00190000, 0x00180000, 0x00170000, + 0x00160000, 0x00160000, 0x00150000, 0x00140000, + 0x00130000, 0x00130000, 0x00120000, 0x00110000, + 0x00100000, 0x00100000, 0x000F0000, 0x000E0000, + 0x000E0000, 0x000D0000, 0x000C0000, 0x000B0000, + 0x000B0000, 0x000A0000, 0x000A0000, 0x00090000, + 0x00080000, 0x00080000, 0x00070000, 0x00070000, + 0x00060000, 0x00050000, 0x00050000, 0x00040000, + 0x00040000, 0x00030000, 0x00030000, 0x00020000, + 0x00020000, 0x00010000, 0x00010000, 0x00000000, + 0x007F8000, 0x007E0000, 0x007C0000, 0x007A0000, + 0x00780000, 0x00760000, 0x00740000, 0x00730000, + 0x00710000, 0x006F0000, 0x006E0000, 0x006C0000, + 0x006A0000, 0x00690000, 0x00670000, 0x00660000, + 0x00640000, 0x00630000, 0x00620000, 0x00600000, + 0x005F0000, 0x005E0000, 0x005C0000, 0x005B0000, + 0x005A0000, 0x00590000, 0x00570000, 0x00560000, + 0x00550000, 0x00540000, 0x00530000, 0x00520000, + 0x00510000, 0x004F0000, 0x004E0000, 0x004D0000, + 0x004C0000, 0x004B0000, 0x004A0000, 0x00490000, + 0x00480000, 0x00470000, 0x00460000, 0x00450000, + 0x00450000, 0x00440000, 0x00430000, 0x00420000, + 0x00410000, 0x00400000, 0x003F0000, 0x003E0000, + 0x003E0000, 0x003D0000, 0x003C0000, 0x003B0000, + 0x003A0000, 0x003A0000, 0x00390000, 0x00380000, + 0x00370000, 0x00370000, 0x00360000, 0x00350000, +}; + +/*****************************************************************************/ +/* Integer ALU operations */ + +/* Rn = Rx + Ry */ +void adsp21062_device::compute_add(int rn, int rx, int ry) +{ + UINT32 r = REG(rx) + REG(ry); + + if (m_mode1 & MODE1_ALUSAT) + fatalerror("SHARC: compute_add: ALU saturation not implemented!\n"); + + CLEAR_ALU_FLAGS(); + SET_FLAG_AN(r); + SET_FLAG_AZ(r); + SET_FLAG_AV_ADD(r, REG(rx), REG(ry)); + SET_FLAG_AC_ADD(r, REG(rx), REG(ry)); + REG(rn) = r; + + m_astat &= ~AF; +} + +/* Rn = Rx - Ry */ +void adsp21062_device::compute_sub(int rn, int rx, int ry) +{ + UINT32 r = REG(rx) - REG(ry); + + if (m_mode1 & MODE1_ALUSAT) + fatalerror("SHARC: compute_sub: ALU saturation not implemented!\n"); + + CLEAR_ALU_FLAGS(); + SET_FLAG_AN(r); + SET_FLAG_AZ(r); + SET_FLAG_AV_SUB(r, REG(rx), REG(ry)); + SET_FLAG_AC_SUB(r, REG(rx), REG(ry)); + REG(rn) = r; + + m_astat &= ~AF; +} + +/* Rn = Rx + Ry + CI */ +void adsp21062_device::compute_add_ci(int rn, int rx, int ry) +{ + int c = (m_astat & AC) ? 1 : 0; + UINT32 r = REG(rx) + REG(ry) + c; + + if (m_mode1 & MODE1_ALUSAT) + fatalerror("SHARC: compute_add_ci: ALU saturation not implemented!\n"); + + CLEAR_ALU_FLAGS(); + SET_FLAG_AN(r); + SET_FLAG_AZ(r); + SET_FLAG_AV_ADD(r, REG(rx), REG(ry)+c); + SET_FLAG_AC_ADD(r, REG(rx), REG(ry)+c); + REG(rn) = r; + + m_astat &= ~AF; +} + +/* Rn = Rx - Ry + CI - 1 */ +void adsp21062_device::compute_sub_ci(int rn, int rx, int ry) +{ + int c = (m_astat & AC) ? 1 : 0; + UINT32 r = REG(rx) - REG(ry) + c - 1; + + if (m_mode1 & MODE1_ALUSAT) + fatalerror("SHARC: compute_sub_ci: ALU saturation not implemented!\n"); + + CLEAR_ALU_FLAGS(); + SET_FLAG_AN(r); + SET_FLAG_AZ(r); + SET_FLAG_AV_SUB(r, REG(rx), REG(ry)+c-1); + SET_FLAG_AC_SUB(r, REG(rx), REG(ry)+c-1); + REG(rn) = r; + + m_astat &= ~AF; +} + +/* Rn = Rx AND Ry */ +void adsp21062_device::compute_and(int rn, int rx, int ry) +{ + UINT32 r = REG(rx) & REG(ry); + + CLEAR_ALU_FLAGS(); + SET_FLAG_AN(r); + SET_FLAG_AZ(r); + REG(rn) = r; + + m_astat &= ~AF; +} + +/* COMP(Rx, Ry) */ +void adsp21062_device::compute_comp(int rx, int ry) +{ + UINT32 comp_accum; + + CLEAR_ALU_FLAGS(); + if( REG(rx) == REG(ry) ) + m_astat |= AZ; + if( (INT32)REG(rx) < (INT32)REG(ry) ) + m_astat |= AN; + + // Update ASTAT compare accumulation register + comp_accum = (m_astat >> 24) & 0xff; + comp_accum >>= 1; + if ((m_astat & (AZ|AN)) == 0) + { + comp_accum |= 0x80; + } + m_astat &= 0xffffff; + m_astat |= comp_accum << 24; + + m_astat &= ~AF; +} + +/* Rn = PASS Rx */ +void adsp21062_device::compute_pass(int rn, int rx) +{ + CLEAR_ALU_FLAGS(); + /* TODO: floating-point extension field is set to 0 */ + + REG(rn) = REG(rx); + if (REG(rn) == 0) + m_astat |= AZ; + if (REG(rn) & 0x80000000) + m_astat |= AN; + + m_astat &= ~AF; +} + +/* Rn = Rx XOR Ry */ +void adsp21062_device::compute_xor(int rn, int rx, int ry) +{ + UINT32 r = REG(rx) ^ REG(ry); + CLEAR_ALU_FLAGS(); + SET_FLAG_AN(r); + SET_FLAG_AZ(r); + REG(rn) = r; + + m_astat &= ~AF; +} + +/* Rn = Rx OR Ry */ +void adsp21062_device::compute_or(int rn, int rx, int ry) +{ + UINT32 r = REG(rx) | REG(ry); + CLEAR_ALU_FLAGS(); + SET_FLAG_AN(r); + SET_FLAG_AZ(r); + REG(rn) = r; + + m_astat &= ~AF; +} + +/* Rn = Rx + 1 */ +void adsp21062_device::compute_inc(int rn, int rx) +{ + UINT32 r = REG(rx) + 1; + + CLEAR_ALU_FLAGS(); + SET_FLAG_AN(r); + SET_FLAG_AZ(r); + SET_FLAG_AV_ADD(r, REG(rx), 1); + SET_FLAG_AC_ADD(r, REG(rx), 1); + + REG(rn) = r; + + m_astat &= ~AF; +} + +/* Rn = Rx - 1 */ +void adsp21062_device::compute_dec(int rn, int rx) +{ + UINT32 r = REG(rx) - 1; + + CLEAR_ALU_FLAGS(); + SET_FLAG_AN(r); + SET_FLAG_AZ(r); + SET_FLAG_AV_SUB(r, REG(rx), 1); + SET_FLAG_AC_SUB(r, REG(rx), 1); + + REG(rn) = r; + + m_astat &= ~AF; +} + +/* Rn = MIN(Rx, Ry) */ +void adsp21062_device::compute_min(int rn, int rx, int ry) +{ + UINT32 r = MIN((INT32)REG(rx), (INT32)REG(ry)); + + CLEAR_ALU_FLAGS(); + SET_FLAG_AN(r); + SET_FLAG_AZ(r); + + REG(rn) = r; + + m_astat &= ~AF; +} + +/* Rn = MAX(Rx, Ry) */ +void adsp21062_device::compute_max(int rn, int rx, int ry) +{ + UINT32 r = MAX((INT32)REG(rx), (INT32)REG(ry)); + + CLEAR_ALU_FLAGS(); + SET_FLAG_AN(r); + SET_FLAG_AZ(r); + + REG(rn) = r; + + m_astat &= ~AF; +} + +/* Rn = -Rx */ +void adsp21062_device::compute_neg(int rn, int rx) +{ + UINT32 r = -(INT32)(REG(rx)); + + CLEAR_ALU_FLAGS(); + SET_FLAG_AN(r); + SET_FLAG_AZ(r); + SET_FLAG_AV_SUB(r, 0, REG(rx)); + SET_FLAG_AC_SUB(r, 0, REG(rx)); + + REG(rn) = r; + + m_astat &= ~AF; +} + +/* Rn = NOT Rx */ +void adsp21062_device::compute_not(int rn, int rx) +{ + UINT32 r = ~REG(rx); + + CLEAR_ALU_FLAGS(); + SET_FLAG_AN(r); + SET_FLAG_AZ(r); + + REG(rn) = r; + + m_astat &= ~AF; +} + +/*****************************************************************************/ +/* Floating-point ALU operations */ + +UINT32 adsp21062_device::SCALB(SHARC_REG rx, int ry) +{ + UINT32 mantissa = rx.r & FLOAT_MANTISSA; + UINT32 sign = rx.r & FLOAT_SIGN; + + int exponent = ((rx.r >> 23) & 0xff) - 127; + exponent += (INT32)(REG(ry)); + + if (exponent > 127) + { + // overflow + m_astat |= AV; + return sign | FLOAT_INFINITY; + } + else if (exponent < -126) + { + // denormal + m_astat |= AZ; + return sign; + } + else + { + return sign | (((exponent + 127) & 0xff) << 23) | mantissa; + } +} + +/* Fn = FLOAT Rx */ +void adsp21062_device::compute_float(int rn, int rx) +{ + // verified + FREG(rn) = (float)(INT32)REG(rx); + + CLEAR_ALU_FLAGS(); + // AN + SET_FLAG_AN(REG(rn)); + // AZ + m_astat |= (IS_FLOAT_DENORMAL(REG(rn)) || IS_FLOAT_ZERO(REG(rn))) ? AZ : 0; + // AUS + m_stky |= (IS_FLOAT_DENORMAL(REG(rn))) ? AUS : 0; + /* TODO: AV flag */ + + m_astat |= AF; +} + +/* Rn = FIX Fx */ +void adsp21062_device::compute_fix(int rn, int rx) +{ + INT32 alu_i; + SHARC_REG r_alu; + + r_alu.f = FREG(rx); + if (m_mode1 & MODE1_TRUNCATE) + { + alu_i = (INT32)(r_alu.f); + } + else + { + alu_i = (INT32)(r_alu.f < 0 ? (r_alu.f - 0.5f) : (r_alu.f + 0.5f)); + } + + CLEAR_ALU_FLAGS(); + SET_FLAG_AN(alu_i); + // AZ + SET_FLAG_AZ(alu_i); + // AU + m_stky |= (IS_FLOAT_DENORMAL(r_alu.r)) ? AUS : 0; + // AI + m_astat |= (IS_FLOAT_NAN(REG(rx))) ? AI : 0; + /* TODO: AV flag */ + + REG(rn) = alu_i; + m_astat |= AF; +} + +/* Rn = FIX Fx BY Ry */ +void adsp21062_device::compute_fix_scaled(int rn, int rx, int ry) +{ + INT32 alu_i; + SHARC_REG r_alu; + + r_alu.r = SCALB(m_r[rx], ry); + if (m_mode1 & MODE1_TRUNCATE) + { + alu_i = (INT32)(r_alu.f); + } + else + { + alu_i = (INT32)(r_alu.f < 0 ? (r_alu.f - 0.5f) : (r_alu.f + 0.5f)); + } + + CLEAR_ALU_FLAGS(); + SET_FLAG_AN(alu_i); + // AZ + SET_FLAG_AZ(alu_i); + // AU + m_stky |= (IS_FLOAT_DENORMAL(r_alu.r)) ? AUS : 0; + // AI + m_astat |= (IS_FLOAT_NAN(REG(rx))) ? AI : 0; + /* TODO: AV flag */ + + REG(rn) = alu_i; + m_astat |= AF; +} + +/* Fn = FLOAT Rx BY Ry */ +void adsp21062_device::compute_float_scaled(int rn, int rx, int ry) +{ + SHARC_REG x; + x.f = (float)(INT32)(REG(rx)); + + // verified + CLEAR_ALU_FLAGS(); + + REG(rn) = SCALB(x, ry); + + // AN + SET_FLAG_AN(REG(rn)); + // AZ + m_astat |= (IS_FLOAT_DENORMAL(REG(rn)) || IS_FLOAT_ZERO(REG(rn))) ? AZ : 0; + // AU + m_stky |= (IS_FLOAT_DENORMAL(REG(rn))) ? AUS : 0; + + m_astat |= AF; +} + +/* Rn = LOGB Fx */ +void adsp21062_device::compute_logb(int rn, int rx) +{ + // verified + UINT32 r = REG(rx); + + CLEAR_ALU_FLAGS(); + + if (IS_FLOAT_INFINITY(REG(rx))) + { + REG(rn) = FLOAT_INFINITY; + + m_astat |= AV; + } + else if (IS_FLOAT_ZERO(REG(rx))) + { + REG(rn) = FLOAT_SIGN | FLOAT_INFINITY; + + m_astat |= AV; + } + else if (IS_FLOAT_NAN(REG(rx))) + { + REG(rn) = 0xffffffff; + + m_astat |= AI; + m_stky |= AIS; + } + else + { + int exponent = (r >> 23) & 0xff; + exponent -= 127; + + // AN + SET_FLAG_AN(exponent); + // AZ + SET_FLAG_AZ(exponent); + + REG(rn) = exponent; + } + m_astat |= AF; +} + +/* Fn = SCALB Fx BY Fy */ +void adsp21062_device::compute_scalb(int rn, int rx, int ry) +{ + // verified + SHARC_REG r; + CLEAR_ALU_FLAGS(); + + if (IS_FLOAT_NAN(REG(rx))) + { + m_astat |= AI; + m_stky |= AIS; + + REG(rn) = 0xffffffff; + } + else + { + r.r = SCALB(m_r[rx], ry); + + // AN + SET_FLAG_AN(r.r); + // AZ + m_astat |= IS_FLOAT_ZERO(r.r) ? AZ : 0; + // AUS + m_stky |= (IS_FLOAT_DENORMAL(r.r)) ? AUS : 0; + + FREG(rn) = r.f; + } + m_astat |= AF; +} + +/* Fn = Fx + Fy */ +void adsp21062_device::compute_fadd(int rn, int rx, int ry) +{ + SHARC_REG r; + r.f = FREG(rx) + FREG(ry); + + CLEAR_ALU_FLAGS(); + // AN + m_astat |= (r.f < 0.0f) ? AN : 0; + // AZ + m_astat |= (IS_FLOAT_DENORMAL(r.r) || IS_FLOAT_ZERO(r.r)) ? AZ : 0; + // AUS + m_stky |= (IS_FLOAT_DENORMAL(r.r)) ? AUS : 0; + // AI + m_astat |= (IS_FLOAT_NAN(REG(rx)) || IS_FLOAT_NAN(REG(ry))) ? AI : 0; + /* TODO: AV flag */ + + // AIS + if (m_astat & AI) m_stky |= AIS; + + FREG(rn) = r.f; + m_astat |= AF; +} + +void adsp21062_device::compute_favg(int rn, int rx, int ry) +{ + SHARC_REG r; + r.f = (FREG(rx) + FREG(ry)) / (float) 2.0f; + + CLEAR_ALU_FLAGS(); + // AN + m_astat |= (r.f < 0.0f) ? AN : 0; + // AZ + m_astat |= (IS_FLOAT_DENORMAL(r.r) || IS_FLOAT_ZERO(r.r)) ? AZ : 0; + // AUS + m_stky |= (IS_FLOAT_DENORMAL(r.r)) ? AUS : 0; + // AI + m_astat |= (IS_FLOAT_NAN(REG(rx)) || IS_FLOAT_NAN(REG(ry))) ? AI : 0; + /* TODO: AV flag */ + + // AIS + if (m_astat & AI) m_stky |= AIS; + + FREG(rn) = r.f; + m_astat |= AF; +} + +/* Fn = Fx - Fy */ +void adsp21062_device::compute_fsub(int rn, int rx, int ry) +{ + SHARC_REG r; + r.f = FREG(rx) - FREG(ry); + + CLEAR_ALU_FLAGS(); + // AN + m_astat |= (r.f < 0.0f) ? AN : 0; + // AZ + m_astat |= (IS_FLOAT_DENORMAL(r.r) || IS_FLOAT_ZERO(r.r)) ? AZ : 0; + // AUS + m_stky |= (IS_FLOAT_DENORMAL(r.r)) ? AUS : 0; + // AI + m_astat |= (IS_FLOAT_NAN(REG(rx)) || IS_FLOAT_NAN(REG(ry))) ? AI : 0; + /* TODO: AV flag */ + + // AIS + if (m_astat & AI) m_stky |= AIS; + + FREG(rn) = r.f; + m_astat |= AF; +} + +/* Fn = -Fx */ +void adsp21062_device::compute_fneg(int rn, int rx) +{ + SHARC_REG r; + r.f = -FREG(rx); + + CLEAR_ALU_FLAGS(); + // AZ + m_astat |= (IS_FLOAT_ZERO(r.r)) ? AZ : 0; + // AN + m_astat |= (r.f < 0.0f) ? AN : 0; + // AI + m_astat |= (IS_FLOAT_NAN(REG(rx))) ? AI : 0; + + // AIS + if (m_astat & AI) m_stky |= AIS; + + FREG(rn) = r.f; + m_astat |= AF; +} + +/* COMP(Fx, Fy) */ +void adsp21062_device::compute_fcomp(int rx, int ry) +{ + UINT32 comp_accum; + + CLEAR_ALU_FLAGS(); + // AZ + if( FREG(rx) == FREG(ry) ) + m_astat |= AZ; + // AN + if( FREG(rx) < FREG(ry) ) + m_astat |= AN; + // AI + m_astat |= (IS_FLOAT_NAN(REG(rx)) || IS_FLOAT_NAN(REG(ry))) ? AI : 0; + + // AIS + if (m_astat & AI) m_stky |= AIS; + + // Update ASTAT compare accumulation register + comp_accum = (m_astat >> 24) & 0xff; + comp_accum >>= 1; + if ((m_astat & (AZ|AN)) == 0) + { + comp_accum |= 0x80; + } + m_astat &= 0xffffff; + m_astat |= comp_accum << 24; + m_astat |= AF; +} + +/* Fn = ABS(Fx + Fy) */ +void adsp21062_device::compute_fabs_plus(int rn, int rx, int ry) +{ + SHARC_REG r; + r.f = fabs(FREG(rx) + FREG(ry)); + + CLEAR_ALU_FLAGS(); + // AZ + m_astat |= (IS_FLOAT_DENORMAL(r.r) || IS_FLOAT_ZERO(r.r)) ? AZ : 0; + // AUS + m_stky |= (IS_FLOAT_DENORMAL(r.r)) ? AUS : 0; + // AI + m_astat |= (IS_FLOAT_NAN(REG(rx)) || IS_FLOAT_NAN(REG(ry))) ? AI : 0; + /* TODO: AV flag */ + + // AIS + if (m_astat & AI) m_stky |= AIS; + + FREG(rn) = r.f; + m_astat |= AF; +} + +/* Fn = MAX(Fx, Fy) */ +void adsp21062_device::compute_fmax(int rn, int rx, int ry) +{ + SHARC_REG r_alu; + + r_alu.f = MAX(FREG(rx), FREG(ry)); + + CLEAR_ALU_FLAGS(); + m_astat |= (r_alu.f < 0.0f) ? AN : 0; + // AZ + m_astat |= (IS_FLOAT_ZERO(r_alu.r)) ? AZ : 0; + // AU + m_stky |= (IS_FLOAT_DENORMAL(r_alu.r)) ? AUS : 0; + // AI + m_astat |= (IS_FLOAT_NAN(REG(rx)) || IS_FLOAT_NAN(REG(ry))) ? AI : 0; + /* TODO: AV flag */ + + FREG(rn) = r_alu.f; + m_astat |= AF; +} + +/* Fn = MIN(Fx, Fy) */ +void adsp21062_device::compute_fmin(int rn, int rx, int ry) +{ + SHARC_REG r_alu; + + r_alu.f = MIN(FREG(rx), FREG(ry)); + + CLEAR_ALU_FLAGS(); + m_astat |= (r_alu.f < 0.0f) ? AN : 0; + // AZ + m_astat |= (IS_FLOAT_ZERO(r_alu.r)) ? AZ : 0; + // AU + m_stky |= (IS_FLOAT_DENORMAL(r_alu.r)) ? AUS : 0; + // AI + m_astat |= (IS_FLOAT_NAN(REG(rx)) || IS_FLOAT_NAN(REG(ry))) ? AI : 0; + /* TODO: AV flag */ + + FREG(rn) = r_alu.f; + m_astat |= AF; +} + +/* Fn = CLIP Fx BY Fy */ +void adsp21062_device::compute_fclip(int rn, int rx, int ry) +{ + SHARC_REG r_alu; + + if (FREG(rx) < fabsf(FREG(ry))) + { + r_alu.f = FREG(rx); + } + else + { + if (FREG(rx) >= 0.0f) + { + r_alu.f = fabsf(FREG(ry)); + } + else + { + r_alu.f = -fabsf(FREG(ry)); + } + } + + + CLEAR_ALU_FLAGS(); + SET_FLAG_AN(r_alu.r); + // AZ + m_astat |= (IS_FLOAT_ZERO(r_alu.r)) ? AZ : 0; + // AU + m_stky |= (IS_FLOAT_DENORMAL(r_alu.r)) ? AUS : 0; + // AI + m_astat |= (IS_FLOAT_NAN(REG(rx)) || IS_FLOAT_NAN(REG(ry))) ? AI : 0; + + FREG(rn) = r_alu.f; + m_astat |= AF; +} + +/* Fn = RECIPS Fx */ +void adsp21062_device::compute_recips(int rn, int rx) +{ + // verified + UINT32 r; + + CLEAR_ALU_FLAGS(); + + if (IS_FLOAT_NAN(REG(rx))) + { + // NaN + r = 0xffffffff; + + // AI + m_astat |= AI; + + // AIS + m_stky |= AIS; + } + else if (IS_FLOAT_ZERO(REG(rx))) + { + // +- Zero + r = (REG(rx) & FLOAT_SIGN) | FLOAT_INFINITY; + + m_astat |= AZ; + } + else + { + UINT32 mantissa = REG(rx) & 0x7fffff; + UINT32 exponent = (REG(rx) >> 23) & 0xff; + UINT32 sign = REG(rx) & FLOAT_SIGN; + + UINT32 res_mantissa = recips_mantissa_lookup[mantissa >> 16]; + + int res_exponent = -(exponent - 127) - 1; + if (res_exponent > 125 || res_exponent < -126) + { + res_exponent = 0; + res_mantissa = 0; + } + else + { + res_exponent = (res_exponent + 127) & 0xff; + } + + r = sign | (res_exponent << 23) | res_mantissa; + + SET_FLAG_AN(REG(rx)); + // AZ & AV + m_astat |= (IS_FLOAT_ZERO(r)) ? AZ : 0; + m_astat |= (IS_FLOAT_ZERO(REG(rx))) ? AV : 0; + // AI + m_astat |= (IS_FLOAT_NAN(REG(rx))) ? AI : 0; + + // AIS + if (m_astat & AI) m_stky |= AIS; + } + + // AF + m_astat |= AF; + + REG(rn) = r; +} + +/* Fn = RSQRTS Fx */ +void adsp21062_device::compute_rsqrts(int rn, int rx) +{ + // verified + UINT32 r; + + if ((UINT32)(REG(rx)) > 0x80000000) + { + // non-zero negative + r = 0xffffffff; + } + else if (IS_FLOAT_NAN(REG(rx))) + { + // NaN + r = 0xffffffff; + } + else + { + UINT32 mantissa = REG(rx) & 0xffffff; // mantissa + LSB of biased exponent + UINT32 exponent = (REG(rx) >> 23) & 0xff; + UINT32 sign = REG(rx) & FLOAT_SIGN; + + UINT32 res_mantissa = rsqrts_mantissa_lookup[mantissa >> 17]; + + int res_exponent = -((exponent - 127) / 2) - 1; + res_exponent = (res_exponent + 127) & 0xff; + + r = sign | (res_exponent << 23) | res_mantissa; + } + + CLEAR_ALU_FLAGS(); + // AN + m_astat |= (REG(rx) == 0x80000000) ? AN : 0; + // AZ & AV + m_astat |= (IS_FLOAT_ZERO(r)) ? AZ : 0; + m_astat |= (IS_FLOAT_ZERO(REG(rx))) ? AV : 0; + // AI + m_astat |= (IS_FLOAT_NAN(REG(rx)) || (REG(rx) & 0x80000000)) ? AI : 0; + // AIS + if (m_astat & AI) m_stky |= AIS; + // AF + m_astat |= AF; + + REG(rn) = r; +} + + +/* Fn = PASS Fx */ +void adsp21062_device::compute_fpass(int rn, int rx) +{ + SHARC_REG r; + r.f = FREG(rx); + + CLEAR_ALU_FLAGS(); + // AN + m_astat |= (r.f < 0.0f) ? AN : 0; + // AZ + m_astat |= (IS_FLOAT_ZERO(r.r)) ? AZ : 0; + // AI + m_astat |= (IS_FLOAT_NAN(REG(rx))) ? AI : 0; + + FREG(rn) = r.f; + m_astat |= AF; +} + +/* Fn = ABS Fx */ +void adsp21062_device::compute_fabs(int rn, int rx) +{ + SHARC_REG r; + r.f = fabs(FREG(rx)); + + CLEAR_ALU_FLAGS(); + // AN + m_astat |= (r.f < 0.0f) ? AN : 0; + // AZ + m_astat |= (IS_FLOAT_ZERO(r.r)) ? AZ : 0; + // AI + m_astat |= (IS_FLOAT_NAN(REG(rx))) ? AI : 0; + + FREG(rn) = r.f; + m_astat |= AF; +} + +/*****************************************************************************/ +/* Multiplier opcodes */ + +/* Rn = (unsigned)Rx * (unsigned)Ry, integer, no rounding */ +void adsp21062_device::compute_mul_uuin(int rn, int rx, int ry) +{ + UINT64 r = (UINT64)(UINT32)REG(rx) * (UINT64)(UINT32)REG(ry); + + CLEAR_MULTIPLIER_FLAGS(); + SET_FLAG_MN((UINT32)r); + SET_FLAG_MV(r); + SET_FLAG_MU(r); + + REG(rn) = (UINT32)(r); +} + +/* Rn = (signed)Rx * (signed)Ry, integer, no rounding */ +void adsp21062_device::compute_mul_ssin(int rn, int rx, int ry) +{ + UINT64 r = (INT64)(INT32)REG(rx) * (INT64)(INT32)REG(ry); + + CLEAR_MULTIPLIER_FLAGS(); + SET_FLAG_MN((UINT32)r); + SET_FLAG_MV(r); + SET_FLAG_MU(r); + + REG(rn) = (UINT32)(r); +} + +/* MRF + (signed)Rx * (signed)Ry, integer, no rounding */ +UINT32 adsp21062_device::compute_mrf_plus_mul_ssin(int rx, int ry) +{ + UINT64 r = m_mrf + ((INT64)(INT32)REG(rx) * (INT64)(INT32)REG(ry)); + + CLEAR_MULTIPLIER_FLAGS(); + SET_FLAG_MN((UINT32)r); + SET_FLAG_MV(r); + SET_FLAG_MU(r); + + return (UINT32)(r); +} + +/* MRB + (signed)Rx * (signed)Ry, integer, no rounding */ +UINT32 adsp21062_device::compute_mrb_plus_mul_ssin(int rx, int ry) +{ + INT64 r = m_mrb + ((INT64)(INT32)REG(rx) * (INT64)(INT32)REG(ry)); + + CLEAR_MULTIPLIER_FLAGS(); + SET_FLAG_MN((UINT32)r); + SET_FLAG_MV(r); + SET_FLAG_MU(r); + + return (UINT32)(r); +} + +/* Fn = Fx * Fy */ +void adsp21062_device::compute_fmul(int rn, int rx, int ry) +{ + FREG(rn) = FREG(rx) * FREG(ry); + + CLEAR_MULTIPLIER_FLAGS(); + SET_FLAG_MN(REG(rn)); + /* TODO: MV flag */ + /* TODO: MU flag */ + /* TODO: MI flag */ +} + +/*****************************************************************************/ + +/* multi function opcodes */ + +/* integer*/ +void adsp21062_device::compute_multi_mr_to_reg(int ai, int rk) +{ + switch(ai) + { + case 0: SET_UREG(rk, (UINT32)(m_mrf)); break; + case 1: SET_UREG(rk, (UINT32)(m_mrf >> 32)); break; + case 2: fatalerror("SHARC: tried to load MR2F\n"); break; + case 4: SET_UREG(rk, (UINT32)(m_mrb)); break; + case 5: SET_UREG(rk, (UINT32)(m_mrb >> 32)); break; + case 6: fatalerror("SHARC: tried to load MR2B\n"); break; + default: fatalerror("SHARC: unknown ai %d in mr_to_reg\n", ai); + } + + CLEAR_MULTIPLIER_FLAGS(); +} + +void adsp21062_device::compute_multi_reg_to_mr(int ai, int rk) +{ + switch(ai) + { + case 0: m_mrf &= ~0xffffffff; m_mrf |= GET_UREG(rk); break; + case 1: m_mrf &= 0xffffffff; m_mrf |= (UINT64)(GET_UREG(rk)) << 32; break; + case 2: fatalerror("SHARC: tried to write MR2F\n"); break; + case 4: m_mrb &= ~0xffffffff; m_mrb |= GET_UREG(rk); break; + case 5: m_mrb &= 0xffffffff; m_mrb |= (UINT64)(GET_UREG(rk)) << 32; break; + case 6: fatalerror("SHARC: tried to write MR2B\n"); break; + default: fatalerror("SHARC: unknown ai %d in reg_to_mr\n", ai); + } + + CLEAR_MULTIPLIER_FLAGS(); +} + +/* Ra = Rx + Ry, Rs = Rx - Ry */ +void adsp21062_device::compute_dual_add_sub(int ra, int rs, int rx, int ry) +{ + UINT32 r_add = REG(rx) + REG(ry); + UINT32 r_sub = REG(rx) - REG(ry); + + CLEAR_ALU_FLAGS(); + if (r_add == 0 || r_sub == 0) + { + m_astat |= AZ; + } + if (r_add & 0x80000000 || r_sub & 0x80000000) + { + m_astat |= AN; + } + if (((~(REG(rx) ^ REG(ry)) & (REG(rx) ^ r_add)) & 0x80000000) || + (( (REG(rx) ^ REG(ry)) & (REG(rx) ^ r_sub)) & 0x80000000)) + { + m_astat |= AV; + } + if (((UINT32)r_add < (UINT32)REG(rx)) || + (!((UINT32)r_sub < (UINT32)REG(rx)))) + { + m_astat |= AC; + } + + REG(ra) = r_add; + REG(rs) = r_sub; + + m_astat &= ~AF; +} + +/* Rm = (signed)Rxm * (signed)Rym, fractional, rounding, Ra = Rxa + Rya */ +void adsp21062_device::compute_mul_ssfr_add(int rm, int rxm, int rym, int ra, int rxa, int rya) +{ + UINT32 r_mul = (UINT32)(((INT64)(REG(rxm)) * (INT64)(REG(rym))) >> 31); + UINT32 r_add = REG(rxa) + REG(rya); + + CLEAR_MULTIPLIER_FLAGS(); + SET_FLAG_MN(r_mul); + /* TODO: MV flag */ + /* TODO: MU flag */ + /* TODO: MI flag */ + + CLEAR_ALU_FLAGS(); + SET_FLAG_AN(r_add); + SET_FLAG_AZ(r_add); + SET_FLAG_AV_ADD(r_add, REG(rxa), REG(rya)); + SET_FLAG_AC_ADD(r_add, REG(rxa), REG(rya)); + + + REG(rm) = r_mul; + REG(ra) = r_add; + + m_astat &= ~AF; +} + +/* Rm = (signed)Rxm * (signed)Rym, fractional, rounding, Ra = Rxa - Rya */ +void adsp21062_device::compute_mul_ssfr_sub(int rm, int rxm, int rym, int ra, int rxa, int rya) +{ + UINT32 r_mul = (UINT32)(((INT64)(REG(rxm)) * (INT64)(REG(rym))) >> 31); + UINT32 r_sub = REG(rxa) - REG(rya); + + CLEAR_MULTIPLIER_FLAGS(); + SET_FLAG_MN(r_mul); + /* TODO: MV flag */ + /* TODO: MU flag */ + /* TODO: MI flag */ + + CLEAR_ALU_FLAGS(); + SET_FLAG_AN(r_sub); + SET_FLAG_AZ(r_sub); + SET_FLAG_AV_SUB(r_sub, REG(rxa), REG(rya)); + SET_FLAG_AC_SUB(r_sub, REG(rxa), REG(rya)); + + + REG(rm) = r_mul; + REG(ra) = r_sub; + + m_astat &= ~AF; +} + + +/* floating-point */ + +/* Fa = Fx + Fy, Fs = Fx - Fy */ +void adsp21062_device::compute_dual_fadd_fsub(int ra, int rs, int rx, int ry) +{ + SHARC_REG r_add, r_sub; + r_add.f = FREG(rx) + FREG(ry); + r_sub.f = FREG(rx) - FREG(ry); + + CLEAR_ALU_FLAGS(); + // AN + m_astat |= ((r_add.f < 0.0f) || (r_sub.f < 0.0f)) ? AN : 0; + // AZ + m_astat |= (IS_FLOAT_DENORMAL(r_add.r) || IS_FLOAT_ZERO(r_add.r) || + IS_FLOAT_DENORMAL(r_sub.r) || IS_FLOAT_ZERO(r_sub.r)) ? AZ : 0; + // AUS + m_stky |= (IS_FLOAT_DENORMAL(r_add.r) || IS_FLOAT_DENORMAL(r_sub.r)) ? AUS : 0; + // AI + m_astat |= (IS_FLOAT_NAN(REG(rx)) || IS_FLOAT_NAN(REG(ry))) ? AI : 0; + /* TODO: AV flag */ + + // AIS + if (m_astat & AI) m_stky |= AIS; + + FREG(ra) = r_add.f; + FREG(rs) = r_sub.f; + m_astat |= AF; +} + +/* Fm = Fxm * Fym, Fa = Fxa + Fya */ +void adsp21062_device::compute_fmul_fadd(int fm, int fxm, int fym, int fa, int fxa, int fya) +{ + SHARC_REG r_mul, r_add; + r_mul.f = FREG(fxm) * FREG(fym); + r_add.f = FREG(fxa) + FREG(fya); + + CLEAR_MULTIPLIER_FLAGS(); + SET_FLAG_MN(r_mul.r); + /* TODO: MV flag */ + /* TODO: MU flag */ + /* TODO: MI flag */ + + CLEAR_ALU_FLAGS(); + m_astat |= (r_add.f < 0.0f) ? AN : 0; + // AZ + m_astat |= (IS_FLOAT_DENORMAL(r_add.r) || IS_FLOAT_ZERO(r_add.r)) ? AZ : 0; + // AU + m_stky |= (IS_FLOAT_DENORMAL(r_add.r)) ? AUS : 0; + // AI + m_astat |= (IS_FLOAT_NAN(REG(fxa)) || IS_FLOAT_NAN(REG(fya))) ? AI : 0; + /* TODO: AV flag */ + + // AIS + if (m_astat & AI) m_stky |= AIS; + + FREG(fm) = r_mul.f; + FREG(fa) = r_add.f; + m_astat |= AF; +} + +/* Fm = Fxm * Fym, Fa = Fxa - Fya */ +void adsp21062_device::compute_fmul_fsub(int fm, int fxm, int fym, int fa, int fxa, int fya) +{ + SHARC_REG r_mul, r_sub; + r_mul.f = FREG(fxm) * FREG(fym); + r_sub.f = FREG(fxa) - FREG(fya); + + CLEAR_MULTIPLIER_FLAGS(); + SET_FLAG_MN(r_mul.r); + /* TODO: MV flag */ + /* TODO: MU flag */ + /* TODO: MI flag */ + + CLEAR_ALU_FLAGS(); + m_astat |= (r_sub.f < 0.0f) ? AN : 0; + // AZ + m_astat |= (IS_FLOAT_DENORMAL(r_sub.r) || IS_FLOAT_ZERO(r_sub.r)) ? AZ : 0; + // AU + m_stky |= (IS_FLOAT_DENORMAL(r_sub.r)) ? AUS : 0; + // AI + m_astat |= (IS_FLOAT_NAN(REG(fxa)) || IS_FLOAT_NAN(REG(fya))) ? AI : 0; + /* TODO: AV flag */ + + // AIS + if (m_astat & AI) m_stky |= AIS; + + FREG(fm) = r_mul.f; + FREG(fa) = r_sub.f; + m_astat |= AF; +} + +/* Fm = Fxm * Fym, Fa = FLOAT Fxa BY Fya */ +void adsp21062_device::compute_fmul_float_scaled(int fm, int fxm, int fym, int fa, int fxa, int fya) +{ + SHARC_REG x; + SHARC_REG r_mul, r_alu; + r_mul.f = FREG(fxm) * FREG(fym); + + x.f = (float)(INT32)REG(fxa); + + r_alu.r = SCALB(x, fya); + + CLEAR_MULTIPLIER_FLAGS(); + SET_FLAG_MN(r_mul.r); + /* TODO: MV flag */ + /* TODO: MU flag */ + /* TODO: MI flag */ + + CLEAR_ALU_FLAGS(); + m_astat |= (r_alu.f < 0.0f) ? AN : 0; + // AZ + m_astat |= (IS_FLOAT_DENORMAL(r_alu.r) || IS_FLOAT_ZERO(r_alu.r)) ? AZ : 0; + // AU + m_stky |= (IS_FLOAT_DENORMAL(r_alu.r)) ? AUS : 0; + /* TODO: set AV if overflowed */ + + FREG(fm) = r_mul.f; + FREG(fa) = r_alu.f; + m_astat |= AF; +} + +/* Fm = Fxm * Fym, Fa = FIX Fxa BY Fya */ +void adsp21062_device::compute_fmul_fix_scaled(int fm, int fxm, int fym, int fa, int fxa, int fya) +{ + INT32 alu_i; + SHARC_REG r_mul, r_alu; + r_mul.f = FREG(fxm) * FREG(fym); + + r_alu.r = SCALB(m_r[fxa], fya); + + if (m_mode1 & MODE1_TRUNCATE) + { + alu_i = (INT32)(r_alu.f); + } + else + { + alu_i = (INT32)(r_alu.f < 0 ? (r_alu.f - 0.5f) : (r_alu.f + 0.5f)); + } + + CLEAR_MULTIPLIER_FLAGS(); + SET_FLAG_MN(r_mul.r); + /* TODO: MV flag */ + /* TODO: MU flag */ + /* TODO: MI flag */ + + CLEAR_ALU_FLAGS(); + SET_FLAG_AN(alu_i); + // AZ + SET_FLAG_AZ(alu_i); + // AU + m_stky |= (IS_FLOAT_DENORMAL(r_alu.r)) ? AUS : 0; + // AI + m_astat |= (IS_FLOAT_NAN(REG(fxa))) ? AI : 0; + /* TODO: AV flag */ + + FREG(fm) = r_mul.f; + REG(fa) = alu_i; // TODO: check this, should be RA? + m_astat |= AF; +} + +void adsp21062_device::compute_fmul_avg(int fm, int fxm, int fym, int fa, int fxa, int fya) +{ + INT32 alu_i; + SHARC_REG r_mul, r_alu; + r_mul.f = FREG(fxm) * FREG(fym); + r_alu.f = (FREG(fxa) * FREG(fya))/((float) 2.0); + + /* TODO: are flags right for this? */ + if (m_mode1 & MODE1_TRUNCATE) + { + alu_i = (INT32)(r_alu.f); + } + else + { + alu_i = (INT32)(r_alu.f < 0 ? (r_alu.f - 0.5f) : (r_alu.f + 0.5f)); + } + + CLEAR_MULTIPLIER_FLAGS(); + SET_FLAG_MN(r_mul.r); + /* TODO: MV flag */ + /* TODO: MU flag */ + /* TODO: MI flag */ + + CLEAR_ALU_FLAGS(); + SET_FLAG_AN(alu_i); + // AZ + SET_FLAG_AZ(alu_i); + // AU + m_stky |= (IS_FLOAT_DENORMAL(r_alu.r)) ? AUS : 0; + // AI + m_astat |= (IS_FLOAT_NAN(REG(fxa))) ? AI : 0; + /* TODO: AV flag */ + + FREG(fm) = r_mul.f; + REG(fa) = alu_i; + m_astat |= AF; +} + +/* Fm = Fxm * Fym, Fa = MAX(Fxa, Fya) */ +void adsp21062_device::compute_fmul_fmax(int fm, int fxm, int fym, int fa, int fxa, int fya) +{ + SHARC_REG r_mul, r_alu; + r_mul.f = FREG(fxm) * FREG(fym); + + r_alu.f = MAX(FREG(fxa), FREG(fya)); + + CLEAR_MULTIPLIER_FLAGS(); + SET_FLAG_MN(r_mul.r); + /* TODO: MV flag */ + /* TODO: MU flag */ + /* TODO: MI flag */ + + CLEAR_ALU_FLAGS(); + m_astat |= (r_alu.f < 0.0f) ? AN : 0; + // AZ + m_astat |= (IS_FLOAT_ZERO(r_alu.r)) ? AZ : 0; + // AU + m_stky |= (IS_FLOAT_DENORMAL(r_alu.r)) ? AUS : 0; + // AI + m_astat |= (IS_FLOAT_NAN(REG(fxa)) || IS_FLOAT_NAN(REG(fya))) ? AI : 0; + /* TODO: AV flag */ + + FREG(fm) = r_mul.f; + FREG(fa) = r_alu.f; + m_astat |= AF; +} + + +/* Fm = Fxm * Fym, Fa = MIN(Fxa, Fya) */ +void adsp21062_device::compute_fmul_fmin(int fm, int fxm, int fym, int fa, int fxa, int fya) +{ + SHARC_REG r_mul, r_alu; + r_mul.f = FREG(fxm) * FREG(fym); + + r_alu.f = MIN(FREG(fxa), FREG(fya)); + + CLEAR_MULTIPLIER_FLAGS(); + SET_FLAG_MN(r_mul.r); + /* TODO: MV flag */ + /* TODO: MU flag */ + /* TODO: MI flag */ + + CLEAR_ALU_FLAGS(); + m_astat |= (r_alu.f < 0.0f) ? AN : 0; + // AZ + m_astat |= (IS_FLOAT_ZERO(r_alu.r)) ? AZ : 0; + // AU + m_stky |= (IS_FLOAT_DENORMAL(r_alu.r)) ? AUS : 0; + // AI + m_astat |= (IS_FLOAT_NAN(REG(fxa)) || IS_FLOAT_NAN(REG(fya))) ? AI : 0; + /* TODO: AV flag */ + + FREG(fm) = r_mul.f; + FREG(fa) = r_alu.f; + m_astat |= AF; +} + + + +/* Fm = Fxm * Fym, Fa = Fxa + Fya, Fs = Fxa - Fya */ +void adsp21062_device::compute_fmul_dual_fadd_fsub(int fm, int fxm, int fym, int fa, int fs, int fxa, int fya) +{ + SHARC_REG r_mul, r_add, r_sub; + r_mul.f = FREG(fxm) * FREG(fym); + r_add.f = FREG(fxa) + FREG(fya); + r_sub.f = FREG(fxa) - FREG(fya); + + CLEAR_MULTIPLIER_FLAGS(); + SET_FLAG_MN(r_mul.r); + /* TODO: MV flag */ + /* TODO: MU flag */ + /* TODO: MI flag */ + + CLEAR_ALU_FLAGS(); + // AN + m_astat |= ((r_add.r < 0.0f) || (r_sub.r < 0.0f)) ? AN : 0; + // AZ + m_astat |= (IS_FLOAT_DENORMAL(r_add.r) || IS_FLOAT_ZERO(r_add.r) || + IS_FLOAT_DENORMAL(r_sub.r) || IS_FLOAT_ZERO(r_sub.r)) ? AZ : 0; + // AUS + m_stky |= (IS_FLOAT_DENORMAL(r_add.r) || IS_FLOAT_DENORMAL(r_sub.r)) ? AUS : 0; + // AI + m_astat |= (IS_FLOAT_NAN(REG(fxa)) || IS_FLOAT_NAN(REG(fya))) ? AI : 0; + /* TODO: AV flag */ + + // AIS + if (m_astat & AI) m_stky |= AIS; + + FREG(fm) = r_mul.f; + FREG(fa) = r_add.f; + FREG(fs) = r_sub.f; + m_astat |= AF; +} diff --git a/src/devices/cpu/sharc/sharc.c b/src/devices/cpu/sharc/sharc.c new file mode 100644 index 00000000000..702f36ebe4c --- /dev/null +++ b/src/devices/cpu/sharc/sharc.c @@ -0,0 +1,960 @@ +// license:BSD-3-Clause +// copyright-holders:Ville Linde +/* Analog Devices ADSP-2106x SHARC emulator v2.0 + + Written by Ville Linde +*/ + +#include "emu.h" +#include "debugger.h" +#include "sharc.h" + + +enum +{ + SHARC_PC=1, SHARC_PCSTK, SHARC_MODE1, SHARC_MODE2, + SHARC_ASTAT, SHARC_STKY, SHARC_IRPTL, SHARC_IMASK, + SHARC_IMASKP, SHARC_USTAT1, SHARC_USTAT2, SHARC_LCNTR, + SHARC_R0, SHARC_R1, SHARC_R2, SHARC_R3, + SHARC_R4, SHARC_R5, SHARC_R6, SHARC_R7, + SHARC_R8, SHARC_R9, SHARC_R10, SHARC_R11, + SHARC_R12, SHARC_R13, SHARC_R14, SHARC_R15, + SHARC_SYSCON, SHARC_SYSSTAT, SHARC_MRF, SHARC_MRB, + SHARC_STSTKP, SHARC_PCSTKP, SHARC_LSTKP, + SHARC_FADDR, SHARC_DADDR, + SHARC_I0, SHARC_I1, SHARC_I2, SHARC_I3, + SHARC_I4, SHARC_I5, SHARC_I6, SHARC_I7, + SHARC_I8, SHARC_I9, SHARC_I10, SHARC_I11, + SHARC_I12, SHARC_I13, SHARC_I14, SHARC_I15, + SHARC_M0, SHARC_M1, SHARC_M2, SHARC_M3, + SHARC_M4, SHARC_M5, SHARC_M6, SHARC_M7, + SHARC_M8, SHARC_M9, SHARC_M10, SHARC_M11, + SHARC_M12, SHARC_M13, SHARC_M14, SHARC_M15, + SHARC_L0, SHARC_L1, SHARC_L2, SHARC_L3, + SHARC_L4, SHARC_L5, SHARC_L6, SHARC_L7, + SHARC_L8, SHARC_L9, SHARC_L10, SHARC_L11, + SHARC_L12, SHARC_L13, SHARC_L14, SHARC_L15, + SHARC_B0, SHARC_B1, SHARC_B2, SHARC_B3, + SHARC_B4, SHARC_B5, SHARC_B6, SHARC_B7, + SHARC_B8, SHARC_B9, SHARC_B10, SHARC_B11, + SHARC_B12, SHARC_B13, SHARC_B14, SHARC_B15 +}; + + +#define ROPCODE(pc) ((UINT64)(m_internal_ram[((pc-0x20000) * 3) + 0]) << 32) | \ + ((UINT64)(m_internal_ram[((pc-0x20000) * 3) + 1]) << 16) | \ + ((UINT64)(m_internal_ram[((pc-0x20000) * 3) + 2]) << 0) + + +const device_type ADSP21062 = &device_creator; + + +// This is just used to stop the debugger from complaining about executing from I/O space +static ADDRESS_MAP_START( internal_pgm, AS_PROGRAM, 64, adsp21062_device ) + AM_RANGE(0x20000, 0x7ffff) AM_RAM AM_SHARE("x") +ADDRESS_MAP_END + + +adsp21062_device::adsp21062_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : cpu_device(mconfig, ADSP21062, "ADSP21062", tag, owner, clock, "adsp21062", __FILE__) + , m_program_config("program", ENDIANNESS_LITTLE, 64, 24, -3, ADDRESS_MAP_NAME(internal_pgm)) + , m_data_config("data", ENDIANNESS_LITTLE, 32, 32, -2) + , m_boot_mode(BOOT_MODE_HOST) +{ +} + + +offs_t adsp21062_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( sharc ); + return CPU_DISASSEMBLE_NAME(sharc)(this, buffer, pc, oprom, opram, options); +} + + +void adsp21062_device::CHANGE_PC(UINT32 newpc) +{ + m_pc = newpc; + m_daddr = newpc; + m_faddr = newpc+1; + m_nfaddr = newpc+2; +} + +void adsp21062_device::CHANGE_PC_DELAYED(UINT32 newpc) +{ + m_nfaddr = newpc; + + m_delay_slot1 = m_pc; + m_delay_slot2 = m_daddr; +} + +TIMER_CALLBACK_MEMBER(adsp21062_device::sharc_iop_delayed_write_callback) +{ + switch (m_iop_delayed_reg) + { + case 0x1c: + { + if (m_iop_delayed_data & 0x1) + { + sharc_dma_exec(6); + } + break; + } + + case 0x1d: + { + if (m_iop_delayed_data & 0x1) + { + sharc_dma_exec(7); + } + break; + } + + default: fatalerror("SHARC: sharc_iop_delayed_write: unknown IOP register %02X\n", m_iop_delayed_reg); + } + + m_delayed_iop_timer->adjust(attotime::never, 0); +} + +void adsp21062_device::sharc_iop_delayed_w(UINT32 reg, UINT32 data, int cycles) +{ + m_iop_delayed_reg = reg; + m_iop_delayed_data = data; + + m_delayed_iop_timer->adjust(cycles_to_attotime(cycles), 0); +} + + +/* IOP registers */ +UINT32 adsp21062_device::sharc_iop_r(UINT32 address) +{ + switch (address) + { + case 0x00: return 0; // System configuration + + case 0x37: // DMA status + { + return m_dma_status; + } + default: fatalerror("sharc_iop_r: Unimplemented IOP reg %02X at %08X\n", address, m_pc); + } +} + +void adsp21062_device::sharc_iop_w(UINT32 address, UINT32 data) +{ + switch (address) + { + case 0x00: break; // System configuration + case 0x02: break; // External Memory Wait State Configuration + case 0x04: // External port DMA buffer 0 + /* TODO: Last Bronx uses this to init the program, int_index however is 0? */ + { + external_dma_write(m_extdma_shift,data); + m_extdma_shift++; + if(m_extdma_shift == 3) + m_extdma_shift = 0; + + #if 0 + UINT64 r = pm_read48(m_dma[6].int_index); + + r &= ~((UINT64)(0xffff) << (m_extdma_shift*16)); + r |= ((UINT64)data & 0xffff) << (m_extdma_shift*16); + + pm_write48(m_dma[6].int_index, r); + + m_extdma_shift++; + if (m_extdma_shift == 3) + { + m_extdma_shift = 0; + m_dma[6].int_index ++; + } + #endif + } + break; + + case 0x08: break; // Message Register 0 + case 0x09: break; // Message Register 1 + case 0x0a: break; // Message Register 2 + case 0x0b: break; // Message Register 3 + case 0x0c: break; // Message Register 4 + case 0x0d: break; // Message Register 5 + case 0x0e: break; // Message Register 6 + case 0x0f: break; // Message Register 7 + + case 0x14: // reserved??? written by Last Bronx + case 0x17: break; + + // DMA 6 + case 0x1c: + { + m_dma[6].control = data; + sharc_iop_delayed_w(0x1c, data, 1); + break; + } + + case 0x20: break; + + case 0x40: m_dma[6].int_index = data; return; + case 0x41: m_dma[6].int_modifier = data; return; + case 0x42: m_dma[6].int_count = data; return; + case 0x43: m_dma[6].chain_ptr = data; return; + case 0x44: m_dma[6].gen_purpose = data; return; + case 0x45: m_dma[6].ext_index = data; return; + case 0x46: m_dma[6].ext_modifier = data; return; + case 0x47: m_dma[6].ext_count = data; return; + + // DMA 7 + case 0x1d: + { + m_dma[7].control = data; + sharc_iop_delayed_w(0x1d, data, 30); + break; + } + + case 0x48: m_dma[7].int_index = data; return; + case 0x49: m_dma[7].int_modifier = data; return; + case 0x4a: m_dma[7].int_count = data; return; + case 0x4b: m_dma[7].chain_ptr = data; return; + case 0x4c: m_dma[7].gen_purpose = data; return; + case 0x4d: m_dma[7].ext_index = data; return; + case 0x4e: m_dma[7].ext_modifier = data; return; + case 0x4f: m_dma[7].ext_count = data; return; + + default: fatalerror("sharc_iop_w: Unimplemented IOP reg %02X, %08X at %08X\n", address, data, m_pc); + } +} + + +#include "sharcmem.inc" +#include "sharcdma.inc" +#include "sharcops.inc" +#include "sharcops.h" + + + +void adsp21062_device::build_opcode_table() +{ + int i, j; + int num_ops = sizeof(s_sharc_opcode_table) / sizeof(SHARC_OP); + + for (i=0; i < 512; i++) + { + m_sharc_op[i] = &adsp21062_device::sharcop_unimplemented; + } + + for (i=0; i < 512; i++) + { + UINT16 op = i << 7; + + for (j=0; j < num_ops; j++) + { + if ((s_sharc_opcode_table[j].op_mask & op) == s_sharc_opcode_table[j].op_bits) + { + if (m_sharc_op[i] != &adsp21062_device::sharcop_unimplemented) + { + fatalerror("build_opcode_table: table already filled! (i=%04X, j=%d)\n", i, j); + } + else + { + m_sharc_op[i] = s_sharc_opcode_table[j].handler; + } + } + } + } +} + +/*****************************************************************************/ + +void adsp21062_device::external_iop_write(UINT32 address, UINT32 data) +{ + if (address == 0x1c) + { + if (data != 0) + { + m_dma[6].control = data; + } + } + else + { + osd_printf_debug("SHARC IOP write %08X, %08X\n", address, data); + sharc_iop_w(address, data); + } +} + +void adsp21062_device::external_dma_write(UINT32 address, UINT64 data) +{ + /* + All addresses in the 17-bit index registers are offset by 0x0002 0000, the + first internal RAM location, before they are used by the DMA controller. + */ + + switch ((m_dma[6].control >> 6) & 0x3) + { + case 2: // 16/48 packing + { + int shift = address % 3; + UINT64 r = pm_read48((m_dma[6].int_index & 0x1ffff) | 0x20000); + + r &= ~((UINT64)(0xffff) << (shift*16)); + r |= (data & 0xffff) << (shift*16); + + pm_write48((m_dma[6].int_index & 0x1ffff) | 0x20000, r); + + if (shift == 2) + { + m_dma[6].int_index += m_dma[6].int_modifier; + } + break; + } + default: + { + fatalerror("sharc_external_dma_write: unimplemented packing mode %d\n", (m_dma[6].control >> 6) & 0x3); + } + } +} + +void adsp21062_device::device_start() +{ + int saveindex; + + m_program = &space(AS_PROGRAM); + m_data = &space(AS_DATA); + + build_opcode_table(); + + m_internal_ram_block0 = &m_internal_ram[0]; + m_internal_ram_block1 = &m_internal_ram[0x20000/2]; + + m_delayed_iop_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(adsp21062_device::sharc_iop_delayed_write_callback), this)); + + for (int i=0; i < 12; i++) + { + m_dma_op[i].src = 0; + m_dma_op[i].dst = 0; + m_dma_op[i].chain_ptr = 0; + m_dma_op[i].src_modifier = 0; + m_dma_op[i].dst_modifier = 0; + m_dma_op[i].src_count = 0; + m_dma_op[i].dst_count = 0; + m_dma_op[i].pmode = 0; + m_dma_op[i].chained_direction = 0; + m_dma_op[i].active = false; + m_dma_op[i].timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(adsp21062_device::sharc_dma_callback), this)); + } + + for (int i=0; i < 16; i++) + { + m_r[i].r = 0; + m_reg_alt[i].r = 0; + } + m_mrf = 0; + m_mrb = 0; + for (int i=0; i < 32; i++) + { + m_pcstack[i] = 0; + } + for (int i=0; i < 6; i++) + { + m_lcstack[i] = 0; + m_lastack[i] = 0; + } + m_pcstk = 0; + m_laddr.addr = m_laddr.code = m_laddr.loop_type = 0; + m_curlcntr = 0; + m_lcntr = 0; + for (int i=0; i < 8; i++) + { + m_dag1.i[i] = m_dag1.m[i] = m_dag1.b[i] = m_dag1.l[i] = 0; + m_dag2.i[i] = m_dag2.m[i] = m_dag2.b[i] = m_dag2.l[i] = 0; + m_dag1_alt.i[i] = m_dag1_alt.m[i] = m_dag1_alt.b[i] = m_dag1_alt.l[i] = 0; + m_dag2_alt.i[i] = m_dag2_alt.m[i] = m_dag2_alt.b[i] = m_dag2_alt.l[i] = 0; + } + for (int i=0; i < 12; i++) + { + m_dma[i].control = 0; + m_dma[i].int_index = 0; + m_dma[i].int_modifier = 0; + m_dma[i].int_count = 0; + m_dma[i].chain_ptr = 0; + m_dma[i].gen_purpose = 0; + m_dma[i].ext_index = 0; + m_dma[i].ext_modifier = 0; + m_dma[i].ext_count = 0; + } + m_mode1 = 0; + m_mode2 = 0; + m_astat = 0; + m_irptl = 0; + m_imask = 0; + m_imaskp = 0; + m_ustat1 = 0; + m_ustat2 = 0; + m_flag[0] = m_flag[1] = m_flag[2] = m_flag[3] = 0; + m_syscon = 0; + m_sysstat = 0; + for (int i=0; i < 5; i++) + { + m_status_stack[i].mode1 = 0; + m_status_stack[i].astat = 0; + } + m_status_stkp = 0; + m_px = 0; + m_opcode = 0; + m_irq_active = 0; + m_active_irq_num = 0; + m_dma_status = 0; + m_iop_delayed_reg = 0; + m_iop_delayed_data = 0; + m_delay_slot1 = 0; + m_delay_slot2 = 0; + m_systemreg_latency_cycles = 0; + m_systemreg_latency_reg = 0; + m_systemreg_latency_data = 0; + m_systemreg_previous_data = 0; + m_astat_old = 0; + m_astat_old_old = 0; + m_astat_old_old_old = 0; + + save_item(NAME(m_pc)); + save_pointer(NAME(&m_r[0].r), ARRAY_LENGTH(m_r)); + save_pointer(NAME(&m_reg_alt[0].r), ARRAY_LENGTH(m_reg_alt)); + save_item(NAME(m_mrf)); + save_item(NAME(m_mrb)); + + save_item(NAME(m_pcstack)); + save_item(NAME(m_lcstack)); + save_item(NAME(m_lastack)); + save_item(NAME(m_lstkp)); + + save_item(NAME(m_faddr)); + save_item(NAME(m_daddr)); + save_item(NAME(m_pcstk)); + save_item(NAME(m_pcstkp)); + save_item(NAME(m_laddr.addr)); + save_item(NAME(m_laddr.code)); + save_item(NAME(m_laddr.loop_type)); + save_item(NAME(m_curlcntr)); + save_item(NAME(m_lcntr)); + + save_item(NAME(m_dag1.i)); + save_item(NAME(m_dag1.m)); + save_item(NAME(m_dag1.b)); + save_item(NAME(m_dag1.l)); + save_item(NAME(m_dag2.i)); + save_item(NAME(m_dag2.m)); + save_item(NAME(m_dag2.b)); + save_item(NAME(m_dag2.l)); + save_item(NAME(m_dag1_alt.i)); + save_item(NAME(m_dag1_alt.m)); + save_item(NAME(m_dag1_alt.b)); + save_item(NAME(m_dag1_alt.l)); + save_item(NAME(m_dag2_alt.i)); + save_item(NAME(m_dag2_alt.m)); + save_item(NAME(m_dag2_alt.b)); + save_item(NAME(m_dag2_alt.l)); + + for (saveindex = 0; saveindex < ARRAY_LENGTH(m_dma); saveindex++) + { + save_item(NAME(m_dma[saveindex].control), saveindex); + save_item(NAME(m_dma[saveindex].int_index), saveindex); + save_item(NAME(m_dma[saveindex].int_modifier), saveindex); + save_item(NAME(m_dma[saveindex].int_count), saveindex); + save_item(NAME(m_dma[saveindex].chain_ptr), saveindex); + save_item(NAME(m_dma[saveindex].gen_purpose), saveindex); + save_item(NAME(m_dma[saveindex].ext_index), saveindex); + save_item(NAME(m_dma[saveindex].ext_modifier), saveindex); + save_item(NAME(m_dma[saveindex].ext_count), saveindex); + } + + save_item(NAME(m_mode1)); + save_item(NAME(m_mode2)); + save_item(NAME(m_astat)); + save_item(NAME(m_stky)); + save_item(NAME(m_irptl)); + save_item(NAME(m_imask)); + save_item(NAME(m_imaskp)); + save_item(NAME(m_ustat1)); + save_item(NAME(m_ustat2)); + + save_item(NAME(m_flag)); + + save_item(NAME(m_syscon)); + save_item(NAME(m_sysstat)); + + for (saveindex = 0; saveindex < ARRAY_LENGTH(m_status_stack); saveindex++) + { + save_item(NAME(m_status_stack[saveindex].mode1), saveindex); + save_item(NAME(m_status_stack[saveindex].astat), saveindex); + } + save_item(NAME(m_status_stkp)); + + save_item(NAME(m_px)); + + save_pointer(NAME(m_internal_ram), 2 * 0x10000); + + save_item(NAME(m_opcode)); + + save_item(NAME(m_nfaddr)); + + save_item(NAME(m_idle)); + save_item(NAME(m_irq_active)); + save_item(NAME(m_active_irq_num)); + + for (saveindex = 0; saveindex < ARRAY_LENGTH(m_dma_op); saveindex++) + { + save_item(NAME(m_dma_op[saveindex].src), saveindex); + save_item(NAME(m_dma_op[saveindex].dst), saveindex); + save_item(NAME(m_dma_op[saveindex].chain_ptr), saveindex); + save_item(NAME(m_dma_op[saveindex].src_modifier), saveindex); + save_item(NAME(m_dma_op[saveindex].dst_modifier), saveindex); + save_item(NAME(m_dma_op[saveindex].src_count), saveindex); + save_item(NAME(m_dma_op[saveindex].dst_count), saveindex); + save_item(NAME(m_dma_op[saveindex].pmode), saveindex); + save_item(NAME(m_dma_op[saveindex].chained_direction), saveindex); + save_item(NAME(m_dma_op[saveindex].active), saveindex); + } + + save_item(NAME(m_dma_status)); + + save_item(NAME(m_interrupt_active)); + + save_item(NAME(m_iop_delayed_reg)); + save_item(NAME(m_iop_delayed_data)); + + save_item(NAME(m_delay_slot1)); + save_item(NAME(m_delay_slot2)); + + save_item(NAME(m_systemreg_latency_cycles)); + save_item(NAME(m_systemreg_latency_reg)); + save_item(NAME(m_systemreg_latency_data)); + save_item(NAME(m_systemreg_previous_data)); + + save_item(NAME(m_astat_old)); + save_item(NAME(m_astat_old_old)); + save_item(NAME(m_astat_old_old_old)); + + state_add( SHARC_PC, "PC", m_pc).formatstr("%08X"); + state_add( SHARC_PCSTK, "PCSTK", m_pcstk).formatstr("%08X"); + state_add( SHARC_PCSTKP, "PCSTKP", m_pcstkp).formatstr("%08X"); + state_add( SHARC_LSTKP, "LSTKP", m_lstkp).formatstr("%08X"); + state_add( SHARC_FADDR, "FADDR", m_faddr).formatstr("%08X"); + state_add( SHARC_DADDR, "DADDR", m_daddr).formatstr("%08X"); + state_add( SHARC_MODE1, "MODE1", m_mode1).formatstr("%08X"); + state_add( SHARC_MODE2, "MODE2", m_mode2).formatstr("%08X"); + state_add( SHARC_ASTAT, "ASTAT", m_astat).formatstr("%08X"); + state_add( SHARC_IRPTL, "IRPTL", m_irptl).formatstr("%08X"); + state_add( SHARC_IMASK, "IMASK", m_imask).formatstr("%08X"); + state_add( SHARC_USTAT1, "USTAT1", m_ustat1).formatstr("%08X"); + state_add( SHARC_USTAT2, "USTAT2", m_ustat2).formatstr("%08X"); + state_add( SHARC_STSTKP, "STSTKP", m_status_stkp).formatstr("%08X"); + + state_add( SHARC_R0, "R0", m_r[0].r).formatstr("%08X"); + state_add( SHARC_R1, "R1", m_r[1].r).formatstr("%08X"); + state_add( SHARC_R2, "R2", m_r[2].r).formatstr("%08X"); + state_add( SHARC_R3, "R3", m_r[3].r).formatstr("%08X"); + state_add( SHARC_R4, "R4", m_r[4].r).formatstr("%08X"); + state_add( SHARC_R5, "R5", m_r[5].r).formatstr("%08X"); + state_add( SHARC_R6, "R6", m_r[6].r).formatstr("%08X"); + state_add( SHARC_R7, "R7", m_r[7].r).formatstr("%08X"); + state_add( SHARC_R8, "R8", m_r[8].r).formatstr("%08X"); + state_add( SHARC_R9, "R9", m_r[9].r).formatstr("%08X"); + state_add( SHARC_R10, "R10", m_r[10].r).formatstr("%08X"); + state_add( SHARC_R11, "R11", m_r[11].r).formatstr("%08X"); + state_add( SHARC_R12, "R12", m_r[12].r).formatstr("%08X"); + state_add( SHARC_R13, "R13", m_r[13].r).formatstr("%08X"); + state_add( SHARC_R14, "R14", m_r[14].r).formatstr("%08X"); + state_add( SHARC_R15, "R15", m_r[15].r).formatstr("%08X"); + + state_add( SHARC_I0, "I0", m_dag1.i[0]).formatstr("%08X"); + state_add( SHARC_I1, "I1", m_dag1.i[1]).formatstr("%08X"); + state_add( SHARC_I2, "I2", m_dag1.i[2]).formatstr("%08X"); + state_add( SHARC_I3, "I3", m_dag1.i[3]).formatstr("%08X"); + state_add( SHARC_I4, "I4", m_dag1.i[4]).formatstr("%08X"); + state_add( SHARC_I5, "I5", m_dag1.i[5]).formatstr("%08X"); + state_add( SHARC_I6, "I6", m_dag1.i[6]).formatstr("%08X"); + state_add( SHARC_I7, "I7", m_dag1.i[7]).formatstr("%08X"); + state_add( SHARC_I8, "I8", m_dag2.i[0]).formatstr("%08X"); + state_add( SHARC_I9, "I9", m_dag2.i[1]).formatstr("%08X"); + state_add( SHARC_I10, "I10", m_dag2.i[2]).formatstr("%08X"); + state_add( SHARC_I11, "I11", m_dag2.i[3]).formatstr("%08X"); + state_add( SHARC_I12, "I12", m_dag2.i[4]).formatstr("%08X"); + state_add( SHARC_I13, "I13", m_dag2.i[5]).formatstr("%08X"); + state_add( SHARC_I14, "I14", m_dag2.i[6]).formatstr("%08X"); + state_add( SHARC_I15, "I15", m_dag2.i[7]).formatstr("%08X"); + + state_add( SHARC_M0, "M0", m_dag1.m[0]).formatstr("%08X"); + state_add( SHARC_M1, "M1", m_dag1.m[1]).formatstr("%08X"); + state_add( SHARC_M2, "M2", m_dag1.m[2]).formatstr("%08X"); + state_add( SHARC_M3, "M3", m_dag1.m[3]).formatstr("%08X"); + state_add( SHARC_M4, "M4", m_dag1.m[4]).formatstr("%08X"); + state_add( SHARC_M5, "M5", m_dag1.m[5]).formatstr("%08X"); + state_add( SHARC_M6, "M6", m_dag1.m[6]).formatstr("%08X"); + state_add( SHARC_M7, "M7", m_dag1.m[7]).formatstr("%08X"); + state_add( SHARC_M8, "M8", m_dag2.m[0]).formatstr("%08X"); + state_add( SHARC_M9, "M9", m_dag2.m[1]).formatstr("%08X"); + state_add( SHARC_M10, "M10", m_dag2.m[2]).formatstr("%08X"); + state_add( SHARC_M11, "M11", m_dag2.m[3]).formatstr("%08X"); + state_add( SHARC_M12, "M12", m_dag2.m[4]).formatstr("%08X"); + state_add( SHARC_M13, "M13", m_dag2.m[5]).formatstr("%08X"); + state_add( SHARC_M14, "M14", m_dag2.m[6]).formatstr("%08X"); + state_add( SHARC_M15, "M15", m_dag2.m[7]).formatstr("%08X"); + + state_add( SHARC_L0, "L0", m_dag1.l[0]).formatstr("%08X"); + state_add( SHARC_L1, "L1", m_dag1.l[1]).formatstr("%08X"); + state_add( SHARC_L2, "L2", m_dag1.l[2]).formatstr("%08X"); + state_add( SHARC_L3, "L3", m_dag1.l[3]).formatstr("%08X"); + state_add( SHARC_L4, "L4", m_dag1.l[4]).formatstr("%08X"); + state_add( SHARC_L5, "L5", m_dag1.l[5]).formatstr("%08X"); + state_add( SHARC_L6, "L6", m_dag1.l[6]).formatstr("%08X"); + state_add( SHARC_L7, "L7", m_dag1.l[7]).formatstr("%08X"); + state_add( SHARC_L8, "L8", m_dag2.l[0]).formatstr("%08X"); + state_add( SHARC_L9, "L9", m_dag2.l[1]).formatstr("%08X"); + state_add( SHARC_L10, "L10", m_dag2.l[2]).formatstr("%08X"); + state_add( SHARC_L11, "L11", m_dag2.l[3]).formatstr("%08X"); + state_add( SHARC_L12, "L12", m_dag2.l[4]).formatstr("%08X"); + state_add( SHARC_L13, "L13", m_dag2.l[5]).formatstr("%08X"); + state_add( SHARC_L14, "L14", m_dag2.l[6]).formatstr("%08X"); + state_add( SHARC_L15, "L15", m_dag2.l[7]).formatstr("%08X"); + + state_add( SHARC_B0, "B0", m_dag1.b[0]).formatstr("%08X"); + state_add( SHARC_B1, "B1", m_dag1.b[1]).formatstr("%08X"); + state_add( SHARC_B2, "B2", m_dag1.b[2]).formatstr("%08X"); + state_add( SHARC_B3, "B3", m_dag1.b[3]).formatstr("%08X"); + state_add( SHARC_B4, "B4", m_dag1.b[4]).formatstr("%08X"); + state_add( SHARC_B5, "B5", m_dag1.b[5]).formatstr("%08X"); + state_add( SHARC_B6, "B6", m_dag1.b[6]).formatstr("%08X"); + state_add( SHARC_B7, "B7", m_dag1.b[7]).formatstr("%08X"); + state_add( SHARC_B8, "B8", m_dag2.b[0]).formatstr("%08X"); + state_add( SHARC_B9, "B9", m_dag2.b[1]).formatstr("%08X"); + state_add( SHARC_B10, "B10", m_dag2.b[2]).formatstr("%08X"); + state_add( SHARC_B11, "B11", m_dag2.b[3]).formatstr("%08X"); + state_add( SHARC_B12, "B12", m_dag2.b[4]).formatstr("%08X"); + state_add( SHARC_B13, "B13", m_dag2.b[5]).formatstr("%08X"); + state_add( SHARC_B14, "B14", m_dag2.b[6]).formatstr("%08X"); + state_add( SHARC_B15, "B15", m_dag2.b[7]).formatstr("%08X"); + + state_add( STATE_GENPC, "GENPC", m_pc).noshow(); + + m_icountptr = &m_icount; +} + +void adsp21062_device::device_reset() +{ + memset(m_internal_ram, 0, 2 * 0x10000 * sizeof(UINT16)); + + switch(m_boot_mode) + { + case BOOT_MODE_EPROM: + { + m_dma[6].int_index = 0x20000; + m_dma[6].int_modifier = 1; + m_dma[6].int_count = 0x100; + m_dma[6].ext_index = 0x400000; + m_dma[6].ext_modifier = 1; + m_dma[6].ext_count = 0x600; + m_dma[6].control = 0x2a1; + + sharc_dma_exec(6); + dma_op(6); + + m_dma_op[6].timer->adjust(attotime::never, 0); + break; + } + + case BOOT_MODE_HOST: + { + m_dma[6].int_index = 0x20000; + m_dma[6].int_modifier = 1; + m_dma[6].int_count = 0x100; + m_dma[6].control = 0xa1; + break; + } + + default: + fatalerror("SHARC: Unimplemented boot mode %d\n", m_boot_mode); + } + + m_pc = 0x20004; + m_extdma_shift = 0; + m_daddr = m_pc + 1; + m_faddr = m_daddr + 1; + m_nfaddr = m_faddr+1; + + m_idle = 0; + m_stky = 0x5400000; + + m_lstkp = 0; + m_pcstkp = 0; + m_interrupt_active = 0; +} + + +void adsp21062_device::execute_set_input(int irqline, int state) +{ + if (irqline >= 0 && irqline <= 2) + { + if (state == ASSERT_LINE) + { + m_irq_active |= 1 << (8-irqline); + } + else + { + m_irq_active &= ~(1 << (8-irqline)); + } + } + else if (irqline >= SHARC_INPUT_FLAG0 && irqline <= SHARC_INPUT_FLAG3) + { + set_flag_input(irqline - SHARC_INPUT_FLAG0, state); + } +} + +void adsp21062_device::set_flag_input(int flag_num, int state) +{ + if (flag_num >= 0 && flag_num < 4) + { + // Check if flag is set to input in MODE2 (bit == 0) + if ((m_mode2 & (1 << (flag_num+15))) == 0) + { + m_flag[flag_num] = state ? 1 : 0; + } + else + { + fatalerror("sharc_set_flag_input: flag %d is set output!\n", flag_num); + } + } +} + +void adsp21062_device::check_interrupts() +{ + int i; + if ((m_imask & m_irq_active) && (m_mode1 & MODE1_IRPTEN) && !m_interrupt_active && + m_pc != m_delay_slot1 && m_pc != m_delay_slot2) + { + int which = 0; + for (i=0; i < 32; i++) + { + if (m_irq_active & (1 << i)) + { + break; + } + which++; + } + + if (m_idle) + { + PUSH_PC(m_pc+1); + } + else + { + PUSH_PC(m_daddr); + } + + m_irptl |= 1 << which; + + if (which >= 6 && which <= 8) + { + PUSH_STATUS_STACK(); + } + + CHANGE_PC(0x20000 + (which * 0x4)); + + /* TODO: alter IMASKP */ + + m_active_irq_num = which; + m_irq_active &= ~(1 << which); + + m_interrupt_active = 1; + } +} + +void adsp21062_device::execute_run() +{ + if (m_idle && m_irq_active == 0) + { + m_icount = 0; + debugger_instruction_hook(this, m_daddr); + } + if (m_irq_active != 0) + { + check_interrupts(); + m_idle = 0; + } + + while (m_icount > 0 && !m_idle) + { + m_pc = m_daddr; + m_daddr = m_faddr; + m_faddr = m_nfaddr; + m_nfaddr++; + + m_astat_old_old_old = m_astat_old_old; + m_astat_old_old = m_astat_old; + m_astat_old = m_astat; + + m_opcode = ROPCODE(m_pc); + + debugger_instruction_hook(this, m_pc); + + // handle looping + if (m_pc == m_laddr.addr) + { + switch (m_laddr.loop_type) + { + case 0: // arithmetic condition-based + { + int condition = m_laddr.code; + + { + UINT32 looptop = TOP_PC(); + if (m_pc - looptop > 2) + { + m_astat = m_astat_old_old_old; + } + } + + if (DO_CONDITION_CODE(condition)) + { + POP_LOOP(); + POP_PC(); + } + else + { + CHANGE_PC(TOP_PC()); + } + + m_astat = m_astat_old; + break; + } + case 1: // counter-based, length 1 + { + //fatalerror("SHARC: counter-based loop, length 1 at %08X\n", m_pc); + //break; + } + case 2: // counter-based, length 2 + { + //fatalerror("SHARC: counter-based loop, length 2 at %08X\n", m_pc); + //break; + } + case 3: // counter-based, length >2 + { + --m_lcstack[m_lstkp]; + --m_curlcntr; + if (m_curlcntr == 0) + { + POP_LOOP(); + POP_PC(); + } + else + { + CHANGE_PC(TOP_PC()); + } + } + } + } + + (this->*m_sharc_op[(m_opcode >> 39) & 0x1ff])(); + + + + + // System register latency effect + if (m_systemreg_latency_cycles > 0) + { + --m_systemreg_latency_cycles; + if (m_systemreg_latency_cycles <= 0) + { + systemreg_write_latency_effect(); + } + } + + --m_icount; + }; +} + +bool adsp21062_device::memory_read(address_spacenum spacenum, offs_t offset, int size, UINT64 &value) +{ + if (spacenum == AS_PROGRAM) + { + int address = offset >> 3; + + if (address >= 0x20000 && address < 0x30000) + { + switch (size) + { + case 1: + { + int frac = offset & 7; + value = (pm_read48(offset >> 3) >> ((frac^7) * 8)) & 0xff; + break; + } + case 8: + { + value = pm_read48(offset >> 3); + break; + } + } + } + else + { + value = 0; + } + } + else if (spacenum == AS_DATA) + { + int address = offset >> 2; + + if (address >= 0x20000) + { + switch (size) + { + case 1: + { + int frac = offset & 3; + value = (dm_read32(offset >> 2) >> ((frac^3) * 8)) & 0xff; + break; + } + case 2: + { + int frac = (offset >> 1) & 1; + value = (dm_read32(offset >> 2) >> ((frac^1) * 16)) & 0xffff; + break; + } + case 4: + { + value = dm_read32(offset >> 2); + break; + } + } + } + else + { + value = 0; + } + } + return true; +} + +bool adsp21062_device::memory_readop(offs_t offset, int size, UINT64 &value) +{ + UINT64 mask = (size < 8) ? (((UINT64)1 << (8 * size)) - 1) : ~(UINT64)0; + int shift = 8 * (offset & 7); + offset >>= 3; + + if (offset >= 0x20000 && offset < 0x28000) + { + UINT64 op = ((UINT64)(m_internal_ram_block0[((offset-0x20000) * 3) + 0]) << 32) | + ((UINT64)(m_internal_ram_block0[((offset-0x20000) * 3) + 1]) << 16) | + ((UINT64)(m_internal_ram_block0[((offset-0x20000) * 3) + 2]) << 0); + value = (op >> shift) & mask; + return true; + } + else if (offset >= 0x28000 && offset < 0x30000) + { + UINT64 op = ((UINT64)(m_internal_ram_block1[((offset-0x28000) * 3) + 0]) << 32) | + ((UINT64)(m_internal_ram_block1[((offset-0x28000) * 3) + 1]) << 16) | + ((UINT64)(m_internal_ram_block1[((offset-0x28000) * 3) + 2]) << 0); + value = (op >> shift) & mask; + return true; + } + + return false; +} diff --git a/src/devices/cpu/sharc/sharc.h b/src/devices/cpu/sharc/sharc.h new file mode 100644 index 00000000000..52f6d91ecd9 --- /dev/null +++ b/src/devices/cpu/sharc/sharc.h @@ -0,0 +1,358 @@ +// license:BSD-3-Clause +// copyright-holders:Ville Linde +#pragma once + +#ifndef __SHARC_H__ +#define __SHARC_H__ + + +#define SHARC_INPUT_FLAG0 3 +#define SHARC_INPUT_FLAG1 4 +#define SHARC_INPUT_FLAG2 5 +#define SHARC_INPUT_FLAG3 6 + + +enum SHARC_BOOT_MODE +{ + BOOT_MODE_EPROM, + BOOT_MODE_HOST, + BOOT_MODE_LINK, + BOOT_MODE_NOBOOT +}; + + +struct SHARC_DAG +{ + UINT32 i[8]; + UINT32 m[8]; + UINT32 b[8]; + UINT32 l[8]; +}; + +union SHARC_REG +{ + INT32 r; + float f; +}; + +struct SHARC_DMA_REGS +{ + UINT32 control; + UINT32 int_index; + UINT32 int_modifier; + UINT32 int_count; + UINT32 chain_ptr; + UINT32 gen_purpose; + UINT32 ext_index; + UINT32 ext_modifier; + UINT32 ext_count; +}; + +struct SHARC_LADDR +{ + UINT32 addr; + UINT32 code; + UINT32 loop_type; +}; + +struct SHARC_DMA_OP +{ + UINT32 src; + UINT32 dst; + UINT32 chain_ptr; + INT32 src_modifier; + INT32 dst_modifier; + INT32 src_count; + INT32 dst_count; + INT32 pmode; + INT32 chained_direction; + emu_timer *timer; + bool active; +}; + + +#define MCFG_SHARC_BOOT_MODE(boot_mode) \ + adsp21062_device::set_boot_mode(*device, boot_mode); + + +class adsp21062_device : public cpu_device +{ +public: + // construction/destruction + adsp21062_device(const machine_config &mconfig, const char *_tag, device_t *_owner, UINT32 _clock); + + // static configuration helpers + static void set_boot_mode(device_t &device, const SHARC_BOOT_MODE boot_mode) { downcast(device).m_boot_mode = boot_mode; } + + void set_flag_input(int flag_num, int state); + void external_iop_write(UINT32 address, UINT32 data); + void external_dma_write(UINT32 address, UINT64 data); + + TIMER_CALLBACK_MEMBER(sharc_iop_delayed_write_callback); + TIMER_CALLBACK_MEMBER(sharc_dma_callback); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_execute_interface overrides + virtual UINT32 execute_min_cycles() const { return 8; } + virtual UINT32 execute_max_cycles() const { return 8; } + virtual UINT32 execute_input_lines() const { return 32; } + virtual void execute_run(); + virtual void execute_set_input(int inputnum, int state); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const { return (spacenum == AS_PROGRAM) ? &m_program_config : ( (spacenum == AS_DATA) ? &m_data_config : NULL ); } + virtual bool memory_read(address_spacenum spacenum, offs_t offset, int size, UINT64 &value); + virtual bool memory_readop(offs_t offset, int size, UINT64 &value); + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const { return 1; } + virtual UINT32 disasm_max_opcode_bytes() const { return 40; } + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + +private: + address_space_config m_program_config; + address_space_config m_data_config; + + typedef void (adsp21062_device::*opcode_func)(); + struct SHARC_OP + { + UINT32 op_mask; + UINT32 op_bits; + opcode_func handler; + }; + static const SHARC_OP s_sharc_opcode_table[]; + + UINT32 m_pc; + SHARC_REG m_r[16]; + SHARC_REG m_reg_alt[16]; + UINT64 m_mrf; + UINT64 m_mrb; + + UINT32 m_pcstack[32]; + UINT32 m_lcstack[6]; + UINT32 m_lastack[6]; + UINT32 m_lstkp; + + UINT32 m_faddr; + UINT32 m_daddr; + UINT32 m_pcstk; + UINT32 m_pcstkp; + SHARC_LADDR m_laddr; + UINT32 m_curlcntr; + UINT32 m_lcntr; + UINT8 m_extdma_shift; + + /* Data Address Generator (DAG) */ + SHARC_DAG m_dag1; // (DM bus) + SHARC_DAG m_dag2; // (PM bus) + SHARC_DAG m_dag1_alt; + SHARC_DAG m_dag2_alt; + + SHARC_DMA_REGS m_dma[12]; + + /* System registers */ + UINT32 m_mode1; + UINT32 m_mode2; + UINT32 m_astat; + UINT32 m_stky; + UINT32 m_irptl; + UINT32 m_imask; + UINT32 m_imaskp; + UINT32 m_ustat1; + UINT32 m_ustat2; + + UINT32 m_flag[4]; + + UINT32 m_syscon; + UINT32 m_sysstat; + + struct + { + UINT32 mode1; + UINT32 astat; + } m_status_stack[5]; + INT32 m_status_stkp; + + UINT64 m_px; + + UINT16 *m_internal_ram_block0, *m_internal_ram_block1; + + address_space *m_program; + address_space *m_data; + opcode_func m_sharc_op[512]; + int m_icount; + UINT64 m_opcode; + + UINT32 m_nfaddr; + + INT32 m_idle; + INT32 m_irq_active; + INT32 m_active_irq_num; + + SHARC_BOOT_MODE m_boot_mode; + + SHARC_DMA_OP m_dma_op[12]; + UINT32 m_dma_status; + + INT32 m_interrupt_active; + + UINT32 m_iop_delayed_reg; + UINT32 m_iop_delayed_data; + emu_timer *m_delayed_iop_timer; + + UINT32 m_delay_slot1, m_delay_slot2; + + INT32 m_systemreg_latency_cycles; + INT32 m_systemreg_latency_reg; + UINT32 m_systemreg_latency_data; + UINT32 m_systemreg_previous_data; + + UINT32 m_astat_old; + UINT32 m_astat_old_old; + UINT32 m_astat_old_old_old; + + UINT16 m_internal_ram[2 * 0x10000]; // 2x 128KB + + inline void CHANGE_PC(UINT32 newpc); + inline void CHANGE_PC_DELAYED(UINT32 newpc); + void sharc_iop_delayed_w(UINT32 reg, UINT32 data, int cycles); + UINT32 sharc_iop_r(UINT32 address); + void sharc_iop_w(UINT32 address, UINT32 data); + UINT32 pm_read32(UINT32 address); + void pm_write32(UINT32 address, UINT32 data); + UINT64 pm_read48(UINT32 address); + void pm_write48(UINT32 address, UINT64 data); + UINT32 dm_read32(UINT32 address); + void dm_write32(UINT32 address, UINT32 data); + void schedule_chained_dma_op(int channel, UINT32 dma_chain_ptr, int chained_direction); + void schedule_dma_op(int channel, UINT32 src, UINT32 dst, int src_modifier, int dst_modifier, int src_count, int dst_count, int pmode); + void dma_op(int channel); + void sharc_dma_exec(int channel); + void add_systemreg_write_latency_effect(int sysreg, UINT32 data, UINT32 prev_data); + inline void swap_register(UINT32 *a, UINT32 *b); + void systemreg_write_latency_effect(); + UINT32 GET_UREG(int ureg); + void SET_UREG(int ureg, UINT32 data); + void SHIFT_OPERATION_IMM(int shiftop, int data, int rn, int rx); + void COMPUTE(UINT32 opcode); + void check_interrupts(); + inline void PUSH_PC(UINT32 pc); + inline UINT32 POP_PC(); + inline UINT32 TOP_PC(); + inline void PUSH_LOOP(UINT32 addr, UINT32 code, UINT32 type, UINT32 count); + inline void POP_LOOP(); + inline void PUSH_STATUS_STACK(); + inline void POP_STATUS_STACK(); + inline int IF_CONDITION_CODE(int cond); + inline int DO_CONDITION_CODE(int cond); + void sharcop_compute_dreg_dm_dreg_pm(); + void sharcop_compute(); + void sharcop_compute_ureg_dmpm_premod(); + void sharcop_compute_ureg_dmpm_postmod(); + void sharcop_compute_dm_to_dreg_immmod(); + void sharcop_compute_dreg_to_dm_immmod(); + void sharcop_compute_pm_to_dreg_immmod(); + void sharcop_compute_dreg_to_pm_immmod(); + void sharcop_compute_ureg_to_ureg(); + void sharcop_imm_shift_dreg_dmpm(); + void sharcop_imm_shift(); + void sharcop_compute_modify(); + void sharcop_direct_call(); + void sharcop_direct_jump(); + void sharcop_relative_call(); + void sharcop_relative_jump(); + void sharcop_indirect_jump(); + void sharcop_indirect_call(); + void sharcop_relative_jump_compute(); + void sharcop_relative_call_compute(); + void sharcop_indirect_jump_compute_dreg_dm(); + void sharcop_relative_jump_compute_dreg_dm(); + void sharcop_rts(); + void sharcop_rti(); + void sharcop_do_until_counter_imm(); + void sharcop_do_until_counter_ureg(); + void sharcop_do_until(); + void sharcop_dm_to_ureg_direct(); + void sharcop_ureg_to_dm_direct(); + void sharcop_pm_to_ureg_direct(); + void sharcop_ureg_to_pm_direct(); + void sharcop_dm_to_ureg_indirect(); + void sharcop_ureg_to_dm_indirect(); + void sharcop_pm_to_ureg_indirect(); + void sharcop_ureg_to_pm_indirect(); + void sharcop_imm_to_dmpm(); + void sharcop_imm_to_ureg(); + void sharcop_sysreg_bitop(); + void sharcop_modify(); + void sharcop_bit_reverse(); + void sharcop_push_pop_stacks(); + void sharcop_nop(); + void sharcop_idle(); + void sharcop_unimplemented(); + inline void compute_add(int rn, int rx, int ry); + inline void compute_sub(int rn, int rx, int ry); + inline void compute_add_ci(int rn, int rx, int ry); + inline void compute_sub_ci(int rn, int rx, int ry); + inline void compute_and(int rn, int rx, int ry); + inline void compute_comp(int rx, int ry); + inline void compute_pass(int rn, int rx); + inline void compute_xor(int rn, int rx, int ry); + inline void compute_or(int rn, int rx, int ry); + inline void compute_inc(int rn, int rx); + inline void compute_dec(int rn, int rx); + inline void compute_min(int rn, int rx, int ry); + inline void compute_max(int rn, int rx, int ry); + inline void compute_neg(int rn, int rx); + inline void compute_not(int rn, int rx); + inline UINT32 SCALB(SHARC_REG rx, int ry); + inline void compute_float(int rn, int rx); + inline void compute_fix(int rn, int rx); + inline void compute_fix_scaled(int rn, int rx, int ry); + inline void compute_float_scaled(int rn, int rx, int ry); + inline void compute_logb(int rn, int rx); + inline void compute_scalb(int rn, int rx, int ry); + inline void compute_fadd(int rn, int rx, int ry); + inline void compute_fsub(int rn, int rx, int ry); + inline void compute_favg(int rn, int rx, int ry); + inline void compute_fneg(int rn, int rx); + inline void compute_fcomp(int rx, int ry); + inline void compute_fabs_plus(int rn, int rx, int ry); + inline void compute_fmax(int rn, int rx, int ry); + inline void compute_fmin(int rn, int rx, int ry); + inline void compute_fclip(int rn, int rx, int ry); + inline void compute_recips(int rn, int rx); + inline void compute_rsqrts(int rn, int rx); + inline void compute_fpass(int rn, int rx); + inline void compute_fabs(int rn, int rx); + inline void compute_mul_uuin(int rn, int rx, int ry); + inline void compute_mul_ssin(int rn, int rx, int ry); + inline UINT32 compute_mrf_plus_mul_ssin(int rx, int ry); + inline UINT32 compute_mrb_plus_mul_ssin(int rx, int ry); + inline void compute_fmul(int rn, int rx, int ry); + inline void compute_multi_mr_to_reg(int ai, int rk); + inline void compute_multi_reg_to_mr(int ai, int rk); + inline void compute_dual_add_sub(int ra, int rs, int rx, int ry); + inline void compute_mul_ssfr_add(int rm, int rxm, int rym, int ra, int rxa, int rya); + inline void compute_mul_ssfr_sub(int rm, int rxm, int rym, int ra, int rxa, int rya); + inline void compute_dual_fadd_fsub(int ra, int rs, int rx, int ry); + inline void compute_fmul_fadd(int fm, int fxm, int fym, int fa, int fxa, int fya); + inline void compute_fmul_fsub(int fm, int fxm, int fym, int fa, int fxa, int fya); + inline void compute_fmul_float_scaled(int fm, int fxm, int fym, int fa, int fxa, int fya); + inline void compute_fmul_fix_scaled(int fm, int fxm, int fym, int fa, int fxa, int fya); + inline void compute_fmul_avg(int fm, int fxm, int fym, int fa, int fxa, int fya); + inline void compute_fmul_fmax(int fm, int fxm, int fym, int fa, int fxa, int fya); + inline void compute_fmul_fmin(int fm, int fxm, int fym, int fa, int fxa, int fya); + inline void compute_fmul_dual_fadd_fsub(int fm, int fxm, int fym, int fa, int fs, int fxa, int fya); + void build_opcode_table(); + +}; + + +extern const device_type ADSP21062; + + +#endif /* __SHARC_H__ */ diff --git a/src/devices/cpu/sharc/sharcdma.inc b/src/devices/cpu/sharc/sharcdma.inc new file mode 100644 index 00000000000..eacede6fb5b --- /dev/null +++ b/src/devices/cpu/sharc/sharcdma.inc @@ -0,0 +1,246 @@ +// license:BSD-3-Clause +// copyright-holders:Ville Linde +/* SHARC DMA operations */ + +#define DMA_PMODE_NO_PACKING 0 +#define DMA_PMODE_16_32 1 +#define DMA_PMODE_16_48 2 +#define DMA_PMODE_32_48 3 +#define DMA_PMODE_8_48 4 + +void adsp21062_device::schedule_chained_dma_op(int channel, UINT32 dma_chain_ptr, int chained_direction) +{ + UINT32 op_ptr = 0x20000 + dma_chain_ptr; + + UINT32 int_index = dm_read32(op_ptr - 0); + UINT32 int_modifier = dm_read32(op_ptr - 1); + UINT32 int_count = dm_read32(op_ptr - 2); + UINT32 chain_ptr = dm_read32(op_ptr - 3); + //UINT32 gen_purpose = dm_read32(op_ptr - 4); + UINT32 ext_index = dm_read32(op_ptr - 5); + UINT32 ext_modifier = dm_read32(op_ptr - 6); + UINT32 ext_count = dm_read32(op_ptr - 7); + + if (m_dma_op[channel].active) + { + fatalerror("schedule_chained_dma_op: DMA operation already scheduled at %08X!\n", m_pc); + } + + if (chained_direction) // Transmit to external + { + m_dma_op[channel].dst = ext_index; + m_dma_op[channel].dst_modifier = ext_modifier; + m_dma_op[channel].dst_count = ext_count; + m_dma_op[channel].src = int_index; + m_dma_op[channel].src_modifier = int_modifier; + m_dma_op[channel].src_count = int_count; + } + else // Receive from external + { + m_dma_op[channel].src = ext_index; + m_dma_op[channel].src_modifier = ext_modifier; + m_dma_op[channel].src_count = ext_count; + m_dma_op[channel].dst = int_index; + m_dma_op[channel].dst_modifier = int_modifier; + m_dma_op[channel].dst_count = int_count; + } + + m_dma_op[channel].pmode = 0; + m_dma_op[channel].chain_ptr = chain_ptr; + m_dma_op[channel].chained_direction = chained_direction; + + m_dma_op[channel].active = true; + + int cycles = m_dma_op[channel].src_count / 4; + m_dma_op[channel].timer->adjust(cycles_to_attotime(cycles), channel); + + // enable busy flag + m_dma_status |= (1 << channel); +} + +void adsp21062_device::schedule_dma_op(int channel, UINT32 src, UINT32 dst, int src_modifier, int dst_modifier, int src_count, int dst_count, int pmode) +{ + if (m_dma_op[channel].active) + { + fatalerror("schedule_dma_op: DMA operation already scheduled at %08X!\n", m_pc); + } + + m_dma_op[channel].src = src; + m_dma_op[channel].dst = dst; + m_dma_op[channel].src_modifier = src_modifier; + m_dma_op[channel].dst_modifier = dst_modifier; + m_dma_op[channel].src_count = src_count; + m_dma_op[channel].dst_count = dst_count; + m_dma_op[channel].pmode = pmode; + m_dma_op[channel].chain_ptr = 0; + + m_dma_op[channel].active = true; + + int cycles = src_count / 4; + m_dma_op[channel].timer->adjust(cycles_to_attotime(cycles), channel); + + // enable busy flag + m_dma_status |= (1 << channel); +} + +void adsp21062_device::dma_op(int channel) +{ + int i; + UINT32 src = m_dma_op[channel].src; + UINT32 dst = m_dma_op[channel].dst; + int src_modifier = m_dma_op[channel].src_modifier; + int dst_modifier = m_dma_op[channel].dst_modifier; + int src_count = m_dma_op[channel].src_count; + //int dst_count = m_dma_op[channel].dst_count; + int pmode = m_dma_op[channel].pmode; + + //printf("dma_op: %08X, %08X, %08X, %08X, %08X, %08X, %d\n", src, dst, src_modifier, dst_modifier, src_count, dst_count, pmode); + + switch (pmode) + { + case DMA_PMODE_NO_PACKING: + { + for (i=0; i < src_count; i++) + { + UINT32 data = dm_read32(src); + dm_write32(dst, data); + src += src_modifier; + dst += dst_modifier; + } + break; + } + case DMA_PMODE_16_32: + { + int length = src_count/2; + for (i=0; i < length; i++) + { + UINT32 data = ((dm_read32(src+0) & 0xffff) << 16) | (dm_read32(src+1) & 0xffff); + + dm_write32(dst, data); + src += src_modifier * 2; + dst += dst_modifier; + } + break; + } + case DMA_PMODE_8_48: + { + int length = src_count/6; + for (i=0; i < length; i++) + { + UINT64 data = ((UINT64)(dm_read32(src+0) & 0xff) << 0) | + ((UINT64)(dm_read32(src+1) & 0xff) << 8) | + ((UINT64)(dm_read32(src+2) & 0xff) << 16) | + ((UINT64)(dm_read32(src+3) & 0xff) << 24) | + ((UINT64)(dm_read32(src+4) & 0xff) << 32) | + ((UINT64)(dm_read32(src+5) & 0xff) << 40); + + pm_write48(dst, data); + src += src_modifier * 6; + dst += dst_modifier; + } + break; + } + default: + { + fatalerror("SHARC: dma_op: unimplemented packing mode %d\n", pmode); + } + } + + if (channel == 6) + { + m_irptl |= (1 << (channel+10)); + + /* DMA interrupt */ + if (m_imask & (1 << (channel+10))) + { + m_irq_active |= 1 << (channel+10); + } + } + + // clear busy flag + m_dma_status &= ~(1 << channel); + + m_dma_op[channel].active = false; +} + +void adsp21062_device::sharc_dma_exec(int channel) +{ + UINT32 src, dst; + UINT32 src_count, dst_count; + UINT32 src_modifier, dst_modifier; + int chen, tran, dtype, pmode, /*mswf, master,*/ ishake, intio/*, ext, flsh*/; + + chen = (m_dma[channel].control >> 1) & 0x1; + tran = (m_dma[channel].control >> 2) & 0x1; + dtype = (m_dma[channel].control >> 5) & 0x1; + pmode = (m_dma[channel].control >> 6) & 0x3; + //mswf = (m_dma[channel].control >> 8) & 0x1; + //master = (m_dma[channel].control >> 9) & 0x1; + ishake = (m_dma[channel].control >> 10) & 0x1; + intio = (m_dma[channel].control >> 11) & 0x1; + //ext = (m_dma[channel].control >> 12) & 0x1; + //flsh = (m_dma[channel].control >> 13) & 0x1; + + if (ishake) + fatalerror("SHARC: dma_exec: handshake not supported\n"); + if (intio) + fatalerror("SHARC: dma_exec: single-word interrupt enable not supported\n"); + + + if (chen) // Chained DMA + { + UINT32 dma_chain_ptr = m_dma[channel].chain_ptr & 0x1ffff; + + schedule_chained_dma_op(channel, dma_chain_ptr, tran); + } + else + { + if (tran) // Transmit to external + { + dst = m_dma[channel].ext_index; + dst_modifier = m_dma[channel].ext_modifier; + dst_count = m_dma[channel].ext_count; + src = (m_dma[channel].int_index & 0x1ffff) | 0x20000; + src_modifier = m_dma[channel].int_modifier; + src_count = m_dma[channel].int_count; + } + else // Receive from external + { + src = m_dma[channel].ext_index; + src_modifier = m_dma[channel].ext_modifier; + src_count = m_dma[channel].ext_count; + dst = (m_dma[channel].int_index & 0x1ffff) | 0x20000; + dst_modifier = m_dma[channel].int_modifier; + dst_count = m_dma[channel].int_count; + } + + if (dtype) + //if (src_count != dst_count) + { + pmode = DMA_PMODE_8_48; + } + + schedule_dma_op(channel, src, dst, src_modifier, dst_modifier, src_count, dst_count, pmode); + } +} + +TIMER_CALLBACK_MEMBER(adsp21062_device::sharc_dma_callback) +{ + int channel = param; + + m_dma_op[channel].timer->adjust(attotime::never, 0); + + m_irptl |= (1 << (channel+10)); + + // DMA interrupt + if (m_imask & (1 << (channel+10))) + { + m_irq_active |= 1 << (channel+10); + } + + dma_op(channel); + if (m_dma_op[channel].chain_ptr != 0) + { + schedule_chained_dma_op(channel, m_dma_op[channel].chain_ptr, m_dma_op[channel].chained_direction); + } +} diff --git a/src/devices/cpu/sharc/sharcdsm.c b/src/devices/cpu/sharc/sharcdsm.c new file mode 100644 index 00000000000..c498dcb78e5 --- /dev/null +++ b/src/devices/cpu/sharc/sharcdsm.c @@ -0,0 +1,1220 @@ +// license:BSD-3-Clause +// copyright-holders:Ville Linde +/* + Analog Devices ADSP-2106x SHARC Disassembler + + Written by Ville Linde for use in MAME +*/ + +#include "emu.h" +#include "sharcdsm.h" + +static UINT32 (* sharcdasm_table[256])(UINT32, UINT64); +static int dasm_table_built = 0; + +#define GET_UREG(x) (ureg_names[x]) +#define GET_SREG(x) (GET_UREG(0x70 | (x & 0xf))) +#define GET_DREG(x) (GET_UREG(0x00 | (x & 0xf))) +#define GET_DAG1_I(x) (GET_UREG(0x10 | (x & 0x7))) +#define GET_DAG1_M(x) (GET_UREG(0x20 | (x & 0x7))) +#define GET_DAG1_L(x) (GET_UREG(0x30 | (x & 0x7))) +#define GET_DAG1_B(x) (GET_UREG(0x40 | (x & 0x7))) +#define GET_DAG2_I(x) (GET_UREG(0x10 | (8 + (x & 0x7)))) +#define GET_DAG2_M(x) (GET_UREG(0x20 | (8 + (x & 0x7)))) +#define GET_DAG2_L(x) (GET_UREG(0x30 | (8 + (x & 0x7)))) +#define GET_DAG2_B(x) (GET_UREG(0x40 | (8 + (x & 0x7)))) + +#define SIGN_EXTEND6(x) ((x & 0x20) ? (0xffffffc0 | x) : x) +#define SIGN_EXTEND24(x) ((x & 0x800000) ? (0xff000000 | x) : x) + + +static char *output; +static void ATTR_PRINTF(1,2) print(const char *fmt, ...) +{ + va_list vl; + + va_start(vl, fmt); + output += vsprintf(output, fmt, vl); + va_end(vl); +} + + + +static void compute(UINT32 opcode) +{ + int op = (opcode >> 12) & 0xff; + int cu = (opcode >> 20) & 0x3; + int rn = (opcode >> 8) & 0xf; + int rx = (opcode >> 4) & 0xf; + int ry = (opcode >> 0) & 0xf; + int rs = (opcode >> 12) & 0xf; + int ra = rn; + int rm = rs; + + if (opcode & 0x400000) /* Multi-function opcode */ + { + int multiop = (opcode >> 16) & 0x3f; + int rxm = (opcode >> 6) & 0x3; + int rym = (opcode >> 4) & 0x3; + int rxa = (opcode >> 2) & 0x3; + int rya = (opcode >> 0) & 0x3; + + switch(multiop) + { + case 0x04: print("R%d = R%d * R%d (SSFR), R%d = R%d + R%d", rm, rxm, rym+4, ra, rxa+8, rya+12); break; + case 0x05: print("R%d = R%d * R%d (SSFR), R%d = R%d - R%d", rm, rxm, rym+4, ra, rxa+8, rya+12); break; + case 0x06: print("R%d = R%d * R%d (SSFR), R%d = (R%d + R%d)/2", rm, rxm, rym+4, ra, rxa+8, rya+12); break; + case 0x08: print("MRF = MRF + R%d * R%d (SSF), R%d = R%d + R%d", rxm, rym+4, ra, rxa+8, rya+12); break; + case 0x09: print("MRF = MRF + R%d * R%d (SSF), R%d = R%d - R%d", rxm, rym+4, ra, rxa+8, rya+12); break; + case 0x0a: print("MRF = MRF + R%d * R%d (SSF), R%d = (R%d + R%d)/2", rxm, rym+4, ra, rxa+8, rya+12); break; + case 0x0c: print("R%d = MRF + R%d * R%d (SSFR), R%d = R%d + R%d", rm, rxm, rym+4, ra, rxa+8, rya+12); break; + case 0x0d: print("R%d = MRF + R%d * R%d (SSFR), R%d = R%d - R%d", rm, rxm, rym+4, ra, rxa+8, rya+12); break; + case 0x0e: print("R%d = MRF + R%d * R%d (SSFR), R%d = (R%d + R%d)/2", rm, rxm, rym+4, ra, rxa+8, rya+12); break; + case 0x10: print("MRF = MRF - R%d * R%d (SSF), R%d = R%d + R%d", rxm, rym+4, ra, rxa+8, rya+12); break; + case 0x11: print("MRF = MRF - R%d * R%d (SSF), R%d = R%d - R%d", rxm, rym+4, ra, rxa+8, rya+12); break; + case 0x12: print("MRF = MRF - R%d * R%d (SSF), R%d = (R%d + R%d)/2", rxm, rym+4, ra, rxa+8, rya+12); break; + case 0x14: print("R%d = MRF - R%d * R%d (SSFR), R%d = R%d + R%d", rm, rxm, rym+4, ra, rxa+8, rya+12); break; + case 0x15: print("R%d = MRF - R%d * R%d (SSFR), R%d = R%d - R%d", rm, rxm, rym+4, ra, rxa+8, rya+12); break; + case 0x16: print("R%d = MRF - R%d * R%d (SSFR), R%d = (R%d + R%d)/2", rm, rxm, rym+4, ra, rxa+8, rya+12); break; + case 0x18: print("F%d = F%d * F%d, F%d = F%d + F%d", rm, rxm, rym+4, ra, rxa+8, rya+12); break; + case 0x19: print("F%d = F%d * F%d, F%d = F%d - F%d", rm, rxm, rym+4, ra, rxa+8, rya+12); break; + case 0x1a: print("F%d = F%d * F%d, F%d = FLOAT F%d BY F%d", rm, rxm, rym+4, ra, rxa+8, rya+12); break; + case 0x1b: print("F%d = F%d * F%d, F%d = FIX F%d BY F%d", rm, rxm, rym+4, ra, rxa+8, rya+12); break; + case 0x1c: print("F%d = F%d * F%d, F%d = (F%d + F%d)/2", rm, rxm, rym+4, ra, rxa+8, rya+12); break; + case 0x1d: print("F%d = F%d * F%d, F%d = ABS F%d", rm, rxm, rym+4, ra, rxa+8); break; + case 0x1e: print("F%d = F%d * F%d, F%d = MAX(F%d, F%d)", rm, rxm, rym+4, ra, rxa+8, rya+12); break; + case 0x1f: print("F%d = F%d * F%d, F%d = MIN(F%d, F%d)", rm, rxm, rym+4, ra, rxa+8, rya+12); break; + + case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27: + case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: case 0x2f: + { + print("R%d = R%d * R%d (SSFR), R%d = R%d + R%d, R%d = R%d - R%d", rm, rxm, rym+4, ra, rxa+8, rya+12, rs, rxa+8, rya+12); + break; + } + + case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37: + case 0x38: case 0x39: case 0x3a: case 0x3b: case 0x3c: case 0x3d: case 0x3e: case 0x3f: + { + print("F%d = F%d * F%d, F%d = F%d + F%d, F%d = F%d - F%d", rm, rxm, rym+4, ra, rxa+8, rya+12, rs, rxa+8, rya+12); + break; + } + + case 0x00: + { + int rk = (opcode >> 8) & 0xf; + int ai = (opcode >> 12) & 0xf; + print("R%d = %s", rk, mr_regnames[ai]); + break; + } + case 0x01: + { + int rk = (opcode >> 8) & 0xf; + int ai = (opcode >> 12) & 0xf; + print("%s = R%d", mr_regnames[ai], rk); + break; + } + + default: + { + print("??? (COMPUTE, MULTIOP)"); + break; + } + } + } + else /* Single-function */ + { + switch(cu) + { + /******************/ + /* ALU operations */ + /******************/ + case 0: + { + switch(op) + { + /* Fixed-point */ + case 0x01: print("R%d = R%d + R%d", rn, rx, ry); break; + case 0x02: print("R%d = R%d - R%d", rn, rx, ry); break; + case 0x05: print("R%d = R%d + R%d + CI", rn, rx, ry); break; + case 0x06: print("R%d = R%d - R%d + CI - 1", rn, rx, ry); break; + case 0x09: print("R%d = (R%d + R%d)/2", rn, rx, ry); break; + case 0x0a: print("COMP(R%d, R%d)", rx, ry); break; + case 0x25: print("R%d = R%d + CI", rn, rx); break; + case 0x26: print("R%d = R%d + CI - 1", rn, rx); break; + case 0x29: print("R%d = R%d + 1", rn, rx); break; + case 0x2a: print("R%d = R%d - 1", rn, rx); break; + case 0x22: print("R%d = -R%d", rn, rx); break; + case 0x30: print("R%d = ABS R%d", rn, rx); break; + case 0x21: print("R%d = PASS R%d", rn, rx); break; + case 0x40: print("R%d = R%d AND R%d", rn, rx, ry); break; + case 0x41: print("R%d = R%d OR R%d", rn, rx, ry); break; + case 0x42: print("R%d = R%d XOR R%d", rn, rx, ry); break; + case 0x43: print("R%d = NOT R%d", rn, rx); break; + case 0x61: print("R%d = MIN(R%d, R%d)", rn, rx, ry); break; + case 0x62: print("R%d = MAX(R%d, R%d)", rn, rx, ry); break; + case 0x63: print("R%d = CLIP R%d BY R%d", rn, rx, ry); break; + /* Floating-point */ + case 0x81: print("F%d = F%d + F%d", rn, rx, ry); break; + case 0x82: print("F%d = F%d - F%d", rn, rx, ry); break; + case 0x91: print("F%d = ABS(F%d + F%d)", rn, rx, ry); break; + case 0x92: print("F%d = ABS(F%d - F%d)", rn, rx, ry); break; + case 0x89: print("F%d = (F%d + F%d)/2", rn, rx, ry); break; + case 0x8a: print("COMP(F%d, F%d)", rx, ry); break; + case 0xa2: print("F%d = -F%d", rn, rx); break; + case 0xb0: print("F%d = ABS F%d", rn, rx); break; + case 0xa1: print("F%d = PASS F%d", rn, rx); break; + case 0xa5: print("F%d = RND R%d", rn, rx); break; + case 0xbd: print("F%d = SCALB F%d BY R%d", rn, rx, ry); break; + case 0xad: print("R%d = MANT F%d", rn, rx); break; + case 0xc1: print("R%d = LOGB F%d", rn, rx); break; + case 0xd9: print("R%d = FIX F%d BY R%d", rn, rx, ry); break; + case 0xc9: print("R%d = FIX F%d", rn, rx); break; + case 0xdd: print("R%d = TRUNC F%d BY R%d", rn, rx, ry); break; + case 0xcd: print("R%d = TRUNC F%d", rn, rx); break; + case 0xda: print("F%d = FLOAT R%d BY R%d", rn, rx, ry); break; + case 0xca: print("F%d = FLOAT R%d", rn, rx); break; + case 0xc4: print("F%d = RECIPS F%d", rn, rx); break; + case 0xc5: print("F%d = RSQRTS F%d", rn, rx); break; + case 0xe0: print("F%d = F%d COPYSIGN F%d", rn, rx, ry); break; + case 0xe1: print("F%d = MIN(F%d, F%d)", rn, rx, ry); break; + case 0xe2: print("F%d = MAX(F%d, F%d)", rn, rx, ry); break; + case 0xe3: print("F%d = CLIP F%d BY F%d", rn, rx, ry); break; + + case 0x70: case 0x71: case 0x72: case 0x73: case 0x74: case 0x75: case 0x76: case 0x77: + case 0x78: case 0x79: case 0x7a: case 0x7b: case 0x7c: case 0x7d: case 0x7e: case 0x7f: + { + print("R%d = R%d + R%d, R%d = R%d - R%d", ra, rx, ry, rs, rx, ry); + break; + } + case 0xf0: case 0xf1: case 0xf2: case 0xf3: case 0xf4: case 0xf5: case 0xf6: case 0xf7: + case 0xf8: case 0xf9: case 0xfa: case 0xfb: case 0xfc: case 0xfd: case 0xfe: case 0xff: + { + print("F%d = F%d + F%d, F%d = F%d - F%d", ra, rx, ry, rs, rx, ry); + break; + } + default: + { + print("??? (COMPUTE, ALU)"); + break; + } + } + break; + } + + /*************************/ + /* Multiplier operations */ + /*************************/ + case 1: + { + if( op == 0x30 ) { + print("F%d = F%d * F%d", rn, rx, ry); + return; + } + + switch((op >> 1) & 0x3) + { + case 0: + case 1: print("R%d = ", rn); break; + case 2: print("MRF = "); break; + case 3: print("MRB = "); break; + } + switch((op >> 6) & 0x3) + { + case 0: + switch((op >> 4) & 0x3) + { + case 0: print("SAT %s", (op & 0x2) ? "MRB" : "MRF"); break; + case 1: + if (op & 0x8) + { + print("RND %s", (op & 0x2) ? "MRB" : "MRF"); + } + else + { + print("0"); + } + break; + } + break; + + case 1: + print("R%d * R%d", rx, ry); break; + + case 2: + print("%s +(R%d * R%d)", (op & 0x2) ? "MRB" : "MRF", rx, ry); break; + + case 3: + print("%s -(R%d * R%d)", (op & 0x2) ? "MRB" : "MRF", rx, ry); break; + } + break; + } + + /**********************/ + /* Shifter operations */ + /**********************/ + case 2: + { + switch(op) + { + case 0x00: print("R%d = LSHIFT R%d BY R%d", rn, rx, ry); break; + case 0x20: print("R%d = R%d OR LSHIFT R%d BY R%d", rn, rn, rx, ry); break; + case 0x04: print("R%d = ASHIFT R%d BY R%d", rn, rx, ry); break; + case 0x24: print("R%d = R%d OR ASHIFT R%d BY R%d", rn, rn, rx, ry); break; + case 0x08: print("R%d = ROT R%d BY R%d", rn, rx, ry); break; + case 0xc4: print("R%d = BCLR R%d BY R%d", rn, rx, ry); break; + case 0xc0: print("R%d = BSET R%d BY R%d", rn, rx, ry); break; + case 0xc8: print("R%d = BTGL R%d BY R%d", rn, rx, ry); break; + case 0xcc: print("BTST R%d BY R%d", rx, ry); break; + case 0x44: print("R%d = FDEP R%d BY R%d", rn, rx, ry); break; + case 0x64: print("R%d = R%d OR FDEP R%d BY R%d", rn, rn, rx, ry); break; + case 0x4c: print("R%d = FDEP R%d BY R%d (SE)", rn, rx, ry); break; + case 0x6c: print("R%d = R%d OR FDEP R%d BY R%d (SE)", rn, rn, rx, ry); break; + case 0x40: print("R%d = FEXT R%d BY R%d", rn, rx, ry); break; + case 0x48: print("R%d = FEXT R%d BY R%d (SE)", rn, rx, ry); break; + case 0x80: print("R%d = EXP R%d", rn, rx); break; + case 0x84: print("R%d = EXP R%d (EX)", rn, rx); break; + case 0x88: print("R%d = LEFTZ R%d", rn, rx); break; + case 0x8c: print("R%d = LEFTO R%d", rn, rx); break; + case 0x90: print("R%d = FPACK F%d", rn, rx); break; + case 0x94: print("F%d = FUNPACK R%d", rn, rx); break; + default: print("??? (COMPUTE, SHIFT)"); break; + } + break; + } + + default: + { + print("??? (COMPUTE)"); + break; + } + } + } +} + +static void get_if_condition(int cond) +{ + if (cond != 31) + { + print("IF %s, ", condition_codes_if[cond]); + } +} + +static void pm_dm_ureg(int g, int d, int i, int m, int ureg, int update) +{ + if (update) // post-modify + { + if (d) + { + if (g) + { + print("PM(%s, %s) = %s", GET_DAG2_I(i), GET_DAG2_M(m), GET_UREG(ureg)); + } + else + { + print("DM(%s, %s) = %s", GET_DAG1_I(i), GET_DAG1_M(m), GET_UREG(ureg)); + } + } + else + { + if (g) + { + print("%s = PM(%s, %s)", GET_UREG(ureg), GET_DAG2_I(i), GET_DAG2_M(m)); + } + else + { + print("%s = DM(%s, %s)", GET_UREG(ureg), GET_DAG1_I(i), GET_DAG1_M(m)); + } + } + + } + else // pre-modify + { + if (d) + { + if (g) + { + print("PM(%s, %s) = %s", GET_DAG2_M(m), GET_DAG2_I(i), GET_UREG(ureg)); + } + else + { + print("DM(%s, %s) = %s", GET_DAG1_M(m), GET_DAG1_I(i), GET_UREG(ureg)); + } + } + else + { + if (g) + { + print("%s = PM(%s, %s)", GET_UREG(ureg), GET_DAG2_M(m), GET_DAG2_I(i)); + } + else + { + print("%s = DM(%s, %s)", GET_UREG(ureg), GET_DAG1_M(m), GET_DAG1_I(i)); + } + } + } +} + +static void pm_dm_imm_dreg(int g, int d, int i, int data, int dreg, int update) +{ + const char *sign = ""; + if (data & 0x20) + { + /* negative sign */ + data = (data ^ 0x3f) + 1; + sign = "-"; + } + if (update) // post-modify + { + if (d) + { + if (g) + { + print("PM(%s, %s0x%02X) = %s", GET_DAG2_I(i), sign, data, GET_DREG(dreg)); + } + else + { + print("DM(%s, %s0x%02X) = %s", GET_DAG1_I(i), sign, data, GET_DREG(dreg)); + } + } + else + { + if (g) + { + print("%s = PM(%s, %s0x%02X)", GET_DREG(dreg), GET_DAG2_I(i), sign, data); + } + else + { + print("%s = DM(%s, %s0x%02X)", GET_DREG(dreg), GET_DAG1_I(i), sign, data); + } + } + } + else // pre-modify + { + if (d) + { + if (g) + { + print("PM(%s0x%02X, %s) = %s", sign, data, GET_DAG2_I(i), GET_DREG(dreg)); + } + else + { + print("DM(%s0x%02X, %s) = %s", sign, data, GET_DAG1_I(i), GET_DREG(dreg)); + } + } + else + { + if (g) + { + print("%s = PM(%s0x%02X, %s)", GET_DREG(dreg), sign, data, GET_DAG2_I(i)); + } + else + { + print("%s = DM(%s0x%02X, %s)", GET_DREG(dreg), sign, data, GET_DAG1_I(i)); + } + } + } +} + +static void pm_dm_dreg(int g, int d, int i, int m, int dreg) +{ + if (d) + { + if (g) + { + print("PM(%s, %s) = %s", GET_DAG2_I(i), GET_DAG2_M(m), GET_DREG(dreg)); + } + else + { + print("DM(%s, %s) = %s", GET_DAG1_I(i), GET_DAG1_M(m), GET_DREG(dreg)); + } + } + else + { + if (g) + { + print("%s = PM(%s, %s)", GET_DREG(dreg), GET_DAG2_I(i), GET_DAG2_M(m)); + } + else + { + print("%s = DM(%s, %s)", GET_DREG(dreg), GET_DAG1_I(i), GET_DAG1_M(m)); + } + } +} + +static void shiftop(int shift, int data, int rn, int rx) +{ + INT8 data8 = data & 0xff; + int bit6 = data & 0x3f; + int len = (data >> 6) & 0x3f; + + switch(shift) + { + case 0x00: print("R%d = LSHIFT R%d BY %d", rn, rx, data8); break; + case 0x08: print("R%d = R%d OR LSHIFT R%d BY %d", rn, rn, rx, data8); break; + case 0x01: print("R%d = ASHIFT R%d BY %d", rn, rx, data8); break; + case 0x09: print("R%d = R%d OR ASHIFT R%d BY %d", rn, rn, rx, data8); break; + case 0x02: print("R%d = ROT R%d BY %d", rn, rx, data8); break; + case 0x31: print("R%d = BCLR R%d BY %d", rn, rx, data8); break; + case 0x30: print("R%d = BSET R%d BY %d", rn, rx, data8); break; + case 0x32: print("R%d = BTGL R%d BY %d", rn, rx, data8); break; + case 0x33: print("BTST R%d BY %d", rx, data8); break; + case 0x11: print("R%d = FDEP R%d BY %d:%d", rn, rx, bit6, len); break; + case 0x19: print("R%d = R%d OR FDEP R%d BY %d:%d", rn, rn, rx, bit6, len); break; + case 0x13: print("R%d = FDEP R%d BY %d:%d (SE)", rn, rx, bit6, len); break; + case 0x1b: print("R%d = R%d OR FDEP R%d BY %d:%d (SE)", rn, rn, rx, bit6, len); break; + case 0x10: print("R%d = FEXT R%d BY %d:%d", rn, rx, bit6, len); break; + case 0x12: print("R%d = FEXT R%d BY %d:%d (SE)", rn, rx, bit6, len); break; + case 0x20: print("R%d = EXP R%d", rn, rx); break; + case 0x21: print("R%d = EXP R%d (EX)", rn, rx); break; + case 0x22: print("R%d = LEFTZ R%d", rn, rx); break; + case 0x23: print("R%d = LEFTO R%d", rn, rx); break; + case 0x24: print("R%d = FPACK F%d", rn, rx); break; + case 0x25: print("F%d = FUNPACK R%d", rn, rx); break; + default: print("??? (SHIFTOP)"); break; + } +} + + + + + +static UINT32 dasm_compute_dreg_dmpm(UINT32 pc, UINT64 opcode) +{ + int dmi = (opcode >> 41) & 0x7; + int dmm = (opcode >> 38) & 0x7; + int pmi = (opcode >> 30) & 0x7; + int pmm = (opcode >> 27) & 0x7; + int dmdreg = (opcode >> 33) & 0xf; + int pmdreg = (opcode >> 23) & 0xf; + int comp = opcode & 0x7fffff; + int dmd = (opcode >> 44) & 0x1; + int pmd = (opcode >> 37) & 0x1; + + if (comp) + { + compute(comp); + print(", "); + } + if (dmd) + { + print("DM(%s, %s) = R%d, ", GET_DAG1_I(dmi), GET_DAG1_M(dmm), dmdreg); + } + else + { + print("R%d = DM(%s, %s), ", dmdreg, GET_DAG1_I(dmi), GET_DAG1_M(dmm)); + } + if (pmd) + { + print("PM(%s, %s) = R%d", GET_DAG2_I(pmi), GET_DAG2_M(pmm), pmdreg); + } + else + { + print("R%d = PM(%s, %s)", pmdreg, GET_DAG2_I(pmi), GET_DAG2_M(pmm)); + } + return 0; +} + +static UINT32 dasm_compute(UINT32 pc, UINT64 opcode) +{ + int cond = (opcode >> 33) & 0x1f; + int comp = opcode & 0x7fffff; + + if (comp) + { + get_if_condition(cond); + compute(comp); + } + return 0; +} + +static UINT32 dasm_compute_uregdmpm_regmod(UINT32 pc, UINT64 opcode) +{ + int cond = (opcode >> 33) & 0x1f; + int g = (opcode >> 32) & 0x1; + int d = (opcode >> 31) & 0x1; + int i = (opcode >> 41) & 0x7; + int m = (opcode >> 38) & 0x7; + int u = (opcode >> 44) & 0x1; + int ureg = (opcode >> 23) & 0xff; + int comp = opcode & 0x7fffff; + + get_if_condition(cond); + if (comp) + { + compute(comp); + print(", "); + } + pm_dm_ureg(g,d,i,m, ureg, u); + return 0; +} + +static UINT32 dasm_compute_dregdmpm_immmod(UINT32 pc, UINT64 opcode) +{ + int cond = (opcode >> 33) & 0x1f; + int g = (opcode >> 40) & 0x1; + int d = (opcode >> 39) & 0x1; + int i = (opcode >> 41) & 0x7; + int u = (opcode >> 38) & 0x1; + int dreg = (opcode >> 23) & 0xf; + int data = (opcode >> 27) & 0x3f; + int comp = opcode & 0x7fffff; + + get_if_condition(cond); + if (comp) + { + compute(comp); + print(", "); + } + pm_dm_imm_dreg(g,d,i, data, dreg, u); + return 0; +} + +static UINT32 dasm_compute_ureg_ureg(UINT32 pc, UINT64 opcode) +{ + int cond = (opcode >> 31) & 0x1f; + int uregs = (opcode >> 36) & 0xff; + int uregd = (opcode >> 23) & 0xff; + int comp = opcode & 0x7fffff; + + get_if_condition(cond); + if (comp) + { + compute(comp); + print(", "); + } + print("%s = %s", GET_UREG(uregd), GET_UREG(uregs)); + return 0; +} + +static UINT32 dasm_immshift_dregdmpm(UINT32 pc, UINT64 opcode) +{ + int cond = (opcode >> 33) & 0x1f; + int g = (opcode >> 32) & 0x1; + int d = (opcode >> 31) & 0x1; + int i = (opcode >> 41) & 0x7; + int m = (opcode >> 38) & 0x7; + int rn = (opcode >> 4) & 0xf; + int rx = (opcode >> 0) & 0xf; + int shift = (opcode >> 16) & 0x3f; + int dreg = (opcode >> 23) & 0xf; + int data = (((opcode >> 27) & 0xf) << 8) | ((opcode >> 8) & 0xff); + + get_if_condition(cond); + shiftop(shift, data, rn, rx); + print(", "); + pm_dm_dreg(g,d,i,m, dreg); + return 0; +} + +static UINT32 dasm_immshift_dregdmpm_nodata(UINT32 pc, UINT64 opcode) +{ + int cond = (opcode >> 33) & 0x1f; + int rn = (opcode >> 4) & 0xf; + int rx = (opcode >> 0) & 0xf; + int shift = (opcode >> 16) & 0x3f; + int data = (((opcode >> 27) & 0xf) << 8) | ((opcode >> 8) & 0xff); + + get_if_condition(cond); + shiftop(shift, data, rn, rx); + return 0; +} + +static UINT32 dasm_compute_modify(UINT32 pc, UINT64 opcode) +{ + int cond = (opcode >> 33) & 0x1f; + int g = (opcode >> 38) & 0x7; + int i = (opcode >> 30) & 0x7; + int m = (opcode >> 27) & 0x7; + int comp = opcode & 0x7fffff; + + get_if_condition(cond); + if (comp) + { + compute(comp); + print(", "); + } + print("MODIFY(I%d, M%d)", (g ? 8+i : i), (g ? 8+m : m)); + return 0; +} + +static UINT32 dasm_direct_jump(UINT32 pc, UINT64 opcode) +{ + int j = (opcode >> 26) & 0x1; + int cond = (opcode >> 33) & 0x1f; + int ci = (opcode >> 24) & 0x1; + UINT32 addr = opcode & 0xffffff; + UINT32 flags = 0; + + get_if_condition(cond); + if (opcode & U64(0x8000000000)) + { + print("CALL"); + flags = DASMFLAG_STEP_OVER; + } + else + { + print("JUMP"); + } + + if (opcode & U64(0x10000000000)) /* PC-relative branch */ + { + print(" (0x%08X)", pc + SIGN_EXTEND24(addr)); + } + else /* Indirect branch */ + { + print(" (0x%08X)", addr); + } + if (j) + { + print(" (DB)"); + } + if (ci) + { + print(" (CI)"); + } + return flags; +} + +static UINT32 dasm_indirect_jump_compute(UINT32 pc, UINT64 opcode) +{ + int b = (opcode >> 39) & 0x1; + int j = (opcode >> 26) & 0x1; + int e = (opcode >> 25) & 0x1; + int ci = (opcode >> 24) & 0x1; + int cond = (opcode >> 33) & 0x1f; + int pmi = (opcode >> 30) & 0x7; + int pmm = (opcode >> 27) & 0x7; + int reladdr = (opcode >> 27) & 0x3f; + int comp = opcode & 0x7fffff; + UINT32 flags = 0; + + get_if_condition(cond); + if (b) + { + print("CALL"); + flags = DASMFLAG_STEP_OVER; + } + else + { + print("JUMP"); + } + + if (opcode & U64(0x10000000000)) /* PC-relative branch */ + { + print(" (0x%08X)", pc + SIGN_EXTEND6(reladdr)); + } + else /* Indirect branch */ + { + print(" (%s, %s)", GET_DAG2_M(pmm), GET_DAG2_I(pmi)); + } + if (j) + { + print(" (DB)"); + } + if (ci) + { + print(" (CI)"); + } + + if (comp) + { + print(", "); + if (e) + { + print("ELSE "); + } + + compute(comp); + } + return flags; +} + +static UINT32 dasm_indirect_jump_compute_dregdm(UINT32 pc, UINT64 opcode) +{ + int d = (opcode >> 44) & 0x1; + int cond = (opcode >> 33) & 0x1f; + int pmi = (opcode >> 30) & 0x7; + int pmm = (opcode >> 27) & 0x7; + int dmi = (opcode >> 41) & 0x7; + int dmm = (opcode >> 38) & 0x7; + int reladdr = (opcode >> 27) & 0x3f; + int dreg = (opcode >> 23) & 0xf; + int comp = opcode & 0x7fffff; + + get_if_condition(cond); + print("JUMP"); + + if (opcode & U64(0x200000000000)) /* PC-relative branch */ + { + print(" (0x%08X)", pc + SIGN_EXTEND6(reladdr)); + } + else /* Indirect branch */ + { + print(" (%s, %s)", GET_DAG2_M(pmm), GET_DAG2_I(pmi)); + } + print(", ELSE "); + + if (comp) + { + compute(comp); + print(", "); + } + if (d) + { + print("%s = DM(%s, %s)", GET_DREG(dreg), GET_DAG1_I(dmi), GET_DAG1_M(dmm)); + } + else + { + print("DM(%s, %s) = %s", GET_DAG1_I(dmi), GET_DAG1_M(dmm), GET_DREG(dreg)); + } + return 0; +} + +static UINT32 dasm_rts_compute(UINT32 pc, UINT64 opcode) +{ + int j = (opcode >> 26) & 0x1; + int e = (opcode >> 25) & 0x1; + int lr = (opcode >> 24) & 0x1; + int cond = (opcode >> 33) & 0x1f; + int comp = opcode & 0x7fffff; + + get_if_condition(cond); + + if (opcode & U64(0x10000000000)) + { + print("RTI"); + } + else + { + print("RTS"); + } + + if (j) + { + print(" (DB)"); + } + if (lr) + { + print(" (LR)"); + } + + if (comp) + { + print(", "); + if (e) + { + print("ELSE "); + } + + compute(comp); + } + return DASMFLAG_STEP_OUT; +} + +static UINT32 dasm_do_until_counter(UINT32 pc, UINT64 opcode) +{ + int data = (opcode >> 24) & 0xffff; + int ureg = (opcode >> 32) & 0xff; + UINT32 addr = opcode & 0xffffff; + + if (opcode & U64(0x10000000000)) /* Loop counter from universal register */ + { + print("LCNTR = %s, ", GET_UREG(ureg)); + print("DO (0x%08X)", pc + SIGN_EXTEND24(addr)); + } + else /* Loop counter from immediate */ + { + print("LCNTR = 0x%04X, ", data); + print("DO (0x%08X) UNTIL LCE", pc + SIGN_EXTEND24(addr)); + } + return 0; +} + +static UINT32 dasm_do_until(UINT32 pc, UINT64 opcode) +{ + int term = (opcode >> 33) & 0x1f; + UINT32 addr = opcode & 0xffffff; + + print("DO (0x%08X) UNTIL %s", pc + SIGN_EXTEND24(addr), condition_codes_do[term]); + return 0; +} + +static UINT32 dasm_immmove_uregdmpm(UINT32 pc, UINT64 opcode) +{ + int d = (opcode >> 40) & 0x1; + int g = (opcode >> 41) & 0x1; + int ureg = (opcode >> 32) & 0xff; + UINT32 addr = opcode & 0xffffffff; + + if (g) + { + if (d) + { + print("PM(0x%08X) = %s", addr, GET_UREG(ureg)); + } + else + { + print("%s = PM(0x%08X)", GET_UREG(ureg), addr); + } + } + else + { + if (d) + { + print("DM(0x%08X) = %s", addr, GET_UREG(ureg)); + } + else + { + print("%s = DM(0x%08X)", GET_UREG(ureg), addr); + } + } + return 0; +} + +static UINT32 dasm_immmove_uregdmpm_indirect(UINT32 pc, UINT64 opcode) +{ + int d = (opcode >> 40) & 0x1; + int g = (opcode >> 44) & 0x1; + int i = (opcode >> 41) & 0x7; + int ureg = (opcode >> 32) & 0xff; + UINT32 addr = opcode & 0xffffffff; + + if (g) + { + if (d) + { + print("PM(0x%08X, %s) = %s", addr, GET_DAG2_I(i), GET_UREG(ureg)); + } + else + { + print("%s = PM(0x%08X, %s)", GET_UREG(ureg), addr, GET_DAG2_I(i)); + } + } + else + { + if (d) + { + print("DM(0x%08X, %s) = %s", addr, GET_DAG1_I(i), GET_UREG(ureg)); + } + else + { + print("%s = DM(0x%08X, %s)", GET_UREG(ureg), addr, GET_DAG1_I(i)); + } + } + return 0; +} + +static UINT32 dasm_immmove_immdata_dmpm(UINT32 pc, UINT64 opcode) +{ + int g = (opcode >> 37) & 0x1; + int i = (opcode >> 41) & 0x7; + int m = (opcode >> 38) & 0x7; + UINT32 data = opcode & 0xffffffff; + + if (g) + { + print("PM(%s, %s) = 0x%08X", GET_DAG2_I(i), GET_DAG2_M(m), data); + } + else + { + print("DM(%s, %s) = 0x%08X", GET_DAG1_I(i), GET_DAG1_M(m), data); + } + return 0; +} + +static UINT32 dasm_immmove_immdata_ureg(UINT32 pc, UINT64 opcode) +{ + int ureg = (opcode >> 32) & 0xff; + UINT32 data = opcode & 0xffffffff; + + print("%s = 0x%08X", GET_UREG(ureg), data); + return 0; +} + +static UINT32 dasm_sysreg_bitop(UINT32 pc, UINT64 opcode) +{ + int bop = (opcode >> 37) & 0x7; + int sreg = (opcode >> 32) & 0xf; + UINT32 data = opcode & 0xffffffff; + + print("BIT "); + print("%s ", bopnames[bop]); + print("%s ", GET_SREG(sreg)); + print("0x%08X", data); + return 0; +} + +static UINT32 dasm_ireg_modify(UINT32 pc, UINT64 opcode) +{ + int g = (opcode >> 38) & 0x1; + int i = (opcode >> 32) & 0x7; + UINT32 data = opcode & 0xffffffff; + + if (opcode & U64(0x8000000000)) /* with bit-reverse */ + { + if (g) + { + print("BITREV (%s, 0x%08X)", GET_DAG2_I(i), data); + } + else + { + print("BITREV (%s, 0x%08X)", GET_DAG1_I(i), data); + } + } + else /* without bit-reverse */ + { + if (g) + { + print("MODIFY (%s, 0x%08X)", GET_DAG2_I(i), data); + } + else + { + print("MODIFY (%s, 0x%08X)", GET_DAG1_I(i), data); + } + } + return 0; +} + +static UINT32 dasm_misc(UINT32 pc, UINT64 opcode) +{ + int bits = (opcode >> 33) & 0x7f; + int lpu = (opcode >> 39) & 0x1; + int lpo = (opcode >> 38) & 0x1; + int spu = (opcode >> 37) & 0x1; + int spo = (opcode >> 36) & 0x1; + int ppu = (opcode >> 35) & 0x1; + int ppo = (opcode >> 34) & 0x1; + int fc = (opcode >> 33) & 0x1; + + if (lpu) + { + print("PUSH LOOP"); + if (bits & 0x3f) + { + print(", "); + } + } + if (lpo) + { + print("POP LOOP"); + if (bits & 0x1f) + { + print(", "); + } + } + if (spu) + { + print("PUSH STS"); + if (bits & 0xf) + { + print(", "); + } + } + if (spo) + { + print("POP STS"); + if (bits & 0x7) + { + print(", "); + } + } + if (ppu) + { + print("PUSH PCSTK"); + if (bits & 0x3) + { + print(", "); + } + } + if (ppo) + { + print("POP PCSTK"); + if (bits & 0x1) + { + print(", "); + } + } + if (fc) + { + print("FLUSH CACHE"); + } + return 0; +} + +static UINT32 dasm_idlenop(UINT32 pc, UINT64 opcode) +{ + if (opcode & U64(0x8000000000)) + { + print("IDLE"); + } + else + { + print("NOP"); + } + return 0; +} + +#ifdef UNUSED_FUNCTION +static UINT32 dasm_cjump_rframe(UINT32 pc, UINT64 opcode) +{ + /* TODO */ + if (opcode & U64(0x10000000000)) /* RFRAME */ + { + print("TODO: RFRAME"); + } + else + { + print("TODO: CJUMP"); + } + return 0; +} +#endif + +static UINT32 dasm_invalid(UINT32 pc, UINT64 opcode) +{ + print("?"); + return 0; +} + +static const SHARC_DASM_OP sharc_dasm_ops[] = +{ + // |0 0 1| + { 0xe000, 0x2000, dasm_compute_dreg_dmpm }, + + // |0 0 0|0 0 0 0 1| + { 0xff00, 0x0100, dasm_compute }, + + // |0 1 0| + { 0xe000, 0x4000, dasm_compute_uregdmpm_regmod }, + + // |0 1 1|0| + { 0xf000, 0x6000, dasm_compute_dregdmpm_immmod }, + + // |0 1 1|1| + { 0xf000, 0x7000, dasm_compute_ureg_ureg }, + + // |1 0 0|0| + { 0xf000, 0x8000, dasm_immshift_dregdmpm }, + + // |0 0 0|0 0 0 1 0| + { 0xff00, 0x0200, dasm_immshift_dregdmpm_nodata }, + + // |0 0 0|0 0 1 0 0| + { 0xff00, 0x0400, dasm_compute_modify }, + + // |0 0 0|0 0 1 1 x| + { 0xfe00, 0x0600, dasm_direct_jump }, + + // |0 0 0|0 1 0 0 x| + { 0xfe00, 0x0800, dasm_indirect_jump_compute }, + + // |1 1 x| + { 0xc000, 0xc000, dasm_indirect_jump_compute_dregdm }, + + // |0 0 0|0 1 0 1 x| + { 0xfe00, 0x0a00, dasm_rts_compute }, + + // |0 0 0|0 1 1 0 x| + { 0xfe00, 0x0c00, dasm_do_until_counter }, + + // |0 0 0|0 1 1 1 0| + { 0xff00, 0x0e00, dasm_do_until }, + + // |0 0 0|1 0 0|x|x| + { 0xfc00, 0x1000, dasm_immmove_uregdmpm }, + + // |1 0 1|x|x x x|x| + { 0xe000, 0xa000, dasm_immmove_uregdmpm_indirect }, + + // |1 0 0|1| + { 0xf000, 0x9000, dasm_immmove_immdata_dmpm }, + + // |0 0 0|0 1 1 1 1| + { 0xff00, 0x0f00, dasm_immmove_immdata_ureg }, + + // |0 0 0|1 0 1 0 0| + { 0xff00, 0x1400, dasm_sysreg_bitop }, + + // |0 0 0|1 0 1 1 0| + { 0xff00, 0x1600, dasm_ireg_modify }, + + // |0 0 0|1 0 1 1 1| + { 0xff00, 0x1700, dasm_misc }, + + // |0 0 0|0 0 0 0 0| + { 0xff00, 0x0000, dasm_idlenop }, +}; + +static void build_dasm_table(void) +{ + int i, j; + int num_ops = sizeof(sharc_dasm_ops) / sizeof(SHARC_DASM_OP); + + for (i=0; i < 256; i++) + { + sharcdasm_table[i] = dasm_invalid; + } + + for (i=0; i < 256; i++) + { + UINT16 op = i << 8; + + for (j=0; j < num_ops; j++) + { + if ((sharc_dasm_ops[j].op_mask & op) == sharc_dasm_ops[j].op_bits) + { + if (sharcdasm_table[i] != dasm_invalid) + { + fatalerror("build_dasm_table: table already filled! (i=%04X, j=%d)\n", i, j); + } + else + { + sharcdasm_table[i] = sharc_dasm_ops[j].handler; + } + } + } + } +} + +static UINT32 sharc_dasm_one(char *buffer, offs_t pc, UINT64 opcode) +{ + #define DEFAULT_DASM_WIDTH (64) + + char dasm_buffer[2000]; + int i; + int op = (opcode >> 40) & 0xff; + UINT32 flags; + + if (!dasm_table_built) + { + build_dasm_table(); + dasm_table_built = 1; + } + + memset(dasm_buffer, 0, sizeof(dasm_buffer)); + + /* set buffer for print */ + output = dasm_buffer; + + flags = (*sharcdasm_table[op])(pc, opcode); + + for (i=0; i < DEFAULT_DASM_WIDTH; i++) + { + buffer[i] = dasm_buffer[i]; + } + return flags; +} + + +CPU_DISASSEMBLE( sharc ) +{ + UINT64 op = 0; + UINT32 flags = 0; + + op = ((UINT64)oprom[0] << 0) | ((UINT64)oprom[1] << 8) | + ((UINT64)oprom[2] << 16) | ((UINT64)oprom[3] << 24) | + ((UINT64)oprom[4] << 32) | ((UINT64)oprom[5] << 40); + + flags = sharc_dasm_one(buffer, pc, op); + return 1 | flags | DASMFLAG_SUPPORTED; +} diff --git a/src/devices/cpu/sharc/sharcdsm.h b/src/devices/cpu/sharc/sharcdsm.h new file mode 100644 index 00000000000..8407b73cb50 --- /dev/null +++ b/src/devices/cpu/sharc/sharcdsm.h @@ -0,0 +1,79 @@ +// license:BSD-3-Clause +// copyright-holders:Ville Linde +static const char ureg_names[256][16] = +{ + "R0", "R1", "R2", "R3", "R4", "R5", "R6", "R7", + "R8", "R9", "R10", "R11", "R12", "R13", "R14", "R15", + "I0", "I1", "I2", "I3", "I4", "I5", "I6", "I7", + "I8", "I9", "I10", "I11", "I12", "I13", "I14", "I15", + "M0", "M1", "M2", "M3", "M4", "M5", "M6", "M7", + "M8", "M9", "M10", "M11", "M12", "M13", "M14", "M15", + "L0", "L1", "L2", "L3", "L4", "L5", "L6", "L7", + "L8", "L9", "L10", "L11", "L12", "L13", "L14", "L15", + "B0", "B1", "B2", "B3", "B4", "B5", "B6", "B7", + "B8", "B9", "B10", "B11", "B12", "B13", "B14", "B15", + "???", "???", "???", "???", "???", "???", "???", "???", + "???", "???", "???", "???", "???", "???", "???", "???", + "FADDR", "DADDR", "???", "PC", "PCSTK", "PCSTKP", "LADDR", "CURLCNTR", + "LCNTR", "???", "???", "???", "???", "???", "???", "???", + "USTAT1", "USTAT2", "???", "???", "???", "???", "???", "???", + "???", "IRPTL", "MODE2", "MODE1", "ASTAT", "IMASK", "STKY", "IMASKP", + "???", "???", "???", "???", "???", "???", "???", "???", + "???", "???", "???", "???", "???", "???", "???", "???", + "???", "???", "???", "???", "???", "???", "???", "???", + "???", "???", "???", "???", "???", "???", "???", "???", + "???", "???", "???", "???", "???", "???", "???", "???", + "???", "???", "???", "???", "???", "???", "???", "???", + "???", "???", "???", "???", "???", "???", "???", "???", + "???", "???", "???", "???", "???", "???", "???", "???", + "???", "???", "???", "???", "???", "???", "???", "???", + "???", "???", "???", "???", "???", "???", "???", "???", + "???", "???", "???", "???", "???", "???", "???", "???", + "???", "???", "???", "PX", "PX1", "PX2", "TPERIOD", "TCOUNT", + "???", "???", "???", "???", "???", "???", "???", "???", + "???", "???", "???", "???", "???", "???", "???", "???", + "???", "???", "???", "???", "???", "???", "???", "???", + "???", "???", "???", "???", "???", "???", "???", "???" +}; + +static const char bopnames[8][8] = +{ + "SET", "CLEAR", "TOGGLE", "???", "TEST", "XOR", "???", "???" +}; + +static const char condition_codes_if[32][32] = +{ + "EQ", "LT", "LE", "AC", + "AV", "MV", "MS", "SV", + "SZ", "FLAG0_IN", "FLAG1_IN", "FLAG2_IN", + "FLAG3_IN", "TF", "BM", "NOT LCE", + "NE", "GE", "GT", "NOT AC", + "NOT AV", "NOT MV", "NOT MS", "NOT SV", + "NOT SZ", "NOT FLAG0_IN", "NOT FLAG1_IN", "NOT FLAG2_IN", + "NOT FLAG3_IN", "NOT TF", "NBM", "" +}; + +static const char condition_codes_do[32][32] = +{ + "EQ", "LT", "LE", "AC", + "AV", "MV", "MS", "SV", + "SZ", "FLAG0_IN", "FLAG1_IN", "FLAG2_IN", + "FLAG3_IN", "TF", "BM", "LCE", + "NE", "GE", "GT", "NOT AC", + "NOT AV", "NOT MV", "NOT MS", "NOT SV", + "NOT SZ", "NOT FLAG0_IN", "NOT FLAG1_IN", "NOT FLAG2_IN", + "NOT FLAG3_IN", "NOT TF", "NBM", "FOREVER" +}; + +static const char mr_regnames[16][8] = +{ + "MR0F", "MR1F", "MR2F", "MR0B", "MR1B", "MR2B", "???", "???", + "???", "???", "???", "???", "???", "???", "???", "???" +}; + +struct SHARC_DASM_OP +{ + UINT32 op_mask; + UINT32 op_bits; + UINT32 (* handler)(UINT32, UINT64); +}; diff --git a/src/devices/cpu/sharc/sharcmem.inc b/src/devices/cpu/sharc/sharcmem.inc new file mode 100644 index 00000000000..3427e0346b8 --- /dev/null +++ b/src/devices/cpu/sharc/sharcmem.inc @@ -0,0 +1,204 @@ +// license:BSD-3-Clause +// copyright-holders:Ville Linde +/* SHARC memory operations */ + +UINT32 adsp21062_device::pm_read32(UINT32 address) +{ + if (address >= 0x20000 && address < 0x28000) + { + UINT32 addr = (address & 0x7fff) * 3; + + return (UINT32)(m_internal_ram_block0[addr + 0] << 16) | + (m_internal_ram_block0[addr + 1]); + } + else if (address >= 0x28000 && address < 0x40000) + { + // block 1 is mirrored in 0x28000...2ffff, 0x30000...0x37fff and 0x38000...3ffff + UINT32 addr = (address & 0x7fff) * 3; + + return (UINT32)(m_internal_ram_block1[addr + 0] << 16) | + (m_internal_ram_block1[addr + 1]); + } + else { + fatalerror("SHARC: PM Bus Read32 %08X at %08X\n", address, m_pc); + } +} + +void adsp21062_device::pm_write32(UINT32 address, UINT32 data) +{ + if (address >= 0x20000 && address < 0x28000) + { + UINT32 addr = (address & 0x7fff) * 3; + + m_internal_ram_block0[addr + 0] = (UINT16)(data >> 16); + m_internal_ram_block0[addr + 1] = (UINT16)(data); + return; + } + else if (address >= 0x28000 && address < 0x40000) + { + // block 1 is mirrored in 0x28000...2ffff, 0x30000...0x37fff and 0x38000...3ffff + UINT32 addr = (address & 0x7fff) * 3; + + m_internal_ram_block1[addr + 0] = (UINT16)(data >> 16); + m_internal_ram_block1[addr + 1] = (UINT16)(data); + return; + } + else { + fatalerror("SHARC: PM Bus Write32 %08X, %08X at %08X\n", address, data, m_pc); + } +} + +UINT64 adsp21062_device::pm_read48(UINT32 address) +{ + if ((address >= 0x20000 && address < 0x28000)) + { + UINT32 addr = (address & 0x7fff) * 3; + + return ((UINT64)(m_internal_ram_block0[addr + 0]) << 32) | + ((UINT64)(m_internal_ram_block0[addr + 1]) << 16) | + ((UINT64)(m_internal_ram_block0[addr + 2]) << 0); + } + else if (address >= 0x28000 && address < 0x40000) + { + // block 1 is mirrored in 0x28000...2ffff, 0x30000...0x37fff and 0x38000...3ffff + UINT32 addr = (address & 0x7fff) * 3; + + return ((UINT64)(m_internal_ram_block1[addr + 0]) << 32) | + ((UINT64)(m_internal_ram_block1[addr + 1]) << 16) | + ((UINT64)(m_internal_ram_block1[addr + 2]) << 0); + } + else { + fatalerror("SHARC: PM Bus Read48 %08X at %08X\n", address, m_pc); + } + + return 0; +} + +void adsp21062_device::pm_write48(UINT32 address, UINT64 data) +{ + if ((address >= 0x20000 && address < 0x28000)) + { + UINT32 addr = (address & 0x7fff) * 3; + + m_internal_ram_block0[addr + 0] = (UINT16)(data >> 32); + m_internal_ram_block0[addr + 1] = (UINT16)(data >> 16); + m_internal_ram_block0[addr + 2] = (UINT16)(data); + return; + } + else if (address >= 0x28000 && address < 0x40000) + { + // block 1 is mirrored in 0x28000...2ffff, 0x30000...0x37fff and 0x38000...3ffff + UINT32 addr = (address & 0x7fff) * 3; + + m_internal_ram_block1[addr + 0] = (UINT16)(data >> 32); + m_internal_ram_block1[addr + 1] = (UINT16)(data >> 16); + m_internal_ram_block1[addr + 2] = (UINT16)(data); + return; + } + else { + fatalerror("SHARC: PM Bus Write48 %08X, %04X%08X at %08X\n", address, (UINT16)(data >> 32),(UINT32)data, m_pc); + } +} + +UINT32 adsp21062_device::dm_read32(UINT32 address) +{ + if (address < 0x100) + { + return sharc_iop_r(address); + } + else if (address >= 0x20000 && address < 0x28000) + { + UINT32 addr = (address & 0x7fff) * 2; + + return (UINT32)(m_internal_ram_block0[addr + 0] << 16) | + (m_internal_ram_block0[addr + 1]); + } + else if (address >= 0x28000 && address < 0x40000) + { + // block 1 is mirrored in 0x28000...2ffff, 0x30000...0x37fff and 0x38000...3ffff + UINT32 addr = (address & 0x7fff) * 2; + + return (UINT32)(m_internal_ram_block1[addr + 0] << 16) | + (m_internal_ram_block1[addr + 1]); + } + + // short word addressing + else if (address >= 0x40000 && address < 0x50000) + { + UINT32 addr = address & 0xffff; + + UINT16 r = m_internal_ram_block0[addr ^ 1]; + if (m_mode1 & 0x4000) + { + // sign-extend + return (INT32)(INT16)(r); + } + else + { + return (UINT32)(r); + } + } + else if (address >= 0x50000 && address < 0x80000) + { + // block 1 is mirrored in 0x50000...5ffff, 0x60000...0x6ffff and 0x70000...7ffff + UINT32 addr = address & 0xffff; + + UINT16 r = m_internal_ram_block1[addr ^ 1]; + if (m_mode1 & 0x4000) + { + // sign-extend + return (INT32)(INT16)(r); + } + else + { + return (UINT32)(r); + } + } + + return m_data->read_dword(address << 2); +} + +void adsp21062_device::dm_write32(UINT32 address, UINT32 data) +{ + if (address < 0x100) + { + sharc_iop_w(address, data); + return; + } + else if (address >= 0x20000 && address < 0x28000) + { + UINT32 addr = (address & 0x7fff) * 2; + + m_internal_ram_block0[addr + 0] = (UINT16)(data >> 16); + m_internal_ram_block0[addr + 1] = (UINT16)(data); + return; + } + else if (address >= 0x28000 && address < 0x40000) + { + // block 1 is mirrored in 0x28000...2ffff, 0x30000...0x37fff and 0x38000...3ffff + UINT32 addr = (address & 0x7fff) * 2; + + m_internal_ram_block1[addr + 0] = (UINT16)(data >> 16); + m_internal_ram_block1[addr + 1] = (UINT16)(data); + return; + } + + // short word addressing + else if (address >= 0x40000 && address < 0x50000) + { + UINT32 addr = address & 0xffff; + + m_internal_ram_block0[addr ^ 1] = data; + return; + } + else if (address >= 0x50000 && address < 0x80000) + { + // block 1 is mirrored in 0x50000...5ffff, 0x60000...0x6ffff and 0x70000...7ffff + UINT32 addr = address & 0xffff; + + m_internal_ram_block1[addr ^ 1] = data; + return; + } + + m_data->write_dword(address << 2, data); +} diff --git a/src/devices/cpu/sharc/sharcops.h b/src/devices/cpu/sharc/sharcops.h new file mode 100644 index 00000000000..42c305d8d10 --- /dev/null +++ b/src/devices/cpu/sharc/sharcops.h @@ -0,0 +1,134 @@ +// license:BSD-3-Clause +// copyright-holders:Ville Linde + +const adsp21062_device::SHARC_OP adsp21062_device::s_sharc_opcode_table[] = +{ + // |0 0 1| + { 0xe000, 0x2000, &adsp21062_device::sharcop_compute_dreg_dm_dreg_pm }, + + // |0 0 0|0 0 0 0 1| + { 0xff00, 0x0100, &adsp21062_device::sharcop_compute }, + + // |0 1 0|0| + { 0xf000, 0x4000, &adsp21062_device::sharcop_compute_ureg_dmpm_premod }, + + // |0 1 0|1| + { 0xf000, 0x5000, &adsp21062_device::sharcop_compute_ureg_dmpm_postmod }, + + // |0 1 1|0|x x x|0|0| + { 0xf180, 0x6000, &adsp21062_device::sharcop_compute_dm_to_dreg_immmod }, + + // |0 1 1|0|x x x|0|1| + { 0xf180, 0x6080, &adsp21062_device::sharcop_compute_dreg_to_dm_immmod }, + + // |0 1 1|0|x x x|1|0| + { 0xf180, 0x6100, &adsp21062_device::sharcop_compute_pm_to_dreg_immmod }, + + // |0 1 1|0|x x x|1|1| + { 0xf180, 0x6180, &adsp21062_device::sharcop_compute_dreg_to_pm_immmod }, + + // |0 1 1|1| + { 0xf000, 0x7000, &adsp21062_device::sharcop_compute_ureg_to_ureg }, + + // |1 0 0|0| + { 0xf000, 0x8000, &adsp21062_device::sharcop_imm_shift_dreg_dmpm }, + + // |0 0 0|0 0 0 1 0| + { 0xff00, 0x0200, &adsp21062_device::sharcop_imm_shift }, + + // |0 0 0|0 0 1 0 0| + { 0xff00, 0x0400, &adsp21062_device::sharcop_compute_modify }, + + // |0 0 0|0 0 1 1 0|0| + { 0xff80, 0x0600, &adsp21062_device::sharcop_direct_jump }, + + // |0 0 0|0 0 1 1 0|1| + { 0xff80, 0x0680, &adsp21062_device::sharcop_direct_call }, + + // |0 0 0|0 0 1 1 1|0| + { 0xff80, 0x0700, &adsp21062_device::sharcop_relative_jump }, + + // |0 0 0|0 0 1 1 1|1| + { 0xff80, 0x0780, &adsp21062_device::sharcop_relative_call }, + + // |0 0 0|0 1 0 0 0|0| + { 0xff80, 0x0800, &adsp21062_device::sharcop_indirect_jump }, + + // |0 0 0|0 1 0 0 0|1| + { 0xff80, 0x0880, &adsp21062_device::sharcop_indirect_call }, + + // |0 0 0|0 1 0 0 1|0| + { 0xff80, 0x0900, &adsp21062_device::sharcop_relative_jump_compute }, + + // |0 0 0|0 1 0 0 1|1| + { 0xff80, 0x0980, &adsp21062_device::sharcop_relative_call_compute }, + + // |1 1 0| + { 0xe000, 0xc000, &adsp21062_device::sharcop_indirect_jump_compute_dreg_dm }, + + // |1 1 1| + { 0xe000, 0xe000, &adsp21062_device::sharcop_relative_jump_compute_dreg_dm }, + + // |0 0 0|0 1 0 1 0| + { 0xff00, 0x0a00, &adsp21062_device::sharcop_rts }, + + // |0 0 0|0 1 0 1 1| + { 0xff00, 0x0b00, &adsp21062_device::sharcop_rti }, + + // |0 0 0|0 1 1 0 0| + { 0xff00, 0x0c00, &adsp21062_device::sharcop_do_until_counter_imm }, + + // |0 0 0|0 1 1 0 1| + { 0xff00, 0x0d00, &adsp21062_device::sharcop_do_until_counter_ureg }, + + // |0 0 0|0 1 1 1 0| + { 0xff00, 0x0e00, &adsp21062_device::sharcop_do_until }, + + // |0 0 0|1 0 0|0|0| + { 0xff00, 0x1000, &adsp21062_device::sharcop_dm_to_ureg_direct }, + + // |0 0 0|1 0 0|0|1| + { 0xff00, 0x1100, &adsp21062_device::sharcop_ureg_to_dm_direct }, + + // |0 0 0|1 0 0|1|0| + { 0xff00, 0x1200, &adsp21062_device::sharcop_pm_to_ureg_direct }, + + // |0 0 0|1 0 0|1|1| + { 0xff00, 0x1300, &adsp21062_device::sharcop_ureg_to_pm_direct }, + + // |1 0 1|0|x x x|0| + { 0xf100, 0xa000, &adsp21062_device::sharcop_dm_to_ureg_indirect }, + + // |1 0 1|0|x x x|1| + { 0xf100, 0xa100, &adsp21062_device::sharcop_ureg_to_dm_indirect }, + + // |1 0 1|1|x x x|0| + { 0xf100, 0xb000, &adsp21062_device::sharcop_pm_to_ureg_indirect }, + + // |1 0 1|1|x x x|1| + { 0xf100, 0xb100, &adsp21062_device::sharcop_ureg_to_pm_indirect }, + + // |1 0 0|1| + { 0xf000, 0x9000, &adsp21062_device::sharcop_imm_to_dmpm }, + + // |0 0 0|0 1 1 1 1| + { 0xff00, 0x0f00, &adsp21062_device::sharcop_imm_to_ureg }, + + // |0 0 0|1 0 1 0 0| + { 0xff00, 0x1400, &adsp21062_device::sharcop_sysreg_bitop }, + + // |0 0 0|1 0 1 1 0|0| + { 0xff80, 0x1600, &adsp21062_device::sharcop_modify }, + + // |0 0 0|1 0 1 1 0|1| + { 0xff80, 0x1680, &adsp21062_device::sharcop_bit_reverse }, + + // |0 0 0|1 0 1 1 1| + { 0xff00, 0x1700, &adsp21062_device::sharcop_push_pop_stacks }, + + // |0 0 0|0 0 0 0 0|0| + { 0xff80, 0x0000, &adsp21062_device::sharcop_nop }, + + // |0 0 0|0 0 0 0 0|1| + { 0xff80, 0x0080, &adsp21062_device::sharcop_idle }, +}; diff --git a/src/devices/cpu/sharc/sharcops.inc b/src/devices/cpu/sharc/sharcops.inc new file mode 100644 index 00000000000..f36454f1805 --- /dev/null +++ b/src/devices/cpu/sharc/sharcops.inc @@ -0,0 +1,2767 @@ +// license:BSD-3-Clause +// copyright-holders:Ville Linde +#define SIGN_EXTEND6(x) (((x) & 0x20) ? (0xffffffc0 | (x)) : (x)) +#define SIGN_EXTEND24(x) (((x) & 0x800000) ? (0xff000000 | (x)) : (x)) + +#define PM_REG_I(x) (m_dag2.i[x]) +#define PM_REG_M(x) (m_dag2.m[x]) +#define PM_REG_B(x) (m_dag2.b[x]) +#define PM_REG_L(x) (m_dag2.l[x]) +#define DM_REG_I(x) (m_dag1.i[x]) +#define DM_REG_M(x) (m_dag1.m[x]) +#define DM_REG_B(x) (m_dag1.b[x]) +#define DM_REG_L(x) (m_dag1.l[x]) + +// ASTAT flags +#define AZ 0x1 /* ALU result zero */ +#define AV 0x2 /* ALU overflow */ +#define AN 0x4 /* ALU result negative */ +#define AC 0x8 /* ALU fixed-point carry */ +#define AS 0x10 /* ALU X input sign */ +#define AI 0x20 /* ALU floating-point invalid operation */ +#define MN 0x40 /* Multiplier result negative */ +#define MV 0x80 /* Multiplier overflow */ +#define MU 0x100 /* Multiplier underflow */ +#define MI 0x200 /* Multiplier floating-point invalid operation */ +#define AF 0x400 +#define SV 0x800 /* Shifter overflow */ +#define SZ 0x1000 /* Shifter result zero */ +#define SS 0x2000 /* Shifter input sign */ +#define BTF 0x40000 /* Bit Test Flag */ +#define FLG0 0x80000 /* FLAG0 */ +#define FLG1 0x100000 /* FLAG1 */ +#define FLG2 0x200000 /* FLAG2 */ +#define FLG3 0x400000 /* FLAG3 */ + +// STKY flags +#define AUS 0x1 /* ALU floating-point underflow */ +#define AVS 0x2 /* ALU floating-point overflow */ +#define AOS 0x4 /* ALU fixed-point overflow */ +#define AIS 0x20 /* ALU floating-point invalid operation */ + +// MODE1 flags +#define MODE1_BR8 0x1 /* Bit-reverse for I8 */ +#define MODE1_BR0 0x2 /* Bit-reverse for I0 */ +#define MODE1_SRCU 0x4 /* Alternate register select for computational units */ +#define MODE1_SRD1H 0x8 /* DAG alternate register select (7-4) */ +#define MODE1_SRD1L 0x10 /* DAG alternate register select (3-0) */ +#define MODE1_SRD2H 0x20 /* DAG alternate register select (15-12) */ +#define MODE1_SRD2L 0x40 /* DAG alternate register select (11-8) */ +#define MODE1_SRRFH 0x80 /* Register file alternate select for R(15-8) */ +#define MODE1_SRRFL 0x400 /* Register file alternate select for R(7-0) */ +#define MODE1_NESTM 0x800 /* Interrupt nesting enable */ +#define MODE1_IRPTEN 0x1000 /* Global interrupt enable */ +#define MODE1_ALUSAT 0x2000 /* Enable ALU fixed-point saturation */ +#define MODE1_SSE 0x4000 /* Enable short word sign extension */ +#define MODE1_TRUNCATE 0x8000 /* (1) Floating-point truncation / (0) round to nearest */ +#define MODE1_RND32 0x10000 /* (1) 32-bit floating-point rounding / (0) 40-bit rounding */ +#define MODE1_CSEL 0x60000 /* CSelect */ + +// MODE2 flags +#define MODE2_IRQ0E 0x1 /* IRQ0 (1) Edge sens. / (0) Level sens. */ +#define MODE2_IRQ1E 0x2 /* IRQ1 (1) Edge sens. / (0) Level sens. */ +#define MODE2_IRQ2E 0x4 /* IRQ2 (1) Edge sens. / (0) Level sens. */ +#define MODE2_CADIS 0x10 /* Cache disable */ +#define MODE2_TIMEN 0x20 /* Timer enable */ +#define MODE2_BUSLK 0x40 /* External bus lock */ +#define MODE2_FLG0O 0x8000 /* FLAG0 (1) Output / (0) Input */ +#define MODE2_FLG1O 0x10000 /* FLAG1 (1) Output / (0) Input */ +#define MODE2_FLG2O 0x20000 /* FLAG2 (1) Output / (0) Input */ +#define MODE2_FLG3O 0x40000 /* FLAG3 (1) Output / (0) Input */ +#define MODE2_CAFRZ 0x80000 /* Cache freeze */ + + +#define REG_PC 0x63 +#define REG_PCSTK 0x64 +#define REG_PCSTKP 0x65 +#define REG_LADDR 0x66 +#define REG_CURLCNTR 0x67 +#define REG_LCNTR 0x68 +#define REG_USTAT1 0x70 +#define REG_USTAT2 0x71 +#define REG_IRPTL 0x79 +#define REG_MODE2 0x7a +#define REG_MODE1 0x7b +#define REG_ASTAT 0x7c +#define REG_IMASK 0x7d +#define REG_STKY 0x7e +#define REG_IMASKP 0x7f + + + +#define REG(x) (m_r[x].r) +#define FREG(x) (m_r[x].f) + +#define UPDATE_CIRCULAR_BUFFER_PM(x) \ + { \ + if (PM_REG_L(x) != 0) \ + { \ + if (PM_REG_I(x) > PM_REG_B(x)+PM_REG_L(x)) \ + { \ + PM_REG_I(x) -= PM_REG_L(x); \ + } \ + else if (PM_REG_I(x) < PM_REG_B(x)) \ + { \ + PM_REG_I(x) += PM_REG_L(x); \ + } \ + } \ + } + +#define UPDATE_CIRCULAR_BUFFER_DM(x) \ + { \ + if (DM_REG_L(x) != 0) \ + { \ + if (DM_REG_I(x) > DM_REG_B(x)+DM_REG_L(x)) \ + { \ + DM_REG_I(x) -= DM_REG_L(x); \ + } \ + else if (DM_REG_I(x) < DM_REG_B(x)) \ + { \ + DM_REG_I(x) += DM_REG_L(x); \ + } \ + } \ + } + + +/*****************************************************************************/ + +void adsp21062_device::add_systemreg_write_latency_effect(int sysreg, UINT32 data, UINT32 prev_data) +{ + if (m_systemreg_latency_cycles > 0) + { + //fatalerror("SHARC: add_systemreg_write_latency_effect: already scheduled! (reg: %02X, data: %08X, PC: %08X)\n", systemreg_latency_reg, systemreg_latency_data, m_pc); + systemreg_write_latency_effect(); + } + + m_systemreg_latency_cycles = 2; + m_systemreg_latency_reg = sysreg; + m_systemreg_latency_data = data; + m_systemreg_previous_data = prev_data; +} + +void adsp21062_device::swap_register(UINT32 *a, UINT32 *b) +{ + UINT32 temp = *a; + *a = *b; + *b = temp; +} + +void adsp21062_device::systemreg_write_latency_effect() +{ + int i; + UINT32 data = m_systemreg_latency_data; + UINT32 old_data = m_systemreg_previous_data; + + switch(m_systemreg_latency_reg) + { + case 0xb: /* MODE1 */ + { + UINT32 oldreg = old_data; + m_mode1 = data; + + if ((data & 0x1) != (oldreg & 0x1)) + { + fatalerror("SHARC: systemreg_latency_op: enable I8 bit-reversing\n"); + } + if ((data & 0x2) != (oldreg & 0x2)) + { + fatalerror("SHARC: systemreg_latency_op: enable I0 bit-reversing\n"); + } + if ((data & 0x4) != (oldreg & 0x4)) + { + fatalerror("SHARC: systemreg_latency_op: enable MR alternate\n"); + } + + if ((data & 0x8) != (oldreg & 0x8)) /* Switch DAG1 7-4 */ + { + swap_register(&m_dag1.i[4], &m_dag1_alt.i[4]); + swap_register(&m_dag1.i[5], &m_dag1_alt.i[5]); + swap_register(&m_dag1.i[6], &m_dag1_alt.i[6]); + swap_register(&m_dag1.i[7], &m_dag1_alt.i[7]); + swap_register(&m_dag1.m[4], &m_dag1_alt.m[4]); + swap_register(&m_dag1.m[5], &m_dag1_alt.m[5]); + swap_register(&m_dag1.m[6], &m_dag1_alt.m[6]); + swap_register(&m_dag1.m[7], &m_dag1_alt.m[7]); + swap_register(&m_dag1.l[4], &m_dag1_alt.l[4]); + swap_register(&m_dag1.l[5], &m_dag1_alt.l[5]); + swap_register(&m_dag1.l[6], &m_dag1_alt.l[6]); + swap_register(&m_dag1.l[7], &m_dag1_alt.l[7]); + swap_register(&m_dag1.b[4], &m_dag1_alt.b[4]); + swap_register(&m_dag1.b[5], &m_dag1_alt.b[5]); + swap_register(&m_dag1.b[6], &m_dag1_alt.b[6]); + swap_register(&m_dag1.b[7], &m_dag1_alt.b[7]); + } + if ((data & 0x10) != (oldreg & 0x10)) /* Switch DAG1 3-0 */ + { + swap_register(&m_dag1.i[0], &m_dag1_alt.i[0]); + swap_register(&m_dag1.i[1], &m_dag1_alt.i[1]); + swap_register(&m_dag1.i[2], &m_dag1_alt.i[2]); + swap_register(&m_dag1.i[3], &m_dag1_alt.i[3]); + swap_register(&m_dag1.m[0], &m_dag1_alt.m[0]); + swap_register(&m_dag1.m[1], &m_dag1_alt.m[1]); + swap_register(&m_dag1.m[2], &m_dag1_alt.m[2]); + swap_register(&m_dag1.m[3], &m_dag1_alt.m[3]); + swap_register(&m_dag1.l[0], &m_dag1_alt.l[0]); + swap_register(&m_dag1.l[1], &m_dag1_alt.l[1]); + swap_register(&m_dag1.l[2], &m_dag1_alt.l[2]); + swap_register(&m_dag1.l[3], &m_dag1_alt.l[3]); + swap_register(&m_dag1.b[0], &m_dag1_alt.b[0]); + swap_register(&m_dag1.b[1], &m_dag1_alt.b[1]); + swap_register(&m_dag1.b[2], &m_dag1_alt.b[2]); + swap_register(&m_dag1.b[3], &m_dag1_alt.b[3]); + } + if ((data & 0x20) != (oldreg & 0x20)) /* Switch DAG2 15-12 */ + { + swap_register(&m_dag2.i[4], &m_dag2_alt.i[4]); + swap_register(&m_dag2.i[5], &m_dag2_alt.i[5]); + swap_register(&m_dag2.i[6], &m_dag2_alt.i[6]); + swap_register(&m_dag2.i[7], &m_dag2_alt.i[7]); + swap_register(&m_dag2.m[4], &m_dag2_alt.m[4]); + swap_register(&m_dag2.m[5], &m_dag2_alt.m[5]); + swap_register(&m_dag2.m[6], &m_dag2_alt.m[6]); + swap_register(&m_dag2.m[7], &m_dag2_alt.m[7]); + swap_register(&m_dag2.l[4], &m_dag2_alt.l[4]); + swap_register(&m_dag2.l[5], &m_dag2_alt.l[5]); + swap_register(&m_dag2.l[6], &m_dag2_alt.l[6]); + swap_register(&m_dag2.l[7], &m_dag2_alt.l[7]); + swap_register(&m_dag2.b[4], &m_dag2_alt.b[4]); + swap_register(&m_dag2.b[5], &m_dag2_alt.b[5]); + swap_register(&m_dag2.b[6], &m_dag2_alt.b[6]); + swap_register(&m_dag2.b[7], &m_dag2_alt.b[7]); + } + if ((data & 0x40) != (oldreg & 0x40)) /* Switch DAG2 11-8 */ + { + swap_register(&m_dag2.i[0], &m_dag2_alt.i[0]); + swap_register(&m_dag2.i[1], &m_dag2_alt.i[1]); + swap_register(&m_dag2.i[2], &m_dag2_alt.i[2]); + swap_register(&m_dag2.i[3], &m_dag2_alt.i[3]); + swap_register(&m_dag2.m[0], &m_dag2_alt.m[0]); + swap_register(&m_dag2.m[1], &m_dag2_alt.m[1]); + swap_register(&m_dag2.m[2], &m_dag2_alt.m[2]); + swap_register(&m_dag2.m[3], &m_dag2_alt.m[3]); + swap_register(&m_dag2.l[0], &m_dag2_alt.l[0]); + swap_register(&m_dag2.l[1], &m_dag2_alt.l[1]); + swap_register(&m_dag2.l[2], &m_dag2_alt.l[2]); + swap_register(&m_dag2.l[3], &m_dag2_alt.l[3]); + swap_register(&m_dag2.b[0], &m_dag2_alt.b[0]); + swap_register(&m_dag2.b[1], &m_dag2_alt.b[1]); + swap_register(&m_dag2.b[2], &m_dag2_alt.b[2]); + swap_register(&m_dag2.b[3], &m_dag2_alt.b[3]); + } + if ((data & 0x80) != (oldreg & 0x80)) + { + for (i=8; i<16; i++) + swap_register((UINT32*)&m_r[i].r, (UINT32*)&m_reg_alt[i].r); + } + if ((data & 0x400) != (oldreg & 0x400)) + { + for (i=0; i<8; i++) + swap_register((UINT32*)&m_r[i].r, (UINT32*)&m_reg_alt[i].r); + } + break; + } + default: fatalerror("SHARC: systemreg_latency_op: unknown register %02X at %08X\n", m_systemreg_latency_reg, m_pc); + } + + m_systemreg_latency_reg = -1; +} + +UINT32 adsp21062_device::GET_UREG(int ureg) +{ + int reg = ureg & 0xf; + switch((ureg >> 4) & 0xf) + { + case 0x0: /* R0 - R15 */ + { + return m_r[reg].r; + } + + case 0x1: + { + if (reg & 0x8) /* I8 - I15 */ + { + return m_dag2.i[reg & 0x7]; + } + else /* I0 - I7 */ + { + return m_dag1.i[reg & 0x7]; + } + } + + case 0x2: + { + if (reg & 0x8) /* M8 - M15 */ + { + INT32 r = m_dag2.m[reg & 0x7]; + if (r & 0x800000) r |= 0xff000000; + + return r; + } + else /* M0 - M7 */ + { + return m_dag1.m[reg & 0x7]; + } + } + + case 0x3: + { + if (reg & 0x8) /* L8 - L15 */ + { + return m_dag2.l[reg & 0x7]; + } + else /* L0 - L7 */ + { + return m_dag1.l[reg & 0x7]; + } + } + + case 0x4: + { + if (reg & 0x8) /* B8 - B15 */ + { + return m_dag2.b[reg & 0x7]; + } + else /* B0 - B7 */ + { + return m_dag1.b[reg & 0x7]; + } + } + + case 0x6: + { + switch(reg) + { + case 0x4: return m_pcstack[m_pcstkp]; /* PCSTK */ + default: fatalerror("SHARC: GET_UREG: unknown register %08X at %08X\n", ureg, m_pc); + } + break; + } + + case 0x7: + { + switch(reg) + { + case 0x0: return m_ustat1; /* USTAT1 */ + case 0x1: return m_ustat2; /* USTAT2 */ + case 0x9: return m_irptl; /* IRPTL */ + case 0xa: return m_mode2; /* MODE2 */ + case 0xb: return m_mode1; /* MODE1 */ + case 0xc: /* ASTAT */ + { + UINT32 r = m_astat; + r &= ~0x00780000; + r |= (m_flag[0] << 19); + r |= (m_flag[1] << 20); + r |= (m_flag[2] << 21); + r |= (m_flag[3] << 22); + return r; + } + case 0xd: return m_imask; /* IMASK */ + case 0xe: return m_stky; /* STKY */ + default: fatalerror("SHARC: GET_UREG: unknown register %08X at %08X\n", ureg, m_pc); + } + break; + } + + case 0xd: + { + switch(reg) + { + /* PX needs to be handled separately if the whole 48 bits are needed */ + case 0xb: return (UINT32)(m_px); /* PX */ + case 0xc: return (UINT16)(m_px); /* PX1 */ + case 0xd: return (UINT32)(m_px >> 16); /* PX2 */ + default: fatalerror("SHARC: GET_UREG: unknown register %08X at %08X\n", ureg, m_pc); + } + break; + } + + default: fatalerror("SHARC: GET_UREG: unknown register %08X at %08X\n", ureg, m_pc); + } +} + +void adsp21062_device::SET_UREG(int ureg, UINT32 data) +{ + int reg = ureg & 0xf; + switch((ureg >> 4) & 0xf) + { + case 0x0: /* R0 - R15 */ + m_r[reg].r = data; + break; + + case 0x1: + if (reg & 0x8) /* I8 - I15 */ + { + m_dag2.i[reg & 0x7] = data; + } + else /* I0 - I7 */ + { + m_dag1.i[reg & 0x7] = data; + } + break; + + case 0x2: + if (reg & 0x8) /* M8 - M15 */ + { + m_dag2.m[reg & 0x7] = data; + } + else /* M0 - M7 */ + { + m_dag1.m[reg & 0x7] = data; + } + break; + + case 0x3: + if (reg & 0x8) /* L8 - L15 */ + { + m_dag2.l[reg & 0x7] = data; + } + else /* L0 - L7 */ + { + m_dag1.l[reg & 0x7] = data; + } + break; + + case 0x4: + // Note: loading B also loads the same value in I + if (reg & 0x8) /* B8 - B15 */ + { + m_dag2.b[reg & 0x7] = data; + m_dag2.i[reg & 0x7] = data; + } + else /* B0 - B7 */ + { + m_dag1.b[reg & 0x7] = data; + m_dag1.i[reg & 0x7] = data; + } + break; + + case 0x6: + switch (reg) + { + case 0x5: m_pcstkp = data; break; /* PCSTKP */ + case 0x8: m_lcntr = data; break; /* LCNTR */ + default: fatalerror("SHARC: SET_UREG: unknown register %08X at %08X\n", ureg, m_pc); + } + break; + + case 0x7: /* system regs */ + switch(reg) + { + case 0x0: m_ustat1 = data; break; /* USTAT1 */ + case 0x1: m_ustat2 = data; break; /* USTAT2 */ + + case 0x9: m_irptl = data; break; /* IRPTL */ + case 0xa: m_mode2 = data; break; /* MODE2 */ + + case 0xb: /* MODE1 */ + { + add_systemreg_write_latency_effect(reg, data, m_mode1); + m_mode1 = data; + break; + } + + case 0xc: m_astat = data; break; /* ASTAT */ + + case 0xd: /* IMASK */ + { + check_interrupts(); + m_imask = data; + break; + } + + case 0xe: m_stky = data; break; /* STKY */ + default: fatalerror("SHARC: SET_UREG: unknown register %08X at %08X\n", ureg, m_pc); + } + break; + + case 0xd: + switch(reg) + { + case 0xc: m_px &= U64(0xffffffffffff0000); m_px |= (data & 0xffff); break; /* PX1 */ + case 0xd: m_px &= U64(0x000000000000ffff); m_px |= (UINT64)data << 16; break; /* PX2 */ + default: fatalerror("SHARC: SET_UREG: unknown register %08X at %08X\n", ureg, m_pc); + } + break; + + default: fatalerror("SHARC: SET_UREG: unknown register %08X at %08X\n", ureg, m_pc); + } +} + +/*****************************************************************************/ +#define SET_FLAG_SV_LSHIFT(x, shift) if((x) & ((UINT32)0xffffffff << shift)) m_astat |= SV +#define SET_FLAG_SV_RSHIFT(x, shift) if((x) & ((UINT32)0xffffffff >> shift)) m_astat |= SV + +#define SET_FLAG_SZ(x) if((x) == 0) m_astat |= SZ + +#define MAKE_EXTRACT_MASK(start_bit, length) ((0xffffffff << start_bit) & (((UINT32)0xffffffff) >> (32 - (start_bit + length)))) + +void adsp21062_device::SHIFT_OPERATION_IMM(int shiftop, int data, int rn, int rx) +{ + INT8 shift = data & 0xff; + int bit = data & 0x3f; + int len = (data >> 6) & 0x3f; + + m_astat &= ~(SZ|SV|SS); + + switch(shiftop) + { + case 0x00: /* LSHIFT Rx BY */ + { + if(shift < 0) { + REG(rn) = (shift > -32 ) ? (REG(rx) >> -shift) : 0; + } else { + REG(rn) = (shift < 32) ? (REG(rx) << shift) : 0; + if (shift > 0) + { + m_astat |= SV; + } + } + SET_FLAG_SZ(REG(rn)); + break; + } + + case 0x01: /* ASHIFT Rx BY */ + { + if (shift < 0) + { + REG(rn) = (shift > -32) ? ((INT32)REG(rx) >> -shift) : ((REG(rx) & 0x80000000) ? 0xffffffff : 0); + } + else + { + REG(rn) = (shift < 32) ? ((INT32)REG(rx) << shift) : 0; + if (shift > 0) + { + m_astat |= SV; + } + } + SET_FLAG_SZ(REG(rn)); + break; + } + + case 0x02: /* ROT Rx BY */ + { + if (shift < 0) + { + int s = (-shift) & 0x1f; + REG(rn) = (((UINT32)REG(rx) >> s) & ((UINT32)(0xffffffff) >> s)) | + (((UINT32)REG(rx) << (32-s)) & ((UINT32)(0xffffffff) << (32-s))); + } + else + { + int s = shift & 0x1f; + REG(rn) = (((UINT32)REG(rx) << s) & ((UINT32)(0xffffffff) << s)) | + (((UINT32)REG(rx) >> (32-s)) & ((UINT32)(0xffffffff) >> (32-s))); + } + SET_FLAG_SZ(REG(rn)); + break; + } + + case 0x08: /* Rn = Rn OR LSHIFT Rx BY */ + { + UINT32 r = 0; + if(shift < 0) { + r = (shift > -32 ) ? (REG(rx) >> -shift) : 0; + } else { + r = (shift < 32) ? (REG(rx) << shift) : 0; + if (shift > 0) + { + m_astat |= SV; + } + } + SET_FLAG_SZ(r); + + REG(rn) = REG(rn) | r; + break; + } + + case 0x10: /* FEXT Rx BY : */ + { + UINT32 ext = REG(rx) & MAKE_EXTRACT_MASK(bit, len); + REG(rn) = ext >> bit; + + SET_FLAG_SZ(REG(rn)); + if (bit+len > 32) + { + m_astat |= SV; + } + break; + } + + case 0x11: /* TODO */ + break; + + case 0x12: /* FEXT Rx BY : (Sign Extended) */ + { + UINT32 ext = (REG(rx) & MAKE_EXTRACT_MASK(bit, len)) >> bit; + if (ext & (1 << (len-1))) { + ext |= (UINT32)0xffffffff << (len-1); + } + REG(rn) = ext; + + SET_FLAG_SZ(REG(rn)); + if (bit+len > 32) + { + m_astat |= SV; + } + break; + } + + case 0x13: /* FDEP Rx BY Ry : (Sign Extended) */ + { + UINT32 ext = REG(rx) & MAKE_EXTRACT_MASK(0, len); + if (ext & (1 << (len-1))) { + ext |= (UINT32)0xffffffff << (len-1); + } + REG(rn) = ext << bit; + + SET_FLAG_SZ(REG(rn)); + if (bit+len > 32) + { + m_astat |= SV; + } + break; + } + + case 0x19: /* Rn = Rn OR FDEP Rx BY : */ + { + UINT32 ext = REG(rx) & MAKE_EXTRACT_MASK(0, len); + + REG(rn) |= ext << bit; + + SET_FLAG_SZ(REG(rn)); + if (bit+len > 32) + { + m_astat |= SV; + } + break; + } + + case 0x30: /* BSET Rx BY */ + { + REG(rn) = REG(rx); + if (data >= 0 && data < 32) + { + REG(rn) |= (1 << data); + } + else + { + m_astat |= SV; + } + SET_FLAG_SZ(REG(rn)); + break; + } + + case 0x31: /* BCLR Rx BY */ + { + REG(rn) = REG(rx); + if (data >= 0 && data < 32) + { + REG(rn) &= ~(1 << data); + } + else + { + m_astat |= SV; + } + SET_FLAG_SZ(REG(rn)); + break; + } + + case 0x32: /* BTGL Rx BY */ + { + REG(rn) = REG(rx); + if (data >= 0 && data < 32) + { + REG(rn) ^= (1 << data); + } + else + { + m_astat |= SV; + } + SET_FLAG_SZ(REG(rn)); + break; + } + + case 0x33: /* BTST Rx BY */ + { + if (data < 32) + { + UINT32 r = REG(rx) & (1 << data); + + SET_FLAG_SZ(r); + } + else + { + m_astat |= SZ | SV; + } + break; + } + + default: fatalerror("SHARC: unimplemented shift operation %02X at %08X\n", shiftop, m_pc); + } +} + +#include "compute.inc" + +void adsp21062_device::COMPUTE(UINT32 opcode) +{ + int multiop; + int op = (opcode >> 12) & 0xff; + int cu = (opcode >> 20) & 0x3; + int rn = (opcode >> 8) & 0xf; + int rx = (opcode >> 4) & 0xf; + int ry = (opcode >> 0) & 0xf; + //int rs = (opcode >> 12) & 0xf; + //int ra = rn; + //int rm = rs; + + if(opcode & 0x400000) /* Multi-function opcode */ + { + int fm = (opcode >> 12) & 0xf; + int fa = (opcode >> 8) & 0xf; + int fxm = (opcode >> 6) & 0x3; // registers 0 - 3 + int fym = ((opcode >> 4) & 0x3) + 4; // registers 4 - 7 + int fxa = ((opcode >> 2) & 0x3) + 8; // registers 8 - 11 + int fya = (opcode & 0x3) + 12; // registers 12 - 15 + + multiop = (opcode >> 16) & 0x3f; + switch(multiop) + { + case 0x00: compute_multi_mr_to_reg(op & 0xf, rn); break; + case 0x01: compute_multi_reg_to_mr(op & 0xf, rn); break; + + case 0x04: /* Rm = Rxm * Rym (SSFR), Ra = Rxa + Rya */ + { + compute_mul_ssfr_add(fm, fxm, fym, fa, fxa, fya); + break; + } + + case 0x05: /* Rm = Rxm * Rym (SSFR), Ra = Rxa - Rya */ + { + compute_mul_ssfr_sub(fm, fxm, fym, fa, fxa, fya); + break; + } + + case 0x18: /* Fm = Fxm * Fym, Fa = Fxa + Fya */ + { + compute_fmul_fadd(fm, fxm, fym, fa, fxa, fya); + break; + } + + case 0x19: /* Fm = Fxm * Fym, Fa = Fxa - Fya */ + { + compute_fmul_fsub(fm, fxm, fym, fa, fxa, fya); + break; + } + + case 0x1a: /* Fm = Fxm * Fym, Fa = FLOAT Fxa BY Fya */ + { + compute_fmul_float_scaled(fm, fxm, fym, fa, fxa, fya); + break; + } + + case 0x1b: /* Fm = Fxm * Fym, Fa = FIX Fxa BY Fya */ + { + compute_fmul_fix_scaled(fm, fxm, fym, fa, fxa, fya); + break; + } + + case 0x1c: /* TODO! fmul_avg */ + { + compute_fmul_avg(fm, fxm, fym, fa, fxa, fya); + break; + } + + case 0x1e: /* Fm = Fxm * Fym, Fa = MAX(Fxa, Fya) */ + { + compute_fmul_fmax(fm, fxm, fym, fa, fxa, fya); + break; + } + + case 0x1f: /* Fm = Fxm * Fym, Fa = MIN(Fxa, Fya) */ + { + compute_fmul_fmin(fm, fxm, fym, fa, fxa, fya); + break; + } + + case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37: + case 0x38: case 0x39: case 0x3a: case 0x3b: case 0x3c: case 0x3d: case 0x3e: case 0x3f: + { + /* Parallel Multiplier & Dual Add/Subtract */ + /* Floating-point */ + int fs = (opcode >> 16) & 0xf; + compute_fmul_dual_fadd_fsub(fm, fxm, fym, fa, fs, fxa, fya); + break; + } + + default: + fatalerror("SHARC: compute: multi-function opcode %02X not implemented ! (%08X, %08X)\n", multiop, m_pc, opcode); + break; + } + } + else /* Single-function opcode */ + { + switch(cu) + { + /* ALU operations */ + case 0: + { + switch(op) + { + case 0x01: compute_add(rn, rx, ry); break; + case 0x02: compute_sub(rn, rx, ry); break; + case 0x05: compute_add_ci(rn, rx, ry); break; + case 0x06: compute_sub_ci(rn, rx, ry); break; + case 0x0a: compute_comp(rx, ry); break; + case 0x21: compute_pass(rn, rx); break; + case 0x22: compute_neg(rn, rx); break; + case 0x29: compute_inc(rn, rx); break; + case 0x2a: compute_dec(rn, rx); break; + case 0x40: compute_and(rn, rx, ry); break; + case 0x41: compute_or(rn, rx, ry); break; + case 0x42: compute_xor(rn, rx, ry); break; + case 0x43: compute_not(rn, rx); break; + case 0x61: compute_min(rn, rx, ry); break; + case 0x62: compute_max(rn, rx, ry); break; + case 0x81: compute_fadd(rn, rx, ry); break; + case 0x82: compute_fsub(rn, rx, ry); break; + case 0x89: compute_favg(rn, rx, ry); break; + case 0x8a: compute_fcomp(rx, ry); break; + case 0x91: compute_fabs_plus(rn, rx, ry); break; + case 0xa1: compute_fpass(rn, rx); break; + case 0xa2: compute_fneg(rn, rx); break; + case 0xb0: compute_fabs(rn, rx); break; + case 0xbd: compute_scalb(rn, rx, ry); break; + case 0xc1: compute_logb(rn, rx); break; + case 0xc4: compute_recips(rn, rx); break; + case 0xc5: compute_rsqrts(rn, rx); break; + case 0xc9: compute_fix(rn, rx); break; + case 0xca: compute_float(rn, rx); break; + case 0xd9: compute_fix_scaled(rn, rx, ry); break; + case 0xda: compute_float_scaled(rn, rx, ry); break; + case 0xe1: compute_fmin(rn, rx, ry); break; + case 0xe2: compute_fmax(rn, rx, ry); break; + case 0xe3: compute_fclip(rn, rx, ry); break; + + case 0x70: case 0x71: case 0x72: case 0x73: case 0x74: case 0x75: case 0x76: case 0x77: + case 0x78: case 0x79: case 0x7a: case 0x7b: case 0x7c: case 0x7d: case 0x7e: case 0x7f: + { + /* Fixed-point Dual Add/Subtract */ + int rs = (opcode >> 12) & 0xf; + int ra = (opcode >> 8) & 0xf; + compute_dual_add_sub(ra, rs, rx, ry); + break; + } + + case 0xf0: case 0xf1: case 0xf2: case 0xf3: case 0xf4: case 0xf5: case 0xf6: case 0xf7: + case 0xf8: case 0xf9: case 0xfa: case 0xfb: case 0xfc: case 0xfd: case 0xfe: case 0xff: + { + /* Floating-point Dual Add/Subtract */ + int rs = (opcode >> 12) & 0xf; + int ra = (opcode >> 8) & 0xf; + compute_dual_fadd_fsub(ra, rs, rx, ry); + break; + } + + default: fatalerror("SHARC: compute: unimplemented ALU operation %02X (%08X, %08X)\n", op, m_pc, opcode); + } + break; + } + + + /* Multiplier operations */ + case 1: + { + switch(op) + { + case 0x14: m_mrf = 0; break; + case 0x16: m_mrb = 0; break; + + case 0x30: compute_fmul(rn, rx, ry); break; + case 0x40: compute_mul_uuin(rn, rx, ry); break; + case 0x70: compute_mul_ssin(rn, rx, ry); break; + + case 0xb0: REG(rn) = compute_mrf_plus_mul_ssin(rx, ry); break; + case 0xb2: REG(rn) = compute_mrb_plus_mul_ssin(rx, ry); break; + + default: + fatalerror("SHARC: compute: multiplier operation %02X not implemented ! (%08X, %08X)\n", op, m_pc, opcode); + break; + } + break; + } + + + /* Shifter operations */ + case 2: + { + m_astat &= ~(SZ|SV|SS); + + op >>= 2; + switch(op) + { + case 0x00: /* LSHIFT Rx BY Ry*/ + { + int shift = REG(ry); + if(shift < 0) + { + REG(rn) = (shift > -32 ) ? (REG(rx) >> -shift) : 0; + } + else + { + REG(rn) = (shift < 32) ? (REG(rx) << shift) : 0; + if (shift > 0) + { + m_astat |= SV; + } + } + SET_FLAG_SZ(REG(rn)); + break; + } + + case 0x02: /* ROT Rx BY Ry */ + { + int shift = REG(ry); + if (shift < 0) + { + int s = (-shift) & 0x1f; + REG(rn) = (((UINT32)REG(rx) >> s) & ((UINT32)(0xffffffff) >> s)) | + (((UINT32)REG(rx) << (32-s)) & ((UINT32)(0xffffffff) << (32-s))); + } + else + { + int s = shift & 0x1f; + REG(rn) = (((UINT32)REG(rx) << s) & ((UINT32)(0xffffffff) << s)) | + (((UINT32)REG(rx) >> (32-s)) & ((UINT32)(0xffffffff) >> (32-s))); + if (shift > 0) + { + m_astat |= SV; + } + } + SET_FLAG_SZ(REG(rn)); + break; + } + + case 0x08: /* Rn = Rn OR LSHIFT Rx BY Ry*/ + { + INT8 shift = REG(ry); + if(shift < 0) { + REG(rn) = REG(rn) | ((shift > -32 ) ? (REG(rx) >> -shift) : 0); + } else { + REG(rn) = REG(rn) | ((shift < 32) ? (REG(rx) << shift) : 0); + if (shift > 0) + { + m_astat |= SV; + } + } + SET_FLAG_SZ(REG(rn)); + break; + } + + case 0x10: /* FEXT Rx BY Ry */ + { + int bit = REG(ry) & 0x3f; + int len = (REG(ry) >> 6) & 0x3f; + UINT32 ext = REG(rx) & MAKE_EXTRACT_MASK(bit, len); + REG(rn) = ext >> bit; + + SET_FLAG_SZ(REG(rn)); + if (bit+len > 32) + { + m_astat |= SV; + } + break; + } + + case 0x12: /* FEXT Rx BY Ry (Sign Extended) */ + { + int bit = REG(ry) & 0x3f; + int len = (REG(ry) >> 6) & 0x3f; + UINT32 ext = (REG(rx) & MAKE_EXTRACT_MASK(bit, len)) >> bit; + if (ext & (1 << (len-1))) { + ext |= (UINT32)0xffffffff << (len-1); + } + REG(rn) = ext; + + SET_FLAG_SZ(REG(rn)); + if (bit+len > 32) + { + m_astat |= SV; + } + break; + } + + case 0x19: /* Rn = Rn OR FDEP Rx BY Ry */ + { + int bit = REG(ry) & 0x3f; + int len = (REG(ry) >> 6) & 0x3f; + UINT32 ext = REG(rx) & MAKE_EXTRACT_MASK(0, len); + + REG(rn) |= ext << bit; + + SET_FLAG_SZ(REG(rn)); + if (bit+len > 32) + { + m_astat |= SV; + } + break; + } + + case 0x30: /* BSET Rx BY Ry */ + { + UINT32 shift = REG(ry); + REG(rn) = REG(rx); + if (shift < 32) + { + REG(rn) |= (1 << shift); + } + else + { + m_astat |= SV; + } + SET_FLAG_SZ(REG(rn)); + break; + } + + case 0x31: /* BCLR Rx BY Ry */ + { + UINT32 shift = REG(ry); + REG(rn) = REG(rx); + if (shift < 32) + { + REG(rn) &= ~(1 << shift); + } + else + { + m_astat |= SV; + } + SET_FLAG_SZ(REG(rn)); + break; + } + + case 0x33: /* BTST Rx BY Ry */ + { + UINT32 shift = REG(ry); + if (shift < 32) + { + UINT32 r = REG(rx) & (1 << shift); + + SET_FLAG_SZ(r); + } + else + { + m_astat |= SZ | SV; + } + break; + } + + default: + fatalerror("SHARC: compute: shift operation %02X not implemented ! (%08X, %08X)\n", op, m_pc, opcode); + } + break; + } + + default: + fatalerror("SHARC: compute: invalid single-function operation %02X\n", cu); + } + } +} + +void adsp21062_device::PUSH_PC(UINT32 pc) +{ + m_pcstkp++; + if(m_pcstkp >= 32) + { + fatalerror("SHARC: PC Stack overflow!\n"); + } + + if (m_pcstkp == 0) + { + m_stky |= 0x400000; + } + else + { + m_stky &= ~0x400000; + } + + m_pcstk = pc; + m_pcstack[m_pcstkp] = pc; +} + +UINT32 adsp21062_device::POP_PC() +{ + m_pcstk = m_pcstack[m_pcstkp]; + + if(m_pcstkp == 0) + { + fatalerror("SHARC: PC Stack underflow!\n"); + } + + m_pcstkp--; + + if (m_pcstkp == 0) + { + m_stky |= 0x400000; + } + else + { + m_stky &= ~0x400000; + } + + return m_pcstk; +} + +UINT32 adsp21062_device::TOP_PC() +{ + return m_pcstack[m_pcstkp]; +} + +void adsp21062_device::PUSH_LOOP(UINT32 addr, UINT32 code, UINT32 type, UINT32 count) +{ + m_lstkp++; + if(m_lstkp >= 6) + { + fatalerror("SHARC: Loop Stack overflow!\n"); + } + + if (m_lstkp == 0) + { + m_stky |= 0x4000000; + } + else + { + m_stky &= ~0x4000000; + } + + m_lcstack[m_lstkp] = count; + m_lastack[m_lstkp] = (type << 30) | (code << 24) | addr; + m_curlcntr = count; + + m_laddr.addr = addr; + m_laddr.code = code; + m_laddr.loop_type = type; +} + +void adsp21062_device::POP_LOOP() +{ + if(m_lstkp == 0) + { + fatalerror("SHARC: Loop Stack underflow!\n"); + } + + m_lstkp--; + + if (m_lstkp == 0) + { + m_stky |= 0x4000000; + } + else + { + m_stky &= ~0x4000000; + } + + m_curlcntr = m_lcstack[m_lstkp]; + + m_laddr.addr = m_lastack[m_lstkp] & 0xffffff; + m_laddr.code = (m_lastack[m_lstkp] >> 24) & 0x1f; + m_laddr.loop_type = (m_lastack[m_lstkp] >> 30) & 0x3; +} + +void adsp21062_device::PUSH_STATUS_STACK() +{ + m_status_stkp++; + if (m_status_stkp >= 5) + { + fatalerror("SHARC: Status stack overflow!\n"); + } + + if (m_status_stkp == 0) + { + m_stky |= 0x1000000; + } + else + { + m_stky &= ~0x1000000; + } + + m_status_stack[m_status_stkp].mode1 = GET_UREG(REG_MODE1); + m_status_stack[m_status_stkp].astat = GET_UREG(REG_ASTAT); +} + +void adsp21062_device::POP_STATUS_STACK() +{ + SET_UREG(REG_MODE1, m_status_stack[m_status_stkp].mode1); + SET_UREG(REG_ASTAT, m_status_stack[m_status_stkp].astat); + + m_status_stkp--; + if (m_status_stkp < 0) + { + fatalerror("SHARC: Status stack underflow!\n"); + } + + if (m_status_stkp == 0) + { + m_stky |= 0x1000000; + } + else + { + m_stky &= ~0x1000000; + } +} + +int adsp21062_device::IF_CONDITION_CODE(int cond) +{ + switch(cond) + { + case 0x00: return m_astat & AZ; /* EQ */ + case 0x01: return !(m_astat & AZ) && (m_astat & AN); /* LT */ + case 0x02: return (m_astat & AZ) || (m_astat & AN); /* LE */ + case 0x03: return (m_astat & AC); /* AC */ + case 0x04: return (m_astat & AV); /* AV */ + case 0x05: return (m_astat & MV); /* MV */ + case 0x06: return (m_astat & MN); /* MS */ + case 0x07: return (m_astat & SV); /* SV */ + case 0x08: return (m_astat & SZ); /* SZ */ + case 0x09: return (m_flag[0] != 0); /* FLAG0 */ + case 0x0a: return (m_flag[1] != 0); /* FLAG1 */ + case 0x0b: return (m_flag[2] != 0); /* FLAG2 */ + case 0x0c: return (m_flag[3] != 0); /* FLAG3 */ + case 0x0d: return (m_astat & BTF); /* TF */ + case 0x0e: return 0; /* BM */ + case 0x0f: return (m_curlcntr!=1); /* NOT LCE */ + case 0x10: return !(m_astat & AZ); /* NOT EQUAL */ + case 0x11: return (m_astat & AZ) || !(m_astat & AN); /* GE */ + case 0x12: return !(m_astat & AZ) && !(m_astat & AN); /* GT */ + case 0x13: return !(m_astat & AC); /* NOT AC */ + case 0x14: return !(m_astat & AV); /* NOT AV */ + case 0x15: return !(m_astat & MV); /* NOT MV */ + case 0x16: return !(m_astat & MN); /* NOT MS */ + case 0x17: return !(m_astat & SV); /* NOT SV */ + case 0x18: return !(m_astat & SZ); /* NOT SZ */ + case 0x19: return (m_flag[0] == 0); /* NOT FLAG0 */ + case 0x1a: return (m_flag[1] == 0); /* NOT FLAG1 */ + case 0x1b: return (m_flag[2] == 0); /* NOT FLAG2 */ + case 0x1c: return (m_flag[3] == 0); /* NOT FLAG3 */ + case 0x1d: return !(m_astat & BTF); /* NOT TF */ + case 0x1e: return 1; /* NOT BM */ + case 0x1f: return 1; /* TRUE */ + } + return 1; +} + +int adsp21062_device::DO_CONDITION_CODE(int cond) +{ + switch(cond) + { + case 0x00: return m_astat & AZ; /* EQ */ + case 0x01: return !(m_astat & AZ) && (m_astat & AN); /* LT */ + case 0x02: return (m_astat & AZ) || (m_astat & AN); /* LE */ + case 0x03: return (m_astat & AC); /* AC */ + case 0x04: return (m_astat & AV); /* AV */ + case 0x05: return (m_astat & MV); /* MV */ + case 0x06: return (m_astat & MN); /* MS */ + case 0x07: return (m_astat & SV); /* SV */ + case 0x08: return (m_astat & SZ); /* SZ */ + case 0x09: return (m_flag[0] != 0); /* FLAG0 */ + case 0x0a: return (m_flag[1] != 0); /* FLAG1 */ + case 0x0b: return (m_flag[2] != 0); /* FLAG2 */ + case 0x0c: return (m_flag[3] != 0); /* FLAG3 */ + case 0x0d: return (m_astat & BTF); /* TF */ + case 0x0e: return 0; /* BM */ + case 0x0f: return (m_curlcntr==1); /* LCE */ + case 0x10: return !(m_astat & AZ); /* NOT EQUAL */ + case 0x11: return (m_astat & AZ) || !(m_astat & AN); /* GE */ + case 0x12: return !(m_astat & AZ) && !(m_astat & AN); /* GT */ + case 0x13: return !(m_astat & AC); /* NOT AC */ + case 0x14: return !(m_astat & AV); /* NOT AV */ + case 0x15: return !(m_astat & MV); /* NOT MV */ + case 0x16: return !(m_astat & MN); /* NOT MS */ + case 0x17: return !(m_astat & SV); /* NOT SV */ + case 0x18: return !(m_astat & SZ); /* NOT SZ */ + case 0x19: return (m_flag[0] == 0); /* NOT FLAG0 */ + case 0x1a: return (m_flag[1] == 0); /* NOT FLAG1 */ + case 0x1b: return (m_flag[2] == 0); /* NOT FLAG2 */ + case 0x1c: return (m_flag[3] == 0); /* NOT FLAG3 */ + case 0x1d: return !(m_astat & BTF); /* NOT TF */ + case 0x1e: return 1; /* NOT BM */ + case 0x1f: return 0; /* FALSE (FOREVER) */ + } + return 1; +} + +/*****************************************************************************/ +/* | 001xxxxxx | */ + +/* compute / dreg <-> DM / dreg <-> PM */ +void adsp21062_device::sharcop_compute_dreg_dm_dreg_pm() +{ + int pm_dreg = (m_opcode >> 23) & 0xf; + int pmm = (m_opcode >> 27) & 0x7; + int pmi = (m_opcode >> 30) & 0x7; + int dm_dreg = (m_opcode >> 33) & 0xf; + int dmm = (m_opcode >> 38) & 0x7; + int dmi = (m_opcode >> 41) & 0x7; + int pmd = (m_opcode >> 37) & 0x1; + int dmd = (m_opcode >> 44) & 0x1; + int compute = m_opcode & 0x7fffff; + + /* due to parallelity issues, source DREGs must be saved */ + /* because the compute operation may change them */ + UINT32 parallel_pm_dreg = REG(pm_dreg); + UINT32 parallel_dm_dreg = REG(dm_dreg); + + if (compute) + { + COMPUTE(compute); + } + + if (pmd) // dreg -> PM + { + pm_write32(PM_REG_I(pmi), parallel_pm_dreg); + PM_REG_I(pmi) += PM_REG_M(pmm); + UPDATE_CIRCULAR_BUFFER_PM(pmi); + } + else // PM -> dreg + { + REG(pm_dreg) = pm_read32(PM_REG_I(pmi)); + PM_REG_I(pmi) += PM_REG_M(pmm); + UPDATE_CIRCULAR_BUFFER_PM(pmi); + } + + if (dmd) // dreg -> DM + { + dm_write32(DM_REG_I(dmi), parallel_dm_dreg); + DM_REG_I(dmi) += DM_REG_M(dmm); + UPDATE_CIRCULAR_BUFFER_DM(dmi); + } + else // DM -> dreg + { + REG(dm_dreg) = dm_read32(DM_REG_I(dmi)); + DM_REG_I(dmi) += DM_REG_M(dmm); + UPDATE_CIRCULAR_BUFFER_DM(dmi); + } +} + +/*****************************************************************************/ +/* | 00000001x | */ + +/* compute */ +void adsp21062_device::sharcop_compute() +{ + int cond = (m_opcode >> 33) & 0x1f; + int compute = m_opcode & 0x7fffff; + + if (IF_CONDITION_CODE(cond) && compute != 0) + { + COMPUTE(compute); + } +} + +/*****************************************************************************/ +/* | 010xxxxxx | */ + +/* compute / ureg <-> DM|PM, pre-modify */ +void adsp21062_device::sharcop_compute_ureg_dmpm_premod() +{ + int i = (m_opcode >> 41) & 0x7; + int m = (m_opcode >> 38) & 0x7; + int cond = (m_opcode >> 33) & 0x1f; + int g = (m_opcode >> 32) & 0x1; + int d = (m_opcode >> 31) & 0x1; + int ureg = (m_opcode >> 23) & 0xff; + int compute = m_opcode & 0x7fffff; + + if (IF_CONDITION_CODE(cond)) + { + /* due to parallelity issues, source UREG must be saved */ + /* because the compute operation may change it */ + UINT32 parallel_ureg = GET_UREG(ureg); + + if (compute) + { + COMPUTE(compute); + } + + if (g) /* PM */ + { + if (d) /* ureg -> PM */ + { + if (ureg == 0xdb) /* PX register access is always 48-bit */ + { + pm_write48(PM_REG_I(i)+PM_REG_M(m), m_px); + } + else + { + pm_write32(PM_REG_I(i)+PM_REG_M(m), parallel_ureg); + } + } + else /* PM <- ureg */ + { + if (ureg == 0xdb) /* PX register access is always 48-bit */ + { + m_px = pm_read48(PM_REG_I(i)+PM_REG_M(m)); + } + else + { + SET_UREG(ureg, pm_read32(PM_REG_I(i)+PM_REG_M(m))); + } + } + } + else /* DM */ + { + if (d) /* ureg -> DM */ + { + dm_write32(DM_REG_I(i)+DM_REG_M(m), parallel_ureg); + } + else /* DM <- ureg */ + { + SET_UREG(ureg, dm_read32(DM_REG_I(i)+DM_REG_M(m))); + } + } + } +} + +/* compute / ureg <-> DM|PM, post-modify */ +void adsp21062_device::sharcop_compute_ureg_dmpm_postmod() +{ + int i = (m_opcode >> 41) & 0x7; + int m = (m_opcode >> 38) & 0x7; + int cond = (m_opcode >> 33) & 0x1f; + int g = (m_opcode >> 32) & 0x1; + int d = (m_opcode >> 31) & 0x1; + int ureg = (m_opcode >> 23) & 0xff; + int compute = m_opcode & 0x7fffff; + + if(IF_CONDITION_CODE(cond)) + { + /* due to parallelity issues, source UREG must be saved */ + /* because the compute operation may change it */ + UINT32 parallel_ureg = GET_UREG(ureg); + + if (compute) + { + COMPUTE(compute); + } + + if (g) /* PM */ + { + if (d) /* ureg -> PM */ + { + if (ureg == 0xdb) /* PX register access is always 48-bit */ + { + pm_write48(PM_REG_I(i), m_px); + } + else + { + pm_write32(PM_REG_I(i), parallel_ureg); + } + PM_REG_I(i) += PM_REG_M(m); + UPDATE_CIRCULAR_BUFFER_PM(i); + } + else /* PM <- ureg */ + { + if (ureg == 0xdb) /* PX register access is always 48-bit */ + { + m_px = pm_read48(PM_REG_I(i)); + } + else + { + SET_UREG(ureg, pm_read32(PM_REG_I(i))); + } + PM_REG_I(i) += PM_REG_M(m); + UPDATE_CIRCULAR_BUFFER_PM(i); + } + } + else /* DM */ + { + if (d) /* ureg -> DM */ + { + dm_write32(DM_REG_I(i), parallel_ureg); + DM_REG_I(i) += DM_REG_M(m); + UPDATE_CIRCULAR_BUFFER_DM(i); + } + else /* DM <- ureg */ + { + SET_UREG(ureg, dm_read32(DM_REG_I(i))); + DM_REG_I(i) += DM_REG_M(m); + UPDATE_CIRCULAR_BUFFER_DM(i); + } + } + } +} + +/*****************************************************************************/ +/* | 0110xxxxx | */ + +/* compute / dreg <- DM, immediate modify */ +void adsp21062_device::sharcop_compute_dm_to_dreg_immmod() +{ + int cond = (m_opcode >> 33) & 0x1f; + int u = (m_opcode >> 38) & 0x1; + int dreg = (m_opcode >> 23) & 0xf; + int i = (m_opcode >> 41) & 0x7; + int mod = SIGN_EXTEND6((m_opcode >> 27) & 0x3f); + int compute = m_opcode & 0x7fffff; + + if (IF_CONDITION_CODE(cond)) + { + if (compute != 0) + { + COMPUTE(compute); + } + + if (u) /* post-modify with update */ + { + REG(dreg) = dm_read32(DM_REG_I(i)); + DM_REG_I(i) += mod; + UPDATE_CIRCULAR_BUFFER_DM(i); + } + else /* pre-modify, no update */ + { + REG(dreg) = dm_read32(DM_REG_I(i) + mod); + } + } +} + +/* compute / dreg -> DM, immediate modify */ +void adsp21062_device::sharcop_compute_dreg_to_dm_immmod() +{ + int cond = (m_opcode >> 33) & 0x1f; + int u = (m_opcode >> 38) & 0x1; + int dreg = (m_opcode >> 23) & 0xf; + int i = (m_opcode >> 41) & 0x7; + int mod = SIGN_EXTEND6((m_opcode >> 27) & 0x3f); + int compute = m_opcode & 0x7fffff; + + /* due to parallelity issues, source REG must be saved */ + /* because the shift operation may change it */ + UINT32 parallel_dreg = REG(dreg); + + if (IF_CONDITION_CODE(cond)) + { + if (compute != 0) + { + COMPUTE(compute); + } + + if (u) /* post-modify with update */ + { + dm_write32(DM_REG_I(i), parallel_dreg); + DM_REG_I(i) += mod; + UPDATE_CIRCULAR_BUFFER_DM(i); + } + else /* pre-modify, no update */ + { + dm_write32(DM_REG_I(i) + mod, parallel_dreg); + } + } +} + +/* compute / dreg <- PM, immediate modify */ +void adsp21062_device::sharcop_compute_pm_to_dreg_immmod() +{ + int cond = (m_opcode >> 33) & 0x1f; + int u = (m_opcode >> 38) & 0x1; + int dreg = (m_opcode >> 23) & 0xf; + int i = (m_opcode >> 41) & 0x7; + int mod = SIGN_EXTEND6((m_opcode >> 27) & 0x3f); + int compute = m_opcode & 0x7fffff; + + if (IF_CONDITION_CODE(cond)) + { + if (compute != 0) + { + COMPUTE(compute); + } + + if (u) /* post-modify with update */ + { + REG(dreg) = pm_read32(PM_REG_I(i)); + PM_REG_I(i) += mod; + UPDATE_CIRCULAR_BUFFER_PM(i); + } + else /* pre-modify, no update */ + { + REG(dreg) = pm_read32(PM_REG_I(i) + mod); + } + } +} + +/* compute / dreg -> PM, immediate modify */ +void adsp21062_device::sharcop_compute_dreg_to_pm_immmod() +{ + int cond = (m_opcode >> 33) & 0x1f; + int u = (m_opcode >> 38) & 0x1; + int dreg = (m_opcode >> 23) & 0xf; + int i = (m_opcode >> 41) & 0x7; + int mod = SIGN_EXTEND6((m_opcode >> 27) & 0x3f); + int compute = m_opcode & 0x7fffff; + + /* due to parallelity issues, source REG must be saved */ + /* because the compute operation may change it */ + UINT32 parallel_dreg = REG(dreg); + + if (IF_CONDITION_CODE(cond)) + { + if (compute != 0) + { + COMPUTE(compute); + } + + if (u) /* post-modify with update */ + { + pm_write32(PM_REG_I(i), parallel_dreg); + PM_REG_I(i) += mod; + UPDATE_CIRCULAR_BUFFER_PM(i); + } + else /* pre-modify, no update */ + { + pm_write32(PM_REG_I(i) + mod, parallel_dreg); + } + } +} + +/*****************************************************************************/ +/* | 0111xxxxx | */ + +/* compute / ureg <-> ureg */ +void adsp21062_device::sharcop_compute_ureg_to_ureg() +{ + int src_ureg = (m_opcode >> 36) & 0xff; + int dst_ureg = (m_opcode >> 23) & 0xff; + int cond = (m_opcode >> 31) & 0x1f; + int compute = m_opcode & 0x7fffff; + + if (IF_CONDITION_CODE(cond)) + { + /* due to parallelity issues, source UREG must be saved */ + /* because the compute operation may change it */ + UINT32 parallel_ureg = GET_UREG(src_ureg); + + if (compute != 0) + { + COMPUTE(compute); + } + + SET_UREG(dst_ureg, parallel_ureg); + } +} + +/*****************************************************************************/ +/* | 1000xxxxx | */ + +/* immediate shift / dreg <-> DM|PM */ +void adsp21062_device::sharcop_imm_shift_dreg_dmpm() +{ + int i = (m_opcode >> 41) & 0x7; + int m = (m_opcode >> 38) & 0x7; + int g = (m_opcode >> 32) & 0x1; + int d = (m_opcode >> 31) & 0x1; + int dreg = (m_opcode >> 23) & 0xf; + int cond = (m_opcode >> 33) & 0x1f; + int data = ((m_opcode >> 8) & 0xff) | ((m_opcode >> 19) & 0xf00); + int shiftop = (m_opcode >> 16) & 0x3f; + int rn = (m_opcode >> 4) & 0xf; + int rx = (m_opcode & 0xf); + + if (IF_CONDITION_CODE(cond)) + { + /* due to parallelity issues, source REG must be saved */ + /* because the shift operation may change it */ + UINT32 parallel_dreg = REG(dreg); + + SHIFT_OPERATION_IMM(shiftop, data, rn, rx); + + if (g) /* PM */ + { + if (d) /* dreg -> PM */ + { + pm_write32(PM_REG_I(i), parallel_dreg); + PM_REG_I(i) += PM_REG_M(m); + UPDATE_CIRCULAR_BUFFER_PM(i); + } + else /* PM <- dreg */ + { + REG(dreg) = pm_read32(PM_REG_I(i)); + PM_REG_I(i) += PM_REG_M(m); + UPDATE_CIRCULAR_BUFFER_PM(i); + } + } + else /* DM */ + { + if (d) /* dreg -> DM */ + { + dm_write32(DM_REG_I(i), parallel_dreg); + DM_REG_I(i) += DM_REG_M(m); + UPDATE_CIRCULAR_BUFFER_DM(i); + } + else /* DM <- dreg */ + { + REG(dreg) = dm_read32(DM_REG_I(i)); + DM_REG_I(i) += DM_REG_M(m); + UPDATE_CIRCULAR_BUFFER_DM(i); + } + } + } +} + +/*****************************************************************************/ +/* | 00000010x | */ + +/* immediate shift */ +void adsp21062_device::sharcop_imm_shift() +{ + int cond = (m_opcode >> 33) & 0x1f; + int data = ((m_opcode >> 8) & 0xff) | ((m_opcode >> 19) & 0xf00); + int shiftop = (m_opcode >> 16) & 0x3f; + int rn = (m_opcode >> 4) & 0xf; + int rx = (m_opcode & 0xf); + + if (IF_CONDITION_CODE(cond)) + { + SHIFT_OPERATION_IMM(shiftop, data, rn, rx); + } +} + +/*****************************************************************************/ +/* | 00000100x | */ + +/* compute / modify */ +void adsp21062_device::sharcop_compute_modify() +{ + int cond = (m_opcode >> 33) & 0x1f; + int compute = m_opcode & 0x7fffff; + int g = (m_opcode >> 38) & 0x1; + int m = (m_opcode >> 27) & 0x7; + int i = (m_opcode >> 30) & 0x7; + + if (IF_CONDITION_CODE(cond)) + { + if (compute != 0) + { + COMPUTE(compute); + } + + if (g) /* Modify PM */ + { + PM_REG_I(i) += PM_REG_M(m); + UPDATE_CIRCULAR_BUFFER_PM(i); + } + else /* Modify DM */ + { + DM_REG_I(i) += DM_REG_M(m); + UPDATE_CIRCULAR_BUFFER_DM(i); + } + } +} + +/*****************************************************************************/ +/* | 00000110x | */ + +/* direct call to absolute address */ +void adsp21062_device::sharcop_direct_call() +{ + int j = (m_opcode >> 26) & 0x1; + int cond = (m_opcode >> 33) & 0x1f; + UINT32 address = m_opcode & 0xffffff; + + if (IF_CONDITION_CODE(cond)) + { + if (j) + { + //PUSH_PC(m_pc+3); /* 1 instruction + 2 delayed instructions */ + PUSH_PC(m_nfaddr); /* 1 instruction + 2 delayed instructions */ + CHANGE_PC_DELAYED(address); + } + else + { + //PUSH_PC(m_pc+1); + PUSH_PC(m_daddr); + CHANGE_PC(address); + } + } +} + +/* direct jump to absolute address */ +void adsp21062_device::sharcop_direct_jump() +{ + int la = (m_opcode >> 38) & 0x1; + int ci = (m_opcode >> 24) & 0x1; + int j = (m_opcode >> 26) & 0x1; + int cond = (m_opcode >> 33) & 0x1f; + UINT32 address = m_opcode & 0xffffff; + + if(IF_CONDITION_CODE(cond)) + { + // Clear Interrupt + if (ci) + { + // TODO: anything else? + if (m_status_stkp > 0) + { + POP_STATUS_STACK(); + } + + m_interrupt_active = 0; + m_irptl &= ~(1 << m_active_irq_num); + } + + if (la) + { + POP_PC(); + POP_LOOP(); + } + + if (j) + { + CHANGE_PC_DELAYED(address); + } + else + { + CHANGE_PC(address); + } + } +} + +/*****************************************************************************/ +/* | 00000111x | */ + +/* direct call to relative address */ +void adsp21062_device::sharcop_relative_call() +{ + int j = (m_opcode >> 26) & 0x1; + int cond = (m_opcode >> 33) & 0x1f; + UINT32 address = m_opcode & 0xffffff; + + if (IF_CONDITION_CODE(cond)) + { + if (j) + { + PUSH_PC(m_pc+3); /* 1 instruction + 2 delayed instructions */ + CHANGE_PC_DELAYED(m_pc + SIGN_EXTEND24(address)); + } + else + { + PUSH_PC(m_pc+1); + CHANGE_PC(m_pc + SIGN_EXTEND24(address)); + } + } +} + +/* direct jump to relative address */ +void adsp21062_device::sharcop_relative_jump() +{ + int la = (m_opcode >> 38) & 0x1; + int ci = (m_opcode >> 24) & 0x1; + int j = (m_opcode >> 26) & 0x1; + int cond = (m_opcode >> 33) & 0x1f; + UINT32 address = m_opcode & 0xffffff; + + if (IF_CONDITION_CODE(cond)) + { + // Clear Interrupt + if (ci) + { + // TODO: anything else? + if (m_status_stkp > 0) + { + POP_STATUS_STACK(); + } + + m_interrupt_active = 0; + m_irptl &= ~(1 << m_active_irq_num); + } + + if (la) + { + POP_PC(); + POP_LOOP(); + } + + if (j) + { + CHANGE_PC_DELAYED(m_pc + SIGN_EXTEND24(address)); + } + else + { + CHANGE_PC(m_pc + SIGN_EXTEND24(address)); + } + } +} + +/*****************************************************************************/ +/* | 00001000x | */ + +/* indirect jump */ +void adsp21062_device::sharcop_indirect_jump() +{ + int la = (m_opcode >> 38) & 0x1; + int ci = (m_opcode >> 24) & 0x1; + int j = (m_opcode >> 26) & 0x1; + int e = (m_opcode >> 25) & 0x1; + int pmi = (m_opcode >> 30) & 0x7; + int pmm = (m_opcode >> 27) & 0x7; + int cond = (m_opcode >> 33) & 0x1f; + int compute = m_opcode & 0x7fffff; + + // Clear Interrupt + if (ci) + { + // TODO: anything else? + if (m_status_stkp > 0) + { + POP_STATUS_STACK(); + } + + m_interrupt_active = 0; + m_irptl &= ~(1 << m_active_irq_num); + } + + if (e) /* IF...ELSE */ + { + if (IF_CONDITION_CODE(cond)) + { + if (la) + { + POP_PC(); + POP_LOOP(); + } + + if(j) + { + CHANGE_PC_DELAYED(PM_REG_I(pmi) + PM_REG_M(pmm)); + } + else + { + CHANGE_PC(PM_REG_I(pmi) + PM_REG_M(pmm)); + } + } + else + { + if (compute) + { + COMPUTE(compute); + } + } + } + else /* IF */ + { + if (IF_CONDITION_CODE(cond)) + { + if (compute) + { + COMPUTE(compute); + } + + if (la) + { + POP_PC(); + POP_LOOP(); + } + + if(j) + { + CHANGE_PC_DELAYED(PM_REG_I(pmi) + PM_REG_M(pmm)); + } + else + { + CHANGE_PC(PM_REG_I(pmi) + PM_REG_M(pmm)); + } + } + } +} + +/* indirect call */ +void adsp21062_device::sharcop_indirect_call() +{ + int j = (m_opcode >> 26) & 0x1; + int e = (m_opcode >> 25) & 0x1; + int pmi = (m_opcode >> 30) & 0x7; + int pmm = (m_opcode >> 27) & 0x7; + int cond = (m_opcode >> 33) & 0x1f; + int compute = m_opcode & 0x7fffff; + + if (e) /* IF...ELSE */ + { + if (IF_CONDITION_CODE(cond)) + { + if (j) + { + //PUSH_PC(m_pc+3); /* 1 instruction + 2 delayed instructions */ + PUSH_PC(m_nfaddr); /* 1 instruction + 2 delayed instructions */ + CHANGE_PC_DELAYED(PM_REG_I(pmi) + PM_REG_M(pmm)); + } + else + { + //PUSH_PC(m_pc+1); + PUSH_PC(m_daddr); + CHANGE_PC(PM_REG_I(pmi) + PM_REG_M(pmm)); + } + } + else + { + if (compute) + { + COMPUTE(compute); + } + } + } + else /* IF */ + { + if (IF_CONDITION_CODE(cond)) + { + if (compute) + { + COMPUTE(compute); + } + + if (j) + { + //PUSH_PC(m_pc+3); /* 1 instruction + 2 delayed instructions */ + PUSH_PC(m_nfaddr); /* 1 instruction + 2 delayed instructions */ + CHANGE_PC_DELAYED(PM_REG_I(pmi) + PM_REG_M(pmm)); + } + else + { + //PUSH_PC(m_pc+1); + PUSH_PC(m_daddr); + CHANGE_PC(PM_REG_I(pmi) + PM_REG_M(pmm)); + } + } + } +} + +/*****************************************************************************/ +/* | 00001001x | */ + +/* indirect jump to relative address */ +void adsp21062_device::sharcop_relative_jump_compute() +{ + int la = (m_opcode >> 38) & 0x1; + int ci = (m_opcode >> 24) & 0x1; + int j = (m_opcode >> 26) & 0x1; + int e = (m_opcode >> 25) & 0x1; + int cond = (m_opcode >> 33) & 0x1f; + int compute = m_opcode & 0x7fffff; + + // Clear Interrupt + if (ci) + { + // TODO: anything else? + if (m_status_stkp > 0) + { + POP_STATUS_STACK(); + } + + m_interrupt_active = 0; + m_irptl &= ~(1 << m_active_irq_num); + } + + if (e) /* IF...ELSE */ + { + if (IF_CONDITION_CODE(cond)) + { + if (la) + { + POP_PC(); + POP_LOOP(); + } + + if (j) + { + CHANGE_PC_DELAYED(m_pc + SIGN_EXTEND6((m_opcode >> 27) & 0x3f)); + } + else + { + CHANGE_PC(m_pc + SIGN_EXTEND6((m_opcode >> 27) & 0x3f)); + } + } + else + { + if (compute) + { + COMPUTE(compute); + } + } + } + else /* IF */ + { + if (IF_CONDITION_CODE(cond)) + { + if (compute) + { + COMPUTE(compute); + } + + if (la) + { + POP_PC(); + POP_LOOP(); + } + + if (j) + { + CHANGE_PC_DELAYED(m_pc + SIGN_EXTEND6((m_opcode >> 27) & 0x3f)); + } + else + { + CHANGE_PC(m_pc + SIGN_EXTEND6((m_opcode >> 27) & 0x3f)); + } + } + } +} + +/* indirect call to relative address */ +void adsp21062_device::sharcop_relative_call_compute() +{ + int j = (m_opcode >> 26) & 0x1; + int e = (m_opcode >> 25) & 0x1; + int cond = (m_opcode >> 33) & 0x1f; + int compute = m_opcode & 0x7fffff; + + if (e) /* IF...ELSE */ + { + if (IF_CONDITION_CODE(cond)) + { + if (j) + { + //PUSH_PC(m_pc+3); /* 1 instruction + 2 delayed instructions */ + PUSH_PC(m_nfaddr); /* 1 instruction + 2 delayed instructions */ + CHANGE_PC_DELAYED(m_pc + SIGN_EXTEND6((m_opcode >> 27) & 0x3f)); + } + else + { + //PUSH_PC(m_pc+1); + PUSH_PC(m_daddr); + CHANGE_PC(m_pc + SIGN_EXTEND6((m_opcode >> 27) & 0x3f)); + } + } + else + { + if (compute) + { + COMPUTE(compute); + } + } + } + else /* IF */ + { + if (IF_CONDITION_CODE(cond)) + { + if (compute) + { + COMPUTE(compute); + } + + if (j) + { + //PUSH_PC(m_pc+3); /* 1 instruction + 2 delayed instructions */ + PUSH_PC(m_nfaddr); /* 1 instruction + 2 delayed instructions */ + CHANGE_PC_DELAYED(m_pc + SIGN_EXTEND6((m_opcode >> 27) & 0x3f)); + } + else + { + //PUSH_PC(m_pc+1); + PUSH_PC(m_daddr); + CHANGE_PC(m_pc + SIGN_EXTEND6((m_opcode >> 27) & 0x3f)); + } + } + } +} + +/*****************************************************************************/ +/* | 110xxxxxx | */ + +/* indirect jump / compute / dreg <-> DM */ +void adsp21062_device::sharcop_indirect_jump_compute_dreg_dm() +{ + int d = (m_opcode >> 44) & 0x1; + int dmi = (m_opcode >> 41) & 0x7; + int dmm = (m_opcode >> 38) & 0x7; + int pmi = (m_opcode >> 30) & 0x7; + int pmm = (m_opcode >> 27) & 0x7; + int cond = (m_opcode >> 33) & 0x1f; + int dreg = (m_opcode >> 23) & 0xf; + + if (IF_CONDITION_CODE(cond)) + { + CHANGE_PC(PM_REG_I(pmi) + PM_REG_M(pmm)); + } + else + { + UINT32 compute = m_opcode & 0x7fffff; + /* due to parallelity issues, source REG must be saved */ + /* because the compute operation may change it */ + UINT32 parallel_dreg = REG(dreg); + + if (compute) + { + COMPUTE(compute); + } + + if (d) /* dreg -> DM */ + { + dm_write32(DM_REG_I(dmi), parallel_dreg); + DM_REG_I(dmi) += DM_REG_M(dmm); + UPDATE_CIRCULAR_BUFFER_DM(dmi); + } + else /* DM <- dreg */ + { + REG(dreg) = dm_read32(DM_REG_I(dmi)); + DM_REG_I(dmi) += DM_REG_M(dmm); + UPDATE_CIRCULAR_BUFFER_DM(dmi); + } + } +} + +/*****************************************************************************/ +/* | 111xxxxxx | */ + +/* relative jump / compute / dreg <-> DM */ +void adsp21062_device::sharcop_relative_jump_compute_dreg_dm() +{ + int d = (m_opcode >> 44) & 0x1; + int dmi = (m_opcode >> 41) & 0x7; + int dmm = (m_opcode >> 38) & 0x7; + int cond = (m_opcode >> 33) & 0x1f; + int dreg = (m_opcode >> 23) & 0xf; + + if (IF_CONDITION_CODE(cond)) + { + CHANGE_PC(m_pc + SIGN_EXTEND6((m_opcode >> 27) & 0x3f)); + } + else + { + UINT32 compute = m_opcode & 0x7fffff; + /* due to parallelity issues, source REG must be saved */ + /* because the compute operation may change it */ + UINT32 parallel_dreg = REG(dreg); + + if (compute) + { + COMPUTE(compute); + } + + if (d) /* dreg -> DM */ + { + dm_write32(DM_REG_I(dmi), parallel_dreg); + DM_REG_I(dmi) += DM_REG_M(dmm); + UPDATE_CIRCULAR_BUFFER_DM(dmi); + } + else /* DM <- dreg */ + { + REG(dreg) = dm_read32(DM_REG_I(dmi)); + DM_REG_I(dmi) += DM_REG_M(dmm); + UPDATE_CIRCULAR_BUFFER_DM(dmi); + } + } +} + +/*****************************************************************************/ +/* | 00001010x | */ + +/* return from subroutine / compute */ +void adsp21062_device::sharcop_rts() +{ + int cond = (m_opcode >> 33) & 0x1f; + int j = (m_opcode >> 26) & 0x1; + int e = (m_opcode >> 25) & 0x1; + //int lr = (m_opcode >> 24) & 0x1; + int compute = m_opcode & 0x7fffff; + + //if(lr) + // fatalerror("SHARC: rts: loop reentry not implemented!\n"); + + if (e) /* IF...ELSE */ + { + if(IF_CONDITION_CODE(cond)) + { + if (j) + { + CHANGE_PC_DELAYED(POP_PC()); + } + else + { + CHANGE_PC(POP_PC()); + } + } + else + { + if (compute) + { + COMPUTE(compute); + } + } + } + else /* IF */ + { + if (IF_CONDITION_CODE(cond)) + { + if (compute) + { + COMPUTE(compute); + } + + if (j) + { + CHANGE_PC_DELAYED(POP_PC()); + } + else + { + CHANGE_PC(POP_PC()); + } + } + } +} + +/*****************************************************************************/ +/* | 00001011x | */ + +/* return from interrupt / compute */ +void adsp21062_device::sharcop_rti() +{ + int cond = (m_opcode >> 33) & 0x1f; + int j = (m_opcode >> 26) & 0x1; + int e = (m_opcode >> 25) & 0x1; + int compute = m_opcode & 0x7fffff; + + m_irptl &= ~(1 << m_active_irq_num); + + if(e) /* IF...ELSE */ + { + if (IF_CONDITION_CODE(cond)) + { + if (j) + { + CHANGE_PC_DELAYED(POP_PC()); + } + else + { + CHANGE_PC(POP_PC()); + } + } + else + { + if (compute) + { + COMPUTE(compute); + } + } + } + else /* IF */ + { + if (IF_CONDITION_CODE(cond)) + { + if (compute) + { + COMPUTE(compute); + } + + if (j) + { + CHANGE_PC_DELAYED(POP_PC()); + } + else + { + CHANGE_PC(POP_PC()); + } + } + } + + if (m_status_stkp > 0) + { + POP_STATUS_STACK(); + } + + m_interrupt_active = 0; + check_interrupts(); +} + +/*****************************************************************************/ +/* | 00001100x | */ + +/* do until counter expired, LCNTR immediate */ +void adsp21062_device::sharcop_do_until_counter_imm() +{ + UINT16 data = (UINT16)(m_opcode >> 24); + int offset = SIGN_EXTEND24(m_opcode & 0xffffff); + UINT32 address = m_pc + offset; + int type; + int cond = 0xf; /* until LCE (loop counter expired */ + int distance = abs(offset); + + if (distance == 1) + { + type = 1; + } + else if (distance == 2) + { + type = 2; + } + else + { + type = 3; + } + + m_lcntr = data; + if (m_lcntr > 0) + { + PUSH_PC(m_pc+1); + PUSH_LOOP(address, cond, type, m_lcntr); + } +} + +/*****************************************************************************/ +/* | 00001101x | */ + +/* do until counter expired, LCNTR from UREG */ +void adsp21062_device::sharcop_do_until_counter_ureg() +{ + int ureg = (m_opcode >> 32) & 0xff; + int offset = SIGN_EXTEND24(m_opcode & 0xffffff); + UINT32 address = m_pc + offset; + int type; + int cond = 0xf; /* until LCE (loop counter expired */ + int distance = abs(offset); + + if (distance == 1) + { + type = 1; + } + else if (distance == 2) + { + type = 2; + } + else + { + type = 3; + } + + m_lcntr = GET_UREG(ureg); + if (m_lcntr > 0) + { + PUSH_PC(m_pc+1); + PUSH_LOOP(address, cond, type, m_lcntr); + } +} + +/*****************************************************************************/ +/* | 00001110x | */ + +/* do until */ +void adsp21062_device::sharcop_do_until() +{ + int cond = (m_opcode >> 33) & 0x1f; + int offset = SIGN_EXTEND24(m_opcode & 0xffffff); + UINT32 address = (m_pc + offset); + + PUSH_PC(m_pc+1); + PUSH_LOOP(address, cond, 0, 0); +} + +/*****************************************************************************/ +/* | 000100 | G | D | */ + +/* ureg <- DM (direct addressing) */ +void adsp21062_device::sharcop_dm_to_ureg_direct() +{ + int ureg = (m_opcode >> 32) & 0xff; + UINT32 address = (UINT32)(m_opcode); + + SET_UREG(ureg, dm_read32(address)); +} + +/* ureg -> DM (direct addressing) */ +void adsp21062_device::sharcop_ureg_to_dm_direct() +{ + int ureg = (m_opcode >> 32) & 0xff; + UINT32 address = (UINT32)(m_opcode); + + dm_write32(address, GET_UREG(ureg)); +} + +/* ureg <- PM (direct addressing) */ +void adsp21062_device::sharcop_pm_to_ureg_direct() +{ + int ureg = (m_opcode >> 32) & 0xff; + UINT32 address = (UINT32)(m_opcode); + + if (ureg == 0xdb) // PX is 48-bit + { + m_px = pm_read48(address); + } + else + { + SET_UREG(ureg, pm_read32(address)); + } +} + +/* ureg -> PM (direct addressing) */ +void adsp21062_device::sharcop_ureg_to_pm_direct() +{ + int ureg = (m_opcode >> 32) & 0xff; + UINT32 address = (UINT32)(m_opcode); + + if (ureg == 0xdb) // PX is 48-bit + { + pm_write48(address, m_px); + } + else + { + pm_write32(address, GET_UREG(ureg)); + } +} + +/*****************************************************************************/ +/* | 101 | G | III | D | */ + +/* ureg <- DM (indirect addressing) */ +void adsp21062_device::sharcop_dm_to_ureg_indirect() +{ + int ureg = (m_opcode >> 32) & 0xff; + UINT32 offset = (UINT32)m_opcode; + int i = (m_opcode >> 41) & 0x7; + + SET_UREG(ureg, dm_read32(DM_REG_I(i) + offset)); +} + +/* ureg -> DM (indirect addressing) */ +void adsp21062_device::sharcop_ureg_to_dm_indirect() +{ + int ureg = (m_opcode >> 32) & 0xff; + UINT32 offset = (UINT32)m_opcode; + int i = (m_opcode >> 41) & 0x7; + + dm_write32(DM_REG_I(i) + offset, GET_UREG(ureg)); +} + +/* ureg <- PM (indirect addressing) */ +void adsp21062_device::sharcop_pm_to_ureg_indirect() +{ + int ureg = (m_opcode >> 32) & 0xff; + UINT32 offset = m_opcode & 0xffffff; + int i = (m_opcode >> 41) & 0x7; + + if (ureg == 0xdb) /* PX is 48-bit */ + { + m_px = pm_read48(PM_REG_I(i) + offset); + } + else + { + SET_UREG(ureg, pm_read32(PM_REG_I(i) + offset)); + } +} + +/* ureg -> PM (indirect addressing) */ +void adsp21062_device::sharcop_ureg_to_pm_indirect() +{ + int ureg = (m_opcode >> 32) & 0xff; + UINT32 offset = (UINT32)m_opcode; + int i = (m_opcode >> 41) & 0x7; + + if (ureg == 0xdb) /* PX is 48-bit */ + { + pm_write48(PM_REG_I(i) + offset, m_px); + } + else + { + pm_write32(PM_REG_I(i) + offset, GET_UREG(ureg)); + } +} + +/*****************************************************************************/ +/* | 1001xxxxx | */ + +/* immediate data -> DM|PM */ +void adsp21062_device::sharcop_imm_to_dmpm() +{ + int i = (m_opcode >> 41) & 0x7; + int m = (m_opcode >> 38) & 0x7; + int g = (m_opcode >> 37) & 0x1; + UINT32 data = (UINT32)m_opcode; + + if (g) + { + /* program memory (PM) */ + pm_write32(PM_REG_I(i), data); + PM_REG_I(i) += PM_REG_M(m); + UPDATE_CIRCULAR_BUFFER_PM(i); + } + else + { + /* data memory (DM) */ + dm_write32(DM_REG_I(i), data); + DM_REG_I(i) += DM_REG_M(m); + UPDATE_CIRCULAR_BUFFER_DM(i); + } +} + +/*****************************************************************************/ +/* | 00001111x | */ + +/* immediate data -> ureg */ +void adsp21062_device::sharcop_imm_to_ureg() +{ + int ureg = (m_opcode >> 32) & 0xff; + UINT32 data = (UINT32)m_opcode; + + SET_UREG(ureg, data); +} + +/*****************************************************************************/ +/* | 00010100x | */ + +/* system register bit manipulation */ +void adsp21062_device::sharcop_sysreg_bitop() +{ + int bop = (m_opcode >> 37) & 0x7; + int sreg = (m_opcode >> 32) & 0xf; + UINT32 data = (UINT32)m_opcode; + + UINT32 src = GET_UREG(0x70 | sreg); + + switch(bop) + { + case 0: /* SET */ + { + src |= data; + break; + } + case 1: /* CLEAR */ + { + src &= ~data; + break; + } + case 2: /* TOGGLE */ + { + src ^= data; + break; + } + case 4: /* TEST */ + { + if ((src & data) == data) + { + m_astat |= BTF; + } + else + { + m_astat &= ~BTF; + } + break; + } + case 5: /* XOR */ + { + if (src == data) + { + m_astat |= BTF; + } + else + { + m_astat &= ~BTF; + } + break; + } + default: + fatalerror("SHARC: sysreg_bitop: invalid bitop %d\n", bop); + break; + } + + SET_UREG(0x70 | sreg, src); +} + +/*****************************************************************************/ +/* | 000101100 | */ + +/* I register modify */ +void adsp21062_device::sharcop_modify() +{ + int g = (m_opcode >> 38) & 0x1; + int i = (m_opcode >> 32) & 0x7; + INT32 data = (m_opcode); + + if (g) // PM + { + PM_REG_I(i) += data; + UPDATE_CIRCULAR_BUFFER_PM(i); + } + else // DM + { + DM_REG_I(i) += data; + UPDATE_CIRCULAR_BUFFER_DM(i); + } +} + +/*****************************************************************************/ +/* | 000101101 | */ + +/* I register bit-reverse */ +void adsp21062_device::sharcop_bit_reverse() +{ + fatalerror("SHARC: sharcop_bit_reverse unimplemented\n"); +} + +/*****************************************************************************/ +/* | 00010111x | */ + +/* push/pop stacks / flush cache */ +void adsp21062_device::sharcop_push_pop_stacks() +{ + if (m_opcode & U64(0x008000000000)) + { + fatalerror("sharcop_push_pop_stacks: push loop not implemented\n"); + } + if (m_opcode & U64(0x004000000000)) + { + fatalerror("sharcop_push_pop_stacks: pop loop not implemented\n"); + } + if (m_opcode & U64(0x002000000000)) + { + //fatalerror("sharcop_push_pop_stacks: push sts not implemented\n"); + PUSH_STATUS_STACK(); + } + if (m_opcode & U64(0x001000000000)) + { + //fatalerror("sharcop_push_pop_stacks: pop sts not implemented\n"); + POP_STATUS_STACK(); + } + if (m_opcode & U64(0x000800000000)) + { + PUSH_PC(m_pcstk); + } + if (m_opcode & U64(0x000400000000)) + { + POP_PC(); + } +} + +/*****************************************************************************/ +/* | 000000000 | */ + +void adsp21062_device::sharcop_nop() +{ +} + +/*****************************************************************************/ +/* | 000000001 | */ + +void adsp21062_device::sharcop_idle() +{ + //CHANGE_PC(m_pc); + + m_daddr = m_pc; + m_faddr = m_pc+1; + m_nfaddr = m_pc+2; + + m_idle = 1; +} + +/*****************************************************************************/ + +void adsp21062_device::sharcop_unimplemented() +{ + extern CPU_DISASSEMBLE(sharc); + char dasm[1000]; + CPU_DISASSEMBLE_NAME(sharc)(NULL, dasm, m_pc, NULL, NULL, 0); + osd_printf_debug("SHARC: %08X: %s\n", m_pc, dasm); + fatalerror("SHARC: Unimplemented opcode %04X%08X at %08X\n", (UINT16)(m_opcode >> 32), (UINT32)(m_opcode), m_pc); +} diff --git a/src/devices/cpu/sm510/sm510.c b/src/devices/cpu/sm510/sm510.c new file mode 100644 index 00000000000..ef4f704590b --- /dev/null +++ b/src/devices/cpu/sm510/sm510.c @@ -0,0 +1,376 @@ +// license:BSD-3-Clause +// copyright-holders:hap +/* + + Sharp SM510 MCU family - known chips: + - SM510: 2.7Kx8 ROM, 128x4 RAM(32x4 for LCD) + - SM511: 4Kx8 ROM, 128x4 RAM(32x4 for LCD), melody controller + - SM512: 4Kx8 ROM, 128x4 RAM(48x4 for LCD), melody controller + + Other chips that may be in the same family, investigate more when one of + them needs to get emulated: SM500, SM530/31, SM4A, SM3903, .. + + References: + - 1990 Sharp Microcomputers Data Book + - 1996 Sharp Microcomputer Databook + + TODO: + - proper support for LFSR program counter in debugger + - callback for lcd screen as MAME bitmap (when needed) + - LCD bs pin blink mode via Y register (0.5s off, 0.5s on) + - LB/SBM is correct? + - SM511 unknown opcodes + +*/ + +#include "sm510.h" +#include "debugger.h" + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +enum +{ + SM510_PC=1, SM510_ACC, SM510_BL, SM510_BM, + SM510_C, SM510_W +}; + +void sm510_base_device::device_start() +{ + m_program = &space(AS_PROGRAM); + m_data = &space(AS_DATA); + m_prgmask = (1 << m_prgwidth) - 1; + m_datamask = (1 << m_datawidth) - 1; + + // resolve callbacks + m_read_k.resolve_safe(0); + m_read_ba.resolve_safe(1); + m_read_b.resolve_safe(1); + m_write_s.resolve_safe(); + m_write_r.resolve_safe(); + + m_write_sega.resolve_safe(); + m_write_segb.resolve_safe(); + m_write_segbs.resolve_safe(); + m_write_segc.resolve_safe(); + + // zerofill + memset(m_stack, 0, sizeof(m_stack)); + m_pc = 0; + m_prev_pc = 0; + m_op = 0; + m_prev_op = 0; + m_param = 0; + m_acc = 0; + m_bl = 0; + m_bm = 0; + m_c = 0; + m_skip = false; + m_w = 0; + m_r = 0; + m_div = 0; + m_1s = false; + m_k_active = false; + m_l = 0; + m_x = 0; + m_y = 0; + m_bp = false; + m_bc = false; + m_halt = false; + m_melody_rd = 0; + m_melody_step_count = 0; + m_melody_duty_count = 0; + m_melody_duty_index = 0; + m_melody_address = 0; + + // register for savestates + save_item(NAME(m_stack)); + save_item(NAME(m_pc)); + save_item(NAME(m_prev_pc)); + save_item(NAME(m_op)); + save_item(NAME(m_prev_op)); + save_item(NAME(m_param)); + save_item(NAME(m_acc)); + save_item(NAME(m_bl)); + save_item(NAME(m_bm)); + save_item(NAME(m_c)); + save_item(NAME(m_skip)); + save_item(NAME(m_w)); + save_item(NAME(m_r)); + save_item(NAME(m_div)); + save_item(NAME(m_1s)); + save_item(NAME(m_k_active)); + save_item(NAME(m_l)); + save_item(NAME(m_x)); + save_item(NAME(m_y)); + save_item(NAME(m_bp)); + save_item(NAME(m_bc)); + save_item(NAME(m_halt)); + save_item(NAME(m_melody_rd)); + save_item(NAME(m_melody_step_count)); + save_item(NAME(m_melody_duty_count)); + save_item(NAME(m_melody_duty_index)); + save_item(NAME(m_melody_address)); + + // register state for debugger + state_add(SM510_PC, "PC", m_pc).formatstr("%04X"); + state_add(SM510_ACC, "ACC", m_acc).formatstr("%01X"); + state_add(SM510_BL, "BL", m_bl).formatstr("%01X"); + state_add(SM510_BM, "BM", m_bm).formatstr("%01X"); + state_add(SM510_C, "C", m_c).formatstr("%01X"); + state_add(SM510_W, "W", m_w).formatstr("%02X"); + + state_add(STATE_GENPC, "curpc", m_pc).formatstr("%04X").noshow(); + state_add(STATE_GENFLAGS, "GENFLAGS", m_c).formatstr("%1s").noshow(); + + m_icountptr = &m_icount; + + // init peripherals + init_divider(); + init_lcd_driver(); + init_melody(); +} + + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void sm510_base_device::device_reset() +{ + m_skip = false; + m_halt = false; + m_op = m_prev_op = 0; + do_branch(3, 7, 0); + m_prev_pc = m_pc; + + // lcd is on (Bp on, BC off, bs(y) off) + m_bp = true; + m_bc = false; + m_y = 0; + + m_r = 0; + m_write_r(0, 0, 0xff); + m_melody_rd &= ~1; +} + + + +//------------------------------------------------- +// lcd driver +//------------------------------------------------- + +inline UINT16 sm510_base_device::get_lcd_row(int column, UINT8* ram) +{ + // output 0 if lcd blackpate/bleeder is off, or in case row doesn't exist + if (ram == NULL || m_bc || !m_bp) + return 0; + + UINT16 rowdata = 0; + for (int i = 0; i < 0x10; i++) + rowdata |= (ram[i] >> column & 1) << i; + + return rowdata; +} + +TIMER_CALLBACK_MEMBER(sm510_base_device::lcd_timer_cb) +{ + // 4 columns + for (int h = 0; h < 4; h++) + { + // 16 segments per row from upper part of RAM + m_write_sega(h | SM510_PORT_SEGA, get_lcd_row(h, m_lcd_ram_a), 0xffff); + m_write_segb(h | SM510_PORT_SEGB, get_lcd_row(h, m_lcd_ram_b), 0xffff); + m_write_segc(h | SM510_PORT_SEGC, get_lcd_row(h, m_lcd_ram_c), 0xffff); + + // bs output from L/X and Y regs + UINT8 bs = (m_l >> h & 1) | ((m_x*2) >> h & 2); + m_write_segbs(h | SM510_PORT_SEGBS, (m_bc || !m_bp) ? 0 : bs, 0xffff); + } + + // schedule next timeout + m_lcd_timer->adjust(attotime::from_ticks(0x200, unscaled_clock())); +} + +void sm510_base_device::init_lcd_driver() +{ + // note: in reality, this timer runs at high frequency off the main divider, strobing one segment at a time + m_lcd_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(sm510_base_device::lcd_timer_cb), this)); + m_lcd_timer->adjust(attotime::from_ticks(0x200, unscaled_clock())); // 64hz default +} + + + +//------------------------------------------------- +// melody controller +//------------------------------------------------- + +void sm510_base_device::clock_melody() +{ + if (!m_melody_rom) + return; + + // tone cycle table (SM511/SM512 datasheet fig.5) + // cmd 0 = cmd, 1 = stop, > 13 = illegal(unknown) + static const UINT8 lut_tone_cycles[4*16] = + { + 0, 0, 7, 8, 8, 9, 9, 10,11,11,12,13,14,14, 7*2, 8*2, + 0, 0, 8, 8, 9, 9, 10,11,11,12,13,13,14,15, 8*2, 8*2, + 0, 0, 8, 8, 9, 9, 10,10,11,12,12,13,14,15, 8*2, 8*2, + 0, 0, 8, 9, 9, 10,10,11,11,12,13,14,14,15, 8*2, 9*2 + }; + + UINT8 cmd = m_melody_rom[m_melody_address] & 0x3f; + UINT8 out = 0; + + // clock duty cycle if tone is active + if ((cmd & 0xf) > 1) + { + out = m_melody_duty_index & m_melody_rd & 1; + m_melody_duty_count++; + int index = m_melody_duty_index << 4 | (cmd & 0xf); + int shift = ~cmd >> 4 & 1; // OCT + + if (m_melody_duty_count >= (lut_tone_cycles[index] << shift)) + { + m_melody_duty_count = 0; + m_melody_duty_index = (m_melody_duty_index + 1) & 3; + } + } + else if ((cmd & 0xf) == 1) + { + // rest tell signal + m_melody_rd |= 2; + } + + // clock time base on F8(d7) + if ((m_div & 0x7f) == 0) + { + UINT8 mask = (cmd & 0x20) ? 0x1f : 0x0f; + m_melody_step_count = (m_melody_step_count + 1) & mask; + + if (m_melody_step_count == 0) + m_melody_address++; + } + + // output to R pin + if (out != m_r) + { + m_write_r(0, out, 0xff); + m_r = out; + } +} + +void sm510_base_device::init_melody() +{ + if (!m_melody_rom) + return; + + // verify melody rom + for (int i = 0; i < 0x100; i++) + { + UINT8 data = m_melody_rom[i]; + if (data & 0xc0 || (data & 0x0f) > 13) + logerror("%s unknown melody ROM data $%02X at $%02X\n", tag(), data, i); + } +} + + + +//------------------------------------------------- +// interrupt/divider +//------------------------------------------------- + +bool sm510_base_device::wake_me_up() +{ + // in halt mode, wake up after 1S signal or K input + if (m_k_active || m_1s) + { + // note: official doc warns that Bl/Bm and the stack are undefined + // after waking up, but we leave it unchanged + m_halt = false; + do_branch(1, 0, 0); + + standard_irq_callback(0); + return true; + } + else + return false; +} + +void sm510_base_device::execute_set_input(int line, int state) +{ + if (line != SM510_INPUT_LINE_K) + return; + + // set K input lines active state + m_k_active = (state != 0); +} + +TIMER_CALLBACK_MEMBER(sm510_base_device::div_timer_cb) +{ + m_div = (m_div + 1) & 0x7fff; + + // 1S signal on overflow(falling edge of f1) + if (m_div == 0) + m_1s = true; + + clock_melody(); +} + +void sm510_base_device::init_divider() +{ + m_div_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(sm510_base_device::div_timer_cb), this)); + m_div_timer->adjust(attotime::from_ticks(1, unscaled_clock()), 0, attotime::from_ticks(1, unscaled_clock())); +} + + + +//------------------------------------------------- +// execute +//------------------------------------------------- + +void sm510_base_device::increment_pc() +{ + // PL(program counter low 6 bits) is a simple LFSR: newbit = (bit0==bit1) + // PU,PM(high bits) specify page, PL specifies steps within page + int feed = ((m_pc >> 1 ^ m_pc) & 1) ? 0 : 0x20; + m_pc = feed | (m_pc >> 1 & 0x1f) | (m_pc & ~0x3f); +} + +void sm510_base_device::execute_run() +{ + while (m_icount > 0) + { + m_icount--; + + if (m_halt && !wake_me_up()) + { + // got nothing to do + m_icount = 0; + return; + } + + // remember previous state + m_prev_op = m_op; + m_prev_pc = m_pc; + + // fetch next opcode + debugger_instruction_hook(this, m_pc); + m_op = m_program->read_byte(m_pc); + increment_pc(); + get_opcode_param(); + + // handle opcode if it's not skipped + if (m_skip) + { + m_skip = false; + m_op = 0; // fake nop + } + else + execute_one(); + } +} diff --git a/src/devices/cpu/sm510/sm510.h b/src/devices/cpu/sm510/sm510.h new file mode 100644 index 00000000000..8dd7446b884 --- /dev/null +++ b/src/devices/cpu/sm510/sm510.h @@ -0,0 +1,307 @@ +// license:BSD-3-Clause +// copyright-holders:hap +/* + + Sharp SM510 MCU family cores + +*/ + +#ifndef _SM510_H_ +#define _SM510_H_ + +#include "emu.h" + + +// I/O ports setup + +// 4-bit K input port (pull-down) +#define MCFG_SM510_READ_K_CB(_devcb) \ + sm510_base_device::set_read_k_callback(*device, DEVCB_##_devcb); +// when in halt state, any K input going High can wake up the CPU, +// driver is required to use execute_set_input(SM510_INPUT_LINE_K, state) +#define SM510_INPUT_LINE_K 0 + +// 1-bit BA input pin (pull-up) +#define MCFG_SM510_READ_BA_CB(_devcb) \ + sm510_base_device::set_read_ba_callback(*device, DEVCB_##_devcb); + +// 1-bit B(beta) input pin (pull-up) +#define MCFG_SM510_READ_B_CB(_devcb) \ + sm510_base_device::set_read_b_callback(*device, DEVCB_##_devcb); + +// 8-bit S strobe output port +#define MCFG_SM510_WRITE_S_CB(_devcb) \ + sm510_base_device::set_write_s_callback(*device, DEVCB_##_devcb); + +// 2-bit R melody output port +#define MCFG_SM510_WRITE_R_CB(_devcb) \ + sm510_base_device::set_write_r_callback(*device, DEVCB_##_devcb); + +// LCD segment outputs: H1-4 as offset(low), a/b/c 1-16 as data d0-d15 +#define MCFG_SM510_WRITE_SEGA_CB(_devcb) \ + sm510_base_device::set_write_sega_callback(*device, DEVCB_##_devcb); +#define MCFG_SM510_WRITE_SEGB_CB(_devcb) \ + sm510_base_device::set_write_segb_callback(*device, DEVCB_##_devcb); +#define MCFG_SM510_WRITE_SEGC_CB(_devcb) \ + sm510_base_device::set_write_segc_callback(*device, DEVCB_##_devcb); + +// LCD bs output: same as above, but only up to 2 bits used +#define MCFG_SM510_WRITE_SEGBS_CB(_devcb) \ + sm510_base_device::set_write_segbs_callback(*device, DEVCB_##_devcb); + +enum +{ + SM510_PORT_SEGA = 0x00, + SM510_PORT_SEGB = 0x04, + SM510_PORT_SEGBS = 0x08, + SM510_PORT_SEGC = 0x0c +}; + + +// pinout reference + +/* + +*/ + +class sm510_base_device : public cpu_device +{ +public: + // construction/destruction + sm510_base_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, int stack_levels, int prgwidth, address_map_constructor program, int datawidth, address_map_constructor data, const char *shortname, const char *source) + : cpu_device(mconfig, type, name, tag, owner, clock, shortname, source) + , m_program_config("program", ENDIANNESS_LITTLE, 8, prgwidth, 0, program) + , m_data_config("data", ENDIANNESS_LITTLE, 8, datawidth, 0, data) + , m_prgwidth(prgwidth) + , m_datawidth(datawidth) + , m_stack_levels(stack_levels) + , m_lcd_ram_a(*this, "lcd_ram_a"), m_lcd_ram_b(*this, "lcd_ram_b"), m_lcd_ram_c(*this, "lcd_ram_c") + , m_write_sega(*this), m_write_segb(*this), m_write_segc(*this), m_write_segbs(*this) + , m_melody_rom(*this, "music") + , m_read_k(*this) + , m_read_ba(*this), m_read_b(*this) + , m_write_s(*this) + , m_write_r(*this) + { } + + // static configuration helpers + template static devcb_base &set_read_k_callback(device_t &device, _Object object) { return downcast(device).m_read_k.set_callback(object); } + template static devcb_base &set_read_ba_callback(device_t &device, _Object object) { return downcast(device).m_read_ba.set_callback(object); } + template static devcb_base &set_read_b_callback(device_t &device, _Object object) { return downcast(device).m_read_b.set_callback(object); } + template static devcb_base &set_write_s_callback(device_t &device, _Object object) { return downcast(device).m_write_s.set_callback(object); } + template static devcb_base &set_write_r_callback(device_t &device, _Object object) { return downcast(device).m_write_r.set_callback(object); } + + template static devcb_base &set_write_sega_callback(device_t &device, _Object object) { return downcast(device).m_write_sega.set_callback(object); } + template static devcb_base &set_write_segb_callback(device_t &device, _Object object) { return downcast(device).m_write_segb.set_callback(object); } + template static devcb_base &set_write_segc_callback(device_t &device, _Object object) { return downcast(device).m_write_segc.set_callback(object); } + template static devcb_base &set_write_segbs_callback(device_t &device, _Object object) { return downcast(device).m_write_segbs.set_callback(object); } + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_execute_interface overrides + virtual UINT64 execute_clocks_to_cycles(UINT64 clocks) const { return (clocks + 2 - 1) / 2; } // default 2 cycles per machine cycle + virtual UINT64 execute_cycles_to_clocks(UINT64 cycles) const { return (cycles * 2); } // " + virtual UINT32 execute_min_cycles() const { return 1; } + virtual UINT32 execute_max_cycles() const { return 2; } + virtual UINT32 execute_input_lines() const { return 1; } + virtual void execute_set_input(int line, int state); + virtual void execute_run(); + virtual void execute_one() { } // -> child class + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const { return(spacenum == AS_PROGRAM) ? &m_program_config : ((spacenum == AS_DATA) ? &m_data_config : NULL); } + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const { return 1; } + virtual UINT32 disasm_max_opcode_bytes() const { return 0x40; } // actually 2, but debugger doesn't like non-linear pc + + address_space_config m_program_config; + address_space_config m_data_config; + address_space *m_program; + address_space *m_data; + + int m_prgwidth; + int m_datawidth; + int m_prgmask; + int m_datamask; + + UINT16 m_pc, m_prev_pc; + UINT16 m_op, m_prev_op; + UINT8 m_param; + int m_stack_levels; + UINT16 m_stack[2]; + int m_icount; + + UINT8 m_acc; + UINT8 m_bl; + UINT8 m_bm; + UINT8 m_c; + bool m_skip; + UINT8 m_w; + UINT8 m_r; + bool m_k_active; + bool m_halt; + + // lcd driver + optional_shared_ptr m_lcd_ram_a, m_lcd_ram_b, m_lcd_ram_c; + devcb_write16 m_write_sega, m_write_segb, m_write_segc, m_write_segbs; + emu_timer *m_lcd_timer; + UINT8 m_l, m_x; + UINT8 m_y; + bool m_bp; + bool m_bc; + + UINT16 get_lcd_row(int column, UINT8* ram); + TIMER_CALLBACK_MEMBER(lcd_timer_cb); + void init_lcd_driver(); + + // melody controller + optional_region_ptr m_melody_rom; + UINT8 m_melody_rd; + UINT8 m_melody_step_count; + UINT8 m_melody_duty_count; + UINT8 m_melody_duty_index; + UINT8 m_melody_address; + + void clock_melody(); + void init_melody(); + + // interrupt/divider + emu_timer *m_div_timer; + UINT16 m_div; + bool m_1s; + + bool wake_me_up(); + void init_divider(); + TIMER_CALLBACK_MEMBER(div_timer_cb); + + // other i/o handlers + devcb_read8 m_read_k; + devcb_read_line m_read_ba; + devcb_read_line m_read_b; + devcb_write8 m_write_s; + devcb_write8 m_write_r; + + // misc internal helpers + void increment_pc(); + virtual void get_opcode_param() { } + virtual void update_w_latch() { } + + UINT8 ram_r(); + void ram_w(UINT8 data); + void pop_stack(); + void push_stack(); + void do_branch(UINT8 pu, UINT8 pm, UINT8 pl); + UINT8 bitmask(UINT16 param); + + // opcode handlers + void op_lb(); + void op_lbl(); + void op_sbm(); + void op_exbla(); + void op_incb(); + void op_decb(); + + void op_atpl(); + void op_rtn0(); + void op_rtn1(); + void op_tl(); + void op_tml(); + void op_tm(); + void op_t(); + + void op_exc(); + void op_bdc(); + void op_exci(); + void op_excd(); + void op_lda(); + void op_lax(); + void op_ptw(); + void op_wr(); + void op_ws(); + + void op_kta(); + void op_atbp(); + void op_atx(); + void op_atl(); + void op_atfc(); + void op_atr(); + + void op_add(); + void op_add11(); + void op_adx(); + void op_coma(); + void op_rot(); + void op_rc(); + void op_sc(); + + void op_tb(); + void op_tc(); + void op_tam(); + void op_tmi(); + void op_ta0(); + void op_tabl(); + void op_tis(); + void op_tal(); + void op_tf1(); + void op_tf4(); + + void op_rm(); + void op_sm(); + + void op_pre(); + void op_sme(); + void op_rme(); + void op_tmel(); + + void op_skip(); + void op_cend(); + void op_idiv(); + + void op_illegal(); +}; + + +class sm510_device : public sm510_base_device +{ +public: + sm510_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + virtual void execute_one(); + virtual void get_opcode_param(); + + virtual void update_w_latch() { m_write_s(0, m_w, 0xff); } // W is connected directly to S +}; + + +class sm511_device : public sm510_base_device +{ +public: + sm511_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + sm511_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, int stack_levels, int prgwidth, address_map_constructor program, int datawidth, address_map_constructor data, const char *shortname, const char *source); + +protected: + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + virtual void execute_one(); + virtual void get_opcode_param(); +}; + +class sm512_device : public sm511_device +{ +public: + sm512_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + + +extern const device_type SM510; +extern const device_type SM511; +extern const device_type SM512; + + +#endif /* _SM510_H_ */ diff --git a/src/devices/cpu/sm510/sm510core.c b/src/devices/cpu/sm510/sm510core.c new file mode 100644 index 00000000000..bf1449804c3 --- /dev/null +++ b/src/devices/cpu/sm510/sm510core.c @@ -0,0 +1,136 @@ +// license:BSD-3-Clause +// copyright-holders:hap +/* + + Sharp SM510 MCU core implementation + +*/ + +#include "sm510.h" +#include "debugger.h" + + +// MCU types +const device_type SM510 = &device_creator; + + +// internal memory maps +static ADDRESS_MAP_START(program_2_7k, AS_PROGRAM, 8, sm510_base_device) + AM_RANGE(0x0000, 0x02bf) AM_ROM + AM_RANGE(0x0400, 0x06bf) AM_ROM + AM_RANGE(0x0800, 0x0abf) AM_ROM + AM_RANGE(0x0c00, 0x0ebf) AM_ROM +ADDRESS_MAP_END + +static ADDRESS_MAP_START(data_96_32x4, AS_DATA, 8, sm510_base_device) + AM_RANGE(0x00, 0x5f) AM_RAM + AM_RANGE(0x60, 0x6f) AM_RAM AM_SHARE("lcd_ram_a") + AM_RANGE(0x70, 0x7f) AM_RAM AM_SHARE("lcd_ram_b") +ADDRESS_MAP_END + + +// device definitions +sm510_device::sm510_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : sm510_base_device(mconfig, SM510, "SM510", tag, owner, clock, 2 /* stack levels */, 12 /* prg width */, ADDRESS_MAP_NAME(program_2_7k), 7 /* data width */, ADDRESS_MAP_NAME(data_96_32x4), "sm510", __FILE__) +{ } + + +// disasm +offs_t sm510_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE(sm510); + return CPU_DISASSEMBLE_NAME(sm510)(this, buffer, pc, oprom, opram, options); +} + + + +//------------------------------------------------- +// execute +//------------------------------------------------- + +void sm510_device::get_opcode_param() +{ + // LBL, TL, TML opcodes are 2 bytes + if (m_op == 0x5f || (m_op & 0xf0) == 0x70) + { + m_icount--; + m_param = m_program->read_byte(m_pc); + increment_pc(); + } +} + +void sm510_device::execute_one() +{ + switch (m_op & 0xf0) + { + case 0x20: op_lax(); break; + case 0x30: op_adx(); break; + case 0x40: op_lb(); break; + + case 0x80: case 0x90: case 0xa0: case 0xb0: + op_t(); break; + case 0xc0: case 0xd0: case 0xe0: case 0xf0: + op_tm(); break; + + default: + switch (m_op & 0xfc) + { + case 0x04: op_rm(); break; + case 0x0c: op_sm(); break; + case 0x10: op_exc(); break; + case 0x14: op_exci(); break; + case 0x18: op_lda(); break; + case 0x1c: op_excd(); break; + case 0x54: op_tmi(); break; + case 0x70: case 0x74: case 0x78: op_tl(); break; + case 0x7c: op_tml(); break; + + default: + switch (m_op) + { + case 0x00: op_skip(); break; + case 0x01: op_atbp(); break; + case 0x02: op_sbm(); break; + case 0x03: op_atpl(); break; + case 0x08: op_add(); break; + case 0x09: op_add11(); break; + case 0x0a: op_coma(); break; + case 0x0b: op_exbla(); break; + + case 0x51: op_tb(); break; + case 0x52: op_tc(); break; + case 0x53: op_tam(); break; + case 0x58: op_tis(); break; + case 0x59: op_atl(); break; + case 0x5a: op_ta0(); break; + case 0x5b: op_tabl(); break; + case 0x5d: op_cend(); break; + case 0x5e: op_tal(); break; + case 0x5f: op_lbl(); break; + + case 0x60: op_atfc(); break; + case 0x61: op_atr(); break; + case 0x62: op_wr(); break; + case 0x63: op_ws(); break; + case 0x64: op_incb(); break; + case 0x65: op_idiv(); break; + case 0x66: op_rc(); break; + case 0x67: op_sc(); break; + case 0x68: op_tf1(); break; + case 0x69: op_tf4(); break; + case 0x6a: op_kta(); break; + case 0x6b: op_rot(); break; + case 0x6c: op_decb(); break; + case 0x6d: op_bdc(); break; + case 0x6e: op_rtn0(); break; + case 0x6f: op_rtn1(); break; + + default: op_illegal(); break; + } + break; // 0xff + + } + break; // 0xfc + + } // big switch +} diff --git a/src/devices/cpu/sm510/sm510d.c b/src/devices/cpu/sm510/sm510d.c new file mode 100644 index 00000000000..70e6b2c8ed6 --- /dev/null +++ b/src/devices/cpu/sm510/sm510d.c @@ -0,0 +1,215 @@ +// license:BSD-3-Clause +// copyright-holders:hap +/* + + Sharp SM510 MCU family disassembler + +*/ + +#include "emu.h" +#include "debugger.h" +#include "sm510.h" + + +// common lookup tables + +enum e_mnemonics +{ + mILL, mEXT, + mLB, mLBL, mSBM, mEXBLA, mINCB, mDECB, + mATPL, mRTN0, mRTN1, mTL, mTML, mTM, mT, + mEXC, mBDC, mEXCI, mEXCD, mLDA, mLAX, mPTW, mWR, mWS, + mKTA, mATBP, mATX, mATL, mATFC, mATR, + mADD, mADD11, mADX, mCOMA, mROT, mRC, mSC, + mTB, mTC, mTAM, mTMI, mTA0, mTABL, mTIS, mTAL, mTF1, mTF4, + mRM, mSM, + mPRE, mSME, mRME, mTMEL, + mSKIP, mCEND, mIDIV +}; + +static const char *const s_mnemonics[] = +{ + "?", "", + "LB", "LBL", "SBM", "EXBLA", "INCB", "DECB", + "ATPL", "RTN0", "RTN1", "TL", "TML", "TM", "T", + "EXC", "BDC", "EXCI", "EXCD", "LDA", "LAX", "PTW", "WR", "WS", + "KTA", "ATBP", "ATX", "ATL", "ATFC", "ATR", + "ADD", "ADD11", "ADX", "COMA", "ROT", "RC", "SC", + "TB", "TC", "TAM", "TMI", "TA0", "TABL", "TIS", "TAL", "TF1", "TF4", + "RM", "SM", + "PRE", "SME", "RME", "TMEL", + "SKIP", "CEND", "IDIV" +}; + +// number of bits per opcode parameter, 8 or larger means 2-byte opcode +static const UINT8 s_bits[] = +{ + 0, 8, + 4, 8, 0, 0, 0, 0, + 0, 0, 0, 4+8, 2+8, 6, 6, + 2, 0, 2, 2, 2, 4, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 4, 0, 0, 0, 0, + 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, + 2, 2, + 8, 0, 0, 0, + 0, 0, 0 +}; + +#define _OVER DASMFLAG_STEP_OVER +#define _OUT DASMFLAG_STEP_OUT + +static const UINT32 s_flags[] = +{ + 0, 0, + 0, 0, 0, 0, 0, 0, + 0, _OUT, _OUT, 0, _OVER, _OVER, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, + 0, 0, 0, 0, + 0, _OVER, 0 +}; + +// next program counter in sequence (relative) +static const INT8 s_next_pc[0x40] = +{ + 32, -1 /* rollback */, -1, 30, 30, -3, -3, 28, 28, -5, -5, 26, 26, -7, -7, 24, + 24, -9, -9, 22, 22, -11, -11, 20, 20, -13, -13, 18, 18, -15, -15, 16, + 16, -17, -17, 14, 14, -19, -19, 12, 12, -21, -21, 10, 10, -23, -23, 8, + 8, -25, -25, 6, 6, -27, -27, 4, 4, -29, -29, 2, 2, -31, -31, 0 /* gets stuck here */ +}; + + + +// common disasm + +static offs_t sm510_common_disasm(const UINT8 *lut_mnemonic, const UINT8 *lut_extended, char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram) +{ + // get raw opcode + UINT8 op = oprom[0]; + UINT8 instr = lut_mnemonic[op]; + int len = 1; + + int bits = s_bits[instr]; + UINT8 mask = op & ((1 << (bits & 7)) - 1); + UINT16 param = mask; + if (bits >= 8) + { + // note: disasm view shows correct parameter, but raw view does not + // note2: oprom array negative index doesn't work either :( + param = oprom[s_next_pc[pc & 0x3f]]; + len++; + } + + // extended opcode + bool is_extended = (instr == mEXT); + if (is_extended) + instr = lut_extended[param]; + + // disassemble it + char *dst = buffer; + dst += sprintf(dst, "%-6s ", s_mnemonics[instr]); + if (bits > 0) + { + if (bits <= 4) + { + if (param < 10) + dst += sprintf(dst, "%d", param); + else + dst += sprintf(dst, "$%X", param); + } + else if (bits <= 8) + { + if (!is_extended) + dst += sprintf(dst, "$%02X", param); + } + else + { + UINT16 address = (param << 4 & 0xc00) | (mask << 6 & 0x3c0) | (param & 0x03f); + dst += sprintf(dst, "$%03X", address); + } + + // show param offset + if (bits >= 8) + dst += sprintf(dst, " [$%03X]", pc + s_next_pc[pc & 0x3f]); + } + + return len | s_flags[instr] | DASMFLAG_SUPPORTED; +} + + +// SM510 disasm + +static const UINT8 sm510_mnemonic[0x100] = +{ +/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ + mSKIP, mATBP, mSBM, mATPL, mRM, mRM, mRM, mRM, mADD, mADD11,mCOMA, mEXBLA,mSM, mSM, mSM, mSM, // 0 + mEXC, mEXC, mEXC, mEXC, mEXCI, mEXCI, mEXCI, mEXCI, mLDA, mLDA, mLDA, mLDA, mEXCD, mEXCD, mEXCD, mEXCD, // 1 + mLAX, mLAX, mLAX, mLAX, mLAX, mLAX, mLAX, mLAX, mLAX, mLAX, mLAX, mLAX, mLAX, mLAX, mLAX, mLAX, // 2 + mADX, mADX, mADX, mADX, mADX, mADX, mADX, mADX, mADX, mADX, mADX, mADX, mADX, mADX, mADX, mADX, // 3 - note: $3A has synonym DC(decimal correct) + + mLB, mLB, mLB, mLB, mLB, mLB, mLB, mLB, mLB, mLB, mLB, mLB, mLB, mLB, mLB, mLB, // 4 + 0, mTB, mTC, mTAM, mTMI, mTMI, mTMI, mTMI, mTIS, mATL, mTA0, mTABL, 0, mCEND, mTAL, mLBL, // 5 + mATFC, mATR, mWR, mWS, mINCB, mIDIV, mRC, mSC, mTF1, mTF4, mKTA, mROT, mDECB, mBDC, mRTN0, mRTN1, // 6 + mTL, mTL, mTL, mTL, mTL, mTL, mTL, mTL, mTL, mTL, mTL, mTL, mTML, mTML, mTML, mTML, // 7 + + mT, mT, mT, mT, mT, mT, mT, mT, mT, mT, mT, mT, mT, mT, mT, mT, // 8 + mT, mT, mT, mT, mT, mT, mT, mT, mT, mT, mT, mT, mT, mT, mT, mT, // 9 + mT, mT, mT, mT, mT, mT, mT, mT, mT, mT, mT, mT, mT, mT, mT, mT, // A + mT, mT, mT, mT, mT, mT, mT, mT, mT, mT, mT, mT, mT, mT, mT, mT, // B + + mTM, mTM, mTM, mTM, mTM, mTM, mTM, mTM, mTM, mTM, mTM, mTM, mTM, mTM, mTM, mTM, // C + mTM, mTM, mTM, mTM, mTM, mTM, mTM, mTM, mTM, mTM, mTM, mTM, mTM, mTM, mTM, mTM, // D + mTM, mTM, mTM, mTM, mTM, mTM, mTM, mTM, mTM, mTM, mTM, mTM, mTM, mTM, mTM, mTM, // E + mTM, mTM, mTM, mTM, mTM, mTM, mTM, mTM, mTM, mTM, mTM, mTM, mTM, mTM, mTM, mTM // F +}; + +CPU_DISASSEMBLE(sm510) +{ + return sm510_common_disasm(sm510_mnemonic, NULL, buffer, pc, oprom, opram); +} + + +// SM511 disasm + +static const UINT8 sm511_mnemonic[0x100] = +{ +/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ + mROT, 0, mSBM, mATPL, mRM, mRM, mRM, mRM, mADD, mADD11,mCOMA, mEXBLA,mSM, mSM, mSM, mSM, // 0 + mEXC, mEXC, mEXC, mEXC, mEXCI, mEXCI, mEXCI, mEXCI, mLDA, mLDA, mLDA, mLDA, mEXCD, mEXCD, mEXCD, mEXCD, // 1 + mLAX, mLAX, mLAX, mLAX, mLAX, mLAX, mLAX, mLAX, mLAX, mLAX, mLAX, mLAX, mLAX, mLAX, mLAX, mLAX, // 2 + mADX, mADX, mADX, mADX, mADX, mADX, mADX, mADX, mADX, mADX, mADX, mADX, mADX, mADX, mADX, mADX, // 3 + + mLB, mLB, mLB, mLB, mLB, mLB, mLB, mLB, mLB, mLB, mLB, mLB, mLB, mLB, mLB, mLB, // 4 + mKTA, mTB, mTC, mTAM, mTMI, mTMI, mTMI, mTMI, mTIS, mATL, mTA0, mTABL, mATX, 0, mTAL, mLBL, // 5 + mEXT, mPRE, mWR, mWS, mINCB, 0, mRC, mSC, mTML, mTML, mTML, mTML, mDECB, mPTW, mRTN0, mRTN1, // 6 + mTL, mTL, mTL, mTL, mTL, mTL, mTL, mTL, mTL, mTL, mTL, mTL, mTL, mTL, mTL, mTL, // 7 + + mT, mT, mT, mT, mT, mT, mT, mT, mT, mT, mT, mT, mT, mT, mT, mT, // 8 + mT, mT, mT, mT, mT, mT, mT, mT, mT, mT, mT, mT, mT, mT, mT, mT, // 9 + mT, mT, mT, mT, mT, mT, mT, mT, mT, mT, mT, mT, mT, mT, mT, mT, // A + mT, mT, mT, mT, mT, mT, mT, mT, mT, mT, mT, mT, mT, mT, mT, mT, // B + + mTM, mTM, mTM, mTM, mTM, mTM, mTM, mTM, mTM, mTM, mTM, mTM, mTM, mTM, mTM, mTM, // C + mTM, mTM, mTM, mTM, mTM, mTM, mTM, mTM, mTM, mTM, mTM, mTM, mTM, mTM, mTM, mTM, // D + mTM, mTM, mTM, mTM, mTM, mTM, mTM, mTM, mTM, mTM, mTM, mTM, mTM, mTM, mTM, mTM, // E + mTM, mTM, mTM, mTM, mTM, mTM, mTM, mTM, mTM, mTM, mTM, mTM, mTM, mTM, mTM, mTM // F +}; + +static const UINT8 sm511_extended[0x10] = +{ + mRME, mSME, mTMEL, mATFC, mBDC, mATBP, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 60 3 +}; + +CPU_DISASSEMBLE(sm511) +{ + // create extended opcode table + UINT8 ext[0x100]; + memset(ext, 0, 0x100); + memcpy(ext + 0x30, sm511_extended, 0x10); + + return sm510_common_disasm(sm511_mnemonic, ext, buffer, pc, oprom, opram); +} diff --git a/src/devices/cpu/sm510/sm510op.c b/src/devices/cpu/sm510/sm510op.c new file mode 100644 index 00000000000..cf99cbc5ae4 --- /dev/null +++ b/src/devices/cpu/sm510/sm510op.c @@ -0,0 +1,456 @@ +// license:BSD-3-Clause +// copyright-holders:hap + +// SM510 opcode handlers + +#include "sm510.h" + + +// internal helpers + +inline UINT8 sm510_base_device::ram_r() +{ + int bmh = (m_prev_op == 0x02) ? (1 << (m_datawidth-1)) : 0; // from SBM + UINT8 address = (bmh | m_bm << 4 | m_bl) & m_datamask; + return m_data->read_byte(address) & 0xf; +} + +inline void sm510_base_device::ram_w(UINT8 data) +{ + int bmh = (m_prev_op == 0x02) ? (1 << (m_datawidth-1)) : 0; // from SBM + UINT8 address = (bmh | m_bm << 4 | m_bl) & m_datamask; + m_data->write_byte(address, data & 0xf); +} + +void sm510_base_device::pop_stack() +{ + m_pc = m_stack[0] & m_prgmask; + for (int i = 0; i < m_stack_levels-1; i++) + m_stack[i] = m_stack[i+1]; +} + +void sm510_base_device::push_stack() +{ + for (int i = m_stack_levels-1; i >= 1; i--) + m_stack[i] = m_stack[i-1]; + m_stack[0] = m_pc; +} + +void sm510_base_device::do_branch(UINT8 pu, UINT8 pm, UINT8 pl) +{ + // set new PC(Pu/Pm/Pl) + m_pc = ((pu << 10 & 0xc00) | (pm << 6 & 0x3c0) | (pl & 0x03f)) & m_prgmask; +} + +inline UINT8 sm510_base_device::bitmask(UINT16 param) +{ + // bitmask from immediate opcode param + return 1 << (param & 3); +} + + + +// instruction set + +// RAM address instructions + +void sm510_base_device::op_lb() +{ + // LB x: load BM/BL with 4-bit immediate value (partial) + + // SM510 WIP.. + // bm and bl(low) are probably ok! + m_bm = (m_bm & 4) | (m_op & 3); + m_bl = (m_op >> 2 & 3); + + // bl(high) is still unclear, official doc is confusing + UINT8 hi = 0; + switch (m_bl) + { + case 0: hi = 3; break; + case 1: hi = 0; break; + case 2: hi = 0; break; + case 3: hi = 3; break; + } + m_bl |= (hi << 2 & 0xc); +} + +void sm510_base_device::op_lbl() +{ + // LBL xy: load BM/BL with 8-bit immediate value + m_bl = m_param & 0xf; + m_bm = (m_param & m_datamask) >> 4; +} + +void sm510_base_device::op_sbm() +{ + // SBM: set BM high bit for next opcode - handled in ram_r/w + assert(m_op == 0x02); +} + +void sm510_base_device::op_exbla() +{ + // EXBLA: exchange BL with ACC + UINT8 a = m_acc; + m_acc = m_bl; + m_bl = a; +} + +void sm510_base_device::op_incb() +{ + // INCB: increment BL, skip next on overflow + m_bl = (m_bl + 1) & 0xf; + m_skip = (m_bl == 0); +} + +void sm510_base_device::op_decb() +{ + // DECB: decrement BL, skip next on overflow + m_bl = (m_bl - 1) & 0xf; + m_skip = (m_bl == 0xf); +} + + +// ROM address instructions + +void sm510_base_device::op_atpl() +{ + // ATPL: load Pl(PC low bits) with ACC + m_pc = (m_pc & ~0xf) | m_acc; +} + +void sm510_base_device::op_rtn0() +{ + // RTN0: return from subroutine + pop_stack(); +} + +void sm510_base_device::op_rtn1() +{ + // RTN1: return from subroutine, skip next + op_rtn0(); + m_skip = true; +} + +void sm510_base_device::op_t() +{ + // T xy: jump(transfer) within current page + m_pc = (m_pc & ~0x3f) | (m_op & 0x3f); +} + +void sm510_base_device::op_tl() +{ + // TL xyz: long jump + do_branch(m_param >> 6 & 3, m_op & 0xf, m_param & 0x3f); +} + +void sm510_base_device::op_tml() +{ + // TML xyz: long call + push_stack(); + do_branch(m_param >> 6 & 3, m_op & 3, m_param & 0x3f); +} + +void sm510_base_device::op_tm() +{ + // TM x: indirect subroutine call, pointers(IDX) are in page 0 + m_icount--; + push_stack(); + UINT8 idx = m_program->read_byte(m_op & 0x3f); + do_branch(idx >> 6 & 3, 4, idx & 0x3f); +} + + + +// Data transfer instructions + +void sm510_base_device::op_exc() +{ + // EXC x: exchange ACC with RAM, xor BM with x + UINT8 a = m_acc; + m_acc = ram_r(); + ram_w(a); + m_bm ^= (m_op & 3); +} + +void sm510_base_device::op_bdc() +{ + // BDC: enable LCD bleeder current with C + m_bc = (m_c != 0); +} + +void sm510_base_device::op_exci() +{ + // EXCI x: EXC x, INCB + op_exc(); + op_incb(); +} + +void sm510_base_device::op_excd() +{ + // EXCD x: EXC x, DECB + op_exc(); + op_decb(); +} + +void sm510_base_device::op_lda() +{ + // LDA x: load ACC with RAM, xor BM with x + m_acc = ram_r(); + m_bm ^= (m_op & 3); +} + +void sm510_base_device::op_lax() +{ + // LAX x: load ACC with immediate value, skip any next LAX + if ((m_op & ~0xf) != (m_prev_op & ~0xf)) + m_acc = m_op & 0xf; +} + +void sm510_base_device::op_ptw() +{ + // PTW: output W latch + m_write_s(0, m_w, 0xff); +} + +void sm510_base_device::op_wr() +{ + // WR: shift 0 into W + m_w = m_w << 1 | 0; + update_w_latch(); +} + +void sm510_base_device::op_ws() +{ + // WR: shift 1 into W + m_w = m_w << 1 | 1; + update_w_latch(); +} + + +// I/O instructions + +void sm510_base_device::op_kta() +{ + // KTA: input K to ACC + m_acc = m_read_k(0, 0xff) & 0xf; +} + +void sm510_base_device::op_atbp() +{ + // ATBP: output ACC to BP(internal LCD backplate signal) + m_bp = ((m_acc & 1) != 0); +} + +void sm510_base_device::op_atx() +{ + // ATX: output ACC to X + m_x = m_acc; +} + +void sm510_base_device::op_atl() +{ + // ATL: output ACC to L + m_l = m_acc; +} + +void sm510_base_device::op_atfc() +{ + // ATFC: output ACC to Y + m_y = m_acc; +} + +void sm510_base_device::op_atr() +{ + // ATR: output ACC to R + if (m_r != (m_acc & 3)) + { + m_r = m_acc & 3; + m_write_r(0, m_r, 0xff); + } +} + + +// Arithmetic instructions + +void sm510_base_device::op_add() +{ + // ADD: add RAM to ACC + m_acc = (m_acc + ram_r()) & 0xf; +} + +void sm510_base_device::op_add11() +{ + // ADD11: add RAM and carry to ACC and carry, skip next on carry + m_acc += ram_r() + m_c; + m_c = m_acc >> 4 & 1; + m_skip = (m_c == 1); + m_acc &= 0xf; +} + +void sm510_base_device::op_adx() +{ + // ADX x: add immediate value to ACC, skip next on carry + m_acc += (m_op & 0xf); + m_skip = ((m_acc & 0x10) != 0); + m_acc &= 0xf; +} + +void sm510_base_device::op_coma() +{ + // COMA: complement ACC + m_acc ^= 0xf; +} + +void sm510_base_device::op_rot() +{ + // ROT: rotate ACC right through carry + UINT8 c = m_acc & 1; + m_acc = m_acc >> 1 | m_c << 3; + m_c = c; +} + +void sm510_base_device::op_rc() +{ + // RC: reset carry + m_c = 0; +} + +void sm510_base_device::op_sc() +{ + // SC: set carry + m_c = 1; +} + + +// Test instructions + +void sm510_base_device::op_tb() +{ + // TB: skip next if B(beta) pin is set + m_skip = (m_read_b() != 0); +} + +void sm510_base_device::op_tc() +{ + // TC: skip next if no carry + m_skip = !m_c; +} + +void sm510_base_device::op_tam() +{ + // TAM: skip next if ACC equals RAM + m_skip = (m_acc == ram_r()); +} + +void sm510_base_device::op_tmi() +{ + // TMI x: skip next if RAM bit is set + m_skip = ((ram_r() & bitmask(m_op)) != 0); +} + +void sm510_base_device::op_ta0() +{ + // TA0: skip next if ACC is clear + m_skip = !m_acc; +} + +void sm510_base_device::op_tabl() +{ + // TABL: skip next if ACC equals BL + m_skip = (m_acc == m_bl); +} + +void sm510_base_device::op_tis() +{ + // TIS: skip next if 1S(gamma flag) is clear, reset it after + m_skip = !m_1s; + m_1s = false; +} + +void sm510_base_device::op_tal() +{ + // TAL: skip next if BA pin is set + m_skip = (m_read_ba() != 0); +} + +void sm510_base_device::op_tf1() +{ + // TF1: skip next if divider F1(d14) is set + m_skip = ((m_div & 0x4000) != 0); +} + +void sm510_base_device::op_tf4() +{ + // TF4: skip next if divider F4(d11) is set + m_skip = ((m_div & 0x0800) != 0); +} + + +// Bit manipulation instructions + +void sm510_base_device::op_rm() +{ + // RM x: reset RAM bit + ram_w(ram_r() & ~bitmask(m_op)); +} + +void sm510_base_device::op_sm() +{ + // SM x: set RAM bit + ram_w(ram_r() | bitmask(m_op)); +} + + +// Melody control instructions + +void sm510_base_device::op_pre() +{ + // PRE x: melody ROM pointer preset + m_melody_address = m_param; + m_melody_step_count = 0; +} + +void sm510_base_device::op_sme() +{ + // SME: set melody enable + m_melody_rd |= 1; +} + +void sm510_base_device::op_rme() +{ + // RME: reset melody enable + m_melody_rd &= ~1; +} + +void sm510_base_device::op_tmel() +{ + // TMEL: skip next if rest signal is set, reset it + m_skip = ((m_melody_rd & 2) != 0); + m_melody_rd &= ~2; +} + + +// Special instructions + +void sm510_base_device::op_skip() +{ + // SKIP: no operation +} + +void sm510_base_device::op_cend() +{ + // CEND: stop clock (halt the cpu and go into low-power mode) + m_halt = true; +} + +void sm510_base_device::op_idiv() +{ + // IDIV: reset divider + m_div = 0; +} + +void sm510_base_device::op_illegal() +{ + logerror("%s unknown opcode $%02X at $%04X\n", tag(), m_op, m_prev_pc); +} diff --git a/src/devices/cpu/sm510/sm511core.c b/src/devices/cpu/sm510/sm511core.c new file mode 100644 index 00000000000..2347721ff90 --- /dev/null +++ b/src/devices/cpu/sm510/sm511core.c @@ -0,0 +1,162 @@ +// license:BSD-3-Clause +// copyright-holders:hap +/* + + Sharp SM511 MCU core implementation + +*/ + +#include "sm510.h" +#include "debugger.h" + + +// MCU types +const device_type SM511 = &device_creator; +const device_type SM512 = &device_creator; + + +// internal memory maps +static ADDRESS_MAP_START(program_4k, AS_PROGRAM, 8, sm510_base_device) + AM_RANGE(0x0000, 0x0fff) AM_ROM +ADDRESS_MAP_END + +static ADDRESS_MAP_START(data_96_32x4, AS_DATA, 8, sm510_base_device) + AM_RANGE(0x00, 0x5f) AM_RAM + AM_RANGE(0x60, 0x6f) AM_RAM AM_SHARE("lcd_ram_a") + AM_RANGE(0x70, 0x7f) AM_RAM AM_SHARE("lcd_ram_b") +ADDRESS_MAP_END + +static ADDRESS_MAP_START(data_80_48x4, AS_DATA, 8, sm510_base_device) + AM_RANGE(0x00, 0x4f) AM_RAM + AM_RANGE(0x50, 0x5f) AM_RAM AM_SHARE("lcd_ram_c") + AM_RANGE(0x60, 0x6f) AM_RAM AM_SHARE("lcd_ram_a") + AM_RANGE(0x70, 0x7f) AM_RAM AM_SHARE("lcd_ram_b") +ADDRESS_MAP_END + + +// disasm +offs_t sm511_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE(sm511); + return CPU_DISASSEMBLE_NAME(sm511)(this, buffer, pc, oprom, opram, options); +} + + +// device definitions +sm511_device::sm511_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : sm510_base_device(mconfig, SM511, "SM511", tag, owner, clock, 2 /* stack levels */, 12 /* prg width */, ADDRESS_MAP_NAME(program_4k), 7 /* data width */, ADDRESS_MAP_NAME(data_96_32x4), "sm511", __FILE__) +{ } + +sm511_device::sm511_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, int stack_levels, int prgwidth, address_map_constructor program, int datawidth, address_map_constructor data, const char *shortname, const char *source) + : sm510_base_device(mconfig, type, name, tag, owner, clock, stack_levels, prgwidth, program, datawidth, data, shortname, source) +{ } + +sm512_device::sm512_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : sm511_device(mconfig, SM512, "SM512", tag, owner, clock, 2, 12, ADDRESS_MAP_NAME(program_4k), 7, ADDRESS_MAP_NAME(data_80_48x4), "sm512", __FILE__) +{ } + + + +//------------------------------------------------- +// execute +//------------------------------------------------- + +void sm511_device::get_opcode_param() +{ + // XXX?, LBL, PRE, TL, TML and prefix opcodes are 2 bytes + if (m_op == 0x01 || (m_op >= 0x5f && m_op <= 0x61) || (m_op & 0xf0) == 0x70 || (m_op & 0xfc) == 0x68) + { + m_icount--; + m_param = m_program->read_byte(m_pc); + increment_pc(); + } +} + +void sm511_device::execute_one() +{ + switch (m_op & 0xf0) + { + case 0x20: op_lax(); break; + case 0x30: op_adx(); break; + case 0x40: op_lb(); break; + case 0x70: op_tl(); break; + + case 0x80: case 0x90: case 0xa0: case 0xb0: + op_t(); break; + case 0xc0: case 0xd0: case 0xe0: case 0xf0: + op_tm(); break; + + default: + switch (m_op & 0xfc) + { + case 0x04: op_rm(); break; + case 0x0c: op_sm(); break; + case 0x10: op_exc(); break; + case 0x14: op_exci(); break; + case 0x18: op_lda(); break; + case 0x1c: op_excd(); break; + case 0x54: op_tmi(); break; + case 0x68: op_tml(); break; + + default: + switch (m_op) + { + case 0x00: op_rot(); break; +// case 0x01: op_xxx(); break; // ? + case 0x02: op_sbm(); break; + case 0x03: op_atpl(); break; + case 0x08: op_add(); break; + case 0x09: op_add11(); break; + case 0x0a: op_coma(); break; + case 0x0b: op_exbla(); break; + + case 0x50: op_kta(); break; + case 0x51: op_tb(); break; + case 0x52: op_tc(); break; + case 0x53: op_tam(); break; + case 0x58: op_tis(); break; + case 0x59: op_atl(); break; + case 0x5a: op_ta0(); break; + case 0x5b: op_tabl(); break; + case 0x5c: op_atx(); break; +// case 0x5d: op_cend(); break; + case 0x5e: op_tal(); break; + case 0x5f: op_lbl(); break; + + case 0x61: op_pre(); break; + case 0x62: op_wr(); break; + case 0x63: op_ws(); break; + case 0x64: op_incb(); break; +// case 0x65: op_idiv(); break; + case 0x66: op_rc(); break; + case 0x67: op_sc(); break; + case 0x6c: op_decb(); break; + case 0x6d: op_ptw(); break; + case 0x6e: op_rtn0(); break; + case 0x6f: op_rtn1(); break; + + // extended opcodes + case 0x60: + m_op = m_op << 8 | m_param; + switch (m_param) + { + case 0x30: op_rme(); break; + case 0x31: op_sme(); break; + case 0x32: op_tmel(); break; + case 0x33: op_atfc(); break; + case 0x34: op_bdc(); break; + case 0x35: op_atbp(); break; + + default: op_illegal(); break; + } + break; // 0x60 + + default: op_illegal(); break; + } + break; // 0xff + + } + break; // 0xfc + + } // big switch +} diff --git a/src/devices/cpu/sm8500/sm8500.c b/src/devices/cpu/sm8500/sm8500.c new file mode 100644 index 00000000000..6159d8a45fa --- /dev/null +++ b/src/devices/cpu/sm8500/sm8500.c @@ -0,0 +1,428 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +/* + Implementation for Sharp sm8500 cpu. There is hardly any information available + on this cpu. Currently we've only found documentation on the microcontroller + parts of the cpu, but nothing on the cpu itself. + + Through looking at binary data we have attempted to figure out the opcodes for + this cpu, and made educated guesses on the number of cycles for each instruction. + + Code by Wilbert Pol + + +There is some internal ram for the main cpu registers. They are offset by an index value. +The address is (PS0 & 0xF8) + register number. It is not known what happens when PS0 >= F8. +The assumption is that F8 to 107 is used, but it might wrap around instead. +The registers also mirror out to main RAM, appearing at 0000 to 000F regardless of where +they are internally. + +*/ + +#include "emu.h" +#include "debugger.h" +#include "sm8500.h" + + +const device_type SM8500 = &device_creator; + + +static const UINT8 sm8500_b2w[8] = { + 0, 8, 2, 10, 4, 12, 6, 14 +}; + + +sm8500_cpu_device::sm8500_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : cpu_device(mconfig, SM8500, "SM8500", tag, owner, clock, "sm8500", __FILE__) + , m_program_config("program", ENDIANNESS_BIG, 8, 16, 0) + , m_dma_func(*this) + , m_timer_func(*this) + , m_PC(0) + , m_SYS(0) + , m_SP(0) + , m_PS0(0) + , m_PS1(0) +{ +} + + +void sm8500_cpu_device::get_sp() +{ + m_SP = m_program->read_byte(0x1d); + if (m_SYS & 0x40) m_SP |= ( m_program->read_byte(0x1c) << 8 ); +} + + +UINT8 sm8500_cpu_device::mem_readbyte( UINT32 offset ) +{ + offset &= 0xffff; + if ( offset < 0x10) + { + return m_register_ram[offset + (m_PS0 & 0xF8)]; + } + + return m_program->read_byte( offset ); +} + + +void sm8500_cpu_device::mem_writebyte( UINT32 offset, UINT8 data ) +{ + UINT8 i; + offset &= 0xffff; + if (offset < 0x10) + { + m_register_ram[offset + (m_PS0 & 0xF8)] = data; + } + + m_program->write_byte( offset, data ); + + switch (offset) + { + case 0x10: m_IE0 = data; break; + case 0x11: m_IE1 = data; break; + case 0x12: m_IR0 = data; break; + case 0x13: m_IR1 = data; break; + case 0x19: m_SYS = data; break; + case 0x1a: m_CKC = data; break; + case 0x1c: + case 0x1d: get_sp(); break; + case 0x1e: m_PS0 = data; + for (i = 0; i < 16; i++) // refresh register contents in debugger + { + m_program->write_byte(i, mem_readbyte(i)); + } + break; + case 0x1f: m_PS1 = data; break; + } +} + + +void sm8500_cpu_device::device_start() +{ + m_program = &space(AS_PROGRAM); + + m_dma_func.resolve_safe(); + m_timer_func.resolve_safe(); + + save_item(NAME(m_PC)); + save_item(NAME(m_IE0)); + save_item(NAME(m_IE1)); + save_item(NAME(m_IR0)); + save_item(NAME(m_IR1)); + save_item(NAME(m_SYS)); + save_item(NAME(m_CKC)); + save_item(NAME(m_clock_changed)); + save_item(NAME(m_SP)); + save_item(NAME(m_PS0)); + save_item(NAME(m_PS1)); + save_item(NAME(m_IFLAGS)); + save_item(NAME(m_CheckInterrupts)); + save_item(NAME(m_halted)); + save_item(NAME(m_oldpc)); + save_pointer(NAME(m_register_ram),0x108); + + // Register state for debugger + state_add(SM8500_PC, "PC", m_PC ).callimport().callexport().formatstr("%04X"); + state_add(SM8500_SP, "SP", m_SP ).callimport().callexport().formatstr("%04X"); + state_add(SM8500_PS, "PS", m_PS0 ).callimport().callexport().formatstr("%04s"); + state_add(SM8500_SYS, "SYS", m_SYS ).callimport().callexport().formatstr("%04X"); + state_add(SM8500_RR0, "RR0", m_PC ).callimport().callexport().formatstr("%04s"); + state_add(SM8500_RR2, "RR2", m_PC ).callimport().callexport().formatstr("%04s"); + state_add(SM8500_RR4, "RR4", m_PC ).callimport().callexport().formatstr("%04s"); + state_add(SM8500_RR6, "RR6", m_PC ).callimport().callexport().formatstr("%04s"); + state_add(SM8500_RR8, "RR8", m_PC ).callimport().callexport().formatstr("%04s"); + state_add(SM8500_RR10, "RR10", m_PC ).callimport().callexport().formatstr("%04s"); + state_add(SM8500_RR12, "RR12", m_PC ).callimport().callexport().formatstr("%04s"); + state_add(SM8500_RR14, "RR14", m_PC ).callimport().callexport().formatstr("%04s"); + state_add(STATE_GENPC, "curpc", m_PC).callimport().callexport().formatstr("%8s").noshow(); + state_add(STATE_GENFLAGS, "GENFLAGS", m_PS1).formatstr("%8s").noshow(); + + m_icountptr = &m_icount; +} + + +void sm8500_cpu_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + switch (entry.index()) + { + case SM8500_PS: + strprintf(str, "%04X", ( m_PS0 << 8 ) | m_PS1 ); + break; + + case SM8500_RR0: + strprintf(str, "%04X", mem_readword( 0x00 ) ); + break; + + case SM8500_RR2: + strprintf(str, "%04X", mem_readword( 0x02 ) ); + break; + + case SM8500_RR4: + strprintf(str, "%04X", mem_readword( 0x04 ) ); + break; + + case SM8500_RR6: + strprintf(str, "%04X", mem_readword( 0x06 ) ); + break; + + case SM8500_RR8: + strprintf(str, "%04X", mem_readword( 0x08 ) ); + break; + + case SM8500_RR10: + strprintf(str, "%04X", mem_readword( 0x0a ) ); + break; + + case SM8500_RR12: + strprintf(str, "%04X", mem_readword( 0x0c ) ); + break; + + case SM8500_RR14: + strprintf(str, "%04X", mem_readword( 0x0e ) ); + break; + + case STATE_GENFLAGS: + strprintf(str, "%c%c%c%c%c%c%c%c", + m_PS1 & FLAG_C ? 'C' : '.', + m_PS1 & FLAG_Z ? 'Z' : '.', + m_PS1 & FLAG_S ? 'S' : '.', + m_PS1 & FLAG_V ? 'V' : '.', + m_PS1 & FLAG_D ? 'D' : '.', + m_PS1 & FLAG_H ? 'H' : '.', + m_PS1 & FLAG_B ? 'B' : '.', + m_PS1 & FLAG_I ? 'I' : '.' ); + break; + } +} + + +void sm8500_cpu_device::device_reset() +{ + for ( int i = 0; i < 0x108; i++ ) + { + m_register_ram[i] = 0; + } + + m_PC = 0x1020; + m_clock_changed = 0; + m_CheckInterrupts = 0; + m_halted = 0; + m_IFLAGS = 0; + mem_writeword(0x10, 0); // IE0, IE1 + mem_writeword(0x12, 0); // IR0, IR1 + mem_writeword(0x14, 0xffff); // P0, P1 + mem_writeword(0x16, 0xff00); // P2, P3 + mem_writebyte(0x19, 0); // SYS + mem_writebyte(0x1a, 0); // CKC + mem_writebyte(0x1f, 0); // PS1 + mem_writebyte(0x2b, 0xff); // URTT + mem_writebyte(0x2d, 0x42); // URTS + mem_writebyte(0x5f, 0x38); // WDTC +} + + +#define PUSH_BYTE(X) m_SP--; \ + if ( ( m_SYS & 0x40 ) == 0 ) m_SP &= 0xFF; \ + mem_writebyte( m_SP, X ); + + +void sm8500_cpu_device::take_interrupt(UINT16 vector) +{ + /* Get regs from ram */ + get_sp(); + m_SYS = m_program->read_byte(0x19); + m_PS1 = m_program->read_byte(0x1f); + /* Push PC */ + PUSH_BYTE( m_PC & 0xFF ); + PUSH_BYTE( m_PC >> 8 ); + /* Push PS1 */ + PUSH_BYTE( m_PS1 ); + /* Clear I flag */ + m_PS1 &= ~ 0x01; + /* save regs to ram */ + m_program->write_byte(0x1f, m_PS1); + m_program->write_byte(0x1d, m_SP&0xFF); + if (m_SYS&0x40) m_program->write_byte(0x1c, m_SP>>8); + /* Change PC to address stored at "vector" */ + m_PC = mem_readword( vector ); +} + + +void sm8500_cpu_device::process_interrupts() +{ + if ( m_CheckInterrupts ) + { + int irqline = 0; + while( irqline < 11 ) + { + if ( m_IFLAGS & ( 1 << irqline ) ) + { + m_halted = 0; + m_IE0 = m_program->read_byte(0x10); + m_IE1 = m_program->read_byte(0x11); + m_IR0 = m_program->read_byte(0x12); + m_IR1 = m_program->read_byte(0x13); + m_PS0 = m_program->read_byte(0x1e); + m_PS1 = m_program->read_byte(0x1f); + switch( irqline ) + { + case WDT_INT: + take_interrupt( 0x101C ); + break; + case ILL_INT: + case NMI_INT: + take_interrupt( 0x101E ); + break; + case DMA_INT: + m_IR0 |= 0x80; + if ( ( m_IE0 & 0x80 ) && ( ( m_PS0 & 0x07 ) < 8 ) && ( m_PS1 & 0x01 ) ) + { + take_interrupt( 0x1000 ); + } + break; + case TIM0_INT: + m_IR0 |= 0x40; + if ( ( m_IE0 & 0x40 ) && ( ( m_PS0 & 0x07 ) < 8 ) && ( m_PS1 & 0x01 ) ) + { + take_interrupt( 0x1002 ); + } + break; + case EXT_INT: + m_IR0 |= 0x10; + if ( ( m_IE0 & 0x10 ) && ( ( m_PS0 & 0x07 ) < 7 ) && ( m_PS1 & 0x01 ) ) + { + take_interrupt( 0x1006 ); + } + break; + case UART_INT: + m_IR0 |= 0x08; + if ( ( m_IE0 & 0x08 ) && ( ( m_PS0 & 0x07 ) < 6 ) && ( m_PS1 & 0x01 ) ) + { + take_interrupt( 0x1008 ); + } + break; + case LCDC_INT: + m_IR0 |= 0x01; + if ( ( m_IE0 & 0x01 ) && ( ( m_PS0 & 0x07 ) < 5 ) && ( m_PS1 & 0x01 ) ) + { + take_interrupt( 0x100E ); + } + break; + case TIM1_INT: + m_IR1 |= 0x40; + if ( ( m_IE1 & 0x40 ) && ( ( m_PS0 & 0x07 ) < 4 ) && ( m_PS1 & 0x01 ) ) + { + take_interrupt( 0x1012 ); + } + break; + case CK_INT: + m_IR1 |= 0x10; + if ( ( m_IE1 & 0x10 ) && ( ( m_PS0 & 0x07 ) < 3 ) && ( m_PS1 & 0x01 ) ) + { + take_interrupt( 0x1016 ); + } + break; + case PIO_INT: + m_IR1 |= 0x04; + if ( ( m_IE1 & 0x04 ) && ( ( m_PS0 & 0x07 ) < 2 ) && ( m_PS1 & 0x01 ) ) + { + take_interrupt( 0x101A ); + } + break; + } + m_IFLAGS &= ~ ( 1 << irqline ); + m_program->write_byte(0x12, m_IR0); + m_program->write_byte(0x13, m_IR1); + } + irqline++; + } + } +} + + +offs_t sm8500_cpu_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( sm8500 ); + return CPU_DISASSEMBLE_NAME(sm8500)(this, buffer, pc, oprom, opram, options); +} + + +void sm8500_cpu_device::execute_run() +{ + do + { + int mycycles = 0; + UINT8 r1,r2; + UINT16 s1,s2; + UINT32 d1,d2; + UINT32 res; + + debugger_instruction_hook(this, m_PC); + m_oldpc = m_PC; + process_interrupts(); + if ( !m_halted ) { + UINT8 op = mem_readbyte( m_PC++ ); + m_SYS = m_program->read_byte(0x19); + m_PS0 = m_program->read_byte(0x1e); + m_PS1 = m_program->read_byte(0x1f); + get_sp(); + switch( op ) + { +#include "sm85ops.h" + } + if (m_SYS&0x40) m_program->write_byte(0x1c,m_SP>>8); + m_program->write_byte(0x1d,m_SP&0xFF); + mem_writebyte(0x1e,m_PS0); // need to update debugger + m_program->write_byte(0x1f,m_PS1); + } else { + mycycles = 4; + m_dma_func( mycycles ); + } + m_timer_func( mycycles ); + m_icount -= mycycles; + } while ( m_icount > 0 ); +} + + +void sm8500_cpu_device::execute_set_input( int inptnum, int state ) +{ + m_IR0 = m_program->read_byte(0x12); + m_IR1 = m_program->read_byte(0x13); + if ( state == ASSERT_LINE ) + { + m_IFLAGS |= ( 0x01 << inptnum ); + m_CheckInterrupts = 1; + switch( inptnum ) + { + case DMA_INT: m_IR0 |= 0x80; break; + case TIM0_INT: m_IR0 |= 0x40; break; + case EXT_INT: m_IR0 |= 0x10; break; + case UART_INT: m_IR0 |= 0x08; break; + case LCDC_INT: m_IR0 |= 0x01; break; + case TIM1_INT: m_IR1 |= 0x40; break; + case CK_INT: m_IR1 |= 0x10; break; + case PIO_INT: m_IR1 |= 0x04; break; + } + } + else + { + m_IFLAGS &= ~( 0x01 << inptnum ); + switch( inptnum ) + { + case DMA_INT: m_IR0 &= ~0x80; break; + case TIM0_INT: m_IR0 &= ~0x40; break; + case EXT_INT: m_IR0 &= ~0x10; break; + case UART_INT: m_IR0 &= ~0x08; break; + case LCDC_INT: m_IR0 &= ~0x01; break; + case TIM1_INT: m_IR1 &= ~0x40; break; + case CK_INT: m_IR1 &= ~0x10; break; + case PIO_INT: m_IR1 &= ~0x04; break; + } + if ( 0 == m_IFLAGS ) + { + m_CheckInterrupts = 0; + } + } + m_program->write_byte(0x12, m_IR0); + m_program->write_byte(0x13, m_IR1); +} diff --git a/src/devices/cpu/sm8500/sm8500.h b/src/devices/cpu/sm8500/sm8500.h new file mode 100644 index 00000000000..7cd7df8f6f4 --- /dev/null +++ b/src/devices/cpu/sm8500/sm8500.h @@ -0,0 +1,118 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +#pragma once + +#ifndef __SM8500_H__ +#define __SM8500_H__ + +#define MCFG_SM8500_DMA_CB(_devcb) \ + sm8500_cpu_device::set_dma_cb(*device, DEVCB_##_devcb); + +#define MCFG_SM8500_TIMER_CB(_devcb) \ + sm8500_cpu_device::set_timer_cb(*device, DEVCB_##_devcb); + +enum +{ + /* "main" 16 bit register */ + SM8500_PC=1, SM8500_SP, SM8500_PS, SM8500_SYS16, SM8500_RR0, SM8500_RR2, SM8500_RR4, SM8500_RR6, SM8500_RR8, SM8500_RR10, + SM8500_RR12, SM8500_RR14, + /* additional internal 8 bit registers */ + SM8500_IE0, SM8500_IE1, SM8500_IR0, SM8500_IR1, SM8500_P0, SM8500_P1, SM8500_P2, SM8500_P3, SM8500_SYS, SM8500_CKC, + SM8500_SPH, SM8500_SPL, SM8500_PS0, SM8500_PS1, SM8500_P0C, SM8500_P1C, SM8500_P2C, SM8500_P3C +}; + + +class sm8500_cpu_device : public cpu_device +{ +public: + // construction/destruction + sm8500_cpu_device(const machine_config &mconfig, const char *_tag, device_t *_owner, UINT32 _clock); + + // static configuration helpers + template static devcb_base &set_dma_cb(device_t &device, _Object object) { return downcast(device).m_dma_func.set_callback(object); } + template static devcb_base &set_timer_cb(device_t &device, _Object object) { return downcast(device).m_timer_func.set_callback(object); } + + /* interrupts */ + static const int ILL_INT = 0; + static const int DMA_INT = 1; + static const int TIM0_INT = 2; + static const int EXT_INT = 3; + static const int UART_INT = 4; + static const int LCDC_INT = 5; + static const int TIM1_INT = 6; + static const int CK_INT = 7; + static const int PIO_INT = 8; + static const int WDT_INT = 9; + static const int NMI_INT = 10; + +protected: + // Flags + static const UINT8 FLAG_C = 0x80; + static const UINT8 FLAG_Z = 0x40; + static const UINT8 FLAG_S = 0x20; + static const UINT8 FLAG_V = 0x10; + static const UINT8 FLAG_D = 0x08; + static const UINT8 FLAG_H = 0x04; + static const UINT8 FLAG_B = 0x02; + static const UINT8 FLAG_I = 0x01; + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_execute_interface overrides + virtual UINT32 execute_min_cycles() const { return 1; } + virtual UINT32 execute_max_cycles() const { return 16; } + virtual UINT32 execute_input_lines() const { return 11; } + virtual void execute_run(); + virtual void execute_set_input(int inputnum, int state); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const { return (spacenum == AS_PROGRAM) ? &m_program_config : NULL; } + + // device_state_interface overrides + void state_string_export(const device_state_entry &entry, std::string &str); + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const { return 1; } + virtual UINT32 disasm_max_opcode_bytes() const { return 5; } + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + + inline void get_sp(); + UINT8 mem_readbyte(UINT32 offset); + void mem_writebyte(UINT32 offset, UINT8 data); + inline UINT16 mem_readword(UINT32 address) { return (mem_readbyte(address ) << 8) | (mem_readbyte(address+1)); } + inline void mem_writeword(UINT32 address, UINT16 value) { mem_writebyte(address, value >> 8); mem_writebyte(address+1, value); } + inline void take_interrupt(UINT16 vector); + void process_interrupts(); + + address_space_config m_program_config; + + devcb_write8 m_dma_func; + devcb_write8 m_timer_func; + + UINT16 m_PC; + UINT8 m_IE0; + UINT8 m_IE1; + UINT8 m_IR0; + UINT8 m_IR1; + UINT8 m_SYS; + UINT8 m_CKC; + UINT8 m_clock_changed; + UINT16 m_SP; + UINT8 m_PS0; + UINT8 m_PS1; + UINT16 m_IFLAGS; + UINT8 m_CheckInterrupts; + int m_halted; + int m_icount; + address_space *m_program; + UINT16 m_oldpc; + UINT8 m_register_ram[0x108]; +}; + + +extern const device_type SM8500; + + +#endif /* __SM8500_H__ */ diff --git a/src/devices/cpu/sm8500/sm8500d.c b/src/devices/cpu/sm8500/sm8500d.c new file mode 100644 index 00000000000..06b37795d54 --- /dev/null +++ b/src/devices/cpu/sm8500/sm8500d.c @@ -0,0 +1,583 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +/******************************************************************* + +sm8500d.c +Sharp sm8500 CPU disassembly + + + +*******************************************************************/ + +#include "emu.h" +#include "debugger.h" +#include "sm8500.h" + +enum e_mnemonics +{ + zADC=0, zADCW, zADD, zADDW, zAND, zANDW, zBAND, zBBC, zBBS, + zBCLR, zBCMP, zBMOV, zBOR, zBR, zBTST, zBSET, zBXOR, zCALL, zCALS, zCLR, + zCLRC, zCMP, zCMPW, zCOM, zCOMC, zDA, zDBNZ, zDEC, + zDECW, zDI, zDIV, zEI, zEXTS, zHALT, zINC, zINCW, + zIRET, zJMP, zMOV, zMOVM, zMOVW, zMULT, zNEG, zNOP, zOR, + zORW, zPOP, zPOPW, zPUSH, zPUSHW, zRET, zRL, zRLC, + zRR, zRRC, zSBC, zSBCW, zSETC, zSLL, zSRA, zSRL, zSTOP, + zSUB, zSUBW, zSWAP, zXOR, zXORW, zMOVPS0, zINVLD, zDM, +/* unknowns */ +z5A, z5B, + +/* more complicated instructions */ +z1A, z1B, z4F +}; + +/* instructions not found: +5A, 5B, +*/ + +static const char *const s_mnemonic[] = +{ + "adc", "adcw", "add", "addw", "and", "andw", "band", "bbc", "bbs", + "bclr", "bcmp", "bmov", "bor", "br", "btst", "bset", "bxor", "call", "cals", "clr", + "clrc", "cmp", "cmpw", "com", "comc", "da", "dbnz", "dec", + "decw", "di", "div", "ei", "exts", "halt", "inc", "incw", + "iret", "jmp", "mov", "movm", "movw", "mult", "neg", "nop", "or", + "orw", "pop", "popw", "push", "pushw", "ret", "rl", "rlc", + "rr", "rrc", "sbc", "sbcw", "setc", "sll", "sra", "srl", "stop", + "sub", "subw", "swap", "xor", "xorw", "mov PS0,", "invalid", "dm?", +/* unknowns */ +"unk5A", "unk5B", + +/* more complicated instructions */ +"comp1A", "comp1B", "comp4F", +}; + +#define _OVER DASMFLAG_STEP_OVER +#define _OUT DASMFLAG_STEP_OUT + +static const UINT32 s_flags[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, _OVER, _OVER, 0, + 0, 0, 0, 0, 0, 0, _OVER, 0, + 0, 0, 0, 0, 0, _OVER, 0, 0, + _OUT, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, _OUT, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, + 0, 0, 0 +}; + +struct sm8500dasm +{ + UINT8 mnemonic; + UINT8 arguments; +}; + +static const char *const sm8500_cond[16] = { + "F", "LT", "LE", "ULE", "OV", "MI", "Z", "C", + "T", "GE", "GT", "UGT", "NOV", "PL", "NZ", "NC" +}; + +static const UINT8 sm8500_b2w[8] = { + 0, 8, 2, 10, 4, 12, 6, 14 +}; + +enum e_addrmodes { + AM_R=1, AM_rr, AM_r1, AM_S, AM_rmb, AM_mbr, AM_Ri, AM_rmw, AM_mwr, AM_smw, AM_mws, + AM_Sw, AM_iR, AM_rbr, AM_riw, AM_cjp, AM_rib, AM_pi, AM_cbr, AM_i, AM_ii, + AM_ss, AM_RR, AM_2, AM_SS, AM_bR, AM_Rbr, AM_Rb, AM_rR, AM_Rr, AM_Rii, AM_RiR, + AM_riB, AM_iS, AM_CALS, AM_bid, AM_1A, AM_1B, AM_4F +}; + +static const sm8500dasm mnemonic[256] = { + /* 00 - 0F */ + {zCLR, AM_R}, {zNEG,AM_R}, {zCOM,AM_R}, {zRR,AM_R}, + {zRL, AM_R}, {zRRC,AM_R}, {zRLC,AM_R}, {zSRL,AM_R}, + {zINC, AM_R}, {zDEC,AM_R}, {zSRA,AM_R}, {zSLL,AM_R}, + {zDA, AM_R}, {zSWAP,AM_R}, {zPUSH,AM_R}, {zPOP,AM_R}, + /* 10 - 1F */ + {zCMP,AM_rr}, {zADD,AM_rr}, {zSUB,AM_rr}, {zADC,AM_rr}, + {zSBC,AM_rr}, {zAND,AM_rr}, {zOR,AM_rr}, {zXOR,AM_rr}, + {zINCW,AM_S}, {zDECW,AM_S}, {z1A,AM_1A}, {z1B,AM_1B}, + {zBCLR,AM_riB}, {zBSET,AM_riB}, {zPUSHW,AM_S}, {zPOPW,AM_S}, + /* 20 - 2F */ + {zCMP,AM_rmb}, {zADD,AM_rmb}, {zSUB,AM_rmb}, {zADC,AM_rmb}, + {zSBC,AM_rmb}, {zAND,AM_rmb}, {zOR,AM_rmb}, {zXOR,AM_rmb}, + {zMOV,AM_rmb}, {zMOV,AM_mbr}, {zBBC,AM_bid}, {zBBS,AM_bid}, + {zEXTS,AM_R}, {zDM,AM_i}, {zMOVPS0,AM_i}, {zBTST,AM_Ri}, + /* 30 - 3F */ + {zCMP,AM_rmw}, {zADD,AM_rmw}, {zSUB,AM_rmw}, {zADC,AM_rmw}, + {zSBC,AM_rmw}, {zAND,AM_rmw}, {zOR,AM_rmw}, {zXOR,AM_rmw}, + {zMOV,AM_rmw}, {zMOV,AM_mwr}, {zMOVW,AM_smw}, {zMOVW,AM_mws}, + {zMOVW,AM_ss}, {zDM,AM_R}, {zJMP,AM_2}, {zCALL,AM_2}, + /* 40 - 4F */ + {zCMP,AM_RR}, {zADD,AM_RR}, {zSUB,AM_RR}, {zADC,AM_RR}, + {zSBC,AM_RR}, {zAND,AM_RR}, {zOR,AM_RR}, {zXOR,AM_RR}, + {zMOV,AM_RR}, {zCALL,AM_ii}, {zMOVW,AM_SS}, {zMOVW,AM_Sw}, + {zMULT,AM_RR}, {zMULT,AM_iR}, {zBMOV,AM_bR}, {z4F,AM_4F}, + /* 50 - 5F */ + {zCMP,AM_iR}, {zADD,AM_iR}, {zSUB,AM_iR}, {zADC,AM_iR}, + {zSBC,AM_iR}, {zAND,AM_iR}, {zOR,AM_iR}, {zXOR,AM_iR}, + {zMOV, AM_iR}, {zINVLD,0}, {z5A,AM_ii}, {z5B,AM_ii}, + {zDIV,AM_SS}, {zDIV,AM_iS}, {zMOVM,AM_RiR}, {zMOVM,AM_Rii}, + /* 60 - 6F */ + {zCMPW,AM_SS}, {zADDW,AM_SS}, {zSUBW,AM_SS}, {zADCW,AM_SS}, + {zSBCW,AM_SS}, {zANDW,AM_SS}, {zORW,AM_SS}, {zXORW,AM_SS}, + {zCMPW,AM_Sw}, {zADDW,AM_Sw}, {zSUBW,AM_Sw}, {zADCW,AM_Sw}, + {zSBCW,AM_Sw}, {zANDW,AM_Sw}, {zORW,AM_Sw}, {zXORW,AM_Sw}, + /* 70 - 7F */ + {zDBNZ,AM_rbr}, {zDBNZ,AM_rbr}, {zDBNZ,AM_rbr}, {zDBNZ,AM_rbr}, + {zDBNZ,AM_rbr}, {zDBNZ,AM_rbr}, {zDBNZ,AM_rbr}, {zDBNZ,AM_rbr}, + {zMOVW,AM_riw}, {zMOVW,AM_riw}, {zMOVW,AM_riw}, {zMOVW,AM_riw}, + {zMOVW,AM_riw}, {zMOVW,AM_riw}, {zMOVW,AM_riw}, {zMOVW,AM_riw}, + /* 80 - 8F */ + {zBBC,AM_Rbr}, {zBBC,AM_Rbr}, {zBBC,AM_Rbr}, {zBBC,AM_Rbr}, + {zBBC,AM_Rbr}, {zBBC,AM_Rbr}, {zBBC,AM_Rbr}, {zBBC,AM_Rbr}, + {zBBS,AM_Rbr}, {zBBS,AM_Rbr}, {zBBS,AM_Rbr}, {zBBS,AM_Rbr}, + {zBBS,AM_Rbr}, {zBBS,AM_Rbr}, {zBBS,AM_Rbr}, {zBBS,AM_Rbr}, + /* 90 - 9F */ + {zJMP,AM_cjp}, {zJMP,AM_cjp}, {zJMP,AM_cjp}, {zJMP,AM_cjp}, + {zJMP,AM_cjp}, {zJMP,AM_cjp}, {zJMP,AM_cjp}, {zJMP,AM_cjp}, + {zJMP,AM_cjp}, {zJMP,AM_cjp}, {zJMP,AM_cjp}, {zJMP,AM_cjp}, + {zJMP,AM_cjp}, {zJMP,AM_cjp}, {zJMP,AM_cjp}, {zJMP,AM_cjp}, + /* A0 - AF */ + {zBCLR,AM_Rb}, {zBCLR,AM_Rb}, {zBCLR,AM_Rb}, {zBCLR,AM_Rb}, + {zBCLR,AM_Rb}, {zBCLR,AM_Rb}, {zBCLR,AM_Rb}, {zBCLR,AM_Rb}, + {zBSET,AM_Rb}, {zBSET,AM_Rb}, {zBSET,AM_Rb}, {zBSET,AM_Rb}, + {zBSET,AM_Rb}, {zBSET,AM_Rb}, {zBSET,AM_Rb}, {zBSET,AM_Rb}, + /* B0 - BF */ + {zMOV,AM_rR}, {zMOV,AM_rR}, {zMOV,AM_rR}, {zMOV,AM_rR}, + {zMOV,AM_rR}, {zMOV,AM_rR}, {zMOV,AM_rR}, {zMOV,AM_rR}, + {zMOV,AM_Rr}, {zMOV,AM_Rr}, {zMOV,AM_Rr}, {zMOV,AM_Rr}, + {zMOV,AM_Rr}, {zMOV,AM_Rr}, {zMOV,AM_Rr}, {zMOV,AM_Rr}, + /* C0 - CF */ + {zMOV,AM_rib}, {zMOV,AM_rib}, {zMOV,AM_rib}, {zMOV,AM_rib}, + {zMOV,AM_rib}, {zMOV,AM_rib}, {zMOV,AM_rib}, {zMOV,AM_rib}, + {zMOV,AM_pi}, {zMOV,AM_pi}, {zMOV,AM_pi}, {zMOV,AM_pi}, + {zMOV,AM_pi}, {zMOV,AM_pi}, {zMOV,AM_pi}, {zMOV,AM_pi}, + /* D0 - DF */ + {zBR,AM_cbr}, {zBR,AM_cbr}, {zBR,AM_cbr}, {zBR,AM_cbr}, + {zBR,AM_cbr}, {zBR,AM_cbr}, {zBR,AM_cbr}, {zBR,AM_cbr}, + {zBR,AM_cbr}, {zBR,AM_cbr}, {zBR,AM_cbr}, {zBR,AM_cbr}, + {zBR,AM_cbr}, {zBR,AM_cbr}, {zBR,AM_cbr}, {zBR,AM_cbr}, + /* E0 - EF */ + {zCALS,AM_CALS}, {zCALS,AM_CALS}, {zCALS,AM_CALS}, {zCALS,AM_CALS}, + {zCALS,AM_CALS}, {zCALS,AM_CALS}, {zCALS,AM_CALS}, {zCALS,AM_CALS}, + {zCALS,AM_CALS}, {zCALS,AM_CALS}, {zCALS,AM_CALS}, {zCALS,AM_CALS}, + {zCALS,AM_CALS}, {zCALS,AM_CALS}, {zCALS,AM_CALS}, {zCALS,AM_CALS}, + /* F0 - FF */ + {zSTOP,0}, {zHALT,0}, {zINVLD,0}, {zINVLD,0}, + {zINVLD,0}, {zINVLD,0}, {zINVLD,0}, {zINVLD,0}, + {zRET,0}, {zIRET,0}, {zCLRC,0}, {zCOMC,0}, + {zSETC,0}, {zEI,0}, {zDI,0}, {zNOP,0}, + +}; + +CPU_DISASSEMBLE( sm8500 ) +{ + const sm8500dasm *instr; + char *dst; + UINT8 op; + INT8 offset = 0; + UINT16 ea = 0, ea2 = 0; + int pos = 0; + + dst = buffer; + + op = oprom[pos++]; + + instr = &mnemonic[op]; + + if ( instr->arguments ) + { + if ( instr->arguments != AM_1A && instr->arguments != AM_1B && instr->arguments != AM_4F ) { + dst += sprintf( dst, "%-4s ", s_mnemonic[ instr->mnemonic ] ); + } + switch( instr->arguments ) { + case AM_R: + ea = oprom[pos++]; + dst += sprintf( dst, "R%02Xh", ea ); + break; + case AM_iR: + dst += sprintf( dst, "R%02Xh, $%02X", oprom[pos + 1], oprom[pos + 0]); + pos += 2; + break; + case AM_iS: + dst += sprintf( dst, "RR%02Xh, $%02X", oprom[pos + 1], oprom[pos + 0]); + pos += 2; + break; + case AM_Sw: + ea2 = oprom[pos++]; + ea = oprom[pos++] << 8; + ea += oprom[pos++]; + dst+= sprintf( dst, "RR%02Xh, $%04X", ea2, ea ); + break; + case AM_rib: + ea = oprom[pos++]; + dst += sprintf( dst, "r%02Xh, $%02X", op & 0x07, ea ); + break; + case AM_riw: + ea = oprom[pos++] << 8; + ea += oprom[pos++]; + dst += sprintf( dst, "rr%02Xh, $%04X", sm8500_b2w[op & 0x07], ea ); + break; + case AM_rmb: + ea = oprom[pos++]; + dst += sprintf( dst, "r%02Xh,", ( ea >> 3 ) & 0x07 ); + switch( ea & 0xC0 ) { + case 0x00: + dst += sprintf( dst, "@r%02Xh", ea & 0x07 ); break; + case 0x40: + dst += sprintf( dst, "(r%02Xh)+", ea & 0x07 ); break; + case 0x80: + ea2 = oprom[pos++]; + if ( ea & 0x07 ) { + dst += sprintf( dst, "$%02X(r%02Xh)", ea2, ea & 0x07 ); + } else { + dst += sprintf( dst, "@$%02X", ea2 ); + } + break; + case 0xC0: + dst += sprintf( dst, "-(r%02Xh)", ea & 0x07 ); break; + } + break; + case AM_mbr: + ea = oprom[pos++]; + switch( ea & 0xC0 ) { + case 0x00: + dst += sprintf( dst, "@r%02Xh", ea & 0x07 ); break; + case 0x40: + dst += sprintf( dst, "(r%02Xh)+", ea & 0x07 ); break; + case 0x80: + ea2 = oprom[pos++]; + if ( ea & 0x07 ) { + dst += sprintf( dst, "$%02X(r%02Xh)", ea2, ea & 0x07 ); + } else { + dst += sprintf( dst, "@$%02X", ea2 ); + } + break; + case 0xC0: + dst += sprintf( dst, "-(r%02Xh)", ea & 0x07 ); break; + } + dst += sprintf( dst, ",r%02Xh", ( ea >> 3 ) & 0x07 ); + break; + case AM_rmw: + ea = oprom[pos++]; + dst += sprintf( dst, "r%02Xh,", ( ea >> 3 ) & 0x07 ); + switch( ea & 0xC0 ) { + case 0x00: + dst += sprintf( dst, "@rr%02Xh", sm8500_b2w[ea & 0x07] ); break; + case 0x40: + dst += sprintf( dst, "(rr%02Xh)+", sm8500_b2w[ea & 0x07] ); break; + case 0x80: + ea2 = oprom[pos++] << 8; + ea2 += oprom[pos++]; + if ( ea & 0x07 ) { + dst += sprintf( dst, "$%04X(rr%02Xh)", ea2, sm8500_b2w[ea & 0x07] ); + } else { + dst += sprintf( dst, "@$%04X", ea2 ); + } + break; + case 0xC0: + dst += sprintf( dst, "-(rr%02Xh)", sm8500_b2w[ea & 0x07] ); break; + } + break; + case AM_mwr: + ea = oprom[pos++]; + switch( ea & 0xC0 ) { + case 0x00: + dst += sprintf( dst, "@rr%02Xh", sm8500_b2w[ea & 0x07] ); break; + case 0x40: + dst += sprintf( dst, "(rr%02Xh)+", sm8500_b2w[ea & 0x07] ); break; + case 0x80: + ea2 = oprom[pos++] << 8; + ea2 += oprom[pos++]; + if ( ea & 0x07 ) { + dst += sprintf( dst, "$%04X(rr%02Xh)", ea2, sm8500_b2w[ea & 0x07] ); + } else { + dst += sprintf( dst, "@$%04X", ea2 ); + } + break; + case 0xC0: + dst += sprintf( dst, "-(rr%02Xh)", sm8500_b2w[ea & 0x07] ); break; + } + dst += sprintf( dst, ",r%02Xh", ( ea >> 3 ) & 0x07 ); + break; + case AM_smw: + ea = oprom[pos++]; + dst += sprintf( dst, "rr%02Xh,", sm8500_b2w[( ea >> 3 ) & 0x07] ); + switch( ea & 0xC0 ) { + case 0x00: + dst += sprintf( dst, "@rr%02Xh", sm8500_b2w[ea & 0x07] ); break; + case 0x40: + dst += sprintf( dst, "(rr%02Xh)+", sm8500_b2w[ea & 0x07] ); break; + case 0x80: + ea2 = oprom[pos++] << 8; + ea2 += oprom[pos++]; + if ( ea & 0x07 ) { + dst += sprintf( dst, "$%04X(rr%02Xh)", ea2, sm8500_b2w[ea & 0x07] ); + } else { + dst += sprintf( dst, "@$%04X", ea2 ); + } + break; + case 0xC0: + dst += sprintf( dst, "-(rr%02Xh)", sm8500_b2w[ea & 0x07] ); break; + } + break; + case AM_mws: + ea = oprom[pos++]; + switch( ea & 0xC0 ) { + case 0x00: + dst += sprintf( dst, "@rr%02Xh", sm8500_b2w[ea & 0x07] ); break; + case 0x40: + dst += sprintf( dst, "(rr%02Xh)+", sm8500_b2w[ea & 0x07] ); break; + case 0x80: + ea2 = oprom[pos++] << 8; + ea2 += oprom[pos++]; + if ( ea & 0x07 ) { + dst += sprintf( dst, "$%04X(rr%02Xh)", ea2, sm8500_b2w[ea & 0x07] ); + } else { + dst += sprintf( dst, "@$%04X", ea2 ); + } + break; + case 0xC0: + dst += sprintf( dst, "-(rr%02Xh)", sm8500_b2w[ea & 0x07] ); break; + } + dst += sprintf( dst, ",rr%02Xh", sm8500_b2w[( ea >> 3 ) & 0x07] ); + break; + case AM_cbr: + offset = (INT8) oprom[pos++]; + dst += sprintf( dst, "%s,$%04X", sm8500_cond[ op & 0x0F ], pc + pos + offset ); + break; + case AM_rbr: + offset = (INT8) oprom[pos++]; + dst += sprintf( dst, "r%02Xh,$%04X", op & 0x07, pc + pos + offset ); + break; + case AM_cjp: + ea = oprom[pos++] << 8; + ea += oprom[pos++]; + dst += sprintf( dst, "%s,$%04X", sm8500_cond[ op & 0x0F], ea ); + break; + case AM_rr: + ea = oprom[pos++]; + switch( ea & 0xc0 ) { + case 0x00: + dst += sprintf( dst, "r%02Xh,r%02Xh", (ea >> 3 ) & 0x07, ea & 0x07 ); + break; + case 0x40: + case 0x80: + case 0xC0: + dst += sprintf( dst, "undef" ); + break; + } + break; + case AM_r1: + ea = oprom[pos++]; + switch( ea & 0xC0 ) { + case 0x00: + dst += sprintf( dst, "@r%02Xh", (ea >> 3 ) & 0x07 ); + break; + case 0x40: + case 0x80: + case 0xC0: + dst += sprintf( dst, "undef" ); + break; + } + break; + case AM_S: + ea = oprom[pos++]; + dst += sprintf( dst, "RR%02Xh", ea ); + break; + case AM_pi: + ea = oprom[pos++]; + dst += sprintf( dst, "r%02Xh, $%02X", 0x10 + (op & 0x07), ea ); + break; + case AM_Ri: + ea = oprom[pos++]; + ea2 = oprom[pos++]; + dst += sprintf( dst, "R%02Xh,$%02X", ea, ea2 ); + break; + case AM_i: + ea = oprom[pos++]; + dst += sprintf( dst, "$%02X", ea ); + break; + case AM_ii: + ea = oprom[pos++] << 8; + ea += oprom[pos++]; + dst += sprintf( dst, "$%04X", ea ); + break; + case AM_ss: + ea = oprom[pos++]; + switch( ea & 0xC0 ) { + case 0x00: + dst += sprintf( dst, "rr%02Xh,rr%02Xh", sm8500_b2w[( ea >> 3 ) & 0x07], sm8500_b2w[ea & 0x07] ); break; + case 0x40: + dst += sprintf( dst, "undef" ); break; + case 0x80: + dst += sprintf( dst, "undef" ); break; + case 0xC0: + dst += sprintf( dst, "undef" ); break; + } + break; + case AM_RR: + ea = oprom[pos++]; + ea2 = oprom[pos++]; + dst += sprintf( dst, "R%02Xh,R%02Xh", ea2, ea ); + break; + case AM_2: + ea = oprom[pos++]; + switch( ea & 0xC0 ) { + case 0x00: + dst += sprintf( dst, "rr%02Xh", sm8500_b2w[ea & 0x07] ); break; + case 0x40: + ea2 = oprom[pos++] << 8; + ea2 += oprom[pos++]; + if ( ea & 0x38 ) { + dst += sprintf( dst, "@$%04X(r%02Xh)", ea2, ( ea >> 3 ) & 0x07 ); + } else { + dst += sprintf( dst, "@$%04X", ea2 ); + } + break; + case 0x80: + dst += sprintf( dst, "undef" ); break; + case 0xC0: + dst += sprintf( dst, "undef" ); break; + } + break; + case AM_SS: + ea = oprom[pos++]; + ea2 = oprom[pos++]; + dst += sprintf( dst, "RR%02Xh,RR%02Xh", ea2, ea ); + break; + case AM_bR: + ea = oprom[pos++]; + ea2 = oprom[pos++]; + switch( ea & 0xC0 ) { + case 0x00: + dst += sprintf( dst, "BF,R%02Xh,#%d", ea2, ea & 0x07 ); break; + case 0x40: + dst += sprintf( dst, "R%02Xh,#%d,BF", ea2, ea & 0x07 ); break; + case 0x80: + dst += sprintf( dst, "undef" ); break; + case 0xC0: + dst += sprintf( dst, "undef" ); break; + } + break; + case AM_Rbr: + ea = oprom[pos++]; + offset = (INT8) oprom[pos++]; + dst += sprintf( dst, "R%02Xh,#%d,$%04X", ea, op & 0x07, pc + pos + offset ); + break; + case AM_Rb: + ea = oprom[pos++]; + dst += sprintf( dst, "R%02Xh,#%d", ea, op&0x07 ); + break; + case AM_rR: + ea = oprom[pos++]; + dst += sprintf( dst, "r%02Xh,R%02Xh", op & 0x07, ea ); + break; + case AM_Rr: + ea = oprom[pos++]; + dst += sprintf( dst, "R%02Xh,r%02Xh", ea, op & 0x07 ); + break; + case AM_Rii: + ea = oprom[pos++]; + dst += sprintf( dst, "R%02Xh,", ea ); + ea = oprom[pos++]; + dst += sprintf( dst, "$%02X,", ea ); + ea = oprom[pos++]; + dst += sprintf( dst, "$%02X", ea ); + break; + case AM_RiR: + ea = oprom[pos++]; + dst += sprintf( dst, "R%02Xh,", ea ); + ea = oprom[pos++]; + dst += sprintf( dst, "$%02X,", ea ); + ea = oprom[pos++]; + dst += sprintf( dst, "R%02Xh", ea ); + break; + case AM_riB: + ea = oprom[pos++]; + ea2 = oprom[pos++]; + switch( ea & 0xC0 ) { + case 0x00: + dst += sprintf( dst, "#%2x(r%02Xh),#%d", ea2, ea >> 3, ea & 0x07 ); + break; + case 0x40: + dst += sprintf( dst, "undef" ); break; + case 0x80: + dst += sprintf( dst, "undef" ); break; + case 0xC0: + dst += sprintf( dst, "undef" ); break; + } + break; + case AM_CALS: + ea = oprom[pos++]; + dst += sprintf( dst, "$%04X", 0x1000 | ( ( op & 0x0f ) << 8 ) | ea ); + break; + case AM_bid: + ea = oprom[pos++]; + ea2 = oprom[pos++]; + if ( ea & 0x38 ) { + dst += sprintf( dst, "$%02X(r%02Xh)", ea2, ( ea >> 3 ) & 0x07 ); + } else { + dst += sprintf( dst, "$%04X", 0xFF00 + ea2 ); + } + dst += sprintf( dst, ",#%d,", ea & 0x07 ); + offset = (INT8) oprom[pos++]; + dst += sprintf( dst, "$%04X", pc + pos + offset ); + break; + case AM_1A: + ea = oprom[pos++]; + switch( ea & 0x07 ) { + case 0x00: dst += sprintf( dst, "%-4s ", s_mnemonic[ zCLR ] ); break; + case 0x01: dst += sprintf( dst, "%-4s ", s_mnemonic[ zNEG ] ); break; + case 0x02: dst += sprintf( dst, "%-4s ", s_mnemonic[ zCOM ] ); break; + case 0x03: dst += sprintf( dst, "%-4s ", s_mnemonic[ zRR ] ); break; + case 0x04: dst += sprintf( dst, "%-4s ", s_mnemonic[ zRL ] ); break; + case 0x05: dst += sprintf( dst, "%-4s ", s_mnemonic[ zRRC ] ); break; + case 0x06: dst += sprintf( dst, "%-4s ", s_mnemonic[ zRLC ] ); break; + case 0x07: dst += sprintf( dst, "%-4s ", s_mnemonic[ zSRL ] ); break; + } + dst += sprintf( dst, "@r%02Xh", ( ea >> 3 ) & 0x07 ); + break; + case AM_1B: + ea = oprom[pos++]; + switch( ea & 0x07 ) { + case 0x00: dst += sprintf( dst, "%-4s ", s_mnemonic[ zINC ] ); break; + case 0x01: dst += sprintf( dst, "%-4s ", s_mnemonic[ zDEC ] ); break; + case 0x02: dst += sprintf( dst, "%-4s ", s_mnemonic[ zSRA ] ); break; + case 0x03: dst += sprintf( dst, "%-4s ", s_mnemonic[ zSLL ] ); break; + case 0x04: dst += sprintf( dst, "%-4s ", s_mnemonic[ zDA ] ); break; + case 0x05: dst += sprintf( dst, "%-4s ", s_mnemonic[ zSWAP ] ); break; + case 0x06: dst += sprintf( dst, "%-4s ", s_mnemonic[ zPUSH ] ); break; + case 0x07: dst += sprintf( dst, "%-4s ", s_mnemonic[ zPOP ] ); break; + } + dst += sprintf( dst, "@r%02Xh", ( ea >> 3 ) & 0x07 ); + break; + case AM_4F: + ea = oprom[pos++]; + ea2 = oprom[pos++]; + switch( ea & 0xc0 ) { + case 0x00: dst += sprintf( dst, "%-4s ", s_mnemonic[ zBCMP ] ); break; + case 0x40: dst += sprintf( dst, "%-4s ", s_mnemonic[ zBAND ] ); break; + case 0x80: dst += sprintf( dst, "%-4s ", s_mnemonic[ zBOR ] ); break; + case 0xC0: dst += sprintf( dst, "%-4s ", s_mnemonic[ zBXOR ] ); break; + } + if ( ! ( ea & 0x80 ) ) { + dst += sprintf( dst, "BF," ); + } + dst += sprintf( dst, "R%02Xh,$%02X", ea2, ea & 0x07 ); + if ( ea & 0x80 ) { + dst += sprintf( dst, ",BF" ); + } + break; + } + } + else + { + dst += sprintf( dst, "%s", s_mnemonic[ instr->mnemonic ] ); + } + + return pos | s_flags[instr->mnemonic] | DASMFLAG_SUPPORTED; +} diff --git a/src/devices/cpu/sm8500/sm85ops.h b/src/devices/cpu/sm8500/sm85ops.h new file mode 100644 index 00000000000..dacfa02482d --- /dev/null +++ b/src/devices/cpu/sm8500/sm85ops.h @@ -0,0 +1,1691 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol + +#define ARG_R r1 = mem_readbyte( m_PC++ ); + +#define ARG_RR r2 = mem_readbyte( m_PC++ ); \ + r1 = mem_readbyte( m_PC++ ); + +#define ARG_rR r1 = op & 0x07; \ + r2 = mem_readbyte( m_PC++ ); + +#define ARG_iR r2 = mem_readbyte( m_PC++ ); \ + r1 = mem_readbyte( m_PC++ ); + +#define ARG_Sw r1 = mem_readbyte( m_PC++ ); \ + s2 = mem_readword( m_PC ); m_PC += 2; + +#define ARG_rrw r1 = sm8500_b2w[op & 0x07]; \ + s2 = mem_readword( m_PC ); m_PC += 2; + +#define ARG_ri r1 = op & 0x07; \ + r2 = mem_readbyte( m_PC++ ); + +#define ARG_pi r1 = 0x10 + ( op & 0x07 ); \ + r2 = mem_readbyte( m_PC++ ); + +#define ARG_rmb r1 = mem_readbyte( m_PC++ ); \ + s2 = 0; \ + switch( r1 & 0xC0 ) { \ + case 0x00: \ + s2 = mem_readbyte( r1 & 0x07 ); \ + break; \ + case 0x40: \ + s2 = mem_readbyte( r1 & 0x07 ); \ + mem_writebyte( r1 & 0x07, s2 + 1 ); \ + break; \ + case 0x80: \ + s2 = mem_readbyte( m_PC++ ); \ + if ( r1 & 0x07 ) { \ + s2 = s2 + mem_readbyte( r1 & 0x07 ); \ + } \ + break; \ + case 0xC0: \ + s2 = mem_readbyte( r1 & 0x07 ); \ + mem_writebyte( r1 & 0x07, s2 - 1 ); \ + break; \ + } \ + r2 = r1; \ + r1 = ( r1 >> 3 ) & 0x07; + +#define ARG_rmw r1 = mem_readbyte( m_PC++ ); \ + s2 = 0; \ + switch( r1 & 0xC0 ) { \ + case 0x00: \ + s2 = mem_readword( sm8500_b2w[r1 & 0x07] ); \ + break; \ + case 0x40: \ + s2 = mem_readword( sm8500_b2w[r1 & 0x07] ); \ + mem_writeword( sm8500_b2w[r1 & 0x07], s2 + 1 ); \ + break; \ + case 0x80: \ + s2 = mem_readword( m_PC ); m_PC += 2; \ + if ( r1 & 0x07 ) { \ + s2 = s2 + mem_readword( sm8500_b2w[r1 & 0x07] ); \ + } \ + break; \ + case 0xC0: \ + s2 = mem_readword( sm8500_b2w[r1 & 0x07])-1; \ + mem_writeword( sm8500_b2w[r1 & 0x07], s2 ); \ + break; \ + } \ + r2 = r1; \ + r1 = ( r1 >> 3 ) & 0x07; + +#define ARG_smw r1 = mem_readbyte( m_PC++ ); \ + s2 = 0; \ + switch( r1 & 0xC0 ) { \ + case 0x00: \ + s2 = mem_readword( sm8500_b2w[r1 & 0x07] ); \ + break; \ + case 0x40: \ + s2 = mem_readword( sm8500_b2w[r1 & 0x07] ); \ + mem_writeword( sm8500_b2w[r1 & 0x07], s2 + 1 ); \ + break; \ + case 0x80: \ + s2 = mem_readword( m_PC ); m_PC += 2; \ + if ( r1 & 0x07 ) { \ + s2 = s2 + mem_readword( sm8500_b2w[r1 & 0x07] ); \ + } \ + break; \ + case 0xC0: \ + s2 = mem_readword( sm8500_b2w[ r1 & 0x07] ); \ + mem_writeword( sm8500_b2w[r1 & 0x07], s2 - 1 ); \ + break; \ + } \ + r2 = r1; \ + r1 = sm8500_b2w[ ( r1 >> 3 ) & 0x07 ]; + +#define ARG_d8 r1 = mem_readbyte( m_PC++ ); \ + s2 = m_PC + ((INT8)r1); + +#define ARG_Rbr r1 = mem_readbyte( m_PC++ ); \ + r2 = mem_readbyte( m_PC++ ); \ + s2 = m_PC + ((INT8)r2); + +#define ARG_ad16 s2 = mem_readword( m_PC ); \ + m_PC += 2; + +#define ARG_rr r1 = mem_readbyte( m_PC++ ); \ + r2 = 0x00; \ + switch( r1 & 0xC0 ) { \ + case 0x00: \ + r2 = r1 & 0x07; \ + r1 = ( r1 >> 3 ) & 0x07; \ + break; \ + case 0x40: \ + case 0x80: \ + case 0xC0: \ + break; \ + } + +#define ARG_ss r1 = mem_readbyte( m_PC++ ); \ + r2 = 0x00; \ + switch( r1 & 0xC0 ) { \ + case 0x00: \ + r2 = sm8500_b2w[r1 & 0x07]; \ + r1 = sm8500_b2w[( r1 >> 3 ) & 0x07]; \ + break; \ + case 0x40: \ + case 0x80: \ + case 0xC0: \ + break; \ + } + +#define ARG_2 r1 = mem_readbyte( m_PC++ ); \ + s2 = 0; \ + switch( r1 & 0xC0 ) { \ + case 0x00: \ + s2 = mem_readword( sm8500_b2w[ r1 & 0x07 ] ); \ + break; \ + case 0x40: \ + s2 = mem_readword( m_PC ); m_PC += 2; \ + if ( r1 & 0x38 ) { \ + s2 = s2 + mem_readbyte( ( r1 >> 3 ) & 0x07 ); \ + } \ + s2 = mem_readword( s2 ); \ + case 0x80: \ + case 0xC0: \ + break; \ + } + +#define ARG_RiR r1 = mem_readbyte( m_PC++ ); \ + d1 = mem_readbyte( m_PC++ ); \ + r2 = mem_readbyte( m_PC++ ); + +#define ARG_Rii r1 = mem_readbyte( m_PC++ ); \ + d1 = mem_readbyte( m_PC++ ); \ + r2 = mem_readbyte( m_PC++ ); + +#define ARG_riB r1 = mem_readbyte( m_PC++ ); \ + s2 = 1 << ( r1 & 0x07 ); \ + d1 = mem_readbyte( m_PC++ ); \ + if ( r1 & 0x38 ) { \ + s1 = d1 + mem_readbyte( ( r1 >> 3 ) & 0x07 ); \ + } else { \ + s1 = 0xFF00 + d1; \ + } + +#define ARG_riBd r1 = mem_readbyte( m_PC++ ); \ + s2 = 1 << ( r1 & 0x07 ); \ + d1 = mem_readbyte( m_PC++ ); \ + if ( r1 & 0x38 ) { \ + s1 = d1 + mem_readbyte( ( r1 >> 3 ) & 0x07 ); \ + } else { \ + s1 = 0xFF00 + d1; \ + } \ + d1 = mem_readbyte( m_PC++ ); + +#define OP_INTSUB8(X,Y,MASK) d1 = X; \ + d2 = Y; \ + res = d1 - d2; \ + m_PS1 = m_PS1 & ( MASK ); \ + m_PS1 = m_PS1 | ( ( res > 0xFF ) ? FLAG_C : 0 ); \ + m_PS1 = m_PS1 | ( ( ( res & 0xFF ) == 0 ) ? FLAG_Z : 0 ); \ + m_PS1 = m_PS1 | ( ( res & 0x80 ) ? FLAG_S : 0 ); \ + m_PS1 = m_PS1 | ( ( ( ( d2 ^ d1 ) & ( res ^ d1 ) ) & 0x80 ) ? FLAG_V : 0 ); + +#define OP_CMP8(X,Y) OP_INTSUB8( X, Y, (FLAG_B | FLAG_I | FLAG_H | FLAG_D ) ); + +#define OP_SUB8(X,Y) OP_INTSUB8( X, Y, (FLAG_B | FLAG_I ) ); \ + m_PS1 = m_PS1 | FLAG_D; \ + m_PS1 = m_PS1 | ( ( ( d1 ^ d2 ^ res ) & 0x10 ) ? FLAG_H : 0 ); + +#define OP_INTSUB16(X,Y,MASK) d1 = X; \ + d2 = Y; \ + res = d1 - d2; \ + m_PS1 = m_PS1 & ( MASK ); \ + m_PS1 = m_PS1 | ( ( res > 0xFFFF ) ? FLAG_C : 0 ); \ + m_PS1 = m_PS1 | ( ( ( res & 0xFFFF ) == 0 ) ? FLAG_Z : 0 ); \ + m_PS1 = m_PS1 | ( ( res & 0x8000 ) ? FLAG_S : 0 ); \ + m_PS1 = m_PS1 | ( ( ( ( d2 ^ d1 ) & (res ^ d1) ) & 0x8000 ) ? FLAG_V : 0 ); + +#define OP_CMP16(X,Y) OP_INTSUB16( X, Y, ( FLAG_B | FLAG_I | FLAG_H | FLAG_D ) ); + +#define OP_SUB16(X,Y) OP_INTSUB16( X, Y, ( FLAG_B | FLAG_I ) ); \ + m_PS1 = m_PS1 | FLAG_D; \ + m_PS1 = m_PS1 | ( ( ( d1 ^ d2 ^ res ) & 0x0010 ) ? FLAG_H : 0 ); + +#define OP_SBC8(X,Y) d1 = X; \ + d2 = Y; \ + res = d1 - d2 - ((m_PS1 & FLAG_C) ? 1 : 0); \ + m_PS1 = m_PS1 & ( FLAG_B | FLAG_I ); \ + m_PS1 = m_PS1 | ( ( res > 0xFF ) ? FLAG_C : 0 ); \ + m_PS1 = m_PS1 | ( ( ( res & 0xFF ) == 0 ) ? FLAG_Z : 0 ); \ + m_PS1 = m_PS1 | ( ( res & 0x80 ) ? FLAG_S : 0); \ + m_PS1 = m_PS1 | ( ( ( ( d2 ^ d1 ) & (res ^ d1) ) & 0x80 ) ? FLAG_V : 0 ); \ + m_PS1 = m_PS1 | FLAG_D; \ + m_PS1 = m_PS1 | ( ( ( d1 ^ d2 ^ res ) & 0x10 ) ? FLAG_H : 0 ); + +#define OP_SBC16(X,Y) d1 = X; \ + d2 = Y; \ + res = d1 - d2 - ((m_PS1 & FLAG_C) ? 1 : 0); \ + m_PS1 = m_PS1 & ( FLAG_B | FLAG_I ); \ + m_PS1 = m_PS1 | ( ( res > 0xFFFF ) ? FLAG_C : 0 ); \ + m_PS1 = m_PS1 | ( ( ( res & 0xFFFF ) == 0 ) ? FLAG_Z : 0 ); \ + m_PS1 = m_PS1 | ( ( res & 0x8000 ) ? FLAG_S : 0 ); \ + m_PS1 = m_PS1 | ( ( ( ( d2 ^ d1 ) & ( res ^ d1 ) ) & 0x8000 ) ? FLAG_V : 0 ); \ + m_PS1 = m_PS1 | FLAG_D; \ + m_PS1 = m_PS1 | ( ( ( d1 ^ d2 ^ res ) & 0x10 ) ? FLAG_H : 0 ); + +#define OP_ADD8(X,Y) d1 = X; \ + d2 = Y; \ + res = d1 + d2; \ + m_PS1 = m_PS1 & ( FLAG_B | FLAG_I ); \ + m_PS1 = m_PS1 | ( ( res > 0xFF ) ? FLAG_C : 0 ); \ + m_PS1 = m_PS1 | ( ( ( res & 0xFF ) == 0 ) ? FLAG_Z : 0 ); \ + m_PS1 = m_PS1 | ( ( res & 0x80 ) ? FLAG_S : 0); \ + m_PS1 = m_PS1 | ( ( ( ( d2 ^ d1 ^ 0x80 ) & (res ^ d1) ) & 0x80 ) ? FLAG_V : 0 ); \ + m_PS1 = m_PS1 | ( ( ( d1 ^ d2 ^ res ) & 0x10 ) ? FLAG_H : 0 ); + +#define OP_ADD16(X,Y) d1 = X; \ + d2 = Y; \ + res = d1 + d2; \ + m_PS1 = m_PS1 & ( FLAG_B | FLAG_I ); \ + m_PS1 = m_PS1 | ( ( res > 0xFFFF ) ? FLAG_C : 0 ); \ + m_PS1 = m_PS1 | ( ( ( res & 0xFFFF ) == 0 ) ? FLAG_Z : 0 ); \ + m_PS1 = m_PS1 | ( ( res & 0x8000 ) ? FLAG_S : 0 ); \ + m_PS1 = m_PS1 | ( ( ( ( d2 ^ d1 ) & ( res ^ d1 ) ) & 0x8000 ) ? FLAG_V : 0 ); \ + m_PS1 = m_PS1 | ( ( ( d2 ^ d1 ^ res ) & 0x0010 ) ? FLAG_H : 0 ); + +#define OP_ADC8(X,Y) d1 = X; \ + d2 = Y; \ + res = d1 + d2 + ((m_PS1 & FLAG_C) ? 1 : 0); \ + m_PS1 = m_PS1 & ( FLAG_B | FLAG_I ); \ + m_PS1 = m_PS1 | ( ( res > 0xFF ) ? FLAG_C : 0 ); \ + m_PS1 = m_PS1 | ( ( ( res & 0xFF ) == 0 ) ? FLAG_Z : 0 ); \ + m_PS1 = m_PS1 | ( ( res & 0x80 ) ? FLAG_S : 0); \ + m_PS1 = m_PS1 | ( ( ( ( d2 ^ d1 ) & (res ^ d1) ) & 0x80 ) ? FLAG_V : 0 ); \ + m_PS1 = m_PS1 | ( ( ( d1 ^ d2 ^ res ) & 0x10 ) ? FLAG_H : 0 ); + +#define OP_ADC16(X,Y) d1 = X; \ + d2 = Y; \ + res = d1 + d2 + ((m_PS1 & FLAG_C) ? 1 : 0); \ + m_PS1 = m_PS1 & ( FLAG_B | FLAG_I ); \ + m_PS1 = m_PS1 | ( ( res > 0xFFFF ) ? FLAG_C : 0 ); \ + m_PS1 = m_PS1 | ( ( ( res & 0xFFFF ) == 0 ) ? FLAG_Z : 0 ); \ + m_PS1 = m_PS1 | ( ( res & 0x8000 ) ? FLAG_S : 0 ); \ + m_PS1 = m_PS1 | ( ( ( ( d2 ^ d1 ) & ( res ^ d1) ) & 0x8000 ) ? FLAG_V : 0 ); \ + m_PS1 = m_PS1 | ( ( ( d1 ^ d2 ^ res ) & 0x10 ) ? FLAG_H : 0 ); + +#define OP_NEG8(X) res = -X; \ + m_PS1 = m_PS1 & ( FLAG_D | FLAG_H | FLAG_B | FLAG_I ); \ + m_PS1 = m_PS1 | ( ( ( res & 0xFF ) == 0 ) ? FLAG_C | FLAG_Z : 0 ); \ + m_PS1 = m_PS1 | ( ( res & 0x80 ) ? FLAG_S : 0 ); \ + m_PS1 = m_PS1 | ( ( ( res & 0xFF ) == 0x80 ) ? FLAG_V : 0 ); + +#define OP_COM8(X) res = ~X; \ + m_PS1 = m_PS1 & ( FLAG_C | FLAG_D | FLAG_H | FLAG_B | FLAG_I ); \ + m_PS1 = m_PS1 | ( ( ( res & 0xFF ) == 0 ) ? FLAG_Z : 0 ); \ + m_PS1 = m_PS1 | ( ( res & 0x80 ) ? FLAG_S : 0 ); + +#define OP_RR8(X) d1 = X; \ + res = d1 >> 1; \ + if ( d1 & 0x01 ) { \ + res |= 0x80; \ + } \ + m_PS1 = m_PS1 & ( FLAG_D | FLAG_H | FLAG_B | FLAG_I ); \ + m_PS1 = m_PS1 | ( ( d1 & 0x01 ) ? FLAG_C : 0 ); \ + m_PS1 = m_PS1 | ( ( ( res & 0xFF ) == 0 ) ? FLAG_Z : 0 ); \ + m_PS1 = m_PS1 | ( ( res & 0x80 ) ? FLAG_S : 0 ); \ + m_PS1 = m_PS1 | ( ( ( ( d1 ^ res ) & 0x80 ) && ! ( res & 0x80 ) ) ? FLAG_V : 0 ); + +#define OP_RL8(X) d1 = X; \ + res = d1 << 1; \ + if ( d1 & 0x80 ) { \ + res |= 0x01; \ + } \ + m_PS1 = m_PS1 & ( FLAG_D | FLAG_H | FLAG_B | FLAG_I ); \ + m_PS1 = m_PS1 | ( ( d1 & 0x80 ) ? FLAG_C : 0 ); \ + m_PS1 = m_PS1 | ( ( ( res & 0xFF ) == 0 ) ? FLAG_Z : 0 ); \ + m_PS1 = m_PS1 | ( ( res & 0x80 ) ? FLAG_S : 0 ); \ + m_PS1 = m_PS1 | ( ( ( d1 ^ res ) & 0x80 ) ? FLAG_V : 0 ); + +#define OP_RRC8(X) d1 = X; \ + res = d1 >> 1; \ + if ( m_PS1 & FLAG_C ) { \ + res |= 0x80; \ + } \ + m_PS1 = m_PS1 & ( FLAG_D | FLAG_H | FLAG_B | FLAG_I ); \ + m_PS1 = m_PS1 | ( ( d1 & 0x01 ) ? FLAG_C : 0 ); \ + m_PS1 = m_PS1 | ( ( ( res & 0xFF ) == 0 ) ? FLAG_Z : 0 ); \ + m_PS1 = m_PS1 | ( ( res & 0x80 ) ? FLAG_S : 0 ); \ + m_PS1 = m_PS1 | ( ( ( ( d1 ^ res ) & 0x80 ) && ! ( res & 0x80 ) ) ? FLAG_V : 0 ); + +#define OP_RLC8(X) d1 = X; \ + res = d1 << 1; \ + if ( m_PS1 & FLAG_C ) { \ + res |= 0x01; \ + } \ + m_PS1 = m_PS1 & ( FLAG_D | FLAG_H | FLAG_B | FLAG_I ); \ + m_PS1 = m_PS1 | ( ( d1 & 0x80 ) ? FLAG_C : 0 ); \ + m_PS1 = m_PS1 | ( ( ( res & 0xFF ) == 0 ) ? FLAG_Z : 0 ); \ + m_PS1 = m_PS1 | ( ( res & 0x80 ) ? FLAG_S : 0 ); \ + m_PS1 = m_PS1 | ( ( ( d1 ^ res ) & 0x80 ) ? FLAG_V : 0 ); + +#define OP_SRL8(X) d1 = X; \ + res = d1 >> 1; \ + m_PS1 = m_PS1 & ( FLAG_D | FLAG_H | FLAG_B | FLAG_I ); \ + m_PS1 = m_PS1 | ( ( d1 & 0x01 ) ? FLAG_C : 0 ); \ + m_PS1 = m_PS1 | ( ( ( res & 0xFF ) == 0 ) ? FLAG_Z : 0 ); + +#define OP_SRA8(X) d1 = X; \ + res = d1 >> 1; \ + if ( d1 & 0x80 ) { \ + res |= 0x80; \ + } \ + m_PS1 = m_PS1 & ( FLAG_D | FLAG_H | FLAG_B | FLAG_I ); \ + m_PS1 = m_PS1 | ( ( d1 & 0x01 ) ? FLAG_C : 0 ); \ + m_PS1 = m_PS1 | ( ( ( res & 0xFF ) == 0 ) ? FLAG_Z : 0 ); \ + m_PS1 = m_PS1 | ( ( res & 0x80 ) ? FLAG_S : 0 ); + +#define OP_SLL8(X) d1 = X; \ + res = d1 << 1; \ + m_PS1 = m_PS1 & ( FLAG_D | FLAG_H | FLAG_B | FLAG_I ); \ + m_PS1 = m_PS1 | ( ( d1 & 0x80 ) ? FLAG_C : 0 ); \ + m_PS1 = m_PS1 | ( ( ( res & 0xFF ) == 0 ) ? FLAG_Z : 0 ); \ + m_PS1 = m_PS1 | ( ( res & 0x80 ) ? FLAG_S : 0 ); + +#define OP_INC8(X) d1 = X; \ + res = d1 + 1; \ + m_PS1 = m_PS1 & ( FLAG_C | FLAG_D | FLAG_H | FLAG_B | FLAG_I ); \ + m_PS1 = m_PS1 | ( ( ( res & 0xFF ) == 0 ) ? FLAG_Z : 0 ); \ + m_PS1 = m_PS1 | ( ( res & 0x80 ) ? FLAG_S : 0 ); \ + m_PS1 = m_PS1 | ( ( ( ( d1 ^ res ) & 0x80 ) && ! ( res & 0x80 ) ) ? FLAG_V : 0 ); + +#define OP_INC16(X) d1 = X; \ + res = d1 + 1; \ + m_PS1 = m_PS1 & ( FLAG_C | FLAG_D | FLAG_H | FLAG_B | FLAG_I ); \ + m_PS1 = m_PS1 | ( ( ( res & 0xFF ) == 0 ) ? FLAG_Z : 0 ); \ + m_PS1 = m_PS1 | ( ( res & 0x8000 ) ? FLAG_S : 0 ); \ + m_PS1 = m_PS1 | ( ( ( ( d1 ^ res ) & 0x8000 ) && ! ( res & 0x8000 ) ) ? FLAG_V : 0 ); + +#define OP_DEC8(X) d1 = X; \ + res = d1 - 1; \ + m_PS1 = m_PS1 & ( FLAG_C | FLAG_D | FLAG_H | FLAG_B | FLAG_I ); \ + m_PS1 = m_PS1 | ( ( ( res & 0xFF ) == 0 ) ? FLAG_Z : 0 ); \ + m_PS1 = m_PS1 | ( ( res & 0x80 ) ? FLAG_S : 0 ); \ + m_PS1 = m_PS1 | ( ( ( ( d1 ^ res ) & 0x80 ) && ( res & 0x80 ) ) ? FLAG_V : 0 ); + +#define OP_DEC16(X) d1 = X; \ + res = d1 - 1; \ + m_PS1 = m_PS1 & ( FLAG_C | FLAG_D | FLAG_H | FLAG_B | FLAG_I ); \ + m_PS1 = m_PS1 | ( ( ( res & 0xFFFF ) == 0 ) ? FLAG_Z : 0 ); \ + m_PS1 = m_PS1 | ( ( res & 0x8000 ) ? FLAG_S : 0 ); \ + m_PS1 = m_PS1 | ( ( ( ( d1 ^ res ) & 0x8000 ) && ( res & 0x8000 ) ) ? FLAG_V : 0 ); + +#define OP_AND8(X,Y) d1 = X; \ + d2 = Y; \ + res = d1 & d2; \ + m_PS1 = m_PS1 & ( FLAG_B | FLAG_I | FLAG_H | FLAG_D ); \ + m_PS1 = m_PS1 | ( ( ( res & 0xFF ) == 0 ) ? FLAG_Z : 0 ); \ + m_PS1 = m_PS1 | ( ( res & 0x80 ) ? FLAG_S : 0 ); + +#define OP_AND16(X,Y) d1 = X; \ + d2 = Y; \ + res = d1 & d2; \ + m_PS1 = m_PS1 & ( FLAG_C | FLAG_S | FLAG_B | FLAG_I | FLAG_H | FLAG_D ); \ + m_PS1 = m_PS1 | ( ( ( res & 0xFFFF ) == 0 ) ? FLAG_Z : 0 ); + +#define OP_OR8(X,Y) d1 = X; \ + d2 = Y; \ + res = d1 | d2; \ + m_PS1 = m_PS1 & ( FLAG_B | FLAG_I | FLAG_H | FLAG_D ); \ + m_PS1 = m_PS1 | ( ( ( res & 0xFF ) == 0 ) ? FLAG_Z : 0 ); \ + m_PS1 = m_PS1 | ( ( res & 0x80 ) ? FLAG_S : 0 ); + +#define OP_OR16(X,Y) d1 = X; \ + d2 = Y; \ + res = d1 | d2; \ + m_PS1 = m_PS1 & ( FLAG_B | FLAG_I | FLAG_H | FLAG_D | FLAG_C | FLAG_S ); \ + m_PS1 = m_PS1 | ( ( ( res & 0xFFFF ) == 0 ) ? FLAG_Z : 0 ); + +#define OP_XOR8(X,Y) d1 = X; \ + d2 = Y; \ + res = d1 ^ d2; \ + m_PS1 = m_PS1 & ( FLAG_B | FLAG_I | FLAG_H | FLAG_D ); \ + m_PS1 = m_PS1 | ( ( ( res & 0xFF ) == 0 ) ? FLAG_Z : 0 ); \ + m_PS1 = m_PS1 | ( ( res & 0x80 ) ? FLAG_S : 0 ); + +#define OP_XOR16(X,Y) d1 = X; \ + d2 = Y; \ + res = d1 ^ d2; \ + m_PS1 = m_PS1 & ( FLAG_B | FLAG_I | FLAG_H | FLAG_D | FLAG_C | FLAG_S ); \ + m_PS1 = m_PS1 | ( ( ( res & 0xFFFF ) == 0 ) ? FLAG_Z : 0 ); + +#define OP_DA8(X) d1 = X; \ + res = d1; \ + if ( m_PS1 & FLAG_D ) { \ + if ( m_PS1 & FLAG_C ) { \ + if ( m_PS1 & FLAG_H ) { \ + res += 0x9A; \ + } else { \ + res += 0xA0; \ + } \ + } else { \ + if ( m_PS1 & FLAG_H ) { \ + res += 0xFA; \ + } \ + } \ + } else { \ + if ( m_PS1 & FLAG_C ) { \ + if ( m_PS1 & FLAG_H ) { \ + res += 0x66; \ + } else { \ + if ( ( res & 0x0F ) < 10 ) { \ + res += 0x60; \ + } else { \ + res += 0x66; \ + } \ + } \ + } else { \ + if ( m_PS1 & FLAG_H ) { \ + if ( ( res & 0xF0 ) < 0xA0 ) { \ + res += 0x06; \ + } else { \ + res += 0x66; \ + m_PS1 = m_PS1 | FLAG_C; \ + } \ + } else { \ + if ( ( res & 0x0F ) < 10 ) { \ + if ( ( res & 0xF0 ) >= 0xA0 ) { \ + res += 0x60; \ + m_PS1 = m_PS1 | FLAG_C; \ + } \ + } else { \ + if ( ( res & 0xF0 ) < 0x90 ) { \ + res += 0x06; \ + } else { \ + res += 0x66; \ + m_PS1 = m_PS1 | FLAG_C; \ + } \ + } \ + } \ + } \ + } \ + m_PS1 = m_PS1 & ~ ( FLAG_Z | FLAG_S ); \ + m_PS1 = m_PS1 | ( ( ( res & 0xFF ) == 0x00 ) ? FLAG_Z : 0 ); \ + m_PS1 = m_PS1 | ( ( res & 0x80 ) ? FLAG_S : 0 ); + +#define OP_SWAP8(X) d1 = X; \ + res = ( d1 << 4 ) | ( d1 >> 4 ); + +#define CHECK_CC res = 0; \ + switch( op & 0x0F ) { \ + case 0x00: /* F */ res = 0; break; \ + case 0x01: /* LT */ if ( ( m_PS1 & FLAG_S ) ^ ( ( m_PS1 & FLAG_V ) << 1 ) ) res = 1; break; \ + case 0x02: /* LE */ if ( ( ( m_PS1 & FLAG_S ) && ! ( m_PS1 & FLAG_V ) ) || ( ( m_PS1 & FLAG_S ) && ( m_PS1 & FLAG_V ) && ( m_PS1 & FLAG_Z ) ) || ( ! ( m_PS1 & FLAG_S ) && ( ( m_PS1 & FLAG_Z ) || (m_PS1 & FLAG_V ) ) ) ) res = 1; break; \ + case 0x03: /* ULE */ if ( m_PS1 & FLAG_Z || m_PS1 & FLAG_C ) res = 1; break; \ + case 0x04: /* OV */ if ( m_PS1 & FLAG_V ) res = 1; break; \ + case 0x05: /* MI */ if ( m_PS1 & FLAG_S ) res = 1; break; \ + case 0x06: /* Z */ if ( m_PS1 & FLAG_Z ) res = 1; break; \ + case 0x07: /* C */ if ( m_PS1 & FLAG_C ) res = 1; break; \ + case 0x08: /* T */ res = 1; break; \ + case 0x09: /* GE */ if ( ! ( ( m_PS1 & FLAG_S ) ^ ( ( m_PS1 & FLAG_V ) << 1 ) ) ) res = 1; break; \ + case 0x0A: /* GT */ if ( ( ! ( m_PS1 & FLAG_Z ) && ( m_PS1 & FLAG_S ) && ( m_PS1 & FLAG_V ) ) || ( ! ( m_PS1 & FLAG_Z ) && ! ( m_PS1 & FLAG_V ) && ! ( m_PS1 & FLAG_S ) ) ) res = 1; break; \ + case 0x0B: /* UGT */ if ( ! ( m_PS1 & FLAG_Z || m_PS1 & FLAG_C ) ) res = 1; break; \ + case 0x0C: /* NOV */ if ( ! (m_PS1 & FLAG_V) ) res = 1; break; \ + case 0x0D: /* PL */ if ( ! (m_PS1 & FLAG_S) ) res = 1; break; \ + case 0x0E: /* NZ */ if ( ! (m_PS1 & FLAG_Z) ) res = 1; break; \ + case 0x0F: /* NC */ if ( ! (m_PS1 & FLAG_C) ) res = 1; break; \ + } + +#define PUSH8(X) m_SP--; \ + if ( ( m_SYS & 0x40 ) == 0 ) m_SP &= 0xFF; \ + mem_writebyte( m_SP, X ); + +#define POP8(X) X = mem_readbyte( m_SP ); \ + m_SP++; \ + if ( ( m_SYS & 0x40 ) == 0 ) m_SP &= 0xFF; + +case 0x00: /* CLR R - 4 cycles - Flags affected: -------- */ + ARG_R; + mem_writebyte( r1, 0 ); + mycycles += 4; + break; +case 0x01: /* NEG R - 5 cycles - Flags affected: CZSV---- */ + ARG_R; + OP_NEG8( mem_readbyte( r1 ) ); + mem_writebyte( r1 , res & 0xFF ); + mycycles += 5; + break; +case 0x02: /* COM R - 4 cycles - Flags affected: -ZS0---- */ + ARG_R; + OP_COM8( mem_readbyte( r1 ) ); + mem_writebyte( r1, res & 0xFF ); + mycycles += 4; + break; +case 0x03: /* RR R - 4 cycles - Flags affected: CZSV---- */ + ARG_R; + OP_RR8( mem_readbyte( r1 ) ); + mem_writebyte( r1, res & 0xFF ); + mycycles += 4; + break; +case 0x04: /* RL R - 4 cycles - Flags affected: CZSV---- */ + ARG_R; + OP_RL8( mem_readbyte( r1 ) ); + mem_writebyte( r1 , res & 0xFF ); + mycycles += 4; + break; +case 0x05: /* RRC R - 4 cycles - Flags affected: CZSV---- */ + ARG_R; + OP_RRC8( mem_readbyte( r1 ) ); + mem_writebyte( r1, res & 0xFF ); + mycycles += 4; + break; +case 0x06: /* RLC R - 4 cycles - Flags affected: CZSV---- */ + ARG_R; + OP_RLC8( mem_readbyte( r1 ) ); + mem_writebyte( r1, res & 0xFF ); + mycycles += 4; + break; +case 0x07: /* SRL R - 4 cycles - Flags affected: CZ00---- */ + ARG_R; + OP_SRL8( mem_readbyte( r1 ) ); + mem_writebyte( r1, res & 0xFF ); + mycycles += 4; + break; +case 0x08: /* INC R - 4 cycles - Flags affected: -ZSV---- */ + ARG_R; + OP_INC8( mem_readbyte( r1 ) ); + mem_writebyte( r1, res & 0xFF ); + mycycles += 4; + break; +case 0x09: /* DEC R - 4 cycles - Flags affected: -ZSV---- */ + ARG_R; + OP_DEC8( mem_readbyte( r1 ) ); + mem_writebyte( r1, res & 0xFF ); + mycycles += 4; + break; +case 0x0A: /* SRA R - 4 cycles - Flags affected: CZS0---- */ + ARG_R; + OP_SRA8( mem_readbyte( r1 ) ); + mem_writebyte( r1, res & 0xFF ); + mycycles += 4; + break; +case 0x0B: /* SLL R - 4 cycles - Flags affected: CZS0---- */ + ARG_R; + OP_SLL8( mem_readbyte( r1 ) ); + mem_writebyte( r1, res & 0xFF ); + mycycles += 4; + break; +case 0x0C: /* DA R - 4 cycles - Flags affected: CZS----- */ + ARG_R; + OP_DA8( mem_readbyte( r1 ) ); + mem_writebyte( r1, res & 0xFF ); + mycycles += 4; + break; +case 0x0D: /* SWAP R - 7 cycles - Flags affected: -------- */ + ARG_R; + OP_SWAP8( mem_readbyte( r1 ) ); + mem_writebyte( r1, res & 0xFF ); + mycycles += 7; + break; +case 0x0E: /* PUSH R - 5?/12? (8bit SP),10 (16bit SP) cycles */ + ARG_R; + PUSH8( mem_readbyte( r1 ) ); + mycycles += ( ( m_SYS & 0x40 ) ? 12 : 10 ); + break; +case 0x0F: /* POP R - 9,8 cycles */ + ARG_R; + POP8( r2 ); + mem_writebyte( r1, r2 ); + mycycles += ( ( m_SYS & 0x40 ) ? 9 : 8 ); + break; +case 0x10: /* CMP Rr,Rs - 5 cycles - Flags affected: CZSV---- */ + ARG_rr; + OP_CMP8( mem_readbyte( r1 ), mem_readbyte( r2 ) ); + mycycles += 5; + break; +case 0x11: /* ADD Rr,Rs - 5 cycles - Flags affected: CZSV0H-- */ + ARG_rr; + OP_ADD8( mem_readbyte( r1 ), mem_readbyte( r2 ) ); + mem_writebyte( r1, res & 0xFF ); + mycycles += 5; + break; +case 0x12: /* SUB Rr,Rs - 5 cycles - Flags affected: CZSV1H-- */ + ARG_rr; + OP_SUB8( mem_readbyte( r1 ), mem_readbyte( r2 ) ); + mem_writebyte( r1, res & 0xFF ); + mycycles += 5; + break; +case 0x13: /* ADC Rr,Rs - 5 cycles - Flags affected: CZSV0H-- */ + ARG_rr; + OP_ADC8( mem_readbyte( r1 ), mem_readbyte( r2 ) ); + mem_writebyte( r1, res & 0xFF ); + mycycles += 5; + break; +case 0x14: /* SBC Rr,Rs - 5 cycles - Flags affected: CZSV1H-- */ + ARG_rr; + OP_SBC8( mem_readbyte( r1 ), mem_readbyte( r2 ) ); + mem_writebyte( r1, res & 0xFF ); + mycycles += 5; + break; +case 0x15: /* AND Rr,Rs - 5 cycles - Flags affected: -ZS0---- */ + ARG_rr; + OP_AND8( mem_readbyte( r1 ), mem_readbyte( r2 ) ); + mem_writebyte( r1, res & 0xFF ); + mycycles += 5; + break; +case 0x16: /* OR Rr,Rs - 5 cycles - Flags affected: -ZS0---- */ + ARG_rr; + OP_OR8( mem_readbyte( r1 ), mem_readbyte( r2 ) ); + mem_writebyte( r1, res & 0xFF ); + mycycles += 5; + break; +case 0x17: /* XOR Rr,Rs - 5 cycles - Flags affected: -ZS0---- */ + ARG_rr; + OP_XOR8( mem_readbyte( r1 ), mem_readbyte( r2 ) ); + mem_writebyte( r1, res & 0xFF ); + mycycles += 5; + break; +case 0x18: /* INCW S - 8 cycles - Flags affected: -ZSV---- */ + ARG_R; + OP_INC16( mem_readword( r1 ) ); + mem_writeword( r1, res & 0xFFFF ); + mycycles += 8; + break; +case 0x19: /* DECW S - 8 cycles - Flags affected: -ZSV---- */ + ARG_R; + OP_DEC16( mem_readword( r1 ) ); + mem_writeword( r1, res & 0xFFFF ); + mycycles += 8; + break; +case 0x1A: /* CLR/NEG/COM/RR/RL/RRC/RLC/SRL @Rr - 7/8/7/7/7/7/7/6 cycles */ + ARG_rr; + res = 0; + s1 = mem_readbyte( r1 ); + switch( r2 ) { + case 0x00: /* Flags affected: -------- */ + res = 0; + mycycles += 7; + break; + case 0x01: /* Flags affected: CZSV---- */ + OP_NEG8( mem_readbyte( s1 ) ); + mycycles += 8; + break; + case 0x02: /* Flags affected: -ZS0---- */ + OP_COM8( mem_readbyte( s1 ) ); + mycycles += 7; + break; + case 0x03: /* Flags affected: CZSV---- */ + OP_RR8( mem_readbyte( s1 ) ); + mycycles += 7; + break; + case 0x04: /* Flags affected: CZSV---- */ + OP_RL8( mem_readbyte( s1 ) ); + mycycles += 7; + break; + case 0x05: /* Flags affected: CZSV---- */ + OP_RRC8( mem_readbyte( s1 ) ); + mycycles += 7; + break; + case 0x06: /* Flags affected: CZSV---- */ + OP_RLC8( mem_readbyte( s1 ) ); + mycycles += 7; + break; + case 0x07: /* Flags affected: CZ00---- */ + OP_SRL8( mem_readbyte( s1 ) ); + mycycles += 6; + break; + } + mem_writebyte( s1, res & 0xFF ); + break; +case 0x1B: /* INC/DEC/SRA/SLL/DA/SWAP/PUSH/POP @Rr - 7,7,6,7,9,13,8,12,11 cycles */ + ARG_rr; + s1 = mem_readbyte( r1 ); + switch( r2 ) { + case 0x00: /* Flags affected: -ZSV---- */ + OP_INC8( mem_readbyte( s1 ) ); + mem_writebyte( s1, res & 0xFF ); + mycycles += 7; + break; + case 0x01: /* Flags affected: -ZSV---- */ + OP_DEC8( mem_readbyte( s1 ) ); + mem_writebyte( s1, res & 0xFF ); + mycycles += 7; + break; + case 0x02: /* Flags affected: CZS0---- */ + OP_SRA8( mem_readbyte( s1 ) ); + mem_writebyte( s1, res & 0xFF ); + mycycles += 6; + break; + case 0x03: /* Flags affected: CZS0---- */ + OP_SLL8( mem_readbyte( s1 ) ); + mem_writebyte( s1, res & 0xFF ); + mycycles += 6; + break; + case 0x04: /* Flags affected: CZS----- */ + OP_DA8( mem_readbyte( s1 ) ); + mem_writebyte( s1, res & 0xFF ); + mycycles += 7; + break; + case 0x05: /* Flags affected: -------- */ + OP_SWAP8( mem_readbyte( s1 ) ); + mem_writebyte( s1, res & 0xFF ); + mycycles += 9; + break; + case 0x06: /* Flags affected: -------- */ + PUSH8( mem_readbyte( s1 ) ); + mycycles += ( ( m_SYS & 0x40 ) ? 13 : 8 ); + break; + case 0x07: /* Flags affected: -------- */ + POP8( res ); + mem_writebyte( s1, res ); + mycycles += ( ( m_SYS & 0x40 ) ? 12 : 11 ); + break; + } + break; +case 0x1C: /* BCLR 0xFFdd/d8(r),#b - 12,8 cycles - Flags affected: -------- */ + ARG_riB; + mem_writebyte( s1, mem_readbyte( s1 ) & ~s2 ); + mycycles += ( ( r1 & 0x38 ) ? 8 : 12 ); + break; +case 0x1D: /* BSET 0xFFdd/d8(r),#b - 12,8 cycles - Flags affected: -------- */ + ARG_riB; + mem_writebyte( s1, mem_readbyte( s1 ) | s2 ); + mycycles += ( ( r1 & 0x38 ) ? 8 : 12 ); + break; +case 0x1E: /* PUSHW S - 12,9 cycles - Flags affected: -------- */ + ARG_R; + PUSH8( mem_readbyte( r1 + 1 ) ); + PUSH8( mem_readbyte( r1 ) ); + mycycles += ( ( m_SYS & 0x40 ) ? 12 : 9 ); + break; +case 0x1F: /* POPW S - 12,13 cycles - Flags affected: -------- */ + ARG_R; + POP8( r2 ); + mem_writebyte( r1, r2 ); + POP8( r2 ); + mem_writebyte( r1 + 1, r2 ); + mycycles += ( ( m_SYS & 0x40 ) ? 12 : 13 ); + break; +case 0x20: /* CMP r,@r / CMP r,(r)+ / CMP r,@w / CMP r,w(r) / CMP r,-(r) - 7,8,10,8,9 cycles - Flags affected: CZSV---- */ + ARG_rmb; + OP_CMP8( mem_readbyte( r1 ), mem_readbyte( s2 ) ); + switch( r2 & 0xC0 ) { + case 0x00: mycycles += 7; break; + case 0x40: mycycles += 8; break; + case 0x80: mycycles += ( ( r2 & 0x07 ) ? 8 : 10 ); break; + case 0xC0: mycycles += 9; break; + } + break; +case 0x21: /* ADD r,@r / ADD r,(r)+ / ADD r,@w / ADD r,w(r) / ADD r,-(r) - 7,8,10,8,9 cycles - Flags affected: CZSV0H-- */ + ARG_rmb; + OP_ADD8( mem_readbyte( r1 ), mem_readbyte( s2 ) ); + mem_writebyte( r1, res & 0xFF ); + switch( r2 & 0xC0 ) { + case 0x00: mycycles += 7; break; + case 0x40: mycycles += 8; break; + case 0x80: mycycles += ( ( r2 & 0x07 ) ? 8 : 10 ); break; + case 0xC0: mycycles += 9; break; + } + break; +case 0x22: /* SUB r,@r / SUB r,(r)+ / SUB r,@w / SUB r,w(r) / SUB r,-(r) - 7,8,10,8,9 cycles - Flags affected: CZSV1H-- */ + ARG_rmb; + OP_SUB8( mem_readbyte( r1 ), mem_readbyte( s2 ) ); + mem_writebyte( r1, res & 0xFF ); + switch( r2 & 0xC0 ) { + case 0x00: mycycles += 7; break; + case 0x40: mycycles += 8; break; + case 0x80: mycycles += ( ( r2 & 0x07 ) ? 8 : 10 ); break; + case 0xC0: mycycles += 9; break; + } + break; +case 0x23: /* ADC r,@r / ADC r,(r)+ / ADC r,@w / ADC r,w(r) / ADC r,-(r) - 7,8,10,8,9 cycles - Flags affected: CZSV0H-- */ + ARG_rmb; + OP_ADC8( mem_readbyte( r1 ), mem_readbyte( s2 ) ); + mem_writebyte( r1, res & 0xFF ); + switch( r2 & 0xC0 ) { + case 0x00: mycycles += 7; break; + case 0x40: mycycles += 8; break; + case 0x80: mycycles += ( ( r2 & 0x07 ) ? 8 : 10 ); break; + case 0xC0: mycycles += 9; break; + } + break; +case 0x24: /* SBC r,@r / SBC r,(r)+ / SBC r,@w / SBC r,w(r) / SBC r,-(r) - 7,8,10,8,9 cycles - Flags affected: CZSV1H-- */ + ARG_rmb; + OP_SBC8( mem_readbyte( r1 ), mem_readbyte( s2 ) ); + mem_writebyte( r1, res & 0xFF ); + switch( r2 & 0xC0 ) { + case 0x00: mycycles += 7; break; + case 0x40: mycycles += 8; break; + case 0x80: mycycles += ( ( r2 & 0x07 ) ? 8 : 10 ); break; + case 0xC0: mycycles += 9; break; + } + break; +case 0x25: /* AND r,@r / AND r,(r)+ / AND r,@w / AND r,w(r) / AND r,-(r) - 7,8,10,8,9 cycles - Flags affected: -ZS0---- */ + ARG_rmb; + OP_AND8( mem_readbyte( r1 ), mem_readbyte( s2 ) ); + mem_writebyte( r1, res & 0xFF ); + switch( r2 & 0xC0 ) { + case 0x00: mycycles += 7; break; + case 0x40: mycycles += 8; break; + case 0x80: mycycles += ( ( r2 & 0x07 ) ? 8 : 10 ); break; + case 0xC0: mycycles += 9; break; + } + break; +case 0x26: /* OR r,@r / OR r,(r)+ / OR r,@w / OR r,w(r) / OR r,-(r) - 7,8,10,8,9 cycles - Flags affected: -ZS0---- */ + ARG_rmb; + OP_OR8( mem_readbyte( r1 ), mem_readbyte( s2 ) ); + mem_writebyte( r1, res & 0xFF ); + switch( r2 & 0xC0 ) { + case 0x00: mycycles += 7; break; + case 0x40: mycycles += 8; break; + case 0x80: mycycles += ( ( r2 & 0x07 ) ? 8 : 10 ); break; + case 0xC0: mycycles += 9; break; + } + break; +case 0x27: /* XOR r,@r / XOR r,(r)+ / XOR r,@w / XOR r,w(r) / XOR r,-(r) - 7,8,10,8,9 cycles - Flags affected: -ZS0---- */ + ARG_rmb; + OP_XOR8( mem_readbyte( r1 ), mem_readbyte( s2 ) ); + mem_writebyte( r1, res & 0xFF ); + switch( r2 & 0xC0 ) { + case 0x00: mycycles += 7; break; + case 0x40: mycycles += 8; break; + case 0x80: mycycles += ( ( r2 & 0x07 ) ? 8 : 10 ); break; + case 0xC0: mycycles += 9; break; + } + break; +case 0x28: /* MOV r,@r / MOV r,(r)+ / MOV r,@w / MOV r,w(r) / MOV r,-(r) - 6,7,10,7,8 cycles - Flags affected: -------- */ + ARG_rmb; + mem_writebyte( r1, mem_readbyte( s2 ) ); + switch( r2 & 0xC0 ) { + case 0x00: mycycles += 6; break; + case 0x40: mycycles += 7; break; + case 0x80: mycycles += ( ( r2 & 0x07 ) ? 7 : 10 ); break; + case 0xC0: mycycles += 8; break; + } + break; +case 0x29: /* MOV @r,r / MOV (r)+,r / MOV @w,r / MOV w(r),r / MOV -(r),r - 8,8,10,9,9 cycles - Flags affected: -------- */ + ARG_rmb; + mem_writebyte( s2, mem_readbyte( r1 ) ); + switch( r2 & 0xC0 ) { + case 0x00: mycycles += 8; break; + case 0x40: mycycles += 8; break; + case 0x80: mycycles += ( ( r2 & 0x07 ) ? 9 : 10 ); break; + case 0xC0: mycycles += 9; break; + } + break; +case 0x2A: /* BBC FFii/i(Rr),#b,d8 - 16,12/14,10 cycles - Flags affected: -------- */ + ARG_riBd; + if ( mem_readbyte( s1 ) & s2 ) { + mycycles += 10; + } else { + m_PC = m_PC + ((INT8)d1); + mycycles += 14; + } + if ( ( r1 & 0x38 ) == 0 ) { + mycycles += 2; + } + break; +case 0x2B: /* BBS FFii/i(Rr),#b,d8 - 16,12/14,10 cycles - Flags affected: -------- */ + ARG_riBd; + if ( mem_readbyte( s1 ) & s2 ) { + m_PC = m_PC + ((INT8)d1); + mycycles += 14; + } else { + mycycles += 10; + } + if ( ( r1 & 0x38 ) == 0 ) { + mycycles += 2; + } + break; +case 0x2C: /* EXTS Rr - 6 cycles - Flags affected: -------- */ + ARG_R; + res = mem_readword( r1 ); + if ( res & 0x80 ) { + res = res | 0xFF00; + } else { + res = res & 0x00FF; + } + mem_writeword( r1, res ); + mycycles += 6; + break; +case 0x2D: /* unk2D - 4 cycles */ +logerror( "%04X: unk%02x\n", m_PC-1,op ); + mycycles += 4; + break; +case 0x2E: /* MOV PS0,#00 - 4 cycles - Flags affected: -------- */ + ARG_R; + m_PS0 = r1; + mycycles += 4; + break; +case 0x2F: /* BTST R,i - 6 cycles - Flags affected: -Z-0---- */ + ARG_RR; + m_PS1 = m_PS1 & ~ FLAG_V; + if ( ( mem_readbyte( r2 ) & r1 ) == 0x00 ) { + m_PS1 = m_PS1 | FLAG_Z; + } else { + m_PS1 = m_PS1 & ( ~ FLAG_Z ); + } + mycycles += 6; + break; +case 0x30: /* CMP r,@rr / CMP r,(rr)+ / CMP r,@ww / CMP r,ww(rr) / CMP r,-(rr) - 8,13,11,15,13 cycles - Flags affected: CZSV---- */ + ARG_rmw; + OP_CMP8( mem_readbyte( r1 ), mem_readbyte( s2 ) ); + switch( r2 & 0xC0 ) { + case 0x00: mycycles += 8; break; + case 0x40: mycycles += 13; break; + case 0x80: mycycles += ( ( r2 & 0x07 ) ? 11 : 15 ); break; + case 0xC0: mycycles += 13; break; + } + break; +case 0x31: /* ADD r,@rr / ADD r,(rr)+ / ADD r,@ww / ADD r,ww(rr) / ADD r,-(rr) - 8,13,11,15,13 cycles - Flags affected: CZSV0H-- */ + ARG_rmw; + OP_ADD8( mem_readbyte( r1 ), mem_readbyte( s2 ) ); + mem_writebyte( r1, res & 0xFF ); + switch( r2 & 0xC0 ) { + case 0x00: mycycles += 8; break; + case 0x40: mycycles += 13; break; + case 0x80: mycycles += ( ( r2 & 0x07 ) ? 11 : 15 ); break; + case 0xC0: mycycles += 13; break; + } + break; +case 0x32: /* SUB r,@rr / SUB r,(rr)+ / SUB r,@ww / SUB r,ww(rr) / SUB r,-(rr) - 8,13,11,15,13 cycles - Flags affected: CZSV1H-- */ + ARG_rmw; + OP_SUB8( mem_readbyte( r1 ), mem_readbyte( s2 ) ); + switch( r2 & 0xC0 ) { + case 0x00: mycycles += 8; break; + case 0x40: mycycles += 13; break; + case 0x80: mycycles += ( ( r2 & 0x07 ) ? 11 : 15 ); break; + case 0xC0: mycycles += 13; break; + } + break; +case 0x33: /* ADC r,@rr / ADC r,(rr)+ / ADC r,@ww / ADC r,ww(rr) / ADC r,-(rr) - 8,13,11,15,13 cycles - Flags affected: CZSV0H-- */ + ARG_rmw; + OP_ADC8( mem_readbyte( r1 ), mem_readbyte( s2 ) ); + mem_writebyte( r1, res & 0xFF ); + switch( r2 & 0xC0 ) { + case 0x00: mycycles += 8; break; + case 0x40: mycycles += 13; break; + case 0x80: mycycles += ( ( r2 & 0x07 ) ? 11 : 15 ); break; + case 0xC0: mycycles += 13; break; + } + break; +case 0x34: /* SBC r,@rr / SBC r,(rr)+ / SBC r,@ww / SBC r,ww(rr) / SBC r,-(rr) - 8,13,11,15,13 cycles - Flags affected: CZSV1H-- */ + ARG_rmw; + OP_SBC8( mem_readbyte( r1 ), mem_readbyte( s2 ) ); + mem_writebyte( r1, res & 0xFF ); + switch( r2 & 0xC0 ) { + case 0x00: mycycles += 8; break; + case 0x40: mycycles += 13; break; + case 0x80: mycycles += ( ( r2 & 0x07 ) ? 11 : 15 ); break; + case 0xC0: mycycles += 13; break; + } + break; +case 0x35: /* AND r,@rr / AND r,(rr)+ / AND r,@ww / AND r,ww(rr) / AND r,-(rr) - 8,13,11,15,13 cycles - Flags affected: -ZS0---- */ + ARG_rmw; + OP_AND8( mem_readbyte( r1 ), mem_readbyte( s2 ) ); + mem_writebyte( r1, res & 0xFF ); + switch( r2 & 0xC0 ) { + case 0x00: mycycles += 8; break; + case 0x40: mycycles += 13; break; + case 0x80: mycycles += ( ( r2 & 0x07 ) ? 11 : 15 ); break; + case 0xC0: mycycles += 13; break; + } + break; +case 0x36: /* OR r,@rr / OR r,(rr)+ / OR r,@ww / OR r,ww(rr) / OR r,-(rr) - 8,13,11,15,13 cycles - Flags affected: -ZS0---- */ + ARG_rmw; + OP_OR8( mem_readbyte( r1 ), mem_readbyte( s2 ) ); + mem_writebyte( r1, res & 0xFF ); + switch( r2 & 0xC0 ) { + case 0x00: mycycles += 8; break; + case 0x40: mycycles += 13; break; + case 0x80: mycycles += ( ( r2 & 0x07 ) ? 11 : 15 ); break; + case 0xC0: mycycles += 13; break; + } + break; +case 0x37: /* XOR? r,@rr / XOR r,(rr)+ / XOR r,@ww / XOR r,ww(rr) / XOR r,-(rr) - 8,13,11,15,13 cycles - Flagsaffected: -ZS0---- */ + ARG_rmw; + OP_XOR8( mem_readbyte( r1 ), mem_readbyte( s2 ) ); + mem_writebyte( r1, res & 0xFF ); + switch( r2 & 0xC0 ) { + case 0x00: mycycles += 8; break; + case 0x40: mycycles += 13; break; + case 0x80: mycycles += ( ( r2 & 0x07 ) ? 11 : 15 ); break; + case 0xC0: mycycles += 13; break; + } + break; +case 0x38: /* MOV r,@rr / MOV r,(rr)+ / MOV r,@ww / MOV r,ww(rr) / MOV r,-(rr) - 8,13,11,15,13 cycles - Flags affected: -------- */ + ARG_rmw; + mem_writebyte( r1, mem_readbyte( s2 ) ); + switch( r2 & 0xC0 ) { + case 0x00: mycycles += 8; break; + case 0x40: mycycles += 13; break; + case 0x80: mycycles += ( ( r2 & 0x07 ) ? 11 : 15 ); break; + case 0xC0: mycycles += 13; break; + } + break; +case 0x39: /* MOV @rr,r / MOV (rr)+,r / MOV @ww,r / MOV ww(rr),r / MOV -(rr),r - 8,13,11,15,13 cycles - Flags affected: -------- */ + ARG_rmw; + mem_writebyte( s2, mem_readbyte( r1 ) ); + switch( r2 & 0xC0 ) { + case 0x00: mycycles += 8; break; + case 0x40: mycycles += 13; break; + case 0x80: mycycles += ( ( r2 & 0x07 ) ? 11 : 15 ); break; + case 0xC0: mycycles += 13; break; + } + break; +case 0x3A: /* MOVW rr,@rr / MOV rr,(rr)+ / MOV rr,@ww / MOV rr,ww(rr) / MOV rr,-(rr) - 11,16,14,18,16 cycles - Flags affected: -------- */ + ARG_smw; + mem_writeword( r1, mem_readword( s2 ) ); + switch( r2 & 0xC0 ) { + case 0x00: mycycles += 11; break; + case 0x40: mycycles += 16; break; + case 0x80: mycycles += ( ( r2 & 0x07 ) ? 18 : 14 ); break; + case 0xC0: mycycles += 16; break; + } + break; +case 0x3B: /* MOVW @rr,rr / MOV (rr)+,rr / MOV @ww,rr / MOV ww(rr),rr / MOV -(rr),rr - 11,16,14,18,16 cycles - Flags affected: -------- */ + ARG_smw; + mem_writeword( s2, mem_readword( r1 ) ); + switch( r2 & 0xC0 ) { + case 0x00: mycycles += 11; break; + case 0x40: mycycles += 16; break; + case 0x80: mycycles += ( ( r2 & 0x07 ) ? 18 : 14 ); break; + case 0xC0: mycycles += 16; break; + } + break; +case 0x3C: /* MOVW RRr,RRs - 7 cycles - Flags affected: -------- */ + ARG_ss; + mem_writeword( r1, mem_readword( r2 ) ); + mycycles += 7; + break; +case 0x3D: /* unk3D DM??? 3D 0E -> DM R0Eh ?? - 4,4 cycles */ +logerror( "%04X: unk%02x\n", m_PC-1,op ); + mycycles += 4; + break; +case 0x3E: /* JMP RRr/@ww/ww(RRr) - 7/15/19 cycles - Flags affected: -------- */ + ARG_2; + m_PC = s2; + switch( r1 & 0xc0 ) { + case 0x00: mycycles += 7; break; + case 0x40: mycycles += ( ( r1 & 0x38 ) ? 19 : 15 ); break; + default: mycycles += 4; + } + break; +case 0x3F: /* CALL RRr/@ww/ww(RRr) - 11,14/22,19/26,23 cycles - Flags affected: -------- */ + ARG_2; + PUSH8( m_PC & 0xFF ); + PUSH8( m_PC >> 8 ); + m_PC = s2; + switch( r1 & 0xc0 ) { + case 0x00: mycycles += ( ( m_SYS & 0x40 ) ? 14 : 11 ); break; + case 0x40: mycycles += ( ( r1 & 0x38 ) ? ( ( m_SYS & 0x40 ) ? 26 : 23 ) : ( ( m_SYS & 0x40 ) ? 22 : 19 ) );break; + default: mycycles += 4; + } + break; +case 0x40: /* CMP Rr,Rs - 6 cycles - Flags affected: CZSV---- */ + ARG_RR; + OP_CMP8( mem_readbyte( r1 ), mem_readbyte( r2 ) ); + mycycles += 6; + break; +case 0x41: /* ADD Rr,Rs - 6 cycles - Flags affected: CZSV0H-- */ + ARG_RR; + OP_ADD8( mem_readbyte( r1 ), mem_readbyte( r2 ) ); + mem_writebyte( r1, res & 0xFF ); + mycycles += 6; + break; +case 0x42: /* SUB Rr,Rs - 6 cycles - Flags affected: CZSV1H-- */ + ARG_RR; + OP_SUB8( mem_readbyte( r1 ), mem_readbyte( r2 ) ); + mem_writebyte( r1, res & 0xFF ); + mycycles += 6; + break; +case 0x43: /* ADC Rr,Rs - 6 cycles - Flags affected: CZSV0H-- */ + ARG_RR; + OP_ADC8( mem_readbyte( r1 ), mem_readbyte( r2 ) ); + mem_writebyte( r1, res & 0xFF ); + mycycles += 6; + break; +case 0x44: /* SBC Rr,Rs - 6 cycles - Flags affected: CZSV1H-- */ + ARG_RR; + OP_SBC8( mem_readbyte( r1 ), mem_readbyte( r2 ) ); + mem_writebyte( r1, res & 0xFF ); + mycycles += 6; + break; +case 0x45: /* AND Rr,Rs - 6 cycles - Flags affected: -ZS0---- */ + ARG_RR; + OP_AND8( mem_readbyte( r1 ), mem_readbyte( r2 ) ); + mem_writebyte( r1, res & 0xFF ); + mycycles += 6; + break; +case 0x46: /* OR Rr,Rs - 6 cycles - Flags affected: -ZS0---- */ + ARG_RR; + OP_OR8( mem_readbyte( r1 ), mem_readbyte( r2 ) ); + mem_writebyte( r1, res & 0xFF ); + mycycles += 6; + break; +case 0x47: /* XOR Rr,Rs - 6 cycles - Flags affected: -ZS0---- */ + ARG_RR; + OP_XOR8( mem_readbyte( r1 ), mem_readbyte( r2 ) ); + mem_writebyte( r1, res & 0xFF ); + mycycles += 6; + break; +case 0x48: /* MOV Rr,Rs - 6 cycles - Flags affected: -------- */ + ARG_RR; + mem_writebyte( r1, mem_readbyte( r2 ) ); + mycycles += 6; + break; +case 0x49: /* CALL ad16 - 12,10 - Flags affected: -------- */ + ARG_ad16; + PUSH8( m_PC & 0xFF ); + PUSH8( m_PC >> 8 ); + m_PC = s2; + mycycles += ( ( m_SYS & 0x40 ) ? 12 : 10 ); + break; +case 0x4A: /* MOVW RRr,RRs - 8 cycles - Flags affected: -------- */ + ARG_RR; + mem_writeword( r1, mem_readword( r2 ) ); + mycycles += 8; + break; +case 0x4B: /* MOVW RRr,ww - 9 cycles - Flags affected: -------- */ + ARG_Sw; + mem_writeword( r1, s2 ); + mycycles += 9; + break; +case 0x4C: /* MULT Rrr,Rs - 24 cycles - Flags affected: -Z-0---- */ + ARG_RR; + res = mem_readword( r1 ) * mem_readbyte( r2 ); + mem_writeword( r1, res & 0xFFFF ); + m_PS1 = m_PS1 & ~ ( FLAG_Z | FLAG_V ); + m_PS1 |= ( ( res & 0xFFFF ) == 0x00 ? FLAG_Z : 0 ); + mycycles += 24; + break; +case 0x4D: /* MULT RRr,i - 24 cycles - Flags affected: -Z-0---- */ + ARG_iR; + res = mem_readbyte( r1 + 1 ) * r2; + mem_writeword( r1, res & 0xFFFF ); + m_PS1 = m_PS1 & ~ ( FLAG_Z | FLAG_V ); + m_PS1 |= ( ( res & 0xFFFF ) == 0x00 ? FLAG_Z : 0 ); + mycycles += 24; + break; +case 0x4E: /* BMOV Rr,#b,BF/BF,Rr,#b - 6 cycles - Flags affected: --------/-Z-0--B- */ + r2 = mem_readbyte( m_PC++ ); + r1 = mem_readbyte( m_PC++ ); + switch( r2 & 0xC0 ) { + case 0x40: + res = mem_readbyte( r1 ); + if ( m_PS1 & FLAG_B ) { + res = res | ( 1 << ( r2 & 0x07 ) ); + } else { + res = res & ~( 1 << ( r2 & 0x07 ) ); + } + mem_writebyte( r1, res & 0xFF ); + break; + case 0x00: + m_PS1 = m_PS1 & ( FLAG_C | FLAG_S | FLAG_D | FLAG_H | FLAG_I ); + if ( mem_readbyte( r1 ) & ( 1 << ( r2 & 0x07 ) ) ) { + m_PS1 = m_PS1 | FLAG_B; + } else { + m_PS1 = m_PS1 | FLAG_Z; + } + break; + case 0x80: + case 0xC0: + break; + } + mycycles += 6; + break; +case 0x4F: /* BCMP/BAND/BOR/BXOR BF,Rr,#b - 6 cycles - Flags affected: -Z-0---- / -Z-0--B- */ + r2 = mem_readbyte( m_PC++ ); + r1 = mem_readbyte( m_PC++ ); + s1 = mem_readbyte( r1 ) & ( 1 << ( r2 & 0x07 ) ); + s2 = ( ( m_PS1 & FLAG_B ) >> 1 ) << ( r2 & 0x07 ); + switch( r2 & 0xC0 ) { + case 0x00: + m_PS1 = m_PS1 & ~ ( FLAG_Z | FLAG_V ); + if ( s1 == s2 ) { + m_PS1 = m_PS1 | FLAG_Z; + } + break; + case 0x40: + m_PS1 = m_PS1 & ~ ( FLAG_Z | FLAG_V | FLAG_B ); + m_PS1 = m_PS1 | ( ( s1 & s2 ) ? FLAG_B : FLAG_Z ); + break; + case 0x80: + m_PS1 = m_PS1 & ~ ( FLAG_Z | FLAG_V | FLAG_B ); + m_PS1 = m_PS1 | ( ( s1 | s2 ) ? FLAG_B : FLAG_Z ); + break; + case 0xC0: + m_PS1 = m_PS1 & ~ ( FLAG_Z | FLAG_V | FLAG_B ); + m_PS1 = m_PS1 | ( ( s1 ^ s2 ) ? FLAG_B : FLAG_Z ); + break; + } + mycycles += 6; + break; +case 0x50: /* CMP Rr,i - 6 cycles - Flags affected: CZSV---- */ + ARG_iR; + OP_CMP8( mem_readbyte( r1 ), r2 ); + mycycles += 6; + break; +case 0x51: /* ADD Rr,i - 6 cycles - Flags affected: CZSV0H-- */ + ARG_iR; + OP_ADD8( mem_readbyte( r1 ), r2 ); + mem_writebyte( r1, res & 0xFF ); + mycycles += 6; + break; +case 0x52: /* SUB Rr,i - 6 cycles - Flags affected: CZSV1H-- */ + ARG_iR; + OP_SUB8( mem_readbyte( r1 ), r2 ); + mem_writebyte( r1, res & 0xFF ); + mycycles += 6; + break; +case 0x53: /* ADC Rr,i - 6 cycles - Flags affected: CZSV0H-- */ + ARG_iR; + OP_ADC8( mem_readbyte( r1 ), r2 ); + mem_writebyte( r1, res & 0xFF ); + mycycles += 6; + break; +case 0x54: /* SBC Rr,i - 6 cycles - Flags affected: CZSV1H-- */ + ARG_iR; + OP_SBC8( mem_readbyte( r1 ), r2 ); + mem_writebyte( r1, res & 0xFF ); + mycycles += 6; + break; +case 0x55: /* AND Rr,i - 6 cycles - Flags affected: -ZS0---- */ + ARG_iR; + OP_AND8( mem_readbyte( r1 ), r2 ); + mem_writebyte( r1, res & 0xFF ); + mycycles += 6; + break; +case 0x56: /* OR Rr,i - 6 cycles - Flags affected: -ZS0---- */ + ARG_iR; + OP_OR8( mem_readbyte( r1 ), r2 ); + mem_writebyte( r1, res & 0xFF ); + mycycles += 6; + break; +case 0x57: /* XOR Rr,i - 6 cycles - Flags affected: -ZS0---- */ + ARG_iR; + OP_XOR8( mem_readbyte( r1 ), r2 ); + mem_writebyte( r1, res & 0xFF ); + mycycles += 6; + break; +case 0x58: /* MOV Rr,i - 6 cycles - Flags affected: -------- */ + ARG_iR; + mem_writebyte( r1, r2 ); + mycycles += 6; + break; +case 0x59: /* Invalid - 2? cycles - Flags affected: --------? */ + logerror( "%04X: 59h: Invalid instruction\n", m_PC-1 ); + mycycles += 2; + break; +case 0x5A: /* unk5A - 7,8,12,9,8 cycles */ + logerror( "%04X: unk%02x\n", m_PC-1,op ); +/* NOTE: This unknown command is used in the calculator as a compare instruction + at 0x493A and 0x4941, we set the flags on the 3rd byte, although its real + function remains a mystery */ + ARG_iR; + OP_CMP8( 0, r1 ); + mycycles += 7; + break; +case 0x5B: /* unk5B - 6,7,11,8,7 cycles */ + logerror( "%04X: unk%02x\n", m_PC-1,op ); +/* NOTE: This unknown command is used in several carts, the code below allows those carts to boot */ + ARG_iR; + r1 = r2 & 7; + res = mem_readbyte( r1 ) + 1; + mem_writebyte( r1, res ); + mycycles += 6; + break; +case 0x5C: /* DIV RRr,RRs - 47 cycles - Flags affected: -Z-V---- */ + /* lower 8 bits of RRs is used to divide */ + /* remainder in stored upper 8 bits of RRs */ +logerror( "%04X: DIV RRr,Rs!\n", m_PC-1 ); + ARG_RR; + m_PS1 = m_PS1 & ~ ( FLAG_Z | FLAG_V ); + s1 = mem_readbyte( r2 + 1 ); + if ( s1 ) { + UINT16 div = mem_readword( r1 ); + res = div / s1; + mem_writebyte( r2, div % s1 ); + mem_writeword( r1, res ); + m_PS1 = m_PS1 | ( ( res == 0 ) ? FLAG_Z : 0 ); + } else { + m_PS1 = m_PS1 | FLAG_V; + } + mycycles += 47; + break; +case 0x5D: /* DIV RRr,i - 44 cycles - Flags affected: -Z-V---- */ +logerror( "%04X: DIV RRr,i!\n", m_PC-1 ); + ARG_iR; + m_PS1 = m_PS1 & ~ ( FLAG_Z | FLAG_V ); + if ( r2 ) { + res = mem_readword( r1 ) / r2; + mem_writeword( r1, res ); + m_PS1 = m_PS1 | ( ( res == 0 ) ? FLAG_Z : 0 ); + } else { + m_PS1 = m_PS1 | FLAG_V; + } + mycycles += 44; + break; +case 0x5E: /* MOVM Rr,i,Rs - 9 cycles - Flags affected: -------- */ + ARG_RiR; + mem_writebyte( r1, ( mem_readbyte( r1 ) & d1 ) | mem_readbyte( r2 ) ); + mycycles += 9; + break; +case 0x5F: /* MOVM Rr,i,j - 8 cycles - Flags affected: -------- */ + ARG_Rii; + mem_writebyte( r1, ( mem_readbyte( r1 ) & d1 ) | r2 ); + mycycles += 8; + break; +case 0x60: /* CMPW RRr,RRs - 9 cycles - Flags affected: CZSV---- */ + ARG_RR; + OP_CMP16( mem_readword( r1 ), mem_readword( r2 ) ); + mycycles += 9; + break; +case 0x61: /* ADDW RRr,RRs - 10 cycles - Flags affected: CZSV0H-- */ + ARG_RR; + OP_ADD16( mem_readword( r1 ), mem_readword( r2 ) ); + mem_writeword( r1, res & 0xFFFF ); + mycycles += 10; + break; +case 0x62: /* SUBW RRr,RRs - 10 cycles - Flags affected: CZSV1H-- */ + ARG_RR; + OP_SUB16( mem_readword( r1 ), mem_readword( r2 ) ); + mem_writeword( r1, res & 0xFFFF ); + mycycles += 10; + break; +case 0x63: /* ADCW RRr,RRs - 10 cycles - Flags affected: CZSV0H-- */ + ARG_RR; + OP_ADC16( mem_readword( r1 ), mem_readword( r2 ) ); + mem_writeword( r1, res & 0xFFFF ); + mycycles += 10; + break; +case 0x64: /* SBCW RRr,RRs - 10 cycles - Flags affected: CZSV1H-- */ + ARG_RR; + OP_SBC16( mem_readword( r1 ), mem_readword( r2 ) ); + mem_writeword( r1, res & 0xFFFF ); + mycycles += 10; + break; +case 0x65: /* ANDW RRr,RRs - 14 cycles - Flags affected: -Z-0---- */ + ARG_RR; + OP_AND16( mem_readword( r1 ), mem_readword( r2 ) ); + mem_writeword( r1, res & 0xFFFF ); + mycycles += 14; + break; +case 0x66: /* ORW RRr,RRs - 14 cycles - Flags affected: -Z-0---- */ + ARG_RR; + OP_OR16( mem_readword( r1 ), mem_readword( r2 ) ); + mem_writeword( r1, res & 0xFFFF ); + mycycles += 14; + break; +case 0x67: /* XORW RRr,RRs - 14 cycles - Flags affected: -Z-0---- */ + ARG_RR; + OP_XOR16( mem_readword( r1 ), mem_readword( r2 ) ); + mem_writeword( r1, res & 0xFFFF ); + mycycles += 14; + break; +case 0x68: /* CMPW RRr,w - 9 cycles - Flags affected: CZSV---- */ + ARG_Sw; + OP_CMP16( mem_readword( r1 ), s2 ); + mycycles += 9; + break; +case 0x69: /* ADDW RRr,w - 10 cycles - Flags affected: CZSV0H-- */ + ARG_Sw; + OP_ADD16( mem_readword( r1 ), s2 ); + mem_writeword( r1, res & 0xFFFF ); + mycycles += 10; + break; +case 0x6A: /* SUBW RRr,w - 10 cycles - Flags affected: CZSV1H-- */ + ARG_Sw; + OP_SUB16( mem_readword( r1 ), s2 ); + mem_writeword( r1, res & 0xFFFF ); + mycycles += 10; + break; +case 0x6B: /* ADCW RRr,w - 10 cycles - Flags affected: CZSV0H-- */ + ARG_Sw; + OP_ADC16( mem_readword( r1 ), s2 ); + mem_writeword( r1, res & 0xFFFF ); + mycycles += 10; + break; +case 0x6C: /* SBCW RRr,w - 10 cycles - Flags affected: CZSV1H-- */ + ARG_Sw; + OP_SBC16( mem_readword( r1 ), s2 ); + mem_writeword( r1, res & 0xFFFF ); + mycycles += 10; + break; +case 0x6D: /* ANDW RRr,w - 13 cycles - Flags affected: -Z-0---- */ + ARG_Sw; + OP_AND16( mem_readword( r1 ), s2 ); + mem_writeword( r1, res & 0xFFFF ); + mycycles += 13; + break; +case 0x6E: /* ORW RRr,w - 13 cycles - Flags affected: -Z-0---- */ + ARG_Sw; + OP_OR16( mem_readword( r1 ), s2 ); + mem_writeword( r1, res & 0xFFFF ); + mycycles += 13; + break; +case 0x6F: /* XORW RRr,w - 13 cycles - Flags affected: -Z-0---- */ + ARG_Sw; + OP_XOR16( mem_readword( r1 ), s2 ); + mem_writeword( r1, res & 0xFFFF); + mycycles += 13; + break; +case 0x70: /* DBNZ r,rel8 - 10,6 cycles - Flags affected: -------- */ +case 0x71: +case 0x72: +case 0x73: +case 0x74: +case 0x75: +case 0x76: +case 0x77: + ARG_d8; + r1 = mem_readbyte( op & 0x07 ); + r1--; + mem_writebyte( op & 0x07, r1 ); + if ( r1 != 0 ) { + m_PC = s2; + mycycles += 10; + } else { + mycycles += 6; + } + break; +case 0x78: /* MOVW RRx,w - 6 cycles - Flags affected: -------- */ +case 0x79: +case 0x7A: +case 0x7B: +case 0x7C: +case 0x7D: +case 0x7E: +case 0x7F: + ARG_rrw; + mem_writeword( r1, s2 ); + mycycles += 6; + break; +case 0x80: /* BBC R,#b,d8 - 10,6 cycles - Flags affected: -------- */ +case 0x81: +case 0x82: +case 0x83: +case 0x84: +case 0x85: +case 0x86: +case 0x87: + ARG_Rbr; + if ( ( mem_readbyte( r1 ) & ( 1 << (op & 0x07) ) ) == 0 ) { + m_PC = s2; + mycycles += 10; + } else { + mycycles += 6; + } + break; +case 0x88: /* BBS R,#b,d8 - 10,6 cycles - Flags affected: -------- */ +case 0x89: +case 0x8A: +case 0x8B: +case 0x8C: +case 0x8D: +case 0x8E: +case 0x8F: + ARG_Rbr; + if ( ( mem_readbyte( r1 ) & ( 1 << (op & 0x07) ) ) ) { + m_PC = s2; + mycycles += 10; + } else { + mycycles += 6; + } + break; +case 0x90: /* JMP cc,ad16 - 6 cycles - Flags affected: -------- */ +case 0x91: +case 0x92: +case 0x93: +case 0x94: +case 0x95: +case 0x96: +case 0x97: +case 0x98: +case 0x99: +case 0x9A: +case 0x9B: +case 0x9C: +case 0x9D: +case 0x9E: +case 0x9F: + ARG_ad16; + CHECK_CC; + if ( res ) { + m_PC = s2; + } + mycycles += 6; + break; +case 0xA0: /* BCLR R,#b - 4 cycles - Flags affected: -------- */ +case 0xA1: +case 0xA2: +case 0xA3: +case 0xA4: +case 0xA5: +case 0xA6: +case 0xA7: + ARG_R; + mem_writebyte( r1, mem_readbyte( r1 ) & ~ ( 1 << (op & 0x07) ) ); + mycycles += 4; + break; +case 0xA8: /* BSET R,#b - 4 cycles - Flags affected: -------- */ +case 0xA9: +case 0xAA: +case 0xAB: +case 0xAC: +case 0xAD: +case 0xAE: +case 0xAF: + ARG_R; + mem_writebyte( r1, mem_readbyte( r1 ) | ( 1 << (op & 0x07) ) ); + mycycles += 4; + break; +case 0xB0: /* MOV Rx,Rr - 4 cycles - Flags affected: -------- */ +case 0xB1: +case 0xB2: +case 0xB3: +case 0xB4: +case 0xB5: +case 0xB6: +case 0xB7: + ARG_rR; + mem_writebyte( r1, mem_readbyte( r2 ) ); + mycycles += 4; + break; +case 0xB8: /* MOV Rr,Rx - 4 cycles - Flags affected: -------- */ +case 0xB9: +case 0xBA: +case 0xBB: +case 0xBC: +case 0xBD: +case 0xBE: +case 0xBF: + ARG_rR; + mem_writebyte( r2, mem_readbyte( r1 ) ); + mycycles += 4; + break; +case 0xC0: /* MOV Rx,i - 4 cycles - Flags affected: -------- */ +case 0xC1: +case 0xC2: +case 0xC3: +case 0xC4: +case 0xC5: +case 0xC6: +case 0xC7: + ARG_ri; + mem_writebyte( r1, r2 ); + mycycles += 4; + break; +case 0xC8: /* MOV IE0/IE1/IR0/IR1/P0/P1/P2/P3,i - 4 cycles - Flags affected: -------- */ +case 0xC9: +case 0xCA: +case 0xCB: +case 0xCC: +case 0xCD: +case 0xCE: +case 0xCF: + ARG_pi; + mem_writebyte( r1, r2 ); + mycycles += 4; + break; +case 0xD0: /* BR cc,rel8 - 8,4 cycles - Flags affected: -------- */ +case 0xD1: +case 0xD2: +case 0xD3: +case 0xD4: +case 0xD5: +case 0xD6: +case 0xD7: +case 0xD8: +case 0xD9: +case 0xDA: +case 0xDB: +case 0xDC: +case 0xDD: +case 0xDE: +case 0xDF: + ARG_d8; + CHECK_CC; + if ( res ) { + m_PC = s2; + mycycles += 8; + } else { + mycycles += 4; + } + break; +case 0xE0: /* CALS - 12,9 cycles */ +case 0xE1: +case 0xE2: +case 0xE3: +case 0xE4: +case 0xE5: +case 0xE6: +case 0xE7: +case 0xE8: +case 0xE9: +case 0xEA: +case 0xEB: +case 0xEC: +case 0xED: +case 0xEE: +case 0xEF: /* CALS 1xWW - 12,9 cycles - Flags affected: -------- */ + ARG_R; + s2 = 0x1000 + ( ( op & 0x0F ) << 8 ) + r1; + PUSH8( m_PC & 0xFF ); + PUSH8( m_PC >> 8 ); + m_PC = s2; + mycycles += ( ( m_SYS & 0x40 ) ? 12 : 9 ); + break; +case 0xF0: /* STOP - 2 cycles - Flags affected: -------- */ + mycycles += 2; + if ( m_clock_changed ) { + /* TODO: Set system clock divider */ + /* TODO: Add a bunch of additional cycles */ + m_clock_changed = 0; + } + break; +case 0xF1: /* HALT - 2 cycles - Flags affected: -------- */ + m_halted = 1; + mycycles += 2; + break; +case 0xF2: /* Invalid - 2? cycles - Flags affected: --------? */ +case 0xF3: +case 0xF4: +case 0xF5: +case 0xF6: +case 0xF7: + mycycles += 2; + break; +case 0xF8: /* RET - 10,8 cycles - Flags affected: -------- */ + POP8( r1 ); + POP8( r2 ); + m_PC = ( r1 << 8 ) | r2; + mycycles += ( ( m_SYS & 0x40 ) ? 10 : 8 ); + break; +case 0xF9: /* IRET - 12,10 cycles - Flags affected: CZSVDHBI */ + POP8( m_PS1 ); + POP8( r1 ); + POP8( r2 ); + m_PC = ( r1 << 8 ) | r2; + mycycles += ( ( m_SYS & 0x40 ) ? 12 : 10 ); + break; +case 0xFA: /* CLRC - 2 cycles - Flags affected: C------- */ + m_PS1 = m_PS1 & ~ ( FLAG_C ); + mycycles += 2; + break; +case 0xFB: /* COMC - 2 cycles - Flags affected: C------- */ + m_PS1 = m_PS1 ^ FLAG_C; + mycycles += 2; + break; +case 0xFC: /* SETC - 2 cycles - Flags affected: C------- */ + m_PS1 = m_PS1 | FLAG_C; + mycycles += 2; + break; +case 0xFD: /* EI - 2 cycles - Flags affected: -------I */ + m_PS1 = m_PS1 | FLAG_I; + mycycles += 2; + break; +case 0xFE: /* DI - 2 cycles - Flags affected: -------I */ + m_PS1 = m_PS1 & ~ ( FLAG_I ); + mycycles += 2; + break; +case 0xFF: /* NOP - 2 cycles - Flags affected: -------- */ + mycycles += 2; + break; +default: + mycycles += 2; + break; diff --git a/src/devices/cpu/spc700/spc700.c b/src/devices/cpu/spc700/spc700.c new file mode 100644 index 00000000000..a21ab8bc27f --- /dev/null +++ b/src/devices/cpu/spc700/spc700.c @@ -0,0 +1,1692 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont, Karl Stenerud +/* ======================================================================== */ +/* =============================== COPYRIGHT ============================== */ +/* ======================================================================== */ +/* + + Sony/Nintendo SPC700 CPU Emulator + + The SPC700 is 6502-based at heart but contains a lot of the extended + opcodes of the Mitsubishi 770 and 7700 series 65xxx-based MCUs, plus + a few special twists borrowed from the 68000. + + It was designed by Sony's Ken Kutaragi, later the "father of the PlayStation". + + Original emulation by Anthony Kruize and Lee Hammerton. + Substantially revised by R. Belmont. + + Thanks to Anonymous, TRAC, Brad Martin, anomie, Blargg, and everyone + else on ZSNES Technical for probing the darker corners of the SNES + with test programs so we have a chance at getting things accurate. + + MESS Bugzilla bugs: + - 804 ADC sets carry too late (FIXED) + - 805 ADDW/SUBW set V wrongly (FIXED) + - 806 BRK should modify PSW (FIXED) + - 807 DAA/DAS problem (FIXED) + + +*/ +/* ======================================================================== */ +/* ================================= NOTES ================================ */ +/* ======================================================================== */ +/* + +snes mapped ports: f0-ff +Address Function Register R/W When Reset Remarks + +00F0H (test) --- ------ Installed in sound-CPU +00F1H Control W Control = "00-000" +00F2H Register Add. R/W Indeterminate Installed in DSP +00F3H Register Data R/W Indeterminate Installed in DSP +00F4H Port-0 R/W Port0r = "00" Installed in sound-CPU + Port0w = "00" +00F5H Port-1 R/W Port1r = "00" Installed in sound-CPU + Port1w = "00" +00F6H Port-2 R/W Port2r = "00" Installed in sound-CPU + Port2w = "00" +00F7H Port-3 R/W Port3r = "00" Installed in sound-CPU + Port3w = "00" +00F8H ------ --- ---------- ------------------- +00F9H ------ --- ---------- ------------------- +00FAH Timer-0 W Indeterminate Installed in sound-CPU +00FBH Timer-1 W Indeterminate Installed in sound-CPU +00FCH Timer-2 W Indeterminate Installed in sound-CPU +00FDH Counter-0 W Indeterminate Installed in sound-CPU +00FEH Counter-1 W Indeterminate Installed in sound-CPU +00FFH Counter-2 W Indeterminate Installed in sound-CPU + +*/ +/* ======================================================================== */ +/* ================================ INCLUDES ============================== */ +/* ======================================================================== */ + +#include +#include "emu.h" +#include "debugger.h" +#include "spc700.h" + + +/* ======================================================================== */ +/* ==================== ARCHITECTURE-DEPENDANT DEFINES ==================== */ +/* ======================================================================== */ + +#undef int8 + +/* Allow for architectures that don't have 8-bit sizes */ +#if UCHAR_MAX == 0xff +#define int8 char +#define MAKE_INT_8(A) (int8)((A)&0xff) +#else +#define int8 int +INLINE int MAKE_INT_8(int A) {return (A & 0x80) ? A | ~0xff : A & 0xff;} +#endif /* UCHAR_MAX == 0xff */ + +#define MAKE_UINT_8(A) ((A)&0xff) +#define MAKE_UINT_16(A) ((A)&0xffff) + +/* ======================================================================== */ +/* ============================ GENERAL DEFINES =========================== */ +/* ======================================================================== */ + +/* Bits */ +#define BIT_0 0x01 +#define BIT_1 0x02 +#define BIT_2 0x04 +#define BIT_3 0x08 +#define BIT_4 0x10 +#define BIT_5 0x20 +#define BIT_6 0x40 +#define BIT_7 0x80 +#define BIT_8 0x100 + +/* Flag positions in Processor Status Register */ +#define FLAGPOS_N BIT_7 /* Negative */ +#define FLAGPOS_V BIT_6 /* Overflow */ +#define FLAGPOS_P BIT_5 /* Direct Page Selector */ +#define FLAGPOS_B BIT_4 /* Break */ +#define FLAGPOS_H BIT_3 /* Half-carry */ +#define FLAGPOS_I BIT_2 /* Interrupt */ +#define FLAGPOS_Z BIT_1 /* Zero */ +#define FLAGPOS_C BIT_0 /* Carry */ + +#define NFLAG_SET FLAGPOS_N +#define VFLAG_SET BIT_7 +#define PFLAG_SET BIT_8 +#define BFLAG_SET FLAGPOS_B +#define HFLAG_SET BIT_3 +#define IFLAG_SET FLAGPOS_I +#define ZFLAG_SET 0 +#define CFLAG_SET BIT_8 +#define NZFLAG_CLEAR 1 +#define VFLAG_CLEAR 0 +#define PFLAG_CLEAR 0 +#define BFLAG_CLEAR 0 +#define HFLAG_CLEAR 0 +#define IFLAG_CLEAR 0 +#define CFLAG_CLEAR 0 + +#define NMI_SET 1 +#define NMI_CLEAR 0 +#define IRQ_SET IFLAG_CLEAR +#define IRQ_CLEAR IFLAG_SET + +#define STACK_PAGE 0x100 /* Stack Page Offset */ + +#define VECTOR_RST 0xfffe /* Reset */ +#define VECTOR_BRK 0xffde /* Break Instruction */ +#define VECTOR_IRQ 0xfffc /* IRQ ??? what is real vector? */ +#define VECTOR_NMI 0xfffa /* NMI ??? what is real vector? */ + +#define REG_A m_a /* Accumulator */ +#define REG_X m_x /* Index X Register */ +#define REG_Y m_y /* Index Y Register */ +#define REG_S m_s /* Stack Pointer */ +#define REG_PC m_pc /* Program Counter */ +#define REG_PPC m_ppc /* Previous Program Counter */ +#define REG_P m_p /* Processor Status Register */ +#define FLAG_NZ m_flag_n = m_flag_z /* Negative Flag and inverted Zero flag */ +#define FLAG_N m_flag_n /* Negative flag */ +#define FLAG_Z m_flag_z /* Inverted Zero flag */ +#define FLAG_V m_flag_v /* Overflow Flag */ +#define FLAG_P m_flag_p /* Direct Page Flag */ +#define FLAG_B m_flag_b /* BRK Instruction Flag */ +#define FLAG_H m_flag_h /* Decimal Mode Flag */ +#define FLAG_I m_flag_i /* Interrupt Mask Flag */ +#define FLAG_C m_flag_c /* Carry Flag */ +#define LINE_IRQ m_line_irq /* Status of the IRQ line */ +#define LINE_NMI m_line_nmi /* Status of the NMI line */ +#define REG_IR m_ir /* Instruction Register */ +#define CLOCKS m_ICount /* Clock cycles remaining */ +#define CPU_STOPPED m_stopped /* Stopped status */ + +#define SRC m_source /* Source Operand */ +#define DST m_destination /* Destination Operand */ +#define TMP1 m_temp1 /* temporary result 1 */ +#define TMP2 m_temp2 /* temporary result 2 */ +#define TMP3 m_temp3 /* temporary result 3 */ + +#define STOP_LEVEL_STOP 1 +#define STOP_LEVEL_SLEEP 2 + + +/* ======================================================================== */ +/* ============================ GENERAL MACROS ============================ */ +/* ======================================================================== */ + +/* Codition code tests */ +#define COND_CC() (!(FLAG_C&0x100)) /* Carry Clear */ +#define COND_CS() (FLAG_C&0x100) /* Carry Set */ +#define COND_EQ() (!FLAG_Z) /* Equal */ +#define COND_NE() (FLAG_Z) /* Not Equal */ +#define COND_MI() (FLAG_N&0x80) /* Minus */ +#define COND_PL() (!(FLAG_N&0x80)) /* Plus */ +#define COND_VC() (!(FLAG_V&0x80)) /* Overflow Clear */ +#define COND_VS() (FLAG_V&0x80) /* Overflow Set */ + +/* Set Overflow flag in math operations */ +#define VFLAG_ADD_8(S, D, R) ((S^R) & (D^R)) +#define VFLAG_ADD_16(S, D, R) (((S^R) & (D^R))>>8) +#define VFLAG_SUB_8(S, D, R) ((S^D) & (R^D)) +#define VFLAG_SUB_16(S, D, R) (((S^D) & (R^D))>>8) + +#define CFLAG_AS_1() ((FLAG_C>>8)&1) +#define CFLAG_AS_NOT_1() (!(FLAG_C&CFLAG_SET)) + +#define NZFLAG_16(A) (((A)&0x7f) | (((A)>>1)&0x40) | (((A)>>8)&0xff)) +#define CFLAG_16(A) ((A)>>8) + + +/* ======================================================================== */ +/* ================================= MAME ================================= */ +/* ======================================================================== */ + +#define spc700_read_8(addr) m_program->read_byte(addr) +#define spc700_write_8(addr,data) m_program->write_byte(addr,data) + +#define spc700_read_8_direct(A) spc700_read_8(A) +#define spc700_write_8_direct(A, V) spc700_write_8(A, V) +//#define spc700_read_instruction(A) memory_decrypted_read_byte(m_program,A) +//#define spc700_read_8_immediate(A) memory_raw_read_byte(m_program,A) +#define spc700_read_instruction(A) m_program->read_byte(A) +#define spc700_read_8_immediate(A) m_program->read_byte(A) +#define spc700_jumping(A) +#define spc700_branching(A) + + + +const device_type SPC700 = &device_creator; + + +spc700_device::spc700_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : cpu_device(mconfig, SPC700, "SPC700", tag, owner, clock, "spc700", __FILE__) + , m_program_config("program", ENDIANNESS_LITTLE, 8, 16, 0) + , m_a(0) + , m_x(0) + , m_y(0) + , m_s(0) + , m_pc(0) + , m_ppc(0) + , m_debugger_temp(0) +{ +} + + +/* ======================================================================== */ +/* ============================ UTILITY MACROS ============================ */ +/* ======================================================================== */ + +/* Use up clock cycles */ +#define CLK(A) CLOCKS -= (A) +#define CLK_ALL() CLOCKS = 0 + + +UINT32 spc700_device::read_8_normal(UINT32 address) +{ + address = MAKE_UINT_16(address); + return spc700_read_8(address); +} + +UINT32 spc700_device::read_8_immediate(UINT32 address) +{ + address = MAKE_UINT_16(address); + return spc700_read_8_immediate(address); +} + +UINT32 spc700_device::read_8_instruction(UINT32 address) +{ + address = MAKE_UINT_16(address); + return spc700_read_instruction(address); +} + +UINT32 spc700_device::read_8_direct(UINT32 address) +{ + address = MAKE_UINT_8(address) | FLAG_P; + return spc700_read_8_direct(address); +} + +void spc700_device::write_8_normal(UINT32 address, UINT32 value) +{ + address = MAKE_UINT_16(address); + value = MAKE_UINT_8(value); + spc700_write_8(address, value); +} + +void spc700_device::write_8_direct(UINT32 address, UINT32 value) +{ + address = MAKE_UINT_8(address) | FLAG_P; + value = MAKE_UINT_8(value); + spc700_write_8_direct(address, value); +} + + +UINT32 spc700_device::read_16_normal(UINT32 address) +{ + return read_8_normal(address) | (read_8_normal(address+1)<<8); +} + +UINT32 spc700_device::read_16_immediate(UINT32 address) +{ + return read_8_immediate(address) | (read_8_immediate(address+1)<<8); +} + +UINT32 spc700_device::read_16_direct(UINT32 address) +{ + return read_8_direct(address) | (read_8_direct(address+1)<<8); +} + +void spc700_device::write_16_direct(UINT32 address, UINT32 value) +{ + write_8_direct(address, value); + write_8_direct(address+1, value>>8); +} + +/* Low level memory access macros */ +#define read_8_NORM(A) read_8_normal(A) +#define read_8_IMM(A) read_8_immediate(A) +#define read_8_ABS(A) read_8_normal(A) +#define read_8_ABX(A) read_8_normal(A) +#define read_8_ABY(A) read_8_normal(A) +#define read_8_AXI(A) read_8_normal(A) +#define read_8_DP(A) read_8_direct(A) +#define read_8_DPX(A) read_8_direct(A) +#define read_8_DPY(A) read_8_direct(A) +#define read_8_DPI(A) read_8_normal(A) +#define read_8_DXI(A) read_8_normal(A) +#define read_8_DIY(A) read_8_normal(A) +#define read_8_STK(A) read_8_normal(A) +#define read_8_XI(A) read_8_direct(A) +#define read_8_XII(A) read_8_direct(A) +#define read_8_YI(A) read_8_direct(A) + + +#define read_16_NORM(A) read_16_normal(A) +#define read_16_IMM(A) read_16_immediate(A) +#define read_16_ABS(A) read_16_absolute(A) +#define read_16_ABX(A) read_16_normal(A) +#define read_16_DP(A) read_16_direct(A) +#define read_16_DPX(A) read_16_direct(A) +#define read_16_DPY(A) read_16_direct(A) +#define read_16_DPI(A) read_16_normal(A) +#define read_16_VEC(A) read_16_normal(A) +#define read_16_XI(A) read_16_direct(A) +#define read_16_XII(A) read_16_direct(A) +#define read_16_YI(A) read_16_direct(A) + +#define write_8_NORM(A, V) write_8_normal(A, V) +#define write_8_IMM(A, V) write_8_normal(A, V) +#define write_8_ABS(A, V) write_8_normal(A, V) +#define write_8_ABX(A, V) write_8_normal(A, V) +#define write_8_ABY(A, V) write_8_normal(A, V) +#define write_8_AXI(A, V) write_8_normal(A, V) +#define write_8_DP(A, V) write_8_direct(A, V) +#define write_8_DPX(A, V) write_8_direct(A, V) +#define write_8_DPY(A, V) write_8_direct(A, V) +#define write_8_DPI(A, V) write_8_normal(A, V) +#define write_8_DXI(A, V) write_8_normal(A, V) +#define write_8_DIY(A, V) write_8_normal(A, V) +#define write_8_STK(A, V) write_8_normal(A, V) +#define write_8_XI(A, V) write_8_direct(A, V) +#define write_8_XII(A, V) write_8_direct(A, V) +#define write_8_YI(A, V) write_8_direct(A, V) + +#define write_16_NORM(A, V) write_16_normal(A, V) +#define write_16_ABS(A, V) write_16_normal(A, V) +#define write_16_ABX(A, V) write_16_normal(A, V) +#define write_16_ABY(A, V) write_16_normal(A, V) +#define write_16_AXI(A, V) write_16_normal(A, V) +#define write_16_DP(A, V) write_16_direct(A, V) +#define write_16_DPX(A, V) write_16_direct(A, V) +#define write_16_DPY(A, V) write_16_direct(A, V) +#define write_16_DPI(A, V) write_16_normal(A, V) +#define write_16_DXI(A, V) write_16_normal(A, V) +#define write_16_DIY(A, V) write_16_normal(A, V) +#define write_16_STK(A, V) write_16_normal(A, V) +#define write_16_XI(A, V) write_16_direct(A, V) +#define write_16_XII(A, V) write_16_direct(A, V) +#define write_16_YI(A, V) write_16_direct(A, V) + + +#define OPER_8_IMM() read_8_IMM(EA_IMM()) +#define OPER_8_ABS() read_8_ABS(EA_ABS()) +#define OPER_8_ABX() read_8_ABX(EA_ABX()) +#define OPER_8_ABY() read_8_ABY(EA_ABY()) +#define OPER_8_AXI() read_8_IND(EA_IND()) +#define OPER_8_DP() read_8_DP(EA_DP()) +#define OPER_8_DPX() read_8_DPX(EA_DPX()) +#define OPER_8_DPY() read_8_DPY(EA_DPY()) +#define OPER_8_DPI() read_8_DPI(EA_DPI()) +#define OPER_8_DXI() read_8_DXI(EA_DXI()) +#define OPER_8_DIY() read_8_DIY(EA_DIY()) +#define OPER_8_XI() read_8_XI(EA_XI()) +#define OPER_8_XII() read_8_XI(EA_XII()) +#define OPER_8_YI() read_8_YI(EA_YI()) + +#define OPER_16_IMM() read_16_IMM(EA_IMM16()) +#define OPER_16_ABS() read_16_ABS(EA_ABS()) +#define OPER_16_ABX() read_16_ABX(EA_ABX()) +#define OPER_16_ABY() read_16_ABY(EA_ABY()) +#define OPER_16_AXI() read_16_IND(EA_IND()) +#define OPER_16_DP() read_16_DP(EA_DP()) +#define OPER_16_DPX() read_16_DPX(EA_DPX()) +#define OPER_16_DPY() read_16_DPY(EA_DPY()) +#define OPER_16_DPI() read_16_DPI(EA_DXI()) +#define OPER_16_DXI() read_16_DXI(EA_DXI()) +#define OPER_16_DIY() read_16_DIY(EA_DIY()) +#define OPER_16_XI() read_16_XI(EA_XI()) +#define OPER_16_XII() read_16_XI(EA_XII()) +#define OPER_16_YI() read_16_YI(EA_YI()) + +/* Effective Address Calculations */ +UINT32 spc700_device::EA_IMM() {return REG_PC++;} +UINT32 spc700_device::EA_IMM16() {REG_PC += 2; return REG_PC-2;} +UINT32 spc700_device::EA_ABS() {return OPER_16_IMM();} +UINT32 spc700_device::EA_ABX() {return EA_ABS() + REG_X;} +UINT32 spc700_device::EA_ABY() {return EA_ABS() + REG_Y;} +UINT32 spc700_device::EA_AXI() {return OPER_16_ABX();} +UINT32 spc700_device::EA_DP() {return OPER_8_IMM();} +UINT32 spc700_device::EA_DPX() {return (EA_DP() + REG_X)&0xff;} +UINT32 spc700_device::EA_DPY() {return (EA_DP() + REG_Y)&0xff;} +UINT32 spc700_device::EA_DXI() {return OPER_16_DPX();} +UINT32 spc700_device::EA_DIY() {UINT32 addr = OPER_16_DP(); if((addr&0xff00) != ((addr+REG_Y)&0xff00)) CLK(1); return addr + REG_Y;} +UINT32 spc700_device::EA_XI() {return REG_X;} +UINT32 spc700_device::EA_XII() {UINT32 val = REG_X;REG_X = MAKE_UINT_8(REG_X+1);return val;} +UINT32 spc700_device::EA_YI() {return REG_Y;} + + + +/* Change the Program Counter */ +void spc700_device::JUMP(UINT32 address) +{ + REG_PC = address; + spc700_jumping(REG_PC); +} + +void spc700_device::BRANCH(UINT32 offset) +{ + REG_PC = MAKE_UINT_16(REG_PC + MAKE_INT_8(offset)); + spc700_branching(REG_PC); +} + + +#define GET_REG_YA() (REG_A | (REG_Y<<8)) + +void spc700_device::SET_REG_YA(UINT32 value) +{ + REG_A = MAKE_UINT_8(value); + REG_Y = MAKE_UINT_8(value>>8); +} + +/* Get the Processor Status Register */ +#define GET_REG_P() \ + ((FLAG_N & 0x80) | \ + ((FLAG_V & 0x80) >> 1) | \ + (FLAG_P>>3) | \ + FLAG_B | \ + (FLAG_H& HFLAG_SET) | \ + FLAG_I | \ + ((!FLAG_Z) << 1) | \ + CFLAG_AS_1()) + +/* Set the Process Status Register */ +void spc700_device::SET_REG_P(UINT32 value) +{ + FLAG_N = (value & 0x80); + FLAG_Z = !(value & 2); + FLAG_V = value<<1; + FLAG_P = (value & FLAGPOS_P) << 3; + FLAG_B = value & FLAGPOS_B; + FLAG_H = value & HFLAG_SET; + FLAG_C = value << 8; + SET_FLAG_I(value); +} + +/* Push/Pull data to/from the stack */ +void spc700_device::PUSH_8(UINT32 value) +{ + write_8_STK(REG_S+STACK_PAGE, value); + REG_S = MAKE_UINT_8(REG_S - 1); +} + +UINT32 spc700_device::PULL_8() +{ + REG_S = MAKE_UINT_8(REG_S + 1); + return read_8_STK(REG_S+STACK_PAGE); +} + +void spc700_device::PUSH_16(UINT32 value) +{ + PUSH_8(value>>8); + PUSH_8(value); +} + +UINT32 spc700_device::PULL_16() +{ + UINT32 value = PULL_8(); + return value | (PULL_8()<<8); +} + +void spc700_device::CHECK_IRQ() +{ + if(FLAG_I & LINE_IRQ) + SERVICE_IRQ(); +} + +void spc700_device::SERVICE_IRQ() +{ + fatalerror("spc700: SERVICE_IRQ() not implemented yet!\n"); +} + + +void spc700_device::SET_FLAG_I(UINT32 value) +{ + FLAG_I = value & IFLAG_SET; +#if !SPC700_OPTIMIZE_SNES + CHECK_IRQ(); +#endif +} + +/* ======================================================================== */ +/* =========================== OPERATION MACROS =========================== */ +/* ======================================================================== */ + +#define SUBOP_ADC(A, B) \ + m_spc_int16 = (A) + (B) + CFLAG_AS_1(); \ + TMP1 = ((A) & 0x0f) + (CFLAG_AS_1()); \ + FLAG_C = (m_spc_int16 > 0xff) ? CFLAG_SET : 0; \ + FLAG_V = (~((A) ^ (B))) & (((A) ^ m_spc_int16) & 0x80); \ + FLAG_H = (((m_spc_int16 & 0x0f) - TMP1) & 0x10) >> 1; \ + FLAG_NZ = (UINT8)m_spc_int16 + + +/* Add With Carry */ +#define OP_ADC(BCLK, MODE) \ + CLK(BCLK); \ + SRC = OPER_8_##MODE(); \ + SUBOP_ADC(SRC, REG_A); \ + REG_A = (UINT8)m_spc_int16; + + +/* Add With Carry to memory */ +#define OP_ADCM(BCLK, SMODE, DMODE) \ + CLK(BCLK); \ + SRC = OPER_8_##SMODE(); \ + DST = EA_##DMODE(); \ + SUBOP_ADC(SRC, read_8_##DMODE(DST)); \ + write_8_##DMODE(DST, (UINT8)m_spc_int16) + +/* Add word */ +#define OP_ADDW(BCLK) \ + CLK(BCLK); \ + SRC = OPER_16_DP(); \ + DST = GET_REG_YA(); \ + TMP1 = ((SRC) & 0xff) + ((DST) & 0xff); \ + TMP2 = (TMP1 > 0xff) ? 1 : 0; \ + TMP3 = ((SRC) >> 8) + ((DST) >> 8) + TMP2; \ + m_spc_int16 = ((TMP1 & 0xff) + (TMP3 << 8)) & 0xffff; \ + FLAG_C = (TMP3 > 0xff) ? CFLAG_SET : 0; \ + FLAG_H = ((unsigned) ((((DST) >> 8) & 0x0F) + \ + (((SRC) >> 8) & 0x0F) + TMP2)) > 0x0F ? HFLAG_SET : 0; \ + FLAG_V = (~((DST) ^ (SRC)) & ((SRC) ^ (UINT16) m_spc_int16) & 0x8000) ? VFLAG_SET : 0; \ + FLAG_Z = (m_spc_int16 != 0); \ + FLAG_N = (m_spc_int16>>8); \ + SET_REG_YA(m_spc_int16); + +/* Logical AND with accumulator */ +#define OP_AND(BCLK, MODE) \ + CLK(BCLK); \ + FLAG_NZ = REG_A &= OPER_8_##MODE() + +/* Logical AND operand */ +#define OP_ANDM(BCLK, SMODE, DMODE) \ + CLK(BCLK); \ + FLAG_NZ = OPER_8_##SMODE(); \ + DST = EA_##DMODE(); \ + FLAG_NZ &= read_8_##DMODE(DST); \ + write_8_##DMODE(DST, FLAG_NZ) + +/* Logical AND bit to C */ +#define OP_AND1(BCLK) \ + CLK(BCLK); \ + DST = EA_IMM16(); \ + if(FLAG_C & CFLAG_SET) \ + { \ + DST = read_16_IMM(DST); \ + SRC = 1 << (DST >> 13); \ + DST &= 0x1fff; \ + if(!(read_8_NORM(DST) & SRC)) \ + FLAG_C = CFLAG_CLEAR; \ + } + +/* AND negated bit to C */ +#define OP_ANDN1(BCLK) \ + CLK(BCLK); \ + DST = EA_IMM16(); \ + if(FLAG_C & CFLAG_SET) \ + { \ + DST = read_16_IMM(DST); \ + SRC = 1 << (DST >> 13); \ + DST &= 0x1fff; \ + if(read_8_NORM(DST) & SRC) \ + FLAG_C = CFLAG_CLEAR; \ + } + +/* Arithmetic Shift Left accumulator */ +#define OP_ASL(BCLK) \ + CLK(BCLK); \ + FLAG_C = REG_A << 1; \ + FLAG_NZ = REG_A = MAKE_UINT_8(FLAG_C) + +/* Arithmetic Shift Left operand */ +#define OP_ASLM(BCLK, MODE) \ + CLK(BCLK); \ + DST = EA_##MODE(); \ + FLAG_C = read_8_##MODE(DST) << 1; \ + FLAG_NZ = MAKE_UINT_8(FLAG_C); \ + write_8_##MODE(DST, FLAG_NZ) + +/* Branch if Bit Reset */ +#define OP_BBC(BCLK, BIT) \ + CLK(BCLK); \ + SRC = OPER_8_DP(); \ + DST = OPER_8_IMM(); \ + if(!(SRC & BIT)) \ + { \ + CLK(2); \ + BRANCH(DST); \ + } + +/* Branch if Bit Set */ +#define OP_BBS(BCLK, BIT) \ + CLK(BCLK); \ + SRC = OPER_8_DP(); \ + DST = OPER_8_IMM(); \ + if(SRC & BIT) \ + { \ + CLK(2); \ + BRANCH(DST); \ + } + +/* Branch on Condition Code */ +#define OP_BCC(BCLK, COND) \ + CLK(BCLK); \ + DST = OPER_8_IMM(); \ + if(COND) \ + { \ + CLK(2); \ + BRANCH(DST); \ + } + +/* Branch Unconditional */ +/* speed up busy loops */ +#define OP_BRA(BCLK) \ + CLK(BCLK); \ + BRANCH(OPER_8_IMM()); \ + if(REG_PC == REG_PPC) \ + CLK_ALL() + +/* Cause a Break interrupt */ +#define OP_BRK(BCLK) \ + CLK(BCLK); \ + PUSH_16(REG_PC); \ + PUSH_8(GET_REG_P()); \ + FLAG_B |= FLAGPOS_B; \ + FLAG_I = IFLAG_CLEAR; \ + JUMP(read_16_VEC(VECTOR_BRK)) + +/* Call subroutine */ +#define OP_CALL(BCLK) \ + CLK(BCLK); \ + DST = EA_ABS(); \ + PUSH_16(REG_PC); \ + JUMP(DST) + +/* Compare accumulator and branch if not equal */ +#define OP_CBNE(BCLK, MODE) \ + CLK(BCLK); \ + SRC = OPER_8_##MODE(); \ + DST = EA_IMM(); \ + if(SRC != REG_A) \ + { \ + CLK(2); \ + BRANCH(read_8_IMM(DST)); \ + } + +/* Clear Carry flag */ +#define OP_CLRC(BCLK) \ + CLK(BCLK); \ + FLAG_C = CFLAG_CLEAR + +/* Clear Memory Bit */ +#define OP_CLR(BCLK, BIT) \ + CLK(BCLK); \ + DST = EA_DP(); \ + SRC = read_8_DP(DST) & ~BIT; \ + write_8_DP(DST, SRC) + +/* Clear Overflow flag (also clears half-carry) */ +#define OP_CLRV(BCLK) \ + CLK(BCLK); \ + FLAG_V = VFLAG_CLEAR; \ + FLAG_H = 0; + +/* Clear the Page flag */ +#define OP_CLRP(BCLK) \ + CLK(BCLK); \ + FLAG_P = PFLAG_CLEAR + +/* Compare operand to register */ +#define OP_CMPR(BCLK, REG, MODE) \ + CLK(BCLK); \ + SRC = OPER_8_##MODE(); \ + m_spc_int16 = (short)REG - (short)SRC; \ + FLAG_C = (m_spc_int16 >= 0) ? CFLAG_SET : 0; \ + FLAG_NZ = MAKE_UINT_8(m_spc_int16); + +/* Compare memory */ +#define OP_CMPM(BCLK, SMODE, DMODE) \ + CLK(BCLK); \ + SRC = OPER_8_##SMODE(); \ + m_spc_int16 = (short)OPER_8_##DMODE() - (short)SRC; \ + FLAG_C = (m_spc_int16 >= 0) ? CFLAG_SET : 0; \ + FLAG_NZ = MAKE_UINT_8(m_spc_int16); + +/* Compare word */ +#define OP_CMPW(BCLK, MODE) \ + CLK(BCLK); \ + SRC = OPER_16_##MODE(); \ + m_spc_int32 = (int)GET_REG_YA() - (int)SRC; \ + FLAG_C = (m_spc_int32 >= 0) ? CFLAG_SET : 0; \ + FLAG_NZ = NZFLAG_16(m_spc_int32); + +/* Decimal adjust for addition */ +#define OP_DAA(BCLK) \ + CLK(BCLK); \ + SRC = REG_A; \ + if (((SRC & 0x0f) > 9) || (FLAG_H & HFLAG_SET)) \ + { \ + REG_A += 6; \ + if (REG_A < 6) \ + { \ + FLAG_C = CFLAG_SET; \ + } \ + } \ + if ((SRC > 0x99) || (FLAG_C & CFLAG_SET)) \ + { \ + REG_A += 0x60; \ + FLAG_C = CFLAG_SET; \ + } \ + FLAG_NZ = REG_A = MAKE_UINT_8(REG_A); + +/* Decimal adjust for subtraction */ +#define OP_DAS(BCLK) \ + CLK(BCLK); \ + SRC = REG_A; \ + if (!(FLAG_H & HFLAG_SET) || ((SRC & 0xf) > 9)) \ + { \ + REG_A -= 6; \ + } \ + if (!(FLAG_C & CFLAG_SET) || (SRC > 0x99)) \ + { \ + REG_A -= 0x60; \ + FLAG_C = 0; \ + } \ + FLAG_NZ = REG_A = MAKE_UINT_8(REG_A) + +/* Decrement register and branch if not zero */ +/* speed up busy loops */ +#define OP_DBNZR(BCLK) \ + CLK(BCLK); \ + REG_Y = MAKE_UINT_8(REG_Y - 1); \ + DST = EA_IMM(); \ + if(REG_Y != 0) \ + { \ + CLK(2); \ + BRANCH(read_8_IMM(DST)); \ + } + +/* Decrement operand and branch if not zero */ +/* Speed up busy loops but do reads/writes for compatibility */ +#define OP_DBNZM(BCLK) \ + CLK(BCLK); \ + DST = EA_DP(); \ + SRC = MAKE_UINT_8(read_8_DP(DST) - 1); \ + write_8_DP(DST, SRC); \ + DST = EA_IMM(); \ + if(SRC != 0) \ + { \ + CLK(2); \ + BRANCH(read_8_IMM(DST)); \ + } + +/* Decrement register */ +#define OP_DECR(BCLK, REG) \ + CLK(BCLK); \ + FLAG_NZ = REG = MAKE_UINT_8(REG - 1) + +/* Decrement operand */ +#define OP_DECM(BCLK, MODE) \ + CLK(BCLK); \ + DST = EA_##MODE(); \ + FLAG_NZ = MAKE_UINT_8(read_8_##MODE(DST) - 1); \ + write_8_##MODE(DST, FLAG_NZ) + +/* Decrement word */ +#define OP_DECW(BCLK) \ + CLK(BCLK); \ + DST = EA_DP(); \ + FLAG_NZ = MAKE_UINT_16(read_16_DP(DST) - 1); \ + write_16_DP(DST, FLAG_Z); \ + FLAG_NZ = NZFLAG_16(FLAG_Z) + +/* Disable interrupts */ +#define OP_DI(BCLK) \ + CLK(BCLK); \ + FLAG_I = IFLAG_CLEAR + +/* Divide - should be almost exactly how the hardware works */ +#define OP_DIV(BCLK) \ + CLK(BCLK); \ + TMP1 = SRC = GET_REG_YA(); \ + TMP2 = (REG_X << 9); \ + FLAG_H = 0; \ + if ((REG_Y & 0xf) >= (REG_X & 0xf)) FLAG_H = HFLAG_SET; \ + for (TMP3 = 0; TMP3 < 9; TMP3++) \ + { \ + TMP1 <<= 1; \ + if (TMP1 & 0x20000) TMP1 = (TMP1 & 0x1ffff) | 1; \ + if (TMP1 >= TMP2) TMP1 ^= 1; \ + if (TMP1 & 1) TMP1 = ((TMP1 - TMP2) & 0x1ffff); \ + } \ + FLAG_V = (TMP1 & 0x100) ? VFLAG_SET : 0; \ + SET_REG_YA((((TMP1 >> 9) & 0xff) << 8) + (TMP1 & 0xff)); \ + FLAG_NZ = MAKE_UINT_8(GET_REG_YA()); + +/* Enable interrupts */ +#define OP_EI(BCLK) \ + CLK(BCLK); \ + FLAG_I = IFLAG_SET + +/* Exclusive Or operand to accumulator */ +#define OP_EOR(BCLK, MODE) \ + CLK(BCLK); \ + FLAG_NZ = REG_A ^= OPER_8_##MODE() + +/* Logical EOR operand */ +#define OP_EORM(BCLK, SMODE, DMODE) \ + CLK(BCLK); \ + FLAG_NZ = OPER_8_##SMODE(); \ + DST = EA_##DMODE(); \ + FLAG_NZ ^= read_8_##DMODE(DST); \ + write_8_##DMODE(DST, FLAG_NZ) + +/* Exclusive OR bit to C */ +#define OP_EOR1(BCLK) \ + CLK(BCLK); \ + DST = OPER_16_IMM(); \ + SRC = 1 << (DST >> 13); \ + DST &= 0x1fff; \ + if(read_8_NORM(DST) & SRC) \ + FLAG_C = ~FLAG_C + +/* Increment register */ +#define OP_INCR(BCLK, REG) \ + CLK(BCLK); \ + FLAG_NZ = REG = MAKE_UINT_8(REG + 1) + +/* Increment operand */ +#define OP_INCM(BCLK, MODE) \ + CLK(BCLK); \ + DST = EA_##MODE(); \ + FLAG_NZ = MAKE_UINT_8(read_8_##MODE(DST) + 1); \ + write_8_##MODE(DST, FLAG_NZ) + +/* Increment word */ +#define OP_INCW(BCLK) \ + CLK(BCLK); \ + DST = EA_DP(); \ + FLAG_NZ = MAKE_UINT_16(read_16_DP(DST) + 1); \ + write_16_DP(DST, FLAG_Z); \ + FLAG_NZ = NZFLAG_16(FLAG_Z) + +/* Jump */ +/* If we're in a busy loop, eat all clock cycles */ +#define OP_JMP(BCLK, MODE) \ + CLK(BCLK); \ + JUMP(EA_##MODE()); \ + if(REG_PC == REG_PPC) \ + CLK_ALL() + +/* Jump to Subroutine */ +#define OP_JSR(BCLK, MODE) \ + CLK(BCLK); \ + PUSH_16(REG_PC); \ + JUMP(EA_##MODE()) + +/* Logical Shift Right accumulator */ +#define OP_LSR(BCLK) \ + CLK(BCLK); \ + FLAG_C = REG_A << 8; \ + FLAG_NZ = REG_A >>= 1 + +/* Logical Shift Right operand */ +#define OP_LSRM(BCLK, MODE) \ + CLK(BCLK); \ + DST = EA_##MODE(); \ + FLAG_NZ = read_8_##MODE(DST); \ + FLAG_C = FLAG_NZ << 8; \ + FLAG_NZ >>= 1; \ + write_8_##MODE(DST, FLAG_NZ) + +/* Move from register to register */ +#define OP_MOVRR(BCLK, SREG, DREG) \ + CLK(BCLK); \ + FLAG_NZ = DREG = SREG + +/* Move from register to memory */ +#define OP_MOVRM(BCLK, SREG, DMODE) \ + CLK(BCLK); \ + write_8_##DMODE(EA_##DMODE(), SREG) + +/* Move from memory to register */ +#define OP_MOVMR(BCLK, SMODE, DREG) \ + CLK(BCLK); \ + FLAG_NZ = DREG = OPER_8_##SMODE() + +/* Move from memory to memory */ +#define OP_MOVMM(BCLK, SMODE, DMODE) \ + CLK(BCLK); \ + SRC = OPER_8_##SMODE(); \ + DST = EA_##DMODE(); \ + write_8_##DMODE(DST, SRC) + +/* Move word register to memory */ +#define OP_MOVWRM(BCLK) \ + CLK(BCLK); \ + write_16_DP(EA_DP(), GET_REG_YA()) + +/* Move word memory to register */ +#define OP_MOVWMR(BCLK) \ + CLK(BCLK); \ + FLAG_NZ = OPER_16_DP(); \ + SET_REG_YA(FLAG_Z); \ + FLAG_NZ = NZFLAG_16(FLAG_Z) + +/* Move from Stack pointer to X */ +#define OP_MOVSX(BCLK) \ + CLK(BCLK); \ + FLAG_NZ = REG_X = REG_S + +/* Move from X to Stack pointer */ +#define OP_MOVXS(BCLK) \ + CLK(BCLK); \ + REG_S = REG_X + +/* Move bit from memory to C */ +#define OP_MOV1C(BCLK) \ + CLK(BCLK); \ + DST = OPER_16_IMM(); \ + SRC = 1 << (DST >> 13); \ + DST &= 0x1fff; \ + FLAG_C = ((read_8_NORM(DST) & SRC) != 0) << 8 + +/* Move bit from C to memory */ +#define OP_MOV1M(BCLK) \ + CLK(BCLK); \ + DST = OPER_16_IMM(); \ + SRC = 1 << (DST >> 13); \ + DST &= 0x1fff; \ + if(FLAG_C & CFLAG_SET) \ + write_8_NORM(DST, read_8_NORM(DST) | SRC); \ + else \ + write_8_NORM(DST, read_8_NORM(DST) & ~SRC) + + +/* Multiply A and Y and store result in YA */ +#define OP_MUL(BCLK) \ + CLK(BCLK); \ + SRC = REG_Y * REG_A; \ + REG_A = MAKE_UINT_8(SRC); \ + FLAG_NZ = REG_Y = SRC >> 8; + +/* No Operation */ +#define OP_NOP(BCLK) \ + CLK(BCLK) + +/* Invert the C flag */ +#define OP_NOTC(BCLK) \ + CLK(BCLK); \ + FLAG_C = ~FLAG_C + +/* NOT bit */ +#define OP_NOT1(BCLK) \ + CLK(BCLK); \ + DST = OPER_16_IMM(); \ + SRC = 1 << (DST >> 13); \ + DST &= 0x1fff; \ + write_8_NORM(DST, read_8_NORM(DST) ^ SRC) + +/* Logical OR operand to accumulator */ +#define OP_OR(BCLK, MODE) \ + CLK(BCLK); \ + FLAG_NZ = REG_A |= OPER_8_##MODE() + +/* Logical OR operand */ +#define OP_ORM(BCLK, SMODE, DMODE) \ + CLK(BCLK); \ + FLAG_NZ = OPER_8_##SMODE(); \ + DST = EA_##DMODE(); \ + FLAG_NZ |= read_8_##DMODE(DST); \ + write_8_##DMODE(DST, FLAG_NZ) + +/* Logical OR bit to C */ +#define OP_OR1(BCLK) \ + CLK(BCLK); \ + DST = EA_IMM16(); \ + if(!(FLAG_C & CFLAG_SET)) \ + { \ + DST = read_16_IMM(DST); \ + SRC = 1 << (DST >> 13); \ + DST &= 0x1fff; \ + if(read_8_NORM(DST) & SRC) \ + FLAG_C = CFLAG_SET; \ + } + +/* OR negated bit to C */ +#define OP_ORN1(BCLK) \ + CLK(BCLK); \ + DST = EA_IMM16(); \ + if(!(FLAG_C & CFLAG_SET)) \ + { \ + DST = read_16_IMM(DST); \ + SRC = 1 << (DST >> 13); \ + DST &= 0x1fff; \ + if(!(read_8_NORM(DST) & SRC)) \ + FLAG_C = CFLAG_SET; \ + } + +/* UPage Call */ +#define OP_PCALL(BCLK) \ + CLK(BCLK); \ + DST = EA_DP(); \ + PUSH_16(REG_PC); \ + JUMP(0xff00 | DST) + +/* Push a register to the stack */ +#define OP_PUSH(BCLK, REG) \ + CLK(BCLK); \ + PUSH_8(REG) + +/* Push the Processor Status Register to the stack */ +#define OP_PHP(BCLK) \ + CLK(BCLK); \ + PUSH_8(GET_REG_P()) + +/* Pull a register from the stack */ +#define OP_PULL(BCLK, REG) \ + CLK(BCLK); \ + REG = PULL_8() + +/* Pull the Processor Status Register from the stack */ +#define OP_PLP(BCLK) \ + CLK(BCLK); \ + SET_REG_P(PULL_8()) + +/* Return from Subroutine */ +#define OP_RET(BCLK) \ + CLK(BCLK); \ + JUMP(PULL_16()) + +/* Return from Interrupt */ +#define OP_RETI(BCLK) \ + CLK(BCLK); \ + SET_REG_P(PULL_8()); \ + JUMP(PULL_16()) + +/* Rotate Left the accumulator */ +#define OP_ROL(BCLK) \ + CLK(BCLK); \ + FLAG_C = (REG_A<<1) | CFLAG_AS_1(); \ + FLAG_NZ = REG_A = MAKE_UINT_8(FLAG_C) + +/* Rotate Left an operand */ +#define OP_ROLM(BCLK, MODE) \ + CLK(BCLK); \ + DST = EA_##MODE(); \ + FLAG_C = (read_8_##MODE(DST)<<1) | CFLAG_AS_1(); \ + FLAG_NZ = MAKE_UINT_8(FLAG_C); \ + write_8_##MODE(DST, FLAG_NZ) + +/* Rotate Right the accumulator */ +#define OP_ROR(BCLK) \ + CLK(BCLK); \ + REG_A |= FLAG_C & 0x100; \ + FLAG_C = REG_A << 8; \ + FLAG_NZ = REG_A >>= 1 + +/* Rotate Right an operand */ +#define OP_RORM(BCLK, MODE) \ + CLK(BCLK); \ + DST = EA_##MODE(); \ + FLAG_NZ = read_8_##MODE(DST) | (FLAG_C & 0x100); \ + FLAG_C = FLAG_NZ << 8; \ + FLAG_NZ >>= 1; \ + write_8_##MODE(DST, FLAG_NZ) + +/* Subtract with Carry */ +#define OP_SBC(BCLK, MODE) \ + CLK(BCLK); \ + SRC = OPER_8_##MODE(); \ + TMP2 = REG_A - SRC - (CFLAG_AS_1() ^ 1); \ + SUBOP_ADC(REG_A, ~SRC); \ + FLAG_C = (TMP2 <= 0xff) ? CFLAG_SET : 0; \ + REG_A = (UINT8)m_spc_int16; + +/* Subtract With Carry to memory */ +#define OP_SBCM(BCLK, SMODE, DMODE) \ + CLK(BCLK); \ + SRC = OPER_8_##SMODE(); \ + DST = EA_##DMODE(); \ + TMP3 = read_8_##DMODE(DST); \ + TMP2 = TMP3 - SRC - (CFLAG_AS_1() ^ 1); \ + SUBOP_ADC(~SRC, TMP3); \ + FLAG_C = (TMP2 <= 0xff) ? CFLAG_SET : 0; \ + write_8_##DMODE(DST, (UINT8)m_spc_int16) + +/* Set Carry flag */ +#define OP_SETC(BCLK) \ + CLK(BCLK); \ + FLAG_C = CFLAG_SET + +/* Set Page flag */ +#define OP_SETP(BCLK) \ + CLK(BCLK); \ + FLAG_P = PFLAG_SET + +/* Set Memory Bit */ +#define OP_SET(BCLK, BIT) \ + CLK(BCLK); \ + DST = EA_DP(); \ + SRC = read_8_DP(DST) | BIT; \ + write_8_DP(DST, SRC) + +/* Put the CPU to sleep */ +#define OP_SLEEP(BCLK) \ + CLK(BCLK); \ + CPU_STOPPED |= STOP_LEVEL_SLEEP; \ + CLK_ALL() + +/* Stop the CPU */ +#define OP_STOP(BCLK) \ + CLK(BCLK); \ + CPU_STOPPED |= STOP_LEVEL_STOP; \ + CLK_ALL() + +/* Subtract word */ +#define OP_SUBW(BCLK) \ + CLK(BCLK); \ + SRC = OPER_16_DP(); \ + DST = GET_REG_YA(); \ + TMP1 = ((DST) & 0xff) - ((SRC) & 0xff); \ + TMP2 = (TMP1 > 0xff) ? 1 : 0; \ + TMP3 = ((DST) >> 8) - ((SRC) >> 8) - TMP2; \ + m_spc_int16 = ((TMP1 & 0xff) + (TMP3 << 8)) & 0xffff; \ + FLAG_C = (TMP3 <= 0xff) ? CFLAG_SET : 0; \ + FLAG_H = ((unsigned) ((((DST) >> 8) & 0x0F) - \ + (((SRC) >> 8) & 0x0F) - TMP2)) > 0x0F ? 0: HFLAG_SET; \ + FLAG_V = (((DST) ^ (SRC)) & ((DST) ^ (UINT16) m_spc_int16) & 0x8000) ? VFLAG_SET : 0; \ + FLAG_Z = (m_spc_int16 != 0); \ + FLAG_N = (m_spc_int16>>8); \ + SET_REG_YA(m_spc_int16); + +/* Table Call */ +#define OP_TCALL(BCLK, NUM) \ + CLK(BCLK); \ + PUSH_16(REG_PC); \ + JUMP(read_16_NORM(0xffc0 + ((15-NUM)<<1))) + +/* Test and Clear Bits */ +#define OP_TCLR1(BCLK, MODE) \ + CLK(BCLK); \ + DST = EA_##MODE(); \ + FLAG_NZ = read_8_##MODE(DST); \ + write_8_##MODE(DST, FLAG_NZ & ~REG_A); \ + FLAG_NZ &= REG_A + +/* Test and Set Bits */ +#define OP_TSET1(BCLK, MODE) \ + CLK(BCLK); \ + DST = EA_##MODE(); \ + FLAG_NZ = read_8_##MODE(DST); \ + write_8_##MODE(DST, FLAG_NZ | REG_A); \ + FLAG_NZ &= REG_A + +/* Exchange high and low nybbles of accumulator */ +#define OP_XCN(BCLK) \ + CLK(BCLK); \ + FLAG_NZ = REG_A = MAKE_UINT_8((REG_A<<4) | (REG_A>>4)) + +#define OP_ILLEGAL(BCLK) \ + CLK(BCLK) + + +/* ======================================================================== */ +/* ================================= API ================================== */ +/* ======================================================================== */ + +void spc700_device::device_start() +{ + m_program = &space(AS_PROGRAM); + + save_item(NAME(m_a)); + save_item(NAME(m_x)); + save_item(NAME(m_y)); + save_item(NAME(m_s)); + save_item(NAME(m_pc)); + save_item(NAME(m_ppc)); + save_item(NAME(m_flag_n)); + save_item(NAME(m_flag_z)); + save_item(NAME(m_flag_v)); + save_item(NAME(m_flag_p)); + save_item(NAME(m_flag_b)); + save_item(NAME(m_flag_h)); + save_item(NAME(m_flag_i)); + save_item(NAME(m_flag_c)); + save_item(NAME(m_line_irq)); + save_item(NAME(m_line_nmi)); + save_item(NAME(m_line_rst)); + save_item(NAME(m_ir)); + save_item(NAME(m_stopped)); + save_item(NAME(m_ICount)); + save_item(NAME(m_source)); + save_item(NAME(m_destination)); + save_item(NAME(m_temp1)); + save_item(NAME(m_temp2)); + save_item(NAME(m_temp3)); + save_item(NAME(m_spc_int16)); + save_item(NAME(m_spc_int32)); + + // Register state for debugger + state_add( SPC700_PC, "PC", m_pc ).formatstr("%04X"); + state_add( SPC700_S, "S", m_s ).formatstr("%02X"); + state_add( SPC700_P, "P", m_debugger_temp ).callimport().callexport().formatstr("%02X"); + state_add( SPC700_A, "A", m_a ).formatstr("%02X"); + state_add( SPC700_X, "X", m_x ).formatstr("%02X"); + state_add( SPC700_Y, "Y", m_y ).formatstr("%02X"); + + state_add(STATE_GENPC, "curpc", m_pc).formatstr("%04X").noshow(); + state_add(STATE_GENSP, "GENSP", m_debugger_temp).mask(0x1ff).callexport().formatstr("%04X").noshow(); + state_add(STATE_GENFLAGS, "GENFLAGS", m_debugger_temp).formatstr("%8s").noshow(); + state_add(STATE_GENPCBASE, "GENPCBASE", m_ppc).formatstr("%04X").noshow(); + + m_icountptr = &m_ICount; +} + + +void spc700_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + switch (entry.index()) + { + case STATE_GENFLAGS: + strprintf(str, "%c%c%c%c%c%c%c%c", + (m_flag_n & 0x80) ? 'N':'.', + ((m_flag_v & 0x80) >> 1) ? 'V':'.', + (m_flag_p>>3) ? 'P':'.', + (m_flag_b) ? 'B':'.', + (m_flag_h & HFLAG_SET) ? 'H':'.', + ( m_flag_i) ? 'I':'.', + ((!m_flag_z) << 1) ? 'Z':'.', + ((m_flag_c >> 8)&1) ? 'C':'.' + ); + break; + } +} + + +void spc700_device::state_import(const device_state_entry &entry) +{ + switch (entry.index()) + { + case SPC700_P: + SET_REG_P(m_debugger_temp); + break; + } +} + + +void spc700_device::state_export(const device_state_entry &entry) +{ + switch (entry.index()) + { + case SPC700_P: + m_debugger_temp = ((m_flag_n & 0x80) | + ((m_flag_v & 0x80) >> 1) | + m_flag_p>>3 | + m_flag_b | + (m_flag_h & HFLAG_SET) | + m_flag_i | + ((!m_flag_z) << 1) | + ((m_flag_c >> 8)&1)); + break; + + case STATE_GENSP: + m_debugger_temp = m_s + STACK_PAGE; + break; + } +} + + +void spc700_device::device_reset() +{ + CPU_STOPPED = 0; + LINE_IRQ = 0; + LINE_NMI = 0; + REG_S = 0; + FLAG_NZ = NZFLAG_CLEAR; + FLAG_V = VFLAG_CLEAR; + FLAG_P = PFLAG_CLEAR; + FLAG_B = BFLAG_CLEAR; + FLAG_H = HFLAG_CLEAR; + FLAG_I = IFLAG_CLEAR; + FLAG_C = CFLAG_CLEAR; + JUMP(read_16_VEC(VECTOR_RST)); +} + + +void spc700_device::execute_set_input( int inptnum, int state ) +{ + if ( inptnum == INPUT_LINE_NMI ) + { + /* Assert or clear the NMI line of the CPU */ +#if !SPC700_OPTIMIZE_SNES + if(state == CLEAR_LINE) + LINE_NMI = 0; + else if(!LINE_NMI) + { + LINE_NMI = 1; + CLK(7); + PUSH_16(REG_PC); + PUSH_8(GET_REG_P()); + JUMP(read_16_VEC(VECTOR_NMI)); + } +#endif /* SPC700_OPTIMIZE_SNES */ + } + else + { + /* Assert or clear the IRQ line of the CPU */ +#if !SPC700_OPTIMIZE_SNES + LINE_IRQ = (state != CLEAR_LINE) ? IRQ_SET : IRQ_CLEAR; + CHECK_IRQ(); +#endif /* SPC700_OPTIMIZE_SNES */ + } +} + +#include "spc700ds.h" + +offs_t spc700_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + return CPU_DISASSEMBLE_NAME(spc700)(this, buffer, pc, oprom, opram, options); +} + +//int dump_flag = 0; + +/* Execute instructions for cycles */ +void spc700_device::execute_run() +{ + if (CPU_STOPPED) + { + CLOCKS = 0; + return; + } + while(CLOCKS > 0) + { + REG_PPC = REG_PC; + debugger_instruction_hook(this, REG_PC); + REG_PC++; + + switch(REG_IR = read_8_immediate(REG_PPC)) + { + case 0x00: OP_NOP ( 2 ); break; /* NOP */ + case 0x01: OP_TCALL ( 8, 0 ); break; /* TCALL 0 */ + case 0x02: OP_SET ( 4, BIT_0 ); break; /* SET 0 */ + case 0x03: OP_BBS ( 5, BIT_0 ); break; /* BBS 0 */ + + case 0x04: OP_OR ( 3, DP ); break; /* ORA dp */ + case 0x05: OP_OR ( 4, ABS ); break; /* ORA abs */ + case 0x06: OP_OR ( 3, XI ); break; /* ORA xi */ + case 0x07: OP_OR ( 6, DXI ); break; /* ORA dxi */ + + case 0x08: OP_OR ( 2, IMM ); break; /* ORA imm */ + case 0x09: OP_ORM ( 6, DP , DP ); break; /* ORM dp dp */ + case 0x0a: OP_OR1 ( 5 ); break; /* OR1 bit */ + case 0x0b: OP_ASLM ( 4, DP ); break; /* ASL dp */ + + case 0x0c: OP_ASLM ( 5, ABS ); break; /* ASL abs */ + case 0x0d: OP_PHP ( 4 ); break; /* PHP */ + case 0x0e: OP_TSET1 ( 6, ABS ); break; /* TSET1 abs */ + case 0x0f: OP_BRK ( 8 ); break; /* BRK */ + + case 0x10: OP_BCC ( 2, COND_PL() ); break; /* BPL */ + case 0x11: OP_TCALL ( 8, 1 ); break; /* TCALL 1 */ + case 0x12: OP_CLR ( 4, BIT_0 ); break; /* CLR 0 */ + case 0x13: OP_BBC ( 5, BIT_0 ); break; /* BBC 0 */ + + case 0x14: OP_OR ( 4, DPX ); break; /* ORA dpx */ + case 0x15: OP_OR ( 5, ABX ); break; /* ORA abx */ + case 0x16: OP_OR ( 5, ABY ); break; /* ORA aby */ + case 0x17: OP_OR ( 6, DIY ); break; /* ORA diy */ + + case 0x18: OP_ORM ( 5, IMM, DP ); break; /* ORM dp, imm */ + case 0x19: OP_ORM ( 5, YI, XI ); break; /* ORM xi, yi */ + case 0x1a: OP_DECW ( 6 ); break; /* DECW di */ + case 0x1b: OP_ASLM ( 5, DPX ); break; /* ASL dpx */ + + case 0x1c: OP_ASL ( 2 ); break; /* ASL a */ + case 0x1d: OP_DECR ( 2, REG_X ); break; /* DEC x */ + case 0x1e: OP_CMPR ( 4, REG_X, ABS ); break; /* CMP x, abs */ + case 0x1f: OP_JMP ( 6, AXI ); break; /* JMP axi */ + + case 0x20: OP_CLRP ( 2 ); break; /* CLRP */ + case 0x21: OP_TCALL ( 8, 2 ); break; /* TCALL 2 */ + case 0x22: OP_SET ( 4, BIT_1 ); break; /* SET 1 */ + case 0x23: OP_BBS ( 5, BIT_1 ); break; /* BBS 1 */ + + case 0x24: OP_AND ( 3, DP ); break; /* AND dp */ + case 0x25: OP_AND ( 4, ABS ); break; /* AND abs */ + case 0x26: OP_AND ( 3, XI ); break; /* AND xi */ + case 0x27: OP_AND ( 6, DXI ); break; /* AND dxi */ + + case 0x28: OP_AND ( 2, IMM ); break; /* AND imm */ + case 0x29: OP_ANDM ( 6, DP , DP ); break; /* AND dp, dp */ + case 0x2a: OP_ORN1 ( 5 ); break; /* OR1 !bit */ + case 0x2b: OP_ROLM ( 4, DP ); break; /* ROL dp */ + + case 0x2c: OP_ROLM ( 5, ABS ); break; /* ROL abs */ + case 0x2d: OP_PUSH ( 4, REG_A ); break; /* PUSH a */ + case 0x2e: OP_CBNE ( 5, DP ); break; /* CBNE dp */ + case 0x2f: OP_BRA ( 4 ); break; /* BRA */ + + case 0x30: OP_BCC ( 2, COND_MI() ); break; /* BMI */ + case 0x31: OP_TCALL ( 8, 3 ); break; /* TCALL 3 */ + case 0x32: OP_CLR ( 4, BIT_1 ); break; /* CLR 1 */ + case 0x33: OP_BBC ( 5, BIT_1 ); break; /* BBC 1 */ + + case 0x34: OP_AND ( 4, DPX ); break; /* AND dpx */ + case 0x35: OP_AND ( 5, ABX ); break; /* AND abx */ + case 0x36: OP_AND ( 5, ABY ); break; /* AND aby */ + case 0x37: OP_AND ( 6, DIY ); break; /* AND diy */ + + case 0x38: OP_ANDM ( 5, IMM, DP ); break; /* AND dp, imm */ + case 0x39: OP_ANDM ( 5, YI , XI ); break; /* AND xi, yi */ + case 0x3a: OP_INCW ( 6 ); break; /* INCW di */ + case 0x3b: OP_ROLM ( 5, DPX ); break; /* ROL dpx */ + + case 0x3c: OP_ROL ( 2 ); break; /* ROL acc */ + case 0x3d: OP_INCR ( 2, REG_X ); break; /* INC x */ + case 0x3e: OP_CMPR ( 3, REG_X, DP ); break; /* CMP x, dp */ + case 0x3f: OP_CALL ( 8 ); break; /* CALL abs */ + + case 0x40: OP_SETP ( 2 ); break; /* RTI */ + case 0x41: OP_TCALL ( 8, 4 ); break; /* TCALL 4 */ + case 0x42: OP_SET ( 4, BIT_2 ); break; /* SET 2 */ + case 0x43: OP_BBS ( 5, BIT_2 ); break; /* BBS 2 */ + + case 0x44: OP_EOR ( 3, DP ); break; /* EOR dp */ + case 0x45: OP_EOR ( 4, ABS ); break; /* EOR abs */ + case 0x46: OP_EOR ( 3, XI ); break; /* EOR xi */ + case 0x47: OP_EOR ( 6, DXI ); break; /* EOR dxi */ + + case 0x48: OP_EOR ( 2, IMM ); break; /* EOR imm */ + case 0x49: OP_EORM ( 6, DP, DP ); break; /* EOR dp, dp */ + case 0x4a: OP_AND1 ( 4 ); break; /* AND1 bit */ + case 0x4b: OP_LSRM ( 4, DP ); break; /* LSR dp */ + + case 0x4c: OP_LSRM ( 5, ABS ); break; /* LSR abs */ + case 0x4d: OP_PUSH ( 4, REG_X ); break; /* PUSH x */ + case 0x4e: OP_TCLR1 ( 6, ABS ); break; /* TCLR1 abs */ + case 0x4f: OP_PCALL ( 6 ); break; /* PCALL */ + + case 0x50: OP_BCC ( 2, COND_VC() ); break; /* BVC */ + case 0x51: OP_TCALL ( 8, 5 ); break; /* TCALL 5 */ + case 0x52: OP_CLR ( 4, BIT_2 ); break; /* CLR 2 */ + case 0x53: OP_BBC ( 5, BIT_2 ); break; /* BBC 2 */ + + case 0x54: OP_EOR ( 4, DPX ); break; /* EOR dpx */ + case 0x55: OP_EOR ( 5, ABX ); break; /* EOR abx */ + case 0x56: OP_EOR ( 5, ABY ); break; /* EOR aby */ + case 0x57: OP_EOR ( 6, DIY ); break; /* EOR diy */ + + case 0x58: OP_EORM ( 5, IMM, DP ); break; /* EOR dp, imm */ + case 0x59: OP_EORM ( 5, YI , XI ); break; /* EOR xi, yi */ + case 0x5a: OP_CMPW ( 4, DP ); break; /* CMPW dp */ + case 0x5b: OP_LSRM ( 5, DPX ); break; /* LSR dpx */ + + case 0x5c: OP_LSR ( 2 ); break; /* LSR */ + case 0x5d: OP_MOVRR ( 2, REG_A, REG_X ); break; /* MOV X, A */ + case 0x5e: OP_CMPR ( 4, REG_Y, ABS ); break; /* CMP Y, abs */ + case 0x5f: OP_JMP ( 3, ABS ); break; /* JMP abs */ + + case 0x60: OP_CLRC ( 2 ); break; /* CLRC */ + case 0x61: OP_TCALL ( 8, 6 ); break; /* TCALL 6 */ + case 0x62: OP_SET ( 4, BIT_3 ); break; /* SET 3 */ + case 0x63: OP_BBS ( 5, BIT_3 ); break; /* BBS 3 */ + + case 0x64: OP_CMPR ( 3, REG_A, DP ); break; /* CMP A, dp */ + case 0x65: OP_CMPR ( 4, REG_A, ABS ); break; /* CMP A, abs */ + case 0x66: OP_CMPR ( 3, REG_A, XI ); break; /* CMP A, xi */ + case 0x67: OP_CMPR ( 6, REG_A, DXI ); break; /* CMP A, dxi */ + + case 0x68: OP_CMPR ( 2, REG_A, IMM ); break; /* CMP A, imm */ + case 0x69: OP_CMPM ( 6, DP, DP ); break; /* CMP dp, dp */ + case 0x6a: OP_ANDN1 ( 4 ); break; /* AND1 !bit */ + case 0x6b: OP_RORM ( 4, DP ); break; /* ROR dp */ + + case 0x6c: OP_RORM ( 5, ABS ); break; /* ROR abs */ + case 0x6d: OP_PUSH ( 4, REG_Y ); break; /* PUSH Y */ + case 0x6e: OP_DBNZM ( 5 ); break; /* DBNZ dp */ + case 0x6f: OP_RET ( 5 ); break; /* RET */ + + case 0x70: OP_BCC ( 2, COND_VS() ); break; /* BVS */ + case 0x71: OP_TCALL ( 8, 7 ); break; /* TCALL 7 */ + case 0x72: OP_CLR ( 4, BIT_3 ); break; /* CLR 3 */ + case 0x73: OP_BBC ( 5, BIT_3 ); break; /* BBC 3 */ + case 0x74: OP_CMPR ( 4, REG_A, DPX ); break; /* CMP A, dpx */ + case 0x75: OP_CMPR ( 5, REG_A, ABX ); break; /* CMP A, abx */ + case 0x76: OP_CMPR ( 5, REG_A, ABY ); break; /* CMP A, aby */ + case 0x77: OP_CMPR ( 6, REG_A, DIY ); break; /* CMP A, diy */ + + case 0x78: OP_CMPM ( 5, IMM, DP ); break; /* CMP dp, imm */ + case 0x79: OP_CMPM ( 5, YI, XI ); break; /* CMP xi, yi */ + case 0x7a: OP_ADDW ( 5 ); break; /* ADDW di */ + case 0x7b: OP_RORM ( 5, DPX ); break; /* ROR dpx */ + + case 0x7c: OP_ROR ( 2 ); break; /* ROR A */ + case 0x7d: OP_MOVRR ( 2, REG_X, REG_A ); break; /* MOV A, X */ + case 0x7e: OP_CMPR ( 3, REG_Y, DP ); break; /* CMP Y, dp */ + case 0x7f: OP_RETI ( 6 ); break; /* RETI */ + + case 0x80: OP_SETC ( 2 ); break; /* SETC */ + case 0x81: OP_TCALL ( 8, 8 ); break; /* TCALL 8 */ + case 0x82: OP_SET ( 4, BIT_4 ); break; /* SET 4 */ + case 0x83: OP_BBS ( 5, BIT_4 ); break; /* BBS 4 */ + + case 0x84: OP_ADC ( 3, DP ); break; /* ADC dp */ + case 0x85: OP_ADC ( 4, ABS ); break; /* ADC abs */ + case 0x86: OP_ADC ( 3, XI ); break; /* ADC xi */ + case 0x87: OP_ADC ( 6, DXI ); break; /* ADC dxi */ + + case 0x88: OP_ADC ( 2, IMM ); break; /* ADC imm */ + case 0x89: OP_ADCM ( 6, DP, DP ); break; /* ADC dp, dp */ + case 0x8a: OP_EOR1 ( 5 ); break; /* EOR1 bit */ + case 0x8b: OP_DECM ( 4, DP ); break; /* DEC dp */ + + case 0x8c: OP_DECM ( 5, ABS ); break; /* DEC abs */ + case 0x8d: OP_MOVMR ( 2, IMM, REG_Y ); break; /* MOV Y, imm */ + case 0x8e: OP_PLP ( 4 ); break; /* POP PSW */ + case 0x8f: OP_MOVMM ( 5, IMM, DP ); break; /* MOV dp, imm */ + + case 0x90: OP_BCC ( 2, COND_CC() ); break; /* BCC */ + case 0x91: OP_TCALL ( 8, 9 ); break; /* TCALL 9 */ + case 0x92: OP_CLR ( 4, BIT_4 ); break; /* CLR 4 */ + case 0x93: OP_BBC ( 5, BIT_4 ); break; /* BBC 4 */ + + case 0x94: OP_ADC ( 4, DPX ); break; /* ADC dpx */ + case 0x95: OP_ADC ( 5, ABX ); break; /* ADC abx */ + case 0x96: OP_ADC ( 5, ABY ); break; /* ADC aby */ + case 0x97: OP_ADC ( 6, DIY ); break; /* ADC diy */ + + case 0x98: OP_ADCM ( 5, IMM, DP ); break; /* ADC dp, imm */ + case 0x99: OP_ADCM ( 5, YI, XI ); break; /* ADC xi, yi */ + case 0x9a: OP_SUBW ( 5 ); break; /* SUBW dp */ + case 0x9b: OP_DECM ( 5, DPX ); break; /* DEC dpx */ + + case 0x9c: OP_DECR ( 2, REG_A ); break; /* DEC A */ + case 0x9d: OP_MOVSX ( 2 ); break; /* MOV X, SP */ + case 0x9e: OP_DIV (12 ); break; /* DIV YA, X */ + case 0x9f: OP_XCN ( 5 ); break; /* XCN A */ + + case 0xa0: OP_EI ( 3 ); break; /* EI */ + case 0xa1: OP_TCALL ( 8, 10 ); break; /* TCALL 10 */ + case 0xa2: OP_SET ( 4, BIT_5 ); break; /* SET 5 */ + case 0xa3: OP_BBS ( 5, BIT_5 ); break; /* BBS 5 */ + + case 0xa4: OP_SBC ( 3, DP ); break; /* SBC dp */ + case 0xa5: OP_SBC ( 4, ABS ); break; /* SBC abs */ + case 0xa6: OP_SBC ( 3, XI ); break; /* SBC xi */ + case 0xa7: OP_SBC ( 6, DXI ); break; /* SBC dxi */ + + case 0xa8: OP_SBC ( 2, IMM ); break; /* SBC imm */ + case 0xa9: OP_SBCM ( 6, DP, DP ); break; /* SBC dp, dp */ + case 0xaa: OP_MOV1C ( 4 ); break; /* MOV1 bit->C */ + case 0xab: OP_INCM ( 4, DP ); break; /* INC dp */ + + case 0xac: OP_INCM ( 5, ABS ); break; /* INC abs */ + case 0xad: OP_CMPR ( 2, REG_Y, IMM ); break; /* CMP Y, imm */ + case 0xae: OP_PULL ( 4, REG_A ); break; /* POP A */ + case 0xaf: OP_MOVRM ( 4, REG_A, XII ); break; /* MOV xii, A */ + + case 0xb0: OP_BCC ( 2, COND_CS() ); break; /* BCS */ + case 0xb1: OP_TCALL ( 8, 11 ); break; /* TCALL 11 */ + case 0xb2: OP_CLR ( 4, BIT_5 ); break; /* CLR 5 */ + case 0xb3: OP_BBC ( 5, BIT_5 ); break; /* BBC 5 */ + + case 0xb4: OP_SBC ( 4, DPX ); break; /* SBC dpx */ + case 0xb5: OP_SBC ( 5, ABX ); break; /* SBC abx */ + case 0xb6: OP_SBC ( 5, ABY ); break; /* SBC aby */ + case 0xb7: OP_SBC ( 6, DIY ); break; /* SBC diy */ + + case 0xb8: OP_SBCM ( 5, IMM, DP ); break; /* SBC dp, imm */ + case 0xb9: OP_SBCM ( 5, YI, XI ); break; /* SBC xi, yi */ + case 0xba: OP_MOVWMR( 5 ); break; /* MOVW YA, dp */ + case 0xbb: OP_INCM ( 5, DPX ); break; /* INC dpx */ + + case 0xbc: OP_INCR ( 2, REG_A ); break; /* INC A */ + case 0xbd: OP_MOVXS ( 2 ); break; /* MOV SP, X */ + case 0xbe: OP_DAS ( 3 ); break; /* DAS A */ + case 0xbf: OP_MOVMR ( 4, XII, REG_A ); break; /* MOV A, xii */ + + case 0xc0: OP_DI ( 3 ); break; /* DI */ + case 0xc1: OP_TCALL ( 8, 12 ); break; /* TCALL 12 */ + case 0xc2: OP_SET ( 4, BIT_6 ); break; /* SET 6 */ + case 0xc3: OP_BBS ( 5, BIT_6 ); break; /* BBS 6 */ + case 0xc4: OP_MOVRM ( 4, REG_A, DP ); break; /* MOV dp, A */ + case 0xc5: OP_MOVRM ( 5, REG_A, ABS ); break; /* MOV abs, A */ + case 0xc6: OP_MOVRM ( 4, REG_A, XI ); break; /* MOV xi, A */ + case 0xc7: OP_MOVRM ( 7, REG_A, DXI ); break; /* MOV dxi, A */ + + case 0xc8: OP_CMPR ( 2, REG_X, IMM ); break; /* CMP X, imm */ + case 0xc9: OP_MOVRM ( 5, REG_X, ABS ); break; /* MOV abs, X */ + case 0xca: OP_MOV1M ( 6 ); break; /* MOV1 C->bit */ + case 0xcb: OP_MOVRM ( 4, REG_Y, DP ); break; /* MOV dp, Y */ + + case 0xcc: OP_MOVRM ( 5, REG_Y, ABS ); break; /* MOV abs, Y */ + case 0xcd: OP_MOVMR ( 2, IMM, REG_X ); break; /* MOV X, imm */ + case 0xce: OP_PULL ( 4, REG_X ); break; /* POP X */ + case 0xcf: OP_MUL ( 9 ); break; /* MUL YA */ + + case 0xd0: OP_BCC ( 2, COND_NE() ); break; /* BNE */ + case 0xd1: OP_TCALL ( 8, 13 ); break; /* TCALL 13 */ + case 0xd2: OP_CLR ( 4, BIT_6 ); break; /* CLR 6 */ + case 0xd3: OP_BBC ( 5, BIT_6 ); break; /* BBC 6 */ + + case 0xd4: OP_MOVRM ( 5, REG_A, DPX ); break; /* MOV dpx, A */ + case 0xd5: OP_MOVRM ( 6, REG_A, ABX ); break; /* MOV abx, A */ + case 0xd6: OP_MOVRM ( 6, REG_A, ABY ); break; /* MOV aby, A */ + case 0xd7: OP_MOVRM ( 7, REG_A, DIY ); break; /* MOV diy, A */ + + case 0xd8: OP_MOVRM ( 4, REG_X, DP ); break; /* MOV dp, X */ + case 0xd9: OP_MOVRM ( 5, REG_X, DPY ); break; /* MOV dpy, X */ + case 0xda: OP_MOVWRM( 5 ); break; /* MOVW dp, YA */ + case 0xdb: OP_MOVRM ( 5, REG_Y, DPX ); break; /* MOV dpx, Y */ + + case 0xdc: OP_DECR ( 2, REG_Y ); break; /* DEC Y */ + case 0xdd: OP_MOVRR ( 2, REG_Y, REG_A ); break; /* MOV A, Y */ + case 0xde: OP_CBNE ( 6, DPX ); break; /* CBNE dpx */ + case 0xdf: OP_DAA ( 3 ); break; /* DAA */ + + case 0xe0: OP_CLRV ( 2 ); break; /* CLRV */ + case 0xe1: OP_TCALL ( 8, 14 ); break; /* TCALL 14 */ + case 0xe2: OP_SET ( 4, BIT_7 ); break; /* SET 7 */ + case 0xe3: OP_BBS ( 5, BIT_7 ); break; /* BBS 7 */ + + case 0xe4: OP_MOVMR ( 3, DP, REG_A ); break; /* MOV A, dp */ + case 0xe5: OP_MOVMR ( 4, ABS, REG_A ); break; /* MOV A, abs */ + case 0xe6: OP_MOVMR ( 3, XI, REG_A ); break; /* MOV A, xi */ + case 0xe7: OP_MOVMR ( 6, DXI, REG_A ); break; /* MOV A, dxi */ + + case 0xe8: OP_MOVMR ( 2, IMM, REG_A ); break; /* CMP A, imm */ + case 0xe9: OP_MOVMR ( 4, ABS, REG_X ); break; /* MOV X, abs */ + case 0xea: OP_NOT1 ( 5 ); break; /* NOT1 */ + case 0xeb: OP_MOVMR ( 3, DP, REG_Y ); break; /* MOV Y, dp */ + + case 0xec: OP_MOVMR ( 4, ABS, REG_Y ); break; /* MOV Y, abs */ + case 0xed: OP_NOTC ( 3 ); break; /* NOTC */ + case 0xee: OP_PULL ( 4, REG_Y ); break; /* POP Y */ + case 0xef: OP_SLEEP ( 1 ); break; /* SLEEP */ + + case 0xf0: OP_BCC ( 2, COND_EQ() ); break; /* BEQ */ + case 0xf1: OP_TCALL ( 8, 15 ); break; /* TCALL1 5 */ + case 0xf2: OP_CLR ( 4, BIT_7 ); break; /* CLR 7 */ + case 0xf3: OP_BBC ( 5, BIT_7 ); break; /* BBC 7 */ + + case 0xf4: OP_MOVMR ( 4, DPX, REG_A ); break; /* MOV A, dpx */ + case 0xf5: OP_MOVMR ( 5, ABX, REG_A ); break; /* MOV A, abx */ + case 0xf6: OP_MOVMR ( 5, ABY, REG_A ); break; /* MOV A, aby */ + case 0xf7: OP_MOVMR ( 6, DIY, REG_A ); break; /* MOV A, diy */ + + case 0xf8: OP_MOVMR ( 3, DP, REG_X ); break; /* MOV X, dp */ + case 0xf9: OP_MOVMR ( 4, DPY, REG_X ); break; /* MOV X, dpy */ + case 0xfa: OP_MOVMM ( 5, DP, DP ); break; /* MOV dp, dp */ + case 0xfb: OP_MOVMR ( 4, DPX, REG_Y ); break; /* MOV Y, DPX */ + case 0xfc: OP_INCR ( 2, REG_Y ); break; /* INC Y */ + case 0xfd: OP_MOVRR ( 2, REG_A, REG_Y ); break; /* MOV Y, A */ + case 0xfe: OP_DBNZR ( 4 ); break; /* DBNZ Y */ + case 0xff: OP_STOP ( 1 ); break; /* STOP */ + } + } +} + +/* ======================================================================== */ +/* ============================== END OF FILE ============================= */ +/* ======================================================================== */ diff --git a/src/devices/cpu/spc700/spc700.h b/src/devices/cpu/spc700/spc700.h new file mode 100644 index 00000000000..7177e2a6534 --- /dev/null +++ b/src/devices/cpu/spc700/spc700.h @@ -0,0 +1,141 @@ +// license:BSD-3-Clause +// copyright-holders:Karl Stenerud +#pragma once + +#ifndef __SPC700_H__ +#define __SPC700_H__ + + +class spc700_device : public cpu_device +{ +public: + // construction/destruction + spc700_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_execute_interface overrides + virtual UINT32 execute_min_cycles() const { return 2; } + virtual UINT32 execute_max_cycles() const { return 8; } + virtual UINT32 execute_input_lines() const { return 1; } + virtual void execute_run(); + virtual void execute_set_input(int inputnum, int state); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const { return (spacenum == AS_PROGRAM) ? &m_program_config : NULL; } + + // device_state_interface overrides + virtual void state_import(const device_state_entry &entry); + virtual void state_export(const device_state_entry &entry); + void state_string_export(const device_state_entry &entry, std::string &str); + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const { return 1; } + virtual UINT32 disasm_max_opcode_bytes() const { return 3; } + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + +private: + address_space_config m_program_config; + + UINT32 m_a; /* Accumulator */ + UINT32 m_x; /* Index Register X */ + UINT32 m_y; /* Index Register Y */ + UINT32 m_s; /* Stack Pointer */ + UINT32 m_pc; /* Program Counter */ + UINT32 m_ppc; /* Previous Program Counter */ + UINT32 m_flag_n; /* Negative Flag */ + UINT32 m_flag_z; /* Zero flag */ + UINT32 m_flag_v; /* Overflow Flag */ + UINT32 m_flag_p; /* Direct Page Flag */ + UINT32 m_flag_b; /* BRK Instruction Flag */ + UINT32 m_flag_h; /* Half-carry Flag */ + UINT32 m_flag_i; /* Interrupt Mask Flag */ + UINT32 m_flag_c; /* Carry Flag */ + UINT32 m_line_irq; /* Status of the IRQ line */ + UINT32 m_line_nmi; /* Status of the NMI line */ + UINT32 m_line_rst; /* Status of the RESET line */ + UINT32 m_ir; /* Instruction Register */ + address_space *m_program; + UINT32 m_stopped; /* stopped status */ + int m_ICount; + UINT32 m_source; + UINT32 m_destination; + UINT32 m_temp1; + UINT32 m_temp2; + UINT32 m_temp3; + short m_spc_int16; + int m_spc_int32; + + UINT32 m_debugger_temp; + + inline UINT32 read_8_normal(UINT32 address); + inline UINT32 read_8_immediate(UINT32 address); + inline UINT32 read_8_instruction(UINT32 address); + inline UINT32 read_8_direct(UINT32 address); + inline void write_8_normal(UINT32 address, UINT32 value); + inline void write_8_direct(UINT32 address, UINT32 value); + inline UINT32 read_16_normal(UINT32 address); + inline UINT32 read_16_immediate(UINT32 address); + inline UINT32 read_16_direct(UINT32 address); + inline void write_16_direct(UINT32 address, UINT32 value); + inline UINT32 EA_IMM(); + inline UINT32 EA_IMM16(); + inline UINT32 EA_ABS(); + inline UINT32 EA_ABX(); + inline UINT32 EA_ABY(); + inline UINT32 EA_AXI(); + inline UINT32 EA_DP(); + inline UINT32 EA_DPX(); + inline UINT32 EA_DPY(); + inline UINT32 EA_DXI(); + inline UINT32 EA_DIY(); + inline UINT32 EA_XI(); + inline UINT32 EA_XII(); + inline UINT32 EA_YI(); + inline void JUMP(UINT32 address); + inline void BRANCH(UINT32 offset); + inline void SET_REG_YA(UINT32 value); + inline void SET_REG_P(UINT32 value); + inline void PUSH_8(UINT32 value); + inline UINT32 PULL_8(); + inline void PUSH_16(UINT32 value); + inline UINT32 PULL_16(); + inline void CHECK_IRQ(); + inline void SET_FLAG_I(UINT32 value); + void SERVICE_IRQ(); +}; + + +extern const device_type SPC700; + + +/* ======================================================================== */ +/* ============================= Configuration ============================ */ +/* ======================================================================== */ + +/* Turn on optimizations for SNES since it doesn't hook up the interrupt lines */ +#define SPC700_OPTIMIZE_SNES 1 + + +/* ======================================================================== */ +/* ============================== PROTOTYPES ============================== */ +/* ======================================================================== */ + +enum +{ + SPC700_PC=1, SPC700_S, SPC700_P, SPC700_A, SPC700_X, SPC700_Y +}; + +#define SPC700_INT_NONE 0 +#define SPC700_INT_IRQ 1 +#define SPC700_INT_NMI 2 + + +/* ======================================================================== */ +/* ============================== END OF FILE ============================= */ +/* ======================================================================== */ + +#endif /* __SPC700_H__ */ diff --git a/src/devices/cpu/spc700/spc700ds.c b/src/devices/cpu/spc700/spc700ds.c new file mode 100644 index 00000000000..ef5fbd4fe91 --- /dev/null +++ b/src/devices/cpu/spc700/spc700ds.c @@ -0,0 +1,437 @@ +// license:BSD-3-Clause +// copyright-holders:Karl Stenerud +/* ======================================================================== */ +/* =============================== COPYRIGHT ============================== */ +/* ======================================================================== */ +/* + +SPC700 CPU Emulator V0.90 + +Copyright Karl Stenerud +All rights reserved. + +*/ + +#include "emu.h" +#include "spc700ds.h" + + + +struct spc700_opcode_struct +{ + unsigned char name; + unsigned char args[2]; +}; + +enum +{ + IMP , A , X , Y , YA , SP , PSW , C , REL , UPAG, IMM , XI , + XII , YI , DP , DPX , DPY , DPI , DXI , DIY , ABS , ABX , ABY , AXI , N0 , + N1 , N2 , N3 , N4 , N5 , N6 , N7 , N8 , N9 , N10 , N11 , N12 , + N13 , N14 , N15 , DP0 , DP1 , DP2 , DP3 , DP4 , DP5 , DP6 , DP7 , MEMN, + MEMI +}; + + +enum +{ + ADC , ADDW , AND , AND1 , ASL , BBC , BBS , BCC , + BCS , BEQ , BMI , BNE , BPL , BRA , BRK , BVC , + BVS , CALL , CBNE , CLR1 , CLRC , CLRP , CLRV , CMP , + CMPW , DAA , DAS , DBNZ , DEC , DECW , DI , DIV , + EI , EOR , EOR1 , INC , INCW , JMP , LSR , MOV , + MOV1 , MOVW , MUL , NOP , NOT1 , NOTQ , NOTC , OR , + OR1 , PCALL , POP , PUSH , RET , RETI , ROL , ROR , + SBC , SET1 , SETC , SETP , SLEEP , STOP , SUBW , TCALL , + TCLR1 , TSET1 , XCN +}; + + +static const char *const g_opnames[] = +{ + "ADC ", "ADDW ", "AND ", "AND1 ", "ASL ", "BBC ", "BBS ", "BCC ", + "BCS ", "BEQ ", "BMI ", "BNE ", "BPL ", "BRA ", "BRK ", "BVC ", + "BVS ", "CALL ", "CBNE ", "CLR1 ", "CLRC ", "CLRP ", "CLRV ", "CMP ", + "CMPW ", "DAA ", "DAS ", "DBNZ ", "DEC ", "DECW ", "DI ", "DIV ", + "EI ", "EOR ", "EOR1 ", "INC ", "INCW ", "JMP ", "LSR ", "MOV ", + "MOV1 ", "MOVW ", "MUL ", "NOP ", "NOT1 ", "NOTQ ", "NOTC ", "OR ", + "OR1 ", "PCALL", "POP ", "PUSH ", "RET ", "RETI ", "ROL ", "ROR ", + "SBC ", "SET1 ", "SETC ", "SETP ", "SLEEP", "STOP ", "SUBW ", "TCALL", + "TCLR1", "TSET1", "XCN " +}; + +static const spc700_opcode_struct g_opcodes[256] = +{ +/* 00 */ {NOP , {IMP , IMP }}, +/* 01 */ {TCALL , {N0 , IMP }}, +/* 02 */ {SET1 , {DP0 , IMP }}, +/* 03 */ {BBS , {DP0 , REL }}, +/* 04 */ {OR , {A , DP }}, +/* 05 */ {OR , {A , ABS }}, +/* 06 */ {OR , {A , XI }}, +/* 07 */ {OR , {A , DXI }}, +/* 08 */ {OR , {A , IMM }}, +/* 09 */ {OR , {DP , DP }}, +/* 0A */ {OR1 , {C , MEMN}}, +/* 0B */ {ASL , {DP , IMP }}, +/* 0C */ {ASL , {ABS , IMP }}, +/* 0D */ {PUSH , {PSW , IMP }}, +/* 0E */ {TSET1 , {ABS , IMP }}, +/* 0F */ {BRK , {IMP , IMP }}, +/* 10 */ {BPL , {REL , IMP }}, +/* 11 */ {TCALL , {N1 , IMP }}, +/* 12 */ {CLR1 , {DP0 , IMP }}, +/* 13 */ {BBC , {DP0 , REL }}, +/* 14 */ {OR , {A , DPX }}, +/* 15 */ {OR , {A , ABX }}, +/* 16 */ {OR , {A , ABY }}, +/* 17 */ {OR , {A , DIY }}, +/* 18 */ {OR , {DP , IMM }}, +/* 19 */ {OR , {XI , YI }}, +/* 1A */ {DECW , {DP , IMP }}, +/* 1B */ {ASL , {DPX , IMP }}, +/* 1C */ {ASL , {A , IMP }}, +/* 1D */ {DEC , {X , IMP }}, +/* 1E */ {CMP , {X , ABS }}, +/* 1F */ {JMP , {AXI , IMP }}, +/* 20 */ {CLRP , {IMP , IMP }}, +/* 21 */ {TCALL , {N2 , IMP }}, +/* 22 */ {SET1 , {DP1 , IMP }}, +/* 23 */ {BBS , {DP1 , REL }}, +/* 24 */ {AND , {A , DP }}, +/* 25 */ {AND , {A , ABS }}, +/* 26 */ {AND , {A , XI }}, +/* 27 */ {AND , {A , DXI }}, +/* 28 */ {AND , {A , IMM }}, +/* 29 */ {AND , {DP , DP }}, +/* 2A */ {OR1 , {C , MEMI}}, +/* 2B */ {ROL , {DP , IMP }}, +/* 2C */ {ROL , {ABS , IMP }}, +/* 2D */ {PUSH , {A , IMP }}, +/* 2E */ {CBNE , {DP , REL }}, +/* 2F */ {BRA , {REL , IMP }}, +/* 30 */ {BMI , {REL , IMP }}, +/* 31 */ {TCALL , {N3 , IMP }}, +/* 32 */ {CLR1 , {DP1 , IMP }}, +/* 33 */ {BBC , {DP1 , REL }}, +/* 34 */ {AND , {A , DPX }}, +/* 35 */ {AND , {A , ABX }}, +/* 36 */ {AND , {A , ABY }}, +/* 37 */ {AND , {A , DIY }}, +/* 38 */ {AND , {DP , IMM }}, +/* 39 */ {AND , {XI , YI }}, +/* 3A */ {INCW , {DP , IMP }}, +/* 3B */ {ROL , {DPX , IMP }}, +/* 3C */ {ROL , {A , IMP }}, +/* 3D */ {INC , {X , IMP }}, +/* 3E */ {CMP , {X , DP }}, +/* 3F */ {CALL , {ABS , IMP }}, +/* 40 */ {SETP , {IMP , IMP }}, +/* 41 */ {TCALL , {N4 , IMP }}, +/* 42 */ {SET1 , {DP2 , IMP }}, +/* 43 */ {BBS , {DP2 , REL }}, +/* 44 */ {EOR , {A , DP }}, +/* 45 */ {EOR , {A , ABS }}, +/* 46 */ {EOR , {A , XI }}, +/* 47 */ {EOR , {A , DXI }}, +/* 48 */ {EOR , {A , IMM }}, +/* 49 */ {EOR , {DP , DP }}, +/* 4A */ {AND1 , {C , MEMN}}, +/* 4B */ {LSR , {DP , IMP }}, +/* 4C */ {LSR , {ABS , IMP }}, +/* 4D */ {PUSH , {X , IMP }}, +/* 4E */ {TCLR1 , {ABS , IMP }}, +/* 4F */ {PCALL , {UPAG, IMP }}, +/* 50 */ {BVC , {REL , IMP }}, +/* 51 */ {TCALL , {N5 , IMP }}, +/* 52 */ {CLR1 , {DP2 , IMP }}, +/* 53 */ {BBC , {DP2 , REL }}, +/* 54 */ {EOR , {A , DPX }}, +/* 55 */ {EOR , {A , ABX }}, +/* 56 */ {EOR , {A , ABY }}, +/* 57 */ {EOR , {A , DIY }}, +/* 58 */ {EOR , {DP , IMM }}, +/* 59 */ {EOR , {XI , YI }}, +/* 5A */ {CMPW , {DP , IMP }}, +/* 5B */ {LSR , {DPX , IMP }}, +/* 5C */ {LSR , {A , IMP }}, +/* 5D */ {MOV , {X , A }}, +/* 5E */ {CMP , {Y , ABS }}, +/* 5F */ {JMP , {ABS , IMP }}, +/* 60 */ {CLRC , {IMP , IMP }}, +/* 61 */ {TCALL , {N6 , IMP }}, +/* 62 */ {SET1 , {DP3 , IMP }}, +/* 63 */ {BBS , {DP3 , REL }}, +/* 64 */ {CMP , {A , DP }}, +/* 65 */ {CMP , {A , ABS }}, +/* 66 */ {CMP , {A , XI }}, +/* 67 */ {CMP , {A , DXI }}, +/* 68 */ {CMP , {A , IMM }}, +/* 69 */ {CMP , {DP , DP }}, +/* 6A */ {AND1 , {C , MEMI}}, +/* 6B */ {ROR , {DP , IMP }}, +/* 6C */ {ROR , {ABS , IMP }}, +/* 6D */ {PUSH , {Y , IMP }}, +/* 6E */ {DBNZ , {DP , REL }}, +/* 6F */ {RET , {IMP , IMP }}, +/* 70 */ {BVS , {REL , IMP }}, +/* 71 */ {TCALL , {N7 , IMP }}, +/* 72 */ {CLR1 , {DP3 , IMP }}, +/* 73 */ {BBC , {DP3 , REL }}, +/* 74 */ {CMP , {A , DPX }}, +/* 75 */ {CMP , {A , ABX }}, +/* 76 */ {CMP , {A , ABY }}, +/* 77 */ {CMP , {A , DIY }}, +/* 78 */ {CMP , {DP , IMM }}, +/* 79 */ {CMP , {XI , YI }}, +/* 7A */ {ADDW , {DP , IMP }}, +/* 7B */ {ROR , {DPX , IMP }}, +/* 7C */ {ROR , {A , IMP }}, +/* 7D */ {MOV , {A , X }}, +/* 7E */ {CMP , {Y , DP }}, +/* 7F */ {RETI , {IMP , IMP }}, +/* 80 */ {SETC , {IMP , IMP }}, +/* 81 */ {TCALL , {N8 , IMP }}, +/* 82 */ {SET1 , {DP4 , IMP }}, +/* 83 */ {BBS , {DP4 , REL }}, +/* 84 */ {ADC , {A , DP }}, +/* 85 */ {ADC , {A , ABS }}, +/* 86 */ {ADC , {A , XI }}, +/* 87 */ {ADC , {A , DXI }}, +/* 88 */ {ADC , {A , IMM }}, +/* 89 */ {ADC , {DP , DP }}, +/* 8A */ {EOR1 , {C , MEMN}}, +/* 8B */ {DEC , {DP , IMP }}, +/* 8C */ {DEC , {ABS , IMP }}, +/* 8D */ {MOV , {Y , IMM }}, +/* 8E */ {POP , {PSW , IMP }}, +/* 8F */ {MOV , {DP , IMM }}, +/* 90 */ {BCC , {REL , IMP }}, +/* 91 */ {TCALL , {N9 , IMP }}, +/* 92 */ {CLR1 , {DP4 , IMP }}, +/* 93 */ {BBC , {DP4 , REL }}, +/* 94 */ {ADC , {A , DPX }}, +/* 95 */ {ADC , {A , ABX }}, +/* 96 */ {ADC , {A , ABY }}, +/* 97 */ {ADC , {A , DIY }}, +/* 98 */ {ADC , {DP , IMM }}, +/* 99 */ {ADC , {XI , YI }}, +/* 9A */ {SUBW , {DP , IMP }}, +/* 9B */ {DEC , {DPX , IMP }}, +/* 9C */ {DEC , {A , IMP }}, +/* 9D */ {MOV , {X , SP }}, +/* 9E */ {DIV , {YA , X }}, +/* 9F */ {XCN , {A , IMP }}, +/* A0 */ {EI , {IMP , IMP }}, +/* A1 */ {TCALL , {N10 , IMP }}, +/* A2 */ {SET1 , {DP5 , IMP }}, +/* A3 */ {BBS , {DP5 , REL }}, +/* A4 */ {SBC , {A , DP }}, +/* A5 */ {SBC , {A , ABS }}, +/* A6 */ {SBC , {A , XI }}, +/* A7 */ {SBC , {A , DXI }}, +/* A8 */ {SBC , {A , IMM }}, +/* A9 */ {SBC , {DP , DP }}, +/* AA */ {MOV1 , {C , MEMN}}, +/* AB */ {INC , {DP , IMP }}, +/* AC */ {INC , {ABS , IMP }}, +/* AD */ {CMP , {Y , IMM }}, +/* AE */ {POP , {A , IMP }}, +/* AF */ {MOV , {XII , A }}, +/* B0 */ {BCS , {REL , IMP }}, +/* B1 */ {TCALL , {N11 , IMP }}, +/* B2 */ {CLR1 , {DP5 , IMP }}, +/* B3 */ {BBC , {DP5 , REL }}, +/* B4 */ {SBC , {A , DPX }}, +/* B5 */ {SBC , {A , ABX }}, +/* B6 */ {SBC , {A , ABY }}, +/* B7 */ {SBC , {A , DIY }}, +/* B8 */ {SBC , {DP , IMM }}, +/* B9 */ {SBC , {XI , YI }}, +/* BA */ {MOVW , {YA , DP }}, +/* BB */ {INC , {DPX , IMP }}, +/* BC */ {INC , {A , IMP }}, +/* BD */ {MOV , {SP , X }}, +/* BE */ {DAS , {A , IMP }}, +/* BF */ {MOV , {A , XII }}, +/* C0 */ {DI , {IMP , IMP }}, +/* C1 */ {TCALL , {N12 , IMP }}, +/* C2 */ {SET1 , {DP6 , IMP }}, +/* C3 */ {BBS , {DP6 , REL }}, +/* C4 */ {MOV , {DP , A }}, +/* C5 */ {MOV , {ABS , A }}, +/* C6 */ {MOV , {XI , A }}, +/* C7 */ {MOV , {DXI , A }}, +/* C8 */ {CMP , {X , IMM }}, +/* C9 */ {MOV , {ABS , X }}, +/* CA */ {MOV1 , {MEMN, C }}, +/* CB */ {MOV , {DP , Y }}, +/* CC */ {MOV , {ABS , Y }}, +/* CD */ {MOV , {X , IMM }}, +/* CE */ {POP , {X , IMP }}, +/* CF */ {MUL , {YA , IMP }}, +/* D0 */ {BNE , {REL , IMP }}, +/* D1 */ {TCALL , {N13 , IMP }}, +/* D2 */ {CLR1 , {DP6 , IMP }}, +/* D3 */ {BBC , {DP6 , REL }}, +/* D4 */ {MOV , {DPX , A }}, +/* D5 */ {MOV , {ABX , A }}, +/* D6 */ {MOV , {ABY , A }}, +/* D7 */ {MOV , {DIY , A }}, +/* D8 */ {MOV , {DP , X }}, +/* D9 */ {MOV , {DPY , X }}, +/* DA */ {MOVW , {DP , YA }}, +/* DB */ {MOV , {DPX , Y }}, +/* DC */ {DEC , {Y , IMP }}, +/* DD */ {MOV , {A , Y }}, +/* DE */ {CBNE , {DPX , REL }}, +/* DF */ {DAA , {IMP , IMP }}, +/* E0 */ {CLRV , {IMP , IMP }}, +/* E1 */ {TCALL , {N14 , IMP }}, +/* E2 */ {SET1 , {DP7 , IMP }}, +/* E3 */ {BBS , {DP7 , REL }}, +/* E4 */ {MOV , {A , DP }}, +/* E5 */ {MOV , {A , ABS }}, +/* E6 */ {MOV , {A , XI }}, +/* E7 */ {MOV , {A , DXI }}, +/* E8 */ {MOV , {A , IMM }}, +/* E9 */ {MOV , {X , ABS }}, +/* EA */ {NOT1 , {IMP , IMP }}, +/* EB */ {MOV , {Y , DP }}, +/* EC */ {MOV , {Y , ABS }}, +/* ED */ {NOTC , {IMP , IMP }}, +/* EE */ {POP , {Y , IMP }}, +/* EF */ {SLEEP , {IMP , IMP }}, +/* F0 */ {BEQ , {REL , IMP }}, +/* F1 */ {TCALL , {N15 , IMP }}, +/* F2 */ {CLR1 , {DP7 , IMP }}, +/* F3 */ {BBC , {DP7 , REL }}, +/* F4 */ {MOV , {A , DPX }}, +/* F5 */ {MOV , {A , ABX }}, +/* F6 */ {MOV , {A , ABY }}, +/* F7 */ {MOV , {A , DIY }}, +/* F8 */ {MOV , {X , DP }}, +/* F9 */ {MOV , {X , DPY }}, +/* FA */ {MOV , {DP , DP }}, +/* FB */ {MOV , {Y , DPX }}, +/* FC */ {INC , {Y , IMP }}, +/* FD */ {MOV , {Y , A }}, +/* FE */ {DBNZ , {Y , REL }}, +/* FF */ {STOP , {IMP , IMP }}, +}; + +static unsigned int g_pc; +static const UINT8 *rombase; + +INLINE unsigned int read_8_immediate(void) +{ + g_pc++; + return *rombase++; +} + +INLINE unsigned int read_16_immediate(void) +{ + unsigned int result; + g_pc += 2; + result = *rombase++; + return result | (*rombase++ << 8); +} + +CPU_DISASSEMBLE( spc700 ) +{ + const spc700_opcode_struct* opcode; + UINT32 flags = 0; + char* ptr; + int var; + int i; + + g_pc = pc; + rombase = oprom; + opcode = g_opcodes + read_8_immediate(); + + sprintf(buffer, "%s ", g_opnames[opcode->name]); + ptr = buffer + strlen(buffer); + + if (opcode->name == CALL) + flags = DASMFLAG_STEP_OVER; + else if (opcode->name == RET || opcode->name == RETI) + flags = DASMFLAG_STEP_OUT; + + if (opcode->args[0] == DP && (opcode->args[1] == DP || opcode->args[1] == IMM)) + { + int src = read_8_immediate(); + int dst = read_8_immediate(); + sprintf(ptr, "$%02x,%s$%02x", dst, (opcode->args[1] == IMM ? "#" : ""), src); + ptr += strlen(ptr); + } + else for(i=0;i<2;i++) + { + if(i == 1 && opcode->args[0] != IMP && opcode->args[1] != IMP) + { + sprintf(ptr, ","); + ptr += strlen(ptr); + } + + switch(opcode->args[i]) + { + case IMP: break; + case A: sprintf(ptr, "A"); break; + case X: sprintf(ptr, "X"); break; + case Y: sprintf(ptr, "Y"); break; + case YA: sprintf(ptr, "YA"); break; + case SP: sprintf(ptr, "SP"); break; + case PSW: sprintf(ptr, "PSW"); break; + case C: sprintf(ptr, "C"); break; + case REL: sprintf(ptr, "%04x", ((g_pc + (char)read_8_immediate())&0xffff)); break; + case UPAG: sprintf(ptr, "$%02x", read_8_immediate()); break; + case IMM: sprintf(ptr, "#$%02x", read_8_immediate()); break; + case XI: sprintf(ptr, "(X)"); break; + case XII: sprintf(ptr, "(X)+"); break; + case YI: sprintf(ptr, "(Y)"); break; + case DP: sprintf(ptr, "$%02x", read_8_immediate()); break; + case DPX: sprintf(ptr, "$%02x+X", read_8_immediate()); break; + case DPY: sprintf(ptr, "$%02x+Y", read_8_immediate()); break; + case DPI: sprintf(ptr, "($%02x)", read_8_immediate()); break; + case DXI: sprintf(ptr, "($%02x+X)", read_8_immediate()); break; + case DIY: sprintf(ptr, "($%02x)+Y", read_8_immediate()); break; + case ABS: sprintf(ptr, "$%04x", read_16_immediate()); break; + case ABX: sprintf(ptr, "$%04x+X", read_16_immediate()); break; + case ABY: sprintf(ptr, "$%04x+Y", read_16_immediate()); break; + case AXI: sprintf(ptr, "($%04x+X)", read_16_immediate()); break; + case N0: sprintf(ptr, "0"); break; + case N1: sprintf(ptr, "1"); break; + case N2: sprintf(ptr, "2"); break; + case N3: sprintf(ptr, "3"); break; + case N4: sprintf(ptr, "4"); break; + case N5: sprintf(ptr, "5"); break; + case N6: sprintf(ptr, "6"); break; + case N7: sprintf(ptr, "7"); break; + case N8: sprintf(ptr, "8"); break; + case N9: sprintf(ptr, "9"); break; + case N10: sprintf(ptr, "10"); break; + case N11: sprintf(ptr, "11"); break; + case N12: sprintf(ptr, "12"); break; + case N13: sprintf(ptr, "13"); break; + case N14: sprintf(ptr, "14"); break; + case N15: sprintf(ptr, "15"); break; + case DP0: sprintf(ptr, "$%02x.0", read_8_immediate()); break; + case DP1: sprintf(ptr, "$%02x.1", read_8_immediate()); break; + case DP2: sprintf(ptr, "$%02x.2", read_8_immediate()); break; + case DP3: sprintf(ptr, "$%02x.3", read_8_immediate()); break; + case DP4: sprintf(ptr, "$%02x.4", read_8_immediate()); break; + case DP5: sprintf(ptr, "$%02x.5", read_8_immediate()); break; + case DP6: sprintf(ptr, "$%02x.6", read_8_immediate()); break; + case DP7: sprintf(ptr, "$%02x.7", read_8_immediate()); break; + case MEMN: + var = read_16_immediate(); + sprintf(ptr, "%04x.%d", var&0x1fff, var>>13); + break; + case MEMI: + var = read_16_immediate(); + sprintf(ptr, "/%04x.%d", var&0x1fff, var>>13); + break; + } + ptr += strlen(ptr); + } + return (g_pc - pc) | flags | DASMFLAG_SUPPORTED; +} diff --git a/src/devices/cpu/spc700/spc700ds.h b/src/devices/cpu/spc700/spc700ds.h new file mode 100644 index 00000000000..e2135526363 --- /dev/null +++ b/src/devices/cpu/spc700/spc700ds.h @@ -0,0 +1,24 @@ +// license:BSD-3-Clause +// copyright-holders:Karl Stenerud +#pragma once + +#ifndef __SPC700DS_H__ +#define __SPC700DS_H__ +/* ======================================================================== */ +/* =============================== COPYRIGHT ============================== */ +/* ======================================================================== */ +/* + +Sony SPC700 CPU Emulator V1.0 + +Copyright Karl Stenerud +All rights reserved. + + +*/ + + +CPU_DISASSEMBLE( spc700 ); + + +#endif /* __SPC700DS_H__ */ diff --git a/src/devices/cpu/ssem/ssem.c b/src/devices/cpu/ssem/ssem.c new file mode 100644 index 00000000000..f5622e5fb38 --- /dev/null +++ b/src/devices/cpu/ssem/ssem.c @@ -0,0 +1,316 @@ +// license:BSD-3-Clause +// copyright-holders:Ryan Holtz +/* + Manchester Small-Scale Experimental Machine (SSEM) emulator + + Written by MooglyGuy +*/ + +#include "emu.h" +#include "debugger.h" +#include "ssem.h" + +CPU_DISASSEMBLE( ssem ); + + +#define SSEM_DISASM_ON_UNIMPL 0 +#define SSEM_DUMP_MEM_ON_UNIMPL 0 + +#define INSTR ((op >> 13) & 7) +#define ADDR (op & 0x1f) + +/*****************************************************************************/ + +// The SSEM stores its data, visually, with the leftmost bit corresponding to the least significant bit. +// The de facto snapshot format for other SSEM simulators stores the data physically in that format as well. +// Therefore, in MESS, every 32-bit word has its bits reversed, too, and as a result the values must be +// un-reversed before being used. +INLINE UINT32 reverse(UINT32 v) +{ + // Taken from http://www-graphics.stanford.edu/~seander/bithacks.html#ReverseParallel + // swap odd and even bits + v = ((v >> 1) & 0x55555555) | ((v & 0x55555555) << 1); + // swap consecutive pairs + v = ((v >> 2) & 0x33333333) | ((v & 0x33333333) << 2); + // swap nibbles ... + v = ((v >> 4) & 0x0F0F0F0F) | ((v & 0x0F0F0F0F) << 4); + // swap bytes + v = ((v >> 8) & 0x00FF00FF) | ((v & 0x00FF00FF) << 8); + // swap 2-byte long pairs + v = ( v >> 16 ) | ( v << 16); + + return v; +} + +inline UINT32 ssem_device::program_read32(UINT32 address) +{ + UINT32 v = 0; + // The MAME core does not have a good way of specifying a minimum datum size that is more than + // 8 bits in width. The minimum datum width on the SSEM is 32 bits, so we need to quadruple + // the address value to get the appropriate byte index. + address <<= 2; + + v |= m_program->read_byte(address + 0) << 24; + v |= m_program->read_byte(address + 1) << 16; + v |= m_program->read_byte(address + 2) << 8; + v |= m_program->read_byte(address + 3) << 0; + + return reverse(v); +} + +inline void ssem_device::program_write32(UINT32 address, UINT32 data) +{ + UINT32 v = reverse(data); + + // The MAME core does not have a good way of specifying a minimum datum size that is more than + // 8 bits in width. The minimum datum width on the SSEM is 32 bits, so we need to quadruple + // the address value to get the appropriate byte index. + address <<= 2; + + m_program->write_byte(address + 0, (v >> 24) & 0x000000ff); + m_program->write_byte(address + 1, (v >> 16) & 0x000000ff); + m_program->write_byte(address + 2, (v >> 8) & 0x000000ff); + m_program->write_byte(address + 3, (v >> 0) & 0x000000ff); + return; +} + +/*****************************************************************************/ + +const device_type SSEMCPU = &device_creator; + +//------------------------------------------------- +// ssem_device - constructor +//------------------------------------------------- + +ssem_device::ssem_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : cpu_device(mconfig, SSEMCPU, "SSEMCPU", tag, owner, clock, "ssem_cpu", __FILE__), + m_program_config("program", ENDIANNESS_LITTLE, 8, 16), + m_pc(1), + m_shifted_pc(1<<2), + m_a(0), + m_halt(0), + m_icount(0) +{ + // Allocate & setup +} + + +void ssem_device::device_start() +{ + m_program = &space(AS_PROGRAM); + + // register our state for the debugger + std::string tempstr; + state_add(STATE_GENPC, "GENPC", m_pc).noshow(); + state_add(STATE_GENFLAGS, "GENFLAGS", m_halt).callimport().callexport().formatstr("%1s").noshow(); + state_add(SSEM_PC, "PC", m_shifted_pc).mask(0xffff); + state_add(SSEM_A, "A", m_a).mask(0xffffffff); + state_add(SSEM_HALT, "HALT", m_halt).mask(0xf); + + /* setup regtable */ + save_item(NAME(m_pc)); + save_item(NAME(m_a)); + save_item(NAME(m_halt)); + + // set our instruction counter + m_icountptr = &m_icount; +} + +void ssem_device::device_stop() +{ +} + +void ssem_device::device_reset() +{ + m_pc = 1; + m_shifted_pc = m_pc << 2; + m_a = 0; + m_halt = 0; +} + + +//------------------------------------------------- +// memory_space_config - return the configuration +// of the specified address space, or NULL if +// the space doesn't exist +//------------------------------------------------- + +const address_space_config *ssem_device::memory_space_config(address_spacenum spacenum) const +{ + if (spacenum == AS_PROGRAM) + { + return &m_program_config; + } + return NULL; +} + + +//------------------------------------------------- +// state_string_export - export state as a string +// for the debugger +//------------------------------------------------- + +void ssem_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + switch (entry.index()) + { + case STATE_GENFLAGS: + strprintf(str, "%c", m_halt ? 'H' : '.'); + break; + } +} + + +//------------------------------------------------- +// disasm_min_opcode_bytes - return the length +// of the shortest instruction, in bytes +//------------------------------------------------- + +UINT32 ssem_device::disasm_min_opcode_bytes() const +{ + return 4; +} + + +//------------------------------------------------- +// disasm_max_opcode_bytes - return the length +// of the longest instruction, in bytes +//------------------------------------------------- + +UINT32 ssem_device::disasm_max_opcode_bytes() const +{ + return 4; +} + + +//------------------------------------------------- +// disasm_disassemble - call the disassembly +// helper function +//------------------------------------------------- + +offs_t ssem_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( ssem ); + return CPU_DISASSEMBLE_NAME(ssem)(this, buffer, pc, oprom, opram, options); +} + + +//************************************************************************** +// CORE EXECUTION LOOP +//************************************************************************** + +//------------------------------------------------- +// execute_min_cycles - return minimum number of +// cycles it takes for one instruction to execute +//------------------------------------------------- + +UINT32 ssem_device::execute_min_cycles() const +{ + return 1; +} + + +//------------------------------------------------- +// execute_max_cycles - return maximum number of +// cycles it takes for one instruction to execute +//------------------------------------------------- + +UINT32 ssem_device::execute_max_cycles() const +{ + return 1; +} + + +//------------------------------------------------- +// execute_input_lines - return the number of +// input/interrupt lines +//------------------------------------------------- + +UINT32 ssem_device::execute_input_lines() const +{ + return 0; +} + + +//------------------------------------------------- +// execute_set_input - set the state of an input +// line during execution +//------------------------------------------------- + +void ssem_device::execute_set_input(int inputnum, int state) +{ +} + + +//------------------------------------------------- +// execute_run - execute a timeslice's worth of +// opcodes +//------------------------------------------------- + +void ssem_device::execute_run() +{ + UINT32 op; + + m_pc &= 0x1f; + m_shifted_pc = m_pc << 2; + + while (m_icount > 0) + { + debugger_instruction_hook(this, m_pc); + + op = program_read32(m_pc); + + if( !m_halt ) + { + m_pc++; + m_shifted_pc = m_pc << 2; + } + else + { + op = 0x0000e000; + } + + switch (INSTR) + { + case 0: + // JMP: Move the value at the specified address into the Program Counter. + m_pc = program_read32(ADDR) + 1; + m_shifted_pc = m_pc << 2; + break; + case 1: + // JRP: Add the value at the specified address to the Program Counter. + m_pc += (INT32)program_read32(ADDR); + m_shifted_pc = m_pc << 2; + break; + case 2: + // LDN: Load the accumulator with the two's-complement negation of the value at the specified address. + m_a = (UINT32)(0 - (INT32)program_read32(ADDR)); + break; + case 3: + // STO: Store the value in the accumulator at the specified address. + program_write32(ADDR, m_a); + break; + case 4: + case 5: + // SUB: Subtract the value at the specified address from the accumulator. + m_a -= program_read32(ADDR); + break; + case 6: + // CMP: If the accumulator is less than zero, skip the next opcode. + if((INT32)(m_a) < 0) + { + m_pc++; + m_shifted_pc = m_pc << 2; + } + break; + case 7: + // STP: Halt the computer. + m_halt = 1; + break; + default: + break; + } + + --m_icount; + } +} diff --git a/src/devices/cpu/ssem/ssem.h b/src/devices/cpu/ssem/ssem.h new file mode 100644 index 00000000000..cfcb0e5dc11 --- /dev/null +++ b/src/devices/cpu/ssem/ssem.h @@ -0,0 +1,86 @@ +// license:BSD-3-Clause +// copyright-holders:Ryan Holtz +/* + Manchester Small-Scale Experimental Machine (SSEM) emulator + + Written by MooglyGuy +*/ + +#pragma once + +#ifndef __SSEM_H__ +#define __SSEM_H__ + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> ssem_device + +// Used by core CPU interface +class ssem_device : public cpu_device +{ +public: + // construction/destruction + ssem_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_stop(); + + // device_execute_interface overrides + virtual UINT32 execute_min_cycles() const; + virtual UINT32 execute_max_cycles() const; + virtual UINT32 execute_input_lines() const; + virtual void execute_run(); + virtual void execute_set_input(int inputnum, int state); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const; + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const; + virtual UINT32 disasm_max_opcode_bytes() const; + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + + // device_state_interface overrides + virtual void state_string_export(const device_state_entry &entry, std::string &str); + + // address spaces + const address_space_config m_program_config; + + // memory access + inline UINT32 program_read32(UINT32 addr); + inline void program_write32(UINT32 addr, UINT32 data); + + // CPU registers + UINT32 m_pc; + UINT32 m_shifted_pc; + UINT32 m_a; + UINT32 m_halt; + + // other internal states + int m_icount; + + // address spaces + address_space *m_program; +}; + +// device type definition +extern const device_type SSEMCPU; + +/*************************************************************************** + REGISTER ENUMERATION +***************************************************************************/ + +enum +{ + SSEM_PC = 1, + SSEM_A, + SSEM_HALT +}; + +CPU_DISASSEMBLE( ssem ); + +#endif /* __SSEM_H__ */ diff --git a/src/devices/cpu/ssem/ssemdasm.c b/src/devices/cpu/ssem/ssemdasm.c new file mode 100644 index 00000000000..0a10e4dbe12 --- /dev/null +++ b/src/devices/cpu/ssem/ssemdasm.c @@ -0,0 +1,87 @@ +// license:BSD-3-Clause +// copyright-holders:Ryan Holtz +/* + Manchester Small-Scale Experimental Machine (SSEM) disassembler + + Written by MooglyGuy +*/ + +#include "emu.h" + +static char *output; + +static void ATTR_PRINTF(1,2) print(const char *fmt, ...) +{ + va_list vl; + + va_start(vl, fmt); + output += vsprintf(output, fmt, vl); + va_end(vl); +} + +INLINE UINT32 reverse(UINT32 v) +{ + // Taken from http://www-graphics.stanford.edu/~seander/bithacks.html#ReverseParallel + // swap odd and even bits + v = ((v >> 1) & 0x55555555) | ((v & 0x55555555) << 1); + // swap consecutive pairs + v = ((v >> 2) & 0x33333333) | ((v & 0x33333333) << 2); + // swap nibbles ... + v = ((v >> 4) & 0x0F0F0F0F) | ((v & 0x0F0F0F0F) << 4); + // swap bytes + v = ((v >> 8) & 0x00FF00FF) | ((v & 0x00FF00FF) << 8); + // swap 2-byte long pairs + v = ( v >> 16 ) | ( v << 16); + + return v; +} + +offs_t ssem_dasm_one(char *buffer, offs_t pc, UINT32 op) +{ + UINT8 instr = (reverse(op) >> 13) & 7; + UINT8 addr = reverse(op) & 0x1f; + + output = buffer; + + switch (instr) + { + case 0: // JMP S + print("JMP %d", addr); + break; + case 1: // JRP S + print("JRP %d", addr); + break; + case 2: // LDN S + print("LDN %d", addr); + break; + case 3: // STO S + print("STO %d", addr); + break; + case 4: // SUB S + case 5: + print("SUB %d", addr); + break; + case 6: // CMP + print("CMP"); + break; + case 7: // STP + print("STP"); + break; + default: + print("???"); + break; + } + + return 4 | DASMFLAG_SUPPORTED; +} + +/*****************************************************************************/ + +CPU_DISASSEMBLE( ssem ) +{ + UINT32 op = (*(UINT8 *)(opram + 0) << 24) | + (*(UINT8 *)(opram + 1) << 16) | + (*(UINT8 *)(opram + 2) << 8) | + (*(UINT8 *)(opram + 3) << 0); + return ssem_dasm_one(buffer, pc, op); +} diff --git a/src/devices/cpu/ssp1601/ssp1601.c b/src/devices/cpu/ssp1601/ssp1601.c new file mode 100644 index 00000000000..fb15aa3d84e --- /dev/null +++ b/src/devices/cpu/ssp1601/ssp1601.c @@ -0,0 +1,781 @@ +// license:??? +// copyright-holders:Pierpaolo Prazzoli,Grazvydas Ignotas +/* + * Samsung SSP1601 DSP emulator + * + * Copyright 2008, Grazvydas Ignotas + * + * notes: + * not everything is implemented, but it is accurate enough to + * properly emulate Virtua Racing for Genesis/MegaDrive: + * + * only Z and N status flags are emulated (others unused by VR) + * so all condition checks except N and Z are ignored (not used by VR) + * modifiers for 'OP a, ri' and ((ri)) are ignored (not used by VR) + * loop repeat mode when destination is (ri) is ignored + * ops not used by VR are not implemented + */ + +#include "emu.h" +#include "debugger.h" +#include "ssp1601.h" + + +/* detect ops with unimplemented/invalid fields. + * Useful for homebrew or if a new VR revision pops up. */ +//#define DO_CHECKS + + +// 0 +#define rX m_gr[SSP_X].w.h +#define rY m_gr[SSP_Y].w.h +#define rA m_gr[SSP_A].w.h +#define rST m_gr[SSP_ST].w.h // 4 +#define rSTACK m_gr[SSP_STACK].w.h +#define rPC m_gr[SSP_PC].w.h +#define rP m_gr[SSP_P] + +#define rAL m_gr[SSP_A].w.l +#define rA32 m_gr[SSP_A].d +#define rIJ m_r + +#define IJind (((op>>6)&4)|(op&3)) + +#define PPC m_ppc.w.h + +#define FETCH() m_direct->read_word(rPC++ << 1) +#define PROGRAM_WORD(a) m_program->read_word((a) << 1) +#define GET_PPC_OFFS() PPC + +#define REG_READ(r) (((r) <= 4) ? m_gr[r].w.h : (this->*reg_read_handlers[r])(r)) +#define REG_WRITE(r,d) { \ + int r1 = r; \ + if (r1 >= 4) (this->*reg_write_handlers[r1])(r1,d); \ + else if (r1 > 0) m_gr[r1].w.h = d; \ +} + +// flags +#define SSP_FLAG_L (1<<0xc) +#define SSP_FLAG_Z (1<<0xd) +#define SSP_FLAG_V (1<<0xe) +#define SSP_FLAG_N (1<<0xf) + +// update ZN according to 32bit ACC. +#define UPD_ACC_ZN \ + rST &= ~(SSP_FLAG_Z|SSP_FLAG_N); \ + if (!rA32) rST |= SSP_FLAG_Z; \ + else rST |= (rA32>>16)&SSP_FLAG_N; + +// it seems SVP code never checks for L and OV, so we leave them out. +#define UPD_LZVN \ + rST &= ~(SSP_FLAG_L|SSP_FLAG_Z|SSP_FLAG_V|SSP_FLAG_N); \ + if (!rA32) rST |= SSP_FLAG_Z; \ + else rST |= (rA32>>16)&SSP_FLAG_N; + +// standard cond processing. +// again, only Z and N is checked, as VR doesn't seem to use any other conds. +#define COND_CHECK \ + switch (op&0xf0) { \ + case 0x00: cond = 1; break; /* always true */ \ + case 0x50: cond = !((rST ^ (op<<5)) & SSP_FLAG_Z); break; /* Z matches f(?) bit */ \ + case 0x70: cond = !((rST ^ (op<<7)) & SSP_FLAG_N); break; /* N matches f(?) bit */ \ + default:logerror(__FILE__ " FIXME: unimplemented cond @ %04x\n", GET_PPC_OFFS()); break; \ + } + +// ops with accumulator. +// note that 'ld A' doesn't affect flags +#define OP_LDA(x) \ + rA = x + +#define OP_LDA32(x) \ + rA32 = x + +#define OP_SUBA(x) { \ + rA32 -= (x) << 16; \ + UPD_LZVN \ +} + +#define OP_SUBA32(x) { \ + rA32 -= (x); \ + UPD_LZVN \ +} + +#define OP_CMPA(x) { \ + UINT32 t = rA32 - ((x) << 16); \ + rST &= ~(SSP_FLAG_L|SSP_FLAG_Z|SSP_FLAG_V|SSP_FLAG_N); \ + if (!t) rST |= SSP_FLAG_Z; \ + else rST |= (t>>16)&SSP_FLAG_N; \ +} + +#define OP_CMPA32(x) { \ + UINT32 t = rA32 - (x); \ + rST &= ~(SSP_FLAG_L|SSP_FLAG_Z|SSP_FLAG_V|SSP_FLAG_N); \ + if (!t) rST |= SSP_FLAG_Z; \ + else rST |= (t>>16)&SSP_FLAG_N; \ +} + +#define OP_ADDA(x) { \ + rA32 += (x) << 16; \ + UPD_LZVN \ +} + +#define OP_ADDA32(x) { \ + rA32 += (x); \ + UPD_LZVN \ +} + +#define OP_ANDA(x) \ + rA32 &= (x) << 16; \ + UPD_ACC_ZN + +#define OP_ANDA32(x) \ + rA32 &= (x); \ + UPD_ACC_ZN + +#define OP_ORA(x) \ + rA32 |= (x) << 16; \ + UPD_ACC_ZN + +#define OP_ORA32(x) \ + rA32 |= (x); \ + UPD_ACC_ZN + +#define OP_EORA(x) \ + rA32 ^= (x) << 16; \ + UPD_ACC_ZN + +#define OP_EORA32(x) \ + rA32 ^= (x); \ + UPD_ACC_ZN + + +#define OP_CHECK32(OP) { \ + if ((op & 0x0f) == SSP_P) { /* A <- P */ \ + update_P(); \ + OP(rP.d); \ + break; \ + } \ + if ((op & 0x0f) == SSP_A) { /* A <- A */ \ + OP(rA32); \ + break; \ + } \ +} + + +#ifdef DO_CHECKS +#define CHECK_IMM16() if (op&0x1ff) logerror(__FILE__ " imm bits! %04x @ %04x\n", op, GET_PPC_OFFS()) +#define CHECK_B_SET() if (op&0x100) logerror(__FILE__ " b set! %04x @ %04x\n", op, GET_PPC_OFFS()) +#define CHECK_B_CLEAR() if (!(op&0x100)) logerror(__FILE__ " b clear! %04x @ %04x\n", op, GET_PPC_OFFS()) +#define CHECK_MOD() if (op&0x00c) logerror(__FILE__ " mod bits! %04x @ %04x\n", op, GET_PPC_OFFS()) +#define CHECK_10f() if (op&0x10f) logerror(__FILE__ " bits 10f! %04x @ %04x\n", op, GET_PPC_OFFS()) +#define CHECK_008() if (op&0x008) logerror(__FILE__ " bits 008! %04x @ %04x\n", op, GET_PPC_OFFS()) +#define CHECK_00f() if (op&0x00f) logerror(__FILE__ " bits 00f! %04x @ %04x\n", op, GET_PPC_OFFS()) +#define CHECK_0f0() if (op&0x0f0) logerror(__FILE__ " bits 0f0! %04x @ %04x\n", op, GET_PPC_OFFS()) +#define CHECK_1f0() if (op&0x1f0) logerror(__FILE__ " bits 1f0! %04x @ %04x\n", op, GET_PPC_OFFS()) +#define CHECK_RPL() if (rST&7) logerror(__FILE__ " unhandled RPL! %04x @ %04x\n", op, GET_PPC_OFFS()) +#define CHECK_ST(d) if((rST^d)&0xf98)logerror(__FILE__ " ssp FIXME ST %04x -> %04x @ %04x\n", rST, d, GET_PPC_OFFS()) +#else +#define CHECK_IMM16() +#define CHECK_B_SET() +#define CHECK_B_CLEAR() +#define CHECK_MOD() +#define CHECK_10f() +#define CHECK_008() +#define CHECK_00f() +#define CHECK_0f0() +#define CHECK_1f0() +#define CHECK_RPL() +#define CHECK_ST(d) +#endif + + +const device_type SSP1601 = &device_creator; + + +ssp1601_device::ssp1601_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : cpu_device(mconfig, SSP1601, "SSP1601", tag, owner, clock, "ssp1601", __FILE__) + , m_program_config("program", ENDIANNESS_BIG, 16, 16, -1) + , m_io_config("io", ENDIANNESS_BIG, 16, 4, 0) +{ +} + + +offs_t ssp1601_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( ssp1601 ); + return CPU_DISASSEMBLE_NAME(ssp1601)(this, buffer, pc, oprom, opram, options); +} + + +// ----------------------------------------------------- +// register i/o handlers + +void ssp1601_device::update_P() +{ + int m1 = (signed short)rX; + int m2 = (signed short)rY; + rP.d = (m1 * m2 * 2); +} + +UINT32 ssp1601_device::read_unknown(int reg) +{ + logerror("%s:%i FIXME\n", __FILE__, __LINE__); + return 0; +} + +void ssp1601_device::write_unknown(int reg, UINT32 d) +{ + logerror("%s:%i FIXME\n", __FILE__, __LINE__); +} + +/* map EXT regs to virtual I/O range of 0x00-0x0f */ +UINT32 ssp1601_device::read_ext(int reg) +{ + reg &= 7; + return m_io->read_word((reg << 1)); +} + +void ssp1601_device::write_ext(int reg, UINT32 d) +{ + reg &= 7; + m_io->write_word((reg << 1), d); +} + +// 4 +void ssp1601_device::write_ST(int reg, UINT32 d) +{ + CHECK_ST(d); + rST = d; +} + +// 5 +UINT32 ssp1601_device::read_STACK(int reg) +{ + --rSTACK; + if ((signed short)rSTACK < 0) { + rSTACK = 5; + logerror(__FILE__ " FIXME: stack underflow! (%i) @ %04x\n", rSTACK, GET_PPC_OFFS()); + } + return m_stack[rSTACK]; +} + +void ssp1601_device::write_STACK(int reg, UINT32 d) +{ + if (rSTACK >= 6) { + logerror(__FILE__ " FIXME: stack overflow! (%i) @ %04x\n", rSTACK, GET_PPC_OFFS()); + rSTACK = 0; + } + m_stack[rSTACK++] = d; +} + +// 6 +UINT32 ssp1601_device::read_PC(int reg) +{ + return rPC; +} + +void ssp1601_device::write_PC(int reg, UINT32 d) +{ + rPC = d; + m_g_cycles--; +} + +// 7 +UINT32 ssp1601_device::read_P(int reg) +{ + update_P(); + return rP.w.h; +} + +// 15 +UINT32 ssp1601_device::read_AL(int reg) +{ + /* apparently reading AL causes some effect on EXT bus, VR depends on that.. */ + read_ext(reg); + return rAL; +} + +void ssp1601_device::write_AL(int reg, UINT32 d) +{ + write_ext(reg, d); + rAL = d; +} + + + +const ssp1601_device::read_func_t ssp1601_device::reg_read_handlers[16] = +{ + &ssp1601_device::read_unknown, &ssp1601_device::read_unknown, &ssp1601_device::read_unknown, &ssp1601_device::read_unknown, // -, X, Y, A + &ssp1601_device::read_unknown, // 4 ST + &ssp1601_device::read_STACK, + &ssp1601_device::read_PC, + &ssp1601_device::read_P, + &ssp1601_device::read_ext, // 8 + &ssp1601_device::read_ext, + &ssp1601_device::read_ext, + &ssp1601_device::read_ext, + &ssp1601_device::read_ext, // 12 + &ssp1601_device::read_ext, + &ssp1601_device::read_ext, + &ssp1601_device::read_AL +}; + +const ssp1601_device::write_func_t ssp1601_device::reg_write_handlers[16] = +{ + &ssp1601_device::write_unknown, &ssp1601_device::write_unknown, &ssp1601_device::write_unknown, &ssp1601_device::write_unknown, // -, X, Y, A + &ssp1601_device::write_ST, + &ssp1601_device::write_STACK, + &ssp1601_device::write_PC, + &ssp1601_device::write_unknown, // 7 P (not writable) + &ssp1601_device::write_ext, // 8 + &ssp1601_device::write_ext, + &ssp1601_device::write_ext, + &ssp1601_device::write_ext, + &ssp1601_device::write_ext, // 12 + &ssp1601_device::write_ext, + &ssp1601_device::write_ext, + &ssp1601_device::write_AL +}; + +// ----------------------------------------------------- +// pointer register handlers + +// +#define ptr1_read(op) ptr1_read_(op&3,(op>>6)&4,(op<<1)&0x18) + +UINT32 ssp1601_device::ptr1_read_(int ri, int isj2, int modi3) +{ + //int t = (op&3) | ((op>>6)&4) | ((op<<1)&0x18); + UINT32 mask, add = 0, t = ri | isj2 | modi3; + unsigned char *rp = NULL; + switch (t) + { + // mod=0 (00) + case 0x00: + case 0x01: + case 0x02: return mem.m_RAM0[regs.m_r0[t&3]]; + case 0x03: return mem.m_RAM0[0]; + case 0x04: + case 0x05: + case 0x06: return mem.m_RAM1[regs.m_r1[t&3]]; + case 0x07: return mem.m_RAM1[0]; + // mod=1 (01), "+!" + case 0x08: + case 0x09: + case 0x0a: return mem.m_RAM0[regs.m_r0[t&3]++]; + case 0x0b: return mem.m_RAM0[1]; + case 0x0c: + case 0x0d: + case 0x0e: return mem.m_RAM1[regs.m_r1[t&3]++]; + case 0x0f: return mem.m_RAM1[1]; + // mod=2 (10), "-" + case 0x10: + case 0x11: + case 0x12: rp = ®s.m_r0[t&3]; t = mem.m_RAM0[*rp]; + if (!(rST&7)) { (*rp)--; return t; } + add = -1; goto modulo; + case 0x13: return mem.m_RAM0[2]; + case 0x14: + case 0x15: + case 0x16: rp = ®s.m_r1[t&3]; t = mem.m_RAM1[*rp]; + if (!(rST&7)) { (*rp)--; return t; } + add = -1; goto modulo; + case 0x17: return mem.m_RAM1[2]; + // mod=3 (11), "+" + case 0x18: + case 0x19: + case 0x1a: rp = ®s.m_r0[t&3]; t = mem.m_RAM0[*rp]; + if (!(rST&7)) { (*rp)++; return t; } + add = 1; goto modulo; + case 0x1b: return mem.m_RAM0[3]; + case 0x1c: + case 0x1d: + case 0x1e: rp = ®s.m_r1[t&3]; t = mem.m_RAM1[*rp]; + if (!(rST&7)) { (*rp)++; return t; } + add = 1; goto modulo; + case 0x1f: return mem.m_RAM1[3]; + } + + return 0; + +modulo: + mask = (1 << (rST&7)) - 1; + *rp = (*rp & ~mask) | ((*rp + add) & mask); + return t; +} + +void ssp1601_device::ptr1_write(int op, UINT32 d) +{ + int t = (op&3) | ((op>>6)&4) | ((op<<1)&0x18); + switch (t) + { + // mod=0 (00) + case 0x00: + case 0x01: + case 0x02: mem.m_RAM0[regs.m_r0[t&3]] = d; return; + case 0x03: mem.m_RAM0[0] = d; return; + case 0x04: + case 0x05: + case 0x06: mem.m_RAM1[regs.m_r1[t&3]] = d; return; + case 0x07: mem.m_RAM1[0] = d; return; + // mod=1 (01), "+!" + // mod=3, "+" + case 0x08: + case 0x09: + case 0x0a: mem.m_RAM0[regs.m_r0[t&3]++] = d; return; + case 0x0b: mem.m_RAM0[1] = d; return; + case 0x0c: + case 0x0d: + case 0x0e: mem.m_RAM1[regs.m_r1[t&3]++] = d; return; + case 0x0f: mem.m_RAM1[1] = d; return; + // mod=2 (10), "-" + case 0x10: + case 0x11: + case 0x12: mem.m_RAM0[regs.m_r0[t&3]--] = d; CHECK_RPL(); return; + case 0x13: mem.m_RAM0[2] = d; return; + case 0x14: + case 0x15: + case 0x16: mem.m_RAM1[regs.m_r1[t&3]--] = d; CHECK_RPL(); return; + case 0x17: mem.m_RAM1[2] = d; return; + // mod=3 (11), "+" + case 0x18: + case 0x19: + case 0x1a: mem.m_RAM0[regs.m_r0[t&3]++] = d; CHECK_RPL(); return; + case 0x1b: mem.m_RAM0[3] = d; return; + case 0x1c: + case 0x1d: + case 0x1e: mem.m_RAM1[regs.m_r1[t&3]++] = d; CHECK_RPL(); return; + case 0x1f: mem.m_RAM1[3] = d; return; + } +} + +UINT32 ssp1601_device::ptr2_read(int op) +{ + int mv = 0, t = (op&3) | ((op>>6)&4) | ((op<<1)&0x18); + switch (t) + { + // mod=0 (00) + case 0x00: + case 0x01: + case 0x02: mv = mem.m_RAM0[regs.m_r0[t&3]]++; break; + case 0x03: mv = mem.m_RAM0[0]++; break; + case 0x04: + case 0x05: + case 0x06: mv = mem.m_RAM1[regs.m_r1[t&3]]++; break; + case 0x07: mv = mem.m_RAM1[0]++; break; + // mod=1 (01) + case 0x0b: mv = mem.m_RAM0[1]++; break; + case 0x0f: mv = mem.m_RAM1[1]++; break; + // mod=2 (10) + case 0x13: mv = mem.m_RAM0[2]++; break; + case 0x17: mv = mem.m_RAM1[2]++; break; + // mod=3 (11) + case 0x1b: mv = mem.m_RAM0[3]++; break; + case 0x1f: mv = mem.m_RAM1[3]++; break; + default: logerror(__FILE__ " FIXME: unimplemented mod in ((rX)) @ %04x\n", GET_PPC_OFFS()); + return 0; + } + + return PROGRAM_WORD(mv); +} + + +// ----------------------------------------------------- + + +void ssp1601_device::device_start() +{ + save_item(NAME(rX)); + save_item(NAME(rY)); + save_item(NAME(rA32)); + save_item(NAME(rST)); + save_item(NAME(rSTACK)); + save_item(NAME(rPC)); + save_item(NAME(rP.d)); + save_item(NAME(PPC)); + save_item(NAME(m_stack)); + save_item(NAME(m_r)); + save_item(NAME(m_RAM)); + + /* clear the state */ + for ( int i = 0; i < 8; i++ ) + { + m_gr[i].d = 0; + m_r[i] = 0; + } + memset( m_RAM, 0, sizeof(m_RAM)); + for ( int i = 0; i < 6; i++ ) + { + m_stack[i] = 0; + } + m_ppc.d = 0; + m_g_cycles = 0; + + m_gr[0].w.h = 0xffff; // constant reg + m_program = &space(AS_PROGRAM); + m_direct = &m_program->direct(); + m_io = &space(AS_IO); + + state_add( SSP_R0, "REG0", m_gr[0].w.h).formatstr("%04X"); + state_add( SSP_X, "X", rX).formatstr("%04X"); + state_add( SSP_Y, "Y", rY).formatstr("%04X"); + state_add( SSP_A, "A", rA32).formatstr("%08X"); + state_add( SSP_ST, "ST", rST).formatstr("%04X"); + state_add( SSP_STACK, "STACK", rSTACK).formatstr("%04X"); + state_add( SSP_PC, "PC", rPC).formatstr("%04X"); + state_add( SSP_P, "P", rP.d).formatstr("%08X"); + state_add( SSP_STACK0, "STACK0", m_stack[0]).formatstr("%04X"); + state_add( SSP_STACK1, "STACK1", m_stack[1]).formatstr("%04X"); + state_add( SSP_STACK2, "STACK2", m_stack[2]).formatstr("%04X"); + state_add( SSP_STACK3, "STACK3", m_stack[3]).formatstr("%04X"); + state_add( SSP_STACK4, "STACK4", m_stack[4]).formatstr("%04X"); + state_add( SSP_STACK5, "STACK5", m_stack[5]).formatstr("%04X"); + state_add( SSP_PR0, "R0", m_r[0]).formatstr("%02X"); + state_add( SSP_PR1, "R1", m_r[1]).formatstr("%02X"); + state_add( SSP_PR2, "R2", m_r[2]).formatstr("%02X"); + state_add( SSP_PR3, "R3", m_r[3]).formatstr("%02X"); + state_add( SSP_PR4, "R4", m_r[4]).formatstr("%02X"); + state_add( SSP_PR5, "R5", m_r[5]).formatstr("%02X"); + state_add( SSP_PR6, "R6", m_r[6]).formatstr("%02X"); + state_add( SSP_PR7, "R7", m_r[7]).formatstr("%02X"); + + state_add(STATE_GENPC, "GENPC", rPC).noshow(); + state_add(STATE_GENFLAGS, "GENFLAGS", rST).formatstr("%4s").noshow(); + state_add(STATE_GENPCBASE, "GENPCBASE", PPC).noshow(); + + m_icountptr = &m_g_cycles; +} + + +void ssp1601_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + switch (entry.index()) + { + case STATE_GENFLAGS: + strprintf(str, "%c%c%c%c", (rST&SSP_FLAG_N) ? 'N' : '.', (rST&SSP_FLAG_V) ? 'V' : '.', + (rST&SSP_FLAG_Z)?'Z':'.', (rST&SSP_FLAG_L)?'L':'.' + ); + break; + } +} + + +void ssp1601_device::device_reset() +{ + rPC = 0x400; + rSTACK = 0; // ? using ascending stack + rST = 0; +} + + +void ssp1601_device::execute_run() +{ + while (m_g_cycles > 0) + { + int op; + UINT32 tmpv; + + PPC = rPC; + + debugger_instruction_hook(this, rPC); + + op = FETCH(); + + switch (op >> 9) + { + // ld d, s + case 0x00: + CHECK_B_SET(); + if (op == 0) break; // nop + if (op == ((SSP_A<<4)|SSP_P)) { // A <- P + update_P(); + rA32 = rP.d; + } + else + { + tmpv = REG_READ(op & 0x0f); + REG_WRITE((op & 0xf0) >> 4, tmpv); + } + break; + + // ld d, (ri) + case 0x01: tmpv = ptr1_read(op); REG_WRITE((op & 0xf0) >> 4, tmpv); break; + + // ld (ri), s + case 0x02: tmpv = REG_READ((op & 0xf0) >> 4); ptr1_write(op, tmpv); break; + + // ldi d, imm + case 0x04: CHECK_10f(); tmpv = FETCH(); REG_WRITE((op & 0xf0) >> 4, tmpv);m_g_cycles--; break; + + // ld d, ((ri)) + case 0x05: CHECK_MOD(); tmpv = ptr2_read(op); REG_WRITE((op & 0xf0) >> 4, tmpv); m_g_cycles -= 2; break; + + // ldi (ri), imm + case 0x06: tmpv = FETCH(); ptr1_write(op, tmpv); m_g_cycles--; break; + + // ld adr, a + case 0x07: m_RAM[op & 0x1ff] = rA; break; + + // ld d, ri + case 0x09: CHECK_MOD(); tmpv = rIJ[(op&3)|((op>>6)&4)]; REG_WRITE((op & 0xf0) >> 4, tmpv); break; + + // ld ri, s + case 0x0a: CHECK_MOD(); rIJ[(op&3)|((op>>6)&4)] = REG_READ((op & 0xf0) >> 4); break; + + // ldi ri, simm + case 0x0c: + case 0x0d: + case 0x0e: + case 0x0f: rIJ[(op>>8)&7] = op; break; + + // call cond, addr + case 0x24: { + int cond = 0; + CHECK_00f(); + COND_CHECK + if (cond) { int new_PC = FETCH(); write_STACK(SSP_STACK, rPC); rPC = new_PC; } + else rPC++; + m_g_cycles--; // always 2 cycles + break; + } + + // ld d, (a) + case 0x25: + CHECK_10f(); + tmpv = PROGRAM_WORD(rA); + REG_WRITE((op & 0xf0) >> 4, tmpv); + m_g_cycles -= 2; // 3 cycles total + break; + + // bra cond, addr + case 0x26: { + int cond = 0; + CHECK_00f(); + COND_CHECK + if (cond) { rPC = FETCH(); } + else rPC++; + m_g_cycles--; + break; + } + + // mod cond, op + case 0x48: { + int cond = 0; + CHECK_008(); + COND_CHECK + if (cond) { + switch (op & 7) { + case 2: rA32 = (signed int)rA32 >> 1; break; // shr (arithmetic) + case 3: rA32 <<= 1; break; // shl + case 6: rA32 = -(signed int)rA32; break; // neg + case 7: if ((int)rA32 < 0) rA32 = -(signed int)rA32; break; // abs + default: logerror(__FILE__ " FIXME: unhandled mod %i @ %04x\n", + op&7, GET_PPC_OFFS()); + } + UPD_ACC_ZN + } + break; + } + + // mpys? + case 0x1b: + CHECK_B_CLEAR(); + update_P(); + rA32 -= rP.d; + UPD_ACC_ZN + rX = ptr1_read_(op&3, 0, (op<<1)&0x18); + rY = ptr1_read_((op>>4)&3, 4, (op>>3)&0x18); + break; + + // mpya (rj), (ri), b + case 0x4b: + CHECK_B_CLEAR(); + update_P(); + rA32 += rP.d; + UPD_ACC_ZN + rX = ptr1_read_(op&3, 0, (op<<1)&0x18); + rY = ptr1_read_((op>>4)&3, 4, (op>>3)&0x18); + break; + + // mld (rj), (ri), b + case 0x5b: + CHECK_B_CLEAR(); + rA32 = 0; + rST &= 0x0fff; + rST |= SSP_FLAG_Z; + rX = ptr1_read_(op&3, 0, (op<<1)&0x18); + rY = ptr1_read_((op>>4)&3, 4, (op>>3)&0x18); + break; + + // OP a, s + case 0x10: CHECK_1f0(); OP_CHECK32(OP_SUBA32); tmpv = REG_READ(op & 0x0f); OP_SUBA(tmpv); break; + case 0x30: CHECK_1f0(); OP_CHECK32(OP_CMPA32); tmpv = REG_READ(op & 0x0f); OP_CMPA(tmpv); break; + case 0x40: CHECK_1f0(); OP_CHECK32(OP_ADDA32); tmpv = REG_READ(op & 0x0f); OP_ADDA(tmpv); break; + case 0x50: CHECK_1f0(); OP_CHECK32(OP_ANDA32); tmpv = REG_READ(op & 0x0f); OP_ANDA(tmpv); break; + case 0x60: CHECK_1f0(); OP_CHECK32(OP_ORA32 ); tmpv = REG_READ(op & 0x0f); OP_ORA (tmpv); break; + case 0x70: CHECK_1f0(); OP_CHECK32(OP_EORA32); tmpv = REG_READ(op & 0x0f); OP_EORA(tmpv); break; + + // OP a, (ri) + case 0x11: CHECK_0f0(); tmpv = ptr1_read(op); OP_SUBA(tmpv); break; + case 0x31: CHECK_0f0(); tmpv = ptr1_read(op); OP_CMPA(tmpv); break; + case 0x41: CHECK_0f0(); tmpv = ptr1_read(op); OP_ADDA(tmpv); break; + case 0x51: CHECK_0f0(); tmpv = ptr1_read(op); OP_ANDA(tmpv); break; + case 0x61: CHECK_0f0(); tmpv = ptr1_read(op); OP_ORA (tmpv); break; + case 0x71: CHECK_0f0(); tmpv = ptr1_read(op); OP_EORA(tmpv); break; + + // OP a, adr + case 0x03: tmpv = m_RAM[op & 0x1ff]; OP_LDA (tmpv); break; + case 0x13: tmpv = m_RAM[op & 0x1ff]; OP_SUBA(tmpv); break; + case 0x33: tmpv = m_RAM[op & 0x1ff]; OP_CMPA(tmpv); break; + case 0x43: tmpv = m_RAM[op & 0x1ff]; OP_ADDA(tmpv); break; + case 0x53: tmpv = m_RAM[op & 0x1ff]; OP_ANDA(tmpv); break; + case 0x63: tmpv = m_RAM[op & 0x1ff]; OP_ORA (tmpv); break; + case 0x73: tmpv = m_RAM[op & 0x1ff]; OP_EORA(tmpv); break; + + // OP a, imm + case 0x14: CHECK_IMM16(); tmpv = FETCH(); OP_SUBA(tmpv); m_g_cycles--; break; + case 0x34: CHECK_IMM16(); tmpv = FETCH(); OP_CMPA(tmpv); m_g_cycles--; break; + case 0x44: CHECK_IMM16(); tmpv = FETCH(); OP_ADDA(tmpv); m_g_cycles--; break; + case 0x54: CHECK_IMM16(); tmpv = FETCH(); OP_ANDA(tmpv); m_g_cycles--; break; + case 0x64: CHECK_IMM16(); tmpv = FETCH(); OP_ORA (tmpv); m_g_cycles--; break; + case 0x74: CHECK_IMM16(); tmpv = FETCH(); OP_EORA(tmpv); m_g_cycles--; break; + + // OP a, ((ri)) + case 0x15: CHECK_MOD(); tmpv = ptr2_read(op); OP_SUBA(tmpv); m_g_cycles -= 2; break; + case 0x35: CHECK_MOD(); tmpv = ptr2_read(op); OP_CMPA(tmpv); m_g_cycles -= 2; break; + case 0x45: CHECK_MOD(); tmpv = ptr2_read(op); OP_ADDA(tmpv); m_g_cycles -= 2; break; + case 0x55: CHECK_MOD(); tmpv = ptr2_read(op); OP_ANDA(tmpv); m_g_cycles -= 2; break; + case 0x65: CHECK_MOD(); tmpv = ptr2_read(op); OP_ORA (tmpv); m_g_cycles -= 2; break; + case 0x75: CHECK_MOD(); tmpv = ptr2_read(op); OP_EORA(tmpv); m_g_cycles -= 2; break; + + // OP a, ri + case 0x19: CHECK_MOD(); tmpv = rIJ[IJind]; OP_SUBA(tmpv); break; + case 0x39: CHECK_MOD(); tmpv = rIJ[IJind]; OP_CMPA(tmpv); break; + case 0x49: CHECK_MOD(); tmpv = rIJ[IJind]; OP_ADDA(tmpv); break; + case 0x59: CHECK_MOD(); tmpv = rIJ[IJind]; OP_ANDA(tmpv); break; + case 0x69: CHECK_MOD(); tmpv = rIJ[IJind]; OP_ORA (tmpv); break; + case 0x79: CHECK_MOD(); tmpv = rIJ[IJind]; OP_EORA(tmpv); break; + + // OP simm + case 0x1c: CHECK_B_SET(); OP_SUBA(op & 0xff); break; + case 0x3c: CHECK_B_SET(); OP_CMPA(op & 0xff); break; + case 0x4c: CHECK_B_SET(); OP_ADDA(op & 0xff); break; + case 0x5c: CHECK_B_SET(); OP_ANDA(op & 0xff); break; + case 0x6c: CHECK_B_SET(); OP_ORA (op & 0xff); break; + case 0x7c: CHECK_B_SET(); OP_EORA(op & 0xff); break; + + default: + logerror(__FILE__ " FIXME unhandled op %04x @ %04x\n", op, GET_PPC_OFFS()); + break; + } + m_g_cycles--; + } + + update_P(); +} + + +void ssp1601_device::execute_set_input( int inputnum, int state ) +{ + fatalerror("ssp1610: execute_set_input not implemented yet!\n"); +} diff --git a/src/devices/cpu/ssp1601/ssp1601.h b/src/devices/cpu/ssp1601/ssp1601.h new file mode 100644 index 00000000000..ef400cac42b --- /dev/null +++ b/src/devices/cpu/ssp1601/ssp1601.h @@ -0,0 +1,107 @@ +// license:BSD-3-Clause +// copyright-holders:Pierpaolo Prazzoli +#pragma once + +#ifndef __SSP1601_H__ +#define __SSP1601_H__ + + +enum +{ + /* general registers */ + SSP_R0, SSP_X, SSP_Y, SSP_A, + SSP_ST, SSP_STACK, SSP_PC, SSP_P, + /* hardware stack */ + SSP_STACK0, SSP_STACK1, SSP_STACK2, SSP_STACK3, SSP_STACK4, SSP_STACK5, + /* pointer registers */ + SSP_PR0, SSP_PR1, SSP_PR2, SSP_PR3, SSP_PR4, SSP_PR5, SSP_PR6, SSP_PR7 +}; + + +class ssp1601_device : public cpu_device +{ +public: + // construction/destruction + ssp1601_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_execute_interface overrides + virtual UINT32 execute_min_cycles() const { return 1; } + virtual UINT32 execute_max_cycles() const { return 4; } + virtual UINT32 execute_input_lines() const { return 3; } + virtual void execute_run(); + virtual void execute_set_input(int inputnum, int state); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const { return (spacenum == AS_PROGRAM) ? &m_program_config : ((spacenum == AS_IO) ? &m_io_config : NULL); } + + // device_state_interface overrides + void state_string_export(const device_state_entry &entry, std::string &str); + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const { return 2; } + virtual UINT32 disasm_max_opcode_bytes() const { return 4; } + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + +private: + address_space_config m_program_config; + address_space_config m_io_config; + + PAIR m_gr[8]; /* general regs, some are 16bit, some 32bit */ + union { + unsigned char m_r[8]; /* pointer registers, 4 for earch bank */ + struct { + unsigned char m_r0[4]; + unsigned char m_r1[4]; + } regs; + }; + union { + unsigned short m_RAM[256*2]; /* 2 256-word internal RAM banks */ + struct { + unsigned short m_RAM0[256]; + unsigned short m_RAM1[256]; + } mem; + }; + UINT16 m_stack[6]; /* 6-level hardware stack */ + PAIR m_ppc; + + int m_g_cycles; + + address_space *m_program; + direct_read_data *m_direct; + address_space *m_io; + + void update_P(); + UINT32 read_unknown(int reg); + void write_unknown(int reg, UINT32 d); + UINT32 read_ext(int reg); + void write_ext(int reg, UINT32 d); + void write_ST(int reg, UINT32 d); + UINT32 read_STACK(int reg); + void write_STACK(int reg, UINT32 d); + UINT32 read_PC(int reg); + void write_PC(int reg, UINT32 d); + UINT32 read_P(int reg); + UINT32 read_AL(int reg); + void write_AL(int reg, UINT32 d); + UINT32 ptr1_read_(int ri, int isj2, int modi3); + void ptr1_write(int op, UINT32 d); + UINT32 ptr2_read(int op); + + typedef UINT32 (ssp1601_device::*read_func_t)(int reg); + typedef void (ssp1601_device::*write_func_t)(int reg, UINT32 d); + + static const read_func_t reg_read_handlers[16]; + static const write_func_t reg_write_handlers[16]; + +}; + + +extern const device_type SSP1601; + + +#endif /* __SSP1601_H__ */ diff --git a/src/devices/cpu/ssp1601/ssp1601d.c b/src/devices/cpu/ssp1601/ssp1601d.c new file mode 100644 index 00000000000..c147cbd8534 --- /dev/null +++ b/src/devices/cpu/ssp1601/ssp1601d.c @@ -0,0 +1,298 @@ +// license:BSD-3-Clause +// copyright-holders:Pierpaolo Prazzoli +/* + + SSP1601 disassembler + written by Pierpaolo Prazzoli + updated for SSP1601 by Grazvydas Ignotas + +*/ + +#include "emu.h" +#include "debugger.h" + + +static const char *const reg[16] = +{ + "-", "X", "Y", "A", + "ST", "STACK", "PC", "P", + "EXT0", "EXT1", "EXT2", "EXT3", + "EXT4", "EXT5", "EXT6", "AL" +}; + +static const char *const rij[8] = +{ + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7" +}; + +static const char *const modifier[4] = +{ + "", "+!", "-", "+" +}; + +static const char *const modifier_sf[4] = +{ + "|00", "|01", "|10", "|11" +}; + +static const char *const cond[16] = +{ + "always", "RESERVED", "gpi0", "gpi1", + "l", "z", "ov", "n", + "diof", "gpi2", "gpi3", "RESERVED", + "RESERVED", "RESERVED", "RESERVED", "RESERVED", +}; + +static const char *const acc_op[8] = +{ + "ror", "rol", "shr", "shl", "inc", "dec", "neg", "abs" +}; + +// pag. 81 uses different addresses! +static const char *const flag_op[16] = +{ + "?", "?", "resl", "setl", "resie", "setie", "?", "?", "resop", "setop", "?", "?", "?", "?", "res", "set" +}; + +static const char *const arith_ops[8] = +{ + "", "add", "", "cmp", "add", "and", "or", "eor" +}; + + +#define BIT_B ((op >> 8) & 1) +#define RIJ rij[(BIT_B << 2) + (op & 3)] +#define RI(i) rij[(i) & 3] +#define RJ(i) rij[((i) & 3) + 4] +#define MODIFIER(mod,r3) (((r3) == 3) ? modifier_sf[mod] : modifier[mod]) +#define MODIFIER_LOW MODIFIER((op >> 2) & 3, op&3) +#define MODIFIER_HIGH MODIFIER((op >> 6) & 3, (op >> 4)&3) + +#define READ_OP_DASM(p) ((base_oprom[p] << 8) | base_oprom[(p) + 1]) + +static char *get_cond(int op) +{ + static char scond[16]; + if (op&0xf0) sprintf(scond, "%s=%i", cond[(op >> 4) & 0xf], BIT_B); + else sprintf(scond, "%s", cond[(op >> 4) & 0xf]); + return scond; +} + + +static unsigned dasm_ssp1601(char *buffer, unsigned pc, const UINT8 *oprom) +{ + const UINT8 *base_oprom; + UINT16 op; + int size = 1; + int flags = 0; + + base_oprom = oprom; + + op = READ_OP_DASM(0); + + switch (op >> 9) + { + case 0x00: + if(op == 0) + { + // nop + sprintf(buffer, "nop"); + } + else if((op & 0xff) == 0x65) + { + // ret + sprintf(buffer, "ret"); + flags |= DASMFLAG_STEP_OUT; + } + else + { + // ld d, s + sprintf(buffer, "ld %s, %s", reg[(op >> 4) & 0xf], reg[op & 0xf]); + } + break; + + // ld d, (ri) + case 0x01: + sprintf(buffer, "ld %s, (%s%s)", reg[(op >> 4) & 0xf], RIJ, MODIFIER_LOW); + break; + + // ld (ri), s + case 0x02: + sprintf(buffer, "ld (%s%s), %s", RIJ, MODIFIER_LOW, reg[(op >> 4) & 0xf]); + break; + + // ld a, addr + case 0x03: + sprintf(buffer, "ld A, %X", op & 0x1ff); + break; + + // ldi d, imm + case 0x04: + sprintf(buffer, "ld %s, %X", reg[(op >> 4) & 0xf], READ_OP_DASM(2)); + size = 2; + break; + + // ld d, ((ri)) + case 0x05: + sprintf(buffer, "ld %s, ((%s%s))", reg[(op >> 4) & 0xf], RIJ, MODIFIER_LOW); + break; + + // ldi (ri), imm + case 0x06: + sprintf(buffer, "ld (%s%s), %X", RIJ, MODIFIER_LOW, READ_OP_DASM(2)); + size = 2; + break; + + // ld addr, a + case 0x07: + sprintf(buffer, "ld %X, A", op & 0x1ff); + break; + + // ld d, ri + case 0x09: + sprintf(buffer, "ld %s, %s%s", reg[(op >> 4) & 0xf], RIJ, MODIFIER_LOW); + break; + + // ld ri, s + case 0x0a: + sprintf(buffer, "ld %s%s, %s", RIJ, MODIFIER_LOW, reg[(op >> 4) & 0xf]); + break; + + // ldi ri, simm + case 0x0c: + case 0x0d: + case 0x0e: + case 0x0f: + sprintf(buffer, "ldi %s, %X", rij[(op >> 8) & 7], op & 0xff); + break; + + // op a, s + case 0x10: + case 0x30: + case 0x40: + case 0x50: + case 0x60: + case 0x70: + sprintf(buffer, "%s A, %s", arith_ops[op >> 13], reg[op & 0xf]); + break; + + // op a, (ri) + case 0x11: + case 0x31: + case 0x41: + case 0x51: + case 0x61: + case 0x71: + sprintf(buffer, "%s A, (%s%s)", arith_ops[op >> 13], RIJ, MODIFIER_LOW); + break; + + // op a, adr + case 0x13: + case 0x33: + case 0x43: + case 0x53: + case 0x63: + case 0x73: + sprintf(buffer, "%s A, %X", arith_ops[op >> 13], op & 0x1ff); + break; + + // subi a, imm + case 0x14: + case 0x34: + case 0x44: + case 0x54: + case 0x64: + case 0x74: + sprintf(buffer, "%si A, %X", arith_ops[op >> 13], READ_OP_DASM(2)); + size = 2; + break; + + // op a, ((ri)) + case 0x15: + case 0x35: + case 0x45: + case 0x55: + case 0x65: + case 0x75: + sprintf(buffer, "%s A, ((%s%s))", arith_ops[op >> 13], RIJ, MODIFIER_LOW); + break; + + // sub a, ri + case 0x19: + case 0x39: + case 0x49: + case 0x59: + case 0x69: + case 0x79: + sprintf(buffer, "%s A, %s%s", arith_ops[op >> 13], RIJ, MODIFIER_LOW); + break; + + // mpys (rj), (ri), b + case 0x1b: + sprintf(buffer, "mpya (%s%s), (%s%s), %d", RJ(op >> 4), MODIFIER_HIGH, RI(op), MODIFIER_LOW, BIT_B); + break; + + // subi simm + case 0x1c: + case 0x3c: + case 0x4c: + case 0x5c: + case 0x6c: + case 0x7c: + sprintf(buffer, "%si %X", arith_ops[op >> 13], op & 0xff); + break; + + // call cond, addr + case 0x24: + sprintf(buffer, "call %s, %X", get_cond(op), READ_OP_DASM(2)); + flags |= DASMFLAG_STEP_OVER; + size = 2; + break; + + // ld d, (a) + case 0x25: + sprintf(buffer, "ld %s, (A)", reg[(op >> 4) & 0xf]); + break; + + // bra cond, addr + case 0x26: + sprintf(buffer, "bra %s, %X", get_cond(op), READ_OP_DASM(2)); + size = 2; + break; + + // mod cond, op + case 0x48: + sprintf(buffer, "mod %s, %s", get_cond(op), acc_op[op & 7]); + break; + + // mod f, op + case 0x4a: + sprintf(buffer, "%s", flag_op[op & 0xf]); + break; + + // mpya (rj), (ri), b + case 0x4b: + sprintf(buffer, "mpya (%s%s), (%s%s), %d", RJ(op >> 4), MODIFIER_HIGH, RI(op), MODIFIER_LOW, BIT_B); + break; + + // mld (rj), (ri), b + case 0x5b: + sprintf(buffer, "mld (%s%s), (%s%s), %d", RJ(op >> 4), MODIFIER_HIGH, RI(op), MODIFIER_LOW, BIT_B); + break; + + default: + sprintf(buffer, "OP = %04X", op); + break; + } + + return size | flags | DASMFLAG_SUPPORTED; +} + +// vim:ts=4 + +CPU_DISASSEMBLE( ssp1601 ) +{ + //ssp1601_state_t *ssp1601_state = get_safe_token(device); + + return dasm_ssp1601(buffer, pc, oprom); +} diff --git a/src/devices/cpu/superfx/sfx_dasm.c b/src/devices/cpu/superfx/sfx_dasm.c new file mode 100644 index 00000000000..e76e37ee003 --- /dev/null +++ b/src/devices/cpu/superfx/sfx_dasm.c @@ -0,0 +1,425 @@ +// license:BSD-3-Clause +// copyright-holders:Ryan Holtz +#include "emu.h" +#include "superfx.h" + +static char *output; + +static void ATTR_PRINTF(1,2) print(const char *fmt, ...) +{ + va_list vl; + + va_start(vl, fmt); + output += vsprintf(output, fmt, vl); + va_end(vl); +} + +offs_t superfx_dasm_one(char *buffer, offs_t pc, UINT8 op, UINT8 param0, UINT8 param1, UINT16 alt) +{ + UINT8 bytes_consumed = 1; + output = buffer; + + switch(op) + { + case 0x00: // STOP + print("STOP"); + break; + case 0x01: // NOP + print("NOP"); + break; + case 0x02: // CACHE + print("CACHE"); + break; + case 0x03: // LSR + print("LSR"); + break; + case 0x04: // ROL + print("ROL"); + break; + case 0x05: // BRA + print("BRA %d", (INT8)param0); + bytes_consumed = 2; + break; + case 0x06: // BLT + print("BLT %d", (INT8)param0); + bytes_consumed = 2; + break; + case 0x07: // BGE + print("BGE %d", (INT8)param0); + bytes_consumed = 2; + break; + case 0x08: // BNE + print("BNE %d", (INT8)param0); + bytes_consumed = 2; + break; + case 0x09: // BEQ + print("BEQ %d", (INT8)param0); + bytes_consumed = 2; + break; + case 0x0a: // BPL + print("BPL %d", (INT8)param0); + bytes_consumed = 2; + break; + case 0x0b: // BMI + print("BMI %d", (INT8)param0); + bytes_consumed = 2; + break; + case 0x0c: // BCC + print("BCC %d", (INT8)param0); + bytes_consumed = 2; + break; + case 0x0d: // BCS + print("BCS %d", (INT8)param0); + bytes_consumed = 2; + break; + case 0x0e: // BVC + print("BVC %d", (INT8)param0); + bytes_consumed = 2; + break; + case 0x0f: // BVS + print("BVS %d", (INT8)param0); + bytes_consumed = 2; + break; + + case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17: + case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f: // TO + print("TO R%d", op & 0xf); + break; + + case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27: + case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: case 0x2f: // WITH + print("WITH R%d", op & 0xf); + break; + + case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: + case 0x36: case 0x37: case 0x38: case 0x39: case 0x3a: case 0x3b: // STW_IR / STB_IR + switch(alt) + { + case SUPERFX_SFR_ALT0: + case SUPERFX_SFR_ALT2: + print("STW (R%d)", op & 0xf); + break; + case SUPERFX_SFR_ALT1: + case SUPERFX_SFR_ALT3: + print("STB (R%d)", op & 0xf); + break; + } + break; + + case 0x3c: // LOOP + print("LOOP"); + break; + case 0x3d: // ALT1 + print("ALT1"); + break; + case 0x3e: // ALT2 + print("ALT2"); + break; + case 0x3f: // ALT3 + print("ALT3"); + break; + + case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: + case 0x46: case 0x47: case 0x48: case 0x49: case 0x4a: case 0x4b: // LDW_IR / LDB_IR + switch(alt) + { + case SUPERFX_SFR_ALT0: + case SUPERFX_SFR_ALT2: + print("LDW (R%d)", op & 0xf); + break; + case SUPERFX_SFR_ALT1: + case SUPERFX_SFR_ALT3: + print("LDB (R%d)", op & 0xf); + break; + } + break; + + case 0x4c: // PLOT / RPIX + switch(alt) + { + case SUPERFX_SFR_ALT0: + case SUPERFX_SFR_ALT2: + print("PLOT"); + break; + case SUPERFX_SFR_ALT1: + case SUPERFX_SFR_ALT3: + print("RPIX"); + break; + } + break; + + case 0x4d: // SWAP + print("SWAP"); + break; + + case 0x4e: // COLOR / CMODE + switch(alt) + { + case SUPERFX_SFR_ALT0: + case SUPERFX_SFR_ALT2: + print("COLOR"); + break; + case SUPERFX_SFR_ALT1: + case SUPERFX_SFR_ALT3: + print("CMODE"); + break; + } + break; + + case 0x4f: // NOT + print("NOT"); + break; + + case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x55: case 0x56: case 0x57: + case 0x58: case 0x59: case 0x5a: case 0x5b: case 0x5c: case 0x5d: case 0x5e: case 0x5f: // ADD / ADC / ADDI / ADCI + switch(alt) + { + case SUPERFX_SFR_ALT0: + print("ADD R%d", op &0xf); + break; + case SUPERFX_SFR_ALT1: + print("ADC R%d", op &0xf); + break; + case SUPERFX_SFR_ALT2: + print("ADDI R%d", op &0xf); + break; + case SUPERFX_SFR_ALT3: + print("ADCI R%d", op &0xf); + break; + } + break; + + case 0x60: case 0x61: case 0x62: case 0x63: case 0x64: case 0x65: case 0x66: case 0x67: + case 0x68: case 0x69: case 0x6a: case 0x6b: case 0x6c: case 0x6d: case 0x6e: case 0x6f: // SUB / SBC / SUBI / CMP + switch(alt) + { + case SUPERFX_SFR_ALT0: + print("SUB R%d", op &0xf); + break; + case SUPERFX_SFR_ALT1: + print("SBC R%d", op &0xf); + break; + case SUPERFX_SFR_ALT2: + print("SUBI R%d", op &0xf); + break; + case SUPERFX_SFR_ALT3: + print("CMP R%d", op &0xf); + break; + } + break; + + case 0x70: // MERGE + print("MERGE"); + break; + + 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: // AND / BIC / ANDI / BICI + switch(alt) + { + case SUPERFX_SFR_ALT0: + print("AND R%d", op &0xf); + break; + case SUPERFX_SFR_ALT1: + print("BIC R%d", op &0xf); + break; + case SUPERFX_SFR_ALT2: + print("ANDI R%d", op &0xf); + break; + case SUPERFX_SFR_ALT3: + print("BICI R%d", op &0xf); + break; + } + 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: // MULT / UMULT / MULTI / UMULTI + switch(alt) + { + case SUPERFX_SFR_ALT0: + print("MULT R%d", op &0xf); + break; + case SUPERFX_SFR_ALT1: + print("UMULT R%d", op &0xf); + break; + case SUPERFX_SFR_ALT2: + print("MULTI R%d", op &0xf); + break; + case SUPERFX_SFR_ALT3: + print("UMULTI R%d", op &0xf); + break; + } + break; + + case 0x90: // SBK + print("SBK"); + break; + + case 0x91: case 0x92: case 0x93: case 0x94: // LINK + print("LINK %d", op & 0xf); + break; + + case 0x95: // SEX + print("SEX"); + break; + + case 0x96: // ASR / DIV2 + switch(alt) + { + case SUPERFX_SFR_ALT0: + case SUPERFX_SFR_ALT2: + print("ASR"); + break; + case SUPERFX_SFR_ALT1: + case SUPERFX_SFR_ALT3: + print("DIV2"); + break; + } + break; + + case 0x97: // ROR + print("ROR"); + break; + + case 0x98: case 0x99: case 0x9a: case 0x9b: case 0x9c: case 0x9d: // JMP / LJMP + switch(alt) + { + case SUPERFX_SFR_ALT0: + case SUPERFX_SFR_ALT2: + print("JMP R%d", op & 0xf); + break; + case SUPERFX_SFR_ALT1: + case SUPERFX_SFR_ALT3: + print("LJMP R%d", op & 0xf); + break; + } + break; + + case 0x9e: // LOB + print("LOB"); + break; + + case 0x9f: // FMULT / LMULT + switch(alt) + { + case SUPERFX_SFR_ALT0: + case SUPERFX_SFR_ALT2: + print("FMULT"); + break; + case SUPERFX_SFR_ALT1: + case SUPERFX_SFR_ALT3: + print("LMULT"); + break; + } + break; + + case 0xa0: case 0xa1: case 0xa2: case 0xa3: case 0xa4: case 0xa5: case 0xa6: case 0xa7: + case 0xa8: case 0xa9: case 0xaa: case 0xab: case 0xac: case 0xad: case 0xae: case 0xaf: // IBT / LMS / SMS / LML + switch(alt) + { + case SUPERFX_SFR_ALT0: + print("IBT R%d,0x%02x", op & 0xf, param0); + break; + case SUPERFX_SFR_ALT2: + print("SMS R%d,(0x%04x)", op & 0xf, param0 << 1); + break; + case SUPERFX_SFR_ALT1: + case SUPERFX_SFR_ALT3: + print("LMS R%d,(0x%04x)", op & 0xf, param0 << 1); + break; + } + bytes_consumed = 2; + break; + + case 0xb0: case 0xb1: case 0xb2: case 0xb3: case 0xb4: case 0xb5: case 0xb6: case 0xb7: + case 0xb8: case 0xb9: case 0xba: case 0xbb: case 0xbc: case 0xbd: case 0xbe: case 0xbf: // FROM + print("FROM R%d", op & 0xf); + break; + + case 0xc0: // HIB + print("HIB"); + break; + + case 0xc1: case 0xc2: case 0xc3: case 0xc4: case 0xc5: case 0xc6: case 0xc7: + case 0xc8: case 0xc9: case 0xca: case 0xcb: case 0xcc: case 0xcd: case 0xce: case 0xcf: // OR / XOR / ORI / XORI + switch(alt) + { + case SUPERFX_SFR_ALT0: + print("OR R%d", op &0xf); + break; + case SUPERFX_SFR_ALT1: + print("XOR R%d", op &0xf); + break; + case SUPERFX_SFR_ALT2: + print("ORI R%d", op &0xf); + break; + case SUPERFX_SFR_ALT3: + print("XORI R%d", op &0xf); + break; + } + break; + + case 0xd0: case 0xd1: case 0xd2: case 0xd3: case 0xd4: case 0xd5: case 0xd6: case 0xd7: + case 0xd8: case 0xd9: case 0xda: case 0xdb: case 0xdc: case 0xdd: case 0xde: // INC + print("INC R%d", op & 0xf); + break; + + case 0xdf: // GETC / RAMB / ROMB + switch(alt) + { + case SUPERFX_SFR_ALT0: + case SUPERFX_SFR_ALT1: + print("GETC"); + break; + case SUPERFX_SFR_ALT2: + print("RAMB"); + break; + case SUPERFX_SFR_ALT3: + print("ROMB"); + break; + } + break; + + case 0xe0: case 0xe1: case 0xe2: case 0xe3: case 0xe4: case 0xe5: case 0xe6: case 0xe7: + case 0xe8: case 0xe9: case 0xea: case 0xeb: case 0xec: case 0xed: case 0xee: // DEC + print("DEC R%d", op & 0xf); + break; + + case 0xef: // GETB / GETBH / GETBL / GETBS + switch(alt) + { + case SUPERFX_SFR_ALT0: + print("GETB"); + break; + case SUPERFX_SFR_ALT1: + print("GETBH"); + break; + case SUPERFX_SFR_ALT2: + print("GETBL"); + break; + case SUPERFX_SFR_ALT3: + print("GETBS"); + break; + } + break; + + case 0xf0: case 0xf1: case 0xf2: case 0xf3: case 0xf4: case 0xf5: case 0xf6: case 0xf7: + case 0xf8: case 0xf9: case 0xfa: case 0xfb: case 0xfc: case 0xfd: case 0xfe: case 0xff: // IWT / LM / SM / LM + switch(alt) + { + case SUPERFX_SFR_ALT0: + print("IWT R%d,#%02x%02x", op & 0xf, param1, param0); + bytes_consumed = 3; + break; + case SUPERFX_SFR_ALT2: + print("SM R%d", op & 0xf); + break; + case SUPERFX_SFR_ALT1: + case SUPERFX_SFR_ALT3: + print("LM R%d", op & 0xf); + break; + } + break; + } + + return bytes_consumed | DASMFLAG_SUPPORTED; +} diff --git a/src/devices/cpu/superfx/superfx.c b/src/devices/cpu/superfx/superfx.c new file mode 100644 index 00000000000..b59be533acd --- /dev/null +++ b/src/devices/cpu/superfx/superfx.c @@ -0,0 +1,1447 @@ +// license:BSD-3-Clause +// copyright-holders:Ryan Holtz +#include "emu.h" +#include "debugger.h" +#include "superfx.h" + + +const device_type SUPERFX = &device_creator; + +superfx_device::superfx_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : cpu_device(mconfig, SUPERFX, "SuperFX", tag, owner, clock, "superfx", __FILE__) + , m_program_config("program", ENDIANNESS_LITTLE, 8, 32, 0) + , m_out_irq_func(*this) +{ +} + + +#define SUPERFX_SFR_OV_SET ((m_sfr & SUPERFX_SFR_OV) ? 1 : 0) +#define SUPERFX_SFR_OV_CLEAR ((m_sfr & SUPERFX_SFR_OV) ? 0 : 1) +#define SUPERFX_SFR_S_SET ((m_sfr & SUPERFX_SFR_S) ? 1 : 0) +#define SUPERFX_SFR_S_CLEAR ((m_sfr & SUPERFX_SFR_S) ? 0 : 1) +#define SUPERFX_SFR_CY_SET ((m_sfr & SUPERFX_SFR_CY) ? 1 : 0) +#define SUPERFX_SFR_CY_CLEAR ((m_sfr & SUPERFX_SFR_CY) ? 0 : 1) +#define SUPERFX_SFR_Z_SET ((m_sfr & SUPERFX_SFR_Z) ? 1 : 0) +#define SUPERFX_SFR_Z_CLEAR ((m_sfr & SUPERFX_SFR_Z) ? 0 : 1) + + +void superfx_device::superfx_regs_reset() +{ + m_sfr &= ~(SUPERFX_SFR_B | SUPERFX_SFR_ALT3); + + m_sreg = &m_r[0]; + m_dreg = &m_r[0]; + m_dreg_idx = 0; + m_sreg_idx = 0; +} + +void superfx_device::superfx_update_speed() +{ + m_cache_access_speed = (m_clsr ? 1 : 2); + m_memory_access_speed = (m_clsr ? 5 : 6); + if(m_clsr) + { + m_cfgr &= ~SUPERFX_CFGR_MS0; // Cannot use high-speed multiplication in 21MHz mode + } +} + +void superfx_device::superfx_cache_flush() +{ + UINT32 n = 0; + for(n = 0; n < 32; n++) + { + m_cache.valid[n] = 0; + } +} + +UINT8 superfx_device::superfx_cache_mmio_read(UINT32 addr) +{ + addr = (addr + m_cbr) & 0x1ff; + return m_cache.buffer[addr]; +} + +void superfx_device::superfx_cache_mmio_write(UINT32 addr, UINT8 data) +{ + addr = (addr + m_cbr) & 0x1ff; + m_cache.buffer[addr] = data; + if((addr & 15) == 15) + { + m_cache.valid[addr >> 4] = 1; + } +} + +void superfx_device::superfx_memory_reset() +{ + UINT32 n = 0; + for(n = 0; n < 0x200; n++) + { + m_cache.buffer[n] = 0x00; + } + for(n = 0; n < 0x20; n++) + { + m_cache.valid[n] = 0; + } + for(n = 0; n < 2; n++) + { + m_pixelcache[n].offset = ~0; + m_pixelcache[n].bitpend = 0x00; + } +} + +UINT8 superfx_device::superfx_bus_read(UINT32 addr) +{ + return m_program->read_byte(addr); +} + +void superfx_device::superfx_bus_write(UINT32 addr, UINT8 data) +{ + m_program->write_byte(addr, data); +} + +void superfx_device::superfx_pixelcache_flush(INT32 line) +{ + UINT8 x = m_pixelcache[line].offset << 3; + UINT8 y = m_pixelcache[line].offset >> 5; + UINT32 cn = 0; + UINT32 bpp = 2 << ((m_scmr & SUPERFX_SCMR_MD) - ((m_scmr & SUPERFX_SCMR_MD) >> 1)); // = [regs.scmr.md]{ 2, 4, 4, 8 }; + UINT32 addr = 0; + UINT32 n = 0; + + if(m_pixelcache[line].bitpend == 0x00) + { + return; + } + + switch(((m_por & SUPERFX_POR_OBJ) ? SUPERFX_SCMR_HT3 : (m_scmr & SUPERFX_SCMR_HT_MASK))) + { + case SUPERFX_SCMR_HT0: + cn = ((x & 0xf8) << 1) + ((y & 0xf8) >> 3); + break; + case SUPERFX_SCMR_HT1: + cn = ((x & 0xf8) << 1) + ((x & 0xf8) >> 1) + ((y & 0xf8) >> 3); + break; + case SUPERFX_SCMR_HT2: + cn = ((x & 0xf8) << 1) + ((x & 0xf8) << 0) + ((y & 0xf8) >> 3); + break; + case SUPERFX_SCMR_HT3: + cn = ((y & 0x80) << 2) + ((x & 0x80) << 1) + ((y & 0x78) << 1) + ((x & 0x78) >> 3); + break; + } + + addr = 0x700000 + (cn * (bpp << 3)) + (m_scbr << 10) + ((y & 0x07) * 2); + + for(n = 0; n < bpp; n++) + { + UINT32 byte = ((n >> 1) << 4) + (n & 1); // = [n]{ 0, 1, 16, 17, 32, 33, 48, 49 }; + UINT8 data = 0x00; + UINT32 x32 = 0; + for(x32 = 0; x32 < 8; x32++) + { + data |= ((m_pixelcache[line].data[x32] >> n) & 1) << x32; + } + if(m_pixelcache[line].bitpend != 0xff) + { + superfx_add_clocks_internal(m_memory_access_speed); + data &= m_pixelcache[line].bitpend; + data |= superfx_bus_read(addr + byte) & ~m_pixelcache[line].bitpend; + } + superfx_add_clocks_internal(m_memory_access_speed); + superfx_bus_write(addr + byte, data); + } + + m_pixelcache[line].bitpend = 0x00; +} + +void superfx_device::superfx_plot(UINT8 x, UINT8 y) +{ + UINT8 color = m_colr; + UINT16 offset = (y << 5) + (x >> 3); + + if((m_por & SUPERFX_POR_DITHER) != 0 && (m_scmr & SUPERFX_SCMR_MD) != 3) + { + if((x ^ y) & 1) + { + color >>= 4; + } + color &= 0x0f; + } + + if((m_por & SUPERFX_POR_TRANSPARENT) == 0) + { + if((m_scmr & SUPERFX_SCMR_MD) == 3) + { + if(m_por & SUPERFX_POR_FREEZEHIGH) + { + if((color & 0x0f) == 0) + { + return; + } + } + else + { + if(color == 0) + { + return; + } + } + } + else + { + if((color & 0x0f) == 0) + { + return; + } + } + } + + if(offset != m_pixelcache[0].offset) + { + superfx_pixelcache_flush(1); + m_pixelcache[1] = m_pixelcache[0]; + m_pixelcache[0].bitpend = 0x00; + m_pixelcache[0].offset = offset; + } + + x = (x & 7) ^ 7; + m_pixelcache[0].data[x] = color; + m_pixelcache[0].bitpend |= 1 << x; + if(m_pixelcache[0].bitpend == 0xff) + { + superfx_pixelcache_flush(1); + m_pixelcache[1] = m_pixelcache[0]; + m_pixelcache[0].bitpend = 0x00; + } +} + +UINT8 superfx_device::superfx_rpix(UINT8 x, UINT8 y) +{ + UINT32 cn = 0; + UINT32 bpp = 0; + UINT32 addr = 0; + UINT8 data = 0x00; + UINT32 n = 0; + + superfx_pixelcache_flush(1); + superfx_pixelcache_flush(0); + + bpp = 2 << ((m_scmr & SUPERFX_SCMR_MD) - ((m_scmr & SUPERFX_SCMR_MD) >> 1)); // = [regs.scmr.md]{ 2, 4, 4, 8 }; + + switch((m_por & SUPERFX_POR_OBJ) ? SUPERFX_SCMR_HT3 : (m_scmr & SUPERFX_SCMR_HT_MASK)) + { + case SUPERFX_SCMR_HT0: + cn = ((x & 0xf8) << 1) + ((y & 0xf8) >> 3); + break; + case SUPERFX_SCMR_HT1: + cn = ((x & 0xf8) << 1) + ((x & 0xf8) >> 1) + ((y & 0xf8) >> 3); + break; + case SUPERFX_SCMR_HT2: + cn = ((x & 0xf8) << 1) + ((x & 0xf8) << 0) + ((y & 0xf8) >> 3); + break; + case SUPERFX_SCMR_HT3: + cn = ((y & 0x80) << 2) + ((x & 0x80) << 1) + ((y & 0x78) << 1) + ((x & 0x78) >> 3); + break; + } + + addr = 0x700000 + (cn * (bpp << 3)) + (m_scbr << 10) + ((y & 0x07) * 2); + x = (x & 7) ^ 7; + + for(n = 0; n < bpp; n++) + { + UINT32 byte = ((n >> 1) << 4) + (n & 1); // = [n]{ 0, 1, 16, 17, 32, 33, 48, 49 }; + superfx_add_clocks_internal(m_memory_access_speed); + data |= ((superfx_bus_read(addr + byte) >> x) & 1) << n; + } + + return data; +} + +UINT8 superfx_device::superfx_color(UINT8 source) +{ + if(m_por & SUPERFX_POR_HIGHNIBBLE) + { + return (m_colr & 0xf0) | (source >> 4); + } + if(m_por & SUPERFX_POR_FREEZEHIGH) + { + return (m_colr & 0xf0) | (source & 0x0f); + } + return source; +} + +void superfx_device::superfx_rambuffer_sync() +{ + if(m_ramcl) + { + superfx_add_clocks_internal(m_ramcl); + } +} + +UINT8 superfx_device::superfx_rambuffer_read(UINT16 addr) +{ + superfx_rambuffer_sync(); + return superfx_bus_read(0x700000 + (m_rambr << 16) + addr); +} + +void superfx_device::superfx_rambuffer_write(UINT16 addr, UINT8 data) +{ + superfx_rambuffer_sync(); + m_ramcl = m_memory_access_speed; + m_ramar = addr; + m_ramdr = data; +} + +void superfx_device::superfx_rombuffer_sync() +{ + if(m_romcl) + { + superfx_add_clocks_internal(m_romcl); + } +} + +void superfx_device::superfx_rombuffer_update() +{ + m_sfr |= SUPERFX_SFR_R; + m_romcl = m_memory_access_speed; +} + +UINT8 superfx_device::superfx_rombuffer_read() +{ + superfx_rombuffer_sync(); + return m_romdr; +} + +void superfx_device::superfx_gpr_write(UINT8 r, UINT16 data) +{ + m_r[r] = data; + if(r == 14) + { + superfx_rombuffer_update(); + } + else if(r == 15) + { + m_r15_modified = 1; + } +} + +UINT8 superfx_device::superfx_op_read(UINT16 addr) +{ + UINT16 offset = addr - m_cbr; + if(offset < 512) + { + if(!m_cache.valid[offset >> 4]) + { + UINT32 dp = offset & 0xfff0; + UINT32 sp = (m_pbr << 16) + ((m_cbr + dp) & 0xfff0); + UINT32 n = 0; + for(n = 0; n < 16; n++) + { + superfx_add_clocks_internal(m_memory_access_speed); + m_cache.buffer[dp++] = superfx_bus_read(sp++); + } + m_cache.valid[offset >> 4] = 1; + } + else + { + superfx_add_clocks_internal(m_memory_access_speed); + } + return m_cache.buffer[offset]; + } + + if(m_pbr <= 0x5f) + { + //$[00-5f]:[0000-ffff] ROM + superfx_rombuffer_sync(); + superfx_add_clocks_internal(m_memory_access_speed); + return superfx_bus_read((m_pbr << 16) + addr); + } + else + { + //$[60-7f]:[0000-ffff] RAM + superfx_rambuffer_sync(); + superfx_add_clocks_internal(m_memory_access_speed); + return superfx_bus_read((m_pbr << 16) + addr); + } +} + +UINT8 superfx_device::superfx_peekpipe() +{ + UINT8 result = m_pipeline; + m_pipeline = superfx_op_read(m_r[15]); + m_r15_modified = 0; + return result; +} + +UINT8 superfx_device::superfx_pipe() +{ + UINT8 result = m_pipeline; + m_pipeline = superfx_op_read(++m_r[15]); + m_r15_modified = 0; + return result; +} + +/*****************************************************************************/ + +/* reads to SuperFX RAM only happen if this returns 1 */ +int superfx_device::access_ram() +{ + if ((m_sfr & SUPERFX_SFR_G) && (m_scmr & SUPERFX_SCMR_RAN)) + return 0; + + return 1; +} + +/* reads to SuperFX ROM only happen if this returns 1 */ +int superfx_device::access_rom() +{ + if ((m_sfr & SUPERFX_SFR_G) && (m_scmr & SUPERFX_SCMR_RON)) + return 0; + + return 1; +} + +UINT8 superfx_device::mmio_read(UINT32 addr) +{ + addr &= 0xffff; + + if(addr >= 0x3100 && addr <= 0x32ff) + { + return superfx_cache_mmio_read(addr - 0x3100); + } + + if(addr >= 0x3000 && addr <= 0x301f) + { + return m_r[(addr >> 1) & 0xf] >> ((addr & 1) << 3); + } + + switch(addr) + { + case 0x3030: + return m_sfr >> 0; + + case 0x3031: + { + UINT8 r = m_sfr >> 8; + m_sfr &= ~SUPERFX_SFR_IRQ; + m_irq = 0; + m_out_irq_func(m_irq); + return r; + } + + case 0x3034: + return m_pbr; + + case 0x3036: + return m_rombr; + + case 0x303b: + return m_vcr; + + case 0x303c: + return m_rambr; + + case 0x303e: + return m_cbr >> 0; + + case 0x303f: + return m_cbr >> 8; + } + + return 0; +} + +void superfx_device::mmio_write(UINT32 addr, UINT8 data) +{ + addr &= 0xffff; + + //printf( "superfx_mmio_write: %08x = %02x\n", addr, data ); + + if(addr >= 0x3100 && addr <= 0x32ff) + { + superfx_cache_mmio_write(addr - 0x3100, data); + return; + } + + if(addr >= 0x3000 && addr <= 0x301f) + { + UINT32 n = (addr >> 1) & 0xf; + if((addr & 1) == 0) + { + m_r[n] = (m_r[n] & 0xff00) | data; + } + else + { + m_r[n] = (data << 8) | (m_r[n] & 0xff); + } + + if(addr == 0x301f) + { + m_sfr |= SUPERFX_SFR_G; + } + return; + } + + switch(addr) + { + case 0x3030: + { + UINT8 g = (m_sfr & SUPERFX_SFR_G) ? 1 : 0; + m_sfr = (m_sfr & 0xff00) | (data << 0); + if(g == 1 && !(m_sfr & SUPERFX_SFR_G)) + { + m_cbr = 0x0000; + superfx_cache_flush(); + } + break; + } + + case 0x3031: + m_sfr = (data << 8) | (m_sfr & 0x00ff); + break; + + case 0x3033: + m_bramr = data & 1; + break; + + case 0x3034: + m_pbr = data & 0x7f; + superfx_cache_flush(); + break; + + case 0x3037: + m_cfgr = data; + superfx_update_speed(); + break; + + case 0x3038: + m_scbr = data; + break; + + case 0x3039: + m_clsr = data & 1; + superfx_update_speed(); + break; + + case 0x303a: + m_scmr = data; + break; + } +} + +void superfx_device::superfx_add_clocks_internal(UINT32 clocks) +{ + if(m_romcl) + { + m_romcl -= MIN(clocks, m_romcl); + if(m_romcl == 0) + { + m_sfr &= ~SUPERFX_SFR_R; + m_romdr = superfx_bus_read((m_rombr << 16) + m_r[14]); + } + } + + if(m_ramcl) + { + m_ramcl -= MIN(clocks, m_ramcl); + if(m_ramcl == 0) + { + superfx_bus_write(0x700000 + (m_rambr << 16) + m_ramar, m_ramdr); + } + } +} + +void superfx_device::superfx_timing_reset() +{ + superfx_update_speed(); + m_r15_modified = 0; + + m_romcl = 0; + m_romdr = 0; + + m_ramcl = 0; + m_ramar = 0; + m_ramdr = 0; +} + +void superfx_device::add_clocks(INT32 clocks) +{ + superfx_add_clocks_internal(clocks); +} + +/*****************************************************************************/ + +void superfx_device::device_start() +{ + for(int i = 0; i < 16; i++) + { + m_r[i] = 0; + } + + m_sfr = 0; + m_pbr = 0; + m_rombr = 0; + m_rambr = 0; + m_cbr = 0; + m_scbr = 0; + m_scmr = 0; + m_colr = 0; + m_por = 0; + m_bramr = 0; + m_vcr = 0x04; + m_cfgr = 0; + m_clsr = 0; + m_pipeline = 0x01; // nop + m_ramaddr = 0; + m_r15_modified = 0; + m_irq = 0; + m_cache_access_speed = 0; + m_memory_access_speed = 0; + m_debugger_temp = 0; + m_romcl = 0; + m_romdr = 0; + m_ramcl = 0; + m_ramar = 0; + m_ramdr = 0; + + superfx_regs_reset(); + superfx_memory_reset(); + superfx_update_speed(); + + m_program = &space(AS_PROGRAM); + + m_out_irq_func.resolve(); + + save_item(NAME(m_pipeline)); + save_item(NAME(m_ramaddr)); + + save_item(NAME(m_r)); + save_item(NAME(m_sfr)); + save_item(NAME(m_pbr)); + save_item(NAME(m_rombr)); + save_item(NAME(m_rambr)); + save_item(NAME(m_cbr)); + save_item(NAME(m_scbr)); + save_item(NAME(m_scmr)); + save_item(NAME(m_colr)); + save_item(NAME(m_por)); + save_item(NAME(m_bramr)); + save_item(NAME(m_vcr)); + save_item(NAME(m_cfgr)); + save_item(NAME(m_clsr)); + + save_item(NAME(m_romcl)); + save_item(NAME(m_romdr)); + + save_item(NAME(m_ramcl)); + save_item(NAME(m_ramar)); + save_item(NAME(m_ramdr)); + + save_item(NAME(m_sreg_idx)); + save_item(NAME(m_dreg_idx)); + save_item(NAME(m_r15_modified)); + + save_item(NAME(m_irq)); + + save_item(NAME(m_cache_access_speed)); + save_item(NAME(m_memory_access_speed)); + + save_item(NAME(m_cache.buffer)); + save_item(NAME(m_cache.valid)); + + for (int i = 0; i < 2; i++) + { + save_item(NAME(m_pixelcache[i].offset), i); + save_item(NAME(m_pixelcache[i].bitpend), i); + save_item(NAME(m_pixelcache[i].data), i); + } + + state_add( SUPERFX_PC, "PC", m_debugger_temp).callimport().callexport().formatstr("%06X"); + state_add( SUPERFX_DREG, "DREG", m_dreg_idx).mask(0xf).formatstr("%02u"); + state_add( SUPERFX_SREG, "SREG", m_sreg_idx).mask(0xf).formatstr("%02u"); + state_add( SUPERFX_R0, "R0", m_r[0]).formatstr("%04X"); + state_add( SUPERFX_R1, "R1", m_r[1]).formatstr("%04X"); + state_add( SUPERFX_R2, "R2", m_r[2]).formatstr("%04X"); + state_add( SUPERFX_R3, "R3", m_r[3]).formatstr("%04X"); + state_add( SUPERFX_R4, "R4", m_r[4]).formatstr("%04X"); + state_add( SUPERFX_R5, "R5", m_r[5]).formatstr("%04X"); + state_add( SUPERFX_R6, "R6", m_r[6]).formatstr("%04X"); + state_add( SUPERFX_R7, "R7", m_r[7]).formatstr("%04X"); + state_add( SUPERFX_R8, "R8", m_r[8]).formatstr("%04X"); + state_add( SUPERFX_R9, "R9", m_r[9]).formatstr("%04X"); + state_add( SUPERFX_R10, "R10", m_r[10]).formatstr("%04X"); + state_add( SUPERFX_R11, "R11", m_r[11]).formatstr("%04X"); + state_add( SUPERFX_R12, "R12", m_r[12]).formatstr("%04X"); + state_add( SUPERFX_R13, "R13", m_r[13]).formatstr("%04X"); + state_add( SUPERFX_R14, "R14", m_r[14]).formatstr("%04X"); + state_add( SUPERFX_R15, "R15", m_r[15]).formatstr("%04X"); + state_add( SUPERFX_SFR, "SFR", m_sfr).formatstr("%04X"); + state_add( SUPERFX_PBR, "PBR", m_pbr).formatstr("%02X"); + state_add( SUPERFX_ROMBR, "ROMBR", m_rombr).formatstr("%02X"); + state_add( SUPERFX_RAMBR, "RAMBR", m_rambr).formatstr("%02X"); + state_add( SUPERFX_CBR, "CBR", m_cbr).formatstr("%04X"); + state_add( SUPERFX_SCBR, "SCBR", m_scbr).formatstr("%02X"); + state_add( SUPERFX_SCMR, "SCMR", m_scmr).formatstr("%02X"); + state_add( SUPERFX_COLR, "COLR", m_colr).formatstr("%02X"); + state_add( SUPERFX_POR, "POR", m_por).formatstr("%02X"); + state_add( SUPERFX_BRAMR, "BRAMR", m_bramr).formatstr("%02X"); + state_add( SUPERFX_VCR, "VCR", m_vcr).formatstr("%02X"); + state_add( SUPERFX_CFGR, "CFGR", m_cfgr).formatstr("%02X"); + state_add( SUPERFX_CLSR, "CLSR", m_clsr).formatstr("%02X"); + state_add( SUPERFX_ROMCL, "ROMCL", m_romcl).formatstr("%08X"); + state_add( SUPERFX_ROMDR, "ROMDR", m_romdr).formatstr("%02X"); + state_add( SUPERFX_RAMCL, "RAMCL", m_ramcl).formatstr("%08X"); + state_add( SUPERFX_RAMAR, "RAMAR", m_ramar).formatstr("%04X"); + state_add( SUPERFX_RAMDR, "RAMDR", m_ramdr).formatstr("%02X"); + state_add( SUPERFX_RAMADDR, "RAMADDR", m_ramaddr).formatstr("%04X"); + + m_icountptr = &m_icount; +} + + +void superfx_device::state_import(const device_state_entry &entry) +{ + switch (entry.index()) + { + case SUPERFX_PC: + m_r[15] = m_debugger_temp; + break; + } +} + + +void superfx_device::state_export(const device_state_entry &entry) +{ + switch (entry.index()) + { + case STATE_GENPC: + case SUPERFX_PC: + m_debugger_temp = ( (m_pbr << 16) | m_r[15] ) - 1; + break; + } +} + + +void superfx_device::device_reset() +{ + int i; + + for(i = 0; i < 16; i++) + { + m_r[i] = 0; + } + + m_sfr = 0; + m_pbr = 0; + m_rombr = 0; + m_rambr = 0; + m_cbr = 0; + m_scbr = 0; + m_scmr = 0; + m_colr = 0; + m_por = 0; + m_bramr = 0; + m_vcr = 0x04; + m_cfgr = 0; + m_clsr = 0; + m_pipeline = 0x01; // nop + m_ramaddr = 0; + + superfx_regs_reset(); + superfx_timing_reset(); +} + +void superfx_device::superfx_dreg_sfr_sz_update() +{ + m_sfr &= ~(SUPERFX_SFR_S | SUPERFX_SFR_Z); + m_sfr |= (*(m_dreg) & 0x8000) ? SUPERFX_SFR_S : 0; + m_sfr |= (*(m_dreg) == 0) ? SUPERFX_SFR_Z : 0; +} + +void superfx_device::execute_run() +{ + UINT8 op; + + if(!(m_sfr & SUPERFX_SFR_G)) + { + superfx_add_clocks_internal(6); + m_icount = MIN(m_icount, 0); + } + + while (m_icount > 0 && (m_sfr & SUPERFX_SFR_G)) + { + if(!(m_sfr & SUPERFX_SFR_G)) + { + superfx_add_clocks_internal(6); + m_icount = MIN(m_icount, 0); + break; + } + + debugger_instruction_hook(this, (m_pbr << 16) | m_r[15]); + + op = superfx_peekpipe(); + + switch(op) + { + case 0x00: // STOP + if((m_cfgr & SUPERFX_CFGR_IRQ) == 0) + { + m_sfr |= SUPERFX_SFR_IRQ; + m_irq = 1; + m_out_irq_func(m_irq ? ASSERT_LINE : CLEAR_LINE ); + } + m_sfr &= ~SUPERFX_SFR_G; + m_pipeline = 0x01; + superfx_regs_reset(); + break; + case 0x01: // NOP + superfx_regs_reset(); + break; + case 0x02: // CACHE + if(m_cbr != (m_r[15] & 0xfff0)) + { + m_cbr = m_r[15] & 0xfff0; + superfx_cache_flush(); + } + superfx_regs_reset(); + break; + case 0x03: // LSR + m_sfr &= ~SUPERFX_SFR_CY; + m_sfr |= (*(m_sreg) & 1) ? SUPERFX_SFR_CY : 0; + superfx_gpr_write(m_dreg_idx, *(m_sreg) >> 1); + superfx_dreg_sfr_sz_update(); + superfx_regs_reset(); + break; + case 0x04: // ROL + { + UINT16 carry = *(m_sreg) & 0x8000; + superfx_gpr_write(m_dreg_idx, (*(m_sreg) << 1) | SUPERFX_SFR_CY_SET); + m_sfr &= ~SUPERFX_SFR_CY; + m_sfr |= carry ? SUPERFX_SFR_CY : 0; + superfx_dreg_sfr_sz_update(); + superfx_regs_reset(); + break; + } + case 0x05: // BRA + { + INT32 e = (INT8)superfx_pipe(); + superfx_gpr_write(15, m_r[15] + e); + break; + } + case 0x06: // BLT + { + INT32 e = (INT8)superfx_pipe(); + if((SUPERFX_SFR_S_SET ^ SUPERFX_SFR_OV_SET) == 0) + { + superfx_gpr_write(15, m_r[15] + e); + } + break; + } + case 0x07: // BGE + { + INT32 e = (INT8)superfx_pipe(); + if((SUPERFX_SFR_S_SET ^ SUPERFX_SFR_OV_SET) == 1) + { + superfx_gpr_write(15, m_r[15] + e); + } + break; + } + case 0x08: // BNE + { + INT32 e = (INT8)superfx_pipe(); + if(SUPERFX_SFR_Z_SET == 0) + { + superfx_gpr_write(15, m_r[15] + e); + } + break; + } + case 0x09: // BEQ + { + INT32 e = (INT8)superfx_pipe(); + if(SUPERFX_SFR_Z_SET == 1) + { + superfx_gpr_write(15, m_r[15] + e); + } + break; + } + case 0x0a: // BPL + { + INT32 e = (INT8)superfx_pipe(); + if(SUPERFX_SFR_S_SET == 0) + { + superfx_gpr_write(15, m_r[15] + e); + } + break; + } + case 0x0b: // BMI + { + INT32 e = (INT8)superfx_pipe(); + if(SUPERFX_SFR_S_SET == 1) + { + superfx_gpr_write(15, m_r[15] + e); + } + break; + } + case 0x0c: // BCC + { + INT32 e = (INT8)superfx_pipe(); + if(SUPERFX_SFR_CY_SET == 0) + { + superfx_gpr_write(15, m_r[15] + e); + } + break; + } + case 0x0d: // BCS + { + INT32 e = (INT8)superfx_pipe(); + if(SUPERFX_SFR_CY_SET == 1) + { + superfx_gpr_write(15, m_r[15] + e); + } + break; + } + case 0x0e: // BVC + { + INT32 e = (INT8)superfx_pipe(); + if(SUPERFX_SFR_OV_SET == 0) + { + superfx_gpr_write(15, m_r[15] + e); + } + break; + } + case 0x0f: // BVS + { + INT32 e = (INT8)superfx_pipe(); + if(SUPERFX_SFR_OV_SET == 1) + { + superfx_gpr_write(15, m_r[15] + e); + } + break; + } + + case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17: + case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f: // TO + if((m_sfr & SUPERFX_SFR_B) == 0) + { + m_dreg = &m_r[op & 0xf]; + m_dreg_idx = op & 0xf; + } + else + { + superfx_gpr_write(op & 0xf, *(m_sreg)); + superfx_regs_reset(); + } + break; + + case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27: + case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: case 0x2f: // WITH + m_sreg = &m_r[op & 0xf]; + m_sreg_idx = op & 0xf; + m_dreg = &m_r[op & 0xf]; + m_dreg_idx = op & 0xf; + m_sfr |= SUPERFX_SFR_B; + break; + + case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: + case 0x36: case 0x37: case 0x38: case 0x39: case 0x3a: case 0x3b: // STW_IR / STB_IR + if((m_sfr & SUPERFX_SFR_ALT1) == 0) + { // STW_IR + m_ramaddr = m_r[op & 0xf]; + superfx_rambuffer_write(m_ramaddr ^ 0, (*(m_sreg)) >> 0); + superfx_rambuffer_write(m_ramaddr ^ 1, (*(m_sreg)) >> 8); + superfx_regs_reset(); + } + else + { // STB_IR + m_ramaddr = m_r[op & 0xf]; + superfx_rambuffer_write(m_ramaddr, *(m_sreg)); + superfx_regs_reset(); + } + break; + + case 0x3c: // LOOP + superfx_gpr_write(12, m_r[12] - 1); + m_sfr &= ~(SUPERFX_SFR_S | SUPERFX_SFR_Z); + m_sfr |= (m_r[12] & 0x8000) ? SUPERFX_SFR_S : 0; + m_sfr |= (m_r[12] == 0) ? SUPERFX_SFR_Z : 0; + if(!(m_sfr & SUPERFX_SFR_Z)) + { + superfx_gpr_write(15, m_r[13]); + } + superfx_regs_reset(); + break; + case 0x3d: // ALT1 + m_sfr &= ~SUPERFX_SFR_B; + m_sfr |= SUPERFX_SFR_ALT1; + break; + case 0x3e: // ALT2 + m_sfr &= ~SUPERFX_SFR_B; + m_sfr |= SUPERFX_SFR_ALT2; + break; + case 0x3f: // ALT3 + m_sfr &= ~SUPERFX_SFR_B; + m_sfr |= SUPERFX_SFR_ALT1; + m_sfr |= SUPERFX_SFR_ALT2; + break; + + case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: + case 0x46: case 0x47: case 0x48: case 0x49: case 0x4a: case 0x4b: // LDW_IR / LDB_IR + if((m_sfr & SUPERFX_SFR_ALT1) == 0) + { // LDW_IR + UINT16 data = 0; + m_ramaddr = m_r[op & 0xf]; + data = superfx_rambuffer_read(m_ramaddr ^ 0) << 0; + data |= superfx_rambuffer_read(m_ramaddr ^ 1) << 8; + superfx_gpr_write(m_dreg_idx, data); + superfx_regs_reset(); + } + else + { // LDB_IR + m_ramaddr = m_r[op & 0xf]; + superfx_gpr_write(m_dreg_idx, superfx_rambuffer_read(m_ramaddr)); + superfx_regs_reset(); + } + break; + + case 0x4c: // PLOT / RPIX + if((m_sfr & SUPERFX_SFR_ALT1) == 0) + { // PLOT + superfx_plot(m_r[1], m_r[2]); + superfx_gpr_write(1, m_r[1] + 1); + superfx_regs_reset(); + } + else + { // RPIX + superfx_gpr_write(m_dreg_idx, superfx_rpix(m_r[1], m_r[2])); + superfx_dreg_sfr_sz_update(); + superfx_regs_reset(); + } + break; + + case 0x4d: // SWAP + superfx_gpr_write(m_dreg_idx, (*(m_sreg) >> 8) | (*(m_sreg) << 8)); + superfx_dreg_sfr_sz_update(); + superfx_regs_reset(); + break; + + case 0x4e: // COLOR / CMODE + if((m_sfr & SUPERFX_SFR_ALT1) == 0) + { // COLOR + m_colr = superfx_color(*(m_sreg)); + superfx_regs_reset(); + } + else + { // CMODE + m_por = *(m_sreg); + superfx_regs_reset(); + } + break; + + case 0x4f: // NOT + superfx_gpr_write(m_dreg_idx, ~(*(m_sreg))); + superfx_dreg_sfr_sz_update(); + superfx_regs_reset(); + break; + + case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x55: case 0x56: case 0x57: + case 0x58: case 0x59: case 0x5a: case 0x5b: case 0x5c: case 0x5d: case 0x5e: case 0x5f: // ADD / ADC / ADDI / ADCI + { + INT32 r = *(m_sreg); + m_sfr &= ~(SUPERFX_SFR_OV | SUPERFX_SFR_S | SUPERFX_SFR_Z); + switch(m_sfr & SUPERFX_SFR_ALT) + { + case SUPERFX_SFR_ALT0: // ADD + r += m_r[op & 0xf]; + m_sfr |= (~(*(m_sreg) ^ m_r[op & 0xf]) & (m_r[op & 0xf] ^ r) & 0x8000) ? SUPERFX_SFR_OV : 0; + break; + case SUPERFX_SFR_ALT1: // ADC + r += m_r[op & 0xf] + SUPERFX_SFR_CY_SET; + m_sfr |= (~(*(m_sreg) ^ m_r[op & 0xf]) & (m_r[op & 0xf] ^ r) & 0x8000) ? SUPERFX_SFR_OV : 0; + break; + case SUPERFX_SFR_ALT2: // ADDI + r += op & 0xf; + m_sfr |= (~(*(m_sreg) ^ (op & 0xf)) & ((op & 0xf) ^ r) & 0x8000) ? SUPERFX_SFR_OV : 0; + break; + case SUPERFX_SFR_ALT3: // ADCI + r += (op & 0xf) + SUPERFX_SFR_CY_SET; + m_sfr |= (~(*(m_sreg) ^ (op & 0xf)) & ((op & 0xf) ^ r) & 0x8000) ? SUPERFX_SFR_OV : 0; + break; + } + m_sfr &= ~SUPERFX_SFR_CY; + m_sfr |= (r & 0x8000) ? SUPERFX_SFR_S : 0; + m_sfr |= (r >= 0x10000) ? SUPERFX_SFR_CY : 0; + m_sfr |= ((UINT16)r == 0) ? SUPERFX_SFR_Z : 0; + superfx_gpr_write(m_dreg_idx, r); + superfx_regs_reset(); + break; + } + + case 0x60: case 0x61: case 0x62: case 0x63: case 0x64: case 0x65: case 0x66: case 0x67: + case 0x68: case 0x69: case 0x6a: case 0x6b: case 0x6c: case 0x6d: case 0x6e: case 0x6f: // SUB / SBC / SUBI / CMP + { + INT32 r = 0; + m_sfr &= ~(SUPERFX_SFR_OV | SUPERFX_SFR_S | SUPERFX_SFR_Z); + switch(m_sfr & SUPERFX_SFR_ALT) + { + case SUPERFX_SFR_ALT0: // SUB + r = *(m_sreg) - m_r[op & 0xf]; + m_sfr |= ((*(m_sreg) ^ m_r[op & 0xf]) & (*(m_sreg) ^ r) & 0x8000) ? SUPERFX_SFR_OV : 0; + superfx_gpr_write(m_dreg_idx, r); + break; + case SUPERFX_SFR_ALT1: // SBC + r = *(m_sreg) - m_r[op & 0xf] - SUPERFX_SFR_CY_CLEAR; + m_sfr |= ((*(m_sreg) ^ m_r[op & 0xf]) & (*(m_sreg) ^ r) & 0x8000) ? SUPERFX_SFR_OV : 0; + superfx_gpr_write(m_dreg_idx, r); + break; + case SUPERFX_SFR_ALT2: // SUBI + r = *(m_sreg) - (op & 0xf); + m_sfr |= ((*(m_sreg) ^ (op & 0xf)) & (*(m_sreg) ^ r) & 0x8000) ? SUPERFX_SFR_OV : 0; + superfx_gpr_write(m_dreg_idx, r); + break; + case SUPERFX_SFR_ALT3: // CMP + r = *(m_sreg) - m_r[op & 0xf]; + m_sfr |= ((*(m_sreg) ^ m_r[op & 0xf]) & (*(m_sreg) ^ r) & 0x8000) ? SUPERFX_SFR_OV : 0; + break; + } + m_sfr &= ~SUPERFX_SFR_CY; + m_sfr |= (r & 0x8000) ? SUPERFX_SFR_S : 0; + m_sfr |= (r >= 0x0) ? SUPERFX_SFR_CY : 0; + m_sfr |= ((UINT16)r == 0) ? SUPERFX_SFR_Z : 0; + superfx_regs_reset(); + break; + } + + case 0x70: // MERGE + superfx_gpr_write(m_dreg_idx, (m_r[7] & 0xff00) | (m_r[8] >> 8)); + m_sfr &= ~(SUPERFX_SFR_OV | SUPERFX_SFR_S | SUPERFX_SFR_CY | SUPERFX_SFR_Z); + m_sfr |= (*(m_dreg) & 0xc0c0) ? SUPERFX_SFR_OV : 0; + m_sfr |= (*(m_dreg) & 0x8080) ? SUPERFX_SFR_S : 0; + m_sfr |= (*(m_dreg) & 0xe0e0) ? SUPERFX_SFR_CY : 0; + m_sfr |= (*(m_dreg) & 0xf0f0) ? SUPERFX_SFR_Z : 0; + superfx_regs_reset(); + break; + + 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: // AND / BIC / ANDI / BICI + switch(m_sfr & SUPERFX_SFR_ALT) + { + case SUPERFX_SFR_ALT0: // AND + superfx_gpr_write(m_dreg_idx, *(m_sreg) & m_r[op & 0xf]); + break; + case SUPERFX_SFR_ALT1: // BIC + superfx_gpr_write(m_dreg_idx, *(m_sreg) & ~m_r[op & 0xf]); + break; + case SUPERFX_SFR_ALT2: // ANDI + superfx_gpr_write(m_dreg_idx, *(m_sreg) & (op & 0xf)); + break; + case SUPERFX_SFR_ALT3: // BICI + superfx_gpr_write(m_dreg_idx, *(m_sreg) & ~(op & 0xf)); + break; + } + superfx_dreg_sfr_sz_update(); + superfx_regs_reset(); + 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: // MULT / UMULT / MULTI / UMULTI + switch(m_sfr & SUPERFX_SFR_ALT) + { + case SUPERFX_SFR_ALT0: // MULT + superfx_gpr_write(m_dreg_idx, (INT8)(*(m_sreg)) * (INT8)(m_r[op & 0xf])); + break; + case SUPERFX_SFR_ALT1: // UMULT + superfx_gpr_write(m_dreg_idx, (UINT8)(*(m_sreg)) * (UINT8)(m_r[op & 0xf])); + break; + case SUPERFX_SFR_ALT2: // MULTI + superfx_gpr_write(m_dreg_idx, (INT8)(*(m_sreg)) * (INT8)(op & 0xf)); + break; + case SUPERFX_SFR_ALT3: // UMULTI + superfx_gpr_write(m_dreg_idx, (UINT8)(*(m_sreg)) * (UINT8)(op & 0xf)); + break; + } + superfx_dreg_sfr_sz_update(); + superfx_regs_reset(); + if(!(m_cfgr & SUPERFX_CFGR_MS0)) + { + superfx_add_clocks_internal(2); + } + break; + + case 0x90: // SBK + superfx_rambuffer_write(m_ramaddr ^ 0, *(m_sreg) >> 0); + superfx_rambuffer_write(m_ramaddr ^ 1, *(m_sreg) >> 8); + superfx_regs_reset(); + break; + + case 0x91: case 0x92: case 0x93: case 0x94: // LINK + superfx_gpr_write(11, m_r[15] + (op & 0xf)); + superfx_regs_reset(); + break; + + case 0x95: // SEX + superfx_gpr_write(m_dreg_idx, (INT8)(*(m_sreg))); + superfx_dreg_sfr_sz_update(); + superfx_regs_reset(); + break; + + case 0x96: // ASR / DIV2 + if((m_sfr & SUPERFX_SFR_ALT1) == 0) + { // ASR + m_sfr &= ~SUPERFX_SFR_CY; + m_sfr |= (*(m_sreg) & 1) ? SUPERFX_SFR_CY : 0; + superfx_gpr_write(m_dreg_idx, (INT16)(*(m_sreg)) >> 1); + superfx_dreg_sfr_sz_update(); + superfx_regs_reset(); + } + else + { // DIV2 + m_sfr &= ~SUPERFX_SFR_CY; + m_sfr |= (*(m_sreg) & 1) ? SUPERFX_SFR_CY : 0; + superfx_gpr_write(m_dreg_idx, ((INT16)(*(m_sreg)) >> 1) + ((UINT32)(*(m_sreg) + 1) >> 16)); + superfx_dreg_sfr_sz_update(); + superfx_regs_reset(); + } + break; + + case 0x97: // ROR + { + UINT16 carry = *(m_sreg) & 1; + superfx_gpr_write(m_dreg_idx, (SUPERFX_SFR_CY_SET << 15) | ((UINT16)(*(m_sreg)) >> 1)); + m_sfr &= ~SUPERFX_SFR_CY; + m_sfr |= carry ? SUPERFX_SFR_CY : 0; + superfx_dreg_sfr_sz_update(); + superfx_regs_reset(); + break; + } + + case 0x98: case 0x99: case 0x9a: case 0x9b: case 0x9c: case 0x9d: // JMP / LJMP + if((m_sfr & SUPERFX_SFR_ALT1) == 0) + { // JMP + superfx_gpr_write(15, m_r[op & 0xf]); + superfx_regs_reset(); + } + else + { // LJMP + m_pbr = m_r[op & 0xf] & 0x7f; + superfx_gpr_write(15, *(m_sreg)); + m_cbr = m_r[15] & 0xfff0; + superfx_cache_flush(); + superfx_regs_reset(); + } + break; + + case 0x9e: // LOB + superfx_gpr_write(m_dreg_idx, (UINT16)(*(m_sreg)) & 0x00ff); + m_sfr &= ~(SUPERFX_SFR_S | SUPERFX_SFR_Z); + m_sfr |= (*(m_dreg) & 0x80) ? SUPERFX_SFR_S : 0; + m_sfr |= (*(m_dreg) == 0) ? SUPERFX_SFR_Z : 0; + superfx_regs_reset(); + break; + + case 0x9f: // FMULT / LMULT + { + UINT32 result = (INT16)(*(m_sreg)) * (INT16)(m_r[6]); + if(m_sfr & SUPERFX_SFR_ALT1) + { // LMULT + superfx_gpr_write(4, result); + } + superfx_gpr_write(m_dreg_idx, result >> 16); + m_sfr &= ~SUPERFX_SFR_CY; + m_sfr |= (result & 0x8000) ? SUPERFX_SFR_CY : 0; + superfx_dreg_sfr_sz_update(); + superfx_regs_reset(); + superfx_add_clocks_internal(4 + ((m_cfgr & SUPERFX_CFGR_MS0) ? 4 : 0)); + break; + } + + case 0xa0: case 0xa1: case 0xa2: case 0xa3: case 0xa4: case 0xa5: case 0xa6: case 0xa7: + case 0xa8: case 0xa9: case 0xaa: case 0xab: case 0xac: case 0xad: case 0xae: case 0xaf: // IBT / LMS / SMS / LMS + switch(m_sfr & SUPERFX_SFR_ALT) + { + case SUPERFX_SFR_ALT0: // IBT + superfx_gpr_write(op & 0xf, (INT8)superfx_pipe()); + superfx_regs_reset(); + break; + case SUPERFX_SFR_ALT2: // SMS + m_ramaddr = superfx_pipe() << 1; + superfx_rambuffer_write(m_ramaddr ^ 0, m_r[op & 0xf] >> 0); + superfx_rambuffer_write(m_ramaddr ^ 1, m_r[op & 0xf] >> 8); + superfx_regs_reset(); + break; + case SUPERFX_SFR_ALT1: // LMS + case SUPERFX_SFR_ALT3: // LMS + { + UINT16 data = 0; + m_ramaddr = superfx_pipe() << 1; + data = superfx_rambuffer_read(m_ramaddr ^ 0) << 0; + data |= superfx_rambuffer_read(m_ramaddr ^ 1) << 8; + superfx_gpr_write(op & 0xf, data); + superfx_regs_reset(); + break; + } + } + break; + + case 0xb0: case 0xb1: case 0xb2: case 0xb3: case 0xb4: case 0xb5: case 0xb6: case 0xb7: + case 0xb8: case 0xb9: case 0xba: case 0xbb: case 0xbc: case 0xbd: case 0xbe: case 0xbf: // FROM + if((m_sfr & SUPERFX_SFR_B) == 0) + { + m_sreg = &(m_r[op & 0xf]); + m_sreg_idx = op & 0xf; + } + else + { + superfx_gpr_write(m_dreg_idx, m_r[op & 0xf]); + m_sfr &= ~SUPERFX_SFR_OV; + m_sfr |= (*(m_dreg) & 0x80) ? SUPERFX_SFR_OV : 0; + superfx_dreg_sfr_sz_update(); + superfx_regs_reset(); + } + break; + + case 0xc0: // HIB + superfx_gpr_write(m_dreg_idx, (*(m_sreg)) >> 8); + m_sfr &= ~(SUPERFX_SFR_S | SUPERFX_SFR_Z); + m_sfr |= (*(m_dreg) & 0x80) ? SUPERFX_SFR_S : 0; + m_sfr |= (*(m_dreg) == 0) ? SUPERFX_SFR_Z : 0; + superfx_regs_reset(); + break; + + case 0xc1: case 0xc2: case 0xc3: case 0xc4: case 0xc5: case 0xc6: case 0xc7: + case 0xc8: case 0xc9: case 0xca: case 0xcb: case 0xcc: case 0xcd: case 0xce: case 0xcf: // OR / XOR / ORI / XORI + switch(m_sfr & SUPERFX_SFR_ALT) + { + case SUPERFX_SFR_ALT0: // OR + superfx_gpr_write(m_dreg_idx, *(m_sreg) | m_r[op & 0xf]); + break; + case SUPERFX_SFR_ALT1: // XOR + superfx_gpr_write(m_dreg_idx, *(m_sreg) ^ m_r[op & 0xf]); + break; + case SUPERFX_SFR_ALT2: // ORI + superfx_gpr_write(m_dreg_idx, *(m_sreg) | (op & 0xf)); + break; + case SUPERFX_SFR_ALT3: // XORI + superfx_gpr_write(m_dreg_idx, *(m_sreg) ^ (op & 0xf)); + break; + } + superfx_dreg_sfr_sz_update(); + superfx_regs_reset(); + break; + + case 0xd0: case 0xd1: case 0xd2: case 0xd3: case 0xd4: case 0xd5: case 0xd6: case 0xd7: + case 0xd8: case 0xd9: case 0xda: case 0xdb: case 0xdc: case 0xdd: case 0xde: // INC + superfx_gpr_write(op & 0xf, m_r[op & 0xf] + 1); + m_sfr &= ~(SUPERFX_SFR_S | SUPERFX_SFR_Z); + m_sfr |= (m_r[op & 0xf] & 0x8000) ? SUPERFX_SFR_S : 0; + m_sfr |= (m_r[op & 0xf] == 0) ? SUPERFX_SFR_Z : 0; + superfx_regs_reset(); + break; + + case 0xdf: // GETC / RAMB / ROMB + switch(m_sfr & SUPERFX_SFR_ALT) + { + case SUPERFX_SFR_ALT0: // GETC + case SUPERFX_SFR_ALT1: // GETC + m_colr = superfx_color(superfx_rombuffer_read()); + superfx_regs_reset(); + break; + case SUPERFX_SFR_ALT2: // RAMB + superfx_rambuffer_sync(); + m_rambr = ((*(m_sreg)) & 1) ? 1 : 0; + superfx_regs_reset(); + break; + case SUPERFX_SFR_ALT3: // ROMB + superfx_rombuffer_sync(); + m_rombr = *(m_sreg) & 0x7f; + superfx_regs_reset(); + break; + } + break; + + case 0xe0: case 0xe1: case 0xe2: case 0xe3: case 0xe4: case 0xe5: case 0xe6: case 0xe7: + case 0xe8: case 0xe9: case 0xea: case 0xeb: case 0xec: case 0xed: case 0xee: // DEC + superfx_gpr_write(op & 0xf, m_r[op & 0xf] - 1); + m_sfr &= ~(SUPERFX_SFR_S | SUPERFX_SFR_Z); + m_sfr |= (m_r[op & 0xf] & 0x8000) ? SUPERFX_SFR_S : 0; + m_sfr |= (m_r[op & 0xf] == 0) ? SUPERFX_SFR_Z : 0; + superfx_regs_reset(); + break; + + case 0xef: // GETB / GETBH / GETBL / GETBS + { + UINT8 byte = superfx_rombuffer_read(); + switch(m_sfr & SUPERFX_SFR_ALT) + { + case SUPERFX_SFR_ALT0: // GETB + superfx_gpr_write(m_dreg_idx, byte); + break; + case SUPERFX_SFR_ALT1: // GETBH + superfx_gpr_write(m_dreg_idx, (byte << 8) | (*(m_sreg) & 0x00ff)); + break; + case SUPERFX_SFR_ALT2: // GETBL + superfx_gpr_write(m_dreg_idx, (*(m_sreg) & 0xff00) | (byte << 0)); + break; + case SUPERFX_SFR_ALT3: // GETBS + superfx_gpr_write(m_dreg_idx, (INT8)byte); + break; + } + superfx_regs_reset(); + break; + } + + case 0xf0: case 0xf1: case 0xf2: case 0xf3: case 0xf4: case 0xf5: case 0xf6: case 0xf7: + case 0xf8: case 0xf9: case 0xfa: case 0xfb: case 0xfc: case 0xfd: case 0xfe: case 0xff: // IWT / LM / SM / LM + { + UINT16 data; + switch(m_sfr & SUPERFX_SFR_ALT) + { + case SUPERFX_SFR_ALT0: // IWT + data = superfx_pipe() << 0; + data |= superfx_pipe() << 8; + superfx_gpr_write(op & 0xf, data); + superfx_regs_reset(); + break; + case SUPERFX_SFR_ALT2: // SM + m_ramaddr = superfx_pipe() << 0; + m_ramaddr |= superfx_pipe() << 8; + superfx_rambuffer_write(m_ramaddr ^ 0, m_r[op & 0xf] >> 0); + superfx_rambuffer_write(m_ramaddr ^ 1, m_r[op & 0xf] >> 8); + superfx_regs_reset(); + break; + case SUPERFX_SFR_ALT1: + case SUPERFX_SFR_ALT3: // LM + m_ramaddr = superfx_pipe() << 0; + m_ramaddr |= superfx_pipe() << 8; + data = superfx_rambuffer_read(m_ramaddr ^ 0) << 0; + data |= superfx_rambuffer_read(m_ramaddr ^ 1) << 8; + superfx_gpr_write(op & 0xf, data); + superfx_regs_reset(); + break; + } + break; + } + } + + if(!m_r15_modified) + { + m_r[15]++; + } + + //printf( " r0:%04x r1:%04x r2:%04x r3:%04x r4:%04x r5:%04x r6:%04x r7:%04x\n", m_r[0], m_r[1], m_r[2], m_r[3], m_r[4], m_r[5], m_r[6], m_r[7] ); + //printf( " r8:%04x r9:%04x r10:%04x r11:%04x r12:%04x r13:%04x r14:%04x r15:%04x\n", m_r[8], m_r[9], m_r[10], m_r[11], m_r[12], m_r[13], m_r[14], m_r[15] ); + //printf( "sfr:%04x\n", m_sfr ); + + --m_icount; + } +} + + +offs_t superfx_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ +extern offs_t superfx_dasm_one(char *buffer, offs_t pc, UINT8 op, UINT8 param0, UINT8 param1, UINT16 alt); + + UINT8 op = *(UINT8 *)(opram + 0); + UINT8 param0 = *(UINT8 *)(opram + 1); + UINT8 param1 = *(UINT8 *)(opram + 2); + UINT16 alt = m_sfr & SUPERFX_SFR_ALT; + + return superfx_dasm_one(buffer, pc, op, param0, param1, alt); +} diff --git a/src/devices/cpu/superfx/superfx.h b/src/devices/cpu/superfx/superfx.h new file mode 100644 index 00000000000..8c3a8b3d2bd --- /dev/null +++ b/src/devices/cpu/superfx/superfx.h @@ -0,0 +1,217 @@ +// license:BSD-3-Clause +// copyright-holders:Ryan Holtz +#ifndef __SUPERFX_H__ +#define __SUPERFX_H__ + + +enum +{ + SUPERFX_PC = 1, + + SUPERFX_DREG, + SUPERFX_SREG, + + SUPERFX_R0, + SUPERFX_R1, + SUPERFX_R2, + SUPERFX_R3, + SUPERFX_R4, + SUPERFX_R5, + SUPERFX_R6, + SUPERFX_R7, + SUPERFX_R8, + SUPERFX_R9, + SUPERFX_R10, + SUPERFX_R11, + SUPERFX_R12, + SUPERFX_R13, + SUPERFX_R14, + SUPERFX_R15, + + SUPERFX_PBR, + SUPERFX_SFR, + SUPERFX_ROMBR, + SUPERFX_RAMBR, + SUPERFX_CBR, + SUPERFX_SCBR, + SUPERFX_SCMR, + SUPERFX_COLR, + SUPERFX_POR, + SUPERFX_BRAMR, + SUPERFX_VCR, + SUPERFX_CFGR, + SUPERFX_CLSR, + + SUPERFX_ROMCL, + SUPERFX_ROMDR, + + SUPERFX_RAMCL, + SUPERFX_RAMAR, + SUPERFX_RAMDR, + SUPERFX_RAMADDR +}; + +#define SUPERFX_SFR_IRQ 0x8000 // Interrupt Flag +#define SUPERFX_SFR_B 0x1000 // WITH Flag +#define SUPERFX_SFR_IH 0x0800 // Immediate Higher 8-bit Flag +#define SUPERFX_SFR_IL 0x0400 // Immediate Lower 8-bit Flag +#define SUPERFX_SFR_ALT 0x0300 // ALT Mode, both bits +#define SUPERFX_SFR_ALT0 0x0000 // ALT Mode, no bits +#define SUPERFX_SFR_ALT1 0x0100 // ALT Mode, bit 0 +#define SUPERFX_SFR_ALT2 0x0200 // ALT Mode, bit 1 +#define SUPERFX_SFR_ALT3 0x0300 // ALT Mode, both bits (convenience dupe) +#define SUPERFX_SFR_R 0x0040 // ROM R14 Read Flag +#define SUPERFX_SFR_G 0x0020 // GO Flag +#define SUPERFX_SFR_OV 0x0010 // Overflow Flag +#define SUPERFX_SFR_S 0x0008 // Sign Flag +#define SUPERFX_SFR_CY 0x0004 // Carry Flag +#define SUPERFX_SFR_Z 0x0002 // Zero Flag + +#define SUPERFX_POR_OBJ 0x10 +#define SUPERFX_POR_FREEZEHIGH 0x08 +#define SUPERFX_POR_HIGHNIBBLE 0x04 +#define SUPERFX_POR_DITHER 0x02 +#define SUPERFX_POR_TRANSPARENT 0x01 + +#define SUPERFX_SCMR_HT_MASK 0x24 +#define SUPERFX_SCMR_HT0 0x00 +#define SUPERFX_SCMR_HT1 0x04 +#define SUPERFX_SCMR_HT2 0x20 +#define SUPERFX_SCMR_HT3 0x24 +#define SUPERFX_SCMR_RON 0x10 +#define SUPERFX_SCMR_RAN 0x08 +#define SUPERFX_SCMR_MD 0x03 + +#define SUPERFX_CFGR_IRQ 0x80 // IRQ +#define SUPERFX_CFGR_MS0 0x20 // MS0 + + +#define MCFG_SUPERFX_OUT_IRQ(_devcb) \ + superfx_device::set_out_irq_func(*device, DEVCB_##_devcb); + + +class superfx_device : public cpu_device +{ +public: + // construction/destruction + superfx_device(const machine_config &mconfig, const char *_tag, device_t *_owner, UINT32 _clock); + + // static configuration helpers + template static devcb_base &set_out_irq_func(device_t &device, _Object object) { return downcast(device).m_out_irq_func.set_callback(object); } + + UINT8 mmio_read(UINT32 addr); + void mmio_write(UINT32 addr, UINT8 data); + void add_clocks(INT32 clocks); + int access_ram(); + int access_rom(); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_execute_interface overrides + virtual UINT32 execute_min_cycles() const { return 1; } + virtual UINT32 execute_max_cycles() const { return 1; } + virtual UINT32 execute_input_lines() const { return 0; } + virtual void execute_run(); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const { return (spacenum == AS_PROGRAM) ? &m_program_config : NULL; } + + // device_state_interface overrides + virtual void state_import(const device_state_entry &entry); + virtual void state_export(const device_state_entry &entry); + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const { return 1; } + virtual UINT32 disasm_max_opcode_bytes() const { return 3; } + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + +private: + address_space_config m_program_config; + + devcb_write_line m_out_irq_func; + + UINT8 m_pipeline; + UINT16 m_ramaddr; // RAM Address + + UINT16 m_r[16]; // GPRs + UINT16 m_sfr; // Status Flag Register + UINT8 m_pbr; // Program Bank Register + UINT8 m_rombr; // Game Pack ROM Bank Register + UINT8 m_rambr; // Game Pack RAM Bank Register + UINT16 m_cbr; // Cache Base Register + UINT8 m_scbr; // Screen Base Register + UINT8 m_scmr; // Screen Mode Register + UINT8 m_colr; // Color Register + UINT8 m_por; // Plot Option Register + UINT8 m_bramr; // Back-Up RAM Register + UINT8 m_vcr; // Version Code Register + UINT8 m_cfgr; // Config Register + UINT8 m_clsr; // Clock Select Register + + UINT32 m_romcl; // Clock ticks until ROMDR is valid + UINT8 m_romdr; // ROM Buffer Data Register + + UINT32 m_ramcl; // Clock ticks until RAMDR is valid; + UINT16 m_ramar; // RAM Buffer Address Register + UINT8 m_ramdr; // RAM Buffer Data Register + + UINT16 *m_sreg; // Source Register (From) + UINT8 m_sreg_idx;// Source Register (To), index + UINT16 *m_dreg; // Destination Register (To) + UINT8 m_dreg_idx;// Destination Register (To), index + UINT8 m_r15_modified; + + UINT8 m_irq; // IRQ Pending + + UINT32 m_cache_access_speed; + UINT32 m_memory_access_speed; + + struct { + UINT8 buffer[0x200]; + UINT8 valid[0x20]; + } m_cache; + struct { + UINT16 offset; + UINT8 bitpend; + UINT8 data[8]; + } m_pixelcache[2]; + + address_space *m_program; + int m_icount; + + UINT32 m_debugger_temp; + + inline void superfx_regs_reset(); + void superfx_update_speed(); + void superfx_cache_flush(); + UINT8 superfx_cache_mmio_read(UINT32 addr); + void superfx_cache_mmio_write(UINT32 addr, UINT8 data); + void superfx_memory_reset(); + inline UINT8 superfx_bus_read(UINT32 addr); + inline void superfx_bus_write(UINT32 addr, UINT8 data); + inline void superfx_pixelcache_flush(INT32 line); + inline void superfx_plot(UINT8 x, UINT8 y); + UINT8 superfx_rpix(UINT8 x, UINT8 y); + inline UINT8 superfx_color(UINT8 source); + inline void superfx_rambuffer_sync(); + inline UINT8 superfx_rambuffer_read(UINT16 addr); + inline void superfx_rambuffer_write(UINT16 addr, UINT8 data); + inline void superfx_rombuffer_sync(); + inline void superfx_rombuffer_update(); + inline UINT8 superfx_rombuffer_read(); + inline void superfx_gpr_write(UINT8 r, UINT16 data); + inline UINT8 superfx_op_read(UINT16 addr); + inline UINT8 superfx_peekpipe(); + inline UINT8 superfx_pipe(); + inline void superfx_add_clocks_internal(UINT32 clocks); + void superfx_timing_reset(); + inline void superfx_dreg_sfr_sz_update(); +}; + + +extern const device_type SUPERFX; + +#endif /* __SUPERFX_H__ */ diff --git a/src/devices/cpu/t11/t11.c b/src/devices/cpu/t11/t11.c new file mode 100644 index 00000000000..97f53e74b34 --- /dev/null +++ b/src/devices/cpu/t11/t11.c @@ -0,0 +1,426 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*** t11: Portable DEC T-11 emulator ****************************************** + + System dependencies: long must be at least 32 bits + word must be 16 bit unsigned int + byte must be 8 bit unsigned int + long must be more than 16 bits + arrays up to 65536 bytes must be supported + machine must be twos complement + +*****************************************************************************/ + +#include "emu.h" +#include "debugger.h" +#include "t11.h" + + +/************************************* + * + * Macro shortcuts + * + *************************************/ + +/* registers of various sizes */ +#define REGD(x) m_reg[x].d +#define REGW(x) m_reg[x].w.l +#define REGB(x) m_reg[x].b.l + +/* PC, SP, and PSW definitions */ +#define SP REGW(6) +#define PC REGW(7) +#define SPD REGD(6) +#define PCD REGD(7) +#define PSW m_psw.b.l + + +const device_type T11 = &device_creator; +const device_type K1801VM2 = &device_creator; + + +k1801vm2_device::k1801vm2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : t11_device(mconfig, K1801VM2, "K1801VM2", tag, owner, clock, "k1801vm2", __FILE__) +{ +} + +t11_device::t11_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : cpu_device(mconfig, type, name, tag, owner, clock, shortname, source) + , m_program_config("program", ENDIANNESS_LITTLE, 16, 16, 0) + , c_initial_mode(0) +{ + m_is_octal = true; + memset(m_reg, 0x00, sizeof(m_reg)); + memset(&m_psw, 0x00, sizeof(m_psw)); +} + +t11_device::t11_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : cpu_device(mconfig, T11, "T11", tag, owner, clock, "t11", __FILE__) + , m_program_config("program", ENDIANNESS_LITTLE, 16, 16, 0) + , c_initial_mode(0) +{ + m_is_octal = true; + memset(m_reg, 0x00, sizeof(m_reg)); + memset(&m_psw, 0x00, sizeof(m_psw)); +} + + +/************************************* + * + * Low-level memory operations + * + *************************************/ + +int t11_device::ROPCODE() +{ + PC &= 0xfffe; + int val = m_direct->read_word(PC); + PC += 2; + return val; +} + + +int t11_device::RBYTE(int addr) +{ + return m_program->read_byte(addr); +} + + +void t11_device::WBYTE(int addr, int data) +{ + m_program->write_byte(addr, data); +} + + +int t11_device::RWORD(int addr) +{ + return m_program->read_word(addr & 0xfffe); +} + + +void t11_device::WWORD(int addr, int data) +{ + m_program->write_word(addr & 0xfffe, data); +} + + + +/************************************* + * + * Low-level stack operations + * + *************************************/ + +void t11_device::PUSH(int val) +{ + SP -= 2; + WWORD(SPD, val); +} + + +int t11_device::POP() +{ + int result = RWORD(SPD); + SP += 2; + return result; +} + + + +/************************************* + * + * Flag definitions and operations + * + *************************************/ + +/* flag definitions */ +#define CFLAG 1 +#define VFLAG 2 +#define ZFLAG 4 +#define NFLAG 8 + +/* extracts flags */ +#define GET_C (PSW & CFLAG) +#define GET_V (PSW & VFLAG) +#define GET_Z (PSW & ZFLAG) +#define GET_N (PSW & NFLAG) + +/* clears flags */ +#define CLR_C (PSW &= ~CFLAG) +#define CLR_V (PSW &= ~VFLAG) +#define CLR_Z (PSW &= ~ZFLAG) +#define CLR_N (PSW &= ~NFLAG) + +/* sets flags */ +#define SET_C (PSW |= CFLAG) +#define SET_V (PSW |= VFLAG) +#define SET_Z (PSW |= ZFLAG) +#define SET_N (PSW |= NFLAG) + + + +/************************************* + * + * Interrupt handling + * + *************************************/ + +struct irq_table_entry +{ + UINT8 priority; + UINT8 vector; +}; + +static const struct irq_table_entry irq_table[] = +{ + { 0<<5, 0x00 }, + { 4<<5, 0x38 }, + { 4<<5, 0x34 }, + { 4<<5, 0x30 }, + { 5<<5, 0x5c }, + { 5<<5, 0x58 }, + { 5<<5, 0x54 }, + { 5<<5, 0x50 }, + { 6<<5, 0x4c }, + { 6<<5, 0x48 }, + { 6<<5, 0x44 }, + { 6<<5, 0x40 }, + { 7<<5, 0x6c }, + { 7<<5, 0x68 }, + { 7<<5, 0x64 }, + { 7<<5, 0x60 } +}; + +void t11_device::t11_check_irqs() +{ + const struct irq_table_entry *irq = &irq_table[m_irq_state & 15]; + int priority = PSW & 0xe0; + + /* compare the priority of the interrupt to the PSW */ + if (irq->priority > priority) + { + int vector = irq->vector; + int new_pc, new_psw; + + /* call the callback; if we don't get -1 back, use the return value as our vector */ + int new_vector = standard_irq_callback(m_irq_state & 15); + if (new_vector != -1) + vector = new_vector; + + /* fetch the new PC and PSW from that vector */ + assert((vector & 3) == 0); + new_pc = RWORD(vector); + new_psw = RWORD(vector + 2); + + /* push the old state, set the new one */ + PUSH(PSW); + PUSH(PC); + PCD = new_pc; + PSW = new_psw; + t11_check_irqs(); + + /* count cycles and clear the WAIT flag */ + m_icount -= 114; + m_wait_state = 0; + } +} + + + +/************************************* + * + * Core opcodes + * + *************************************/ + +/* includes the static function prototypes and the master opcode table */ +#include "t11table.inc" + +/* includes the actual opcode implementations */ +#include "t11ops.inc" + + + +/************************************* + * + * Low-level initialization/cleanup + * + *************************************/ + +void t11_device::device_start() +{ + static const UINT16 initial_pc[] = + { + 0xc000, 0x8000, 0x4000, 0x2000, + 0x1000, 0x0000, 0xf600, 0xf400 + }; + + m_initial_pc = initial_pc[c_initial_mode >> 13]; + m_program = &space(AS_PROGRAM); + m_direct = &m_program->direct(); + + save_item(NAME(m_ppc.w.l)); + save_item(NAME(m_reg[0].w.l)); + save_item(NAME(m_reg[1].w.l)); + save_item(NAME(m_reg[2].w.l)); + save_item(NAME(m_reg[3].w.l)); + save_item(NAME(m_reg[4].w.l)); + save_item(NAME(m_reg[5].w.l)); + save_item(NAME(m_reg[6].w.l)); + save_item(NAME(m_reg[7].w.l)); + save_item(NAME(m_psw.w.l)); + save_item(NAME(m_initial_pc)); + save_item(NAME(m_wait_state)); + save_item(NAME(m_irq_state)); + + // Register debugger state + state_add( T11_PC, "PC", m_reg[7].w.l).formatstr("%04X"); + state_add( T11_SP, "SP", m_reg[6].w.l).formatstr("%04X"); + state_add( T11_PSW, "PSW", m_psw.b.l).formatstr("%02X"); + state_add( T11_R0, "R0", m_reg[0].w.l).formatstr("%04X"); + state_add( T11_R1, "R1", m_reg[1].w.l).formatstr("%04X"); + state_add( T11_R2, "R2", m_reg[2].w.l).formatstr("%04X"); + state_add( T11_R3, "R3", m_reg[3].w.l).formatstr("%04X"); + state_add( T11_R4, "R4", m_reg[4].w.l).formatstr("%04X"); + state_add( T11_R5, "R5", m_reg[5].w.l).formatstr("%04X"); + + state_add(STATE_GENPC, "curpc", m_reg[7].w.l).noshow(); + state_add(STATE_GENFLAGS, "GENFLAGS", m_psw.b.l).noshow(); + state_add(STATE_GENPCBASE, "GENPCBASE", m_ppc.w.l).noshow(); + + m_icountptr = &m_icount; +} + +void t11_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + switch (entry.index()) + { + case STATE_GENFLAGS: + strprintf(str, "%c%c%c%c%c%c%c%c", + m_psw.b.l & 0x80 ? '?':'.', + m_psw.b.l & 0x40 ? 'I':'.', + m_psw.b.l & 0x20 ? 'I':'.', + m_psw.b.l & 0x10 ? 'T':'.', + m_psw.b.l & 0x08 ? 'N':'.', + m_psw.b.l & 0x04 ? 'Z':'.', + m_psw.b.l & 0x02 ? 'V':'.', + m_psw.b.l & 0x01 ? 'C':'.' + ); + break; + } +} + +void k1801vm2_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + switch (entry.index()) + { + case STATE_GENFLAGS: + strprintf(str, "%c%c%c%c%c%c%c%c%c", + m_psw.b.l & 0x100 ? 'H':'.', + m_psw.b.l & 0x80 ? 'P':'.', + m_psw.b.l & 0x40 ? '?':'.', + m_psw.b.l & 0x20 ? '?':'.', + m_psw.b.l & 0x10 ? 'T':'.', + m_psw.b.l & 0x08 ? 'N':'.', + m_psw.b.l & 0x04 ? 'Z':'.', + m_psw.b.l & 0x02 ? 'V':'.', + m_psw.b.l & 0x01 ? 'C':'.' + ); + break; + } +} + + +/************************************* + * + * CPU reset + * + *************************************/ + +void t11_device::device_reset() +{ + /* initial SP is 376 octal, or 0xfe */ + SP = 0x00fe; + + /* initial PC comes from the setup word */ + PC = m_initial_pc; + + /* PSW starts off at highest priority */ + PSW = 0xe0; + + /* initialize the IRQ state */ + m_irq_state = 0; + + /* reset the remaining state */ + REGD(0) = 0; + REGD(1) = 0; + REGD(2) = 0; + REGD(3) = 0; + REGD(4) = 0; + REGD(5) = 0; + m_ppc.d = 0; + m_wait_state = 0; +} + +void k1801vm2_device::device_reset() +{ + t11_device::device_reset(); + + PC = RWORD(c_initial_mode); + PSW = RWORD(c_initial_mode+2); +} + + +/************************************* + * + * Interrupt handling + * + *************************************/ + +void t11_device::execute_set_input(int irqline, int state) +{ + /* set the appropriate bit */ + if (state == CLEAR_LINE) + m_irq_state &= ~(1 << irqline); + else + m_irq_state |= 1 << irqline; +} + + + +/************************************* + * + * Core execution + * + *************************************/ + +void t11_device::execute_run() +{ + t11_check_irqs(); + + if (m_wait_state) + { + m_icount = 0; + return; + } + + do + { + UINT16 op; + + m_ppc = m_reg[7]; /* copy PC to previous PC */ + + debugger_instruction_hook(this, PCD); + + op = ROPCODE(); + (this->*s_opcode_table[op >> 3])(op); + + } while (m_icount > 0); +} + + +offs_t t11_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( t11 ); + return CPU_DISASSEMBLE_NAME(t11)(this, buffer, pc, oprom, opram, options); +} diff --git a/src/devices/cpu/t11/t11.h b/src/devices/cpu/t11/t11.h new file mode 100644 index 00000000000..45c4ca86c5f --- /dev/null +++ b/src/devices/cpu/t11/t11.h @@ -0,0 +1,1156 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*** T-11: Portable DEC T-11 emulator ******************************************/ + +#pragma once + +#ifndef __T11_H__ +#define __T11_H__ + + +enum +{ + T11_R0=1, T11_R1, T11_R2, T11_R3, T11_R4, T11_R5, T11_SP, T11_PC, T11_PSW +}; + +#define T11_IRQ0 0 /* IRQ0 */ +#define T11_IRQ1 1 /* IRQ1 */ +#define T11_IRQ2 2 /* IRQ2 */ +#define T11_IRQ3 3 /* IRQ3 */ + +#define T11_RESERVED 0x000 /* Reserved vector */ +#define T11_TIMEOUT 0x004 /* Time-out/system error vector */ +#define T11_ILLINST 0x008 /* Illegal and reserved instruction vector */ +#define T11_BPT 0x00C /* BPT instruction vector */ +#define T11_IOT 0x010 /* IOT instruction vector */ +#define T11_PWRFAIL 0x014 /* Power fail vector */ +#define T11_EMT 0x018 /* EMT instruction vector */ +#define T11_TRAP 0x01C /* TRAP instruction vector */ + + +#define MCFG_T11_INITIAL_MODE(_mode) \ + t11_device::set_initial_mode(*device, _mode); + + +class t11_device : public cpu_device +{ +public: + // construction/destruction + t11_device(const machine_config &mconfig, const char *_tag, device_t *_owner, UINT32 _clock); + t11_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + // static configuration helpers + static void set_initial_mode(device_t &device, const UINT16 mode) { downcast(device).c_initial_mode = mode; } + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_execute_interface overrides + virtual UINT32 execute_min_cycles() const { return 12; } + virtual UINT32 execute_max_cycles() const { return 110; } + virtual UINT32 execute_input_lines() const { return 4; } + virtual void execute_run(); + virtual void execute_set_input(int inputnum, int state); + virtual UINT32 execute_default_irq_vector() const { return -1; }; + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const { return (spacenum == AS_PROGRAM) ? &m_program_config : NULL; } + + // device_state_interface overrides + void state_string_export(const device_state_entry &entry, std::string &str); + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const { return 2; } + virtual UINT32 disasm_max_opcode_bytes() const { return 6; } + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + +protected: + address_space_config m_program_config; + + UINT16 c_initial_mode; + + PAIR m_ppc; /* previous program counter */ + PAIR m_reg[8]; + PAIR m_psw; + UINT16 m_initial_pc; + UINT8 m_wait_state; + UINT8 m_irq_state; + int m_icount; + address_space *m_program; + direct_read_data *m_direct; + + inline int ROPCODE(); + inline int RBYTE(int addr); + inline void WBYTE(int addr, int data); + inline int RWORD(int addr); + inline void WWORD(int addr, int data); + inline void PUSH(int val); + inline int POP(); + void t11_check_irqs(); + + typedef void ( t11_device::*opcode_func )(UINT16 op); + static const opcode_func s_opcode_table[65536 >> 3]; + + void op_0000(UINT16 op); + void halt(UINT16 op); + void illegal(UINT16 op); + void jmp_rgd(UINT16 op); + void jmp_in(UINT16 op); + void jmp_ind(UINT16 op); + void jmp_de(UINT16 op); + void jmp_ded(UINT16 op); + void jmp_ix(UINT16 op); + void jmp_ixd(UINT16 op); + void rts(UINT16 op); + void ccc(UINT16 op); + void scc(UINT16 op); + void swab_rg(UINT16 op); + void swab_rgd(UINT16 op); + void swab_in(UINT16 op); + void swab_ind(UINT16 op); + void swab_de(UINT16 op); + void swab_ded(UINT16 op); + void swab_ix(UINT16 op); + void swab_ixd(UINT16 op); + void br(UINT16 op); + void bne(UINT16 op); + void beq(UINT16 op); + void bge(UINT16 op); + void blt(UINT16 op); + void bgt(UINT16 op); + void ble(UINT16 op); + void jsr_rgd(UINT16 op); + void jsr_in(UINT16 op); + void jsr_ind(UINT16 op); + void jsr_de(UINT16 op); + void jsr_ded(UINT16 op); + void jsr_ix(UINT16 op); + void jsr_ixd(UINT16 op); + void clr_rg(UINT16 op); + void clr_rgd(UINT16 op); + void clr_in(UINT16 op); + void clr_ind(UINT16 op); + void clr_de(UINT16 op); + void clr_ded(UINT16 op); + void clr_ix(UINT16 op); + void clr_ixd(UINT16 op); + void com_rg(UINT16 op); + void com_rgd(UINT16 op); + void com_in(UINT16 op); + void com_ind(UINT16 op); + void com_de(UINT16 op); + void com_ded(UINT16 op); + void com_ix(UINT16 op); + void com_ixd(UINT16 op); + void inc_rg(UINT16 op); + void inc_rgd(UINT16 op); + void inc_in(UINT16 op); + void inc_ind(UINT16 op); + void inc_de(UINT16 op); + void inc_ded(UINT16 op); + void inc_ix(UINT16 op); + void inc_ixd(UINT16 op); + void dec_rg(UINT16 op); + void dec_rgd(UINT16 op); + void dec_in(UINT16 op); + void dec_ind(UINT16 op); + void dec_de(UINT16 op); + void dec_ded(UINT16 op); + void dec_ix(UINT16 op); + void dec_ixd(UINT16 op); + void neg_rg(UINT16 op); + void neg_rgd(UINT16 op); + void neg_in(UINT16 op); + void neg_ind(UINT16 op); + void neg_de(UINT16 op); + void neg_ded(UINT16 op); + void neg_ix(UINT16 op); + void neg_ixd(UINT16 op); + void adc_rg(UINT16 op); + void adc_rgd(UINT16 op); + void adc_in(UINT16 op); + void adc_ind(UINT16 op); + void adc_de(UINT16 op); + void adc_ded(UINT16 op); + void adc_ix(UINT16 op); + void adc_ixd(UINT16 op); + void sbc_rg(UINT16 op); + void sbc_rgd(UINT16 op); + void sbc_in(UINT16 op); + void sbc_ind(UINT16 op); + void sbc_de(UINT16 op); + void sbc_ded(UINT16 op); + void sbc_ix(UINT16 op); + void sbc_ixd(UINT16 op); + void tst_rg(UINT16 op); + void tst_rgd(UINT16 op); + void tst_in(UINT16 op); + void tst_ind(UINT16 op); + void tst_de(UINT16 op); + void tst_ded(UINT16 op); + void tst_ix(UINT16 op); + void tst_ixd(UINT16 op); + void ror_rg(UINT16 op); + void ror_rgd(UINT16 op); + void ror_in(UINT16 op); + void ror_ind(UINT16 op); + void ror_de(UINT16 op); + void ror_ded(UINT16 op); + void ror_ix(UINT16 op); + void ror_ixd(UINT16 op); + void rol_rg(UINT16 op); + void rol_rgd(UINT16 op); + void rol_in(UINT16 op); + void rol_ind(UINT16 op); + void rol_de(UINT16 op); + void rol_ded(UINT16 op); + void rol_ix(UINT16 op); + void rol_ixd(UINT16 op); + void asr_rg(UINT16 op); + void asr_rgd(UINT16 op); + void asr_in(UINT16 op); + void asr_ind(UINT16 op); + void asr_de(UINT16 op); + void asr_ded(UINT16 op); + void asr_ix(UINT16 op); + void asr_ixd(UINT16 op); + void asl_rg(UINT16 op); + void asl_rgd(UINT16 op); + void asl_in(UINT16 op); + void asl_ind(UINT16 op); + void asl_de(UINT16 op); + void asl_ded(UINT16 op); + void asl_ix(UINT16 op); + void asl_ixd(UINT16 op); + void mark(UINT16 op); + void sxt_rg(UINT16 op); + void sxt_rgd(UINT16 op); + void sxt_in(UINT16 op); + void sxt_ind(UINT16 op); + void sxt_de(UINT16 op); + void sxt_ded(UINT16 op); + void sxt_ix(UINT16 op); + void sxt_ixd(UINT16 op); + void mov_rg_rg(UINT16 op); + void mov_rg_rgd(UINT16 op); + void mov_rg_in(UINT16 op); + void mov_rg_ind(UINT16 op); + void mov_rg_de(UINT16 op); + void mov_rg_ded(UINT16 op); + void mov_rg_ix(UINT16 op); + void mov_rg_ixd(UINT16 op); + void mov_rgd_rg(UINT16 op); + void mov_rgd_rgd(UINT16 op); + void mov_rgd_in(UINT16 op); + void mov_rgd_ind(UINT16 op); + void mov_rgd_de(UINT16 op); + void mov_rgd_ded(UINT16 op); + void mov_rgd_ix(UINT16 op); + void mov_rgd_ixd(UINT16 op); + void mov_in_rg(UINT16 op); + void mov_in_rgd(UINT16 op); + void mov_in_in(UINT16 op); + void mov_in_ind(UINT16 op); + void mov_in_de(UINT16 op); + void mov_in_ded(UINT16 op); + void mov_in_ix(UINT16 op); + void mov_in_ixd(UINT16 op); + void mov_ind_rg(UINT16 op); + void mov_ind_rgd(UINT16 op); + void mov_ind_in(UINT16 op); + void mov_ind_ind(UINT16 op); + void mov_ind_de(UINT16 op); + void mov_ind_ded(UINT16 op); + void mov_ind_ix(UINT16 op); + void mov_ind_ixd(UINT16 op); + void mov_de_rg(UINT16 op); + void mov_de_rgd(UINT16 op); + void mov_de_in(UINT16 op); + void mov_de_ind(UINT16 op); + void mov_de_de(UINT16 op); + void mov_de_ded(UINT16 op); + void mov_de_ix(UINT16 op); + void mov_de_ixd(UINT16 op); + void mov_ded_rg(UINT16 op); + void mov_ded_rgd(UINT16 op); + void mov_ded_in(UINT16 op); + void mov_ded_ind(UINT16 op); + void mov_ded_de(UINT16 op); + void mov_ded_ded(UINT16 op); + void mov_ded_ix(UINT16 op); + void mov_ded_ixd(UINT16 op); + void mov_ix_rg(UINT16 op); + void mov_ix_rgd(UINT16 op); + void mov_ix_in(UINT16 op); + void mov_ix_ind(UINT16 op); + void mov_ix_de(UINT16 op); + void mov_ix_ded(UINT16 op); + void mov_ix_ix(UINT16 op); + void mov_ix_ixd(UINT16 op); + void mov_ixd_rg(UINT16 op); + void mov_ixd_rgd(UINT16 op); + void mov_ixd_in(UINT16 op); + void mov_ixd_ind(UINT16 op); + void mov_ixd_de(UINT16 op); + void mov_ixd_ded(UINT16 op); + void mov_ixd_ix(UINT16 op); + void mov_ixd_ixd(UINT16 op); + void cmp_rg_rg(UINT16 op); + void cmp_rg_rgd(UINT16 op); + void cmp_rg_in(UINT16 op); + void cmp_rg_ind(UINT16 op); + void cmp_rg_de(UINT16 op); + void cmp_rg_ded(UINT16 op); + void cmp_rg_ix(UINT16 op); + void cmp_rg_ixd(UINT16 op); + void cmp_rgd_rg(UINT16 op); + void cmp_rgd_rgd(UINT16 op); + void cmp_rgd_in(UINT16 op); + void cmp_rgd_ind(UINT16 op); + void cmp_rgd_de(UINT16 op); + void cmp_rgd_ded(UINT16 op); + void cmp_rgd_ix(UINT16 op); + void cmp_rgd_ixd(UINT16 op); + void cmp_in_rg(UINT16 op); + void cmp_in_rgd(UINT16 op); + void cmp_in_in(UINT16 op); + void cmp_in_ind(UINT16 op); + void cmp_in_de(UINT16 op); + void cmp_in_ded(UINT16 op); + void cmp_in_ix(UINT16 op); + void cmp_in_ixd(UINT16 op); + void cmp_ind_rg(UINT16 op); + void cmp_ind_rgd(UINT16 op); + void cmp_ind_in(UINT16 op); + void cmp_ind_ind(UINT16 op); + void cmp_ind_de(UINT16 op); + void cmp_ind_ded(UINT16 op); + void cmp_ind_ix(UINT16 op); + void cmp_ind_ixd(UINT16 op); + void cmp_de_rg(UINT16 op); + void cmp_de_rgd(UINT16 op); + void cmp_de_in(UINT16 op); + void cmp_de_ind(UINT16 op); + void cmp_de_de(UINT16 op); + void cmp_de_ded(UINT16 op); + void cmp_de_ix(UINT16 op); + void cmp_de_ixd(UINT16 op); + void cmp_ded_rg(UINT16 op); + void cmp_ded_rgd(UINT16 op); + void cmp_ded_in(UINT16 op); + void cmp_ded_ind(UINT16 op); + void cmp_ded_de(UINT16 op); + void cmp_ded_ded(UINT16 op); + void cmp_ded_ix(UINT16 op); + void cmp_ded_ixd(UINT16 op); + void cmp_ix_rg(UINT16 op); + void cmp_ix_rgd(UINT16 op); + void cmp_ix_in(UINT16 op); + void cmp_ix_ind(UINT16 op); + void cmp_ix_de(UINT16 op); + void cmp_ix_ded(UINT16 op); + void cmp_ix_ix(UINT16 op); + void cmp_ix_ixd(UINT16 op); + void cmp_ixd_rg(UINT16 op); + void cmp_ixd_rgd(UINT16 op); + void cmp_ixd_in(UINT16 op); + void cmp_ixd_ind(UINT16 op); + void cmp_ixd_de(UINT16 op); + void cmp_ixd_ded(UINT16 op); + void cmp_ixd_ix(UINT16 op); + void cmp_ixd_ixd(UINT16 op); + void bit_rg_rg(UINT16 op); + void bit_rg_rgd(UINT16 op); + void bit_rg_in(UINT16 op); + void bit_rg_ind(UINT16 op); + void bit_rg_de(UINT16 op); + void bit_rg_ded(UINT16 op); + void bit_rg_ix(UINT16 op); + void bit_rg_ixd(UINT16 op); + void bit_rgd_rg(UINT16 op); + void bit_rgd_rgd(UINT16 op); + void bit_rgd_in(UINT16 op); + void bit_rgd_ind(UINT16 op); + void bit_rgd_de(UINT16 op); + void bit_rgd_ded(UINT16 op); + void bit_rgd_ix(UINT16 op); + void bit_rgd_ixd(UINT16 op); + void bit_in_rg(UINT16 op); + void bit_in_rgd(UINT16 op); + void bit_in_in(UINT16 op); + void bit_in_ind(UINT16 op); + void bit_in_de(UINT16 op); + void bit_in_ded(UINT16 op); + void bit_in_ix(UINT16 op); + void bit_in_ixd(UINT16 op); + void bit_ind_rg(UINT16 op); + void bit_ind_rgd(UINT16 op); + void bit_ind_in(UINT16 op); + void bit_ind_ind(UINT16 op); + void bit_ind_de(UINT16 op); + void bit_ind_ded(UINT16 op); + void bit_ind_ix(UINT16 op); + void bit_ind_ixd(UINT16 op); + void bit_de_rg(UINT16 op); + void bit_de_rgd(UINT16 op); + void bit_de_in(UINT16 op); + void bit_de_ind(UINT16 op); + void bit_de_de(UINT16 op); + void bit_de_ded(UINT16 op); + void bit_de_ix(UINT16 op); + void bit_de_ixd(UINT16 op); + void bit_ded_rg(UINT16 op); + void bit_ded_rgd(UINT16 op); + void bit_ded_in(UINT16 op); + void bit_ded_ind(UINT16 op); + void bit_ded_de(UINT16 op); + void bit_ded_ded(UINT16 op); + void bit_ded_ix(UINT16 op); + void bit_ded_ixd(UINT16 op); + void bit_ix_rg(UINT16 op); + void bit_ix_rgd(UINT16 op); + void bit_ix_in(UINT16 op); + void bit_ix_ind(UINT16 op); + void bit_ix_de(UINT16 op); + void bit_ix_ded(UINT16 op); + void bit_ix_ix(UINT16 op); + void bit_ix_ixd(UINT16 op); + void bit_ixd_rg(UINT16 op); + void bit_ixd_rgd(UINT16 op); + void bit_ixd_in(UINT16 op); + void bit_ixd_ind(UINT16 op); + void bit_ixd_de(UINT16 op); + void bit_ixd_ded(UINT16 op); + void bit_ixd_ix(UINT16 op); + void bit_ixd_ixd(UINT16 op); + void bic_rg_rg(UINT16 op); + void bic_rg_rgd(UINT16 op); + void bic_rg_in(UINT16 op); + void bic_rg_ind(UINT16 op); + void bic_rg_de(UINT16 op); + void bic_rg_ded(UINT16 op); + void bic_rg_ix(UINT16 op); + void bic_rg_ixd(UINT16 op); + void bic_rgd_rg(UINT16 op); + void bic_rgd_rgd(UINT16 op); + void bic_rgd_in(UINT16 op); + void bic_rgd_ind(UINT16 op); + void bic_rgd_de(UINT16 op); + void bic_rgd_ded(UINT16 op); + void bic_rgd_ix(UINT16 op); + void bic_rgd_ixd(UINT16 op); + void bic_in_rg(UINT16 op); + void bic_in_rgd(UINT16 op); + void bic_in_in(UINT16 op); + void bic_in_ind(UINT16 op); + void bic_in_de(UINT16 op); + void bic_in_ded(UINT16 op); + void bic_in_ix(UINT16 op); + void bic_in_ixd(UINT16 op); + void bic_ind_rg(UINT16 op); + void bic_ind_rgd(UINT16 op); + void bic_ind_in(UINT16 op); + void bic_ind_ind(UINT16 op); + void bic_ind_de(UINT16 op); + void bic_ind_ded(UINT16 op); + void bic_ind_ix(UINT16 op); + void bic_ind_ixd(UINT16 op); + void bic_de_rg(UINT16 op); + void bic_de_rgd(UINT16 op); + void bic_de_in(UINT16 op); + void bic_de_ind(UINT16 op); + void bic_de_de(UINT16 op); + void bic_de_ded(UINT16 op); + void bic_de_ix(UINT16 op); + void bic_de_ixd(UINT16 op); + void bic_ded_rg(UINT16 op); + void bic_ded_rgd(UINT16 op); + void bic_ded_in(UINT16 op); + void bic_ded_ind(UINT16 op); + void bic_ded_de(UINT16 op); + void bic_ded_ded(UINT16 op); + void bic_ded_ix(UINT16 op); + void bic_ded_ixd(UINT16 op); + void bic_ix_rg(UINT16 op); + void bic_ix_rgd(UINT16 op); + void bic_ix_in(UINT16 op); + void bic_ix_ind(UINT16 op); + void bic_ix_de(UINT16 op); + void bic_ix_ded(UINT16 op); + void bic_ix_ix(UINT16 op); + void bic_ix_ixd(UINT16 op); + void bic_ixd_rg(UINT16 op); + void bic_ixd_rgd(UINT16 op); + void bic_ixd_in(UINT16 op); + void bic_ixd_ind(UINT16 op); + void bic_ixd_de(UINT16 op); + void bic_ixd_ded(UINT16 op); + void bic_ixd_ix(UINT16 op); + void bic_ixd_ixd(UINT16 op); + void bis_rg_rg(UINT16 op); + void bis_rg_rgd(UINT16 op); + void bis_rg_in(UINT16 op); + void bis_rg_ind(UINT16 op); + void bis_rg_de(UINT16 op); + void bis_rg_ded(UINT16 op); + void bis_rg_ix(UINT16 op); + void bis_rg_ixd(UINT16 op); + void bis_rgd_rg(UINT16 op); + void bis_rgd_rgd(UINT16 op); + void bis_rgd_in(UINT16 op); + void bis_rgd_ind(UINT16 op); + void bis_rgd_de(UINT16 op); + void bis_rgd_ded(UINT16 op); + void bis_rgd_ix(UINT16 op); + void bis_rgd_ixd(UINT16 op); + void bis_in_rg(UINT16 op); + void bis_in_rgd(UINT16 op); + void bis_in_in(UINT16 op); + void bis_in_ind(UINT16 op); + void bis_in_de(UINT16 op); + void bis_in_ded(UINT16 op); + void bis_in_ix(UINT16 op); + void bis_in_ixd(UINT16 op); + void bis_ind_rg(UINT16 op); + void bis_ind_rgd(UINT16 op); + void bis_ind_in(UINT16 op); + void bis_ind_ind(UINT16 op); + void bis_ind_de(UINT16 op); + void bis_ind_ded(UINT16 op); + void bis_ind_ix(UINT16 op); + void bis_ind_ixd(UINT16 op); + void bis_de_rg(UINT16 op); + void bis_de_rgd(UINT16 op); + void bis_de_in(UINT16 op); + void bis_de_ind(UINT16 op); + void bis_de_de(UINT16 op); + void bis_de_ded(UINT16 op); + void bis_de_ix(UINT16 op); + void bis_de_ixd(UINT16 op); + void bis_ded_rg(UINT16 op); + void bis_ded_rgd(UINT16 op); + void bis_ded_in(UINT16 op); + void bis_ded_ind(UINT16 op); + void bis_ded_de(UINT16 op); + void bis_ded_ded(UINT16 op); + void bis_ded_ix(UINT16 op); + void bis_ded_ixd(UINT16 op); + void bis_ix_rg(UINT16 op); + void bis_ix_rgd(UINT16 op); + void bis_ix_in(UINT16 op); + void bis_ix_ind(UINT16 op); + void bis_ix_de(UINT16 op); + void bis_ix_ded(UINT16 op); + void bis_ix_ix(UINT16 op); + void bis_ix_ixd(UINT16 op); + void bis_ixd_rg(UINT16 op); + void bis_ixd_rgd(UINT16 op); + void bis_ixd_in(UINT16 op); + void bis_ixd_ind(UINT16 op); + void bis_ixd_de(UINT16 op); + void bis_ixd_ded(UINT16 op); + void bis_ixd_ix(UINT16 op); + void bis_ixd_ixd(UINT16 op); + void add_rg_rg(UINT16 op); + void add_rg_rgd(UINT16 op); + void add_rg_in(UINT16 op); + void add_rg_ind(UINT16 op); + void add_rg_de(UINT16 op); + void add_rg_ded(UINT16 op); + void add_rg_ix(UINT16 op); + void add_rg_ixd(UINT16 op); + void add_rgd_rg(UINT16 op); + void add_rgd_rgd(UINT16 op); + void add_rgd_in(UINT16 op); + void add_rgd_ind(UINT16 op); + void add_rgd_de(UINT16 op); + void add_rgd_ded(UINT16 op); + void add_rgd_ix(UINT16 op); + void add_rgd_ixd(UINT16 op); + void add_in_rg(UINT16 op); + void add_in_rgd(UINT16 op); + void add_in_in(UINT16 op); + void add_in_ind(UINT16 op); + void add_in_de(UINT16 op); + void add_in_ded(UINT16 op); + void add_in_ix(UINT16 op); + void add_in_ixd(UINT16 op); + void add_ind_rg(UINT16 op); + void add_ind_rgd(UINT16 op); + void add_ind_in(UINT16 op); + void add_ind_ind(UINT16 op); + void add_ind_de(UINT16 op); + void add_ind_ded(UINT16 op); + void add_ind_ix(UINT16 op); + void add_ind_ixd(UINT16 op); + void add_de_rg(UINT16 op); + void add_de_rgd(UINT16 op); + void add_de_in(UINT16 op); + void add_de_ind(UINT16 op); + void add_de_de(UINT16 op); + void add_de_ded(UINT16 op); + void add_de_ix(UINT16 op); + void add_de_ixd(UINT16 op); + void add_ded_rg(UINT16 op); + void add_ded_rgd(UINT16 op); + void add_ded_in(UINT16 op); + void add_ded_ind(UINT16 op); + void add_ded_de(UINT16 op); + void add_ded_ded(UINT16 op); + void add_ded_ix(UINT16 op); + void add_ded_ixd(UINT16 op); + void add_ix_rg(UINT16 op); + void add_ix_rgd(UINT16 op); + void add_ix_in(UINT16 op); + void add_ix_ind(UINT16 op); + void add_ix_de(UINT16 op); + void add_ix_ded(UINT16 op); + void add_ix_ix(UINT16 op); + void add_ix_ixd(UINT16 op); + void add_ixd_rg(UINT16 op); + void add_ixd_rgd(UINT16 op); + void add_ixd_in(UINT16 op); + void add_ixd_ind(UINT16 op); + void add_ixd_de(UINT16 op); + void add_ixd_ded(UINT16 op); + void add_ixd_ix(UINT16 op); + void add_ixd_ixd(UINT16 op); + void xor_rg(UINT16 op); + void xor_rgd(UINT16 op); + void xor_in(UINT16 op); + void xor_ind(UINT16 op); + void xor_de(UINT16 op); + void xor_ded(UINT16 op); + void xor_ix(UINT16 op); + void xor_ixd(UINT16 op); + void sob(UINT16 op); + void bpl(UINT16 op); + void bmi(UINT16 op); + void bhi(UINT16 op); + void blos(UINT16 op); + void bvc(UINT16 op); + void bvs(UINT16 op); + void bcc(UINT16 op); + void bcs(UINT16 op); + void emt(UINT16 op); + void trap(UINT16 op); + void clrb_rg(UINT16 op); + void clrb_rgd(UINT16 op); + void clrb_in(UINT16 op); + void clrb_ind(UINT16 op); + void clrb_de(UINT16 op); + void clrb_ded(UINT16 op); + void clrb_ix(UINT16 op); + void clrb_ixd(UINT16 op); + void comb_rg(UINT16 op); + void comb_rgd(UINT16 op); + void comb_in(UINT16 op); + void comb_ind(UINT16 op); + void comb_de(UINT16 op); + void comb_ded(UINT16 op); + void comb_ix(UINT16 op); + void comb_ixd(UINT16 op); + void incb_rg(UINT16 op); + void incb_rgd(UINT16 op); + void incb_in(UINT16 op); + void incb_ind(UINT16 op); + void incb_de(UINT16 op); + void incb_ded(UINT16 op); + void incb_ix(UINT16 op); + void incb_ixd(UINT16 op); + void decb_rg(UINT16 op); + void decb_rgd(UINT16 op); + void decb_in(UINT16 op); + void decb_ind(UINT16 op); + void decb_de(UINT16 op); + void decb_ded(UINT16 op); + void decb_ix(UINT16 op); + void decb_ixd(UINT16 op); + void negb_rg(UINT16 op); + void negb_rgd(UINT16 op); + void negb_in(UINT16 op); + void negb_ind(UINT16 op); + void negb_de(UINT16 op); + void negb_ded(UINT16 op); + void negb_ix(UINT16 op); + void negb_ixd(UINT16 op); + void adcb_rg(UINT16 op); + void adcb_rgd(UINT16 op); + void adcb_in(UINT16 op); + void adcb_ind(UINT16 op); + void adcb_de(UINT16 op); + void adcb_ded(UINT16 op); + void adcb_ix(UINT16 op); + void adcb_ixd(UINT16 op); + void sbcb_rg(UINT16 op); + void sbcb_rgd(UINT16 op); + void sbcb_in(UINT16 op); + void sbcb_ind(UINT16 op); + void sbcb_de(UINT16 op); + void sbcb_ded(UINT16 op); + void sbcb_ix(UINT16 op); + void sbcb_ixd(UINT16 op); + void tstb_rg(UINT16 op); + void tstb_rgd(UINT16 op); + void tstb_in(UINT16 op); + void tstb_ind(UINT16 op); + void tstb_de(UINT16 op); + void tstb_ded(UINT16 op); + void tstb_ix(UINT16 op); + void tstb_ixd(UINT16 op); + void rorb_rg(UINT16 op); + void rorb_rgd(UINT16 op); + void rorb_in(UINT16 op); + void rorb_ind(UINT16 op); + void rorb_de(UINT16 op); + void rorb_ded(UINT16 op); + void rorb_ix(UINT16 op); + void rorb_ixd(UINT16 op); + void rolb_rg(UINT16 op); + void rolb_rgd(UINT16 op); + void rolb_in(UINT16 op); + void rolb_ind(UINT16 op); + void rolb_de(UINT16 op); + void rolb_ded(UINT16 op); + void rolb_ix(UINT16 op); + void rolb_ixd(UINT16 op); + void asrb_rg(UINT16 op); + void asrb_rgd(UINT16 op); + void asrb_in(UINT16 op); + void asrb_ind(UINT16 op); + void asrb_de(UINT16 op); + void asrb_ded(UINT16 op); + void asrb_ix(UINT16 op); + void asrb_ixd(UINT16 op); + void aslb_rg(UINT16 op); + void aslb_rgd(UINT16 op); + void aslb_in(UINT16 op); + void aslb_ind(UINT16 op); + void aslb_de(UINT16 op); + void aslb_ded(UINT16 op); + void aslb_ix(UINT16 op); + void aslb_ixd(UINT16 op); + void mtps_rg(UINT16 op); + void mtps_rgd(UINT16 op); + void mtps_in(UINT16 op); + void mtps_ind(UINT16 op); + void mtps_de(UINT16 op); + void mtps_ded(UINT16 op); + void mtps_ix(UINT16 op); + void mtps_ixd(UINT16 op); + void mfps_rg(UINT16 op); + void mfps_rgd(UINT16 op); + void mfps_in(UINT16 op); + void mfps_ind(UINT16 op); + void mfps_de(UINT16 op); + void mfps_ded(UINT16 op); + void mfps_ix(UINT16 op); + void mfps_ixd(UINT16 op); + void movb_rg_rg(UINT16 op); + void movb_rg_rgd(UINT16 op); + void movb_rg_in(UINT16 op); + void movb_rg_ind(UINT16 op); + void movb_rg_de(UINT16 op); + void movb_rg_ded(UINT16 op); + void movb_rg_ix(UINT16 op); + void movb_rg_ixd(UINT16 op); + void movb_rgd_rg(UINT16 op); + void movb_rgd_rgd(UINT16 op); + void movb_rgd_in(UINT16 op); + void movb_rgd_ind(UINT16 op); + void movb_rgd_de(UINT16 op); + void movb_rgd_ded(UINT16 op); + void movb_rgd_ix(UINT16 op); + void movb_rgd_ixd(UINT16 op); + void movb_in_rg(UINT16 op); + void movb_in_rgd(UINT16 op); + void movb_in_in(UINT16 op); + void movb_in_ind(UINT16 op); + void movb_in_de(UINT16 op); + void movb_in_ded(UINT16 op); + void movb_in_ix(UINT16 op); + void movb_in_ixd(UINT16 op); + void movb_ind_rg(UINT16 op); + void movb_ind_rgd(UINT16 op); + void movb_ind_in(UINT16 op); + void movb_ind_ind(UINT16 op); + void movb_ind_de(UINT16 op); + void movb_ind_ded(UINT16 op); + void movb_ind_ix(UINT16 op); + void movb_ind_ixd(UINT16 op); + void movb_de_rg(UINT16 op); + void movb_de_rgd(UINT16 op); + void movb_de_in(UINT16 op); + void movb_de_ind(UINT16 op); + void movb_de_de(UINT16 op); + void movb_de_ded(UINT16 op); + void movb_de_ix(UINT16 op); + void movb_de_ixd(UINT16 op); + void movb_ded_rg(UINT16 op); + void movb_ded_rgd(UINT16 op); + void movb_ded_in(UINT16 op); + void movb_ded_ind(UINT16 op); + void movb_ded_de(UINT16 op); + void movb_ded_ded(UINT16 op); + void movb_ded_ix(UINT16 op); + void movb_ded_ixd(UINT16 op); + void movb_ix_rg(UINT16 op); + void movb_ix_rgd(UINT16 op); + void movb_ix_in(UINT16 op); + void movb_ix_ind(UINT16 op); + void movb_ix_de(UINT16 op); + void movb_ix_ded(UINT16 op); + void movb_ix_ix(UINT16 op); + void movb_ix_ixd(UINT16 op); + void movb_ixd_rg(UINT16 op); + void movb_ixd_rgd(UINT16 op); + void movb_ixd_in(UINT16 op); + void movb_ixd_ind(UINT16 op); + void movb_ixd_de(UINT16 op); + void movb_ixd_ded(UINT16 op); + void movb_ixd_ix(UINT16 op); + void movb_ixd_ixd(UINT16 op); + void cmpb_rg_rg(UINT16 op); + void cmpb_rg_rgd(UINT16 op); + void cmpb_rg_in(UINT16 op); + void cmpb_rg_ind(UINT16 op); + void cmpb_rg_de(UINT16 op); + void cmpb_rg_ded(UINT16 op); + void cmpb_rg_ix(UINT16 op); + void cmpb_rg_ixd(UINT16 op); + void cmpb_rgd_rg(UINT16 op); + void cmpb_rgd_rgd(UINT16 op); + void cmpb_rgd_in(UINT16 op); + void cmpb_rgd_ind(UINT16 op); + void cmpb_rgd_de(UINT16 op); + void cmpb_rgd_ded(UINT16 op); + void cmpb_rgd_ix(UINT16 op); + void cmpb_rgd_ixd(UINT16 op); + void cmpb_in_rg(UINT16 op); + void cmpb_in_rgd(UINT16 op); + void cmpb_in_in(UINT16 op); + void cmpb_in_ind(UINT16 op); + void cmpb_in_de(UINT16 op); + void cmpb_in_ded(UINT16 op); + void cmpb_in_ix(UINT16 op); + void cmpb_in_ixd(UINT16 op); + void cmpb_ind_rg(UINT16 op); + void cmpb_ind_rgd(UINT16 op); + void cmpb_ind_in(UINT16 op); + void cmpb_ind_ind(UINT16 op); + void cmpb_ind_de(UINT16 op); + void cmpb_ind_ded(UINT16 op); + void cmpb_ind_ix(UINT16 op); + void cmpb_ind_ixd(UINT16 op); + void cmpb_de_rg(UINT16 op); + void cmpb_de_rgd(UINT16 op); + void cmpb_de_in(UINT16 op); + void cmpb_de_ind(UINT16 op); + void cmpb_de_de(UINT16 op); + void cmpb_de_ded(UINT16 op); + void cmpb_de_ix(UINT16 op); + void cmpb_de_ixd(UINT16 op); + void cmpb_ded_rg(UINT16 op); + void cmpb_ded_rgd(UINT16 op); + void cmpb_ded_in(UINT16 op); + void cmpb_ded_ind(UINT16 op); + void cmpb_ded_de(UINT16 op); + void cmpb_ded_ded(UINT16 op); + void cmpb_ded_ix(UINT16 op); + void cmpb_ded_ixd(UINT16 op); + void cmpb_ix_rg(UINT16 op); + void cmpb_ix_rgd(UINT16 op); + void cmpb_ix_in(UINT16 op); + void cmpb_ix_ind(UINT16 op); + void cmpb_ix_de(UINT16 op); + void cmpb_ix_ded(UINT16 op); + void cmpb_ix_ix(UINT16 op); + void cmpb_ix_ixd(UINT16 op); + void cmpb_ixd_rg(UINT16 op); + void cmpb_ixd_rgd(UINT16 op); + void cmpb_ixd_in(UINT16 op); + void cmpb_ixd_ind(UINT16 op); + void cmpb_ixd_de(UINT16 op); + void cmpb_ixd_ded(UINT16 op); + void cmpb_ixd_ix(UINT16 op); + void cmpb_ixd_ixd(UINT16 op); + void bitb_rg_rg(UINT16 op); + void bitb_rg_rgd(UINT16 op); + void bitb_rg_in(UINT16 op); + void bitb_rg_ind(UINT16 op); + void bitb_rg_de(UINT16 op); + void bitb_rg_ded(UINT16 op); + void bitb_rg_ix(UINT16 op); + void bitb_rg_ixd(UINT16 op); + void bitb_rgd_rg(UINT16 op); + void bitb_rgd_rgd(UINT16 op); + void bitb_rgd_in(UINT16 op); + void bitb_rgd_ind(UINT16 op); + void bitb_rgd_de(UINT16 op); + void bitb_rgd_ded(UINT16 op); + void bitb_rgd_ix(UINT16 op); + void bitb_rgd_ixd(UINT16 op); + void bitb_in_rg(UINT16 op); + void bitb_in_rgd(UINT16 op); + void bitb_in_in(UINT16 op); + void bitb_in_ind(UINT16 op); + void bitb_in_de(UINT16 op); + void bitb_in_ded(UINT16 op); + void bitb_in_ix(UINT16 op); + void bitb_in_ixd(UINT16 op); + void bitb_ind_rg(UINT16 op); + void bitb_ind_rgd(UINT16 op); + void bitb_ind_in(UINT16 op); + void bitb_ind_ind(UINT16 op); + void bitb_ind_de(UINT16 op); + void bitb_ind_ded(UINT16 op); + void bitb_ind_ix(UINT16 op); + void bitb_ind_ixd(UINT16 op); + void bitb_de_rg(UINT16 op); + void bitb_de_rgd(UINT16 op); + void bitb_de_in(UINT16 op); + void bitb_de_ind(UINT16 op); + void bitb_de_de(UINT16 op); + void bitb_de_ded(UINT16 op); + void bitb_de_ix(UINT16 op); + void bitb_de_ixd(UINT16 op); + void bitb_ded_rg(UINT16 op); + void bitb_ded_rgd(UINT16 op); + void bitb_ded_in(UINT16 op); + void bitb_ded_ind(UINT16 op); + void bitb_ded_de(UINT16 op); + void bitb_ded_ded(UINT16 op); + void bitb_ded_ix(UINT16 op); + void bitb_ded_ixd(UINT16 op); + void bitb_ix_rg(UINT16 op); + void bitb_ix_rgd(UINT16 op); + void bitb_ix_in(UINT16 op); + void bitb_ix_ind(UINT16 op); + void bitb_ix_de(UINT16 op); + void bitb_ix_ded(UINT16 op); + void bitb_ix_ix(UINT16 op); + void bitb_ix_ixd(UINT16 op); + void bitb_ixd_rg(UINT16 op); + void bitb_ixd_rgd(UINT16 op); + void bitb_ixd_in(UINT16 op); + void bitb_ixd_ind(UINT16 op); + void bitb_ixd_de(UINT16 op); + void bitb_ixd_ded(UINT16 op); + void bitb_ixd_ix(UINT16 op); + void bitb_ixd_ixd(UINT16 op); + void bicb_rg_rg(UINT16 op); + void bicb_rg_rgd(UINT16 op); + void bicb_rg_in(UINT16 op); + void bicb_rg_ind(UINT16 op); + void bicb_rg_de(UINT16 op); + void bicb_rg_ded(UINT16 op); + void bicb_rg_ix(UINT16 op); + void bicb_rg_ixd(UINT16 op); + void bicb_rgd_rg(UINT16 op); + void bicb_rgd_rgd(UINT16 op); + void bicb_rgd_in(UINT16 op); + void bicb_rgd_ind(UINT16 op); + void bicb_rgd_de(UINT16 op); + void bicb_rgd_ded(UINT16 op); + void bicb_rgd_ix(UINT16 op); + void bicb_rgd_ixd(UINT16 op); + void bicb_in_rg(UINT16 op); + void bicb_in_rgd(UINT16 op); + void bicb_in_in(UINT16 op); + void bicb_in_ind(UINT16 op); + void bicb_in_de(UINT16 op); + void bicb_in_ded(UINT16 op); + void bicb_in_ix(UINT16 op); + void bicb_in_ixd(UINT16 op); + void bicb_ind_rg(UINT16 op); + void bicb_ind_rgd(UINT16 op); + void bicb_ind_in(UINT16 op); + void bicb_ind_ind(UINT16 op); + void bicb_ind_de(UINT16 op); + void bicb_ind_ded(UINT16 op); + void bicb_ind_ix(UINT16 op); + void bicb_ind_ixd(UINT16 op); + void bicb_de_rg(UINT16 op); + void bicb_de_rgd(UINT16 op); + void bicb_de_in(UINT16 op); + void bicb_de_ind(UINT16 op); + void bicb_de_de(UINT16 op); + void bicb_de_ded(UINT16 op); + void bicb_de_ix(UINT16 op); + void bicb_de_ixd(UINT16 op); + void bicb_ded_rg(UINT16 op); + void bicb_ded_rgd(UINT16 op); + void bicb_ded_in(UINT16 op); + void bicb_ded_ind(UINT16 op); + void bicb_ded_de(UINT16 op); + void bicb_ded_ded(UINT16 op); + void bicb_ded_ix(UINT16 op); + void bicb_ded_ixd(UINT16 op); + void bicb_ix_rg(UINT16 op); + void bicb_ix_rgd(UINT16 op); + void bicb_ix_in(UINT16 op); + void bicb_ix_ind(UINT16 op); + void bicb_ix_de(UINT16 op); + void bicb_ix_ded(UINT16 op); + void bicb_ix_ix(UINT16 op); + void bicb_ix_ixd(UINT16 op); + void bicb_ixd_rg(UINT16 op); + void bicb_ixd_rgd(UINT16 op); + void bicb_ixd_in(UINT16 op); + void bicb_ixd_ind(UINT16 op); + void bicb_ixd_de(UINT16 op); + void bicb_ixd_ded(UINT16 op); + void bicb_ixd_ix(UINT16 op); + void bicb_ixd_ixd(UINT16 op); + void bisb_rg_rg(UINT16 op); + void bisb_rg_rgd(UINT16 op); + void bisb_rg_in(UINT16 op); + void bisb_rg_ind(UINT16 op); + void bisb_rg_de(UINT16 op); + void bisb_rg_ded(UINT16 op); + void bisb_rg_ix(UINT16 op); + void bisb_rg_ixd(UINT16 op); + void bisb_rgd_rg(UINT16 op); + void bisb_rgd_rgd(UINT16 op); + void bisb_rgd_in(UINT16 op); + void bisb_rgd_ind(UINT16 op); + void bisb_rgd_de(UINT16 op); + void bisb_rgd_ded(UINT16 op); + void bisb_rgd_ix(UINT16 op); + void bisb_rgd_ixd(UINT16 op); + void bisb_in_rg(UINT16 op); + void bisb_in_rgd(UINT16 op); + void bisb_in_in(UINT16 op); + void bisb_in_ind(UINT16 op); + void bisb_in_de(UINT16 op); + void bisb_in_ded(UINT16 op); + void bisb_in_ix(UINT16 op); + void bisb_in_ixd(UINT16 op); + void bisb_ind_rg(UINT16 op); + void bisb_ind_rgd(UINT16 op); + void bisb_ind_in(UINT16 op); + void bisb_ind_ind(UINT16 op); + void bisb_ind_de(UINT16 op); + void bisb_ind_ded(UINT16 op); + void bisb_ind_ix(UINT16 op); + void bisb_ind_ixd(UINT16 op); + void bisb_de_rg(UINT16 op); + void bisb_de_rgd(UINT16 op); + void bisb_de_in(UINT16 op); + void bisb_de_ind(UINT16 op); + void bisb_de_de(UINT16 op); + void bisb_de_ded(UINT16 op); + void bisb_de_ix(UINT16 op); + void bisb_de_ixd(UINT16 op); + void bisb_ded_rg(UINT16 op); + void bisb_ded_rgd(UINT16 op); + void bisb_ded_in(UINT16 op); + void bisb_ded_ind(UINT16 op); + void bisb_ded_de(UINT16 op); + void bisb_ded_ded(UINT16 op); + void bisb_ded_ix(UINT16 op); + void bisb_ded_ixd(UINT16 op); + void bisb_ix_rg(UINT16 op); + void bisb_ix_rgd(UINT16 op); + void bisb_ix_in(UINT16 op); + void bisb_ix_ind(UINT16 op); + void bisb_ix_de(UINT16 op); + void bisb_ix_ded(UINT16 op); + void bisb_ix_ix(UINT16 op); + void bisb_ix_ixd(UINT16 op); + void bisb_ixd_rg(UINT16 op); + void bisb_ixd_rgd(UINT16 op); + void bisb_ixd_in(UINT16 op); + void bisb_ixd_ind(UINT16 op); + void bisb_ixd_de(UINT16 op); + void bisb_ixd_ded(UINT16 op); + void bisb_ixd_ix(UINT16 op); + void bisb_ixd_ixd(UINT16 op); + void sub_rg_rg(UINT16 op); + void sub_rg_rgd(UINT16 op); + void sub_rg_in(UINT16 op); + void sub_rg_ind(UINT16 op); + void sub_rg_de(UINT16 op); + void sub_rg_ded(UINT16 op); + void sub_rg_ix(UINT16 op); + void sub_rg_ixd(UINT16 op); + void sub_rgd_rg(UINT16 op); + void sub_rgd_rgd(UINT16 op); + void sub_rgd_in(UINT16 op); + void sub_rgd_ind(UINT16 op); + void sub_rgd_de(UINT16 op); + void sub_rgd_ded(UINT16 op); + void sub_rgd_ix(UINT16 op); + void sub_rgd_ixd(UINT16 op); + void sub_in_rg(UINT16 op); + void sub_in_rgd(UINT16 op); + void sub_in_in(UINT16 op); + void sub_in_ind(UINT16 op); + void sub_in_de(UINT16 op); + void sub_in_ded(UINT16 op); + void sub_in_ix(UINT16 op); + void sub_in_ixd(UINT16 op); + void sub_ind_rg(UINT16 op); + void sub_ind_rgd(UINT16 op); + void sub_ind_in(UINT16 op); + void sub_ind_ind(UINT16 op); + void sub_ind_de(UINT16 op); + void sub_ind_ded(UINT16 op); + void sub_ind_ix(UINT16 op); + void sub_ind_ixd(UINT16 op); + void sub_de_rg(UINT16 op); + void sub_de_rgd(UINT16 op); + void sub_de_in(UINT16 op); + void sub_de_ind(UINT16 op); + void sub_de_de(UINT16 op); + void sub_de_ded(UINT16 op); + void sub_de_ix(UINT16 op); + void sub_de_ixd(UINT16 op); + void sub_ded_rg(UINT16 op); + void sub_ded_rgd(UINT16 op); + void sub_ded_in(UINT16 op); + void sub_ded_ind(UINT16 op); + void sub_ded_de(UINT16 op); + void sub_ded_ded(UINT16 op); + void sub_ded_ix(UINT16 op); + void sub_ded_ixd(UINT16 op); + void sub_ix_rg(UINT16 op); + void sub_ix_rgd(UINT16 op); + void sub_ix_in(UINT16 op); + void sub_ix_ind(UINT16 op); + void sub_ix_de(UINT16 op); + void sub_ix_ded(UINT16 op); + void sub_ix_ix(UINT16 op); + void sub_ix_ixd(UINT16 op); + void sub_ixd_rg(UINT16 op); + void sub_ixd_rgd(UINT16 op); + void sub_ixd_in(UINT16 op); + void sub_ixd_ind(UINT16 op); + void sub_ixd_de(UINT16 op); + void sub_ixd_ded(UINT16 op); + void sub_ixd_ix(UINT16 op); + void sub_ixd_ixd(UINT16 op); +}; + +class k1801vm2_device : public t11_device +{ +public: + // construction/destruction + k1801vm2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // device-level overrides + virtual void device_reset(); + + // device_state_interface overrides + void state_string_export(const device_state_entry &entry, std::string &str); +}; + + +extern const device_type T11; +extern const device_type K1801VM2; + + +#endif /* __T11_H__ */ diff --git a/src/devices/cpu/t11/t11dasm.c b/src/devices/cpu/t11/t11dasm.c new file mode 100644 index 00000000000..0bb9da4e7ea --- /dev/null +++ b/src/devices/cpu/t11/t11dasm.c @@ -0,0 +1,518 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/* + * A T11 disassembler + * + * Note: this is probably not the most efficient disassembler in the world :-) + * + * This code written by Aaron Giles (agiles@sirius.com) for the MAME project + * + */ + +#include "emu.h" +#include "debugger.h" +#include "t11.h" + +static const char *const regs[8] = { "R0", "R1", "R2", "R3", "R4", "R5", "SP", "PC" }; + +static const UINT8 *rombase; +static offs_t pcbase; + +#define PARAM_WORD(v) ((v) = rombase[pc - pcbase] | (rombase[pc + 1 - pcbase] << 8), pc += 2) + +static unsigned MakeEA (char *ea, int lo, unsigned pc, int width) +{ + int reg, pm; + + assert (width == 2 || width == 4); + + reg = lo & 7; + + switch ((lo >> 3) & 7) + { + case 0: + sprintf (ea, "%s", regs[reg]); + break; + case 1: + sprintf (ea, "(%s)", regs[reg]); + break; + case 2: + if (reg == 7) + { + PARAM_WORD (pm); + sprintf (ea, "#$%0*X", width, pm & ((width == 2) ? 0xff : 0xffff)); + } + else + { + sprintf (ea, "(%s)+", regs[reg]); + } + break; + case 3: + if (reg == 7) + { + PARAM_WORD (pm); + sprintf (ea, "$%04X", pm &= 0xffff); + } + else + { + sprintf (ea, "@(%s)+", regs[reg]); + } + break; + case 4: + sprintf (ea, "-(%s)", regs[reg]); + break; + case 5: + sprintf (ea, "@-(%s)", regs[reg]); + break; + case 6: + PARAM_WORD (pm); + sprintf(ea, "%s$%X(%s)", + (pm&0x8000)?"-":"", + (pm&0x8000)?-(signed short)pm:pm, + regs[reg]); + break; + case 7: + PARAM_WORD (pm); + sprintf(ea, "@%s$%X(%s)", + (pm&0x8000)?"-":"", + (pm&0x8000)?-(signed short)pm:pm, + regs[reg]); + break; + } + + return pc; +} + + +CPU_DISASSEMBLE( t11 ) +{ + char ea1[32], ea2[32]; + unsigned PC = pc; + UINT16 op, lo, hi, addr; + INT16 offset; + UINT32 flags = 0; + + rombase = oprom; + pcbase = pc; + + PARAM_WORD(op); + lo = op & 077; + hi = (op >> 6) & 077; + + switch (op & 0xffc0) + { + case 0x0000: + switch (lo) + { + case 0x00: sprintf (buffer, "HALT"); break; + case 0x01: sprintf (buffer, "WAIT"); break; + case 0x02: sprintf (buffer, "RTI"); flags = DASMFLAG_STEP_OUT; break; + case 0x03: sprintf (buffer, "BPT"); break; + case 0x04: sprintf (buffer, "IOT"); break; + case 0x05: sprintf (buffer, "RESET"); break; + case 0x06: sprintf (buffer, "RTT"); break; + default: sprintf (buffer, "???? (%04X)", op); break; + } + break; + case 0x0040: + pc = MakeEA (ea1, lo, pc, 4); + sprintf (buffer, "JMP %s", ea1); + break; + case 0x0080: + switch (lo & 070) + { + case 000: + if( (lo & 7) == 7 ) + sprintf (buffer, "RTS"); + else + sprintf (buffer, "RTS %s", regs[lo & 7]); + flags = DASMFLAG_STEP_OUT; + break; + case 040: + case 050: + switch( lo & 15 ) + { + case 0x00: sprintf (buffer, "NOP"); break; + case 0x0f: sprintf (buffer, "CCC"); break; + case 0x01: sprintf (buffer, "CEC"); break; + case 0x02: sprintf (buffer, "CEV"); break; + case 0x04: sprintf (buffer, "CEZ"); break; + case 0x08: sprintf (buffer, "CEN"); break; + default: sprintf (buffer, "Ccc #$%X", lo & 15); break; + } + break; + case 060: + case 070: + switch( lo & 15 ) + { + case 0x00: sprintf (buffer, "NOP"); break; + case 0x0f: sprintf (buffer, "SCC"); break; + case 0x01: sprintf (buffer, "SEC"); break; + case 0x02: sprintf (buffer, "SEV"); break; + case 0x04: sprintf (buffer, "SEZ"); break; + case 0x08: sprintf (buffer, "SEN"); break; + default: sprintf (buffer, "Scc #$%X", lo & 15); break; + } + break; + } + break; + case 0x00c0: + pc = MakeEA (ea1, lo, pc, 4); + sprintf (buffer, "SWAB %s", ea1); + break; + case 0x0100: case 0x0140: case 0x0180: case 0x01c0: + offset = 2 * (INT8)(op & 0xff); + sprintf (buffer, "BR $%04X", pc + offset); + break; + case 0x0200: case 0x0240: case 0x0280: case 0x02c0: + offset = 2 * (INT8)(op & 0xff); + sprintf (buffer, "BNE $%04X", pc + offset); + break; + case 0x0300: case 0x0340: case 0x0380: case 0x03c0: + offset = 2 * (INT8)(op & 0xff); + sprintf (buffer, "BEQ $%04X", pc + offset); + break; + case 0x0400: case 0x0440: case 0x0480: case 0x04c0: + offset = 2 * (INT8)(op & 0xff); + sprintf (buffer, "BGE $%04X", pc + offset); + break; + case 0x0500: case 0x0540: case 0x0580: case 0x05c0: + offset = 2 * (INT8)(op & 0xff); + sprintf (buffer, "BLT $%04X", pc + offset); + break; + case 0x0600: case 0x0640: case 0x0680: case 0x06c0: + offset = 2 * (INT8)(op & 0xff); + sprintf (buffer, "BGT $%04X", pc + offset); + break; + case 0x0700: case 0x0740: case 0x0780: case 0x07c0: + offset = 2 * (INT8)(op & 0xff); + sprintf (buffer, "BLE $%04X", pc + offset); + break; + case 0x0800: case 0x0840: case 0x0880: case 0x08c0: + case 0x0900: case 0x0940: case 0x0980: case 0x09c0: + pc = MakeEA (ea1, lo, pc, 4); + if ( (hi & 7) == 7 ) + sprintf (buffer, "JSR %s", ea1); + else + sprintf (buffer, "JSR %s,%s", regs[hi & 7], ea1); + flags = DASMFLAG_STEP_OVER; + break; + case 0x0a00: + pc = MakeEA (ea1, lo, pc, 4); + sprintf (buffer, "CLR %s", ea1); + break; + case 0x0a40: + pc = MakeEA (ea1, lo, pc, 4); + sprintf (buffer, "COM %s", ea1); + break; + case 0x0a80: + pc = MakeEA (ea1, lo, pc, 4); + sprintf (buffer, "INC %s", ea1); + break; + case 0x0ac0: + pc = MakeEA (ea1, lo, pc, 4); + sprintf (buffer, "DEC %s", ea1); + break; + case 0x0b00: + pc = MakeEA (ea1, lo, pc, 4); + sprintf (buffer, "NEG %s", ea1); + break; + case 0x0b40: + pc = MakeEA (ea1, lo, pc, 4); + sprintf (buffer, "ADC %s", ea1); + break; + case 0x0b80: + pc = MakeEA (ea1, lo, pc, 4); + sprintf (buffer, "SBC %s", ea1); + break; + case 0x0bc0: + pc = MakeEA (ea1, lo, pc, 4); + sprintf (buffer, "TST %s", ea1); + break; + case 0x0c00: + pc = MakeEA (ea1, lo, pc, 4); + sprintf (buffer, "ROR %s", ea1); + break; + case 0x0c40: + pc = MakeEA (ea1, lo, pc, 4); + sprintf (buffer, "ROL %s", ea1); + break; + case 0x0c80: + pc = MakeEA (ea1, lo, pc, 4); + sprintf (buffer, "ASR %s", ea1); + break; + case 0x0cc0: + pc = MakeEA (ea1, lo, pc, 4); + sprintf (buffer, "ASL %s", ea1); + break; +/* case 0x0d00: + sprintf (buffer, "MARK #$%X", lo); + break;*/ + case 0x0dc0: + pc = MakeEA (ea1, lo, pc, 4); + sprintf (buffer, "SXT %s", ea1); + break; + case 0x1000: case 0x1040: case 0x1080: case 0x10c0: case 0x1100: case 0x1140: case 0x1180: case 0x11c0: + case 0x1200: case 0x1240: case 0x1280: case 0x12c0: case 0x1300: case 0x1340: case 0x1380: case 0x13c0: + case 0x1400: case 0x1440: case 0x1480: case 0x14c0: case 0x1500: case 0x1540: case 0x1580: case 0x15c0: + case 0x1600: case 0x1640: case 0x1680: case 0x16c0: case 0x1700: case 0x1740: case 0x1780: case 0x17c0: + case 0x1800: case 0x1840: case 0x1880: case 0x18c0: case 0x1900: case 0x1940: case 0x1980: case 0x19c0: + case 0x1a00: case 0x1a40: case 0x1a80: case 0x1ac0: case 0x1b00: case 0x1b40: case 0x1b80: case 0x1bc0: + case 0x1c00: case 0x1c40: case 0x1c80: case 0x1cc0: case 0x1d00: case 0x1d40: case 0x1d80: case 0x1dc0: + case 0x1e00: case 0x1e40: case 0x1e80: case 0x1ec0: case 0x1f00: case 0x1f40: case 0x1f80: case 0x1fc0: + pc = MakeEA (ea1, hi, pc, 4); + pc = MakeEA (ea2, lo, pc, 4); + if (lo == 046) /* MOV src,-(SP) */ + sprintf (buffer, "PUSH %s", ea1); + else + if (hi == 026) /* MOV (SP)+,buffer */ + sprintf (buffer, "POP %s", ea2); + else /* all other */ + sprintf (buffer, "MOV %s,%s", ea1, ea2); + break; + case 0x2000: case 0x2040: case 0x2080: case 0x20c0: case 0x2100: case 0x2140: case 0x2180: case 0x21c0: + case 0x2200: case 0x2240: case 0x2280: case 0x22c0: case 0x2300: case 0x2340: case 0x2380: case 0x23c0: + case 0x2400: case 0x2440: case 0x2480: case 0x24c0: case 0x2500: case 0x2540: case 0x2580: case 0x25c0: + case 0x2600: case 0x2640: case 0x2680: case 0x26c0: case 0x2700: case 0x2740: case 0x2780: case 0x27c0: + case 0x2800: case 0x2840: case 0x2880: case 0x28c0: case 0x2900: case 0x2940: case 0x2980: case 0x29c0: + case 0x2a00: case 0x2a40: case 0x2a80: case 0x2ac0: case 0x2b00: case 0x2b40: case 0x2b80: case 0x2bc0: + case 0x2c00: case 0x2c40: case 0x2c80: case 0x2cc0: case 0x2d00: case 0x2d40: case 0x2d80: case 0x2dc0: + case 0x2e00: case 0x2e40: case 0x2e80: case 0x2ec0: case 0x2f00: case 0x2f40: case 0x2f80: case 0x2fc0: + pc = MakeEA (ea1, hi, pc, 4); + pc = MakeEA (ea2, lo, pc, 4); + sprintf (buffer, "CMP %s,%s", ea1, ea2); + break; + case 0x3000: case 0x3040: case 0x3080: case 0x30c0: case 0x3100: case 0x3140: case 0x3180: case 0x31c0: + case 0x3200: case 0x3240: case 0x3280: case 0x32c0: case 0x3300: case 0x3340: case 0x3380: case 0x33c0: + case 0x3400: case 0x3440: case 0x3480: case 0x34c0: case 0x3500: case 0x3540: case 0x3580: case 0x35c0: + case 0x3600: case 0x3640: case 0x3680: case 0x36c0: case 0x3700: case 0x3740: case 0x3780: case 0x37c0: + case 0x3800: case 0x3840: case 0x3880: case 0x38c0: case 0x3900: case 0x3940: case 0x3980: case 0x39c0: + case 0x3a00: case 0x3a40: case 0x3a80: case 0x3ac0: case 0x3b00: case 0x3b40: case 0x3b80: case 0x3bc0: + case 0x3c00: case 0x3c40: case 0x3c80: case 0x3cc0: case 0x3d00: case 0x3d40: case 0x3d80: case 0x3dc0: + case 0x3e00: case 0x3e40: case 0x3e80: case 0x3ec0: case 0x3f00: case 0x3f40: case 0x3f80: case 0x3fc0: + pc = MakeEA (ea1, hi, pc, 4); + pc = MakeEA (ea2, lo, pc, 4); + sprintf (buffer, "BIT %s,%s", ea1, ea2); + break; + case 0x4000: case 0x4040: case 0x4080: case 0x40c0: case 0x4100: case 0x4140: case 0x4180: case 0x41c0: + case 0x4200: case 0x4240: case 0x4280: case 0x42c0: case 0x4300: case 0x4340: case 0x4380: case 0x43c0: + case 0x4400: case 0x4440: case 0x4480: case 0x44c0: case 0x4500: case 0x4540: case 0x4580: case 0x45c0: + case 0x4600: case 0x4640: case 0x4680: case 0x46c0: case 0x4700: case 0x4740: case 0x4780: case 0x47c0: + case 0x4800: case 0x4840: case 0x4880: case 0x48c0: case 0x4900: case 0x4940: case 0x4980: case 0x49c0: + case 0x4a00: case 0x4a40: case 0x4a80: case 0x4ac0: case 0x4b00: case 0x4b40: case 0x4b80: case 0x4bc0: + case 0x4c00: case 0x4c40: case 0x4c80: case 0x4cc0: case 0x4d00: case 0x4d40: case 0x4d80: case 0x4dc0: + case 0x4e00: case 0x4e40: case 0x4e80: case 0x4ec0: case 0x4f00: case 0x4f40: case 0x4f80: case 0x4fc0: + pc = MakeEA (ea1, hi, pc, 4); + pc = MakeEA (ea2, lo, pc, 4); + sprintf (buffer, "BIC %s,%s", ea1, ea2); + break; + case 0x5000: case 0x5040: case 0x5080: case 0x50c0: case 0x5100: case 0x5140: case 0x5180: case 0x51c0: + case 0x5200: case 0x5240: case 0x5280: case 0x52c0: case 0x5300: case 0x5340: case 0x5380: case 0x53c0: + case 0x5400: case 0x5440: case 0x5480: case 0x54c0: case 0x5500: case 0x5540: case 0x5580: case 0x55c0: + case 0x5600: case 0x5640: case 0x5680: case 0x56c0: case 0x5700: case 0x5740: case 0x5780: case 0x57c0: + case 0x5800: case 0x5840: case 0x5880: case 0x58c0: case 0x5900: case 0x5940: case 0x5980: case 0x59c0: + case 0x5a00: case 0x5a40: case 0x5a80: case 0x5ac0: case 0x5b00: case 0x5b40: case 0x5b80: case 0x5bc0: + case 0x5c00: case 0x5c40: case 0x5c80: case 0x5cc0: case 0x5d00: case 0x5d40: case 0x5d80: case 0x5dc0: + case 0x5e00: case 0x5e40: case 0x5e80: case 0x5ec0: case 0x5f00: case 0x5f40: case 0x5f80: case 0x5fc0: + pc = MakeEA (ea1, hi, pc, 4); + pc = MakeEA (ea2, lo, pc, 4); + sprintf (buffer, "BIS %s,%s", ea1, ea2); + break; + case 0x6000: case 0x6040: case 0x6080: case 0x60c0: case 0x6100: case 0x6140: case 0x6180: case 0x61c0: + case 0x6200: case 0x6240: case 0x6280: case 0x62c0: case 0x6300: case 0x6340: case 0x6380: case 0x63c0: + case 0x6400: case 0x6440: case 0x6480: case 0x64c0: case 0x6500: case 0x6540: case 0x6580: case 0x65c0: + case 0x6600: case 0x6640: case 0x6680: case 0x66c0: case 0x6700: case 0x6740: case 0x6780: case 0x67c0: + case 0x6800: case 0x6840: case 0x6880: case 0x68c0: case 0x6900: case 0x6940: case 0x6980: case 0x69c0: + case 0x6a00: case 0x6a40: case 0x6a80: case 0x6ac0: case 0x6b00: case 0x6b40: case 0x6b80: case 0x6bc0: + case 0x6c00: case 0x6c40: case 0x6c80: case 0x6cc0: case 0x6d00: case 0x6d40: case 0x6d80: case 0x6dc0: + case 0x6e00: case 0x6e40: case 0x6e80: case 0x6ec0: case 0x6f00: case 0x6f40: case 0x6f80: case 0x6fc0: + pc = MakeEA (ea1, hi, pc, 4); + pc = MakeEA (ea2, lo, pc, 4); + sprintf (buffer, "ADD %s,%s", ea1, ea2); + break; + + case 0x7800: case 0x7840: case 0x7880: case 0x78c0: case 0x7900: case 0x7940: case 0x7980: case 0x79c0: + pc = MakeEA (ea1, lo, pc, 4); + sprintf (buffer, "XOR %s,%s", regs[hi & 7], ea1); + break; + + case 0x7e00: case 0x7e40: case 0x7e80: case 0x7ec0: case 0x7f00: case 0x7f40: case 0x7f80: case 0x7fc0: + addr = (pc + 2 - 2 * lo) & 0xffff; + sprintf (buffer, "SOB %s,$%X", regs[hi & 7], addr); + break; + + case 0x8000: case 0x8040: case 0x8080: case 0x80c0: + offset = 2 * (INT8)(op & 0xff); + sprintf (buffer, "BPL $%04X", pc + offset); + break; + case 0x8100: case 0x8140: case 0x8180: case 0x81c0: + offset = 2 * (INT8)(op & 0xff); + sprintf (buffer, "BMI $%04X", pc + offset); + break; + case 0x8200: case 0x8240: case 0x8280: case 0x82c0: + offset = 2 * (INT8)(op & 0xff); + sprintf (buffer, "BHI $%04X", pc + offset); + break; + case 0x8300: case 0x8340: case 0x8380: case 0x83c0: + offset = 2 * (INT8)(op & 0xff); + sprintf (buffer, "BLOS $%04X", pc + offset); + break; + case 0x8400: case 0x8440: case 0x8480: case 0x84c0: + offset = 2 * (INT8)(op & 0xff); + sprintf (buffer, "BVC $%04X", pc + offset); + break; + case 0x8500: case 0x8540: case 0x8580: case 0x85c0: + offset = 2 * (INT8)(op & 0xff); + sprintf (buffer, "BVS $%04X", pc + offset); + break; + case 0x8600: case 0x8640: case 0x8680: case 0x86c0: + offset = 2 * (INT8)(op & 0xff); + sprintf (buffer, "BCC $%04X", pc + offset); + break; + case 0x8700: case 0x8740: case 0x8780: case 0x87c0: + offset = 2 * (INT8)(op & 0xff); + sprintf (buffer, "BCS $%04X", pc + offset); + break; + case 0x8800: case 0x8840: case 0x8880: case 0x88c0: + sprintf (buffer, "EMT #$%02X", op & 0xff); + break; + case 0x8900: case 0x8940: case 0x8980: case 0x89c0: + sprintf (buffer, "TRAP #$%02X", op & 0xff); + break; + + case 0x8a00: + pc = MakeEA (ea1, lo, pc, 2); + sprintf (buffer, "CLRB %s", ea1); + break; + case 0x8a40: + pc = MakeEA (ea1, lo, pc, 2); + sprintf (buffer, "COMB %s", ea1); + break; + case 0x8a80: + pc = MakeEA (ea1, lo, pc, 2); + sprintf (buffer, "INCB %s", ea1); + break; + case 0x8ac0: + pc = MakeEA (ea1, lo, pc, 2); + sprintf (buffer, "DECB %s", ea1); + break; + case 0x8b00: + pc = MakeEA (ea1, lo, pc, 2); + sprintf (buffer, "NEGB %s", ea1); + break; + case 0x8b40: + pc = MakeEA (ea1, lo, pc, 2); + sprintf (buffer, "ADCB %s", ea1); + break; + case 0x8b80: + pc = MakeEA (ea1, lo, pc, 2); + sprintf (buffer, "SBCB %s", ea1); + break; + case 0x8bc0: + pc = MakeEA (ea1, lo, pc, 2); + sprintf (buffer, "TSTB %s", ea1); + break; + case 0x8c00: + pc = MakeEA (ea1, lo, pc, 2); + sprintf (buffer, "RORB %s", ea1); + break; + case 0x8c40: + pc = MakeEA (ea1, lo, pc, 2); + sprintf (buffer, "ROLB %s", ea1); + break; + case 0x8c80: + pc = MakeEA (ea1, lo, pc, 2); + sprintf (buffer, "ASRB %s", ea1); + break; + case 0x8cc0: + pc = MakeEA (ea1, lo, pc, 2); + sprintf (buffer, "ASLB %s", ea1); + break; + case 0x8d00: + pc = MakeEA (ea1, lo, pc, 2); + sprintf (buffer, "MTPS %s", ea1); + break; + case 0x8dc0: + pc = MakeEA (ea1, lo, pc, 2); + sprintf (buffer, "MFPS %s", ea1); + break; + case 0x9000: case 0x9040: case 0x9080: case 0x90c0: case 0x9100: case 0x9140: case 0x9180: case 0x91c0: + case 0x9200: case 0x9240: case 0x9280: case 0x92c0: case 0x9300: case 0x9340: case 0x9380: case 0x93c0: + case 0x9400: case 0x9440: case 0x9480: case 0x94c0: case 0x9500: case 0x9540: case 0x9580: case 0x95c0: + case 0x9600: case 0x9640: case 0x9680: case 0x96c0: case 0x9700: case 0x9740: case 0x9780: case 0x97c0: + case 0x9800: case 0x9840: case 0x9880: case 0x98c0: case 0x9900: case 0x9940: case 0x9980: case 0x99c0: + case 0x9a00: case 0x9a40: case 0x9a80: case 0x9ac0: case 0x9b00: case 0x9b40: case 0x9b80: case 0x9bc0: + case 0x9c00: case 0x9c40: case 0x9c80: case 0x9cc0: case 0x9d00: case 0x9d40: case 0x9d80: case 0x9dc0: + case 0x9e00: case 0x9e40: case 0x9e80: case 0x9ec0: case 0x9f00: case 0x9f40: case 0x9f80: case 0x9fc0: + pc = MakeEA (ea1, hi, pc, 2); + pc = MakeEA (ea2, lo, pc, 2); + sprintf (buffer, "MOVB %s,%s", ea1, ea2); + break; + case 0xa000: case 0xa040: case 0xa080: case 0xa0c0: case 0xa100: case 0xa140: case 0xa180: case 0xa1c0: + case 0xa200: case 0xa240: case 0xa280: case 0xa2c0: case 0xa300: case 0xa340: case 0xa380: case 0xa3c0: + case 0xa400: case 0xa440: case 0xa480: case 0xa4c0: case 0xa500: case 0xa540: case 0xa580: case 0xa5c0: + case 0xa600: case 0xa640: case 0xa680: case 0xa6c0: case 0xa700: case 0xa740: case 0xa780: case 0xa7c0: + case 0xa800: case 0xa840: case 0xa880: case 0xa8c0: case 0xa900: case 0xa940: case 0xa980: case 0xa9c0: + case 0xaa00: case 0xaa40: case 0xaa80: case 0xaac0: case 0xab00: case 0xab40: case 0xab80: case 0xabc0: + case 0xac00: case 0xac40: case 0xac80: case 0xacc0: case 0xad00: case 0xad40: case 0xad80: case 0xadc0: + case 0xae00: case 0xae40: case 0xae80: case 0xaec0: case 0xaf00: case 0xaf40: case 0xaf80: case 0xafc0: + pc = MakeEA (ea1, hi, pc, 2); + pc = MakeEA (ea2, lo, pc, 2); + sprintf (buffer, "CMPB %s,%s", ea1, ea2); + break; + case 0xb000: case 0xb040: case 0xb080: case 0xb0c0: case 0xb100: case 0xb140: case 0xb180: case 0xb1c0: + case 0xb200: case 0xb240: case 0xb280: case 0xb2c0: case 0xb300: case 0xb340: case 0xb380: case 0xb3c0: + case 0xb400: case 0xb440: case 0xb480: case 0xb4c0: case 0xb500: case 0xb540: case 0xb580: case 0xb5c0: + case 0xb600: case 0xb640: case 0xb680: case 0xb6c0: case 0xb700: case 0xb740: case 0xb780: case 0xb7c0: + case 0xb800: case 0xb840: case 0xb880: case 0xb8c0: case 0xb900: case 0xb940: case 0xb980: case 0xb9c0: + case 0xba00: case 0xba40: case 0xba80: case 0xbac0: case 0xbb00: case 0xbb40: case 0xbb80: case 0xbbc0: + case 0xbc00: case 0xbc40: case 0xbc80: case 0xbcc0: case 0xbd00: case 0xbd40: case 0xbd80: case 0xbdc0: + case 0xbe00: case 0xbe40: case 0xbe80: case 0xbec0: case 0xbf00: case 0xbf40: case 0xbf80: case 0xbfc0: + pc = MakeEA (ea1, hi, pc, 2); + pc = MakeEA (ea2, lo, pc, 2); + sprintf (buffer, "BITB %s,%s", ea1, ea2); + break; + case 0xc000: case 0xc040: case 0xc080: case 0xc0c0: case 0xc100: case 0xc140: case 0xc180: case 0xc1c0: + case 0xc200: case 0xc240: case 0xc280: case 0xc2c0: case 0xc300: case 0xc340: case 0xc380: case 0xc3c0: + case 0xc400: case 0xc440: case 0xc480: case 0xc4c0: case 0xc500: case 0xc540: case 0xc580: case 0xc5c0: + case 0xc600: case 0xc640: case 0xc680: case 0xc6c0: case 0xc700: case 0xc740: case 0xc780: case 0xc7c0: + case 0xc800: case 0xc840: case 0xc880: case 0xc8c0: case 0xc900: case 0xc940: case 0xc980: case 0xc9c0: + case 0xca00: case 0xca40: case 0xca80: case 0xcac0: case 0xcb00: case 0xcb40: case 0xcb80: case 0xcbc0: + case 0xcc00: case 0xcc40: case 0xcc80: case 0xccc0: case 0xcd00: case 0xcd40: case 0xcd80: case 0xcdc0: + case 0xce00: case 0xce40: case 0xce80: case 0xcec0: case 0xcf00: case 0xcf40: case 0xcf80: case 0xcfc0: + pc = MakeEA (ea1, hi, pc, 2); + pc = MakeEA (ea2, lo, pc, 2); + sprintf (buffer, "BICB %s,%s", ea1, ea2); + break; + case 0xd000: case 0xd040: case 0xd080: case 0xd0c0: case 0xd100: case 0xd140: case 0xd180: case 0xd1c0: + case 0xd200: case 0xd240: case 0xd280: case 0xd2c0: case 0xd300: case 0xd340: case 0xd380: case 0xd3c0: + case 0xd400: case 0xd440: case 0xd480: case 0xd4c0: case 0xd500: case 0xd540: case 0xd580: case 0xd5c0: + case 0xd600: case 0xd640: case 0xd680: case 0xd6c0: case 0xd700: case 0xd740: case 0xd780: case 0xd7c0: + case 0xd800: case 0xd840: case 0xd880: case 0xd8c0: case 0xd900: case 0xd940: case 0xd980: case 0xd9c0: + case 0xda00: case 0xda40: case 0xda80: case 0xdac0: case 0xdb00: case 0xdb40: case 0xdb80: case 0xdbc0: + case 0xdc00: case 0xdc40: case 0xdc80: case 0xdcc0: case 0xdd00: case 0xdd40: case 0xdd80: case 0xddc0: + case 0xde00: case 0xde40: case 0xde80: case 0xdec0: case 0xdf00: case 0xdf40: case 0xdf80: case 0xdfc0: + pc = MakeEA (ea1, hi, pc, 2); + pc = MakeEA (ea2, lo, pc, 2); + sprintf (buffer, "BISB %s,%s", ea1, ea2); + break; + case 0xe000: case 0xe040: case 0xe080: case 0xe0c0: case 0xe100: case 0xe140: case 0xe180: case 0xe1c0: + case 0xe200: case 0xe240: case 0xe280: case 0xe2c0: case 0xe300: case 0xe340: case 0xe380: case 0xe3c0: + case 0xe400: case 0xe440: case 0xe480: case 0xe4c0: case 0xe500: case 0xe540: case 0xe580: case 0xe5c0: + case 0xe600: case 0xe640: case 0xe680: case 0xe6c0: case 0xe700: case 0xe740: case 0xe780: case 0xe7c0: + case 0xe800: case 0xe840: case 0xe880: case 0xe8c0: case 0xe900: case 0xe940: case 0xe980: case 0xe9c0: + case 0xea00: case 0xea40: case 0xea80: case 0xeac0: case 0xeb00: case 0xeb40: case 0xeb80: case 0xebc0: + case 0xec00: case 0xec40: case 0xec80: case 0xecc0: case 0xed00: case 0xed40: case 0xed80: case 0xedc0: + case 0xee00: case 0xee40: case 0xee80: case 0xeec0: case 0xef00: case 0xef40: case 0xef80: case 0xefc0: + pc = MakeEA (ea1, hi, pc, 4); + pc = MakeEA (ea2, lo, pc, 4); + sprintf (buffer, "SUB %s,%s", ea1, ea2); + break; + + default: + sprintf (buffer, "???? (%06o)", op); + break; + } + + return (pc - PC) | flags | DASMFLAG_SUPPORTED; +} diff --git a/src/devices/cpu/t11/t11ops.inc b/src/devices/cpu/t11/t11ops.inc new file mode 100644 index 00000000000..223159a9357 --- /dev/null +++ b/src/devices/cpu/t11/t11ops.inc @@ -0,0 +1,1414 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*** t11: Portable DEC T-11 emulator ****************************************** + + Actual opcode implementation. Excuse the excessive use of macros, it + was the only way I could bear to type all this in! + +*****************************************************************************/ + + +/* given a register index 'r', this computes the effective address for a byte-sized operation + and puts the result in 'ea' */ +#define MAKE_EAB_RGD(r) ea = REGD(r) +#define MAKE_EAB_IN(r) ea = REGD(r); REGW(r) += ((r) < 6 ? 1 : 2) +#define MAKE_EAB_INS(r) ea = REGD(r); REGW(r) += ((r) < 6 ? 1 : 2) +#define MAKE_EAB_IND(r) ea = REGD(r); REGW(r) += 2; ea = RWORD(ea) +#define MAKE_EAB_DE(r) REGW(r) -= ((r) < 6 ? 1 : 2); ea = REGD(r) +#define MAKE_EAB_DED(r) REGW(r) -= 2; ea = REGD(r); ea = RWORD(ea) +#define MAKE_EAB_IX(r) ea = ROPCODE(); ea = (ea + REGD(r)) & 0xffff +#define MAKE_EAB_IXD(r) ea = ROPCODE(); ea = (ea + REGD(r)) & 0xffff; ea = RWORD(ea) + +/* given a register index 'r', this computes the effective address for a word-sized operation + and puts the result in 'ea' */ +/* note that word accesses ignore the low bit!! this fixes APB! */ +#define MAKE_EAW_RGD(r) MAKE_EAB_RGD(r) +#define MAKE_EAW_IN(r) ea = REGD(r); REGW(r) += 2 +#define MAKE_EAW_IND(r) MAKE_EAB_IND(r) +#define MAKE_EAW_DE(r) REGW(r) -= 2; ea = REGD(r) +#define MAKE_EAW_DED(r) MAKE_EAB_DED(r) +#define MAKE_EAW_IX(r) MAKE_EAB_IX(r) +#define MAKE_EAW_IXD(r) MAKE_EAB_IXD(r) + +/* extracts the source/destination register index from the opcode into 'sreg' or 'dreg' */ +#define GET_SREG sreg = (op >> 6) & 7 +#define GET_DREG dreg = op & 7 + +/* for a byte-sized source operand: extracts 'sreg', computes 'ea', and loads the value into 'source' */ +#define GET_SB_RG GET_SREG; source = REGB(sreg) +#define GET_SB_RGD GET_SREG; MAKE_EAB_RGD(sreg); source = RBYTE(ea) +#define GET_SB_IN GET_SREG; if (sreg == 7) { source = ROPCODE(); } else { MAKE_EAB_IN(sreg); source = RBYTE(ea); } +#define GET_SB_IND GET_SREG; if (sreg == 7) { ea = ROPCODE(); } else { MAKE_EAB_IND(sreg); } source = RBYTE(ea) +#define GET_SB_DE GET_SREG; MAKE_EAB_DE(sreg); source = RBYTE(ea) +#define GET_SB_DED GET_SREG; MAKE_EAB_DED(sreg); source = RBYTE(ea) +#define GET_SB_IX GET_SREG; MAKE_EAB_IX(sreg); source = RBYTE(ea) +#define GET_SB_IXD GET_SREG; MAKE_EAB_IXD(sreg); source = RBYTE(ea) + +/* for a word-sized source operand: extracts 'sreg', computes 'ea', and loads the value into 'source' */ +#define GET_SW_RG GET_SREG; source = REGD(sreg) +#define GET_SW_RGD GET_SREG; MAKE_EAW_RGD(sreg); source = RWORD(ea) +#define GET_SW_IN GET_SREG; if (sreg == 7) { source = ROPCODE(); } else { MAKE_EAW_IN(sreg); source = RWORD(ea); } +#define GET_SW_IND GET_SREG; if (sreg == 7) { ea = ROPCODE(); } else { MAKE_EAW_IND(sreg); } source = RWORD(ea) +#define GET_SW_DE GET_SREG; MAKE_EAW_DE(sreg); source = RWORD(ea) +#define GET_SW_DED GET_SREG; MAKE_EAW_DED(sreg); source = RWORD(ea) +#define GET_SW_IX GET_SREG; MAKE_EAW_IX(sreg); source = RWORD(ea) +#define GET_SW_IXD GET_SREG; MAKE_EAW_IXD(sreg); source = RWORD(ea) + +/* for a byte-sized destination operand: extracts 'dreg', computes 'ea', and loads the value into 'dest' */ +#define GET_DB_RG GET_DREG; dest = REGB(dreg) +#define GET_DB_RGD GET_DREG; MAKE_EAB_RGD(dreg); dest = RBYTE(ea) +#define GET_DB_IN GET_DREG; MAKE_EAB_IN(dreg); dest = RBYTE(ea) +#define GET_DB_IND GET_DREG; if (dreg == 7) { ea = ROPCODE(); } else { MAKE_EAB_IND(dreg); } dest = RBYTE(ea) +#define GET_DB_DE GET_DREG; MAKE_EAB_DE(dreg); dest = RBYTE(ea) +#define GET_DB_DED GET_DREG; MAKE_EAB_DED(dreg); dest = RBYTE(ea) +#define GET_DB_IX GET_DREG; MAKE_EAB_IX(dreg); dest = RBYTE(ea) +#define GET_DB_IXD GET_DREG; MAKE_EAB_IXD(dreg); dest = RBYTE(ea) + +/* for a word-sized destination operand: extracts 'dreg', computes 'ea', and loads the value into 'dest' */ +#define GET_DW_RG GET_DREG; dest = REGD(dreg) +#define GET_DW_RGD GET_DREG; MAKE_EAW_RGD(dreg); dest = RWORD(ea) +#define GET_DW_IN GET_DREG; MAKE_EAW_IN(dreg); dest = RWORD(ea) +#define GET_DW_IND GET_DREG; if (dreg == 7) { ea = ROPCODE(); } else { MAKE_EAW_IND(dreg); } dest = RWORD(ea) +#define GET_DW_DE GET_DREG; MAKE_EAW_DE(dreg); dest = RWORD(ea) +#define GET_DW_DED GET_DREG; MAKE_EAW_DED(dreg); dest = RWORD(ea) +#define GET_DW_IX GET_DREG; MAKE_EAW_IX(dreg); dest = RWORD(ea) +#define GET_DW_IXD GET_DREG; MAKE_EAW_IXD(dreg); dest = RWORD(ea) + +/* writes a value to a previously computed 'ea' */ +#define PUT_DB_EA(v) WBYTE(ea, (v)) +#define PUT_DW_EA(v) WWORD(ea, (v)) + +/* writes a value to a previously computed 'dreg' register */ +#define PUT_DB_DREG(v) REGB(dreg) = (v) +#define PUT_DW_DREG(v) REGW(dreg) = (v) + +/* for a byte-sized destination operand: extracts 'dreg', computes 'ea', and writes 'v' to it */ +#define PUT_DB_RG(v) GET_DREG; REGB(dreg) = (v) +#define PUT_DB_RGD(v) GET_DREG; MAKE_EAB_RGD(dreg); WBYTE(ea, (v)) +#define PUT_DB_IN(v) GET_DREG; MAKE_EAB_IN(dreg); WBYTE(ea, (v)) +#define PUT_DB_IND(v) GET_DREG; if (dreg == 7) { ea = ROPCODE(); } else { MAKE_EAB_IND(dreg); } WBYTE(ea, (v)) +#define PUT_DB_DE(v) GET_DREG; MAKE_EAB_DE(dreg); WBYTE(ea, (v)) +#define PUT_DB_DED(v) GET_DREG; MAKE_EAB_DED(dreg); WBYTE(ea, (v)) +#define PUT_DB_IX(v) GET_DREG; MAKE_EAB_IX(dreg); WBYTE(ea, (v)) +#define PUT_DB_IXD(v) GET_DREG; MAKE_EAB_IXD(dreg); WBYTE(ea, (v)) + +/* for a word-sized destination operand: extracts 'dreg', computes 'ea', and writes 'v' to it */ +#define PUT_DW_RG(v) GET_DREG; REGW(dreg) = (v) +#define PUT_DW_RGD(v) GET_DREG; MAKE_EAW_RGD(dreg); WWORD(ea, (v)) +#define PUT_DW_IN(v) GET_DREG; MAKE_EAW_IN(dreg); WWORD(ea, (v)) +#define PUT_DW_IND(v) GET_DREG; if (dreg == 7) { ea = ROPCODE(); } else { MAKE_EAW_IND(dreg); } WWORD(ea, (v)) +#define PUT_DW_DE(v) GET_DREG; MAKE_EAW_DE(dreg); WWORD(ea, (v)) +#define PUT_DW_DED(v) GET_DREG; MAKE_EAW_DED(dreg); WWORD(ea, (v)) +#define PUT_DW_IX(v) GET_DREG; MAKE_EAW_IX(dreg); WWORD(ea, (v)) +#define PUT_DW_IXD(v) GET_DREG; MAKE_EAW_IXD(dreg); WWORD(ea, (v)) + +/* flag clearing; must be done before setting */ +#define CLR_ZV (PSW &= ~(ZFLAG | VFLAG)) +#define CLR_NZV (PSW &= ~(NFLAG | ZFLAG | VFLAG)) +#define CLR_NZVC (PSW &= ~(NFLAG | ZFLAG | VFLAG | CFLAG)) + +/* set individual flags byte-sized */ +#define SETB_N (PSW |= (result >> 4) & 0x08) +#define SETB_Z (PSW |= ((result & 0xff) == 0) << 2) +#define SETB_V (PSW |= ((source ^ dest ^ result ^ (result >> 1)) >> 6) & 0x02) +#define SETB_C (PSW |= (result >> 8) & 0x01) +#define SETB_NZ SETB_N; SETB_Z +#define SETB_NZV SETB_N; SETB_Z; SETB_V +#define SETB_NZVC SETB_N; SETB_Z; SETB_V; SETB_C + +/* set individual flags word-sized */ +#define SETW_N (PSW |= (result >> 12) & 0x08) +#define SETW_Z (PSW |= ((result & 0xffff) == 0) << 2) +#define SETW_V (PSW |= ((source ^ dest ^ result ^ (result >> 1)) >> 14) & 0x02) +#define SETW_C (PSW |= (result >> 16) & 0x01) +#define SETW_NZ SETW_N; SETW_Z +#define SETW_NZV SETW_N; SETW_Z; SETW_V +#define SETW_NZVC SETW_N; SETW_Z; SETW_V; SETW_C + +/* operations */ +/* ADC: dst += C */ +#define ADC_R(d) int dreg, source, dest, result; source = GET_C; GET_DW_##d; CLR_NZVC; result = dest + source; SETW_NZVC; PUT_DW_DREG(result) +#define ADC_M(d) int dreg, source, dest, result, ea; source = GET_C; GET_DW_##d; CLR_NZVC; result = dest + source; SETW_NZVC; PUT_DW_EA(result) +#define ADCB_R(d) int dreg, source, dest, result; source = GET_C; GET_DB_##d; CLR_NZVC; result = dest + source; SETB_NZVC; PUT_DB_DREG(result) +#define ADCB_M(d) int dreg, source, dest, result, ea; source = GET_C; GET_DB_##d; CLR_NZVC; result = dest + source; SETB_NZVC; PUT_DB_EA(result) +/* ADD: dst += src */ +#define ADD_R(s,d) int sreg, dreg, source, dest, result; GET_SW_##s; GET_DW_##d; CLR_NZVC; result = dest + source; SETW_NZVC; PUT_DW_DREG(result) +#define ADD_X(s,d) int sreg, dreg, source, dest, result, ea; GET_SW_##s; GET_DW_##d; CLR_NZVC; result = dest + source; SETW_NZVC; PUT_DW_DREG(result) +#define ADD_M(s,d) int sreg, dreg, source, dest, result, ea; GET_SW_##s; GET_DW_##d; CLR_NZVC; result = dest + source; SETW_NZVC; PUT_DW_EA(result) +/* ASL: dst = (dst << 1); C = (dst >> 7) */ +#define ASL_R(d) int dreg, dest, result; GET_DW_##d; CLR_NZVC; result = dest << 1; SETW_NZ; PSW |= (dest >> 15) & 1; PSW |= ((PSW << 1) ^ (PSW >> 2)) & 2; PUT_DW_DREG(result) +#define ASL_M(d) int dreg, dest, result, ea; GET_DW_##d; CLR_NZVC; result = dest << 1; SETW_NZ; PSW |= (dest >> 15) & 1; PSW |= ((PSW << 1) ^ (PSW >> 2)) & 2; PUT_DW_EA(result) +#define ASLB_R(d) int dreg, dest, result; GET_DB_##d; CLR_NZVC; result = dest << 1; SETB_NZ; PSW |= (dest >> 7) & 1; PSW |= ((PSW << 1) ^ (PSW >> 2)) & 2; PUT_DB_DREG(result) +#define ASLB_M(d) int dreg, dest, result, ea; GET_DB_##d; CLR_NZVC; result = dest << 1; SETB_NZ; PSW |= (dest >> 7) & 1; PSW |= ((PSW << 1) ^ (PSW >> 2)) & 2; PUT_DB_EA(result) +/* ASR: dst = (dst << 1); C = (dst >> 7) */ +#define ASR_R(d) int dreg, dest, result; GET_DW_##d; CLR_NZVC; result = (dest >> 1) | (dest & 0x8000); SETW_NZ; PSW |= dest & 1; PSW |= ((PSW << 1) ^ (PSW >> 2)) & 2; PUT_DW_DREG(result) +#define ASR_M(d) int dreg, dest, result, ea; GET_DW_##d; CLR_NZVC; result = (dest >> 1) | (dest & 0x8000); SETW_NZ; PSW |= dest & 1; PSW |= ((PSW << 1) ^ (PSW >> 2)) & 2; PUT_DW_EA(result) +#define ASRB_R(d) int dreg, dest, result; GET_DB_##d; CLR_NZVC; result = (dest >> 1) | (dest & 0x80); SETB_NZ; PSW |= dest & 1; PSW |= ((PSW << 1) ^ (PSW >> 2)) & 2; PUT_DB_DREG(result) +#define ASRB_M(d) int dreg, dest, result, ea; GET_DB_##d; CLR_NZVC; result = (dest >> 1) | (dest & 0x80); SETB_NZ; PSW |= dest & 1; PSW |= ((PSW << 1) ^ (PSW >> 2)) & 2; PUT_DB_EA(result) +/* BIC: dst &= ~src */ +#define BIC_R(s,d) int sreg, dreg, source, dest, result; GET_SW_##s; GET_DW_##d; CLR_NZV; result = dest & ~source; SETW_NZ; PUT_DW_DREG(result) +#define BIC_X(s,d) int sreg, dreg, source, dest, result, ea; GET_SW_##s; GET_DW_##d; CLR_NZV; result = dest & ~source; SETW_NZ; PUT_DW_DREG(result) +#define BIC_M(s,d) int sreg, dreg, source, dest, result, ea; GET_SW_##s; GET_DW_##d; CLR_NZV; result = dest & ~source; SETW_NZ; PUT_DW_EA(result) +#define BICB_R(s,d) int sreg, dreg, source, dest, result; GET_SB_##s; GET_DB_##d; CLR_NZV; result = dest & ~source; SETB_NZ; PUT_DB_DREG(result) +#define BICB_X(s,d) int sreg, dreg, source, dest, result, ea; GET_SB_##s; GET_DB_##d; CLR_NZV; result = dest & ~source; SETB_NZ; PUT_DB_DREG(result) +#define BICB_M(s,d) int sreg, dreg, source, dest, result, ea; GET_SB_##s; GET_DB_##d; CLR_NZV; result = dest & ~source; SETB_NZ; PUT_DB_EA(result) +/* BIS: dst |= src */ +#define BIS_R(s,d) int sreg, dreg, source, dest, result; GET_SW_##s; GET_DW_##d; CLR_NZV; result = dest | source; SETW_NZ; PUT_DW_DREG(result) +#define BIS_X(s,d) int sreg, dreg, source, dest, result, ea; GET_SW_##s; GET_DW_##d; CLR_NZV; result = dest | source; SETW_NZ; PUT_DW_DREG(result) +#define BIS_M(s,d) int sreg, dreg, source, dest, result, ea; GET_SW_##s; GET_DW_##d; CLR_NZV; result = dest | source; SETW_NZ; PUT_DW_EA(result) +#define BISB_R(s,d) int sreg, dreg, source, dest, result; GET_SB_##s; GET_DB_##d; CLR_NZV; result = dest | source; SETB_NZ; PUT_DB_DREG(result) +#define BISB_X(s,d) int sreg, dreg, source, dest, result, ea; GET_SB_##s; GET_DB_##d; CLR_NZV; result = dest | source; SETB_NZ; PUT_DB_DREG(result) +#define BISB_M(s,d) int sreg, dreg, source, dest, result, ea; GET_SB_##s; GET_DB_##d; CLR_NZV; result = dest | source; SETB_NZ; PUT_DB_EA(result) +/* BIT: flags = dst & src */ +#define BIT_R(s,d) int sreg, dreg, source, dest, result; GET_SW_##s; GET_DW_##d; CLR_NZV; result = dest & source; SETW_NZ; +#define BIT_M(s,d) int sreg, dreg, source, dest, result, ea; GET_SW_##s; GET_DW_##d; CLR_NZV; result = dest & source; SETW_NZ; +#define BITB_R(s,d) int sreg, dreg, source, dest, result; GET_SB_##s; GET_DB_##d; CLR_NZV; result = dest & source; SETB_NZ; +#define BITB_M(s,d) int sreg, dreg, source, dest, result, ea; GET_SB_##s; GET_DB_##d; CLR_NZV; result = dest & source; SETB_NZ; +/* BR: if (condition) branch */ +#define BR(c) if (c) { PC += 2 * (signed char)(op & 0xff); } +/* CLR: dst = 0 */ +#define CLR_R(d) int dreg; PUT_DW_##d(0); CLR_NZVC; SET_Z +#define CLR_M(d) int dreg, ea; PUT_DW_##d(0); CLR_NZVC; SET_Z +#define CLRB_R(d) int dreg; PUT_DB_##d(0); CLR_NZVC; SET_Z +#define CLRB_M(d) int dreg, ea; PUT_DB_##d(0); CLR_NZVC; SET_Z +/* CMP: flags = src - dst */ +#define CMP_R(s,d) int sreg, dreg, source, dest, result; GET_SW_##s; GET_DW_##d; CLR_NZVC; result = source - dest; SETW_NZVC; +#define CMP_M(s,d) int sreg, dreg, source, dest, result, ea; GET_SW_##s; GET_DW_##d; CLR_NZVC; result = source - dest; SETW_NZVC; +#define CMPB_R(s,d) int sreg, dreg, source, dest, result; GET_SB_##s; GET_DB_##d; CLR_NZVC; result = source - dest; SETB_NZVC; +#define CMPB_M(s,d) int sreg, dreg, source, dest, result, ea; GET_SB_##s; GET_DB_##d; CLR_NZVC; result = source - dest; SETB_NZVC; +/* COM: dst = ~dst */ +#define COM_R(d) int dreg, dest, result; GET_DW_##d; CLR_NZVC; result = ~dest; SETW_NZ; SET_C; PUT_DW_DREG(result) +#define COM_M(d) int dreg, dest, result, ea; GET_DW_##d; CLR_NZVC; result = ~dest; SETW_NZ; SET_C; PUT_DW_EA(result) +#define COMB_R(d) int dreg, dest, result; GET_DB_##d; CLR_NZVC; result = ~dest; SETB_NZ; SET_C; PUT_DB_DREG(result) +#define COMB_M(d) int dreg, dest, result, ea; GET_DB_##d; CLR_NZVC; result = ~dest; SETB_NZ; SET_C; PUT_DB_EA(result) +/* DEC: dst -= 1 */ +#define DEC_R(d) int dreg, dest, result; GET_DW_##d; CLR_NZV; result = dest - 1; SETW_NZ; if (dest == 0x8000) SET_V; PUT_DW_DREG(result) +#define DEC_M(d) int dreg, dest, result, ea; GET_DW_##d; CLR_NZV; result = dest - 1; SETW_NZ; if (dest == 0x8000) SET_V; PUT_DW_EA(result) +#define DECB_R(d) int dreg, dest, result; GET_DB_##d; CLR_NZV; result = dest - 1; SETB_NZ; if (dest == 0x80) SET_V; PUT_DB_DREG(result) +#define DECB_M(d) int dreg, dest, result, ea; GET_DB_##d; CLR_NZV; result = dest - 1; SETB_NZ; if (dest == 0x80) SET_V; PUT_DB_EA(result) +/* INC: dst += 1 */ +#define INC_R(d) int dreg, dest, result; GET_DW_##d; CLR_NZV; result = dest + 1; SETW_NZ; if (dest == 0x7fff) SET_V; PUT_DW_DREG(result) +#define INC_M(d) int dreg, dest, result, ea; GET_DW_##d; CLR_NZV; result = dest + 1; SETW_NZ; if (dest == 0x7fff) SET_V; PUT_DW_EA(result) +#define INCB_R(d) int dreg, dest, result; GET_DB_##d; CLR_NZV; result = dest + 1; SETB_NZ; if (dest == 0x7f) SET_V; PUT_DB_DREG(result) +#define INCB_M(d) int dreg, dest, result, ea; GET_DB_##d; CLR_NZV; result = dest + 1; SETB_NZ; if (dest == 0x7f) SET_V; PUT_DB_EA(result) +/* JMP: PC = ea */ +#define JMP(d) int dreg, ea; GET_DREG; MAKE_EAW_##d(dreg); PC = ea +/* JSR: PUSH src, src = PC, PC = ea */ +#define JSR(d) int sreg, dreg, ea; GET_SREG; GET_DREG; MAKE_EAW_##d(dreg); PUSH(REGW(sreg)); REGW(sreg) = PC; PC = ea +/* MFPS: dst = flags */ +#define MFPS_R(d) int dreg, result; result = PSW; CLR_NZV; SETB_NZ; PUT_DW_##d((signed char)result) +#define MFPS_M(d) int dreg, result, ea; result = PSW; CLR_NZV; SETB_NZ; PUT_DB_##d(result) +/* MOV: dst = src */ +#define MOV_R(s,d) int sreg, dreg, source, result; GET_SW_##s; CLR_NZV; result = source; SETW_NZ; PUT_DW_##d(result) +#define MOV_M(s,d) int sreg, dreg, source, result, ea; GET_SW_##s; CLR_NZV; result = source; SETW_NZ; PUT_DW_##d(result) +#define MOVB_R(s,d) int sreg, dreg, source, result; GET_SB_##s; CLR_NZV; result = source; SETB_NZ; PUT_DW_##d((signed char)result) +#define MOVB_X(s,d) int sreg, dreg, source, result, ea; GET_SB_##s; CLR_NZV; result = source; SETB_NZ; PUT_DW_##d((signed char)result) +#define MOVB_M(s,d) int sreg, dreg, source, result, ea; GET_SB_##s; CLR_NZV; result = source; SETB_NZ; PUT_DB_##d(result) +/* MTPS: flags = src */ +#define MTPS_R(d) int dreg, dest; GET_DW_##d; PSW = (PSW & ~0xef) | (dest & 0xef); t11_check_irqs() +#define MTPS_M(d) int dreg, dest, ea; GET_DW_##d; PSW = (PSW & ~0xef) | (dest & 0xef); t11_check_irqs() +/* NEG: dst = -dst */ +#define NEG_R(d) int dreg, dest, result; GET_DW_##d; CLR_NZVC; result = -dest; SETW_NZ; if (dest == 0x8000) SET_V; if (result) SET_C; PUT_DW_DREG(result) +#define NEG_M(d) int dreg, dest, result, ea; GET_DW_##d; CLR_NZVC; result = -dest; SETW_NZ; if (dest == 0x8000) SET_V; if (result) SET_C; PUT_DW_EA(result) +#define NEGB_R(d) int dreg, dest, result; GET_DB_##d; CLR_NZVC; result = -dest; SETB_NZ; if (dest == 0x80) SET_V; if (result) SET_C; PUT_DB_DREG(result) +#define NEGB_M(d) int dreg, dest, result, ea; GET_DB_##d; CLR_NZVC; result = -dest; SETB_NZ; if (dest == 0x80) SET_V; if (result) SET_C; PUT_DB_EA(result) +/* ROL: dst = (dst << 1) | C; C = (dst >> 7) */ +#define ROL_R(d) int dreg, dest, result; GET_DW_##d; result = (dest << 1) | GET_C; CLR_NZVC; SETW_NZ; PSW |= (dest >> 15) & 1; PSW |= ((PSW << 1) ^ (PSW >> 2)) & 2; PUT_DW_DREG(result) +#define ROL_M(d) int dreg, dest, result, ea; GET_DW_##d; result = (dest << 1) | GET_C; CLR_NZVC; SETW_NZ; PSW |= (dest >> 15) & 1; PSW |= ((PSW << 1) ^ (PSW >> 2)) & 2; PUT_DW_EA(result) +#define ROLB_R(d) int dreg, dest, result; GET_DB_##d; result = (dest << 1) | GET_C; CLR_NZVC; SETB_NZ; PSW |= (dest >> 7) & 1; PSW |= ((PSW << 1) ^ (PSW >> 2)) & 2; PUT_DB_DREG(result) +#define ROLB_M(d) int dreg, dest, result, ea; GET_DB_##d; result = (dest << 1) | GET_C; CLR_NZVC; SETB_NZ; PSW |= (dest >> 7) & 1; PSW |= ((PSW << 1) ^ (PSW >> 2)) & 2; PUT_DB_EA(result) +/* ROR: dst = (dst >> 1) | (C << 7); C = dst & 1 */ +#define ROR_R(d) int dreg, dest, result; GET_DW_##d; result = (dest >> 1) | (GET_C << 15); CLR_NZVC; SETW_NZ; PSW |= dest & 1; PSW |= ((PSW << 1) ^ (PSW >> 2)) & 2; PUT_DW_DREG(result) +#define ROR_M(d) int dreg, dest, result, ea; GET_DW_##d; result = (dest >> 1) | (GET_C << 15); CLR_NZVC; SETW_NZ; PSW |= dest & 1; PSW |= ((PSW << 1) ^ (PSW >> 2)) & 2; PUT_DW_EA(result) +#define RORB_R(d) int dreg, dest, result; GET_DB_##d; result = (dest >> 1) | (GET_C << 7); CLR_NZVC; SETB_NZ; PSW |= dest & 1; PSW |= ((PSW << 1) ^ (PSW >> 2)) & 2; PUT_DB_DREG(result) +#define RORB_M(d) int dreg, dest, result, ea; GET_DB_##d; result = (dest >> 1) | (GET_C << 7); CLR_NZVC; SETB_NZ; PSW |= dest & 1; PSW |= ((PSW << 1) ^ (PSW >> 2)) & 2; PUT_DB_EA(result) +/* SBC: dst -= C */ +#define SBC_R(d) int dreg, source, dest, result; source = GET_C; GET_DW_##d; CLR_NZVC; result = dest - source; SETW_NZVC; PUT_DW_DREG(result) +#define SBC_M(d) int dreg, source, dest, result, ea; source = GET_C; GET_DW_##d; CLR_NZVC; result = dest - source; SETW_NZVC; PUT_DW_EA(result) +#define SBCB_R(d) int dreg, source, dest, result; source = GET_C; GET_DB_##d; CLR_NZVC; result = dest - source; SETB_NZVC; PUT_DB_DREG(result) +#define SBCB_M(d) int dreg, source, dest, result, ea; source = GET_C; GET_DB_##d; CLR_NZVC; result = dest - source; SETB_NZVC; PUT_DB_EA(result) +/* SUB: dst -= src */ +#define SUB_R(s,d) int sreg, dreg, source, dest, result; GET_SW_##s; GET_DW_##d; CLR_NZVC; result = dest - source; SETW_NZVC; PUT_DW_DREG(result) +#define SUB_X(s,d) int sreg, dreg, source, dest, result, ea; GET_SW_##s; GET_DW_##d; CLR_NZVC; result = dest - source; SETW_NZVC; PUT_DW_DREG(result) +#define SUB_M(s,d) int sreg, dreg, source, dest, result, ea; GET_SW_##s; GET_DW_##d; CLR_NZVC; result = dest - source; SETW_NZVC; PUT_DW_EA(result) +#define SUBB_R(s,d) int sreg, dreg, source, dest, result; GET_SB_##s; GET_DB_##d; CLR_NZVC; result = dest - source; SETB_NZVC; PUT_DB_DREG(result) +#define SUBB_X(s,d) int sreg, dreg, source, dest, result, ea; GET_SB_##s; GET_DB_##d; CLR_NZVC; result = dest - source; SETB_NZVC; PUT_DB_DREG(result) +#define SUBB_M(s,d) int sreg, dreg, source, dest, result, ea; GET_SB_##s; GET_DB_##d; CLR_NZVC; result = dest - source; SETB_NZVC; PUT_DB_EA(result) +/* SWAB: dst = (dst >> 8) + (dst << 8) */ +#define SWAB_R(d) int dreg, dest, result; GET_DW_##d; CLR_NZVC; result = ((dest >> 8) & 0xff) + (dest << 8); SETB_NZ; PUT_DW_DREG(result) +#define SWAB_M(d) int dreg, dest, result, ea; GET_DW_##d; CLR_NZVC; result = ((dest >> 8) & 0xff) + (dest << 8); SETB_NZ; PUT_DW_EA(result) +/* SXT: dst = sign-extend dst */ +#define SXT_R(d) int dreg, result; CLR_ZV; if (GET_N) result = -1; else { result = 0; SET_Z; } PUT_DW_##d(result) +#define SXT_M(d) int dreg, result, ea; CLR_ZV; if (GET_N) result = -1; else { result = 0; SET_Z; } PUT_DW_##d(result) +/* TST: dst = ~dst */ +#define TST_R(d) int dreg, dest, result; GET_DW_##d; CLR_NZVC; result = dest; SETW_NZ; +#define TST_M(d) int dreg, dest, result, ea; GET_DW_##d; CLR_NZVC; result = dest; SETW_NZ; +#define TSTB_R(d) int dreg, dest, result; GET_DB_##d; CLR_NZVC; result = dest; SETB_NZ; +#define TSTB_M(d) int dreg, dest, result, ea; GET_DB_##d; CLR_NZVC; result = dest; SETB_NZ; +/* XOR: dst ^= src */ +#define XOR_R(d) int sreg, dreg, source, dest, result; GET_SREG; source = REGW(sreg); GET_DW_##d; CLR_NZV; result = dest ^ source; SETW_NZ; PUT_DW_DREG(result) +#define XOR_M(d) int sreg, dreg, source, dest, result, ea; GET_SREG; source = REGW(sreg); GET_DW_##d; CLR_NZV; result = dest ^ source; SETW_NZ; PUT_DW_EA(result) + + + +void t11_device::op_0000(UINT16 op) +{ + switch (op & 0x3f) + { + case 0x00: /* HALT */ halt(op); break; + case 0x01: /* WAIT */ m_icount = 0; m_wait_state = 1; break; + case 0x02: /* RTI */ m_icount -= 24; PC = POP(); PSW = POP(); t11_check_irqs(); break; + case 0x03: /* BPT */ m_icount -= 48; PUSH(PSW); PUSH(PC); PC = RWORD(0x0c); PSW = RWORD(0x0e); t11_check_irqs(); break; + case 0x04: /* IOT */ m_icount -= 48; PUSH(PSW); PUSH(PC); PC = RWORD(0x10); PSW = RWORD(0x12); t11_check_irqs(); break; + case 0x05: /* RESET */ m_icount -= 110; break; + case 0x06: /* RTT */ m_icount -= 33; PC = POP(); PSW = POP(); t11_check_irqs(); break; + default: illegal(op); break; + } +} + +void t11_device::halt(UINT16 op) +{ + m_icount -= 48; + PUSH(PSW); + PUSH(PC); + PC = RWORD(0x04); + PSW = RWORD(0x06); + t11_check_irqs(); +} + +void t11_device::illegal(UINT16 op) +{ + m_icount -= 48; + PUSH(PSW); + PUSH(PC); + PC = RWORD(0x08); + PSW = RWORD(0x0a); + t11_check_irqs(); +} + +void t11_device::mark(UINT16 op) +{ + m_icount -= 36; + + SP = SP + 2 * (op & 0x3f); + PC = REGW(5); + REGW(5) = POP(); +} + +void t11_device::jmp_rgd(UINT16 op) { m_icount -= 15; { JMP(RGD); } } +void t11_device::jmp_in(UINT16 op) { m_icount -= 18; { JMP(IN); } } +void t11_device::jmp_ind(UINT16 op) { m_icount -= 18; { JMP(IND); } } +void t11_device::jmp_de(UINT16 op) { m_icount -= 18; { JMP(DE); } } +void t11_device::jmp_ded(UINT16 op) { m_icount -= 21; { JMP(DED); } } +void t11_device::jmp_ix(UINT16 op) { m_icount -= 21; { JMP(IX); } } +void t11_device::jmp_ixd(UINT16 op) { m_icount -= 27; { JMP(IXD); } } + +void t11_device::rts(UINT16 op) +{ + int dreg; + m_icount -= 21; + GET_DREG; + PC = REGD(dreg); + REGW(dreg) = POP(); +} + +void t11_device::ccc(UINT16 op) { m_icount -= 18; { PSW &= ~(op & 15); } } +void t11_device::scc(UINT16 op) { m_icount -= 18; { PSW |= (op & 15); } } + +void t11_device::swab_rg(UINT16 op) { m_icount -= 12; { SWAB_R(RG); } } +void t11_device::swab_rgd(UINT16 op) { m_icount -= 21; { SWAB_M(RGD); } } +void t11_device::swab_in(UINT16 op) { m_icount -= 21; { SWAB_M(IN); } } +void t11_device::swab_ind(UINT16 op) { m_icount -= 27; { SWAB_M(IND); } } +void t11_device::swab_de(UINT16 op) { m_icount -= 24; { SWAB_M(DE); } } +void t11_device::swab_ded(UINT16 op) { m_icount -= 30; { SWAB_M(DED); } } +void t11_device::swab_ix(UINT16 op) { m_icount -= 30; { SWAB_M(IX); } } +void t11_device::swab_ixd(UINT16 op) { m_icount -= 36; { SWAB_M(IXD); } } + +void t11_device::br(UINT16 op) { m_icount -= 12; { BR(1); } } +void t11_device::bne(UINT16 op) { m_icount -= 12; { BR(!GET_Z); } } +void t11_device::beq(UINT16 op) { m_icount -= 12; { BR( GET_Z); } } +void t11_device::bge(UINT16 op) { m_icount -= 12; { BR(!((GET_N >> 2) ^ GET_V)); } } +void t11_device::blt(UINT16 op) { m_icount -= 12; { BR(((GET_N >> 2) ^ GET_V)); } } +void t11_device::bgt(UINT16 op) { m_icount -= 12; { BR(!GET_Z && !((GET_N >> 2) ^ GET_V)); } } +void t11_device::ble(UINT16 op) { m_icount -= 12; { BR( GET_Z || ((GET_N >> 2) ^ GET_V)); } } + +void t11_device::jsr_rgd(UINT16 op) { m_icount -= 27; { JSR(RGD); } } +void t11_device::jsr_in(UINT16 op) { m_icount -= 30; { JSR(IN); } } +void t11_device::jsr_ind(UINT16 op) { m_icount -= 30; { JSR(IND); } } +void t11_device::jsr_de(UINT16 op) { m_icount -= 30; { JSR(DE); } } +void t11_device::jsr_ded(UINT16 op) { m_icount -= 33; { JSR(DED); } } +void t11_device::jsr_ix(UINT16 op) { m_icount -= 33; { JSR(IX); } } +void t11_device::jsr_ixd(UINT16 op) { m_icount -= 39; { JSR(IXD); } } + +void t11_device::clr_rg(UINT16 op) { m_icount -= 12; { CLR_R(RG); } } +void t11_device::clr_rgd(UINT16 op) { m_icount -= 21; { CLR_M(RGD); } } +void t11_device::clr_in(UINT16 op) { m_icount -= 21; { CLR_M(IN); } } +void t11_device::clr_ind(UINT16 op) { m_icount -= 27; { CLR_M(IND); } } +void t11_device::clr_de(UINT16 op) { m_icount -= 24; { CLR_M(DE); } } +void t11_device::clr_ded(UINT16 op) { m_icount -= 30; { CLR_M(DED); } } +void t11_device::clr_ix(UINT16 op) { m_icount -= 30; { CLR_M(IX); } } +void t11_device::clr_ixd(UINT16 op) { m_icount -= 36; { CLR_M(IXD); } } + +void t11_device::com_rg(UINT16 op) { m_icount -= 12; { COM_R(RG); } } +void t11_device::com_rgd(UINT16 op) { m_icount -= 21; { COM_M(RGD); } } +void t11_device::com_in(UINT16 op) { m_icount -= 21; { COM_M(IN); } } +void t11_device::com_ind(UINT16 op) { m_icount -= 27; { COM_M(IND); } } +void t11_device::com_de(UINT16 op) { m_icount -= 24; { COM_M(DE); } } +void t11_device::com_ded(UINT16 op) { m_icount -= 30; { COM_M(DED); } } +void t11_device::com_ix(UINT16 op) { m_icount -= 30; { COM_M(IX); } } +void t11_device::com_ixd(UINT16 op) { m_icount -= 36; { COM_M(IXD); } } + +void t11_device::inc_rg(UINT16 op) { m_icount -= 12; { INC_R(RG); } } +void t11_device::inc_rgd(UINT16 op) { m_icount -= 21; { INC_M(RGD); } } +void t11_device::inc_in(UINT16 op) { m_icount -= 21; { INC_M(IN); } } +void t11_device::inc_ind(UINT16 op) { m_icount -= 27; { INC_M(IND); } } +void t11_device::inc_de(UINT16 op) { m_icount -= 24; { INC_M(DE); } } +void t11_device::inc_ded(UINT16 op) { m_icount -= 30; { INC_M(DED); } } +void t11_device::inc_ix(UINT16 op) { m_icount -= 30; { INC_M(IX); } } +void t11_device::inc_ixd(UINT16 op) { m_icount -= 36; { INC_M(IXD); } } + +void t11_device::dec_rg(UINT16 op) { m_icount -= 12; { DEC_R(RG); } } +void t11_device::dec_rgd(UINT16 op) { m_icount -= 21; { DEC_M(RGD); } } +void t11_device::dec_in(UINT16 op) { m_icount -= 21; { DEC_M(IN); } } +void t11_device::dec_ind(UINT16 op) { m_icount -= 27; { DEC_M(IND); } } +void t11_device::dec_de(UINT16 op) { m_icount -= 24; { DEC_M(DE); } } +void t11_device::dec_ded(UINT16 op) { m_icount -= 30; { DEC_M(DED); } } +void t11_device::dec_ix(UINT16 op) { m_icount -= 30; { DEC_M(IX); } } +void t11_device::dec_ixd(UINT16 op) { m_icount -= 36; { DEC_M(IXD); } } + +void t11_device::neg_rg(UINT16 op) { m_icount -= 12; { NEG_R(RG); } } +void t11_device::neg_rgd(UINT16 op) { m_icount -= 21; { NEG_M(RGD); } } +void t11_device::neg_in(UINT16 op) { m_icount -= 21; { NEG_M(IN); } } +void t11_device::neg_ind(UINT16 op) { m_icount -= 27; { NEG_M(IND); } } +void t11_device::neg_de(UINT16 op) { m_icount -= 24; { NEG_M(DE); } } +void t11_device::neg_ded(UINT16 op) { m_icount -= 30; { NEG_M(DED); } } +void t11_device::neg_ix(UINT16 op) { m_icount -= 30; { NEG_M(IX); } } +void t11_device::neg_ixd(UINT16 op) { m_icount -= 36; { NEG_M(IXD); } } + +void t11_device::adc_rg(UINT16 op) { m_icount -= 12; { ADC_R(RG); } } +void t11_device::adc_rgd(UINT16 op) { m_icount -= 21; { ADC_M(RGD); } } +void t11_device::adc_in(UINT16 op) { m_icount -= 21; { ADC_M(IN); } } +void t11_device::adc_ind(UINT16 op) { m_icount -= 27; { ADC_M(IND); } } +void t11_device::adc_de(UINT16 op) { m_icount -= 24; { ADC_M(DE); } } +void t11_device::adc_ded(UINT16 op) { m_icount -= 30; { ADC_M(DED); } } +void t11_device::adc_ix(UINT16 op) { m_icount -= 30; { ADC_M(IX); } } +void t11_device::adc_ixd(UINT16 op) { m_icount -= 36; { ADC_M(IXD); } } + +void t11_device::sbc_rg(UINT16 op) { m_icount -= 12; { SBC_R(RG); } } +void t11_device::sbc_rgd(UINT16 op) { m_icount -= 21; { SBC_M(RGD); } } +void t11_device::sbc_in(UINT16 op) { m_icount -= 21; { SBC_M(IN); } } +void t11_device::sbc_ind(UINT16 op) { m_icount -= 27; { SBC_M(IND); } } +void t11_device::sbc_de(UINT16 op) { m_icount -= 24; { SBC_M(DE); } } +void t11_device::sbc_ded(UINT16 op) { m_icount -= 30; { SBC_M(DED); } } +void t11_device::sbc_ix(UINT16 op) { m_icount -= 30; { SBC_M(IX); } } +void t11_device::sbc_ixd(UINT16 op) { m_icount -= 36; { SBC_M(IXD); } } + +void t11_device::tst_rg(UINT16 op) { m_icount -= 12; { TST_R(RG); } } +void t11_device::tst_rgd(UINT16 op) { m_icount -= 18; { TST_M(RGD); } } +void t11_device::tst_in(UINT16 op) { m_icount -= 18; { TST_M(IN); } } +void t11_device::tst_ind(UINT16 op) { m_icount -= 24; { TST_M(IND); } } +void t11_device::tst_de(UINT16 op) { m_icount -= 21; { TST_M(DE); } } +void t11_device::tst_ded(UINT16 op) { m_icount -= 27; { TST_M(DED); } } +void t11_device::tst_ix(UINT16 op) { m_icount -= 27; { TST_M(IX); } } +void t11_device::tst_ixd(UINT16 op) { m_icount -= 33; { TST_M(IXD); } } + +void t11_device::ror_rg(UINT16 op) { m_icount -= 12; { ROR_R(RG); } } +void t11_device::ror_rgd(UINT16 op) { m_icount -= 21; { ROR_M(RGD); } } +void t11_device::ror_in(UINT16 op) { m_icount -= 21; { ROR_M(IN); } } +void t11_device::ror_ind(UINT16 op) { m_icount -= 27; { ROR_M(IND); } } +void t11_device::ror_de(UINT16 op) { m_icount -= 24; { ROR_M(DE); } } +void t11_device::ror_ded(UINT16 op) { m_icount -= 30; { ROR_M(DED); } } +void t11_device::ror_ix(UINT16 op) { m_icount -= 30; { ROR_M(IX); } } +void t11_device::ror_ixd(UINT16 op) { m_icount -= 36; { ROR_M(IXD); } } + +void t11_device::rol_rg(UINT16 op) { m_icount -= 12; { ROL_R(RG); } } +void t11_device::rol_rgd(UINT16 op) { m_icount -= 21; { ROL_M(RGD); } } +void t11_device::rol_in(UINT16 op) { m_icount -= 21; { ROL_M(IN); } } +void t11_device::rol_ind(UINT16 op) { m_icount -= 27; { ROL_M(IND); } } +void t11_device::rol_de(UINT16 op) { m_icount -= 24; { ROL_M(DE); } } +void t11_device::rol_ded(UINT16 op) { m_icount -= 30; { ROL_M(DED); } } +void t11_device::rol_ix(UINT16 op) { m_icount -= 30; { ROL_M(IX); } } +void t11_device::rol_ixd(UINT16 op) { m_icount -= 36; { ROL_M(IXD); } } + +void t11_device::asr_rg(UINT16 op) { m_icount -= 12; { ASR_R(RG); } } +void t11_device::asr_rgd(UINT16 op) { m_icount -= 21; { ASR_M(RGD); } } +void t11_device::asr_in(UINT16 op) { m_icount -= 21; { ASR_M(IN); } } +void t11_device::asr_ind(UINT16 op) { m_icount -= 27; { ASR_M(IND); } } +void t11_device::asr_de(UINT16 op) { m_icount -= 24; { ASR_M(DE); } } +void t11_device::asr_ded(UINT16 op) { m_icount -= 30; { ASR_M(DED); } } +void t11_device::asr_ix(UINT16 op) { m_icount -= 30; { ASR_M(IX); } } +void t11_device::asr_ixd(UINT16 op) { m_icount -= 36; { ASR_M(IXD); } } + +void t11_device::asl_rg(UINT16 op) { m_icount -= 12; { ASL_R(RG); } } +void t11_device::asl_rgd(UINT16 op) { m_icount -= 21; { ASL_M(RGD); } } +void t11_device::asl_in(UINT16 op) { m_icount -= 21; { ASL_M(IN); } } +void t11_device::asl_ind(UINT16 op) { m_icount -= 27; { ASL_M(IND); } } +void t11_device::asl_de(UINT16 op) { m_icount -= 24; { ASL_M(DE); } } +void t11_device::asl_ded(UINT16 op) { m_icount -= 30; { ASL_M(DED); } } +void t11_device::asl_ix(UINT16 op) { m_icount -= 30; { ASL_M(IX); } } +void t11_device::asl_ixd(UINT16 op) { m_icount -= 36; { ASL_M(IXD); } } + +void t11_device::sxt_rg(UINT16 op) { m_icount -= 12; { SXT_R(RG); } } +void t11_device::sxt_rgd(UINT16 op) { m_icount -= 21; { SXT_M(RGD); } } +void t11_device::sxt_in(UINT16 op) { m_icount -= 21; { SXT_M(IN); } } +void t11_device::sxt_ind(UINT16 op) { m_icount -= 27; { SXT_M(IND); } } +void t11_device::sxt_de(UINT16 op) { m_icount -= 24; { SXT_M(DE); } } +void t11_device::sxt_ded(UINT16 op) { m_icount -= 30; { SXT_M(DED); } } +void t11_device::sxt_ix(UINT16 op) { m_icount -= 30; { SXT_M(IX); } } +void t11_device::sxt_ixd(UINT16 op) { m_icount -= 36; { SXT_M(IXD); } } + +void t11_device::mov_rg_rg(UINT16 op) { m_icount -= 9+ 3; { MOV_R(RG,RG); } } +void t11_device::mov_rg_rgd(UINT16 op) { m_icount -= 9+12; { MOV_M(RG,RGD); } } +void t11_device::mov_rg_in(UINT16 op) { m_icount -= 9+12; { MOV_M(RG,IN); } } +void t11_device::mov_rg_ind(UINT16 op) { m_icount -= 9+18; { MOV_M(RG,IND); } } +void t11_device::mov_rg_de(UINT16 op) { m_icount -= 9+15; { MOV_M(RG,DE); } } +void t11_device::mov_rg_ded(UINT16 op) { m_icount -= 9+21; { MOV_M(RG,DED); } } +void t11_device::mov_rg_ix(UINT16 op) { m_icount -= 9+21; { MOV_M(RG,IX); } } +void t11_device::mov_rg_ixd(UINT16 op) { m_icount -= 9+27; { MOV_M(RG,IXD); } } +void t11_device::mov_rgd_rg(UINT16 op) { m_icount -= 15+ 3; { MOV_M(RGD,RG); } } +void t11_device::mov_rgd_rgd(UINT16 op) { m_icount -= 15+12; { MOV_M(RGD,RGD); } } +void t11_device::mov_rgd_in(UINT16 op) { m_icount -= 15+12; { MOV_M(RGD,IN); } } +void t11_device::mov_rgd_ind(UINT16 op) { m_icount -= 15+18; { MOV_M(RGD,IND); } } +void t11_device::mov_rgd_de(UINT16 op) { m_icount -= 15+15; { MOV_M(RGD,DE); } } +void t11_device::mov_rgd_ded(UINT16 op) { m_icount -= 15+21; { MOV_M(RGD,DED); } } +void t11_device::mov_rgd_ix(UINT16 op) { m_icount -= 15+21; { MOV_M(RGD,IX); } } +void t11_device::mov_rgd_ixd(UINT16 op) { m_icount -= 15+27; { MOV_M(RGD,IXD); } } +void t11_device::mov_in_rg(UINT16 op) { m_icount -= 15+ 3; { MOV_M(IN,RG); } } +void t11_device::mov_in_rgd(UINT16 op) { m_icount -= 15+12; { MOV_M(IN,RGD); } } +void t11_device::mov_in_in(UINT16 op) { m_icount -= 15+12; { MOV_M(IN,IN); } } +void t11_device::mov_in_ind(UINT16 op) { m_icount -= 15+18; { MOV_M(IN,IND); } } +void t11_device::mov_in_de(UINT16 op) { m_icount -= 15+15; { MOV_M(IN,DE); } } +void t11_device::mov_in_ded(UINT16 op) { m_icount -= 15+21; { MOV_M(IN,DED); } } +void t11_device::mov_in_ix(UINT16 op) { m_icount -= 15+21; { MOV_M(IN,IX); } } +void t11_device::mov_in_ixd(UINT16 op) { m_icount -= 15+27; { MOV_M(IN,IXD); } } +void t11_device::mov_ind_rg(UINT16 op) { m_icount -= 21+ 3; { MOV_M(IND,RG); } } +void t11_device::mov_ind_rgd(UINT16 op) { m_icount -= 21+12; { MOV_M(IND,RGD); } } +void t11_device::mov_ind_in(UINT16 op) { m_icount -= 21+12; { MOV_M(IND,IN); } } +void t11_device::mov_ind_ind(UINT16 op) { m_icount -= 21+18; { MOV_M(IND,IND); } } +void t11_device::mov_ind_de(UINT16 op) { m_icount -= 21+15; { MOV_M(IND,DE); } } +void t11_device::mov_ind_ded(UINT16 op) { m_icount -= 21+21; { MOV_M(IND,DED); } } +void t11_device::mov_ind_ix(UINT16 op) { m_icount -= 21+21; { MOV_M(IND,IX); } } +void t11_device::mov_ind_ixd(UINT16 op) { m_icount -= 21+27; { MOV_M(IND,IXD); } } +void t11_device::mov_de_rg(UINT16 op) { m_icount -= 18+ 3; { MOV_M(DE,RG); } } +void t11_device::mov_de_rgd(UINT16 op) { m_icount -= 18+12; { MOV_M(DE,RGD); } } +void t11_device::mov_de_in(UINT16 op) { m_icount -= 18+12; { MOV_M(DE,IN); } } +void t11_device::mov_de_ind(UINT16 op) { m_icount -= 18+18; { MOV_M(DE,IND); } } +void t11_device::mov_de_de(UINT16 op) { m_icount -= 18+15; { MOV_M(DE,DE); } } +void t11_device::mov_de_ded(UINT16 op) { m_icount -= 18+21; { MOV_M(DE,DED); } } +void t11_device::mov_de_ix(UINT16 op) { m_icount -= 18+21; { MOV_M(DE,IX); } } +void t11_device::mov_de_ixd(UINT16 op) { m_icount -= 18+27; { MOV_M(DE,IXD); } } +void t11_device::mov_ded_rg(UINT16 op) { m_icount -= 24+ 3; { MOV_M(DED,RG); } } +void t11_device::mov_ded_rgd(UINT16 op) { m_icount -= 24+12; { MOV_M(DED,RGD); } } +void t11_device::mov_ded_in(UINT16 op) { m_icount -= 24+12; { MOV_M(DED,IN); } } +void t11_device::mov_ded_ind(UINT16 op) { m_icount -= 24+18; { MOV_M(DED,IND); } } +void t11_device::mov_ded_de(UINT16 op) { m_icount -= 24+15; { MOV_M(DED,DE); } } +void t11_device::mov_ded_ded(UINT16 op) { m_icount -= 24+21; { MOV_M(DED,DED); } } +void t11_device::mov_ded_ix(UINT16 op) { m_icount -= 24+21; { MOV_M(DED,IX); } } +void t11_device::mov_ded_ixd(UINT16 op) { m_icount -= 24+27; { MOV_M(DED,IXD); } } +void t11_device::mov_ix_rg(UINT16 op) { m_icount -= 24+ 3; { MOV_M(IX,RG); } } +void t11_device::mov_ix_rgd(UINT16 op) { m_icount -= 24+12; { MOV_M(IX,RGD); } } +void t11_device::mov_ix_in(UINT16 op) { m_icount -= 24+12; { MOV_M(IX,IN); } } +void t11_device::mov_ix_ind(UINT16 op) { m_icount -= 24+18; { MOV_M(IX,IND); } } +void t11_device::mov_ix_de(UINT16 op) { m_icount -= 24+15; { MOV_M(IX,DE); } } +void t11_device::mov_ix_ded(UINT16 op) { m_icount -= 24+21; { MOV_M(IX,DED); } } +void t11_device::mov_ix_ix(UINT16 op) { m_icount -= 24+21; { MOV_M(IX,IX); } } +void t11_device::mov_ix_ixd(UINT16 op) { m_icount -= 24+27; { MOV_M(IX,IXD); } } +void t11_device::mov_ixd_rg(UINT16 op) { m_icount -= 30+ 3; { MOV_M(IXD,RG); } } +void t11_device::mov_ixd_rgd(UINT16 op) { m_icount -= 30+12; { MOV_M(IXD,RGD); } } +void t11_device::mov_ixd_in(UINT16 op) { m_icount -= 30+12; { MOV_M(IXD,IN); } } +void t11_device::mov_ixd_ind(UINT16 op) { m_icount -= 30+18; { MOV_M(IXD,IND); } } +void t11_device::mov_ixd_de(UINT16 op) { m_icount -= 30+15; { MOV_M(IXD,DE); } } +void t11_device::mov_ixd_ded(UINT16 op) { m_icount -= 30+21; { MOV_M(IXD,DED); } } +void t11_device::mov_ixd_ix(UINT16 op) { m_icount -= 30+21; { MOV_M(IXD,IX); } } +void t11_device::mov_ixd_ixd(UINT16 op) { m_icount -= 30+27; { MOV_M(IXD,IXD); } } + +void t11_device::cmp_rg_rg(UINT16 op) { m_icount -= 9+ 3; { CMP_R(RG,RG); } } +void t11_device::cmp_rg_rgd(UINT16 op) { m_icount -= 9+ 9; { CMP_M(RG,RGD); } } +void t11_device::cmp_rg_in(UINT16 op) { m_icount -= 9+ 9; { CMP_M(RG,IN); } } +void t11_device::cmp_rg_ind(UINT16 op) { m_icount -= 9+15; { CMP_M(RG,IND); } } +void t11_device::cmp_rg_de(UINT16 op) { m_icount -= 9+12; { CMP_M(RG,DE); } } +void t11_device::cmp_rg_ded(UINT16 op) { m_icount -= 9+18; { CMP_M(RG,DED); } } +void t11_device::cmp_rg_ix(UINT16 op) { m_icount -= 9+18; { CMP_M(RG,IX); } } +void t11_device::cmp_rg_ixd(UINT16 op) { m_icount -= 9+24; { CMP_M(RG,IXD); } } +void t11_device::cmp_rgd_rg(UINT16 op) { m_icount -= 15+ 3; { CMP_M(RGD,RG); } } +void t11_device::cmp_rgd_rgd(UINT16 op) { m_icount -= 15+ 9; { CMP_M(RGD,RGD); } } +void t11_device::cmp_rgd_in(UINT16 op) { m_icount -= 15+ 9; { CMP_M(RGD,IN); } } +void t11_device::cmp_rgd_ind(UINT16 op) { m_icount -= 15+15; { CMP_M(RGD,IND); } } +void t11_device::cmp_rgd_de(UINT16 op) { m_icount -= 15+12; { CMP_M(RGD,DE); } } +void t11_device::cmp_rgd_ded(UINT16 op) { m_icount -= 15+18; { CMP_M(RGD,DED); } } +void t11_device::cmp_rgd_ix(UINT16 op) { m_icount -= 15+18; { CMP_M(RGD,IX); } } +void t11_device::cmp_rgd_ixd(UINT16 op) { m_icount -= 15+24; { CMP_M(RGD,IXD); } } +void t11_device::cmp_in_rg(UINT16 op) { m_icount -= 15+ 3; { CMP_M(IN,RG); } } +void t11_device::cmp_in_rgd(UINT16 op) { m_icount -= 15+ 9; { CMP_M(IN,RGD); } } +void t11_device::cmp_in_in(UINT16 op) { m_icount -= 15+ 9; { CMP_M(IN,IN); } } +void t11_device::cmp_in_ind(UINT16 op) { m_icount -= 15+15; { CMP_M(IN,IND); } } +void t11_device::cmp_in_de(UINT16 op) { m_icount -= 15+12; { CMP_M(IN,DE); } } +void t11_device::cmp_in_ded(UINT16 op) { m_icount -= 15+18; { CMP_M(IN,DED); } } +void t11_device::cmp_in_ix(UINT16 op) { m_icount -= 15+18; { CMP_M(IN,IX); } } +void t11_device::cmp_in_ixd(UINT16 op) { m_icount -= 15+24; { CMP_M(IN,IXD); } } +void t11_device::cmp_ind_rg(UINT16 op) { m_icount -= 21+ 3; { CMP_M(IND,RG); } } +void t11_device::cmp_ind_rgd(UINT16 op) { m_icount -= 21+ 9; { CMP_M(IND,RGD); } } +void t11_device::cmp_ind_in(UINT16 op) { m_icount -= 21+ 9; { CMP_M(IND,IN); } } +void t11_device::cmp_ind_ind(UINT16 op) { m_icount -= 21+15; { CMP_M(IND,IND); } } +void t11_device::cmp_ind_de(UINT16 op) { m_icount -= 21+12; { CMP_M(IND,DE); } } +void t11_device::cmp_ind_ded(UINT16 op) { m_icount -= 21+18; { CMP_M(IND,DED); } } +void t11_device::cmp_ind_ix(UINT16 op) { m_icount -= 21+18; { CMP_M(IND,IX); } } +void t11_device::cmp_ind_ixd(UINT16 op) { m_icount -= 21+24; { CMP_M(IND,IXD); } } +void t11_device::cmp_de_rg(UINT16 op) { m_icount -= 18+ 3; { CMP_M(DE,RG); } } +void t11_device::cmp_de_rgd(UINT16 op) { m_icount -= 18+ 9; { CMP_M(DE,RGD); } } +void t11_device::cmp_de_in(UINT16 op) { m_icount -= 18+ 9; { CMP_M(DE,IN); } } +void t11_device::cmp_de_ind(UINT16 op) { m_icount -= 18+15; { CMP_M(DE,IND); } } +void t11_device::cmp_de_de(UINT16 op) { m_icount -= 18+12; { CMP_M(DE,DE); } } +void t11_device::cmp_de_ded(UINT16 op) { m_icount -= 18+18; { CMP_M(DE,DED); } } +void t11_device::cmp_de_ix(UINT16 op) { m_icount -= 18+18; { CMP_M(DE,IX); } } +void t11_device::cmp_de_ixd(UINT16 op) { m_icount -= 18+24; { CMP_M(DE,IXD); } } +void t11_device::cmp_ded_rg(UINT16 op) { m_icount -= 24+ 3; { CMP_M(DED,RG); } } +void t11_device::cmp_ded_rgd(UINT16 op) { m_icount -= 24+ 9; { CMP_M(DED,RGD); } } +void t11_device::cmp_ded_in(UINT16 op) { m_icount -= 24+ 9; { CMP_M(DED,IN); } } +void t11_device::cmp_ded_ind(UINT16 op) { m_icount -= 24+15; { CMP_M(DED,IND); } } +void t11_device::cmp_ded_de(UINT16 op) { m_icount -= 24+12; { CMP_M(DED,DE); } } +void t11_device::cmp_ded_ded(UINT16 op) { m_icount -= 24+18; { CMP_M(DED,DED); } } +void t11_device::cmp_ded_ix(UINT16 op) { m_icount -= 24+18; { CMP_M(DED,IX); } } +void t11_device::cmp_ded_ixd(UINT16 op) { m_icount -= 24+24; { CMP_M(DED,IXD); } } +void t11_device::cmp_ix_rg(UINT16 op) { m_icount -= 24+ 3; { CMP_M(IX,RG); } } +void t11_device::cmp_ix_rgd(UINT16 op) { m_icount -= 24+ 9; { CMP_M(IX,RGD); } } +void t11_device::cmp_ix_in(UINT16 op) { m_icount -= 24+ 9; { CMP_M(IX,IN); } } +void t11_device::cmp_ix_ind(UINT16 op) { m_icount -= 24+15; { CMP_M(IX,IND); } } +void t11_device::cmp_ix_de(UINT16 op) { m_icount -= 24+12; { CMP_M(IX,DE); } } +void t11_device::cmp_ix_ded(UINT16 op) { m_icount -= 24+18; { CMP_M(IX,DED); } } +void t11_device::cmp_ix_ix(UINT16 op) { m_icount -= 24+18; { CMP_M(IX,IX); } } +void t11_device::cmp_ix_ixd(UINT16 op) { m_icount -= 24+24; { CMP_M(IX,IXD); } } +void t11_device::cmp_ixd_rg(UINT16 op) { m_icount -= 30+ 3; { CMP_M(IXD,RG); } } +void t11_device::cmp_ixd_rgd(UINT16 op) { m_icount -= 30+ 9; { CMP_M(IXD,RGD); } } +void t11_device::cmp_ixd_in(UINT16 op) { m_icount -= 30+ 9; { CMP_M(IXD,IN); } } +void t11_device::cmp_ixd_ind(UINT16 op) { m_icount -= 30+15; { CMP_M(IXD,IND); } } +void t11_device::cmp_ixd_de(UINT16 op) { m_icount -= 30+12; { CMP_M(IXD,DE); } } +void t11_device::cmp_ixd_ded(UINT16 op) { m_icount -= 30+18; { CMP_M(IXD,DED); } } +void t11_device::cmp_ixd_ix(UINT16 op) { m_icount -= 30+18; { CMP_M(IXD,IX); } } +void t11_device::cmp_ixd_ixd(UINT16 op) { m_icount -= 30+24; { CMP_M(IXD,IXD); } } + +void t11_device::bit_rg_rg(UINT16 op) { m_icount -= 9+ 3; { BIT_R(RG,RG); } } +void t11_device::bit_rg_rgd(UINT16 op) { m_icount -= 9+ 9; { BIT_M(RG,RGD); } } +void t11_device::bit_rg_in(UINT16 op) { m_icount -= 9+ 9; { BIT_M(RG,IN); } } +void t11_device::bit_rg_ind(UINT16 op) { m_icount -= 9+15; { BIT_M(RG,IND); } } +void t11_device::bit_rg_de(UINT16 op) { m_icount -= 9+12; { BIT_M(RG,DE); } } +void t11_device::bit_rg_ded(UINT16 op) { m_icount -= 9+18; { BIT_M(RG,DED); } } +void t11_device::bit_rg_ix(UINT16 op) { m_icount -= 9+18; { BIT_M(RG,IX); } } +void t11_device::bit_rg_ixd(UINT16 op) { m_icount -= 9+24; { BIT_M(RG,IXD); } } +void t11_device::bit_rgd_rg(UINT16 op) { m_icount -= 15+ 3; { BIT_M(RGD,RG); } } +void t11_device::bit_rgd_rgd(UINT16 op) { m_icount -= 15+ 9; { BIT_M(RGD,RGD); } } +void t11_device::bit_rgd_in(UINT16 op) { m_icount -= 15+ 9; { BIT_M(RGD,IN); } } +void t11_device::bit_rgd_ind(UINT16 op) { m_icount -= 15+15; { BIT_M(RGD,IND); } } +void t11_device::bit_rgd_de(UINT16 op) { m_icount -= 15+12; { BIT_M(RGD,DE); } } +void t11_device::bit_rgd_ded(UINT16 op) { m_icount -= 15+18; { BIT_M(RGD,DED); } } +void t11_device::bit_rgd_ix(UINT16 op) { m_icount -= 15+18; { BIT_M(RGD,IX); } } +void t11_device::bit_rgd_ixd(UINT16 op) { m_icount -= 15+24; { BIT_M(RGD,IXD); } } +void t11_device::bit_in_rg(UINT16 op) { m_icount -= 15+ 3; { BIT_M(IN,RG); } } +void t11_device::bit_in_rgd(UINT16 op) { m_icount -= 15+ 9; { BIT_M(IN,RGD); } } +void t11_device::bit_in_in(UINT16 op) { m_icount -= 15+ 9; { BIT_M(IN,IN); } } +void t11_device::bit_in_ind(UINT16 op) { m_icount -= 15+15; { BIT_M(IN,IND); } } +void t11_device::bit_in_de(UINT16 op) { m_icount -= 15+12; { BIT_M(IN,DE); } } +void t11_device::bit_in_ded(UINT16 op) { m_icount -= 15+18; { BIT_M(IN,DED); } } +void t11_device::bit_in_ix(UINT16 op) { m_icount -= 15+18; { BIT_M(IN,IX); } } +void t11_device::bit_in_ixd(UINT16 op) { m_icount -= 15+24; { BIT_M(IN,IXD); } } +void t11_device::bit_ind_rg(UINT16 op) { m_icount -= 21+ 3; { BIT_M(IND,RG); } } +void t11_device::bit_ind_rgd(UINT16 op) { m_icount -= 21+ 9; { BIT_M(IND,RGD); } } +void t11_device::bit_ind_in(UINT16 op) { m_icount -= 21+ 9; { BIT_M(IND,IN); } } +void t11_device::bit_ind_ind(UINT16 op) { m_icount -= 21+15; { BIT_M(IND,IND); } } +void t11_device::bit_ind_de(UINT16 op) { m_icount -= 21+12; { BIT_M(IND,DE); } } +void t11_device::bit_ind_ded(UINT16 op) { m_icount -= 21+18; { BIT_M(IND,DED); } } +void t11_device::bit_ind_ix(UINT16 op) { m_icount -= 21+18; { BIT_M(IND,IX); } } +void t11_device::bit_ind_ixd(UINT16 op) { m_icount -= 21+24; { BIT_M(IND,IXD); } } +void t11_device::bit_de_rg(UINT16 op) { m_icount -= 18+ 3; { BIT_M(DE,RG); } } +void t11_device::bit_de_rgd(UINT16 op) { m_icount -= 18+ 9; { BIT_M(DE,RGD); } } +void t11_device::bit_de_in(UINT16 op) { m_icount -= 18+ 9; { BIT_M(DE,IN); } } +void t11_device::bit_de_ind(UINT16 op) { m_icount -= 18+15; { BIT_M(DE,IND); } } +void t11_device::bit_de_de(UINT16 op) { m_icount -= 18+12; { BIT_M(DE,DE); } } +void t11_device::bit_de_ded(UINT16 op) { m_icount -= 18+18; { BIT_M(DE,DED); } } +void t11_device::bit_de_ix(UINT16 op) { m_icount -= 18+18; { BIT_M(DE,IX); } } +void t11_device::bit_de_ixd(UINT16 op) { m_icount -= 18+24; { BIT_M(DE,IXD); } } +void t11_device::bit_ded_rg(UINT16 op) { m_icount -= 24+ 3; { BIT_M(DED,RG); } } +void t11_device::bit_ded_rgd(UINT16 op) { m_icount -= 24+ 9; { BIT_M(DED,RGD); } } +void t11_device::bit_ded_in(UINT16 op) { m_icount -= 24+ 9; { BIT_M(DED,IN); } } +void t11_device::bit_ded_ind(UINT16 op) { m_icount -= 24+15; { BIT_M(DED,IND); } } +void t11_device::bit_ded_de(UINT16 op) { m_icount -= 24+12; { BIT_M(DED,DE); } } +void t11_device::bit_ded_ded(UINT16 op) { m_icount -= 24+18; { BIT_M(DED,DED); } } +void t11_device::bit_ded_ix(UINT16 op) { m_icount -= 24+18; { BIT_M(DED,IX); } } +void t11_device::bit_ded_ixd(UINT16 op) { m_icount -= 24+24; { BIT_M(DED,IXD); } } +void t11_device::bit_ix_rg(UINT16 op) { m_icount -= 24+ 3; { BIT_M(IX,RG); } } +void t11_device::bit_ix_rgd(UINT16 op) { m_icount -= 24+ 9; { BIT_M(IX,RGD); } } +void t11_device::bit_ix_in(UINT16 op) { m_icount -= 24+ 9; { BIT_M(IX,IN); } } +void t11_device::bit_ix_ind(UINT16 op) { m_icount -= 24+15; { BIT_M(IX,IND); } } +void t11_device::bit_ix_de(UINT16 op) { m_icount -= 24+12; { BIT_M(IX,DE); } } +void t11_device::bit_ix_ded(UINT16 op) { m_icount -= 24+18; { BIT_M(IX,DED); } } +void t11_device::bit_ix_ix(UINT16 op) { m_icount -= 24+18; { BIT_M(IX,IX); } } +void t11_device::bit_ix_ixd(UINT16 op) { m_icount -= 24+24; { BIT_M(IX,IXD); } } +void t11_device::bit_ixd_rg(UINT16 op) { m_icount -= 30+ 3; { BIT_M(IXD,RG); } } +void t11_device::bit_ixd_rgd(UINT16 op) { m_icount -= 30+ 9; { BIT_M(IXD,RGD); } } +void t11_device::bit_ixd_in(UINT16 op) { m_icount -= 30+ 9; { BIT_M(IXD,IN); } } +void t11_device::bit_ixd_ind(UINT16 op) { m_icount -= 30+15; { BIT_M(IXD,IND); } } +void t11_device::bit_ixd_de(UINT16 op) { m_icount -= 30+12; { BIT_M(IXD,DE); } } +void t11_device::bit_ixd_ded(UINT16 op) { m_icount -= 30+18; { BIT_M(IXD,DED); } } +void t11_device::bit_ixd_ix(UINT16 op) { m_icount -= 30+18; { BIT_M(IXD,IX); } } +void t11_device::bit_ixd_ixd(UINT16 op) { m_icount -= 30+24; { BIT_M(IXD,IXD); } } + +void t11_device::bic_rg_rg(UINT16 op) { m_icount -= 9+ 3; { BIC_R(RG,RG); } } +void t11_device::bic_rg_rgd(UINT16 op) { m_icount -= 9+12; { BIC_M(RG,RGD); } } +void t11_device::bic_rg_in(UINT16 op) { m_icount -= 9+12; { BIC_M(RG,IN); } } +void t11_device::bic_rg_ind(UINT16 op) { m_icount -= 9+18; { BIC_M(RG,IND); } } +void t11_device::bic_rg_de(UINT16 op) { m_icount -= 9+15; { BIC_M(RG,DE); } } +void t11_device::bic_rg_ded(UINT16 op) { m_icount -= 9+21; { BIC_M(RG,DED); } } +void t11_device::bic_rg_ix(UINT16 op) { m_icount -= 9+21; { BIC_M(RG,IX); } } +void t11_device::bic_rg_ixd(UINT16 op) { m_icount -= 9+27; { BIC_M(RG,IXD); } } +void t11_device::bic_rgd_rg(UINT16 op) { m_icount -= 15+ 3; { BIC_X(RGD,RG); } } +void t11_device::bic_rgd_rgd(UINT16 op) { m_icount -= 15+12; { BIC_M(RGD,RGD); } } +void t11_device::bic_rgd_in(UINT16 op) { m_icount -= 15+12; { BIC_M(RGD,IN); } } +void t11_device::bic_rgd_ind(UINT16 op) { m_icount -= 15+18; { BIC_M(RGD,IND); } } +void t11_device::bic_rgd_de(UINT16 op) { m_icount -= 15+15; { BIC_M(RGD,DE); } } +void t11_device::bic_rgd_ded(UINT16 op) { m_icount -= 15+21; { BIC_M(RGD,DED); } } +void t11_device::bic_rgd_ix(UINT16 op) { m_icount -= 15+21; { BIC_M(RGD,IX); } } +void t11_device::bic_rgd_ixd(UINT16 op) { m_icount -= 15+27; { BIC_M(RGD,IXD); } } +void t11_device::bic_in_rg(UINT16 op) { m_icount -= 15+ 3; { BIC_X(IN,RG); } } +void t11_device::bic_in_rgd(UINT16 op) { m_icount -= 15+12; { BIC_M(IN,RGD); } } +void t11_device::bic_in_in(UINT16 op) { m_icount -= 15+12; { BIC_M(IN,IN); } } +void t11_device::bic_in_ind(UINT16 op) { m_icount -= 15+18; { BIC_M(IN,IND); } } +void t11_device::bic_in_de(UINT16 op) { m_icount -= 15+15; { BIC_M(IN,DE); } } +void t11_device::bic_in_ded(UINT16 op) { m_icount -= 15+21; { BIC_M(IN,DED); } } +void t11_device::bic_in_ix(UINT16 op) { m_icount -= 15+21; { BIC_M(IN,IX); } } +void t11_device::bic_in_ixd(UINT16 op) { m_icount -= 15+27; { BIC_M(IN,IXD); } } +void t11_device::bic_ind_rg(UINT16 op) { m_icount -= 21+ 3; { BIC_X(IND,RG); } } +void t11_device::bic_ind_rgd(UINT16 op) { m_icount -= 21+12; { BIC_M(IND,RGD); } } +void t11_device::bic_ind_in(UINT16 op) { m_icount -= 21+12; { BIC_M(IND,IN); } } +void t11_device::bic_ind_ind(UINT16 op) { m_icount -= 21+18; { BIC_M(IND,IND); } } +void t11_device::bic_ind_de(UINT16 op) { m_icount -= 21+15; { BIC_M(IND,DE); } } +void t11_device::bic_ind_ded(UINT16 op) { m_icount -= 21+21; { BIC_M(IND,DED); } } +void t11_device::bic_ind_ix(UINT16 op) { m_icount -= 21+21; { BIC_M(IND,IX); } } +void t11_device::bic_ind_ixd(UINT16 op) { m_icount -= 21+27; { BIC_M(IND,IXD); } } +void t11_device::bic_de_rg(UINT16 op) { m_icount -= 18+ 3; { BIC_X(DE,RG); } } +void t11_device::bic_de_rgd(UINT16 op) { m_icount -= 18+12; { BIC_M(DE,RGD); } } +void t11_device::bic_de_in(UINT16 op) { m_icount -= 18+12; { BIC_M(DE,IN); } } +void t11_device::bic_de_ind(UINT16 op) { m_icount -= 18+18; { BIC_M(DE,IND); } } +void t11_device::bic_de_de(UINT16 op) { m_icount -= 18+15; { BIC_M(DE,DE); } } +void t11_device::bic_de_ded(UINT16 op) { m_icount -= 18+21; { BIC_M(DE,DED); } } +void t11_device::bic_de_ix(UINT16 op) { m_icount -= 18+21; { BIC_M(DE,IX); } } +void t11_device::bic_de_ixd(UINT16 op) { m_icount -= 18+27; { BIC_M(DE,IXD); } } +void t11_device::bic_ded_rg(UINT16 op) { m_icount -= 24+ 3; { BIC_X(DED,RG); } } +void t11_device::bic_ded_rgd(UINT16 op) { m_icount -= 24+12; { BIC_M(DED,RGD); } } +void t11_device::bic_ded_in(UINT16 op) { m_icount -= 24+12; { BIC_M(DED,IN); } } +void t11_device::bic_ded_ind(UINT16 op) { m_icount -= 24+18; { BIC_M(DED,IND); } } +void t11_device::bic_ded_de(UINT16 op) { m_icount -= 24+15; { BIC_M(DED,DE); } } +void t11_device::bic_ded_ded(UINT16 op) { m_icount -= 24+21; { BIC_M(DED,DED); } } +void t11_device::bic_ded_ix(UINT16 op) { m_icount -= 24+21; { BIC_M(DED,IX); } } +void t11_device::bic_ded_ixd(UINT16 op) { m_icount -= 24+27; { BIC_M(DED,IXD); } } +void t11_device::bic_ix_rg(UINT16 op) { m_icount -= 24+ 3; { BIC_X(IX,RG); } } +void t11_device::bic_ix_rgd(UINT16 op) { m_icount -= 24+12; { BIC_M(IX,RGD); } } +void t11_device::bic_ix_in(UINT16 op) { m_icount -= 24+12; { BIC_M(IX,IN); } } +void t11_device::bic_ix_ind(UINT16 op) { m_icount -= 24+18; { BIC_M(IX,IND); } } +void t11_device::bic_ix_de(UINT16 op) { m_icount -= 24+15; { BIC_M(IX,DE); } } +void t11_device::bic_ix_ded(UINT16 op) { m_icount -= 24+21; { BIC_M(IX,DED); } } +void t11_device::bic_ix_ix(UINT16 op) { m_icount -= 24+21; { BIC_M(IX,IX); } } +void t11_device::bic_ix_ixd(UINT16 op) { m_icount -= 24+27; { BIC_M(IX,IXD); } } +void t11_device::bic_ixd_rg(UINT16 op) { m_icount -= 30+ 3; { BIC_X(IXD,RG); } } +void t11_device::bic_ixd_rgd(UINT16 op) { m_icount -= 30+12; { BIC_M(IXD,RGD); } } +void t11_device::bic_ixd_in(UINT16 op) { m_icount -= 30+12; { BIC_M(IXD,IN); } } +void t11_device::bic_ixd_ind(UINT16 op) { m_icount -= 30+18; { BIC_M(IXD,IND); } } +void t11_device::bic_ixd_de(UINT16 op) { m_icount -= 30+15; { BIC_M(IXD,DE); } } +void t11_device::bic_ixd_ded(UINT16 op) { m_icount -= 30+21; { BIC_M(IXD,DED); } } +void t11_device::bic_ixd_ix(UINT16 op) { m_icount -= 30+21; { BIC_M(IXD,IX); } } +void t11_device::bic_ixd_ixd(UINT16 op) { m_icount -= 30+27; { BIC_M(IXD,IXD); } } + +void t11_device::bis_rg_rg(UINT16 op) { m_icount -= 9+ 3; { BIS_R(RG,RG); } } +void t11_device::bis_rg_rgd(UINT16 op) { m_icount -= 9+12; { BIS_M(RG,RGD); } } +void t11_device::bis_rg_in(UINT16 op) { m_icount -= 9+12; { BIS_M(RG,IN); } } +void t11_device::bis_rg_ind(UINT16 op) { m_icount -= 9+18; { BIS_M(RG,IND); } } +void t11_device::bis_rg_de(UINT16 op) { m_icount -= 9+15; { BIS_M(RG,DE); } } +void t11_device::bis_rg_ded(UINT16 op) { m_icount -= 9+21; { BIS_M(RG,DED); } } +void t11_device::bis_rg_ix(UINT16 op) { m_icount -= 9+21; { BIS_M(RG,IX); } } +void t11_device::bis_rg_ixd(UINT16 op) { m_icount -= 9+27; { BIS_M(RG,IXD); } } +void t11_device::bis_rgd_rg(UINT16 op) { m_icount -= 15+ 3; { BIS_X(RGD,RG); } } +void t11_device::bis_rgd_rgd(UINT16 op) { m_icount -= 15+12; { BIS_M(RGD,RGD); } } +void t11_device::bis_rgd_in(UINT16 op) { m_icount -= 15+12; { BIS_M(RGD,IN); } } +void t11_device::bis_rgd_ind(UINT16 op) { m_icount -= 15+18; { BIS_M(RGD,IND); } } +void t11_device::bis_rgd_de(UINT16 op) { m_icount -= 15+15; { BIS_M(RGD,DE); } } +void t11_device::bis_rgd_ded(UINT16 op) { m_icount -= 15+21; { BIS_M(RGD,DED); } } +void t11_device::bis_rgd_ix(UINT16 op) { m_icount -= 15+21; { BIS_M(RGD,IX); } } +void t11_device::bis_rgd_ixd(UINT16 op) { m_icount -= 15+27; { BIS_M(RGD,IXD); } } +void t11_device::bis_in_rg(UINT16 op) { m_icount -= 15+ 3; { BIS_X(IN,RG); } } +void t11_device::bis_in_rgd(UINT16 op) { m_icount -= 15+12; { BIS_M(IN,RGD); } } +void t11_device::bis_in_in(UINT16 op) { m_icount -= 15+12; { BIS_M(IN,IN); } } +void t11_device::bis_in_ind(UINT16 op) { m_icount -= 15+18; { BIS_M(IN,IND); } } +void t11_device::bis_in_de(UINT16 op) { m_icount -= 15+15; { BIS_M(IN,DE); } } +void t11_device::bis_in_ded(UINT16 op) { m_icount -= 15+21; { BIS_M(IN,DED); } } +void t11_device::bis_in_ix(UINT16 op) { m_icount -= 15+21; { BIS_M(IN,IX); } } +void t11_device::bis_in_ixd(UINT16 op) { m_icount -= 15+27; { BIS_M(IN,IXD); } } +void t11_device::bis_ind_rg(UINT16 op) { m_icount -= 21+ 3; { BIS_X(IND,RG); } } +void t11_device::bis_ind_rgd(UINT16 op) { m_icount -= 21+12; { BIS_M(IND,RGD); } } +void t11_device::bis_ind_in(UINT16 op) { m_icount -= 21+12; { BIS_M(IND,IN); } } +void t11_device::bis_ind_ind(UINT16 op) { m_icount -= 21+18; { BIS_M(IND,IND); } } +void t11_device::bis_ind_de(UINT16 op) { m_icount -= 21+15; { BIS_M(IND,DE); } } +void t11_device::bis_ind_ded(UINT16 op) { m_icount -= 21+21; { BIS_M(IND,DED); } } +void t11_device::bis_ind_ix(UINT16 op) { m_icount -= 21+21; { BIS_M(IND,IX); } } +void t11_device::bis_ind_ixd(UINT16 op) { m_icount -= 21+27; { BIS_M(IND,IXD); } } +void t11_device::bis_de_rg(UINT16 op) { m_icount -= 18+ 3; { BIS_X(DE,RG); } } +void t11_device::bis_de_rgd(UINT16 op) { m_icount -= 18+12; { BIS_M(DE,RGD); } } +void t11_device::bis_de_in(UINT16 op) { m_icount -= 18+12; { BIS_M(DE,IN); } } +void t11_device::bis_de_ind(UINT16 op) { m_icount -= 18+18; { BIS_M(DE,IND); } } +void t11_device::bis_de_de(UINT16 op) { m_icount -= 18+15; { BIS_M(DE,DE); } } +void t11_device::bis_de_ded(UINT16 op) { m_icount -= 18+21; { BIS_M(DE,DED); } } +void t11_device::bis_de_ix(UINT16 op) { m_icount -= 18+21; { BIS_M(DE,IX); } } +void t11_device::bis_de_ixd(UINT16 op) { m_icount -= 18+27; { BIS_M(DE,IXD); } } +void t11_device::bis_ded_rg(UINT16 op) { m_icount -= 24+ 3; { BIS_X(DED,RG); } } +void t11_device::bis_ded_rgd(UINT16 op) { m_icount -= 24+12; { BIS_M(DED,RGD); } } +void t11_device::bis_ded_in(UINT16 op) { m_icount -= 24+12; { BIS_M(DED,IN); } } +void t11_device::bis_ded_ind(UINT16 op) { m_icount -= 24+18; { BIS_M(DED,IND); } } +void t11_device::bis_ded_de(UINT16 op) { m_icount -= 24+15; { BIS_M(DED,DE); } } +void t11_device::bis_ded_ded(UINT16 op) { m_icount -= 24+21; { BIS_M(DED,DED); } } +void t11_device::bis_ded_ix(UINT16 op) { m_icount -= 24+21; { BIS_M(DED,IX); } } +void t11_device::bis_ded_ixd(UINT16 op) { m_icount -= 24+27; { BIS_M(DED,IXD); } } +void t11_device::bis_ix_rg(UINT16 op) { m_icount -= 24+ 3; { BIS_X(IX,RG); } } +void t11_device::bis_ix_rgd(UINT16 op) { m_icount -= 24+12; { BIS_M(IX,RGD); } } +void t11_device::bis_ix_in(UINT16 op) { m_icount -= 24+12; { BIS_M(IX,IN); } } +void t11_device::bis_ix_ind(UINT16 op) { m_icount -= 24+18; { BIS_M(IX,IND); } } +void t11_device::bis_ix_de(UINT16 op) { m_icount -= 24+15; { BIS_M(IX,DE); } } +void t11_device::bis_ix_ded(UINT16 op) { m_icount -= 24+21; { BIS_M(IX,DED); } } +void t11_device::bis_ix_ix(UINT16 op) { m_icount -= 24+21; { BIS_M(IX,IX); } } +void t11_device::bis_ix_ixd(UINT16 op) { m_icount -= 24+27; { BIS_M(IX,IXD); } } +void t11_device::bis_ixd_rg(UINT16 op) { m_icount -= 30+ 3; { BIS_X(IXD,RG); } } +void t11_device::bis_ixd_rgd(UINT16 op) { m_icount -= 30+12; { BIS_M(IXD,RGD); } } +void t11_device::bis_ixd_in(UINT16 op) { m_icount -= 30+12; { BIS_M(IXD,IN); } } +void t11_device::bis_ixd_ind(UINT16 op) { m_icount -= 30+18; { BIS_M(IXD,IND); } } +void t11_device::bis_ixd_de(UINT16 op) { m_icount -= 30+15; { BIS_M(IXD,DE); } } +void t11_device::bis_ixd_ded(UINT16 op) { m_icount -= 30+21; { BIS_M(IXD,DED); } } +void t11_device::bis_ixd_ix(UINT16 op) { m_icount -= 30+21; { BIS_M(IXD,IX); } } +void t11_device::bis_ixd_ixd(UINT16 op) { m_icount -= 30+27; { BIS_M(IXD,IXD); } } + +void t11_device::add_rg_rg(UINT16 op) { m_icount -= 9+ 3; { ADD_R(RG,RG); } } +void t11_device::add_rg_rgd(UINT16 op) { m_icount -= 9+12; { ADD_M(RG,RGD); } } +void t11_device::add_rg_in(UINT16 op) { m_icount -= 9+12; { ADD_M(RG,IN); } } +void t11_device::add_rg_ind(UINT16 op) { m_icount -= 9+18; { ADD_M(RG,IND); } } +void t11_device::add_rg_de(UINT16 op) { m_icount -= 9+15; { ADD_M(RG,DE); } } +void t11_device::add_rg_ded(UINT16 op) { m_icount -= 9+21; { ADD_M(RG,DED); } } +void t11_device::add_rg_ix(UINT16 op) { m_icount -= 9+21; { ADD_M(RG,IX); } } +void t11_device::add_rg_ixd(UINT16 op) { m_icount -= 9+27; { ADD_M(RG,IXD); } } +void t11_device::add_rgd_rg(UINT16 op) { m_icount -= 15+ 3; { ADD_X(RGD,RG); } } +void t11_device::add_rgd_rgd(UINT16 op) { m_icount -= 15+12; { ADD_M(RGD,RGD); } } +void t11_device::add_rgd_in(UINT16 op) { m_icount -= 15+12; { ADD_M(RGD,IN); } } +void t11_device::add_rgd_ind(UINT16 op) { m_icount -= 15+18; { ADD_M(RGD,IND); } } +void t11_device::add_rgd_de(UINT16 op) { m_icount -= 15+15; { ADD_M(RGD,DE); } } +void t11_device::add_rgd_ded(UINT16 op) { m_icount -= 15+21; { ADD_M(RGD,DED); } } +void t11_device::add_rgd_ix(UINT16 op) { m_icount -= 15+21; { ADD_M(RGD,IX); } } +void t11_device::add_rgd_ixd(UINT16 op) { m_icount -= 15+27; { ADD_M(RGD,IXD); } } +void t11_device::add_in_rg(UINT16 op) { m_icount -= 15+ 3; { ADD_X(IN,RG); } } +void t11_device::add_in_rgd(UINT16 op) { m_icount -= 15+12; { ADD_M(IN,RGD); } } +void t11_device::add_in_in(UINT16 op) { m_icount -= 15+12; { ADD_M(IN,IN); } } +void t11_device::add_in_ind(UINT16 op) { m_icount -= 15+18; { ADD_M(IN,IND); } } +void t11_device::add_in_de(UINT16 op) { m_icount -= 15+15; { ADD_M(IN,DE); } } +void t11_device::add_in_ded(UINT16 op) { m_icount -= 15+21; { ADD_M(IN,DED); } } +void t11_device::add_in_ix(UINT16 op) { m_icount -= 15+21; { ADD_M(IN,IX); } } +void t11_device::add_in_ixd(UINT16 op) { m_icount -= 15+27; { ADD_M(IN,IXD); } } +void t11_device::add_ind_rg(UINT16 op) { m_icount -= 21+ 3; { ADD_X(IND,RG); } } +void t11_device::add_ind_rgd(UINT16 op) { m_icount -= 21+12; { ADD_M(IND,RGD); } } +void t11_device::add_ind_in(UINT16 op) { m_icount -= 21+12; { ADD_M(IND,IN); } } +void t11_device::add_ind_ind(UINT16 op) { m_icount -= 21+18; { ADD_M(IND,IND); } } +void t11_device::add_ind_de(UINT16 op) { m_icount -= 21+15; { ADD_M(IND,DE); } } +void t11_device::add_ind_ded(UINT16 op) { m_icount -= 21+21; { ADD_M(IND,DED); } } +void t11_device::add_ind_ix(UINT16 op) { m_icount -= 21+21; { ADD_M(IND,IX); } } +void t11_device::add_ind_ixd(UINT16 op) { m_icount -= 21+27; { ADD_M(IND,IXD); } } +void t11_device::add_de_rg(UINT16 op) { m_icount -= 18+ 3; { ADD_X(DE,RG); } } +void t11_device::add_de_rgd(UINT16 op) { m_icount -= 18+12; { ADD_M(DE,RGD); } } +void t11_device::add_de_in(UINT16 op) { m_icount -= 18+12; { ADD_M(DE,IN); } } +void t11_device::add_de_ind(UINT16 op) { m_icount -= 18+18; { ADD_M(DE,IND); } } +void t11_device::add_de_de(UINT16 op) { m_icount -= 18+15; { ADD_M(DE,DE); } } +void t11_device::add_de_ded(UINT16 op) { m_icount -= 18+21; { ADD_M(DE,DED); } } +void t11_device::add_de_ix(UINT16 op) { m_icount -= 18+21; { ADD_M(DE,IX); } } +void t11_device::add_de_ixd(UINT16 op) { m_icount -= 18+27; { ADD_M(DE,IXD); } } +void t11_device::add_ded_rg(UINT16 op) { m_icount -= 24+ 3; { ADD_X(DED,RG); } } +void t11_device::add_ded_rgd(UINT16 op) { m_icount -= 24+12; { ADD_M(DED,RGD); } } +void t11_device::add_ded_in(UINT16 op) { m_icount -= 24+12; { ADD_M(DED,IN); } } +void t11_device::add_ded_ind(UINT16 op) { m_icount -= 24+18; { ADD_M(DED,IND); } } +void t11_device::add_ded_de(UINT16 op) { m_icount -= 24+15; { ADD_M(DED,DE); } } +void t11_device::add_ded_ded(UINT16 op) { m_icount -= 24+21; { ADD_M(DED,DED); } } +void t11_device::add_ded_ix(UINT16 op) { m_icount -= 24+21; { ADD_M(DED,IX); } } +void t11_device::add_ded_ixd(UINT16 op) { m_icount -= 24+27; { ADD_M(DED,IXD); } } +void t11_device::add_ix_rg(UINT16 op) { m_icount -= 24+ 3; { ADD_X(IX,RG); } } +void t11_device::add_ix_rgd(UINT16 op) { m_icount -= 24+12; { ADD_M(IX,RGD); } } +void t11_device::add_ix_in(UINT16 op) { m_icount -= 24+12; { ADD_M(IX,IN); } } +void t11_device::add_ix_ind(UINT16 op) { m_icount -= 24+18; { ADD_M(IX,IND); } } +void t11_device::add_ix_de(UINT16 op) { m_icount -= 24+15; { ADD_M(IX,DE); } } +void t11_device::add_ix_ded(UINT16 op) { m_icount -= 24+21; { ADD_M(IX,DED); } } +void t11_device::add_ix_ix(UINT16 op) { m_icount -= 24+21; { ADD_M(IX,IX); } } +void t11_device::add_ix_ixd(UINT16 op) { m_icount -= 24+27; { ADD_M(IX,IXD); } } +void t11_device::add_ixd_rg(UINT16 op) { m_icount -= 30+ 3; { ADD_X(IXD,RG); } } +void t11_device::add_ixd_rgd(UINT16 op) { m_icount -= 30+12; { ADD_M(IXD,RGD); } } +void t11_device::add_ixd_in(UINT16 op) { m_icount -= 30+12; { ADD_M(IXD,IN); } } +void t11_device::add_ixd_ind(UINT16 op) { m_icount -= 30+18; { ADD_M(IXD,IND); } } +void t11_device::add_ixd_de(UINT16 op) { m_icount -= 30+15; { ADD_M(IXD,DE); } } +void t11_device::add_ixd_ded(UINT16 op) { m_icount -= 30+21; { ADD_M(IXD,DED); } } +void t11_device::add_ixd_ix(UINT16 op) { m_icount -= 30+21; { ADD_M(IXD,IX); } } +void t11_device::add_ixd_ixd(UINT16 op) { m_icount -= 30+27; { ADD_M(IXD,IXD); } } + +void t11_device::xor_rg(UINT16 op) { m_icount -= 12; { XOR_R(RG); } } +void t11_device::xor_rgd(UINT16 op) { m_icount -= 21; { XOR_M(RGD); } } +void t11_device::xor_in(UINT16 op) { m_icount -= 21; { XOR_M(IN); } } +void t11_device::xor_ind(UINT16 op) { m_icount -= 27; { XOR_M(IND); } } +void t11_device::xor_de(UINT16 op) { m_icount -= 24; { XOR_M(DE); } } +void t11_device::xor_ded(UINT16 op) { m_icount -= 30; { XOR_M(DED); } } +void t11_device::xor_ix(UINT16 op) { m_icount -= 30; { XOR_M(IX); } } +void t11_device::xor_ixd(UINT16 op) { m_icount -= 36; { XOR_M(IXD); } } + +void t11_device::sob(UINT16 op) +{ + int sreg, source; + + m_icount -= 18; + GET_SREG; source = REGD(sreg); + source -= 1; + REGW(sreg) = source; + if (source) + PC -= 2 * (op & 0x3f); +} + +void t11_device::bpl(UINT16 op) { m_icount -= 12; { BR(!GET_N); } } +void t11_device::bmi(UINT16 op) { m_icount -= 12; { BR( GET_N); } } +void t11_device::bhi(UINT16 op) { m_icount -= 12; { BR(!GET_C && !GET_Z); } } +void t11_device::blos(UINT16 op) { m_icount -= 12; { BR( GET_C || GET_Z); } } +void t11_device::bvc(UINT16 op) { m_icount -= 12; { BR(!GET_V); } } +void t11_device::bvs(UINT16 op) { m_icount -= 12; { BR( GET_V); } } +void t11_device::bcc(UINT16 op) { m_icount -= 12; { BR(!GET_C); } } +void t11_device::bcs(UINT16 op) { m_icount -= 12; { BR( GET_C); } } + +void t11_device::emt(UINT16 op) +{ + m_icount -= 48; + PUSH(PSW); + PUSH(PC); + PC = RWORD(0x18); + PSW = RWORD(0x1a); + t11_check_irqs(); +} + +void t11_device::trap(UINT16 op) +{ + m_icount -= 48; + PUSH(PSW); + PUSH(PC); + PC = RWORD(0x1c); + PSW = RWORD(0x1e); + t11_check_irqs(); +} + +void t11_device::clrb_rg(UINT16 op) { m_icount -= 12; { CLRB_R(RG); } } +void t11_device::clrb_rgd(UINT16 op) { m_icount -= 21; { CLRB_M(RGD); } } +void t11_device::clrb_in(UINT16 op) { m_icount -= 21; { CLRB_M(IN); } } +void t11_device::clrb_ind(UINT16 op) { m_icount -= 27; { CLRB_M(IND); } } +void t11_device::clrb_de(UINT16 op) { m_icount -= 24; { CLRB_M(DE); } } +void t11_device::clrb_ded(UINT16 op) { m_icount -= 30; { CLRB_M(DED); } } +void t11_device::clrb_ix(UINT16 op) { m_icount -= 30; { CLRB_M(IX); } } +void t11_device::clrb_ixd(UINT16 op) { m_icount -= 36; { CLRB_M(IXD); } } + +void t11_device::comb_rg(UINT16 op) { m_icount -= 12; { COMB_R(RG); } } +void t11_device::comb_rgd(UINT16 op) { m_icount -= 21; { COMB_M(RGD); } } +void t11_device::comb_in(UINT16 op) { m_icount -= 21; { COMB_M(IN); } } +void t11_device::comb_ind(UINT16 op) { m_icount -= 27; { COMB_M(IND); } } +void t11_device::comb_de(UINT16 op) { m_icount -= 24; { COMB_M(DE); } } +void t11_device::comb_ded(UINT16 op) { m_icount -= 30; { COMB_M(DED); } } +void t11_device::comb_ix(UINT16 op) { m_icount -= 30; { COMB_M(IX); } } +void t11_device::comb_ixd(UINT16 op) { m_icount -= 36; { COMB_M(IXD); } } + +void t11_device::incb_rg(UINT16 op) { m_icount -= 12; { INCB_R(RG); } } +void t11_device::incb_rgd(UINT16 op) { m_icount -= 21; { INCB_M(RGD); } } +void t11_device::incb_in(UINT16 op) { m_icount -= 21; { INCB_M(IN); } } +void t11_device::incb_ind(UINT16 op) { m_icount -= 27; { INCB_M(IND); } } +void t11_device::incb_de(UINT16 op) { m_icount -= 24; { INCB_M(DE); } } +void t11_device::incb_ded(UINT16 op) { m_icount -= 30; { INCB_M(DED); } } +void t11_device::incb_ix(UINT16 op) { m_icount -= 30; { INCB_M(IX); } } +void t11_device::incb_ixd(UINT16 op) { m_icount -= 36; { INCB_M(IXD); } } + +void t11_device::decb_rg(UINT16 op) { m_icount -= 12; { DECB_R(RG); } } +void t11_device::decb_rgd(UINT16 op) { m_icount -= 21; { DECB_M(RGD); } } +void t11_device::decb_in(UINT16 op) { m_icount -= 21; { DECB_M(IN); } } +void t11_device::decb_ind(UINT16 op) { m_icount -= 27; { DECB_M(IND); } } +void t11_device::decb_de(UINT16 op) { m_icount -= 24; { DECB_M(DE); } } +void t11_device::decb_ded(UINT16 op) { m_icount -= 30; { DECB_M(DED); } } +void t11_device::decb_ix(UINT16 op) { m_icount -= 30; { DECB_M(IX); } } +void t11_device::decb_ixd(UINT16 op) { m_icount -= 36; { DECB_M(IXD); } } + +void t11_device::negb_rg(UINT16 op) { m_icount -= 12; { NEGB_R(RG); } } +void t11_device::negb_rgd(UINT16 op) { m_icount -= 21; { NEGB_M(RGD); } } +void t11_device::negb_in(UINT16 op) { m_icount -= 21; { NEGB_M(IN); } } +void t11_device::negb_ind(UINT16 op) { m_icount -= 27; { NEGB_M(IND); } } +void t11_device::negb_de(UINT16 op) { m_icount -= 24; { NEGB_M(DE); } } +void t11_device::negb_ded(UINT16 op) { m_icount -= 30; { NEGB_M(DED); } } +void t11_device::negb_ix(UINT16 op) { m_icount -= 30; { NEGB_M(IX); } } +void t11_device::negb_ixd(UINT16 op) { m_icount -= 36; { NEGB_M(IXD); } } + +void t11_device::adcb_rg(UINT16 op) { m_icount -= 12; { ADCB_R(RG); } } +void t11_device::adcb_rgd(UINT16 op) { m_icount -= 21; { ADCB_M(RGD); } } +void t11_device::adcb_in(UINT16 op) { m_icount -= 21; { ADCB_M(IN); } } +void t11_device::adcb_ind(UINT16 op) { m_icount -= 27; { ADCB_M(IND); } } +void t11_device::adcb_de(UINT16 op) { m_icount -= 24; { ADCB_M(DE); } } +void t11_device::adcb_ded(UINT16 op) { m_icount -= 30; { ADCB_M(DED); } } +void t11_device::adcb_ix(UINT16 op) { m_icount -= 30; { ADCB_M(IX); } } +void t11_device::adcb_ixd(UINT16 op) { m_icount -= 36; { ADCB_M(IXD); } } + +void t11_device::sbcb_rg(UINT16 op) { m_icount -= 12; { SBCB_R(RG); } } +void t11_device::sbcb_rgd(UINT16 op) { m_icount -= 21; { SBCB_M(RGD); } } +void t11_device::sbcb_in(UINT16 op) { m_icount -= 21; { SBCB_M(IN); } } +void t11_device::sbcb_ind(UINT16 op) { m_icount -= 27; { SBCB_M(IND); } } +void t11_device::sbcb_de(UINT16 op) { m_icount -= 24; { SBCB_M(DE); } } +void t11_device::sbcb_ded(UINT16 op) { m_icount -= 30; { SBCB_M(DED); } } +void t11_device::sbcb_ix(UINT16 op) { m_icount -= 30; { SBCB_M(IX); } } +void t11_device::sbcb_ixd(UINT16 op) { m_icount -= 36; { SBCB_M(IXD); } } + +void t11_device::tstb_rg(UINT16 op) { m_icount -= 12; { TSTB_R(RG); } } +void t11_device::tstb_rgd(UINT16 op) { m_icount -= 18; { TSTB_M(RGD); } } +void t11_device::tstb_in(UINT16 op) { m_icount -= 18; { TSTB_M(IN); } } +void t11_device::tstb_ind(UINT16 op) { m_icount -= 24; { TSTB_M(IND); } } +void t11_device::tstb_de(UINT16 op) { m_icount -= 21; { TSTB_M(DE); } } +void t11_device::tstb_ded(UINT16 op) { m_icount -= 27; { TSTB_M(DED); } } +void t11_device::tstb_ix(UINT16 op) { m_icount -= 27; { TSTB_M(IX); } } +void t11_device::tstb_ixd(UINT16 op) { m_icount -= 33; { TSTB_M(IXD); } } + +void t11_device::rorb_rg(UINT16 op) { m_icount -= 12; { RORB_R(RG); } } +void t11_device::rorb_rgd(UINT16 op) { m_icount -= 21; { RORB_M(RGD); } } +void t11_device::rorb_in(UINT16 op) { m_icount -= 21; { RORB_M(IN); } } +void t11_device::rorb_ind(UINT16 op) { m_icount -= 27; { RORB_M(IND); } } +void t11_device::rorb_de(UINT16 op) { m_icount -= 24; { RORB_M(DE); } } +void t11_device::rorb_ded(UINT16 op) { m_icount -= 30; { RORB_M(DED); } } +void t11_device::rorb_ix(UINT16 op) { m_icount -= 30; { RORB_M(IX); } } +void t11_device::rorb_ixd(UINT16 op) { m_icount -= 36; { RORB_M(IXD); } } + +void t11_device::rolb_rg(UINT16 op) { m_icount -= 12; { ROLB_R(RG); } } +void t11_device::rolb_rgd(UINT16 op) { m_icount -= 21; { ROLB_M(RGD); } } +void t11_device::rolb_in(UINT16 op) { m_icount -= 21; { ROLB_M(IN); } } +void t11_device::rolb_ind(UINT16 op) { m_icount -= 27; { ROLB_M(IND); } } +void t11_device::rolb_de(UINT16 op) { m_icount -= 24; { ROLB_M(DE); } } +void t11_device::rolb_ded(UINT16 op) { m_icount -= 30; { ROLB_M(DED); } } +void t11_device::rolb_ix(UINT16 op) { m_icount -= 30; { ROLB_M(IX); } } +void t11_device::rolb_ixd(UINT16 op) { m_icount -= 36; { ROLB_M(IXD); } } + +void t11_device::asrb_rg(UINT16 op) { m_icount -= 12; { ASRB_R(RG); } } +void t11_device::asrb_rgd(UINT16 op) { m_icount -= 21; { ASRB_M(RGD); } } +void t11_device::asrb_in(UINT16 op) { m_icount -= 21; { ASRB_M(IN); } } +void t11_device::asrb_ind(UINT16 op) { m_icount -= 27; { ASRB_M(IND); } } +void t11_device::asrb_de(UINT16 op) { m_icount -= 24; { ASRB_M(DE); } } +void t11_device::asrb_ded(UINT16 op) { m_icount -= 30; { ASRB_M(DED); } } +void t11_device::asrb_ix(UINT16 op) { m_icount -= 30; { ASRB_M(IX); } } +void t11_device::asrb_ixd(UINT16 op) { m_icount -= 36; { ASRB_M(IXD); } } + +void t11_device::aslb_rg(UINT16 op) { m_icount -= 12; { ASLB_R(RG); } } +void t11_device::aslb_rgd(UINT16 op) { m_icount -= 21; { ASLB_M(RGD); } } +void t11_device::aslb_in(UINT16 op) { m_icount -= 21; { ASLB_M(IN); } } +void t11_device::aslb_ind(UINT16 op) { m_icount -= 27; { ASLB_M(IND); } } +void t11_device::aslb_de(UINT16 op) { m_icount -= 24; { ASLB_M(DE); } } +void t11_device::aslb_ded(UINT16 op) { m_icount -= 30; { ASLB_M(DED); } } +void t11_device::aslb_ix(UINT16 op) { m_icount -= 30; { ASLB_M(IX); } } +void t11_device::aslb_ixd(UINT16 op) { m_icount -= 36; { ASLB_M(IXD); } } + +void t11_device::mtps_rg(UINT16 op) { m_icount -= 24; { MTPS_R(RG); } } +void t11_device::mtps_rgd(UINT16 op) { m_icount -= 30; { MTPS_M(RGD); } } +void t11_device::mtps_in(UINT16 op) { m_icount -= 30; { MTPS_M(IN); } } +void t11_device::mtps_ind(UINT16 op) { m_icount -= 36; { MTPS_M(IND); } } +void t11_device::mtps_de(UINT16 op) { m_icount -= 33; { MTPS_M(DE); } } +void t11_device::mtps_ded(UINT16 op) { m_icount -= 39; { MTPS_M(DED); } } +void t11_device::mtps_ix(UINT16 op) { m_icount -= 39; { MTPS_M(IX); } } +void t11_device::mtps_ixd(UINT16 op) { m_icount -= 45; { MTPS_M(IXD); } } + +void t11_device::mfps_rg(UINT16 op) { m_icount -= 12; { MFPS_R(RG); } } +void t11_device::mfps_rgd(UINT16 op) { m_icount -= 21; { MFPS_M(RGD); } } +void t11_device::mfps_in(UINT16 op) { m_icount -= 21; { MFPS_M(IN); } } +void t11_device::mfps_ind(UINT16 op) { m_icount -= 27; { MFPS_M(IND); } } +void t11_device::mfps_de(UINT16 op) { m_icount -= 24; { MFPS_M(DE); } } +void t11_device::mfps_ded(UINT16 op) { m_icount -= 30; { MFPS_M(DED); } } +void t11_device::mfps_ix(UINT16 op) { m_icount -= 30; { MFPS_M(IX); } } +void t11_device::mfps_ixd(UINT16 op) { m_icount -= 36; { MFPS_M(IXD); } } + +void t11_device::movb_rg_rg(UINT16 op) { m_icount -= 9+ 3; { MOVB_R(RG,RG); } } +void t11_device::movb_rg_rgd(UINT16 op) { m_icount -= 9+12; { MOVB_M(RG,RGD); } } +void t11_device::movb_rg_in(UINT16 op) { m_icount -= 9+12; { MOVB_M(RG,IN); } } +void t11_device::movb_rg_ind(UINT16 op) { m_icount -= 9+18; { MOVB_M(RG,IND); } } +void t11_device::movb_rg_de(UINT16 op) { m_icount -= 9+15; { MOVB_M(RG,DE); } } +void t11_device::movb_rg_ded(UINT16 op) { m_icount -= 9+21; { MOVB_M(RG,DED); } } +void t11_device::movb_rg_ix(UINT16 op) { m_icount -= 9+21; { MOVB_M(RG,IX); } } +void t11_device::movb_rg_ixd(UINT16 op) { m_icount -= 9+27; { MOVB_M(RG,IXD); } } +void t11_device::movb_rgd_rg(UINT16 op) { m_icount -= 15+ 3; { MOVB_X(RGD,RG); } } +void t11_device::movb_rgd_rgd(UINT16 op) { m_icount -= 15+12; { MOVB_M(RGD,RGD); } } +void t11_device::movb_rgd_in(UINT16 op) { m_icount -= 15+12; { MOVB_M(RGD,IN); } } +void t11_device::movb_rgd_ind(UINT16 op) { m_icount -= 15+18; { MOVB_M(RGD,IND); } } +void t11_device::movb_rgd_de(UINT16 op) { m_icount -= 15+15; { MOVB_M(RGD,DE); } } +void t11_device::movb_rgd_ded(UINT16 op) { m_icount -= 15+21; { MOVB_M(RGD,DED); } } +void t11_device::movb_rgd_ix(UINT16 op) { m_icount -= 15+21; { MOVB_M(RGD,IX); } } +void t11_device::movb_rgd_ixd(UINT16 op) { m_icount -= 15+27; { MOVB_M(RGD,IXD); } } +void t11_device::movb_in_rg(UINT16 op) { m_icount -= 15+ 3; { MOVB_X(IN,RG); } } +void t11_device::movb_in_rgd(UINT16 op) { m_icount -= 15+12; { MOVB_M(IN,RGD); } } +void t11_device::movb_in_in(UINT16 op) { m_icount -= 15+12; { MOVB_M(IN,IN); } } +void t11_device::movb_in_ind(UINT16 op) { m_icount -= 15+18; { MOVB_M(IN,IND); } } +void t11_device::movb_in_de(UINT16 op) { m_icount -= 15+15; { MOVB_M(IN,DE); } } +void t11_device::movb_in_ded(UINT16 op) { m_icount -= 15+21; { MOVB_M(IN,DED); } } +void t11_device::movb_in_ix(UINT16 op) { m_icount -= 15+21; { MOVB_M(IN,IX); } } +void t11_device::movb_in_ixd(UINT16 op) { m_icount -= 15+27; { MOVB_M(IN,IXD); } } +void t11_device::movb_ind_rg(UINT16 op) { m_icount -= 21+ 3; { MOVB_X(IND,RG); } } +void t11_device::movb_ind_rgd(UINT16 op) { m_icount -= 21+12; { MOVB_M(IND,RGD); } } +void t11_device::movb_ind_in(UINT16 op) { m_icount -= 21+12; { MOVB_M(IND,IN); } } +void t11_device::movb_ind_ind(UINT16 op) { m_icount -= 21+18; { MOVB_M(IND,IND); } } +void t11_device::movb_ind_de(UINT16 op) { m_icount -= 21+15; { MOVB_M(IND,DE); } } +void t11_device::movb_ind_ded(UINT16 op) { m_icount -= 21+21; { MOVB_M(IND,DED); } } +void t11_device::movb_ind_ix(UINT16 op) { m_icount -= 21+21; { MOVB_M(IND,IX); } } +void t11_device::movb_ind_ixd(UINT16 op) { m_icount -= 21+27; { MOVB_M(IND,IXD); } } +void t11_device::movb_de_rg(UINT16 op) { m_icount -= 18+ 3; { MOVB_X(DE,RG); } } +void t11_device::movb_de_rgd(UINT16 op) { m_icount -= 18+12; { MOVB_M(DE,RGD); } } +void t11_device::movb_de_in(UINT16 op) { m_icount -= 18+12; { MOVB_M(DE,IN); } } +void t11_device::movb_de_ind(UINT16 op) { m_icount -= 18+18; { MOVB_M(DE,IND); } } +void t11_device::movb_de_de(UINT16 op) { m_icount -= 18+15; { MOVB_M(DE,DE); } } +void t11_device::movb_de_ded(UINT16 op) { m_icount -= 18+21; { MOVB_M(DE,DED); } } +void t11_device::movb_de_ix(UINT16 op) { m_icount -= 18+21; { MOVB_M(DE,IX); } } +void t11_device::movb_de_ixd(UINT16 op) { m_icount -= 18+27; { MOVB_M(DE,IXD); } } +void t11_device::movb_ded_rg(UINT16 op) { m_icount -= 24+ 3; { MOVB_X(DED,RG); } } +void t11_device::movb_ded_rgd(UINT16 op) { m_icount -= 24+12; { MOVB_M(DED,RGD); } } +void t11_device::movb_ded_in(UINT16 op) { m_icount -= 24+12; { MOVB_M(DED,IN); } } +void t11_device::movb_ded_ind(UINT16 op) { m_icount -= 24+18; { MOVB_M(DED,IND); } } +void t11_device::movb_ded_de(UINT16 op) { m_icount -= 24+15; { MOVB_M(DED,DE); } } +void t11_device::movb_ded_ded(UINT16 op) { m_icount -= 24+21; { MOVB_M(DED,DED); } } +void t11_device::movb_ded_ix(UINT16 op) { m_icount -= 24+21; { MOVB_M(DED,IX); } } +void t11_device::movb_ded_ixd(UINT16 op) { m_icount -= 24+27; { MOVB_M(DED,IXD); } } +void t11_device::movb_ix_rg(UINT16 op) { m_icount -= 24+ 3; { MOVB_X(IX,RG); } } +void t11_device::movb_ix_rgd(UINT16 op) { m_icount -= 24+12; { MOVB_M(IX,RGD); } } +void t11_device::movb_ix_in(UINT16 op) { m_icount -= 24+12; { MOVB_M(IX,IN); } } +void t11_device::movb_ix_ind(UINT16 op) { m_icount -= 24+18; { MOVB_M(IX,IND); } } +void t11_device::movb_ix_de(UINT16 op) { m_icount -= 24+15; { MOVB_M(IX,DE); } } +void t11_device::movb_ix_ded(UINT16 op) { m_icount -= 24+21; { MOVB_M(IX,DED); } } +void t11_device::movb_ix_ix(UINT16 op) { m_icount -= 24+21; { MOVB_M(IX,IX); } } +void t11_device::movb_ix_ixd(UINT16 op) { m_icount -= 24+27; { MOVB_M(IX,IXD); } } +void t11_device::movb_ixd_rg(UINT16 op) { m_icount -= 30+ 3; { MOVB_X(IXD,RG); } } +void t11_device::movb_ixd_rgd(UINT16 op) { m_icount -= 30+12; { MOVB_M(IXD,RGD); } } +void t11_device::movb_ixd_in(UINT16 op) { m_icount -= 30+12; { MOVB_M(IXD,IN); } } +void t11_device::movb_ixd_ind(UINT16 op) { m_icount -= 30+18; { MOVB_M(IXD,IND); } } +void t11_device::movb_ixd_de(UINT16 op) { m_icount -= 30+15; { MOVB_M(IXD,DE); } } +void t11_device::movb_ixd_ded(UINT16 op) { m_icount -= 30+21; { MOVB_M(IXD,DED); } } +void t11_device::movb_ixd_ix(UINT16 op) { m_icount -= 30+21; { MOVB_M(IXD,IX); } } +void t11_device::movb_ixd_ixd(UINT16 op) { m_icount -= 30+27; { MOVB_M(IXD,IXD); } } + +void t11_device::cmpb_rg_rg(UINT16 op) { m_icount -= 9+ 3; { CMPB_R(RG,RG); } } +void t11_device::cmpb_rg_rgd(UINT16 op) { m_icount -= 9+ 9; { CMPB_M(RG,RGD); } } +void t11_device::cmpb_rg_in(UINT16 op) { m_icount -= 9+ 9; { CMPB_M(RG,IN); } } +void t11_device::cmpb_rg_ind(UINT16 op) { m_icount -= 9+15; { CMPB_M(RG,IND); } } +void t11_device::cmpb_rg_de(UINT16 op) { m_icount -= 9+12; { CMPB_M(RG,DE); } } +void t11_device::cmpb_rg_ded(UINT16 op) { m_icount -= 9+18; { CMPB_M(RG,DED); } } +void t11_device::cmpb_rg_ix(UINT16 op) { m_icount -= 9+18; { CMPB_M(RG,IX); } } +void t11_device::cmpb_rg_ixd(UINT16 op) { m_icount -= 9+24; { CMPB_M(RG,IXD); } } +void t11_device::cmpb_rgd_rg(UINT16 op) { m_icount -= 15+ 3; { CMPB_M(RGD,RG); } } +void t11_device::cmpb_rgd_rgd(UINT16 op) { m_icount -= 15+ 9; { CMPB_M(RGD,RGD); } } +void t11_device::cmpb_rgd_in(UINT16 op) { m_icount -= 15+ 9; { CMPB_M(RGD,IN); } } +void t11_device::cmpb_rgd_ind(UINT16 op) { m_icount -= 15+15; { CMPB_M(RGD,IND); } } +void t11_device::cmpb_rgd_de(UINT16 op) { m_icount -= 15+12; { CMPB_M(RGD,DE); } } +void t11_device::cmpb_rgd_ded(UINT16 op) { m_icount -= 15+18; { CMPB_M(RGD,DED); } } +void t11_device::cmpb_rgd_ix(UINT16 op) { m_icount -= 15+18; { CMPB_M(RGD,IX); } } +void t11_device::cmpb_rgd_ixd(UINT16 op) { m_icount -= 15+24; { CMPB_M(RGD,IXD); } } +void t11_device::cmpb_in_rg(UINT16 op) { m_icount -= 15+ 3; { CMPB_M(IN,RG); } } +void t11_device::cmpb_in_rgd(UINT16 op) { m_icount -= 15+ 9; { CMPB_M(IN,RGD); } } +void t11_device::cmpb_in_in(UINT16 op) { m_icount -= 15+ 9; { CMPB_M(IN,IN); } } +void t11_device::cmpb_in_ind(UINT16 op) { m_icount -= 15+15; { CMPB_M(IN,IND); } } +void t11_device::cmpb_in_de(UINT16 op) { m_icount -= 15+12; { CMPB_M(IN,DE); } } +void t11_device::cmpb_in_ded(UINT16 op) { m_icount -= 15+18; { CMPB_M(IN,DED); } } +void t11_device::cmpb_in_ix(UINT16 op) { m_icount -= 15+18; { CMPB_M(IN,IX); } } +void t11_device::cmpb_in_ixd(UINT16 op) { m_icount -= 15+24; { CMPB_M(IN,IXD); } } +void t11_device::cmpb_ind_rg(UINT16 op) { m_icount -= 21+ 3; { CMPB_M(IND,RG); } } +void t11_device::cmpb_ind_rgd(UINT16 op) { m_icount -= 21+ 9; { CMPB_M(IND,RGD); } } +void t11_device::cmpb_ind_in(UINT16 op) { m_icount -= 21+ 9; { CMPB_M(IND,IN); } } +void t11_device::cmpb_ind_ind(UINT16 op) { m_icount -= 21+15; { CMPB_M(IND,IND); } } +void t11_device::cmpb_ind_de(UINT16 op) { m_icount -= 21+12; { CMPB_M(IND,DE); } } +void t11_device::cmpb_ind_ded(UINT16 op) { m_icount -= 21+18; { CMPB_M(IND,DED); } } +void t11_device::cmpb_ind_ix(UINT16 op) { m_icount -= 21+18; { CMPB_M(IND,IX); } } +void t11_device::cmpb_ind_ixd(UINT16 op) { m_icount -= 21+24; { CMPB_M(IND,IXD); } } +void t11_device::cmpb_de_rg(UINT16 op) { m_icount -= 18+ 3; { CMPB_M(DE,RG); } } +void t11_device::cmpb_de_rgd(UINT16 op) { m_icount -= 18+ 9; { CMPB_M(DE,RGD); } } +void t11_device::cmpb_de_in(UINT16 op) { m_icount -= 18+ 9; { CMPB_M(DE,IN); } } +void t11_device::cmpb_de_ind(UINT16 op) { m_icount -= 18+15; { CMPB_M(DE,IND); } } +void t11_device::cmpb_de_de(UINT16 op) { m_icount -= 18+12; { CMPB_M(DE,DE); } } +void t11_device::cmpb_de_ded(UINT16 op) { m_icount -= 18+18; { CMPB_M(DE,DED); } } +void t11_device::cmpb_de_ix(UINT16 op) { m_icount -= 18+18; { CMPB_M(DE,IX); } } +void t11_device::cmpb_de_ixd(UINT16 op) { m_icount -= 18+24; { CMPB_M(DE,IXD); } } +void t11_device::cmpb_ded_rg(UINT16 op) { m_icount -= 24+ 3; { CMPB_M(DED,RG); } } +void t11_device::cmpb_ded_rgd(UINT16 op) { m_icount -= 24+ 9; { CMPB_M(DED,RGD); } } +void t11_device::cmpb_ded_in(UINT16 op) { m_icount -= 24+ 9; { CMPB_M(DED,IN); } } +void t11_device::cmpb_ded_ind(UINT16 op) { m_icount -= 24+15; { CMPB_M(DED,IND); } } +void t11_device::cmpb_ded_de(UINT16 op) { m_icount -= 24+12; { CMPB_M(DED,DE); } } +void t11_device::cmpb_ded_ded(UINT16 op) { m_icount -= 24+18; { CMPB_M(DED,DED); } } +void t11_device::cmpb_ded_ix(UINT16 op) { m_icount -= 24+18; { CMPB_M(DED,IX); } } +void t11_device::cmpb_ded_ixd(UINT16 op) { m_icount -= 24+24; { CMPB_M(DED,IXD); } } +void t11_device::cmpb_ix_rg(UINT16 op) { m_icount -= 24+ 3; { CMPB_M(IX,RG); } } +void t11_device::cmpb_ix_rgd(UINT16 op) { m_icount -= 24+ 9; { CMPB_M(IX,RGD); } } +void t11_device::cmpb_ix_in(UINT16 op) { m_icount -= 24+ 9; { CMPB_M(IX,IN); } } +void t11_device::cmpb_ix_ind(UINT16 op) { m_icount -= 24+15; { CMPB_M(IX,IND); } } +void t11_device::cmpb_ix_de(UINT16 op) { m_icount -= 24+12; { CMPB_M(IX,DE); } } +void t11_device::cmpb_ix_ded(UINT16 op) { m_icount -= 24+18; { CMPB_M(IX,DED); } } +void t11_device::cmpb_ix_ix(UINT16 op) { m_icount -= 24+18; { CMPB_M(IX,IX); } } +void t11_device::cmpb_ix_ixd(UINT16 op) { m_icount -= 24+24; { CMPB_M(IX,IXD); } } +void t11_device::cmpb_ixd_rg(UINT16 op) { m_icount -= 30+ 3; { CMPB_M(IXD,RG); } } +void t11_device::cmpb_ixd_rgd(UINT16 op) { m_icount -= 30+ 9; { CMPB_M(IXD,RGD); } } +void t11_device::cmpb_ixd_in(UINT16 op) { m_icount -= 30+ 9; { CMPB_M(IXD,IN); } } +void t11_device::cmpb_ixd_ind(UINT16 op) { m_icount -= 30+15; { CMPB_M(IXD,IND); } } +void t11_device::cmpb_ixd_de(UINT16 op) { m_icount -= 30+12; { CMPB_M(IXD,DE); } } +void t11_device::cmpb_ixd_ded(UINT16 op) { m_icount -= 30+18; { CMPB_M(IXD,DED); } } +void t11_device::cmpb_ixd_ix(UINT16 op) { m_icount -= 30+18; { CMPB_M(IXD,IX); } } +void t11_device::cmpb_ixd_ixd(UINT16 op) { m_icount -= 30+24; { CMPB_M(IXD,IXD); } } + +void t11_device::bitb_rg_rg(UINT16 op) { m_icount -= 9+ 3; { BITB_R(RG,RG); } } +void t11_device::bitb_rg_rgd(UINT16 op) { m_icount -= 9+ 9; { BITB_M(RG,RGD); } } +void t11_device::bitb_rg_in(UINT16 op) { m_icount -= 9+ 9; { BITB_M(RG,IN); } } +void t11_device::bitb_rg_ind(UINT16 op) { m_icount -= 9+15; { BITB_M(RG,IND); } } +void t11_device::bitb_rg_de(UINT16 op) { m_icount -= 9+12; { BITB_M(RG,DE); } } +void t11_device::bitb_rg_ded(UINT16 op) { m_icount -= 9+18; { BITB_M(RG,DED); } } +void t11_device::bitb_rg_ix(UINT16 op) { m_icount -= 9+18; { BITB_M(RG,IX); } } +void t11_device::bitb_rg_ixd(UINT16 op) { m_icount -= 9+24; { BITB_M(RG,IXD); } } +void t11_device::bitb_rgd_rg(UINT16 op) { m_icount -= 15+ 3; { BITB_M(RGD,RG); } } +void t11_device::bitb_rgd_rgd(UINT16 op) { m_icount -= 15+ 9; { BITB_M(RGD,RGD); } } +void t11_device::bitb_rgd_in(UINT16 op) { m_icount -= 15+ 9; { BITB_M(RGD,IN); } } +void t11_device::bitb_rgd_ind(UINT16 op) { m_icount -= 15+15; { BITB_M(RGD,IND); } } +void t11_device::bitb_rgd_de(UINT16 op) { m_icount -= 15+12; { BITB_M(RGD,DE); } } +void t11_device::bitb_rgd_ded(UINT16 op) { m_icount -= 15+18; { BITB_M(RGD,DED); } } +void t11_device::bitb_rgd_ix(UINT16 op) { m_icount -= 15+18; { BITB_M(RGD,IX); } } +void t11_device::bitb_rgd_ixd(UINT16 op) { m_icount -= 15+24; { BITB_M(RGD,IXD); } } +void t11_device::bitb_in_rg(UINT16 op) { m_icount -= 15+ 3; { BITB_M(IN,RG); } } +void t11_device::bitb_in_rgd(UINT16 op) { m_icount -= 15+ 9; { BITB_M(IN,RGD); } } +void t11_device::bitb_in_in(UINT16 op) { m_icount -= 15+ 9; { BITB_M(IN,IN); } } +void t11_device::bitb_in_ind(UINT16 op) { m_icount -= 15+15; { BITB_M(IN,IND); } } +void t11_device::bitb_in_de(UINT16 op) { m_icount -= 15+12; { BITB_M(IN,DE); } } +void t11_device::bitb_in_ded(UINT16 op) { m_icount -= 15+18; { BITB_M(IN,DED); } } +void t11_device::bitb_in_ix(UINT16 op) { m_icount -= 15+18; { BITB_M(IN,IX); } } +void t11_device::bitb_in_ixd(UINT16 op) { m_icount -= 15+24; { BITB_M(IN,IXD); } } +void t11_device::bitb_ind_rg(UINT16 op) { m_icount -= 21+ 3; { BITB_M(IND,RG); } } +void t11_device::bitb_ind_rgd(UINT16 op) { m_icount -= 21+ 9; { BITB_M(IND,RGD); } } +void t11_device::bitb_ind_in(UINT16 op) { m_icount -= 21+ 9; { BITB_M(IND,IN); } } +void t11_device::bitb_ind_ind(UINT16 op) { m_icount -= 21+15; { BITB_M(IND,IND); } } +void t11_device::bitb_ind_de(UINT16 op) { m_icount -= 21+12; { BITB_M(IND,DE); } } +void t11_device::bitb_ind_ded(UINT16 op) { m_icount -= 21+18; { BITB_M(IND,DED); } } +void t11_device::bitb_ind_ix(UINT16 op) { m_icount -= 21+18; { BITB_M(IND,IX); } } +void t11_device::bitb_ind_ixd(UINT16 op) { m_icount -= 21+24; { BITB_M(IND,IXD); } } +void t11_device::bitb_de_rg(UINT16 op) { m_icount -= 18+ 3; { BITB_M(DE,RG); } } +void t11_device::bitb_de_rgd(UINT16 op) { m_icount -= 18+ 9; { BITB_M(DE,RGD); } } +void t11_device::bitb_de_in(UINT16 op) { m_icount -= 18+ 9; { BITB_M(DE,IN); } } +void t11_device::bitb_de_ind(UINT16 op) { m_icount -= 18+15; { BITB_M(DE,IND); } } +void t11_device::bitb_de_de(UINT16 op) { m_icount -= 18+12; { BITB_M(DE,DE); } } +void t11_device::bitb_de_ded(UINT16 op) { m_icount -= 18+18; { BITB_M(DE,DED); } } +void t11_device::bitb_de_ix(UINT16 op) { m_icount -= 18+18; { BITB_M(DE,IX); } } +void t11_device::bitb_de_ixd(UINT16 op) { m_icount -= 18+24; { BITB_M(DE,IXD); } } +void t11_device::bitb_ded_rg(UINT16 op) { m_icount -= 24+ 3; { BITB_M(DED,RG); } } +void t11_device::bitb_ded_rgd(UINT16 op) { m_icount -= 24+ 9; { BITB_M(DED,RGD); } } +void t11_device::bitb_ded_in(UINT16 op) { m_icount -= 24+ 9; { BITB_M(DED,IN); } } +void t11_device::bitb_ded_ind(UINT16 op) { m_icount -= 24+15; { BITB_M(DED,IND); } } +void t11_device::bitb_ded_de(UINT16 op) { m_icount -= 24+12; { BITB_M(DED,DE); } } +void t11_device::bitb_ded_ded(UINT16 op) { m_icount -= 24+18; { BITB_M(DED,DED); } } +void t11_device::bitb_ded_ix(UINT16 op) { m_icount -= 24+18; { BITB_M(DED,IX); } } +void t11_device::bitb_ded_ixd(UINT16 op) { m_icount -= 24+24; { BITB_M(DED,IXD); } } +void t11_device::bitb_ix_rg(UINT16 op) { m_icount -= 24+ 3; { BITB_M(IX,RG); } } +void t11_device::bitb_ix_rgd(UINT16 op) { m_icount -= 24+ 9; { BITB_M(IX,RGD); } } +void t11_device::bitb_ix_in(UINT16 op) { m_icount -= 24+ 9; { BITB_M(IX,IN); } } +void t11_device::bitb_ix_ind(UINT16 op) { m_icount -= 24+15; { BITB_M(IX,IND); } } +void t11_device::bitb_ix_de(UINT16 op) { m_icount -= 24+12; { BITB_M(IX,DE); } } +void t11_device::bitb_ix_ded(UINT16 op) { m_icount -= 24+18; { BITB_M(IX,DED); } } +void t11_device::bitb_ix_ix(UINT16 op) { m_icount -= 24+18; { BITB_M(IX,IX); } } +void t11_device::bitb_ix_ixd(UINT16 op) { m_icount -= 24+24; { BITB_M(IX,IXD); } } +void t11_device::bitb_ixd_rg(UINT16 op) { m_icount -= 30+ 3; { BITB_M(IXD,RG); } } +void t11_device::bitb_ixd_rgd(UINT16 op) { m_icount -= 30+ 9; { BITB_M(IXD,RGD); } } +void t11_device::bitb_ixd_in(UINT16 op) { m_icount -= 30+ 9; { BITB_M(IXD,IN); } } +void t11_device::bitb_ixd_ind(UINT16 op) { m_icount -= 30+15; { BITB_M(IXD,IND); } } +void t11_device::bitb_ixd_de(UINT16 op) { m_icount -= 30+12; { BITB_M(IXD,DE); } } +void t11_device::bitb_ixd_ded(UINT16 op) { m_icount -= 30+18; { BITB_M(IXD,DED); } } +void t11_device::bitb_ixd_ix(UINT16 op) { m_icount -= 30+18; { BITB_M(IXD,IX); } } +void t11_device::bitb_ixd_ixd(UINT16 op) { m_icount -= 30+24; { BITB_M(IXD,IXD); } } + +void t11_device::bicb_rg_rg(UINT16 op) { m_icount -= 9+ 3; { BICB_R(RG,RG); } } +void t11_device::bicb_rg_rgd(UINT16 op) { m_icount -= 9+12; { BICB_M(RG,RGD); } } +void t11_device::bicb_rg_in(UINT16 op) { m_icount -= 9+12; { BICB_M(RG,IN); } } +void t11_device::bicb_rg_ind(UINT16 op) { m_icount -= 9+18; { BICB_M(RG,IND); } } +void t11_device::bicb_rg_de(UINT16 op) { m_icount -= 9+15; { BICB_M(RG,DE); } } +void t11_device::bicb_rg_ded(UINT16 op) { m_icount -= 9+21; { BICB_M(RG,DED); } } +void t11_device::bicb_rg_ix(UINT16 op) { m_icount -= 9+21; { BICB_M(RG,IX); } } +void t11_device::bicb_rg_ixd(UINT16 op) { m_icount -= 9+27; { BICB_M(RG,IXD); } } +void t11_device::bicb_rgd_rg(UINT16 op) { m_icount -= 15+ 3; { BICB_X(RGD,RG); } } +void t11_device::bicb_rgd_rgd(UINT16 op) { m_icount -= 15+12; { BICB_M(RGD,RGD); } } +void t11_device::bicb_rgd_in(UINT16 op) { m_icount -= 15+12; { BICB_M(RGD,IN); } } +void t11_device::bicb_rgd_ind(UINT16 op) { m_icount -= 15+18; { BICB_M(RGD,IND); } } +void t11_device::bicb_rgd_de(UINT16 op) { m_icount -= 15+15; { BICB_M(RGD,DE); } } +void t11_device::bicb_rgd_ded(UINT16 op) { m_icount -= 15+21; { BICB_M(RGD,DED); } } +void t11_device::bicb_rgd_ix(UINT16 op) { m_icount -= 15+21; { BICB_M(RGD,IX); } } +void t11_device::bicb_rgd_ixd(UINT16 op) { m_icount -= 15+27; { BICB_M(RGD,IXD); } } +void t11_device::bicb_in_rg(UINT16 op) { m_icount -= 15+ 3; { BICB_X(IN,RG); } } +void t11_device::bicb_in_rgd(UINT16 op) { m_icount -= 15+12; { BICB_M(IN,RGD); } } +void t11_device::bicb_in_in(UINT16 op) { m_icount -= 15+12; { BICB_M(IN,IN); } } +void t11_device::bicb_in_ind(UINT16 op) { m_icount -= 15+18; { BICB_M(IN,IND); } } +void t11_device::bicb_in_de(UINT16 op) { m_icount -= 15+15; { BICB_M(IN,DE); } } +void t11_device::bicb_in_ded(UINT16 op) { m_icount -= 15+21; { BICB_M(IN,DED); } } +void t11_device::bicb_in_ix(UINT16 op) { m_icount -= 15+21; { BICB_M(IN,IX); } } +void t11_device::bicb_in_ixd(UINT16 op) { m_icount -= 15+27; { BICB_M(IN,IXD); } } +void t11_device::bicb_ind_rg(UINT16 op) { m_icount -= 21+ 3; { BICB_X(IND,RG); } } +void t11_device::bicb_ind_rgd(UINT16 op) { m_icount -= 21+12; { BICB_M(IND,RGD); } } +void t11_device::bicb_ind_in(UINT16 op) { m_icount -= 21+12; { BICB_M(IND,IN); } } +void t11_device::bicb_ind_ind(UINT16 op) { m_icount -= 21+18; { BICB_M(IND,IND); } } +void t11_device::bicb_ind_de(UINT16 op) { m_icount -= 21+15; { BICB_M(IND,DE); } } +void t11_device::bicb_ind_ded(UINT16 op) { m_icount -= 21+21; { BICB_M(IND,DED); } } +void t11_device::bicb_ind_ix(UINT16 op) { m_icount -= 21+21; { BICB_M(IND,IX); } } +void t11_device::bicb_ind_ixd(UINT16 op) { m_icount -= 21+27; { BICB_M(IND,IXD); } } +void t11_device::bicb_de_rg(UINT16 op) { m_icount -= 18+ 3; { BICB_X(DE,RG); } } +void t11_device::bicb_de_rgd(UINT16 op) { m_icount -= 18+12; { BICB_M(DE,RGD); } } +void t11_device::bicb_de_in(UINT16 op) { m_icount -= 18+12; { BICB_M(DE,IN); } } +void t11_device::bicb_de_ind(UINT16 op) { m_icount -= 18+18; { BICB_M(DE,IND); } } +void t11_device::bicb_de_de(UINT16 op) { m_icount -= 18+15; { BICB_M(DE,DE); } } +void t11_device::bicb_de_ded(UINT16 op) { m_icount -= 18+21; { BICB_M(DE,DED); } } +void t11_device::bicb_de_ix(UINT16 op) { m_icount -= 18+21; { BICB_M(DE,IX); } } +void t11_device::bicb_de_ixd(UINT16 op) { m_icount -= 18+27; { BICB_M(DE,IXD); } } +void t11_device::bicb_ded_rg(UINT16 op) { m_icount -= 24+ 3; { BICB_X(DED,RG); } } +void t11_device::bicb_ded_rgd(UINT16 op) { m_icount -= 24+12; { BICB_M(DED,RGD); } } +void t11_device::bicb_ded_in(UINT16 op) { m_icount -= 24+12; { BICB_M(DED,IN); } } +void t11_device::bicb_ded_ind(UINT16 op) { m_icount -= 24+18; { BICB_M(DED,IND); } } +void t11_device::bicb_ded_de(UINT16 op) { m_icount -= 24+15; { BICB_M(DED,DE); } } +void t11_device::bicb_ded_ded(UINT16 op) { m_icount -= 24+21; { BICB_M(DED,DED); } } +void t11_device::bicb_ded_ix(UINT16 op) { m_icount -= 24+21; { BICB_M(DED,IX); } } +void t11_device::bicb_ded_ixd(UINT16 op) { m_icount -= 24+27; { BICB_M(DED,IXD); } } +void t11_device::bicb_ix_rg(UINT16 op) { m_icount -= 24+ 3; { BICB_X(IX,RG); } } +void t11_device::bicb_ix_rgd(UINT16 op) { m_icount -= 24+12; { BICB_M(IX,RGD); } } +void t11_device::bicb_ix_in(UINT16 op) { m_icount -= 24+12; { BICB_M(IX,IN); } } +void t11_device::bicb_ix_ind(UINT16 op) { m_icount -= 24+18; { BICB_M(IX,IND); } } +void t11_device::bicb_ix_de(UINT16 op) { m_icount -= 24+15; { BICB_M(IX,DE); } } +void t11_device::bicb_ix_ded(UINT16 op) { m_icount -= 24+21; { BICB_M(IX,DED); } } +void t11_device::bicb_ix_ix(UINT16 op) { m_icount -= 24+21; { BICB_M(IX,IX); } } +void t11_device::bicb_ix_ixd(UINT16 op) { m_icount -= 24+27; { BICB_M(IX,IXD); } } +void t11_device::bicb_ixd_rg(UINT16 op) { m_icount -= 30+ 3; { BICB_X(IXD,RG); } } +void t11_device::bicb_ixd_rgd(UINT16 op) { m_icount -= 30+12; { BICB_M(IXD,RGD); } } +void t11_device::bicb_ixd_in(UINT16 op) { m_icount -= 30+12; { BICB_M(IXD,IN); } } +void t11_device::bicb_ixd_ind(UINT16 op) { m_icount -= 30+18; { BICB_M(IXD,IND); } } +void t11_device::bicb_ixd_de(UINT16 op) { m_icount -= 30+15; { BICB_M(IXD,DE); } } +void t11_device::bicb_ixd_ded(UINT16 op) { m_icount -= 30+21; { BICB_M(IXD,DED); } } +void t11_device::bicb_ixd_ix(UINT16 op) { m_icount -= 30+21; { BICB_M(IXD,IX); } } +void t11_device::bicb_ixd_ixd(UINT16 op) { m_icount -= 30+27; { BICB_M(IXD,IXD); } } + +void t11_device::bisb_rg_rg(UINT16 op) { m_icount -= 9+ 3; { BISB_R(RG,RG); } } +void t11_device::bisb_rg_rgd(UINT16 op) { m_icount -= 9+12; { BISB_M(RG,RGD); } } +void t11_device::bisb_rg_in(UINT16 op) { m_icount -= 9+12; { BISB_M(RG,IN); } } +void t11_device::bisb_rg_ind(UINT16 op) { m_icount -= 9+18; { BISB_M(RG,IND); } } +void t11_device::bisb_rg_de(UINT16 op) { m_icount -= 9+15; { BISB_M(RG,DE); } } +void t11_device::bisb_rg_ded(UINT16 op) { m_icount -= 9+21; { BISB_M(RG,DED); } } +void t11_device::bisb_rg_ix(UINT16 op) { m_icount -= 9+21; { BISB_M(RG,IX); } } +void t11_device::bisb_rg_ixd(UINT16 op) { m_icount -= 9+27; { BISB_M(RG,IXD); } } +void t11_device::bisb_rgd_rg(UINT16 op) { m_icount -= 15+ 3; { BISB_X(RGD,RG); } } +void t11_device::bisb_rgd_rgd(UINT16 op) { m_icount -= 15+12; { BISB_M(RGD,RGD); } } +void t11_device::bisb_rgd_in(UINT16 op) { m_icount -= 15+12; { BISB_M(RGD,IN); } } +void t11_device::bisb_rgd_ind(UINT16 op) { m_icount -= 15+18; { BISB_M(RGD,IND); } } +void t11_device::bisb_rgd_de(UINT16 op) { m_icount -= 15+15; { BISB_M(RGD,DE); } } +void t11_device::bisb_rgd_ded(UINT16 op) { m_icount -= 15+21; { BISB_M(RGD,DED); } } +void t11_device::bisb_rgd_ix(UINT16 op) { m_icount -= 15+21; { BISB_M(RGD,IX); } } +void t11_device::bisb_rgd_ixd(UINT16 op) { m_icount -= 15+27; { BISB_M(RGD,IXD); } } +void t11_device::bisb_in_rg(UINT16 op) { m_icount -= 15+ 3; { BISB_X(IN,RG); } } +void t11_device::bisb_in_rgd(UINT16 op) { m_icount -= 15+12; { BISB_M(IN,RGD); } } +void t11_device::bisb_in_in(UINT16 op) { m_icount -= 15+12; { BISB_M(IN,IN); } } +void t11_device::bisb_in_ind(UINT16 op) { m_icount -= 15+18; { BISB_M(IN,IND); } } +void t11_device::bisb_in_de(UINT16 op) { m_icount -= 15+15; { BISB_M(IN,DE); } } +void t11_device::bisb_in_ded(UINT16 op) { m_icount -= 15+21; { BISB_M(IN,DED); } } +void t11_device::bisb_in_ix(UINT16 op) { m_icount -= 15+21; { BISB_M(IN,IX); } } +void t11_device::bisb_in_ixd(UINT16 op) { m_icount -= 15+27; { BISB_M(IN,IXD); } } +void t11_device::bisb_ind_rg(UINT16 op) { m_icount -= 21+ 3; { BISB_X(IND,RG); } } +void t11_device::bisb_ind_rgd(UINT16 op) { m_icount -= 21+12; { BISB_M(IND,RGD); } } +void t11_device::bisb_ind_in(UINT16 op) { m_icount -= 21+12; { BISB_M(IND,IN); } } +void t11_device::bisb_ind_ind(UINT16 op) { m_icount -= 21+18; { BISB_M(IND,IND); } } +void t11_device::bisb_ind_de(UINT16 op) { m_icount -= 21+15; { BISB_M(IND,DE); } } +void t11_device::bisb_ind_ded(UINT16 op) { m_icount -= 21+21; { BISB_M(IND,DED); } } +void t11_device::bisb_ind_ix(UINT16 op) { m_icount -= 21+21; { BISB_M(IND,IX); } } +void t11_device::bisb_ind_ixd(UINT16 op) { m_icount -= 21+27; { BISB_M(IND,IXD); } } +void t11_device::bisb_de_rg(UINT16 op) { m_icount -= 18+ 3; { BISB_X(DE,RG); } } +void t11_device::bisb_de_rgd(UINT16 op) { m_icount -= 18+12; { BISB_M(DE,RGD); } } +void t11_device::bisb_de_in(UINT16 op) { m_icount -= 18+12; { BISB_M(DE,IN); } } +void t11_device::bisb_de_ind(UINT16 op) { m_icount -= 18+18; { BISB_M(DE,IND); } } +void t11_device::bisb_de_de(UINT16 op) { m_icount -= 18+15; { BISB_M(DE,DE); } } +void t11_device::bisb_de_ded(UINT16 op) { m_icount -= 18+21; { BISB_M(DE,DED); } } +void t11_device::bisb_de_ix(UINT16 op) { m_icount -= 18+21; { BISB_M(DE,IX); } } +void t11_device::bisb_de_ixd(UINT16 op) { m_icount -= 18+27; { BISB_M(DE,IXD); } } +void t11_device::bisb_ded_rg(UINT16 op) { m_icount -= 24+ 3; { BISB_X(DED,RG); } } +void t11_device::bisb_ded_rgd(UINT16 op) { m_icount -= 24+12; { BISB_M(DED,RGD); } } +void t11_device::bisb_ded_in(UINT16 op) { m_icount -= 24+12; { BISB_M(DED,IN); } } +void t11_device::bisb_ded_ind(UINT16 op) { m_icount -= 24+18; { BISB_M(DED,IND); } } +void t11_device::bisb_ded_de(UINT16 op) { m_icount -= 24+15; { BISB_M(DED,DE); } } +void t11_device::bisb_ded_ded(UINT16 op) { m_icount -= 24+21; { BISB_M(DED,DED); } } +void t11_device::bisb_ded_ix(UINT16 op) { m_icount -= 24+21; { BISB_M(DED,IX); } } +void t11_device::bisb_ded_ixd(UINT16 op) { m_icount -= 24+27; { BISB_M(DED,IXD); } } +void t11_device::bisb_ix_rg(UINT16 op) { m_icount -= 24+ 3; { BISB_X(IX,RG); } } +void t11_device::bisb_ix_rgd(UINT16 op) { m_icount -= 24+12; { BISB_M(IX,RGD); } } +void t11_device::bisb_ix_in(UINT16 op) { m_icount -= 24+12; { BISB_M(IX,IN); } } +void t11_device::bisb_ix_ind(UINT16 op) { m_icount -= 24+18; { BISB_M(IX,IND); } } +void t11_device::bisb_ix_de(UINT16 op) { m_icount -= 24+15; { BISB_M(IX,DE); } } +void t11_device::bisb_ix_ded(UINT16 op) { m_icount -= 24+21; { BISB_M(IX,DED); } } +void t11_device::bisb_ix_ix(UINT16 op) { m_icount -= 24+21; { BISB_M(IX,IX); } } +void t11_device::bisb_ix_ixd(UINT16 op) { m_icount -= 24+27; { BISB_M(IX,IXD); } } +void t11_device::bisb_ixd_rg(UINT16 op) { m_icount -= 30+ 3; { BISB_X(IXD,RG); } } +void t11_device::bisb_ixd_rgd(UINT16 op) { m_icount -= 30+12; { BISB_M(IXD,RGD); } } +void t11_device::bisb_ixd_in(UINT16 op) { m_icount -= 30+12; { BISB_M(IXD,IN); } } +void t11_device::bisb_ixd_ind(UINT16 op) { m_icount -= 30+18; { BISB_M(IXD,IND); } } +void t11_device::bisb_ixd_de(UINT16 op) { m_icount -= 30+15; { BISB_M(IXD,DE); } } +void t11_device::bisb_ixd_ded(UINT16 op) { m_icount -= 30+21; { BISB_M(IXD,DED); } } +void t11_device::bisb_ixd_ix(UINT16 op) { m_icount -= 30+21; { BISB_M(IXD,IX); } } +void t11_device::bisb_ixd_ixd(UINT16 op) { m_icount -= 30+27; { BISB_M(IXD,IXD); } } + +void t11_device::sub_rg_rg(UINT16 op) { m_icount -= 9+ 3; { SUB_R(RG,RG); } } +void t11_device::sub_rg_rgd(UINT16 op) { m_icount -= 9+12; { SUB_M(RG,RGD); } } +void t11_device::sub_rg_in(UINT16 op) { m_icount -= 9+12; { SUB_M(RG,IN); } } +void t11_device::sub_rg_ind(UINT16 op) { m_icount -= 9+18; { SUB_M(RG,IND); } } +void t11_device::sub_rg_de(UINT16 op) { m_icount -= 9+15; { SUB_M(RG,DE); } } +void t11_device::sub_rg_ded(UINT16 op) { m_icount -= 9+21; { SUB_M(RG,DED); } } +void t11_device::sub_rg_ix(UINT16 op) { m_icount -= 9+21; { SUB_M(RG,IX); } } +void t11_device::sub_rg_ixd(UINT16 op) { m_icount -= 9+27; { SUB_M(RG,IXD); } } +void t11_device::sub_rgd_rg(UINT16 op) { m_icount -= 15+ 3; { SUB_X(RGD,RG); } } +void t11_device::sub_rgd_rgd(UINT16 op) { m_icount -= 15+12; { SUB_M(RGD,RGD); } } +void t11_device::sub_rgd_in(UINT16 op) { m_icount -= 15+12; { SUB_M(RGD,IN); } } +void t11_device::sub_rgd_ind(UINT16 op) { m_icount -= 15+18; { SUB_M(RGD,IND); } } +void t11_device::sub_rgd_de(UINT16 op) { m_icount -= 15+15; { SUB_M(RGD,DE); } } +void t11_device::sub_rgd_ded(UINT16 op) { m_icount -= 15+21; { SUB_M(RGD,DED); } } +void t11_device::sub_rgd_ix(UINT16 op) { m_icount -= 15+21; { SUB_M(RGD,IX); } } +void t11_device::sub_rgd_ixd(UINT16 op) { m_icount -= 15+27; { SUB_M(RGD,IXD); } } +void t11_device::sub_in_rg(UINT16 op) { m_icount -= 15+ 3; { SUB_X(IN,RG); } } +void t11_device::sub_in_rgd(UINT16 op) { m_icount -= 15+12; { SUB_M(IN,RGD); } } +void t11_device::sub_in_in(UINT16 op) { m_icount -= 15+12; { SUB_M(IN,IN); } } +void t11_device::sub_in_ind(UINT16 op) { m_icount -= 15+18; { SUB_M(IN,IND); } } +void t11_device::sub_in_de(UINT16 op) { m_icount -= 15+15; { SUB_M(IN,DE); } } +void t11_device::sub_in_ded(UINT16 op) { m_icount -= 15+21; { SUB_M(IN,DED); } } +void t11_device::sub_in_ix(UINT16 op) { m_icount -= 15+21; { SUB_M(IN,IX); } } +void t11_device::sub_in_ixd(UINT16 op) { m_icount -= 15+27; { SUB_M(IN,IXD); } } +void t11_device::sub_ind_rg(UINT16 op) { m_icount -= 21+ 3; { SUB_X(IND,RG); } } +void t11_device::sub_ind_rgd(UINT16 op) { m_icount -= 21+12; { SUB_M(IND,RGD); } } +void t11_device::sub_ind_in(UINT16 op) { m_icount -= 21+12; { SUB_M(IND,IN); } } +void t11_device::sub_ind_ind(UINT16 op) { m_icount -= 21+18; { SUB_M(IND,IND); } } +void t11_device::sub_ind_de(UINT16 op) { m_icount -= 21+15; { SUB_M(IND,DE); } } +void t11_device::sub_ind_ded(UINT16 op) { m_icount -= 21+21; { SUB_M(IND,DED); } } +void t11_device::sub_ind_ix(UINT16 op) { m_icount -= 21+21; { SUB_M(IND,IX); } } +void t11_device::sub_ind_ixd(UINT16 op) { m_icount -= 21+27; { SUB_M(IND,IXD); } } +void t11_device::sub_de_rg(UINT16 op) { m_icount -= 18+ 3; { SUB_X(DE,RG); } } +void t11_device::sub_de_rgd(UINT16 op) { m_icount -= 18+12; { SUB_M(DE,RGD); } } +void t11_device::sub_de_in(UINT16 op) { m_icount -= 18+12; { SUB_M(DE,IN); } } +void t11_device::sub_de_ind(UINT16 op) { m_icount -= 18+18; { SUB_M(DE,IND); } } +void t11_device::sub_de_de(UINT16 op) { m_icount -= 18+15; { SUB_M(DE,DE); } } +void t11_device::sub_de_ded(UINT16 op) { m_icount -= 18+21; { SUB_M(DE,DED); } } +void t11_device::sub_de_ix(UINT16 op) { m_icount -= 18+21; { SUB_M(DE,IX); } } +void t11_device::sub_de_ixd(UINT16 op) { m_icount -= 18+27; { SUB_M(DE,IXD); } } +void t11_device::sub_ded_rg(UINT16 op) { m_icount -= 24+ 3; { SUB_X(DED,RG); } } +void t11_device::sub_ded_rgd(UINT16 op) { m_icount -= 24+12; { SUB_M(DED,RGD); } } +void t11_device::sub_ded_in(UINT16 op) { m_icount -= 24+12; { SUB_M(DED,IN); } } +void t11_device::sub_ded_ind(UINT16 op) { m_icount -= 24+18; { SUB_M(DED,IND); } } +void t11_device::sub_ded_de(UINT16 op) { m_icount -= 24+15; { SUB_M(DED,DE); } } +void t11_device::sub_ded_ded(UINT16 op) { m_icount -= 24+21; { SUB_M(DED,DED); } } +void t11_device::sub_ded_ix(UINT16 op) { m_icount -= 24+21; { SUB_M(DED,IX); } } +void t11_device::sub_ded_ixd(UINT16 op) { m_icount -= 24+27; { SUB_M(DED,IXD); } } +void t11_device::sub_ix_rg(UINT16 op) { m_icount -= 24+ 3; { SUB_X(IX,RG); } } +void t11_device::sub_ix_rgd(UINT16 op) { m_icount -= 24+12; { SUB_M(IX,RGD); } } +void t11_device::sub_ix_in(UINT16 op) { m_icount -= 24+12; { SUB_M(IX,IN); } } +void t11_device::sub_ix_ind(UINT16 op) { m_icount -= 24+18; { SUB_M(IX,IND); } } +void t11_device::sub_ix_de(UINT16 op) { m_icount -= 24+15; { SUB_M(IX,DE); } } +void t11_device::sub_ix_ded(UINT16 op) { m_icount -= 24+21; { SUB_M(IX,DED); } } +void t11_device::sub_ix_ix(UINT16 op) { m_icount -= 24+21; { SUB_M(IX,IX); } } +void t11_device::sub_ix_ixd(UINT16 op) { m_icount -= 24+27; { SUB_M(IX,IXD); } } +void t11_device::sub_ixd_rg(UINT16 op) { m_icount -= 30+ 3; { SUB_X(IXD,RG); } } +void t11_device::sub_ixd_rgd(UINT16 op) { m_icount -= 30+12; { SUB_M(IXD,RGD); } } +void t11_device::sub_ixd_in(UINT16 op) { m_icount -= 30+12; { SUB_M(IXD,IN); } } +void t11_device::sub_ixd_ind(UINT16 op) { m_icount -= 30+18; { SUB_M(IXD,IND); } } +void t11_device::sub_ixd_de(UINT16 op) { m_icount -= 30+15; { SUB_M(IXD,DE); } } +void t11_device::sub_ixd_ded(UINT16 op) { m_icount -= 30+21; { SUB_M(IXD,DED); } } +void t11_device::sub_ixd_ix(UINT16 op) { m_icount -= 30+21; { SUB_M(IXD,IX); } } +void t11_device::sub_ixd_ixd(UINT16 op) { m_icount -= 30+27; { SUB_M(IXD,IXD); } } diff --git a/src/devices/cpu/t11/t11table.inc b/src/devices/cpu/t11/t11table.inc new file mode 100644 index 00000000000..14a5ec825f1 --- /dev/null +++ b/src/devices/cpu/t11/t11table.inc @@ -0,0 +1,1322 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*** t11: Portable DEC T-11 emulator ****************************************** + + Opcode table + +*****************************************************************************/ + +/* + +modes: + rg = register + rgd = register deferred + in = increment + ind = increment deferred + de = decrement + ded = decrement deferred + ix = index + ixd = index deferred + +*/ + +#define OP(x) &t11_device::x + +const t11_device::opcode_func t11_device::s_opcode_table[65536 >> 3] = +{ + /* 0x0000 */ + OP(op_0000), OP(halt), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + OP(illegal), OP(jmp_rgd), OP(jmp_in), OP(jmp_ind), OP(jmp_de), OP(jmp_ded), OP(jmp_ix), OP(jmp_ixd), + OP(rts), OP(illegal), OP(illegal), OP(illegal), OP(ccc), OP(ccc), OP(scc), OP(scc), + OP(swab_rg), OP(swab_rgd), OP(swab_in), OP(swab_ind), OP(swab_de), OP(swab_ded), OP(swab_ix), OP(swab_ixd), + /* 0x0100 */ + OP(br), OP(br), OP(br), OP(br), OP(br), OP(br), OP(br), OP(br), + OP(br), OP(br), OP(br), OP(br), OP(br), OP(br), OP(br), OP(br), + OP(br), OP(br), OP(br), OP(br), OP(br), OP(br), OP(br), OP(br), + OP(br), OP(br), OP(br), OP(br), OP(br), OP(br), OP(br), OP(br), + /* 0x0200 */ + OP(bne), OP(bne), OP(bne), OP(bne), OP(bne), OP(bne), OP(bne), OP(bne), + OP(bne), OP(bne), OP(bne), OP(bne), OP(bne), OP(bne), OP(bne), OP(bne), + OP(bne), OP(bne), OP(bne), OP(bne), OP(bne), OP(bne), OP(bne), OP(bne), + OP(bne), OP(bne), OP(bne), OP(bne), OP(bne), OP(bne), OP(bne), OP(bne), + /* 0x0300 */ + OP(beq), OP(beq), OP(beq), OP(beq), OP(beq), OP(beq), OP(beq), OP(beq), + OP(beq), OP(beq), OP(beq), OP(beq), OP(beq), OP(beq), OP(beq), OP(beq), + OP(beq), OP(beq), OP(beq), OP(beq), OP(beq), OP(beq), OP(beq), OP(beq), + OP(beq), OP(beq), OP(beq), OP(beq), OP(beq), OP(beq), OP(beq), OP(beq), + /* 0x0400 */ + OP(bge), OP(bge), OP(bge), OP(bge), OP(bge), OP(bge), OP(bge), OP(bge), + OP(bge), OP(bge), OP(bge), OP(bge), OP(bge), OP(bge), OP(bge), OP(bge), + OP(bge), OP(bge), OP(bge), OP(bge), OP(bge), OP(bge), OP(bge), OP(bge), + OP(bge), OP(bge), OP(bge), OP(bge), OP(bge), OP(bge), OP(bge), OP(bge), + /* 0x0500 */ + OP(blt), OP(blt), OP(blt), OP(blt), OP(blt), OP(blt), OP(blt), OP(blt), + OP(blt), OP(blt), OP(blt), OP(blt), OP(blt), OP(blt), OP(blt), OP(blt), + OP(blt), OP(blt), OP(blt), OP(blt), OP(blt), OP(blt), OP(blt), OP(blt), + OP(blt), OP(blt), OP(blt), OP(blt), OP(blt), OP(blt), OP(blt), OP(blt), + /* 0x0600 */ + OP(bgt), OP(bgt), OP(bgt), OP(bgt), OP(bgt), OP(bgt), OP(bgt), OP(bgt), + OP(bgt), OP(bgt), OP(bgt), OP(bgt), OP(bgt), OP(bgt), OP(bgt), OP(bgt), + OP(bgt), OP(bgt), OP(bgt), OP(bgt), OP(bgt), OP(bgt), OP(bgt), OP(bgt), + OP(bgt), OP(bgt), OP(bgt), OP(bgt), OP(bgt), OP(bgt), OP(bgt), OP(bgt), + /* 0x0700 */ + OP(ble), OP(ble), OP(ble), OP(ble), OP(ble), OP(ble), OP(ble), OP(ble), + OP(ble), OP(ble), OP(ble), OP(ble), OP(ble), OP(ble), OP(ble), OP(ble), + OP(ble), OP(ble), OP(ble), OP(ble), OP(ble), OP(ble), OP(ble), OP(ble), + OP(ble), OP(ble), OP(ble), OP(ble), OP(ble), OP(ble), OP(ble), OP(ble), + /* 0x0800 */ + OP(illegal), OP(jsr_rgd), OP(jsr_in), OP(jsr_ind), OP(jsr_de), OP(jsr_ded), OP(jsr_ix), OP(jsr_ixd), + OP(illegal), OP(jsr_rgd), OP(jsr_in), OP(jsr_ind), OP(jsr_de), OP(jsr_ded), OP(jsr_ix), OP(jsr_ixd), + OP(illegal), OP(jsr_rgd), OP(jsr_in), OP(jsr_ind), OP(jsr_de), OP(jsr_ded), OP(jsr_ix), OP(jsr_ixd), + OP(illegal), OP(jsr_rgd), OP(jsr_in), OP(jsr_ind), OP(jsr_de), OP(jsr_ded), OP(jsr_ix), OP(jsr_ixd), + /* 0x0900 */ + OP(illegal), OP(jsr_rgd), OP(jsr_in), OP(jsr_ind), OP(jsr_de), OP(jsr_ded), OP(jsr_ix), OP(jsr_ixd), + OP(illegal), OP(jsr_rgd), OP(jsr_in), OP(jsr_ind), OP(jsr_de), OP(jsr_ded), OP(jsr_ix), OP(jsr_ixd), + OP(illegal), OP(jsr_rgd), OP(jsr_in), OP(jsr_ind), OP(jsr_de), OP(jsr_ded), OP(jsr_ix), OP(jsr_ixd), + OP(illegal), OP(jsr_rgd), OP(jsr_in), OP(jsr_ind), OP(jsr_de), OP(jsr_ded), OP(jsr_ix), OP(jsr_ixd), + /* 0x0a00 */ + OP(clr_rg), OP(clr_rgd), OP(clr_in), OP(clr_ind), OP(clr_de), OP(clr_ded), OP(clr_ix), OP(clr_ixd), + OP(com_rg), OP(com_rgd), OP(com_in), OP(com_ind), OP(com_de), OP(com_ded), OP(com_ix), OP(com_ixd), + OP(inc_rg), OP(inc_rgd), OP(inc_in), OP(inc_ind), OP(inc_de), OP(inc_ded), OP(inc_ix), OP(inc_ixd), + OP(dec_rg), OP(dec_rgd), OP(dec_in), OP(dec_ind), OP(dec_de), OP(dec_ded), OP(dec_ix), OP(dec_ixd), + /* 0x0b00 */ + OP(neg_rg), OP(neg_rgd), OP(neg_in), OP(neg_ind), OP(neg_de), OP(neg_ded), OP(neg_ix), OP(neg_ixd), + OP(adc_rg), OP(adc_rgd), OP(adc_in), OP(adc_ind), OP(adc_de), OP(adc_ded), OP(adc_ix), OP(adc_ixd), + OP(sbc_rg), OP(sbc_rgd), OP(sbc_in), OP(sbc_ind), OP(sbc_de), OP(sbc_ded), OP(sbc_ix), OP(sbc_ixd), + OP(tst_rg), OP(tst_rgd), OP(tst_in), OP(tst_ind), OP(tst_de), OP(tst_ded), OP(tst_ix), OP(tst_ixd), + /* 0x0c00 */ + OP(ror_rg), OP(ror_rgd), OP(ror_in), OP(ror_ind), OP(ror_de), OP(ror_ded), OP(ror_ix), OP(ror_ixd), + OP(rol_rg), OP(rol_rgd), OP(rol_in), OP(rol_ind), OP(rol_de), OP(rol_ded), OP(rol_ix), OP(rol_ixd), + OP(asr_rg), OP(asr_rgd), OP(asr_in), OP(asr_ind), OP(asr_de), OP(asr_ded), OP(asr_ix), OP(asr_ixd), + OP(asl_rg), OP(asl_rgd), OP(asl_in), OP(asl_ind), OP(asl_de), OP(asl_ded), OP(asl_ix), OP(asl_ixd), + /* 0x0d00 */ + OP(mark), OP(mark), OP(mark), OP(mark), OP(mark), OP(mark), OP(mark), OP(mark), + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + OP(sxt_rg), OP(sxt_rgd), OP(sxt_in), OP(sxt_ind), OP(sxt_de), OP(sxt_ded), OP(sxt_ix), OP(sxt_ixd), + /* 0x0e00 */ + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + /* 0x0f00 */ + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + + /* 0x1000 */ + OP(mov_rg_rg), OP(mov_rg_rgd), OP(mov_rg_in), OP(mov_rg_ind), OP(mov_rg_de), OP(mov_rg_ded), OP(mov_rg_ix), OP(mov_rg_ixd), + OP(mov_rg_rg), OP(mov_rg_rgd), OP(mov_rg_in), OP(mov_rg_ind), OP(mov_rg_de), OP(mov_rg_ded), OP(mov_rg_ix), OP(mov_rg_ixd), + OP(mov_rg_rg), OP(mov_rg_rgd), OP(mov_rg_in), OP(mov_rg_ind), OP(mov_rg_de), OP(mov_rg_ded), OP(mov_rg_ix), OP(mov_rg_ixd), + OP(mov_rg_rg), OP(mov_rg_rgd), OP(mov_rg_in), OP(mov_rg_ind), OP(mov_rg_de), OP(mov_rg_ded), OP(mov_rg_ix), OP(mov_rg_ixd), + /* 0x1100 */ + OP(mov_rg_rg), OP(mov_rg_rgd), OP(mov_rg_in), OP(mov_rg_ind), OP(mov_rg_de), OP(mov_rg_ded), OP(mov_rg_ix), OP(mov_rg_ixd), + OP(mov_rg_rg), OP(mov_rg_rgd), OP(mov_rg_in), OP(mov_rg_ind), OP(mov_rg_de), OP(mov_rg_ded), OP(mov_rg_ix), OP(mov_rg_ixd), + OP(mov_rg_rg), OP(mov_rg_rgd), OP(mov_rg_in), OP(mov_rg_ind), OP(mov_rg_de), OP(mov_rg_ded), OP(mov_rg_ix), OP(mov_rg_ixd), + OP(mov_rg_rg), OP(mov_rg_rgd), OP(mov_rg_in), OP(mov_rg_ind), OP(mov_rg_de), OP(mov_rg_ded), OP(mov_rg_ix), OP(mov_rg_ixd), + /* 0x1200 */ + OP(mov_rgd_rg), OP(mov_rgd_rgd), OP(mov_rgd_in), OP(mov_rgd_ind), OP(mov_rgd_de), OP(mov_rgd_ded), OP(mov_rgd_ix), OP(mov_rgd_ixd), + OP(mov_rgd_rg), OP(mov_rgd_rgd), OP(mov_rgd_in), OP(mov_rgd_ind), OP(mov_rgd_de), OP(mov_rgd_ded), OP(mov_rgd_ix), OP(mov_rgd_ixd), + OP(mov_rgd_rg), OP(mov_rgd_rgd), OP(mov_rgd_in), OP(mov_rgd_ind), OP(mov_rgd_de), OP(mov_rgd_ded), OP(mov_rgd_ix), OP(mov_rgd_ixd), + OP(mov_rgd_rg), OP(mov_rgd_rgd), OP(mov_rgd_in), OP(mov_rgd_ind), OP(mov_rgd_de), OP(mov_rgd_ded), OP(mov_rgd_ix), OP(mov_rgd_ixd), + /* 0x1300 */ + OP(mov_rgd_rg), OP(mov_rgd_rgd), OP(mov_rgd_in), OP(mov_rgd_ind), OP(mov_rgd_de), OP(mov_rgd_ded), OP(mov_rgd_ix), OP(mov_rgd_ixd), + OP(mov_rgd_rg), OP(mov_rgd_rgd), OP(mov_rgd_in), OP(mov_rgd_ind), OP(mov_rgd_de), OP(mov_rgd_ded), OP(mov_rgd_ix), OP(mov_rgd_ixd), + OP(mov_rgd_rg), OP(mov_rgd_rgd), OP(mov_rgd_in), OP(mov_rgd_ind), OP(mov_rgd_de), OP(mov_rgd_ded), OP(mov_rgd_ix), OP(mov_rgd_ixd), + OP(mov_rgd_rg), OP(mov_rgd_rgd), OP(mov_rgd_in), OP(mov_rgd_ind), OP(mov_rgd_de), OP(mov_rgd_ded), OP(mov_rgd_ix), OP(mov_rgd_ixd), + /* 0x1400 */ + OP(mov_in_rg), OP(mov_in_rgd), OP(mov_in_in), OP(mov_in_ind), OP(mov_in_de), OP(mov_in_ded), OP(mov_in_ix), OP(mov_in_ixd), + OP(mov_in_rg), OP(mov_in_rgd), OP(mov_in_in), OP(mov_in_ind), OP(mov_in_de), OP(mov_in_ded), OP(mov_in_ix), OP(mov_in_ixd), + OP(mov_in_rg), OP(mov_in_rgd), OP(mov_in_in), OP(mov_in_ind), OP(mov_in_de), OP(mov_in_ded), OP(mov_in_ix), OP(mov_in_ixd), + OP(mov_in_rg), OP(mov_in_rgd), OP(mov_in_in), OP(mov_in_ind), OP(mov_in_de), OP(mov_in_ded), OP(mov_in_ix), OP(mov_in_ixd), + /* 0x1500 */ + OP(mov_in_rg), OP(mov_in_rgd), OP(mov_in_in), OP(mov_in_ind), OP(mov_in_de), OP(mov_in_ded), OP(mov_in_ix), OP(mov_in_ixd), + OP(mov_in_rg), OP(mov_in_rgd), OP(mov_in_in), OP(mov_in_ind), OP(mov_in_de), OP(mov_in_ded), OP(mov_in_ix), OP(mov_in_ixd), + OP(mov_in_rg), OP(mov_in_rgd), OP(mov_in_in), OP(mov_in_ind), OP(mov_in_de), OP(mov_in_ded), OP(mov_in_ix), OP(mov_in_ixd), + OP(mov_in_rg), OP(mov_in_rgd), OP(mov_in_in), OP(mov_in_ind), OP(mov_in_de), OP(mov_in_ded), OP(mov_in_ix), OP(mov_in_ixd), + /* 0x1600 */ + OP(mov_ind_rg), OP(mov_ind_rgd), OP(mov_ind_in), OP(mov_ind_ind), OP(mov_ind_de), OP(mov_ind_ded), OP(mov_ind_ix), OP(mov_ind_ixd), + OP(mov_ind_rg), OP(mov_ind_rgd), OP(mov_ind_in), OP(mov_ind_ind), OP(mov_ind_de), OP(mov_ind_ded), OP(mov_ind_ix), OP(mov_ind_ixd), + OP(mov_ind_rg), OP(mov_ind_rgd), OP(mov_ind_in), OP(mov_ind_ind), OP(mov_ind_de), OP(mov_ind_ded), OP(mov_ind_ix), OP(mov_ind_ixd), + OP(mov_ind_rg), OP(mov_ind_rgd), OP(mov_ind_in), OP(mov_ind_ind), OP(mov_ind_de), OP(mov_ind_ded), OP(mov_ind_ix), OP(mov_ind_ixd), + /* 0x1700 */ + OP(mov_ind_rg), OP(mov_ind_rgd), OP(mov_ind_in), OP(mov_ind_ind), OP(mov_ind_de), OP(mov_ind_ded), OP(mov_ind_ix), OP(mov_ind_ixd), + OP(mov_ind_rg), OP(mov_ind_rgd), OP(mov_ind_in), OP(mov_ind_ind), OP(mov_ind_de), OP(mov_ind_ded), OP(mov_ind_ix), OP(mov_ind_ixd), + OP(mov_ind_rg), OP(mov_ind_rgd), OP(mov_ind_in), OP(mov_ind_ind), OP(mov_ind_de), OP(mov_ind_ded), OP(mov_ind_ix), OP(mov_ind_ixd), + OP(mov_ind_rg), OP(mov_ind_rgd), OP(mov_ind_in), OP(mov_ind_ind), OP(mov_ind_de), OP(mov_ind_ded), OP(mov_ind_ix), OP(mov_ind_ixd), + /* 0x1800 */ + OP(mov_de_rg), OP(mov_de_rgd), OP(mov_de_in), OP(mov_de_ind), OP(mov_de_de), OP(mov_de_ded), OP(mov_de_ix), OP(mov_de_ixd), + OP(mov_de_rg), OP(mov_de_rgd), OP(mov_de_in), OP(mov_de_ind), OP(mov_de_de), OP(mov_de_ded), OP(mov_de_ix), OP(mov_de_ixd), + OP(mov_de_rg), OP(mov_de_rgd), OP(mov_de_in), OP(mov_de_ind), OP(mov_de_de), OP(mov_de_ded), OP(mov_de_ix), OP(mov_de_ixd), + OP(mov_de_rg), OP(mov_de_rgd), OP(mov_de_in), OP(mov_de_ind), OP(mov_de_de), OP(mov_de_ded), OP(mov_de_ix), OP(mov_de_ixd), + /* 0x1900 */ + OP(mov_de_rg), OP(mov_de_rgd), OP(mov_de_in), OP(mov_de_ind), OP(mov_de_de), OP(mov_de_ded), OP(mov_de_ix), OP(mov_de_ixd), + OP(mov_de_rg), OP(mov_de_rgd), OP(mov_de_in), OP(mov_de_ind), OP(mov_de_de), OP(mov_de_ded), OP(mov_de_ix), OP(mov_de_ixd), + OP(mov_de_rg), OP(mov_de_rgd), OP(mov_de_in), OP(mov_de_ind), OP(mov_de_de), OP(mov_de_ded), OP(mov_de_ix), OP(mov_de_ixd), + OP(mov_de_rg), OP(mov_de_rgd), OP(mov_de_in), OP(mov_de_ind), OP(mov_de_de), OP(mov_de_ded), OP(mov_de_ix), OP(mov_de_ixd), + /* 0x1a00 */ + OP(mov_ded_rg), OP(mov_ded_rgd), OP(mov_ded_in), OP(mov_ded_ind), OP(mov_ded_de), OP(mov_ded_ded), OP(mov_ded_ix), OP(mov_ded_ixd), + OP(mov_ded_rg), OP(mov_ded_rgd), OP(mov_ded_in), OP(mov_ded_ind), OP(mov_ded_de), OP(mov_ded_ded), OP(mov_ded_ix), OP(mov_ded_ixd), + OP(mov_ded_rg), OP(mov_ded_rgd), OP(mov_ded_in), OP(mov_ded_ind), OP(mov_ded_de), OP(mov_ded_ded), OP(mov_ded_ix), OP(mov_ded_ixd), + OP(mov_ded_rg), OP(mov_ded_rgd), OP(mov_ded_in), OP(mov_ded_ind), OP(mov_ded_de), OP(mov_ded_ded), OP(mov_ded_ix), OP(mov_ded_ixd), + /* 0x1b00 */ + OP(mov_ded_rg), OP(mov_ded_rgd), OP(mov_ded_in), OP(mov_ded_ind), OP(mov_ded_de), OP(mov_ded_ded), OP(mov_ded_ix), OP(mov_ded_ixd), + OP(mov_ded_rg), OP(mov_ded_rgd), OP(mov_ded_in), OP(mov_ded_ind), OP(mov_ded_de), OP(mov_ded_ded), OP(mov_ded_ix), OP(mov_ded_ixd), + OP(mov_ded_rg), OP(mov_ded_rgd), OP(mov_ded_in), OP(mov_ded_ind), OP(mov_ded_de), OP(mov_ded_ded), OP(mov_ded_ix), OP(mov_ded_ixd), + OP(mov_ded_rg), OP(mov_ded_rgd), OP(mov_ded_in), OP(mov_ded_ind), OP(mov_ded_de), OP(mov_ded_ded), OP(mov_ded_ix), OP(mov_ded_ixd), + /* 0x1c00 */ + OP(mov_ix_rg), OP(mov_ix_rgd), OP(mov_ix_in), OP(mov_ix_ind), OP(mov_ix_de), OP(mov_ix_ded), OP(mov_ix_ix), OP(mov_ix_ixd), + OP(mov_ix_rg), OP(mov_ix_rgd), OP(mov_ix_in), OP(mov_ix_ind), OP(mov_ix_de), OP(mov_ix_ded), OP(mov_ix_ix), OP(mov_ix_ixd), + OP(mov_ix_rg), OP(mov_ix_rgd), OP(mov_ix_in), OP(mov_ix_ind), OP(mov_ix_de), OP(mov_ix_ded), OP(mov_ix_ix), OP(mov_ix_ixd), + OP(mov_ix_rg), OP(mov_ix_rgd), OP(mov_ix_in), OP(mov_ix_ind), OP(mov_ix_de), OP(mov_ix_ded), OP(mov_ix_ix), OP(mov_ix_ixd), + /* 0x1d00 */ + OP(mov_ix_rg), OP(mov_ix_rgd), OP(mov_ix_in), OP(mov_ix_ind), OP(mov_ix_de), OP(mov_ix_ded), OP(mov_ix_ix), OP(mov_ix_ixd), + OP(mov_ix_rg), OP(mov_ix_rgd), OP(mov_ix_in), OP(mov_ix_ind), OP(mov_ix_de), OP(mov_ix_ded), OP(mov_ix_ix), OP(mov_ix_ixd), + OP(mov_ix_rg), OP(mov_ix_rgd), OP(mov_ix_in), OP(mov_ix_ind), OP(mov_ix_de), OP(mov_ix_ded), OP(mov_ix_ix), OP(mov_ix_ixd), + OP(mov_ix_rg), OP(mov_ix_rgd), OP(mov_ix_in), OP(mov_ix_ind), OP(mov_ix_de), OP(mov_ix_ded), OP(mov_ix_ix), OP(mov_ix_ixd), + /* 0x1e00 */ + OP(mov_ixd_rg), OP(mov_ixd_rgd), OP(mov_ixd_in), OP(mov_ixd_ind), OP(mov_ixd_de), OP(mov_ixd_ded), OP(mov_ixd_ix), OP(mov_ixd_ixd), + OP(mov_ixd_rg), OP(mov_ixd_rgd), OP(mov_ixd_in), OP(mov_ixd_ind), OP(mov_ixd_de), OP(mov_ixd_ded), OP(mov_ixd_ix), OP(mov_ixd_ixd), + OP(mov_ixd_rg), OP(mov_ixd_rgd), OP(mov_ixd_in), OP(mov_ixd_ind), OP(mov_ixd_de), OP(mov_ixd_ded), OP(mov_ixd_ix), OP(mov_ixd_ixd), + OP(mov_ixd_rg), OP(mov_ixd_rgd), OP(mov_ixd_in), OP(mov_ixd_ind), OP(mov_ixd_de), OP(mov_ixd_ded), OP(mov_ixd_ix), OP(mov_ixd_ixd), + /* 0x1f00 */ + OP(mov_ixd_rg), OP(mov_ixd_rgd), OP(mov_ixd_in), OP(mov_ixd_ind), OP(mov_ixd_de), OP(mov_ixd_ded), OP(mov_ixd_ix), OP(mov_ixd_ixd), + OP(mov_ixd_rg), OP(mov_ixd_rgd), OP(mov_ixd_in), OP(mov_ixd_ind), OP(mov_ixd_de), OP(mov_ixd_ded), OP(mov_ixd_ix), OP(mov_ixd_ixd), + OP(mov_ixd_rg), OP(mov_ixd_rgd), OP(mov_ixd_in), OP(mov_ixd_ind), OP(mov_ixd_de), OP(mov_ixd_ded), OP(mov_ixd_ix), OP(mov_ixd_ixd), + OP(mov_ixd_rg), OP(mov_ixd_rgd), OP(mov_ixd_in), OP(mov_ixd_ind), OP(mov_ixd_de), OP(mov_ixd_ded), OP(mov_ixd_ix), OP(mov_ixd_ixd), + + /* 0x2000 */ + OP(cmp_rg_rg), OP(cmp_rg_rgd), OP(cmp_rg_in), OP(cmp_rg_ind), OP(cmp_rg_de), OP(cmp_rg_ded), OP(cmp_rg_ix), OP(cmp_rg_ixd), + OP(cmp_rg_rg), OP(cmp_rg_rgd), OP(cmp_rg_in), OP(cmp_rg_ind), OP(cmp_rg_de), OP(cmp_rg_ded), OP(cmp_rg_ix), OP(cmp_rg_ixd), + OP(cmp_rg_rg), OP(cmp_rg_rgd), OP(cmp_rg_in), OP(cmp_rg_ind), OP(cmp_rg_de), OP(cmp_rg_ded), OP(cmp_rg_ix), OP(cmp_rg_ixd), + OP(cmp_rg_rg), OP(cmp_rg_rgd), OP(cmp_rg_in), OP(cmp_rg_ind), OP(cmp_rg_de), OP(cmp_rg_ded), OP(cmp_rg_ix), OP(cmp_rg_ixd), + /* 0x2100 */ + OP(cmp_rg_rg), OP(cmp_rg_rgd), OP(cmp_rg_in), OP(cmp_rg_ind), OP(cmp_rg_de), OP(cmp_rg_ded), OP(cmp_rg_ix), OP(cmp_rg_ixd), + OP(cmp_rg_rg), OP(cmp_rg_rgd), OP(cmp_rg_in), OP(cmp_rg_ind), OP(cmp_rg_de), OP(cmp_rg_ded), OP(cmp_rg_ix), OP(cmp_rg_ixd), + OP(cmp_rg_rg), OP(cmp_rg_rgd), OP(cmp_rg_in), OP(cmp_rg_ind), OP(cmp_rg_de), OP(cmp_rg_ded), OP(cmp_rg_ix), OP(cmp_rg_ixd), + OP(cmp_rg_rg), OP(cmp_rg_rgd), OP(cmp_rg_in), OP(cmp_rg_ind), OP(cmp_rg_de), OP(cmp_rg_ded), OP(cmp_rg_ix), OP(cmp_rg_ixd), + /* 0x2200 */ + OP(cmp_rgd_rg), OP(cmp_rgd_rgd), OP(cmp_rgd_in), OP(cmp_rgd_ind), OP(cmp_rgd_de), OP(cmp_rgd_ded), OP(cmp_rgd_ix), OP(cmp_rgd_ixd), + OP(cmp_rgd_rg), OP(cmp_rgd_rgd), OP(cmp_rgd_in), OP(cmp_rgd_ind), OP(cmp_rgd_de), OP(cmp_rgd_ded), OP(cmp_rgd_ix), OP(cmp_rgd_ixd), + OP(cmp_rgd_rg), OP(cmp_rgd_rgd), OP(cmp_rgd_in), OP(cmp_rgd_ind), OP(cmp_rgd_de), OP(cmp_rgd_ded), OP(cmp_rgd_ix), OP(cmp_rgd_ixd), + OP(cmp_rgd_rg), OP(cmp_rgd_rgd), OP(cmp_rgd_in), OP(cmp_rgd_ind), OP(cmp_rgd_de), OP(cmp_rgd_ded), OP(cmp_rgd_ix), OP(cmp_rgd_ixd), + /* 0x2300 */ + OP(cmp_rgd_rg), OP(cmp_rgd_rgd), OP(cmp_rgd_in), OP(cmp_rgd_ind), OP(cmp_rgd_de), OP(cmp_rgd_ded), OP(cmp_rgd_ix), OP(cmp_rgd_ixd), + OP(cmp_rgd_rg), OP(cmp_rgd_rgd), OP(cmp_rgd_in), OP(cmp_rgd_ind), OP(cmp_rgd_de), OP(cmp_rgd_ded), OP(cmp_rgd_ix), OP(cmp_rgd_ixd), + OP(cmp_rgd_rg), OP(cmp_rgd_rgd), OP(cmp_rgd_in), OP(cmp_rgd_ind), OP(cmp_rgd_de), OP(cmp_rgd_ded), OP(cmp_rgd_ix), OP(cmp_rgd_ixd), + OP(cmp_rgd_rg), OP(cmp_rgd_rgd), OP(cmp_rgd_in), OP(cmp_rgd_ind), OP(cmp_rgd_de), OP(cmp_rgd_ded), OP(cmp_rgd_ix), OP(cmp_rgd_ixd), + /* 0x2400 */ + OP(cmp_in_rg), OP(cmp_in_rgd), OP(cmp_in_in), OP(cmp_in_ind), OP(cmp_in_de), OP(cmp_in_ded), OP(cmp_in_ix), OP(cmp_in_ixd), + OP(cmp_in_rg), OP(cmp_in_rgd), OP(cmp_in_in), OP(cmp_in_ind), OP(cmp_in_de), OP(cmp_in_ded), OP(cmp_in_ix), OP(cmp_in_ixd), + OP(cmp_in_rg), OP(cmp_in_rgd), OP(cmp_in_in), OP(cmp_in_ind), OP(cmp_in_de), OP(cmp_in_ded), OP(cmp_in_ix), OP(cmp_in_ixd), + OP(cmp_in_rg), OP(cmp_in_rgd), OP(cmp_in_in), OP(cmp_in_ind), OP(cmp_in_de), OP(cmp_in_ded), OP(cmp_in_ix), OP(cmp_in_ixd), + /* 0x2500 */ + OP(cmp_in_rg), OP(cmp_in_rgd), OP(cmp_in_in), OP(cmp_in_ind), OP(cmp_in_de), OP(cmp_in_ded), OP(cmp_in_ix), OP(cmp_in_ixd), + OP(cmp_in_rg), OP(cmp_in_rgd), OP(cmp_in_in), OP(cmp_in_ind), OP(cmp_in_de), OP(cmp_in_ded), OP(cmp_in_ix), OP(cmp_in_ixd), + OP(cmp_in_rg), OP(cmp_in_rgd), OP(cmp_in_in), OP(cmp_in_ind), OP(cmp_in_de), OP(cmp_in_ded), OP(cmp_in_ix), OP(cmp_in_ixd), + OP(cmp_in_rg), OP(cmp_in_rgd), OP(cmp_in_in), OP(cmp_in_ind), OP(cmp_in_de), OP(cmp_in_ded), OP(cmp_in_ix), OP(cmp_in_ixd), + /* 0x2600 */ + OP(cmp_ind_rg), OP(cmp_ind_rgd), OP(cmp_ind_in), OP(cmp_ind_ind), OP(cmp_ind_de), OP(cmp_ind_ded), OP(cmp_ind_ix), OP(cmp_ind_ixd), + OP(cmp_ind_rg), OP(cmp_ind_rgd), OP(cmp_ind_in), OP(cmp_ind_ind), OP(cmp_ind_de), OP(cmp_ind_ded), OP(cmp_ind_ix), OP(cmp_ind_ixd), + OP(cmp_ind_rg), OP(cmp_ind_rgd), OP(cmp_ind_in), OP(cmp_ind_ind), OP(cmp_ind_de), OP(cmp_ind_ded), OP(cmp_ind_ix), OP(cmp_ind_ixd), + OP(cmp_ind_rg), OP(cmp_ind_rgd), OP(cmp_ind_in), OP(cmp_ind_ind), OP(cmp_ind_de), OP(cmp_ind_ded), OP(cmp_ind_ix), OP(cmp_ind_ixd), + /* 0x2700 */ + OP(cmp_ind_rg), OP(cmp_ind_rgd), OP(cmp_ind_in), OP(cmp_ind_ind), OP(cmp_ind_de), OP(cmp_ind_ded), OP(cmp_ind_ix), OP(cmp_ind_ixd), + OP(cmp_ind_rg), OP(cmp_ind_rgd), OP(cmp_ind_in), OP(cmp_ind_ind), OP(cmp_ind_de), OP(cmp_ind_ded), OP(cmp_ind_ix), OP(cmp_ind_ixd), + OP(cmp_ind_rg), OP(cmp_ind_rgd), OP(cmp_ind_in), OP(cmp_ind_ind), OP(cmp_ind_de), OP(cmp_ind_ded), OP(cmp_ind_ix), OP(cmp_ind_ixd), + OP(cmp_ind_rg), OP(cmp_ind_rgd), OP(cmp_ind_in), OP(cmp_ind_ind), OP(cmp_ind_de), OP(cmp_ind_ded), OP(cmp_ind_ix), OP(cmp_ind_ixd), + /* 0x2800 */ + OP(cmp_de_rg), OP(cmp_de_rgd), OP(cmp_de_in), OP(cmp_de_ind), OP(cmp_de_de), OP(cmp_de_ded), OP(cmp_de_ix), OP(cmp_de_ixd), + OP(cmp_de_rg), OP(cmp_de_rgd), OP(cmp_de_in), OP(cmp_de_ind), OP(cmp_de_de), OP(cmp_de_ded), OP(cmp_de_ix), OP(cmp_de_ixd), + OP(cmp_de_rg), OP(cmp_de_rgd), OP(cmp_de_in), OP(cmp_de_ind), OP(cmp_de_de), OP(cmp_de_ded), OP(cmp_de_ix), OP(cmp_de_ixd), + OP(cmp_de_rg), OP(cmp_de_rgd), OP(cmp_de_in), OP(cmp_de_ind), OP(cmp_de_de), OP(cmp_de_ded), OP(cmp_de_ix), OP(cmp_de_ixd), + /* 0x2900 */ + OP(cmp_de_rg), OP(cmp_de_rgd), OP(cmp_de_in), OP(cmp_de_ind), OP(cmp_de_de), OP(cmp_de_ded), OP(cmp_de_ix), OP(cmp_de_ixd), + OP(cmp_de_rg), OP(cmp_de_rgd), OP(cmp_de_in), OP(cmp_de_ind), OP(cmp_de_de), OP(cmp_de_ded), OP(cmp_de_ix), OP(cmp_de_ixd), + OP(cmp_de_rg), OP(cmp_de_rgd), OP(cmp_de_in), OP(cmp_de_ind), OP(cmp_de_de), OP(cmp_de_ded), OP(cmp_de_ix), OP(cmp_de_ixd), + OP(cmp_de_rg), OP(cmp_de_rgd), OP(cmp_de_in), OP(cmp_de_ind), OP(cmp_de_de), OP(cmp_de_ded), OP(cmp_de_ix), OP(cmp_de_ixd), + /* 0x2a00 */ + OP(cmp_ded_rg), OP(cmp_ded_rgd), OP(cmp_ded_in), OP(cmp_ded_ind), OP(cmp_ded_de), OP(cmp_ded_ded), OP(cmp_ded_ix), OP(cmp_ded_ixd), + OP(cmp_ded_rg), OP(cmp_ded_rgd), OP(cmp_ded_in), OP(cmp_ded_ind), OP(cmp_ded_de), OP(cmp_ded_ded), OP(cmp_ded_ix), OP(cmp_ded_ixd), + OP(cmp_ded_rg), OP(cmp_ded_rgd), OP(cmp_ded_in), OP(cmp_ded_ind), OP(cmp_ded_de), OP(cmp_ded_ded), OP(cmp_ded_ix), OP(cmp_ded_ixd), + OP(cmp_ded_rg), OP(cmp_ded_rgd), OP(cmp_ded_in), OP(cmp_ded_ind), OP(cmp_ded_de), OP(cmp_ded_ded), OP(cmp_ded_ix), OP(cmp_ded_ixd), + /* 0x2b00 */ + OP(cmp_ded_rg), OP(cmp_ded_rgd), OP(cmp_ded_in), OP(cmp_ded_ind), OP(cmp_ded_de), OP(cmp_ded_ded), OP(cmp_ded_ix), OP(cmp_ded_ixd), + OP(cmp_ded_rg), OP(cmp_ded_rgd), OP(cmp_ded_in), OP(cmp_ded_ind), OP(cmp_ded_de), OP(cmp_ded_ded), OP(cmp_ded_ix), OP(cmp_ded_ixd), + OP(cmp_ded_rg), OP(cmp_ded_rgd), OP(cmp_ded_in), OP(cmp_ded_ind), OP(cmp_ded_de), OP(cmp_ded_ded), OP(cmp_ded_ix), OP(cmp_ded_ixd), + OP(cmp_ded_rg), OP(cmp_ded_rgd), OP(cmp_ded_in), OP(cmp_ded_ind), OP(cmp_ded_de), OP(cmp_ded_ded), OP(cmp_ded_ix), OP(cmp_ded_ixd), + /* 0x2c00 */ + OP(cmp_ix_rg), OP(cmp_ix_rgd), OP(cmp_ix_in), OP(cmp_ix_ind), OP(cmp_ix_de), OP(cmp_ix_ded), OP(cmp_ix_ix), OP(cmp_ix_ixd), + OP(cmp_ix_rg), OP(cmp_ix_rgd), OP(cmp_ix_in), OP(cmp_ix_ind), OP(cmp_ix_de), OP(cmp_ix_ded), OP(cmp_ix_ix), OP(cmp_ix_ixd), + OP(cmp_ix_rg), OP(cmp_ix_rgd), OP(cmp_ix_in), OP(cmp_ix_ind), OP(cmp_ix_de), OP(cmp_ix_ded), OP(cmp_ix_ix), OP(cmp_ix_ixd), + OP(cmp_ix_rg), OP(cmp_ix_rgd), OP(cmp_ix_in), OP(cmp_ix_ind), OP(cmp_ix_de), OP(cmp_ix_ded), OP(cmp_ix_ix), OP(cmp_ix_ixd), + /* 0x2d00 */ + OP(cmp_ix_rg), OP(cmp_ix_rgd), OP(cmp_ix_in), OP(cmp_ix_ind), OP(cmp_ix_de), OP(cmp_ix_ded), OP(cmp_ix_ix), OP(cmp_ix_ixd), + OP(cmp_ix_rg), OP(cmp_ix_rgd), OP(cmp_ix_in), OP(cmp_ix_ind), OP(cmp_ix_de), OP(cmp_ix_ded), OP(cmp_ix_ix), OP(cmp_ix_ixd), + OP(cmp_ix_rg), OP(cmp_ix_rgd), OP(cmp_ix_in), OP(cmp_ix_ind), OP(cmp_ix_de), OP(cmp_ix_ded), OP(cmp_ix_ix), OP(cmp_ix_ixd), + OP(cmp_ix_rg), OP(cmp_ix_rgd), OP(cmp_ix_in), OP(cmp_ix_ind), OP(cmp_ix_de), OP(cmp_ix_ded), OP(cmp_ix_ix), OP(cmp_ix_ixd), + /* 0x2e00 */ + OP(cmp_ixd_rg), OP(cmp_ixd_rgd), OP(cmp_ixd_in), OP(cmp_ixd_ind), OP(cmp_ixd_de), OP(cmp_ixd_ded), OP(cmp_ixd_ix), OP(cmp_ixd_ixd), + OP(cmp_ixd_rg), OP(cmp_ixd_rgd), OP(cmp_ixd_in), OP(cmp_ixd_ind), OP(cmp_ixd_de), OP(cmp_ixd_ded), OP(cmp_ixd_ix), OP(cmp_ixd_ixd), + OP(cmp_ixd_rg), OP(cmp_ixd_rgd), OP(cmp_ixd_in), OP(cmp_ixd_ind), OP(cmp_ixd_de), OP(cmp_ixd_ded), OP(cmp_ixd_ix), OP(cmp_ixd_ixd), + OP(cmp_ixd_rg), OP(cmp_ixd_rgd), OP(cmp_ixd_in), OP(cmp_ixd_ind), OP(cmp_ixd_de), OP(cmp_ixd_ded), OP(cmp_ixd_ix), OP(cmp_ixd_ixd), + /* 0x2f00 */ + OP(cmp_ixd_rg), OP(cmp_ixd_rgd), OP(cmp_ixd_in), OP(cmp_ixd_ind), OP(cmp_ixd_de), OP(cmp_ixd_ded), OP(cmp_ixd_ix), OP(cmp_ixd_ixd), + OP(cmp_ixd_rg), OP(cmp_ixd_rgd), OP(cmp_ixd_in), OP(cmp_ixd_ind), OP(cmp_ixd_de), OP(cmp_ixd_ded), OP(cmp_ixd_ix), OP(cmp_ixd_ixd), + OP(cmp_ixd_rg), OP(cmp_ixd_rgd), OP(cmp_ixd_in), OP(cmp_ixd_ind), OP(cmp_ixd_de), OP(cmp_ixd_ded), OP(cmp_ixd_ix), OP(cmp_ixd_ixd), + OP(cmp_ixd_rg), OP(cmp_ixd_rgd), OP(cmp_ixd_in), OP(cmp_ixd_ind), OP(cmp_ixd_de), OP(cmp_ixd_ded), OP(cmp_ixd_ix), OP(cmp_ixd_ixd), + + /* 0x3000 */ + OP(bit_rg_rg), OP(bit_rg_rgd), OP(bit_rg_in), OP(bit_rg_ind), OP(bit_rg_de), OP(bit_rg_ded), OP(bit_rg_ix), OP(bit_rg_ixd), + OP(bit_rg_rg), OP(bit_rg_rgd), OP(bit_rg_in), OP(bit_rg_ind), OP(bit_rg_de), OP(bit_rg_ded), OP(bit_rg_ix), OP(bit_rg_ixd), + OP(bit_rg_rg), OP(bit_rg_rgd), OP(bit_rg_in), OP(bit_rg_ind), OP(bit_rg_de), OP(bit_rg_ded), OP(bit_rg_ix), OP(bit_rg_ixd), + OP(bit_rg_rg), OP(bit_rg_rgd), OP(bit_rg_in), OP(bit_rg_ind), OP(bit_rg_de), OP(bit_rg_ded), OP(bit_rg_ix), OP(bit_rg_ixd), + /* 0x3100 */ + OP(bit_rg_rg), OP(bit_rg_rgd), OP(bit_rg_in), OP(bit_rg_ind), OP(bit_rg_de), OP(bit_rg_ded), OP(bit_rg_ix), OP(bit_rg_ixd), + OP(bit_rg_rg), OP(bit_rg_rgd), OP(bit_rg_in), OP(bit_rg_ind), OP(bit_rg_de), OP(bit_rg_ded), OP(bit_rg_ix), OP(bit_rg_ixd), + OP(bit_rg_rg), OP(bit_rg_rgd), OP(bit_rg_in), OP(bit_rg_ind), OP(bit_rg_de), OP(bit_rg_ded), OP(bit_rg_ix), OP(bit_rg_ixd), + OP(bit_rg_rg), OP(bit_rg_rgd), OP(bit_rg_in), OP(bit_rg_ind), OP(bit_rg_de), OP(bit_rg_ded), OP(bit_rg_ix), OP(bit_rg_ixd), + /* 0x3200 */ + OP(bit_rgd_rg), OP(bit_rgd_rgd), OP(bit_rgd_in), OP(bit_rgd_ind), OP(bit_rgd_de), OP(bit_rgd_ded), OP(bit_rgd_ix), OP(bit_rgd_ixd), + OP(bit_rgd_rg), OP(bit_rgd_rgd), OP(bit_rgd_in), OP(bit_rgd_ind), OP(bit_rgd_de), OP(bit_rgd_ded), OP(bit_rgd_ix), OP(bit_rgd_ixd), + OP(bit_rgd_rg), OP(bit_rgd_rgd), OP(bit_rgd_in), OP(bit_rgd_ind), OP(bit_rgd_de), OP(bit_rgd_ded), OP(bit_rgd_ix), OP(bit_rgd_ixd), + OP(bit_rgd_rg), OP(bit_rgd_rgd), OP(bit_rgd_in), OP(bit_rgd_ind), OP(bit_rgd_de), OP(bit_rgd_ded), OP(bit_rgd_ix), OP(bit_rgd_ixd), + /* 0x3300 */ + OP(bit_rgd_rg), OP(bit_rgd_rgd), OP(bit_rgd_in), OP(bit_rgd_ind), OP(bit_rgd_de), OP(bit_rgd_ded), OP(bit_rgd_ix), OP(bit_rgd_ixd), + OP(bit_rgd_rg), OP(bit_rgd_rgd), OP(bit_rgd_in), OP(bit_rgd_ind), OP(bit_rgd_de), OP(bit_rgd_ded), OP(bit_rgd_ix), OP(bit_rgd_ixd), + OP(bit_rgd_rg), OP(bit_rgd_rgd), OP(bit_rgd_in), OP(bit_rgd_ind), OP(bit_rgd_de), OP(bit_rgd_ded), OP(bit_rgd_ix), OP(bit_rgd_ixd), + OP(bit_rgd_rg), OP(bit_rgd_rgd), OP(bit_rgd_in), OP(bit_rgd_ind), OP(bit_rgd_de), OP(bit_rgd_ded), OP(bit_rgd_ix), OP(bit_rgd_ixd), + /* 0x3400 */ + OP(bit_in_rg), OP(bit_in_rgd), OP(bit_in_in), OP(bit_in_ind), OP(bit_in_de), OP(bit_in_ded), OP(bit_in_ix), OP(bit_in_ixd), + OP(bit_in_rg), OP(bit_in_rgd), OP(bit_in_in), OP(bit_in_ind), OP(bit_in_de), OP(bit_in_ded), OP(bit_in_ix), OP(bit_in_ixd), + OP(bit_in_rg), OP(bit_in_rgd), OP(bit_in_in), OP(bit_in_ind), OP(bit_in_de), OP(bit_in_ded), OP(bit_in_ix), OP(bit_in_ixd), + OP(bit_in_rg), OP(bit_in_rgd), OP(bit_in_in), OP(bit_in_ind), OP(bit_in_de), OP(bit_in_ded), OP(bit_in_ix), OP(bit_in_ixd), + /* 0x3500 */ + OP(bit_in_rg), OP(bit_in_rgd), OP(bit_in_in), OP(bit_in_ind), OP(bit_in_de), OP(bit_in_ded), OP(bit_in_ix), OP(bit_in_ixd), + OP(bit_in_rg), OP(bit_in_rgd), OP(bit_in_in), OP(bit_in_ind), OP(bit_in_de), OP(bit_in_ded), OP(bit_in_ix), OP(bit_in_ixd), + OP(bit_in_rg), OP(bit_in_rgd), OP(bit_in_in), OP(bit_in_ind), OP(bit_in_de), OP(bit_in_ded), OP(bit_in_ix), OP(bit_in_ixd), + OP(bit_in_rg), OP(bit_in_rgd), OP(bit_in_in), OP(bit_in_ind), OP(bit_in_de), OP(bit_in_ded), OP(bit_in_ix), OP(bit_in_ixd), + /* 0x3600 */ + OP(bit_ind_rg), OP(bit_ind_rgd), OP(bit_ind_in), OP(bit_ind_ind), OP(bit_ind_de), OP(bit_ind_ded), OP(bit_ind_ix), OP(bit_ind_ixd), + OP(bit_ind_rg), OP(bit_ind_rgd), OP(bit_ind_in), OP(bit_ind_ind), OP(bit_ind_de), OP(bit_ind_ded), OP(bit_ind_ix), OP(bit_ind_ixd), + OP(bit_ind_rg), OP(bit_ind_rgd), OP(bit_ind_in), OP(bit_ind_ind), OP(bit_ind_de), OP(bit_ind_ded), OP(bit_ind_ix), OP(bit_ind_ixd), + OP(bit_ind_rg), OP(bit_ind_rgd), OP(bit_ind_in), OP(bit_ind_ind), OP(bit_ind_de), OP(bit_ind_ded), OP(bit_ind_ix), OP(bit_ind_ixd), + /* 0x3700 */ + OP(bit_ind_rg), OP(bit_ind_rgd), OP(bit_ind_in), OP(bit_ind_ind), OP(bit_ind_de), OP(bit_ind_ded), OP(bit_ind_ix), OP(bit_ind_ixd), + OP(bit_ind_rg), OP(bit_ind_rgd), OP(bit_ind_in), OP(bit_ind_ind), OP(bit_ind_de), OP(bit_ind_ded), OP(bit_ind_ix), OP(bit_ind_ixd), + OP(bit_ind_rg), OP(bit_ind_rgd), OP(bit_ind_in), OP(bit_ind_ind), OP(bit_ind_de), OP(bit_ind_ded), OP(bit_ind_ix), OP(bit_ind_ixd), + OP(bit_ind_rg), OP(bit_ind_rgd), OP(bit_ind_in), OP(bit_ind_ind), OP(bit_ind_de), OP(bit_ind_ded), OP(bit_ind_ix), OP(bit_ind_ixd), + /* 0x3800 */ + OP(bit_de_rg), OP(bit_de_rgd), OP(bit_de_in), OP(bit_de_ind), OP(bit_de_de), OP(bit_de_ded), OP(bit_de_ix), OP(bit_de_ixd), + OP(bit_de_rg), OP(bit_de_rgd), OP(bit_de_in), OP(bit_de_ind), OP(bit_de_de), OP(bit_de_ded), OP(bit_de_ix), OP(bit_de_ixd), + OP(bit_de_rg), OP(bit_de_rgd), OP(bit_de_in), OP(bit_de_ind), OP(bit_de_de), OP(bit_de_ded), OP(bit_de_ix), OP(bit_de_ixd), + OP(bit_de_rg), OP(bit_de_rgd), OP(bit_de_in), OP(bit_de_ind), OP(bit_de_de), OP(bit_de_ded), OP(bit_de_ix), OP(bit_de_ixd), + /* 0x3900 */ + OP(bit_de_rg), OP(bit_de_rgd), OP(bit_de_in), OP(bit_de_ind), OP(bit_de_de), OP(bit_de_ded), OP(bit_de_ix), OP(bit_de_ixd), + OP(bit_de_rg), OP(bit_de_rgd), OP(bit_de_in), OP(bit_de_ind), OP(bit_de_de), OP(bit_de_ded), OP(bit_de_ix), OP(bit_de_ixd), + OP(bit_de_rg), OP(bit_de_rgd), OP(bit_de_in), OP(bit_de_ind), OP(bit_de_de), OP(bit_de_ded), OP(bit_de_ix), OP(bit_de_ixd), + OP(bit_de_rg), OP(bit_de_rgd), OP(bit_de_in), OP(bit_de_ind), OP(bit_de_de), OP(bit_de_ded), OP(bit_de_ix), OP(bit_de_ixd), + /* 0x3a00 */ + OP(bit_ded_rg), OP(bit_ded_rgd), OP(bit_ded_in), OP(bit_ded_ind), OP(bit_ded_de), OP(bit_ded_ded), OP(bit_ded_ix), OP(bit_ded_ixd), + OP(bit_ded_rg), OP(bit_ded_rgd), OP(bit_ded_in), OP(bit_ded_ind), OP(bit_ded_de), OP(bit_ded_ded), OP(bit_ded_ix), OP(bit_ded_ixd), + OP(bit_ded_rg), OP(bit_ded_rgd), OP(bit_ded_in), OP(bit_ded_ind), OP(bit_ded_de), OP(bit_ded_ded), OP(bit_ded_ix), OP(bit_ded_ixd), + OP(bit_ded_rg), OP(bit_ded_rgd), OP(bit_ded_in), OP(bit_ded_ind), OP(bit_ded_de), OP(bit_ded_ded), OP(bit_ded_ix), OP(bit_ded_ixd), + /* 0x3b00 */ + OP(bit_ded_rg), OP(bit_ded_rgd), OP(bit_ded_in), OP(bit_ded_ind), OP(bit_ded_de), OP(bit_ded_ded), OP(bit_ded_ix), OP(bit_ded_ixd), + OP(bit_ded_rg), OP(bit_ded_rgd), OP(bit_ded_in), OP(bit_ded_ind), OP(bit_ded_de), OP(bit_ded_ded), OP(bit_ded_ix), OP(bit_ded_ixd), + OP(bit_ded_rg), OP(bit_ded_rgd), OP(bit_ded_in), OP(bit_ded_ind), OP(bit_ded_de), OP(bit_ded_ded), OP(bit_ded_ix), OP(bit_ded_ixd), + OP(bit_ded_rg), OP(bit_ded_rgd), OP(bit_ded_in), OP(bit_ded_ind), OP(bit_ded_de), OP(bit_ded_ded), OP(bit_ded_ix), OP(bit_ded_ixd), + /* 0x3c00 */ + OP(bit_ix_rg), OP(bit_ix_rgd), OP(bit_ix_in), OP(bit_ix_ind), OP(bit_ix_de), OP(bit_ix_ded), OP(bit_ix_ix), OP(bit_ix_ixd), + OP(bit_ix_rg), OP(bit_ix_rgd), OP(bit_ix_in), OP(bit_ix_ind), OP(bit_ix_de), OP(bit_ix_ded), OP(bit_ix_ix), OP(bit_ix_ixd), + OP(bit_ix_rg), OP(bit_ix_rgd), OP(bit_ix_in), OP(bit_ix_ind), OP(bit_ix_de), OP(bit_ix_ded), OP(bit_ix_ix), OP(bit_ix_ixd), + OP(bit_ix_rg), OP(bit_ix_rgd), OP(bit_ix_in), OP(bit_ix_ind), OP(bit_ix_de), OP(bit_ix_ded), OP(bit_ix_ix), OP(bit_ix_ixd), + /* 0x3d00 */ + OP(bit_ix_rg), OP(bit_ix_rgd), OP(bit_ix_in), OP(bit_ix_ind), OP(bit_ix_de), OP(bit_ix_ded), OP(bit_ix_ix), OP(bit_ix_ixd), + OP(bit_ix_rg), OP(bit_ix_rgd), OP(bit_ix_in), OP(bit_ix_ind), OP(bit_ix_de), OP(bit_ix_ded), OP(bit_ix_ix), OP(bit_ix_ixd), + OP(bit_ix_rg), OP(bit_ix_rgd), OP(bit_ix_in), OP(bit_ix_ind), OP(bit_ix_de), OP(bit_ix_ded), OP(bit_ix_ix), OP(bit_ix_ixd), + OP(bit_ix_rg), OP(bit_ix_rgd), OP(bit_ix_in), OP(bit_ix_ind), OP(bit_ix_de), OP(bit_ix_ded), OP(bit_ix_ix), OP(bit_ix_ixd), + /* 0x3e00 */ + OP(bit_ixd_rg), OP(bit_ixd_rgd), OP(bit_ixd_in), OP(bit_ixd_ind), OP(bit_ixd_de), OP(bit_ixd_ded), OP(bit_ixd_ix), OP(bit_ixd_ixd), + OP(bit_ixd_rg), OP(bit_ixd_rgd), OP(bit_ixd_in), OP(bit_ixd_ind), OP(bit_ixd_de), OP(bit_ixd_ded), OP(bit_ixd_ix), OP(bit_ixd_ixd), + OP(bit_ixd_rg), OP(bit_ixd_rgd), OP(bit_ixd_in), OP(bit_ixd_ind), OP(bit_ixd_de), OP(bit_ixd_ded), OP(bit_ixd_ix), OP(bit_ixd_ixd), + OP(bit_ixd_rg), OP(bit_ixd_rgd), OP(bit_ixd_in), OP(bit_ixd_ind), OP(bit_ixd_de), OP(bit_ixd_ded), OP(bit_ixd_ix), OP(bit_ixd_ixd), + /* 0x3f00 */ + OP(bit_ixd_rg), OP(bit_ixd_rgd), OP(bit_ixd_in), OP(bit_ixd_ind), OP(bit_ixd_de), OP(bit_ixd_ded), OP(bit_ixd_ix), OP(bit_ixd_ixd), + OP(bit_ixd_rg), OP(bit_ixd_rgd), OP(bit_ixd_in), OP(bit_ixd_ind), OP(bit_ixd_de), OP(bit_ixd_ded), OP(bit_ixd_ix), OP(bit_ixd_ixd), + OP(bit_ixd_rg), OP(bit_ixd_rgd), OP(bit_ixd_in), OP(bit_ixd_ind), OP(bit_ixd_de), OP(bit_ixd_ded), OP(bit_ixd_ix), OP(bit_ixd_ixd), + OP(bit_ixd_rg), OP(bit_ixd_rgd), OP(bit_ixd_in), OP(bit_ixd_ind), OP(bit_ixd_de), OP(bit_ixd_ded), OP(bit_ixd_ix), OP(bit_ixd_ixd), + + /* 0x4000 */ + OP(bic_rg_rg), OP(bic_rg_rgd), OP(bic_rg_in), OP(bic_rg_ind), OP(bic_rg_de), OP(bic_rg_ded), OP(bic_rg_ix), OP(bic_rg_ixd), + OP(bic_rg_rg), OP(bic_rg_rgd), OP(bic_rg_in), OP(bic_rg_ind), OP(bic_rg_de), OP(bic_rg_ded), OP(bic_rg_ix), OP(bic_rg_ixd), + OP(bic_rg_rg), OP(bic_rg_rgd), OP(bic_rg_in), OP(bic_rg_ind), OP(bic_rg_de), OP(bic_rg_ded), OP(bic_rg_ix), OP(bic_rg_ixd), + OP(bic_rg_rg), OP(bic_rg_rgd), OP(bic_rg_in), OP(bic_rg_ind), OP(bic_rg_de), OP(bic_rg_ded), OP(bic_rg_ix), OP(bic_rg_ixd), + /* 0x4100 */ + OP(bic_rg_rg), OP(bic_rg_rgd), OP(bic_rg_in), OP(bic_rg_ind), OP(bic_rg_de), OP(bic_rg_ded), OP(bic_rg_ix), OP(bic_rg_ixd), + OP(bic_rg_rg), OP(bic_rg_rgd), OP(bic_rg_in), OP(bic_rg_ind), OP(bic_rg_de), OP(bic_rg_ded), OP(bic_rg_ix), OP(bic_rg_ixd), + OP(bic_rg_rg), OP(bic_rg_rgd), OP(bic_rg_in), OP(bic_rg_ind), OP(bic_rg_de), OP(bic_rg_ded), OP(bic_rg_ix), OP(bic_rg_ixd), + OP(bic_rg_rg), OP(bic_rg_rgd), OP(bic_rg_in), OP(bic_rg_ind), OP(bic_rg_de), OP(bic_rg_ded), OP(bic_rg_ix), OP(bic_rg_ixd), + /* 0x4200 */ + OP(bic_rgd_rg), OP(bic_rgd_rgd), OP(bic_rgd_in), OP(bic_rgd_ind), OP(bic_rgd_de), OP(bic_rgd_ded), OP(bic_rgd_ix), OP(bic_rgd_ixd), + OP(bic_rgd_rg), OP(bic_rgd_rgd), OP(bic_rgd_in), OP(bic_rgd_ind), OP(bic_rgd_de), OP(bic_rgd_ded), OP(bic_rgd_ix), OP(bic_rgd_ixd), + OP(bic_rgd_rg), OP(bic_rgd_rgd), OP(bic_rgd_in), OP(bic_rgd_ind), OP(bic_rgd_de), OP(bic_rgd_ded), OP(bic_rgd_ix), OP(bic_rgd_ixd), + OP(bic_rgd_rg), OP(bic_rgd_rgd), OP(bic_rgd_in), OP(bic_rgd_ind), OP(bic_rgd_de), OP(bic_rgd_ded), OP(bic_rgd_ix), OP(bic_rgd_ixd), + /* 0x4300 */ + OP(bic_rgd_rg), OP(bic_rgd_rgd), OP(bic_rgd_in), OP(bic_rgd_ind), OP(bic_rgd_de), OP(bic_rgd_ded), OP(bic_rgd_ix), OP(bic_rgd_ixd), + OP(bic_rgd_rg), OP(bic_rgd_rgd), OP(bic_rgd_in), OP(bic_rgd_ind), OP(bic_rgd_de), OP(bic_rgd_ded), OP(bic_rgd_ix), OP(bic_rgd_ixd), + OP(bic_rgd_rg), OP(bic_rgd_rgd), OP(bic_rgd_in), OP(bic_rgd_ind), OP(bic_rgd_de), OP(bic_rgd_ded), OP(bic_rgd_ix), OP(bic_rgd_ixd), + OP(bic_rgd_rg), OP(bic_rgd_rgd), OP(bic_rgd_in), OP(bic_rgd_ind), OP(bic_rgd_de), OP(bic_rgd_ded), OP(bic_rgd_ix), OP(bic_rgd_ixd), + /* 0x4400 */ + OP(bic_in_rg), OP(bic_in_rgd), OP(bic_in_in), OP(bic_in_ind), OP(bic_in_de), OP(bic_in_ded), OP(bic_in_ix), OP(bic_in_ixd), + OP(bic_in_rg), OP(bic_in_rgd), OP(bic_in_in), OP(bic_in_ind), OP(bic_in_de), OP(bic_in_ded), OP(bic_in_ix), OP(bic_in_ixd), + OP(bic_in_rg), OP(bic_in_rgd), OP(bic_in_in), OP(bic_in_ind), OP(bic_in_de), OP(bic_in_ded), OP(bic_in_ix), OP(bic_in_ixd), + OP(bic_in_rg), OP(bic_in_rgd), OP(bic_in_in), OP(bic_in_ind), OP(bic_in_de), OP(bic_in_ded), OP(bic_in_ix), OP(bic_in_ixd), + /* 0x4500 */ + OP(bic_in_rg), OP(bic_in_rgd), OP(bic_in_in), OP(bic_in_ind), OP(bic_in_de), OP(bic_in_ded), OP(bic_in_ix), OP(bic_in_ixd), + OP(bic_in_rg), OP(bic_in_rgd), OP(bic_in_in), OP(bic_in_ind), OP(bic_in_de), OP(bic_in_ded), OP(bic_in_ix), OP(bic_in_ixd), + OP(bic_in_rg), OP(bic_in_rgd), OP(bic_in_in), OP(bic_in_ind), OP(bic_in_de), OP(bic_in_ded), OP(bic_in_ix), OP(bic_in_ixd), + OP(bic_in_rg), OP(bic_in_rgd), OP(bic_in_in), OP(bic_in_ind), OP(bic_in_de), OP(bic_in_ded), OP(bic_in_ix), OP(bic_in_ixd), + /* 0x4600 */ + OP(bic_ind_rg), OP(bic_ind_rgd), OP(bic_ind_in), OP(bic_ind_ind), OP(bic_ind_de), OP(bic_ind_ded), OP(bic_ind_ix), OP(bic_ind_ixd), + OP(bic_ind_rg), OP(bic_ind_rgd), OP(bic_ind_in), OP(bic_ind_ind), OP(bic_ind_de), OP(bic_ind_ded), OP(bic_ind_ix), OP(bic_ind_ixd), + OP(bic_ind_rg), OP(bic_ind_rgd), OP(bic_ind_in), OP(bic_ind_ind), OP(bic_ind_de), OP(bic_ind_ded), OP(bic_ind_ix), OP(bic_ind_ixd), + OP(bic_ind_rg), OP(bic_ind_rgd), OP(bic_ind_in), OP(bic_ind_ind), OP(bic_ind_de), OP(bic_ind_ded), OP(bic_ind_ix), OP(bic_ind_ixd), + /* 0x4700 */ + OP(bic_ind_rg), OP(bic_ind_rgd), OP(bic_ind_in), OP(bic_ind_ind), OP(bic_ind_de), OP(bic_ind_ded), OP(bic_ind_ix), OP(bic_ind_ixd), + OP(bic_ind_rg), OP(bic_ind_rgd), OP(bic_ind_in), OP(bic_ind_ind), OP(bic_ind_de), OP(bic_ind_ded), OP(bic_ind_ix), OP(bic_ind_ixd), + OP(bic_ind_rg), OP(bic_ind_rgd), OP(bic_ind_in), OP(bic_ind_ind), OP(bic_ind_de), OP(bic_ind_ded), OP(bic_ind_ix), OP(bic_ind_ixd), + OP(bic_ind_rg), OP(bic_ind_rgd), OP(bic_ind_in), OP(bic_ind_ind), OP(bic_ind_de), OP(bic_ind_ded), OP(bic_ind_ix), OP(bic_ind_ixd), + /* 0x4800 */ + OP(bic_de_rg), OP(bic_de_rgd), OP(bic_de_in), OP(bic_de_ind), OP(bic_de_de), OP(bic_de_ded), OP(bic_de_ix), OP(bic_de_ixd), + OP(bic_de_rg), OP(bic_de_rgd), OP(bic_de_in), OP(bic_de_ind), OP(bic_de_de), OP(bic_de_ded), OP(bic_de_ix), OP(bic_de_ixd), + OP(bic_de_rg), OP(bic_de_rgd), OP(bic_de_in), OP(bic_de_ind), OP(bic_de_de), OP(bic_de_ded), OP(bic_de_ix), OP(bic_de_ixd), + OP(bic_de_rg), OP(bic_de_rgd), OP(bic_de_in), OP(bic_de_ind), OP(bic_de_de), OP(bic_de_ded), OP(bic_de_ix), OP(bic_de_ixd), + /* 0x4900 */ + OP(bic_de_rg), OP(bic_de_rgd), OP(bic_de_in), OP(bic_de_ind), OP(bic_de_de), OP(bic_de_ded), OP(bic_de_ix), OP(bic_de_ixd), + OP(bic_de_rg), OP(bic_de_rgd), OP(bic_de_in), OP(bic_de_ind), OP(bic_de_de), OP(bic_de_ded), OP(bic_de_ix), OP(bic_de_ixd), + OP(bic_de_rg), OP(bic_de_rgd), OP(bic_de_in), OP(bic_de_ind), OP(bic_de_de), OP(bic_de_ded), OP(bic_de_ix), OP(bic_de_ixd), + OP(bic_de_rg), OP(bic_de_rgd), OP(bic_de_in), OP(bic_de_ind), OP(bic_de_de), OP(bic_de_ded), OP(bic_de_ix), OP(bic_de_ixd), + /* 0x4a00 */ + OP(bic_ded_rg), OP(bic_ded_rgd), OP(bic_ded_in), OP(bic_ded_ind), OP(bic_ded_de), OP(bic_ded_ded), OP(bic_ded_ix), OP(bic_ded_ixd), + OP(bic_ded_rg), OP(bic_ded_rgd), OP(bic_ded_in), OP(bic_ded_ind), OP(bic_ded_de), OP(bic_ded_ded), OP(bic_ded_ix), OP(bic_ded_ixd), + OP(bic_ded_rg), OP(bic_ded_rgd), OP(bic_ded_in), OP(bic_ded_ind), OP(bic_ded_de), OP(bic_ded_ded), OP(bic_ded_ix), OP(bic_ded_ixd), + OP(bic_ded_rg), OP(bic_ded_rgd), OP(bic_ded_in), OP(bic_ded_ind), OP(bic_ded_de), OP(bic_ded_ded), OP(bic_ded_ix), OP(bic_ded_ixd), + /* 0x4b00 */ + OP(bic_ded_rg), OP(bic_ded_rgd), OP(bic_ded_in), OP(bic_ded_ind), OP(bic_ded_de), OP(bic_ded_ded), OP(bic_ded_ix), OP(bic_ded_ixd), + OP(bic_ded_rg), OP(bic_ded_rgd), OP(bic_ded_in), OP(bic_ded_ind), OP(bic_ded_de), OP(bic_ded_ded), OP(bic_ded_ix), OP(bic_ded_ixd), + OP(bic_ded_rg), OP(bic_ded_rgd), OP(bic_ded_in), OP(bic_ded_ind), OP(bic_ded_de), OP(bic_ded_ded), OP(bic_ded_ix), OP(bic_ded_ixd), + OP(bic_ded_rg), OP(bic_ded_rgd), OP(bic_ded_in), OP(bic_ded_ind), OP(bic_ded_de), OP(bic_ded_ded), OP(bic_ded_ix), OP(bic_ded_ixd), + /* 0x4c00 */ + OP(bic_ix_rg), OP(bic_ix_rgd), OP(bic_ix_in), OP(bic_ix_ind), OP(bic_ix_de), OP(bic_ix_ded), OP(bic_ix_ix), OP(bic_ix_ixd), + OP(bic_ix_rg), OP(bic_ix_rgd), OP(bic_ix_in), OP(bic_ix_ind), OP(bic_ix_de), OP(bic_ix_ded), OP(bic_ix_ix), OP(bic_ix_ixd), + OP(bic_ix_rg), OP(bic_ix_rgd), OP(bic_ix_in), OP(bic_ix_ind), OP(bic_ix_de), OP(bic_ix_ded), OP(bic_ix_ix), OP(bic_ix_ixd), + OP(bic_ix_rg), OP(bic_ix_rgd), OP(bic_ix_in), OP(bic_ix_ind), OP(bic_ix_de), OP(bic_ix_ded), OP(bic_ix_ix), OP(bic_ix_ixd), + /* 0x4d00 */ + OP(bic_ix_rg), OP(bic_ix_rgd), OP(bic_ix_in), OP(bic_ix_ind), OP(bic_ix_de), OP(bic_ix_ded), OP(bic_ix_ix), OP(bic_ix_ixd), + OP(bic_ix_rg), OP(bic_ix_rgd), OP(bic_ix_in), OP(bic_ix_ind), OP(bic_ix_de), OP(bic_ix_ded), OP(bic_ix_ix), OP(bic_ix_ixd), + OP(bic_ix_rg), OP(bic_ix_rgd), OP(bic_ix_in), OP(bic_ix_ind), OP(bic_ix_de), OP(bic_ix_ded), OP(bic_ix_ix), OP(bic_ix_ixd), + OP(bic_ix_rg), OP(bic_ix_rgd), OP(bic_ix_in), OP(bic_ix_ind), OP(bic_ix_de), OP(bic_ix_ded), OP(bic_ix_ix), OP(bic_ix_ixd), + /* 0x4e00 */ + OP(bic_ixd_rg), OP(bic_ixd_rgd), OP(bic_ixd_in), OP(bic_ixd_ind), OP(bic_ixd_de), OP(bic_ixd_ded), OP(bic_ixd_ix), OP(bic_ixd_ixd), + OP(bic_ixd_rg), OP(bic_ixd_rgd), OP(bic_ixd_in), OP(bic_ixd_ind), OP(bic_ixd_de), OP(bic_ixd_ded), OP(bic_ixd_ix), OP(bic_ixd_ixd), + OP(bic_ixd_rg), OP(bic_ixd_rgd), OP(bic_ixd_in), OP(bic_ixd_ind), OP(bic_ixd_de), OP(bic_ixd_ded), OP(bic_ixd_ix), OP(bic_ixd_ixd), + OP(bic_ixd_rg), OP(bic_ixd_rgd), OP(bic_ixd_in), OP(bic_ixd_ind), OP(bic_ixd_de), OP(bic_ixd_ded), OP(bic_ixd_ix), OP(bic_ixd_ixd), + /* 0x4f00 */ + OP(bic_ixd_rg), OP(bic_ixd_rgd), OP(bic_ixd_in), OP(bic_ixd_ind), OP(bic_ixd_de), OP(bic_ixd_ded), OP(bic_ixd_ix), OP(bic_ixd_ixd), + OP(bic_ixd_rg), OP(bic_ixd_rgd), OP(bic_ixd_in), OP(bic_ixd_ind), OP(bic_ixd_de), OP(bic_ixd_ded), OP(bic_ixd_ix), OP(bic_ixd_ixd), + OP(bic_ixd_rg), OP(bic_ixd_rgd), OP(bic_ixd_in), OP(bic_ixd_ind), OP(bic_ixd_de), OP(bic_ixd_ded), OP(bic_ixd_ix), OP(bic_ixd_ixd), + OP(bic_ixd_rg), OP(bic_ixd_rgd), OP(bic_ixd_in), OP(bic_ixd_ind), OP(bic_ixd_de), OP(bic_ixd_ded), OP(bic_ixd_ix), OP(bic_ixd_ixd), + + /* 0x5000 */ + OP(bis_rg_rg), OP(bis_rg_rgd), OP(bis_rg_in), OP(bis_rg_ind), OP(bis_rg_de), OP(bis_rg_ded), OP(bis_rg_ix), OP(bis_rg_ixd), + OP(bis_rg_rg), OP(bis_rg_rgd), OP(bis_rg_in), OP(bis_rg_ind), OP(bis_rg_de), OP(bis_rg_ded), OP(bis_rg_ix), OP(bis_rg_ixd), + OP(bis_rg_rg), OP(bis_rg_rgd), OP(bis_rg_in), OP(bis_rg_ind), OP(bis_rg_de), OP(bis_rg_ded), OP(bis_rg_ix), OP(bis_rg_ixd), + OP(bis_rg_rg), OP(bis_rg_rgd), OP(bis_rg_in), OP(bis_rg_ind), OP(bis_rg_de), OP(bis_rg_ded), OP(bis_rg_ix), OP(bis_rg_ixd), + /* 0x5100 */ + OP(bis_rg_rg), OP(bis_rg_rgd), OP(bis_rg_in), OP(bis_rg_ind), OP(bis_rg_de), OP(bis_rg_ded), OP(bis_rg_ix), OP(bis_rg_ixd), + OP(bis_rg_rg), OP(bis_rg_rgd), OP(bis_rg_in), OP(bis_rg_ind), OP(bis_rg_de), OP(bis_rg_ded), OP(bis_rg_ix), OP(bis_rg_ixd), + OP(bis_rg_rg), OP(bis_rg_rgd), OP(bis_rg_in), OP(bis_rg_ind), OP(bis_rg_de), OP(bis_rg_ded), OP(bis_rg_ix), OP(bis_rg_ixd), + OP(bis_rg_rg), OP(bis_rg_rgd), OP(bis_rg_in), OP(bis_rg_ind), OP(bis_rg_de), OP(bis_rg_ded), OP(bis_rg_ix), OP(bis_rg_ixd), + /* 0x5200 */ + OP(bis_rgd_rg), OP(bis_rgd_rgd), OP(bis_rgd_in), OP(bis_rgd_ind), OP(bis_rgd_de), OP(bis_rgd_ded), OP(bis_rgd_ix), OP(bis_rgd_ixd), + OP(bis_rgd_rg), OP(bis_rgd_rgd), OP(bis_rgd_in), OP(bis_rgd_ind), OP(bis_rgd_de), OP(bis_rgd_ded), OP(bis_rgd_ix), OP(bis_rgd_ixd), + OP(bis_rgd_rg), OP(bis_rgd_rgd), OP(bis_rgd_in), OP(bis_rgd_ind), OP(bis_rgd_de), OP(bis_rgd_ded), OP(bis_rgd_ix), OP(bis_rgd_ixd), + OP(bis_rgd_rg), OP(bis_rgd_rgd), OP(bis_rgd_in), OP(bis_rgd_ind), OP(bis_rgd_de), OP(bis_rgd_ded), OP(bis_rgd_ix), OP(bis_rgd_ixd), + /* 0x5300 */ + OP(bis_rgd_rg), OP(bis_rgd_rgd), OP(bis_rgd_in), OP(bis_rgd_ind), OP(bis_rgd_de), OP(bis_rgd_ded), OP(bis_rgd_ix), OP(bis_rgd_ixd), + OP(bis_rgd_rg), OP(bis_rgd_rgd), OP(bis_rgd_in), OP(bis_rgd_ind), OP(bis_rgd_de), OP(bis_rgd_ded), OP(bis_rgd_ix), OP(bis_rgd_ixd), + OP(bis_rgd_rg), OP(bis_rgd_rgd), OP(bis_rgd_in), OP(bis_rgd_ind), OP(bis_rgd_de), OP(bis_rgd_ded), OP(bis_rgd_ix), OP(bis_rgd_ixd), + OP(bis_rgd_rg), OP(bis_rgd_rgd), OP(bis_rgd_in), OP(bis_rgd_ind), OP(bis_rgd_de), OP(bis_rgd_ded), OP(bis_rgd_ix), OP(bis_rgd_ixd), + /* 0x5400 */ + OP(bis_in_rg), OP(bis_in_rgd), OP(bis_in_in), OP(bis_in_ind), OP(bis_in_de), OP(bis_in_ded), OP(bis_in_ix), OP(bis_in_ixd), + OP(bis_in_rg), OP(bis_in_rgd), OP(bis_in_in), OP(bis_in_ind), OP(bis_in_de), OP(bis_in_ded), OP(bis_in_ix), OP(bis_in_ixd), + OP(bis_in_rg), OP(bis_in_rgd), OP(bis_in_in), OP(bis_in_ind), OP(bis_in_de), OP(bis_in_ded), OP(bis_in_ix), OP(bis_in_ixd), + OP(bis_in_rg), OP(bis_in_rgd), OP(bis_in_in), OP(bis_in_ind), OP(bis_in_de), OP(bis_in_ded), OP(bis_in_ix), OP(bis_in_ixd), + /* 0x5500 */ + OP(bis_in_rg), OP(bis_in_rgd), OP(bis_in_in), OP(bis_in_ind), OP(bis_in_de), OP(bis_in_ded), OP(bis_in_ix), OP(bis_in_ixd), + OP(bis_in_rg), OP(bis_in_rgd), OP(bis_in_in), OP(bis_in_ind), OP(bis_in_de), OP(bis_in_ded), OP(bis_in_ix), OP(bis_in_ixd), + OP(bis_in_rg), OP(bis_in_rgd), OP(bis_in_in), OP(bis_in_ind), OP(bis_in_de), OP(bis_in_ded), OP(bis_in_ix), OP(bis_in_ixd), + OP(bis_in_rg), OP(bis_in_rgd), OP(bis_in_in), OP(bis_in_ind), OP(bis_in_de), OP(bis_in_ded), OP(bis_in_ix), OP(bis_in_ixd), + /* 0x5600 */ + OP(bis_ind_rg), OP(bis_ind_rgd), OP(bis_ind_in), OP(bis_ind_ind), OP(bis_ind_de), OP(bis_ind_ded), OP(bis_ind_ix), OP(bis_ind_ixd), + OP(bis_ind_rg), OP(bis_ind_rgd), OP(bis_ind_in), OP(bis_ind_ind), OP(bis_ind_de), OP(bis_ind_ded), OP(bis_ind_ix), OP(bis_ind_ixd), + OP(bis_ind_rg), OP(bis_ind_rgd), OP(bis_ind_in), OP(bis_ind_ind), OP(bis_ind_de), OP(bis_ind_ded), OP(bis_ind_ix), OP(bis_ind_ixd), + OP(bis_ind_rg), OP(bis_ind_rgd), OP(bis_ind_in), OP(bis_ind_ind), OP(bis_ind_de), OP(bis_ind_ded), OP(bis_ind_ix), OP(bis_ind_ixd), + /* 0x5700 */ + OP(bis_ind_rg), OP(bis_ind_rgd), OP(bis_ind_in), OP(bis_ind_ind), OP(bis_ind_de), OP(bis_ind_ded), OP(bis_ind_ix), OP(bis_ind_ixd), + OP(bis_ind_rg), OP(bis_ind_rgd), OP(bis_ind_in), OP(bis_ind_ind), OP(bis_ind_de), OP(bis_ind_ded), OP(bis_ind_ix), OP(bis_ind_ixd), + OP(bis_ind_rg), OP(bis_ind_rgd), OP(bis_ind_in), OP(bis_ind_ind), OP(bis_ind_de), OP(bis_ind_ded), OP(bis_ind_ix), OP(bis_ind_ixd), + OP(bis_ind_rg), OP(bis_ind_rgd), OP(bis_ind_in), OP(bis_ind_ind), OP(bis_ind_de), OP(bis_ind_ded), OP(bis_ind_ix), OP(bis_ind_ixd), + /* 0x5800 */ + OP(bis_de_rg), OP(bis_de_rgd), OP(bis_de_in), OP(bis_de_ind), OP(bis_de_de), OP(bis_de_ded), OP(bis_de_ix), OP(bis_de_ixd), + OP(bis_de_rg), OP(bis_de_rgd), OP(bis_de_in), OP(bis_de_ind), OP(bis_de_de), OP(bis_de_ded), OP(bis_de_ix), OP(bis_de_ixd), + OP(bis_de_rg), OP(bis_de_rgd), OP(bis_de_in), OP(bis_de_ind), OP(bis_de_de), OP(bis_de_ded), OP(bis_de_ix), OP(bis_de_ixd), + OP(bis_de_rg), OP(bis_de_rgd), OP(bis_de_in), OP(bis_de_ind), OP(bis_de_de), OP(bis_de_ded), OP(bis_de_ix), OP(bis_de_ixd), + /* 0x5900 */ + OP(bis_de_rg), OP(bis_de_rgd), OP(bis_de_in), OP(bis_de_ind), OP(bis_de_de), OP(bis_de_ded), OP(bis_de_ix), OP(bis_de_ixd), + OP(bis_de_rg), OP(bis_de_rgd), OP(bis_de_in), OP(bis_de_ind), OP(bis_de_de), OP(bis_de_ded), OP(bis_de_ix), OP(bis_de_ixd), + OP(bis_de_rg), OP(bis_de_rgd), OP(bis_de_in), OP(bis_de_ind), OP(bis_de_de), OP(bis_de_ded), OP(bis_de_ix), OP(bis_de_ixd), + OP(bis_de_rg), OP(bis_de_rgd), OP(bis_de_in), OP(bis_de_ind), OP(bis_de_de), OP(bis_de_ded), OP(bis_de_ix), OP(bis_de_ixd), + /* 0x5a00 */ + OP(bis_ded_rg), OP(bis_ded_rgd), OP(bis_ded_in), OP(bis_ded_ind), OP(bis_ded_de), OP(bis_ded_ded), OP(bis_ded_ix), OP(bis_ded_ixd), + OP(bis_ded_rg), OP(bis_ded_rgd), OP(bis_ded_in), OP(bis_ded_ind), OP(bis_ded_de), OP(bis_ded_ded), OP(bis_ded_ix), OP(bis_ded_ixd), + OP(bis_ded_rg), OP(bis_ded_rgd), OP(bis_ded_in), OP(bis_ded_ind), OP(bis_ded_de), OP(bis_ded_ded), OP(bis_ded_ix), OP(bis_ded_ixd), + OP(bis_ded_rg), OP(bis_ded_rgd), OP(bis_ded_in), OP(bis_ded_ind), OP(bis_ded_de), OP(bis_ded_ded), OP(bis_ded_ix), OP(bis_ded_ixd), + /* 0x5b00 */ + OP(bis_ded_rg), OP(bis_ded_rgd), OP(bis_ded_in), OP(bis_ded_ind), OP(bis_ded_de), OP(bis_ded_ded), OP(bis_ded_ix), OP(bis_ded_ixd), + OP(bis_ded_rg), OP(bis_ded_rgd), OP(bis_ded_in), OP(bis_ded_ind), OP(bis_ded_de), OP(bis_ded_ded), OP(bis_ded_ix), OP(bis_ded_ixd), + OP(bis_ded_rg), OP(bis_ded_rgd), OP(bis_ded_in), OP(bis_ded_ind), OP(bis_ded_de), OP(bis_ded_ded), OP(bis_ded_ix), OP(bis_ded_ixd), + OP(bis_ded_rg), OP(bis_ded_rgd), OP(bis_ded_in), OP(bis_ded_ind), OP(bis_ded_de), OP(bis_ded_ded), OP(bis_ded_ix), OP(bis_ded_ixd), + /* 0x5c00 */ + OP(bis_ix_rg), OP(bis_ix_rgd), OP(bis_ix_in), OP(bis_ix_ind), OP(bis_ix_de), OP(bis_ix_ded), OP(bis_ix_ix), OP(bis_ix_ixd), + OP(bis_ix_rg), OP(bis_ix_rgd), OP(bis_ix_in), OP(bis_ix_ind), OP(bis_ix_de), OP(bis_ix_ded), OP(bis_ix_ix), OP(bis_ix_ixd), + OP(bis_ix_rg), OP(bis_ix_rgd), OP(bis_ix_in), OP(bis_ix_ind), OP(bis_ix_de), OP(bis_ix_ded), OP(bis_ix_ix), OP(bis_ix_ixd), + OP(bis_ix_rg), OP(bis_ix_rgd), OP(bis_ix_in), OP(bis_ix_ind), OP(bis_ix_de), OP(bis_ix_ded), OP(bis_ix_ix), OP(bis_ix_ixd), + /* 0x5d00 */ + OP(bis_ix_rg), OP(bis_ix_rgd), OP(bis_ix_in), OP(bis_ix_ind), OP(bis_ix_de), OP(bis_ix_ded), OP(bis_ix_ix), OP(bis_ix_ixd), + OP(bis_ix_rg), OP(bis_ix_rgd), OP(bis_ix_in), OP(bis_ix_ind), OP(bis_ix_de), OP(bis_ix_ded), OP(bis_ix_ix), OP(bis_ix_ixd), + OP(bis_ix_rg), OP(bis_ix_rgd), OP(bis_ix_in), OP(bis_ix_ind), OP(bis_ix_de), OP(bis_ix_ded), OP(bis_ix_ix), OP(bis_ix_ixd), + OP(bis_ix_rg), OP(bis_ix_rgd), OP(bis_ix_in), OP(bis_ix_ind), OP(bis_ix_de), OP(bis_ix_ded), OP(bis_ix_ix), OP(bis_ix_ixd), + /* 0x5e00 */ + OP(bis_ixd_rg), OP(bis_ixd_rgd), OP(bis_ixd_in), OP(bis_ixd_ind), OP(bis_ixd_de), OP(bis_ixd_ded), OP(bis_ixd_ix), OP(bis_ixd_ixd), + OP(bis_ixd_rg), OP(bis_ixd_rgd), OP(bis_ixd_in), OP(bis_ixd_ind), OP(bis_ixd_de), OP(bis_ixd_ded), OP(bis_ixd_ix), OP(bis_ixd_ixd), + OP(bis_ixd_rg), OP(bis_ixd_rgd), OP(bis_ixd_in), OP(bis_ixd_ind), OP(bis_ixd_de), OP(bis_ixd_ded), OP(bis_ixd_ix), OP(bis_ixd_ixd), + OP(bis_ixd_rg), OP(bis_ixd_rgd), OP(bis_ixd_in), OP(bis_ixd_ind), OP(bis_ixd_de), OP(bis_ixd_ded), OP(bis_ixd_ix), OP(bis_ixd_ixd), + /* 0x5f00 */ + OP(bis_ixd_rg), OP(bis_ixd_rgd), OP(bis_ixd_in), OP(bis_ixd_ind), OP(bis_ixd_de), OP(bis_ixd_ded), OP(bis_ixd_ix), OP(bis_ixd_ixd), + OP(bis_ixd_rg), OP(bis_ixd_rgd), OP(bis_ixd_in), OP(bis_ixd_ind), OP(bis_ixd_de), OP(bis_ixd_ded), OP(bis_ixd_ix), OP(bis_ixd_ixd), + OP(bis_ixd_rg), OP(bis_ixd_rgd), OP(bis_ixd_in), OP(bis_ixd_ind), OP(bis_ixd_de), OP(bis_ixd_ded), OP(bis_ixd_ix), OP(bis_ixd_ixd), + OP(bis_ixd_rg), OP(bis_ixd_rgd), OP(bis_ixd_in), OP(bis_ixd_ind), OP(bis_ixd_de), OP(bis_ixd_ded), OP(bis_ixd_ix), OP(bis_ixd_ixd), + + /* 0x6000 */ + OP(add_rg_rg), OP(add_rg_rgd), OP(add_rg_in), OP(add_rg_ind), OP(add_rg_de), OP(add_rg_ded), OP(add_rg_ix), OP(add_rg_ixd), + OP(add_rg_rg), OP(add_rg_rgd), OP(add_rg_in), OP(add_rg_ind), OP(add_rg_de), OP(add_rg_ded), OP(add_rg_ix), OP(add_rg_ixd), + OP(add_rg_rg), OP(add_rg_rgd), OP(add_rg_in), OP(add_rg_ind), OP(add_rg_de), OP(add_rg_ded), OP(add_rg_ix), OP(add_rg_ixd), + OP(add_rg_rg), OP(add_rg_rgd), OP(add_rg_in), OP(add_rg_ind), OP(add_rg_de), OP(add_rg_ded), OP(add_rg_ix), OP(add_rg_ixd), + /* 0x6100 */ + OP(add_rg_rg), OP(add_rg_rgd), OP(add_rg_in), OP(add_rg_ind), OP(add_rg_de), OP(add_rg_ded), OP(add_rg_ix), OP(add_rg_ixd), + OP(add_rg_rg), OP(add_rg_rgd), OP(add_rg_in), OP(add_rg_ind), OP(add_rg_de), OP(add_rg_ded), OP(add_rg_ix), OP(add_rg_ixd), + OP(add_rg_rg), OP(add_rg_rgd), OP(add_rg_in), OP(add_rg_ind), OP(add_rg_de), OP(add_rg_ded), OP(add_rg_ix), OP(add_rg_ixd), + OP(add_rg_rg), OP(add_rg_rgd), OP(add_rg_in), OP(add_rg_ind), OP(add_rg_de), OP(add_rg_ded), OP(add_rg_ix), OP(add_rg_ixd), + /* 0x6200 */ + OP(add_rgd_rg), OP(add_rgd_rgd), OP(add_rgd_in), OP(add_rgd_ind), OP(add_rgd_de), OP(add_rgd_ded), OP(add_rgd_ix), OP(add_rgd_ixd), + OP(add_rgd_rg), OP(add_rgd_rgd), OP(add_rgd_in), OP(add_rgd_ind), OP(add_rgd_de), OP(add_rgd_ded), OP(add_rgd_ix), OP(add_rgd_ixd), + OP(add_rgd_rg), OP(add_rgd_rgd), OP(add_rgd_in), OP(add_rgd_ind), OP(add_rgd_de), OP(add_rgd_ded), OP(add_rgd_ix), OP(add_rgd_ixd), + OP(add_rgd_rg), OP(add_rgd_rgd), OP(add_rgd_in), OP(add_rgd_ind), OP(add_rgd_de), OP(add_rgd_ded), OP(add_rgd_ix), OP(add_rgd_ixd), + /* 0x6300 */ + OP(add_rgd_rg), OP(add_rgd_rgd), OP(add_rgd_in), OP(add_rgd_ind), OP(add_rgd_de), OP(add_rgd_ded), OP(add_rgd_ix), OP(add_rgd_ixd), + OP(add_rgd_rg), OP(add_rgd_rgd), OP(add_rgd_in), OP(add_rgd_ind), OP(add_rgd_de), OP(add_rgd_ded), OP(add_rgd_ix), OP(add_rgd_ixd), + OP(add_rgd_rg), OP(add_rgd_rgd), OP(add_rgd_in), OP(add_rgd_ind), OP(add_rgd_de), OP(add_rgd_ded), OP(add_rgd_ix), OP(add_rgd_ixd), + OP(add_rgd_rg), OP(add_rgd_rgd), OP(add_rgd_in), OP(add_rgd_ind), OP(add_rgd_de), OP(add_rgd_ded), OP(add_rgd_ix), OP(add_rgd_ixd), + /* 0x6400 */ + OP(add_in_rg), OP(add_in_rgd), OP(add_in_in), OP(add_in_ind), OP(add_in_de), OP(add_in_ded), OP(add_in_ix), OP(add_in_ixd), + OP(add_in_rg), OP(add_in_rgd), OP(add_in_in), OP(add_in_ind), OP(add_in_de), OP(add_in_ded), OP(add_in_ix), OP(add_in_ixd), + OP(add_in_rg), OP(add_in_rgd), OP(add_in_in), OP(add_in_ind), OP(add_in_de), OP(add_in_ded), OP(add_in_ix), OP(add_in_ixd), + OP(add_in_rg), OP(add_in_rgd), OP(add_in_in), OP(add_in_ind), OP(add_in_de), OP(add_in_ded), OP(add_in_ix), OP(add_in_ixd), + /* 0x6500 */ + OP(add_in_rg), OP(add_in_rgd), OP(add_in_in), OP(add_in_ind), OP(add_in_de), OP(add_in_ded), OP(add_in_ix), OP(add_in_ixd), + OP(add_in_rg), OP(add_in_rgd), OP(add_in_in), OP(add_in_ind), OP(add_in_de), OP(add_in_ded), OP(add_in_ix), OP(add_in_ixd), + OP(add_in_rg), OP(add_in_rgd), OP(add_in_in), OP(add_in_ind), OP(add_in_de), OP(add_in_ded), OP(add_in_ix), OP(add_in_ixd), + OP(add_in_rg), OP(add_in_rgd), OP(add_in_in), OP(add_in_ind), OP(add_in_de), OP(add_in_ded), OP(add_in_ix), OP(add_in_ixd), + /* 0x6600 */ + OP(add_ind_rg), OP(add_ind_rgd), OP(add_ind_in), OP(add_ind_ind), OP(add_ind_de), OP(add_ind_ded), OP(add_ind_ix), OP(add_ind_ixd), + OP(add_ind_rg), OP(add_ind_rgd), OP(add_ind_in), OP(add_ind_ind), OP(add_ind_de), OP(add_ind_ded), OP(add_ind_ix), OP(add_ind_ixd), + OP(add_ind_rg), OP(add_ind_rgd), OP(add_ind_in), OP(add_ind_ind), OP(add_ind_de), OP(add_ind_ded), OP(add_ind_ix), OP(add_ind_ixd), + OP(add_ind_rg), OP(add_ind_rgd), OP(add_ind_in), OP(add_ind_ind), OP(add_ind_de), OP(add_ind_ded), OP(add_ind_ix), OP(add_ind_ixd), + /* 0x6700 */ + OP(add_ind_rg), OP(add_ind_rgd), OP(add_ind_in), OP(add_ind_ind), OP(add_ind_de), OP(add_ind_ded), OP(add_ind_ix), OP(add_ind_ixd), + OP(add_ind_rg), OP(add_ind_rgd), OP(add_ind_in), OP(add_ind_ind), OP(add_ind_de), OP(add_ind_ded), OP(add_ind_ix), OP(add_ind_ixd), + OP(add_ind_rg), OP(add_ind_rgd), OP(add_ind_in), OP(add_ind_ind), OP(add_ind_de), OP(add_ind_ded), OP(add_ind_ix), OP(add_ind_ixd), + OP(add_ind_rg), OP(add_ind_rgd), OP(add_ind_in), OP(add_ind_ind), OP(add_ind_de), OP(add_ind_ded), OP(add_ind_ix), OP(add_ind_ixd), + /* 0x6800 */ + OP(add_de_rg), OP(add_de_rgd), OP(add_de_in), OP(add_de_ind), OP(add_de_de), OP(add_de_ded), OP(add_de_ix), OP(add_de_ixd), + OP(add_de_rg), OP(add_de_rgd), OP(add_de_in), OP(add_de_ind), OP(add_de_de), OP(add_de_ded), OP(add_de_ix), OP(add_de_ixd), + OP(add_de_rg), OP(add_de_rgd), OP(add_de_in), OP(add_de_ind), OP(add_de_de), OP(add_de_ded), OP(add_de_ix), OP(add_de_ixd), + OP(add_de_rg), OP(add_de_rgd), OP(add_de_in), OP(add_de_ind), OP(add_de_de), OP(add_de_ded), OP(add_de_ix), OP(add_de_ixd), + /* 0x6900 */ + OP(add_de_rg), OP(add_de_rgd), OP(add_de_in), OP(add_de_ind), OP(add_de_de), OP(add_de_ded), OP(add_de_ix), OP(add_de_ixd), + OP(add_de_rg), OP(add_de_rgd), OP(add_de_in), OP(add_de_ind), OP(add_de_de), OP(add_de_ded), OP(add_de_ix), OP(add_de_ixd), + OP(add_de_rg), OP(add_de_rgd), OP(add_de_in), OP(add_de_ind), OP(add_de_de), OP(add_de_ded), OP(add_de_ix), OP(add_de_ixd), + OP(add_de_rg), OP(add_de_rgd), OP(add_de_in), OP(add_de_ind), OP(add_de_de), OP(add_de_ded), OP(add_de_ix), OP(add_de_ixd), + /* 0x6a00 */ + OP(add_ded_rg), OP(add_ded_rgd), OP(add_ded_in), OP(add_ded_ind), OP(add_ded_de), OP(add_ded_ded), OP(add_ded_ix), OP(add_ded_ixd), + OP(add_ded_rg), OP(add_ded_rgd), OP(add_ded_in), OP(add_ded_ind), OP(add_ded_de), OP(add_ded_ded), OP(add_ded_ix), OP(add_ded_ixd), + OP(add_ded_rg), OP(add_ded_rgd), OP(add_ded_in), OP(add_ded_ind), OP(add_ded_de), OP(add_ded_ded), OP(add_ded_ix), OP(add_ded_ixd), + OP(add_ded_rg), OP(add_ded_rgd), OP(add_ded_in), OP(add_ded_ind), OP(add_ded_de), OP(add_ded_ded), OP(add_ded_ix), OP(add_ded_ixd), + /* 0x6b00 */ + OP(add_ded_rg), OP(add_ded_rgd), OP(add_ded_in), OP(add_ded_ind), OP(add_ded_de), OP(add_ded_ded), OP(add_ded_ix), OP(add_ded_ixd), + OP(add_ded_rg), OP(add_ded_rgd), OP(add_ded_in), OP(add_ded_ind), OP(add_ded_de), OP(add_ded_ded), OP(add_ded_ix), OP(add_ded_ixd), + OP(add_ded_rg), OP(add_ded_rgd), OP(add_ded_in), OP(add_ded_ind), OP(add_ded_de), OP(add_ded_ded), OP(add_ded_ix), OP(add_ded_ixd), + OP(add_ded_rg), OP(add_ded_rgd), OP(add_ded_in), OP(add_ded_ind), OP(add_ded_de), OP(add_ded_ded), OP(add_ded_ix), OP(add_ded_ixd), + /* 0x6c00 */ + OP(add_ix_rg), OP(add_ix_rgd), OP(add_ix_in), OP(add_ix_ind), OP(add_ix_de), OP(add_ix_ded), OP(add_ix_ix), OP(add_ix_ixd), + OP(add_ix_rg), OP(add_ix_rgd), OP(add_ix_in), OP(add_ix_ind), OP(add_ix_de), OP(add_ix_ded), OP(add_ix_ix), OP(add_ix_ixd), + OP(add_ix_rg), OP(add_ix_rgd), OP(add_ix_in), OP(add_ix_ind), OP(add_ix_de), OP(add_ix_ded), OP(add_ix_ix), OP(add_ix_ixd), + OP(add_ix_rg), OP(add_ix_rgd), OP(add_ix_in), OP(add_ix_ind), OP(add_ix_de), OP(add_ix_ded), OP(add_ix_ix), OP(add_ix_ixd), + /* 0x6d00 */ + OP(add_ix_rg), OP(add_ix_rgd), OP(add_ix_in), OP(add_ix_ind), OP(add_ix_de), OP(add_ix_ded), OP(add_ix_ix), OP(add_ix_ixd), + OP(add_ix_rg), OP(add_ix_rgd), OP(add_ix_in), OP(add_ix_ind), OP(add_ix_de), OP(add_ix_ded), OP(add_ix_ix), OP(add_ix_ixd), + OP(add_ix_rg), OP(add_ix_rgd), OP(add_ix_in), OP(add_ix_ind), OP(add_ix_de), OP(add_ix_ded), OP(add_ix_ix), OP(add_ix_ixd), + OP(add_ix_rg), OP(add_ix_rgd), OP(add_ix_in), OP(add_ix_ind), OP(add_ix_de), OP(add_ix_ded), OP(add_ix_ix), OP(add_ix_ixd), + /* 0x6e00 */ + OP(add_ixd_rg), OP(add_ixd_rgd), OP(add_ixd_in), OP(add_ixd_ind), OP(add_ixd_de), OP(add_ixd_ded), OP(add_ixd_ix), OP(add_ixd_ixd), + OP(add_ixd_rg), OP(add_ixd_rgd), OP(add_ixd_in), OP(add_ixd_ind), OP(add_ixd_de), OP(add_ixd_ded), OP(add_ixd_ix), OP(add_ixd_ixd), + OP(add_ixd_rg), OP(add_ixd_rgd), OP(add_ixd_in), OP(add_ixd_ind), OP(add_ixd_de), OP(add_ixd_ded), OP(add_ixd_ix), OP(add_ixd_ixd), + OP(add_ixd_rg), OP(add_ixd_rgd), OP(add_ixd_in), OP(add_ixd_ind), OP(add_ixd_de), OP(add_ixd_ded), OP(add_ixd_ix), OP(add_ixd_ixd), + /* 0x6f00 */ + OP(add_ixd_rg), OP(add_ixd_rgd), OP(add_ixd_in), OP(add_ixd_ind), OP(add_ixd_de), OP(add_ixd_ded), OP(add_ixd_ix), OP(add_ixd_ixd), + OP(add_ixd_rg), OP(add_ixd_rgd), OP(add_ixd_in), OP(add_ixd_ind), OP(add_ixd_de), OP(add_ixd_ded), OP(add_ixd_ix), OP(add_ixd_ixd), + OP(add_ixd_rg), OP(add_ixd_rgd), OP(add_ixd_in), OP(add_ixd_ind), OP(add_ixd_de), OP(add_ixd_ded), OP(add_ixd_ix), OP(add_ixd_ixd), + OP(add_ixd_rg), OP(add_ixd_rgd), OP(add_ixd_in), OP(add_ixd_ind), OP(add_ixd_de), OP(add_ixd_ded), OP(add_ixd_ix), OP(add_ixd_ixd), + + /* 0x7000 */ + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + /* 0x7100 */ + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + /* 0x7200 */ + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + /* 0x7300 */ + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + /* 0x7400 */ + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + /* 0x7500 */ + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + /* 0x7600 */ + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + /* 0x7700 */ + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + /* 0x7800 */ + OP(xor_rg), OP(xor_rgd), OP(xor_in), OP(xor_ind), OP(xor_de), OP(xor_ded), OP(xor_ix), OP(xor_ixd), + OP(xor_rg), OP(xor_rgd), OP(xor_in), OP(xor_ind), OP(xor_de), OP(xor_ded), OP(xor_ix), OP(xor_ixd), + OP(xor_rg), OP(xor_rgd), OP(xor_in), OP(xor_ind), OP(xor_de), OP(xor_ded), OP(xor_ix), OP(xor_ixd), + OP(xor_rg), OP(xor_rgd), OP(xor_in), OP(xor_ind), OP(xor_de), OP(xor_ded), OP(xor_ix), OP(xor_ixd), + /* 0x7900 */ + OP(xor_rg), OP(xor_rgd), OP(xor_in), OP(xor_ind), OP(xor_de), OP(xor_ded), OP(xor_ix), OP(xor_ixd), + OP(xor_rg), OP(xor_rgd), OP(xor_in), OP(xor_ind), OP(xor_de), OP(xor_ded), OP(xor_ix), OP(xor_ixd), + OP(xor_rg), OP(xor_rgd), OP(xor_in), OP(xor_ind), OP(xor_de), OP(xor_ded), OP(xor_ix), OP(xor_ixd), + OP(xor_rg), OP(xor_rgd), OP(xor_in), OP(xor_ind), OP(xor_de), OP(xor_ded), OP(xor_ix), OP(xor_ixd), + /* 0x7a00 */ + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + /* 0x7b00 */ + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + /* 0x7c00 */ + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + /* 0x7d00 */ + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + /* 0x7e00 */ + OP(sob), OP(sob), OP(sob), OP(sob), OP(sob), OP(sob), OP(sob), OP(sob), + OP(sob), OP(sob), OP(sob), OP(sob), OP(sob), OP(sob), OP(sob), OP(sob), + OP(sob), OP(sob), OP(sob), OP(sob), OP(sob), OP(sob), OP(sob), OP(sob), + OP(sob), OP(sob), OP(sob), OP(sob), OP(sob), OP(sob), OP(sob), OP(sob), + /* 0x7f00 */ + OP(sob), OP(sob), OP(sob), OP(sob), OP(sob), OP(sob), OP(sob), OP(sob), + OP(sob), OP(sob), OP(sob), OP(sob), OP(sob), OP(sob), OP(sob), OP(sob), + OP(sob), OP(sob), OP(sob), OP(sob), OP(sob), OP(sob), OP(sob), OP(sob), + OP(sob), OP(sob), OP(sob), OP(sob), OP(sob), OP(sob), OP(sob), OP(sob), + + /* 0x8000 */ + OP(bpl), OP(bpl), OP(bpl), OP(bpl), OP(bpl), OP(bpl), OP(bpl), OP(bpl), + OP(bpl), OP(bpl), OP(bpl), OP(bpl), OP(bpl), OP(bpl), OP(bpl), OP(bpl), + OP(bpl), OP(bpl), OP(bpl), OP(bpl), OP(bpl), OP(bpl), OP(bpl), OP(bpl), + OP(bpl), OP(bpl), OP(bpl), OP(bpl), OP(bpl), OP(bpl), OP(bpl), OP(bpl), + /* 0x8100 */ + OP(bmi), OP(bmi), OP(bmi), OP(bmi), OP(bmi), OP(bmi), OP(bmi), OP(bmi), + OP(bmi), OP(bmi), OP(bmi), OP(bmi), OP(bmi), OP(bmi), OP(bmi), OP(bmi), + OP(bmi), OP(bmi), OP(bmi), OP(bmi), OP(bmi), OP(bmi), OP(bmi), OP(bmi), + OP(bmi), OP(bmi), OP(bmi), OP(bmi), OP(bmi), OP(bmi), OP(bmi), OP(bmi), + /* 0x8200 */ + OP(bhi), OP(bhi), OP(bhi), OP(bhi), OP(bhi), OP(bhi), OP(bhi), OP(bhi), + OP(bhi), OP(bhi), OP(bhi), OP(bhi), OP(bhi), OP(bhi), OP(bhi), OP(bhi), + OP(bhi), OP(bhi), OP(bhi), OP(bhi), OP(bhi), OP(bhi), OP(bhi), OP(bhi), + OP(bhi), OP(bhi), OP(bhi), OP(bhi), OP(bhi), OP(bhi), OP(bhi), OP(bhi), + /* 0x8300 */ + OP(blos), OP(blos), OP(blos), OP(blos), OP(blos), OP(blos), OP(blos), OP(blos), + OP(blos), OP(blos), OP(blos), OP(blos), OP(blos), OP(blos), OP(blos), OP(blos), + OP(blos), OP(blos), OP(blos), OP(blos), OP(blos), OP(blos), OP(blos), OP(blos), + OP(blos), OP(blos), OP(blos), OP(blos), OP(blos), OP(blos), OP(blos), OP(blos), + /* 0x8400 */ + OP(bvc), OP(bvc), OP(bvc), OP(bvc), OP(bvc), OP(bvc), OP(bvc), OP(bvc), + OP(bvc), OP(bvc), OP(bvc), OP(bvc), OP(bvc), OP(bvc), OP(bvc), OP(bvc), + OP(bvc), OP(bvc), OP(bvc), OP(bvc), OP(bvc), OP(bvc), OP(bvc), OP(bvc), + OP(bvc), OP(bvc), OP(bvc), OP(bvc), OP(bvc), OP(bvc), OP(bvc), OP(bvc), + /* 0x8500 */ + OP(bvs), OP(bvs), OP(bvs), OP(bvs), OP(bvs), OP(bvs), OP(bvs), OP(bvs), + OP(bvs), OP(bvs), OP(bvs), OP(bvs), OP(bvs), OP(bvs), OP(bvs), OP(bvs), + OP(bvs), OP(bvs), OP(bvs), OP(bvs), OP(bvs), OP(bvs), OP(bvs), OP(bvs), + OP(bvs), OP(bvs), OP(bvs), OP(bvs), OP(bvs), OP(bvs), OP(bvs), OP(bvs), + /* 0x8600 */ + OP(bcc), OP(bcc), OP(bcc), OP(bcc), OP(bcc), OP(bcc), OP(bcc), OP(bcc), + OP(bcc), OP(bcc), OP(bcc), OP(bcc), OP(bcc), OP(bcc), OP(bcc), OP(bcc), + OP(bcc), OP(bcc), OP(bcc), OP(bcc), OP(bcc), OP(bcc), OP(bcc), OP(bcc), + OP(bcc), OP(bcc), OP(bcc), OP(bcc), OP(bcc), OP(bcc), OP(bcc), OP(bcc), + /* 0x8700 */ + OP(bcs), OP(bcs), OP(bcs), OP(bcs), OP(bcs), OP(bcs), OP(bcs), OP(bcs), + OP(bcs), OP(bcs), OP(bcs), OP(bcs), OP(bcs), OP(bcs), OP(bcs), OP(bcs), + OP(bcs), OP(bcs), OP(bcs), OP(bcs), OP(bcs), OP(bcs), OP(bcs), OP(bcs), + OP(bcs), OP(bcs), OP(bcs), OP(bcs), OP(bcs), OP(bcs), OP(bcs), OP(bcs), + /* 0x8800 */ + OP(emt), OP(emt), OP(emt), OP(emt), OP(emt), OP(emt), OP(emt), OP(emt), + OP(emt), OP(emt), OP(emt), OP(emt), OP(emt), OP(emt), OP(emt), OP(emt), + OP(emt), OP(emt), OP(emt), OP(emt), OP(emt), OP(emt), OP(emt), OP(emt), + OP(emt), OP(emt), OP(emt), OP(emt), OP(emt), OP(emt), OP(emt), OP(emt), + /* 0x8900 */ + OP(trap), OP(trap), OP(trap), OP(trap), OP(trap), OP(trap), OP(trap), OP(trap), + OP(trap), OP(trap), OP(trap), OP(trap), OP(trap), OP(trap), OP(trap), OP(trap), + OP(trap), OP(trap), OP(trap), OP(trap), OP(trap), OP(trap), OP(trap), OP(trap), + OP(trap), OP(trap), OP(trap), OP(trap), OP(trap), OP(trap), OP(trap), OP(trap), + /* 0x8a00 */ + OP(clrb_rg), OP(clrb_rgd), OP(clrb_in), OP(clrb_ind), OP(clrb_de), OP(clrb_ded), OP(clrb_ix), OP(clrb_ixd), + OP(comb_rg), OP(comb_rgd), OP(comb_in), OP(comb_ind), OP(comb_de), OP(comb_ded), OP(comb_ix), OP(comb_ixd), + OP(incb_rg), OP(incb_rgd), OP(incb_in), OP(incb_ind), OP(incb_de), OP(incb_ded), OP(incb_ix), OP(incb_ixd), + OP(decb_rg), OP(decb_rgd), OP(decb_in), OP(decb_ind), OP(decb_de), OP(decb_ded), OP(decb_ix), OP(decb_ixd), + /* 0x8b00 */ + OP(negb_rg), OP(negb_rgd), OP(negb_in), OP(negb_ind), OP(negb_de), OP(negb_ded), OP(negb_ix), OP(negb_ixd), + OP(adcb_rg), OP(adcb_rgd), OP(adcb_in), OP(adcb_ind), OP(adcb_de), OP(adcb_ded), OP(adcb_ix), OP(adcb_ixd), + OP(sbcb_rg), OP(sbcb_rgd), OP(sbcb_in), OP(sbcb_ind), OP(sbcb_de), OP(sbcb_ded), OP(sbcb_ix), OP(sbcb_ixd), + OP(tstb_rg), OP(tstb_rgd), OP(tstb_in), OP(tstb_ind), OP(tstb_de), OP(tstb_ded), OP(tstb_ix), OP(tstb_ixd), + /* 0x8c00 */ + OP(rorb_rg), OP(rorb_rgd), OP(rorb_in), OP(rorb_ind), OP(rorb_de), OP(rorb_ded), OP(rorb_ix), OP(rorb_ixd), + OP(rolb_rg), OP(rolb_rgd), OP(rolb_in), OP(rolb_ind), OP(rolb_de), OP(rolb_ded), OP(rolb_ix), OP(rolb_ixd), + OP(asrb_rg), OP(asrb_rgd), OP(asrb_in), OP(asrb_ind), OP(asrb_de), OP(asrb_ded), OP(asrb_ix), OP(asrb_ixd), + OP(aslb_rg), OP(aslb_rgd), OP(aslb_in), OP(aslb_ind), OP(aslb_de), OP(aslb_ded), OP(aslb_ix), OP(aslb_ixd), + /* 0x8d00 */ + OP(mtps_rg), OP(mtps_rgd), OP(mtps_in), OP(mtps_ind), OP(mtps_de), OP(mtps_ded), OP(mtps_ix), OP(mtps_ixd), + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + OP(mfps_rg), OP(mfps_rgd), OP(mfps_in), OP(mfps_ind), OP(mfps_de), OP(mfps_ded), OP(mfps_ix), OP(mfps_ixd), + /* 0x8e00 */ + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + /* 0x8f00 */ + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + + /* 0x9000 */ + OP(movb_rg_rg), OP(movb_rg_rgd), OP(movb_rg_in), OP(movb_rg_ind), OP(movb_rg_de), OP(movb_rg_ded), OP(movb_rg_ix), OP(movb_rg_ixd), + OP(movb_rg_rg), OP(movb_rg_rgd), OP(movb_rg_in), OP(movb_rg_ind), OP(movb_rg_de), OP(movb_rg_ded), OP(movb_rg_ix), OP(movb_rg_ixd), + OP(movb_rg_rg), OP(movb_rg_rgd), OP(movb_rg_in), OP(movb_rg_ind), OP(movb_rg_de), OP(movb_rg_ded), OP(movb_rg_ix), OP(movb_rg_ixd), + OP(movb_rg_rg), OP(movb_rg_rgd), OP(movb_rg_in), OP(movb_rg_ind), OP(movb_rg_de), OP(movb_rg_ded), OP(movb_rg_ix), OP(movb_rg_ixd), + /* 0x9100 */ + OP(movb_rg_rg), OP(movb_rg_rgd), OP(movb_rg_in), OP(movb_rg_ind), OP(movb_rg_de), OP(movb_rg_ded), OP(movb_rg_ix), OP(movb_rg_ixd), + OP(movb_rg_rg), OP(movb_rg_rgd), OP(movb_rg_in), OP(movb_rg_ind), OP(movb_rg_de), OP(movb_rg_ded), OP(movb_rg_ix), OP(movb_rg_ixd), + OP(movb_rg_rg), OP(movb_rg_rgd), OP(movb_rg_in), OP(movb_rg_ind), OP(movb_rg_de), OP(movb_rg_ded), OP(movb_rg_ix), OP(movb_rg_ixd), + OP(movb_rg_rg), OP(movb_rg_rgd), OP(movb_rg_in), OP(movb_rg_ind), OP(movb_rg_de), OP(movb_rg_ded), OP(movb_rg_ix), OP(movb_rg_ixd), + /* 0x9200 */ + OP(movb_rgd_rg), OP(movb_rgd_rgd), OP(movb_rgd_in), OP(movb_rgd_ind), OP(movb_rgd_de), OP(movb_rgd_ded), OP(movb_rgd_ix), OP(movb_rgd_ixd), + OP(movb_rgd_rg), OP(movb_rgd_rgd), OP(movb_rgd_in), OP(movb_rgd_ind), OP(movb_rgd_de), OP(movb_rgd_ded), OP(movb_rgd_ix), OP(movb_rgd_ixd), + OP(movb_rgd_rg), OP(movb_rgd_rgd), OP(movb_rgd_in), OP(movb_rgd_ind), OP(movb_rgd_de), OP(movb_rgd_ded), OP(movb_rgd_ix), OP(movb_rgd_ixd), + OP(movb_rgd_rg), OP(movb_rgd_rgd), OP(movb_rgd_in), OP(movb_rgd_ind), OP(movb_rgd_de), OP(movb_rgd_ded), OP(movb_rgd_ix), OP(movb_rgd_ixd), + /* 0x9300 */ + OP(movb_rgd_rg), OP(movb_rgd_rgd), OP(movb_rgd_in), OP(movb_rgd_ind), OP(movb_rgd_de), OP(movb_rgd_ded), OP(movb_rgd_ix), OP(movb_rgd_ixd), + OP(movb_rgd_rg), OP(movb_rgd_rgd), OP(movb_rgd_in), OP(movb_rgd_ind), OP(movb_rgd_de), OP(movb_rgd_ded), OP(movb_rgd_ix), OP(movb_rgd_ixd), + OP(movb_rgd_rg), OP(movb_rgd_rgd), OP(movb_rgd_in), OP(movb_rgd_ind), OP(movb_rgd_de), OP(movb_rgd_ded), OP(movb_rgd_ix), OP(movb_rgd_ixd), + OP(movb_rgd_rg), OP(movb_rgd_rgd), OP(movb_rgd_in), OP(movb_rgd_ind), OP(movb_rgd_de), OP(movb_rgd_ded), OP(movb_rgd_ix), OP(movb_rgd_ixd), + /* 0x9400 */ + OP(movb_in_rg), OP(movb_in_rgd), OP(movb_in_in), OP(movb_in_ind), OP(movb_in_de), OP(movb_in_ded), OP(movb_in_ix), OP(movb_in_ixd), + OP(movb_in_rg), OP(movb_in_rgd), OP(movb_in_in), OP(movb_in_ind), OP(movb_in_de), OP(movb_in_ded), OP(movb_in_ix), OP(movb_in_ixd), + OP(movb_in_rg), OP(movb_in_rgd), OP(movb_in_in), OP(movb_in_ind), OP(movb_in_de), OP(movb_in_ded), OP(movb_in_ix), OP(movb_in_ixd), + OP(movb_in_rg), OP(movb_in_rgd), OP(movb_in_in), OP(movb_in_ind), OP(movb_in_de), OP(movb_in_ded), OP(movb_in_ix), OP(movb_in_ixd), + /* 0x9500 */ + OP(movb_in_rg), OP(movb_in_rgd), OP(movb_in_in), OP(movb_in_ind), OP(movb_in_de), OP(movb_in_ded), OP(movb_in_ix), OP(movb_in_ixd), + OP(movb_in_rg), OP(movb_in_rgd), OP(movb_in_in), OP(movb_in_ind), OP(movb_in_de), OP(movb_in_ded), OP(movb_in_ix), OP(movb_in_ixd), + OP(movb_in_rg), OP(movb_in_rgd), OP(movb_in_in), OP(movb_in_ind), OP(movb_in_de), OP(movb_in_ded), OP(movb_in_ix), OP(movb_in_ixd), + OP(movb_in_rg), OP(movb_in_rgd), OP(movb_in_in), OP(movb_in_ind), OP(movb_in_de), OP(movb_in_ded), OP(movb_in_ix), OP(movb_in_ixd), + /* 0x9600 */ + OP(movb_ind_rg), OP(movb_ind_rgd), OP(movb_ind_in), OP(movb_ind_ind), OP(movb_ind_de), OP(movb_ind_ded), OP(movb_ind_ix), OP(movb_ind_ixd), + OP(movb_ind_rg), OP(movb_ind_rgd), OP(movb_ind_in), OP(movb_ind_ind), OP(movb_ind_de), OP(movb_ind_ded), OP(movb_ind_ix), OP(movb_ind_ixd), + OP(movb_ind_rg), OP(movb_ind_rgd), OP(movb_ind_in), OP(movb_ind_ind), OP(movb_ind_de), OP(movb_ind_ded), OP(movb_ind_ix), OP(movb_ind_ixd), + OP(movb_ind_rg), OP(movb_ind_rgd), OP(movb_ind_in), OP(movb_ind_ind), OP(movb_ind_de), OP(movb_ind_ded), OP(movb_ind_ix), OP(movb_ind_ixd), + /* 0x9700 */ + OP(movb_ind_rg), OP(movb_ind_rgd), OP(movb_ind_in), OP(movb_ind_ind), OP(movb_ind_de), OP(movb_ind_ded), OP(movb_ind_ix), OP(movb_ind_ixd), + OP(movb_ind_rg), OP(movb_ind_rgd), OP(movb_ind_in), OP(movb_ind_ind), OP(movb_ind_de), OP(movb_ind_ded), OP(movb_ind_ix), OP(movb_ind_ixd), + OP(movb_ind_rg), OP(movb_ind_rgd), OP(movb_ind_in), OP(movb_ind_ind), OP(movb_ind_de), OP(movb_ind_ded), OP(movb_ind_ix), OP(movb_ind_ixd), + OP(movb_ind_rg), OP(movb_ind_rgd), OP(movb_ind_in), OP(movb_ind_ind), OP(movb_ind_de), OP(movb_ind_ded), OP(movb_ind_ix), OP(movb_ind_ixd), + /* 0x9800 */ + OP(movb_de_rg), OP(movb_de_rgd), OP(movb_de_in), OP(movb_de_ind), OP(movb_de_de), OP(movb_de_ded), OP(movb_de_ix), OP(movb_de_ixd), + OP(movb_de_rg), OP(movb_de_rgd), OP(movb_de_in), OP(movb_de_ind), OP(movb_de_de), OP(movb_de_ded), OP(movb_de_ix), OP(movb_de_ixd), + OP(movb_de_rg), OP(movb_de_rgd), OP(movb_de_in), OP(movb_de_ind), OP(movb_de_de), OP(movb_de_ded), OP(movb_de_ix), OP(movb_de_ixd), + OP(movb_de_rg), OP(movb_de_rgd), OP(movb_de_in), OP(movb_de_ind), OP(movb_de_de), OP(movb_de_ded), OP(movb_de_ix), OP(movb_de_ixd), + /* 0x9900 */ + OP(movb_de_rg), OP(movb_de_rgd), OP(movb_de_in), OP(movb_de_ind), OP(movb_de_de), OP(movb_de_ded), OP(movb_de_ix), OP(movb_de_ixd), + OP(movb_de_rg), OP(movb_de_rgd), OP(movb_de_in), OP(movb_de_ind), OP(movb_de_de), OP(movb_de_ded), OP(movb_de_ix), OP(movb_de_ixd), + OP(movb_de_rg), OP(movb_de_rgd), OP(movb_de_in), OP(movb_de_ind), OP(movb_de_de), OP(movb_de_ded), OP(movb_de_ix), OP(movb_de_ixd), + OP(movb_de_rg), OP(movb_de_rgd), OP(movb_de_in), OP(movb_de_ind), OP(movb_de_de), OP(movb_de_ded), OP(movb_de_ix), OP(movb_de_ixd), + /* 0x9a00 */ + OP(movb_ded_rg), OP(movb_ded_rgd), OP(movb_ded_in), OP(movb_ded_ind), OP(movb_ded_de), OP(movb_ded_ded), OP(movb_ded_ix), OP(movb_ded_ixd), + OP(movb_ded_rg), OP(movb_ded_rgd), OP(movb_ded_in), OP(movb_ded_ind), OP(movb_ded_de), OP(movb_ded_ded), OP(movb_ded_ix), OP(movb_ded_ixd), + OP(movb_ded_rg), OP(movb_ded_rgd), OP(movb_ded_in), OP(movb_ded_ind), OP(movb_ded_de), OP(movb_ded_ded), OP(movb_ded_ix), OP(movb_ded_ixd), + OP(movb_ded_rg), OP(movb_ded_rgd), OP(movb_ded_in), OP(movb_ded_ind), OP(movb_ded_de), OP(movb_ded_ded), OP(movb_ded_ix), OP(movb_ded_ixd), + /* 0x9b00 */ + OP(movb_ded_rg), OP(movb_ded_rgd), OP(movb_ded_in), OP(movb_ded_ind), OP(movb_ded_de), OP(movb_ded_ded), OP(movb_ded_ix), OP(movb_ded_ixd), + OP(movb_ded_rg), OP(movb_ded_rgd), OP(movb_ded_in), OP(movb_ded_ind), OP(movb_ded_de), OP(movb_ded_ded), OP(movb_ded_ix), OP(movb_ded_ixd), + OP(movb_ded_rg), OP(movb_ded_rgd), OP(movb_ded_in), OP(movb_ded_ind), OP(movb_ded_de), OP(movb_ded_ded), OP(movb_ded_ix), OP(movb_ded_ixd), + OP(movb_ded_rg), OP(movb_ded_rgd), OP(movb_ded_in), OP(movb_ded_ind), OP(movb_ded_de), OP(movb_ded_ded), OP(movb_ded_ix), OP(movb_ded_ixd), + /* 0x9c00 */ + OP(movb_ix_rg), OP(movb_ix_rgd), OP(movb_ix_in), OP(movb_ix_ind), OP(movb_ix_de), OP(movb_ix_ded), OP(movb_ix_ix), OP(movb_ix_ixd), + OP(movb_ix_rg), OP(movb_ix_rgd), OP(movb_ix_in), OP(movb_ix_ind), OP(movb_ix_de), OP(movb_ix_ded), OP(movb_ix_ix), OP(movb_ix_ixd), + OP(movb_ix_rg), OP(movb_ix_rgd), OP(movb_ix_in), OP(movb_ix_ind), OP(movb_ix_de), OP(movb_ix_ded), OP(movb_ix_ix), OP(movb_ix_ixd), + OP(movb_ix_rg), OP(movb_ix_rgd), OP(movb_ix_in), OP(movb_ix_ind), OP(movb_ix_de), OP(movb_ix_ded), OP(movb_ix_ix), OP(movb_ix_ixd), + /* 0x9d00 */ + OP(movb_ix_rg), OP(movb_ix_rgd), OP(movb_ix_in), OP(movb_ix_ind), OP(movb_ix_de), OP(movb_ix_ded), OP(movb_ix_ix), OP(movb_ix_ixd), + OP(movb_ix_rg), OP(movb_ix_rgd), OP(movb_ix_in), OP(movb_ix_ind), OP(movb_ix_de), OP(movb_ix_ded), OP(movb_ix_ix), OP(movb_ix_ixd), + OP(movb_ix_rg), OP(movb_ix_rgd), OP(movb_ix_in), OP(movb_ix_ind), OP(movb_ix_de), OP(movb_ix_ded), OP(movb_ix_ix), OP(movb_ix_ixd), + OP(movb_ix_rg), OP(movb_ix_rgd), OP(movb_ix_in), OP(movb_ix_ind), OP(movb_ix_de), OP(movb_ix_ded), OP(movb_ix_ix), OP(movb_ix_ixd), + /* 0x9e00 */ + OP(movb_ixd_rg), OP(movb_ixd_rgd), OP(movb_ixd_in), OP(movb_ixd_ind), OP(movb_ixd_de), OP(movb_ixd_ded), OP(movb_ixd_ix), OP(movb_ixd_ixd), + OP(movb_ixd_rg), OP(movb_ixd_rgd), OP(movb_ixd_in), OP(movb_ixd_ind), OP(movb_ixd_de), OP(movb_ixd_ded), OP(movb_ixd_ix), OP(movb_ixd_ixd), + OP(movb_ixd_rg), OP(movb_ixd_rgd), OP(movb_ixd_in), OP(movb_ixd_ind), OP(movb_ixd_de), OP(movb_ixd_ded), OP(movb_ixd_ix), OP(movb_ixd_ixd), + OP(movb_ixd_rg), OP(movb_ixd_rgd), OP(movb_ixd_in), OP(movb_ixd_ind), OP(movb_ixd_de), OP(movb_ixd_ded), OP(movb_ixd_ix), OP(movb_ixd_ixd), + /* 0x9f00 */ + OP(movb_ixd_rg), OP(movb_ixd_rgd), OP(movb_ixd_in), OP(movb_ixd_ind), OP(movb_ixd_de), OP(movb_ixd_ded), OP(movb_ixd_ix), OP(movb_ixd_ixd), + OP(movb_ixd_rg), OP(movb_ixd_rgd), OP(movb_ixd_in), OP(movb_ixd_ind), OP(movb_ixd_de), OP(movb_ixd_ded), OP(movb_ixd_ix), OP(movb_ixd_ixd), + OP(movb_ixd_rg), OP(movb_ixd_rgd), OP(movb_ixd_in), OP(movb_ixd_ind), OP(movb_ixd_de), OP(movb_ixd_ded), OP(movb_ixd_ix), OP(movb_ixd_ixd), + OP(movb_ixd_rg), OP(movb_ixd_rgd), OP(movb_ixd_in), OP(movb_ixd_ind), OP(movb_ixd_de), OP(movb_ixd_ded), OP(movb_ixd_ix), OP(movb_ixd_ixd), + + /* 0xa000 */ + OP(cmpb_rg_rg), OP(cmpb_rg_rgd), OP(cmpb_rg_in), OP(cmpb_rg_ind), OP(cmpb_rg_de), OP(cmpb_rg_ded), OP(cmpb_rg_ix), OP(cmpb_rg_ixd), + OP(cmpb_rg_rg), OP(cmpb_rg_rgd), OP(cmpb_rg_in), OP(cmpb_rg_ind), OP(cmpb_rg_de), OP(cmpb_rg_ded), OP(cmpb_rg_ix), OP(cmpb_rg_ixd), + OP(cmpb_rg_rg), OP(cmpb_rg_rgd), OP(cmpb_rg_in), OP(cmpb_rg_ind), OP(cmpb_rg_de), OP(cmpb_rg_ded), OP(cmpb_rg_ix), OP(cmpb_rg_ixd), + OP(cmpb_rg_rg), OP(cmpb_rg_rgd), OP(cmpb_rg_in), OP(cmpb_rg_ind), OP(cmpb_rg_de), OP(cmpb_rg_ded), OP(cmpb_rg_ix), OP(cmpb_rg_ixd), + /* 0xa100 */ + OP(cmpb_rg_rg), OP(cmpb_rg_rgd), OP(cmpb_rg_in), OP(cmpb_rg_ind), OP(cmpb_rg_de), OP(cmpb_rg_ded), OP(cmpb_rg_ix), OP(cmpb_rg_ixd), + OP(cmpb_rg_rg), OP(cmpb_rg_rgd), OP(cmpb_rg_in), OP(cmpb_rg_ind), OP(cmpb_rg_de), OP(cmpb_rg_ded), OP(cmpb_rg_ix), OP(cmpb_rg_ixd), + OP(cmpb_rg_rg), OP(cmpb_rg_rgd), OP(cmpb_rg_in), OP(cmpb_rg_ind), OP(cmpb_rg_de), OP(cmpb_rg_ded), OP(cmpb_rg_ix), OP(cmpb_rg_ixd), + OP(cmpb_rg_rg), OP(cmpb_rg_rgd), OP(cmpb_rg_in), OP(cmpb_rg_ind), OP(cmpb_rg_de), OP(cmpb_rg_ded), OP(cmpb_rg_ix), OP(cmpb_rg_ixd), + /* 0xa200 */ + OP(cmpb_rgd_rg), OP(cmpb_rgd_rgd), OP(cmpb_rgd_in), OP(cmpb_rgd_ind), OP(cmpb_rgd_de), OP(cmpb_rgd_ded), OP(cmpb_rgd_ix), OP(cmpb_rgd_ixd), + OP(cmpb_rgd_rg), OP(cmpb_rgd_rgd), OP(cmpb_rgd_in), OP(cmpb_rgd_ind), OP(cmpb_rgd_de), OP(cmpb_rgd_ded), OP(cmpb_rgd_ix), OP(cmpb_rgd_ixd), + OP(cmpb_rgd_rg), OP(cmpb_rgd_rgd), OP(cmpb_rgd_in), OP(cmpb_rgd_ind), OP(cmpb_rgd_de), OP(cmpb_rgd_ded), OP(cmpb_rgd_ix), OP(cmpb_rgd_ixd), + OP(cmpb_rgd_rg), OP(cmpb_rgd_rgd), OP(cmpb_rgd_in), OP(cmpb_rgd_ind), OP(cmpb_rgd_de), OP(cmpb_rgd_ded), OP(cmpb_rgd_ix), OP(cmpb_rgd_ixd), + /* 0xa300 */ + OP(cmpb_rgd_rg), OP(cmpb_rgd_rgd), OP(cmpb_rgd_in), OP(cmpb_rgd_ind), OP(cmpb_rgd_de), OP(cmpb_rgd_ded), OP(cmpb_rgd_ix), OP(cmpb_rgd_ixd), + OP(cmpb_rgd_rg), OP(cmpb_rgd_rgd), OP(cmpb_rgd_in), OP(cmpb_rgd_ind), OP(cmpb_rgd_de), OP(cmpb_rgd_ded), OP(cmpb_rgd_ix), OP(cmpb_rgd_ixd), + OP(cmpb_rgd_rg), OP(cmpb_rgd_rgd), OP(cmpb_rgd_in), OP(cmpb_rgd_ind), OP(cmpb_rgd_de), OP(cmpb_rgd_ded), OP(cmpb_rgd_ix), OP(cmpb_rgd_ixd), + OP(cmpb_rgd_rg), OP(cmpb_rgd_rgd), OP(cmpb_rgd_in), OP(cmpb_rgd_ind), OP(cmpb_rgd_de), OP(cmpb_rgd_ded), OP(cmpb_rgd_ix), OP(cmpb_rgd_ixd), + /* 0xa400 */ + OP(cmpb_in_rg), OP(cmpb_in_rgd), OP(cmpb_in_in), OP(cmpb_in_ind), OP(cmpb_in_de), OP(cmpb_in_ded), OP(cmpb_in_ix), OP(cmpb_in_ixd), + OP(cmpb_in_rg), OP(cmpb_in_rgd), OP(cmpb_in_in), OP(cmpb_in_ind), OP(cmpb_in_de), OP(cmpb_in_ded), OP(cmpb_in_ix), OP(cmpb_in_ixd), + OP(cmpb_in_rg), OP(cmpb_in_rgd), OP(cmpb_in_in), OP(cmpb_in_ind), OP(cmpb_in_de), OP(cmpb_in_ded), OP(cmpb_in_ix), OP(cmpb_in_ixd), + OP(cmpb_in_rg), OP(cmpb_in_rgd), OP(cmpb_in_in), OP(cmpb_in_ind), OP(cmpb_in_de), OP(cmpb_in_ded), OP(cmpb_in_ix), OP(cmpb_in_ixd), + /* 0xa500 */ + OP(cmpb_in_rg), OP(cmpb_in_rgd), OP(cmpb_in_in), OP(cmpb_in_ind), OP(cmpb_in_de), OP(cmpb_in_ded), OP(cmpb_in_ix), OP(cmpb_in_ixd), + OP(cmpb_in_rg), OP(cmpb_in_rgd), OP(cmpb_in_in), OP(cmpb_in_ind), OP(cmpb_in_de), OP(cmpb_in_ded), OP(cmpb_in_ix), OP(cmpb_in_ixd), + OP(cmpb_in_rg), OP(cmpb_in_rgd), OP(cmpb_in_in), OP(cmpb_in_ind), OP(cmpb_in_de), OP(cmpb_in_ded), OP(cmpb_in_ix), OP(cmpb_in_ixd), + OP(cmpb_in_rg), OP(cmpb_in_rgd), OP(cmpb_in_in), OP(cmpb_in_ind), OP(cmpb_in_de), OP(cmpb_in_ded), OP(cmpb_in_ix), OP(cmpb_in_ixd), + /* 0xa600 */ + OP(cmpb_ind_rg), OP(cmpb_ind_rgd), OP(cmpb_ind_in), OP(cmpb_ind_ind), OP(cmpb_ind_de), OP(cmpb_ind_ded), OP(cmpb_ind_ix), OP(cmpb_ind_ixd), + OP(cmpb_ind_rg), OP(cmpb_ind_rgd), OP(cmpb_ind_in), OP(cmpb_ind_ind), OP(cmpb_ind_de), OP(cmpb_ind_ded), OP(cmpb_ind_ix), OP(cmpb_ind_ixd), + OP(cmpb_ind_rg), OP(cmpb_ind_rgd), OP(cmpb_ind_in), OP(cmpb_ind_ind), OP(cmpb_ind_de), OP(cmpb_ind_ded), OP(cmpb_ind_ix), OP(cmpb_ind_ixd), + OP(cmpb_ind_rg), OP(cmpb_ind_rgd), OP(cmpb_ind_in), OP(cmpb_ind_ind), OP(cmpb_ind_de), OP(cmpb_ind_ded), OP(cmpb_ind_ix), OP(cmpb_ind_ixd), + /* 0xa700 */ + OP(cmpb_ind_rg), OP(cmpb_ind_rgd), OP(cmpb_ind_in), OP(cmpb_ind_ind), OP(cmpb_ind_de), OP(cmpb_ind_ded), OP(cmpb_ind_ix), OP(cmpb_ind_ixd), + OP(cmpb_ind_rg), OP(cmpb_ind_rgd), OP(cmpb_ind_in), OP(cmpb_ind_ind), OP(cmpb_ind_de), OP(cmpb_ind_ded), OP(cmpb_ind_ix), OP(cmpb_ind_ixd), + OP(cmpb_ind_rg), OP(cmpb_ind_rgd), OP(cmpb_ind_in), OP(cmpb_ind_ind), OP(cmpb_ind_de), OP(cmpb_ind_ded), OP(cmpb_ind_ix), OP(cmpb_ind_ixd), + OP(cmpb_ind_rg), OP(cmpb_ind_rgd), OP(cmpb_ind_in), OP(cmpb_ind_ind), OP(cmpb_ind_de), OP(cmpb_ind_ded), OP(cmpb_ind_ix), OP(cmpb_ind_ixd), + /* 0xa800 */ + OP(cmpb_de_rg), OP(cmpb_de_rgd), OP(cmpb_de_in), OP(cmpb_de_ind), OP(cmpb_de_de), OP(cmpb_de_ded), OP(cmpb_de_ix), OP(cmpb_de_ixd), + OP(cmpb_de_rg), OP(cmpb_de_rgd), OP(cmpb_de_in), OP(cmpb_de_ind), OP(cmpb_de_de), OP(cmpb_de_ded), OP(cmpb_de_ix), OP(cmpb_de_ixd), + OP(cmpb_de_rg), OP(cmpb_de_rgd), OP(cmpb_de_in), OP(cmpb_de_ind), OP(cmpb_de_de), OP(cmpb_de_ded), OP(cmpb_de_ix), OP(cmpb_de_ixd), + OP(cmpb_de_rg), OP(cmpb_de_rgd), OP(cmpb_de_in), OP(cmpb_de_ind), OP(cmpb_de_de), OP(cmpb_de_ded), OP(cmpb_de_ix), OP(cmpb_de_ixd), + /* 0xa900 */ + OP(cmpb_de_rg), OP(cmpb_de_rgd), OP(cmpb_de_in), OP(cmpb_de_ind), OP(cmpb_de_de), OP(cmpb_de_ded), OP(cmpb_de_ix), OP(cmpb_de_ixd), + OP(cmpb_de_rg), OP(cmpb_de_rgd), OP(cmpb_de_in), OP(cmpb_de_ind), OP(cmpb_de_de), OP(cmpb_de_ded), OP(cmpb_de_ix), OP(cmpb_de_ixd), + OP(cmpb_de_rg), OP(cmpb_de_rgd), OP(cmpb_de_in), OP(cmpb_de_ind), OP(cmpb_de_de), OP(cmpb_de_ded), OP(cmpb_de_ix), OP(cmpb_de_ixd), + OP(cmpb_de_rg), OP(cmpb_de_rgd), OP(cmpb_de_in), OP(cmpb_de_ind), OP(cmpb_de_de), OP(cmpb_de_ded), OP(cmpb_de_ix), OP(cmpb_de_ixd), + /* 0xaa00 */ + OP(cmpb_ded_rg), OP(cmpb_ded_rgd), OP(cmpb_ded_in), OP(cmpb_ded_ind), OP(cmpb_ded_de), OP(cmpb_ded_ded), OP(cmpb_ded_ix), OP(cmpb_ded_ixd), + OP(cmpb_ded_rg), OP(cmpb_ded_rgd), OP(cmpb_ded_in), OP(cmpb_ded_ind), OP(cmpb_ded_de), OP(cmpb_ded_ded), OP(cmpb_ded_ix), OP(cmpb_ded_ixd), + OP(cmpb_ded_rg), OP(cmpb_ded_rgd), OP(cmpb_ded_in), OP(cmpb_ded_ind), OP(cmpb_ded_de), OP(cmpb_ded_ded), OP(cmpb_ded_ix), OP(cmpb_ded_ixd), + OP(cmpb_ded_rg), OP(cmpb_ded_rgd), OP(cmpb_ded_in), OP(cmpb_ded_ind), OP(cmpb_ded_de), OP(cmpb_ded_ded), OP(cmpb_ded_ix), OP(cmpb_ded_ixd), + /* 0xab00 */ + OP(cmpb_ded_rg), OP(cmpb_ded_rgd), OP(cmpb_ded_in), OP(cmpb_ded_ind), OP(cmpb_ded_de), OP(cmpb_ded_ded), OP(cmpb_ded_ix), OP(cmpb_ded_ixd), + OP(cmpb_ded_rg), OP(cmpb_ded_rgd), OP(cmpb_ded_in), OP(cmpb_ded_ind), OP(cmpb_ded_de), OP(cmpb_ded_ded), OP(cmpb_ded_ix), OP(cmpb_ded_ixd), + OP(cmpb_ded_rg), OP(cmpb_ded_rgd), OP(cmpb_ded_in), OP(cmpb_ded_ind), OP(cmpb_ded_de), OP(cmpb_ded_ded), OP(cmpb_ded_ix), OP(cmpb_ded_ixd), + OP(cmpb_ded_rg), OP(cmpb_ded_rgd), OP(cmpb_ded_in), OP(cmpb_ded_ind), OP(cmpb_ded_de), OP(cmpb_ded_ded), OP(cmpb_ded_ix), OP(cmpb_ded_ixd), + /* 0xac00 */ + OP(cmpb_ix_rg), OP(cmpb_ix_rgd), OP(cmpb_ix_in), OP(cmpb_ix_ind), OP(cmpb_ix_de), OP(cmpb_ix_ded), OP(cmpb_ix_ix), OP(cmpb_ix_ixd), + OP(cmpb_ix_rg), OP(cmpb_ix_rgd), OP(cmpb_ix_in), OP(cmpb_ix_ind), OP(cmpb_ix_de), OP(cmpb_ix_ded), OP(cmpb_ix_ix), OP(cmpb_ix_ixd), + OP(cmpb_ix_rg), OP(cmpb_ix_rgd), OP(cmpb_ix_in), OP(cmpb_ix_ind), OP(cmpb_ix_de), OP(cmpb_ix_ded), OP(cmpb_ix_ix), OP(cmpb_ix_ixd), + OP(cmpb_ix_rg), OP(cmpb_ix_rgd), OP(cmpb_ix_in), OP(cmpb_ix_ind), OP(cmpb_ix_de), OP(cmpb_ix_ded), OP(cmpb_ix_ix), OP(cmpb_ix_ixd), + /* 0xad00 */ + OP(cmpb_ix_rg), OP(cmpb_ix_rgd), OP(cmpb_ix_in), OP(cmpb_ix_ind), OP(cmpb_ix_de), OP(cmpb_ix_ded), OP(cmpb_ix_ix), OP(cmpb_ix_ixd), + OP(cmpb_ix_rg), OP(cmpb_ix_rgd), OP(cmpb_ix_in), OP(cmpb_ix_ind), OP(cmpb_ix_de), OP(cmpb_ix_ded), OP(cmpb_ix_ix), OP(cmpb_ix_ixd), + OP(cmpb_ix_rg), OP(cmpb_ix_rgd), OP(cmpb_ix_in), OP(cmpb_ix_ind), OP(cmpb_ix_de), OP(cmpb_ix_ded), OP(cmpb_ix_ix), OP(cmpb_ix_ixd), + OP(cmpb_ix_rg), OP(cmpb_ix_rgd), OP(cmpb_ix_in), OP(cmpb_ix_ind), OP(cmpb_ix_de), OP(cmpb_ix_ded), OP(cmpb_ix_ix), OP(cmpb_ix_ixd), + /* 0xae00 */ + OP(cmpb_ixd_rg), OP(cmpb_ixd_rgd), OP(cmpb_ixd_in), OP(cmpb_ixd_ind), OP(cmpb_ixd_de), OP(cmpb_ixd_ded), OP(cmpb_ixd_ix), OP(cmpb_ixd_ixd), + OP(cmpb_ixd_rg), OP(cmpb_ixd_rgd), OP(cmpb_ixd_in), OP(cmpb_ixd_ind), OP(cmpb_ixd_de), OP(cmpb_ixd_ded), OP(cmpb_ixd_ix), OP(cmpb_ixd_ixd), + OP(cmpb_ixd_rg), OP(cmpb_ixd_rgd), OP(cmpb_ixd_in), OP(cmpb_ixd_ind), OP(cmpb_ixd_de), OP(cmpb_ixd_ded), OP(cmpb_ixd_ix), OP(cmpb_ixd_ixd), + OP(cmpb_ixd_rg), OP(cmpb_ixd_rgd), OP(cmpb_ixd_in), OP(cmpb_ixd_ind), OP(cmpb_ixd_de), OP(cmpb_ixd_ded), OP(cmpb_ixd_ix), OP(cmpb_ixd_ixd), + /* 0xaf00 */ + OP(cmpb_ixd_rg), OP(cmpb_ixd_rgd), OP(cmpb_ixd_in), OP(cmpb_ixd_ind), OP(cmpb_ixd_de), OP(cmpb_ixd_ded), OP(cmpb_ixd_ix), OP(cmpb_ixd_ixd), + OP(cmpb_ixd_rg), OP(cmpb_ixd_rgd), OP(cmpb_ixd_in), OP(cmpb_ixd_ind), OP(cmpb_ixd_de), OP(cmpb_ixd_ded), OP(cmpb_ixd_ix), OP(cmpb_ixd_ixd), + OP(cmpb_ixd_rg), OP(cmpb_ixd_rgd), OP(cmpb_ixd_in), OP(cmpb_ixd_ind), OP(cmpb_ixd_de), OP(cmpb_ixd_ded), OP(cmpb_ixd_ix), OP(cmpb_ixd_ixd), + OP(cmpb_ixd_rg), OP(cmpb_ixd_rgd), OP(cmpb_ixd_in), OP(cmpb_ixd_ind), OP(cmpb_ixd_de), OP(cmpb_ixd_ded), OP(cmpb_ixd_ix), OP(cmpb_ixd_ixd), + + /* 0xb000 */ + OP(bitb_rg_rg), OP(bitb_rg_rgd), OP(bitb_rg_in), OP(bitb_rg_ind), OP(bitb_rg_de), OP(bitb_rg_ded), OP(bitb_rg_ix), OP(bitb_rg_ixd), + OP(bitb_rg_rg), OP(bitb_rg_rgd), OP(bitb_rg_in), OP(bitb_rg_ind), OP(bitb_rg_de), OP(bitb_rg_ded), OP(bitb_rg_ix), OP(bitb_rg_ixd), + OP(bitb_rg_rg), OP(bitb_rg_rgd), OP(bitb_rg_in), OP(bitb_rg_ind), OP(bitb_rg_de), OP(bitb_rg_ded), OP(bitb_rg_ix), OP(bitb_rg_ixd), + OP(bitb_rg_rg), OP(bitb_rg_rgd), OP(bitb_rg_in), OP(bitb_rg_ind), OP(bitb_rg_de), OP(bitb_rg_ded), OP(bitb_rg_ix), OP(bitb_rg_ixd), + /* 0xb100 */ + OP(bitb_rg_rg), OP(bitb_rg_rgd), OP(bitb_rg_in), OP(bitb_rg_ind), OP(bitb_rg_de), OP(bitb_rg_ded), OP(bitb_rg_ix), OP(bitb_rg_ixd), + OP(bitb_rg_rg), OP(bitb_rg_rgd), OP(bitb_rg_in), OP(bitb_rg_ind), OP(bitb_rg_de), OP(bitb_rg_ded), OP(bitb_rg_ix), OP(bitb_rg_ixd), + OP(bitb_rg_rg), OP(bitb_rg_rgd), OP(bitb_rg_in), OP(bitb_rg_ind), OP(bitb_rg_de), OP(bitb_rg_ded), OP(bitb_rg_ix), OP(bitb_rg_ixd), + OP(bitb_rg_rg), OP(bitb_rg_rgd), OP(bitb_rg_in), OP(bitb_rg_ind), OP(bitb_rg_de), OP(bitb_rg_ded), OP(bitb_rg_ix), OP(bitb_rg_ixd), + /* 0xb200 */ + OP(bitb_rgd_rg), OP(bitb_rgd_rgd), OP(bitb_rgd_in), OP(bitb_rgd_ind), OP(bitb_rgd_de), OP(bitb_rgd_ded), OP(bitb_rgd_ix), OP(bitb_rgd_ixd), + OP(bitb_rgd_rg), OP(bitb_rgd_rgd), OP(bitb_rgd_in), OP(bitb_rgd_ind), OP(bitb_rgd_de), OP(bitb_rgd_ded), OP(bitb_rgd_ix), OP(bitb_rgd_ixd), + OP(bitb_rgd_rg), OP(bitb_rgd_rgd), OP(bitb_rgd_in), OP(bitb_rgd_ind), OP(bitb_rgd_de), OP(bitb_rgd_ded), OP(bitb_rgd_ix), OP(bitb_rgd_ixd), + OP(bitb_rgd_rg), OP(bitb_rgd_rgd), OP(bitb_rgd_in), OP(bitb_rgd_ind), OP(bitb_rgd_de), OP(bitb_rgd_ded), OP(bitb_rgd_ix), OP(bitb_rgd_ixd), + /* 0xb300 */ + OP(bitb_rgd_rg), OP(bitb_rgd_rgd), OP(bitb_rgd_in), OP(bitb_rgd_ind), OP(bitb_rgd_de), OP(bitb_rgd_ded), OP(bitb_rgd_ix), OP(bitb_rgd_ixd), + OP(bitb_rgd_rg), OP(bitb_rgd_rgd), OP(bitb_rgd_in), OP(bitb_rgd_ind), OP(bitb_rgd_de), OP(bitb_rgd_ded), OP(bitb_rgd_ix), OP(bitb_rgd_ixd), + OP(bitb_rgd_rg), OP(bitb_rgd_rgd), OP(bitb_rgd_in), OP(bitb_rgd_ind), OP(bitb_rgd_de), OP(bitb_rgd_ded), OP(bitb_rgd_ix), OP(bitb_rgd_ixd), + OP(bitb_rgd_rg), OP(bitb_rgd_rgd), OP(bitb_rgd_in), OP(bitb_rgd_ind), OP(bitb_rgd_de), OP(bitb_rgd_ded), OP(bitb_rgd_ix), OP(bitb_rgd_ixd), + /* 0xb400 */ + OP(bitb_in_rg), OP(bitb_in_rgd), OP(bitb_in_in), OP(bitb_in_ind), OP(bitb_in_de), OP(bitb_in_ded), OP(bitb_in_ix), OP(bitb_in_ixd), + OP(bitb_in_rg), OP(bitb_in_rgd), OP(bitb_in_in), OP(bitb_in_ind), OP(bitb_in_de), OP(bitb_in_ded), OP(bitb_in_ix), OP(bitb_in_ixd), + OP(bitb_in_rg), OP(bitb_in_rgd), OP(bitb_in_in), OP(bitb_in_ind), OP(bitb_in_de), OP(bitb_in_ded), OP(bitb_in_ix), OP(bitb_in_ixd), + OP(bitb_in_rg), OP(bitb_in_rgd), OP(bitb_in_in), OP(bitb_in_ind), OP(bitb_in_de), OP(bitb_in_ded), OP(bitb_in_ix), OP(bitb_in_ixd), + /* 0xb500 */ + OP(bitb_in_rg), OP(bitb_in_rgd), OP(bitb_in_in), OP(bitb_in_ind), OP(bitb_in_de), OP(bitb_in_ded), OP(bitb_in_ix), OP(bitb_in_ixd), + OP(bitb_in_rg), OP(bitb_in_rgd), OP(bitb_in_in), OP(bitb_in_ind), OP(bitb_in_de), OP(bitb_in_ded), OP(bitb_in_ix), OP(bitb_in_ixd), + OP(bitb_in_rg), OP(bitb_in_rgd), OP(bitb_in_in), OP(bitb_in_ind), OP(bitb_in_de), OP(bitb_in_ded), OP(bitb_in_ix), OP(bitb_in_ixd), + OP(bitb_in_rg), OP(bitb_in_rgd), OP(bitb_in_in), OP(bitb_in_ind), OP(bitb_in_de), OP(bitb_in_ded), OP(bitb_in_ix), OP(bitb_in_ixd), + /* 0xb600 */ + OP(bitb_ind_rg), OP(bitb_ind_rgd), OP(bitb_ind_in), OP(bitb_ind_ind), OP(bitb_ind_de), OP(bitb_ind_ded), OP(bitb_ind_ix), OP(bitb_ind_ixd), + OP(bitb_ind_rg), OP(bitb_ind_rgd), OP(bitb_ind_in), OP(bitb_ind_ind), OP(bitb_ind_de), OP(bitb_ind_ded), OP(bitb_ind_ix), OP(bitb_ind_ixd), + OP(bitb_ind_rg), OP(bitb_ind_rgd), OP(bitb_ind_in), OP(bitb_ind_ind), OP(bitb_ind_de), OP(bitb_ind_ded), OP(bitb_ind_ix), OP(bitb_ind_ixd), + OP(bitb_ind_rg), OP(bitb_ind_rgd), OP(bitb_ind_in), OP(bitb_ind_ind), OP(bitb_ind_de), OP(bitb_ind_ded), OP(bitb_ind_ix), OP(bitb_ind_ixd), + /* 0xb700 */ + OP(bitb_ind_rg), OP(bitb_ind_rgd), OP(bitb_ind_in), OP(bitb_ind_ind), OP(bitb_ind_de), OP(bitb_ind_ded), OP(bitb_ind_ix), OP(bitb_ind_ixd), + OP(bitb_ind_rg), OP(bitb_ind_rgd), OP(bitb_ind_in), OP(bitb_ind_ind), OP(bitb_ind_de), OP(bitb_ind_ded), OP(bitb_ind_ix), OP(bitb_ind_ixd), + OP(bitb_ind_rg), OP(bitb_ind_rgd), OP(bitb_ind_in), OP(bitb_ind_ind), OP(bitb_ind_de), OP(bitb_ind_ded), OP(bitb_ind_ix), OP(bitb_ind_ixd), + OP(bitb_ind_rg), OP(bitb_ind_rgd), OP(bitb_ind_in), OP(bitb_ind_ind), OP(bitb_ind_de), OP(bitb_ind_ded), OP(bitb_ind_ix), OP(bitb_ind_ixd), + /* 0xb800 */ + OP(bitb_de_rg), OP(bitb_de_rgd), OP(bitb_de_in), OP(bitb_de_ind), OP(bitb_de_de), OP(bitb_de_ded), OP(bitb_de_ix), OP(bitb_de_ixd), + OP(bitb_de_rg), OP(bitb_de_rgd), OP(bitb_de_in), OP(bitb_de_ind), OP(bitb_de_de), OP(bitb_de_ded), OP(bitb_de_ix), OP(bitb_de_ixd), + OP(bitb_de_rg), OP(bitb_de_rgd), OP(bitb_de_in), OP(bitb_de_ind), OP(bitb_de_de), OP(bitb_de_ded), OP(bitb_de_ix), OP(bitb_de_ixd), + OP(bitb_de_rg), OP(bitb_de_rgd), OP(bitb_de_in), OP(bitb_de_ind), OP(bitb_de_de), OP(bitb_de_ded), OP(bitb_de_ix), OP(bitb_de_ixd), + /* 0xb900 */ + OP(bitb_de_rg), OP(bitb_de_rgd), OP(bitb_de_in), OP(bitb_de_ind), OP(bitb_de_de), OP(bitb_de_ded), OP(bitb_de_ix), OP(bitb_de_ixd), + OP(bitb_de_rg), OP(bitb_de_rgd), OP(bitb_de_in), OP(bitb_de_ind), OP(bitb_de_de), OP(bitb_de_ded), OP(bitb_de_ix), OP(bitb_de_ixd), + OP(bitb_de_rg), OP(bitb_de_rgd), OP(bitb_de_in), OP(bitb_de_ind), OP(bitb_de_de), OP(bitb_de_ded), OP(bitb_de_ix), OP(bitb_de_ixd), + OP(bitb_de_rg), OP(bitb_de_rgd), OP(bitb_de_in), OP(bitb_de_ind), OP(bitb_de_de), OP(bitb_de_ded), OP(bitb_de_ix), OP(bitb_de_ixd), + /* 0xba00 */ + OP(bitb_ded_rg), OP(bitb_ded_rgd), OP(bitb_ded_in), OP(bitb_ded_ind), OP(bitb_ded_de), OP(bitb_ded_ded), OP(bitb_ded_ix), OP(bitb_ded_ixd), + OP(bitb_ded_rg), OP(bitb_ded_rgd), OP(bitb_ded_in), OP(bitb_ded_ind), OP(bitb_ded_de), OP(bitb_ded_ded), OP(bitb_ded_ix), OP(bitb_ded_ixd), + OP(bitb_ded_rg), OP(bitb_ded_rgd), OP(bitb_ded_in), OP(bitb_ded_ind), OP(bitb_ded_de), OP(bitb_ded_ded), OP(bitb_ded_ix), OP(bitb_ded_ixd), + OP(bitb_ded_rg), OP(bitb_ded_rgd), OP(bitb_ded_in), OP(bitb_ded_ind), OP(bitb_ded_de), OP(bitb_ded_ded), OP(bitb_ded_ix), OP(bitb_ded_ixd), + /* 0xbb00 */ + OP(bitb_ded_rg), OP(bitb_ded_rgd), OP(bitb_ded_in), OP(bitb_ded_ind), OP(bitb_ded_de), OP(bitb_ded_ded), OP(bitb_ded_ix), OP(bitb_ded_ixd), + OP(bitb_ded_rg), OP(bitb_ded_rgd), OP(bitb_ded_in), OP(bitb_ded_ind), OP(bitb_ded_de), OP(bitb_ded_ded), OP(bitb_ded_ix), OP(bitb_ded_ixd), + OP(bitb_ded_rg), OP(bitb_ded_rgd), OP(bitb_ded_in), OP(bitb_ded_ind), OP(bitb_ded_de), OP(bitb_ded_ded), OP(bitb_ded_ix), OP(bitb_ded_ixd), + OP(bitb_ded_rg), OP(bitb_ded_rgd), OP(bitb_ded_in), OP(bitb_ded_ind), OP(bitb_ded_de), OP(bitb_ded_ded), OP(bitb_ded_ix), OP(bitb_ded_ixd), + /* 0xbc00 */ + OP(bitb_ix_rg), OP(bitb_ix_rgd), OP(bitb_ix_in), OP(bitb_ix_ind), OP(bitb_ix_de), OP(bitb_ix_ded), OP(bitb_ix_ix), OP(bitb_ix_ixd), + OP(bitb_ix_rg), OP(bitb_ix_rgd), OP(bitb_ix_in), OP(bitb_ix_ind), OP(bitb_ix_de), OP(bitb_ix_ded), OP(bitb_ix_ix), OP(bitb_ix_ixd), + OP(bitb_ix_rg), OP(bitb_ix_rgd), OP(bitb_ix_in), OP(bitb_ix_ind), OP(bitb_ix_de), OP(bitb_ix_ded), OP(bitb_ix_ix), OP(bitb_ix_ixd), + OP(bitb_ix_rg), OP(bitb_ix_rgd), OP(bitb_ix_in), OP(bitb_ix_ind), OP(bitb_ix_de), OP(bitb_ix_ded), OP(bitb_ix_ix), OP(bitb_ix_ixd), + /* 0xbd00 */ + OP(bitb_ix_rg), OP(bitb_ix_rgd), OP(bitb_ix_in), OP(bitb_ix_ind), OP(bitb_ix_de), OP(bitb_ix_ded), OP(bitb_ix_ix), OP(bitb_ix_ixd), + OP(bitb_ix_rg), OP(bitb_ix_rgd), OP(bitb_ix_in), OP(bitb_ix_ind), OP(bitb_ix_de), OP(bitb_ix_ded), OP(bitb_ix_ix), OP(bitb_ix_ixd), + OP(bitb_ix_rg), OP(bitb_ix_rgd), OP(bitb_ix_in), OP(bitb_ix_ind), OP(bitb_ix_de), OP(bitb_ix_ded), OP(bitb_ix_ix), OP(bitb_ix_ixd), + OP(bitb_ix_rg), OP(bitb_ix_rgd), OP(bitb_ix_in), OP(bitb_ix_ind), OP(bitb_ix_de), OP(bitb_ix_ded), OP(bitb_ix_ix), OP(bitb_ix_ixd), + /* 0xbe00 */ + OP(bitb_ixd_rg), OP(bitb_ixd_rgd), OP(bitb_ixd_in), OP(bitb_ixd_ind), OP(bitb_ixd_de), OP(bitb_ixd_ded), OP(bitb_ixd_ix), OP(bitb_ixd_ixd), + OP(bitb_ixd_rg), OP(bitb_ixd_rgd), OP(bitb_ixd_in), OP(bitb_ixd_ind), OP(bitb_ixd_de), OP(bitb_ixd_ded), OP(bitb_ixd_ix), OP(bitb_ixd_ixd), + OP(bitb_ixd_rg), OP(bitb_ixd_rgd), OP(bitb_ixd_in), OP(bitb_ixd_ind), OP(bitb_ixd_de), OP(bitb_ixd_ded), OP(bitb_ixd_ix), OP(bitb_ixd_ixd), + OP(bitb_ixd_rg), OP(bitb_ixd_rgd), OP(bitb_ixd_in), OP(bitb_ixd_ind), OP(bitb_ixd_de), OP(bitb_ixd_ded), OP(bitb_ixd_ix), OP(bitb_ixd_ixd), + /* 0xbf00 */ + OP(bitb_ixd_rg), OP(bitb_ixd_rgd), OP(bitb_ixd_in), OP(bitb_ixd_ind), OP(bitb_ixd_de), OP(bitb_ixd_ded), OP(bitb_ixd_ix), OP(bitb_ixd_ixd), + OP(bitb_ixd_rg), OP(bitb_ixd_rgd), OP(bitb_ixd_in), OP(bitb_ixd_ind), OP(bitb_ixd_de), OP(bitb_ixd_ded), OP(bitb_ixd_ix), OP(bitb_ixd_ixd), + OP(bitb_ixd_rg), OP(bitb_ixd_rgd), OP(bitb_ixd_in), OP(bitb_ixd_ind), OP(bitb_ixd_de), OP(bitb_ixd_ded), OP(bitb_ixd_ix), OP(bitb_ixd_ixd), + OP(bitb_ixd_rg), OP(bitb_ixd_rgd), OP(bitb_ixd_in), OP(bitb_ixd_ind), OP(bitb_ixd_de), OP(bitb_ixd_ded), OP(bitb_ixd_ix), OP(bitb_ixd_ixd), + + /* 0xc000 */ + OP(bicb_rg_rg), OP(bicb_rg_rgd), OP(bicb_rg_in), OP(bicb_rg_ind), OP(bicb_rg_de), OP(bicb_rg_ded), OP(bicb_rg_ix), OP(bicb_rg_ixd), + OP(bicb_rg_rg), OP(bicb_rg_rgd), OP(bicb_rg_in), OP(bicb_rg_ind), OP(bicb_rg_de), OP(bicb_rg_ded), OP(bicb_rg_ix), OP(bicb_rg_ixd), + OP(bicb_rg_rg), OP(bicb_rg_rgd), OP(bicb_rg_in), OP(bicb_rg_ind), OP(bicb_rg_de), OP(bicb_rg_ded), OP(bicb_rg_ix), OP(bicb_rg_ixd), + OP(bicb_rg_rg), OP(bicb_rg_rgd), OP(bicb_rg_in), OP(bicb_rg_ind), OP(bicb_rg_de), OP(bicb_rg_ded), OP(bicb_rg_ix), OP(bicb_rg_ixd), + /* 0xc100 */ + OP(bicb_rg_rg), OP(bicb_rg_rgd), OP(bicb_rg_in), OP(bicb_rg_ind), OP(bicb_rg_de), OP(bicb_rg_ded), OP(bicb_rg_ix), OP(bicb_rg_ixd), + OP(bicb_rg_rg), OP(bicb_rg_rgd), OP(bicb_rg_in), OP(bicb_rg_ind), OP(bicb_rg_de), OP(bicb_rg_ded), OP(bicb_rg_ix), OP(bicb_rg_ixd), + OP(bicb_rg_rg), OP(bicb_rg_rgd), OP(bicb_rg_in), OP(bicb_rg_ind), OP(bicb_rg_de), OP(bicb_rg_ded), OP(bicb_rg_ix), OP(bicb_rg_ixd), + OP(bicb_rg_rg), OP(bicb_rg_rgd), OP(bicb_rg_in), OP(bicb_rg_ind), OP(bicb_rg_de), OP(bicb_rg_ded), OP(bicb_rg_ix), OP(bicb_rg_ixd), + /* 0xc200 */ + OP(bicb_rgd_rg), OP(bicb_rgd_rgd), OP(bicb_rgd_in), OP(bicb_rgd_ind), OP(bicb_rgd_de), OP(bicb_rgd_ded), OP(bicb_rgd_ix), OP(bicb_rgd_ixd), + OP(bicb_rgd_rg), OP(bicb_rgd_rgd), OP(bicb_rgd_in), OP(bicb_rgd_ind), OP(bicb_rgd_de), OP(bicb_rgd_ded), OP(bicb_rgd_ix), OP(bicb_rgd_ixd), + OP(bicb_rgd_rg), OP(bicb_rgd_rgd), OP(bicb_rgd_in), OP(bicb_rgd_ind), OP(bicb_rgd_de), OP(bicb_rgd_ded), OP(bicb_rgd_ix), OP(bicb_rgd_ixd), + OP(bicb_rgd_rg), OP(bicb_rgd_rgd), OP(bicb_rgd_in), OP(bicb_rgd_ind), OP(bicb_rgd_de), OP(bicb_rgd_ded), OP(bicb_rgd_ix), OP(bicb_rgd_ixd), + /* 0xc300 */ + OP(bicb_rgd_rg), OP(bicb_rgd_rgd), OP(bicb_rgd_in), OP(bicb_rgd_ind), OP(bicb_rgd_de), OP(bicb_rgd_ded), OP(bicb_rgd_ix), OP(bicb_rgd_ixd), + OP(bicb_rgd_rg), OP(bicb_rgd_rgd), OP(bicb_rgd_in), OP(bicb_rgd_ind), OP(bicb_rgd_de), OP(bicb_rgd_ded), OP(bicb_rgd_ix), OP(bicb_rgd_ixd), + OP(bicb_rgd_rg), OP(bicb_rgd_rgd), OP(bicb_rgd_in), OP(bicb_rgd_ind), OP(bicb_rgd_de), OP(bicb_rgd_ded), OP(bicb_rgd_ix), OP(bicb_rgd_ixd), + OP(bicb_rgd_rg), OP(bicb_rgd_rgd), OP(bicb_rgd_in), OP(bicb_rgd_ind), OP(bicb_rgd_de), OP(bicb_rgd_ded), OP(bicb_rgd_ix), OP(bicb_rgd_ixd), + /* 0xc400 */ + OP(bicb_in_rg), OP(bicb_in_rgd), OP(bicb_in_in), OP(bicb_in_ind), OP(bicb_in_de), OP(bicb_in_ded), OP(bicb_in_ix), OP(bicb_in_ixd), + OP(bicb_in_rg), OP(bicb_in_rgd), OP(bicb_in_in), OP(bicb_in_ind), OP(bicb_in_de), OP(bicb_in_ded), OP(bicb_in_ix), OP(bicb_in_ixd), + OP(bicb_in_rg), OP(bicb_in_rgd), OP(bicb_in_in), OP(bicb_in_ind), OP(bicb_in_de), OP(bicb_in_ded), OP(bicb_in_ix), OP(bicb_in_ixd), + OP(bicb_in_rg), OP(bicb_in_rgd), OP(bicb_in_in), OP(bicb_in_ind), OP(bicb_in_de), OP(bicb_in_ded), OP(bicb_in_ix), OP(bicb_in_ixd), + /* 0xc500 */ + OP(bicb_in_rg), OP(bicb_in_rgd), OP(bicb_in_in), OP(bicb_in_ind), OP(bicb_in_de), OP(bicb_in_ded), OP(bicb_in_ix), OP(bicb_in_ixd), + OP(bicb_in_rg), OP(bicb_in_rgd), OP(bicb_in_in), OP(bicb_in_ind), OP(bicb_in_de), OP(bicb_in_ded), OP(bicb_in_ix), OP(bicb_in_ixd), + OP(bicb_in_rg), OP(bicb_in_rgd), OP(bicb_in_in), OP(bicb_in_ind), OP(bicb_in_de), OP(bicb_in_ded), OP(bicb_in_ix), OP(bicb_in_ixd), + OP(bicb_in_rg), OP(bicb_in_rgd), OP(bicb_in_in), OP(bicb_in_ind), OP(bicb_in_de), OP(bicb_in_ded), OP(bicb_in_ix), OP(bicb_in_ixd), + /* 0xc600 */ + OP(bicb_ind_rg), OP(bicb_ind_rgd), OP(bicb_ind_in), OP(bicb_ind_ind), OP(bicb_ind_de), OP(bicb_ind_ded), OP(bicb_ind_ix), OP(bicb_ind_ixd), + OP(bicb_ind_rg), OP(bicb_ind_rgd), OP(bicb_ind_in), OP(bicb_ind_ind), OP(bicb_ind_de), OP(bicb_ind_ded), OP(bicb_ind_ix), OP(bicb_ind_ixd), + OP(bicb_ind_rg), OP(bicb_ind_rgd), OP(bicb_ind_in), OP(bicb_ind_ind), OP(bicb_ind_de), OP(bicb_ind_ded), OP(bicb_ind_ix), OP(bicb_ind_ixd), + OP(bicb_ind_rg), OP(bicb_ind_rgd), OP(bicb_ind_in), OP(bicb_ind_ind), OP(bicb_ind_de), OP(bicb_ind_ded), OP(bicb_ind_ix), OP(bicb_ind_ixd), + /* 0xc700 */ + OP(bicb_ind_rg), OP(bicb_ind_rgd), OP(bicb_ind_in), OP(bicb_ind_ind), OP(bicb_ind_de), OP(bicb_ind_ded), OP(bicb_ind_ix), OP(bicb_ind_ixd), + OP(bicb_ind_rg), OP(bicb_ind_rgd), OP(bicb_ind_in), OP(bicb_ind_ind), OP(bicb_ind_de), OP(bicb_ind_ded), OP(bicb_ind_ix), OP(bicb_ind_ixd), + OP(bicb_ind_rg), OP(bicb_ind_rgd), OP(bicb_ind_in), OP(bicb_ind_ind), OP(bicb_ind_de), OP(bicb_ind_ded), OP(bicb_ind_ix), OP(bicb_ind_ixd), + OP(bicb_ind_rg), OP(bicb_ind_rgd), OP(bicb_ind_in), OP(bicb_ind_ind), OP(bicb_ind_de), OP(bicb_ind_ded), OP(bicb_ind_ix), OP(bicb_ind_ixd), + /* 0xc800 */ + OP(bicb_de_rg), OP(bicb_de_rgd), OP(bicb_de_in), OP(bicb_de_ind), OP(bicb_de_de), OP(bicb_de_ded), OP(bicb_de_ix), OP(bicb_de_ixd), + OP(bicb_de_rg), OP(bicb_de_rgd), OP(bicb_de_in), OP(bicb_de_ind), OP(bicb_de_de), OP(bicb_de_ded), OP(bicb_de_ix), OP(bicb_de_ixd), + OP(bicb_de_rg), OP(bicb_de_rgd), OP(bicb_de_in), OP(bicb_de_ind), OP(bicb_de_de), OP(bicb_de_ded), OP(bicb_de_ix), OP(bicb_de_ixd), + OP(bicb_de_rg), OP(bicb_de_rgd), OP(bicb_de_in), OP(bicb_de_ind), OP(bicb_de_de), OP(bicb_de_ded), OP(bicb_de_ix), OP(bicb_de_ixd), + /* 0xc900 */ + OP(bicb_de_rg), OP(bicb_de_rgd), OP(bicb_de_in), OP(bicb_de_ind), OP(bicb_de_de), OP(bicb_de_ded), OP(bicb_de_ix), OP(bicb_de_ixd), + OP(bicb_de_rg), OP(bicb_de_rgd), OP(bicb_de_in), OP(bicb_de_ind), OP(bicb_de_de), OP(bicb_de_ded), OP(bicb_de_ix), OP(bicb_de_ixd), + OP(bicb_de_rg), OP(bicb_de_rgd), OP(bicb_de_in), OP(bicb_de_ind), OP(bicb_de_de), OP(bicb_de_ded), OP(bicb_de_ix), OP(bicb_de_ixd), + OP(bicb_de_rg), OP(bicb_de_rgd), OP(bicb_de_in), OP(bicb_de_ind), OP(bicb_de_de), OP(bicb_de_ded), OP(bicb_de_ix), OP(bicb_de_ixd), + /* 0xca00 */ + OP(bicb_ded_rg), OP(bicb_ded_rgd), OP(bicb_ded_in), OP(bicb_ded_ind), OP(bicb_ded_de), OP(bicb_ded_ded), OP(bicb_ded_ix), OP(bicb_ded_ixd), + OP(bicb_ded_rg), OP(bicb_ded_rgd), OP(bicb_ded_in), OP(bicb_ded_ind), OP(bicb_ded_de), OP(bicb_ded_ded), OP(bicb_ded_ix), OP(bicb_ded_ixd), + OP(bicb_ded_rg), OP(bicb_ded_rgd), OP(bicb_ded_in), OP(bicb_ded_ind), OP(bicb_ded_de), OP(bicb_ded_ded), OP(bicb_ded_ix), OP(bicb_ded_ixd), + OP(bicb_ded_rg), OP(bicb_ded_rgd), OP(bicb_ded_in), OP(bicb_ded_ind), OP(bicb_ded_de), OP(bicb_ded_ded), OP(bicb_ded_ix), OP(bicb_ded_ixd), + /* 0xcb00 */ + OP(bicb_ded_rg), OP(bicb_ded_rgd), OP(bicb_ded_in), OP(bicb_ded_ind), OP(bicb_ded_de), OP(bicb_ded_ded), OP(bicb_ded_ix), OP(bicb_ded_ixd), + OP(bicb_ded_rg), OP(bicb_ded_rgd), OP(bicb_ded_in), OP(bicb_ded_ind), OP(bicb_ded_de), OP(bicb_ded_ded), OP(bicb_ded_ix), OP(bicb_ded_ixd), + OP(bicb_ded_rg), OP(bicb_ded_rgd), OP(bicb_ded_in), OP(bicb_ded_ind), OP(bicb_ded_de), OP(bicb_ded_ded), OP(bicb_ded_ix), OP(bicb_ded_ixd), + OP(bicb_ded_rg), OP(bicb_ded_rgd), OP(bicb_ded_in), OP(bicb_ded_ind), OP(bicb_ded_de), OP(bicb_ded_ded), OP(bicb_ded_ix), OP(bicb_ded_ixd), + /* 0xcc00 */ + OP(bicb_ix_rg), OP(bicb_ix_rgd), OP(bicb_ix_in), OP(bicb_ix_ind), OP(bicb_ix_de), OP(bicb_ix_ded), OP(bicb_ix_ix), OP(bicb_ix_ixd), + OP(bicb_ix_rg), OP(bicb_ix_rgd), OP(bicb_ix_in), OP(bicb_ix_ind), OP(bicb_ix_de), OP(bicb_ix_ded), OP(bicb_ix_ix), OP(bicb_ix_ixd), + OP(bicb_ix_rg), OP(bicb_ix_rgd), OP(bicb_ix_in), OP(bicb_ix_ind), OP(bicb_ix_de), OP(bicb_ix_ded), OP(bicb_ix_ix), OP(bicb_ix_ixd), + OP(bicb_ix_rg), OP(bicb_ix_rgd), OP(bicb_ix_in), OP(bicb_ix_ind), OP(bicb_ix_de), OP(bicb_ix_ded), OP(bicb_ix_ix), OP(bicb_ix_ixd), + /* 0xcd00 */ + OP(bicb_ix_rg), OP(bicb_ix_rgd), OP(bicb_ix_in), OP(bicb_ix_ind), OP(bicb_ix_de), OP(bicb_ix_ded), OP(bicb_ix_ix), OP(bicb_ix_ixd), + OP(bicb_ix_rg), OP(bicb_ix_rgd), OP(bicb_ix_in), OP(bicb_ix_ind), OP(bicb_ix_de), OP(bicb_ix_ded), OP(bicb_ix_ix), OP(bicb_ix_ixd), + OP(bicb_ix_rg), OP(bicb_ix_rgd), OP(bicb_ix_in), OP(bicb_ix_ind), OP(bicb_ix_de), OP(bicb_ix_ded), OP(bicb_ix_ix), OP(bicb_ix_ixd), + OP(bicb_ix_rg), OP(bicb_ix_rgd), OP(bicb_ix_in), OP(bicb_ix_ind), OP(bicb_ix_de), OP(bicb_ix_ded), OP(bicb_ix_ix), OP(bicb_ix_ixd), + /* 0xce00 */ + OP(bicb_ixd_rg), OP(bicb_ixd_rgd), OP(bicb_ixd_in), OP(bicb_ixd_ind), OP(bicb_ixd_de), OP(bicb_ixd_ded), OP(bicb_ixd_ix), OP(bicb_ixd_ixd), + OP(bicb_ixd_rg), OP(bicb_ixd_rgd), OP(bicb_ixd_in), OP(bicb_ixd_ind), OP(bicb_ixd_de), OP(bicb_ixd_ded), OP(bicb_ixd_ix), OP(bicb_ixd_ixd), + OP(bicb_ixd_rg), OP(bicb_ixd_rgd), OP(bicb_ixd_in), OP(bicb_ixd_ind), OP(bicb_ixd_de), OP(bicb_ixd_ded), OP(bicb_ixd_ix), OP(bicb_ixd_ixd), + OP(bicb_ixd_rg), OP(bicb_ixd_rgd), OP(bicb_ixd_in), OP(bicb_ixd_ind), OP(bicb_ixd_de), OP(bicb_ixd_ded), OP(bicb_ixd_ix), OP(bicb_ixd_ixd), + /* 0xcf00 */ + OP(bicb_ixd_rg), OP(bicb_ixd_rgd), OP(bicb_ixd_in), OP(bicb_ixd_ind), OP(bicb_ixd_de), OP(bicb_ixd_ded), OP(bicb_ixd_ix), OP(bicb_ixd_ixd), + OP(bicb_ixd_rg), OP(bicb_ixd_rgd), OP(bicb_ixd_in), OP(bicb_ixd_ind), OP(bicb_ixd_de), OP(bicb_ixd_ded), OP(bicb_ixd_ix), OP(bicb_ixd_ixd), + OP(bicb_ixd_rg), OP(bicb_ixd_rgd), OP(bicb_ixd_in), OP(bicb_ixd_ind), OP(bicb_ixd_de), OP(bicb_ixd_ded), OP(bicb_ixd_ix), OP(bicb_ixd_ixd), + OP(bicb_ixd_rg), OP(bicb_ixd_rgd), OP(bicb_ixd_in), OP(bicb_ixd_ind), OP(bicb_ixd_de), OP(bicb_ixd_ded), OP(bicb_ixd_ix), OP(bicb_ixd_ixd), + + /* 0xd000 */ + OP(bisb_rg_rg), OP(bisb_rg_rgd), OP(bisb_rg_in), OP(bisb_rg_ind), OP(bisb_rg_de), OP(bisb_rg_ded), OP(bisb_rg_ix), OP(bisb_rg_ixd), + OP(bisb_rg_rg), OP(bisb_rg_rgd), OP(bisb_rg_in), OP(bisb_rg_ind), OP(bisb_rg_de), OP(bisb_rg_ded), OP(bisb_rg_ix), OP(bisb_rg_ixd), + OP(bisb_rg_rg), OP(bisb_rg_rgd), OP(bisb_rg_in), OP(bisb_rg_ind), OP(bisb_rg_de), OP(bisb_rg_ded), OP(bisb_rg_ix), OP(bisb_rg_ixd), + OP(bisb_rg_rg), OP(bisb_rg_rgd), OP(bisb_rg_in), OP(bisb_rg_ind), OP(bisb_rg_de), OP(bisb_rg_ded), OP(bisb_rg_ix), OP(bisb_rg_ixd), + /* 0xd100 */ + OP(bisb_rg_rg), OP(bisb_rg_rgd), OP(bisb_rg_in), OP(bisb_rg_ind), OP(bisb_rg_de), OP(bisb_rg_ded), OP(bisb_rg_ix), OP(bisb_rg_ixd), + OP(bisb_rg_rg), OP(bisb_rg_rgd), OP(bisb_rg_in), OP(bisb_rg_ind), OP(bisb_rg_de), OP(bisb_rg_ded), OP(bisb_rg_ix), OP(bisb_rg_ixd), + OP(bisb_rg_rg), OP(bisb_rg_rgd), OP(bisb_rg_in), OP(bisb_rg_ind), OP(bisb_rg_de), OP(bisb_rg_ded), OP(bisb_rg_ix), OP(bisb_rg_ixd), + OP(bisb_rg_rg), OP(bisb_rg_rgd), OP(bisb_rg_in), OP(bisb_rg_ind), OP(bisb_rg_de), OP(bisb_rg_ded), OP(bisb_rg_ix), OP(bisb_rg_ixd), + /* 0xd200 */ + OP(bisb_rgd_rg), OP(bisb_rgd_rgd), OP(bisb_rgd_in), OP(bisb_rgd_ind), OP(bisb_rgd_de), OP(bisb_rgd_ded), OP(bisb_rgd_ix), OP(bisb_rgd_ixd), + OP(bisb_rgd_rg), OP(bisb_rgd_rgd), OP(bisb_rgd_in), OP(bisb_rgd_ind), OP(bisb_rgd_de), OP(bisb_rgd_ded), OP(bisb_rgd_ix), OP(bisb_rgd_ixd), + OP(bisb_rgd_rg), OP(bisb_rgd_rgd), OP(bisb_rgd_in), OP(bisb_rgd_ind), OP(bisb_rgd_de), OP(bisb_rgd_ded), OP(bisb_rgd_ix), OP(bisb_rgd_ixd), + OP(bisb_rgd_rg), OP(bisb_rgd_rgd), OP(bisb_rgd_in), OP(bisb_rgd_ind), OP(bisb_rgd_de), OP(bisb_rgd_ded), OP(bisb_rgd_ix), OP(bisb_rgd_ixd), + /* 0xd300 */ + OP(bisb_rgd_rg), OP(bisb_rgd_rgd), OP(bisb_rgd_in), OP(bisb_rgd_ind), OP(bisb_rgd_de), OP(bisb_rgd_ded), OP(bisb_rgd_ix), OP(bisb_rgd_ixd), + OP(bisb_rgd_rg), OP(bisb_rgd_rgd), OP(bisb_rgd_in), OP(bisb_rgd_ind), OP(bisb_rgd_de), OP(bisb_rgd_ded), OP(bisb_rgd_ix), OP(bisb_rgd_ixd), + OP(bisb_rgd_rg), OP(bisb_rgd_rgd), OP(bisb_rgd_in), OP(bisb_rgd_ind), OP(bisb_rgd_de), OP(bisb_rgd_ded), OP(bisb_rgd_ix), OP(bisb_rgd_ixd), + OP(bisb_rgd_rg), OP(bisb_rgd_rgd), OP(bisb_rgd_in), OP(bisb_rgd_ind), OP(bisb_rgd_de), OP(bisb_rgd_ded), OP(bisb_rgd_ix), OP(bisb_rgd_ixd), + /* 0xd400 */ + OP(bisb_in_rg), OP(bisb_in_rgd), OP(bisb_in_in), OP(bisb_in_ind), OP(bisb_in_de), OP(bisb_in_ded), OP(bisb_in_ix), OP(bisb_in_ixd), + OP(bisb_in_rg), OP(bisb_in_rgd), OP(bisb_in_in), OP(bisb_in_ind), OP(bisb_in_de), OP(bisb_in_ded), OP(bisb_in_ix), OP(bisb_in_ixd), + OP(bisb_in_rg), OP(bisb_in_rgd), OP(bisb_in_in), OP(bisb_in_ind), OP(bisb_in_de), OP(bisb_in_ded), OP(bisb_in_ix), OP(bisb_in_ixd), + OP(bisb_in_rg), OP(bisb_in_rgd), OP(bisb_in_in), OP(bisb_in_ind), OP(bisb_in_de), OP(bisb_in_ded), OP(bisb_in_ix), OP(bisb_in_ixd), + /* 0xd500 */ + OP(bisb_in_rg), OP(bisb_in_rgd), OP(bisb_in_in), OP(bisb_in_ind), OP(bisb_in_de), OP(bisb_in_ded), OP(bisb_in_ix), OP(bisb_in_ixd), + OP(bisb_in_rg), OP(bisb_in_rgd), OP(bisb_in_in), OP(bisb_in_ind), OP(bisb_in_de), OP(bisb_in_ded), OP(bisb_in_ix), OP(bisb_in_ixd), + OP(bisb_in_rg), OP(bisb_in_rgd), OP(bisb_in_in), OP(bisb_in_ind), OP(bisb_in_de), OP(bisb_in_ded), OP(bisb_in_ix), OP(bisb_in_ixd), + OP(bisb_in_rg), OP(bisb_in_rgd), OP(bisb_in_in), OP(bisb_in_ind), OP(bisb_in_de), OP(bisb_in_ded), OP(bisb_in_ix), OP(bisb_in_ixd), + /* 0xd600 */ + OP(bisb_ind_rg), OP(bisb_ind_rgd), OP(bisb_ind_in), OP(bisb_ind_ind), OP(bisb_ind_de), OP(bisb_ind_ded), OP(bisb_ind_ix), OP(bisb_ind_ixd), + OP(bisb_ind_rg), OP(bisb_ind_rgd), OP(bisb_ind_in), OP(bisb_ind_ind), OP(bisb_ind_de), OP(bisb_ind_ded), OP(bisb_ind_ix), OP(bisb_ind_ixd), + OP(bisb_ind_rg), OP(bisb_ind_rgd), OP(bisb_ind_in), OP(bisb_ind_ind), OP(bisb_ind_de), OP(bisb_ind_ded), OP(bisb_ind_ix), OP(bisb_ind_ixd), + OP(bisb_ind_rg), OP(bisb_ind_rgd), OP(bisb_ind_in), OP(bisb_ind_ind), OP(bisb_ind_de), OP(bisb_ind_ded), OP(bisb_ind_ix), OP(bisb_ind_ixd), + /* 0xd700 */ + OP(bisb_ind_rg), OP(bisb_ind_rgd), OP(bisb_ind_in), OP(bisb_ind_ind), OP(bisb_ind_de), OP(bisb_ind_ded), OP(bisb_ind_ix), OP(bisb_ind_ixd), + OP(bisb_ind_rg), OP(bisb_ind_rgd), OP(bisb_ind_in), OP(bisb_ind_ind), OP(bisb_ind_de), OP(bisb_ind_ded), OP(bisb_ind_ix), OP(bisb_ind_ixd), + OP(bisb_ind_rg), OP(bisb_ind_rgd), OP(bisb_ind_in), OP(bisb_ind_ind), OP(bisb_ind_de), OP(bisb_ind_ded), OP(bisb_ind_ix), OP(bisb_ind_ixd), + OP(bisb_ind_rg), OP(bisb_ind_rgd), OP(bisb_ind_in), OP(bisb_ind_ind), OP(bisb_ind_de), OP(bisb_ind_ded), OP(bisb_ind_ix), OP(bisb_ind_ixd), + /* 0xd800 */ + OP(bisb_de_rg), OP(bisb_de_rgd), OP(bisb_de_in), OP(bisb_de_ind), OP(bisb_de_de), OP(bisb_de_ded), OP(bisb_de_ix), OP(bisb_de_ixd), + OP(bisb_de_rg), OP(bisb_de_rgd), OP(bisb_de_in), OP(bisb_de_ind), OP(bisb_de_de), OP(bisb_de_ded), OP(bisb_de_ix), OP(bisb_de_ixd), + OP(bisb_de_rg), OP(bisb_de_rgd), OP(bisb_de_in), OP(bisb_de_ind), OP(bisb_de_de), OP(bisb_de_ded), OP(bisb_de_ix), OP(bisb_de_ixd), + OP(bisb_de_rg), OP(bisb_de_rgd), OP(bisb_de_in), OP(bisb_de_ind), OP(bisb_de_de), OP(bisb_de_ded), OP(bisb_de_ix), OP(bisb_de_ixd), + /* 0xd900 */ + OP(bisb_de_rg), OP(bisb_de_rgd), OP(bisb_de_in), OP(bisb_de_ind), OP(bisb_de_de), OP(bisb_de_ded), OP(bisb_de_ix), OP(bisb_de_ixd), + OP(bisb_de_rg), OP(bisb_de_rgd), OP(bisb_de_in), OP(bisb_de_ind), OP(bisb_de_de), OP(bisb_de_ded), OP(bisb_de_ix), OP(bisb_de_ixd), + OP(bisb_de_rg), OP(bisb_de_rgd), OP(bisb_de_in), OP(bisb_de_ind), OP(bisb_de_de), OP(bisb_de_ded), OP(bisb_de_ix), OP(bisb_de_ixd), + OP(bisb_de_rg), OP(bisb_de_rgd), OP(bisb_de_in), OP(bisb_de_ind), OP(bisb_de_de), OP(bisb_de_ded), OP(bisb_de_ix), OP(bisb_de_ixd), + /* 0xda00 */ + OP(bisb_ded_rg), OP(bisb_ded_rgd), OP(bisb_ded_in), OP(bisb_ded_ind), OP(bisb_ded_de), OP(bisb_ded_ded), OP(bisb_ded_ix), OP(bisb_ded_ixd), + OP(bisb_ded_rg), OP(bisb_ded_rgd), OP(bisb_ded_in), OP(bisb_ded_ind), OP(bisb_ded_de), OP(bisb_ded_ded), OP(bisb_ded_ix), OP(bisb_ded_ixd), + OP(bisb_ded_rg), OP(bisb_ded_rgd), OP(bisb_ded_in), OP(bisb_ded_ind), OP(bisb_ded_de), OP(bisb_ded_ded), OP(bisb_ded_ix), OP(bisb_ded_ixd), + OP(bisb_ded_rg), OP(bisb_ded_rgd), OP(bisb_ded_in), OP(bisb_ded_ind), OP(bisb_ded_de), OP(bisb_ded_ded), OP(bisb_ded_ix), OP(bisb_ded_ixd), + /* 0xdb00 */ + OP(bisb_ded_rg), OP(bisb_ded_rgd), OP(bisb_ded_in), OP(bisb_ded_ind), OP(bisb_ded_de), OP(bisb_ded_ded), OP(bisb_ded_ix), OP(bisb_ded_ixd), + OP(bisb_ded_rg), OP(bisb_ded_rgd), OP(bisb_ded_in), OP(bisb_ded_ind), OP(bisb_ded_de), OP(bisb_ded_ded), OP(bisb_ded_ix), OP(bisb_ded_ixd), + OP(bisb_ded_rg), OP(bisb_ded_rgd), OP(bisb_ded_in), OP(bisb_ded_ind), OP(bisb_ded_de), OP(bisb_ded_ded), OP(bisb_ded_ix), OP(bisb_ded_ixd), + OP(bisb_ded_rg), OP(bisb_ded_rgd), OP(bisb_ded_in), OP(bisb_ded_ind), OP(bisb_ded_de), OP(bisb_ded_ded), OP(bisb_ded_ix), OP(bisb_ded_ixd), + /* 0xdc00 */ + OP(bisb_ix_rg), OP(bisb_ix_rgd), OP(bisb_ix_in), OP(bisb_ix_ind), OP(bisb_ix_de), OP(bisb_ix_ded), OP(bisb_ix_ix), OP(bisb_ix_ixd), + OP(bisb_ix_rg), OP(bisb_ix_rgd), OP(bisb_ix_in), OP(bisb_ix_ind), OP(bisb_ix_de), OP(bisb_ix_ded), OP(bisb_ix_ix), OP(bisb_ix_ixd), + OP(bisb_ix_rg), OP(bisb_ix_rgd), OP(bisb_ix_in), OP(bisb_ix_ind), OP(bisb_ix_de), OP(bisb_ix_ded), OP(bisb_ix_ix), OP(bisb_ix_ixd), + OP(bisb_ix_rg), OP(bisb_ix_rgd), OP(bisb_ix_in), OP(bisb_ix_ind), OP(bisb_ix_de), OP(bisb_ix_ded), OP(bisb_ix_ix), OP(bisb_ix_ixd), + /* 0xdd00 */ + OP(bisb_ix_rg), OP(bisb_ix_rgd), OP(bisb_ix_in), OP(bisb_ix_ind), OP(bisb_ix_de), OP(bisb_ix_ded), OP(bisb_ix_ix), OP(bisb_ix_ixd), + OP(bisb_ix_rg), OP(bisb_ix_rgd), OP(bisb_ix_in), OP(bisb_ix_ind), OP(bisb_ix_de), OP(bisb_ix_ded), OP(bisb_ix_ix), OP(bisb_ix_ixd), + OP(bisb_ix_rg), OP(bisb_ix_rgd), OP(bisb_ix_in), OP(bisb_ix_ind), OP(bisb_ix_de), OP(bisb_ix_ded), OP(bisb_ix_ix), OP(bisb_ix_ixd), + OP(bisb_ix_rg), OP(bisb_ix_rgd), OP(bisb_ix_in), OP(bisb_ix_ind), OP(bisb_ix_de), OP(bisb_ix_ded), OP(bisb_ix_ix), OP(bisb_ix_ixd), + /* 0xde00 */ + OP(bisb_ixd_rg), OP(bisb_ixd_rgd), OP(bisb_ixd_in), OP(bisb_ixd_ind), OP(bisb_ixd_de), OP(bisb_ixd_ded), OP(bisb_ixd_ix), OP(bisb_ixd_ixd), + OP(bisb_ixd_rg), OP(bisb_ixd_rgd), OP(bisb_ixd_in), OP(bisb_ixd_ind), OP(bisb_ixd_de), OP(bisb_ixd_ded), OP(bisb_ixd_ix), OP(bisb_ixd_ixd), + OP(bisb_ixd_rg), OP(bisb_ixd_rgd), OP(bisb_ixd_in), OP(bisb_ixd_ind), OP(bisb_ixd_de), OP(bisb_ixd_ded), OP(bisb_ixd_ix), OP(bisb_ixd_ixd), + OP(bisb_ixd_rg), OP(bisb_ixd_rgd), OP(bisb_ixd_in), OP(bisb_ixd_ind), OP(bisb_ixd_de), OP(bisb_ixd_ded), OP(bisb_ixd_ix), OP(bisb_ixd_ixd), + /* 0xdf00 */ + OP(bisb_ixd_rg), OP(bisb_ixd_rgd), OP(bisb_ixd_in), OP(bisb_ixd_ind), OP(bisb_ixd_de), OP(bisb_ixd_ded), OP(bisb_ixd_ix), OP(bisb_ixd_ixd), + OP(bisb_ixd_rg), OP(bisb_ixd_rgd), OP(bisb_ixd_in), OP(bisb_ixd_ind), OP(bisb_ixd_de), OP(bisb_ixd_ded), OP(bisb_ixd_ix), OP(bisb_ixd_ixd), + OP(bisb_ixd_rg), OP(bisb_ixd_rgd), OP(bisb_ixd_in), OP(bisb_ixd_ind), OP(bisb_ixd_de), OP(bisb_ixd_ded), OP(bisb_ixd_ix), OP(bisb_ixd_ixd), + OP(bisb_ixd_rg), OP(bisb_ixd_rgd), OP(bisb_ixd_in), OP(bisb_ixd_ind), OP(bisb_ixd_de), OP(bisb_ixd_ded), OP(bisb_ixd_ix), OP(bisb_ixd_ixd), + + /* 0xe000 */ + OP(sub_rg_rg), OP(sub_rg_rgd), OP(sub_rg_in), OP(sub_rg_ind), OP(sub_rg_de), OP(sub_rg_ded), OP(sub_rg_ix), OP(sub_rg_ixd), + OP(sub_rg_rg), OP(sub_rg_rgd), OP(sub_rg_in), OP(sub_rg_ind), OP(sub_rg_de), OP(sub_rg_ded), OP(sub_rg_ix), OP(sub_rg_ixd), + OP(sub_rg_rg), OP(sub_rg_rgd), OP(sub_rg_in), OP(sub_rg_ind), OP(sub_rg_de), OP(sub_rg_ded), OP(sub_rg_ix), OP(sub_rg_ixd), + OP(sub_rg_rg), OP(sub_rg_rgd), OP(sub_rg_in), OP(sub_rg_ind), OP(sub_rg_de), OP(sub_rg_ded), OP(sub_rg_ix), OP(sub_rg_ixd), + /* 0xe100 */ + OP(sub_rg_rg), OP(sub_rg_rgd), OP(sub_rg_in), OP(sub_rg_ind), OP(sub_rg_de), OP(sub_rg_ded), OP(sub_rg_ix), OP(sub_rg_ixd), + OP(sub_rg_rg), OP(sub_rg_rgd), OP(sub_rg_in), OP(sub_rg_ind), OP(sub_rg_de), OP(sub_rg_ded), OP(sub_rg_ix), OP(sub_rg_ixd), + OP(sub_rg_rg), OP(sub_rg_rgd), OP(sub_rg_in), OP(sub_rg_ind), OP(sub_rg_de), OP(sub_rg_ded), OP(sub_rg_ix), OP(sub_rg_ixd), + OP(sub_rg_rg), OP(sub_rg_rgd), OP(sub_rg_in), OP(sub_rg_ind), OP(sub_rg_de), OP(sub_rg_ded), OP(sub_rg_ix), OP(sub_rg_ixd), + /* 0xe200 */ + OP(sub_rgd_rg), OP(sub_rgd_rgd), OP(sub_rgd_in), OP(sub_rgd_ind), OP(sub_rgd_de), OP(sub_rgd_ded), OP(sub_rgd_ix), OP(sub_rgd_ixd), + OP(sub_rgd_rg), OP(sub_rgd_rgd), OP(sub_rgd_in), OP(sub_rgd_ind), OP(sub_rgd_de), OP(sub_rgd_ded), OP(sub_rgd_ix), OP(sub_rgd_ixd), + OP(sub_rgd_rg), OP(sub_rgd_rgd), OP(sub_rgd_in), OP(sub_rgd_ind), OP(sub_rgd_de), OP(sub_rgd_ded), OP(sub_rgd_ix), OP(sub_rgd_ixd), + OP(sub_rgd_rg), OP(sub_rgd_rgd), OP(sub_rgd_in), OP(sub_rgd_ind), OP(sub_rgd_de), OP(sub_rgd_ded), OP(sub_rgd_ix), OP(sub_rgd_ixd), + /* 0xe300 */ + OP(sub_rgd_rg), OP(sub_rgd_rgd), OP(sub_rgd_in), OP(sub_rgd_ind), OP(sub_rgd_de), OP(sub_rgd_ded), OP(sub_rgd_ix), OP(sub_rgd_ixd), + OP(sub_rgd_rg), OP(sub_rgd_rgd), OP(sub_rgd_in), OP(sub_rgd_ind), OP(sub_rgd_de), OP(sub_rgd_ded), OP(sub_rgd_ix), OP(sub_rgd_ixd), + OP(sub_rgd_rg), OP(sub_rgd_rgd), OP(sub_rgd_in), OP(sub_rgd_ind), OP(sub_rgd_de), OP(sub_rgd_ded), OP(sub_rgd_ix), OP(sub_rgd_ixd), + OP(sub_rgd_rg), OP(sub_rgd_rgd), OP(sub_rgd_in), OP(sub_rgd_ind), OP(sub_rgd_de), OP(sub_rgd_ded), OP(sub_rgd_ix), OP(sub_rgd_ixd), + /* 0xe400 */ + OP(sub_in_rg), OP(sub_in_rgd), OP(sub_in_in), OP(sub_in_ind), OP(sub_in_de), OP(sub_in_ded), OP(sub_in_ix), OP(sub_in_ixd), + OP(sub_in_rg), OP(sub_in_rgd), OP(sub_in_in), OP(sub_in_ind), OP(sub_in_de), OP(sub_in_ded), OP(sub_in_ix), OP(sub_in_ixd), + OP(sub_in_rg), OP(sub_in_rgd), OP(sub_in_in), OP(sub_in_ind), OP(sub_in_de), OP(sub_in_ded), OP(sub_in_ix), OP(sub_in_ixd), + OP(sub_in_rg), OP(sub_in_rgd), OP(sub_in_in), OP(sub_in_ind), OP(sub_in_de), OP(sub_in_ded), OP(sub_in_ix), OP(sub_in_ixd), + /* 0xe500 */ + OP(sub_in_rg), OP(sub_in_rgd), OP(sub_in_in), OP(sub_in_ind), OP(sub_in_de), OP(sub_in_ded), OP(sub_in_ix), OP(sub_in_ixd), + OP(sub_in_rg), OP(sub_in_rgd), OP(sub_in_in), OP(sub_in_ind), OP(sub_in_de), OP(sub_in_ded), OP(sub_in_ix), OP(sub_in_ixd), + OP(sub_in_rg), OP(sub_in_rgd), OP(sub_in_in), OP(sub_in_ind), OP(sub_in_de), OP(sub_in_ded), OP(sub_in_ix), OP(sub_in_ixd), + OP(sub_in_rg), OP(sub_in_rgd), OP(sub_in_in), OP(sub_in_ind), OP(sub_in_de), OP(sub_in_ded), OP(sub_in_ix), OP(sub_in_ixd), + /* 0xe600 */ + OP(sub_ind_rg), OP(sub_ind_rgd), OP(sub_ind_in), OP(sub_ind_ind), OP(sub_ind_de), OP(sub_ind_ded), OP(sub_ind_ix), OP(sub_ind_ixd), + OP(sub_ind_rg), OP(sub_ind_rgd), OP(sub_ind_in), OP(sub_ind_ind), OP(sub_ind_de), OP(sub_ind_ded), OP(sub_ind_ix), OP(sub_ind_ixd), + OP(sub_ind_rg), OP(sub_ind_rgd), OP(sub_ind_in), OP(sub_ind_ind), OP(sub_ind_de), OP(sub_ind_ded), OP(sub_ind_ix), OP(sub_ind_ixd), + OP(sub_ind_rg), OP(sub_ind_rgd), OP(sub_ind_in), OP(sub_ind_ind), OP(sub_ind_de), OP(sub_ind_ded), OP(sub_ind_ix), OP(sub_ind_ixd), + /* 0xe700 */ + OP(sub_ind_rg), OP(sub_ind_rgd), OP(sub_ind_in), OP(sub_ind_ind), OP(sub_ind_de), OP(sub_ind_ded), OP(sub_ind_ix), OP(sub_ind_ixd), + OP(sub_ind_rg), OP(sub_ind_rgd), OP(sub_ind_in), OP(sub_ind_ind), OP(sub_ind_de), OP(sub_ind_ded), OP(sub_ind_ix), OP(sub_ind_ixd), + OP(sub_ind_rg), OP(sub_ind_rgd), OP(sub_ind_in), OP(sub_ind_ind), OP(sub_ind_de), OP(sub_ind_ded), OP(sub_ind_ix), OP(sub_ind_ixd), + OP(sub_ind_rg), OP(sub_ind_rgd), OP(sub_ind_in), OP(sub_ind_ind), OP(sub_ind_de), OP(sub_ind_ded), OP(sub_ind_ix), OP(sub_ind_ixd), + /* 0xe800 */ + OP(sub_de_rg), OP(sub_de_rgd), OP(sub_de_in), OP(sub_de_ind), OP(sub_de_de), OP(sub_de_ded), OP(sub_de_ix), OP(sub_de_ixd), + OP(sub_de_rg), OP(sub_de_rgd), OP(sub_de_in), OP(sub_de_ind), OP(sub_de_de), OP(sub_de_ded), OP(sub_de_ix), OP(sub_de_ixd), + OP(sub_de_rg), OP(sub_de_rgd), OP(sub_de_in), OP(sub_de_ind), OP(sub_de_de), OP(sub_de_ded), OP(sub_de_ix), OP(sub_de_ixd), + OP(sub_de_rg), OP(sub_de_rgd), OP(sub_de_in), OP(sub_de_ind), OP(sub_de_de), OP(sub_de_ded), OP(sub_de_ix), OP(sub_de_ixd), + /* 0xe900 */ + OP(sub_de_rg), OP(sub_de_rgd), OP(sub_de_in), OP(sub_de_ind), OP(sub_de_de), OP(sub_de_ded), OP(sub_de_ix), OP(sub_de_ixd), + OP(sub_de_rg), OP(sub_de_rgd), OP(sub_de_in), OP(sub_de_ind), OP(sub_de_de), OP(sub_de_ded), OP(sub_de_ix), OP(sub_de_ixd), + OP(sub_de_rg), OP(sub_de_rgd), OP(sub_de_in), OP(sub_de_ind), OP(sub_de_de), OP(sub_de_ded), OP(sub_de_ix), OP(sub_de_ixd), + OP(sub_de_rg), OP(sub_de_rgd), OP(sub_de_in), OP(sub_de_ind), OP(sub_de_de), OP(sub_de_ded), OP(sub_de_ix), OP(sub_de_ixd), + /* 0xea00 */ + OP(sub_ded_rg), OP(sub_ded_rgd), OP(sub_ded_in), OP(sub_ded_ind), OP(sub_ded_de), OP(sub_ded_ded), OP(sub_ded_ix), OP(sub_ded_ixd), + OP(sub_ded_rg), OP(sub_ded_rgd), OP(sub_ded_in), OP(sub_ded_ind), OP(sub_ded_de), OP(sub_ded_ded), OP(sub_ded_ix), OP(sub_ded_ixd), + OP(sub_ded_rg), OP(sub_ded_rgd), OP(sub_ded_in), OP(sub_ded_ind), OP(sub_ded_de), OP(sub_ded_ded), OP(sub_ded_ix), OP(sub_ded_ixd), + OP(sub_ded_rg), OP(sub_ded_rgd), OP(sub_ded_in), OP(sub_ded_ind), OP(sub_ded_de), OP(sub_ded_ded), OP(sub_ded_ix), OP(sub_ded_ixd), + /* 0xeb00 */ + OP(sub_ded_rg), OP(sub_ded_rgd), OP(sub_ded_in), OP(sub_ded_ind), OP(sub_ded_de), OP(sub_ded_ded), OP(sub_ded_ix), OP(sub_ded_ixd), + OP(sub_ded_rg), OP(sub_ded_rgd), OP(sub_ded_in), OP(sub_ded_ind), OP(sub_ded_de), OP(sub_ded_ded), OP(sub_ded_ix), OP(sub_ded_ixd), + OP(sub_ded_rg), OP(sub_ded_rgd), OP(sub_ded_in), OP(sub_ded_ind), OP(sub_ded_de), OP(sub_ded_ded), OP(sub_ded_ix), OP(sub_ded_ixd), + OP(sub_ded_rg), OP(sub_ded_rgd), OP(sub_ded_in), OP(sub_ded_ind), OP(sub_ded_de), OP(sub_ded_ded), OP(sub_ded_ix), OP(sub_ded_ixd), + /* 0xec00 */ + OP(sub_ix_rg), OP(sub_ix_rgd), OP(sub_ix_in), OP(sub_ix_ind), OP(sub_ix_de), OP(sub_ix_ded), OP(sub_ix_ix), OP(sub_ix_ixd), + OP(sub_ix_rg), OP(sub_ix_rgd), OP(sub_ix_in), OP(sub_ix_ind), OP(sub_ix_de), OP(sub_ix_ded), OP(sub_ix_ix), OP(sub_ix_ixd), + OP(sub_ix_rg), OP(sub_ix_rgd), OP(sub_ix_in), OP(sub_ix_ind), OP(sub_ix_de), OP(sub_ix_ded), OP(sub_ix_ix), OP(sub_ix_ixd), + OP(sub_ix_rg), OP(sub_ix_rgd), OP(sub_ix_in), OP(sub_ix_ind), OP(sub_ix_de), OP(sub_ix_ded), OP(sub_ix_ix), OP(sub_ix_ixd), + /* 0xed00 */ + OP(sub_ix_rg), OP(sub_ix_rgd), OP(sub_ix_in), OP(sub_ix_ind), OP(sub_ix_de), OP(sub_ix_ded), OP(sub_ix_ix), OP(sub_ix_ixd), + OP(sub_ix_rg), OP(sub_ix_rgd), OP(sub_ix_in), OP(sub_ix_ind), OP(sub_ix_de), OP(sub_ix_ded), OP(sub_ix_ix), OP(sub_ix_ixd), + OP(sub_ix_rg), OP(sub_ix_rgd), OP(sub_ix_in), OP(sub_ix_ind), OP(sub_ix_de), OP(sub_ix_ded), OP(sub_ix_ix), OP(sub_ix_ixd), + OP(sub_ix_rg), OP(sub_ix_rgd), OP(sub_ix_in), OP(sub_ix_ind), OP(sub_ix_de), OP(sub_ix_ded), OP(sub_ix_ix), OP(sub_ix_ixd), + /* 0xee00 */ + OP(sub_ixd_rg), OP(sub_ixd_rgd), OP(sub_ixd_in), OP(sub_ixd_ind), OP(sub_ixd_de), OP(sub_ixd_ded), OP(sub_ixd_ix), OP(sub_ixd_ixd), + OP(sub_ixd_rg), OP(sub_ixd_rgd), OP(sub_ixd_in), OP(sub_ixd_ind), OP(sub_ixd_de), OP(sub_ixd_ded), OP(sub_ixd_ix), OP(sub_ixd_ixd), + OP(sub_ixd_rg), OP(sub_ixd_rgd), OP(sub_ixd_in), OP(sub_ixd_ind), OP(sub_ixd_de), OP(sub_ixd_ded), OP(sub_ixd_ix), OP(sub_ixd_ixd), + OP(sub_ixd_rg), OP(sub_ixd_rgd), OP(sub_ixd_in), OP(sub_ixd_ind), OP(sub_ixd_de), OP(sub_ixd_ded), OP(sub_ixd_ix), OP(sub_ixd_ixd), + /* 0xef00 */ + OP(sub_ixd_rg), OP(sub_ixd_rgd), OP(sub_ixd_in), OP(sub_ixd_ind), OP(sub_ixd_de), OP(sub_ixd_ded), OP(sub_ixd_ix), OP(sub_ixd_ixd), + OP(sub_ixd_rg), OP(sub_ixd_rgd), OP(sub_ixd_in), OP(sub_ixd_ind), OP(sub_ixd_de), OP(sub_ixd_ded), OP(sub_ixd_ix), OP(sub_ixd_ixd), + OP(sub_ixd_rg), OP(sub_ixd_rgd), OP(sub_ixd_in), OP(sub_ixd_ind), OP(sub_ixd_de), OP(sub_ixd_ded), OP(sub_ixd_ix), OP(sub_ixd_ixd), + OP(sub_ixd_rg), OP(sub_ixd_rgd), OP(sub_ixd_in), OP(sub_ixd_ind), OP(sub_ixd_de), OP(sub_ixd_ded), OP(sub_ixd_ix), OP(sub_ixd_ixd), + + /* 0xf000 */ + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + /* 0xf100 */ + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + /* 0xf200 */ + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + /* 0xf300 */ + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + /* 0xf400 */ + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + /* 0xf500 */ + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + /* 0xf600 */ + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + /* 0xf700 */ + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + /* 0xf800 */ + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + /* 0xf900 */ + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + /* 0xfa00 */ + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + /* 0xfb00 */ + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + /* 0xfc00 */ + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + /* 0xfd00 */ + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + /* 0xfe00 */ + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + /* 0xff00 */ + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), + OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal), OP(illegal) +}; diff --git a/src/devices/cpu/tlcs90/tlcs90.c b/src/devices/cpu/tlcs90/tlcs90.c new file mode 100644 index 00000000000..1e3d5dde80a --- /dev/null +++ b/src/devices/cpu/tlcs90/tlcs90.c @@ -0,0 +1,2786 @@ +// license:BSD-3-Clause +// copyright-holders:Luca Elia +/************************************************************************************************************* + + Toshiba TLCS-90 Series MCU's + + emulation by Luca Elia, based on the Z80 core by Juergen Buchmueller + + ChangeLog: + + 20150517 Fixed TRUN bit masking (timers start/stop handling) [Rainer Keuchel] + +*************************************************************************************************************/ + +#include "emu.h" +#include "debugger.h" +#include "tlcs90.h" + +enum _e_op { UNKNOWN, NOP, EX, EXX, LD, LDW, LDA, LDI, LDIR, LDD, LDDR, CPI, CPIR, CPD, CPDR, PUSH, POP, JP, JR, CALL, CALLR, RET, RETI, HALT, DI, EI, SWI, DAA, CPL, NEG, LDAR, RCF, SCF, CCF, TSET, BIT, SET, RES, INC, DEC, INCX, DECX, INCW, DECW, ADD, ADC, SUB, SBC, AND, XOR, OR, CP, RLC, RRC, RL, RR, SLA, SRA, SLL, SRL, RLD, RRD, DJNZ, MUL, DIV }; +static const char *const op_names[] = { "??", "nop", "ex", "exx", "ld", "ldw", "lda", "ldi", "ldir", "ldd", "lddr", "cpi", "cpir", "cpd", "cpdr", "push", "pop", "jp", "jr", "call", "callr", "ret", "reti", "halt", "di", "ei", "swi", "daa", "cpl", "neg", "ldar", "rcf", "scf", "ccf", "tset", "bit", "set", "res", "inc", "dec", "incx", "decx", "incw", "decw", "add", "adc", "sub", "sbc", "and", "xor", "or", "cp", "rlc", "rrc", "rl", "rr", "sla", "sra", "sll", "srl", "rld", "rrd", "djnz", "mul", "div" }; + +ALLOW_SAVE_TYPE(tlcs90_device::e_mode); // allow save_item on a non-fundamental type + + +const device_type TMP90840 = &device_creator; +const device_type TMP90841 = &device_creator; +const device_type TMP91640 = &device_creator; +const device_type TMP91641 = &device_creator; + + +static ADDRESS_MAP_START(tmp90840_mem, AS_PROGRAM, 8, tlcs90_device) + AM_RANGE( 0x0000, 0x1fff ) AM_ROM // 8KB ROM (internal) + AM_RANGE( 0xfec0, 0xffc0 ) AM_RAM // 256b RAM (internal) + AM_RANGE( T90_IOBASE, T90_IOBASE+47 ) AM_READWRITE( t90_internal_registers_r, t90_internal_registers_w ) +ADDRESS_MAP_END + +static ADDRESS_MAP_START(tmp90841_mem, AS_PROGRAM, 8, tlcs90_device) +// AM_RANGE( 0x0000, 0x1fff ) AM_ROM // rom-less + AM_RANGE( 0xfec0, 0xffc0 ) AM_RAM // 256b RAM (internal) + AM_RANGE( T90_IOBASE, T90_IOBASE+47 ) AM_READWRITE( t90_internal_registers_r, t90_internal_registers_w ) +ADDRESS_MAP_END + +static ADDRESS_MAP_START(tmp91640_mem, AS_PROGRAM, 8, tlcs90_device ) + AM_RANGE( 0x0000, 0x3fff ) AM_ROM // 16KB ROM (internal) + AM_RANGE( 0xfdc0, 0xffc0 ) AM_RAM // 512b RAM (internal) + AM_RANGE( T90_IOBASE, T90_IOBASE+47 ) AM_READWRITE( t90_internal_registers_r, t90_internal_registers_w ) +ADDRESS_MAP_END + +static ADDRESS_MAP_START(tmp91641_mem, AS_PROGRAM, 8, tlcs90_device ) +// AM_RANGE( 0x0000, 0x3fff ) AM_ROM // rom-less + AM_RANGE( 0xfdc0, 0xffc0 ) AM_RAM // 512b RAM (internal) + AM_RANGE( T90_IOBASE, T90_IOBASE+47 ) AM_READWRITE( t90_internal_registers_r, t90_internal_registers_w ) +ADDRESS_MAP_END + + +tlcs90_device::tlcs90_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source, address_map_constructor program_map) + : cpu_device(mconfig, type, name, tag, owner, clock, shortname, source) + , m_program_config("program", ENDIANNESS_LITTLE, 8, 20, 0, program_map) + , m_io_config("io", ENDIANNESS_LITTLE, 8, 16, 0) +{ +} + + +tmp90840_device::tmp90840_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : tlcs90_device(mconfig, TMP90840, "TMP90840", tag, owner, clock, "tmp90840", __FILE__, ADDRESS_MAP_NAME(tmp90840_mem)) +{ +} + +tmp90841_device::tmp90841_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : tlcs90_device(mconfig, TMP90841, "TMP90841", tag, owner, clock, "tmp90841", __FILE__, ADDRESS_MAP_NAME(tmp90841_mem)) +{ +} + + +tmp91640_device::tmp91640_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : tlcs90_device(mconfig, TMP91640, "TMP91640", tag, owner, clock, "tmp91640", __FILE__, ADDRESS_MAP_NAME(tmp91640_mem)) +{ +} + + +tmp91641_device::tmp91641_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : tlcs90_device(mconfig, TMP91641, "TMP91641", tag, owner, clock, "tmp91641", __FILE__, ADDRESS_MAP_NAME(tmp91641_mem)) +{ +} + + +enum { + T90_B, T90_C, T90_D, T90_E, T90_H, T90_L, T90_A, + T90_BC, T90_DE, T90_HL, T90_XX, T90_IX, T90_IY, T90_SP, + T90_AF, T90_PC +}; + +// Regs + +#define B 0 +#define C 1 +#define D 2 +#define E 3 +#define H 4 +#define L 5 +#define A 6 + +#define BC 0 +#define DE 1 +#define HL 2 +// 3 +#define IX 4 +#define IY 5 +#define SP 6 + +#define AF 7 +#define AF2 8 +#define PC 9 + +#define F m_af.b.l + +static const char *const r8_names[] = { "b", "c", "d", "e", "h", "l", "a" }; +static const char *const r16_names[] = { "bc", "de", "hl", "??", "ix", "iy", "sp", "af", "af'", "pc" }; + +// Condition Codes + +#define FLS 0x0 +#define LT 0x1 +#define LE 0x2 +#define ULE 0x3 +#define OV 0x4 +#define PE 0x4 +#define MI 0x5 +#define Z 0x6 +#define EQ 0x6 +#define CR 0x7 +#define ULT 0x7 +#define T 0x8 +#define GE 0x9 +#define GT 0xa +#define UGT 0xb +#define NOV 0xc +#define PO 0xc +#define PL 0xd +#define NZ 0xe +#define NE 0xe +#define NC 0xf +#define UGE 0xf + +#define CF 0x01 +#define NF 0x02 +#define PF 0x04 +#define VF PF +#define XCF 0x08 +#define HF 0x10 +#define IF 0x20 +#define ZF 0x40 +#define SF 0x80 + +static UINT8 SZ[256]; /* zero and sign flags */ +static UINT8 SZ_BIT[256]; /* zero, sign and parity/overflow (=zero) flags for BIT opcode */ +static UINT8 SZP[256]; /* zero, sign and parity flags */ +static UINT8 SZHV_inc[256]; /* zero, sign, half carry and overflow flags INC r8 */ +static UINT8 SZHV_dec[256]; /* zero, sign, half carry and overflow flags DEC r8 */ + +static const char *const cc_names[] = { "f", "lt", "le", "ule", "ov", "mi", "z", "c", "", "ge", "gt", "ugt", "nov", "pl", "nz", "nc" }; + +// Opcodes + +#define OP_16 0x80 + + + + + +#define OP( X,CT ) m_op = X; m_cyc_t = (CT*2); +#define OP16( X,CT ) OP( (X)|OP_16,CT ) + +#define OPCC( X,CF,CT ) OP( X, CT ) m_cyc_f = (CF*2); +#define OPCC16( X,CF,CT ) OPCC( (X)|OP_16,CF,CT ) + +#define BIT8( N,I ) m_mode##N = MODE_BIT8; m_r##N = I; +#define I8( N,I ) m_mode##N = MODE_I8; m_r##N = I; +#define D8( N,I ) m_mode##N = MODE_D8; m_r##N = I; +#define I16( N,I ) m_mode##N = MODE_I16; m_r##N = I; +#define D16( N,I ) m_mode##N = MODE_D16; m_r##N = I; +#define R8( N,R ) m_mode##N = MODE_R8; m_r##N = R; +#define R16( N,R ) m_mode##N = MODE_R16; m_r##N = R; +#define Q16( N,R ) m_mode##N = MODE_R16; m_r##N = R; if (m_r##N == SP) m_r##N = AF; +#define MI16( N,I ) m_mode##N = MODE_MI16; m_r##N = I; +#define MR16( N,R ) m_mode##N = MODE_MR16; m_r##N = R; +#define MR16D8( N,R,I ) m_mode##N = MODE_MR16D8; m_r##N = R; m_r##N##b = I; +#define MR16R8( N,R,g ) m_mode##N = MODE_MR16R8; m_r##N = R; m_r##N##b = g; +#define NONE( N ) m_mode##N = MODE_NONE; +#define CC( N,cc ) m_mode##N = MODE_CC; m_r##N = cc; +#define R16D8( N,R,I ) m_mode##N = MODE_R16D8; m_r##N = R; m_r##N##b = I; +#define R16R8( N,R,g ) m_mode##N = MODE_R16R8; m_r##N = R; m_r##N##b = g; + +UINT8 tlcs90_device::RM8 (UINT32 a) { return m_program->read_byte( a ); } +UINT16 tlcs90_device::RM16(UINT32 a) { return RM8(a) | (RM8( (a+1) & 0xffff ) << 8); } + +void tlcs90_device::WM8 (UINT32 a, UINT8 v) { m_program->write_byte( a, v ); } +void tlcs90_device::WM16(UINT32 a, UINT16 v) { WM8(a,v); WM8( (a+1) & 0xffff, v >> 8); } + +UINT8 tlcs90_device::RX8 (UINT32 a, UINT32 base) { return m_program->read_byte( base | a ); } +UINT16 tlcs90_device::RX16(UINT32 a, UINT32 base) { return RX8(a,base) | (RX8( (a+1) & 0xffff, base ) << 8); } + +void tlcs90_device::WX8 (UINT32 a, UINT8 v, UINT32 base) { m_program->write_byte( base | a, v ); } +void tlcs90_device::WX16(UINT32 a, UINT16 v, UINT32 base) { WX8(a,v,base); WX8( (a+1) & 0xffff, v >> 8, base); } + +UINT8 tlcs90_device::READ8() { UINT8 b0 = RM8( m_addr++ ); m_addr &= 0xffff; return b0; } +UINT16 tlcs90_device::READ16() { UINT8 b0 = READ8(); return b0 | (READ8() << 8); } + +void tlcs90_device::decode() +{ + UINT8 b0, b1, b2, b3; + UINT16 imm16; + + b0 = READ8(); + + switch ( b0 ) + { + case 0x00: + OP( NOP,2 ) NONE( 1 ) NONE( 2 ) return; // NOP + + case 0x01: + OP( HALT,4 ) NONE( 1 ) NONE( 2 ) return; // HALT + case 0x02: + OP( DI,2 ) NONE( 1 ) NONE( 2 ) return; // DI + case 0x03: + OP( EI,2 ) NONE( 1 ) NONE( 2 ) return; // EI + + case 0x07: + OPCC( INCX,6,10 ) MI16( 1, 0xFF00|READ8() ) NONE( 2 ) return; // INCX ($FF00+n) + + case 0x08: + OP( EX,2 ) R16( 1, DE ) R16( 2, HL ) return; // EX DE,HL + case 0x09: + OP( EX,2 ) R16( 1, AF ) R16( 2, AF2 ) return; // EX AF,AF' + case 0x0a: + OP( EXX,2 ) NONE( 1 ) NONE( 2 ) return; // EXX + + case 0x0b: + OP( DAA,4 ) R8( 1, A ) NONE( 2 ) return; // DAA A + + case 0x0c: + OP( RCF,2 ) NONE( 1 ) NONE( 2 ) return; // RCF + case 0x0d: + OP( SCF,2 ) NONE( 1 ) NONE( 2 ) return; // SCF + case 0x0e: + OP( CCF,2 ) NONE( 1 ) NONE( 2 ) return; // CCF + + case 0x0f: + OPCC( DECX,6,10 ) MI16( 1, 0xFF00|READ8() ) NONE( 2 ) return; // DECX ($FF00+n) + + case 0x10: + OP( CPL,2 ) R8( 1, A ) NONE( 2 ) return; // CPL A + case 0x11: + OP( NEG,2 ) R8( 1, A ) NONE( 2 ) return; // NEG A + + case 0x12: // MUL HL,n + case 0x13: // DIV HL,n + OP( MUL+b0-0x12,16) R16( 1, HL ) I8( 2, READ8() ) return; + + case 0x14: case 0x15: case 0x16: + OP16( ADD,6 ) R16( 1, IX+b0-0x14 ) I16( 2, READ16() ) return; // ADD ix,mn + + case 0x17: + OP( LDAR,8 ) R16( 1, HL ) D16( 2, READ16() ) return; // LDAR HL,+cd + + case 0x18: + OP( DJNZ,10 ) D8( 1, READ8() ) NONE( 2 ) return; // DJNZ +d + case 0x19: + OP16( DJNZ,10 ) R16( 1, BC ) D8( 2, READ8() ) return; // DJNZ BC,+d + + case 0x1a: + OPCC( JP,8,8 ) CC( 1, T ) I16( 2, READ16() ) return; // JP T,mn + case 0x1b: + OPCC16( JR,10,10 ) CC( 1, T ) D16( 2, READ16() ) return; // JR T,+cd + + case 0x1c: + OPCC( CALL,14,14 ) CC( 1, T ) I16( 2, READ16() ) return; // CALL T,mn + case 0x1d: + OP( CALLR,16 ) D16( 1, READ16() ) NONE( 2 ) return; // CALLR +cd + + case 0x1e: + OPCC( RET,10,10 ) CC( 1, T ) NONE( 2 ) return; // RET T + case 0x1f: + OP( RETI,14 ) NONE( 1 ) NONE( 2 ) return; // RETI + + case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: + OP( LD,2 ) R8( 1, A ) R8( 2, b0 - 0x20 ) return; // LD A,r + + case 0x27: + OP( LD,8 ) R8( 1, A ) MI16( 2, 0xFF00|READ8() ) return; // LD A,($FF00+n) + + case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: + OP( LD,2 ) R8( 1, b0 - 0x28 ) R8( 2, A ) return; // LD r,A + + case 0x2f: + OP( LD,8 ) MI16( 1, 0xFF00|READ8() ) R8( 2, A ) return; // LD ($FF00+n), A + + case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: + OP( LD,4 ) R8( 1, b0 - 0x30 ) I8( 2, READ8() ) return; // LD r,n + + case 0x37: + OP( LD,10 ) MI16( 1, 0xFF00|READ8() ) I8( 2, READ8() ) return; // LD ($FF00+w),n + + case 0x38: case 0x39: case 0x3a: /*case 0x3b:*/ case 0x3c: case 0x3d: case 0x3e: + OP16( LD,6 ) R16( 1, b0 - 0x38 ) I16( 2, READ16() ) return; // LD rr,nn + + case 0x3f: + OP( LDW,14 ) MI16( 1, 0xFF00|READ8() ) I16( 2, READ16() ) return; // LDW ($FF00+w),mn + + case 0x40: case 0x41: case 0x42: /*case 0x43:*/ case 0x44: case 0x45: case 0x46: + OP16( LD,4 ) R16( 1, HL ) R16( 2, b0 - 0x40 ) return; // LD HL,rr + + case 0x47: + OP16( LD,10 ) R16( 1, HL ) MI16( 2, 0xFF00|READ8() ) return; // LD HL,($FF00+n) + + case 0x48: case 0x49: case 0x4a: /*case 0x4b:*/ case 0x4c: case 0x4d: case 0x4e: + OP16( LD,4 ) R16( 1, b0 - 0x48 ) R16( 2, HL ) return; // LD rr,HL + + case 0x4f: + OP16( LD,10 ) MI16( 1, 0xFF00|READ8() ) R16( 2, HL ) return; // LD ($FF00+n), HL + + case 0x50: case 0x51: case 0x52: /*case 0x53:*/ case 0x54: case 0x55: case 0x56: + OP( PUSH,8 ) Q16( 1, b0 - 0x50 ) NONE( 2 ) return; // PUSH qq + case 0x58: case 0x59: case 0x5a: /*case 0x5b:*/ case 0x5c: case 0x5d: case 0x5e: + OP( POP,10 ) Q16( 1, b0 - 0x58 ) NONE( 2 ) return; // POP qq + + case 0x60: // ADD A,($FF00+n) + case 0x61: // ADC A,($FF00+n) + case 0x62: // SUB A,($FF00+n) + case 0x63: // SBC A,($FF00+n) + case 0x64: // AND A,($FF00+n) + case 0x65: // XOR A,($FF00+n) + case 0x66: // OR A,($FF00+n) + case 0x67: // CP A,($FF00+n) + OP( ADD+b0-0x60,8 ) R8( 1, A ) MI16( 2, 0xFF00|READ8() ) return; + + case 0x68: // ADD A,n + case 0x69: // ADC A,n + case 0x6a: // SUB A,n + case 0x6b: // SBC A,n + case 0x6c: // AND A,n + case 0x6d: // XOR A,n + case 0x6e: // OR A,n + case 0x6f: // CP A,n + OP( ADD+b0-0x68,4 ) R8( 1, A ) I8( 2, READ8() ) return; + + case 0x70: // ADD HL,($FF00+n) + case 0x71: // ADC HL,($FF00+n) + case 0x72: // SUB HL,($FF00+n) + case 0x73: // SBC HL,($FF00+n) + case 0x74: // AND HL,($FF00+n) + case 0x75: // XOR HL,($FF00+n) + case 0x76: // OR HL,($FF00+n) + case 0x77: // CP HL,($FF00+n) + OP16( ADD+b0-0x70,10 ) R16( 1, HL ) MI16( 2, 0xFF00|READ8() ) return; + + case 0x78: // ADD HL,mn + case 0x79: // ADC HL,mn + case 0x7a: // SUB HL,mn + case 0x7b: // SBC HL,mn + case 0x7c: // AND HL,mn + case 0x7d: // XOR HL,mn + case 0x7e: // OR HL,mn + case 0x7f: // CP HL,mn + OP16( ADD+b0-0x78,6 ) R16( 1, HL ) I16( 2, READ16() ) return; + + case 0x80: case 0x81: case 0x82: case 0x83: case 0x84: case 0x85: case 0x86: + OP( INC,2 ) R8( 1, b0 - 0x80 ) NONE( 2 ) return; // INC r + case 0x87: + OP( INC,10 ) MI16( 1, 0xFF00|READ8() ) NONE( 2 ) return; // INC ($FF00+n) + + case 0x88: case 0x89: case 0x8a: case 0x8b: case 0x8c: case 0x8d: case 0x8e: + OP( DEC,2 ) R8( 1, b0 - 0x88 ) NONE( 2 ) return; // DEC r + case 0x8f: + OP( DEC,10 ) MI16( 1, 0xFF00|READ8() ) NONE( 2 ) return; // DEC ($FF00+n) + + case 0x90: case 0x91: case 0x92: /*case 0x93:*/ case 0x94: case 0x95: case 0x96: + OP16( INC,4 ) R16( 1, b0 - 0x90 ) NONE( 2 ) return; // INC rr + case 0x97: + OP( INCW,14 ) MI16( 1, 0xFF00|READ8() ) NONE( 2 ) return; // INCW ($FF00+n) + case 0x98: case 0x99: case 0x9a: /*case 0x9b:*/ case 0x9c: case 0x9d: case 0x9e: + OP16( DEC,4 ) R16( 1, b0 - 0x98 ) NONE( 2 ) return; // DEC rr + case 0x9f: + OP( DECW,14 ) MI16( 1, 0xFF00|READ8() ) NONE( 2 ) return; // DECW ($FF00+n) + + case 0xa0: // RLC A + case 0xa1: // RRC A + case 0xa2: // RL A + case 0xa3: // RR A + case 0xa4: // SLA A + case 0xa5: // SRA A + case 0xa6: // SLL A + case 0xa7: // SRL A + OP( RLC+b0-0xa0,2 ) R8( 1, A ) NONE( 2 ) return; + + case 0xa8: case 0xa9: case 0xaa: case 0xab: case 0xac: case 0xad: case 0xae: case 0xaf: + OP( BIT,8 ) BIT8( 1, b0 - 0xa8 ) MI16( 2, 0xFF00|READ8() ) return; // BIT b,($FF00+n) + case 0xb0: case 0xb1: case 0xb2: case 0xb3: case 0xb4: case 0xb5: case 0xb6: case 0xb7: + OP( RES,12 ) BIT8( 1, b0 - 0xb0 ) MI16( 2, 0xFF00|READ8() ) return; // RES b,($FF00+n) + case 0xb8: case 0xb9: case 0xba: case 0xbb: case 0xbc: case 0xbd: case 0xbe: case 0xbf: + OP( SET,12 ) BIT8( 1, b0 - 0xb8 ) MI16( 2, 0xFF00|READ8() ) return; // SET b,($FF00+n) + + case 0xc0: case 0xc1: case 0xc2: case 0xc3: case 0xc4: case 0xc5: case 0xc6: case 0xc7: + case 0xc8: case 0xc9: case 0xca: case 0xcb: case 0xcc: case 0xcd: case 0xce: case 0xcf: + OPCC( JR,4,8 ) CC( 1, b0 - 0xc0 ) D8( 2, READ8() ) return; // JR cc,+d + + case 0xe0: case 0xe1: case 0xe2: /*case 0xe3:*/ case 0xe4: case 0xe5: case 0xe6: + b1 = READ8(); + switch ( b1 ) { + case 0x10: // RLD (gg) + case 0x11: // RRD (gg) + OP( RLD+b1-0x10,12 ) MR16( 1, b0 - 0xe0 ) NONE( 2 ) return; + + case 0x12: // MUL HL,(gg) + case 0x13: // DIV HL,(gg) + OP( MUL+b1-0x12,18 ) R16( 1, HL ) MR16( 2, b0 - 0xe0 ) return; + + case 0x14: case 0x15: case 0x16: + OP16( ADD,8 ) R16( 1, IX+b1-0x14 ) MR16( 2, b0 - 0xe0 ) return; // ADD ix,(gg) + + case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: + OP( LD,6 ) R8( 1, b1 - 0x28 ) MR16( 2, b0 - 0xe0 ) return; // LD r,(gg) + case 0x48: case 0x49: case 0x4a: /*case 0x4b:*/ case 0x4c: case 0x4d: case 0x4e: + OP16( LD,8 ) R16( 1, b1 - 0x48 ) MR16( 2, b0 - 0xe0 ) return; // LD rr,(gg) + + case 0x50: case 0x51: case 0x52: /*case 0x53:*/ case 0x54: case 0x55: case 0x56: + OP( EX,14 ) MR16( 1, b0 - 0xe0 ) R16( 2, b1 - 0x50 ) return; // EX (gg),rr + + case 0x60: // ADD A,(gg) + case 0x61: // ADC A,(gg) + case 0x62: // SUB A,(gg) + case 0x63: // SBC A,(gg) + case 0x64: // AND A,(gg) + case 0x65: // XOR A,(gg) + case 0x66: // OR A,(gg) + case 0x67: // CP A,(gg) + OP( ADD+b1-0x60,6 ) R8( 1, A ) MR16( 2, b0 - 0xe0 ) return; + + case 0x70: // ADD HL,(gg) + case 0x71: // ADC HL,(gg) + case 0x72: // SUB HL,(gg) + case 0x73: // SBC HL,(gg) + case 0x74: // AND HL,(gg) + case 0x75: // XOR HL,(gg) + case 0x76: // OR HL,(gg) + case 0x77: // CP HL,(gg) + OP16( ADD+b1-0x70,8 ) R16( 1, HL ) MR16( 2, b0 - 0xe0 ) return; + + case 0x87: + OP( INC,8 ) MR16( 1, b0 - 0xe0 ) NONE( 2 ) return; // INC (gg) + case 0x8f: + OP( DEC,8 ) MR16( 1, b0 - 0xe0 ) NONE( 2 ) return; // DEC (gg) + + case 0x97: + OP( INCW,12 ) MR16( 1, b0 - 0xe0 ) NONE( 2 ) return; // INCW (gg) + case 0x9f: + OP( DECW,12 ) MR16( 1, b0 - 0xe0 ) NONE( 2 ) return; // DECW (gg) + + case 0xa0: // RLC (gg) + case 0xa1: // RRC (gg) + case 0xa2: // RL (gg) + case 0xa3: // RR (gg) + case 0xa4: // SLA (gg) + case 0xa5: // SRA (gg) + case 0xa6: // SLL (gg) + case 0xa7: // SRL (gg) + OP( RLC+b1-0xa0,8 ) MR16( 1, b0 - 0xe0 ) NONE( 2 ) return; + + case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f: + OP( TSET,12 ) BIT8( 1, b1 - 0x18 ) MR16( 2, b0 - 0xe0 ) return; // TSET b,(gg) + case 0xa8: case 0xa9: case 0xaa: case 0xab: case 0xac: case 0xad: case 0xae: case 0xaf: + OP( BIT,6 ) BIT8( 1, b1 - 0xa8 ) MR16( 2, b0 - 0xe0 ) return; // BIT b,(gg) + case 0xb0: case 0xb1: case 0xb2: case 0xb3: case 0xb4: case 0xb5: case 0xb6: case 0xb7: + OP( RES,10 ) BIT8( 1, b1 - 0xb0 ) MR16( 2, b0 - 0xe0 ) return; // RES b,(gg) + case 0xb8: case 0xb9: case 0xba: case 0xbb: case 0xbc: case 0xbd: case 0xbe: case 0xbf: + OP( SET,10 ) BIT8( 1, b1 - 0xb8 ) MR16( 2, b0 - 0xe0 ) return; // SET b,(gg) + } break; + case 0xe3: + imm16 = READ16(); + b3 = READ8(); + switch ( b3 ) { + case 0x10: // RLD (mn) + case 0x11: // RRD (mn) + OP( RLD+b3-0x10,16 ) MI16( 1, imm16 ) NONE( 2 ) return; + + case 0x12: // MUL HL,(mn) + case 0x13: // DIV HL,(mn) + OP( MUL+b3-0x12,22 ) R16( 1, HL ) MI16( 2, imm16 ) return; + + case 0x14: case 0x15: case 0x16: + OP16( ADD,12 ) R16( 1, IX+b3-0x14 ) MI16( 2, imm16 ) return; // ADD ix,(mn) + + case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: + OP( LD,10 ) R8( 1, b3 - 0x28 ) MI16( 2, imm16 ) return; // LD r,(mn) + case 0x48: case 0x49: case 0x4a: /*case 0x4b:*/ case 0x4c: case 0x4d: case 0x4e: + OP16( LD,12 ) R16( 1, b3 - 0x48 ) MI16( 2, imm16 ) return; // LD rr,(mn) + + case 0x50: case 0x51: case 0x52: /*case 0x53:*/ case 0x54: case 0x55: case 0x56: + OP( EX,18 ) MI16( 1, imm16 ) R16( 2, b3 - 0x50 ) return; // EX (mn),rr + + case 0x60: // ADD A,(mn) + case 0x61: // ADC A,(mn) + case 0x62: // SUB A,(mn) + case 0x63: // SBC A,(mn) + case 0x64: // AND A,(mn) + case 0x65: // XOR A,(mn) + case 0x66: // OR A,(mn) + case 0x67: // CP A,(mn) + OP( ADD+b3-0x60,10 ) R8( 1, A ) MI16( 2, imm16 ) return; + + case 0x70: // ADD HL,(mn) + case 0x71: // ADC HL,(mn) + case 0x72: // SUB HL,(mn) + case 0x73: // SBC HL,(mn) + case 0x74: // AND HL,(mn) + case 0x75: // XOR HL,(mn) + case 0x76: // OR HL,(mn) + case 0x77: // CP HL,(mn) + OP16( ADD+b3-0x70,12 ) R16( 1, HL ) MI16( 2, imm16 ) return; + + case 0x87: + OP( INC,12 ) MI16( 1, imm16 ) NONE( 2 ) return; // INC (mn) + case 0x8f: + OP( DEC,12 ) MI16( 1, imm16 ) NONE( 2 ) return; // DEC (mn) + + case 0x97: + OP( INCW,16 ) MI16( 1, imm16 ) NONE( 2 ) return; // INCW (mn) + case 0x9f: + OP( DECW,16 ) MI16( 1, imm16 ) NONE( 2 ) return; // DECW (mn) + + case 0xa0: // RLC (mn) + case 0xa1: // RRC (mn) + case 0xa2: // RL (mn) + case 0xa3: // RR (mn) + case 0xa4: // SLA (mn) + case 0xa5: // SRA (mn) + case 0xa6: // SLL (mn) + case 0xa7: // SRL (mn) + OP( RLC+b3-0xa0,12 ) MI16( 1, imm16 ) NONE( 2 ) return; + + case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f: + OP( TSET,16 ) BIT8( 1, b3 - 0x18 ) MI16( 2, imm16 ) return; // TSET b,(mn) + case 0xa8: case 0xa9: case 0xaa: case 0xab: case 0xac: case 0xad: case 0xae: case 0xaf: + OP( BIT,10 ) BIT8( 1, b3 - 0xa8 ) MI16( 2, imm16 ) return; // BIT b,(mn) + case 0xb0: case 0xb1: case 0xb2: case 0xb3: case 0xb4: case 0xb5: case 0xb6: case 0xb7: + OP( RES,14 ) BIT8( 1, b3 - 0xb0 ) MI16( 2, imm16 ) return; // RES b,(mn) + case 0xb8: case 0xb9: case 0xba: case 0xbb: case 0xbc: case 0xbd: case 0xbe: case 0xbf: + OP( SET,14 ) BIT8( 1, b3 - 0xb8 ) MI16( 2, imm16 ) return; // SET b,(mn) + } break; + + case 0xe7: + b1 = READ8(); + b2 = READ8(); + switch ( b2 ) { + case 0x10: // RLD ($FF00+n) + case 0x11: // RRD ($FF00+n) + OP( RLD+b2-0x10,14 ) MI16( 1, 0xFF00|b1 ) NONE( 2 ) return; + + case 0x12: // MUL HL,($FF00+n) + case 0x13: // DIV HL,($FF00+n) + OP( MUL+b2-0x12,20 ) R16( 1, HL ) MI16( 2, 0xFF00|b1 ) return; + + case 0x14: case 0x15: case 0x16: + OP16( ADD,10 ) R16( 1, IX+b2-0x14 ) MI16( 2, 0xFF00|b1 ) return; // ADD ix,($FF00+n) + + case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f: + OP( TSET,14 ) BIT8( 1, b2 - 0x18 ) MI16( 2, 0xFF00|b1 ) return; // TSET b,($FF00+n) + case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: + OP( LD,8 ) R8( 1, b2 - 0x28 ) MI16( 2, 0xFF00|b1 ) return; // LD r,($FF00+n) + case 0x48: case 0x49: case 0x4a: /*case 0x4b:*/ case 0x4c: case 0x4d: case 0x4e: + OP16( LD,10 ) R16( 1, b2 - 0x48 ) MI16( 2, 0xFF00|b1 ) return; // LD rr,($FF00+n) + + case 0x50: case 0x51: case 0x52: /*case 0x53:*/ case 0x54: case 0x55: case 0x56: + OP( EX,16 ) MI16( 1, 0xFF00|b1 ) R16( 2, b2 - 0x50 ) return; // EX ($FF00+n),rr + + case 0xa0: // RLC ($FF00+n) + case 0xa1: // RRC ($FF00+n) + case 0xa2: // RL ($FF00+n) + case 0xa3: // RR ($FF00+n) + case 0xa4: // SLA ($FF00+n) + case 0xa5: // SRA ($FF00+n) + case 0xa6: // SLL ($FF00+n) + case 0xa7: // SRL ($FF00+n) + OP( RLC+b2-0xa0,10 ) MI16( 1, 0xFF00|b1 ) NONE( 2 ) return; + } break; + + case 0xe8: case 0xe9: case 0xea: /*case 0xeb:*/ case 0xec: case 0xed: case 0xee: + b1 = READ8(); + switch ( b1 ) { + case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: + OP( LD,6 ) MR16( 1, b0 - 0xe8 ) R8( 2, b1 - 0x20 ) return; // LD (gg),r + case 0x37: + OP( LD,8 ) MR16( 1, b0 - 0xe8 ) I8( 2, READ8() ) return; // LD (gg),n + case 0x3f: + OP( LDW,12 ) MR16( 1, b0 - 0xe8 ) I16( 2, READ16() ) return; // LDW (gg),mn + case 0x40: case 0x41: case 0x42: /*case 0x43:*/ case 0x44: case 0x45: case 0x46: + OP16( LD,8 ) MR16( 1, b0 - 0xe8 ) R16( 2, b1 - 0x40 ) return; // LD (gg),rr + + case 0x68: // ADD (gg),n + case 0x69: // ADC (gg),n + case 0x6a: // SUB (gg),n + case 0x6b: // SBC (gg),n + case 0x6c: // AND (gg),n + case 0x6d: // XOR (gg),n + case 0x6e: // OR (gg),n + OP( ADD+b1-0x68,10 ) MR16( 1, b0 - 0xe8 ) I8( 2, READ8() ) return; + case 0x6f: // CP (gg),n + OP( CP,8 ) MR16( 1, b0 - 0xe8 ) I8( 2, READ8() ) return; + + case 0xc0: case 0xc1: case 0xc2: case 0xc3: case 0xc4: case 0xc5: case 0xc6: case 0xc7: + case 0xc8: case 0xc9: case 0xca: case 0xcb: case 0xcc: case 0xcd: case 0xce: case 0xcf: + OPCC( JP,6,8 ) CC( 1, b1 - 0xc0 ) R16( 2, b0 - 0xe8 ) return; // JP [cc,]gg + case 0xd0: case 0xd1: case 0xd2: case 0xd3: case 0xd4: case 0xd5: case 0xd6: case 0xd7: + case 0xd8: case 0xd9: case 0xda: case 0xdb: case 0xdc: case 0xdd: case 0xde: case 0xdf: + OPCC( CALL,6,14 ) CC( 1, b1 - 0xd0 ) R16( 2, b0 - 0xe8 ) return; // CALL [cc,]gg + } break; + case 0xeb: + imm16 = READ16(); + b3 = READ8(); + switch ( b3 ) { + case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: + OP( LD,10 ) MI16( 1, imm16 ) R8( 2, b3 - 0x20 ) return; // LD (mn),r + case 0x37: + OP( LD,12 ) MI16( 1, imm16 ) I8( 2, READ8() ) return; // LD (vw),n + case 0x3f: + OP( LDW,16 ) MI16( 1, imm16 ) I16( 2, READ16() ) return; // LDW (vw),mn + case 0x40: case 0x41: case 0x42: /*case 0x43:*/ case 0x44: case 0x45: case 0x46: + OP16( LD,12 ) MI16( 1, imm16 ) R16( 2, b3 - 0x40 ) return; // LD (mn),rr + + case 0x68: // ADD (vw),n + case 0x69: // ADC (vw),n + case 0x6a: // SUB (vw),n + case 0x6b: // SBC (vw),n + case 0x6c: // AND (vw),n + case 0x6d: // XOR (vw),n + case 0x6e: // OR (vw),n + OP( ADD+b3-0x68,14 ) MI16( 1, imm16 ) I8( 2, READ8() ) return; + case 0x6f: // CP (vw),n + OP( ADD+b3-0x68,12 ) MI16( 1, imm16 ) I8( 2, READ8() ) return; + + case 0xc0: case 0xc1: case 0xc2: case 0xc3: case 0xc4: case 0xc5: case 0xc6: case 0xc7: + case 0xc8: case 0xc9: case 0xca: case 0xcb: case 0xcc: case 0xcd: case 0xce: case 0xcf: + OPCC( JP,10,12 ) CC( 1, b3 - 0xc0 ) I16( 2, imm16 ) return; // JP cc,mn + case 0xd0: case 0xd1: case 0xd2: case 0xd3: case 0xd4: case 0xd5: case 0xd6: case 0xd7: + case 0xd8: case 0xd9: case 0xda: case 0xdb: case 0xdc: case 0xdd: case 0xde: case 0xdf: + OPCC( CALL,10,18 ) CC( 1, b3 - 0xd0 ) I16( 2, imm16 ) return; // CALL cc,mn + } break; + + case 0xef: + b1 = READ8(); + b2 = READ8(); + switch ( b2 ) { + case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: + OP( LD,8 ) MI16( 1, 0xFF00|b1 ) R8( 2, b2 - 0x20 ) return; // LD ($FF00+n),r + case 0x40: case 0x41: case 0x42: /*case 0x43:*/ case 0x44: case 0x45: case 0x46: + OP16( LD,10 ) MI16( 1, 0xFF00|b1 ) R16( 2, b2 - 0x40 ) return; // LD ($FF00+n),rr + + case 0x68: // ADD ($FF00+w),n + case 0x69: // ADC ($FF00+w),n + case 0x6a: // SUB ($FF00+w),n + case 0x6b: // SBC ($FF00+w),n + case 0x6c: // AND ($FF00+w),n + case 0x6d: // XOR ($FF00+w),n + case 0x6e: // OR ($FF00+w),n + OP( ADD+b2-0x68,12 ) MI16( 1, 0xFF00|b1 ) I8( 2, READ8() ) return; + case 0x6f: // CP ($FF00+w),n + OP( ADD+b2-0x68,10 ) MI16( 1, 0xFF00|b1 ) I8( 2, READ8() ) return; + } break; + + case 0xf0: case 0xf1: case 0xf2: + b1 = READ8(); + b2 = READ8(); + switch ( b2 ) { + case 0x10: // RLD (ix+d) + case 0x11: // RRD (ix+d) + OP( RLD+b2-0x10,16 ) MR16D8( 1, IX + b0 - 0xf0, b1 ) NONE( 2 ) return; + + case 0x12: // MUL HL,(ix+d) + case 0x13: // DIV HL,(ix+d) + OP( MUL+b2-0x12,22 ) R16( 1, HL ) MR16D8( 2, IX + b0 - 0xf0, b1 ) return; + + case 0x14: case 0x15: case 0x16: + OP16( ADD,12 ) R16( 1, IX+b2-0x14 ) MR16D8( 2, IX + b0 - 0xf0, b1 ) return; // ADD ix,(jx+d) + + case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: + OP( LD,10 ) R8( 1, b2 - 0x28 ) MR16D8( 2, IX + b0 - 0xf0, b1 ) return; // LD r,(ix+d) + case 0x48: case 0x49: case 0x4a: /*case 0x4b:*/ case 0x4c: case 0x4d: case 0x4e: + OP16( LD,12 ) R16( 1, b2 - 0x48 ) MR16D8( 2, IX + b0 - 0xf0, b1 ) return; // LD rr,(ix+d) + + case 0x50: case 0x51: case 0x52: /*case 0x53:*/ case 0x54: case 0x55: case 0x56: + OP( EX,18 ) MR16D8( 1, IX + b0 - 0xf0, b1 ) R16( 2, b2 - 0x50 ) return; // EX (ix+d),rr + + case 0x60: // ADD A,(ix+d) + case 0x61: // ADC A,(ix+d) + case 0x62: // SUB A,(ix+d) + case 0x63: // SBC A,(ix+d) + case 0x64: // AND A,(ix+d) + case 0x65: // XOR A,(ix+d) + case 0x66: // OR A,(ix+d) + case 0x67: // CP A,(ix+d) + OP( ADD+b2-0x60,10 ) R8( 1, A ) MR16D8( 2, IX + b0 - 0xf0, b1 ) return; + + case 0x70: // ADD HL,(ix+d) + case 0x71: // ADC HL,(ix+d) + case 0x72: // SUB HL,(ix+d) + case 0x73: // SBC HL,(ix+d) + case 0x74: // AND HL,(ix+d) + case 0x75: // XOR HL,(ix+d) + case 0x76: // OR HL,(ix+d) + case 0x77: // CP HL,(ix+d) + OP16( ADD+b2-0x70,12 ) R16( 1, HL ) MR16D8( 2, IX + b0 - 0xf0, b1 ) return; + + case 0x87: + OP( INC,12 ) MR16D8( 1, IX + b0 - 0xf0, b1 ) NONE( 2 ) return; // INC (ix+d) + case 0x8f: + OP( DEC,12 ) MR16D8( 1, IX + b0 - 0xf0, b1 ) NONE( 2 ) return; // DEC (ix+d) + + case 0x97: + OP( INCW,16 ) MR16D8( 1, IX + b0 - 0xf0, b1 ) NONE( 2 ) return; // INCW (ix+d) + case 0x9f: + OP( DECW,16 ) MR16D8( 1, IX + b0 - 0xf0, b1 ) NONE( 2 ) return; // DECW (ix+d) + + case 0xa0: // RLC (ix+d) + case 0xa1: // RRC (ix+d) + case 0xa2: // RL (ix+d) + case 0xa3: // RR (ix+d) + case 0xa4: // SLA (ix+d) + case 0xa5: // SRA (ix+d) + case 0xa6: // SLL (ix+d) + case 0xa7: // SRL (ix+d) + OP( RLC+b2-0xa0,12 ) MR16D8( 1, IX + b0 - 0xf0, b1 ) NONE( 2 ) return; + + case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f: + OP( TSET,16 ) BIT8( 1, b2 - 0x18 ) MR16D8( 2, IX + b0 - 0xf0, b1 ) return; // TSET b,(ix+d) + case 0xa8: case 0xa9: case 0xaa: case 0xab: case 0xac: case 0xad: case 0xae: case 0xaf: + OP( BIT,10 ) BIT8( 1, b2 - 0xa8 ) MR16D8( 2, IX + b0 - 0xf0, b1 ) return; // BIT b,(ix+d) + case 0xb0: case 0xb1: case 0xb2: case 0xb3: case 0xb4: case 0xb5: case 0xb6: case 0xb7: + OP( RES,14 ) BIT8( 1, b2 - 0xb0 ) MR16D8( 2, IX + b0 - 0xf0, b1 ) return; // RES b,(ix+d) + case 0xb8: case 0xb9: case 0xba: case 0xbb: case 0xbc: case 0xbd: case 0xbe: case 0xbf: + OP( SET,14 ) BIT8( 1, b2 - 0xb8 ) MR16D8( 2, IX + b0 - 0xf0, b1 ) return; // SET b,(ix+d) + } break; + + case 0xf3: + b1 = READ8(); + switch ( b1 ) { + case 0x10: // RLD (HL+A) + case 0x11: // RRD (HL+A) + OP( RLD+b1-0x10,20 ) MR16R8( 1, HL, A ) NONE( 2 ) return; + + case 0x12: // MUL HL,(HL+A) + case 0x13: // DIV HL,(HL+A) + OP( MUL+b1-0x12,26 ) R16( 1, HL ) MR16R8( 2, HL, A ) return; + + case 0x14: case 0x15: case 0x16: + OP16( ADD,16 ) R16( 1, IX+b1-0x14 ) MR16R8( 2, HL, A ) return; // ADD ix,(HL+A) + + case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: + OP( LD,14 ) R8( 1, b1 - 0x28 ) MR16R8( 2, HL, A ) return; // LD r,(HL+A) + case 0x48: case 0x49: case 0x4a: /*case 0x4b:*/ case 0x4c: case 0x4d: case 0x4e: + OP16( LD,16 ) R16( 1, b1 - 0x48 ) MR16R8( 2, HL, A ) return; // LD rr,(HL+A) + + case 0x50: case 0x51: case 0x52: /*case 0x53:*/ case 0x54: case 0x55: case 0x56: + OP( EX,22 ) MR16R8( 1, HL, A ) R16( 2, b1 - 0x50 ) return; // EX (HL+A),rr + + case 0x60: // ADD A,(HL+A) + case 0x61: // ADC A,(HL+A) + case 0x62: // SUB A,(HL+A) + case 0x63: // SBC A,(HL+A) + case 0x64: // AND A,(HL+A) + case 0x65: // XOR A,(HL+A) + case 0x66: // OR A,(HL+A) + case 0x67: // CP A,(HL+A) + OP( ADD+b1-0x60,14 ) R8( 1, A ) MR16R8( 2, HL, A ) return; + + case 0x70: // ADD HL,(HL+A) + case 0x71: // ADC HL,(HL+A) + case 0x72: // SUB HL,(HL+A) + case 0x73: // SBC HL,(HL+A) + case 0x74: // AND HL,(HL+A) + case 0x75: // XOR HL,(HL+A) + case 0x76: // OR HL,(HL+A) + case 0x77: // CP HL,(HL+A) + OP16( ADD+b1-0x70,16 ) R16( 1, HL ) MR16R8( 2, HL, A ) return; + + case 0x87: + OP( INC,16 ) MR16R8( 1, HL, A ) NONE( 2 ) return; // INC (HL+A) + case 0x8f: + OP( DEC,16 ) MR16R8( 1, HL, A ) NONE( 2 ) return; // DEC (HL+A) + + case 0x97: + OP( INCW,20 ) MR16R8( 1, HL, A ) NONE( 2 ) return; // INCW (HL+A) + case 0x9f: + OP( DECW,20 ) MR16R8( 1, HL, A ) NONE( 2 ) return; // DECW (HL+A) + + case 0xa0: // RLC (HL+A) + case 0xa1: // RRC (HL+A) + case 0xa2: // RL (HL+A) + case 0xa3: // RR (HL+A) + case 0xa4: // SLA (HL+A) + case 0xa5: // SRA (HL+A) + case 0xa6: // SLL (HL+A) + case 0xa7: // SRL (HL+A) + OP( RLC+b1-0xa0,16 ) MR16R8( 1, HL, A ) NONE( 2 ) return; + + case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f: + OP( TSET,20 ) BIT8( 1, b1 - 0x18 ) MR16R8( 2, HL, A ) return; // TSET b,(HL+A) + case 0xa8: case 0xa9: case 0xaa: case 0xab: case 0xac: case 0xad: case 0xae: case 0xaf: + OP( BIT,14 ) BIT8( 1, b1 - 0xa8 ) MR16R8( 2, HL, A ) return; // BIT b,(HL+A) + case 0xb0: case 0xb1: case 0xb2: case 0xb3: case 0xb4: case 0xb5: case 0xb6: case 0xb7: + OP( RES,18 ) BIT8( 1, b1 - 0xb0 ) MR16R8( 2, HL, A ) return; // RES b,(HL+A) + case 0xb8: case 0xb9: case 0xba: case 0xbb: case 0xbc: case 0xbd: case 0xbe: case 0xbf: + OP( SET,18 ) BIT8( 1, b1 - 0xb8 ) MR16R8( 2, HL, A ) return; // SET b,(HL+A) + } break; + + case 0xf4: case 0xf5: case 0xf6: + b1 = READ8(); + b2 = READ8(); + switch ( b2 ) { + case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: + OP( LD,10 ) MR16D8( 1, IX + b0 - 0xf4, b1 ) R8( 2, b2 - 0x20 ) return; // LD (ix+d),r + case 0x37: + OP( LD,12 ) MR16D8( 1, IX + b0 - 0xf4, b1 ) I8( 2, READ8() ) return; // LD (ix+d),n + case 0x38: case 0x39: case 0x3a: /*case 0x3b:*/ case 0x3c: case 0x3d: case 0x3e: + OP( LDA,10 ) R16( 1, b2 - 0x38 ) R16D8( 2, IX + b0 - 0xf4, b1 ) return; // LDA rr,ix+d + case 0x3f: + OP( LDW,16 ) MR16D8( 1, IX + b0 - 0xf4, b1 ) I16( 2, READ16() ) return; // LDW (ix+d),mn + case 0x40: case 0x41: case 0x42: /*case 0x43:*/ case 0x44: case 0x45: case 0x46: + OP16( LD,12 ) MR16D8( 1, IX + b0 - 0xf4, b1 ) R16( 2, b2 - 0x40 ) return; // LD (ix+d),rr + + case 0x68: // ADD (ix+d),n + case 0x69: // ADC (ix+d),n + case 0x6a: // SUB (ix+d),n + case 0x6b: // SBC (ix+d),n + case 0x6c: // AND (ix+d),n + case 0x6d: // XOR (ix+d),n + case 0x6e: // OR (ix+d),n + OP( ADD+b2-0x68,14) MR16D8( 1, IX + b0 - 0xf4, b1 ) I8( 2, READ8() ) return; + case 0x6f: // CP (ix+d),n + OP( ADD+b2-0x68,12) MR16D8( 1, IX + b0 - 0xf4, b1 ) I8( 2, READ8() ) return; + + case 0xc0: case 0xc1: case 0xc2: case 0xc3: case 0xc4: case 0xc5: case 0xc6: case 0xc7: + case 0xc8: case 0xc9: case 0xca: case 0xcb: case 0xcc: case 0xcd: case 0xce: case 0xcf: + OPCC( JP,10,12 ) CC( 1, b2 - 0xc0 ) R16D8( 2, IX + b0 - 0xf4, b1 ) return; // JP [cc,]ix+d + case 0xd0: case 0xd1: case 0xd2: case 0xd3: case 0xd4: case 0xd5: case 0xd6: case 0xd7: + case 0xd8: case 0xd9: case 0xda: case 0xdb: case 0xdc: case 0xdd: case 0xde: case 0xdf: + OPCC( CALL,10,18 ) CC( 1, b2 - 0xd0 ) R16D8( 2, IX + b0 - 0xf4, b1 ) return; // CALL [cc,]ix+d + } break; + + case 0xf7: + b1 = READ8(); + switch ( b1 ) { + case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: + OP( LD,14 ) MR16R8( 1, HL, A ) R8( 2, b1 - 0x20 ) return; // LD (HL+A),r + case 0x37: + OP( LD,16 ) MR16R8( 1, HL, A ) I8( 2, READ8() ) return; // LD (HL+A),n + case 0x38: case 0x39: case 0x3a: /*case 0x3b:*/ case 0x3c: case 0x3d: case 0x3e: + OP( LDA,14 ) R16( 1, b1 - 0x38 ) R16R8( 2, HL, A ) return; // LDA rr,HL+A + case 0x3f: + OP( LDW,20 ) MR16R8( 1, HL, A ) I16( 2, READ16() ) return; // LDW (HL+A),mn + case 0x40: case 0x41: case 0x42: /*case 0x43:*/ case 0x44: case 0x45: case 0x46: + OP16( LD,16 ) MR16R8( 1, HL, A ) R16( 2, b1 - 0x40 ) return; // LD (HL+A),rr + + case 0x68: // ADD (HL+A),n + case 0x69: // ADC (HL+A),n + case 0x6a: // SUB (HL+A),n + case 0x6b: // SBC (HL+A),n + case 0x6c: // AND (HL+A),n + case 0x6d: // XOR (HL+A),n + case 0x6e: // OR (HL+A),n + OP( ADD+b1-0x68,18) MR16R8( 1, HL, A ) I8( 2, READ8() ) return; + case 0x6f: // CP (HL+A),n + OP( ADD+b1-0x68,16) MR16R8( 1, HL, A ) I8( 2, READ8() ) return; + + case 0xc0: case 0xc1: case 0xc2: case 0xc3: case 0xc4: case 0xc5: case 0xc6: case 0xc7: + case 0xc8: case 0xc9: case 0xca: case 0xcb: case 0xcc: case 0xcd: case 0xce: case 0xcf: + OPCC( JP,14,16 ) CC( 1, b1 - 0xc0 ) R16R8( 2, HL, A ) return; // JP [cc,]HL+A + case 0xd0: case 0xd1: case 0xd2: case 0xd3: case 0xd4: case 0xd5: case 0xd6: case 0xd7: + case 0xd8: case 0xd9: case 0xda: case 0xdb: case 0xdc: case 0xdd: case 0xde: case 0xdf: + OPCC( CALL,14,22 ) CC( 1, b1 - 0xd0 ) R16R8( 2, HL, A ) return; // CALL [cc,]HL+A + } break; + + case 0xf8: case 0xf9: case 0xfa: case 0xfb: case 0xfc: case 0xfd: case 0xfe: + b1 = READ8(); + switch ( b1 ) { + case 0x12: // MUL HL,g + case 0x13: // DIV HL,g + OP( MUL+b1-0x12,18) R16( 1, HL ) R8( 2, b0 - 0xf8 ) return; + + case 0x14: case 0x15: case 0x16: + OP16( ADD,8 ) R16( 1, IX+b1-0x14 ) R16( 2, b0 - 0xf8 ) return; // ADD ix,gg + + case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: + OP( LD,4 ) R8( 1, b1 - 0x30 ) R8( 2, b0 - 0xf8 ) return; // LD r,g + case 0x38: case 0x39: case 0x3a: /*case 0x3b:*/ case 0x3c: case 0x3d: case 0x3e: + OP16( LD,6 ) R16( 1, b1 - 0x38 ) R16( 2, b0 - 0xf8 ) return; // LD rr,gg + + case 0x58: // LDI + case 0x59: // LDIR + case 0x5a: // LDD + case 0x5b: // LDDR + case 0x5c: // CPI + case 0x5d: // CPIR + case 0x5e: // CPD + case 0x5f: // CPDR + if (b0 == 0xfe) { + OPCC( LDI+b1-0x58,14,18 ) NONE( 1 ) NONE( 2 ) return; + } + + case 0x60: // ADD A,g + case 0x61: // ADC A,g + case 0x62: // SUB A,g + case 0x63: // SBC A,g + case 0x64: // AND A,g + case 0x65: // XOR A,g + case 0x66: // OR A,g + case 0x67: // CP A,g + OP( ADD+b1-0x60,4 ) R8( 1, A ) R8( 2, b0 - 0xf8 ) return; + + case 0x68: // ADD g,n + case 0x69: // ADC g,n + case 0x6a: // SUB g,n + case 0x6b: // SBC g,n + case 0x6c: // AND g,n + case 0x6d: // XOR g,n + case 0x6e: // OR g,n + case 0x6f: // CP g,n + OP( ADD+b1-0x68,6 ) R8( 1, b0 - 0xf8 ) I8( 2, READ8() ) return; + + case 0x70: // ADD HL,gg + case 0x71: // ADC HL,gg + case 0x72: // SUB HL,gg + case 0x73: // SBC HL,gg + case 0x74: // AND HL,gg + case 0x75: // XOR HL,gg + case 0x76: // OR HL,gg + case 0x77: // CP HL,gg + OP16( ADD+b1-0x70,8 ) R16( 1, HL ) R16( 2, b0 - 0xf8 ) return; + + case 0xa0: // RLC g + case 0xa1: // RRC g + case 0xa2: // RL g + case 0xa3: // RR g + case 0xa4: // SLA g + case 0xa5: // SRA g + case 0xa6: // SLL g + case 0xa7: // SRL g + OP( RLC+b1-0xa0,4 ) R8( 1, b0 - 0xf8 ) NONE( 2 ) return; + + case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f: + OP( TSET,8 ) BIT8( 1, b1 - 0x18 ) R8( 2, b0 - 0xf8 ) return; // TSET b,g + case 0xa8: case 0xa9: case 0xaa: case 0xab: case 0xac: case 0xad: case 0xae: case 0xaf: + OP( BIT,4 ) BIT8( 1, b1 - 0xa8 ) R8( 2, b0 - 0xf8 ) return; // BIT b,g + case 0xb0: case 0xb1: case 0xb2: case 0xb3: case 0xb4: case 0xb5: case 0xb6: case 0xb7: + OP( RES,4 ) BIT8( 1, b1 - 0xb0 ) R8( 2, b0 - 0xf8 ) return; // RES b,g + case 0xb8: case 0xb9: case 0xba: case 0xbb: case 0xbc: case 0xbd: case 0xbe: case 0xbf: + OP( SET,4 ) BIT8( 1, b1 - 0xb8 ) R8( 2, b0 - 0xf8 ) return; // SET b,g + + case 0xd0: case 0xd1: case 0xd2: case 0xd3: case 0xd4: case 0xd5: case 0xd6: case 0xd7: + case 0xd8: case 0xd9: case 0xda: case 0xdb: case 0xdc: case 0xdd: case 0xde: case 0xdf: + if (b0 == 0xfe) { + OPCC( RET,6,14 ) CC( 1, b1 - 0xd0 ) NONE( 2 ) return; // RET cc + } + } break; + + case 0xff: + OP( SWI,20 ) NONE( 1 ) NONE( 2 ) return; // SWI + } + + OP( UNKNOWN,2 ) NONE( 1 ) NONE( 2 ) +} + +static const char *const ir_names[] = { + "P0", "P1", "P01CR/IRFL", "IRFH", "P2", "P2CR", "P3", "P3CR", + "P4", "P4CR", "P5", "SMMOD", "P6", "P7", "P67CR", "SMCR", + "P8", "P8CR", "WDMOD", "WDCR", "TREG0", "TREG1", "TREG2", "TREG3", + "TCLK", "TFFCR", "TMOD", "TRUN", "CAP1L", "CAP1H", "CAP2L", "CAL2H", + "TREG4L", "TREG4H", "TREG5L", "TREG5H", "T4MOD", "T4FFCR", "INTEL", "INTEH", + "DMAEH", "SCMOD", "SCCR", "SCBUF", "BX", "BY", "ADREG", "ADMOD" +}; + +const char *tlcs90_device::internal_registers_names(UINT16 x) +{ + int ir = x - T90_IOBASE; + if ( ir >= 0 && ir < ARRAY_LENGTH(ir_names) ) + return ir_names[ir]; + return NULL; +} +int tlcs90_device::sprint_arg(char *buffer, UINT32 pc, const char *pre, const e_mode mode, const UINT16 r, const UINT16 rb) +{ + const char *reg_name; + switch ( mode ) + { + case MODE_NONE: return 0; + + case MODE_BIT8: return sprintf( buffer, "%s%d", pre, r ); + case MODE_I8: return sprintf( buffer, "%s$%02X", pre, r ); + case MODE_D8: return sprintf( buffer, "%s$%04X", pre, (pc+2+(r&0x7f)-(r&0x80))&0xffff ); + case MODE_I16: return sprintf( buffer, "%s$%04X", pre, r ); + case MODE_D16: return sprintf( buffer, "%s$%04X", pre, (pc+2+(r&0x7fff)-(r&0x8000))&0xffff ); + case MODE_MI16: + reg_name = internal_registers_names(r); + return (reg_name) ? sprintf( buffer, "%s(%s)", pre, reg_name ): + sprintf( buffer, "%s($%04X)", pre, r ); + case MODE_R8: return sprintf( buffer, "%s%s", pre, r8_names[r] ); + case MODE_R16: return sprintf( buffer, "%s%s", pre, r16_names[r] ); + case MODE_MR16: return sprintf( buffer, "%s(%s)", pre, r16_names[r] ); + + case MODE_MR16R8: return sprintf( buffer, "%s(%s+%s)", pre, r16_names[r], r8_names[rb] ); + case MODE_MR16D8: return sprintf( buffer, "%s(%s%c$%02X)", pre, r16_names[r], (rb&0x80)?'-':'+', (rb&0x80)?((rb^0xff)+1):rb ); + + case MODE_CC: return sprintf( buffer, "%s%s", pre, cc_names[r] ); + + case MODE_R16R8: return sprintf( buffer, "%s%s+%s", pre, r16_names[r], r8_names[rb] ); + case MODE_R16D8: return sprintf( buffer, "%s%s%c$%02X", pre, r16_names[r], (rb&0x80)?'-':'+', (rb&0x80)?((rb^0xff)+1):rb ); + + default: + fatalerror("%04x: unimplemented addr mode = %d\n",pc,mode); + } + + // never executed + //return 0; +} + +offs_t tlcs90_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + int len; + + m_addr = pc; + + decode(); + m_op &= ~OP_16; + + buffer += sprintf ( buffer, "%-5s", op_names[ m_op ] ); // strlen("callr") == 5 + len = sprint_arg ( buffer, pc, " ", m_mode1, m_r1, m_r1b ); + buffer += len; + buffer += sprint_arg ( buffer, pc, (len>1)?",":"", m_mode2, m_r2, m_r2b ); + + return (m_addr - pc) | DASMFLAG_SUPPORTED; +} + + +UINT16 tlcs90_device::r8( const UINT16 r ) +{ + switch( r ) + { + case A: return m_af.b.h; + case B: return m_bc.b.h; + case C: return m_bc.b.l; + case D: return m_de.b.h; + case E: return m_de.b.l; + case H: return m_hl.b.h; + case L: return m_hl.b.l; + + default: + fatalerror("%04x: unimplemented r8 register index = %d\n",m_pc.w.l,r); + } +} + +void tlcs90_device::w8( const UINT16 r, UINT16 value ) +{ + switch( r ) + { + case A: m_af.b.h = value; return; + case B: m_bc.b.h = value; return; + case C: m_bc.b.l = value; return; + case D: m_de.b.h = value; return; + case E: m_de.b.l = value; return; + case H: m_hl.b.h = value; return; + case L: m_hl.b.l = value; return; + + default: + fatalerror("%04x: unimplemented w8 register index = %d\n",m_pc.w.l,r); + } +} + +UINT16 tlcs90_device::r16( const UINT16 r ) +{ + switch( r ) + { + case BC: return m_bc.w.l; + case DE: return m_de.w.l; + case HL: return m_hl.w.l; + case IX: return m_ix.w.l; + case IY: return m_iy.w.l; + case SP: return m_sp.w.l; + case AF: return m_af.w.l; +// case AF2: return m_af2.w.l; +// one interrupt flip-flop? Needed by e.g. mjifb + case AF2: return (m_af2.w.l & (~IF)) | (m_af.w.l & IF); + case PC: return m_pc.w.l; + + default: + fatalerror("%04x: unimplemented r16 register index = %d\n",m_pc.w.l,r); + } +} + +void tlcs90_device::w16( const UINT16 r, UINT16 value ) +{ + switch( r ) + { + case BC: m_bc.w.l = value; return; + case DE: m_de.w.l = value; return; + case HL: m_hl.w.l = value; return; + case IX: m_ix.w.l = value; return; + case IY: m_iy.w.l = value; return; + case SP: m_sp.w.l = value; return; + case AF: m_af.w.l = value; return; + case AF2: m_af2.w.l = value; return; + case PC: m_pc.d = value; return; + + default: + fatalerror("%04x: unimplemented w16 register index = %d\n",m_pc.w.l,r); + } +} + + +#define READ_FN( N ) \ +UINT8 tlcs90_device::Read##N##_8() { \ + switch ( m_mode##N ) { \ + case MODE_CC: \ + case MODE_BIT8: \ + case MODE_I8: return (UINT8)m_r##N; \ + case MODE_D8: return (UINT8)m_r##N; \ + case MODE_R8: return (UINT8)r8(m_r##N); \ + case MODE_MI16: return RM8(m_r##N); \ + case MODE_MR16R8: return RM8((UINT16)(r16(m_r##N) + (INT8)r8(m_r##N##b))); \ + case MODE_MR16: \ + switch( m_r##N ) { \ + case IX: return RX8(m_ix.w.l,m_ixbase); \ + case IY: return RX8(m_iy.w.l,m_iybase); \ + } \ + return RM8(r16(m_r##N)); \ + case MODE_MR16D8: \ + switch( m_r##N ) { \ + case IX: return RX8((UINT16)(m_ix.w.l + (INT8)m_r##N##b),m_ixbase); \ + case IY: return RX8((UINT16)(m_iy.w.l + (INT8)m_r##N##b),m_iybase); \ + } \ + return RM8((UINT16)(r16(m_r##N) + (INT8)m_r##N##b)); \ + default: \ + fatalerror("%04x: unimplemented Read%d_8 mode = %d\n",m_pc.w.l,N,m_mode##N); \ + } \ + return 0; \ +} \ +UINT16 tlcs90_device::Read##N##_16() { \ + switch ( m_mode##N ) { \ + case MODE_I16: return m_r##N; \ + case MODE_D16: return m_r##N - 1; \ + case MODE_R16: return r16(m_r##N); \ + case MODE_R16D8: return r16(m_r##N) + (INT8)m_r##N##b; \ + case MODE_R16R8: return r16(m_r##N) + (INT8)r8(m_r##N##b); \ + case MODE_MI16: return RM16(m_r##N); \ + case MODE_MR16R8: return RM16((UINT16)(r16(m_r##N) + (INT8)r8(m_r##N##b))); \ + case MODE_MR16: \ + switch( m_r##N ) { \ + case IX: return RX16(m_ix.w.l,m_ixbase); \ + case IY: return RX16(m_iy.w.l,m_iybase); \ + } \ + return RM16(r16(m_r##N)); \ + case MODE_MR16D8: \ + switch( m_r##N ) { \ + case IX: return RX16((UINT16)(m_ix.w.l + (INT8)m_r##N##b),m_ixbase); \ + case IY: return RX16((UINT16)(m_iy.w.l + (INT8)m_r##N##b),m_iybase); \ + } \ + return RM16((UINT16)(r16(m_r##N) + (INT8)m_r##N##b)); \ + default: \ + fatalerror("%04x: unimplemented Read%d_16 modes = %d\n",m_pc.w.l,N,m_mode##N); \ + } \ + return 0; \ +} + + + +#define WRITE_FN( N ) \ +void tlcs90_device::Write##N##_8( UINT8 value ) { \ + switch ( m_mode##N ) { \ + case MODE_R8: w8(m_r##N,value); return; \ + case MODE_MI16: WM8(m_r##N, value); return; \ + case MODE_MR16R8: WM8((UINT16)(r16(m_r##N) + (INT8)r8(m_r##N##b)), value); return; \ + case MODE_MR16: \ + switch( m_r##N ) { \ + case IX: WX8(m_ix.w.l,value,m_ixbase); return; \ + case IY: WX8(m_iy.w.l,value,m_iybase); return; \ + } \ + WM8(r16(m_r##N), value); return; \ + case MODE_MR16D8: \ + switch( m_r##N ) { \ + case IX: WX8((UINT16)(m_ix.w.l + (INT8)m_r##N##b),value,m_ixbase); return; \ + case IY: WX8((UINT16)(m_iy.w.l + (INT8)m_r##N##b),value,m_iybase); return; \ + } \ + WM8((UINT16)(r16(m_r##N) + (INT8)m_r##N##b), value); return; \ + default: \ + fatalerror("%04x: unimplemented Write%d_8 mode = %d\n",m_pc.w.l,N,m_mode##N); \ + } \ +} \ +void tlcs90_device::Write##N##_16( UINT16 value ) \ +{ \ + switch ( m_mode##N ) { \ + case MODE_R16: w16(m_r##N,value); return; \ + case MODE_MI16: WM16(m_r##N, value); return; \ + case MODE_MR16R8: WM16((UINT16)(r16(m_r##N) + (INT8)r8(m_r##N##b)), value); return; \ + case MODE_MR16: \ + switch( m_r##N ) { \ + case IX: WX16(m_ix.w.l,value,m_ixbase); return; \ + case IY: WX16(m_iy.w.l,value,m_iybase); return; \ + } \ + WM16(r16(m_r##N), value); return; \ + case MODE_MR16D8: \ + switch( m_r##N ) { \ + case IX: WX16((UINT16)(m_ix.w.l + (INT8)m_r##N##b),value,m_ixbase); return; \ + case IY: WX16((UINT16)(m_iy.w.l + (INT8)m_r##N##b),value,m_iybase); return; \ + } \ + WM16((UINT16)(r16(m_r##N) + (INT8)m_r##N##b), value); return; \ + default: \ + fatalerror("%04x: unimplemented Write%d_16 mode = %d\n",m_pc.w.l,N,m_mode##N); \ + } \ +} + +READ_FN(1) +READ_FN(2) +WRITE_FN(1) +WRITE_FN(2) + +int tlcs90_device::Test( UINT8 cond ) +{ + int s,v; + switch ( cond ) + { + case FLS: return 0; + case LT: s = F & SF; v = F & VF; return (s && !v) || (!s && v); + case LE: s = F & SF; v = F & VF; return (F & ZF) || (s && !v) || (!s && v); + case ULE: return (F & CF) || (F & ZF); + case OV: return F & VF; + case MI: return F & SF; + case Z: return F & ZF; + case CR: return F & CF; + case T: return 1; + case GE: s = F & SF; v = F & VF; return (s && v) || (!s && !v); + case GT: s = F & SF; v = F & VF; return !((F & ZF) || (s && !v) || (!s && v)); + case UGT: return !(F & CF) && !(F & ZF); + case NOV: return !(F & VF); + case PL: return !(F & SF); + case NZ: return !(F & ZF); + case NC: return !(F & CF); + default: + fatalerror("%04x: unimplemented condition = %d\n",m_pc.w.l,cond); + } + + // never executed + //return 0; +} + +void tlcs90_device::Push( UINT16 rr ) +{ + m_sp.w.l -= 2; + WM16( m_sp.w.l, r16(rr) ); +} +void tlcs90_device::Pop( UINT16 rr ) +{ + w16( rr, RM16( m_sp.w.l ) ); + m_sp.w.l += 2; +} + +/************************************************************************************************************* + +Interrupts + +---------------------------------------------------------------------------------------------------------------- +Priority Type Interrupt Source Vector/8 Vector Address uDMA Address +---------------------------------------------------------------------------------------------------------------- +1 Non Maskable SWI - 10 0010 - +2 "" NMI - 18 0018 - +3 "" INTWD Watch Dog - 20 0020 - +4 Maskable INT0 External 0 05 28 0028 FF28 +5 "" INTT0 Timer 0 06 30 0030 FF30 +6 "" INTT1 Timer 1 07 38 0038 FF38 +7 "" INTAD A/D 08 40 0040 FF48 +"" "" INTT2 Timer 2 "" "" "" "" +8 "" INTT3 Timer 3 09 48 0048 FF48 +9 "" INTT4 Timer 4 0A 50 0050 FF50 +10 "" INT1 External 1 0B 58 0058 FF58 +11 "" INTT5 Timer 5 0C 60 0060 FF60 +12 "" INT2 External 2 0D 68 0068 FF68 +13 "" INTRX End Serial Receive 0E 70 0070 FF70 +14 "" INTTX End Serial Transmit 0F 78 0078 FF78 + +---------------------------------------------------------------------------------------------------------------- +Interrupt Terminal Mode How To Set +---------------------------------------------------------------------------------------------------------------- +NMI - Falling Edge - +INT0 P80 Level P8CR = 0 + Rising Edge P8CR = 1 +INT1 P81 Rising Edge T4MOD = 0,0 or 0,1 or 1,1 + Falling Edge T4MOD = 1,0 +INT2 P82 Rising Edge - + +*************************************************************************************************************/ + +void tlcs90_device::leave_halt() +{ + if( m_halt ) + { + m_halt = 0; + m_pc.w.l++; + } +} + +void tlcs90_device::take_interrupt(tlcs90_e_irq irq) +{ + m_irq_state &= ~(1 << irq); + + leave_halt(); + + Push( PC ); + Push( AF ); + + F &= ~IF; + + m_pc.w.l = 0x10 + irq * 8; + + m_extra_cycles += 20*2; +} + +void tlcs90_device::check_interrupts() +{ + tlcs90_e_irq irq; + int mask; + + if (!(F & IF)) + return; + + for (irq = INTSWI; irq < INTMAX; irq++) + { + mask = (1 << irq); + if(irq >= INT0) mask &= m_irq_mask; + if ( m_irq_state & mask ) + { + take_interrupt( irq ); + return; + } + } +} + +void tlcs90_device::execute_set_input(int inputnum, int state) +{ + switch(inputnum) { + case INPUT_LINE_NMI: + set_irq_line(INTNMI, state); + break; + case INPUT_LINE_IRQ0: + set_irq_line(INT0, state); + break; + case INPUT_LINE_IRQ1: + set_irq_line(INT1, state); + break; + case INPUT_LINE_IRQ2: + set_irq_line(INT2, state); + break; + } +} + +void tlcs90_device::set_irq_line(int irq, int state) +{ + if ( ((m_irq_state >> irq)&1) == state ) return; + + if (state) + { + m_irq_state |= 1 << irq; + check_interrupts(); + } + else + { + m_irq_state &= ~(1 << irq); + } +} + +void tlcs90_device::Cyc() { m_icount -= m_cyc_t; } +void tlcs90_device::Cyc_f() { m_icount -= m_cyc_f; } + +void tlcs90_device::execute_run() +{ + UINT8 a8,b8; + UINT16 a16,b16; + unsigned a32; + PAIR tmp; + + m_icount -= m_extra_cycles; + m_extra_cycles = 0; + + do + { + m_prvpc.d = m_pc.d; + debugger_instruction_hook(this, m_pc.d); + + check_interrupts(); + + m_addr = m_pc.d; + decode(); + m_pc.d = m_addr; + + switch ( m_op ) + { + case NOP: + Cyc(); + break; + + case EX: + a16 = Read1_16(); + Write1_16( Read2_16() ); + Write2_16( a16 ); + Cyc(); + break; + case EXX: + tmp = m_bc; m_bc = m_bc2; m_bc2 = tmp; + tmp = m_de; m_de = m_de2; m_de2 = tmp; + tmp = m_hl; m_hl = m_hl2; m_hl2 = tmp; + Cyc(); + break; + + case LD: + Write1_8( Read2_8() ); + Cyc(); + break; + case LDW: + case LD | OP_16: + Write1_16( Read2_16() ); + Cyc(); + break; + +// case LDA: +// Cyc(); +// break; + + case LDI: +#define _LDI \ + WM8( m_de.w.l, RM8(m_hl.w.l) ); \ + m_de.w.l++; \ + m_hl.w.l++; \ + m_bc.w.l--; \ + F &= SF | ZF | IF | XCF | CF; \ + if ( m_bc.w.l ) F |= VF; + + _LDI + Cyc(); + break; + case LDIR: + _LDI + if ( m_bc.w.l ) + { + m_pc.w.l -= 2; + Cyc(); + } + else Cyc_f(); + break; + + case LDD: +#define _LDD \ + WM8( m_de.w.l, RM8(m_hl.w.l) ); \ + m_de.w.l--; \ + m_hl.w.l--; \ + m_bc.w.l--; \ + F &= SF | ZF | IF | XCF | CF; \ + if ( m_bc.w.l ) F |= VF; + + _LDD + Cyc(); + break; + case LDDR: + _LDD + if ( m_bc.w.l ) + { + m_pc.w.l -= 2; + Cyc(); + } + else Cyc_f(); + break; + + +// case CPD: +// Cyc(); +// break; +// case CPDR: +// Cyc(); +// break; + case CPI: + a8 = RM8(m_hl.w.l); + b8 = m_af.b.h - a8; + m_hl.w.l++; + m_bc.w.l--; + F = (F & (IF | CF)) | SZ[b8] | ((m_af.b.h^a8^b8)&HF) | NF; + if ( m_bc.w.l ) F |= VF; + Cyc(); + break; + case CPIR: + a8 = RM8(m_hl.w.l); + b8 = m_af.b.h - a8; + m_hl.w.l++; + m_bc.w.l--; + F = (F & (IF | CF)) | SZ[b8] | ((m_af.b.h^a8^b8)&HF) | NF; + if ( m_bc.w.l ) + { + F |= VF; + m_pc.w.l -= 2; + Cyc(); + } + else Cyc_f(); + break; + + case PUSH: + Push( m_r1 ); + Cyc(); + break; + case POP: + Pop( m_r1 ); + Cyc(); + break; + + case JP: + if ( Test( Read1_8() ) ) + { + m_pc.w.l = Read2_16(); + Cyc(); + } + else Cyc_f(); + break; + case JR: + if ( Test( Read1_8() ) ) + { + m_pc.w.l += /*2 +*/ (INT8)Read2_8(); + Cyc(); + } + else Cyc_f(); + break; + case JR | OP_16: + if ( Test( Read1_8() ) ) + { + m_pc.w.l += /*2 +*/ Read2_16(); + Cyc(); + } + else Cyc_f(); + break; + + + case CALL: + if ( Test( Read1_8() ) ) + { + Push( PC ); + m_pc.w.l = Read2_16(); + Cyc(); + } + else Cyc_f(); + break; + case CALLR: + Push( PC ); + m_pc.w.l += /*2 +*/ Read1_16(); + Cyc(); + break; + + case RET: + if ( Test( Read1_8() ) ) + { + Pop( PC ); + Cyc(); + } + else Cyc_f(); + break; + case RETI: + Pop( AF ); + Pop( PC ); + Cyc(); + break; + +// case HALT: +// Cyc(); +// break; + case DI: + m_after_EI = 0; + F &= ~IF; + Cyc(); + break; + case EI: + m_after_EI = !(F & IF); + Cyc(); + break; + + case SWI: + Cyc(); + take_interrupt( INTSWI ); + break; + + case DAA: + { + UINT8 cf, nf, hf, lo, hi, diff; + cf = F & CF; + nf = F & NF; + hf = F & HF; + lo = m_af.b.h & 15; + hi = m_af.b.h / 16; + + if (cf) + { + diff = (lo <= 9 && !hf) ? 0x60 : 0x66; + } + else + { + if (lo >= 10) + { + diff = hi <= 8 ? 0x06 : 0x66; + } + else + { + if (hi >= 10) + { + diff = hf ? 0x66 : 0x60; + } + else + { + diff = hf ? 0x06 : 0x00; + } + } + } + if (nf) m_af.b.h -= diff; + else m_af.b.h += diff; + + F = SZP[A] | (F & (IF | NF)); + if (cf || (lo <= 9 ? hi >= 10 : hi >= 9)) F |= XCF | CF; + if (nf ? hf && lo <= 5 : lo >= 10) F |= HF; + } + Cyc(); + break; + + + case CPL: + m_af.b.h ^= 0xff; + F |= HF | NF; + Cyc(); + break; + case NEG: + a8 = 0; + b8 = m_af.b.h; + a32 = a8 - b8; + F = (F & IF) | SZ[(UINT8)a32] | NF; + if (a32 & 0x100) F |= CF | XCF; //X? + if ((a8 ^ a32 ^ b8) & 0x10) F |= HF; + if ((b8 ^ a8) & (a8 ^ a32) & 0x80) F |= VF; + m_af.b.h = a32; + Cyc(); + break; + + case LDAR: + m_hl.w.l = m_pc.w.l + /*2 +*/ Read2_16(); + Cyc(); + break; + + case RCF: + F &= SF | ZF | IF | VF; + Cyc(); + break; + case SCF: + F = (F & (SF | ZF | IF | VF)) | XCF | CF; + Cyc(); + break; + case CCF: + F = (F & (SF | ZF | IF | VF)) | ((F & CF)?HF:(XCF | CF)); + Cyc(); + break; + +// case TSET: +// Cyc(); +// break; + case BIT: + F = (F & (IF | CF)) | HF | SZ_BIT[ Read2_8() & (1 << Read1_8()) ]; + Cyc(); + break; + case SET: + Write2_8( Read2_8() | (1 << Read1_8()) ); + Cyc(); + break; + case RES: + Write2_8( Read2_8() & (~(1 << Read1_8())) ); + Cyc(); + break; + + case INC: + a8 = Read1_8() + 1; + Write1_8( a8 ); + F = (F & (IF | CF)) | SZHV_inc[a8]; + if (a8 == 0) F |= XCF; + Cyc(); + break; + case INCX: + if ( F & XCF ) + { + a8 = Read1_8() + 1; + Write1_8( a8 ); + F = (F & (IF | CF)) | SZHV_inc[a8]; + if (a8 == 0) F |= XCF; + Cyc(); + } + else Cyc_f(); + break; + case INC | OP_16: + a16 = Read1_16() + 1; + Write1_16( a16 ); + if (a16 == 0) F |= XCF; + else F &= ~XCF; + Cyc(); + break; + case INCW: + a16 = Read1_16(); + a32 = a16 + 1; + Write1_16( a32 ); + F &= IF | CF; + if ((UINT16)a32 == 0) F |= ZF | XCF; + if (a32 & 0x8000) F |= SF; + if ((a16 ^ 0x8000) & a32 & 0x8000) F |= VF; + if ((a16 ^ a32 ^ 1) & 0x1000) F |= HF; //?? + Cyc(); + break; + + + case DEC: + a8 = Read1_8() - 1; + Write1_8( a8 ); + F = (F & (IF | CF)) | SZHV_dec[a8]; + if (a8 == 0) F |= XCF; + Cyc(); + break; + case DECX: + if ( F & XCF ) + { + a8 = Read1_8() - 1; + Write1_8( a8 ); + F = (F & (IF | CF)) | SZHV_dec[a8]; + if (a8 == 0) F |= XCF; + Cyc(); + } + else Cyc_f(); + break; + case DEC | OP_16: + a16 = Read1_16() - 1; + Write1_16( a16 ); + if (a16 == 0) F |= XCF; + else F &= ~XCF; + Cyc(); + break; + case DECW: + a16 = Read1_16(); + a32 = a16 - 1; + Write1_16( a32 ); + F = (F & (IF | CF)) | NF; + if ((UINT16)a32 == 0) F |= ZF | XCF; + if (a32 & 0x8000) F |= SF; + if (a16 == 0x8000) F |= VF; + if ((a16 ^ a32 ^ 1) & 0x1000) F |= HF; //?? + Cyc(); + break; + + case ADD: + case ADC: + a8 = Read1_8(); + b8 = Read2_8(); + a32 = a8 + b8; + if ( (m_op == ADC) && (F & CF) ) a32 += 1; + Write1_8( a32 ); + F = (F & IF) | SZ[(UINT8)a32]; + if (a32 & 0x100) F |= CF | XCF; //X? + if ((a8 ^ a32 ^ b8) & 0x10) F |= HF; + if ((b8 ^ a8 ^ 0x80) & (b8 ^ a32) & 0x80) F |= VF; + Cyc(); + break; + case ADD | OP_16: + case ADC | OP_16: + a16 = Read1_16(); + b16 = Read2_16(); + a32 = a16 + b16; + if ( (m_op == (ADC | OP_16)) && (F & CF) ) a32 += 1; + Write1_16( a32 ); + if ( (m_op == (ADD | OP_16)) && m_mode2 == MODE_R16 ) + { + F &= SF | ZF | IF | VF; + } + else + { + F &= IF; + if ((UINT16)a32 == 0) F |= ZF; + if (a32 & 0x8000) F |= SF; + if ((b16 ^ a16 ^ 0x8000) & (b16 ^ a32) & 0x8000) F |= VF; + } + if (a32 & 0x10000) F |= CF | XCF; //X? + if ((a16 ^ a32 ^ b16) & 0x1000) F |= HF; //?? + Cyc(); + break; + + case CP: + case SUB: + case SBC: + a8 = Read1_8(); + b8 = Read2_8(); + a32 = a8 - b8; + if ( (m_op == SBC) && (F & CF) ) a32 -= 1; + F = (F & IF) | SZ[(UINT8)a32] | NF; + if (a32 & 0x100) F |= CF | XCF; //X? + if ((a8 ^ a32 ^ b8) & 0x10) F |= HF; + if ((b8 ^ a8) & (a8 ^ a32) & 0x80) F |= VF; + if (m_op != CP) + Write1_8( a32 ); + Cyc(); + break; + case CP | OP_16: + case SUB | OP_16: + case SBC | OP_16: + a16 = Read1_16(); + b16 = Read2_16(); + a32 = a16 - b16; + if ( (m_op == (SBC | OP_16)) && (F & CF) ) a32 -= 1; + F = (F & IF) | NF; + if ((UINT16)a32 == 0) F |= ZF; + if (a32 & 0x8000) F |= SF; + if (a32 & 0x10000) F |= CF | XCF; //X? + if ((a16 ^ a32 ^ b16) & 0x1000) F |= HF; //?? + if ((b16 ^ a16) & (a16 ^ a32) & 0x8000) F |= VF; + if (m_op != (CP | OP_16)) + Write1_16( a32 ); + Cyc(); + break; + + case AND: + a8 = Read1_8() & Read2_8(); + Write1_8( a8 ); + F = (F & IF) | SZP[a8] | HF; + Cyc(); + break; + case AND | OP_16: + a16 = Read1_16() & Read2_16(); + Write1_16( a16 ); + F = (F & IF) | HF; + if (a16 == 0) F |= ZF; + if (a16 & 0x8000) F |= SF; + Cyc(); + break; + case XOR: + a8 = Read1_8() ^ Read2_8(); + Write1_8( a8 ); + F = (F & IF) | SZP[a8]; + Cyc(); + break; + case XOR | OP_16: + a16 = Read1_16() ^ Read2_16(); + Write1_16( a16 ); + F &= IF; + if (a16 == 0) F |= ZF; + if (a16 & 0x8000) F |= SF; + Cyc(); + break; + case OR: + a8 = Read1_8() | Read2_8(); + Write1_8( a8 ); + F = (F & IF) | SZP[a8]; + Cyc(); + break; + case OR | OP_16: + a16 = Read1_16() | Read2_16(); + Write1_16( a16 ); + F &= IF; + if (a16 == 0) F |= ZF; + if (a16 & 0x8000) F |= SF; + Cyc(); + break; + + case RLC: + a8 = Read1_8(); + a8 = (a8 << 1) | (a8 >> 7); + Write1_8( a8 ); + if ( m_mode1 == MODE_R8 && m_r1 == A ) F &= SF | ZF | IF | PF; + else F = (F & IF) | SZP[a8]; + if (a8 & 0x01) F |= CF | XCF; // X? + Cyc(); + break; + case RRC: + a8 = Read1_8(); + a8 = (a8 >> 1) | (a8 << 7); + Write1_8( a8 ); + if ( m_mode1 == MODE_R8 && m_r1 == A ) F &= SF | ZF | IF | PF; + else F = (F & IF) | SZP[a8]; + if (a8 & 0x80) F |= CF | XCF; // X? + Cyc(); + break; + case RL: + a8 = Read1_8(); + b8 = a8 & 0x80; + a8 <<= 1; + if (F & CF) a8 |= 0x01; + Write1_8( a8 ); + if ( m_mode1 == MODE_R8 && m_r1 == A ) F &= SF | ZF | IF | PF; + else F = (F & IF) | SZP[a8]; + if (b8) F |= CF | XCF; // X? + Cyc(); + break; + case RR: + a8 = Read1_8(); + b8 = a8 & 0x01; + a8 >>= 1; + if (F & CF) a8 |= 0x80; + Write1_8( a8 ); + if ( m_mode1 == MODE_R8 && m_r1 == A ) F &= SF | ZF | IF | PF; + else F = (F & IF) | SZP[a8]; + if (b8) F |= CF | XCF; // X? + Cyc(); + break; + + case SLA: + case SLL: + a8 = Read1_8(); + b8 = a8 & 0x80; + a8 <<= 1; + Write1_8( a8 ); + if ( m_mode1 == MODE_R8 && m_r1 == A ) F &= SF | ZF | IF | PF; + else F = (F & IF) | SZP[a8]; + if (b8) F |= CF | XCF; // X? + Cyc(); + break; + case SRA: + a8 = Read1_8(); + b8 = a8 & 0x01; + a8 = (a8 & 0x80) | (a8 >> 1); + Write1_8( a8 ); + if ( m_mode1 == MODE_R8 && m_r1 == A ) F &= SF | ZF | IF | PF; + else F = (F & IF) | SZP[a8]; + if (b8) F |= CF | XCF; // X? + Cyc(); + break; + case SRL: + a8 = Read1_8(); + b8 = a8 & 0x01; + a8 >>= 1; + Write1_8( a8 ); + if ( m_mode1 == MODE_R8 && m_r1 == A ) F &= SF | ZF | IF | PF; + else F = (F & IF) | SZP[a8]; + if (b8) F |= CF | XCF; // X? + Cyc(); + break; + case RLD: + a8 = m_af.b.h; + b8 = Read1_8(); + Write1_8( (b8 << 4) | (a8 & 0x0f) ); + a8 = (a8 & 0xf0) | (b8 >> 4); + F = (F & (IF | CF)) | SZP[a8]; + m_af.b.h = a8; + Cyc(); + break; + case RRD: + a8 = m_af.b.h; + b8 = Read1_8(); + Write1_8( (b8 >> 4) | (a8 << 4) ); + a8 = (a8 & 0xf0) | (b8 & 0x0f); + F = (F & (IF | CF)) | SZP[a8]; + m_af.b.h = a8; + Cyc(); + break; + + case DJNZ: + if ( --m_bc.b.h ) + { + m_pc.w.l += /*2 +*/ (INT8)Read1_8(); + Cyc(); + } + else Cyc_f(); + break; + case DJNZ | OP_16: + if ( --m_bc.w.l ) + { + m_pc.w.l += /*2 +*/ (INT8)Read2_8(); + Cyc(); + } + else Cyc_f(); + break; + + case MUL: + m_hl.w.l = (UINT16)m_hl.b.l * (UINT16)Read2_8(); + Cyc(); + break; + case DIV: + a16 = m_hl.w.l; + b16 = (UINT16)Read2_8(); + if (b16 == 0) + { + F |= VF; + m_hl.w.l = (a16 << 8) | ((a16 >> 8) ^ 0xff); + } + else + { + m_hl.b.h = a16 % b16; + a16 /= b16; + if (a16 > 0xff) F |= VF; + else F &= ~VF; + m_hl.b.l = a16; + } + Cyc(); + break; + + default: + fatalerror("%04x: unimplemented opcode, op=%02x\n",pc(),m_op); + } + + if ( m_op != EI ) + if (m_after_EI) + { + F |= IF; + m_after_EI = 0; + } + + } while( m_icount > 0 ); + + m_icount -= m_extra_cycles; + m_extra_cycles = 0; +} + +void tlcs90_device::device_reset() +{ + m_irq_state = 0; + m_irq_mask = 0; + m_pc.d = 0x0000; + F &= ~IF; +/* + P0/D0-D7 P1/A0-A7 P2/A8-A15 P6 P7 = INPUT + P35/~RD P36/~WR CLK = 1 (ALWAYS OUTPUTS) + P4/A16-A19 P83 = 0 + dedicated input ports and CPU registers remain unchanged, + but PC IFF BX BY = 0, A undefined +*/ + memset(m_internal_registers, 0, sizeof(m_internal_registers)); +} + +void tlcs90_device::execute_burn(INT32 cycles) +{ + m_icount -= 4 * ((cycles + 3) / 4); +} + + +/************************************************************************************************************* + + +---------------------------------------------------------------------------------------------------------------- +FFC0 P0 R/W Reset Description +---------------------------------------------------------------------------------------------------------------- +7-0 P07-P00 R W IN I/O Port 0 + +---------------------------------------------------------------------------------------------------------------- +FFC1 P1 R/W Reset Description +---------------------------------------------------------------------------------------------------------------- +7-0 P17-P10 R W IN I/O Port 1 + +---------------------------------------------------------------------------------------------------------------- +FFC2 P01CR/ R/W Reset Description * Prohibit Read-Modify-Write * + IRFL +---------------------------------------------------------------------------------------------------------------- + 7 - - 0 - + 6 IRF0 R 0 INT0 interrupt request (1 = asserted) + 5 IRFT0 R 0 INTT0 "" + 4 IRFT1 R 0 INTT1 "" + 3 - - 0 - + 2 EXT W 0 P1/P2 control: 0 = Port 1 = Address Bus + 1 P1CR W 0 P1 control: 0 = IN 1 = OUT | + 0 P0CR W 0 P0 control: 0 = IN 1 = OUT | + | | + Port 0 also functions as data bus (D0-D7),so P1: regardless of + P0CR is reset when external memory is accessed P2: only if P2CR is set to 1 (output) + TMP90C841A: always address bus + +---------------------------------------------------------------------------------------------------------------- +FFC3 IRFH R/W Reset Description * Prohibit Read-Modify-Write * +---------------------------------------------------------------------------------------------------------------- + 7 IRFT2 R W 0 INTT2 interrupt request (1 = asserted) + 6 IRFT3 R W 0 INTT3 "" + 5 IRFT4 R W 0 INTT4 "" + 4 IRF1 R W 0 INT1 "" + 3 IRFT5 R W 0 INTT5 "" + 2 IRF2 R W 0 INT2 "" + 1 IRFRX R W 0 INTRX "" + 0 IRFTX R W 0 INTTX "" + |__ Writing Vector/8 clears the request flip-flop for that interrupt + +---------------------------------------------------------------------------------------------------------------- +FFC4 P2 R/W Reset Description +---------------------------------------------------------------------------------------------------------------- +7-0 P27-P20 R W IN I/O Port 2 + +---------------------------------------------------------------------------------------------------------------- +FFC5 P2CR R/W Reset Description +---------------------------------------------------------------------------------------------------------------- +7-0 P27C- W 0 Port 2 control: 0 = IN 1 = OUT + P20C + +---------------------------------------------------------------------------------------------------------------- +FFC6 P3 R/W Reset Description +---------------------------------------------------------------------------------------------------------------- + 7 P37 R IN P37 input + 6 P36 R W 1 ~WD + 5 P35 R W 1 ~RD + 4 P34 R IN P34 input + 3 P33 R W 1 TxD / P33 output + 2 P32 R W 1 TxD / P32 output + 1 P31 R IN RxD / P31 input + 0 P30 R IN RxD / P30 input + +---------------------------------------------------------------------------------------------------------------- +FFC7 P3CR R/W Reset Description * Prohibit Read-Modify-Write * +---------------------------------------------------------------------------------------------------------------- +7-6 WAITC1-0R W 00 Wait control: 00 = 2state 01 = normal 10 = no wait 11 = reserved + 5 RDE R W 0 RD control: 0 = only external access 1 = always + 4 ODE R W 0 P33 control: 0 = CMOS 1 = Open Drain +3-2 TXDC1-0 R W 00 P33-P32: 00 = OUT-OUT 01 = OUT-TxD 10 = TxD-OUT 11 = TxD-~RTS/SCLK +1-0 RXDC1-0 R W 00 P31-P30: 00 = IN-IN 01 = IN-RxD 10 = RxD-IN 11 = not used + +---------------------------------------------------------------------------------------------------------------- +FFC8 P4 R/W Reset Description +---------------------------------------------------------------------------------------------------------------- +7-4 - +3-0 P43-P40 R W 0 I/O Port 4 bits 3-0 or address bus A16-A19 + +---------------------------------------------------------------------------------------------------------------- +FFC9 P4CR R/W Reset Description +---------------------------------------------------------------------------------------------------------------- +7-4 - +3-0 P43C- W 0 Port 4 control: 0 = OUT 1 = Address Output + P40C + +---------------------------------------------------------------------------------------------------------------- +FFCA P5 R/W Reset Description +---------------------------------------------------------------------------------------------------------------- +7 - R 0 Test bit, must be set to 0 +6 - R 0 +5-0 P55-P50 R 0 I/O Port 5 bits 5-0 / AN5-AN0 analog inputs + +---------------------------------------------------------------------------------------------------------------- +FFCB SMMOD R/W Reset Description +---------------------------------------------------------------------------------------------------------------- + 7 - R W - + 6 SM7M0 R W 0 Motor Step: 0 = Full 1 = Half + 5 P70C1 R W 0 Port 7 control: 0 = IN-OUT 0 = IN-OUT,TO3 1 = IN / M1 1 = Timer 4 + 4 P70C0 R W 0 0 1 0 Timer 2,3 1 + 3 - R W - + 2 SM6M0 R W 0 Motor Step: 0 = Full 1 = Half + 1 P60C1 R W 0 Port 6 control: 0 = IN-OUT 0 = IN-OUT,TO1 1 = IN / M0 + 0 P60C0 R W 0 0 1 X Timer 0,1 + +---------------------------------------------------------------------------------------------------------------- +FFCC P6 R/W Reset Description * Read-Modify-Write not available in Stepping Motor control * +---------------------------------------------------------------------------------------------------------------- +7-4 SA60-63 W Undef Stepping motor Port 0 (M0) Shifter alternate reg. +3-0 P63-P60 R W IN Bits 3-0 of I/O Port 6 or Stepping motor Port 0 (M0) + +---------------------------------------------------------------------------------------------------------------- +FFCD P7 R/W Reset Description * Read-Modify-Write not available in Stepping Motor control * +---------------------------------------------------------------------------------------------------------------- +7-4 SA70-73 W Undef Stepping motor Port 1 (M1) Shifter alternate reg. +3-0 P73-P70 R W IN Bits 3-0 of I/O Port 7 or Stepping motor Port 1 (M1) + +---------------------------------------------------------------------------------------------------------------- +FFCE P67CR R/W Reset Description * Prohibit Read-Modify-Write * +---------------------------------------------------------------------------------------------------------------- +7-4 P73-70C W 0 Port 7: 0 = IN 1 = OUT +3-0 P63-60C W 0 Port 6: 0 = IN 1 = OUT + +---------------------------------------------------------------------------------------------------------------- +FFD0 P8 R/W Reset Description +---------------------------------------------------------------------------------------------------------------- +7-4 - + 3 P83 R W 0 P83 / TIO3 / TIO4 output + 2 P82 R IN P82 + INT2 input + 1 P81 R IN P81 + INT1 input + 0 P80 R IN P80 + INT0 input + +---------------------------------------------------------------------------------------------------------------- +FFD1 P8CR R/W Reset Description +---------------------------------------------------------------------------------------------------------------- +7-4 - + 3 P83OC W 0 P83 out control: 0 = P83 1 = TO3 / TO4 + 2 ZCE2 W 0 INT2/TI5 control: 0 = ZCD disable 1 = ZCD enable + 1 ZCE1 W 0 INT1/TI4 control: 0 = ZCD disable 1 = ZCD enable + 0 EDGE W 0 INT0 control: 0 = Level 1 = Rising edge + +---------------------------------------------------------------------------------------------------------------- +FFD2 WDMOD R/W Reset Description +---------------------------------------------------------------------------------------------------------------- + 7 WDTE R W 1 1 = WDT Enable + 6 WDTP1 R W 0 WDT detection time: 0 = 2^14/fc 0 = 2^16/fc 1 = 2^18/fc 1 = 2^20/fc + 5 WDTP0 R W 0 0 1 0 1 + 4 WARM R W 0 Warming up time: 0 = 2^14/fc 1 = 2^16/fc + 3 HALTM1 R W 0 Standby mode: 0 = RUN 0 = STOP 1 = IDLE1 1 = IDLE2 + 2 HALTM0 R W 0 0 1 0 1 + 1 EXF R Undef Invert each time EXX instruction is executed + 0 DRIVE R W 0 1 to drive pins in stop mode + +---------------------------------------------------------------------------------------------------------------- +FFD4 TREG0 R/W Reset Description +---------------------------------------------------------------------------------------------------------------- +7-0 - W 0 Timer 0 match value + +---------------------------------------------------------------------------------------------------------------- +FFD5 TREG1 R/W Reset Description +---------------------------------------------------------------------------------------------------------------- +7-0 - W 0 Timer 0 match value + +---------------------------------------------------------------------------------------------------------------- +FFD6 TREG2 R/W Reset Description +---------------------------------------------------------------------------------------------------------------- +7-0 - W 0 Timer 0 match value + +---------------------------------------------------------------------------------------------------------------- +FFD7 TREG3 R/W Reset Description +---------------------------------------------------------------------------------------------------------------- +7-0 - W 0 Timer 0 match value + +---------------------------------------------------------------------------------------------------------------- +FFD8 TCLK R/W Reset Description +---------------------------------------------------------------------------------------------------------------- +7-6 T3CLK1-0R W 00 Timer 3 clock: 00 = Timer 2 01 = clock 10 = clock/16 11 = clock/256 <- Timer 2 overflow output in 16 bit mode +5-4 T2CLK1-0R W 00 Timer 2 clock: 00 = - 01 = clock 10 = clock/16 11 = clock/256 +3-2 T1CLK1-0R W 00 Timer 1 clock: 00 = Timer 0 01 = clock 10 = clock/16 11 = clock/256 <- Timer 0 overflow output in 16 bit mode +1-0 T0CLK1-0R W 00 Timer 0 clock: 00 = - 01 = clock 10 = clock/16 11 = clock/256 + +---------------------------------------------------------------------------------------------------------------- +FFD9 TFFCR R/W Reset Description +---------------------------------------------------------------------------------------------------------------- +7-6 TFF3C1-0 W - Timer 3 flip-flop: 00 = Clear 01 = Set 10 = Invert 11 = Don't care <- Always read as 11 +5 TFF3IE R W 0 Timer 3 Invert: 0 = Disable 1 = Enable +4 TFF3IS R W 0 Timer 3 Invert: 0 = Timer 2 1 = Timer 3 +3-2 TFF1C1-0 W - Timer 1 Flip-Flop: 00 = Clear 01 = Set 10 = Invert 11 = Don't care <- Always read as 11 +1 TFF1IE R W 0 Timer 1 Invert: 0 = Disable 1 = Enable +0 TFF1IS R W 0 Timer 1 Invert: 0 = Timer 0 1 = Timer 1 + +---------------------------------------------------------------------------------------------------------------- +FFDA TMOD R/W Reset Description +---------------------------------------------------------------------------------------------------------------- +7-6 T32M1-0 R W 00 Timers 2 & 3: 00 = 8b x 2 01 = 16b(T3+T2) 10 = 8b PPG(T3) 11 = 8b PWM (T3) + 8b (T2) +5-4 PWM21-0 R W 00 Timer 3 PWM freq: 00 = - 01 = 63/fc 10 = 127/fc 11 = 255/fc +3-2 T10M1-0 R W 00 Timers 1 & 0: 00 = 8b x 2 01 = 16b(T1+T0) 10 = 8b PPG(T1) 11 = 8b PWM (T1) + 8b (T0) +1-0 PWM01-0 R W 00 Timer 1 PWM freq: 00 = - 01 = 63/fc 10 = 127/fc 11 = 255/fc + +---------------------------------------------------------------------------------------------------------------- +FFDB TRUN R/W Reset Description +---------------------------------------------------------------------------------------------------------------- +7-6 BRATE1-0R W 00 Serial baud rate: 00 = 300/150 01 = 1200/600 10 = 4800/2400 11 = 19200/9600 + 5 PRRUN R W 0 Prescaler control: 0 = Stop & Clear 1 = Run + 4 T4RUN R W 0 Timer 4 control: 0 = Stop & Clear 1 = Run +3-0 T4RUN-0 R W 00 Timers 3-0 control: 0 = Stop & Clear 1 = Run + +---------------------------------------------------------------------------------------------------------------- +FFE6 INTEL R/W Reset Description +---------------------------------------------------------------------------------------------------------------- + 7 DET2 R W 0 INTT2/INTAD interrupt enable flag (1 = enable) + 6 DET3 R W 0 INTT3 "" + 5 DET4 R W 0 INTT4 "" + 4 DE1 R W 0 INT1 "" + 3 DET5 R W 0 INTT5 "" + 2 DE2 R W 0 INT2 "" + 1 DERX R W 0 INTRX "" + 0 DETX R W 0 INTTX "" + +---------------------------------------------------------------------------------------------------------------- +FFE7 INTEH R/W Reset Description +---------------------------------------------------------------------------------------------------------------- + 7 - R W 0 Write "0" + 6 DE0 R W 0 INT0 DMA enable flag (1 = enable) + 5 DET0 R W 0 INTT0 "" + 4 DET1 R W 0 INTT1 "" + 3 ADIS R W 0 INTT2/INTAD selection (1 = INTAD) + 2 IE0 R W 0 INT0 interrupt enable flag (1 = enable) + 1 IET0 R W 0 INTT0 "" + 0 IET1 R W 0 INTT1 "" + +---------------------------------------------------------------------------------------------------------------- +FFE8 DMAEH R/W Reset Description +---------------------------------------------------------------------------------------------------------------- + 7 DET2 R W 0 INTT2/INTAD DMA enable flag (1 = enable) + 6 DET3 R W 0 INTT3 "" + 5 DET4 R W 0 INTT4 "" + 4 DE1 R W 0 INT1 "" + 3 DET5 R W 0 INTT5 "" + 2 DE2 R W 0 INT2 "" + 1 DERX R W 0 INTRX "" + 0 DETX R W 0 INTTX "" + +---------------------------------------------------------------------------------------------------------------- +FFEC BX R/W Reset Description +---------------------------------------------------------------------------------------------------------------- + 7 - R 1 + 6 - R 1 + 5 - R 1 + 4 - R 1 + 3 BX3 R W 0 IX bank register bit 3 + 2 BX2 R W 0 IX bank register bit 2 + 1 BX1 R w 0 IX bank register bit 1 + 0 BX0 R W 0 IX bank register bit 0 + +---------------------------------------------------------------------------------------------------------------- +FFED BX R/W Reset Description +---------------------------------------------------------------------------------------------------------------- + 7 - R 1 + 6 - R 1 + 5 - R 1 + 4 - R 1 + 3 BY3 R W 0 IY bank register bit 3 + 2 BY2 R W 0 IY bank register bit 2 + 1 BY1 R w 0 IY bank register bit 1 + 0 BY0 R W 0 IY bank register bit 0 + +*************************************************************************************************************/ + +READ8_MEMBER( tlcs90_device::t90_internal_registers_r ) +{ + #define RIO m_io->read_byte( T90_IOBASE+offset ) + + UINT8 data = m_internal_registers[offset]; + switch ( T90_IOBASE + offset ) + { + case T90_P3: // 7,4,1,0 + return (data & 0x6c) | (RIO & 0x93); + + case T90_P4: // only output + return data & 0x0f; + + case T90_P5: + return (RIO & 0x3f); + + case T90_P6: + case T90_P7: + return (data & 0xf0) | (RIO & 0x0f); + + case T90_P8: // 2,1,0 + return (data & 0x08) | (RIO & 0x07); + + case T90_BX: + case T90_BY: + return 0xf0 | data; + } + return data; +} + +void tlcs90_device::t90_start_timer(int i) +{ + int prescaler; + attotime period; + + m_timer_value[i] = 0; + + switch((m_internal_registers[ T90_TMOD - T90_IOBASE ] >> (i * 2)) & 0x03) + { + case 0: + // 8-bit mode + break; + case 1: + // 16-bit mode + break; + case 2: + logerror("%04X: CPU Timer %d, unsupported PPG mode\n", m_pc.w.l, i); + return; + case 3: + logerror("%04X: CPU Timer %d, unsupported PWM mode\n", m_pc.w.l, i); + return; + } + + switch((m_internal_registers[ T90_TCLK - T90_IOBASE ] >> (i * 2)) & 0x03) + { + case 0: if (i & 1) logerror("%04X: CPU Timer %d clocked by Timer %d match signal\n", m_pc.w.l, i,i-1); + else logerror("%04X: CPU Timer %d, unsupported TCLK = 0\n", m_pc.w.l, i); + return; + case 2: prescaler = 16; break; + case 3: prescaler = 256; break; + default: + case 1: prescaler = 1; break; + } + + + period = m_timer_period * prescaler; + + m_timer[i]->adjust(period, i, period); + + logerror("%04X: CPU Timer %d started at %f Hz\n", m_pc.w.l, i, 1.0 / period.as_double()); +} + +void tlcs90_device::t90_start_timer4() +{ + int prescaler; + attotime period; + + m_timer4_value = 0; + + switch(m_internal_registers[ T90_T4MOD - T90_IOBASE ] & 0x03) + { + case 1: prescaler = 1; break; + case 2: prescaler = 16; break; + default: logerror("%04X: CPU Timer 4, unsupported T4MOD = %d\n", m_pc.w.l,m_internal_registers[ T90_T4MOD - T90_IOBASE ] & 0x03); + return; + } + + period = m_timer_period * prescaler; + + m_timer[4]->adjust(period, 4, period); + + logerror("%04X: CPU Timer 4 started at %f Hz\n", m_pc.w.l, 1.0 / period.as_double()); +} + + +void tlcs90_device::t90_stop_timer(int i) +{ + m_timer[i]->adjust(attotime::never, i); + logerror("%04X: CPU Timer %d stopped\n", m_pc.w.l, i); +} + +void tlcs90_device::t90_stop_timer4() +{ + t90_stop_timer(4); +} + +TIMER_CALLBACK_MEMBER( tlcs90_device::t90_timer_callback ) +{ + int mode, timer_fired; + int i = param; + + int mask = 0x20 | (1 << i); + if ( (m_internal_registers[ T90_TRUN - T90_IOBASE ] & mask) != mask ) + return; + + timer_fired = 0; + + mode = (m_internal_registers[ T90_TMOD - T90_IOBASE ] >> ((i & ~1) + 2)) & 0x03; + // Match + switch (mode) + { + case 0x02: // 8bit PPG + case 0x03: // 8bit PWM + logerror("CPU Timer %d expired with unhandled mode %d\n", i, mode); + // TODO: hmm... + case 0x00: // 8bit + m_timer_value[i]++; + if ( m_timer_value[i] == m_internal_registers[ T90_TREG0+i - T90_IOBASE ] ) + timer_fired = 1; + break; + + case 0x01: // 16bit + if(i & 1) + break; + m_timer_value[i]++; + if(m_timer_value[i] == 0) m_timer_value[i+1]++; + if(m_timer_value[i+1] == m_internal_registers[ T90_TREG0+i+1 - T90_IOBASE ]) + if(m_timer_value[i] == m_internal_registers[ T90_TREG0+i - T90_IOBASE ]) + timer_fired = 1; + break; + } + + if(timer_fired) { + // special stuff handling + switch(mode) { + case 0x02: // 8bit PPG + case 0x03: // 8bit PWM + // TODO: hmm... + case 0x00: // 8bit + if(i & 1) + break; + if ( (m_internal_registers[ T90_TCLK - T90_IOBASE ] & (0x0C << (i * 2))) == 0 ) // T0/T1 match signal clocks T1/T3 + t90_timer_callback(ptr, i+1); + break; + case 0x01: // 16bit, only can happen for i=0,2 + m_timer_value[i+1] = 0; + set_irq_line(INTT0 + i+1, 1); + break; + } + // regular handling + m_timer_value[i] = 0; + set_irq_line(INTT0 + i, 1); + } +} + +TIMER_CALLBACK_MEMBER( tlcs90_device::t90_timer4_callback ) +{ +// logerror("CPU Timer 4 fired! value = %d\n", (unsigned)m_timer_value[4]); + + m_timer4_value++; + + // Match + + if ( m_timer4_value == (m_internal_registers[ T90_TREG4L - T90_IOBASE ] + (m_internal_registers[ T90_TREG4H - T90_IOBASE ] << 8)) ) + { +// logerror("CPU Timer 4 matches TREG4\n"); + set_irq_line(INTT4, 1); + } + if ( m_timer4_value == (m_internal_registers[ T90_TREG5L - T90_IOBASE ] + (m_internal_registers[ T90_TREG5H - T90_IOBASE ] << 8)) ) + { +// logerror("CPU Timer 4 matches TREG5\n"); + set_irq_line(INTT5, 1); + if (m_internal_registers[ T90_T4MOD - T90_IOBASE ] & 0x04) + m_timer4_value = 0; + } + + // Overflow + + if ( m_timer_value == 0 ) + { +// logerror("CPU Timer 4 overflow\n"); + } +} + +WRITE8_MEMBER( tlcs90_device::t90_internal_registers_w ) +{ + #define WIO m_io->write_byte( T90_IOBASE+offset, data ) + + UINT8 out_mask; + UINT8 old = m_internal_registers[offset]; + switch ( T90_IOBASE + offset ) + { + case T90_TRUN: + { + int i; + UINT8 mask; + // Timers 0-3 + for (i = 0; i < 4; i++) + { + mask = 0x20 | (1 << i); + if ( (old ^ data) & mask ) // if timer bit or prescaler bit changed + { + if ( (data & mask) == mask ) t90_start_timer(i); + else t90_stop_timer(i); + } + } + + // Timer 4 + mask = 0x20 | 0x10; + if ( (old ^ data) & mask ) + { + if ( (data & mask) == mask ) t90_start_timer4(); + else t90_stop_timer4(); + } + break; + } + + case T90_INTEL: + m_irq_mask &= ~( (1 << INTT2 ) | + (1 << INTT3 ) | + (1 << INTT4 ) | + (1 << INT1 ) | + (1 << INTT5 ) | + (1 << INT2 ) | + (1 << INTRX ) | + (1 << INTTX ) ); + + m_irq_mask |= ((data & 0x80) ? (1 << INTT2 ) : 0) | + ((data & 0x40) ? (1 << INTT3 ) : 0) | + ((data & 0x20) ? (1 << INTT4 ) : 0) | + ((data & 0x10) ? (1 << INT1 ) : 0) | + ((data & 0x08) ? (1 << INTT5 ) : 0) | + ((data & 0x04) ? (1 << INT2 ) : 0) | + ((data & 0x02) ? (1 << INTRX ) : 0) | + ((data & 0x01) ? (1 << INTTX ) : 0) ; + break; + + case T90_INTEH: + m_irq_mask &= ~( (1 << INT0 ) | + (1 << INTT0) | + (1 << INTT1) ); + + m_irq_mask |= ((data & 0x04) ? (1 << INT0 ) : 0) | + ((data & 0x02) ? (1 << INTT0) : 0) | + ((data & 0x01) ? (1 << INTT1) : 0) ; + break; + + case T90_P3: + data &= 0x6c; + WIO; + break; + + case T90_P4: + data &= 0x0f; + out_mask = (~m_internal_registers[ T90_P4CR - T90_IOBASE ]) & 0x0f; + if (out_mask) + { + data &= out_mask; + WIO; + } + break; + + case T90_P6: + out_mask = m_internal_registers[ T90_P67CR - T90_IOBASE ] & 0x0f; + switch (m_internal_registers[ T90_SMMOD - T90_IOBASE ] & 0x03) + { + case 1: + data &= ~0x01; + // add TO1 here + break; + case 2: + case 3: + data &= ~0x0f; + // add M0 here + break; + } + + if (out_mask) + { + data &= out_mask; + WIO; + } + break; + + case T90_P7: + out_mask = (m_internal_registers[ T90_P67CR - T90_IOBASE ] & 0xf0) >> 4; + switch ((m_internal_registers[ T90_SMMOD - T90_IOBASE ]>>4) & 0x03) + { + case 1: + data &= ~0x01; + // add TO3 here + break; + case 2: + case 3: + data &= ~0x0f; + // add M1 here + break; + } + + if (out_mask) + { + data &= out_mask; + WIO; + } + break; + + case T90_P8: + data &= 0x0f; + out_mask = (~m_internal_registers[ T90_P8CR - T90_IOBASE ]) & 0x08; + if (out_mask) + { + data &= out_mask; + WIO; + } + break; + + case T90_BX: + m_ixbase = (data & 0xf) << 16; + break; + case T90_BY: + m_iybase = (data & 0xf) << 16; + break; + } + m_internal_registers[offset] = data; +} + + +void tlcs90_device::device_start() +{ + int i, p; + + save_item(NAME(m_prvpc.w.l)); + save_item(NAME(m_pc.w.l)); + save_item(NAME(m_sp.w.l)); + save_item(NAME(m_af.w.l)); + save_item(NAME(m_bc.w.l)); + save_item(NAME(m_de.w.l)); + save_item(NAME(m_hl.w.l)); + save_item(NAME(m_ix.w.l)); + save_item(NAME(m_iy.w.l)); + save_item(NAME(m_af2.w.l)); + save_item(NAME(m_bc2.w.l)); + save_item(NAME(m_de2.w.l)); + save_item(NAME(m_hl2.w.l)); + save_item(NAME(m_halt)); + save_item(NAME(m_after_EI)); + save_item(NAME(m_irq_state)); + save_item(NAME(m_irq_mask)); + save_item(NAME(m_extra_cycles)); + + save_item(NAME(m_internal_registers)); + save_item(NAME(m_ixbase)); + save_item(NAME(m_iybase)); + + save_item(NAME(m_timer_value)); + save_item(NAME(m_timer4_value)); + + // Work registers + save_item(NAME(m_op)); + save_item(NAME(m_mode1)); + save_item(NAME(m_r1)); + save_item(NAME(m_r1b)); + save_item(NAME(m_mode2)); + save_item(NAME(m_r2)); + save_item(NAME(m_r2b)); + + save_item(NAME(m_cyc_t)); + save_item(NAME(m_cyc_f)); + save_item(NAME(m_addr)); + + for (i = 0; i < 256; i++) + { + p = 0; + if( i&0x01 ) ++p; + if( i&0x02 ) ++p; + if( i&0x04 ) ++p; + if( i&0x08 ) ++p; + if( i&0x10 ) ++p; + if( i&0x20 ) ++p; + if( i&0x40 ) ++p; + if( i&0x80 ) ++p; + SZ[i] = i ? i & SF : ZF; +// SZ[i] |= (i & (YF | XF)); /* undocumented flag bits 5+3 */ + SZ_BIT[i] = i ? i & SF : ZF | PF; +// SZ_BIT[i] |= (i & (YF | XF)); /* undocumented flag bits 5+3 */ + SZP[i] = SZ[i] | ((p & 1) ? 0 : PF); + SZHV_inc[i] = SZ[i]; + if( i == 0x80 ) SZHV_inc[i] |= VF; + if( (i & 0x0f) == 0x00 ) SZHV_inc[i] |= HF; + SZHV_dec[i] = SZ[i] | NF; + if( i == 0x7f ) SZHV_dec[i] |= VF; + if( (i & 0x0f) == 0x0f ) SZHV_dec[i] |= HF; + } + + m_prvpc.d = m_pc.d = m_sp.d = m_af.d = m_bc.d = m_de.d = m_hl.d = m_ix.d = m_iy.d = 0; + m_af2.d = m_bc2.d = m_de2.d = m_hl2.d = 0; + m_halt = m_after_EI = 0; + m_irq_state = m_irq_mask = 0; + m_extra_cycles = 0; + memset(m_internal_registers, 0, sizeof(m_internal_registers)); + m_ixbase = m_iybase = 0; + m_timer_value[0] = m_timer_value[1] = m_timer_value[2] = m_timer_value[3] = 0; + m_timer4_value = 0; + m_op = 0; + m_mode1 = MODE_NONE; + m_r1 = m_r1b = 0; + m_mode2 = MODE_NONE; + m_r2 = m_r2b = 0; + m_cyc_t = m_cyc_f = 0; + m_addr = 0; + + m_program = &space(AS_PROGRAM); + m_io = &space(AS_IO); + + m_timer_period = attotime::from_hz(unscaled_clock()) * 8; + + // Timers + + for (i = 0; i < 4; i++) + m_timer[i] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(tlcs90_device::t90_timer_callback),this)); + + m_timer[4] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(tlcs90_device::t90_timer4_callback),this)); + + state_add( T90_PC, "PC", m_pc.w.l).formatstr("%04X"); + state_add( T90_SP, "SP", m_sp.w.l).formatstr("%04X"); + state_add( T90_A, "~A", m_af.b.h).formatstr("%02X"); + state_add( T90_B, "~B", m_bc.b.h).formatstr("%02X"); + state_add( T90_C, "~C", m_bc.b.l).formatstr("%02X"); + state_add( T90_D, "~D", m_de.b.h).formatstr("%02X"); + state_add( T90_E, "~E", m_de.b.l).formatstr("%02X"); + state_add( T90_H, "~H", m_hl.b.h).formatstr("%02X"); + state_add( T90_L, "~L", m_hl.b.l).formatstr("%02X"); + state_add( T90_AF, "AF", m_af.w.l).formatstr("%04X"); + state_add( T90_BC, "BC", m_bc.w.l).formatstr("%04X"); + state_add( T90_DE, "DE", m_de.w.l).formatstr("%04X"); + state_add( T90_HL, "HL", m_hl.w.l).formatstr("%04X"); + state_add( T90_IX, "IX", m_ix.w.l).formatstr("%04X"); + state_add( T90_IY, "IY", m_iy.w.l).formatstr("%04X"); + + state_add(STATE_GENPC, "GENPC", m_pc.w.l).formatstr("%04X").noshow(); + state_add(STATE_GENSP, "GENSP", m_sp.w.l).formatstr("%04X").noshow(); + state_add(STATE_GENFLAGS, "GENFLAGS", F ).formatstr("%8s").noshow(); + state_add(STATE_GENPCBASE, "GENPCBASE", m_prvpc.w.l).formatstr("%04X").noshow(); + + m_icountptr = &m_icount; +} + + +void tlcs90_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + switch (entry.index()) + { + case STATE_GENFLAGS: + strprintf(str, "%c%c%c%c%c%c%c%c", + F & 0x80 ? 'S':'.', + F & 0x40 ? 'Z':'.', + F & 0x20 ? 'I':'.', + F & 0x10 ? 'H':'.', + F & 0x08 ? 'X':'.', + F & 0x04 ? 'P':'.', + F & 0x02 ? 'N':'.', + F & 0x01 ? 'C':'.' + ); + break; + } +} diff --git a/src/devices/cpu/tlcs90/tlcs90.h b/src/devices/cpu/tlcs90/tlcs90.h new file mode 100644 index 00000000000..5e379cb4425 --- /dev/null +++ b/src/devices/cpu/tlcs90/tlcs90.h @@ -0,0 +1,181 @@ +// license:BSD-3-Clause +// copyright-holders:Luca Elia +#pragma once + +#ifndef __TLCS90_H__ +#define __TLCS90_H__ + + +#define T90_IOBASE 0xffc0 + +enum e_ir +{ + T90_P0=T90_IOBASE, T90_P1, T90_P01CR_IRFL, T90_IRFH, T90_P2, T90_P2CR, T90_P3, T90_P3CR, + T90_P4, T90_P4CR, T90_P5, T90_SMMOD, T90_P6, T90_P7, T90_P67CR, T90_SMCR, + T90_P8, T90_P8CR, T90_WDMOD, T90_WDCR, T90_TREG0, T90_TREG1, T90_TREG2, T90_TREG3, + T90_TCLK, T90_TFFCR, T90_TMOD, T90_TRUN, T90_CAP1L, T90_CAP1H, T90_CAP2L, T90_CAL2H, + T90_TREG4L, T90_TREG4H, T90_TREG5L, T90_TREG5H, T90_T4MOD, T90_T4FFCR, T90_INTEL, T90_INTEH, + T90_DMAEH, T90_SCMOD, T90_SCCR, T90_SCBUF, T90_BX, T90_BY, T90_ADREG, T90_ADMOD +}; + +enum tlcs90_e_irq { INTSWI = 0, INTNMI, INTWD, INT0, INTT0, INTT1, INTT2, INTT3, INTT4, INT1, INTT5, INT2, INTRX, INTTX, INTMAX }; +DECLARE_ENUM_OPERATORS(tlcs90_e_irq) + +class tlcs90_device : public cpu_device +{ +public: + // construction/destruction + tlcs90_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source, address_map_constructor program_map); + + DECLARE_READ8_MEMBER( t90_internal_registers_r ); + DECLARE_WRITE8_MEMBER( t90_internal_registers_w ); + + TIMER_CALLBACK_MEMBER( t90_timer_callback ); + TIMER_CALLBACK_MEMBER( t90_timer4_callback ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_execute_interface overrides + virtual UINT32 execute_min_cycles() const { return 2; } + virtual UINT32 execute_max_cycles() const { return 26; } + virtual UINT32 execute_input_lines() const { return 1; } + virtual UINT32 execute_default_irq_vector() const { return 0xff; } + virtual void execute_run(); + virtual void execute_set_input(int inputnum, int state); + virtual void execute_burn(INT32 cycles); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const { return (spacenum == AS_PROGRAM) ? &m_program_config : ( (spacenum == AS_IO) ? &m_io_config : NULL ); } + + // device_state_interface overrides + void state_string_export(const device_state_entry &entry, std::string &str); + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const { return 1; } + virtual UINT32 disasm_max_opcode_bytes() const { return 6; } + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + +private: + enum e_mode { + MODE_NONE, MODE_BIT8, MODE_CC, + MODE_I8, MODE_D8, MODE_R8, + MODE_I16, MODE_D16, MODE_R16, + MODE_MI16, MODE_MR16, MODE_MR16D8, MODE_MR16R8, + MODE_R16D8, MODE_R16R8 + }; + + address_space_config m_program_config; + address_space_config m_io_config; + + PAIR m_prvpc,m_pc,m_sp,m_af,m_bc,m_de,m_hl,m_ix,m_iy; + PAIR m_af2,m_bc2,m_de2,m_hl2; + UINT8 m_halt, m_after_EI; + UINT16 m_irq_state, m_irq_mask; + address_space *m_program; + address_space *m_io; + int m_icount; + int m_extra_cycles; // extra cycles for interrupts + UINT8 m_internal_registers[48]; + UINT32 m_ixbase,m_iybase; + + // Timers: 4 x 8-bit + 1 x 16-bit + emu_timer *m_timer[4+1]; + UINT8 m_timer_value[4]; + UINT16 m_timer4_value; + attotime m_timer_period; + + // Work registers + UINT8 m_op; + + e_mode m_mode1; + UINT16 m_r1,m_r1b; + + e_mode m_mode2; + UINT16 m_r2,m_r2b; + + int m_cyc_t,m_cyc_f; + + UINT32 m_addr; + + inline UINT8 RM8 (UINT32 a); + inline UINT16 RM16(UINT32 a); + inline void WM8 (UINT32 a, UINT8 v); + inline void WM16(UINT32 a, UINT16 v); + inline UINT8 RX8 (UINT32 a, UINT32 base); + inline UINT16 RX16(UINT32 a, UINT32 base); + inline void WX8 (UINT32 a, UINT8 v, UINT32 base); + inline void WX16(UINT32 a, UINT16 v, UINT32 base); + inline UINT8 READ8(); + inline UINT16 READ16(); + void decode(); + const char *internal_registers_names(UINT16 x); + int sprint_arg(char *buffer, UINT32 pc, const char *pre, const e_mode mode, const UINT16 r, const UINT16 rb); + inline UINT16 r8( const UINT16 r ); + inline void w8( const UINT16 r, UINT16 value ); + inline UINT16 r16( const UINT16 r ); + inline void w16( const UINT16 r, UINT16 value ); + inline UINT8 Read1_8(); + inline UINT16 Read1_16(); + inline UINT8 Read2_8(); + inline UINT16 Read2_16(); + inline void Write1_8( UINT8 value ); + inline void Write1_16( UINT16 value ); + inline void Write2_8( UINT8 value ); + inline void Write2_16( UINT16 value ); + inline int Test( UINT8 cond ); + inline void Push( UINT16 rr ); + inline void Pop( UINT16 rr ); + inline void leave_halt(); + void take_interrupt(tlcs90_e_irq irq); + void check_interrupts(); + inline void Cyc(); + inline void Cyc_f(); + void t90_start_timer(int i); + void t90_start_timer4(); + void t90_stop_timer(int i); + void t90_stop_timer4(); + void set_irq_line(int irq, int state); +}; + + +class tmp90840_device : public tlcs90_device +{ +public: + // construction/destruction + tmp90840_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +class tmp90841_device : public tlcs90_device +{ +public: + // construction/destruction + tmp90841_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +class tmp91640_device : public tlcs90_device +{ +public: + // construction/destruction + tmp91640_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +class tmp91641_device : public tlcs90_device +{ +public: + // construction/destruction + tmp91641_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +extern const device_type TMP90840; +extern const device_type TMP90841; +extern const device_type TMP91640; +extern const device_type TMP91641; + +#endif /* __TLCS90_H__ */ diff --git a/src/devices/cpu/tlcs900/900tbl.inc b/src/devices/cpu/tlcs900/900tbl.inc new file mode 100644 index 00000000000..2e66f1cf6c9 --- /dev/null +++ b/src/devices/cpu/tlcs900/900tbl.inc @@ -0,0 +1,6036 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +/******************************************************************* + +TLCS-900/H instruction set + +*******************************************************************/ + + +enum e_operand +{ + _A=1, /* currect register set register A */ + _C8, /* current register set byte */ + _C16, /* current register set word */ + _C32, /* current register set long word */ + _MC16, /* current register set mul/div register word */ + _CC, /* condition */ + _CR8, + _CR16, + _CR32, + _D8, /* byte displacement */ + _D16, /* word displacement */ + _F, /* F register */ + _I3, /* immediate 3 bit (part of last byte) */ + _I8, /* immediate byte */ + _I16, /* immediate word */ + _I24, /* immediate 3 byte address */ + _I32, /* immediate long word */ + _M, /* memory location (defined by extension) */ + _M8, /* (8) */ + _M16, /* (i16) */ + _R, /* register (defined by extension) */ + _SR /* status register */ +}; + + +int tlcs900h_device::condition_true( UINT8 cond ) +{ + switch ( cond & 0x0f ) + { + /* F */ + case 0x00: + return 0; + + /* LT */ + case 0x01: + return ( ( ( m_sr.b.l & ( FLAG_SF | FLAG_VF ) ) == FLAG_SF ) || + ( ( m_sr.b.l & ( FLAG_SF | FLAG_VF ) ) == FLAG_VF ) ); + + /* LE */ + case 0x02: + return ( ( ( m_sr.b.l & ( FLAG_SF | FLAG_VF ) ) == FLAG_SF ) || + ( ( m_sr.b.l & ( FLAG_SF | FLAG_VF ) ) == FLAG_VF ) || + ( m_sr.b.l & FLAG_ZF ) ); + + /* ULE */ + case 0x03: + return ( m_sr.b.l & ( FLAG_ZF | FLAG_CF ) ); + + /* OV */ + case 0x04: + return ( m_sr.b.l & FLAG_VF ); + + /* MI */ + case 0x05: + return ( m_sr.b.l & FLAG_SF ); + + /* Z */ + case 0x06: + return ( m_sr.b.l & FLAG_ZF ); + + /* C */ + case 0x07: + return ( m_sr.b.l & FLAG_CF ); + + /* T */ + case 0x08: + return 1; + + /* GE */ + case 0x09: + return ! ( ( ( m_sr.b.l & ( FLAG_SF | FLAG_VF ) ) == FLAG_SF ) || + ( ( m_sr.b.l & ( FLAG_SF | FLAG_VF ) ) == FLAG_VF ) ); + + /* GT */ + case 0x0A: + return ! ( ( ( m_sr.b.l & ( FLAG_SF | FLAG_VF ) ) == FLAG_SF ) || + ( ( m_sr.b.l & ( FLAG_SF | FLAG_VF ) ) == FLAG_VF ) || + ( m_sr.b.l & FLAG_ZF ) ); + + /* UGT */ + case 0x0B: + return ! ( m_sr.b.l & ( FLAG_ZF | FLAG_CF ) ); + + /* NOV */ + case 0x0C: + return ! ( m_sr.b.l & FLAG_VF ); + + /* PL */ + case 0x0D: + return ! ( m_sr.b.l & FLAG_SF ); + + /* NZ */ + case 0x0E: + return ! ( m_sr.b.l & FLAG_ZF ); + + /* NC */ + case 0x0F: + return ! ( m_sr.b.l & FLAG_CF ); + } + return 0; +} + + +UINT8* tlcs900h_device::get_reg8_current( UINT8 reg ) +{ + switch( reg & 7 ) + { + /* W */ + case 0: + return &m_xwa[m_regbank].b.h; + + /* A */ + case 1: + return &m_xwa[m_regbank].b.l; + + /* B */ + case 2: + return &m_xbc[m_regbank].b.h; + + /* C */ + case 3: + return &m_xbc[m_regbank].b.l; + + /* D */ + case 4: + return &m_xde[m_regbank].b.h; + + /* E */ + case 5: + return &m_xde[m_regbank].b.l; + + /* H */ + case 6: + return &m_xhl[m_regbank].b.h; + + /* L */ + case 7: + return &m_xhl[m_regbank].b.l; + } + /* keep compiler happy */ + return &m_dummy.b.l; +} + + +UINT16* tlcs900h_device::get_reg16_current( UINT8 reg ) +{ + switch( reg & 7 ) + { + /* WA */ + case 0: + return &m_xwa[m_regbank].w.l; + + /* BC */ + case 1: + return &m_xbc[m_regbank].w.l; + + /* DE */ + case 2: + return &m_xde[m_regbank].w.l; + + /* HL */ + case 3: + return &m_xhl[m_regbank].w.l; + + /* IX */ + case 4: + return &m_xix.w.l; + + /* IY */ + case 5: + return &m_xiy.w.l; + + /* IZ */ + case 6: + return &m_xiz.w.l; + + /* SP */ + /* TODO: Use correct user/system SP */ + case 7: + return &m_xssp.w.l; + } + /* keep compiler happy */ + return &m_dummy.w.l; +} + + +UINT32* tlcs900h_device::get_reg32_current( UINT8 reg ) +{ + switch( reg & 7 ) + { + /* XWA */ + case 0: + return &m_xwa[m_regbank].d; + + /* XBC */ + case 1: + return &m_xbc[m_regbank].d; + + /* XDE */ + case 2: + return &m_xde[m_regbank].d; + + /* XHL */ + case 3: + return &m_xhl[m_regbank].d; + + /* XIX */ + case 4: + return &m_xix.d; + + /* XIY */ + case 5: + return &m_xiy.d; + + /* XIZ */ + case 6: + return &m_xiz.d; + + /* XSP */ + case 7: + /* TODO: Add selector for user/system stack pointer */ + return &m_xssp.d; + } + /* keep compiler happy */ + return &m_dummy.d; +} + + +PAIR* tlcs900h_device::get_reg( UINT8 reg ) +{ + UINT8 regbank; + + switch( reg & 0xf0 ) + { + case 0x00: case 0x10: case 0x20: case 0x30: /* explicit register bank */ + case 0xd0: /* "previous" register bank */ + case 0xe0: /* current register bank */ + regbank = ( reg & 0xf0 ) >> 4; + if ( regbank == 0x0d ) + regbank = ( m_regbank - 1 ) & 0x03; + + if ( regbank == 0x0e ) + regbank = m_regbank; + + switch ( reg & 0x0c ) + { + case 0x00: return &m_xwa[regbank]; + case 0x04: return &m_xbc[regbank]; + case 0x08: return &m_xde[regbank]; + case 0x0c: return &m_xhl[regbank]; + } + break; + case 0xf0: /* index registers and sp */ + switch ( reg & 0x0c ) + { + case 0x00: return &m_xix; + case 0x04: return &m_xiy; + case 0x08: return &m_xiz; + /* TODO: Use correct SP */ + case 0x0c: return &m_xssp; + } + break; + } + + /* illegal/unknown register reference */ + logerror( "Access to unknown tlcs-900 cpu register %02x\n", reg ); + return &m_dummy; +} + + +UINT8* tlcs900h_device::get_reg8( UINT8 reg ) +{ + PAIR *r = get_reg( reg ); + + switch ( reg & 0x03 ) + { + case 0x00: return &r->b.l; + case 0x01: return &r->b.h; + case 0x02: return &r->b.h2; + case 0x03: return &r->b.h3; + } + + return &r->b.l; +} + + +UINT16* tlcs900h_device::get_reg16( UINT8 reg ) +{ + PAIR *r = get_reg( reg ); + + return ( reg & 0x02 ) ? &r->w.h : &r->w.l; +} + + +UINT32* tlcs900h_device::get_reg32( UINT8 reg ) +{ + PAIR *r = get_reg( reg ); + + return &r->d; +} + + + +void tlcs900h_device::parity8( UINT8 a ) +{ + int i, j; + + j = 0; + for ( i = 0; i < 8; i++ ) + { + if ( a & 1 ) j++; + a >>= 1; + } + m_sr.b.l |= ( ( j & 1 ) ? 0 : FLAG_VF ); +} + + +void tlcs900h_device::parity16( UINT16 a ) +{ + int i, j; + + j = 0; + for ( i = 0; i < 16; i++ ) + { + if ( a & 1 ) j++; + a >>= 1; + } + m_sr.b.l |= ( ( j & 1 ) ? 0 : FLAG_VF ); +} + + +void tlcs900h_device::parity32( UINT32 a ) +{ + int i, j; + + j = 0; + for ( i = 0; i < 32; i++ ) + { + if ( a & 1 ) j++; + a >>= 1; + } + m_sr.b.l |= ( ( j & 1 ) ? 0 : FLAG_VF ); +} + + +UINT8 tlcs900h_device::adc8( UINT8 a, UINT8 b) +{ + UINT8 cy = m_sr.b.l & FLAG_CF; + UINT8 result = a + b + cy; + + m_sr.b.l &= ~(FLAG_SF | FLAG_ZF | FLAG_HF | FLAG_VF | FLAG_NF | FLAG_CF); + m_sr.b.l |= ( result & FLAG_SF ) | ( result ? 0 : FLAG_ZF ) | + ( ( ( a ^ b ) ^ result ) & FLAG_HF ) | + ( ( ( result ^ a ) & ( result ^ b ) & 0x80 ) ? FLAG_VF : 0 ) | + ( ( ( result < a ) || ( ( result == a ) && cy ) ) ? FLAG_CF : 0 ); + + return result; +} + + +UINT16 tlcs900h_device::adc16( UINT16 a, UINT16 b) +{ + UINT8 cy = m_sr.b.l & FLAG_CF; + UINT16 result = a + b + cy; + + m_sr.b.l &= ~(FLAG_SF | FLAG_ZF | FLAG_HF | FLAG_VF | FLAG_NF | FLAG_CF); + m_sr.b.l |= ( ( result >> 8 ) & FLAG_SF ) | ( result ? 0 : FLAG_ZF ) | + ( ( ( a ^ b ) ^ result ) & FLAG_HF ) | + ( ( ( result ^ a ) & ( result ^ b ) & 0x8000 ) ? FLAG_VF : 0 ) | + ( ( ( result < a ) || ( ( result == a ) && cy ) ) ? FLAG_CF : 0 ); + + return result; +} + + +UINT32 tlcs900h_device::adc32( UINT32 a, UINT32 b) +{ + UINT8 cy = m_sr.b.l & FLAG_CF; + UINT32 result = a + b + cy; + + m_sr.b.l &= ~(FLAG_SF | FLAG_ZF | FLAG_HF | FLAG_VF | FLAG_NF | FLAG_CF); + m_sr.b.l |= ( ( result >> 24 ) & FLAG_SF ) | ( result ? 0 : FLAG_ZF ) | + ( ( ( result ^ a ) & ( result ^ b ) & 0x80000000 ) ? FLAG_VF : 0 ) | + ( ( ( result < a ) || ( ( result == a ) && cy ) ) ? FLAG_CF : 0 ); + + return result; +} + + +UINT8 tlcs900h_device::add8( UINT8 a, UINT8 b) +{ + UINT8 result = a + b; + + m_sr.b.l &= ~(FLAG_SF | FLAG_ZF | FLAG_HF | FLAG_VF | FLAG_NF | FLAG_CF); + m_sr.b.l |= ( result & FLAG_SF ) | ( result ? 0 : FLAG_ZF ) | + ( ( ( a ^ b ) ^ result ) & FLAG_HF ) | + ( ( ( result ^ a ) & ( result ^ b ) & 0x80 ) ? FLAG_VF : 0 ) | + ( ( result < a ) ? FLAG_CF : 0 ); + + return result; +} + + +UINT16 tlcs900h_device::add16( UINT16 a, UINT16 b) +{ + UINT16 result = a + b; + + m_sr.b.l &= ~(FLAG_SF | FLAG_ZF | FLAG_HF | FLAG_VF | FLAG_NF | FLAG_CF); + m_sr.b.l |= ( ( result >> 8 ) & FLAG_SF ) | ( result ? 0 : FLAG_ZF ) | + ( ( ( a ^ b ) ^ result ) & FLAG_HF ) | + ( ( ( result ^ a ) & ( result ^ b ) & 0x8000 ) ? FLAG_VF : 0 ) | + ( ( result < a ) ? FLAG_CF : 0 ); + + return result; +} + + +UINT32 tlcs900h_device::add32( UINT32 a, UINT32 b) +{ + UINT32 result = a + b; + + m_sr.b.l &= ~(FLAG_SF | FLAG_ZF | FLAG_HF | FLAG_VF | FLAG_NF | FLAG_CF); + m_sr.b.l |= ( ( result >> 24 ) & FLAG_SF ) | ( result ? 0 : FLAG_ZF ) | + ( ( ( result ^ a ) & ( result ^ b ) & 0x80000000 ) ? FLAG_VF : 0 ) | + ( ( result < a ) ? FLAG_CF : 0 ); + + return result; +} + + +UINT8 tlcs900h_device::sbc8( UINT8 a, UINT8 b) +{ + UINT8 cy = m_sr.b.l & FLAG_CF; + UINT8 result = a - b - cy; + + m_sr.b.l &= ~(FLAG_SF | FLAG_ZF | FLAG_HF | FLAG_VF | FLAG_CF); + m_sr.b.l |= ( result & FLAG_SF ) | ( result ? 0 : FLAG_ZF ) | + ( ( ( a ^ b ) ^ result ) & FLAG_HF ) | + ( ( ( result ^ a ) & ( a ^ b ) & 0x80 ) ? FLAG_VF : 0 ) | + ( ( ( result > a ) || ( cy && b == 0xFF ) ) ? FLAG_CF : 0 ) | FLAG_NF; + + return result; +} + + +UINT16 tlcs900h_device::sbc16( UINT16 a, UINT16 b) +{ + UINT8 cy = m_sr.b.l & FLAG_CF; + UINT16 result = a - b - cy; + + m_sr.b.l &= ~(FLAG_SF | FLAG_ZF | FLAG_HF | FLAG_VF | FLAG_CF); + m_sr.b.l |= ( ( result >> 8 ) & FLAG_SF ) | ( result ? 0 : FLAG_ZF ) | + ( ( ( a ^ b ) ^ result ) & FLAG_HF ) | + ( ( ( result ^ a ) & ( a ^ b ) & 0x8000 ) ? FLAG_VF : 0 ) | + ( ( ( result > a ) || ( cy && b == 0xFFFF ) ) ? FLAG_CF : 0 ) | FLAG_NF; + + return result; +} + + +UINT32 tlcs900h_device::sbc32( UINT32 a, UINT32 b) +{ + UINT8 cy = m_sr.b.l & FLAG_CF; + UINT32 result = a - b - cy; + + m_sr.b.l &= ~(FLAG_SF | FLAG_ZF | FLAG_HF | FLAG_VF | FLAG_CF); + m_sr.b.l |= ( ( result >> 24 ) & FLAG_SF ) | ( result ? 0 : FLAG_ZF ) | + ( ( ( result ^ a ) & ( a ^ b ) & 0x80000000 ) ? FLAG_VF : 0 ) | + ( ( ( result > a ) || ( cy && b == 0xFFFFFFFF ) ) ? FLAG_CF : 0 ) | FLAG_NF; + + return result; +} + + +UINT8 tlcs900h_device::sub8( UINT8 a, UINT8 b) +{ + UINT8 result = a - b; + + m_sr.b.l &= ~(FLAG_SF | FLAG_ZF | FLAG_HF | FLAG_VF | FLAG_CF); + m_sr.b.l |= ( result & FLAG_SF ) | ( result ? 0 : FLAG_ZF ) | + ( ( ( a ^ b ) ^ result ) & FLAG_HF ) | + ( ( ( result ^ a ) & ( a ^ b ) & 0x80 ) ? FLAG_VF : 0 ) | + ( ( result > a ) ? FLAG_CF : 0 ) | FLAG_NF; + + return result; +} + + +UINT16 tlcs900h_device::sub16( UINT16 a, UINT16 b) +{ + UINT16 result = a - b; + + m_sr.b.l &= ~(FLAG_SF | FLAG_ZF | FLAG_HF | FLAG_VF | FLAG_CF); + m_sr.b.l |= ( ( result >> 8 ) & FLAG_SF ) | ( result ? 0 : FLAG_ZF ) | + ( ( ( a ^ b ) ^ result ) & FLAG_HF ) | + ( ( ( result ^ a ) & ( a ^ b ) & 0x8000 ) ? FLAG_VF : 0 ) | + ( ( result > a ) ? FLAG_CF : 0 ) | FLAG_NF; + + return result; +} + + +UINT32 tlcs900h_device::sub32( UINT32 a, UINT32 b) +{ + UINT32 result = a - b; + + m_sr.b.l &= ~(FLAG_SF | FLAG_ZF | FLAG_HF | FLAG_VF | FLAG_CF); + m_sr.b.l |= ( ( result >> 24 ) & FLAG_SF ) | ( result ? 0 : FLAG_ZF ) | + ( ( ( result ^ a ) & ( a ^ b ) & 0x80000000 ) ? FLAG_VF : 0 ) | + ( ( result > a ) ? FLAG_CF : 0 ) | FLAG_NF; + + return result; +} + + +UINT8 tlcs900h_device::and8( UINT8 a, UINT8 b) +{ + UINT8 result = a & b; + + m_sr.b.l &= ~(FLAG_SF | FLAG_ZF | FLAG_HF | FLAG_VF | FLAG_NF | FLAG_CF); + m_sr.b.l |= ( result & FLAG_SF ) | ( result ? 0 : FLAG_ZF ) | FLAG_HF; + + parity8( result ); + + return result; +} + + +UINT16 tlcs900h_device::and16( UINT16 a, UINT16 b) +{ + UINT16 result = a & b; + + m_sr.b.l &= ~(FLAG_SF | FLAG_ZF | FLAG_HF | FLAG_VF | FLAG_NF | FLAG_CF); + m_sr.b.l |= ( ( result >> 8 ) & FLAG_SF ) | ( result ? 0 : FLAG_ZF ) | FLAG_HF; + + parity16( result ); + + return result; +} + + +UINT32 tlcs900h_device::and32( UINT32 a, UINT32 b) +{ + UINT32 result = a & b; + + m_sr.b.l &= ~(FLAG_SF | FLAG_ZF | FLAG_HF | FLAG_VF | FLAG_NF | FLAG_CF); + m_sr.b.l |= ( ( result >> 24 ) & FLAG_SF ) | ( result ? 0 : FLAG_ZF ) | FLAG_HF; + + return result; +} + + +UINT8 tlcs900h_device::or8( UINT8 a, UINT8 b) +{ + UINT8 result = a | b; + + m_sr.b.l &= ~(FLAG_SF | FLAG_ZF | FLAG_HF | FLAG_VF | FLAG_NF | FLAG_CF); + m_sr.b.l |= ( result & FLAG_SF ) | ( result ? 0 : FLAG_ZF ); + + parity8( result ); + + return result; +} + + +UINT16 tlcs900h_device::or16( UINT16 a, UINT16 b) +{ + UINT16 result = a | b; + + m_sr.b.l &= ~(FLAG_SF | FLAG_ZF | FLAG_HF | FLAG_VF | FLAG_NF | FLAG_CF); + m_sr.b.l |= ( ( result >> 8 ) & FLAG_SF ) | ( result ? 0 : FLAG_ZF ); + + parity16( result ); + + return result; +} + + +UINT32 tlcs900h_device::or32( UINT32 a, UINT32 b) +{ + UINT32 result = a | b; + + m_sr.b.l &= ~(FLAG_SF | FLAG_ZF | FLAG_HF | FLAG_VF | FLAG_NF | FLAG_CF); + m_sr.b.l |= ( ( result >> 24 ) & FLAG_SF ) | ( result ? 0 : FLAG_ZF ); + + return result; +} + + +UINT8 tlcs900h_device::xor8( UINT8 a, UINT8 b) +{ + UINT8 result = a ^ b; + + m_sr.b.l &= ~(FLAG_SF | FLAG_ZF | FLAG_HF | FLAG_VF | FLAG_NF | FLAG_CF); + m_sr.b.l |= ( result & FLAG_SF ) | ( result ? 0 : FLAG_ZF ); + + parity8( result ); + + return result; +} + + +UINT16 tlcs900h_device::xor16( UINT16 a, UINT16 b) +{ + UINT16 result = a ^ b; + + m_sr.b.l &= ~(FLAG_SF | FLAG_ZF | FLAG_HF | FLAG_VF | FLAG_NF | FLAG_CF); + m_sr.b.l |= ( ( result >> 8 ) & FLAG_SF ) | ( result ? 0 : FLAG_ZF ); + + parity16( result ); + + return result; +} + + +UINT32 tlcs900h_device::xor32( UINT32 a, UINT32 b) +{ + UINT32 result = a ^ b; + + m_sr.b.l &= ~(FLAG_SF | FLAG_ZF | FLAG_HF | FLAG_VF | FLAG_NF | FLAG_CF); + m_sr.b.l |= ( ( result >> 24 ) & FLAG_SF ) | ( result ? 0 : FLAG_ZF ); + + return result; +} + + +void tlcs900h_device::ldcf8( UINT8 a, UINT8 b ) +{ + if ( b & ( 1 << ( a & 0x07 ) ) ) + m_sr.b.l |= FLAG_CF; + else + m_sr.b.l &= ~ FLAG_CF; +} + + +void tlcs900h_device::ldcf16( UINT8 a, UINT8 b ) +{ + if ( b & ( 1 << ( a & 0x0f ) ) ) + m_sr.b.l |= FLAG_CF; + else + m_sr.b.l &= ~ FLAG_CF; +} + + +void tlcs900h_device::andcf8( UINT8 a, UINT8 b ) +{ + if ( ( b & ( 1 << ( a & 0x07 ) ) ) && ( m_sr.b.l & FLAG_CF ) ) + m_sr.b.l |= FLAG_CF; + else + m_sr.b.l &= ~ FLAG_CF; +} + + +void tlcs900h_device::andcf16( UINT8 a, UINT8 b ) +{ + if ( ( b & ( 1 << ( a & 0x0f ) ) ) && ( m_sr.b.l & FLAG_CF ) ) + m_sr.b.l |= FLAG_CF; + else + m_sr.b.l &= ~ FLAG_CF; +} + + +void tlcs900h_device::orcf8( UINT8 a, UINT8 b ) +{ + if ( b & ( 1 << ( a & 0x07 ) ) ) + m_sr.b.l |= FLAG_CF; +} + + +void tlcs900h_device::orcf16( UINT8 a, UINT8 b ) +{ + if ( b & ( 1 << ( a & 0x0f ) ) ) + m_sr.b.l |= FLAG_CF; +} + + +void tlcs900h_device::xorcf8( UINT8 a, UINT8 b ) +{ + if ( b & ( 1 << ( a & 0x07 ) ) ) + m_sr.b.l ^= FLAG_CF; +} + + +void tlcs900h_device::xorcf16( UINT8 a, UINT8 b ) +{ + if ( b & ( 1 << ( a & 0x0f ) ) ) + m_sr.b.l ^= FLAG_CF; +} + + +UINT8 tlcs900h_device::rl8( UINT8 a, UINT8 s ) +{ + UINT8 count = ( s & 0x0f ) ? ( s & 0x0f ) : 16; + + for ( ; count > 0; count-- ) + { + if ( a & 0x80 ) + { + a = ( a << 1 ) | ( m_sr.b.l & FLAG_CF ); + m_sr.b.l |= FLAG_CF; + } + else + { + a = ( a << 1 ) | ( m_sr.b.l & FLAG_CF ); + m_sr.b.l &= ~ FLAG_CF; + } + } + + m_sr.b.l &= ~ ( FLAG_SF | FLAG_ZF | FLAG_HF | FLAG_VF | FLAG_NF ); + m_sr.b.l |= ( a & FLAG_SF ) | ( a ? 0 : FLAG_ZF ); + parity8( a ); + + return a; +} + + +UINT16 tlcs900h_device::rl16( UINT16 a, UINT8 s ) +{ + UINT8 count = ( s & 0x0f ) ? ( s & 0x0f ) : 16; + + for ( ; count > 0; count-- ) + { + if ( a & 0x8000 ) + { + a = ( a << 1 ) | ( m_sr.b.l & FLAG_CF ); + m_sr.b.l |= FLAG_CF; + } + else + { + a = ( a << 1 ) | ( m_sr.b.l & FLAG_CF ); + m_sr.b.l &= ~ FLAG_CF; + } + } + + m_sr.b.l &= ~ ( FLAG_SF | FLAG_ZF | FLAG_HF | FLAG_VF | FLAG_NF ); + m_sr.b.l |= ( ( a >> 8 ) & FLAG_SF ) | ( a ? 0 : FLAG_ZF ); + parity16( a ); + + return a; +} + + +UINT32 tlcs900h_device::rl32( UINT32 a, UINT8 s ) +{ + UINT8 count = ( s & 0x0f ) ? ( s & 0x0f ) : 16; + + for ( ; count > 0; count-- ) + { + if ( a & 0x80000000 ) + { + a = ( a << 1 ) | ( m_sr.b.l & FLAG_CF ); + m_sr.b.l |= FLAG_CF; + } + else + { + a = ( a << 1 ) | ( m_sr.b.l & FLAG_CF ); + m_sr.b.l &= ~ FLAG_CF; + } + m_cycles += 2; + } + + m_sr.b.l &= ~ ( FLAG_SF | FLAG_ZF | FLAG_HF | FLAG_VF | FLAG_NF ); + m_sr.b.l |= ( ( a >> 24 ) & FLAG_SF ) | ( a ? 0 : FLAG_ZF ); + parity32( a ); + + return a; +} + +UINT8 tlcs900h_device::rlc8( UINT8 a, UINT8 s ) +{ + UINT8 count = ( s & 0x0f ) ? ( s & 0x0f ) : 16; + + for ( ; count > 0; count-- ) + { + a = ( a << 1 ) | ( ( a & 0x80 ) ? 1 : 0 ); + } + + m_sr.b.l &= ~ ( FLAG_SF | FLAG_ZF | FLAG_HF | FLAG_VF | FLAG_NF | FLAG_CF ); + m_sr.b.l |= ( a & FLAG_SF ) | ( a ? 0 : FLAG_ZF ) | ( a & FLAG_CF ); + parity8( a ); + + return a; +} + + +UINT16 tlcs900h_device::rlc16( UINT16 a, UINT8 s ) +{ + UINT8 count = ( s & 0x0f ) ? ( s & 0x0f ) : 16; + + for ( ; count > 0; count-- ) + { + a = ( a << 1 ) | ( ( a & 0x8000 ) ? 1 : 0 ); + } + + m_sr.b.l &= ~ ( FLAG_SF | FLAG_ZF | FLAG_HF | FLAG_VF | FLAG_NF | FLAG_CF ); + m_sr.b.l |= ( ( a >> 8 ) & FLAG_SF ) | ( a ? 0 : FLAG_ZF ) | ( a & FLAG_CF ); + parity16( a ); + + return a; +} + + +UINT32 tlcs900h_device::rlc32( UINT32 a, UINT8 s ) +{ + UINT8 count = ( s & 0x0f ) ? ( s & 0x0f ) : 16; + + for ( ; count > 0; count-- ) + { + a = ( a << 1 ) | ( ( a & 0x80000000 ) ? 1 : 0 ); + m_cycles += 2; + } + + m_sr.b.l &= ~ ( FLAG_SF | FLAG_ZF | FLAG_HF | FLAG_VF | FLAG_NF | FLAG_CF ); + m_sr.b.l |= ( ( a >> 24 ) & FLAG_SF ) | ( a ? 0 : FLAG_ZF ) | ( a & FLAG_CF ); + parity32( a ); + + return a; +} + + +UINT8 tlcs900h_device::rr8( UINT8 a, UINT8 s ) +{ + UINT8 count = ( s & 0x0f ) ? ( s & 0x0f ) : 16; + + for ( ; count > 0; count-- ) + { + if ( m_sr.b.l & FLAG_CF ) + { + m_sr.b.l = ( m_sr.b.l & ~ FLAG_CF ) | ( a & FLAG_CF ); + a = ( a >> 1 ) | 0x80; + } + else + { + m_sr.b.l = ( m_sr.b.l & ~ FLAG_CF ) | ( a & FLAG_CF ); + a = ( a >> 1 ); + } + } + + m_sr.b.l &= ~ ( FLAG_SF | FLAG_ZF | FLAG_HF | FLAG_VF | FLAG_NF ); + m_sr.b.l |= ( a & FLAG_SF ) | ( a ? 0 : FLAG_ZF ); + parity8( a ); + + return a; +} + + +UINT16 tlcs900h_device::rr16( UINT16 a, UINT8 s ) +{ + UINT8 count = ( s & 0x0f ) ? ( s & 0x0f ) : 16; + + for ( ; count > 0; count-- ) + { + if ( m_sr.b.l & FLAG_CF ) + { + m_sr.b.l = ( m_sr.b.l & ~ FLAG_CF ) | ( a & FLAG_CF ); + a = ( a >> 1 ) | 0x8000; + } + else + { + m_sr.b.l = ( m_sr.b.l & ~ FLAG_CF ) | ( a & FLAG_CF ); + a = ( a >> 1 ); + } + } + + m_sr.b.l &= ~ ( FLAG_SF | FLAG_ZF | FLAG_HF | FLAG_VF | FLAG_NF ); + m_sr.b.l |= ( ( a >> 8 ) & FLAG_SF ) | ( a ? 0 : FLAG_ZF ); + parity16( a ); + + return a; +} + + +UINT32 tlcs900h_device::rr32( UINT32 a, UINT8 s ) +{ + UINT8 count = ( s & 0x0f ) ? ( s & 0x0f ) : 16; + + for ( ; count > 0; count-- ) + { + if ( m_sr.b.l & FLAG_CF ) + { + m_sr.b.l = ( m_sr.b.l & ~ FLAG_CF ) | ( a & FLAG_CF ); + a = ( a >> 1 ) | 0x80000000; + } + else + { + m_sr.b.l = ( m_sr.b.l & ~ FLAG_CF ) | ( a & FLAG_CF ); + a = ( a >> 1 ); + } + m_cycles += 2; + } + + m_sr.b.l &= ~ ( FLAG_SF | FLAG_ZF | FLAG_HF | FLAG_VF | FLAG_NF ); + m_sr.b.l |= ( ( a >> 24 ) & FLAG_SF ) | ( a ? 0 : FLAG_ZF ); + parity32( a ); + + return a; +} + + +UINT8 tlcs900h_device::rrc8( UINT8 a, UINT8 s ) +{ + UINT8 count = ( s & 0x0f ) ? ( s & 0x0f ) : 16; + + for ( ; count > 0; count-- ) + { + a = ( a >> 1 ) | ( ( a & 0x01 ) ? 0x80 : 0 ); + } + + m_sr.b.l &= ~ ( FLAG_SF | FLAG_ZF | FLAG_HF | FLAG_VF | FLAG_NF | FLAG_CF ); + m_sr.b.l |= ( ( a & FLAG_SF ) ? FLAG_CF | FLAG_SF : 0 ) | ( a ? 0 : FLAG_ZF ); + parity8( a ); + + return a; +} + + +UINT16 tlcs900h_device::rrc16( UINT16 a, UINT8 s ) +{ + UINT8 count = ( s & 0x0f ) ? ( s & 0x0f ) : 16; + + for ( ; count > 0; count-- ) + { + a = ( a >> 1 ) | ( ( a & 0x0001 ) ? 0x8000 : 0 ); + } + + m_sr.b.l &= ~ ( FLAG_SF | FLAG_ZF | FLAG_HF | FLAG_VF | FLAG_NF | FLAG_CF ); + m_sr.b.l |= ( ( ( a >> 8 ) & FLAG_SF ) ? FLAG_CF | FLAG_SF : 0 ) | ( a ? 0 : FLAG_ZF ); + parity16( a ); + + return a; +} + + +UINT32 tlcs900h_device::rrc32( UINT32 a, UINT8 s ) +{ + UINT8 count = ( s & 0x0f ) ? ( s & 0x0f ) : 16; + + for ( ; count > 0; count-- ) + { + a = ( a >> 1 ) | ( ( a & 0x00000001 ) ? 0x80000000 : 0 ); + m_cycles += 2; + } + + m_sr.b.l &= ~ ( FLAG_SF | FLAG_ZF | FLAG_HF | FLAG_VF | FLAG_NF | FLAG_CF ); + m_sr.b.l |= ( ( ( a >> 24 ) & FLAG_SF ) ? FLAG_CF | FLAG_SF : 0 ) | ( a ? 0 : FLAG_ZF ); + parity32( a ); + + return a; +} + + +UINT8 tlcs900h_device::sla8( UINT8 a, UINT8 s ) +{ + UINT8 count = ( s & 0x0f ) ? ( s & 0x0f ) : 16; + + for ( ; count > 0; count-- ) + { + m_sr.b.l = ( m_sr.b.l & ~ FLAG_CF ) | ( ( a & 0x80 ) ? FLAG_CF : 0 ); + a = ( a << 1 ); + } + + m_sr.b.l &= ~ ( FLAG_SF | FLAG_ZF | FLAG_HF | FLAG_VF | FLAG_NF ); + m_sr.b.l |= ( a & FLAG_SF ) | ( a ? 0 : FLAG_ZF ); + parity8( a ); + + return a; +} + + +UINT16 tlcs900h_device::sla16( UINT16 a, UINT8 s ) +{ + UINT8 count = ( s & 0x0f ) ? ( s & 0x0f ) : 16; + + for ( ; count > 0; count-- ) + { + m_sr.b.l = ( m_sr.b.l & ~ FLAG_CF ) | ( ( a & 0x8000 ) ? FLAG_CF : 0 ); + a = ( a << 1 ); + } + + m_sr.b.l &= ~ ( FLAG_SF | FLAG_ZF | FLAG_HF | FLAG_VF | FLAG_NF ); + m_sr.b.l |= ( ( a >> 8 ) & FLAG_SF ) | ( a ? 0 : FLAG_ZF ); + parity16( a ); + + return a; +} + + +UINT32 tlcs900h_device::sla32( UINT32 a, UINT8 s ) +{ + UINT8 count = ( s & 0x0f ) ? ( s & 0x0f ) : 16; + + for ( ; count > 0; count-- ) + { + m_sr.b.l = ( m_sr.b.l & ~ FLAG_CF ) | ( ( a & 0x80000000 ) ? FLAG_CF : 0 ); + a = ( a << 1 ); + m_cycles += 2; + } + + m_sr.b.l &= ~ ( FLAG_SF | FLAG_ZF | FLAG_HF | FLAG_VF | FLAG_NF ); + m_sr.b.l |= ( ( a >> 24 ) & FLAG_SF ) | ( a ? 0 : FLAG_ZF ); + parity32( a ); + + return a; +} + + +UINT8 tlcs900h_device::sra8( UINT8 a, UINT8 s ) +{ + UINT8 count = ( s & 0x0f ) ? ( s & 0x0f ) : 16; + + for ( ; count > 0; count-- ) + { + m_sr.b.l = ( m_sr.b.l & ~ FLAG_CF ) | ( a & FLAG_CF ); + a = ( a & 0x80 ) | ( a >> 1 ); + } + + m_sr.b.l &= ~ ( FLAG_SF | FLAG_ZF | FLAG_HF | FLAG_VF | FLAG_NF ); + m_sr.b.l |= ( a & FLAG_SF ) | ( a ? 0 : FLAG_ZF ); + parity8( a ); + + return a; +} + + +UINT16 tlcs900h_device::sra16( UINT16 a, UINT8 s ) +{ + UINT8 count = ( s & 0x0f ) ? ( s & 0x0f ) : 16; + + for ( ; count > 0; count-- ) + { + m_sr.b.l = ( m_sr.b.l & ~ FLAG_CF ) | ( a & FLAG_CF ); + a = ( a & 0x8000 ) | ( a >> 1 ); + } + + m_sr.b.l &= ~ ( FLAG_SF | FLAG_ZF | FLAG_HF | FLAG_VF | FLAG_NF ); + m_sr.b.l |= ( ( a >> 8 ) & FLAG_SF ) | ( a ? 0 : FLAG_ZF ); + parity16( a ); + + return a; +} + + +UINT32 tlcs900h_device::sra32( UINT32 a, UINT8 s ) +{ + UINT8 count = ( s & 0x0f ) ? ( s & 0x0f ) : 16; + + for ( ; count > 0; count-- ) + { + m_sr.b.l = ( m_sr.b.l & ~ FLAG_CF ) | ( a & FLAG_CF ); + a = ( a & 0x80000000 ) | ( a >> 1 ); + m_cycles += 2; + } + + m_sr.b.l &= ~ ( FLAG_SF | FLAG_ZF | FLAG_HF | FLAG_VF | FLAG_NF ); + m_sr.b.l |= ( ( a >> 24 ) & FLAG_SF ) | ( a ? 0 : FLAG_ZF ); + parity32( a ); + + return a; +} + + +UINT8 tlcs900h_device::srl8( UINT8 a, UINT8 s ) +{ + UINT8 count = ( s & 0x0f ) ? ( s & 0x0f ) : 16; + + for ( ; count > 0; count-- ) + { + m_sr.b.l = ( m_sr.b.l & ~ FLAG_CF ) | ( a & FLAG_CF ); + a = ( a >> 1 ); + } + + m_sr.b.l &= ~ ( FLAG_SF | FLAG_ZF | FLAG_HF | FLAG_VF | FLAG_NF ); + m_sr.b.l |= ( a & FLAG_SF ) | ( a ? 0 : FLAG_ZF ); + parity8( a ); + + return a; +} + + +UINT16 tlcs900h_device::srl16( UINT16 a, UINT8 s ) +{ + UINT8 count = ( s & 0x0f ) ? ( s & 0x0f ) : 16; + + for ( ; count > 0; count-- ) + { + m_sr.b.l = ( m_sr.b.l & ~ FLAG_CF ) | ( a & FLAG_CF ); + a = ( a >> 1 ); + } + + m_sr.b.l &= ~ ( FLAG_SF | FLAG_ZF | FLAG_HF | FLAG_VF | FLAG_NF ); + m_sr.b.l |= ( ( a >> 8 ) & FLAG_SF ) | ( a ? 0 : FLAG_ZF ); + parity16( a ); + + return a; +} + + +UINT32 tlcs900h_device::srl32( UINT32 a, UINT8 s ) +{ + UINT8 count = ( s & 0x0f ) ? ( s & 0x0f ) : 16; + + for ( ; count > 0; count-- ) + { + m_sr.b.l = ( m_sr.b.l & ~ FLAG_CF ) | ( a & FLAG_CF ); + a = ( a >> 1 ); + m_cycles += 2; + } + + m_sr.b.l &= ~ ( FLAG_SF | FLAG_ZF | FLAG_HF | FLAG_VF | FLAG_NF ); + m_sr.b.l |= ( ( a >> 24 ) & FLAG_SF ) | ( a ? 0 : FLAG_ZF ); + parity32( a ); + + return a; +} + + +UINT16 tlcs900h_device::div8( UINT16 a, UINT8 b ) +{ + ldiv_t result; + + if ( !b ) + { + m_sr.b.l |= FLAG_VF; + return ( a << 8 ) | ( ( a >> 8 ) ^ 0xff ); + } + + if ( a >= ( 0x0200 * b ) ) { + UINT16 diff = a - ( 0x0200 * b ); + UINT16 range = 0x100 - b; + + result = ldiv( diff, range ); + result.quot = 0x1ff - result.quot; + result.rem = result.rem + b; + } + else + { + result = ldiv( a, b ); + } + + if ( result.quot > 0xff ) + m_sr.b.l |= FLAG_VF; + else + m_sr.b.l &= ~ FLAG_VF; + + return ( result.quot & 0xff ) | ( ( result.rem & 0xff ) << 8 ); +} + + +UINT32 tlcs900h_device::div16( UINT32 a, UINT16 b ) +{ + ldiv_t result; + + if ( !b ) + { + m_sr.b.l |= FLAG_VF; + return ( a << 16 ) | ( ( a >> 16 ) ^ 0xffff ); + } + +// if ( a >= ( 0x02000000 * b ) ) { +// UINT32 diff = a - ( 0x02000000 * b ); +// UINT32 range = 0x1000000 - b; +// +// result = ldiv( diff, range ); +// result.quot = 0x1ffffff - result.quot; +// result.rem = result.rem + b; +// } +// else +// { + result = ldiv( a, b ); +// } + + if ( result.quot > 0xffff ) + m_sr.b.l |= FLAG_VF; + else + m_sr.b.l &= ~ FLAG_VF; + + return ( result.quot & 0xffff ) | ( ( result.rem & 0xffff ) << 16 ); +} + + +UINT16 tlcs900h_device::divs8( INT16 a, INT8 b ) +{ + ldiv_t result; + + if ( !b ) + { + m_sr.b.l |= FLAG_VF; + return ( a << 8 ) | ( ( a >> 8 ) ^ 0xff ); + } + + result = ldiv( a, b ); + + if ( result.quot > 0xff ) + m_sr.b.l |= FLAG_VF; + else + m_sr.b.l &= ~ FLAG_VF; + + return ( result.quot & 0xff ) | ( ( result.rem & 0xff ) << 8 ); +} + + +UINT32 tlcs900h_device::divs16( INT32 a, INT16 b ) +{ + ldiv_t result; + + if ( !b ) + { + m_sr.b.l |= FLAG_VF; + return ( a << 16 ) | ( ( a >> 16 ) ^ 0xffff ); + } + + result = ldiv( a, b ); + + if ( result.quot > 0xffff ) + m_sr.b.l |= FLAG_VF; + else + m_sr.b.l &= ~ FLAG_VF; + + return ( result.quot & 0xffff ) | ( ( result.rem & 0xffff ) << 16 ); +} + + +void tlcs900h_device::_ADCBMI() +{ + WRMEM( m_ea1.d, adc8( RDMEM( m_ea1.d ), m_imm2.b.l ) ); +} + + +void tlcs900h_device::_ADCBMR() +{ + WRMEM( m_ea1.d, adc8( RDMEM( m_ea1.d ), *m_p2_reg8 ) ); +} + + +void tlcs900h_device::_ADCBRI() +{ + *m_p1_reg8 = adc8( *m_p1_reg8, m_imm2.b.l ); +} + + +void tlcs900h_device::_ADCBRM() +{ + *m_p1_reg8 = adc8( *m_p1_reg8, RDMEM( m_ea2.d ) ); +} + + +void tlcs900h_device::_ADCBRR() +{ + *m_p1_reg8 = adc8( *m_p1_reg8, *m_p2_reg8 ); +} + + +void tlcs900h_device::_ADCWMI() +{ + WRMEMW( m_ea1.d, adc16( RDMEMW( m_ea1.d ), m_imm2.w.l ) ); +} + + +void tlcs900h_device::_ADCWMR() +{ + WRMEMW( m_ea1.d, adc16( RDMEMW( m_ea1.d ), *m_p2_reg16 ) ); +} + + +void tlcs900h_device::_ADCWRI() +{ + *m_p1_reg16 = adc16( *m_p1_reg16, m_imm2.w.l ); +} + + +void tlcs900h_device::_ADCWRM() +{ + *m_p1_reg16 = adc16( *m_p1_reg16, RDMEMW( m_ea2.d ) ); +} + + +void tlcs900h_device::_ADCWRR() +{ + *m_p1_reg16 = adc16( *m_p1_reg16, *m_p2_reg16 ); +} + + +void tlcs900h_device::_ADCLMR() +{ + WRMEML( m_ea1.d, adc32( RDMEML( m_ea1.d ), *m_p2_reg32 ) ); +} + + +void tlcs900h_device::_ADCLRI() +{ + *m_p1_reg32 = adc32( *m_p1_reg32, m_imm2.d ); +} + + +void tlcs900h_device::_ADCLRM() +{ + *m_p1_reg32 = adc32( *m_p1_reg32, RDMEML( m_ea2.d ) ); +} + + +void tlcs900h_device::_ADCLRR() +{ + *m_p1_reg32 = adc32( *m_p1_reg32, *m_p2_reg32 ); +} + + +void tlcs900h_device::_ADDBMI() +{ + WRMEM( m_ea1.d, add8( RDMEM( m_ea1.d ), m_imm2.b.l ) ); +} + + +void tlcs900h_device::_ADDBMR() +{ + WRMEM( m_ea1.d, add8( RDMEM( m_ea1.d ), *m_p2_reg8 ) ); +} + + +void tlcs900h_device::_ADDBRI() +{ + *m_p1_reg8 = add8( *m_p1_reg8, m_imm2.b.l ); +} + + +void tlcs900h_device::_ADDBRM() +{ + *m_p1_reg8 = add8( *m_p1_reg8, RDMEM( m_ea2.d ) ); +} + + +void tlcs900h_device::_ADDBRR() +{ + *m_p1_reg8 = add8( *m_p1_reg8, *m_p2_reg8 ); +} + + +void tlcs900h_device::_ADDWMI() +{ + WRMEMW( m_ea1.d, add16( RDMEMW( m_ea1.d ), m_imm2.w.l ) ); +} + + +void tlcs900h_device::_ADDWMR() +{ + WRMEMW( m_ea1.d, add16( RDMEMW( m_ea1.d ), *m_p2_reg16 ) ); +} + + +void tlcs900h_device::_ADDWRI() +{ + *m_p1_reg16 = add16( *m_p1_reg16, m_imm2.w.l ); +} + + +void tlcs900h_device::_ADDWRM() +{ + *m_p1_reg16 = add16( *m_p1_reg16, RDMEMW( m_ea2.d ) ); +} + + +void tlcs900h_device::_ADDWRR() +{ + *m_p1_reg16 = add16( *m_p1_reg16, *m_p2_reg16 ); +} + + +void tlcs900h_device::_ADDLMR() +{ + WRMEML( m_ea1.d, add32( RDMEML( m_ea1.d ), *m_p2_reg32 ) ); +} + + +void tlcs900h_device::_ADDLRI() +{ + *m_p1_reg32 = add32( *m_p1_reg32, m_imm2.d ); +} + + +void tlcs900h_device::_ADDLRM() +{ + *m_p1_reg32 = add32( *m_p1_reg32, RDMEML( m_ea2.d ) ); +} + + +void tlcs900h_device::_ADDLRR() +{ + *m_p1_reg32 = add32( *m_p1_reg32, *m_p2_reg32 ); +} + + +void tlcs900h_device::_ANDBMI() +{ + WRMEM( m_ea1.d, and8( RDMEM( m_ea1.d ), m_imm2.b.l ) ); +} + + +void tlcs900h_device::_ANDBMR() +{ + WRMEM( m_ea1.d, and8( RDMEM( m_ea1.d ), *m_p2_reg8 ) ); +} + + +void tlcs900h_device::_ANDBRI() +{ + *m_p1_reg8 = and8( *m_p1_reg8, m_imm2.b.l ); +} + + +void tlcs900h_device::_ANDBRM() +{ + *m_p1_reg8 = and8( *m_p1_reg8, RDMEM( m_ea2.d ) ); +} + + +void tlcs900h_device::_ANDBRR() +{ + *m_p1_reg8 = and8( *m_p1_reg8, *m_p2_reg8 ); +} + + +void tlcs900h_device::_ANDWMI() +{ + WRMEMW( m_ea1.d, and16( RDMEMW( m_ea1.d ), m_imm2.w.l ) ); +} + + +void tlcs900h_device::_ANDWMR() +{ + WRMEMW( m_ea1.d, and16( RDMEMW( m_ea1.d ), *m_p2_reg16 ) ); +} + + +void tlcs900h_device::_ANDWRI() +{ + *m_p1_reg16 = and16( *m_p1_reg16, m_imm2.w.l ); +} + + +void tlcs900h_device::_ANDWRM() +{ + *m_p1_reg16 = and16( *m_p1_reg16, RDMEMW( m_ea2.d ) ); +} + + +void tlcs900h_device::_ANDWRR() +{ + *m_p1_reg16 = and16( *m_p1_reg16, *m_p2_reg16 ); +} + + +void tlcs900h_device::_ANDLMR() +{ + WRMEML( m_ea1.d, and32( RDMEML( m_ea1.d ), *m_p2_reg32 ) ); +} + + +void tlcs900h_device::_ANDLRI() +{ + *m_p1_reg32 = and32( *m_p1_reg32, m_imm2.d ); +} + + +void tlcs900h_device::_ANDLRM() +{ + *m_p1_reg32 = and32( *m_p1_reg32, RDMEML( m_ea2.d ) ); +} + + +void tlcs900h_device::_ANDLRR() +{ + *m_p1_reg32 = and32( *m_p1_reg32, *m_p2_reg32 ); +} + + +void tlcs900h_device::_ANDCFBIM() +{ + andcf8( m_imm1.b.l, RDMEM( m_ea2.d ) ); +} + + +void tlcs900h_device::_ANDCFBIR() +{ + andcf8( m_imm1.b.l, *m_p2_reg8 ); +} + + +void tlcs900h_device::_ANDCFBRM() +{ + andcf8( *m_p1_reg8, RDMEM( m_ea2.d ) ); +} + + +void tlcs900h_device::_ANDCFBRR() +{ + andcf8( *m_p1_reg8, *m_p2_reg8 ); +} + + +void tlcs900h_device::_ANDCFWIR() +{ + andcf16( m_imm1.b.l, *m_p2_reg16 ); +} + + +void tlcs900h_device::_ANDCFWRR() +{ + andcf16( *m_p1_reg8, *m_p2_reg16 ); +} + + +void tlcs900h_device::_BITBIM() +{ + m_sr.b.l &= ~ ( FLAG_ZF | FLAG_NF ); + if ( RDMEM( m_ea2.d ) & ( 1 << ( m_imm1.b.l & 0x07 ) ) ) + m_sr.b.l |= FLAG_HF; + else + m_sr.b.l |= FLAG_HF | FLAG_ZF; +} + + +void tlcs900h_device::_BITBIR() +{ + m_sr.b.l &= ~ ( FLAG_ZF | FLAG_NF ); + if ( *m_p2_reg8 & ( 1 << ( m_imm1.b.l & 0x0f ) ) ) + m_sr.b.l |= FLAG_HF; + else + m_sr.b.l |= FLAG_HF | FLAG_ZF; +} + + +void tlcs900h_device::_BITWIR() +{ + m_sr.b.l &= ~ ( FLAG_ZF | FLAG_NF ); + if ( *m_p2_reg16 & ( 1 << ( m_imm1.b.l & 0x0f ) ) ) + m_sr.b.l |= FLAG_HF; + else + m_sr.b.l |= FLAG_HF | FLAG_ZF; +} + + +void tlcs900h_device::_BS1BRR() +{ + UINT16 r = *m_p2_reg16; + + if ( r ) + { + m_sr.b.l &= ~ FLAG_VF; + *m_p1_reg8 = 15; + while( r < 0x8000 ) + { + r <<= 1; + *m_p1_reg8 -= 1; + } + } + else + m_sr.b.l |= FLAG_VF; +} + + +void tlcs900h_device::_BS1FRR() +{ + UINT16 r = *m_p2_reg16; + + if ( r ) + { + m_sr.b.l &= ~ FLAG_VF; + *m_p1_reg8 = 0; + while( ! ( r & 0x0001 ) ) + { + r >>= 1; + *m_p1_reg8 += 1; + } + } + else + m_sr.b.l |= FLAG_VF; +} + + +void tlcs900h_device::_CALLI() +{ + m_xssp.d -= 4; + WRMEML( m_xssp.d, m_pc.d ); + m_pc.d = m_imm1.d; + m_prefetch_clear = true; +} + + +void tlcs900h_device::_CALLM() +{ + if ( condition_true( m_op ) ) + { + m_xssp.d -= 4; + WRMEML( m_xssp.d, m_pc.d ); + m_pc.d = m_ea2.d; + m_cycles += 6; + m_prefetch_clear = true; + } +} + + +void tlcs900h_device::_CALR() +{ + m_xssp.d -= 4; + WRMEML( m_xssp.d, m_pc.d ); + m_pc.d = m_ea1.d; + m_prefetch_clear = true; +} + + +void tlcs900h_device::_CCF() +{ + m_sr.b.l &= ~ FLAG_NF; + m_sr.b.l ^= FLAG_CF; +} + + +void tlcs900h_device::_CHGBIM() +{ + WRMEM( m_ea2.d, RDMEM( m_ea2.d ) ^ ( 1 << ( m_imm1.b.l & 0x07 ) ) ); +} + + +void tlcs900h_device::_CHGBIR() +{ + *m_p2_reg8 ^= ( 1 << ( m_imm1.b.l & 0x07 ) ); +} + + +void tlcs900h_device::_CHGWIR() +{ + *m_p2_reg16 ^= ( 1 << ( m_imm1.b.l & 0x0f ) ); +} + + +void tlcs900h_device::_CPBMI() +{ + sub8( RDMEM( m_ea1.d ), m_imm2.b.l ); +} + + +void tlcs900h_device::_CPBMR() +{ + sub8( RDMEM( m_ea1.d ), *m_p2_reg8 ); +} + + +void tlcs900h_device::_CPBRI() +{ + sub8( *m_p1_reg8, m_imm2.b.l ); +} + + +void tlcs900h_device::_CPBRM() +{ + sub8( *m_p1_reg8, RDMEM( m_ea2.d ) ); +} + + +void tlcs900h_device::_CPBRR() +{ + sub8( *m_p1_reg8, *m_p2_reg8 ); +} + + +void tlcs900h_device::_CPWMI() +{ + sub16( RDMEMW( m_ea1.d ), m_imm2.w.l ); +} + + +void tlcs900h_device::_CPWMR() +{ + sub16( RDMEMW( m_ea1.d ), *m_p2_reg16 ); +} + + +void tlcs900h_device::_CPWRI() +{ + sub16( *m_p1_reg16, m_imm2.w.l ); +} + + +void tlcs900h_device::_CPWRM() +{ + sub16( *m_p1_reg16, RDMEMW( m_ea2.d ) ); +} + + +void tlcs900h_device::_CPWRR() +{ + sub16( *m_p1_reg16, *m_p2_reg16 ); +} + + +void tlcs900h_device::_CPLMR() +{ + sub32( RDMEML( m_ea1.d ), *m_p2_reg32 ); +} + + +void tlcs900h_device::_CPLRI() +{ + sub32( *m_p1_reg32, m_imm2.d ); +} + + +void tlcs900h_device::_CPLRM() +{ + sub32( *m_p1_reg32, RDMEML( m_ea2.d ) ); +} + + +void tlcs900h_device::_CPLRR() +{ + sub32( *m_p1_reg32, *m_p2_reg32 ); +} + + +void tlcs900h_device::_CPD() +{ + UINT8 result = *get_reg8_current( 1 ) - RDMEM( *m_p2_reg32 ); + UINT16 *bc = get_reg16_current( 1 ); + + *m_p2_reg32 -= 1; + *bc -= 1; + m_sr.b.l &= ~ ( FLAG_SF | FLAG_ZF | FLAG_HF | FLAG_VF ); + m_sr.b.l |= ( result & FLAG_SF ) | ( result ? FLAG_NF : FLAG_NF | FLAG_ZF ) | + ( *bc ? FLAG_VF : 0 ); +} + + +void tlcs900h_device::_CPDR() +{ + _CPD(); + + if ( ( m_sr.b.l & ( FLAG_ZF | FLAG_VF ) ) == FLAG_VF ) + { + m_pc.d -= 2; + m_cycles += 4; + m_prefetch_clear = true; + } +} + + +void tlcs900h_device::_CPDW() +{ + UINT16 result = *get_reg16_current( 0 ) - RDMEMW( *m_p2_reg32 ); + UINT16 *bc = get_reg16_current( 1 ); + + *m_p2_reg32 -= 2; + *bc -= 1; + m_sr.b.l &= ~ ( FLAG_SF | FLAG_ZF | FLAG_HF | FLAG_VF ); + m_sr.b.l |= ( ( result >> 8 ) & FLAG_SF ) | ( result ? FLAG_NF : FLAG_NF | FLAG_ZF ) | + ( *bc ? FLAG_VF : 0 ); +} + + +void tlcs900h_device::_CPDRW() +{ + _CPDW(); + + if ( ( m_sr.b.l & ( FLAG_ZF | FLAG_VF ) ) == FLAG_VF ) + { + m_pc.d -= 2; + m_cycles += 4; + m_prefetch_clear = true; + } +} + + +void tlcs900h_device::_CPI() +{ + UINT8 result = *get_reg8_current( 1 ) - RDMEM( *m_p2_reg32 ); + UINT16 *bc = get_reg16_current( 1 ); + + *m_p2_reg32 += 1; + *bc -= 1; + m_sr.b.l &= ~ ( FLAG_SF | FLAG_ZF | FLAG_HF | FLAG_VF ); + m_sr.b.l |= ( result & FLAG_SF ) | ( result ? FLAG_NF : FLAG_NF | FLAG_ZF ) | + ( *bc ? FLAG_VF : 0 ); +} + + +void tlcs900h_device::_CPIR() +{ + _CPI(); + + if ( ( m_sr.b.l & ( FLAG_ZF | FLAG_VF ) ) == FLAG_VF ) + { + m_pc.d -= 2; + m_cycles += 4; + m_prefetch_clear = true; + } +} + + +void tlcs900h_device::_CPIW() +{ + UINT16 result = *get_reg16_current( 0 ) - RDMEMW( *m_p2_reg32 ); + UINT16 *bc = get_reg16_current( 1 ); + + *m_p2_reg32 += 2; + *bc -= 1; + m_sr.b.l &= ~ ( FLAG_SF | FLAG_ZF | FLAG_HF | FLAG_VF ); + m_sr.b.l |= ( ( result >> 8 ) & FLAG_SF ) | ( result ? FLAG_NF : FLAG_NF | FLAG_ZF ) | + ( *bc ? FLAG_VF : 0 ); +} + + +void tlcs900h_device::_CPIRW() +{ + _CPIW(); + + if ( ( m_sr.b.l & ( FLAG_ZF | FLAG_VF ) ) == FLAG_VF ) + { + m_pc.d -= 2; + m_cycles += 4; + m_prefetch_clear = true; + } +} + + +void tlcs900h_device::_CPLBR() +{ + *m_p1_reg8 = ~ *m_p1_reg8; + m_sr.b.l |= FLAG_HF | FLAG_NF; +} + + +void tlcs900h_device::_CPLWR() +{ + *m_p1_reg16 = ~ *m_p1_reg16; + m_sr.b.l |= FLAG_HF | FLAG_NF; +} + + +void tlcs900h_device::_DAABR() +{ + UINT8 oldval = *m_p1_reg8; + UINT8 fixval = 0; + UINT8 carry = 0; + UINT8 high = *m_p1_reg8 & 0xf0; + UINT8 low = *m_p1_reg8 & 0x0f; + + if ( m_sr.b.l & FLAG_CF ) + { + if ( m_sr.b.l & FLAG_HF ) + { + fixval = 0x66; + } + else + { + if ( low < 0x0a ) + fixval = 0x60; + else + fixval = 0x66; + } + carry = 1; + } + else + { + if ( m_sr.b.l & FLAG_HF ) + { + if ( *m_p1_reg8 < 0x9a ) + fixval = 0x06; + else + fixval = 0x66; + } + else + { + if ( high < 0x90 && low > 0x09 ) + fixval = 0x06; + else if ( high > 0x80 && low > 0x09 ) + fixval = 0x66; + else if ( high > 0x90 && low < 0x0a ) + fixval = 0x60; + } + } + m_sr.b.l &= ~ ( FLAG_VF | FLAG_SF | FLAG_ZF | FLAG_HF | FLAG_CF ); + if ( m_sr.b.l & FLAG_NF ) + { + /* after SUB, SBC, or NEG operation */ + *m_p1_reg8 -= fixval; + m_sr.b.l |= ( ( *m_p1_reg8 > oldval || carry ) ? FLAG_CF : 0 ); + } + else + { + /* after ADD or ADC operation */ + *m_p1_reg8 += fixval; + m_sr.b.l |= ( ( *m_p1_reg8 < oldval || carry ) ? FLAG_CF : 0 ); + } + m_sr.b.l |= ( *m_p1_reg8 & FLAG_SF ) | ( *m_p1_reg8 ? 0 : FLAG_ZF ) | + ( ( ( oldval ^ fixval ) ^ *m_p1_reg8 ) & FLAG_HF ); + + parity8( *m_p1_reg8 ); +} + + +void tlcs900h_device::_DB() +{ + logerror("%08x: invalid or illegal instruction\n", m_pc.d ); +} + + +void tlcs900h_device::_DECBIM() +{ + UINT8 cy = m_sr.b.l & FLAG_CF; + + WRMEM( m_ea2.d, sub8( RDMEM( m_ea2.d ), m_imm1.b.l ? m_imm1.b.l : 8 ) ); + m_sr.b.l = ( m_sr.b.l & ~ FLAG_CF ) | cy; +} + + +void tlcs900h_device::_DECBIR() +{ + UINT8 cy = m_sr.b.l & FLAG_CF; + + *m_p2_reg8 = sub8( *m_p2_reg8, m_imm1.b.l ? m_imm1.b.l : 8 ); + m_sr.b.l = ( m_sr.b.l & ~ FLAG_CF ) | cy; +} + + +void tlcs900h_device::_DECWIM() +{ + UINT8 cy = m_sr.b.l & FLAG_CF; + + WRMEMW( m_ea2.d, sub16( RDMEMW( m_ea2.d ), m_imm1.b.l ? m_imm1.b.l : 8 ) ); + m_sr.b.l = ( m_sr.b.l & ~ FLAG_CF ) | cy; +} + + +void tlcs900h_device::_DECWIR() +{ + *m_p2_reg16 -= m_imm1.b.l ? m_imm1.b.l : 8; +} + + +void tlcs900h_device::_DECLIR() +{ + *m_p2_reg32 -= m_imm1.b.l ? m_imm1.b.l : 8; +} + + +void tlcs900h_device::_DECF() +{ + /* 0x03 for MAX mode, 0x07 for MIN mode */ + m_sr.b.h = ( m_sr.b.h & 0xf8 ) | ( ( m_sr.b.h - 1 ) & 0x07 ); + m_regbank = m_sr.b.h & 0x03; +} + + +void tlcs900h_device::_DIVBRI() +{ + *m_p1_reg16 = div8( *m_p1_reg16, m_imm2.b.l ); +} + + +void tlcs900h_device::_DIVBRM() +{ + *m_p1_reg16 = div8( *m_p1_reg16, RDMEM( m_ea2.d ) ); +} + + +void tlcs900h_device::_DIVBRR() +{ + *m_p1_reg16 = div8( *m_p1_reg16, *m_p2_reg8 ); +} + + +void tlcs900h_device::_DIVWRI() +{ + *m_p1_reg32 = div16( *m_p1_reg32, m_imm2.w.l ); +} + + +void tlcs900h_device::_DIVWRM() +{ + *m_p1_reg32 = div16( *m_p1_reg32, RDMEMW( m_ea2.d ) ); +} + + +void tlcs900h_device::_DIVWRR() +{ + *m_p1_reg32 = div16( *m_p1_reg32, *m_p2_reg16 ); +} + + +void tlcs900h_device::_DIVSBRI() +{ + *m_p1_reg16 = divs8( *m_p1_reg16, m_imm2.b.l ); +} + + +void tlcs900h_device::_DIVSBRM() +{ + *m_p1_reg16 = divs8( *m_p1_reg16, RDMEM( m_ea2.d ) ); +} + + +void tlcs900h_device::_DIVSBRR() +{ + *m_p1_reg16 = divs8( *m_p1_reg16, *m_p2_reg8 ); +} + + +void tlcs900h_device::_DIVSWRI() +{ + *m_p1_reg32 = divs16( *m_p1_reg32, m_imm2.w.l ); +} + + +void tlcs900h_device::_DIVSWRM() +{ + *m_p1_reg32 = divs16( *m_p1_reg32, RDMEMW( m_ea2.d ) ); +} + + +void tlcs900h_device::_DIVSWRR() +{ + *m_p1_reg32 = divs16( *m_p1_reg32, *m_p2_reg16 ); +} + + +void tlcs900h_device::_DJNZB() +{ + *m_p1_reg8 -= 1; + if ( *m_p1_reg8 ) + { + m_pc.d = m_ea2.d; + m_cycles += 4; + m_prefetch_clear = true; + } +} + + +void tlcs900h_device::_DJNZW() +{ + *m_p1_reg16 -= 1; + if ( *m_p1_reg16 ) + { + m_pc.d = m_ea2.d; + m_cycles += 4; + m_prefetch_clear = true; + } +} + + +void tlcs900h_device::_EI() +{ + m_sr.b.h = ( m_sr.b.h & 0x8f ) | ( ( m_imm1.b.l & 0x07 ) << 4 ); + m_check_irqs = 1; +} + + +void tlcs900h_device::_EXBMR() +{ + UINT8 i = RDMEM( m_ea1.d ); + + WRMEM( m_ea1.d, *m_p2_reg8 ); + *m_p2_reg8 = i; +} + + +void tlcs900h_device::_EXBRR() +{ + UINT8 i = *m_p2_reg8; + + *m_p2_reg8 = *m_p1_reg8; + *m_p1_reg8 = i; +} + + +void tlcs900h_device::_EXWMR() +{ + UINT16 i = RDMEMW( m_ea1.d ); + + WRMEMW( m_ea1.d, *m_p2_reg16 ); + *m_p2_reg16 = i; +} + + +void tlcs900h_device::_EXWRR() +{ + UINT16 i = *m_p2_reg16; + + *m_p2_reg16 = *m_p1_reg16; + *m_p1_reg16 = i; +} + + +void tlcs900h_device::_EXTSWR() +{ + if ( *m_p1_reg16 & 0x0080 ) + *m_p1_reg16 |= 0xff00; + else + *m_p1_reg16 &= 0x00ff; +} + + +void tlcs900h_device::_EXTSLR() +{ + if ( *m_p1_reg32 & 0x00008000 ) + *m_p1_reg32 |= 0xffff0000; + else + *m_p1_reg32 &= 0x0000ffff; +} + + +void tlcs900h_device::_EXTZWR() +{ + *m_p1_reg16 &= 0x00ff; +} + + +void tlcs900h_device::_EXTZLR() +{ + *m_p1_reg32 &= 0x0000ffff; +} + + +void tlcs900h_device::_HALT() +{ + m_halted = 1; +} + + +void tlcs900h_device::_INCBIM() +{ + UINT8 cy = m_sr.b.l & FLAG_CF; + + WRMEM( m_ea2.d, add8( RDMEM( m_ea2.d ), m_imm1.b.l ? m_imm1.b.l : 8 ) ); + m_sr.b.l = ( m_sr.b.l & ~ FLAG_CF ) | cy; +} + + +void tlcs900h_device::_INCBIR() +{ + UINT8 cy = m_sr.b.l & FLAG_CF; + + *m_p2_reg8 = add8( *m_p2_reg8, m_imm1.b.l ? m_imm1.b.l : 8 ); + m_sr.b.l = ( m_sr.b.l & ~ FLAG_CF ) | cy; +} + + +void tlcs900h_device::_INCWIM() +{ + UINT8 cy = m_sr.b.l & FLAG_CF; + + WRMEMW( m_ea2.d, add16( RDMEMW( m_ea2.d ), m_imm1.b.l ? m_imm1.b.l : 8 ) ); + m_sr.b.l = ( m_sr.b.l & ~ FLAG_CF ) | cy; +} + + +void tlcs900h_device::_INCWIR() +{ + *m_p2_reg16 += m_imm1.b.l ? m_imm1.b.l : 8; +} + + +void tlcs900h_device::_INCLIR() +{ + *m_p2_reg32 += m_imm1.b.l ? m_imm1.b.l : 8; +} + + +void tlcs900h_device::_INCF() +{ + /* 0x03 for MAX mode, 0x07 for MIN mode */ + m_sr.b.h = ( m_sr.b.h & 0xf8 ) | ( ( m_sr.b.h + 1 ) & 0x07 ); + m_regbank = m_sr.b.h & 0x03; +} + + +void tlcs900h_device::_JPI() +{ + m_pc.d = m_imm1.d; + m_prefetch_clear = true; +} + + +void tlcs900h_device::_JPM() +{ + if ( condition_true( m_op ) ) + { + m_pc.d = m_ea2.d; + m_cycles += 4; + m_prefetch_clear = true; + } +} + + +void tlcs900h_device::_JR() +{ + if ( condition_true( m_op ) ) + { + m_pc.d = m_ea2.d; + m_cycles += 4; + m_prefetch_clear = true; + } +} + + +void tlcs900h_device::_JRL() +{ + if ( condition_true( m_op ) ) + { + m_pc.d = m_ea2.d; + m_cycles += 4; + m_prefetch_clear = true; + } +} + + +void tlcs900h_device::_LDBMI() +{ + WRMEM( m_ea1.d, m_imm2.b.l ); +} + + +void tlcs900h_device::_LDBMM() +{ + WRMEM( m_ea1.d, RDMEM( m_ea2.d ) ); +} + + +void tlcs900h_device::_LDBMR() +{ + WRMEM( m_ea1.d, *m_p2_reg8 ); +} + + +void tlcs900h_device::_LDBRI() +{ + *m_p1_reg8 = m_imm2.b.l; +} + + +void tlcs900h_device::_LDBRM() +{ + *m_p1_reg8 = RDMEM( m_ea2.d ); +} + + +void tlcs900h_device::_LDBRR() +{ + *m_p1_reg8 = *m_p2_reg8; +} + + +void tlcs900h_device::_LDWMI() +{ + WRMEMW( m_ea1.d, m_imm2.w.l ); +} + + +void tlcs900h_device::_LDWMM() +{ + WRMEMW( m_ea1.d, RDMEMW( m_ea2.d ) ); +} + + +void tlcs900h_device::_LDWMR() +{ + WRMEMW( m_ea1.d, *m_p2_reg16 ); +} + + +void tlcs900h_device::_LDWRI() +{ + *m_p1_reg16 = m_imm2.w.l; +} + + +void tlcs900h_device::_LDWRM() +{ + *m_p1_reg16 = RDMEMW( m_ea2.d ); +} + + +void tlcs900h_device::_LDWRR() +{ + *m_p1_reg16 = *m_p2_reg16; +} + + +void tlcs900h_device::_LDLRI() +{ + *m_p1_reg32 = m_imm2.d; +} + + +void tlcs900h_device::_LDLRM() +{ + *m_p1_reg32 = RDMEML( m_ea2.d ); +} + + +void tlcs900h_device::_LDLRR() +{ + *m_p1_reg32 = *m_p2_reg32; +} + + +void tlcs900h_device::_LDLMR() +{ + WRMEML( m_ea1.d, *m_p2_reg32 ); +} + + +void tlcs900h_device::_LDAW() +{ + *m_p1_reg16 = m_ea2.w.l; +} + + +void tlcs900h_device::_LDAL() +{ + *m_p1_reg32 = m_ea2.d; +} + + +void tlcs900h_device::_LDCBRR() +{ + *m_p1_reg8 = *m_p2_reg8; +} + + +void tlcs900h_device::_LDCWRR() +{ + *m_p1_reg16 = *m_p2_reg16; +} + + +void tlcs900h_device::_LDCLRR() +{ + *m_p1_reg32 = *m_p2_reg32; +} + + +void tlcs900h_device::_LDCFBIM() +{ + ldcf8( m_imm1.b.l, RDMEM( m_ea2.d ) ); +} + + +void tlcs900h_device::_LDCFBIR() +{ + ldcf8( m_imm1.b.l, *m_p2_reg8 ); +} + + +void tlcs900h_device::_LDCFBRM() +{ + ldcf8( *m_p1_reg8, RDMEM( m_ea2.d ) ); +} + + +void tlcs900h_device::_LDCFBRR() +{ + ldcf8( *m_p1_reg8, *m_p2_reg8 ); +} + + +void tlcs900h_device::_LDCFWIR() +{ + ldcf16( m_imm1.b.l, *m_p2_reg16 ); +} + + +void tlcs900h_device::_LDCFWRR() +{ + ldcf16( *m_p1_reg8, *m_p2_reg16 ); +} + + +void tlcs900h_device::_LDD() +{ + UINT16 *bc = get_reg16_current( 1 ); + + WRMEM( *m_p1_reg32, RDMEM( *m_p2_reg32 ) ); + *m_p1_reg32 -= 1; + *m_p2_reg32 -= 1; + *bc -= 1; + m_sr.b.l &= ~ ( FLAG_HF | FLAG_VF | FLAG_NF ); + if ( *bc ) + { + m_sr.b.l |= FLAG_VF; + } +} + + +void tlcs900h_device::_LDDR() +{ + UINT16 *bc = get_reg16_current( 1 ); + + WRMEM( *m_p1_reg32, RDMEM( *m_p2_reg32 ) ); + *m_p1_reg32 -= 1; + *m_p2_reg32 -= 1; + *bc -= 1; + m_sr.b.l &= ~ ( FLAG_HF | FLAG_VF | FLAG_NF ); + if ( *bc ) + { + m_sr.b.l |= FLAG_VF; + m_pc.d -= 2; + m_cycles += 4; + m_prefetch_clear = true; + } +} + + +void tlcs900h_device::_LDDRW() +{ + UINT16 *bc = get_reg16_current( 1 ); + + WRMEMW( *m_p1_reg32, RDMEMW( *m_p2_reg32 ) ); + *m_p1_reg32 -= 2; + *m_p2_reg32 -= 2; + *bc -= 1; + m_sr.b.l &= ~ ( FLAG_HF | FLAG_VF | FLAG_NF ); + if ( *bc ) + { + m_sr.b.l |= FLAG_VF; + m_pc.d -= 2; + m_cycles += 4; + m_prefetch_clear = true; + } +} + + +void tlcs900h_device::_LDDW() +{ + UINT16 *bc = get_reg16_current( 1 ); + + WRMEMW( *m_p1_reg32, RDMEMW( *m_p2_reg32 ) ); + *m_p1_reg32 -= 2; + *m_p2_reg32 -= 2; + *bc -= 1; + m_sr.b.l &= ~ ( FLAG_HF | FLAG_VF | FLAG_NF ); + if ( *bc ) + { + m_sr.b.l |= FLAG_VF; + } +} + + +void tlcs900h_device::_LDF() +{ + m_sr.b.h = ( m_sr.b.h & 0xf8 ) | ( m_imm1.b.l & 0x07 ); + m_regbank = m_imm1.b.l & 0x03; +} + + +void tlcs900h_device::_LDI() +{ + UINT16 *bc = get_reg16_current( 1 ); + + WRMEM( *m_p1_reg32, RDMEM( *m_p2_reg32 ) ); + *m_p1_reg32 += 1; + *m_p2_reg32 += 1; + *bc -= 1; + m_sr.b.l &= ~ ( FLAG_HF | FLAG_VF | FLAG_NF ); + if ( *bc ) + { + m_sr.b.l |= FLAG_VF; + } +} + + +void tlcs900h_device::_LDIR() +{ + UINT16 *bc = get_reg16_current( 1 ); + + WRMEM( *m_p1_reg32, RDMEM( *m_p2_reg32 ) ); + *m_p1_reg32 += 1; + *m_p2_reg32 += 1; + *bc -= 1; + m_sr.b.l &= ~ ( FLAG_HF | FLAG_VF | FLAG_NF ); + if ( *bc ) + { + m_sr.b.l |= FLAG_VF; + m_pc.d -= 2; + m_cycles += 4; + m_prefetch_clear = true; + } +} + + +void tlcs900h_device::_LDIRW() +{ + UINT16 *bc = get_reg16_current( 1 ); + + WRMEMW( *m_p1_reg32, RDMEMW( *m_p2_reg32 ) ); + *m_p1_reg32 += 2; + *m_p2_reg32 += 2; + *bc -= 1; + m_sr.b.l &= ~ ( FLAG_HF | FLAG_VF | FLAG_NF ); + if ( *bc ) + { + m_sr.b.l |= FLAG_VF; + m_pc.d -= 2; + m_cycles += 4; + m_prefetch_clear = true; + } +} + + +void tlcs900h_device::_LDIW() +{ + UINT16 *bc = get_reg16_current( 1 ); + + WRMEMW( *m_p1_reg32, RDMEMW( *m_p2_reg32 ) ); + *m_p1_reg32 += 2; + *m_p2_reg32 += 2; + *bc -= 1; + m_sr.b.l &= ~ ( FLAG_HF | FLAG_VF | FLAG_NF ); + if ( *bc ) + { + m_sr.b.l |= FLAG_VF; + } +} + + +void tlcs900h_device::_LDX() +{ + UINT8 a, b; + + RDOP(); + a = RDOP(); + RDOP(); + b = RDOP(); + RDOP(); + WRMEM( a, b ); +} + + +void tlcs900h_device::_LINK() +{ + m_xssp.d -= 4; + WRMEML( m_xssp.d, *m_p1_reg32 ); + *m_p1_reg32 = m_xssp.d; + m_xssp.d += m_imm2.sw.l; +} + + +void tlcs900h_device::_MAX() +{ + m_sr.b.h |= 0x04; +} + + +void tlcs900h_device::_MDEC1() +{ + if ( ( *m_p2_reg16 & m_imm1.w.l ) == m_imm1.w.l ) + *m_p2_reg16 += m_imm1.w.l; + else + *m_p2_reg16 -= 1; +} + + +void tlcs900h_device::_MDEC2() +{ + if ( ( *m_p2_reg16 & m_imm1.w.l ) == m_imm1.w.l ) + *m_p2_reg16 += m_imm1.w.l; + else + *m_p2_reg16 -= 2; +} + + +void tlcs900h_device::_MDEC4() +{ + if ( ( *m_p2_reg16 & m_imm1.w.l ) == m_imm1.w.l ) + *m_p2_reg16 += m_imm1.w.l; + else + *m_p2_reg16 -= 4; +} + + +void tlcs900h_device::_MINC1() +{ + if ( ( *m_p2_reg16 & m_imm1.w.l ) == m_imm1.w.l ) + *m_p2_reg16 -= m_imm1.w.l; + else + *m_p2_reg16 += 1; +} + + +void tlcs900h_device::_MINC2() +{ + if ( ( *m_p2_reg16 & m_imm1.w.l ) == m_imm1.w.l ) + *m_p2_reg16 -= m_imm1.w.l; + else + *m_p2_reg16 += 2; +} + + +void tlcs900h_device::_MINC4() +{ + if ( ( *m_p2_reg16 & m_imm1.w.l ) == m_imm1.w.l ) + *m_p2_reg16 -= m_imm1.w.l; + else + *m_p2_reg16 += 4; +} + + +void tlcs900h_device::_MIRRW() +{ + UINT16 r = *m_p1_reg16; + UINT16 s = ( r & 0x01 ); + int i; + + + for ( i = 0; i < 15; i++ ) + { + r >>= 1; + s <<= 1; + s |= ( r & 0x01 ); + } + + *m_p1_reg16 = s; +} + + +void tlcs900h_device::_MULBRI() +{ + *m_p1_reg16 = ( *m_p1_reg16 & 0xff ) * m_imm2.b.l; +} + + +void tlcs900h_device::_MULBRM() +{ + *m_p1_reg16 = ( *m_p1_reg16 & 0xff ) * RDMEM( m_ea2.d ); +} + + +void tlcs900h_device::_MULBRR() +{ + *m_p1_reg16 = ( *m_p1_reg16 & 0xff ) * *m_p2_reg8; +} + + +void tlcs900h_device::_MULWRI() +{ + *m_p1_reg32 = ( *m_p1_reg32 & 0xffff ) * m_imm2.w.l; +} + + +void tlcs900h_device::_MULWRM() +{ + *m_p1_reg32 = ( *m_p1_reg32 & 0xffff ) * RDMEMW( m_ea2.d ); +} + + +void tlcs900h_device::_MULWRR() +{ + *m_p1_reg32 = ( *m_p1_reg32 & 0xffff ) * *m_p2_reg16; +} + + +void tlcs900h_device::_MULAR() +{ + UINT32 *xde = get_reg32_current( 2 ); + UINT32 *xhl = get_reg32_current( 3 ); + + *m_p1_reg32 = *m_p1_reg32 + ( ((INT16)RDMEMW( *xde )) * ((INT16)RDMEMW( *xhl )) ); + *xhl -= 2; + + m_sr.b.l &= ~ ( FLAG_SF | FLAG_ZF | FLAG_VF ); + m_sr.b.l |= ( ( *m_p1_reg32 >> 24 ) & FLAG_SF ) | ( *m_p1_reg32 ? 0 : FLAG_ZF ); +} + + +void tlcs900h_device::_MULSBRI() +{ + *m_p1_reg16 = (INT8)( *m_p1_reg16 & 0xff ) * m_imm2.sb.l; +} + + +void tlcs900h_device::_MULSBRM() +{ + *m_p1_reg16 = (INT8)( *m_p1_reg16 & 0xff ) * (INT8)RDMEM( m_ea2.d ); +} + + +void tlcs900h_device::_MULSBRR() +{ + *m_p1_reg16 = (INT8)( *m_p1_reg16 & 0xff ) * (INT8)*m_p2_reg8; +} + + +void tlcs900h_device::_MULSWRI() +{ + *m_p1_reg32 = (INT16)( *m_p1_reg32 & 0xffff ) * m_imm2.sw.l; +} + + +void tlcs900h_device::_MULSWRM() +{ + *m_p1_reg32 = (INT16)( *m_p1_reg32 & 0xffff ) * (INT16)RDMEMW( m_ea2.d ); +} + + +void tlcs900h_device::_MULSWRR() +{ + *m_p1_reg32 = (INT16)( *m_p1_reg32 & 0xffff ) * (INT16)*m_p2_reg16; +} + + +void tlcs900h_device::_NEGBR() +{ + *m_p1_reg8 = sub8( 0, *m_p1_reg8 ); +} + + +void tlcs900h_device::_NEGWR() +{ + *m_p1_reg16 = sub16( 0, *m_p1_reg16 ); +} + + +void tlcs900h_device::_NOP() +{ + /* Do nothing */ +} + + +void tlcs900h_device::_NORMAL() +{ + m_sr.b.h &= 0x7F; +} + + +void tlcs900h_device::_ORBMI() +{ + WRMEM( m_ea1.d, or8( RDMEM( m_ea1.d ), m_imm2.b.l ) ); +} + + +void tlcs900h_device::_ORBMR() +{ + WRMEM( m_ea1.d, or8( RDMEM( m_ea1.d ), *m_p2_reg8 ) ); +} + + +void tlcs900h_device::_ORBRI() +{ + *m_p1_reg8 = or8( *m_p1_reg8, m_imm2.b.l ); +} + + +void tlcs900h_device::_ORBRM() +{ + *m_p1_reg8 = or8( *m_p1_reg8, RDMEM( m_ea2.d ) ); +} + + +void tlcs900h_device::_ORBRR() +{ + *m_p1_reg8 = or8( *m_p1_reg8, *m_p2_reg8 ); +} + + +void tlcs900h_device::_ORWMI() +{ + WRMEMW( m_ea1.d, or16( RDMEMW( m_ea1.d ), m_imm2.w.l ) ); +} + + +void tlcs900h_device::_ORWMR() +{ + WRMEMW( m_ea1.d, or16( RDMEMW( m_ea1.d ), *m_p2_reg16 ) ); +} + + +void tlcs900h_device::_ORWRI() +{ + *m_p1_reg16 = or16( *m_p1_reg16, m_imm2.w.l ); +} + + +void tlcs900h_device::_ORWRM() +{ + *m_p1_reg16 = or16( *m_p1_reg16, RDMEMW( m_ea2.d ) ); +} + + +void tlcs900h_device::_ORWRR() +{ + *m_p1_reg16 = or16( *m_p1_reg16, *m_p2_reg16 ); +} + + +void tlcs900h_device::_ORLMR() +{ + WRMEML( m_ea1.d, or32( RDMEML( m_ea1.d ), *m_p2_reg32 ) ); +} + + +void tlcs900h_device::_ORLRI() +{ + *m_p1_reg32 = or32( *m_p1_reg32, m_imm2.d ); +} + + +void tlcs900h_device::_ORLRM() +{ + *m_p1_reg32 = or32( *m_p1_reg32, RDMEML( m_ea2.d ) ); +} + + +void tlcs900h_device::_ORLRR() +{ + *m_p1_reg32 = or32( *m_p1_reg32, *m_p2_reg32 ); +} + + +void tlcs900h_device::_ORCFBIM() +{ + orcf8( m_imm1.b.l, RDMEM( m_ea2.d ) ); +} + + +void tlcs900h_device::_ORCFBIR() +{ + orcf8( m_imm1.b.l, *m_p2_reg8 ); +} + + +void tlcs900h_device::_ORCFBRM() +{ + orcf8( *m_p1_reg8, RDMEM( m_ea2.d ) ); +} + + +void tlcs900h_device::_ORCFBRR() +{ + orcf8( *m_p1_reg8, *m_p2_reg8 ); +} + + +void tlcs900h_device::_ORCFWIR() +{ + orcf16( m_imm1.b.l, *m_p2_reg16 ); +} + + +void tlcs900h_device::_ORCFWRR() +{ + orcf16( *m_p1_reg8, *m_p2_reg16 ); +} + + +void tlcs900h_device::_PAAWR() +{ + if ( *m_p1_reg16 & 1 ) + *m_p1_reg16 += 1; +} + + +void tlcs900h_device::_PAALR() +{ + if ( *m_p1_reg32 & 1 ) + *m_p1_reg32 += 1; +} + + +void tlcs900h_device::_POPBM() +{ + WRMEM( m_ea1.d, RDMEM( m_xssp.d ) ); + m_xssp.d += 1; +} + + +void tlcs900h_device::_POPBR() +{ + *m_p1_reg8 = RDMEM( m_xssp.d ); + m_xssp.d += 1; +} + + +void tlcs900h_device::_POPWM() +{ + WRMEMW( m_ea1.d, RDMEMW( m_xssp.d ) ); + m_xssp.d += 2; +} + + +void tlcs900h_device::_POPWR() +{ + *m_p1_reg16 = RDMEMW( m_xssp.d ); + m_xssp.d += 2; +} + + +void tlcs900h_device::_POPWSR() +{ + _POPWR(); + m_regbank = m_sr.b.h & 0x03; + m_check_irqs = 1; +} + + +void tlcs900h_device::_POPLR() +{ + *m_p1_reg32 = RDMEML( m_xssp.d ); + m_xssp.d += 4; +} + + +void tlcs900h_device::_PUSHBI() +{ + m_xssp.d -= 1; + WRMEM( m_xssp.d, m_imm1.b.l ); +} + + +void tlcs900h_device::_PUSHBM() +{ + m_xssp.d -= 1; + WRMEM( m_xssp.d, RDMEM( m_ea1.d ) ); +} + + +void tlcs900h_device::_PUSHBR() +{ + m_xssp.d -= 1; + WRMEM( m_xssp.d, *m_p1_reg8 ); +} + + +void tlcs900h_device::_PUSHWI() +{ + m_xssp.d -= 2; + WRMEMW( m_xssp.d, m_imm1.w.l ); +} + + +void tlcs900h_device::_PUSHWM() +{ + m_xssp.d -= 2; + WRMEMW( m_xssp.d, RDMEMW( m_ea1.d ) ); +} + + +void tlcs900h_device::_PUSHWR() +{ + m_xssp.d -= 2; + WRMEMW( m_xssp.d, *m_p1_reg16 ); +} + + +void tlcs900h_device::_PUSHLR() +{ + m_xssp.d -= 4; + WRMEML( m_xssp.d, *m_p1_reg32 ); +} + + +void tlcs900h_device::_RCF() +{ + m_sr.b.l &= ~ ( FLAG_HF | FLAG_NF | FLAG_CF ); +} + + +void tlcs900h_device::_RESBIM() +{ + WRMEM( m_ea2.d, RDMEM( m_ea2.d ) & ~( 1 << ( m_imm1.d & 0x07 ) ) ); +} + + +void tlcs900h_device::_RESBIR() +{ + *m_p2_reg8 = *m_p2_reg8 & ~( 1 << ( m_imm1.d & 0x07 ) ); +} + + +void tlcs900h_device::_RESWIR() +{ + *m_p2_reg16 = *m_p2_reg16 & ~( 1 << ( m_imm1.d & 0x0f ) ); +} + + +void tlcs900h_device::_RET() +{ + m_pc.d = RDMEML( m_xssp.d ); + m_xssp.d += 4; + m_prefetch_clear = true; +} + + +void tlcs900h_device::_RETCC() +{ + if ( condition_true( m_op ) ) + { + m_pc.d = RDMEML( m_xssp.d ); + m_xssp.d += 4; + m_cycles += 6; + m_prefetch_clear = true; + } +} + + +void tlcs900h_device::_RETD() +{ + m_pc.d = RDMEML( m_xssp.d ); + m_xssp.d += 4 + m_imm1.sw.l; + m_prefetch_clear = true; +} + + +void tlcs900h_device::_RETI() +{ + m_sr.w.l = RDMEMW( m_xssp.d ); + m_xssp.d += 2; + m_pc.d = RDMEML( m_xssp.d ); + m_xssp.d += 4; + m_regbank = m_sr.b.h & 0x03; + m_check_irqs = 1; + m_prefetch_clear = true; +} + + +void tlcs900h_device::_RLBM() +{ + WRMEM( m_ea2.d, rl8( RDMEM( m_ea2.d ), 1 ) ); +} + + +void tlcs900h_device::_RLWM() +{ + WRMEMW( m_ea2.d, rl16( RDMEMW( m_ea2.d ), 1 ) ); +} + + +void tlcs900h_device::_RLBIR() +{ + *m_p2_reg8 = rl8( *m_p2_reg8, m_imm1.b.l ); +} + + +void tlcs900h_device::_RLBRR() +{ + *m_p2_reg8 = rl8( *m_p2_reg8, *m_p1_reg8 ); +} + + +void tlcs900h_device::_RLWIR() +{ + *m_p2_reg16 = rl16( *m_p2_reg16, m_imm1.b.l ); +} + + +void tlcs900h_device::_RLWRR() +{ + *m_p2_reg16 = rl16( *m_p2_reg16, *m_p1_reg8 ); +} + + +void tlcs900h_device::_RLLIR() +{ + *m_p2_reg32 = rl32( *m_p2_reg32, m_imm1.b.l ); +} + + +void tlcs900h_device::_RLLRR() +{ + *m_p2_reg32 = rl32( *m_p2_reg32, *m_p1_reg8 ); +} + + +void tlcs900h_device::_RLCBM() +{ + WRMEM( m_ea2.d, rlc8( RDMEM( m_ea2.d ), 1 ) ); +} + + +void tlcs900h_device::_RLCWM() +{ + WRMEMW( m_ea2.d, rlc16( RDMEMW( m_ea2.d ), 1 ) ); +} + + +void tlcs900h_device::_RLCBIR() +{ + *m_p2_reg8 = rlc8( *m_p2_reg8, m_imm1.b.l ); +} + + +void tlcs900h_device::_RLCBRR() +{ + *m_p2_reg8 = rlc8( *m_p2_reg8, *m_p1_reg8 ); +} + + +void tlcs900h_device::_RLCWIR() +{ + *m_p2_reg16 = rlc16( *m_p2_reg16, m_imm1.b.l ); +} + + +void tlcs900h_device::_RLCWRR() +{ + *m_p2_reg16 = rlc16( *m_p2_reg16, *m_p1_reg8 ); +} + + +void tlcs900h_device::_RLCLIR() +{ + *m_p2_reg32 = rlc32( *m_p2_reg32, m_imm1.b.l ); +} + + +void tlcs900h_device::_RLCLRR() +{ + *m_p2_reg32 = rlc32( *m_p2_reg32, *m_p1_reg8 ); +} + + +void tlcs900h_device::_RLDRM() +{ + UINT8 a = *m_p1_reg8 & 0x0f; + UINT8 b = RDMEM( m_ea2.d ); + + *m_p1_reg8 = ( *m_p1_reg8 & 0xf0 ) | ( ( b & 0xf0 ) >> 4 ); + WRMEM( m_ea2.d, ( ( b & 0x0f ) << 4 ) | a ); + m_sr.b.l &= ~ ( FLAG_SF | FLAG_ZF | FLAG_HF | FLAG_VF | FLAG_NF | FLAG_CF ); + m_sr.b.l |= ( *m_p1_reg8 & FLAG_SF ) | ( *m_p1_reg8 ? 0 : FLAG_ZF ); + parity8( *m_p1_reg8 ); +} + + +void tlcs900h_device::_RRBM() +{ + WRMEM( m_ea2.d, rr8( RDMEM( m_ea2.d ), 1 ) ); +} + + +void tlcs900h_device::_RRWM() +{ + WRMEMW( m_ea2.d, rr16( RDMEMW( m_ea2.d ), 1 ) ); +} + + +void tlcs900h_device::_RRBIR() +{ + *m_p2_reg8 = rr8( *m_p2_reg8, m_imm1.b.l ); +} + + +void tlcs900h_device::_RRBRR() +{ + *m_p2_reg8 = rr8( *m_p2_reg8, *m_p1_reg8 ); +} + + +void tlcs900h_device::_RRWIR() +{ + *m_p2_reg16 = rr16( *m_p2_reg16, m_imm1.b.l ); +} + + +void tlcs900h_device::_RRWRR() +{ + *m_p2_reg16 = rr16( *m_p2_reg16, *m_p1_reg8 ); +} + + +void tlcs900h_device::_RRLIR() +{ + *m_p2_reg32 = rr32( *m_p2_reg32, m_imm1.b.l ); +} + + +void tlcs900h_device::_RRLRR() +{ + *m_p2_reg32 = rr32( *m_p2_reg32, *m_p1_reg8 ); +} + + +void tlcs900h_device::_RRCBM() +{ + WRMEM( m_ea2.d, rrc8( RDMEM( m_ea2.d ), 1 ) ); +} + + +void tlcs900h_device::_RRCWM() +{ + WRMEMW( m_ea2.d, rrc16( RDMEMW( m_ea2.d ), 1 ) ); +} + + +void tlcs900h_device::_RRCBIR() +{ + *m_p2_reg8 = rrc8( *m_p2_reg8, m_imm1.b.l ); +} + + +void tlcs900h_device::_RRCBRR() +{ + *m_p2_reg8 = rrc8( *m_p2_reg8, *m_p1_reg8 ); +} + + +void tlcs900h_device::_RRCWIR() +{ + *m_p2_reg16 = rrc16( *m_p2_reg16, m_imm1.b.l ); +} + + +void tlcs900h_device::_RRCWRR() +{ + *m_p2_reg16 = rrc16( *m_p2_reg16, *m_p1_reg8 ); +} + + +void tlcs900h_device::_RRCLIR() +{ + *m_p2_reg32 = rrc32( *m_p2_reg32, m_imm1.b.l ); +} + + +void tlcs900h_device::_RRCLRR() +{ + *m_p2_reg32 = rrc32( *m_p2_reg32, *m_p1_reg8 ); +} + + +void tlcs900h_device::_RRDRM() +{ + UINT8 a = *m_p1_reg8 & 0x0f; + UINT8 b = RDMEM( m_ea2.d ); + + *m_p1_reg8 = ( *m_p1_reg8 & 0xf0 ) | ( b & 0x0f ); + WRMEM( m_ea2.d, ( ( b & 0xf0 ) >> 4 ) | ( a << 4 ) ); + m_sr.b.l &= ~ ( FLAG_SF | FLAG_ZF | FLAG_HF | FLAG_VF | FLAG_NF | FLAG_CF ); + m_sr.b.l |= ( *m_p1_reg8 & FLAG_SF ) | ( *m_p1_reg8 ? 0 : FLAG_ZF ); + parity8( *m_p1_reg8 ); +} + + +void tlcs900h_device::_SBCBMI() +{ + WRMEM( m_ea1.d, sbc8( RDMEM( m_ea1.d ), m_imm2.b.l ) ); +} + + +void tlcs900h_device::_SBCBMR() +{ + WRMEM( m_ea1.d, sbc8( RDMEM( m_ea1.d ), *m_p2_reg8 ) ); +} + + +void tlcs900h_device::_SBCBRI() +{ + *m_p1_reg8 = sbc8( *m_p1_reg8, m_imm2.b.l ); +} + + +void tlcs900h_device::_SBCBRM() +{ + *m_p1_reg8 = sbc8( *m_p1_reg8, RDMEM( m_ea2.d ) ); +} + + +void tlcs900h_device::_SBCBRR() +{ + *m_p1_reg8 = sbc8( *m_p1_reg8, *m_p2_reg8 ); +} + + +void tlcs900h_device::_SBCWMI() +{ + WRMEMW( m_ea1.d, sbc16( RDMEMW( m_ea1.d ), m_imm2.w.l ) ); +} + + +void tlcs900h_device::_SBCWMR() +{ + WRMEMW( m_ea1.d, sbc16( RDMEMW( m_ea1.d ), *m_p2_reg16 ) ); +} + + +void tlcs900h_device::_SBCWRI() +{ + *m_p1_reg16 = sbc16( *m_p1_reg16, m_imm2.w.l ); +} + + +void tlcs900h_device::_SBCWRM() +{ + *m_p1_reg16 = sbc16( *m_p1_reg16, RDMEMW( m_ea2.d ) ); +} + + +void tlcs900h_device::_SBCWRR() +{ + *m_p1_reg16 = sbc16( *m_p1_reg16, *m_p2_reg16 ); +} + + +void tlcs900h_device::_SBCLMR() +{ + WRMEML( m_ea1.d, sbc32( RDMEML( m_ea1.d ), *m_p2_reg32 ) ); +} + + +void tlcs900h_device::_SBCLRI() +{ + *m_p1_reg32 = sbc32( *m_p1_reg32, m_imm2.d ); +} + + +void tlcs900h_device::_SBCLRM() +{ + *m_p1_reg32 = sbc32( *m_p1_reg32, RDMEML( m_ea2.d ) ); +} + + +void tlcs900h_device::_SBCLRR() +{ + *m_p1_reg32 = sbc32( *m_p1_reg32, *m_p2_reg32 ); +} + + +void tlcs900h_device::_SCCBR() +{ + *m_p2_reg8 = condition_true( m_op ) ? 1 : 0; +} + + +void tlcs900h_device::_SCCWR() +{ + *m_p2_reg16 = condition_true( m_op ) ? 1 : 0; +} + + +void tlcs900h_device::_SCF() +{ + m_sr.b.l &= ~ ( FLAG_HF | FLAG_NF ); + m_sr.b.l |= FLAG_CF; +} + + +void tlcs900h_device::_SETBIM() +{ + WRMEM( m_ea2.d, RDMEM( m_ea2.d ) | ( 1 << ( m_imm1.d & 0x07 ) ) ); +} + + +void tlcs900h_device::_SETBIR() +{ + *m_p2_reg8 = *m_p2_reg8 | ( 1 << ( m_imm1.d & 0x07 ) ); +} + + +void tlcs900h_device::_SETWIR() +{ + *m_p2_reg16 = *m_p2_reg16 | ( 1 << ( m_imm1.d & 0x0f ) ); +} + + +void tlcs900h_device::_SLABM() +{ + WRMEM( m_ea2.d, sla8( RDMEM( m_ea2.d ), 1 ) ); +} + + +void tlcs900h_device::_SLAWM() +{ + WRMEMW( m_ea2.d, sla16( RDMEMW( m_ea2.d ), 1 ) ); +} + + +void tlcs900h_device::_SLABIR() +{ + *m_p2_reg8 = sla8( *m_p2_reg8, m_imm1.b.l ); +} + + +void tlcs900h_device::_SLABRR() +{ + *m_p2_reg8 = sla8( *m_p2_reg8, *m_p1_reg8 ); +} + + +void tlcs900h_device::_SLAWIR() +{ + *m_p2_reg16 = sla16( *m_p2_reg16, m_imm1.b.l ); +} + + +void tlcs900h_device::_SLAWRR() +{ + *m_p2_reg16 = sla16( *m_p2_reg16, *m_p1_reg8 ); +} + + +void tlcs900h_device::_SLALIR() +{ + *m_p2_reg32 = sla32( *m_p2_reg32, m_imm1.b.l ); +} + + +void tlcs900h_device::_SLALRR() +{ + *m_p2_reg32 = sla32( *m_p2_reg32, *m_p1_reg8 ); +} + + +void tlcs900h_device::_SLLBM() +{ + WRMEM( m_ea2.d, sla8( RDMEM( m_ea2.d ), 1 ) ); +} + + +void tlcs900h_device::_SLLWM() +{ + WRMEMW( m_ea2.d, sla16( RDMEMW( m_ea2.d ), 1 ) ); +} + + +void tlcs900h_device::_SLLBIR() +{ + *m_p2_reg8 = sla8( *m_p2_reg8, m_imm1.b.l ); +} + + +void tlcs900h_device::_SLLBRR() +{ + *m_p2_reg8 = sla8( *m_p2_reg8, *m_p1_reg8 ); +} + + +void tlcs900h_device::_SLLWIR() +{ + *m_p2_reg16 = sla16( *m_p2_reg16, m_imm1.b.l ); +} + + +void tlcs900h_device::_SLLWRR() +{ + *m_p2_reg16 = sla16( *m_p2_reg16, *m_p1_reg8 ); +} + + +void tlcs900h_device::_SLLLIR() +{ + *m_p2_reg32 = sla32( *m_p2_reg32, m_imm1.b.l ); +} + + +void tlcs900h_device::_SLLLRR() +{ + *m_p2_reg32 = sla32( *m_p2_reg32, *m_p1_reg8 ); +} + + +void tlcs900h_device::_SRABM() +{ + WRMEM( m_ea2.d, sra8( RDMEM( m_ea2.d ), 1 ) ); +} + + +void tlcs900h_device::_SRAWM() +{ + WRMEMW( m_ea2.d, sra16( RDMEMW( m_ea2.d ), 1 ) ); +} + + +void tlcs900h_device::_SRABIR() +{ + *m_p2_reg8 = sra8( *m_p2_reg8, m_imm1.b.l ); +} + + +void tlcs900h_device::_SRABRR() +{ + *m_p2_reg8 = sra8( *m_p2_reg8, *m_p1_reg8 ); +} + + +void tlcs900h_device::_SRAWIR() +{ + *m_p2_reg16 = sra16( *m_p2_reg16, m_imm1.b.l ); +} + + +void tlcs900h_device::_SRAWRR() +{ + *m_p2_reg16 = sra16( *m_p2_reg16, *m_p1_reg8 ); +} + + +void tlcs900h_device::_SRALIR() +{ + *m_p2_reg32 = sra32( *m_p2_reg32, m_imm1.b.l ); +} + + +void tlcs900h_device::_SRALRR() +{ + *m_p2_reg32 = sra32( *m_p2_reg32, *m_p1_reg8 ); +} + + +void tlcs900h_device::_SRLBM() +{ + WRMEM( m_ea2.d, srl8( RDMEM( m_ea2.d ), 1 ) ); +} + + +void tlcs900h_device::_SRLWM() +{ + WRMEMW( m_ea2.d, srl16( RDMEMW( m_ea2.d ), 1 ) ); +} + + +void tlcs900h_device::_SRLBIR() +{ + *m_p2_reg8 = srl8( *m_p2_reg8, m_imm1.b.l ); +} + + +void tlcs900h_device::_SRLBRR() +{ + *m_p2_reg8 = srl8( *m_p2_reg8, *m_p1_reg8 ); +} + + +void tlcs900h_device::_SRLWIR() +{ + *m_p2_reg16 = srl16( *m_p2_reg16, m_imm1.b.l ); +} + + +void tlcs900h_device::_SRLWRR() +{ + *m_p2_reg16 = srl16( *m_p2_reg16, *m_p1_reg8 ); +} + + +void tlcs900h_device::_SRLLIR() +{ + *m_p2_reg32 = srl32( *m_p2_reg32, m_imm1.b.l ); +} + + +void tlcs900h_device::_SRLLRR() +{ + *m_p2_reg32 = srl32( *m_p2_reg32, *m_p1_reg8 ); +} + + +void tlcs900h_device::_STCFBIM() +{ + if ( m_sr.b.l & FLAG_CF ) + WRMEM( m_ea2.d, RDMEM( m_ea2.d ) | ( 1 << ( m_imm1.b.l & 0x07 ) ) ); + else + WRMEM( m_ea2.d, RDMEM( m_ea2.d ) & ~ ( 1 << ( m_imm1.b.l & 0x07 ) ) ); +} + + +void tlcs900h_device::_STCFBIR() +{ + if ( m_sr.b.l & FLAG_CF ) + *m_p2_reg8 |= ( 1 << ( m_imm1.b.l & 0x07 ) ); + else + *m_p2_reg8 &= ~ ( 1 << ( m_imm1.b.l & 0x07 ) ); +} + + +void tlcs900h_device::_STCFBRM() +{ + if ( m_sr.b.l & FLAG_CF ) + WRMEM( m_ea2.d, RDMEM( m_ea2.d ) | ( 1 << ( *m_p1_reg8 & 0x07 ) ) ); + else + WRMEM( m_ea2.d, RDMEM( m_ea2.d ) & ~ ( 1 << ( *m_p1_reg8 & 0x07 ) ) ); +} + + +void tlcs900h_device::_STCFBRR() +{ + if ( m_sr.b.l & FLAG_CF ) + *m_p2_reg8 |= ( 1 << ( *m_p1_reg8 & 0x07 ) ); + else + *m_p2_reg8 &= ~ ( 1 << ( *m_p1_reg8 & 0x07 ) ); +} + + +void tlcs900h_device::_STCFWIR() +{ + if ( m_sr.b.l & FLAG_CF ) + *m_p2_reg16 |= ( 1 << ( m_imm1.b.l & 0x0f ) ); + else + *m_p2_reg16 &= ~ ( 1 << ( m_imm1.b.l & 0x0f ) ); +} + + +void tlcs900h_device::_STCFWRR() +{ + if ( m_sr.b.l & FLAG_CF ) + *m_p2_reg16 |= ( 1 << ( *m_p1_reg8 & 0x0f ) ); + else + *m_p2_reg16 &= ~ ( 1 << ( *m_p1_reg8 & 0x0f ) ); +} + + +void tlcs900h_device::_SUBBMI() +{ + WRMEM( m_ea1.d, sub8( RDMEM( m_ea1.d ), m_imm2.b.l ) ); +} + + +void tlcs900h_device::_SUBBMR() +{ + WRMEM( m_ea1.d, sub8( RDMEM( m_ea1.d ), *m_p2_reg8 ) ); +} + + +void tlcs900h_device::_SUBBRI() +{ + *m_p1_reg8 = sub8( *m_p1_reg8, m_imm2.b.l ); +} + + +void tlcs900h_device::_SUBBRM() +{ + *m_p1_reg8 = sub8( *m_p1_reg8, RDMEM( m_ea2.d ) ); +} + + +void tlcs900h_device::_SUBBRR() +{ + *m_p1_reg8 = sub8( *m_p1_reg8, *m_p2_reg8 ); +} + + +void tlcs900h_device::_SUBWMI() +{ + WRMEMW( m_ea1.d, sub16( RDMEMW( m_ea1.d ), m_imm2.w.l ) ); +} + + +void tlcs900h_device::_SUBWMR() +{ + WRMEMW( m_ea1.d, sub16( RDMEMW( m_ea1.d ), *m_p2_reg16 ) ); +} + + +void tlcs900h_device::_SUBWRI() +{ + *m_p1_reg16 = sub16( *m_p1_reg16, m_imm2.w.l ); +} + + +void tlcs900h_device::_SUBWRM() +{ + *m_p1_reg16 = sub16( *m_p1_reg16, RDMEMW( m_ea2.d ) ); +} + + +void tlcs900h_device::_SUBWRR() +{ + *m_p1_reg16 = sub16( *m_p1_reg16, *m_p2_reg16 ); +} + + +void tlcs900h_device::_SUBLMR() +{ + WRMEML( m_ea1.d, sub32( RDMEML( m_ea1.d ), *m_p2_reg32 ) ); +} + + +void tlcs900h_device::_SUBLRI() +{ + *m_p1_reg32 = sub32( *m_p1_reg32, m_imm2.d ); +} + + +void tlcs900h_device::_SUBLRM() +{ + *m_p1_reg32 = sub32( *m_p1_reg32, RDMEML( m_ea2.d ) ); +} + + +void tlcs900h_device::_SUBLRR() +{ + *m_p1_reg32 = sub32( *m_p1_reg32, *m_p2_reg32 ); +} + + +void tlcs900h_device::_SWI() +{ + m_xssp.d -= 4; + WRMEML( m_xssp.d, m_pc.d ); + m_xssp.d -= 2; + WRMEMW( m_xssp.d, m_sr.w.l ); + m_pc.d = RDMEML( 0x00ffff00 + 4 * m_imm1.b.l ); + m_prefetch_clear = true; +} + + +void tlcs900h_device::_TSETBIM() +{ + UINT8 b = 1 << ( m_imm1.b.l & 0x07 ); + UINT8 a = RDMEM( m_ea2.d ); + + m_sr.b.l &= ~ ( FLAG_ZF | FLAG_NF ); + m_sr.b.l |= ( ( a & b ) ? 0 : FLAG_ZF ) | FLAG_HF; + WRMEM( m_ea2.d, a | b ); +} + + +void tlcs900h_device::_TSETBIR() +{ + UINT8 b = 1 << ( m_imm1.b.l & 0x07 ); + + m_sr.b.l &= ~ ( FLAG_ZF | FLAG_NF ); + m_sr.b.l |= ( ( *m_p2_reg8 & b ) ? 0 : FLAG_ZF ) | FLAG_HF; + *m_p2_reg8 |= b; +} + + +void tlcs900h_device::_TSETWIR() +{ + UINT16 b = 1 << ( m_imm1.b.l & 0x0f ); + + m_sr.b.l &= ~ ( FLAG_ZF | FLAG_NF ); + m_sr.b.l |= ( ( *m_p2_reg16 & b ) ? 0 : FLAG_ZF ) | FLAG_HF; + *m_p2_reg16 |= b; +} + + +void tlcs900h_device::_UNLK() +{ + m_xssp.d = *m_p1_reg32; + *m_p1_reg32 = RDMEML( m_xssp.d ); + m_xssp.d += 4; +} + + +void tlcs900h_device::_XORBMI() +{ + WRMEM( m_ea1.d, xor8( RDMEM( m_ea1.d ), m_imm2.b.l ) ); +} + + +void tlcs900h_device::_XORBMR() +{ + WRMEM( m_ea1.d, xor8( RDMEM( m_ea1.d ), *m_p2_reg8 ) ); +} + + +void tlcs900h_device::_XORBRI() +{ + *m_p1_reg8 = xor8( *m_p1_reg8, m_imm2.b.l ); +} + + +void tlcs900h_device::_XORBRM() +{ + *m_p1_reg8 = xor8( *m_p1_reg8, RDMEM( m_ea2.d ) ); +} + + +void tlcs900h_device::_XORBRR() +{ + *m_p1_reg8 = xor8( *m_p1_reg8, *m_p2_reg8 ); +} + + +void tlcs900h_device::_XORWMI() +{ + WRMEMW( m_ea1.d, xor16( RDMEMW( m_ea1.d ), m_imm2.w.l ) ); +} + + +void tlcs900h_device::_XORWMR() +{ + WRMEMW( m_ea1.d, xor16( RDMEMW( m_ea1.d ), *m_p2_reg16 ) ); +} + + +void tlcs900h_device::_XORWRI() +{ + *m_p1_reg16 = xor16( *m_p1_reg16, m_imm2.w.l ); +} + + +void tlcs900h_device::_XORWRM() +{ + *m_p1_reg16 = xor16( *m_p1_reg16, RDMEMW( m_ea2.d ) ); +} + + +void tlcs900h_device::_XORWRR() +{ + *m_p1_reg16 = xor16( *m_p1_reg16, *m_p2_reg16 ); +} + + +void tlcs900h_device::_XORLMR() +{ + WRMEML( m_ea1.d, xor32( RDMEML( m_ea1.d ), *m_p2_reg32 ) ); +} + + +void tlcs900h_device::_XORLRI() +{ + *m_p1_reg32 = xor32( *m_p1_reg32, m_imm2.d ); +} + + +void tlcs900h_device::_XORLRM() +{ + *m_p1_reg32 = xor32( *m_p1_reg32, RDMEML( m_ea2.d ) ); +} + + +void tlcs900h_device::_XORLRR() +{ + *m_p1_reg32 = xor32( *m_p1_reg32, *m_p2_reg32 ); +} + + +void tlcs900h_device::_XORCFBIM() +{ + xorcf8( m_imm1.b.l, RDMEM( m_ea2.d ) ); +} + + +void tlcs900h_device::_XORCFBIR() +{ + xorcf8( m_imm1.b.l, *m_p2_reg8 ); +} + + +void tlcs900h_device::_XORCFBRM() +{ + xorcf8( *m_p1_reg8, RDMEM( m_ea2.d ) ); +} + + +void tlcs900h_device::_XORCFBRR() +{ + xorcf8( *m_p1_reg8, *m_p2_reg8 ); +} + + +void tlcs900h_device::_XORCFWIR() +{ + xorcf16( m_imm1.b.l, *m_p2_reg16 ); +} + + +void tlcs900h_device::_XORCFWRR() +{ + xorcf16( *m_p1_reg8, *m_p2_reg16 ); +} + + +void tlcs900h_device::_ZCF() +{ + m_sr.b.l &= ~ ( FLAG_NF | FLAG_CF ); + m_sr.b.l |= ( ( m_sr.b.l & FLAG_ZF ) ? 0 : FLAG_CF ); +} + + +void tlcs900h_device::prepare_operands(const tlcs900inst *inst) +{ + switch ( inst->operand1 ) + { + case _A: + m_p1_reg8 = &m_xwa[m_regbank].b.l; + break; + case _F: + m_p1_reg8 = &m_sr.b.l; + break; + case _SR: + m_p1_reg16 = &m_sr.w.l; + break; + case _C8: + m_p1_reg8 = get_reg8_current( m_op ); + break; + case _C16: + m_p1_reg16 = get_reg16_current( m_op ); + break; + case _MC16: /* For MUL and DIV operations */ + m_p1_reg16 = get_reg16_current( ( m_op >> 1 ) & 0x03 ); + break; + case _C32: + m_p1_reg32 = get_reg32_current( m_op ); + break; + case _CR8: + m_imm1.d = RDOP(); + switch( m_imm1.d ) + { + case 0x22: + m_p1_reg8 = &m_dmam[0].b.l; + break; + case 0x26: + m_p1_reg8 = &m_dmam[1].b.l; + break; + case 0x2a: + m_p1_reg8 = &m_dmam[2].b.l; + break; + case 0x2e: + m_p1_reg8 = &m_dmam[3].b.l; + break; + default: + m_p1_reg8 = &m_dummy.b.l; + break; + } + break; + case _CR16: + m_imm1.d = RDOP(); + switch( m_imm1.d ) + { + case 0x20: + m_p1_reg16 = &m_dmac[0].w.l; + break; + case 0x24: + m_p1_reg16 = &m_dmac[1].w.l; + break; + case 0x28: + m_p1_reg16 = &m_dmac[2].w.l; + break; + case 0x2c: + m_p1_reg16 = &m_dmac[3].w.l; + break; + default: + m_p1_reg16 = &m_dummy.w.l; + break; + } + break; + case _CR32: + m_imm1.d = RDOP(); + switch( m_imm1.d ) + { + case 0x00: + m_p1_reg32 = &m_dmas[0].d; + break; + case 0x04: + m_p1_reg32 = &m_dmas[1].d; + break; + case 0x08: + m_p1_reg32 = &m_dmas[2].d; + break; + case 0x0c: + m_p1_reg32 = &m_dmas[3].d; + break; + case 0x10: + m_p1_reg32 = &m_dmad[0].d; + break; + case 0x14: + m_p1_reg32 = &m_dmad[1].d; + break; + case 0x18: + m_p1_reg32 = &m_dmad[2].d; + break; + case 0x1c: + m_p1_reg32 = &m_dmad[3].d; + break; + default: + m_p1_reg32 = &m_dummy.d; + break; + } + break; + case _D8: + m_ea1.d = RDOP(); + m_ea1.d = m_pc.d + m_ea1.sb.l; + break; + case _D16: + m_ea1.d = RDOP(); + m_ea1.b.h = RDOP(); + m_ea1.d = m_pc.d + m_ea1.sw.l; + break; + case _I3: + m_imm1.d = m_op & 0x07; + break; + case _I8: + m_imm1.d = RDOP(); + break; + case _I16: + m_imm1.d = RDOP(); + m_imm1.b.h = RDOP(); + break; + case _I24: + m_imm1.d = RDOP(); + m_imm1.b.h = RDOP(); + m_imm1.b.h2 = RDOP(); + break; + case _I32: + m_imm1.d = RDOP(); + m_imm1.b.h = RDOP(); + m_imm1.b.h2 = RDOP(); + m_imm1.b.h3 = RDOP(); + break; + case _M: + m_ea1.d = m_ea2.d; + break; + case _M8: + m_ea1.d = RDOP(); + break; + case _M16: + m_ea1.d = RDOP(); + m_ea1.b.h = RDOP(); + break; + case _R: + m_p1_reg8 = m_p2_reg8; + m_p1_reg16 = m_p2_reg16; + m_p1_reg32 = m_p2_reg32; + break; + } + + switch ( inst->operand2 ) + { + case _A: + m_p2_reg8 = &m_xwa[m_regbank].b.l; + break; + case _F: /* F' */ + m_p2_reg8 = &m_f2.b.l; + break; + case _SR: + m_p2_reg16 = &m_sr.w.l; + break; + case _C8: + m_p2_reg8 = get_reg8_current( m_op ); + break; + case _C16: + m_p2_reg16 = get_reg16_current( m_op ); + break; + case _C32: + m_p2_reg32 = get_reg32_current( m_op ); + break; + case _CR8: + m_imm1.d = RDOP(); + switch( m_imm1.d ) + { + case 0x22: + m_p2_reg8 = &m_dmam[0].b.l; + break; + case 0x26: + m_p2_reg8 = &m_dmam[1].b.l; + break; + case 0x2a: + m_p2_reg8 = &m_dmam[2].b.l; + break; + case 0x2e: + m_p2_reg8 = &m_dmam[3].b.l; + break; + default: + m_p2_reg8 = &m_dummy.b.l; + break; + } + break; + case _CR16: + m_imm1.d = RDOP(); + switch( m_imm1.d ) + { + case 0x20: + m_p2_reg16 = &m_dmac[0].w.l; + break; + case 0x24: + m_p2_reg16 = &m_dmac[1].w.l; + break; + case 0x28: + m_p2_reg16 = &m_dmac[2].w.l; + break; + case 0x2c: + m_p2_reg16 = &m_dmac[3].w.l; + break; + default: + m_p2_reg16 = &m_dummy.w.l; + break; + } + break; + case _CR32: + m_imm1.d = RDOP(); + switch( m_imm1.d ) + { + case 0x00: + m_p2_reg32 = &m_dmas[0].d; + break; + case 0x04: + m_p2_reg32 = &m_dmas[1].d; + break; + case 0x08: + m_p2_reg32 = &m_dmas[2].d; + break; + case 0x0c: + m_p2_reg32 = &m_dmas[3].d; + break; + case 0x10: + m_p2_reg32 = &m_dmad[0].d; + break; + case 0x14: + m_p2_reg32 = &m_dmad[1].d; + break; + case 0x18: + m_p2_reg32 = &m_dmad[2].d; + break; + case 0x1c: + m_p2_reg32 = &m_dmad[3].d; + break; + default: + m_p2_reg32 = &m_dummy.d; + break; + } + break; + case _D8: + m_ea2.d = RDOP(); + m_ea2.d = m_pc.d + m_ea2.sb.l; + break; + case _D16: + m_ea2.d = RDOP(); + m_ea2.b.h = RDOP(); + m_ea2.d = m_pc.d + m_ea2.sw.l; + break; + case _I3: + m_imm2.d = m_op & 0x07; + break; + case _I8: + m_imm2.d = RDOP(); + break; + case _I16: + m_imm2.d = RDOP(); + m_imm2.b.h = RDOP(); + break; + case _I32: + m_imm2.d = RDOP(); + m_imm2.b.h = RDOP(); + m_imm2.b.h2 = RDOP(); + m_imm2.b.h3 = RDOP(); + break; + case _M8: + m_ea2.d = RDOP(); + break; + case _M16: + m_ea2.d = RDOP(); + m_ea2.b.h = RDOP(); + break; + } +} + + +const tlcs900h_device::tlcs900inst tlcs900h_device::s_mnemonic_80[256] = +{ + /* 00 - 1F */ + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_PUSHBM, _M, 0, 7 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_RLDRM, _A, _M, 12 }, { &tlcs900h_device::_RRDRM, _A, _M, 12 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_LDI, 0, 0, 10 }, { &tlcs900h_device::_LDIR, 0, 0, 10 }, { &tlcs900h_device::_LDD, 0, 0, 10 }, { &tlcs900h_device::_LDDR, 0, 0, 10 }, + { &tlcs900h_device::_CPI, 0, 0, 8 }, { &tlcs900h_device::_CPIR, 0, 0, 10 }, { &tlcs900h_device::_CPD, 0, 0, 8 }, { &tlcs900h_device::_CPDR, 0, 0, 10 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_LDBMM, _M16, _M, 8 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + + /* 20 - 3F */ + { &tlcs900h_device::_LDBRM, _C8, _M, 4 }, { &tlcs900h_device::_LDBRM, _C8, _M, 4 }, { &tlcs900h_device::_LDBRM, _C8, _M, 4 }, { &tlcs900h_device::_LDBRM, _C8, _M, 4 }, + { &tlcs900h_device::_LDBRM, _C8, _M, 4 }, { &tlcs900h_device::_LDBRM, _C8, _M, 4 }, { &tlcs900h_device::_LDBRM, _C8, _M, 4 }, { &tlcs900h_device::_LDBRM, _C8, _M, 4 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_EXBMR, _M, _C8, 6 }, { &tlcs900h_device::_EXBMR, _M, _C8, 6 }, { &tlcs900h_device::_EXBMR, _M, _C8, 6 }, { &tlcs900h_device::_EXBMR, _M, _C8, 6 }, + { &tlcs900h_device::_EXBMR, _M, _C8, 6 }, { &tlcs900h_device::_EXBMR, _M, _C8, 6 }, { &tlcs900h_device::_EXBMR, _M, _C8, 6 }, { &tlcs900h_device::_EXBMR, _M, _C8, 6 }, + { &tlcs900h_device::_ADDBMI, _M, _I8, 7 }, { &tlcs900h_device::_ADCBMI, _M, _I8, 7 }, { &tlcs900h_device::_SUBBMI, _M, _I8, 7 }, { &tlcs900h_device::_SBCBMI, _M, _I8, 7 }, + { &tlcs900h_device::_ANDBMI, _M, _I8, 7 }, { &tlcs900h_device::_XORBMI, _M, _I8, 7 }, { &tlcs900h_device::_ORBMI, _M, _I8, 7 }, { &tlcs900h_device::_CPBMI, _M, _I8, 6 }, + + /* 40 - 5F */ + { &tlcs900h_device::_MULBRM, _MC16, _M, 18}, { &tlcs900h_device::_MULBRM, _MC16, _M, 18 }, { &tlcs900h_device::_MULBRM, _MC16, _M, 18 }, { &tlcs900h_device::_MULBRM, _MC16, _M, 18 }, + { &tlcs900h_device::_MULBRM, _MC16, _M, 18}, { &tlcs900h_device::_MULBRM, _MC16, _M, 18 }, { &tlcs900h_device::_MULBRM, _MC16, _M, 18 }, { &tlcs900h_device::_MULBRM, _MC16, _M, 18 }, + { &tlcs900h_device::_MULSBRM, _MC16, _M, 18 }, { &tlcs900h_device::_MULSBRM, _MC16, _M, 18 }, { &tlcs900h_device::_MULSBRM, _MC16, _M, 18 }, { &tlcs900h_device::_MULSBRM, _MC16, _M, 18 }, + { &tlcs900h_device::_MULSBRM, _MC16, _M, 18 }, { &tlcs900h_device::_MULSBRM, _MC16, _M, 18 }, { &tlcs900h_device::_MULSBRM, _MC16, _M, 18 }, { &tlcs900h_device::_MULSBRM, _MC16, _M, 18 }, + { &tlcs900h_device::_DIVBRM, _MC16, _M, 22 }, { &tlcs900h_device::_DIVBRM, _MC16, _M, 22 }, { &tlcs900h_device::_DIVBRM, _MC16, _M, 22 }, { &tlcs900h_device::_DIVBRM, _MC16, _M, 22 }, + { &tlcs900h_device::_DIVBRM, _MC16, _M, 22 }, { &tlcs900h_device::_DIVBRM, _MC16, _M, 22 }, { &tlcs900h_device::_DIVBRM, _MC16, _M, 22 }, { &tlcs900h_device::_DIVBRM, _MC16, _M, 22 }, + { &tlcs900h_device::_DIVSBRM, _MC16, _M, 24 }, { &tlcs900h_device::_DIVSBRM, _MC16, _M, 24 }, { &tlcs900h_device::_DIVSBRM, _MC16, _M, 24 }, { &tlcs900h_device::_DIVSBRM, _MC16, _M, 24 }, + { &tlcs900h_device::_DIVSBRM, _MC16, _M, 24 }, { &tlcs900h_device::_DIVSBRM, _MC16, _M, 24 }, { &tlcs900h_device::_DIVSBRM, _MC16, _M, 24 }, { &tlcs900h_device::_DIVSBRM, _MC16, _M, 24 }, + + /* 60 - 7F */ + { &tlcs900h_device::_INCBIM, _I3, _M, 6 }, { &tlcs900h_device::_INCBIM, _I3, _M, 6 }, { &tlcs900h_device::_INCBIM, _I3, _M, 6 }, { &tlcs900h_device::_INCBIM, _I3, _M, 6 }, + { &tlcs900h_device::_INCBIM, _I3, _M, 6 }, { &tlcs900h_device::_INCBIM, _I3, _M, 6 }, { &tlcs900h_device::_INCBIM, _I3, _M, 6 }, { &tlcs900h_device::_INCBIM, _I3, _M, 6 }, + { &tlcs900h_device::_DECBIM, _I3, _M, 6 }, { &tlcs900h_device::_DECBIM, _I3, _M, 6 }, { &tlcs900h_device::_DECBIM, _I3, _M, 6 }, { &tlcs900h_device::_DECBIM, _I3, _M, 6 }, + { &tlcs900h_device::_DECBIM, _I3, _M, 6 }, { &tlcs900h_device::_DECBIM, _I3, _M, 6 }, { &tlcs900h_device::_DECBIM, _I3, _M, 6 }, { &tlcs900h_device::_DECBIM, _I3, _M, 6 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_RLCBM, _M, 0, 8 }, { &tlcs900h_device::_RRCBM, _M, 0, 8 }, { &tlcs900h_device::_RLBM, _M, 0, 8 }, { &tlcs900h_device::_RRBM, _M, 0, 8 }, + { &tlcs900h_device::_SLABM, _M, 0, 8 }, { &tlcs900h_device::_SRABM, _M, 0, 8 }, { &tlcs900h_device::_SLLBM, _M, 0, 8 }, { &tlcs900h_device::_SRLBM, _M, 0, 8 }, + + /* 80 - 9F */ + { &tlcs900h_device::_ADDBRM, _C8, _M, 4 }, { &tlcs900h_device::_ADDBRM, _C8, _M, 4 }, { &tlcs900h_device::_ADDBRM, _C8, _M, 4 }, { &tlcs900h_device::_ADDBRM, _C8, _M, 4 }, + { &tlcs900h_device::_ADDBRM, _C8, _M, 4 }, { &tlcs900h_device::_ADDBRM, _C8, _M, 4 }, { &tlcs900h_device::_ADDBRM, _C8, _M, 4 }, { &tlcs900h_device::_ADDBRM, _C8, _M, 4 }, + { &tlcs900h_device::_ADDBMR, _M, _C8, 6 }, { &tlcs900h_device::_ADDBMR, _M, _C8, 6 }, { &tlcs900h_device::_ADDBMR, _M, _C8, 6 }, { &tlcs900h_device::_ADDBMR, _M, _C8, 6 }, + { &tlcs900h_device::_ADDBMR, _M, _C8, 6 }, { &tlcs900h_device::_ADDBMR, _M, _C8, 6 }, { &tlcs900h_device::_ADDBMR, _M, _C8, 6 }, { &tlcs900h_device::_ADDBMR, _M, _C8, 6 }, + { &tlcs900h_device::_ADCBRM, _C8, _M, 4 }, { &tlcs900h_device::_ADCBRM, _C8, _M, 4 }, { &tlcs900h_device::_ADCBRM, _C8, _M, 4 }, { &tlcs900h_device::_ADCBRM, _C8, _M, 4 }, + { &tlcs900h_device::_ADCBRM, _C8, _M, 4 }, { &tlcs900h_device::_ADCBRM, _C8, _M, 4 }, { &tlcs900h_device::_ADCBRM, _C8, _M, 4 }, { &tlcs900h_device::_ADCBRM, _C8, _M, 4 }, + { &tlcs900h_device::_ADCBMR, _M, _C8, 6 }, { &tlcs900h_device::_ADCBMR, _M, _C8, 6 }, { &tlcs900h_device::_ADCBMR, _M, _C8, 6 }, { &tlcs900h_device::_ADCBMR, _M, _C8, 6 }, + { &tlcs900h_device::_ADCBMR, _M, _C8, 6 }, { &tlcs900h_device::_ADCBMR, _M, _C8, 6 }, { &tlcs900h_device::_ADCBMR, _M, _C8, 6 }, { &tlcs900h_device::_ADCBMR, _M, _C8, 6 }, + + /* A0 - BF */ + { &tlcs900h_device::_SUBBRM, _C8, _M, 4 }, { &tlcs900h_device::_SUBBRM, _C8, _M, 4 }, { &tlcs900h_device::_SUBBRM, _C8, _M, 4 }, { &tlcs900h_device::_SUBBRM, _C8, _M, 4 }, + { &tlcs900h_device::_SUBBRM, _C8, _M, 4 }, { &tlcs900h_device::_SUBBRM, _C8, _M, 4 }, { &tlcs900h_device::_SUBBRM, _C8, _M, 4 }, { &tlcs900h_device::_SUBBRM, _C8, _M, 4 }, + { &tlcs900h_device::_SUBBMR, _M, _C8, 6 }, { &tlcs900h_device::_SUBBMR, _M, _C8, 6 }, { &tlcs900h_device::_SUBBMR, _M, _C8, 6 }, { &tlcs900h_device::_SUBBMR, _M, _C8, 6 }, + { &tlcs900h_device::_SUBBMR, _M, _C8, 6 }, { &tlcs900h_device::_SUBBMR, _M, _C8, 6 }, { &tlcs900h_device::_SUBBMR, _M, _C8, 6 }, { &tlcs900h_device::_SUBBMR, _M, _C8, 6 }, + { &tlcs900h_device::_SBCBRM, _C8, _M, 4 }, { &tlcs900h_device::_SBCBRM, _C8, _M, 4 }, { &tlcs900h_device::_SBCBRM, _C8, _M, 4 }, { &tlcs900h_device::_SBCBRM, _C8, _M, 4 }, + { &tlcs900h_device::_SBCBRM, _C8, _M, 4 }, { &tlcs900h_device::_SBCBRM, _C8, _M, 4 }, { &tlcs900h_device::_SBCBRM, _C8, _M, 4 }, { &tlcs900h_device::_SBCBRM, _C8, _M, 4 }, + { &tlcs900h_device::_SBCBMR, _M, _C8, 6 }, { &tlcs900h_device::_SBCBMR, _M, _C8, 6 }, { &tlcs900h_device::_SBCBMR, _M, _C8, 6 }, { &tlcs900h_device::_SBCBMR, _M, _C8, 6 }, + { &tlcs900h_device::_SBCBMR, _M, _C8, 6 }, { &tlcs900h_device::_SBCBMR, _M, _C8, 6 }, { &tlcs900h_device::_SBCBMR, _M, _C8, 6 }, { &tlcs900h_device::_SBCBMR, _M, _C8, 6 }, + + /* C0 - DF */ + { &tlcs900h_device::_ANDBRM, _C8, _M, 4 }, { &tlcs900h_device::_ANDBRM, _C8, _M, 4 }, { &tlcs900h_device::_ANDBRM, _C8, _M, 4 }, { &tlcs900h_device::_ANDBRM, _C8, _M, 4 }, + { &tlcs900h_device::_ANDBRM, _C8, _M, 4 }, { &tlcs900h_device::_ANDBRM, _C8, _M, 4 }, { &tlcs900h_device::_ANDBRM, _C8, _M, 4 }, { &tlcs900h_device::_ANDBRM, _C8, _M, 4 }, + { &tlcs900h_device::_ANDBMR, _M, _C8, 6 }, { &tlcs900h_device::_ANDBMR, _M, _C8, 6 }, { &tlcs900h_device::_ANDBMR, _M, _C8, 6 }, { &tlcs900h_device::_ANDBMR, _M, _C8, 6 }, + { &tlcs900h_device::_ANDBMR, _M, _C8, 6 }, { &tlcs900h_device::_ANDBMR, _M, _C8, 6 }, { &tlcs900h_device::_ANDBMR, _M, _C8, 6 }, { &tlcs900h_device::_ANDBMR, _M, _C8, 6 }, + { &tlcs900h_device::_XORBRM, _C8, _M, 4 }, { &tlcs900h_device::_XORBRM, _C8, _M, 4 }, { &tlcs900h_device::_XORBRM, _C8, _M, 4 }, { &tlcs900h_device::_XORBRM, _C8, _M, 4 }, + { &tlcs900h_device::_XORBRM, _C8, _M, 4 }, { &tlcs900h_device::_XORBRM, _C8, _M, 4 }, { &tlcs900h_device::_XORBRM, _C8, _M, 4 }, { &tlcs900h_device::_XORBRM, _C8, _M, 4 }, + { &tlcs900h_device::_XORBMR, _M, _C8, 6 }, { &tlcs900h_device::_XORBMR, _M, _C8, 6 }, { &tlcs900h_device::_XORBMR, _M, _C8, 6 }, { &tlcs900h_device::_XORBMR, _M, _C8, 6 }, + { &tlcs900h_device::_XORBMR, _M, _C8, 6 }, { &tlcs900h_device::_XORBMR, _M, _C8, 6 }, { &tlcs900h_device::_XORBMR, _M, _C8, 6 }, { &tlcs900h_device::_XORBMR, _M, _C8, 6 }, + + /* E0 - FF */ + { &tlcs900h_device::_ORBRM, _C8, _M, 4 }, { &tlcs900h_device::_ORBRM, _C8, _M, 4 }, { &tlcs900h_device::_ORBRM, _C8, _M, 4 }, { &tlcs900h_device::_ORBRM, _C8, _M, 4 }, + { &tlcs900h_device::_ORBRM, _C8, _M, 4 }, { &tlcs900h_device::_ORBRM, _C8, _M, 4 }, { &tlcs900h_device::_ORBRM, _C8, _M, 4 }, { &tlcs900h_device::_ORBRM, _C8, _M, 4 }, + { &tlcs900h_device::_ORBMR, _M, _C8, 6 }, { &tlcs900h_device::_ORBMR, _M, _C8, 6 }, { &tlcs900h_device::_ORBMR, _M, _C8, 6 }, { &tlcs900h_device::_ORBMR, _M, _C8, 6 }, + { &tlcs900h_device::_ORBMR, _M, _C8, 6 }, { &tlcs900h_device::_ORBMR, _M, _C8, 6 }, { &tlcs900h_device::_ORBMR, _M, _C8, 6 }, { &tlcs900h_device::_ORBMR, _M, _C8, 6 }, + { &tlcs900h_device::_CPBRM, _C8, _M, 4 }, { &tlcs900h_device::_CPBRM, _C8, _M, 4 }, { &tlcs900h_device::_CPBRM, _C8, _M, 4 }, { &tlcs900h_device::_CPBRM, _C8, _M, 4 }, + { &tlcs900h_device::_CPBRM, _C8, _M, 4 }, { &tlcs900h_device::_CPBRM, _C8, _M, 4 }, { &tlcs900h_device::_CPBRM, _C8, _M, 4 }, { &tlcs900h_device::_CPBRM, _C8, _M, 4 }, + { &tlcs900h_device::_CPBMR, _M, _C8, 6 }, { &tlcs900h_device::_CPBMR, _M, _C8, 6 }, { &tlcs900h_device::_CPBMR, _M, _C8, 6 }, { &tlcs900h_device::_CPBMR, _M, _C8, 6 }, + { &tlcs900h_device::_CPBMR, _M, _C8, 6 }, { &tlcs900h_device::_CPBMR, _M, _C8, 6 }, { &tlcs900h_device::_CPBMR, _M, _C8, 6 }, { &tlcs900h_device::_CPBMR, _M, _C8, 6 }, +}; + + +const tlcs900h_device::tlcs900inst tlcs900h_device::s_mnemonic_88[256] = +{ + /* 00 - 1F */ + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_PUSHBM, _M, 0, 7 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_RLDRM, _A, _M, 12 }, { &tlcs900h_device::_RRDRM, _A, _M, 12 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_LDBMM, _M16, _M, 8 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + + /* 20 - 3F */ + { &tlcs900h_device::_LDBRM, _C8, _M, 4 }, { &tlcs900h_device::_LDBRM, _C8, _M, 4 }, { &tlcs900h_device::_LDBRM, _C8, _M, 4 }, { &tlcs900h_device::_LDBRM, _C8, _M, 4 }, + { &tlcs900h_device::_LDBRM, _C8, _M, 4 }, { &tlcs900h_device::_LDBRM, _C8, _M, 4 }, { &tlcs900h_device::_LDBRM, _C8, _M, 4 }, { &tlcs900h_device::_LDBRM, _C8, _M, 4 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_EXBMR, _M, _C8, 6 }, { &tlcs900h_device::_EXBMR, _M, _C8, 6 }, { &tlcs900h_device::_EXBMR, _M, _C8, 6 }, { &tlcs900h_device::_EXBMR, _M, _C8, 6 }, + { &tlcs900h_device::_EXBMR, _M, _C8, 6 }, { &tlcs900h_device::_EXBMR, _M, _C8, 6 }, { &tlcs900h_device::_EXBMR, _M, _C8, 6 }, { &tlcs900h_device::_EXBMR, _M, _C8, 6 }, + { &tlcs900h_device::_ADDBMI, _M, _I8, 7 }, { &tlcs900h_device::_ADCBMI, _M, _I8, 7 }, { &tlcs900h_device::_SUBBMI, _M, _I8, 7 }, { &tlcs900h_device::_SBCBMI, _M, _I8, 7 }, + { &tlcs900h_device::_ANDBMI, _M, _I8, 7 }, { &tlcs900h_device::_XORBMI, _M, _I8, 7 }, { &tlcs900h_device::_ORBMI, _M, _I8, 7 }, { &tlcs900h_device::_CPBMI, _M, _I8, 6 }, + + /* 40 - 5F */ + { &tlcs900h_device::_MULBRM, _MC16, _M, 18 }, { &tlcs900h_device::_MULBRM, _MC16, _M, 18 }, { &tlcs900h_device::_MULBRM, _MC16, _M, 18 }, { &tlcs900h_device::_MULBRM, _MC16, _M, 18 }, + { &tlcs900h_device::_MULBRM, _MC16, _M, 18 }, { &tlcs900h_device::_MULBRM, _MC16, _M, 18 }, { &tlcs900h_device::_MULBRM, _MC16, _M, 18 }, { &tlcs900h_device::_MULBRM, _MC16, _M, 18 }, + { &tlcs900h_device::_MULSBRM, _MC16, _M, 18 }, { &tlcs900h_device::_MULSBRM, _MC16, _M, 18 }, { &tlcs900h_device::_MULSBRM, _MC16, _M, 18 }, { &tlcs900h_device::_MULSBRM, _MC16, _M, 18 }, + { &tlcs900h_device::_MULSBRM, _MC16, _M, 18 }, { &tlcs900h_device::_MULSBRM, _MC16, _M, 18 }, { &tlcs900h_device::_MULSBRM, _MC16, _M, 18 }, { &tlcs900h_device::_MULSBRM, _MC16, _M, 18 }, + { &tlcs900h_device::_DIVBRM, _MC16, _M, 22 }, { &tlcs900h_device::_DIVBRM, _MC16, _M, 22 }, { &tlcs900h_device::_DIVBRM, _MC16, _M, 22 }, { &tlcs900h_device::_DIVBRM, _MC16, _M, 22 }, + { &tlcs900h_device::_DIVBRM, _MC16, _M, 22 }, { &tlcs900h_device::_DIVBRM, _MC16, _M, 22 }, { &tlcs900h_device::_DIVBRM, _MC16, _M, 22 }, { &tlcs900h_device::_DIVBRM, _MC16, _M, 22 }, + { &tlcs900h_device::_DIVSBRM, _MC16, _M, 24 }, { &tlcs900h_device::_DIVSBRM, _MC16, _M, 24 }, { &tlcs900h_device::_DIVSBRM, _MC16, _M, 24 }, { &tlcs900h_device::_DIVSBRM, _MC16, _M, 24 }, + { &tlcs900h_device::_DIVSBRM, _MC16, _M, 24 }, { &tlcs900h_device::_DIVSBRM, _MC16, _M, 24 }, { &tlcs900h_device::_DIVSBRM, _MC16, _M, 24 }, { &tlcs900h_device::_DIVSBRM, _MC16, _M, 24 }, + + /* 60 - 7F */ + { &tlcs900h_device::_INCBIM, _I3, _M, 6 }, { &tlcs900h_device::_INCBIM, _I3, _M, 6 }, { &tlcs900h_device::_INCBIM, _I3, _M, 6 }, { &tlcs900h_device::_INCBIM, _I3, _M, 6 }, + { &tlcs900h_device::_INCBIM, _I3, _M, 6 }, { &tlcs900h_device::_INCBIM, _I3, _M, 6 }, { &tlcs900h_device::_INCBIM, _I3, _M, 6 }, { &tlcs900h_device::_INCBIM, _I3, _M, 6 }, + { &tlcs900h_device::_DECBIM, _I3, _M, 6 }, { &tlcs900h_device::_DECBIM, _I3, _M, 6 }, { &tlcs900h_device::_DECBIM, _I3, _M, 6 }, { &tlcs900h_device::_DECBIM, _I3, _M, 6 }, + { &tlcs900h_device::_DECBIM, _I3, _M, 6 }, { &tlcs900h_device::_DECBIM, _I3, _M, 6 }, { &tlcs900h_device::_DECBIM, _I3, _M, 6 }, { &tlcs900h_device::_DECBIM, _I3, _M, 6 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_RLCBM, _M, 0, 8 }, { &tlcs900h_device::_RRCBM, _M, 0, 8 }, { &tlcs900h_device::_RLBM, _M, 0, 8 }, { &tlcs900h_device::_RRBM, _M, 0, 8 }, + { &tlcs900h_device::_SLABM, _M, 0, 8 }, { &tlcs900h_device::_SRABM, _M, 0, 8 }, { &tlcs900h_device::_SLLBM, _M, 0, 8 }, { &tlcs900h_device::_SRLBM, _M, 0, 8 }, + + /* 80 - 9F */ + { &tlcs900h_device::_ADDBRM, _C8, _M, 4 }, { &tlcs900h_device::_ADDBRM, _C8, _M, 4 }, { &tlcs900h_device::_ADDBRM, _C8, _M, 4 }, { &tlcs900h_device::_ADDBRM, _C8, _M, 4 }, + { &tlcs900h_device::_ADDBRM, _C8, _M, 4 }, { &tlcs900h_device::_ADDBRM, _C8, _M, 4 }, { &tlcs900h_device::_ADDBRM, _C8, _M, 4 }, { &tlcs900h_device::_ADDBRM, _C8, _M, 4 }, + { &tlcs900h_device::_ADDBMR, _M, _C8, 6 }, { &tlcs900h_device::_ADDBMR, _M, _C8, 6 }, { &tlcs900h_device::_ADDBMR, _M, _C8, 6 }, { &tlcs900h_device::_ADDBMR, _M, _C8, 6 }, + { &tlcs900h_device::_ADDBMR, _M, _C8, 6 }, { &tlcs900h_device::_ADDBMR, _M, _C8, 6 }, { &tlcs900h_device::_ADDBMR, _M, _C8, 6 }, { &tlcs900h_device::_ADDBMR, _M, _C8, 6 }, + { &tlcs900h_device::_ADCBRM, _C8, _M, 4 }, { &tlcs900h_device::_ADCBRM, _C8, _M, 4 }, { &tlcs900h_device::_ADCBRM, _C8, _M, 4 }, { &tlcs900h_device::_ADCBRM, _C8, _M, 4 }, + { &tlcs900h_device::_ADCBRM, _C8, _M, 4 }, { &tlcs900h_device::_ADCBRM, _C8, _M, 4 }, { &tlcs900h_device::_ADCBRM, _C8, _M, 4 }, { &tlcs900h_device::_ADCBRM, _C8, _M, 4 }, + { &tlcs900h_device::_ADCBMR, _M, _C8, 6 }, { &tlcs900h_device::_ADCBMR, _M, _C8, 6 }, { &tlcs900h_device::_ADCBMR, _M, _C8, 6 }, { &tlcs900h_device::_ADCBMR, _M, _C8, 6 }, + { &tlcs900h_device::_ADCBMR, _M, _C8, 6 }, { &tlcs900h_device::_ADCBMR, _M, _C8, 6 }, { &tlcs900h_device::_ADCBMR, _M, _C8, 6 }, { &tlcs900h_device::_ADCBMR, _M, _C8, 6 }, + + /* A0 - BF */ + { &tlcs900h_device::_SUBBRM, _C8, _M, 4 }, { &tlcs900h_device::_SUBBRM, _C8, _M, 4 }, { &tlcs900h_device::_SUBBRM, _C8, _M, 4 }, { &tlcs900h_device::_SUBBRM, _C8, _M, 4 }, + { &tlcs900h_device::_SUBBRM, _C8, _M, 4 }, { &tlcs900h_device::_SUBBRM, _C8, _M, 4 }, { &tlcs900h_device::_SUBBRM, _C8, _M, 4 }, { &tlcs900h_device::_SUBBRM, _C8, _M, 4 }, + { &tlcs900h_device::_SUBBMR, _M, _C8, 6 }, { &tlcs900h_device::_SUBBMR, _M, _C8, 6 }, { &tlcs900h_device::_SUBBMR, _M, _C8, 6 }, { &tlcs900h_device::_SUBBMR, _M, _C8, 6 }, + { &tlcs900h_device::_SUBBMR, _M, _C8, 6 }, { &tlcs900h_device::_SUBBMR, _M, _C8, 6 }, { &tlcs900h_device::_SUBBMR, _M, _C8, 6 }, { &tlcs900h_device::_SUBBMR, _M, _C8, 6 }, + { &tlcs900h_device::_SBCBRM, _C8, _M, 4 }, { &tlcs900h_device::_SBCBRM, _C8, _M, 4 }, { &tlcs900h_device::_SBCBRM, _C8, _M, 4 }, { &tlcs900h_device::_SBCBRM, _C8, _M, 4 }, + { &tlcs900h_device::_SBCBRM, _C8, _M, 4 }, { &tlcs900h_device::_SBCBRM, _C8, _M, 4 }, { &tlcs900h_device::_SBCBRM, _C8, _M, 4 }, { &tlcs900h_device::_SBCBRM, _C8, _M, 4 }, + { &tlcs900h_device::_SBCBMR, _M, _C8, 6 }, { &tlcs900h_device::_SBCBMR, _M, _C8, 6 }, { &tlcs900h_device::_SBCBMR, _M, _C8, 6 }, { &tlcs900h_device::_SBCBMR, _M, _C8, 6 }, + { &tlcs900h_device::_SBCBMR, _M, _C8, 6 }, { &tlcs900h_device::_SBCBMR, _M, _C8, 6 }, { &tlcs900h_device::_SBCBMR, _M, _C8, 6 }, { &tlcs900h_device::_SBCBMR, _M, _C8, 6 }, + + /* C0 - DF */ + { &tlcs900h_device::_ANDBRM, _C8, _M, 4 }, { &tlcs900h_device::_ANDBRM, _C8, _M, 4 }, { &tlcs900h_device::_ANDBRM, _C8, _M, 4 }, { &tlcs900h_device::_ANDBRM, _C8, _M, 4 }, + { &tlcs900h_device::_ANDBRM, _C8, _M, 4 }, { &tlcs900h_device::_ANDBRM, _C8, _M, 4 }, { &tlcs900h_device::_ANDBRM, _C8, _M, 4 }, { &tlcs900h_device::_ANDBRM, _C8, _M, 4 }, + { &tlcs900h_device::_ANDBMR, _M, _C8, 6 }, { &tlcs900h_device::_ANDBMR, _M, _C8, 6 }, { &tlcs900h_device::_ANDBMR, _M, _C8, 6 }, { &tlcs900h_device::_ANDBMR, _M, _C8, 6 }, + { &tlcs900h_device::_ANDBMR, _M, _C8, 6 }, { &tlcs900h_device::_ANDBMR, _M, _C8, 6 }, { &tlcs900h_device::_ANDBMR, _M, _C8, 6 }, { &tlcs900h_device::_ANDBMR, _M, _C8, 6 }, + { &tlcs900h_device::_XORBRM, _C8, _M, 4 }, { &tlcs900h_device::_XORBRM, _C8, _M, 4 }, { &tlcs900h_device::_XORBRM, _C8, _M, 4 }, { &tlcs900h_device::_XORBRM, _C8, _M, 4 }, + { &tlcs900h_device::_XORBRM, _C8, _M, 4 }, { &tlcs900h_device::_XORBRM, _C8, _M, 4 }, { &tlcs900h_device::_XORBRM, _C8, _M, 4 }, { &tlcs900h_device::_XORBRM, _C8, _M, 4 }, + { &tlcs900h_device::_XORBMR, _M, _C8, 6 }, { &tlcs900h_device::_XORBMR, _M, _C8, 6 }, { &tlcs900h_device::_XORBMR, _M, _C8, 6 }, { &tlcs900h_device::_XORBMR, _M, _C8, 6 }, + { &tlcs900h_device::_XORBMR, _M, _C8, 6 }, { &tlcs900h_device::_XORBMR, _M, _C8, 6 }, { &tlcs900h_device::_XORBMR, _M, _C8, 6 }, { &tlcs900h_device::_XORBMR, _M, _C8, 6 }, + + /* E0 - FF */ + { &tlcs900h_device::_ORBRM, _C8, _M, 4 }, { &tlcs900h_device::_ORBRM, _C8, _M, 4 }, { &tlcs900h_device::_ORBRM, _C8, _M, 4 }, { &tlcs900h_device::_ORBRM, _C8, _M, 4 }, + { &tlcs900h_device::_ORBRM, _C8, _M, 4 }, { &tlcs900h_device::_ORBRM, _C8, _M, 4 }, { &tlcs900h_device::_ORBRM, _C8, _M, 4 }, { &tlcs900h_device::_ORBRM, _C8, _M, 4 }, + { &tlcs900h_device::_ORBMR, _M, _C8, 6 }, { &tlcs900h_device::_ORBMR, _M, _C8, 6 }, { &tlcs900h_device::_ORBMR, _M, _C8, 6 }, { &tlcs900h_device::_ORBMR, _M, _C8, 6 }, + { &tlcs900h_device::_ORBMR, _M, _C8, 6 }, { &tlcs900h_device::_ORBMR, _M, _C8, 6 }, { &tlcs900h_device::_ORBMR, _M, _C8, 6 }, { &tlcs900h_device::_ORBMR, _M, _C8, 6 }, + { &tlcs900h_device::_CPBRM, _C8, _M, 4 }, { &tlcs900h_device::_CPBRM, _C8, _M, 4 }, { &tlcs900h_device::_CPBRM, _C8, _M, 4 }, { &tlcs900h_device::_CPBRM, _C8, _M, 4 }, + { &tlcs900h_device::_CPBRM, _C8, _M, 4 }, { &tlcs900h_device::_CPBRM, _C8, _M, 4 }, { &tlcs900h_device::_CPBRM, _C8, _M, 4 }, { &tlcs900h_device::_CPBRM, _C8, _M, 4 }, + { &tlcs900h_device::_CPBMR, _M, _C8, 6 }, { &tlcs900h_device::_CPBMR, _M, _C8, 6 }, { &tlcs900h_device::_CPBMR, _M, _C8, 6 }, { &tlcs900h_device::_CPBMR, _M, _C8, 6 }, + { &tlcs900h_device::_CPBMR, _M, _C8, 6 }, { &tlcs900h_device::_CPBMR, _M, _C8, 6 }, { &tlcs900h_device::_CPBMR, _M, _C8, 6 }, { &tlcs900h_device::_CPBMR, _M, _C8, 6 }, +}; + + +const tlcs900h_device::tlcs900inst tlcs900h_device::s_mnemonic_90[256] = +{ + /* 00 - 1F */ + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_PUSHWM, _M, 0, 7 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_LDIW, 0, 0, 10 }, { &tlcs900h_device::_LDIRW, 0, 0, 10 }, { &tlcs900h_device::_LDDW, 0, 0, 10 }, { &tlcs900h_device::_LDDRW, 0, 0, 10 }, + { &tlcs900h_device::_CPIW, 0, 0, 8 }, { &tlcs900h_device::_CPIRW, 0, 0, 10 }, { &tlcs900h_device::_CPDW, 0, 0, 8 }, { &tlcs900h_device::_CPDRW, 0, 0, 10 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_LDWMM, _M16, _M, 8 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + + /* 20 - 3F */ + { &tlcs900h_device::_LDWRM, _C16, _M, 4 }, { &tlcs900h_device::_LDWRM, _C16, _M, 4 }, { &tlcs900h_device::_LDWRM, _C16, _M, 4 }, { &tlcs900h_device::_LDWRM, _C16, _M, 4 }, + { &tlcs900h_device::_LDWRM, _C16, _M, 4 }, { &tlcs900h_device::_LDWRM, _C16, _M, 4 }, { &tlcs900h_device::_LDWRM, _C16, _M, 4 }, { &tlcs900h_device::_LDWRM, _C16, _M, 4 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_EXWMR, _M, _C16, 6 }, { &tlcs900h_device::_EXWMR, _M, _C16, 6 }, { &tlcs900h_device::_EXWMR, _M, _C16, 6 }, { &tlcs900h_device::_EXWMR, _M, _C16, 6 }, + { &tlcs900h_device::_EXWMR, _M, _C16, 6 }, { &tlcs900h_device::_EXWMR, _M, _C16, 6 }, { &tlcs900h_device::_EXWMR, _M, _C16, 6 }, { &tlcs900h_device::_EXWMR, _M, _C16, 6 }, + { &tlcs900h_device::_ADDWMI, _M, _I16, 8 }, { &tlcs900h_device::_ADCWMI, _M, _I16, 8 }, { &tlcs900h_device::_SUBWMI, _M, _I16, 8 }, { &tlcs900h_device::_SBCWMI, _M, _I16, 8 }, + { &tlcs900h_device::_ANDWMI, _M, _I16, 8 }, { &tlcs900h_device::_XORWMI, _M, _I16, 8 }, { &tlcs900h_device::_ORWMI, _M, _I16, 8 }, { &tlcs900h_device::_CPWMI, _M, _I16, 6 }, + + /* 40 - 5F */ + { &tlcs900h_device::_MULWRM, _C32, _M, 26 }, { &tlcs900h_device::_MULWRM, _C32, _M, 26 }, { &tlcs900h_device::_MULWRM, _C32, _M, 26 }, { &tlcs900h_device::_MULWRM, _C32, _M, 26 }, + { &tlcs900h_device::_MULWRM, _C32, _M, 26 }, { &tlcs900h_device::_MULWRM, _C32, _M, 26 }, { &tlcs900h_device::_MULWRM, _C32, _M, 26 }, { &tlcs900h_device::_MULWRM, _C32, _M, 26 }, + { &tlcs900h_device::_MULSWRM, _C32, _M, 26 }, { &tlcs900h_device::_MULSWRM, _C32, _M, 26 }, { &tlcs900h_device::_MULSWRM, _C32, _M, 26 }, { &tlcs900h_device::_MULSWRM, _C32, _M, 26 }, + { &tlcs900h_device::_MULSWRM, _C32, _M, 26 }, { &tlcs900h_device::_MULSWRM, _C32, _M, 26 }, { &tlcs900h_device::_MULSWRM, _C32, _M, 26 }, { &tlcs900h_device::_MULSWRM, _C32, _M, 26 }, + { &tlcs900h_device::_DIVWRM, _C32, _M, 30 }, { &tlcs900h_device::_DIVWRM, _C32, _M, 30 }, { &tlcs900h_device::_DIVWRM, _C32, _M, 30 }, { &tlcs900h_device::_DIVWRM, _C32, _M, 30 }, + { &tlcs900h_device::_DIVWRM, _C32, _M, 30 }, { &tlcs900h_device::_DIVWRM, _C32, _M, 30 }, { &tlcs900h_device::_DIVWRM, _C32, _M, 30 }, { &tlcs900h_device::_DIVWRM, _C32, _M, 30 }, + { &tlcs900h_device::_DIVSWRM, _C32, _M, 32 }, { &tlcs900h_device::_DIVSWRM, _C32, _M, 32 }, { &tlcs900h_device::_DIVSWRM, _C32, _M, 32 }, { &tlcs900h_device::_DIVSWRM, _C32, _M, 32 }, + { &tlcs900h_device::_DIVSWRM, _C32, _M, 32 }, { &tlcs900h_device::_DIVSWRM, _C32, _M, 32 }, { &tlcs900h_device::_DIVSWRM, _C32, _M, 32 }, { &tlcs900h_device::_DIVSWRM, _C32, _M, 32 }, + + /* 60 - 7F */ + { &tlcs900h_device::_INCWIM, _I3, _M, 6 }, { &tlcs900h_device::_INCWIM, _I3, _M, 6 }, { &tlcs900h_device::_INCWIM, _I3, _M, 6 }, { &tlcs900h_device::_INCWIM, _I3, _M, 6 }, + { &tlcs900h_device::_INCWIM, _I3, _M, 6 }, { &tlcs900h_device::_INCWIM, _I3, _M, 6 }, { &tlcs900h_device::_INCWIM, _I3, _M, 6 }, { &tlcs900h_device::_INCWIM, _I3, _M, 6 }, + { &tlcs900h_device::_DECWIM, _I3, _M, 6 }, { &tlcs900h_device::_DECWIM, _I3, _M, 6 }, { &tlcs900h_device::_DECWIM, _I3, _M, 6 }, { &tlcs900h_device::_DECWIM, _I3, _M, 6 }, + { &tlcs900h_device::_DECWIM, _I3, _M, 6 }, { &tlcs900h_device::_DECWIM, _I3, _M, 6 }, { &tlcs900h_device::_DECWIM, _I3, _M, 6 }, { &tlcs900h_device::_DECWIM, _I3, _M, 6 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_RLCWM, _M, 0, 8 }, { &tlcs900h_device::_RRCWM, _M, 0, 8 }, { &tlcs900h_device::_RLWM, _M, 0, 8 }, { &tlcs900h_device::_RRWM, _M, 0, 8 }, + { &tlcs900h_device::_SLAWM, _M, 0, 8 }, { &tlcs900h_device::_SRAWM, _M, 0, 8 }, { &tlcs900h_device::_SLLWM, _M, 0, 8 }, { &tlcs900h_device::_SRLWM, _M, 0, 8 }, + + /* 80 - 9F */ + { &tlcs900h_device::_ADDWRM, _C16, _M, 4 }, { &tlcs900h_device::_ADDWRM, _C16, _M, 4 }, { &tlcs900h_device::_ADDWRM, _C16, _M, 4 }, { &tlcs900h_device::_ADDWRM, _C16, _M, 4 }, + { &tlcs900h_device::_ADDWRM, _C16, _M, 4 }, { &tlcs900h_device::_ADDWRM, _C16, _M, 4 }, { &tlcs900h_device::_ADDWRM, _C16, _M, 4 }, { &tlcs900h_device::_ADDWRM, _C16, _M, 4 }, + { &tlcs900h_device::_ADDWMR, _M, _C16, 6 }, { &tlcs900h_device::_ADDWMR, _M, _C16, 6 }, { &tlcs900h_device::_ADDWMR, _M, _C16, 6 }, { &tlcs900h_device::_ADDWMR, _M, _C16, 6 }, + { &tlcs900h_device::_ADDWMR, _M, _C16, 6 }, { &tlcs900h_device::_ADDWMR, _M, _C16, 6 }, { &tlcs900h_device::_ADDWMR, _M, _C16, 6 }, { &tlcs900h_device::_ADDWMR, _M, _C16, 6 }, + { &tlcs900h_device::_ADCWRM, _C16, _M, 4 }, { &tlcs900h_device::_ADCWRM, _C16, _M, 4 }, { &tlcs900h_device::_ADCWRM, _C16, _M, 4 }, { &tlcs900h_device::_ADCWRM, _C16, _M, 4 }, + { &tlcs900h_device::_ADCWRM, _C16, _M, 4 }, { &tlcs900h_device::_ADCWRM, _C16, _M, 4 }, { &tlcs900h_device::_ADCWRM, _C16, _M, 4 }, { &tlcs900h_device::_ADCWRM, _C16, _M, 4 }, + { &tlcs900h_device::_ADCWMR, _M, _C16, 6 }, { &tlcs900h_device::_ADCWMR, _M, _C16, 6 }, { &tlcs900h_device::_ADCWMR, _M, _C16, 6 }, { &tlcs900h_device::_ADCWMR, _M, _C16, 6 }, + { &tlcs900h_device::_ADCWMR, _M, _C16, 6 }, { &tlcs900h_device::_ADCWMR, _M, _C16, 6 }, { &tlcs900h_device::_ADCWMR, _M, _C16, 6 }, { &tlcs900h_device::_ADCWMR, _M, _C16, 6 }, + + /* A0 - BF */ + { &tlcs900h_device::_SUBWRM, _C16, _M, 4 }, { &tlcs900h_device::_SUBWRM, _C16, _M, 4 }, { &tlcs900h_device::_SUBWRM, _C16, _M, 4 }, { &tlcs900h_device::_SUBWRM, _C16, _M, 4 }, + { &tlcs900h_device::_SUBWRM, _C16, _M, 4 }, { &tlcs900h_device::_SUBWRM, _C16, _M, 4 }, { &tlcs900h_device::_SUBWRM, _C16, _M, 4 }, { &tlcs900h_device::_SUBWRM, _C16, _M, 4 }, + { &tlcs900h_device::_SUBWMR, _M, _C16, 6 }, { &tlcs900h_device::_SUBWMR, _M, _C16, 6 }, { &tlcs900h_device::_SUBWMR, _M, _C16, 6 }, { &tlcs900h_device::_SUBWMR, _M, _C16, 6 }, + { &tlcs900h_device::_SUBWMR, _M, _C16, 6 }, { &tlcs900h_device::_SUBWMR, _M, _C16, 6 }, { &tlcs900h_device::_SUBWMR, _M, _C16, 6 }, { &tlcs900h_device::_SUBWMR, _M, _C16, 6 }, + { &tlcs900h_device::_SBCWRM, _C16, _M, 4 }, { &tlcs900h_device::_SBCWRM, _C16, _M, 4 }, { &tlcs900h_device::_SBCWRM, _C16, _M, 4 }, { &tlcs900h_device::_SBCWRM, _C16, _M, 4 }, + { &tlcs900h_device::_SBCWRM, _C16, _M, 4 }, { &tlcs900h_device::_SBCWRM, _C16, _M, 4 }, { &tlcs900h_device::_SBCWRM, _C16, _M, 4 }, { &tlcs900h_device::_SBCWRM, _C16, _M, 4 }, + { &tlcs900h_device::_SBCWMR, _M, _C16, 6 }, { &tlcs900h_device::_SBCWMR, _M, _C16, 6 }, { &tlcs900h_device::_SBCWMR, _M, _C16, 6 }, { &tlcs900h_device::_SBCWMR, _M, _C16, 6 }, + { &tlcs900h_device::_SBCWMR, _M, _C16, 6 }, { &tlcs900h_device::_SBCWMR, _M, _C16, 6 }, { &tlcs900h_device::_SBCWMR, _M, _C16, 6 }, { &tlcs900h_device::_SBCWMR, _M, _C16, 6 }, + + /* C0 - DF */ + { &tlcs900h_device::_ANDWRM, _C16, _M, 4 }, { &tlcs900h_device::_ANDWRM, _C16, _M, 4 }, { &tlcs900h_device::_ANDWRM, _C16, _M, 4 }, { &tlcs900h_device::_ANDWRM, _C16, _M, 4 }, + { &tlcs900h_device::_ANDWRM, _C16, _M, 4 }, { &tlcs900h_device::_ANDWRM, _C16, _M, 4 }, { &tlcs900h_device::_ANDWRM, _C16, _M, 4 }, { &tlcs900h_device::_ANDWRM, _C16, _M, 4 }, + { &tlcs900h_device::_ANDWMR, _M, _C16, 6 }, { &tlcs900h_device::_ANDWMR, _M, _C16, 6 }, { &tlcs900h_device::_ANDWMR, _M, _C16, 6 }, { &tlcs900h_device::_ANDWMR, _M, _C16, 6 }, + { &tlcs900h_device::_ANDWMR, _M, _C16, 6 }, { &tlcs900h_device::_ANDWMR, _M, _C16, 6 }, { &tlcs900h_device::_ANDWMR, _M, _C16, 6 }, { &tlcs900h_device::_ANDWMR, _M, _C16, 6 }, + { &tlcs900h_device::_XORWRM, _C16, _M, 4 }, { &tlcs900h_device::_XORWRM, _C16, _M, 4 }, { &tlcs900h_device::_XORWRM, _C16, _M, 4 }, { &tlcs900h_device::_XORWRM, _C16, _M, 4 }, + { &tlcs900h_device::_XORWRM, _C16, _M, 4 }, { &tlcs900h_device::_XORWRM, _C16, _M, 4 }, { &tlcs900h_device::_XORWRM, _C16, _M, 4 }, { &tlcs900h_device::_XORWRM, _C16, _M, 4 }, + { &tlcs900h_device::_XORWMR, _M, _C16, 6 }, { &tlcs900h_device::_XORWMR, _M, _C16, 6 }, { &tlcs900h_device::_XORWMR, _M, _C16, 6 }, { &tlcs900h_device::_XORWMR, _M, _C16, 6 }, + { &tlcs900h_device::_XORWMR, _M, _C16, 6 }, { &tlcs900h_device::_XORWMR, _M, _C16, 6 }, { &tlcs900h_device::_XORWMR, _M, _C16, 6 }, { &tlcs900h_device::_XORWMR, _M, _C16, 6 }, + + /* E0 - FF */ + { &tlcs900h_device::_ORWRM, _C16, _M, 4 }, { &tlcs900h_device::_ORWRM, _C16, _M, 4 }, { &tlcs900h_device::_ORWRM, _C16, _M, 4 }, { &tlcs900h_device::_ORWRM, _C16, _M, 4 }, + { &tlcs900h_device::_ORWRM, _C16, _M, 4 }, { &tlcs900h_device::_ORWRM, _C16, _M, 4 }, { &tlcs900h_device::_ORWRM, _C16, _M, 4 }, { &tlcs900h_device::_ORWRM, _C16, _M, 4 }, + { &tlcs900h_device::_ORWMR, _M, _C16, 6 }, { &tlcs900h_device::_ORWMR, _M, _C16, 6 }, { &tlcs900h_device::_ORWMR, _M, _C16, 6 }, { &tlcs900h_device::_ORWMR, _M, _C16, 6 }, + { &tlcs900h_device::_ORWMR, _M, _C16, 6 }, { &tlcs900h_device::_ORWMR, _M, _C16, 6 }, { &tlcs900h_device::_ORWMR, _M, _C16, 6 }, { &tlcs900h_device::_ORWMR, _M, _C16, 6 }, + { &tlcs900h_device::_CPWRM, _C16, _M, 4 }, { &tlcs900h_device::_CPWRM, _C16, _M, 4 }, { &tlcs900h_device::_CPWRM, _C16, _M, 4 }, { &tlcs900h_device::_CPWRM, _C16, _M, 4 }, + { &tlcs900h_device::_CPWRM, _C16, _M, 4 }, { &tlcs900h_device::_CPWRM, _C16, _M, 4 }, { &tlcs900h_device::_CPWRM, _C16, _M, 4 }, { &tlcs900h_device::_CPWRM, _C16, _M, 4 }, + { &tlcs900h_device::_CPWMR, _M, _C16, 6 }, { &tlcs900h_device::_CPWMR, _M, _C16, 6 }, { &tlcs900h_device::_CPWMR, _M, _C16, 6 }, { &tlcs900h_device::_CPWMR, _M, _C16, 6 }, + { &tlcs900h_device::_CPWMR, _M, _C16, 6 }, { &tlcs900h_device::_CPWMR, _M, _C16, 6 }, { &tlcs900h_device::_CPWMR, _M, _C16, 6 }, { &tlcs900h_device::_CPWMR, _M, _C16, 6 }, +}; + + +const tlcs900h_device::tlcs900inst tlcs900h_device::s_mnemonic_98[256] = +{ + /* 00 - 1F */ + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_PUSHWM, _M, 0, 7 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_LDWMM, _M16, _M, 8 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + + /* 20 - 3F */ + { &tlcs900h_device::_LDWRM, _C16, _M, 4 }, { &tlcs900h_device::_LDWRM, _C16, _M, 4 }, { &tlcs900h_device::_LDWRM, _C16, _M, 4 }, { &tlcs900h_device::_LDWRM, _C16, _M, 4 }, + { &tlcs900h_device::_LDWRM, _C16, _M, 4 }, { &tlcs900h_device::_LDWRM, _C16, _M, 4 }, { &tlcs900h_device::_LDWRM, _C16, _M, 4 }, { &tlcs900h_device::_LDWRM, _C16, _M, 4 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_EXWMR, _M, _C16, 6 }, { &tlcs900h_device::_EXWMR, _M, _C16, 6 }, { &tlcs900h_device::_EXWMR, _M, _C16, 6 }, { &tlcs900h_device::_EXWMR, _M, _C16, 6 }, + { &tlcs900h_device::_EXWMR, _M, _C16, 6 }, { &tlcs900h_device::_EXWMR, _M, _C16, 6 }, { &tlcs900h_device::_EXWMR, _M, _C16, 6 }, { &tlcs900h_device::_EXWMR, _M, _C16, 6 }, + { &tlcs900h_device::_ADDWMI, _M, _I16, 8 }, { &tlcs900h_device::_ADCWMI, _M, _I16, 8 }, { &tlcs900h_device::_SUBWMI, _M, _I16, 8 }, { &tlcs900h_device::_SBCWMI, _M, _I16, 8 }, + { &tlcs900h_device::_ANDWMI, _M, _I16, 8 }, { &tlcs900h_device::_XORWMI, _M, _I16, 8 }, { &tlcs900h_device::_ORWMI, _M, _I16, 8 }, { &tlcs900h_device::_CPWMI, _M, _I16, 6 }, + + /* 40 - 5F */ + { &tlcs900h_device::_MULWRM, _C32, _M, 26 }, { &tlcs900h_device::_MULWRM, _C32, _M, 26 }, { &tlcs900h_device::_MULWRM, _C32, _M, 26 }, { &tlcs900h_device::_MULWRM, _C32, _M, 26 }, + { &tlcs900h_device::_MULWRM, _C32, _M, 26 }, { &tlcs900h_device::_MULWRM, _C32, _M, 26 }, { &tlcs900h_device::_MULWRM, _C32, _M, 26 }, { &tlcs900h_device::_MULWRM, _C32, _M, 26 }, + { &tlcs900h_device::_MULSWRM, _C32, _M, 26 }, { &tlcs900h_device::_MULSWRM, _C32, _M, 26 }, { &tlcs900h_device::_MULSWRM, _C32, _M, 26 }, { &tlcs900h_device::_MULSWRM, _C32, _M, 26 }, + { &tlcs900h_device::_MULSWRM, _C32, _M, 26 }, { &tlcs900h_device::_MULSWRM, _C32, _M, 26 }, { &tlcs900h_device::_MULSWRM, _C32, _M, 26 }, { &tlcs900h_device::_MULSWRM, _C32, _M, 26 }, + { &tlcs900h_device::_DIVWRM, _C32, _M, 30 }, { &tlcs900h_device::_DIVWRM, _C32, _M, 30 }, { &tlcs900h_device::_DIVWRM, _C32, _M, 30 }, { &tlcs900h_device::_DIVWRM, _C32, _M, 30 }, + { &tlcs900h_device::_DIVWRM, _C32, _M, 30 }, { &tlcs900h_device::_DIVWRM, _C32, _M, 30 }, { &tlcs900h_device::_DIVWRM, _C32, _M, 30 }, { &tlcs900h_device::_DIVWRM, _C32, _M, 30 }, + { &tlcs900h_device::_DIVSWRM, _C32, _M, 32 }, { &tlcs900h_device::_DIVSWRM, _C32, _M, 32 }, { &tlcs900h_device::_DIVSWRM, _C32, _M, 32 }, { &tlcs900h_device::_DIVSWRM, _C32, _M, 32 }, + { &tlcs900h_device::_DIVSWRM, _C32, _M, 32 }, { &tlcs900h_device::_DIVSWRM, _C32, _M, 32 }, { &tlcs900h_device::_DIVSWRM, _C32, _M, 32 }, { &tlcs900h_device::_DIVSWRM, _C32, _M, 32 }, + + /* 60 - 7F */ + { &tlcs900h_device::_INCWIM, _I3, _M, 6 }, { &tlcs900h_device::_INCWIM, _I3, _M, 6 }, { &tlcs900h_device::_INCWIM, _I3, _M, 6 }, { &tlcs900h_device::_INCWIM, _I3, _M, 6 }, + { &tlcs900h_device::_INCWIM, _I3, _M, 6 }, { &tlcs900h_device::_INCWIM, _I3, _M, 6 }, { &tlcs900h_device::_INCWIM, _I3, _M, 6 }, { &tlcs900h_device::_INCWIM, _I3, _M, 6 }, + { &tlcs900h_device::_DECWIM, _I3, _M, 6 }, { &tlcs900h_device::_DECWIM, _I3, _M, 6 }, { &tlcs900h_device::_DECWIM, _I3, _M, 6 }, { &tlcs900h_device::_DECWIM, _I3, _M, 6 }, + { &tlcs900h_device::_DECWIM, _I3, _M, 6 }, { &tlcs900h_device::_DECWIM, _I3, _M, 6 }, { &tlcs900h_device::_DECWIM, _I3, _M, 6 }, { &tlcs900h_device::_DECWIM, _I3, _M, 6 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_RLCWM, _M, 0, 8 }, { &tlcs900h_device::_RRCWM, _M, 0, 8 }, { &tlcs900h_device::_RLWM, _M, 0, 8 }, { &tlcs900h_device::_RRWM, _M, 0, 8 }, + { &tlcs900h_device::_SLAWM, _M, 0, 8 }, { &tlcs900h_device::_SRAWM, _M, 0, 8 }, { &tlcs900h_device::_SLLWM, _M, 0, 8 }, { &tlcs900h_device::_SRLWM, _M, 0, 8 }, + + /* 80 - 9F */ + { &tlcs900h_device::_ADDWRM, _C16, _M, 4 }, { &tlcs900h_device::_ADDWRM, _C16, _M, 4 }, { &tlcs900h_device::_ADDWRM, _C16, _M, 4 }, { &tlcs900h_device::_ADDWRM, _C16, _M, 4 }, + { &tlcs900h_device::_ADDWRM, _C16, _M, 4 }, { &tlcs900h_device::_ADDWRM, _C16, _M, 4 }, { &tlcs900h_device::_ADDWRM, _C16, _M, 4 }, { &tlcs900h_device::_ADDWRM, _C16, _M, 4 }, + { &tlcs900h_device::_ADDWMR, _M, _C16, 6 }, { &tlcs900h_device::_ADDWMR, _M, _C16, 6 }, { &tlcs900h_device::_ADDWMR, _M, _C16, 6 }, { &tlcs900h_device::_ADDWMR, _M, _C16, 6 }, + { &tlcs900h_device::_ADDWMR, _M, _C16, 6 }, { &tlcs900h_device::_ADDWMR, _M, _C16, 6 }, { &tlcs900h_device::_ADDWMR, _M, _C16, 6 }, { &tlcs900h_device::_ADDWMR, _M, _C16, 6 }, + { &tlcs900h_device::_ADCWRM, _C16, _M, 4 }, { &tlcs900h_device::_ADCWRM, _C16, _M, 4 }, { &tlcs900h_device::_ADCWRM, _C16, _M, 4 }, { &tlcs900h_device::_ADCWRM, _C16, _M, 4 }, + { &tlcs900h_device::_ADCWRM, _C16, _M, 4 }, { &tlcs900h_device::_ADCWRM, _C16, _M, 4 }, { &tlcs900h_device::_ADCWRM, _C16, _M, 4 }, { &tlcs900h_device::_ADCWRM, _C16, _M, 4 }, + { &tlcs900h_device::_ADCWMR, _M, _C16, 6 }, { &tlcs900h_device::_ADCWMR, _M, _C16, 6 }, { &tlcs900h_device::_ADCWMR, _M, _C16, 6 }, { &tlcs900h_device::_ADCWMR, _M, _C16, 6 }, + { &tlcs900h_device::_ADCWMR, _M, _C16, 6 }, { &tlcs900h_device::_ADCWMR, _M, _C16, 6 }, { &tlcs900h_device::_ADCWMR, _M, _C16, 6 }, { &tlcs900h_device::_ADCWMR, _M, _C16, 6 }, + + /* A0 - BF */ + { &tlcs900h_device::_SUBWRM, _C16, _M, 4 }, { &tlcs900h_device::_SUBWRM, _C16, _M, 4 }, { &tlcs900h_device::_SUBWRM, _C16, _M, 4 }, { &tlcs900h_device::_SUBWRM, _C16, _M, 4 }, + { &tlcs900h_device::_SUBWRM, _C16, _M, 4 }, { &tlcs900h_device::_SUBWRM, _C16, _M, 4 }, { &tlcs900h_device::_SUBWRM, _C16, _M, 4 }, { &tlcs900h_device::_SUBWRM, _C16, _M, 4 }, + { &tlcs900h_device::_SUBWMR, _M, _C16, 6 }, { &tlcs900h_device::_SUBWMR, _M, _C16, 6 }, { &tlcs900h_device::_SUBWMR, _M, _C16, 6 }, { &tlcs900h_device::_SUBWMR, _M, _C16, 6 }, + { &tlcs900h_device::_SUBWMR, _M, _C16, 6 }, { &tlcs900h_device::_SUBWMR, _M, _C16, 6 }, { &tlcs900h_device::_SUBWMR, _M, _C16, 6 }, { &tlcs900h_device::_SUBWMR, _M, _C16, 6 }, + { &tlcs900h_device::_SBCWRM, _C16, _M, 4 }, { &tlcs900h_device::_SBCWRM, _C16, _M, 4 }, { &tlcs900h_device::_SBCWRM, _C16, _M, 4 }, { &tlcs900h_device::_SBCWRM, _C16, _M, 4 }, + { &tlcs900h_device::_SBCWRM, _C16, _M, 4 }, { &tlcs900h_device::_SBCWRM, _C16, _M, 4 }, { &tlcs900h_device::_SBCWRM, _C16, _M, 4 }, { &tlcs900h_device::_SBCWRM, _C16, _M, 4 }, + { &tlcs900h_device::_SBCWMR, _M, _C16, 6 }, { &tlcs900h_device::_SBCWMR, _M, _C16, 6 }, { &tlcs900h_device::_SBCWMR, _M, _C16, 6 }, { &tlcs900h_device::_SBCWMR, _M, _C16, 6 }, + { &tlcs900h_device::_SBCWMR, _M, _C16, 6 }, { &tlcs900h_device::_SBCWMR, _M, _C16, 6 }, { &tlcs900h_device::_SBCWMR, _M, _C16, 6 }, { &tlcs900h_device::_SBCWMR, _M, _C16, 6 }, + + /* C0 - DF */ + { &tlcs900h_device::_ANDWRM, _C16, _M, 4 }, { &tlcs900h_device::_ANDWRM, _C16, _M, 4 }, { &tlcs900h_device::_ANDWRM, _C16, _M, 4 }, { &tlcs900h_device::_ANDWRM, _C16, _M, 4 }, + { &tlcs900h_device::_ANDWRM, _C16, _M, 4 }, { &tlcs900h_device::_ANDWRM, _C16, _M, 4 }, { &tlcs900h_device::_ANDWRM, _C16, _M, 4 }, { &tlcs900h_device::_ANDWRM, _C16, _M, 4 }, + { &tlcs900h_device::_ANDWMR, _M, _C16, 6 }, { &tlcs900h_device::_ANDWMR, _M, _C16, 6 }, { &tlcs900h_device::_ANDWMR, _M, _C16, 6 }, { &tlcs900h_device::_ANDWMR, _M, _C16, 6 }, + { &tlcs900h_device::_ANDWMR, _M, _C16, 6 }, { &tlcs900h_device::_ANDWMR, _M, _C16, 6 }, { &tlcs900h_device::_ANDWMR, _M, _C16, 6 }, { &tlcs900h_device::_ANDWMR, _M, _C16, 6 }, + { &tlcs900h_device::_XORWRM, _C16, _M, 4 }, { &tlcs900h_device::_XORWRM, _C16, _M, 4 }, { &tlcs900h_device::_XORWRM, _C16, _M, 4 }, { &tlcs900h_device::_XORWRM, _C16, _M, 4 }, + { &tlcs900h_device::_XORWRM, _C16, _M, 4 }, { &tlcs900h_device::_XORWRM, _C16, _M, 4 }, { &tlcs900h_device::_XORWRM, _C16, _M, 4 }, { &tlcs900h_device::_XORWRM, _C16, _M, 4 }, + { &tlcs900h_device::_XORWMR, _M, _C16, 6 }, { &tlcs900h_device::_XORWMR, _M, _C16, 6 }, { &tlcs900h_device::_XORWMR, _M, _C16, 6 }, { &tlcs900h_device::_XORWMR, _M, _C16, 6 }, + { &tlcs900h_device::_XORWMR, _M, _C16, 6 }, { &tlcs900h_device::_XORWMR, _M, _C16, 6 }, { &tlcs900h_device::_XORWMR, _M, _C16, 6 }, { &tlcs900h_device::_XORWMR, _M, _C16, 6 }, + + /* E0 - FF */ + { &tlcs900h_device::_ORWRM, _C16, _M, 4 }, { &tlcs900h_device::_ORWRM, _C16, _M, 4 }, { &tlcs900h_device::_ORWRM, _C16, _M, 4 }, { &tlcs900h_device::_ORWRM, _C16, _M, 4 }, + { &tlcs900h_device::_ORWRM, _C16, _M, 4 }, { &tlcs900h_device::_ORWRM, _C16, _M, 4 }, { &tlcs900h_device::_ORWRM, _C16, _M, 4 }, { &tlcs900h_device::_ORWRM, _C16, _M, 4 }, + { &tlcs900h_device::_ORWMR, _M, _C16, 6 }, { &tlcs900h_device::_ORWMR, _M, _C16, 6 }, { &tlcs900h_device::_ORWMR, _M, _C16, 6 }, { &tlcs900h_device::_ORWMR, _M, _C16, 6 }, + { &tlcs900h_device::_ORWMR, _M, _C16, 6 }, { &tlcs900h_device::_ORWMR, _M, _C16, 6 }, { &tlcs900h_device::_ORWMR, _M, _C16, 6 }, { &tlcs900h_device::_ORWMR, _M, _C16, 6 }, + { &tlcs900h_device::_CPWRM, _C16, _M, 4 }, { &tlcs900h_device::_CPWRM, _C16, _M, 4 }, { &tlcs900h_device::_CPWRM, _C16, _M, 4 }, { &tlcs900h_device::_CPWRM, _C16, _M, 4 }, + { &tlcs900h_device::_CPWRM, _C16, _M, 4 }, { &tlcs900h_device::_CPWRM, _C16, _M, 4 }, { &tlcs900h_device::_CPWRM, _C16, _M, 4 }, { &tlcs900h_device::_CPWRM, _C16, _M, 4 }, + { &tlcs900h_device::_CPWMR, _M, _C16, 6 }, { &tlcs900h_device::_CPWMR, _M, _C16, 6 }, { &tlcs900h_device::_CPWMR, _M, _C16, 6 }, { &tlcs900h_device::_CPWMR, _M, _C16, 6 }, + { &tlcs900h_device::_CPWMR, _M, _C16, 6 }, { &tlcs900h_device::_CPWMR, _M, _C16, 6 }, { &tlcs900h_device::_CPWMR, _M, _C16, 6 }, { &tlcs900h_device::_CPWMR, _M, _C16, 6 }, +}; + + +const tlcs900h_device::tlcs900inst tlcs900h_device::s_mnemonic_a0[256] = +{ + /* 00 - 1F */ + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + + /* 20 - 3F */ + { &tlcs900h_device::_LDLRM, _C32, _M, 6 }, { &tlcs900h_device::_LDLRM, _C32, _M, 6 }, { &tlcs900h_device::_LDLRM, _C32, _M, 6 }, { &tlcs900h_device::_LDLRM, _C32, _M, 6 }, + { &tlcs900h_device::_LDLRM, _C32, _M, 6 }, { &tlcs900h_device::_LDLRM, _C32, _M, 6 }, { &tlcs900h_device::_LDLRM, _C32, _M, 6 }, { &tlcs900h_device::_LDLRM, _C32, _M, 6 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + + /* 40 - 5F */ + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + + /* 60 - 7F */ + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + + /* 80 - 9F */ + { &tlcs900h_device::_ADDLRM, _C32, _M, 6 }, { &tlcs900h_device::_ADDLRM, _C32, _M, 6 }, { &tlcs900h_device::_ADDLRM, _C32, _M, 6 }, { &tlcs900h_device::_ADDLRM, _C32, _M, 6 }, + { &tlcs900h_device::_ADDLRM, _C32, _M, 6 }, { &tlcs900h_device::_ADDLRM, _C32, _M, 6 }, { &tlcs900h_device::_ADDLRM, _C32, _M, 6 }, { &tlcs900h_device::_ADDLRM, _C32, _M, 6 }, + { &tlcs900h_device::_ADDLMR, _M, _C32, 10 }, { &tlcs900h_device::_ADDLMR, _M, _C32, 10 }, { &tlcs900h_device::_ADDLMR, _M, _C32, 10 }, { &tlcs900h_device::_ADDLMR, _M, _C32, 10 }, + { &tlcs900h_device::_ADDLMR, _M, _C32, 10 }, { &tlcs900h_device::_ADDLMR, _M, _C32, 10 }, { &tlcs900h_device::_ADDLMR, _M, _C32, 10 }, { &tlcs900h_device::_ADDLMR, _M, _C32, 10 }, + { &tlcs900h_device::_ADCLRM, _C32, _M, 6 }, { &tlcs900h_device::_ADCLRM, _C32, _M, 6 }, { &tlcs900h_device::_ADCLRM, _C32, _M, 6 }, { &tlcs900h_device::_ADCLRM, _C32, _M, 6 }, + { &tlcs900h_device::_ADCLRM, _C32, _M, 6 }, { &tlcs900h_device::_ADCLRM, _C32, _M, 6 }, { &tlcs900h_device::_ADCLRM, _C32, _M, 6 }, { &tlcs900h_device::_ADCLRM, _C32, _M, 6 }, + { &tlcs900h_device::_ADCLMR, _M, _C32, 10 }, { &tlcs900h_device::_ADCLMR, _M, _C32, 10 }, { &tlcs900h_device::_ADCLMR, _M, _C32, 10 }, { &tlcs900h_device::_ADCLMR, _M, _C32, 10 }, + { &tlcs900h_device::_ADCLMR, _M, _C32, 10 }, { &tlcs900h_device::_ADCLMR, _M, _C32, 10 }, { &tlcs900h_device::_ADCLMR, _M, _C32, 10 }, { &tlcs900h_device::_ADCLMR, _M, _C32, 10 }, + + /* A0 - BF */ + { &tlcs900h_device::_SUBLRM, _C32, _M, 6 }, { &tlcs900h_device::_SUBLRM, _C32, _M, 6 }, { &tlcs900h_device::_SUBLRM, _C32, _M, 6 }, { &tlcs900h_device::_SUBLRM, _C32, _M, 6 }, + { &tlcs900h_device::_SUBLRM, _C32, _M, 6 }, { &tlcs900h_device::_SUBLRM, _C32, _M, 6 }, { &tlcs900h_device::_SUBLRM, _C32, _M, 6 }, { &tlcs900h_device::_SUBLRM, _C32, _M, 6 }, + { &tlcs900h_device::_SUBLMR, _M, _C32, 10 }, { &tlcs900h_device::_SUBLMR, _M, _C32, 10 }, { &tlcs900h_device::_SUBLMR, _M, _C32, 10 }, { &tlcs900h_device::_SUBLMR, _M, _C32, 10 }, + { &tlcs900h_device::_SUBLMR, _M, _C32, 10 }, { &tlcs900h_device::_SUBLMR, _M, _C32, 10 }, { &tlcs900h_device::_SUBLMR, _M, _C32, 10 }, { &tlcs900h_device::_SUBLMR, _M, _C32, 10 }, + { &tlcs900h_device::_SBCLRM, _C32, _M, 6 }, { &tlcs900h_device::_SBCLRM, _C32, _M, 6 }, { &tlcs900h_device::_SBCLRM, _C32, _M, 6 }, { &tlcs900h_device::_SBCLRM, _C32, _M, 6 }, + { &tlcs900h_device::_SBCLRM, _C32, _M, 6 }, { &tlcs900h_device::_SBCLRM, _C32, _M, 6 }, { &tlcs900h_device::_SBCLRM, _C32, _M, 6 }, { &tlcs900h_device::_SBCLRM, _C32, _M, 6 }, + { &tlcs900h_device::_SBCLMR, _M, _C32, 10 }, { &tlcs900h_device::_SBCLMR, _M, _C32, 10 }, { &tlcs900h_device::_SBCLMR, _M, _C32, 10 }, { &tlcs900h_device::_SBCLMR, _M, _C32, 10 }, + { &tlcs900h_device::_SBCLMR, _M, _C32, 10 }, { &tlcs900h_device::_SBCLMR, _M, _C32, 10 }, { &tlcs900h_device::_SBCLMR, _M, _C32, 10 }, { &tlcs900h_device::_SBCLMR, _M, _C32, 10 }, + + /* C0 - DF */ + { &tlcs900h_device::_ANDLRM, _C32, _M, 6 }, { &tlcs900h_device::_ANDLRM, _C32, _M, 6 }, { &tlcs900h_device::_ANDLRM, _C32, _M, 6 }, { &tlcs900h_device::_ANDLRM, _C32, _M, 6 }, + { &tlcs900h_device::_ANDLRM, _C32, _M, 6 }, { &tlcs900h_device::_ANDLRM, _C32, _M, 6 }, { &tlcs900h_device::_ANDLRM, _C32, _M, 6 }, { &tlcs900h_device::_ANDLRM, _C32, _M, 6 }, + { &tlcs900h_device::_ANDLMR, _M, _C32, 10 }, { &tlcs900h_device::_ANDLMR, _M, _C32, 10 }, { &tlcs900h_device::_ANDLMR, _M, _C32, 10 }, { &tlcs900h_device::_ANDLMR, _M, _C32, 10 }, + { &tlcs900h_device::_ANDLMR, _M, _C32, 10 }, { &tlcs900h_device::_ANDLMR, _M, _C32, 10 }, { &tlcs900h_device::_ANDLMR, _M, _C32, 10 }, { &tlcs900h_device::_ANDLMR, _M, _C32, 10 }, + { &tlcs900h_device::_XORLRM, _C32, _M, 6 }, { &tlcs900h_device::_XORLRM, _C32, _M, 6 }, { &tlcs900h_device::_XORLRM, _C32, _M, 6 }, { &tlcs900h_device::_XORLRM, _C32, _M, 6 }, + { &tlcs900h_device::_XORLRM, _C32, _M, 6 }, { &tlcs900h_device::_XORLRM, _C32, _M, 6 }, { &tlcs900h_device::_XORLRM, _C32, _M, 6 }, { &tlcs900h_device::_XORLRM, _C32, _M, 6 }, + { &tlcs900h_device::_XORLMR, _M, _C32, 10 }, { &tlcs900h_device::_XORLMR, _M, _C32, 10 }, { &tlcs900h_device::_XORLMR, _M, _C32, 10 }, { &tlcs900h_device::_XORLMR, _M, _C32, 10 }, + { &tlcs900h_device::_XORLMR, _M, _C32, 10 }, { &tlcs900h_device::_XORLMR, _M, _C32, 10 }, { &tlcs900h_device::_XORLMR, _M, _C32, 10 }, { &tlcs900h_device::_XORLMR, _M, _C32, 10 }, + + /* E0 - FF */ + { &tlcs900h_device::_ORLRM, _C32, _M, 6 }, { &tlcs900h_device::_ORLRM, _C32, _M, 6 }, { &tlcs900h_device::_ORLRM, _C32, _M, 6 }, { &tlcs900h_device::_ORLRM, _C32, _M, 6 }, + { &tlcs900h_device::_ORLRM, _C32, _M, 6 }, { &tlcs900h_device::_ORLRM, _C32, _M, 6 }, { &tlcs900h_device::_ORLRM, _C32, _M, 6 }, { &tlcs900h_device::_ORLRM, _C32, _M, 6 }, + { &tlcs900h_device::_ORLMR, _M, _C32, 10 }, { &tlcs900h_device::_ORLMR, _M, _C32, 10 }, { &tlcs900h_device::_ORLMR, _M, _C32, 10 }, { &tlcs900h_device::_ORLMR, _M, _C32, 10 }, + { &tlcs900h_device::_ORLMR, _M, _C32, 10 }, { &tlcs900h_device::_ORLMR, _M, _C32, 10 }, { &tlcs900h_device::_ORLMR, _M, _C32, 10 }, { &tlcs900h_device::_ORLMR, _M, _C32, 10 }, + { &tlcs900h_device::_CPLRM, _C32, _M, 6 }, { &tlcs900h_device::_CPLRM, _C32, _M, 6 }, { &tlcs900h_device::_CPLRM, _C32, _M, 6 }, { &tlcs900h_device::_CPLRM, _C32, _M, 6 }, + { &tlcs900h_device::_CPLRM, _C32, _M, 6 }, { &tlcs900h_device::_CPLRM, _C32, _M, 6 }, { &tlcs900h_device::_CPLRM, _C32, _M, 6 }, { &tlcs900h_device::_CPLRM, _C32, _M, 6 }, + { &tlcs900h_device::_CPLMR, _M, _C32, 6 }, { &tlcs900h_device::_CPLMR, _M, _C32, 6 }, { &tlcs900h_device::_CPLMR, _M, _C32, 6 }, { &tlcs900h_device::_CPLMR, _M, _C32, 6 }, + { &tlcs900h_device::_CPLMR, _M, _C32, 6 }, { &tlcs900h_device::_CPLMR, _M, _C32, 6 }, { &tlcs900h_device::_CPLMR, _M, _C32, 6 }, { &tlcs900h_device::_CPLMR, _M, _C32, 6 }, +}; + + +const tlcs900h_device::tlcs900inst tlcs900h_device::s_mnemonic_b0[256] = +{ + /* 00 - 1F */ + { &tlcs900h_device::_LDBMI, _M, _I8, 5 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_LDWMI, _M, _I16, 6 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_POPBM, _M, 0, 6 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_POPWM, _M, 0, 6 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_LDBMM, _M, _M16, 8 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_LDWMM, _M, _M16, 8 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + + /* 20 - 3F */ + { &tlcs900h_device::_LDAW, _C16, _M, 4 }, { &tlcs900h_device::_LDAW, _C16, _M, 4 }, { &tlcs900h_device::_LDAW, _C16, _M, 4 }, { &tlcs900h_device::_LDAW, _C16, _M, 4 }, + { &tlcs900h_device::_LDAW, _C16, _M, 4 }, { &tlcs900h_device::_LDAW, _C16, _M, 4 }, { &tlcs900h_device::_LDAW, _C16, _M, 4 }, { &tlcs900h_device::_LDAW, _C16, _M, 4 }, + { &tlcs900h_device::_ANDCFBRM, _A, _M, 8 }, { &tlcs900h_device::_ORCFBRM, _A, _M, 8 }, { &tlcs900h_device::_XORCFBRM, _A, _M, 8 }, { &tlcs900h_device::_LDCFBRM, _A, _M, 8 }, + { &tlcs900h_device::_STCFBRM, _A, _M, 8 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_LDAL, _C32, _M, 4 }, { &tlcs900h_device::_LDAL, _C32, _M, 4 }, { &tlcs900h_device::_LDAL, _C32, _M, 4 }, { &tlcs900h_device::_LDAL, _C32, _M, 4 }, + { &tlcs900h_device::_LDAL, _C32, _M, 4 }, { &tlcs900h_device::_LDAL, _C32, _M, 4 }, { &tlcs900h_device::_LDAL, _C32, _M, 4 }, { &tlcs900h_device::_LDAL, _C32, _M, 4 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + + /* 40 - 5F */ + { &tlcs900h_device::_LDBMR, _M, _C8, 4 }, { &tlcs900h_device::_LDBMR, _M, _C8, 4 }, { &tlcs900h_device::_LDBMR, _M, _C8, 4 }, { &tlcs900h_device::_LDBMR, _M, _C8, 4 }, + { &tlcs900h_device::_LDBMR, _M, _C8, 4 }, { &tlcs900h_device::_LDBMR, _M, _C8, 4 }, { &tlcs900h_device::_LDBMR, _M, _C8, 4 }, { &tlcs900h_device::_LDBMR, _M, _C8, 4 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_LDWMR, _M, _C16, 4 }, { &tlcs900h_device::_LDWMR, _M, _C16, 4 }, { &tlcs900h_device::_LDWMR, _M, _C16, 4 }, { &tlcs900h_device::_LDWMR, _M, _C16, 4 }, + { &tlcs900h_device::_LDWMR, _M, _C16, 4 }, { &tlcs900h_device::_LDWMR, _M, _C16, 4 }, { &tlcs900h_device::_LDWMR, _M, _C16, 4 }, { &tlcs900h_device::_LDWMR, _M, _C16, 4 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + + /* 60 - 7F */ + { &tlcs900h_device::_LDLMR, _M, _C32, 6 }, { &tlcs900h_device::_LDLMR, _M, _C32, 6 }, { &tlcs900h_device::_LDLMR, _M, _C32, 6 }, { &tlcs900h_device::_LDLMR, _M, _C32, 6 }, + { &tlcs900h_device::_LDLMR, _M, _C32, 6 }, { &tlcs900h_device::_LDLMR, _M, _C32, 6 }, { &tlcs900h_device::_LDLMR, _M, _C32, 6 }, { &tlcs900h_device::_LDLMR, _M, _C32, 6 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + + /* 80 - 9F */ + { &tlcs900h_device::_ANDCFBIM, _I3, _M, 8 }, { &tlcs900h_device::_ANDCFBIM, _I3, _M, 8 }, { &tlcs900h_device::_ANDCFBIM, _I3, _M, 8 }, { &tlcs900h_device::_ANDCFBIM, _I3, _M, 8 }, + { &tlcs900h_device::_ANDCFBIM, _I3, _M, 8 }, { &tlcs900h_device::_ANDCFBIM, _I3, _M, 8 }, { &tlcs900h_device::_ANDCFBIM, _I3, _M, 8 }, { &tlcs900h_device::_ANDCFBIM, _I3, _M, 8 }, + { &tlcs900h_device::_ORCFBIM, _I3, _M, 8 }, { &tlcs900h_device::_ORCFBIM, _I3, _M, 8 }, { &tlcs900h_device::_ORCFBIM, _I3, _M, 8 }, { &tlcs900h_device::_ORCFBIM, _I3, _M, 8 }, + { &tlcs900h_device::_ORCFBIM, _I3, _M, 8 }, { &tlcs900h_device::_ORCFBIM, _I3, _M, 8 }, { &tlcs900h_device::_ORCFBIM, _I3, _M, 8 }, { &tlcs900h_device::_ORCFBIM, _I3, _M, 8 }, + { &tlcs900h_device::_XORCFBIM, _I3, _M, 8 }, { &tlcs900h_device::_XORCFBIM, _I3, _M, 8 }, { &tlcs900h_device::_XORCFBIM, _I3, _M, 8 }, { &tlcs900h_device::_XORCFBIM, _I3, _M, 8 }, + { &tlcs900h_device::_XORCFBIM, _I3, _M, 8 }, { &tlcs900h_device::_XORCFBIM, _I3, _M, 8 }, { &tlcs900h_device::_XORCFBIM, _I3, _M, 8 }, { &tlcs900h_device::_XORCFBIM, _I3, _M, 8 }, + { &tlcs900h_device::_LDCFBIM, _I3, _M, 8 }, { &tlcs900h_device::_LDCFBIM, _I3, _M, 8 }, { &tlcs900h_device::_LDCFBIM, _I3, _M, 8 }, { &tlcs900h_device::_LDCFBIM, _I3, _M, 8 }, + { &tlcs900h_device::_LDCFBIM, _I3, _M, 8 }, { &tlcs900h_device::_LDCFBIM, _I3, _M, 8 }, { &tlcs900h_device::_LDCFBIM, _I3, _M, 8 }, { &tlcs900h_device::_LDCFBIM, _I3, _M, 8 }, + + /* A0 - BF */ + { &tlcs900h_device::_STCFBIM, _I3, _M, 8 }, { &tlcs900h_device::_STCFBIM, _I3, _M, 8 }, { &tlcs900h_device::_STCFBIM, _I3, _M, 8 }, { &tlcs900h_device::_STCFBIM, _I3, _M, 8 }, + { &tlcs900h_device::_STCFBIM, _I3, _M, 8 }, { &tlcs900h_device::_STCFBIM, _I3, _M, 8 }, { &tlcs900h_device::_STCFBIM, _I3, _M, 8 }, { &tlcs900h_device::_STCFBIM, _I3, _M, 8 }, + { &tlcs900h_device::_TSETBIM, _I3, _M, 10 }, { &tlcs900h_device::_TSETBIM, _I3, _M, 10 }, { &tlcs900h_device::_TSETBIM, _I3, _M, 10 }, { &tlcs900h_device::_TSETBIM, _I3, _M, 10 }, + { &tlcs900h_device::_TSETBIM, _I3, _M, 10 }, { &tlcs900h_device::_TSETBIM, _I3, _M, 10 }, { &tlcs900h_device::_TSETBIM, _I3, _M, 10 }, { &tlcs900h_device::_TSETBIM, _I3, _M, 10 }, + { &tlcs900h_device::_RESBIM, _I3, _M, 8 }, { &tlcs900h_device::_RESBIM, _I3, _M, 8 }, { &tlcs900h_device::_RESBIM, _I3, _M, 8 }, { &tlcs900h_device::_RESBIM, _I3, _M, 8 }, + { &tlcs900h_device::_RESBIM, _I3, _M, 8 }, { &tlcs900h_device::_RESBIM, _I3, _M, 8 }, { &tlcs900h_device::_RESBIM, _I3, _M, 8 }, { &tlcs900h_device::_RESBIM, _I3, _M, 8 }, + { &tlcs900h_device::_SETBIM, _I3, _M, 8 }, { &tlcs900h_device::_SETBIM, _I3, _M, 8 }, { &tlcs900h_device::_SETBIM, _I3, _M, 8 }, { &tlcs900h_device::_SETBIM, _I3, _M, 8 }, + { &tlcs900h_device::_SETBIM, _I3, _M, 8 }, { &tlcs900h_device::_SETBIM, _I3, _M, 8 }, { &tlcs900h_device::_SETBIM, _I3, _M, 8 }, { &tlcs900h_device::_SETBIM, _I3, _M, 8 }, + + /* C0 - DF */ + { &tlcs900h_device::_CHGBIM, _I3, _M, 8 }, { &tlcs900h_device::_CHGBIM, _I3, _M, 8 }, { &tlcs900h_device::_CHGBIM, _I3, _M, 8 }, { &tlcs900h_device::_CHGBIM, _I3, _M, 8 }, + { &tlcs900h_device::_CHGBIM, _I3, _M, 8 }, { &tlcs900h_device::_CHGBIM, _I3, _M, 8 }, { &tlcs900h_device::_CHGBIM, _I3, _M, 8 }, { &tlcs900h_device::_CHGBIM, _I3, _M, 8 }, + { &tlcs900h_device::_BITBIM, _I3, _M, 8 }, { &tlcs900h_device::_BITBIM, _I3, _M, 8 }, { &tlcs900h_device::_BITBIM, _I3, _M, 8 }, { &tlcs900h_device::_BITBIM, _I3, _M, 8 }, + { &tlcs900h_device::_BITBIM, _I3, _M, 8 }, { &tlcs900h_device::_BITBIM, _I3, _M, 8 }, { &tlcs900h_device::_BITBIM, _I3, _M, 8 }, { &tlcs900h_device::_BITBIM, _I3, _M, 8 }, + { &tlcs900h_device::_JPM, _CC, _M, 4 }, { &tlcs900h_device::_JPM, _CC, _M, 4 }, { &tlcs900h_device::_JPM, _CC, _M, 4 }, { &tlcs900h_device::_JPM, _CC, _M, 4 }, + { &tlcs900h_device::_JPM, _CC, _M, 4 }, { &tlcs900h_device::_JPM, _CC, _M, 4 }, { &tlcs900h_device::_JPM, _CC, _M, 4 }, { &tlcs900h_device::_JPM, _CC, _M, 4 }, + { &tlcs900h_device::_JPM, _CC, _M, 4 }, { &tlcs900h_device::_JPM, _CC, _M, 4 }, { &tlcs900h_device::_JPM, _CC, _M, 4 }, { &tlcs900h_device::_JPM, _CC, _M, 4 }, + { &tlcs900h_device::_JPM, _CC, _M, 4 }, { &tlcs900h_device::_JPM, _CC, _M, 4 }, { &tlcs900h_device::_JPM, _CC, _M, 4 }, { &tlcs900h_device::_JPM, _CC, _M, 4 }, + + /* E0 - FF */ + { &tlcs900h_device::_CALLM, _CC, _M, 6 }, { &tlcs900h_device::_CALLM, _CC, _M, 6 }, { &tlcs900h_device::_CALLM, _CC, _M, 6 }, { &tlcs900h_device::_CALLM, _CC, _M, 6 }, + { &tlcs900h_device::_CALLM, _CC, _M, 6 }, { &tlcs900h_device::_CALLM, _CC, _M, 6 }, { &tlcs900h_device::_CALLM, _CC, _M, 6 }, { &tlcs900h_device::_CALLM, _CC, _M, 6 }, + { &tlcs900h_device::_CALLM, _CC, _M, 6 }, { &tlcs900h_device::_CALLM, _CC, _M, 6 }, { &tlcs900h_device::_CALLM, _CC, _M, 6 }, { &tlcs900h_device::_CALLM, _CC, _M, 6 }, + { &tlcs900h_device::_CALLM, _CC, _M, 6 }, { &tlcs900h_device::_CALLM, _CC, _M, 6 }, { &tlcs900h_device::_CALLM, _CC, _M, 6 }, { &tlcs900h_device::_CALLM, _CC, _M, 6 }, + { &tlcs900h_device::_RETCC, _CC, 0, 6 }, { &tlcs900h_device::_RETCC, _CC, 0, 6 }, { &tlcs900h_device::_RETCC, _CC, 0, 6 }, { &tlcs900h_device::_RETCC, _CC, 0, 6 }, + { &tlcs900h_device::_RETCC, _CC, 0, 6 }, { &tlcs900h_device::_RETCC, _CC, 0, 6 }, { &tlcs900h_device::_RETCC, _CC, 0, 6 }, { &tlcs900h_device::_RETCC, _CC, 0, 6 }, + { &tlcs900h_device::_RETCC, _CC, 0, 6 }, { &tlcs900h_device::_RETCC, _CC, 0, 6 }, { &tlcs900h_device::_RETCC, _CC, 0, 6 }, { &tlcs900h_device::_RETCC, _CC, 0, 6 }, + { &tlcs900h_device::_RETCC, _CC, 0, 6 }, { &tlcs900h_device::_RETCC, _CC, 0, 6 }, { &tlcs900h_device::_RETCC, _CC, 0, 6 }, { &tlcs900h_device::_RETCC, _CC, 0, 6 } +}; + + +const tlcs900h_device::tlcs900inst tlcs900h_device::s_mnemonic_b8[256] = +{ + /* 00 - 1F */ + { &tlcs900h_device::_LDBMI, _M, _I8, 5 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_LDWMI, _M, _I16, 6 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_POPBM, _M, 0, 6 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_POPWM, _M, 0, 6 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_LDBMM, _M, _M16, 8 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_LDWMM, _M, _M16, 8 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + + /* 20 - 3F */ + { &tlcs900h_device::_LDAW, _C16, _M, 4 }, { &tlcs900h_device::_LDAW, _C16, _M, 4 }, { &tlcs900h_device::_LDAW, _C16, _M, 4 }, { &tlcs900h_device::_LDAW, _C16, _M, 4 }, + { &tlcs900h_device::_LDAW, _C16, _M, 4 }, { &tlcs900h_device::_LDAW, _C16, _M, 4 }, { &tlcs900h_device::_LDAW, _C16, _M, 4 }, { &tlcs900h_device::_LDAW, _C16, _M, 4 }, + { &tlcs900h_device::_ANDCFBRM, _A, _M, 8 }, { &tlcs900h_device::_ORCFBRM, _A, _M, 8 }, { &tlcs900h_device::_XORCFBRM, _A, _M, 8 }, { &tlcs900h_device::_LDCFBRM, _A, _M, 8 }, + { &tlcs900h_device::_STCFBRM, _A, _M, 8 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_LDAL, _C32, _M, 4 }, { &tlcs900h_device::_LDAL, _C32, _M, 4 }, { &tlcs900h_device::_LDAL, _C32, _M, 4 }, { &tlcs900h_device::_LDAL, _C32, _M, 4 }, + { &tlcs900h_device::_LDAL, _C32, _M, 4 }, { &tlcs900h_device::_LDAL, _C32, _M, 4 }, { &tlcs900h_device::_LDAL, _C32, _M, 4 }, { &tlcs900h_device::_LDAL, _C32, _M, 4 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + + /* 40 - 5F */ + { &tlcs900h_device::_LDBMR, _M, _C8, 4 }, { &tlcs900h_device::_LDBMR, _M, _C8, 4 }, { &tlcs900h_device::_LDBMR, _M, _C8, 4 }, { &tlcs900h_device::_LDBMR, _M, _C8, 4 }, + { &tlcs900h_device::_LDBMR, _M, _C8, 4 }, { &tlcs900h_device::_LDBMR, _M, _C8, 4 }, { &tlcs900h_device::_LDBMR, _M, _C8, 4 }, { &tlcs900h_device::_LDBMR, _M, _C8, 4 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_LDWMR, _M, _C16, 4 }, { &tlcs900h_device::_LDWMR, _M, _C16, 4 }, { &tlcs900h_device::_LDWMR, _M, _C16, 4 }, { &tlcs900h_device::_LDWMR, _M, _C16, 4 }, + { &tlcs900h_device::_LDWMR, _M, _C16, 4 }, { &tlcs900h_device::_LDWMR, _M, _C16, 4 }, { &tlcs900h_device::_LDWMR, _M, _C16, 4 }, { &tlcs900h_device::_LDWMR, _M, _C16, 4 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + + /* 60 - 7F */ + { &tlcs900h_device::_LDLMR, _M, _C32, 6 }, { &tlcs900h_device::_LDLMR, _M, _C32, 6 }, { &tlcs900h_device::_LDLMR, _M, _C32, 6 }, { &tlcs900h_device::_LDLMR, _M, _C32, 6 }, + { &tlcs900h_device::_LDLMR, _M, _C32, 6 }, { &tlcs900h_device::_LDLMR, _M, _C32, 6 }, { &tlcs900h_device::_LDLMR, _M, _C32, 6 }, { &tlcs900h_device::_LDLMR, _M, _C32, 6 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + + /* 80 - 9F */ + { &tlcs900h_device::_ANDCFBIM, _I3, _M, 8 }, { &tlcs900h_device::_ANDCFBIM, _I3, _M, 8 }, { &tlcs900h_device::_ANDCFBIM, _I3, _M, 8 }, { &tlcs900h_device::_ANDCFBIM, _I3, _M, 8 }, + { &tlcs900h_device::_ANDCFBIM, _I3, _M, 8 }, { &tlcs900h_device::_ANDCFBIM, _I3, _M, 8 }, { &tlcs900h_device::_ANDCFBIM, _I3, _M, 8 }, { &tlcs900h_device::_ANDCFBIM, _I3, _M, 8 }, + { &tlcs900h_device::_ORCFBIM, _I3, _M, 8 }, { &tlcs900h_device::_ORCFBIM, _I3, _M, 8 }, { &tlcs900h_device::_ORCFBIM, _I3, _M, 8 }, { &tlcs900h_device::_ORCFBIM, _I3, _M, 8 }, + { &tlcs900h_device::_ORCFBIM, _I3, _M, 8 }, { &tlcs900h_device::_ORCFBIM, _I3, _M, 8 }, { &tlcs900h_device::_ORCFBIM, _I3, _M, 8 }, { &tlcs900h_device::_ORCFBIM, _I3, _M, 8 }, + { &tlcs900h_device::_XORCFBIM, _I3, _M, 8 }, { &tlcs900h_device::_XORCFBIM, _I3, _M, 8 }, { &tlcs900h_device::_XORCFBIM, _I3, _M, 8 }, { &tlcs900h_device::_XORCFBIM, _I3, _M, 8 }, + { &tlcs900h_device::_XORCFBIM, _I3, _M, 8 }, { &tlcs900h_device::_XORCFBIM, _I3, _M, 8 }, { &tlcs900h_device::_XORCFBIM, _I3, _M, 8 }, { &tlcs900h_device::_XORCFBIM, _I3, _M, 8 }, + { &tlcs900h_device::_LDCFBIM, _I3, _M, 8 }, { &tlcs900h_device::_LDCFBIM, _I3, _M, 8 }, { &tlcs900h_device::_LDCFBIM, _I3, _M, 8 }, { &tlcs900h_device::_LDCFBIM, _I3, _M, 8 }, + { &tlcs900h_device::_LDCFBIM, _I3, _M, 8 }, { &tlcs900h_device::_LDCFBIM, _I3, _M, 8 }, { &tlcs900h_device::_LDCFBIM, _I3, _M, 8 }, { &tlcs900h_device::_LDCFBIM, _I3, _M, 8 }, + + /* A0 - BF */ + { &tlcs900h_device::_STCFBIM, _I3, _M, 8 }, { &tlcs900h_device::_STCFBIM, _I3, _M, 8 }, { &tlcs900h_device::_STCFBIM, _I3, _M, 8 }, { &tlcs900h_device::_STCFBIM, _I3, _M, 8 }, + { &tlcs900h_device::_STCFBIM, _I3, _M, 8 }, { &tlcs900h_device::_STCFBIM, _I3, _M, 8 }, { &tlcs900h_device::_STCFBIM, _I3, _M, 8 }, { &tlcs900h_device::_STCFBIM, _I3, _M, 8 }, + { &tlcs900h_device::_TSETBIM, _I3, _M, 10 }, { &tlcs900h_device::_TSETBIM, _I3, _M, 10 }, { &tlcs900h_device::_TSETBIM, _I3, _M, 10 }, { &tlcs900h_device::_TSETBIM, _I3, _M, 10 }, + { &tlcs900h_device::_TSETBIM, _I3, _M, 10 }, { &tlcs900h_device::_TSETBIM, _I3, _M, 10 }, { &tlcs900h_device::_TSETBIM, _I3, _M, 10 }, { &tlcs900h_device::_TSETBIM, _I3, _M, 10 }, + { &tlcs900h_device::_RESBIM, _I3, _M, 8 }, { &tlcs900h_device::_RESBIM, _I3, _M, 8 }, { &tlcs900h_device::_RESBIM, _I3, _M, 8 }, { &tlcs900h_device::_RESBIM, _I3, _M, 8 }, + { &tlcs900h_device::_RESBIM, _I3, _M, 8 }, { &tlcs900h_device::_RESBIM, _I3, _M, 8 }, { &tlcs900h_device::_RESBIM, _I3, _M, 8 }, { &tlcs900h_device::_RESBIM, _I3, _M, 8 }, + { &tlcs900h_device::_SETBIM, _I3, _M, 8 }, { &tlcs900h_device::_SETBIM, _I3, _M, 8 }, { &tlcs900h_device::_SETBIM, _I3, _M, 8 }, { &tlcs900h_device::_SETBIM, _I3, _M, 8 }, + { &tlcs900h_device::_SETBIM, _I3, _M, 8 }, { &tlcs900h_device::_SETBIM, _I3, _M, 8 }, { &tlcs900h_device::_SETBIM, _I3, _M, 8 }, { &tlcs900h_device::_SETBIM, _I3, _M, 8 }, + + /* C0 - DF */ + { &tlcs900h_device::_CHGBIM, _I3, _M, 8 }, { &tlcs900h_device::_CHGBIM, _I3, _M, 8 }, { &tlcs900h_device::_CHGBIM, _I3, _M, 8 }, { &tlcs900h_device::_CHGBIM, _I3, _M, 8 }, + { &tlcs900h_device::_CHGBIM, _I3, _M, 8 }, { &tlcs900h_device::_CHGBIM, _I3, _M, 8 }, { &tlcs900h_device::_CHGBIM, _I3, _M, 8 }, { &tlcs900h_device::_CHGBIM, _I3, _M, 8 }, + { &tlcs900h_device::_BITBIM, _I3, _M, 8 }, { &tlcs900h_device::_BITBIM, _I3, _M, 8 }, { &tlcs900h_device::_BITBIM, _I3, _M, 8 }, { &tlcs900h_device::_BITBIM, _I3, _M, 8 }, + { &tlcs900h_device::_BITBIM, _I3, _M, 8 }, { &tlcs900h_device::_BITBIM, _I3, _M, 8 }, { &tlcs900h_device::_BITBIM, _I3, _M, 8 }, { &tlcs900h_device::_BITBIM, _I3, _M, 8 }, + { &tlcs900h_device::_JPM, _CC, _M, 4 }, { &tlcs900h_device::_JPM, _CC, _M, 4 }, { &tlcs900h_device::_JPM, _CC, _M, 4 }, { &tlcs900h_device::_JPM, _CC, _M, 4 }, + { &tlcs900h_device::_JPM, _CC, _M, 4 }, { &tlcs900h_device::_JPM, _CC, _M, 4 }, { &tlcs900h_device::_JPM, _CC, _M, 4 }, { &tlcs900h_device::_JPM, _CC, _M, 4 }, + { &tlcs900h_device::_JPM, _CC, _M, 4 }, { &tlcs900h_device::_JPM, _CC, _M, 4 }, { &tlcs900h_device::_JPM, _CC, _M, 4 }, { &tlcs900h_device::_JPM, _CC, _M, 4 }, + { &tlcs900h_device::_JPM, _CC, _M, 4 }, { &tlcs900h_device::_JPM, _CC, _M, 4 }, { &tlcs900h_device::_JPM, _CC, _M, 4 }, { &tlcs900h_device::_JPM, _CC, _M, 4 }, + + /* E0 - FF */ + { &tlcs900h_device::_CALLM, _CC, _M, 6 }, { &tlcs900h_device::_CALLM, _CC, _M, 6 }, { &tlcs900h_device::_CALLM, _CC, _M, 6 }, { &tlcs900h_device::_CALLM, _CC, _M, 6 }, + { &tlcs900h_device::_CALLM, _CC, _M, 6 }, { &tlcs900h_device::_CALLM, _CC, _M, 6 }, { &tlcs900h_device::_CALLM, _CC, _M, 6 }, { &tlcs900h_device::_CALLM, _CC, _M, 6 }, + { &tlcs900h_device::_CALLM, _CC, _M, 6 }, { &tlcs900h_device::_CALLM, _CC, _M, 6 }, { &tlcs900h_device::_CALLM, _CC, _M, 6 }, { &tlcs900h_device::_CALLM, _CC, _M, 6 }, + { &tlcs900h_device::_CALLM, _CC, _M, 6 }, { &tlcs900h_device::_CALLM, _CC, _M, 6 }, { &tlcs900h_device::_CALLM, _CC, _M, 6 }, { &tlcs900h_device::_CALLM, _CC, _M, 6 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 } +}; + + +const tlcs900h_device::tlcs900inst tlcs900h_device::s_mnemonic_c0[256] = +{ + /* 00 - 1F */ + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_PUSHBM, _M, 0, 7 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_RLDRM, _A, _M, 12 }, { &tlcs900h_device::_RRDRM, _A, _M, 12 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_LDBMM, _M16, _M, 8 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + + /* 20 - 3F */ + { &tlcs900h_device::_LDBRM, _C8, _M, 4 }, { &tlcs900h_device::_LDBRM, _C8, _M, 4 }, { &tlcs900h_device::_LDBRM, _C8, _M, 4 }, { &tlcs900h_device::_LDBRM, _C8, _M, 4 }, + { &tlcs900h_device::_LDBRM, _C8, _M, 4 }, { &tlcs900h_device::_LDBRM, _C8, _M, 4 }, { &tlcs900h_device::_LDBRM, _C8, _M, 4 }, { &tlcs900h_device::_LDBRM, _C8, _M, 4 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_EXBMR, _M, _C8, 6 }, { &tlcs900h_device::_EXBMR, _M, _C8, 6 }, { &tlcs900h_device::_EXBMR, _M, _C8, 6 }, { &tlcs900h_device::_EXBMR, _M, _C8, 6 }, + { &tlcs900h_device::_EXBMR, _M, _C8, 6 }, { &tlcs900h_device::_EXBMR, _M, _C8, 6 }, { &tlcs900h_device::_EXBMR, _M, _C8, 6 }, { &tlcs900h_device::_EXBMR, _M, _C8, 6 }, + { &tlcs900h_device::_ADDBMI, _M, _I8, 7 }, { &tlcs900h_device::_ADCBMI, _M, _I8, 7 }, { &tlcs900h_device::_SUBBMI, _M, _I8, 7 }, { &tlcs900h_device::_SBCBMI, _M, _I8, 7 }, + { &tlcs900h_device::_ANDBMI, _M, _I8, 7 }, { &tlcs900h_device::_XORBMI, _M, _I8, 7 }, { &tlcs900h_device::_ORBMI, _M, _I8, 7 }, { &tlcs900h_device::_CPBMI, _M, _I8, 6 }, + + /* 40 - 5F */ + { &tlcs900h_device::_MULBRM, _MC16, _M, 18 }, { &tlcs900h_device::_MULBRM, _MC16, _M, 18 }, { &tlcs900h_device::_MULBRM, _MC16, _M, 18 }, { &tlcs900h_device::_MULBRM, _MC16, _M, 18 }, + { &tlcs900h_device::_MULBRM, _MC16, _M, 18 }, { &tlcs900h_device::_MULBRM, _MC16, _M, 18 }, { &tlcs900h_device::_MULBRM, _MC16, _M, 18 }, { &tlcs900h_device::_MULBRM, _MC16, _M, 18 }, + { &tlcs900h_device::_MULSBRM, _MC16, _M, 18 }, { &tlcs900h_device::_MULSBRM, _MC16, _M, 18 }, { &tlcs900h_device::_MULSBRM, _MC16, _M, 18 }, { &tlcs900h_device::_MULSBRM, _MC16, _M, 18 }, + { &tlcs900h_device::_MULSBRM, _MC16, _M, 18 }, { &tlcs900h_device::_MULSBRM, _MC16, _M, 18 }, { &tlcs900h_device::_MULSBRM, _MC16, _M, 18 }, { &tlcs900h_device::_MULSBRM, _MC16, _M, 18 }, + { &tlcs900h_device::_DIVBRM, _MC16, _M, 22 }, { &tlcs900h_device::_DIVBRM, _MC16, _M, 22 }, { &tlcs900h_device::_DIVBRM, _MC16, _M, 22 }, { &tlcs900h_device::_DIVBRM, _MC16, _M, 22 }, + { &tlcs900h_device::_DIVBRM, _MC16, _M, 22 }, { &tlcs900h_device::_DIVBRM, _MC16, _M, 22 }, { &tlcs900h_device::_DIVBRM, _MC16, _M, 22 }, { &tlcs900h_device::_DIVBRM, _MC16, _M, 22 }, + { &tlcs900h_device::_DIVSBRM, _MC16, _M, 24 }, { &tlcs900h_device::_DIVSBRM, _MC16, _M, 24 }, { &tlcs900h_device::_DIVSBRM, _MC16, _M, 24 }, { &tlcs900h_device::_DIVSBRM, _MC16, _M, 24 }, + { &tlcs900h_device::_DIVSBRM, _MC16, _M, 24 }, { &tlcs900h_device::_DIVSBRM, _MC16, _M, 24 }, { &tlcs900h_device::_DIVSBRM, _MC16, _M, 24 }, { &tlcs900h_device::_DIVSBRM, _MC16, _M, 24 }, + + /* 60 - 7F */ + { &tlcs900h_device::_INCBIM, _I3, _M, 6 }, { &tlcs900h_device::_INCBIM, _I3, _M, 6 }, { &tlcs900h_device::_INCBIM, _I3, _M, 6 }, { &tlcs900h_device::_INCBIM, _I3, _M, 6 }, + { &tlcs900h_device::_INCBIM, _I3, _M, 6 }, { &tlcs900h_device::_INCBIM, _I3, _M, 6 }, { &tlcs900h_device::_INCBIM, _I3, _M, 6 }, { &tlcs900h_device::_INCBIM, _I3, _M, 6 }, + { &tlcs900h_device::_DECBIM, _I3, _M, 6 }, { &tlcs900h_device::_DECBIM, _I3, _M, 6 }, { &tlcs900h_device::_DECBIM, _I3, _M, 6 }, { &tlcs900h_device::_DECBIM, _I3, _M, 6 }, + { &tlcs900h_device::_DECBIM, _I3, _M, 6 }, { &tlcs900h_device::_DECBIM, _I3, _M, 6 }, { &tlcs900h_device::_DECBIM, _I3, _M, 6 }, { &tlcs900h_device::_DECBIM, _I3, _M, 6 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_RLCBM, _M, 0, 8 }, { &tlcs900h_device::_RRCBM, _M, 0, 8 }, { &tlcs900h_device::_RLBM, _M, 0, 8 }, { &tlcs900h_device::_RRBM, _M, 0, 8 }, + { &tlcs900h_device::_SLABM, _M, 0, 8 }, { &tlcs900h_device::_SRABM, _M, 0, 8 }, { &tlcs900h_device::_SLLBM, _M, 0, 8 }, { &tlcs900h_device::_SRLBM, _M, 0, 8 }, + + /* 80 - 9F */ + { &tlcs900h_device::_ADDBRM, _C8, _M, 4 }, { &tlcs900h_device::_ADDBRM, _C8, _M, 4 }, { &tlcs900h_device::_ADDBRM, _C8, _M, 4 }, { &tlcs900h_device::_ADDBRM, _C8, _M, 4 }, + { &tlcs900h_device::_ADDBRM, _C8, _M, 4 }, { &tlcs900h_device::_ADDBRM, _C8, _M, 4 }, { &tlcs900h_device::_ADDBRM, _C8, _M, 4 }, { &tlcs900h_device::_ADDBRM, _C8, _M, 4 }, + { &tlcs900h_device::_ADDBMR, _M, _C8, 6 }, { &tlcs900h_device::_ADDBMR, _M, _C8, 6 }, { &tlcs900h_device::_ADDBMR, _M, _C8, 6 }, { &tlcs900h_device::_ADDBMR, _M, _C8, 6 }, + { &tlcs900h_device::_ADDBMR, _M, _C8, 6 }, { &tlcs900h_device::_ADDBMR, _M, _C8, 6 }, { &tlcs900h_device::_ADDBMR, _M, _C8, 6 }, { &tlcs900h_device::_ADDBMR, _M, _C8, 6 }, + { &tlcs900h_device::_ADCBRM, _C8, _M, 4 }, { &tlcs900h_device::_ADCBRM, _C8, _M, 4 }, { &tlcs900h_device::_ADCBRM, _C8, _M, 4 }, { &tlcs900h_device::_ADCBRM, _C8, _M, 4 }, + { &tlcs900h_device::_ADCBRM, _C8, _M, 4 }, { &tlcs900h_device::_ADCBRM, _C8, _M, 4 }, { &tlcs900h_device::_ADCBRM, _C8, _M, 4 }, { &tlcs900h_device::_ADCBRM, _C8, _M, 4 }, + { &tlcs900h_device::_ADCBMR, _M, _C8, 6 }, { &tlcs900h_device::_ADCBMR, _M, _C8, 6 }, { &tlcs900h_device::_ADCBMR, _M, _C8, 6 }, { &tlcs900h_device::_ADCBMR, _M, _C8, 6 }, + { &tlcs900h_device::_ADCBMR, _M, _C8, 6 }, { &tlcs900h_device::_ADCBMR, _M, _C8, 6 }, { &tlcs900h_device::_ADCBMR, _M, _C8, 6 }, { &tlcs900h_device::_ADCBMR, _M, _C8, 6 }, + + /* A0 - BF */ + { &tlcs900h_device::_SUBBRM, _C8, _M, 4 }, { &tlcs900h_device::_SUBBRM, _C8, _M, 4 }, { &tlcs900h_device::_SUBBRM, _C8, _M, 4 }, { &tlcs900h_device::_SUBBRM, _C8, _M, 4 }, + { &tlcs900h_device::_SUBBRM, _C8, _M, 4 }, { &tlcs900h_device::_SUBBRM, _C8, _M, 4 }, { &tlcs900h_device::_SUBBRM, _C8, _M, 4 }, { &tlcs900h_device::_SUBBRM, _C8, _M, 4 }, + { &tlcs900h_device::_SUBBMR, _M, _C8, 6 }, { &tlcs900h_device::_SUBBMR, _M, _C8, 6 }, { &tlcs900h_device::_SUBBMR, _M, _C8, 6 }, { &tlcs900h_device::_SUBBMR, _M, _C8, 6 }, + { &tlcs900h_device::_SUBBMR, _M, _C8, 6 }, { &tlcs900h_device::_SUBBMR, _M, _C8, 6 }, { &tlcs900h_device::_SUBBMR, _M, _C8, 6 }, { &tlcs900h_device::_SUBBMR, _M, _C8, 6 }, + { &tlcs900h_device::_SBCBRM, _C8, _M, 4 }, { &tlcs900h_device::_SBCBRM, _C8, _M, 4 }, { &tlcs900h_device::_SBCBRM, _C8, _M, 4 }, { &tlcs900h_device::_SBCBRM, _C8, _M, 4 }, + { &tlcs900h_device::_SBCBRM, _C8, _M, 4 }, { &tlcs900h_device::_SBCBRM, _C8, _M, 4 }, { &tlcs900h_device::_SBCBRM, _C8, _M, 4 }, { &tlcs900h_device::_SBCBRM, _C8, _M, 4 }, + { &tlcs900h_device::_SBCBMR, _M, _C8, 6 }, { &tlcs900h_device::_SBCBMR, _M, _C8, 6 }, { &tlcs900h_device::_SBCBMR, _M, _C8, 6 }, { &tlcs900h_device::_SBCBMR, _M, _C8, 6 }, + { &tlcs900h_device::_SBCBMR, _M, _C8, 6 }, { &tlcs900h_device::_SBCBMR, _M, _C8, 6 }, { &tlcs900h_device::_SBCBMR, _M, _C8, 6 }, { &tlcs900h_device::_SBCBMR, _M, _C8, 6 }, + + /* C0 - DF */ + { &tlcs900h_device::_ANDBRM, _C8, _M, 4 }, { &tlcs900h_device::_ANDBRM, _C8, _M, 4 }, { &tlcs900h_device::_ANDBRM, _C8, _M, 4 }, { &tlcs900h_device::_ANDBRM, _C8, _M, 4 }, + { &tlcs900h_device::_ANDBRM, _C8, _M, 4 }, { &tlcs900h_device::_ANDBRM, _C8, _M, 4 }, { &tlcs900h_device::_ANDBRM, _C8, _M, 4 }, { &tlcs900h_device::_ANDBRM, _C8, _M, 4 }, + { &tlcs900h_device::_ANDBMR, _M, _C8, 6 }, { &tlcs900h_device::_ANDBMR, _M, _C8, 6 }, { &tlcs900h_device::_ANDBMR, _M, _C8, 6 }, { &tlcs900h_device::_ANDBMR, _M, _C8, 6 }, + { &tlcs900h_device::_ANDBMR, _M, _C8, 6 }, { &tlcs900h_device::_ANDBMR, _M, _C8, 6 }, { &tlcs900h_device::_ANDBMR, _M, _C8, 6 }, { &tlcs900h_device::_ANDBMR, _M, _C8, 6 }, + { &tlcs900h_device::_XORBRM, _C8, _M, 4 }, { &tlcs900h_device::_XORBRM, _C8, _M, 4 }, { &tlcs900h_device::_XORBRM, _C8, _M, 4 }, { &tlcs900h_device::_XORBRM, _C8, _M, 4 }, + { &tlcs900h_device::_XORBRM, _C8, _M, 4 }, { &tlcs900h_device::_XORBRM, _C8, _M, 4 }, { &tlcs900h_device::_XORBRM, _C8, _M, 4 }, { &tlcs900h_device::_XORBRM, _C8, _M, 4 }, + { &tlcs900h_device::_XORBMR, _M, _C8, 6 }, { &tlcs900h_device::_XORBMR, _M, _C8, 6 }, { &tlcs900h_device::_XORBMR, _M, _C8, 6 }, { &tlcs900h_device::_XORBMR, _M, _C8, 6 }, + { &tlcs900h_device::_XORBMR, _M, _C8, 6 }, { &tlcs900h_device::_XORBMR, _M, _C8, 6 }, { &tlcs900h_device::_XORBMR, _M, _C8, 6 }, { &tlcs900h_device::_XORBMR, _M, _C8, 6 }, + + /* E0 - FF */ + { &tlcs900h_device::_ORBRM, _C8, _M, 4 }, { &tlcs900h_device::_ORBRM, _C8, _M, 4 }, { &tlcs900h_device::_ORBRM, _C8, _M, 4 }, { &tlcs900h_device::_ORBRM, _C8, _M, 4 }, + { &tlcs900h_device::_ORBRM, _C8, _M, 4 }, { &tlcs900h_device::_ORBRM, _C8, _M, 4 }, { &tlcs900h_device::_ORBRM, _C8, _M, 4 }, { &tlcs900h_device::_ORBRM, _C8, _M, 4 }, + { &tlcs900h_device::_ORBMR, _M, _C8, 6 }, { &tlcs900h_device::_ORBMR, _M, _C8, 6 }, { &tlcs900h_device::_ORBMR, _M, _C8, 6 }, { &tlcs900h_device::_ORBMR, _M, _C8, 6 }, + { &tlcs900h_device::_ORBMR, _M, _C8, 6 }, { &tlcs900h_device::_ORBMR, _M, _C8, 6 }, { &tlcs900h_device::_ORBMR, _M, _C8, 6 }, { &tlcs900h_device::_ORBMR, _M, _C8, 6 }, + { &tlcs900h_device::_CPBRM, _C8, _M, 4 }, { &tlcs900h_device::_CPBRM, _C8, _M, 4 }, { &tlcs900h_device::_CPBRM, _C8, _M, 4 }, { &tlcs900h_device::_CPBRM, _C8, _M, 4 }, + { &tlcs900h_device::_CPBRM, _C8, _M, 4 }, { &tlcs900h_device::_CPBRM, _C8, _M, 4 }, { &tlcs900h_device::_CPBRM, _C8, _M, 4 }, { &tlcs900h_device::_CPBRM, _C8, _M, 4 }, + { &tlcs900h_device::_CPBMR, _M, _C8, 6 }, { &tlcs900h_device::_CPBMR, _M, _C8, 6 }, { &tlcs900h_device::_CPBMR, _M, _C8, 6 }, { &tlcs900h_device::_CPBMR, _M, _C8, 6 }, + { &tlcs900h_device::_CPBMR, _M, _C8, 6 }, { &tlcs900h_device::_CPBMR, _M, _C8, 6 }, { &tlcs900h_device::_CPBMR, _M, _C8, 6 }, { &tlcs900h_device::_CPBMR, _M, _C8, 6 }, +}; + + +const tlcs900h_device::tlcs900inst tlcs900h_device::s_mnemonic_c8[256] = +{ + /* 00 - 1F */ + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_LDBRI, _R, _I8, 4 }, + { &tlcs900h_device::_PUSHBR, _R, 0, 6 }, { &tlcs900h_device::_POPBR, _R, 0, 6 }, { &tlcs900h_device::_CPLBR, _R, 0, 4 }, { &tlcs900h_device::_NEGBR, _R, 0, 5 }, + { &tlcs900h_device::_MULBRI, _R, _I8, 18}, { &tlcs900h_device::_MULSBRI, _R, _I8, 18 }, { &tlcs900h_device::_DIVBRI, _R, _I8, 22 }, { &tlcs900h_device::_DIVSBRI, _R, _I8, 24 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DAABR, _R, 0, 6 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DJNZB, _R, _D8, 7 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + + /* 20 - 3F */ + { &tlcs900h_device::_ANDCFBIR, _I8, _R, 4 }, { &tlcs900h_device::_ORCFBIR, _I8, _R, 4 }, { &tlcs900h_device::_XORCFBIR, _I8, _R, 4 }, { &tlcs900h_device::_LDCFBIR, _I8, _R, 4 }, + { &tlcs900h_device::_STCFBIR, _I8, _R, 4 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_ANDCFBRR, _A, _R, 4 }, { &tlcs900h_device::_ORCFBRR, _A, _R, 4 }, { &tlcs900h_device::_XORCFBRR, _A, _R, 4 }, { &tlcs900h_device::_LDCFBRR, _A, _R, 4 }, + { &tlcs900h_device::_STCFBRR, _A, _R, 4 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_LDCBRR, _CR8, _R, 1 }, { &tlcs900h_device::_LDCBRR, _R, _CR8, 1 }, + { &tlcs900h_device::_RESBIR, _I8, _R, 4 }, { &tlcs900h_device::_SETBIR, _I8, _R, 4 }, { &tlcs900h_device::_CHGBIR, _I8, _R, 4 }, { &tlcs900h_device::_BITBIR, _I8, _R, 4 }, + { &tlcs900h_device::_TSETBIR, _I8, _R, 6 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + + /* 40 - 5F */ + { &tlcs900h_device::_MULBRR, _MC16, _R, 18 }, { &tlcs900h_device::_MULBRR, _MC16, _R, 18 }, { &tlcs900h_device::_MULBRR, _MC16, _R, 18 }, { &tlcs900h_device::_MULBRR, _MC16, _R, 18 }, + { &tlcs900h_device::_MULBRR, _MC16, _R, 18 }, { &tlcs900h_device::_MULBRR, _MC16, _R, 18 }, { &tlcs900h_device::_MULBRR, _MC16, _R, 18 }, { &tlcs900h_device::_MULBRR, _MC16, _R, 18 }, + { &tlcs900h_device::_MULSBRR, _MC16, _R, 18 }, { &tlcs900h_device::_MULSBRR, _MC16, _R, 18 }, { &tlcs900h_device::_MULSBRR, _MC16, _R, 18 }, { &tlcs900h_device::_MULSBRR, _MC16, _R, 18 }, + { &tlcs900h_device::_MULSBRR, _MC16, _R, 18 }, { &tlcs900h_device::_MULSBRR, _MC16, _R, 18 }, { &tlcs900h_device::_MULSBRR, _MC16, _R, 18 }, { &tlcs900h_device::_MULSBRR, _MC16, _R, 18 }, + { &tlcs900h_device::_DIVBRR, _MC16, _R, 22 }, { &tlcs900h_device::_DIVBRR, _MC16, _R, 22 }, { &tlcs900h_device::_DIVBRR, _MC16, _R, 22 }, { &tlcs900h_device::_DIVBRR, _MC16, _R, 22 }, + { &tlcs900h_device::_DIVBRR, _MC16, _R, 22 }, { &tlcs900h_device::_DIVBRR, _MC16, _R, 22 }, { &tlcs900h_device::_DIVBRR, _MC16, _R, 22 }, { &tlcs900h_device::_DIVBRR, _MC16, _R, 22 }, + { &tlcs900h_device::_DIVSBRR, _MC16, _R, 24 }, { &tlcs900h_device::_DIVSBRR, _MC16, _R, 24 }, { &tlcs900h_device::_DIVSBRR, _MC16, _R, 24 }, { &tlcs900h_device::_DIVSBRR, _MC16, _R, 24 }, + { &tlcs900h_device::_DIVSBRR, _MC16, _R, 24 }, { &tlcs900h_device::_DIVSBRR, _MC16, _R, 24 }, { &tlcs900h_device::_DIVSBRR, _MC16, _R, 24 }, { &tlcs900h_device::_DIVSBRR, _MC16, _R, 24 }, + + /* 60 - 7F */ + { &tlcs900h_device::_INCBIR, _I3, _R, 4 }, { &tlcs900h_device::_INCBIR, _I3, _R, 4 }, { &tlcs900h_device::_INCBIR, _I3, _R, 4 }, { &tlcs900h_device::_INCBIR, _I3, _R, 4 }, + { &tlcs900h_device::_INCBIR, _I3, _R, 4 }, { &tlcs900h_device::_INCBIR, _I3, _R, 4 }, { &tlcs900h_device::_INCBIR, _I3, _R, 4 }, { &tlcs900h_device::_INCBIR, _I3, _R, 4 }, + { &tlcs900h_device::_DECBIR, _I3, _R, 4 }, { &tlcs900h_device::_DECBIR, _I3, _R, 4 }, { &tlcs900h_device::_DECBIR, _I3, _R, 4 }, { &tlcs900h_device::_DECBIR, _I3, _R, 4 }, + { &tlcs900h_device::_DECBIR, _I3, _R, 4 }, { &tlcs900h_device::_DECBIR, _I3, _R, 4 }, { &tlcs900h_device::_DECBIR, _I3, _R, 4 }, { &tlcs900h_device::_DECBIR, _I3, _R, 4 }, + { &tlcs900h_device::_SCCBR, _CC, _R, 6 }, { &tlcs900h_device::_SCCBR, _CC, _R, 6 }, { &tlcs900h_device::_SCCBR, _CC, _R, 6 }, { &tlcs900h_device::_SCCBR, _CC, _R, 6 }, + { &tlcs900h_device::_SCCBR, _CC, _R, 6 }, { &tlcs900h_device::_SCCBR, _CC, _R, 6 }, { &tlcs900h_device::_SCCBR, _CC, _R, 6 }, { &tlcs900h_device::_SCCBR, _CC, _R, 6 }, + { &tlcs900h_device::_SCCBR, _CC, _R, 6 }, { &tlcs900h_device::_SCCBR, _CC, _R, 6 }, { &tlcs900h_device::_SCCBR, _CC, _R, 6 }, { &tlcs900h_device::_SCCBR, _CC, _R, 6 }, + { &tlcs900h_device::_SCCBR, _CC, _R, 6 }, { &tlcs900h_device::_SCCBR, _CC, _R, 6 }, { &tlcs900h_device::_SCCBR, _CC, _R, 6 }, { &tlcs900h_device::_SCCBR, _CC, _R, 6 }, + + /* 80 - 9F */ + { &tlcs900h_device::_ADDBRR, _C8, _R, 4 }, { &tlcs900h_device::_ADDBRR, _C8, _R, 4 }, { &tlcs900h_device::_ADDBRR, _C8, _R, 4 }, { &tlcs900h_device::_ADDBRR, _C8, _R, 4 }, + { &tlcs900h_device::_ADDBRR, _C8, _R, 4 }, { &tlcs900h_device::_ADDBRR, _C8, _R, 4 }, { &tlcs900h_device::_ADDBRR, _C8, _R, 4 }, { &tlcs900h_device::_ADDBRR, _C8, _R, 4 }, + { &tlcs900h_device::_LDBRR, _C8, _R, 4 }, { &tlcs900h_device::_LDBRR, _C8, _R, 4 }, { &tlcs900h_device::_LDBRR, _C8, _R, 4 }, { &tlcs900h_device::_LDBRR, _C8, _R, 4 }, + { &tlcs900h_device::_LDBRR, _C8, _R, 4 }, { &tlcs900h_device::_LDBRR, _C8, _R, 4 }, { &tlcs900h_device::_LDBRR, _C8, _R, 4 }, { &tlcs900h_device::_LDBRR, _C8, _R, 4 }, + { &tlcs900h_device::_ADCBRR, _C8, _R, 4 }, { &tlcs900h_device::_ADCBRR, _C8, _R, 4 }, { &tlcs900h_device::_ADCBRR, _C8, _R, 4 }, { &tlcs900h_device::_ADCBRR, _C8, _R, 4 }, + { &tlcs900h_device::_ADCBRR, _C8, _R, 4 }, { &tlcs900h_device::_ADCBRR, _C8, _R, 4 }, { &tlcs900h_device::_ADCBRR, _C8, _R, 4 }, { &tlcs900h_device::_ADCBRR, _C8, _R, 4 }, + { &tlcs900h_device::_LDBRR, _R, _C8, 4 }, { &tlcs900h_device::_LDBRR, _R, _C8, 4 }, { &tlcs900h_device::_LDBRR, _R, _C8, 4 }, { &tlcs900h_device::_LDBRR, _R, _C8, 4 }, + { &tlcs900h_device::_LDBRR, _R, _C8, 4 }, { &tlcs900h_device::_LDBRR, _R, _C8, 4 }, { &tlcs900h_device::_LDBRR, _R, _C8, 4 }, { &tlcs900h_device::_LDBRR, _R, _C8, 4 }, + + /* A0 - BF */ + { &tlcs900h_device::_SUBBRR, _C8, _R, 4 }, { &tlcs900h_device::_SUBBRR, _C8, _R, 4 }, { &tlcs900h_device::_SUBBRR, _C8, _R, 4 }, { &tlcs900h_device::_SUBBRR, _C8, _R, 4 }, + { &tlcs900h_device::_SUBBRR, _C8, _R, 4 }, { &tlcs900h_device::_SUBBRR, _C8, _R, 4 }, { &tlcs900h_device::_SUBBRR, _C8, _R, 4 }, { &tlcs900h_device::_SUBBRR, _C8, _R, 4 }, + { &tlcs900h_device::_LDBRI, _R, _I3, 4 }, { &tlcs900h_device::_LDBRI, _R, _I3, 4 }, { &tlcs900h_device::_LDBRI, _R, _I3, 4 }, { &tlcs900h_device::_LDBRI, _R, _I3, 4 }, + { &tlcs900h_device::_LDBRI, _R, _I3, 4 }, { &tlcs900h_device::_LDBRI, _R, _I3, 4 }, { &tlcs900h_device::_LDBRI, _R, _I3, 4 }, { &tlcs900h_device::_LDBRI, _R, _I3, 4 }, + { &tlcs900h_device::_SBCBRR, _C8, _R, 4 }, { &tlcs900h_device::_SBCBRR, _C8, _R, 4 }, { &tlcs900h_device::_SBCBRR, _C8, _R, 4 }, { &tlcs900h_device::_SBCBRR, _C8, _R, 4 }, + { &tlcs900h_device::_SBCBRR, _C8, _R, 4 }, { &tlcs900h_device::_SBCBRR, _C8, _R, 4 }, { &tlcs900h_device::_SBCBRR, _C8, _R, 4 }, { &tlcs900h_device::_SBCBRR, _C8, _R, 4 }, + { &tlcs900h_device::_EXBRR, _C8, _R, 5 }, { &tlcs900h_device::_EXBRR, _C8, _R, 5 }, { &tlcs900h_device::_EXBRR, _C8, _R, 5 }, { &tlcs900h_device::_EXBRR, _C8, _R, 5 }, + { &tlcs900h_device::_EXBRR, _C8, _R, 5 }, { &tlcs900h_device::_EXBRR, _C8, _R, 5 }, { &tlcs900h_device::_EXBRR, _C8, _R, 5 }, { &tlcs900h_device::_EXBRR, _C8, _R, 5 }, + + /* C0 - DF */ + { &tlcs900h_device::_ANDBRR, _C8, _R, 4 }, { &tlcs900h_device::_ANDBRR, _C8, _R, 4 }, { &tlcs900h_device::_ANDBRR, _C8, _R, 4 }, { &tlcs900h_device::_ANDBRR, _C8, _R, 4 }, + { &tlcs900h_device::_ANDBRR, _C8, _R, 4 }, { &tlcs900h_device::_ANDBRR, _C8, _R, 4 }, { &tlcs900h_device::_ANDBRR, _C8, _R, 4 }, { &tlcs900h_device::_ANDBRR, _C8, _R, 4 }, + { &tlcs900h_device::_ADDBRI, _R, _I8, 4 }, { &tlcs900h_device::_ADCBRI, _R, _I8, 4 }, { &tlcs900h_device::_SUBBRI, _R, _I8, 4 }, { &tlcs900h_device::_SBCBRI, _R, _I8, 4 }, + { &tlcs900h_device::_ANDBRI, _R, _I8, 4 }, { &tlcs900h_device::_XORBRI, _R, _I8, 4 }, { &tlcs900h_device::_ORBRI, _R, _I8, 4 }, { &tlcs900h_device::_CPBRI, _R, _I8, 4 }, + { &tlcs900h_device::_XORBRR, _C8, _R, 4 }, { &tlcs900h_device::_XORBRR, _C8, _R, 4 }, { &tlcs900h_device::_XORBRR, _C8, _R, 4 }, { &tlcs900h_device::_XORBRR, _C8, _R, 4 }, + { &tlcs900h_device::_XORBRR, _C8, _R, 4 }, { &tlcs900h_device::_XORBRR, _C8, _R, 4 }, { &tlcs900h_device::_XORBRR, _C8, _R, 4 }, { &tlcs900h_device::_XORBRR, _C8, _R, 4 }, + { &tlcs900h_device::_CPBRI, _R, _I3, 4 }, { &tlcs900h_device::_CPBRI, _R, _I3, 4 }, { &tlcs900h_device::_CPBRI, _R, _I3, 4 }, { &tlcs900h_device::_CPBRI, _R, _I3, 4 }, + { &tlcs900h_device::_CPBRI, _R, _I3, 4 }, { &tlcs900h_device::_CPBRI, _R, _I3, 4 }, { &tlcs900h_device::_CPBRI, _R, _I3, 4 }, { &tlcs900h_device::_CPBRI, _R, _I3, 4 }, + + /* E0 - FF */ + { &tlcs900h_device::_ORBRR, _C8, _R, 4 }, { &tlcs900h_device::_ORBRR, _C8, _R, 4 }, { &tlcs900h_device::_ORBRR, _C8, _R, 4 }, { &tlcs900h_device::_ORBRR, _C8, _R, 4 }, + { &tlcs900h_device::_ORBRR, _C8, _R, 4 }, { &tlcs900h_device::_ORBRR, _C8, _R, 4 }, { &tlcs900h_device::_ORBRR, _C8, _R, 4 }, { &tlcs900h_device::_ORBRR, _C8, _R, 4 }, + { &tlcs900h_device::_RLCBIR, _I8, _R, 6 }, { &tlcs900h_device::_RRCBIR, _I8, _R, 6 }, { &tlcs900h_device::_RLBIR, _I8, _R, 6 }, { &tlcs900h_device::_RRBIR, _I8, _R, 6 }, + { &tlcs900h_device::_SLABIR, _I8, _R, 6 }, { &tlcs900h_device::_SRABIR, _I8, _R, 6 }, { &tlcs900h_device::_SLLBIR, _I8, _R, 6 }, { &tlcs900h_device::_SRLBIR, _I8, _R, 6 }, + { &tlcs900h_device::_CPBRR, _C8, _R, 4 }, { &tlcs900h_device::_CPBRR, _C8, _R, 4 }, { &tlcs900h_device::_CPBRR, _C8, _R, 4 }, { &tlcs900h_device::_CPBRR, _C8, _R, 4 }, + { &tlcs900h_device::_CPBRR, _C8, _R, 4 }, { &tlcs900h_device::_CPBRR, _C8, _R, 4 }, { &tlcs900h_device::_CPBRR, _C8, _R, 4 }, { &tlcs900h_device::_CPBRR, _C8, _R, 4 }, + { &tlcs900h_device::_RLCBRR, _A, _R, 6 }, { &tlcs900h_device::_RRCBRR, _A, _R, 6 }, { &tlcs900h_device::_RLBRR, _A, _R, 6 }, { &tlcs900h_device::_RRBRR, _A, _R, 6 }, + { &tlcs900h_device::_SLABRR, _A, _R, 6 }, { &tlcs900h_device::_SRABRR, _A, _R, 6 }, { &tlcs900h_device::_SLLBRR, _A, _R, 6 }, { &tlcs900h_device::_SRLBRR, _A, _R, 6 } +}; + + +const tlcs900h_device::tlcs900inst tlcs900h_device::s_mnemonic_d0[256] = +{ + /* 00 - 1F */ + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_PUSHWM, _M, 0, 7 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_LDWMM, _M16, _M, 8 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + + /* 20 - 3F */ + { &tlcs900h_device::_LDWRM, _C16, _M, 4 }, { &tlcs900h_device::_LDWRM, _C16, _M, 4 }, { &tlcs900h_device::_LDWRM, _C16, _M, 4 }, { &tlcs900h_device::_LDWRM, _C16, _M, 4 }, + { &tlcs900h_device::_LDWRM, _C16, _M, 4 }, { &tlcs900h_device::_LDWRM, _C16, _M, 4 }, { &tlcs900h_device::_LDWRM, _C16, _M, 4 }, { &tlcs900h_device::_LDWRM, _C16, _M, 4 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_EXWMR, _M, _C16, 6 }, { &tlcs900h_device::_EXWMR, _M, _C16, 6 }, { &tlcs900h_device::_EXWMR, _M, _C16, 6 }, { &tlcs900h_device::_EXWMR, _M, _C16, 6 }, + { &tlcs900h_device::_EXWMR, _M, _C16, 6 }, { &tlcs900h_device::_EXWMR, _M, _C16, 6 }, { &tlcs900h_device::_EXWMR, _M, _C16, 6 }, { &tlcs900h_device::_EXWMR, _M, _C16, 6 }, + { &tlcs900h_device::_ADDWMI, _M, _I16, 8 }, { &tlcs900h_device::_ADCWMI, _M, _I16, 8 }, { &tlcs900h_device::_SUBWMI, _M, _I16, 8 }, { &tlcs900h_device::_SBCWMI, _M, _I16, 8 }, + { &tlcs900h_device::_ANDWMI, _M, _I16, 8 }, { &tlcs900h_device::_XORWMI, _M, _I16, 8 }, { &tlcs900h_device::_ORWMI, _M, _I16, 8 }, { &tlcs900h_device::_CPWMI, _M, _I16, 6 }, + + /* 40 - 5F */ + { &tlcs900h_device::_MULWRM, _C32, _M, 26 }, { &tlcs900h_device::_MULWRM, _C32, _M, 26 }, { &tlcs900h_device::_MULWRM, _C32, _M, 26 }, { &tlcs900h_device::_MULWRM, _C32, _M, 26 }, + { &tlcs900h_device::_MULWRM, _C32, _M, 26 }, { &tlcs900h_device::_MULWRM, _C32, _M, 26 }, { &tlcs900h_device::_MULWRM, _C32, _M, 26 }, { &tlcs900h_device::_MULWRM, _C32, _M, 26 }, + { &tlcs900h_device::_MULSWRM, _C32, _M, 26 }, { &tlcs900h_device::_MULSWRM, _C32, _M, 26 }, { &tlcs900h_device::_MULSWRM, _C32, _M, 26 }, { &tlcs900h_device::_MULSWRM, _C32, _M, 26 }, + { &tlcs900h_device::_MULSWRM, _C32, _M, 26 }, { &tlcs900h_device::_MULSWRM, _C32, _M, 26 }, { &tlcs900h_device::_MULSWRM, _C32, _M, 26 }, { &tlcs900h_device::_MULSWRM, _C32, _M, 26 }, + { &tlcs900h_device::_DIVWRM, _C32, _M, 30 }, { &tlcs900h_device::_DIVWRM, _C32, _M, 30 }, { &tlcs900h_device::_DIVWRM, _C32, _M, 30 }, { &tlcs900h_device::_DIVWRM, _C32, _M, 30 }, + { &tlcs900h_device::_DIVWRM, _C32, _M, 30 }, { &tlcs900h_device::_DIVWRM, _C32, _M, 30 }, { &tlcs900h_device::_DIVWRM, _C32, _M, 30 }, { &tlcs900h_device::_DIVWRM, _C32, _M, 30 }, + { &tlcs900h_device::_DIVSWRM, _C32, _M, 32 }, { &tlcs900h_device::_DIVSWRM, _C32, _M, 32 }, { &tlcs900h_device::_DIVSWRM, _C32, _M, 32 }, { &tlcs900h_device::_DIVSWRM, _C32, _M, 32 }, + { &tlcs900h_device::_DIVSWRM, _C32, _M, 32 }, { &tlcs900h_device::_DIVSWRM, _C32, _M, 32 }, { &tlcs900h_device::_DIVSWRM, _C32, _M, 32 }, { &tlcs900h_device::_DIVSWRM, _C32, _M, 32 }, + + /* 60 - 7F */ + { &tlcs900h_device::_INCWIM, _I3, _M, 6 }, { &tlcs900h_device::_INCWIM, _I3, _M, 6 }, { &tlcs900h_device::_INCWIM, _I3, _M, 6 }, { &tlcs900h_device::_INCWIM, _I3, _M, 6 }, + { &tlcs900h_device::_INCWIM, _I3, _M, 6 }, { &tlcs900h_device::_INCWIM, _I3, _M, 6 }, { &tlcs900h_device::_INCWIM, _I3, _M, 6 }, { &tlcs900h_device::_INCWIM, _I3, _M, 6 }, + { &tlcs900h_device::_DECWIM, _I3, _M, 6 }, { &tlcs900h_device::_DECWIM, _I3, _M, 6 }, { &tlcs900h_device::_DECWIM, _I3, _M, 6 }, { &tlcs900h_device::_DECWIM, _I3, _M, 6 }, + { &tlcs900h_device::_DECWIM, _I3, _M, 6 }, { &tlcs900h_device::_DECWIM, _I3, _M, 6 }, { &tlcs900h_device::_DECWIM, _I3, _M, 6 }, { &tlcs900h_device::_DECWIM, _I3, _M, 6 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_RLCWM, _M, 0, 8 }, { &tlcs900h_device::_RRCWM, _M, 0, 8 }, { &tlcs900h_device::_RLWM, _M, 0, 8 }, { &tlcs900h_device::_RRWM, _M, 0, 8 }, + { &tlcs900h_device::_SLAWM, _M, 0, 8 }, { &tlcs900h_device::_SRAWM, _M, 0, 8 }, { &tlcs900h_device::_SLLWM, _M, 0, 8 }, { &tlcs900h_device::_SRLWM, _M, 0, 8 }, + + /* 80 - 9F */ + { &tlcs900h_device::_ADDWRM, _C16, _M, 4 }, { &tlcs900h_device::_ADDWRM, _C16, _M, 4 }, { &tlcs900h_device::_ADDWRM, _C16, _M, 4 }, { &tlcs900h_device::_ADDWRM, _C16, _M, 4 }, + { &tlcs900h_device::_ADDWRM, _C16, _M, 4 }, { &tlcs900h_device::_ADDWRM, _C16, _M, 4 }, { &tlcs900h_device::_ADDWRM, _C16, _M, 4 }, { &tlcs900h_device::_ADDWRM, _C16, _M, 4 }, + { &tlcs900h_device::_ADDWMR, _M, _C16, 6 }, { &tlcs900h_device::_ADDWMR, _M, _C16, 6 }, { &tlcs900h_device::_ADDWMR, _M, _C16, 6 }, { &tlcs900h_device::_ADDWMR, _M, _C16, 6 }, + { &tlcs900h_device::_ADDWMR, _M, _C16, 6 }, { &tlcs900h_device::_ADDWMR, _M, _C16, 6 }, { &tlcs900h_device::_ADDWMR, _M, _C16, 6 }, { &tlcs900h_device::_ADDWMR, _M, _C16, 6 }, + { &tlcs900h_device::_ADCWRM, _C16, _M, 4 }, { &tlcs900h_device::_ADCWRM, _C16, _M, 4 }, { &tlcs900h_device::_ADCWRM, _C16, _M, 4 }, { &tlcs900h_device::_ADCWRM, _C16, _M, 4 }, + { &tlcs900h_device::_ADCWRM, _C16, _M, 4 }, { &tlcs900h_device::_ADCWRM, _C16, _M, 4 }, { &tlcs900h_device::_ADCWRM, _C16, _M, 4 }, { &tlcs900h_device::_ADCWRM, _C16, _M, 4 }, + { &tlcs900h_device::_ADCWMR, _M, _C16, 6 }, { &tlcs900h_device::_ADCWMR, _M, _C16, 6 }, { &tlcs900h_device::_ADCWMR, _M, _C16, 6 }, { &tlcs900h_device::_ADCWMR, _M, _C16, 6 }, + { &tlcs900h_device::_ADCWMR, _M, _C16, 6 }, { &tlcs900h_device::_ADCWMR, _M, _C16, 6 }, { &tlcs900h_device::_ADCWMR, _M, _C16, 6 }, { &tlcs900h_device::_ADCWMR, _M, _C16, 6 }, + + /* A0 - BF */ + { &tlcs900h_device::_SUBWRM, _C16, _M, 4 }, { &tlcs900h_device::_SUBWRM, _C16, _M, 4 }, { &tlcs900h_device::_SUBWRM, _C16, _M, 4 }, { &tlcs900h_device::_SUBWRM, _C16, _M, 4 }, + { &tlcs900h_device::_SUBWRM, _C16, _M, 4 }, { &tlcs900h_device::_SUBWRM, _C16, _M, 4 }, { &tlcs900h_device::_SUBWRM, _C16, _M, 4 }, { &tlcs900h_device::_SUBWRM, _C16, _M, 4 }, + { &tlcs900h_device::_SUBWMR, _M, _C16, 6 }, { &tlcs900h_device::_SUBWMR, _M, _C16, 6 }, { &tlcs900h_device::_SUBWMR, _M, _C16, 6 }, { &tlcs900h_device::_SUBWMR, _M, _C16, 6 }, + { &tlcs900h_device::_SUBWMR, _M, _C16, 6 }, { &tlcs900h_device::_SUBWMR, _M, _C16, 6 }, { &tlcs900h_device::_SUBWMR, _M, _C16, 6 }, { &tlcs900h_device::_SUBWMR, _M, _C16, 6 }, + { &tlcs900h_device::_SBCWRM, _C16, _M, 4 }, { &tlcs900h_device::_SBCWRM, _C16, _M, 4 }, { &tlcs900h_device::_SBCWRM, _C16, _M, 4 }, { &tlcs900h_device::_SBCWRM, _C16, _M, 4 }, + { &tlcs900h_device::_SBCWRM, _C16, _M, 4 }, { &tlcs900h_device::_SBCWRM, _C16, _M, 4 }, { &tlcs900h_device::_SBCWRM, _C16, _M, 4 }, { &tlcs900h_device::_SBCWRM, _C16, _M, 4 }, + { &tlcs900h_device::_SBCWMR, _M, _C16, 6 }, { &tlcs900h_device::_SBCWMR, _M, _C16, 6 }, { &tlcs900h_device::_SBCWMR, _M, _C16, 6 }, { &tlcs900h_device::_SBCWMR, _M, _C16, 6 }, + { &tlcs900h_device::_SBCWMR, _M, _C16, 6 }, { &tlcs900h_device::_SBCWMR, _M, _C16, 6 }, { &tlcs900h_device::_SBCWMR, _M, _C16, 6 }, { &tlcs900h_device::_SBCWMR, _M, _C16, 6 }, + + /* C0 - DF */ + { &tlcs900h_device::_ANDWRM, _C16, _M, 4 }, { &tlcs900h_device::_ANDWRM, _C16, _M, 4 }, { &tlcs900h_device::_ANDWRM, _C16, _M, 4 }, { &tlcs900h_device::_ANDWRM, _C16, _M, 4 }, + { &tlcs900h_device::_ANDWRM, _C16, _M, 4 }, { &tlcs900h_device::_ANDWRM, _C16, _M, 4 }, { &tlcs900h_device::_ANDWRM, _C16, _M, 4 }, { &tlcs900h_device::_ANDWRM, _C16, _M, 4 }, + { &tlcs900h_device::_ANDWMR, _M, _C16, 6 }, { &tlcs900h_device::_ANDWMR, _M, _C16, 6 }, { &tlcs900h_device::_ANDWMR, _M, _C16, 6 }, { &tlcs900h_device::_ANDWMR, _M, _C16, 6 }, + { &tlcs900h_device::_ANDWMR, _M, _C16, 6 }, { &tlcs900h_device::_ANDWMR, _M, _C16, 6 }, { &tlcs900h_device::_ANDWMR, _M, _C16, 6 }, { &tlcs900h_device::_ANDWMR, _M, _C16, 6 }, + { &tlcs900h_device::_XORWRM, _C16, _M, 4 }, { &tlcs900h_device::_XORWRM, _C16, _M, 4 }, { &tlcs900h_device::_XORWRM, _C16, _M, 4 }, { &tlcs900h_device::_XORWRM, _C16, _M, 4 }, + { &tlcs900h_device::_XORWRM, _C16, _M, 4 }, { &tlcs900h_device::_XORWRM, _C16, _M, 4 }, { &tlcs900h_device::_XORWRM, _C16, _M, 4 }, { &tlcs900h_device::_XORWRM, _C16, _M, 4 }, + { &tlcs900h_device::_XORWMR, _M, _C16, 6 }, { &tlcs900h_device::_XORWMR, _M, _C16, 6 }, { &tlcs900h_device::_XORWMR, _M, _C16, 6 }, { &tlcs900h_device::_XORWMR, _M, _C16, 6 }, + { &tlcs900h_device::_XORWMR, _M, _C16, 6 }, { &tlcs900h_device::_XORWMR, _M, _C16, 6 }, { &tlcs900h_device::_XORWMR, _M, _C16, 6 }, { &tlcs900h_device::_XORWMR, _M, _C16, 6 }, + + /* E0 - FF */ + { &tlcs900h_device::_ORWRM, _C16, _M, 4 }, { &tlcs900h_device::_ORWRM, _C16, _M, 4 }, { &tlcs900h_device::_ORWRM, _C16, _M, 4 }, { &tlcs900h_device::_ORWRM, _C16, _M, 4 }, + { &tlcs900h_device::_ORWRM, _C16, _M, 4 }, { &tlcs900h_device::_ORWRM, _C16, _M, 4 }, { &tlcs900h_device::_ORWRM, _C16, _M, 4 }, { &tlcs900h_device::_ORWRM, _C16, _M, 4 }, + { &tlcs900h_device::_ORWMR, _M, _C16, 6 }, { &tlcs900h_device::_ORWMR, _M, _C16, 6 }, { &tlcs900h_device::_ORWMR, _M, _C16, 6 }, { &tlcs900h_device::_ORWMR, _M, _C16, 6 }, + { &tlcs900h_device::_ORWMR, _M, _C16, 6 }, { &tlcs900h_device::_ORWMR, _M, _C16, 6 }, { &tlcs900h_device::_ORWMR, _M, _C16, 6 }, { &tlcs900h_device::_ORWMR, _M, _C16, 6 }, + { &tlcs900h_device::_CPWRM, _C16, _M, 4 }, { &tlcs900h_device::_CPWRM, _C16, _M, 4 }, { &tlcs900h_device::_CPWRM, _C16, _M, 4 }, { &tlcs900h_device::_CPWRM, _C16, _M, 4 }, + { &tlcs900h_device::_CPWRM, _C16, _M, 4 }, { &tlcs900h_device::_CPWRM, _C16, _M, 4 }, { &tlcs900h_device::_CPWRM, _C16, _M, 4 }, { &tlcs900h_device::_CPWRM, _C16, _M, 4 }, + { &tlcs900h_device::_CPWMR, _M, _C16, 6 }, { &tlcs900h_device::_CPWMR, _M, _C16, 6 }, { &tlcs900h_device::_CPWMR, _M, _C16, 6 }, { &tlcs900h_device::_CPWMR, _M, _C16, 6 }, + { &tlcs900h_device::_CPWMR, _M, _C16, 6 }, { &tlcs900h_device::_CPWMR, _M, _C16, 6 }, { &tlcs900h_device::_CPWMR, _M, _C16, 6 }, { &tlcs900h_device::_CPWMR, _M, _C16, 6 }, +}; + + +const tlcs900h_device::tlcs900inst tlcs900h_device::s_mnemonic_d8[256] = +{ + /* 00 - 1F */ + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_LDWRI, _R, _I16, 4 }, + { &tlcs900h_device::_PUSHWR, _R, 0, 5 }, { &tlcs900h_device::_POPWR, _R, 0, 6 }, { &tlcs900h_device::_CPLWR, _R, 0, 4 }, { &tlcs900h_device::_NEGWR, _R, 0, 5 }, + { &tlcs900h_device::_MULWRI, _R, _I16, 26 }, { &tlcs900h_device::_MULSWRI, _R, _I16, 26 }, { &tlcs900h_device::_DIVWRI, _R, _I16, 30 }, { &tlcs900h_device::_DIVSWRI, _R, _I16, 32 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_BS1FRR, _A, _R, 4 }, { &tlcs900h_device::_BS1BRR, _A, _R, 4 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_EXTZWR, _R, 0, 4 }, { &tlcs900h_device::_EXTSWR, _R, 0, 5 }, + { &tlcs900h_device::_PAAWR, _R, 0, 4 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_MIRRW, _R, 0, 4 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_MULAR, _R, 0, 31 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DJNZW, _R, _D8, 7 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + + /* 20 - 3F */ + { &tlcs900h_device::_ANDCFWIR, _I8, _R, 4 }, { &tlcs900h_device::_ORCFWIR, _I8, _R, 4 }, { &tlcs900h_device::_XORCFWIR, _I8, _R, 4 }, { &tlcs900h_device::_LDCFWIR, _I8, _R, 4 }, + { &tlcs900h_device::_STCFWIR, _I8, _R, 4 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_ANDCFWRR, _A, _R, 4 }, { &tlcs900h_device::_ORCFWRR, _A, _R, 4 }, { &tlcs900h_device::_XORCFWRR, _A, _R, 4 }, { &tlcs900h_device::_LDCFWRR, _A, _R, 4 }, + { &tlcs900h_device::_STCFWRR, _A, _R, 4 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_LDCWRR, _CR16, _R, 1 }, { &tlcs900h_device::_LDCWRR, _R, _CR16, 1 }, + { &tlcs900h_device::_RESWIR, _I8, _R, 4 }, { &tlcs900h_device::_SETWIR, _I8, _R, 4 }, { &tlcs900h_device::_CHGWIR, _I8, _R, 4 }, { &tlcs900h_device::_BITWIR, _I8, _R, 4 }, + { &tlcs900h_device::_TSETWIR, _I8, _R, 6 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_MINC1, _I16, _R, 8 }, { &tlcs900h_device::_MINC2, _I16, _R, 8 }, { &tlcs900h_device::_MINC4, _I16, _R, 8 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_MDEC1, _I16, _R, 7 }, { &tlcs900h_device::_MDEC2, _I16, _R, 7 }, { &tlcs900h_device::_MDEC4, _I16, _R, 7 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + + /* 40 - 5F */ + { &tlcs900h_device::_MULWRR, _C32, _R, 26 }, { &tlcs900h_device::_MULWRR, _C32, _R, 26 }, { &tlcs900h_device::_MULWRR, _C32, _R, 26 }, { &tlcs900h_device::_MULWRR, _C32, _R, 26 }, + { &tlcs900h_device::_MULWRR, _C32, _R, 26 }, { &tlcs900h_device::_MULWRR, _C32, _R, 26 }, { &tlcs900h_device::_MULWRR, _C32, _R, 26 }, { &tlcs900h_device::_MULWRR, _C32, _R, 26 }, + { &tlcs900h_device::_MULSWRR, _C32, _R, 26 }, { &tlcs900h_device::_MULSWRR, _C32, _R, 26 }, { &tlcs900h_device::_MULSWRR, _C32, _R, 26 }, { &tlcs900h_device::_MULSWRR, _C32, _R, 26 }, + { &tlcs900h_device::_MULSWRR, _C32, _R, 26 }, { &tlcs900h_device::_MULSWRR, _C32, _R, 26 }, { &tlcs900h_device::_MULSWRR, _C32, _R, 26 }, { &tlcs900h_device::_MULSWRR, _C32, _R, 26 }, + { &tlcs900h_device::_DIVWRR, _C32, _R, 30 }, { &tlcs900h_device::_DIVWRR, _C32, _R, 30 }, { &tlcs900h_device::_DIVWRR, _C32, _R, 30 }, { &tlcs900h_device::_DIVWRR, _C32, _R, 30 }, + { &tlcs900h_device::_DIVWRR, _C32, _R, 30 }, { &tlcs900h_device::_DIVWRR, _C32, _R, 30 }, { &tlcs900h_device::_DIVWRR, _C32, _R, 30 }, { &tlcs900h_device::_DIVWRR, _C32, _R, 30 }, + { &tlcs900h_device::_DIVSWRR, _C32, _R, 32 }, { &tlcs900h_device::_DIVSWRR, _C32, _R, 32 }, { &tlcs900h_device::_DIVSWRR, _C32, _R, 32 }, { &tlcs900h_device::_DIVSWRR, _C32, _R, 32 }, + { &tlcs900h_device::_DIVSWRR, _C32, _R, 32 }, { &tlcs900h_device::_DIVSWRR, _C32, _R, 32 }, { &tlcs900h_device::_DIVSWRR, _C32, _R, 32 }, { &tlcs900h_device::_DIVSWRR, _C32, _R, 32 }, + + /* 60 - 7F */ + { &tlcs900h_device::_INCWIR, _I3, _R, 4 }, { &tlcs900h_device::_INCWIR, _I3, _R, 4 }, { &tlcs900h_device::_INCWIR, _I3, _R, 4 }, { &tlcs900h_device::_INCWIR, _I3, _R, 4 }, + { &tlcs900h_device::_INCWIR, _I3, _R, 4 }, { &tlcs900h_device::_INCWIR, _I3, _R, 4 }, { &tlcs900h_device::_INCWIR, _I3, _R, 4 }, { &tlcs900h_device::_INCWIR, _I3, _R, 4 }, + { &tlcs900h_device::_DECWIR, _I3, _R, 4 }, { &tlcs900h_device::_DECWIR, _I3, _R, 4 }, { &tlcs900h_device::_DECWIR, _I3, _R, 4 }, { &tlcs900h_device::_DECWIR, _I3, _R, 4 }, + { &tlcs900h_device::_DECWIR, _I3, _R, 4 }, { &tlcs900h_device::_DECWIR, _I3, _R, 4 }, { &tlcs900h_device::_DECWIR, _I3, _R, 4 }, { &tlcs900h_device::_DECWIR, _I3, _R, 4 }, + { &tlcs900h_device::_SCCWR, _CC, _R, 6 }, { &tlcs900h_device::_SCCWR, _CC, _R, 6 }, { &tlcs900h_device::_SCCWR, _CC, _R, 6 }, { &tlcs900h_device::_SCCWR, _CC, _R, 6 }, + { &tlcs900h_device::_SCCWR, _CC, _R, 6 }, { &tlcs900h_device::_SCCWR, _CC, _R, 6 }, { &tlcs900h_device::_SCCWR, _CC, _R, 6 }, { &tlcs900h_device::_SCCWR, _CC, _R, 6 }, + { &tlcs900h_device::_SCCWR, _CC, _R, 6 }, { &tlcs900h_device::_SCCWR, _CC, _R, 6 }, { &tlcs900h_device::_SCCWR, _CC, _R, 6 }, { &tlcs900h_device::_SCCWR, _CC, _R, 6 }, + { &tlcs900h_device::_SCCWR, _CC, _R, 6 }, { &tlcs900h_device::_SCCWR, _CC, _R, 6 }, { &tlcs900h_device::_SCCWR, _CC, _R, 6 }, { &tlcs900h_device::_SCCWR, _CC, _R, 6 }, + + /* 80 - 9F */ + { &tlcs900h_device::_ADDWRR, _C16, _R, 4 }, { &tlcs900h_device::_ADDWRR, _C16, _R, 4 }, { &tlcs900h_device::_ADDWRR, _C16, _R, 4 }, { &tlcs900h_device::_ADDWRR, _C16, _R, 4 }, + { &tlcs900h_device::_ADDWRR, _C16, _R, 4 }, { &tlcs900h_device::_ADDWRR, _C16, _R, 4 }, { &tlcs900h_device::_ADDWRR, _C16, _R, 4 }, { &tlcs900h_device::_ADDWRR, _C16, _R, 4 }, + { &tlcs900h_device::_LDWRR, _C16, _R, 4 }, { &tlcs900h_device::_LDWRR, _C16, _R, 4 }, { &tlcs900h_device::_LDWRR, _C16, _R, 4 }, { &tlcs900h_device::_LDWRR, _C16, _R, 4 }, + { &tlcs900h_device::_LDWRR, _C16, _R, 4 }, { &tlcs900h_device::_LDWRR, _C16, _R, 4 }, { &tlcs900h_device::_LDWRR, _C16, _R, 4 }, { &tlcs900h_device::_LDWRR, _C16, _R, 4 }, + { &tlcs900h_device::_ADCWRR, _C16, _R, 4 }, { &tlcs900h_device::_ADCWRR, _C16, _R, 4 }, { &tlcs900h_device::_ADCWRR, _C16, _R, 4 }, { &tlcs900h_device::_ADCWRR, _C16, _R, 4 }, + { &tlcs900h_device::_ADCWRR, _C16, _R, 4 }, { &tlcs900h_device::_ADCWRR, _C16, _R, 4 }, { &tlcs900h_device::_ADCWRR, _C16, _R, 4 }, { &tlcs900h_device::_ADCWRR, _C16, _R, 4 }, + { &tlcs900h_device::_LDWRR, _R, _C16, 4 }, { &tlcs900h_device::_LDWRR, _R, _C16, 4 }, { &tlcs900h_device::_LDWRR, _R, _C16, 4 }, { &tlcs900h_device::_LDWRR, _R, _C16, 4 }, + { &tlcs900h_device::_LDWRR, _R, _C16, 4 }, { &tlcs900h_device::_LDWRR, _R, _C16, 4 }, { &tlcs900h_device::_LDWRR, _R, _C16, 4 }, { &tlcs900h_device::_LDWRR, _R, _C16, 4 }, + + /* A0 - BF */ + { &tlcs900h_device::_SUBWRR, _C16, _R, 4 }, { &tlcs900h_device::_SUBWRR, _C16, _R, 4 }, { &tlcs900h_device::_SUBWRR, _C16, _R, 4 }, { &tlcs900h_device::_SUBWRR, _C16, _R, 4 }, + { &tlcs900h_device::_SUBWRR, _C16, _R, 4 }, { &tlcs900h_device::_SUBWRR, _C16, _R, 4 }, { &tlcs900h_device::_SUBWRR, _C16, _R, 4 }, { &tlcs900h_device::_SUBWRR, _C16, _R, 4 }, + { &tlcs900h_device::_LDWRI, _R, _I3, 4 }, { &tlcs900h_device::_LDWRI, _R, _I3, 4 }, { &tlcs900h_device::_LDWRI, _R, _I3, 4 }, { &tlcs900h_device::_LDWRI, _R, _I3, 4 }, + { &tlcs900h_device::_LDWRI, _R, _I3, 4 }, { &tlcs900h_device::_LDWRI, _R, _I3, 4 }, { &tlcs900h_device::_LDWRI, _R, _I3, 4 }, { &tlcs900h_device::_LDWRI, _R, _I3, 4 }, + { &tlcs900h_device::_SBCWRR, _C16, _R, 4 }, { &tlcs900h_device::_SBCWRR, _C16, _R, 4 }, { &tlcs900h_device::_SBCWRR, _C16, _R, 4 }, { &tlcs900h_device::_SBCWRR, _C16, _R, 4 }, + { &tlcs900h_device::_SBCWRR, _C16, _R, 4 }, { &tlcs900h_device::_SBCWRR, _C16, _R, 4 }, { &tlcs900h_device::_SBCWRR, _C16, _R, 4 }, { &tlcs900h_device::_SBCWRR, _C16, _R, 4 }, + { &tlcs900h_device::_EXWRR, _C16, _R, 5 }, { &tlcs900h_device::_EXWRR, _C16, _R, 5 }, { &tlcs900h_device::_EXWRR, _C16, _R, 5 }, { &tlcs900h_device::_EXWRR, _C16, _R, 5 }, + { &tlcs900h_device::_EXWRR, _C16, _R, 5 }, { &tlcs900h_device::_EXWRR, _C16, _R, 5 }, { &tlcs900h_device::_EXWRR, _C16, _R, 5 }, { &tlcs900h_device::_EXWRR, _C16, _R, 5 }, + + /* C0 - DF */ + { &tlcs900h_device::_ANDWRR, _C16, _R, 4 }, { &tlcs900h_device::_ANDWRR, _C16, _R, 4 }, { &tlcs900h_device::_ANDWRR, _C16, _R, 4 }, { &tlcs900h_device::_ANDWRR, _C16, _R, 4 }, + { &tlcs900h_device::_ANDWRR, _C16, _R, 4 }, { &tlcs900h_device::_ANDWRR, _C16, _R, 4 }, { &tlcs900h_device::_ANDWRR, _C16, _R, 4 }, { &tlcs900h_device::_ANDWRR, _C16, _R, 4 }, + { &tlcs900h_device::_ADDWRI, _R, _I16, 4 }, { &tlcs900h_device::_ADCWRI, _R, _I16, 4 }, { &tlcs900h_device::_SUBWRI, _R, _I16, 4 }, { &tlcs900h_device::_SBCWRI, _R, _I16, 4 }, + { &tlcs900h_device::_ANDWRI, _R, _I16, 4 }, { &tlcs900h_device::_XORWRI, _R, _I16, 4 }, { &tlcs900h_device::_ORWRI, _R, _I16, 4 }, { &tlcs900h_device::_CPWRI, _R, _I16, 4 }, + { &tlcs900h_device::_XORWRR, _C16, _R, 4 }, { &tlcs900h_device::_XORWRR, _C16, _R, 4 }, { &tlcs900h_device::_XORWRR, _C16, _R, 4 }, { &tlcs900h_device::_XORWRR, _C16, _R, 4 }, + { &tlcs900h_device::_XORWRR, _C16, _R, 4 }, { &tlcs900h_device::_XORWRR, _C16, _R, 4 }, { &tlcs900h_device::_XORWRR, _C16, _R, 4 }, { &tlcs900h_device::_XORWRR, _C16, _R, 4 }, + { &tlcs900h_device::_CPWRI, _R, _I3, 4 }, { &tlcs900h_device::_CPWRI, _R, _I3, 4 }, { &tlcs900h_device::_CPWRI, _R, _I3, 4 }, { &tlcs900h_device::_CPWRI, _R, _I3, 4 }, + { &tlcs900h_device::_CPWRI, _R, _I3, 4 }, { &tlcs900h_device::_CPWRI, _R, _I3, 4 }, { &tlcs900h_device::_CPWRI, _R, _I3, 4 }, { &tlcs900h_device::_CPWRI, _R, _I3, 4 }, + + /* E0 - FF */ + { &tlcs900h_device::_ORWRR, _C16, _R, 4 }, { &tlcs900h_device::_ORWRR, _C16, _R, 4 }, { &tlcs900h_device::_ORWRR, _C16, _R, 4 }, { &tlcs900h_device::_ORWRR, _C16, _R, 4 }, + { &tlcs900h_device::_ORWRR, _C16, _R, 4 }, { &tlcs900h_device::_ORWRR, _C16, _R, 4 }, { &tlcs900h_device::_ORWRR, _C16, _R, 4 }, { &tlcs900h_device::_ORWRR, _C16, _R, 4 }, + { &tlcs900h_device::_RLCWIR, _I8, _R, 6 }, { &tlcs900h_device::_RRCWIR, _I8, _R, 6 }, { &tlcs900h_device::_RLWIR, _I8, _R, 6 }, { &tlcs900h_device::_RRWIR, _I8, _R, 6 }, + { &tlcs900h_device::_SLAWIR, _I8, _R, 6 }, { &tlcs900h_device::_SRAWIR, _I8, _R, 6 }, { &tlcs900h_device::_SLLWIR, _I8, _R, 6 }, { &tlcs900h_device::_SRLWIR, _I8, _R, 6 }, + { &tlcs900h_device::_CPWRR, _C16, _R, 4 }, { &tlcs900h_device::_CPWRR, _C16, _R, 4 }, { &tlcs900h_device::_CPWRR, _C16, _R, 4 }, { &tlcs900h_device::_CPWRR, _C16, _R, 4 }, + { &tlcs900h_device::_CPWRR, _C16, _R, 4 }, { &tlcs900h_device::_CPWRR, _C16, _R, 4 }, { &tlcs900h_device::_CPWRR, _C16, _R, 4 }, { &tlcs900h_device::_CPWRR, _C16, _R, 4 }, + { &tlcs900h_device::_RLCWRR, _A, _R, 6 }, { &tlcs900h_device::_RRCWRR, _A, _R, 6 }, { &tlcs900h_device::_RLWRR, _A, _R, 6 }, { &tlcs900h_device::_RRWRR, _A, _R, 6 }, + { &tlcs900h_device::_SLAWRR, _A, _R, 6 }, { &tlcs900h_device::_SRAWRR, _A, _R, 6 }, { &tlcs900h_device::_SLLWRR, _A, _R, 6 }, { &tlcs900h_device::_SRLWRR, _A, _R, 6 } +}; + + +const tlcs900h_device::tlcs900inst tlcs900h_device::s_mnemonic_e0[256] = +{ + /* 00 - 1F */ + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + + /* 20 - 3F */ + { &tlcs900h_device::_LDLRM, _C32, _M, 6 }, { &tlcs900h_device::_LDLRM, _C32, _M, 6 }, { &tlcs900h_device::_LDLRM, _C32, _M, 6 }, { &tlcs900h_device::_LDLRM, _C32, _M, 6 }, + { &tlcs900h_device::_LDLRM, _C32, _M, 6 }, { &tlcs900h_device::_LDLRM, _C32, _M, 6 }, { &tlcs900h_device::_LDLRM, _C32, _M, 6 }, { &tlcs900h_device::_LDLRM, _C32, _M, 6 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + + /* 40 - 5F */ + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + + /* 60 - 7F */ + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + + /* 80 - 9F */ + { &tlcs900h_device::_ADDLRM, _C32, _M, 6 }, { &tlcs900h_device::_ADDLRM, _C32, _M, 6 }, { &tlcs900h_device::_ADDLRM, _C32, _M, 6 }, { &tlcs900h_device::_ADDLRM, _C32, _M, 6 }, + { &tlcs900h_device::_ADDLRM, _C32, _M, 6 }, { &tlcs900h_device::_ADDLRM, _C32, _M, 6 }, { &tlcs900h_device::_ADDLRM, _C32, _M, 6 }, { &tlcs900h_device::_ADDLRM, _C32, _M, 6 }, + { &tlcs900h_device::_ADDLMR, _M, _C32, 10 }, { &tlcs900h_device::_ADDLMR, _M, _C32, 10 }, { &tlcs900h_device::_ADDLMR, _M, _C32, 10 }, { &tlcs900h_device::_ADDLMR, _M, _C32, 10 }, + { &tlcs900h_device::_ADDLMR, _M, _C32, 10 }, { &tlcs900h_device::_ADDLMR, _M, _C32, 10 }, { &tlcs900h_device::_ADDLMR, _M, _C32, 10 }, { &tlcs900h_device::_ADDLMR, _M, _C32, 10 }, + { &tlcs900h_device::_ADCLRM, _C32, _M, 6 }, { &tlcs900h_device::_ADCLRM, _C32, _M, 6 }, { &tlcs900h_device::_ADCLRM, _C32, _M, 6 }, { &tlcs900h_device::_ADCLRM, _C32, _M, 6 }, + { &tlcs900h_device::_ADCLRM, _C32, _M, 6 }, { &tlcs900h_device::_ADCLRM, _C32, _M, 6 }, { &tlcs900h_device::_ADCLRM, _C32, _M, 6 }, { &tlcs900h_device::_ADCLRM, _C32, _M, 6 }, + { &tlcs900h_device::_ADCLMR, _M, _C32, 10 }, { &tlcs900h_device::_ADCLMR, _M, _C32, 10 }, { &tlcs900h_device::_ADCLMR, _M, _C32, 10 }, { &tlcs900h_device::_ADCLMR, _M, _C32, 10 }, + { &tlcs900h_device::_ADCLMR, _M, _C32, 10 }, { &tlcs900h_device::_ADCLMR, _M, _C32, 10 }, { &tlcs900h_device::_ADCLMR, _M, _C32, 10 }, { &tlcs900h_device::_ADCLMR, _M, _C32, 10 }, + + /* A0 - BF */ + { &tlcs900h_device::_SUBLRM, _C32, _M, 6 }, { &tlcs900h_device::_SUBLRM, _C32, _M, 6 }, { &tlcs900h_device::_SUBLRM, _C32, _M, 6 }, { &tlcs900h_device::_SUBLRM, _C32, _M, 6 }, + { &tlcs900h_device::_SUBLRM, _C32, _M, 6 }, { &tlcs900h_device::_SUBLRM, _C32, _M, 6 }, { &tlcs900h_device::_SUBLRM, _C32, _M, 6 }, { &tlcs900h_device::_SUBLRM, _C32, _M, 6 }, + { &tlcs900h_device::_SUBLMR, _M, _C32, 10 }, { &tlcs900h_device::_SUBLMR, _M, _C32, 10 }, { &tlcs900h_device::_SUBLMR, _M, _C32, 10 }, { &tlcs900h_device::_SUBLMR, _M, _C32, 10 }, + { &tlcs900h_device::_SUBLMR, _M, _C32, 10 }, { &tlcs900h_device::_SUBLMR, _M, _C32, 10 }, { &tlcs900h_device::_SUBLMR, _M, _C32, 10 }, { &tlcs900h_device::_SUBLMR, _M, _C32, 10 }, + { &tlcs900h_device::_SBCLRM, _C32, _M, 6 }, { &tlcs900h_device::_SBCLRM, _C32, _M, 6 }, { &tlcs900h_device::_SBCLRM, _C32, _M, 6 }, { &tlcs900h_device::_SBCLRM, _C32, _M, 6 }, + { &tlcs900h_device::_SBCLRM, _C32, _M, 6 }, { &tlcs900h_device::_SBCLRM, _C32, _M, 6 }, { &tlcs900h_device::_SBCLRM, _C32, _M, 6 }, { &tlcs900h_device::_SBCLRM, _C32, _M, 6 }, + { &tlcs900h_device::_SBCLMR, _M, _C32, 10 }, { &tlcs900h_device::_SBCLMR, _M, _C32, 10 }, { &tlcs900h_device::_SBCLMR, _M, _C32, 10 }, { &tlcs900h_device::_SBCLMR, _M, _C32, 10 }, + { &tlcs900h_device::_SBCLMR, _M, _C32, 10 }, { &tlcs900h_device::_SBCLMR, _M, _C32, 10 }, { &tlcs900h_device::_SBCLMR, _M, _C32, 10 }, { &tlcs900h_device::_SBCLMR, _M, _C32, 10 }, + + /* C0 - DF */ + { &tlcs900h_device::_ANDLRM, _C32, _M, 6 }, { &tlcs900h_device::_ANDLRM, _C32, _M, 6 }, { &tlcs900h_device::_ANDLRM, _C32, _M, 6 }, { &tlcs900h_device::_ANDLRM, _C32, _M, 6 }, + { &tlcs900h_device::_ANDLRM, _C32, _M, 6 }, { &tlcs900h_device::_ANDLRM, _C32, _M, 6 }, { &tlcs900h_device::_ANDLRM, _C32, _M, 6 }, { &tlcs900h_device::_ANDLRM, _C32, _M, 6 }, + { &tlcs900h_device::_ANDLMR, _M, _C32, 10 }, { &tlcs900h_device::_ANDLMR, _M, _C32, 10 }, { &tlcs900h_device::_ANDLMR, _M, _C32, 10 }, { &tlcs900h_device::_ANDLMR, _M, _C32, 10 }, + { &tlcs900h_device::_ANDLMR, _M, _C32, 10 }, { &tlcs900h_device::_ANDLMR, _M, _C32, 10 }, { &tlcs900h_device::_ANDLMR, _M, _C32, 10 }, { &tlcs900h_device::_ANDLMR, _M, _C32, 10 }, + { &tlcs900h_device::_XORLRM, _C32, _M, 6 }, { &tlcs900h_device::_XORLRM, _C32, _M, 6 }, { &tlcs900h_device::_XORLRM, _C32, _M, 6 }, { &tlcs900h_device::_XORLRM, _C32, _M, 6 }, + { &tlcs900h_device::_XORLRM, _C32, _M, 6 }, { &tlcs900h_device::_XORLRM, _C32, _M, 6 }, { &tlcs900h_device::_XORLRM, _C32, _M, 6 }, { &tlcs900h_device::_XORLRM, _C32, _M, 6 }, + { &tlcs900h_device::_XORLMR, _M, _C32, 10 }, { &tlcs900h_device::_XORLMR, _M, _C32, 10 }, { &tlcs900h_device::_XORLMR, _M, _C32, 10 }, { &tlcs900h_device::_XORLMR, _M, _C32, 10 }, + { &tlcs900h_device::_XORLMR, _M, _C32, 10 }, { &tlcs900h_device::_XORLMR, _M, _C32, 10 }, { &tlcs900h_device::_XORLMR, _M, _C32, 10 }, { &tlcs900h_device::_XORLMR, _M, _C32, 10 }, + + /* E0 - FF */ + { &tlcs900h_device::_ORLRM, _C32, _M, 6 }, { &tlcs900h_device::_ORLRM, _C32, _M, 6 }, { &tlcs900h_device::_ORLRM, _C32, _M, 6 }, { &tlcs900h_device::_ORLRM, _C32, _M, 6 }, + { &tlcs900h_device::_ORLRM, _C32, _M, 6 }, { &tlcs900h_device::_ORLRM, _C32, _M, 6 }, { &tlcs900h_device::_ORLRM, _C32, _M, 6 }, { &tlcs900h_device::_ORLRM, _C32, _M, 6 }, + { &tlcs900h_device::_ORLMR, _M, _C32, 10 }, { &tlcs900h_device::_ORLMR, _M, _C32, 10 }, { &tlcs900h_device::_ORLMR, _M, _C32, 10 }, { &tlcs900h_device::_ORLMR, _M, _C32, 10 }, + { &tlcs900h_device::_ORLMR, _M, _C32, 10 }, { &tlcs900h_device::_ORLMR, _M, _C32, 10 }, { &tlcs900h_device::_ORLMR, _M, _C32, 10 }, { &tlcs900h_device::_ORLMR, _M, _C32, 10 }, + { &tlcs900h_device::_CPLRM, _C32, _M, 6 }, { &tlcs900h_device::_CPLRM, _C32, _M, 6 }, { &tlcs900h_device::_CPLRM, _C32, _M, 6 }, { &tlcs900h_device::_CPLRM, _C32, _M, 6 }, + { &tlcs900h_device::_CPLRM, _C32, _M, 6 }, { &tlcs900h_device::_CPLRM, _C32, _M, 6 }, { &tlcs900h_device::_CPLRM, _C32, _M, 6 }, { &tlcs900h_device::_CPLRM, _C32, _M, 6 }, + { &tlcs900h_device::_CPLMR, _M, _C32, 6 }, { &tlcs900h_device::_CPLMR, _M, _C32, 6 }, { &tlcs900h_device::_CPLMR, _M, _C32, 6 }, { &tlcs900h_device::_CPLMR, _M, _C32, 6 }, + { &tlcs900h_device::_CPLMR, _M, _C32, 6 }, { &tlcs900h_device::_CPLMR, _M, _C32, 6 }, { &tlcs900h_device::_CPLMR, _M, _C32, 6 }, { &tlcs900h_device::_CPLMR, _M, _C32, 6 }, +}; + + +const tlcs900h_device::tlcs900inst tlcs900h_device::s_mnemonic_e8[256] = +{ + /* 00 - 1F */ + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_LDLRI, _R, _I32, 6 }, + { &tlcs900h_device::_PUSHLR, _R, 0, 7 }, { &tlcs900h_device::_POPLR, _R, 0, 8 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_LINK, _R, _I16, 10 }, { &tlcs900h_device::_UNLK, _R, 0, 8 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_EXTZLR, _R, 0, 4 }, { &tlcs900h_device::_EXTSLR, _R, 0, 5 }, + { &tlcs900h_device::_PAALR, _R, 0, 4 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + + /* 20 - 3F */ + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_LDCLRR, _CR32, _R, 1 }, { &tlcs900h_device::_LDCLRR, _R, _CR32, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + + /* 40 - 5F */ + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + + /* 60 - 7F */ + { &tlcs900h_device::_INCLIR, _I3, _R, 4 }, { &tlcs900h_device::_INCLIR, _I3, _R, 4 }, { &tlcs900h_device::_INCLIR, _I3, _R, 4 }, { &tlcs900h_device::_INCLIR, _I3, _R, 4 }, + { &tlcs900h_device::_INCLIR, _I3, _R, 4 }, { &tlcs900h_device::_INCLIR, _I3, _R, 4 }, { &tlcs900h_device::_INCLIR, _I3, _R, 4 }, { &tlcs900h_device::_INCLIR, _I3, _R, 4 }, + { &tlcs900h_device::_DECLIR, _I3, _R, 4 }, { &tlcs900h_device::_DECLIR, _I3, _R, 4 }, { &tlcs900h_device::_DECLIR, _I3, _R, 4 }, { &tlcs900h_device::_DECLIR, _I3, _R, 4 }, + { &tlcs900h_device::_DECLIR, _I3, _R, 4 }, { &tlcs900h_device::_DECLIR, _I3, _R, 4 }, { &tlcs900h_device::_DECLIR, _I3, _R, 4 }, { &tlcs900h_device::_DECLIR, _I3, _R, 4 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + + /* 80 - 9F */ + { &tlcs900h_device::_ADDLRR, _C32, _R, 7 }, { &tlcs900h_device::_ADDLRR, _C32, _R, 7 }, { &tlcs900h_device::_ADDLRR, _C32, _R, 7 }, { &tlcs900h_device::_ADDLRR, _C32, _R, 7 }, + { &tlcs900h_device::_ADDLRR, _C32, _R, 7 }, { &tlcs900h_device::_ADDLRR, _C32, _R, 7 }, { &tlcs900h_device::_ADDLRR, _C32, _R, 7 }, { &tlcs900h_device::_ADDLRR, _C32, _R, 7 }, + { &tlcs900h_device::_LDLRR, _C32, _R, 4 }, { &tlcs900h_device::_LDLRR, _C32, _R, 4 }, { &tlcs900h_device::_LDLRR, _C32, _R, 4 }, { &tlcs900h_device::_LDLRR, _C32, _R, 4 }, + { &tlcs900h_device::_LDLRR, _C32, _R, 4 }, { &tlcs900h_device::_LDLRR, _C32, _R, 4 }, { &tlcs900h_device::_LDLRR, _C32, _R, 4 }, { &tlcs900h_device::_LDLRR, _C32, _R, 4 }, + { &tlcs900h_device::_ADCLRR, _C32, _R, 7 }, { &tlcs900h_device::_ADCLRR, _C32, _R, 7 }, { &tlcs900h_device::_ADCLRR, _C32, _R, 7 }, { &tlcs900h_device::_ADCLRR, _C32, _R, 7 }, + { &tlcs900h_device::_ADCLRR, _C32, _R, 7 }, { &tlcs900h_device::_ADCLRR, _C32, _R, 7 }, { &tlcs900h_device::_ADCLRR, _C32, _R, 7 }, { &tlcs900h_device::_ADCLRR, _C32, _R, 7 }, + { &tlcs900h_device::_LDLRR, _R, _C32, 4 }, { &tlcs900h_device::_LDLRR, _R, _C32, 4 }, { &tlcs900h_device::_LDLRR, _R, _C32, 4 }, { &tlcs900h_device::_LDLRR, _R, _C32, 4 }, + { &tlcs900h_device::_LDLRR, _R, _C32, 4 }, { &tlcs900h_device::_LDLRR, _R, _C32, 4 }, { &tlcs900h_device::_LDLRR, _R, _C32, 4 }, { &tlcs900h_device::_LDLRR, _R, _C32, 4 }, + + /* A0 - BF */ + { &tlcs900h_device::_SUBLRR, _C32, _R, 7 }, { &tlcs900h_device::_SUBLRR, _C32, _R, 7 }, { &tlcs900h_device::_SUBLRR, _C32, _R, 7 }, { &tlcs900h_device::_SUBLRR, _C32, _R, 7 }, + { &tlcs900h_device::_SUBLRR, _C32, _R, 7 }, { &tlcs900h_device::_SUBLRR, _C32, _R, 7 }, { &tlcs900h_device::_SUBLRR, _C32, _R, 7 }, { &tlcs900h_device::_SUBLRR, _C32, _R, 7 }, + { &tlcs900h_device::_LDLRI, _R, _I3, 4 }, { &tlcs900h_device::_LDLRI, _R, _I3, 4 }, { &tlcs900h_device::_LDLRI, _R, _I3, 4 }, { &tlcs900h_device::_LDLRI, _R, _I3, 4 }, + { &tlcs900h_device::_LDLRI, _R, _I3, 4 }, { &tlcs900h_device::_LDLRI, _R, _I3, 4 }, { &tlcs900h_device::_LDLRI, _R, _I3, 4 }, { &tlcs900h_device::_LDLRI, _R, _I3, 4 }, + { &tlcs900h_device::_SBCLRR, _C32, _R, 7 }, { &tlcs900h_device::_SBCLRR, _C32, _R, 7 }, { &tlcs900h_device::_SBCLRR, _C32, _R, 7 }, { &tlcs900h_device::_SBCLRR, _C32, _R, 7 }, + { &tlcs900h_device::_SBCLRR, _C32, _R, 7 }, { &tlcs900h_device::_SBCLRR, _C32, _R, 7 }, { &tlcs900h_device::_SBCLRR, _C32, _R, 7 }, { &tlcs900h_device::_SBCLRR, _C32, _R, 7 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + + /* C0 - DF */ + { &tlcs900h_device::_ANDLRR, _C32, _R, 7 }, { &tlcs900h_device::_ANDLRR, _C32, _R, 7 }, { &tlcs900h_device::_ANDLRR, _C32, _R, 7 }, { &tlcs900h_device::_ANDLRR, _C32, _R, 7 }, + { &tlcs900h_device::_ANDLRR, _C32, _R, 7 }, { &tlcs900h_device::_ANDLRR, _C32, _R, 7 }, { &tlcs900h_device::_ANDLRR, _C32, _R, 7 }, { &tlcs900h_device::_ANDLRR, _C32, _R, 7 }, + { &tlcs900h_device::_ADDLRI, _R, _I32, 7 }, { &tlcs900h_device::_ADCLRI, _R, _I32, 7 }, { &tlcs900h_device::_SUBLRI, _R, _I32, 7 }, { &tlcs900h_device::_SBCLRI, _R, _I32, 7 }, + { &tlcs900h_device::_ANDLRI, _R, _I32, 7 }, { &tlcs900h_device::_XORLRI, _R, _I32, 7 }, { &tlcs900h_device::_ORLRI, _R, _I32, 7 }, { &tlcs900h_device::_CPLRI, _R, _I32, 7 }, + { &tlcs900h_device::_XORLRR, _C32, _R, 7 }, { &tlcs900h_device::_XORLRR, _C32, _R, 7 }, { &tlcs900h_device::_XORLRR, _C32, _R, 7 }, { &tlcs900h_device::_XORLRR, _C32, _R, 7 }, + { &tlcs900h_device::_XORLRR, _C32, _R, 7 }, { &tlcs900h_device::_XORLRR, _C32, _R, 7 }, { &tlcs900h_device::_XORLRR, _C32, _R, 7 }, { &tlcs900h_device::_XORLRR, _C32, _R, 7 }, + { &tlcs900h_device::_CPLRI, _R, _I3, 6 }, { &tlcs900h_device::_CPLRI, _R, _I3, 6 }, { &tlcs900h_device::_CPLRI, _R, _I3, 6 }, { &tlcs900h_device::_CPLRI, _R, _I3, 6 }, + { &tlcs900h_device::_CPLRI, _R, _I3, 6 }, { &tlcs900h_device::_CPLRI, _R, _I3, 6 }, { &tlcs900h_device::_CPLRI, _R, _I3, 6 }, { &tlcs900h_device::_CPLRI, _R, _I3, 6 }, + + /* E0 - FF */ + { &tlcs900h_device::_ORLRR, _C32, _R, 7 }, { &tlcs900h_device::_ORLRR, _C32, _R, 7 }, { &tlcs900h_device::_ORLRR, _C32, _R, 7 }, { &tlcs900h_device::_ORLRR, _C32, _R, 7 }, + { &tlcs900h_device::_ORLRR, _C32, _R, 7 }, { &tlcs900h_device::_ORLRR, _C32, _R, 7 }, { &tlcs900h_device::_ORLRR, _C32, _R, 7 }, { &tlcs900h_device::_ORLRR, _C32, _R, 7 }, + { &tlcs900h_device::_RLCLIR, _I8, _R, 8 }, { &tlcs900h_device::_RRCLIR, _I8, _R, 8 }, { &tlcs900h_device::_RLLIR, _I8, _R, 8 }, { &tlcs900h_device::_RRLIR, _I8, _R, 8 }, + { &tlcs900h_device::_SLALIR, _I8, _R, 8 }, { &tlcs900h_device::_SRALIR, _I8, _R, 8 }, { &tlcs900h_device::_SLLLIR, _I8, _R, 8 }, { &tlcs900h_device::_SRLLIR, _I8, _R, 8 }, + { &tlcs900h_device::_CPLRR, _C32, _R, 7 }, { &tlcs900h_device::_CPLRR, _C32, _R, 7 }, { &tlcs900h_device::_CPLRR, _C32, _R, 7 }, { &tlcs900h_device::_CPLRR, _C32, _R, 7 }, + { &tlcs900h_device::_CPLRR, _C32, _R, 7 }, { &tlcs900h_device::_CPLRR, _C32, _R, 7 }, { &tlcs900h_device::_CPLRR, _C32, _R, 7 }, { &tlcs900h_device::_CPLRR, _C32, _R, 7 }, + { &tlcs900h_device::_RLCLRR, _A, _R, 8 }, { &tlcs900h_device::_RRCLRR, _A, _R, 8 }, { &tlcs900h_device::_RLLRR, _A, _R, 8 }, { &tlcs900h_device::_RRLRR, _A, _R, 8 }, + { &tlcs900h_device::_SLALRR, _A, _R, 8 }, { &tlcs900h_device::_SRALRR, _A, _R, 8 }, { &tlcs900h_device::_SLLLRR, _A, _R, 8 }, { &tlcs900h_device::_SRLLRR, _A, _R, 8 } +}; + + +const tlcs900h_device::tlcs900inst tlcs900h_device::s_mnemonic_f0[256] = +{ + /* 00 - 1F */ + { &tlcs900h_device::_LDBMI, _M, _I8, 5 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_LDWMI, _M, _I16, 6 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_POPBM, _M, 0, 6 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_POPWM, _M, 0, 6 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_LDBMM, _M, _M16, 8 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_LDWMM, _M, _M16, 8 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + + /* 20 - 3F */ + { &tlcs900h_device::_LDAW, _C16, _M, 4 }, { &tlcs900h_device::_LDAW, _C16, _M, 4 }, { &tlcs900h_device::_LDAW, _C16, _M, 4 }, { &tlcs900h_device::_LDAW, _C16, _M, 4 }, + { &tlcs900h_device::_LDAW, _C16, _M, 4 }, { &tlcs900h_device::_LDAW, _C16, _M, 4 }, { &tlcs900h_device::_LDAW, _C16, _M, 4 }, { &tlcs900h_device::_LDAW, _C16, _M, 4 }, + { &tlcs900h_device::_ANDCFBRM, _A, _M, 4 }, { &tlcs900h_device::_ORCFBRM, _A, _M, 4 }, { &tlcs900h_device::_XORCFBRM, _A, _M, 4 }, { &tlcs900h_device::_LDCFBRM, _A, _M, 4 }, + { &tlcs900h_device::_STCFBRM, _A, _M, 4 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_LDAL, _C32, _M, 4 }, { &tlcs900h_device::_LDAL, _C32, _M, 4 }, { &tlcs900h_device::_LDAL, _C32, _M, 4 }, { &tlcs900h_device::_LDAL, _C32, _M, 4 }, + { &tlcs900h_device::_LDAL, _C32, _M, 4 }, { &tlcs900h_device::_LDAL, _C32, _M, 4 }, { &tlcs900h_device::_LDAL, _C32, _M, 4 }, { &tlcs900h_device::_LDAL, _C32, _M, 4 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + + /* 40 - 5F */ + { &tlcs900h_device::_LDBMR, _M, _C8, 4 }, { &tlcs900h_device::_LDBMR, _M, _C8, 4 }, { &tlcs900h_device::_LDBMR, _M, _C8, 4 }, { &tlcs900h_device::_LDBMR, _M, _C8, 4 }, + { &tlcs900h_device::_LDBMR, _M, _C8, 4 }, { &tlcs900h_device::_LDBMR, _M, _C8, 4 }, { &tlcs900h_device::_LDBMR, _M, _C8, 4 }, { &tlcs900h_device::_LDBMR, _M, _C8, 4 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_LDWMR, _M, _C16, 4 }, { &tlcs900h_device::_LDWMR, _M, _C16, 4 }, { &tlcs900h_device::_LDWMR, _M, _C16, 4 }, { &tlcs900h_device::_LDWMR, _M, _C16, 4 }, + { &tlcs900h_device::_LDWMR, _M, _C16, 4 }, { &tlcs900h_device::_LDWMR, _M, _C16, 4 }, { &tlcs900h_device::_LDWMR, _M, _C16, 4 }, { &tlcs900h_device::_LDWMR, _M, _C16, 4 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + + /* 60 - 7F */ + { &tlcs900h_device::_LDLMR, _M, _C32, 6 }, { &tlcs900h_device::_LDLMR, _M, _C32, 6 }, { &tlcs900h_device::_LDLMR, _M, _C32, 6 }, { &tlcs900h_device::_LDLMR, _M, _C32, 6 }, + { &tlcs900h_device::_LDLMR, _M, _C32, 6 }, { &tlcs900h_device::_LDLMR, _M, _C32, 6 }, { &tlcs900h_device::_LDLMR, _M, _C32, 6 }, { &tlcs900h_device::_LDLMR, _M, _C32, 6 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + + /* 80 - 9F */ + { &tlcs900h_device::_ANDCFBIM, _I3, _M, 4 }, { &tlcs900h_device::_ANDCFBIM, _I3, _M, 4 }, { &tlcs900h_device::_ANDCFBIM, _I3, _M, 4 }, { &tlcs900h_device::_ANDCFBIM, _I3, _M, 4 }, + { &tlcs900h_device::_ANDCFBIM, _I3, _M, 4 }, { &tlcs900h_device::_ANDCFBIM, _I3, _M, 4 }, { &tlcs900h_device::_ANDCFBIM, _I3, _M, 4 }, { &tlcs900h_device::_ANDCFBIM, _I3, _M, 4 }, + { &tlcs900h_device::_ORCFBIM, _I3, _M, 4 }, { &tlcs900h_device::_ORCFBIM, _I3, _M, 4 }, { &tlcs900h_device::_ORCFBIM, _I3, _M, 4 }, { &tlcs900h_device::_ORCFBIM, _I3, _M, 4 }, + { &tlcs900h_device::_ORCFBIM, _I3, _M, 4 }, { &tlcs900h_device::_ORCFBIM, _I3, _M, 4 }, { &tlcs900h_device::_ORCFBIM, _I3, _M, 4 }, { &tlcs900h_device::_ORCFBIM, _I3, _M, 4 }, + { &tlcs900h_device::_XORCFBIM, _I3, _M, 4 }, { &tlcs900h_device::_XORCFBIM, _I3, _M, 4 }, { &tlcs900h_device::_XORCFBIM, _I3, _M, 4 }, { &tlcs900h_device::_XORCFBIM, _I3, _M, 4 }, + { &tlcs900h_device::_XORCFBIM, _I3, _M, 4 }, { &tlcs900h_device::_XORCFBIM, _I3, _M, 4 }, { &tlcs900h_device::_XORCFBIM, _I3, _M, 4 }, { &tlcs900h_device::_XORCFBIM, _I3, _M, 4 }, + { &tlcs900h_device::_LDCFBIM, _I3, _M, 4 }, { &tlcs900h_device::_LDCFBIM, _I3, _M, 4 }, { &tlcs900h_device::_LDCFBIM, _I3, _M, 4 }, { &tlcs900h_device::_LDCFBIM, _I3, _M, 4 }, + { &tlcs900h_device::_LDCFBIM, _I3, _M, 4 }, { &tlcs900h_device::_LDCFBIM, _I3, _M, 4 }, { &tlcs900h_device::_LDCFBIM, _I3, _M, 4 }, { &tlcs900h_device::_LDCFBIM, _I3, _M, 4 }, + + /* A0 - BF */ + { &tlcs900h_device::_STCFBIM, _I3, _M, 4 }, { &tlcs900h_device::_STCFBIM, _I3, _M, 4 }, { &tlcs900h_device::_STCFBIM, _I3, _M, 4 }, { &tlcs900h_device::_STCFBIM, _I3, _M, 4 }, + { &tlcs900h_device::_STCFBIM, _I3, _M, 4 }, { &tlcs900h_device::_STCFBIM, _I3, _M, 4 }, { &tlcs900h_device::_STCFBIM, _I3, _M, 4 }, { &tlcs900h_device::_STCFBIM, _I3, _M, 4 }, + { &tlcs900h_device::_TSETBIM, _I3, _M, 10 }, { &tlcs900h_device::_TSETBIM, _I3, _M, 10 }, { &tlcs900h_device::_TSETBIM, _I3, _M, 10 }, { &tlcs900h_device::_TSETBIM, _I3, _M, 10 }, + { &tlcs900h_device::_TSETBIM, _I3, _M, 10 }, { &tlcs900h_device::_TSETBIM, _I3, _M, 10 }, { &tlcs900h_device::_TSETBIM, _I3, _M, 10 }, { &tlcs900h_device::_TSETBIM, _I3, _M, 10 }, + { &tlcs900h_device::_RESBIM, _I3, _M, 8 }, { &tlcs900h_device::_RESBIM, _I3, _M, 8 }, { &tlcs900h_device::_RESBIM, _I3, _M, 8 }, { &tlcs900h_device::_RESBIM, _I3, _M, 8 }, + { &tlcs900h_device::_RESBIM, _I3, _M, 8 }, { &tlcs900h_device::_RESBIM, _I3, _M, 8 }, { &tlcs900h_device::_RESBIM, _I3, _M, 8 }, { &tlcs900h_device::_RESBIM, _I3, _M, 8 }, + { &tlcs900h_device::_SETBIM, _I3, _M, 8 }, { &tlcs900h_device::_SETBIM, _I3, _M, 8 }, { &tlcs900h_device::_SETBIM, _I3, _M, 8 }, { &tlcs900h_device::_SETBIM, _I3, _M, 8 }, + { &tlcs900h_device::_SETBIM, _I3, _M, 8 }, { &tlcs900h_device::_SETBIM, _I3, _M, 8 }, { &tlcs900h_device::_SETBIM, _I3, _M, 8 }, { &tlcs900h_device::_SETBIM, _I3, _M, 8 }, + + /* C0 - DF */ + { &tlcs900h_device::_CHGBIM, _I3, _M, 8 }, { &tlcs900h_device::_CHGBIM, _I3, _M, 8 }, { &tlcs900h_device::_CHGBIM, _I3, _M, 8 }, { &tlcs900h_device::_CHGBIM, _I3, _M, 8 }, + { &tlcs900h_device::_CHGBIM, _I3, _M, 8 }, { &tlcs900h_device::_CHGBIM, _I3, _M, 8 }, { &tlcs900h_device::_CHGBIM, _I3, _M, 8 }, { &tlcs900h_device::_CHGBIM, _I3, _M, 8 }, + { &tlcs900h_device::_BITBIM, _I3, _M, 4 }, { &tlcs900h_device::_BITBIM, _I3, _M, 4 }, { &tlcs900h_device::_BITBIM, _I3, _M, 4 }, { &tlcs900h_device::_BITBIM, _I3, _M, 4 }, + { &tlcs900h_device::_BITBIM, _I3, _M, 4 }, { &tlcs900h_device::_BITBIM, _I3, _M, 4 }, { &tlcs900h_device::_BITBIM, _I3, _M, 4 }, { &tlcs900h_device::_BITBIM, _I3, _M, 4 }, + { &tlcs900h_device::_JPM, _CC, _M, 4 }, { &tlcs900h_device::_JPM, _CC, _M, 4 }, { &tlcs900h_device::_JPM, _CC, _M, 4 }, { &tlcs900h_device::_JPM, _CC, _M, 4 }, + { &tlcs900h_device::_JPM, _CC, _M, 4 }, { &tlcs900h_device::_JPM, _CC, _M, 4 }, { &tlcs900h_device::_JPM, _CC, _M, 4 }, { &tlcs900h_device::_JPM, _CC, _M, 4 }, + { &tlcs900h_device::_JPM, _CC, _M, 4 }, { &tlcs900h_device::_JPM, _CC, _M, 4 }, { &tlcs900h_device::_JPM, _CC, _M, 4 }, { &tlcs900h_device::_JPM, _CC, _M, 4 }, + { &tlcs900h_device::_JPM, _CC, _M, 4 }, { &tlcs900h_device::_JPM, _CC, _M, 4 }, { &tlcs900h_device::_JPM, _CC, _M, 4 }, { &tlcs900h_device::_JPM, _CC, _M, 4 }, + + /* E0 - FF */ + { &tlcs900h_device::_CALLM, _CC, _M, 6 }, { &tlcs900h_device::_CALLM, _CC, _M, 6 }, { &tlcs900h_device::_CALLM, _CC, _M, 6 }, { &tlcs900h_device::_CALLM, _CC, _M, 6 }, + { &tlcs900h_device::_CALLM, _CC, _M, 6 }, { &tlcs900h_device::_CALLM, _CC, _M, 6 }, { &tlcs900h_device::_CALLM, _CC, _M, 6 }, { &tlcs900h_device::_CALLM, _CC, _M, 6 }, + { &tlcs900h_device::_CALLM, _CC, _M, 6 }, { &tlcs900h_device::_CALLM, _CC, _M, 6 }, { &tlcs900h_device::_CALLM, _CC, _M, 6 }, { &tlcs900h_device::_CALLM, _CC, _M, 6 }, + { &tlcs900h_device::_CALLM, _CC, _M, 6 }, { &tlcs900h_device::_CALLM, _CC, _M, 6 }, { &tlcs900h_device::_CALLM, _CC, _M, 6 }, { &tlcs900h_device::_CALLM, _CC, _M, 6 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 } +}; + + +/* (XWA/XBC/XDE/XHL/XIX/XIY/XIZ/XSP) used as source in byte operations */ +void tlcs900h_device::_80() +{ + const tlcs900inst *inst; + + /* For CPI/CPIR/CPD/CPDR/LDI/LDD/LDIR/LDDR operations */ + m_p1_reg32 = get_reg32_current( m_op - 1 ); + m_p2_reg32 = get_reg32_current( m_op ); + + m_ea2.d = *get_reg32_current( m_op ); + m_op = RDOP(); + inst = &s_mnemonic_80[m_op]; + prepare_operands( inst ); + (this->*inst->opfunc)(); + m_cycles += inst->cycles; +} + + +/* (XWA/XBC/XDE/XHL/XIX/XIY/XIZ/XSP + d8) used as source in byte operations */ +void tlcs900h_device::_88() +{ + const tlcs900inst *inst; + + /* For CPI/CPIR/CPD/CPDR/LDI/LDD/LDIR/LDDR operations */ + m_p1_reg32 = get_reg32_current( m_op - 1 ); + m_p2_reg32 = get_reg32_current( m_op ); + + m_ea2.d = *get_reg32_current( m_op ); + m_op = RDOP(); + m_ea2.d += (INT8)m_op; + m_cycles += 2; + m_op = RDOP(); + inst = &s_mnemonic_80[m_op]; + prepare_operands( inst ); + (this->*inst->opfunc)(); + m_cycles += inst->cycles; +} + + +/* (XWA/XBC/XDE/XHL/XIXI/XIY/XIZ/XSP) used as source in word operations */ +void tlcs900h_device::_90() +{ + const tlcs900inst *inst; + + /* For CPI/CPIR/CPD/CPDR/LDI/LDD/LDIR/LDDR operations */ + m_p1_reg32 = get_reg32_current( m_op - 1 ); + m_p2_reg32 = get_reg32_current( m_op ); + + m_ea2.d = *get_reg32_current( m_op ); + m_op = RDOP(); + inst = &s_mnemonic_90[m_op]; + prepare_operands( inst ); + (this->*inst->opfunc)(); + m_cycles += inst->cycles; +} + + +/* (XWA/XBC/XDE/XHL/XIX/XIY/XIZ/XSP + d8) used as source in word operations */ +void tlcs900h_device::_98() +{ + const tlcs900inst *inst; + + m_ea2.d = *get_reg32_current( m_op ); + m_op = RDOP(); + m_ea2.d += (INT8)m_op; + m_cycles += 2; + m_op = RDOP(); + inst = &s_mnemonic_98[m_op]; + prepare_operands( inst ); + (this->*inst->opfunc)(); + m_cycles += inst->cycles; +} + + +/* (XWA/XBC/XDE/XHL/XIX/XIY/XIZ/XSP) used as source in long word operations */ +void tlcs900h_device::_A0() +{ + const tlcs900inst *inst; + + m_ea2.d = *get_reg32_current( m_op ); + m_op = RDOP(); + inst = &s_mnemonic_a0[m_op]; + prepare_operands( inst ); + (this->*inst->opfunc)(); + m_cycles += inst->cycles; +} + + +/* (XWA/XBC/XDE/XHL/XIX/XIY/XIZ/XSP + d8) used as source in long word operations */ +void tlcs900h_device::_A8() +{ + const tlcs900inst *inst; + + m_ea2.d = *get_reg32_current( m_op ); + m_op = RDOP(); + m_ea2.d += (INT8)m_op; + m_cycles += 2; + m_op = RDOP(); + inst = &s_mnemonic_a0[m_op]; + prepare_operands( inst ); + (this->*inst->opfunc)(); + m_cycles += inst->cycles; +} + + +/* (XWA/XBC/XDE/XHL/XIX/XIY/XIZ/XSP) used as destination in operations */ +void tlcs900h_device::_B0() +{ + const tlcs900inst *inst; + + m_ea2.d = *get_reg32_current( m_op ); + m_op = RDOP(); + inst = &s_mnemonic_b0[m_op]; + prepare_operands( inst ); + (this->*inst->opfunc)(); + m_cycles += inst->cycles; +} + + +/* (XWA/XBC/XDE/XHL/XIX/XIY/XIZ/XSP + d8) used as destination in operations */ +void tlcs900h_device::_B8() +{ + const tlcs900inst *inst; + + m_ea2.d = *get_reg32_current( m_op ); + m_op = RDOP(); + m_ea2.d += (INT8)m_op; + m_cycles += 2; + m_op = RDOP(); + inst = &s_mnemonic_b8[m_op]; + prepare_operands( inst ); + (this->*inst->opfunc)(); + m_cycles += inst->cycles; +} + + +/* memory used as source in byte operations */ +void tlcs900h_device::_C0() +{ + const tlcs900inst *inst; + UINT32 *reg = NULL; + + switch ( m_op & 0x07 ) + { + case 0x00: /* (n) */ + m_ea2.d = RDOP(); + m_cycles += 2; + break; + + case 0x01: /* (nn) */ + m_ea2.d = RDOP(); + m_ea2.b.h = RDOP(); + m_cycles += 2; + break; + + case 0x02: /* (nnn) */ + m_ea2.d = RDOP(); + m_ea2.b.h = RDOP(); + m_ea2.b.h2 = RDOP(); + m_cycles += 3; + break; + + case 0x03: + m_op = RDOP(); + switch ( m_op & 0x03 ) + { + /* (xrr) */ + case 0x00: + m_ea2.d = *get_reg32( m_op ); + m_cycles += 5; + break; + + /* (xrr+d16) */ + case 0x01: + m_ea2.b.l = RDOP(); + m_ea2.b.h = RDOP(); + m_ea2.d = *get_reg32( m_op ) + m_ea2.sw.l; + m_cycles += 5; + break; + + /* unknown/illegal */ + case 0x02: + break; + + case 0x03: + switch ( m_op ) + { + /* (xrr+r8) */ + case 0x03: + m_op = RDOP(); + m_ea2.d = *get_reg32( m_op ); + m_op = RDOP(); + m_ea2.d += (INT8) *get_reg8( m_op ); + m_cycles += 8; + break; + + /* (xrr+r16) */ + case 0x07: + m_op = RDOP(); + m_ea2.d = *get_reg32( m_op ); + m_op = RDOP(); + m_ea2.d += (INT16) *get_reg16( m_op ); + m_cycles += 8; + break; + + /* (pc+d16) */ + case 0x13: + m_ea2.b.l = RDOP(); + m_ea2.b.h = RDOP(); + m_ea2.d = m_pc.d + m_ea2.sw.l; + m_cycles += 5; + break; + } + } + break; + + case 0x04: /* (-xrr) */ + m_op = RDOP(); + reg = get_reg32( m_op ); + *reg -= ( 1 << ( m_op & 0x03 ) ); + m_ea2.d = *reg; + m_cycles += 3; + break; + + case 0x05: /* (xrr+) */ + m_op = RDOP(); + reg = get_reg32( m_op ); + m_ea2.d = *reg; + *reg += ( 1 << ( m_op & 0x03 ) ); + m_cycles += 3; + break; + } + m_op = RDOP(); + inst = &s_mnemonic_c0[m_op]; + prepare_operands( inst ); + (this->*inst->opfunc)(); + m_cycles += inst->cycles; +} + + +void tlcs900h_device::oC8() +{ + const tlcs900inst *inst; + + if ( m_op & 0x08 ) + { + m_p2_reg8 = get_reg8_current( m_op ); + /* For MUL and DIV operations */ + m_p2_reg16 = get_reg16_current( ( m_op >> 1 ) & 0x03 ); + } + else + { + m_op = RDOP(); + m_p2_reg8 = get_reg8( m_op ); + /* For MUL and DIV operations */ + m_p2_reg16 = get_reg16( m_op ); + } + m_op = RDOP(); + inst = &s_mnemonic_c8[m_op]; + prepare_operands( inst ); + (this->*inst->opfunc)(); + m_cycles += inst->cycles; +} + + +/* memory used as source in word operations */ +void tlcs900h_device::_D0() +{ + const tlcs900inst *inst; + UINT32 *reg = NULL; + + switch ( m_op & 0x07 ) + { + case 0x00: /* (n) */ + m_ea2.d = RDOP(); + m_cycles += 2; + break; + + case 0x01: /* (nn) */ + m_ea2.d = RDOP(); + m_ea2.b.h = RDOP(); + m_cycles += 2; + break; + + case 0x02: /* (nnn) */ + m_ea2.d = RDOP(); + m_ea2.b.h = RDOP(); + m_ea2.b.h2 = RDOP(); + m_cycles += 3; + break; + + case 0x03: + m_op = RDOP(); + switch ( m_op & 0x03 ) + { + /* (xrr) */ + case 0x00: + m_ea2.d = *get_reg32( m_op ); + m_cycles += 5; + break; + + /* (xrr+d16) */ + case 0x01: + m_ea2.b.l = RDOP(); + m_ea2.b.h = RDOP(); + m_ea2.d = *get_reg32( m_op ) + m_ea2.sw.l; + m_cycles += 5; + break; + + /* unknown/illegal */ + case 0x02: + break; + + case 0x03: + switch ( m_op ) + { + /* (xrr+r8) */ + case 0x03: + m_op = RDOP(); + m_ea2.d = *get_reg32( m_op ); + m_op = RDOP(); + m_ea2.d += (INT8) *get_reg8( m_op ); + m_cycles += 8; + break; + + /* (xrr+r16) */ + case 0x07: + m_op = RDOP(); + m_ea2.d = *get_reg32( m_op ); + m_op = RDOP(); + m_ea2.d += (INT16) *get_reg16( m_op ); + m_cycles += 8; + break; + + /* (pc+d16) */ + case 0x13: + m_ea2.b.l = RDOP(); + m_ea2.b.h = RDOP(); + m_ea2.d = m_pc.d + m_ea2.sw.l; + m_cycles += 5; + break; + } + } + break; + + case 0x04: /* (-xrr) */ + m_op = RDOP(); + reg = get_reg32( m_op ); + *reg -= ( 1 << ( m_op & 0x03 ) ); + m_ea2.d = *reg; + m_cycles += 3; + break; + + case 0x05: /* (xrr+) */ + m_op = RDOP(); + reg = get_reg32( m_op ); + m_ea2.d = *reg; + *reg += ( 1 << ( m_op & 0x03 ) ); + m_cycles += 3; + break; + } + m_op = RDOP(); + inst = &s_mnemonic_d0[m_op]; + prepare_operands( inst ); + (this->*inst->opfunc)(); + m_cycles += inst->cycles; +} + + +void tlcs900h_device::oD8() +{ + const tlcs900inst *inst; + + if ( m_op & 0x08 ) + { + m_p2_reg16 = get_reg16_current( m_op ); + m_p2_reg32 = get_reg32_current( m_op ); + } + else + { + m_op = RDOP(); + m_p2_reg16 = get_reg16( m_op ); + m_p2_reg32 = get_reg32( m_op ); + } + m_op = RDOP(); + inst = &s_mnemonic_d8[m_op]; + prepare_operands( inst ); + (this->*inst->opfunc)(); + m_cycles += inst->cycles; +} + + +/* memory used as source in long word operations */ +void tlcs900h_device::_E0() +{ + const tlcs900inst *inst; + UINT32 *reg = NULL; + + switch ( m_op & 0x07 ) + { + case 0x00: /* (n) */ + m_ea2.d = RDOP(); + m_cycles += 2; + break; + + case 0x01: /* (nn) */ + m_ea2.d = RDOP(); + m_ea2.b.h = RDOP(); + m_cycles += 2; + break; + + case 0x02: /* (nnn) */ + m_ea2.d = RDOP(); + m_ea2.b.h = RDOP(); + m_ea2.b.h2 = RDOP(); + m_cycles += 3; + break; + + case 0x03: + m_op = RDOP(); + switch ( m_op & 0x03 ) + { + /* (xrr) */ + case 0x00: + m_ea2.d = *get_reg32( m_op ); + m_cycles += 5; + break; + + /* (xrr+d16) */ + case 0x01: + m_ea2.b.l = RDOP(); + m_ea2.b.h = RDOP(); + m_ea2.d = *get_reg32( m_op ) + m_ea2.sw.l; + m_cycles += 5; + break; + + /* unknown/illegal */ + case 0x02: + break; + + case 0x03: + switch ( m_op ) + { + /* (xrr+r8) */ + case 0x03: + m_op = RDOP(); + m_ea2.d = *get_reg32( m_op ); + m_op = RDOP(); + m_ea2.d += (INT8) *get_reg8( m_op ); + m_cycles += 8; + break; + + /* (xrr+r16) */ + case 0x07: + m_op = RDOP(); + m_ea2.d = *get_reg32( m_op ); + m_op = RDOP(); + m_ea2.d += (INT16) *get_reg16( m_op ); + m_cycles += 8; + break; + + /* (pc+d16) */ + case 0x13: + m_ea2.b.l = RDOP(); + m_ea2.b.h = RDOP(); + m_ea2.d = m_pc.d + m_ea2.sw.l; + m_cycles += 5; + break; + } + } + break; + + case 0x04: /* (-xrr) */ + m_op = RDOP(); + reg = get_reg32( m_op ); + *reg -= ( 1 << ( m_op & 0x03 ) ); + m_ea2.d = *reg; + m_cycles += 3; + break; + + case 0x05: /* (xrr+) */ + m_op = RDOP(); + reg = get_reg32( m_op ); + m_ea2.d = *reg; + *reg += ( 1 << ( m_op & 0x03 ) ); + m_cycles += 3; + break; + } + m_op = RDOP(); + inst = &s_mnemonic_e0[m_op]; + prepare_operands( inst ); + (this->*inst->opfunc)(); + m_cycles += inst->cycles; +} + + +void tlcs900h_device::_E8() +{ + const tlcs900inst *inst; + + if ( m_op & 0x08 ) + { + m_p2_reg32 = get_reg32_current( m_op ); + } + else + { + m_op = RDOP(); + m_p2_reg32 = get_reg32( m_op ); + } + m_op = RDOP(); + inst = &s_mnemonic_e8[m_op]; + prepare_operands( inst ); + (this->*inst->opfunc)(); + m_cycles += inst->cycles; +} + + +/* memory used as destination operations */ +void tlcs900h_device::_F0() +{ + const tlcs900inst *inst; + UINT32 *reg = NULL; + + switch ( m_op & 0x07 ) + { + case 0x00: /* (n) */ + m_ea2.d = RDOP(); + m_cycles += 2; + break; + + case 0x01: /* (nn) */ + m_ea2.d = RDOP(); + m_ea2.b.h = RDOP(); + m_cycles += 2; + break; + + case 0x02: /* (nnn) */ + m_ea2.d = RDOP(); + m_ea2.b.h = RDOP(); + m_ea2.b.h2 = RDOP(); + m_cycles += 3; + break; + + case 0x03: + m_op = RDOP(); + switch ( m_op & 0x03 ) + { + /* (xrr) */ + case 0x00: + m_ea2.d = *get_reg32( m_op ); + m_cycles += 5; + break; + + /* (xrr+d16) */ + case 0x01: + m_ea2.b.l = RDOP(); + m_ea2.b.h = RDOP(); + m_ea2.d = *get_reg32( m_op ) + m_ea2.sw.l; + m_cycles += 5; + break; + + /* unknown/illegal */ + case 0x02: + break; + + case 0x03: + switch ( m_op ) + { + /* (xrr+r8) */ + case 0x03: + m_op = RDOP(); + m_ea2.d = *get_reg32( m_op ); + m_op = RDOP(); + m_ea2.d += (INT8) *get_reg8( m_op ); + m_cycles += 8; + break; + + /* (xrr+r16) */ + case 0x07: + m_op = RDOP(); + m_ea2.d = *get_reg32( m_op ); + m_op = RDOP(); + m_ea2.d += (INT16) *get_reg16( m_op ); + m_cycles += 8; + break; + + /* (pc+d16) */ + case 0x13: + m_ea2.b.l = RDOP(); + m_ea2.b.h = RDOP(); + m_ea2.d = m_pc.d + m_ea2.sw.l; + m_cycles += 5; + break; + } + } + break; + + case 0x04: /* (-xrr) */ + m_op = RDOP(); + reg = get_reg32( m_op ); + *reg -= ( 1 << ( m_op & 0x03 ) ); + m_ea2.d = *reg; + m_cycles += 3; + break; + + case 0x05: /* (xrr+) */ + m_op = RDOP(); + reg = get_reg32( m_op ); + m_ea2.d = *reg; + *reg += ( 1 << ( m_op & 0x03 ) ); + m_cycles += 3; + break; + } + + m_op = RDOP(); + inst = &s_mnemonic_f0[m_op]; + prepare_operands( inst ); + (this->*inst->opfunc)(); + m_cycles += inst->cycles; +} + + +const tlcs900h_device::tlcs900inst tlcs900h_device::s_mnemonic[256] = +{ + /* 00 - 1F */ + { &tlcs900h_device::_NOP, 0, 0, 1 }, { &tlcs900h_device::_NORMAL, 0, 0, 4 }, { &tlcs900h_device::_PUSHWR, _SR, 0, 4 }, { &tlcs900h_device::_POPWSR, _SR, 0, 6 }, + { &tlcs900h_device::_MAX, 0, 0, 4 }, { &tlcs900h_device::_HALT, 0, 0, 8 }, { &tlcs900h_device::_EI, _I8, 0, 5 }, { &tlcs900h_device::_RETI, 0, 0, 12 }, + { &tlcs900h_device::_LDBMI, _M8, _I8, 5 }, { &tlcs900h_device::_PUSHBI, _I8, 0, 4 }, { &tlcs900h_device::_LDWMI, _M8, _I16, 6 }, { &tlcs900h_device::_PUSHWI, _I16, 0, 5 }, + { &tlcs900h_device::_INCF, 0, 0, 2 }, { &tlcs900h_device::_DECF, 0, 0, 2 }, { &tlcs900h_device::_RET, 0, 0, 9 }, { &tlcs900h_device::_RETD, _I16, 0, 9 }, + { &tlcs900h_device::_RCF, 0, 0, 2 }, { &tlcs900h_device::_SCF, 0, 0, 2 }, { &tlcs900h_device::_CCF, 0, 0, 2 }, { &tlcs900h_device::_ZCF, 0, 0, 2 }, + { &tlcs900h_device::_PUSHBR, _A, 0, 3 }, { &tlcs900h_device::_POPBR, _A, 0, 4 }, { &tlcs900h_device::_EXBRR, _F, _F, 2 }, { &tlcs900h_device::_LDF, _I8, 0, 2 }, + { &tlcs900h_device::_PUSHBR, _F, 0, 3 }, { &tlcs900h_device::_POPBR, _F, 0, 4 }, { &tlcs900h_device::_JPI, _I16, 0, 7 }, { &tlcs900h_device::_JPI, _I24, 0, 7 }, + { &tlcs900h_device::_CALLI, _I16, 0, 12 }, { &tlcs900h_device::_CALLI, _I24, 0, 12 }, { &tlcs900h_device::_CALR, _D16, 0, 12 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + + /* 20 - 3F */ + { &tlcs900h_device::_LDBRI, _C8, _I8, 2 }, { &tlcs900h_device::_LDBRI, _C8, _I8, 2 }, { &tlcs900h_device::_LDBRI, _C8, _I8, 2 }, { &tlcs900h_device::_LDBRI, _C8, _I8, 2 }, + { &tlcs900h_device::_LDBRI, _C8, _I8, 2 }, { &tlcs900h_device::_LDBRI, _C8, _I8, 2 }, { &tlcs900h_device::_LDBRI, _C8, _I8, 2 }, { &tlcs900h_device::_LDBRI, _C8, _I8, 2 }, + { &tlcs900h_device::_PUSHWR, _C16, 0, 3 }, { &tlcs900h_device::_PUSHWR, _C16, 0, 3 }, { &tlcs900h_device::_PUSHWR, _C16, 0, 3 }, { &tlcs900h_device::_PUSHWR, _C16, 0, 3 }, + { &tlcs900h_device::_PUSHWR, _C16, 0, 3 }, { &tlcs900h_device::_PUSHWR, _C16, 0, 3 }, { &tlcs900h_device::_PUSHWR, _C16, 0, 3 }, { &tlcs900h_device::_PUSHWR, _C16, 0, 3 }, + { &tlcs900h_device::_LDWRI, _C16, _I16, 3 }, { &tlcs900h_device::_LDWRI, _C16, _I16, 3 }, { &tlcs900h_device::_LDWRI, _C16, _I16, 3 }, { &tlcs900h_device::_LDWRI, _C16, _I16, 3 }, + { &tlcs900h_device::_LDWRI, _C16, _I16, 3 }, { &tlcs900h_device::_LDWRI, _C16, _I16, 3 }, { &tlcs900h_device::_LDWRI, _C16, _I16, 3 }, { &tlcs900h_device::_LDWRI, _C16, _I16, 3 }, + { &tlcs900h_device::_PUSHLR, _C32, 0, 5 }, { &tlcs900h_device::_PUSHLR, _C32, 0, 5 }, { &tlcs900h_device::_PUSHLR, _C32, 0, 5 }, { &tlcs900h_device::_PUSHLR, _C32, 0, 5 }, + { &tlcs900h_device::_PUSHLR, _C32, 0, 5 }, { &tlcs900h_device::_PUSHLR, _C32, 0, 5 }, { &tlcs900h_device::_PUSHLR, _C32, 0, 5 }, { &tlcs900h_device::_PUSHLR, _C32, 0, 5 }, + + /* 40 - 5F */ + { &tlcs900h_device::_LDLRI, _C32, _I32, 5 }, { &tlcs900h_device::_LDLRI, _C32, _I32, 5 }, { &tlcs900h_device::_LDLRI, _C32, _I32, 5 }, { &tlcs900h_device::_LDLRI, _C32, _I32, 5 }, + { &tlcs900h_device::_LDLRI, _C32, _I32, 5 }, { &tlcs900h_device::_LDLRI, _C32, _I32, 5 }, { &tlcs900h_device::_LDLRI, _C32, _I32, 5 }, { &tlcs900h_device::_LDLRI, _C32, _I32, 5 }, + { &tlcs900h_device::_POPWR, _C16, 0, 4 }, { &tlcs900h_device::_POPWR, _C16, 0, 4 }, { &tlcs900h_device::_POPWR, _C16, 0, 4 }, { &tlcs900h_device::_POPWR, _C16, 0, 4 }, + { &tlcs900h_device::_POPWR, _C16, 0, 4 }, { &tlcs900h_device::_POPWR, _C16, 0, 4 }, { &tlcs900h_device::_POPWR, _C16, 0, 4 }, { &tlcs900h_device::_POPWR, _C16, 0, 4 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, { &tlcs900h_device::_DB, 0, 0, 1 }, + { &tlcs900h_device::_POPLR, _C32, 0, 6 }, { &tlcs900h_device::_POPLR, _C32, 0, 6 }, { &tlcs900h_device::_POPLR, _C32, 0, 6 }, { &tlcs900h_device::_POPLR, _C32, 0, 6 }, + { &tlcs900h_device::_POPLR, _C32, 0, 6 }, { &tlcs900h_device::_POPLR, _C32, 0, 6 }, { &tlcs900h_device::_POPLR, _C32, 0, 6 }, { &tlcs900h_device::_POPLR, _C32, 0, 6 }, + + /* 60 - 7F */ + { &tlcs900h_device::_JR, _CC, _D8, 4 }, { &tlcs900h_device::_JR, _CC, _D8, 4 }, { &tlcs900h_device::_JR, _CC, _D8, 4 }, { &tlcs900h_device::_JR, _CC, _D8, 4 }, + { &tlcs900h_device::_JR, _CC, _D8, 4 }, { &tlcs900h_device::_JR, _CC, _D8, 4 }, { &tlcs900h_device::_JR, _CC, _D8, 4 }, { &tlcs900h_device::_JR, _CC, _D8, 4 }, + { &tlcs900h_device::_JR, _CC, _D8, 4 }, { &tlcs900h_device::_JR, _CC, _D8, 4 }, { &tlcs900h_device::_JR, _CC, _D8, 4 }, { &tlcs900h_device::_JR, _CC, _D8, 4 }, + { &tlcs900h_device::_JR, _CC, _D8, 4 }, { &tlcs900h_device::_JR, _CC, _D8, 4 }, { &tlcs900h_device::_JR, _CC, _D8, 4 }, { &tlcs900h_device::_JR, _CC, _D8, 4 }, + { &tlcs900h_device::_JRL, _CC, _D16, 4 }, { &tlcs900h_device::_JRL, _CC, _D16, 4 }, { &tlcs900h_device::_JRL, _CC, _D16, 4 }, { &tlcs900h_device::_JRL, _CC, _D16, 4 }, + { &tlcs900h_device::_JRL, _CC, _D16, 4 }, { &tlcs900h_device::_JRL, _CC, _D16, 4 }, { &tlcs900h_device::_JRL, _CC, _D16, 4 }, { &tlcs900h_device::_JRL, _CC, _D16, 4 }, + { &tlcs900h_device::_JRL, _CC, _D16, 4 }, { &tlcs900h_device::_JRL, _CC, _D16, 4 }, { &tlcs900h_device::_JRL, _CC, _D16, 4 }, { &tlcs900h_device::_JRL, _CC, _D16, 4 }, + { &tlcs900h_device::_JRL, _CC, _D16, 4 }, { &tlcs900h_device::_JRL, _CC, _D16, 4 }, { &tlcs900h_device::_JRL, _CC, _D16, 4 }, { &tlcs900h_device::_JRL, _CC, _D16, 4 }, + + /* 80 - 9F */ + { &tlcs900h_device::_80, 0, 0, 0 }, { &tlcs900h_device::_80, 0, 0, 0 }, { &tlcs900h_device::_80, 0, 0, 0 }, { &tlcs900h_device::_80, 0, 0, 0 }, + { &tlcs900h_device::_80, 0, 0, 0 }, { &tlcs900h_device::_80, 0, 0, 0 }, { &tlcs900h_device::_80, 0, 0, 0 }, { &tlcs900h_device::_80, 0, 0, 0 }, + { &tlcs900h_device::_88, 0, 0, 0 }, { &tlcs900h_device::_88, 0, 0, 0 }, { &tlcs900h_device::_88, 0, 0, 0 }, { &tlcs900h_device::_88, 0, 0, 0 }, + { &tlcs900h_device::_88, 0, 0, 0 }, { &tlcs900h_device::_88, 0, 0, 0 }, { &tlcs900h_device::_88, 0, 0, 0 }, { &tlcs900h_device::_88, 0, 0, 0 }, + { &tlcs900h_device::_90, 0, 0, 0 }, { &tlcs900h_device::_90, 0, 0, 0 }, { &tlcs900h_device::_90, 0, 0, 0 }, { &tlcs900h_device::_90, 0, 0, 0 }, + { &tlcs900h_device::_90, 0, 0, 0 }, { &tlcs900h_device::_90, 0, 0, 0 }, { &tlcs900h_device::_90, 0, 0, 0 }, { &tlcs900h_device::_90, 0, 0, 0 }, + { &tlcs900h_device::_98, 0, 0, 0 }, { &tlcs900h_device::_98, 0, 0, 0 }, { &tlcs900h_device::_98, 0, 0, 0 }, { &tlcs900h_device::_98, 0, 0, 0 }, + { &tlcs900h_device::_98, 0, 0, 0 }, { &tlcs900h_device::_98, 0, 0, 0 }, { &tlcs900h_device::_98, 0, 0, 0 }, { &tlcs900h_device::_98, 0, 0, 0 }, + + /* A0 - BF */ + { &tlcs900h_device::_A0, 0, 0, 0 }, { &tlcs900h_device::_A0, 0, 0, 0 }, { &tlcs900h_device::_A0, 0, 0, 0 }, { &tlcs900h_device::_A0, 0, 0, 0 }, + { &tlcs900h_device::_A0, 0, 0, 0 }, { &tlcs900h_device::_A0, 0, 0, 0 }, { &tlcs900h_device::_A0, 0, 0, 0 }, { &tlcs900h_device::_A0, 0, 0, 0 }, + { &tlcs900h_device::_A8, 0, 0, 0 }, { &tlcs900h_device::_A8, 0, 0, 0 }, { &tlcs900h_device::_A8, 0, 0, 0 }, { &tlcs900h_device::_A8, 0, 0, 0 }, + { &tlcs900h_device::_A8, 0, 0, 0 }, { &tlcs900h_device::_A8, 0, 0, 0 }, { &tlcs900h_device::_A8, 0, 0, 0 }, { &tlcs900h_device::_A8, 0, 0, 0 }, + { &tlcs900h_device::_B0, 0, 0, 0 }, { &tlcs900h_device::_B0, 0, 0, 0 }, { &tlcs900h_device::_B0, 0, 0, 0 }, { &tlcs900h_device::_B0, 0, 0, 0 }, + { &tlcs900h_device::_B0, 0, 0, 0 }, { &tlcs900h_device::_B0, 0, 0, 0 }, { &tlcs900h_device::_B0, 0, 0, 0 }, { &tlcs900h_device::_B0, 0, 0, 0 }, + { &tlcs900h_device::_B8, 0, 0, 0 }, { &tlcs900h_device::_B8, 0, 0, 0 }, { &tlcs900h_device::_B8, 0, 0, 0 }, { &tlcs900h_device::_B8, 0, 0, 0 }, + { &tlcs900h_device::_B8, 0, 0, 0 }, { &tlcs900h_device::_B8, 0, 0, 0 }, { &tlcs900h_device::_B8, 0, 0, 0 }, { &tlcs900h_device::_B8, 0, 0, 0 }, + + /* C0 - DF */ + { &tlcs900h_device::_C0, 0, 0, 0 }, { &tlcs900h_device::_C0, 0, 0, 0 }, { &tlcs900h_device::_C0, 0, 0, 0 }, { &tlcs900h_device::_C0, 0, 0, 0 }, + { &tlcs900h_device::_C0, 0, 0, 0 }, { &tlcs900h_device::_C0, 0, 0, 0 }, { &tlcs900h_device::_DB, 0, 0, 0 }, { &tlcs900h_device::oC8, 0, 0, 0 }, + { &tlcs900h_device::oC8, 0, 0, 0 }, { &tlcs900h_device::oC8, 0, 0, 0 }, { &tlcs900h_device::oC8, 0, 0, 0 }, { &tlcs900h_device::oC8, 0, 0, 0 }, + { &tlcs900h_device::oC8, 0, 0, 0 }, { &tlcs900h_device::oC8, 0, 0, 0 }, { &tlcs900h_device::oC8, 0, 0, 0 }, { &tlcs900h_device::oC8, 0, 0, 0 }, + { &tlcs900h_device::_D0, 0, 0, 0 }, { &tlcs900h_device::_D0, 0, 0, 0 }, { &tlcs900h_device::_D0, 0, 0, 0 }, { &tlcs900h_device::_D0, 0, 0, 0 }, + { &tlcs900h_device::_D0, 0, 0, 0 }, { &tlcs900h_device::_D0, 0, 0, 0 }, { &tlcs900h_device::_DB, 0, 0, 0 }, { &tlcs900h_device::oD8, 0, 0, 0 }, + { &tlcs900h_device::oD8, 0, 0, 0 }, { &tlcs900h_device::oD8, 0, 0, 0 }, { &tlcs900h_device::oD8, 0, 0, 0 }, { &tlcs900h_device::oD8, 0, 0, 0 }, + { &tlcs900h_device::oD8, 0, 0, 0 }, { &tlcs900h_device::oD8, 0, 0, 0 }, { &tlcs900h_device::oD8, 0, 0, 0 }, { &tlcs900h_device::oD8, 0, 0, 0 }, + + /* E0 - FF */ + { &tlcs900h_device::_E0, 0, 0, 0 }, { &tlcs900h_device::_E0, 0, 0, 0 }, { &tlcs900h_device::_E0, 0, 0, 0 }, { &tlcs900h_device::_E0, 0, 0, 0 }, + { &tlcs900h_device::_E0, 0, 0, 0 }, { &tlcs900h_device::_E0, 0, 0, 0 }, { &tlcs900h_device::_DB, 0, 0, 0 }, { &tlcs900h_device::_E8, 0, 0, 0 }, + { &tlcs900h_device::_E8, 0, 0, 0 }, { &tlcs900h_device::_E8, 0, 0, 0 }, { &tlcs900h_device::_E8, 0, 0, 0 }, { &tlcs900h_device::_E8, 0, 0, 0 }, + { &tlcs900h_device::_E8, 0, 0, 0 }, { &tlcs900h_device::_E8, 0, 0, 0 }, { &tlcs900h_device::_E8, 0, 0, 0 }, { &tlcs900h_device::_E8, 0, 0, 0 }, + { &tlcs900h_device::_F0, 0, 0, 0 }, { &tlcs900h_device::_F0, 0, 0, 0 }, { &tlcs900h_device::_F0, 0, 0, 0 }, { &tlcs900h_device::_F0, 0, 0, 0 }, + { &tlcs900h_device::_F0, 0, 0, 0 }, { &tlcs900h_device::_F0, 0, 0, 0 }, { &tlcs900h_device::_DB, 0, 0, 0 }, { &tlcs900h_device::_LDX, 0, 0, 9 }, + { &tlcs900h_device::_SWI, _I3, 0, 16 }, { &tlcs900h_device::_SWI, _I3, 0, 16 }, { &tlcs900h_device::_SWI, _I3, 0, 16 }, { &tlcs900h_device::_SWI, _I3, 0, 16 }, + { &tlcs900h_device::_SWI, _I3, 0, 16 }, { &tlcs900h_device::_SWI, _I3, 0, 16 }, { &tlcs900h_device::_SWI, _I3, 0, 16 }, { &tlcs900h_device::_SWI, _I3, 0, 16 } +}; diff --git a/src/devices/cpu/tlcs900/dasm900.c b/src/devices/cpu/tlcs900/dasm900.c new file mode 100644 index 00000000000..7231a2f4759 --- /dev/null +++ b/src/devices/cpu/tlcs900/dasm900.c @@ -0,0 +1,2258 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +/******************************************************************* + +Toshiba TLCS-900/H disassembly + +*******************************************************************/ + +#include "emu.h" +#include "debugger.h" +#include "tlcs900.h" + +enum e_mnemonics +{ + M_ADC, M_ADD, M_AND, M_ANDCF, M_BIT, M_BS1B, + M_BS1F, M_CALL, M_CALR, M_CCF, M_CHG, M_CP, + M_CPD, M_CPDW, M_CPDR, M_CPDRW, M_CPI, M_CPIR, + M_CPIRW, M_CPIW, M_CPL, M_DAA, M_DB, M_DEC, + M_DECF, M_DECW, M_DIV, M_DIVS, M_DJNZ, M_EI, + M_EX, M_EXTS, M_EXTZ, M_HALT, M_INC, M_INCF, + M_INCW, M_JP, M_JR, M_JRL, M_LD, M_LDA, + M_LDC, M_LDCF, M_LDD, M_LDDR, M_LDDRW, M_LDDW, + M_LDF, M_LDI, M_LDIR, M_LDIRW, M_LDIW, M_LDW, + M_LDX, M_LINK, M_MAX, M_MDEC1, M_MDEC2, M_MDEC4, + M_MINC1, M_MINC2, M_MINC4, M_MIRR, M_MUL, M_MULA, + M_MULS, M_NEG, M_NOP, M_NORMAL, M_OR, M_ORCF, + M_PAA, M_POP, M_POPW, M_PUSH, M_PUSHW, M_RCF, + M_RES, M_RET, M_RETD, M_RETI, M_RL, M_RLC, + M_RLCW, M_RLD, M_RLW, M_RR, M_RRC, M_RRCW, + M_RRD, M_RRW, M_SBC, M_SCC, M_SCF, M_SET, + M_SLA, M_SLAW, M_SLL, M_SLLW, M_SRA, M_SRAW, + M_SRL, M_SRLW, M_STCF, M_SUB, M_SWI, M_TSET, + M_UNLK, M_XOR, M_XORCF, M_ZCF, + M_80, M_88, M_90, M_98, M_A0, M_A8, M_B0, M_B8, + M_C0, oC8, M_D0, oD8, M_E0, M_E8, M_F0 +}; + + +static const char *const s_mnemonic[] = +{ + "adc", "add", "and", "andcf", "bit", "bs1b", + "bs1f", "call", "calr", "ccf", "chg", "cp", + "cpd", "cpdw", "cpdr", "cpdrw", "cpi", "cpir", + "cpirw", "cpiw", "cpl", "daa", "db", "dec", + "decf", "decw", "div", "divs", "djnz", "ei", + "ex", "exts", "extz", "halt", "inc", "incf", + "incw", "jp" ,"jr", "jrl", "ld", "lda", + "ldc", "ldcf", "ldd", "lddr", "lddrw", "lddw", + "ldf", "ldi", "ldir", "ldirw", "ldiw", "ldw", + "ldx", "link", "max", "mdec1", "mdec2", "mdec4", + "minc1", "minc2", "minc4", "mirr", "mul", "mula", + "muls", "neg", "nop", "normal", "or", "orcf", + "paa", "pop", "popw", "push", "pushw", "rcf", + "res", "ret", "retd", "reti", "rl", "rlc", + "rlcw", "rld", "rlw", "rr", "rrc", "rrcw", + "rrd", "rrw", "sbc", "scc", "scf", "set", + "sla", "slaw", "sll", "sllw", "sra", "sraw", + "srl", "srlw", "stcf", "sub", "swi", "tset", + "unlk", "xor", "xorcf", "zcf", + "db", "db", "db", "db", "db", "db", "db", "db", + "db", "db", "db", "db", "db", "db", "db" +}; + + +enum e_operand +{ + O_NONE, + O_A, /* currect register set register A */ + O_C8, /* current register set byte */ + O_C16, /* current register set word */ + O_C32, /* current register set long word */ + O_MC16, /* current register set mul/div register word */ + O_CC, /* condition */ + O_CR8, /* byte control register */ + O_CR16, /* word control register */ + O_CR32, /* long word control register */ + O_D8, /* byte displacement */ + O_D16, /* word displacement */ + O_F, /* F register */ + O_I3, /* immediate 3 bit (part of last byte) */ + O_I8, /* immediate byte */ + O_I16, /* immediate word */ + O_I24, /* immediate 3 byte address */ + O_I32, /* immediate long word */ + O_M, /* memory location (defined by extension) */ + O_M8, /* (8) */ + O_M16, /* (i16) */ + O_R, /* register */ + O_SR /* status register */ +}; + + +struct tlcs900inst +{ + e_mnemonics mnemonic; + e_operand operand1; + e_operand operand2; +}; + + +static const tlcs900inst mnemonic_80[256] = +{ + /* 00 - 1F */ + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_PUSH, O_M, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_RLD, O_A, O_M }, { M_RRD, O_A, O_M }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_LDI, O_NONE, O_NONE }, { M_LDIR, O_NONE, O_NONE }, { M_LDD, O_NONE, O_NONE }, { M_LDDR, O_NONE, O_NONE }, + { M_CPI, O_NONE, O_NONE }, { M_CPIR, O_NONE, O_NONE }, { M_CPD, O_NONE, O_NONE }, { M_CPDR, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_LD, O_M16, O_M }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + + /* 20 - 3F */ + { M_LD, O_C8, O_M }, { M_LD, O_C8, O_M }, { M_LD, O_C8, O_M }, { M_LD, O_C8, O_M }, + { M_LD, O_C8, O_M }, { M_LD, O_C8, O_M }, { M_LD, O_C8, O_M }, { M_LD, O_C8, O_M }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_EX, O_M, O_C8 }, { M_EX, O_M, O_C8 }, { M_EX, O_M, O_C8 }, { M_EX, O_M, O_C8 }, + { M_EX, O_M, O_C8 }, { M_EX, O_M, O_C8 }, { M_EX, O_M, O_C8 }, { M_EX, O_M, O_C8 }, + { M_ADD, O_M, O_I8 }, { M_ADC, O_M, O_I8 }, { M_SUB, O_M, O_I8 }, { M_SBC, O_M, O_I8 }, + { M_AND, O_M, O_I8 }, { M_XOR, O_M, O_I8 }, { M_OR, O_M, O_I8 }, { M_CP, O_M, O_I8 }, + + /* 40 - 5F */ + { M_MUL, O_MC16, O_M }, { M_MUL, O_MC16, O_M }, { M_MUL, O_MC16, O_M }, { M_MUL, O_MC16, O_M }, + { M_MUL, O_MC16, O_M }, { M_MUL, O_MC16, O_M }, { M_MUL, O_MC16, O_M }, { M_MUL, O_MC16, O_M }, + { M_MULS, O_MC16, O_M }, { M_MULS, O_MC16, O_M }, { M_MULS, O_MC16, O_M }, { M_MULS, O_MC16, O_M }, + { M_MULS, O_MC16, O_M }, { M_MULS, O_MC16, O_M }, { M_MULS, O_MC16, O_M }, { M_MULS, O_MC16, O_M }, + { M_DIV, O_MC16, O_M }, { M_DIV, O_MC16, O_M }, { M_DIV, O_MC16, O_M }, { M_DIV, O_MC16, O_M }, + { M_DIV, O_MC16, O_M }, { M_DIV, O_MC16, O_M }, { M_DIV, O_MC16, O_M }, { M_DIV, O_MC16, O_M }, + { M_DIVS, O_MC16, O_M }, { M_DIVS, O_MC16, O_M }, { M_DIVS, O_MC16, O_M }, { M_DIVS, O_MC16, O_M }, + { M_DIVS, O_MC16, O_M }, { M_DIVS, O_MC16, O_M }, { M_DIVS, O_MC16, O_M }, { M_DIVS, O_MC16, O_M }, + + /* 60 - 7F */ + { M_INC, O_I3, O_M }, { M_INC, O_I3, O_M }, { M_INC, O_I3, O_M }, { M_INC, O_I3, O_M }, + { M_INC, O_I3, O_M }, { M_INC, O_I3, O_M }, { M_INC, O_I3, O_M }, { M_INC, O_I3, O_M }, + { M_DEC, O_I3, O_M }, { M_DEC, O_I3, O_M }, { M_DEC, O_I3, O_M }, { M_DEC, O_I3, O_M }, + { M_DEC, O_I3, O_M }, { M_DEC, O_I3, O_M }, { M_DEC, O_I3, O_M }, { M_DEC, O_I3, O_M }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_RLC, O_M, O_NONE }, { M_RRC, O_M, O_NONE }, { M_RL, O_M, O_NONE }, { M_RR, O_M, O_NONE }, + { M_SLA, O_M, O_NONE }, { M_SRA, O_M, O_NONE }, { M_SLL, O_M, O_NONE }, { M_SRL, O_M, O_NONE }, + + /* 80 - 9F */ + { M_ADD, O_C8, O_M }, { M_ADD, O_C8, O_M }, { M_ADD, O_C8, O_M }, { M_ADD, O_C8, O_M }, + { M_ADD, O_C8, O_M }, { M_ADD, O_C8, O_M }, { M_ADD, O_C8, O_M }, { M_ADD, O_C8, O_M }, + { M_ADD, O_M, O_C8 }, { M_ADD, O_M, O_C8 }, { M_ADD, O_M, O_C8 }, { M_ADD, O_M, O_C8 }, + { M_ADD, O_M, O_C8 }, { M_ADD, O_M, O_C8 }, { M_ADD, O_M, O_C8 }, { M_ADD, O_M, O_C8 }, + { M_ADC, O_C8, O_M }, { M_ADC, O_C8, O_M }, { M_ADC, O_C8, O_M }, { M_ADC, O_C8, O_M }, + { M_ADC, O_C8, O_M }, { M_ADC, O_C8, O_M }, { M_ADC, O_C8, O_M }, { M_ADC, O_C8, O_M }, + { M_ADC, O_M, O_C8 }, { M_ADC, O_M, O_C8 }, { M_ADC, O_M, O_C8 }, { M_ADC, O_M, O_C8 }, + { M_ADC, O_M, O_C8 }, { M_ADC, O_M, O_C8 }, { M_ADC, O_M, O_C8 }, { M_ADC, O_M, O_C8 }, + + /* A0 - BF */ + { M_SUB, O_C8, O_M }, { M_SUB, O_C8, O_M }, { M_SUB, O_C8, O_M }, { M_SUB, O_C8, O_M }, + { M_SUB, O_C8, O_M }, { M_SUB, O_C8, O_M }, { M_SUB, O_C8, O_M }, { M_SUB, O_C8, O_M }, + { M_SUB, O_M, O_C8 }, { M_SUB, O_M, O_C8 }, { M_SUB, O_M, O_C8 }, { M_SUB, O_M, O_C8 }, + { M_SUB, O_M, O_C8 }, { M_SUB, O_M, O_C8 }, { M_SUB, O_M, O_C8 }, { M_SUB, O_M, O_C8 }, + { M_SBC, O_C8, O_M }, { M_SBC, O_C8, O_M }, { M_SBC, O_C8, O_M }, { M_SBC, O_C8, O_M }, + { M_SBC, O_C8, O_M }, { M_SBC, O_C8, O_M }, { M_SBC, O_C8, O_M }, { M_SBC, O_C8, O_M }, + { M_SBC, O_M, O_C8 }, { M_SBC, O_M, O_C8 }, { M_SBC, O_M, O_C8 }, { M_SBC, O_M, O_C8 }, + { M_SBC, O_M, O_C8 }, { M_SBC, O_M, O_C8 }, { M_SBC, O_M, O_C8 }, { M_SBC, O_M, O_C8 }, + + /* C0 - DF */ + { M_AND, O_C8, O_M }, { M_AND, O_C8, O_M }, { M_AND, O_C8, O_M }, { M_AND, O_C8, O_M }, + { M_AND, O_C8, O_M }, { M_AND, O_C8, O_M }, { M_AND, O_C8, O_M }, { M_AND, O_C8, O_M }, + { M_AND, O_M, O_C8 }, { M_AND, O_M, O_C8 }, { M_AND, O_M, O_C8 }, { M_AND, O_M, O_C8 }, + { M_AND, O_M, O_C8 }, { M_AND, O_M, O_C8 }, { M_AND, O_M, O_C8 }, { M_AND, O_M, O_C8 }, + { M_XOR, O_C8, O_M }, { M_XOR, O_C8, O_M }, { M_XOR, O_C8, O_M }, { M_XOR, O_C8, O_M }, + { M_XOR, O_C8, O_M }, { M_XOR, O_C8, O_M }, { M_XOR, O_C8, O_M }, { M_XOR, O_C8, O_M }, + { M_XOR, O_M, O_C8 }, { M_XOR, O_M, O_C8 }, { M_XOR, O_M, O_C8 }, { M_XOR, O_M, O_C8 }, + { M_XOR, O_M, O_C8 }, { M_XOR, O_M, O_C8 }, { M_XOR, O_M, O_C8 }, { M_XOR, O_M, O_C8 }, + + /* E0 - FF */ + { M_OR, O_C8, O_M }, { M_OR, O_C8, O_M }, { M_OR, O_C8, O_M }, { M_OR, O_C8, O_M }, + { M_OR, O_C8, O_M }, { M_OR, O_C8, O_M }, { M_OR, O_C8, O_M }, { M_OR, O_C8, O_M }, + { M_OR, O_M, O_C8 }, { M_OR, O_M, O_C8 }, { M_OR, O_M, O_C8 }, { M_OR, O_M, O_C8 }, + { M_OR, O_M, O_C8 }, { M_OR, O_M, O_C8 }, { M_OR, O_M, O_C8 }, { M_OR, O_M, O_C8 }, + { M_CP, O_C8, O_M }, { M_CP, O_C8, O_M }, { M_CP, O_C8, O_M }, { M_CP, O_C8, O_M }, + { M_CP, O_C8, O_M }, { M_CP, O_C8, O_M }, { M_CP, O_C8, O_M }, { M_CP, O_C8, O_M }, + { M_CP, O_M, O_C8 }, { M_CP, O_M, O_C8 }, { M_CP, O_M, O_C8 }, { M_CP, O_M, O_C8 }, + { M_CP, O_M, O_C8 }, { M_CP, O_M, O_C8 }, { M_CP, O_M, O_C8 }, { M_CP, O_M, O_C8 }, +}; + + +static const tlcs900inst mnemonic_88[256] = +{ + /* 00 - 1F */ + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_PUSH, O_M, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_RLD, O_A, O_M }, { M_RRD, O_A, O_M }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_LD, O_M16, O_M }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + + /* 20 - 3F */ + { M_LD, O_C8, O_M }, { M_LD, O_C8, O_M }, { M_LD, O_C8, O_M }, { M_LD, O_C8, O_M }, + { M_LD, O_C8, O_M }, { M_LD, O_C8, O_M }, { M_LD, O_C8, O_M }, { M_LD, O_C8, O_M }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_EX, O_M, O_C8 }, { M_EX, O_M, O_C8 }, { M_EX, O_M, O_C8 }, { M_EX, O_M, O_C8 }, + { M_EX, O_M, O_C8 }, { M_EX, O_M, O_C8 }, { M_EX, O_M, O_C8 }, { M_EX, O_M, O_C8 }, + { M_ADD, O_M, O_I8 }, { M_ADC, O_M, O_I8 }, { M_SUB, O_M, O_I8 }, { M_SBC, O_M, O_I8 }, + { M_AND, O_M, O_I8 }, { M_XOR, O_M, O_I8 }, { M_OR, O_M, O_I8 }, { M_CP, O_M, O_I8 }, + + /* 40 - 5F */ + { M_MUL, O_MC16, O_M }, { M_MUL, O_MC16, O_M }, { M_MUL, O_MC16, O_M }, { M_MUL, O_MC16, O_M }, + { M_MUL, O_MC16, O_M }, { M_MUL, O_MC16, O_M }, { M_MUL, O_MC16, O_M }, { M_MUL, O_MC16, O_M }, + { M_MULS, O_MC16, O_M }, { M_MULS, O_MC16, O_M }, { M_MULS, O_MC16, O_M }, { M_MULS, O_MC16, O_M }, + { M_MULS, O_MC16, O_M }, { M_MULS, O_MC16, O_M }, { M_MULS, O_MC16, O_M }, { M_MULS, O_MC16, O_M }, + { M_DIV, O_MC16, O_M }, { M_DIV, O_MC16, O_M }, { M_DIV, O_MC16, O_M }, { M_DIV, O_MC16, O_M }, + { M_DIV, O_MC16, O_M }, { M_DIV, O_MC16, O_M }, { M_DIV, O_MC16, O_M }, { M_DIV, O_MC16, O_M }, + { M_DIVS, O_MC16, O_M }, { M_DIVS, O_MC16, O_M }, { M_DIVS, O_MC16, O_M }, { M_DIVS, O_MC16, O_M }, + { M_DIVS, O_MC16, O_M }, { M_DIVS, O_MC16, O_M }, { M_DIVS, O_MC16, O_M }, { M_DIVS, O_MC16, O_M }, + + /* 60 - 7F */ + { M_INC, O_I3, O_M }, { M_INC, O_I3, O_M }, { M_INC, O_I3, O_M }, { M_INC, O_I3, O_M }, + { M_INC, O_I3, O_M }, { M_INC, O_I3, O_M }, { M_INC, O_I3, O_M }, { M_INC, O_I3, O_M }, + { M_DEC, O_I3, O_M }, { M_DEC, O_I3, O_M }, { M_DEC, O_I3, O_M }, { M_DEC, O_I3, O_M }, + { M_DEC, O_I3, O_M }, { M_DEC, O_I3, O_M }, { M_DEC, O_I3, O_M }, { M_DEC, O_I3, O_M }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_RLC, O_M, O_NONE }, { M_RRC, O_M, O_NONE }, { M_RL, O_M, O_NONE }, { M_RR, O_M, O_NONE }, + { M_SLA, O_M, O_NONE }, { M_SRA, O_M, O_NONE }, { M_SLL, O_M, O_NONE }, { M_SRL, O_M, O_NONE }, + + /* 80 - 9F */ + { M_ADD, O_C8, O_M }, { M_ADD, O_C8, O_M }, { M_ADD, O_C8, O_M }, { M_ADD, O_C8, O_M }, + { M_ADD, O_C8, O_M }, { M_ADD, O_C8, O_M }, { M_ADD, O_C8, O_M }, { M_ADD, O_C8, O_M }, + { M_ADD, O_M, O_C8 }, { M_ADD, O_M, O_C8 }, { M_ADD, O_M, O_C8 }, { M_ADD, O_M, O_C8 }, + { M_ADD, O_M, O_C8 }, { M_ADD, O_M, O_C8 }, { M_ADD, O_M, O_C8 }, { M_ADD, O_M, O_C8 }, + { M_ADC, O_C8, O_M }, { M_ADC, O_C8, O_M }, { M_ADC, O_C8, O_M }, { M_ADC, O_C8, O_M }, + { M_ADC, O_C8, O_M }, { M_ADC, O_C8, O_M }, { M_ADC, O_C8, O_M }, { M_ADC, O_C8, O_M }, + { M_ADC, O_M, O_C8 }, { M_ADC, O_M, O_C8 }, { M_ADC, O_M, O_C8 }, { M_ADC, O_M, O_C8 }, + { M_ADC, O_M, O_C8 }, { M_ADC, O_M, O_C8 }, { M_ADC, O_M, O_C8 }, { M_ADC, O_M, O_C8 }, + + /* A0 - BF */ + { M_SUB, O_C8, O_M }, { M_SUB, O_C8, O_M }, { M_SUB, O_C8, O_M }, { M_SUB, O_C8, O_M }, + { M_SUB, O_C8, O_M }, { M_SUB, O_C8, O_M }, { M_SUB, O_C8, O_M }, { M_SUB, O_C8, O_M }, + { M_SUB, O_M, O_C8 }, { M_SUB, O_M, O_C8 }, { M_SUB, O_M, O_C8 }, { M_SUB, O_M, O_C8 }, + { M_SUB, O_M, O_C8 }, { M_SUB, O_M, O_C8 }, { M_SUB, O_M, O_C8 }, { M_SUB, O_M, O_C8 }, + { M_SBC, O_C8, O_M }, { M_SBC, O_C8, O_M }, { M_SBC, O_C8, O_M }, { M_SBC, O_C8, O_M }, + { M_SBC, O_C8, O_M }, { M_SBC, O_C8, O_M }, { M_SBC, O_C8, O_M }, { M_SBC, O_C8, O_M }, + { M_SBC, O_M, O_C8 }, { M_SBC, O_M, O_C8 }, { M_SBC, O_M, O_C8 }, { M_SBC, O_M, O_C8 }, + { M_SBC, O_M, O_C8 }, { M_SBC, O_M, O_C8 }, { M_SBC, O_M, O_C8 }, { M_SBC, O_M, O_C8 }, + + /* C0 - DF */ + { M_AND, O_C8, O_M }, { M_AND, O_C8, O_M }, { M_AND, O_C8, O_M }, { M_AND, O_C8, O_M }, + { M_AND, O_C8, O_M }, { M_AND, O_C8, O_M }, { M_AND, O_C8, O_M }, { M_AND, O_C8, O_M }, + { M_AND, O_M, O_C8 }, { M_AND, O_M, O_C8 }, { M_AND, O_M, O_C8 }, { M_AND, O_M, O_C8 }, + { M_AND, O_M, O_C8 }, { M_AND, O_M, O_C8 }, { M_AND, O_M, O_C8 }, { M_AND, O_M, O_C8 }, + { M_XOR, O_C8, O_M }, { M_XOR, O_C8, O_M }, { M_XOR, O_C8, O_M }, { M_XOR, O_C8, O_M }, + { M_XOR, O_C8, O_M }, { M_XOR, O_C8, O_M }, { M_XOR, O_C8, O_M }, { M_XOR, O_C8, O_M }, + { M_XOR, O_M, O_C8 }, { M_XOR, O_M, O_C8 }, { M_XOR, O_M, O_C8 }, { M_XOR, O_M, O_C8 }, + { M_XOR, O_M, O_C8 }, { M_XOR, O_M, O_C8 }, { M_XOR, O_M, O_C8 }, { M_XOR, O_M, O_C8 }, + + /* E0 - FF */ + { M_OR, O_C8, O_M }, { M_OR, O_C8, O_M }, { M_OR, O_C8, O_M }, { M_OR, O_C8, O_M }, + { M_OR, O_C8, O_M }, { M_OR, O_C8, O_M }, { M_OR, O_C8, O_M }, { M_OR, O_C8, O_M }, + { M_OR, O_M, O_C8 }, { M_OR, O_M, O_C8 }, { M_OR, O_M, O_C8 }, { M_OR, O_M, O_C8 }, + { M_OR, O_M, O_C8 }, { M_OR, O_M, O_C8 }, { M_OR, O_M, O_C8 }, { M_OR, O_M, O_C8 }, + { M_CP, O_C8, O_M }, { M_CP, O_C8, O_M }, { M_CP, O_C8, O_M }, { M_CP, O_C8, O_M }, + { M_CP, O_C8, O_M }, { M_CP, O_C8, O_M }, { M_CP, O_C8, O_M }, { M_CP, O_C8, O_M }, + { M_CP, O_M, O_C8 }, { M_CP, O_M, O_C8 }, { M_CP, O_M, O_C8 }, { M_CP, O_M, O_C8 }, + { M_CP, O_M, O_C8 }, { M_CP, O_M, O_C8 }, { M_CP, O_M, O_C8 }, { M_CP, O_M, O_C8 }, +}; + + +static const tlcs900inst mnemonic_90[256] = +{ + /* 00 - 1F */ + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_PUSHW, O_M, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_LDIW, O_NONE, O_NONE }, { M_LDIRW, O_NONE, O_NONE }, { M_LDDW, O_NONE, O_NONE }, { M_LDDRW, O_NONE, O_NONE }, + { M_CPIW, O_NONE, O_NONE }, { M_CPIRW, O_NONE, O_NONE }, { M_CPDW, O_NONE, O_NONE }, { M_CPDRW, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_LDW, O_M16, O_M }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + + /* 20 - 3F */ + { M_LD, O_C16, O_M }, { M_LD, O_C16, O_M }, { M_LD, O_C16, O_M }, { M_LD, O_C16, O_M }, + { M_LD, O_C16, O_M }, { M_LD, O_C16, O_M }, { M_LD, O_C16, O_M }, { M_LD, O_C16, O_M }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_EX, O_M, O_C16 }, { M_EX, O_M, O_C16 }, { M_EX, O_M, O_C16 }, { M_EX, O_M, O_C16 }, + { M_EX, O_M, O_C16 }, { M_EX, O_M, O_C16 }, { M_EX, O_M, O_C16 }, { M_EX, O_M, O_C16 }, + { M_ADD, O_M, O_I16 }, { M_ADC, O_M, O_I16 }, { M_SUB, O_M, O_I16 }, { M_SBC, O_M, O_I16 }, + { M_AND, O_M, O_I16 }, { M_XOR, O_M, O_I16 }, { M_OR, O_M, O_I16 }, { M_CP, O_M, O_I16 }, + + /* 40 - 5F */ + { M_MUL, O_C32, O_M }, { M_MUL, O_C32, O_M }, { M_MUL, O_C32, O_M }, { M_MUL, O_C32, O_M }, + { M_MUL, O_C32, O_M }, { M_MUL, O_C32, O_M }, { M_MUL, O_C32, O_M }, { M_MUL, O_C32, O_M }, + { M_MULS, O_C32, O_M }, { M_MULS, O_C32, O_M }, { M_MULS, O_C32, O_M }, { M_MULS, O_C32, O_M }, + { M_MULS, O_C32, O_M }, { M_MULS, O_C32, O_M }, { M_MULS, O_C32, O_M }, { M_MULS, O_C32, O_M }, + { M_DIV, O_C32, O_M }, { M_DIV, O_C32, O_M }, { M_DIV, O_C32, O_M }, { M_DIV, O_C32, O_M }, + { M_DIV, O_C32, O_M }, { M_DIV, O_C32, O_M }, { M_DIV, O_C32, O_M }, { M_DIV, O_C32, O_M }, + { M_DIVS, O_C32, O_M }, { M_DIVS, O_C32, O_M }, { M_DIVS, O_C32, O_M }, { M_DIVS, O_C32, O_M }, + { M_DIVS, O_C32, O_M }, { M_DIVS, O_C32, O_M }, { M_DIVS, O_C32, O_M }, { M_DIVS, O_C32, O_M }, + + /* 60 - 7F */ + { M_INCW, O_I3, O_M }, { M_INCW, O_I3, O_M }, { M_INCW, O_I3, O_M }, { M_INCW, O_I3, O_M }, + { M_INCW, O_I3, O_M }, { M_INCW, O_I3, O_M }, { M_INCW, O_I3, O_M }, { M_INCW, O_I3, O_M }, + { M_DECW, O_I3, O_M }, { M_DECW, O_I3, O_M }, { M_DECW, O_I3, O_M }, { M_DECW, O_I3, O_M }, + { M_DECW, O_I3, O_M }, { M_DECW, O_I3, O_M }, { M_DECW, O_I3, O_M }, { M_DECW, O_I3, O_M }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_RLCW, O_M, O_NONE }, { M_RRCW, O_M, O_NONE }, { M_RLW, O_M, O_NONE }, { M_RRW, O_M, O_NONE }, + { M_SLAW, O_M, O_NONE }, { M_SRAW, O_M, O_NONE }, { M_SLLW, O_M, O_NONE }, { M_SRLW, O_M, O_NONE }, + + /* 80 - 9F */ + { M_ADD, O_C16, O_M }, { M_ADD, O_C16, O_M }, { M_ADD, O_C16, O_M }, { M_ADD, O_C16, O_M }, + { M_ADD, O_C16, O_M }, { M_ADD, O_C16, O_M }, { M_ADD, O_C16, O_M }, { M_ADD, O_C16, O_M }, + { M_ADD, O_M, O_C16 }, { M_ADD, O_M, O_C16 }, { M_ADD, O_M, O_C16 }, { M_ADD, O_M, O_C16 }, + { M_ADD, O_M, O_C16 }, { M_ADD, O_M, O_C16 }, { M_ADD, O_M, O_C16 }, { M_ADD, O_M, O_C16 }, + { M_ADC, O_C16, O_M }, { M_ADC, O_C16, O_M }, { M_ADC, O_C16, O_M }, { M_ADC, O_C16, O_M }, + { M_ADC, O_C16, O_M }, { M_ADC, O_C16, O_M }, { M_ADC, O_C16, O_M }, { M_ADC, O_C16, O_M }, + { M_ADC, O_M, O_C16 }, { M_ADC, O_M, O_C16 }, { M_ADC, O_M, O_C16 }, { M_ADC, O_M, O_C16 }, + { M_ADC, O_M, O_C16 }, { M_ADC, O_M, O_C16 }, { M_ADC, O_M, O_C16 }, { M_ADC, O_M, O_C16 }, + + /* A0 - BF */ + { M_SUB, O_C16, O_M }, { M_SUB, O_C16, O_M }, { M_SUB, O_C16, O_M }, { M_SUB, O_C16, O_M }, + { M_SUB, O_C16, O_M }, { M_SUB, O_C16, O_M }, { M_SUB, O_C16, O_M }, { M_SUB, O_C16, O_M }, + { M_SUB, O_M, O_C16 }, { M_SUB, O_M, O_C16 }, { M_SUB, O_M, O_C16 }, { M_SUB, O_M, O_C16 }, + { M_SUB, O_M, O_C16 }, { M_SUB, O_M, O_C16 }, { M_SUB, O_M, O_C16 }, { M_SUB, O_M, O_C16 }, + { M_SBC, O_C16, O_M }, { M_SBC, O_C16, O_M }, { M_SBC, O_C16, O_M }, { M_SBC, O_C16, O_M }, + { M_SBC, O_C16, O_M }, { M_SBC, O_C16, O_M }, { M_SBC, O_C16, O_M }, { M_SBC, O_C16, O_M }, + { M_SBC, O_M, O_C16 }, { M_SBC, O_M, O_C16 }, { M_SBC, O_M, O_C16 }, { M_SBC, O_M, O_C16 }, + { M_SBC, O_M, O_C16 }, { M_SBC, O_M, O_C16 }, { M_SBC, O_M, O_C16 }, { M_SBC, O_M, O_C16 }, + + /* C0 - DF */ + { M_AND, O_C16, O_M }, { M_AND, O_C16, O_M }, { M_AND, O_C16, O_M }, { M_AND, O_C16, O_M }, + { M_AND, O_C16, O_M }, { M_AND, O_C16, O_M }, { M_AND, O_C16, O_M }, { M_AND, O_C16, O_M }, + { M_AND, O_M, O_C16 }, { M_AND, O_M, O_C16 }, { M_AND, O_M, O_C16 }, { M_AND, O_M, O_C16 }, + { M_AND, O_M, O_C16 }, { M_AND, O_M, O_C16 }, { M_AND, O_M, O_C16 }, { M_AND, O_M, O_C16 }, + { M_XOR, O_C16, O_M }, { M_XOR, O_C16, O_M }, { M_XOR, O_C16, O_M }, { M_XOR, O_C16, O_M }, + { M_XOR, O_C16, O_M }, { M_XOR, O_C16, O_M }, { M_XOR, O_C16, O_M }, { M_XOR, O_C16, O_M }, + { M_XOR, O_M, O_C16 }, { M_XOR, O_M, O_C16 }, { M_XOR, O_M, O_C16 }, { M_XOR, O_M, O_C16 }, + { M_XOR, O_M, O_C16 }, { M_XOR, O_M, O_C16 }, { M_XOR, O_M, O_C16 }, { M_XOR, O_M, O_C16 }, + + /* E0 - FF */ + { M_OR, O_C16, O_M }, { M_OR, O_C16, O_M }, { M_OR, O_C16, O_M }, { M_OR, O_C16, O_M }, + { M_OR, O_C16, O_M }, { M_OR, O_C16, O_M }, { M_OR, O_C16, O_M }, { M_OR, O_C16, O_M }, + { M_OR, O_M, O_C16 }, { M_OR, O_M, O_C16 }, { M_OR, O_M, O_C16 }, { M_OR, O_M, O_C16 }, + { M_OR, O_M, O_C16 }, { M_OR, O_M, O_C16 }, { M_OR, O_M, O_C16 }, { M_OR, O_M, O_C16 }, + { M_CP, O_C16, O_M }, { M_CP, O_C16, O_M }, { M_CP, O_C16, O_M }, { M_CP, O_C16, O_M }, + { M_CP, O_C16, O_M }, { M_CP, O_C16, O_M }, { M_CP, O_C16, O_M }, { M_CP, O_C16, O_M }, + { M_CP, O_M, O_C16 }, { M_CP, O_M, O_C16 }, { M_CP, O_M, O_C16 }, { M_CP, O_M, O_C16 }, + { M_CP, O_M, O_C16 }, { M_CP, O_M, O_C16 }, { M_CP, O_M, O_C16 }, { M_CP, O_M, O_C16 }, +}; + + +static const tlcs900inst mnemonic_98[256] = +{ + /* 00 - 1F */ + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_PUSHW, O_M, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_LDW, O_M16, O_M }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + + /* 20 - 3F */ + { M_LD, O_C16, O_M }, { M_LD, O_C16, O_M }, { M_LD, O_C16, O_M }, { M_LD, O_C16, O_M }, + { M_LD, O_C16, O_M }, { M_LD, O_C16, O_M }, { M_LD, O_C16, O_M }, { M_LD, O_C16, O_M }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_EX, O_M, O_C16 }, { M_EX, O_M, O_C16 }, { M_EX, O_M, O_C16 }, { M_EX, O_M, O_C16 }, + { M_EX, O_M, O_C16 }, { M_EX, O_M, O_C16 }, { M_EX, O_M, O_C16 }, { M_EX, O_M, O_C16 }, + { M_ADD, O_M, O_I16 }, { M_ADC, O_M, O_I16 }, { M_SUB, O_M, O_I16 }, { M_SBC, O_M, O_I16 }, + { M_AND, O_M, O_I16 }, { M_XOR, O_M, O_I16 }, { M_OR, O_M, O_I16 }, { M_CP, O_M, O_I16 }, + + /* 40 - 5F */ + { M_MUL, O_C32, O_M }, { M_MUL, O_C32, O_M }, { M_MUL, O_C32, O_M }, { M_MUL, O_C32, O_M }, + { M_MUL, O_C32, O_M }, { M_MUL, O_C32, O_M }, { M_MUL, O_C32, O_M }, { M_MUL, O_C32, O_M }, + { M_MULS, O_C32, O_M }, { M_MULS, O_C32, O_M }, { M_MULS, O_C32, O_M }, { M_MULS, O_C32, O_M }, + { M_MULS, O_C32, O_M }, { M_MULS, O_C32, O_M }, { M_MULS, O_C32, O_M }, { M_MULS, O_C32, O_M }, + { M_DIV, O_C32, O_M }, { M_DIV, O_C32, O_M }, { M_DIV, O_C32, O_M }, { M_DIV, O_C32, O_M }, + { M_DIV, O_C32, O_M }, { M_DIV, O_C32, O_M }, { M_DIV, O_C32, O_M }, { M_DIV, O_C32, O_M }, + { M_DIVS, O_C32, O_M }, { M_DIVS, O_C32, O_M }, { M_DIVS, O_C32, O_M }, { M_DIVS, O_C32, O_M }, + { M_DIVS, O_C32, O_M }, { M_DIVS, O_C32, O_M }, { M_DIVS, O_C32, O_M }, { M_DIVS, O_C32, O_M }, + + /* 60 - 7F */ + { M_INCW, O_I3, O_M }, { M_INCW, O_I3, O_M }, { M_INCW, O_I3, O_M }, { M_INCW, O_I3, O_M }, + { M_INCW, O_I3, O_M }, { M_INCW, O_I3, O_M }, { M_INCW, O_I3, O_M }, { M_INCW, O_I3, O_M }, + { M_DECW, O_I3, O_M }, { M_DECW, O_I3, O_M }, { M_DECW, O_I3, O_M }, { M_DECW, O_I3, O_M }, + { M_DECW, O_I3, O_M }, { M_DECW, O_I3, O_M }, { M_DECW, O_I3, O_M }, { M_DECW, O_I3, O_M }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_RLCW, O_M, O_NONE }, { M_RRCW, O_M, O_NONE }, { M_RLW, O_M, O_NONE }, { M_RRW, O_M, O_NONE }, + { M_SLAW, O_M, O_NONE }, { M_SRAW, O_M, O_NONE }, { M_SLLW, O_M, O_NONE }, { M_SRLW, O_M, O_NONE }, + + /* 80 - 9F */ + { M_ADD, O_C16, O_M }, { M_ADD, O_C16, O_M }, { M_ADD, O_C16, O_M }, { M_ADD, O_C16, O_M }, + { M_ADD, O_C16, O_M }, { M_ADD, O_C16, O_M }, { M_ADD, O_C16, O_M }, { M_ADD, O_C16, O_M }, + { M_ADD, O_M, O_C16 }, { M_ADD, O_M, O_C16 }, { M_ADD, O_M, O_C16 }, { M_ADD, O_M, O_C16 }, + { M_ADD, O_M, O_C16 }, { M_ADD, O_M, O_C16 }, { M_ADD, O_M, O_C16 }, { M_ADD, O_M, O_C16 }, + { M_ADC, O_C16, O_M }, { M_ADC, O_C16, O_M }, { M_ADC, O_C16, O_M }, { M_ADC, O_C16, O_M }, + { M_ADC, O_C16, O_M }, { M_ADC, O_C16, O_M }, { M_ADC, O_C16, O_M }, { M_ADC, O_C16, O_M }, + { M_ADC, O_M, O_C16 }, { M_ADC, O_M, O_C16 }, { M_ADC, O_M, O_C16 }, { M_ADC, O_M, O_C16 }, + { M_ADC, O_M, O_C16 }, { M_ADC, O_M, O_C16 }, { M_ADC, O_M, O_C16 }, { M_ADC, O_M, O_C16 }, + + /* A0 - BF */ + { M_SUB, O_C16, O_M }, { M_SUB, O_C16, O_M }, { M_SUB, O_C16, O_M }, { M_SUB, O_C16, O_M }, + { M_SUB, O_C16, O_M }, { M_SUB, O_C16, O_M }, { M_SUB, O_C16, O_M }, { M_SUB, O_C16, O_M }, + { M_SUB, O_M, O_C16 }, { M_SUB, O_M, O_C16 }, { M_SUB, O_M, O_C16 }, { M_SUB, O_M, O_C16 }, + { M_SUB, O_M, O_C16 }, { M_SUB, O_M, O_C16 }, { M_SUB, O_M, O_C16 }, { M_SUB, O_M, O_C16 }, + { M_SBC, O_C16, O_M }, { M_SBC, O_C16, O_M }, { M_SBC, O_C16, O_M }, { M_SBC, O_C16, O_M }, + { M_SBC, O_C16, O_M }, { M_SBC, O_C16, O_M }, { M_SBC, O_C16, O_M }, { M_SBC, O_C16, O_M }, + { M_SBC, O_M, O_C16 }, { M_SBC, O_M, O_C16 }, { M_SBC, O_M, O_C16 }, { M_SBC, O_M, O_C16 }, + { M_SBC, O_M, O_C16 }, { M_SBC, O_M, O_C16 }, { M_SBC, O_M, O_C16 }, { M_SBC, O_M, O_C16 }, + + /* C0 - DF */ + { M_AND, O_C16, O_M }, { M_AND, O_C16, O_M }, { M_AND, O_C16, O_M }, { M_AND, O_C16, O_M }, + { M_AND, O_C16, O_M }, { M_AND, O_C16, O_M }, { M_AND, O_C16, O_M }, { M_AND, O_C16, O_M }, + { M_AND, O_M, O_C16 }, { M_AND, O_M, O_C16 }, { M_AND, O_M, O_C16 }, { M_AND, O_M, O_C16 }, + { M_AND, O_M, O_C16 }, { M_AND, O_M, O_C16 }, { M_AND, O_M, O_C16 }, { M_AND, O_M, O_C16 }, + { M_XOR, O_C16, O_M }, { M_XOR, O_C16, O_M }, { M_XOR, O_C16, O_M }, { M_XOR, O_C16, O_M }, + { M_XOR, O_C16, O_M }, { M_XOR, O_C16, O_M }, { M_XOR, O_C16, O_M }, { M_XOR, O_C16, O_M }, + { M_XOR, O_M, O_C16 }, { M_XOR, O_M, O_C16 }, { M_XOR, O_M, O_C16 }, { M_XOR, O_M, O_C16 }, + { M_XOR, O_M, O_C16 }, { M_XOR, O_M, O_C16 }, { M_XOR, O_M, O_C16 }, { M_XOR, O_M, O_C16 }, + + /* E0 - FF */ + { M_OR, O_C16, O_M }, { M_OR, O_C16, O_M }, { M_OR, O_C16, O_M }, { M_OR, O_C16, O_M }, + { M_OR, O_C16, O_M }, { M_OR, O_C16, O_M }, { M_OR, O_C16, O_M }, { M_OR, O_C16, O_M }, + { M_OR, O_M, O_C16 }, { M_OR, O_M, O_C16 }, { M_OR, O_M, O_C16 }, { M_OR, O_M, O_C16 }, + { M_OR, O_M, O_C16 }, { M_OR, O_M, O_C16 }, { M_OR, O_M, O_C16 }, { M_OR, O_M, O_C16 }, + { M_CP, O_C16, O_M }, { M_CP, O_C16, O_M }, { M_CP, O_C16, O_M }, { M_CP, O_C16, O_M }, + { M_CP, O_C16, O_M }, { M_CP, O_C16, O_M }, { M_CP, O_C16, O_M }, { M_CP, O_C16, O_M }, + { M_CP, O_M, O_C16 }, { M_CP, O_M, O_C16 }, { M_CP, O_M, O_C16 }, { M_CP, O_M, O_C16 }, + { M_CP, O_M, O_C16 }, { M_CP, O_M, O_C16 }, { M_CP, O_M, O_C16 }, { M_CP, O_M, O_C16 }, +}; + + +static const tlcs900inst mnemonic_a0[256] = +{ + /* 00 - 1F */ + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + + /* 20 - 3F */ + { M_LD, O_C32, O_M }, { M_LD, O_C32, O_M }, { M_LD, O_C32, O_M }, { M_LD, O_C32, O_M }, + { M_LD, O_C32, O_M }, { M_LD, O_C32, O_M }, { M_LD, O_C32, O_M }, { M_LD, O_C32, O_M }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + + /* 40 - 5F */ + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + + /* 60 - 7F */ + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + + /* 80 - 9F */ + { M_ADD, O_C32, O_M }, { M_ADD, O_C32, O_M }, { M_ADD, O_C32, O_M }, { M_ADD, O_C32, O_M }, + { M_ADD, O_C32, O_M }, { M_ADD, O_C32, O_M }, { M_ADD, O_C32, O_M }, { M_ADD, O_C32, O_M }, + { M_ADD, O_M, O_C32 }, { M_ADD, O_M, O_C32 }, { M_ADD, O_M, O_C32 }, { M_ADD, O_M, O_C32 }, + { M_ADD, O_M, O_C32 }, { M_ADD, O_M, O_C32 }, { M_ADD, O_M, O_C32 }, { M_ADD, O_M, O_C32 }, + { M_ADC, O_C32, O_M }, { M_ADC, O_C32, O_M }, { M_ADC, O_C32, O_M }, { M_ADC, O_C32, O_M }, + { M_ADC, O_C32, O_M }, { M_ADC, O_C32, O_M }, { M_ADC, O_C32, O_M }, { M_ADC, O_C32, O_M }, + { M_ADC, O_M, O_C32 }, { M_ADC, O_M, O_C32 }, { M_ADC, O_M, O_C32 }, { M_ADC, O_M, O_C32 }, + { M_ADC, O_M, O_C32 }, { M_ADC, O_M, O_C32 }, { M_ADC, O_M, O_C32 }, { M_ADC, O_M, O_C32 }, + + /* A0 - BF */ + { M_SUB, O_C32, O_M }, { M_SUB, O_C32, O_M }, { M_SUB, O_C32, O_M }, { M_SUB, O_C32, O_M }, + { M_SUB, O_C32, O_M }, { M_SUB, O_C32, O_M }, { M_SUB, O_C32, O_M }, { M_SUB, O_C32, O_M }, + { M_SUB, O_M, O_C32 }, { M_SUB, O_M, O_C32 }, { M_SUB, O_M, O_C32 }, { M_SUB, O_M, O_C32 }, + { M_SUB, O_M, O_C32 }, { M_SUB, O_M, O_C32 }, { M_SUB, O_M, O_C32 }, { M_SUB, O_M, O_C32 }, + { M_SBC, O_C32, O_M }, { M_SBC, O_C32, O_M }, { M_SBC, O_C32, O_M }, { M_SBC, O_C32, O_M }, + { M_SBC, O_C32, O_M }, { M_SBC, O_C32, O_M }, { M_SBC, O_C32, O_M }, { M_SBC, O_C32, O_M }, + { M_SBC, O_M, O_C32 }, { M_SBC, O_M, O_C32 }, { M_SBC, O_M, O_C32 }, { M_SBC, O_M, O_C32 }, + { M_SBC, O_M, O_C32 }, { M_SBC, O_M, O_C32 }, { M_SBC, O_M, O_C32 }, { M_SBC, O_M, O_C32 }, + + /* C0 - DF */ + { M_AND, O_C32, O_M }, { M_AND, O_C32, O_M }, { M_AND, O_C32, O_M }, { M_AND, O_C32, O_M }, + { M_AND, O_C32, O_M }, { M_AND, O_C32, O_M }, { M_AND, O_C32, O_M }, { M_AND, O_C32, O_M }, + { M_AND, O_M, O_C32 }, { M_AND, O_M, O_C32 }, { M_AND, O_M, O_C32 }, { M_AND, O_M, O_C32 }, + { M_AND, O_M, O_C32 }, { M_AND, O_M, O_C32 }, { M_AND, O_M, O_C32 }, { M_AND, O_M, O_C32 }, + { M_XOR, O_C32, O_M }, { M_XOR, O_C32, O_M }, { M_XOR, O_C32, O_M }, { M_XOR, O_C32, O_M }, + { M_XOR, O_C32, O_M }, { M_XOR, O_C32, O_M }, { M_XOR, O_C32, O_M }, { M_XOR, O_C32, O_M }, + { M_XOR, O_M, O_C32 }, { M_XOR, O_M, O_C32 }, { M_XOR, O_M, O_C32 }, { M_XOR, O_M, O_C32 }, + { M_XOR, O_M, O_C32 }, { M_XOR, O_M, O_C32 }, { M_XOR, O_M, O_C32 }, { M_XOR, O_M, O_C32 }, + + /* E0 - FF */ + { M_OR, O_C32, O_M }, { M_OR, O_C32, O_M }, { M_OR, O_C32, O_M }, { M_OR, O_C32, O_M }, + { M_OR, O_C32, O_M }, { M_OR, O_C32, O_M }, { M_OR, O_C32, O_M }, { M_OR, O_C32, O_M }, + { M_OR, O_M, O_C32 }, { M_OR, O_M, O_C32 }, { M_OR, O_M, O_C32 }, { M_OR, O_M, O_C32 }, + { M_OR, O_M, O_C32 }, { M_OR, O_M, O_C32 }, { M_OR, O_M, O_C32 }, { M_OR, O_M, O_C32 }, + { M_CP, O_C32, O_M }, { M_CP, O_C32, O_M }, { M_CP, O_C32, O_M }, { M_CP, O_C32, O_M }, + { M_CP, O_C32, O_M }, { M_CP, O_C32, O_M }, { M_CP, O_C32, O_M }, { M_CP, O_C32, O_M }, + { M_CP, O_M, O_C32 }, { M_CP, O_M, O_C32 }, { M_CP, O_M, O_C32 }, { M_CP, O_M, O_C32 }, + { M_CP, O_M, O_C32 }, { M_CP, O_M, O_C32 }, { M_CP, O_M, O_C32 }, { M_CP, O_M, O_C32 }, +}; + + +static const tlcs900inst mnemonic_b0[256] = +{ + /* 00 - 1F */ + { M_LD, O_M, O_I8 }, { M_DB, O_NONE, O_NONE }, { M_LD, O_M, O_I16 }, { M_DB, O_NONE, O_NONE }, + { M_POP, O_M, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_POPW, O_M, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_LD, O_M, O_M16 }, { M_DB, O_NONE, O_NONE }, { M_LDW, O_M, O_M16 }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + + /* 20 - 3F */ + { M_LDA, O_C16, O_M }, { M_LDA, O_C16, O_M }, { M_LDA, O_C16, O_M }, { M_LDA, O_C16, O_M }, + { M_LDA, O_C16, O_M }, { M_LDA, O_C16, O_M }, { M_LDA, O_C16, O_M }, { M_LDA, O_C16, O_M }, + { M_ANDCF, O_A, O_M }, { M_ORCF, O_A, O_M }, { M_XORCF, O_A, O_M }, { M_LDCF, O_A, O_M }, + { M_STCF, O_A, O_M }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_LDA, O_C32, O_M }, { M_LDA, O_C32, O_M }, { M_LDA, O_C32, O_M }, { M_LDA, O_C32, O_M }, + { M_LDA, O_C32, O_M }, { M_LDA, O_C32, O_M }, { M_LDA, O_C32, O_M }, { M_LDA, O_C32, O_M }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + + /* 40 - 5F */ + { M_LD, O_M, O_C8 }, { M_LD, O_M, O_C8 }, { M_LD, O_M, O_C8 }, { M_LD, O_M, O_C8 }, + { M_LD, O_M, O_C8 }, { M_LD, O_M, O_C8 }, { M_LD, O_M, O_C8 }, { M_LD, O_M, O_C8 }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_LD, O_M, O_C16 }, { M_LD, O_M, O_C16 }, { M_LD, O_M, O_C16 }, { M_LD, O_M, O_C16 }, + { M_LD, O_M, O_C16 }, { M_LD, O_M, O_C16 }, { M_LD, O_M, O_C16 }, { M_LD, O_M, O_C16 }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + + /* 60 - 7F */ + { M_LD, O_M, O_C32 }, { M_LD, O_M, O_C32 }, { M_LD, O_M, O_C32 }, { M_LD, O_M, O_C32 }, + { M_LD, O_M, O_C32 }, { M_LD, O_M, O_C32 }, { M_LD, O_M, O_C32 }, { M_LD, O_M, O_C32 }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + + /* 80 - 9F */ + { M_ANDCF, O_I3, O_M }, { M_ANDCF, O_I3, O_M }, { M_ANDCF, O_I3, O_M }, { M_ANDCF, O_I3, O_M }, + { M_ANDCF, O_I3, O_M }, { M_ANDCF, O_I3, O_M }, { M_ANDCF, O_I3, O_M }, { M_ANDCF, O_I3, O_M }, + { M_ORCF, O_I3, O_M }, { M_ORCF, O_I3, O_M }, { M_ORCF, O_I3, O_M }, { M_ORCF, O_I3, O_M }, + { M_ORCF, O_I3, O_M }, { M_ORCF, O_I3, O_M }, { M_ORCF, O_I3, O_M }, { M_ORCF, O_I3, O_M }, + { M_XORCF, O_I3, O_M }, { M_XORCF, O_I3, O_M }, { M_XORCF, O_I3, O_M }, { M_XORCF, O_I3, O_M }, + { M_XORCF, O_I3, O_M }, { M_XORCF, O_I3, O_M }, { M_XORCF, O_I3, O_M }, { M_XORCF, O_I3, O_M }, + { M_LDCF, O_I3, O_M }, { M_LDCF, O_I3, O_M }, { M_LDCF, O_I3, O_M }, { M_LDCF, O_I3, O_M }, + { M_LDCF, O_I3, O_M }, { M_LDCF, O_I3, O_M }, { M_LDCF, O_I3, O_M }, { M_LDCF, O_I3, O_M }, + + /* A0 - BF */ + { M_STCF, O_I3, O_M }, { M_STCF, O_I3, O_M }, { M_STCF, O_I3, O_M }, { M_STCF, O_I3, O_M }, + { M_STCF, O_I3, O_M }, { M_STCF, O_I3, O_M }, { M_STCF, O_I3, O_M }, { M_STCF, O_I3, O_M }, + { M_TSET, O_I3, O_M }, { M_TSET, O_I3, O_M }, { M_TSET, O_I3, O_M }, { M_TSET, O_I3, O_M }, + { M_TSET, O_I3, O_M }, { M_TSET, O_I3, O_M }, { M_TSET, O_I3, O_M }, { M_TSET, O_I3, O_M }, + { M_RES, O_I3, O_M }, { M_RES, O_I3, O_M }, { M_RES, O_I3, O_M }, { M_RES, O_I3, O_M }, + { M_RES, O_I3, O_M }, { M_RES, O_I3, O_M }, { M_RES, O_I3, O_M }, { M_RES, O_I3, O_M }, + { M_SET, O_I3, O_M }, { M_SET, O_I3, O_M }, { M_SET, O_I3, O_M }, { M_SET, O_I3, O_M }, + { M_SET, O_I3, O_M }, { M_SET, O_I3, O_M }, { M_SET, O_I3, O_M }, { M_SET, O_I3, O_M }, + + /* C0 - DF */ + { M_CHG, O_I3, O_M }, { M_CHG, O_I3, O_M }, { M_CHG, O_I3, O_M }, { M_CHG, O_I3, O_M }, + { M_CHG, O_I3, O_M }, { M_CHG, O_I3, O_M }, { M_CHG, O_I3, O_M }, { M_CHG, O_I3, O_M }, + { M_BIT, O_I3, O_M }, { M_BIT, O_I3, O_M }, { M_BIT, O_I3, O_M }, { M_BIT, O_I3, O_M }, + { M_BIT, O_I3, O_M }, { M_BIT, O_I3, O_M }, { M_BIT, O_I3, O_M }, { M_BIT, O_I3, O_M }, + { M_JP, O_CC, O_M }, { M_JP, O_CC, O_M }, { M_JP, O_CC, O_M }, { M_JP, O_CC, O_M }, + { M_JP, O_CC, O_M }, { M_JP, O_CC, O_M }, { M_JP, O_CC, O_M }, { M_JP, O_CC, O_M }, + { M_JP, O_CC, O_M }, { M_JP, O_CC, O_M }, { M_JP, O_CC, O_M }, { M_JP, O_CC, O_M }, + { M_JP, O_CC, O_M }, { M_JP, O_CC, O_M }, { M_JP, O_CC, O_M }, { M_JP, O_CC, O_M }, + + /* E0 - FF */ + { M_CALL, O_CC, O_M }, { M_CALL, O_CC, O_M }, { M_CALL, O_CC, O_M }, { M_CALL, O_CC, O_M }, + { M_CALL, O_CC, O_M }, { M_CALL, O_CC, O_M }, { M_CALL, O_CC, O_M }, { M_CALL, O_CC, O_M }, + { M_CALL, O_CC, O_M }, { M_CALL, O_CC, O_M }, { M_CALL, O_CC, O_M }, { M_CALL, O_CC, O_M }, + { M_CALL, O_CC, O_M }, { M_CALL, O_CC, O_M }, { M_CALL, O_CC, O_M }, { M_CALL, O_CC, O_M }, + { M_RET, O_CC, O_NONE }, { M_RET, O_CC, O_NONE }, { M_RET, O_CC, O_NONE }, { M_RET, O_CC, O_NONE }, + { M_RET, O_CC, O_NONE }, { M_RET, O_CC, O_NONE }, { M_RET, O_CC, O_NONE }, { M_RET, O_CC, O_NONE }, + { M_RET, O_CC, O_NONE }, { M_RET, O_CC, O_NONE }, { M_RET, O_CC, O_NONE }, { M_RET, O_CC, O_NONE }, + { M_RET, O_CC, O_NONE }, { M_RET, O_CC, O_NONE }, { M_RET, O_CC, O_NONE }, { M_RET, O_CC, O_NONE } +}; + + +static const tlcs900inst mnemonic_b8[256] = +{ + /* 00 - 1F */ + { M_LD, O_M, O_I8 }, { M_DB, O_NONE, O_NONE }, { M_LD, O_M, O_I16 }, { M_DB, O_NONE, O_NONE }, + { M_POP, O_M, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_POPW, O_M, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_LD, O_M, O_M16 }, { M_DB, O_NONE, O_NONE }, { M_LDW, O_M, O_M16 }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + + /* 20 - 3F */ + { M_LDA, O_C16, O_M }, { M_LDA, O_C16, O_M }, { M_LDA, O_C16, O_M }, { M_LDA, O_C16, O_M }, + { M_LDA, O_C16, O_M }, { M_LDA, O_C16, O_M }, { M_LDA, O_C16, O_M }, { M_LDA, O_C16, O_M }, + { M_ANDCF, O_A, O_M }, { M_ORCF, O_A, O_M }, { M_XORCF, O_A, O_M }, { M_LDCF, O_A, O_M }, + { M_STCF, O_A, O_M }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_LDA, O_C32, O_M }, { M_LDA, O_C32, O_M }, { M_LDA, O_C32, O_M }, { M_LDA, O_C32, O_M }, + { M_LDA, O_C32, O_M }, { M_LDA, O_C32, O_M }, { M_LDA, O_C32, O_M }, { M_LDA, O_C32, O_M }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + + /* 40 - 5F */ + { M_LD, O_M, O_C8 }, { M_LD, O_M, O_C8 }, { M_LD, O_M, O_C8 }, { M_LD, O_M, O_C8 }, + { M_LD, O_M, O_C8 }, { M_LD, O_M, O_C8 }, { M_LD, O_M, O_C8 }, { M_LD, O_M, O_C8 }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_LD, O_M, O_C16 }, { M_LD, O_M, O_C16 }, { M_LD, O_M, O_C16 }, { M_LD, O_M, O_C16 }, + { M_LD, O_M, O_C16 }, { M_LD, O_M, O_C16 }, { M_LD, O_M, O_C16 }, { M_LD, O_M, O_C16 }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + + /* 60 - 7F */ + { M_LD, O_M, O_C32 }, { M_LD, O_M, O_C32 }, { M_LD, O_M, O_C32 }, { M_LD, O_M, O_C32 }, + { M_LD, O_M, O_C32 }, { M_LD, O_M, O_C32 }, { M_LD, O_M, O_C32 }, { M_LD, O_M, O_C32 }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + + /* 80 - 9F */ + { M_ANDCF, O_I3, O_M }, { M_ANDCF, O_I3, O_M }, { M_ANDCF, O_I3, O_M }, { M_ANDCF, O_I3, O_M }, + { M_ANDCF, O_I3, O_M }, { M_ANDCF, O_I3, O_M }, { M_ANDCF, O_I3, O_M }, { M_ANDCF, O_I3, O_M }, + { M_ORCF, O_I3, O_M }, { M_ORCF, O_I3, O_M }, { M_ORCF, O_I3, O_M }, { M_ORCF, O_I3, O_M }, + { M_ORCF, O_I3, O_M }, { M_ORCF, O_I3, O_M }, { M_ORCF, O_I3, O_M }, { M_ORCF, O_I3, O_M }, + { M_XORCF, O_I3, O_M }, { M_XORCF, O_I3, O_M }, { M_XORCF, O_I3, O_M }, { M_XORCF, O_I3, O_M }, + { M_XORCF, O_I3, O_M }, { M_XORCF, O_I3, O_M }, { M_XORCF, O_I3, O_M }, { M_XORCF, O_I3, O_M }, + { M_LDCF, O_I3, O_M }, { M_LDCF, O_I3, O_M }, { M_LDCF, O_I3, O_M }, { M_LDCF, O_I3, O_M }, + { M_LDCF, O_I3, O_M }, { M_LDCF, O_I3, O_M }, { M_LDCF, O_I3, O_M }, { M_LDCF, O_I3, O_M }, + + /* A0 - BF */ + { M_STCF, O_I3, O_M }, { M_STCF, O_I3, O_M }, { M_STCF, O_I3, O_M }, { M_STCF, O_I3, O_M }, + { M_STCF, O_I3, O_M }, { M_STCF, O_I3, O_M }, { M_STCF, O_I3, O_M }, { M_STCF, O_I3, O_M }, + { M_TSET, O_I3, O_M }, { M_TSET, O_I3, O_M }, { M_TSET, O_I3, O_M }, { M_TSET, O_I3, O_M }, + { M_TSET, O_I3, O_M }, { M_TSET, O_I3, O_M }, { M_TSET, O_I3, O_M }, { M_TSET, O_I3, O_M }, + { M_RES, O_I3, O_M }, { M_RES, O_I3, O_M }, { M_RES, O_I3, O_M }, { M_RES, O_I3, O_M }, + { M_RES, O_I3, O_M }, { M_RES, O_I3, O_M }, { M_RES, O_I3, O_M }, { M_RES, O_I3, O_M }, + { M_SET, O_I3, O_M }, { M_SET, O_I3, O_M }, { M_SET, O_I3, O_M }, { M_SET, O_I3, O_M }, + { M_SET, O_I3, O_M }, { M_SET, O_I3, O_M }, { M_SET, O_I3, O_M }, { M_SET, O_I3, O_M }, + + /* C0 - DF */ + { M_CHG, O_I3, O_M }, { M_CHG, O_I3, O_M }, { M_CHG, O_I3, O_M }, { M_CHG, O_I3, O_M }, + { M_CHG, O_I3, O_M }, { M_CHG, O_I3, O_M }, { M_CHG, O_I3, O_M }, { M_CHG, O_I3, O_M }, + { M_BIT, O_I3, O_M }, { M_BIT, O_I3, O_M }, { M_BIT, O_I3, O_M }, { M_BIT, O_I3, O_M }, + { M_BIT, O_I3, O_M }, { M_BIT, O_I3, O_M }, { M_BIT, O_I3, O_M }, { M_BIT, O_I3, O_M }, + { M_JP, O_CC, O_M }, { M_JP, O_CC, O_M }, { M_JP, O_CC, O_M }, { M_JP, O_CC, O_M }, + { M_JP, O_CC, O_M }, { M_JP, O_CC, O_M }, { M_JP, O_CC, O_M }, { M_JP, O_CC, O_M }, + { M_JP, O_CC, O_M }, { M_JP, O_CC, O_M }, { M_JP, O_CC, O_M }, { M_JP, O_CC, O_M }, + { M_JP, O_CC, O_M }, { M_JP, O_CC, O_M }, { M_JP, O_CC, O_M }, { M_JP, O_CC, O_M }, + + /* E0 - FF */ + { M_CALL, O_CC, O_M }, { M_CALL, O_CC, O_M }, { M_CALL, O_CC, O_M }, { M_CALL, O_CC, O_M }, + { M_CALL, O_CC, O_M }, { M_CALL, O_CC, O_M }, { M_CALL, O_CC, O_M }, { M_CALL, O_CC, O_M }, + { M_CALL, O_CC, O_M }, { M_CALL, O_CC, O_M }, { M_CALL, O_CC, O_M }, { M_CALL, O_CC, O_M }, + { M_CALL, O_CC, O_M }, { M_CALL, O_CC, O_M }, { M_CALL, O_CC, O_M }, { M_CALL, O_CC, O_M }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE } +}; + + +static const tlcs900inst mnemonic_c0[256] = +{ + /* 00 - 1F */ + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_PUSH, O_M, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_RLD, O_A, O_M }, { M_RRD, O_A, O_M }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_LD, O_M16, O_M }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + + /* 20 - 3F */ + { M_LD, O_C8, O_M }, { M_LD, O_C8, O_M }, { M_LD, O_C8, O_M }, { M_LD, O_C8, O_M }, + { M_LD, O_C8, O_M }, { M_LD, O_C8, O_M }, { M_LD, O_C8, O_M }, { M_LD, O_C8, O_M }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_EX, O_M, O_C8 }, { M_EX, O_M, O_C8 }, { M_EX, O_M, O_C8 }, { M_EX, O_M, O_C8 }, + { M_EX, O_M, O_C8 }, { M_EX, O_M, O_C8 }, { M_EX, O_M, O_C8 }, { M_EX, O_M, O_C8 }, + { M_ADD, O_M, O_I8 }, { M_ADC, O_M, O_I8 }, { M_SUB, O_M, O_I8 }, { M_SBC, O_M, O_I8 }, + { M_AND, O_M, O_I8 }, { M_XOR, O_M, O_I8 }, { M_OR, O_M, O_I8 }, { M_CP, O_M, O_I8 }, + + /* 40 - 5F */ + { M_MUL, O_MC16, O_M }, { M_MUL, O_MC16, O_M }, { M_MUL, O_MC16, O_M }, { M_MUL, O_MC16, O_M }, + { M_MUL, O_MC16, O_M }, { M_MUL, O_MC16, O_M }, { M_MUL, O_MC16, O_M }, { M_MUL, O_MC16, O_M }, + { M_MULS, O_MC16, O_M }, { M_MULS, O_MC16, O_M }, { M_MULS, O_MC16, O_M }, { M_MULS, O_MC16, O_M }, + { M_MULS, O_MC16, O_M }, { M_MULS, O_MC16, O_M }, { M_MULS, O_MC16, O_M }, { M_MULS, O_MC16, O_M }, + { M_DIV, O_MC16, O_M }, { M_DIV, O_MC16, O_M }, { M_DIV, O_MC16, O_M }, { M_DIV, O_MC16, O_M }, + { M_DIV, O_MC16, O_M }, { M_DIV, O_MC16, O_M }, { M_DIV, O_MC16, O_M }, { M_DIV, O_MC16, O_M }, + { M_DIVS, O_MC16, O_M }, { M_DIVS, O_MC16, O_M }, { M_DIVS, O_MC16, O_M }, { M_DIVS, O_MC16, O_M }, + { M_DIVS, O_MC16, O_M }, { M_DIVS, O_MC16, O_M }, { M_DIVS, O_MC16, O_M }, { M_DIVS, O_MC16, O_M }, + + /* 60 - 7F */ + { M_INC, O_I3, O_M }, { M_INC, O_I3, O_M }, { M_INC, O_I3, O_M }, { M_INC, O_I3, O_M }, + { M_INC, O_I3, O_M }, { M_INC, O_I3, O_M }, { M_INC, O_I3, O_M }, { M_INC, O_I3, O_M }, + { M_DEC, O_I3, O_M }, { M_DEC, O_I3, O_M }, { M_DEC, O_I3, O_M }, { M_DEC, O_I3, O_M }, + { M_DEC, O_I3, O_M }, { M_DEC, O_I3, O_M }, { M_DEC, O_I3, O_M }, { M_DEC, O_I3, O_M }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_RLC, O_M, O_NONE }, { M_RRC, O_M, O_NONE }, { M_RL, O_M, O_NONE }, { M_RR, O_M, O_NONE }, + { M_SLA, O_M, O_NONE }, { M_SRA, O_M, O_NONE }, { M_SLL, O_M, O_NONE }, { M_SRL, O_M, O_NONE }, + + /* 80 - 9F */ + { M_ADD, O_C8, O_M }, { M_ADD, O_C8, O_M }, { M_ADD, O_C8, O_M }, { M_ADD, O_C8, O_M }, + { M_ADD, O_C8, O_M }, { M_ADD, O_C8, O_M }, { M_ADD, O_C8, O_M }, { M_ADD, O_C8, O_M }, + { M_ADD, O_M, O_C8 }, { M_ADD, O_M, O_C8 }, { M_ADD, O_M, O_C8 }, { M_ADD, O_M, O_C8 }, + { M_ADD, O_M, O_C8 }, { M_ADD, O_M, O_C8 }, { M_ADD, O_M, O_C8 }, { M_ADD, O_M, O_C8 }, + { M_ADC, O_C8, O_M }, { M_ADC, O_C8, O_M }, { M_ADC, O_C8, O_M }, { M_ADC, O_C8, O_M }, + { M_ADC, O_C8, O_M }, { M_ADC, O_C8, O_M }, { M_ADC, O_C8, O_M }, { M_ADC, O_C8, O_M }, + { M_ADC, O_M, O_C8 }, { M_ADC, O_M, O_C8 }, { M_ADC, O_M, O_C8 }, { M_ADC, O_M, O_C8 }, + { M_ADC, O_M, O_C8 }, { M_ADC, O_M, O_C8 }, { M_ADC, O_M, O_C8 }, { M_ADC, O_M, O_C8 }, + + /* A0 - BF */ + { M_SUB, O_C8, O_M }, { M_SUB, O_C8, O_M }, { M_SUB, O_C8, O_M }, { M_SUB, O_C8, O_M }, + { M_SUB, O_C8, O_M }, { M_SUB, O_C8, O_M }, { M_SUB, O_C8, O_M }, { M_SUB, O_C8, O_M }, + { M_SUB, O_M, O_C8 }, { M_SUB, O_M, O_C8 }, { M_SUB, O_M, O_C8 }, { M_SUB, O_M, O_C8 }, + { M_SUB, O_M, O_C8 }, { M_SUB, O_M, O_C8 }, { M_SUB, O_M, O_C8 }, { M_SUB, O_M, O_C8 }, + { M_SBC, O_C8, O_M }, { M_SBC, O_C8, O_M }, { M_SBC, O_C8, O_M }, { M_SBC, O_C8, O_M }, + { M_SBC, O_C8, O_M }, { M_SBC, O_C8, O_M }, { M_SBC, O_C8, O_M }, { M_SBC, O_C8, O_M }, + { M_SBC, O_M, O_C8 }, { M_SBC, O_M, O_C8 }, { M_SBC, O_M, O_C8 }, { M_SBC, O_M, O_C8 }, + { M_SBC, O_M, O_C8 }, { M_SBC, O_M, O_C8 }, { M_SBC, O_M, O_C8 }, { M_SBC, O_M, O_C8 }, + + /* C0 - DF */ + { M_AND, O_C8, O_M }, { M_AND, O_C8, O_M }, { M_AND, O_C8, O_M }, { M_AND, O_C8, O_M }, + { M_AND, O_C8, O_M }, { M_AND, O_C8, O_M }, { M_AND, O_C8, O_M }, { M_AND, O_C8, O_M }, + { M_AND, O_M, O_C8 }, { M_AND, O_M, O_C8 }, { M_AND, O_M, O_C8 }, { M_AND, O_M, O_C8 }, + { M_AND, O_M, O_C8 }, { M_AND, O_M, O_C8 }, { M_AND, O_M, O_C8 }, { M_AND, O_M, O_C8 }, + { M_XOR, O_C8, O_M }, { M_XOR, O_C8, O_M }, { M_XOR, O_C8, O_M }, { M_XOR, O_C8, O_M }, + { M_XOR, O_C8, O_M }, { M_XOR, O_C8, O_M }, { M_XOR, O_C8, O_M }, { M_XOR, O_C8, O_M }, + { M_XOR, O_M, O_C8 }, { M_XOR, O_M, O_C8 }, { M_XOR, O_M, O_C8 }, { M_XOR, O_M, O_C8 }, + { M_XOR, O_M, O_C8 }, { M_XOR, O_M, O_C8 }, { M_XOR, O_M, O_C8 }, { M_XOR, O_M, O_C8 }, + + /* E0 - FF */ + { M_OR, O_C8, O_M }, { M_OR, O_C8, O_M }, { M_OR, O_C8, O_M }, { M_OR, O_C8, O_M }, + { M_OR, O_C8, O_M }, { M_OR, O_C8, O_M }, { M_OR, O_C8, O_M }, { M_OR, O_C8, O_M }, + { M_OR, O_M, O_C8 }, { M_OR, O_M, O_C8 }, { M_OR, O_M, O_C8 }, { M_OR, O_M, O_C8 }, + { M_OR, O_M, O_C8 }, { M_OR, O_M, O_C8 }, { M_OR, O_M, O_C8 }, { M_OR, O_M, O_C8 }, + { M_CP, O_C8, O_M }, { M_CP, O_C8, O_M }, { M_CP, O_C8, O_M }, { M_CP, O_C8, O_M }, + { M_CP, O_C8, O_M }, { M_CP, O_C8, O_M }, { M_CP, O_C8, O_M }, { M_CP, O_C8, O_M }, + { M_CP, O_M, O_C8 }, { M_CP, O_M, O_C8 }, { M_CP, O_M, O_C8 }, { M_CP, O_M, O_C8 }, + { M_CP, O_M, O_C8 }, { M_CP, O_M, O_C8 }, { M_CP, O_M, O_C8 }, { M_CP, O_M, O_C8 }, +}; + + +/* TODO: M_MUL_O_I8, M_MULS_O_I8, M_DIV_O_I8, M_DIVS_O_i8 need to be fixed */ +static const tlcs900inst mnemonic_c8[256] = +{ + /* 00 - 1F */ + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_LD, O_R, O_I8 }, + { M_PUSH, O_R, O_NONE }, { M_POP, O_R, O_NONE }, { M_CPL, O_R, O_NONE }, { M_NEG, O_R, O_NONE }, + { M_MUL, O_R, O_I8 }, { M_MULS, O_R, O_I8 }, { M_DIV, O_R, O_I8 }, { M_DIVS, O_R, O_I8 }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DAA, O_R, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DJNZ, O_R, O_D8 }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + + /* 20 - 3F */ + { M_ANDCF, O_I8, O_R }, { M_ORCF, O_I8, O_R }, { M_XORCF, O_I8, O_R }, { M_LDCF, O_I8, O_R }, + { M_STCF, O_I8, O_R }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_ANDCF, O_A, O_R }, { M_ORCF, O_A, O_R }, { M_XORCF, O_A, O_R }, { M_LDCF, O_A, O_R }, + { M_STCF, O_A, O_R }, { M_DB, O_NONE, O_NONE }, { M_LDC, O_CR8, O_R }, { M_LDC, O_R, O_CR8 }, + { M_RES, O_I8, O_R }, { M_SET, O_I8, O_R }, { M_CHG, O_I8, O_R }, { M_BIT, O_I8, O_R }, + { M_TSET, O_I8, O_R }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + + /* 40 - 5F */ + { M_MUL, O_MC16, O_R }, { M_MUL, O_MC16, O_R }, { M_MUL, O_MC16, O_R }, { M_MUL, O_MC16, O_R }, + { M_MUL, O_MC16, O_R }, { M_MUL, O_MC16, O_R }, { M_MUL, O_MC16, O_R }, { M_MUL, O_MC16, O_R }, + { M_MULS, O_MC16, O_R }, { M_MULS, O_MC16, O_R }, { M_MULS, O_MC16, O_R }, { M_MULS, O_MC16, O_R }, + { M_MULS, O_MC16, O_R }, { M_MULS, O_MC16, O_R }, { M_MULS, O_MC16, O_R }, { M_MULS, O_MC16, O_R }, + { M_DIV, O_MC16, O_R }, { M_DIV, O_MC16, O_R }, { M_DIV, O_MC16, O_R }, { M_DIV, O_MC16, O_R }, + { M_DIV, O_MC16, O_R }, { M_DIV, O_MC16, O_R }, { M_DIV, O_MC16, O_R }, { M_DIV, O_MC16, O_R }, + { M_DIVS, O_MC16, O_R }, { M_DIVS, O_MC16, O_R }, { M_DIVS, O_MC16, O_R }, { M_DIVS, O_MC16, O_R }, + { M_DIVS, O_MC16, O_R }, { M_DIVS, O_MC16, O_R }, { M_DIVS, O_MC16, O_R }, { M_DIVS, O_MC16, O_R }, + + /* 60 - 7F */ + { M_INC, O_I3, O_R }, { M_INC, O_I3, O_R }, { M_INC, O_I3, O_R }, { M_INC, O_I3, O_R }, + { M_INC, O_I3, O_R }, { M_INC, O_I3, O_R }, { M_INC, O_I3, O_R }, { M_INC, O_I3, O_R }, + { M_DEC, O_I3, O_R }, { M_DEC, O_I3, O_R }, { M_DEC, O_I3, O_R }, { M_DEC, O_I3, O_R }, + { M_DEC, O_I3, O_R }, { M_DEC, O_I3, O_R }, { M_DEC, O_I3, O_R }, { M_DEC, O_I3, O_R }, + { M_SCC, O_CC, O_R }, { M_SCC, O_CC, O_R }, { M_SCC, O_CC, O_R }, { M_SCC, O_CC, O_R }, + { M_SCC, O_CC, O_R }, { M_SCC, O_CC, O_R }, { M_SCC, O_CC, O_R }, { M_SCC, O_CC, O_R }, + { M_SCC, O_CC, O_R }, { M_SCC, O_CC, O_R }, { M_SCC, O_CC, O_R }, { M_SCC, O_CC, O_R }, + { M_SCC, O_CC, O_R }, { M_SCC, O_CC, O_R }, { M_SCC, O_CC, O_R }, { M_SCC, O_CC, O_R }, + + /* 80 - 9F */ + { M_ADD, O_C8, O_R }, { M_ADD, O_C8, O_R }, { M_ADD, O_C8, O_R }, { M_ADD, O_C8, O_R }, + { M_ADD, O_C8, O_R }, { M_ADD, O_C8, O_R }, { M_ADD, O_C8, O_R }, { M_ADD, O_C8, O_R }, + { M_LD, O_C8, O_R }, { M_LD, O_C8, O_R }, { M_LD, O_C8, O_R }, { M_LD, O_C8, O_R }, + { M_LD, O_C8, O_R }, { M_LD, O_C8, O_R }, { M_LD, O_C8, O_R }, { M_LD, O_C8, O_R }, + { M_ADC, O_C8, O_R }, { M_ADC, O_C8, O_R }, { M_ADC, O_C8, O_R }, { M_ADC, O_C8, O_R }, + { M_ADC, O_C8, O_R }, { M_ADC, O_C8, O_R }, { M_ADC, O_C8, O_R }, { M_ADC, O_C8, O_R }, + { M_LD, O_R, O_C8 }, { M_LD, O_R, O_C8 }, { M_LD, O_R, O_C8 }, { M_LD, O_R, O_C8 }, + { M_LD, O_R, O_C8 }, { M_LD, O_R, O_C8 }, { M_LD, O_R, O_C8 }, { M_LD, O_R, O_C8 }, + + /* A0 - BF */ + { M_SUB, O_C8, O_R }, { M_SUB, O_C8, O_R }, { M_SUB, O_C8, O_R }, { M_SUB, O_C8, O_R }, + { M_SUB, O_C8, O_R }, { M_SUB, O_C8, O_R }, { M_SUB, O_C8, O_R }, { M_SUB, O_C8, O_R }, + { M_LD, O_R, O_I3 }, { M_LD, O_R, O_I3 }, { M_LD, O_R, O_I3 }, { M_LD, O_R, O_I3 }, + { M_LD, O_R, O_I3 }, { M_LD, O_R, O_I3 }, { M_LD, O_R, O_I3 }, { M_LD, O_R, O_I3 }, + { M_SBC, O_C8, O_R }, { M_SBC, O_C8, O_R }, { M_SBC, O_C8, O_R }, { M_SBC, O_C8, O_R }, + { M_SBC, O_C8, O_R }, { M_SBC, O_C8, O_R }, { M_SBC, O_C8, O_R }, { M_SBC, O_C8, O_R }, + { M_EX, O_C8, O_R }, { M_EX, O_C8, O_R }, { M_EX, O_C8, O_R }, { M_EX, O_C8, O_R }, + { M_EX, O_C8, O_R }, { M_EX, O_C8, O_R }, { M_EX, O_C8, O_R }, { M_EX, O_C8, O_R }, + + /* C0 - DF */ + { M_AND, O_C8, O_R }, { M_AND, O_C8, O_R }, { M_AND, O_C8, O_R }, { M_AND, O_C8, O_R }, + { M_AND, O_C8, O_R }, { M_AND, O_C8, O_R }, { M_AND, O_C8, O_R }, { M_AND, O_C8, O_R }, + { M_ADD, O_R, O_I8 }, { M_ADC, O_R, O_I8 }, { M_SUB, O_R, O_I8 }, { M_SBC, O_R, O_I8 }, + { M_AND, O_R, O_I8 }, { M_XOR, O_R, O_I8 }, { M_OR, O_R, O_I8 }, { M_CP, O_R, O_I8 }, + { M_XOR, O_C8, O_R }, { M_XOR, O_C8, O_R }, { M_XOR, O_C8, O_R }, { M_XOR, O_C8, O_R }, + { M_XOR, O_C8, O_R }, { M_XOR, O_C8, O_R }, { M_XOR, O_C8, O_R }, { M_XOR, O_C8, O_R }, + { M_CP, O_R, O_I3 }, { M_CP, O_R, O_I3 }, { M_CP, O_R, O_I3 }, { M_CP, O_R, O_I3 }, + { M_CP, O_R, O_I3 }, { M_CP, O_R, O_I3 }, { M_CP, O_R, O_I3 }, { M_CP, O_R, O_I3 }, + + /* E0 - FF */ + { M_OR, O_C8, O_R }, { M_OR, O_C8, O_R }, { M_OR, O_C8, O_R }, { M_OR, O_C8, O_R }, + { M_OR, O_C8, O_R }, { M_OR, O_C8, O_R }, { M_OR, O_C8, O_R }, { M_OR, O_C8, O_R }, + { M_RLC, O_I8, O_R }, { M_RRC, O_I8, O_R }, { M_RL, O_I8, O_R }, { M_RR, O_I8, O_R }, + { M_SLA, O_I8, O_R }, { M_SRA, O_I8, O_R }, { M_SLL, O_I8, O_R }, { M_SRL, O_I8, O_R }, + { M_CP, O_C8, O_R }, { M_CP, O_C8, O_R }, { M_CP, O_C8, O_R }, { M_CP, O_C8, O_R }, + { M_CP, O_C8, O_R }, { M_CP, O_C8, O_R }, { M_CP, O_C8, O_R }, { M_CP, O_C8, O_R }, + { M_RLC, O_A, O_R }, { M_RRC, O_A, O_R }, { M_RL, O_A, O_R }, { M_RR, O_A, O_R }, + { M_SLA, O_A, O_R }, { M_SRA, O_A, O_R }, { M_SLL, O_A, O_R }, { M_SRL, O_A, O_R } +}; + + +static const tlcs900inst mnemonic_d0[256] = +{ + /* 00 - 1F */ + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_PUSHW, O_M, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_LDW, O_M16, O_M }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + + /* 20 - 3F */ + { M_LD, O_C16, O_M }, { M_LD, O_C16, O_M }, { M_LD, O_C16, O_M }, { M_LD, O_C16, O_M }, + { M_LD, O_C16, O_M }, { M_LD, O_C16, O_M }, { M_LD, O_C16, O_M }, { M_LD, O_C16, O_M }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_EX, O_M, O_C16 }, { M_EX, O_M, O_C16 }, { M_EX, O_M, O_C16 }, { M_EX, O_M, O_C16 }, + { M_EX, O_M, O_C16 }, { M_EX, O_M, O_C16 }, { M_EX, O_M, O_C16 }, { M_EX, O_M, O_C16 }, + { M_ADD, O_M, O_I16 }, { M_ADC, O_M, O_I16 }, { M_SUB, O_M, O_I16 }, { M_SBC, O_M, O_I16 }, + { M_AND, O_M, O_I16 }, { M_XOR, O_M, O_I16 }, { M_OR, O_M, O_I16 }, { M_CP, O_M, O_I16 }, + + /* 40 - 5F */ + { M_MUL, O_C32, O_M }, { M_MUL, O_C32, O_M }, { M_MUL, O_C32, O_M }, { M_MUL, O_C32, O_M }, + { M_MUL, O_C32, O_M }, { M_MUL, O_C32, O_M }, { M_MUL, O_C32, O_M }, { M_MUL, O_C32, O_M }, + { M_MULS, O_C32, O_M }, { M_MULS, O_C32, O_M }, { M_MULS, O_C32, O_M }, { M_MULS, O_C32, O_M }, + { M_MULS, O_C32, O_M }, { M_MULS, O_C32, O_M }, { M_MULS, O_C32, O_M }, { M_MULS, O_C32, O_M }, + { M_DIV, O_C32, O_M }, { M_DIV, O_C32, O_M }, { M_DIV, O_C32, O_M }, { M_DIV, O_C32, O_M }, + { M_DIV, O_C32, O_M }, { M_DIV, O_C32, O_M }, { M_DIV, O_C32, O_M }, { M_DIV, O_C32, O_M }, + { M_DIVS, O_C32, O_M }, { M_DIVS, O_C32, O_M }, { M_DIVS, O_C32, O_M }, { M_DIVS, O_C32, O_M }, + { M_DIVS, O_C32, O_M }, { M_DIVS, O_C32, O_M }, { M_DIVS, O_C32, O_M }, { M_DIVS, O_C32, O_M }, + + /* 60 - 7F */ + { M_INCW, O_I3, O_M }, { M_INCW, O_I3, O_M }, { M_INCW, O_I3, O_M }, { M_INCW, O_I3, O_M }, + { M_INCW, O_I3, O_M }, { M_INCW, O_I3, O_M }, { M_INCW, O_I3, O_M }, { M_INCW, O_I3, O_M }, + { M_DECW, O_I3, O_M }, { M_DECW, O_I3, O_M }, { M_DECW, O_I3, O_M }, { M_DECW, O_I3, O_M }, + { M_DECW, O_I3, O_M }, { M_DECW, O_I3, O_M }, { M_DECW, O_I3, O_M }, { M_DECW, O_I3, O_M }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_RLCW, O_M, O_NONE }, { M_RRCW, O_M, O_NONE }, { M_RLW, O_M, O_NONE }, { M_RRW, O_M, O_NONE }, + { M_SLAW, O_M, O_NONE }, { M_SRAW, O_M, O_NONE }, { M_SLLW, O_M, O_NONE }, { M_SRLW, O_M, O_NONE }, + + /* 80 - 9F */ + { M_ADD, O_C16, O_M }, { M_ADD, O_C16, O_M }, { M_ADD, O_C16, O_M }, { M_ADD, O_C16, O_M }, + { M_ADD, O_C16, O_M }, { M_ADD, O_C16, O_M }, { M_ADD, O_C16, O_M }, { M_ADD, O_C16, O_M }, + { M_ADD, O_M, O_C16 }, { M_ADD, O_M, O_C16 }, { M_ADD, O_M, O_C16 }, { M_ADD, O_M, O_C16 }, + { M_ADD, O_M, O_C16 }, { M_ADD, O_M, O_C16 }, { M_ADD, O_M, O_C16 }, { M_ADD, O_M, O_C16 }, + { M_ADC, O_C16, O_M }, { M_ADC, O_C16, O_M }, { M_ADC, O_C16, O_M }, { M_ADC, O_C16, O_M }, + { M_ADC, O_C16, O_M }, { M_ADC, O_C16, O_M }, { M_ADC, O_C16, O_M }, { M_ADC, O_C16, O_M }, + { M_ADC, O_M, O_C16 }, { M_ADC, O_M, O_C16 }, { M_ADC, O_M, O_C16 }, { M_ADC, O_M, O_C16 }, + { M_ADC, O_M, O_C16 }, { M_ADC, O_M, O_C16 }, { M_ADC, O_M, O_C16 }, { M_ADC, O_M, O_C16 }, + + /* A0 - BF */ + { M_SUB, O_C16, O_M }, { M_SUB, O_C16, O_M }, { M_SUB, O_C16, O_M }, { M_SUB, O_C16, O_M }, + { M_SUB, O_C16, O_M }, { M_SUB, O_C16, O_M }, { M_SUB, O_C16, O_M }, { M_SUB, O_C16, O_M }, + { M_SUB, O_M, O_C16 }, { M_SUB, O_M, O_C16 }, { M_SUB, O_M, O_C16 }, { M_SUB, O_M, O_C16 }, + { M_SUB, O_M, O_C16 }, { M_SUB, O_M, O_C16 }, { M_SUB, O_M, O_C16 }, { M_SUB, O_M, O_C16 }, + { M_SBC, O_C16, O_M }, { M_SBC, O_C16, O_M }, { M_SBC, O_C16, O_M }, { M_SBC, O_C16, O_M }, + { M_SBC, O_C16, O_M }, { M_SBC, O_C16, O_M }, { M_SBC, O_C16, O_M }, { M_SBC, O_C16, O_M }, + { M_SBC, O_M, O_C16 }, { M_SBC, O_M, O_C16 }, { M_SBC, O_M, O_C16 }, { M_SBC, O_M, O_C16 }, + { M_SBC, O_M, O_C16 }, { M_SBC, O_M, O_C16 }, { M_SBC, O_M, O_C16 }, { M_SBC, O_M, O_C16 }, + + /* C0 - DF */ + { M_AND, O_C16, O_M }, { M_AND, O_C16, O_M }, { M_AND, O_C16, O_M }, { M_AND, O_C16, O_M }, + { M_AND, O_C16, O_M }, { M_AND, O_C16, O_M }, { M_AND, O_C16, O_M }, { M_AND, O_C16, O_M }, + { M_AND, O_M, O_C16 }, { M_AND, O_M, O_C16 }, { M_AND, O_M, O_C16 }, { M_AND, O_M, O_C16 }, + { M_AND, O_M, O_C16 }, { M_AND, O_M, O_C16 }, { M_AND, O_M, O_C16 }, { M_AND, O_M, O_C16 }, + { M_XOR, O_C16, O_M }, { M_XOR, O_C16, O_M }, { M_XOR, O_C16, O_M }, { M_XOR, O_C16, O_M }, + { M_XOR, O_C16, O_M }, { M_XOR, O_C16, O_M }, { M_XOR, O_C16, O_M }, { M_XOR, O_C16, O_M }, + { M_XOR, O_M, O_C16 }, { M_XOR, O_M, O_C16 }, { M_XOR, O_M, O_C16 }, { M_XOR, O_M, O_C16 }, + { M_XOR, O_M, O_C16 }, { M_XOR, O_M, O_C16 }, { M_XOR, O_M, O_C16 }, { M_XOR, O_M, O_C16 }, + + /* E0 - FF */ + { M_OR, O_C16, O_M }, { M_OR, O_C16, O_M }, { M_OR, O_C16, O_M }, { M_OR, O_C16, O_M }, + { M_OR, O_C16, O_M }, { M_OR, O_C16, O_M }, { M_OR, O_C16, O_M }, { M_OR, O_C16, O_M }, + { M_OR, O_M, O_C16 }, { M_OR, O_M, O_C16 }, { M_OR, O_M, O_C16 }, { M_OR, O_M, O_C16 }, + { M_OR, O_M, O_C16 }, { M_OR, O_M, O_C16 }, { M_OR, O_M, O_C16 }, { M_OR, O_M, O_C16 }, + { M_CP, O_C16, O_M }, { M_CP, O_C16, O_M }, { M_CP, O_C16, O_M }, { M_CP, O_C16, O_M }, + { M_CP, O_C16, O_M }, { M_CP, O_C16, O_M }, { M_CP, O_C16, O_M }, { M_CP, O_C16, O_M }, + { M_CP, O_M, O_C16 }, { M_CP, O_M, O_C16 }, { M_CP, O_M, O_C16 }, { M_CP, O_M, O_C16 }, + { M_CP, O_M, O_C16 }, { M_CP, O_M, O_C16 }, { M_CP, O_M, O_C16 }, { M_CP, O_M, O_C16 }, +}; + + +static const tlcs900inst mnemonic_d8[256] = +{ + /* 00 - 1F */ + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_LD, O_R, O_I16 }, + { M_PUSH, O_R, O_NONE }, { M_POP, O_R, O_NONE }, { M_CPL, O_R, O_NONE }, { M_NEG, O_R, O_NONE }, + { M_MUL, O_R, O_I16 }, { M_MULS, O_R, O_I16 }, { M_DIV, O_R, O_I16 }, { M_DIVS, O_R, O_I16 }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_BS1F, O_A, O_R }, { M_BS1B, O_A, O_R }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_EXTZ, O_R, O_NONE }, { M_EXTS, O_R, O_NONE }, + { M_PAA, O_R, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_MIRR, O_R, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_MULA, O_R, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DJNZ, O_R, O_D8 }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + + /* 20 - 3F */ + { M_ANDCF, O_I8, O_R }, { M_ORCF, O_I8, O_R }, { M_XORCF, O_I8, O_R }, { M_LDCF, O_I8, O_R }, + { M_STCF, O_I8, O_R }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_ANDCF, O_A, O_R }, { M_ORCF, O_A, O_R }, { M_XORCF, O_A, O_R }, { M_LDCF, O_A, O_R }, + { M_STCF, O_A, O_R }, { M_DB, O_NONE, O_NONE }, { M_LDC, O_CR16, O_R }, { M_LDC, O_R, O_CR16 }, + { M_RES, O_I8, O_R }, { M_SET, O_I8, O_R }, { M_CHG, O_I8, O_R }, { M_BIT, O_I8, O_R }, + { M_TSET, O_I8, O_R }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_MINC1, O_I16, O_R }, { M_MINC2, O_I16, O_R }, { M_MINC4, O_I16, O_R }, { M_DB, O_NONE, O_NONE }, + { M_MDEC1, O_I16, O_R }, { M_MDEC2, O_I16, O_R }, { M_MDEC4, O_I16, O_R }, { M_DB, O_NONE, O_NONE }, + + /* 40 - 5F */ + { M_MUL, O_C32, O_R }, { M_MUL, O_C32, O_R }, { M_MUL, O_C32, O_R }, { M_MUL, O_C32, O_R }, + { M_MUL, O_C32, O_R }, { M_MUL, O_C32, O_R }, { M_MUL, O_C32, O_R }, { M_MUL, O_C32, O_R }, + { M_MULS, O_C32, O_R }, { M_MULS, O_C32, O_R }, { M_MULS, O_C32, O_R }, { M_MULS, O_C32, O_R }, + { M_MULS, O_C32, O_R }, { M_MULS, O_C32, O_R }, { M_MULS, O_C32, O_R }, { M_MULS, O_C32, O_R }, + { M_DIV, O_C32, O_R }, { M_DIV, O_C32, O_R }, { M_DIV, O_C32, O_R }, { M_DIV, O_C32, O_R }, + { M_DIV, O_C32, O_R }, { M_DIV, O_C32, O_R }, { M_DIV, O_C32, O_R }, { M_DIV, O_C32, O_R }, + { M_DIVS, O_C32, O_R }, { M_DIVS, O_C32, O_R }, { M_DIVS, O_C32, O_R }, { M_DIVS, O_C32, O_R }, + { M_DIVS, O_C32, O_R }, { M_DIVS, O_C32, O_R }, { M_DIVS, O_C32, O_R }, { M_DIVS, O_C32, O_R }, + + /* 60 - 7F */ + { M_INC, O_I3, O_R }, { M_INC, O_I3, O_R }, { M_INC, O_I3, O_R }, { M_INC, O_I3, O_R }, + { M_INC, O_I3, O_R }, { M_INC, O_I3, O_R }, { M_INC, O_I3, O_R }, { M_INC, O_I3, O_R }, + { M_DEC, O_I3, O_R }, { M_DEC, O_I3, O_R }, { M_DEC, O_I3, O_R }, { M_DEC, O_I3, O_R }, + { M_DEC, O_I3, O_R }, { M_DEC, O_I3, O_R }, { M_DEC, O_I3, O_R }, { M_DEC, O_I3, O_R }, + { M_SCC, O_CC, O_R }, { M_SCC, O_CC, O_R }, { M_SCC, O_CC, O_R }, { M_SCC, O_CC, O_R }, + { M_SCC, O_CC, O_R }, { M_SCC, O_CC, O_R }, { M_SCC, O_CC, O_R }, { M_SCC, O_CC, O_R }, + { M_SCC, O_CC, O_R }, { M_SCC, O_CC, O_R }, { M_SCC, O_CC, O_R }, { M_SCC, O_CC, O_R }, + { M_SCC, O_CC, O_R }, { M_SCC, O_CC, O_R }, { M_SCC, O_CC, O_R }, { M_SCC, O_CC, O_R }, + + /* 80 - 9F */ + { M_ADD, O_C16, O_R }, { M_ADD, O_C16, O_R }, { M_ADD, O_C16, O_R }, { M_ADD, O_C16, O_R }, + { M_ADD, O_C16, O_R }, { M_ADD, O_C16, O_R }, { M_ADD, O_C16, O_R }, { M_ADD, O_C16, O_R }, + { M_LD, O_C16, O_R }, { M_LD, O_C16, O_R }, { M_LD, O_C16, O_R }, { M_LD, O_C16, O_R }, + { M_LD, O_C16, O_R }, { M_LD, O_C16, O_R }, { M_LD, O_C16, O_R }, { M_LD, O_C16, O_R }, + { M_ADC, O_C16, O_R }, { M_ADC, O_C16, O_R }, { M_ADC, O_C16, O_R }, { M_ADC, O_C16, O_R }, + { M_ADC, O_C16, O_R }, { M_ADC, O_C16, O_R }, { M_ADC, O_C16, O_R }, { M_ADC, O_C16, O_R }, + { M_LD, O_R, O_C16 }, { M_LD, O_R, O_C16 }, { M_LD, O_R, O_C16 }, { M_LD, O_R, O_C16 }, + { M_LD, O_R, O_C16 }, { M_LD, O_R, O_C16 }, { M_LD, O_R, O_C16 }, { M_LD, O_R, O_C16 }, + + /* A0 - BF */ + { M_SUB, O_C16, O_R }, { M_SUB, O_C16, O_R }, { M_SUB, O_C16, O_R }, { M_SUB, O_C16, O_R }, + { M_SUB, O_C16, O_R }, { M_SUB, O_C16, O_R }, { M_SUB, O_C16, O_R }, { M_SUB, O_C16, O_R }, + { M_LD, O_R, O_I3 }, { M_LD, O_R, O_I3 }, { M_LD, O_R, O_I3 }, { M_LD, O_R, O_I3 }, + { M_LD, O_R, O_I3 }, { M_LD, O_R, O_I3 }, { M_LD, O_R, O_I3 }, { M_LD, O_R, O_I3 }, + { M_SBC, O_C16, O_R }, { M_SBC, O_C16, O_R }, { M_SBC, O_C16, O_R }, { M_SBC, O_C16, O_R }, + { M_SBC, O_C16, O_R }, { M_SBC, O_C16, O_R }, { M_SBC, O_C16, O_R }, { M_SBC, O_C16, O_R }, + { M_EX, O_C16, O_R }, { M_EX, O_C16, O_R }, { M_EX, O_C16, O_R }, { M_EX, O_C16, O_R }, + { M_EX, O_C16, O_R }, { M_EX, O_C16, O_R }, { M_EX, O_C16, O_R }, { M_EX, O_C16, O_R }, + + /* C0 - DF */ + { M_AND, O_C16, O_R }, { M_AND, O_C16, O_R }, { M_AND, O_C16, O_R }, { M_AND, O_C16, O_R }, + { M_AND, O_C16, O_R }, { M_AND, O_C16, O_R }, { M_AND, O_C16, O_R }, { M_AND, O_C16, O_R }, + { M_ADD, O_R, O_I16 }, { M_ADC, O_R, O_I16 }, { M_SUB, O_R, O_I16 }, { M_SBC, O_R, O_I16 }, + { M_AND, O_R, O_I16 }, { M_XOR, O_R, O_I16 }, { M_OR, O_R, O_I16 }, { M_CP, O_R, O_I16 }, + { M_XOR, O_C16, O_R }, { M_XOR, O_C16, O_R }, { M_XOR, O_C16, O_R }, { M_XOR, O_C16, O_R }, + { M_XOR, O_C16, O_R }, { M_XOR, O_C16, O_R }, { M_XOR, O_C16, O_R }, { M_XOR, O_C16, O_R }, + { M_CP, O_R, O_I3 }, { M_CP, O_R, O_I3 }, { M_CP, O_R, O_I3 }, { M_CP, O_R, O_I3 }, + { M_CP, O_R, O_I3 }, { M_CP, O_R, O_I3 }, { M_CP, O_R, O_I3 }, { M_CP, O_R, O_I3 }, + + /* E0 - FF */ + { M_OR, O_C16, O_R }, { M_OR, O_C16, O_R }, { M_OR, O_C16, O_R }, { M_OR, O_C16, O_R }, + { M_OR, O_C16, O_R }, { M_OR, O_C16, O_R }, { M_OR, O_C16, O_R }, { M_OR, O_C16, O_R }, + { M_RLC, O_I8, O_R }, { M_RRC, O_I8, O_R }, { M_RL, O_I8, O_R }, { M_RR, O_I8, O_R }, + { M_SLA, O_I8, O_R }, { M_SRA, O_I8, O_R }, { M_SLL, O_I8, O_R }, { M_SRL, O_I8, O_R }, + { M_CP, O_C16, O_R }, { M_CP, O_C16, O_R }, { M_CP, O_C16, O_R }, { M_CP, O_C16, O_R }, + { M_CP, O_C16, O_R }, { M_CP, O_C16, O_R }, { M_CP, O_C16, O_R }, { M_CP, O_C16, O_R }, + { M_RLC, O_A, O_R }, { M_RRC, O_A, O_R }, { M_RL, O_A, O_R }, { M_RR, O_A, O_R }, + { M_SLA, O_A, O_R }, { M_SRA, O_A, O_R }, { M_SLL, O_A, O_R }, { M_SRL, O_A, O_R } +}; + + +static const tlcs900inst mnemonic_e0[256] = +{ + /* 00 - 1F */ + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + + /* 20 - 3F */ + { M_LD, O_C32, O_M }, { M_LD, O_C32, O_M }, { M_LD, O_C32, O_M }, { M_LD, O_C32, O_M }, + { M_LD, O_C32, O_M }, { M_LD, O_C32, O_M }, { M_LD, O_C32, O_M }, { M_LD, O_C32, O_M }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + + /* 40 - 5F */ + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + + /* 60 - 7F */ + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + + /* 80 - 9F */ + { M_ADD, O_C32, O_M }, { M_ADD, O_C32, O_M }, { M_ADD, O_C32, O_M }, { M_ADD, O_C32, O_M }, + { M_ADD, O_C32, O_M }, { M_ADD, O_C32, O_M }, { M_ADD, O_C32, O_M }, { M_ADD, O_C32, O_M }, + { M_ADD, O_M, O_C32 }, { M_ADD, O_M, O_C32 }, { M_ADD, O_M, O_C32 }, { M_ADD, O_M, O_C32 }, + { M_ADD, O_M, O_C32 }, { M_ADD, O_M, O_C32 }, { M_ADD, O_M, O_C32 }, { M_ADD, O_M, O_C32 }, + { M_ADC, O_C32, O_M }, { M_ADC, O_C32, O_M }, { M_ADC, O_C32, O_M }, { M_ADC, O_C32, O_M }, + { M_ADC, O_C32, O_M }, { M_ADC, O_C32, O_M }, { M_ADC, O_C32, O_M }, { M_ADC, O_C32, O_M }, + { M_ADC, O_M, O_C32 }, { M_ADC, O_M, O_C32 }, { M_ADC, O_M, O_C32 }, { M_ADC, O_M, O_C32 }, + { M_ADC, O_M, O_C32 }, { M_ADC, O_M, O_C32 }, { M_ADC, O_M, O_C32 }, { M_ADC, O_M, O_C32 }, + + /* A0 - BF */ + { M_SUB, O_C32, O_M }, { M_SUB, O_C32, O_M }, { M_SUB, O_C32, O_M }, { M_SUB, O_C32, O_M }, + { M_SUB, O_C32, O_M }, { M_SUB, O_C32, O_M }, { M_SUB, O_C32, O_M }, { M_SUB, O_C32, O_M }, + { M_SUB, O_M, O_C32 }, { M_SUB, O_M, O_C32 }, { M_SUB, O_M, O_C32 }, { M_SUB, O_M, O_C32 }, + { M_SUB, O_M, O_C32 }, { M_SUB, O_M, O_C32 }, { M_SUB, O_M, O_C32 }, { M_SUB, O_M, O_C32 }, + { M_SBC, O_C32, O_M }, { M_SBC, O_C32, O_M }, { M_SBC, O_C32, O_M }, { M_SBC, O_C32, O_M }, + { M_SBC, O_C32, O_M }, { M_SBC, O_C32, O_M }, { M_SBC, O_C32, O_M }, { M_SBC, O_C32, O_M }, + { M_SBC, O_M, O_C32 }, { M_SBC, O_M, O_C32 }, { M_SBC, O_M, O_C32 }, { M_SBC, O_M, O_C32 }, + { M_SBC, O_M, O_C32 }, { M_SBC, O_M, O_C32 }, { M_SBC, O_M, O_C32 }, { M_SBC, O_M, O_C32 }, + + /* C0 - DF */ + { M_AND, O_C32, O_M }, { M_AND, O_C32, O_M }, { M_AND, O_C32, O_M }, { M_AND, O_C32, O_M }, + { M_AND, O_C32, O_M }, { M_AND, O_C32, O_M }, { M_AND, O_C32, O_M }, { M_AND, O_C32, O_M }, + { M_AND, O_M, O_C32 }, { M_AND, O_M, O_C32 }, { M_AND, O_M, O_C32 }, { M_AND, O_M, O_C32 }, + { M_AND, O_M, O_C32 }, { M_AND, O_M, O_C32 }, { M_AND, O_M, O_C32 }, { M_AND, O_M, O_C32 }, + { M_XOR, O_C32, O_M }, { M_XOR, O_C32, O_M }, { M_XOR, O_C32, O_M }, { M_XOR, O_C32, O_M }, + { M_XOR, O_C32, O_M }, { M_XOR, O_C32, O_M }, { M_XOR, O_C32, O_M }, { M_XOR, O_C32, O_M }, + { M_XOR, O_M, O_C32 }, { M_XOR, O_M, O_C32 }, { M_XOR, O_M, O_C32 }, { M_XOR, O_M, O_C32 }, + { M_XOR, O_M, O_C32 }, { M_XOR, O_M, O_C32 }, { M_XOR, O_M, O_C32 }, { M_XOR, O_M, O_C32 }, + + /* E0 - FF */ + { M_OR, O_C32, O_M }, { M_OR, O_C32, O_M }, { M_OR, O_C32, O_M }, { M_OR, O_C32, O_M }, + { M_OR, O_C32, O_M }, { M_OR, O_C32, O_M }, { M_OR, O_C32, O_M }, { M_OR, O_C32, O_M }, + { M_OR, O_M, O_C32 }, { M_OR, O_M, O_C32 }, { M_OR, O_M, O_C32 }, { M_OR, O_M, O_C32 }, + { M_OR, O_M, O_C32 }, { M_OR, O_M, O_C32 }, { M_OR, O_M, O_C32 }, { M_OR, O_M, O_C32 }, + { M_CP, O_C32, O_M }, { M_CP, O_C32, O_M }, { M_CP, O_C32, O_M }, { M_CP, O_C32, O_M }, + { M_CP, O_C32, O_M }, { M_CP, O_C32, O_M }, { M_CP, O_C32, O_M }, { M_CP, O_C32, O_M }, + { M_CP, O_M, O_C32 }, { M_CP, O_M, O_C32 }, { M_CP, O_M, O_C32 }, { M_CP, O_M, O_C32 }, + { M_CP, O_M, O_C32 }, { M_CP, O_M, O_C32 }, { M_CP, O_M, O_C32 }, { M_CP, O_M, O_C32 }, +}; + + +static const tlcs900inst mnemonic_e8[256] = +{ + /* 00 - 1F */ + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_LD, O_R, O_I32 }, + { M_PUSH, O_R, O_NONE }, { M_POP, O_R, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_LINK, O_R, O_I16 }, { M_UNLK, O_R, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_EXTZ, O_R, O_NONE }, { M_EXTS, O_R, O_NONE }, + { M_PAA, O_R, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + + /* 20 - 3F */ + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_LDC, O_CR32, O_R }, { M_LDC, O_R, O_CR32 }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + + /* 40 - 5F */ + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + + /* 60 - 7F */ + { M_INC, O_I3, O_R }, { M_INC, O_I3, O_R }, { M_INC, O_I3, O_R }, { M_INC, O_I3, O_R }, + { M_INC, O_I3, O_R }, { M_INC, O_I3, O_R }, { M_INC, O_I3, O_R }, { M_INC, O_I3, O_R }, + { M_DEC, O_I3, O_R }, { M_DEC, O_I3, O_R }, { M_DEC, O_I3, O_R }, { M_DEC, O_I3, O_R }, + { M_DEC, O_I3, O_R }, { M_DEC, O_I3, O_R }, { M_DEC, O_I3, O_R }, { M_DEC, O_I3, O_R }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + + /* 80 - 9F */ + { M_ADD, O_C32, O_R }, { M_ADD, O_C32, O_R }, { M_ADD, O_C32, O_R }, { M_ADD, O_C32, O_R }, + { M_ADD, O_C32, O_R }, { M_ADD, O_C32, O_R }, { M_ADD, O_C32, O_R }, { M_ADD, O_C32, O_R }, + { M_LD, O_C32, O_R }, { M_LD, O_C32, O_R }, { M_LD, O_C32, O_R }, { M_LD, O_C32, O_R }, + { M_LD, O_C32, O_R }, { M_LD, O_C32, O_R }, { M_LD, O_C32, O_R }, { M_LD, O_C32, O_R }, + { M_ADC, O_C32, O_R }, { M_ADC, O_C32, O_R }, { M_ADC, O_C32, O_R }, { M_ADC, O_C32, O_R }, + { M_ADC, O_C32, O_R }, { M_ADC, O_C32, O_R }, { M_ADC, O_C32, O_R }, { M_ADC, O_C32, O_R }, + { M_LD, O_R, O_C32 }, { M_LD, O_R, O_C32 }, { M_LD, O_R, O_C32 }, { M_LD, O_R, O_C32 }, + { M_LD, O_R, O_C32 }, { M_LD, O_R, O_C32 }, { M_LD, O_R, O_C32 }, { M_LD, O_R, O_C32 }, + + /* A0 - BF */ + { M_SUB, O_C32, O_R }, { M_SUB, O_C32, O_R }, { M_SUB, O_C32, O_R }, { M_SUB, O_C32, O_R }, + { M_SUB, O_C32, O_R }, { M_SUB, O_C32, O_R }, { M_SUB, O_C32, O_R }, { M_SUB, O_C32, O_R }, + { M_LD, O_R, O_I3 }, { M_LD, O_R, O_I3 }, { M_LD, O_R, O_I3 }, { M_LD, O_R, O_I3 }, + { M_LD, O_R, O_I3 }, { M_LD, O_R, O_I3 }, { M_LD, O_R, O_I3 }, { M_LD, O_R, O_I3 }, + { M_SBC, O_C32, O_R }, { M_SBC, O_C32, O_R }, { M_SBC, O_C32, O_R }, { M_SBC, O_C32, O_R }, + { M_SBC, O_C32, O_R }, { M_SBC, O_C32, O_R }, { M_SBC, O_C32, O_R }, { M_SBC, O_C32, O_R }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + + /* C0 - DF */ + { M_AND, O_C32, O_R }, { M_AND, O_C32, O_R }, { M_AND, O_C32, O_R }, { M_AND, O_C32, O_R }, + { M_AND, O_C32, O_R }, { M_AND, O_C32, O_R }, { M_AND, O_C32, O_R }, { M_AND, O_C32, O_R }, + { M_ADD, O_R, O_I32 }, { M_ADC, O_R, O_I32 }, { M_SUB, O_R, O_I32 }, { M_SBC, O_R, O_I32 }, + { M_AND, O_R, O_I32 }, { M_XOR, O_R, O_I32 }, { M_OR, O_R, O_I32 }, { M_CP, O_R, O_I32 }, + { M_XOR, O_C32, O_R }, { M_XOR, O_C32, O_R }, { M_XOR, O_C32, O_R }, { M_XOR, O_C32, O_R }, + { M_XOR, O_C32, O_R }, { M_XOR, O_C32, O_R }, { M_XOR, O_C32, O_R }, { M_XOR, O_C32, O_R }, + { M_CP, O_R, O_I3 }, { M_CP, O_R, O_I3 }, { M_CP, O_R, O_I3 }, { M_CP, O_R, O_I3 }, + { M_CP, O_R, O_I3 }, { M_CP, O_R, O_I3 }, { M_CP, O_R, O_I3 }, { M_CP, O_R, O_I3 }, + + /* E0 - FF */ + { M_OR, O_C32, O_R }, { M_OR, O_C32, O_R }, { M_OR, O_C32, O_R }, { M_OR, O_C32, O_R }, + { M_OR, O_C32, O_R }, { M_OR, O_C32, O_R }, { M_OR, O_C32, O_R }, { M_OR, O_C32, O_R }, + { M_RLC, O_I8, O_R }, { M_RRC, O_I8, O_R }, { M_RL, O_I8, O_R }, { M_RR, O_I8, O_R }, + { M_SLA, O_I8, O_R }, { M_SRA, O_I8, O_R }, { M_SLL, O_I8, O_R }, { M_SRL, O_I8, O_R }, + { M_CP, O_C32, O_R }, { M_CP, O_C32, O_R }, { M_CP, O_C32, O_R }, { M_CP, O_C32, O_R }, + { M_CP, O_C32, O_R }, { M_CP, O_C32, O_R }, { M_CP, O_C32, O_R }, { M_CP, O_C32, O_R }, + { M_RLC, O_A, O_R }, { M_RRC, O_A, O_R }, { M_RL, O_A, O_R }, { M_RR, O_A, O_R }, + { M_SLA, O_A, O_R }, { M_SRA, O_A, O_R }, { M_SLL, O_A, O_R }, { M_SRL, O_A, O_R } +}; + + +static const tlcs900inst mnemonic_f0[256] = +{ + /* 00 - 1F */ + { M_LD, O_M, O_I8 }, { M_DB, O_NONE, O_NONE }, { M_LD, O_M, O_I16 }, { M_DB, O_NONE, O_NONE }, + { M_POP, O_M, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_POPW, O_M, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_LD, O_M, O_M16 }, { M_DB, O_NONE, O_NONE }, { M_LDW, O_M, O_M16 }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + + /* 20 - 3F */ + { M_LDA, O_C16, O_M }, { M_LDA, O_C16, O_M }, { M_LDA, O_C16, O_M }, { M_LDA, O_C16, O_M }, + { M_LDA, O_C16, O_M }, { M_LDA, O_C16, O_M }, { M_LDA, O_C16, O_M }, { M_LDA, O_C16, O_M }, + { M_ANDCF, O_A, O_M }, { M_ORCF, O_A, O_M }, { M_XORCF, O_A, O_M }, { M_LDCF, O_A, O_M }, + { M_STCF, O_A, O_M }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_LDA, O_C32, O_M }, { M_LDA, O_C32, O_M }, { M_LDA, O_C32, O_M }, { M_LDA, O_C32, O_M }, + { M_LDA, O_C32, O_M }, { M_LDA, O_C32, O_M }, { M_LDA, O_C32, O_M }, { M_LDA, O_C32, O_M }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + + /* 40 - 5F */ + { M_LD, O_M, O_C8 }, { M_LD, O_M, O_C8 }, { M_LD, O_M, O_C8 }, { M_LD, O_M, O_C8 }, + { M_LD, O_M, O_C8 }, { M_LD, O_M, O_C8 }, { M_LD, O_M, O_C8 }, { M_LD, O_M, O_C8 }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_LD, O_M, O_C16 }, { M_LD, O_M, O_C16 }, { M_LD, O_M, O_C16 }, { M_LD, O_M, O_C16 }, + { M_LD, O_M, O_C16 }, { M_LD, O_M, O_C16 }, { M_LD, O_M, O_C16 }, { M_LD, O_M, O_C16 }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + + /* 60 - 7F */ + { M_LD, O_M, O_C32 }, { M_LD, O_M, O_C32 }, { M_LD, O_M, O_C32 }, { M_LD, O_M, O_C32 }, + { M_LD, O_M, O_C32 }, { M_LD, O_M, O_C32 }, { M_LD, O_M, O_C32 }, { M_LD, O_M, O_C32 }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + + /* 80 - 9F */ + { M_ANDCF, O_I3, O_M }, { M_ANDCF, O_I3, O_M }, { M_ANDCF, O_I3, O_M }, { M_ANDCF, O_I3, O_M }, + { M_ANDCF, O_I3, O_M }, { M_ANDCF, O_I3, O_M }, { M_ANDCF, O_I3, O_M }, { M_ANDCF, O_I3, O_M }, + { M_ORCF, O_I3, O_M }, { M_ORCF, O_I3, O_M }, { M_ORCF, O_I3, O_M }, { M_ORCF, O_I3, O_M }, + { M_ORCF, O_I3, O_M }, { M_ORCF, O_I3, O_M }, { M_ORCF, O_I3, O_M }, { M_ORCF, O_I3, O_M }, + { M_XORCF, O_I3, O_M }, { M_XORCF, O_I3, O_M }, { M_XORCF, O_I3, O_M }, { M_XORCF, O_I3, O_M }, + { M_XORCF, O_I3, O_M }, { M_XORCF, O_I3, O_M }, { M_XORCF, O_I3, O_M }, { M_XORCF, O_I3, O_M }, + { M_LDCF, O_I3, O_M }, { M_LDCF, O_I3, O_M }, { M_LDCF, O_I3, O_M }, { M_LDCF, O_I3, O_M }, + { M_LDCF, O_I3, O_M }, { M_LDCF, O_I3, O_M }, { M_LDCF, O_I3, O_M }, { M_LDCF, O_I3, O_M }, + + /* A0 - BF */ + { M_STCF, O_I3, O_M }, { M_STCF, O_I3, O_M }, { M_STCF, O_I3, O_M }, { M_STCF, O_I3, O_M }, + { M_STCF, O_I3, O_M }, { M_STCF, O_I3, O_M }, { M_STCF, O_I3, O_M }, { M_STCF, O_I3, O_M }, + { M_TSET, O_I3, O_M }, { M_TSET, O_I3, O_M }, { M_TSET, O_I3, O_M }, { M_TSET, O_I3, O_M }, + { M_TSET, O_I3, O_M }, { M_TSET, O_I3, O_M }, { M_TSET, O_I3, O_M }, { M_TSET, O_I3, O_M }, + { M_RES, O_I3, O_M }, { M_RES, O_I3, O_M }, { M_RES, O_I3, O_M }, { M_RES, O_I3, O_M }, + { M_RES, O_I3, O_M }, { M_RES, O_I3, O_M }, { M_RES, O_I3, O_M }, { M_RES, O_I3, O_M }, + { M_SET, O_I3, O_M }, { M_SET, O_I3, O_M }, { M_SET, O_I3, O_M }, { M_SET, O_I3, O_M }, + { M_SET, O_I3, O_M }, { M_SET, O_I3, O_M }, { M_SET, O_I3, O_M }, { M_SET, O_I3, O_M }, + + /* C0 - DF */ + { M_CHG, O_I3, O_M }, { M_CHG, O_I3, O_M }, { M_CHG, O_I3, O_M }, { M_CHG, O_I3, O_M }, + { M_CHG, O_I3, O_M }, { M_CHG, O_I3, O_M }, { M_CHG, O_I3, O_M }, { M_CHG, O_I3, O_M }, + { M_BIT, O_I3, O_M }, { M_BIT, O_I3, O_M }, { M_BIT, O_I3, O_M }, { M_BIT, O_I3, O_M }, + { M_BIT, O_I3, O_M }, { M_BIT, O_I3, O_M }, { M_BIT, O_I3, O_M }, { M_BIT, O_I3, O_M }, + { M_JP, O_CC, O_M }, { M_JP, O_CC, O_M }, { M_JP, O_CC, O_M }, { M_JP, O_CC, O_M }, + { M_JP, O_CC, O_M }, { M_JP, O_CC, O_M }, { M_JP, O_CC, O_M }, { M_JP, O_CC, O_M }, + { M_JP, O_CC, O_M }, { M_JP, O_CC, O_M }, { M_JP, O_CC, O_M }, { M_JP, O_CC, O_M }, + { M_JP, O_CC, O_M }, { M_JP, O_CC, O_M }, { M_JP, O_CC, O_M }, { M_JP, O_CC, O_M }, + + /* E0 - FF */ + { M_CALL, O_CC, O_M }, { M_CALL, O_CC, O_M }, { M_CALL, O_CC, O_M }, { M_CALL, O_CC, O_M }, + { M_CALL, O_CC, O_M }, { M_CALL, O_CC, O_M }, { M_CALL, O_CC, O_M }, { M_CALL, O_CC, O_M }, + { M_CALL, O_CC, O_M }, { M_CALL, O_CC, O_M }, { M_CALL, O_CC, O_M }, { M_CALL, O_CC, O_M }, + { M_CALL, O_CC, O_M }, { M_CALL, O_CC, O_M }, { M_CALL, O_CC, O_M }, { M_CALL, O_CC, O_M }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE } +}; + + +static const tlcs900inst mnemonic[256] = +{ + /* 00 - 1F */ + { M_NOP, O_NONE, O_NONE }, { M_NORMAL, O_NONE, O_NONE }, { M_PUSH, O_SR, O_NONE }, { M_POP, O_SR, O_NONE }, + { M_MAX, O_NONE, O_NONE }, { M_HALT, O_NONE, O_NONE }, { M_EI, O_I8, O_NONE }, { M_RETI, O_NONE, O_NONE }, + { M_LD, O_M8, O_I8 }, { M_PUSH, O_I8, O_NONE }, { M_LD, O_M8, O_I16 }, { M_PUSH, O_I16, O_NONE }, + { M_INCF, O_NONE, O_NONE }, { M_DECF, O_NONE, O_NONE }, { M_RET, O_NONE, O_NONE }, { M_RETD, O_I16, O_NONE }, + { M_RCF, O_NONE, O_NONE }, { M_SCF, O_NONE, O_NONE }, { M_CCF, O_NONE, O_NONE }, { M_ZCF, O_NONE, O_NONE }, + { M_PUSH, O_A, O_NONE }, { M_POP, O_A, O_NONE }, { M_EX, O_F, O_F }, { M_LDF, O_I8, O_NONE }, + { M_PUSH, O_F, O_NONE }, { M_POP, O_F, O_NONE }, { M_JP, O_I16, O_NONE }, { M_JP, O_I24, O_NONE }, + { M_CALL, O_I16, O_NONE }, { M_CALL, O_I24, O_NONE }, { M_CALR, O_D16, O_NONE }, { M_DB, O_NONE, O_NONE }, + + /* 20 - 3F */ + { M_LD, O_C8, O_I8 }, { M_LD, O_C8, O_I8 }, { M_LD, O_C8, O_I8 }, { M_LD, O_C8, O_I8 }, + { M_LD, O_C8, O_I8 }, { M_LD, O_C8, O_I8 }, { M_LD, O_C8, O_I8 }, { M_LD, O_C8, O_I8 }, + { M_PUSH, O_C16, O_NONE }, { M_PUSH, O_C16, O_NONE }, { M_PUSH, O_C16, O_NONE }, { M_PUSH, O_C16, O_NONE }, + { M_PUSH, O_C16, O_NONE }, { M_PUSH, O_C16, O_NONE }, { M_PUSH, O_C16, O_NONE }, { M_PUSH, O_C16, O_NONE }, + { M_LD, O_C16, O_I16 }, { M_LD, O_C16, O_I16 }, { M_LD, O_C16, O_I16 }, { M_LD, O_C16, O_I16 }, + { M_LD, O_C16, O_I16 }, { M_LD, O_C16, O_I16 }, { M_LD, O_C16, O_I16 }, { M_LD, O_C16, O_I16 }, + { M_PUSH, O_C32, O_NONE }, { M_PUSH, O_C32, O_NONE }, { M_PUSH, O_C32, O_NONE }, { M_PUSH, O_C32, O_NONE }, + { M_PUSH, O_C32, O_NONE }, { M_PUSH, O_C32, O_NONE }, { M_PUSH, O_C32, O_NONE }, { M_PUSH, O_C32, O_NONE }, + + /* 40 - 5F */ + { M_LD, O_C32, O_I32 }, { M_LD, O_C32, O_I32 }, { M_LD, O_C32, O_I32 }, { M_LD, O_C32, O_I32 }, + { M_LD, O_C32, O_I32 }, { M_LD, O_C32, O_I32 }, { M_LD, O_C32, O_I32 }, { M_LD, O_C32, O_I32 }, + { M_POP, O_C16, O_NONE }, { M_POP, O_C16, O_NONE }, { M_POP, O_C16, O_NONE }, { M_POP, O_C16, O_NONE }, + { M_POP, O_C16, O_NONE }, { M_POP, O_C16, O_NONE }, { M_POP, O_C16, O_NONE }, { M_POP, O_C16, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, + { M_POP, O_C32, O_NONE }, { M_POP, O_C32, O_NONE }, { M_POP, O_C32, O_NONE }, { M_POP, O_C32, O_NONE }, + { M_POP, O_C32, O_NONE }, { M_POP, O_C32, O_NONE }, { M_POP, O_C32, O_NONE }, { M_POP, O_C32, O_NONE }, + + /* 60 - 7F */ + { M_JR, O_CC, O_D8 }, { M_JR, O_CC, O_D8 }, { M_JR, O_CC, O_D8 }, { M_JR, O_CC, O_D8 }, + { M_JR, O_CC, O_D8 }, { M_JR, O_CC, O_D8 }, { M_JR, O_CC, O_D8 }, { M_JR, O_CC, O_D8 }, + { M_JR, O_CC, O_D8 }, { M_JR, O_CC, O_D8 }, { M_JR, O_CC, O_D8 }, { M_JR, O_CC, O_D8 }, + { M_JR, O_CC, O_D8 }, { M_JR, O_CC, O_D8 }, { M_JR, O_CC, O_D8 }, { M_JR, O_CC, O_D8 }, + { M_JRL, O_CC, O_D16 }, { M_JRL, O_CC, O_D16 }, { M_JRL, O_CC, O_D16 }, { M_JRL, O_CC, O_D16 }, + { M_JRL, O_CC, O_D16 }, { M_JRL, O_CC, O_D16 }, { M_JRL, O_CC, O_D16 }, { M_JRL, O_CC, O_D16 }, + { M_JRL, O_CC, O_D16 }, { M_JRL, O_CC, O_D16 }, { M_JRL, O_CC, O_D16 }, { M_JRL, O_CC, O_D16 }, + { M_JRL, O_CC, O_D16 }, { M_JRL, O_CC, O_D16 }, { M_JRL, O_CC, O_D16 }, { M_JRL, O_CC, O_D16 }, + + /* 80 - 9F */ + { M_80, O_NONE, O_NONE }, { M_80, O_NONE, O_NONE }, { M_80, O_NONE, O_NONE }, { M_80, O_NONE, O_NONE }, + { M_80, O_NONE, O_NONE }, { M_80, O_NONE, O_NONE }, { M_80, O_NONE, O_NONE }, { M_80, O_NONE, O_NONE }, + { M_88, O_NONE, O_NONE }, { M_88, O_NONE, O_NONE }, { M_88, O_NONE, O_NONE }, { M_88, O_NONE, O_NONE }, + { M_88, O_NONE, O_NONE }, { M_88, O_NONE, O_NONE }, { M_88, O_NONE, O_NONE }, { M_88, O_NONE, O_NONE }, + { M_90, O_NONE, O_NONE }, { M_90, O_NONE, O_NONE }, { M_90, O_NONE, O_NONE }, { M_90, O_NONE, O_NONE }, + { M_90, O_NONE, O_NONE }, { M_90, O_NONE, O_NONE }, { M_90, O_NONE, O_NONE }, { M_90, O_NONE, O_NONE }, + { M_98, O_NONE, O_NONE }, { M_98, O_NONE, O_NONE }, { M_98, O_NONE, O_NONE }, { M_98, O_NONE, O_NONE }, + { M_98, O_NONE, O_NONE }, { M_98, O_NONE, O_NONE }, { M_98, O_NONE, O_NONE }, { M_98, O_NONE, O_NONE }, + + /* A0 - BF */ + { M_A0, O_NONE, O_NONE }, { M_A0, O_NONE, O_NONE }, { M_A0, O_NONE, O_NONE }, { M_A0, O_NONE, O_NONE }, + { M_A0, O_NONE, O_NONE }, { M_A0, O_NONE, O_NONE }, { M_A0, O_NONE, O_NONE }, { M_A0, O_NONE, O_NONE }, + { M_A8, O_NONE, O_NONE }, { M_A8, O_NONE, O_NONE }, { M_A8, O_NONE, O_NONE }, { M_A8, O_NONE, O_NONE }, + { M_A8, O_NONE, O_NONE }, { M_A8, O_NONE, O_NONE }, { M_A8, O_NONE, O_NONE }, { M_A8, O_NONE, O_NONE }, + { M_B0, O_NONE, O_NONE }, { M_B0, O_NONE, O_NONE }, { M_B0, O_NONE, O_NONE }, { M_B0, O_NONE, O_NONE }, + { M_B0, O_NONE, O_NONE }, { M_B0, O_NONE, O_NONE }, { M_B0, O_NONE, O_NONE }, { M_B0, O_NONE, O_NONE }, + { M_B8, O_NONE, O_NONE }, { M_B8, O_NONE, O_NONE }, { M_B8, O_NONE, O_NONE }, { M_B8, O_NONE, O_NONE }, + { M_B8, O_NONE, O_NONE }, { M_B8, O_NONE, O_NONE }, { M_B8, O_NONE, O_NONE }, { M_B8, O_NONE, O_NONE }, + + /* C0 - DF */ + { M_C0, O_NONE, O_NONE }, { M_C0, O_NONE, O_NONE }, { M_C0, O_NONE, O_NONE }, { M_C0, O_NONE, O_NONE }, + { M_C0, O_NONE, O_NONE }, { M_C0, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { oC8, O_NONE, O_NONE }, + { oC8, O_NONE, O_NONE }, { oC8, O_NONE, O_NONE }, { oC8, O_NONE, O_NONE }, { oC8, O_NONE, O_NONE }, + { oC8, O_NONE, O_NONE }, { oC8, O_NONE, O_NONE }, { oC8, O_NONE, O_NONE }, { oC8, O_NONE, O_NONE }, + { M_D0, O_NONE, O_NONE }, { M_D0, O_NONE, O_NONE }, { M_D0, O_NONE, O_NONE }, { M_D0, O_NONE, O_NONE }, + { M_D0, O_NONE, O_NONE }, { M_D0, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { oD8, O_NONE, O_NONE }, + { oD8, O_NONE, O_NONE }, { oD8, O_NONE, O_NONE }, { oD8, O_NONE, O_NONE }, { oD8, O_NONE, O_NONE }, + { oD8, O_NONE, O_NONE }, { oD8, O_NONE, O_NONE }, { oD8, O_NONE, O_NONE }, { oD8, O_NONE, O_NONE }, + + /* E0 - FF */ + { M_E0, O_NONE, O_NONE }, { M_E0, O_NONE, O_NONE }, { M_E0, O_NONE, O_NONE }, { M_E0, O_NONE, O_NONE }, + { M_E0, O_NONE, O_NONE }, { M_E0, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_E8, O_NONE, O_NONE }, + { M_E8, O_NONE, O_NONE }, { M_E8, O_NONE, O_NONE }, { M_E8, O_NONE, O_NONE }, { M_E8, O_NONE, O_NONE }, + { M_E8, O_NONE, O_NONE }, { M_E8, O_NONE, O_NONE }, { M_E8, O_NONE, O_NONE }, { M_E8, O_NONE, O_NONE }, + { M_F0, O_NONE, O_NONE }, { M_F0, O_NONE, O_NONE }, { M_F0, O_NONE, O_NONE }, { M_F0, O_NONE, O_NONE }, + { M_F0, O_NONE, O_NONE }, { M_F0, O_NONE, O_NONE }, { M_DB, O_NONE, O_NONE }, { M_LDX, O_NONE, O_NONE }, + { M_SWI, O_I3, O_NONE }, { M_SWI, O_I3, O_NONE }, { M_SWI, O_I3, O_NONE }, { M_SWI, O_I3, O_NONE }, + { M_SWI, O_I3, O_NONE }, { M_SWI, O_I3, O_NONE }, { M_SWI, O_I3, O_NONE }, { M_SWI, O_I3, O_NONE } +}; + + + +static const char *const s_reg8[8] = { "W", "A", "B", "C", "D", "E", "H", "L" }; +static const char *const s_reg16[8] = { "WA", "BC", "DE", "HL", "IX", "IY", "IZ", "SP" }; +static const char *const s_reg32[8] = { "XWA", "XBC", "XDE", "XHL", "XIX", "XIY", "XIZ", "XSP" }; +static const char *const s_mulreg16[8] = { "??", "WA", "??", "BC", "??", "DE", "??", "HL" }; +static const char *const s_allreg8[256] = +{ + "RA0" ,"RW0" ,"QA0" ,"QW0" ,"RC0" ,"RB0" ,"QC0" ,"QB0" ,"RE0" ,"RD0" ,"QE0" ,"QD0" ,"RL0" ,"RH0" ,"QL0" ,"QH0" , + "RA1" ,"RW1" ,"QA1" ,"QW1" ,"RC1" ,"RB1" ,"QC1" ,"QB1" ,"RE1" ,"RD1" ,"QE1" ,"QD1" ,"RL1" ,"RH1" ,"QL1" ,"QH1" , + "RA2" ,"RW2" ,"QA2" ,"QW2" ,"RC2" ,"RB2" ,"QC2" ,"QB2" ,"RE2" ,"RD2" ,"QE2" ,"QD2" ,"RL2" ,"RH2" ,"QL2" ,"QH2" , + "RA3" ,"RW3" ,"QA3" ,"QW3" ,"RC3" ,"RB3" ,"QC3" ,"QB3" ,"RE3" ,"RD3" ,"QE3" ,"QD3" ,"RL3" ,"RH3" ,"QL3" ,"QH3" , + "r40B","r41B","r42B","r43B","r44B","r45B","r46B","r47B","r48B","r49B","r4AB","r4BB","r4CB","r4DB","r4EB","r4FB", + "r50B","r51B","r52B","r53B","r54B","r55B","r56B","r57B","r58B","r59B","r5AB","r5BB","r5CB","r5DB","r5EB","r5FB", + "r60B","r61B","r62B","r63B","r64B","r65B","r66B","r67B","r68B","r69B","r6AB","r6BB","r6CB","r6DB","r6EB","r6FB", + "r70B","r71B","r72B","r73B","r74B","r75B","r76B","r77B","r78B","r79B","r7AB","r7BB","r7CB","r7DB","r7EB","r7FB", + "r80B","r81B","r82B","r83B","r84B","r85B","r86B","r87B","r88B","r89B","r8AB","r8BB","r8CB","r8DB","r8EB","r8FB", + "r90B","r91B","r92B","r93B","r94B","r95B","r96B","r97B","r98B","r99B","r9AB","r9BB","r9CB","r9DB","r9EB","r9FB", + "rA0B","rA1B","rA2B","rA3B","rA4B","rA5B","rA6B","rA7B","rA8B","rA9B","rAAB","rABB","rACB","rADB","rAEB","rAFB", + "rB0B","rB1B","rB2B","rB3B","rB4B","rB5B","rB6B","rB7B","rB8B","rB9B","rBAB","rBBB","rBCB","rBDB","rBEB","rBFB", + "rC0B","rC1B","rC2B","rC3B","rC4B","rC5B","rC6B","rC7B","rC8B","rC9B","rCAB","rCBB","rCCB","rCDB","rCEB","rCFB", + "RA-1","RW-1","QA-1","QW-1","RC-1","RB-1","QC-1","QB-1","RE-1","RD-1","QE-1","QD-1","RL-1","RH-1","QL-1","QH-1", + "A" ,"W" ,"QA" ,"QW" ,"C" ,"B" ,"QC" ,"QB" ,"E" ,"D" ,"QE" ,"QD" ,"L" ,"H" ,"QL" ,"QH" , + "IXL" ,"IXH" ,"QIXL","QIXH","IYL" ,"IYH" ,"QIYL","QIYH","IZL" ,"IZH" ,"QIZL","QIZH","SPL" ,"SPH" ,"QSPL","QSPH", +}; + + +static const char *const s_allreg16[256] = +{ + "RWA0","r01W","QWA0","r03W","RBC0","r05W","QBC0","r07W","RDE0","r09W","QDE0","r0BW","RHL0","r0DW","QHL0","r0FW", + "RWA1","r11W","QWA1","r13W","RBC1","r15W","QBC1","r17W","RDE1","r19W","QDE1","r1BW","RHL1","r1DW","QHL1","r1FW", + "RWA2","r21W","QWA2","r23W","RBC2","r25W","QBC2","r27W","RDE2","r29W","QDE2","r2BW","RHL2","r2DW","QHL2","r2FW", + "RWA3","r31W","QWA3","r33W","RBC3","r35W","QBC3","r37W","RDE3","r39W","QDE3","r3BW","RHL3","r3DW","QHL3","r3FW", + "r40W","r41W","r42W","r43W","r44W","r45W","r46W","r47W","r48W","r49W","r4AW","r4BW","r4CW","r4DW","r4EW","r4FW", + "r50W","r51W","r52W","r53W","r54W","r55W","r56W","r57W","r58W","r59W","r5AW","r5BW","r5CW","r5DW","r5EW","r5FW", + "r60W","r61W","r62W","r63W","r64W","r65W","r66W","r67W","r68W","r69W","r6AW","r6BW","r6CW","r6DW","r6EW","r6FW", + "r70W","r71W","r72W","r73W","r74W","r75W","r76W","r77W","r78W","r79W","r7AW","r7BW","r7CW","r7DW","r7EW","r7FW", + "r80W","r81W","r82W","r83W","r84W","r85W","r86W","r87W","r88W","r89W","r8AW","r8BW","r8CW","r8DW","r8EW","r8FW", + "r90W","r91W","r92W","r93W","r94W","r95W","r96W","r97W","r98W","r99W","r9AW","r9BW","r9CW","r9DW","r9EW","r9FW", + "rA0W","rA1W","rA2W","rA3W","rA4W","rA5W","rA6W","rA7W","rA8W","rA9W","rAAW","rABW","rACW","rADW","rAEW","rAFW", + "rB0W","rB1W","rB2W","rB3W","rB4W","rB5W","rB6W","rB7W","rB8W","rB9W","rBAW","rBBW","rBCW","rBDW","rBEW","rBFW", + "rC0W","rC1W","rC2W","rC3W","rC4W","rC5W","rC6W","rC7W","rC8W","rC9W","rCAW","rCBW","rCCW","rCDW","rCEW","rCFW", + "RWA-1","rD1W","QWA-1","rD3W","RBC-1","rD5W","QBC-1","rD7W","RDE-1","rD9W","QDE-1","rDBW","RHL-1","rDDW","QHL-1","rDFW", + "WA" ,"rE1W","QWA" ,"rE3W","BC" ,"rE5W","QBC" ,"rE7W","DE" ,"rE9W","QDE" ,"rEBW","HL" ,"rEDW","QHL" ,"rEFW", + "IX" ,"rF1W","QIX" ,"rF3W","IY" ,"rF5W","QIY" ,"rF7W","IZ" ,"rF9W","QIZ" ,"rFBW","SP" ,"rFDW","QSP" ,"rFFW", +}; + + +static const char *const s_allreg32[256] = +{ + "XWA0","XWA0","XWA0","r03L","XBC0","XBC0","XBC0","r07L","XDE0","XDE0","XDE0","r0BL","XHL0","XHL0","XHL0","r0FL", + "XWA1","XWA1","XWA1","r13L","XBC1","XBC1","XBC1","r17L","XDE1","XDE1","XDE1","r1BL","XHL1","XHL1","XHL1","r1FL", + "XWA2","XWA2","XWA2","r23L","XBC2","XBC2","XBC2","r27L","XDE2","XDE2","XDE2","r2BL","XHL2","XHL2","XHL2","r2FL", + "XWA3","XWA3","XWA3","r33L","XBC3","XBC3","XBC3","r37L","XDE3","XDE3","XDE3","r3BL","XHL3","XHL3","XHL3","r3FL", + "r40L","r41L","r42L","r43L","r44L","r45L","r46L","r47L","r48L","r49L","r4AL","r4BL","r4CL","r4DL","r4EL","r4FL", + "r50L","r51L","r52L","r53L","r54L","r55L","r56L","r57L","r58L","r59L","r5AL","r5BL","r5CL","r5DL","r5EL","r5FL", + "r60L","r61L","r62L","r63L","r64L","r65L","r66L","r67L","r68L","r69L","r6AL","r6BL","r6CL","r6DL","r6EL","r6FL", + "r70L","r71L","r72L","r73L","r74L","r75L","r76L","r77L","r78L","r79L","r7AL","r7BL","r7CL","r7DL","r7EL","r7FL", + "r80L","r81L","r82L","r83L","r84L","r85L","r86L","r87L","r88L","r89L","r8AL","r8BL","r8CL","r8DL","r8EL","r8FL", + "r90L","r91L","r92L","r93L","r94L","r95L","r96L","r97L","r98L","r99L","r9AL","r9BL","r9CL","r9DL","r9EL","r9FL", + "rA0L","rA1L","rA2L","rA3L","rA4L","rA5L","rA6L","rA7L","rA8L","rA9L","rAAL","rABL","rACL","rADL","rAEL","rAFL", + "rB0L","rB1L","rB2L","rB3L","rB4L","rB5L","rB6L","rB7L","rB8L","rB9L","rBAL","rBBL","rBCL","rBDL","rBEL","rBFL", + "rC0L","rC1L","rC2L","rC3L","rC4L","rC5L","rC6L","rC7L","rC8L","rC9L","rCAL","rCBL","rCCL","rCDL","rCEL","rCFL", + "XWA-1","XWA-1","XWA-1","rD3L","XBC-1","XBC-1","XBC-1","rD7L","XDE-1","XDE-1","XDE-1","rDBL","XHL-1","XHL-1","XHL-1","rDFL", + "XWA" ,"XWA" ,"XWA" ,"rE3L","XBC" ,"XBC", "XBC" ,"rE7L","XDE" ,"XDE" ,"XDE" ,"rEDL","XHL" ,"XHL" ,"XHL" ,"rEFL", + "XIX" ,"XIX" ,"XIX" ,"rF3L","XIY" ,"XIY" ,"XIY" ,"rF7L","XIZ" ,"XIZ" ,"XIZ" ,"rFBL","XSP" ,"XSP" ,"XSP" ,"rFFL", +}; + + +static const char *const s_cond[16] = +{ + "F","LT","LE","ULE","PE/OV","M/MI","Z","C","T","GE","GT","UGT","PO/NOV","P/PL","NZ","NC" +}; + + +CPU_DISASSEMBLE( tlcs900 ) +{ + const tlcs900inst *dasm; + char *dst = buffer; + char buf[32]; + UINT8 op, op1; + UINT32 imm; + int flags = 0; + int pos = 0; + + op = oprom[ pos++ ]; + + dasm = &mnemonic[ op ]; + + /* Check for extended addressing modes */ + switch( dasm->mnemonic ) + { + default: + break; + case M_80: + sprintf( buf, "%s", s_reg32[op & 0x07] ); + op = oprom[ pos++ ]; + dasm = &mnemonic_80[ op ]; + break; + + case M_88: + imm = oprom[ pos++ ]; + sprintf( buf, "%s+0x%02x", s_reg32[op & 0x07], imm ); + op = oprom[ pos++ ]; + dasm = &mnemonic_88[ op ]; + break; + + case M_90: + sprintf( buf, "%s", s_reg32[op & 0x07] ); + op = oprom[ pos++ ]; + dasm = &mnemonic_90[ op ]; + break; + + case M_98: + imm = oprom[ pos++ ]; + sprintf( buf, "%s+0x%02x", s_reg32[op & 0x07], imm ); + op = oprom[ pos++ ]; + dasm = &mnemonic_98[ op ]; + break; + + case M_A0: + sprintf( buf, "%s", s_reg32[op & 0x07] ); + op = oprom[ pos++ ]; + dasm = &mnemonic_a0[ op ]; + break; + + case M_A8: + imm = oprom[ pos++ ]; + sprintf( buf, "%s+0x%02x", s_reg32[op & 0x07], imm ); + op = oprom[ pos++ ]; + dasm = &mnemonic_a0[ op ]; + break; + + case M_B0: + sprintf( buf, "%s", s_reg32[op & 0x07] ); + op = oprom[ pos++ ]; + dasm = &mnemonic_b0[ op ]; + break; + + case M_B8: + imm = oprom[ pos++ ]; + sprintf( buf, "%s+0x%02x", s_reg32[op & 0x07], imm ); + op = oprom[ pos++ ]; + dasm = &mnemonic_b8[ op ]; + break; + + case M_C0: + switch( op & 0x07 ) + { + case 0x00: /* 0xC0 */ + imm = oprom[ pos++ ]; + sprintf( buf, "0x%02x", imm ); + break; + + case 0x01: /* 0xC1 */ + imm = oprom[ pos++ ]; + imm = imm | ( oprom[ pos++ ] << 8 ); + sprintf( buf, "0x%04x", imm ); + break; + + case 0x02: /* 0xC2 */ + imm = oprom[ pos++ ]; + imm = imm | ( oprom[ pos++ ] << 8 ); + imm = imm | ( oprom[ pos++ ] << 16 ); + sprintf( buf, "0x%06x", imm ); + break; + + case 0x03: /* 0xC3 */ + imm = oprom[ pos++ ]; + switch( imm & 0x03 ) + { + case 0x00: + sprintf( buf, "%s", s_allreg32[imm] ); + break; + + case 0x01: + op = imm; + imm = oprom[ pos++ ]; + imm = imm | ( oprom[ pos++ ] << 8 ); + sprintf( buf, "%s+0x%04x", s_allreg32[op], imm ); + break; + + case 0x02: + sprintf( buf, "unknown" ); + break; + + case 0x03: + switch( imm ) + { + case 0x03: + op = oprom[ pos++ ]; + op1 = oprom[ pos++ ]; + sprintf( buf, "%s+%s", s_allreg32[op], s_allreg8[op1] ); + break; + + case 0x07: + op = oprom[ pos++ ]; + op1 = oprom[ pos++ ]; + sprintf( buf, "%s+%s", s_allreg32[op], s_allreg16[op1] ); + break; + + case 0x13: + imm = oprom[ pos++ ]; + imm = imm | ( oprom[ pos++ ] << 8 ); + sprintf( buf, "0x%06x", pc + pos + (INT16)imm ); + break; + } + break; + } + break; + + case 0x04: /* 0xC4 */ + imm = oprom[ pos++ ]; + sprintf( buf, "-%s", s_allreg32[imm] ); + break; + + case 0x05: /* 0xC5 */ + imm = oprom[ pos++ ]; + sprintf( buf, "%s+", s_allreg32[imm] ); + break; + } + op = oprom[ pos++ ]; + dasm = &mnemonic_c0[ op ]; + break; + + case oC8: + if ( op & 0x08 ) + { + sprintf( buf, "%s", s_reg8[ op & 0x07 ] ); + } + else + { + imm = oprom[ pos++ ]; + sprintf( buf, "%s", s_allreg8[imm] ); + } + op = oprom[ pos++ ]; + dasm = &mnemonic_c8[ op ]; + break; + + case M_D0: + switch( op & 0x07 ) + { + case 0x00: /* 0xD0 */ + imm = oprom[ pos++ ]; + sprintf( buf, "0x%02x", imm ); + break; + + case 0x01: /* 0xD1 */ + imm = oprom[ pos++ ]; + imm = imm | ( oprom[ pos++ ] << 8 ); + sprintf( buf, "0x%04x", imm ); + break; + + case 0x02: /* 0xD2 */ + imm = oprom[ pos++ ]; + imm = imm | ( oprom[ pos++ ] << 8 ); + imm = imm | ( oprom[ pos++ ] << 16 ); + sprintf( buf, "0x%06x", imm ); + break; + + case 0x03: /* 0xD3 */ + imm = oprom[ pos++ ]; + switch( imm & 0x03 ) + { + case 0x00: + sprintf( buf, "%s", s_allreg32[imm] ); + break; + + case 0x01: + op = imm; + imm = oprom[ pos++ ]; + imm = imm | ( oprom[ pos++ ] << 8 ); + sprintf( buf, "%s+0x%04x", s_allreg32[op], imm ); + break; + + case 0x02: + sprintf( buf, "unknown" ); + break; + + case 0x03: + switch( imm ) + { + case 0x03: + op = oprom[ pos++ ]; + op1 = oprom[ pos++ ]; + sprintf( buf, "%s+%s", s_allreg32[op], s_allreg8[op1] ); + break; + + case 0x07: + op = oprom[ pos++ ]; + op1 = oprom[ pos++ ]; + sprintf( buf, "%s+%s", s_allreg32[op], s_allreg16[op1] ); + break; + + case 0x13: + imm = oprom[ pos++ ]; + imm = imm | ( oprom[ pos++ ] << 8 ); + sprintf( buf, "0x%06x", pc + pos + (INT16)imm ); + break; + } + break; + } + break; + + case 0x04: /* 0xD4 */ + imm = oprom[ pos++ ]; + sprintf( buf, "-%s", s_allreg32[imm] ); + break; + + case 0x05: /* 0xD5 */ + imm = oprom[ pos++ ]; + sprintf( buf, "%s+", s_allreg32[imm] ); + break; + } + op = oprom[ pos++ ]; + dasm = &mnemonic_d0[ op ]; + break; + + case oD8: + if ( op & 0x08 ) + { + sprintf( buf, "%s", s_reg16[ op & 0x07 ] ); + } + else + { + imm = oprom[ pos++ ]; + sprintf( buf, "%s", s_allreg16[imm] ); + } + + op = oprom[ pos++ ]; + dasm = &mnemonic_d8[ op ]; + break; + + case M_E0: + switch( op & 0x07 ) + { + case 0x00: /* 0xE0 */ + imm = oprom[ pos++ ]; + sprintf( buf, "0x%02x", imm ); + break; + + case 0x01: /* 0xE1 */ + imm = oprom[ pos++ ]; + imm = imm | ( oprom[ pos++ ] << 8 ); + sprintf( buf, "0x%04x", imm ); + break; + + case 0x02: /* 0xE2 */ + imm = oprom[ pos++ ]; + imm = imm | ( oprom[ pos++ ] << 8 ); + imm = imm | ( oprom[ pos++ ] << 16 ); + sprintf( buf, "0x%06x", imm ); + break; + + case 0x03: /* 0xE3 */ + imm = oprom[ pos++ ]; + switch( imm & 0x03 ) + { + case 0x00: + sprintf( buf, "%s", s_allreg32[imm] ); + break; + + case 0x01: + op = imm; + imm = oprom[ pos++ ]; + imm = imm | ( oprom[ pos++ ] << 8 ); + sprintf( buf, "%s+0x%04x", s_allreg32[op], imm ); + break; + + case 0x02: + sprintf( buf, "unknown" ); + break; + + case 0x03: + switch( imm ) + { + case 0x03: + op = oprom[ pos++ ]; + op1 = oprom[ pos++ ]; + sprintf( buf, "%s+%s", s_allreg32[op], s_allreg8[op1] ); + break; + + case 0x07: + op = oprom[ pos++ ]; + op1 = oprom[ pos++ ]; + sprintf( buf, "%s+%s", s_allreg32[op], s_allreg16[op1] ); + break; + + case 0x13: + imm = oprom[ pos++ ]; + imm = imm | ( oprom[ pos++ ] << 8 ); + sprintf( buf, "0x%06x", pc + pos + (INT16)imm ); + break; + } + break; + } + break; + + case 0x04: /* 0xE4 */ + imm = oprom[ pos++ ]; + sprintf( buf, "-%s", s_allreg32[imm] ); + break; + + case 0x05: /* 0xE5 */ + imm = oprom[ pos++ ]; + sprintf( buf, "%s+", s_allreg32[imm] ); + break; + } + op = oprom[ pos++ ]; + dasm = &mnemonic_e0[ op ]; + break; + + case M_E8: + if ( op & 0x08 ) + { + sprintf( buf, "%s", s_reg32[ op & 0x07 ] ); + } + else + { + imm = oprom[ pos++ ]; + sprintf( buf, "%s", s_allreg32[imm] ); + } + op = oprom[ pos++ ]; + dasm = &mnemonic_e8[ op ]; + break; + + case M_F0: + switch( op & 0x07 ) + { + case 0x00: /* 0xF0 */ + imm = oprom[ pos++ ]; + sprintf( buf, "0x%02x", imm ); + break; + + case 0x01: /* 0xF1 */ + imm = oprom[ pos++ ]; + imm = imm | ( oprom[ pos++ ] << 8 ); + sprintf( buf, "0x%04x", imm ); + break; + + case 0x02: /* 0xF2 */ + imm = oprom[ pos++ ]; + imm = imm | ( oprom[ pos++ ] << 8 ); + imm = imm | ( oprom[ pos++ ] << 16 ); + sprintf( buf, "0x%06x", imm ); + break; + + case 0x03: /* 0xF3 */ + imm = oprom[ pos++ ]; + switch( imm & 0x03 ) + { + case 0x00: + sprintf( buf, "%s", s_allreg32[imm] ); + break; + + case 0x01: + op = imm; + imm = oprom[ pos++ ]; + imm = imm | ( oprom[ pos++ ] << 8 ); + sprintf( buf, "%s+0x%04x", s_allreg32[op], imm ); + break; + + case 0x02: + sprintf( buf, "unknown" ); + break; + + case 0x03: + switch( imm ) + { + case 0x03: + op = oprom[ pos++ ]; + op1 = oprom[ pos++ ]; + sprintf( buf, "%s+%s", s_allreg32[op], s_allreg8[op1] ); + break; + + case 0x07: + op = oprom[ pos++ ]; + op1 = oprom[ pos++ ]; + sprintf( buf, "%s+%s", s_allreg32[op], s_allreg16[op1] ); + break; + + case 0x13: + imm = oprom[ pos++ ]; + imm = imm | ( oprom[ pos++ ] << 8 ); + sprintf( buf, "0x%06x", pc + pos + (INT16)imm ); + break; + } + break; + } + break; + + case 0x04: /* 0xF4 */ + imm = oprom[ pos++ ]; + sprintf( buf, "-%s", s_allreg32[imm] ); + break; + + case 0x05: /* 0xF5 */ + imm = oprom[ pos++ ]; + sprintf( buf, "%s+", s_allreg32[imm] ); + break; + } + op = oprom[ pos++ ]; + dasm = &mnemonic_f0[ op ]; + break; + } + + dst += sprintf( dst, "%s", s_mnemonic[ dasm->mnemonic ] ); + + switch( dasm->mnemonic ) + { + default: + /* maybe assert */ + break; + case M_CALL: + case M_CALR: + flags = DASMFLAG_STEP_OVER; + break; + case M_RET: + case M_RETD: + case M_RETI: + flags = DASMFLAG_STEP_OUT; + break; + } + + switch( dasm->operand1 ) + { + case O_NONE: + break; + + case O_A: + dst += sprintf( dst, " A" ); + break; + + case O_C8: + dst += sprintf( dst, " %s", s_reg8[op & 0x07] ); + break; + + case O_C16: + dst += sprintf( dst, " %s", s_reg16[op & 0x07] ); + break; + + case O_C32: + dst += sprintf( dst, " %s", s_reg32[op & 0x07] ); + break; + + case O_MC16: + dst += sprintf( dst, " %s", s_mulreg16[op & 0x07] ); + break; + + case O_CC: + dst += sprintf( dst, " %s", s_cond[op & 0x0F] ); + break; + + case O_CR8: + imm = oprom[ pos++ ]; + switch( imm ) + { + case 0x22: + dst += sprintf( dst, " DMAM0" ); + break; + case 0x26: + dst += sprintf( dst, " DMAM1" ); + break; + case 0x2a: + dst += sprintf( dst, " DMAM2" ); + break; + case 0x2e: + dst += sprintf( dst, " DMAM3" ); + break; + default: + dst += sprintf( dst, " unknown" ); + break; + } + break; + + case O_CR16: + imm = oprom[ pos++ ]; + switch( imm ) + { + case 0x20: + dst += sprintf( dst, " DMAC0" ); + break; + case 0x24: + dst += sprintf( dst, " DMAC1" ); + break; + case 0x28: + dst += sprintf( dst, " DMAC2" ); + break; + case 0x2c: + dst += sprintf( dst, " DMAC3" ); + break; + default: + dst += sprintf( dst, " unknown" ); + break; + } + break; + + case O_CR32: + imm = oprom[ pos++ ]; + switch( imm ) + { + case 0x00: + dst += sprintf( dst, " DMAS0" ); + break; + case 0x04: + dst += sprintf( dst, " DMAS1" ); + break; + case 0x08: + dst += sprintf( dst, " DMAS2" ); + break; + case 0x0c: + dst += sprintf( dst, " DMAS3" ); + break; + case 0x10: + dst += sprintf( dst, " DMAD0" ); + break; + case 0x14: + dst += sprintf( dst, " DMAD1" ); + break; + case 0x18: + dst += sprintf( dst, " DMAD2" ); + break; + case 0x1c: + dst += sprintf( dst, " DMAD3" ); + break; + default: + dst += sprintf( dst, " unknown" ); + break; + } + break; + + case O_D8: + imm = oprom[ pos++ ]; + dst += sprintf( dst, " 0x%06x", ( pc + pos + (INT8)imm ) & 0xFFFFFF ); + break; + + case O_D16: + imm = oprom[ pos++ ]; + imm = imm | ( oprom[ pos++ ] << 8 ); + dst += sprintf( dst, " 0x%06x", ( pc + pos + (INT16)imm ) & 0xFFFFFF ); + break; + + case O_F: + dst += sprintf( dst, " F" ); + break; + + case O_I3: + dst += sprintf( dst, " %d", op & 0x07 ); + break; + + case O_I8: + imm = oprom[ pos++ ]; + dst += sprintf( dst, " 0x%02x", imm ); + break; + + case O_I16: + imm = oprom[ pos++ ]; + imm = imm | ( oprom[ pos++ ] << 8 ); + dst += sprintf( dst, " 0x%04x", imm ); + break; + + case O_I24: + imm = oprom[ pos++ ]; + imm = imm | ( oprom[ pos++ ] << 8 ); + imm = imm | ( oprom[ pos++ ] << 16 ); + dst += sprintf( dst, " 0x%06x", imm ); + break; + + case O_I32: + imm = oprom[ pos++ ]; + imm = imm | ( oprom[ pos++ ] << 8 ); + imm = imm | ( oprom[ pos++ ] << 16 ); + imm = imm | ( oprom[ pos++ ] << 24 ); + dst += sprintf( dst, "0x%08x", imm ); + break; + + case O_M: + switch( dasm->mnemonic ) + { + case M_CALL: + case M_JP: + case M_LDA: + dst += sprintf( dst, " %s", buf ); + break; + default: + dst += sprintf( dst, " (%s)", buf ); + break; + } + break; + + case O_M8: + imm = oprom[ pos++ ]; + dst += sprintf( dst, " (0x%02x)", imm ); + break; + + case O_M16: + imm = oprom[ pos++ ]; + imm = imm | ( oprom[ pos++ ] << 8 ); + dst += sprintf( dst, " (0x%04x)", imm ); + break; + + case O_R: + dst += sprintf( dst, " %s", buf ); + break; + + case O_SR: + dst += sprintf( dst, " SR" ); + break; + } + + switch( dasm->operand2 ) + { + case O_NONE: + break; + + case O_A: + dst += sprintf( dst, ",A" ); + break; + + case O_C8: + dst += sprintf( dst, ",%s", s_reg8[op & 0x07] ); + break; + + case O_C16: + dst += sprintf( dst, ",%s", s_reg16[op & 0x07] ); + break; + + case O_C32: + dst += sprintf( dst, ",%s", s_reg32[op & 0x07] ); + break; + + case O_MC16: + dst += sprintf( dst, ",%s", s_mulreg16[op & 0x07] ); + break; + + case O_CC: + dst += sprintf( dst, ",%s", s_cond[op & 0x0F] ); + break; + + case O_CR8: + imm = oprom[ pos++ ]; + switch( imm ) + { + case 0x22: + dst += sprintf( dst, ",DMAM0" ); + break; + case 0x26: + dst += sprintf( dst, ",DMAM1" ); + break; + case 0x2a: + dst += sprintf( dst, ",DMAM2" ); + break; + case 0x2e: + dst += sprintf( dst, ",DMAM3" ); + break; + default: + dst += sprintf( dst, ",unknown" ); + break; + } + break; + + case O_CR16: + imm = oprom[ pos++ ]; + switch( imm ) + { + case 0x20: + dst += sprintf( dst, ",DMAC0" ); + break; + case 0x24: + dst += sprintf( dst, ",DMAC1" ); + break; + case 0x28: + dst += sprintf( dst, ",DMAC2" ); + break; + case 0x2c: + dst += sprintf( dst, ",DMAC3" ); + break; + default: + dst += sprintf( dst, ",unknown" ); + break; + } + break; + + case O_CR32: + imm = oprom[ pos++ ]; + switch( imm ) + { + case 0x00: + dst += sprintf( dst, ",DMAS0" ); + break; + case 0x04: + dst += sprintf( dst, ",DMAS1" ); + break; + case 0x08: + dst += sprintf( dst, ",DMAS2" ); + break; + case 0x0c: + dst += sprintf( dst, ",DMAS3" ); + break; + case 0x10: + dst += sprintf( dst, ",DMAD0" ); + break; + case 0x14: + dst += sprintf( dst, ",DMAD1" ); + break; + case 0x18: + dst += sprintf( dst, ",DMAD2" ); + break; + case 0x1c: + dst += sprintf( dst, ",DMAD3" ); + break; + default: + dst += sprintf( dst, ",unknown" ); + break; + } + break; + + case O_D8: + imm = oprom[ pos++ ]; + dst += sprintf( dst, ",0x%06x", ( pc + pos + (INT8)imm ) & 0xFFFFFF ); + break; + + case O_D16: + imm = oprom[ pos++ ]; + imm = imm | ( oprom[ pos++ ] << 8 ); + dst += sprintf( dst, ",0x%06x", ( pc + pos + (INT16)imm ) & 0xFFFFFF ); + break; + + case O_F: + dst += sprintf( dst, ",F'" ); + break; + + case O_I3: + dst += sprintf( dst, ",%d", op & 0x07 ); + break; + + case O_I8: + imm = oprom[ pos++ ]; + dst += sprintf( dst, ",0x%02x", imm ); + break; + + case O_I16: + imm = oprom[ pos++ ]; + imm = imm | ( oprom[ pos++ ] << 8 ); + dst += sprintf( dst, ",0x%04x", imm ); + break; + + case O_I24: + imm = oprom[ pos++ ]; + imm = imm | ( oprom[ pos++ ] << 8 ); + imm = imm | ( oprom[ pos++ ] << 16 ); + dst += sprintf( dst, ",0x%06x", imm ); + break; + + case O_I32: + imm = oprom[ pos++ ]; + imm = imm | ( oprom[ pos++ ] << 8 ); + imm = imm | ( oprom[ pos++ ] << 16 ); + imm = imm | ( oprom[ pos++ ] << 24 ); + dst += sprintf( dst, ",0x%08x", imm ); + break; + + case O_M: + switch( dasm->mnemonic ) + { + case M_CALL: + case M_JP: + case M_LDA: + dst += sprintf( dst, ",%s", buf ); + break; + default: + dst += sprintf( dst, ",(%s)", buf ); + break; + } + break; + + case O_M8: + imm = oprom[ pos++ ]; + dst += sprintf( dst, ",(0x%02x)", imm ); + break; + + case O_M16: + imm = oprom[ pos++ ]; + imm = imm | ( oprom[ pos++ ] << 8 ); + dst += sprintf( dst, ",(0x%04x)", imm ); + break; + + case O_R: + dst += sprintf( dst, ",%s", buf ); + break; + + case O_SR: + dst += sprintf( dst, ",SR" ); + break; + } + + return pos | flags | DASMFLAG_SUPPORTED; +} diff --git a/src/devices/cpu/tlcs900/tlcs900.c b/src/devices/cpu/tlcs900/tlcs900.c new file mode 100644 index 00000000000..c11dc9c08a9 --- /dev/null +++ b/src/devices/cpu/tlcs900/tlcs900.c @@ -0,0 +1,2202 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +/******************************************************************* + +Toshiba TLCS-900/H emulation + +This code only supports the 900/H mode which is needed for Neogeo +Pocket emulation. The 900 and 900/M modes are not supported yet. + + +TODO: +- review cycle counts +- implement the remaining internal mcu features (serial transfer, etc) +- add support for 900 and 900/M modes + +*******************************************************************/ + +#include "emu.h" +#include "debugger.h" +#include "tlcs900.h" + + +const device_type TMP95C061 = &device_creator; +const device_type TMP95C063 = &device_creator; + + +static ADDRESS_MAP_START( tmp95c061_mem8, AS_PROGRAM, 8, tmp95c061_device ) + AM_RANGE( 0x000000, 0x00007f ) AM_READWRITE( internal_r, internal_w ) +ADDRESS_MAP_END + +static ADDRESS_MAP_START( tmp95c061_mem16, AS_PROGRAM, 16, tmp95c061_device ) + AM_RANGE( 0x000000, 0x00007f ) AM_READWRITE8( internal_r, internal_w, 0xffff ) +ADDRESS_MAP_END + + +static ADDRESS_MAP_START(tmp95c063_mem8, AS_PROGRAM, 8, tmp95c063_device ) + AM_RANGE( 0x000000, 0x00009f ) AM_READWRITE( internal_r, internal_w ) +ADDRESS_MAP_END + +static ADDRESS_MAP_START(tmp95c063_mem16, AS_PROGRAM, 16, tmp95c063_device ) + AM_RANGE( 0x000000, 0x00009f ) AM_READWRITE8( internal_r, internal_w, 0xffff ) +ADDRESS_MAP_END + + +tlcs900h_device::tlcs900h_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname) + : cpu_device(mconfig, type, name, tag, owner, clock, shortname, __FILE__), + m_am8_16(0) +{ +} + +tmp95c061_device::tmp95c061_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : tlcs900h_device(mconfig, TMP95C061, "TMP95C061", tag, owner, clock, "tmp95c061" ), + m_port1_read(*this), + m_port1_write(*this), + m_port2_write(*this), + m_port5_read(*this), + m_port5_write(*this), + m_port6_read(*this), + m_port6_write(*this), + m_port7_read(*this), + m_port7_write(*this), + m_port8_read(*this), + m_port8_write(*this), + m_port9_read(*this), + m_porta_read(*this), + m_porta_write(*this), + m_portb_read(*this), + m_portb_write(*this) +{ +} + +//------------------------------------------------- +// device_config_complete - perform any +// operations now that the configuration is +// complete +//------------------------------------------------- + +void tmp95c061_device::device_config_complete() +{ + if (m_am8_16 == 0) + { + m_program_config = address_space_config("program", ENDIANNESS_LITTLE, 16, 24, 0, ADDRESS_MAP_NAME(tmp95c061_mem16)); + } + else + { + m_program_config = address_space_config("program", ENDIANNESS_LITTLE, 8, 24, 0, ADDRESS_MAP_NAME(tmp95c061_mem8)); + } +} + +tmp95c063_device::tmp95c063_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : tlcs900h_device(mconfig, TMP95C063, "TMP95C063", tag, owner, clock, "tmp95c063"), + m_port1_read(*this), + m_port1_write(*this), + m_port2_write(*this), + m_port5_read(*this), + m_port5_write(*this), + m_port6_read(*this), + m_port6_write(*this), + m_port7_read(*this), + m_port7_write(*this), + m_port8_read(*this), + m_port8_write(*this), + m_port9_read(*this), + m_port9_write(*this), + m_porta_read(*this), + m_porta_write(*this), + m_portb_read(*this), + m_portb_write(*this), + m_portc_read(*this), + m_portd_read(*this), + m_portd_write(*this), + m_porte_read(*this), + m_porte_write(*this) +{ +} + +//------------------------------------------------- +// device_config_complete - perform any +// operations now that the configuration is +// complete +//------------------------------------------------- + +void tmp95c063_device::device_config_complete() +{ + if (m_am8_16 == 0) + { + m_program_config = address_space_config("program", ENDIANNESS_LITTLE, 16, 24, 0, ADDRESS_MAP_NAME(tmp95c063_mem16)); + } + else + { + m_program_config = address_space_config("program", ENDIANNESS_LITTLE, 8, 24, 0, ADDRESS_MAP_NAME(tmp95c063_mem8)); + } +} + + +offs_t tlcs900h_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( tlcs900 ); + return CPU_DISASSEMBLE_NAME(tlcs900)(this, buffer, pc, oprom, opram, options); +} + + + +/* Internal register defines */ +#define TMP95C061_P1 0x01 +#define TMP95C061_P1CR 0x02 +#define TMP95C061_P2 0x06 +#define TMP95C061_P2FC 0x09 +#define TMP95C061_P5 0x0d +#define TMP95C061_P5CR 0x10 +#define TMP95C061_P5FC 0x11 +#define TMP95C061_P6 0x12 +#define TMP95C061_P7 0x13 +#define TMP95C061_P6FC 0x15 +#define TMP95C061_P7CR 0x16 +#define TMP95C061_P7FC 0x17 +#define TMP95C061_P8 0x18 +#define TMP95C061_P9 0x19 +#define TMP95C061_P8CR 0x1a +#define TMP95C061_P8FC 0x1b +#define TMP95C061_PA 0x1e +#define TMP95C061_PB 0x1f +#define TMP95C061_TRUN 0x20 +#define TMP95C061_TREG0 0x22 +#define TMP95C061_TREG1 0x23 +#define TMP95C061_T01MOD 0x24 +#define TMP95C061_TFFCR 0x25 +#define TMP95C061_TREG2 0x26 +#define TMP95C061_TREG3 0x27 +#define TMP95C061_T23MOD 0x28 +#define TMP95C061_TRDC 0x29 +#define TMP95C061_PACR 0x2c +#define TMP95C061_PAFC 0x2d +#define TMP95C061_PBCR 0x2e +#define TMP95C061_PBFC 0x2f +#define TMP95C061_TREG4L 0x30 +#define TMP95C061_TREG4H 0x31 +#define TMP95C061_TREG5L 0x32 +#define TMP95C061_TREG5H 0x33 +#define TMP95C061_CAP1L 0x34 +#define TMP95C061_CAP1H 0x35 +#define TMP95C061_CAP2L 0x36 +#define TMP95C061_CAP2H 0x37 +#define TMP95C061_T4MOD 0x38 +#define TMP95C061_T4FFCR 0x39 +#define TMP95C061_T45CR 0x3a +#define TMP95C061_MSAR0 0x3c +#define TMP95C061_MAMR0 0x3d +#define TMP95C061_MSAR1 0x3e +#define TMP95C061_MAMR1 0x3f +#define TMP95C061_TREG6L 0x40 +#define TMP95C061_TREG6H 0x41 +#define TMP95C061_TREG7L 0x42 +#define TMP95C061_TREG7H 0x43 +#define TMP95C061_CAP3L 0x44 +#define TMP95C061_CAP3H 0x45 +#define TMP95C061_CAP4L 0x46 +#define TMP95C061_CAP4H 0x47 +#define TMP95C061_T5MOD 0x48 +#define TMP95C061_T5FFCR 0x49 +#define TMP95C061_PG0REG 0x4c +#define TMP95C061_PG1REG 0x4d +#define TMP95C061_PG01CR 0x4e +#define TMP95C061_SC0BUF 0x50 +#define TMP95C061_SC0CR 0x51 +#define TMP95C061_SC0MOD 0x52 +#define TMP95C061_BR0CR 0x53 +#define TMP95C061_SC1BUF 0x54 +#define TMP95C061_SC1CR 0x55 +#define TMP95C061_SC1MOD 0x56 +#define TMP95C061_BR1CR 0x57 +#define TMP95C061_ODE 0x58 +#define TMP95C061_DREFCR 0x5a +#define TMP95C061_DMEMCR 0x5b +#define TMP95C061_MSAR2 0x5c +#define TMP95C061_MAMR2 0x5d +#define TMP95C061_MSAR3 0x5e +#define TMP95C061_MAMR3 0x5f +#define TMP95C061_ADREG0L 0x60 +#define TMP95C061_ADREG0H 0x61 +#define TMP95C061_ADREG1L 0x62 +#define TMP95C061_ADREG1H 0x63 +#define TMP95C061_ADREG2L 0x64 +#define TMP95C061_ADREG2H 0x65 +#define TMP95C061_ADREG3L 0x66 +#define TMP95C061_ADREG3H 0x67 +#define TMP95C061_B0CS 0x68 +#define TMP95C061_B1CS 0x69 +#define TMP95C061_B2CS 0x6a +#define TMP95C061_B3CS 0x6b +#define TMP95C061_BEXCS 0x6c +#define TMP95C061_ADMOD 0x6d +#define TMP95C061_WDMOD 0x6e +#define TMP95C061_WDCR 0x6f +#define TMP95C061_INTE0AD 0x70 +#define TMP95C061_INTE45 0x71 +#define TMP95C061_INTE67 0x72 +#define TMP95C061_INTET10 0x73 +#define TMP95C061_INTET32 0x74 +#define TMP95C061_INTET54 0x75 +#define TMP95C061_INTET76 0x76 +#define TMP95C061_INTES0 0x77 +#define TMP95C061_INTES1 0x78 +#define TMP95C061_INTETC10 0x79 +#define TMP95C061_INTETC32 0x7a +#define TMP95C061_IIMC 0x7b +#define TMP95C061_DMA0V 0x7c +#define TMP95C061_DMA1V 0x7d +#define TMP95C061_DMA2V 0x7e +#define TMP95C061_DMA3V 0x7f + + +/* Flag defines */ +#define FLAG_CF 0x01 +#define FLAG_NF 0x02 +#define FLAG_VF 0x04 +#define FLAG_HF 0x10 +#define FLAG_ZF 0x40 +#define FLAG_SF 0x80 + + +inline UINT8 tlcs900h_device::RDOP() +{ + UINT8 data; + + if ( m_prefetch_clear ) + { + for ( int i = 0; i < 4; i++ ) + { + m_prefetch[ i ] = RDMEM( m_pc.d + i ); + } + m_prefetch_index = 0; + m_prefetch_clear = false; + } + else + { + m_prefetch[ m_prefetch_index ] = RDMEM( m_pc.d + 3 ); + m_prefetch_index = ( m_prefetch_index + 1 ) & 0x03; + } + data = m_prefetch[ m_prefetch_index ]; + m_pc.d++; + return data; +} + + +void tlcs900h_device::device_start() +{ + m_program = &space( AS_PROGRAM ); + + m_pc.d = 0; + memset(m_xwa, 0x00, sizeof(m_xwa)); + memset(m_xbc, 0x00, sizeof(m_xbc)); + memset(m_xde, 0x00, sizeof(m_xde)); + memset(m_xhl, 0x00, sizeof(m_xhl)); + m_xix.d = 0; + m_xiy.d = 0; + m_xiz.d = 0; + m_xnsp.d = 0; + m_xssp.d = 0; + memset(m_dmas, 0x00, sizeof(m_dmas)); + memset(m_dmad, 0x00, sizeof(m_dmad)); + memset(m_dmac, 0x00, sizeof(m_dmac)); + memset(m_dmam, 0x00, sizeof(m_dmam)); + + save_item( NAME(m_xwa) ); + save_item( NAME(m_xbc) ); + save_item( NAME(m_xde) ); + save_item( NAME(m_xhl) ); + save_item( NAME(m_xix) ); + save_item( NAME(m_xiy) ); + save_item( NAME(m_xiz) ); + save_item( NAME(m_xssp) ); + save_item( NAME(m_xnsp) ); + save_item( NAME(m_pc) ); + save_item( NAME(m_sr) ); + save_item( NAME(m_f2) ); + save_item( NAME(m_dmas) ); + save_item( NAME(m_dmad) ); + save_item( NAME(m_dmac) ); + save_item( NAME(m_dmam) ); + save_item( NAME(m_reg) ); + save_item( NAME(m_timer_pre) ); + save_item( NAME(m_timer) ); + save_item( NAME(m_timer_change) ); + save_item( NAME(m_level) ); + save_item( NAME(m_check_irqs) ); + save_item( NAME(m_ad_cycles_left) ); + save_item( NAME(m_nmi_state) ); + save_item( NAME(m_prefetch_clear) ); + save_item( NAME(m_prefetch_index) ); + save_item( NAME(m_prefetch) ); + + state_add( TLCS900_PC, "PC", m_pc.d ).formatstr("%08X"); + state_add( TLCS900_XWA0, "XWA0", m_xwa[0].d ).formatstr("%08X"); + state_add( TLCS900_XBC0, "XBC0", m_xbc[0].d ).formatstr("%08X"); + state_add( TLCS900_XDE0, "XDE0", m_xde[0].d ).formatstr("%08X"); + state_add( TLCS900_XHL0, "XHL0", m_xhl[0].d ).formatstr("%08X"); + state_add( TLCS900_XWA1, "XWA1", m_xwa[1].d ).formatstr("%08X"); + state_add( TLCS900_XBC1, "XBC1", m_xbc[1].d ).formatstr("%08X"); + state_add( TLCS900_XDE1, "XDE1", m_xde[1].d ).formatstr("%08X"); + state_add( TLCS900_XHL1, "XHL1", m_xhl[1].d ).formatstr("%08X"); + state_add( TLCS900_XWA2, "XWA2", m_xwa[2].d ).formatstr("%08X"); + state_add( TLCS900_XBC2, "XBC2", m_xbc[2].d ).formatstr("%08X"); + state_add( TLCS900_XDE2, "XDE2", m_xde[2].d ).formatstr("%08X"); + state_add( TLCS900_XHL2, "XHL2", m_xhl[2].d ).formatstr("%08X"); + state_add( TLCS900_XWA3, "XWA3", m_xwa[3].d ).formatstr("%08X"); + state_add( TLCS900_XBC3, "XBC3", m_xbc[3].d ).formatstr("%08X"); + state_add( TLCS900_XDE3, "XDE3", m_xde[3].d ).formatstr("%08X"); + state_add( TLCS900_XHL3, "XHL3", m_xhl[3].d ).formatstr("%08X"); + state_add( TLCS900_XIX, "XIX", m_xix.d ).formatstr("%08X"); + state_add( TLCS900_XIY, "XIY", m_xiy.d ).formatstr("%08X"); + state_add( TLCS900_XIZ, "XIZ", m_xiz.d ).formatstr("%08X"); + state_add( TLCS900_XNSP, "XNSP", m_xnsp.d ).formatstr("%08X"); + state_add( TLCS900_XSSP, "XSSP", m_xssp.d ).formatstr("%08X"); + state_add( TLCS900_DMAS0, "DMAS0", m_dmas[0].d ).formatstr("%08X"); + state_add( TLCS900_DMAD0, "DMAD0", m_dmad[0].d ).formatstr("%08X"); + state_add( TLCS900_DMAC0, "DMAC0", m_dmac[0].w.l ).formatstr("%04X"); + state_add( TLCS900_DMAM0, "DMAM0", m_dmam[0].b.l ).formatstr("%02X"); + state_add( TLCS900_DMAS1, "DMAS0", m_dmas[1].d ).formatstr("%08X"); + state_add( TLCS900_DMAD1, "DMAD0", m_dmad[1].d ).formatstr("%08X"); + state_add( TLCS900_DMAC1, "DMAC0", m_dmac[1].w.l ).formatstr("%04X"); + state_add( TLCS900_DMAM1, "DMAM0", m_dmam[1].b.l ).formatstr("%02X"); + state_add( TLCS900_DMAS2, "DMAS0", m_dmas[2].d ).formatstr("%08X"); + state_add( TLCS900_DMAD2, "DMAD0", m_dmad[2].d ).formatstr("%08X"); + state_add( TLCS900_DMAC2, "DMAC0", m_dmac[2].w.l ).formatstr("%04X"); + state_add( TLCS900_DMAM2, "DMAM0", m_dmam[2].b.l ).formatstr("%02X"); + state_add( TLCS900_DMAS3, "DMAS0", m_dmas[3].d ).formatstr("%08X"); + state_add( TLCS900_DMAD3, "DMAD0", m_dmad[3].d ).formatstr("%08X"); + state_add( TLCS900_DMAC3, "DMAC0", m_dmac[3].w.l ).formatstr("%04X"); + state_add( TLCS900_DMAM3, "DMAM0", m_dmam[3].b.l ).formatstr("%02X"); + + state_add( STATE_GENPC, "GENPC", m_pc.d ).noshow(); + state_add( STATE_GENFLAGS, "GENFLAGS", m_sr.w.l ).formatstr("%12s").noshow(); + + m_icountptr = &m_icount; +} + + +void tlcs900h_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + switch (entry.index()) + { + case STATE_GENFLAGS: + strprintf(str, "%c%d%c%d%c%c%c%c%c%c%c%c", + m_sr.w.l & 0x8000 ? 'S' : 'U', + ( m_sr.w.l & 0x7000 ) >> 12, + m_sr.w.l & 0x0800 ? 'M' : 'N', + ( m_sr.w.l & 0x0700 ) >> 8, + m_sr.w.l & 0x0080 ? 'S' : '.', + m_sr.w.l & 0x0040 ? 'Z' : '.', + m_sr.w.l & 0x0020 ? '1' : '.', + m_sr.w.l & 0x0010 ? 'H' : '.', + m_sr.w.l & 0x0008 ? '1' : '.', + m_sr.w.l & 0x0004 ? 'V' : '.', + m_sr.w.l & 0x0002 ? 'N' : '.', + m_sr.w.l & 0x0001 ? 'C' : '.' ); + break; + } +} + +void tmp95c061_device::device_start() +{ + tlcs900h_device::device_start(); + + save_item( NAME(m_to1) ); + save_item( NAME(m_to3) ); + + m_port1_read.resolve_safe(0); + m_port1_write.resolve_safe(); + m_port2_write.resolve_safe(); + m_port5_read.resolve_safe(0); + m_port5_write.resolve_safe(); + m_port6_read.resolve_safe(0); + m_port6_write.resolve_safe(); + m_port7_read.resolve_safe(0); + m_port7_write.resolve_safe(); + m_port8_read.resolve_safe(0); + m_port8_write.resolve_safe(); + m_port9_read.resolve_safe(0); + m_porta_read.resolve_safe(0); + m_porta_write.resolve_safe(); + m_portb_read.resolve_safe(0); + m_portb_write.resolve_safe(); +} + +void tmp95c061_device::device_reset() +{ + int i; + + m_to1 = 0; + m_to3 = 0; + + m_pc.b.l = RDMEM( 0xFFFF00 ); + m_pc.b.h = RDMEM( 0xFFFF01 ); + m_pc.b.h2 = RDMEM( 0xFFFF02 ); + m_pc.b.h3 = 0; + /* system mode, iff set to 111, max mode, register bank 0 */ + m_sr.d = 0xF800; + m_regbank = 0; + m_xssp.d = 0x0100; + m_halted = 0; + m_check_irqs = 0; + m_ad_cycles_left = 0; + m_nmi_state = CLEAR_LINE; + m_timer_pre = 0; + m_timer_change[0] = 0; + m_timer_change[1] = 0; + m_timer_change[2] = 0; + m_timer_change[3] = 0; + + memset(m_reg, 0x00, sizeof(m_reg)); + + m_reg[TMP95C061_P1] = 0x00; + m_reg[TMP95C061_P1CR] = 0x00; + m_reg[TMP95C061_P2] = 0xff; + m_reg[TMP95C061_P2FC] = 0x00; + m_reg[TMP95C061_P5] = 0x3d; + m_reg[TMP95C061_P5CR] = 0x00; + m_reg[TMP95C061_P5FC] = 0x00; + m_reg[TMP95C061_P6] = 0x3b; + m_reg[TMP95C061_P6FC] = 0x00; + m_reg[TMP95C061_P7] = 0xff; + m_reg[TMP95C061_P7CR] = 0x00; + m_reg[TMP95C061_P7FC] = 0x00; + m_reg[TMP95C061_P8] = 0x3f; + m_reg[TMP95C061_P8CR] = 0x00; + m_reg[TMP95C061_P8FC] = 0x00; + m_reg[TMP95C061_PA] = 0x0f; + m_reg[TMP95C061_PACR] = 0x0c; // HACK ngpc needs this but should be zero + m_reg[TMP95C061_PAFC] = 0x0c; // HACK ngpc needs this but should be zero + m_reg[TMP95C061_PB] = 0xff; + m_reg[TMP95C061_PBCR] = 0x00; + m_reg[TMP95C061_PBFC] = 0x00; + m_reg[TMP95C061_MSAR0] = 0xff; + m_reg[TMP95C061_MSAR1] = 0xff; + m_reg[TMP95C061_MSAR2] = 0xff; + m_reg[TMP95C061_MSAR3] = 0xff; + m_reg[TMP95C061_MAMR0] = 0xff; + m_reg[TMP95C061_MAMR1] = 0xff; + m_reg[TMP95C061_MAMR2] = 0xff; + m_reg[TMP95C061_MAMR3] = 0xff; + m_reg[TMP95C061_DREFCR] = 0x00; + m_reg[TMP95C061_DMEMCR] = 0x80; + m_reg[TMP95C061_T01MOD] = 0x00; + m_reg[TMP95C061_T23MOD] = 0x00; + m_reg[TMP95C061_TFFCR] = 0x00; + m_reg[TMP95C061_TRUN] = 0x00; + m_reg[TMP95C061_TRDC] = 0x00; + m_reg[TMP95C061_T4MOD] = 0x20; + m_reg[TMP95C061_T4FFCR] = 0x00; + m_reg[TMP95C061_T5MOD] = 0x20; + m_reg[TMP95C061_T5FFCR] = 0x00; + m_reg[TMP95C061_T45CR] = 0x00; + m_reg[TMP95C061_PG01CR] = 0x00; + m_reg[TMP95C061_PG0REG] = 0x00; + m_reg[TMP95C061_PG1REG] = 0x00; + m_reg[TMP95C061_SC0MOD] = 0x00; + m_reg[TMP95C061_SC0CR] = 0x00; + m_reg[TMP95C061_BR0CR] = 0x00; + m_reg[TMP95C061_SC1MOD] = 0x00; + m_reg[TMP95C061_SC1CR] = 0x00; + m_reg[TMP95C061_BR1CR] = 0x00; + m_reg[TMP95C061_P8FC] = 0x00; + m_reg[TMP95C061_ODE] = 0x00; + m_reg[TMP95C061_ADMOD] = 0x00; + m_reg[TMP95C061_ADREG0L] = 0x3f; + m_reg[TMP95C061_ADREG1L] = 0x3f; + m_reg[TMP95C061_ADREG2L] = 0x3f; + m_reg[TMP95C061_ADREG3L] = 0x3f; + m_reg[TMP95C061_WDMOD] = 0x80; + + for ( i = 0; i < TLCS900_NUM_INPUTS; i++ ) + { + m_level[i] = CLEAR_LINE; + } + m_prefetch_clear = true; +} + + +#include "900tbl.inc" + + +#define TMP95C061_NUM_MASKABLE_IRQS 22 +static const struct { + UINT8 reg; + UINT8 iff; + UINT8 vector; +} tmp95c061_irq_vector_map[TMP95C061_NUM_MASKABLE_IRQS] = +{ + { TMP95C061_INTETC32, 0x80, 0x80 }, /* INTTC3 */ + { TMP95C061_INTETC32, 0x08, 0x7c }, /* INTTC2 */ + { TMP95C061_INTETC10, 0x80, 0x78 }, /* INTTC1 */ + { TMP95C061_INTETC10, 0x08, 0x74 }, /* INTTC0 */ + { TMP95C061_INTE0AD, 0x80, 0x70 }, /* INTAD */ + { TMP95C061_INTES1, 0x80, 0x6c }, /* INTTX1 */ + { TMP95C061_INTES1, 0x08, 0x68 }, /* INTRX1 */ + { TMP95C061_INTES0, 0x80, 0x64 }, /* INTTX0 */ + { TMP95C061_INTES0, 0x08, 0x60 }, /* INTRX0 */ + { TMP95C061_INTET76, 0x80, 0x5c }, /* INTTR7 */ + { TMP95C061_INTET76, 0x08, 0x58 }, /* INTTR6 */ + { TMP95C061_INTET54, 0x80, 0x54 }, /* INTTR5 */ + { TMP95C061_INTET54, 0x08, 0x50 }, /* INTTR4 */ + { TMP95C061_INTET32, 0x80, 0x4c }, /* INTT3 */ + { TMP95C061_INTET32, 0x08, 0x48 }, /* INTT2 */ + { TMP95C061_INTET10, 0x80, 0x44 }, /* INTT1 */ + { TMP95C061_INTET10, 0x08, 0x40 }, /* INTT0 */ + /* 0x3c - reserved */ + { TMP95C061_INTE67, 0x80, 0x38 }, /* INT7 */ + { TMP95C061_INTE67, 0x08, 0x34 }, /* INT6 */ + { TMP95C061_INTE45, 0x80, 0x30 }, /* INT5 */ + { TMP95C061_INTE45, 0x08, 0x2c }, /* INT4 */ + { TMP95C061_INTE0AD, 0x08, 0x28 } /* INT0 */ +}; + + +int tmp95c061_device::tlcs900_process_hdma( int channel ) +{ + UINT8 vector = ( m_reg[0x7c + channel] & 0x1f ) << 2; + + /* Check if any HDMA actions should be performed */ + if ( vector >= 0x28 && vector != 0x3C && vector < 0x74 ) + { + int irq = 0; + + while( irq < TMP95C061_NUM_MASKABLE_IRQS && tmp95c061_irq_vector_map[irq].vector != vector ) + irq++; + + /* Check if our interrupt flip-flop is set */ + if ( irq < TMP95C061_NUM_MASKABLE_IRQS && m_reg[tmp95c061_irq_vector_map[irq].reg] & tmp95c061_irq_vector_map[irq].iff ) + { + switch( m_dmam[channel].b.l & 0x1f ) + { + case 0x00: + WRMEM( m_dmad[channel].d, RDMEM( m_dmas[channel].d ) ); + m_dmad[channel].d += 1; + m_cycles += 8; + break; + case 0x01: + WRMEMW( m_dmad[channel].d, RDMEMW( m_dmas[channel].d ) ); + m_dmad[channel].d += 2; + m_cycles += 8; + break; + case 0x02: + WRMEML( m_dmad[channel].d, RDMEML( m_dmas[channel].d ) ); + m_dmad[channel].d += 4; + m_cycles += 12; + break; + case 0x04: + WRMEM( m_dmad[channel].d, RDMEM( m_dmas[channel].d ) ); + m_dmad[channel].d -= 1; + m_cycles += 8; + break; + case 0x05: + WRMEMW( m_dmad[channel].d, RDMEMW( m_dmas[channel].d ) ); + m_dmad[channel].d -= 2; + m_cycles += 8; + break; + case 0x06: + WRMEML( m_dmad[channel].d, RDMEML( m_dmas[channel].d ) ); + m_dmad[channel].d -= 4; + m_cycles += 12; + break; + case 0x08: + WRMEM( m_dmad[channel].d, RDMEM( m_dmas[channel].d ) ); + m_dmas[channel].d += 1; + m_cycles += 8; + break; + case 0x09: + WRMEMW( m_dmad[channel].d, RDMEMW( m_dmas[channel].d ) ); + m_dmas[channel].d += 2; + m_cycles += 8; + break; + case 0x0a: + WRMEML( m_dmad[channel].d, RDMEML( m_dmas[channel].d ) ); + m_dmas[channel].d += 4; + m_cycles += 12; + break; + case 0x0c: + WRMEM( m_dmad[channel].d, RDMEMW( m_dmas[channel].d ) ); + m_dmas[channel].d -= 1; + m_cycles += 8; + break; + case 0x0d: + WRMEMW( m_dmad[channel].d, RDMEMW( m_dmas[channel].d ) ); + m_dmas[channel].d -= 2; + m_cycles += 8; + break; + case 0x0e: + WRMEML( m_dmad[channel].d, RDMEML( m_dmas[channel].d ) ); + m_dmas[channel].d -= 4; + m_cycles += 12; + break; + case 0x10: + WRMEM( m_dmad[channel].d, RDMEMW( m_dmas[channel].d ) ); + m_cycles += 8; + break; + case 0x11: + WRMEMW( m_dmad[channel].d, RDMEMW( m_dmas[channel].d ) ); + m_cycles += 8; + break; + case 0x12: + WRMEML( m_dmad[channel].d, RDMEML( m_dmas[channel].d ) ); + m_cycles += 12; + break; + case 0x14: + m_dmas[channel].d += 1; + m_cycles += 5; + break; + } + + m_dmac[channel].w.l -= 1; + + if ( m_dmac[channel].w.l == 0 ) + { + m_reg[0x7c + channel] = 0; + switch( channel ) + { + case 0: + m_reg[TMP95C061_INTETC10] |= 0x08; + break; + case 1: + m_reg[TMP95C061_INTETC10] |= 0x80; + break; + case 2: + m_reg[TMP95C061_INTETC32] |= 0x08; + break; + case 3: + m_reg[TMP95C061_INTETC32] |= 0x80; + break; + } + } + + /* Clear the interrupt flip-flop */ + m_reg[tmp95c061_irq_vector_map[irq].reg] &= ~tmp95c061_irq_vector_map[irq].iff; + + return 1; + } + } + return 0; +} + + +void tmp95c061_device::tlcs900_check_hdma() +{ + /* HDMA can only be performed if interrupts are allowed */ + if ( ( m_sr.b.h & 0x70 ) != 0x70 ) + { + if ( ! tlcs900_process_hdma( 0 ) ) + { + if ( ! tlcs900_process_hdma( 1 ) ) + { + if ( ! tlcs900_process_hdma( 2 ) ) + { + tlcs900_process_hdma( 3 ); + } + } + } + } +} + + +void tmp95c061_device::tlcs900_check_irqs() +{ + int irq_vectors[9] = { -1, -1, -1, -1, -1, -1, -1, -1, -1 }; + int level = 0; + int irq = -1; + int i; + + /* Check for NMI */ + if ( m_nmi_state == ASSERT_LINE ) + { + m_xssp.d -= 4; + WRMEML( m_xssp.d, m_pc.d ); + m_xssp.d -= 2; + WRMEMW( m_xssp.d, m_sr.w.l ); + m_pc.d = RDMEML( 0xffff00 + 0x20 ); + m_cycles += 18; + m_prefetch_clear = true; + + m_halted = 0; + + m_nmi_state = CLEAR_LINE; + + return; + } + + /* Check regular irqs */ + for( i = 0; i < TMP95C061_NUM_MASKABLE_IRQS; i++ ) + { + if ( m_reg[tmp95c061_irq_vector_map[i].reg] & tmp95c061_irq_vector_map[i].iff ) + { + switch( tmp95c061_irq_vector_map[i].iff ) + { + case 0x80: + irq_vectors[ ( m_reg[ tmp95c061_irq_vector_map[i].reg ] >> 4 ) & 0x07 ] = i; + break; + case 0x08: + irq_vectors[ m_reg[ tmp95c061_irq_vector_map[i].reg ] & 0x07 ] = i; + break; + } + } + } + + /* Check highest allowed priority irq */ + for ( i = MAX( 1, ( ( m_sr.b.h & 0x70 ) >> 4 ) ); i < 7; i++ ) + { + if ( irq_vectors[i] >= 0 ) + { + irq = irq_vectors[i]; + level = i + 1; + } + } + + /* Take irq */ + if ( irq >= 0 ) + { + UINT8 vector = tmp95c061_irq_vector_map[irq].vector; + + m_xssp.d -= 4; + WRMEML( m_xssp.d, m_pc.d ); + m_xssp.d -= 2; + WRMEMW( m_xssp.d, m_sr.w.l ); + + /* Mask off any lower priority interrupts */ + m_sr.b.h = ( m_sr.b.h & 0x8f ) | ( level << 4 ); + + m_pc.d = RDMEML( 0xffff00 + vector ); + m_cycles += 18; + m_prefetch_clear = true; + + m_halted = 0; + + /* Clear taken IRQ */ + m_reg[ tmp95c061_irq_vector_map[irq].reg ] &= ~ tmp95c061_irq_vector_map[irq].iff; + } +} + + +void tmp95c061_device::tlcs900_handle_ad() +{ + if ( m_ad_cycles_left > 0 ) + { + m_ad_cycles_left -= m_cycles; + if ( m_ad_cycles_left <= 0 ) + { + /* Store A/D converted value */ + switch( m_reg[TMP95C061_ADMOD] & 0x03 ) + { + case 0x00: /* AN0 */ + m_reg[TMP95C061_ADREG0L] |= 0xc0; + m_reg[TMP95C061_ADREG0H] = 0xff; + break; + case 0x01: /* AN1 */ + case 0x02: /* AN2 */ + case 0x03: /* AN3 */ + break; + } + + /* Clear BUSY flag, set END flag */ + m_reg[TMP95C061_ADMOD] &= ~ 0x40; + m_reg[TMP95C061_ADMOD] |= 0x80; + + m_reg[TMP95C061_INTE0AD] |= 0x80; + m_check_irqs = 1; + } + } +} + + +enum ff_change +{ + FF_CLEAR, + FF_SET, + FF_INVERT +}; + + +void tmp95c061_device::tlcs900_change_tff( int which, int change ) +{ + switch( which ) + { + case 1: + switch( change ) + { + case FF_CLEAR: + m_to1 = 0; + break; + case FF_SET: + m_to1 = 1; + break; + case FF_INVERT: + m_to1 ^= 1; + break; + } + break; + + case 3: + switch( change ) + { + case FF_CLEAR: + m_to3 = 0; + break; + case FF_SET: + m_to3 = 1; + break; + case FF_INVERT: + m_to3 ^= 1; + break; + } + break; + } + + update_porta(); +} + + +void tmp95c061_device::tlcs900_handle_timers() +{ + UINT32 old_pre = m_timer_pre; + + /* Is the pre-scaler active */ + if ( m_reg[TMP95C061_TRUN] & 0x80 ) + m_timer_pre += m_cycles; + + /* Timer 0 */ + if ( m_reg[TMP95C061_TRUN] & 0x01 ) + { + switch( m_reg[TMP95C061_T01MOD] & 0x03 ) + { + case 0x00: /* TIO */ + break; + case 0x01: /* T1 */ + m_timer_change[0] += ( m_timer_pre >> 7 ) - ( old_pre >> 7 ); + break; + case 0x02: /* T4 */ + m_timer_change[0] += ( m_timer_pre >> 9 ) - ( old_pre >> 9 ); + break; + case 0x03: /* T16 */ + m_timer_change[0] += ( m_timer_pre >> 11 ) - ( old_pre >> 11 ); + break; + } + + for( ; m_timer_change[0] > 0; m_timer_change[0]-- ) + { +//printf("timer0 = %02x, TREG0 = %02x\n", m_timer[0], m_reg[TREG0] ); + m_timer[0] += 1; + if ( m_timer[0] == m_reg[TMP95C061_TREG0] ) + { + if ( ( m_reg[TMP95C061_T01MOD] & 0x0c ) == 0x00 ) + { + m_timer_change[1] += 1; + } + + /* In 16bit timer mode the timer should not be reset */ + if ( ( m_reg[TMP95C061_T01MOD] & 0xc0 ) != 0x40 ) + { + m_timer[0] = 0; + m_reg[TMP95C061_INTET10] |= 0x08; + } + } + } + } + + /* Timer 1 */ + if ( m_reg[TMP95C061_TRUN] & 0x02 ) + { + switch( ( m_reg[TMP95C061_T01MOD] >> 2 ) & 0x03 ) + { + case 0x00: /* TO0TRG */ + break; + case 0x01: /* T1 */ + m_timer_change[1] += ( m_timer_pre >> 7 ) - ( old_pre >> 7 ); + break; + case 0x02: /* T16 */ + m_timer_change[1] += ( m_timer_pre >> 11 ) - ( old_pre >> 11 ); + break; + case 0x03: /* T256 */ + m_timer_change[1] += ( m_timer_pre >> 15 ) - ( old_pre >> 15 ); + break; + } + + for( ; m_timer_change[1] > 0; m_timer_change[1]-- ) + { + m_timer[1] += 1; + if ( m_timer[1] == m_reg[TMP95C061_TREG1] ) + { + m_timer[1] = 0; + m_reg[TMP95C061_INTET10] |= 0x80; + + if ( m_reg[TMP95C061_TFFCR] & 0x02 ) + { + tlcs900_change_tff( 1, FF_INVERT ); + } + + /* In 16bit timer mode also reset timer 0 */ + if ( ( m_reg[TMP95C061_T01MOD] & 0xc0 ) == 0x40 ) + { + m_timer[0] = 0; + } + } + } + } + + /* Timer 2 */ + if ( m_reg[TMP95C061_TRUN] & 0x04 ) + { + switch( m_reg[TMP95C061_T23MOD] & 0x03 ) + { + case 0x00: /* invalid */ + case 0x01: /* T1 */ + m_timer_change[2] += ( m_timer_pre >> 7 ) - ( old_pre >> 7 ); + break; + case 0x02: /* T4 */ + m_timer_change[2] += ( m_timer_pre >> 9 ) - ( old_pre >> 9 ); + break; + case 0x03: /* T16 */ + m_timer_change[2] += ( m_timer_pre >> 11 ) - ( old_pre >> 11 ); + break; + } + + for( ; m_timer_change[2] > 0; m_timer_change[2]-- ) + { + m_timer[2] += 1; + if ( m_timer[2] == m_reg[TMP95C061_TREG2] ) + { + if ( ( m_reg[TMP95C061_T23MOD] & 0x0c ) == 0x00 ) + { + m_timer_change[3] += 1; + } + + /* In 16bit timer mode the timer should not be reset */ + if ( ( m_reg[TMP95C061_T23MOD] & 0xc0 ) != 0x40 ) + { + m_timer[2] = 0; + m_reg[TMP95C061_INTET32] |= 0x08; + } + } + } + } + + /* Timer 3 */ + if ( m_reg[TMP95C061_TRUN] & 0x08 ) + { + switch( ( m_reg[TMP95C061_T23MOD] >> 2 ) & 0x03 ) + { + case 0x00: /* TO2TRG */ + break; + case 0x01: /* T1 */ + m_timer_change[3] += ( m_timer_pre >> 7 ) - ( old_pre >> 7 ); + break; + case 0x02: /* T16 */ + m_timer_change[3] += ( m_timer_pre >> 11 ) - ( old_pre >> 11 ); + break; + case 0x03: /* T256 */ + m_timer_change[3] += ( m_timer_pre >> 15 ) - ( old_pre >> 15 ); + break; + } + + for( ; m_timer_change[3] > 0; m_timer_change[3]-- ) + { + m_timer[3] += 1; + if ( m_timer[3] == m_reg[TMP95C061_TREG3] ) + { + m_timer[3] = 0; + m_reg[TMP95C061_INTET32] |= 0x80; + + if ( m_reg[TMP95C061_TFFCR] & 0x20 ) + { + tlcs900_change_tff( 3, FF_INVERT ); + } + + /* In 16bit timer mode also reset timer 2 */ + if ( ( m_reg[TMP95C061_T23MOD] & 0xc0 ) == 0x40 ) + { + m_timer[2] = 0; + } + } + } + } + + m_timer_pre &= 0xffffff; +} + + +void tlcs900h_device::execute_run() +{ + do + { + const tlcs900inst *inst; + + m_cycles = 0; + + if ( m_check_irqs ) + { + tlcs900_check_irqs(); + m_check_irqs = 0; + } + + debugger_instruction_hook( this, m_pc.d ); + + if ( m_halted ) + { + m_cycles += 8; + } + else + { + m_op = RDOP(); + inst = &s_mnemonic[m_op]; + prepare_operands( inst ); + + /* Execute the instruction */ + (this->*inst->opfunc)(); + m_cycles += inst->cycles; + } + + tlcs900_handle_ad(); + + tlcs900_handle_timers(); + + tlcs900_check_hdma(); + + m_icount -= m_cycles; + } while ( m_icount > 0 ); +} + + +void tmp95c061_device::execute_set_input(int input, int level) +{ + switch( input ) + { + case INPUT_LINE_NMI: + case TLCS900_NMI: + if ( m_level[TLCS900_NMI] == CLEAR_LINE && level == ASSERT_LINE ) + { + m_nmi_state = level; + } + m_level[TLCS900_NMI] = level; + break; + + case TLCS900_INTWD: + break; + + case TLCS900_INT0: + /* Is INT0 functionality enabled? */ + if ( m_reg[TMP95C061_IIMC] & 0x04 ) + { + if ( m_reg[TMP95C061_IIMC] & 0x02 ) + { + /* Rising edge detect */ + if ( m_level[TLCS900_INT0] == CLEAR_LINE && level == ASSERT_LINE ) + { + /* Leave HALT state */ + m_halted = 0; + m_reg[TMP95C061_INTE0AD] |= 0x08; + } + } + else + { + /* Level detect */ + if ( level == ASSERT_LINE ) + m_reg[TMP95C061_INTE0AD] |= 0x08; + else + m_reg[TMP95C061_INTE0AD] &= ~ 0x08; + } + } + m_level[TLCS900_INT0] = level; + break; + + case TLCS900_INT4: + if ( ! ( m_reg[TMP95C061_PBCR] & 0x01 ) ) + { + if ( m_level[TLCS900_INT4] == CLEAR_LINE && level == ASSERT_LINE ) + { + m_reg[TMP95C061_INTE45] |= 0x08; + } + } + m_level[TLCS900_INT4] = level; + break; + + case TLCS900_INT5: + if ( ! ( m_reg[TMP95C061_PBCR] & 0x02 ) ) + { + if ( m_level[TLCS900_INT5] == CLEAR_LINE && level == ASSERT_LINE ) + { + m_reg[TMP95C061_INTE45] |= 0x80; + } + } + m_level[TLCS900_INT5] = level; + break; + + case TLCS900_TIO: /* External timer input for timer 0 */ + if ( ( m_reg[TMP95C061_TRUN] & 0x01 ) && ( m_reg[TMP95C061_T01MOD] & 0x03 ) == 0x00 ) + { + if ( m_level[TLCS900_TIO] == CLEAR_LINE && level == ASSERT_LINE ) + { + m_timer_change[0] += 1; + } + } + m_level[TLCS900_TIO] = level; + break; + } + m_check_irqs = 1; +} + + +READ8_MEMBER( tmp95c061_device::internal_r ) +{ + switch (offset) + { + case TMP95C061_P1: m_reg[offset] = m_port1_read(0); break; + case TMP95C061_P5: m_reg[offset] = m_port5_read(0); break; + case TMP95C061_P6: m_reg[offset] = m_port6_read(0); break; + case TMP95C061_P7: m_reg[offset] = m_port7_read(0); break; + case TMP95C061_P8: m_reg[offset] = m_port8_read(0); break; + case TMP95C061_P9: m_reg[offset] = m_port9_read(0); break; + case TMP95C061_PA: m_reg[offset] = m_porta_read(0); break; + case TMP95C061_PB: m_reg[offset] = m_portb_read(0); break; + } + return m_reg[ offset ]; +} + + +void tmp95c061_device::update_porta() +{ + int fc = (m_to1 << 2) | (m_to3 << 3); + + m_porta_write(0, ((fc & m_reg[TMP95C061_PAFC]) | (m_reg[TMP95C061_PA] & ~m_reg[TMP95C061_PAFC])) & m_reg[TMP95C061_PACR], 0xff); +} + +WRITE8_MEMBER( tmp95c061_device::internal_w ) +{ + switch ( offset ) + { + case TMP95C061_TRUN: + if ( ! ( data & 0x01 ) ) + { + m_timer[0] = 0; + m_timer_change[0] = 0; + } + if ( ! ( data & 0x02 ) ) + { + m_timer[1] = 0; + m_timer_change[1] = 0; + } + if ( ! ( data & 0x04 ) ) + { + m_timer[2] = 0; + m_timer_change[2] = 0; + } + if ( ! ( data & 0x08 ) ) + { + m_timer[3] = 0; + m_timer_change[3] = 0; + } + if ( ! ( data & 0x10 ) ) + m_timer[4] = 0; + if ( ! ( data & 0x20 ) ) + m_timer[5] = 0; + break; + + case TMP95C061_TFFCR: + switch( data & 0x0c ) + { + case 0x00: + tlcs900_change_tff( 1, FF_INVERT ); + break; + case 0x04: + tlcs900_change_tff( 1, FF_SET ); + break; + case 0x08: + tlcs900_change_tff( 1, FF_CLEAR ); + break; + } + switch( data & 0xc0 ) + { + case 0x00: + tlcs900_change_tff( 3, FF_INVERT ); + break; + case 0x40: + tlcs900_change_tff( 3, FF_SET ); + break; + case 0x80: + tlcs900_change_tff( 3, FF_CLEAR ); + break; + } + break; + case TMP95C061_MSAR0: + case TMP95C061_MAMR0: + case TMP95C061_MSAR1: + case TMP95C061_MAMR1: + break; + + case TMP95C061_SC0BUF: + // Fake finish sending data + m_reg[TMP95C061_INTES0] |= 0x80; + break; + + case TMP95C061_ADMOD: + /* Preserve read-only bits */ + data = ( m_reg[TMP95C061_ADMOD] & 0xc0 ) | ( data & 0x3f ); + + /* Check for A/D request start */ + if ( data & 0x04 ) + { + data &= ~0x04; + data |= 0x40; + m_ad_cycles_left = ( data & 0x08 ) ? 640 : 320; + } + break; + + case TMP95C061_WDMOD: + case TMP95C061_WDCR: + break; + + case TMP95C061_INTE0AD: + case TMP95C061_INTE45: + case TMP95C061_INTE67: + case TMP95C061_INTET10: + case TMP95C061_INTET32: + case TMP95C061_INTET54: + case TMP95C061_INTET76: + case TMP95C061_INTES0: + case TMP95C061_INTES1: + case TMP95C061_INTETC10: + case TMP95C061_INTETC32: + if ( data & 0x80 ) + data = ( data & 0x7f ) | ( m_reg[offset] & 0x80 ); + if ( data & 0x08 ) + data = ( data & 0xf7 ) | ( m_reg[offset] & 0x08 ); + break; + + case TMP95C061_IIMC: + break; + + default: + break; + } + + m_check_irqs = 1; + m_reg[ offset ] = data; + + switch(offset) + { + case TMP95C061_P1: m_port1_write(0, data, 0xff); break; + case TMP95C061_P2: m_port2_write(0, data, 0xff); break; + case TMP95C061_P5: m_port5_write(0, data, 0xff); break; + case TMP95C061_P6: m_port6_write(0, data, 0xff); break; + case TMP95C061_P7: m_port7_write(0, data, 0xff); break; + case TMP95C061_P8: m_port8_write(0, data, 0xff); break; + + case TMP95C061_PA: + case TMP95C061_PACR: + case TMP95C061_PAFC: + update_porta(); + break; + } +} + + + +// Toshiba TMP95C063 + +/* TMP95C063 Internal register defines */ + +#define TMP95C063_P1 0x01 +#define TMP95C063_P1CR 0x04 +#define TMP95C063_P2 0x06 +#define TMP95C063_P2FC 0x09 +#define TMP95C063_P5 0x0d +#define TMP95C063_P5CR 0x10 +#define TMP95C063_P5FC 0x11 +#define TMP95C063_P6 0x12 +#define TMP95C063_P7 0x13 +#define TMP95C063_P6FC 0x15 +#define TMP95C063_P7CR 0x16 +#define TMP95C063_P7FC 0x17 +#define TMP95C063_P8 0x18 +#define TMP95C063_P9 0x19 +#define TMP95C063_P8CR 0x1a +#define TMP95C063_P8FC 0x1b +#define TMP95C063_P9CR 0x1c +#define TMP95C063_P9FC 0x1d +#define TMP95C063_PA 0x1e +#define TMP95C063_PB 0x1f +#define TMP95C063_T8RUN 0x20 +#define TMP95C063_TRDC 0x21 +#define TMP95C063_TREG0 0x22 +#define TMP95C063_TREG1 0x23 +#define TMP95C063_T01MOD 0x24 +#define TMP95C063_T02FFCR 0x25 +#define TMP95C063_TREG2 0x26 +#define TMP95C063_TREG3 0x27 +#define TMP95C063_T23MOD 0x28 +#define TMP95C063_TREG4 0x29 +#define TMP95C063_TREG5 0x2a +#define TMP95C063_T45MOD 0x2b +#define TMP95C063_T46FFCR 0x2c +#define TMP95C063_TREG6 0x2d +#define TMP95C063_TREG7 0x2e +#define TMP95C063_T67MOD 0x2f +#define TMP95C063_TREG8L 0x30 +#define TMP95C063_TREG8H 0x31 +#define TMP95C063_TREG9L 0x32 +#define TMP95C063_TREG9H 0x33 +#define TMP95C063_CAP1L 0x34 +#define TMP95C063_CAP1H 0x35 +#define TMP95C063_CAP2L 0x36 +#define TMP95C063_CAP2H 0x37 +#define TMP95C063_T8MOD 0x38 +#define TMP95C063_T8FFCR 0x39 +#define TMP95C063_T89CR 0x3a +#define TMP95C063_T16RUN 0x3b +#define TMP95C063_TREGAL 0x40 +#define TMP95C063_TREGAH 0x41 +#define TMP95C063_TREGBL 0x42 +#define TMP95C063_TREGBH 0x43 +#define TMP95C063_CAP3L 0x44 +#define TMP95C063_CAP3H 0x45 +#define TMP95C063_CAP4L 0x46 +#define TMP95C063_CAP4H 0x47 +#define TMP95C063_T9MOD 0x48 +#define TMP95C063_T9FFCR 0x49 +#define TMP95C063_DAREG0 0x4a +#define TMP95C063_DAREG1 0x4b +#define TMP95C063_PG0REG 0x4c +#define TMP95C063_PG1REG 0x4d +#define TMP95C063_PG01CR 0x4e +#define TMP95C063_DADRV 0x4f +#define TMP95C063_SC0BUF 0x50 +#define TMP95C063_SC0CR 0x51 +#define TMP95C063_SC0MOD 0x52 +#define TMP95C063_BR0CR 0x53 +#define TMP95C063_SC1BUF 0x54 +#define TMP95C063_SC1CR 0x55 +#define TMP95C063_SC1MOD 0x56 +#define TMP95C063_BR1CR 0x57 +#define TMP95C063_ODE 0x58 +#define TMP95C063_DMA0V 0x5a +#define TMP95C063_DMA1V 0x5b +#define TMP95C063_DMA2V 0x5c +#define TMP95C063_DMA3V 0x5d +#define TMP95C063_ADMOD1 0x5e +#define TMP95C063_ADMOD2 0x5f +#define TMP95C063_ADREG04L 0x60 +#define TMP95C063_ADREG04H 0x61 +#define TMP95C063_ADREG15L 0x62 +#define TMP95C063_ADREG15H 0x63 +#define TMP95C063_ADREG26L 0x64 +#define TMP95C063_ADREG26H 0x65 +#define TMP95C063_ADREG37L 0x66 +#define TMP95C063_ADREG37H 0x67 +#define TMP95C063_SDMACR0 0x6a +#define TMP95C063_SDMACR1 0x6b +#define TMP95C063_SDMACR2 0x6c +#define TMP95C063_SDMACR3 0x6d +#define TMP95C063_WDMOD 0x6e +#define TMP95C063_WDCR 0x6f +#define TMP95C063_INTE0AD 0x70 +#define TMP95C063_INTE12 0x71 +#define TMP95C063_INTE34 0x72 +#define TMP95C063_INTE56 0x73 +#define TMP95C063_INTE78 0x74 +#define TMP95C063_INTET01 0x75 +#define TMP95C063_INTET23 0x76 +#define TMP95C063_INTET45 0x77 +#define TMP95C063_INTET67 0x78 +#define TMP95C063_INTET89 0x79 +#define TMP95C063_INTETAB 0x7a +#define TMP95C063_INTES0 0x7b +#define TMP95C063_INTES1 0x7c +#define TMP95C063_INTETC01 0x7d +#define TMP95C063_INTETC23 0x7e +#define TMP95C063_IIMC 0x7f +#define TMP95C063_PACR 0x80 +#define TMP95C063_PAFC 0x81 +#define TMP95C063_PBCR 0x82 +#define TMP95C063_PBFC 0x83 +#define TMP95C063_PC 0x84 +#define TMP95C063_PD 0x85 +#define TMP95C063_PDCR 0x88 +#define TMP95C063_PE 0x8a +#define TMP95C063_PECR 0x8c +#define TMP95C063_BEXCS 0x8f +#define TMP95C063_B0CS 0x90 +#define TMP95C063_B1CS 0x91 +#define TMP95C063_B2CS 0x92 +#define TMP95C063_B3CS 0x93 +#define TMP95C063_MSAR0 0x94 +#define TMP95C063_MAMR0 0x95 +#define TMP95C063_MSAR1 0x96 +#define TMP95C063_MAMR1 0x97 +#define TMP95C063_MSAR2 0x98 +#define TMP95C063_MAMR2 0x99 +#define TMP95C063_MSAR3 0x9a +#define TMP95C063_MAMR3 0x9b +#define TMP95C063_DREFCR1 0x9c +#define TMP95C063_DMEMCR1 0x9d +#define TMP95C063_DREFCR3 0x9e +#define TMP95C063_DMEMCR3 0x9f + + +#define TMP95C063_NUM_MASKABLE_IRQS 30 +static const struct { + UINT8 reg; + UINT8 iff; + UINT8 vector; +} tmp95c063_irq_vector_map[TMP95C063_NUM_MASKABLE_IRQS] = +{ + { TMP95C063_INTETC23, 0x80, 0xa0 }, /* INTTC3 */ + { TMP95C063_INTETC23, 0x08, 0x9c }, /* INTTC2 */ + { TMP95C063_INTETC01, 0x80, 0x98 }, /* INTTC1 */ + { TMP95C063_INTETC01, 0x08, 0x94 }, /* INTTC0 */ + { TMP95C063_INTE0AD, 0x80, 0x90 }, /* INTAD */ + { TMP95C063_INTES1, 0x80, 0x8c }, /* INTTX1 */ + { TMP95C063_INTES1, 0x08, 0x88 }, /* INTRX1 */ + { TMP95C063_INTES0, 0x80, 0x84 }, /* INTTX0 */ + { TMP95C063_INTES0, 0x08, 0x80 }, /* INTRX0 */ + { TMP95C063_INTETAB, 0x80, 0x7c }, /* INTTRB */ + { TMP95C063_INTETAB, 0x08, 0x78 }, /* INTTRA */ + { TMP95C063_INTET89, 0x80, 0x74 }, /* INTTR9 */ + { TMP95C063_INTET89, 0x80, 0x70 }, /* INTTR8 */ + { TMP95C063_INTET67, 0x80, 0x6c }, /* INTT7 */ + { TMP95C063_INTET67, 0x08, 0x68 }, /* INTT6 */ + { TMP95C063_INTET45, 0x80, 0x64 }, /* INTT5 */ + { TMP95C063_INTET45, 0x08, 0x60 }, /* INTT4 */ + { TMP95C063_INTET23, 0x80, 0x5c }, /* INTT3 */ + { TMP95C063_INTET23, 0x08, 0x58 }, /* INTT2 */ + { TMP95C063_INTET01, 0x80, 0x54 }, /* INTT1 */ + { TMP95C063_INTET01, 0x08, 0x50 }, /* INTT0 */ + { TMP95C063_INTE78, 0x80, 0x4c }, /* INT8 */ + { TMP95C063_INTE78, 0x08, 0x48 }, /* INT7 */ + { TMP95C063_INTE56, 0x80, 0x44 }, /* INT6 */ + { TMP95C063_INTE56, 0x08, 0x40 }, /* INT5 */ + /* 0x3c - reserved */ + { TMP95C063_INTE34, 0x80, 0x38 }, /* INT4 */ + { TMP95C063_INTE34, 0x08, 0x34 }, /* INT3 */ + { TMP95C063_INTE12, 0x80, 0x30 }, /* INT2 */ + { TMP95C063_INTE12, 0x08, 0x2c }, /* INT1 */ + { TMP95C063_INTE0AD, 0x08, 0x28 } /* INT0 */ +}; + +void tmp95c063_device::tlcs900_handle_timers() +{ + // TODO: implement timers 4-7 + + UINT32 old_pre = m_timer_pre; + + /* Is the pre-scaler active */ + if ( m_reg[TMP95C063_T8RUN] & 0x80 ) + m_timer_pre += m_cycles; + + /* Timer 0 */ + if ( m_reg[TMP95C063_T8RUN] & 0x01 ) + { + switch( m_reg[TMP95C063_T01MOD] & 0x03 ) + { + case 0x00: /* TIO */ + break; + case 0x01: /* T1 */ + m_timer_change[0] += ( m_timer_pre >> 7 ) - ( old_pre >> 7 ); + break; + case 0x02: /* T4 */ + m_timer_change[0] += ( m_timer_pre >> 9 ) - ( old_pre >> 9 ); + break; + case 0x03: /* T16 */ + m_timer_change[0] += ( m_timer_pre >> 11 ) - ( old_pre >> 11 ); + break; + } + + for( ; m_timer_change[0] > 0; m_timer_change[0]-- ) + { +//printf("timer0 = %02x, TREG0 = %02x\n", m_timer[0], m_reg[TREG0] ); + m_timer[0] += 1; + if ( m_timer[0] == m_reg[TMP95C063_TREG0] ) + { + if ( ( m_reg[TMP95C063_T01MOD] & 0x0c ) == 0x00 ) + { + m_timer_change[1] += 1; + } + + /* In 16bit timer mode the timer should not be reset */ + if ( ( m_reg[TMP95C063_T01MOD] & 0xc0 ) != 0x40 ) + { + m_timer[0] = 0; + m_reg[TMP95C063_INTET01] |= 0x08; + } + } + } + } + + /* Timer 1 */ + if ( m_reg[TMP95C063_T8RUN] & 0x02 ) + { + switch( ( m_reg[TMP95C063_T01MOD] >> 2 ) & 0x03 ) + { + case 0x00: /* TO0TRG */ + break; + case 0x01: /* T1 */ + m_timer_change[1] += ( m_timer_pre >> 7 ) - ( old_pre >> 7 ); + break; + case 0x02: /* T16 */ + m_timer_change[1] += ( m_timer_pre >> 11 ) - ( old_pre >> 11 ); + break; + case 0x03: /* T256 */ + m_timer_change[1] += ( m_timer_pre >> 15 ) - ( old_pre >> 15 ); + break; + } + + for( ; m_timer_change[1] > 0; m_timer_change[1]-- ) + { + m_timer[1] += 1; + if ( m_timer[1] == m_reg[TMP95C063_TREG1] ) + { + m_timer[1] = 0; + m_reg[TMP95C063_INTET01] |= 0x80; + + if ( m_reg[TMP95C063_T02FFCR] & 0x02 ) + { + //tlcs900_change_tff( 1, FF_INVERT ); + } + + /* In 16bit timer mode also reset timer 0 */ + if ( ( m_reg[TMP95C063_T01MOD] & 0xc0 ) == 0x40 ) + { + m_timer[0] = 0; + } + } + } + } + + /* Timer 2 */ + if ( m_reg[TMP95C063_T8RUN] & 0x04 ) + { + switch( m_reg[TMP95C063_T23MOD] & 0x03 ) + { + case 0x00: /* invalid */ + case 0x01: /* T1 */ + m_timer_change[2] += ( m_timer_pre >> 7 ) - ( old_pre >> 7 ); + break; + case 0x02: /* T4 */ + m_timer_change[2] += ( m_timer_pre >> 9 ) - ( old_pre >> 9 ); + break; + case 0x03: /* T16 */ + m_timer_change[2] += ( m_timer_pre >> 11 ) - ( old_pre >> 11 ); + break; + } + + for( ; m_timer_change[2] > 0; m_timer_change[2]-- ) + { + m_timer[2] += 1; + if ( m_timer[2] == m_reg[TMP95C063_TREG2] ) + { + if ( ( m_reg[TMP95C063_T23MOD] & 0x0c ) == 0x00 ) + { + m_timer_change[3] += 1; + } + + /* In 16bit timer mode the timer should not be reset */ + if ( ( m_reg[TMP95C063_T23MOD] & 0xc0 ) != 0x40 ) + { + m_timer[2] = 0; + m_reg[TMP95C063_INTET23] |= 0x08; + } + } + } + } + + /* Timer 3 */ + if ( m_reg[TMP95C063_T8RUN] & 0x08 ) + { + switch( ( m_reg[TMP95C063_T23MOD] >> 2 ) & 0x03 ) + { + case 0x00: /* TO2TRG */ + break; + case 0x01: /* T1 */ + m_timer_change[3] += ( m_timer_pre >> 7 ) - ( old_pre >> 7 ); + break; + case 0x02: /* T16 */ + m_timer_change[3] += ( m_timer_pre >> 11 ) - ( old_pre >> 11 ); + break; + case 0x03: /* T256 */ + m_timer_change[3] += ( m_timer_pre >> 15 ) - ( old_pre >> 15 ); + break; + } + + for( ; m_timer_change[3] > 0; m_timer_change[3]-- ) + { + m_timer[3] += 1; + if ( m_timer[3] == m_reg[TMP95C061_TREG3] ) + { + m_timer[3] = 0; + m_reg[TMP95C063_INTET23] |= 0x80; + + if ( m_reg[TMP95C063_T02FFCR] & 0x20 ) + { + //tlcs900_change_tff( 3, FF_INVERT ); + } + + /* In 16bit timer mode also reset timer 2 */ + if ( ( m_reg[TMP95C063_T23MOD] & 0xc0 ) == 0x40 ) + { + m_timer[2] = 0; + } + } + } + } + + m_timer_pre &= 0xffffff; +} + +void tmp95c063_device::tlcs900_check_hdma() +{ + // TODO +} + +void tmp95c063_device::tlcs900_check_irqs() +{ + int irq_vectors[9] = { -1, -1, -1, -1, -1, -1, -1, -1, -1 }; + int level = 0; + int irq = -1; + int i; + + /* Check for NMI */ + if ( m_nmi_state == ASSERT_LINE ) + { + m_xssp.d -= 4; + WRMEML( m_xssp.d, m_pc.d ); + m_xssp.d -= 2; + WRMEMW( m_xssp.d, m_sr.w.l ); + m_pc.d = RDMEML( 0xffff00 + 0x20 ); + m_cycles += 18; + m_prefetch_clear = true; + + m_halted = 0; + + m_nmi_state = CLEAR_LINE; + + return; + } + + /* Check regular irqs */ + for( i = 0; i < TMP95C063_NUM_MASKABLE_IRQS; i++ ) + { + if ( m_reg[tmp95c063_irq_vector_map[i].reg] & tmp95c063_irq_vector_map[i].iff ) + { + switch( tmp95c063_irq_vector_map[i].iff ) + { + case 0x80: + irq_vectors[ ( m_reg[ tmp95c063_irq_vector_map[i].reg ] >> 4 ) & 0x07 ] = i; + break; + case 0x08: + irq_vectors[ m_reg[ tmp95c063_irq_vector_map[i].reg ] & 0x07 ] = i; + break; + } + } + } + + /* Check highest allowed priority irq */ + for ( i = MAX( 1, ( ( m_sr.b.h & 0x70 ) >> 4 ) ); i < 7; i++ ) + { + if ( irq_vectors[i] >= 0 ) + { + irq = irq_vectors[i]; + level = i + 1; + } + } + + /* Take irq */ + if ( irq >= 0 ) + { + UINT8 vector = tmp95c063_irq_vector_map[irq].vector; + + m_xssp.d -= 4; + WRMEML( m_xssp.d, m_pc.d ); + m_xssp.d -= 2; + WRMEMW( m_xssp.d, m_sr.w.l ); + + /* Mask off any lower priority interrupts */ + m_sr.b.h = ( m_sr.b.h & 0x8f ) | ( level << 4 ); + + m_pc.d = RDMEML( 0xffff00 + vector ); + m_cycles += 18; + m_prefetch_clear = true; + + m_halted = 0; + + /* Clear taken IRQ */ + m_reg[ tmp95c063_irq_vector_map[irq].reg ] &= ~ tmp95c063_irq_vector_map[irq].iff; + } +} + + +void tmp95c063_device::tlcs900_handle_ad() +{ + // TODO +} + + +void tmp95c063_device::device_start() +{ + tlcs900h_device::device_start(); + + m_port1_read.resolve_safe(0); + m_port1_write.resolve_safe(); + m_port2_write.resolve_safe(); + m_port5_read.resolve_safe(0); + m_port5_write.resolve_safe(); + m_port6_read.resolve_safe(0); + m_port6_write.resolve_safe(); + m_port7_read.resolve_safe(0); + m_port7_write.resolve_safe(); + m_port8_read.resolve_safe(0); + m_port8_write.resolve_safe(); + m_port9_read.resolve_safe(0); + m_port9_write.resolve_safe(); + m_porta_read.resolve_safe(0); + m_porta_write.resolve_safe(); + m_portb_read.resolve_safe(0); + m_portb_write.resolve_safe(); + m_portc_read.resolve_safe(0); + m_portd_read.resolve_safe(0); + m_portd_write.resolve_safe(); + m_porte_read.resolve_safe(0); + m_porte_write.resolve_safe(); +} + +void tmp95c063_device::device_reset() +{ + int i; + + m_pc.b.l = RDMEM( 0xFFFF00 ); + m_pc.b.h = RDMEM( 0xFFFF01 ); + m_pc.b.h2 = RDMEM( 0xFFFF02 ); + m_pc.b.h3 = 0; + /* system mode, iff set to 111, max mode, register bank 0 */ + m_sr.d = 0xF800; + m_regbank = 0; + m_xssp.d = 0x0100; + m_halted = 0; + m_check_irqs = 0; + m_ad_cycles_left = 0; + m_nmi_state = CLEAR_LINE; + m_timer_pre = 0; + m_timer_change[0] = 0; + m_timer_change[1] = 0; + m_timer_change[2] = 0; + m_timer_change[3] = 0; + + m_reg[TMP95C063_P1] = 0x00; + m_reg[TMP95C063_P1CR] = 0x00; + m_reg[TMP95C063_P2] = 0xff; + m_reg[TMP95C063_P2FC] = 0x00; + m_reg[TMP95C063_P5] = 0x3d; + m_reg[TMP95C063_P5CR] = 0x00; + m_reg[TMP95C063_P5FC] = 0x00; + m_reg[TMP95C063_P6] = 0x3b; + m_reg[TMP95C063_P6FC] = 0x00; + m_reg[TMP95C063_P7] = 0xff; + m_reg[TMP95C063_P7CR] = 0x00; + m_reg[TMP95C063_P7FC] = 0x00; + m_reg[TMP95C063_P8] = 0x3f; + m_reg[TMP95C063_P8CR] = 0x00; + m_reg[TMP95C063_P8FC] = 0x00; + m_reg[TMP95C063_PA] = 0x0f; + m_reg[TMP95C063_PACR] = 0x00; + m_reg[TMP95C063_PAFC] = 0x00; + m_reg[TMP95C063_PB] = 0xff; + m_reg[TMP95C063_PBCR] = 0x00; + m_reg[TMP95C063_PBFC] = 0x00; + m_reg[TMP95C063_MSAR0] = 0xff; + m_reg[TMP95C063_MSAR1] = 0xff; + m_reg[TMP95C063_MSAR2] = 0xff; + m_reg[TMP95C063_MSAR3] = 0xff; + m_reg[TMP95C063_MAMR0] = 0xff; + m_reg[TMP95C063_MAMR1] = 0xff; + m_reg[TMP95C063_MAMR2] = 0xff; + m_reg[TMP95C063_MAMR3] = 0xff; + m_reg[TMP95C063_DREFCR1] = 0x00; + m_reg[TMP95C063_DMEMCR1] = 0x80; + m_reg[TMP95C063_DREFCR3] = 0x00; + m_reg[TMP95C063_DMEMCR3] = 0x80; + m_reg[TMP95C063_T01MOD] = 0x00; + m_reg[TMP95C063_T23MOD] = 0x00; + m_reg[TMP95C063_T02FFCR] = 0x00; + m_reg[TMP95C063_T46FFCR] = 0x00; + m_reg[TMP95C063_T8RUN] = 0x00; + m_reg[TMP95C063_TRDC] = 0x00; + m_reg[TMP95C063_T45MOD] = 0x20; + m_reg[TMP95C063_T46FFCR] = 0x00; + m_reg[TMP95C063_PG01CR] = 0x00; + m_reg[TMP95C063_PG0REG] = 0x00; + m_reg[TMP95C063_PG1REG] = 0x00; + m_reg[TMP95C063_SC0MOD] = 0x00; + m_reg[TMP95C063_SC0CR] = 0x00; + m_reg[TMP95C063_BR0CR] = 0x00; + m_reg[TMP95C063_SC1MOD] = 0x00; + m_reg[TMP95C063_SC1CR] = 0x00; + m_reg[TMP95C063_BR1CR] = 0x00; + m_reg[TMP95C063_P8FC] = 0x00; + m_reg[TMP95C063_ODE] = 0x00; + m_reg[TMP95C063_ADMOD1] = 0x00; + m_reg[TMP95C063_ADMOD2] = 0x00; + m_reg[TMP95C063_ADREG04L] = 0x3f; + m_reg[TMP95C063_ADREG04H] = 0x00; + m_reg[TMP95C063_ADREG15L] = 0x3f; + m_reg[TMP95C063_ADREG15H] = 0x00; + m_reg[TMP95C063_ADREG26L] = 0x3f; + m_reg[TMP95C063_ADREG26H] = 0x00; + m_reg[TMP95C063_ADREG37L] = 0x3f; + m_reg[TMP95C063_ADREG37H] = 0x00; + m_reg[TMP95C063_WDMOD] = 0x80; + + for ( i = 0; i < TLCS900_NUM_INPUTS; i++ ) + { + m_level[i] = CLEAR_LINE; + } + m_prefetch_clear = true; +} + +READ8_MEMBER( tmp95c063_device::internal_r ) +{ + switch (offset) + { + case TMP95C063_P1: m_reg[offset] = m_port1_read(0); break; + case TMP95C063_P5: m_reg[offset] = m_port5_read(0); break; + case TMP95C063_P6: m_reg[offset] = m_port6_read(0); break; + case TMP95C063_P7: m_reg[offset] = m_port7_read(0); break; + case TMP95C063_P8: m_reg[offset] = m_port8_read(0); break; + case TMP95C063_P9: m_reg[offset] = m_port9_read(0); break; + case TMP95C063_PA: m_reg[offset] = m_porta_read(0); break; + case TMP95C063_PB: m_reg[offset] = m_portb_read(0); break; + case TMP95C063_PC: m_reg[offset] = m_portc_read(0); break; + case TMP95C063_PD: m_reg[offset] = m_portd_read(0); break; + case TMP95C063_PE: m_reg[offset] = m_porte_read(0); break; + } + return m_reg[ offset ]; +} + + +WRITE8_MEMBER( tmp95c063_device::internal_w ) +{ + switch ( offset ) + { + case TMP95C063_T8RUN: + if ( ! ( data & 0x01 ) ) + { + m_timer[0] = 0; + m_timer_change[0] = 0; + } + if ( ! ( data & 0x02 ) ) + { + m_timer[1] = 0; + m_timer_change[1] = 0; + } + if ( ! ( data & 0x04 ) ) + { + m_timer[2] = 0; + m_timer_change[2] = 0; + } + if ( ! ( data & 0x08 ) ) + { + m_timer[3] = 0; + m_timer_change[3] = 0; + } + if ( ! ( data & 0x10 ) ) + m_timer[4] = 0; + if ( ! ( data & 0x20 ) ) + m_timer[5] = 0; + break; + + case TMP95C063_T02FFCR: + switch( data & 0x0c ) + { + case 0x00: + //tlcs900_change_tff( 1, FF_INVERT ); + break; + case 0x04: + //tlcs900_change_tff( 1, FF_SET ); + break; + case 0x08: + //tlcs900_change_tff( 1, FF_CLEAR ); + break; + } + switch( data & 0xc0 ) + { + case 0x00: + //tlcs900_change_tff( 3, FF_INVERT ); + break; + case 0x40: + //tlcs900_change_tff( 3, FF_SET ); + break; + case 0x80: + //tlcs900_change_tff( 3, FF_CLEAR ); + break; + } + break; + + case TMP95C063_T46FFCR: + switch( data & 0x0c ) + { + case 0x00: + //tlcs900_change_tff( 5, FF_INVERT ); + break; + case 0x04: + //tlcs900_change_tff( 5, FF_SET ); + break; + case 0x08: + //tlcs900_change_tff( 5, FF_CLEAR ); + break; + } + switch( data & 0xc0 ) + { + case 0x00: + //tlcs900_change_tff( 7, FF_INVERT ); + break; + case 0x40: + //tlcs900_change_tff( 7, FF_SET ); + break; + case 0x80: + //tlcs900_change_tff( 7, FF_CLEAR ); + break; + } + break; + + case TMP95C063_T8FFCR: + switch( data & 0x03 ) + { + case 0x00: + //tlcs900_change_tff( 8, FF_INVERT ); + break; + case 0x01: + //tlcs900_change_tff( 8, FF_SET ); + break; + case 0x02: + //tlcs900_change_tff( 8, FF_CLEAR ); + break; + } + switch( data & 0xc0 ) + { + case 0x00: + //tlcs900_change_tff( 9, FF_INVERT ); + break; + case 0x40: + //tlcs900_change_tff( 9, FF_SET ); + break; + case 0x80: + //tlcs900_change_tff( 9, FF_CLEAR ); + break; + } + break; + + case TMP95C063_T9FFCR: + switch( data & 0x03 ) + { + case 0x00: + //tlcs900_change_tff( 0xa, FF_INVERT ); + break; + case 0x01: + //tlcs900_change_tff( 0xa, FF_SET ); + break; + case 0x02: + //tlcs900_change_tff( 0xa, FF_CLEAR ); + break; + } + switch( data & 0xc0 ) + { + case 0x00: + //tlcs900_change_tff( 0xb, FF_INVERT ); + break; + case 0x40: + //tlcs900_change_tff( 0xb, FF_SET ); + break; + case 0x80: + //tlcs900_change_tff( 0xb, FF_CLEAR ); + break; + } + break; + + case TMP95C063_MSAR0: + case TMP95C063_MAMR0: + case TMP95C063_MSAR1: + case TMP95C063_MAMR1: + break; + + case TMP95C063_WDMOD: + case TMP95C063_WDCR: + break; + + case TMP95C063_INTE0AD: + case TMP95C063_INTE12: + case TMP95C063_INTE34: + case TMP95C063_INTE56: + case TMP95C063_INTE78: + case TMP95C063_INTET01: + case TMP95C063_INTET23: + case TMP95C063_INTET45: + case TMP95C063_INTET67: + case TMP95C063_INTET89: + case TMP95C063_INTETAB: + case TMP95C063_INTES0: + case TMP95C063_INTES1: + case TMP95C063_INTETC01: + case TMP95C063_INTETC23: + if ( data & 0x80 ) + data = ( data & 0x7f ) | ( m_reg[offset] & 0x80 ); + if ( data & 0x08 ) + data = ( data & 0xf7 ) | ( m_reg[offset] & 0x08 ); + break; + + case TMP95C063_IIMC: + break; + + default: + break; + } + + m_check_irqs = 1; + m_reg[ offset ] = data; + + switch (offset) + { + case TMP95C063_P1: m_port1_write(0, data, 0xff); break; + case TMP95C063_P2: m_port2_write(0, data, 0xff); break; + case TMP95C063_P5: m_port5_write(0, data, 0xff); break; + case TMP95C063_P6: m_port6_write(0, data, 0xff); break; + case TMP95C063_P7: m_port7_write(0, data, 0xff); break; + case TMP95C063_P8: m_port8_write(0, data, 0xff); break; + case TMP95C063_P9: m_port9_write(0, data, 0xff); break; + case TMP95C063_PA: m_porta_write(0, data, 0xff); break; + case TMP95C063_PB: m_portb_write(0, data, 0xff); break; + //case TMP95C063_PC: m_portc_write(0, data, 0xff); break; + case TMP95C063_PD: m_portd_write(0, data, 0xff); break; + case TMP95C063_PE: m_porte_write(0, data, 0xff); break; + } +} + + +void tmp95c063_device::execute_set_input(int input, int level) +{ + switch( input ) + { + case INPUT_LINE_NMI: + case TLCS900_NMI: + if ( m_level[TLCS900_NMI] == CLEAR_LINE && level == ASSERT_LINE ) + { + m_nmi_state = level; + } + m_level[TLCS900_NMI] = level; + break; + + case TLCS900_INTWD: + break; + + case TLCS900_INT0: + /* Is INT0 functionality enabled? */ + if (m_reg[TMP95C063_IIMC] & 0x04) + { + if (m_reg[TMP95C063_IIMC] & 0x02) + { + /* Rising edge detect */ + if (m_level[TLCS900_INT0] == CLEAR_LINE && level == ASSERT_LINE) + { + /* Leave HALT state */ + m_halted = 0; + m_reg[TMP95C063_INTE0AD] |= 0x08; + } + } + else + { + /* Level detect */ + if (level == ASSERT_LINE) + m_reg[TMP95C063_INTE0AD] |= 0x08; + else + m_reg[TMP95C063_INTE0AD] &= ~ 0x08; + } + } + m_level[TLCS900_INT0] = level; + break; + + case TLCS900_INT1: + if (m_level[TLCS900_INT1] == CLEAR_LINE && level == ASSERT_LINE) + { + m_reg[TMP95C063_INTE12] |= 0x08; + } + else if (m_level[TLCS900_INT1] == ASSERT_LINE && level == CLEAR_LINE) + { + m_reg[TMP95C063_INTE12] &= ~0x08; + } + m_level[TLCS900_INT1] = level; + break; + + case TLCS900_INT2: + if (m_level[TLCS900_INT2] == CLEAR_LINE && level == ASSERT_LINE) + { + m_reg[TMP95C063_INTE12] |= 0x80; + } + else if (m_level[TLCS900_INT2] == ASSERT_LINE && level == CLEAR_LINE) + { + m_reg[TMP95C063_INTE12] &= ~0x80; + } + m_level[TLCS900_INT2] = level; + break; + + case TLCS900_INT3: + if (m_level[TLCS900_INT3] == CLEAR_LINE && level == ASSERT_LINE) + { + m_reg[TMP95C063_INTE34] |= 0x08; + } + else if (m_level[TLCS900_INT3] == ASSERT_LINE && level == CLEAR_LINE) + { + m_reg[TMP95C063_INTE34] &= ~0x08; + } + m_level[TLCS900_INT3] = level; + break; + + case TLCS900_INT4: + if ( ! ( m_reg[TMP95C063_PBCR] & 0x01 ) ) + { + if ( m_level[TLCS900_INT4] == CLEAR_LINE && level == ASSERT_LINE ) + { + m_reg[TMP95C063_INTE34] |= 0x80; + } + } + m_level[TLCS900_INT4] = level; + break; + + case TLCS900_INT5: + if ( ! ( m_reg[TMP95C063_PBCR] & 0x02 ) ) + { + if ( m_level[TLCS900_INT5] == CLEAR_LINE && level == ASSERT_LINE ) + { + m_reg[TMP95C063_INTE56] |= 0x08; + } + } + m_level[TLCS900_INT5] = level; + break; + + case TLCS900_INT6: + if (m_level[TLCS900_INT6] == CLEAR_LINE && level == ASSERT_LINE) + { + m_reg[TMP95C063_INTE56] |= 0x80; + } + else if (m_level[TLCS900_INT6] == ASSERT_LINE && level == CLEAR_LINE) + { + m_reg[TMP95C063_INTE56] &= ~0x80; + } + m_level[TLCS900_INT6] = level; + break; + + case TLCS900_TIO: /* External timer input for timer 0 */ + if ( ( m_reg[TMP95C063_T8RUN] & 0x01 ) && ( m_reg[TMP95C063_T01MOD] & 0x03 ) == 0x00 ) + { + if ( m_level[TLCS900_TIO] == CLEAR_LINE && level == ASSERT_LINE ) + { + m_timer_change[0] += 1; + } + } + m_level[TLCS900_TIO] = level; + break; + } + m_check_irqs = 1; +} diff --git a/src/devices/cpu/tlcs900/tlcs900.h b/src/devices/cpu/tlcs900/tlcs900.h new file mode 100644 index 00000000000..e8235ae5cb5 --- /dev/null +++ b/src/devices/cpu/tlcs900/tlcs900.h @@ -0,0 +1,840 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +#ifndef __TLCS900_H__ +#define __TLCS900_H__ + + + +enum tlcs900_inputs +{ + TLCS900_NMI=0, + TLCS900_INTWD, + TLCS900_INT0, + TLCS900_INTAD, + TLCS900_INT1, + TLCS900_INT2, + TLCS900_INT3, + TLCS900_INT4, + TLCS900_INT5, + TLCS900_INT6, + TLCS900_INT7, + TLCS900_INT8, + TLCS900_TIO, + TLCS900_NUM_INPUTS +}; + + +enum +{ + TLCS900_PC=1, TLCS900_SR, + TLCS900_XWA0, TLCS900_XBC0, TLCS900_XDE0, TLCS900_XHL0, + TLCS900_XWA1, TLCS900_XBC1, TLCS900_XDE1, TLCS900_XHL1, + TLCS900_XWA2, TLCS900_XBC2, TLCS900_XDE2, TLCS900_XHL2, + TLCS900_XWA3, TLCS900_XBC3, TLCS900_XDE3, TLCS900_XHL3, + TLCS900_XIX, TLCS900_XIY, TLCS900_XIZ, TLCS900_XNSP, TLCS900_XSSP, + TLCS900_DMAS0, TLCS900_DMAS1, TLCS900_DMAS2, TLCS900_DMAS3, + TLCS900_DMAD0, TLCS900_DMAD1, TLCS900_DMAD2, TLCS900_DMAD3, + TLCS900_DMAC0, TLCS900_DMAC1, TLCS900_DMAC2, TLCS900_DMAC3, + TLCS900_DMAM0, TLCS900_DMAM1, TLCS900_DMAM2, TLCS900_DMAM3 +}; + + +extern const device_type TMP95C061; +extern const device_type TMP95C063; + + +#define MCFG_TLCS900H_AM8_16( am8_16 ) tlcs900h_device::set_am8_16( *device, am8_16 ); + +class tlcs900h_device : public cpu_device +{ +public: + // construction/destruction + tlcs900h_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + tlcs900h_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname); + + // static configuration helpers + static void set_am8_16(device_t &device, int am8_16) { downcast(device).m_am8_16 = am8_16; } + +protected: + // device-level overrides + virtual void device_start(); + + // device_execute_interface overrides + virtual UINT32 execute_min_cycles() const { return 1; } /* FIXME */ + virtual UINT32 execute_max_cycles() const { return 1; } /* FIXME */ + virtual UINT32 execute_input_lines() const { return 6; } + virtual void execute_run(); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const + { + return (spacenum == AS_PROGRAM) ? &m_program_config : NULL; + } + + // device_state_interface overrides + void state_string_export(const device_state_entry &entry, std::string &str); + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const { return 1; } + virtual UINT32 disasm_max_opcode_bytes() const { return 7; } /* FIXME */ + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + +protected: + int m_am8_16; + address_space_config m_program_config; + + UINT8 RDMEM(offs_t addr) { return m_program->read_byte( addr ); } + UINT16 RDMEMW(offs_t addr) { return m_program->read_word( addr ); } + UINT32 RDMEML(offs_t addr) { return m_program->read_dword( addr ); } + void WRMEM(offs_t addr, UINT8 data) { m_program->write_byte( addr, data ); } + void WRMEMW(offs_t addr,UINT16 data) { m_program->write_word( addr, data ); } + void WRMEML(offs_t addr,UINT32 data) { m_program->write_dword( addr, data ); } + + /* registers */ + PAIR m_xwa[4]; + PAIR m_xbc[4]; + PAIR m_xde[4]; + PAIR m_xhl[4]; + PAIR m_xix; + PAIR m_xiy; + PAIR m_xiz; + PAIR m_xssp; + PAIR m_xnsp; + PAIR m_pc; + PAIR m_sr; + PAIR m_f2; /* f' */ + /* DMA registers */ + PAIR m_dmas[4]; + PAIR m_dmad[4]; + PAIR m_dmac[4]; + PAIR m_dmam[4]; + + /* Internal timers, irqs, etc */ + UINT8 m_reg[0xa0]; + UINT32 m_timer_pre; + UINT8 m_timer[6]; + int m_timer_change[4]; + bool m_prefetch_clear; + UINT8 m_prefetch_index; + UINT8 m_prefetch[4]; + + /* Current state of input levels */ + int m_level[TLCS900_NUM_INPUTS]; + int m_check_irqs; + int m_ad_cycles_left; + int m_nmi_state; + + /* used during execution */ + PAIR m_dummy; /* for illegal register references */ + UINT8 m_op; + PAIR m_ea1, m_ea2; + PAIR m_imm1, m_imm2; + int m_cycles; + UINT8 *m_p1_reg8, *m_p2_reg8; + UINT16 *m_p1_reg16, *m_p2_reg16; + UINT32 *m_p1_reg32, *m_p2_reg32; + + int m_halted; + int m_icount; + int m_regbank; + address_space *m_program; + + typedef void (tlcs900h_device::*ophandler)(); + struct tlcs900inst + { + ophandler opfunc; + int operand1; + int operand2; + int cycles; + }; + static const tlcs900inst s_mnemonic_80[256]; + static const tlcs900inst s_mnemonic_88[256]; + static const tlcs900inst s_mnemonic_90[256]; + static const tlcs900inst s_mnemonic_98[256]; + static const tlcs900inst s_mnemonic_a0[256]; + static const tlcs900inst s_mnemonic_b0[256]; + static const tlcs900inst s_mnemonic_b8[256]; + static const tlcs900inst s_mnemonic_c0[256]; + static const tlcs900inst s_mnemonic_c8[256]; + static const tlcs900inst s_mnemonic_d0[256]; + static const tlcs900inst s_mnemonic_d8[256]; + static const tlcs900inst s_mnemonic_e0[256]; + static const tlcs900inst s_mnemonic_e8[256]; + static const tlcs900inst s_mnemonic_f0[256]; + static const tlcs900inst s_mnemonic[256]; + + inline UINT8 RDOP(); + virtual void tlcs900_check_hdma() = 0; + virtual void tlcs900_check_irqs() = 0; + virtual void tlcs900_handle_ad() = 0; + virtual void tlcs900_handle_timers() = 0; + + int condition_true( UINT8 cond ); + UINT8 *get_reg8_current( UINT8 reg ); + UINT16 *get_reg16_current( UINT8 reg ); + UINT32 *get_reg32_current( UINT8 reg ); + PAIR *get_reg( UINT8 reg ); + UINT8 *get_reg8( UINT8 reg ); + UINT16 *get_reg16( UINT8 reg ); + UINT32 *get_reg32( UINT8 reg ); + void parity8( UINT8 a ); + void parity16( UINT16 a ); + void parity32( UINT32 a ); + UINT8 adc8( UINT8 a, UINT8 b); + UINT16 adc16( UINT16 a, UINT16 b); + UINT32 adc32( UINT32 a, UINT32 b); + UINT8 add8( UINT8 a, UINT8 b); + UINT16 add16( UINT16 a, UINT16 b); + UINT32 add32( UINT32 a, UINT32 b); + UINT8 sbc8( UINT8 a, UINT8 b); + UINT16 sbc16( UINT16 a, UINT16 b); + UINT32 sbc32( UINT32 a, UINT32 b); + UINT8 sub8( UINT8 a, UINT8 b); + UINT16 sub16( UINT16 a, UINT16 b); + UINT32 sub32( UINT32 a, UINT32 b); + UINT8 and8( UINT8 a, UINT8 b); + UINT16 and16( UINT16 a, UINT16 b); + UINT32 and32( UINT32 a, UINT32 b); + UINT8 or8( UINT8 a, UINT8 b); + UINT16 or16( UINT16 a, UINT16 b); + UINT32 or32( UINT32 a, UINT32 b); + UINT8 xor8( UINT8 a, UINT8 b); + UINT16 xor16( UINT16 a, UINT16 b); + UINT32 xor32( UINT32 a, UINT32 b); + void ldcf8( UINT8 a, UINT8 b ); + void ldcf16( UINT8 a, UINT8 b ); + void andcf8( UINT8 a, UINT8 b ); + void andcf16( UINT8 a, UINT8 b ); + void orcf8( UINT8 a, UINT8 b ); + void orcf16( UINT8 a, UINT8 b ); + void xorcf8( UINT8 a, UINT8 b ); + void xorcf16( UINT8 a, UINT8 b ); + UINT8 rl8( UINT8 a, UINT8 s ); + UINT16 rl16( UINT16 a, UINT8 s ); + UINT32 rl32( UINT32 a, UINT8 s ); + UINT8 rlc8( UINT8 a, UINT8 s ); + UINT16 rlc16( UINT16 a, UINT8 s ); + UINT32 rlc32( UINT32 a, UINT8 s ); + UINT8 rr8( UINT8 a, UINT8 s ); + UINT16 rr16( UINT16 a, UINT8 s ); + UINT32 rr32( UINT32 a, UINT8 s ); + UINT8 rrc8( UINT8 a, UINT8 s ); + UINT16 rrc16( UINT16 a, UINT8 s ); + UINT32 rrc32( UINT32 a, UINT8 s ); + UINT8 sla8( UINT8 a, UINT8 s ); + UINT16 sla16( UINT16 a, UINT8 s ); + UINT32 sla32( UINT32 a, UINT8 s ); + UINT8 sra8( UINT8 a, UINT8 s ); + UINT16 sra16( UINT16 a, UINT8 s ); + UINT32 sra32( UINT32 a, UINT8 s ); + UINT8 srl8( UINT8 a, UINT8 s ); + UINT16 srl16( UINT16 a, UINT8 s ); + UINT32 srl32( UINT32 a, UINT8 s ); + UINT16 div8( UINT16 a, UINT8 b ); + UINT32 div16( UINT32 a, UINT16 b ); + UINT16 divs8( INT16 a, INT8 b ); + UINT32 divs16( INT32 a, INT16 b ); + void _ADCBMI(); + void _ADCBMR(); + void _ADCBRI(); + void _ADCBRM(); + void _ADCBRR(); + void _ADCWMI(); + void _ADCWMR(); + void _ADCWRI(); + void _ADCWRM(); + void _ADCWRR(); + void _ADCLMR(); + void _ADCLRI(); + void _ADCLRM(); + void _ADCLRR(); + void _ADDBMI(); + void _ADDBMR(); + void _ADDBRI(); + void _ADDBRM(); + void _ADDBRR(); + void _ADDWMI(); + void _ADDWMR(); + void _ADDWRI(); + void _ADDWRM(); + void _ADDWRR(); + void _ADDLMR(); + void _ADDLRI(); + void _ADDLRM(); + void _ADDLRR(); + void _ANDBMI(); + void _ANDBMR(); + void _ANDBRI(); + void _ANDBRM(); + void _ANDBRR(); + void _ANDWMI(); + void _ANDWMR(); + void _ANDWRI(); + void _ANDWRM(); + void _ANDWRR(); + void _ANDLMR(); + void _ANDLRI(); + void _ANDLRM(); + void _ANDLRR(); + void _ANDCFBIM(); + void _ANDCFBIR(); + void _ANDCFBRM(); + void _ANDCFBRR(); + void _ANDCFWIR(); + void _ANDCFWRR(); + void _BITBIM(); + void _BITBIR(); + void _BITWIR(); + void _BS1BRR(); + void _BS1FRR(); + void _CALLI(); + void _CALLM(); + void _CALR(); + void _CCF(); + void _CHGBIM(); + void _CHGBIR(); + void _CHGWIR(); + void _CPBMI(); + void _CPBMR(); + void _CPBRI(); + void _CPBRM(); + void _CPBRR(); + void _CPWMI(); + void _CPWMR(); + void _CPWRI(); + void _CPWRM(); + void _CPWRR(); + void _CPLMR(); + void _CPLRI(); + void _CPLRM(); + void _CPLRR(); + void _CPD(); + void _CPDR(); + void _CPDW(); + void _CPDRW(); + void _CPI(); + void _CPIR(); + void _CPIW(); + void _CPIRW(); + void _CPLBR(); + void _CPLWR(); + void _DAABR(); + void _DB(); + void _DECBIM(); + void _DECBIR(); + void _DECWIM(); + void _DECWIR(); + void _DECLIR(); + void _DECF(); + void _DIVBRI(); + void _DIVBRM(); + void _DIVBRR(); + void _DIVWRI(); + void _DIVWRM(); + void _DIVWRR(); + void _DIVSBRI(); + void _DIVSBRM(); + void _DIVSBRR(); + void _DIVSWRI(); + void _DIVSWRM(); + void _DIVSWRR(); + void _DJNZB(); + void _DJNZW(); + void _EI(); + void _EXBMR(); + void _EXBRR(); + void _EXWMR(); + void _EXWRR(); + void _EXTSWR(); + void _EXTSLR(); + void _EXTZWR(); + void _EXTZLR(); + void _HALT(); + void _INCBIM(); + void _INCBIR(); + void _INCWIM(); + void _INCWIR(); + void _INCLIR(); + void _INCF(); + void _JPI(); + void _JPM(); + void _JR(); + void _JRL(); + void _LDBMI(); + void _LDBMM(); + void _LDBMR(); + void _LDBRI(); + void _LDBRM(); + void _LDBRR(); + void _LDWMI(); + void _LDWMM(); + void _LDWMR(); + void _LDWRI(); + void _LDWRM(); + void _LDWRR(); + void _LDLRI(); + void _LDLRM(); + void _LDLRR(); + void _LDLMR(); + void _LDAW(); + void _LDAL(); + void _LDCBRR(); + void _LDCWRR(); + void _LDCLRR(); + void _LDCFBIM(); + void _LDCFBIR(); + void _LDCFBRM(); + void _LDCFBRR(); + void _LDCFWIR(); + void _LDCFWRR(); + void _LDD(); + void _LDDR(); + void _LDDRW(); + void _LDDW(); + void _LDF(); + void _LDI(); + void _LDIR(); + void _LDIRW(); + void _LDIW(); + void _LDX(); + void _LINK(); + void _MAX(); + void _MDEC1(); + void _MDEC2(); + void _MDEC4(); + void _MINC1(); + void _MINC2(); + void _MINC4(); + void _MIRRW(); + void _MULBRI(); + void _MULBRM(); + void _MULBRR(); + void _MULWRI(); + void _MULWRM(); + void _MULWRR(); + void _MULAR(); + void _MULSBRI(); + void _MULSBRM(); + void _MULSBRR(); + void _MULSWRI(); + void _MULSWRM(); + void _MULSWRR(); + void _NEGBR(); + void _NEGWR(); + void _NOP(); + void _NORMAL(); + void _ORBMI(); + void _ORBMR(); + void _ORBRI(); + void _ORBRM(); + void _ORBRR(); + void _ORWMI(); + void _ORWMR(); + void _ORWRI(); + void _ORWRM(); + void _ORWRR(); + void _ORLMR(); + void _ORLRI(); + void _ORLRM(); + void _ORLRR(); + void _ORCFBIM(); + void _ORCFBIR(); + void _ORCFBRM(); + void _ORCFBRR(); + void _ORCFWIR(); + void _ORCFWRR(); + void _PAAWR(); + void _PAALR(); + void _POPBM(); + void _POPBR(); + void _POPWM(); + void _POPWR(); + void _POPWSR(); + void _POPLR(); + void _PUSHBI(); + void _PUSHBM(); + void _PUSHBR(); + void _PUSHWI(); + void _PUSHWM(); + void _PUSHWR(); + void _PUSHLR(); + void _RCF(); + void _RESBIM(); + void _RESBIR(); + void _RESWIR(); + void _RET(); + void _RETCC(); + void _RETD(); + void _RETI(); + void _RLBM(); + void _RLWM(); + void _RLBIR(); + void _RLBRR(); + void _RLWIR(); + void _RLWRR(); + void _RLLIR(); + void _RLLRR(); + void _RLCBM(); + void _RLCWM(); + void _RLCBIR(); + void _RLCBRR(); + void _RLCWIR(); + void _RLCWRR(); + void _RLCLIR(); + void _RLCLRR(); + void _RLDRM(); + void _RRBM(); + void _RRWM(); + void _RRBIR(); + void _RRBRR(); + void _RRWIR(); + void _RRWRR(); + void _RRLIR(); + void _RRLRR(); + void _RRCBM(); + void _RRCWM(); + void _RRCBIR(); + void _RRCBRR(); + void _RRCWIR(); + void _RRCWRR(); + void _RRCLIR(); + void _RRCLRR(); + void _RRDRM(); + void _SBCBMI(); + void _SBCBMR(); + void _SBCBRI(); + void _SBCBRM(); + void _SBCBRR(); + void _SBCWMI(); + void _SBCWMR(); + void _SBCWRI(); + void _SBCWRM(); + void _SBCWRR(); + void _SBCLMR(); + void _SBCLRI(); + void _SBCLRM(); + void _SBCLRR(); + void _SCCBR(); + void _SCCWR(); + void _SCF(); + void _SETBIM(); + void _SETBIR(); + void _SETWIR(); + void _SLABM(); + void _SLAWM(); + void _SLABIR(); + void _SLABRR(); + void _SLAWIR(); + void _SLAWRR(); + void _SLALIR(); + void _SLALRR(); + void _SLLBM(); + void _SLLWM(); + void _SLLBIR(); + void _SLLBRR(); + void _SLLWIR(); + void _SLLWRR(); + void _SLLLIR(); + void _SLLLRR(); + void _SRABM(); + void _SRAWM(); + void _SRABIR(); + void _SRABRR(); + void _SRAWIR(); + void _SRAWRR(); + void _SRALIR(); + void _SRALRR(); + void _SRLBM(); + void _SRLWM(); + void _SRLBIR(); + void _SRLBRR(); + void _SRLWIR(); + void _SRLWRR(); + void _SRLLIR(); + void _SRLLRR(); + void _STCFBIM(); + void _STCFBIR(); + void _STCFBRM(); + void _STCFBRR(); + void _STCFWIR(); + void _STCFWRR(); + void _SUBBMI(); + void _SUBBMR(); + void _SUBBRI(); + void _SUBBRM(); + void _SUBBRR(); + void _SUBWMI(); + void _SUBWMR(); + void _SUBWRI(); + void _SUBWRM(); + void _SUBWRR(); + void _SUBLMR(); + void _SUBLRI(); + void _SUBLRM(); + void _SUBLRR(); + void _SWI(); + void _TSETBIM(); + void _TSETBIR(); + void _TSETWIR(); + void _UNLK(); + void _XORBMI(); + void _XORBMR(); + void _XORBRI(); + void _XORBRM(); + void _XORBRR(); + void _XORWMI(); + void _XORWMR(); + void _XORWRI(); + void _XORWRM(); + void _XORWRR(); + void _XORLMR(); + void _XORLRI(); + void _XORLRM(); + void _XORLRR(); + void _XORCFBIM(); + void _XORCFBIR(); + void _XORCFBRM(); + void _XORCFBRR(); + void _XORCFWIR(); + void _XORCFWRR(); + void _ZCF(); + void prepare_operands(const tlcs900inst *inst); + void _80(); + void _88(); + void _90(); + void _98(); + void _A0(); + void _A8(); + void _B0(); + void _B8(); + void _C0(); + void oC8(); + void _D0(); + void oD8(); + void _E0(); + void _E8(); + void _F0(); +}; + +#define MCFG_TMP95C061_PORT1_READ( _port_read ) tmp95c061_device::set_port1_read( *device, DEVCB_##_port_read ); +#define MCFG_TMP95C061_PORT1_WRITE( _port_write ) tmp95c061_device::set_port1_write( *device, DEVCB_##_port_write ); +#define MCFG_TMP95C061_PORT2_WRITE( _port_write ) tmp95c061_device::set_port2_write( *device, DEVCB_##_port_write ); +#define MCFG_TMP95C061_PORT5_READ( _port_read ) tmp95c061_device::set_port5_read( *device, DEVCB_##_port_read ); +#define MCFG_TMP95C061_PORT5_WRITE( _port_write ) tmp95c061_device::set_port5_write( *device, DEVCB_##_port_write ); +#define MCFG_TMP95C061_PORT6_READ( _port_read ) tmp95c061_device::set_port6_read( *device, DEVCB_##_port_read ); +#define MCFG_TMP95C061_PORT6_WRITE( _port_write ) tmp95c061_device::set_port6_write( *device, DEVCB_##_port_write ); +#define MCFG_TMP95C061_PORT7_READ( _port_read ) tmp95c061_device::set_port7_read( *device, DEVCB_##_port_read ); +#define MCFG_TMP95C061_PORT7_WRITE( _port_write ) tmp95c061_device::set_port7_write( *device, DEVCB_##_port_write ); +#define MCFG_TMP95C061_PORT8_READ( _port_read ) tmp95c061_device::set_port8_read( *device, DEVCB_##_port_read ); +#define MCFG_TMP95C061_PORT8_WRITE( _port_write ) tmp95c061_device::set_port8_write( *device, DEVCB_##_port_write ); +#define MCFG_TMP95C061_PORT9_READ( _port_read ) tmp95c061_device::set_port9_read( *device, DEVCB_##_port_read ); +#define MCFG_TMP95C061_PORTA_READ( _port_read ) tmp95c061_device::set_porta_read( *device, DEVCB_##_port_read ); +#define MCFG_TMP95C061_PORTA_WRITE( _port_write ) tmp95c061_device::set_porta_write( *device, DEVCB_##_port_write ); +#define MCFG_TMP95C061_PORTB_READ( _port_read ) tmp95c061_device::set_portb_read( *device, DEVCB_##_port_read ); +#define MCFG_TMP95C061_PORTB_WRITE( _port_write ) tmp95c061_device::set_portb_write( *device, DEVCB_##_port_write ); + +class tmp95c061_device : public tlcs900h_device +{ +public: + // construction/destruction + tmp95c061_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // static configuration helpers + template static devcb_base &set_port1_read(device_t &device, _Object object) { return downcast(device).m_port1_read.set_callback(object); } + template static devcb_base &set_port1_write(device_t &device, _Object object) { return downcast(device).m_port1_write.set_callback(object); } + template static devcb_base &set_port2_write(device_t &device, _Object object) { return downcast(device).m_port2_write.set_callback(object); } + template static devcb_base &set_port5_read(device_t &device, _Object object) { return downcast(device).m_port5_read.set_callback(object); } + template static devcb_base &set_port5_write(device_t &device, _Object object) { return downcast(device).m_port5_write.set_callback(object); } + template static devcb_base &set_port6_write(device_t &device, _Object object) { return downcast(device).m_port6_write.set_callback(object); } + template static devcb_base &set_port7_read(device_t &device, _Object object) { return downcast(device).m_port7_read.set_callback(object); } + template static devcb_base &set_port7_write(device_t &device, _Object object) { return downcast(device).m_port7_write.set_callback(object); } + template static devcb_base &set_port8_read(device_t &device, _Object object) { return downcast(device).m_port8_read.set_callback(object); } + template static devcb_base &set_port8_write(device_t &device, _Object object) { return downcast(device).m_port8_write.set_callback(object); } + template static devcb_base &set_port9_read(device_t &device, _Object object) { return downcast(device).m_port9_read.set_callback(object); } + template static devcb_base &set_porta_read(device_t &device, _Object object) { return downcast(device).m_porta_read.set_callback(object); } + template static devcb_base &set_porta_write(device_t &device, _Object object) { return downcast(device).m_porta_write.set_callback(object); } + template static devcb_base &set_portb_read(device_t &device, _Object object) { return downcast(device).m_portb_read.set_callback(object); } + template static devcb_base &set_portb_write(device_t &device, _Object object) { return downcast(device).m_portb_write.set_callback(object); } + + DECLARE_READ8_MEMBER( internal_r ); + DECLARE_WRITE8_MEMBER( internal_w ); + +protected: + virtual void device_config_complete(); + virtual void device_start(); + virtual void device_reset(); + + virtual void execute_set_input(int inputnum, int state); + virtual void tlcs900_check_hdma(); + virtual void tlcs900_check_irqs(); + virtual void tlcs900_handle_ad(); + virtual void tlcs900_handle_timers(); + + void tlcs900_change_tff( int which, int change ); + int tlcs900_process_hdma( int channel ); + void update_porta(); + +private: + UINT8 m_to1; + UINT8 m_to3; + + // Port 1: 8 bit I/O. Shared with D8-D15 + devcb_read8 m_port1_read; + devcb_write8 m_port1_write; + + // Port 2: 8 bit output only. Shared with A16-A23 + devcb_write8 m_port2_write; + + // Port 5: 4 bit I/O. Shared with HWR, BUSRQ, BUSAK, RW + devcb_read8 m_port5_read; + devcb_write8 m_port5_write; + + // Port 6: 6 bit I/O. Shared with CS0, CS1, CS3/LCAS, RAS, REFOUT + devcb_read8 m_port6_read; + devcb_write8 m_port6_write; + + // Port 7: 8 bit I/O. Shared with PG0-OUT, PG1-OUT + devcb_read8 m_port7_read; + devcb_write8 m_port7_write; + + // Port 8: 6 bit I/O. Shared with TXD0, TXD1, RXD0, RXD1, CTS0, SCLK0, SCLK1 + devcb_read8 m_port8_read; + devcb_write8 m_port8_write; + + // Port 9: 4 bit input only. Shared with AN0-AN3 + devcb_read8 m_port9_read; + + // Port A: 4 bit I/O. Shared with WAIT, TI0, TO1, TO2 + devcb_read8 m_porta_read; + devcb_write8 m_porta_write; + + // Port B: 8 bit I/O. Shared with TI4/INT4, TI5/INT5, TI6/INT6, TI7/INT7, TO4, TO5, TO6 + devcb_read8 m_portb_read; + devcb_write8 m_portb_write; +}; + + +#define MCFG_TMP95C063_PORT0_READ( _port_read ) tmp95c063_device::set_port0_read( *device, DEVCB_##_port_read ); +#define MCFG_TMP95C063_PORT0_WRITE( _port_write ) tmp95c063_device::set_port0_write( *device, DEVCB_##_port_write ); +#define MCFG_TMP95C063_PORT1_READ( _port_read ) tmp95c063_device::set_port1_read( *device, DEVCB_##_port_read ); +#define MCFG_TMP95C063_PORT1_WRITE( _port_write ) tmp95c063_device::set_port1_write( *device, DEVCB_##_port_write ); +#define MCFG_TMP95C063_PORT2_READ( _port_read ) tmp95c063_device::set_port2_read( *device, DEVCB_##_port_read ); +#define MCFG_TMP95C063_PORT2_WRITE( _port_write ) tmp95c063_device::set_port2_write( *device, DEVCB_##_port_write ); +#define MCFG_TMP95C063_PORT3_READ( _port_read ) tmp95c063_device::set_port3_read( *device, DEVCB_##_port_read ); +#define MCFG_TMP95C063_PORT3_WRITE( _port_write ) tmp95c063_device::set_port3_write( *device, DEVCB_##_port_write ); +#define MCFG_TMP95C063_PORT4_READ( _port_read ) tmp95c063_device::set_port4_read( *device, DEVCB_##_port_read ); +#define MCFG_TMP95C063_PORT4_WRITE( _port_write ) tmp95c063_device::set_port4_write( *device, DEVCB_##_port_write ); +#define MCFG_TMP95C063_PORT5_READ( _port_read ) tmp95c063_device::set_port5_read( *device, DEVCB_##_port_read ); +#define MCFG_TMP95C063_PORT5_WRITE( _port_write ) tmp95c063_device::set_port5_write( *device, DEVCB_##_port_write ); +#define MCFG_TMP95C063_PORT6_READ( _port_read ) tmp95c063_device::set_port6_read( *device, DEVCB_##_port_read ); +#define MCFG_TMP95C063_PORT6_WRITE( _port_write ) tmp95c063_device::set_port6_write( *device, DEVCB_##_port_write ); +#define MCFG_TMP95C063_PORT7_READ( _port_read ) tmp95c063_device::set_port7_read( *device, DEVCB_##_port_read ); +#define MCFG_TMP95C063_PORT7_WRITE( _port_write ) tmp95c063_device::set_port7_write( *device, DEVCB_##_port_write ); +#define MCFG_TMP95C063_PORT8_READ( _port_read ) tmp95c063_device::set_port8_read( *device, DEVCB_##_port_read ); +#define MCFG_TMP95C063_PORT8_WRITE( _port_write ) tmp95c063_device::set_port8_write( *device, DEVCB_##_port_write ); +#define MCFG_TMP95C063_PORT9_READ( _port_read ) tmp95c063_device::set_port9_read( *device, DEVCB_##_port_read ); +#define MCFG_TMP95C063_PORT9_WRITE( _port_write ) tmp95c063_device::set_port9_write( *device, DEVCB_##_port_write ); +#define MCFG_TMP95C063_PORTA_READ( _port_read ) tmp95c063_device::set_porta_read( *device, DEVCB_##_port_read ); +#define MCFG_TMP95C063_PORTA_WRITE( _port_write ) tmp95c063_device::set_porta_write( *device, DEVCB_##_port_write ); +#define MCFG_TMP95C063_PORTB_READ( _port_read ) tmp95c063_device::set_portb_read( *device, DEVCB_##_port_read ); +#define MCFG_TMP95C063_PORTB_WRITE( _port_write ) tmp95c063_device::set_portb_write( *device, DEVCB_##_port_write ); +#define MCFG_TMP95C063_PORTC_READ( _port_read ) tmp95c063_device::set_portc_read( *device, DEVCB_##_port_read ); +#define MCFG_TMP95C063_PORTC_WRITE( _port_write ) tmp95c063_device::set_portc_write( *device, DEVCB_##_port_write ); +#define MCFG_TMP95C063_PORTD_READ( _port_read ) tmp95c063_device::set_portd_read( *device, DEVCB_##_port_read ); +#define MCFG_TMP95C063_PORTD_WRITE( _port_write ) tmp95c063_device::set_portd_write( *device, DEVCB_##_port_write ); +#define MCFG_TMP95C063_PORTE_READ( _port_read ) tmp95c063_device::set_porte_read( *device, DEVCB_##_port_read ); +#define MCFG_TMP95C063_PORTE_WRITE( _port_write ) tmp95c063_device::set_porte_write( *device, DEVCB_##_port_write ); + +class tmp95c063_device : public tlcs900h_device +{ +public: + // construction/destruction + tmp95c063_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + DECLARE_READ8_MEMBER( internal_r ); + DECLARE_WRITE8_MEMBER( internal_w ); + + // static configuration helpers + template static devcb_base &set_port1_read(device_t &device, _Object object) { return downcast(device).m_port1_read.set_callback(object); } + template static devcb_base &set_port1_write(device_t &device, _Object object) { return downcast(device).m_port1_write.set_callback(object); } + template static devcb_base &set_port2_write(device_t &device, _Object object) { return downcast(device).m_port2_write.set_callback(object); } + template static devcb_base &set_port5_read(device_t &device, _Object object) { return downcast(device).m_port5_read.set_callback(object); } + template static devcb_base &set_port5_write(device_t &device, _Object object) { return downcast(device).m_port5_write.set_callback(object); } + template static devcb_base &set_port6_read(device_t &device, _Object object) { return downcast(device).m_port6_read.set_callback(object); } + template static devcb_base &set_port6_write(device_t &device, _Object object) { return downcast(device).m_port6_write.set_callback(object); } + template static devcb_base &set_port7_read(device_t &device, _Object object) { return downcast(device).m_port7_read.set_callback(object); } + template static devcb_base &set_port7_write(device_t &device, _Object object) { return downcast(device).m_port7_write.set_callback(object); } + template static devcb_base &set_port8_read(device_t &device, _Object object) { return downcast(device).m_port8_read.set_callback(object); } + template static devcb_base &set_port8_write(device_t &device, _Object object) { return downcast(device).m_port8_write.set_callback(object); } + template static devcb_base &set_port9_read(device_t &device, _Object object) { return downcast(device).m_port9_read.set_callback(object); } + template static devcb_base &set_port9_write(device_t &device, _Object object) { return downcast(device).m_port9_write.set_callback(object); } + template static devcb_base &set_porta_read(device_t &device, _Object object) { return downcast(device).m_porta_read.set_callback(object); } + template static devcb_base &set_porta_write(device_t &device, _Object object) { return downcast(device).m_porta_write.set_callback(object); } + template static devcb_base &set_portb_read(device_t &device, _Object object) { return downcast(device).m_portb_read.set_callback(object); } + template static devcb_base &set_portb_write(device_t &device, _Object object) { return downcast(device).m_portb_write.set_callback(object); } + template static devcb_base &set_portc_read(device_t &device, _Object object) { return downcast(device).m_portc_read.set_callback(object); } + template static devcb_base &set_portd_read(device_t &device, _Object object) { return downcast(device).m_portd_read.set_callback(object); } + template static devcb_base &set_portd_write(device_t &device, _Object object) { return downcast(device).m_portd_write.set_callback(object); } + template static devcb_base &set_porte_read(device_t &device, _Object object) { return downcast(device).m_porte_read.set_callback(object); } + template static devcb_base &set_porte_write(device_t &device, _Object object) { return downcast(device).m_porte_write.set_callback(object); } + +protected: + virtual void device_config_complete(); + virtual void device_start(); + virtual void device_reset(); + + virtual void execute_set_input(int inputnum, int state); + virtual void tlcs900_check_hdma(); + virtual void tlcs900_check_irqs(); + virtual void tlcs900_handle_ad(); + virtual void tlcs900_handle_timers(); + +private: + // Port 1: 8 bit I/O. Shared with d8-d15 + devcb_read8 m_port1_read; + devcb_write8 m_port1_write; + + // Port 2: 8 bit output only. Shared with a16-a23 + devcb_write8 m_port2_write; + + // Port 5: 6 bit I/O + devcb_read8 m_port5_read; + devcb_write8 m_port5_write; + + // Port 6: 8 bit I/O. Shared with cs1, cs3 & dram control + devcb_read8 m_port6_read; + devcb_write8 m_port6_write; + + // Port 7: 8 bit I/O + devcb_read8 m_port7_read; + devcb_write8 m_port7_write; + + // Port 8: 8 bit I/O. Shared with SCOUT, WAIT, NMI2, INT0-INT3 + devcb_read8 m_port8_read; + devcb_write8 m_port8_write; + + // Port 9: 8 bit I/O. Shared with clock input and output for the 8-bit timers + devcb_read8 m_port9_read; + devcb_write8 m_port9_write; + + // Port A: 8 bit I/O. Shared with serial channels 0/1 + devcb_read8 m_porta_read; + devcb_write8 m_porta_write; + + // Port B: 8 bit I/O. Shared with 16bit timers + devcb_read8 m_portb_read; + devcb_write8 m_portb_write; + + // Port C: 8 bit input only. Shared with analogue inputs + devcb_read8 m_portc_read; + + // Port D: 5 bit I/O. Shared with INT8 + devcb_read8 m_portd_read; + devcb_write8 m_portd_write; + + // Port E: 8 bit I/O. + devcb_read8 m_porte_read; + devcb_write8 m_porte_write; +}; + +#endif diff --git a/src/devices/cpu/tms0980/tms0980.c b/src/devices/cpu/tms0980/tms0980.c new file mode 100644 index 00000000000..8275f09d815 --- /dev/null +++ b/src/devices/cpu/tms0980/tms0980.c @@ -0,0 +1,1441 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol, hap +/* + + TMS0980/TMS1000-family MCU cores + + TODO: + - emulate TMS1600 L-pins + - fix debugger disasm view + + +The TMS0980 and TMS1000-family MCU cores are very similar. The TMS0980 has a +slightly bigger addressable area and uses 9bit instructions where the TMS1000 +family uses 8bit instruction. The instruction set themselves are very similar +though. + +Each instruction takes 12 cycles to execute in 2 phases: a fetch phase and an +execution phase. The execution phase takes place at the same time as the fetch +phase of the next instruction. So, during execution there are both fetch and +execution operations taking place. The operation can be split up as follows: +cycle #0 + - Fetch: + 1. ROM address 0 + - Execute: + 1. Read RAM + 2. Clear ALU inputs + 3. Execute BRANCH/CALL/RETN part #2 + 4. K input valid +cycle #1 + - Fetch: + 1. ROM address 1 + - Execute: + 1. Update ALU inputs +cycle #2 + - Fetch: + 1. nothing/wait(?) + - Execute: + 1. Perform ALU operation + 2. Write RAM +cycle #3 + - Fetch: + 1. Fetch/Update PC/RAM address #1 + - Execute: + 1. Register store part #1 +cycle #4 + - Fetch: + 1. Fetch/Update PC/RAM address #2 + - Execute: + 1. Register store part #2 +cycle #5 + - Fetch: + 1. Instruction decode + - Execute: + 1. Execute BRANCH/CALL/RETN part #1 + +*/ + +#include "tms0980.h" +#include "debugger.h" + +/* + +The MCU cores contains a set of fixed instructions and a set of +instructions created using microinstructions. A subset of the +instruction set could be defined from the microinstructions by +TI customers. + +cycle #0: 15TN, ATN, CIN, CKN, CKP, DMTP, MTN, MTP, NATN, NDMTP, YTP +cycle #2: C8(?), CKM, NE(?), STO +cycle #3,#4: AUTA, AUTY + +unknown cycle: CME, SSE, SSS + +*/ + +/* Microinstructions */ +#define M_15TN (1<<0) /* 15 to -ALU */ +#define M_ATN (1<<1) /* ACC to -ALU */ +#define M_AUTA (1<<2) /* ALU to ACC */ +#define M_AUTY (1<<3) /* ALU to Y */ +#define M_C8 (1<<4) /* CARRY8 to STATUS */ +#define M_CIN (1<<5) /* Carry In to ALU */ +#define M_CKM (1<<6) /* CKB to MEM */ +#define M_CKN (1<<7) /* CKB to -ALU */ +#define M_CKP (1<<8) /* CKB to +ALU */ +#define M_MTN (1<<9) /* MEM to -ALU */ +#define M_MTP (1<<10) /* MEM to +ALU */ +#define M_NATN (1<<11) /* ~ACC to -ALU */ +#define M_NE (1<<12) /* COMP to STATUS */ +#define M_STO (1<<13) /* ACC to MEM */ +#define M_STSL (1<<14) /* STATUS to Status Latch */ +#define M_YTP (1<<15) /* Y to +ALU */ + +#define M_CME (1<<16) /* Conditional Memory Enable */ +#define M_DMTP (1<<17) /* DAM to +ALU */ +#define M_NDMTP (1<<18) /* ~DAM to +ALU */ +#define M_SSE (1<<19) /* Special Status Enable */ +#define M_SSS (1<<20) /* Special Status Sample */ + +#define M_RSTR (1<<21) /* -> line #36, F_RSTR (TMS02x0 custom) */ +#define M_UNK1 (1<<22) /* -> line #37, F_???? (TMS0270 custom) */ + +/* Standard/fixed instructions - these are documented more in their specific handlers below */ +#define F_BR (1<<0) +#define F_CALL (1<<1) +#define F_CLO (1<<2) +#define F_COMC (1<<3) +#define F_COMX (1<<4) +#define F_COMX8 (1<<5) +#define F_LDP (1<<6) +#define F_LDX (1<<7) +#define F_RBIT (1<<8) +#define F_RETN (1<<9) +#define F_RSTR (1<<10) +#define F_SBIT (1<<11) +#define F_SETR (1<<12) +#define F_TDO (1<<13) +#define F_TPC (1<<14) + +#define F_OFF (1<<15) +#define F_REAC (1<<16) +#define F_SAL (1<<17) +#define F_SBL (1<<18) +#define F_SEAC (1<<19) +#define F_XDA (1<<20) + + +// supported types: +// note: dice information assumes the orientation is pictured with RAM at the bottom-left, except where noted + +// TMS1000 +// - 64x4bit RAM array at the bottom-left +// - 1024x8bit ROM array at the bottom-right +// * FYI, the row-selector to the left of it is laid out as: +// 3,4,11,12,19,20,27,28,35,36,43,44,51,52,59,60,0,7,8,15,16,23,24,31,32,39,40,47,48,55,56,63, +// 2,5,10,13,18,21,26,29,34,37,42,45,50,53,58,61,1,6,9,14,17,22,25,30,33,38,41,46,49,54,57,62 +// - 30-term microinstructions PLA(mpla) at the top half, to the right of the midline, supporting 16 microinstructions +// - 20-term output PLA(opla) at the top-left +// - the ALU is between the opla and mpla +const device_type TMS1000 = &device_creator; // 28-pin DIP, 11 R pins +const device_type TMS1070 = &device_creator; // high voltage version +const device_type TMS1040 = &device_creator; // same as TMS1070 with just a different pinout? +const device_type TMS1200 = &device_creator; // 40-pin DIP, 13 R pins +// TMS1270 has 10 O pins, how does that work? + +// TMS1100 is nearly the same as TMS1000, some different opcodes, and with double the RAM and ROM +const device_type TMS1100 = &device_creator; // 28-pin DIP, 11 R pins +const device_type TMS1170 = &device_creator; // high voltage version +const device_type TMS1300 = &device_creator; // 40-pin DIP, 16 R pins +const device_type TMS1370 = &device_creator; // high voltage version + +// TMS1400 follows the TMS1100, it doubles the ROM size again (4 chapters of 16 pages), and adds a 3-level callstack +// - rotate the view and mirror the OR-mask to get the proper layout of the mpla, the default is identical to tms1100 +// - the opla size is increased from 20 to 32 terms +const device_type TMS1400 = &device_creator; // 28-pin DIP, 11 R pins (TMS1400CR is same, but with TMS1100 pinout) +const device_type TMS1470 = &device_creator; // high voltage version, 1 R pin removed for Vdd + +// TMS1600 adds more I/O to the TMS1400, input pins are doubled with added L1,2,4,8 +// - rotate the view and mirror the OR-mask to get the proper layout of the mpla, the default is identical to tms1100 +// - the opla size is increased from 20 to 32 terms +const device_type TMS1600 = &device_creator; // 40-pin DIP, 16 R pins +const device_type TMS1670 = &device_creator; // high voltage version + +// TMS0980 +// - 64x9bit RAM array at the bottom-left (set up as 144x4) +// - 2048x9bit ROM array at the bottom-left +// - main instructions PLA at the top half, to the right of the midline +// - 64-term microinstructions PLA between the RAM and ROM, supporting 20 microinstructions +// - 16-term output PLA and segment PLA above the RAM (rotate opla 90 degrees) +const device_type TMS0980 = &device_creator; // 28-pin DIP, 9 R pins + +// TMS0970 is a stripped-down version of the TMS0980, itself acting more like a TMS1000 +// - RAM and ROM is exactly the same as TMS1000 +// - main instructions PLA at the top half, to the right of the midline +// - 32-term microinstructions PLA between the RAM and ROM, supporting 15 microinstructions +// - 16-term output PLA and segment PLA above the RAM (rotate opla 90 degrees) +const device_type TMS0970 = &device_creator; // 28-pin DIP, 11 R pins (note: pinout may slightly differ from chip to chip) +const device_type TMS1990 = &device_creator; // 28-pin DIP, ? R pins.. +// TMS0950 is same? + +// TMS0270 on the other hand, is a TMS0980 with earrings and a new hat. The new changes look like a quick afterthought, almost hacky +// - RAM, ROM, and main instructions PLA is exactly the same as TMS0980 +// - 64-term microinstructions PLA between the RAM and ROM, supporting 20 microinstructions plus optional separate lines for custom opcode handling +// - 48-term output PLA above the RAM (rotate opla 90 degrees) +const device_type TMS0270 = &device_creator; // 40-pin DIP, 16 O pins, 8+ R pins (some R pins are internally hooked up to support more I/O) +// newer TMS0270 chips (eg. Speak & Math) have 42 pins +// TMS0260 is similar? except opla is 32 instead of 48 terms + + +// internal memory maps +static ADDRESS_MAP_START(program_11bit_9, AS_PROGRAM, 16, tms1xxx_cpu_device) + AM_RANGE(0x000, 0xfff) AM_ROM +ADDRESS_MAP_END + +static ADDRESS_MAP_START(program_10bit_8, AS_PROGRAM, 8, tms1xxx_cpu_device) + AM_RANGE(0x000, 0x3ff) AM_ROM +ADDRESS_MAP_END + +static ADDRESS_MAP_START(program_11bit_8, AS_PROGRAM, 8, tms1xxx_cpu_device) + AM_RANGE(0x000, 0x7ff) AM_ROM +ADDRESS_MAP_END + +static ADDRESS_MAP_START(program_12bit_8, AS_PROGRAM, 8, tms1xxx_cpu_device) + AM_RANGE(0x000, 0xfff) AM_ROM +ADDRESS_MAP_END + + +static ADDRESS_MAP_START(data_64x4, AS_DATA, 8, tms1xxx_cpu_device) + AM_RANGE(0x00, 0x3f) AM_RAM +ADDRESS_MAP_END + +static ADDRESS_MAP_START(data_128x4, AS_DATA, 8, tms1xxx_cpu_device) + AM_RANGE(0x00, 0x7f) AM_RAM +ADDRESS_MAP_END + +static ADDRESS_MAP_START(data_64x9_as4, AS_DATA, 8, tms1xxx_cpu_device) + AM_RANGE(0x00, 0x7f) AM_RAM + AM_RANGE(0x80, 0x8f) AM_RAM AM_MIRROR(0x70) // DAM +ADDRESS_MAP_END + + +// device definitions +tms1000_cpu_device::tms1000_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : tms1xxx_cpu_device(mconfig, TMS1000, "TMS1000", tag, owner, clock, 8 /* o pins */, 11 /* r pins */, 6 /* pc bits */, 8 /* byte width */, 2 /* x width */, 10 /* prg width */, ADDRESS_MAP_NAME(program_10bit_8), 6 /* data width */, ADDRESS_MAP_NAME(data_64x4), "tms1000", __FILE__) +{ } + +tms1000_cpu_device::tms1000_cpu_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, UINT8 o_pins, UINT8 r_pins, UINT8 pc_bits, UINT8 byte_bits, UINT8 x_bits, int prgwidth, address_map_constructor program, int datawidth, address_map_constructor data, const char *shortname, const char *source) + : tms1xxx_cpu_device(mconfig, type, name, tag, owner, clock, o_pins, r_pins, pc_bits, byte_bits, x_bits, prgwidth, program, datawidth, data, shortname, source) +{ } + +tms1070_cpu_device::tms1070_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : tms1000_cpu_device(mconfig, TMS1070, "TMS1070", tag, owner, clock, 8, 11, 6, 8, 2, 10, ADDRESS_MAP_NAME(program_10bit_8), 6, ADDRESS_MAP_NAME(data_64x4), "tms1070", __FILE__) +{ } + +tms1040_cpu_device::tms1040_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : tms1000_cpu_device(mconfig, TMS1040, "TMS1040", tag, owner, clock, 8, 11, 6, 8, 2, 10, ADDRESS_MAP_NAME(program_10bit_8), 6, ADDRESS_MAP_NAME(data_64x4), "tms1040", __FILE__) +{ } + +tms1200_cpu_device::tms1200_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : tms1000_cpu_device(mconfig, TMS1200, "TMS1200", tag, owner, clock, 8, 13, 6, 8, 2, 10, ADDRESS_MAP_NAME(program_10bit_8), 6, ADDRESS_MAP_NAME(data_64x4), "tms1200", __FILE__) +{ } + + +tms1100_cpu_device::tms1100_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : tms1000_cpu_device(mconfig, TMS1100, "TMS1100", tag, owner, clock, 8, 11, 6, 8, 3, 11, ADDRESS_MAP_NAME(program_11bit_8), 7, ADDRESS_MAP_NAME(data_128x4), "tms1100", __FILE__) +{ } + +tms1100_cpu_device::tms1100_cpu_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, UINT8 o_pins, UINT8 r_pins, UINT8 pc_bits, UINT8 byte_bits, UINT8 x_bits, int prgwidth, address_map_constructor program, int datawidth, address_map_constructor data, const char *shortname, const char *source) + : tms1000_cpu_device(mconfig, type, name, tag, owner, clock, o_pins, r_pins, pc_bits, byte_bits, x_bits, prgwidth, program, datawidth, data, shortname, source) +{ } + +tms1170_cpu_device::tms1170_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : tms1100_cpu_device(mconfig, TMS1170, "TMS1170", tag, owner, clock, 8, 11, 6, 8, 3, 11, ADDRESS_MAP_NAME(program_11bit_8), 7, ADDRESS_MAP_NAME(data_128x4), "tms1170", __FILE__) +{ } + +tms1300_cpu_device::tms1300_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : tms1100_cpu_device(mconfig, TMS1300, "TMS1300", tag, owner, clock, 8, 16, 6, 8, 3, 11, ADDRESS_MAP_NAME(program_11bit_8), 7, ADDRESS_MAP_NAME(data_128x4), "tms1300", __FILE__) +{ } + +tms1370_cpu_device::tms1370_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : tms1100_cpu_device(mconfig, TMS1370, "TMS1370", tag, owner, clock, 8, 16, 6, 8, 3, 11, ADDRESS_MAP_NAME(program_11bit_8), 7, ADDRESS_MAP_NAME(data_128x4), "tms1370", __FILE__) +{ } + + +tms1400_cpu_device::tms1400_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : tms1100_cpu_device(mconfig, TMS1400, "TMS1400", tag, owner, clock, 8, 11, 6, 8, 3, 12, ADDRESS_MAP_NAME(program_12bit_8), 7, ADDRESS_MAP_NAME(data_128x4), "tms1400", __FILE__) +{ } + +tms1400_cpu_device::tms1400_cpu_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, UINT8 o_pins, UINT8 r_pins, UINT8 pc_bits, UINT8 byte_bits, UINT8 x_bits, int prgwidth, address_map_constructor program, int datawidth, address_map_constructor data, const char *shortname, const char *source) + : tms1100_cpu_device(mconfig, type, name, tag, owner, clock, o_pins, r_pins, pc_bits, byte_bits, x_bits, prgwidth, program, datawidth, data, shortname, source) +{ } + +tms1470_cpu_device::tms1470_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : tms1400_cpu_device(mconfig, TMS1470, "TMS1470", tag, owner, clock, 8, 10, 6, 8, 3, 12, ADDRESS_MAP_NAME(program_12bit_8), 7, ADDRESS_MAP_NAME(data_128x4), "tms1470", __FILE__) +{ } + + +tms1600_cpu_device::tms1600_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : tms1400_cpu_device(mconfig, TMS1600, "TMS1600", tag, owner, clock, 8, 16, 6, 8, 3, 12, ADDRESS_MAP_NAME(program_12bit_8), 7, ADDRESS_MAP_NAME(data_128x4), "tms1600", __FILE__) +{ } + +tms1600_cpu_device::tms1600_cpu_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, UINT8 o_pins, UINT8 r_pins, UINT8 pc_bits, UINT8 byte_bits, UINT8 x_bits, int prgwidth, address_map_constructor program, int datawidth, address_map_constructor data, const char *shortname, const char *source) + : tms1400_cpu_device(mconfig, type, name, tag, owner, clock, o_pins, r_pins, pc_bits, byte_bits, x_bits, prgwidth, program, datawidth, data, shortname, source) +{ } + +tms1670_cpu_device::tms1670_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : tms1600_cpu_device(mconfig, TMS1670, "TMS1670", tag, owner, clock, 8, 16, 6, 8, 3, 12, ADDRESS_MAP_NAME(program_12bit_8), 7, ADDRESS_MAP_NAME(data_128x4), "tms1670", __FILE__) +{ } + + +tms0970_cpu_device::tms0970_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : tms1000_cpu_device(mconfig, TMS0970, "TMS0970", tag, owner, clock, 8, 11, 6, 8, 2, 10, ADDRESS_MAP_NAME(program_10bit_8), 6, ADDRESS_MAP_NAME(data_64x4), "tms0970", __FILE__) +{ } + +tms0970_cpu_device::tms0970_cpu_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, UINT8 o_pins, UINT8 r_pins, UINT8 pc_bits, UINT8 byte_bits, UINT8 x_bits, int prgwidth, address_map_constructor program, int datawidth, address_map_constructor data, const char *shortname, const char *source) + : tms1000_cpu_device(mconfig, type, name, tag, owner, clock, o_pins, r_pins, pc_bits, byte_bits, x_bits, prgwidth, program, datawidth, data, shortname, source) +{ } + +tms1990_cpu_device::tms1990_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : tms0970_cpu_device(mconfig, TMS1990, "TMS1990", tag, owner, clock, 8, 11, 6, 8, 2, 10, ADDRESS_MAP_NAME(program_10bit_8), 6, ADDRESS_MAP_NAME(data_64x4), "tms1990", __FILE__) +{ } + + +tms0980_cpu_device::tms0980_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : tms0970_cpu_device(mconfig, TMS0980, "TMS0980", tag, owner, clock, 8, 9, 7, 9, 4, 12, ADDRESS_MAP_NAME(program_11bit_9), 8, ADDRESS_MAP_NAME(data_64x9_as4), "tms0980", __FILE__) +{ } + +tms0980_cpu_device::tms0980_cpu_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, UINT8 o_pins, UINT8 r_pins, UINT8 pc_bits, UINT8 byte_bits, UINT8 x_bits, int prgwidth, address_map_constructor program, int datawidth, address_map_constructor data, const char *shortname, const char *source) + : tms0970_cpu_device(mconfig, type, name, tag, owner, clock, o_pins, r_pins, pc_bits, byte_bits, x_bits, prgwidth, program, datawidth, data, shortname, source) +{ } + + +tms0270_cpu_device::tms0270_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : tms0980_cpu_device(mconfig, TMS0270, "TMS0270", tag, owner, clock, 16, 16, 7, 9, 4, 12, ADDRESS_MAP_NAME(program_11bit_9), 8, ADDRESS_MAP_NAME(data_64x9_as4), "tms0270", __FILE__) + , m_read_ctl(*this) + , m_write_ctl(*this) + , m_write_pdc(*this) +{ } + + +// machine configs +static MACHINE_CONFIG_FRAGMENT(tms1000) + + // microinstructions PLA, output PLA + MCFG_PLA_ADD("mpla", 8, 16, 30) + MCFG_PLA_FILEFORMAT(PLA_FMT_BERKELEY) + MCFG_PLA_ADD("opla", 5, 8, 20) + MCFG_PLA_FILEFORMAT(PLA_FMT_BERKELEY) +MACHINE_CONFIG_END + +machine_config_constructor tms1000_cpu_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME(tms1000); +} + + +static MACHINE_CONFIG_FRAGMENT(tms1400) + + // microinstructions PLA, output PLA + MCFG_PLA_ADD("mpla", 8, 16, 30) + MCFG_PLA_FILEFORMAT(PLA_FMT_BERKELEY) + MCFG_PLA_ADD("opla", 5, 8, 32) + MCFG_PLA_FILEFORMAT(PLA_FMT_BERKELEY) +MACHINE_CONFIG_END + +machine_config_constructor tms1400_cpu_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME(tms1400); +} + + +static MACHINE_CONFIG_FRAGMENT(tms0970) + + // main opcodes PLA, microinstructions PLA, output PLA, segment PLA + MCFG_PLA_ADD("ipla", 8, 15, 18) + MCFG_PLA_FILEFORMAT(PLA_FMT_BERKELEY) + MCFG_PLA_ADD("mpla", 5, 15, 32) + MCFG_PLA_FILEFORMAT(PLA_FMT_BERKELEY) + MCFG_PLA_ADD("opla", 4, 8, 16) + MCFG_PLA_FILEFORMAT(PLA_FMT_BERKELEY) + MCFG_PLA_ADD("spla", 3, 8, 8) + MCFG_PLA_FILEFORMAT(PLA_FMT_BERKELEY) +MACHINE_CONFIG_END + +machine_config_constructor tms0970_cpu_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME(tms0970); +} + + +static MACHINE_CONFIG_FRAGMENT(tms0980) + + // main opcodes PLA, microinstructions PLA, output PLA, segment PLA + MCFG_PLA_ADD("ipla", 9, 22, 24) + MCFG_PLA_FILEFORMAT(PLA_FMT_BERKELEY) + MCFG_PLA_ADD("mpla", 6, 20, 64) + MCFG_PLA_FILEFORMAT(PLA_FMT_BERKELEY) + MCFG_PLA_ADD("opla", 4, 8, 16) + MCFG_PLA_FILEFORMAT(PLA_FMT_BERKELEY) + MCFG_PLA_ADD("spla", 3, 8, 8) + MCFG_PLA_FILEFORMAT(PLA_FMT_BERKELEY) +MACHINE_CONFIG_END + +machine_config_constructor tms0980_cpu_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME(tms0980); +} + + +static MACHINE_CONFIG_FRAGMENT(tms0270) + + // main opcodes PLA, microinstructions PLA, output PLA + MCFG_PLA_ADD("ipla", 9, 22, 24) + MCFG_PLA_FILEFORMAT(PLA_FMT_BERKELEY) + MCFG_PLA_ADD("mpla", 6, 22, 64) + MCFG_PLA_FILEFORMAT(PLA_FMT_BERKELEY) + MCFG_PLA_ADD("opla", 6, 16, 48) + MCFG_PLA_FILEFORMAT(PLA_FMT_BERKELEY) +MACHINE_CONFIG_END + +machine_config_constructor tms0270_cpu_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME(tms0270); +} + + +// disasm +offs_t tms1000_cpu_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE(tms1000); + return CPU_DISASSEMBLE_NAME(tms1000)(this, buffer, pc, oprom, opram, options); +} + +offs_t tms1100_cpu_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE(tms1100); + return CPU_DISASSEMBLE_NAME(tms1100)(this, buffer, pc, oprom, opram, options); +} + +offs_t tms0980_cpu_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE(tms0980); + return CPU_DISASSEMBLE_NAME(tms0980)(this, buffer, pc, oprom, opram, options); +} + +void tms1xxx_cpu_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + switch (entry.index()) + { + case STATE_GENPC: + strprintf(str, "%03X", m_rom_address << ((m_byte_bits > 8) ? 1 : 0)); + break; + } +} + + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +enum +{ + TMS0980_PC=1, TMS0980_SR, TMS0980_PA, TMS0980_PB, + TMS0980_A, TMS0980_X, TMS0980_Y, TMS0980_STATUS +}; + +void tms1xxx_cpu_device::device_start() +{ + m_program = &space(AS_PROGRAM); + m_data = &space(AS_DATA); + + m_o_mask = (1 << m_o_pins) - 1; + m_r_mask = (1 << m_r_pins) - 1; + m_pc_mask = (1 << m_pc_bits) - 1; + m_x_mask = (1 << m_x_bits) - 1; + + // resolve callbacks + m_read_k.resolve_safe(0); + m_write_o.resolve_safe(); + m_write_r.resolve_safe(); + m_power_off.resolve_safe(); + + // zerofill + m_pc = 0; + m_sr = 0; + m_pa = 0; + m_pb = 0; + m_ps = 0; + m_a = 0; + m_x = 0; + m_y = 0; + m_ca = 0; + m_cb = 0; + m_cs = 0; + m_r = 0; + m_o = 0; + m_cki_bus = 0; + m_c4 = 0; + m_p = 0; + m_n = 0; + m_adder_out = 0; + m_carry_in = 0; + m_carry_out = 0; + m_status = 0; + m_status_latch = 0; + m_eac = 0; + m_clatch = 0; + m_add = 0; + m_bl = 0; + + m_ram_in = 0; + m_dam_in = 0; + m_ram_out = 0; + m_ram_address = 0; + m_rom_address = 0; + m_opcode = 0; + m_fixed = 0; + m_micro = 0; + m_subcycle = 0; + + // register for savestates + save_item(NAME(m_pc)); + save_item(NAME(m_sr)); + save_item(NAME(m_pa)); + save_item(NAME(m_pb)); + save_item(NAME(m_ps)); + save_item(NAME(m_a)); + save_item(NAME(m_x)); + save_item(NAME(m_y)); + save_item(NAME(m_ca)); + save_item(NAME(m_cb)); + save_item(NAME(m_cs)); + save_item(NAME(m_r)); + save_item(NAME(m_o)); + save_item(NAME(m_cki_bus)); + save_item(NAME(m_c4)); + save_item(NAME(m_p)); + save_item(NAME(m_n)); + save_item(NAME(m_adder_out)); + save_item(NAME(m_carry_in)); + save_item(NAME(m_carry_out)); + save_item(NAME(m_status)); + save_item(NAME(m_status_latch)); + save_item(NAME(m_eac)); + save_item(NAME(m_clatch)); + save_item(NAME(m_add)); + save_item(NAME(m_bl)); + + save_item(NAME(m_ram_in)); + save_item(NAME(m_dam_in)); + save_item(NAME(m_ram_out)); + save_item(NAME(m_ram_address)); + save_item(NAME(m_rom_address)); + save_item(NAME(m_opcode)); + save_item(NAME(m_fixed)); + save_item(NAME(m_micro)); + save_item(NAME(m_subcycle)); + + // register state for debugger + state_add(TMS0980_PC, "PC", m_pc ).formatstr("%02X"); + state_add(TMS0980_SR, "SR", m_sr ).formatstr("%01X"); + state_add(TMS0980_PA, "PA", m_pa ).formatstr("%01X"); + state_add(TMS0980_PB, "PB", m_pb ).formatstr("%01X"); + state_add(TMS0980_A, "A", m_a ).formatstr("%01X"); + state_add(TMS0980_X, "X", m_x ).formatstr("%01X"); + state_add(TMS0980_Y, "Y", m_y ).formatstr("%01X"); + state_add(TMS0980_STATUS, "STATUS", m_status).formatstr("%01X"); + + state_add(STATE_GENPC, "curpc", m_rom_address).formatstr("%03X").noshow(); + state_add(STATE_GENFLAGS, "GENFLAGS", m_sr).formatstr("%8s").noshow(); + + m_icountptr = &m_icount; +} + +void tms0270_cpu_device::device_start() +{ + // common init + tms1xxx_cpu_device::device_start(); + + m_read_ctl.resolve_safe(0); + m_write_ctl.resolve_safe(); + m_write_pdc.resolve_safe(); + + // zerofill + m_r_prev = 0; + m_chipsel = 0; + m_ctl_dir = 0; + m_ctl_out = 0; + m_pdc = -1; // ! + + m_o_latch_low = 0; + m_o_latch = 0; + m_o_latch_prev = 0; + + // register for savestates + save_item(NAME(m_r_prev)); + save_item(NAME(m_chipsel)); + save_item(NAME(m_ctl_dir)); + save_item(NAME(m_ctl_out)); + save_item(NAME(m_pdc)); + + save_item(NAME(m_o_latch_low)); + save_item(NAME(m_o_latch)); + save_item(NAME(m_o_latch_prev)); +} + + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void tms1xxx_cpu_device::device_reset() +{ + m_pa = 0xf; + m_pb = 0xf; + m_pc = 0; + m_ca = 0; + m_cb = 0; + m_cs = 0; + + m_eac = 0; + m_bl = 0; + m_add = 0; + + m_opcode = 0; + m_micro = 0; + m_fixed = 0; + + m_subcycle = 0; + + // clear outputs + m_r = 0; + m_write_r(0, m_r & m_r_mask, 0xffff); + write_o_output(0); + m_write_r(0, m_r & m_r_mask, 0xffff); + m_power_off(0); +} + + +void tms1000_cpu_device::device_reset() +{ + // common reset + tms1xxx_cpu_device::device_reset(); + + // pre-decode instructionset + m_fixed_decode.resize(0x100); + memset(&m_fixed_decode[0], 0, 0x100*sizeof(UINT32)); + m_micro_decode.resize(0x100); + memset(&m_micro_decode[0], 0, 0x100*sizeof(UINT32)); + + for (int op = 0; op < 0x100; op++) + { + // _____ _____ ______ _____ ______ _____ _____ _____ _____ + const UINT32 md[16] = { M_STSL, M_AUTY, M_AUTA, M_CIN, M_C8, M_NE, M_CKN, M_15TN, M_MTN, M_NATN, M_ATN, M_MTP, M_YTP, M_CKP, M_CKM, M_STO }; + UINT16 mask = m_mpla->read(op); + mask ^= 0x3fc8; // invert active-negative + + for (int bit = 0; bit < 16; bit++) + if (mask & (1 << bit)) + m_micro_decode[op] |= md[bit]; + } + + // the fixed instruction set is not programmable + m_fixed_decode[0x00] = F_COMX; + m_fixed_decode[0x0a] = F_TDO; + m_fixed_decode[0x0b] = F_CLO; + m_fixed_decode[0x0c] = F_RSTR; + m_fixed_decode[0x0d] = F_SETR; + m_fixed_decode[0x0f] = F_RETN; + + for (int i = 0x10; i < 0x20; i++) m_fixed_decode[i] = F_LDP; + for (int i = 0x30; i < 0x34; i++) m_fixed_decode[i] = F_SBIT; + for (int i = 0x34; i < 0x38; i++) m_fixed_decode[i] = F_RBIT; + for (int i = 0x3c; i < 0x40; i++) m_fixed_decode[i] = F_LDX; + + for (int i = 0x80; i < 0xc0; i++) m_fixed_decode[i] = F_BR; + for (int i = 0xc0; i < 0x100; i++) m_fixed_decode[i] = F_CALL; +} + +void tms1100_cpu_device::device_reset() +{ + tms1000_cpu_device::device_reset(); + + // small differences in 00-3f area + m_fixed_decode[0x00] = 0; + m_fixed_decode[0x09] = F_COMX8; // ! + m_fixed_decode[0x0b] = F_COMC; + + for (int i = 0x28; i < 0x30; i++) m_fixed_decode[i] = F_LDX; + for (int i = 0x3c; i < 0x40; i++) m_fixed_decode[i] = 0; +} + +void tms1400_cpu_device::device_reset() +{ + tms1100_cpu_device::device_reset(); + + // small differences in 00-3f area + m_fixed_decode[0x0b] = F_TPC; +} + + +void tms0970_cpu_device::device_reset() +{ + // common reset + tms1xxx_cpu_device::device_reset(); + + // pre-decode instructionset + m_fixed_decode.resize(0x100); + memset(&m_fixed_decode[0], 0, 0x100*sizeof(UINT32)); + m_micro_decode.resize(0x100); + memset(&m_micro_decode[0], 0, 0x100*sizeof(UINT32)); + + for (int op = 0; op < 0x100; op++) + { + // upper half of the opcodes is always branch/call + if (op & 0x80) + m_fixed_decode[op] = (op & 0x40) ? F_CALL: F_BR; + + // 5 output bits select a microinstruction index + UINT32 imask = m_ipla->read(op); + UINT8 msel = imask & 0x1f; + + // but if (from bottom to top) term 1 is active and output bit 5 is 0, R2,R4-R7 directly select a microinstruction index + if (imask & 0x40 && (imask & 0x20) == 0) + msel = (op & 0xf) | (op >> 1 & 0x10); + + msel = BITSWAP8(msel,7,6,5,0,1,2,3,4); // lines are reversed + UINT32 mmask = m_mpla->read(msel); + mmask ^= 0x09fe; // invert active-negative + + // _____ _____ _____ _____ ______ _____ ______ _____ _____ + const UINT32 md[15] = { M_CKM, M_CKP, M_YTP, M_MTP, M_ATN, M_NATN, M_MTN, M_15TN, M_CKN, M_NE, M_C8, M_CIN, M_AUTA, M_AUTY, M_STO }; + + for (int bit = 0; bit < 15; bit++) + if (mmask & (1 << bit)) + m_micro_decode[op] |= md[bit]; + + // the other ipla terms each select a fixed instruction + const UINT32 id[8] = { F_LDP, F_TDO, F_COMX, F_LDX, F_SBIT, F_RBIT, F_SETR, F_RETN }; + + for (int bit = 0; bit < 8; bit++) + if (imask & (0x80 << bit)) + m_fixed_decode[op] |= id[bit]; + } +} + + +UINT32 tms0980_cpu_device::decode_micro(UINT8 sel) +{ + UINT32 decode = 0; + + sel = BITSWAP8(sel,7,6,0,1,2,3,4,5); // lines are reversed + UINT32 mask = m_mpla->read(sel); + mask ^= 0x43fc3; // invert active-negative + + // M_RSTR is specific to TMS02x0, it redirects to F_RSTR + // M_UNK1 is specific to TMS0270, unknown yet + // _______ ______ _____ _____ _____ _____ ______ _____ ______ _____ _____ + const UINT32 md[22] = { M_NDMTP, M_DMTP, M_AUTY, M_AUTA, M_CKM, M_SSE, M_CKP, M_YTP, M_MTP, M_ATN, M_NATN, M_MTN, M_15TN, M_CKN, M_NE, M_C8, M_SSS, M_CME, M_CIN, M_STO, M_RSTR, M_UNK1 }; + + for (int bit = 0; bit < 22 && bit < m_mpla->outputs(); bit++) + if (mask & (1 << bit)) + decode |= md[bit]; + + return decode; +} + +void tms0980_cpu_device::device_reset() +{ + // common reset + tms1xxx_cpu_device::device_reset(); + + // pre-decode instructionset + m_fixed_decode.resize(0x200); + memset(&m_fixed_decode[0], 0, 0x200*sizeof(UINT32)); + m_micro_decode.resize(0x200); + memset(&m_micro_decode[0], 0, 0x200*sizeof(UINT32)); + + for (int op = 0; op < 0x200; op++) + { + // upper half of the opcodes is always branch/call + if (op & 0x100) + m_fixed_decode[op] = (op & 0x80) ? F_CALL: F_BR; + + UINT32 imask = m_ipla->read(op); + + // 6 output bits select a microinstruction index + m_micro_decode[op] = decode_micro(imask & 0x3f); + + // the other ipla terms each select a fixed instruction + const UINT32 id[15] = { F_LDP, F_SBL, F_OFF, F_RBIT, F_SAL, F_XDA, F_REAC, F_SETR, F_RETN, F_SBIT, F_TDO, F_COMX8, F_COMX, F_LDX, F_SEAC }; + + for (int bit = 0; bit < 15; bit++) + if (imask & (0x80 << bit)) + m_fixed_decode[op] |= id[bit]; + } + + // like on TMS0970, one of the terms directly select a microinstruction index (via R4-R8), + // but it can't be pre-determined when it's active + m_micro_direct.resize(0x40); + memset(&m_micro_decode[0], 0, 0x40*sizeof(UINT32)); + + for (int op = 0; op < 0x40; op++) + m_micro_direct[op] = decode_micro(op); +} + +void tms0270_cpu_device::device_reset() +{ + // common reset + tms0980_cpu_device::device_reset(); + + m_o_latch_low = 0; + m_o_latch = 0; + m_o_latch_prev = 0; +} + + + +//------------------------------------------------- +// program counter/opcode decode +//------------------------------------------------- + +void tms1xxx_cpu_device::next_pc() +{ + // The program counter is a LFSR. To put it simply, the feedback bit is a XOR of the two highest bits, + // but it makes an exception when all low bits are set (eg. in TMS1000 case, when PC is 0x1f or 0x3f). + int high = 1 << (m_pc_bits - 1); + int fb = (m_pc << 1 & high) == (m_pc & high); + + if (m_pc == (m_pc_mask >> 1)) + fb = 1; + else if (m_pc == m_pc_mask) + fb = 0; + + m_pc = (m_pc << 1 | fb) & m_pc_mask; +} + +void tms1xxx_cpu_device::read_opcode() +{ + debugger_instruction_hook(this, m_rom_address); + m_opcode = m_program->read_byte(m_rom_address); + m_c4 = BITSWAP8(m_opcode,7,6,5,4,0,1,2,3) & 0xf; // opcode operand is bitswapped for most opcodes + + m_fixed = m_fixed_decode[m_opcode]; + m_micro = m_micro_decode[m_opcode]; + + next_pc(); +} + +void tms0980_cpu_device::read_opcode() +{ + debugger_instruction_hook(this, m_rom_address << 1); + m_opcode = m_program->read_word(m_rom_address << 1) & 0x1ff; + m_c4 = BITSWAP8(m_opcode,7,6,5,4,0,1,2,3) & 0xf; // opcode operand is bitswapped for most opcodes + + m_fixed = m_fixed_decode[m_opcode]; + + // if ipla term 0 is active, R4-R8 directly select a microinstruction index when R0 or R0^BL is 0 + int r0 = m_opcode >> 8 & 1; + if (m_ipla->read(m_opcode) & 0x40 && !((r0 & m_bl) ^ r0)) + m_micro = m_micro_direct[m_opcode & 0x3f]; + else + m_micro = m_micro_decode[m_opcode]; + + next_pc(); +} + +void tms0270_cpu_device::read_opcode() +{ + tms0980_cpu_device::read_opcode(); + + // RSTR is on the mpla + if (m_micro & M_RSTR) + m_fixed |= F_RSTR; +} + + + +//------------------------------------------------- +// i/o handling +//------------------------------------------------- + +void tms1xxx_cpu_device::write_o_output(UINT8 index) +{ + // a hardcoded table is supported if the output pla is unknown + m_o = (m_output_pla_table == NULL) ? m_opla->read(index) : m_output_pla_table[index]; + m_write_o(0, m_o & m_o_mask, 0xffff); +} + +void tms0970_cpu_device::write_o_output(UINT8 index) +{ + m_o = m_spla->read(index); + m_write_o(0, m_o & m_o_mask, 0xffff); +} + + +void tms0270_cpu_device::dynamic_output() +{ + // R11: TMS5100 CTL port direction (0=read from TMS5100, 1=write to TMS5100) + m_ctl_dir = m_r >> 11 & 1; + + // R12: chip select (off=display via OPLA, on=TMS5100 via ACC/CKB) + m_chipsel = m_r >> 12 & 1; + + if (m_chipsel) + { + // ACC via SEG B,C,D,G: TMS5100 CTL pins + if (m_ctl_dir && m_a != m_ctl_out) + { + m_ctl_out = m_a; + m_write_ctl(0, m_ctl_out, 0xff); + } + + // R10 via SEG E: TMS5100 PDC pin + if (m_pdc != (m_r >> 10 & 1)) + { + m_pdc = m_r >> 10 & 1; + m_write_pdc(m_pdc); + } + } + else + { + // standard O-output + if (m_o_latch != m_o_latch_prev) + { + write_o_output(m_o_latch); + m_o_latch_prev = m_o_latch; + } + } + + // standard R-output + if (m_r != m_r_prev) + { + m_write_r(0, m_r & m_r_mask, 0xffff); + m_r_prev = m_r; + } +} + + +UINT8 tms1xxx_cpu_device::read_k_input() +{ + // K1,2,4,8 (KC test pin is not emulated) + return m_read_k(0, 0xff) & 0xf; +} + +UINT8 tms0980_cpu_device::read_k_input() +{ + UINT8 k = m_read_k(0, 0xff) & 0x1f; + UINT8 k3 = (k & 0x10) ? 3: 0; // the TMS0980 K3 line is simply K1|K2 + return (k & 0xf) | k3; +} + +UINT8 tms0270_cpu_device::read_k_input() +{ + // external: TMS5100 CTL port via SEG B,C,D,G + if (m_chipsel) + return (m_ctl_dir) ? m_ctl_out : m_read_ctl(0, 0xff) & 0xf; + + // standard K-input otherwise + UINT8 k = m_read_k(0, 0xff) & 0x1f; + return (k & 0x10) ? 0xf : k; // the TMS0270 KF line asserts all K-inputs +} + + +void tms1xxx_cpu_device::set_cki_bus() +{ + switch (m_opcode & 0xf8) + { + // 00001XXX: K-inputs + case 0x08: + m_cki_bus = read_k_input(); + break; + + // 0011XXXX: select bit + case 0x30: case 0x38: + m_cki_bus = 1 << (m_c4 >> 2) ^ 0xf; + break; + + // 01XXXXXX: constant + case 0x00: // R2,3,4 are NANDed with eachother, and then ORed with R1, making 00000XXX valid too + case 0x40: case 0x48: case 0x50: case 0x58: case 0x60: case 0x68: case 0x70: case 0x78: + m_cki_bus = m_c4; + break; + + default: + m_cki_bus = 0; + break; + } +} + +void tms0980_cpu_device::set_cki_bus() +{ + switch (m_opcode & 0x1f8) + { + // 000001XXX: K-inputs + case 0x008: + m_cki_bus = read_k_input(); + break; + + // 0X0100XXX: select bit + case 0x020: case 0x0a0: + m_cki_bus = 1 << (m_c4 >> 2) ^ 0xf; + break; + + // 0X1XXXXXX: constant + case 0x040: case 0x048: case 0x050: case 0x058: case 0x060: case 0x068: case 0x070: case 0x078: + case 0x0c0: case 0x0c8: case 0x0d0: case 0x0d8: case 0x0e0: case 0x0e8: case 0x0f0: case 0x0f8: + m_cki_bus = m_c4; + break; + + default: + m_cki_bus = 0; + break; + } +} + + + +//------------------------------------------------- +// fixed opcode set +//------------------------------------------------- + +// handle branches: + +// TMS1000/common +// note: add(latch) and bl(branch latch) are specific to 0980 series, +// c(chapter) bits are specific to 1100(and 1400) series + +void tms1xxx_cpu_device::op_br() +{ + // BR/BL: conditional branch + if (m_status) + { + if (m_clatch == 0) + m_pa = m_pb; + m_ca = m_cb; + m_pc = m_opcode & m_pc_mask; + } +} + +void tms1xxx_cpu_device::op_call() +{ + // CALL/CALLL: conditional call + if (m_status) + { + UINT8 prev_pa = m_pa; + + if (m_clatch == 0) + { + m_clatch = 1; + m_sr = m_pc; + m_pa = m_pb; + m_cs = m_ca; + } + m_ca = m_cb; + m_pb = prev_pa; + m_pc = m_opcode & m_pc_mask; + } +} + +void tms1xxx_cpu_device::op_retn() +{ + // RETN: return from subroutine + if (m_clatch == 1) + { + m_clatch = 0; + m_pc = m_sr; + m_ca = m_cs; + } + m_add = 0; + m_bl = 0; + m_pa = m_pb; +} + + +// TMS1400-specific + +void tms1400_cpu_device::op_br() +{ + // BR/BL: conditional branch + if (m_status) + { + m_pa = m_pb; // don't care about clatch + m_ca = m_cb; + m_pc = m_opcode & m_pc_mask; + } +} + +void tms1400_cpu_device::op_call() +{ + // CALL/CALLL: conditional call + if (m_status) + { + // 3-level stack, mask clatch 3 bits (no need to mask others) + m_clatch = (m_clatch << 1 | 1) & 7; + + m_sr = m_sr << m_pc_bits | m_pc; + m_pc = m_opcode & m_pc_mask; + + m_ps = m_ps << 4 | m_pa; + m_pa = m_pb; + + m_cs = m_cs << 2 | m_ca; + m_ca = m_cb; + } + else + { + m_pb = m_pa; + m_cb = m_ca; + } +} + +void tms1400_cpu_device::op_retn() +{ + // RETN: return from subroutine + if (m_clatch & 1) + { + m_clatch >>= 1; + + m_pc = m_sr & m_pc_mask; + m_sr >>= m_pc_bits; + + m_pa = m_pb = m_ps & 0xf; + m_ps >>= 4; + + m_ca = m_cb = m_cs & 3; + m_cs >>= 2; + } +} + + +// handle other: + +// TMS1000/common + +void tms1xxx_cpu_device::op_sbit() +{ + // SBIT: set memory bit + if (m_ram_out == -1) + m_ram_out = m_ram_in; + m_ram_out |= (m_cki_bus ^ 0xf); +} + +void tms1xxx_cpu_device::op_rbit() +{ + // RBIT: reset memory bit + if (m_ram_out == -1) + m_ram_out = m_ram_in; + m_ram_out &= m_cki_bus; +} + +void tms1xxx_cpu_device::op_setr() +{ + // SETR: set one R-output line + m_r = m_r | (1 << m_y); + m_write_r(0, m_r & m_r_mask, 0xffff); +} + +void tms1xxx_cpu_device::op_rstr() +{ + // RSTR: reset one R-output line + m_r = m_r & ~(1 << m_y); + m_write_r(0, m_r & m_r_mask, 0xffff); +} + +void tms1xxx_cpu_device::op_tdo() +{ + // TDO: transfer accumulator and status latch to O-output + write_o_output(m_status_latch << 4 | m_a); +} + +void tms1xxx_cpu_device::op_clo() +{ + // CLO: clear O-output + write_o_output(0); +} + +void tms1xxx_cpu_device::op_ldx() +{ + // LDX: load X register with (x_bits) constant + m_x = m_c4 >> (4-m_x_bits); +} + +void tms1xxx_cpu_device::op_comx() +{ + // COMX: complement X register + m_x ^= m_x_mask; +} + +void tms1xxx_cpu_device::op_comx8() +{ + // COMX8: complement MSB of X register + // note: on TMS1100, the mnemonic is simply called "COMX" + m_x ^= 1 << (m_x_bits-1); +} + +void tms1xxx_cpu_device::op_ldp() +{ + // LDP: load page buffer with constant + m_pb = m_c4; +} + + +// TMS1100-specific + +void tms1100_cpu_device::op_setr() +{ + // SETR: same, but X register MSB must be clear + if (~m_x & (1 << (m_x_bits-1))) + tms1xxx_cpu_device::op_setr(); +} + +void tms1100_cpu_device::op_rstr() +{ + // RSTR: same, but X register MSB must be clear + if (~m_x & (1 << (m_x_bits-1))) + tms1xxx_cpu_device::op_rstr(); +} + +void tms1xxx_cpu_device::op_comc() +{ + // COMC: complement chapter buffer + m_cb ^= 1; +} + + +// TMS1400-specific + +void tms1xxx_cpu_device::op_tpc() +{ + // TPC: transfer page buffer to chapter buffer + m_cb = m_pb & 3; +} + + +// TMS0970-specific (and possibly child classes) +void tms0970_cpu_device::op_setr() +{ + // SETR: set output register + // DDIG line is a coincidence between the selected output pla row(s) and segment pla row(s) + int ddig = (m_opla->read(m_a) & m_o) ? 0 : 1; + m_r = (m_r & ~(1 << m_y)) | (ddig << m_y); +} + +void tms0970_cpu_device::op_tdo() +{ + // TDO: transfer digits to output + write_o_output(m_a & 0x7); + m_write_r(0, m_r & m_r_mask, 0xffff); +} + + +// TMS0980-specific (and possibly child classes) + +void tms0980_cpu_device::op_comx() +{ + // COMX: complement X register, but not the MSB + m_x ^= (m_x_mask >> 1); +} + +void tms1xxx_cpu_device::op_xda() +{ + // XDA: exchange DAM and A + // note: setting A to DAM is done with DMTP and AUTA during this instruction + m_ram_address |= (0x10 << (m_x_bits-1)); +} + +void tms1xxx_cpu_device::op_off() +{ + // OFF: request auto power-off + m_power_off(1); +} + +void tms1xxx_cpu_device::op_seac() +{ + // SEAC: set end around carry + m_eac = 1; +} + +void tms1xxx_cpu_device::op_reac() +{ + // REAC: reset end around carry + m_eac = 0; +} + +void tms1xxx_cpu_device::op_sal() +{ + // SAL: set add latch (reset is done with RETN) + m_add = 1; +} + +void tms1xxx_cpu_device::op_sbl() +{ + // SBL: set branch latch (reset is done with RETN) + m_bl = 1; +} + + +// TMS0270-specific + +void tms0270_cpu_device::op_setr() +{ + // same as default, but handle write to output in dynamic_output + m_r = m_r | (1 << m_y); +} + +void tms0270_cpu_device::op_rstr() +{ + // same as default, but handle write to output in dynamic_output + m_r = m_r & ~(1 << m_y); +} + +void tms0270_cpu_device::op_tdo() +{ + // TDO: transfer data out + if (m_status) + m_o_latch_low = m_a; + else + m_o_latch = m_o_latch_low | (m_a << 4 & 0x30); + + // write to output is done in dynamic_output +} + + + +//------------------------------------------------- +// execute_run +//------------------------------------------------- + +void tms1xxx_cpu_device::execute_run() +{ + do + { + m_icount--; + switch (m_subcycle) + { + case 0: + // fetch: rom address 1/2 + + // execute: br/call 2/2 + if (m_fixed & F_BR) op_br(); + if (m_fixed & F_CALL) op_call(); + if (m_fixed & F_RETN) op_retn(); + + // execute: k input valid, read ram, clear alu inputs + dynamic_output(); + set_cki_bus(); + m_ram_in = m_data->read_byte(m_ram_address) & 0xf; + m_dam_in = m_data->read_byte(m_ram_address | (0x10 << (m_x_bits-1))) & 0xf; + m_p = 0; + m_n = 0; + m_carry_in = 0; + + break; + + case 1: + // fetch: rom address 2/2 + m_rom_address = (m_ca << (m_pc_bits+4)) | (m_pa << m_pc_bits) | m_pc; + + // execute: update alu inputs + // N inputs + if (m_micro & M_15TN) m_n |= 0xf; + if (m_micro & M_ATN) m_n |= m_a; + if (m_micro & M_NATN) m_n |= (~m_a & 0xf); + if (m_micro & M_CKN) m_n |= m_cki_bus; + if (m_micro & M_MTN) m_n |= m_ram_in; + + // P inputs + if (m_micro & M_CKP) m_p |= m_cki_bus; + if (m_micro & M_MTP) m_p |= m_ram_in; + if (m_micro & M_YTP) m_p |= m_y; + if (m_micro & M_DMTP) m_p |= m_dam_in; + if (m_micro & M_NDMTP) m_p |= (~m_dam_in & 0xf); + + // carry input + if (m_micro & M_CIN) m_carry_in |= 1; + if (m_micro & M_SSS) m_carry_in |= m_eac; + + break; + + case 2: + { + // fetch: nothing + + // execute: perform alu logic + // note: officially, only 1 alu operation is allowed per opcode + m_adder_out = m_p + m_n + m_carry_in; + int carry_out = m_adder_out >> 4 & 1; + int status = 1; + m_ram_out = -1; + + if (m_micro & M_C8) status &= carry_out; + if (m_micro & M_NE) status &= (m_n != m_p); // COMP + if (m_micro & M_CKM) m_ram_out = m_cki_bus; + + // special status circuit + if (m_micro & M_SSE) + { + m_eac = m_carry_out; + if (m_add) + m_eac |= carry_out; + } + m_carry_out = carry_out; + + if (m_micro & M_STO || (m_micro & M_CME && m_eac == m_add)) + m_ram_out = m_a; + + // handle the other fixed opcodes here + if (m_fixed & F_SBIT) op_sbit(); + if (m_fixed & F_RBIT) op_rbit(); + if (m_fixed & F_SETR) op_setr(); + if (m_fixed & F_RSTR) op_rstr(); + if (m_fixed & F_TDO) op_tdo(); + if (m_fixed & F_CLO) op_clo(); + if (m_fixed & F_LDX) op_ldx(); + if (m_fixed & F_COMX) op_comx(); + if (m_fixed & F_COMX8) op_comx8(); + if (m_fixed & F_LDP) op_ldp(); + if (m_fixed & F_COMC) op_comc(); + if (m_fixed & F_TPC) op_tpc(); + if (m_fixed & F_OFF) op_off(); + if (m_fixed & F_SEAC) op_seac(); + if (m_fixed & F_REAC) op_reac(); + if (m_fixed & F_SAL) op_sal(); + if (m_fixed & F_SBL) op_sbl(); + if (m_fixed & F_XDA) op_xda(); + + // after fixed opcode handling: store status, write ram + m_status = status; + if (m_ram_out != -1) + m_data->write_byte(m_ram_address, m_ram_out); + + break; + } + + case 3: + // fetch: update pc, ram address 1/2 + // execute: register store 1/2 + break; + + case 4: + // execute: register store 2/2 + if (m_micro & M_AUTA) m_a = m_adder_out & 0xf; + if (m_micro & M_AUTY) m_y = m_adder_out & 0xf; + if (m_micro & M_STSL) m_status_latch = m_status; + + // fetch: update pc, ram address 2/2 + read_opcode(); + m_ram_address = m_x << 4 | m_y; + break; + + case 5: + // fetch: instruction decode (handled above, before next_pc) + // execute: br/call 1/2 + break; + } + m_subcycle = (m_subcycle + 1) % 6; + } while (m_icount > 0); +} diff --git a/src/devices/cpu/tms0980/tms0980.h b/src/devices/cpu/tms0980/tms0980.h new file mode 100644 index 00000000000..fb9c3690fdd --- /dev/null +++ b/src/devices/cpu/tms0980/tms0980.h @@ -0,0 +1,472 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol, hap +/* + + TMS0980/TMS1000-family MCU cores + +*/ + +#ifndef _TMS0980_H_ +#define _TMS0980_H_ + +#include "emu.h" +#include "machine/pla.h" + + +// K input pins +#define MCFG_TMS1XXX_READ_K_CB(_devcb) \ + tms1xxx_cpu_device::set_read_k_callback(*device, DEVCB_##_devcb); + +// O/Segment output pins +#define MCFG_TMS1XXX_WRITE_O_CB(_devcb) \ + tms1xxx_cpu_device::set_write_o_callback(*device, DEVCB_##_devcb); + +// Use this if the output PLA is unknown: +// If the microinstructions (or other) PLA is unknown, try using one from another romset. +#define MCFG_TMS1XXX_OUTPUT_PLA(_pla) \ + tms1xxx_cpu_device::set_output_pla(*device, _pla); + +// R output pins (also called D on some chips) +#define MCFG_TMS1XXX_WRITE_R_CB(_devcb) \ + tms1xxx_cpu_device::set_write_r_callback(*device, DEVCB_##_devcb); + +// OFF request on TMS0980 and up +#define MCFG_TMS1XXX_POWER_OFF_CB(_devcb) \ + tms1xxx_cpu_device::set_power_off_callback(*device, DEVCB_##_devcb); + + +// TMS0270 was designed to interface with TMS5100, set it up at driver level +#define MCFG_TMS0270_READ_CTL_CB(_devcb) \ + tms0270_cpu_device::set_read_ctl_callback(*device, DEVCB_##_devcb); + +#define MCFG_TMS0270_WRITE_CTL_CB(_devcb) \ + tms0270_cpu_device::set_write_ctl_callback(*device, DEVCB_##_devcb); + +#define MCFG_TMS0270_WRITE_PDC_CB(_devcb) \ + tms0270_cpu_device::set_write_pdc_callback(*device, DEVCB_##_devcb); + + +// pinout reference + +/* + + ____ ____ ____ ____ + R8 1 |* \_/ | 28 R7 R0 1 |* \_/ | 28 Vss + R9 2 | | 27 R6 R1 2 | | 27 OSC2 + R10 3 | | 26 R5 R2 3 | | 26 OSC1 + Vdd 4 | | 25 R4 R3 4 | | 25 O0 + K1 5 | | 24 R3 R4 5 | | 24 O1 + K2 6 | TMS1000 | 23 R2 R5 6 | | 23 O2 + K4 7 | TMS1070 | 22 R1 R6 7 | TMS1400 | 22 O3 + K8 8 | TMS1100 | 21 R0 R7 8 | | 21 O4 + INIT 9 | TMS1170 | 20 Vss R8 9 | | 20 O5 + O7 10 | | 19 OSC2 R9 10 | | 19 O6 + O6 11 | | 18 OSC1 R10 11 | | 18 O7 + O5 12 | | 17 O0 Vdd 12 | | 17 K8 + O4 13 | | 16 O1 INIT 13 | | 16 K4 + O3 14 |___________| 15 O2 K1 14 |___________| 15 K2 + + + ____ ____ + R2 1 |* \_/ | 28 R3 + R1 2 | | 27 R4 + R0 3 | | 26 R5 + ? 4 | | 25 R6 + Vdd 5 | | 24 R7 + K3 6 | | 23 R8 + K8 7 | TMS0980 | 22 ? + K4 8 | | 21 ? + K2 9 | | 20 Vss + K1 10 | | 19 ? + O7 11 | | 18 O0 + O6 12 | | 17 O1 + O5 13 | | 16 O2 + O4 14 |___________| 15 O3 + + note: TMS0980 official pin names for R0-R8 is D9-D1, O0-O7 is S(A-G,DP) + +*/ + + +class tms1xxx_cpu_device : public cpu_device +{ +public: + // construction/destruction + tms1xxx_cpu_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, UINT8 o_pins, UINT8 r_pins, UINT8 pc_bits, UINT8 byte_bits, UINT8 x_bits, int prgwidth, address_map_constructor program, int datawidth, address_map_constructor data, const char *shortname, const char *source) + : cpu_device(mconfig, type, name, tag, owner, clock, shortname, source) + , m_program_config("program", ENDIANNESS_BIG, byte_bits > 8 ? 16 : 8, prgwidth, 0, program) + , m_data_config("data", ENDIANNESS_BIG, 8, datawidth, 0, data) + , m_mpla(*this, "mpla") + , m_ipla(*this, "ipla") + , m_opla(*this, "opla") + , m_spla(*this, "spla") + , m_o_pins(o_pins) + , m_r_pins(r_pins) + , m_pc_bits(pc_bits) + , m_byte_bits(byte_bits) + , m_x_bits(x_bits) + , m_output_pla_table(NULL) + , m_read_k(*this) + , m_write_o(*this) + , m_write_r(*this) + , m_power_off(*this) + { } + + // static configuration helpers + template static devcb_base &set_read_k_callback(device_t &device, _Object object) { return downcast(device).m_read_k.set_callback(object); } + template static devcb_base &set_write_o_callback(device_t &device, _Object object) { return downcast(device).m_write_o.set_callback(object); } + template static devcb_base &set_write_r_callback(device_t &device, _Object object) { return downcast(device).m_write_r.set_callback(object); } + template static devcb_base &set_power_off_callback(device_t &device, _Object object) { return downcast(device).m_power_off.set_callback(object); } + static void set_output_pla(device_t &device, const UINT16 *output_pla) { downcast(device).m_output_pla_table = output_pla; } + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_execute_interface overrides + virtual UINT32 execute_min_cycles() const { return 1; } + virtual UINT32 execute_max_cycles() const { return 6; } + virtual UINT32 execute_input_lines() const { return 1; } + virtual void execute_run(); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const { return(spacenum == AS_PROGRAM) ? &m_program_config : ((spacenum == AS_DATA) ? &m_data_config : NULL); } + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const { return 1; } + virtual UINT32 disasm_max_opcode_bytes() const { return 1; } + + void state_string_export(const device_state_entry &entry, std::string &str); + + void next_pc(); + + virtual void write_o_output(UINT8 index); + virtual UINT8 read_k_input(); + virtual void set_cki_bus(); + virtual void dynamic_output() { ; } // not used by default + virtual void read_opcode(); + + virtual void op_br(); + virtual void op_call(); + virtual void op_retn(); + + virtual void op_sbit(); + virtual void op_rbit(); + virtual void op_setr(); + virtual void op_rstr(); + virtual void op_tdo(); + virtual void op_clo(); + virtual void op_ldx(); + virtual void op_comx(); + virtual void op_comx8(); + virtual void op_ldp(); + + virtual void op_comc(); + virtual void op_tpc(); + virtual void op_xda(); + virtual void op_off(); + virtual void op_seac(); + virtual void op_reac(); + virtual void op_sal(); + virtual void op_sbl(); + + address_space_config m_program_config; + address_space_config m_data_config; + + optional_device m_mpla; + optional_device m_ipla; + optional_device m_opla; + optional_device m_spla; + + UINT8 m_pc; // 6 or 7-bit program counter + UINT32 m_sr; // 6 or 7-bit subroutine return register(s) + UINT8 m_pa; // 4-bit page address register + UINT8 m_pb; // 4-bit page buffer register + UINT16 m_ps; // 4-bit page subroutine register(s) + UINT8 m_a; // 4-bit accumulator + UINT8 m_x; // 2,3,or 4-bit RAM X register + UINT8 m_y; // 4-bit RAM Y register + UINT8 m_ca; // chapter address register + UINT8 m_cb; // chapter buffer register + UINT16 m_cs; // chapter subroutine register(s) + UINT16 m_r; + UINT16 m_o; + UINT8 m_cki_bus; + UINT8 m_c4; + UINT8 m_p; // 4-bit adder p(lus)-input + UINT8 m_n; // 4-bit adder n(egative)-input + UINT8 m_adder_out; // adder result + UINT8 m_carry_in; // adder carry-in bit + UINT8 m_carry_out; // adder carry-out bit + UINT8 m_status; + UINT8 m_status_latch; + UINT8 m_eac; // end around carry bit + UINT8 m_clatch; // call latch bit(s) + UINT8 m_add; // add latch bit + UINT8 m_bl; // branch latch bit + + UINT8 m_ram_in; + UINT8 m_dam_in; + int m_ram_out; // signed! + UINT8 m_ram_address; + UINT16 m_rom_address; + UINT16 m_opcode; + UINT32 m_fixed; + UINT32 m_micro; + int m_subcycle; + int m_icount; + + UINT8 m_o_pins; // how many O pins + UINT8 m_r_pins; // how many R pins + UINT8 m_pc_bits; // how many program counter bits + UINT8 m_byte_bits; // how many bits per 'byte' + UINT8 m_x_bits; // how many X register bits + + address_space *m_program; + address_space *m_data; + + const UINT16 *m_output_pla_table; + devcb_read8 m_read_k; + devcb_write16 m_write_o; + devcb_write16 m_write_r; + devcb_write_line m_power_off; + + UINT32 m_o_mask; + UINT32 m_r_mask; + UINT32 m_k_mask; + UINT32 m_pc_mask; + UINT32 m_x_mask; + + // lookup tables + std::vector m_fixed_decode; + std::vector m_micro_decode; + std::vector m_micro_direct; +}; + + + +class tms1000_cpu_device : public tms1xxx_cpu_device +{ +public: + tms1000_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + tms1000_cpu_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, UINT8 o_pins, UINT8 r_pins, UINT8 pc_bits, UINT8 byte_bits, UINT8 x_bits, int prgwidth, address_map_constructor program, int datawidth, address_map_constructor data, const char *shortname, const char *source); + +protected: + // overrides + virtual void device_reset(); + virtual machine_config_constructor device_mconfig_additions() const; + + + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); +}; + +class tms1070_cpu_device : public tms1000_cpu_device +{ +public: + tms1070_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class tms1040_cpu_device : public tms1000_cpu_device +{ +public: + tms1040_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +class tms1200_cpu_device : public tms1000_cpu_device +{ +public: + tms1200_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +class tms1100_cpu_device : public tms1000_cpu_device +{ +public: + tms1100_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + tms1100_cpu_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, UINT8 o_pins, UINT8 r_pins, UINT8 pc_bits, UINT8 byte_bits, UINT8 x_bits, int prgwidth, address_map_constructor program, int datawidth, address_map_constructor data, const char *shortname, const char *source); + +protected: + // overrides + virtual void device_reset(); + + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + + virtual void op_setr(); + virtual void op_rstr(); +}; + +class tms1170_cpu_device : public tms1100_cpu_device +{ +public: + tms1170_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class tms1300_cpu_device : public tms1100_cpu_device +{ +public: + tms1300_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class tms1370_cpu_device : public tms1100_cpu_device +{ +public: + tms1370_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +class tms1400_cpu_device : public tms1100_cpu_device +{ +public: + tms1400_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + tms1400_cpu_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, UINT8 o_pins, UINT8 r_pins, UINT8 pc_bits, UINT8 byte_bits, UINT8 x_bits, int prgwidth, address_map_constructor program, int datawidth, address_map_constructor data, const char *shortname, const char *source); + +protected: + // overrides + virtual void device_reset(); + virtual machine_config_constructor device_mconfig_additions() const; + + virtual void op_br(); + virtual void op_call(); + virtual void op_retn(); + + virtual void op_setr() { tms1xxx_cpu_device::op_setr(); } // no anomaly with MSB of X register + virtual void op_rstr() { tms1xxx_cpu_device::op_rstr(); } // " +}; + +class tms1470_cpu_device : public tms1400_cpu_device +{ +public: + tms1470_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +class tms1600_cpu_device : public tms1400_cpu_device +{ +public: + tms1600_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + tms1600_cpu_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, UINT8 o_pins, UINT8 r_pins, UINT8 pc_bits, UINT8 byte_bits, UINT8 x_bits, int prgwidth, address_map_constructor program, int datawidth, address_map_constructor data, const char *shortname, const char *source); +}; + +class tms1670_cpu_device : public tms1600_cpu_device +{ +public: + tms1670_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +class tms0970_cpu_device : public tms1000_cpu_device +{ +public: + tms0970_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + tms0970_cpu_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, UINT8 o_pins, UINT8 r_pins, UINT8 pc_bits, UINT8 byte_bits, UINT8 x_bits, int prgwidth, address_map_constructor program, int datawidth, address_map_constructor data, const char *shortname, const char *source); + +protected: + // overrides + virtual void device_reset(); + virtual machine_config_constructor device_mconfig_additions() const; + + virtual void write_o_output(UINT8 index); + + virtual void op_setr(); + virtual void op_tdo(); +}; + +class tms1990_cpu_device : public tms0970_cpu_device +{ +public: + tms1990_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +class tms0980_cpu_device : public tms0970_cpu_device +{ +public: + tms0980_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + tms0980_cpu_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, UINT8 o_pins, UINT8 r_pins, UINT8 pc_bits, UINT8 byte_bits, UINT8 x_bits, int prgwidth, address_map_constructor program, int datawidth, address_map_constructor data, const char *shortname, const char *source); + +protected: + // overrides + virtual void device_reset(); + + virtual machine_config_constructor device_mconfig_additions() const; + + virtual UINT32 disasm_min_opcode_bytes() const { return 2; } + virtual UINT32 disasm_max_opcode_bytes() const { return 2; } + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + + virtual UINT8 read_k_input(); + virtual void set_cki_bus(); + virtual void read_opcode(); + + virtual void op_comx(); + + UINT32 decode_micro(UINT8 sel); +}; + + +class tms0270_cpu_device : public tms0980_cpu_device +{ +public: + tms0270_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // static configuration helpers + template static devcb_base &set_read_ctl_callback(device_t &device, _Object object) { return downcast(device).m_read_ctl.set_callback(object); } + template static devcb_base &set_write_ctl_callback(device_t &device, _Object object) { return downcast(device).m_write_ctl.set_callback(object); } + template static devcb_base &set_write_pdc_callback(device_t &device, _Object object) { return downcast(device).m_write_pdc.set_callback(object); } + +protected: + // overrides + virtual void device_start(); + virtual void device_reset(); + + virtual machine_config_constructor device_mconfig_additions() const; + + virtual void write_o_output(UINT8 index) { tms1xxx_cpu_device::write_o_output(index); } + virtual UINT8 read_k_input(); + virtual void dynamic_output(); + virtual void read_opcode(); + + virtual void op_setr(); + virtual void op_rstr(); + virtual void op_tdo(); + +private: + // state specific to interface with TMS5100 + UINT16 m_r_prev; + UINT8 m_chipsel; + UINT8 m_ctl_out; + UINT8 m_ctl_dir; + int m_pdc; + + UINT8 m_o_latch_low; + UINT8 m_o_latch; + UINT8 m_o_latch_prev; + + devcb_read8 m_read_ctl; + devcb_write8 m_write_ctl; + devcb_write_line m_write_pdc; +}; + + + +extern const device_type TMS1000; +extern const device_type TMS1070; +extern const device_type TMS1040; +extern const device_type TMS1200; +extern const device_type TMS1100; +extern const device_type TMS1170; +extern const device_type TMS1300; +extern const device_type TMS1370; +extern const device_type TMS1400; +extern const device_type TMS1470; +extern const device_type TMS1600; +extern const device_type TMS1670; +extern const device_type TMS0970; +extern const device_type TMS1990; +extern const device_type TMS0980; +extern const device_type TMS0270; + + +#endif /* _TMS0980_H_ */ diff --git a/src/devices/cpu/tms0980/tms0980d.c b/src/devices/cpu/tms0980/tms0980d.c new file mode 100644 index 00000000000..ea72ba9be2e --- /dev/null +++ b/src/devices/cpu/tms0980/tms0980d.c @@ -0,0 +1,343 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol, hap +/* + + TMS0980/TMS1000-family disassembler + +*/ + +#include "emu.h" +#include "debugger.h" +#include "tms0980.h" + + +enum e_mnemonics { + zA10AAC=0, zA6AAC, zA8AAC, zAC1AC, zACACC, zACNAA, zALEC, zALEM, zAMAAC, zBRANCH, zCALL, zCCLA, + zCLA, zCLO, zCOMC, zCOMX, zCOMX8, zCPAIZ, zCTMDYN, zDAN, zDMAN, zDMEA, zDNAA, + zDYN, zIA, zIMAC, zIYC, zKNEZ, zLDP, zLDX, zLDX3, zLDX4, zMNEA, zMNEZ, + zNDMEA, zOFF, zRBIT, zREAC, zRETN, zRSTR, zSAL, zSAMAN, zSBIT, + zSBL, zSEAC, zSETR, zTAM, zTAMACS, zTAMDYN, zTAMIY, zTAMIYC, zTAMZA, + zTAY, zTBIT, zTCMIY, zTCY, zTDO, zTKA, zTKM, zTMA, + zTMY, zTYA, zXDA, zXMA, zYMCY, zYNEA, zYNEC, + zILL +}; + +static const char *const s_mnemonic[] = { + "A10AAC", "A6AAC", "A8AAC", "AC1AC", "ACACC", "ACNAA", "ALEC", "ALEM", "AMAAC", "BRANCH", "CALL", "CCLA", + "CLA", "CLO", "COMC", "COMX", "COMX8", "CPAIZ", "CTMDYN", "DAN", "DMAN", "DMEA", "DNAA", + "DYN", "IA", "IMAC", "IYC", "KNEZ", "LDP", "LDX", "LDX", "LDX", "MNEA", "MNEZ", + "NDMEA", "OFF", "RBIT", "REAC", "RETN", "RSTR", "SAL", "SAMAN", "SBIT", + "SBL", "SEAC", "SETR", "TAM", "TAMACS", "TAMDYN", "TAMIY", "TAMIYC", "TAMZA", + "TAY", "TBIT", "TCMIY", "TCY", "TDO", "TKA", "TKM", "TMA", + "TMY", "TYA", "XDA", "XMA", "YMCY", "YNEA", "YNEC", + "?" +}; + + +#define _OVER DASMFLAG_STEP_OVER +#define _OUT DASMFLAG_STEP_OUT + +static const UINT32 s_flags[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, _OVER, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, _OUT, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + 0 +}; + + +enum e_addressing { + zB0=0, zI2, zI3, zI4, zB7 +}; + +static const UINT8 s_addressing[] = { + zB0, zB0, zB0, zI4, zI4, zI4, zI4, zB0, zB0, zB7, zB7, zB0, + zB0, zB0, zB0, zB0, zB0, zB0, zB0, zB0, zB0, zB0, zB0, + zB0, zB0, zB0, zB0, zB0, zI4, zI2, zI3, zI4, zB0, zB0, + zB0, zB0, zI2, zB0, zB0, zB0, zB0, zB0, zI2, + zB0, zB0, zB0, zB0, zI4, zB0, zB0, zB0, zB0, + zB0, zI2, zI4, zI4, zB0, zB0, zB0, zB0, + zB0, zB0, zB0, zB0, zI4, zB0, zI4, + zB0 +}; + + +static const UINT8 tms0980_mnemonic[512] = { + /* 0x000 */ + zCOMX, zALEM, zYNEA, zXMA, zDYN, zIYC, zCLA, zDMAN, + zTKA, zMNEA, zTKM, zILL, zILL, zSETR, zKNEZ, zILL, + /* 0x010 */ + zDMEA, zDNAA, zCCLA, zNDMEA, zILL, zAMAAC, zILL, zILL, + zCTMDYN, zXDA, zILL, zILL, zILL, zILL, zILL, zILL, + /* 0x020 */ + zTBIT, zTBIT, zTBIT, zTBIT, zILL, zILL, zILL, zILL, + zTAY, zTMA, zTMY, zTYA, zTAMDYN, zTAMIYC, zTAMZA, zTAM, + /* 0x030 */ + zSAMAN, zCPAIZ, zIMAC, zMNEZ, zILL, zILL, zILL, zILL, + zTCY, zYNEC, zTCMIY, zACACC, zACNAA, zTAMACS, zALEC, zYMCY, + /* 0x040 */ + zTCY, zTCY, zTCY, zTCY, zTCY, zTCY, zTCY, zTCY, + zTCY, zTCY, zTCY, zTCY, zTCY, zTCY, zTCY, zTCY, + /* 0x050 */ + zYNEC, zYNEC, zYNEC, zYNEC, zYNEC, zYNEC, zYNEC, zYNEC, + zYNEC, zYNEC, zYNEC, zYNEC, zYNEC, zYNEC, zYNEC, zYNEC, + /* 0x060 */ + zTCMIY, zTCMIY, zTCMIY, zTCMIY, zTCMIY, zTCMIY, zTCMIY, zTCMIY, + zTCMIY, zTCMIY, zTCMIY, zTCMIY, zTCMIY, zTCMIY, zTCMIY, zTCMIY, + /* 0x070 */ + zACACC, zACACC, zACACC, zACACC, zACACC, zACACC, zACACC, zACACC, + zACACC, zACACC, zACACC, zACACC, zACACC, zACACC, zACACC, zACACC, + /* 0x080 */ + zLDP, zLDP, zLDP, zLDP, zLDP, zLDP, zLDP, zLDP, + zLDP, zLDP, zLDP, zLDP, zLDP, zLDP, zLDP, zLDP, + /* 0x090 */ + zLDX4, zLDX4, zLDX4, zLDX4, zLDX4, zLDX4, zLDX4, zLDX4, + zLDX4, zLDX4, zLDX4, zLDX4, zLDX4, zLDX4, zLDX4, zLDX4, + /* 0x0A0 */ + zSBIT, zSBIT, zSBIT, zSBIT, zRBIT, zRBIT, zRBIT, zRBIT, + zILL, zILL, zILL, zILL, zILL, zILL, zILL, zILL, + /* 0x0B0 */ + zTDO, zSAL, zCOMX8, zSBL, zREAC, zSEAC, zOFF, zILL, + zILL, zILL, zILL, zILL, zILL, zILL, zILL, zRETN, + /* 0x0C0 */ + zACNAA, zACNAA, zACNAA, zACNAA, zACNAA, zACNAA, zACNAA, zACNAA, + zACNAA, zACNAA, zACNAA, zACNAA, zACNAA, zACNAA, zACNAA, zACNAA, + /* 0x0D0 */ + zTAMACS, zTAMACS, zTAMACS, zTAMACS, zTAMACS, zTAMACS, zTAMACS, zTAMACS, + zTAMACS, zTAMACS, zTAMACS, zTAMACS, zTAMACS, zTAMACS, zTAMACS, zTAMACS, + /* 0x0E0 */ + zALEC, zALEC, zALEC, zALEC, zALEC, zALEC, zALEC, zALEC, + zALEC, zALEC, zALEC, zALEC, zALEC, zALEC, zALEC, zALEC, + /* 0x0F0 */ + zYMCY, zYMCY, zYMCY, zYMCY, zYMCY, zYMCY, zYMCY, zYMCY, + zYMCY, zYMCY, zYMCY, zYMCY, zYMCY, zYMCY, zYMCY, zYMCY, + /* 0x100 */ + zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, + zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, + zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, + zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, + zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, + zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, + zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, + zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, + zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, + zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, + zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, + zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, + zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, + zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, + zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, + zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, + /* 0x180 */ + zCALL, zCALL, zCALL, zCALL, zCALL, zCALL, zCALL, zCALL, + zCALL, zCALL, zCALL, zCALL, zCALL, zCALL, zCALL, zCALL, + zCALL, zCALL, zCALL, zCALL, zCALL, zCALL, zCALL, zCALL, + zCALL, zCALL, zCALL, zCALL, zCALL, zCALL, zCALL, zCALL, + zCALL, zCALL, zCALL, zCALL, zCALL, zCALL, zCALL, zCALL, + zCALL, zCALL, zCALL, zCALL, zCALL, zCALL, zCALL, zCALL, + zCALL, zCALL, zCALL, zCALL, zCALL, zCALL, zCALL, zCALL, + zCALL, zCALL, zCALL, zCALL, zCALL, zCALL, zCALL, zCALL, + zCALL, zCALL, zCALL, zCALL, zCALL, zCALL, zCALL, zCALL, + zCALL, zCALL, zCALL, zCALL, zCALL, zCALL, zCALL, zCALL, + zCALL, zCALL, zCALL, zCALL, zCALL, zCALL, zCALL, zCALL, + zCALL, zCALL, zCALL, zCALL, zCALL, zCALL, zCALL, zCALL, + zCALL, zCALL, zCALL, zCALL, zCALL, zCALL, zCALL, zCALL, + zCALL, zCALL, zCALL, zCALL, zCALL, zCALL, zCALL, zCALL, + zCALL, zCALL, zCALL, zCALL, zCALL, zCALL, zCALL, zCALL, + zCALL, zCALL, zCALL, zCALL, zCALL, zCALL, zCALL, zCALL +}; + + +static const UINT8 tms1000_mnemonic[256] = { + /* 0x00 */ + zCOMX, zA8AAC, zYNEA, zTAM, zTAMZA, zA10AAC, zA6AAC, zDAN, + zTKA, zKNEZ, zTDO, zCLO, zRSTR, zSETR, zIA, zRETN, + zLDP, zLDP, zLDP, zLDP, zLDP, zLDP, zLDP, zLDP, + zLDP, zLDP, zLDP, zLDP, zLDP, zLDP, zLDP, zLDP, + zTAMIY, zTMA, zTMY, zTYA, zTAY, zAMAAC, zMNEZ, zSAMAN, + zIMAC, zALEM, zDMAN, zIYC, zDYN, zCPAIZ, zXMA, zCLA, + zSBIT, zSBIT, zSBIT, zSBIT, zRBIT, zRBIT, zRBIT, zRBIT, + zTBIT, zTBIT, zTBIT, zTBIT, zLDX, zLDX, zLDX, zLDX, + /* 0x40 */ + zTCY, zTCY, zTCY, zTCY, zTCY, zTCY, zTCY, zTCY, + zTCY, zTCY, zTCY, zTCY, zTCY, zTCY, zTCY, zTCY, + zYNEC, zYNEC, zYNEC, zYNEC, zYNEC, zYNEC, zYNEC, zYNEC, + zYNEC, zYNEC, zYNEC, zYNEC, zYNEC, zYNEC, zYNEC, zYNEC, + zTCMIY, zTCMIY, zTCMIY, zTCMIY, zTCMIY, zTCMIY, zTCMIY, zTCMIY, + zTCMIY, zTCMIY, zTCMIY, zTCMIY, zTCMIY, zTCMIY, zTCMIY, zTCMIY, + zALEC, zALEC, zALEC, zALEC, zALEC, zALEC, zALEC, zALEC, + zALEC, zALEC, zALEC, zALEC, zALEC, zALEC, zALEC, zALEC, + /* 0x80 */ + zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, + zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, + zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, + zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, + zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, + zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, + zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, + zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, + /* 0xc0 */ + zCALL, zCALL, zCALL, zCALL, zCALL, zCALL, zCALL, zCALL, + zCALL, zCALL, zCALL, zCALL, zCALL, zCALL, zCALL, zCALL, + zCALL, zCALL, zCALL, zCALL, zCALL, zCALL, zCALL, zCALL, + zCALL, zCALL, zCALL, zCALL, zCALL, zCALL, zCALL, zCALL, + zCALL, zCALL, zCALL, zCALL, zCALL, zCALL, zCALL, zCALL, + zCALL, zCALL, zCALL, zCALL, zCALL, zCALL, zCALL, zCALL, + zCALL, zCALL, zCALL, zCALL, zCALL, zCALL, zCALL, zCALL, + zCALL, zCALL, zCALL, zCALL, zCALL, zCALL, zCALL, zCALL +}; + + +static const UINT8 tms1100_mnemonic[256] = { + /* 0x00 */ + zMNEA, zALEM, zYNEA, zXMA, zDYN, zIYC, zAMAAC, zDMAN, + zTKA, zCOMX, zTDO, zCOMC, zRSTR, zSETR, zKNEZ, zRETN, + zLDP, zLDP, zLDP, zLDP, zLDP, zLDP, zLDP, zLDP, + zLDP, zLDP, zLDP, zLDP, zLDP, zLDP, zLDP, zLDP, + /* 0x20 */ + zTAY, zTMA, zTMY, zTYA, zTAMDYN, zTAMIYC, zTAMZA, zTAM, + zLDX3, zLDX3, zLDX3, zLDX3, zLDX3, zLDX3, zLDX3, zLDX3, + zSBIT, zSBIT, zSBIT, zSBIT, zRBIT, zRBIT, zRBIT, zRBIT, + zTBIT, zTBIT, zTBIT, zTBIT, zSAMAN, zCPAIZ, zIMAC, zMNEZ, + /* 0x40 */ + zTCY, zTCY, zTCY, zTCY, zTCY, zTCY, zTCY, zTCY, + zTCY, zTCY, zTCY, zTCY, zTCY, zTCY, zTCY, zTCY, + zYNEC, zYNEC, zYNEC, zYNEC, zYNEC, zYNEC, zYNEC, zYNEC, + zYNEC, zYNEC, zYNEC, zYNEC, zYNEC, zYNEC, zYNEC, zYNEC, + /* 0x60 */ + zTCMIY, zTCMIY, zTCMIY, zTCMIY, zTCMIY, zTCMIY, zTCMIY, zTCMIY, + zTCMIY, zTCMIY, zTCMIY, zTCMIY, zTCMIY, zTCMIY, zTCMIY, zTCMIY, + zAC1AC, zAC1AC, zAC1AC, zAC1AC, zAC1AC, zAC1AC, zAC1AC, zAC1AC, + zAC1AC, zAC1AC, zAC1AC, zAC1AC, zAC1AC, zAC1AC, zAC1AC, zCLA, + /* 0x80 */ + zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, + zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, + zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, + zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, + zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, + zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, + zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, + zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, zBRANCH, + /* 0xC0 */ + zCALL, zCALL, zCALL, zCALL, zCALL, zCALL, zCALL, zCALL, + zCALL, zCALL, zCALL, zCALL, zCALL, zCALL, zCALL, zCALL, + zCALL, zCALL, zCALL, zCALL, zCALL, zCALL, zCALL, zCALL, + zCALL, zCALL, zCALL, zCALL, zCALL, zCALL, zCALL, zCALL, + zCALL, zCALL, zCALL, zCALL, zCALL, zCALL, zCALL, zCALL, + zCALL, zCALL, zCALL, zCALL, zCALL, zCALL, zCALL, zCALL, + zCALL, zCALL, zCALL, zCALL, zCALL, zCALL, zCALL, zCALL, + zCALL, zCALL, zCALL, zCALL, zCALL, zCALL, zCALL, zCALL, +}; + + +static const UINT8 tms0980_i2_value[4] = +{ + 0x00, 0x02, 0x01, 0x03 +}; +static const UINT8 tms0980_i3_value[8] = +{ + 0x00, 0x04, 0x02, 0x06, 0x01, 0x05, 0x03, 0x07 +}; +static const UINT8 tms0980_i4_value[16] = +{ + 0x00, 0x08, 0x04, 0x0C, 0x02, 0x0A, 0x06, 0x0E, 0x01, 0x09, 0x05, 0x0D, 0x03, 0x0B, 0x07, 0x0F +}; + + +CPU_DISASSEMBLE( tms0980 ) { + char *dst = buffer; + UINT16 op, instr; + int pos = 0; + + op = ( ( oprom[pos] << 8 ) | oprom[pos + 1] ) & 0x01FF; + pos += 2; + + instr = tms0980_mnemonic[op]; + + dst += sprintf( dst, "%-8s ", s_mnemonic[instr] ); + + switch( s_addressing[instr] ) { + default: + case zB0: + break; + case zI2: + dst += sprintf( dst, "%d", tms0980_i2_value[ op & 0x03 ] ); + break; + case zI4: + dst += sprintf( dst, "%d", tms0980_i4_value[ op & 0x0F ] ); + break; + case zB7: + dst += sprintf( dst, "$%02X", ( op & 0x7F ) << 1 ); + break; + } + + return pos | s_flags[instr] | DASMFLAG_SUPPORTED; +} + + +CPU_DISASSEMBLE( tms1000 ) { + char *dst = buffer; + UINT8 op, instr; + int pos = 0; + + op = oprom[pos]; + pos += 1; + + instr = tms1000_mnemonic[op]; + + dst += sprintf( dst, "%-8s ", s_mnemonic[instr] ); + + switch( s_addressing[instr] ) { + default: + case zB0: + break; + case zI2: + dst += sprintf( dst, "%d", tms0980_i2_value[ op & 0x03 ] ); + break; + case zI4: + dst += sprintf( dst, "%d", tms0980_i4_value[ op & 0x0F ] ); + break; + case zB7: + dst += sprintf( dst, "$%02X", ( op & 0x3F ) ); + break; + } + + return pos | s_flags[instr] | DASMFLAG_SUPPORTED; +} + + +CPU_DISASSEMBLE( tms1100 ) { + char *dst = buffer; + UINT8 op, instr; + int pos = 0; + + op = oprom[pos]; + pos += 1; + + instr = tms1100_mnemonic[op]; + + dst += sprintf( dst, "%-8s ", s_mnemonic[instr] ); + + switch( s_addressing[instr] ) { + default: + case zB0: + break; + case zI2: + dst += sprintf( dst, "%d", tms0980_i2_value[ op & 0x03 ] ); + break; + case zI3: + dst += sprintf( dst, "%d", tms0980_i3_value[ op & 0x07 ] ); + break; + case zI4: + dst += sprintf( dst, "%d", tms0980_i4_value[ op & 0x0F ] ); + break; + case zB7: + dst += sprintf( dst, "$%02X", ( op & 0x3F ) ); + break; + } + + return pos | s_flags[instr] | DASMFLAG_SUPPORTED; +} diff --git a/src/devices/cpu/tms32010/32010dsm.c b/src/devices/cpu/tms32010/32010dsm.c new file mode 100644 index 00000000000..a4c0fd5294c --- /dev/null +++ b/src/devices/cpu/tms32010/32010dsm.c @@ -0,0 +1,338 @@ +// license:BSD-3-Clause +// copyright-holders:Tony La Porta + /**************************************************************************\ + * Texas Instruments TMS32010 DSP Disassembler * + * * + * Copyright Tony La Porta * + * To be used with TMS32010 DSP Emulator engine. * + * You are not allowed to distribute this software commercially. * + * Written for the MAME project. * + * * + * Many thanks to those involved in the i8039 Disassembler * + * as this was based on it. * + * * + * * + * * + * A Memory address * + * B Branch Address for Branch instructions (Requires next opcode read) * + * D Immediate byte load * + * K Immediate bit load * + * W Immediate word load (Actually 13 bit) * + * M AR[x] register modification type (for indirect addressing) * + * N ARP register to change ARP pointer to (for indirect addressing) * + * P I/O port address number * + * R AR[R] register to use * + * S Shift ALU left * + * * + \**************************************************************************/ + +#include "emu.h" +#include "debugger.h" +#include + +#include "tms32010.h" + + + +typedef unsigned char byte; +typedef unsigned short int word; + +#define FMT(a,b) a, b +#define PTRS_PER_FORMAT 2 + +static const char *const arith[4] = { "*" , "*-" , "*+" , "??" } ; +static const char *const nextar[4] = { ",AR0" , ",AR1" , "" , "" } ; + + +static const char *const TMS32010Formats[] = { + FMT("0000ssss0aaaaaaa", "add %A%S"), + FMT("0000ssss10mmn00n", "add %M%S%N"), + FMT("0001ssss0aaaaaaa", "sub %A%S"), + FMT("0001ssss10mmn00n", "sub %M%S%N"), + FMT("0010ssss0aaaaaaa", "lac %A%S"), + FMT("0010ssss10mmn00n", "lac %M%S%N"), + FMT("0011000r0aaaaaaa", "sar %R,%A"), + FMT("0011000r10mmn00n", "sar %R%M%N"), + FMT("0011100r0aaaaaaa", "lar %R,%A"), + FMT("0011100r10mmn00n", "lar %R%M%N"), + FMT("01000ppp0aaaaaaa", "in %A,%P"), + FMT("01000ppp10mmn00n", "in %M,%P%N"), + FMT("01001ppp0aaaaaaa", "out %A,%P"), + FMT("01001ppp10mmn00n", "out %M,%P%N"), + FMT("01010sss0aaaaaaa", "sacl %A"), /* This instruction has a shift but */ + FMT("01010sss10mmn00n", "sacl %M%N"), /* is documented as not performed */ + FMT("01011sss0aaaaaaa", "sach %A%S"), + FMT("01011sss10mmn00n", "sach %M%S%N"), + FMT("011000000aaaaaaa", "addh %A"), + FMT("0110000010mmn00n", "addh %M%N"), + FMT("011000010aaaaaaa", "adds %A"), + FMT("0110000110mmn00n", "adds %M%N"), + FMT("011000100aaaaaaa", "subh %A"), + FMT("0110001010mmn00n", "subh %M%N"), + FMT("011000110aaaaaaa", "subs %A"), + FMT("0110001110mmn00n", "subs %M%N"), + FMT("011001000aaaaaaa", "subc %A"), + FMT("0110010010mmn00n", "subc %M%N"), + FMT("011001010aaaaaaa", "zalh %A"), + FMT("0110010110mmn00n", "zalh %M%N"), + FMT("011001100aaaaaaa", "zals %A"), + FMT("0110011010mmn00n", "zals %M%N"), + FMT("011001110aaaaaaa", "tblr %A"), + FMT("0110011110mmn00n", "tblr %M%N"), + FMT("011010001000000k", "larp %K"), + FMT("011010000aaaaaaa", "mar %A"), /* Actually this is executed as a NOP */ +/* FMT("0110100010mmn00n", "mar %M%N"), */ +/* MAR indirect has been expanded out to all its variations because one of */ +/* its opcodes is the same as LARP (actually performs the same function) */ + + FMT("0110100010001000", "mar *"), + FMT("0110100010001001", "mar *"), + FMT("0110100010010000", "mar *-,AR0"), + FMT("0110100010010001", "mar *-,AR1"), + FMT("0110100010011000", "mar *-"), + FMT("0110100010011001", "mar *-"), + FMT("0110100010100000", "mar *+,AR0"), + FMT("0110100010100001", "mar *+,AR1"), + FMT("0110100010101000", "mar *+"), + FMT("0110100010101001", "mar *+"), + FMT("0110100010110000", "mar ??,AR0"), + FMT("0110100010110001", "mar ??,AR1"), + FMT("0110100010111000", "mar ??"), + FMT("0110100010111001", "mar ??"), + + FMT("011010010aaaaaaa", "dmov %A"), + FMT("0110100110mmn00n", "dmov %M%N"), + FMT("011010100aaaaaaa", "lt %A"), + FMT("0110101010mmn00n", "lt %M%N"), + FMT("011010110aaaaaaa", "ltd %A"), + FMT("0110101110mmn00n", "ltd %M%N"), + FMT("011011000aaaaaaa", "lta %A"), + FMT("0110110010mmn00n", "lta %M%N"), + FMT("011011010aaaaaaa", "mpy %A"), + FMT("0110110110mmn00n", "mpy %M%N"), + FMT("011011100000000k", "ldpk %K"), + FMT("011011110aaaaaaa", "ldp %A"), + FMT("0110111110mmn00n", "ldp %M%N"), + FMT("0111000rdddddddd", "lark %R,%D"), + FMT("011110000aaaaaaa", "xor %A"), + FMT("0111100010mmn00n", "xor %M%N"), + FMT("011110010aaaaaaa", "and %A"), + FMT("0111100110mmn00n", "and %M%N"), + FMT("011110100aaaaaaa", "or %A"), + FMT("0111101010mmn00n", "or %M%N"), + FMT("011110110aaaaaaa", "lst %A"), + FMT("0111101110mmn00n", "lst %M%N"), + FMT("011111000aaaaaaa", "sst %A"), + FMT("0111110010mmn00n", "sst %M%N"), + FMT("011111010aaaaaaa", "tblw %A"), + FMT("0111110110mmn00n", "tblw %M%N"), + FMT("01111110dddddddd", "lack %D"), + FMT("0111111110000000", "nop"), /* 7F80 */ + FMT("0111111110000001", "dint"), + FMT("0111111110000010", "eint"), + FMT("0111111110001000", "abs"), /* 7F88 */ + FMT("0111111110001001", "zac"), + FMT("0111111110001010", "rovm"), + FMT("0111111110001011", "sovm"), + FMT("0111111110001100", "cala"), + FMT("0111111110001101", "ret"), + FMT("0111111110001110", "pac"), + FMT("0111111110001111", "apac"), + FMT("0111111110010000", "spac"), + FMT("0111111110011100", "push"), + FMT("0111111110011101", "pop"), /* 7F9D */ + FMT("100wwwwwwwwwwwww", "mpyk %W"), + FMT("1111010000000000bbbbbbbbbbbbbbbb", "banz %B"), + FMT("1111010100000000bbbbbbbbbbbbbbbb", "bv %B"), + FMT("1111011000000000bbbbbbbbbbbbbbbb", "bioz %B"), + FMT("1111100000000000bbbbbbbbbbbbbbbb", "call %B"), + FMT("1111100100000000bbbbbbbbbbbbbbbb", "b %B"), + FMT("1111101000000000bbbbbbbbbbbbbbbb", "blz %B"), + FMT("1111101100000000bbbbbbbbbbbbbbbb", "blez %B"), + FMT("1111110000000000bbbbbbbbbbbbbbbb", "bgz %B"), + FMT("1111110100000000bbbbbbbbbbbbbbbb", "bgez %B"), + FMT("1111111000000000bbbbbbbbbbbbbbbb", "bnz %B"), + FMT("1111111100000000bbbbbbbbbbbbbbbb", "bz %B"), + NULL +}; + +#define MAX_OPS ((ARRAY_LENGTH(TMS32010Formats) - 1) / PTRS_PER_FORMAT) + +struct TMS32010Opcode { + word mask; /* instruction mask */ + word bits; /* constant bits */ + word extcode; /* value that gets extension code */ + const char *parse; /* how to parse bits */ + const char *fmt; /* instruction format */ +}; + +static TMS32010Opcode Op[MAX_OPS+1]; +static int OpInizialized = 0; + +static void InitDasm32010(void) +{ + const char *p; + const char *const *ops; + word mask, bits; + int bit; + int i; + + ops = TMS32010Formats; i = 0; + while (*ops) + { + p = *ops; + mask = 0; bits = 0; bit = 15; + while (*p && bit >= 0) + { + switch (*p++) + { + case '1': mask |= 1<= 0) + { + /* osd_printf_debug("{%c/%d}",*cp,bit); */ + switch(*cp) + { + case 'a': a <<=1; a |= ((code & (1< +#include + +#include "32010dsm.c" + + +unsigned char *Buffer; + + +int main(int argc,char *argv[]) +{ + int length=0, length_to_dump=0, offset=0, disasm_words=0; + int filelength=0, bytes_read; + int Counter=0; + + FILE *F; + char *String_Output; + + if(argc<2) + { + printf("\n"); + printf("TMS32010 Disassembler 1.1 by Tony La Porta (C)1999-2002+\n\n"); + printf("Usage: dis32010 [ [ ] ]\n"); + printf(" source file data must be MSB first\n"); + printf(" starting address to disassemble from (decimal)\n"); + printf(" number of addresses to disassemble (decimal)\n"); + printf(" Precede values with 0x if HEX values preffered\n"); + exit(1); + } + + if(!(F=fopen(argv[1],"rb"))) + { + printf("\n%s: Can't open file %s\n",argv[0],argv[1]); + exit(2); + } + argv++; argc--; + if (argv[1]) + { + offset = strtol(argv[1],NULL,0); + argv++; argc--; + } + if (argv[1]) + { + length = strtol(argv[1],NULL,0); + argv++; argc--; + } + + fseek(F,0, SEEK_END); + filelength = ftell(F); + + length *= 2; + + if ((length > (filelength - (offset*2))) || (length == 0)) length = filelength - (offset*2); + printf("Length=%04Xh(words) Offset=$%04Xh filelength=%04Xh(words) %04Xh(bytes)\n",length/2,offset,filelength/2,filelength); + length_to_dump = length; + printf("Starting from %d, dumping %d opcodes (word size)\n",offset,length/2); + Buffer = calloc((filelength+1),sizeof(char)); + if (Buffer==NULL) + { + printf("Out of Memory !!!"); + fclose(F); + exit(3); + } + String_Output = calloc(80,sizeof(char)); + if (String_Output==NULL) + { + printf("Out of Memory !!!"); + free(Buffer); + fclose(F); + exit(4); + } + + if (fseek(F,0,SEEK_SET) != 0) + { + printf("Error seeking to beginning of file\n"); + free(String_Output); + free(Buffer); + fclose(F); + exit(5); + } + + Counter = offset; + bytes_read = fread(Buffer,sizeof(char),filelength,F); + if (bytes_read >= length) + { + for (; length > 0; length -= (disasm_words*2)) + { + int ii; + disasm_words = Dasm32010(String_Output,Counter); + printf("$%04lX: ",Counter); + for (ii = 0; ii < disasm_words; ii++) + { + if (((Counter*2) + ii) > filelength) /* Past end of length to dump ? */ + { + sprintf(String_Output,"???? dw %02.2X%02.2Xh (Past end of disassembly !)",Buffer[((Counter-1)*2)],Buffer[((Counter-1)*2)+1]); + } + else + { + printf("%02.2x%02.2x ",Buffer[(Counter*2)],Buffer[(Counter*2) + 1]); + } + Counter++ ; + } + for (; ii < 4; ii++) + { + printf(" "); + } + printf("\t%s\n",String_Output); + } + } + else + { + printf("ERROR length to dump was %d ", length_to_dump/2); + printf(", but bytes read from file were %d\n", bytes_read/2); + free(String_Output); + free(Buffer); + fclose(F); + exit(7); + } + free(String_Output); + free(Buffer); + fclose(F); + return(0); +} diff --git a/src/devices/cpu/tms32010/tms32010.c b/src/devices/cpu/tms32010/tms32010.c new file mode 100644 index 00000000000..e6264d3f1dd --- /dev/null +++ b/src/devices/cpu/tms32010/tms32010.c @@ -0,0 +1,987 @@ +// license:BSD-3-Clause +// copyright-holders:Tony La Porta + /**************************************************************************\ + * Texas Instruments TMS32010 DSP Emulator * + * * + * Copyright Tony La Porta * + * You are not allowed to distribute this software commercially. * + * Written for the MAME project. * + * * + * * + * Notes : The term 'DMA' within this document, is in reference * + * to Direct Memory Addressing, and NOT the usual term * + * of Direct Memory Access. * + * This is a word based microcontroller, with addressing * + * architecture based on the Harvard addressing scheme. * + * * + * * + * * + * **** Change Log **** * + * * + * TLP (13-Jul-2002) * + * - Added Save-State support * + * - Converted the pending_irq flag to INTF (a real flag in this device) * + * - Fixed the ignore Interrupt Request for previous critical * + * instructions requiring an extra instruction to be processed. For * + * this reason, instant IRQ servicing cannot be supported here, so * + * INTF needs to be polled within the instruction execution loop * + * - Removed IRQ callback (IRQ ACK not supported on this device) * + * - A pending IRQ will remain pending until it's serviced. De-asserting * + * the IRQ Pin does not remove a pending IRQ state * + * - BIO is no longer treated as an IRQ line. It's polled when required. * + * This is the true behaviour of the device * + * - Removed the Clear OV flag from overflow instructions. Overflow * + * instructions can only set the flag. Flag test instructions clear it * + * - Fixed the ABST, SUBC and SUBH instructions * + * - Fixed the signedness in many equation based instructions * + * - Added the missing Previous PC to the get_register function * + * - Changed Cycle timings to include clock ticks * + * - Converted some registers from ints to pairs for much cleaner code * + * TLP (20-Jul-2002) Ver 1.10 * + * - Fixed the dissasembly from the debugger * + * - Changed all references from TMS320C10 to TMS32010 * + * ASG (24-Sep-2002) Ver 1.20 * + * - Fixed overflow handling * + * - Simplified logic in a few locations * + * TLP (22-Feb-2004) Ver 1.21 * + * - Overflow for ADDH only affects upper 16bits (was modifying 32 bits) * + * - Internal Data Memory map is assigned here now * + * - Cycle counts for invalid opcodes 7F1E and 7F1F are now 0 * + * RK (23-Nov-2006) Ver 1.22 * + * - Fixed state of the Overflow Flag on reset * + * - Fixed the SUBC instruction which was incorrectly zeroing the divisor * + * TLP (13-Jul-2010) Ver 1.30 * + * - LST instruction was incorrectly setting an Indirect Addressing * + * feature when Direct Addressing mode was selected * + * - Added TMS32015 and TMS32016 variants * + * TLP (27-Jul-2010) Ver 1.31 * + * - Corrected cycle timing for conditional branch instructions * + * * + \**************************************************************************/ + + +#include "emu.h" +#include "debugger.h" +#include "tms32010.h" + + + +#define M_RDROM(A) TMS32010_ROM_RDMEM(A) +#define M_WRTROM(A,V) TMS32010_ROM_WRMEM(A,V) +#define M_RDRAM(A) TMS32010_RAM_RDMEM(A) +#define M_WRTRAM(A,V) TMS32010_RAM_WRMEM(A,V) +#define M_RDOP(A) TMS32010_RDOP(A) +#define M_RDOP_ARG(A) TMS32010_RDOP_ARG(A) +#define P_IN(A) TMS32010_In(A) +#define P_OUT(A,V) TMS32010_Out(A,V) +#define BIO_IN TMS32010_BIO_In + + +const device_type TMS32010 = &device_creator; +const device_type TMS32015 = &device_creator; +const device_type TMS32016 = &device_creator; + + +/**************************************************************************** + * TMS32010 Internal Memory Map + ****************************************************************************/ + +static ADDRESS_MAP_START( tms32010_ram, AS_DATA, 16, tms32010_device ) + AM_RANGE(0x00, 0x7f) AM_RAM /* Page 0 */ + AM_RANGE(0x80, 0x8f) AM_RAM /* Page 1 */ +ADDRESS_MAP_END + +/**************************************************************************** + * TMS32015/6 Internal Memory Map + ****************************************************************************/ + +static ADDRESS_MAP_START( tms32015_ram, AS_DATA, 16, tms32010_device ) + AM_RANGE(0x00, 0x7f) AM_RAM /* Page 0 */ + AM_RANGE(0x80, 0xff) AM_RAM /* Page 1 */ +ADDRESS_MAP_END + + +tms32010_device::tms32010_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : cpu_device(mconfig, TMS32010, "TMS32010", tag, owner, clock, "tms32010", __FILE__) + , m_program_config("program", ENDIANNESS_BIG, 16, 12, -1) + , m_data_config("data", ENDIANNESS_BIG, 16, 8, -1, ADDRESS_MAP_NAME(tms32010_ram)) + , m_io_config("io", ENDIANNESS_BIG, 16, 5, -1) + , m_addr_mask(0x0fff) +{ +} + + +tms32010_device::tms32010_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source, int addr_mask) + : cpu_device(mconfig, type, name, tag, owner, clock, shortname, source) + , m_program_config("program", ENDIANNESS_BIG, 16, 12, -1) + , m_data_config("data", ENDIANNESS_BIG, 16, 8, -1, ADDRESS_MAP_NAME(tms32015_ram)) + , m_io_config("io", ENDIANNESS_BIG, 16, 5, -1) + , m_addr_mask(addr_mask) +{ +} + + +tms32015_device::tms32015_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : tms32010_device(mconfig, TMS32015, "TMS32015", tag, owner, clock, "tms32015", __FILE__, 0x0fff) +{ +} + + +tms32016_device::tms32016_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : tms32010_device(mconfig, TMS32016, "TMS32016", tag, owner, clock, "tms32016", __FILE__, 0xffff) +{ +} + + +offs_t tms32010_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( tms32010 ); + return CPU_DISASSEMBLE_NAME(tms32010)(this, buffer, pc, oprom, opram, options); +} + + +/********* The following is the Status (Flag) register definition. *********/ +/* 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 */ +/* OV | OVM | INTM | 1 | 1 | 1 | 1 | ARP | 1 | 1 | 1 | 1 | 1 | 1 | 1 | DP */ +#define OV_FLAG 0x8000 /* OV (Overflow flag) 1 indicates an overflow */ +#define OVM_FLAG 0x4000 /* OVM (Overflow Mode bit) 1 forces ACC overflow to greatest positive or negative saturation value */ +#define INTM_FLAG 0x2000 /* INTM (Interrupt Mask flag) 0 enables maskable interrupts */ +#define ARP_REG 0x0100 /* ARP (Auxiliary Register Pointer) */ +#define DP_REG 0x0001 /* DP (Data memory Pointer (bank) bit) */ + +#define OV ( m_STR & OV_FLAG) /* OV (Overflow flag) */ +#define OVM ( m_STR & OVM_FLAG) /* OVM (Overflow Mode bit) 1 indicates an overflow */ +#define INTM ( m_STR & INTM_FLAG) /* INTM (Interrupt enable flag) 0 enables maskable interrupts */ +#define ARP ((m_STR & ARP_REG) >> 8) /* ARP (Auxiliary Register Pointer) */ +#define DP ((m_STR & DP_REG) << 7) /* DP (Data memory Pointer bit) */ + +#define DMA_DP (DP | (m_opcode.b.l & 0x7f)) /* address used in direct memory access operations */ +#define DMA_DP1 (0x80 | m_opcode.b.l) /* address used in direct memory access operations for sst instruction */ +#define IND (m_AR[ARP] & 0xff) /* address used in indirect memory access operations */ + + + +/**************************************************************************** + * Read the state of the BIO pin + */ + +#define TMS32010_BIO_In (m_io->read_word(TMS32010_BIO<<1)) + + +/**************************************************************************** + * Input a word from given I/O port + */ + +#define TMS32010_In(Port) (m_io->read_word((Port)<<1)) + + +/**************************************************************************** + * Output a word to given I/O port + */ + +#define TMS32010_Out(Port,Value) (m_io->write_word((Port)<<1,Value)) + + + +/**************************************************************************** + * Read a word from given ROM memory location + */ + +#define TMS32010_ROM_RDMEM(A) (m_program->read_word((A)<<1)) + + +/**************************************************************************** + * Write a word to given ROM memory location + */ + +#define TMS32010_ROM_WRMEM(A,V) (m_program->write_word((A)<<1,V)) + + + +/**************************************************************************** + * Read a word from given RAM memory location + */ + +#define TMS32010_RAM_RDMEM(A) (m_data->read_word((A)<<1)) + + +/**************************************************************************** + * Write a word to given RAM memory location + */ + +#define TMS32010_RAM_WRMEM(A,V) (m_data->write_word((A)<<1,V)) + + + +/**************************************************************************** + * TMS32010_RDOP() is identical to TMS32010_RDMEM() except it is used for reading + * opcodes. In case of system with memory mapped I/O, this function can be + * used to greatly speed up emulation + */ + +#define TMS32010_RDOP(A) (m_direct->read_word((A)<<1)) + + +/**************************************************************************** + * TMS32010_RDOP_ARG() is identical to TMS32010_RDOP() except it is used + * for reading opcode arguments. This difference can be used to support systems + * that use different encoding mechanisms for opcodes and opcode arguments + */ + +#define TMS32010_RDOP_ARG(A) (m_direct->read_word((A)<<1)) + + +/************************************************************************ + * Shortcuts + ************************************************************************/ + +void tms32010_device::CLR(UINT16 flag) { m_STR &= ~flag; m_STR |= 0x1efe; } +void tms32010_device::SET_FLAG(UINT16 flag) { m_STR |= flag; m_STR |= 0x1efe; } + + +void tms32010_device::CALCULATE_ADD_OVERFLOW(INT32 addval) +{ + if ((INT32)(~(m_oldacc.d ^ addval) & (m_oldacc.d ^ m_ACC.d)) < 0) { + SET_FLAG(OV_FLAG); + if (OVM) + m_ACC.d = ((INT32)m_oldacc.d < 0) ? 0x80000000 : 0x7fffffff; + } +} +void tms32010_device::CALCULATE_SUB_OVERFLOW(INT32 subval) +{ + if ((INT32)((m_oldacc.d ^ subval) & (m_oldacc.d ^ m_ACC.d)) < 0) { + SET_FLAG(OV_FLAG); + if (OVM) + m_ACC.d = ((INT32)m_oldacc.d < 0) ? 0x80000000 : 0x7fffffff; + } +} + +UINT16 tms32010_device::POP_STACK() +{ + UINT16 data = m_STACK[3]; + m_STACK[3] = m_STACK[2]; + m_STACK[2] = m_STACK[1]; + m_STACK[1] = m_STACK[0]; + return (data & m_addr_mask); +} +void tms32010_device::PUSH_STACK(UINT16 data) +{ + m_STACK[0] = m_STACK[1]; + m_STACK[1] = m_STACK[2]; + m_STACK[2] = m_STACK[3]; + m_STACK[3] = (data & m_addr_mask); +} + +void tms32010_device::UPDATE_AR() +{ + if (m_opcode.b.l & 0x30) { + UINT16 tmpAR = m_AR[ARP]; + if (m_opcode.b.l & 0x20) tmpAR++ ; + if (m_opcode.b.l & 0x10) tmpAR-- ; + m_AR[ARP] = (m_AR[ARP] & 0xfe00) | (tmpAR & 0x01ff); + } +} +void tms32010_device::UPDATE_ARP() +{ + if (~m_opcode.b.l & 0x08) { + if (m_opcode.b.l & 0x01) SET_FLAG(ARP_REG); + else CLR(ARP_REG); + } +} + + +void tms32010_device::getdata(UINT8 shift,UINT8 signext) +{ + if (m_opcode.b.l & 0x80) + m_memaccess = IND; + else + m_memaccess = DMA_DP; + + m_ALU.d = (UINT16)M_RDRAM(m_memaccess); + if (signext) m_ALU.d = (INT16)m_ALU.d; + m_ALU.d <<= shift; + if (m_opcode.b.l & 0x80) { + UPDATE_AR(); + UPDATE_ARP(); + } +} + +void tms32010_device::putdata(UINT16 data) +{ + if (m_opcode.b.l & 0x80) + m_memaccess = IND; + else + m_memaccess = DMA_DP; + + if (m_opcode.b.l & 0x80) { + UPDATE_AR(); + UPDATE_ARP(); + } + M_WRTRAM(m_memaccess,data); +} +void tms32010_device::putdata_sar(UINT8 data) +{ + if (m_opcode.b.l & 0x80) + m_memaccess = IND; + else + m_memaccess = DMA_DP; + + if (m_opcode.b.l & 0x80) { + UPDATE_AR(); + UPDATE_ARP(); + } + M_WRTRAM(m_memaccess,m_AR[data]); +} +void tms32010_device::putdata_sst(UINT16 data) +{ + if (m_opcode.b.l & 0x80) + m_memaccess = IND; + else + m_memaccess = DMA_DP1; /* Page 1 only */ + + if (m_opcode.b.l & 0x80) { + UPDATE_AR(); + } + M_WRTRAM(m_memaccess,data); +} + + + +/************************************************************************ + * Emulate the Instructions + ************************************************************************/ + +/* This following function is here to fill in the void for */ +/* the opcode call function. This function is never called. */ + +void tms32010_device::opcodes_7F() { fatalerror("Should never get here!\n"); } + + +void tms32010_device::illegal() +{ + logerror("TMS32010: PC=%04x, Illegal opcode = %04x\n", (m_PC-1), m_opcode.w.l); +} + +void tms32010_device::abst() +{ + if ( (INT32)(m_ACC.d) < 0 ) { + m_ACC.d = -m_ACC.d; + if (OVM && (m_ACC.d == 0x80000000)) m_ACC.d-- ; + } +} + +/*** The manual doesn't mention overflow with the ADD? instructions however *** + *** overflow is implemented here, because it makes little sense otherwise **** + *** while newer generations of this type of chip supported it. The *********** + *** manual may be wrong wrong (apart from other errors the manual has). ****** + +void tms32010_device::add_sh() { getdata(m_opcode.b.h,1); m_ACC.d += m_ALU.d; } +void tms32010_device::addh() { getdata(0,0); m_ACC.d += (m_ALU.d << 16); } + ***/ + +void tms32010_device::add_sh() +{ + m_oldacc.d = m_ACC.d; + getdata((m_opcode.b.h & 0xf),1); + m_ACC.d += m_ALU.d; + CALCULATE_ADD_OVERFLOW(m_ALU.d); +} +void tms32010_device::addh() +{ + m_oldacc.d = m_ACC.d; + getdata(0,0); + m_ACC.w.h += m_ALU.w.l; + if ((INT16)(~(m_oldacc.w.h ^ m_ALU.w.h) & (m_oldacc.w.h ^ m_ACC.w.h)) < 0) { + SET_FLAG(OV_FLAG); + if (OVM) + m_ACC.w.h = ((INT16)m_oldacc.w.h < 0) ? 0x8000 : 0x7fff; + } +} +void tms32010_device::adds() +{ + m_oldacc.d = m_ACC.d; + getdata(0,0); + m_ACC.d += m_ALU.d; + CALCULATE_ADD_OVERFLOW(m_ALU.d); +} +void tms32010_device::and_() +{ + getdata(0,0); + m_ACC.d &= m_ALU.d; +} +void tms32010_device::apac() +{ + m_oldacc.d = m_ACC.d; + m_ACC.d += m_Preg.d; + CALCULATE_ADD_OVERFLOW(m_Preg.d); +} +void tms32010_device::br() +{ + m_PC = M_RDOP_ARG(m_PC); +} +void tms32010_device::banz() +{ + if (m_AR[ARP] & 0x01ff) { + m_PC = M_RDOP_ARG(m_PC); + m_icount -= add_branch_cycle(); + } + else + m_PC++ ; + m_ALU.w.l = m_AR[ARP]; + m_ALU.w.l-- ; + m_AR[ARP] = (m_AR[ARP] & 0xfe00) | (m_ALU.w.l & 0x01ff); +} +void tms32010_device::bgez() +{ + if ( (INT32)(m_ACC.d) >= 0 ) { + m_PC = M_RDOP_ARG(m_PC); + m_icount -= add_branch_cycle(); + } + else + m_PC++ ; +} +void tms32010_device::bgz() +{ + if ( (INT32)(m_ACC.d) > 0 ) { + m_PC = M_RDOP_ARG(m_PC); + m_icount -= add_branch_cycle(); + } + else + m_PC++ ; +} +void tms32010_device::bioz() +{ + if (BIO_IN != CLEAR_LINE) { + m_PC = M_RDOP_ARG(m_PC); + m_icount -= add_branch_cycle(); + } + else + m_PC++ ; +} +void tms32010_device::blez() +{ + if ( (INT32)(m_ACC.d) <= 0 ) { + m_PC = M_RDOP_ARG(m_PC); + m_icount -= add_branch_cycle(); + } + else + m_PC++ ; +} +void tms32010_device::blz() +{ + if ( (INT32)(m_ACC.d) < 0 ) { + m_PC = M_RDOP_ARG(m_PC); + m_icount -= add_branch_cycle(); + } + else + m_PC++ ; +} +void tms32010_device::bnz() +{ + if (m_ACC.d != 0) { + m_PC = M_RDOP_ARG(m_PC); + m_icount -= add_branch_cycle(); + } + else + m_PC++ ; +} +void tms32010_device::bv() +{ + if (OV) { + CLR(OV_FLAG); + m_PC = M_RDOP_ARG(m_PC); + m_icount -= add_branch_cycle(); + } + else + m_PC++ ; +} +void tms32010_device::bz() +{ + if (m_ACC.d == 0) { + m_PC = M_RDOP_ARG(m_PC); + m_icount -= add_branch_cycle(); + } + else + m_PC++ ; +} +void tms32010_device::cala() +{ + PUSH_STACK(m_PC); + m_PC = m_ACC.w.l & m_addr_mask; +} +void tms32010_device::call() +{ + m_PC++ ; + PUSH_STACK(m_PC); + m_PC = M_RDOP_ARG((m_PC - 1)); +} +void tms32010_device::dint() +{ + SET_FLAG(INTM_FLAG); +} +void tms32010_device::dmov() +{ + getdata(0,0); + M_WRTRAM((m_memaccess + 1),m_ALU.w.l); +} +void tms32010_device::eint() +{ + CLR(INTM_FLAG); +} +void tms32010_device::in_p() +{ + m_ALU.w.l = P_IN( (m_opcode.b.h & 7) ); + putdata(m_ALU.w.l); +} +void tms32010_device::lac_sh() +{ + getdata((m_opcode.b.h & 0x0f),1); + m_ACC.d = m_ALU.d; +} +void tms32010_device::lack() +{ + m_ACC.d = m_opcode.b.l; +} +void tms32010_device::lar_ar0() +{ + getdata(0,0); + m_AR[0] = m_ALU.w.l; +} +void tms32010_device::lar_ar1() +{ + getdata(0,0); + m_AR[1] = m_ALU.w.l; +} +void tms32010_device::lark_ar0() +{ + m_AR[0] = m_opcode.b.l; +} +void tms32010_device::lark_ar1() +{ + m_AR[1] = m_opcode.b.l; +} +void tms32010_device::larp_mar() +{ + if (m_opcode.b.l & 0x80) { + UPDATE_AR(); + UPDATE_ARP(); + } +} +void tms32010_device::ldp() +{ + getdata(0,0); + if (m_ALU.d & 1) + SET_FLAG(DP_REG); + else + CLR(DP_REG); +} +void tms32010_device::ldpk() +{ + if (m_opcode.b.l & 1) + SET_FLAG(DP_REG); + else + CLR(DP_REG); +} +void tms32010_device::lst() +{ + if (m_opcode.b.l & 0x80) { + m_opcode.b.l |= 0x08; /* In Indirect Addressing mode, next ARP is not supported here so mask it */ + } + getdata(0,0); + m_ALU.w.l &= (~INTM_FLAG); /* Must not affect INTM */ + m_STR &= INTM_FLAG; + m_STR |= m_ALU.w.l; + m_STR |= 0x1efe; +} +void tms32010_device::lt() +{ + getdata(0,0); + m_Treg = m_ALU.w.l; +} +void tms32010_device::lta() +{ + m_oldacc.d = m_ACC.d; + getdata(0,0); + m_Treg = m_ALU.w.l; + m_ACC.d += m_Preg.d; + CALCULATE_ADD_OVERFLOW(m_Preg.d); +} +void tms32010_device::ltd() +{ + m_oldacc.d = m_ACC.d; + getdata(0,0); + m_Treg = m_ALU.w.l; + M_WRTRAM((m_memaccess + 1),m_ALU.w.l); + m_ACC.d += m_Preg.d; + CALCULATE_ADD_OVERFLOW(m_Preg.d); +} +void tms32010_device::mpy() +{ + getdata(0,0); + m_Preg.d = (INT16)m_ALU.w.l * (INT16)m_Treg; + if (m_Preg.d == 0x40000000) m_Preg.d = 0xc0000000; +} +void tms32010_device::mpyk() +{ + m_Preg.d = (INT16)m_Treg * ((INT16)(m_opcode.w.l << 3) >> 3); +} +void tms32010_device::nop() +{ + /* Nothing to do */ +} +void tms32010_device::or_() +{ + getdata(0,0); + m_ACC.w.l |= m_ALU.w.l; +} +void tms32010_device::out_p() +{ + getdata(0,0); + P_OUT( (m_opcode.b.h & 7), m_ALU.w.l ); +} +void tms32010_device::pac() +{ + m_ACC.d = m_Preg.d; +} +void tms32010_device::pop() +{ + m_ACC.w.l = POP_STACK(); + m_ACC.w.h = 0x0000; +} +void tms32010_device::push() +{ + PUSH_STACK(m_ACC.w.l); +} +void tms32010_device::ret() +{ + m_PC = POP_STACK(); +} +void tms32010_device::rovm() +{ + CLR(OVM_FLAG); +} +void tms32010_device::sach_sh() +{ + m_ALU.d = (m_ACC.d << (m_opcode.b.h & 7)); + putdata(m_ALU.w.h); +} +void tms32010_device::sacl() +{ + putdata(m_ACC.w.l); +} +void tms32010_device::sar_ar0() +{ + putdata_sar(0); +} +void tms32010_device::sar_ar1() +{ + putdata_sar(1); +} +void tms32010_device::sovm() +{ + SET_FLAG(OVM_FLAG); +} +void tms32010_device::spac() +{ + m_oldacc.d = m_ACC.d; + m_ACC.d -= m_Preg.d; + CALCULATE_SUB_OVERFLOW(m_Preg.d); +} +void tms32010_device::sst() +{ + putdata_sst(m_STR); +} +void tms32010_device::sub_sh() +{ + m_oldacc.d = m_ACC.d; + getdata((m_opcode.b.h & 0x0f),1); + m_ACC.d -= m_ALU.d; + CALCULATE_SUB_OVERFLOW(m_ALU.d); +} +void tms32010_device::subc() +{ + m_oldacc.d = m_ACC.d; + getdata(15,0); + m_ALU.d = (INT32) m_ACC.d - m_ALU.d; + if ((INT32)((m_oldacc.d ^ m_ALU.d) & (m_oldacc.d ^ m_ACC.d)) < 0) + SET_FLAG(OV_FLAG); + if ( (INT32)(m_ALU.d) >= 0 ) + m_ACC.d = ((m_ALU.d << 1) + 1); + else + m_ACC.d = (m_ACC.d << 1); +} +void tms32010_device::subh() +{ + m_oldacc.d = m_ACC.d; + getdata(16,0); + m_ACC.d -= m_ALU.d; + CALCULATE_SUB_OVERFLOW(m_ALU.d); +} +void tms32010_device::subs() +{ + m_oldacc.d = m_ACC.d; + getdata(0,0); + m_ACC.d -= m_ALU.d; + CALCULATE_SUB_OVERFLOW(m_ALU.d); +} +void tms32010_device::tblr() +{ + m_ALU.d = M_RDROM((m_ACC.w.l & m_addr_mask)); + putdata(m_ALU.w.l); + m_STACK[0] = m_STACK[1]; +} +void tms32010_device::tblw() +{ + getdata(0,0); + M_WRTROM(((m_ACC.w.l & m_addr_mask)),m_ALU.w.l); + m_STACK[0] = m_STACK[1]; +} +void tms32010_device::xor_() +{ + getdata(0,0); + m_ACC.w.l ^= m_ALU.w.l; +} +void tms32010_device::zac() +{ + m_ACC.d = 0; +} +void tms32010_device::zalh() +{ + getdata(0,0); + m_ACC.w.h = m_ALU.w.l; + m_ACC.w.l = 0x0000; +} +void tms32010_device::zals() +{ + getdata(0,0); + m_ACC.w.l = m_ALU.w.l; + m_ACC.w.h = 0x0000; +} + + + +/*********************************************************************** + * Opcode Table (Cycles, Instruction) + ***********************************************************************/ + +/* Conditional Branch instructions take two cycles when the test condition is met and the branch performed */ + +const tms32010_device::tms32010_opcode tms32010_device::s_opcode_main[256]= +{ +/*00*/ {1, &tms32010_device::add_sh },{1, &tms32010_device::add_sh },{1, &tms32010_device::add_sh },{1, &tms32010_device::add_sh },{1, &tms32010_device::add_sh },{1, &tms32010_device::add_sh },{1, &tms32010_device::add_sh },{1, &tms32010_device::add_sh }, +/*08*/ {1, &tms32010_device::add_sh },{1, &tms32010_device::add_sh },{1, &tms32010_device::add_sh },{1, &tms32010_device::add_sh },{1, &tms32010_device::add_sh },{1, &tms32010_device::add_sh },{1, &tms32010_device::add_sh },{1, &tms32010_device::add_sh }, +/*10*/ {1, &tms32010_device::sub_sh },{1, &tms32010_device::sub_sh },{1, &tms32010_device::sub_sh },{1, &tms32010_device::sub_sh },{1, &tms32010_device::sub_sh },{1, &tms32010_device::sub_sh },{1, &tms32010_device::sub_sh },{1, &tms32010_device::sub_sh }, +/*18*/ {1, &tms32010_device::sub_sh },{1, &tms32010_device::sub_sh },{1, &tms32010_device::sub_sh },{1, &tms32010_device::sub_sh },{1, &tms32010_device::sub_sh },{1, &tms32010_device::sub_sh },{1, &tms32010_device::sub_sh },{1, &tms32010_device::sub_sh }, +/*20*/ {1, &tms32010_device::lac_sh },{1, &tms32010_device::lac_sh },{1, &tms32010_device::lac_sh },{1, &tms32010_device::lac_sh },{1, &tms32010_device::lac_sh },{1, &tms32010_device::lac_sh },{1, &tms32010_device::lac_sh },{1, &tms32010_device::lac_sh }, +/*28*/ {1, &tms32010_device::lac_sh },{1, &tms32010_device::lac_sh },{1, &tms32010_device::lac_sh },{1, &tms32010_device::lac_sh },{1, &tms32010_device::lac_sh },{1, &tms32010_device::lac_sh },{1, &tms32010_device::lac_sh },{1, &tms32010_device::lac_sh }, +/*30*/ {1, &tms32010_device::sar_ar0 },{1, &tms32010_device::sar_ar1 },{0, &tms32010_device::illegal },{0, &tms32010_device::illegal },{0, &tms32010_device::illegal },{0, &tms32010_device::illegal },{0, &tms32010_device::illegal },{0, &tms32010_device::illegal }, +/*38*/ {1, &tms32010_device::lar_ar0 },{1, &tms32010_device::lar_ar1 },{0, &tms32010_device::illegal },{0, &tms32010_device::illegal },{0, &tms32010_device::illegal },{0, &tms32010_device::illegal },{0, &tms32010_device::illegal },{0, &tms32010_device::illegal }, +/*40*/ {2, &tms32010_device::in_p },{2, &tms32010_device::in_p },{2, &tms32010_device::in_p },{2, &tms32010_device::in_p },{2, &tms32010_device::in_p },{2, &tms32010_device::in_p },{2, &tms32010_device::in_p },{2, &tms32010_device::in_p }, +/*48*/ {2, &tms32010_device::out_p },{2, &tms32010_device::out_p },{2, &tms32010_device::out_p },{2, &tms32010_device::out_p },{2, &tms32010_device::out_p },{2, &tms32010_device::out_p },{2, &tms32010_device::out_p },{2, &tms32010_device::out_p }, +/*50*/ {1, &tms32010_device::sacl },{0, &tms32010_device::illegal },{0, &tms32010_device::illegal },{0, &tms32010_device::illegal },{0, &tms32010_device::illegal },{0, &tms32010_device::illegal },{0, &tms32010_device::illegal },{0, &tms32010_device::illegal }, +/*58*/ {1, &tms32010_device::sach_sh },{1, &tms32010_device::sach_sh },{1, &tms32010_device::sach_sh },{1, &tms32010_device::sach_sh },{1, &tms32010_device::sach_sh },{1, &tms32010_device::sach_sh },{1, &tms32010_device::sach_sh },{1, &tms32010_device::sach_sh }, +/*60*/ {1, &tms32010_device::addh },{1, &tms32010_device::adds },{1, &tms32010_device::subh },{1, &tms32010_device::subs },{1, &tms32010_device::subc },{1, &tms32010_device::zalh },{1, &tms32010_device::zals },{3, &tms32010_device::tblr }, +/*68*/ {1, &tms32010_device::larp_mar},{1, &tms32010_device::dmov },{1, &tms32010_device::lt },{1, &tms32010_device::ltd },{1, &tms32010_device::lta },{1, &tms32010_device::mpy },{1, &tms32010_device::ldpk },{1, &tms32010_device::ldp }, +/*70*/ {1, &tms32010_device::lark_ar0},{1, &tms32010_device::lark_ar1 },{0, &tms32010_device::illegal },{0, &tms32010_device::illegal },{0, &tms32010_device::illegal },{0, &tms32010_device::illegal },{0, &tms32010_device::illegal },{0, &tms32010_device::illegal }, +/*78*/ {1, &tms32010_device::xor_ },{1, &tms32010_device::and_ },{1, &tms32010_device::or_ },{1, &tms32010_device::lst },{1, &tms32010_device::sst },{3, &tms32010_device::tblw },{1, &tms32010_device::lack },{0, &tms32010_device::opcodes_7F }, +/*80*/ {1, &tms32010_device::mpyk },{1, &tms32010_device::mpyk },{1, &tms32010_device::mpyk },{1, &tms32010_device::mpyk },{1, &tms32010_device::mpyk },{1, &tms32010_device::mpyk },{1, &tms32010_device::mpyk },{1, &tms32010_device::mpyk }, +/*88*/ {1, &tms32010_device::mpyk },{1, &tms32010_device::mpyk },{1, &tms32010_device::mpyk },{1, &tms32010_device::mpyk },{1, &tms32010_device::mpyk },{1, &tms32010_device::mpyk },{1, &tms32010_device::mpyk },{1, &tms32010_device::mpyk }, +/*90*/ {1, &tms32010_device::mpyk },{1, &tms32010_device::mpyk },{1, &tms32010_device::mpyk },{1, &tms32010_device::mpyk },{1, &tms32010_device::mpyk },{1, &tms32010_device::mpyk },{1, &tms32010_device::mpyk },{1, &tms32010_device::mpyk }, +/*98*/ {1, &tms32010_device::mpyk },{1, &tms32010_device::mpyk },{1, &tms32010_device::mpyk },{1, &tms32010_device::mpyk },{1, &tms32010_device::mpyk },{1, &tms32010_device::mpyk },{1, &tms32010_device::mpyk },{1, &tms32010_device::mpyk }, +/*A0*/ {0, &tms32010_device::illegal },{0, &tms32010_device::illegal },{0, &tms32010_device::illegal },{0, &tms32010_device::illegal },{0, &tms32010_device::illegal },{0, &tms32010_device::illegal },{0, &tms32010_device::illegal },{0, &tms32010_device::illegal }, +/*A8*/ {0, &tms32010_device::illegal },{0, &tms32010_device::illegal },{0, &tms32010_device::illegal },{0, &tms32010_device::illegal },{0, &tms32010_device::illegal },{0, &tms32010_device::illegal },{0, &tms32010_device::illegal },{0, &tms32010_device::illegal }, +/*B0*/ {0, &tms32010_device::illegal },{0, &tms32010_device::illegal },{0, &tms32010_device::illegal },{0, &tms32010_device::illegal },{0, &tms32010_device::illegal },{0, &tms32010_device::illegal },{0, &tms32010_device::illegal },{0, &tms32010_device::illegal }, +/*B8*/ {0, &tms32010_device::illegal },{0, &tms32010_device::illegal },{0, &tms32010_device::illegal },{0, &tms32010_device::illegal },{0, &tms32010_device::illegal },{0, &tms32010_device::illegal },{0, &tms32010_device::illegal },{0, &tms32010_device::illegal }, +/*C0*/ {0, &tms32010_device::illegal },{0, &tms32010_device::illegal },{0, &tms32010_device::illegal },{0, &tms32010_device::illegal },{0, &tms32010_device::illegal },{0, &tms32010_device::illegal },{0, &tms32010_device::illegal },{0, &tms32010_device::illegal }, +/*C8*/ {0, &tms32010_device::illegal },{0, &tms32010_device::illegal },{0, &tms32010_device::illegal },{0, &tms32010_device::illegal },{0, &tms32010_device::illegal },{0, &tms32010_device::illegal },{0, &tms32010_device::illegal },{0, &tms32010_device::illegal }, +/*D0*/ {0, &tms32010_device::illegal },{0, &tms32010_device::illegal },{0, &tms32010_device::illegal },{0, &tms32010_device::illegal },{0, &tms32010_device::illegal },{0, &tms32010_device::illegal },{0, &tms32010_device::illegal },{0, &tms32010_device::illegal }, +/*D8*/ {0, &tms32010_device::illegal },{0, &tms32010_device::illegal },{0, &tms32010_device::illegal },{0, &tms32010_device::illegal },{0, &tms32010_device::illegal },{0, &tms32010_device::illegal },{0, &tms32010_device::illegal },{0, &tms32010_device::illegal }, +/*E0*/ {0, &tms32010_device::illegal },{0, &tms32010_device::illegal },{0, &tms32010_device::illegal },{0, &tms32010_device::illegal },{0, &tms32010_device::illegal },{0, &tms32010_device::illegal },{0, &tms32010_device::illegal },{0, &tms32010_device::illegal }, +/*E8*/ {0, &tms32010_device::illegal },{0, &tms32010_device::illegal },{0, &tms32010_device::illegal },{0, &tms32010_device::illegal },{0, &tms32010_device::illegal },{0, &tms32010_device::illegal },{0, &tms32010_device::illegal },{0, &tms32010_device::illegal }, +/*F0*/ {0, &tms32010_device::illegal },{0, &tms32010_device::illegal },{0, &tms32010_device::illegal },{0, &tms32010_device::illegal },{1, &tms32010_device::banz },{1, &tms32010_device::bv },{1, &tms32010_device::bioz },{0, &tms32010_device::illegal }, +/*F8*/ {2, &tms32010_device::call },{2, &tms32010_device::br },{1, &tms32010_device::blz },{1, &tms32010_device::blez },{1, &tms32010_device::bgz },{1, &tms32010_device::bgez },{1, &tms32010_device::bnz },{1, &tms32010_device::bz } +}; + +const tms32010_device::tms32010_opcode tms32010_device::s_opcode_7F[32]= +{ +/*80*/ {1, &tms32010_device::nop },{1, &tms32010_device::dint },{1, &tms32010_device::eint },{0, &tms32010_device::illegal },{0, &tms32010_device::illegal },{0, &tms32010_device::illegal },{0, &tms32010_device::illegal },{0, &tms32010_device::illegal }, +/*88*/ {1, &tms32010_device::abst },{1, &tms32010_device::zac },{1, &tms32010_device::rovm },{1, &tms32010_device::sovm },{2, &tms32010_device::cala },{2, &tms32010_device::ret },{1, &tms32010_device::pac },{1, &tms32010_device::apac }, +/*90*/ {1, &tms32010_device::spac },{0, &tms32010_device::illegal },{0, &tms32010_device::illegal },{0, &tms32010_device::illegal },{0, &tms32010_device::illegal },{0, &tms32010_device::illegal },{0, &tms32010_device::illegal },{0, &tms32010_device::illegal }, +/*98*/ {0, &tms32010_device::illegal },{0, &tms32010_device::illegal },{0, &tms32010_device::illegal },{0, &tms32010_device::illegal },{2, &tms32010_device::push },{2, &tms32010_device::pop },{0, &tms32010_device::illegal },{0, &tms32010_device::illegal } +}; + +int tms32010_device::add_branch_cycle() +{ + return s_opcode_main[m_opcode.b.h].cycles; +} + +/**************************************************************************** + * Inits CPU emulation + ****************************************************************************/ + +void tms32010_device::device_start() +{ + save_item(NAME(m_PC)); + save_item(NAME(m_PREVPC)); + save_item(NAME(m_STR)); + save_item(NAME(m_ACC.d)); + save_item(NAME(m_ALU.d)); + save_item(NAME(m_Preg.d)); + save_item(NAME(m_Treg)); + save_item(NAME(m_AR[0])); + save_item(NAME(m_AR[1])); + save_item(NAME(m_STACK[0])); + save_item(NAME(m_STACK[1])); + save_item(NAME(m_STACK[2])); + save_item(NAME(m_STACK[3])); + save_item(NAME(m_INTF)); + save_item(NAME(m_opcode.d)); + save_item(NAME(m_oldacc.d)); + save_item(NAME(m_memaccess)); + save_item(NAME(m_addr_mask)); + + m_program = &space(AS_PROGRAM); + m_direct = &m_program->direct(); + m_data = &space(AS_DATA); + m_io = &space(AS_IO); + + m_PREVPC = 0; + m_ALU.d = 0; + m_Preg.d = 0; + m_Treg = 0; + m_AR[0] = m_AR[1] = 0; + m_STACK[0] = m_STACK[1] = m_STACK[2] = m_STACK[3] = 0; + m_opcode.d = 0; + m_oldacc.d = 0; + m_memaccess = 0; + m_PC = 0; + m_STR = 0; + m_ACC.d = 0; + + state_add( TMS32010_PC, "PC", m_PC).formatstr("%04X"); + state_add( TMS32010_STR, "STR", m_STR).formatstr("%04X"); + state_add( TMS32010_ACC, "ACC", m_ACC.d).formatstr("%08X"); + state_add( TMS32010_PREG, "P", m_Preg.d).formatstr("%08X"); + state_add( TMS32010_TREG, "T", m_Treg).formatstr("%04X"); + state_add( TMS32010_AR0, "AR0", m_AR[0]).formatstr("%04X"); + state_add( TMS32010_AR1, "AR1", m_AR[1]).formatstr("%04X"); + state_add( TMS32010_STK0, "STK0", m_STACK[0]).formatstr("%04X"); + state_add( TMS32010_STK1, "STK1", m_STACK[1]).formatstr("%04X"); + state_add( TMS32010_STK2, "STK2", m_STACK[2]).formatstr("%04X"); + state_add( TMS32010_STK3, "STK3", m_STACK[3]).formatstr("%04X"); + + state_add(STATE_GENPC, "GENPC", m_PC).formatstr("%04X").noshow(); + /* This is actually not a stack pointer, but the stack contents */ + state_add(STATE_GENSP, "GENSP", m_STACK[3]).formatstr("%04X").noshow(); + state_add(STATE_GENFLAGS, "GENFLAGS", m_STR).formatstr("%16s").noshow(); + state_add(STATE_GENPCBASE, "GENPCBASE", m_PREVPC).formatstr("%04X").noshow(); + + m_icountptr = &m_icount; +} + + +/**************************************************************************** + * TMS32010 Reset registers to their initial values + ****************************************************************************/ + +void tms32010_device::device_reset() +{ + m_PC = 0; + m_ACC.d = 0; + m_INTF = TMS32010_INT_NONE; + /* Setup Status Register : 7efe */ + CLR((OV_FLAG | ARP_REG | DP_REG)); + SET_FLAG((OVM_FLAG | INTM_FLAG)); +} + + +void tms32010_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + switch (entry.index()) + { + case STATE_GENFLAGS: + strprintf(str, "%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c", + m_STR & 0x8000 ? 'O':'.', + m_STR & 0x4000 ? 'M':'.', + m_STR & 0x2000 ? 'I':'.', + m_STR & 0x1000 ? '.':'?', + m_STR & 0x0800 ? 'a':'?', + m_STR & 0x0400 ? 'r':'?', + m_STR & 0x0200 ? 'p':'?', + m_STR & 0x0100 ? '1':'0', + m_STR & 0x0080 ? '.':'?', + m_STR & 0x0040 ? '.':'?', + m_STR & 0x0020 ? '.':'?', + m_STR & 0x0010 ? '.':'?', + m_STR & 0x0008 ? '.':'?', + m_STR & 0x0004 ? 'd':'?', + m_STR & 0x0002 ? 'p':'?', + m_STR & 0x0001 ? '1':'0' + ); + break; + } +} + + +/**************************************************************************** + * Set IRQ line state + ****************************************************************************/ + +void tms32010_device::execute_set_input(int irqline, int state) +{ + /* Pending Interrupts cannot be cleared! */ + if (state == ASSERT_LINE) m_INTF |= TMS32010_INT_PENDING; +} + + + +/**************************************************************************** + * Issue an interrupt if necessary + ****************************************************************************/ + +int tms32010_device::Ext_IRQ() +{ + if (INTM == 0) + { + logerror("TMS32010: EXT INTERRUPT\n"); + m_INTF = TMS32010_INT_NONE; + SET_FLAG(INTM_FLAG); + PUSH_STACK(m_PC); + m_PC = 0x0002; + return (s_opcode_7F[0x1c].cycles + s_opcode_7F[0x01].cycles); /* 3 cycles used due to PUSH and DINT operation ? */ + } + return (0); +} + + +/**************************************************************************** + * Execute IPeriod. Return 0 if emulation should be stopped + ****************************************************************************/ + +void tms32010_device::execute_run() +{ + do + { + if (m_INTF) { + /* Dont service INT if previous instruction was MPY, MPYK or EINT */ + if ((m_opcode.b.h != 0x6d) && ((m_opcode.b.h & 0xe0) != 0x80) && (m_opcode.w.l != 0x7f82)) + m_icount -= Ext_IRQ(); + } + + m_PREVPC = m_PC; + + debugger_instruction_hook(this, m_PC); + + m_opcode.d = M_RDOP(m_PC); + m_PC++; + + if (m_opcode.b.h != 0x7f) { /* Do all opcodes except the 7Fxx ones */ + m_icount -= s_opcode_main[m_opcode.b.h].cycles; + (this->*s_opcode_main[m_opcode.b.h].function)(); + } + else { /* Opcode major byte 7Fxx has many opcodes in its minor byte */ + m_icount -= s_opcode_7F[(m_opcode.b.l & 0x1f)].cycles; + (this->*s_opcode_7F[(m_opcode.b.l & 0x1f)].function)(); + } + } while (m_icount > 0); +} diff --git a/src/devices/cpu/tms32010/tms32010.h b/src/devices/cpu/tms32010/tms32010.h new file mode 100644 index 00000000000..6059d1efa57 --- /dev/null +++ b/src/devices/cpu/tms32010/tms32010.h @@ -0,0 +1,222 @@ +// license:BSD-3-Clause +// copyright-holders:Tony La Porta + /**************************************************************************\ + * Texas Instruments TMS32010 DSP Emulator * + * * + * Copyright Tony La Porta * + * You are not allowed to distribute this software commercially. * + * Written for the MAME project. * + * * + * * + * Note : This is a word based microcontroller, with addressing * + * architecture based on the Harvard addressing scheme. * + * * + \**************************************************************************/ + +#pragma once + +#ifndef __TMS32010_H__ +#define __TMS32010_H__ + + + + +/**************************************************************************** + * Use this in the I/O port address fields of your driver for the BIO pin + * i.e, + * AM_RANGE(TMS32010_BIO, TMS32010_BIO) AM_READ(twincobr_bio_line_r) + */ + +#define TMS32010_BIO 0x10 /* BIO input */ + + +#define TMS32010_INT_PENDING 0x80000000 +#define TMS32010_INT_NONE 0 + + +enum +{ + TMS32010_PC=1, TMS32010_SP, TMS32010_STR, TMS32010_ACC, + TMS32010_PREG, TMS32010_TREG, TMS32010_AR0, TMS32010_AR1, + TMS32010_STK0, TMS32010_STK1, TMS32010_STK2, TMS32010_STK3 +}; + + +/**************************************************************************** + * Public Functions + */ + + +class tms32010_device : public cpu_device +{ +public: + // construction/destruction + tms32010_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + tms32010_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source, int addr_mask); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_execute_interface overrides + virtual UINT32 execute_min_cycles() const { return 1; } + virtual UINT32 execute_max_cycles() const { return 3; } + virtual UINT32 execute_input_lines() const { return 1; } + virtual void execute_run(); + virtual void execute_set_input(int inputnum, int state); + virtual UINT64 execute_clocks_to_cycles(UINT64 clocks) const { return (clocks + 4 - 1) / 4; } + virtual UINT64 execute_cycles_to_clocks(UINT64 cycles) const { return (cycles * 4); } + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const { return (spacenum == AS_PROGRAM) ? &m_program_config : ( (spacenum == AS_IO) ? &m_io_config : ( (spacenum == AS_DATA) ? &m_data_config : NULL ) ); } + + // device_state_interface overrides + void state_string_export(const device_state_entry &entry, std::string &str); + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const { return 2; } + virtual UINT32 disasm_max_opcode_bytes() const { return 4; } + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + +private: + address_space_config m_program_config; + address_space_config m_data_config; + address_space_config m_io_config; + + typedef void ( tms32010_device::*opcode_func ) (); + struct tms32010_opcode + { + UINT8 cycles; + opcode_func function; + }; + static const tms32010_opcode s_opcode_main[256]; + static const tms32010_opcode s_opcode_7F[32]; + + /******************** CPU Internal Registers *******************/ + UINT16 m_PC; + UINT16 m_PREVPC; /* previous program counter */ + UINT16 m_STR; + PAIR m_ACC; + PAIR m_ALU; + PAIR m_Preg; + UINT16 m_Treg; + UINT16 m_AR[2]; + UINT16 m_STACK[4]; + + PAIR m_opcode; + int m_INTF; /* Pending Interrupt flag */ + int m_icount; + PAIR m_oldacc; + UINT16 m_memaccess; + int m_addr_mask; + + address_space *m_program; + direct_read_data *m_direct; + address_space *m_data; + address_space *m_io; + + inline void CLR(UINT16 flag); + inline void SET_FLAG(UINT16 flag); + inline void CALCULATE_ADD_OVERFLOW(INT32 addval); + inline void CALCULATE_SUB_OVERFLOW(INT32 subval); + inline UINT16 POP_STACK(); + inline void PUSH_STACK(UINT16 data); + inline void UPDATE_AR(); + inline void UPDATE_ARP(); + inline void getdata(UINT8 shift,UINT8 signext); + inline void putdata(UINT16 data); + inline void putdata_sar(UINT8 data); + inline void putdata_sst(UINT16 data); + void opcodes_7F(); + void illegal(); + void abst(); + void add_sh(); + void addh(); + void adds(); + void and_(); + void apac(); + void br(); + void banz(); + void bgez(); + void bgz(); + void bioz(); + void blez(); + void blz(); + void bnz(); + void bv(); + void bz(); + void cala(); + void call(); + void dint(); + void dmov(); + void eint(); + void in_p(); + void lac_sh(); + void lack(); + void lar_ar0(); + void lar_ar1(); + void lark_ar0(); + void lark_ar1(); + void larp_mar(); + void ldp(); + void ldpk(); + void lst(); + void lt(); + void lta(); + void ltd(); + void mpy(); + void mpyk(); + void nop(); + void or_(); + void out_p(); + void pac(); + void pop(); + void push(); + void ret(); + void rovm(); + void sach_sh(); + void sacl(); + void sar_ar0(); + void sar_ar1(); + void sovm(); + void spac(); + void sst(); + void sub_sh(); + void subc(); + void subh(); + void subs(); + void tblr(); + void tblw(); + void xor_(); + void zac(); + void zalh(); + void zals(); + inline int add_branch_cycle(); + int Ext_IRQ(); + +}; + + +class tms32015_device : public tms32010_device +{ +public: + // construction/destruction + tms32015_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +class tms32016_device : public tms32010_device +{ +public: + // construction/destruction + tms32016_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +extern const device_type TMS32010; +extern const device_type TMS32015; +extern const device_type TMS32016; + + +#endif /* __TMS32010_H__ */ diff --git a/src/devices/cpu/tms32025/32025dsm.c b/src/devices/cpu/tms32025/32025dsm.c new file mode 100644 index 00000000000..d266c468d65 --- /dev/null +++ b/src/devices/cpu/tms32025/32025dsm.c @@ -0,0 +1,507 @@ +// license:BSD-3-Clause +// copyright-holders:Tony La Porta, hap + /**************************************************************************\ + * Texas Instruments TMS320x25 DSP Disassembler * + * * + * Copyright Tony La Porta * + * To be used with TMS320x25 DSP Emulator engine. * + * Written for the MAME project. * + * * + * Many thanks to those involved in the i8039 Disassembler * + * as the structure here was borrowed from it. * + * * + * Note : This is a word based microcontroller, with addressing * + * architecture based on the Harvard addressing scheme. * + * * + * * + * A Memory Address * + * B Opcode Address Argument (Requires next opcode read) * + * C Compare mode * + * D Immediate byte load * + * K Immediate bit load * + * W Immediate word load * + * M AR[x] register modification type (for indirect addressing) * + * N ARP register to change ARP pointer to (for indirect addressing) * + * P I/O port address number * + * R AR[R] register to use * + * S Shift ALU left * + * T Shift ALU left (Hex) / Nibble data * + * X Don't care bit * + * * + \**************************************************************************/ + +#include "emu.h" +#include "debugger.h" +#include + +#include "tms32025.h" + + + +typedef unsigned char byte; +typedef unsigned short int word; + +#define FMT(a,b) a, b +#define PTRS_PER_FORMAT 2 + +static const char *const arith[8] = { "*", "*-", "*+", "??", "BR0-", "*0-", "*0+", "*BR0+" } ; +static const char *const nextar[16] = { "", "", "", "", "", "", "", "", ",AR0", ",AR1", ",AR2", ",AR3", ",AR4", ",AR5", ",AR6", ",AR7" } ; +static const char *const cmpmode[4] = { "0 (ARx = AR0)" , "1 (ARx < AR0)" , "2 (ARx > AR0)" , "3 (ARx <> AR0)" } ; + + +static const char *const TMS32025Formats[] = { + FMT("0000tttt0aaaaaaa", "add %A,%T"), /* 0xxx */ + FMT("0000tttt1mmmnnnn", "add %M,%T%N"), + FMT("0001tttt0aaaaaaa", "sub %A,%T"), /* 1xxx */ + FMT("0001tttt1mmmnnnn", "sub %M,%T%N"), + FMT("0010tttt0aaaaaaa", "lac %A,%T"), /* 2xxx */ + FMT("0010tttt1mmmnnnn", "lac %M,%T%N"), + FMT("00110rrr0aaaaaaa", "lar %R,%A"), /* 3xxx */ + FMT("00110rrr1mmmnnnn", "lar %R%M%N"), + FMT("001110000aaaaaaa", "mpy %A"), /* 38xx */ + FMT("001110001mmmnnnn", "mpy %M%N"), + FMT("001110010aaaaaaa", "sqra %A"), /* 39xx */ + FMT("001110011mmmnnnn", "sqra %M%N"), + FMT("001110100aaaaaaa", "mpya %A"), /* 3Axx */ + FMT("001110101mmmnnnn", "mpya %M%N"), + FMT("001110110aaaaaaa", "mpys %A"), /* 3Bxx */ + FMT("001110111mmmnnnn", "mpys %M%N"), + FMT("001111000aaaaaaa", "lt %A"), /* 3Cxx */ + FMT("001111001mmmnnnn", "lt %M%N"), + FMT("001111010aaaaaaa", "lta %A"), /* 3Dxx */ + FMT("001111011mmmnnnn", "lta %M%N"), + FMT("001111100aaaaaaa", "ltp %A"), /* 3Exx */ + FMT("001111101mmmnnnn", "ltp %M%N"), + FMT("001111110aaaaaaa", "ltd %A"), /* 3Fxx */ + FMT("001111111mmmnnnn", "ltd %M%N"), + FMT("010000000aaaaaaa", "zalh %A"), /* 40xx */ + FMT("010000001mmmnnnn", "zalh %M%N"), + FMT("010000010aaaaaaa", "zals %A"), /* 41xx */ + FMT("010000011mmmnnnn", "zals %M%N"), + FMT("010000100aaaaaaa", "lact %A"), /* 42xx */ + FMT("010000101mmmnnnn", "lact %M%N"), + FMT("010000110aaaaaaa", "addc %A%S"), /* 43xx */ + FMT("010000111mmmnnnn", "addc %M%S%N"), + FMT("010001000aaaaaaa", "subh %A"), /* 44xx */ + FMT("010001001mmmnnnn", "subh %M%N"), + FMT("010001010aaaaaaa", "subs %A"), /* 45xx */ + FMT("010001011mmmnnnn", "subs %M%N"), + FMT("010001100aaaaaaa", "subt %A"), /* 46xx */ + FMT("010001101mmmnnnn", "subt %M%N"), + FMT("010001110aaaaaaa", "subc %A"), /* 47xx */ + FMT("010001111mmmnnnn", "subc %M%N"), + FMT("010010000aaaaaaa", "addh %A"), /* 48xx */ + FMT("010010001mmmnnnn", "addh %M%N"), + FMT("010010010aaaaaaa", "adds %A"), /* 49xx */ + FMT("010010011mmmnnnn", "adds %M%N"), + FMT("010010100aaaaaaa", "addt %A"), /* 4Axx */ + FMT("010010101mmmnnnn", "addt %M%N"), + FMT("010010110aaaaaaa", "rpt %A"), /* 4Bxx */ + FMT("010010111mmmnnnn", "rpt %M%N"), + FMT("010011000aaaaaaa", "xor %A"), /* 4Cxx */ + FMT("010011001mmmnnnn", "xor %M%N"), + FMT("010011010aaaaaaa", "or %A"), /* 4Dxx */ + FMT("010011011mmmnnnn", "or %M%N"), + FMT("010011100aaaaaaa", "and %A"), /* 4Exx */ + FMT("010011101mmmnnnn", "and %M%N"), + FMT("010011110aaaaaaa", "subb %A"), /* 4Fxx */ + FMT("010011111mmmnnnn", "subb %M%N"), + FMT("010100000aaaaaaa", "lst %A"), /* 50xx */ + FMT("010100001mmmnnnn", "lst %M%N"), + FMT("010100010aaaaaaa", "lst1 %A"), /* 51xx */ + FMT("010100011mmmnnnn", "lst1 %M%N"), + FMT("010100100aaaaaaa", "ldp %A"), /* 52xx */ + FMT("010100101mmmnnnn", "ldp %M%N"), + FMT("010100110aaaaaaa", "lph %A"), /* 53xx */ + FMT("010100111mmmnnnn", "lph %M%N"), + FMT("010101000aaaaaaa", "pshd %A"), /* 54xx */ + FMT("010101001mmmnnnn", "pshd %M%N"), + +/* FMT("010101010aaaaaaa", "mar %A"), 55xx */ +/* MAR direct has been expanded out to all its variations because one of its */ +/* its opcodes is the same as NOP. Actually MAR direct just performs a NOP */ + FMT("0101010100000000", "nop"), /* 5500 */ + FMT("0101010100000001", "mar $01"), + FMT("0101010100000010", "mar $02"), + FMT("0101010100000011", "mar $03"), + FMT("0101010100000100", "mar $04"), + FMT("0101010100000101", "mar $05"), + FMT("0101010100000110", "mar $06"), + FMT("0101010100000111", "mar $07"), + FMT("0101010100001000", "mar $08"), + FMT("0101010100001001", "mar $09"), + FMT("0101010100001010", "mar $0A"), + FMT("0101010100001011", "mar $0B"), + FMT("0101010100001100", "mar $0C"), + FMT("0101010100001101", "mar $0D"), + FMT("0101010100001110", "mar $0E"), + FMT("0101010100001111", "mar $0F"), + FMT("010101010001tttt", "mar $1%T"), + FMT("010101010010tttt", "mar $2%T"), + FMT("010101010011tttt", "mar $3%T"), + FMT("010101010100tttt", "mar $4%T"), + FMT("010101010101tttt", "mar $5%T"), + FMT("010101010110tttt", "mar $6%T"), + FMT("010101010111tttt", "mar $7%T"), + +/* FMT("010101011mmmnnnn", "mar %M%N"), 55xx */ +/* MAR indirect has been expanded out to all its variations because one of */ +/* its opcodes, is the same as LARP (actually performs the same function) */ + FMT("0101010110000xxx", "mar *"), /* 558x */ + FMT("0101010110001kkk", "larp %K"), /* 558x */ + FMT("010101011001nnnn", "mar *-%N"), /* 558x */ + FMT("010101011010nnnn", "mar *+%N"), + FMT("010101011011nnnn", "mar ??%N"), + FMT("010101011100nnnn", "mar *BR0-%N"), + FMT("010101011101nnnn", "mar *0-%N"), + FMT("010101011110nnnn", "mar *0+%N"), + FMT("010101011111nnnn", "mar *BR0+%N"), + + FMT("010101100aaaaaaa", "dmov %A"), /* 56xx */ + FMT("010101101mmmnnnn", "dmov %M%N"), + FMT("010101110aaaaaaa", "bitt %A"), /* 57xx */ + FMT("010101111mmmnnnn", "bitt %M%N"), + FMT("010110000aaaaaaa", "tblr %A"), /* 58xx */ + FMT("010110001mmmnnnn", "tblr %M%N"), + FMT("010110010aaaaaaa", "tblw %A"), /* 59xx */ + FMT("010110011mmmnnnn", "tblw %M%N"), + FMT("010110100aaaaaaa", "sqrs %A"), /* 5Axx */ + FMT("010110101mmmnnnn", "sqrs %M%N"), + FMT("010110110aaaaaaa", "lts %A"), /* 5Bxx */ + FMT("010110111mmmnnnn", "lts %M%N"), + FMT("010111000aaaaaaabbbbbbbbbbbbbbbb", "macd %B,%A"), /* 5Cxx */ + FMT("010111001mmmnnnnbbbbbbbbbbbbbbbb", "macd %B,%M%N"), + FMT("010111010aaaaaaabbbbbbbbbbbbbbbb", "mac %B,%A"), /* 5Dxx */ + FMT("010111011mmmnnnnbbbbbbbbbbbbbbbb", "mac %B,%M%N"), + FMT("010111101mmmnnnnbbbbbbbbbbbbbbbb", "bc %B %M%N"), /* 5Exx */ + FMT("010111111mmmnnnnbbbbbbbbbbbbbbbb", "bnc %B %M%N"), /* 5Fxx */ + FMT("01100sss0aaaaaaa", "sacl %A%S"), /* 6xxx */ + FMT("01100sss1mmmnnnn", "sacl %M%S%N"), + FMT("01101sss0aaaaaaa", "sach %A%S"), /* 6Xxx */ + FMT("01101sss1mmmnnnn", "sach %M%S%N"), + FMT("01110rrr0aaaaaaa", "sar %R,%A"), /* 7xxx */ + FMT("01110rrr1mmmnnnn", "sar %R%M%N"), + FMT("011110000aaaaaaa", "sst %A"), /* 78xx */ + FMT("011110001mmmnnnn", "sst %M%N"), + FMT("011110010aaaaaaa", "sst1 %A"), /* 79xx */ + FMT("011110011mmmnnnn", "sst1 %M%N"), + FMT("011110100aaaaaaa", "popd %A"), /* 7Axx */ + FMT("011110101mmmnnnn", "popd %M%N"), + FMT("011110110aaaaaaa", "zalr %A"), /* 7Bxx */ + FMT("011110111mmmnnnn", "zalr %M%N"), + FMT("011111000aaaaaaa", "spl %A"), /* 7Cxx */ + FMT("011111001mmmnnnn", "spl %M%N"), + FMT("011111010aaaaaaa", "sph %A"), /* 7Dxx */ + FMT("011111011mmmnnnn", "sph %M%N"), + FMT("011111100aaaaaaa", "adrk %A"), /* 7Exx */ + FMT("011111101mmmnnnn", "adrk %M%N"), + FMT("011111110aaaaaaa", "sbrk %A"), /* 7Fxx */ + FMT("011111111mmmnnnn", "sbrk %M%N"), + FMT("1000pppp0aaaaaaa", "in %A,%P"), /* 8xxx */ + FMT("1000pppp1mmmnnnn", "in %M,%P%N"), + FMT("1001tttt0aaaaaaa", "bit %A,%T"), /* 9xxx */ + FMT("1001tttt1mmmnnnn", "bit %M,%T%N"), + FMT("101wwwwwwwwwwwww", "mpyk %W"), /* Axxx-Bxxx */ + FMT("11000rrrdddddddd", "lark %R,%D"), /* Cxxx */ + FMT("1100100kdddddddd", "ldpk %K%D"), /* Cxxx */ +/* FMT("11001010dddddddd", "lack %D"), CAxx */ +/* LACK has been expanded out to all its variations because one of its */ +/* its opcodes is the same as ZAC. Actually, it performs the same function */ + FMT("1100101000000000", "zac"), /* CA00 */ + FMT("1100101000000001", "lack 01h"), /* CAxx */ + FMT("1100101000000010", "lack 02h"), + FMT("1100101000000011", "lack 03h"), + FMT("1100101000000100", "lack 04h"), + FMT("1100101000000101", "lack 05h"), + FMT("1100101000000110", "lack 06h"), + FMT("1100101000000111", "lack 07h"), + FMT("1100101000001000", "lack 08h"), + FMT("1100101000001001", "lack 09h"), + FMT("1100101000001010", "lack 0Ah"), + FMT("1100101000001011", "lack 0Bh"), + FMT("1100101000001100", "lack 0Ch"), + FMT("1100101000001101", "lack 0Dh"), + FMT("1100101000001110", "lack 0Eh"), + FMT("1100101000001111", "lack 0Fh"), + FMT("110010100001tttt", "lack 1%T"), + FMT("110010100010tttt", "lack 2%T"), + FMT("110010100011tttt", "lack 3%T"), + FMT("110010100100tttt", "lack 4%T"), + FMT("110010100101tttt", "lack 5%T"), + FMT("110010100110tttt", "lack 6%T"), + FMT("110010100111tttt", "lack 7%T"), + FMT("110010101000tttt", "lack 8%T"), + FMT("110010101001tttt", "lack 9%T"), + FMT("110010101010tttt", "lack A%T"), + FMT("110010101011tttt", "lack B%T"), + FMT("110010101100tttt", "lack C%T"), + FMT("110010101101tttt", "lack D%T"), + FMT("110010101110tttt", "lack E%T"), + FMT("110010101111tttt", "lack F%T"), + + FMT("11001011dddddddd", "rptk %D"), /* CBxx */ + FMT("11001100dddddddd", "addk %D"), /* CCxx */ + FMT("11001101dddddddd", "subk %D"), /* CDxx */ + FMT("1100111000000000", "eint"), /* CE00 */ + FMT("1100111000000001", "dint"), /* CE01 */ + FMT("1100111000000010", "rovm"), /* CE02 */ + FMT("1100111000000011", "sovm"), /* CE03 */ + FMT("1100111000000100", "cnfd"), /* CE04 */ + FMT("1100111000000101", "cnfp"), /* CE05 */ + FMT("1100111000000110", "rsxm"), /* CE06 */ + FMT("1100111000000111", "ssxm"), /* CE07 */ + FMT("11001110000010kk", "spm %K"), /* CE0x */ + FMT("1100111000001100", "rxf"), /* CE0C */ + FMT("1100111000001101", "sxf"), /* CE0D */ + FMT("110011100000111k", "fort %K"), /* CE0x */ + FMT("1100111000010100", "pac"), /* CE14 */ + FMT("1100111000010101", "apac"), /* CE15 */ + FMT("1100111000010110", "spac"), /* CE16 */ + FMT("1100111000011000", "sfl"), /* CE18 */ + FMT("1100111000011001", "sfr"), /* CE19 */ + FMT("1100111000011011", "abs"), /* CE1B */ + FMT("1100111000011100", "push"), /* CE1C */ + FMT("1100111000011101", "pop"), /* CE1D */ + FMT("1100111000011110", "trap"), /* CE1E */ + FMT("1100111000011111", "idle"), /* CE1F */ + FMT("1100111000100000", "rtxm"), /* CE20 */ + FMT("1100111000100001", "stxm"), /* CE21 */ + FMT("1100111000100011", "neg"), /* CE23 */ + FMT("1100111000100100", "cala"), /* CE24 */ + FMT("1100111000100101", "bacc"), /* CE25 */ + FMT("1100111000100110", "ret"), /* CE26 */ + FMT("1100111000100111", "cmpl"), /* CE27 */ + FMT("1100111000110000", "rc"), /* CE30 */ + FMT("1100111000110001", "sc"), /* CE31 */ + FMT("1100111000110010", "rtc"), /* CE32 */ + FMT("1100111000110011", "stc"), /* CE33 */ + FMT("1100111000110100", "rol"), /* CE34 */ + FMT("1100111000110101", "ror"), /* CE35 */ + FMT("1100111000110110", "rfsm"), /* CE36 */ + FMT("1100111000110111", "sfsm"), /* CE37 */ + FMT("1100111000111000", "rhm"), /* CE38 */ + FMT("1100111000111001", "shm"), /* CE39 */ + FMT("11001110001111kk", "conf %K"), /* CE3x */ + FMT("11001110010100cc", "cmpr %C"), /* CE5x */ + FMT("110011101mmm0010", "norm %M"), /* CEx2 */ + FMT("110011110aaaaaaa", "mpys %A"), /* CFxx */ + FMT("110011111mmmnnnn", "mpys %M%N"), + FMT("11010rrr00000000wwwwwwwwwwwwwwww", "lrlk %R,%W"), /* Dx00 */ + FMT("1101tttt00000001wwwwwwwwwwwwwwww", "lalk %W,%T"), /* Dx01 */ + FMT("1101tttt00000010wwwwwwwwwwwwwwww", "adlk %W,%T"), /* Dx02 */ + FMT("1101tttt00000011wwwwwwwwwwwwwwww", "sblk %W,%T"), /* Dx03 */ + FMT("1101tttt00000100wwwwwwwwwwwwwwww", "andk %W,%T"), /* Dx04 */ + FMT("1101tttt00000101wwwwwwwwwwwwwwww", "ork %W,%T"), /* Dx05 */ + FMT("1101tttt00000110wwwwwwwwwwwwwwww", "xork %W,%T"), /* Dx06 */ + FMT("1110pppp0aaaaaaa", "out %A,%P"), /* Exxx */ + FMT("1110pppp1mmmnnnn", "out %M,%P%N"), + FMT("111100001mmmnnnnbbbbbbbbbbbbbbbb", "bv %B %M%N"), /* F0xx */ + FMT("111100011mmmnnnnbbbbbbbbbbbbbbbb", "bgz %B %M%N"), /* F1xx */ + FMT("111100101mmmnnnnbbbbbbbbbbbbbbbb", "blez %B %M%N"), /* F2xx */ + FMT("111100111mmmnnnnbbbbbbbbbbbbbbbb", "blz %B %M%N"), /* F3xx */ + FMT("111101001mmmnnnnbbbbbbbbbbbbbbbb", "bgez %B %M%N"), /* F4xx */ + FMT("111101011mmmnnnnbbbbbbbbbbbbbbbb", "bnz %B %M%N"), /* F5xx */ + FMT("111101101mmmnnnnbbbbbbbbbbbbbbbb", "bz %B %M%N"), /* F6xx */ + FMT("111101111mmmnnnnbbbbbbbbbbbbbbbb", "bnv %B %M%N"), /* F7xx */ + FMT("111110001mmmnnnnbbbbbbbbbbbbbbbb", "bbz %B %M%N"), /* F8xx */ + FMT("111110011mmmnnnnbbbbbbbbbbbbbbbb", "bbnz %B %M%N"), /* F9xx */ + FMT("111110101mmmnnnnbbbbbbbbbbbbbbbb", "bioz %B %M%N"), /* FAxx */ + FMT("111110111mmmnnnnbbbbbbbbbbbbbbbb", "banz %B %M%N"), /* FBxx */ + FMT("111111000aaaaaaabbbbbbbbbbbbbbbb", "blkp %B,%A"), /* FCxx */ + FMT("111111001mmmnnnnbbbbbbbbbbbbbbbb", "blkp %B,%M%N"), + FMT("111111010aaaaaaabbbbbbbbbbbbbbbb", "blkd %B,%A"), /* FDxx */ + FMT("111111011mmmnnnnbbbbbbbbbbbbbbbb", "blkd %B,%M%N"), + FMT("111111101mmmnnnnbbbbbbbbbbbbbbbb", "call %B %M%N"), /* FExx */ + FMT("111111111mmmnnnnbbbbbbbbbbbbbbbb", "b %B %M%N"), /* FFxx */ + NULL +}; + +#define MAX_OPS ((ARRAY_LENGTH(TMS32025Formats) - 1) / PTRS_PER_FORMAT) + +struct TMS32025Opcode { + word mask; /* instruction mask */ + word bits; /* constant bits */ + word extcode; /* value that gets extension code */ + const char *parse; /* how to parse bits */ + const char *fmt; /* instruction format */ +}; + +static TMS32025Opcode Op[MAX_OPS+1]; +static int OpInizialized = 0; + +static void InitDasm32025(void) +{ + const char *p; + const char *const *ops; + word mask, bits; + int bit; + int i; + + ops = TMS32025Formats; i = 0; + while (*ops) + { + p = *ops; + mask = 0; bits = 0; bit = 15; + while (*p && bit >= 0) + { + switch (*p++) + { + case '1': mask |= 1<= 0) + { + /* osd_printf_debug("{%c/%d}",*cp,bit); */ + switch(*cp) + { + case 'a': a <<=1; a |= ((code & (1< +#include + +#include "32025dsm.c" + + +unsigned char *Buffer; + + +int main(int argc,char *argv[]) +{ + int length=0, length_to_dump=0, offset=0, disasm_words=0; + int filelength=0, bytes_read; + int Counter=0; + + FILE *F; + char *String_Output; + + if(argc<2) + { + printf("\n"); + printf("TMS32025 Disassembler 1.1 by Tony La Porta (C)2001-2002+\n\n"); + printf("Usage: dis32025 [ [ ] ]\n"); + printf(" source file data must be MSB first\n"); + printf(" starting address to disassemble from (decimal)\n"); + printf(" number of addresses to disassemble (decimal)\n"); + printf(" Precede values with 0x if HEX values preffered\n"); + exit(1); + } + + if(!(F=fopen(argv[1],"rb"))) + { + printf("\n%s: Can't open file %s\n",argv[0],argv[1]); + exit(2); + } + argv++; argc--; + if (argv[1]) + { + offset = strtol(argv[1],NULL,0); + argv++; argc--; + } + if (argv[1]) + { + length = strtol(argv[1],NULL,0); + argv++; argc--; + } + + fseek(F,0, SEEK_END); + filelength = ftell(F); + + length *= 2; + + if ((length > (filelength - (offset*2))) || (length == 0)) length = filelength - (offset*2); + printf("Length=%04Xh(words) Offset=$%04Xh filelength=%04Xh(words) %04Xh(bytes)\n",length/2,offset,filelength/2,filelength); + length_to_dump = length; + printf("Starting from %d, dumping %d opcodes (word size)\n",offset,length/2); + Buffer = calloc((filelength+1),sizeof(char)); + if (Buffer==NULL) + { + printf("Out of Memory !!!"); + fclose(F); + exit(3); + } + String_Output = calloc(80,sizeof(char)); + if (String_Output==NULL) + { + printf("Out of Memory !!!"); + free(Buffer); + fclose(F); + exit(4); + } + + if (fseek(F,0,SEEK_SET) != 0) + { + printf("Error seeking to beginning of file\n"); + free(String_Output); + free(Buffer); + fclose(F); + exit(5); + } + + Counter = offset; + bytes_read = fread(Buffer,sizeof(char),filelength,F); + if (bytes_read >= length) + { + for (; length > 0; length -= (disasm_words*2)) + { + int ii; + disasm_words = Dasm32025(String_Output,Counter); + printf("$%04lX: ",Counter); + for (ii = 0; ii < disasm_words; ii++) + { + if (((Counter*2) + ii) > filelength) /* Past end of length to dump ? */ + { + sprintf(String_Output,"???? dw %02.2X%02.2Xh (Past end of disassembly !)",Buffer[((Counter-1)*2)],Buffer[((Counter-1)*2)+1]); + } + else + { + printf("%02.2x%02.2x ",Buffer[(Counter*2)],Buffer[(Counter*2) + 1]); + } + Counter++ ; + } + for (; ii < 4; ii++) + { + printf(" "); + } + printf("\t%s\n",String_Output); + } + } + else + { + printf("ERROR length to dump was %d ", length_to_dump/2); + printf(", but bytes read from file were %d\n", bytes_read/2); + free(String_Output); + free(Buffer); + fclose(F); + exit(7); + } + free(String_Output); + free(Buffer); + fclose(F); + return(0); +} diff --git a/src/devices/cpu/tms32025/tms32025.c b/src/devices/cpu/tms32025/tms32025.c new file mode 100644 index 00000000000..9acc4a31f8c --- /dev/null +++ b/src/devices/cpu/tms32025/tms32025.c @@ -0,0 +1,2282 @@ +// license:BSD-3-Clause +// copyright-holders:Tony La Porta, hap + /**************************************************************************\ + * Texas Instruments TMS320x25 DSP Emulator * + * * + * Copyright Tony La Porta * + * Written for the MAME project. * + * * + * * + * Three versions of the chip are available, and they are: * + * TMS320C25 Internal ROM one time programmed at TI * + * TMS320E25 Internal ROM programmable as a normal EPROM * + * TMS320P25 Internal ROM programmable once as a normal EPROM only * + * These devices can also be used as a MicroController with external ROM * + * * + * * + * Notes : The term 'DMA' within this document, is in reference * + * to Direct Memory Addressing, and NOT the usual term * + * of Direct Memory Access. * + * This is a word based microcontroller, with addressing * + * architecture based on the Harvard addressing scheme. * + * * + * * + * * + * **** Change Log **** * + * * + * TLP (2x-May-2001) * + * - Work began on this emulator * + * TLP (12-Jul-2001) * + * - First private release * + * TLP (xx-Dec-2001) Ver 0.11 * + * - Various undocumented fixes * + * TLP (13-Jul-2002) Ver 0.12 * + * - Corrected IRQ2 vector pointer * + * - Fixed the signedness in many equation based instructions * + * - Adjusted the level sensing for the Signal inputs * + * - Added the ability to view the CPU in the debugger when it's halted * + * TLP (16-Nov-2002) * + * - First public release after nearly 1.5 years! * + * - Adjusted more signedness instructions (ADDH, SUBC, SUBH, etc) * + * TLP (21-Dec-2002) * + * - Added memory banking for the CNFD, CNFP and CONF instructions * + * - Corrected IRQ masking checks * + * TLP (25-Dec-2002) Ver 1.10 * + * - Added internal timer * + * * + \**************************************************************************/ + +/***************************************************************************** + To fix, or currently lacking from this emulator are: + + Fix the levels for S_IN and S_OUT - use assert/release line + + # Support for the built in Timer/Counter Page 91 + When idling, Counter must still be activly counting down. When counter + reaches 0 it should issue a TINT (if it's not masked), then come out of + IDLE mode. + If TINT is masked, the Timer still needs to count down. + + # Support for the built in Serial Port + # Support for the Global memory register + # Support for the switch for RAM block 0 banking between RAM and ROM space + # Correct the multi-cycle instruction cycle counts + # Add support to set ROM & RAM as Internal/External in order to correctly + compute cycle timings + # Check (read) Hold signal level during execution loop ? + # Fix bugs + # Fix more bugs :-) + # Add/fix other things I forgot +*****************************************************************************/ + +/* + TMS32025 CONF Mode Decoding Table +|=======================================| +| Status bit | Blocks | +| CNF | B0 | B1 | B2 | +|------------+---------+---------+------| +| 0 0 | data | data | data | +| 1 1 | program | data | data | +|=======================================| + + + TMS32026 CONF Mode Decoding Table +|==================================================| +| Status bits | Blocks | +| CNF1 | CNF0 | B0 | B1 | B2 | B3 | +|------+------+---------+---------+------+---------| +| 0 | 0 | data | data | data | data | +| 0 | 1 | program | data | data | data | +| 1 | 0 | program | program | data | data | +| 1 | 1 | program | program | data | program | +|==================================================| + + + +Table 3-2. TMS32025/26 Memory Blocks +|=========================================================| +| Configured As Data Memory | +|-------+-------TMS320C25--------+-------TMS320C26--------| +| | | Hexadecimal | | Hexadecimal | +| Block | Pages | Address | Pages | Address | +|-------+---------+--------------+---------+--------------| +| B2 | 0 | 0060h-007Fh | 0 | 0060h-007Fh | +| B0 | 4-5 | 0200h-02FFh | 4-7 | 0200h-03FFh | +| B1 | 6-7 | 0300h-03FFh | 8-11 | 0400h-05FFh | +| B3 | B3 does not exist | 12-15 | 0600h-07FFh | +|=========================================================| +| Configured As Program Memory | +|-------+-------TMS320C25--------+-------TMS320C26--------| +| | | Hexadecimal | | Hexadecimal | +| Block | Pages | Address | Pages | Address | +|-------+---------+--------------+---------+--------------| +| B2 | B2 is not configurable | B2 is not configurable | +| B0 | 510-511 | FF00h-FFFFh | 500-503 | FA00h-FBFFh | +| B1 | B1 is not configurable | 504-507 | FC00h-FDFFh | +| B3 | B3 does not exist | 508-511 | FE00h-FFFFh | +|=========================================================| +*/ + + +#include "emu.h" +#include "debugger.h" +#include "tms32025.h" + + +#define CLK 4 /* 1 cycle equals 4 clock ticks */ /* PE/DI */ + + + +#define SET_PC(x) do { m_PC = (x); } while (0) + +#define P_IN(A) (m_io->read_word((A)<<1)) +#define P_OUT(A,V) (m_io->write_word(((A)<<1),(V))) +#define S_IN(A) (m_io->read_word((A)<<1)) +#define S_OUT(A,V) (m_io->write_word(((A)<<1),(V))) + +#define M_RDOP(A) ((m_pgmmap[(A) >> 7]) ? (m_pgmmap[(A) >> 7][(A) & 0x7f]) : m_direct->read_word((A)<<1)) +#define M_RDOP_ARG(A) ((m_pgmmap[(A) >> 7]) ? (m_pgmmap[(A) >> 7][(A) & 0x7f]) : m_direct->read_word((A)<<1)) + + +/************************** Memory mapped registers ****************/ +#define DRR m_intRAM[0] +#define DXR m_intRAM[1] +#define TIM m_intRAM[2] +#define PRD m_intRAM[3] +#define IMR m_intRAM[4] +#define GREG m_intRAM[5] + + +/**************************************************************************** + ******* The following is the Status (Flag) register 0 definition. ******** +| 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | +| <----ARP---> | OV | OVM | 1 | INTM | <--------------DP---------------> | */ + +#define ARP_REG 0xe000 /* ARP (Auxiliary Register Pointer) */ +#define OV_FLAG 0x1000 /* OV (Overflow flag) 1 indicates an overflow */ +#define OVM_FLAG 0x0800 /* OVM (Overflow Mode bit) 1 forces ACC overflow to greatest positive or negative saturation value */ +#define INTM_FLAG 0x0200 /* INTM (Interrupt Mask flag) 0 enables maskable interrupts */ +#define DP_REG 0x01ff /* DP (Data bank memory Pointer) */ + + +/*********************************************************************************** + *** The following is the Status (Flag) register 1 definition for TMS32025. ******** +| 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | +| <----ARB---> | CNF0 | TC | SXM | C | 1 | 1 | HM | FSM | XF | FO | TXM | <-PM-> | */ + +/*** The following is the Status (Flag) register 1 definition for TMS32026. *********** +| 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | +| <----ARB---> | CNF0 | TC | SXM | C | 1 | CNF1 | HM | FSM | XF | FO | TXM | <-PM-> | */ + +#define ARB_REG 0xe000 /* ARB (Auxiliary Register pointer Backup) */ +#define CNF0_REG 0x1000 /* CNF0 (Onchip RAM CoNFiguration) 0 means B0=data memory, 1means B0=program memory */ +#define CNF1_REG 0x0080 /* CNF1 (Onchip RAM CoNFiguration) 0 means B0=data memory, 1means B0=program memory */ +#define TC_FLAG 0x0800 /* TC (Test Control flag) */ +#define SXM_FLAG 0x0400 /* SXM (Sign eXtension Mode) */ +#define C_FLAG 0x0200 /* C (Carry flag) */ +#define HM_FLAG 0x0040 /* HM (Processor Hold Mode) */ +#define FSM_FLAG 0x0020 /* FSM (Frame Synchronization Mode - for serial port) */ +#define XF_FLAG 0x0010 /* XF (XF output pin status) */ +#define FO_FLAG 0x0008 /* FO (Serial port Format In/Out mode) */ +#define TXM_FLAG 0x0004 /* TXM (Transmit Mode - for serial port) */ +#define PM_REG 0x0003 /* PM (Product shift Mode) */ + + +#define OV ( m_STR0 & OV_FLAG) /* OV (Overflow flag) */ +#define OVM ( m_STR0 & OVM_FLAG) /* OVM (Overflow Mode bit) 1 indicates an overflow */ +#define INTM ( m_STR0 & INTM_FLAG) /* INTM (Interrupt enable flag) 0 enables maskable interrupts */ +#define ARP ((m_STR0 & ARP_REG) >> 13) /* ARP (Auxiliary Register Pointer) */ +#define DP ((m_STR0 & DP_REG) << 7) /* DP (Data memory Pointer bit) */ +#define ARB ( m_STR1 & ARB_REG) /* ARB (Backup Auxiliary Register pointer) */ +#define CNF0 ( m_STR1 & CNF0_REG) /* CNF0 (Onchip Ram Config register) */ +#define TC ( m_STR1 & TC_FLAG) /* TC (Test Control Flag) */ +#define SXM ( m_STR1 & SXM_FLAG) /* SXM (Sign Extension Mode) */ +#define CARRY ( m_STR1 & C_FLAG) /* C (Carry Flag for accumulator) */ +#define HM ( m_STR1 & HM_FLAG) /* HM (Processor Hold Mode) */ +#define FSM ( m_STR1 & FSM_FLAG) /* FSM (Frame Synchronization Mode - for serial port) */ +#define XF ( m_STR1 & FSM_FLAG) /* XF (XF output pin status) */ +#define FO ( m_STR1 & FO_FLAG) /* FO (Serial port Format In/Out mode) */ +#define TXM ( m_STR1 & TXM_FLAG) /* TXM (Transmit Mode - for serial port) */ +#define PM ( m_STR1 & PM_REG) /* PM (P register shift Mode. See SHIFT_Preg_TO_ALU below )*/ + +#define DMA (DP | (m_opcode.b.l & 0x7f)) /* address used in direct memory access operations */ +#define DMApg0 (m_opcode.b.l & 0x7f) /* address used in direct memory access operations for sst instruction */ +#define IND m_AR[ARP] /* address used in indirect memory access operations */ + + +const device_type TMS32025 = &device_creator; +const device_type TMS32026 = &device_creator; + + +tms32025_device::tms32025_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : cpu_device(mconfig, TMS32025, "TMS32025", tag, owner, clock, "tms32025", __FILE__) + , m_program_config("program", ENDIANNESS_BIG, 16, 16, -1) + , m_data_config("data", ENDIANNESS_BIG, 16, 16, -1) + , m_io_config("io", ENDIANNESS_BIG, 16, 17, -1) +{ +} + + +tms32025_device::tms32025_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : cpu_device(mconfig, type, name, tag, owner, clock, shortname, source) + , m_program_config("program", ENDIANNESS_BIG, 16, 16, -1) + , m_data_config("data", ENDIANNESS_BIG, 16, 16, -1) + , m_io_config("io", ENDIANNESS_BIG, 16, 16, -1) +{ +} + + +tms32026_device::tms32026_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : tms32025_device(mconfig, TMS32026, "TMS32026", tag, owner, clock, "tms32026", __FILE__) +{ +} + + +offs_t tms32025_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( tms32025 ); + return CPU_DISASSEMBLE_NAME(tms32025)(this, buffer, pc, oprom, opram, options); +} + + +void tms32025_device::CLR0(UINT16 flag) { m_STR0 &= ~flag; m_STR0 |= 0x0400; } +void tms32025_device::SET0(UINT16 flag) { m_STR0 |= flag; m_STR0 |= 0x0400; } +void tms32025_device::CLR1(UINT16 flag) { m_STR1 &= ~flag; m_STR1 |= 0x0180; } +void tms32025_device::SET1(UINT16 flag) { m_STR1 |= flag; m_STR1 |= 0x0180; } + +void tms32025_device::MODIFY_DP(int data) +{ + m_STR0 &= ~DP_REG; + m_STR0 |= (data & DP_REG); + m_STR0 |= 0x0400; +} +void tms32025_device::MODIFY_PM(int data) +{ + m_STR1 &= ~PM_REG; + m_STR1 |= (data & PM_REG); + m_STR1 |= 0x0180; +} +void tms32025_device::MODIFY_ARP(int data) +{ + m_STR1 &= ~ARB_REG; + m_STR1 |= (m_STR0 & ARP_REG); + m_STR1 |= 0x0180; + m_STR0 &= ~ARP_REG; + m_STR0 |= ((data << 13) & ARP_REG); + m_STR0 |= 0x0400; +} + +UINT16 tms32025_device::M_RDROM(offs_t addr) +{ + UINT16 *ram; + addr &= 0xffff; + ram = m_pgmmap[addr >> 7]; + if (ram) return ram[addr & 0x7f]; + return m_program->read_word(addr << 1); +} + +void tms32025_device::M_WRTROM(offs_t addr, UINT16 data) +{ + UINT16 *ram; + addr &= 0xffff; + ram = m_pgmmap[addr >> 7]; + if (ram) { ram[addr & 0x7f] = data; } + else m_program->write_word(addr << 1, data); +} + +UINT16 tms32025_device::M_RDRAM(offs_t addr) +{ + UINT16 *ram; + addr &= 0xffff; + ram = m_datamap[addr >> 7]; + if (ram) return ram[addr & 0x7f]; + return m_data->read_word(addr << 1); +} + +void tms32025_device::M_WRTRAM(offs_t addr, UINT16 data) +{ + UINT16 *ram; + addr &= 0xffff; + ram = m_datamap[addr >> 7]; + if (ram) { + ram[addr & 0x7f] = data; + if(addr == 1 && ram == m_intRAM && TXM) { + if(FSM) + m_waiting_for_serial_frame = 1; + else + m_IFR |= 0x20; + } + } + else m_data->write_word(addr << 1, data); +} + + +UINT16 tms32025_device::reverse_carry_add(UINT16 arg0, UINT16 arg1 ) +{ + UINT16 result = 0; + int carry = 0; + int count; + for( count=0; count<16; count++ ) + { + int sum = (arg0>>15)+(arg1>>15)+carry; + result = (result<<1)|(sum&1); + carry = sum>>1; + arg0<<=1; + arg1<<=1; + } + return result; +} + +void tms32025_device::MODIFY_AR_ARP() +{ /* modify address register referenced by ARP */ + switch (m_opcode.b.l & 0x70) /* Cases ordered by predicted useage */ + { + case 0x00: /* 000 nop */ + break; + + case 0x10: /* 001 *- */ + m_AR[ARP] -- ; + break; + + case 0x20: /* 010 *+ */ + m_AR[ARP] ++ ; + break; + + case 0x30: /* 011 reserved */ + break; + + case 0x40: /* 100 *BR0- */ + m_AR[ARP] = reverse_carry_add(m_AR[ARP],-m_AR[0]); + break; + + case 0x50: /* 101 *0- */ + m_AR[ARP] -= m_AR[0]; + break; + + case 0x60: /* 110 *0+ */ + m_AR[ARP] += m_AR[0]; + break; + + case 0x70: /* 111 *BR0+ */ + m_AR[ARP] += reverse_carry_add(m_AR[ARP],m_AR[0]); + break; + } + + if( !m_mHackIgnoreARP ) + { + if (m_opcode.b.l & 8) + { /* bit 3 determines if new value is loaded into ARP */ + MODIFY_ARP((m_opcode.b.l & 7) ); + } + } +} + +void tms32025_device::CALCULATE_ADD_CARRY() +{ + if ( (UINT32)(m_oldacc.d) > (UINT32)(m_ACC.d) ) { + SET1(C_FLAG); + } + else { + CLR1(C_FLAG); + } +} + +void tms32025_device::CALCULATE_SUB_CARRY() +{ + if ( (UINT32)(m_oldacc.d) < (UINT32)(m_ACC.d) ) { + CLR1(C_FLAG); + } + else { + SET1(C_FLAG); + } +} + +void tms32025_device::CALCULATE_ADD_OVERFLOW(INT32 addval) +{ + if ((INT32)((m_ACC.d ^ addval) & (m_oldacc.d ^ m_ACC.d)) < 0) + { + SET0(OV_FLAG); + if (OVM) + { + m_ACC.d = ((INT32)m_oldacc.d < 0) ? 0x80000000 : 0x7fffffff; + } + } +} +void tms32025_device::CALCULATE_SUB_OVERFLOW(INT32 subval) +{ + if ((INT32)((m_oldacc.d ^ subval) & (m_oldacc.d ^ m_ACC.d)) < 0) + { + SET0(OV_FLAG); + if (OVM) + { + m_ACC.d = ((INT32)m_oldacc.d < 0) ? 0x80000000 : 0x7fffffff; + } + } +} + +UINT16 tms32025_device::POP_STACK() +{ + UINT16 data = m_STACK[7]; + m_STACK[7] = m_STACK[6]; + m_STACK[6] = m_STACK[5]; + m_STACK[5] = m_STACK[4]; + m_STACK[4] = m_STACK[3]; + m_STACK[3] = m_STACK[2]; + m_STACK[2] = m_STACK[1]; + m_STACK[1] = m_STACK[0]; + return data; +} +void tms32025_device::PUSH_STACK(UINT16 data) +{ + m_STACK[0] = m_STACK[1]; + m_STACK[1] = m_STACK[2]; + m_STACK[2] = m_STACK[3]; + m_STACK[3] = m_STACK[4]; + m_STACK[4] = m_STACK[5]; + m_STACK[5] = m_STACK[6]; + m_STACK[6] = m_STACK[7]; + m_STACK[7] = data; +} + +void tms32025_device::SHIFT_Preg_TO_ALU() +{ + switch(PM) /* PM (in STR1) is the shift mode for Preg */ + { + case 0: m_ALU.d = m_Preg.d; break; + case 1: m_ALU.d = (m_Preg.d << 1); break; + case 2: m_ALU.d = (m_Preg.d << 4); break; + case 3: m_ALU.d = (m_Preg.d >> 6); if (m_Preg.d & 0x80000000) m_ALU.d |= 0xfc000000; break; + default: break; + } +} + +void tms32025_device::GETDATA(int shift,int signext) +{ + if (m_opcode.b.l & 0x80) + { /* indirect memory access */ + m_memaccess = IND; + } + else + { /* direct memory address */ + m_memaccess = DMA; + } + + if (m_memaccess >= 0x800) + { + m_external_mem_access = 1; /* Pause if hold pin is active */ + } + else + { + m_external_mem_access = 0; + } + + m_ALU.d = (UINT16)M_RDRAM(m_memaccess); + if (signext) m_ALU.d = (INT16)m_ALU.d; + m_ALU.d <<= shift; + + /* next ARP */ + if (m_opcode.b.l & 0x80) MODIFY_AR_ARP(); +} + +void tms32025_device::PUTDATA(UINT16 data) +{ + if (m_opcode.b.l & 0x80) { + if (m_memaccess >= 0x800) m_external_mem_access = 1; /* Pause if hold pin is active */ + else m_external_mem_access = 0; + + M_WRTRAM(IND, data); + MODIFY_AR_ARP(); + } + else { + if (m_memaccess >= 0x800) m_external_mem_access = 1; /* Pause if hold pin is active */ + else m_external_mem_access = 0; + + M_WRTRAM(DMA, data); + } +} +void tms32025_device::PUTDATA_SST(UINT16 data) +{ + if (m_opcode.b.l & 0x80) m_memaccess = IND; + else m_memaccess = DMApg0; + + if (m_memaccess >= 0x800) m_external_mem_access = 1; /* Pause if hold pin is active */ + else m_external_mem_access = 0; + + if (m_opcode.b.l & 0x80) { + m_opcode.b.l &= 0xf7; /* Stop ARP changes */ + MODIFY_AR_ARP(); + } + M_WRTRAM(m_memaccess, data); +} + + + +/**************************************************************************** + * Emulate the Instructions + ****************************************************************************/ + +/* The following functions are here to fill the void for the */ +/* opcode call functions. These functions are never actually called. */ +void tms32025_device::opcodes_CE() { fatalerror("Should never get here!\n"); } +void tms32025_device::opcodes_Dx() { fatalerror("Should never get here!\n"); } + +void tms32025_device::illegal() +{ + logerror("TMS32025: PC = %04x, Illegal opcode = %04x\n", (m_PC-1), m_opcode.w.l); +} + +void tms32025_device::abst() +{ + if ( (INT32)(m_ACC.d) < 0 ) { + m_ACC.d = -m_ACC.d; + if (m_ACC.d == 0x80000000) { + SET0(OV_FLAG); + if (OVM) m_ACC.d-- ; + } + } + CLR1(C_FLAG); +} +void tms32025_device::add() +{ + m_oldacc.d = m_ACC.d; + GETDATA((m_opcode.b.h & 0xf), SXM); + m_ACC.d += m_ALU.d; + CALCULATE_ADD_OVERFLOW(m_ALU.d); + CALCULATE_ADD_CARRY(); +} +void tms32025_device::addc() +{ + m_oldacc.d = m_ACC.d; + GETDATA(0, 0); + if (CARRY) m_ACC.d++; + m_ACC.d += m_ALU.d; + CALCULATE_ADD_OVERFLOW(m_ALU.d); + if (m_ACC.d == m_oldacc.d) {} /* edge case, carry remains same */ + else CALCULATE_ADD_CARRY(); +} +void tms32025_device::addh() +{ + m_oldacc.d = m_ACC.d; + GETDATA(0, 0); + m_ACC.w.h += m_ALU.w.l; + if ( (UINT16)(m_oldacc.w.h) > (UINT16)(m_ACC.w.h) ) { + SET1(C_FLAG); /* Carry flag is not cleared, if no carry occurred */ + } + if ((INT16)((m_ACC.w.h ^ m_ALU.w.l) & (m_oldacc.w.h ^ m_ACC.w.h)) < 0) { + SET0(OV_FLAG); + if (OVM) m_ACC.w.h = ((INT16)m_oldacc.w.h < 0) ? 0x8000 : 0x7fff; + } +} +void tms32025_device::addk() +{ + m_oldacc.d = m_ACC.d; + m_ALU.d = (UINT8)m_opcode.b.l; + m_ACC.d += m_ALU.d; + CALCULATE_ADD_OVERFLOW(m_ALU.d); + CALCULATE_ADD_CARRY(); +} +void tms32025_device::adds() +{ + m_oldacc.d = m_ACC.d; + GETDATA(0, 0); + m_ACC.d += m_ALU.d; + CALCULATE_ADD_OVERFLOW(m_ALU.d); + CALCULATE_ADD_CARRY(); +} +void tms32025_device::addt() +{ + m_oldacc.d = m_ACC.d; + GETDATA((m_Treg & 0xf), SXM); + m_ACC.d += m_ALU.d; + CALCULATE_ADD_OVERFLOW(m_ALU.d); + CALCULATE_ADD_CARRY(); +} +void tms32025_device::adlk() +{ + m_oldacc.d = m_ACC.d; + if (SXM) m_ALU.d = (INT16)M_RDOP_ARG(m_PC); + else m_ALU.d = (UINT16)M_RDOP_ARG(m_PC); + m_PC++; + m_ALU.d <<= (m_opcode.b.h & 0xf); + m_ACC.d += m_ALU.d; + CALCULATE_ADD_OVERFLOW(m_ALU.d); + CALCULATE_ADD_CARRY(); +} +void tms32025_device::adrk() +{ + m_AR[ARP] += m_opcode.b.l; +} +void tms32025_device::and_() +{ + GETDATA(0, 0); + m_ACC.d &= m_ALU.d; +} +void tms32025_device::andk() +{ + m_oldacc.d = m_ACC.d; + m_ALU.d = (UINT16)M_RDOP_ARG(m_PC); + m_PC++; + m_ALU.d <<= (m_opcode.b.h & 0xf); + m_ACC.d &= m_ALU.d; +} +void tms32025_device::apac() +{ + m_oldacc.d = m_ACC.d; + SHIFT_Preg_TO_ALU(); + m_ACC.d += m_ALU.d; + CALCULATE_ADD_OVERFLOW(m_ALU.d); + CALCULATE_ADD_CARRY(); +} +void tms32025_device::br() +{ + SET_PC(M_RDOP_ARG(m_PC)); + MODIFY_AR_ARP(); +} +void tms32025_device::bacc() +{ + SET_PC(m_ACC.w.l); +} +void tms32025_device::banz() +{ + if (m_AR[ARP]) SET_PC(M_RDOP_ARG(m_PC)); + else m_PC++ ; + MODIFY_AR_ARP(); +} +void tms32025_device::bbnz() +{ + if (TC) SET_PC(M_RDOP_ARG(m_PC)); + else m_PC++ ; + MODIFY_AR_ARP(); +} +void tms32025_device::bbz() +{ + if (TC == 0) SET_PC(M_RDOP_ARG(m_PC)); + else m_PC++ ; + MODIFY_AR_ARP(); +} +void tms32025_device::bc() +{ + if (CARRY) SET_PC(M_RDOP_ARG(m_PC)); + else m_PC++ ; + MODIFY_AR_ARP(); +} +void tms32025_device::bgez() +{ + if ( (INT32)(m_ACC.d) >= 0 ) SET_PC(M_RDOP_ARG(m_PC)); + else m_PC++ ; + MODIFY_AR_ARP(); +} +void tms32025_device::bgz() +{ + if ( (INT32)(m_ACC.d) > 0 ) SET_PC(M_RDOP_ARG(m_PC)); + else m_PC++ ; + MODIFY_AR_ARP(); +} +void tms32025_device::bioz() +{ + if (S_IN(TMS32025_BIO) != CLEAR_LINE) SET_PC(M_RDOP_ARG(m_PC)); + else m_PC++ ; + MODIFY_AR_ARP(); +} +void tms32025_device::bit() +{ + GETDATA(0, 0); + if (m_ALU.d & (0x8000 >> (m_opcode.b.h & 0xf))) SET1(TC_FLAG); + else CLR1(TC_FLAG); +} +void tms32025_device::bitt() +{ + GETDATA(0, 0); + if (m_ALU.d & (0x8000 >> (m_Treg & 0xf))) SET1(TC_FLAG); + else CLR1(TC_FLAG); +} +void tms32025_device::blez() +{ + if ( (INT32)(m_ACC.d) <= 0 ) SET_PC(M_RDOP_ARG(m_PC)); + else m_PC++ ; + MODIFY_AR_ARP(); +} +void tms32025_device::blkd() +{ /** Fix cycle timing **/ + if (m_init_load_addr) { + m_PFC = M_RDOP_ARG(m_PC); + m_PC++; + } + m_ALU.d = M_RDRAM(m_PFC); + PUTDATA(m_ALU.d); + m_PFC++; + m_tms32025_dec_cycles += (1*CLK); +} +void tms32025_device::blkp() +{ /** Fix cycle timing **/ + if (m_init_load_addr) { + m_PFC = M_RDOP_ARG(m_PC); + m_PC++; + } + m_ALU.d = M_RDROM(m_PFC); + PUTDATA(m_ALU.d); + m_PFC++; + m_tms32025_dec_cycles += (2*CLK); +} +void tms32025_device::blz() +{ + if ( (INT32)(m_ACC.d) < 0 ) SET_PC(M_RDOP_ARG(m_PC)); + else m_PC++ ; + MODIFY_AR_ARP(); +} +void tms32025_device::bnc() +{ + if (CARRY == 0) SET_PC(M_RDOP_ARG(m_PC)); + else m_PC++ ; + MODIFY_AR_ARP(); +} +void tms32025_device::bnv() +{ + if (OV == 0) SET_PC(M_RDOP_ARG(m_PC)); + else { + m_PC++ ; + CLR0(OV_FLAG); + } + MODIFY_AR_ARP(); +} +void tms32025_device::bnz() +{ + if (m_ACC.d != 0) SET_PC(M_RDOP_ARG(m_PC)); + else m_PC++ ; + MODIFY_AR_ARP(); +} +void tms32025_device::bv() +{ + if (OV) { + SET_PC(M_RDOP_ARG(m_PC)); + CLR0(OV_FLAG); + } + else m_PC++ ; + MODIFY_AR_ARP(); +} +void tms32025_device::bz() +{ + if (m_ACC.d == 0) SET_PC(M_RDOP_ARG(m_PC)); + else m_PC++ ; + MODIFY_AR_ARP(); +} +void tms32025_device::cala() +{ + PUSH_STACK(m_PC); + SET_PC(m_ACC.w.l); +} +void tms32025_device::call() +{ + m_PC++ ; + PUSH_STACK(m_PC); + SET_PC(M_RDOP_ARG((m_PC - 1))); + MODIFY_AR_ARP(); +} +void tms32025_device::cmpl() +{ + m_ACC.d = (~m_ACC.d); +} +void tms32025_device::cmpr() +{ + switch (m_opcode.b.l & 3) + { + case 00: if ( (UINT16)(m_AR[ARP]) == (UINT16)(m_AR[0]) ) SET1(TC_FLAG); + else CLR1(TC_FLAG); + break; + case 01: if ( (UINT16)(m_AR[ARP]) < (UINT16)(m_AR[0]) ) SET1(TC_FLAG); + else CLR1(TC_FLAG); + break; + case 02: if ( (UINT16)(m_AR[ARP]) > (UINT16)(m_AR[0]) ) SET1(TC_FLAG); + else CLR1(TC_FLAG); + break; + case 03: if ( (UINT16)(m_AR[ARP]) != (UINT16)(m_AR[0]) ) SET1(TC_FLAG); + else CLR1(TC_FLAG); + break; + } +} +void tms32025_device::cnfd() /** next two fetches need to use previous CNF value ! **/ +{ + CLR1(CNF0_REG); + m_datamap[4] = &m_intRAM[0x200]; /* B0 */ + m_datamap[5] = &m_intRAM[0x280]; /* B0 */ + m_pgmmap[510] = NULL; + m_pgmmap[511] = NULL; +} +void tms32025_device::cnfp() /** next two fetches need to use previous CNF value ! **/ +{ + SET1(CNF0_REG); + m_datamap[4] = NULL; /* B0 */ + m_datamap[5] = NULL; /* B0 */ + m_pgmmap[510] = &m_intRAM[0x200]; + m_pgmmap[511] = &m_intRAM[0x280]; +} +void tms32025_device::conf() /** Need to reconfigure the memory blocks */ +{ + switch (m_opcode.b.l & 3) + { + case 00: CLR1(CNF1_REG); CLR1(CNF0_REG); + m_datamap[4] = &m_intRAM[0x200]; /* B0 */ + m_datamap[5] = &m_intRAM[0x280]; /* B0 */ + m_datamap[6] = &m_intRAM[0x300]; /* B0 */ + m_datamap[7] = &m_intRAM[0x380]; /* B0 */ + m_datamap[8] = &m_intRAM[0x400]; /* B1 */ + m_datamap[9] = &m_intRAM[0x480]; /* B1 */ + m_datamap[10] = &m_intRAM[0x500]; /* B1 */ + m_datamap[11] = &m_intRAM[0x580]; /* B1 */ + m_datamap[12] = &m_intRAM[0x600]; /* B3 */ + m_datamap[13] = &m_intRAM[0x680]; /* B3 */ + m_datamap[14] = &m_intRAM[0x700]; /* B3 */ + m_datamap[15] = &m_intRAM[0x780]; /* B3 */ + m_pgmmap[500] = NULL; + m_pgmmap[501] = NULL; + m_pgmmap[502] = NULL; + m_pgmmap[503] = NULL; + m_pgmmap[504] = NULL; + m_pgmmap[505] = NULL; + m_pgmmap[506] = NULL; + m_pgmmap[507] = NULL; + m_pgmmap[508] = NULL; + m_pgmmap[509] = NULL; + m_pgmmap[510] = NULL; + m_pgmmap[511] = NULL; + break; + + case 01: CLR1(CNF1_REG); SET1(CNF0_REG); + m_datamap[4] = NULL; + m_datamap[5] = NULL; + m_datamap[6] = NULL; + m_datamap[7] = NULL; + m_datamap[8] = &m_intRAM[0x400]; /* B1 */ + m_datamap[9] = &m_intRAM[0x480]; /* B1 */ + m_datamap[10] = &m_intRAM[0x500]; /* B1 */ + m_datamap[11] = &m_intRAM[0x580]; /* B1 */ + m_datamap[12] = &m_intRAM[0x600]; /* B3 */ + m_datamap[13] = &m_intRAM[0x680]; /* B3 */ + m_datamap[14] = &m_intRAM[0x700]; /* B3 */ + m_datamap[15] = &m_intRAM[0x780]; /* B3 */ + m_pgmmap[500] = &m_intRAM[0x200]; /* B0 */ + m_pgmmap[501] = &m_intRAM[0x280]; /* B0 */ + m_pgmmap[502] = &m_intRAM[0x300]; /* B0 */ + m_pgmmap[503] = &m_intRAM[0x380]; /* B0 */ + m_pgmmap[504] = NULL; + m_pgmmap[505] = NULL; + m_pgmmap[506] = NULL; + m_pgmmap[507] = NULL; + m_pgmmap[508] = NULL; + m_pgmmap[509] = NULL; + m_pgmmap[510] = NULL; + m_pgmmap[511] = NULL; + break; + + case 02: SET1(CNF1_REG); CLR1(CNF0_REG); + m_datamap[4] = NULL; + m_datamap[5] = NULL; + m_datamap[6] = NULL; + m_datamap[7] = NULL; + m_datamap[8] = NULL; + m_datamap[9] = NULL; + m_datamap[10] = NULL; + m_datamap[11] = NULL; + m_datamap[12] = &m_intRAM[0x600]; /* B3 */ + m_datamap[13] = &m_intRAM[0x680]; /* B3 */ + m_datamap[14] = &m_intRAM[0x700]; /* B3 */ + m_datamap[15] = &m_intRAM[0x780]; /* B3 */ + m_pgmmap[500] = &m_intRAM[0x200]; /* B0 */ + m_pgmmap[501] = &m_intRAM[0x280]; /* B0 */ + m_pgmmap[502] = &m_intRAM[0x300]; /* B0 */ + m_pgmmap[503] = &m_intRAM[0x380]; /* B0 */ + m_pgmmap[504] = &m_intRAM[0x400]; /* B1 */ + m_pgmmap[505] = &m_intRAM[0x480]; /* B1 */ + m_pgmmap[506] = &m_intRAM[0x500]; /* B1 */ + m_pgmmap[507] = &m_intRAM[0x580]; /* B1 */ + m_pgmmap[508] = NULL; + m_pgmmap[509] = NULL; + m_pgmmap[510] = NULL; + m_pgmmap[511] = NULL; + break; + + case 03: SET1(CNF1_REG); SET1(CNF0_REG); + m_datamap[4] = NULL; + m_datamap[5] = NULL; + m_datamap[6] = NULL; + m_datamap[7] = NULL; + m_datamap[8] = NULL; + m_datamap[9] = NULL; + m_datamap[10] = NULL; + m_datamap[11] = NULL; + m_datamap[12] = NULL; + m_datamap[13] = NULL; + m_datamap[14] = NULL; + m_datamap[15] = NULL; + m_pgmmap[500] = &m_intRAM[0x200]; /* B0 */ + m_pgmmap[501] = &m_intRAM[0x280]; /* B0 */ + m_pgmmap[502] = &m_intRAM[0x300]; /* B0 */ + m_pgmmap[503] = &m_intRAM[0x380]; /* B0 */ + m_pgmmap[504] = &m_intRAM[0x400]; /* B1 */ + m_pgmmap[505] = &m_intRAM[0x480]; /* B1 */ + m_pgmmap[506] = &m_intRAM[0x500]; /* B1 */ + m_pgmmap[507] = &m_intRAM[0x580]; /* B1 */ + m_pgmmap[508] = &m_intRAM[0x600]; /* B3 */ + m_pgmmap[509] = &m_intRAM[0x680]; /* B3 */ + m_pgmmap[510] = &m_intRAM[0x700]; /* B3 */ + m_pgmmap[511] = &m_intRAM[0x780]; /* B3 */ + break; + } +} +void tms32025_device::dint() +{ + SET0(INTM_FLAG); +} +void tms32025_device::dmov() /** Careful with how memory is configured !! */ +{ + GETDATA(0, 0); + M_WRTRAM((m_memaccess + 1), m_ALU.w.l); +} +void tms32025_device::eint() +{ + CLR0(INTM_FLAG); +} +void tms32025_device::fort() +{ + if (m_opcode.b.l & 1) SET1(FO_FLAG); + else CLR1(FO_FLAG); +} +void tms32025_device::idle() +{ + CLR0(INTM_FLAG); + m_idle = 1; +} +void tms32025_device::in() +{ + m_ALU.w.l = P_IN( (m_opcode.b.h & 0xf) ); + PUTDATA(m_ALU.w.l); +} +void tms32025_device::lac() +{ + GETDATA((m_opcode.b.h & 0xf), SXM); + m_ACC.d = m_ALU.d; +} +void tms32025_device::lack() /* ZAC is a subset of this instruction */ +{ + m_ACC.d = (UINT8)m_opcode.b.l; +} +void tms32025_device::lact() +{ + GETDATA((m_Treg & 0xf), SXM); + m_ACC.d = m_ALU.d; +} +void tms32025_device::lalk() +{ + if (SXM) m_ALU.d = (INT16)M_RDOP_ARG(m_PC); + else m_ALU.d = (UINT16)M_RDOP_ARG(m_PC); + m_PC++; + m_ALU.d <<= (m_opcode.b.h & 0xf); + m_ACC.d = m_ALU.d; +} +void tms32025_device::lar_ar0() { GETDATA(0, 0); m_AR[0] = m_ALU.w.l; } +void tms32025_device::lar_ar1() { GETDATA(0, 0); m_AR[1] = m_ALU.w.l; } +void tms32025_device::lar_ar2() { GETDATA(0, 0); m_AR[2] = m_ALU.w.l; } +void tms32025_device::lar_ar3() { GETDATA(0, 0); m_AR[3] = m_ALU.w.l; } +void tms32025_device::lar_ar4() { GETDATA(0, 0); m_AR[4] = m_ALU.w.l; } +void tms32025_device::lar_ar5() { GETDATA(0, 0); m_AR[5] = m_ALU.w.l; } +void tms32025_device::lar_ar6() { GETDATA(0, 0); m_AR[6] = m_ALU.w.l; } +void tms32025_device::lar_ar7() { GETDATA(0, 0); m_AR[7] = m_ALU.w.l; } +void tms32025_device::lark_ar0() { m_AR[0] = m_opcode.b.l; } +void tms32025_device::lark_ar1() { m_AR[1] = m_opcode.b.l; } +void tms32025_device::lark_ar2() { m_AR[2] = m_opcode.b.l; } +void tms32025_device::lark_ar3() { m_AR[3] = m_opcode.b.l; } +void tms32025_device::lark_ar4() { m_AR[4] = m_opcode.b.l; } +void tms32025_device::lark_ar5() { m_AR[5] = m_opcode.b.l; } +void tms32025_device::lark_ar6() { m_AR[6] = m_opcode.b.l; } +void tms32025_device::lark_ar7() { m_AR[7] = m_opcode.b.l; } +void tms32025_device::ldp() +{ + GETDATA(0, 0); + MODIFY_DP(m_ALU.d & 0x1ff); +} +void tms32025_device::ldpk() +{ + MODIFY_DP(m_opcode.w.l & 0x1ff); +} +void tms32025_device::lph() +{ + GETDATA(0, 0); + m_Preg.w.h = m_ALU.w.l; +} +void tms32025_device::lrlk() +{ + m_ALU.d = (UINT16)M_RDOP_ARG(m_PC); + m_PC++; + m_AR[m_opcode.b.h & 7] = m_ALU.w.l; +} +void tms32025_device::lst() +{ + m_mHackIgnoreARP = 1; + GETDATA(0, 0); + m_mHackIgnoreARP = 0; + + m_ALU.w.l &= (~INTM_FLAG); + m_STR0 &= INTM_FLAG; + m_STR0 |= m_ALU.w.l; /* Must not affect INTM */ + m_STR0 |= 0x0400; +} +void tms32025_device::lst1() +{ + m_mHackIgnoreARP = 1; + GETDATA(0, 0); + m_mHackIgnoreARP = 0; + + m_STR1 = m_ALU.w.l; + m_STR1 |= 0x0180; + m_STR0 &= (~ARP_REG); /* ARB also gets copied to ARP */ + m_STR0 |= (m_STR1 & ARB_REG); +} +void tms32025_device::lt() +{ + GETDATA(0, 0); + m_Treg = m_ALU.w.l; +} +void tms32025_device::lta() +{ + m_oldacc.d = m_ACC.d; + GETDATA(0, 0); + m_Treg = m_ALU.w.l; + SHIFT_Preg_TO_ALU(); + m_ACC.d += m_ALU.d; + CALCULATE_ADD_OVERFLOW(m_ALU.d); + CALCULATE_ADD_CARRY(); +} +void tms32025_device::ltd() /** Careful with how memory is configured !! */ +{ + m_oldacc.d = m_ACC.d; + GETDATA(0, 0); + m_Treg = m_ALU.w.l; + M_WRTRAM((m_memaccess+1), m_ALU.w.l); + SHIFT_Preg_TO_ALU(); + m_ACC.d += m_ALU.d; + CALCULATE_ADD_OVERFLOW(m_ALU.d); + CALCULATE_ADD_CARRY(); +} +void tms32025_device::ltp() +{ + m_oldacc.d = m_ACC.d; + GETDATA(0, 0); + m_Treg = m_ALU.w.l; + SHIFT_Preg_TO_ALU(); + m_ACC.d = m_ALU.d; +} +void tms32025_device::lts() +{ + m_oldacc.d = m_ACC.d; + GETDATA(0, 0); + m_Treg = m_ALU.w.l; + SHIFT_Preg_TO_ALU(); + m_ACC.d -= m_ALU.d; + CALCULATE_SUB_OVERFLOW(m_ALU.d); + CALCULATE_SUB_CARRY(); +} +void tms32025_device::mac() /** RAM blocks B0,B1,B2 may be important ! */ +{ /** Fix cycle timing **/ + m_oldacc.d = m_ACC.d; + if (m_init_load_addr) { + m_PFC = M_RDOP_ARG(m_PC); + m_PC++; + } + SHIFT_Preg_TO_ALU(); + m_ACC.d += m_ALU.d; + CALCULATE_ADD_OVERFLOW(m_ALU.d); + CALCULATE_ADD_CARRY(); + GETDATA(0, 0); + m_Treg = m_ALU.w.l; + m_Preg.d = ( (INT16)m_ALU.w.l * (INT16)M_RDROM(m_PFC) ); + m_PFC++; + m_tms32025_dec_cycles += (2*CLK); +} +void tms32025_device::macd() /** RAM blocks B0,B1,B2 may be important ! */ +{ /** Fix cycle timing **/ + m_oldacc.d = m_ACC.d; + if (m_init_load_addr) { + m_PFC = M_RDOP_ARG(m_PC); + m_PC++; + } + SHIFT_Preg_TO_ALU(); + m_ACC.d += m_ALU.d; + CALCULATE_ADD_OVERFLOW(m_ALU.d); + CALCULATE_ADD_CARRY(); + GETDATA(0, 0); + if ( (m_opcode.b.l & 0x80) || m_init_load_addr ) { /* No writing during repetition, or DMA mode */ + M_WRTRAM((m_memaccess+1), m_ALU.w.l); + } + m_Treg = m_ALU.w.l; + m_Preg.d = ( (INT16)m_ALU.w.l * (INT16)M_RDROM(m_PFC) ); + m_PFC++; + m_tms32025_dec_cycles += (2*CLK); +} +void tms32025_device::mar() /* LARP and NOP are a subset of this instruction */ +{ + if (m_opcode.b.l & 0x80) MODIFY_AR_ARP(); +} +void tms32025_device::mpy() +{ + GETDATA(0, 0); + m_Preg.d = (INT16)(m_ALU.w.l) * (INT16)(m_Treg); +} +void tms32025_device::mpya() +{ + m_oldacc.d = m_ACC.d; + SHIFT_Preg_TO_ALU(); + m_ACC.d += m_ALU.d; + CALCULATE_ADD_OVERFLOW(m_ALU.d); + CALCULATE_ADD_CARRY(); + GETDATA(0, 0); + m_Preg.d = (INT16)(m_ALU.w.l) * (INT16)(m_Treg); +} +void tms32025_device::mpyk() +{ + m_Preg.d = (INT16)m_Treg * ((INT16)(m_opcode.w.l << 3) >> 3); + +} +void tms32025_device::mpys() +{ + m_oldacc.d = m_ACC.d; + SHIFT_Preg_TO_ALU(); + m_ACC.d -= m_ALU.d; + CALCULATE_SUB_OVERFLOW(m_ALU.d); + CALCULATE_SUB_CARRY(); + GETDATA(0, 0); + m_Preg.d = (INT16)(m_ALU.w.l) * (INT16)(m_Treg); +} +void tms32025_device::mpyu() +{ + GETDATA(0, 0); + m_Preg.d = (UINT16)(m_ALU.w.l) * (UINT16)(m_Treg); +} +void tms32025_device::neg() +{ + if (m_ACC.d == 0x80000000) { + SET0(OV_FLAG); + if (OVM) m_ACC.d = 0x7fffffff; + } + else m_ACC.d = -m_ACC.d; + if (m_ACC.d) CLR0(C_FLAG); + else SET0(C_FLAG); +} +/* +void tms32025_device::nop() { } // NOP is a subset of the MAR instruction +*/ +void tms32025_device::norm() +{ + if (m_ACC.d !=0 && (INT32)(m_ACC.d ^ (m_ACC.d << 1)) >= 0) + { + CLR1(TC_FLAG); + m_ACC.d <<= 1; + MODIFY_AR_ARP(); + } + else SET1(TC_FLAG); +} +void tms32025_device::or_() +{ + GETDATA(0, 0); + m_ACC.w.l |= m_ALU.w.l; +} +void tms32025_device::ork() +{ + m_ALU.d = (UINT16)M_RDOP_ARG(m_PC); + m_PC++; + m_ALU.d <<= (m_opcode.b.h & 0xf); + m_ACC.d |= (m_ALU.d); +} +void tms32025_device::out() +{ + GETDATA(0, 0); + P_OUT( (m_opcode.b.h & 0xf), m_ALU.w.l ); +} +void tms32025_device::pac() +{ + SHIFT_Preg_TO_ALU(); + m_ACC.d = m_ALU.d; +} +void tms32025_device::pop() +{ + m_ACC.d = (UINT16)POP_STACK(); +} +void tms32025_device::popd() +{ + m_ALU.d = (UINT16)POP_STACK(); + PUTDATA(m_ALU.w.l); +} +void tms32025_device::pshd() +{ + GETDATA(0, 0); + PUSH_STACK(m_ALU.w.l); +} +void tms32025_device::push() +{ + PUSH_STACK(m_ACC.w.l); +} +void tms32025_device::rc() +{ + CLR1(C_FLAG); +} +void tms32025_device::ret() +{ + SET_PC(POP_STACK()); +} +void tms32025_device::rfsm() /** serial port mode */ +{ + CLR1(FSM_FLAG); +} +void tms32025_device::rhm() +{ + CLR1(HM_FLAG); +} +void tms32025_device::rol() +{ + m_ALU.d = m_ACC.d; + m_ACC.d <<= 1; + if (CARRY) m_ACC.d |= 1; + if (m_ALU.d & 0x80000000) SET1(C_FLAG); + else CLR1(C_FLAG); +} +void tms32025_device::ror() +{ + m_ALU.d = m_ACC.d; + m_ACC.d >>= 1; + if (CARRY) m_ACC.d |= 0x80000000; + if (m_ALU.d & 1) SET1(C_FLAG); + else CLR1(C_FLAG); +} +void tms32025_device::rovm() +{ + CLR0(OVM_FLAG); +} +void tms32025_device::rpt() +{ + GETDATA(0, 0); + m_RPTC = m_ALU.b.l; + m_init_load_addr = 2; /* Initiate repeat mode */ +} +void tms32025_device::rptk() +{ + m_RPTC = m_opcode.b.l; + m_init_load_addr = 2; /* Initiate repeat mode */ +} +void tms32025_device::rsxm() +{ + CLR1(SXM_FLAG); +} +void tms32025_device::rtc() +{ + CLR1(TC_FLAG); +} +void tms32025_device::rtxm() /** Serial port stuff */ +{ + CLR1(TXM_FLAG); +} +void tms32025_device::rxf() +{ + CLR1(XF_FLAG); + S_OUT(TMS32025_XF,CLEAR_LINE); +} +void tms32025_device::sach() +{ + m_ALU.d = (m_ACC.d << (m_opcode.b.h & 7)); + PUTDATA(m_ALU.w.h); +} +void tms32025_device::sacl() +{ + m_ALU.d = (m_ACC.d << (m_opcode.b.h & 7)); + PUTDATA(m_ALU.w.l); +} +void tms32025_device::sar_ar0() { PUTDATA(m_AR[0]); } +void tms32025_device::sar_ar1() { PUTDATA(m_AR[1]); } +void tms32025_device::sar_ar2() { PUTDATA(m_AR[2]); } +void tms32025_device::sar_ar3() { PUTDATA(m_AR[3]); } +void tms32025_device::sar_ar4() { PUTDATA(m_AR[4]); } +void tms32025_device::sar_ar5() { PUTDATA(m_AR[5]); } +void tms32025_device::sar_ar6() { PUTDATA(m_AR[6]); } +void tms32025_device::sar_ar7() { PUTDATA(m_AR[7]); } + +void tms32025_device::sblk() +{ + m_oldacc.d = m_ACC.d; + if (SXM) m_ALU.d = (INT16)M_RDOP_ARG(m_PC); + else m_ALU.d = (UINT16)M_RDOP_ARG(m_PC); + m_PC++; + m_ALU.d <<= (m_opcode.b.h & 0xf); + m_ACC.d -= m_ALU.d; + CALCULATE_SUB_OVERFLOW(m_ALU.d); + CALCULATE_SUB_CARRY(); +} +void tms32025_device::sbrk_ar() +{ + m_AR[ARP] -= m_opcode.b.l; +} +void tms32025_device::sc() +{ + SET1(C_FLAG); +} +void tms32025_device::sfl() +{ + m_ALU.d = m_ACC.d; + m_ACC.d <<= 1; + if (m_ALU.d & 0x80000000) SET1(C_FLAG); + else CLR1(C_FLAG); +} +void tms32025_device::sfr() +{ + m_ALU.d = m_ACC.d; + m_ACC.d >>= 1; + if (SXM) { + if (m_ALU.d & 0x80000000) m_ACC.d |= 0x80000000; + } + if (m_ALU.d & 1) SET1(C_FLAG); + else CLR1(C_FLAG); +} +void tms32025_device::sfsm() /** Serial port mode */ +{ + SET1(FSM_FLAG); +} +void tms32025_device::shm() +{ + SET1(HM_FLAG); +} +void tms32025_device::sovm() +{ + SET0(OVM_FLAG); +} +void tms32025_device::spac() +{ + m_oldacc.d = m_ACC.d; + SHIFT_Preg_TO_ALU(); + m_ACC.d -= m_ALU.d; + CALCULATE_SUB_OVERFLOW(m_ALU.d); + CALCULATE_SUB_CARRY(); +} +void tms32025_device::sph() +{ + SHIFT_Preg_TO_ALU(); + PUTDATA(m_ALU.w.h); +} +void tms32025_device::spl() +{ + SHIFT_Preg_TO_ALU(); + PUTDATA(m_ALU.w.l); +} +void tms32025_device::spm() +{ + MODIFY_PM((m_opcode.b.l & 3) ); +} +void tms32025_device::sqra() +{ + m_oldacc.d = m_ACC.d; + SHIFT_Preg_TO_ALU(); + m_ACC.d += m_ALU.d; + CALCULATE_ADD_OVERFLOW(m_ALU.d); + CALCULATE_ADD_CARRY(); + GETDATA(0, 0); + m_Treg = m_ALU.w.l; + m_Preg.d = ((INT16)m_ALU.w.l * (INT16)m_ALU.w.l); +} +void tms32025_device::sqrs() +{ + m_oldacc.d = m_ACC.d; + SHIFT_Preg_TO_ALU(); + m_ACC.d -= m_ALU.d; + CALCULATE_SUB_OVERFLOW(m_ALU.d); + CALCULATE_SUB_CARRY(); + GETDATA(0, 0); + m_Treg = m_ALU.w.l; + m_Preg.d = ((INT16)m_ALU.w.l * (INT16)m_ALU.w.l); +} +void tms32025_device::sst() +{ + PUTDATA_SST(m_STR0); +} +void tms32025_device::sst1() +{ + PUTDATA_SST(m_STR1); +} +void tms32025_device::ssxm() +{ + SET1(SXM_FLAG); +} +void tms32025_device::stc() +{ + SET1(TC_FLAG); +} +void tms32025_device::stxm() /** Serial port stuff */ +{ + SET1(TXM_FLAG); +} +void tms32025_device::sub() +{ + m_oldacc.d = m_ACC.d; + GETDATA((m_opcode.b.h & 0xf), SXM); + m_ACC.d -= m_ALU.d; + CALCULATE_SUB_OVERFLOW(m_ALU.d); + CALCULATE_SUB_CARRY(); +} +void tms32025_device::subb() +{ + m_oldacc.d = m_ACC.d; + GETDATA(0, 0); + if (CARRY == 0) m_ACC.d--; + m_ACC.d -= m_ALU.d; + CALCULATE_SUB_OVERFLOW(m_ALU.d); + if (m_ACC.d == m_oldacc.d) {} /* edge case, carry remains same */ + else CALCULATE_SUB_CARRY(); +} +void tms32025_device::subc() +{ + m_oldacc.d = m_ACC.d; + GETDATA(15, SXM); + m_ACC.d -= m_ALU.d; /* Temporary switch to ACC. Actual calculation is done as (ACC)-[mem] -> ALU, will be preserved later on. */ + if ((INT32)((m_oldacc.d ^ m_ALU.d) & (m_oldacc.d ^ m_ACC.d)) < 0) { + SET0(OV_FLAG); /* Not affected by OVM */ + } + CALCULATE_SUB_CARRY(); + if( m_oldacc.d >= m_ALU.d ) { + m_ALU.d = m_ACC.d; + m_ACC.d = m_ACC.d << 1 | 1; + } + else { + m_ALU.d = m_ACC.d; + m_ACC.d = m_oldacc.d << 1; + } +} +void tms32025_device::subh() +{ + m_oldacc.d = m_ACC.d; + GETDATA(0, 0); + m_ACC.w.h -= m_ALU.w.l; + if ( (UINT16)(m_oldacc.w.h) < (UINT16)(m_ACC.w.h) ) { + CLR1(C_FLAG); /* Carry flag is not affected, if no borrow occurred */ + } + if ((INT16)((m_oldacc.w.h ^ m_ALU.w.l) & (m_oldacc.w.h ^ m_ACC.w.h)) < 0) { + SET0(OV_FLAG); + if (OVM) m_ACC.w.h = ((INT16)m_oldacc.w.h < 0) ? 0x8000 : 0x7fff; + } +} +void tms32025_device::subk() +{ + m_oldacc.d = m_ACC.d; + m_ALU.d = (UINT8)m_opcode.b.l; + m_ACC.d -= m_ALU.b.l; + CALCULATE_SUB_OVERFLOW(m_ALU.d); + CALCULATE_SUB_CARRY(); +} +void tms32025_device::subs() +{ + m_oldacc.d = m_ACC.d; + GETDATA(0, 0); + m_ACC.d -= m_ALU.w.l; + CALCULATE_SUB_OVERFLOW(m_ALU.d); + CALCULATE_SUB_CARRY(); +} +void tms32025_device::subt() +{ + m_oldacc.d = m_ACC.d; + GETDATA((m_Treg & 0xf), SXM); + m_ACC.d -= m_ALU.d; + CALCULATE_SUB_OVERFLOW(m_ALU.d); + CALCULATE_SUB_CARRY(); +} +void tms32025_device::sxf() +{ + SET1(XF_FLAG); + S_OUT(TMS32025_XF,ASSERT_LINE); +} +void tms32025_device::tblr() +{ + if (m_init_load_addr) { + m_PFC = m_ACC.w.l; + } + m_ALU.w.l = M_RDROM(m_PFC); + if ( (CNF0) && ( (UINT16)(m_PFC) >= 0xff00 ) ) {} /** TMS32025 only */ + else m_tms32025_dec_cycles += (1*CLK); + PUTDATA(m_ALU.w.l); + m_PFC++; +} +void tms32025_device::tblw() +{ + if (m_init_load_addr) { + m_PFC = m_ACC.w.l; + } + m_tms32025_dec_cycles += (1*CLK); + GETDATA(0, 0); + if (m_external_mem_access) m_tms32025_dec_cycles += (1*CLK); + M_WRTROM(m_PFC, m_ALU.w.l); + m_PFC++; +} +void tms32025_device::trap() +{ + PUSH_STACK(m_PC); + SET_PC(0x001E); /* Trap vector */ +} +void tms32025_device::xor_() +{ + GETDATA(0, 0); + m_ACC.w.l ^= m_ALU.w.l; +} +void tms32025_device::xork() +{ + m_ALU.d = M_RDOP_ARG(m_PC); + m_PC++; + m_ALU.d <<= (m_opcode.b.h & 0xf); + m_ACC.d ^= m_ALU.d; +} +void tms32025_device::zalh() +{ + GETDATA(0, 0); + m_ACC.w.h = m_ALU.w.l; + m_ACC.w.l = 0x0000; +} +void tms32025_device::zalr() +{ + GETDATA(0, 0); + m_ACC.w.h = m_ALU.w.l; + m_ACC.w.l = 0x8000; +} +void tms32025_device::zals() +{ + GETDATA(0, 0); + m_ACC.w.l = m_ALU.w.l; + m_ACC.w.h = 0x0000; +} + + +/*********************************************************************** + * Opcode Table (Cycles, Instruction) + ***********************************************************************/ + +const tms32025_device::tms32025_opcode tms32025_device::s_opcode_main[256]= +{ +/*00*/ {1*CLK, &tms32025_device::add },{1*CLK, &tms32025_device::add },{1*CLK, &tms32025_device::add },{1*CLK, &tms32025_device::add },{1*CLK, &tms32025_device::add },{1*CLK, &tms32025_device::add },{1*CLK, &tms32025_device::add },{1*CLK, &tms32025_device::add }, +/*08*/ {1*CLK, &tms32025_device::add },{1*CLK, &tms32025_device::add },{1*CLK, &tms32025_device::add },{1*CLK, &tms32025_device::add },{1*CLK, &tms32025_device::add },{1*CLK, &tms32025_device::add },{1*CLK, &tms32025_device::add },{1*CLK, &tms32025_device::add }, +/*10*/ {1*CLK, &tms32025_device::sub },{1*CLK, &tms32025_device::sub },{1*CLK, &tms32025_device::sub },{1*CLK, &tms32025_device::sub },{1*CLK, &tms32025_device::sub },{1*CLK, &tms32025_device::sub },{1*CLK, &tms32025_device::sub },{1*CLK, &tms32025_device::sub }, +/*18*/ {1*CLK, &tms32025_device::sub },{1*CLK, &tms32025_device::sub },{1*CLK, &tms32025_device::sub },{1*CLK, &tms32025_device::sub },{1*CLK, &tms32025_device::sub },{1*CLK, &tms32025_device::sub },{1*CLK, &tms32025_device::sub },{1*CLK, &tms32025_device::sub }, +/*20*/ {1*CLK, &tms32025_device::lac },{1*CLK, &tms32025_device::lac },{1*CLK, &tms32025_device::lac },{1*CLK, &tms32025_device::lac },{1*CLK, &tms32025_device::lac },{1*CLK, &tms32025_device::lac },{1*CLK, &tms32025_device::lac },{1*CLK, &tms32025_device::lac }, +/*28*/ {1*CLK, &tms32025_device::lac },{1*CLK, &tms32025_device::lac },{1*CLK, &tms32025_device::lac },{1*CLK, &tms32025_device::lac },{1*CLK, &tms32025_device::lac },{1*CLK, &tms32025_device::lac },{1*CLK, &tms32025_device::lac },{1*CLK, &tms32025_device::lac }, +/*30*/ {1*CLK, &tms32025_device::lar_ar0 },{1*CLK, &tms32025_device::lar_ar1 },{1*CLK, &tms32025_device::lar_ar2 },{1*CLK, &tms32025_device::lar_ar3 },{1*CLK, &tms32025_device::lar_ar4 },{1*CLK, &tms32025_device::lar_ar5 },{1*CLK, &tms32025_device::lar_ar6 },{1*CLK, &tms32025_device::lar_ar7 }, +/*38*/ {1*CLK, &tms32025_device::mpy },{1*CLK, &tms32025_device::sqra },{1*CLK, &tms32025_device::mpya },{1*CLK, &tms32025_device::mpys },{1*CLK, &tms32025_device::lt },{1*CLK, &tms32025_device::lta },{1*CLK, &tms32025_device::ltp },{1*CLK, &tms32025_device::ltd }, +/*40*/ {1*CLK, &tms32025_device::zalh },{1*CLK, &tms32025_device::zals },{1*CLK, &tms32025_device::lact },{1*CLK, &tms32025_device::addc },{1*CLK, &tms32025_device::subh },{1*CLK, &tms32025_device::subs },{1*CLK, &tms32025_device::subt },{1*CLK, &tms32025_device::subc }, +/*48*/ {1*CLK, &tms32025_device::addh },{1*CLK, &tms32025_device::adds },{1*CLK, &tms32025_device::addt },{1*CLK, &tms32025_device::rpt },{1*CLK, &tms32025_device::xor_ },{1*CLK, &tms32025_device::or_ },{1*CLK, &tms32025_device::and_ },{1*CLK, &tms32025_device::subb }, +/*50*/ {1*CLK, &tms32025_device::lst },{1*CLK, &tms32025_device::lst1 },{1*CLK, &tms32025_device::ldp },{1*CLK, &tms32025_device::lph },{1*CLK, &tms32025_device::pshd },{1*CLK, &tms32025_device::mar },{1*CLK, &tms32025_device::dmov },{1*CLK, &tms32025_device::bitt }, +/*58*/ {3*CLK, &tms32025_device::tblr },{2*CLK, &tms32025_device::tblw },{1*CLK, &tms32025_device::sqrs },{1*CLK, &tms32025_device::lts },{2*CLK, &tms32025_device::macd },{2*CLK, &tms32025_device::mac },{2*CLK, &tms32025_device::bc },{2*CLK, &tms32025_device::bnc }, +/*60*/ {1*CLK, &tms32025_device::sacl },{1*CLK, &tms32025_device::sacl },{1*CLK, &tms32025_device::sacl },{1*CLK, &tms32025_device::sacl },{1*CLK, &tms32025_device::sacl },{1*CLK, &tms32025_device::sacl },{1*CLK, &tms32025_device::sacl },{1*CLK, &tms32025_device::sacl }, +/*68*/ {1*CLK, &tms32025_device::sach },{1*CLK, &tms32025_device::sach },{1*CLK, &tms32025_device::sach },{1*CLK, &tms32025_device::sach },{1*CLK, &tms32025_device::sach },{1*CLK, &tms32025_device::sach },{1*CLK, &tms32025_device::sach },{1*CLK, &tms32025_device::sach }, +/*70*/ {1*CLK, &tms32025_device::sar_ar0 },{1*CLK, &tms32025_device::sar_ar1 },{1*CLK, &tms32025_device::sar_ar2 },{1*CLK, &tms32025_device::sar_ar3 },{1*CLK, &tms32025_device::sar_ar4 },{1*CLK, &tms32025_device::sar_ar5 },{1*CLK, &tms32025_device::sar_ar6 },{1*CLK, &tms32025_device::sar_ar7 }, +/*78*/ {1*CLK, &tms32025_device::sst },{1*CLK, &tms32025_device::sst1 },{1*CLK, &tms32025_device::popd },{1*CLK, &tms32025_device::zalr },{1*CLK, &tms32025_device::spl },{1*CLK, &tms32025_device::sph },{1*CLK, &tms32025_device::adrk },{1*CLK, &tms32025_device::sbrk_ar }, +/*80*/ {2*CLK, &tms32025_device::in },{2*CLK, &tms32025_device::in },{2*CLK, &tms32025_device::in },{2*CLK, &tms32025_device::in },{2*CLK, &tms32025_device::in },{2*CLK, &tms32025_device::in },{2*CLK, &tms32025_device::in },{2*CLK, &tms32025_device::in }, +/*88*/ {2*CLK, &tms32025_device::in },{2*CLK, &tms32025_device::in },{2*CLK, &tms32025_device::in },{2*CLK, &tms32025_device::in },{2*CLK, &tms32025_device::in },{2*CLK, &tms32025_device::in },{2*CLK, &tms32025_device::in },{2*CLK, &tms32025_device::in }, +/*90*/ {1*CLK, &tms32025_device::bit },{1*CLK, &tms32025_device::bit },{1*CLK, &tms32025_device::bit },{1*CLK, &tms32025_device::bit },{1*CLK, &tms32025_device::bit },{1*CLK, &tms32025_device::bit },{1*CLK, &tms32025_device::bit },{1*CLK, &tms32025_device::bit }, +/*98*/ {1*CLK, &tms32025_device::bit },{1*CLK, &tms32025_device::bit },{1*CLK, &tms32025_device::bit },{1*CLK, &tms32025_device::bit },{1*CLK, &tms32025_device::bit },{1*CLK, &tms32025_device::bit },{1*CLK, &tms32025_device::bit },{1*CLK, &tms32025_device::bit }, +/*A0*/ {1*CLK, &tms32025_device::mpyk },{1*CLK, &tms32025_device::mpyk },{1*CLK, &tms32025_device::mpyk },{1*CLK, &tms32025_device::mpyk },{1*CLK, &tms32025_device::mpyk },{1*CLK, &tms32025_device::mpyk },{1*CLK, &tms32025_device::mpyk },{1*CLK, &tms32025_device::mpyk }, +/*A8*/ {1*CLK, &tms32025_device::mpyk },{1*CLK, &tms32025_device::mpyk },{1*CLK, &tms32025_device::mpyk },{1*CLK, &tms32025_device::mpyk },{1*CLK, &tms32025_device::mpyk },{1*CLK, &tms32025_device::mpyk },{1*CLK, &tms32025_device::mpyk },{1*CLK, &tms32025_device::mpyk }, +/*B0*/ {1*CLK, &tms32025_device::mpyk },{1*CLK, &tms32025_device::mpyk },{1*CLK, &tms32025_device::mpyk },{1*CLK, &tms32025_device::mpyk },{1*CLK, &tms32025_device::mpyk },{1*CLK, &tms32025_device::mpyk },{1*CLK, &tms32025_device::mpyk },{1*CLK, &tms32025_device::mpyk }, +/*B8*/ {1*CLK, &tms32025_device::mpyk },{1*CLK, &tms32025_device::mpyk },{1*CLK, &tms32025_device::mpyk },{1*CLK, &tms32025_device::mpyk },{1*CLK, &tms32025_device::mpyk },{1*CLK, &tms32025_device::mpyk },{1*CLK, &tms32025_device::mpyk },{1*CLK, &tms32025_device::mpyk }, +/*C0*/ {1*CLK, &tms32025_device::lark_ar0 },{1*CLK, &tms32025_device::lark_ar1 },{1*CLK, &tms32025_device::lark_ar2 },{1*CLK, &tms32025_device::lark_ar3 },{1*CLK, &tms32025_device::lark_ar4 },{1*CLK, &tms32025_device::lark_ar5 },{1*CLK, &tms32025_device::lark_ar6 },{1*CLK, &tms32025_device::lark_ar7 }, +/*C8*/ {1*CLK, &tms32025_device::ldpk },{1*CLK, &tms32025_device::ldpk },{1*CLK, &tms32025_device::lack },{1*CLK, &tms32025_device::rptk },{1*CLK, &tms32025_device::addk },{1*CLK, &tms32025_device::subk },{1*CLK, &tms32025_device::opcodes_CE},{1*CLK, &tms32025_device::mpyu }, +/*D0*/ {1*CLK, &tms32025_device::opcodes_Dx},{1*CLK, &tms32025_device::opcodes_Dx},{1*CLK, &tms32025_device::opcodes_Dx},{1*CLK, &tms32025_device::opcodes_Dx},{1*CLK, &tms32025_device::opcodes_Dx},{1*CLK, &tms32025_device::opcodes_Dx},{1*CLK, &tms32025_device::opcodes_Dx},{0*CLK, &tms32025_device::opcodes_Dx}, +/*D8*/ {1*CLK, &tms32025_device::opcodes_Dx},{1*CLK, &tms32025_device::opcodes_Dx},{1*CLK, &tms32025_device::opcodes_Dx},{1*CLK, &tms32025_device::opcodes_Dx},{1*CLK, &tms32025_device::opcodes_Dx},{1*CLK, &tms32025_device::opcodes_Dx},{1*CLK, &tms32025_device::opcodes_Dx},{1*CLK, &tms32025_device::opcodes_Dx}, +/*E0*/ {2*CLK, &tms32025_device::out },{2*CLK, &tms32025_device::out },{2*CLK, &tms32025_device::out },{2*CLK, &tms32025_device::out },{2*CLK, &tms32025_device::out },{2*CLK, &tms32025_device::out },{2*CLK, &tms32025_device::out },{2*CLK, &tms32025_device::out }, +/*E8*/ {2*CLK, &tms32025_device::out },{2*CLK, &tms32025_device::out },{2*CLK, &tms32025_device::out },{2*CLK, &tms32025_device::out },{2*CLK, &tms32025_device::out },{2*CLK, &tms32025_device::out },{2*CLK, &tms32025_device::out },{2*CLK, &tms32025_device::out }, +/*F0*/ {2*CLK, &tms32025_device::bv },{2*CLK, &tms32025_device::bgz },{2*CLK, &tms32025_device::blez },{2*CLK, &tms32025_device::blz },{2*CLK, &tms32025_device::bgez },{2*CLK, &tms32025_device::bnz },{2*CLK, &tms32025_device::bz },{2*CLK, &tms32025_device::bnv }, +/*F8*/ {2*CLK, &tms32025_device::bbz },{2*CLK, &tms32025_device::bbnz },{2*CLK, &tms32025_device::bioz },{2*CLK, &tms32025_device::banz },{2*CLK, &tms32025_device::blkp },{2*CLK, &tms32025_device::blkd },{2*CLK, &tms32025_device::call },{2*CLK, &tms32025_device::br } +}; + +const tms32025_device::tms32025_opcode tms32025_device::s_opcode_CE_subset[256]= /* Instructions living under the CExx opcode */ +{ +/*00*/ {1*CLK, &tms32025_device::eint },{1*CLK, &tms32025_device::dint },{1*CLK, &tms32025_device::rovm },{1*CLK, &tms32025_device::sovm },{1*CLK, &tms32025_device::cnfd },{1*CLK, &tms32025_device::cnfp },{1*CLK, &tms32025_device::rsxm },{1*CLK, &tms32025_device::ssxm }, +/*08*/ {1*CLK, &tms32025_device::spm },{1*CLK, &tms32025_device::spm },{1*CLK, &tms32025_device::spm },{1*CLK, &tms32025_device::spm },{1*CLK, &tms32025_device::rxf },{1*CLK, &tms32025_device::sxf },{1*CLK, &tms32025_device::fort },{1*CLK, &tms32025_device::fort }, +/*10*/ {0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{1*CLK, &tms32025_device::pac },{1*CLK, &tms32025_device::apac },{1*CLK, &tms32025_device::spac },{0*CLK, &tms32025_device::illegal }, +/*18*/ {1*CLK, &tms32025_device::sfl },{1*CLK, &tms32025_device::sfr },{0*CLK, &tms32025_device::illegal },{1*CLK, &tms32025_device::abst },{1*CLK, &tms32025_device::push },{1*CLK, &tms32025_device::pop },{2*CLK, &tms32025_device::trap },{3*CLK, &tms32025_device::idle }, +/*20*/ {1*CLK, &tms32025_device::rtxm },{1*CLK, &tms32025_device::stxm },{0*CLK, &tms32025_device::illegal },{1*CLK, &tms32025_device::neg },{2*CLK, &tms32025_device::cala },{2*CLK, &tms32025_device::bacc },{2*CLK, &tms32025_device::ret },{1*CLK, &tms32025_device::cmpl }, +/*28*/ {0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal }, +/*30*/ {1*CLK, &tms32025_device::rc },{1*CLK, &tms32025_device::sc },{1*CLK, &tms32025_device::rtc },{1*CLK, &tms32025_device::stc },{1*CLK, &tms32025_device::rol },{1*CLK, &tms32025_device::ror },{1*CLK, &tms32025_device::rfsm },{1*CLK, &tms32025_device::sfsm }, +/*38*/ {1*CLK, &tms32025_device::rhm },{1*CLK, &tms32025_device::shm },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{1*CLK, &tms32025_device::conf },{1*CLK, &tms32025_device::conf },{1*CLK, &tms32025_device::conf },{1*CLK, &tms32025_device::conf }, +/*40*/ {0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal }, +/*48*/ {0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal }, +/*50*/ {1*CLK, &tms32025_device::cmpr },{1*CLK, &tms32025_device::cmpr },{1*CLK, &tms32025_device::cmpr },{1*CLK, &tms32025_device::cmpr },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal }, +/*58*/ {0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal }, +/*60*/ {0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal }, +/*68*/ {0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal }, +/*70*/ {0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal }, +/*78*/ {0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal }, +/*80*/ {0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{1*CLK, &tms32025_device::norm },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal }, +/*88*/ {0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal }, +/*90*/ {0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{1*CLK, &tms32025_device::norm },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal }, +/*98*/ {0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal }, +/*A0*/ {0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{1*CLK, &tms32025_device::norm },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal }, +/*A8*/ {0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal }, +/*B0*/ {0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{1*CLK, &tms32025_device::norm },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal }, +/*B8*/ {0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal }, +/*C0*/ {0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{1*CLK, &tms32025_device::norm },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal }, +/*C8*/ {0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal }, +/*D0*/ {0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{1*CLK, &tms32025_device::norm },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal }, +/*D8*/ {0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal }, +/*E0*/ {0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{1*CLK, &tms32025_device::norm },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal }, +/*E8*/ {0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal }, +/*F0*/ {0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{1*CLK, &tms32025_device::norm },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal }, +/*F8*/ {0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal },{0*CLK, &tms32025_device::illegal } +}; + +const tms32025_device::tms32025_opcode tms32025_device::s_opcode_Dx_subset[8]= /* Instructions living under the Dxxx opcode */ +{ +/*00*/ {2*CLK, &tms32025_device::lrlk },{2*CLK, &tms32025_device::lalk },{2*CLK, &tms32025_device::adlk },{2*CLK, &tms32025_device::sblk },{2*CLK, &tms32025_device::andk },{2*CLK, &tms32025_device::ork },{2*CLK, &tms32025_device::xork },{0*CLK, &tms32025_device::illegal } +}; + + + +/**************************************************************************** + * Initialise the CPU emulation + ****************************************************************************/ +void tms32025_device::device_start() +{ + m_program = &space(AS_PROGRAM); + m_direct = &m_program->direct(); + m_data = &space(AS_DATA); + m_io = &space(AS_IO); + + m_PREVPC = 0; + m_PFC = 0; + m_STR0 = 0; + m_STR1 = 0; + m_ACC.d = 0; + m_Preg.d = 0; + m_Treg = 0; + m_AR[0] = m_AR[1] = m_AR[2] = m_AR[3] = m_AR[4] = m_AR[5] = m_AR[6] = m_AR[7] = 0; + m_STACK[0] = m_STACK[1] = m_STACK[2] = m_STACK[3] = m_STACK[4] = m_STACK[5] = m_STACK[6] = m_STACK[7] = 0; + m_ALU.d = 0; + memset(m_intRAM, 0, sizeof(m_intRAM)); + m_timerover = 0; + m_opcode.d = 0; + m_external_mem_access = 0; + m_tms32025_irq_cycles = 0; + m_oldacc.d = 0; + m_memaccess = 0; + m_mHackIgnoreARP = 0; + m_waiting_for_serial_frame = 0; + + save_item(NAME(m_PC)); + save_item(NAME(m_STR0)); + save_item(NAME(m_STR1)); + save_item(NAME(m_PFC)); + save_item(NAME(m_IFR)); + save_item(NAME(m_RPTC)); + save_item(NAME(m_ACC.d)); + save_item(NAME(m_ALU.d)); + save_item(NAME(m_Preg.d)); + save_item(NAME(m_Treg)); + save_item(NAME(m_AR[0])); + save_item(NAME(m_AR[1])); + save_item(NAME(m_AR[2])); + save_item(NAME(m_AR[3])); + save_item(NAME(m_AR[4])); + save_item(NAME(m_AR[5])); + save_item(NAME(m_AR[6])); + save_item(NAME(m_AR[7])); + save_item(NAME(m_STACK[0])); + save_item(NAME(m_STACK[1])); + save_item(NAME(m_STACK[2])); + save_item(NAME(m_STACK[3])); + save_item(NAME(m_STACK[4])); + save_item(NAME(m_STACK[5])); + save_item(NAME(m_STACK[6])); + save_item(NAME(m_STACK[7])); + + save_item(NAME(m_oldacc)); + save_item(NAME(m_memaccess)); + save_item(NAME(m_mHackIgnoreARP)); + + save_item(NAME(m_idle)); + save_item(NAME(m_hold)); + save_item(NAME(m_external_mem_access)); + save_item(NAME(m_init_load_addr)); + save_item(NAME(m_PREVPC)); + + save_item(NAME(m_intRAM)); + + state_add( TMS32025_PC, "PC", m_PC).formatstr("%04X"); + state_add( TMS32025_STR0, "STR0", m_STR0).formatstr("%04X"); + state_add( TMS32025_STR1, "STR1", m_STR1).formatstr("%04X"); + state_add( TMS32025_IFR, "IFR", m_IFR).formatstr("%04X"); + state_add( TMS32025_RPTC, "RPTC", m_RPTC).formatstr("%02X"); + state_add( TMS32025_STK7, "STK7", m_STACK[7]).formatstr("%04X"); + state_add( TMS32025_STK6, "STK6", m_STACK[6]).formatstr("%04X"); + state_add( TMS32025_STK5, "STK5", m_STACK[5]).formatstr("%04X"); + state_add( TMS32025_STK4, "STK4", m_STACK[4]).formatstr("%04X"); + state_add( TMS32025_STK3, "STK3", m_STACK[3]).formatstr("%04X"); + state_add( TMS32025_STK2, "STK2", m_STACK[2]).formatstr("%04X"); + state_add( TMS32025_STK1, "STK1", m_STACK[1]).formatstr("%04X"); + state_add( TMS32025_STK0, "STK0", m_STACK[0]).formatstr("%04X"); + state_add( TMS32025_ACC, "ACC", m_ACC.d).formatstr("%08X"); + state_add( TMS32025_PREG, "P", m_Preg.d).formatstr("%08X"); + state_add( TMS32025_TREG, "T", m_Treg).formatstr("%04X"); + state_add( TMS32025_AR0, "AR0", m_AR[0]).formatstr("%04X"); + state_add( TMS32025_AR1, "AR1", m_AR[1]).formatstr("%04X"); + state_add( TMS32025_AR2, "AR2", m_AR[2]).formatstr("%04X"); + state_add( TMS32025_AR3, "AR3", m_AR[3]).formatstr("%04X"); + state_add( TMS32025_AR4, "AR4", m_AR[4]).formatstr("%04X"); + state_add( TMS32025_AR5, "AR5", m_AR[5]).formatstr("%04X"); + state_add( TMS32025_AR6, "AR6", m_AR[6]).formatstr("%04X"); + state_add( TMS32025_AR7, "AR7", m_AR[7]).formatstr("%04X"); + state_add( TMS32025_DRR, "DRR", m_debugger_temp).callimport().callexport().formatstr("%04X"); + state_add( TMS32025_DXR, "DXR", m_debugger_temp).callimport().callexport().formatstr("%04X"); + state_add( TMS32025_TIM, "TIM", m_debugger_temp).callimport().callexport().formatstr("%04X"); + state_add( TMS32025_PRD, "PRD", m_debugger_temp).callimport().callexport().formatstr("%04X"); + state_add( TMS32025_IMR, "IMR", m_debugger_temp).callimport().callexport().formatstr("%04X"); + state_add( TMS32025_GREG, "GREG", m_debugger_temp).callimport().callexport().formatstr("%04X"); + + state_add(STATE_GENPC, "GENPC", m_PC).formatstr("%04X").noshow(); + /* This is actually not a stack pointer, but the stack contents */ + state_add(STATE_GENSP, "GENSP", m_STACK[7]).formatstr("%04X").noshow(); + state_add(STATE_GENFLAGS, "GENFLAGS", m_STR0).formatstr("%33s").noshow(); + state_add(STATE_GENPCBASE, "GENPCBASE", m_PREVPC).formatstr("%04X").noshow(); + + m_icountptr = &m_icount; +} + + +void tms32025_device::state_import(const device_state_entry &entry) +{ + switch (entry.index()) + { + case TMS32025_DRR: + M_WRTRAM(0, m_debugger_temp); + break; + + case TMS32025_DXR: + M_WRTRAM(1, m_debugger_temp); + break; + + case TMS32025_TIM: + M_WRTRAM(2, m_debugger_temp); + break; + + case TMS32025_PRD: + M_WRTRAM(3, m_debugger_temp); + break; + + case TMS32025_IMR: + M_WRTRAM(4,m_debugger_temp); + break; + + case TMS32025_GREG: + M_WRTRAM(5, m_debugger_temp); + break; + } +} + + +void tms32025_device::state_export(const device_state_entry &entry) +{ + switch (entry.index()) + { + case TMS32025_DRR: + m_debugger_temp = M_RDRAM(0); + break; + + case TMS32025_DXR: + m_debugger_temp = M_RDRAM(1); + break; + + case TMS32025_TIM: + m_debugger_temp = M_RDRAM(2); + break; + + case TMS32025_PRD: + m_debugger_temp = M_RDRAM(3); + break; + + case TMS32025_IMR: + m_debugger_temp = M_RDRAM(4); + break; + + case TMS32025_GREG: + m_debugger_temp = M_RDRAM(5); + break; + } +} + + +void tms32025_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + switch (entry.index()) + { + case STATE_GENFLAGS: + strprintf(str, "arp%d%c%c%c%cdp%03x arb%d%c%c%c%c%c%c%c%c%c%c%cpm%d", + (m_STR0 & 0xe000) >> 13, + m_STR0 & 0x1000 ? 'O':'.', + m_STR0 & 0x0800 ? 'M':'.', + m_STR0 & 0x0400 ? '.':'?', + m_STR0 & 0x0200 ? 'I':'.', + (m_STR0 & 0x01ff), + + (m_STR1 & 0xe000) >> 13, + m_STR1 & 0x1000 ? 'P':'D', + m_STR1 & 0x0800 ? 'T':'.', + m_STR1 & 0x0400 ? 'S':'.', + m_STR1 & 0x0200 ? 'C':'?', + m_STR0 & 0x0100 ? '.':'?', + m_STR1 & 0x0080 ? '.':'?', + m_STR1 & 0x0040 ? 'H':'.', + m_STR1 & 0x0020 ? 'F':'.', + m_STR1 & 0x0010 ? 'X':'.', + m_STR1 & 0x0008 ? 'f':'.', + m_STR1 & 0x0004 ? 'o':'i', + (m_STR1 & 0x0003) + ); + break; + } +} + + +/**************************************************************************** + * Reset registers to their initial values + ****************************************************************************/ +void tms32025_device::device_reset() +{ + SET_PC(0); /* Starting address on a reset */ + m_STR0 |= 0x0600; /* INTM and unused bit set to 1 */ + m_STR0 &= 0xefff; /* OV cleared to 0. Remaining bits undefined */ + m_STR1 |= 0x07f0; /* SXM, C, HM, FSM, XF and unused bits set to 1 */ + m_STR1 &= 0xeff0; /* CNF, FO, TXM, PM bits cleared to 0. Remaining bits undefined */ + m_RPTC = 0; /* Reset repeat counter to 0 */ + m_IFR = 0; /* IRQ pending flags */ + + S_OUT(TMS32025_XF,ASSERT_LINE); /* XF flag is high. Must set the pin */ + + /* Set the internal memory mapped registers */ + GREG = 0; + TIM = 0xffff; + PRD = 0xffff; + IMR = 0xffc0; + + m_idle = 0; + m_hold = 0; + m_tms32025_dec_cycles = 0; + m_init_load_addr = 1; + + /* Reset the Data/Program address banks */ + memset(m_pgmmap, 0, sizeof(m_pgmmap)); + memset(m_datamap, 0, sizeof(m_datamap)); + + m_datamap[0] = &m_intRAM[0x000]; /* B2 */ + m_datamap[4] = &m_intRAM[0x200]; /* B0 */ + m_datamap[5] = &m_intRAM[0x280]; /* B0 */ + m_datamap[6] = &m_intRAM[0x300]; /* B1 */ + m_datamap[7] = &m_intRAM[0x380]; /* B1 */ +} + +void tms32026_device::device_reset() +{ + tms32025_device::device_reset(); + + m_datamap[8] = &m_intRAM[0x400]; /* B1 */ + m_datamap[9] = &m_intRAM[0x480]; /* B1 */ + m_datamap[10] = &m_intRAM[0x500]; /* B1 */ + m_datamap[11] = &m_intRAM[0x580]; /* B1 */ + m_datamap[12] = &m_intRAM[0x600]; /* B3 */ + m_datamap[13] = &m_intRAM[0x680]; /* B3 */ + m_datamap[14] = &m_intRAM[0x700]; /* B3 */ + m_datamap[15] = &m_intRAM[0x780]; /* B3 */ +} + + +/**************************************************************************** + * Issue an interrupt if necessary + ****************************************************************************/ +int tms32025_device::process_IRQs() +{ + /********** Interrupt Flag Register (IFR) ********** + | 5 | 4 | 3 | 2 | 1 | 0 | + | XINT| RINT| TINT| INT2| INT1| INT0| + */ + + m_tms32025_irq_cycles = 0; + + /* Dont service Interrupts if masked, or prev instruction was EINT ! */ + + if ( (INTM == 0) && (m_opcode.w.l != 0xce00) && (m_IFR & IMR) ) + { + m_tms32025_irq_cycles = (3*CLK); /* 3 clock cycles used due to PUSH and DINT operation ? */ + PUSH_STACK(m_PC); + + if ((m_IFR & 0x01) && (IMR & 0x01)) { /* IRQ line 0 */ + //logerror("TMS32025: Active INT0\n"); + SET_PC(0x0002); + standard_irq_callback(0); + m_idle = 0; + m_IFR &= (~0x01); + SET0(INTM_FLAG); + return m_tms32025_irq_cycles; + } + if ((m_IFR & 0x02) && (IMR & 0x02)) { /* IRQ line 1 */ + //logerror("TMS32025: Active INT1\n"); + SET_PC(0x0004); + standard_irq_callback(1); + m_idle = 0; + m_IFR &= (~0x02); + SET0(INTM_FLAG); + return m_tms32025_irq_cycles; + } + if ((m_IFR & 0x04) && (IMR & 0x04)) { /* IRQ line 2 */ + //logerror("TMS32025: Active INT2\n"); + SET_PC(0x0006); + standard_irq_callback(2); + m_idle = 0; + m_IFR &= (~0x04); + SET0(INTM_FLAG); + return m_tms32025_irq_cycles; + } + if ((m_IFR & 0x08) && (IMR & 0x08)) { /* Timer IRQ (internal) */ +// logerror("TMS32025: Active TINT (Timer)\n"); + SET_PC(0x0018); + m_idle = 0; + m_IFR &= (~0x08); + SET0(INTM_FLAG); + return m_tms32025_irq_cycles; + } + if ((m_IFR & 0x10) && (IMR & 0x10)) { /* Serial port receive IRQ (internal) */ +// logerror("TMS32025: Active RINT (Serial receive)\n"); + DRR = S_IN(TMS32025_DR); + SET_PC(0x001A); + m_idle = 0; + m_IFR &= (~0x10); + SET0(INTM_FLAG); + return m_tms32025_irq_cycles; + } + if ((m_IFR & 0x20) && (IMR & 0x20)) { /* Serial port transmit IRQ (internal) */ +// logerror("TMS32025: Active XINT (Serial transmit)\n"); + S_OUT(TMS32025_DX,DXR); + SET_PC(0x001C); + m_idle = 0; + m_IFR &= (~0x20); + SET0(INTM_FLAG); + return m_tms32025_irq_cycles; + } + } + return m_tms32025_irq_cycles; +} + + +void tms32025_device::process_timer(int clocks) +{ + int preclocks, ticks; + + /* easy case: no actual ticks */ +again: + preclocks = CLK - m_timerover; + if (clocks < preclocks) + { + m_timerover += clocks; + m_icount -= clocks; + return; + } + + /* if we're not going to overflow the timer, just count the clocks */ + ticks = 1 + (clocks - preclocks) / CLK; + if (ticks <= TIM) + { + m_icount -= clocks; + m_timerover = clocks - (ticks - 1) * CLK - preclocks; + TIM -= ticks; + } + + /* otherwise, overflow the timer and signal an interrupt */ + else + { + m_icount -= preclocks + CLK * TIM; + m_timerover = 0; + TIM = PRD; + + m_IFR |= 0x08; + clocks = process_IRQs(); /* Handle Timer IRQ */ + goto again; + } +} + + +/**************************************************************************** + * Execute ICount cycles. Exit when 0 or less + ****************************************************************************/ +void tms32025_device::execute_run() +{ + /**** Respond to external hold signal */ + if (S_IN(TMS32025_HOLD) == ASSERT_LINE) { + if (m_hold == 0) { + S_OUT(TMS32025_HOLDA,ASSERT_LINE); /* Hold-Ack (active low) */ + } + m_hold = 1; + if (HM) { + m_icount = 0; /* Exit */ + } + else { + if (m_external_mem_access) { + m_icount = 0; /* Exit */ + } + } + } + else { + if (m_hold == 1) { + S_OUT(TMS32025_HOLDA,CLEAR_LINE); /* Hold-Ack (active low) */ + process_timer(3); + } + m_hold = 0; + } + + /**** If idling, update timer and/or exit execution, but test for irqs first */ + if (m_idle && m_IFR && m_icount > 0) + m_icount -= process_IRQs(); + + while (m_idle && m_icount > 0) + process_timer(m_icount); + + if (m_icount <= 0) debugger_instruction_hook(this, m_PC); + + + while (m_icount > 0) + { + m_tms32025_dec_cycles = 0; + + if (m_IFR) { /* Check IRQ Flag Register for pending IRQs */ + m_tms32025_dec_cycles += process_IRQs(); + } + + m_PREVPC = m_PC; + + debugger_instruction_hook(this, m_PC); + + m_opcode.d = M_RDOP(m_PC); + m_PC++; + + if (m_opcode.b.h == 0xCE) /* Opcode 0xCExx has many sub-opcodes in its minor byte */ + { + m_tms32025_dec_cycles += s_opcode_CE_subset[m_opcode.b.l].cycles; + (this->*s_opcode_CE_subset[m_opcode.b.l].function)(); + } + else if ((m_opcode.w.l & 0xf0f8) == 0xd000) /* Opcode 0xDxxx has many sub-opcodes in its minor byte */ + { + m_tms32025_dec_cycles += s_opcode_Dx_subset[m_opcode.b.l].cycles; + (this->*s_opcode_Dx_subset[m_opcode.b.l].function)(); + } + else /* Do all opcodes except the CExx and Dxxx ones */ + { + m_tms32025_dec_cycles += s_opcode_main[m_opcode.b.h].cycles; + (this->*s_opcode_main[m_opcode.b.h].function)(); + } + + + if (m_init_load_addr == 2) { /* Repeat next instruction */ + /****************************************************\ + ******* These instructions are not repeatable ******** + ** ADLK, ANDK, LALK, LRLK, ORK, SBLK, XORK ** + ** ADDK, ADRK, LACK, LARK, LDPK, MPYK, RPTK ** + ** SBRK, SPM, SUBK, ZAC, IDLE, RPT, TRAP ** + ** BACC, CALA, RET ** + ** B, BANZ, BBNZ, BBZ, BC, BGEZ, BGZ, BIOZ ** + ** BNC, BNV, BNZ, BV, BZ, CALL, BLEZ, BLZ ** + \****************************************************/ + m_PREVPC = m_PC; + + debugger_instruction_hook(this, m_PC); + + m_opcode.d = M_RDOP(m_PC); + m_PC++; + m_tms32025_dec_cycles += (1*CLK); + + do { + if (m_opcode.b.h == 0xCE) + { /* Do all 0xCExx Opcodes */ + if (m_init_load_addr) { + m_tms32025_dec_cycles += (1*CLK); + } + else { + m_tms32025_dec_cycles += (1*CLK); + } + (this->*s_opcode_CE_subset[m_opcode.b.l].function)(); + } + else + { /* Do all other opcodes */ + if (m_init_load_addr) { + m_tms32025_dec_cycles += (1*CLK); + } + else { + m_tms32025_dec_cycles += (1*CLK); + } + (this->*s_opcode_main[m_opcode.b.h].function)(); + } + m_init_load_addr = 0; + m_RPTC-- ; + } while ((INT8)(m_RPTC) != -1); + m_RPTC = 0; + m_PFC = m_PC; + m_init_load_addr = 1; + } + + process_timer(m_tms32025_dec_cycles); + + /**** If device is put into idle mode, exit and wait for an interrupt */ + while (m_idle && m_icount > 0) + process_timer(m_icount); + + + /**** If hold pin is active, exit if accessing external memory or if HM is set */ + if (m_hold) { + if (m_external_mem_access || (HM)) { + if (m_icount > 0) { + m_icount = 0; + } + } + } + } +} + + + +/**************************************************************************** + * Set IRQ line state + ****************************************************************************/ +void tms32025_device::execute_set_input(int irqline, int state) +{ + if ( irqline == TMS32025_FSX ) { + if (state != CLEAR_LINE && m_waiting_for_serial_frame) + { + m_waiting_for_serial_frame = 0; + m_IFR = 0x20; + } + } + else + { + /* Pending IRQs cannot be cleared */ + if (state != CLEAR_LINE) + { + m_IFR |= (1 << irqline); + } + } +} + + +/**************************************************************************** + * Opcode fetcher + ****************************************************************************/ +bool tms32025_device::memory_readop(offs_t offset, int size, UINT64 &value) +{ + void *ptr; + + /* skip if not custom */ + if (!m_pgmmap[offset >> 8]) + return 0; + + ptr = &((UINT8 *)&m_pgmmap[offset >> 8])[offset & 0xff]; + switch (size) + { + case 1: value = *((UINT8 *) ptr); + case 2: value = *((UINT16 *) ptr); + case 4: value = *((UINT32 *) ptr); + case 8: value = *((UINT64 *) ptr); + } + return 1; +} + + +/**************************************************************************** + * Memory reader + ****************************************************************************/ +bool tms32025_device::memory_read(address_spacenum spacenum, offs_t offset, int size, UINT64 &value) +{ + void *ptr = NULL; + UINT64 temp = 0; + + switch (spacenum) + { + case AS_PROGRAM: + ptr = m_pgmmap[offset >> 8]; + if (!ptr) + return 0; + break; + + case AS_DATA: + ptr = m_datamap[offset >> 8]; + if (!ptr) + return 0; + break; + + default: + case AS_IO: + return 0; + } + + switch (size) + { + case 1: + value = ((UINT8 *)ptr)[BYTE_XOR_BE(offset & 0xff)]; + break; + case 2: + value = ((UINT16 *)ptr)[(offset & 0xff) / 2]; + break; + case 4: + memory_read(spacenum, offset + 0, 2, temp); + value = temp << 16; + memory_read(spacenum, offset + 2, 2, temp); + value |= temp & 0xffff; + break; + case 8: + memory_read(spacenum, offset + 0, 4, temp); + value = temp << 32; + memory_read(spacenum, offset + 4, 4, temp); + value |= temp & 0xffffffff; + break; + } + return 1; +} + + +/**************************************************************************** + * Memory writer + ****************************************************************************/ +bool tms32025_device::memory_write(address_spacenum spacenum, offs_t offset, int size, UINT64 value) +{ + void *ptr = NULL; + + switch (spacenum) + { + case AS_PROGRAM: + ptr = m_pgmmap[offset >> 8]; + if (!ptr) + return 0; + break; + + case AS_DATA: + ptr = m_datamap[offset >> 8]; + if (!ptr) + return 0; + break; + + default: + case AS_IO: + return 0; + } + + switch (size) + { + case 1: + ((UINT8 *)ptr)[BYTE_XOR_BE(offset & 0xff)] = value; + break; + case 2: + ((UINT16 *)ptr)[(offset & 0xff) / 2] = value; + break; + case 4: + memory_write(spacenum, offset + 0, 2, value >> 16); + memory_write(spacenum, offset + 2, 2, value); + break; + case 8: + memory_write(spacenum, offset + 0, 4, value >> 32); + memory_write(spacenum, offset + 4, 4, value); + break; + } + + return 1; +} diff --git a/src/devices/cpu/tms32025/tms32025.h b/src/devices/cpu/tms32025/tms32025.h new file mode 100644 index 00000000000..5992012d08e --- /dev/null +++ b/src/devices/cpu/tms32025/tms32025.h @@ -0,0 +1,368 @@ +// license:BSD-3-Clause +// copyright-holders:Tony La Porta, hap + /**************************************************************************\ + * Texas Instruments TMS320x25 DSP Emulator * + * * + * Copyright Tony La Porta * + * Written for the MAME project. * + * * + * Note : This is a word based microcontroller, with addressing * + * architecture based on the Harvard addressing scheme. * + * * + * Three versions of the chip are available, and they are: * + * TMS320C25 Internal ROM one time programmed at TI * + * TMS320E25 Internal ROM programmable as a normal EPROM * + * TMS320P25 Internal ROM programmable once as a normal EPROM only * + * These devices can also be used as a MicroController with external ROM * + * * + \***************************************************************************/ + +#pragma once + +#ifndef __TMS32025_H__ +#define __TMS32025_H__ + + + + +#define TMS32025_BIO 0x10000 /* BIO input */ +#define TMS32025_HOLD 0x10001 /* HOLD input */ +#define TMS32025_HOLDA 0x10001 /* HOLD Acknowledge output */ +#define TMS32025_XF 0x10002 /* XF output */ +#define TMS32025_DR 0x10003 /* Serial Data Receive input */ +#define TMS32025_DX 0x10003 /* Serial Data Transmit output */ + + + +/**************************************************************************** + * Interrupt constants + */ + +#define TMS32025_INT0 0 /* External INT0 */ +#define TMS32025_INT1 1 /* External INT1 */ +#define TMS32025_INT2 2 /* External INT2 */ +#define TMS32025_TINT 3 /* Internal Timer interrupt */ +#define TMS32025_RINT 4 /* Serial Port receive interrupt */ +#define TMS32025_XINT 5 /* Serial Port transmit interrupt */ +#define TMS32025_TRAP 6 /* Trap instruction */ +#define TMS32025_INT_NONE -1 + +/* Non-irq line */ +#define TMS32025_FSX 7 /* Frame synchronisation */ + +enum +{ + TMS32025_PC=1, + TMS32025_PFC, TMS32025_STR0, TMS32025_STR1, TMS32025_IFR, + TMS32025_RPTC, TMS32025_ACC, TMS32025_PREG, TMS32025_TREG, + TMS32025_AR0, TMS32025_AR1, TMS32025_AR2, TMS32025_AR3, + TMS32025_AR4, TMS32025_AR5, TMS32025_AR6, TMS32025_AR7, + TMS32025_STK0, TMS32025_STK1, TMS32025_STK2, TMS32025_STK3, + TMS32025_STK4, TMS32025_STK5, TMS32025_STK6, TMS32025_STK7, + TMS32025_DRR, TMS32025_DXR, TMS32025_TIM, TMS32025_PRD, + TMS32025_IMR, TMS32025_GREG +}; + + +/**************************************************************************** + * Public Functions + */ + + +class tms32025_device : public cpu_device +{ +public: + // construction/destruction + tms32025_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + tms32025_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_execute_interface overrides + virtual UINT32 execute_min_cycles() const { return 4; } + virtual UINT32 execute_max_cycles() const { return 20; } + virtual UINT32 execute_input_lines() const { return 6; } + virtual void execute_run(); + virtual void execute_set_input(int inputnum, int state); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const { return (spacenum == AS_PROGRAM) ? &m_program_config : ( (spacenum == AS_IO) ? &m_io_config : ( (spacenum == AS_DATA) ? &m_data_config : NULL ) ); } + virtual bool memory_read(address_spacenum spacenum, offs_t offset, int size, UINT64 &value); + virtual bool memory_write(address_spacenum spacenum, offs_t offset, int size, UINT64 value); + virtual bool memory_readop(offs_t offset, int size, UINT64 &value); + + // device_state_interface overrides + virtual void state_import(const device_state_entry &entry); + virtual void state_export(const device_state_entry &entry); + void state_string_export(const device_state_entry &entry, std::string &str); + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const { return 2; } + virtual UINT32 disasm_max_opcode_bytes() const { return 4; } + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + +private: + address_space_config m_program_config; + address_space_config m_data_config; + address_space_config m_io_config; + + typedef void ( tms32025_device::*opcode_func ) (); + struct tms32025_opcode + { + UINT8 cycles; + opcode_func function; + }; + static const tms32025_opcode s_opcode_main[256]; + static const tms32025_opcode s_opcode_CE_subset[256]; + static const tms32025_opcode s_opcode_Dx_subset[8]; + + + /******************** CPU Internal Registers *******************/ + UINT16 m_PREVPC; /* previous program counter */ + UINT16 m_PC; + UINT16 m_PFC; + UINT16 m_STR0, m_STR1; + UINT8 m_IFR; + UINT8 m_RPTC; + PAIR m_ACC; + PAIR m_Preg; + UINT16 m_Treg; + UINT16 m_AR[8]; + UINT16 m_STACK[8]; + PAIR m_ALU; +protected: + UINT16 m_intRAM[0x800]; +private: + UINT8 m_timerover; + + /********************** Status data ****************************/ + PAIR m_opcode; + int m_idle; + int m_hold; + int m_external_mem_access; /** required for hold mode. Implement it ! */ + int m_init_load_addr; /* 0=No, 1=Yes, 2=Once for repeat mode */ + int m_tms32025_irq_cycles; + int m_tms32025_dec_cycles; + + PAIR m_oldacc; + UINT32 m_memaccess; + int m_icount; + int m_mHackIgnoreARP; /* special handling for lst, lst1 instructions */ + int m_waiting_for_serial_frame; + + address_space *m_program; + direct_read_data *m_direct; + address_space *m_data; + address_space *m_io; + + UINT16 *m_pgmmap[0x200]; +protected: + UINT16 *m_datamap[0x200]; + +private: + UINT32 m_debugger_temp; + + inline void CLR0(UINT16 flag); + inline void SET0(UINT16 flag); + inline void CLR1(UINT16 flag); + inline void SET1(UINT16 flag); + inline void MODIFY_DP(int data); + inline void MODIFY_PM(int data); + inline void MODIFY_ARP(int data); + inline UINT16 M_RDROM(offs_t addr); + inline void M_WRTROM(offs_t addr, UINT16 data); + inline UINT16 M_RDRAM(offs_t addr); + inline void M_WRTRAM(offs_t addr, UINT16 data); + UINT16 reverse_carry_add(UINT16 arg0, UINT16 arg1 ); + inline void MODIFY_AR_ARP(); + inline void CALCULATE_ADD_CARRY(); + inline void CALCULATE_SUB_CARRY(); + inline void CALCULATE_ADD_OVERFLOW(INT32 addval); + inline void CALCULATE_SUB_OVERFLOW(INT32 subval); + inline UINT16 POP_STACK(); + inline void PUSH_STACK(UINT16 data); + inline void SHIFT_Preg_TO_ALU(); + inline void GETDATA(int shift,int signext); + inline void PUTDATA(UINT16 data); + inline void PUTDATA_SST(UINT16 data); + void opcodes_CE(); + void opcodes_Dx(); + void illegal(); + void abst(); + void add(); + void addc(); + void addh(); + void addk(); + void adds(); + void addt(); + void adlk(); + void adrk(); + void and_(); + void andk(); + void apac(); + void br(); + void bacc(); + void banz(); + void bbnz(); + void bbz(); + void bc(); + void bgez(); + void bgz(); + void bioz(); + void bit(); + void bitt(); + void blez(); + void blkd(); + void blkp(); + void blz(); + void bnc(); + void bnv(); + void bnz(); + void bv(); + void bz(); + void cala(); + void call(); + void cmpl(); + void cmpr(); + void cnfd(); + void cnfp(); + void conf(); + void dint(); + void dmov(); + void eint(); + void fort(); + void idle(); + void in(); + void lac(); + void lack(); + void lact(); + void lalk(); + void lar_ar0(); + void lar_ar1(); + void lar_ar2(); + void lar_ar3(); + void lar_ar4(); + void lar_ar5(); + void lar_ar6(); + void lar_ar7(); + void lark_ar0(); + void lark_ar1(); + void lark_ar2(); + void lark_ar3(); + void lark_ar4(); + void lark_ar5(); + void lark_ar6(); + void lark_ar7(); + void ldp(); + void ldpk(); + void lph(); + void lrlk(); + void lst(); + void lst1(); + void lt(); + void lta(); + void ltd(); + void ltp(); + void lts(); + void mac(); + void macd(); + void mar(); + void mpy(); + void mpya(); + void mpyk(); + void mpys(); + void mpyu(); + void neg(); + void nop(); + void norm(); + void or_(); + void ork(); + void out(); + void pac(); + void pop(); + void popd(); + void pshd(); + void push(); + void rc(); + void ret(); + void rfsm(); + void rhm(); + void rol(); + void ror(); + void rovm(); + void rpt(); + void rptk(); + void rsxm(); + void rtc(); + void rtxm(); + void rxf(); + void sach(); + void sacl(); + void sar_ar0(); + void sar_ar1(); + void sar_ar2(); + void sar_ar3(); + void sar_ar4(); + void sar_ar5(); + void sar_ar6(); + void sar_ar7(); + void sblk(); + void sbrk_ar(); + void sc(); + void sfl(); + void sfr(); + void sfsm(); + void shm(); + void sovm(); + void spac(); + void sph(); + void spl(); + void spm(); + void sqra(); + void sqrs(); + void sst(); + void sst1(); + void ssxm(); + void stc(); + void stxm(); + void sub(); + void subb(); + void subc(); + void subh(); + void subk(); + void subs(); + void subt(); + void sxf(); + void tblr(); + void tblw(); + void trap(); + void xor_(); + void xork(); + void zalh(); + void zalr(); + void zals(); + inline int process_IRQs(); + inline void process_timer(int clocks); + +}; + + +class tms32026_device : public tms32025_device +{ +public: + // construction/destruction + tms32026_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual void device_reset(); +}; + + +extern const device_type TMS32025; +extern const device_type TMS32026; + + +#endif /* __TMS32025_H__ */ diff --git a/src/devices/cpu/tms32031/32031ops.c b/src/devices/cpu/tms32031/32031ops.c new file mode 100644 index 00000000000..1475c5f8839 --- /dev/null +++ b/src/devices/cpu/tms32031/32031ops.c @@ -0,0 +1,6890 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + 32031ops.c + + TMS32031/2 emulator + +***************************************************************************/ + + +//************************************************************************** +// COMPILE-TIME OPTIONS +//************************************************************************** + +#define USE_FP 0 + + + +//************************************************************************** +// MACROS +//************************************************************************** + +#define IREG(rnum) (m_r[rnum].i32[0]) +#define FREGEXP(rnum) (m_r[rnum].exponent()) +#define FREGMAN(rnum) (m_r[rnum].mantissa()) + +#define FP2LONG(rnum) ((FREGEXP(rnum) << 24) | ((UINT32)FREGMAN(rnum) >> 8)) +#define LONG2FP(rnum,v) do { m_r[rnum].set_mantissa((v) << 8); m_r[rnum].set_exponent((INT32)(v) >> 24); } while (0) +#define SHORT2FP(rnum,v) do { \ + if ((UINT16)(v) == 0x8000) { m_r[rnum].set_mantissa(0); m_r[rnum].set_exponent(-128); } \ + else { m_r[rnum].set_mantissa((v) << 20); m_r[rnum].set_exponent((INT16)(v) >> 12); } \ + } while (0) + +#define DIRECT(op) (((IREG(TMR_DP) & 0xff) << 16) | ((UINT16)op)) +#define INDIRECT_D(op,o) ((this->*s_indirect_d[((o) >> 3) & 31])(op,o)) +#define INDIRECT_1(op,o) ((this->*s_indirect_1[((o) >> 3) & 31])(op,o)) +#define INDIRECT_1_DEF(op,o) ((this->*s_indirect_1_def[((o) >> 3) & 31])(op,o,defptr)) + +#define SIGN(val) ((val) & 0x80000000) + +#define OVERFLOW_SUB(a,b,r) ((INT32)(((a) ^ (b)) & ((a) ^ (r))) < 0) +#define OVERFLOW_ADD(a,b,r) ((INT32)(((a) ^ (r)) & ((b) ^ (r))) < 0) + +#define CLR_FLAGS(f) do { IREG(TMR_ST) &= ~(f); } while (0) +#define CLR_NVUF() CLR_FLAGS(NFLAG | VFLAG | UFFLAG) +#define CLR_NZVUF() CLR_FLAGS(NFLAG | ZFLAG | VFLAG | UFFLAG) +#define CLR_NZCVUF() CLR_FLAGS(NFLAG | ZFLAG | VFLAG | CFLAG | UFFLAG) + +#define OR_C(flag) do { IREG(TMR_ST) |= flag & CFLAG; } while (0) +#define OR_NZ(val) do { IREG(TMR_ST) |= (((val) >> 28) & NFLAG) | (((val) == 0) << 2); } while (0) +#define OR_NZF(reg) do { IREG(TMR_ST) |= ((reg.mantissa() >> 28) & NFLAG) | ((reg.exponent() == -128) << 2); } while (0) +#define OR_NUF(reg) do { int temp = (reg.exponent() == -128) << 4; IREG(TMR_ST) |= ((reg.mantissa() >> 28) & NFLAG) | (temp) | (temp << 2); } while (0) +#define OR_V_SUB(a,b,r) do { UINT32 temp = ((((a) ^ (b)) & ((a) ^ (r))) >> 30) & VFLAG; IREG(TMR_ST) |= temp | (temp << 4); } while (0) +#define OR_V_ADD(a,b,r) do { UINT32 temp = ((((a) ^ (r)) & ((b) ^ (r))) >> 30) & VFLAG; IREG(TMR_ST) |= temp | (temp << 4); } while (0) +#define OR_C_SUB(a,b,r) do { IREG(TMR_ST) |= ((UINT32)(b) > (UINT32)(a)); } while (0) +#define OR_C_ADD(a,b,r) do { IREG(TMR_ST) |= ((UINT32)(a) > (UINT32)(r)); } while (0) +#define OR_C_SBB(a,b,c) do { INT64 temp = (INT64)(a) - (UINT32)(b) - (UINT32)(c); IREG(TMR_ST) |= (temp < 0); } while (0) +#define OR_C_ADC(a,b,c) do { UINT64 temp = (UINT64)(a) + (UINT32)(b) + (UINT32)(c); IREG(TMR_ST) |= (temp > 0xffffffff); } while (0) + +#define OVM() (IREG(TMR_ST) & OVMFLAG) + +#define DECLARE_DEF UINT32 defval; UINT32 *defptr = &defval +#define UPDATE_DEF() *defptr = defval + + + +//************************************************************************** +// IMPLEMENTATION +//************************************************************************** + +void tms3203x_device::illegal(UINT32 op) +{ + if ((machine().debug_flags & DEBUG_FLAG_ENABLED) != 0) + { + logerror("Illegal op @ %06X: %08X (tbl=%03X)\n", m_pc - 1, op, op >> 21); + debugger_break(machine()); + } +} + + +void tms3203x_device::unimplemented(UINT32 op) +{ + fatalerror("Unimplemented op @ %06X: %08X (tbl=%03X)\n", m_pc - 1, op, op >> 21); +} + + +inline void tms3203x_device::execute_one() +{ + UINT32 op = ROPCODE(m_pc); + m_icount -= 2; // 2 clocks per cycle + m_pc++; +#if (TMS_3203X_LOG_OPCODE_USAGE) + m_hits[op >> 21]++; +#endif + (this->*s_tms32031ops[op >> 21])(op); +} + + +void tms3203x_device::update_special(int dreg) +{ + if (dreg == TMR_BK) + { + UINT32 temp = IREG(TMR_BK); + m_bkmask = temp; + while (temp >>= 1) + m_bkmask |= temp; + } + else if (dreg == TMR_IOF) + { + if (IREG(TMR_IOF) & 0x002) + m_xf0_cb((offs_t)0, (IREG(TMR_IOF) >> 2) & 1); + if (IREG(TMR_IOF) & 0x020) + m_xf1_cb((offs_t)0, (IREG(TMR_IOF) >> 6) & 1); + } + else if (dreg == TMR_ST || dreg == TMR_IF || dreg == TMR_IE) + check_irqs(); +} + + + +//************************************************************************** +// CONDITION CODES +//************************************************************************** + +const UINT32 C_LO = 1 << 1; +const UINT32 C_LS = 1 << 2; +const UINT32 C_HI = 1 << 3; +const UINT32 C_HS = 1 << 4; +const UINT32 C_EQ = 1 << 5; +const UINT32 C_NE = 1 << 6; +const UINT32 C_LT = 1 << 7; +const UINT32 C_LE = 1 << 8; +const UINT32 C_GT = 1 << 9; +const UINT32 C_GE = 1 << 10; +const UINT32 C_NV = 1 << 12; +const UINT32 C_V = 1 << 13; +const UINT32 C_NUF = 1 << 14; +const UINT32 C_UF = 1 << 15; +const UINT32 C_NLV = 1 << 16; +const UINT32 C_LV = 1 << 17; +const UINT32 C_NLUF = 1 << 18; +const UINT32 C_LUF = 1 << 19; +const UINT32 C_ZUF = 1 << 20; + +const UINT32 condition_table[0x80] = +{ +/* ------- */ 1 | C_HI | C_HS | C_NE | C_GT | C_GE | C_NV | C_NUF | C_NLV | C_NLUF, +/* ------C */ 1 | C_LO | C_LS | C_NE | C_GT | C_GE | C_NV | C_NUF | C_NLV | C_NLUF, +/* -----V- */ 1 | C_HI | C_HS | C_NE | C_GT | C_GE | C_V | C_NUF | C_NLV | C_NLUF, +/* -----VC */ 1 | C_LO | C_LS | C_NE | C_GT | C_GE | C_V | C_NUF | C_NLV | C_NLUF, +/* ----Z-- */ 1 | C_LS | C_HS | C_EQ | C_LE | C_GE | C_NV | C_NUF | C_NLV | C_NLUF | C_ZUF, +/* ----Z-C */ 1 | C_LO | C_LS | C_EQ | C_LE | C_GE | C_NV | C_NUF | C_NLV | C_NLUF | C_ZUF, +/* ----ZV- */ 1 | C_LS | C_HS | C_EQ | C_LE | C_GE | C_V | C_NUF | C_NLV | C_NLUF | C_ZUF, +/* ----ZVC */ 1 | C_LO | C_LS | C_EQ | C_LE | C_GE | C_V | C_NUF | C_NLV | C_NLUF | C_ZUF, +/* ---N--- */ 1 | C_HI | C_HS | C_NE | C_LT | C_LE | C_NV | C_NUF | C_NLV | C_NLUF, +/* ---N--C */ 1 | C_LO | C_LS | C_NE | C_LT | C_LE | C_NV | C_NUF | C_NLV | C_NLUF, +/* ---N-V- */ 1 | C_HI | C_HS | C_NE | C_LT | C_LE | C_V | C_NUF | C_NLV | C_NLUF, +/* ---N-VC */ 1 | C_LO | C_LS | C_NE | C_LT | C_LE | C_V | C_NUF | C_NLV | C_NLUF, +/* ---NZ-- */ 1 | C_LS | C_HS | C_EQ | C_LT | C_LE | C_NV | C_NUF | C_NLV | C_NLUF | C_ZUF, +/* ---NZ-C */ 1 | C_LO | C_LS | C_EQ | C_LT | C_LE | C_NV | C_NUF | C_NLV | C_NLUF | C_ZUF, +/* ---NZV- */ 1 | C_LS | C_HS | C_EQ | C_LT | C_LE | C_V | C_NUF | C_NLV | C_NLUF | C_ZUF, +/* ---NZVC */ 1 | C_LO | C_LS | C_EQ | C_LT | C_LE | C_V | C_NUF | C_NLV | C_NLUF | C_ZUF, +/* --U---- */ 1 | C_HI | C_HS | C_NE | C_GT | C_GE | C_NV | C_UF | C_NLV | C_NLUF | C_ZUF, +/* --U---C */ 1 | C_LO | C_LS | C_NE | C_GT | C_GE | C_NV | C_UF | C_NLV | C_NLUF | C_ZUF, +/* --U--V- */ 1 | C_HI | C_HS | C_NE | C_GT | C_GE | C_V | C_UF | C_NLV | C_NLUF | C_ZUF, +/* --U--VC */ 1 | C_LO | C_LS | C_NE | C_GT | C_GE | C_V | C_UF | C_NLV | C_NLUF | C_ZUF, +/* --U-Z-- */ 1 | C_LS | C_HS | C_EQ | C_LE | C_GE | C_NV | C_UF | C_NLV | C_NLUF | C_ZUF, +/* --U-Z-C */ 1 | C_LO | C_LS | C_EQ | C_LE | C_GE | C_NV | C_UF | C_NLV | C_NLUF | C_ZUF, +/* --U-ZV- */ 1 | C_LS | C_HS | C_EQ | C_LE | C_GE | C_V | C_UF | C_NLV | C_NLUF | C_ZUF, +/* --U-ZVC */ 1 | C_LO | C_LS | C_EQ | C_LE | C_GE | C_V | C_UF | C_NLV | C_NLUF | C_ZUF, +/* --UN--- */ 1 | C_HI | C_HS | C_NE | C_LT | C_LE | C_NV | C_UF | C_NLV | C_NLUF | C_ZUF, +/* --UN--C */ 1 | C_LO | C_LS | C_NE | C_LT | C_LE | C_NV | C_UF | C_NLV | C_NLUF | C_ZUF, +/* --UN-V- */ 1 | C_HI | C_HS | C_NE | C_LT | C_LE | C_V | C_UF | C_NLV | C_NLUF | C_ZUF, +/* --UN-VC */ 1 | C_LO | C_LS | C_NE | C_LT | C_LE | C_V | C_UF | C_NLV | C_NLUF | C_ZUF, +/* --UNZ-- */ 1 | C_LS | C_HS | C_EQ | C_LT | C_LE | C_NV | C_UF | C_NLV | C_NLUF | C_ZUF, +/* --UNZ-C */ 1 | C_LO | C_LS | C_EQ | C_LT | C_LE | C_NV | C_UF | C_NLV | C_NLUF | C_ZUF, +/* --UNZV- */ 1 | C_LS | C_HS | C_EQ | C_LT | C_LE | C_V | C_UF | C_NLV | C_NLUF | C_ZUF, +/* --UNZVC */ 1 | C_LO | C_LS | C_EQ | C_LT | C_LE | C_V | C_UF | C_NLV | C_NLUF | C_ZUF, +/* -v----- */ 1 | C_HI | C_HS | C_NE | C_GT | C_GE | C_NV | C_NUF | C_LV | C_NLUF, +/* -v----C */ 1 | C_LO | C_LS | C_NE | C_GT | C_GE | C_NV | C_NUF | C_LV | C_NLUF, +/* -v---V- */ 1 | C_HI | C_HS | C_NE | C_GT | C_GE | C_V | C_NUF | C_LV | C_NLUF, +/* -v---VC */ 1 | C_LO | C_LS | C_NE | C_GT | C_GE | C_V | C_NUF | C_LV | C_NLUF, +/* -v--Z-- */ 1 | C_LS | C_HS | C_EQ | C_LE | C_GE | C_NV | C_NUF | C_LV | C_NLUF | C_ZUF, +/* -v--Z-C */ 1 | C_LO | C_LS | C_EQ | C_LE | C_GE | C_NV | C_NUF | C_LV | C_NLUF | C_ZUF, +/* -v--ZV- */ 1 | C_LS | C_HS | C_EQ | C_LE | C_GE | C_V | C_NUF | C_LV | C_NLUF | C_ZUF, +/* -v--ZVC */ 1 | C_LO | C_LS | C_EQ | C_LE | C_GE | C_V | C_NUF | C_LV | C_NLUF | C_ZUF, +/* -v-N--- */ 1 | C_HI | C_HS | C_NE | C_LT | C_LE | C_NV | C_NUF | C_LV | C_NLUF, +/* -v-N--C */ 1 | C_LO | C_LS | C_NE | C_LT | C_LE | C_NV | C_NUF | C_LV | C_NLUF, +/* -v-N-V- */ 1 | C_HI | C_HS | C_NE | C_LT | C_LE | C_V | C_NUF | C_LV | C_NLUF, +/* -v-N-VC */ 1 | C_LO | C_LS | C_NE | C_LT | C_LE | C_V | C_NUF | C_LV | C_NLUF, +/* -v-NZ-- */ 1 | C_LS | C_HS | C_EQ | C_LT | C_LE | C_NV | C_NUF | C_LV | C_NLUF | C_ZUF, +/* -v-NZ-C */ 1 | C_LO | C_LS | C_EQ | C_LT | C_LE | C_NV | C_NUF | C_LV | C_NLUF | C_ZUF, +/* -v-NZV- */ 1 | C_LS | C_HS | C_EQ | C_LT | C_LE | C_V | C_NUF | C_LV | C_NLUF | C_ZUF, +/* -v-NZVC */ 1 | C_LO | C_LS | C_EQ | C_LT | C_LE | C_V | C_NUF | C_LV | C_NLUF | C_ZUF, +/* -vU---- */ 1 | C_HI | C_HS | C_NE | C_GT | C_GE | C_NV | C_UF | C_LV | C_NLUF | C_ZUF, +/* -vU---C */ 1 | C_LO | C_LS | C_NE | C_GT | C_GE | C_NV | C_UF | C_LV | C_NLUF | C_ZUF, +/* -vU--V- */ 1 | C_HI | C_HS | C_NE | C_GT | C_GE | C_V | C_UF | C_LV | C_NLUF | C_ZUF, +/* -vU--VC */ 1 | C_LO | C_LS | C_NE | C_GT | C_GE | C_V | C_UF | C_LV | C_NLUF | C_ZUF, +/* -vU-Z-- */ 1 | C_LS | C_HS | C_EQ | C_LE | C_GE | C_NV | C_UF | C_LV | C_NLUF | C_ZUF, +/* -vU-Z-C */ 1 | C_LO | C_LS | C_EQ | C_LE | C_GE | C_NV | C_UF | C_LV | C_NLUF | C_ZUF, +/* -vU-ZV- */ 1 | C_LS | C_HS | C_EQ | C_LE | C_GE | C_V | C_UF | C_LV | C_NLUF | C_ZUF, +/* -vU-ZVC */ 1 | C_LO | C_LS | C_EQ | C_LE | C_GE | C_V | C_UF | C_LV | C_NLUF | C_ZUF, +/* -vUN--- */ 1 | C_HI | C_HS | C_NE | C_LT | C_LE | C_NV | C_UF | C_LV | C_NLUF | C_ZUF, +/* -vUN--C */ 1 | C_LO | C_LS | C_NE | C_LT | C_LE | C_NV | C_UF | C_LV | C_NLUF | C_ZUF, +/* -vUN-V- */ 1 | C_HI | C_HS | C_NE | C_LT | C_LE | C_V | C_UF | C_LV | C_NLUF | C_ZUF, +/* -vUN-VC */ 1 | C_LO | C_LS | C_NE | C_LT | C_LE | C_V | C_UF | C_LV | C_NLUF | C_ZUF, +/* -vUNZ-- */ 1 | C_LS | C_HS | C_EQ | C_LT | C_LE | C_NV | C_UF | C_LV | C_NLUF | C_ZUF, +/* -vUNZ-C */ 1 | C_LO | C_LS | C_EQ | C_LT | C_LE | C_NV | C_UF | C_LV | C_NLUF | C_ZUF, +/* -vUNZV- */ 1 | C_LS | C_HS | C_EQ | C_LT | C_LE | C_V | C_UF | C_LV | C_NLUF | C_ZUF, +/* -vUNZVC */ 1 | C_LO | C_LS | C_EQ | C_LT | C_LE | C_V | C_UF | C_LV | C_NLUF | C_ZUF, +/* u------ */ 1 | C_HI | C_HS | C_NE | C_GT | C_GE | C_NV | C_NUF | C_NLV | C_LUF, +/* u-----C */ 1 | C_LO | C_LS | C_NE | C_GT | C_GE | C_NV | C_NUF | C_NLV | C_LUF, +/* u----V- */ 1 | C_HI | C_HS | C_NE | C_GT | C_GE | C_V | C_NUF | C_NLV | C_LUF, +/* u----VC */ 1 | C_LO | C_LS | C_NE | C_GT | C_GE | C_V | C_NUF | C_NLV | C_LUF, +/* u---Z-- */ 1 | C_LS | C_HS | C_EQ | C_LE | C_GE | C_NV | C_NUF | C_NLV | C_LUF | C_ZUF, +/* u---Z-C */ 1 | C_LO | C_LS | C_EQ | C_LE | C_GE | C_NV | C_NUF | C_NLV | C_LUF | C_ZUF, +/* u---ZV- */ 1 | C_LS | C_HS | C_EQ | C_LE | C_GE | C_V | C_NUF | C_NLV | C_LUF | C_ZUF, +/* u---ZVC */ 1 | C_LO | C_LS | C_EQ | C_LE | C_GE | C_V | C_NUF | C_NLV | C_LUF | C_ZUF, +/* u--N--- */ 1 | C_HI | C_HS | C_NE | C_LT | C_LE | C_NV | C_NUF | C_NLV | C_LUF, +/* u--N--C */ 1 | C_LO | C_LS | C_NE | C_LT | C_LE | C_NV | C_NUF | C_NLV | C_LUF, +/* u--N-V- */ 1 | C_HI | C_HS | C_NE | C_LT | C_LE | C_V | C_NUF | C_NLV | C_LUF, +/* u--N-VC */ 1 | C_LO | C_LS | C_NE | C_LT | C_LE | C_V | C_NUF | C_NLV | C_LUF, +/* u--NZ-- */ 1 | C_LS | C_HS | C_EQ | C_LT | C_LE | C_NV | C_NUF | C_NLV | C_LUF | C_ZUF, +/* u--NZ-C */ 1 | C_LO | C_LS | C_EQ | C_LT | C_LE | C_NV | C_NUF | C_NLV | C_LUF | C_ZUF, +/* u--NZV- */ 1 | C_LS | C_HS | C_EQ | C_LT | C_LE | C_V | C_NUF | C_NLV | C_LUF | C_ZUF, +/* u--NZVC */ 1 | C_LO | C_LS | C_EQ | C_LT | C_LE | C_V | C_NUF | C_NLV | C_LUF | C_ZUF, +/* u-U---- */ 1 | C_HI | C_HS | C_NE | C_GT | C_GE | C_NV | C_UF | C_NLV | C_LUF | C_ZUF, +/* u-U---C */ 1 | C_LO | C_LS | C_NE | C_GT | C_GE | C_NV | C_UF | C_NLV | C_LUF | C_ZUF, +/* u-U--V- */ 1 | C_HI | C_HS | C_NE | C_GT | C_GE | C_V | C_UF | C_NLV | C_LUF | C_ZUF, +/* u-U--VC */ 1 | C_LO | C_LS | C_NE | C_GT | C_GE | C_V | C_UF | C_NLV | C_LUF | C_ZUF, +/* u-U-Z-- */ 1 | C_LS | C_HS | C_EQ | C_LE | C_GE | C_NV | C_UF | C_NLV | C_LUF | C_ZUF, +/* u-U-Z-C */ 1 | C_LO | C_LS | C_EQ | C_LE | C_GE | C_NV | C_UF | C_NLV | C_LUF | C_ZUF, +/* u-U-ZV- */ 1 | C_LS | C_HS | C_EQ | C_LE | C_GE | C_V | C_UF | C_NLV | C_LUF | C_ZUF, +/* u-U-ZVC */ 1 | C_LO | C_LS | C_EQ | C_LE | C_GE | C_V | C_UF | C_NLV | C_LUF | C_ZUF, +/* u-UN--- */ 1 | C_HI | C_HS | C_NE | C_LT | C_LE | C_NV | C_UF | C_NLV | C_LUF | C_ZUF, +/* u-UN--C */ 1 | C_LO | C_LS | C_NE | C_LT | C_LE | C_NV | C_UF | C_NLV | C_LUF | C_ZUF, +/* u-UN-V- */ 1 | C_HI | C_HS | C_NE | C_LT | C_LE | C_V | C_UF | C_NLV | C_LUF | C_ZUF, +/* u-UN-VC */ 1 | C_LO | C_LS | C_NE | C_LT | C_LE | C_V | C_UF | C_NLV | C_LUF | C_ZUF, +/* u-UNZ-- */ 1 | C_LS | C_HS | C_EQ | C_LT | C_LE | C_NV | C_UF | C_NLV | C_LUF | C_ZUF, +/* u-UNZ-C */ 1 | C_LO | C_LS | C_EQ | C_LT | C_LE | C_NV | C_UF | C_NLV | C_LUF | C_ZUF, +/* u-UNZV- */ 1 | C_LS | C_HS | C_EQ | C_LT | C_LE | C_V | C_UF | C_NLV | C_LUF | C_ZUF, +/* u-UNZVC */ 1 | C_LO | C_LS | C_EQ | C_LT | C_LE | C_V | C_UF | C_NLV | C_LUF | C_ZUF, +/* uv----- */ 1 | C_HI | C_HS | C_NE | C_GT | C_GE | C_NV | C_NUF | C_LV | C_LUF, +/* uv----C */ 1 | C_LO | C_LS | C_NE | C_GT | C_GE | C_NV | C_NUF | C_LV | C_LUF, +/* uv---V- */ 1 | C_HI | C_HS | C_NE | C_GT | C_GE | C_V | C_NUF | C_LV | C_LUF, +/* uv---VC */ 1 | C_LO | C_LS | C_NE | C_GT | C_GE | C_V | C_NUF | C_LV | C_LUF, +/* uv--Z-- */ 1 | C_LS | C_HS | C_EQ | C_LE | C_GE | C_NV | C_NUF | C_LV | C_LUF | C_ZUF, +/* uv--Z-C */ 1 | C_LO | C_LS | C_EQ | C_LE | C_GE | C_NV | C_NUF | C_LV | C_LUF | C_ZUF, +/* uv--ZV- */ 1 | C_LS | C_HS | C_EQ | C_LE | C_GE | C_V | C_NUF | C_LV | C_LUF | C_ZUF, +/* uv--ZVC */ 1 | C_LO | C_LS | C_EQ | C_LE | C_GE | C_V | C_NUF | C_LV | C_LUF | C_ZUF, +/* uv-N--- */ 1 | C_HI | C_HS | C_NE | C_LT | C_LE | C_NV | C_NUF | C_LV | C_LUF, +/* uv-N--C */ 1 | C_LO | C_LS | C_NE | C_LT | C_LE | C_NV | C_NUF | C_LV | C_LUF, +/* uv-N-V- */ 1 | C_HI | C_HS | C_NE | C_LT | C_LE | C_V | C_NUF | C_LV | C_LUF, +/* uv-N-VC */ 1 | C_LO | C_LS | C_NE | C_LT | C_LE | C_V | C_NUF | C_LV | C_LUF, +/* uv-NZ-- */ 1 | C_LS | C_HS | C_EQ | C_LT | C_LE | C_NV | C_NUF | C_LV | C_LUF | C_ZUF, +/* uv-NZ-C */ 1 | C_LO | C_LS | C_EQ | C_LT | C_LE | C_NV | C_NUF | C_LV | C_LUF | C_ZUF, +/* uv-NZV- */ 1 | C_LS | C_HS | C_EQ | C_LT | C_LE | C_V | C_NUF | C_LV | C_LUF | C_ZUF, +/* uv-NZVC */ 1 | C_LO | C_LS | C_EQ | C_LT | C_LE | C_V | C_NUF | C_LV | C_LUF | C_ZUF, +/* uvU---- */ 1 | C_HI | C_HS | C_NE | C_GT | C_GE | C_NV | C_UF | C_LV | C_LUF | C_ZUF, +/* uvU---C */ 1 | C_LO | C_LS | C_NE | C_GT | C_GE | C_NV | C_UF | C_LV | C_LUF | C_ZUF, +/* uvU--V- */ 1 | C_HI | C_HS | C_NE | C_GT | C_GE | C_V | C_UF | C_LV | C_LUF | C_ZUF, +/* uvU--VC */ 1 | C_LO | C_LS | C_NE | C_GT | C_GE | C_V | C_UF | C_LV | C_LUF | C_ZUF, +/* uvU-Z-- */ 1 | C_LS | C_HS | C_EQ | C_LE | C_GE | C_NV | C_UF | C_LV | C_LUF | C_ZUF, +/* uvU-Z-C */ 1 | C_LO | C_LS | C_EQ | C_LE | C_GE | C_NV | C_UF | C_LV | C_LUF | C_ZUF, +/* uvU-ZV- */ 1 | C_LS | C_HS | C_EQ | C_LE | C_GE | C_V | C_UF | C_LV | C_LUF | C_ZUF, +/* uvU-ZVC */ 1 | C_LO | C_LS | C_EQ | C_LE | C_GE | C_V | C_UF | C_LV | C_LUF | C_ZUF, +/* uvUN--- */ 1 | C_HI | C_HS | C_NE | C_LT | C_LE | C_NV | C_UF | C_LV | C_LUF | C_ZUF, +/* uvUN--C */ 1 | C_LO | C_LS | C_NE | C_LT | C_LE | C_NV | C_UF | C_LV | C_LUF | C_ZUF, +/* uvUN-V- */ 1 | C_HI | C_HS | C_NE | C_LT | C_LE | C_V | C_UF | C_LV | C_LUF | C_ZUF, +/* uvUN-VC */ 1 | C_LO | C_LS | C_NE | C_LT | C_LE | C_V | C_UF | C_LV | C_LUF | C_ZUF, +/* uvUNZ-- */ 1 | C_LS | C_HS | C_EQ | C_LT | C_LE | C_NV | C_UF | C_LV | C_LUF | C_ZUF, +/* uvUNZ-C */ 1 | C_LO | C_LS | C_EQ | C_LT | C_LE | C_NV | C_UF | C_LV | C_LUF | C_ZUF, +/* uvUNZV- */ 1 | C_LS | C_HS | C_EQ | C_LT | C_LE | C_V | C_UF | C_LV | C_LUF | C_ZUF, +/* uvUNZVC */ 1 | C_LO | C_LS | C_EQ | C_LT | C_LE | C_V | C_UF | C_LV | C_LUF | C_ZUF, +}; + +#define CONDITION_LO() (IREG(TMR_ST) & CFLAG) +#define CONDITION_LS() (IREG(TMR_ST) & (CFLAG | ZFLAG)) +#define CONDITION_HI() (!(IREG(TMR_ST) & (CFLAG | ZFLAG))) +#define CONDITION_HS() (!(IREG(TMR_ST) & CFLAG)) +#define CONDITION_EQ() (IREG(TMR_ST) & ZFLAG) +#define CONDITION_NE() (!(IREG(TMR_ST) & ZFLAG)) +#define CONDITION_LT() (IREG(TMR_ST) & NFLAG) +#define CONDITION_LE() (IREG(TMR_ST) & (NFLAG | ZFLAG)) +#define CONDITION_GT() (!(IREG(TMR_ST) & (NFLAG | ZFLAG))) +#define CONDITION_GE() (!(IREG(TMR_ST) & NFLAG)) +#define CONDITION_NV() (!(IREG(TMR_ST) & VFLAG)) +#define CONDITION_V() (IREG(TMR_ST) & VFLAG) +#define CONDITION_NUF() (!(IREG(TMR_ST) & UFFLAG)) +#define CONDITION_UF() (IREG(TMR_ST) & UFFLAG) +#define CONDITION_NLV() (!(IREG(TMR_ST) & LVFLAG)) +#define CONDITION_LV() (IREG(TMR_ST) & LVFLAG) +#define CONDITION_NLUF() (!(IREG(TMR_ST) & LUFFLAG)) +#define CONDITION_LUF() (IREG(TMR_ST) & LUFFLAG) +#define CONDITION_ZUF() (IREG(TMR_ST) & (UFFLAG | ZFLAG)) + +inline bool tms3203x_device::condition(int which) +{ + return (condition_table[IREG(TMR_ST) & (LUFFLAG | LVFLAG | UFFLAG | NFLAG | ZFLAG | VFLAG | CFLAG)] >> (which & 31)) & 1; +} + + + +//************************************************************************** +// FLOATING POINT HELPERS +//************************************************************************** + +#if USE_FP +void tms3203x_device::double_to_dsp_with_flags(double val, tmsreg &result) +{ + int_double id; + id.d = val; + + CLR_NZVUF(); + + int mantissa = ((id.i[BYTE_XOR_BE(0)] & 0x000fffff) << 11) | ((id.i[BYTE_XOR_BE(1)] & 0xffe00000) >> 21); + int exponent = ((id.i[BYTE_XOR_BE(0)] & 0x7ff00000) >> 20) - 1023; + if (exponent <= -128) + { + result.set_mantissa(0); + result.set_exponent(-128); + IREG(TMR_ST) |= UFFLAG | LUFFLAG | ZFLAG; + } + else if (exponent > 127) + { + if ((INT32)id.i[BYTE_XOR_BE(0)] >= 0) + result.set_mantissa(0x7fffffff); + else + { + result.set_mantissa(0x80000001); + IREG(TMR_ST) |= NFLAG; + } + result.set_exponent(127); + IREG(TMR_ST) |= VFLAG | LVFLAG; + } + else if (val == 0) + { + result.set_mantissa(0); + result.set_exponent(-128); + IREG(TMR_ST) |= ZFLAG; + } + else if ((INT32)id.i[BYTE_XOR_BE(0)] >= 0) + { + result.set_mantissa(mantissa); + result.set_exponent(exponent); + } + else if (mantissa != 0) + { + result.set_mantissa(0x80000000 | -mantissa); + result.set_exponent(exponent); + IREG(TMR_ST) |= NFLAG; + } + else + { + result.set_mantissa(0x80000000); + result.set_exponent(exponent - 1); + IREG(TMR_ST) |= NFLAG; + } +} +#endif + +// integer to floating point conversion +#if USE_FP +void tms3203x_device::int2float(tmsreg &srcdst) +{ + double val = srcdst.mantissa(); + double_to_dsp_with_flags(val, srcdst); +} +#else +void tms3203x_device::int2float(tmsreg &srcdst) +{ + UINT32 man = srcdst.mantissa(); + int exp, cnt; + + // never overflows or underflows + CLR_NZVUF(); + + // 0 always has exponent of -128 + if (man == 0) + { + man = 0x80000000; + exp = -128; + } + + // check for -1 here because count_leading_ones will infinite loop + else if (man == (UINT32)-1) + { + man = 0; + exp = -1; + } + + // positive values; count leading zeros and shift + else if ((INT32)man > 0) + { + cnt = count_leading_zeros(man); + man <<= cnt; + exp = 31 - cnt; + } + + // negative values; count leading ones and shift + else + { + cnt = count_leading_ones(man); + man <<= cnt; + exp = 31 - cnt; + } + + // set the final results and compute NZ + srcdst.set_mantissa(man ^ 0x80000000); + srcdst.set_exponent(exp); + OR_NZF(srcdst); +} +#endif + + +// floating point to integer conversion +#if USE_FP +void tms3203x_device::float2int(tmsreg &srcdst, int setflags) +{ + INT32 val; + + if (setflags) CLR_NZVUF(); + if (srcdst.exponent() > 30) + { + if ((INT32)srcdst.mantissa() >= 0) + val = 0x7fffffff; + else + val = 0x80000000; + if (setflags) IREG(TMR_ST) |= VFLAG | LVFLAG; + } + else + val = floor(srcdst.as_double()); + srcdst.set_mantissa(val); + if (setflags) OR_NZ(val); +} +#else +void tms3203x_device::float2int(tmsreg &srcdst, bool setflags) +{ + INT32 man = srcdst.mantissa(); + int shift = 31 - srcdst.exponent(); + + // never underflows + if (setflags) CLR_NZVUF(); + + // if we've got too much to handle, overflow + if (shift <= 0) + { + srcdst.set_mantissa((man >= 0) ? 0x7fffffff : 0x80000000); + if (setflags) IREG(TMR_ST) |= VFLAG | LVFLAG; + } + + // if we're too small, go to 0 or -1 + else if (shift > 31) + srcdst.set_mantissa(man >> 31); + + // we're in the middle; shift it + else + srcdst.set_mantissa((man >> shift) ^ (1 << (31 - shift))); + + // set the NZ flags + if (setflags) OR_NZ(srcdst.mantissa()); +} +#endif + + +// compute the negative of a floating point value +#if USE_FP +void tms3203x_device::negf(tmsreg &dst, tmsreg tmsreg &src) +{ + double val = -src.as_double(); + double_to_dsp_with_flags(val, dst); +} +#else +void tms3203x_device::negf(tmsreg &dst, tmsreg &src) +{ + INT32 man = src.mantissa(); + + CLR_NZVUF(); + + if (src.exponent() == -128) + { + dst.set_mantissa(0); + dst.set_exponent(-128); + } + else if ((man & 0x7fffffff) != 0) + { + dst.set_mantissa(-man); + dst.set_exponent(src.exponent()); + } + else + { + dst.set_mantissa(man ^ 0x80000000); + if (man == 0) + dst.set_exponent(src.exponent() - 1); + else + dst.set_exponent(src.exponent() + 1); + } + OR_NZF(dst); +} +#endif + + + +// add two floating point values +#if USE_FP +void tms3203x_device::addf(tmsreg &dst, tmsreg &src1, tmsreg &src2) +{ + double val = src1.as_double() + src2.as_double(); + double_to_dsp_with_flags(val, dst); +} +#else +void tms3203x_device::addf(tmsreg &dst, tmsreg &src1, tmsreg &src2) +{ + INT64 man; + INT64 m1, m2; + int exp, cnt; + + // reset over/underflow conditions + CLR_NZVUF(); + + // first check for 0 operands + if (src1.exponent() == -128) + { + dst = src2; + OR_NZF(dst); + return; + } + if (src2.exponent() == -128) + { + dst = src1; + OR_NZF(dst); + return; + } + + // extract mantissas from 1.0.31 values to 1.1.31 values + m1 = (INT64)src1.mantissa() ^ 0x80000000; + m2 = (INT64)src2.mantissa() ^ 0x80000000; + + // normalize based on the exponent + if (src1.exponent() > src2.exponent()) + { + exp = src1.exponent(); + cnt = exp - src2.exponent(); + if (cnt >= 32) + { + dst = src1; + OR_NZF(dst); + return; + } + m2 >>= cnt; + } + else + { + exp = src2.exponent(); + cnt = exp - src1.exponent(); + if (cnt >= 32) + { + dst = src2; + OR_NZF(dst); + return; + } + m1 >>= cnt; + } + + // add + man = m1 + m2; + + // if the mantissa is zero, set the exponent appropriately + if (man == 0 || exp == -128) + { + exp = -128; + man = 0x80000000; + } + + // if the mantissa is >= 2.0 or < -2.0, normalize + else if (man >= ((INT64)2 << 31) || man < ((INT64)-2 << 31)) + { + man >>= 1; + exp++; + } + + // if the mantissa is < 1.0 and > -1.0, normalize + else if (man < ((INT64)1 << 31) && man >= ((INT64)-1 << 31)) + { + if (man > 0) + { + cnt = count_leading_zeros((UINT32)man); + man <<= cnt; + exp -= cnt; + } + else + { + cnt = count_leading_ones((UINT32)man); + man <<= cnt; + exp -= cnt; + } + } + + // check for underflow + if (exp <= -128) + { + man = 0x80000000; + exp = -128; + IREG(TMR_ST) |= UFFLAG | LUFFLAG; + } + + // check for overflow + else if (exp > 127) + { + man = (man < 0) ? 0x00000000 : 0xffffffff; + exp = 127; + IREG(TMR_ST) |= VFLAG | LVFLAG; + } + + // store the result back, removing the implicit one and putting + // back the sign bit + dst.set_mantissa((UINT32)man ^ 0x80000000); + dst.set_exponent(exp); + OR_NZF(dst); +} +#endif + + +// subtract two floating point values +#if USE_FP +void tms3203x_device::subf(tmsreg &dst, tmsreg &src1, tmsreg &src2) +{ + double val = src1.as_double() - src2.as_double(); + double_to_dsp_with_flags(val, dst); +} +#else +void tms3203x_device::subf(tmsreg &dst, tmsreg &src1, tmsreg &src2) +{ + INT64 man; + INT64 m1, m2; + int exp, cnt; + + // reset over/underflow conditions + CLR_NZVUF(); + + // first check for 0 operands + if (src2.exponent() == -128) + { + dst = src1; + OR_NZF(dst); + return; + } + + // extract mantissas from 1.0.31 values to 1.1.31 values + m1 = (INT64)src1.mantissa() ^ 0x80000000; + m2 = (INT64)src2.mantissa() ^ 0x80000000; + + // normalize based on the exponent + if (src1.exponent() > src2.exponent()) + { + exp = src1.exponent(); + cnt = exp - src2.exponent(); + if (cnt >= 32) + { + dst = src1; + OR_NZF(dst); + return; + } + m2 >>= cnt; + } + else + { + exp = src2.exponent(); + cnt = exp - src1.exponent(); + if (cnt >= 32) + { + negf(dst, src2); + return; + } + m1 >>= cnt; + } + + // subtract + man = m1 - m2; + + // if the mantissa is zero, set the exponent appropriately + if (man == 0 || exp == -128) + { + exp = -128; + man = 0x80000000; + } + + // if the mantissa is >= 2.0 or < -2.0, normalize + else if (man >= ((INT64)2 << 31) || man < ((INT64)-2 << 31)) + { + man >>= 1; + exp++; + } + + // if the mantissa is < 1.0 and > -1.0, normalize + else if (man < ((INT64)1 << 31) && man >= ((INT64)-1 << 31)) + { + if (man > 0) + { + cnt = count_leading_zeros((UINT32)man); + man <<= cnt; + exp -= cnt; + } + else + { + cnt = count_leading_ones((UINT32)man); + man <<= cnt; + exp -= cnt; + } + } + + // check for underflow + if (exp <= -128) + { + // make sure a 0 result doesn't set underflow + if (man != 0 || exp < -128) + IREG(TMR_ST) |= UFFLAG | LUFFLAG; + man = 0x80000000; + exp = -128; + } + + // check for overflow + else if (exp > 127) + { + man = (man < 0) ? 0x00000000 : 0xffffffff; + exp = 127; + IREG(TMR_ST) |= VFLAG | LVFLAG; + } + + // store the result back, removing the implicit one and putting + // back the sign bit + dst.set_mantissa((UINT32)man ^ 0x80000000); + dst.set_exponent(exp); + OR_NZF(dst); +} +#endif + + +// multiply two floating point values +#if USE_FP +void tms3203x_device::mpyf(tmsreg &dst, tmsreg &src1, tmsreg &src2) +{ + double val = (double)src1.as_float() * (double)src2.as_float(); + double_to_dsp_with_flags(val, dst); +} +#else +void tms3203x_device::mpyf(tmsreg &dst, tmsreg &src1, tmsreg &src2) +{ + // reset over/underflow conditions + CLR_NZVUF(); + + // first check for 0 multipliers and return 0 in any case + if (src1.exponent() == -128 || src2.exponent() == -128) + { + dst.set_mantissa(0); + dst.set_exponent(-128); + OR_NZF(dst); + return; + } + + // convert the mantissas from 1.0.31 numbers to 1.1.23 numbers + INT32 m1 = (src1.mantissa() >> 8) ^ 0x800000; + INT32 m2 = (src2.mantissa() >> 8) ^ 0x800000; + + // multiply the mantissas and add the exponents + INT64 man = (INT64)m1 * (INT64)m2; + int exp = src1.exponent() + src2.exponent(); + + // chop off the low bits, going from 1.2.46 down to 1.2.31 + man >>= 46 - 31; + + // if the mantissa is zero, set the exponent appropriately + if (man == 0) + { + exp = -128; + man = 0x80000000; + } + + // if the mantissa is >= 2.0 or <= -2.0, normalize + else if (man >= ((INT64)2 << 31)) + { + man >>= 1; + exp++; + if (man >= ((INT64)2 << 31)) + { + man >>= 1; + exp++; + } + } + + // if the mantissa is >= 2.0 or <= -2.0, normalize + else if (man < ((INT64)-2 << 31)) + { + man >>= 1; + exp++; + } + + // check for underflow + if (exp <= -128) + { + man = 0x80000000; + exp = -128; + IREG(TMR_ST) |= UFFLAG | LUFFLAG; + } + + // check for overflow + else if (exp > 127) + { + man = (man < 0) ? 0x00000000 : 0xffffffff; + exp = 127; + IREG(TMR_ST) |= VFLAG | LVFLAG; + } + + // store the result back, removing the implicit one and putting + // back the sign bit + dst.set_mantissa((UINT32)man ^ 0x80000000); + dst.set_exponent(exp); + OR_NZF(dst); +} +#endif + + +// normalize a floating point value +#if USE_FP +void tms3203x_device::norm(tmsreg &dst, tmsreg &src) +{ + fatalerror("norm not implemented\n"); +} +#else +void tms3203x_device::norm(tmsreg &dst, tmsreg &src) +{ + INT32 man = src.mantissa(); + int exp = src.exponent(); + + CLR_NZVUF(); + + if (exp == -128 || man == 0) + { + dst.set_mantissa(0); + dst.set_exponent(-128); + if (man != 0) + IREG(TMR_ST) |= UFFLAG | LUFFLAG; + } + else + { + int cnt; + if (man > 0) + { + cnt = count_leading_zeros((UINT32)man); + man <<= cnt; + exp -= cnt; + } + else + { + cnt = count_leading_ones((UINT32)man); + man <<= cnt; + exp -= cnt; + } + + // check for underflow + if (exp <= -128) + { + man = 0x00000000; + exp = -128; + IREG(TMR_ST) |= UFFLAG | LUFFLAG; + } + } + + dst.set_mantissa(man); + dst.set_exponent(exp); + OR_NZF(dst); +} +#endif + + + + +//************************************************************************** +// INDIRECT MEMORY REFS +//************************************************************************** + +// immediate displacement variants + +UINT32 tms3203x_device::mod00_d(UINT32 op, UINT8 ar) +{ + int reg = TMR_AR0 + (ar & 7); + return IREG(reg) + (UINT8)op; +} + +UINT32 tms3203x_device::mod01_d(UINT32 op, UINT8 ar) +{ + int reg = TMR_AR0 + (ar & 7); + return IREG(reg) - (UINT8)op; +} + +UINT32 tms3203x_device::mod02_d(UINT32 op, UINT8 ar) +{ + int reg = TMR_AR0 + (ar & 7); + IREG(reg) += (UINT8)op; + return IREG(reg); +} + +UINT32 tms3203x_device::mod03_d(UINT32 op, UINT8 ar) +{ + int reg = TMR_AR0 + (ar & 7); + IREG(reg) -= (UINT8)op; + return IREG(reg); +} + +UINT32 tms3203x_device::mod04_d(UINT32 op, UINT8 ar) +{ + int reg = TMR_AR0 + (ar & 7); + UINT32 result = IREG(reg); + IREG(reg) += (UINT8)op; + return result; +} + +UINT32 tms3203x_device::mod05_d(UINT32 op, UINT8 ar) +{ + int reg = TMR_AR0 + (ar & 7); + UINT32 result = IREG(reg); + IREG(reg) -= (UINT8)op; + return result; +} + +UINT32 tms3203x_device::mod06_d(UINT32 op, UINT8 ar) +{ + int reg = TMR_AR0 + (ar & 7); + UINT32 result = IREG(reg); + INT32 temp = (result & m_bkmask) + (UINT8)op; + if (temp >= IREG(TMR_BK)) + temp -= IREG(TMR_BK); + IREG(reg) = (IREG(reg) & ~m_bkmask) | (temp & m_bkmask); + return result; +} + +UINT32 tms3203x_device::mod07_d(UINT32 op, UINT8 ar) +{ + int reg = TMR_AR0 + (ar & 7); + UINT32 result = IREG(reg); + INT32 temp = (result & m_bkmask) - (UINT8)op; + if (temp < 0) + temp += IREG(TMR_BK); + IREG(reg) = (IREG(reg) & ~m_bkmask) | (temp & m_bkmask); + return result; +} + + +// immediate displacement variants (implied 1) + +UINT32 tms3203x_device::mod00_1(UINT32 op, UINT8 ar) +{ + int reg = TMR_AR0 + (ar & 7); + return IREG(reg) + 1; +} + +UINT32 tms3203x_device::mod01_1(UINT32 op, UINT8 ar) +{ + int reg = TMR_AR0 + (ar & 7); + return IREG(reg) - 1; +} + +UINT32 tms3203x_device::mod02_1(UINT32 op, UINT8 ar) +{ + int reg = TMR_AR0 + (ar & 7); + return ++IREG(reg); +} + +UINT32 tms3203x_device::mod03_1(UINT32 op, UINT8 ar) +{ + int reg = TMR_AR0 + (ar & 7); + return --IREG(reg); +} + +UINT32 tms3203x_device::mod04_1(UINT32 op, UINT8 ar) +{ + int reg = TMR_AR0 + (ar & 7); + return IREG(reg)++; +} + +UINT32 tms3203x_device::mod05_1(UINT32 op, UINT8 ar) +{ + int reg = TMR_AR0 + (ar & 7); + return IREG(reg)--; +} + +UINT32 tms3203x_device::mod06_1(UINT32 op, UINT8 ar) +{ + int reg = TMR_AR0 + (ar & 7); + UINT32 result = IREG(reg); + INT32 temp = (result & m_bkmask) + 1; + if (temp >= IREG(TMR_BK)) + temp -= IREG(TMR_BK); + IREG(reg) = (IREG(reg) & ~m_bkmask) | (temp & m_bkmask); + return result; +} + +UINT32 tms3203x_device::mod07_1(UINT32 op, UINT8 ar) +{ + int reg = TMR_AR0 + (ar & 7); + UINT32 result = IREG(reg); + INT32 temp = (result & m_bkmask) - 1; + if (temp < 0) + temp += IREG(TMR_BK); + IREG(reg) = (IREG(reg) & ~m_bkmask) | (temp & m_bkmask); + return result; +} + + +// IR0 displacement variants + +UINT32 tms3203x_device::mod08(UINT32 op, UINT8 ar) +{ + int reg = TMR_AR0 + (ar & 7); + return IREG(reg) + IREG(TMR_IR0); +} + +UINT32 tms3203x_device::mod09(UINT32 op, UINT8 ar) +{ + int reg = TMR_AR0 + (ar & 7); + return IREG(reg) - IREG(TMR_IR0); +} + +UINT32 tms3203x_device::mod0a(UINT32 op, UINT8 ar) +{ + int reg = TMR_AR0 + (ar & 7); + IREG(reg) += IREG(TMR_IR0); + return IREG(reg); +} + +UINT32 tms3203x_device::mod0b(UINT32 op, UINT8 ar) +{ + int reg = TMR_AR0 + (ar & 7); + IREG(reg) -= IREG(TMR_IR0); + return IREG(reg); +} + +UINT32 tms3203x_device::mod0c(UINT32 op, UINT8 ar) +{ + int reg = TMR_AR0 + (ar & 7); + UINT32 result = IREG(reg); + IREG(reg) += IREG(TMR_IR0); + return result; +} + +UINT32 tms3203x_device::mod0d(UINT32 op, UINT8 ar) +{ + int reg = TMR_AR0 + (ar & 7); + UINT32 result = IREG(reg); + IREG(reg) -= IREG(TMR_IR0); + return result; +} + +UINT32 tms3203x_device::mod0e(UINT32 op, UINT8 ar) +{ + int reg = TMR_AR0 + (ar & 7); + UINT32 result = IREG(reg); + INT32 temp = (result & m_bkmask) + IREG(TMR_IR0); + if (temp >= IREG(TMR_BK)) + temp -= IREG(TMR_BK); + IREG(reg) = (IREG(reg) & ~m_bkmask) | (temp & m_bkmask); + return result; +} + +UINT32 tms3203x_device::mod0f(UINT32 op, UINT8 ar) +{ + int reg = TMR_AR0 + (ar & 7); + UINT32 result = IREG(reg); + INT32 temp = (result & m_bkmask) - IREG(TMR_IR0); + if (temp < 0) + temp += IREG(TMR_BK); + IREG(reg) = (IREG(reg) & ~m_bkmask) | (temp & m_bkmask); + return result; +} + + +// IR1 displacement variants + +UINT32 tms3203x_device::mod10(UINT32 op, UINT8 ar) +{ + int reg = TMR_AR0 + (ar & 7); + return IREG(reg) + IREG(TMR_IR1); +} + +UINT32 tms3203x_device::mod11(UINT32 op, UINT8 ar) +{ + int reg = TMR_AR0 + (ar & 7); + return IREG(reg) - IREG(TMR_IR1); +} + +UINT32 tms3203x_device::mod12(UINT32 op, UINT8 ar) +{ + int reg = TMR_AR0 + (ar & 7); + IREG(reg) += IREG(TMR_IR1); + return IREG(reg); +} + +UINT32 tms3203x_device::mod13(UINT32 op, UINT8 ar) +{ + int reg = TMR_AR0 + (ar & 7); + IREG(reg) -= IREG(TMR_IR1); + return IREG(reg); +} + +UINT32 tms3203x_device::mod14(UINT32 op, UINT8 ar) +{ + int reg = TMR_AR0 + (ar & 7); + UINT32 result = IREG(reg); + IREG(reg) += IREG(TMR_IR1); + return result; +} + +UINT32 tms3203x_device::mod15(UINT32 op, UINT8 ar) +{ + int reg = TMR_AR0 + (ar & 7); + UINT32 result = IREG(reg); + IREG(reg) -= IREG(TMR_IR1); + return result; +} + +UINT32 tms3203x_device::mod16(UINT32 op, UINT8 ar) +{ + int reg = TMR_AR0 + (ar & 7); + UINT32 result = IREG(reg); + INT32 temp = (result & m_bkmask) + IREG(TMR_IR1); + if (temp >= IREG(TMR_BK)) + temp -= IREG(TMR_BK); + IREG(reg) = (IREG(reg) & ~m_bkmask) | (temp & m_bkmask); + return result; +} + +UINT32 tms3203x_device::mod17(UINT32 op, UINT8 ar) +{ + int reg = TMR_AR0 + (ar & 7); + UINT32 result = IREG(reg); + INT32 temp = (result & m_bkmask) - IREG(TMR_IR1); + if (temp < 0) + temp += IREG(TMR_BK); + IREG(reg) = (IREG(reg) & ~m_bkmask) | (temp & m_bkmask); + return result; +} + + +// special variants + +UINT32 tms3203x_device::mod18(UINT32 op, UINT8 ar) +{ + int reg = TMR_AR0 + (ar & 7); + return IREG(reg); +} + +UINT32 tms3203x_device::mod19(UINT32 op, UINT8 ar) +{ + unimplemented(op); + return 0; +} + +UINT32 tms3203x_device::modillegal(UINT32 op, UINT8 ar) +{ + illegal(op); + return 0; +} + + +// immediate displacement variants (implied 1) + +UINT32 tms3203x_device::mod00_1_def(UINT32 op, UINT8 ar, UINT32 *&defptrptr) +{ + int reg = TMR_AR0 + (ar & 7); + return IREG(reg) + 1; +} + +UINT32 tms3203x_device::mod01_1_def(UINT32 op, UINT8 ar, UINT32 *&defptrptr) +{ + int reg = TMR_AR0 + (ar & 7); + return IREG(reg) - 1; +} + +UINT32 tms3203x_device::mod02_1_def(UINT32 op, UINT8 ar, UINT32 *&defptrptr) +{ + int reg = TMR_AR0 + (ar & 7); + UINT32 defval = IREG(reg) + 1; + *defptrptr = defval; + defptrptr = &IREG(reg); + return defval; +} + +UINT32 tms3203x_device::mod03_1_def(UINT32 op, UINT8 ar, UINT32 *&defptrptr) +{ + int reg = TMR_AR0 + (ar & 7); + UINT32 defval = IREG(reg) - 1; + *defptrptr = defval; + defptrptr = &IREG(reg); + return defval; +} + +UINT32 tms3203x_device::mod04_1_def(UINT32 op, UINT8 ar, UINT32 *&defptrptr) +{ + int reg = TMR_AR0 + (ar & 7); + *defptrptr = IREG(reg) + 1; + defptrptr = &IREG(reg); + return IREG(reg); +} + +UINT32 tms3203x_device::mod05_1_def(UINT32 op, UINT8 ar, UINT32 *&defptrptr) +{ + int reg = TMR_AR0 + (ar & 7); + *defptrptr = IREG(reg) - 1; + defptrptr = &IREG(reg); + return IREG(reg); +} + +UINT32 tms3203x_device::mod06_1_def(UINT32 op, UINT8 ar, UINT32 *&defptrptr) +{ + int reg = TMR_AR0 + (ar & 7); + UINT32 result = IREG(reg); + INT32 temp = (result & m_bkmask) + 1; + if (temp >= IREG(TMR_BK)) + temp -= IREG(TMR_BK); + *defptrptr = (IREG(reg) & ~m_bkmask) | (temp & m_bkmask); + defptrptr = &IREG(reg); + return result; +} + +UINT32 tms3203x_device::mod07_1_def(UINT32 op, UINT8 ar, UINT32 *&defptrptr) +{ + int reg = TMR_AR0 + (ar & 7); + UINT32 result = IREG(reg); + INT32 temp = (result & m_bkmask) - 1; + if (temp < 0) + temp += IREG(TMR_BK); + *defptrptr = (IREG(reg) & ~m_bkmask) | (temp & m_bkmask); + defptrptr = &IREG(reg); + return result; +} + + +// IR0 displacement variants + +UINT32 tms3203x_device::mod08_def(UINT32 op, UINT8 ar, UINT32 *&defptrptr) +{ + int reg = TMR_AR0 + (ar & 7); + return IREG(reg) + IREG(TMR_IR0); +} + +UINT32 tms3203x_device::mod09_def(UINT32 op, UINT8 ar, UINT32 *&defptrptr) +{ + int reg = TMR_AR0 + (ar & 7); + return IREG(reg) - IREG(TMR_IR0); +} + +UINT32 tms3203x_device::mod0a_def(UINT32 op, UINT8 ar, UINT32 *&defptrptr) +{ + int reg = TMR_AR0 + (ar & 7); + UINT32 defval = IREG(reg) + IREG(TMR_IR0); + *defptrptr = defval; + defptrptr = &IREG(reg); + return defval; +} + +UINT32 tms3203x_device::mod0b_def(UINT32 op, UINT8 ar, UINT32 *&defptrptr) +{ + int reg = TMR_AR0 + (ar & 7); + UINT32 defval = IREG(reg) - IREG(TMR_IR0); + *defptrptr = defval; + defptrptr = &IREG(reg); + return defval; +} + +UINT32 tms3203x_device::mod0c_def(UINT32 op, UINT8 ar, UINT32 *&defptrptr) +{ + int reg = TMR_AR0 + (ar & 7); + *defptrptr = IREG(reg) + IREG(TMR_IR0); + defptrptr = &IREG(reg); + return IREG(reg); +} + +UINT32 tms3203x_device::mod0d_def(UINT32 op, UINT8 ar, UINT32 *&defptrptr) +{ + int reg = TMR_AR0 + (ar & 7); + *defptrptr = IREG(reg) - IREG(TMR_IR0); + defptrptr = &IREG(reg); + return IREG(reg); +} + +UINT32 tms3203x_device::mod0e_def(UINT32 op, UINT8 ar, UINT32 *&defptrptr) +{ + int reg = TMR_AR0 + (ar & 7); + UINT32 result = IREG(reg); + INT32 temp = (result & m_bkmask) + IREG(TMR_IR0); + if (temp >= IREG(TMR_BK)) + temp -= IREG(TMR_BK); + *defptrptr = (IREG(reg) & ~m_bkmask) | (temp & m_bkmask); + defptrptr = &IREG(reg); + return result; +} + +UINT32 tms3203x_device::mod0f_def(UINT32 op, UINT8 ar, UINT32 *&defptrptr) +{ + int reg = TMR_AR0 + (ar & 7); + UINT32 result = IREG(reg); + INT32 temp = (result & m_bkmask) - IREG(TMR_IR0); + if (temp < 0) + temp += IREG(TMR_BK); + *defptrptr = (IREG(reg) & ~m_bkmask) | (temp & m_bkmask); + defptrptr = &IREG(reg); + return result; +} + + +// IR1 displacement variants + +UINT32 tms3203x_device::mod10_def(UINT32 op, UINT8 ar, UINT32 *&defptrptr) +{ + int reg = TMR_AR0 + (ar & 7); + return IREG(reg) + IREG(TMR_IR1); +} + +UINT32 tms3203x_device::mod11_def(UINT32 op, UINT8 ar, UINT32 *&defptrptr) +{ + int reg = TMR_AR0 + (ar & 7); + return IREG(reg) - IREG(TMR_IR1); +} + +UINT32 tms3203x_device::mod12_def(UINT32 op, UINT8 ar, UINT32 *&defptrptr) +{ + int reg = TMR_AR0 + (ar & 7); + UINT32 defval = IREG(reg) + IREG(TMR_IR1); + *defptrptr = defval; + defptrptr = &IREG(reg); + return defval; +} + +UINT32 tms3203x_device::mod13_def(UINT32 op, UINT8 ar, UINT32 *&defptrptr) +{ + int reg = TMR_AR0 + (ar & 7); + UINT32 defval = IREG(reg) - IREG(TMR_IR1); + *defptrptr = defval; + defptrptr = &IREG(reg); + return defval; +} + +UINT32 tms3203x_device::mod14_def(UINT32 op, UINT8 ar, UINT32 *&defptrptr) +{ + int reg = TMR_AR0 + (ar & 7); + *defptrptr = IREG(reg) + IREG(TMR_IR1); + defptrptr = &IREG(reg); + return IREG(reg); +} + +UINT32 tms3203x_device::mod15_def(UINT32 op, UINT8 ar, UINT32 *&defptrptr) +{ + int reg = TMR_AR0 + (ar & 7); + *defptrptr = IREG(reg) - IREG(TMR_IR1); + defptrptr = &IREG(reg); + return IREG(reg); +} + +UINT32 tms3203x_device::mod16_def(UINT32 op, UINT8 ar, UINT32 *&defptrptr) +{ + int reg = TMR_AR0 + (ar & 7); + UINT32 result = IREG(reg); + INT32 temp = (result & m_bkmask) + IREG(TMR_IR1); + if (temp >= IREG(TMR_BK)) + temp -= IREG(TMR_BK); + *defptrptr = (IREG(reg) & ~m_bkmask) | (temp & m_bkmask); + defptrptr = &IREG(reg); + return result; +} + +UINT32 tms3203x_device::mod17_def(UINT32 op, UINT8 ar, UINT32 *&defptrptr) +{ + int reg = TMR_AR0 + (ar & 7); + UINT32 result = IREG(reg); + INT32 temp = (result & m_bkmask) - IREG(TMR_IR1); + if (temp < 0) + temp += IREG(TMR_BK); + *defptrptr = (IREG(reg) & ~m_bkmask) | (temp & m_bkmask); + defptrptr = &IREG(reg); + return result; +} + +UINT32 tms3203x_device::mod18_def(UINT32 op, UINT8 ar, UINT32 *&defptrptr) +{ + int reg = TMR_AR0 + (ar & 7); + return IREG(reg); +} + +UINT32 tms3203x_device::mod19_def(UINT32 op, UINT8 ar, UINT32 *&defptrptr) +{ + unimplemented(op); + return 0; +} + +UINT32 tms3203x_device::modillegal_def(UINT32 op, UINT8 ar, UINT32 *&defptrptr) +{ + illegal(op); + return 0; +} + + +/*-----------------------------------------------------*/ + +#define ABSF(dreg, sreg) \ +{ \ + INT32 man = FREGMAN(sreg); \ + CLR_NZVUF(); \ + m_r[dreg] = m_r[sreg]; \ + if (man < 0) \ + { \ + m_r[dreg].set_mantissa(~man); \ + if (man == (INT32)0x80000000 && FREGEXP(sreg) == 127) \ + IREG(TMR_ST) |= VFLAG | LVFLAG; \ + } \ + OR_NZF(m_r[dreg]); \ +} + +void tms3203x_device::absf_reg(UINT32 op) +{ + int dreg = (op >> 16) & 7; + int sreg = op & 7; + ABSF(dreg, sreg); +} + +void tms3203x_device::absf_dir(UINT32 op) +{ + UINT32 res = RMEM(DIRECT(op)); + int dreg = (op >> 16) & 7; + LONG2FP(TMR_TEMP1, res); + ABSF(dreg, TMR_TEMP1); +} + +void tms3203x_device::absf_ind(UINT32 op) +{ + UINT32 res = RMEM(INDIRECT_D(op, op >> 8)); + int dreg = (op >> 16) & 7; + LONG2FP(TMR_TEMP1, res); + ABSF(dreg, TMR_TEMP1); +} + +void tms3203x_device::absf_imm(UINT32 op) +{ + int dreg = (op >> 16) & 7; + SHORT2FP(TMR_TEMP1, op); + ABSF(dreg, TMR_TEMP1); +} + +/*-----------------------------------------------------*/ + +#define ABSI(dreg, src) \ +{ \ + UINT32 _res = ((INT32)src < 0) ? -src : src; \ + if (!OVM() || _res != 0x80000000) \ + IREG(dreg) = _res; \ + else \ + IREG(dreg) = 0x7fffffff; \ + if (dreg < 8) \ + { \ + CLR_NZVUF(); \ + OR_NZ(_res); \ + if (_res == 0x80000000) \ + IREG(TMR_ST) |= VFLAG | LVFLAG; \ + } \ + else if (dreg >= TMR_BK) \ + update_special(dreg); \ +} + +void tms3203x_device::absi_reg(UINT32 op) +{ + UINT32 src = IREG(op & 31); + int dreg = (op >> 16) & 31; + ABSI(dreg, src); +} + +void tms3203x_device::absi_dir(UINT32 op) +{ + UINT32 src = RMEM(DIRECT(op)); + int dreg = (op >> 16) & 31; + ABSI(dreg, src); +} + +void tms3203x_device::absi_ind(UINT32 op) +{ + UINT32 src = RMEM(INDIRECT_D(op, op >> 8)); + int dreg = (op >> 16) & 31; + ABSI(dreg, src); +} + +void tms3203x_device::absi_imm(UINT32 op) +{ + UINT32 src = (INT16)op; + int dreg = (op >> 16) & 31; + ABSI(dreg, src); +} + +/*-----------------------------------------------------*/ + +#define ADDC(dreg, src1, src2) \ +{ \ + UINT32 _res = src1 + src2 + (IREG(TMR_ST) & CFLAG); \ + if (!OVM() || !OVERFLOW_ADD(src1,src2,_res)) \ + IREG(dreg) = _res; \ + else \ + IREG(dreg) = ((INT32)src1 < 0) ? 0x80000000 : 0x7fffffff; \ + if (dreg < 8) \ + { \ + UINT32 tempc = IREG(TMR_ST) & CFLAG; \ + CLR_NZCVUF(); \ + OR_C_ADC(src1,src2,tempc); \ + OR_V_ADD(src1,src2,_res); \ + OR_NZ(_res); \ + } \ + else if (dreg >= TMR_BK) \ + update_special(dreg); \ +} + +void tms3203x_device::addc_reg(UINT32 op) +{ + UINT32 src = IREG(op & 31); + int dreg = (op >> 16) & 31; + UINT32 dst = IREG(dreg); + ADDC(dreg, dst, src); +} + +void tms3203x_device::addc_dir(UINT32 op) +{ + UINT32 src = RMEM(DIRECT(op)); + int dreg = (op >> 16) & 31; + UINT32 dst = IREG(dreg); + ADDC(dreg, dst, src); +} + +void tms3203x_device::addc_ind(UINT32 op) +{ + UINT32 src = RMEM(INDIRECT_D(op, op >> 8)); + int dreg = (op >> 16) & 31; + UINT32 dst = IREG(dreg); + ADDC(dreg, dst, src); +} + +void tms3203x_device::addc_imm(UINT32 op) +{ + UINT32 src = (INT16)op; + int dreg = (op >> 16) & 31; + UINT32 dst = IREG(dreg); + ADDC(dreg, dst, src); +} + +/*-----------------------------------------------------*/ + +void tms3203x_device::addf_reg(UINT32 op) +{ + int dreg = (op >> 16) & 7; + addf(m_r[dreg], m_r[dreg], m_r[op & 7]); +} + +void tms3203x_device::addf_dir(UINT32 op) +{ + UINT32 res = RMEM(DIRECT(op)); + int dreg = (op >> 16) & 7; + LONG2FP(TMR_TEMP1, res); + addf(m_r[dreg], m_r[dreg], m_r[TMR_TEMP1]); +} + +void tms3203x_device::addf_ind(UINT32 op) +{ + UINT32 res = RMEM(INDIRECT_D(op, op >> 8)); + int dreg = (op >> 16) & 7; + LONG2FP(TMR_TEMP1, res); + addf(m_r[dreg], m_r[dreg], m_r[TMR_TEMP1]); +} + +void tms3203x_device::addf_imm(UINT32 op) +{ + int dreg = (op >> 16) & 7; + SHORT2FP(TMR_TEMP1, op); + addf(m_r[dreg], m_r[dreg], m_r[TMR_TEMP1]); +} + +/*-----------------------------------------------------*/ + +#define ADDI(dreg, src1, src2) \ +{ \ + UINT32 _res = src1 + src2; \ + if (!OVM() || !OVERFLOW_ADD(src1,src2,_res)) \ + IREG(dreg) = _res; \ + else \ + IREG(dreg) = ((INT32)src1 < 0) ? 0x80000000 : 0x7fffffff; \ + if (dreg < 8) \ + { \ + CLR_NZCVUF(); \ + OR_C_ADD(src1,src2,_res); \ + OR_V_ADD(src1,src2,_res); \ + OR_NZ(_res); \ + } \ + else if (dreg >= TMR_BK) \ + update_special(dreg); \ +} + +void tms3203x_device::addi_reg(UINT32 op) +{ + UINT32 src = IREG(op & 31); + int dreg = (op >> 16) & 31; + UINT32 dst = IREG(dreg); + ADDI(dreg, dst, src); +} + +void tms3203x_device::addi_dir(UINT32 op) +{ + UINT32 src = RMEM(DIRECT(op)); + int dreg = (op >> 16) & 31; + UINT32 dst = IREG(dreg); + ADDI(dreg, dst, src); +} + +void tms3203x_device::addi_ind(UINT32 op) +{ + UINT32 src = RMEM(INDIRECT_D(op, op >> 8)); + int dreg = (op >> 16) & 31; + UINT32 dst = IREG(dreg); + ADDI(dreg, dst, src); +} + +void tms3203x_device::addi_imm(UINT32 op) +{ + UINT32 src = (INT16)op; + int dreg = (op >> 16) & 31; + UINT32 dst = IREG(dreg); + ADDI(dreg, dst, src); +} + +/*-----------------------------------------------------*/ + +#define AND(dreg, src1, src2) \ +{ \ + UINT32 _res = (src1) & (src2); \ + IREG(dreg) = _res; \ + if (dreg < 8) \ + { \ + CLR_NZVUF(); \ + OR_NZ(_res); \ + } \ + else if (dreg >= TMR_BK) \ + update_special(dreg); \ +} + +void tms3203x_device::and_reg(UINT32 op) +{ + UINT32 src = IREG(op & 31); + int dreg = (op >> 16) & 31; + UINT32 dst = IREG(dreg); + AND(dreg, dst, src); +} + +void tms3203x_device::and_dir(UINT32 op) +{ + UINT32 src = RMEM(DIRECT(op)); + int dreg = (op >> 16) & 31; + UINT32 dst = IREG(dreg); + AND(dreg, dst, src); +} + +void tms3203x_device::and_ind(UINT32 op) +{ + UINT32 src = RMEM(INDIRECT_D(op, op >> 8)); + int dreg = (op >> 16) & 31; + UINT32 dst = IREG(dreg); + AND(dreg, dst, src); +} + +void tms3203x_device::and_imm(UINT32 op) +{ + UINT32 src = (UINT16)op; + int dreg = (op >> 16) & 31; + UINT32 dst = IREG(dreg); + AND(dreg, dst, src); +} + +/*-----------------------------------------------------*/ + +#define ANDN(dreg, src1, src2) \ +{ \ + UINT32 _res = (src1) & ~(src2); \ + IREG(dreg) = _res; \ + if (dreg < 8) \ + { \ + CLR_NZVUF(); \ + OR_NZ(_res); \ + } \ + else if (dreg >= TMR_BK) \ + update_special(dreg); \ +} + +void tms3203x_device::andn_reg(UINT32 op) +{ + UINT32 src = IREG(op & 31); + int dreg = (op >> 16) & 31; + UINT32 dst = IREG(dreg); + ANDN(dreg, dst, src); +} + +void tms3203x_device::andn_dir(UINT32 op) +{ + UINT32 src = RMEM(DIRECT(op)); + int dreg = (op >> 16) & 31; + UINT32 dst = IREG(dreg); + ANDN(dreg, dst, src); +} + +void tms3203x_device::andn_ind(UINT32 op) +{ + UINT32 src = RMEM(INDIRECT_D(op, op >> 8)); + int dreg = (op >> 16) & 31; + UINT32 dst = IREG(dreg); + ANDN(dreg, dst, src); +} + +void tms3203x_device::andn_imm(UINT32 op) +{ + UINT32 src = (UINT16)op; + int dreg = (op >> 16) & 31; + UINT32 dst = IREG(dreg); + ANDN(dreg, dst, src); +} + +/*-----------------------------------------------------*/ + +#define ASH(dreg, src, count) \ +{ \ + UINT32 _res; \ + INT32 _count = (INT16)(count << 9) >> 9; /* 7 LSBs */ \ + if (_count < 0) \ + { \ + if (_count >= -31) \ + _res = (INT32)src >> -_count; \ + else \ + _res = (INT32)src >> 31; \ + } \ + else \ + { \ + if (_count <= 31) \ + _res = (INT32)src << _count; \ + else \ + _res = 0; \ + } \ + IREG(dreg) = _res; \ + if (dreg < 8) \ + { \ + CLR_NZCVUF(); \ + OR_NZ(_res); \ + if (_count < 0) \ + { \ + if (_count >= -32) \ + OR_C(((INT32)src >> (-_count - 1)) & 1); \ + else \ + OR_C(((INT32)src >> 31) & 1); \ + } \ + else if (_count > 0) \ + { \ + if (_count <= 32) \ + OR_C(((UINT32)src << (_count - 1)) >> 31); \ + } \ + } \ + else if (dreg >= TMR_BK) \ + update_special(dreg); \ +} + +void tms3203x_device::ash_reg(UINT32 op) +{ + int dreg = (op >> 16) & 31; + int count = IREG(op & 31); + UINT32 src = IREG(dreg); + ASH(dreg, src, count); +} + +void tms3203x_device::ash_dir(UINT32 op) +{ + int dreg = (op >> 16) & 31; + int count = RMEM(DIRECT(op)); + UINT32 src = IREG(dreg); + ASH(dreg, src, count); +} + +void tms3203x_device::ash_ind(UINT32 op) +{ + int dreg = (op >> 16) & 31; + int count = RMEM(INDIRECT_D(op, op >> 8)); + UINT32 src = IREG(dreg); + ASH(dreg, src, count); +} + +void tms3203x_device::ash_imm(UINT32 op) +{ + int dreg = (op >> 16) & 31; + int count = op; + UINT32 src = IREG(dreg); + ASH(dreg, src, count); +} + +/*-----------------------------------------------------*/ + +void tms3203x_device::cmpf_reg(UINT32 op) +{ + int dreg = (op >> 16) & 7; + subf(m_r[TMR_TEMP2], m_r[dreg], m_r[op & 7]); +} + +void tms3203x_device::cmpf_dir(UINT32 op) +{ + UINT32 res = RMEM(DIRECT(op)); + int dreg = (op >> 16) & 7; + LONG2FP(TMR_TEMP1, res); + subf(m_r[TMR_TEMP2], m_r[dreg], m_r[TMR_TEMP1]); +} + +void tms3203x_device::cmpf_ind(UINT32 op) +{ + UINT32 res = RMEM(INDIRECT_D(op, op >> 8)); + int dreg = (op >> 16) & 7; + LONG2FP(TMR_TEMP1, res); + subf(m_r[TMR_TEMP2], m_r[dreg], m_r[TMR_TEMP1]); +} + +void tms3203x_device::cmpf_imm(UINT32 op) +{ + int dreg = (op >> 16) & 7; + SHORT2FP(TMR_TEMP1, op); + subf(m_r[TMR_TEMP2], m_r[dreg], m_r[TMR_TEMP1]); +} + +/*-----------------------------------------------------*/ + +#define CMPI(src1, src2) \ +{ \ + UINT32 _res = src1 - src2; \ + CLR_NZCVUF(); \ + OR_C_SUB(src1,src2,_res); \ + OR_V_SUB(src1,src2,_res); \ + OR_NZ(_res); \ +} + +void tms3203x_device::cmpi_reg(UINT32 op) +{ + UINT32 src = IREG(op & 31); + UINT32 dst = IREG((op >> 16) & 31); + CMPI(dst, src); +} + +void tms3203x_device::cmpi_dir(UINT32 op) +{ + UINT32 src = RMEM(DIRECT(op)); + UINT32 dst = IREG((op >> 16) & 31); + CMPI(dst, src); +} + +void tms3203x_device::cmpi_ind(UINT32 op) +{ + UINT32 src = RMEM(INDIRECT_D(op, op >> 8)); + UINT32 dst = IREG((op >> 16) & 31); + CMPI(dst, src); +} + +void tms3203x_device::cmpi_imm(UINT32 op) +{ + UINT32 src = (INT16)op; + UINT32 dst = IREG((op >> 16) & 31); + CMPI(dst, src); +} + +/*-----------------------------------------------------*/ + +void tms3203x_device::fix_reg(UINT32 op) +{ + int dreg = (op >> 16) & 31; + m_r[TMR_TEMP1] = m_r[op & 7]; + float2int(m_r[TMR_TEMP1], dreg < 8); + m_r[dreg].set_mantissa(m_r[TMR_TEMP1].mantissa()); +} + +void tms3203x_device::fix_dir(UINT32 op) +{ + UINT32 res = RMEM(DIRECT(op)); + int dreg = (op >> 16) & 31; + LONG2FP(TMR_TEMP1, res); + float2int(m_r[TMR_TEMP1], dreg < 8); + m_r[dreg].set_mantissa(m_r[TMR_TEMP1].mantissa()); +} + +void tms3203x_device::fix_ind(UINT32 op) +{ + UINT32 res = RMEM(INDIRECT_D(op, op >> 8)); + int dreg = (op >> 16) & 31; + LONG2FP(TMR_TEMP1, res); + float2int(m_r[TMR_TEMP1], dreg < 8); + m_r[dreg].set_mantissa(m_r[TMR_TEMP1].mantissa()); +} + +void tms3203x_device::fix_imm(UINT32 op) +{ + int dreg = (op >> 16) & 31; + SHORT2FP(TMR_TEMP1, op); + float2int(m_r[TMR_TEMP1], dreg < 8); + m_r[dreg].set_mantissa(m_r[TMR_TEMP1].mantissa()); +} + +/*-----------------------------------------------------*/ + +#define FLOAT(dreg, src) \ +{ \ + IREG(dreg) = src; \ + int2float(m_r[dreg]); \ +} + +void tms3203x_device::float_reg(UINT32 op) +{ + UINT32 src = IREG(op & 31); + int dreg = (op >> 16) & 7; + FLOAT(dreg, src); +} + +void tms3203x_device::float_dir(UINT32 op) +{ + UINT32 src = RMEM(DIRECT(op)); + int dreg = (op >> 16) & 7; + FLOAT(dreg, src); +} + +void tms3203x_device::float_ind(UINT32 op) +{ + UINT32 src = RMEM(INDIRECT_D(op, op >> 8)); + int dreg = (op >> 16) & 7; + FLOAT(dreg, src); +} + +void tms3203x_device::float_imm(UINT32 op) +{ + UINT32 src = (INT16)op; + int dreg = (op >> 16) & 7; + FLOAT(dreg, src); +} + +/*-----------------------------------------------------*/ + +void tms3203x_device::idle(UINT32 op) +{ + m_is_idling = true; + IREG(TMR_ST) |= GIEFLAG; + check_irqs(); + if (m_is_idling) + m_icount = 0; +} + +/*-----------------------------------------------------*/ + +void tms3203x_device::lde_reg(UINT32 op) +{ + int dreg = (op >> 16) & 7; + m_r[dreg].set_exponent(m_r[op & 7].exponent()); + if (m_r[dreg].exponent() == -128) + m_r[dreg].set_mantissa(0); +} + +void tms3203x_device::lde_dir(UINT32 op) +{ + UINT32 res = RMEM(DIRECT(op)); + int dreg = (op >> 16) & 7; + LONG2FP(TMR_TEMP1, res); + m_r[dreg].set_exponent(m_r[TMR_TEMP1].exponent()); + if (m_r[dreg].exponent() == -128) + m_r[dreg].set_mantissa(0); +} + +void tms3203x_device::lde_ind(UINT32 op) +{ + UINT32 res = RMEM(INDIRECT_D(op, op >> 8)); + int dreg = (op >> 16) & 7; + LONG2FP(TMR_TEMP1, res); + m_r[dreg].set_exponent(m_r[TMR_TEMP1].exponent()); + if (m_r[dreg].exponent() == -128) + m_r[dreg].set_mantissa(0); +} + +void tms3203x_device::lde_imm(UINT32 op) +{ + int dreg = (op >> 16) & 7; + SHORT2FP(TMR_TEMP1, op); + m_r[dreg].set_exponent(m_r[TMR_TEMP1].exponent()); + if (m_r[dreg].exponent() == -128) + m_r[dreg].set_mantissa(0); +} + +/*-----------------------------------------------------*/ + +void tms3203x_device::ldf_reg(UINT32 op) +{ + int dreg = (op >> 16) & 7; + m_r[dreg] = m_r[op & 7]; + CLR_NZVUF(); + OR_NZF(m_r[dreg]); +} + +void tms3203x_device::ldf_dir(UINT32 op) +{ + UINT32 res = RMEM(DIRECT(op)); + int dreg = (op >> 16) & 7; + LONG2FP(dreg, res); + CLR_NZVUF(); + OR_NZF(m_r[dreg]); +} + +void tms3203x_device::ldf_ind(UINT32 op) +{ + UINT32 res = RMEM(INDIRECT_D(op, op >> 8)); + int dreg = (op >> 16) & 7; + LONG2FP(dreg, res); + CLR_NZVUF(); + OR_NZF(m_r[dreg]); +} + +void tms3203x_device::ldf_imm(UINT32 op) +{ + int dreg = (op >> 16) & 7; + SHORT2FP(dreg, op); + CLR_NZVUF(); + OR_NZF(m_r[dreg]); +} + +/*-----------------------------------------------------*/ + +void tms3203x_device::ldfi_dir(UINT32 op) { unimplemented(op); } +void tms3203x_device::ldfi_ind(UINT32 op) { unimplemented(op); } + +/*-----------------------------------------------------*/ + +#define LDI(dreg, src) \ +{ \ + IREG(dreg) = src; \ + if (dreg < 8) \ + { \ + CLR_NZVUF(); \ + OR_NZ(src); \ + } \ + else if (dreg >= TMR_BK) \ + update_special(dreg); \ +} + +void tms3203x_device::ldi_reg(UINT32 op) +{ + UINT32 src = IREG(op & 31); + int dreg = (op >> 16) & 31; + LDI(dreg, src); +} + +void tms3203x_device::ldi_dir(UINT32 op) +{ + UINT32 src = RMEM(DIRECT(op)); + int dreg = (op >> 16) & 31; + LDI(dreg, src); +} + +void tms3203x_device::ldi_ind(UINT32 op) +{ + UINT32 src = RMEM(INDIRECT_D(op, op >> 8)); + int dreg = (op >> 16) & 31; + LDI(dreg, src); +} + +void tms3203x_device::ldi_imm(UINT32 op) +{ + UINT32 src = (INT16)op; + int dreg = (op >> 16) & 31; + LDI(dreg, src); +} + +/*-----------------------------------------------------*/ + +void tms3203x_device::ldii_dir(UINT32 op) { unimplemented(op); } +void tms3203x_device::ldii_ind(UINT32 op) { unimplemented(op); } + +/*-----------------------------------------------------*/ + +void tms3203x_device::ldm_reg(UINT32 op) +{ + int dreg = (op >> 16) & 7; + m_r[dreg].set_mantissa(m_r[op & 7].mantissa()); +} + +void tms3203x_device::ldm_dir(UINT32 op) +{ + UINT32 res = RMEM(DIRECT(op)); + int dreg = (op >> 16) & 7; + m_r[dreg].set_mantissa(res); +} + +void tms3203x_device::ldm_ind(UINT32 op) +{ + UINT32 res = RMEM(INDIRECT_D(op, op >> 8)); + int dreg = (op >> 16) & 7; + m_r[dreg].set_mantissa(res); +} + +void tms3203x_device::ldm_imm(UINT32 op) +{ + int dreg = (op >> 16) & 7; + SHORT2FP(TMR_TEMP1, op); + m_r[dreg].set_mantissa(m_r[TMR_TEMP1].mantissa()); +} + +/*-----------------------------------------------------*/ + +#define LSH(dreg, src, count) \ +{ \ + UINT32 _res; \ + INT32 _count = (INT16)(count << 9) >> 9; /* 7 LSBs */ \ + if (_count < 0) \ + { \ + if (_count >= -31) \ + _res = (UINT32)src >> -_count; \ + else \ + _res = 0; \ + } \ + else \ + { \ + if (_count <= 31) \ + _res = (UINT32)src << _count; \ + else \ + _res = 0; \ + } \ + IREG(dreg) = _res; \ + if (dreg < 8) \ + { \ + CLR_NZCVUF(); \ + OR_NZ(_res); \ + if (_count < 0) \ + { \ + if (_count >= -32) \ + OR_C(((UINT32)src >> (-_count - 1)) & 1); \ + } \ + else if (_count > 0) \ + { \ + if (_count <= 32) \ + OR_C(((UINT32)src << (_count - 1)) >> 31); \ + } \ + } \ + else if (dreg >= TMR_BK) \ + update_special(dreg); \ +} + +void tms3203x_device::lsh_reg(UINT32 op) +{ + int dreg = (op >> 16) & 31; + int count = IREG(op & 31); + UINT32 src = IREG(dreg); + LSH(dreg, src, count); +} + +void tms3203x_device::lsh_dir(UINT32 op) +{ + int dreg = (op >> 16) & 31; + int count = RMEM(DIRECT(op)); + UINT32 src = IREG(dreg); + LSH(dreg, src, count); +} + +void tms3203x_device::lsh_ind(UINT32 op) +{ + int dreg = (op >> 16) & 31; + int count = RMEM(INDIRECT_D(op, op >> 8)); + UINT32 src = IREG(dreg); + LSH(dreg, src, count); +} + +void tms3203x_device::lsh_imm(UINT32 op) +{ + int dreg = (op >> 16) & 31; + int count = op; + UINT32 src = IREG(dreg); + LSH(dreg, src, count); +} + +/*-----------------------------------------------------*/ + +void tms3203x_device::mpyf_reg(UINT32 op) +{ + int dreg = (op >> 16) & 31; + mpyf(m_r[dreg], m_r[dreg], m_r[op & 31]); +} + +void tms3203x_device::mpyf_dir(UINT32 op) +{ + UINT32 res = RMEM(DIRECT(op)); + int dreg = (op >> 16) & 31; + LONG2FP(TMR_TEMP1, res); + mpyf(m_r[dreg], m_r[dreg], m_r[TMR_TEMP1]); +} + +void tms3203x_device::mpyf_ind(UINT32 op) +{ + UINT32 res = RMEM(INDIRECT_D(op, op >> 8)); + int dreg = (op >> 16) & 31; + LONG2FP(TMR_TEMP1, res); + mpyf(m_r[dreg], m_r[dreg], m_r[TMR_TEMP1]); +} + +void tms3203x_device::mpyf_imm(UINT32 op) +{ + int dreg = (op >> 16) & 31; + SHORT2FP(TMR_TEMP1, op); + mpyf(m_r[dreg], m_r[dreg], m_r[TMR_TEMP1]); +} + +/*-----------------------------------------------------*/ + +#define MPYI(dreg, src1, src2) \ +{ \ + INT64 _res = (INT64)((INT32)(src1 << 8) >> 8) * (INT64)((INT32)(src2 << 8) >> 8);\ + if (!OVM() || (_res >= -(INT64)0x80000000 && _res <= (INT64)0x7fffffff)) \ + IREG(dreg) = _res; \ + else \ + IREG(dreg) = (_res < 0) ? 0x80000000 : 0x7fffffff; \ + if (dreg < 8) \ + { \ + CLR_NZVUF(); \ + OR_NZ((UINT32)_res); \ + if (_res < -(INT64)0x80000000 || _res > (INT64)0x7fffffff) \ + IREG(TMR_ST) |= VFLAG | LVFLAG; \ + } \ + else if (dreg >= TMR_BK) \ + update_special(dreg); \ +} + +void tms3203x_device::mpyi_reg(UINT32 op) +{ + UINT32 src = IREG(op & 31); + int dreg = (op >> 16) & 31; + UINT32 dst = IREG(dreg); + MPYI(dreg, dst, src); +} + +void tms3203x_device::mpyi_dir(UINT32 op) +{ + UINT32 src = RMEM(DIRECT(op)); + int dreg = (op >> 16) & 31; + UINT32 dst = IREG(dreg); + MPYI(dreg, dst, src); +} + +void tms3203x_device::mpyi_ind(UINT32 op) +{ + UINT32 src = RMEM(INDIRECT_D(op, op >> 8)); + int dreg = (op >> 16) & 31; + UINT32 dst = IREG(dreg); + MPYI(dreg, dst, src); +} + +void tms3203x_device::mpyi_imm(UINT32 op) +{ + UINT32 src = (INT16)op; + int dreg = (op >> 16) & 31; + UINT32 dst = IREG(dreg); + MPYI(dreg, dst, src); +} + +/*-----------------------------------------------------*/ + +#define NEGB(dreg, src) \ +{ \ + UINT32 _res = 0 - src - (IREG(TMR_ST) & CFLAG); \ + if (!OVM() || !OVERFLOW_SUB(0,src,_res)) \ + IREG(dreg) = _res; \ + else \ + IREG(dreg) = ((INT32)src < 0) ? 0x80000000 : 0x7fffffff; \ + if (dreg < 8) \ + { \ + UINT32 tempc = IREG(TMR_ST) & CFLAG; \ + CLR_NZCVUF(); \ + OR_C_SBB(0,src,tempc); \ + OR_V_SUB(0,src,_res); \ + OR_NZ(_res); \ + } \ + else if (dreg >= TMR_BK) \ + update_special(dreg); \ +} + +void tms3203x_device::negb_reg(UINT32 op) +{ + UINT32 src = IREG(op & 31); + int dreg = (op >> 16) & 31; + NEGB(dreg, src); +} + +void tms3203x_device::negb_dir(UINT32 op) +{ + UINT32 src = RMEM(DIRECT(op)); + int dreg = (op >> 16) & 31; + NEGB(dreg, src); +} + +void tms3203x_device::negb_ind(UINT32 op) +{ + UINT32 src = RMEM(INDIRECT_D(op, op >> 8)); + int dreg = (op >> 16) & 31; + NEGB(dreg, src); +} + +void tms3203x_device::negb_imm(UINT32 op) +{ + UINT32 src = (INT16)op; + int dreg = (op >> 16) & 31; + NEGB(dreg, src); +} + +/*-----------------------------------------------------*/ + +void tms3203x_device::negf_reg(UINT32 op) +{ + int dreg = (op >> 16) & 7; + negf(m_r[dreg], m_r[op & 7]); +} + +void tms3203x_device::negf_dir(UINT32 op) +{ + UINT32 res = RMEM(DIRECT(op)); + int dreg = (op >> 16) & 7; + LONG2FP(TMR_TEMP1, res); + negf(m_r[dreg], m_r[TMR_TEMP1]); +} + +void tms3203x_device::negf_ind(UINT32 op) +{ + UINT32 res = RMEM(INDIRECT_D(op, op >> 8)); + int dreg = (op >> 16) & 7; + LONG2FP(TMR_TEMP1, res); + negf(m_r[dreg], m_r[TMR_TEMP1]); +} + +void tms3203x_device::negf_imm(UINT32 op) +{ + int dreg = (op >> 16) & 7; + SHORT2FP(TMR_TEMP1, op); + negf(m_r[dreg], m_r[TMR_TEMP1]); +} + +/*-----------------------------------------------------*/ + +#define NEGI(dreg, src) \ +{ \ + UINT32 _res = 0 - src; \ + if (!OVM() || !OVERFLOW_SUB(0,src,_res)) \ + IREG(dreg) = _res; \ + else \ + IREG(dreg) = ((INT32)src < 0) ? 0x80000000 : 0x7fffffff; \ + if (dreg < 8) \ + { \ + CLR_NZCVUF(); \ + OR_C_SUB(0,src,_res); \ + OR_V_SUB(0,src,_res); \ + OR_NZ(_res); \ + } \ + else if (dreg >= TMR_BK) \ + update_special(dreg); \ +} + +void tms3203x_device::negi_reg(UINT32 op) +{ + UINT32 src = IREG(op & 31); + int dreg = (op >> 16) & 31; + NEGI(dreg, src); +} + +void tms3203x_device::negi_dir(UINT32 op) +{ + UINT32 src = RMEM(DIRECT(op)); + int dreg = (op >> 16) & 31; + NEGI(dreg, src); +} + +void tms3203x_device::negi_ind(UINT32 op) +{ + UINT32 src = RMEM(INDIRECT_D(op, op >> 8)); + int dreg = (op >> 16) & 31; + NEGI(dreg, src); +} + +void tms3203x_device::negi_imm(UINT32 op) +{ + UINT32 src = (INT16)op; + int dreg = (op >> 16) & 31; + NEGI(dreg, src); +} + +/*-----------------------------------------------------*/ + +void tms3203x_device::nop_reg(UINT32 op) +{ +} + +void tms3203x_device::nop_ind(UINT32 op) +{ + RMEM(INDIRECT_D(op, op >> 8)); +} + +/*-----------------------------------------------------*/ + +void tms3203x_device::norm_reg(UINT32 op) +{ + int dreg = (op >> 16) & 7; + norm(m_r[dreg], m_r[op & 7]); +} + +void tms3203x_device::norm_dir(UINT32 op) +{ + UINT32 res = RMEM(DIRECT(op)); + int dreg = (op >> 16) & 7; + LONG2FP(TMR_TEMP1, res); + norm(m_r[dreg], m_r[TMR_TEMP1]); +} + +void tms3203x_device::norm_ind(UINT32 op) +{ + UINT32 res = RMEM(INDIRECT_D(op, op >> 8)); + int dreg = (op >> 16) & 7; + LONG2FP(TMR_TEMP1, res); + norm(m_r[dreg], m_r[TMR_TEMP1]); +} + +void tms3203x_device::norm_imm(UINT32 op) +{ + int dreg = (op >> 16) & 7; + SHORT2FP(TMR_TEMP1, op); + norm(m_r[dreg], m_r[TMR_TEMP1]); +} + +/*-----------------------------------------------------*/ + +#define NOT(dreg, src) \ +{ \ + UINT32 _res = ~(src); \ + IREG(dreg) = _res; \ + if (dreg < 8) \ + { \ + CLR_NZVUF(); \ + OR_NZ(_res); \ + } \ + else if (dreg >= TMR_BK) \ + update_special(dreg); \ +} + +void tms3203x_device::not_reg(UINT32 op) +{ + UINT32 src = IREG(op & 31); + int dreg = (op >> 16) & 31; + NOT(dreg, src); +} + +void tms3203x_device::not_dir(UINT32 op) +{ + UINT32 src = RMEM(DIRECT(op)); + int dreg = (op >> 16) & 31; + NOT(dreg, src); +} + +void tms3203x_device::not_ind(UINT32 op) +{ + UINT32 src = RMEM(INDIRECT_D(op, op >> 8)); + int dreg = (op >> 16) & 31; + NOT(dreg, src); +} + +void tms3203x_device::not_imm(UINT32 op) +{ + UINT32 src = (UINT16)op; + int dreg = (op >> 16) & 31; + NOT(dreg, src); +} + +/*-----------------------------------------------------*/ + +void tms3203x_device::pop(UINT32 op) +{ + int dreg = (op >> 16) & 31; + UINT32 val = RMEM(IREG(TMR_SP)--); + IREG(dreg) = val; + if (dreg < 8) + { + CLR_NZVUF(); + OR_NZ(val); + } + else if (dreg >= TMR_BK) + update_special(dreg); +} + +void tms3203x_device::popf(UINT32 op) +{ + int dreg = (op >> 16) & 7; + UINT32 val = RMEM(IREG(TMR_SP)--); + LONG2FP(dreg, val); + CLR_NZVUF(); + OR_NZF(m_r[dreg]); +} + +void tms3203x_device::push(UINT32 op) +{ + WMEM(++IREG(TMR_SP), IREG((op >> 16) & 31)); +} + +void tms3203x_device::pushf(UINT32 op) +{ + int dreg = (op >> 16) & 7; + WMEM(++IREG(TMR_SP), FP2LONG(dreg)); +} + +/*-----------------------------------------------------*/ + +#define OR(dreg, src1, src2) \ +{ \ + UINT32 _res = (src1) | (src2); \ + IREG(dreg) = _res; \ + if (dreg < 8) \ + { \ + CLR_NZVUF(); \ + OR_NZ(_res); \ + } \ + else if (dreg >= TMR_BK) \ + update_special(dreg); \ +} + +void tms3203x_device::or_reg(UINT32 op) +{ + UINT32 src = IREG(op & 31); + int dreg = (op >> 16) & 31; + UINT32 dst = IREG(dreg); + OR(dreg, dst, src); +} + +void tms3203x_device::or_dir(UINT32 op) +{ + UINT32 src = RMEM(DIRECT(op)); + int dreg = (op >> 16) & 31; + UINT32 dst = IREG(dreg); + OR(dreg, dst, src); +} + +void tms3203x_device::or_ind(UINT32 op) +{ + UINT32 src = RMEM(INDIRECT_D(op, op >> 8)); + int dreg = (op >> 16) & 31; + UINT32 dst = IREG(dreg); + OR(dreg, dst, src); +} + +void tms3203x_device::or_imm(UINT32 op) +{ + UINT32 src = (UINT16)op; + int dreg = (op >> 16) & 31; + UINT32 dst = IREG(dreg); + OR(dreg, dst, src); +} + +/*-----------------------------------------------------*/ + +void tms3203x_device::maxspeed(UINT32 op) { unimplemented(op); } + +/*-----------------------------------------------------*/ + +#define RND(dreg) \ +{ \ + INT32 man = FREGMAN(dreg); \ + CLR_NVUF(); \ + if (man < 0x7fffff80) \ + { \ + m_r[dreg].set_mantissa(((UINT32)man + 0x80) & 0xffffff00); \ + OR_NUF(m_r[dreg]); \ + } \ + else if (FREGEXP(dreg) < 127) \ + { \ + m_r[dreg].set_mantissa(((UINT32)man + 0x80) & 0x7fffff00); \ + m_r[dreg].set_exponent(FREGEXP(dreg) + 1); \ + OR_NUF(m_r[dreg]); \ + } \ + else \ + { \ + m_r[dreg].set_mantissa(0x7fffff00); \ + IREG(TMR_ST) |= VFLAG | LVFLAG; \ + } \ +} + +void tms3203x_device::rnd_reg(UINT32 op) +{ + int sreg = op & 7; + int dreg = (op >> 16) & 7; + m_r[dreg] = m_r[sreg]; + RND(dreg); +} + +void tms3203x_device::rnd_dir(UINT32 op) +{ + UINT32 res = RMEM(DIRECT(op)); + int dreg = (op >> 16) & 7; + LONG2FP(dreg, res); + RND(dreg); +} + +void tms3203x_device::rnd_ind(UINT32 op) +{ + UINT32 res = RMEM(INDIRECT_D(op, op >> 8)); + int dreg = (op >> 16) & 7; + LONG2FP(dreg, res); + RND(dreg); +} + +void tms3203x_device::rnd_imm(UINT32 op) +{ + int dreg = (op >> 16) & 7; + SHORT2FP(dreg, op); + RND(dreg); +} + +/*-----------------------------------------------------*/ + +void tms3203x_device::rol(UINT32 op) +{ + int dreg = (op >> 16) & 31; + UINT32 res = IREG(dreg); + int newcflag = res >> 31; + res = (res << 1) | newcflag; + IREG(dreg) = res; + if (dreg < 8) + { + CLR_NZCVUF(); + OR_NZ(res); + OR_C(newcflag); + } + else if (dreg >= TMR_BK) + update_special(dreg); +} + +void tms3203x_device::rolc(UINT32 op) +{ + int dreg = (op >> 16) & 31; + UINT32 res = IREG(dreg); + int newcflag = res >> 31; + res = (res << 1) | (IREG(TMR_ST) & CFLAG); + IREG(dreg) = res; + if (dreg < 8) + { + CLR_NZCVUF(); + OR_NZ(res); + OR_C(newcflag); + } + else if (dreg >= TMR_BK) + update_special(dreg); +} + +void tms3203x_device::ror(UINT32 op) +{ + int dreg = (op >> 16) & 31; + UINT32 res = IREG(dreg); + int newcflag = res & 1; + res = (res >> 1) | (newcflag << 31); + IREG(dreg) = res; + if (dreg < 8) + { + CLR_NZCVUF(); + OR_NZ(res); + OR_C(newcflag); + } + else if (dreg >= TMR_BK) + update_special(dreg); +} + +void tms3203x_device::rorc(UINT32 op) +{ + int dreg = (op >> 16) & 31; + UINT32 res = IREG(dreg); + int newcflag = res & 1; + res = (res >> 1) | ((IREG(TMR_ST) & CFLAG) << 31); + IREG(dreg) = res; + if (dreg < 8) + { + CLR_NZCVUF(); + OR_NZ(res); + OR_C(newcflag); + } + else if (dreg >= TMR_BK) + update_special(dreg); +} + +/*-----------------------------------------------------*/ + +void tms3203x_device::rtps_reg(UINT32 op) +{ + IREG(TMR_RC) = IREG(op & 31); + IREG(TMR_RS) = m_pc; + IREG(TMR_RE) = m_pc; + IREG(TMR_ST) |= RMFLAG; + m_icount -= 3*2; + m_delayed = true; +} + +void tms3203x_device::rtps_dir(UINT32 op) +{ + IREG(TMR_RC) = RMEM(DIRECT(op)); + IREG(TMR_RS) = m_pc; + IREG(TMR_RE) = m_pc; + IREG(TMR_ST) |= RMFLAG; + m_icount -= 3*2; + m_delayed = true; +} + +void tms3203x_device::rtps_ind(UINT32 op) +{ + IREG(TMR_RC) = RMEM(INDIRECT_D(op, op >> 8)); + IREG(TMR_RS) = m_pc; + IREG(TMR_RE) = m_pc; + IREG(TMR_ST) |= RMFLAG; + m_icount -= 3*2; + m_delayed = true; +} + +void tms3203x_device::rtps_imm(UINT32 op) +{ + IREG(TMR_RC) = (UINT16)op; + IREG(TMR_RS) = m_pc; + IREG(TMR_RE) = m_pc; + IREG(TMR_ST) |= RMFLAG; + m_icount -= 3*2; + m_delayed = true; +} + +/*-----------------------------------------------------*/ + +void tms3203x_device::stf_dir(UINT32 op) +{ + WMEM(DIRECT(op), FP2LONG((op >> 16) & 7)); +} + +void tms3203x_device::stf_ind(UINT32 op) +{ + WMEM(INDIRECT_D(op, op >> 8), FP2LONG((op >> 16) & 7)); +} + +/*-----------------------------------------------------*/ + +void tms3203x_device::stfi_dir(UINT32 op) { unimplemented(op); } +void tms3203x_device::stfi_ind(UINT32 op) { unimplemented(op); } + +/*-----------------------------------------------------*/ + +void tms3203x_device::sti_dir(UINT32 op) +{ + WMEM(DIRECT(op), IREG((op >> 16) & 31)); +} + +void tms3203x_device::sti_ind(UINT32 op) +{ + WMEM(INDIRECT_D(op, op >> 8), IREG((op >> 16) & 31)); +} + +/*-----------------------------------------------------*/ + +void tms3203x_device::stii_dir(UINT32 op) { unimplemented(op); } +void tms3203x_device::stii_ind(UINT32 op) { unimplemented(op); } + +/*-----------------------------------------------------*/ + +void tms3203x_device::sigi(UINT32 op) { unimplemented(op); } + +/*-----------------------------------------------------*/ + +#define SUBB(dreg, src1, src2) \ +{ \ + UINT32 _res = src1 - src2 - (IREG(TMR_ST) & CFLAG); \ + if (!OVM() || !OVERFLOW_SUB(src1,src2,_res)) \ + IREG(dreg) = _res; \ + else \ + IREG(dreg) = ((INT32)src1 < 0) ? 0x80000000 : 0x7fffffff; \ + if (dreg < 8) \ + { \ + UINT32 tempc = IREG(TMR_ST) & CFLAG; \ + CLR_NZCVUF(); \ + OR_C_SBB(src1,src2,tempc); \ + OR_V_SUB(src1,src2,_res); \ + OR_NZ(_res); \ + } \ + else if (dreg >= TMR_BK) \ + update_special(dreg); \ +} + +void tms3203x_device::subb_reg(UINT32 op) +{ + UINT32 src = IREG(op & 31); + int dreg = (op >> 16) & 31; + UINT32 dst = IREG(dreg); + SUBB(dreg, dst, src); +} + +void tms3203x_device::subb_dir(UINT32 op) +{ + UINT32 src = RMEM(DIRECT(op)); + int dreg = (op >> 16) & 31; + UINT32 dst = IREG(dreg); + SUBB(dreg, dst, src); +} + +void tms3203x_device::subb_ind(UINT32 op) +{ + UINT32 src = RMEM(INDIRECT_D(op, op >> 8)); + int dreg = (op >> 16) & 31; + UINT32 dst = IREG(dreg); + SUBB(dreg, dst, src); +} + +void tms3203x_device::subb_imm(UINT32 op) +{ + UINT32 src = (INT16)op; + int dreg = (op >> 16) & 31; + UINT32 dst = IREG(dreg); + SUBB(dreg, dst, src); +} + +/*-----------------------------------------------------*/ + +#define SUBC(dreg, src) \ +{ \ + UINT32 dst = IREG(dreg); \ + if (dst >= src) \ + IREG(dreg) = ((dst - src) << 1) | 1; \ + else \ + IREG(dreg) = dst << 1; \ + if (dreg >= TMR_BK) \ + update_special(dreg); \ +} + +void tms3203x_device::subc_reg(UINT32 op) +{ + UINT32 src = IREG(op & 31); + int dreg = (op >> 16) & 31; + SUBC(dreg, src); +} + +void tms3203x_device::subc_dir(UINT32 op) +{ + UINT32 src = RMEM(DIRECT(op)); + int dreg = (op >> 16) & 31; + SUBC(dreg, src); +} + +void tms3203x_device::subc_ind(UINT32 op) +{ + UINT32 src = RMEM(INDIRECT_D(op, op >> 8)); + int dreg = (op >> 16) & 31; + SUBC(dreg, src); +} + +void tms3203x_device::subc_imm(UINT32 op) +{ + UINT32 src = (INT16)op; + int dreg = (op >> 16) & 31; + SUBC(dreg, src); +} + +/*-----------------------------------------------------*/ + +void tms3203x_device::subf_reg(UINT32 op) +{ + int dreg = (op >> 16) & 7; + subf(m_r[dreg], m_r[dreg], m_r[op & 7]); +} + +void tms3203x_device::subf_dir(UINT32 op) +{ + UINT32 res = RMEM(DIRECT(op)); + int dreg = (op >> 16) & 7; + LONG2FP(TMR_TEMP1, res); + subf(m_r[dreg], m_r[dreg], m_r[TMR_TEMP1]); +} + +void tms3203x_device::subf_ind(UINT32 op) +{ + UINT32 res = RMEM(INDIRECT_D(op, op >> 8)); + int dreg = (op >> 16) & 7; + LONG2FP(TMR_TEMP1, res); + subf(m_r[dreg], m_r[dreg], m_r[TMR_TEMP1]); +} + +void tms3203x_device::subf_imm(UINT32 op) +{ + int dreg = (op >> 16) & 7; + SHORT2FP(TMR_TEMP1, op); + subf(m_r[dreg], m_r[dreg], m_r[TMR_TEMP1]); +} + +/*-----------------------------------------------------*/ + +#define SUBI(dreg, src1, src2) \ +{ \ + UINT32 _res = src1 - src2; \ + if (!OVM() || !OVERFLOW_SUB(src1,src2,_res)) \ + IREG(dreg) = _res; \ + else \ + IREG(dreg) = ((INT32)src1 < 0) ? 0x80000000 : 0x7fffffff; \ + if (dreg < 8) \ + { \ + CLR_NZCVUF(); \ + OR_C_SUB(src1,src2,_res); \ + OR_V_SUB(src1,src2,_res); \ + OR_NZ(_res); \ + } \ + else if (dreg >= TMR_BK) \ + update_special(dreg); \ +} + +void tms3203x_device::subi_reg(UINT32 op) +{ + UINT32 src = IREG(op & 31); + int dreg = (op >> 16) & 31; + UINT32 dst = IREG(dreg); + SUBI(dreg, dst, src); +} + +void tms3203x_device::subi_dir(UINT32 op) +{ + UINT32 src = RMEM(DIRECT(op)); + int dreg = (op >> 16) & 31; + UINT32 dst = IREG(dreg); + SUBI(dreg, dst, src); +} + +void tms3203x_device::subi_ind(UINT32 op) +{ + UINT32 src = RMEM(INDIRECT_D(op, op >> 8)); + int dreg = (op >> 16) & 31; + UINT32 dst = IREG(dreg); + SUBI(dreg, dst, src); +} + +void tms3203x_device::subi_imm(UINT32 op) +{ + UINT32 src = (INT16)op; + int dreg = (op >> 16) & 31; + UINT32 dst = IREG(dreg); + SUBI(dreg, dst, src); +} + +/*-----------------------------------------------------*/ + +void tms3203x_device::subrb_reg(UINT32 op) +{ + UINT32 src = IREG(op & 31); + int dreg = (op >> 16) & 31; + UINT32 dst = IREG(dreg); + SUBB(dreg, src, dst); +} + +void tms3203x_device::subrb_dir(UINT32 op) +{ + UINT32 src = RMEM(DIRECT(op)); + int dreg = (op >> 16) & 31; + UINT32 dst = IREG(dreg); + SUBB(dreg, src, dst); +} + +void tms3203x_device::subrb_ind(UINT32 op) +{ + UINT32 src = RMEM(INDIRECT_D(op, op >> 8)); + int dreg = (op >> 16) & 31; + UINT32 dst = IREG(dreg); + SUBB(dreg, src, dst); +} + +void tms3203x_device::subrb_imm(UINT32 op) +{ + UINT32 src = (INT16)op; + int dreg = (op >> 16) & 31; + UINT32 dst = IREG(dreg); + SUBB(dreg, src, dst); +} + +/*-----------------------------------------------------*/ + +void tms3203x_device::subrf_reg(UINT32 op) +{ + int dreg = (op >> 16) & 7; + subf(m_r[dreg], m_r[op & 7], m_r[dreg]); +} + +void tms3203x_device::subrf_dir(UINT32 op) +{ + UINT32 res = RMEM(DIRECT(op)); + int dreg = (op >> 16) & 7; + LONG2FP(TMR_TEMP1, res); + subf(m_r[dreg], m_r[TMR_TEMP1], m_r[dreg]); +} + +void tms3203x_device::subrf_ind(UINT32 op) +{ + UINT32 res = RMEM(INDIRECT_D(op, op >> 8)); + int dreg = (op >> 16) & 7; + LONG2FP(TMR_TEMP1, res); + subf(m_r[dreg], m_r[TMR_TEMP1], m_r[dreg]); +} + +void tms3203x_device::subrf_imm(UINT32 op) +{ + int dreg = (op >> 16) & 7; + SHORT2FP(TMR_TEMP1, op); + subf(m_r[dreg], m_r[TMR_TEMP1], m_r[dreg]); +} + +/*-----------------------------------------------------*/ + +void tms3203x_device::subri_reg(UINT32 op) +{ + UINT32 src = IREG(op & 31); + int dreg = (op >> 16) & 31; + UINT32 dst = IREG(dreg); + SUBI(dreg, src, dst); +} + +void tms3203x_device::subri_dir(UINT32 op) +{ + UINT32 src = RMEM(DIRECT(op)); + int dreg = (op >> 16) & 31; + UINT32 dst = IREG(dreg); + SUBI(dreg, src, dst); +} + +void tms3203x_device::subri_ind(UINT32 op) +{ + UINT32 src = RMEM(INDIRECT_D(op, op >> 8)); + int dreg = (op >> 16) & 31; + UINT32 dst = IREG(dreg); + SUBI(dreg, src, dst); +} + +void tms3203x_device::subri_imm(UINT32 op) +{ + UINT32 src = (INT16)op; + int dreg = (op >> 16) & 31; + UINT32 dst = IREG(dreg); + SUBI(dreg, src, dst); +} + +/*-----------------------------------------------------*/ + +#define TSTB(src1, src2) \ +{ \ + UINT32 _res = (src1) & (src2); \ + CLR_NZVUF(); \ + OR_NZ(_res); \ +} + +void tms3203x_device::tstb_reg(UINT32 op) +{ + UINT32 src = IREG(op & 31); + UINT32 dst = IREG((op >> 16) & 31); + TSTB(dst, src); +} + +void tms3203x_device::tstb_dir(UINT32 op) +{ + UINT32 src = RMEM(DIRECT(op)); + UINT32 dst = IREG((op >> 16) & 31); + TSTB(dst, src); +} + +void tms3203x_device::tstb_ind(UINT32 op) +{ + UINT32 src = RMEM(INDIRECT_D(op, op >> 8)); + UINT32 dst = IREG((op >> 16) & 31); + TSTB(dst, src); +} + +void tms3203x_device::tstb_imm(UINT32 op) +{ + UINT32 src = (UINT16)op; + UINT32 dst = IREG((op >> 16) & 31); + TSTB(dst, src); +} + +/*-----------------------------------------------------*/ + +#define XOR(dreg, src1, src2) \ +{ \ + UINT32 _res = (src1) ^ (src2); \ + IREG(dreg) = _res; \ + if (dreg < 8) \ + { \ + CLR_NZVUF(); \ + OR_NZ(_res); \ + } \ + else if (dreg >= TMR_BK) \ + update_special(dreg); \ +} + +void tms3203x_device::xor_reg(UINT32 op) +{ + UINT32 src = IREG(op & 31); + int dreg = (op >> 16) & 31; + UINT32 dst = IREG(dreg); + XOR(dreg, dst, src); +} + +void tms3203x_device::xor_dir(UINT32 op) +{ + UINT32 src = RMEM(DIRECT(op)); + int dreg = (op >> 16) & 31; + UINT32 dst = IREG(dreg); + XOR(dreg, dst, src); +} + +void tms3203x_device::xor_ind(UINT32 op) +{ + UINT32 src = RMEM(INDIRECT_D(op, op >> 8)); + int dreg = (op >> 16) & 31; + UINT32 dst = IREG(dreg); + XOR(dreg, dst, src); +} + +void tms3203x_device::xor_imm(UINT32 op) +{ + UINT32 src = (UINT16)op; + int dreg = (op >> 16) & 31; + UINT32 dst = IREG(dreg); + XOR(dreg, dst, src); +} + +/*-----------------------------------------------------*/ + +void tms3203x_device::iack_dir(UINT32 op) +{ + offs_t addr = DIRECT(op); + m_iack_cb(addr, ASSERT_LINE); + RMEM(addr); + m_iack_cb(addr, CLEAR_LINE); +} + +void tms3203x_device::iack_ind(UINT32 op) +{ + offs_t addr = INDIRECT_D(op, op >> 8); + m_iack_cb(addr, ASSERT_LINE); + RMEM(addr); + m_iack_cb(addr, CLEAR_LINE); +} + +/*-----------------------------------------------------*/ + +void tms3203x_device::addc3_regreg(UINT32 op) +{ + UINT32 src1 = IREG((op >> 8) & 31); + UINT32 src2 = IREG(op & 31); + int dreg = (op >> 16) & 31; + ADDC(dreg, src1, src2); +} + +void tms3203x_device::addc3_indreg(UINT32 op) +{ + UINT32 src1 = RMEM(INDIRECT_1(op, op >> 8)); + UINT32 src2 = IREG(op & 31); + int dreg = (op >> 16) & 31; + ADDC(dreg, src1, src2); +} + +void tms3203x_device::addc3_regind(UINT32 op) +{ + UINT32 src2 = RMEM(INDIRECT_1(op, op)); + UINT32 src1 = IREG((op >> 8) & 31); + int dreg = (op >> 16) & 31; + ADDC(dreg, src1, src2); +} + +void tms3203x_device::addc3_indind(UINT32 op) +{ + DECLARE_DEF; + UINT32 src1 = RMEM(INDIRECT_1_DEF(op, op >> 8)); + UINT32 src2 = RMEM(INDIRECT_1(op, op)); + int dreg = (op >> 16) & 31; + UPDATE_DEF(); + ADDC(dreg, src1, src2); +} + +/*-----------------------------------------------------*/ + +void tms3203x_device::addf3_regreg(UINT32 op) +{ + int sreg1 = (op >> 8) & 7; + int sreg2 = op & 7; + int dreg = (op >> 16) & 7; + addf(m_r[dreg], m_r[sreg1], m_r[sreg2]); +} + +void tms3203x_device::addf3_indreg(UINT32 op) +{ + UINT32 src1 = RMEM(INDIRECT_1(op, op >> 8)); + int sreg2 = op & 7; + int dreg = (op >> 16) & 7; + LONG2FP(TMR_TEMP1, src1); + addf(m_r[dreg], m_r[TMR_TEMP1], m_r[sreg2]); +} + +void tms3203x_device::addf3_regind(UINT32 op) +{ + UINT32 src2 = RMEM(INDIRECT_1(op, op)); + int sreg1 = (op >> 8) & 7; + int dreg = (op >> 16) & 7; + LONG2FP(TMR_TEMP2, src2); + addf(m_r[dreg], m_r[sreg1], m_r[TMR_TEMP2]); +} + +void tms3203x_device::addf3_indind(UINT32 op) +{ + DECLARE_DEF; + UINT32 src1 = RMEM(INDIRECT_1_DEF(op, op >> 8)); + UINT32 src2 = RMEM(INDIRECT_1(op, op)); + int dreg = (op >> 16) & 7; + UPDATE_DEF(); + LONG2FP(TMR_TEMP1, src1); + LONG2FP(TMR_TEMP2, src2); + addf(m_r[dreg], m_r[TMR_TEMP1], m_r[TMR_TEMP2]); +} + +/*-----------------------------------------------------*/ + +void tms3203x_device::addi3_regreg(UINT32 op) +{ + UINT32 src1 = IREG((op >> 8) & 31); + UINT32 src2 = IREG(op & 31); + int dreg = (op >> 16) & 31; + ADDI(dreg, src1, src2); +} + +void tms3203x_device::addi3_indreg(UINT32 op) +{ + UINT32 src1 = RMEM(INDIRECT_1(op, op >> 8)); + UINT32 src2 = IREG(op & 31); + int dreg = (op >> 16) & 31; + ADDI(dreg, src1, src2); +} + +void tms3203x_device::addi3_regind(UINT32 op) +{ + // Radikal Bikers confirms via ADDI3 AR3,*AR3++(1),R2 / SUB $0001,R2 sequence + UINT32 src2 = RMEM(INDIRECT_1(op, op)); + UINT32 src1 = IREG((op >> 8) & 31); + int dreg = (op >> 16) & 31; + ADDI(dreg, src1, src2); +} + +void tms3203x_device::addi3_indind(UINT32 op) +{ + DECLARE_DEF; + UINT32 src1 = RMEM(INDIRECT_1_DEF(op, op >> 8)); + UINT32 src2 = RMEM(INDIRECT_1(op, op)); + int dreg = (op >> 16) & 31; + UPDATE_DEF(); + ADDI(dreg, src1, src2); +} + +/*-----------------------------------------------------*/ + +void tms3203x_device::and3_regreg(UINT32 op) +{ + UINT32 src1 = IREG((op >> 8) & 31); + UINT32 src2 = IREG(op & 31); + int dreg = (op >> 16) & 31; + AND(dreg, src1, src2); +} + +void tms3203x_device::and3_indreg(UINT32 op) +{ + UINT32 src1 = RMEM(INDIRECT_1(op, op >> 8)); + UINT32 src2 = IREG(op & 31); + int dreg = (op >> 16) & 31; + AND(dreg, src1, src2); +} + +void tms3203x_device::and3_regind(UINT32 op) +{ + UINT32 src2 = RMEM(INDIRECT_1(op, op)); + UINT32 src1 = IREG((op >> 8) & 31); + int dreg = (op >> 16) & 31; + AND(dreg, src1, src2); +} + +void tms3203x_device::and3_indind(UINT32 op) +{ + DECLARE_DEF; + UINT32 src1 = RMEM(INDIRECT_1_DEF(op, op >> 8)); + UINT32 src2 = RMEM(INDIRECT_1(op, op)); + int dreg = (op >> 16) & 31; + UPDATE_DEF(); + AND(dreg, src1, src2); +} + +/*-----------------------------------------------------*/ + +void tms3203x_device::andn3_regreg(UINT32 op) +{ + UINT32 src1 = IREG((op >> 8) & 31); + UINT32 src2 = IREG(op & 31); + int dreg = (op >> 16) & 31; + ANDN(dreg, src1, src2); +} + +void tms3203x_device::andn3_indreg(UINT32 op) +{ + UINT32 src1 = RMEM(INDIRECT_1(op, op >> 8)); + UINT32 src2 = IREG(op & 31); + int dreg = (op >> 16) & 31; + ANDN(dreg, src1, src2); +} + +void tms3203x_device::andn3_regind(UINT32 op) +{ + UINT32 src2 = RMEM(INDIRECT_1(op, op)); + UINT32 src1 = IREG((op >> 8) & 31); + int dreg = (op >> 16) & 31; + ANDN(dreg, src1, src2); +} + +void tms3203x_device::andn3_indind(UINT32 op) +{ + DECLARE_DEF; + UINT32 src1 = RMEM(INDIRECT_1_DEF(op, op >> 8)); + UINT32 src2 = RMEM(INDIRECT_1(op, op)); + int dreg = (op >> 16) & 31; + UPDATE_DEF(); + ANDN(dreg, src1, src2); +} + +/*-----------------------------------------------------*/ + +void tms3203x_device::ash3_regreg(UINT32 op) +{ + UINT32 src1 = IREG((op >> 8) & 31); + UINT32 src2 = IREG(op & 31); + int dreg = (op >> 16) & 31; + ASH(dreg, src1, src2); +} + +void tms3203x_device::ash3_indreg(UINT32 op) +{ + UINT32 src1 = RMEM(INDIRECT_1(op, op >> 8)); + UINT32 src2 = IREG(op & 31); + int dreg = (op >> 16) & 31; + ASH(dreg, src1, src2); +} + +void tms3203x_device::ash3_regind(UINT32 op) +{ + UINT32 src2 = RMEM(INDIRECT_1(op, op)); + UINT32 src1 = IREG((op >> 8) & 31); + int dreg = (op >> 16) & 31; + ASH(dreg, src1, src2); +} + +void tms3203x_device::ash3_indind(UINT32 op) +{ + DECLARE_DEF; + UINT32 src1 = RMEM(INDIRECT_1_DEF(op, op >> 8)); + UINT32 src2 = RMEM(INDIRECT_1(op, op)); + int dreg = (op >> 16) & 31; + UPDATE_DEF(); + ASH(dreg, src1, src2); +} + +/*-----------------------------------------------------*/ + +void tms3203x_device::cmpf3_regreg(UINT32 op) +{ + int sreg1 = (op >> 8) & 7; + int sreg2 = op & 7; + subf(m_r[TMR_TEMP1], m_r[sreg1], m_r[sreg2]); +} + +void tms3203x_device::cmpf3_indreg(UINT32 op) +{ + UINT32 src1 = RMEM(INDIRECT_1(op, op >> 8)); + int sreg2 = op & 7; + LONG2FP(TMR_TEMP1, src1); + subf(m_r[TMR_TEMP1], m_r[TMR_TEMP1], m_r[sreg2]); +} + +void tms3203x_device::cmpf3_regind(UINT32 op) +{ + UINT32 src2 = RMEM(INDIRECT_1(op, op)); + int sreg1 = (op >> 8) & 7; + LONG2FP(TMR_TEMP2, src2); + subf(m_r[TMR_TEMP1], m_r[sreg1], m_r[TMR_TEMP2]); +} + +void tms3203x_device::cmpf3_indind(UINT32 op) +{ + DECLARE_DEF; + UINT32 src1 = RMEM(INDIRECT_1_DEF(op, op >> 8)); + UINT32 src2 = RMEM(INDIRECT_1(op, op)); + UPDATE_DEF(); + LONG2FP(TMR_TEMP1, src1); + LONG2FP(TMR_TEMP2, src2); + subf(m_r[TMR_TEMP1], m_r[TMR_TEMP1], m_r[TMR_TEMP2]); +} + +/*-----------------------------------------------------*/ + +void tms3203x_device::cmpi3_regreg(UINT32 op) +{ + UINT32 src1 = IREG((op >> 8) & 31); + UINT32 src2 = IREG(op & 31); + CMPI(src1, src2); +} + +void tms3203x_device::cmpi3_indreg(UINT32 op) +{ + UINT32 src1 = RMEM(INDIRECT_1(op, op >> 8)); + UINT32 src2 = IREG(op & 31); + CMPI(src1, src2); +} + +void tms3203x_device::cmpi3_regind(UINT32 op) +{ + UINT32 src2 = RMEM(INDIRECT_1(op, op)); + UINT32 src1 = IREG((op >> 8) & 31); + CMPI(src1, src2); +} + +void tms3203x_device::cmpi3_indind(UINT32 op) +{ + DECLARE_DEF; + UINT32 src1 = RMEM(INDIRECT_1_DEF(op, op >> 8)); + UINT32 src2 = RMEM(INDIRECT_1(op, op)); + UPDATE_DEF(); + CMPI(src1, src2); +} + +/*-----------------------------------------------------*/ + +void tms3203x_device::lsh3_regreg(UINT32 op) +{ + UINT32 src1 = IREG((op >> 8) & 31); + UINT32 src2 = IREG(op & 31); + int dreg = (op >> 16) & 31; + LSH(dreg, src1, src2); +} + +void tms3203x_device::lsh3_indreg(UINT32 op) +{ + UINT32 src1 = RMEM(INDIRECT_1(op, op >> 8)); + UINT32 src2 = IREG(op & 31); + int dreg = (op >> 16) & 31; + LSH(dreg, src1, src2); +} + +void tms3203x_device::lsh3_regind(UINT32 op) +{ + UINT32 src2 = RMEM(INDIRECT_1(op, op)); + UINT32 src1 = IREG((op >> 8) & 31); + int dreg = (op >> 16) & 31; + LSH(dreg, src1, src2); +} + +void tms3203x_device::lsh3_indind(UINT32 op) +{ + DECLARE_DEF; + UINT32 src1 = RMEM(INDIRECT_1_DEF(op, op >> 8)); + UINT32 src2 = RMEM(INDIRECT_1(op, op)); + int dreg = (op >> 16) & 31; + UPDATE_DEF(); + LSH(dreg, src1, src2); +} + +/*-----------------------------------------------------*/ + +void tms3203x_device::mpyf3_regreg(UINT32 op) +{ + int sreg1 = (op >> 8) & 7; + int sreg2 = op & 7; + int dreg = (op >> 16) & 7; + mpyf(m_r[dreg], m_r[sreg1], m_r[sreg2]); +} + +void tms3203x_device::mpyf3_indreg(UINT32 op) +{ + UINT32 src1 = RMEM(INDIRECT_1(op, op >> 8)); + int sreg2 = op & 7; + int dreg = (op >> 16) & 7; + LONG2FP(TMR_TEMP1, src1); + mpyf(m_r[dreg], m_r[TMR_TEMP1], m_r[sreg2]); +} + +void tms3203x_device::mpyf3_regind(UINT32 op) +{ + UINT32 src2 = RMEM(INDIRECT_1(op, op)); + int sreg1 = (op >> 8) & 7; + int dreg = (op >> 16) & 7; + LONG2FP(TMR_TEMP2, src2); + mpyf(m_r[dreg], m_r[sreg1], m_r[TMR_TEMP2]); +} + +void tms3203x_device::mpyf3_indind(UINT32 op) +{ + DECLARE_DEF; + UINT32 src1 = RMEM(INDIRECT_1_DEF(op, op >> 8)); + UINT32 src2 = RMEM(INDIRECT_1(op, op)); + int dreg = (op >> 16) & 7; + UPDATE_DEF(); + LONG2FP(TMR_TEMP1, src1); + LONG2FP(TMR_TEMP2, src2); + mpyf(m_r[dreg], m_r[TMR_TEMP1], m_r[TMR_TEMP2]); +} + +/*-----------------------------------------------------*/ + +void tms3203x_device::mpyi3_regreg(UINT32 op) +{ + UINT32 src1 = IREG((op >> 8) & 31); + UINT32 src2 = IREG(op & 31); + int dreg = (op >> 16) & 31; + MPYI(dreg, src1, src2); +} + +void tms3203x_device::mpyi3_indreg(UINT32 op) +{ + UINT32 src1 = RMEM(INDIRECT_1(op, op >> 8)); + UINT32 src2 = IREG(op & 31); + int dreg = (op >> 16) & 31; + MPYI(dreg, src1, src2); +} + +void tms3203x_device::mpyi3_regind(UINT32 op) +{ + UINT32 src2 = RMEM(INDIRECT_1(op, op)); + UINT32 src1 = IREG((op >> 8) & 31); + int dreg = (op >> 16) & 31; + MPYI(dreg, src1, src2); +} + +void tms3203x_device::mpyi3_indind(UINT32 op) +{ + DECLARE_DEF; + UINT32 src1 = RMEM(INDIRECT_1_DEF(op, op >> 8)); + UINT32 src2 = RMEM(INDIRECT_1(op, op)); + int dreg = (op >> 16) & 31; + UPDATE_DEF(); + MPYI(dreg, src1, src2); +} + +/*-----------------------------------------------------*/ + +void tms3203x_device::or3_regreg(UINT32 op) +{ + UINT32 src1 = IREG((op >> 8) & 31); + UINT32 src2 = IREG(op & 31); + int dreg = (op >> 16) & 31; + OR(dreg, src1, src2); +} + +void tms3203x_device::or3_indreg(UINT32 op) +{ + UINT32 src1 = RMEM(INDIRECT_1(op, op >> 8)); + UINT32 src2 = IREG(op & 31); + int dreg = (op >> 16) & 31; + OR(dreg, src1, src2); +} + +void tms3203x_device::or3_regind(UINT32 op) +{ + UINT32 src2 = RMEM(INDIRECT_1(op, op)); + UINT32 src1 = IREG((op >> 8) & 31); + int dreg = (op >> 16) & 31; + OR(dreg, src1, src2); +} + +void tms3203x_device::or3_indind(UINT32 op) +{ + DECLARE_DEF; + UINT32 src1 = RMEM(INDIRECT_1_DEF(op, op >> 8)); + UINT32 src2 = RMEM(INDIRECT_1(op, op)); + int dreg = (op >> 16) & 31; + UPDATE_DEF(); + OR(dreg, src1, src2); +} + +/*-----------------------------------------------------*/ + +void tms3203x_device::subb3_regreg(UINT32 op) +{ + UINT32 src1 = IREG((op >> 8) & 31); + UINT32 src2 = IREG(op & 31); + int dreg = (op >> 16) & 31; + SUBB(dreg, src1, src2); +} + +void tms3203x_device::subb3_indreg(UINT32 op) +{ + UINT32 src1 = RMEM(INDIRECT_1(op, op >> 8)); + UINT32 src2 = IREG(op & 31); + int dreg = (op >> 16) & 31; + SUBB(dreg, src1, src2); +} + +void tms3203x_device::subb3_regind(UINT32 op) +{ + UINT32 src2 = RMEM(INDIRECT_1(op, op)); + UINT32 src1 = IREG((op >> 8) & 31); + int dreg = (op >> 16) & 31; + SUBB(dreg, src1, src2); +} + +void tms3203x_device::subb3_indind(UINT32 op) +{ + DECLARE_DEF; + UINT32 src1 = RMEM(INDIRECT_1_DEF(op, op >> 8)); + UINT32 src2 = RMEM(INDIRECT_1(op, op)); + int dreg = (op >> 16) & 31; + UPDATE_DEF(); + SUBB(dreg, src1, src2); +} + +/*-----------------------------------------------------*/ + +void tms3203x_device::subf3_regreg(UINT32 op) +{ + int sreg1 = (op >> 8) & 7; + int sreg2 = op & 7; + int dreg = (op >> 16) & 7; + subf(m_r[dreg], m_r[sreg1], m_r[sreg2]); +} + +void tms3203x_device::subf3_indreg(UINT32 op) +{ + UINT32 src1 = RMEM(INDIRECT_1(op, op >> 8)); + int sreg2 = op & 7; + int dreg = (op >> 16) & 7; + LONG2FP(TMR_TEMP1, src1); + subf(m_r[dreg], m_r[TMR_TEMP1], m_r[sreg2]); +} + +void tms3203x_device::subf3_regind(UINT32 op) +{ + UINT32 src2 = RMEM(INDIRECT_1(op, op)); + int sreg1 = (op >> 8) & 7; + int dreg = (op >> 16) & 7; + LONG2FP(TMR_TEMP2, src2); + subf(m_r[dreg], m_r[sreg1], m_r[TMR_TEMP2]); +} + +void tms3203x_device::subf3_indind(UINT32 op) +{ + DECLARE_DEF; + UINT32 src1 = RMEM(INDIRECT_1_DEF(op, op >> 8)); + UINT32 src2 = RMEM(INDIRECT_1(op, op)); + int dreg = (op >> 16) & 7; + UPDATE_DEF(); + LONG2FP(TMR_TEMP1, src1); + LONG2FP(TMR_TEMP2, src2); + subf(m_r[dreg], m_r[TMR_TEMP1], m_r[TMR_TEMP2]); +} + +/*-----------------------------------------------------*/ + +void tms3203x_device::subi3_regreg(UINT32 op) +{ + UINT32 src1 = IREG((op >> 8) & 31); + UINT32 src2 = IREG(op & 31); + int dreg = (op >> 16) & 31; + SUBI(dreg, src1, src2); +} + +void tms3203x_device::subi3_indreg(UINT32 op) +{ + UINT32 src1 = RMEM(INDIRECT_1(op, op >> 8)); + UINT32 src2 = IREG(op & 31); + int dreg = (op >> 16) & 31; + SUBI(dreg, src1, src2); +} + +void tms3203x_device::subi3_regind(UINT32 op) +{ + UINT32 src2 = RMEM(INDIRECT_1(op, op)); + UINT32 src1 = IREG((op >> 8) & 31); + int dreg = (op >> 16) & 31; + SUBI(dreg, src1, src2); +} + +void tms3203x_device::subi3_indind(UINT32 op) +{ + DECLARE_DEF; + UINT32 src1 = RMEM(INDIRECT_1_DEF(op, op >> 8)); + UINT32 src2 = RMEM(INDIRECT_1(op, op)); + int dreg = (op >> 16) & 31; + UPDATE_DEF(); + SUBI(dreg, src1, src2); +} + +/*-----------------------------------------------------*/ + +void tms3203x_device::tstb3_regreg(UINT32 op) +{ + UINT32 src1 = IREG((op >> 8) & 31); + UINT32 src2 = IREG(op & 31); + TSTB(src1, src2); +} + +void tms3203x_device::tstb3_indreg(UINT32 op) +{ + UINT32 src1 = RMEM(INDIRECT_1(op, op >> 8)); + UINT32 src2 = IREG(op & 31); + TSTB(src1, src2); +} + +void tms3203x_device::tstb3_regind(UINT32 op) +{ + UINT32 src2 = RMEM(INDIRECT_1(op, op)); + UINT32 src1 = IREG((op >> 8) & 31); + TSTB(src1, src2); +} + +void tms3203x_device::tstb3_indind(UINT32 op) +{ + DECLARE_DEF; + UINT32 src1 = RMEM(INDIRECT_1_DEF(op, op >> 8)); + UINT32 src2 = RMEM(INDIRECT_1(op, op)); + UPDATE_DEF(); + TSTB(src1, src2); +} + +/*-----------------------------------------------------*/ + +void tms3203x_device::xor3_regreg(UINT32 op) +{ + UINT32 src1 = IREG((op >> 8) & 31); + UINT32 src2 = IREG(op & 31); + int dreg = (op >> 16) & 31; + XOR(dreg, src1, src2); +} + +void tms3203x_device::xor3_indreg(UINT32 op) +{ + UINT32 src1 = RMEM(INDIRECT_1(op, op >> 8)); + UINT32 src2 = IREG(op & 31); + int dreg = (op >> 16) & 31; + XOR(dreg, src1, src2); +} + +void tms3203x_device::xor3_regind(UINT32 op) +{ + UINT32 src2 = RMEM(INDIRECT_1(op, op)); + UINT32 src1 = IREG((op >> 8) & 31); + int dreg = (op >> 16) & 31; + XOR(dreg, src1, src2); +} + +void tms3203x_device::xor3_indind(UINT32 op) +{ + DECLARE_DEF; + UINT32 src1 = RMEM(INDIRECT_1_DEF(op, op >> 8)); + UINT32 src2 = RMEM(INDIRECT_1(op, op)); + int dreg = (op >> 16) & 31; + UPDATE_DEF(); + XOR(dreg, src1, src2); +} + +/*-----------------------------------------------------*/ + +void tms3203x_device::ldfu_reg(UINT32 op) +{ + m_r[(op >> 16) & 7] = m_r[op & 7]; +} + +void tms3203x_device::ldfu_dir(UINT32 op) +{ + UINT32 res = RMEM(DIRECT(op)); + int dreg = (op >> 16) & 7; + LONG2FP(dreg, res); +} + +void tms3203x_device::ldfu_ind(UINT32 op) +{ + UINT32 res = RMEM(INDIRECT_D(op, op >> 8)); + int dreg = (op >> 16) & 7; + LONG2FP(dreg, res); +} + +void tms3203x_device::ldfu_imm(UINT32 op) +{ + int dreg = (op >> 16) & 7; + SHORT2FP(dreg, op); +} + +/*-----------------------------------------------------*/ + +void tms3203x_device::ldflo_reg(UINT32 op) +{ + if (CONDITION_LO()) + m_r[(op >> 16) & 7] = m_r[op & 7]; +} + +void tms3203x_device::ldflo_dir(UINT32 op) +{ + if (CONDITION_LO()) + { + UINT32 res = RMEM(DIRECT(op)); + int dreg = (op >> 16) & 7; + LONG2FP(dreg, res); + } +} + +void tms3203x_device::ldflo_ind(UINT32 op) +{ + if (CONDITION_LO()) + { + UINT32 res = RMEM(INDIRECT_D(op, op >> 8)); + int dreg = (op >> 16) & 7; + LONG2FP(dreg, res); + } + else + INDIRECT_D(op, op >> 8); +} + +void tms3203x_device::ldflo_imm(UINT32 op) +{ + if (CONDITION_LO()) + { + int dreg = (op >> 16) & 7; + SHORT2FP(dreg, op); + } +} + +/*-----------------------------------------------------*/ + +void tms3203x_device::ldfls_reg(UINT32 op) +{ + if (CONDITION_LS()) + m_r[(op >> 16) & 7] = m_r[op & 7]; +} + +void tms3203x_device::ldfls_dir(UINT32 op) +{ + if (CONDITION_LS()) + { + UINT32 res = RMEM(DIRECT(op)); + int dreg = (op >> 16) & 7; + LONG2FP(dreg, res); + } +} + +void tms3203x_device::ldfls_ind(UINT32 op) +{ + if (CONDITION_LS()) + { + UINT32 res = RMEM(INDIRECT_D(op, op >> 8)); + int dreg = (op >> 16) & 7; + LONG2FP(dreg, res); + } + else + INDIRECT_D(op, op >> 8); +} + +void tms3203x_device::ldfls_imm(UINT32 op) +{ + if (CONDITION_LS()) + { + int dreg = (op >> 16) & 7; + SHORT2FP(dreg, op); + } +} + +/*-----------------------------------------------------*/ + +void tms3203x_device::ldfhi_reg(UINT32 op) +{ + if (CONDITION_HI()) + m_r[(op >> 16) & 7] = m_r[op & 7]; +} + +void tms3203x_device::ldfhi_dir(UINT32 op) +{ + if (CONDITION_HI()) + { + UINT32 res = RMEM(DIRECT(op)); + int dreg = (op >> 16) & 7; + LONG2FP(dreg, res); + } +} + +void tms3203x_device::ldfhi_ind(UINT32 op) +{ + if (CONDITION_HI()) + { + UINT32 res = RMEM(INDIRECT_D(op, op >> 8)); + int dreg = (op >> 16) & 7; + LONG2FP(dreg, res); + } + else + INDIRECT_D(op, op >> 8); +} + +void tms3203x_device::ldfhi_imm(UINT32 op) +{ + if (CONDITION_HI()) + { + int dreg = (op >> 16) & 7; + SHORT2FP(dreg, op); + } +} + +/*-----------------------------------------------------*/ + +void tms3203x_device::ldfhs_reg(UINT32 op) +{ + if (CONDITION_HS()) + m_r[(op >> 16) & 7] = m_r[op & 7]; +} + +void tms3203x_device::ldfhs_dir(UINT32 op) +{ + if (CONDITION_HS()) + { + UINT32 res = RMEM(DIRECT(op)); + int dreg = (op >> 16) & 7; + LONG2FP(dreg, res); + } +} + +void tms3203x_device::ldfhs_ind(UINT32 op) +{ + if (CONDITION_HS()) + { + UINT32 res = RMEM(INDIRECT_D(op, op >> 8)); + int dreg = (op >> 16) & 7; + LONG2FP(dreg, res); + } + else + INDIRECT_D(op, op >> 8); +} + +void tms3203x_device::ldfhs_imm(UINT32 op) +{ + if (CONDITION_HS()) + { + int dreg = (op >> 16) & 7; + SHORT2FP(dreg, op); + } +} + +/*-----------------------------------------------------*/ + +void tms3203x_device::ldfeq_reg(UINT32 op) +{ + if (CONDITION_EQ()) + m_r[(op >> 16) & 7] = m_r[op & 7]; +} + +void tms3203x_device::ldfeq_dir(UINT32 op) +{ + if (CONDITION_EQ()) + { + UINT32 res = RMEM(DIRECT(op)); + int dreg = (op >> 16) & 7; + LONG2FP(dreg, res); + } +} + +void tms3203x_device::ldfeq_ind(UINT32 op) +{ + if (CONDITION_EQ()) + { + UINT32 res = RMEM(INDIRECT_D(op, op >> 8)); + int dreg = (op >> 16) & 7; + LONG2FP(dreg, res); + } + else + INDIRECT_D(op, op >> 8); +} + +void tms3203x_device::ldfeq_imm(UINT32 op) +{ + if (CONDITION_EQ()) + { + int dreg = (op >> 16) & 7; + SHORT2FP(dreg, op); + } +} + +/*-----------------------------------------------------*/ + +void tms3203x_device::ldfne_reg(UINT32 op) +{ + if (CONDITION_NE()) + m_r[(op >> 16) & 7] = m_r[op & 7]; +} + +void tms3203x_device::ldfne_dir(UINT32 op) +{ + if (CONDITION_NE()) + { + UINT32 res = RMEM(DIRECT(op)); + int dreg = (op >> 16) & 7; + LONG2FP(dreg, res); + } +} + +void tms3203x_device::ldfne_ind(UINT32 op) +{ + if (CONDITION_NE()) + { + UINT32 res = RMEM(INDIRECT_D(op, op >> 8)); + int dreg = (op >> 16) & 7; + LONG2FP(dreg, res); + } + else + INDIRECT_D(op, op >> 8); +} + +void tms3203x_device::ldfne_imm(UINT32 op) +{ + if (CONDITION_NE()) + { + int dreg = (op >> 16) & 7; + SHORT2FP(dreg, op); + } +} + +/*-----------------------------------------------------*/ + +void tms3203x_device::ldflt_reg(UINT32 op) +{ + if (CONDITION_LT()) + m_r[(op >> 16) & 7] = m_r[op & 7]; +} + +void tms3203x_device::ldflt_dir(UINT32 op) +{ + if (CONDITION_LT()) + { + UINT32 res = RMEM(DIRECT(op)); + int dreg = (op >> 16) & 7; + LONG2FP(dreg, res); + } +} + +void tms3203x_device::ldflt_ind(UINT32 op) +{ + if (CONDITION_LT()) + { + UINT32 res = RMEM(INDIRECT_D(op, op >> 8)); + int dreg = (op >> 16) & 7; + LONG2FP(dreg, res); + } + else + INDIRECT_D(op, op >> 8); +} + +void tms3203x_device::ldflt_imm(UINT32 op) +{ + if (CONDITION_LT()) + { + int dreg = (op >> 16) & 7; + SHORT2FP(dreg, op); + } +} + +/*-----------------------------------------------------*/ + +void tms3203x_device::ldfle_reg(UINT32 op) +{ + if (CONDITION_LE()) + m_r[(op >> 16) & 7] = m_r[op & 7]; +} + +void tms3203x_device::ldfle_dir(UINT32 op) +{ + if (CONDITION_LE()) + { + UINT32 res = RMEM(DIRECT(op)); + int dreg = (op >> 16) & 7; + LONG2FP(dreg, res); + } +} + +void tms3203x_device::ldfle_ind(UINT32 op) +{ + if (CONDITION_LE()) + { + UINT32 res = RMEM(INDIRECT_D(op, op >> 8)); + int dreg = (op >> 16) & 7; + LONG2FP(dreg, res); + } + else + INDIRECT_D(op, op >> 8); +} + +void tms3203x_device::ldfle_imm(UINT32 op) +{ + if (CONDITION_LE()) + { + int dreg = (op >> 16) & 7; + SHORT2FP(dreg, op); + } +} + +/*-----------------------------------------------------*/ + +void tms3203x_device::ldfgt_reg(UINT32 op) +{ + if (CONDITION_GT()) + m_r[(op >> 16) & 7] = m_r[op & 7]; +} + +void tms3203x_device::ldfgt_dir(UINT32 op) +{ + if (CONDITION_GT()) + { + UINT32 res = RMEM(DIRECT(op)); + int dreg = (op >> 16) & 7; + LONG2FP(dreg, res); + } +} + +void tms3203x_device::ldfgt_ind(UINT32 op) +{ + if (CONDITION_GT()) + { + UINT32 res = RMEM(INDIRECT_D(op, op >> 8)); + int dreg = (op >> 16) & 7; + LONG2FP(dreg, res); + } + else + INDIRECT_D(op, op >> 8); +} + +void tms3203x_device::ldfgt_imm(UINT32 op) +{ + if (CONDITION_GT()) + { + int dreg = (op >> 16) & 7; + SHORT2FP(dreg, op); + } +} + +/*-----------------------------------------------------*/ + +void tms3203x_device::ldfge_reg(UINT32 op) +{ + if (CONDITION_GE()) + m_r[(op >> 16) & 7] = m_r[op & 7]; +} + +void tms3203x_device::ldfge_dir(UINT32 op) +{ + if (CONDITION_GE()) + { + UINT32 res = RMEM(DIRECT(op)); + int dreg = (op >> 16) & 7; + LONG2FP(dreg, res); + } +} + +void tms3203x_device::ldfge_ind(UINT32 op) +{ + if (CONDITION_GE()) + { + UINT32 res = RMEM(INDIRECT_D(op, op >> 8)); + int dreg = (op >> 16) & 7; + LONG2FP(dreg, res); + } + else + INDIRECT_D(op, op >> 8); +} + +void tms3203x_device::ldfge_imm(UINT32 op) +{ + if (CONDITION_GE()) + { + int dreg = (op >> 16) & 7; + SHORT2FP(dreg, op); + } +} + +/*-----------------------------------------------------*/ + +void tms3203x_device::ldfnv_reg(UINT32 op) +{ + if (CONDITION_NV()) + m_r[(op >> 16) & 7] = m_r[op & 7]; +} + +void tms3203x_device::ldfnv_dir(UINT32 op) +{ + if (CONDITION_NV()) + { + UINT32 res = RMEM(DIRECT(op)); + int dreg = (op >> 16) & 7; + LONG2FP(dreg, res); + } +} + +void tms3203x_device::ldfnv_ind(UINT32 op) +{ + if (CONDITION_NV()) + { + UINT32 res = RMEM(INDIRECT_D(op, op >> 8)); + int dreg = (op >> 16) & 7; + LONG2FP(dreg, res); + } + else + INDIRECT_D(op, op >> 8); +} + +void tms3203x_device::ldfnv_imm(UINT32 op) +{ + if (CONDITION_NV()) + { + int dreg = (op >> 16) & 7; + SHORT2FP(dreg, op); + } +} + +/*-----------------------------------------------------*/ + +void tms3203x_device::ldfv_reg(UINT32 op) +{ + if (CONDITION_V()) + m_r[(op >> 16) & 7] = m_r[op & 7]; +} + +void tms3203x_device::ldfv_dir(UINT32 op) +{ + if (CONDITION_V()) + { + UINT32 res = RMEM(DIRECT(op)); + int dreg = (op >> 16) & 7; + LONG2FP(dreg, res); + } +} + +void tms3203x_device::ldfv_ind(UINT32 op) +{ + if (CONDITION_V()) + { + UINT32 res = RMEM(INDIRECT_D(op, op >> 8)); + int dreg = (op >> 16) & 7; + LONG2FP(dreg, res); + } + else + INDIRECT_D(op, op >> 8); +} + +void tms3203x_device::ldfv_imm(UINT32 op) +{ + if (CONDITION_V()) + { + int dreg = (op >> 16) & 7; + SHORT2FP(dreg, op); + } +} + +/*-----------------------------------------------------*/ + +void tms3203x_device::ldfnuf_reg(UINT32 op) +{ + if (CONDITION_NUF()) + m_r[(op >> 16) & 7] = m_r[op & 7]; +} + +void tms3203x_device::ldfnuf_dir(UINT32 op) +{ + if (CONDITION_NUF()) + { + UINT32 res = RMEM(DIRECT(op)); + int dreg = (op >> 16) & 7; + LONG2FP(dreg, res); + } +} + +void tms3203x_device::ldfnuf_ind(UINT32 op) +{ + if (CONDITION_NUF()) + { + UINT32 res = RMEM(INDIRECT_D(op, op >> 8)); + int dreg = (op >> 16) & 7; + LONG2FP(dreg, res); + } + else + INDIRECT_D(op, op >> 8); +} + +void tms3203x_device::ldfnuf_imm(UINT32 op) +{ + if (CONDITION_NUF()) + { + int dreg = (op >> 16) & 7; + SHORT2FP(dreg, op); + } +} + +/*-----------------------------------------------------*/ + +void tms3203x_device::ldfuf_reg(UINT32 op) +{ + if (CONDITION_UF()) + m_r[(op >> 16) & 7] = m_r[op & 7]; +} + +void tms3203x_device::ldfuf_dir(UINT32 op) +{ + if (CONDITION_UF()) + { + UINT32 res = RMEM(DIRECT(op)); + int dreg = (op >> 16) & 7; + LONG2FP(dreg, res); + } +} + +void tms3203x_device::ldfuf_ind(UINT32 op) +{ + if (CONDITION_UF()) + { + UINT32 res = RMEM(INDIRECT_D(op, op >> 8)); + int dreg = (op >> 16) & 7; + LONG2FP(dreg, res); + } + else + INDIRECT_D(op, op >> 8); +} + +void tms3203x_device::ldfuf_imm(UINT32 op) +{ + if (CONDITION_UF()) + { + int dreg = (op >> 16) & 7; + SHORT2FP(dreg, op); + } +} + +/*-----------------------------------------------------*/ + +void tms3203x_device::ldfnlv_reg(UINT32 op) +{ + if (CONDITION_NLV()) + m_r[(op >> 16) & 7] = m_r[op & 7]; +} + +void tms3203x_device::ldfnlv_dir(UINT32 op) +{ + if (CONDITION_NLV()) + { + UINT32 res = RMEM(DIRECT(op)); + int dreg = (op >> 16) & 7; + LONG2FP(dreg, res); + } +} + +void tms3203x_device::ldfnlv_ind(UINT32 op) +{ + if (CONDITION_NLV()) + { + UINT32 res = RMEM(INDIRECT_D(op, op >> 8)); + int dreg = (op >> 16) & 7; + LONG2FP(dreg, res); + } + else + INDIRECT_D(op, op >> 8); +} + +void tms3203x_device::ldfnlv_imm(UINT32 op) +{ + if (CONDITION_NLV()) + { + int dreg = (op >> 16) & 7; + SHORT2FP(dreg, op); + } +} + +/*-----------------------------------------------------*/ + +void tms3203x_device::ldflv_reg(UINT32 op) +{ + if (CONDITION_LV()) + m_r[(op >> 16) & 7] = m_r[op & 7]; +} + +void tms3203x_device::ldflv_dir(UINT32 op) +{ + if (CONDITION_LV()) + { + UINT32 res = RMEM(DIRECT(op)); + int dreg = (op >> 16) & 7; + LONG2FP(dreg, res); + } +} + +void tms3203x_device::ldflv_ind(UINT32 op) +{ + if (CONDITION_LV()) + { + UINT32 res = RMEM(INDIRECT_D(op, op >> 8)); + int dreg = (op >> 16) & 7; + LONG2FP(dreg, res); + } + else + INDIRECT_D(op, op >> 8); +} + +void tms3203x_device::ldflv_imm(UINT32 op) +{ + if (CONDITION_LV()) + { + int dreg = (op >> 16) & 7; + SHORT2FP(dreg, op); + } +} + +/*-----------------------------------------------------*/ + +void tms3203x_device::ldfnluf_reg(UINT32 op) +{ + if (CONDITION_NLUF()) + m_r[(op >> 16) & 7] = m_r[op & 7]; +} + +void tms3203x_device::ldfnluf_dir(UINT32 op) +{ + if (CONDITION_NLUF()) + { + UINT32 res = RMEM(DIRECT(op)); + int dreg = (op >> 16) & 7; + LONG2FP(dreg, res); + } +} + +void tms3203x_device::ldfnluf_ind(UINT32 op) +{ + if (CONDITION_NLUF()) + { + UINT32 res = RMEM(INDIRECT_D(op, op >> 8)); + int dreg = (op >> 16) & 7; + LONG2FP(dreg, res); + } + else + INDIRECT_D(op, op >> 8); +} + +void tms3203x_device::ldfnluf_imm(UINT32 op) +{ + if (CONDITION_NLUF()) + { + int dreg = (op >> 16) & 7; + SHORT2FP(dreg, op); + } +} + +/*-----------------------------------------------------*/ + +void tms3203x_device::ldfluf_reg(UINT32 op) +{ + if (CONDITION_LUF()) + m_r[(op >> 16) & 7] = m_r[op & 7]; +} + +void tms3203x_device::ldfluf_dir(UINT32 op) +{ + if (CONDITION_LUF()) + { + UINT32 res = RMEM(DIRECT(op)); + int dreg = (op >> 16) & 7; + LONG2FP(dreg, res); + } +} + +void tms3203x_device::ldfluf_ind(UINT32 op) +{ + if (CONDITION_LUF()) + { + UINT32 res = RMEM(INDIRECT_D(op, op >> 8)); + int dreg = (op >> 16) & 7; + LONG2FP(dreg, res); + } + else + INDIRECT_D(op, op >> 8); +} + +void tms3203x_device::ldfluf_imm(UINT32 op) +{ + if (CONDITION_LUF()) + { + int dreg = (op >> 16) & 7; + SHORT2FP(dreg, op); + } +} + +/*-----------------------------------------------------*/ + +void tms3203x_device::ldfzuf_reg(UINT32 op) +{ + if (CONDITION_ZUF()) + m_r[(op >> 16) & 7] = m_r[op & 7]; +} + +void tms3203x_device::ldfzuf_dir(UINT32 op) +{ + if (CONDITION_ZUF()) + { + UINT32 res = RMEM(DIRECT(op)); + int dreg = (op >> 16) & 7; + LONG2FP(dreg, res); + } +} + +void tms3203x_device::ldfzuf_ind(UINT32 op) +{ + if (CONDITION_ZUF()) + { + UINT32 res = RMEM(INDIRECT_D(op, op >> 8)); + int dreg = (op >> 16) & 7; + LONG2FP(dreg, res); + } + else + INDIRECT_D(op, op >> 8); +} + +void tms3203x_device::ldfzuf_imm(UINT32 op) +{ + if (CONDITION_ZUF()) + { + int dreg = (op >> 16) & 7; + SHORT2FP(dreg, op); + } +} + +/*-----------------------------------------------------*/ + +void tms3203x_device::ldiu_reg(UINT32 op) +{ + int dreg = (op >> 16) & 31; + IREG(dreg) = IREG(op & 31); + if (dreg >= TMR_BK) + update_special(dreg); +} + +void tms3203x_device::ldiu_dir(UINT32 op) +{ + int dreg = (op >> 16) & 31; + IREG(dreg) = RMEM(DIRECT(op)); + if (dreg >= TMR_BK) + update_special(dreg); +} + +void tms3203x_device::ldiu_ind(UINT32 op) +{ + int dreg = (op >> 16) & 31; + IREG(dreg) = RMEM(INDIRECT_D(op, op >> 8)); + if (dreg >= TMR_BK) + update_special(dreg); +} + +void tms3203x_device::ldiu_imm(UINT32 op) +{ + int dreg = (op >> 16) & 31; + IREG(dreg) = (INT16)op; + if (dreg >= TMR_BK) + update_special(dreg); +} + +/*-----------------------------------------------------*/ + +void tms3203x_device::ldilo_reg(UINT32 op) +{ + if (CONDITION_LO()) + { + int dreg = (op >> 16) & 31; + IREG(dreg) = IREG(op & 31); + if (dreg >= TMR_BK) + update_special(dreg); + } +} + +void tms3203x_device::ldilo_dir(UINT32 op) +{ + UINT32 val = RMEM(DIRECT(op)); + if (CONDITION_LO()) + { + int dreg = (op >> 16) & 31; + IREG(dreg) = val; + if (dreg >= TMR_BK) + update_special(dreg); + } +} + +void tms3203x_device::ldilo_ind(UINT32 op) +{ + UINT32 val = RMEM(INDIRECT_D(op, op >> 8)); + if (CONDITION_LO()) + { + int dreg = (op >> 16) & 31; + IREG(dreg) = val; + if (dreg >= TMR_BK) + update_special(dreg); + } +} + +void tms3203x_device::ldilo_imm(UINT32 op) +{ + if (CONDITION_LO()) + { + int dreg = (op >> 16) & 31; + IREG(dreg) = (INT16)op; + if (dreg >= TMR_BK) + update_special(dreg); + } +} + +/*-----------------------------------------------------*/ + +void tms3203x_device::ldils_reg(UINT32 op) +{ + if (CONDITION_LS()) + { + int dreg = (op >> 16) & 31; + IREG(dreg) = IREG(op & 31); + if (dreg >= TMR_BK) + update_special(dreg); + } +} + +void tms3203x_device::ldils_dir(UINT32 op) +{ + UINT32 val = RMEM(DIRECT(op)); + if (CONDITION_LS()) + { + int dreg = (op >> 16) & 31; + IREG(dreg) = val; + if (dreg >= TMR_BK) + update_special(dreg); + } +} + +void tms3203x_device::ldils_ind(UINT32 op) +{ + UINT32 val = RMEM(INDIRECT_D(op, op >> 8)); + if (CONDITION_LS()) + { + int dreg = (op >> 16) & 31; + IREG(dreg) = val; + if (dreg >= TMR_BK) + update_special(dreg); + } +} + +void tms3203x_device::ldils_imm(UINT32 op) +{ + if (CONDITION_LS()) + { + int dreg = (op >> 16) & 31; + IREG(dreg) = (INT16)op; + if (dreg >= TMR_BK) + update_special(dreg); + } +} + +/*-----------------------------------------------------*/ + +void tms3203x_device::ldihi_reg(UINT32 op) +{ + if (CONDITION_HI()) + { + int dreg = (op >> 16) & 31; + IREG(dreg) = IREG(op & 31); + if (dreg >= TMR_BK) + update_special(dreg); + } +} + +void tms3203x_device::ldihi_dir(UINT32 op) +{ + UINT32 val = RMEM(DIRECT(op)); + if (CONDITION_HI()) + { + int dreg = (op >> 16) & 31; + IREG(dreg) = val; + if (dreg >= TMR_BK) + update_special(dreg); + } +} + +void tms3203x_device::ldihi_ind(UINT32 op) +{ + UINT32 val = RMEM(INDIRECT_D(op, op >> 8)); + if (CONDITION_HI()) + { + int dreg = (op >> 16) & 31; + IREG(dreg) = val; + if (dreg >= TMR_BK) + update_special(dreg); + } +} + +void tms3203x_device::ldihi_imm(UINT32 op) +{ + if (CONDITION_HI()) + { + int dreg = (op >> 16) & 31; + IREG(dreg) = (INT16)op; + if (dreg >= TMR_BK) + update_special(dreg); + } +} + +/*-----------------------------------------------------*/ + +void tms3203x_device::ldihs_reg(UINT32 op) +{ + if (CONDITION_HS()) + { + int dreg = (op >> 16) & 31; + IREG(dreg) = IREG(op & 31); + if (dreg >= TMR_BK) + update_special(dreg); + } +} + +void tms3203x_device::ldihs_dir(UINT32 op) +{ + UINT32 val = RMEM(DIRECT(op)); + if (CONDITION_HS()) + { + int dreg = (op >> 16) & 31; + IREG(dreg) = val; + if (dreg >= TMR_BK) + update_special(dreg); + } +} + +void tms3203x_device::ldihs_ind(UINT32 op) +{ + UINT32 val = RMEM(INDIRECT_D(op, op >> 8)); + if (CONDITION_HS()) + { + int dreg = (op >> 16) & 31; + IREG(dreg) = val; + if (dreg >= TMR_BK) + update_special(dreg); + } +} + +void tms3203x_device::ldihs_imm(UINT32 op) +{ + if (CONDITION_HS()) + { + int dreg = (op >> 16) & 31; + IREG(dreg) = (INT16)op; + if (dreg >= TMR_BK) + update_special(dreg); + } +} + +/*-----------------------------------------------------*/ + +void tms3203x_device::ldieq_reg(UINT32 op) +{ + if (CONDITION_EQ()) + { + int dreg = (op >> 16) & 31; + IREG(dreg) = IREG(op & 31); + if (dreg >= TMR_BK) + update_special(dreg); + } +} + +void tms3203x_device::ldieq_dir(UINT32 op) +{ + UINT32 val = RMEM(DIRECT(op)); + if (CONDITION_EQ()) + { + int dreg = (op >> 16) & 31; + IREG(dreg) = val; + if (dreg >= TMR_BK) + update_special(dreg); + } +} + +void tms3203x_device::ldieq_ind(UINT32 op) +{ + UINT32 val = RMEM(INDIRECT_D(op, op >> 8)); + if (CONDITION_EQ()) + { + int dreg = (op >> 16) & 31; + IREG(dreg) = val; + if (dreg >= TMR_BK) + update_special(dreg); + } +} + +void tms3203x_device::ldieq_imm(UINT32 op) +{ + if (CONDITION_EQ()) + { + int dreg = (op >> 16) & 31; + IREG(dreg) = (INT16)op; + if (dreg >= TMR_BK) + update_special(dreg); + } +} + +/*-----------------------------------------------------*/ + +void tms3203x_device::ldine_reg(UINT32 op) +{ + if (CONDITION_NE()) + { + int dreg = (op >> 16) & 31; + IREG(dreg) = IREG(op & 31); + if (dreg >= TMR_BK) + update_special(dreg); + } +} + +void tms3203x_device::ldine_dir(UINT32 op) +{ + UINT32 val = RMEM(DIRECT(op)); + if (CONDITION_NE()) + { + int dreg = (op >> 16) & 31; + IREG(dreg) = val; + if (dreg >= TMR_BK) + update_special(dreg); + } +} + +void tms3203x_device::ldine_ind(UINT32 op) +{ + UINT32 val = RMEM(INDIRECT_D(op, op >> 8)); + if (CONDITION_NE()) + { + int dreg = (op >> 16) & 31; + IREG(dreg) = val; + if (dreg >= TMR_BK) + update_special(dreg); + } +} + +void tms3203x_device::ldine_imm(UINT32 op) +{ + if (CONDITION_NE()) + { + int dreg = (op >> 16) & 31; + IREG(dreg) = (INT16)op; + if (dreg >= TMR_BK) + update_special(dreg); + } +} + +/*-----------------------------------------------------*/ + +void tms3203x_device::ldilt_reg(UINT32 op) +{ + if (CONDITION_LT()) + { + int dreg = (op >> 16) & 31; + IREG(dreg) = IREG(op & 31); + if (dreg >= TMR_BK) + update_special(dreg); + } +} + +void tms3203x_device::ldilt_dir(UINT32 op) +{ + UINT32 val = RMEM(DIRECT(op)); + if (CONDITION_LT()) + { + int dreg = (op >> 16) & 31; + IREG(dreg) = val; + if (dreg >= TMR_BK) + update_special(dreg); + } +} + +void tms3203x_device::ldilt_ind(UINT32 op) +{ + UINT32 val = RMEM(INDIRECT_D(op, op >> 8)); + if (CONDITION_LT()) + { + int dreg = (op >> 16) & 31; + IREG(dreg) = val; + if (dreg >= TMR_BK) + update_special(dreg); + } +} + +void tms3203x_device::ldilt_imm(UINT32 op) +{ + if (CONDITION_LT()) + { + int dreg = (op >> 16) & 31; + IREG(dreg) = (INT16)op; + if (dreg >= TMR_BK) + update_special(dreg); + } +} + +/*-----------------------------------------------------*/ + +void tms3203x_device::ldile_reg(UINT32 op) +{ + if (CONDITION_LE()) + { + int dreg = (op >> 16) & 31; + IREG(dreg) = IREG(op & 31); + if (dreg >= TMR_BK) + update_special(dreg); + } +} + +void tms3203x_device::ldile_dir(UINT32 op) +{ + UINT32 val = RMEM(DIRECT(op)); + if (CONDITION_LE()) + { + int dreg = (op >> 16) & 31; + IREG(dreg) = val; + if (dreg >= TMR_BK) + update_special(dreg); + } +} + +void tms3203x_device::ldile_ind(UINT32 op) +{ + UINT32 val = RMEM(INDIRECT_D(op, op >> 8)); + if (CONDITION_LE()) + { + int dreg = (op >> 16) & 31; + IREG(dreg) = val; + if (dreg >= TMR_BK) + update_special(dreg); + } +} + +void tms3203x_device::ldile_imm(UINT32 op) +{ + if (CONDITION_LE()) + { + int dreg = (op >> 16) & 31; + IREG(dreg) = (INT16)op; + if (dreg >= TMR_BK) + update_special(dreg); + } +} + +/*-----------------------------------------------------*/ + +void tms3203x_device::ldigt_reg(UINT32 op) +{ + if (CONDITION_GT()) + { + int dreg = (op >> 16) & 31; + IREG(dreg) = IREG(op & 31); + if (dreg >= TMR_BK) + update_special(dreg); + } +} + +void tms3203x_device::ldigt_dir(UINT32 op) +{ + UINT32 val = RMEM(DIRECT(op)); + if (CONDITION_GT()) + { + int dreg = (op >> 16) & 31; + IREG(dreg) = val; + if (dreg >= TMR_BK) + update_special(dreg); + } +} + +void tms3203x_device::ldigt_ind(UINT32 op) +{ + UINT32 val = RMEM(INDIRECT_D(op, op >> 8)); + if (CONDITION_GT()) + { + int dreg = (op >> 16) & 31; + IREG(dreg) = val; + if (dreg >= TMR_BK) + update_special(dreg); + } +} + +void tms3203x_device::ldigt_imm(UINT32 op) +{ + if (CONDITION_GT()) + { + int dreg = (op >> 16) & 31; + IREG(dreg) = (INT16)op; + if (dreg >= TMR_BK) + update_special(dreg); + } +} + +/*-----------------------------------------------------*/ + +void tms3203x_device::ldige_reg(UINT32 op) +{ + if (CONDITION_GE()) + { + int dreg = (op >> 16) & 31; + IREG(dreg) = IREG(op & 31); + if (dreg >= TMR_BK) + update_special(dreg); + } +} + +void tms3203x_device::ldige_dir(UINT32 op) +{ + UINT32 val = RMEM(DIRECT(op)); + if (CONDITION_GE()) + { + int dreg = (op >> 16) & 31; + IREG(dreg) = val; + if (dreg >= TMR_BK) + update_special(dreg); + } +} + +void tms3203x_device::ldige_ind(UINT32 op) +{ + UINT32 val = RMEM(INDIRECT_D(op, op >> 8)); + if (CONDITION_GE()) + { + int dreg = (op >> 16) & 31; + IREG(dreg) = val; + if (dreg >= TMR_BK) + update_special(dreg); + } +} + +void tms3203x_device::ldige_imm(UINT32 op) +{ + if (CONDITION_GE()) + { + int dreg = (op >> 16) & 31; + IREG(dreg) = (INT16)op; + if (dreg >= TMR_BK) + update_special(dreg); + } +} + +/*-----------------------------------------------------*/ + +void tms3203x_device::ldinv_reg(UINT32 op) +{ + if (CONDITION_NV()) + { + int dreg = (op >> 16) & 31; + IREG(dreg) = IREG(op & 31); + if (dreg >= TMR_BK) + update_special(dreg); + } +} + +void tms3203x_device::ldinv_dir(UINT32 op) +{ + UINT32 val = RMEM(DIRECT(op)); + if (CONDITION_NV()) + { + int dreg = (op >> 16) & 31; + IREG(dreg) = val; + if (dreg >= TMR_BK) + update_special(dreg); + } +} + +void tms3203x_device::ldinv_ind(UINT32 op) +{ + UINT32 val = RMEM(INDIRECT_D(op, op >> 8)); + if (CONDITION_NV()) + { + int dreg = (op >> 16) & 31; + IREG(dreg) = val; + if (dreg >= TMR_BK) + update_special(dreg); + } +} + +void tms3203x_device::ldinv_imm(UINT32 op) +{ + if (CONDITION_NV()) + { + int dreg = (op >> 16) & 31; + IREG(dreg) = (INT16)op; + if (dreg >= TMR_BK) + update_special(dreg); + } +} + +/*-----------------------------------------------------*/ + +void tms3203x_device::ldiuf_reg(UINT32 op) +{ + if (CONDITION_UF()) + { + int dreg = (op >> 16) & 31; + IREG(dreg) = IREG(op & 31); + if (dreg >= TMR_BK) + update_special(dreg); + } +} + +void tms3203x_device::ldiuf_dir(UINT32 op) +{ + UINT32 val = RMEM(DIRECT(op)); + if (CONDITION_UF()) + { + int dreg = (op >> 16) & 31; + IREG(dreg) = val; + if (dreg >= TMR_BK) + update_special(dreg); + } +} + +void tms3203x_device::ldiuf_ind(UINT32 op) +{ + UINT32 val = RMEM(INDIRECT_D(op, op >> 8)); + if (CONDITION_UF()) + { + int dreg = (op >> 16) & 31; + IREG(dreg) = val; + if (dreg >= TMR_BK) + update_special(dreg); + } +} + +void tms3203x_device::ldiuf_imm(UINT32 op) +{ + if (CONDITION_UF()) + { + int dreg = (op >> 16) & 31; + IREG(dreg) = (INT16)op; + if (dreg >= TMR_BK) + update_special(dreg); + } +} + +/*-----------------------------------------------------*/ + +void tms3203x_device::ldinuf_reg(UINT32 op) +{ + if (CONDITION_NUF()) + { + int dreg = (op >> 16) & 31; + IREG(dreg) = IREG(op & 31); + if (dreg >= TMR_BK) + update_special(dreg); + } +} + +void tms3203x_device::ldinuf_dir(UINT32 op) +{ + UINT32 val = RMEM(DIRECT(op)); + if (CONDITION_NUF()) + { + int dreg = (op >> 16) & 31; + IREG(dreg) = val; + if (dreg >= TMR_BK) + update_special(dreg); + } +} + +void tms3203x_device::ldinuf_ind(UINT32 op) +{ + UINT32 val = RMEM(INDIRECT_D(op, op >> 8)); + if (CONDITION_NUF()) + { + int dreg = (op >> 16) & 31; + IREG(dreg) = val; + if (dreg >= TMR_BK) + update_special(dreg); + } +} + +void tms3203x_device::ldinuf_imm(UINT32 op) +{ + if (CONDITION_NUF()) + { + int dreg = (op >> 16) & 31; + IREG(dreg) = (INT16)op; + if (dreg >= TMR_BK) + update_special(dreg); + } +} + +/*-----------------------------------------------------*/ + +void tms3203x_device::ldiv_reg(UINT32 op) +{ + if (CONDITION_V()) + { + int dreg = (op >> 16) & 31; + IREG(dreg) = IREG(op & 31); + if (dreg >= TMR_BK) + update_special(dreg); + } +} + +void tms3203x_device::ldiv_dir(UINT32 op) +{ + UINT32 val = RMEM(DIRECT(op)); + if (CONDITION_V()) + { + int dreg = (op >> 16) & 31; + IREG(dreg) = val; + if (dreg >= TMR_BK) + update_special(dreg); + } +} + +void tms3203x_device::ldiv_ind(UINT32 op) +{ + UINT32 val = RMEM(INDIRECT_D(op, op >> 8)); + if (CONDITION_V()) + { + int dreg = (op >> 16) & 31; + IREG(dreg) = val; + if (dreg >= TMR_BK) + update_special(dreg); + } +} + +void tms3203x_device::ldiv_imm(UINT32 op) +{ + if (CONDITION_V()) + { + int dreg = (op >> 16) & 31; + IREG(dreg) = (INT16)op; + if (dreg >= TMR_BK) + update_special(dreg); + } +} + +/*-----------------------------------------------------*/ + +void tms3203x_device::ldinlv_reg(UINT32 op) +{ + if (CONDITION_NLV()) + { + int dreg = (op >> 16) & 31; + IREG(dreg) = IREG(op & 31); + if (dreg >= TMR_BK) + update_special(dreg); + } +} + +void tms3203x_device::ldinlv_dir(UINT32 op) +{ + UINT32 val = RMEM(DIRECT(op)); + if (CONDITION_NLV()) + { + int dreg = (op >> 16) & 31; + IREG(dreg) = val; + if (dreg >= TMR_BK) + update_special(dreg); + } +} + +void tms3203x_device::ldinlv_ind(UINT32 op) +{ + UINT32 val = RMEM(INDIRECT_D(op, op >> 8)); + if (CONDITION_NLV()) + { + int dreg = (op >> 16) & 31; + IREG(dreg) = val; + if (dreg >= TMR_BK) + update_special(dreg); + } +} + +void tms3203x_device::ldinlv_imm(UINT32 op) +{ + if (CONDITION_NLV()) + { + int dreg = (op >> 16) & 31; + IREG(dreg) = (INT16)op; + if (dreg >= TMR_BK) + update_special(dreg); + } +} + +/*-----------------------------------------------------*/ + +void tms3203x_device::ldilv_reg(UINT32 op) +{ + if (CONDITION_LV()) + { + int dreg = (op >> 16) & 31; + IREG(dreg) = IREG(op & 31); + if (dreg >= TMR_BK) + update_special(dreg); + } +} + +void tms3203x_device::ldilv_dir(UINT32 op) +{ + UINT32 val = RMEM(DIRECT(op)); + if (CONDITION_LV()) + { + int dreg = (op >> 16) & 31; + IREG(dreg) = val; + if (dreg >= TMR_BK) + update_special(dreg); + } +} + +void tms3203x_device::ldilv_ind(UINT32 op) +{ + UINT32 val = RMEM(INDIRECT_D(op, op >> 8)); + if (CONDITION_LV()) + { + int dreg = (op >> 16) & 31; + IREG(dreg) = val; + if (dreg >= TMR_BK) + update_special(dreg); + } +} + +void tms3203x_device::ldilv_imm(UINT32 op) +{ + if (CONDITION_LV()) + { + int dreg = (op >> 16) & 31; + IREG(dreg) = (INT16)op; + if (dreg >= TMR_BK) + update_special(dreg); + } +} + +/*-----------------------------------------------------*/ + +void tms3203x_device::ldinluf_reg(UINT32 op) +{ + if (CONDITION_NLUF()) + { + int dreg = (op >> 16) & 31; + IREG(dreg) = IREG(op & 31); + if (dreg >= TMR_BK) + update_special(dreg); + } +} + +void tms3203x_device::ldinluf_dir(UINT32 op) +{ + UINT32 val = RMEM(DIRECT(op)); + if (CONDITION_NLUF()) + { + int dreg = (op >> 16) & 31; + IREG(dreg) = val; + if (dreg >= TMR_BK) + update_special(dreg); + } +} + +void tms3203x_device::ldinluf_ind(UINT32 op) +{ + UINT32 val = RMEM(INDIRECT_D(op, op >> 8)); + if (CONDITION_NLUF()) + { + int dreg = (op >> 16) & 31; + IREG(dreg) = val; + if (dreg >= TMR_BK) + update_special(dreg); + } +} + +void tms3203x_device::ldinluf_imm(UINT32 op) +{ + if (CONDITION_NLUF()) + { + int dreg = (op >> 16) & 31; + IREG(dreg) = (INT16)op; + if (dreg >= TMR_BK) + update_special(dreg); + } +} + +/*-----------------------------------------------------*/ + +void tms3203x_device::ldiluf_reg(UINT32 op) +{ + if (CONDITION_LUF()) + { + int dreg = (op >> 16) & 31; + IREG(dreg) = IREG(op & 31); + if (dreg >= TMR_BK) + update_special(dreg); + } +} + +void tms3203x_device::ldiluf_dir(UINT32 op) +{ + UINT32 val = RMEM(DIRECT(op)); + if (CONDITION_LUF()) + { + int dreg = (op >> 16) & 31; + IREG(dreg) = val; + if (dreg >= TMR_BK) + update_special(dreg); + } +} + +void tms3203x_device::ldiluf_ind(UINT32 op) +{ + UINT32 val = RMEM(INDIRECT_D(op, op >> 8)); + if (CONDITION_LUF()) + { + int dreg = (op >> 16) & 31; + IREG(dreg) = val; + if (dreg >= TMR_BK) + update_special(dreg); + } +} + +void tms3203x_device::ldiluf_imm(UINT32 op) +{ + if (CONDITION_LUF()) + { + int dreg = (op >> 16) & 31; + IREG(dreg) = (INT16)op; + if (dreg >= TMR_BK) + update_special(dreg); + } +} + +/*-----------------------------------------------------*/ + +void tms3203x_device::ldizuf_reg(UINT32 op) +{ + if (CONDITION_ZUF()) + { + int dreg = (op >> 16) & 31; + IREG(dreg) = IREG(op & 31); + if (dreg >= TMR_BK) + update_special(dreg); + } +} + +void tms3203x_device::ldizuf_dir(UINT32 op) +{ + UINT32 val = RMEM(DIRECT(op)); + if (CONDITION_ZUF()) + { + int dreg = (op >> 16) & 31; + IREG(dreg) = val; + if (dreg >= TMR_BK) + update_special(dreg); + } +} + +void tms3203x_device::ldizuf_ind(UINT32 op) +{ + UINT32 val = RMEM(INDIRECT_D(op, op >> 8)); + if (CONDITION_ZUF()) + { + int dreg = (op >> 16) & 31; + IREG(dreg) = val; + if (dreg >= TMR_BK) + update_special(dreg); + } +} + +void tms3203x_device::ldizuf_imm(UINT32 op) +{ + if (CONDITION_ZUF()) + { + int dreg = (op >> 16) & 31; + IREG(dreg) = (INT16)op; + if (dreg >= TMR_BK) + update_special(dreg); + } +} + +/*-----------------------------------------------------*/ + +inline void tms3203x_device::execute_delayed(UINT32 newpc) +{ + m_delayed = true; + + if ((machine().debug_flags & DEBUG_FLAG_ENABLED) == 0) + { + execute_one(); + execute_one(); + execute_one(); + } + else + { + debugger_instruction_hook(this, m_pc); + execute_one(); + debugger_instruction_hook(this, m_pc); + execute_one(); + debugger_instruction_hook(this, m_pc); + execute_one(); + } + + if (newpc != ~0) + m_pc = newpc; + + m_delayed = false; + if (m_irq_pending) + { + m_irq_pending = false; + check_irqs(); + } +} + +/*-----------------------------------------------------*/ + +void tms3203x_device::br_imm(UINT32 op) +{ + m_pc = op & 0xffffff; + m_icount -= 3*2; +} + +void tms3203x_device::brd_imm(UINT32 op) +{ + execute_delayed(op & 0xffffff); +} + +/*-----------------------------------------------------*/ + +void tms3203x_device::call_imm(UINT32 op) +{ + WMEM(++IREG(TMR_SP), m_pc); + m_pc = op & 0xffffff; + m_icount -= 3*2; +} + +/*-----------------------------------------------------*/ + +void tms3203x_device::rptb_imm(UINT32 op) +{ + IREG(TMR_RS) = m_pc; + IREG(TMR_RE) = op & 0xffffff; + IREG(TMR_ST) |= RMFLAG; + m_icount -= 3*2; +} + +/*-----------------------------------------------------*/ + +void tms3203x_device::swi(UINT32 op) { unimplemented(op); } + +/*-----------------------------------------------------*/ + +void tms3203x_device::brc_reg(UINT32 op) +{ + if (condition(op >> 16)) + { + m_pc = IREG(op & 31); + m_icount -= 3*2; + } +} + +void tms3203x_device::brcd_reg(UINT32 op) +{ + if (condition(op >> 16)) + execute_delayed(IREG(op & 31)); + else + execute_delayed(~0); +} + +void tms3203x_device::brc_imm(UINT32 op) +{ + if (condition(op >> 16)) + { + m_pc += (INT16)op; + m_icount -= 3*2; + } +} + +void tms3203x_device::brcd_imm(UINT32 op) +{ + if (condition(op >> 16)) + execute_delayed(m_pc + 2 + (INT16)op); + else + execute_delayed(~0); +} + +/*-----------------------------------------------------*/ + +void tms3203x_device::dbc_reg(UINT32 op) +{ + int reg = TMR_AR0 + ((op >> 22) & 7); + int res = (IREG(reg) - 1) & 0xffffff; + IREG(reg) = res | (IREG(reg) & 0xff000000); + if (condition(op >> 16) && !(res & 0x800000)) + { + m_pc = IREG(op & 31); + m_icount -= 3*2; + } +} + +void tms3203x_device::dbcd_reg(UINT32 op) +{ + int reg = TMR_AR0 + ((op >> 22) & 7); + int res = (IREG(reg) - 1) & 0xffffff; + IREG(reg) = res | (IREG(reg) & 0xff000000); + if (condition(op >> 16) && !(res & 0x800000)) + execute_delayed(IREG(op & 31)); + else + execute_delayed(~0); +} + +void tms3203x_device::dbc_imm(UINT32 op) +{ + int reg = TMR_AR0 + ((op >> 22) & 7); + int res = (IREG(reg) - 1) & 0xffffff; + IREG(reg) = res | (IREG(reg) & 0xff000000); + if (condition(op >> 16) && !(res & 0x800000)) + { + m_pc += (INT16)op; + m_icount -= 3*2; + } +} + +void tms3203x_device::dbcd_imm(UINT32 op) +{ + int reg = TMR_AR0 + ((op >> 22) & 7); + int res = (IREG(reg) - 1) & 0xffffff; + IREG(reg) = res | (IREG(reg) & 0xff000000); + if (condition(op >> 16) && !(res & 0x800000)) + execute_delayed(m_pc + 2 + (INT16)op); + else + execute_delayed(~0); +} + +/*-----------------------------------------------------*/ + +void tms3203x_device::callc_reg(UINT32 op) +{ + if (condition(op >> 16)) + { + WMEM(++IREG(TMR_SP), m_pc); + m_pc = IREG(op & 31); + m_icount -= 3*2; + } +} + +void tms3203x_device::callc_imm(UINT32 op) +{ + if (condition(op >> 16)) + { + WMEM(++IREG(TMR_SP), m_pc); + m_pc += (INT16)op; + m_icount -= 3*2; + } +} + +/*-----------------------------------------------------*/ + +void tms3203x_device::trap(int trapnum) +{ + WMEM(++IREG(TMR_SP), m_pc); + IREG(TMR_ST) &= ~GIEFLAG; + if (m_chip_type == CHIP_TYPE_TMS32032) + m_pc = RMEM(((IREG(TMR_IF) >> 16) << 8) + trapnum); + else + m_pc = RMEM(trapnum); + m_icount -= 4*2; +} + +void tms3203x_device::trapc(UINT32 op) +{ + if (condition(op >> 16)) + trap(op & 0x3f); +} + +/*-----------------------------------------------------*/ + +void tms3203x_device::retic_reg(UINT32 op) +{ + if (condition(op >> 16)) + { + m_pc = RMEM(IREG(TMR_SP)--); + IREG(TMR_ST) |= GIEFLAG; + m_icount -= 3*2; + check_irqs(); + } +} + +void tms3203x_device::retsc_reg(UINT32 op) +{ + if (condition(op >> 16)) + { + m_pc = RMEM(IREG(TMR_SP)--); + m_icount -= 3*2; + } +} + +/*-----------------------------------------------------*/ + +void tms3203x_device::mpyaddf_0(UINT32 op) +{ + // src3 * src4, src1 + src2 + DECLARE_DEF; + UINT32 src3 = RMEM(INDIRECT_1_DEF(op, op >> 8)); + UINT32 src4 = RMEM(INDIRECT_1(op, op)); + LONG2FP(TMR_TEMP1, src3); + LONG2FP(TMR_TEMP2, src4); + mpyf(m_r[TMR_TEMP3], m_r[TMR_TEMP1], m_r[TMR_TEMP2]); + addf(m_r[((op >> 22) & 1) | 2], m_r[(op >> 19) & 7], m_r[(op >> 16) & 7]); + m_r[(op >> 23) & 1] = m_r[TMR_TEMP3]; + UPDATE_DEF(); +} + +void tms3203x_device::mpyaddf_1(UINT32 op) +{ + // src3 * src1, src4 + src2 + DECLARE_DEF; + UINT32 src3 = RMEM(INDIRECT_1_DEF(op, op >> 8)); + UINT32 src4 = RMEM(INDIRECT_1(op, op)); + LONG2FP(TMR_TEMP1, src3); + LONG2FP(TMR_TEMP2, src4); + mpyf(m_r[TMR_TEMP3], m_r[TMR_TEMP1], m_r[(op >> 19) & 7]); + addf(m_r[((op >> 22) & 1) | 2], m_r[TMR_TEMP2], m_r[(op >> 16) & 7]); + m_r[(op >> 23) & 1] = m_r[TMR_TEMP3]; + UPDATE_DEF(); +} + +void tms3203x_device::mpyaddf_2(UINT32 op) +{ + // src1 * src2, src3 + src4 + DECLARE_DEF; + UINT32 src3 = RMEM(INDIRECT_1_DEF(op, op >> 8)); + UINT32 src4 = RMEM(INDIRECT_1(op, op)); + LONG2FP(TMR_TEMP1, src3); + LONG2FP(TMR_TEMP2, src4); + mpyf(m_r[TMR_TEMP3], m_r[(op >> 19) & 7], m_r[(op >> 16) & 7]); + addf(m_r[((op >> 22) & 1) | 2], m_r[TMR_TEMP1], m_r[TMR_TEMP2]); + m_r[(op >> 23) & 1] = m_r[TMR_TEMP3]; + UPDATE_DEF(); +} + +void tms3203x_device::mpyaddf_3(UINT32 op) +{ + // src3 * src1, src2 + src4 + DECLARE_DEF; + UINT32 src3 = RMEM(INDIRECT_1_DEF(op, op >> 8)); + UINT32 src4 = RMEM(INDIRECT_1(op, op)); + LONG2FP(TMR_TEMP1, src3); + LONG2FP(TMR_TEMP2, src4); + mpyf(m_r[TMR_TEMP3], m_r[TMR_TEMP1], m_r[(op >> 19) & 7]); + addf(m_r[((op >> 22) & 1) | 2], m_r[(op >> 16) & 7], m_r[TMR_TEMP2]); + m_r[(op >> 23) & 1] = m_r[TMR_TEMP3]; + UPDATE_DEF(); +} + +/*-----------------------------------------------------*/ + +void tms3203x_device::mpysubf_0(UINT32 op) +{ + // src3 * src4, src1 - src2 + DECLARE_DEF; + UINT32 src3 = RMEM(INDIRECT_1_DEF(op, op >> 8)); + UINT32 src4 = RMEM(INDIRECT_1(op, op)); + LONG2FP(TMR_TEMP1, src3); + LONG2FP(TMR_TEMP2, src4); + mpyf(m_r[TMR_TEMP3], m_r[TMR_TEMP1], m_r[TMR_TEMP2]); + subf(m_r[((op >> 22) & 1) | 2], m_r[(op >> 19) & 7], m_r[(op >> 16) & 7]); + m_r[(op >> 23) & 1] = m_r[TMR_TEMP3]; + UPDATE_DEF(); +} + +void tms3203x_device::mpysubf_1(UINT32 op) +{ + // src3 * src1, src4 - src2 + DECLARE_DEF; + UINT32 src3 = RMEM(INDIRECT_1_DEF(op, op >> 8)); + UINT32 src4 = RMEM(INDIRECT_1(op, op)); + LONG2FP(TMR_TEMP1, src3); + LONG2FP(TMR_TEMP2, src4); + mpyf(m_r[TMR_TEMP3], m_r[TMR_TEMP1], m_r[(op >> 19) & 7]); + subf(m_r[((op >> 22) & 1) | 2], m_r[TMR_TEMP2], m_r[(op >> 16) & 7]); + m_r[(op >> 23) & 1] = m_r[TMR_TEMP3]; + UPDATE_DEF(); +} + +void tms3203x_device::mpysubf_2(UINT32 op) +{ + // src1 * src2, src3 - src4 + DECLARE_DEF; + UINT32 src3 = RMEM(INDIRECT_1_DEF(op, op >> 8)); + UINT32 src4 = RMEM(INDIRECT_1(op, op)); + LONG2FP(TMR_TEMP1, src3); + LONG2FP(TMR_TEMP2, src4); + mpyf(m_r[TMR_TEMP3], m_r[(op >> 19) & 7], m_r[(op >> 16) & 7]); + subf(m_r[((op >> 22) & 1) | 2], m_r[TMR_TEMP1], m_r[TMR_TEMP2]); + m_r[(op >> 23) & 1] = m_r[TMR_TEMP3]; + UPDATE_DEF(); +} + +void tms3203x_device::mpysubf_3(UINT32 op) +{ + // src3 * src1, src2 - src4 + DECLARE_DEF; + UINT32 src3 = RMEM(INDIRECT_1_DEF(op, op >> 8)); + UINT32 src4 = RMEM(INDIRECT_1(op, op)); + LONG2FP(TMR_TEMP1, src3); + LONG2FP(TMR_TEMP2, src4); + mpyf(m_r[TMR_TEMP3], m_r[TMR_TEMP1], m_r[(op >> 19) & 7]); + subf(m_r[((op >> 22) & 1) | 2], m_r[(op >> 16) & 7], m_r[TMR_TEMP2]); + m_r[(op >> 23) & 1] = m_r[TMR_TEMP3]; + UPDATE_DEF(); +} + +/*-----------------------------------------------------*/ + +void tms3203x_device::mpyaddi_0(UINT32 op) +{ + // src3 * src4, src1 + src2 + DECLARE_DEF; + UINT32 src1 = IREG((op >> 19) & 7); + UINT32 src2 = IREG((op >> 16) & 7); + UINT32 src3 = RMEM(INDIRECT_1_DEF(op, op >> 8)); + UINT32 src4 = RMEM(INDIRECT_1(op, op)); + INT64 mres = (INT64)((INT32)(src3 << 8) >> 8) * (INT64)((INT32)(src4 << 8) >> 8); + UINT32 ares = src1 + src2; + + CLR_NZVUF(); + if (OVM()) + { + if (mres < -(INT64)0x80000000 || mres > (INT64)0x7fffffff) + mres = (mres < 0) ? 0x80000000 : 0x7fffffff; + if (OVERFLOW_ADD(src1,src2,ares)) + ares = ((INT32)src1 < 0) ? 0x80000000 : 0x7fffffff; + } + IREG((op >> 23) & 1) = mres; + IREG(((op >> 22) & 1) | 2) = ares; + UPDATE_DEF(); +} + +void tms3203x_device::mpyaddi_1(UINT32 op) +{ + // src3 * src1, src4 + src2 + DECLARE_DEF; + UINT32 src1 = IREG((op >> 19) & 7); + UINT32 src2 = IREG((op >> 16) & 7); + UINT32 src3 = RMEM(INDIRECT_1_DEF(op, op >> 8)); + UINT32 src4 = RMEM(INDIRECT_1(op, op)); + INT64 mres = (INT64)((INT32)(src3 << 8) >> 8) * (INT64)((INT32)(src1 << 8) >> 8); + UINT32 ares = src4 + src2; + + CLR_NZVUF(); + if (OVM()) + { + if (mres < -(INT64)0x80000000 || mres > (INT64)0x7fffffff) + mres = (mres < 0) ? 0x80000000 : 0x7fffffff; + if (OVERFLOW_ADD(src4,src2,ares)) + ares = ((INT32)src4 < 0) ? 0x80000000 : 0x7fffffff; + } + IREG((op >> 23) & 1) = mres; + IREG(((op >> 22) & 1) | 2) = ares; + UPDATE_DEF(); +} + +void tms3203x_device::mpyaddi_2(UINT32 op) +{ + // src1 * src2, src3 + src4 + DECLARE_DEF; + UINT32 src1 = IREG((op >> 19) & 7); + UINT32 src2 = IREG((op >> 16) & 7); + UINT32 src3 = RMEM(INDIRECT_1_DEF(op, op >> 8)); + UINT32 src4 = RMEM(INDIRECT_1(op, op)); + INT64 mres = (INT64)((INT32)(src1 << 8) >> 8) * (INT64)((INT32)(src2 << 8) >> 8); + UINT32 ares = src3 + src4; + + CLR_NZVUF(); + if (OVM()) + { + if (mres < -(INT64)0x80000000 || mres > (INT64)0x7fffffff) + mres = (mres < 0) ? 0x80000000 : 0x7fffffff; + if (OVERFLOW_ADD(src3,src4,ares)) + ares = ((INT32)src3 < 0) ? 0x80000000 : 0x7fffffff; + } + IREG((op >> 23) & 1) = mres; + IREG(((op >> 22) & 1) | 2) = ares; + UPDATE_DEF(); +} + +void tms3203x_device::mpyaddi_3(UINT32 op) +{ + // src3 * src1, src2 + src4 + DECLARE_DEF; + UINT32 src1 = IREG((op >> 19) & 7); + UINT32 src2 = IREG((op >> 16) & 7); + UINT32 src3 = RMEM(INDIRECT_1_DEF(op, op >> 8)); + UINT32 src4 = RMEM(INDIRECT_1(op, op)); + INT64 mres = (INT64)((INT32)(src3 << 8) >> 8) * (INT64)((INT32)(src1 << 8) >> 8); + UINT32 ares = src2 + src4; + + CLR_NZVUF(); + if (OVM()) + { + if (mres < -(INT64)0x80000000 || mres > (INT64)0x7fffffff) + mres = (mres < 0) ? 0x80000000 : 0x7fffffff; + if (OVERFLOW_ADD(src2,src4,ares)) + ares = ((INT32)src2 < 0) ? 0x80000000 : 0x7fffffff; + } + IREG((op >> 23) & 1) = mres; + IREG(((op >> 22) & 1) | 2) = ares; + UPDATE_DEF(); +} + +/*-----------------------------------------------------*/ + +void tms3203x_device::mpysubi_0(UINT32 op) +{ + // src3 * src4, src1 - src2 + DECLARE_DEF; + UINT32 src1 = IREG((op >> 19) & 7); + UINT32 src2 = IREG((op >> 16) & 7); + UINT32 src3 = RMEM(INDIRECT_1_DEF(op, op >> 8)); + UINT32 src4 = RMEM(INDIRECT_1(op, op)); + INT64 mres = (INT64)((INT32)(src3 << 8) >> 8) * (INT64)((INT32)(src4 << 8) >> 8); + UINT32 ares = src1 - src2; + + CLR_NZVUF(); + if (OVM()) + { + if (mres < -(INT64)0x80000000 || mres > (INT64)0x7fffffff) + mres = (mres < 0) ? 0x80000000 : 0x7fffffff; + if (OVERFLOW_SUB(src1,src2,ares)) + ares = ((INT32)src1 < 0) ? 0x80000000 : 0x7fffffff; + } + IREG((op >> 23) & 1) = mres; + IREG(((op >> 22) & 1) | 2) = ares; + UPDATE_DEF(); +} + +void tms3203x_device::mpysubi_1(UINT32 op) +{ + // src3 * src1, src4 - src2 + DECLARE_DEF; + UINT32 src1 = IREG((op >> 19) & 7); + UINT32 src2 = IREG((op >> 16) & 7); + UINT32 src3 = RMEM(INDIRECT_1_DEF(op, op >> 8)); + UINT32 src4 = RMEM(INDIRECT_1(op, op)); + INT64 mres = (INT64)((INT32)(src3 << 8) >> 8) * (INT64)((INT32)(src1 << 8) >> 8); + UINT32 ares = src4 - src2; + + CLR_NZVUF(); + if (OVM()) + { + if (mres < -(INT64)0x80000000 || mres > (INT64)0x7fffffff) + mres = (mres < 0) ? 0x80000000 : 0x7fffffff; + if (OVERFLOW_SUB(src4,src2,ares)) + ares = ((INT32)src4 < 0) ? 0x80000000 : 0x7fffffff; + } + IREG((op >> 23) & 1) = mres; + IREG(((op >> 22) & 1) | 2) = ares; + UPDATE_DEF(); +} + +void tms3203x_device::mpysubi_2(UINT32 op) +{ + // src1 * src2, src3 - src4 + DECLARE_DEF; + UINT32 src1 = IREG((op >> 19) & 7); + UINT32 src2 = IREG((op >> 16) & 7); + UINT32 src3 = RMEM(INDIRECT_1_DEF(op, op >> 8)); + UINT32 src4 = RMEM(INDIRECT_1(op, op)); + INT64 mres = (INT64)((INT32)(src1 << 8) >> 8) * (INT64)((INT32)(src2 << 8) >> 8); + UINT32 ares = src3 - src4; + + CLR_NZVUF(); + if (OVM()) + { + if (mres < -(INT64)0x80000000 || mres > (INT64)0x7fffffff) + mres = (mres < 0) ? 0x80000000 : 0x7fffffff; + if (OVERFLOW_SUB(src3,src4,ares)) + ares = ((INT32)src3 < 0) ? 0x80000000 : 0x7fffffff; + } + IREG((op >> 23) & 1) = mres; + IREG(((op >> 22) & 1) | 2) = ares; + UPDATE_DEF(); +} + +void tms3203x_device::mpysubi_3(UINT32 op) +{ + // src3 * src1, src2 - src4 + DECLARE_DEF; + UINT32 src1 = IREG((op >> 19) & 7); + UINT32 src2 = IREG((op >> 16) & 7); + UINT32 src3 = RMEM(INDIRECT_1_DEF(op, op >> 8)); + UINT32 src4 = RMEM(INDIRECT_1(op, op)); + INT64 mres = (INT64)((INT32)(src3 << 8) >> 8) * (INT64)((INT32)(src1 << 8) >> 8); + UINT32 ares = src2 - src4; + + CLR_NZVUF(); + if (OVM()) + { + if (mres < -(INT64)0x80000000 || mres > (INT64)0x7fffffff) + mres = (mres < 0) ? 0x80000000 : 0x7fffffff; + if (OVERFLOW_SUB(src2,src4,ares)) + ares = ((INT32)src2 < 0) ? 0x80000000 : 0x7fffffff; + } + IREG((op >> 23) & 1) = mres; + IREG(((op >> 22) & 1) | 2) = ares; + UPDATE_DEF(); +} + +/*-----------------------------------------------------*/ + +void tms3203x_device::stfstf(UINT32 op) +{ + DECLARE_DEF; + WMEM(INDIRECT_1_DEF(op, op >> 8), FP2LONG((op >> 16) & 7)); + WMEM(INDIRECT_1(op, op), FP2LONG((op >> 22) & 7)); + UPDATE_DEF(); +} + +void tms3203x_device::stisti(UINT32 op) +{ + DECLARE_DEF; + WMEM(INDIRECT_1_DEF(op, op >> 8), IREG((op >> 16) & 7)); + WMEM(INDIRECT_1(op, op), IREG((op >> 22) & 7)); + UPDATE_DEF(); +} + +/*-----------------------------------------------------*/ + +void tms3203x_device::ldfldf(UINT32 op) +{ + DECLARE_DEF; + UINT32 res; + int dreg; + + res = RMEM(INDIRECT_1_DEF(op, op >> 8)); + dreg = (op >> 19) & 7; + LONG2FP(dreg, res); + res = RMEM(INDIRECT_1(op, op)); + dreg = (op >> 22) & 7; + LONG2FP(dreg, res); + UPDATE_DEF(); +} + +void tms3203x_device::ldildi(UINT32 op) +{ + DECLARE_DEF; + IREG((op >> 19) & 7) = RMEM(INDIRECT_1_DEF(op, op >> 8)); + IREG((op >> 22) & 7) = RMEM(INDIRECT_1(op, op)); + UPDATE_DEF(); +} + +/*-----------------------------------------------------*/ + +// src2 = ind(op) +// dst2 = ind(op >> 8) +// sreg3 = ((op >> 16) & 7) +// sreg1 = ((op >> 19) & 7) +// dreg1 = ((op >> 22) & 7) + +void tms3203x_device::absfstf(UINT32 op) +{ + DECLARE_DEF; + UINT32 src3 = FP2LONG((op >> 16) & 7); + UINT32 src2 = RMEM(INDIRECT_1_DEF(op, op)); + { + int dreg = (op >> 22) & 7; + LONG2FP(TMR_TEMP1, src2); + ABSF(dreg, TMR_TEMP1); + } + WMEM(INDIRECT_1(op, op >> 8), src3); + UPDATE_DEF(); +} + +void tms3203x_device::absisti(UINT32 op) +{ + DECLARE_DEF; + UINT32 src3 = IREG((op >> 16) & 7); + UINT32 src2 = RMEM(INDIRECT_1_DEF(op, op)); + { + int dreg = (op >> 22) & 7; + ABSI(dreg, src2); + } + WMEM(INDIRECT_1(op, op >> 8), src3); + UPDATE_DEF(); +} + +void tms3203x_device::addf3stf(UINT32 op) +{ + DECLARE_DEF; + UINT32 src3 = FP2LONG((op >> 16) & 7); + UINT32 src2 = RMEM(INDIRECT_1_DEF(op, op)); + { + LONG2FP(TMR_TEMP1, src2); + addf(m_r[(op >> 22) & 7], m_r[(op >> 19) & 7], m_r[TMR_TEMP1]); + } + WMEM(INDIRECT_1(op, op >> 8), src3); + UPDATE_DEF(); +} + +void tms3203x_device::addi3sti(UINT32 op) +{ + DECLARE_DEF; + UINT32 src3 = IREG((op >> 16) & 7); + UINT32 src2 = RMEM(INDIRECT_1_DEF(op, op)); + { + int dreg = (op >> 22) & 7; + UINT32 src1 = IREG((op >> 19) & 7); + ADDI(dreg, src1, src2); + } + WMEM(INDIRECT_1(op, op >> 8), src3); + UPDATE_DEF(); +} + +void tms3203x_device::and3sti(UINT32 op) +{ + DECLARE_DEF; + UINT32 src3 = IREG((op >> 16) & 7); + UINT32 src2 = RMEM(INDIRECT_1_DEF(op, op)); + { + int dreg = (op >> 22) & 7; + UINT32 src1 = IREG((op >> 19) & 7); + AND(dreg, src1, src2); + } + WMEM(INDIRECT_1(op, op >> 8), src3); + UPDATE_DEF(); +} + +void tms3203x_device::ash3sti(UINT32 op) +{ + DECLARE_DEF; + UINT32 src3 = IREG((op >> 16) & 7); + UINT32 src2 = RMEM(INDIRECT_1_DEF(op, op)); + { + int dreg = (op >> 22) & 7; + UINT32 count = IREG((op >> 19) & 7); + ASH(dreg, src2, count); + } + WMEM(INDIRECT_1(op, op >> 8), src3); + UPDATE_DEF(); +} + +void tms3203x_device::fixsti(UINT32 op) +{ + DECLARE_DEF; + UINT32 src3 = IREG((op >> 16) & 7); + UINT32 src2 = RMEM(INDIRECT_1_DEF(op, op)); + { + int dreg = (op >> 22) & 7; + LONG2FP(dreg, src2); + float2int(m_r[dreg], 1); + } + WMEM(INDIRECT_1(op, op >> 8), src3); + UPDATE_DEF(); +} + +void tms3203x_device::floatstf(UINT32 op) +{ + DECLARE_DEF; + UINT32 src3 = FP2LONG((op >> 16) & 7); + UINT32 src2 = RMEM(INDIRECT_1_DEF(op, op)); + { + int dreg = (op >> 22) & 7; + IREG(dreg) = src2; + int2float(m_r[dreg]); + } + WMEM(INDIRECT_1(op, op >> 8), src3); + UPDATE_DEF(); +} + +void tms3203x_device::ldfstf(UINT32 op) +{ + DECLARE_DEF; + UINT32 src3 = FP2LONG((op >> 16) & 7); + UINT32 src2 = RMEM(INDIRECT_1_DEF(op, op)); + { + int dreg = (op >> 22) & 7; + LONG2FP(dreg, src2); + } + WMEM(INDIRECT_1(op, op >> 8), src3); + UPDATE_DEF(); +} + +void tms3203x_device::ldisti(UINT32 op) +{ + DECLARE_DEF; + UINT32 src3 = IREG((op >> 16) & 7); + UINT32 src2 = RMEM(INDIRECT_1_DEF(op, op)); + IREG((op >> 22) & 7) = src2; + WMEM(INDIRECT_1(op, op >> 8), src3); + UPDATE_DEF(); +} + +void tms3203x_device::lsh3sti(UINT32 op) +{ + DECLARE_DEF; + UINT32 src3 = IREG((op >> 16) & 7); + UINT32 src2 = RMEM(INDIRECT_1_DEF(op, op)); + { + int dreg = (op >> 22) & 7; + UINT32 count = IREG((op >> 19) & 7); + LSH(dreg, src2, count); + } + WMEM(INDIRECT_1(op, op >> 8), src3); + UPDATE_DEF(); +} + +void tms3203x_device::mpyf3stf(UINT32 op) +{ + DECLARE_DEF; + UINT32 src3 = FP2LONG((op >> 16) & 7); + UINT32 src2 = RMEM(INDIRECT_1_DEF(op, op)); + { + LONG2FP(TMR_TEMP1, src2); + mpyf(m_r[(op >> 22) & 7], m_r[(op >> 19) & 7], m_r[TMR_TEMP1]); + } + WMEM(INDIRECT_1(op, op >> 8), src3); + UPDATE_DEF(); +} + +void tms3203x_device::mpyi3sti(UINT32 op) +{ + DECLARE_DEF; + UINT32 src3 = IREG((op >> 16) & 7); + UINT32 src2 = RMEM(INDIRECT_1_DEF(op, op)); + { + int dreg = (op >> 22) & 7; + UINT32 src1 = IREG((op >> 19) & 7); + MPYI(dreg, src1, src2); + } + WMEM(INDIRECT_1(op, op >> 8), src3); + UPDATE_DEF(); +} + +void tms3203x_device::negfstf(UINT32 op) +{ + DECLARE_DEF; + UINT32 src3 = FP2LONG((op >> 16) & 7); + UINT32 src2 = RMEM(INDIRECT_1_DEF(op, op)); + { + LONG2FP(TMR_TEMP1, src2); + negf(m_r[(op >> 22) & 7], m_r[TMR_TEMP1]); + } + WMEM(INDIRECT_1(op, op >> 8), src3); + UPDATE_DEF(); +} + +void tms3203x_device::negisti(UINT32 op) +{ + DECLARE_DEF; + UINT32 src3 = IREG((op >> 16) & 7); + UINT32 src2 = RMEM(INDIRECT_1_DEF(op, op)); + { + int dreg = (op >> 22) & 7; + NEGI(dreg, src2); + } + WMEM(INDIRECT_1(op, op >> 8), src3); + UPDATE_DEF(); +} + +void tms3203x_device::notsti(UINT32 op) +{ + DECLARE_DEF; + UINT32 src3 = IREG((op >> 16) & 7); + UINT32 src2 = RMEM(INDIRECT_1_DEF(op, op)); + { + int dreg = (op >> 22) & 7; + NOT(dreg, src2); + } + WMEM(INDIRECT_1(op, op >> 8), src3); + UPDATE_DEF(); +} + +void tms3203x_device::or3sti(UINT32 op) +{ + DECLARE_DEF; + UINT32 src3 = IREG((op >> 16) & 7); + UINT32 src2 = RMEM(INDIRECT_1_DEF(op, op)); + { + int dreg = (op >> 22) & 7; + UINT32 src1 = IREG((op >> 19) & 7); + OR(dreg, src1, src2); + } + WMEM(INDIRECT_1(op, op >> 8), src3); + UPDATE_DEF(); +} + +void tms3203x_device::subf3stf(UINT32 op) +{ + DECLARE_DEF; + UINT32 src3 = FP2LONG((op >> 16) & 7); + UINT32 src2 = RMEM(INDIRECT_1_DEF(op, op)); + { + LONG2FP(TMR_TEMP1, src2); + subf(m_r[(op >> 22) & 7], m_r[TMR_TEMP1], m_r[(op >> 19) & 7]); + } + WMEM(INDIRECT_1(op, op >> 8), src3); + UPDATE_DEF(); +} + +void tms3203x_device::subi3sti(UINT32 op) +{ + DECLARE_DEF; + UINT32 src3 = IREG((op >> 16) & 7); + UINT32 src2 = RMEM(INDIRECT_1_DEF(op, op)); + { + int dreg = (op >> 22) & 7; + UINT32 src1 = IREG((op >> 19) & 7); + SUBI(dreg, src2, src1); + } + WMEM(INDIRECT_1(op, op >> 8), src3); + UPDATE_DEF(); +} + +void tms3203x_device::xor3sti(UINT32 op) +{ + DECLARE_DEF; + UINT32 src3 = IREG((op >> 16) & 7); + UINT32 src2 = RMEM(INDIRECT_1_DEF(op, op)); + { + int dreg = (op >> 22) & 7; + UINT32 src1 = IREG((op >> 19) & 7); + XOR(dreg, src1, src2); + } + WMEM(INDIRECT_1(op, op >> 8), src3); + UPDATE_DEF(); +} + + +//************************************************************************** +// FUNCTION TABLE +//************************************************************************** + +UINT32 (tms3203x_device::*const tms3203x_device::s_indirect_d[0x20])(UINT32, UINT8) = +{ + &tms3203x_device::mod00_d, &tms3203x_device::mod01_d, &tms3203x_device::mod02_d, &tms3203x_device::mod03_d, + &tms3203x_device::mod04_d, &tms3203x_device::mod05_d, &tms3203x_device::mod06_d, &tms3203x_device::mod07_d, + &tms3203x_device::mod08, &tms3203x_device::mod09, &tms3203x_device::mod0a, &tms3203x_device::mod0b, + &tms3203x_device::mod0c, &tms3203x_device::mod0d, &tms3203x_device::mod0e, &tms3203x_device::mod0f, + &tms3203x_device::mod10, &tms3203x_device::mod11, &tms3203x_device::mod12, &tms3203x_device::mod13, + &tms3203x_device::mod14, &tms3203x_device::mod15, &tms3203x_device::mod16, &tms3203x_device::mod17, + &tms3203x_device::mod18, &tms3203x_device::mod19, &tms3203x_device::modillegal, &tms3203x_device::modillegal, + &tms3203x_device::modillegal, &tms3203x_device::modillegal, &tms3203x_device::modillegal, &tms3203x_device::modillegal +}; + + +UINT32 (tms3203x_device::*const tms3203x_device::s_indirect_1[0x20])(UINT32, UINT8) = +{ + &tms3203x_device::mod00_1, &tms3203x_device::mod01_1, &tms3203x_device::mod02_1, &tms3203x_device::mod03_1, + &tms3203x_device::mod04_1, &tms3203x_device::mod05_1, &tms3203x_device::mod06_1, &tms3203x_device::mod07_1, + &tms3203x_device::mod08, &tms3203x_device::mod09, &tms3203x_device::mod0a, &tms3203x_device::mod0b, + &tms3203x_device::mod0c, &tms3203x_device::mod0d, &tms3203x_device::mod0e, &tms3203x_device::mod0f, + &tms3203x_device::mod10, &tms3203x_device::mod11, &tms3203x_device::mod12, &tms3203x_device::mod13, + &tms3203x_device::mod14, &tms3203x_device::mod15, &tms3203x_device::mod16, &tms3203x_device::mod17, + &tms3203x_device::mod18, &tms3203x_device::mod19, &tms3203x_device::modillegal, &tms3203x_device::modillegal, + &tms3203x_device::modillegal, &tms3203x_device::modillegal, &tms3203x_device::modillegal, &tms3203x_device::modillegal +}; + + +UINT32 (tms3203x_device::*const tms3203x_device::s_indirect_1_def[0x20])(UINT32, UINT8, UINT32 *&) = +{ + &tms3203x_device::mod00_1_def, &tms3203x_device::mod01_1_def, &tms3203x_device::mod02_1_def, &tms3203x_device::mod03_1_def, + &tms3203x_device::mod04_1_def, &tms3203x_device::mod05_1_def, &tms3203x_device::mod06_1_def, &tms3203x_device::mod07_1_def, + &tms3203x_device::mod08_def, &tms3203x_device::mod09_def, &tms3203x_device::mod0a_def, &tms3203x_device::mod0b_def, + &tms3203x_device::mod0c_def, &tms3203x_device::mod0d_def, &tms3203x_device::mod0e_def, &tms3203x_device::mod0f_def, + &tms3203x_device::mod10_def, &tms3203x_device::mod11_def, &tms3203x_device::mod12_def, &tms3203x_device::mod13_def, + &tms3203x_device::mod14_def, &tms3203x_device::mod15_def, &tms3203x_device::mod16_def, &tms3203x_device::mod17_def, + &tms3203x_device::mod18_def, &tms3203x_device::mod19_def, &tms3203x_device::modillegal_def,&tms3203x_device::modillegal_def, + &tms3203x_device::modillegal_def,&tms3203x_device::modillegal_def,&tms3203x_device::modillegal_def,&tms3203x_device::modillegal_def +}; + +void (tms3203x_device::*const tms3203x_device::s_tms32031ops[])(UINT32 op) = +{ + &tms3203x_device::absf_reg, &tms3203x_device::absf_dir, &tms3203x_device::absf_ind, &tms3203x_device::absf_imm, // 0x00 + &tms3203x_device::absi_reg, &tms3203x_device::absi_dir, &tms3203x_device::absi_ind, &tms3203x_device::absi_imm, + &tms3203x_device::addc_reg, &tms3203x_device::addc_dir, &tms3203x_device::addc_ind, &tms3203x_device::addc_imm, + &tms3203x_device::addf_reg, &tms3203x_device::addf_dir, &tms3203x_device::addf_ind, &tms3203x_device::addf_imm, + &tms3203x_device::addi_reg, &tms3203x_device::addi_dir, &tms3203x_device::addi_ind, &tms3203x_device::addi_imm, + &tms3203x_device::and_reg, &tms3203x_device::and_dir, &tms3203x_device::and_ind, &tms3203x_device::and_imm, + &tms3203x_device::andn_reg, &tms3203x_device::andn_dir, &tms3203x_device::andn_ind, &tms3203x_device::andn_imm, + &tms3203x_device::ash_reg, &tms3203x_device::ash_dir, &tms3203x_device::ash_ind, &tms3203x_device::ash_imm, + &tms3203x_device::cmpf_reg, &tms3203x_device::cmpf_dir, &tms3203x_device::cmpf_ind, &tms3203x_device::cmpf_imm, // 0x08 + &tms3203x_device::cmpi_reg, &tms3203x_device::cmpi_dir, &tms3203x_device::cmpi_ind, &tms3203x_device::cmpi_imm, + &tms3203x_device::fix_reg, &tms3203x_device::fix_dir, &tms3203x_device::fix_ind, &tms3203x_device::fix_imm, + &tms3203x_device::float_reg, &tms3203x_device::float_dir, &tms3203x_device::float_ind, &tms3203x_device::float_imm, + &tms3203x_device::idle, &tms3203x_device::idle, &tms3203x_device::idle, &tms3203x_device::idle, + &tms3203x_device::lde_reg, &tms3203x_device::lde_dir, &tms3203x_device::lde_ind, &tms3203x_device::lde_imm, + &tms3203x_device::ldf_reg, &tms3203x_device::ldf_dir, &tms3203x_device::ldf_ind, &tms3203x_device::ldf_imm, + &tms3203x_device::illegal, &tms3203x_device::ldfi_dir, &tms3203x_device::ldfi_ind, &tms3203x_device::illegal, + &tms3203x_device::ldi_reg, &tms3203x_device::ldi_dir, &tms3203x_device::ldi_ind, &tms3203x_device::ldi_imm, // 0x10 + &tms3203x_device::illegal, &tms3203x_device::ldii_dir, &tms3203x_device::ldii_ind, &tms3203x_device::illegal, + &tms3203x_device::ldm_reg, &tms3203x_device::ldm_dir, &tms3203x_device::ldm_ind, &tms3203x_device::ldm_imm, + &tms3203x_device::lsh_reg, &tms3203x_device::lsh_dir, &tms3203x_device::lsh_ind, &tms3203x_device::lsh_imm, + &tms3203x_device::mpyf_reg, &tms3203x_device::mpyf_dir, &tms3203x_device::mpyf_ind, &tms3203x_device::mpyf_imm, + &tms3203x_device::mpyi_reg, &tms3203x_device::mpyi_dir, &tms3203x_device::mpyi_ind, &tms3203x_device::mpyi_imm, + &tms3203x_device::negb_reg, &tms3203x_device::negb_dir, &tms3203x_device::negb_ind, &tms3203x_device::negb_imm, + &tms3203x_device::negf_reg, &tms3203x_device::negf_dir, &tms3203x_device::negf_ind, &tms3203x_device::negf_imm, + &tms3203x_device::negi_reg, &tms3203x_device::negi_dir, &tms3203x_device::negi_ind, &tms3203x_device::negi_imm, // 0x18 + &tms3203x_device::nop_reg, &tms3203x_device::illegal, &tms3203x_device::nop_ind, &tms3203x_device::illegal, + &tms3203x_device::norm_reg, &tms3203x_device::norm_dir, &tms3203x_device::norm_ind, &tms3203x_device::norm_imm, + &tms3203x_device::not_reg, &tms3203x_device::not_dir, &tms3203x_device::not_ind, &tms3203x_device::not_imm, + &tms3203x_device::illegal, &tms3203x_device::pop, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::popf, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::push, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::pushf, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::or_reg, &tms3203x_device::or_dir, &tms3203x_device::or_ind, &tms3203x_device::or_imm, // 0x20 + &tms3203x_device::maxspeed, &tms3203x_device::maxspeed, &tms3203x_device::maxspeed, &tms3203x_device::maxspeed, + &tms3203x_device::rnd_reg, &tms3203x_device::rnd_dir, &tms3203x_device::rnd_ind, &tms3203x_device::rnd_imm, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::rol, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::rolc, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::ror, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::rorc, + &tms3203x_device::rtps_reg, &tms3203x_device::rtps_dir, &tms3203x_device::rtps_ind, &tms3203x_device::rtps_imm, + &tms3203x_device::illegal, &tms3203x_device::stf_dir, &tms3203x_device::stf_ind, &tms3203x_device::illegal, // 0x28 + &tms3203x_device::illegal, &tms3203x_device::stfi_dir, &tms3203x_device::stfi_ind, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::sti_dir, &tms3203x_device::sti_ind, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::stii_dir, &tms3203x_device::stii_ind, &tms3203x_device::illegal, + &tms3203x_device::sigi, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::subb_reg, &tms3203x_device::subb_dir, &tms3203x_device::subb_ind, &tms3203x_device::subb_imm, + &tms3203x_device::subc_reg, &tms3203x_device::subc_dir, &tms3203x_device::subc_ind, &tms3203x_device::subc_imm, + &tms3203x_device::subf_reg, &tms3203x_device::subf_dir, &tms3203x_device::subf_ind, &tms3203x_device::subf_imm, + &tms3203x_device::subi_reg, &tms3203x_device::subi_dir, &tms3203x_device::subi_ind, &tms3203x_device::subi_imm, // 0x30 + &tms3203x_device::subrb_reg, &tms3203x_device::subrb_dir, &tms3203x_device::subrb_ind, &tms3203x_device::subrb_imm, + &tms3203x_device::subrf_reg, &tms3203x_device::subrf_dir, &tms3203x_device::subrf_ind, &tms3203x_device::subrf_imm, + &tms3203x_device::subri_reg, &tms3203x_device::subri_dir, &tms3203x_device::subri_ind, &tms3203x_device::subri_imm, + &tms3203x_device::tstb_reg, &tms3203x_device::tstb_dir, &tms3203x_device::tstb_ind, &tms3203x_device::tstb_imm, + &tms3203x_device::xor_reg, &tms3203x_device::xor_dir, &tms3203x_device::xor_ind, &tms3203x_device::xor_imm, + &tms3203x_device::illegal, &tms3203x_device::iack_dir, &tms3203x_device::iack_ind, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, // 0x38 + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + + &tms3203x_device::addc3_regreg, &tms3203x_device::addc3_indreg, &tms3203x_device::addc3_regind, &tms3203x_device::addc3_indind, // 0x40 + &tms3203x_device::addf3_regreg, &tms3203x_device::addf3_indreg, &tms3203x_device::addf3_regind, &tms3203x_device::addf3_indind, + &tms3203x_device::addi3_regreg, &tms3203x_device::addi3_indreg, &tms3203x_device::addi3_regind, &tms3203x_device::addi3_indind, + &tms3203x_device::and3_regreg, &tms3203x_device::and3_indreg, &tms3203x_device::and3_regind, &tms3203x_device::and3_indind, + &tms3203x_device::andn3_regreg, &tms3203x_device::andn3_indreg, &tms3203x_device::andn3_regind, &tms3203x_device::andn3_indind, + &tms3203x_device::ash3_regreg, &tms3203x_device::ash3_indreg, &tms3203x_device::ash3_regind, &tms3203x_device::ash3_indind, + &tms3203x_device::cmpf3_regreg, &tms3203x_device::cmpf3_indreg, &tms3203x_device::cmpf3_regind, &tms3203x_device::cmpf3_indind, + &tms3203x_device::cmpi3_regreg, &tms3203x_device::cmpi3_indreg, &tms3203x_device::cmpi3_regind, &tms3203x_device::cmpi3_indind, + &tms3203x_device::lsh3_regreg, &tms3203x_device::lsh3_indreg, &tms3203x_device::lsh3_regind, &tms3203x_device::lsh3_indind, // 0x48 + &tms3203x_device::mpyf3_regreg, &tms3203x_device::mpyf3_indreg, &tms3203x_device::mpyf3_regind, &tms3203x_device::mpyf3_indind, + &tms3203x_device::mpyi3_regreg, &tms3203x_device::mpyi3_indreg, &tms3203x_device::mpyi3_regind, &tms3203x_device::mpyi3_indind, + &tms3203x_device::or3_regreg, &tms3203x_device::or3_indreg, &tms3203x_device::or3_regind, &tms3203x_device::or3_indind, + &tms3203x_device::subb3_regreg, &tms3203x_device::subb3_indreg, &tms3203x_device::subb3_regind, &tms3203x_device::subb3_indind, + &tms3203x_device::subf3_regreg, &tms3203x_device::subf3_indreg, &tms3203x_device::subf3_regind, &tms3203x_device::subf3_indind, + &tms3203x_device::subi3_regreg, &tms3203x_device::subi3_indreg, &tms3203x_device::subi3_regind, &tms3203x_device::subi3_indind, + &tms3203x_device::tstb3_regreg, &tms3203x_device::tstb3_indreg, &tms3203x_device::tstb3_regind, &tms3203x_device::tstb3_indind, + &tms3203x_device::xor3_regreg, &tms3203x_device::xor3_indreg, &tms3203x_device::xor3_regind, &tms3203x_device::xor3_indind, // 0x50 + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, // 0x58 + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, // 0x60 + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, // 0x68 + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, // 0x70 + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, // 0x78 + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + + &tms3203x_device::ldfu_reg, &tms3203x_device::ldfu_dir, &tms3203x_device::ldfu_ind, &tms3203x_device::ldfu_imm, // 0x80 + &tms3203x_device::ldflo_reg, &tms3203x_device::ldflo_dir, &tms3203x_device::ldflo_ind, &tms3203x_device::ldflo_imm, + &tms3203x_device::ldfls_reg, &tms3203x_device::ldfls_dir, &tms3203x_device::ldfls_ind, &tms3203x_device::ldfls_imm, + &tms3203x_device::ldfhi_reg, &tms3203x_device::ldfhi_dir, &tms3203x_device::ldfhi_ind, &tms3203x_device::ldfhi_imm, + &tms3203x_device::ldfhs_reg, &tms3203x_device::ldfhs_dir, &tms3203x_device::ldfhs_ind, &tms3203x_device::ldfhs_imm, + &tms3203x_device::ldfeq_reg, &tms3203x_device::ldfeq_dir, &tms3203x_device::ldfeq_ind, &tms3203x_device::ldfeq_imm, + &tms3203x_device::ldfne_reg, &tms3203x_device::ldfne_dir, &tms3203x_device::ldfne_ind, &tms3203x_device::ldfne_imm, + &tms3203x_device::ldflt_reg, &tms3203x_device::ldflt_dir, &tms3203x_device::ldflt_ind, &tms3203x_device::ldflt_imm, + &tms3203x_device::ldfle_reg, &tms3203x_device::ldfle_dir, &tms3203x_device::ldfle_ind, &tms3203x_device::ldfle_imm, // 0x88 + &tms3203x_device::ldfgt_reg, &tms3203x_device::ldfgt_dir, &tms3203x_device::ldfgt_ind, &tms3203x_device::ldfgt_imm, + &tms3203x_device::ldfge_reg, &tms3203x_device::ldfge_dir, &tms3203x_device::ldfge_ind, &tms3203x_device::ldfge_imm, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::ldfnv_reg, &tms3203x_device::ldfnv_dir, &tms3203x_device::ldfnv_ind, &tms3203x_device::ldfnv_imm, + &tms3203x_device::ldfv_reg, &tms3203x_device::ldfv_dir, &tms3203x_device::ldfv_ind, &tms3203x_device::ldfv_imm, + &tms3203x_device::ldfnuf_reg, &tms3203x_device::ldfnuf_dir, &tms3203x_device::ldfnuf_ind, &tms3203x_device::ldfnuf_imm, + &tms3203x_device::ldfuf_reg, &tms3203x_device::ldfuf_dir, &tms3203x_device::ldfuf_ind, &tms3203x_device::ldfuf_imm, + &tms3203x_device::ldfnlv_reg, &tms3203x_device::ldfnlv_dir, &tms3203x_device::ldfnlv_ind, &tms3203x_device::ldfnlv_imm, // 0x90 + &tms3203x_device::ldflv_reg, &tms3203x_device::ldflv_dir, &tms3203x_device::ldflv_ind, &tms3203x_device::ldflv_imm, + &tms3203x_device::ldfnluf_reg, &tms3203x_device::ldfnluf_dir, &tms3203x_device::ldfnluf_ind, &tms3203x_device::ldfnluf_imm, + &tms3203x_device::ldfluf_reg, &tms3203x_device::ldfluf_dir, &tms3203x_device::ldfluf_ind, &tms3203x_device::ldfluf_imm, + &tms3203x_device::ldfzuf_reg, &tms3203x_device::ldfzuf_dir, &tms3203x_device::ldfzuf_ind, &tms3203x_device::ldfzuf_imm, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, // 0x98 + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::ldiu_reg, &tms3203x_device::ldiu_dir, &tms3203x_device::ldiu_ind, &tms3203x_device::ldiu_imm, // 0xa0 + &tms3203x_device::ldilo_reg, &tms3203x_device::ldilo_dir, &tms3203x_device::ldilo_ind, &tms3203x_device::ldilo_imm, + &tms3203x_device::ldils_reg, &tms3203x_device::ldils_dir, &tms3203x_device::ldils_ind, &tms3203x_device::ldils_imm, + &tms3203x_device::ldihi_reg, &tms3203x_device::ldihi_dir, &tms3203x_device::ldihi_ind, &tms3203x_device::ldihi_imm, + &tms3203x_device::ldihs_reg, &tms3203x_device::ldihs_dir, &tms3203x_device::ldihs_ind, &tms3203x_device::ldihs_imm, + &tms3203x_device::ldieq_reg, &tms3203x_device::ldieq_dir, &tms3203x_device::ldieq_ind, &tms3203x_device::ldieq_imm, + &tms3203x_device::ldine_reg, &tms3203x_device::ldine_dir, &tms3203x_device::ldine_ind, &tms3203x_device::ldine_imm, + &tms3203x_device::ldilt_reg, &tms3203x_device::ldilt_dir, &tms3203x_device::ldilt_ind, &tms3203x_device::ldilt_imm, + &tms3203x_device::ldile_reg, &tms3203x_device::ldile_dir, &tms3203x_device::ldile_ind, &tms3203x_device::ldile_imm, // 0xa8 + &tms3203x_device::ldigt_reg, &tms3203x_device::ldigt_dir, &tms3203x_device::ldigt_ind, &tms3203x_device::ldigt_imm, + &tms3203x_device::ldige_reg, &tms3203x_device::ldige_dir, &tms3203x_device::ldige_ind, &tms3203x_device::ldige_imm, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::ldinv_reg, &tms3203x_device::ldinv_dir, &tms3203x_device::ldinv_ind, &tms3203x_device::ldinv_imm, + &tms3203x_device::ldiv_reg, &tms3203x_device::ldiv_dir, &tms3203x_device::ldiv_ind, &tms3203x_device::ldiv_imm, + &tms3203x_device::ldinuf_reg, &tms3203x_device::ldinuf_dir, &tms3203x_device::ldinuf_ind, &tms3203x_device::ldinuf_imm, + &tms3203x_device::ldiuf_reg, &tms3203x_device::ldiuf_dir, &tms3203x_device::ldiuf_ind, &tms3203x_device::ldiuf_imm, + &tms3203x_device::ldinlv_reg, &tms3203x_device::ldinlv_dir, &tms3203x_device::ldinlv_ind, &tms3203x_device::ldinlv_imm, // 0xb0 + &tms3203x_device::ldilv_reg, &tms3203x_device::ldilv_dir, &tms3203x_device::ldilv_ind, &tms3203x_device::ldilv_imm, + &tms3203x_device::ldinluf_reg, &tms3203x_device::ldinluf_dir, &tms3203x_device::ldinluf_ind, &tms3203x_device::ldinluf_imm, + &tms3203x_device::ldiluf_reg, &tms3203x_device::ldiluf_dir, &tms3203x_device::ldiluf_ind, &tms3203x_device::ldiluf_imm, + &tms3203x_device::ldizuf_reg, &tms3203x_device::ldizuf_dir, &tms3203x_device::ldizuf_ind, &tms3203x_device::ldizuf_imm, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, // 0xb8 + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + + &tms3203x_device::br_imm, &tms3203x_device::br_imm, &tms3203x_device::br_imm, &tms3203x_device::br_imm, // 0xc0 + &tms3203x_device::br_imm, &tms3203x_device::br_imm, &tms3203x_device::br_imm, &tms3203x_device::br_imm, + &tms3203x_device::brd_imm, &tms3203x_device::brd_imm, &tms3203x_device::brd_imm, &tms3203x_device::brd_imm, + &tms3203x_device::brd_imm, &tms3203x_device::brd_imm, &tms3203x_device::brd_imm, &tms3203x_device::brd_imm, + &tms3203x_device::call_imm, &tms3203x_device::call_imm, &tms3203x_device::call_imm, &tms3203x_device::call_imm, + &tms3203x_device::call_imm, &tms3203x_device::call_imm, &tms3203x_device::call_imm, &tms3203x_device::call_imm, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::rptb_imm, &tms3203x_device::rptb_imm, &tms3203x_device::rptb_imm, &tms3203x_device::rptb_imm, // 0xc8 + &tms3203x_device::rptb_imm, &tms3203x_device::rptb_imm, &tms3203x_device::rptb_imm, &tms3203x_device::rptb_imm, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::swi, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::brc_reg, &tms3203x_device::brcd_reg, &tms3203x_device::illegal, &tms3203x_device::illegal, // 0xd0 + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::brc_imm, &tms3203x_device::brcd_imm, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::dbc_reg, &tms3203x_device::dbcd_reg, &tms3203x_device::dbc_reg, &tms3203x_device::dbcd_reg, // 0xd8 + &tms3203x_device::dbc_reg, &tms3203x_device::dbcd_reg, &tms3203x_device::dbc_reg, &tms3203x_device::dbcd_reg, + &tms3203x_device::dbc_reg, &tms3203x_device::dbcd_reg, &tms3203x_device::dbc_reg, &tms3203x_device::dbcd_reg, + &tms3203x_device::dbc_reg, &tms3203x_device::dbcd_reg, &tms3203x_device::dbc_reg, &tms3203x_device::dbcd_reg, + &tms3203x_device::dbc_imm, &tms3203x_device::dbcd_imm, &tms3203x_device::dbc_imm, &tms3203x_device::dbcd_imm, + &tms3203x_device::dbc_imm, &tms3203x_device::dbcd_imm, &tms3203x_device::dbc_imm, &tms3203x_device::dbcd_imm, + &tms3203x_device::dbc_imm, &tms3203x_device::dbcd_imm, &tms3203x_device::dbc_imm, &tms3203x_device::dbcd_imm, + &tms3203x_device::dbc_imm, &tms3203x_device::dbcd_imm, &tms3203x_device::dbc_imm, &tms3203x_device::dbcd_imm, + &tms3203x_device::callc_reg, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, // 0xe0 + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::callc_imm, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::trapc, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, // 0xe8 + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::retic_reg, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, // 0xf0 + &tms3203x_device::retsc_reg, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, // 0xf8 + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + + &tms3203x_device::mpyaddf_0, &tms3203x_device::mpyaddf_0, &tms3203x_device::mpyaddf_0, &tms3203x_device::mpyaddf_0, // 0x100 + &tms3203x_device::mpyaddf_0, &tms3203x_device::mpyaddf_0, &tms3203x_device::mpyaddf_0, &tms3203x_device::mpyaddf_0, + &tms3203x_device::mpyaddf_1, &tms3203x_device::mpyaddf_1, &tms3203x_device::mpyaddf_1, &tms3203x_device::mpyaddf_1, + &tms3203x_device::mpyaddf_1, &tms3203x_device::mpyaddf_1, &tms3203x_device::mpyaddf_1, &tms3203x_device::mpyaddf_1, + &tms3203x_device::mpyaddf_2, &tms3203x_device::mpyaddf_2, &tms3203x_device::mpyaddf_2, &tms3203x_device::mpyaddf_2, + &tms3203x_device::mpyaddf_2, &tms3203x_device::mpyaddf_2, &tms3203x_device::mpyaddf_2, &tms3203x_device::mpyaddf_2, + &tms3203x_device::mpyaddf_3, &tms3203x_device::mpyaddf_3, &tms3203x_device::mpyaddf_3, &tms3203x_device::mpyaddf_3, + &tms3203x_device::mpyaddf_3, &tms3203x_device::mpyaddf_3, &tms3203x_device::mpyaddf_3, &tms3203x_device::mpyaddf_3, + &tms3203x_device::mpysubf_0, &tms3203x_device::mpysubf_0, &tms3203x_device::mpysubf_0, &tms3203x_device::mpysubf_0, // 0x108 + &tms3203x_device::mpysubf_0, &tms3203x_device::mpysubf_0, &tms3203x_device::mpysubf_0, &tms3203x_device::mpysubf_0, + &tms3203x_device::mpysubf_1, &tms3203x_device::mpysubf_1, &tms3203x_device::mpysubf_1, &tms3203x_device::mpysubf_1, + &tms3203x_device::mpysubf_1, &tms3203x_device::mpysubf_1, &tms3203x_device::mpysubf_1, &tms3203x_device::mpysubf_1, + &tms3203x_device::mpysubf_2, &tms3203x_device::mpysubf_2, &tms3203x_device::mpysubf_2, &tms3203x_device::mpysubf_2, + &tms3203x_device::mpysubf_2, &tms3203x_device::mpysubf_2, &tms3203x_device::mpysubf_2, &tms3203x_device::mpysubf_2, + &tms3203x_device::mpysubf_3, &tms3203x_device::mpysubf_3, &tms3203x_device::mpysubf_3, &tms3203x_device::mpysubf_3, + &tms3203x_device::mpysubf_3, &tms3203x_device::mpysubf_3, &tms3203x_device::mpysubf_3, &tms3203x_device::mpysubf_3, + &tms3203x_device::mpyaddi_0, &tms3203x_device::mpyaddi_0, &tms3203x_device::mpyaddi_0, &tms3203x_device::mpyaddi_0, // 0x110 + &tms3203x_device::mpyaddi_0, &tms3203x_device::mpyaddi_0, &tms3203x_device::mpyaddi_0, &tms3203x_device::mpyaddi_0, + &tms3203x_device::mpyaddi_1, &tms3203x_device::mpyaddi_1, &tms3203x_device::mpyaddi_1, &tms3203x_device::mpyaddi_1, + &tms3203x_device::mpyaddi_1, &tms3203x_device::mpyaddi_1, &tms3203x_device::mpyaddi_1, &tms3203x_device::mpyaddi_1, + &tms3203x_device::mpyaddi_2, &tms3203x_device::mpyaddi_2, &tms3203x_device::mpyaddi_2, &tms3203x_device::mpyaddi_2, + &tms3203x_device::mpyaddi_2, &tms3203x_device::mpyaddi_2, &tms3203x_device::mpyaddi_2, &tms3203x_device::mpyaddi_2, + &tms3203x_device::mpyaddi_3, &tms3203x_device::mpyaddi_3, &tms3203x_device::mpyaddi_3, &tms3203x_device::mpyaddi_3, + &tms3203x_device::mpyaddi_3, &tms3203x_device::mpyaddi_3, &tms3203x_device::mpyaddi_3, &tms3203x_device::mpyaddi_3, + &tms3203x_device::mpysubi_0, &tms3203x_device::mpysubi_0, &tms3203x_device::mpysubi_0, &tms3203x_device::mpysubi_0, // 0x118 + &tms3203x_device::mpysubi_0, &tms3203x_device::mpysubi_0, &tms3203x_device::mpysubi_0, &tms3203x_device::mpysubi_0, + &tms3203x_device::mpysubi_1, &tms3203x_device::mpysubi_1, &tms3203x_device::mpysubi_1, &tms3203x_device::mpysubi_1, + &tms3203x_device::mpysubi_1, &tms3203x_device::mpysubi_1, &tms3203x_device::mpysubi_1, &tms3203x_device::mpysubi_1, + &tms3203x_device::mpysubi_2, &tms3203x_device::mpysubi_2, &tms3203x_device::mpysubi_2, &tms3203x_device::mpysubi_2, + &tms3203x_device::mpysubi_2, &tms3203x_device::mpysubi_2, &tms3203x_device::mpysubi_2, &tms3203x_device::mpysubi_2, + &tms3203x_device::mpysubi_3, &tms3203x_device::mpysubi_3, &tms3203x_device::mpysubi_3, &tms3203x_device::mpysubi_3, + &tms3203x_device::mpysubi_3, &tms3203x_device::mpysubi_3, &tms3203x_device::mpysubi_3, &tms3203x_device::mpysubi_3, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, // 0x120 + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, // 0x128 + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, // 0x130 + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, // 0x138 + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, // 0x140 + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, // 0x148 + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, // 0x150 + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, // 0x158 + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, // 0x160 + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, // 0x168 + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, // 0x170 + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, // 0x178 + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + + &tms3203x_device::stfstf, &tms3203x_device::stfstf, &tms3203x_device::stfstf, &tms3203x_device::stfstf, // 0x180 + &tms3203x_device::stfstf, &tms3203x_device::stfstf, &tms3203x_device::stfstf, &tms3203x_device::stfstf, + &tms3203x_device::stfstf, &tms3203x_device::stfstf, &tms3203x_device::stfstf, &tms3203x_device::stfstf, + &tms3203x_device::stfstf, &tms3203x_device::stfstf, &tms3203x_device::stfstf, &tms3203x_device::stfstf, + &tms3203x_device::stisti, &tms3203x_device::stisti, &tms3203x_device::stisti, &tms3203x_device::stisti, + &tms3203x_device::stisti, &tms3203x_device::stisti, &tms3203x_device::stisti, &tms3203x_device::stisti, + &tms3203x_device::stisti, &tms3203x_device::stisti, &tms3203x_device::stisti, &tms3203x_device::stisti, + &tms3203x_device::stisti, &tms3203x_device::stisti, &tms3203x_device::stisti, &tms3203x_device::stisti, + &tms3203x_device::ldfldf, &tms3203x_device::ldfldf, &tms3203x_device::ldfldf, &tms3203x_device::ldfldf, // 0x188 + &tms3203x_device::ldfldf, &tms3203x_device::ldfldf, &tms3203x_device::ldfldf, &tms3203x_device::ldfldf, + &tms3203x_device::ldfldf, &tms3203x_device::ldfldf, &tms3203x_device::ldfldf, &tms3203x_device::ldfldf, + &tms3203x_device::ldfldf, &tms3203x_device::ldfldf, &tms3203x_device::ldfldf, &tms3203x_device::ldfldf, + &tms3203x_device::ldildi, &tms3203x_device::ldildi, &tms3203x_device::ldildi, &tms3203x_device::ldildi, + &tms3203x_device::ldildi, &tms3203x_device::ldildi, &tms3203x_device::ldildi, &tms3203x_device::ldildi, + &tms3203x_device::ldildi, &tms3203x_device::ldildi, &tms3203x_device::ldildi, &tms3203x_device::ldildi, + &tms3203x_device::ldildi, &tms3203x_device::ldildi, &tms3203x_device::ldildi, &tms3203x_device::ldildi, + &tms3203x_device::absfstf, &tms3203x_device::absfstf, &tms3203x_device::absfstf, &tms3203x_device::absfstf, // 0x190 + &tms3203x_device::absfstf, &tms3203x_device::absfstf, &tms3203x_device::absfstf, &tms3203x_device::absfstf, + &tms3203x_device::absfstf, &tms3203x_device::absfstf, &tms3203x_device::absfstf, &tms3203x_device::absfstf, + &tms3203x_device::absfstf, &tms3203x_device::absfstf, &tms3203x_device::absfstf, &tms3203x_device::absfstf, + &tms3203x_device::absisti, &tms3203x_device::absisti, &tms3203x_device::absisti, &tms3203x_device::absisti, + &tms3203x_device::absisti, &tms3203x_device::absisti, &tms3203x_device::absisti, &tms3203x_device::absisti, + &tms3203x_device::absisti, &tms3203x_device::absisti, &tms3203x_device::absisti, &tms3203x_device::absisti, + &tms3203x_device::absisti, &tms3203x_device::absisti, &tms3203x_device::absisti, &tms3203x_device::absisti, + &tms3203x_device::addf3stf, &tms3203x_device::addf3stf, &tms3203x_device::addf3stf, &tms3203x_device::addf3stf, // 0x198 + &tms3203x_device::addf3stf, &tms3203x_device::addf3stf, &tms3203x_device::addf3stf, &tms3203x_device::addf3stf, + &tms3203x_device::addf3stf, &tms3203x_device::addf3stf, &tms3203x_device::addf3stf, &tms3203x_device::addf3stf, + &tms3203x_device::addf3stf, &tms3203x_device::addf3stf, &tms3203x_device::addf3stf, &tms3203x_device::addf3stf, + &tms3203x_device::addi3sti, &tms3203x_device::addi3sti, &tms3203x_device::addi3sti, &tms3203x_device::addi3sti, + &tms3203x_device::addi3sti, &tms3203x_device::addi3sti, &tms3203x_device::addi3sti, &tms3203x_device::addi3sti, + &tms3203x_device::addi3sti, &tms3203x_device::addi3sti, &tms3203x_device::addi3sti, &tms3203x_device::addi3sti, + &tms3203x_device::addi3sti, &tms3203x_device::addi3sti, &tms3203x_device::addi3sti, &tms3203x_device::addi3sti, + &tms3203x_device::and3sti, &tms3203x_device::and3sti, &tms3203x_device::and3sti, &tms3203x_device::and3sti, // 0x1a0 + &tms3203x_device::and3sti, &tms3203x_device::and3sti, &tms3203x_device::and3sti, &tms3203x_device::and3sti, + &tms3203x_device::and3sti, &tms3203x_device::and3sti, &tms3203x_device::and3sti, &tms3203x_device::and3sti, + &tms3203x_device::and3sti, &tms3203x_device::and3sti, &tms3203x_device::and3sti, &tms3203x_device::and3sti, + &tms3203x_device::ash3sti, &tms3203x_device::ash3sti, &tms3203x_device::ash3sti, &tms3203x_device::ash3sti, + &tms3203x_device::ash3sti, &tms3203x_device::ash3sti, &tms3203x_device::ash3sti, &tms3203x_device::ash3sti, + &tms3203x_device::ash3sti, &tms3203x_device::ash3sti, &tms3203x_device::ash3sti, &tms3203x_device::ash3sti, + &tms3203x_device::ash3sti, &tms3203x_device::ash3sti, &tms3203x_device::ash3sti, &tms3203x_device::ash3sti, + &tms3203x_device::fixsti, &tms3203x_device::fixsti, &tms3203x_device::fixsti, &tms3203x_device::fixsti, // 0x1a8 + &tms3203x_device::fixsti, &tms3203x_device::fixsti, &tms3203x_device::fixsti, &tms3203x_device::fixsti, + &tms3203x_device::fixsti, &tms3203x_device::fixsti, &tms3203x_device::fixsti, &tms3203x_device::fixsti, + &tms3203x_device::fixsti, &tms3203x_device::fixsti, &tms3203x_device::fixsti, &tms3203x_device::fixsti, + &tms3203x_device::floatstf, &tms3203x_device::floatstf, &tms3203x_device::floatstf, &tms3203x_device::floatstf, + &tms3203x_device::floatstf, &tms3203x_device::floatstf, &tms3203x_device::floatstf, &tms3203x_device::floatstf, + &tms3203x_device::floatstf, &tms3203x_device::floatstf, &tms3203x_device::floatstf, &tms3203x_device::floatstf, + &tms3203x_device::floatstf, &tms3203x_device::floatstf, &tms3203x_device::floatstf, &tms3203x_device::floatstf, + &tms3203x_device::ldfstf, &tms3203x_device::ldfstf, &tms3203x_device::ldfstf, &tms3203x_device::ldfstf, // 0x1b0 + &tms3203x_device::ldfstf, &tms3203x_device::ldfstf, &tms3203x_device::ldfstf, &tms3203x_device::ldfstf, + &tms3203x_device::ldfstf, &tms3203x_device::ldfstf, &tms3203x_device::ldfstf, &tms3203x_device::ldfstf, + &tms3203x_device::ldfstf, &tms3203x_device::ldfstf, &tms3203x_device::ldfstf, &tms3203x_device::ldfstf, + &tms3203x_device::ldisti, &tms3203x_device::ldisti, &tms3203x_device::ldisti, &tms3203x_device::ldisti, + &tms3203x_device::ldisti, &tms3203x_device::ldisti, &tms3203x_device::ldisti, &tms3203x_device::ldisti, + &tms3203x_device::ldisti, &tms3203x_device::ldisti, &tms3203x_device::ldisti, &tms3203x_device::ldisti, + &tms3203x_device::ldisti, &tms3203x_device::ldisti, &tms3203x_device::ldisti, &tms3203x_device::ldisti, + &tms3203x_device::lsh3sti, &tms3203x_device::lsh3sti, &tms3203x_device::lsh3sti, &tms3203x_device::lsh3sti, // 0x1b8 + &tms3203x_device::lsh3sti, &tms3203x_device::lsh3sti, &tms3203x_device::lsh3sti, &tms3203x_device::lsh3sti, + &tms3203x_device::lsh3sti, &tms3203x_device::lsh3sti, &tms3203x_device::lsh3sti, &tms3203x_device::lsh3sti, + &tms3203x_device::lsh3sti, &tms3203x_device::lsh3sti, &tms3203x_device::lsh3sti, &tms3203x_device::lsh3sti, + &tms3203x_device::mpyf3stf, &tms3203x_device::mpyf3stf, &tms3203x_device::mpyf3stf, &tms3203x_device::mpyf3stf, + &tms3203x_device::mpyf3stf, &tms3203x_device::mpyf3stf, &tms3203x_device::mpyf3stf, &tms3203x_device::mpyf3stf, + &tms3203x_device::mpyf3stf, &tms3203x_device::mpyf3stf, &tms3203x_device::mpyf3stf, &tms3203x_device::mpyf3stf, + &tms3203x_device::mpyf3stf, &tms3203x_device::mpyf3stf, &tms3203x_device::mpyf3stf, &tms3203x_device::mpyf3stf, + + &tms3203x_device::mpyi3sti, &tms3203x_device::mpyi3sti, &tms3203x_device::mpyi3sti, &tms3203x_device::mpyi3sti, // 0x1c0 + &tms3203x_device::mpyi3sti, &tms3203x_device::mpyi3sti, &tms3203x_device::mpyi3sti, &tms3203x_device::mpyi3sti, + &tms3203x_device::mpyi3sti, &tms3203x_device::mpyi3sti, &tms3203x_device::mpyi3sti, &tms3203x_device::mpyi3sti, + &tms3203x_device::mpyi3sti, &tms3203x_device::mpyi3sti, &tms3203x_device::mpyi3sti, &tms3203x_device::mpyi3sti, + &tms3203x_device::negfstf, &tms3203x_device::negfstf, &tms3203x_device::negfstf, &tms3203x_device::negfstf, + &tms3203x_device::negfstf, &tms3203x_device::negfstf, &tms3203x_device::negfstf, &tms3203x_device::negfstf, + &tms3203x_device::negfstf, &tms3203x_device::negfstf, &tms3203x_device::negfstf, &tms3203x_device::negfstf, + &tms3203x_device::negfstf, &tms3203x_device::negfstf, &tms3203x_device::negfstf, &tms3203x_device::negfstf, + &tms3203x_device::negisti, &tms3203x_device::negisti, &tms3203x_device::negisti, &tms3203x_device::negisti, // 0x1c8 + &tms3203x_device::negisti, &tms3203x_device::negisti, &tms3203x_device::negisti, &tms3203x_device::negisti, + &tms3203x_device::negisti, &tms3203x_device::negisti, &tms3203x_device::negisti, &tms3203x_device::negisti, + &tms3203x_device::negisti, &tms3203x_device::negisti, &tms3203x_device::negisti, &tms3203x_device::negisti, + &tms3203x_device::notsti, &tms3203x_device::notsti, &tms3203x_device::notsti, &tms3203x_device::notsti, + &tms3203x_device::notsti, &tms3203x_device::notsti, &tms3203x_device::notsti, &tms3203x_device::notsti, + &tms3203x_device::notsti, &tms3203x_device::notsti, &tms3203x_device::notsti, &tms3203x_device::notsti, + &tms3203x_device::notsti, &tms3203x_device::notsti, &tms3203x_device::notsti, &tms3203x_device::notsti, + &tms3203x_device::or3sti, &tms3203x_device::or3sti, &tms3203x_device::or3sti, &tms3203x_device::or3sti, // 0x1d0 + &tms3203x_device::or3sti, &tms3203x_device::or3sti, &tms3203x_device::or3sti, &tms3203x_device::or3sti, + &tms3203x_device::or3sti, &tms3203x_device::or3sti, &tms3203x_device::or3sti, &tms3203x_device::or3sti, + &tms3203x_device::or3sti, &tms3203x_device::or3sti, &tms3203x_device::or3sti, &tms3203x_device::or3sti, + &tms3203x_device::subf3stf, &tms3203x_device::subf3stf, &tms3203x_device::subf3stf, &tms3203x_device::subf3stf, + &tms3203x_device::subf3stf, &tms3203x_device::subf3stf, &tms3203x_device::subf3stf, &tms3203x_device::subf3stf, + &tms3203x_device::subf3stf, &tms3203x_device::subf3stf, &tms3203x_device::subf3stf, &tms3203x_device::subf3stf, + &tms3203x_device::subf3stf, &tms3203x_device::subf3stf, &tms3203x_device::subf3stf, &tms3203x_device::subf3stf, + &tms3203x_device::subi3sti, &tms3203x_device::subi3sti, &tms3203x_device::subi3sti, &tms3203x_device::subi3sti, // 0x1d8 + &tms3203x_device::subi3sti, &tms3203x_device::subi3sti, &tms3203x_device::subi3sti, &tms3203x_device::subi3sti, + &tms3203x_device::subi3sti, &tms3203x_device::subi3sti, &tms3203x_device::subi3sti, &tms3203x_device::subi3sti, + &tms3203x_device::subi3sti, &tms3203x_device::subi3sti, &tms3203x_device::subi3sti, &tms3203x_device::subi3sti, + &tms3203x_device::xor3sti, &tms3203x_device::xor3sti, &tms3203x_device::xor3sti, &tms3203x_device::xor3sti, + &tms3203x_device::xor3sti, &tms3203x_device::xor3sti, &tms3203x_device::xor3sti, &tms3203x_device::xor3sti, + &tms3203x_device::xor3sti, &tms3203x_device::xor3sti, &tms3203x_device::xor3sti, &tms3203x_device::xor3sti, + &tms3203x_device::xor3sti, &tms3203x_device::xor3sti, &tms3203x_device::xor3sti, &tms3203x_device::xor3sti, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, // 0x1e0 + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, // 0x1e8 + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, // 0x1f0 + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, // 0x1f8 + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, + &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal, &tms3203x_device::illegal +}; diff --git a/src/devices/cpu/tms32031/dis32031.c b/src/devices/cpu/tms32031/dis32031.c new file mode 100644 index 00000000000..bc2bd737318 --- /dev/null +++ b/src/devices/cpu/tms32031/dis32031.c @@ -0,0 +1,745 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + dis32031.c + Disassembler for the portable TMS32C031 emulator. + Written by Aaron Giles + +***************************************************************************/ + +#include "emu.h" +#include "tms32031.h" + + +/*************************************************************************** + MEMORY ACCESSORS +***************************************************************************/ + +#define INTEGER 0 +#define FLOAT 1 +#define NODEST 2 +#define NOSOURCE 4 +#define NOSOURCE1 NOSOURCE +#define NOSOURCE2 8 +#define SWAPSRCDST 16 +#define UNSIGNED 32 + + +/*************************************************************************** + CODE CODE +***************************************************************************/ + +#if 0 +INLINE char *signed_16bit(INT16 val) +{ + static char temp[10]; + if (val < 0) + sprintf(temp, "-$%x", -val & 0xffff); + else + sprintf(temp, "$%x", val); + return temp; +} +#endif + +static const char *const regname[32] = +{ + "R0", "R1", "R2", "R3", "R4", "R5", "R6", "R7", + "AR0", "AR1", "AR2", "AR3", "AR4", "AR5", "AR6", "AR7", + "DP", "IR0", "IR1", "BK", "SP", "ST", "IE", "IF", + "IOF", "RS", "RE", "RC", "??", "??", "??", "??" +}; + +static const char *const condition[32] = +{ + "U", "LO", "LS", "HI", "HS", "EQ", "NE", "LT", + "LE", "GT", "GE", "??", "NV", "V", "NUF", "UF", + "NLV", "LV", "NLUF", "LUF", "ZUF", "??", "??", "??", + "??", "??", "??", "??", "??", "??", "??", "??" +}; + +// +// for instructions 0x000-0x3f +// G = (op >> 21) & 3; +// G == 0 -> register -> 000ooooo o00ddddd 00000000 000sssss +// G == 1 -> direct -> 000ooooo o01ddddd DDDDDDDD DDDDDDDD +// G == 2 -> indirect -> 000ooooo o10ddddd mmmmmaaa DDDDDDDD +// G == 3 -> immediate -> 000ooooo o11ddddd iiiiiiii iiiiiiii +// +// for instructions 0x040-0x7f +// T = (op >> 21) & 3; (src1) (src2) +// T == 0 -> reg reg -> 001ooooo o00ddddd 000sssss 000SSSSS +// T == 1 -> ind reg -> 001ooooo o01ddddd mmmmmaaa 000SSSSS +// T == 2 -> reg ind -> 001ooooo o10ddddd 000sssss MMMMMAAA +// T == 3 -> ind ind -> 001ooooo o11ddddd mmmmmaaa MMMMMAAA +// +// for instructions 0x100-0x1ff +// 10ooooPP dDsssSSS mmmmmaaa MMMMMAAA +// 10ooooPP dDsssSSS 111rrrrr 111RRRRR +// +// conditional branches +// xxxxxxBa aaDccccc 00000000 000sssss +// xxxxxxBa aaDccccc iiiiiiii iiiiiiii +// D=0(standard) or 1(delayed) +// B=0(register) or 1(immediate) +// +// status register +// 31-14 = 0 +// 13 = GIE +// 12 = CC +// 11 = CE +// 10 = CF +// 9 = 0 +// 8 = RM +// 7 = OVM +// 6 = LUF (latched FP underflow) +// 5 = LV (latched overflow) +// 4 = UF (FP underflow) +// 3 = N +// 2 = Z +// 1 = V +// 0 = C +// +// conditions: +// 0 = U (unconditional) +// 1 = LO (C) +// 2 = LS (C | Z) +// 3 = HI (~C & ~Z) +// 4 = HS (~C) +// 5 = EQ (Z) +// 6 = NE (~Z) +// 7 = LT (N) +// 8 = LE (N | Z) +// 9 = GT (~N & ~Z) +// 10 = GE (~N) +// 12 = NV (~V) +// 13 = V (V) +// 14 = NUF (~UF) +// 15 = UF (UF) +// 16 = NLV (~LV) +// 17 = LV (LV) +// 18 = NLUF (~LUF) +// 19 = LUF (LUF) +// 20 = ZUF (Z | UF) + +static void append_indirect(UINT8 ma, INT8 disp, char *buffer) +{ + char *dst = &buffer[strlen(buffer)]; + char dispstr[20]; + int mode = (ma >> 3) & 0x1f; + int ar = ma & 7; + + dispstr[0] = 0; + if (disp < 0) + sprintf(dispstr, "(-%X)", -disp & 0xffff); + else if (disp > 0) + sprintf(dispstr, "(%X)", disp); + + switch (mode) + { + case 0: sprintf(dst, "*+AR%d%s", ar, dispstr); break; + case 1: sprintf(dst, "*-AR%d%s", ar, dispstr); break; + case 2: sprintf(dst, "*++AR%d%s", ar, dispstr); break; + case 3: sprintf(dst, "*--AR%d%s", ar, dispstr); break; + case 4: sprintf(dst, "*AR%d++%s", ar, dispstr); break; + case 5: sprintf(dst, "*AR%d--%s", ar, dispstr); break; + case 6: sprintf(dst, "*AR%d++%s%%", ar, dispstr); break; + case 7: sprintf(dst, "*AR%d--%s%%", ar, dispstr); break; + + case 8: sprintf(dst, "*+AR%d(IR0)", ar); break; + case 9: sprintf(dst, "*-AR%d(IR0)", ar); break; + case 10: sprintf(dst, "*++AR%d(IR0)", ar); break; + case 11: sprintf(dst, "*--AR%d(IR0)", ar); break; + case 12: sprintf(dst, "*AR%d++(IR0)", ar); break; + case 13: sprintf(dst, "*AR%d--(IR0)", ar); break; + case 14: sprintf(dst, "*AR%d++(IR0)%%", ar); break; + case 15: sprintf(dst, "*AR%d--(IR0)%%", ar); break; + + case 16: sprintf(dst, "*+AR%d(IR1)", ar); break; + case 17: sprintf(dst, "*-AR%d(IR1)", ar); break; + case 18: sprintf(dst, "*++AR%d(IR1)", ar); break; + case 19: sprintf(dst, "*--AR%d(IR1)", ar); break; + case 20: sprintf(dst, "*AR%d++(IR1)", ar); break; + case 21: sprintf(dst, "*AR%d--(IR1)", ar); break; + case 22: sprintf(dst, "*AR%d++(IR1)%%", ar); break; + case 23: sprintf(dst, "*AR%d--(IR1)%%", ar); break; + + case 24: sprintf(dst, "*AR%d", ar); break; + case 25: sprintf(dst, "*AR%d++(IR0)B", ar); break; + case 28: + case 29: + case 30: + case 31: strcpy(dst, regname[ma & 31]); break; + default: sprintf(dst, "(unknown mode)"); break; + } +} + +static void append_immediate(UINT16 data, int is_float, int is_unsigned, char *buffer) +{ + char *dst = &buffer[strlen(buffer)]; + + if (is_float) + { + int exp = ((INT16)data >> 12) + 127; + UINT32 expanded_data; + float float_val; + + expanded_data = ((data & 0x0800) << 20) + ((exp << 23) & 0x7f800000); + if (data == 0x8000) + *(float *)&expanded_data = 0; + else if (!(data & 0x0800)) + expanded_data += ((data & 0x0fff) << 12); + else + expanded_data += ((-data & 0x0fff) << 12); + float_val = *(float *)&expanded_data; + sprintf(dst, "%8f", (double) float_val); + } + else if (!is_unsigned && (INT16)data < 0) + sprintf(dst, "-$%04X", -data & 0xffff); + else + sprintf(dst, "$%04X", data); +} + +static void disasm_general(const char *opstring, UINT32 op, int flags, char *buffer) +{ + sprintf(buffer, "%-6s", opstring); + + if (flags & SWAPSRCDST) + { + strcat(buffer, regname[(op >> 16) & 31]); + strcat(buffer, ","); + } + + /* switch off of G */ + if (!(flags & NOSOURCE)) + { + switch ((op >> 21) & 3) + { + case 0: + strcat(buffer, regname[op & 31]); + break; + + case 1: + sprintf(&buffer[strlen(buffer)], "($%04X)", op & 0xffff); + break; + + case 2: + append_indirect((op >> 8) & 0xff, op, buffer); + break; + + case 3: + append_immediate(op & 0xffff, (flags & FLOAT), (flags & UNSIGNED), buffer); + break; + } + } + + /* add destination op */ + if (!(flags & NODEST) && !(flags & SWAPSRCDST)) + { + if (!(flags & NOSOURCE)) + strcat(buffer, ","); + strcat(buffer, regname[(op >> 16) & 31]); + } +} + +static void disasm_3op(const char *opstring, UINT32 op, int flags, char *buffer) +{ + sprintf(buffer, "%-6s", opstring); + + /* switch off of T */ + if (!(flags & NOSOURCE1)) + { + switch ((op >> 21) & 1) + { + case 0: + strcat(buffer, regname[(op >> 8) & 31]); + break; + + case 1: + append_indirect(op >> 8, 1, buffer); + break; + } + } + + /* switch off of T */ + if (!(flags & NOSOURCE2)) + { + if (!(flags & NOSOURCE1)) + strcat(buffer, ","); + switch ((op >> 22) & 1) + { + case 0: + strcat(buffer, regname[op & 31]); + break; + + case 1: + append_indirect(op, 1, buffer); + break; + } + } + + /* add destination op */ + if (!(flags & NODEST)) + { + if (!(flags & (NOSOURCE1 | NOSOURCE2))) + strcat(buffer, ","); + strcat(buffer, regname[(op >> 16) & 31]); + } +} + +static void disasm_conditional(const char *opstring, UINT32 op, int flags, char *buffer) +{ + char temp[10]; + sprintf(temp, "%s%s", opstring, condition[(op >> 23) & 31]); + disasm_general(temp, op, flags, buffer); +} + + +static void disasm_parallel_3op3op(const char *opstring1, const char *opstring2, UINT32 op, int flags, const UINT8 *srctable, char *buffer) +{ + const UINT8 *s = &srctable[((op >> 24) & 3) * 4]; + int d1 = (op >> 23) & 1; + int d2 = 2 + ((op >> 22) & 1); + char src[5][20]; + + strcpy(src[1], regname[(op >> 19) & 7]); + strcpy(src[2], regname[(op >> 16) & 7]); + + src[3][0] = 0; + append_indirect(op >> 8, 1, src[3]); + + src[4][0] = 0; + append_indirect(op, 1, src[4]); + + sprintf(buffer, "%s %s,%s,R%d || %s %s,%s,R%d", + opstring1, src[s[0]], src[s[1]], d1, + opstring2, src[s[2]], src[s[3]], d2); +} + + +static void disasm_parallel_3opstore(const char *opstring1, const char *opstring2, UINT32 op, int flags, char *buffer) +{ + int d1 = (op >> 22) & 7; + int s1 = (op >> 19) & 7; + int s3 = (op >> 16) & 7; + char dst2[20], src2[20]; + + dst2[0] = 0; + append_indirect(op >> 8, 1, dst2); + + src2[0] = 0; + append_indirect(op, 1, src2); + + if (!(flags & NOSOURCE1)) + sprintf(buffer, "%s R%d,%s,R%d || %s R%d,%s", + opstring1, s1, src2, d1, + opstring2, s3, dst2); + else + sprintf(buffer, "%s %s,R%d || %s R%d,%s", + opstring1, src2, d1, + opstring2, s3, dst2); +} + + +static void disasm_parallel_loadload(const char *opstring1, const char *opstring2, UINT32 op, int flags, char *buffer) +{ + int d2 = (op >> 22) & 7; + int d1 = (op >> 19) & 7; + char src1[20], src2[20]; + + src1[0] = 0; + append_indirect(op >> 8, 1, src1); + + src2[0] = 0; + append_indirect(op, 1, src2); + + sprintf(buffer, "%s %s,R%d || %s %s,R%d", + opstring1, src2, d2, + opstring2, src1, d1); +} + + +static void disasm_parallel_storestore(const char *opstring1, const char *opstring2, UINT32 op, int flags, char *buffer) +{ + int s2 = (op >> 22) & 7; + int s1 = (op >> 16) & 7; + char dst1[20], dst2[20]; + + dst1[0] = 0; + append_indirect(op >> 8, 1, dst1); + + dst2[0] = 0; + append_indirect(op, 1, dst2); + + sprintf(buffer, "%s R%d,%s || %s R%d,%s", + opstring1, s2, dst2, + opstring2, s1, dst1); +} + + + +static unsigned dasm_tms3203x(char *buffer, unsigned pc, UINT32 op) +{ + UINT32 flags = 0; + + switch (op >> 23) + { + case 0x000: disasm_general("ABSF", op, FLOAT, buffer); break; + case 0x001: disasm_general("ABSI", op, INTEGER, buffer); break; + case 0x002: disasm_general("ADDC", op, INTEGER, buffer); break; + case 0x003: disasm_general("ADDF", op, FLOAT, buffer); break; + case 0x004: disasm_general("ADDI", op, INTEGER, buffer); break; + case 0x005: disasm_general("AND", op, INTEGER | UNSIGNED, buffer); break; + case 0x006: disasm_general("ANDN", op, INTEGER | UNSIGNED, buffer); break; + case 0x007: disasm_general("ASH", op, INTEGER, buffer); break; + + case 0x008: disasm_general("CMPF", op, FLOAT, buffer); break; + case 0x009: disasm_general("CMPI", op, INTEGER, buffer); break; + case 0x00a: disasm_general("FIX", op, FLOAT, buffer); break; + case 0x00b: disasm_general("FLOAT", op, INTEGER, buffer); break; + case 0x00c: disasm_general((op & 1) ? "IDLE2" : "IDLE", op, NOSOURCE | NODEST, buffer); break; + case 0x00d: disasm_general("LDE", op, FLOAT, buffer); break; + case 0x00e: disasm_general("LDF", op, FLOAT, buffer); break; + case 0x00f: disasm_general("LDFI", op, FLOAT, buffer); break; + + case 0x010: disasm_general("LDI", op, INTEGER, buffer); break; + case 0x011: disasm_general("LDII", op, INTEGER, buffer); break; + case 0x012: disasm_general("LDM", op, FLOAT, buffer); break; + case 0x013: disasm_general("LSH", op, INTEGER, buffer); break; + case 0x014: disasm_general("MPYF", op, FLOAT, buffer); break; + case 0x015: disasm_general("MPYI", op, INTEGER, buffer); break; + case 0x016: disasm_general("NEGB", op, INTEGER, buffer); break; + case 0x017: disasm_general("NEGF", op, FLOAT, buffer); break; + + case 0x018: disasm_general("NEGI", op, INTEGER, buffer); break; + case 0x019: disasm_general("NOP", op, NODEST, buffer); break; + case 0x01a: disasm_general("NORM", op, FLOAT, buffer); break; + case 0x01b: disasm_general("NOT", op, INTEGER, buffer); break; + case 0x01c: disasm_general("POP", op, NOSOURCE, buffer); break; + case 0x01d: disasm_general("POPF", op, NOSOURCE, buffer); break; + case 0x01e: disasm_general("PUSH", op, NOSOURCE, buffer); break; + case 0x01f: disasm_general("PUSHF", op, NOSOURCE, buffer); break; + + case 0x020: disasm_general("OR", op, INTEGER | UNSIGNED, buffer); break; + case 0x021: disasm_general((op & 1) ? "LOPOWER" : "MAXSPEED", op, NOSOURCE | NODEST, buffer); break; + case 0x022: disasm_general("RND", op, FLOAT, buffer); break; + case 0x023: disasm_general("ROL", op, INTEGER, buffer); break; + case 0x024: disasm_general("ROLC", op, INTEGER, buffer); break; + case 0x025: disasm_general("ROR", op, INTEGER, buffer); break; + case 0x026: disasm_general("RORC", op, INTEGER, buffer); break; + case 0x027: disasm_general("RTPS", op, INTEGER | NODEST, buffer); break; + + case 0x028: disasm_general("STF", op, FLOAT | SWAPSRCDST, buffer); break; + case 0x029: disasm_general("STFI", op, FLOAT | SWAPSRCDST, buffer); break; + case 0x02a: disasm_general("STI", op, INTEGER | SWAPSRCDST, buffer); break; + case 0x02b: disasm_general("STII", op, INTEGER | SWAPSRCDST, buffer); break; + case 0x02c: disasm_general("SIGI", op, NOSOURCE | NODEST, buffer); break; + case 0x02d: disasm_general("SUBB", op, INTEGER, buffer); break; + case 0x02e: disasm_general("SUBC", op, INTEGER, buffer); break; + case 0x02f: disasm_general("SUBF", op, FLOAT, buffer); break; + + case 0x030: disasm_general("SUBI", op, INTEGER, buffer); break; + case 0x031: disasm_general("SUBRB", op, INTEGER, buffer); break; + case 0x032: disasm_general("SUBRF", op, FLOAT, buffer); break; + case 0x033: disasm_general("SUBRI", op, INTEGER, buffer); break; + case 0x034: disasm_general("TSTB", op, INTEGER, buffer); break; + case 0x035: disasm_general("XOR", op, INTEGER | UNSIGNED, buffer); break; + case 0x036: disasm_general("IACK", op, INTEGER | NODEST, buffer); break; + + case 0x040: disasm_3op("ADDC3", op, INTEGER, buffer); break; + case 0x041: disasm_3op("ADDF3", op, FLOAT, buffer); break; + case 0x042: disasm_3op("ADDI3", op, INTEGER, buffer); break; + case 0x043: disasm_3op("AND3", op, INTEGER, buffer); break; + case 0x044: disasm_3op("ANDN3", op, INTEGER, buffer); break; + case 0x045: disasm_3op("ASH3", op, INTEGER, buffer); break; + case 0x046: disasm_3op("CMPF3", op, FLOAT | NODEST, buffer); break; + case 0x047: disasm_3op("CMPI3", op, INTEGER | NODEST, buffer); break; + + case 0x048: disasm_3op("LSH3", op, INTEGER, buffer); break; + case 0x049: disasm_3op("MPYF3", op, FLOAT, buffer); break; + case 0x04a: disasm_3op("MPYI3", op, INTEGER, buffer); break; + case 0x04b: disasm_3op("OR3", op, INTEGER, buffer); break; + case 0x04c: disasm_3op("SUBB3", op, INTEGER, buffer); break; + case 0x04d: disasm_3op("SUBF3", op, FLOAT, buffer); break; + case 0x04e: disasm_3op("SUBI3", op, INTEGER, buffer); break; + case 0x04f: disasm_3op("TSTB3", op, INTEGER, buffer); break; + + case 0x050: disasm_3op("XOR3", op, INTEGER, buffer); break; + + case 0x080: case 0x081: case 0x082: case 0x083: + case 0x084: case 0x085: case 0x086: case 0x087: + case 0x088: case 0x089: case 0x08a: case 0x08b: + case 0x08c: case 0x08d: case 0x08e: case 0x08f: + case 0x090: case 0x091: case 0x092: case 0x093: + case 0x094: case 0x095: case 0x096: case 0x097: + case 0x098: case 0x099: case 0x09a: case 0x09b: + case 0x09c: case 0x09d: case 0x09e: case 0x09f: + disasm_conditional("LDF", op, FLOAT, buffer); + break; + + case 0x0a0: case 0x0a1: case 0x0a2: case 0x0a3: + case 0x0a4: case 0x0a5: case 0x0a6: case 0x0a7: + case 0x0a8: case 0x0a9: case 0x0aa: case 0x0ab: + case 0x0ac: case 0x0ad: case 0x0ae: case 0x0af: + case 0x0b0: case 0x0b1: case 0x0b2: case 0x0b3: + case 0x0b4: case 0x0b5: case 0x0b6: case 0x0b7: + case 0x0b8: case 0x0b9: case 0x0ba: case 0x0bb: + case 0x0bc: case 0x0bd: case 0x0be: case 0x0bf: + disasm_conditional("LDI", op, INTEGER, buffer); + break; + + + case 0x0c0: case 0x0c1: + sprintf(buffer, "BR $%06X", op & 0xffffff); + break; + + case 0x0c2: case 0x0c3: + sprintf(buffer, "BRD $%06X", op & 0xffffff); + break; + + case 0x0c4: case 0x0c5: + sprintf(buffer, "CALL $%06X", op & 0xffffff); + flags = DASMFLAG_STEP_OVER; + break; + + + case 0x0c8: case 0x0c9: + sprintf(buffer, "RPTB $%06X", op & 0xffffff); + break; + + case 0x0cc: case 0x0cd: case 0x0ce: case 0x0cf: + sprintf(buffer, "SWI"); + break; + + + case 0x0d0: + { + char temp[10]; + sprintf(temp, "B%s%s", condition[(op >> 16) & 31], ((op >> 21) & 1) ? "D" : ""); + sprintf(buffer, "%-6s%s", temp, regname[op & 31]); + break; + } + + case 0x0d4: + { + char temp[10]; + sprintf(temp, "B%s%s", condition[(op >> 16) & 31], ((op >> 21) & 1) ? "D" : ""); + sprintf(buffer, "%-6s$%06X", temp, (pc + (((op >> 21) & 1) ? 3 : 1) + (INT16)op) & 0xffffff); + break; + } + + + case 0x0d8: case 0x0d9: case 0x0da: case 0x0db: + { + char temp[10]; + sprintf(temp, "DB%s%s", condition[(op >> 16) & 31], ((op >> 21) & 1) ? "D" : ""); + sprintf(buffer, "%-6sAR%d,%s", temp, (op >> 22) & 7, regname[op & 31]); + break; + } + + case 0x0dc: case 0x0dd: case 0x0de: case 0x0df: + { + char temp[10]; + sprintf(temp, "DB%s%s", condition[(op >> 16) & 31], ((op >> 21) & 1) ? "D" : ""); + sprintf(buffer, "%-6sAR%d,$%06X", temp, (op >> 22) & 7, (pc + (((op >> 21) & 1) ? 3 : 1) + (INT16)op) & 0xffffff); + break; + } + + + case 0x0e0: + { + char temp[10]; + sprintf(temp, "CALL%s", condition[(op >> 16) & 31]); + sprintf(buffer, "%-6s%s", temp, regname[op & 31]); + flags = DASMFLAG_STEP_OVER; + break; + } + + case 0x0e4: + { + char temp[10]; + sprintf(temp, "CALL%s", condition[(op >> 16) & 31]); + sprintf(buffer, "%-6s$%06X", temp, (pc + 1 + (INT16)op) & 0xffffff); + flags = DASMFLAG_STEP_OVER; + break; + } + + + case 0x0e8: case 0x0e9: case 0x0ea: case 0x0eb: + { + char temp[10]; + sprintf(temp, "TRAP%s", condition[(op >> 16) & 31]); + sprintf(buffer, "%-6s$%02X", temp, op & 31); + flags = DASMFLAG_STEP_OVER; + break; + } + + + case 0x0f0: + sprintf(buffer, "RETI%s", condition[(op >> 16) & 31]); + flags = DASMFLAG_STEP_OUT; + break; + + case 0x0f1: + sprintf(buffer, "RETS%s", condition[(op >> 16) & 31]); + flags = DASMFLAG_STEP_OUT; + break; + + + case 0x100: case 0x101: case 0x102: case 0x103: + case 0x104: case 0x105: case 0x106: case 0x107: // MPYF3||ADDF3 + { + static const UINT8 srctable[] = { 3,4,1,2, 3,1,4,2, 1,2,3,4, 3,1,2,4 }; + disasm_parallel_3op3op("MPYF3", "ADDF3", op, FLOAT, srctable, buffer); + break; + } + + + case 0x108: case 0x109: case 0x10a: case 0x10b: + case 0x10c: case 0x10d: case 0x10e: case 0x10f: // MPYF3||SUBF3 + { + static const UINT8 srctable[] = { 3,4,1,2, 3,1,4,2, 1,2,3,4, 3,1,2,4 }; + disasm_parallel_3op3op("MPYF3", "SUBF3", op, FLOAT, srctable, buffer); + break; + } + + + case 0x110: case 0x111: case 0x112: case 0x113: + case 0x114: case 0x115: case 0x116: case 0x117: // MPYI3||ADDI3 + { + static const UINT8 srctable[] = { 3,4,1,2, 3,1,4,2, 1,2,3,4, 3,1,2,4 }; + disasm_parallel_3op3op("MPYI3", "ADDI3", op, INTEGER, srctable, buffer); + break; + } + + + case 0x118: case 0x119: case 0x11a: case 0x11b: + case 0x11c: case 0x11d: case 0x11e: case 0x11f: // MPYI3||SUBI3 + { + static const UINT8 srctable[] = { 3,4,1,2, 3,1,4,2, 1,2,3,4, 3,1,2,4 }; + disasm_parallel_3op3op("MPYI3", "SUBI3", op, INTEGER, srctable, buffer); + break; + } + + + case 0x180: case 0x181: case 0x182: case 0x183: // STF||STF + disasm_parallel_storestore("STF", "STF", op, FLOAT, buffer); + break; + + case 0x184: case 0x185: case 0x186: case 0x187: // STI||STI + disasm_parallel_storestore("STI", "STI", op, INTEGER, buffer); + break; + + + case 0x188: case 0x189: case 0x18a: case 0x18b: // LDF||LDF + disasm_parallel_loadload("LDF", "LDF", op, FLOAT, buffer); + break; + + case 0x18c: case 0x18d: case 0x18e: case 0x18f: // LDI||LDI + disasm_parallel_loadload("LDI", "LDI", op, INTEGER, buffer); + break; + + + case 0x190: case 0x191: case 0x192: case 0x193: // ABSF||STF + disasm_parallel_3opstore("ABSF", "STF", op, FLOAT | NOSOURCE1, buffer); + break; + + case 0x194: case 0x195: case 0x196: case 0x197: // ABSI||STI + disasm_parallel_3opstore("ABSI", "STI", op, INTEGER | NOSOURCE1, buffer); + break; + + + case 0x198: case 0x199: case 0x19a: case 0x19b: // ADDF3||STF + disasm_parallel_3opstore("ADDF3", "STF", op, FLOAT, buffer); + break; + + case 0x19c: case 0x19d: case 0x19e: case 0x19f: // ADDI3||STI + disasm_parallel_3opstore("ADDI3", "STI", op, INTEGER, buffer); + break; + + + case 0x1a0: case 0x1a1: case 0x1a2: case 0x1a3: // AND3||STI + disasm_parallel_3opstore("AND3", "STI", op, INTEGER, buffer); + break; + + case 0x1a4: case 0x1a5: case 0x1a6: case 0x1a7: // ASH3||STI + disasm_parallel_3opstore("ASH3", "STI", op, INTEGER, buffer); + break; + + + case 0x1a8: case 0x1a9: case 0x1aa: case 0x1ab: // FIX||STI + disasm_parallel_3opstore("FIX", "STF", op, FLOAT | NOSOURCE1, buffer); + break; + + case 0x1ac: case 0x1ad: case 0x1ae: case 0x1af: // FLOAT||STF + disasm_parallel_3opstore("FLOAT", "STF", op, FLOAT | NOSOURCE1, buffer); + break; + + + case 0x1b0: case 0x1b1: case 0x1b2: case 0x1b3: // LDF||STF + disasm_parallel_3opstore("LDF", "STF", op, FLOAT | NOSOURCE1, buffer); + break; + + case 0x1b4: case 0x1b5: case 0x1b6: case 0x1b7: // LDI||STI + disasm_parallel_3opstore("LDI", "STI", op, INTEGER | NOSOURCE1, buffer); + break; + + + case 0x1b8: case 0x1b9: case 0x1ba: case 0x1bb: // LSH3||STI + disasm_parallel_3opstore("LSH3", "STI", op, INTEGER, buffer); + break; + + case 0x1bc: case 0x1bd: case 0x1be: case 0x1bf: // MPYF3||STF + disasm_parallel_3opstore("MPYF3", "STF", op, FLOAT, buffer); + break; + + + case 0x1c0: case 0x1c1: case 0x1c2: case 0x1c3: // MPYI3||STI + disasm_parallel_3opstore("MPYI3", "STI", op, INTEGER, buffer); + break; + + case 0x1c4: case 0x1c5: case 0x1c6: case 0x1c7: // NEGF||STF + disasm_parallel_3opstore("NEGF", "STF", op, FLOAT | NOSOURCE1, buffer); + break; + + + case 0x1c8: case 0x1c9: case 0x1ca: case 0x1cb: // NEGI||STI + disasm_parallel_3opstore("NEGI", "STI", op, INTEGER | NOSOURCE1, buffer); + break; + + case 0x1cc: case 0x1cd: case 0x1ce: case 0x1cf: // NOT||STI + disasm_parallel_3opstore("NOT", "STI", op, INTEGER | NOSOURCE1, buffer); + break; + + + case 0x1d0: case 0x1d1: case 0x1d2: case 0x1d3: // OR3||STI + disasm_parallel_3opstore("OR3", "STI", op, INTEGER, buffer); + break; + + case 0x1d4: case 0x1d5: case 0x1d6: case 0x1d7: // SUBF3||STF + disasm_parallel_3opstore("SUBF3", "STF", op, FLOAT, buffer); + break; + + + case 0x1d8: case 0x1d9: case 0x1da: case 0x1db: // SUBI3||STI + disasm_parallel_3opstore("SUBI3", "STI", op, INTEGER, buffer); + break; + + case 0x1dc: case 0x1dd: case 0x1de: case 0x1df: // XOR3||STI + disasm_parallel_3opstore("XOR3", "STI", op, INTEGER, buffer); + break; + + + default: + break; + } + + return 1 | flags | DASMFLAG_SUPPORTED; +} + + +CPU_DISASSEMBLE( tms3203x ) +{ + UINT32 op = oprom[0] | (oprom[1] << 8) | (oprom[2] << 16) | (oprom[3] << 24); + return dasm_tms3203x(buffer, pc, op); +} diff --git a/src/devices/cpu/tms32031/tms32031.c b/src/devices/cpu/tms32031/tms32031.c new file mode 100644 index 00000000000..1d8096ce959 --- /dev/null +++ b/src/devices/cpu/tms32031/tms32031.c @@ -0,0 +1,849 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + tms32031.c + + TMS32031/2 emulator + +***************************************************************************/ + +#include "emu.h" +#include "debugger.h" +#include "tms32031.h" + + +//************************************************************************** +// CONSTANTS +//************************************************************************** + +// indexes into the register file +enum +{ + TMR_R0 = 0, + TMR_R1, + TMR_R2, + TMR_R3, + TMR_R4, + TMR_R5, + TMR_R6, + TMR_R7, + TMR_AR0, + TMR_AR1, + TMR_AR2, + TMR_AR3, + TMR_AR4, + TMR_AR5, + TMR_AR6, + TMR_AR7, + TMR_DP, + TMR_IR0, + TMR_IR1, + TMR_BK, + TMR_SP, + TMR_ST, + TMR_IE, + TMR_IF, + TMR_IOF, + TMR_RS, + TMR_RE, + TMR_RC, + TMR_R8, // 3204x only + TMR_R9, // 3204x only + TMR_R10, // 3204x only + TMR_R11, // 3204x only + TMR_TEMP1, // used by the interpreter + TMR_TEMP2, // used by the interpreter + TMR_TEMP3 // used by the interpreter +}; + +// flags +const int CFLAG = 0x0001; +const int VFLAG = 0x0002; +const int ZFLAG = 0x0004; +const int NFLAG = 0x0008; +const int UFFLAG = 0x0010; +const int LVFLAG = 0x0020; +const int LUFFLAG = 0x0040; +const int OVMFLAG = 0x0080; +const int RMFLAG = 0x0100; +//const int CFFLAG = 0x0400; +//const int CEFLAG = 0x0800; +//const int CCFLAG = 0x1000; +const int GIEFLAG = 0x2000; + + + +//************************************************************************** +// MACROS +//************************************************************************** + +#define IREG(rnum) (m_r[rnum].i32[0]) + + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +// device type definition +const device_type TMS32031 = &device_creator; +const device_type TMS32032 = &device_creator; + + +// internal memory maps +static ADDRESS_MAP_START( internal_32031, AS_PROGRAM, 32, tms32031_device ) + AM_RANGE(0x809800, 0x809fff) AM_RAM +ADDRESS_MAP_END + +static ADDRESS_MAP_START( internal_32032, AS_PROGRAM, 32, tms32032_device ) + AM_RANGE(0x87fe00, 0x87ffff) AM_RAM +ADDRESS_MAP_END + + +// ROM definitions for the internal boot loader programs +// (Using assembled versions until the code ROMs are extracted from both DSPs) +ROM_START( tms32031 ) + ROM_REGION(0x4000, "tms32031", 0) + ROM_LOAD( "c31boot.bin", 0x0000, 0x4000, BAD_DUMP CRC(bddc2763) SHA1(96b2170ecee5bec5abaa1741bb2d3b6096ecc262) ) // Assembled from c31boot.asm (02-07-92) +ROM_END + +ROM_START( tms32032 ) + ROM_REGION(0x4000, "tms32032", 0) + ROM_LOAD( "c32boot.bin", 0x0000, 0x4000, BAD_DUMP CRC(ecf84729) SHA1(4d32ead450f921f563514b061ea561a222283616) ) // Assembled from c32boot.asm (03-04-96) +ROM_END + + + +//************************************************************************** +// TMSREG REGISTER +//************************************************************************** + +//------------------------------------------------- +// as_float - interpret the contents of a tmsreg +// as a DSP-encoded floating-point value, and +// extract a 32-bit IEEE float from it +//------------------------------------------------- + +float tms3203x_device::tmsreg::as_float() const +{ + int_double id; + + // map 0 to 0 + if (mantissa() == 0 && exponent() == -128) + return 0; + + // handle positive numbers + else if (mantissa() >= 0) + { + int exp = (exponent() + 127) << 23; + id.i[0] = exp + (mantissa() >> 8); + } + + // handle negative numbers + else + { + int exp = (exponent() + 127) << 23; + INT32 man = -mantissa(); + id.i[0] = 0x80000000 + exp + ((man >> 8) & 0x00ffffff); + } + + // return the converted float + return id.f[0]; +} + + +//------------------------------------------------- +// as_double - interpret the contents of a tmsreg +// as a DSP-encoded floating-point value, and +// extract a 64-bit IEEE double from it +//------------------------------------------------- + +double tms3203x_device::tmsreg::as_double() const +{ + int_double id; + + // map 0 to 0 + if (mantissa() == 0 && exponent() == -128) + return 0; + + // handle positive numbers + else if (mantissa() >= 0) + { + int exp = (exponent() + 1023) << 20; + id.i[BYTE_XOR_BE(0)] = exp + (mantissa() >> 11); + id.i[BYTE_XOR_BE(1)] = (mantissa() << 21) & 0xffe00000; + } + + // handle negative numbers + else + { + int exp = (exponent() + 1023) << 20; + INT32 man = -mantissa(); + id.i[BYTE_XOR_BE(0)] = 0x80000000 + exp + ((man >> 11) & 0x001fffff); + id.i[BYTE_XOR_BE(1)] = (man << 21) & 0xffe00000; + } + + // return the converted double + return id.d; +} + + +//------------------------------------------------- +// from_double - import a 64-bit IEEE double into +// the DSP's internal floating point format +//------------------------------------------------- + +void tms3203x_device::tmsreg::from_double(double val) +{ + // extract mantissa and exponent from the IEEE input + int_double id; + id.d = val; + INT32 mantissa = ((id.i[BYTE_XOR_BE(0)] & 0x000fffff) << 11) | ((id.i[BYTE_XOR_BE(1)] & 0xffe00000) >> 21); + INT32 exponent = ((id.i[BYTE_XOR_BE(0)] & 0x7ff00000) >> 20) - 1023; + + // if we're too small, map to 0 + if (exponent < -128) + { + set_mantissa(0); + set_exponent(-128); + } + + // if we're too large, map to the maximum value + else if (exponent > 127) + { + if ((INT32)id.i[BYTE_XOR_BE(0)] >= 0) + set_mantissa(0x7fffffff); + else + set_mantissa(0x80000001); + set_exponent(127); + } + + // if we're positive, map directly + else if ((INT32)id.i[BYTE_XOR_BE(0)] >= 0) + { + set_mantissa(mantissa); + set_exponent(exponent); + } + + // if we're negative with a non-zero mantissa, remove the leading sign bit + else if (mantissa != 0) + { + set_mantissa(0x80000000 | -mantissa); + set_exponent(exponent); + } + + // if we're negative with a zero mantissa, normalize + else + { + set_mantissa(0x80000000); + set_exponent(exponent - 1); + } +} + + + +//************************************************************************** +// DEVICE INTERFACE +//************************************************************************** + +//------------------------------------------------- +// tms3203x_device - constructor +//------------------------------------------------- + +tms3203x_device::tms3203x_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, UINT32 chiptype, address_map_constructor internal_map, const char *shortname, const char *source) + : cpu_device(mconfig, type, name, tag, owner, clock, shortname, source), + m_program_config("program", ENDIANNESS_LITTLE, 32, 24, -2, internal_map), + m_chip_type(chiptype), + m_pc(0), + m_bkmask(0), + m_irq_state(0), + m_delayed(false), + m_irq_pending(false), + m_is_idling(false), + m_icount(0), + m_program(0), + m_direct(0), + m_mcbl_mode(false), + m_xf0_cb(*this), + m_xf1_cb(*this), + m_iack_cb(*this) +{ + // initialize remaining state + memset(&m_r, 0, sizeof(m_r)); + + // set our instruction counter + m_icountptr = &m_icount; + +#if (TMS_3203X_LOG_OPCODE_USAGE) + memset(m_hits, 0, sizeof(m_hits)); +#endif +} + +tms32031_device::tms32031_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : tms3203x_device(mconfig, TMS32031, "TMS32031", tag, owner, clock, CHIP_TYPE_TMS32031, ADDRESS_MAP_NAME(internal_32031), "tms32031", __FILE__) +{ +} + +tms32032_device::tms32032_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : tms3203x_device(mconfig, TMS32032, "TMS32032", tag, owner, clock, CHIP_TYPE_TMS32032, ADDRESS_MAP_NAME(internal_32032), "tms32032", __FILE__) +{ +} + + +DIRECT_UPDATE_MEMBER( tms3203x_device::direct_handler ) +{ + // internal boot loader ROM + if (m_mcbl_mode && address < (0x1000 << 2)) + { + direct.explicit_configure(0x000000, 0x003fff, 0x003fff, m_bootrom); + return (offs_t)-1; + } + + return address; +} + + +//------------------------------------------------- +// ~tms3203x_device - destructor +//------------------------------------------------- + +tms3203x_device::~tms3203x_device() +{ +#if (TMS_3203X_LOG_OPCODE_USAGE) + for (int i = 0; i < ARRAY_LENGTH(m_hits); i++) + if (m_hits[i] != 0) + printf("%10d - %03X.%X\n", m_hits[i], i / 4, i % 4); +#endif +} + + +//------------------------------------------------- +// rom_region - return a pointer to the device's +// internal ROM region +//------------------------------------------------- + +const rom_entry *tms3203x_device::device_rom_region() const +{ + switch (m_chip_type) + { + default: + case CHIP_TYPE_TMS32031: return ROM_NAME( tms32031 ); + case CHIP_TYPE_TMS32032: return ROM_NAME( tms32032 ); + } +} + +//------------------------------------------------- +// ROPCODE - fetch an opcode +//------------------------------------------------- + +inline UINT32 tms3203x_device::ROPCODE(offs_t pc) +{ + return m_direct->read_dword(pc << 2); +} + + +//------------------------------------------------- +// RMEM - read memory +//------------------------------------------------- + +inline UINT32 tms3203x_device::RMEM(offs_t addr) +{ + if (m_mcbl_mode && addr < 0x1000) + return m_bootrom[addr]; + + return m_program->read_dword(addr << 2); +} + + +//------------------------------------------------- +// WMEM - write memory +//------------------------------------------------- + +inline void tms3203x_device::WMEM(offs_t addr, UINT32 data) +{ + m_program->write_dword(addr << 2, data); +} + + +//------------------------------------------------- +// device_start - start up the device +//------------------------------------------------- + +void tms3203x_device::device_start() +{ + // find address spaces + m_program = &space(AS_PROGRAM); + m_direct = &m_program->direct(); + + // resolve devcb handlers + m_xf0_cb.resolve_safe(); + m_xf1_cb.resolve_safe(); + m_iack_cb.resolve_safe(); + + // set up the internal boot loader ROM + m_bootrom = reinterpret_cast(memregion(shortname())->base()); + m_direct->set_direct_update(direct_update_delegate(FUNC(tms3203x_device::direct_handler), this)); + + // save state + save_item(NAME(m_pc)); + for (int regnum = 0; regnum < 36; regnum++) + save_item(NAME(m_r[regnum].i32), regnum); + save_item(NAME(m_bkmask)); + save_item(NAME(m_irq_state)); + save_item(NAME(m_delayed)); + save_item(NAME(m_irq_pending)); + save_item(NAME(m_is_idling)); + + // register our state for the debugger + state_add(TMS3203X_PC, "PC", m_pc); + state_add(STATE_GENPC, "GENPC", m_pc).noshow(); + state_add(STATE_GENFLAGS, "GENFLAGS", m_r[TMR_ST].i32[0]).mask(0xff).noshow().formatstr("%8s"); + state_add(TMS3203X_R0, "R0", m_r[TMR_R0].i32[0]); + state_add(TMS3203X_R1, "R1", m_r[TMR_R1].i32[0]); + state_add(TMS3203X_R2, "R2", m_r[TMR_R2].i32[0]); + state_add(TMS3203X_R3, "R3", m_r[TMR_R3].i32[0]); + state_add(TMS3203X_R4, "R4", m_r[TMR_R4].i32[0]); + state_add(TMS3203X_R5, "R5", m_r[TMR_R5].i32[0]); + state_add(TMS3203X_R6, "R6", m_r[TMR_R6].i32[0]); + state_add(TMS3203X_R7, "R7", m_r[TMR_R7].i32[0]); + state_add(TMS3203X_R0F, "R0F", m_iotemp).callimport().callexport().formatstr("%12s"); + state_add(TMS3203X_R1F, "R1F", m_iotemp).callimport().callexport().formatstr("%12s"); + state_add(TMS3203X_R2F, "R2F", m_iotemp).callimport().callexport().formatstr("%12s"); + state_add(TMS3203X_R3F, "R3F", m_iotemp).callimport().callexport().formatstr("%12s"); + state_add(TMS3203X_R4F, "R4F", m_iotemp).callimport().callexport().formatstr("%12s"); + state_add(TMS3203X_R5F, "R5F", m_iotemp).callimport().callexport().formatstr("%12s"); + state_add(TMS3203X_R6F, "R6F", m_iotemp).callimport().callexport().formatstr("%12s"); + state_add(TMS3203X_R7F, "R7F", m_iotemp).callimport().callexport().formatstr("%12s"); + state_add(TMS3203X_AR0, "AR0", m_r[TMR_AR0].i32[0]); + state_add(TMS3203X_AR1, "AR1", m_r[TMR_AR1].i32[0]); + state_add(TMS3203X_AR2, "AR2", m_r[TMR_AR2].i32[0]); + state_add(TMS3203X_AR3, "AR3", m_r[TMR_AR3].i32[0]); + state_add(TMS3203X_AR4, "AR4", m_r[TMR_AR4].i32[0]); + state_add(TMS3203X_AR5, "AR5", m_r[TMR_AR5].i32[0]); + state_add(TMS3203X_AR6, "AR6", m_r[TMR_AR6].i32[0]); + state_add(TMS3203X_AR7, "AR7", m_r[TMR_AR7].i32[0]); + state_add(TMS3203X_DP, "DP", m_r[TMR_DP].i32[0]).mask(0xff); + state_add(TMS3203X_IR0, "IR0", m_r[TMR_IR0].i32[0]); + state_add(TMS3203X_IR1, "IR1", m_r[TMR_IR1].i32[0]); + state_add(TMS3203X_BK, "BK", m_r[TMR_BK].i32[0]); + state_add(TMS3203X_SP, "SP", m_r[TMR_SP].i32[0]); + state_add(TMS3203X_ST, "ST", m_r[TMR_ST].i32[0]); + state_add(TMS3203X_IE, "IE", m_r[TMR_IE].i32[0]); + state_add(TMS3203X_IF, "IF", m_r[TMR_IF].i32[0]); + state_add(TMS3203X_IOF, "IOF", m_r[TMR_IOF].i32[0]); + state_add(TMS3203X_RS, "RS", m_r[TMR_RS].i32[0]); + state_add(TMS3203X_RE, "RE", m_r[TMR_RE].i32[0]); + state_add(TMS3203X_RC, "RC", m_r[TMR_RC].i32[0]); +} + + +//------------------------------------------------- +// device_reset - reset the device +//------------------------------------------------- + +void tms3203x_device::device_reset() +{ + m_pc = RMEM(0); + + // reset some registers + IREG(TMR_IE) = 0; + IREG(TMR_IF) = 0; + IREG(TMR_ST) = 0; + IREG(TMR_IOF) = 0; + + // update IF with the external interrupt state (required for boot loader operation) + IREG(TMR_IF) |= m_irq_state & 0x0f; + + // reset internal stuff + m_delayed = m_irq_pending = m_is_idling = false; +} + + +//------------------------------------------------- +// memory_space_config - return the configuration +// of the specified address space, or NULL if +// the space doesn't exist +//------------------------------------------------- + +const address_space_config *tms3203x_device::memory_space_config(address_spacenum spacenum) const +{ + return (spacenum == AS_PROGRAM) ? &m_program_config : NULL; +} + + +//------------------------------------------------- +// state_import - import state into the device, +// after it has been set +//------------------------------------------------- + +void tms3203x_device::state_import(const device_state_entry &entry) +{ + switch (entry.index()) + { + case TMS3203X_R0F: + case TMS3203X_R1F: + case TMS3203X_R2F: + case TMS3203X_R3F: + case TMS3203X_R4F: + case TMS3203X_R5F: + case TMS3203X_R6F: + case TMS3203X_R7F: + m_r[TMR_R0 + (entry.index() - TMS3203X_R0F)].from_double(*(float *)&m_iotemp); + break; + + default: + fatalerror("CPU_IMPORT_STATE(tms3203x) called for unexpected value\n"); + } +} + + +//------------------------------------------------- +// state_export - export state into the device, +// before returning it to the caller +//------------------------------------------------- + +void tms3203x_device::state_export(const device_state_entry &entry) +{ + switch (entry.index()) + { + case TMS3203X_R0F: + case TMS3203X_R1F: + case TMS3203X_R2F: + case TMS3203X_R3F: + case TMS3203X_R4F: + case TMS3203X_R5F: + case TMS3203X_R6F: + case TMS3203X_R7F: + *(float *)&m_iotemp = m_r[TMR_R0 + (entry.index() - TMS3203X_R0F)].as_float(); + break; + + default: + fatalerror("CPU_IMPORT_STATE(tms3203x) called for unexpected value\n"); + } +} + + +//------------------------------------------------- +// state_string_export - export state as a string +// for the debugger +//------------------------------------------------- + +void tms3203x_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + switch (entry.index()) + { + case TMS3203X_R0F: + case TMS3203X_R1F: + case TMS3203X_R2F: + case TMS3203X_R3F: + case TMS3203X_R4F: + case TMS3203X_R5F: + case TMS3203X_R6F: + case TMS3203X_R7F: + strprintf(str, "%12g", m_r[TMR_R0 + (entry.index() - TMS3203X_R0F)].as_double()); + break; + + case STATE_GENFLAGS: + UINT32 temp = m_r[TMR_ST].i32[0]; + strprintf(str, "%c%c%c%c%c%c%c%c", + (temp & 0x80) ? 'O':'.', + (temp & 0x40) ? 'U':'.', + (temp & 0x20) ? 'V':'.', + (temp & 0x10) ? 'u':'.', + (temp & 0x08) ? 'n':'.', + (temp & 0x04) ? 'z':'.', + (temp & 0x02) ? 'v':'.', + (temp & 0x01) ? 'c':'.'); + break; + } +} + + +//------------------------------------------------- +// disasm_min_opcode_bytes - return the length +// of the shortest instruction, in bytes +//------------------------------------------------- + +UINT32 tms3203x_device::disasm_min_opcode_bytes() const +{ + return 4; +} + + +//------------------------------------------------- +// disasm_max_opcode_bytes - return the length +// of the longest instruction, in bytes +//------------------------------------------------- + +UINT32 tms3203x_device::disasm_max_opcode_bytes() const +{ + return 4; +} + + +//------------------------------------------------- +// disasm_disassemble - call the disassembly +// helper function +//------------------------------------------------- + +offs_t tms3203x_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( tms3203x ); + return CPU_DISASSEMBLE_NAME(tms3203x)(this, buffer, pc, oprom, opram, options); +} + + + +//************************************************************************** +// PUBLIC INTERFACES +//************************************************************************** + +//------------------------------------------------- +// fp_to_float - convert a 32-bit value from DSP +// floating-point format a 32-bit IEEE float +//------------------------------------------------- + +float tms3203x_device::fp_to_float(UINT32 floatdata) +{ + tmsreg gen(floatdata << 8, (INT32)floatdata >> 24); + return gen.as_float(); +} + + +//------------------------------------------------- +// fp_to_double - convert a 32-bit value from DSP +// floating-point format a 64-bit IEEE double +//------------------------------------------------- + +double tms3203x_device::fp_to_double(UINT32 floatdata) +{ + tmsreg gen(floatdata << 8, (INT32)floatdata >> 24); + return gen.as_double(); +} + + +//------------------------------------------------- +// float_to_fp - convert a 32-bit IEEE float to +// a 32-bit DSP floating-point value +//------------------------------------------------- + +UINT32 tms3203x_device::float_to_fp(float fval) +{ + tmsreg gen(fval); + return (gen.exponent() << 24) | ((UINT32)gen.mantissa() >> 8); +} + + +//------------------------------------------------- +// double_to_fp - convert a 64-bit IEEE double to +// a 32-bit DSP floating-point value +//------------------------------------------------- + +UINT32 tms3203x_device::double_to_fp(double dval) +{ + tmsreg gen(dval); + return (gen.exponent() << 24) | ((UINT32)gen.mantissa() >> 8); +} + + + +//************************************************************************** +// EXECUTION +//************************************************************************** + +//------------------------------------------------- +// check_irqs - check for pending IRQs and take +// them if enabled +//------------------------------------------------- + +void tms3203x_device::check_irqs() +{ + // determine if we have any live interrupts + UINT16 validints = IREG(TMR_IF) & IREG(TMR_IE) & 0x0fff; + if (validints == 0 || (IREG(TMR_ST) & GIEFLAG) == 0) + return; + + // find the lowest signalled value + int whichtrap = 0; + for (int i = 0; i < 12; i++) + if (validints & (1 << i)) + { + whichtrap = i + 1; + break; + } + + // no longer idling if we get here + m_is_idling = false; + if (!m_delayed) + { + UINT16 intmask = 1 << (whichtrap - 1); + + // bit in IF is cleared when interrupt is taken + IREG(TMR_IF) &= ~intmask; + trap(whichtrap); + + // after auto-clearing the interrupt bit, we need to re-trigger + // level-sensitive interrupts + if (m_chip_type == CHIP_TYPE_TMS32031 || (IREG(TMR_ST) & 0x4000) == 0) + IREG(TMR_IF) |= m_irq_state & 0x0f; + } + else + m_irq_pending = true; +} + + +//------------------------------------------------- +// execute_min_cycles - return minimum number of +// cycles it takes for one instruction to execute +//------------------------------------------------- + +UINT32 tms3203x_device::execute_min_cycles() const +{ + return 1; +} + + +//------------------------------------------------- +// execute_max_cycles - return maximum number of +// cycles it takes for one instruction to execute +//------------------------------------------------- + +UINT32 tms3203x_device::execute_max_cycles() const +{ + return 4; +} + + +//------------------------------------------------- +// execute_input_lines - return the number of +// input/interrupt lines +//------------------------------------------------- + +UINT32 tms3203x_device::execute_input_lines() const +{ + return (m_chip_type == CHIP_TYPE_TMS32032) ? 13 : 12; +} + + +//------------------------------------------------- +// execute_set_input - set input and IRQ lines +//------------------------------------------------- + +void tms3203x_device::execute_set_input(int inputnum, int state) +{ + // ignore anything out of range + if (inputnum >= 13) + return; + + if (inputnum == TMS3203X_MCBL) + { + // switch between microcomputer/boot loader and microprocessor modes + m_mcbl_mode = (state == ASSERT_LINE); + m_direct->force_update(); + return; + } + + // update the external state + UINT16 intmask = 1 << inputnum; + if (state == ASSERT_LINE) + { + m_irq_state |= intmask; + IREG(TMR_IF) |= intmask; + } + else + m_irq_state &= ~intmask; + + // external interrupts are level-sensitive on the '31 and can be + // configured as such on the '32; in that case, if the external + // signal is high, we need to update the value in IF accordingly + if (m_chip_type == CHIP_TYPE_TMS32031 || (IREG(TMR_ST) & 0x4000) == 0) + IREG(TMR_IF) |= m_irq_state & 0x0f; +} + + +//------------------------------------------------- +// execute_run - execute until our icount expires +//------------------------------------------------- + +void tms3203x_device::execute_run() +{ + // check IRQs up front + check_irqs(); + + // if we're idling, just eat the cycles + if (m_is_idling) + { + m_icount = 0; + return; + } + + // non-debug case + if ((machine().debug_flags & DEBUG_FLAG_ENABLED) == 0) + { + while (m_icount > 0) + { + if ((IREG(TMR_ST) & RMFLAG) && m_pc == IREG(TMR_RE) + 1) + { + if ((INT32)--IREG(TMR_RC) >= 0) + m_pc = IREG(TMR_RS); + else + { + IREG(TMR_ST) &= ~RMFLAG; + if (m_delayed) + { + m_delayed = false; + if (m_irq_pending) + { + m_irq_pending = false; + check_irqs(); + } + } + } + continue; + } + + execute_one(); + } + } + + // debugging case + else + { + while (m_icount > 0) + { + // watch for out-of-range stack pointers + if (IREG(TMR_SP) & 0xff000000) + debugger_break(machine()); + if ((IREG(TMR_ST) & RMFLAG) && m_pc == IREG(TMR_RE) + 1) + { + if ((INT32)--IREG(TMR_RC) >= 0) + m_pc = IREG(TMR_RS); + else + { + IREG(TMR_ST) &= ~RMFLAG; + if (m_delayed) + { + m_delayed = false; + if (m_irq_pending) + { + m_irq_pending = false; + check_irqs(); + } + } + } + continue; + } + + debugger_instruction_hook(this, m_pc); + execute_one(); + } + } +} + + +//************************************************************************** +// CORE OPCODES +//************************************************************************** + +#include "32031ops.c" diff --git a/src/devices/cpu/tms32031/tms32031.h b/src/devices/cpu/tms32031/tms32031.h new file mode 100644 index 00000000000..e55fcc2d3b4 --- /dev/null +++ b/src/devices/cpu/tms32031/tms32031.h @@ -0,0 +1,817 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + tms32031.h + + TMS32031/2 emulator + +***************************************************************************/ + +#pragma once + +#ifndef __TMS32031_H__ +#define __TMS32031_H__ + + +//************************************************************************** +// DEBUGGING +//************************************************************************** + +#define TMS_3203X_LOG_OPCODE_USAGE (0) + + + +//************************************************************************** +// CONSTANTS +//************************************************************************** + +// interrupts +const int TMS3203X_IRQ0 = 0; // IRQ0 +const int TMS3203X_IRQ1 = 1; // IRQ1 +const int TMS3203X_IRQ2 = 2; // IRQ2 +const int TMS3203X_IRQ3 = 3; // IRQ3 +const int TMS3203X_XINT0 = 4; // serial 0 transmit interrupt +const int TMS3203X_RINT0 = 5; // serial 0 receive interrupt +const int TMS3203X_XINT1 = 6; // serial 1 transmit interrupt +const int TMS3203X_RINT1 = 7; // serial 1 receive interrupt +const int TMS3203X_TINT0 = 8; // timer 0 interrupt +const int TMS3203X_TINT1 = 9; // timer 1 interrupt +const int TMS3203X_DINT = 10; // DMA interrupt +const int TMS3203X_DINT0 = 10; // DMA 0 interrupt (32032 only) +const int TMS3203X_DINT1 = 11; // DMA 1 interrupt (32032 only) +const int TMS3203X_MCBL = 12; // Microcomputer/boot loader mode + +// register enumeration +enum +{ + TMS3203X_PC=1, + TMS3203X_R0, + TMS3203X_R1, + TMS3203X_R2, + TMS3203X_R3, + TMS3203X_R4, + TMS3203X_R5, + TMS3203X_R6, + TMS3203X_R7, + TMS3203X_R0F, + TMS3203X_R1F, + TMS3203X_R2F, + TMS3203X_R3F, + TMS3203X_R4F, + TMS3203X_R5F, + TMS3203X_R6F, + TMS3203X_R7F, + TMS3203X_AR0, + TMS3203X_AR1, + TMS3203X_AR2, + TMS3203X_AR3, + TMS3203X_AR4, + TMS3203X_AR5, + TMS3203X_AR6, + TMS3203X_AR7, + TMS3203X_DP, + TMS3203X_IR0, + TMS3203X_IR1, + TMS3203X_BK, + TMS3203X_SP, + TMS3203X_ST, + TMS3203X_IE, + TMS3203X_IF, + TMS3203X_IOF, + TMS3203X_RS, + TMS3203X_RE, + TMS3203X_RC +}; + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_TMS3203X_MCBL(_mode) \ + tms3203x_device::set_mcbl_mode(*device, _mode); + +#define MCFG_TMS3203X_XF0_CB(_devcb) \ + devcb = &tms3203x_device::set_xf0_callback(*device, DEVCB_##_devcb); + +#define MCFG_TMS3203X_XF1_CB(_devcb) \ + devcb = &tms3203x_device::set_xf1_callback(*device, DEVCB_##_devcb); + +#define MCFG_TMS3203X_IACK_CB(_devcb) \ + devcb = &tms3203x_device::set_iack_callback(*device, DEVCB_##_devcb); + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> tms3203x_device + +class tms3203x_device : public cpu_device +{ + struct tmsreg + { + // constructors + tmsreg() { i32[0] = i32[1] = 0; } + tmsreg(double value) { from_double(value); } + tmsreg(INT32 mantissa, INT8 exponent) { set_mantissa(mantissa); set_exponent(exponent); } + + // getters + UINT32 integer() const { return i32[0]; } + INT32 mantissa() const { return i32[0]; } + INT8 exponent() const { return i32[1]; } + void set_mantissa(INT32 man) { i32[0] = man; } + void set_exponent(INT8 exp) { i32[1] = exp; } + + // exporters + float as_float() const; + double as_double() const; + + // importers + void from_double(double); + + UINT32 i32[2]; + }; + +protected: + enum + { + CHIP_TYPE_TMS32031, + CHIP_TYPE_TMS32032 + }; + + // construction/destruction + tms3203x_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, UINT32 chiptype, address_map_constructor internal_map, const char *shortname, const char *source); + virtual ~tms3203x_device(); + +public: + // inline configuration helpers + static void set_mcbl_mode(device_t &device, bool mode) { downcast(device).m_mcbl_mode = mode; } + template static devcb_base &set_xf0_callback(device_t &device, _Object object) { return downcast(device).m_xf0_cb.set_callback(object); } + template static devcb_base &set_xf1_callback(device_t &device, _Object object) { return downcast(device).m_xf1_cb.set_callback(object); } + template static devcb_base &set_iack_callback(device_t &device, _Object object) { return downcast(device).m_iack_cb.set_callback(object); } + + // public interfaces + static float fp_to_float(UINT32 floatdata); + static double fp_to_double(UINT32 floatdata); + static UINT32 float_to_fp(float fval); + static UINT32 double_to_fp(double dval); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + virtual const rom_entry *device_rom_region() const; + + // device_execute_interface overrides + virtual UINT32 execute_min_cycles() const; + virtual UINT32 execute_max_cycles() const; + virtual UINT32 execute_input_lines() const; + virtual void execute_run(); + virtual void execute_set_input(int inputnum, int state); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const; + + // device_state_interface overrides + virtual void state_import(const device_state_entry &entry); + virtual void state_export(const device_state_entry &entry); + virtual void state_string_export(const device_state_entry &entry, std::string &str); + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const; + virtual UINT32 disasm_max_opcode_bytes() const; + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + + // memory helpers + DECLARE_DIRECT_UPDATE_MEMBER(direct_handler); + UINT32 ROPCODE(offs_t pc); + UINT32 RMEM(offs_t addr); + void WMEM(offs_t addr, UINT32 data); + + // misc helpers + void check_irqs(); + void execute_one(); + void update_special(int dreg); + bool condition(int which); + + // floating point helpers + void double_to_dsp_with_flags(double val, tmsreg &result); + void int2float(tmsreg &srcdst); + void float2int(tmsreg &srcdst, bool setflags); + void negf(tmsreg &dst, tmsreg &src); + void addf(tmsreg &dst, tmsreg &src1, tmsreg &src2); + void subf(tmsreg &dst, tmsreg &src1, tmsreg &src2); + void mpyf(tmsreg &dst, tmsreg &src1, tmsreg &src2); + void norm(tmsreg &dst, tmsreg &src); + + // memory addressing + UINT32 mod00_d(UINT32 op, UINT8 ar); + UINT32 mod01_d(UINT32 op, UINT8 ar); + UINT32 mod02_d(UINT32 op, UINT8 ar); + UINT32 mod03_d(UINT32 op, UINT8 ar); + UINT32 mod04_d(UINT32 op, UINT8 ar); + UINT32 mod05_d(UINT32 op, UINT8 ar); + UINT32 mod06_d(UINT32 op, UINT8 ar); + UINT32 mod07_d(UINT32 op, UINT8 ar); + + UINT32 mod00_1(UINT32 op, UINT8 ar); + UINT32 mod01_1(UINT32 op, UINT8 ar); + UINT32 mod02_1(UINT32 op, UINT8 ar); + UINT32 mod03_1(UINT32 op, UINT8 ar); + UINT32 mod04_1(UINT32 op, UINT8 ar); + UINT32 mod05_1(UINT32 op, UINT8 ar); + UINT32 mod06_1(UINT32 op, UINT8 ar); + UINT32 mod07_1(UINT32 op, UINT8 ar); + + UINT32 mod08(UINT32 op, UINT8 ar); + UINT32 mod09(UINT32 op, UINT8 ar); + UINT32 mod0a(UINT32 op, UINT8 ar); + UINT32 mod0b(UINT32 op, UINT8 ar); + UINT32 mod0c(UINT32 op, UINT8 ar); + UINT32 mod0d(UINT32 op, UINT8 ar); + UINT32 mod0e(UINT32 op, UINT8 ar); + UINT32 mod0f(UINT32 op, UINT8 ar); + + UINT32 mod10(UINT32 op, UINT8 ar); + UINT32 mod11(UINT32 op, UINT8 ar); + UINT32 mod12(UINT32 op, UINT8 ar); + UINT32 mod13(UINT32 op, UINT8 ar); + UINT32 mod14(UINT32 op, UINT8 ar); + UINT32 mod15(UINT32 op, UINT8 ar); + UINT32 mod16(UINT32 op, UINT8 ar); + UINT32 mod17(UINT32 op, UINT8 ar); + + UINT32 mod18(UINT32 op, UINT8 ar); + UINT32 mod19(UINT32 op, UINT8 ar); + UINT32 modillegal(UINT32 op, UINT8 ar); + + UINT32 mod00_1_def(UINT32 op, UINT8 ar, UINT32 *&defptrptr); + UINT32 mod01_1_def(UINT32 op, UINT8 ar, UINT32 *&defptrptr); + UINT32 mod02_1_def(UINT32 op, UINT8 ar, UINT32 *&defptrptr); + UINT32 mod03_1_def(UINT32 op, UINT8 ar, UINT32 *&defptrptr); + UINT32 mod04_1_def(UINT32 op, UINT8 ar, UINT32 *&defptrptr); + UINT32 mod05_1_def(UINT32 op, UINT8 ar, UINT32 *&defptrptr); + UINT32 mod06_1_def(UINT32 op, UINT8 ar, UINT32 *&defptrptr); + UINT32 mod07_1_def(UINT32 op, UINT8 ar, UINT32 *&defptrptr); + + UINT32 mod08_def(UINT32 op, UINT8 ar, UINT32 *&defptrptr); + UINT32 mod09_def(UINT32 op, UINT8 ar, UINT32 *&defptrptr); + UINT32 mod0a_def(UINT32 op, UINT8 ar, UINT32 *&defptrptr); + UINT32 mod0b_def(UINT32 op, UINT8 ar, UINT32 *&defptrptr); + UINT32 mod0c_def(UINT32 op, UINT8 ar, UINT32 *&defptrptr); + UINT32 mod0d_def(UINT32 op, UINT8 ar, UINT32 *&defptrptr); + UINT32 mod0e_def(UINT32 op, UINT8 ar, UINT32 *&defptrptr); + UINT32 mod0f_def(UINT32 op, UINT8 ar, UINT32 *&defptrptr); + + UINT32 mod10_def(UINT32 op, UINT8 ar, UINT32 *&defptrptr); + UINT32 mod11_def(UINT32 op, UINT8 ar, UINT32 *&defptrptr); + UINT32 mod12_def(UINT32 op, UINT8 ar, UINT32 *&defptrptr); + UINT32 mod13_def(UINT32 op, UINT8 ar, UINT32 *&defptrptr); + UINT32 mod14_def(UINT32 op, UINT8 ar, UINT32 *&defptrptr); + UINT32 mod15_def(UINT32 op, UINT8 ar, UINT32 *&defptrptr); + UINT32 mod16_def(UINT32 op, UINT8 ar, UINT32 *&defptrptr); + UINT32 mod17_def(UINT32 op, UINT8 ar, UINT32 *&defptrptr); + UINT32 mod18_def(UINT32 op, UINT8 ar, UINT32 *&defptrptr); + UINT32 mod19_def(UINT32 op, UINT8 ar, UINT32 *&defptrptr); + UINT32 modillegal_def(UINT32 op, UINT8 ar, UINT32 *&defptrptr); + + // instructions + void illegal(UINT32 op); + void unimplemented(UINT32 op); + + void absf_reg(UINT32 op); + void absf_dir(UINT32 op); + void absf_ind(UINT32 op); + void absf_imm(UINT32 op); + void absi_reg(UINT32 op); + void absi_dir(UINT32 op); + void absi_ind(UINT32 op); + void absi_imm(UINT32 op); + void addc_reg(UINT32 op); + void addc_dir(UINT32 op); + void addc_ind(UINT32 op); + void addc_imm(UINT32 op); + void addf_reg(UINT32 op); + void addf_dir(UINT32 op); + void addf_ind(UINT32 op); + void addf_imm(UINT32 op); + void addi_reg(UINT32 op); + void addi_dir(UINT32 op); + void addi_ind(UINT32 op); + void addi_imm(UINT32 op); + void and_reg(UINT32 op); + void and_dir(UINT32 op); + void and_ind(UINT32 op); + void and_imm(UINT32 op); + void andn_reg(UINT32 op); + void andn_dir(UINT32 op); + void andn_ind(UINT32 op); + void andn_imm(UINT32 op); + void ash_reg(UINT32 op); + void ash_dir(UINT32 op); + void ash_ind(UINT32 op); + void ash_imm(UINT32 op); + void cmpf_reg(UINT32 op); + void cmpf_dir(UINT32 op); + void cmpf_ind(UINT32 op); + void cmpf_imm(UINT32 op); + void cmpi_reg(UINT32 op); + void cmpi_dir(UINT32 op); + void cmpi_ind(UINT32 op); + void cmpi_imm(UINT32 op); + void fix_reg(UINT32 op); + void fix_dir(UINT32 op); + void fix_ind(UINT32 op); + void fix_imm(UINT32 op); + void float_reg(UINT32 op); + void float_dir(UINT32 op); + void float_ind(UINT32 op); + void float_imm(UINT32 op); + void idle(UINT32 op); + void lde_reg(UINT32 op); + void lde_dir(UINT32 op); + void lde_ind(UINT32 op); + void lde_imm(UINT32 op); + void ldf_reg(UINT32 op); + void ldf_dir(UINT32 op); + void ldf_ind(UINT32 op); + void ldf_imm(UINT32 op); + void ldfi_dir(UINT32 op); + void ldfi_ind(UINT32 op); + void ldi_reg(UINT32 op); + void ldi_dir(UINT32 op); + void ldi_ind(UINT32 op); + void ldi_imm(UINT32 op); + void ldii_dir(UINT32 op); + void ldii_ind(UINT32 op); + void ldm_reg(UINT32 op); + void ldm_dir(UINT32 op); + void ldm_ind(UINT32 op); + void ldm_imm(UINT32 op); + void lsh_reg(UINT32 op); + void lsh_dir(UINT32 op); + void lsh_ind(UINT32 op); + void lsh_imm(UINT32 op); + void mpyf_reg(UINT32 op); + void mpyf_dir(UINT32 op); + void mpyf_ind(UINT32 op); + void mpyf_imm(UINT32 op); + void mpyi_reg(UINT32 op); + void mpyi_dir(UINT32 op); + void mpyi_ind(UINT32 op); + void mpyi_imm(UINT32 op); + void negb_reg(UINT32 op); + void negb_dir(UINT32 op); + void negb_ind(UINT32 op); + void negb_imm(UINT32 op); + void negf_reg(UINT32 op); + void negf_dir(UINT32 op); + void negf_ind(UINT32 op); + void negf_imm(UINT32 op); + void negi_reg(UINT32 op); + void negi_dir(UINT32 op); + void negi_ind(UINT32 op); + void negi_imm(UINT32 op); + void nop_reg(UINT32 op); + void nop_ind(UINT32 op); + void norm_reg(UINT32 op); + void norm_dir(UINT32 op); + void norm_ind(UINT32 op); + void norm_imm(UINT32 op); + void not_reg(UINT32 op); + void not_dir(UINT32 op); + void not_ind(UINT32 op); + void not_imm(UINT32 op); + void pop(UINT32 op); + void popf(UINT32 op); + void push(UINT32 op); + void pushf(UINT32 op); + void or_reg(UINT32 op); + void or_dir(UINT32 op); + void or_ind(UINT32 op); + void or_imm(UINT32 op); + void maxspeed(UINT32 op); + void rnd_reg(UINT32 op); + void rnd_dir(UINT32 op); + void rnd_ind(UINT32 op); + void rnd_imm(UINT32 op); + void rol(UINT32 op); + void rolc(UINT32 op); + void ror(UINT32 op); + void rorc(UINT32 op); + void rtps_reg(UINT32 op); + void rtps_dir(UINT32 op); + void rtps_ind(UINT32 op); + void rtps_imm(UINT32 op); + void stf_dir(UINT32 op); + void stf_ind(UINT32 op); + void stfi_dir(UINT32 op); + void stfi_ind(UINT32 op); + void sti_dir(UINT32 op); + void sti_ind(UINT32 op); + void stii_dir(UINT32 op); + void stii_ind(UINT32 op); + void sigi(UINT32 op); + void subb_reg(UINT32 op); + void subb_dir(UINT32 op); + void subb_ind(UINT32 op); + void subb_imm(UINT32 op); + void subc_reg(UINT32 op); + void subc_dir(UINT32 op); + void subc_ind(UINT32 op); + void subc_imm(UINT32 op); + void subf_reg(UINT32 op); + void subf_dir(UINT32 op); + void subf_ind(UINT32 op); + void subf_imm(UINT32 op); + void subi_reg(UINT32 op); + void subi_dir(UINT32 op); + void subi_ind(UINT32 op); + void subi_imm(UINT32 op); + void subrb_reg(UINT32 op); + void subrb_dir(UINT32 op); + void subrb_ind(UINT32 op); + void subrb_imm(UINT32 op); + void subrf_reg(UINT32 op); + void subrf_dir(UINT32 op); + void subrf_ind(UINT32 op); + void subrf_imm(UINT32 op); + void subri_reg(UINT32 op); + void subri_dir(UINT32 op); + void subri_ind(UINT32 op); + void subri_imm(UINT32 op); + void tstb_reg(UINT32 op); + void tstb_dir(UINT32 op); + void tstb_ind(UINT32 op); + void tstb_imm(UINT32 op); + void xor_reg(UINT32 op); + void xor_dir(UINT32 op); + void xor_ind(UINT32 op); + void xor_imm(UINT32 op); + void iack_dir(UINT32 op); + void iack_ind(UINT32 op); + void addc3_regreg(UINT32 op); + void addc3_indreg(UINT32 op); + void addc3_regind(UINT32 op); + void addc3_indind(UINT32 op); + void addf3_regreg(UINT32 op); + void addf3_indreg(UINT32 op); + void addf3_regind(UINT32 op); + void addf3_indind(UINT32 op); + void addi3_regreg(UINT32 op); + void addi3_indreg(UINT32 op); + void addi3_regind(UINT32 op); + void addi3_indind(UINT32 op); + void and3_regreg(UINT32 op); + void and3_indreg(UINT32 op); + void and3_regind(UINT32 op); + void and3_indind(UINT32 op); + void andn3_regreg(UINT32 op); + void andn3_indreg(UINT32 op); + void andn3_regind(UINT32 op); + void andn3_indind(UINT32 op); + void ash3_regreg(UINT32 op); + void ash3_indreg(UINT32 op); + void ash3_regind(UINT32 op); + void ash3_indind(UINT32 op); + void cmpf3_regreg(UINT32 op); + void cmpf3_indreg(UINT32 op); + void cmpf3_regind(UINT32 op); + void cmpf3_indind(UINT32 op); + void cmpi3_regreg(UINT32 op); + void cmpi3_indreg(UINT32 op); + void cmpi3_regind(UINT32 op); + void cmpi3_indind(UINT32 op); + void lsh3_regreg(UINT32 op); + void lsh3_indreg(UINT32 op); + void lsh3_regind(UINT32 op); + void lsh3_indind(UINT32 op); + void mpyf3_regreg(UINT32 op); + void mpyf3_indreg(UINT32 op); + void mpyf3_regind(UINT32 op); + void mpyf3_indind(UINT32 op); + void mpyi3_regreg(UINT32 op); + void mpyi3_indreg(UINT32 op); + void mpyi3_regind(UINT32 op); + void mpyi3_indind(UINT32 op); + void or3_regreg(UINT32 op); + void or3_indreg(UINT32 op); + void or3_regind(UINT32 op); + void or3_indind(UINT32 op); + void subb3_regreg(UINT32 op); + void subb3_indreg(UINT32 op); + void subb3_regind(UINT32 op); + void subb3_indind(UINT32 op); + void subf3_regreg(UINT32 op); + void subf3_indreg(UINT32 op); + void subf3_regind(UINT32 op); + void subf3_indind(UINT32 op); + void subi3_regreg(UINT32 op); + void subi3_indreg(UINT32 op); + void subi3_regind(UINT32 op); + void subi3_indind(UINT32 op); + void tstb3_regreg(UINT32 op); + void tstb3_indreg(UINT32 op); + void tstb3_regind(UINT32 op); + void tstb3_indind(UINT32 op); + void xor3_regreg(UINT32 op); + void xor3_indreg(UINT32 op); + void xor3_regind(UINT32 op); + void xor3_indind(UINT32 op); + void ldfu_reg(UINT32 op); + void ldfu_dir(UINT32 op); + void ldfu_ind(UINT32 op); + void ldfu_imm(UINT32 op); + void ldflo_reg(UINT32 op); + void ldflo_dir(UINT32 op); + void ldflo_ind(UINT32 op); + void ldflo_imm(UINT32 op); + void ldfls_reg(UINT32 op); + void ldfls_dir(UINT32 op); + void ldfls_ind(UINT32 op); + void ldfls_imm(UINT32 op); + void ldfhi_reg(UINT32 op); + void ldfhi_dir(UINT32 op); + void ldfhi_ind(UINT32 op); + void ldfhi_imm(UINT32 op); + void ldfhs_reg(UINT32 op); + void ldfhs_dir(UINT32 op); + void ldfhs_ind(UINT32 op); + void ldfhs_imm(UINT32 op); + void ldfeq_reg(UINT32 op); + void ldfeq_dir(UINT32 op); + void ldfeq_ind(UINT32 op); + void ldfeq_imm(UINT32 op); + void ldfne_reg(UINT32 op); + void ldfne_dir(UINT32 op); + void ldfne_ind(UINT32 op); + void ldfne_imm(UINT32 op); + void ldflt_reg(UINT32 op); + void ldflt_dir(UINT32 op); + void ldflt_ind(UINT32 op); + void ldflt_imm(UINT32 op); + void ldfle_reg(UINT32 op); + void ldfle_dir(UINT32 op); + void ldfle_ind(UINT32 op); + void ldfle_imm(UINT32 op); + void ldfgt_reg(UINT32 op); + void ldfgt_dir(UINT32 op); + void ldfgt_ind(UINT32 op); + void ldfgt_imm(UINT32 op); + void ldfge_reg(UINT32 op); + void ldfge_dir(UINT32 op); + void ldfge_ind(UINT32 op); + void ldfge_imm(UINT32 op); + void ldfnv_reg(UINT32 op); + void ldfnv_dir(UINT32 op); + void ldfnv_ind(UINT32 op); + void ldfnv_imm(UINT32 op); + void ldfv_reg(UINT32 op); + void ldfv_dir(UINT32 op); + void ldfv_ind(UINT32 op); + void ldfv_imm(UINT32 op); + void ldfnuf_reg(UINT32 op); + void ldfnuf_dir(UINT32 op); + void ldfnuf_ind(UINT32 op); + void ldfnuf_imm(UINT32 op); + void ldfuf_reg(UINT32 op); + void ldfuf_dir(UINT32 op); + void ldfuf_ind(UINT32 op); + void ldfuf_imm(UINT32 op); + void ldfnlv_reg(UINT32 op); + void ldfnlv_dir(UINT32 op); + void ldfnlv_ind(UINT32 op); + void ldfnlv_imm(UINT32 op); + void ldflv_reg(UINT32 op); + void ldflv_dir(UINT32 op); + void ldflv_ind(UINT32 op); + void ldflv_imm(UINT32 op); + void ldfnluf_reg(UINT32 op); + void ldfnluf_dir(UINT32 op); + void ldfnluf_ind(UINT32 op); + void ldfnluf_imm(UINT32 op); + void ldfluf_reg(UINT32 op); + void ldfluf_dir(UINT32 op); + void ldfluf_ind(UINT32 op); + void ldfluf_imm(UINT32 op); + void ldfzuf_reg(UINT32 op); + void ldfzuf_dir(UINT32 op); + void ldfzuf_ind(UINT32 op); + void ldfzuf_imm(UINT32 op); + void ldiu_reg(UINT32 op); + void ldiu_dir(UINT32 op); + void ldiu_ind(UINT32 op); + void ldiu_imm(UINT32 op); + void ldilo_reg(UINT32 op); + void ldilo_dir(UINT32 op); + void ldilo_ind(UINT32 op); + void ldilo_imm(UINT32 op); + void ldils_reg(UINT32 op); + void ldils_dir(UINT32 op); + void ldils_ind(UINT32 op); + void ldils_imm(UINT32 op); + void ldihi_reg(UINT32 op); + void ldihi_dir(UINT32 op); + void ldihi_ind(UINT32 op); + void ldihi_imm(UINT32 op); + void ldihs_reg(UINT32 op); + void ldihs_dir(UINT32 op); + void ldihs_ind(UINT32 op); + void ldihs_imm(UINT32 op); + void ldieq_reg(UINT32 op); + void ldieq_dir(UINT32 op); + void ldieq_ind(UINT32 op); + void ldieq_imm(UINT32 op); + void ldine_reg(UINT32 op); + void ldine_dir(UINT32 op); + void ldine_ind(UINT32 op); + void ldine_imm(UINT32 op); + void ldilt_reg(UINT32 op); + void ldilt_dir(UINT32 op); + void ldilt_ind(UINT32 op); + void ldilt_imm(UINT32 op); + void ldile_reg(UINT32 op); + void ldile_dir(UINT32 op); + void ldile_ind(UINT32 op); + void ldile_imm(UINT32 op); + void ldigt_reg(UINT32 op); + void ldigt_dir(UINT32 op); + void ldigt_ind(UINT32 op); + void ldigt_imm(UINT32 op); + void ldige_reg(UINT32 op); + void ldige_dir(UINT32 op); + void ldige_ind(UINT32 op); + void ldige_imm(UINT32 op); + void ldinv_reg(UINT32 op); + void ldinv_dir(UINT32 op); + void ldinv_ind(UINT32 op); + void ldinv_imm(UINT32 op); + void ldiuf_reg(UINT32 op); + void ldiuf_dir(UINT32 op); + void ldiuf_ind(UINT32 op); + void ldiuf_imm(UINT32 op); + void ldinuf_reg(UINT32 op); + void ldinuf_dir(UINT32 op); + void ldinuf_ind(UINT32 op); + void ldinuf_imm(UINT32 op); + void ldiv_reg(UINT32 op); + void ldiv_dir(UINT32 op); + void ldiv_ind(UINT32 op); + void ldiv_imm(UINT32 op); + void ldinlv_reg(UINT32 op); + void ldinlv_dir(UINT32 op); + void ldinlv_ind(UINT32 op); + void ldinlv_imm(UINT32 op); + void ldilv_reg(UINT32 op); + void ldilv_dir(UINT32 op); + void ldilv_ind(UINT32 op); + void ldilv_imm(UINT32 op); + void ldinluf_reg(UINT32 op); + void ldinluf_dir(UINT32 op); + void ldinluf_ind(UINT32 op); + void ldinluf_imm(UINT32 op); + void ldiluf_reg(UINT32 op); + void ldiluf_dir(UINT32 op); + void ldiluf_ind(UINT32 op); + void ldiluf_imm(UINT32 op); + void ldizuf_reg(UINT32 op); + void ldizuf_dir(UINT32 op); + void ldizuf_ind(UINT32 op); + void ldizuf_imm(UINT32 op); + void execute_delayed(UINT32 newpc); + void br_imm(UINT32 op); + void brd_imm(UINT32 op); + void call_imm(UINT32 op); + void rptb_imm(UINT32 op); + void swi(UINT32 op); + void brc_reg(UINT32 op); + void brcd_reg(UINT32 op); + void brc_imm(UINT32 op); + void brcd_imm(UINT32 op); + void dbc_reg(UINT32 op); + void dbcd_reg(UINT32 op); + void dbc_imm(UINT32 op); + void dbcd_imm(UINT32 op); + void callc_reg(UINT32 op); + void callc_imm(UINT32 op); + void trap(int trapnum); + void trapc(UINT32 op); + void retic_reg(UINT32 op); + void retsc_reg(UINT32 op); + void mpyaddf_0(UINT32 op); + void mpyaddf_1(UINT32 op); + void mpyaddf_2(UINT32 op); + void mpyaddf_3(UINT32 op); + void mpysubf_0(UINT32 op); + void mpysubf_1(UINT32 op); + void mpysubf_2(UINT32 op); + void mpysubf_3(UINT32 op); + void mpyaddi_0(UINT32 op); + void mpyaddi_1(UINT32 op); + void mpyaddi_2(UINT32 op); + void mpyaddi_3(UINT32 op); + void mpysubi_0(UINT32 op); + void mpysubi_1(UINT32 op); + void mpysubi_2(UINT32 op); + void mpysubi_3(UINT32 op); + void stfstf(UINT32 op); + void stisti(UINT32 op); + void ldfldf(UINT32 op); + void ldildi(UINT32 op); + void absfstf(UINT32 op); + void absisti(UINT32 op); + void addf3stf(UINT32 op); + void addi3sti(UINT32 op); + void and3sti(UINT32 op); + void ash3sti(UINT32 op); + void fixsti(UINT32 op); + void floatstf(UINT32 op); + void ldfstf(UINT32 op); + void ldisti(UINT32 op); + void lsh3sti(UINT32 op); + void mpyf3stf(UINT32 op); + void mpyi3sti(UINT32 op); + void negfstf(UINT32 op); + void negisti(UINT32 op); + void notsti(UINT32 op); + void or3sti(UINT32 op); + void subf3stf(UINT32 op); + void subi3sti(UINT32 op); + void xor3sti(UINT32 op); + + // configuration + const address_space_config m_program_config; + UINT32 m_chip_type; + + union int_double + { + double d; + float f[2]; + UINT32 i[2]; + }; + + // core registers + UINT32 m_pc; + tmsreg m_r[36]; + UINT32 m_bkmask; + + // internal stuff + UINT16 m_irq_state; + bool m_delayed; + bool m_irq_pending; + bool m_is_idling; + int m_icount; + + UINT32 m_iotemp; + address_space * m_program; + direct_read_data * m_direct; + UINT32 * m_bootrom; + + bool m_mcbl_mode; + devcb_write8 m_xf0_cb; + devcb_write8 m_xf1_cb; + devcb_write8 m_iack_cb; + + // tables + static void (tms3203x_device::*const s_tms32031ops[])(UINT32 op); + static UINT32 (tms3203x_device::*const s_indirect_d[0x20])(UINT32, UINT8); + static UINT32 (tms3203x_device::*const s_indirect_1[0x20])(UINT32, UINT8); + static UINT32 (tms3203x_device::*const s_indirect_1_def[0x20])(UINT32, UINT8, UINT32 *&); + +#if (TMS_3203X_LOG_OPCODE_USAGE) + UINT32 m_hits[0x200*4]; +#endif +}; + + +// ======================> tms32031_device + +class tms32031_device : public tms3203x_device +{ +public: + // construction/destruction + tms32031_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +// ======================> tms32032_device + +class tms32032_device : public tms3203x_device +{ +public: + // construction/destruction + tms32032_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +// device type definition +extern const device_type TMS32031; +extern const device_type TMS32032; + + + +#endif /* __TMS32031_H__ */ diff --git a/src/devices/cpu/tms32051/32051ops.c b/src/devices/cpu/tms32051/32051ops.c new file mode 100644 index 00000000000..527c7366394 --- /dev/null +++ b/src/devices/cpu/tms32051/32051ops.c @@ -0,0 +1,1820 @@ +// license:BSD-3-Clause +// copyright-holders:Ville Linde +// stack is LIFO and is 8 levels deep, there is no stackpointer on the real chip +void tms32051_device::PUSH_STACK(UINT16 pc) +{ + m_pcstack_ptr = (m_pcstack_ptr - 1) & 7; + m_pcstack[m_pcstack_ptr] = pc; +} + +UINT16 tms32051_device::POP_STACK() +{ + UINT16 pc = m_pcstack[m_pcstack_ptr]; + m_pcstack_ptr = (m_pcstack_ptr + 1) & 7; + m_pcstack[(m_pcstack_ptr + 7) & 7] = m_pcstack[(m_pcstack_ptr + 6) & 7]; + return pc; +} + +INT32 tms32051_device::SUB(UINT32 a, UINT32 b) +{ + UINT32 res = a - b; + + // C is cleared if borrow was generated + m_st1.c = (b > a) ? 0 : 1; + + // check overflow + if ((a ^ b) & (a ^ res) & 0x80000000) + { + if (m_st0.ovm) // overflow saturation mode + { + res = ((INT32)(res) < 0) ? 0x7fffffff : 0x80000000; + } + + // set OV, this is a sticky flag + m_st0.ov = 1; + } + + return (INT32)(res); +} + +INT32 tms32051_device::ADD(UINT32 a, UINT32 b) +{ + UINT32 res = a + b; + + // C is set if carry was generated + m_st1.c = (a > res) ? 1 : 0; + + // check overflow + if ((a ^ res) & (b ^ res) & 0x80000000) + { + if (m_st0.ovm) // overflow saturation mode + { + res = ((INT32)(res) < 0) ? 0x7fffffff : 0x80000000; + } + + // set OV, this is a sticky flag + m_st0.ov = 1; + } + + return (INT32)(res); +} + + +void tms32051_device::UPDATE_AR(int ar, int step) +{ + int cenb1 = (m_cbcr >> 3) & 0x1; + int car1 = m_cbcr & 0x7; + int cenb2 = (m_cbcr >> 7) & 0x1; + int car2 = (m_cbcr >> 4) & 0x7; + + if (cenb1 && ar == car1) + { + // update circular buffer 1, note that it only checks == + if (m_ar[ar] == m_cber1) + { + m_ar[ar] = m_cbsr1; + } + else + { + m_ar[ar] += step; + } + } + else if (cenb2 && ar == car2) + { + // update circular buffer 2, note that it only checks == + if (m_ar[ar] == m_cber2) + { + m_ar[ar] = m_cbsr2; + } + else + { + m_ar[ar] += step; + } + } + else + { + m_ar[ar] += step; + } +} + +void tms32051_device::UPDATE_ARP(int nar) +{ + m_st1.arb = m_st0.arp; + m_st0.arp = nar; +} + +UINT16 tms32051_device::GET_ADDRESS() +{ + if (m_op & 0x80) // Indirect Addressing + { + UINT16 ea; + int arp = m_st0.arp; + int nar = m_op & 0x7; + + ea = m_ar[arp]; + + switch ((m_op >> 3) & 0xf) + { + case 0x0: // * (no operation) + { + break; + } + case 0x1: // *, ARn (NAR -> ARP) + { + UPDATE_ARP(nar); + break; + } + case 0x2: // *- ((CurrentAR)-1 -> CurrentAR) + { + UPDATE_AR(arp, -1); + break; + } + case 0x3: // *-, ARn ((CurrentAR)-1 -> CurrentAR, NAR -> ARP) + { + UPDATE_AR(arp, -1); + UPDATE_ARP(nar); + break; + } + case 0x4: // *+ ((CurrentAR)+1 -> CurrentAR) + { + UPDATE_AR(arp, 1); + break; + } + case 0x5: // *+, ARn ((CurrentAR)+1 -> CurrentAR, NAR -> ARP) + { + UPDATE_AR(arp, 1); + UPDATE_ARP(nar); + break; + } + case 0xa: // *0- ((CurrentAR) - INDX) + { + UPDATE_AR(arp, -m_indx); + break; + } + case 0xb: // *0-, ARn ((CurrentAR) - INDX -> CurrentAR, NAR -> ARP) + { + UPDATE_AR(arp, -m_indx); + UPDATE_ARP(nar); + break; + } + case 0xc: // *0+ ((CurrentAR) + INDX -> CurrentAR) + { + UPDATE_AR(arp, m_indx); + break; + } + case 0xd: // *0+, ARn ((CurrentAR) + INDX -> CurrentAR, NAR -> ARP) + { + UPDATE_AR(arp, m_indx); + UPDATE_ARP(nar); + break; + } + + default: fatalerror("32051: GET_ADDRESS: unimplemented indirect addressing mode %d at %04X (%04X)\n", (m_op >> 3) & 0xf, m_pc, m_op); + } + + return ea; + } + else // Direct Addressing + { + return m_st0.dp | (m_op & 0x7f); + } +} + +int tms32051_device::GET_ZLVC_CONDITION(int zlvc, int zlvc_mask) +{ + if (zlvc_mask & 0x2) // OV-bit + { + if ((zlvc & 0x2) && m_st0.ov) // OV + { + // clear OV + m_st0.ov = 0; + + return 1; + } + else if ((zlvc & 0x2) == 0 && m_st0.ov == 0) // NOV + return 1; + } + if (zlvc_mask & 0x1) // C-bit + { + if ((zlvc & 0x1) && m_st1.c) // C + return 1; + else if ((zlvc & 0x1) == 0 && m_st1.c == 0) // NC + return 1; + } + if (zlvc_mask & 0x8) // Z-bit + { + if ((zlvc & 0x8) && (INT32)(m_acc) == 0) // EQ + return 1; + else if ((zlvc & 0x8) == 0 && (INT32)(m_acc) != 0) // NEQ + return 1; + } + if (zlvc_mask & 0x4) // L-bit + { + if ((zlvc & 0x4) && (INT32)(m_acc) < 0) // LT + return 1; + else if ((zlvc & 0x4) == 0 && (INT32)(m_acc) > 0) // GT + return 1; + } + return 0; +} + +int tms32051_device::GET_TP_CONDITION(int tp) +{ + switch (tp) + { + case 0: // BIO pin low + { + // TODO + return 0; + } + case 1: // TC = 1 + { + return m_st1.tc; + } + case 2: // TC = 0 + { + return m_st1.tc ^ 1; + } + case 3: // always false + { + return 0; + } + } + return 0; +} + +INT32 tms32051_device::PREG_PSCALER(INT32 preg) +{ + switch (m_st1.pm & 3) + { + case 0: // No shift + { + return preg; + } + case 1: // Left-shifted 1 bit, LSB zero-filled + { + return preg << 1; + } + case 2: // Left-shifted 4 bits, 4 LSBs zero-filled + { + return preg << 4; + } + case 3: // Right-shifted 6 bits, sign-extended, 6 LSBs lost + { + return (INT32)(preg >> 6); + } + } + return 0; +} + + + +void tms32051_device::op_invalid() +{ + fatalerror("32051: invalid op at %08X\n", m_pc-1); +} + +/*****************************************************************************/ + +void tms32051_device::op_abs() +{ + fatalerror("32051: unimplemented op abs at %08X\n", m_pc-1); +} + +void tms32051_device::op_adcb() +{ + fatalerror("32051: unimplemented op adcb at %08X\n", m_pc-1); +} + +void tms32051_device::op_add_mem() +{ + INT32 d; + UINT16 ea = GET_ADDRESS(); + UINT16 data = DM_READ16(ea); + int shift = (m_op >> 8) & 0xf; + + if (m_st1.sxm) + { + d = (INT32)(INT16)(data) << shift; + } + else + { + d = (UINT32)(UINT16)(data) << shift; + } + + m_acc = ADD(m_acc, d); + + CYCLES(1); +} + +void tms32051_device::op_add_simm() +{ + UINT16 imm = m_op & 0xff; + + m_acc = ADD(m_acc, imm); + + CYCLES(1); +} + +void tms32051_device::op_add_limm() +{ + INT32 d; + UINT16 imm = ROPCODE(); + int shift = m_op & 0xf; + + if (m_st1.sxm) + { + d = (INT32)(INT16)(imm) << shift; + } + else + { + d = (UINT32)(UINT16)(imm) << shift; + } + + m_acc = ADD(m_acc, d); + + CYCLES(2); +} + +void tms32051_device::op_add_s16_mem() +{ + UINT16 ea = GET_ADDRESS(); + UINT32 data = DM_READ16(ea) << 16; + + m_acc = ADD(m_acc, data); + + CYCLES(1); +} + +void tms32051_device::op_addb() +{ + m_acc = ADD(m_acc, m_accb); + + CYCLES(1); +} + +void tms32051_device::op_addc() +{ + fatalerror("32051: unimplemented op addc at %08X\n", m_pc-1); +} + +void tms32051_device::op_adds() +{ + fatalerror("32051: unimplemented op adds at %08X\n", m_pc-1); +} + +void tms32051_device::op_addt() +{ + fatalerror("32051: unimplemented op addt at %08X\n", m_pc-1); +} + +void tms32051_device::op_and_mem() +{ + fatalerror("32051: unimplemented op and mem at %08X\n", m_pc-1); +} + +void tms32051_device::op_and_limm() +{ + UINT32 imm = ROPCODE(); + int shift = m_op & 0xf; + + m_acc &= imm << shift; + + CYCLES(2); +} + +void tms32051_device::op_and_s16_limm() +{ + fatalerror("32051: unimplemented op and s16 limm at %08X\n", m_pc-1); +} + +void tms32051_device::op_andb() +{ + fatalerror("32051: unimplemented op andb at %08X\n", m_pc-1); +} + +void tms32051_device::op_bsar() +{ + int shift = (m_op & 0xf) + 1; + + if (m_st1.sxm) + { + m_acc = (INT32)(m_acc) >> shift; + } + else + { + m_acc = (UINT32)(m_acc) >> shift; + } + + CYCLES(1); +} + +void tms32051_device::op_cmpl() +{ + m_acc = ~(UINT32)(m_acc); + + CYCLES(1); +} + +void tms32051_device::op_crgt() +{ + if (m_acc >= m_accb) + { + m_accb = m_acc; + m_st1.c = 1; + } + else + { + m_acc = m_accb; + m_st1.c = 0; + } + + CYCLES(1); +} + +void tms32051_device::op_crlt() +{ + if (m_acc >= m_accb) + { + m_acc = m_accb; + m_st1.c = 0; + } + else + { + m_accb = m_acc; + m_st1.c = 1; + } + + CYCLES(1); +} + +void tms32051_device::op_exar() +{ + INT32 tmp = m_acc; + m_acc = m_accb; + m_accb = tmp; + + CYCLES(1); +} + +void tms32051_device::op_lacb() +{ + m_acc = m_accb; + + CYCLES(1); +} + +void tms32051_device::op_lacc_mem() +{ + int shift = (m_op >> 8) & 0xf; + UINT16 ea = GET_ADDRESS(); + UINT16 data = DM_READ16(ea); + + if (m_st1.sxm) + { + m_acc = (INT32)(INT16)(data) << shift; + } + else + { + m_acc = (UINT32)(UINT16)(data) << shift; + } + + CYCLES(1); +} + +void tms32051_device::op_lacc_limm() +{ + UINT16 imm = ROPCODE(); + int shift = m_op & 0xf; + + if (m_st1.sxm) + { + m_acc = (INT32)(INT16)(imm) << shift; + } + else + { + m_acc = (UINT32)(UINT16)(imm) << shift; + } + + CYCLES(1); +} + +void tms32051_device::op_lacc_s16_mem() +{ + UINT16 ea = GET_ADDRESS(); + m_acc = DM_READ16(ea) << 16; + + CYCLES(1); +} + +void tms32051_device::op_lacl_simm() +{ + m_acc = m_op & 0xff; + + CYCLES(1); +} + +void tms32051_device::op_lacl_mem() +{ + UINT16 ea = GET_ADDRESS(); + m_acc = DM_READ16(ea) & 0xffff; + + CYCLES(1); +} + +void tms32051_device::op_lact() +{ + fatalerror("32051: unimplemented op lact at %08X\n", m_pc-1); +} + +void tms32051_device::op_lamm() +{ + UINT16 ea = GET_ADDRESS() & 0x7f; + m_acc = DM_READ16(ea) & 0xffff; + + CYCLES(1); +} + +void tms32051_device::op_neg() +{ + if ((UINT32)(m_acc) == 0x80000000) + { + m_st0.ov = 1; + m_st1.c = 0; + m_acc = (m_st0.ovm) ? 0x7fffffff : 0x80000000; + } + else + { + m_acc = 0 - (UINT32)(m_acc); + m_st1.c = (m_acc == 0) ? 1 : 0; + } + + CYCLES(1); +} + +void tms32051_device::op_norm() +{ + fatalerror("32051: unimplemented op norm at %08X\n", m_pc-1); +} + +void tms32051_device::op_or_mem() +{ + UINT16 ea = GET_ADDRESS(); + UINT16 data = DM_READ16(ea); + + m_acc |= (UINT32)(data); + + CYCLES(1); +} + +void tms32051_device::op_or_limm() +{ + UINT32 imm = ROPCODE(); + int shift = m_op & 0xf; + + m_acc |= imm << shift; + + CYCLES(1); +} + +void tms32051_device::op_or_s16_limm() +{ + fatalerror("32051: unimplemented op or s16 limm at %08X\n", m_pc-1); +} + +void tms32051_device::op_orb() +{ + m_acc |= m_accb; + + CYCLES(1); +} + +void tms32051_device::op_rol() +{ + fatalerror("32051: unimplemented op rol at %08X\n", m_pc-1); +} + +void tms32051_device::op_rolb() +{ + UINT32 acc = m_acc; + UINT32 accb = m_accb; + UINT32 c = m_st1.c & 1; + + m_acc = (acc << 1) | ((accb >> 31) & 1); + m_accb = (accb << 1) | c; + m_st1.c = (acc >> 31) & 1; + + CYCLES(1); +} + +void tms32051_device::op_ror() +{ + fatalerror("32051: unimplemented op ror at %08X\n", m_pc-1); +} + +void tms32051_device::op_rorb() +{ + fatalerror("32051: unimplemented op rorb at %08X\n", m_pc-1); +} + +void tms32051_device::op_sacb() +{ + m_accb = m_acc; + + CYCLES(1); +} + +void tms32051_device::op_sach() +{ + UINT16 ea = GET_ADDRESS(); + int shift = (m_op >> 8) & 0x7; + + DM_WRITE16(ea, (UINT16)((m_acc << shift) >> 16)); + CYCLES(1); +} + +void tms32051_device::op_sacl() +{ + UINT16 ea = GET_ADDRESS(); + int shift = (m_op >> 8) & 0x7; + + DM_WRITE16(ea, (UINT16)(m_acc << shift)); + CYCLES(1); +} + +void tms32051_device::op_samm() +{ + UINT16 ea = GET_ADDRESS(); + ea &= 0x7f; + + DM_WRITE16(ea, (UINT16)(m_acc)); + CYCLES(1); +} + +void tms32051_device::op_sath() +{ + fatalerror("32051: unimplemented op sath at %08X\n", m_pc-1); +} + +void tms32051_device::op_satl() +{ + fatalerror("32051: unimplemented op satl at %08X\n", m_pc-1); +} + +void tms32051_device::op_sbb() +{ + m_acc = SUB(m_acc, m_accb); + + CYCLES(1); +} + +void tms32051_device::op_sbbb() +{ + fatalerror("32051: unimplemented op sbbb at %08X\n", m_pc-1); +} + +void tms32051_device::op_sfl() +{ + m_st1.c = (m_acc >> 31) & 1; + m_acc = m_acc << 1; + + CYCLES(1); +} + +void tms32051_device::op_sflb() +{ + UINT32 acc = m_acc; + UINT32 accb = m_accb; + + m_acc = (acc << 1) | ((accb >> 31) & 1); + m_accb = (accb << 1); + m_st1.c = (acc >> 31) & 1; + + CYCLES(1); +} + +void tms32051_device::op_sfr() +{ + m_st1.c = m_acc & 1; + + if (m_st1.sxm) + { + m_acc = (INT32)(m_acc) >> 1; + } + else + { + m_acc = (UINT32)(m_acc) >> 1; + } + + CYCLES(1); +} + +void tms32051_device::op_sfrb() +{ + fatalerror("32051: unimplemented op sfrb at %08X\n", m_pc-1); +} + +void tms32051_device::op_sub_mem() +{ + INT32 d; + UINT16 ea = GET_ADDRESS(); + UINT16 data = DM_READ16(ea); + int shift = (m_op >> 8) & 0xf; + + if (m_st1.sxm) + { + d = (INT32)(INT16)(data) << shift; + } + else + { + d = (UINT32)(UINT16)(data) << shift; + } + + m_acc = SUB(m_acc, d); + + CYCLES(1); +} + +void tms32051_device::op_sub_s16_mem() +{ + fatalerror("32051: unimplemented op sub s16 mem at %08X\n", m_pc-1); +} + +void tms32051_device::op_sub_simm() +{ + UINT16 imm = m_op & 0xff; + + m_acc = SUB(m_acc, imm); + + CYCLES(1); +} + +void tms32051_device::op_sub_limm() +{ + INT32 d; + UINT16 imm = ROPCODE(); + int shift = m_op & 0xf; + + if (m_st1.sxm) + { + d = (INT32)(INT16)(imm) << shift; + } + else + { + d = (UINT32)(UINT16)(imm) << shift; + } + + m_acc = SUB(m_acc, d); + + CYCLES(2); +} + +void tms32051_device::op_subb() +{ + fatalerror("32051: unimplemented op subb at %08X\n", m_pc-1); +} + +void tms32051_device::op_subc() +{ + fatalerror("32051: unimplemented op subc at %08X\n", m_pc-1); +} + +void tms32051_device::op_subs() +{ + fatalerror("32051: unimplemented op subs at %08X\n", m_pc-1); +} + +void tms32051_device::op_subt() +{ + fatalerror("32051: unimplemented op subt at %08X\n", m_pc-1); +} + +void tms32051_device::op_xor_mem() +{ + UINT16 ea = GET_ADDRESS(); + UINT16 data = DM_READ16(ea); + + m_acc ^= (UINT32)(data); + + CYCLES(1); +} + +void tms32051_device::op_xor_limm() +{ + UINT32 imm = ROPCODE(); + int shift = m_op & 0xf; + + m_acc ^= imm << shift; + + CYCLES(1); +} + +void tms32051_device::op_xor_s16_limm() +{ + fatalerror("32051: unimplemented op xor s16 limm at %08X\n", m_pc-1); +} + +void tms32051_device::op_xorb() +{ + fatalerror("32051: unimplemented op xorb at %08X\n", m_pc-1); +} + +void tms32051_device::op_zalr() +{ + fatalerror("32051: unimplemented op zalr at %08X\n", m_pc-1); +} + +void tms32051_device::op_zap() +{ + m_acc = 0; + m_preg = 0; + + CYCLES(1); +} + +/*****************************************************************************/ + +void tms32051_device::op_adrk() +{ + UINT16 imm = m_op & 0xff; + UPDATE_AR(m_st0.arp, imm); + + CYCLES(1); +} + +void tms32051_device::op_cmpr() +{ + m_st1.tc = 0; + + switch (m_op & 0x3) + { + case 0: // (CurrentAR) == ARCR + { + if (m_ar[m_st0.arp] == m_arcr) + { + m_st1.tc = 1; + } + break; + } + case 1: // (CurrentAR) < ARCR + { + if (m_ar[m_st0.arp] < m_arcr) + { + m_st1.tc = 1; + } + break; + } + case 2: // (CurrentAR) > ARCR + { + if (m_ar[m_st0.arp] > m_arcr) + { + m_st1.tc = 1; + } + break; + } + case 3: // (CurrentAR) != ARCR + { + if (m_ar[m_st0.arp] != m_arcr) + { + m_st1.tc = 1; + } + break; + } + } + + CYCLES(1); +} + +void tms32051_device::op_lar_mem() +{ + int arx = (m_op >> 8) & 0x7; + UINT16 ea = GET_ADDRESS(); + UINT16 data = DM_READ16(ea); + + m_ar[arx] = data; + + CYCLES(2); +} + +void tms32051_device::op_lar_simm() +{ + int arx = (m_op >> 8) & 0x7; + m_ar[arx] = m_op & 0xff; + + CYCLES(2); +} + +void tms32051_device::op_lar_limm() +{ + int arx = m_op & 0x7; + UINT16 imm = ROPCODE(); + m_ar[arx] = imm; + + CYCLES(2); +} + +void tms32051_device::op_ldp_mem() +{ + fatalerror("32051: unimplemented op ldp mem at %08X\n", m_pc-1); +} + +void tms32051_device::op_ldp_imm() +{ + m_st0.dp = (m_op & 0x1ff) << 7; + CYCLES(2); +} + +void tms32051_device::op_mar() +{ + // direct addressing is NOP + if (m_op & 0x80) + { + GET_ADDRESS(); + } + CYCLES(1); +} + +void tms32051_device::op_sar() +{ + int arx = (m_op >> 8) & 0x7; + UINT16 ar = m_ar[arx]; + UINT16 ea = GET_ADDRESS(); + DM_WRITE16(ea, ar); + + CYCLES(1); +} + +void tms32051_device::op_sbrk() +{ + UINT16 imm = m_op & 0xff; + UPDATE_AR(m_st0.arp, -imm); + + CYCLES(1); +} + +/*****************************************************************************/ + +void tms32051_device::op_b() +{ + UINT16 pma = ROPCODE(); + GET_ADDRESS(); // update AR/ARP + + CHANGE_PC(pma); + CYCLES(4); +} + +void tms32051_device::op_bacc() +{ + CHANGE_PC((UINT16)(m_acc)); + + CYCLES(4); +} + +void tms32051_device::op_baccd() +{ + UINT16 pc = (UINT16)(m_acc); + + delay_slot(m_pc); + CHANGE_PC(pc); + + CYCLES(2); +} + +void tms32051_device::op_banz() +{ + UINT16 pma = ROPCODE(); + + if (m_ar[m_st0.arp] != 0) + { + CHANGE_PC(pma); + CYCLES(4); + } + else + { + CYCLES(2); + } + + GET_ADDRESS(); // modify AR/ARP +} + +void tms32051_device::op_banzd() +{ + fatalerror("32051: unimplemented op banzd at %08X\n", m_pc-1); +} + +void tms32051_device::op_bcnd() +{ + UINT16 pma = ROPCODE(); + + if (GET_ZLVC_CONDITION((m_op >> 4) & 0xf, m_op & 0xf) || GET_TP_CONDITION((m_op >> 8) & 0x3)) + { + CHANGE_PC(pma); + CYCLES(4); + } + else + { + CYCLES(2); + } +} + +void tms32051_device::op_bcndd() +{ + UINT16 pma = ROPCODE(); + + if (GET_ZLVC_CONDITION((m_op >> 4) & 0xf, m_op & 0xf) || GET_TP_CONDITION((m_op >> 8) & 0x3)) + { + delay_slot(m_pc); + CHANGE_PC(pma); + CYCLES(4); + } + else + { + CYCLES(2); + } +} + +void tms32051_device::op_bd() +{ + UINT16 pma = ROPCODE(); + GET_ADDRESS(); // update AR/ARP + + delay_slot(m_pc); + CHANGE_PC(pma); + CYCLES(2); +} + +void tms32051_device::op_cala() +{ + PUSH_STACK(m_pc); + + CHANGE_PC(m_acc); + + CYCLES(4); +} + +void tms32051_device::op_calad() +{ + UINT16 pma = m_acc; + PUSH_STACK(m_pc+2); + + delay_slot(m_pc); + CHANGE_PC(pma); + + CYCLES(4); +} + +void tms32051_device::op_call() +{ + UINT16 pma = ROPCODE(); + GET_ADDRESS(); // update AR/ARP + PUSH_STACK(m_pc); + + CHANGE_PC(pma); + + CYCLES(4); +} + +void tms32051_device::op_calld() +{ + UINT16 pma = ROPCODE(); + GET_ADDRESS(); // update AR/ARP + PUSH_STACK(m_pc+2); + + delay_slot(m_pc); + CHANGE_PC(pma); + + CYCLES(4); +} + +void tms32051_device::op_cc() +{ + fatalerror("32051: unimplemented op cc at %08X\n", m_pc-1); +} + +void tms32051_device::op_ccd() +{ + UINT16 pma = ROPCODE(); + + if (GET_ZLVC_CONDITION((m_op >> 4) & 0xf, m_op & 0xf) || GET_TP_CONDITION((m_op >> 8) & 0x3)) + { + PUSH_STACK(m_pc+2); + + delay_slot(m_pc); + CHANGE_PC(pma); + } + + CYCLES(2); +} + +void tms32051_device::op_intr() +{ + fatalerror("32051: unimplemented op intr at %08X\n", m_pc-1); +} + +void tms32051_device::op_nmi() +{ + fatalerror("32051: unimplemented op nmi at %08X\n", m_pc-1); +} + +void tms32051_device::op_retc() +{ + if ((m_op & 0x3ff) == 0x300 || GET_ZLVC_CONDITION((m_op >> 4) & 0xf, m_op & 0xf) || GET_TP_CONDITION((m_op >> 8) & 0x3)) + { + UINT16 pc = POP_STACK(); + CHANGE_PC(pc); + CYCLES(4); + } + else + { + CYCLES(2); + } +} + +void tms32051_device::op_retcd() +{ + if ((m_op & 0x3ff) == 0x300 || GET_ZLVC_CONDITION((m_op >> 4) & 0xf, m_op & 0xf) || GET_TP_CONDITION((m_op >> 8) & 0x3)) + { + UINT16 pc = POP_STACK(); + delay_slot(m_pc); + CHANGE_PC(pc); + CYCLES(4); + } + else + { + CYCLES(2); + } +} + +void tms32051_device::op_rete() +{ + UINT16 pc = POP_STACK(); + CHANGE_PC(pc); + + m_st0.intm = 0; + + restore_interrupt_context(); + + CYCLES(4); +} + +void tms32051_device::op_reti() +{ + fatalerror("32051: unimplemented op reti at %08X\n", m_pc-1); +} + +void tms32051_device::op_trap() +{ + fatalerror("32051: unimplemented op trap at %08X\n", m_pc-1); +} + +void tms32051_device::op_xc() +{ + if (GET_ZLVC_CONDITION((m_op >> 4) & 0xf, m_op & 0xf) || GET_TP_CONDITION((m_op >> 8) & 0x3)) + { + CYCLES(1); + } + else + { + int n = ((m_op >> 12) & 0x1) + 1; + CHANGE_PC(m_pc + n); + CYCLES(1 + n); + } +} + +/*****************************************************************************/ + +void tms32051_device::op_bldd_slimm() +{ + UINT16 pfc = ROPCODE(); + + while (m_rptc > -1) + { + UINT16 ea = GET_ADDRESS(); + UINT16 data = DM_READ16(pfc); + DM_WRITE16(ea, data); + pfc++; + CYCLES(2); + + m_rptc--; + }; +} + +void tms32051_device::op_bldd_dlimm() +{ + UINT16 pfc = ROPCODE(); + + while (m_rptc > -1) + { + UINT16 ea = GET_ADDRESS(); + UINT16 data = DM_READ16(ea); + DM_WRITE16(pfc, data); + pfc++; + CYCLES(2); + + m_rptc--; + }; +} + +void tms32051_device::op_bldd_sbmar() +{ + UINT16 pfc = m_bmar; + + while (m_rptc > -1) + { + UINT16 ea = GET_ADDRESS(); + UINT16 data = DM_READ16(pfc); + DM_WRITE16(ea, data); + pfc++; + CYCLES(2); + + m_rptc--; + }; +} + +void tms32051_device::op_bldd_dbmar() +{ + UINT16 pfc = m_bmar; + + while (m_rptc > -1) + { + UINT16 ea = GET_ADDRESS(); + UINT16 data = DM_READ16(ea); + DM_WRITE16(pfc, data); + pfc++; + CYCLES(2); + + m_rptc--; + }; +} + +void tms32051_device::op_bldp() +{ + UINT16 pfc = m_bmar; + + while (m_rptc > -1) + { + UINT16 ea = GET_ADDRESS(); + UINT16 data = DM_READ16(ea); + PM_WRITE16(pfc, data); + pfc++; + CYCLES(1); + + m_rptc--; + }; +} + +void tms32051_device::op_blpd_bmar() +{ + fatalerror("32051: unimplemented op bpld bmar at %08X\n", m_pc-1); +} + +void tms32051_device::op_blpd_imm() +{ + UINT16 pfc = ROPCODE(); + + while (m_rptc > -1) + { + UINT16 ea = GET_ADDRESS(); + UINT16 data = PM_READ16(pfc); + DM_WRITE16(ea, data); + pfc++; + CYCLES(2); + + m_rptc--; + }; +} + +/*****************************************************************************/ + +void tms32051_device::op_dmov() +{ + fatalerror("32051: unimplemented op dmov at %08X\n", m_pc-1); +} + +void tms32051_device::op_in() +{ + fatalerror("32051: unimplemented op in at %08X\n", m_pc-1); +} + +void tms32051_device::op_lmmr() +{ + UINT16 pfc = ROPCODE(); + + while (m_rptc > -1) + { + UINT16 ea = GET_ADDRESS(); + UINT16 data = DM_READ16(pfc); + DM_WRITE16(ea & 0x7f, data); + pfc++; + CYCLES(2); + + m_rptc--; + }; +} + +void tms32051_device::op_out() +{ + fatalerror("32051: unimplemented op out at %08X\n", m_pc-1); +} + +void tms32051_device::op_smmr() +{ + UINT16 pfc = ROPCODE(); + + while (m_rptc > -1) + { + UINT16 ea = GET_ADDRESS(); + UINT16 data = DM_READ16(ea & 0x7f); + DM_WRITE16(pfc, data); + pfc++; + CYCLES(2); + + m_rptc--; + }; +} + +void tms32051_device::op_tblr() +{ + UINT16 pfc = (UINT16)(m_acc); + + while (m_rptc > -1) + { + UINT16 ea = GET_ADDRESS(); + UINT16 data = PM_READ16(pfc); + DM_WRITE16(ea, data); + pfc++; + CYCLES(2); + + m_rptc--; + }; +} + +void tms32051_device::op_tblw() +{ + UINT16 pfc = (UINT16)(m_acc); + + while (m_rptc > -1) + { + UINT16 ea = GET_ADDRESS(); + UINT16 data = DM_READ16(ea); + PM_WRITE16(pfc, data); + pfc++; + CYCLES(2); + + m_rptc--; + }; +} + +/*****************************************************************************/ + +void tms32051_device::op_apl_dbmr() +{ + UINT16 ea = GET_ADDRESS(); + UINT16 data = DM_READ16(ea); + data &= m_dbmr; + DM_WRITE16(ea, data); + CYCLES(1); +} + +void tms32051_device::op_apl_imm() +{ + UINT16 ea = GET_ADDRESS(); + UINT16 imm = ROPCODE(); + UINT16 data = DM_READ16(ea); + data &= imm; + DM_WRITE16(ea, data); + CYCLES(1); +} + +void tms32051_device::op_cpl_dbmr() +{ + fatalerror("32051: unimplemented op cpl dbmr at %08X\n", m_pc-1); +} + +void tms32051_device::op_cpl_imm() +{ + UINT16 imm = ROPCODE(); + UINT16 ea = GET_ADDRESS(); + UINT16 data = DM_READ16(ea); + + m_st1.tc = (data == imm) ? 1 : 0; + + CYCLES(1); +} + +void tms32051_device::op_opl_dbmr() +{ + UINT16 ea = GET_ADDRESS(); + UINT16 data = DM_READ16(ea); + data |= m_dbmr; + DM_WRITE16(ea, data); + CYCLES(1); +} + +void tms32051_device::op_opl_imm() +{ + UINT16 ea = GET_ADDRESS(); + UINT16 imm = ROPCODE(); + UINT16 data = DM_READ16(ea); + data |= imm; + DM_WRITE16(ea, data); + CYCLES(1); +} + +void tms32051_device::op_splk() +{ + UINT16 ea = GET_ADDRESS(); + UINT16 imm = ROPCODE(); + + DM_WRITE16(ea, imm); + + CYCLES(2); +} + +void tms32051_device::op_xpl_dbmr() +{ + fatalerror("32051: unimplemented op xpl dbmr at %08X\n", m_pc-1); +} + +void tms32051_device::op_xpl_imm() +{ + fatalerror("32051: unimplemented op xpl imm at %08X\n", m_pc-1); +} + +void tms32051_device::op_apac() +{ + INT32 spreg = PREG_PSCALER(m_preg); + m_acc = ADD(m_acc, spreg); + + CYCLES(1); +} + +void tms32051_device::op_lph() +{ + fatalerror("32051: unimplemented op lph at %08X\n", m_pc-1); +} + +void tms32051_device::op_lt() +{ + UINT16 ea = GET_ADDRESS(); + UINT16 data = DM_READ16(ea); + + m_treg0 = data; + if (m_pmst.trm == 0) + { + m_treg1 = data; + m_treg2 = data; + } + + CYCLES(1); +} + +void tms32051_device::op_lta() +{ + INT32 spreg; + UINT16 ea = GET_ADDRESS(); + UINT16 data = DM_READ16(ea); + + m_treg0 = data; + spreg = PREG_PSCALER(m_preg); + m_acc = ADD(m_acc, spreg); + if (m_pmst.trm == 0) + { + m_treg1 = data; + m_treg2 = data; + } + + CYCLES(1); +} + +void tms32051_device::op_ltd() +{ + fatalerror("32051: unimplemented op ltd at %08X\n", m_pc-1); +} + +void tms32051_device::op_ltp() +{ + fatalerror("32051: unimplemented op ltp at %08X\n", m_pc-1); +} + +void tms32051_device::op_lts() +{ + fatalerror("32051: unimplemented op lts at %08X\n", m_pc-1); +} + +void tms32051_device::op_mac() +{ + fatalerror("32051: unimplemented op mac at %08X\n", m_pc-1); +} + +void tms32051_device::op_macd() +{ + fatalerror("32051: unimplemented op macd at %08X\n", m_pc-1); +} + +void tms32051_device::op_madd() +{ + fatalerror("32051: unimplemented op madd at %08X\n", m_pc-1); +} + +void tms32051_device::op_mads() +{ + fatalerror("32051: unimplemented op mads at %08X\n", m_pc-1); +} + +void tms32051_device::op_mpy_mem() +{ + UINT16 ea = GET_ADDRESS(); + INT16 data = DM_READ16(ea); + + m_preg = (INT32)(data) * (INT32)(INT16)(m_treg0); + + CYCLES(1); +} + +void tms32051_device::op_mpy_simm() +{ + fatalerror("32051: unimplemented op mpy simm at %08X\n", m_pc-1); +} + +void tms32051_device::op_mpy_limm() +{ + fatalerror("32051: unimplemented op mpy limm at %08X\n", m_pc-1); +} + +void tms32051_device::op_mpya() +{ + fatalerror("32051: unimplemented op mpya at %08X\n", m_pc-1); +} + +void tms32051_device::op_mpys() +{ + fatalerror("32051: unimplemented op mpys at %08X\n", m_pc-1); +} + +void tms32051_device::op_mpyu() +{ + fatalerror("32051: unimplemented op mpyu at %08X\n", m_pc-1); +} + +void tms32051_device::op_pac() +{ + fatalerror("32051: unimplemented op pac at %08X\n", m_pc-1); +} + +void tms32051_device::op_spac() +{ + fatalerror("32051: unimplemented op spac at %08X\n", m_pc-1); +} + +void tms32051_device::op_sph() +{ + UINT16 ea = GET_ADDRESS(); + UINT16 spreg = (UINT16)(PREG_PSCALER(m_preg) >> 16); + DM_WRITE16(ea, spreg); + + CYCLES(1); +} + +void tms32051_device::op_spl() +{ + fatalerror("32051: unimplemented op spl at %08X\n", m_pc-1); +} + +void tms32051_device::op_spm() +{ + m_st1.pm = m_op & 0x3; + + CYCLES(1); +} + +void tms32051_device::op_sqra() +{ + fatalerror("32051: unimplemented op sqra at %08X\n", m_pc-1); +} + +void tms32051_device::op_sqrs() +{ + fatalerror("32051: unimplemented op sqrs at %08X\n", m_pc-1); +} + +void tms32051_device::op_zpr() +{ + fatalerror("32051: unimplemented op zpr at %08X\n", m_pc-1); +} + +void tms32051_device::op_bit() +{ + UINT16 ea = GET_ADDRESS(); + UINT16 data = DM_READ16(ea); + + m_st1.tc = (data >> (~m_op >> 8 & 0xf)) & 1; + + CYCLES(1); +} + +void tms32051_device::op_bitt() +{ + UINT16 ea = GET_ADDRESS(); + UINT16 data = DM_READ16(ea); + + m_st1.tc = (data >> (~m_treg2 & 0xf)) & 1; + + CYCLES(1); +} + +void tms32051_device::op_clrc_ov() +{ + m_st0.ovm = 0; + + CYCLES(1); +} + +void tms32051_device::op_clrc_ext() +{ + m_st1.sxm = 0; + + CYCLES(1); +} + +void tms32051_device::op_clrc_hold() +{ + fatalerror("32051: unimplemented op clrc hold at %08X\n", m_pc-1); +} + +void tms32051_device::op_clrc_tc() +{ + fatalerror("32051: unimplemented op clrc tc at %08X\n", m_pc-1); +} + +void tms32051_device::op_clrc_carry() +{ + fatalerror("32051: unimplemented op clrc carry at %08X\n", m_pc-1); +} + +void tms32051_device::op_clrc_cnf() +{ + m_st1.cnf = 0; + + CYCLES(1); +} + +void tms32051_device::op_clrc_intm() +{ + m_st0.intm = 0; + + check_interrupts(); + + CYCLES(1); +} + +void tms32051_device::op_clrc_xf() +{ + fatalerror("32051: unimplemented op clrc xf at %08X\n", m_pc-1); +} + +void tms32051_device::op_idle() +{ + fatalerror("32051: unimplemented op idle at %08X\n", m_pc-1); +} + +void tms32051_device::op_idle2() +{ + fatalerror("32051: unimplemented op idle2 at %08X\n", m_pc-1); +} + +void tms32051_device::op_lst_st0() +{ + fatalerror("32051: unimplemented op lst st0 at %08X\n", m_pc-1); +} + +void tms32051_device::op_lst_st1() +{ + fatalerror("32051: unimplemented op lst st1 at %08X\n", m_pc-1); +} + +void tms32051_device::op_pop() +{ + m_acc = POP_STACK(); + + CYCLES(1); +} + +void tms32051_device::op_popd() +{ + fatalerror("32051: unimplemented op popd at %08X\n", m_pc-1); +} + +void tms32051_device::op_pshd() +{ + fatalerror("32051: unimplemented op pshd at %08X\n", m_pc-1); +} + +void tms32051_device::op_push() +{ + fatalerror("32051: unimplemented op push at %08X\n", m_pc-1); +} + +void tms32051_device::op_rpt_mem() +{ + UINT16 ea = GET_ADDRESS(); + UINT16 data = DM_READ16(ea); + m_rptc = data; + m_rpt_start = m_pc; + m_rpt_end = m_pc; + + CYCLES(1); +} + +void tms32051_device::op_rpt_limm() +{ + m_rptc = (UINT16)ROPCODE(); + m_rpt_start = m_pc; + m_rpt_end = m_pc; + + CYCLES(2); +} + +void tms32051_device::op_rpt_simm() +{ + m_rptc = (m_op & 0xff); + m_rpt_start = m_pc; + m_rpt_end = m_pc; + + CYCLES(1); +} + +void tms32051_device::op_rptb() +{ + UINT16 pma = ROPCODE(); + m_pmst.braf = 1; + m_pasr = m_pc; + m_paer = pma + 1; + + CYCLES(2); +} + +void tms32051_device::op_rptz() +{ + fatalerror("32051: unimplemented op rptz at %08X\n", m_pc-1); +} + +void tms32051_device::op_setc_ov() +{ + m_st0.ovm = 1; + + CYCLES(1); +} + +void tms32051_device::op_setc_ext() +{ + m_st1.sxm = 1; + + CYCLES(1); +} + +void tms32051_device::op_setc_hold() +{ + fatalerror("32051: unimplemented op setc hold at %08X\n", m_pc-1); +} + +void tms32051_device::op_setc_tc() +{ + fatalerror("32051: unimplemented op setc tc at %08X\n", m_pc-1); +} + +void tms32051_device::op_setc_carry() +{ + fatalerror("32051: unimplemented op setc carry at %08X\n", m_pc-1); +} + +void tms32051_device::op_setc_xf() +{ + fatalerror("32051: unimplemented op setc xf at %08X\n", m_pc-1); +} + +void tms32051_device::op_setc_cnf() +{ + m_st1.cnf = 1; + + CYCLES(1); +} + +void tms32051_device::op_setc_intm() +{ + m_st0.intm = 1; + + check_interrupts(); + + CYCLES(1); +} + +void tms32051_device::op_sst_st0() +{ + fatalerror("32051: unimplemented op sst st0 at %08X\n", m_pc-1); +} + +void tms32051_device::op_sst_st1() +{ + fatalerror("32051: unimplemented op sst st1 at %08X\n", m_pc-1); +} diff --git a/src/devices/cpu/tms32051/32051ops.h b/src/devices/cpu/tms32051/32051ops.h new file mode 100644 index 00000000000..f0a1d7d3d25 --- /dev/null +++ b/src/devices/cpu/tms32051/32051ops.h @@ -0,0 +1,253 @@ +// license:BSD-3-Clause +// copyright-holders:Ville Linde +const tms32051_device::opcode_func tms32051_device::s_opcode_table[256] = +{ + /* 0x00 - 0x0f */ + &tms32051_device::op_lar_mem, &tms32051_device::op_lar_mem, &tms32051_device::op_lar_mem, &tms32051_device::op_lar_mem, + &tms32051_device::op_lar_mem, &tms32051_device::op_lar_mem, &tms32051_device::op_lar_mem, &tms32051_device::op_lar_mem, + &tms32051_device::op_lamm, &tms32051_device::op_smmr, &tms32051_device::op_subc, &tms32051_device::op_rpt_mem, + &tms32051_device::op_out, &tms32051_device::op_ldp_mem, &tms32051_device::op_lst_st0, &tms32051_device::op_lst_st1, + /* 0x10 - 0x1f */ + &tms32051_device::op_lacc_mem, &tms32051_device::op_lacc_mem, &tms32051_device::op_lacc_mem, &tms32051_device::op_lacc_mem, + &tms32051_device::op_lacc_mem, &tms32051_device::op_lacc_mem, &tms32051_device::op_lacc_mem, &tms32051_device::op_lacc_mem, + &tms32051_device::op_lacc_mem, &tms32051_device::op_lacc_mem, &tms32051_device::op_lacc_mem, &tms32051_device::op_lacc_mem, + &tms32051_device::op_lacc_mem, &tms32051_device::op_lacc_mem, &tms32051_device::op_lacc_mem, &tms32051_device::op_lacc_mem, + /* 0x20 - 0x2f */ + &tms32051_device::op_add_mem, &tms32051_device::op_add_mem, &tms32051_device::op_add_mem, &tms32051_device::op_add_mem, + &tms32051_device::op_add_mem, &tms32051_device::op_add_mem, &tms32051_device::op_add_mem, &tms32051_device::op_add_mem, + &tms32051_device::op_add_mem, &tms32051_device::op_add_mem, &tms32051_device::op_add_mem, &tms32051_device::op_add_mem, + &tms32051_device::op_add_mem, &tms32051_device::op_add_mem, &tms32051_device::op_add_mem, &tms32051_device::op_add_mem, + /* 0x30 - 0x3f */ + &tms32051_device::op_sub_mem, &tms32051_device::op_sub_mem, &tms32051_device::op_sub_mem, &tms32051_device::op_sub_mem, + &tms32051_device::op_sub_mem, &tms32051_device::op_sub_mem, &tms32051_device::op_sub_mem, &tms32051_device::op_sub_mem, + &tms32051_device::op_sub_mem, &tms32051_device::op_sub_mem, &tms32051_device::op_sub_mem, &tms32051_device::op_sub_mem, + &tms32051_device::op_sub_mem, &tms32051_device::op_sub_mem, &tms32051_device::op_sub_mem, &tms32051_device::op_sub_mem, + /* 0x40 - 0x4f */ + &tms32051_device::op_bit, &tms32051_device::op_bit, &tms32051_device::op_bit, &tms32051_device::op_bit, + &tms32051_device::op_bit, &tms32051_device::op_bit, &tms32051_device::op_bit, &tms32051_device::op_bit, + &tms32051_device::op_bit, &tms32051_device::op_bit, &tms32051_device::op_bit, &tms32051_device::op_bit, + &tms32051_device::op_bit, &tms32051_device::op_bit, &tms32051_device::op_bit, &tms32051_device::op_bit, + /* 0x50 - 0x5f */ + &tms32051_device::op_mpya, &tms32051_device::op_mpys, &tms32051_device::op_sqra, &tms32051_device::op_sqrs, + &tms32051_device::op_mpy_mem, &tms32051_device::op_mpyu, &tms32051_device::op_invalid, &tms32051_device::op_bldp, + &tms32051_device::op_xpl_dbmr, &tms32051_device::op_opl_dbmr, &tms32051_device::op_apl_dbmr, &tms32051_device::op_cpl_dbmr, + &tms32051_device::op_xpl_imm, &tms32051_device::op_opl_imm, &tms32051_device::op_apl_imm, &tms32051_device::op_cpl_imm, + /* 0x60 - 0x6f */ + &tms32051_device::op_addc, &tms32051_device::op_add_s16_mem, &tms32051_device::op_adds, &tms32051_device::op_addt, + &tms32051_device::op_subb, &tms32051_device::op_sub_s16_mem, &tms32051_device::op_subs, &tms32051_device::op_subt, + &tms32051_device::op_zalr, &tms32051_device::op_lacl_mem, &tms32051_device::op_lacc_s16_mem,&tms32051_device::op_lact, + &tms32051_device::op_xor_mem, &tms32051_device::op_or_mem, &tms32051_device::op_and_mem, &tms32051_device::op_bitt, + /* 0x70 - 0x7f */ + &tms32051_device::op_lta, &tms32051_device::op_ltp, &tms32051_device::op_ltd, &tms32051_device::op_lt, + &tms32051_device::op_lts, &tms32051_device::op_lph, &tms32051_device::op_pshd, &tms32051_device::op_dmov, + &tms32051_device::op_adrk, &tms32051_device::op_b, &tms32051_device::op_call, &tms32051_device::op_banz, + &tms32051_device::op_sbrk, &tms32051_device::op_bd, &tms32051_device::op_calld, &tms32051_device::op_banzd, + /* 0x80 - 0x8f */ + &tms32051_device::op_sar, &tms32051_device::op_sar, &tms32051_device::op_sar, &tms32051_device::op_sar, + &tms32051_device::op_sar, &tms32051_device::op_sar, &tms32051_device::op_sar, &tms32051_device::op_sar, + &tms32051_device::op_samm, &tms32051_device::op_lmmr, &tms32051_device::op_popd, &tms32051_device::op_mar, + &tms32051_device::op_spl, &tms32051_device::op_sph, &tms32051_device::op_sst_st0, &tms32051_device::op_sst_st1, + /* 0x90 - 0x9f */ + &tms32051_device::op_sacl, &tms32051_device::op_sacl, &tms32051_device::op_sacl, &tms32051_device::op_sacl, + &tms32051_device::op_sacl, &tms32051_device::op_sacl, &tms32051_device::op_sacl, &tms32051_device::op_sacl, + &tms32051_device::op_sach, &tms32051_device::op_sach, &tms32051_device::op_sach, &tms32051_device::op_sach, + &tms32051_device::op_sach, &tms32051_device::op_sach, &tms32051_device::op_sach, &tms32051_device::op_sach, + /* 0xa0 - 0xaf */ + &tms32051_device::op_norm, &tms32051_device::op_invalid, &tms32051_device::op_mac, &tms32051_device::op_macd, + &tms32051_device::op_blpd_bmar, &tms32051_device::op_blpd_imm, &tms32051_device::op_tblr, &tms32051_device::op_tblw, + &tms32051_device::op_bldd_slimm, &tms32051_device::op_bldd_dlimm, &tms32051_device::op_mads, &tms32051_device::op_madd, + &tms32051_device::op_bldd_sbmar, &tms32051_device::op_bldd_dbmar, &tms32051_device::op_splk, &tms32051_device::op_in, + /* 0xb0 - 0xbf */ + &tms32051_device::op_lar_simm, &tms32051_device::op_lar_simm, &tms32051_device::op_lar_simm, &tms32051_device::op_lar_simm, + &tms32051_device::op_lar_simm, &tms32051_device::op_lar_simm, &tms32051_device::op_lar_simm, &tms32051_device::op_lar_simm, + &tms32051_device::op_add_simm, &tms32051_device::op_lacl_simm, &tms32051_device::op_sub_simm, &tms32051_device::op_rpt_simm, + &tms32051_device::op_ldp_imm, &tms32051_device::op_ldp_imm, &tms32051_device::op_group_be, &tms32051_device::op_group_bf, + /* 0xc0 - 0xcf */ + &tms32051_device::op_mpy_simm, &tms32051_device::op_mpy_simm, &tms32051_device::op_mpy_simm, &tms32051_device::op_mpy_simm, + &tms32051_device::op_mpy_simm, &tms32051_device::op_mpy_simm, &tms32051_device::op_mpy_simm, &tms32051_device::op_mpy_simm, + &tms32051_device::op_mpy_simm, &tms32051_device::op_mpy_simm, &tms32051_device::op_mpy_simm, &tms32051_device::op_mpy_simm, + &tms32051_device::op_mpy_simm, &tms32051_device::op_mpy_simm, &tms32051_device::op_mpy_simm, &tms32051_device::op_mpy_simm, + /* 0xd0 - 0xdf */ + &tms32051_device::op_mpy_simm, &tms32051_device::op_mpy_simm, &tms32051_device::op_mpy_simm, &tms32051_device::op_mpy_simm, + &tms32051_device::op_mpy_simm, &tms32051_device::op_mpy_simm, &tms32051_device::op_mpy_simm, &tms32051_device::op_mpy_simm, + &tms32051_device::op_mpy_simm, &tms32051_device::op_mpy_simm, &tms32051_device::op_mpy_simm, &tms32051_device::op_mpy_simm, + &tms32051_device::op_mpy_simm, &tms32051_device::op_mpy_simm, &tms32051_device::op_mpy_simm, &tms32051_device::op_mpy_simm, + /* 0xe0 - 0xef */ + &tms32051_device::op_bcnd, &tms32051_device::op_bcnd, &tms32051_device::op_bcnd, &tms32051_device::op_bcnd, + &tms32051_device::op_xc, &tms32051_device::op_xc, &tms32051_device::op_xc, &tms32051_device::op_xc, + &tms32051_device::op_cc, &tms32051_device::op_cc, &tms32051_device::op_cc, &tms32051_device::op_cc, + &tms32051_device::op_retc, &tms32051_device::op_retc, &tms32051_device::op_retc, &tms32051_device::op_retc, + /* 0xf0 - 0xff */ + &tms32051_device::op_bcndd, &tms32051_device::op_bcndd, &tms32051_device::op_bcndd, &tms32051_device::op_bcndd, + &tms32051_device::op_xc, &tms32051_device::op_xc, &tms32051_device::op_xc, &tms32051_device::op_xc, + &tms32051_device::op_ccd, &tms32051_device::op_ccd, &tms32051_device::op_ccd, &tms32051_device::op_ccd, + &tms32051_device::op_retcd, &tms32051_device::op_retcd, &tms32051_device::op_retcd, &tms32051_device::op_retcd +}; + +const tms32051_device::opcode_func tms32051_device::s_opcode_table_be[256] = +{ + /* 0x00 - 0x0f */ + &tms32051_device::op_abs, &tms32051_device::op_cmpl, &tms32051_device::op_neg, &tms32051_device::op_pac, + &tms32051_device::op_apac, &tms32051_device::op_spac, &tms32051_device::op_invalid, &tms32051_device::op_invalid, + &tms32051_device::op_invalid, &tms32051_device::op_sfl, &tms32051_device::op_sfr, &tms32051_device::op_invalid, + &tms32051_device::op_rol, &tms32051_device::op_ror, &tms32051_device::op_invalid, &tms32051_device::op_invalid, + /* 0x10 - 0x1f */ + &tms32051_device::op_addb, &tms32051_device::op_adcb, &tms32051_device::op_andb, &tms32051_device::op_orb, + &tms32051_device::op_rolb, &tms32051_device::op_rorb, &tms32051_device::op_sflb, &tms32051_device::op_sfrb, + &tms32051_device::op_sbb, &tms32051_device::op_sbbb, &tms32051_device::op_xorb, &tms32051_device::op_crgt, + &tms32051_device::op_crlt, &tms32051_device::op_exar, &tms32051_device::op_sacb, &tms32051_device::op_lacb, + /* 0x20 - 0x2f */ + &tms32051_device::op_bacc, &tms32051_device::op_baccd, &tms32051_device::op_idle, &tms32051_device::op_idle2, + &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, + &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, + &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, + /* 0x30 - 0x3f */ + &tms32051_device::op_cala, &tms32051_device::op_invalid, &tms32051_device::op_pop, &tms32051_device::op_invalid, + &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, + &tms32051_device::op_reti, &tms32051_device::op_invalid, &tms32051_device::op_rete, &tms32051_device::op_invalid, + &tms32051_device::op_push, &tms32051_device::op_calad, &tms32051_device::op_invalid, &tms32051_device::op_invalid, + /* 0x40 - 0x4f */ + &tms32051_device::op_clrc_intm, &tms32051_device::op_setc_intm, &tms32051_device::op_clrc_ov, &tms32051_device::op_setc_ov, + &tms32051_device::op_clrc_cnf, &tms32051_device::op_setc_cnf, &tms32051_device::op_clrc_ext, &tms32051_device::op_setc_ext, + &tms32051_device::op_clrc_hold, &tms32051_device::op_setc_hold, &tms32051_device::op_clrc_tc, &tms32051_device::op_setc_tc, + &tms32051_device::op_clrc_xf, &tms32051_device::op_setc_xf, &tms32051_device::op_clrc_carry, &tms32051_device::op_setc_carry, + /* 0x50 - 0x5f */ + &tms32051_device::op_invalid, &tms32051_device::op_trap, &tms32051_device::op_nmi, &tms32051_device::op_invalid, + &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, + &tms32051_device::op_zpr, &tms32051_device::op_zap, &tms32051_device::op_sath, &tms32051_device::op_satl, + &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, + /* 0x60 - 0x6f */ + &tms32051_device::op_intr, &tms32051_device::op_intr, &tms32051_device::op_intr, &tms32051_device::op_intr, + &tms32051_device::op_intr, &tms32051_device::op_intr, &tms32051_device::op_intr, &tms32051_device::op_intr, + &tms32051_device::op_intr, &tms32051_device::op_intr, &tms32051_device::op_intr, &tms32051_device::op_intr, + &tms32051_device::op_intr, &tms32051_device::op_intr, &tms32051_device::op_intr, &tms32051_device::op_intr, + /* 0x70 - 0x7f */ + &tms32051_device::op_intr, &tms32051_device::op_intr, &tms32051_device::op_intr, &tms32051_device::op_intr, + &tms32051_device::op_intr, &tms32051_device::op_intr, &tms32051_device::op_intr, &tms32051_device::op_intr, + &tms32051_device::op_intr, &tms32051_device::op_intr, &tms32051_device::op_intr, &tms32051_device::op_intr, + &tms32051_device::op_intr, &tms32051_device::op_intr, &tms32051_device::op_intr, &tms32051_device::op_intr, + /* 0x80 - 0x8f */ + &tms32051_device::op_mpy_limm, &tms32051_device::op_and_s16_limm,&tms32051_device::op_or_s16_limm, &tms32051_device::op_xor_s16_limm, + &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, + &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, + &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, + /* 0x90 - 0x9f */ + &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, + &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, + &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, + &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, + /* 0xa0 - 0xaf */ + &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, + &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, + &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, + &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, + /* 0xb0 - 0xbf */ + &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, + &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, + &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, + &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, + /* 0xc0 - 0xcf */ + &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, + &tms32051_device::op_rpt_limm, &tms32051_device::op_rptz, &tms32051_device::op_rptb, &tms32051_device::op_invalid, + &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, + &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, + /* 0xd0 - 0xdf */ + &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, + &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, + &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, + &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, + /* 0xe0 - 0xef */ + &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, + &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, + &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, + &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, + /* 0xf0 - 0xff */ + &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, + &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, + &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, + &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, +}; + +const tms32051_device::opcode_func tms32051_device::s_opcode_table_bf[256] = +{ + /* 0x00 - 0x0f */ + &tms32051_device::op_spm, &tms32051_device::op_spm, &tms32051_device::op_spm, &tms32051_device::op_spm, + &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, + &tms32051_device::op_lar_limm, &tms32051_device::op_lar_limm, &tms32051_device::op_lar_limm, &tms32051_device::op_lar_limm, + &tms32051_device::op_lar_limm, &tms32051_device::op_lar_limm, &tms32051_device::op_lar_limm, &tms32051_device::op_lar_limm, + /* 0x10 - 0x1f */ + &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, + &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, + &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, + &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, + /* 0x20 - 0x2f */ + &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, + &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, + &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, + &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, + /* 0x30 - 0x3f */ + &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, + &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, + &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, + &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, + /* 0x40 - 0x4f */ + &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, + &tms32051_device::op_cmpr, &tms32051_device::op_cmpr, &tms32051_device::op_cmpr, &tms32051_device::op_cmpr, + &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, + &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, + /* 0x50 - 0x5f */ + &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, + &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, + &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, + &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, + /* 0x60 - 0x6f */ + &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, + &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, + &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, + &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, + /* 0x70 - 0x7f */ + &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, + &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, + &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, + &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, + /* 0x80 - 0x8f */ + &tms32051_device::op_lacc_limm, &tms32051_device::op_lacc_limm, &tms32051_device::op_lacc_limm, &tms32051_device::op_lacc_limm, + &tms32051_device::op_lacc_limm, &tms32051_device::op_lacc_limm, &tms32051_device::op_lacc_limm, &tms32051_device::op_lacc_limm, + &tms32051_device::op_lacc_limm, &tms32051_device::op_lacc_limm, &tms32051_device::op_lacc_limm, &tms32051_device::op_lacc_limm, + &tms32051_device::op_lacc_limm, &tms32051_device::op_lacc_limm, &tms32051_device::op_lacc_limm, &tms32051_device::op_lacc_limm, + /* 0x90 - 0x9f */ + &tms32051_device::op_add_limm, &tms32051_device::op_add_limm, &tms32051_device::op_add_limm, &tms32051_device::op_add_limm, + &tms32051_device::op_add_limm, &tms32051_device::op_add_limm, &tms32051_device::op_add_limm, &tms32051_device::op_add_limm, + &tms32051_device::op_add_limm, &tms32051_device::op_add_limm, &tms32051_device::op_add_limm, &tms32051_device::op_add_limm, + &tms32051_device::op_add_limm, &tms32051_device::op_add_limm, &tms32051_device::op_add_limm, &tms32051_device::op_add_limm, + /* 0xa0 - 0xaf */ + &tms32051_device::op_sub_limm, &tms32051_device::op_sub_limm, &tms32051_device::op_sub_limm, &tms32051_device::op_sub_limm, + &tms32051_device::op_sub_limm, &tms32051_device::op_sub_limm, &tms32051_device::op_sub_limm, &tms32051_device::op_sub_limm, + &tms32051_device::op_sub_limm, &tms32051_device::op_sub_limm, &tms32051_device::op_sub_limm, &tms32051_device::op_sub_limm, + &tms32051_device::op_sub_limm, &tms32051_device::op_sub_limm, &tms32051_device::op_sub_limm, &tms32051_device::op_sub_limm, + /* 0xb0 - 0xbf */ + &tms32051_device::op_and_limm, &tms32051_device::op_and_limm, &tms32051_device::op_and_limm, &tms32051_device::op_and_limm, + &tms32051_device::op_and_limm, &tms32051_device::op_and_limm, &tms32051_device::op_and_limm, &tms32051_device::op_and_limm, + &tms32051_device::op_and_limm, &tms32051_device::op_and_limm, &tms32051_device::op_and_limm, &tms32051_device::op_and_limm, + &tms32051_device::op_and_limm, &tms32051_device::op_and_limm, &tms32051_device::op_and_limm, &tms32051_device::op_and_limm, + /* 0xc0 - 0xcf */ + &tms32051_device::op_or_limm, &tms32051_device::op_or_limm, &tms32051_device::op_or_limm, &tms32051_device::op_or_limm, + &tms32051_device::op_or_limm, &tms32051_device::op_or_limm, &tms32051_device::op_or_limm, &tms32051_device::op_or_limm, + &tms32051_device::op_or_limm, &tms32051_device::op_or_limm, &tms32051_device::op_or_limm, &tms32051_device::op_or_limm, + &tms32051_device::op_or_limm, &tms32051_device::op_or_limm, &tms32051_device::op_or_limm, &tms32051_device::op_or_limm, + /* 0xd0 - 0xdf */ + &tms32051_device::op_xor_limm, &tms32051_device::op_xor_limm, &tms32051_device::op_xor_limm, &tms32051_device::op_xor_limm, + &tms32051_device::op_xor_limm, &tms32051_device::op_xor_limm, &tms32051_device::op_xor_limm, &tms32051_device::op_xor_limm, + &tms32051_device::op_xor_limm, &tms32051_device::op_xor_limm, &tms32051_device::op_xor_limm, &tms32051_device::op_xor_limm, + &tms32051_device::op_xor_limm, &tms32051_device::op_xor_limm, &tms32051_device::op_xor_limm, &tms32051_device::op_xor_limm, + /* 0xe0 - 0xef */ + &tms32051_device::op_bsar, &tms32051_device::op_bsar, &tms32051_device::op_bsar, &tms32051_device::op_bsar, + &tms32051_device::op_bsar, &tms32051_device::op_bsar, &tms32051_device::op_bsar, &tms32051_device::op_bsar, + &tms32051_device::op_bsar, &tms32051_device::op_bsar, &tms32051_device::op_bsar, &tms32051_device::op_bsar, + &tms32051_device::op_bsar, &tms32051_device::op_bsar, &tms32051_device::op_bsar, &tms32051_device::op_bsar, + /* 0xf0 - 0xff */ + &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, + &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, + &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, + &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, &tms32051_device::op_invalid, +}; diff --git a/src/devices/cpu/tms32051/dis32051.c b/src/devices/cpu/tms32051/dis32051.c new file mode 100644 index 00000000000..6f3c4ea2156 --- /dev/null +++ b/src/devices/cpu/tms32051/dis32051.c @@ -0,0 +1,644 @@ +// license:BSD-3-Clause +// copyright-holders:Ville Linde +#include "emu.h" + + + +static const char *const zl_condition_codes[] = +{ + // bit 3, 2 (ZL), bit 1, 0 (MASK) + "", // Z=0, L=0, ZM=0, ZL=0 + "gt", // Z=0, L=0, ZM=0, ZL=1 + "neq", // Z=0, L=0, ZM=1, ZL=0 + "gt", // Z=0, L=0, ZM=1, ZL=1 + "", // Z=0, L=1, ZM=0, ZL=0 + "lt", // Z=0, L=1, ZM=0, ZL=1 + "neq", // Z=0, L=1, ZM=1, ZL=0 + "lt", // Z=0, L=1, ZM=1, ZL=1 + "", // Z=1, L=0, ZM=0, ZL=0 + "gt", // Z=1, L=0, ZM=0, ZL=1 + "eq", // Z=1, L=0, ZM=1, ZL=0 + "geq", // Z=1, L=0, ZM=1, ZL=1 + "", // Z=1, L=1, ZM=0, ZL=0 + "lt", // Z=1, L=1, ZM=0, ZL=1 + "eq", // Z=1, L=1, ZM=1, ZL=0 + "leq", // Z=1, L=1, ZM=1, ZL=1 +}; + +static const char *const cv_condition_codes[16] = +{ + "", // C=0, V=0, CM=0, VM=0 + "nov", // C=0, V=0, CM=0, VM=1 + "nc", // C=0, V=0, CM=1, VM=0 + "nc nov", // C=0, V=0, CM=1, VM=1 + "", // C=0, V=1, CM=0, VM=0 + "ov", // C=0, V=1, CM=0, VM=1 + "nc", // C=0, V=1, CM=1, VM=0 + "nc ov", // C=0, V=1, CM=1, VM=1 + "", // C=1, V=0, CM=0, VM=0 + "nov", // C=1, V=0, CM=0, VM=1 + "c", // C=1, V=0, CM=1, VM=0 + "c nov", // C=1, V=0, CM=1, VM=1 + "", // C=1, V=1, CM=0, VM=0 + "ov", // C=1, V=1, CM=0, VM=1 + "c", // C=1, V=1, CM=1, VM=0 + "c ov", // C=1, V=1, CM=1, VM=1 +}; + +static const char *const tp_condition_codes[4] = +{ + "bio", + "tc", + "ntc", + "" +}; + + +static offs_t npc; +static const UINT8 *rombase; +static offs_t pcbase; + +static char *output; + +static void ATTR_PRINTF(1,2) print(const char *fmt, ...) +{ + va_list vl; + + va_start(vl, fmt); + output += vsprintf(output, fmt, vl); + va_end(vl); +} + +static UINT16 FETCH(void) +{ + UINT16 result = rombase[(npc - pcbase) * 2 + 0] | (rombase[(npc - pcbase) * 2 + 1] << 8); + npc++; + return result; +} + +static char *GET_ADDRESS(int addr_mode, int address) +{ + static char buffer[100]; + + if (addr_mode) // Indirect addressing + { + int nar = address & 0x7; + + + switch ((address >> 3) & 0xf) + { + case 0x0: sprintf(buffer, "*"); break; + case 0x1: sprintf(buffer, "*, ar%d", nar); break; + case 0x2: sprintf(buffer, "*-"); break; + case 0x3: sprintf(buffer, "*-, ar%d", nar); break; + case 0x4: sprintf(buffer, "*+"); break; + case 0x5: sprintf(buffer, "*+, ar%d", nar); break; + case 0x8: sprintf(buffer, "*br0-"); break; + case 0x9: sprintf(buffer, "*br0-, ar%d", nar); break; + case 0xa: sprintf(buffer, "*0-"); break; + case 0xb: sprintf(buffer, "*0-, ar%d", nar); break; + case 0xc: sprintf(buffer, "*0+"); break; + case 0xd: sprintf(buffer, "*0+, ar%d", nar); break; + case 0xe: sprintf(buffer, "*br0+"); break; + case 0xf: sprintf(buffer, "*br0+, ar%d", nar); break; + + default: sprintf(buffer, "??? (indirect)"); break; + } + } + else // Direct addressing + { + sprintf(buffer, "#%02X", address); + } + return buffer; +} + +static char *GET_SHIFT(int shift) +{ + static char buffer[100]; + + if (shift > 0) + { + sprintf(buffer, ", %d", shift); + } + else + { + memset(buffer, 0, sizeof(buffer)); + } + + return buffer; +} + +static void dasm_group_be(UINT16 opcode) +{ + int subop = opcode & 0xff; + + switch (subop) + { + case 0x00: print("abs"); break; + case 0x01: print("cmpl"); break; + case 0x02: print("neg"); break; + case 0x03: print("pac"); break; + case 0x04: print("apac"); break; + case 0x05: print("spac"); break; + case 0x09: print("sfl"); break; + case 0x0a: print("sfr"); break; + case 0x0c: print("rol"); break; + case 0x0d: print("ror"); break; + case 0x10: print("addb"); break; + case 0x11: print("adcb"); break; + case 0x12: print("andb"); break; + case 0x13: print("orb"); break; + case 0x14: print("rolb"); break; + case 0x15: print("rorb"); break; + case 0x16: print("sflb"); break; + case 0x17: print("sfrb"); break; + case 0x18: print("sbb"); break; + case 0x19: print("sbbb"); break; + case 0x1a: print("xorb"); break; + case 0x1b: print("crgt"); break; + case 0x1c: print("crlt"); break; + case 0x1d: print("exar"); break; + case 0x1e: print("sacb"); break; + case 0x1f: print("lacb"); break; + case 0x20: print("bacc"); break; + case 0x21: print("baccd"); break; + case 0x22: print("idle"); break; + case 0x23: print("idle2"); break; + case 0x30: print("cala"); break; + case 0x32: print("pop"); break; + case 0x38: print("reti"); break; + case 0x3a: print("rete"); break; + case 0x3c: print("push"); break; + case 0x3d: print("calad"); break; + case 0x40: print("clrc intm"); break; + case 0x41: print("setc intm"); break; + case 0x42: print("clrc ovm"); break; + case 0x43: print("setc ovm"); break; + case 0x44: print("clrc cnf"); break; + case 0x45: print("setc cnf"); break; + case 0x46: print("clrc sxm"); break; + case 0x47: print("setc sxm"); break; + case 0x48: print("clrc hold"); break; + case 0x49: print("setc hold"); break; + case 0x4a: print("clrc tc"); break; + case 0x4b: print("setc tc"); break; + case 0x4c: print("clrc xf"); break; + case 0x4d: print("setc xf"); break; + case 0x4e: print("clrc carry"); break; + case 0x4f: print("setc carry"); break; + case 0x51: print("trap"); break; + case 0x52: print("nmi"); break; + case 0x58: print("zpr"); break; + case 0x59: print("zap"); break; + case 0x5a: print("sath"); break; + case 0x5b: print("satl"); break; + case 0x60: case 0x61: case 0x62: case 0x63: + case 0x64: case 0x65: case 0x66: case 0x67: + case 0x68: case 0x69: case 0x6a: case 0x6b: + case 0x6c: case 0x6d: case 0x6e: case 0x6f: + case 0x70: case 0x71: case 0x72: case 0x73: + case 0x74: case 0x75: case 0x76: case 0x77: + case 0x78: case 0x79: case 0x7a: case 0x7b: + case 0x7c: case 0x7d: case 0x7e: case 0x7f: + print("intr %d", opcode & 0x1f); break; + + case 0x80: print("mpy #%04X", FETCH()); break; + case 0x81: print("and #%04X", FETCH() << 16); break; + case 0x82: print("or #%04X", FETCH() << 16); break; + case 0x83: print("xor #%04X", FETCH() << 16); break; + case 0xc4: print("rpt #%04X", FETCH()); break; + case 0xc5: print("rpt #%04X", FETCH()); break; + case 0xc6: print("rpt #%04X", FETCH()); break; + + default: print("??? (group be)"); break; + } +} + +static void dasm_group_bf(UINT16 opcode) +{ + int subop = (opcode >> 4) & 0xf; + int shift = opcode & 0xf; + + switch (subop) + { + case 0x0: + { + if (opcode & 0x8) + { + print("lar ar%d, #%04X", opcode & 0x7, FETCH()); + } + else + { + print("spm #%02X", opcode & 0x3); + } + break; + } + + case 0x4: + { + switch (opcode & 0x3) + { + case 0: print("cmpr ar = arcr"); break; + case 1: print("cmpr ar < arcr"); break; + case 2: print("cmpr ar > arcr"); break; + case 3: print("cmpr ar != arcr"); break; + } + break; + } + + case 0x8: print("lacc #%04X", FETCH() << shift); break; + case 0x9: print("add #%04X", FETCH() << shift); break; + case 0xa: print("sub #%04X", FETCH() << shift); break; + case 0xb: print("and #%04X", FETCH() << shift); break; + case 0xc: print("or #%04X", FETCH() << shift); break; + case 0xd: print("xor #%04X", FETCH() << shift); break; + case 0xe: print("bsar %d", shift+1); break; + + default: print("??? (group bf)"); break; + } +} + +CPU_DISASSEMBLE( tms32051 ) +{ + UINT32 flags = 0; + UINT16 opcode; + int baseop; + int address, addr_mode; + + pcbase = pc; + rombase = oprom; + npc = pc; + output = buffer; + + opcode = FETCH(); + baseop = (opcode >> 8) & 0xff; + + addr_mode = (opcode >> 7) & 0x1; + address = opcode & 0x7f; + + switch (baseop) + { + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x04: case 0x05: case 0x06: case 0x07: + { + print("lar ar%d, %s", (opcode >> 8) & 0x7, GET_ADDRESS(addr_mode, address)); + break; + } + case 0x08: print("lamm %s", GET_ADDRESS(addr_mode, address)); break; + case 0x09: print("smmr %s", GET_ADDRESS(addr_mode, address)); break; + case 0x0a: print("subc %s", GET_ADDRESS(addr_mode, address)); break; + case 0x0b: print("rpt %s", GET_ADDRESS(addr_mode, address)); break; + case 0x0c: print("out %s, #%04X", GET_ADDRESS(addr_mode, address), FETCH()); break; + case 0x0d: print("ldp %s", GET_ADDRESS(addr_mode, address)); break; + case 0x0e: print("lst 0, %s", GET_ADDRESS(addr_mode, address)); break; + case 0x0f: print("lst 1, %s", GET_ADDRESS(addr_mode, address)); break; + + case 0x10: case 0x11: case 0x12: case 0x13: + case 0x14: case 0x15: case 0x16: case 0x17: + case 0x18: case 0x19: case 0x1a: case 0x1b: + case 0x1c: case 0x1d: case 0x1e: case 0x1f: + { + print("lacc %s %s", GET_ADDRESS(addr_mode, address), GET_SHIFT((opcode >> 8) & 0xf)); + break; + } + + case 0x20: case 0x21: case 0x22: case 0x23: + case 0x24: case 0x25: case 0x26: case 0x27: + case 0x28: case 0x29: case 0x2a: case 0x2b: + case 0x2c: case 0x2d: case 0x2e: case 0x2f: + { + print("add %s %s", GET_ADDRESS(addr_mode, address), GET_SHIFT((opcode >> 8) & 0xf)); + break; + } + + case 0x30: case 0x31: case 0x32: case 0x33: + case 0x34: case 0x35: case 0x36: case 0x37: + case 0x38: case 0x39: case 0x3a: case 0x3b: + case 0x3c: case 0x3d: case 0x3e: case 0x3f: + { + print("sub %s %s", GET_ADDRESS(addr_mode, address), GET_SHIFT((opcode >> 8) & 0xf)); + break; + } + + case 0x40: case 0x41: case 0x42: case 0x43: + case 0x44: case 0x45: case 0x46: case 0x47: + case 0x48: case 0x49: case 0x4a: case 0x4b: + case 0x4c: case 0x4d: case 0x4e: case 0x4f: + { + print("bit %d, %s", (opcode >> 8) & 0xf, GET_ADDRESS(addr_mode, address)); + break; + } + + case 0x50: print("mpya %s", GET_ADDRESS(addr_mode, address)); break; + case 0x51: print("mpys %s", GET_ADDRESS(addr_mode, address)); break; + case 0x52: print("sqra %s", GET_ADDRESS(addr_mode, address)); break; + case 0x53: print("sqrs %s", GET_ADDRESS(addr_mode, address)); break; + case 0x54: print("mpy %s", GET_ADDRESS(addr_mode, address)); break; + case 0x55: print("mpyu %s", GET_ADDRESS(addr_mode, address)); break; + case 0x57: print("bldp %s", GET_ADDRESS(addr_mode, address)); break; + case 0x58: print("xpl %s", GET_ADDRESS(addr_mode, address)); break; + case 0x59: print("opl %s", GET_ADDRESS(addr_mode, address)); break; + case 0x5a: print("apl %s", GET_ADDRESS(addr_mode, address)); break; + case 0x5b: print("cpl %s", GET_ADDRESS(addr_mode, address)); break; + case 0x5c: print("xpl %s, #%04X", GET_ADDRESS(addr_mode, address), FETCH()); break; + case 0x5d: print("opl %s, #%04X", GET_ADDRESS(addr_mode, address), FETCH()); break; + case 0x5e: print("apl %s, #%04X", GET_ADDRESS(addr_mode, address), FETCH()); break; + case 0x5f: print("cpl %s, #%04X", GET_ADDRESS(addr_mode, address), FETCH()); break; + + case 0x60: print("addc %s", GET_ADDRESS(addr_mode, address)); break; + case 0x61: print("add %s << 16", GET_ADDRESS(addr_mode, address)); break; + case 0x62: print("adds %s", GET_ADDRESS(addr_mode, address)); break; + case 0x63: print("addt %s", GET_ADDRESS(addr_mode, address)); break; + case 0x64: print("subb %s", GET_ADDRESS(addr_mode, address)); break; + case 0x65: print("sub %s << 16", GET_ADDRESS(addr_mode, address)); break; + case 0x66: print("subs %s", GET_ADDRESS(addr_mode, address)); break; + case 0x67: print("subt %s", GET_ADDRESS(addr_mode, address)); break; + case 0x68: print("zalr %s", GET_ADDRESS(addr_mode, address)); break; + case 0x69: print("lacl %s", GET_ADDRESS(addr_mode, address)); break; + case 0x6a: print("lacc %s << 16", GET_ADDRESS(addr_mode, address)); break; + case 0x6b: print("lact %s", GET_ADDRESS(addr_mode, address)); break; + case 0x6c: print("xor %s", GET_ADDRESS(addr_mode, address)); break; + case 0x6d: print("or %s", GET_ADDRESS(addr_mode, address)); break; + case 0x6e: print("and %s", GET_ADDRESS(addr_mode, address)); break; + case 0x6f: print("bitt %s", GET_ADDRESS(addr_mode, address)); break; + + case 0x70: print("lta %s", GET_ADDRESS(addr_mode, address)); break; + case 0x71: print("ltp %s", GET_ADDRESS(addr_mode, address)); break; + case 0x72: print("ltd %s", GET_ADDRESS(addr_mode, address)); break; + case 0x73: print("lt %s", GET_ADDRESS(addr_mode, address)); break; + case 0x74: print("lts %s", GET_ADDRESS(addr_mode, address)); break; + case 0x75: print("lph %s", GET_ADDRESS(addr_mode, address)); break; + case 0x76: print("pshd %s", GET_ADDRESS(addr_mode, address)); break; + case 0x77: print("dmov %s", GET_ADDRESS(addr_mode, address)); break; + case 0x78: print("adrk #%02X", opcode & 0xff); break; + case 0x79: print("b %04X, %s", FETCH(), GET_ADDRESS(1, address)); break; + case 0x7a: print("call %04X, %s", FETCH(), GET_ADDRESS(1, address)); flags = DASMFLAG_STEP_OVER; break; + case 0x7b: print("banz %04X, %s", FETCH(), GET_ADDRESS(1, address)); break; + case 0x7c: print("sbrk #%02X", opcode & 0xff); break; + case 0x7d: print("bd %04X, %s", FETCH(), GET_ADDRESS(1, address)); break; + case 0x7e: print("calld %04X, %s", FETCH(), GET_ADDRESS(1, address)); flags = DASMFLAG_STEP_OVER; break; + case 0x7f: print("banzd %04X, %s", FETCH(), GET_ADDRESS(1, address)); break; + + case 0x80: case 0x81: case 0x82: case 0x83: + case 0x84: case 0x85: case 0x86: case 0x87: + { + print("sar ar%d, %s", (opcode >> 8) & 0x7, GET_ADDRESS(addr_mode, address)); + break; + } + case 0x88: print("samm %s", GET_ADDRESS(addr_mode, address)); break; + case 0x89: print("lmmr %s, #%04X", GET_ADDRESS(addr_mode, address), FETCH()); break; + case 0x8a: print("popd %s", GET_ADDRESS(addr_mode, address)); break; + case 0x8b: + { + if ((opcode & 0xff) == 0) + { + print("nop"); + } + else + { + print("mar %s", GET_ADDRESS(addr_mode, address)); + } + break; + } + case 0x8c: print("spl %s", GET_ADDRESS(addr_mode, address)); break; + case 0x8d: print("sph %s", GET_ADDRESS(addr_mode, address)); break; + case 0x8e: print("sst 0, %s", GET_ADDRESS(addr_mode, address)); break; + case 0x8f: print("sst 1, %s", GET_ADDRESS(addr_mode, address)); break; + + case 0x90: case 0x91: case 0x92: case 0x93: + case 0x94: case 0x95: case 0x96: case 0x97: + { + print("sacl %s %s", GET_ADDRESS(addr_mode, address), GET_SHIFT((opcode >> 8) & 0x7)); + break; + } + case 0x98: case 0x99: case 0x9a: case 0x9b: + case 0x9c: case 0x9d: case 0x9e: case 0x9f: + { + print("sach %s %s", GET_ADDRESS(addr_mode, address), GET_SHIFT((opcode >> 8) & 0x7)); + break; + } + + case 0xa0: print("norm %s, #%04X", GET_ADDRESS(addr_mode, address), FETCH()); break; + case 0xa2: print("mac %s, #%04X", GET_ADDRESS(addr_mode, address), FETCH()); break; + case 0xa3: print("macd %s", GET_ADDRESS(addr_mode, address)); break; + case 0xa4: print("blpd %s", GET_ADDRESS(addr_mode, address)); break; + case 0xa5: print("blpd %s, #%04X", GET_ADDRESS(addr_mode, address), FETCH()); break; + case 0xa6: print("tblr %s", GET_ADDRESS(addr_mode, address)); break; + case 0xa7: print("tblw %s", GET_ADDRESS(addr_mode, address)); break; + case 0xa8: print("bldd %s, #%04X", GET_ADDRESS(addr_mode, address), FETCH()); break; + case 0xa9: print("bldd %s, #%04X", GET_ADDRESS(addr_mode, address), FETCH()); break; + case 0xaa: print("mads %s", GET_ADDRESS(addr_mode, address)); break; + case 0xab: print("madd %s", GET_ADDRESS(addr_mode, address)); break; + case 0xac: print("bldd %s", GET_ADDRESS(addr_mode, address)); break; + case 0xad: print("bldd %s", GET_ADDRESS(addr_mode, address)); break; + case 0xae: print("splk %s, #%04X", GET_ADDRESS(addr_mode, address), FETCH()); break; + case 0xaf: print("in %s, #%04X", GET_ADDRESS(addr_mode, address), FETCH()); break; + + case 0xb0: case 0xb1: case 0xb2: case 0xb3: + case 0xb4: case 0xb5: case 0xb6: case 0xb7: + { + print("lar ar%d, #%02X", (opcode >> 8) & 0x7, opcode & 0xff); + break; + } + case 0xb8: print("add #%02X", opcode & 0xff); break; + case 0xb9: print("lacl #%02X", opcode & 0xff); break; + case 0xba: print("sub #%02X", opcode & 0xff); break; + case 0xbb: print("rpt #%02X", opcode & 0xff); break; + + case 0xbc: + case 0xbd: + { + print("ldp #%03X", opcode & 0x1ff); + break; + } + case 0xbe: dasm_group_be(opcode); break; + case 0xbf: dasm_group_bf(opcode); break; + + case 0xe0: case 0xe1: case 0xe2: case 0xe3: + { + int zlcvmask = opcode & 0xf; + int zlcv = (opcode >> 4) & 0xf; + int zl = (zlcv & 0xc) | ((zlcvmask >> 2) & 0x3); + int cv = ((zlcv << 2) & 0xc) | (zlcvmask & 0x3); + int tp = (opcode >> 8) & 0x3; + + print("bcnd %04X", FETCH()); + + if (*(zl_condition_codes[zl]) != 0) + { + print(", %s", zl_condition_codes[zl]); + } + if (*(cv_condition_codes[cv]) != 0) + { + print(", %s", cv_condition_codes[cv]); + } + if (*(tp_condition_codes[tp]) != 0) + { + print(", %s", tp_condition_codes[tp]); + } + break; + } + + case 0xe4: case 0xe5: case 0xe6: case 0xe7: + case 0xf4: case 0xf5: case 0xf6: case 0xf7: + { + int zlcvmask = opcode & 0xf; + int zlcv = (opcode >> 4) & 0xf; + int zl = (zlcv & 0xc) | ((zlcvmask >> 2) & 0x3); + int cv = ((zlcv << 2) & 0xc) | (zlcvmask & 0x3); + int tp = (opcode >> 8) & 0x3; + int n = ((opcode >> 12) & 0x1) + 1; + + print("xc %d", n); + + if (*(zl_condition_codes[zl]) != 0) + { + print(", %s", zl_condition_codes[zl]); + } + if (*(cv_condition_codes[cv]) != 0) + { + print(", %s", cv_condition_codes[cv]); + } + if (*(tp_condition_codes[tp]) != 0) + { + print(", %s", tp_condition_codes[tp]); + } + break; + } + + case 0xe8: case 0xe9: case 0xea: case 0xeb: + { + int zlcvmask = opcode & 0xf; + int zlcv = (opcode >> 4) & 0xf; + int zl = (zlcv & 0xc) | ((zlcvmask >> 2) & 0x3); + int cv = ((zlcv << 2) & 0xc) | (zlcvmask & 0x3); + int tp = (opcode >> 8) & 0x3; + + print("cc %04X", FETCH()); + + if (*(zl_condition_codes[zl]) != 0) + { + print(", %s", zl_condition_codes[zl]); + } + if (*(cv_condition_codes[cv]) != 0) + { + print(", %s", cv_condition_codes[cv]); + } + if (*(tp_condition_codes[tp]) != 0) + { + print(", %s", tp_condition_codes[tp]); + } + break; + } + + case 0xec: case 0xed: case 0xee: + { + int zlcvmask = opcode & 0xf; + int zlcv = (opcode >> 4) & 0xf; + int zl = (zlcv & 0xc) | ((zlcvmask >> 2) & 0x3); + int cv = ((zlcv << 2) & 0xc) | (zlcvmask & 0x3); + int tp = (opcode >> 8) & 0x3; + + print("retc "); + + if (*(zl_condition_codes[zl]) != 0) + { + print(", %s", zl_condition_codes[zl]); + } + if (*(cv_condition_codes[cv]) != 0) + { + print(", %s", cv_condition_codes[cv]); + } + if (*(tp_condition_codes[tp]) != 0) + { + print(", %s", tp_condition_codes[tp]); + } + flags = DASMFLAG_STEP_OUT; + break; + } + + case 0xef: print("ret"); flags = DASMFLAG_STEP_OUT; break; + + case 0xf0: case 0xf1: case 0xf2: case 0xf3: + { + int zlcvmask = opcode & 0xf; + int zlcv = (opcode >> 4) & 0xf; + int zl = (zlcv & 0xc) | ((zlcvmask >> 2) & 0x3); + int cv = ((zlcv << 2) & 0xc) | (zlcvmask & 0x3); + int tp = (opcode >> 8) & 0x3; + + print("bcndd %04X", FETCH()); + + if (*(zl_condition_codes[zl]) != 0) + { + print(", %s", zl_condition_codes[zl]); + } + if (*(cv_condition_codes[cv]) != 0) + { + print(", %s", cv_condition_codes[cv]); + } + if (*(tp_condition_codes[tp]) != 0) + { + print(", %s", tp_condition_codes[tp]); + } + break; + } + + case 0xf8: case 0xf9: case 0xfa: case 0xfb: + { + int zlcvmask = opcode & 0xf; + int zlcv = (opcode >> 4) & 0xf; + int zl = (zlcv & 0xc) | ((zlcvmask >> 2) & 0x3); + int cv = ((zlcv << 2) & 0xc) | (zlcvmask & 0x3); + int tp = (opcode >> 8) & 0x3; + + print("ccd %04X", FETCH()); + + if (*(zl_condition_codes[zl]) != 0) + { + print(", %s", zl_condition_codes[zl]); + } + if (*(cv_condition_codes[cv]) != 0) + { + print(", %s", cv_condition_codes[cv]); + } + if (*(tp_condition_codes[tp]) != 0) + { + print(", %s", tp_condition_codes[tp]); + } + break; + } + + case 0xfc: case 0xfd: case 0xfe: + { + int zlcvmask = opcode & 0xf; + int zlcv = (opcode >> 4) & 0xf; + int zl = (zlcv & 0xc) | ((zlcvmask >> 2) & 0x3); + int cv = ((zlcv << 2) & 0xc) | (zlcvmask & 0x3); + int tp = (opcode >> 8) & 0x3; + + print("retcd "); + + if (*(zl_condition_codes[zl]) != 0) + { + print(", %s", zl_condition_codes[zl]); + } + if (*(cv_condition_codes[cv]) != 0) + { + print(", %s", cv_condition_codes[cv]); + } + if (*(tp_condition_codes[tp]) != 0) + { + print(", %s", tp_condition_codes[tp]); + } + flags = DASMFLAG_STEP_OUT; + break; + } + + case 0xff: print("retd"); flags = DASMFLAG_STEP_OUT; break; + + default: print("??? ($%04X)", opcode); break; + } + + return (npc-pc) | flags | DASMFLAG_SUPPORTED; +} diff --git a/src/devices/cpu/tms32051/tms32051.c b/src/devices/cpu/tms32051/tms32051.c new file mode 100644 index 00000000000..01a5a414022 --- /dev/null +++ b/src/devices/cpu/tms32051/tms32051.c @@ -0,0 +1,531 @@ +// license:BSD-3-Clause +// copyright-holders:Ville Linde +/* + Texas Instruments TMS320C51 DSP Emulator + + Written by Ville Linde +*/ + +#include "emu.h" +#include "debugger.h" +#include "tms32051.h" + +enum +{ + TMS32051_PC = 1, + TMS32051_ACC, + TMS32051_ACCB, + TMS32051_PREG, + TMS32051_TREG0, + TMS32051_TREG1, + TMS32051_TREG2, + TMS32051_BMAR, + TMS32051_RPTC, + TMS32051_BRCR, + TMS32051_INDX, + TMS32051_DBMR, + TMS32051_ARCR, + TMS32051_DP, + TMS32051_ARP, + TMS32051_ARB, + TMS32051_AR0, + TMS32051_AR1, + TMS32051_AR2, + TMS32051_AR3, + TMS32051_AR4, + TMS32051_AR5, + TMS32051_AR6, + TMS32051_AR7 +}; + + +const device_type TMS32051 = &device_creator; + + +/************************************************************************** + * Internal memory map + **************************************************************************/ + +static ADDRESS_MAP_START( internal_pgm, AS_PROGRAM, 16, tms32051_device ) +// AM_RANGE(0x0000, 0x1fff) AM_ROM // ROM TODO: is off-chip if MP/_MC = 0 + AM_RANGE(0x2000, 0x23ff) AM_RAM AM_SHARE("saram") // SARAM TODO: is off-chip if RAM bit = 0 + AM_RANGE(0xfe00, 0xffff) AM_RAM AM_SHARE("daram_b0") // DARAM B0 TODO: is off-chip if CNF = 0 +ADDRESS_MAP_END + +static ADDRESS_MAP_START( internal_data, AS_DATA, 16, tms32051_device ) + AM_RANGE(0x0000, 0x005f) AM_READWRITE(cpuregs_r, cpuregs_w) + AM_RANGE(0x0060, 0x007f) AM_RAM // DARAM B2 + AM_RANGE(0x0100, 0x02ff) AM_RAM AM_SHARE("daram_b0") // DARAM B0 TODO: is unconnected if CNF = 1 + AM_RANGE(0x0300, 0x04ff) AM_RAM // DARAM B1 + AM_RANGE(0x0800, 0x0bff) AM_RAM AM_SHARE("saram") // SARAM TODO: is off-chip if OVLY = 0 +ADDRESS_MAP_END + + +tms32051_device::tms32051_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : cpu_device(mconfig, TMS32051, "TMS32051", tag, owner, clock, "tms32051", __FILE__) + , m_program_config("program", ENDIANNESS_LITTLE, 16, 16, -1, ADDRESS_MAP_NAME(internal_pgm)) + , m_data_config("data", ENDIANNESS_LITTLE, 16, 16, -1, ADDRESS_MAP_NAME(internal_data)) +{ +} + + +offs_t tms32051_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( tms32051 ); + return CPU_DISASSEMBLE_NAME(tms32051)(this, buffer, pc, oprom, opram, options); +} + + +#define CYCLES(x) (m_icount -= x) + +#define ROPCODE() m_direct->read_word((m_pc++) << 1) + +void tms32051_device::CHANGE_PC(UINT16 new_pc) +{ + m_pc = new_pc; +} + +UINT16 tms32051_device::PM_READ16(UINT16 address) +{ + return m_program->read_word(address << 1); +} + +void tms32051_device::PM_WRITE16(UINT16 address, UINT16 data) +{ + m_program->write_word(address << 1, data); +} + +UINT16 tms32051_device::DM_READ16(UINT16 address) +{ + return m_data->read_word(address << 1); +} + +void tms32051_device::DM_WRITE16(UINT16 address, UINT16 data) +{ + m_data->write_word(address << 1, data); +} + +#include "32051ops.c" +#include "32051ops.h" + +void tms32051_device::op_group_be() +{ + (this->*s_opcode_table_be[m_op & 0xff])(); +} + +void tms32051_device::op_group_bf() +{ + (this->*s_opcode_table_bf[m_op & 0xff])(); +} + +void tms32051_device::delay_slot(UINT16 startpc) +{ + m_op = ROPCODE(); + (this->*s_opcode_table[m_op >> 8])(); + + while (m_pc - startpc < 2) + { + m_op = ROPCODE(); + (this->*s_opcode_table[m_op >> 8])(); + } +} + +/*****************************************************************************/ + +void tms32051_device::device_start() +{ + m_program = &space(AS_PROGRAM); + m_direct = &m_program->direct(); + m_data = &space(AS_DATA); + + m_pcstack_ptr = 0; + m_op = 0; + m_acc = 0; + m_accb = 0; + m_preg = 0; + m_treg0 = 0; + m_treg1 = 0; + m_treg2 = 0; + memset(m_ar, 0, sizeof(m_ar)); + m_bmar = 0; + m_brcr = 0; + m_paer = 0; + m_pasr = 0; + m_indx = 0; + m_dbmr = 0; + m_arcr = 0; + memset(&m_st0, 0, sizeof(m_st0)); + memset(&m_st1, 0, sizeof(m_st1)); + memset(&m_pmst, 0, sizeof(m_pmst)); + memset(m_pcstack, 0, sizeof(m_pcstack)); + m_imr = 0; + m_cbsr1 = 0; + m_cber1 = 0; + m_cbsr2 = 0; + m_cber2 = 0; + memset(&m_timer, 0, sizeof(m_timer)); + memset(&m_serial, 0, sizeof(m_serial)); + + state_add( TMS32051_PC, "PC", m_pc).formatstr("%04X"); + state_add( TMS32051_ACC, "ACC", m_acc).formatstr("%08X"); + state_add( TMS32051_ACCB, "ACCB", m_accb).formatstr("%08X"); + state_add( TMS32051_PREG, "PREG", m_preg).formatstr("%08X"); + state_add( TMS32051_TREG0, "TREG0", m_treg0).formatstr("%04X"); + state_add( TMS32051_TREG1, "TREG1", m_treg1).formatstr("%04X"); + state_add( TMS32051_TREG2, "TREG2", m_treg2).formatstr("%04X"); + state_add( TMS32051_BMAR, "BMAR", m_bmar).formatstr("%08X"); + state_add( TMS32051_RPTC, "RPTC", m_rptc).formatstr("%08X"); + state_add( TMS32051_BRCR, "BRCR", m_brcr).formatstr("%08X"); + state_add( TMS32051_INDX, "INDX", m_indx).formatstr("%04X"); + state_add( TMS32051_DBMR, "DBMR", m_dbmr).formatstr("%04X"); + state_add( TMS32051_ARCR, "ARCR", m_arcr).formatstr("%04X"); + state_add( TMS32051_DP, "DP", m_st0.dp).formatstr("%04X"); + state_add( TMS32051_ARP, "ARP", m_st0.arp).formatstr("%04X"); + state_add( TMS32051_ARB, "ARB", m_st1.arb).formatstr("%04X"); + state_add( TMS32051_AR0, "AR0", m_ar[0]).formatstr("%04X"); + state_add( TMS32051_AR1, "AR1", m_ar[1]).formatstr("%04X"); + state_add( TMS32051_AR2, "AR2", m_ar[2]).formatstr("%04X"); + state_add( TMS32051_AR3, "AR3", m_ar[3]).formatstr("%04X"); + state_add( TMS32051_AR4, "AR4", m_ar[4]).formatstr("%04X"); + state_add( TMS32051_AR5, "AR5", m_ar[5]).formatstr("%04X"); + state_add( TMS32051_AR6, "AR6", m_ar[6]).formatstr("%04X"); + state_add( TMS32051_AR7, "AR7", m_ar[7]).formatstr("%04X"); + + state_add(STATE_GENPC, "GENPC", m_pc).formatstr("%04X").noshow(); + + m_icountptr = &m_icount; +} + +void tms32051_device::device_reset() +{ + // reset registers + m_st0.intm = 1; + m_st0.ov = 0; + m_st1.c = 1; + m_st1.cnf = 0; + m_st1.hm = 1; + m_st1.pm = 0; + m_st1.sxm = 1; + m_st1.xf = 1; + m_pmst.avis = 0; + m_pmst.braf = 0; + m_pmst.iptr = 0; + m_pmst.ndx = 0; + m_pmst.ovly = 0; + m_pmst.ram = 0; + m_pmst.mpmc = 0; // TODO: this is set to logical pin state at reset + m_pmst.trm = 0; + m_ifr = 0; + m_cbcr = 0; + m_rptc = -1; + + // simulate internal rom boot loader (can be removed when the dsp rom(s) is dumped) + m_st0.intm = 1; + m_st1.cnf = 1; + m_pmst.ram = 1; + m_pmst.ovly = 0; + + int i; + UINT16 src, dst, length; + + src = 0x7800; + dst = DM_READ16(src++); + length = DM_READ16(src++); + + CHANGE_PC(dst); + + /* TODO: if you soft reset on Taito JC it tries to do a 0x7802->0x9007 (0xff00) transfer. */ + for (i=0; i < (length & 0x7ff); i++) + { + UINT16 data = DM_READ16(src++); + PM_WRITE16(dst++, data); + } +} + +void tms32051_device::check_interrupts() +{ + if (m_st0.intm == 0 && m_ifr != 0) + { + for (int i = 0; i < 16; i++) + { + if (m_ifr & (1 << i)) + { + m_st0.intm = 1; + PUSH_STACK(m_pc); + + m_pc = (m_pmst.iptr << 11) | ((i+1) << 1); + m_ifr &= ~(1 << i); + + save_interrupt_context(); + break; + } + } + } +} + +void tms32051_device::save_interrupt_context() +{ + m_shadow.acc = m_acc; + m_shadow.accb = m_accb; + m_shadow.arcr = m_arcr; + m_shadow.indx = m_indx; + m_shadow.preg = m_preg; + m_shadow.treg0 = m_treg0; + m_shadow.treg1 = m_treg1; + m_shadow.treg2 = m_treg2; + memcpy(&m_shadow.pmst, &m_pmst, sizeof(TMS32051_PMST)); + memcpy(&m_shadow.st0, &m_st0, sizeof(TMS32051_ST0)); + memcpy(&m_shadow.st1, &m_st1, sizeof(TMS32051_ST1)); +} + +void tms32051_device::restore_interrupt_context() +{ + m_acc = m_shadow.acc; + m_accb = m_shadow.accb; + m_arcr = m_shadow.arcr; + m_indx = m_shadow.indx; + m_preg = m_shadow.preg; + m_treg0 = m_shadow.treg0; + m_treg1 = m_shadow.treg1; + m_treg2 = m_shadow.treg2; + memcpy(&m_pmst, &m_shadow.pmst, sizeof(TMS32051_PMST)); + memcpy(&m_st0, &m_shadow.st0, sizeof(TMS32051_ST0)); + memcpy(&m_st1, &m_shadow.st1, sizeof(TMS32051_ST1)); +} + +void tms32051_device::execute_set_input(int irq, int state) +{ + if (state == ASSERT_LINE) + { + if ((m_imr & (1 << irq)) != 0) + { + m_ifr |= 1 << irq; + } + + check_interrupts(); + } +} + + +void tms32051_device::execute_run() +{ + while (m_icount > 0) + { + UINT16 ppc; + + // handle block repeat + if (m_pmst.braf) + { + if (m_pc == m_paer) + { + if (m_brcr > 0) + { + CHANGE_PC(m_pasr); + } + + m_brcr--; + if (m_brcr <= 0) + { + m_pmst.braf = 0; + } + } + } + + ppc = m_pc; + debugger_instruction_hook(this, m_pc); + + m_op = ROPCODE(); + (this->*s_opcode_table[m_op >> 8])(); + + // handle single repeat + if (m_rptc > 0) + { + if (ppc == m_rpt_end) + { + CHANGE_PC(m_rpt_start); + m_rptc--; + } + } + else + { + m_rptc = 0; + } + + m_timer.psc--; + if (m_timer.psc <= 0) + { + m_timer.psc = m_timer.tddr; + m_timer.tim--; + if (m_timer.tim <= 0) + { + // reset timer + m_timer.tim = m_timer.prd; + + execute_set_input(TMS32051_TINT, ASSERT_LINE); + } + } + } +} + + +/*****************************************************************************/ + +READ16_MEMBER( tms32051_device::cpuregs_r ) +{ + switch (offset) + { + case 0x04: return m_imr; + case 0x06: return m_ifr; + + case 0x07: // PMST + { + UINT16 r = 0; + r |= m_pmst.iptr << 11; + r |= m_pmst.avis << 7; + r |= m_pmst.ovly << 5; + r |= m_pmst.ram << 4; + r |= m_pmst.mpmc << 3; + r |= m_pmst.ndx << 2; + r |= m_pmst.trm << 1; + r |= m_pmst.braf << 0; + return r; + } + + case 0x09: return m_brcr; + case 0x10: return m_ar[0]; + case 0x11: return m_ar[1]; + case 0x12: return m_ar[2]; + case 0x13: return m_ar[3]; + case 0x14: return m_ar[4]; + case 0x15: return m_ar[5]; + case 0x16: return m_ar[6]; + case 0x17: return m_ar[7]; + case 0x18: return m_indx; + case 0x19: return m_arcr; + case 0x1a: return m_cbsr1; + case 0x1b: return m_cber1; + case 0x1c: return m_cbsr2; + case 0x1d: return m_cber2; + case 0x1e: return m_cbcr; + case 0x1f: return m_bmar; + + case 0x20: return m_serial.drr; + case 0x21: return m_serial.dxr; + + case 0x24: return m_timer.tim; + case 0x25: return m_timer.prd; + + case 0x26: // TCR + { + UINT16 r = 0; + r |= (m_timer.psc & 0xf) << 6; + r |= (m_timer.tddr & 0xf); + return r; + } + + case 0x28: // PDWSR + return 0; + + default: + if (!space.debugger_access()) + fatalerror("32051: cpuregs_r: unimplemented memory-mapped register %02X at %04X\n", offset, m_pc-1); + } + + return 0; +} + +WRITE16_MEMBER( tms32051_device::cpuregs_w ) +{ + switch (offset) + { + case 0x00: break; + case 0x04: m_imr = data; break; + + case 0x06: // IFR + { + for (int i = 0; i < 16; i++) + { + if (data & (1 << i)) + { + m_ifr &= ~(1 << i); + } + } + break; + } + + case 0x07: // PMST + { + m_pmst.iptr = (data >> 11) & 0x1f; + m_pmst.avis = (data & 0x80) ? 1 : 0; + m_pmst.ovly = (data & 0x20) ? 1 : 0; + m_pmst.ram = (data & 0x10) ? 1 : 0; + m_pmst.mpmc = (data & 0x08) ? 1 : 0; + m_pmst.ndx = (data & 0x04) ? 1 : 0; + m_pmst.trm = (data & 0x02) ? 1 : 0; + m_pmst.braf = (data & 0x01) ? 1 : 0; + break; + } + + case 0x09: m_brcr = data; break; + case 0x0e: m_treg2 = data; break; + case 0x0f: m_dbmr = data; break; + case 0x10: m_ar[0] = data; break; + case 0x11: m_ar[1] = data; break; + case 0x12: m_ar[2] = data; break; + case 0x13: m_ar[3] = data; break; + case 0x14: m_ar[4] = data; break; + case 0x15: m_ar[5] = data; break; + case 0x16: m_ar[6] = data; break; + case 0x17: m_ar[7] = data; break; + case 0x18: m_indx = data; break; + case 0x19: m_arcr = data; break; + case 0x1a: m_cbsr1 = data; break; + case 0x1b: m_cber1 = data; break; + case 0x1c: m_cbsr2 = data; break; + case 0x1d: m_cber2 = data; break; + case 0x1e: m_cbcr = data; break; + case 0x1f: m_bmar = data; break; + + case 0x20: m_serial.drr = data; break; + case 0x21: m_serial.dxr = data; break; + case 0x22: m_serial.spc = data; break; + + case 0x24: m_timer.tim = data; break; + case 0x25: m_timer.prd = data; break; + + case 0x26: // TCR + { + m_timer.tddr = data & 0xf; + m_timer.psc = (data >> 6) & 0xf; + + if (data & 0x20) + { + m_timer.tim = m_timer.prd; + m_timer.psc = m_timer.tddr; + } + break; + } + + case 0x28: // PDWSR + break; + + default: + if (!space.debugger_access()) + fatalerror("32051: cpuregs_w: unimplemented memory-mapped register %02X, data %04X at %04X\n", offset, data, m_pc-1); + } +} + + +bool tms32051_device::memory_read(address_spacenum spacenum, offs_t offset, int size, UINT64 &value) +{ + /* TODO: alignment if offset is odd */ + if (spacenum == AS_PROGRAM) + { + value = (PM_READ16(offset>>1)); + } + else if (spacenum == AS_DATA) + { + value = (DM_READ16(offset>>1)); + } + return 1; +} diff --git a/src/devices/cpu/tms32051/tms32051.h b/src/devices/cpu/tms32051/tms32051.h new file mode 100644 index 00000000000..43c1008d79c --- /dev/null +++ b/src/devices/cpu/tms32051/tms32051.h @@ -0,0 +1,371 @@ +// license:BSD-3-Clause +// copyright-holders:Ville Linde +#pragma once + +#ifndef __TMS32051_H__ +#define __TMS32051_H__ + + +enum +{ + TMS32051_INT1 = 0, + TMS32051_INT2, + TMS32051_INT3, + TMS32051_TINT, + TMS32051_RINT, + TMS32051_XINT, + TMS32051_TRNT, + TMS32051_TXNT, + TMS32051_INT4 +}; + +struct TMS32051_PMST +{ + UINT16 iptr; + UINT16 avis; + UINT16 ovly; + UINT16 ram; + UINT16 mpmc; + UINT16 ndx; + UINT16 trm; + UINT16 braf; +}; + +struct TMS32051_ST0 +{ + UINT16 dp; + UINT16 intm; + UINT16 ovm; + UINT16 ov; + UINT16 arp; +}; + +struct TMS32051_ST1 +{ + UINT16 arb; + UINT16 cnf; + UINT16 tc; + UINT16 sxm; + UINT16 c; + UINT16 hm; + UINT16 xf; + UINT16 pm; +}; + + +class tms32051_device : public cpu_device +{ +public: + // construction/destruction + tms32051_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + DECLARE_READ16_MEMBER( cpuregs_r ); + DECLARE_WRITE16_MEMBER( cpuregs_w ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_execute_interface overrides + virtual UINT32 execute_min_cycles() const { return 1; } + virtual UINT32 execute_max_cycles() const { return 5; } + virtual UINT32 execute_input_lines() const { return 6; } + virtual void execute_run(); + virtual void execute_set_input(int inputnum, int state); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const { return (spacenum == AS_PROGRAM) ? &m_program_config : ( (spacenum == AS_DATA) ? &m_data_config : NULL ); } + virtual bool memory_read(address_spacenum spacenum, offs_t offset, int size, UINT64 &value); + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const { return 2; } + virtual UINT32 disasm_max_opcode_bytes() const { return 4; } + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + +private: + address_space_config m_program_config; + address_space_config m_data_config; + + typedef void ( tms32051_device::*opcode_func )(); + static const opcode_func s_opcode_table[256]; + static const opcode_func s_opcode_table_be[256]; + static const opcode_func s_opcode_table_bf[256]; + + UINT16 m_pc; + UINT16 m_op; + INT32 m_acc; + INT32 m_accb; + INT32 m_preg; + UINT16 m_treg0; + UINT16 m_treg1; + UINT16 m_treg2; + UINT16 m_ar[8]; + INT32 m_rptc; + + UINT16 m_bmar; + INT32 m_brcr; + UINT16 m_paer; + UINT16 m_pasr; + UINT16 m_indx; + UINT16 m_dbmr; + UINT16 m_arcr; + + TMS32051_ST0 m_st0; + TMS32051_ST1 m_st1; + TMS32051_PMST m_pmst; + + UINT16 m_ifr; + UINT16 m_imr; + + UINT16 m_pcstack[8]; + int m_pcstack_ptr; + + UINT16 m_rpt_start, m_rpt_end; + + UINT16 m_cbcr; + UINT16 m_cbsr1; + UINT16 m_cber1; + UINT16 m_cbsr2; + UINT16 m_cber2; + + struct + { + int tddr; + int psc; + UINT16 tim; + UINT16 prd; + } m_timer; + + struct + { + UINT16 drr; + UINT16 dxr; + UINT16 spc; + } m_serial; + + struct + { + INT32 acc; + INT32 accb; + UINT16 arcr; + UINT16 indx; + TMS32051_PMST pmst; + INT32 preg; + TMS32051_ST0 st0; + TMS32051_ST1 st1; + INT32 treg0; + INT32 treg1; + INT32 treg2; + } m_shadow; + + address_space *m_program; + direct_read_data *m_direct; + address_space *m_data; + int m_icount; + + inline void CHANGE_PC(UINT16 new_pc); + inline UINT16 PM_READ16(UINT16 address); + inline void PM_WRITE16(UINT16 address, UINT16 data); + inline UINT16 DM_READ16(UINT16 address); + inline void DM_WRITE16(UINT16 address, UINT16 data); + inline void PUSH_STACK(UINT16 pc); + inline UINT16 POP_STACK(); + inline INT32 SUB(UINT32 a, UINT32 b); + inline INT32 ADD(UINT32 a, UINT32 b); + inline void UPDATE_AR(int ar, int step); + inline void UPDATE_ARP(int nar); + UINT16 GET_ADDRESS(); + inline int GET_ZLVC_CONDITION(int zlvc, int zlvc_mask); + inline int GET_TP_CONDITION(int tp); + inline INT32 PREG_PSCALER(INT32 preg); + void op_invalid(); + void op_abs(); + void op_adcb(); + void op_add_mem(); + void op_add_simm(); + void op_add_limm(); + void op_add_s16_mem(); + void op_addb(); + void op_addc(); + void op_adds(); + void op_addt(); + void op_and_mem(); + void op_and_limm(); + void op_and_s16_limm(); + void op_andb(); + void op_bsar(); + void op_cmpl(); + void op_crgt(); + void op_crlt(); + void op_exar(); + void op_lacb(); + void op_lacc_mem(); + void op_lacc_limm(); + void op_lacc_s16_mem(); + void op_lacl_simm(); + void op_lacl_mem(); + void op_lact(); + void op_lamm(); + void op_neg(); + void op_norm(); + void op_or_mem(); + void op_or_limm(); + void op_or_s16_limm(); + void op_orb(); + void op_rol(); + void op_rolb(); + void op_ror(); + void op_rorb(); + void op_sacb(); + void op_sach(); + void op_sacl(); + void op_samm(); + void op_sath(); + void op_satl(); + void op_sbb(); + void op_sbbb(); + void op_sfl(); + void op_sflb(); + void op_sfr(); + void op_sfrb(); + void op_sub_mem(); + void op_sub_s16_mem(); + void op_sub_simm(); + void op_sub_limm(); + void op_subb(); + void op_subc(); + void op_subs(); + void op_subt(); + void op_xor_mem(); + void op_xor_limm(); + void op_xor_s16_limm(); + void op_xorb(); + void op_zalr(); + void op_zap(); + void op_adrk(); + void op_cmpr(); + void op_lar_mem(); + void op_lar_simm(); + void op_lar_limm(); + void op_ldp_mem(); + void op_ldp_imm(); + void op_mar(); + void op_sar(); + void op_sbrk(); + void op_b(); + void op_bacc(); + void op_baccd(); + void op_banz(); + void op_banzd(); + void op_bcnd(); + void op_bcndd(); + void op_bd(); + void op_cala(); + void op_calad(); + void op_call(); + void op_calld(); + void op_cc(); + void op_ccd(); + void op_intr(); + void op_nmi(); + void op_retc(); + void op_retcd(); + void op_rete(); + void op_reti(); + void op_trap(); + void op_xc(); + void op_bldd_slimm(); + void op_bldd_dlimm(); + void op_bldd_sbmar(); + void op_bldd_dbmar(); + void op_bldp(); + void op_blpd_bmar(); + void op_blpd_imm(); + void op_dmov(); + void op_in(); + void op_lmmr(); + void op_out(); + void op_smmr(); + void op_tblr(); + void op_tblw(); + void op_apl_dbmr(); + void op_apl_imm(); + void op_cpl_dbmr(); + void op_cpl_imm(); + void op_opl_dbmr(); + void op_opl_imm(); + void op_splk(); + void op_xpl_dbmr(); + void op_xpl_imm(); + void op_apac(); + void op_lph(); + void op_lt(); + void op_lta(); + void op_ltd(); + void op_ltp(); + void op_lts(); + void op_mac(); + void op_macd(); + void op_madd(); + void op_mads(); + void op_mpy_mem(); + void op_mpy_simm(); + void op_mpy_limm(); + void op_mpya(); + void op_mpys(); + void op_mpyu(); + void op_pac(); + void op_spac(); + void op_sph(); + void op_spl(); + void op_spm(); + void op_sqra(); + void op_sqrs(); + void op_zpr(); + void op_bit(); + void op_bitt(); + void op_clrc_ov(); + void op_clrc_ext(); + void op_clrc_hold(); + void op_clrc_tc(); + void op_clrc_carry(); + void op_clrc_cnf(); + void op_clrc_intm(); + void op_clrc_xf(); + void op_idle(); + void op_idle2(); + void op_lst_st0(); + void op_lst_st1(); + void op_pop(); + void op_popd(); + void op_pshd(); + void op_push(); + void op_rpt_mem(); + void op_rpt_limm(); + void op_rpt_simm(); + void op_rptb(); + void op_rptz(); + void op_setc_ov(); + void op_setc_ext(); + void op_setc_hold(); + void op_setc_tc(); + void op_setc_carry(); + void op_setc_xf(); + void op_setc_cnf(); + void op_setc_intm(); + void op_sst_st0(); + void op_sst_st1(); + void op_group_be(); + void op_group_bf(); + void delay_slot(UINT16 startpc); + void check_interrupts(); + void save_interrupt_context(); + void restore_interrupt_context(); +}; + + +extern const device_type TMS32051; + + +#endif /* __TMS32051_H__ */ diff --git a/src/devices/cpu/tms32082/dis_mp.c b/src/devices/cpu/tms32082/dis_mp.c new file mode 100644 index 00000000000..1b89eb88129 --- /dev/null +++ b/src/devices/cpu/tms32082/dis_mp.c @@ -0,0 +1,513 @@ +// license:BSD-3-Clause +// copyright-holders:Ville Linde +// TMS32082 MP Disassembler + +#include "emu.h" + + +#define SIMM15(v) (INT32)((v & 0x4000) ? (v | 0xffffe000) : (v)) +#define UIMM15(v) (v) + +static const char *BCND_CONDITION[32] = +{ + "nev.b", "gt0.b", "eq0.b", "ge0.b", "lt0.b", "ne0.b", "le0.b", "alw.b", + "nev.h", "gt0.h", "eq0.h", "ge0.h", "lt0.h", "ne0.h", "le0.h", "alw.h", + "nev.w", "gt0.w", "eq0.w", "ge0.w", "lt0.w", "ne0.w", "le0.w", "alw.w", + "nev.d", "gt0.d", "eq0.d", "ge0.d", "lt0.d", "ne0.d", "le0.d", "alw.d", +}; + +static const char *BITNUM_CONDITION[32] = +{ + "eq.b", "ne.b", "gt.b", "le.b", "lt.b", "ge.b", "hi.b", "ls.b", + "lo.b", "hs.b", "eq.h", "ne.h", "gt.h", "le.h", "lt.h", "ge.h", + "hi.h", "ls.h", "lo.h", "hs.h", "eq.w", "ne.w", "gt.w", "le.w", + "lt.w", "ge.w", "hi.w", "ls.w", "lo.w", "hs.w", "?", "?", +}; + +static const char *MEMOP_S[2] = +{ + ":s", "" +}; + +static const char *MEMOP_M[2] = +{ + ":m", "" +}; + +static const char *FLOATOP_PRECISION[4] = +{ + "s", "d", "i", "u" +}; + +static const char *ACC_SEL[4] = +{ + "A0", "A1", "A2", "A3" +}; + +static const char *FLOATOP_ROUND[4] = +{ + "n", "z", "p", "m" +}; + +static char *output; +static const UINT8 *opdata; +static int opbytes; + +static void ATTR_PRINTF(1,2) print(const char *fmt, ...) +{ + va_list vl; + + va_start(vl, fmt); + output += vsprintf(output, fmt, vl); + va_end(vl); +} + +static UINT32 fetch(void) +{ + UINT32 d = ((UINT32)(opdata[0]) << 24) | ((UINT32)(opdata[1]) << 16) | ((UINT32)(opdata[2]) << 8) | opdata[3]; + opdata += 4; + opbytes += 4; + return d; +} + +static char* get_creg_name(UINT32 reg) +{ + static char buffer[64]; + + switch (reg) + { + case 0x0000: sprintf(buffer, "EPC"); break; + case 0x0001: sprintf(buffer, "EIP"); break; + case 0x0002: sprintf(buffer, "CONFIG"); break; + case 0x0004: sprintf(buffer, "INTPEN"); break; + case 0x0006: sprintf(buffer, "IE"); break; + case 0x0008: sprintf(buffer, "FPST"); break; + case 0x000a: sprintf(buffer, "PPERROR"); break; + case 0x000d: sprintf(buffer, "PKTREQ"); break; + case 0x000e: sprintf(buffer, "TCOUNT"); break; + case 0x000f: sprintf(buffer, "TSCALE"); break; + case 0x0010: sprintf(buffer, "FLTOP"); break; + case 0x0011: sprintf(buffer, "FLTADR"); break; + case 0x0012: sprintf(buffer, "FLTTAG"); break; + case 0x0013: sprintf(buffer, "FLTDTL"); break; + case 0x0014: sprintf(buffer, "FLTDTH"); break; + case 0x0020: sprintf(buffer, "SYSSTK"); break; + case 0x0021: sprintf(buffer, "SYSTMP"); break; + case 0x0030: sprintf(buffer, "MPC"); break; + case 0x0031: sprintf(buffer, "MIP"); break; + case 0x0033: sprintf(buffer, "ECOMCNTL"); break; + case 0x0034: sprintf(buffer, "ANASTAT"); break; + case 0x0039: sprintf(buffer, "BRK1"); break; + case 0x003a: sprintf(buffer, "BRK2"); break; + case 0x4000: sprintf(buffer, "IN0P"); break; + case 0x4001: sprintf(buffer, "IN1P"); break; + case 0x4002: sprintf(buffer, "OUTP"); break; + default: sprintf(buffer, "CR %04X", reg); + } + + return buffer; +} + +static char* format_vector_op(UINT32 op, UINT32 imm32) +{ + static char buffer[256]; + static char dest[64]; + char *b = buffer; + + int rd = (op >> 27) & 0x1f; + int rs = (op >> 22) & 0x1f; + int src1 = (op & 0x1f); + int subop = (op >> 12) & 0xff; + int vector_ls_bits = (((op >> 9) & 0x3) << 1) | ((op >> 6) & 1); + + int p1 = (op >> 5) & 1; + int pd2 = (op >> 7) & 1; + int pd4 = (op >> 7) & 3; + + int z = op & (1 << 8); + + int acc = (((op >> 16) << 1) & 2) | ((op >> 11) & 1); + bool regdest = (op & (1 << 10)) == 0 && (op & (1 << 6)) == 0; + + // accumulator or register destination + if (regdest) + sprintf(dest, "R%d", rd); + else + sprintf(dest, "A%d", acc); + + // base op + switch (subop) + { + case 0xc0: b += sprintf(b, "vadd.%s%s R%d, R%d, R%d", FLOATOP_PRECISION[p1], FLOATOP_PRECISION[pd2], src1, rs, rs); break; + case 0xc1: b += sprintf(b, "vadd.%s%s 0x%08X, R%d, R%d", FLOATOP_PRECISION[p1], FLOATOP_PRECISION[pd2], imm32, rs, rs); break; + case 0xc2: b += sprintf(b, "vsub.%s%s R%d, R%d, R%d", FLOATOP_PRECISION[p1], FLOATOP_PRECISION[pd2], rs, src1, rs); break; + case 0xc3: b += sprintf(b, "vsub.%s%s R%d, 0x%08X, R%d", FLOATOP_PRECISION[p1], FLOATOP_PRECISION[pd2], rs, imm32, rs); break; + case 0xc4: b += sprintf(b, "vmpy.%s%s R%d, R%d, R%d", FLOATOP_PRECISION[p1], FLOATOP_PRECISION[pd2], src1, rs, rs); break; + case 0xc5: b += sprintf(b, "vmpy.%s%s 0x%08X, R%d, R%d", FLOATOP_PRECISION[p1], FLOATOP_PRECISION[pd2], imm32, rs, rs); break; + + case 0xd6: case 0xc6: + b += sprintf(b, "vmsub.s%s R%d, %s, R%d", FLOATOP_PRECISION[pd2], src1, z ? "0" : ACC_SEL[acc], rs); + break; + case 0xd7: case 0xc7: + b += sprintf(b, "vmsub.s%s 0x%08X, %s, R%d", FLOATOP_PRECISION[pd2], imm32, z ? "0" : ACC_SEL[acc], rs); + break; + case 0xd8: case 0xc8: + b += sprintf(b, "vrnd.%s%s R%d, R%d", FLOATOP_PRECISION[p1], FLOATOP_PRECISION[pd4], src1, rs); + break; + case 0xd9: case 0xc9: + b += sprintf(b, "vrnd.%s%s 0x%08X, R%d", FLOATOP_PRECISION[p1], FLOATOP_PRECISION[pd4], imm32, rs); + break; + + case 0xca: b += sprintf(b, "vrnd.%s%s R%d, R%d", FLOATOP_PRECISION[2 + p1], FLOATOP_PRECISION[pd2],src1, rs); break; + case 0xcb: b += sprintf(b, "vrnd.%s%s 0x%08X, R%d", FLOATOP_PRECISION[2 + p1], FLOATOP_PRECISION[pd2], imm32, rs); break; + + case 0xcc: case 0xdc: + b += sprintf(b, "vmac.ss%s R%d, R%d, %s, %s", FLOATOP_PRECISION[(op >> 9) & 1], src1, rs, z ? "0" : ACC_SEL[acc], (regdest && rd == 0) ? ACC_SEL[acc] : dest); + break; + case 0xcd: case 0xdd: + b += sprintf(b, "vmac.ss%s 0x%08X, R%d, %s, %s", FLOATOP_PRECISION[(op >> 9) & 1], imm32, rs, z ? "0" : ACC_SEL[acc], (regdest && rd == 0) ? ACC_SEL[acc] : dest); + break; + case 0xce: case 0xde: + b += sprintf(b, "vmsc.ss%s R%d, R%d, %s, %s", FLOATOP_PRECISION[(op >> 9) & 1], src1, rs, z ? "0" : ACC_SEL[acc], (regdest && rd == 0) ? ACC_SEL[acc] : dest); + break; + case 0xcf: case 0xdf: + b += sprintf(b, "vmsc.ss%s 0x%08X, R%d, %s, %s", FLOATOP_PRECISION[(op >> 9) & 1], imm32, rs, z ? "0" : ACC_SEL[acc], (regdest && rd == 0) ? ACC_SEL[acc] : dest); + break; + + default: b += sprintf(b, "?"); break; + } + + // align the line end + int len = strlen(buffer); + if (len < 30) + { + for (int i=0; i < (30-len); i++) + { + b += sprintf(b, " "); + } + } + + // optional load/store op + switch (vector_ls_bits) + { + case 0x01: b += sprintf(b, "|| vst.s R%d", rd); break; + case 0x03: b += sprintf(b, "|| vst.d R%d", rd); break; + case 0x04: b += sprintf(b, "|| vld0.s R%d", rd); break; + case 0x05: b += sprintf(b, "|| vld1.s R%d", rd); break; + case 0x06: b += sprintf(b, "|| vld0.d R%d", rd); break; + case 0x07: b += sprintf(b, "|| vld1.d R%d", rd); break; + } + + return buffer; +} + +static offs_t tms32082_disasm_mp(char *buffer, offs_t pc, const UINT8 *oprom) +{ + output = buffer; + opdata = oprom; + opbytes = 0; + UINT32 flags = 0; + + UINT32 op = fetch(); + + int rd = (op >> 27) & 0x1f; + int link = rd; + int bitnum = rd ^ 0x1f; + int rs = (op >> 22) & 0x1f; + int endmask = (op >> 5) & 0x1f; + int rotate = (op & 0x1f); + int src1 = rotate; + UINT32 uimm15 = op & 0x7fff; + + switch ((op >> 20) & 3) + { + case 0: case 1: case 2: // Short immediate + { + int subop = (op >> 15) & 0x7f; + int m = op & (1 << 17) ? 0 : 1; + + switch (subop) + { + case 0x00: print("illop0 "); break; + case 0x01: print("trap %d", UIMM15(uimm15)); break; + case 0x02: print("cmnd 0x%04X", UIMM15(uimm15)); break; + case 0x04: print("rdcr %s, R%d", get_creg_name(UIMM15(uimm15)), rd); break; + case 0x05: print("swcr R%d, %s, R%d", rd, get_creg_name(UIMM15(uimm15)), rs); break; + case 0x06: print("brcr %s", get_creg_name(UIMM15(uimm15))); break; + case 0x08: print("shift%s.dz %d, %d, R%d, R%d", (op & (1 << 10)) ? "r" : "l", rotate, endmask, rs, rd); break; + case 0x09: print("shift%s.dm %d, %d, R%d, R%d", (op & (1 << 10)) ? "r" : "l", rotate, endmask, rs, rd); break; + case 0x0a: print("shift%s.ds %d, %d, R%d, R%d", (op & (1 << 10)) ? "r" : "l", rotate, endmask, rs, rd); break; + case 0x0b: print("shift%s.ez %d, %d, R%d, R%d", (op & (1 << 10)) ? "r" : "l", rotate, endmask, rs, rd); break; + case 0x0c: print("shift%s.em %d, %d, R%d, R%d", (op & (1 << 10)) ? "r" : "l", rotate, endmask, rs, rd); break; + case 0x0d: print("shift%s.es %d, %d, R%d, R%d", (op & (1 << 10)) ? "r" : "l", rotate, endmask, rs, rd); break; + case 0x0e: print("shift%s.iz %d, %d, R%d, R%d", (op & (1 << 10)) ? "r" : "l", rotate, endmask, rs, rd); break; + case 0x0f: print("shift%s.im %d, %d, R%d, R%d", (op & (1 << 10)) ? "r" : "l", rotate, endmask, rs, rd); break; + case 0x11: print("and 0x%04X, R%d, R%d", UIMM15(uimm15), rs, rd); break; + case 0x12: print("and.tf 0x%04X, R%d, R%d", UIMM15(uimm15), rs, rd); break; + case 0x14: print("and.ft 0x%04X, R%d, R%d", UIMM15(uimm15), rs, rd); break; + case 0x16: print("xor 0x%04X, R%d, R%d", UIMM15(uimm15), rs, rd); break; + case 0x17: print("or 0x%04X, R%d, R%d", UIMM15(uimm15), rs, rd); break; + case 0x18: print("and.ff 0x%04X, R%d, R%d", UIMM15(uimm15), rs, rd); break; + case 0x19: print("xnor 0x%04X, R%d, R%d", UIMM15(uimm15), rs, rd); break; + case 0x1b: print("or.tf 0x%04X, R%d, R%d", UIMM15(uimm15), rs, rd); break; + case 0x1d: print("or.ft 0x%04X, R%d, R%d", UIMM15(uimm15), rs, rd); break; + case 0x1e: print("or.ff 0x%04X, R%d, R%d", UIMM15(uimm15), rs, rd); break; + + case 0x24: case 0x20: + print("ld.b 0x%04X(R%d%s), R%d", UIMM15(uimm15), rs, MEMOP_M[m], rd); + break; + case 0x25: case 0x21: + print("ld.h 0x%04X(R%d%s), R%d", UIMM15(uimm15), rs, MEMOP_M[m], rd); + break; + case 0x26: case 0x22: + print("ld 0x%04X(R%d%s), R%d", UIMM15(uimm15), rs, MEMOP_M[m], rd); + break; + case 0x27: case 0x23: + print("ld.d 0x%04X(R%d%s), R%d", UIMM15(uimm15), rs, MEMOP_M[m], rd); + break; + case 0x2c: case 0x28: + print("ld.ub 0x%04X(R%d%s), R%d", UIMM15(uimm15), rs, MEMOP_M[m], rd); + break; + case 0x2d: case 0x29: + print("ld.uh 0x%04X(R%d%s), R%d", UIMM15(uimm15), rs, MEMOP_M[m], rd); + break; + + case 0x34: case 0x30: + print("st.b R%d, 0x%04X(R%d%s)", rd, UIMM15(uimm15), rs, MEMOP_M[m]); + break; + case 0x35: case 0x31: + print("st.h R%d, 0x%04X(R%d%s)", rd, UIMM15(uimm15), rs, MEMOP_M[m]); + break; + case 0x36: case 0x32: + print("st R%d, 0x%04X(R%d%s)", rd, UIMM15(uimm15), rs, MEMOP_M[m]); + break; + case 0x37: case 0x33: + print("st.d R%d, 0x%04X(R%d%s)", rd, UIMM15(uimm15), rs, MEMOP_M[m]); + break; + + case 0x40: print("bsr 0x%08X, R%d", pc + (SIMM15(uimm15) * 4), link); break; + case 0x41: print("bsr.a 0x%08X, R%d", pc + (SIMM15(uimm15) * 4), link); break; + case 0x44: print("jsr 0x%04X(R%d), R%d", SIMM15(uimm15), rs, link); break; + case 0x45: print("jsr.a 0x%04X(R%d), R%d", SIMM15(uimm15), rs, link); break; + case 0x48: print("bbz 0x%08X, R%d, %s (%d)", pc + (SIMM15(uimm15) * 4), rs, BITNUM_CONDITION[bitnum], bitnum); break; + case 0x49: print("bbz.a 0x%08X, R%d, %s (%d)", pc + (SIMM15(uimm15) * 4), rs, BITNUM_CONDITION[bitnum], bitnum); break; + case 0x4a: print("bbo 0x%08X, R%d, %s (%d)", pc + (SIMM15(uimm15) * 4), rs, BITNUM_CONDITION[bitnum], bitnum); break; + case 0x4b: print("bbo.a 0x%08X, R%d, %s (%d)", pc + (SIMM15(uimm15) * 4), rs, BITNUM_CONDITION[bitnum], bitnum); break; + case 0x4c: print("bcnd 0x%08X, R%d, %s", pc + (SIMM15(uimm15) * 4), rs, BCND_CONDITION[rd]); break; + case 0x4d: print("bcnd.a 0x%08X, R%d, %s", pc + (SIMM15(uimm15) * 4), rs, BCND_CONDITION[rd]); break; + case 0x50: print("cmp 0x%08X, R%d, R%d", SIMM15(uimm15), rs, rd); break; + case 0x58: print("add 0x%08X, R%d, R%d", SIMM15(uimm15), rs, rd); break; + case 0x59: print("addu 0x%08X, R%d, R%d", SIMM15(uimm15), rs, rd); break; + case 0x5a: print("sub 0x%08X, R%d, R%d", SIMM15(uimm15), rs, rd); break; + case 0x5b: print("subu 0x%08X, R%d, R%d", SIMM15(uimm15), rs, rd); break; + + default: print("?"); break; + } + break; + } + + case 3: // Register / Long immediate + { + int subop = (op >> 12) & 0xff; + + UINT32 imm32 = 0; + if (op & (1 << 12)) // fetch 32-bit immediate if needed + imm32 = fetch(); + + int m = op & (1 << 15) ? 0 : 1; + int s = op & (1 << 11) ? 0 : 1; + + int p1 = (op >> 5) & 3; + int p2 = (op >> 7) & 3; + int pd = (op >> 9) & 3; + + int rndmode = (op >> 7) & 3; + + + switch (subop) + { + case 0x02: print("trap %d", src1); break; + case 0x03: print("trap %d", imm32); break; + case 0x04: print("cmnd R%d", src1); break; + case 0x05: print("cmnd 0x%08X", imm32); break; + case 0x08: print("rdcr R%d, R%d,", src1, rd); break; + case 0x09: print("rdcr %s, R%d", get_creg_name(imm32), rd); break; + case 0x0a: print("swcr R%d, R%d, R%d", rd, src1, rs); break; + case 0x0b: print("swcr R%d, %s, R%d", rd, get_creg_name(imm32), rs); break; + case 0x0c: print("brcr R%d", src1); break; + case 0x0d: print("brcr %s", get_creg_name(imm32)); break; + + case 0x10: print("shift%s.dz %d, %d, R%d, R%d", (op & (1 << 10)) ? "r" : "l", rotate, endmask, rs, rd); break; + case 0x12: print("shift%s.dm %d, %d, R%d, R%d", (op & (1 << 10)) ? "r" : "l", rotate, endmask, rs, rd); break; + case 0x14: print("shift%s.ds %d, %d, R%d, R%d", (op & (1 << 10)) ? "r" : "l", rotate, endmask, rs, rd); break; + case 0x16: print("shift%s.ez %d, %d, R%d, R%d", (op & (1 << 10)) ? "r" : "l", rotate, endmask, rs, rd); break; + case 0x18: print("shift%s.em %d, %d, R%d, R%d", (op & (1 << 10)) ? "r" : "l", rotate, endmask, rs, rd); break; + case 0x1a: print("shift%s.es %d, %d, R%d, R%d", (op & (1 << 10)) ? "r" : "l", rotate, endmask, rs, rd); break; + case 0x1c: print("shift%s.iz %d, %d, R%d, R%d", (op & (1 << 10)) ? "r" : "l", rotate, endmask, rs, rd); break; + case 0x1e: print("shift%s.im %d, %d, R%d, R%d", (op & (1 << 10)) ? "r" : "l", rotate, endmask, rs, rd); break; + + case 0x22: print("and R%d, R%d, R%d", src1, rs, rd); break; + case 0x23: print("and 0x%08X, R%d, R%d", imm32, rs, rd); break; + case 0x24: print("and.tf R%d, R%d, R%d", src1, rs, rd); break; + case 0x25: print("and.tf 0x%08X, R%d, R%d", imm32, rs, rd); break; + case 0x28: print("and.ft R%d, R%d, R%d", src1, rs, rd); break; + case 0x29: print("and.ft 0x%08X, R%d, R%d", imm32, rs, rd); break; + case 0x2c: print("xor R%d, R%d, R%d", src1, rs, rd); break; + case 0x2d: print("xor 0x%08X, R%d, R%d", imm32, rs, rd); break; + case 0x2e: print("or R%d, R%d, R%d", src1, rs, rd); break; + case 0x2f: print("or 0x%08X, R%d, R%d", imm32, rs, rd); break; + case 0x30: print("and.ff R%d, R%d, R%d", src1, rs, rd); break; + case 0x31: print("and.ff 0x%08X, R%d, R%d", imm32, rs, rd); break; + case 0x32: print("xnor R%d, R%d, R%d", src1, rs, rd); break; + case 0x33: print("xnor 0x%08X, R%d, R%d", imm32, rs, rd); break; + case 0x36: print("or.tf R%d, R%d, R%d", src1, rs, rd); break; + case 0x37: print("or.tf 0x%08X, R%d, R%d", imm32, rs, rd); break; + case 0x3a: print("or.ft R%d, R%d, R%d", src1, rs, rd); break; + case 0x3b: print("or.ft 0x%08X, R%d, R%d", imm32, rs, rd); break; + case 0x3c: print("or.ff R%d, R%d, R%d", src1, rs, rd); break; + case 0x3d: print("or.ff 0x%08X, R%d, R%d", imm32, rs, rd); break; + + case 0x48: case 0x40: + print("ld.b R%d%s(R%d%s), R%d", src1, MEMOP_S[s], rs, MEMOP_M[m], rd); + break; + case 0x49: case 0x41: + print("ld.b 0x%08X%s(R%d%s), R%d", imm32, MEMOP_S[s], rs, MEMOP_M[m], rd); + break; + case 0x4a: case 0x42: + print("ld.h R%d%s(R%d%s), R%d", src1, MEMOP_S[s], rs, MEMOP_M[m], rd); + break; + case 0x4b: case 0x43: + print("ld.h 0x%08X%s(R%d%s), R%d", imm32, MEMOP_S[s], rs, MEMOP_M[m], rd); + break; + case 0x4c: case 0x44: + print("ld R%d%s(R%d%s), R%d", src1, MEMOP_S[s], rs, MEMOP_M[m], rd); + break; + case 0x4d: case 0x45: + print("ld 0x%08X%s(R%d%s), R%d", imm32, MEMOP_S[s], rs,MEMOP_M[m], rd); + break; + case 0x4e: case 0x46: + print("ld.d R%d%s(R%d%s), R%d", src1, MEMOP_S[s], rs, MEMOP_M[m], rd); + break; + case 0x4f: case 0x47: + print("ld.d 0x%08X%s(R%d%s), R%d", imm32, MEMOP_S[s], rs, MEMOP_M[m], rd); + break; + case 0x58: case 0x50: + print("ld.ub R%d%s(R%d%s), R%d", src1, MEMOP_S[s], rs, MEMOP_M[m], rd); + break; + case 0x59: case 0x51: + print("ld.ub 0x%08X%s(R%d%s), R%d", imm32, MEMOP_S[s], rs, MEMOP_M[m], rd); + break; + case 0x5a: case 0x52: + print("ld.uh R%d%s(R%d%s), R%d", src1, MEMOP_S[s], rs, MEMOP_M[m], rd); + break; + case 0x5b: case 0x53: + print("ld.uh 0x%08X%s(R%d%s), R%d", imm32, MEMOP_S[s], rs, MEMOP_M[m], rd); + break; + + case 0x68: case 0x60: + print("st.b R%d, R%d%s(R%d%s)", rd, src1, MEMOP_S[s], rs, MEMOP_M[m]); + break; + case 0x69: case 0x61: + print("st.b R%d, 0x%08X%s(R%d%s)", rd, imm32, MEMOP_S[s], rs, MEMOP_M[m]); + break; + case 0x6a: case 0x62: + print("st.h R%d, R%d%s(R%d%s)", rd, src1, MEMOP_S[s], rs, MEMOP_M[m]); + break; + case 0x6b: case 0x63: + print("st.h R%d, 0x%08X%s(R%d%s)", rd, imm32, MEMOP_S[s], rs, MEMOP_M[m]); + break; + case 0x6c: case 0x64: + print("st R%d, R%d%s(R%d%s)", rd, src1, MEMOP_S[s], rs, MEMOP_M[m]); + break; + case 0x6d: case 0x65: + print("st R%d, 0x%08X%s(R%d%s)", rd, imm32, MEMOP_S[s], rs, MEMOP_M[m]); + break; + case 0x6e: case 0x66: + print("st.d R%d, R%d%s(R%d%s)", rd, src1, MEMOP_S[s], rs, MEMOP_M[m]); + break; + case 0x6f: case 0x67: + print("st.d R%d, 0x%08X%s(R%d%s)", rd, imm32, MEMOP_S[s], rs, MEMOP_M[m]); + break; + + case 0x78: case 0x70: + print("dcache R%d(R%d)", src1, rs); + break; + case 0x79: case 0x71: + print("dcache 0x%08X(R%d)", imm32, rs); + break; + + case 0x80: print("bsr R%d, R%d", src1, link); break; + case 0x81: print("bsr 0x%08X, R%d", imm32, link); break; + case 0x82: print("bsr.a R%d, R%d", src1, rd); break; + case 0x83: print("bsr.a 0x%08X, R%d", imm32, link); break; + case 0x88: print("jsr R%d, R%d", src1, link); break; + case 0x89: print("jsr 0x%08X, R%d", imm32, link); break; + case 0x8a: print("jsr.a R%d, R%d", src1, link); break; + case 0x8b: print("jsr.a 0x%08X, R%d", imm32, link); break; + case 0x90: print("bbz R%d, R%d, %s (%d)", src1, rs, BITNUM_CONDITION[bitnum], bitnum); break; + case 0x91: print("bbz 0x%08X, R%d, %s (%d)", imm32, rs, BITNUM_CONDITION[bitnum], bitnum); break; + case 0x92: print("bbz.a R%d, R%d, %s (%d)", src1, rs, BITNUM_CONDITION[bitnum], bitnum); break; + case 0x93: print("bbz.a 0x%08X, R%d, %s (%d)", imm32, rs, BITNUM_CONDITION[bitnum], bitnum); break; + case 0x94: print("bbo R%d, R%d, %s (%d)", src1, rs, BITNUM_CONDITION[bitnum], bitnum); break; + case 0x95: print("bbo 0x%08X, R%d, %s (%d)", imm32, rs, BITNUM_CONDITION[bitnum], bitnum); break; + case 0x96: print("bbo.a R%d, R%d, %s (%d)", src1, rs, BITNUM_CONDITION[bitnum], bitnum); break; + case 0x97: print("bbo.a 0x%08X, R%d, %s (%d)", imm32, rs, BITNUM_CONDITION[bitnum], bitnum); break; + case 0x98: print("bcnd R%d, R%d, %s", src1, rs, BCND_CONDITION[rd]); break; + case 0x99: print("bcnd 0x%08X, R%d, %s", imm32, rs, BCND_CONDITION[rd]); break; + case 0x9a: print("bcnd.a R%d, R%d, %s", src1, rs, BCND_CONDITION[rd]); break; + case 0x9b: print("bcnd.a 0x%08X, R%d, %s", imm32, rs, BCND_CONDITION[rd]); break; + case 0xa0: print("cmp R%d, R%d, R%d", src1, rs, rd); break; + case 0xa1: print("cmp 0x%08X, R%d, R%d", imm32, rs, rd); break; + case 0xb0: print("add R%d, R%d, R%d", src1, rs, rd); break; + case 0xb1: print("add 0x%08X, R%d, R%d", imm32, rs, rd); break; + case 0xb2: print("addu R%d, R%d, R%d", src1, rs, rd); break; + case 0xb3: print("addu 0x%08X, R%d, R%d", imm32, rs, rd); break; + case 0xb4: print("sub R%d, R%d, R%d", src1, rs, rd); break; + case 0xb5: print("sub 0x%08X, R%d, R%d", imm32, rs, rd); break; + case 0xb6: print("subu R%d, R%d, R%d", src1, rs, rd); break; + case 0xb7: print("subu 0x%08X, R%d, R%d", imm32, rs, rd); break; + + case 0xc0: case 0xc1: case 0xc2: case 0xc3: case 0xc4: case 0xc5: + case 0xc6: case 0xd6: case 0xc7: case 0xd7: case 0xc8: case 0xd8: case 0xc9: case 0xd9: + case 0xca: case 0xcb: case 0xcc: case 0xdc: case 0xcd: case 0xdd: case 0xce: case 0xde: + case 0xcf: case 0xdf: + { + print("%s", format_vector_op(op, imm32)); + break; + } + + case 0xe0: print("fadd.%s%s%s R%d, R%d, R%d", FLOATOP_PRECISION[p1], FLOATOP_PRECISION[p2], FLOATOP_PRECISION[pd], src1, rs, rd); break; + case 0xe1: print("fadd.%s%s%s 0x%08X, R%d, R%d", FLOATOP_PRECISION[p1], FLOATOP_PRECISION[p2], FLOATOP_PRECISION[pd], imm32, rs, rd); break; + case 0xe2: print("fsub.%s%s%s R%d, R%d, R%d", FLOATOP_PRECISION[p1], FLOATOP_PRECISION[p2], FLOATOP_PRECISION[pd], src1, rs, rd); break; + case 0xe3: print("fsub.%s%s%s 0x%08X, R%d, R%d", FLOATOP_PRECISION[p1], FLOATOP_PRECISION[p2], FLOATOP_PRECISION[pd], imm32, rs, rd); break; + case 0xe4: print("fmpy.%s%s%s R%d, R%d, R%d", FLOATOP_PRECISION[p1], FLOATOP_PRECISION[p2], FLOATOP_PRECISION[pd], src1, rs, rd); break; + case 0xe5: print("fmpy.%s%s%s 0x%08X, R%d, R%d", FLOATOP_PRECISION[p1], FLOATOP_PRECISION[p2], FLOATOP_PRECISION[pd], imm32, rs, rd); break; + case 0xe6: print("fdiv.%s%s%s R%d, R%d, R%d", FLOATOP_PRECISION[p1], FLOATOP_PRECISION[p2], FLOATOP_PRECISION[pd], src1, rs, rd); break; + case 0xe7: print("fdiv.%s%s%s 0x%08X, R%d, R%d", FLOATOP_PRECISION[p1], FLOATOP_PRECISION[p2], FLOATOP_PRECISION[pd], imm32, rs, rd); break; + case 0xe8: print("frnd%s.%s%s R%d, R%d", FLOATOP_ROUND[rndmode], FLOATOP_PRECISION[p1], FLOATOP_PRECISION[pd], src1, rd); break; + case 0xe9: print("frnd%s.%s%s 0x%08X, R%d", FLOATOP_ROUND[rndmode], FLOATOP_PRECISION[p1], FLOATOP_PRECISION[pd], imm32, rd); break; + case 0xea: print("fcmp R%d, R%d, R%d", src1, rs, rd); break; + case 0xeb: print("fcmp 0x%08X, R%d, R%d", imm32, rs, rd); break; + case 0xee: print("fsqrt R%d, R%d", src1, rd); break; + case 0xef: print("fsqrt 0x%08X, R%d", imm32, rd); break; + case 0xf0: print("lmo R%d, R%d", rs, rd); break; + case 0xf2: print("rmo R%d, R%d", rs, rd); break; + case 0xfc: print("estop "); break; + + case 0xfe: case 0xff: + print("illopF "); + break; + + default: print("?"); break; + } + break; + } + } + + return opbytes | flags | DASMFLAG_SUPPORTED; +} + +CPU_DISASSEMBLE(tms32082_mp) +{ + return tms32082_disasm_mp(buffer, pc, oprom); +} diff --git a/src/devices/cpu/tms32082/dis_pp.c b/src/devices/cpu/tms32082/dis_pp.c new file mode 100644 index 00000000000..54f8a6d7004 --- /dev/null +++ b/src/devices/cpu/tms32082/dis_pp.c @@ -0,0 +1,714 @@ +// license:BSD-3-Clause +// copyright-holders:Ville Linde +// TMS32082 PP Disassembler + +#include "emu.h" + + +static const char *REG_NAMES[128] = +{ + // 0 - 15 + "a0", "a1", "a2", "a3", "a4", "???", "a6", "a7", + "a8", "a9", "a10", "a11", "a12", "???", "a14", "a15", + // 16 - 31 + "x0", "x1", "x2", "???", "???", "???", "???", "???", + "x8", "x9", "x10", "???", "???", "???", "???", "???", + // 32 - 47 + "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", + "???", "sr", "mf", "???", "???", "???", "???", "???", + // 48 - 63 + "???", "???", "???", "???", "???", "???", "???", "???", + "pc/call", "ipa/br", "ipe", "iprs", "inten", "intflg", "comm", "lctl", + // 64 - 79 + "???", "???", "???", "???", "???", "???", "???", "???", + "???", "???", "???", "???", "???", "???", "???", "???", + // 80 - 95 + "???", "???", "???", "???", "???", "???", "???", "???", + "???", "???", "???", "???", "???", "???", "???", "???", + // 96 - 111 + "lc0", "lc1", "lc2", "???", "lr0", "lr1", "lr2", "???", + "lrse0", "lrse1", "lrse2", "???", "lrs0", "lrs1", "lrs2", "???", + // 112 - 127 + "ls0", "ls1", "ls2", "???", "le0", "le1", "le2", "???", + "???", "???", "???", "???", "tag0", "tag1", "tag2", "tag3" +}; + +static const char *CONDITION_CODES[16] = +{ + "", "[p] ", "[ls] ", "[hi] ", + "[lt] ", "[le] ", "[ge] ", "[gt] ", + "[hs] ", "[lo] ", "[eq] ", "[ne] ", + "[v] ", "[nv] ", "[n] ", "[nn] " +}; + +static const char *TRANSFER_SIZE[4] = +{ + "b:", "h:", "w:", "" +}; + + +static char *output; + +static void ATTR_PRINTF(1,2) print(const char *fmt, ...) +{ + va_list vl; + + va_start(vl, fmt); + output += vsprintf(output, fmt, vl); + va_end(vl); +} + +static char *format_address_mode(int mode, int areg, int s, int limx) +{ + static char buffer[64]; + + memset(buffer, 0, sizeof(char)*64); + + switch (mode) + { + case 0x4: sprintf(buffer, "*(a%d++=x%d)", areg, limx); break; + case 0x5: sprintf(buffer, "*(a%d--=x%d)", areg, limx); break; + case 0x6: sprintf(buffer, "*(a%d++0x%04X)", areg, limx); break; + case 0x7: sprintf(buffer, "*(a%d--0x%04X)", areg, limx); break; + case 0x8: sprintf(buffer, "*(a%d+x%d)", areg, limx); break; + case 0x9: sprintf(buffer, "*(a%d-x%d)", areg, limx); break; + case 0xa: sprintf(buffer, "*(a%d+0x%04X)", areg, limx); break; + case 0xb: sprintf(buffer, "*(a%d-0x%04X)", areg, limx); break; + case 0xc: sprintf(buffer, "*(a%d+=x%d)", areg, limx); break; + case 0xd: sprintf(buffer, "*(a%d-=x%d)", areg, limx); break; + case 0xe: sprintf(buffer, "*(a%d+=0x%04X)", areg, limx); break; + case 0xf: sprintf(buffer, "*(a%d-=0x%04X)", areg, limx); break; + } + + return buffer; +} + +static void format_transfer(UINT64 op) +{ + char buffer[128]; + char *b = buffer; + int lmode = (op >> 35) & 0xf; + int gmode = (op >> 13) & 0xf; + + bool is_nop = false; + + memset(buffer, 0, sizeof(char)*128); + + switch (lmode) + { + case 0x0: + case 0x1: + case 0x2: + case 0x3: + { + int cond = (op >> 32) & 0xf; + + switch (gmode) + { + case 0x00: // Format 7: Conditional DU || Conditional Move + { + int dstbank = (op >> 18) & 0xf; + int srcbank = (op >> 6) & 0xf; + int src = (op >> 10) & 0x7; + int dst = (op >> 3) & 0x7; + + int dreg = (dstbank << 3) | dst; + int sreg = (srcbank << 3) | src; + + b += sprintf(b, "%s", CONDITION_CODES[cond]); + b += sprintf(b, "%s = %s", REG_NAMES[dreg], REG_NAMES[sreg]); + break; + } + case 0x01: // Format 8: Conditional DU ||Conditional Field Move + { + int dstbank = (op >> 18) & 0xf; + int src = (op >> 10) & 0x7; + int dst = (op >> 3) & 0x7; + int itm = (op >> 22) & 0x3; + int size = (op >> 7) & 0x3; + // int e = (op & (1 << 9)); + + int dreg = (dstbank << 3) | dst; + int sreg = (4 << 3) | src; + + b += sprintf(b, "%s", CONDITION_CODES[cond]); + b += sprintf(b, "%s = [%s%d]%s", REG_NAMES[dreg], TRANSFER_SIZE[size], itm, REG_NAMES[sreg]); + break; + } + case 0x02: case 0x03: // Format 10: Conditional Non-D Data Unit + { + int as1bank = (op >> 6) & 0xf; + int adstbank = (op >> 18) & 0xf; + int src = (op >> 45) & 0x7; + int dst = (op >> 48) & 0x7; + + int dreg = (adstbank << 3) | dst; + int sreg = (as1bank << 3) | src; + + if (dreg == sreg) + { + is_nop = true; + } + else + { + b += sprintf(b, "%s", CONDITION_CODES[cond]); + b += sprintf(b, "%s = %s", REG_NAMES[dreg], REG_NAMES[sreg]); + } + break; + } + default: + { + if (op & 0x4) // Format 9: Conditional DU || Conditional Global + { + int bank = (op >> 18) & 0xf; + int le = ((op >> 16) & 2) | ((op >> 9) & 1); + int size = (op >> 7) & 0x3; + int s = (op & (1 << 6)); + int reg = (op >> 10) & 0x7; + int ga = (op >> 3) & 0x7; + int gimx = (op >> 22) & 0x7; + + int greg = (bank << 3) | reg; + + b += sprintf(b, "%s", CONDITION_CODES[cond]); + + switch (le) + { + case 0: b += sprintf(b, "&%s%s = %s", TRANSFER_SIZE[size], format_address_mode(gmode, ga, s, gimx), REG_NAMES[greg]); break; + case 1: b += sprintf(b, "%s = %s", REG_NAMES[greg], format_address_mode(gmode, ga, s, gimx)); break; + case 2: b += sprintf(b, "%s = &%s%s", REG_NAMES[greg], TRANSFER_SIZE[size], format_address_mode(gmode, ga, s, gimx)); break; + case 3: b += sprintf(b, "%s = &%s%s", REG_NAMES[greg], TRANSFER_SIZE[size], format_address_mode(gmode, ga, s, gimx)); break; + } + } + else // Format 5: Global (Long Offset) + { + int bank = (op >> 18) & 0xf; + int le = ((op >> 16) & 2) | ((op >> 9) & 1); + int size = (op >> 7) & 0x3; + int s = (op & (1 << 6)); + int offset = (op >> 22) & 0x7fff; + int reg = (op >> 10) & 0x7; + //int grm = op & 0x3; + int ga = (op >> 3) & 0x7; + + int greg = (bank << 3) | reg; + + // sign extend offset + if (s && (offset & 0x4000)) + offset |= 0xffffc000; + + switch (le) + { + case 0: b += sprintf(b, "&%s%s = %s", TRANSFER_SIZE[size], format_address_mode(gmode, ga, s, offset), REG_NAMES[greg]); break; + case 1: b += sprintf(b, "%s = %s", REG_NAMES[greg], format_address_mode(gmode, ga, s, offset)); break; + case 2: b += sprintf(b, "%s = &%s%s", REG_NAMES[greg], TRANSFER_SIZE[size], format_address_mode(gmode, ga, s, offset)); break; + case 3: b += sprintf(b, "%s = &%s%s", REG_NAMES[greg], TRANSFER_SIZE[size], format_address_mode(gmode, ga, s, offset)); break; + } + } + break; + } + } + break; + } + + default: + { + int mode = gmode | ((op & (1 << 24)) ? 0x10 : 0); + + switch (mode) + { + case 0x00: // Format 2: Move || Local + { + b += sprintf(b, "move||local "); + break; + } + case 0x01: // Format 3: Field Move || Local + { + b += sprintf(b, "field move||local "); + break; + } + case 0x02: case 0x03: // Format 6: Non-D DU || Local + { + int d = (op >> 32) & 0x7; + int s = (op & (1 << 28)); + int size = (op >> 29) & 0x3; + int le = ((op >> 16) & 2) | ((op >> 31) & 1); + int la = (op >> 25) & 0x7; + int limx = op & 0x7; + + int reg = (4 << 3) | d; + + switch (le) + { + case 0: b += sprintf(b, "&%s%s = %s", TRANSFER_SIZE[size], format_address_mode(lmode, la, s, limx), REG_NAMES[reg]); break; + case 1: b += sprintf(b, "%s = %s", REG_NAMES[reg], format_address_mode(lmode, la, s, limx)); break; + case 2: b += sprintf(b, "%s = &%s%s", REG_NAMES[reg], TRANSFER_SIZE[size], format_address_mode(lmode, la, s, limx)); break; + case 3: b += sprintf(b, "%s = &%s%s", REG_NAMES[reg], TRANSFER_SIZE[size], format_address_mode(lmode, la, s, limx)); break; + } + break; + } + case 0x10: case 0x11: case 0x12: case 0x13: // Format 4: Local (Long Offset) + { + int d = (op >> 32) & 0x7; + int bank = (op >> 18) & 0xf; + int s = (op & (1 << 28)); + int size = (op >> 29) & 0x3; + int le = ((op >> 16) & 2) | ((op >> 31) & 1); + int la = (op >> 25) & 0x7; + + int reg = (bank << 3) | d; + + UINT16 offset = 0; + if (s) + { + offset = op & 0x7fff; + if (offset & 0x4000) + offset |= 0xc000; + } + else + { + offset = op & 0x7fff; + } + + switch (le) + { + case 0: b += sprintf(b, "&%s%s = %s", TRANSFER_SIZE[size], format_address_mode(lmode, la, s, offset), REG_NAMES[reg]); break; + case 1: b += sprintf(b, "%s = %s", REG_NAMES[reg], format_address_mode(lmode, la, s, offset)); break; + case 2: b += sprintf(b, "%s = &%s%s", REG_NAMES[reg], TRANSFER_SIZE[size], format_address_mode(lmode, la, s, offset)); break; + case 3: b += sprintf(b, "%s = &%s%s", REG_NAMES[reg], TRANSFER_SIZE[size], format_address_mode(lmode, la, s, offset)); break; + } + break; + } + case 0x14: case 0x15: case 0x16: case 0x17: // Format 1: Double Parallel + case 0x18: case 0x19: case 0x1a: case 0x1b: + case 0x1c: case 0x1d: case 0x1e: case 0x1f: + { + int la = (op >> 25) & 0x7; + int ga = (op >> 3) & 0x7; + int local_imx = op & 0x7; + int global_imx = (op >> 22) & 0x7; + int local_s = (op & (1 << 28)); + int global_s = (op & (1 << 6)); + int local_size = (op >> 29) & 0x3; + int global_size = (op >> 7) & 0x3; + int local_le = ((op >> 20) & 2) | ((op >> 31) & 1); + int global_le = ((op >> 16) & 2) | ((op >> 9) & 1); + int gbank = (op >> 18) & 0x7; + int reg = (op >> 10) & 0x7; + int d = (op >> 32) & 0x7; + + int greg = (gbank << 3) | reg; + int lreg = (4 << 3) | d; + + // local transfer + switch (local_le) + { + case 0: b += sprintf(b, "&%s%s = %s", TRANSFER_SIZE[local_size], format_address_mode(lmode, la, local_s, local_imx), REG_NAMES[lreg]); break; + case 1: b += sprintf(b, "%s = %s", REG_NAMES[lreg], format_address_mode(lmode, la, local_s, local_imx)); break; + case 2: b += sprintf(b, "%s = &%s%s", REG_NAMES[lreg], TRANSFER_SIZE[local_size], format_address_mode(lmode, la, local_s, local_imx)); break; + case 3: b += sprintf(b, "%s = &%s%s", REG_NAMES[lreg], TRANSFER_SIZE[local_size], format_address_mode(lmode, la, local_s, local_imx)); break; + } + + print(", "); + + // global transfer + switch (global_le) + { + case 0: b += sprintf(b, "&%s%s = %s", TRANSFER_SIZE[global_size], format_address_mode(gmode, ga, global_s, global_imx), REG_NAMES[greg]); break; + case 1: b += sprintf(b, "%s = %s", REG_NAMES[greg], format_address_mode(gmode, ga, global_s, global_imx)); break; + case 2: b += sprintf(b, "%s = &%s%s", REG_NAMES[greg], TRANSFER_SIZE[global_size], format_address_mode(gmode, ga, global_s, global_imx)); break; + case 3: b += sprintf(b, "%s = &%s%s", REG_NAMES[greg], TRANSFER_SIZE[global_size], format_address_mode(gmode, ga, global_s, global_imx)); break; + } + break; + } + } + } + } + + if (!is_nop) + print(" || %s", buffer); +} + +static void format_alu_op(int aluop, int a, const char *dst_text, const char *a_text, const char *b_text, const char *c_text) +{ + if (a) // arithmetic + { + int bits = (aluop & 1) | ((aluop >> 1) & 2) | ((aluop >> 2) & 4) | ((aluop >> 3) & 8); + switch (bits) + { + case 1: print("%s = %s - %s<1<", dst_text, a_text, b_text); break; + case 2: print("%s = %s + %s<0<", dst_text, a_text, b_text); break; + case 3: print("%s = %s - %s", dst_text, a_text, c_text); break; + case 4: print("%s = %s - %s>1>", dst_text, a_text, b_text); break; + case 5: print("%s = %s - %s", dst_text, a_text, b_text); break; + case 6: print("?"); break; + case 7: print("%s = %s - %s>0>", dst_text, a_text, b_text); break; + case 8: print("%s = %s + %s>0>", dst_text, a_text, b_text); break; + case 9: print("?"); break; + case 10: print("%s = %s + %s", dst_text, a_text, b_text); break; + case 11: print("%s = %s + %s>1>", dst_text, a_text, b_text); break; + case 12: print("%s = %s + %s", dst_text, a_text, c_text); break; + case 13: print("%s = %s - %s<0<", dst_text, a_text, b_text); break; + case 14: print("%s = %s + %s<1<", dst_text, a_text, b_text); break; + case 15: print("%s = field %s + %s", dst_text, a_text, b_text); break; + } + } + else // boolean + { + switch (aluop) + { + case 0xaa: // A & B & C | A & ~B & C | A & B & ~C | A & ~B & ~C = A + print("%s = %s", dst_text, a_text); + break; + + case 0x55: // ~A & B & C | ~A & ~B & C | ~A & B & ~C | ~A & ~B & ~C = ~A + print("%s = ~%s", dst_text, a_text); + break; + + case 0xcc: // A & B & C | ~A & B & C | A & B & ~C | ~A & B & ~C = B + print("%s = %s", dst_text, b_text); + break; + + case 0x33: // A & ~B & C | ~A & ~B & C | A & ~B & ~C | ~A & ~B & ~C = ~B + print("%s = %s", dst_text, b_text); + break; + + case 0xf0: // A & B & C | ~A & B & C | A & ~B & C | ~A & ~B & C = C + print("%s = %s", dst_text, c_text); + break; + + case 0x0f: // A & B & ~C | ~A & B & ~C | A & ~B & ~C | ~A & ~B & ~C = ~C + print("%s = ~%s", dst_text, c_text); + break; + + case 0x80: // A & B & C + print("%s = %s & %s & %s", dst_text, a_text, b_text, c_text); + break; + + case 0x88: // A & B & C | A & B & ~C = A & B + print("%s = %s & %s", dst_text, a_text, b_text); + break; + + case 0xa0: // A & B & C | A & ~B & C = A & C + print("%s = %s & %s", dst_text, a_text, c_text); + break; + + case 0xc0: // A & B & C | ~A & B & C = B & C + print("%s = %s & %s", dst_text, b_text, c_text); + break; + + case 0xea: // A & B & C | ~A & B & C | A & ~B & C | + // A & B & ~C | A & ~B & ~C = A | C + print("%s = %s | %s", dst_text, a_text, c_text); + break; + + case 0xee: // A & B & C | ~A & B & C | A & ~B & C | + // A & B & ~C | ~A & B & ~C | A & ~B & ~C = A | B + print("%s = %s | %s", dst_text, a_text, b_text); + break; + + case 0x44: // ~A & B & C | ~A & B & ~C = ~A & B + print("%s = ~%s & %s", dst_text, a_text, b_text); + break; + + default: + print("%s = b%02X(%s, %s, %s)", dst_text, aluop, a_text, b_text, c_text); + break; + } + } +} + +static offs_t tms32082_disasm_pp(char *buffer, offs_t pc, const UINT8 *oprom) +{ + output = buffer; + UINT32 flags = 0; + + UINT64 op = ((UINT64)(oprom[0]) << 56) | ((UINT64)(oprom[1]) << 48) | ((UINT64)(oprom[2]) << 40) | ((UINT64)(oprom[3]) << 32) | + ((UINT64)(oprom[4]) << 24) | ((UINT64)(oprom[5]) << 16) | ((UINT64)(oprom[6]) << 8) | ((UINT64)(oprom[7])); + + switch (op >> 60) + { + case 0x6: + case 0x7: // Six-operand + { + print("A: six operand "); + break; + } + + case 0x8: + case 0x9: + case 0xa: + case 0xb: + case 0xc: + case 0xd: + case 0xe: + case 0xf: + { + if ((op & U64(0xfaa8100000000000)) == U64(0x8800000000000000)) + { + int operation = (op >> 39) & 0x1f; + UINT64 parallel_xfer = (op & U64(0x0000007fffffffff)); + + switch (operation) + { + case 0x00: print("nop"); break; + case 0x02: print("eint"); break; + case 0x03: print("dint"); break; + default: print(""); break; + } + + format_transfer(parallel_xfer); + } + else + { + char dst_text[32]; + char a_text[32]; + char b_text[32]; + char c_text[32]; + + switch ((op >> 43) & 3) + { + case 0: + case 1: // Base set ALU (5-bit immediate) + { + UINT64 parallel_xfer = (op & U64(0x0000007fffffffff)); + + int dst = (op >> 48) & 7; + int src1 = (op >> 45) & 7; + int src2imm = (op >> 39) & 0x1f; + int cl = (op >> 60) & 7; + int aluop = (op >> 51) & 0xff; + int a = (op >> 59) & 1; + + int adstbank; + int as1bank; + + if ((op & 0x0101c000) == 0x00004000) + { + adstbank = (op >> 18) & 0xf; + as1bank = (op >> 6) & 0xf; + } + else + { + adstbank = 4; + as1bank = 4; + } + + int s1reg = src1 | (as1bank << 3); + int dreg = dst | (adstbank << 3); + int dstcreg = dst | (0x4 << 3); + + sprintf(dst_text, "%s", REG_NAMES[dreg]); + switch (cl) + { + case 0: + sprintf(a_text, "0x%02X", src2imm); + sprintf(b_text, "%s", REG_NAMES[s1reg]); + sprintf(c_text, "@mf"); + break; + case 1: + sprintf(a_text, "%s", REG_NAMES[dstcreg]); + sprintf(b_text, "%s\\\\d0", REG_NAMES[s1reg]); + sprintf(c_text, "0x%02X", src2imm); + break; + case 2: + sprintf(a_text, "%s", REG_NAMES[dstcreg]); + sprintf(b_text, "%s", REG_NAMES[s1reg]); + sprintf(c_text, "%%0x%02X", src2imm); + break; + case 3: + sprintf(a_text, "%s", REG_NAMES[dstcreg]); + sprintf(b_text, "%s\\\\0x%02X", REG_NAMES[s1reg], src2imm); + sprintf(c_text, "%%0x%02X", src2imm); + break; + case 4: + sprintf(a_text, "0x%02X", src2imm); + sprintf(b_text, "%s\\\\d0", REG_NAMES[s1reg]); + sprintf(c_text, "%%d0"); + break; + case 5: + sprintf(a_text, "0x%02X", src2imm); + sprintf(b_text, "%s\\\\d0", REG_NAMES[s1reg]); + sprintf(c_text, "@mf"); + break; + case 6: + sprintf(a_text, "%s", REG_NAMES[dstcreg]); + sprintf(b_text, "%s", REG_NAMES[s1reg]); + sprintf(c_text, "0x%02X", src2imm); + break; + case 7: + sprintf(a_text, "%s", REG_NAMES[s1reg]); + sprintf(b_text, "1\\\\0x%02X", src2imm); + sprintf(c_text, "0x%02X", src2imm); + break; + } + + format_alu_op(aluop, a, dst_text, a_text, b_text, c_text); + format_transfer(parallel_xfer); + break; + } + + case 2: // Base set ALU (reg src2) + { + UINT64 parallel_xfer = (op & U64(0x0000007fffffffff)); + + int dst = (op >> 48) & 7; + int src1 = (op >> 45) & 7; + int src2 = (op >> 39) & 7; + int cl = (op >> 60) & 7; + int aluop = (op >> 51) & 0xff; + int a = (op >> 59) & 1; + + int adstbank; + int as1bank; + + if ((op & 0x0101c000) == 0x00004000) + { + adstbank = (op >> 18) & 0xf; + as1bank = (op >> 6) & 0xf; + } + else + { + adstbank = 4; + as1bank = 4; + } + + int s1reg = src1 | (as1bank << 3); + int s2reg = src2 | (0x4 << 3); + int dstcreg = dst | (0x4 << 3); + int dreg = dst | (adstbank << 3); + + sprintf(dst_text, "%s", REG_NAMES[dreg]); + switch (cl) + { + case 0: + sprintf(a_text, "%s", REG_NAMES[s2reg]); + sprintf(b_text, "%s", REG_NAMES[s1reg]); + sprintf(c_text, "@mf"); + break; + case 1: + sprintf(a_text, "%s", REG_NAMES[dstcreg]); + sprintf(b_text, "%s\\\\d0", REG_NAMES[s1reg]); + sprintf(c_text, "%s", REG_NAMES[s2reg]); + break; + case 2: + sprintf(a_text, "%s", REG_NAMES[dstcreg]); + sprintf(b_text, "%s", REG_NAMES[s1reg]); + sprintf(c_text, "%%%s", REG_NAMES[s2reg]); + break; + case 3: + sprintf(a_text, "%s", REG_NAMES[dstcreg]); + sprintf(b_text, "%s\\\\%s", REG_NAMES[s1reg], REG_NAMES[s2reg]); + sprintf(c_text, "%%%s", REG_NAMES[s2reg]); + break; + case 4: + sprintf(a_text, "%s", REG_NAMES[s2reg]); + sprintf(b_text, "%s\\\\d0", REG_NAMES[s1reg]); + sprintf(c_text, "%%d0"); + break; + case 5: + sprintf(a_text, "%s", REG_NAMES[s2reg]); + sprintf(b_text, "%s\\\\d0", REG_NAMES[s1reg]); + sprintf(c_text, "@mf"); + break; + case 6: + sprintf(a_text, "%s", REG_NAMES[dstcreg]); + sprintf(b_text, "%s", REG_NAMES[s1reg]); + sprintf(c_text, "%s", REG_NAMES[s2reg]); + break; + case 7: + sprintf(a_text, "%s", REG_NAMES[s1reg]); + sprintf(b_text, "1\\\\%s", REG_NAMES[s2reg]); + sprintf(c_text, "%s", REG_NAMES[s2reg]); + break; + } + + format_alu_op(aluop, a, dst_text, a_text, b_text, c_text); + format_transfer(parallel_xfer); + break; + } + + case 3: // Base set ALU (32-bit immediate) + { + int dst = (op >> 48) & 7; + int src1 = (op >> 45) & 7; + int dstbank = (op >> 39) & 0xf; + int s1bank = (op >> 36) & 7; + int cond = (op >> 32) & 0xf; + int cl = (op >> 60) & 7; + int aluop = (op >> 51) & 0xff; + int a = (op >> 59) & 1; + UINT32 imm32 = (UINT32)(op); + + int dreg = dst | (dstbank << 3); + int s1reg = src1 | (s1bank << 3); + int dstcreg = dst | (0x4 << 3); + + sprintf(dst_text, "%s", REG_NAMES[dreg]); + switch (cl) + { + case 0: + sprintf(a_text, "0x%08X", imm32); + sprintf(b_text, "%s", REG_NAMES[s1reg]); + sprintf(c_text, "@mf"); + break; + case 1: + sprintf(a_text, "%s", REG_NAMES[dstcreg]); + sprintf(b_text, "%s\\\\d0", REG_NAMES[s1reg]); + sprintf(c_text, "0x%08X", imm32); + break; + case 2: + sprintf(a_text, "%s", REG_NAMES[dstcreg]); + sprintf(b_text, "%s", REG_NAMES[s1reg]); + sprintf(c_text, "%%0x%08X", imm32); + break; + case 3: + sprintf(a_text, "%s", REG_NAMES[dstcreg]); + sprintf(b_text, "%s\\\\0x%08X", REG_NAMES[s1reg], imm32); + sprintf(c_text, "%%0x%08X", imm32); + break; + case 4: + sprintf(a_text, "0x%08X", imm32); + sprintf(b_text, "%s\\\\d0", REG_NAMES[s1reg]); + sprintf(c_text, "%%d0"); + break; + case 5: + sprintf(a_text, "0x%08X", imm32); + sprintf(b_text, "%s\\\\d0", REG_NAMES[s1reg]); + sprintf(c_text, "@mf"); + break; + case 6: + sprintf(a_text, "%s", REG_NAMES[dstcreg]); + sprintf(b_text, "%s", REG_NAMES[s1reg]); + sprintf(c_text, "0x%08X", imm32); + break; + case 7: + sprintf(a_text, "%s", REG_NAMES[s1reg]); + sprintf(b_text, "1\\\\0x%08X", imm32); + sprintf(c_text, "0x%08X", imm32); + break; + } + + print("%s", CONDITION_CODES[cond]); + + format_alu_op(aluop, a, dst_text, a_text, b_text, c_text); + break; + } + } + } + break; + } + + default: + print("??? (%02X)", (UINT32)(op >> 60)); + break; + } + + return 8 | flags | DASMFLAG_SUPPORTED; +} + + +CPU_DISASSEMBLE(tms32082_pp) +{ + return tms32082_disasm_pp(buffer, pc, oprom); +} diff --git a/src/devices/cpu/tms32082/mp_ops.c b/src/devices/cpu/tms32082/mp_ops.c new file mode 100644 index 00000000000..79c0b401392 --- /dev/null +++ b/src/devices/cpu/tms32082/mp_ops.c @@ -0,0 +1,1821 @@ +// license:BSD-3-Clause +// copyright-holders:Ville Linde +// TMS320C82 Master Processor core execution + +#include "emu.h" +#include "tms32082.h" + + +#define OP_LINK() ((m_ir >> 27) & 0x1f) +#define OP_RD() ((m_ir >> 27) & 0x1f) +#define OP_RS() ((m_ir >> 22) & 0x1f) +#define OP_BASE() ((m_ir >> 22) & 0x1f) +#define OP_SIMM15() ((m_ir & 0x4000) ? (0xffffe000 | (m_ir & 0x7fff)) : (m_ir & 0x7fff)) +#define OP_UIMM15() (m_ir & 0x7fff) +#define OP_BITNUM() ((m_ir >> 27) & 0x1f) +#define OP_ROTATE() (m_ir & 0x1f) +#define OP_ENDMASK() ((m_ir >> 5) & 0x1f) +#define OP_SRC1() (m_ir & 0x1f) +#define OP_PD() ((m_ir >> 9) & 0x3) +#define OP_P1() ((m_ir >> 5) & 0x3) +#define OP_P2() ((m_ir >> 7) & 0x3) +#define OP_ACC() ((m_ir >> 15) & 0x2) | ((m_ir >> 11) & 1) + +#define ROTATE_L(x, r) ((x << r) | (x >> (32-r))) +#define ROTATE_R(x, r) ((x >> r) | (x << (32-r))) + +#define CMP_OVERFLOW32(r, s, d) ((((d) ^ (s)) & ((d) ^ (r)) & 0x80000000) ? 1 : 0) +#define CMP_OVERFLOW16(r, s, d) ((((d) ^ (s)) & ((d) ^ (r)) & 0x8000) ? 1 : 0) +#define CMP_OVERFLOW8(r, s, d) ((((d) ^ (s)) & ((d) ^ (r)) & 0x80) ? 1 : 0) +#define CARRY32(x) (((x) & (((UINT64)1) << 32)) ? 1 : 0) +#define CARRY16(x) (((x) & 0x10000) ? 1 : 0) +#define CARRY8(x) (((x) & 0x100) ? 1 : 0) +#define SIGN32(x) (((x) & 0x80000000) ? 1 : 0) +#define SIGN16(x) (((x) & 0x8000) ? 1 : 0) +#define SIGN8(x) (((x) & 0x80) ? 1 : 0) + +#define SIGN_EXTEND(x, r) ((x) | (((x) & (0x80000000 >> r)) ? ((INT32)(0x80000000) >> r) : 0)) + + + +bool tms32082_mp_device::test_condition(int condition, UINT32 value) +{ + switch (condition) + { + case 0x00: return false; // never, byte + case 0x01: return (INT8)(value) > 0; // greater than zero, byte + case 0x02: return (INT8)(value) == 0; // equals zero, byte + case 0x03: return (INT8)(value) >= 0; // greater than or equal to zero, byte + case 0x04: return (INT8)(value) < 0; // less than zero, byte + case 0x05: return (INT8)(value) != 0; // not equal to zero, byte + case 0x06: return (INT8)(value) <= 0; // less than or equal to zero, byte + case 0x07: return true; // always, byte + case 0x08: return false; // never, word + case 0x09: return (INT16)(value) > 0; // greater than zero, word + case 0x0a: return (INT16)(value) == 0; // equals zero, word + case 0x0b: return (INT16)(value) >= 0; // greater than or equal to zero, word + case 0x0c: return (INT16)(value) < 0; // less than zero, word + case 0x0d: return (INT16)(value) != 0; // not equal to zero, word + case 0x0e: return (INT16)(value) <= 0; // less than or equal to zero, word + case 0x0f: return true; // always, word + case 0x10: return false; // never, dword + case 0x11: return (INT32)(value) > 0; // greater than zero, dword + case 0x12: return (INT32)(value) == 0; // equals zero, dword + case 0x13: return (INT32)(value) >= 0; // greater than or equal to zero, dword + case 0x14: return (INT32)(value) < 0; // less than zero, dword + case 0x15: return (INT32)(value) != 0; // not equal to zero, dword + case 0x16: return (INT32)(value) <= 0; // less than or equal to zero, dword + case 0x17: return true; // always, dword + default: return false; // reserved + } +} + +UINT32 tms32082_mp_device::calculate_cmp(UINT32 src1, UINT32 src2) +{ + UINT16 src1_16 = (UINT16)(src1); + UINT8 src1_8 = (UINT8)(src1); + UINT16 src2_16 = (UINT16)(src2); + UINT8 src2_8 = (UINT8)(src2); + + UINT64 res32 = (UINT64)src1 - (UINT64)src2; + int z32 = (res32 == 0) ? 1 : 0; + int n32 = SIGN32(res32); + int v32 = CMP_OVERFLOW32(res32, src2, src1); + int c32 = CARRY32(res32); + + UINT32 res16 = (UINT32)src1_16 - (UINT32)src2_16; + int z16 = (res16 == 0) ? 1 : 0; + int n16 = SIGN16(res16); + int v16 = CMP_OVERFLOW16(res16, src2_16, src1_16); + int c16 = CARRY16(res16); + + UINT16 res8 = (UINT16)src1_8 - (UINT16)src2_8; + int z8 = (res8 == 0) ? 1 : 0; + int n8 = SIGN8(res8); + int v8 = CMP_OVERFLOW8(res8, src2_8, src1_8); + int c8 = CARRY8(res8); + + UINT32 flags = 0; + // 32-bits (bits 20-29) + flags |= ((~c32) & 1) << 29; // higher than or same (C) + flags |= ((c32) & 1) << 28; // lower than (~C) + flags |= ((c32|z32) & 1) << 27; // lower than or same (~C|Z) + flags |= ((~c32&~z32) & 1) << 26; // higher than (C&~Z) + flags |= (((n32&v32)|(~n32&~v32)) & 1) << 25; // greater than or equal (N&V)|(~N&~V) + flags |= (((n32&~v32)|(~n32&v32)) & 1) << 24; // less than (N&~V)|(~N&V) + flags |= (((n32&~v32)|(~n32&v32)|(z32)) & 1) << 23; // less than or equal (N&~V)|(~N&V)|Z + flags |= (((n32&v32&~z32)|(~n32&~v32&~z32)) & 1) << 22; // greater than (N&V&~Z)|(~N&~V&~Z) + flags |= ((~z32) & 1) << 21; // not equal (~Z) + flags |= ((z32) & 1) << 20; // equal (Z) + // 16-bits (bits 10-19) + flags |= ((~c16) & 1) << 19; // higher than or same (C) + flags |= ((c16) & 1) << 18; // lower than (~C) + flags |= ((c16|z16) & 1) << 17; // lower than or same (~C|Z) + flags |= ((~c16&~z16) & 1) << 16; // higher than (C&~Z) + flags |= (((n16&v16)|(~n16&~v16)) & 1) << 15; // greater than or equal (N&V)|(~N&~V) + flags |= (((n16&~v16)|(~n16&v16)) & 1) << 14; // less than (N&~V)|(~N&V) + flags |= (((n16&~v16)|(~n16&v16)|(z16)) & 1) << 13; // less than or equal (N&~V)|(~N&V)|Z + flags |= (((n16&v16&~z16)|(~n16&~v16&~z16)) & 1) << 12; // greater than (N&V&~Z)|(~N&~V&~Z) + flags |= ((~z16) & 1) << 11; // not equal (~Z) + flags |= ((z16) & 1) << 10; // equal (Z) + // 8-bits (bits 0-9) + flags |= ((~c8) & 1) << 9; // higher than or same (C) + flags |= ((c8) & 1) << 8; // lower than (~C) + flags |= ((c8|z8) & 1) << 7; // lower than or same (~C|Z) + flags |= ((~c8&~z8) & 1) << 6; // higher than (C&~Z) + flags |= (((n8&v8)|(~n8&~v8)) & 1) << 5; // greater than or equal (N&V)|(~N&~V) + flags |= (((n8&~v8)|(~n8&v8)) & 1) << 4; // less than (N&~V)|(~N&V) + flags |= (((n8&~v8)|(~n8&v8)|(z8)) & 1) << 3; // less than or equal (N&~V)|(~N&V)|Z + flags |= (((n8&v8&~z8)|(~n8&~v8&~z8)) & 1) << 2; // greater than (N&V&~Z)|(~N&~V&~Z) + flags |= ((~z8) & 1) << 1; // not equal (~Z) + flags |= ((z8) & 1) << 0; // equal (Z) + + return flags; +} + +void tms32082_mp_device::vector_loadstore() +{ + int rd = OP_RD(); + int vector_ls_bits = (((m_ir >> 9) & 0x3) << 1) | ((m_ir >> 6) & 1); + + switch (vector_ls_bits) + { + case 0x01: // vst.s + { + m_program->write_dword(m_outp, m_reg[rd]); + m_outp += 4; + break; + } + case 0x03: // vst.d + { + UINT64 data = m_fpair[rd >> 1]; + m_program->write_qword(m_outp, data); + m_outp += 8; + break; + } + case 0x04: // vld0.s + { + m_reg[rd] = m_program->read_dword(m_in0p); + m_in0p += 4; + break; + } + case 0x05: // vld1.s + { + m_reg[rd] = m_program->read_dword(m_in1p); + m_in1p += 4; + break; + } + case 0x06: // vld0.d + { + m_fpair[rd >> 1] = m_program->read_qword(m_in0p); + m_in0p += 8; + break; + } + case 0x07: // vld1.d + { + m_fpair[rd >> 1] = m_program->read_qword(m_in1p); + m_in1p += 8; + break; + } + + default: + fatalerror("vector_loadstore(): ls bits = %02X\n", vector_ls_bits); + } +} + +void tms32082_mp_device::execute_short_imm() +{ + switch ((m_ir >> 15) & 0x7f) + { + case 0x02: // cmnd + { + UINT32 data = OP_UIMM15(); + + processor_command(data); + break; + } + + case 0x04: // rdcr + { + int rd = OP_RD(); + UINT32 imm = OP_UIMM15(); + + UINT32 r = read_creg(imm); + + if (rd) + m_reg[rd] = r; + break; + } + + case 0x05: // swcr + { + int rd = OP_RD(); + int rs = OP_RS(); + UINT32 imm = OP_UIMM15(); + + UINT32 r = read_creg(imm); + if (rd) + m_reg[rd] = r; + + write_creg(imm, m_reg[rs]); + break; + } + + case 0x06: // brcr + { + int cr = OP_UIMM15(); + + if (cr == 0x0001) + { + // ignore jump to EIP because of how we emulate the pipeline + } + else + { + UINT32 data = read_creg(cr); + + m_fetchpc = data & ~3; + m_ie = (m_ie & ~1) | (data & 1); // global interrupt mask from creg + // TODO: user/supervisor latch from creg + } + break; + } + + case 0x08: // shift.dz + { + int r = (m_ir & (1 << 10)); + int inv = (m_ir & (1 << 11)); + int rot = OP_ROTATE(); + int end = OP_ENDMASK(); + UINT32 source = m_reg[OP_RS()]; + int rd = OP_RD(); + + UINT32 endmask = SHIFT_MASK[end ? end : 32]; + if (inv) endmask = ~endmask; + + UINT32 compmask = endmask; // shiftmask == 0xffffffff + + UINT32 res = 0; + if (r) // right + { + res = ROTATE_R(source, rot) & compmask; + } + else // left + { + res = ROTATE_L(source, rot) & compmask; + } + + if (rd) + m_reg[rd] = res; + break; + } + + case 0x0a: // shift.ds + { + int r = (m_ir & (1 << 10)); + int inv = (m_ir & (1 << 11)); + int rot = OP_ROTATE(); + int end = OP_ENDMASK(); + UINT32 source = m_reg[OP_RS()]; + int rd = OP_RD(); + + UINT32 endmask = SHIFT_MASK[end ? end : 32]; + if (inv) endmask = ~endmask; + + UINT32 compmask = endmask; // shiftmask == 0xffffffff + + UINT32 res = 0; + if (r) // right + { + res = ROTATE_R(source, rot) & compmask; + res = SIGN_EXTEND(res, rot); + } + else // left + { + res = ROTATE_L(source, rot) & compmask; + // sign extend makes no sense to left.. + } + + if (rd) + m_reg[rd] = res; + break; + } + + case 0x0b: // shift.ez + { + int r = (m_ir & (1 << 10)); + int inv = (m_ir & (1 << 11)); + int rot = OP_ROTATE(); + int end = OP_ENDMASK(); + UINT32 source = m_reg[OP_RS()]; + int rd = OP_RD(); + + UINT32 endmask = SHIFT_MASK[end ? end : 32]; + if (inv) endmask = ~endmask; + + int shift = r ? 32-rot : rot; + UINT32 shiftmask = SHIFT_MASK[shift ? shift : 32]; + UINT32 compmask = endmask & shiftmask; + + UINT32 res = 0; + if (r) // right + { + res = ROTATE_R(source, rot) & compmask; + } + else // left + { + res = ROTATE_L(source, rot) & compmask; + } + + if (rd) + m_reg[rd] = res; + break; + } + + case 0x0c: // shift.em + { + int r = (m_ir & (1 << 10)); + int inv = (m_ir & (1 << 11)); + int rot = OP_ROTATE(); + int end = OP_ENDMASK(); + UINT32 source = m_reg[OP_RS()]; + int rd = OP_RD(); + + UINT32 endmask = SHIFT_MASK[end ? end : 32]; + if (inv) endmask = ~endmask; + + UINT32 shiftmask = SHIFT_MASK[r ? 32-rot : rot]; + UINT32 compmask = endmask & shiftmask; + + UINT32 res = 0; + if (r) // right + { + res = (ROTATE_R(source, rot) & compmask) | (m_reg[rd] & ~compmask); + } + else // left + { + res = (ROTATE_L(source, rot) & compmask) | (m_reg[rd] & ~compmask); + } + + if (rd) + m_reg[rd] = res; + break; + } + + case 0x0d: // shift.es + { + int r = (m_ir & (1 << 10)); + int inv = (m_ir & (1 << 11)); + int rot = OP_ROTATE(); + int end = OP_ENDMASK(); + UINT32 source = m_reg[OP_RS()]; + int rd = OP_RD(); + + UINT32 endmask = SHIFT_MASK[end ? end : 32]; + if (inv) endmask = ~endmask; + + int shift = r ? 32-rot : rot; + UINT32 shiftmask = SHIFT_MASK[shift ? shift : 32]; + UINT32 compmask = endmask & shiftmask; + + UINT32 res = 0; + if (r) // right + { + res = ROTATE_R(source, rot) & compmask; + res = SIGN_EXTEND(res, rot); + } + else // left + { + res = ROTATE_L(source, rot) & compmask; + // sign extend makes no sense to left.. + } + + if (rd) + m_reg[rd] = res; + break; + } + + case 0x0e: // shift.iz + { + int r = (m_ir & (1 << 10)); + int inv = (m_ir & (1 << 11)); + int rot = OP_ROTATE(); + int end = OP_ENDMASK(); + UINT32 source = m_reg[OP_RS()]; + int rd = OP_RD(); + + UINT32 endmask = SHIFT_MASK[end ? end : 32]; + if (inv) endmask = ~endmask; + + UINT32 shiftmask = SHIFT_MASK[r ? 32-rot : rot]; + UINT32 compmask = endmask & ~shiftmask; + + UINT32 res = 0; + if (r) // right + { + res = ROTATE_R(source, rot) & compmask; + } + else // left + { + res = ROTATE_L(source, rot) & compmask; + } + + if (rd) + m_reg[rd] = res; + break; + } + + case 0x0f: // shift.im + { + int r = (m_ir & (1 << 10)); + int inv = (m_ir & (1 << 11)); + int rot = OP_ROTATE(); + int end = OP_ENDMASK(); + UINT32 source = m_reg[OP_RS()]; + int rd = OP_RD(); + + UINT32 endmask = SHIFT_MASK[end ? end : 32]; + if (inv) endmask = ~endmask; + + UINT32 shiftmask = SHIFT_MASK[r ? 32-rot : rot]; + UINT32 compmask = endmask & ~shiftmask; + + UINT32 res = 0; + if (r) // right + { + res = (ROTATE_R(source, rot) & compmask) | (m_reg[rd] & ~compmask); + } + else // left + { + res = (ROTATE_L(source, rot) & compmask) | (m_reg[rd] & ~compmask); + } + + if (rd) + m_reg[rd] = res; + break; + } + + case 0x11: // and + { + int rd = OP_RD(); + int rs = OP_RS(); + UINT32 imm = OP_UIMM15(); + + if (rd) + m_reg[rd] = m_reg[rs] & imm; + break; + } + + case 0x12: // and.tf + { + int rd = OP_RD(); + int rs = OP_RS(); + UINT32 imm = OP_UIMM15(); + + if (rd) + m_reg[rd] = ~m_reg[rs] & imm; + break; + } + + case 0x14: // and.ft + { + int rd = OP_RD(); + int rs = OP_RS(); + UINT32 imm = OP_UIMM15(); + + if (rd) + m_reg[rd] = m_reg[rs] & ~imm; + break; + } + + case 0x17: // or + { + int rd = OP_RD(); + int rs = OP_RS(); + UINT32 imm = OP_UIMM15(); + + if (rd) + m_reg[rd] = m_reg[rs] | imm; + break; + } + + case 0x1d: // or.ft + { + int rd = OP_RD(); + int rs = OP_RS(); + UINT32 imm = OP_UIMM15(); + + if (rd) + m_reg[rd] = m_reg[rs] | ~imm; + break; + } + + case 0x24: + case 0x20: // ld.b + { + int rd = OP_RD(); + int base = OP_BASE(); + int m = m_ir & (1 << 17); + INT32 offset = OP_SIMM15(); + + UINT32 address = m_reg[base] + offset; + UINT32 data = (UINT8)m_program->read_byte(address); + if (data & 0x80) data |= 0xffffff00; + if (rd) + m_reg[rd] = data; + + if (m && base) + m_reg[base] = address; + break; + } + + case 0x25: + case 0x21: // ld.h + { + int rd = OP_RD(); + int base = OP_BASE(); + int m = m_ir & (1 << 17); + INT32 offset = OP_SIMM15(); + + UINT32 address = m_reg[base] + offset; + UINT32 data = (UINT16)m_program->read_word(address); + if (data & 0x8000) data |= 0xffff0000; + if (rd) + m_reg[rd] = data; + + if (m && base) + m_reg[base] = address; + break; + } + + case 0x26: + case 0x22: // ld + { + int rd = OP_RD(); + int base = OP_BASE(); + int m = m_ir & (1 << 17); + INT32 offset = OP_SIMM15(); + + UINT32 address = m_reg[base] + offset; + UINT32 data = m_program->read_dword(address); + if (rd) + m_reg[rd] = data; + + if (m && base) + m_reg[base] = address; + break; + } + + case 0x27: + case 0x23: // ld.d + { + int rd = OP_RD(); + int base = OP_BASE(); + int m = m_ir & (1 << 17); + INT32 offset = OP_SIMM15(); + + UINT32 address = m_reg[base] + offset; + UINT32 data1 = m_program->read_dword(address); + UINT32 data2 = m_program->read_dword(address+4); + if (rd) + { + m_reg[(rd & ~1)+1] = data1; + m_reg[(rd & ~1)] = data2; + } + + if (m && base) + m_reg[base] = address; + break; + } + + case 0x28: + case 0x2c: // ld.ub + { + int rd = OP_RD(); + int base = OP_BASE(); + int m = m_ir & (1 << 17); + INT32 offset = OP_SIMM15(); + + UINT32 address = m_reg[base] + offset; + UINT32 data = (UINT8)(m_program->read_byte(address)); + if (rd) + m_reg[rd] = data; + + if (m && base) + m_reg[base] = address; + break; + } + + case 0x2d: + case 0x29: // ld.uh + { + int rd = OP_RD(); + int base = OP_BASE(); + int m = m_ir & (1 << 17); + INT32 offset = OP_SIMM15(); + + UINT32 address = m_reg[base] + offset; + UINT32 data = (UINT16)(m_program->read_word(address)); + if (rd) + m_reg[rd] = data; + + if (m && base) + m_reg[base] = address; + break; + } + + case 0x34: + case 0x30: // st.b + { + int rd = OP_RD(); + int base = OP_BASE(); + int m = m_ir & (1 << 17); + INT32 offset = OP_SIMM15(); + + UINT32 address = m_reg[base] + offset; + + m_program->write_byte(address, (UINT8)(m_reg[rd])); + + if (m && base) + m_reg[base] = address; + break; + } + + case 0x35: + case 0x31: // st.h + { + int rd = OP_RD(); + int base = OP_BASE(); + int m = m_ir & (1 << 17); + INT32 offset = OP_SIMM15(); + + UINT32 address = m_reg[base] + offset; + + m_program->write_word(address, (UINT16)(m_reg[rd])); + + if (m && base) + m_reg[base] = address; + break; + } + + case 0x36: + case 0x32: // st + { + int rd = OP_RD(); + int base = OP_BASE(); + int m = m_ir & (1 << 17); + INT32 offset = OP_SIMM15(); + + UINT32 address = m_reg[base] + offset; + + m_program->write_dword(address, m_reg[rd]); + + if (m && base) + m_reg[base] = address; + break; + } + + case 0x37: + case 0x33: // st.d + { + int rd = OP_RD(); + int base = OP_BASE(); + int m = m_ir & (1 << 17); + INT32 offset = OP_SIMM15(); + + UINT32 address = m_reg[base] + offset; + + m_program->write_dword(address+0, m_reg[(rd & ~1) + 1]); + m_program->write_dword(address+4, m_reg[rd & ~1]); + + if (m && base) + m_reg[base] = address; + break; + } + + case 0x45: // jsr.a + { + int link = OP_LINK(); + int base = OP_BASE(); + INT32 offset = OP_SIMM15(); + + if (link) + m_reg[link] = m_fetchpc; + + m_fetchpc = m_reg[base] + offset; + break; + } + + case 0x48: // bbz + { + int bitnum = OP_BITNUM() ^ 0x1f; + INT32 offset = OP_SIMM15(); + int rs = OP_RS(); + + if ((m_reg[rs] & (1 << bitnum)) == 0) + { + UINT32 address = m_pc + (offset * 4); + + m_pc = m_fetchpc; + delay_slot(); + + m_fetchpc = address; + } + break; + } + + case 0x49: // bbz.a + { + int bitnum = OP_BITNUM() ^ 0x1f; + INT32 offset = OP_SIMM15(); + int rs = OP_RS(); + + if ((m_reg[rs] & (1 << bitnum)) == 0) + { + m_fetchpc = m_pc + (offset * 4); + } + break; + } + + case 0x4a: // bbo + { + int bitnum = OP_BITNUM() ^ 0x1f; + INT32 offset = OP_SIMM15(); + int rs = OP_RS(); + + if ((m_reg[rs] & (1 << bitnum)) != 0) + { + UINT32 address = m_pc + (offset * 4); + + m_pc = m_fetchpc; + delay_slot(); + + m_fetchpc = address; + } + break; + } + + case 0x4b: // bbo.a + { + int bitnum = OP_BITNUM() ^ 0x1f; + INT32 offset = OP_SIMM15(); + int rs = OP_RS(); + + if ((m_reg[rs] & (1 << bitnum)) != 0) + { + m_fetchpc = m_pc + (offset * 4); + } + break; + } + + case 0x4c: // bcnd + { + INT32 offset = OP_SIMM15(); + int code = OP_RD(); + int rs = OP_RS(); + + if (test_condition(code, m_reg[rs])) + { + UINT32 address = m_pc + (offset * 4); + + m_pc = m_fetchpc; + delay_slot(); + + m_fetchpc = address; + } + break; + } + + case 0x4d: // bcnd.a + { + INT32 offset = OP_SIMM15(); + int code = OP_RD(); + int rs = OP_RS(); + + if (test_condition(code, m_reg[rs])) + { + m_fetchpc = m_pc + (offset * 4); + } + break; + } + + case 0x50: // cmp + { + UINT32 src1 = OP_SIMM15(); + UINT32 src2 = m_reg[OP_RS()]; + int rd = OP_RD(); + + if (rd) + m_reg[rd] = calculate_cmp(src1, src2); + break; + } + + case 0x58: // add + { + INT32 imm = OP_SIMM15(); + int rd = OP_RD(); + int rs = OP_RS(); + + if (rd) + m_reg[rd] = m_reg[rs] + imm; + + // TODO: integer overflow exception + break; + } + + case 0x59: // addu + { + INT32 imm = OP_SIMM15(); + int rd = OP_RD(); + int rs = OP_RS(); + + if (rd) + m_reg[rd] = m_reg[rs] + imm; + break; + } + + case 0x5a: // sub + { + INT32 imm = OP_SIMM15(); + int rd = OP_RD(); + int rs = OP_RS(); + + if (rd) + m_reg[rd] = imm - m_reg[rs]; + + // TODO: integer overflow exception + break; + } + + case 0x5b: // subu + { + INT32 imm = OP_SIMM15(); + int rd = OP_RD(); + int rs = OP_RS(); + + if (rd) + m_reg[rd] = imm - m_reg[rs]; + break; + } + + default: + fatalerror("execute_short_imm(): %08X: opcode %08X (%02X)", m_pc, m_ir, (m_ir >> 15) & 0x7f); + } +} + +void tms32082_mp_device::execute_reg_long_imm() +{ + UINT32 imm32 = 0; + + int has_imm = (m_ir & (1 << 12)); + + if (has_imm) + imm32 = fetch(); + + switch ((m_ir >> 12) & 0xff) + { + case 0x04: // cmnd + { + UINT32 data = has_imm ? imm32 : m_reg[OP_SRC1()]; + + processor_command(data); + break; + } + + case 0x16: // shift.ez + { + int r = (m_ir & (1 << 10)); + int inv = (m_ir & (1 << 11)); + int rot = m_reg[OP_ROTATE()]; + int end = OP_ENDMASK(); + UINT32 source = m_reg[OP_RS()]; + int rd = OP_RD(); + + UINT32 endmask = end ? SHIFT_MASK[end ? end : 32] : m_reg[OP_ROTATE()+1]; + if (inv) endmask = ~endmask; + + int shift = r ? 32-rot : rot; + UINT32 shiftmask = SHIFT_MASK[shift ? shift : 32]; + UINT32 compmask = endmask & shiftmask; + + UINT32 res = 0; + if (r) // right + { + res = ROTATE_R(source, rot) & compmask; + } + else // left + { + res = ROTATE_L(source, rot) & compmask; + } + + if (rd) + m_reg[rd] = res; + break; + } + + case 0x1a: // shift.es + { + int r = (m_ir & (1 << 10)); + int inv = (m_ir & (1 << 11)); + int rot = m_reg[OP_ROTATE()]; + int end = OP_ENDMASK(); + UINT32 source = m_reg[OP_RS()]; + int rd = OP_RD(); + + UINT32 endmask = end ? SHIFT_MASK[end ? end : 32] : m_reg[OP_ROTATE()+1]; + if (inv) endmask = ~endmask; + + int shift = r ? 32-rot : rot; + UINT32 shiftmask = SHIFT_MASK[shift ? shift : 32]; + UINT32 compmask = endmask & shiftmask; + + UINT32 res = 0; + if (r) // right + { + res = ROTATE_R(source, rot) & compmask; + res = SIGN_EXTEND(res, rot); + } + else // left + { + res = ROTATE_L(source, rot) & compmask; + } + + if (rd) + m_reg[rd] = res; + break; + } + + case 0x1c: // shift.iz + { + int r = (m_ir & (1 << 10)); + int inv = (m_ir & (1 << 11)); + int rot = m_reg[OP_ROTATE()]; + int end = OP_ENDMASK(); + UINT32 source = m_reg[OP_RS()]; + int rd = OP_RD(); + + UINT32 endmask = end ? SHIFT_MASK[end ? end : 32] : m_reg[OP_ROTATE()+1]; + if (inv) endmask = ~endmask; + + int shift = r ? 32-rot : rot; + UINT32 shiftmask = SHIFT_MASK[shift ? shift : 32]; + UINT32 compmask = endmask & ~shiftmask; + + UINT32 res = 0; + if (r) // right + { + res = ROTATE_R(source, rot) & compmask; + } + else // left + { + res = ROTATE_L(source, rot) & compmask; + } + + if (rd) + m_reg[rd] = res; + break; + } + + case 0x22: + case 0x23: // and + { + int rd = OP_RD(); + int rs = OP_RS(); + UINT32 src1 = has_imm ? imm32 : m_reg[OP_SRC1()]; + + if (rd) + m_reg[rd] = src1 & m_reg[rs]; + break; + } + + case 0x24: + case 0x25: // and.tf + { + int rd = OP_RD(); + int rs = OP_RS(); + UINT32 src1 = has_imm ? imm32 : m_reg[OP_SRC1()]; + + if (rd) + m_reg[rd] = src1 & ~(m_reg[rs]); + break; + } + + case 0x2c: + case 0x2d: // xor + { + int rd = OP_RD(); + int rs = OP_RS(); + + if (rd) + m_reg[rd] = m_reg[rs] ^ (has_imm ? imm32 : m_reg[OP_SRC1()]); + break; + } + + case 0x2e: + case 0x2f: // or + { + int rd = OP_RD(); + int rs = OP_RS(); + + if (rd) + m_reg[rd] = m_reg[rs] | (has_imm ? imm32 : m_reg[OP_SRC1()]); + break; + } + + case 0x3a: + case 0x3b: // or.ft + { + int rd = OP_RD(); + int rs = OP_RS(); + + if (rd) + m_reg[rd] = m_reg[rs] | ~(has_imm ? imm32 : m_reg[OP_SRC1()]); + break; + } + + case 0x40: + case 0x41: + case 0x48: + case 0x49: // ld.b + { + int m = m_ir & (1 << 15); + + int base = OP_BASE(); + int rd = OP_RD(); + + UINT32 address = m_reg[base] + (has_imm ? imm32 : m_reg[OP_SRC1()]); + UINT32 r = m_program->read_byte(address); + if (r & 0x80) r |= 0xffffff00; + + if (rd) + m_reg[rd] = r; + + if (m && base) + m_reg[base] = address; + break; + } + + case 0x42: + case 0x4a: + case 0x43: + case 0x4b: // ld.h + { + int shift = (m_ir & (1 << 11)) ? 1 : 0; + int m = m_ir & (1 << 15); + + int base = OP_BASE(); + int rd = OP_RD(); + + UINT32 address = m_reg[base] + ((has_imm ? imm32 : m_reg[OP_SRC1()]) << shift); + UINT32 r = m_program->read_word(address); + if (r & 0x8000) r |= 0xffff0000; + + if (rd) + m_reg[rd] = r; + + if (m && base) + m_reg[base] = address; + break; + } + + case 0x4c: + case 0x44: + case 0x4d: + case 0x45: // ld + { + int shift = (m_ir & (1 << 11)) ? 2 : 0; + int m = m_ir & (1 << 15); + int base = OP_BASE(); + int rd = OP_RD(); + + UINT32 address = m_reg[base] + ((has_imm ? imm32 : m_reg[OP_SRC1()]) << shift); + UINT32 r = m_program->read_dword(address); + + if (rd) + m_reg[rd] = r; + + if (m && base) + m_reg[base] = address; + break; + } + + case 0x4e: + case 0x4f: + case 0x46: + case 0x47: // ld.d + { + int shift = (m_ir & (1 << 11)) ? 3 : 0; + int m = m_ir & (1 << 15); + int base = OP_BASE(); + int rd = OP_RD(); + + UINT32 address = m_reg[base] + ((has_imm ? imm32 : m_reg[OP_SRC1()]) << shift); + UINT64 r = m_program->read_qword(address); + + if (rd) + m_fpair[rd >> 1] = r; + + if (m && base) + m_reg[base] = address; + break; + } + + case 0x58: + case 0x59: + case 0x50: + case 0x51: // ld.ub + { + int m = m_ir & (1 << 15); + int base = OP_BASE(); + int rd = OP_RD(); + + UINT32 address = m_reg[base] + (has_imm ? imm32 : m_reg[OP_SRC1()]); + UINT32 r = (UINT8)(m_program->read_byte(address)); + + if (rd) + m_reg[rd] = r; + + if (m && base) + m_reg[base] = address; + break; + } + + case 0x5a: + case 0x5b: + case 0x52: + case 0x53: // ld.uh + { + int shift = (m_ir & (1 << 11)) ? 1 : 0; + int m = m_ir & (1 << 15); + int base = OP_BASE(); + int rd = OP_RD(); + + UINT32 address = m_reg[base] + ((has_imm ? imm32 : m_reg[OP_SRC1()]) << shift); + UINT32 r = (UINT16)(m_program->read_word(address)); + + if (rd) + m_reg[rd] = r; + + if (m && base) + m_reg[base] = address; + break; + } + + case 0x60: + case 0x61: + case 0x68: + case 0x69: // st.b + { + int m = m_ir & (1 << 15); + + int base = OP_BASE(); + + UINT32 address = m_reg[base] + (has_imm ? imm32 : m_reg[OP_SRC1()]); + m_program->write_byte(address, (UINT8)(m_reg[OP_RD()])); + + if (m && base) + m_reg[base] = address; + break; + } + + case 0x62: + case 0x63: + case 0x6a: + case 0x6b: // st.h + { + int shift = (m_ir & (1 << 11)) ? 1 : 0; + int m = m_ir & (1 << 15); + + int base = OP_BASE(); + + UINT32 address = m_reg[base] + ((has_imm ? imm32 : m_reg[OP_SRC1()]) << shift); + m_program->write_word(address, (UINT16)(m_reg[OP_RD()])); + + if (m && base) + m_reg[base] = address; + break; + } + + case 0x6c: + case 0x6d: + case 0x64: + case 0x65: // st + { + int shift = (m_ir & (1 << 11)) ? 2 : 0; + int m = m_ir & (1 << 15); + + int base = OP_BASE(); + + UINT32 address = m_reg[base] + ((has_imm ? imm32 : m_reg[OP_SRC1()]) << shift); + m_program->write_dword(address, m_reg[OP_RD()]); + + if (m && base) + m_reg[base] = address; + break; + } + + case 0x88: + case 0x89: // jsr + { + int link = OP_LINK(); + int base = OP_BASE(); + + if (link) + m_reg[link] = m_fetchpc + 4; + + UINT32 address = m_reg[base] + (has_imm ? imm32 : m_reg[OP_SRC1()]); + + m_pc = m_fetchpc; + delay_slot(); + + m_fetchpc = address; + break; + } + + case 0x8a: + case 0x8b: // jsr.a + { + int link = OP_LINK(); + int base = OP_BASE(); + + if (link) + m_reg[link] = m_fetchpc; + + m_fetchpc = m_reg[base] + (has_imm ? imm32 : m_reg[OP_SRC1()]); + break; + } + + case 0xa0: + case 0xa1: // cmp + { + int rd = OP_RD(); + UINT32 src1 = has_imm ? imm32 : m_reg[OP_SRC1()]; + UINT32 src2 = m_reg[OP_RS()]; + + if (rd) + m_reg[rd] = calculate_cmp(src1, src2); + break; + } + + case 0xb2: + case 0xb3: // addu + { + int rd = OP_RD(); + int rs = OP_RS(); + + if (rd) + m_reg[rd] = m_reg[rs] + (has_imm ? imm32 : m_reg[OP_SRC1()]); + break; + } + + case 0xb4: + case 0xb5: // sub + { + int rd = OP_RD(); + int rs = OP_RS(); + + if (rd) + m_reg[rd] = (has_imm ? imm32 : m_reg[OP_SRC1()]) - m_reg[rs]; + + // TODO: overflow interrupt + break; + } + + case 0xb6: + case 0xb7: // subu + { + int rd = OP_RD(); + int rs = OP_RS(); + + if (rd) + m_reg[rd] = (has_imm ? imm32 : m_reg[OP_SRC1()]) - m_reg[rs]; + break; + } + + case 0xc4: + case 0xd4: + case 0xc5: + case 0xd5: // vmpy + { + int p1 = m_ir & (1 << 5); + int pd = m_ir & (1 << 7); + int ls_bit1 = m_ir & (1 << 10); + int ls_bit2 = m_ir & (1 << 6); + int rd = OP_RS(); + int src1 OP_SRC1(); + + double source = has_imm ? (double)u2f(imm32) : (p1 ? u2d(m_fpair[src1 >> 1]) : (double)u2f(m_reg[src1])); + + if (rd) + { + if (pd) + { + double res = source * u2d(m_fpair[rd >> 1]); + m_fpair[rd >> 1] = d2u(res); + } + else + { + float res = (float)(source) * u2f(m_reg[rd]); + m_reg[rd] = f2u(res); + } + } + + // parallel load/store op + if (!(ls_bit1 == 0 && ls_bit2 == 0)) + { + vector_loadstore(); + } + break; + } + + case 0xc8: + case 0xd8: + case 0xc9: + case 0xd9: // vrnd + { + int acc = OP_ACC(); + int p1 = m_ir & (1 << 5); + int pd = (m_ir >> 7) & 3; + int ls_bit1 = m_ir & (1 << 10); + int ls_bit2 = m_ir & (1 << 6); + int rd = OP_RS(); + int rs1 = OP_SRC1(); + + double source = has_imm ? (double)u2f(imm32) : (p1 ? u2d(m_fpair[rs1 >> 1]) : (double)u2f(m_reg[rs1])); + + if (rd) + { + // destination register + switch (pd) + { + case 0: + m_reg[rd] = f2u((float)source); + break; + case 1: + m_fpair[rd >> 1] = d2u(source); + break; + case 2: + m_reg[rd] = (INT32)(source); + break; + case 3: + m_reg[rd] = (UINT32)(source); + break; + } + } + else + { + // destination accumulator + if (pd != 1) + fatalerror("vrnd pd = %d at %08X\n", pd, m_pc); + + m_facc[acc] = source; + } + + // parallel load/store op + if (!(ls_bit1 == 0 && ls_bit2 == 0)) + { + vector_loadstore(); + } + break; + } + + case 0xcc: + case 0xdc: + case 0xcd: + case 0xdd: // vmac + { + int acc = OP_ACC(); + int z = m_ir & (1 << 8); + int pd = m_ir & (1 << 9); + int ls_bit1 = m_ir & (1 << 10); + int ls_bit2 = m_ir & (1 << 6); + int rd = OP_RD(); + + float src1 = u2f(m_reg[OP_SRC1()]); + float src2 = u2f(m_reg[OP_RS()]); + + float res = (src1 * src2) + (z ? 0.0f : m_acc[acc]); + + // parallel load/store op + if (!(ls_bit1 == 0 && ls_bit2 == 0)) + { + vector_loadstore(); + + // if the opcode has load/store, dest is always accumulator + m_facc[acc] = (double)res; + } + else + { + if (rd) + { + if (pd) + m_fpair[rd >> 1] = d2u(res); + else + m_reg[rd] = f2u((float)res); + } + else + { + // write to accumulator + m_facc[acc] = (double)res; + } + } + break; + } + + case 0xce: + case 0xde: + case 0xcf: + case 0xdf: // vmsc + { + int acc = OP_ACC(); + int z = m_ir & (1 << 8); + int pd = m_ir & (1 << 9); + int ls_bit1 = m_ir & (1 << 10); + int ls_bit2 = m_ir & (1 << 6); + int rd = OP_RD(); + + float src1 = u2f(m_reg[OP_SRC1()]); + float src2 = u2f(m_reg[OP_RS()]); + + float res = (z ? 0.0f : m_acc[acc]) - (src1 * src2); + + // parallel load/store op + if (!(ls_bit1 == 0 && ls_bit2 == 0)) + { + vector_loadstore(); + + // if the opcode has load/store, dest is always accumulator + m_facc[acc] = (double)res; + } + else + { + if (rd) + { + if (pd) + m_fpair[rd >> 1] = d2u(res); + else + m_reg[rd] = f2u((float)res); + } + else + { + // write to accumulator + m_facc[acc] = (double)res; + } + } + break; + } + + case 0xe0: + case 0xe1: // fadd + { + int rd = OP_RD(); + int rs = OP_RS(); + int src1 = OP_SRC1(); + int precision = (m_ir >> 5) & 0x3f; + + if (rd) // only calculate if destination register is valid + { + switch (precision) + { + case 0x00: // SP - SP -> SP + { + float s1 = u2f(has_imm ? imm32 : m_reg[src1]); + float s2 = u2f(m_reg[rs]); + m_reg[rd] = f2u(s1 + s2); + break; + } + case 0x10: // SP - SP -> DP + { + float s1 = u2f(has_imm ? imm32 : m_reg[src1]); + float s2 = u2f(m_reg[rs]); + UINT64 res = d2u((double)(s1 + s2)); + m_fpair[rd >> 1] = res; + break; + } + case 0x14: // SP - DP -> DP + { + float s1 = u2f(has_imm ? imm32 : m_reg[src1]); + double s2 = u2d(m_fpair[rs >> 1]); + UINT64 res = d2u((double) s1 + s2); + m_fpair[rd >> 1] = res; + break; + } + case 0x11: // DP - SP -> DP + { + double s1 = u2d(m_fpair[src1 >> 1]); + float s2 = u2f(m_reg[rs]); + UINT64 res = d2u(s1 + (double) s2); + m_fpair[rd >> 1] = res; + break; + } + case 0x15: // DP - DP -> DP + { + double s1 = u2d(m_fpair[src1 >> 1]); + double s2 = u2d(m_fpair[rs >> 1]); + UINT64 res = d2u((double)(s1 + s2)); + m_fpair[rd >> 1] = res; + break; + } + default: + fatalerror("fadd: invalid precision combination %02X\n", precision); + } + } + break; + } + + case 0xe2: + case 0xe3: // fsub + { + int rd = OP_RD(); + int rs = OP_RS(); + int src1 = OP_SRC1(); + int precision = (m_ir >> 5) & 0x3f; + + if (rd) // only calculate if destination register is valid + { + switch (precision) + { + case 0x00: // SP - SP -> SP + { + float s1 = u2f(has_imm ? imm32 : m_reg[src1]); + float s2 = u2f(m_reg[rs]); + m_reg[rd] = f2u(s1 - s2); + break; + } + case 0x10: // SP - SP -> DP + { + float s1 = u2f(has_imm ? imm32 : m_reg[src1]); + float s2 = u2f(m_reg[rs]); + UINT64 res = d2u((double)(s1 - s2)); + m_fpair[rd >> 1] = res; + break; + } + case 0x14: // SP - DP -> DP + { + float s1 = u2f(has_imm ? imm32 : m_reg[src1]); + double s2 = u2d(m_fpair[rs >> 1]); + UINT64 res = d2u((double) s1 - s2); + m_fpair[rd >> 1] = res; + break; + } + case 0x11: // DP - SP -> DP + { + double s1 = u2d(m_fpair[src1 >> 1]); + float s2 = u2f(m_reg[rs]); + UINT64 res = d2u(s1 - (double) s2); + m_fpair[rd >> 1] = res; + break; + } + case 0x15: // DP - DP -> DP + { + double s1 = u2d(m_fpair[src1 >> 1]); + double s2 = u2d(m_fpair[rs >> 1]); + UINT64 res = d2u((double)(s1 - s2)); + m_fpair[rd >> 1] = res; + break; + } + default: + fatalerror("fsub: invalid precision combination %02X\n", precision); + } + } + break; + } + + case 0xe4: + case 0xe5: // fmpy + { + int rd = OP_RD(); + int rs = OP_RS(); + int src1 = OP_SRC1(); + int precision = (m_ir >> 5) & 0x3f; + + if (rd) // only calculate if destination register is valid + { + switch (precision) + { + case 0x00: // SP x SP -> SP + { + float s1 = u2f(has_imm ? imm32 : m_reg[src1]); + float s2 = u2f(m_reg[rs]); + m_reg[rd] = f2u(s1 * s2); + break; + } + case 0x10: // SP x SP -> DP + { + float s1 = u2f(has_imm ? imm32 : m_reg[src1]); + float s2 = u2f(m_reg[rs]); + UINT64 res = d2u((double)(s1 * s2)); + m_fpair[rd >> 1] = res; + break; + } + case 0x14: // SP x DP -> DP + { + float s1 = u2f(has_imm ? imm32 : m_reg[src1]); + double s2 = u2d(m_fpair[rs >> 1]); + UINT64 res = d2u((double)s1 * s2); + m_fpair[rd >> 1] = res; + break; + } + case 0x11: // DP x SP -> DP + { + double s1 = u2d(m_fpair[src1 >> 1]); + float s2 = u2f(m_reg[rs]); + UINT64 res = d2u(s1 * (double) s2); + m_fpair[rd >> 1] = res; + break; + } + case 0x15: // DP x DP -> DP + { + double s1 = u2d(m_fpair[src1 >> 1]); + double s2 = u2d(m_fpair[rs >> 1]); + UINT64 res = d2u(s1 * s2); + m_fpair[rd >> 1] = res; + break; + } + case 0x2a: // I x I -> I + { + m_reg[rd] = (INT32)(m_reg[rs]) * (INT32)(has_imm ? imm32 : m_reg[OP_SRC1()]); + break; + } + case 0x3f: // U x U -> U + { + m_reg[rd] = (UINT32)(m_reg[rs]) * (UINT32)(has_imm ? imm32 : m_reg[OP_SRC1()]); + break; + } + default: + fatalerror("fmpy: invalid precision combination %02X\n", precision); + } + } + break; + } + + case 0xe6: + case 0xe7: // fdiv + { + int rd = OP_RD(); + int p1 = m_ir & (1 << 5); + int p2 = m_ir & (1 << 7); + int pd = m_ir & (1 << 9); + int rs1 = OP_SRC1(); + int rs2 = OP_RS(); + + if (rd) + { + double src1 = has_imm ? (double)u2f(imm32) : (p1 ? u2d(m_fpair[rs1 >> 1]) : (double)u2f(m_reg[rs1])); + double src2 = p2 ? u2d(m_fpair[rs2 >> 1]) : (double)u2f(m_reg[rs2]); + + double res = src1 / src2; + + if (pd) + m_fpair[rd >> 1] = d2u(res); + else + m_reg[rd] = f2u((float)res); + } + break; + } + + case 0xe8: + case 0xe9: // frnd + { + //int mode = (m_ir >> 7) & 3; + int p1 = (m_ir >> 5) & 3; + int pd = (m_ir >> 9) & 3; + int src1 = OP_SRC1(); + int rd = OP_RD(); + + double s = 0.0; + + switch (p1) + { + case 0: + s = has_imm ? (double)(u2f(imm32)) : (double)u2f(m_reg[src1]); + break; + case 1: + s = u2d(m_fpair[src1 >> 1]); + break; + case 2: + s = has_imm ? (double)((INT32)(imm32)) : (double)(INT32)(m_reg[src1]); + break; + case 3: + s = has_imm ? (double)((UINT32)(imm32)) : (double)(UINT32)(m_reg[src1]); + break; + } + + // TODO: round + + if (rd) + { + switch (pd) + { + case 0: + m_reg[rd] = f2u((float)(s)); + break; + case 1: + m_fpair[rd] = d2u(s); + break; + case 2: + m_reg[rd] = (INT32)(s); + break; + case 3: + m_reg[rd] = (UINT32)(s); + break; + } + } + break; + } + + case 0xea: + case 0xeb: // fcmp + { + int rd = OP_RD(); + int p1 = m_ir & (1 << 5); + int p2 = m_ir & (1 << 7); + int rs1 = OP_SRC1(); + int rs2 = OP_RS(); + + double src1 = has_imm ? (double)(u2f(imm32)) : (p1 ? u2d(m_fpair[rs1 >> 1]) : (double)u2f(m_reg[rs1])); + double src2 = p2 ? u2d(m_fpair[rs2 >> 1]) : (double)u2f(m_reg[rs2]); + + if (rd) + { + UINT32 flags = 0; + flags |= (src1 == src2) ? (1 << 20) : 0; + flags |= (src1 != src2) ? (1 << 21) : 0; + flags |= (src1 > src2) ? (1 << 22) : 0; + flags |= (src1 <= src2) ? (1 << 23) : 0; + flags |= (src1 < src2) ? (1 << 24) : 0; + flags |= (src1 >= src2) ? (1 << 25) : 0; + flags |= (src1 < 0 || src1 > src2) ? (1 << 26) : 0; + flags |= (src1 > 0 && src1 < src2) ? (1 << 27) : 0; + flags |= (src1 >= 0 && src1 <= src2) ? (1 << 28) : 0; + flags |= (src1 <= 0 || src1 >= src2) ? (1 << 29) : 0; + // TODO: src1 or src2 unordered + // TODO: src1 and src2 ordered + + m_reg[rd] = flags; + } + break; + } + + case 0xee: + case 0xef: // fsqrt + { + int rd = OP_RD(); + int src1 = OP_SRC1(); + int p1 = m_ir & (1 << 5); + int pd = m_ir & (1 << 9); + double source = has_imm ? (double)u2f(imm32) : (p1 ? u2d(m_fpair[src1 >> 1]) : (double)u2f(m_reg[src1])); + + if (rd) + { + double res = sqrt(source); + + if (pd) + m_fpair[rd >> 1] = d2u(res); + else + m_reg[rd] = f2u((float)res); + } + break; + } + + case 0xf2: // rmo + { + UINT32 source = m_reg[OP_RS()]; + int rd = OP_RD(); + + int bit = 32; + + for (int i=0; i < 32; i++) + { + if (source & (1 << (31-i))) + { + bit = i; + break; + } + } + + if (rd) + m_reg[rd] = bit; + break; + } + + default: + fatalerror("execute_reg_long_imm(): %08X: opcode %08X (%02X)", m_pc, m_ir, (m_ir >> 12) & 0xff); + } +} + + +void tms32082_mp_device::execute() +{ + switch ((m_ir >> 20) & 3) + { + case 0: + case 1: + case 2: + execute_short_imm(); + break; + + case 3: + execute_reg_long_imm(); + break; + } +} diff --git a/src/devices/cpu/tms32082/tms32082.c b/src/devices/cpu/tms32082/tms32082.c new file mode 100644 index 00000000000..6ce5a2e2c80 --- /dev/null +++ b/src/devices/cpu/tms32082/tms32082.c @@ -0,0 +1,597 @@ +// license:BSD-3-Clause +// copyright-holders:Ville Linde +/* + Texas Instruments TMS320C82 DSP Emulator + + Written by Ville Linde + +*/ + +#include "emu.h" +#include "debugger.h" +#include "tms32082.h" + +extern CPU_DISASSEMBLE(tms32082_mp); +extern CPU_DISASSEMBLE(tms32082_pp); + +const device_type TMS32082_MP = &device_creator; +const device_type TMS32082_PP = &device_creator; + + + + +// Master Processor + +// internal memory map +static ADDRESS_MAP_START(mp_internal_map, AS_PROGRAM, 32, tms32082_mp_device) + AM_RANGE(0x00000000, 0x00000fff) AM_RAM AM_SHARE("pp0_data0") + AM_RANGE(0x00001000, 0x00001fff) AM_RAM AM_SHARE("pp1_data0") + AM_RANGE(0x00008000, 0x00008fff) AM_RAM AM_SHARE("pp0_data1") + AM_RANGE(0x00009000, 0x00009fff) AM_RAM AM_SHARE("pp1_data1") + AM_RANGE(0x01000000, 0x01000fff) AM_RAM AM_SHARE("pp0_param") + AM_RANGE(0x01001000, 0x01001fff) AM_RAM AM_SHARE("pp1_param") + AM_RANGE(0x01010000, 0x010107ff) AM_READWRITE(mp_param_r, mp_param_w) +ADDRESS_MAP_END + +const UINT32 tms32082_mp_device::SHIFT_MASK[] = +{ + 0x00000000, 0x00000001, 0x00000003, 0x00000007, 0x0000000f, 0x0000001f, 0x0000003f, 0x0000007f, + 0x000000ff, 0x000001ff, 0x000003ff, 0x000007ff, 0x00000fff, 0x00001fff, 0x00003fff, 0x00007fff, + 0x0000ffff, 0x0001ffff, 0x0003ffff, 0x0007ffff, 0x000fffff, 0x001fffff, 0x003fffff, 0x007fffff, + 0x00ffffff, 0x01ffffff, 0x03ffffff, 0x07ffffff, 0x0fffffff, 0x1fffffff, 0x3fffffff, 0x7fffffff, + 0xffffffff +}; + + + +tms32082_mp_device::tms32082_mp_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : cpu_device(mconfig, TMS32082_MP, "TMS32082 MP", tag, owner, clock, "tms32082_mp", __FILE__) + , m_program_config("program", ENDIANNESS_BIG, 32, 32, 0, ADDRESS_MAP_NAME(mp_internal_map)) +{ +} + + +offs_t tms32082_mp_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + return CPU_DISASSEMBLE_NAME(tms32082_mp)(this, buffer, pc, oprom, opram, options); +} + + + +READ32_MEMBER(tms32082_mp_device::mp_param_r) +{ + //printf("mp_param_w: %08X, %08X\n", offset, mem_mask); + return m_param_ram[offset]; +} + +WRITE32_MEMBER(tms32082_mp_device::mp_param_w) +{ + //printf("mp_param_w: %08X, %08X, %08X\n", offset, data, mem_mask); + + COMBINE_DATA(&m_param_ram[offset]); + + if (offset == 0x3f) + { + // initiate Transfer Controller operation + // TODO: move TC functionality to separate device + UINT32 address = data; + + UINT32 next_entry = m_program->read_dword(address + 0); + UINT32 pt_options = m_program->read_dword(address + 4); + UINT32 src_addr = m_program->read_dword(address + 8); + UINT32 dst_addr = m_program->read_dword(address + 12); + UINT32 src_b_count = m_program->read_word(address + 16); + UINT32 src_a_count = m_program->read_word(address + 18); + UINT32 dst_b_count = m_program->read_word(address + 20); + UINT32 dst_a_count = m_program->read_word(address + 22); + UINT32 src_c_count = m_program->read_dword(address + 24); + UINT32 dst_c_count = m_program->read_dword(address + 28); + UINT32 src_b_pitch = m_program->read_dword(address + 32); + UINT32 dst_b_pitch = m_program->read_dword(address + 36); + UINT32 src_c_pitch = m_program->read_dword(address + 40); + UINT32 dst_c_pitch = m_program->read_dword(address + 44); + + printf("TC operation:\n"); + printf(" Next entry: %08X\n", next_entry); + printf(" PT options: %08X\n", pt_options); + printf(" SRC addr: %08X\n", src_addr); + printf(" DST addr: %08X\n", dst_addr); + printf(" SRC count A: %04X, B: %04X\n", src_a_count, src_b_count); + printf(" DST count A: %04X, B: %04X\n", dst_a_count, dst_b_count); + printf(" SRC count C: %08X\n", src_c_count); + printf(" DST count C: %08X\n", dst_c_count); + printf(" SRC B pitch: %08X\n", src_b_pitch); + printf(" DST B pitch: %08X\n", dst_b_pitch); + printf(" SRC C pitch: %08X\n", src_c_pitch); + printf(" DST C pitch: %08X\n", dst_c_pitch); + + if (pt_options != 0x80000000) + fatalerror("TC transfer, options = %08X\n", pt_options); + + for (int ic = 0; ic <= src_c_count; ic++) + { + UINT32 c_src_offset = ic * src_c_pitch; + UINT32 c_dst_offset = ic * dst_c_pitch; + + for (int ib = 0; ib <= src_b_count; ib++) + { + UINT32 b_src_offset = ib * src_b_pitch; + UINT32 b_dst_offset = ib * dst_b_pitch; + + for (int ia = 0; ia < src_a_count; ia++) + { + UINT32 src = src_addr + c_src_offset + b_src_offset + ia; + UINT32 dst = dst_addr + c_dst_offset + b_dst_offset + ia; + + UINT32 data = m_program->read_byte(src); + m_program->write_byte(dst, data); + + //printf("%08X: %02X -> %08X\n", src, data, dst); + } + } + } + } +} + + + +void tms32082_mp_device::device_start() +{ + m_program = &space(AS_PROGRAM); + + save_item(NAME(m_pc)); + save_item(NAME(m_fetchpc)); + save_item(NAME(m_reg)); + save_item(NAME(m_acc)); + + save_item(NAME(m_in0p)); + save_item(NAME(m_in1p)); + save_item(NAME(m_outp)); + save_item(NAME(m_ie)); + save_item(NAME(m_intpen)); + + // Register state for debugger + state_add(MP_PC, "pc", m_pc).formatstr("%08X"); + + state_add(MP_R0, "r0", m_reg[0]).formatstr("%08X"); + state_add(MP_R1, "r1", m_reg[1]).formatstr("%08X"); + state_add(MP_R2, "r2", m_reg[2]).formatstr("%08X"); + state_add(MP_R3, "r3", m_reg[3]).formatstr("%08X"); + state_add(MP_R4, "r4", m_reg[4]).formatstr("%08X"); + state_add(MP_R5, "r5", m_reg[5]).formatstr("%08X"); + state_add(MP_R6, "r6", m_reg[6]).formatstr("%08X"); + state_add(MP_R7, "r7", m_reg[7]).formatstr("%08X"); + state_add(MP_R8, "r8", m_reg[8]).formatstr("%08X"); + state_add(MP_R9, "r9", m_reg[9]).formatstr("%08X"); + state_add(MP_R10, "r10", m_reg[10]).formatstr("%08X"); + state_add(MP_R11, "r11", m_reg[11]).formatstr("%08X"); + state_add(MP_R12, "r12", m_reg[12]).formatstr("%08X"); + state_add(MP_R13, "r13", m_reg[13]).formatstr("%08X"); + state_add(MP_R14, "r14", m_reg[14]).formatstr("%08X"); + state_add(MP_R15, "r15", m_reg[15]).formatstr("%08X"); + state_add(MP_R16, "r16", m_reg[16]).formatstr("%08X"); + state_add(MP_R17, "r17", m_reg[17]).formatstr("%08X"); + state_add(MP_R18, "r18", m_reg[18]).formatstr("%08X"); + state_add(MP_R19, "r19", m_reg[19]).formatstr("%08X"); + state_add(MP_R20, "r20", m_reg[20]).formatstr("%08X"); + state_add(MP_R21, "r21", m_reg[21]).formatstr("%08X"); + state_add(MP_R22, "r22", m_reg[22]).formatstr("%08X"); + state_add(MP_R23, "r23", m_reg[23]).formatstr("%08X"); + state_add(MP_R24, "r24", m_reg[24]).formatstr("%08X"); + state_add(MP_R25, "r25", m_reg[25]).formatstr("%08X"); + state_add(MP_R26, "r26", m_reg[26]).formatstr("%08X"); + state_add(MP_R27, "r27", m_reg[27]).formatstr("%08X"); + state_add(MP_R28, "r28", m_reg[28]).formatstr("%08X"); + state_add(MP_R29, "r29", m_reg[29]).formatstr("%08X"); + state_add(MP_R30, "r30", m_reg[30]).formatstr("%08X"); + state_add(MP_R31, "r31", m_reg[31]).formatstr("%08X"); + + state_add(MP_ACC0, "acc0", m_acc[0]).formatstr("%016X"); + state_add(MP_ACC1, "acc1", m_acc[1]).formatstr("%016X"); + state_add(MP_ACC2, "acc2", m_acc[2]).formatstr("%016X"); + state_add(MP_ACC3, "acc3", m_acc[3]).formatstr("%016X"); + + state_add(MP_IN0P, "in0p", m_in0p).formatstr("%08X"); + state_add(MP_IN1P, "in1p", m_in1p).formatstr("%08X"); + state_add(MP_OUTP, "outp", m_outp).formatstr("%08X"); + state_add(MP_IE, "ie", m_ie).formatstr("%08X"); + state_add(MP_INTPEN, "intpen", m_intpen).formatstr("%08X"); + + state_add(MP_TCOUNT, "tcount", m_tcount).formatstr("%08X"); + state_add(MP_TSCALE, "tscale", m_tscale).formatstr("%08X"); + + state_add(STATE_GENPC, "curpc", m_pc).noshow(); + + m_program = &space(AS_PROGRAM); + m_direct = &m_program->direct(); + + m_icountptr = &m_icount; +} + +void tms32082_mp_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + switch (entry.index()) + { + case STATE_GENFLAGS: + strprintf(str, "?"); + break; + } +} + +void tms32082_mp_device::device_reset() +{ + m_pc = 0; + m_fetchpc = 0xfffffff8; + + for (int i=0; i < 32; i++) + { + m_reg[i] = 0; + } + + m_acc[0] = 0; + m_acc[1] = 0; + m_acc[2] = 0; + m_acc[3] = 0; + + m_in0p = 0; + m_in1p = 0; + m_outp = 0; + + m_intpen = 0; + m_ie = 0; +} + +void tms32082_mp_device::processor_command(UINT32 command) +{ + printf("MP CMND %08X: ", command); + + if (command & 0x80000000) + printf("Reset "); + if (command & 0x40000000) + printf("Halt "); + if (command & 0x20000000) + printf("Unhalt "); + if (command & 0x10000000) + printf("ICR "); + if (command & 0x08000000) + printf("DCR "); + if (command & 0x00004000) + printf("Task "); + if (command & 0x00002000) + printf("Msg "); + + printf("to: "); + + if (command & 0x00000400) + printf("VC "); + if (command & 0x00000200) + printf("TC "); + if (command & 0x00000100) + printf("MP "); + if (command & 0x00000008) + printf("PP3 "); + if (command & 0x00000004) + printf("PP2 "); + if (command & 0x00000002) + printf("PP1 "); + if (command & 0x00000001) + printf("PP0 "); + + printf("\n"); + + // PP0 + if (command & 1) + { + if (command & 0x00004000) + { + // simulate PP behavior for now... + m_program->write_dword(0x00000084, 3); + + UINT32 num = m_program->read_dword(0x90); + + printf("PP num %d\n", num); + + /* + UINT32 ra = 0x1000280; + + printf("FIFO push:\n"); + + for (int i=0; i < num; i++) + { + printf("Entry %d:\n", i); + for (int k=0; k < 6; k++) + { + for (int l=0; l < 4; l++) + { + UINT32 dd = m_program->read_dword(ra); + ra += 4; + + printf("%08X(%f) ", dd, u2f(dd)); + } + printf("\n"); + } + printf("\n"); + } + */ + + UINT32 ra = 0x1000280; + + int oldnum = m_program->read_dword(0x600ffffc); + UINT32 rb = 0x60000000 + (oldnum * 0x60); + + for (int i=0; i < num; i++) + { + for (int k=0; k < 24; k++) + { + UINT32 dd = m_program->read_dword(ra); + ra += 4; + + m_program->write_dword(rb, dd); + rb += 4; + } + } + m_program->write_dword(0x600ffffc, oldnum+num); + + m_program->write_dword(0x00000090, 0); + m_program->write_dword(0x00000094, num); + + } + } + // PP1 + if (command & 2) + { + if (command & 0x00004000) + { + // simulate PP behavior for now... + m_program->write_dword(0x00001014, 3); + } + } +} + +UINT32 tms32082_mp_device::read_creg(int reg) +{ + switch (reg) + { + case 0x0: // EPC + return m_epc; + + case 0x1: // EIP + return m_eip; + + case 0x4: // INTPEN + return m_intpen; + + case 0x6: // IE + return m_ie; + + case 0xa: // PPERROR + return 0xe0000; + + case 0xe: // TCOUNT + return m_tcount; + + case 0x4000: // IN0P + return m_in0p; + + case 0x4001: // IN1P + return m_in1p; + + case 0x4002: // OUTP + return m_outp; + + default: + printf("read_creg(): %08X\n", reg); + break; + } + return 0; +} + +void tms32082_mp_device::write_creg(int reg, UINT32 data) +{ + switch (reg) + { + case 0x0: // EPC + m_epc = data; + break; + + case 0x1: // EIP + m_eip = data; + break; + + case 0x4: // INTPEN + { + for (int i=0; i < 32; i++) + { + if (data & (1 << i)) + m_intpen &= ~(1 << i); + } + break; + } + + case 0x6: // IE + m_ie = data; + printf("IE = %08X\n", data); + break; + + case 0xe: // TCOUNT + m_tcount = data; + break; + + case 0x4000: // IN0P + m_in0p = data; + break; + + case 0x4001: // IN1P + m_in1p = data; + break; + + case 0x4002: // OUTP + m_outp = data; + break; + + default: + printf("write_creg(): %08X, %08X\n", reg, data); + break; + } +} + +void tms32082_mp_device::check_interrupts() +{ + if (m_ie & 1) // global interrupt mask + { + for (int i=1; i < 32; i++) + { + if (m_ie & m_intpen & (1 << i)) + { + m_epc = (m_fetchpc & ~3); + m_epc |= (m_ie & 1); // save global interrupt mask + // TODO: user mode bit to EPC + + m_eip = m_pc; + + m_ie &= ~1; // clear global interrupt mask + + // get new pc from vector table + m_fetchpc = m_pc = m_program->read_dword(0x01010180 + (i * 4)); + return; + } + } + } +} + +void tms32082_mp_device::execute_set_input(int inputnum, int state) +{ + if (state == ASSERT_LINE) + { + switch (inputnum) + { + case INPUT_X1: + m_intpen |= (1 << 11); + break; + case INPUT_X2: + m_intpen |= (1 << 12); + break; + case INPUT_X3: + m_intpen |= (1 << 29); + break; + case INPUT_X4: + m_intpen |= (1 << 30); + break; + default: + break; + } + } +} + +UINT32 tms32082_mp_device::fetch() +{ + UINT32 w = m_direct->read_dword(m_fetchpc); + m_fetchpc += 4; + return w; +} + +void tms32082_mp_device::delay_slot() +{ + debugger_instruction_hook(this, m_pc); + m_ir = fetch(); + execute(); + + m_icount--; +} + +void tms32082_mp_device::execute_run() +{ + while (m_icount > 0) + { + m_pc = m_fetchpc; + + check_interrupts(); + + debugger_instruction_hook(this, m_pc); + + m_ir = fetch(); + execute(); + + m_tcount--; + if (m_tcount < 0) + { + // TODO: timer interrupt + m_tcount = m_tscale; + } + + m_icount--; + }; + + return; +} + + + + +// Parallel Processor + +// internal memory map +static ADDRESS_MAP_START(pp_internal_map, AS_PROGRAM, 32, tms32082_pp_device) + AM_RANGE(0x00000000, 0x00000fff) AM_RAM AM_SHARE("pp0_data0") + AM_RANGE(0x00001000, 0x00001fff) AM_RAM AM_SHARE("pp1_data0") + AM_RANGE(0x00008000, 0x00008fff) AM_RAM AM_SHARE("pp0_data1") + AM_RANGE(0x00009000, 0x00009fff) AM_RAM AM_SHARE("pp1_data1") + AM_RANGE(0x01000000, 0x01000fff) AM_RAM AM_SHARE("pp0_param") + AM_RANGE(0x01001000, 0x01001fff) AM_RAM AM_SHARE("pp1_param") +ADDRESS_MAP_END + +tms32082_pp_device::tms32082_pp_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : cpu_device(mconfig, TMS32082_PP, "TMS32082 PP", tag, owner, clock, "tms32082_pp", __FILE__) + , m_program_config("program", ENDIANNESS_BIG, 32, 32, 0, ADDRESS_MAP_NAME(pp_internal_map)) +{ +} + + +offs_t tms32082_pp_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + return CPU_DISASSEMBLE_NAME(tms32082_pp)(this, buffer, pc, oprom, opram, options); +} + +void tms32082_pp_device::device_start() +{ + m_program = &space(AS_PROGRAM); + + save_item(NAME(m_pc)); + save_item(NAME(m_fetchpc)); + + // Register state for debugger + state_add(PP_PC, "pc", m_pc).formatstr("%08X"); + + state_add(STATE_GENPC, "curpc", m_pc).noshow(); + + m_program = &space(AS_PROGRAM); + m_direct = &m_program->direct(); + + m_icountptr = &m_icount; +} + +void tms32082_pp_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + switch (entry.index()) + { + case STATE_GENFLAGS: + strprintf(str, "?"); + break; + } +} + +void tms32082_pp_device::device_reset() +{ + m_pc = 0; + m_fetchpc = 0x400010a0; +} + +void tms32082_pp_device::execute_run() +{ + m_pc = m_fetchpc; + debugger_instruction_hook(this, m_pc); + + m_icount = 0; + + return; +} diff --git a/src/devices/cpu/tms32082/tms32082.h b/src/devices/cpu/tms32082/tms32082.h new file mode 100644 index 00000000000..494f1580504 --- /dev/null +++ b/src/devices/cpu/tms32082/tms32082.h @@ -0,0 +1,214 @@ +// license:BSD-3-Clause +// copyright-holders:Ville Linde +#pragma once + +#ifndef __TMS32082_H__ +#define __TMS32082_H__ + +// Master Processor class +class tms32082_mp_device : public cpu_device +{ +public: + // construction/destruction + tms32082_mp_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + enum + { + MP_PC=1, + MP_R0, + MP_R1, + MP_R2, + MP_R3, + MP_R4, + MP_R5, + MP_R6, + MP_R7, + MP_R8, + MP_R9, + MP_R10, + MP_R11, + MP_R12, + MP_R13, + MP_R14, + MP_R15, + MP_R16, + MP_R17, + MP_R18, + MP_R19, + MP_R20, + MP_R21, + MP_R22, + MP_R23, + MP_R24, + MP_R25, + MP_R26, + MP_R27, + MP_R28, + MP_R29, + MP_R30, + MP_R31, + MP_ACC0, + MP_ACC1, + MP_ACC2, + MP_ACC3, + MP_IN0P, + MP_IN1P, + MP_OUTP, + MP_IE, + MP_INTPEN, + MP_TCOUNT, + MP_TSCALE + }; + + enum + { + INPUT_X1 = 1, + INPUT_X2 = 2, + INPUT_X3 = 3, + INPUT_X4 = 4 + }; + + DECLARE_READ32_MEMBER(mp_param_r); + DECLARE_WRITE32_MEMBER(mp_param_w); + + +protected: + // device level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_execute_interface overrides + virtual UINT32 execute_min_cycles() const { return 1; } + virtual UINT32 execute_max_cycles() const { return 1; } + virtual UINT32 execute_input_lines() const { return 0; } + virtual void execute_run(); + virtual void execute_set_input(int inputnum, int state); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const + { + switch (spacenum) + { + case AS_PROGRAM: return &m_program_config; + default: return NULL; + } + } + + // device_state_interface overrides + void state_string_export(const device_state_entry &entry, std::string &str); + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const { return 4; } + virtual UINT32 disasm_max_opcode_bytes() const { return 8; } + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + + address_space_config m_program_config; + + static const UINT32 SHIFT_MASK[33]; + + + UINT32 m_pc; + UINT32 m_fetchpc; + union + { + UINT32 m_reg[32]; + UINT64 m_fpair[16]; + }; + union + { + UINT64 m_acc[4]; + double m_facc[4]; + }; + UINT32 m_ir; + + UINT32 m_in0p; + UINT32 m_in1p; + UINT32 m_outp; + UINT32 m_ie; + UINT32 m_intpen; + UINT32 m_epc; + UINT32 m_eip; + + UINT32 m_tcount; + UINT32 m_tscale; + + UINT32 m_param_ram[0x800]; + + int m_icount; + + address_space *m_program; + direct_read_data* m_direct; + + void check_interrupts(); + void processor_command(UINT32 command); + UINT32 fetch(); + void delay_slot(); + void execute(); + void execute_short_imm(); + void execute_reg_long_imm(); + UINT32 read_creg(int reg); + void write_creg(int reg, UINT32 data); + bool test_condition(int condition, UINT32 value); + UINT32 calculate_cmp(UINT32 src1, UINT32 src2); + void vector_loadstore(); +}; + + +// Parallel Processor class +class tms32082_pp_device : public cpu_device +{ +public: + // construction/destruction + tms32082_pp_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + enum + { + PP_PC = 1 + }; + +protected: + // device level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_execute_interface overrides + virtual UINT32 execute_min_cycles() const { return 1; } + virtual UINT32 execute_max_cycles() const { return 1; } + virtual UINT32 execute_input_lines() const { return 0; } + virtual void execute_run(); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const + { + switch (spacenum) + { + case AS_PROGRAM: return &m_program_config; + default: return NULL; + } + } + + // device_state_interface overrides + void state_string_export(const device_state_entry &entry, std::string &str); + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const { return 8; } + virtual UINT32 disasm_max_opcode_bytes() const { return 8; } + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + + address_space_config m_program_config; + + UINT32 m_pc; + UINT32 m_fetchpc; + + int m_icount; + + address_space *m_program; + direct_read_data* m_direct; +}; + + +extern const device_type TMS32082_MP; +extern const device_type TMS32082_PP; + + +#endif /* __TMS32082_H__ */ diff --git a/src/devices/cpu/tms34010/34010dsm.c b/src/devices/cpu/tms34010/34010dsm.c new file mode 100644 index 00000000000..15136885da4 --- /dev/null +++ b/src/devices/cpu/tms34010/34010dsm.c @@ -0,0 +1,1761 @@ +// license:BSD-3-Clause +// copyright-holders:Zsolt Vasvari +/* + * A TMS34010 disassembler + * + * This code written by Zsolt Vasvari for the MAME project + * + */ + +#include "emu.h" + +#ifdef STANDALONE +#define PC __pc + (offset << 3) +#define OP_WORD(v) { v = filebuf[_pc>>3]; _pc += 8; v = v | (filebuf[_pc>>3] << 8); _pc += 8;} +#define PARAM_WORD(v) { v = filebuf[_pc>>3]; _pc += 8; v = v | (filebuf[_pc>>3] << 8); _pc += 8;} +#define PARAM_LONG(v) { int v1, v2; PARAM_WORD(v1); PARAM_WORD(v2); v = v1 | (v2 << 16); } +#else +#define PC __pc +#define OP_WORD(v) { v = rombase[(__pc - pcbase) >> 3] | (rombase[(__pc + 8 - pcbase) >> 3] << 8); _pc += 16; } +#define PARAM_WORD(v) { v = rambase[(__pc + 16 - pcbase) >> 3] | (rambase[(__pc + 24 - pcbase) >> 3] << 8); _pc += 16; } +#define PARAM_LONG(v) { v = rambase[(__pc + 16 - pcbase) >> 3] | (rambase[(__pc + 24 - pcbase) >> 3] << 8) | (rambase[(__pc + 32 - pcbase) >> 3] << 16) | (rambase[(__pc + 40 - pcbase) >> 3] << 24); _pc += 32; } +#endif + +static UINT8 rf; +static UINT32 __pc, _pc; +static UINT16 op,rs,rd; + +static char *buffer; +static char temp[20]; + +static const UINT8 *rombase; +static const UINT8 *rambase; +static offs_t pcbase; + + +static void print_reg(UINT8 reg) +{ + if (reg != 0x0f) + { + sprintf(temp, "%c%d", rf, reg); + strcat(buffer, temp); + } + else + { + strcat(buffer, "SP"); + } +} + +static void print_src_reg(void) +{ + print_reg(rs); +} + +static void print_des_reg(void) +{ + print_reg(rd); +} + +static void print_src_des_reg(void) +{ + print_src_reg(); + strcat(buffer, ","); + print_des_reg(); +} + +static void print_word_parm(void) +{ + UINT16 w; + + PARAM_WORD(w); + + sprintf(temp, "%Xh", w); + strcat(buffer, temp); +} + +static void print_word_parm_1s_comp(void) +{ + UINT16 w; + + PARAM_WORD(w); + w = ~w; + sprintf(temp, "%Xh", w); + strcat(buffer, temp); +} + +static void print_long_parm(void) +{ + UINT32 l; + + PARAM_LONG(l); + sprintf(temp, "%Xh", l); + strcat(buffer, temp); +} + +static void print_long_parm_1s_comp(void) +{ + UINT32 l; + + PARAM_LONG(l); + sprintf(temp, "%Xh", ~l); + strcat(buffer, temp); +} + +static void print_constant(void) +{ + UINT8 constant = (op >> 5) & 0x1f; + + sprintf(temp, "%Xh", constant); + strcat(buffer, temp); +} + +static void print_constant_1_32(void) +{ + UINT8 constant = (op >> 5) & 0x1f; + if (!constant) constant = 0x20; + + sprintf(temp, "%Xh", constant); + strcat(buffer, temp); +} + +static void print_constant_1s_comp(void) +{ + UINT8 constant = (~op >> 5) & 0x1f; + + sprintf(temp, "%Xh", constant); + strcat(buffer, temp); +} + +static void print_constant_2s_comp(void) +{ + UINT8 constant = 32 - ((op >> 5) & 0x1f); + + sprintf(temp, "%Xh", constant); + strcat(buffer, temp); +} + +static void print_relative(void) +{ + UINT16 l; + INT16 ls; + + PARAM_WORD(l); + ls = (INT16)l; + + sprintf(temp, "%Xh", PC + 32 + (ls << 4)); + strcat(buffer, temp); +} + +static void print_relative_8bit(void) +{ + INT8 ls = (INT8)op; + + sprintf(temp, "%Xh", PC + 16 + (ls << 4)); + strcat(buffer, temp); +} + +static void print_relative_5bit(void) +{ + INT8 ls = (INT8)((op >> 5) & 0x1f); + if (op & 0x0400) ls = -ls; + + sprintf(temp, "%Xh", PC + 16 + (ls << 4)); + strcat(buffer, temp); +} + +static void print_field(void) +{ + sprintf(temp, "%c", (op & 0x200) ? '1' : '0'); + strcat(buffer, temp); +} + +static void print_condition_code(void) +{ + switch (op & 0x0f00) + { + case 0x0000: strcat(buffer, " "); break; /* This is really UC (Unconditional) */ + case 0x0100: strcat(buffer, "P "); break; + case 0x0200: strcat(buffer, "LS"); break; + case 0x0300: strcat(buffer, "HI"); break; + case 0x0400: strcat(buffer, "LT"); break; + case 0x0500: strcat(buffer, "GE"); break; + case 0x0600: strcat(buffer, "LE"); break; + case 0x0700: strcat(buffer, "GT"); break; + case 0x0800: strcat(buffer, "C "); break; + case 0x0900: strcat(buffer, "NC"); break; + case 0x0a00: strcat(buffer, "EQ"); break; + case 0x0b00: strcat(buffer, "NE"); break; + case 0x0c00: strcat(buffer, "V "); break; + case 0x0d00: strcat(buffer, "NV"); break; + case 0x0e00: strcat(buffer, "N "); break; + case 0x0f00: strcat(buffer, "NN"); break; + } +} + +static void print_reg_list_range(INT8 first, INT8 last) +{ + if ((first != -1 ) && (first != last)) + { + if ((last - first) == 1) + strcat(buffer, ","); + else + strcat(buffer, "-"); + print_reg(last); + } +} + +static void print_reg_list(UINT16 rev) +{ + UINT16 l; + UINT8 i; + INT8 first = -1, last = 0; + + PARAM_WORD(l); + + for (i = 0; i < 16; i++) + { + int moved; + + if (rev) + { + moved = l & 0x8000; + l <<= 1; + } + else + { + moved = l & 0x01; + l >>= 1; + } + + if (moved) + { + if (first == -1) + { + strcat(buffer, ","); + print_reg(i); + first = i; + } + last = i; + } + else + { + print_reg_list_range(first, last); + first = -1; + } + } + + print_reg_list_range(first, last); +} + + +static unsigned Dasm340x0(char *buff, UINT32 pc, int is_34020) +{ + int flags = 0; + UINT8 bad = 0; + UINT16 subop; + + __pc = _pc = pc; + buffer = buff; + + OP_WORD(op); + + subop = (op & 0x01e0); + rs = (op >> 5) & 0x0f; /* Source register */ + rd = op & 0x0f; /* Destination register */ + rf = ((op & 0x10) ? 'B' : 'A'); /* Register file */ + + switch (op & 0xfe00) + { + case 0x0000: + switch (subop) + { + case 0x0020: + sprintf (buffer, "REV "); + print_des_reg(); + break; + + case 0x0040: + if (is_34020) + sprintf (buffer, "IDLE "); + else + bad = 1; + break; + + case 0x0080: + if (is_34020) + sprintf (buffer, "MWAIT "); + else + bad = 1; + break; + + case 0x00e0: + if (is_34020) + sprintf (buffer, "BLMOVE %d,%d", (op >> 1) & 1, op & 1); + else + bad = 1; + break; + + case 0x0100: + sprintf (buffer, "EMU "); + break; + + case 0x0120: + sprintf (buffer, "EXGPC "); + print_des_reg(); + break; + + case 0x0140: + sprintf (buffer, "GETPC "); + print_des_reg(); + break; + + case 0x0160: + sprintf (buffer, "JUMP "); + print_des_reg(); + break; + + case 0x0180: + sprintf (buffer, "GETST "); + print_des_reg(); + break; + + case 0x01a0: + sprintf (buffer, "PUTST "); + print_des_reg(); + break; + + case 0x01c0: + sprintf (buffer, "POPST "); + break; + + case 0x01e0: + sprintf (buffer, "PUSHST "); + break; + + default: + bad = 1; + } + break; + + + case 0x0200: + switch (subop) + { + case 0x0040: + if (is_34020) + sprintf (buffer, "SETCSP "); + else + bad = 1; + break; + + case 0x0060: + if (is_34020) + sprintf (buffer, "SETCDP "); + else + bad = 1; + break; + + case 0x0080: + if (is_34020) + { + sprintf (buffer, "RPIX "); + print_des_reg(); + } + else + bad = 1; + break; + + case 0x00a0: + if (is_34020) + { + sprintf (buffer, "EXGPS "); + print_des_reg(); + } + else + bad = 1; + break; + + case 0x00c0: + if (is_34020) + { + sprintf (buffer, "GETPS "); + print_des_reg(); + } + else + bad = 1; + break; + + case 0x00e0: + if (is_34020) + sprintf (buffer, "SETCMP "); + else + bad = 1; + break; + + case 0x0100: + sprintf (buffer, "NOP "); + break; + + case 0x0120: + sprintf (buffer, "CLRC "); + break; + + case 0x0140: + sprintf (buffer, "MOVB @"); + print_long_parm(); + strcat(buffer, ",@"); + print_long_parm(); + break; + + case 0x0160: + sprintf (buffer, "DINT "); + break; + + case 0x0180: + sprintf (buffer, "ABS "); + print_des_reg(); + break; + + case 0x01a0: + sprintf (buffer, "NEG "); + print_des_reg(); + break; + + case 0x01c0: + sprintf (buffer, "NEGB "); + print_des_reg(); + break; + + case 0x01e0: + sprintf (buffer, "NOT "); + print_des_reg(); + break; + + default: + bad = 1; + } + break; + + + case 0x0400: + case 0x0600: + switch (subop) + { + case 0x0000: + if (is_34020 && (op & 0xfe00) == 0x0600) + { + UINT32 x; + PARAM_LONG(x); + sprintf(buffer, "CEXEC %d,%06X,%d", (x >> 7) & 1, (x >> 8) & 0x1fffff, (x >> 29) & 7); + } + else + bad = 1; + break; + + case 0x0020: + if (is_34020 && (op & 0xfe00) == 0x0600) + { + UINT32 x; + PARAM_LONG(x); + sprintf(buffer, "CMOVGC "); + print_des_reg(); + sprintf(temp, ",%06X,%d", (x >> 8) & 0x1fffff, (x >> 29) & 7); + strcat(buffer, temp); + } + else + bad = 1; + break; + + case 0x0040: + if (is_34020 && (op & 0xfe00) == 0x0600) + { + UINT32 x; + PARAM_LONG(x); + sprintf(buffer, "CMOVGC "); + print_des_reg(); + strcat(buffer, ","); + rf = (x & 0x10) ? 'B' : 'A'; + print_reg(x & 0x0f); + sprintf(temp, ",%d,%06X,%d", (x >> 7) & 1, (x >> 8) & 0x1fffff, (x >> 29) & 7); + strcat(buffer, temp); + } + else + bad = 1; + break; + + case 0x0060: + if (is_34020 && (op & 0xfe00) == 0x0600) + { + UINT32 x; + PARAM_LONG(x); + + if (op == 0x0660 && (x & 0xff) == 0x01) + { + sprintf(buffer, "CMOVCS "); + sprintf(temp, ",%06X,%d", (x >> 8) & 0x1fffff, (x >> 29) & 7); + strcat(buffer, temp); + } + else + { + sprintf(buffer, "CMOVCG "); + print_des_reg(); + strcat(buffer, ","); + rf = (x & 0x10) ? 'B' : 'A'; + print_reg(x & 0x0f); + sprintf(temp, ",%d,%06X,%d", (x >> 7) & 1, (x >> 8) & 0x1fffff, (x >> 29) & 7); + strcat(buffer, temp); + } + } + else + bad = 1; + break; + + case 0x0080: + if (is_34020 && (op & 0xfe00) == 0x0600) + { + UINT32 x; + PARAM_LONG(x); + sprintf(buffer, "CMOVMC *"); + rf = (x & 0x10) ? 'B' : 'A'; + print_reg(x & 0x0f); + sprintf(temp, "+,%d,%d,%06X,%d", op & 0x1f, (x >> 7) & 1, (x >> 8) & 0x1fffff, (x >> 29) & 7); + strcat(buffer, temp); + } + else + bad = 1; + break; + + case 0x00a0: + if (is_34020 && (op & 0xfe00) == 0x0600) + { + UINT32 x; + PARAM_LONG(x); + sprintf(buffer, "CMOVCM *"); + print_des_reg(); + sprintf(temp, "+,%d,%d,%06X,%d", x & 0x1f, (x >> 7) & 1, (x >> 8) & 0x1fffff, (x >> 29) & 7); + strcat(buffer, temp); + } + else + bad = 1; + break; + + case 0x00c0: + if (is_34020 && (op & 0xfe00) == 0x0600) + { + UINT32 x; + PARAM_LONG(x); + sprintf(buffer, "CMOVCM *-"); + print_des_reg(); + sprintf(temp, ",%d,%d,%06X,%d", x & 0x1f, (x >> 7) & 1, (x >> 8) & 0x1fffff, (x >> 29) & 7); + strcat(buffer, temp); + } + else + bad = 1; + break; + + case 0x00e0: + if (is_34020 && (op & 0xfe00) == 0x0600) + { + UINT32 x; + PARAM_LONG(x); + sprintf(buffer, "CMOVMC *"); + rf = (x & 0x10) ? 'B' : 'A'; + print_reg(x & 0x0f); + strcat(buffer, "+,"); + rf = (op & 0x10) ? 'B' : 'A'; + print_reg(op & 0x0f); + sprintf(temp, ",%d,%06X,%d", (x >> 7) & 1, (x >> 8) & 0x1fffff, (x >> 29) & 7); + strcat(buffer, temp); + } + else + bad = 1; + break; + + case 0x0100: + sprintf (buffer, "SEXT "); + print_des_reg(); + strcat(buffer, ","); + print_field(); + break; + + case 0x0120: + sprintf (buffer, "ZEXT "); + print_des_reg(); + strcat(buffer, ","); + print_field(); + break; + + case 0x0140: + case 0x0160: + sprintf (buffer, "SETF %Xh,%X,", + (op & 0x1f) ? op & 0x1f : 0x20, + (op >> 5) & 1); + print_field(); + break; + + case 0x0180: + sprintf (buffer, "MOVE "); + print_des_reg(); + strcat(buffer, ",@"); + print_long_parm(); + strcat(buffer, ","); + print_field(); + break; + + case 0x01a0: + sprintf (buffer, "MOVE @"); + print_long_parm(); + strcat(buffer, ","); + print_des_reg(); + strcat(buffer, ","); + print_field(); + break; + + case 0x01c0: + sprintf (buffer, "MOVE @"); + print_long_parm(); + strcat(buffer, ",@"); + print_long_parm(); + strcat(buffer, ","); + print_field(); + break; + + case 0x01e0: + if (op & 0x200) + { + sprintf (buffer, "MOVE @"); + print_long_parm(); + strcat(buffer, ","); + print_des_reg(); + } + else + { + sprintf (buffer, "MOVB "); + print_des_reg(); + strcat(buffer, ",@"); + print_long_parm(); + } + break; + + default: + bad = 1; + } + break; + + + case 0x0800: + switch (subop) + { + case 0x0000: + if (is_34020) + { + sprintf (buffer, "TRAPL "); + flags = DASMFLAG_STEP_OVER; + } + else + bad = 1; + break; + + case 0x0020: + if (is_34020) + { + UINT32 x; + PARAM_LONG(x); + sprintf(buffer, "CMOVMC *-"); + rf = (x & 0x10) ? 'B' : 'A'; + print_reg(x & 0x0f); + sprintf(temp, ",%d,%d,%06X,%d", op & 0x1f, (x >> 7) & 1, (x >> 8) & 0x1fffff, (x >> 29) & 7); + strcat(buffer, temp); + } + else + bad = 1; + break; + + case 0x0040: + if (is_34020) + sprintf (buffer, "VBLT B,L"); + else + bad = 1; + break; + + case 0x0060: + if (is_34020) + { + sprintf(buffer, "RETM "); + flags = DASMFLAG_STEP_OUT; + } + else + bad = 1; + break; + + case 0x00e0: + if (is_34020) + sprintf (buffer, "CLIP "); + else + bad = 1; + break; + + case 0x0100: + sprintf (buffer, "TRAP %Xh", op & 0x1f); + flags = DASMFLAG_STEP_OVER; + break; + + case 0x0120: + sprintf (buffer, "CALL "); + print_des_reg(); + flags = DASMFLAG_STEP_OVER; + break; + + case 0x0140: + sprintf (buffer, "RETI "); + flags = DASMFLAG_STEP_OUT; + break; + + case 0x0160: + sprintf (buffer, "RETS "); + flags = DASMFLAG_STEP_OUT; + if (op & 0x1f) + { + sprintf(temp, "%Xh", op & 0x1f); + strcat(buffer, temp); + } + break; + + case 0x0180: + sprintf (buffer, "MMTM "); + print_des_reg(); + print_reg_list(1); + break; + + case 0x01a0: + sprintf (buffer, "MMFM "); + print_des_reg(); + print_reg_list(0); + break; + + case 0x01c0: + sprintf (buffer, "MOVI "); + print_word_parm(); + strcat(buffer, ","); + print_des_reg(); + break; + + case 0x01e0: + sprintf (buffer, "MOVI "); + print_long_parm(); + strcat(buffer, ","); + print_des_reg(); + break; + + default: + bad = 1; + } + break; + + + case 0x0a00: + switch (subop) + { + case 0x0000: + if (is_34020) + sprintf (buffer, "VLCOL "); + else + bad = 1; + break; + + case 0x0020: + if (is_34020) + sprintf (buffer, "PFILL XY"); + else + bad = 1; + break; + + case 0x0040: + if (is_34020) + sprintf (buffer, "VFILL L"); + else + bad = 1; + break; + + case 0x0060: + if (is_34020) + { + sprintf (buffer, "CVMXYL "); + print_des_reg(); + } + else + bad = 1; + break; + + case 0x0080: + if (is_34020) + { + sprintf (buffer, "CVDXYL "); + print_des_reg(); + } + else + bad = 1; + break; + + case 0x00a0: + if (is_34020) + sprintf (buffer, "FPIXEQ "); + else + bad = 1; + break; + + case 0x00c0: + if (is_34020) + sprintf (buffer, "FPIXNE "); + else + bad = 1; + break; + + case 0x0100: + sprintf (buffer, "ADDI "); + print_word_parm(); + strcat(buffer, ","); + print_des_reg(); + break; + + case 0x0120: + sprintf (buffer, "ADDI "); + print_long_parm(); + strcat(buffer, ","); + print_des_reg(); + break; + + case 0x0140: + sprintf (buffer, "CMPI "); + print_word_parm_1s_comp(); + strcat(buffer, ","); + print_des_reg(); + break; + + case 0x0160: + sprintf (buffer, "CMPI "); + print_long_parm_1s_comp(); + strcat(buffer, ","); + print_des_reg(); + break; + + case 0x0180: + sprintf (buffer, "ANDI "); + print_long_parm_1s_comp(); + strcat(buffer, ","); + print_des_reg(); + break; + + case 0x01a0: + sprintf (buffer, "ORI "); + print_long_parm(); + strcat(buffer, ","); + print_des_reg(); + break; + + case 0x01c0: + sprintf (buffer, "XORI "); + print_long_parm(); + strcat(buffer, ","); + print_des_reg(); + break; + + case 0x01e0: + sprintf (buffer, "SUBI "); + print_word_parm_1s_comp(); + strcat(buffer, ","); + print_des_reg(); + break; + + default: + bad = 1; + } + break; + + + case 0x0c00: + switch (subop) + { + case 0x0000: + if (is_34020) + { + sprintf (buffer, "ADDXYI "); + print_long_parm(); + strcat(buffer, ","); + print_des_reg(); + } + else + bad = 1; + break; + + case 0x0040: + if (is_34020) + sprintf (buffer, "LINIT "); + else + bad = 1; + break; + + case 0x0100: + sprintf (buffer, "SUBI "); + print_long_parm_1s_comp(); + strcat(buffer, ","); + print_des_reg(); + break; + + case 0x0120: + sprintf (buffer, "CALLR "); + print_relative(); + flags = DASMFLAG_STEP_OVER; + break; + + case 0x0140: + sprintf (buffer, "CALLA "); + print_long_parm(); + flags = DASMFLAG_STEP_OVER; + break; + + case 0x0160: + sprintf (buffer, "EINT "); + break; + + case 0x0180: + sprintf (buffer, "DSJ "); + print_des_reg(); + strcat(buffer, ","); + print_relative(); + flags = DASMFLAG_STEP_OVER; + break; + + case 0x01a0: + sprintf (buffer, "DSJEQ "); + print_des_reg(); + strcat(buffer, ","); + print_relative(); + flags = DASMFLAG_STEP_OVER; + break; + + case 0x01c0: + sprintf (buffer, "DSJNE "); + print_des_reg(); + strcat(buffer, ","); + print_relative(); + flags = DASMFLAG_STEP_OVER; + break; + + case 0x01e0: + sprintf (buffer, "SETC "); + break; + + default: + bad = 1; + } + break; + + + case 0x0e00: + flags = DASMFLAG_STEP_OVER; + switch (subop) + { + case 0x0000: + if (is_34020) + sprintf (buffer, "PIXBLT L,M,L"); + else + bad = 1; + break; + + case 0x00e0: + if (is_34020) + sprintf (buffer, "TFILL XY"); + else + bad = 1; + break; + + case 0x0100: + sprintf (buffer, "PIXBLT L,L"); + break; + + case 0x0120: + sprintf (buffer, "PIXBLT L,XY"); + break; + + case 0x0140: + sprintf (buffer, "PIXBLT XY,L"); + break; + + case 0x0160: + sprintf (buffer, "PIXBLT XY,XY"); + break; + + case 0x0180: + sprintf (buffer, "PIXBLT B,L"); + break; + + case 0x01a0: + sprintf (buffer, "PIXBLT B,XY"); + break; + + case 0x01c0: + sprintf (buffer, "FILL L"); + break; + + case 0x01e0: + sprintf (buffer, "FILL XY"); + break; + + default: + bad = 1; + } + break; + + + case 0x1000: + case 0x1200: + if ((op & 0x03e0) != 0x0020) + { + sprintf (buffer, "ADDK "); + print_constant_1_32(); + strcat(buffer, ","); + } + else + { + sprintf (buffer, "INC "); + } + print_des_reg(); + + break; + + + case 0x1400: + case 0x1600: + if ((op & 0x03e0) != 0x0020) + { + sprintf (buffer, "SUBK "); + print_constant_1_32(); + strcat(buffer, ","); + } + else + { + sprintf (buffer, "DEC "); + } + print_des_reg(); + + break; + + + case 0x1800: + case 0x1a00: + sprintf (buffer, "MOVK "); + print_constant_1_32(); + strcat(buffer, ","); + print_des_reg(); + break; + + + case 0x1c00: + case 0x1e00: + sprintf (buffer, "BTST "); + print_constant_1s_comp(); + strcat(buffer, ","); + print_des_reg(); + break; + + + case 0x2000: + case 0x2200: + sprintf (buffer, "SLA "); + print_constant(); + strcat(buffer, ","); + print_des_reg(); + break; + + + case 0x2400: + case 0x2600: + sprintf (buffer, "SLL "); + print_constant(); + strcat(buffer, ","); + print_des_reg(); + break; + + + case 0x2800: + case 0x2a00: + sprintf (buffer, "SRA "); + print_constant_2s_comp(); + strcat(buffer, ","); + print_des_reg(); + break; + + + case 0x2c00: + case 0x2e00: + sprintf (buffer, "SRL "); + print_constant_2s_comp(); + strcat(buffer, ","); + print_des_reg(); + break; + + + case 0x3000: + case 0x3200: + sprintf (buffer, "RL "); + print_constant(); + strcat(buffer, ","); + print_des_reg(); + break; + + case 0x3400: + case 0x3600: + if (is_34020) + { + sprintf (buffer, "CMPK "); + print_constant_1_32(); + strcat(buffer, ","); + print_des_reg(); + } + else + bad = 1; + break; + + case 0x3800: + case 0x3a00: + case 0x3c00: + case 0x3e00: + sprintf (buffer, "DSJS "); + print_des_reg(); + strcat(buffer, ","); + print_relative_5bit(); + flags = DASMFLAG_STEP_OVER; + break; + + + case 0x4000: + sprintf (buffer, "ADD "); + print_src_des_reg(); + break; + + + case 0x4200: + sprintf (buffer, "ADDC "); + print_src_des_reg(); + break; + + + case 0x4400: + sprintf (buffer, "SUB "); + print_src_des_reg(); + break; + + + case 0x4600: + sprintf (buffer, "SUBB "); + print_src_des_reg(); + break; + + + case 0x4800: + sprintf (buffer, "CMP "); + print_src_des_reg(); + break; + + + case 0x4a00: + sprintf (buffer, "BTST "); + print_src_des_reg(); + break; + + + case 0x4c00: + case 0x4e00: + sprintf (buffer, "MOVE "); + + if (!(op & 0x0200)) + { + print_src_des_reg(); + } + else + { + print_src_reg(); + strcat(buffer, ","); + + if (rf == 'A') + { + rf = 'B'; + } + else + { + rf = 'A'; + } + + print_des_reg(); + } + break; + + + case 0x5000: + sprintf (buffer, "AND "); + print_src_des_reg(); + break; + + + case 0x5200: + sprintf (buffer, "ANDN "); + print_src_des_reg(); + break; + + + case 0x5400: + sprintf (buffer, "OR "); + print_src_des_reg(); + break; + + + case 0x5600: + if (rs != rd) + { + sprintf (buffer, "XOR "); + print_src_des_reg(); + } + else + { + sprintf (buffer, "CLR "); + print_des_reg(); + } + break; + + + case 0x5800: + sprintf (buffer, "DIVS "); + print_src_des_reg(); + break; + + + case 0x5a00: + sprintf (buffer, "DIVU "); + print_src_des_reg(); + break; + + + case 0x5c00: + sprintf (buffer, "MPYS "); + print_src_des_reg(); + break; + + + case 0x5e00: + sprintf (buffer, "MPYU "); + print_src_des_reg(); + break; + + + case 0x6000: + sprintf (buffer, "SLA "); + print_src_des_reg(); + break; + + + case 0x6200: + sprintf (buffer, "SLL "); + print_src_des_reg(); + break; + + + case 0x6400: + sprintf (buffer, "SRA "); + print_src_des_reg(); + break; + + + case 0x6600: + sprintf (buffer, "SRL "); + print_src_des_reg(); + break; + + + case 0x6800: + sprintf (buffer, "RL "); + print_src_des_reg(); + break; + + + case 0x6a00: + sprintf (buffer, "LMO "); + print_src_des_reg(); + break; + + + case 0x6c00: + sprintf (buffer, "MODS "); + print_src_des_reg(); + break; + + + case 0x6e00: + sprintf (buffer, "MODU "); + print_src_des_reg(); + break; + + + case 0x7a00: + if (is_34020) + { + sprintf (buffer, "RMO "); + print_src_des_reg(); + } + else + bad = 1; + break; + + case 0x7e00: + if (is_34020) + { + sprintf (buffer, "SWAPF *"); + print_src_des_reg(); + strcat(buffer, ",0"); + } + else + bad = 1; + break; + + + case 0x8000: + case 0x8200: + sprintf (buffer, "MOVE "); + print_src_reg(); + strcat(buffer, ",*"); + print_des_reg(); + strcat(buffer, ","); + print_field(); + break; + + + case 0x8400: + case 0x8600: + sprintf (buffer, "MOVE *"); + print_src_des_reg(); + strcat(buffer, ","); + print_field(); + break; + + + case 0x8800: + case 0x8a00: + sprintf (buffer, "MOVE *"); + print_src_reg(); + strcat(buffer, ",*"); + print_des_reg(); + strcat(buffer, ","); + print_field(); + break; + + + case 0x8c00: + sprintf (buffer, "MOVB "); + print_src_reg(); + strcat(buffer, ",*"); + print_des_reg(); + break; + + + case 0x8e00: + sprintf (buffer, "MOVB *"); + print_src_des_reg(); + break; + + + case 0x9000: + case 0x9200: + sprintf (buffer, "MOVE "); + print_src_reg(); + strcat(buffer, ",*"); + print_des_reg(); + strcat(buffer, "+,"); + print_field(); + break; + + + case 0x9400: + case 0x9600: + sprintf (buffer, "MOVE *"); + print_src_reg(); + strcat(buffer, "+,"); + print_des_reg(); + strcat(buffer, ","); + print_field(); + break; + + + case 0x9800: + case 0x9a00: + sprintf (buffer, "MOVE *"); + print_src_reg(); + strcat(buffer, "+,*"); + print_des_reg(); + strcat(buffer, "+,"); + print_field(); + break; + + + case 0x9c00: + sprintf (buffer, "MOVB *"); + print_src_reg(); + strcat(buffer, ",*"); + print_des_reg(); + break; + + + case 0xa000: + case 0xa200: + sprintf (buffer, "MOVE "); + print_src_reg(); + strcat(buffer, ",-*"); + print_des_reg(); + strcat(buffer, ","); + print_field(); + break; + + + case 0xa400: + case 0xa600: + sprintf (buffer, "MOVE -*"); + print_src_des_reg(); + strcat(buffer, ","); + print_field(); + break; + + + case 0xa800: + case 0xaa00: + sprintf (buffer, "MOVE -*"); + print_src_reg(); + strcat(buffer, ",-*"); + print_des_reg(); + strcat(buffer, ","); + print_field(); + break; + + + case 0xac00: + sprintf (buffer, "MOVB "); + print_src_reg(); + strcat(buffer, ",*"); + print_des_reg(); + strcat(buffer, "("); + print_word_parm(); + strcat(buffer, ")"); + break; + + + case 0xae00: + sprintf (buffer, "MOVB *"); + print_src_reg(); + strcat(buffer, "("); + print_word_parm(); + strcat(buffer, "),"); + print_des_reg(); + break; + + + case 0xb000: + case 0xb200: + sprintf (buffer, "MOVE "); + print_src_reg(); + strcat(buffer, ",*"); + print_des_reg(); + strcat(buffer, "("); + print_word_parm(); + strcat(buffer, "),"); + print_field(); + break; + + + case 0xb400: + case 0xb600: + sprintf (buffer, "MOVE *"); + print_src_reg(); + strcat(buffer, "("); + print_word_parm(); + strcat(buffer, "),"); + print_des_reg(); + strcat(buffer, ","); + print_field(); + break; + + + case 0xb800: + case 0xba00: + sprintf (buffer, "MOVE *"); + print_src_reg(); + strcat(buffer, "("); + print_word_parm(); + strcat(buffer, "),*"); + print_des_reg(); + strcat(buffer, "("); + print_word_parm(); + strcat(buffer, "),"); + print_field(); + break; + + + case 0xbc00: + sprintf (buffer, "MOVB *"); + print_src_reg(); + strcat(buffer, "("); + print_word_parm(); + strcat(buffer, "),*"); + print_des_reg(); + strcat(buffer, "("); + print_word_parm(); + strcat(buffer, ")"); + break; + + + case 0xc000: + case 0xc200: + case 0xc400: + case 0xc600: + case 0xc800: + case 0xca00: + case 0xcc00: + case 0xce00: + if ((op & 0x00ff) == 0x80) + { + sprintf (buffer, "JA"); + } + else + { + sprintf (buffer, "JR"); + } + + print_condition_code(); + strcat (buffer, " "); + + switch (op & 0x00ff) + { + case 0x00: + print_relative(); + break; + + case 0x80: + print_long_parm(); + break; + + default: + print_relative_8bit(); + } + break; + + + case 0xd000: + case 0xd200: + sprintf (buffer, "MOVE *"); + print_src_reg(); + strcat(buffer, "("); + print_word_parm(); + strcat(buffer, "),*"); + print_des_reg(); + strcat(buffer, "+,"); + print_field(); + break; + + + case 0xd400: + case 0xd600: + switch (subop) + { + case 0x0000: + sprintf (buffer, "MOVE @"); + print_long_parm(); + strcat(buffer, ",*"); + print_des_reg(); + strcat(buffer, "+,"); + print_field(); + break; + + case 0x0100: + sprintf (buffer, "EXGF "); + print_des_reg(); + strcat(buffer, ","); + print_field(); + break; + + default: + bad = 1; + } + break; + + case 0xd800: + if (is_34020) + { + UINT32 x; + PARAM_WORD(x); + sprintf(buffer, "CEXEC %d,%06X,%d", op & 1, ((x << 5) & 0x1fffe0) | ((op >> 1) & 0x1f), (x >> 13) & 7); + } + else + bad = 1; + break; + + + case 0xde00: + switch (subop) + { + case 0x0000: + if (is_34020) + sprintf (buffer, "FLINE 0"); + else + bad = 1; + break; + + case 0x0080: + if (is_34020) + sprintf (buffer, "FLINE 1"); + else + bad = 1; + break; + + case 0x0100: + sprintf (buffer, "LINE 0"); + break; + + case 0x0180: + sprintf (buffer, "LINE 1"); + break; + + default: + bad = 1; + } + break; + + case 0xe000: + sprintf (buffer, "ADDXY "); + print_src_des_reg(); + break; + + + case 0xe200: + sprintf (buffer, "SUBXY "); + print_src_des_reg(); + break; + + + case 0xe400: + sprintf (buffer, "CMPXY "); + print_src_des_reg(); + break; + + + case 0xe600: + sprintf (buffer, "CPW "); + print_src_des_reg(); + break; + + + case 0xe800: + sprintf (buffer, "CVXYL "); + print_src_des_reg(); + break; + + + case 0xea00: + if (is_34020) + { + sprintf (buffer, "CVSXYL "); + print_src_des_reg(); + } + else + bad = 1; + break; + + + case 0xec00: + sprintf (buffer, "MOVX "); + print_src_des_reg(); + break; + + + case 0xee00: + sprintf (buffer, "MOVY "); + print_src_des_reg(); + break; + + + case 0xf000: + sprintf (buffer, "PIXT "); + print_src_reg(); + strcat(buffer, ",*"); + print_des_reg(); + strcat(buffer, ",XY"); + break; + + + case 0xf200: + sprintf (buffer, "PIXT *"); + print_src_reg(); + strcat(buffer, ",XY,"); + print_des_reg(); + break; + + + case 0xf400: + sprintf (buffer, "PIXT *"); + print_src_reg(); + strcat(buffer, ",XY,*"); + print_des_reg(); + strcat(buffer, ",XY"); + break; + + + case 0xf600: + sprintf (buffer, "DRAV "); + print_src_des_reg(); + break; + + + case 0xf800: + sprintf (buffer, "PIXT "); + print_src_reg(); + strcat(buffer, ",*"); + print_des_reg(); + break; + + + case 0xfa00: + sprintf (buffer, "PIXT *"); + print_src_des_reg(); + break; + + + case 0xfc00: + sprintf (buffer, "PIXT *"); + print_src_reg(); + strcat(buffer, ",*"); + print_des_reg(); + break; + + default: + bad = 1; + } + + if (bad) + { + sprintf (buffer, "DW %04Xh", op & 0xffff); + } + + return (_pc - __pc) | flags | DASMFLAG_SUPPORTED; +} + +CPU_DISASSEMBLE( tms34010 ) +{ + rombase = oprom; + rambase = opram; + pcbase = pc; + return Dasm340x0(buffer, pc, 0); +} + +CPU_DISASSEMBLE( tms34020 ) +{ + rombase = oprom; + rambase = opram; + pcbase = pc; + return Dasm340x0(buffer, pc, 1); +} diff --git a/src/devices/cpu/tms34010/34010fld.c b/src/devices/cpu/tms34010/34010fld.c new file mode 100644 index 00000000000..ca05039dac0 --- /dev/null +++ b/src/devices/cpu/tms34010/34010fld.c @@ -0,0 +1,681 @@ +// license:BSD-3-Clause +// copyright-holders:Alex Pasadyn,Zsolt Vasvari +/*************************************************************************** + + TMS34010: Portable Texas Instruments TMS34010 emulator + + Copyright Alex Pasadyn/Zsolt Vasvari + Parts based on code by Aaron Giles + +***************************************************************************/ + + + +/*************************************************************************** + FIELD WRITE FUNCTIONS +***************************************************************************/ + +void tms340x0_device::wfield_01(offs_t offset, UINT32 data) +{ + WFIELDMAC(0x01,16); +} + +void tms340x0_device::wfield_02(offs_t offset, UINT32 data) +{ + WFIELDMAC(0x03,15); +} + +void tms340x0_device::wfield_03(offs_t offset, UINT32 data) +{ + WFIELDMAC(0x07,14); +} + +void tms340x0_device::wfield_04(offs_t offset, UINT32 data) +{ + WFIELDMAC(0x0f,13); +} + +void tms340x0_device::wfield_05(offs_t offset, UINT32 data) +{ + WFIELDMAC(0x1f,12); +} + +void tms340x0_device::wfield_06(offs_t offset, UINT32 data) +{ + WFIELDMAC(0x3f,11); +} + +void tms340x0_device::wfield_07(offs_t offset, UINT32 data) +{ + WFIELDMAC(0x7f,10); +} + +void tms340x0_device::wfield_08(offs_t offset, UINT32 data) +{ + WFIELDMAC_8(); +} + +void tms340x0_device::wfield_09(offs_t offset, UINT32 data) +{ + WFIELDMAC(0x1ff,8); +} + +void tms340x0_device::wfield_10(offs_t offset, UINT32 data) +{ + WFIELDMAC(0x3ff,7); +} + +void tms340x0_device::wfield_11(offs_t offset, UINT32 data) +{ + WFIELDMAC(0x7ff,6); +} + +void tms340x0_device::wfield_12(offs_t offset, UINT32 data) +{ + WFIELDMAC(0xfff,5); +} + +void tms340x0_device::wfield_13(offs_t offset, UINT32 data) +{ + WFIELDMAC(0x1fff,4); +} + +void tms340x0_device::wfield_14(offs_t offset, UINT32 data) +{ + WFIELDMAC(0x3fff,3); +} + +void tms340x0_device::wfield_15(offs_t offset, UINT32 data) +{ + WFIELDMAC(0x7fff,2); +} + +void tms340x0_device::wfield_16(offs_t offset, UINT32 data) +{ + if (offset & 0x0f) + { + WFIELDMAC(0xffff,1); + } + else + { + TMS34010_WRMEM_WORD(TOBYTE(offset),data); + } +} + +void tms340x0_device::wfield_17(offs_t offset, UINT32 data) +{ + WFIELDMAC(0x1ffff,0); +} + +void tms340x0_device::wfield_18(offs_t offset, UINT32 data) +{ + WFIELDMAC_BIG(0x3ffff,15); +} + +void tms340x0_device::wfield_19(offs_t offset, UINT32 data) +{ + WFIELDMAC_BIG(0x7ffff,14); +} + +void tms340x0_device::wfield_20(offs_t offset, UINT32 data) +{ + WFIELDMAC_BIG(0xfffff,13); +} + +void tms340x0_device::wfield_21(offs_t offset, UINT32 data) +{ + WFIELDMAC_BIG(0x1fffff,12); +} + +void tms340x0_device::wfield_22(offs_t offset, UINT32 data) +{ + WFIELDMAC_BIG(0x3fffff,11); +} + +void tms340x0_device::wfield_23(offs_t offset, UINT32 data) +{ + WFIELDMAC_BIG(0x7fffff,10); +} + +void tms340x0_device::wfield_24(offs_t offset, UINT32 data) +{ + WFIELDMAC_BIG(0xffffff,9); +} + +void tms340x0_device::wfield_25(offs_t offset, UINT32 data) +{ + WFIELDMAC_BIG(0x1ffffff,8); +} + +void tms340x0_device::wfield_26(offs_t offset, UINT32 data) +{ + WFIELDMAC_BIG(0x3ffffff,7); +} + +void tms340x0_device::wfield_27(offs_t offset, UINT32 data) +{ + WFIELDMAC_BIG(0x7ffffff,6); +} + +void tms340x0_device::wfield_28(offs_t offset, UINT32 data) +{ + WFIELDMAC_BIG(0xfffffff,5); +} + +void tms340x0_device::wfield_29(offs_t offset, UINT32 data) +{ + WFIELDMAC_BIG(0x1fffffff,4); +} + +void tms340x0_device::wfield_30(offs_t offset, UINT32 data) +{ + WFIELDMAC_BIG(0x3fffffff,3); +} + +void tms340x0_device::wfield_31(offs_t offset, UINT32 data) +{ + WFIELDMAC_BIG(0x7fffffff,2); +} + +void tms340x0_device::wfield_32(offs_t offset, UINT32 data) +{ + WFIELDMAC_32(); +} + + +const tms340x0_device::wfield_func tms340x0_device::s_wfield_functions[32] = +{ + &tms340x0_device::wfield_32, &tms340x0_device::wfield_01, &tms340x0_device::wfield_02, &tms340x0_device::wfield_03, &tms340x0_device::wfield_04, &tms340x0_device::wfield_05, + &tms340x0_device::wfield_06, &tms340x0_device::wfield_07, &tms340x0_device::wfield_08, &tms340x0_device::wfield_09, &tms340x0_device::wfield_10, &tms340x0_device::wfield_11, + &tms340x0_device::wfield_12, &tms340x0_device::wfield_13, &tms340x0_device::wfield_14, &tms340x0_device::wfield_15, &tms340x0_device::wfield_16, &tms340x0_device::wfield_17, + &tms340x0_device::wfield_18, &tms340x0_device::wfield_19, &tms340x0_device::wfield_20, &tms340x0_device::wfield_21, &tms340x0_device::wfield_22, &tms340x0_device::wfield_23, + &tms340x0_device::wfield_24, &tms340x0_device::wfield_25, &tms340x0_device::wfield_26, &tms340x0_device::wfield_27, &tms340x0_device::wfield_28, &tms340x0_device::wfield_29, + &tms340x0_device::wfield_30, &tms340x0_device::wfield_31 +}; + + + +/*************************************************************************** + FIELD READ FUNCTIONS (ZERO-EXTEND) +***************************************************************************/ + +UINT32 tms340x0_device::rfield_z_01(offs_t offset) +{ + UINT32 ret; + RFIELDMAC(0x01,16); + return ret; +} + +UINT32 tms340x0_device::rfield_z_02(offs_t offset) +{ + UINT32 ret; + RFIELDMAC(0x03,15); + return ret; +} + +UINT32 tms340x0_device::rfield_z_03(offs_t offset) +{ + UINT32 ret; + RFIELDMAC(0x07,14); + return ret; +} + +UINT32 tms340x0_device::rfield_z_04(offs_t offset) +{ + UINT32 ret; + RFIELDMAC(0x0f,13); + return ret; +} + +UINT32 tms340x0_device::rfield_z_05(offs_t offset) +{ + UINT32 ret; + RFIELDMAC(0x1f,12); + return ret; +} + +UINT32 tms340x0_device::rfield_z_06(offs_t offset) +{ + UINT32 ret; + RFIELDMAC(0x3f,11); + return ret; +} + +UINT32 tms340x0_device::rfield_z_07(offs_t offset) +{ + UINT32 ret; + RFIELDMAC(0x7f,10); + return ret; +} + +UINT32 tms340x0_device::rfield_z_08(offs_t offset) +{ + UINT32 ret; + RFIELDMAC_8(); + return ret; +} + +UINT32 tms340x0_device::rfield_z_09(offs_t offset) +{ + UINT32 ret; + RFIELDMAC(0x1ff,8); + return ret; +} + +UINT32 tms340x0_device::rfield_z_10(offs_t offset) +{ + UINT32 ret; + RFIELDMAC(0x3ff,7); + return ret; +} + +UINT32 tms340x0_device::rfield_z_11(offs_t offset) +{ + UINT32 ret; + RFIELDMAC(0x7ff,6); + return ret; +} + +UINT32 tms340x0_device::rfield_z_12(offs_t offset) +{ + UINT32 ret; + RFIELDMAC(0xfff,5); + return ret; +} + +UINT32 tms340x0_device::rfield_z_13(offs_t offset) +{ + UINT32 ret; + RFIELDMAC(0x1fff,4); + return ret; +} + +UINT32 tms340x0_device::rfield_z_14(offs_t offset) +{ + UINT32 ret; + RFIELDMAC(0x3fff,3); + return ret; +} + +UINT32 tms340x0_device::rfield_z_15(offs_t offset) +{ + UINT32 ret; + RFIELDMAC(0x7fff,2); + return ret; +} + +UINT32 tms340x0_device::rfield_z_16(offs_t offset) +{ + UINT32 ret; + if (offset & 0x0f) + { + RFIELDMAC(0xffff,1); + } + + else + ret = TMS34010_RDMEM_WORD(TOBYTE(offset)); + return ret; +} + +UINT32 tms340x0_device::rfield_z_17(offs_t offset) +{ + UINT32 ret; + RFIELDMAC(0x1ffff,0); + return ret; +} + +UINT32 tms340x0_device::rfield_z_18(offs_t offset) +{ + UINT32 ret; + RFIELDMAC_BIG(0x3ffff,15); + return ret; +} + +UINT32 tms340x0_device::rfield_z_19(offs_t offset) +{ + UINT32 ret; + RFIELDMAC_BIG(0x7ffff,14); + return ret; +} + +UINT32 tms340x0_device::rfield_z_20(offs_t offset) +{ + UINT32 ret; + RFIELDMAC_BIG(0xfffff,13); + return ret; +} + +UINT32 tms340x0_device::rfield_z_21(offs_t offset) +{ + UINT32 ret; + RFIELDMAC_BIG(0x1fffff,12); + return ret; +} + +UINT32 tms340x0_device::rfield_z_22(offs_t offset) +{ + UINT32 ret; + RFIELDMAC_BIG(0x3fffff,11); + return ret; +} + +UINT32 tms340x0_device::rfield_z_23(offs_t offset) +{ + UINT32 ret; + RFIELDMAC_BIG(0x7fffff,10); + return ret; +} + +UINT32 tms340x0_device::rfield_z_24(offs_t offset) +{ + UINT32 ret; + RFIELDMAC_BIG(0xffffff,9); + return ret; +} + +UINT32 tms340x0_device::rfield_z_25(offs_t offset) +{ + UINT32 ret; + RFIELDMAC_BIG(0x1ffffff,8); + return ret; +} + +UINT32 tms340x0_device::rfield_z_26(offs_t offset) +{ + UINT32 ret; + RFIELDMAC_BIG(0x3ffffff,7); + return ret; +} + +UINT32 tms340x0_device::rfield_z_27(offs_t offset) +{ + UINT32 ret; + RFIELDMAC_BIG(0x7ffffff,6); + return ret; +} + +UINT32 tms340x0_device::rfield_z_28(offs_t offset) +{ + UINT32 ret; + RFIELDMAC_BIG(0xfffffff,5); + return ret; +} + +UINT32 tms340x0_device::rfield_z_29(offs_t offset) +{ + UINT32 ret; + RFIELDMAC_BIG(0x1fffffff,4); + return ret; +} + +UINT32 tms340x0_device::rfield_z_30(offs_t offset) +{ + UINT32 ret; + RFIELDMAC_BIG(0x3fffffff,3); + return ret; +} + +UINT32 tms340x0_device::rfield_z_31(offs_t offset) +{ + UINT32 ret; + RFIELDMAC_BIG(0x7fffffff,2); + return ret; +} + +UINT32 tms340x0_device::rfield_32(offs_t offset) +{ + RFIELDMAC_32(); +} + + +/*************************************************************************** + FIELD READ FUNCTIONS (SIGN-EXTEND) +***************************************************************************/ + +UINT32 tms340x0_device::rfield_s_01(offs_t offset) +{ + UINT32 ret; + RFIELDMAC(0x01,16); + return ((INT32)(ret << 31)) >> 31; +} + +UINT32 tms340x0_device::rfield_s_02(offs_t offset) +{ + UINT32 ret; + RFIELDMAC(0x03,15); + return ((INT32)(ret << 30)) >> 30; +} + +UINT32 tms340x0_device::rfield_s_03(offs_t offset) +{ + UINT32 ret; + RFIELDMAC(0x07,14); + return ((INT32)(ret << 29)) >> 29; +} + +UINT32 tms340x0_device::rfield_s_04(offs_t offset) +{ + UINT32 ret; + RFIELDMAC(0x0f,13); + return ((INT32)(ret << 28)) >> 28; +} + +UINT32 tms340x0_device::rfield_s_05(offs_t offset) +{ + UINT32 ret; + RFIELDMAC(0x1f,12); + return ((INT32)(ret << 27)) >> 27; +} + +UINT32 tms340x0_device::rfield_s_06(offs_t offset) +{ + UINT32 ret; + RFIELDMAC(0x3f,11); + return ((INT32)(ret << 26)) >> 26; +} + +UINT32 tms340x0_device::rfield_s_07(offs_t offset) +{ + UINT32 ret; + RFIELDMAC(0x7f,10); + return ((INT32)(ret << 25)) >> 25; +} + +UINT32 tms340x0_device::rfield_s_08(offs_t offset) +{ + UINT32 ret; + if (offset & 0x07) + { + RFIELDMAC(0xff,9); + } + + else + ret = TMS34010_RDMEM(TOBYTE(offset)); + return (INT32)(INT8)ret; +} + +UINT32 tms340x0_device::rfield_s_09(offs_t offset) +{ + UINT32 ret; + RFIELDMAC(0x1ff,8); + return ((INT32)(ret << 23)) >> 23; +} + +UINT32 tms340x0_device::rfield_s_10(offs_t offset) +{ + UINT32 ret; + RFIELDMAC(0x3ff,7); + return ((INT32)(ret << 22)) >> 22; +} + +UINT32 tms340x0_device::rfield_s_11(offs_t offset) +{ + UINT32 ret; + RFIELDMAC(0x7ff,6); + return ((INT32)(ret << 21)) >> 21; +} + +UINT32 tms340x0_device::rfield_s_12(offs_t offset) +{ + UINT32 ret; + RFIELDMAC(0xfff,5); + return ((INT32)(ret << 20)) >> 20; +} + +UINT32 tms340x0_device::rfield_s_13(offs_t offset) +{ + UINT32 ret; + RFIELDMAC(0x1fff,4); + return ((INT32)(ret << 19)) >> 19; +} + +UINT32 tms340x0_device::rfield_s_14(offs_t offset) +{ + UINT32 ret; + RFIELDMAC(0x3fff,3); + return ((INT32)(ret << 18)) >> 18; +} + +UINT32 tms340x0_device::rfield_s_15(offs_t offset) +{ + UINT32 ret; + RFIELDMAC(0x7fff,2); + return ((INT32)(ret << 17)) >> 17; +} + +UINT32 tms340x0_device::rfield_s_16(offs_t offset) +{ + UINT32 ret; + if (offset & 0x0f) + { + RFIELDMAC(0xffff,1); + } + + else + { + ret = TMS34010_RDMEM_WORD(TOBYTE(offset)); + } + + return (INT32)(INT16)ret; +} + +UINT32 tms340x0_device::rfield_s_17(offs_t offset) +{ + UINT32 ret; + RFIELDMAC(0x1ffff,0); + return ((INT32)(ret << 15)) >> 15; +} + +UINT32 tms340x0_device::rfield_s_18(offs_t offset) +{ + UINT32 ret; + RFIELDMAC_BIG(0x3ffff,15); + return ((INT32)(ret << 14)) >> 14; +} + +UINT32 tms340x0_device::rfield_s_19(offs_t offset) +{ + UINT32 ret; + RFIELDMAC_BIG(0x7ffff,14); + return ((INT32)(ret << 13)) >> 13; +} + +UINT32 tms340x0_device::rfield_s_20(offs_t offset) +{ + UINT32 ret; + RFIELDMAC_BIG(0xfffff,13); + return ((INT32)(ret << 12)) >> 12; +} + +UINT32 tms340x0_device::rfield_s_21(offs_t offset) +{ + UINT32 ret; + RFIELDMAC_BIG(0x1fffff,12); + return ((INT32)(ret << 11)) >> 11; +} + +UINT32 tms340x0_device::rfield_s_22(offs_t offset) +{ + UINT32 ret; + RFIELDMAC_BIG(0x3fffff,11); + return ((INT32)(ret << 10)) >> 10; +} + +UINT32 tms340x0_device::rfield_s_23(offs_t offset) +{ + UINT32 ret; + RFIELDMAC_BIG(0x7fffff,10); + return ((INT32)(ret << 9)) >> 9; +} + +UINT32 tms340x0_device::rfield_s_24(offs_t offset) +{ + UINT32 ret; + RFIELDMAC_BIG(0xffffff,9); + return ((INT32)(ret << 8)) >> 8; +} + +UINT32 tms340x0_device::rfield_s_25(offs_t offset) +{ + UINT32 ret; + RFIELDMAC_BIG(0x1ffffff,8); + return ((INT32)(ret << 7)) >> 7; +} + +UINT32 tms340x0_device::rfield_s_26(offs_t offset) +{ + UINT32 ret; + RFIELDMAC_BIG(0x3ffffff,7); + return ((INT32)(ret << 6)) >> 6; +} + +UINT32 tms340x0_device::rfield_s_27(offs_t offset) +{ + UINT32 ret; + RFIELDMAC_BIG(0x7ffffff,6); + return ((INT32)(ret << 5)) >> 5; +} + +UINT32 tms340x0_device::rfield_s_28(offs_t offset) +{ + UINT32 ret; + RFIELDMAC_BIG(0xfffffff,5); + return ((INT32)(ret << 4)) >> 4; +} + +UINT32 tms340x0_device::rfield_s_29(offs_t offset) +{ + UINT32 ret; + RFIELDMAC_BIG(0x1fffffff,4); + return ((INT32)(ret << 3)) >> 3; +} + +UINT32 tms340x0_device::rfield_s_30(offs_t offset) +{ + UINT32 ret; + RFIELDMAC_BIG(0x3fffffff,3); + return ((INT32)(ret << 2)) >> 2; +} + +UINT32 tms340x0_device::rfield_s_31(offs_t offset) +{ + UINT32 ret; + RFIELDMAC_BIG(0x7fffffff,2); + return ((INT32)(ret << 1)) >> 1; +} + +const tms340x0_device::rfield_func tms340x0_device::s_rfield_functions[64] = +{ + &tms340x0_device::rfield_32 , &tms340x0_device::rfield_z_01, &tms340x0_device::rfield_z_02, &tms340x0_device::rfield_z_03, &tms340x0_device::rfield_z_04, &tms340x0_device::rfield_z_05, + &tms340x0_device::rfield_z_06, &tms340x0_device::rfield_z_07, &tms340x0_device::rfield_z_08, &tms340x0_device::rfield_z_09, &tms340x0_device::rfield_z_10, &tms340x0_device::rfield_z_11, + &tms340x0_device::rfield_z_12, &tms340x0_device::rfield_z_13, &tms340x0_device::rfield_z_14, &tms340x0_device::rfield_z_15, &tms340x0_device::rfield_z_16, &tms340x0_device::rfield_z_17, + &tms340x0_device::rfield_z_18, &tms340x0_device::rfield_z_19, &tms340x0_device::rfield_z_20, &tms340x0_device::rfield_z_21, &tms340x0_device::rfield_z_22, &tms340x0_device::rfield_z_23, + &tms340x0_device::rfield_z_24, &tms340x0_device::rfield_z_25, &tms340x0_device::rfield_z_26, &tms340x0_device::rfield_z_27, &tms340x0_device::rfield_z_28, &tms340x0_device::rfield_z_29, + &tms340x0_device::rfield_z_30, &tms340x0_device::rfield_z_31, + &tms340x0_device::rfield_32 , &tms340x0_device::rfield_s_01, &tms340x0_device::rfield_s_02, &tms340x0_device::rfield_s_03, &tms340x0_device::rfield_s_04, &tms340x0_device::rfield_s_05, + &tms340x0_device::rfield_s_06, &tms340x0_device::rfield_s_07, &tms340x0_device::rfield_s_08, &tms340x0_device::rfield_s_09, &tms340x0_device::rfield_s_10, &tms340x0_device::rfield_s_11, + &tms340x0_device::rfield_s_12, &tms340x0_device::rfield_s_13, &tms340x0_device::rfield_s_14, &tms340x0_device::rfield_s_15, &tms340x0_device::rfield_s_16, &tms340x0_device::rfield_s_17, + &tms340x0_device::rfield_s_18, &tms340x0_device::rfield_s_19, &tms340x0_device::rfield_s_20, &tms340x0_device::rfield_s_21, &tms340x0_device::rfield_s_22, &tms340x0_device::rfield_s_23, + &tms340x0_device::rfield_s_24, &tms340x0_device::rfield_s_25, &tms340x0_device::rfield_s_26, &tms340x0_device::rfield_s_27, &tms340x0_device::rfield_s_28, &tms340x0_device::rfield_s_29, + &tms340x0_device::rfield_s_30, &tms340x0_device::rfield_s_31 +}; diff --git a/src/devices/cpu/tms34010/34010gfx.c b/src/devices/cpu/tms34010/34010gfx.c new file mode 100644 index 00000000000..15394269a77 --- /dev/null +++ b/src/devices/cpu/tms34010/34010gfx.c @@ -0,0 +1,1972 @@ +// license:BSD-3-Clause +// copyright-holders:Alex Pasadyn,Zsolt Vasvari,Aaron Giles +/*************************************************************************** + + TMS34010: Portable Texas Instruments TMS34010 emulator + + Copyright Alex Pasadyn/Zsolt Vasvari + Parts based on code by Aaron Giles + +***************************************************************************/ + +#ifndef RECURSIVE_INCLUDE + + +#define LOG_GFX_OPS 0 +#define LOGGFX(x) do { if (LOG_GFX_OPS && machine().input().code_pressed(KEYCODE_L)) logerror x; } while (0) + + +/* Graphics Instructions */ + +void tms340x0_device::line(UINT16 op) +{ + if (!P_FLAG()) + { + if (WINDOW_CHECKING() != 0 && WINDOW_CHECKING() != 3) + logerror("LINE XY %08X - Window Checking Mode %d not supported\n", m_pc, WINDOW_CHECKING()); + + m_st |= STBIT_P; + TEMP() = (op & 0x80) ? 1 : 0; /* boundary value depends on the algorithm */ + LOGGFX(("%08X(%3d):LINE (%d,%d)-(%d,%d)\n", m_pc, m_screen->vpos(), DADDR_X(), DADDR_Y(), DADDR_X() + DYDX_X(), DADDR_Y() + DYDX_Y())); + } + + if (COUNT() > 0) + { + INT16 x1,y1; + + COUNT()--; + if (WINDOW_CHECKING() != 3 || + (DADDR_X() >= WSTART_X() && DADDR_X() <= WEND_X() && + DADDR_Y() >= WSTART_Y() && DADDR_Y() <= WEND_Y())) + WPIXEL(DXYTOL(DADDR_XY()),COLOR1()); + + if (SADDR() >= TEMP()) + { + SADDR() += DYDX_Y()*2 - DYDX_X()*2; + x1 = INC1_X(); + y1 = INC1_Y(); + } + else + { + SADDR() += DYDX_Y()*2; + x1 = INC2_X(); + y1 = INC2_Y(); + } + DADDR_X() += x1; + DADDR_Y() += y1; + + COUNT_UNKNOWN_CYCLES(2); + m_pc -= 0x10; /* not done yet, check for interrupts and restart instruction */ + return; + } + m_st &= ~STBIT_P; +} + + +/* +cases: +* window modes (0,1,2,3) +* boolean/arithmetic ops (16+6) +* transparency (on/off) +* plane masking +* directions (left->right/right->left, top->bottom/bottom->top) +*/ + +int tms340x0_device::apply_window(const char *inst_name,int srcbpp, UINT32 *srcaddr, XY *dst, int *dx, int *dy) +{ + /* apply the window */ + if (WINDOW_CHECKING() == 0) + return 0; + else + { + int sx = dst->x; + int sy = dst->y; + int ex = sx + *dx - 1; + int ey = sy + *dy - 1; + int diff, cycles = 3; + + if (WINDOW_CHECKING() == 2) + logerror("%08x: %s apply_window window mode %d not supported!\n", pc(), inst_name, WINDOW_CHECKING()); + + CLR_V(); + if (WINDOW_CHECKING() == 1) + SET_V_LOG(1); + + /* clip X */ + diff = WSTART_X() - sx; + if (diff > 0) + { + if (srcaddr) + *srcaddr += diff * srcbpp; + sx += diff; + SET_V_LOG(1); + } + diff = ex - WEND_X(); + if (diff > 0) + { + ex -= diff; + SET_V_LOG(1); + } + + + /* clip Y */ + diff = WSTART_Y() - sy; + if (diff > 0) + { + if (srcaddr) + *srcaddr += diff * m_convsp; + + sy += diff; + SET_V_LOG(1); + } + diff = ey - WEND_Y(); + if (diff > 0) + { + ey -= diff; + SET_V_LOG(1); + } + + /* compute cycles */ + if (*dx != ex - sx + 1 || *dy != ey - sy + 1) + { + if (dst->x != sx || dst->y != sy) + cycles += 11; + else + cycles += 3; + } + else if (dst->x != sx || dst->y != sy) + cycles += 7; + + /* update the values */ + dst->x = sx; + dst->y = sy; + *dx = ex - sx + 1; + *dy = ey - sy + 1; + return cycles; + } +} + + +/******************************************************************* + + About the timing of gfx operations: + + The 34010 manual lists a fairly intricate and accurate way of + computing cycle timings for graphics ops. However, there are + enough typos and misleading statements to make the reliability + of the timing info questionable. + + So, to address this, here is a simplified approximate version + of the timing. + + timing = setup + (srcwords * 2 + dstwords * gfxop) * rows + + Each read access takes 2 cycles. Each gfx operation has + its own timing as specified in the 34010 manual. So, it's 2 + cycles per read plus gfxop cycles per operation. Pretty + simple, no? + +*******************************************************************/ + +int tms340x0_device::compute_fill_cycles(int left_partials, int right_partials, int full_words, int op_timing) +{ + int dstwords; + + if (left_partials) full_words += 1; + if (right_partials) full_words += 1; + dstwords = full_words; + + return (dstwords * op_timing); +} + +int tms340x0_device::compute_pixblt_cycles(int left_partials, int right_partials, int full_words, int op_timing) +{ + int srcwords, dstwords; + + if (left_partials) full_words += 1; + if (right_partials) full_words += 1; + srcwords = full_words; + dstwords = full_words; + + return (dstwords * op_timing + srcwords * 2) + 2; +} + +int tms340x0_device::compute_pixblt_b_cycles(int left_partials, int right_partials, int full_words, int rows, int op_timing, int bpp) +{ + int srcwords, dstwords; + + if (left_partials) full_words += 1; + if (right_partials) full_words += 1; + srcwords = full_words * bpp / 16; + dstwords = full_words; + + return (dstwords * op_timing + srcwords * 2) * rows + 2; +} + + +/* Shift register handling */ +void tms340x0_device::memory_w(address_space &space, offs_t offset,UINT16 data) +{ + space.write_word(offset, data); +} + +UINT16 tms340x0_device::memory_r(address_space &space, offs_t offset) +{ + return space.read_word(offset); +} + +void tms340x0_device::shiftreg_w(address_space &space, offs_t offset,UINT16 data) +{ + if (!m_from_shiftreg_cb.isnull()) + m_from_shiftreg_cb(space, (UINT32)(offset << 3) & ~15, &m_shiftreg[0]); + else + logerror("From ShiftReg function not set. PC = %08X\n", m_pc); +} + +UINT16 tms340x0_device::shiftreg_r(address_space &space, offs_t offset) +{ + if (!m_to_shiftreg_cb.isnull()) + m_to_shiftreg_cb(space, (UINT32)(offset << 3) & ~15, &m_shiftreg[0]); + else + logerror("To ShiftReg function not set. PC = %08X\n", m_pc); + return m_shiftreg[0]; +} + +UINT16 tms340x0_device::dummy_shiftreg_r(address_space &space, offs_t offset) +{ + return m_shiftreg[0]; +} + + + +/* Pixel operations */ +UINT32 tms340x0_device::pixel_op00(UINT32 dstpix, UINT32 mask, UINT32 srcpix) { return srcpix; } +UINT32 tms340x0_device::pixel_op01(UINT32 dstpix, UINT32 mask, UINT32 srcpix) { return srcpix & dstpix; } +UINT32 tms340x0_device::pixel_op02(UINT32 dstpix, UINT32 mask, UINT32 srcpix) { return srcpix & ~dstpix; } +UINT32 tms340x0_device::pixel_op03(UINT32 dstpix, UINT32 mask, UINT32 srcpix) { return 0; } +UINT32 tms340x0_device::pixel_op04(UINT32 dstpix, UINT32 mask, UINT32 srcpix) { return (srcpix | ~dstpix) & mask; } +UINT32 tms340x0_device::pixel_op05(UINT32 dstpix, UINT32 mask, UINT32 srcpix) { return ~(srcpix ^ dstpix) & mask; } +UINT32 tms340x0_device::pixel_op06(UINT32 dstpix, UINT32 mask, UINT32 srcpix) { return ~dstpix & mask; } +UINT32 tms340x0_device::pixel_op07(UINT32 dstpix, UINT32 mask, UINT32 srcpix) { return ~(srcpix | dstpix) & mask; } +UINT32 tms340x0_device::pixel_op08(UINT32 dstpix, UINT32 mask, UINT32 srcpix) { return (srcpix | dstpix) & mask; } +UINT32 tms340x0_device::pixel_op09(UINT32 dstpix, UINT32 mask, UINT32 srcpix) { return dstpix & mask; } +UINT32 tms340x0_device::pixel_op10(UINT32 dstpix, UINT32 mask, UINT32 srcpix) { return (srcpix ^ dstpix) & mask; } +UINT32 tms340x0_device::pixel_op11(UINT32 dstpix, UINT32 mask, UINT32 srcpix) { return (~srcpix & dstpix) & mask; } +UINT32 tms340x0_device::pixel_op12(UINT32 dstpix, UINT32 mask, UINT32 srcpix) { return mask; } +UINT32 tms340x0_device::pixel_op13(UINT32 dstpix, UINT32 mask, UINT32 srcpix) { return (~srcpix & dstpix) & mask; } +UINT32 tms340x0_device::pixel_op14(UINT32 dstpix, UINT32 mask, UINT32 srcpix) { return ~(srcpix & dstpix) & mask; } +UINT32 tms340x0_device::pixel_op15(UINT32 dstpix, UINT32 mask, UINT32 srcpix) { return srcpix ^ mask; } +UINT32 tms340x0_device::pixel_op16(UINT32 dstpix, UINT32 mask, UINT32 srcpix) { return (srcpix + dstpix) & mask; } +UINT32 tms340x0_device::pixel_op17(UINT32 dstpix, UINT32 mask, UINT32 srcpix) { INT32 tmp = srcpix + (dstpix & mask); return (tmp > mask) ? mask : tmp; } +UINT32 tms340x0_device::pixel_op18(UINT32 dstpix, UINT32 mask, UINT32 srcpix) { return (dstpix - srcpix) & mask; } +UINT32 tms340x0_device::pixel_op19(UINT32 dstpix, UINT32 mask, UINT32 srcpix) { INT32 tmp = srcpix - (dstpix & mask); return (tmp < 0) ? 0 : tmp; } +UINT32 tms340x0_device::pixel_op20(UINT32 dstpix, UINT32 mask, UINT32 srcpix) { dstpix &= mask; return (srcpix > dstpix) ? srcpix : dstpix; } +UINT32 tms340x0_device::pixel_op21(UINT32 dstpix, UINT32 mask, UINT32 srcpix) { dstpix &= mask; return (srcpix < dstpix) ? srcpix : dstpix; } + +const tms340x0_device::pixel_op_func tms340x0_device::s_pixel_op_table[32] = +{ + &tms340x0_device::pixel_op00, &tms340x0_device::pixel_op01, &tms340x0_device::pixel_op02, &tms340x0_device::pixel_op03, &tms340x0_device::pixel_op04, &tms340x0_device::pixel_op05, &tms340x0_device::pixel_op06, &tms340x0_device::pixel_op07, + &tms340x0_device::pixel_op08, &tms340x0_device::pixel_op09, &tms340x0_device::pixel_op10, &tms340x0_device::pixel_op11, &tms340x0_device::pixel_op12, &tms340x0_device::pixel_op13, &tms340x0_device::pixel_op14, &tms340x0_device::pixel_op15, + &tms340x0_device::pixel_op16, &tms340x0_device::pixel_op17, &tms340x0_device::pixel_op18, &tms340x0_device::pixel_op19, &tms340x0_device::pixel_op20, &tms340x0_device::pixel_op21, &tms340x0_device::pixel_op00, &tms340x0_device::pixel_op00, + &tms340x0_device::pixel_op00, &tms340x0_device::pixel_op00, &tms340x0_device::pixel_op00, &tms340x0_device::pixel_op00, &tms340x0_device::pixel_op00, &tms340x0_device::pixel_op00, &tms340x0_device::pixel_op00, &tms340x0_device::pixel_op00 +}; +const UINT8 tms340x0_device::s_pixel_op_timing_table[33] = +{ + 2,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,5,5,6,5,5,2,2,2,2,2,2,2,2,2,2,2 +}; + + +/* tables */ +const tms340x0_device::pixblt_op_func tms340x0_device::s_pixblt_op_table[] = +{ + &tms340x0_device::pixblt_1_op0, &tms340x0_device::pixblt_1_op0_trans, &tms340x0_device::pixblt_1_opx, &tms340x0_device::pixblt_1_opx_trans, + &tms340x0_device::pixblt_1_opx, &tms340x0_device::pixblt_1_opx_trans, &tms340x0_device::pixblt_1_opx, &tms340x0_device::pixblt_1_opx_trans, + &tms340x0_device::pixblt_1_opx, &tms340x0_device::pixblt_1_opx_trans, &tms340x0_device::pixblt_1_opx, &tms340x0_device::pixblt_1_opx_trans, + &tms340x0_device::pixblt_1_opx, &tms340x0_device::pixblt_1_opx_trans, &tms340x0_device::pixblt_1_opx, &tms340x0_device::pixblt_1_opx_trans, + &tms340x0_device::pixblt_1_opx, &tms340x0_device::pixblt_1_opx_trans, &tms340x0_device::pixblt_1_opx, &tms340x0_device::pixblt_1_opx_trans, + &tms340x0_device::pixblt_1_opx, &tms340x0_device::pixblt_1_opx_trans, &tms340x0_device::pixblt_1_opx, &tms340x0_device::pixblt_1_opx_trans, + &tms340x0_device::pixblt_1_opx, &tms340x0_device::pixblt_1_opx_trans, &tms340x0_device::pixblt_1_opx, &tms340x0_device::pixblt_1_opx_trans, + &tms340x0_device::pixblt_1_opx, &tms340x0_device::pixblt_1_opx_trans, &tms340x0_device::pixblt_1_opx, &tms340x0_device::pixblt_1_opx_trans, + &tms340x0_device::pixblt_1_opx, &tms340x0_device::pixblt_1_opx_trans, &tms340x0_device::pixblt_1_opx, &tms340x0_device::pixblt_1_opx_trans, + &tms340x0_device::pixblt_1_opx, &tms340x0_device::pixblt_1_opx_trans, &tms340x0_device::pixblt_1_opx, &tms340x0_device::pixblt_1_opx_trans, + &tms340x0_device::pixblt_1_opx, &tms340x0_device::pixblt_1_opx_trans, &tms340x0_device::pixblt_1_opx, &tms340x0_device::pixblt_1_opx_trans, + &tms340x0_device::pixblt_1_opx, &tms340x0_device::pixblt_1_opx_trans, &tms340x0_device::pixblt_1_opx, &tms340x0_device::pixblt_1_opx_trans, + &tms340x0_device::pixblt_1_opx, &tms340x0_device::pixblt_1_opx_trans, &tms340x0_device::pixblt_1_opx, &tms340x0_device::pixblt_1_opx_trans, + &tms340x0_device::pixblt_1_opx, &tms340x0_device::pixblt_1_opx_trans, &tms340x0_device::pixblt_1_opx, &tms340x0_device::pixblt_1_opx_trans, + &tms340x0_device::pixblt_1_opx, &tms340x0_device::pixblt_1_opx_trans, &tms340x0_device::pixblt_1_opx, &tms340x0_device::pixblt_1_opx_trans, + &tms340x0_device::pixblt_1_opx, &tms340x0_device::pixblt_1_opx_trans, &tms340x0_device::pixblt_1_opx, &tms340x0_device::pixblt_1_opx_trans, + + &tms340x0_device::pixblt_2_op0, &tms340x0_device::pixblt_2_op0_trans, &tms340x0_device::pixblt_2_opx, &tms340x0_device::pixblt_2_opx_trans, + &tms340x0_device::pixblt_2_opx, &tms340x0_device::pixblt_2_opx_trans, &tms340x0_device::pixblt_2_opx, &tms340x0_device::pixblt_2_opx_trans, + &tms340x0_device::pixblt_2_opx, &tms340x0_device::pixblt_2_opx_trans, &tms340x0_device::pixblt_2_opx, &tms340x0_device::pixblt_2_opx_trans, + &tms340x0_device::pixblt_2_opx, &tms340x0_device::pixblt_2_opx_trans, &tms340x0_device::pixblt_2_opx, &tms340x0_device::pixblt_2_opx_trans, + &tms340x0_device::pixblt_2_opx, &tms340x0_device::pixblt_2_opx_trans, &tms340x0_device::pixblt_2_opx, &tms340x0_device::pixblt_2_opx_trans, + &tms340x0_device::pixblt_2_opx, &tms340x0_device::pixblt_2_opx_trans, &tms340x0_device::pixblt_2_opx, &tms340x0_device::pixblt_2_opx_trans, + &tms340x0_device::pixblt_2_opx, &tms340x0_device::pixblt_2_opx_trans, &tms340x0_device::pixblt_2_opx, &tms340x0_device::pixblt_2_opx_trans, + &tms340x0_device::pixblt_2_opx, &tms340x0_device::pixblt_2_opx_trans, &tms340x0_device::pixblt_2_opx, &tms340x0_device::pixblt_2_opx_trans, + &tms340x0_device::pixblt_2_opx, &tms340x0_device::pixblt_2_opx_trans, &tms340x0_device::pixblt_2_opx, &tms340x0_device::pixblt_2_opx_trans, + &tms340x0_device::pixblt_2_opx, &tms340x0_device::pixblt_2_opx_trans, &tms340x0_device::pixblt_2_opx, &tms340x0_device::pixblt_2_opx_trans, + &tms340x0_device::pixblt_2_opx, &tms340x0_device::pixblt_2_opx_trans, &tms340x0_device::pixblt_2_opx, &tms340x0_device::pixblt_2_opx_trans, + &tms340x0_device::pixblt_2_opx, &tms340x0_device::pixblt_2_opx_trans, &tms340x0_device::pixblt_2_opx, &tms340x0_device::pixblt_2_opx_trans, + &tms340x0_device::pixblt_2_opx, &tms340x0_device::pixblt_2_opx_trans, &tms340x0_device::pixblt_2_opx, &tms340x0_device::pixblt_2_opx_trans, + &tms340x0_device::pixblt_2_opx, &tms340x0_device::pixblt_2_opx_trans, &tms340x0_device::pixblt_2_opx, &tms340x0_device::pixblt_2_opx_trans, + &tms340x0_device::pixblt_2_opx, &tms340x0_device::pixblt_2_opx_trans, &tms340x0_device::pixblt_2_opx, &tms340x0_device::pixblt_2_opx_trans, + &tms340x0_device::pixblt_2_opx, &tms340x0_device::pixblt_2_opx_trans, &tms340x0_device::pixblt_2_opx, &tms340x0_device::pixblt_2_opx_trans, + + &tms340x0_device::pixblt_4_op0, &tms340x0_device::pixblt_4_op0_trans, &tms340x0_device::pixblt_4_opx, &tms340x0_device::pixblt_4_opx_trans, + &tms340x0_device::pixblt_4_opx, &tms340x0_device::pixblt_4_opx_trans, &tms340x0_device::pixblt_4_opx, &tms340x0_device::pixblt_4_opx_trans, + &tms340x0_device::pixblt_4_opx, &tms340x0_device::pixblt_4_opx_trans, &tms340x0_device::pixblt_4_opx, &tms340x0_device::pixblt_4_opx_trans, + &tms340x0_device::pixblt_4_opx, &tms340x0_device::pixblt_4_opx_trans, &tms340x0_device::pixblt_4_opx, &tms340x0_device::pixblt_4_opx_trans, + &tms340x0_device::pixblt_4_opx, &tms340x0_device::pixblt_4_opx_trans, &tms340x0_device::pixblt_4_opx, &tms340x0_device::pixblt_4_opx_trans, + &tms340x0_device::pixblt_4_opx, &tms340x0_device::pixblt_4_opx_trans, &tms340x0_device::pixblt_4_opx, &tms340x0_device::pixblt_4_opx_trans, + &tms340x0_device::pixblt_4_opx, &tms340x0_device::pixblt_4_opx_trans, &tms340x0_device::pixblt_4_opx, &tms340x0_device::pixblt_4_opx_trans, + &tms340x0_device::pixblt_4_opx, &tms340x0_device::pixblt_4_opx_trans, &tms340x0_device::pixblt_4_opx, &tms340x0_device::pixblt_4_opx_trans, + &tms340x0_device::pixblt_4_opx, &tms340x0_device::pixblt_4_opx_trans, &tms340x0_device::pixblt_4_opx, &tms340x0_device::pixblt_4_opx_trans, + &tms340x0_device::pixblt_4_opx, &tms340x0_device::pixblt_4_opx_trans, &tms340x0_device::pixblt_4_opx, &tms340x0_device::pixblt_4_opx_trans, + &tms340x0_device::pixblt_4_opx, &tms340x0_device::pixblt_4_opx_trans, &tms340x0_device::pixblt_4_opx, &tms340x0_device::pixblt_4_opx_trans, + &tms340x0_device::pixblt_4_opx, &tms340x0_device::pixblt_4_opx_trans, &tms340x0_device::pixblt_4_opx, &tms340x0_device::pixblt_4_opx_trans, + &tms340x0_device::pixblt_4_opx, &tms340x0_device::pixblt_4_opx_trans, &tms340x0_device::pixblt_4_opx, &tms340x0_device::pixblt_4_opx_trans, + &tms340x0_device::pixblt_4_opx, &tms340x0_device::pixblt_4_opx_trans, &tms340x0_device::pixblt_4_opx, &tms340x0_device::pixblt_4_opx_trans, + &tms340x0_device::pixblt_4_opx, &tms340x0_device::pixblt_4_opx_trans, &tms340x0_device::pixblt_4_opx, &tms340x0_device::pixblt_4_opx_trans, + &tms340x0_device::pixblt_4_opx, &tms340x0_device::pixblt_4_opx_trans, &tms340x0_device::pixblt_4_opx, &tms340x0_device::pixblt_4_opx_trans, + + &tms340x0_device::pixblt_8_op0, &tms340x0_device::pixblt_8_op0_trans, &tms340x0_device::pixblt_8_opx, &tms340x0_device::pixblt_8_opx_trans, + &tms340x0_device::pixblt_8_opx, &tms340x0_device::pixblt_8_opx_trans, &tms340x0_device::pixblt_8_opx, &tms340x0_device::pixblt_8_opx_trans, + &tms340x0_device::pixblt_8_opx, &tms340x0_device::pixblt_8_opx_trans, &tms340x0_device::pixblt_8_opx, &tms340x0_device::pixblt_8_opx_trans, + &tms340x0_device::pixblt_8_opx, &tms340x0_device::pixblt_8_opx_trans, &tms340x0_device::pixblt_8_opx, &tms340x0_device::pixblt_8_opx_trans, + &tms340x0_device::pixblt_8_opx, &tms340x0_device::pixblt_8_opx_trans, &tms340x0_device::pixblt_8_opx, &tms340x0_device::pixblt_8_opx_trans, + &tms340x0_device::pixblt_8_opx, &tms340x0_device::pixblt_8_opx_trans, &tms340x0_device::pixblt_8_opx, &tms340x0_device::pixblt_8_opx_trans, + &tms340x0_device::pixblt_8_opx, &tms340x0_device::pixblt_8_opx_trans, &tms340x0_device::pixblt_8_opx, &tms340x0_device::pixblt_8_opx_trans, + &tms340x0_device::pixblt_8_opx, &tms340x0_device::pixblt_8_opx_trans, &tms340x0_device::pixblt_8_opx, &tms340x0_device::pixblt_8_opx_trans, + &tms340x0_device::pixblt_8_opx, &tms340x0_device::pixblt_8_opx_trans, &tms340x0_device::pixblt_8_opx, &tms340x0_device::pixblt_8_opx_trans, + &tms340x0_device::pixblt_8_opx, &tms340x0_device::pixblt_8_opx_trans, &tms340x0_device::pixblt_8_opx, &tms340x0_device::pixblt_8_opx_trans, + &tms340x0_device::pixblt_8_opx, &tms340x0_device::pixblt_8_opx_trans, &tms340x0_device::pixblt_8_opx, &tms340x0_device::pixblt_8_opx_trans, + &tms340x0_device::pixblt_8_opx, &tms340x0_device::pixblt_8_opx_trans, &tms340x0_device::pixblt_8_opx, &tms340x0_device::pixblt_8_opx_trans, + &tms340x0_device::pixblt_8_opx, &tms340x0_device::pixblt_8_opx_trans, &tms340x0_device::pixblt_8_opx, &tms340x0_device::pixblt_8_opx_trans, + &tms340x0_device::pixblt_8_opx, &tms340x0_device::pixblt_8_opx_trans, &tms340x0_device::pixblt_8_opx, &tms340x0_device::pixblt_8_opx_trans, + &tms340x0_device::pixblt_8_opx, &tms340x0_device::pixblt_8_opx_trans, &tms340x0_device::pixblt_8_opx, &tms340x0_device::pixblt_8_opx_trans, + &tms340x0_device::pixblt_8_opx, &tms340x0_device::pixblt_8_opx_trans, &tms340x0_device::pixblt_8_opx, &tms340x0_device::pixblt_8_opx_trans, + + &tms340x0_device::pixblt_16_op0, &tms340x0_device::pixblt_16_op0_trans, &tms340x0_device::pixblt_16_opx, &tms340x0_device::pixblt_16_opx_trans, + &tms340x0_device::pixblt_16_opx, &tms340x0_device::pixblt_16_opx_trans, &tms340x0_device::pixblt_16_opx, &tms340x0_device::pixblt_16_opx_trans, + &tms340x0_device::pixblt_16_opx, &tms340x0_device::pixblt_16_opx_trans, &tms340x0_device::pixblt_16_opx, &tms340x0_device::pixblt_16_opx_trans, + &tms340x0_device::pixblt_16_opx, &tms340x0_device::pixblt_16_opx_trans, &tms340x0_device::pixblt_16_opx, &tms340x0_device::pixblt_16_opx_trans, + &tms340x0_device::pixblt_16_opx, &tms340x0_device::pixblt_16_opx_trans, &tms340x0_device::pixblt_16_opx, &tms340x0_device::pixblt_16_opx_trans, + &tms340x0_device::pixblt_16_opx, &tms340x0_device::pixblt_16_opx_trans, &tms340x0_device::pixblt_16_opx, &tms340x0_device::pixblt_16_opx_trans, + &tms340x0_device::pixblt_16_opx, &tms340x0_device::pixblt_16_opx_trans, &tms340x0_device::pixblt_16_opx, &tms340x0_device::pixblt_16_opx_trans, + &tms340x0_device::pixblt_16_opx, &tms340x0_device::pixblt_16_opx_trans, &tms340x0_device::pixblt_16_opx, &tms340x0_device::pixblt_16_opx_trans, + &tms340x0_device::pixblt_16_opx, &tms340x0_device::pixblt_16_opx_trans, &tms340x0_device::pixblt_16_opx, &tms340x0_device::pixblt_16_opx_trans, + &tms340x0_device::pixblt_16_opx, &tms340x0_device::pixblt_16_opx_trans, &tms340x0_device::pixblt_16_opx, &tms340x0_device::pixblt_16_opx_trans, + &tms340x0_device::pixblt_16_opx, &tms340x0_device::pixblt_16_opx_trans, &tms340x0_device::pixblt_16_opx, &tms340x0_device::pixblt_16_opx_trans, + &tms340x0_device::pixblt_16_opx, &tms340x0_device::pixblt_16_opx_trans, &tms340x0_device::pixblt_16_opx, &tms340x0_device::pixblt_16_opx_trans, + &tms340x0_device::pixblt_16_opx, &tms340x0_device::pixblt_16_opx_trans, &tms340x0_device::pixblt_16_opx, &tms340x0_device::pixblt_16_opx_trans, + &tms340x0_device::pixblt_16_opx, &tms340x0_device::pixblt_16_opx_trans, &tms340x0_device::pixblt_16_opx, &tms340x0_device::pixblt_16_opx_trans, + &tms340x0_device::pixblt_16_opx, &tms340x0_device::pixblt_16_opx_trans, &tms340x0_device::pixblt_16_opx, &tms340x0_device::pixblt_16_opx_trans, + &tms340x0_device::pixblt_16_opx, &tms340x0_device::pixblt_16_opx_trans, &tms340x0_device::pixblt_16_opx, &tms340x0_device::pixblt_16_opx_trans +}; + +const tms340x0_device::pixblt_op_func tms340x0_device::s_pixblt_r_op_table[] = +{ + &tms340x0_device::pixblt_r_1_op0, &tms340x0_device::pixblt_r_1_op0_trans, &tms340x0_device::pixblt_r_1_opx, &tms340x0_device::pixblt_r_1_opx_trans, + &tms340x0_device::pixblt_r_1_opx, &tms340x0_device::pixblt_r_1_opx_trans, &tms340x0_device::pixblt_r_1_opx, &tms340x0_device::pixblt_r_1_opx_trans, + &tms340x0_device::pixblt_r_1_opx, &tms340x0_device::pixblt_r_1_opx_trans, &tms340x0_device::pixblt_r_1_opx, &tms340x0_device::pixblt_r_1_opx_trans, + &tms340x0_device::pixblt_r_1_opx, &tms340x0_device::pixblt_r_1_opx_trans, &tms340x0_device::pixblt_r_1_opx, &tms340x0_device::pixblt_r_1_opx_trans, + &tms340x0_device::pixblt_r_1_opx, &tms340x0_device::pixblt_r_1_opx_trans, &tms340x0_device::pixblt_r_1_opx, &tms340x0_device::pixblt_r_1_opx_trans, + &tms340x0_device::pixblt_r_1_opx, &tms340x0_device::pixblt_r_1_opx_trans, &tms340x0_device::pixblt_r_1_opx, &tms340x0_device::pixblt_r_1_opx_trans, + &tms340x0_device::pixblt_r_1_opx, &tms340x0_device::pixblt_r_1_opx_trans, &tms340x0_device::pixblt_r_1_opx, &tms340x0_device::pixblt_r_1_opx_trans, + &tms340x0_device::pixblt_r_1_opx, &tms340x0_device::pixblt_r_1_opx_trans, &tms340x0_device::pixblt_r_1_opx, &tms340x0_device::pixblt_r_1_opx_trans, + &tms340x0_device::pixblt_r_1_opx, &tms340x0_device::pixblt_r_1_opx_trans, &tms340x0_device::pixblt_r_1_opx, &tms340x0_device::pixblt_r_1_opx_trans, + &tms340x0_device::pixblt_r_1_opx, &tms340x0_device::pixblt_r_1_opx_trans, &tms340x0_device::pixblt_r_1_opx, &tms340x0_device::pixblt_r_1_opx_trans, + &tms340x0_device::pixblt_r_1_opx, &tms340x0_device::pixblt_r_1_opx_trans, &tms340x0_device::pixblt_r_1_opx, &tms340x0_device::pixblt_r_1_opx_trans, + &tms340x0_device::pixblt_r_1_opx, &tms340x0_device::pixblt_r_1_opx_trans, &tms340x0_device::pixblt_r_1_opx, &tms340x0_device::pixblt_r_1_opx_trans, + &tms340x0_device::pixblt_r_1_opx, &tms340x0_device::pixblt_r_1_opx_trans, &tms340x0_device::pixblt_r_1_opx, &tms340x0_device::pixblt_r_1_opx_trans, + &tms340x0_device::pixblt_r_1_opx, &tms340x0_device::pixblt_r_1_opx_trans, &tms340x0_device::pixblt_r_1_opx, &tms340x0_device::pixblt_r_1_opx_trans, + &tms340x0_device::pixblt_r_1_opx, &tms340x0_device::pixblt_r_1_opx_trans, &tms340x0_device::pixblt_r_1_opx, &tms340x0_device::pixblt_r_1_opx_trans, + &tms340x0_device::pixblt_r_1_opx, &tms340x0_device::pixblt_r_1_opx_trans, &tms340x0_device::pixblt_r_1_opx, &tms340x0_device::pixblt_r_1_opx_trans, + + &tms340x0_device::pixblt_r_2_op0, &tms340x0_device::pixblt_r_2_op0_trans, &tms340x0_device::pixblt_r_2_opx, &tms340x0_device::pixblt_r_2_opx_trans, + &tms340x0_device::pixblt_r_2_opx, &tms340x0_device::pixblt_r_2_opx_trans, &tms340x0_device::pixblt_r_2_opx, &tms340x0_device::pixblt_r_2_opx_trans, + &tms340x0_device::pixblt_r_2_opx, &tms340x0_device::pixblt_r_2_opx_trans, &tms340x0_device::pixblt_r_2_opx, &tms340x0_device::pixblt_r_2_opx_trans, + &tms340x0_device::pixblt_r_2_opx, &tms340x0_device::pixblt_r_2_opx_trans, &tms340x0_device::pixblt_r_2_opx, &tms340x0_device::pixblt_r_2_opx_trans, + &tms340x0_device::pixblt_r_2_opx, &tms340x0_device::pixblt_r_2_opx_trans, &tms340x0_device::pixblt_r_2_opx, &tms340x0_device::pixblt_r_2_opx_trans, + &tms340x0_device::pixblt_r_2_opx, &tms340x0_device::pixblt_r_2_opx_trans, &tms340x0_device::pixblt_r_2_opx, &tms340x0_device::pixblt_r_2_opx_trans, + &tms340x0_device::pixblt_r_2_opx, &tms340x0_device::pixblt_r_2_opx_trans, &tms340x0_device::pixblt_r_2_opx, &tms340x0_device::pixblt_r_2_opx_trans, + &tms340x0_device::pixblt_r_2_opx, &tms340x0_device::pixblt_r_2_opx_trans, &tms340x0_device::pixblt_r_2_opx, &tms340x0_device::pixblt_r_2_opx_trans, + &tms340x0_device::pixblt_r_2_opx, &tms340x0_device::pixblt_r_2_opx_trans, &tms340x0_device::pixblt_r_2_opx, &tms340x0_device::pixblt_r_2_opx_trans, + &tms340x0_device::pixblt_r_2_opx, &tms340x0_device::pixblt_r_2_opx_trans, &tms340x0_device::pixblt_r_2_opx, &tms340x0_device::pixblt_r_2_opx_trans, + &tms340x0_device::pixblt_r_2_opx, &tms340x0_device::pixblt_r_2_opx_trans, &tms340x0_device::pixblt_r_2_opx, &tms340x0_device::pixblt_r_2_opx_trans, + &tms340x0_device::pixblt_r_2_opx, &tms340x0_device::pixblt_r_2_opx_trans, &tms340x0_device::pixblt_r_2_opx, &tms340x0_device::pixblt_r_2_opx_trans, + &tms340x0_device::pixblt_r_2_opx, &tms340x0_device::pixblt_r_2_opx_trans, &tms340x0_device::pixblt_r_2_opx, &tms340x0_device::pixblt_r_2_opx_trans, + &tms340x0_device::pixblt_r_2_opx, &tms340x0_device::pixblt_r_2_opx_trans, &tms340x0_device::pixblt_r_2_opx, &tms340x0_device::pixblt_r_2_opx_trans, + &tms340x0_device::pixblt_r_2_opx, &tms340x0_device::pixblt_r_2_opx_trans, &tms340x0_device::pixblt_r_2_opx, &tms340x0_device::pixblt_r_2_opx_trans, + &tms340x0_device::pixblt_r_2_opx, &tms340x0_device::pixblt_r_2_opx_trans, &tms340x0_device::pixblt_r_2_opx, &tms340x0_device::pixblt_r_2_opx_trans, + + &tms340x0_device::pixblt_r_4_op0, &tms340x0_device::pixblt_r_4_op0_trans, &tms340x0_device::pixblt_r_4_opx, &tms340x0_device::pixblt_r_4_opx_trans, + &tms340x0_device::pixblt_r_4_opx, &tms340x0_device::pixblt_r_4_opx_trans, &tms340x0_device::pixblt_r_4_opx, &tms340x0_device::pixblt_r_4_opx_trans, + &tms340x0_device::pixblt_r_4_opx, &tms340x0_device::pixblt_r_4_opx_trans, &tms340x0_device::pixblt_r_4_opx, &tms340x0_device::pixblt_r_4_opx_trans, + &tms340x0_device::pixblt_r_4_opx, &tms340x0_device::pixblt_r_4_opx_trans, &tms340x0_device::pixblt_r_4_opx, &tms340x0_device::pixblt_r_4_opx_trans, + &tms340x0_device::pixblt_r_4_opx, &tms340x0_device::pixblt_r_4_opx_trans, &tms340x0_device::pixblt_r_4_opx, &tms340x0_device::pixblt_r_4_opx_trans, + &tms340x0_device::pixblt_r_4_opx, &tms340x0_device::pixblt_r_4_opx_trans, &tms340x0_device::pixblt_r_4_opx, &tms340x0_device::pixblt_r_4_opx_trans, + &tms340x0_device::pixblt_r_4_opx, &tms340x0_device::pixblt_r_4_opx_trans, &tms340x0_device::pixblt_r_4_opx, &tms340x0_device::pixblt_r_4_opx_trans, + &tms340x0_device::pixblt_r_4_opx, &tms340x0_device::pixblt_r_4_opx_trans, &tms340x0_device::pixblt_r_4_opx, &tms340x0_device::pixblt_r_4_opx_trans, + &tms340x0_device::pixblt_r_4_opx, &tms340x0_device::pixblt_r_4_opx_trans, &tms340x0_device::pixblt_r_4_opx, &tms340x0_device::pixblt_r_4_opx_trans, + &tms340x0_device::pixblt_r_4_opx, &tms340x0_device::pixblt_r_4_opx_trans, &tms340x0_device::pixblt_r_4_opx, &tms340x0_device::pixblt_r_4_opx_trans, + &tms340x0_device::pixblt_r_4_opx, &tms340x0_device::pixblt_r_4_opx_trans, &tms340x0_device::pixblt_r_4_opx, &tms340x0_device::pixblt_r_4_opx_trans, + &tms340x0_device::pixblt_r_4_opx, &tms340x0_device::pixblt_r_4_opx_trans, &tms340x0_device::pixblt_r_4_opx, &tms340x0_device::pixblt_r_4_opx_trans, + &tms340x0_device::pixblt_r_4_opx, &tms340x0_device::pixblt_r_4_opx_trans, &tms340x0_device::pixblt_r_4_opx, &tms340x0_device::pixblt_r_4_opx_trans, + &tms340x0_device::pixblt_r_4_opx, &tms340x0_device::pixblt_r_4_opx_trans, &tms340x0_device::pixblt_r_4_opx, &tms340x0_device::pixblt_r_4_opx_trans, + &tms340x0_device::pixblt_r_4_opx, &tms340x0_device::pixblt_r_4_opx_trans, &tms340x0_device::pixblt_r_4_opx, &tms340x0_device::pixblt_r_4_opx_trans, + &tms340x0_device::pixblt_r_4_opx, &tms340x0_device::pixblt_r_4_opx_trans, &tms340x0_device::pixblt_r_4_opx, &tms340x0_device::pixblt_r_4_opx_trans, + + &tms340x0_device::pixblt_r_8_op0, &tms340x0_device::pixblt_r_8_op0_trans, &tms340x0_device::pixblt_r_8_opx, &tms340x0_device::pixblt_r_8_opx_trans, + &tms340x0_device::pixblt_r_8_opx, &tms340x0_device::pixblt_r_8_opx_trans, &tms340x0_device::pixblt_r_8_opx, &tms340x0_device::pixblt_r_8_opx_trans, + &tms340x0_device::pixblt_r_8_opx, &tms340x0_device::pixblt_r_8_opx_trans, &tms340x0_device::pixblt_r_8_opx, &tms340x0_device::pixblt_r_8_opx_trans, + &tms340x0_device::pixblt_r_8_opx, &tms340x0_device::pixblt_r_8_opx_trans, &tms340x0_device::pixblt_r_8_opx, &tms340x0_device::pixblt_r_8_opx_trans, + &tms340x0_device::pixblt_r_8_opx, &tms340x0_device::pixblt_r_8_opx_trans, &tms340x0_device::pixblt_r_8_opx, &tms340x0_device::pixblt_r_8_opx_trans, + &tms340x0_device::pixblt_r_8_opx, &tms340x0_device::pixblt_r_8_opx_trans, &tms340x0_device::pixblt_r_8_opx, &tms340x0_device::pixblt_r_8_opx_trans, + &tms340x0_device::pixblt_r_8_opx, &tms340x0_device::pixblt_r_8_opx_trans, &tms340x0_device::pixblt_r_8_opx, &tms340x0_device::pixblt_r_8_opx_trans, + &tms340x0_device::pixblt_r_8_opx, &tms340x0_device::pixblt_r_8_opx_trans, &tms340x0_device::pixblt_r_8_opx, &tms340x0_device::pixblt_r_8_opx_trans, + &tms340x0_device::pixblt_r_8_opx, &tms340x0_device::pixblt_r_8_opx_trans, &tms340x0_device::pixblt_r_8_opx, &tms340x0_device::pixblt_r_8_opx_trans, + &tms340x0_device::pixblt_r_8_opx, &tms340x0_device::pixblt_r_8_opx_trans, &tms340x0_device::pixblt_r_8_opx, &tms340x0_device::pixblt_r_8_opx_trans, + &tms340x0_device::pixblt_r_8_opx, &tms340x0_device::pixblt_r_8_opx_trans, &tms340x0_device::pixblt_r_8_opx, &tms340x0_device::pixblt_r_8_opx_trans, + &tms340x0_device::pixblt_r_8_opx, &tms340x0_device::pixblt_r_8_opx_trans, &tms340x0_device::pixblt_r_8_opx, &tms340x0_device::pixblt_r_8_opx_trans, + &tms340x0_device::pixblt_r_8_opx, &tms340x0_device::pixblt_r_8_opx_trans, &tms340x0_device::pixblt_r_8_opx, &tms340x0_device::pixblt_r_8_opx_trans, + &tms340x0_device::pixblt_r_8_opx, &tms340x0_device::pixblt_r_8_opx_trans, &tms340x0_device::pixblt_r_8_opx, &tms340x0_device::pixblt_r_8_opx_trans, + &tms340x0_device::pixblt_r_8_opx, &tms340x0_device::pixblt_r_8_opx_trans, &tms340x0_device::pixblt_r_8_opx, &tms340x0_device::pixblt_r_8_opx_trans, + &tms340x0_device::pixblt_r_8_opx, &tms340x0_device::pixblt_r_8_opx_trans, &tms340x0_device::pixblt_r_8_opx, &tms340x0_device::pixblt_r_8_opx_trans, + + &tms340x0_device::pixblt_r_16_op0,&tms340x0_device::pixblt_r_16_op0_trans, &tms340x0_device::pixblt_r_16_opx,&tms340x0_device::pixblt_r_16_opx_trans, + &tms340x0_device::pixblt_r_16_opx,&tms340x0_device::pixblt_r_16_opx_trans, &tms340x0_device::pixblt_r_16_opx,&tms340x0_device::pixblt_r_16_opx_trans, + &tms340x0_device::pixblt_r_16_opx,&tms340x0_device::pixblt_r_16_opx_trans, &tms340x0_device::pixblt_r_16_opx,&tms340x0_device::pixblt_r_16_opx_trans, + &tms340x0_device::pixblt_r_16_opx,&tms340x0_device::pixblt_r_16_opx_trans, &tms340x0_device::pixblt_r_16_opx,&tms340x0_device::pixblt_r_16_opx_trans, + &tms340x0_device::pixblt_r_16_opx,&tms340x0_device::pixblt_r_16_opx_trans, &tms340x0_device::pixblt_r_16_opx,&tms340x0_device::pixblt_r_16_opx_trans, + &tms340x0_device::pixblt_r_16_opx,&tms340x0_device::pixblt_r_16_opx_trans, &tms340x0_device::pixblt_r_16_opx,&tms340x0_device::pixblt_r_16_opx_trans, + &tms340x0_device::pixblt_r_16_opx,&tms340x0_device::pixblt_r_16_opx_trans, &tms340x0_device::pixblt_r_16_opx,&tms340x0_device::pixblt_r_16_opx_trans, + &tms340x0_device::pixblt_r_16_opx,&tms340x0_device::pixblt_r_16_opx_trans, &tms340x0_device::pixblt_r_16_opx,&tms340x0_device::pixblt_r_16_opx_trans, + &tms340x0_device::pixblt_r_16_opx,&tms340x0_device::pixblt_r_16_opx_trans, &tms340x0_device::pixblt_r_16_opx,&tms340x0_device::pixblt_r_16_opx_trans, + &tms340x0_device::pixblt_r_16_opx,&tms340x0_device::pixblt_r_16_opx_trans, &tms340x0_device::pixblt_r_16_opx,&tms340x0_device::pixblt_r_16_opx_trans, + &tms340x0_device::pixblt_r_16_opx,&tms340x0_device::pixblt_r_16_opx_trans, &tms340x0_device::pixblt_r_16_opx,&tms340x0_device::pixblt_r_16_opx_trans, + &tms340x0_device::pixblt_r_16_opx,&tms340x0_device::pixblt_r_16_opx_trans, &tms340x0_device::pixblt_r_16_opx,&tms340x0_device::pixblt_r_16_opx_trans, + &tms340x0_device::pixblt_r_16_opx,&tms340x0_device::pixblt_r_16_opx_trans, &tms340x0_device::pixblt_r_16_opx,&tms340x0_device::pixblt_r_16_opx_trans, + &tms340x0_device::pixblt_r_16_opx,&tms340x0_device::pixblt_r_16_opx_trans, &tms340x0_device::pixblt_r_16_opx,&tms340x0_device::pixblt_r_16_opx_trans, + &tms340x0_device::pixblt_r_16_opx,&tms340x0_device::pixblt_r_16_opx_trans, &tms340x0_device::pixblt_r_16_opx,&tms340x0_device::pixblt_r_16_opx_trans, + &tms340x0_device::pixblt_r_16_opx,&tms340x0_device::pixblt_r_16_opx_trans, &tms340x0_device::pixblt_r_16_opx,&tms340x0_device::pixblt_r_16_opx_trans +}; + +const tms340x0_device::pixblt_b_op_func tms340x0_device::s_pixblt_b_op_table[] = +{ + &tms340x0_device::pixblt_b_1_op0, &tms340x0_device::pixblt_b_1_op0_trans, &tms340x0_device::pixblt_b_1_opx, &tms340x0_device::pixblt_b_1_opx_trans, + &tms340x0_device::pixblt_b_1_opx, &tms340x0_device::pixblt_b_1_opx_trans, &tms340x0_device::pixblt_b_1_opx, &tms340x0_device::pixblt_b_1_opx_trans, + &tms340x0_device::pixblt_b_1_opx, &tms340x0_device::pixblt_b_1_opx_trans, &tms340x0_device::pixblt_b_1_opx, &tms340x0_device::pixblt_b_1_opx_trans, + &tms340x0_device::pixblt_b_1_opx, &tms340x0_device::pixblt_b_1_opx_trans, &tms340x0_device::pixblt_b_1_opx, &tms340x0_device::pixblt_b_1_opx_trans, + &tms340x0_device::pixblt_b_1_opx, &tms340x0_device::pixblt_b_1_opx_trans, &tms340x0_device::pixblt_b_1_opx, &tms340x0_device::pixblt_b_1_opx_trans, + &tms340x0_device::pixblt_b_1_opx, &tms340x0_device::pixblt_b_1_opx_trans, &tms340x0_device::pixblt_b_1_opx, &tms340x0_device::pixblt_b_1_opx_trans, + &tms340x0_device::pixblt_b_1_opx, &tms340x0_device::pixblt_b_1_opx_trans, &tms340x0_device::pixblt_b_1_opx, &tms340x0_device::pixblt_b_1_opx_trans, + &tms340x0_device::pixblt_b_1_opx, &tms340x0_device::pixblt_b_1_opx_trans, &tms340x0_device::pixblt_b_1_opx, &tms340x0_device::pixblt_b_1_opx_trans, + &tms340x0_device::pixblt_b_1_opx, &tms340x0_device::pixblt_b_1_opx_trans, &tms340x0_device::pixblt_b_1_opx, &tms340x0_device::pixblt_b_1_opx_trans, + &tms340x0_device::pixblt_b_1_opx, &tms340x0_device::pixblt_b_1_opx_trans, &tms340x0_device::pixblt_b_1_opx, &tms340x0_device::pixblt_b_1_opx_trans, + &tms340x0_device::pixblt_b_1_opx, &tms340x0_device::pixblt_b_1_opx_trans, &tms340x0_device::pixblt_b_1_opx, &tms340x0_device::pixblt_b_1_opx_trans, + &tms340x0_device::pixblt_b_1_opx, &tms340x0_device::pixblt_b_1_opx_trans, &tms340x0_device::pixblt_b_1_opx, &tms340x0_device::pixblt_b_1_opx_trans, + &tms340x0_device::pixblt_b_1_opx, &tms340x0_device::pixblt_b_1_opx_trans, &tms340x0_device::pixblt_b_1_opx, &tms340x0_device::pixblt_b_1_opx_trans, + &tms340x0_device::pixblt_b_1_opx, &tms340x0_device::pixblt_b_1_opx_trans, &tms340x0_device::pixblt_b_1_opx, &tms340x0_device::pixblt_b_1_opx_trans, + &tms340x0_device::pixblt_b_1_opx, &tms340x0_device::pixblt_b_1_opx_trans, &tms340x0_device::pixblt_b_1_opx, &tms340x0_device::pixblt_b_1_opx_trans, + &tms340x0_device::pixblt_b_1_opx, &tms340x0_device::pixblt_b_1_opx_trans, &tms340x0_device::pixblt_b_1_opx, &tms340x0_device::pixblt_b_1_opx_trans, + + &tms340x0_device::pixblt_b_2_op0, &tms340x0_device::pixblt_b_2_op0_trans, &tms340x0_device::pixblt_b_2_opx, &tms340x0_device::pixblt_b_2_opx_trans, + &tms340x0_device::pixblt_b_2_opx, &tms340x0_device::pixblt_b_2_opx_trans, &tms340x0_device::pixblt_b_2_opx, &tms340x0_device::pixblt_b_2_opx_trans, + &tms340x0_device::pixblt_b_2_opx, &tms340x0_device::pixblt_b_2_opx_trans, &tms340x0_device::pixblt_b_2_opx, &tms340x0_device::pixblt_b_2_opx_trans, + &tms340x0_device::pixblt_b_2_opx, &tms340x0_device::pixblt_b_2_opx_trans, &tms340x0_device::pixblt_b_2_opx, &tms340x0_device::pixblt_b_2_opx_trans, + &tms340x0_device::pixblt_b_2_opx, &tms340x0_device::pixblt_b_2_opx_trans, &tms340x0_device::pixblt_b_2_opx, &tms340x0_device::pixblt_b_2_opx_trans, + &tms340x0_device::pixblt_b_2_opx, &tms340x0_device::pixblt_b_2_opx_trans, &tms340x0_device::pixblt_b_2_opx, &tms340x0_device::pixblt_b_2_opx_trans, + &tms340x0_device::pixblt_b_2_opx, &tms340x0_device::pixblt_b_2_opx_trans, &tms340x0_device::pixblt_b_2_opx, &tms340x0_device::pixblt_b_2_opx_trans, + &tms340x0_device::pixblt_b_2_opx, &tms340x0_device::pixblt_b_2_opx_trans, &tms340x0_device::pixblt_b_2_opx, &tms340x0_device::pixblt_b_2_opx_trans, + &tms340x0_device::pixblt_b_2_opx, &tms340x0_device::pixblt_b_2_opx_trans, &tms340x0_device::pixblt_b_2_opx, &tms340x0_device::pixblt_b_2_opx_trans, + &tms340x0_device::pixblt_b_2_opx, &tms340x0_device::pixblt_b_2_opx_trans, &tms340x0_device::pixblt_b_2_opx, &tms340x0_device::pixblt_b_2_opx_trans, + &tms340x0_device::pixblt_b_2_opx, &tms340x0_device::pixblt_b_2_opx_trans, &tms340x0_device::pixblt_b_2_opx, &tms340x0_device::pixblt_b_2_opx_trans, + &tms340x0_device::pixblt_b_2_opx, &tms340x0_device::pixblt_b_2_opx_trans, &tms340x0_device::pixblt_b_2_opx, &tms340x0_device::pixblt_b_2_opx_trans, + &tms340x0_device::pixblt_b_2_opx, &tms340x0_device::pixblt_b_2_opx_trans, &tms340x0_device::pixblt_b_2_opx, &tms340x0_device::pixblt_b_2_opx_trans, + &tms340x0_device::pixblt_b_2_opx, &tms340x0_device::pixblt_b_2_opx_trans, &tms340x0_device::pixblt_b_2_opx, &tms340x0_device::pixblt_b_2_opx_trans, + &tms340x0_device::pixblt_b_2_opx, &tms340x0_device::pixblt_b_2_opx_trans, &tms340x0_device::pixblt_b_2_opx, &tms340x0_device::pixblt_b_2_opx_trans, + &tms340x0_device::pixblt_b_2_opx, &tms340x0_device::pixblt_b_2_opx_trans, &tms340x0_device::pixblt_b_2_opx, &tms340x0_device::pixblt_b_2_opx_trans, + + &tms340x0_device::pixblt_b_4_op0, &tms340x0_device::pixblt_b_4_op0_trans, &tms340x0_device::pixblt_b_4_opx, &tms340x0_device::pixblt_b_4_opx_trans, + &tms340x0_device::pixblt_b_4_opx, &tms340x0_device::pixblt_b_4_opx_trans, &tms340x0_device::pixblt_b_4_opx, &tms340x0_device::pixblt_b_4_opx_trans, + &tms340x0_device::pixblt_b_4_opx, &tms340x0_device::pixblt_b_4_opx_trans, &tms340x0_device::pixblt_b_4_opx, &tms340x0_device::pixblt_b_4_opx_trans, + &tms340x0_device::pixblt_b_4_opx, &tms340x0_device::pixblt_b_4_opx_trans, &tms340x0_device::pixblt_b_4_opx, &tms340x0_device::pixblt_b_4_opx_trans, + &tms340x0_device::pixblt_b_4_opx, &tms340x0_device::pixblt_b_4_opx_trans, &tms340x0_device::pixblt_b_4_opx, &tms340x0_device::pixblt_b_4_opx_trans, + &tms340x0_device::pixblt_b_4_opx, &tms340x0_device::pixblt_b_4_opx_trans, &tms340x0_device::pixblt_b_4_opx, &tms340x0_device::pixblt_b_4_opx_trans, + &tms340x0_device::pixblt_b_4_opx, &tms340x0_device::pixblt_b_4_opx_trans, &tms340x0_device::pixblt_b_4_opx, &tms340x0_device::pixblt_b_4_opx_trans, + &tms340x0_device::pixblt_b_4_opx, &tms340x0_device::pixblt_b_4_opx_trans, &tms340x0_device::pixblt_b_4_opx, &tms340x0_device::pixblt_b_4_opx_trans, + &tms340x0_device::pixblt_b_4_opx, &tms340x0_device::pixblt_b_4_opx_trans, &tms340x0_device::pixblt_b_4_opx, &tms340x0_device::pixblt_b_4_opx_trans, + &tms340x0_device::pixblt_b_4_opx, &tms340x0_device::pixblt_b_4_opx_trans, &tms340x0_device::pixblt_b_4_opx, &tms340x0_device::pixblt_b_4_opx_trans, + &tms340x0_device::pixblt_b_4_opx, &tms340x0_device::pixblt_b_4_opx_trans, &tms340x0_device::pixblt_b_4_opx, &tms340x0_device::pixblt_b_4_opx_trans, + &tms340x0_device::pixblt_b_4_opx, &tms340x0_device::pixblt_b_4_opx_trans, &tms340x0_device::pixblt_b_4_opx, &tms340x0_device::pixblt_b_4_opx_trans, + &tms340x0_device::pixblt_b_4_opx, &tms340x0_device::pixblt_b_4_opx_trans, &tms340x0_device::pixblt_b_4_opx, &tms340x0_device::pixblt_b_4_opx_trans, + &tms340x0_device::pixblt_b_4_opx, &tms340x0_device::pixblt_b_4_opx_trans, &tms340x0_device::pixblt_b_4_opx, &tms340x0_device::pixblt_b_4_opx_trans, + &tms340x0_device::pixblt_b_4_opx, &tms340x0_device::pixblt_b_4_opx_trans, &tms340x0_device::pixblt_b_4_opx, &tms340x0_device::pixblt_b_4_opx_trans, + &tms340x0_device::pixblt_b_4_opx, &tms340x0_device::pixblt_b_4_opx_trans, &tms340x0_device::pixblt_b_4_opx, &tms340x0_device::pixblt_b_4_opx_trans, + + &tms340x0_device::pixblt_b_8_op0, &tms340x0_device::pixblt_b_8_op0_trans, &tms340x0_device::pixblt_b_8_opx, &tms340x0_device::pixblt_b_8_opx_trans, + &tms340x0_device::pixblt_b_8_opx, &tms340x0_device::pixblt_b_8_opx_trans, &tms340x0_device::pixblt_b_8_opx, &tms340x0_device::pixblt_b_8_opx_trans, + &tms340x0_device::pixblt_b_8_opx, &tms340x0_device::pixblt_b_8_opx_trans, &tms340x0_device::pixblt_b_8_opx, &tms340x0_device::pixblt_b_8_opx_trans, + &tms340x0_device::pixblt_b_8_opx, &tms340x0_device::pixblt_b_8_opx_trans, &tms340x0_device::pixblt_b_8_opx, &tms340x0_device::pixblt_b_8_opx_trans, + &tms340x0_device::pixblt_b_8_opx, &tms340x0_device::pixblt_b_8_opx_trans, &tms340x0_device::pixblt_b_8_opx, &tms340x0_device::pixblt_b_8_opx_trans, + &tms340x0_device::pixblt_b_8_opx, &tms340x0_device::pixblt_b_8_opx_trans, &tms340x0_device::pixblt_b_8_opx, &tms340x0_device::pixblt_b_8_opx_trans, + &tms340x0_device::pixblt_b_8_opx, &tms340x0_device::pixblt_b_8_opx_trans, &tms340x0_device::pixblt_b_8_opx, &tms340x0_device::pixblt_b_8_opx_trans, + &tms340x0_device::pixblt_b_8_opx, &tms340x0_device::pixblt_b_8_opx_trans, &tms340x0_device::pixblt_b_8_opx, &tms340x0_device::pixblt_b_8_opx_trans, + &tms340x0_device::pixblt_b_8_opx, &tms340x0_device::pixblt_b_8_opx_trans, &tms340x0_device::pixblt_b_8_opx, &tms340x0_device::pixblt_b_8_opx_trans, + &tms340x0_device::pixblt_b_8_opx, &tms340x0_device::pixblt_b_8_opx_trans, &tms340x0_device::pixblt_b_8_opx, &tms340x0_device::pixblt_b_8_opx_trans, + &tms340x0_device::pixblt_b_8_opx, &tms340x0_device::pixblt_b_8_opx_trans, &tms340x0_device::pixblt_b_8_opx, &tms340x0_device::pixblt_b_8_opx_trans, + &tms340x0_device::pixblt_b_8_opx, &tms340x0_device::pixblt_b_8_opx_trans, &tms340x0_device::pixblt_b_8_opx, &tms340x0_device::pixblt_b_8_opx_trans, + &tms340x0_device::pixblt_b_8_opx, &tms340x0_device::pixblt_b_8_opx_trans, &tms340x0_device::pixblt_b_8_opx, &tms340x0_device::pixblt_b_8_opx_trans, + &tms340x0_device::pixblt_b_8_opx, &tms340x0_device::pixblt_b_8_opx_trans, &tms340x0_device::pixblt_b_8_opx, &tms340x0_device::pixblt_b_8_opx_trans, + &tms340x0_device::pixblt_b_8_opx, &tms340x0_device::pixblt_b_8_opx_trans, &tms340x0_device::pixblt_b_8_opx, &tms340x0_device::pixblt_b_8_opx_trans, + &tms340x0_device::pixblt_b_8_opx, &tms340x0_device::pixblt_b_8_opx_trans, &tms340x0_device::pixblt_b_8_opx, &tms340x0_device::pixblt_b_8_opx_trans, + + &tms340x0_device::pixblt_b_16_op0,&tms340x0_device::pixblt_b_16_op0_trans, &tms340x0_device::pixblt_b_16_opx,&tms340x0_device::pixblt_b_16_opx_trans, + &tms340x0_device::pixblt_b_16_opx,&tms340x0_device::pixblt_b_16_opx_trans, &tms340x0_device::pixblt_b_16_opx,&tms340x0_device::pixblt_b_16_opx_trans, + &tms340x0_device::pixblt_b_16_opx,&tms340x0_device::pixblt_b_16_opx_trans, &tms340x0_device::pixblt_b_16_opx,&tms340x0_device::pixblt_b_16_opx_trans, + &tms340x0_device::pixblt_b_16_opx,&tms340x0_device::pixblt_b_16_opx_trans, &tms340x0_device::pixblt_b_16_opx,&tms340x0_device::pixblt_b_16_opx_trans, + &tms340x0_device::pixblt_b_16_opx,&tms340x0_device::pixblt_b_16_opx_trans, &tms340x0_device::pixblt_b_16_opx,&tms340x0_device::pixblt_b_16_opx_trans, + &tms340x0_device::pixblt_b_16_opx,&tms340x0_device::pixblt_b_16_opx_trans, &tms340x0_device::pixblt_b_16_opx,&tms340x0_device::pixblt_b_16_opx_trans, + &tms340x0_device::pixblt_b_16_opx,&tms340x0_device::pixblt_b_16_opx_trans, &tms340x0_device::pixblt_b_16_opx,&tms340x0_device::pixblt_b_16_opx_trans, + &tms340x0_device::pixblt_b_16_opx,&tms340x0_device::pixblt_b_16_opx_trans, &tms340x0_device::pixblt_b_16_opx,&tms340x0_device::pixblt_b_16_opx_trans, + &tms340x0_device::pixblt_b_16_opx,&tms340x0_device::pixblt_b_16_opx_trans, &tms340x0_device::pixblt_b_16_opx,&tms340x0_device::pixblt_b_16_opx_trans, + &tms340x0_device::pixblt_b_16_opx,&tms340x0_device::pixblt_b_16_opx_trans, &tms340x0_device::pixblt_b_16_opx,&tms340x0_device::pixblt_b_16_opx_trans, + &tms340x0_device::pixblt_b_16_opx,&tms340x0_device::pixblt_b_16_opx_trans, &tms340x0_device::pixblt_b_16_opx,&tms340x0_device::pixblt_b_16_opx_trans, + &tms340x0_device::pixblt_b_16_opx,&tms340x0_device::pixblt_b_16_opx_trans, &tms340x0_device::pixblt_b_16_opx,&tms340x0_device::pixblt_b_16_opx_trans, + &tms340x0_device::pixblt_b_16_opx,&tms340x0_device::pixblt_b_16_opx_trans, &tms340x0_device::pixblt_b_16_opx,&tms340x0_device::pixblt_b_16_opx_trans, + &tms340x0_device::pixblt_b_16_opx,&tms340x0_device::pixblt_b_16_opx_trans, &tms340x0_device::pixblt_b_16_opx,&tms340x0_device::pixblt_b_16_opx_trans, + &tms340x0_device::pixblt_b_16_opx,&tms340x0_device::pixblt_b_16_opx_trans, &tms340x0_device::pixblt_b_16_opx,&tms340x0_device::pixblt_b_16_opx_trans, + &tms340x0_device::pixblt_b_16_opx,&tms340x0_device::pixblt_b_16_opx_trans, &tms340x0_device::pixblt_b_16_opx,&tms340x0_device::pixblt_b_16_opx_trans +}; + +const tms340x0_device::pixblt_b_op_func tms340x0_device::s_fill_op_table[] = +{ + &tms340x0_device::fill_1_op0, &tms340x0_device::fill_1_op0_trans, &tms340x0_device::fill_1_opx, &tms340x0_device::fill_1_opx_trans, + &tms340x0_device::fill_1_opx, &tms340x0_device::fill_1_opx_trans, &tms340x0_device::fill_1_opx, &tms340x0_device::fill_1_opx_trans, + &tms340x0_device::fill_1_opx, &tms340x0_device::fill_1_opx_trans, &tms340x0_device::fill_1_opx, &tms340x0_device::fill_1_opx_trans, + &tms340x0_device::fill_1_opx, &tms340x0_device::fill_1_opx_trans, &tms340x0_device::fill_1_opx, &tms340x0_device::fill_1_opx_trans, + &tms340x0_device::fill_1_opx, &tms340x0_device::fill_1_opx_trans, &tms340x0_device::fill_1_opx, &tms340x0_device::fill_1_opx_trans, + &tms340x0_device::fill_1_opx, &tms340x0_device::fill_1_opx_trans, &tms340x0_device::fill_1_opx, &tms340x0_device::fill_1_opx_trans, + &tms340x0_device::fill_1_opx, &tms340x0_device::fill_1_opx_trans, &tms340x0_device::fill_1_opx, &tms340x0_device::fill_1_opx_trans, + &tms340x0_device::fill_1_opx, &tms340x0_device::fill_1_opx_trans, &tms340x0_device::fill_1_opx, &tms340x0_device::fill_1_opx_trans, + &tms340x0_device::fill_1_opx, &tms340x0_device::fill_1_opx_trans, &tms340x0_device::fill_1_opx, &tms340x0_device::fill_1_opx_trans, + &tms340x0_device::fill_1_opx, &tms340x0_device::fill_1_opx_trans, &tms340x0_device::fill_1_opx, &tms340x0_device::fill_1_opx_trans, + &tms340x0_device::fill_1_opx, &tms340x0_device::fill_1_opx_trans, &tms340x0_device::fill_1_opx, &tms340x0_device::fill_1_opx_trans, + &tms340x0_device::fill_1_opx, &tms340x0_device::fill_1_opx_trans, &tms340x0_device::fill_1_opx, &tms340x0_device::fill_1_opx_trans, + &tms340x0_device::fill_1_opx, &tms340x0_device::fill_1_opx_trans, &tms340x0_device::fill_1_opx, &tms340x0_device::fill_1_opx_trans, + &tms340x0_device::fill_1_opx, &tms340x0_device::fill_1_opx_trans, &tms340x0_device::fill_1_opx, &tms340x0_device::fill_1_opx_trans, + &tms340x0_device::fill_1_opx, &tms340x0_device::fill_1_opx_trans, &tms340x0_device::fill_1_opx, &tms340x0_device::fill_1_opx_trans, + &tms340x0_device::fill_1_opx, &tms340x0_device::fill_1_opx_trans, &tms340x0_device::fill_1_opx, &tms340x0_device::fill_1_opx_trans, + + &tms340x0_device::fill_2_op0, &tms340x0_device::fill_2_op0_trans, &tms340x0_device::fill_2_opx, &tms340x0_device::fill_2_opx_trans, + &tms340x0_device::fill_2_opx, &tms340x0_device::fill_2_opx_trans, &tms340x0_device::fill_2_opx, &tms340x0_device::fill_2_opx_trans, + &tms340x0_device::fill_2_opx, &tms340x0_device::fill_2_opx_trans, &tms340x0_device::fill_2_opx, &tms340x0_device::fill_2_opx_trans, + &tms340x0_device::fill_2_opx, &tms340x0_device::fill_2_opx_trans, &tms340x0_device::fill_2_opx, &tms340x0_device::fill_2_opx_trans, + &tms340x0_device::fill_2_opx, &tms340x0_device::fill_2_opx_trans, &tms340x0_device::fill_2_opx, &tms340x0_device::fill_2_opx_trans, + &tms340x0_device::fill_2_opx, &tms340x0_device::fill_2_opx_trans, &tms340x0_device::fill_2_opx, &tms340x0_device::fill_2_opx_trans, + &tms340x0_device::fill_2_opx, &tms340x0_device::fill_2_opx_trans, &tms340x0_device::fill_2_opx, &tms340x0_device::fill_2_opx_trans, + &tms340x0_device::fill_2_opx, &tms340x0_device::fill_2_opx_trans, &tms340x0_device::fill_2_opx, &tms340x0_device::fill_2_opx_trans, + &tms340x0_device::fill_2_opx, &tms340x0_device::fill_2_opx_trans, &tms340x0_device::fill_2_opx, &tms340x0_device::fill_2_opx_trans, + &tms340x0_device::fill_2_opx, &tms340x0_device::fill_2_opx_trans, &tms340x0_device::fill_2_opx, &tms340x0_device::fill_2_opx_trans, + &tms340x0_device::fill_2_opx, &tms340x0_device::fill_2_opx_trans, &tms340x0_device::fill_2_opx, &tms340x0_device::fill_2_opx_trans, + &tms340x0_device::fill_2_opx, &tms340x0_device::fill_2_opx_trans, &tms340x0_device::fill_2_opx, &tms340x0_device::fill_2_opx_trans, + &tms340x0_device::fill_2_opx, &tms340x0_device::fill_2_opx_trans, &tms340x0_device::fill_2_opx, &tms340x0_device::fill_2_opx_trans, + &tms340x0_device::fill_2_opx, &tms340x0_device::fill_2_opx_trans, &tms340x0_device::fill_2_opx, &tms340x0_device::fill_2_opx_trans, + &tms340x0_device::fill_2_opx, &tms340x0_device::fill_2_opx_trans, &tms340x0_device::fill_2_opx, &tms340x0_device::fill_2_opx_trans, + &tms340x0_device::fill_2_opx, &tms340x0_device::fill_2_opx_trans, &tms340x0_device::fill_2_opx, &tms340x0_device::fill_2_opx_trans, + + &tms340x0_device::fill_4_op0, &tms340x0_device::fill_4_op0_trans, &tms340x0_device::fill_4_opx, &tms340x0_device::fill_4_opx_trans, + &tms340x0_device::fill_4_opx, &tms340x0_device::fill_4_opx_trans, &tms340x0_device::fill_4_opx, &tms340x0_device::fill_4_opx_trans, + &tms340x0_device::fill_4_opx, &tms340x0_device::fill_4_opx_trans, &tms340x0_device::fill_4_opx, &tms340x0_device::fill_4_opx_trans, + &tms340x0_device::fill_4_opx, &tms340x0_device::fill_4_opx_trans, &tms340x0_device::fill_4_opx, &tms340x0_device::fill_4_opx_trans, + &tms340x0_device::fill_4_opx, &tms340x0_device::fill_4_opx_trans, &tms340x0_device::fill_4_opx, &tms340x0_device::fill_4_opx_trans, + &tms340x0_device::fill_4_opx, &tms340x0_device::fill_4_opx_trans, &tms340x0_device::fill_4_opx, &tms340x0_device::fill_4_opx_trans, + &tms340x0_device::fill_4_opx, &tms340x0_device::fill_4_opx_trans, &tms340x0_device::fill_4_opx, &tms340x0_device::fill_4_opx_trans, + &tms340x0_device::fill_4_opx, &tms340x0_device::fill_4_opx_trans, &tms340x0_device::fill_4_opx, &tms340x0_device::fill_4_opx_trans, + &tms340x0_device::fill_4_opx, &tms340x0_device::fill_4_opx_trans, &tms340x0_device::fill_4_opx, &tms340x0_device::fill_4_opx_trans, + &tms340x0_device::fill_4_opx, &tms340x0_device::fill_4_opx_trans, &tms340x0_device::fill_4_opx, &tms340x0_device::fill_4_opx_trans, + &tms340x0_device::fill_4_opx, &tms340x0_device::fill_4_opx_trans, &tms340x0_device::fill_4_opx, &tms340x0_device::fill_4_opx_trans, + &tms340x0_device::fill_4_opx, &tms340x0_device::fill_4_opx_trans, &tms340x0_device::fill_4_opx, &tms340x0_device::fill_4_opx_trans, + &tms340x0_device::fill_4_opx, &tms340x0_device::fill_4_opx_trans, &tms340x0_device::fill_4_opx, &tms340x0_device::fill_4_opx_trans, + &tms340x0_device::fill_4_opx, &tms340x0_device::fill_4_opx_trans, &tms340x0_device::fill_4_opx, &tms340x0_device::fill_4_opx_trans, + &tms340x0_device::fill_4_opx, &tms340x0_device::fill_4_opx_trans, &tms340x0_device::fill_4_opx, &tms340x0_device::fill_4_opx_trans, + &tms340x0_device::fill_4_opx, &tms340x0_device::fill_4_opx_trans, &tms340x0_device::fill_4_opx, &tms340x0_device::fill_4_opx_trans, + + &tms340x0_device::fill_8_op0, &tms340x0_device::fill_8_op0_trans, &tms340x0_device::fill_8_opx, &tms340x0_device::fill_8_opx_trans, + &tms340x0_device::fill_8_opx, &tms340x0_device::fill_8_opx_trans, &tms340x0_device::fill_8_opx, &tms340x0_device::fill_8_opx_trans, + &tms340x0_device::fill_8_opx, &tms340x0_device::fill_8_opx_trans, &tms340x0_device::fill_8_opx, &tms340x0_device::fill_8_opx_trans, + &tms340x0_device::fill_8_opx, &tms340x0_device::fill_8_opx_trans, &tms340x0_device::fill_8_opx, &tms340x0_device::fill_8_opx_trans, + &tms340x0_device::fill_8_opx, &tms340x0_device::fill_8_opx_trans, &tms340x0_device::fill_8_opx, &tms340x0_device::fill_8_opx_trans, + &tms340x0_device::fill_8_opx, &tms340x0_device::fill_8_opx_trans, &tms340x0_device::fill_8_opx, &tms340x0_device::fill_8_opx_trans, + &tms340x0_device::fill_8_opx, &tms340x0_device::fill_8_opx_trans, &tms340x0_device::fill_8_opx, &tms340x0_device::fill_8_opx_trans, + &tms340x0_device::fill_8_opx, &tms340x0_device::fill_8_opx_trans, &tms340x0_device::fill_8_opx, &tms340x0_device::fill_8_opx_trans, + &tms340x0_device::fill_8_opx, &tms340x0_device::fill_8_opx_trans, &tms340x0_device::fill_8_opx, &tms340x0_device::fill_8_opx_trans, + &tms340x0_device::fill_8_opx, &tms340x0_device::fill_8_opx_trans, &tms340x0_device::fill_8_opx, &tms340x0_device::fill_8_opx_trans, + &tms340x0_device::fill_8_opx, &tms340x0_device::fill_8_opx_trans, &tms340x0_device::fill_8_opx, &tms340x0_device::fill_8_opx_trans, + &tms340x0_device::fill_8_opx, &tms340x0_device::fill_8_opx_trans, &tms340x0_device::fill_8_opx, &tms340x0_device::fill_8_opx_trans, + &tms340x0_device::fill_8_opx, &tms340x0_device::fill_8_opx_trans, &tms340x0_device::fill_8_opx, &tms340x0_device::fill_8_opx_trans, + &tms340x0_device::fill_8_opx, &tms340x0_device::fill_8_opx_trans, &tms340x0_device::fill_8_opx, &tms340x0_device::fill_8_opx_trans, + &tms340x0_device::fill_8_opx, &tms340x0_device::fill_8_opx_trans, &tms340x0_device::fill_8_opx, &tms340x0_device::fill_8_opx_trans, + &tms340x0_device::fill_8_opx, &tms340x0_device::fill_8_opx_trans, &tms340x0_device::fill_8_opx, &tms340x0_device::fill_8_opx_trans, + + &tms340x0_device::fill_16_op0, &tms340x0_device::fill_16_op0_trans, &tms340x0_device::fill_16_opx, &tms340x0_device::fill_16_opx_trans, + &tms340x0_device::fill_16_opx, &tms340x0_device::fill_16_opx_trans, &tms340x0_device::fill_16_opx, &tms340x0_device::fill_16_opx_trans, + &tms340x0_device::fill_16_opx, &tms340x0_device::fill_16_opx_trans, &tms340x0_device::fill_16_opx, &tms340x0_device::fill_16_opx_trans, + &tms340x0_device::fill_16_opx, &tms340x0_device::fill_16_opx_trans, &tms340x0_device::fill_16_opx, &tms340x0_device::fill_16_opx_trans, + &tms340x0_device::fill_16_opx, &tms340x0_device::fill_16_opx_trans, &tms340x0_device::fill_16_opx, &tms340x0_device::fill_16_opx_trans, + &tms340x0_device::fill_16_opx, &tms340x0_device::fill_16_opx_trans, &tms340x0_device::fill_16_opx, &tms340x0_device::fill_16_opx_trans, + &tms340x0_device::fill_16_opx, &tms340x0_device::fill_16_opx_trans, &tms340x0_device::fill_16_opx, &tms340x0_device::fill_16_opx_trans, + &tms340x0_device::fill_16_opx, &tms340x0_device::fill_16_opx_trans, &tms340x0_device::fill_16_opx, &tms340x0_device::fill_16_opx_trans, + &tms340x0_device::fill_16_opx, &tms340x0_device::fill_16_opx_trans, &tms340x0_device::fill_16_opx, &tms340x0_device::fill_16_opx_trans, + &tms340x0_device::fill_16_opx, &tms340x0_device::fill_16_opx_trans, &tms340x0_device::fill_16_opx, &tms340x0_device::fill_16_opx_trans, + &tms340x0_device::fill_16_opx, &tms340x0_device::fill_16_opx_trans, &tms340x0_device::fill_16_opx, &tms340x0_device::fill_16_opx_trans, + &tms340x0_device::fill_16_opx, &tms340x0_device::fill_16_opx_trans, &tms340x0_device::fill_16_opx, &tms340x0_device::fill_16_opx_trans, + &tms340x0_device::fill_16_opx, &tms340x0_device::fill_16_opx_trans, &tms340x0_device::fill_16_opx, &tms340x0_device::fill_16_opx_trans, + &tms340x0_device::fill_16_opx, &tms340x0_device::fill_16_opx_trans, &tms340x0_device::fill_16_opx, &tms340x0_device::fill_16_opx_trans, + &tms340x0_device::fill_16_opx, &tms340x0_device::fill_16_opx_trans, &tms340x0_device::fill_16_opx, &tms340x0_device::fill_16_opx_trans, + &tms340x0_device::fill_16_opx, &tms340x0_device::fill_16_opx_trans, &tms340x0_device::fill_16_opx, &tms340x0_device::fill_16_opx_trans +}; + + +#define RECURSIVE_INCLUDE + +/* non-transparent replace ops */ +#define PIXEL_OP(src, mask, pixel) pixel = pixel +#define PIXEL_OP_TIMING 2 +#define PIXEL_OP_REQUIRES_SOURCE 0 +#define TRANSPARENCY 0 + + /* 1bpp cases */ + #define BITS_PER_PIXEL 1 + #define FUNCTION_NAME(base) base##_1_op0 + #include "34010gfx.c" + #undef FUNCTION_NAME + #undef BITS_PER_PIXEL + + /* 2bpp cases */ + #define BITS_PER_PIXEL 2 + #define FUNCTION_NAME(base) base##_2_op0 + #include "34010gfx.c" + #undef FUNCTION_NAME + #undef BITS_PER_PIXEL + + /* 4bpp cases */ + #define BITS_PER_PIXEL 4 + #define FUNCTION_NAME(base) base##_4_op0 + #include "34010gfx.c" + #undef FUNCTION_NAME + #undef BITS_PER_PIXEL + + /* 8bpp cases */ + #define BITS_PER_PIXEL 8 + #define FUNCTION_NAME(base) base##_8_op0 + #include "34010gfx.c" + #undef FUNCTION_NAME + #undef BITS_PER_PIXEL + + /* 16bpp cases */ + #define BITS_PER_PIXEL 16 + #define FUNCTION_NAME(base) base##_16_op0 + #include "34010gfx.c" + #undef FUNCTION_NAME + #undef BITS_PER_PIXEL + +#undef TRANSPARENCY +#undef PIXEL_OP_REQUIRES_SOURCE +#undef PIXEL_OP_TIMING +#undef PIXEL_OP + + +#define PIXEL_OP(src, mask, pixel) pixel = (this->*m_pixel_op)(src, mask, pixel) +#define PIXEL_OP_TIMING m_pixel_op_timing +#define PIXEL_OP_REQUIRES_SOURCE 1 +#define TRANSPARENCY 0 + + /* 1bpp cases */ + #define BITS_PER_PIXEL 1 + #define FUNCTION_NAME(base) base##_1_opx + #include "34010gfx.c" + #undef FUNCTION_NAME + #undef BITS_PER_PIXEL + + /* 2bpp cases */ + #define BITS_PER_PIXEL 2 + #define FUNCTION_NAME(base) base##_2_opx + #include "34010gfx.c" + #undef FUNCTION_NAME + #undef BITS_PER_PIXEL + + /* 4bpp cases */ + #define BITS_PER_PIXEL 4 + #define FUNCTION_NAME(base) base##_4_opx + #include "34010gfx.c" + #undef FUNCTION_NAME + #undef BITS_PER_PIXEL + + /* 8bpp cases */ + #define BITS_PER_PIXEL 8 + #define FUNCTION_NAME(base) base##_8_opx + #include "34010gfx.c" + #undef FUNCTION_NAME + #undef BITS_PER_PIXEL + + /* 16bpp cases */ + #define BITS_PER_PIXEL 16 + #define FUNCTION_NAME(base) base##_16_opx + #include "34010gfx.c" + #undef FUNCTION_NAME + #undef BITS_PER_PIXEL + +#undef TRANSPARENCY +#undef PIXEL_OP_REQUIRES_SOURCE +#undef PIXEL_OP_TIMING +#undef PIXEL_OP + + +/* transparent replace ops */ +#define PIXEL_OP(src, mask, pixel) pixel = pixel +#define PIXEL_OP_REQUIRES_SOURCE 0 +#define PIXEL_OP_TIMING 4 +#define TRANSPARENCY 1 + + /* 1bpp cases */ + #define BITS_PER_PIXEL 1 + #define FUNCTION_NAME(base) base##_1_op0_trans + #include "34010gfx.c" + #undef FUNCTION_NAME + #undef BITS_PER_PIXEL + + /* 2bpp cases */ + #define BITS_PER_PIXEL 2 + #define FUNCTION_NAME(base) base##_2_op0_trans + #include "34010gfx.c" + #undef FUNCTION_NAME + #undef BITS_PER_PIXEL + + /* 4bpp cases */ + #define BITS_PER_PIXEL 4 + #define FUNCTION_NAME(base) base##_4_op0_trans + #include "34010gfx.c" + #undef FUNCTION_NAME + #undef BITS_PER_PIXEL + + /* 8bpp cases */ + #define BITS_PER_PIXEL 8 + #define FUNCTION_NAME(base) base##_8_op0_trans + #include "34010gfx.c" + #undef FUNCTION_NAME + #undef BITS_PER_PIXEL + + /* 16bpp cases */ + #define BITS_PER_PIXEL 16 + #define FUNCTION_NAME(base) base##_16_op0_trans + #include "34010gfx.c" + #undef FUNCTION_NAME + #undef BITS_PER_PIXEL + +#undef TRANSPARENCY +#undef PIXEL_OP_REQUIRES_SOURCE +#undef PIXEL_OP_TIMING +#undef PIXEL_OP + + +#define PIXEL_OP(src, mask, pixel) pixel = (this->*m_pixel_op)(src, mask, pixel) +#define PIXEL_OP_REQUIRES_SOURCE 1 +#define PIXEL_OP_TIMING (2+m_pixel_op_timing) +#define TRANSPARENCY 1 + + /* 1bpp cases */ + #define BITS_PER_PIXEL 1 + #define FUNCTION_NAME(base) base##_1_opx_trans + #include "34010gfx.c" + #undef FUNCTION_NAME + #undef BITS_PER_PIXEL + + /* 2bpp cases */ + #define BITS_PER_PIXEL 2 + #define FUNCTION_NAME(base) base##_2_opx_trans + #include "34010gfx.c" + #undef FUNCTION_NAME + #undef BITS_PER_PIXEL + + /* 4bpp cases */ + #define BITS_PER_PIXEL 4 + #define FUNCTION_NAME(base) base##_4_opx_trans + #include "34010gfx.c" + #undef FUNCTION_NAME + #undef BITS_PER_PIXEL + + /* 8bpp cases */ + #define BITS_PER_PIXEL 8 + #define FUNCTION_NAME(base) base##_8_opx_trans + #include "34010gfx.c" + #undef FUNCTION_NAME + #undef BITS_PER_PIXEL + + /* 16bpp cases */ + #define BITS_PER_PIXEL 16 + #define FUNCTION_NAME(base) base##_16_opx_trans + #include "34010gfx.c" + #undef FUNCTION_NAME + #undef BITS_PER_PIXEL + +#undef TRANSPARENCY +#undef PIXEL_OP_REQUIRES_SOURCE +#undef PIXEL_OP_TIMING +#undef PIXEL_OP + +static const UINT8 pixelsize_lookup[32] = +{ + 0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4 +}; + + +void tms340x0_device::pixblt_b_l(UINT16 op) +{ + int psize = pixelsize_lookup[IOREG(REG_PSIZE) & 0x1f]; + int trans = (IOREG(REG_CONTROL) & 0x20) >> 5; + int rop = (IOREG(REG_CONTROL) >> 10) & 0x1f; + int ix = trans | (rop << 1) | (psize << 6); + if (!P_FLAG()) LOGGFX(("%08X(%3d):PIXBLT B,L (%dx%d) depth=%d\n", m_pc, m_screen->vpos(), DYDX_X(), DYDX_Y(), IOREG(REG_PSIZE) ? IOREG(REG_PSIZE) : 32)); + m_pixel_op = s_pixel_op_table[rop]; + m_pixel_op_timing = s_pixel_op_timing_table[rop]; + (this->*s_pixblt_b_op_table[ix])(1); +} + +void tms340x0_device::pixblt_b_xy(UINT16 op) +{ + int psize = pixelsize_lookup[IOREG(REG_PSIZE) & 0x1f]; + int trans = (IOREG(REG_CONTROL) & 0x20) >> 5; + int rop = (IOREG(REG_CONTROL) >> 10) & 0x1f; + int ix = trans | (rop << 1) | (psize << 6); + if (!P_FLAG()) LOGGFX(("%08X(%3d):PIXBLT B,XY (%d,%d) (%dx%d) depth=%d\n", m_pc, m_screen->vpos(), DADDR_X(), DADDR_Y(), DYDX_X(), DYDX_Y(), IOREG(REG_PSIZE) ? IOREG(REG_PSIZE) : 32)); + m_pixel_op = s_pixel_op_table[rop]; + m_pixel_op_timing = s_pixel_op_timing_table[rop]; + (this->*s_pixblt_b_op_table[ix])(0); +} + +void tms340x0_device::pixblt_l_l(UINT16 op) +{ + int psize = pixelsize_lookup[IOREG(REG_PSIZE) & 0x1f]; + int trans = (IOREG(REG_CONTROL) & 0x20) >> 5; + int rop = (IOREG(REG_CONTROL) >> 10) & 0x1f; + int pbh = (IOREG(REG_CONTROL) >> 8) & 1; + int ix = trans | (rop << 1) | (psize << 6); + if (!P_FLAG()) LOGGFX(("%08X(%3d):PIXBLT L,L (%dx%d) depth=%d\n", m_pc, m_screen->vpos(), DYDX_X(), DYDX_Y(), IOREG(REG_PSIZE) ? IOREG(REG_PSIZE) : 32)); + m_pixel_op = s_pixel_op_table[rop]; + m_pixel_op_timing = s_pixel_op_timing_table[rop]; + if (!pbh) + (this->*s_pixblt_op_table[ix])(1, 1); + else + (this->*s_pixblt_r_op_table[ix])(1, 1); +} + +void tms340x0_device::pixblt_l_xy(UINT16 op) +{ + int psize = pixelsize_lookup[IOREG(REG_PSIZE) & 0x1f]; + int trans = (IOREG(REG_CONTROL) & 0x20) >> 5; + int rop = (IOREG(REG_CONTROL) >> 10) & 0x1f; + int pbh = (IOREG(REG_CONTROL) >> 8) & 1; + int ix = trans | (rop << 1) | (psize << 6); + if (!P_FLAG()) LOGGFX(("%08X(%3d):PIXBLT L,XY (%d,%d) (%dx%d) depth=%d\n", m_pc, m_screen->vpos(), DADDR_X(), DADDR_Y(), DYDX_X(), DYDX_Y(), IOREG(REG_PSIZE) ? IOREG(REG_PSIZE) : 32)); + m_pixel_op = s_pixel_op_table[rop]; + m_pixel_op_timing = s_pixel_op_timing_table[rop]; + if (!pbh) + (this->*s_pixblt_op_table[ix])(1, 0); + else + (this->*s_pixblt_r_op_table[ix])(1, 0); +} + +void tms340x0_device::pixblt_xy_l(UINT16 op) +{ + int psize = pixelsize_lookup[IOREG(REG_PSIZE) & 0x1f]; + int trans = (IOREG(REG_CONTROL) & 0x20) >> 5; + int rop = (IOREG(REG_CONTROL) >> 10) & 0x1f; + int pbh = (IOREG(REG_CONTROL) >> 8) & 1; + int ix = trans | (rop << 1) | (psize << 6); + if (!P_FLAG()) LOGGFX(("%08X(%3d):PIXBLT XY,L (%dx%d) depth=%d\n", m_pc, m_screen->vpos(), DYDX_X(), DYDX_Y(), IOREG(REG_PSIZE) ? IOREG(REG_PSIZE) : 32)); + m_pixel_op = s_pixel_op_table[rop]; + m_pixel_op_timing = s_pixel_op_timing_table[rop]; + if (!pbh) + (this->*s_pixblt_op_table[ix])(0, 1); + else + (this->*s_pixblt_r_op_table[ix])(0, 1); +} + +void tms340x0_device::pixblt_xy_xy(UINT16 op) +{ + int psize = pixelsize_lookup[IOREG(REG_PSIZE) & 0x1f]; + int trans = (IOREG(REG_CONTROL) & 0x20) >> 5; + int rop = (IOREG(REG_CONTROL) >> 10) & 0x1f; + int pbh = (IOREG(REG_CONTROL) >> 8) & 1; + int ix = trans | (rop << 1) | (psize << 6); + if (!P_FLAG()) LOGGFX(("%08X(%3d):PIXBLT XY,XY (%dx%d) depth=%d\n", m_pc, m_screen->vpos(), DYDX_X(), DYDX_Y(), IOREG(REG_PSIZE) ? IOREG(REG_PSIZE) : 32)); + m_pixel_op = s_pixel_op_table[rop]; + m_pixel_op_timing = s_pixel_op_timing_table[rop]; + if (!pbh) + (this->*s_pixblt_op_table[ix])(0, 0); + else + (this->*s_pixblt_r_op_table[ix])(0, 0); +} + +void tms340x0_device::fill_l(UINT16 op) +{ + int psize = pixelsize_lookup[IOREG(REG_PSIZE) & 0x1f]; + int trans = (IOREG(REG_CONTROL) & 0x20) >> 5; + int rop = (IOREG(REG_CONTROL) >> 10) & 0x1f; + int ix = trans | (rop << 1) | (psize << 6); + if (!P_FLAG()) LOGGFX(("%08X(%3d):FILL L (%dx%d) depth=%d\n", m_pc, m_screen->vpos(), DYDX_X(), DYDX_Y(), IOREG(REG_PSIZE) ? IOREG(REG_PSIZE) : 32)); + m_pixel_op = s_pixel_op_table[rop]; + m_pixel_op_timing = s_pixel_op_timing_table[rop]; + (this->*s_fill_op_table[ix])(1); +} + +void tms340x0_device::fill_xy(UINT16 op) +{ + int psize = pixelsize_lookup[IOREG(REG_PSIZE) & 0x1f]; + int trans = (IOREG(REG_CONTROL) & 0x20) >> 5; + int rop = (IOREG(REG_CONTROL) >> 10) & 0x1f; + int ix = trans | (rop << 1) | (psize << 6); + if (!P_FLAG()) LOGGFX(("%08X(%3d):FILL XY (%d,%d) (%dx%d) depth=%d\n", m_pc, m_screen->vpos(), DADDR_X(), DADDR_Y(), DYDX_X(), DYDX_Y(), IOREG(REG_PSIZE) ? IOREG(REG_PSIZE) : 32)); + m_pixel_op = s_pixel_op_table[rop]; + m_pixel_op_timing = s_pixel_op_timing_table[rop]; + (this->*s_fill_op_table[ix])(0); +} + + +#else + + +#undef PIXELS_PER_WORD +#undef PIXEL_MASK + +#define PIXELS_PER_WORD (16 / BITS_PER_PIXEL) +#define PIXEL_MASK ((1 << BITS_PER_PIXEL) - 1) + +void FUNCTION_NAME(tms340x0_device::pixblt)(int src_is_linear, int dst_is_linear) +{ + /* if this is the first time through, perform the operation */ + if (!P_FLAG()) + { + int dx, dy, x, y, /*words,*/ yreverse; + word_write_func word_write; + word_read_func word_read; + UINT32 readwrites = 0; + UINT32 saddr, daddr; + XY dstxy = { 0 }; + + /* determine read/write functions */ + if (IOREG(REG_DPYCTL) & 0x0800) + { + word_write = &tms340x0_device::shiftreg_w; + word_read = &tms340x0_device::shiftreg_r; + } + else + { + word_write = &tms340x0_device::memory_w; + word_read = &tms340x0_device::memory_r; + } + + /* compute the starting addresses */ + saddr = src_is_linear ? SADDR() : SXYTOL(SADDR_XY()); + + /* compute the bounds of the operation */ + dx = (INT16)DYDX_X(); + dy = (INT16)DYDX_Y(); + + /* apply the window for non-linear destinations */ + m_gfxcycles = 7 + (src_is_linear ? 0 : 2); + if (!dst_is_linear) + { + dstxy = DADDR_XY(); + m_gfxcycles += 2 + (!src_is_linear) + apply_window("PIXBLT", BITS_PER_PIXEL, &saddr, &dstxy, &dx, &dy); + daddr = DXYTOL(dstxy); + } + else + daddr = DADDR(); + daddr &= ~(BITS_PER_PIXEL - 1); + LOGGFX((" saddr=%08X daddr=%08X sptch=%08X dptch=%08X\n", saddr, daddr, SPTCH(), DPTCH())); + + /* bail if we're clipped */ + if (dx <= 0 || dy <= 0) + return; + + /* window mode 1: just return and interrupt if we are within the window */ + if (WINDOW_CHECKING() == 1 && !dst_is_linear) + { + CLR_V(); + DADDR_XY() = dstxy; + DYDX_X() = dx; + DYDX_Y() = dy; + IOREG(REG_INTPEND) |= TMS34010_WV; + check_interrupt(); + return; + } + + /* handle flipping the addresses */ + yreverse = (IOREG(REG_CONTROL) >> 9) & 1; + if (!src_is_linear || !dst_is_linear) + { + if (yreverse) + { + saddr += (dy - 1) * m_convsp; + daddr += (dy - 1) * m_convdp; + } + } + + m_st |= STBIT_P; + + /* loop over rows */ + for (y = 0; y < dy; y++) + { + UINT32 srcwordaddr = saddr >> 4; + UINT32 dstwordaddr = daddr >> 4; + UINT8 srcbit = saddr & 15; + UINT8 dstbit = daddr & 15; + UINT32 srcword, dstword = 0; + + /* fetch the initial source word */ + srcword = (this->*word_read)(*m_program, srcwordaddr++ << 1); + readwrites++; + + /* fetch the initial dest word */ + if (PIXEL_OP_REQUIRES_SOURCE || TRANSPARENCY || (daddr & 0x0f) != 0) + { + dstword = (this->*word_read)(*m_program, dstwordaddr << 1); + readwrites++; + } + + /* loop over pixels */ + for (x = 0; x < dx; x++) + { + UINT32 dstmask; + UINT32 pixel; + + /* fetch more words if necessary */ + if (srcbit + BITS_PER_PIXEL > 16) + { + srcword |= (this->*word_read)(*m_program, srcwordaddr++ << 1) << 16; + readwrites++; + } + + /* extract pixel from source */ + pixel = (srcword >> srcbit) & PIXEL_MASK; + srcbit += BITS_PER_PIXEL; + if (srcbit > 16) + { + srcbit -= 16; + srcword >>= 16; + } + + /* fetch additional destination word if necessary */ + if (PIXEL_OP_REQUIRES_SOURCE || TRANSPARENCY) + if (dstbit + BITS_PER_PIXEL > 16) + { + dstword |= (this->*word_read)(*m_program, (dstwordaddr + 1) << 1) << 16; + readwrites++; + } + + /* apply pixel operations */ + pixel <<= dstbit; + dstmask = PIXEL_MASK << dstbit; + PIXEL_OP(dstword, dstmask, pixel); + if (!TRANSPARENCY || pixel != 0) + dstword = (dstword & ~dstmask) | pixel; + + /* flush destination words */ + dstbit += BITS_PER_PIXEL; + if (dstbit > 16) + { + (this->*word_write)(*m_program, dstwordaddr++ << 1, dstword); + readwrites++; + dstbit -= 16; + dstword >>= 16; + } + } + + /* flush any remaining words */ + if (dstbit > 0) + { + /* if we're right-partial, read and mask the remaining bits */ + if (dstbit != 16) + { + UINT16 origdst = (this->*word_read)(*m_program, dstwordaddr << 1); + UINT16 mask = 0xffff << dstbit; + dstword = (dstword & ~mask) | (origdst & mask); + readwrites++; + } + + (this->*word_write)(*m_program, dstwordaddr++ << 1, dstword); + readwrites++; + } + + + +#if 0 + int left_partials, right_partials, full_words, bitshift, bitshift_alt; + UINT16 srcword, srcmask, dstword, dstmask, pixel; + UINT32 swordaddr, dwordaddr; + + /* determine the bit shift to get from source to dest */ + bitshift = ((daddr & 15) - (saddr & 15)) & 15; + bitshift_alt = (16 - bitshift) & 15; + + /* how many left and right partial pixels do we have? */ + left_partials = (PIXELS_PER_WORD - ((daddr & 15) / BITS_PER_PIXEL)) & (PIXELS_PER_WORD - 1); + right_partials = ((daddr + dx * BITS_PER_PIXEL) & 15) / BITS_PER_PIXEL; + full_words = dx - left_partials - right_partials; + if (full_words < 0) + left_partials = dx, right_partials = full_words = 0; + else + full_words /= PIXELS_PER_WORD; + + /* compute cycles */ + m_gfxcycles += compute_pixblt_cycles(left_partials, right_partials, full_words, PIXEL_OP_TIMING); + + /* use word addresses each row */ + swordaddr = saddr >> 4; + dwordaddr = daddr >> 4; + + /* fetch the initial source word */ + srcword = (this->*word_read)(*m_program, swordaddr++ << 1); + srcmask = PIXEL_MASK << (saddr & 15); + + /* handle the left partial word */ + if (left_partials != 0) + { + /* fetch the destination word */ + dstword = (this->*word_read)(*m_program, dwordaddr << 1); + dstmask = PIXEL_MASK << (daddr & 15); + + /* loop over partials */ + for (x = 0; x < left_partials; x++) + { + /* fetch another word if necessary */ + if (srcmask == 0) + { + srcword = (this->*word_read)(*m_program, swordaddr++ << 1); + srcmask = PIXEL_MASK; + } + + /* process the pixel */ + pixel = srcword & srcmask; + if (dstmask > srcmask) + pixel <<= bitshift; + else + pixel >>= bitshift_alt; + PIXEL_OP(dstword, dstmask, pixel); + if (!TRANSPARENCY || pixel != 0) + dstword = (dstword & ~dstmask) | pixel; + + /* update the source */ + srcmask <<= BITS_PER_PIXEL; + + /* update the destination */ + dstmask <<= BITS_PER_PIXEL; + } + + /* write the result */ + (this->*word_write)(*m_program, dwordaddr++ << 1, dstword); + } + + /* loop over full words */ + for (words = 0; words < full_words; words++) + { + /* fetch the destination word (if necessary) */ + if (PIXEL_OP_REQUIRES_SOURCE || TRANSPARENCY) + dstword = (this->*word_read)(*m_program, dwordaddr << 1); + else + dstword = 0; + dstmask = PIXEL_MASK; + + /* loop over partials */ + for (x = 0; x < PIXELS_PER_WORD; x++) + { + /* fetch another word if necessary */ + if (srcmask == 0) + { + srcword = (this->*word_read)(*m_program, swordaddr++ << 1); + srcmask = PIXEL_MASK; + } + + /* process the pixel */ + pixel = srcword & srcmask; + if (dstmask > srcmask) + pixel <<= bitshift; + else + pixel >>= bitshift_alt; + PIXEL_OP(dstword, dstmask, pixel); + if (!TRANSPARENCY || pixel != 0) + dstword = (dstword & ~dstmask) | pixel; + + /* update the source */ + srcmask <<= BITS_PER_PIXEL; + + /* update the destination */ + dstmask <<= BITS_PER_PIXEL; + } + + /* write the result */ + (this->*word_write)(*m_program, dwordaddr++ << 1, dstword); + } + + /* handle the right partial word */ + if (right_partials != 0) + { + /* fetch the destination word */ + dstword = (this->*word_read)(*m_program, dwordaddr << 1); + dstmask = PIXEL_MASK; + + /* loop over partials */ + for (x = 0; x < right_partials; x++) + { + /* fetch another word if necessary */ + if (srcmask == 0) + { + LOGGFX((" right fetch @ %08x\n", swordaddr)); + srcword = (this->*word_read)(*m_program, swordaddr++ << 1); + srcmask = PIXEL_MASK; + } + + /* process the pixel */ + pixel = srcword & srcmask; + if (dstmask > srcmask) + pixel <<= bitshift; + else + pixel >>= bitshift_alt; + PIXEL_OP(dstword, dstmask, pixel); + if (!TRANSPARENCY || pixel != 0) + dstword = (dstword & ~dstmask) | pixel; + + /* update the source */ + srcmask <<= BITS_PER_PIXEL; + + /* update the destination */ + dstmask <<= BITS_PER_PIXEL; + } + + /* write the result */ + (this->*word_write)(*m_program, dwordaddr++ << 1, dstword); + } +#endif + + /* update for next row */ + if (!yreverse) + { + saddr += SPTCH(); + daddr += DPTCH(); + } + else + { + saddr -= SPTCH(); + daddr -= DPTCH(); + } + } + + m_gfxcycles += readwrites * 2 + dx * dy * (PIXEL_OP_TIMING - 2); + + LOGGFX((" (%d cycles)\n", m_gfxcycles)); + } + + /* eat cycles */ + if (m_gfxcycles > m_icount) + { + m_gfxcycles -= m_icount; + m_icount = 0; + m_pc -= 0x10; + } + else + { + m_icount -= m_gfxcycles; + m_st &= ~STBIT_P; + if (src_is_linear && dst_is_linear) + SADDR() += DYDX_Y() * SPTCH(); + else if (src_is_linear) + SADDR() += DYDX_Y() * SPTCH(); + else + SADDR_Y() += DYDX_Y(); + if (dst_is_linear) + DADDR() += DYDX_Y() * DPTCH(); + else + DADDR_Y() += DYDX_Y(); + } +} + +void FUNCTION_NAME(tms340x0_device::pixblt_r)(int src_is_linear, int dst_is_linear) +{ + /* if this is the first time through, perform the operation */ + if (!P_FLAG()) + { + int dx, dy, x, y, words, yreverse; + word_write_func word_write; + word_read_func word_read; + UINT32 saddr, daddr; + XY dstxy = { 0 }; + + /* determine read/write functions */ + if (IOREG(REG_DPYCTL) & 0x0800) + { + word_write = &tms340x0_device::shiftreg_w; + word_read = &tms340x0_device::shiftreg_r; + } + else + { + word_write = &tms340x0_device::memory_w; + word_read = &tms340x0_device::memory_r; + } + + /* compute the starting addresses */ + saddr = src_is_linear ? SADDR() : SXYTOL(SADDR_XY()); +if ((saddr & (BITS_PER_PIXEL - 1)) != 0) osd_printf_debug("PIXBLT_R%d with odd saddr\n", BITS_PER_PIXEL); + saddr &= ~(BITS_PER_PIXEL - 1); + + /* compute the bounds of the operation */ + dx = (INT16)DYDX_X(); + dy = (INT16)DYDX_Y(); + + /* apply the window for non-linear destinations */ + m_gfxcycles = 7 + (src_is_linear ? 0 : 2); + if (!dst_is_linear) + { + dstxy = DADDR_XY(); + m_gfxcycles += 2 + (!src_is_linear) + apply_window("PIXBLT R", BITS_PER_PIXEL, &saddr, &dstxy, &dx, &dy); + daddr = DXYTOL(dstxy); + } + else + daddr = DADDR(); +if ((daddr & (BITS_PER_PIXEL - 1)) != 0) osd_printf_debug("PIXBLT_R%d with odd daddr\n", BITS_PER_PIXEL); + daddr &= ~(BITS_PER_PIXEL - 1); + LOGGFX((" saddr=%08X daddr=%08X sptch=%08X dptch=%08X\n", saddr, daddr, SPTCH(), DPTCH())); + + /* bail if we're clipped */ + if (dx <= 0 || dy <= 0) + return; + + /* window mode 1: just return and interrupt if we are within the window */ + if (WINDOW_CHECKING() == 1 && !dst_is_linear) + { + CLR_V(); + DADDR_XY() = dstxy; + DYDX_X() = dx; + DYDX_Y() = dy; + IOREG(REG_INTPEND) |= TMS34010_WV; + check_interrupt(); + return; + } + + /* handle flipping the addresses */ + yreverse = (IOREG(REG_CONTROL) >> 9) & 1; + if (!src_is_linear || !dst_is_linear) + { + saddr += dx * BITS_PER_PIXEL; + daddr += dx * BITS_PER_PIXEL; + if (yreverse) + { + saddr += (dy - 1) * m_convsp; + daddr += (dy - 1) * m_convdp; + } + } + + m_st |= STBIT_P; + + /* loop over rows */ + for (y = 0; y < dy; y++) + { + int left_partials, right_partials, full_words, bitshift, bitshift_alt; + UINT16 srcword, srcmask, dstword, dstmask, pixel; + UINT32 swordaddr, dwordaddr; + + /* determine the bit shift to get from source to dest */ + bitshift = ((daddr & 15) - (saddr & 15)) & 15; + bitshift_alt = (16 - bitshift) & 15; + + /* how many left and right partial pixels do we have? */ + left_partials = (PIXELS_PER_WORD - (((daddr - dx * BITS_PER_PIXEL) & 15) / BITS_PER_PIXEL)) & (PIXELS_PER_WORD - 1); + right_partials = (daddr & 15) / BITS_PER_PIXEL; + full_words = dx - left_partials - right_partials; + if (full_words < 0) + right_partials = dx, left_partials = full_words = 0; + else + full_words /= PIXELS_PER_WORD; + + /* compute cycles */ + m_gfxcycles += compute_pixblt_cycles(left_partials, right_partials, full_words, PIXEL_OP_TIMING); + + /* use word addresses each row */ + swordaddr = (saddr + 15) >> 4; + dwordaddr = (daddr + 15) >> 4; + + /* fetch the initial source word */ + srcword = (this->*word_read)(*m_program, --swordaddr << 1); + srcmask = PIXEL_MASK << ((saddr - BITS_PER_PIXEL) & 15); + + /* handle the right partial word */ + if (right_partials != 0) + { + /* fetch the destination word */ + dstword = (this->*word_read)(*m_program, --dwordaddr << 1); + dstmask = PIXEL_MASK << ((daddr - BITS_PER_PIXEL) & 15); + + /* loop over partials */ + for (x = 0; x < right_partials; x++) + { + /* fetch source pixel if necessary */ + if (srcmask == 0) + { + srcword = (this->*word_read)(*m_program, --swordaddr << 1); + srcmask = PIXEL_MASK << (16 - BITS_PER_PIXEL); + } + + /* process the pixel */ + pixel = srcword & srcmask; + if (dstmask > srcmask) + pixel <<= bitshift; + else + pixel >>= bitshift_alt; + PIXEL_OP(dstword, dstmask, pixel); + if (!TRANSPARENCY || pixel != 0) + dstword = (dstword & ~dstmask) | pixel; + +#if (BITS_PER_PIXEL<16) + /* update the source */ + srcmask >>= BITS_PER_PIXEL; + + /* update the destination */ + dstmask >>= BITS_PER_PIXEL; +#else + srcmask = 0; + dstmask = 0; +#endif + } + + /* write the result */ + (this->*word_write)(*m_program, dwordaddr << 1, dstword); + } + + /* loop over full words */ + for (words = 0; words < full_words; words++) + { + /* fetch the destination word (if necessary) */ + dwordaddr--; + if (PIXEL_OP_REQUIRES_SOURCE || TRANSPARENCY) + dstword = (this->*word_read)(*m_program, dwordaddr << 1); + else + dstword = 0; + dstmask = PIXEL_MASK << (16 - BITS_PER_PIXEL); + + /* loop over partials */ + for (x = 0; x < PIXELS_PER_WORD; x++) + { + /* fetch source pixel if necessary */ + if (srcmask == 0) + { + srcword = (this->*word_read)(*m_program, --swordaddr << 1); + srcmask = PIXEL_MASK << (16 - BITS_PER_PIXEL); + } + + /* process the pixel */ + pixel = srcword & srcmask; + if (dstmask > srcmask) + pixel <<= bitshift; + else + pixel >>= bitshift_alt; + PIXEL_OP(dstword, dstmask, pixel); + if (!TRANSPARENCY || pixel != 0) + dstword = (dstword & ~dstmask) | pixel; + +#if (BITS_PER_PIXEL<16) + /* update the source */ + srcmask >>= BITS_PER_PIXEL; + + /* update the destination */ + dstmask >>= BITS_PER_PIXEL; +#else + srcmask = 0; + dstmask = 0; +#endif + } + + /* write the result */ + (this->*word_write)(*m_program, dwordaddr << 1, dstword); + } + + /* handle the left partial word */ + if (left_partials != 0) + { + /* fetch the destination word */ + dstword = (this->*word_read)(*m_program, --dwordaddr << 1); + dstmask = PIXEL_MASK << (16 - BITS_PER_PIXEL); + + /* loop over partials */ + for (x = 0; x < left_partials; x++) + { + /* fetch the source pixel if necessary */ + if (srcmask == 0) + { + srcword = (this->*word_read)(*m_program, --swordaddr << 1); + srcmask = PIXEL_MASK << (16 - BITS_PER_PIXEL); + } + + /* process the pixel */ + pixel = srcword & srcmask; + if (dstmask > srcmask) + pixel <<= bitshift; + else + pixel >>= bitshift_alt; + PIXEL_OP(dstword, dstmask, pixel); + if (!TRANSPARENCY || pixel != 0) + dstword = (dstword & ~dstmask) | pixel; + +#if (BITS_PER_PIXEL<16) + /* update the source */ + srcmask >>= BITS_PER_PIXEL; + + /* update the destination */ + dstmask >>= BITS_PER_PIXEL; +#else + srcmask = 0; + dstmask = 0; +#endif + } + + /* write the result */ + (this->*word_write)(*m_program, dwordaddr << 1, dstword); + } + + /* update for next row */ + if (!yreverse) + { + saddr += SPTCH(); + daddr += DPTCH(); + } + else + { + saddr -= SPTCH(); + daddr -= DPTCH(); + } + } + LOGGFX((" (%d cycles)\n", m_gfxcycles)); + } + + /* eat cycles */ + if (m_gfxcycles > m_icount) + { + m_gfxcycles -= m_icount; + m_icount = 0; + m_pc -= 0x10; + } + else + { + m_icount -= m_gfxcycles; + m_st &= ~STBIT_P; + if (src_is_linear && dst_is_linear) + SADDR() += DYDX_Y() * SPTCH(); + else if (src_is_linear) + SADDR() += DYDX_Y() * SPTCH(); + else + SADDR_Y() += DYDX_Y(); + if (dst_is_linear) + DADDR() += DYDX_Y() * DPTCH(); + else + DADDR_Y() += DYDX_Y(); + } +} + +void FUNCTION_NAME(tms340x0_device::pixblt_b)(int dst_is_linear) +{ + /* if this is the first time through, perform the operation */ + if (!P_FLAG()) + { + int dx, dy, x, y, words, left_partials, right_partials, full_words; + word_write_func word_write; + word_read_func word_read; + UINT32 saddr, daddr; + XY dstxy = { 0 }; + + /* determine read/write functions */ + if (IOREG(REG_DPYCTL) & 0x0800) + { + word_write = &tms340x0_device::shiftreg_w; + word_read = &tms340x0_device::shiftreg_r; + } + else + { + word_write = &tms340x0_device::memory_w; + word_read = &tms340x0_device::memory_r; + } + + /* compute the starting addresses */ + saddr = SADDR(); + + /* compute the bounds of the operation */ + dx = (INT16)DYDX_X(); + dy = (INT16)DYDX_Y(); + + /* apply the window for non-linear destinations */ + m_gfxcycles = 4; + if (!dst_is_linear) + { + dstxy = DADDR_XY(); + m_gfxcycles += 2 + apply_window("PIXBLT B", 1, &saddr, &dstxy, &dx, &dy); + daddr = DXYTOL(dstxy); + } + else + daddr = DADDR(); + daddr &= ~(BITS_PER_PIXEL - 1); + LOGGFX((" saddr=%08X daddr=%08X sptch=%08X dptch=%08X\n", saddr, daddr, SPTCH(), DPTCH())); + + /* bail if we're clipped */ + if (dx <= 0 || dy <= 0) + return; + + /* window mode 1: just return and interrupt if we are within the window */ + if (WINDOW_CHECKING() == 1 && !dst_is_linear) + { + CLR_V(); + DADDR_XY() = dstxy; + DYDX_X() = dx; + DYDX_Y() = dy; + IOREG(REG_INTPEND) |= TMS34010_WV; + check_interrupt(); + return; + } + + /* how many left and right partial pixels do we have? */ + left_partials = (PIXELS_PER_WORD - ((daddr & 15) / BITS_PER_PIXEL)) & (PIXELS_PER_WORD - 1); + right_partials = ((daddr + dx * BITS_PER_PIXEL) & 15) / BITS_PER_PIXEL; + full_words = dx - left_partials - right_partials; + if (full_words < 0) + left_partials = dx, right_partials = full_words = 0; + else + full_words /= PIXELS_PER_WORD; + + /* compute cycles */ + m_gfxcycles += compute_pixblt_b_cycles(left_partials, right_partials, full_words, dy, PIXEL_OP_TIMING, BITS_PER_PIXEL); + m_st |= STBIT_P; + + /* loop over rows */ + for (y = 0; y < dy; y++) + { + UINT16 srcword, srcmask, dstword, dstmask, pixel; + UINT32 swordaddr, dwordaddr; + + /* use byte addresses each row */ + swordaddr = saddr >> 4; + dwordaddr = daddr >> 4; + + /* fetch the initial source word */ + srcword = (this->*word_read)(*m_program, swordaddr++ << 1); + srcmask = 1 << (saddr & 15); + + /* handle the left partial word */ + if (left_partials != 0) + { + /* fetch the destination word */ + dstword = (this->*word_read)(*m_program, dwordaddr << 1); + dstmask = PIXEL_MASK << (daddr & 15); + + /* loop over partials */ + for (x = 0; x < left_partials; x++) + { + /* process the pixel */ + pixel = (srcword & srcmask) ? COLOR1() : COLOR0(); + pixel &= dstmask; + PIXEL_OP(dstword, dstmask, pixel); + if (!TRANSPARENCY || pixel != 0) + dstword = (dstword & ~dstmask) | pixel; + + /* update the source */ + srcmask <<= 1; + if (srcmask == 0) + { + srcword = (this->*word_read)(*m_program, swordaddr++ << 1); + srcmask = 0x0001; + } + + /* update the destination */ + dstmask = dstmask << BITS_PER_PIXEL; + } + + /* write the result */ + (this->*word_write)(*m_program, dwordaddr++ << 1, dstword); + } + + /* loop over full words */ + for (words = 0; words < full_words; words++) + { + /* fetch the destination word (if necessary) */ + if (PIXEL_OP_REQUIRES_SOURCE || TRANSPARENCY) + dstword = (this->*word_read)(*m_program, dwordaddr << 1); + else + dstword = 0; + dstmask = PIXEL_MASK; + + /* loop over partials */ + for (x = 0; x < PIXELS_PER_WORD; x++) + { + /* process the pixel */ + pixel = (srcword & srcmask) ? COLOR1() : COLOR0(); + pixel &= dstmask; + PIXEL_OP(dstword, dstmask, pixel); + if (!TRANSPARENCY || pixel != 0) + dstword = (dstword & ~dstmask) | pixel; + + /* update the source */ + srcmask <<= 1; + if (srcmask == 0) + { + srcword = (this->*word_read)(*m_program, swordaddr++ << 1); + srcmask = 0x0001; + } + + /* update the destination */ + dstmask = dstmask << BITS_PER_PIXEL; + } + + /* write the result */ + (this->*word_write)(*m_program, dwordaddr++ << 1, dstword); + } + + /* handle the right partial word */ + if (right_partials != 0) + { + /* fetch the destination word */ + dstword = (this->*word_read)(*m_program, dwordaddr << 1); + dstmask = PIXEL_MASK; + + /* loop over partials */ + for (x = 0; x < right_partials; x++) + { + /* process the pixel */ + pixel = (srcword & srcmask) ? COLOR1() : COLOR0(); + pixel &= dstmask; + PIXEL_OP(dstword, dstmask, pixel); + if (!TRANSPARENCY || pixel != 0) + dstword = (dstword & ~dstmask) | pixel; + + /* update the source */ + srcmask <<= 1; + if (srcmask == 0) + { + srcword = (this->*word_read)(*m_program, swordaddr++ << 1); + srcmask = 0x0001; + } + + /* update the destination */ + dstmask = dstmask << BITS_PER_PIXEL; + } + + /* write the result */ + (this->*word_write)(*m_program, dwordaddr++ << 1, dstword); + } + + /* update for next row */ + saddr += SPTCH(); + daddr += DPTCH(); + } + LOGGFX((" (%d cycles)\n", m_gfxcycles)); + } + + /* eat cycles */ + if (m_gfxcycles > m_icount) + { + m_gfxcycles -= m_icount; + m_icount = 0; + m_pc -= 0x10; + } + else + { + m_icount -= m_gfxcycles; + m_st &= ~STBIT_P; + SADDR() += DYDX_Y() * SPTCH(); + if (dst_is_linear) + DADDR() += DYDX_Y() * DPTCH(); + else + DADDR_Y() += DYDX_Y(); + } +} + +void FUNCTION_NAME(tms340x0_device::fill)(int dst_is_linear) +{ + /* if this is the first time through, perform the operation */ + if (!P_FLAG()) + { + int dx, dy, x, y, words, left_partials, right_partials, full_words; + word_write_func word_write; + word_read_func word_read; + UINT32 daddr; + XY dstxy = { 0 }; + + /* determine read/write functions */ + if (IOREG(REG_DPYCTL) & 0x0800) + { + word_write = &tms340x0_device::shiftreg_w; + word_read = &tms340x0_device::dummy_shiftreg_r; + } + else + { + word_write = &tms340x0_device::memory_w; + word_read = &tms340x0_device::memory_r; + } + + /* compute the bounds of the operation */ + dx = (INT16)DYDX_X(); + dy = (INT16)DYDX_Y(); + + /* apply the window for non-linear destinations */ + m_gfxcycles = 4; + if (!dst_is_linear) + { + dstxy = DADDR_XY(); + m_gfxcycles += 2 + apply_window("FILL", 0, NULL, &dstxy, &dx, &dy); + daddr = DXYTOL(dstxy); + } + else + daddr = DADDR(); + daddr &= ~(BITS_PER_PIXEL - 1); + LOGGFX((" daddr=%08X\n", daddr)); + + /* bail if we're clipped */ + if (dx <= 0 || dy <= 0) + return; + + /* window mode 1: just return and interrupt if we are within the window */ + if (WINDOW_CHECKING() == 1 && !dst_is_linear) + { + CLR_V(); + DADDR_XY() = dstxy; + DYDX_X() = dx; + DYDX_Y() = dy; + IOREG(REG_INTPEND) |= TMS34010_WV; + check_interrupt(); + return; + } + + /* how many left and right partial pixels do we have? */ + left_partials = (PIXELS_PER_WORD - ((daddr & 15) / BITS_PER_PIXEL)) & (PIXELS_PER_WORD - 1); + right_partials = ((daddr + dx * BITS_PER_PIXEL) & 15) / BITS_PER_PIXEL; + full_words = dx - left_partials - right_partials; + if (full_words < 0) + left_partials = dx, right_partials = full_words = 0; + else + full_words /= PIXELS_PER_WORD; + + /* compute cycles */ + m_gfxcycles += 2; + m_st |= STBIT_P; + + /* loop over rows */ + for (y = 0; y < dy; y++) + { + UINT16 dstword, dstmask, pixel; + UINT32 dwordaddr; + + /* use byte addresses each row */ + dwordaddr = daddr >> 4; + + /* compute cycles */ + m_gfxcycles += compute_fill_cycles(left_partials, right_partials, full_words, PIXEL_OP_TIMING); + + /* handle the left partial word */ + if (left_partials != 0) + { + /* fetch the destination word */ + dstword = (this->*word_read)(*m_program, dwordaddr << 1); + dstmask = PIXEL_MASK << (daddr & 15); + + /* loop over partials */ + for (x = 0; x < left_partials; x++) + { + /* process the pixel */ + pixel = COLOR1() & dstmask; + PIXEL_OP(dstword, dstmask, pixel); + if (!TRANSPARENCY || pixel != 0) + dstword = (dstword & ~dstmask) | pixel; + + /* update the destination */ + dstmask = dstmask << BITS_PER_PIXEL; + } + + /* write the result */ + (this->*word_write)(*m_program, dwordaddr++ << 1, dstword); + } + + /* loop over full words */ + for (words = 0; words < full_words; words++) + { + /* fetch the destination word (if necessary) */ + if (PIXEL_OP_REQUIRES_SOURCE || TRANSPARENCY) + dstword = (this->*word_read)(*m_program, dwordaddr << 1); + else + dstword = 0; + dstmask = PIXEL_MASK; + + /* loop over partials */ + for (x = 0; x < PIXELS_PER_WORD; x++) + { + /* process the pixel */ + pixel = COLOR1() & dstmask; + PIXEL_OP(dstword, dstmask, pixel); + if (!TRANSPARENCY || pixel != 0) + dstword = (dstword & ~dstmask) | pixel; + + /* update the destination */ + dstmask = dstmask << BITS_PER_PIXEL; + } + + /* write the result */ + (this->*word_write)(*m_program, dwordaddr++ << 1, dstword); + } + + /* handle the right partial word */ + if (right_partials != 0) + { + /* fetch the destination word */ + dstword = (this->*word_read)(*m_program, dwordaddr << 1); + dstmask = PIXEL_MASK; + + /* loop over partials */ + for (x = 0; x < right_partials; x++) + { + /* process the pixel */ + pixel = COLOR1() & dstmask; + PIXEL_OP(dstword, dstmask, pixel); + if (!TRANSPARENCY || pixel != 0) + dstword = (dstword & ~dstmask) | pixel; + + /* update the destination */ + dstmask = dstmask << BITS_PER_PIXEL; + } + + /* write the result */ + (this->*word_write)(*m_program, dwordaddr++ << 1, dstword); + } + + /* update for next row */ + daddr += DPTCH(); + } + + LOGGFX((" (%d cycles)\n", m_gfxcycles)); + } + + /* eat cycles */ + if (m_gfxcycles > m_icount) + { + m_gfxcycles -= m_icount; + m_icount = 0; + m_pc -= 0x10; + } + else + { + m_icount -= m_gfxcycles; + m_st &= ~STBIT_P; + if (dst_is_linear) + DADDR() += DYDX_Y() * DPTCH(); + else + DADDR_Y() += DYDX_Y(); + } +} + +#endif diff --git a/src/devices/cpu/tms34010/34010ops.c b/src/devices/cpu/tms34010/34010ops.c new file mode 100644 index 00000000000..6674d7a1faa --- /dev/null +++ b/src/devices/cpu/tms34010/34010ops.c @@ -0,0 +1,2460 @@ +// license:BSD-3-Clause +// copyright-holders:Alex Pasadyn,Zsolt Vasvari +/*************************************************************************** + + TMS34010: Portable Texas Instruments TMS34010 emulator + + Copyright Alex Pasadyn/Zsolt Vasvari + Parts based on code by Aaron Giles + +***************************************************************************/ + + + +/*************************************************************************** + MISC MACROS +***************************************************************************/ + +#define ZEXTEND(val,width) if (width) (val) &= ((UINT32)0xffffffff >> (32 - (width))) +#define SEXTEND(val,width) if (width) (val) = (INT32)((val) << (32 - (width))) >> (32 - (width)) + +#define SXYTOL(val) ((((INT16)(val).y * m_convsp) + ((INT16)(val).x << m_pixelshift)) + OFFSET()) +#define DXYTOL(val) ((((INT16)(val).y * m_convdp) + ((INT16)(val).x << m_pixelshift)) + OFFSET()) +#define MXYTOL(val) ((((INT16)(val).y * m_convmp) + ((INT16)(val).x << m_pixelshift)) + OFFSET()) + +#define COUNT_CYCLES(x) m_icount -= x +#define COUNT_UNKNOWN_CYCLES(x) COUNT_CYCLES(x) + +#define CORRECT_ODD_PC(x) do { if (m_pc & 0x0f) logerror("%s to PC=%08X\n", x, m_pc); m_pc &= ~0x0f; } while (0) + + + +/*************************************************************************** + FLAG HANDLING MACROS +***************************************************************************/ + +#define SIGN(val) ((val) & 0x80000000) + +#define CLR_Z() m_st &= ~STBIT_Z +#define CLR_V() m_st &= ~STBIT_V +#define CLR_C() m_st &= ~STBIT_C +#define CLR_N() m_st &= ~STBIT_N +#define CLR_NZ() m_st &= ~(STBIT_N | STBIT_Z) +#define CLR_CZ() m_st &= ~(STBIT_C | STBIT_Z) +#define CLR_ZV() m_st &= ~(STBIT_Z | STBIT_V) +#define CLR_NZV() m_st &= ~(STBIT_N | STBIT_Z | STBIT_V) +#define CLR_NCZ() m_st &= ~(STBIT_N | STBIT_C | STBIT_Z) +#define CLR_NCZV() m_st &= ~(STBIT_N | STBIT_C | STBIT_Z | STBIT_V) + +#define SET_V_BIT_LO(val,bit) m_st |= ((val) << (28 - (bit))) & STBIT_V +#define SET_V_BIT_HI(val,bit) m_st |= ((val) >> ((bit) - 28)) & STBIT_V +#define SET_V_LOG(val) m_st |= (val) << 28 +#define SET_Z_BIT_LO(val,bit) m_st |= ((val) << (29 - (bit))) & STBIT_Z +#define SET_Z_BIT_HI(val,bit) m_st |= ((val) >> ((bit) - 29)) & STBIT_Z +#define SET_Z_LOG(val) m_st |= (val) << 29 +#define SET_C_BIT_LO(val,bit) m_st |= ((val) << (30 - (bit))) & STBIT_C +#define SET_C_BIT_HI(val,bit) m_st |= ((val) >> ((bit) - 30)) & STBIT_C +#define SET_C_LOG(val) m_st |= (val) << 30 +#define SET_N_BIT(val,bit) m_st |= ((val) << (31 - (bit))) & STBIT_N +#define SET_N_LOG(val) m_st |= (val) << 31 + +#define SET_Z_VAL(val) SET_Z_LOG((val) == 0) +#define SET_N_VAL(val) SET_N_BIT(val, 31) +#define SET_NZ_VAL(val) SET_Z_VAL(val); SET_N_VAL(val) +#define SET_V_SUB(a,b,r) SET_V_BIT_HI(((a) ^ (b)) & ((a) ^ (r)), 31) +#define SET_V_ADD(a,b,r) SET_V_BIT_HI(~((a) ^ (b)) & ((a) ^ (r)), 31) +#define SET_C_SUB(a,b) SET_C_LOG((UINT32)(b) > (UINT32)(a)) +#define SET_C_ADD(a,b) SET_C_LOG((UINT32)~(a) < (UINT32)(b)) +#define SET_NZV_SUB(a,b,r) SET_NZ_VAL(r); SET_V_SUB(a,b,r) +#define SET_NZCV_SUB(a,b,r) SET_NZV_SUB(a,b,r); SET_C_SUB(a,b) +#define SET_NZCV_ADD(a,b,r) SET_NZ_VAL(r); SET_V_ADD(a,b,r); SET_C_ADD(a,b) + +static const UINT8 fw_inc[32] = { 32,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31 }; + + +/*************************************************************************** + UNIMPLEMENTED INSTRUCTION +***************************************************************************/ + +void tms340x0_device::unimpl(UINT16 op) +{ + /* kludge for Super High Impact -- this doesn't seem to cause */ + /* an illegal opcode exception */ + if (m_direct->read_word(TOBYTE(m_pc - 0x10)) == 0x0007) + return; + + /* 9 Ball Shootout calls to FFDF7468, expecting it */ + /* to execute the next instruction from FFDF7470 */ + /* but the instruction at FFDF7460 is an 0x0001 */ + if (m_direct->read_word(TOBYTE(m_pc - 0x10)) == 0x0001) + return; + + PUSH(m_pc); + PUSH(m_st); + RESET_ST(); + m_pc = RLONG(0xfffffc20); + COUNT_UNKNOWN_CYCLES(16); + + /* extra check to prevent bad things */ + if (m_pc == 0 || s_opcode_table[m_direct->read_word(TOBYTE(m_pc)) >> 4] == &tms34010_device::unimpl) + { + set_input_line(INPUT_LINE_HALT, ASSERT_LINE); + debugger_break(machine()); + } +} + + + +/*************************************************************************** + X/Y OPERATIONS +***************************************************************************/ + +#define ADD_XY(R) \ +{ \ + XY a = R##REG_XY(SRCREG(op)); \ + XY *b = &R##REG_XY(DSTREG(op)); \ + CLR_NCZV(); \ + b->x += a.x; \ + b->y += a.y; \ + SET_N_LOG(b->x == 0); \ + SET_C_BIT_LO(b->y, 15); \ + SET_Z_LOG(b->y == 0); \ + SET_V_BIT_LO(b->x, 15); \ + COUNT_CYCLES(1); \ +} +void tms340x0_device::add_xy_a(UINT16 op) { ADD_XY(A); } +void tms340x0_device::add_xy_b(UINT16 op) { ADD_XY(B); } + +#define SUB_XY(R) \ +{ \ + XY a = R##REG_XY(SRCREG(op)); \ + XY *b = &R##REG_XY(DSTREG(op)); \ + CLR_NCZV(); \ + SET_N_LOG(a.x == b->x); \ + SET_C_LOG(a.y > b->y); \ + SET_Z_LOG(a.y == b->y); \ + SET_V_LOG(a.x > b->x); \ + b->x -= a.x; \ + b->y -= a.y; \ + COUNT_CYCLES(1); \ +} +void tms340x0_device::sub_xy_a(UINT16 op) { SUB_XY(A); } +void tms340x0_device::sub_xy_b(UINT16 op) { SUB_XY(B); } + +#define CMP_XY(R) \ +{ \ + INT16 res; \ + XY a = R##REG_XY(DSTREG(op)); \ + XY b = R##REG_XY(SRCREG(op)); \ + CLR_NCZV(); \ + res = a.x-b.x; \ + SET_N_LOG(res == 0); \ + SET_V_BIT_LO(res, 15); \ + res = a.y-b.y; \ + SET_Z_LOG(res == 0); \ + SET_C_BIT_LO(res, 15); \ + COUNT_CYCLES(1); \ +} +void tms340x0_device::cmp_xy_a(UINT16 op) { CMP_XY(A); } +void tms340x0_device::cmp_xy_b(UINT16 op) { CMP_XY(B); } + +#define CPW(R) \ +{ \ + INT32 res = 0; \ + INT16 x = R##REG_X(SRCREG(op)); \ + INT16 y = R##REG_Y(SRCREG(op)); \ + \ + CLR_V(); \ + res |= ((WSTART_X() > x) ? 0x20 : 0); \ + res |= ((x > WEND_X()) ? 0x40 : 0); \ + res |= ((WSTART_Y() > y) ? 0x80 : 0); \ + res |= ((y > WEND_Y()) ? 0x100 : 0); \ + R##REG(DSTREG(op)) = res; \ + SET_V_LOG(res != 0); \ + COUNT_CYCLES(1); \ +} +void tms340x0_device::cpw_a(UINT16 op) { CPW(A); } +void tms340x0_device::cpw_b(UINT16 op) { CPW(B); } + +#define CVXYL(R) \ +{ \ + R##REG(DSTREG(op)) = DXYTOL(R##REG_XY(SRCREG(op))); \ + COUNT_CYCLES(3); \ +} +void tms340x0_device::cvxyl_a(UINT16 op) { CVXYL(A); } +void tms340x0_device::cvxyl_b(UINT16 op) { CVXYL(B); } + +#define MOVX(R) \ +{ \ + R##REG(DSTREG(op)) = (R##REG(DSTREG(op)) & 0xffff0000) | (UINT16)R##REG(SRCREG(op)); \ + COUNT_CYCLES(1); \ +} +void tms340x0_device::movx_a(UINT16 op) { MOVX(A); } +void tms340x0_device::movx_b(UINT16 op) { MOVX(B); } + +#define MOVY(R) \ +{ \ + R##REG(DSTREG(op)) = (R##REG(SRCREG(op)) & 0xffff0000) | (UINT16)R##REG(DSTREG(op)); \ + COUNT_CYCLES(1); \ +} +void tms340x0_device::movy_a(UINT16 op) { MOVY(A); } +void tms340x0_device::movy_b(UINT16 op) { MOVY(B); } + + + +/*************************************************************************** + PIXEL TRANSFER OPERATIONS +***************************************************************************/ + +#define PIXT_RI(R) \ +{ \ + WPIXEL(R##REG(DSTREG(op)),R##REG(SRCREG(op))); \ + COUNT_UNKNOWN_CYCLES(2); \ +} +void tms340x0_device::pixt_ri_a(UINT16 op) { PIXT_RI(A); } +void tms340x0_device::pixt_ri_b(UINT16 op) { PIXT_RI(B); } + +#define PIXT_RIXY(R) \ +{ \ + if (WINDOW_CHECKING() != 0) \ + { \ + CLR_V(); \ + if (R##REG_X(DSTREG(op)) < WSTART_X() || R##REG_X(DSTREG(op)) > WEND_X() || \ + R##REG_Y(DSTREG(op)) < WSTART_Y() || R##REG_Y(DSTREG(op)) > WEND_Y()) \ + { \ + SET_V_LOG(1); \ + goto skip; \ + } \ + if (WINDOW_CHECKING() == 1) goto skip; \ + } \ + WPIXEL(DXYTOL(R##REG_XY(DSTREG(op))),R##REG(SRCREG(op))); \ +skip: \ + COUNT_UNKNOWN_CYCLES(4); \ +} +void tms340x0_device::pixt_rixy_a(UINT16 op) { PIXT_RIXY(A); } +void tms340x0_device::pixt_rixy_b(UINT16 op) { PIXT_RIXY(B); } + +#define PIXT_IR(R) \ +{ \ + INT32 temp = RPIXEL(R##REG(SRCREG(op))); \ + CLR_V(); \ + R##REG(DSTREG(op)) = temp; \ + SET_V_LOG(temp != 0); \ + COUNT_CYCLES(4); \ +} +void tms340x0_device::pixt_ir_a(UINT16 op) { PIXT_IR(A); } +void tms340x0_device::pixt_ir_b(UINT16 op) { PIXT_IR(B); } + +#define PIXT_II(R) \ +{ \ + WPIXEL(R##REG(DSTREG(op)),RPIXEL(R##REG(SRCREG(op)))); \ + COUNT_UNKNOWN_CYCLES(4); \ +} +void tms340x0_device::pixt_ii_a(UINT16 op) { PIXT_II(A); } +void tms340x0_device::pixt_ii_b(UINT16 op) { PIXT_II(B); } + +#define PIXT_IXYR(R) \ +{ \ + INT32 temp = RPIXEL(SXYTOL(R##REG_XY(SRCREG(op)))); \ + CLR_V(); \ + R##REG(DSTREG(op)) = temp; \ + SET_V_LOG(temp != 0); \ + COUNT_CYCLES(6); \ +} +void tms340x0_device::pixt_ixyr_a(UINT16 op) { PIXT_IXYR(A); } +void tms340x0_device::pixt_ixyr_b(UINT16 op) { PIXT_IXYR(B); } + +#define PIXT_IXYIXY(R) \ +{ \ + if (WINDOW_CHECKING() != 0) \ + { \ + CLR_V(); \ + if (R##REG_X(DSTREG(op)) < WSTART_X() || R##REG_X(DSTREG(op)) > WEND_X() || \ + R##REG_Y(DSTREG(op)) < WSTART_Y() || R##REG_Y(DSTREG(op)) > WEND_Y()) \ + { \ + SET_V_LOG(1); \ + goto skip; \ + } \ + if (WINDOW_CHECKING() == 1) goto skip; \ + } \ + WPIXEL(DXYTOL(R##REG_XY(DSTREG(op))),RPIXEL(SXYTOL(R##REG_XY(SRCREG(op))))); \ +skip: \ + COUNT_UNKNOWN_CYCLES(7); \ +} +void tms340x0_device::pixt_ixyixy_a(UINT16 op) { PIXT_IXYIXY(A); } +void tms340x0_device::pixt_ixyixy_b(UINT16 op) { PIXT_IXYIXY(B); } + +#define DRAV(R) \ +{ \ + if (WINDOW_CHECKING() != 0) \ + { \ + CLR_V(); \ + if (R##REG_X(DSTREG(op)) < WSTART_X() || R##REG_X(DSTREG(op)) > WEND_X() || \ + R##REG_Y(DSTREG(op)) < WSTART_Y() || R##REG_Y(DSTREG(op)) > WEND_Y()) \ + { \ + SET_V_LOG(1); \ + goto skip; \ + } \ + if (WINDOW_CHECKING() == 1) goto skip; \ + } \ + WPIXEL(DXYTOL(R##REG_XY(DSTREG(op))),COLOR1()); \ +skip: \ + R##REG_X(DSTREG(op)) += R##REG_X(SRCREG(op)); \ + R##REG_Y(DSTREG(op)) += R##REG_Y(SRCREG(op)); \ + COUNT_UNKNOWN_CYCLES(4); \ +} +void tms340x0_device::drav_a(UINT16 op) { DRAV(A); } +void tms340x0_device::drav_b(UINT16 op) { DRAV(B); } + + + +/*************************************************************************** + ARITHMETIC OPERATIONS +***************************************************************************/ + +#define ABS(R) \ +{ \ + INT32 *rd = &R##REG(DSTREG(op)); \ + INT32 r = 0 - *rd; \ + CLR_NZV(); \ + if (r > 0) *rd = r; \ + SET_NZ_VAL(r); \ + SET_V_LOG(r == (INT32)0x80000000); \ + COUNT_CYCLES(1); \ +} +void tms340x0_device::abs_a(UINT16 op) { ABS(A); } +void tms340x0_device::abs_b(UINT16 op) { ABS(B); } + +#define ADD(R) \ +{ \ + INT32 a = R##REG(SRCREG(op)); \ + INT32 *rd = &R##REG(DSTREG(op)); \ + INT32 b = *rd; \ + INT32 r = a + b; \ + CLR_NCZV(); \ + *rd = r; \ + SET_NZCV_ADD(a,b,r); \ + COUNT_CYCLES(1); \ +} +void tms340x0_device::add_a(UINT16 op) { ADD(A); } +void tms340x0_device::add_b(UINT16 op) { ADD(B); } + +#define ADDC(R) \ +{ \ + /* I'm not sure to which side the carry is added to, should */ \ + /* verify it against the examples */ \ + INT32 a = R##REG(SRCREG(op)); \ + INT32 *rd = &R##REG(DSTREG(op)); \ + INT32 b = *rd; \ + INT32 r = a + b + (C_FLAG() ? 1 : 0); \ + CLR_NCZV(); \ + *rd = r; \ + SET_NZCV_ADD(a,b,r); \ + COUNT_CYCLES(1); \ +} +void tms340x0_device::addc_a(UINT16 op) { ADDC(A); } +void tms340x0_device::addc_b(UINT16 op) { ADDC(B); } + +#define ADDI_W(R) \ +{ \ + INT32 a = PARAM_WORD(); \ + INT32 *rd = &R##REG(DSTREG(op)); \ + INT32 b = *rd; \ + INT32 r = a + b; \ + CLR_NCZV(); \ + *rd = r; \ + SET_NZCV_ADD(a,b,r); \ + COUNT_CYCLES(2); \ +} +void tms340x0_device::addi_w_a(UINT16 op) { ADDI_W(A); } +void tms340x0_device::addi_w_b(UINT16 op) { ADDI_W(B); } + +#define ADDI_L(R) \ +{ \ + INT32 a = PARAM_LONG(); \ + INT32 *rd = &R##REG(DSTREG(op)); \ + INT32 b = *rd; \ + INT32 r = a + b; \ + CLR_NCZV(); \ + *rd = r; \ + SET_NZCV_ADD(a,b,r); \ + COUNT_CYCLES(3); \ +} +void tms340x0_device::addi_l_a(UINT16 op) { ADDI_L(A); } +void tms340x0_device::addi_l_b(UINT16 op) { ADDI_L(B); } + +#define ADDK(R) \ +{ \ + INT32 a = fw_inc[PARAM_K(op)]; \ + INT32 *rd = &R##REG(DSTREG(op)); \ + INT32 b = *rd; \ + INT32 r = a + b; \ + CLR_NCZV(); \ + *rd = r; \ + SET_NZCV_ADD(a,b,r); \ + COUNT_CYCLES(1); \ +} +void tms340x0_device::addk_a(UINT16 op) { ADDK(A); } +void tms340x0_device::addk_b(UINT16 op) { ADDK(B); } + +#define AND(R) \ +{ \ + INT32 *rd = &R##REG(DSTREG(op)); \ + CLR_Z(); \ + *rd &= R##REG(SRCREG(op)); \ + SET_Z_VAL(*rd); \ + COUNT_CYCLES(1); \ +} +void tms340x0_device::and_a(UINT16 op) { AND(A); } +void tms340x0_device::and_b(UINT16 op) { AND(B); } + +#define ANDI(R) \ +{ \ + INT32 *rd = &R##REG(DSTREG(op)); \ + CLR_Z(); \ + *rd &= ~PARAM_LONG(); \ + SET_Z_VAL(*rd); \ + COUNT_CYCLES(3); \ +} +void tms340x0_device::andi_a(UINT16 op) { ANDI(A); } +void tms340x0_device::andi_b(UINT16 op) { ANDI(B); } + +#define ANDN(R) \ +{ \ + INT32 *rd = &R##REG(DSTREG(op)); \ + CLR_Z(); \ + *rd &= ~R##REG(SRCREG(op)); \ + SET_Z_VAL(*rd); \ + COUNT_CYCLES(1); \ +} +void tms340x0_device::andn_a(UINT16 op) { ANDN(A); } +void tms340x0_device::andn_b(UINT16 op) { ANDN(B); } + +#define BTST_K(R) \ +{ \ + int bit = 31 - PARAM_K(op); \ + CLR_Z(); \ + if (bit <= 29) \ + SET_Z_BIT_LO(~R##REG(DSTREG(op)), bit); \ + else \ + SET_Z_BIT_HI(~R##REG(DSTREG(op)), bit); \ + COUNT_CYCLES(1); \ +} +void tms340x0_device::btst_k_a(UINT16 op) { BTST_K(A); } +void tms340x0_device::btst_k_b(UINT16 op) { BTST_K(B); } + +#define BTST_R(R) \ +{ \ + int bit = R##REG(SRCREG(op)) & 0x1f; \ + CLR_Z(); \ + if (bit <= 29) \ + SET_Z_BIT_LO(~R##REG(DSTREG(op)), bit); \ + else \ + SET_Z_BIT_HI(~R##REG(DSTREG(op)), bit); \ + COUNT_CYCLES(2); \ +} +void tms340x0_device::btst_r_a(UINT16 op) { BTST_R(A); } +void tms340x0_device::btst_r_b(UINT16 op) { BTST_R(B); } + +void tms340x0_device::clrc(UINT16 op) +{ + CLR_C(); + COUNT_CYCLES(1); +} + +#define CMP(R) \ +{ \ + INT32 *rs = &R##REG(SRCREG(op)); \ + INT32 *rd = &R##REG(DSTREG(op)); \ + INT32 r = *rd - *rs; \ + CLR_NCZV(); \ + SET_NZCV_SUB(*rd,*rs,r); \ + COUNT_CYCLES(1); \ +} +void tms340x0_device::cmp_a(UINT16 op) { CMP(A); } +void tms340x0_device::cmp_b(UINT16 op) { CMP(B); } + +#define CMPI_W(R) \ +{ \ + INT32 *rd = &R##REG(DSTREG(op)); \ + INT32 t = (INT16)~PARAM_WORD(); \ + INT32 r = *rd - t; \ + CLR_NCZV(); \ + SET_NZCV_SUB(*rd,t,r); \ + COUNT_CYCLES(2); \ +} +void tms340x0_device::cmpi_w_a(UINT16 op) { CMPI_W(A); } +void tms340x0_device::cmpi_w_b(UINT16 op) { CMPI_W(B); } + +#define CMPI_L(R) \ +{ \ + INT32 *rd = &R##REG(DSTREG(op)); \ + INT32 t = ~PARAM_LONG(); \ + INT32 r = *rd - t; \ + CLR_NCZV(); \ + SET_NZCV_SUB(*rd,t,r); \ + COUNT_CYCLES(3); \ +} +void tms340x0_device::cmpi_l_a(UINT16 op) { CMPI_L(A); } +void tms340x0_device::cmpi_l_b(UINT16 op) { CMPI_L(B); } + +void tms340x0_device::dint(UINT16 op) +{ + m_st &= ~STBIT_IE; + COUNT_CYCLES(3); +} + +#define DIVS(R) \ +{ \ + INT32 *rs = &R##REG(SRCREG(op)); \ + INT32 *rd1 = &R##REG(DSTREG(op)); \ + CLR_NZV(); \ + if (!(DSTREG(op) & 1)) \ + { \ + if (!*rs) \ + { \ + SET_V_LOG(1); \ + } \ + else \ + { \ + INT32 *rd2 = &R##REG(DSTREG(op)+1); \ + INT64 dividend = ((UINT64)*rd1 << 32) | (UINT32)*rd2; \ + INT64 quotient = dividend / *rs; \ + INT32 remainder = dividend % *rs; \ + UINT32 signbits = (INT32)quotient >> 31; \ + if (EXTRACT_64HI(quotient) != signbits) \ + { \ + SET_V_LOG(1); \ + } \ + else \ + { \ + *rd1 = quotient; \ + *rd2 = remainder; \ + SET_NZ_VAL(*rd1); \ + } \ + } \ + COUNT_CYCLES(40); \ + } \ + else \ + { \ + if (!*rs) \ + { \ + SET_V_LOG(1); \ + } \ + else \ + { \ + *rd1 /= *rs; \ + SET_NZ_VAL(*rd1); \ + } \ + COUNT_CYCLES(39); \ + } \ +} +void tms340x0_device::divs_a(UINT16 op) { DIVS(A); } +void tms340x0_device::divs_b(UINT16 op) { DIVS(B); } + +#define DIVU(R) \ +{ \ + INT32 *rs = &R##REG(SRCREG(op)); \ + INT32 *rd1 = &R##REG(DSTREG(op)); \ + CLR_ZV(); \ + if (!(DSTREG(op) & 1)) \ + { \ + if (!*rs) \ + { \ + SET_V_LOG(1); \ + } \ + else \ + { \ + INT32 *rd2 = &R##REG(DSTREG(op)+1); \ + UINT64 dividend = ((UINT64)*rd1 << 32) | (UINT32)*rd2; \ + UINT64 quotient = dividend / (UINT32)*rs; \ + UINT32 remainder = dividend % (UINT32)*rs; \ + if (EXTRACT_64HI(quotient) != 0) \ + { \ + SET_V_LOG(1); \ + } \ + else \ + { \ + *rd1 = quotient; \ + *rd2 = remainder; \ + SET_Z_VAL(*rd1); \ + } \ + } \ + } \ + else \ + { \ + if (!*rs) \ + { \ + SET_V_LOG(1); \ + } \ + else \ + { \ + *rd1 = (UINT32)*rd1 / (UINT32)*rs; \ + SET_Z_VAL(*rd1); \ + } \ + } \ + COUNT_CYCLES(37); \ +} +void tms340x0_device::divu_a(UINT16 op) { DIVU(A); } +void tms340x0_device::divu_b(UINT16 op) { DIVU(B); } + +void tms340x0_device::eint(UINT16 op) +{ + m_st |= STBIT_IE; + check_interrupt(); + COUNT_CYCLES(3); +} + +#define EXGF(F,R) \ +{ \ + UINT8 shift = F ? 6 : 0; \ + INT32 *rd = &R##REG(DSTREG(op)); \ + UINT32 temp = (m_st >> shift) & 0x3f; \ + m_st &= ~(0x3f << shift); \ + m_st |= (*rd & 0x3f) << shift; \ + *rd = temp; \ + COUNT_CYCLES(1); \ +} +void tms340x0_device::exgf0_a(UINT16 op) { EXGF(0,A); } +void tms340x0_device::exgf0_b(UINT16 op) { EXGF(0,B); } +void tms340x0_device::exgf1_a(UINT16 op) { EXGF(1,A); } +void tms340x0_device::exgf1_b(UINT16 op) { EXGF(1,B); } + +#define LMO(R) \ +{ \ + UINT32 res = 0; \ + UINT32 rs = R##REG(SRCREG(op)); \ + INT32 *rd = &R##REG(DSTREG(op)); \ + CLR_Z(); \ + SET_Z_VAL(rs); \ + if (rs) \ + { \ + while (!(rs & 0x80000000)) \ + { \ + res++; \ + rs <<= 1; \ + } \ + } \ + *rd = res; \ + COUNT_CYCLES(1); \ +} +void tms340x0_device::lmo_a(UINT16 op) { LMO(A); } +void tms340x0_device::lmo_b(UINT16 op) { LMO(B); } + +#define MMFM(R) \ +{ \ + INT32 i; \ + UINT16 l = (UINT16) PARAM_WORD(); \ + COUNT_CYCLES(3); \ + { \ + INT32 rd = DSTREG(op); \ + for (i = 15; i >= 0 ; i--) \ + { \ + if (l & 0x8000) \ + { \ + R##REG(i) = RLONG(R##REG(rd)); \ + R##REG(rd) += 0x20; \ + COUNT_CYCLES(4); \ + } \ + l <<= 1; \ + } \ + } \ +} +void tms340x0_device::mmfm_a(UINT16 op) { MMFM(A); } +void tms340x0_device::mmfm_b(UINT16 op) { MMFM(B); } + +#define MMTM(R) \ +{ \ + UINT32 i; \ + UINT16 l = (UINT16) PARAM_WORD(); \ + COUNT_CYCLES(2); \ + { \ + INT32 rd = DSTREG(op); \ + if (m_is_34020) \ + { \ + CLR_N(); \ + SET_N_VAL(R##REG(rd) ^ 0x80000000); \ + } \ + for (i = 0; i < 16; i++) \ + { \ + if (l & 0x8000) \ + { \ + R##REG(rd) -= 0x20; \ + WLONG(R##REG(rd),R##REG(i)); \ + COUNT_CYCLES(4); \ + } \ + l <<= 1; \ + } \ + } \ +} +void tms340x0_device::mmtm_a(UINT16 op) { MMTM(A); } +void tms340x0_device::mmtm_b(UINT16 op) { MMTM(B); } + +#define MODS(R) \ +{ \ + INT32 *rs = &R##REG(SRCREG(op)); \ + INT32 *rd = &R##REG(DSTREG(op)); \ + CLR_NZV(); \ + if (*rs != 0) \ + { \ + *rd %= *rs; \ + SET_NZ_VAL(*rd); \ + } \ + else \ + SET_V_LOG(1); \ + COUNT_CYCLES(40); \ +} +void tms340x0_device::mods_a(UINT16 op) { MODS(A); } +void tms340x0_device::mods_b(UINT16 op) { MODS(B); } + +#define MODU(R) \ +{ \ + INT32 *rs = &R##REG(SRCREG(op)); \ + INT32 *rd = &R##REG(DSTREG(op)); \ + CLR_ZV(); \ + if (*rs != 0) \ + { \ + *rd = (UINT32)*rd % (UINT32)*rs; \ + SET_Z_VAL(*rd); \ + } \ + else \ + SET_V_LOG(1); \ + COUNT_CYCLES(35); \ +} +void tms340x0_device::modu_a(UINT16 op) { MODU(A); } +void tms340x0_device::modu_b(UINT16 op) { MODU(B); } + +#define MPYS(R) \ +{ \ + INT32 *rd1 = &R##REG(DSTREG(op)); \ + INT32 m1 = R##REG(SRCREG(op)); \ + INT64 product; \ + \ + SEXTEND(m1, FW(1)); \ + CLR_NZ(); \ + product = mul_32x32(m1, *rd1); \ + SET_Z_LOG(product == 0); \ + SET_N_BIT(product >> 32, 31); \ + \ + *rd1 = EXTRACT_64HI(product); \ + R##REG(DSTREG(op)|1) = EXTRACT_64LO(product); \ + \ + COUNT_CYCLES(20); \ +} +void tms340x0_device::mpys_a(UINT16 op) { MPYS(A); } +void tms340x0_device::mpys_b(UINT16 op) { MPYS(B); } + +#define MPYU(R) \ +{ \ + INT32 *rd1 = &R##REG(DSTREG(op)); \ + UINT32 m1 = R##REG(SRCREG(op)); \ + UINT64 product; \ + \ + ZEXTEND(m1, FW(1)); \ + CLR_Z(); \ + product = mulu_32x32(m1, *rd1); \ + SET_Z_LOG(product == 0); \ + \ + *rd1 = EXTRACT_64HI(product); \ + R##REG(DSTREG(op)|1) = EXTRACT_64LO(product); \ + \ + COUNT_CYCLES(21); \ +} +void tms340x0_device::mpyu_a(UINT16 op) { MPYU(A); } +void tms340x0_device::mpyu_b(UINT16 op) { MPYU(B); } + +#define NEG(R) \ +{ \ + INT32 *rd = &R##REG(DSTREG(op)); \ + INT32 r = 0 - *rd; \ + CLR_NCZV(); \ + SET_NZCV_SUB(0,*rd,r); \ + *rd = r; \ + COUNT_CYCLES(1); \ +} +void tms340x0_device::neg_a(UINT16 op) { NEG(A); } +void tms340x0_device::neg_b(UINT16 op) { NEG(B); } + +#define NEGB(R) \ +{ \ + INT32 *rd = &R##REG(DSTREG(op)); \ + INT32 t = *rd + (C_FLAG() ? 1 : 0); \ + INT32 r = 0 - t; \ + CLR_NCZV(); \ + SET_NZCV_SUB(0,t,r); \ + *rd = r; \ + COUNT_CYCLES(1); \ +} +void tms340x0_device::negb_a(UINT16 op) { NEGB(A); } +void tms340x0_device::negb_b(UINT16 op) { NEGB(B); } + +void tms340x0_device::nop(UINT16 op) +{ + COUNT_CYCLES(1); +} + +#define NOT(R) \ +{ \ + INT32 *rd = &R##REG(DSTREG(op)); \ + CLR_Z(); \ + *rd = ~(*rd); \ + SET_Z_VAL(*rd); \ + COUNT_CYCLES(1); \ +} +void tms340x0_device::not_a(UINT16 op) { NOT(A); } +void tms340x0_device::not_b(UINT16 op) { NOT(B); } + +#define OR(R) \ +{ \ + INT32 *rd = &R##REG(DSTREG(op)); \ + CLR_Z(); \ + *rd |= R##REG(SRCREG(op)); \ + SET_Z_VAL(*rd); \ + COUNT_CYCLES(1); \ +} +void tms340x0_device::or_a(UINT16 op) { OR(A); } +void tms340x0_device::or_b(UINT16 op) { OR(B); } + +#define ORI(R) \ +{ \ + INT32 *rd = &R##REG(DSTREG(op)); \ + CLR_Z(); \ + *rd |= PARAM_LONG(); \ + SET_Z_VAL(*rd); \ + COUNT_CYCLES(3); \ +} +void tms340x0_device::ori_a(UINT16 op) { ORI(A); } +void tms340x0_device::ori_b(UINT16 op) { ORI(B); } + +void tms340x0_device::setc(UINT16 op) +{ + SET_C_LOG(1); + COUNT_CYCLES(1); +} + +#define SETF(F) \ +{ \ + UINT8 shift = F ? 6 : 0; \ + m_st &= ~(0x3f << shift); \ + m_st |= (op & 0x3f) << shift; \ + COUNT_CYCLES(1+F); \ +} +void tms340x0_device::setf0(UINT16 op) { SETF(0); } +void tms340x0_device::setf1(UINT16 op) { SETF(1); } + +#define SEXT(F,R) \ +{ \ + INT32 *rd = &R##REG(DSTREG(op)); \ + CLR_NZ(); \ + SEXTEND(*rd,FW(F)); \ + SET_NZ_VAL(*rd); \ + COUNT_CYCLES(3); \ +} +void tms340x0_device::sext0_a(UINT16 op) { SEXT(0,A); } +void tms340x0_device::sext0_b(UINT16 op) { SEXT(0,B); } +void tms340x0_device::sext1_a(UINT16 op) { SEXT(1,A); } +void tms340x0_device::sext1_b(UINT16 op) { SEXT(1,B); } + +#define RL(R,K) \ +{ \ + INT32 *rd = &R##REG(DSTREG(op)); \ + INT32 res = *rd; \ + INT32 k = (K); \ + CLR_CZ(); \ + if (k) \ + { \ + res<<=(k-1); \ + SET_C_BIT_HI(res, 31); \ + res<<=1; \ + res |= (((UINT32)*rd)>>((-k)&0x1f)); \ + *rd = res; \ + } \ + SET_Z_VAL(res); \ + COUNT_CYCLES(1); \ +} +void tms340x0_device::rl_k_a(UINT16 op) { RL(A,PARAM_K(op)); } +void tms340x0_device::rl_k_b(UINT16 op) { RL(B,PARAM_K(op)); } +void tms340x0_device::rl_r_a(UINT16 op) { RL(A,AREG(SRCREG(op))&0x1f); } +void tms340x0_device::rl_r_b(UINT16 op) { RL(B,BREG(SRCREG(op))&0x1f); } + +#define SLA(R,K) \ +{ \ + INT32 *rd = &R##REG(DSTREG(op)); \ + UINT32 res = *rd; \ + INT32 k = K; \ + CLR_NCZV(); \ + if (k) \ + { \ + UINT32 mask = (0xffffffff<<(31-k))&0x7fffffff; \ + UINT32 res2 = SIGN(res) ? res^mask : res; \ + SET_V_LOG((res2 & mask) != 0); \ + \ + res<<=(k-1); \ + SET_C_BIT_HI(res, 31); \ + res<<=1; \ + *rd = res; \ + } \ + SET_NZ_VAL(res); \ + COUNT_CYCLES(3); \ +} +void tms340x0_device::sla_k_a(UINT16 op) { SLA(A,PARAM_K(op)); } +void tms340x0_device::sla_k_b(UINT16 op) { SLA(B,PARAM_K(op)); } +void tms340x0_device::sla_r_a(UINT16 op) { SLA(A,AREG(SRCREG(op))&0x1f); } +void tms340x0_device::sla_r_b(UINT16 op) { SLA(B,BREG(SRCREG(op))&0x1f); } + +#define SLL(R,K) \ +{ \ + INT32 *rd = &R##REG(DSTREG(op)); \ + UINT32 res = *rd; \ + INT32 k = K; \ + CLR_CZ(); \ + if (k) \ + { \ + res<<=(k-1); \ + SET_C_BIT_HI(res, 31); \ + res<<=1; \ + *rd = res; \ + } \ + SET_Z_VAL(res); \ + COUNT_CYCLES(1); \ +} +void tms340x0_device::sll_k_a(UINT16 op) { SLL(A,PARAM_K(op)); } +void tms340x0_device::sll_k_b(UINT16 op) { SLL(B,PARAM_K(op)); } +void tms340x0_device::sll_r_a(UINT16 op) { SLL(A,AREG(SRCREG(op))&0x1f); } +void tms340x0_device::sll_r_b(UINT16 op) { SLL(B,BREG(SRCREG(op))&0x1f); } + +#define SRA(R,K) \ +{ \ + INT32 *rd = &R##REG(DSTREG(op)); \ + INT32 res = *rd; \ + INT32 k = (-(K)) & 0x1f; \ + CLR_NCZ(); \ + if (k) \ + { \ + res>>=(k-1); \ + SET_C_BIT_LO(res, 0); \ + res>>=1; \ + *rd = res; \ + } \ + SET_NZ_VAL(res); \ + COUNT_CYCLES(1); \ +} +void tms340x0_device::sra_k_a(UINT16 op) { SRA(A,PARAM_K(op)); } +void tms340x0_device::sra_k_b(UINT16 op) { SRA(B,PARAM_K(op)); } +void tms340x0_device::sra_r_a(UINT16 op) { SRA(A,AREG(SRCREG(op))); } +void tms340x0_device::sra_r_b(UINT16 op) { SRA(B,BREG(SRCREG(op))); } + +#define SRL(R,K) \ +{ \ + INT32 *rd = &R##REG(DSTREG(op)); \ + UINT32 res = *rd; \ + INT32 k = (-(K)) & 0x1f; \ + CLR_CZ(); \ + if (k) \ + { \ + res>>=(k-1); \ + SET_C_BIT_LO(res, 0); \ + res>>=1; \ + *rd = res; \ + } \ + SET_Z_VAL(res); \ + COUNT_CYCLES(1); \ +} +void tms340x0_device::srl_k_a(UINT16 op) { SRL(A,PARAM_K(op)); } +void tms340x0_device::srl_k_b(UINT16 op) { SRL(B,PARAM_K(op)); } +void tms340x0_device::srl_r_a(UINT16 op) { SRL(A,AREG(SRCREG(op))); } +void tms340x0_device::srl_r_b(UINT16 op) { SRL(B,BREG(SRCREG(op))); } + +#define SUB(R) \ +{ \ + INT32 *rs = &R##REG(SRCREG(op)); \ + INT32 *rd = &R##REG(DSTREG(op)); \ + INT32 r = *rd - *rs; \ + CLR_NCZV(); \ + SET_NZCV_SUB(*rd,*rs,r); \ + *rd = r; \ + COUNT_CYCLES(1); \ +} +void tms340x0_device::sub_a(UINT16 op) { SUB(A); } +void tms340x0_device::sub_b(UINT16 op) { SUB(B); } + +#define SUBB(R) \ +{ \ + INT32 *rd = &R##REG(DSTREG(op)); \ + INT32 t = R##REG(SRCREG(op)); \ + INT32 r = *rd - t - (C_FLAG() ? 1 : 0); \ + CLR_NCZV(); \ + SET_NZCV_SUB(*rd,t,r); \ + *rd = r; \ + COUNT_CYCLES(1); \ +} +void tms340x0_device::subb_a(UINT16 op) { SUBB(A); } +void tms340x0_device::subb_b(UINT16 op) { SUBB(B); } + +#define SUBI_W(R) \ +{ \ + INT32 *rd = &R##REG(DSTREG(op)); \ + INT32 r; \ + INT32 t = ~PARAM_WORD(); \ + CLR_NCZV(); \ + r = *rd - t; \ + SET_NZCV_SUB(*rd,t,r); \ + *rd = r; \ + COUNT_CYCLES(2); \ +} +void tms340x0_device::subi_w_a(UINT16 op) { SUBI_W(A); } +void tms340x0_device::subi_w_b(UINT16 op) { SUBI_W(B); } + +#define SUBI_L(R) \ +{ \ + INT32 *rd = &R##REG(DSTREG(op)); \ + INT32 t = ~PARAM_LONG(); \ + INT32 r = *rd - t; \ + CLR_NCZV(); \ + SET_NZCV_SUB(*rd,t,r); \ + *rd = r; \ + COUNT_CYCLES(3); \ +} +void tms340x0_device::subi_l_a(UINT16 op) { SUBI_L(A); } +void tms340x0_device::subi_l_b(UINT16 op) { SUBI_L(B); } + +#define SUBK(R) \ +{ \ + INT32 *rd = &R##REG(DSTREG(op)); \ + INT32 t = fw_inc[PARAM_K(op)]; \ + INT32 r = *rd - t; \ + CLR_NCZV(); \ + SET_NZCV_SUB(*rd,t,r); \ + *rd = r; \ + COUNT_CYCLES(1); \ +} +void tms340x0_device::subk_a(UINT16 op) { SUBK(A); } +void tms340x0_device::subk_b(UINT16 op) { SUBK(B); } + +#define XOR(R) \ +{ \ + INT32 *rd = &R##REG(DSTREG(op)); \ + CLR_Z(); \ + *rd ^= R##REG(SRCREG(op)); \ + SET_Z_VAL(*rd); \ + COUNT_CYCLES(1); \ +} +void tms340x0_device::xor_a(UINT16 op) { XOR(A); } +void tms340x0_device::xor_b(UINT16 op) { XOR(B); } + +#define XORI(R) \ +{ \ + INT32 *rd = &R##REG(DSTREG(op)); \ + CLR_Z(); \ + *rd ^= PARAM_LONG(); \ + SET_Z_VAL(*rd); \ + COUNT_CYCLES(3); \ +} +void tms340x0_device::xori_a(UINT16 op) { XORI(A); } +void tms340x0_device::xori_b(UINT16 op) { XORI(B); } + +#define ZEXT(F,R) \ +{ \ + INT32 *rd = &R##REG(DSTREG(op)); \ + CLR_Z(); \ + ZEXTEND(*rd,FW(F)); \ + SET_Z_VAL(*rd); \ + COUNT_CYCLES(1); \ +} +void tms340x0_device::zext0_a(UINT16 op) { ZEXT(0,A); } +void tms340x0_device::zext0_b(UINT16 op) { ZEXT(0,B); } +void tms340x0_device::zext1_a(UINT16 op) { ZEXT(1,A); } +void tms340x0_device::zext1_b(UINT16 op) { ZEXT(1,B); } + + + +/*************************************************************************** + MOVE INSTRUCTIONS +***************************************************************************/ + +#define MOVI_W(R) \ +{ \ + INT32 *rd = &R##REG(DSTREG(op)); \ + CLR_NZV(); \ + *rd=PARAM_WORD(); \ + SET_NZ_VAL(*rd); \ + COUNT_CYCLES(2); \ +} +void tms340x0_device::movi_w_a(UINT16 op) { MOVI_W(A); } +void tms340x0_device::movi_w_b(UINT16 op) { MOVI_W(B); } + +#define MOVI_L(R) \ +{ \ + INT32 *rd = &R##REG(DSTREG(op)); \ + CLR_NZV(); \ + *rd=PARAM_LONG(); \ + SET_NZ_VAL(*rd); \ + COUNT_CYCLES(3); \ +} +void tms340x0_device::movi_l_a(UINT16 op) { MOVI_L(A); } +void tms340x0_device::movi_l_b(UINT16 op) { MOVI_L(B); } + +#define MOVK(R) \ +{ \ + INT32 k = PARAM_K(op); if (!k) k = 32; \ + R##REG(DSTREG(op)) = k; \ + COUNT_CYCLES(1); \ +} +void tms340x0_device::movk_a(UINT16 op) { MOVK(A); } +void tms340x0_device::movk_b(UINT16 op) { MOVK(B); } + +#define MOVB_RN(R) \ +{ \ + WBYTE(R##REG(DSTREG(op)),R##REG(SRCREG(op))); \ + COUNT_CYCLES(1); \ +} +void tms340x0_device::movb_rn_a(UINT16 op) { MOVB_RN(A); } +void tms340x0_device::movb_rn_b(UINT16 op) { MOVB_RN(B); } + +#define MOVB_NR(R) \ +{ \ + INT32 *rd = &R##REG(DSTREG(op)); \ + CLR_NZV(); \ + *rd = (INT8)RBYTE(R##REG(SRCREG(op))); \ + SET_NZ_VAL(*rd); \ + COUNT_CYCLES(3); \ +} +void tms340x0_device::movb_nr_a(UINT16 op) { MOVB_NR(A); } +void tms340x0_device::movb_nr_b(UINT16 op) { MOVB_NR(B); } + +#define MOVB_NN(R) \ +{ \ + WBYTE(R##REG(DSTREG(op)),(UINT32)(UINT8)RBYTE(R##REG(SRCREG(op))));\ + COUNT_CYCLES(3); \ +} +void tms340x0_device::movb_nn_a(UINT16 op) { MOVB_NN(A); } +void tms340x0_device::movb_nn_b(UINT16 op) { MOVB_NN(B); } + +#define MOVB_R_NO(R) \ +{ \ + INT32 o = PARAM_WORD(); \ + WBYTE(R##REG(DSTREG(op))+o,R##REG(SRCREG(op))); \ + COUNT_CYCLES(3); \ +} +void tms340x0_device::movb_r_no_a(UINT16 op) { MOVB_R_NO(A); } +void tms340x0_device::movb_r_no_b(UINT16 op) { MOVB_R_NO(B); } + +#define MOVB_NO_R(R) \ +{ \ + INT32 *rd = &R##REG(DSTREG(op)); \ + INT32 o = PARAM_WORD(); \ + CLR_NZV(); \ + *rd = (INT8)RBYTE(R##REG(SRCREG(op))+o); \ + SET_NZ_VAL(*rd); \ + COUNT_CYCLES(5); \ +} +void tms340x0_device::movb_no_r_a(UINT16 op) { MOVB_NO_R(A); } +void tms340x0_device::movb_no_r_b(UINT16 op) { MOVB_NO_R(B); } + +#define MOVB_NO_NO(R) \ +{ \ + INT32 o1 = PARAM_WORD(); \ + INT32 o2 = PARAM_WORD(); \ + WBYTE(R##REG(DSTREG(op))+o2,(UINT32)(UINT8)RBYTE(R##REG(SRCREG(op))+o1)); \ + COUNT_CYCLES(5); \ +} +void tms340x0_device::movb_no_no_a(UINT16 op) { MOVB_NO_NO(A); } +void tms340x0_device::movb_no_no_b(UINT16 op) { MOVB_NO_NO(B); } + +#define MOVB_RA(R) \ +{ \ + WBYTE(PARAM_LONG(),R##REG(DSTREG(op))); \ + COUNT_CYCLES(1); \ +} +void tms340x0_device::movb_ra_a(UINT16 op) { MOVB_RA(A); } +void tms340x0_device::movb_ra_b(UINT16 op) { MOVB_RA(B); } + +#define MOVB_AR(R) \ +{ \ + INT32 *rd = &R##REG(DSTREG(op)); \ + CLR_NZV(); \ + *rd = (INT8)RBYTE(PARAM_LONG()); \ + SET_NZ_VAL(*rd); \ + COUNT_CYCLES(5); \ +} +void tms340x0_device::movb_ar_a(UINT16 op) { MOVB_AR(A); } +void tms340x0_device::movb_ar_b(UINT16 op) { MOVB_AR(B); } + +void tms340x0_device::movb_aa(UINT16 op) +{ + UINT32 bitaddrs=PARAM_LONG(); + WBYTE(PARAM_LONG(),(UINT32)(UINT8)RBYTE(bitaddrs)); + COUNT_CYCLES(6); +} + +#define MOVE_RR(RS,RD) \ +{ \ + INT32 *rd = &RD##REG(DSTREG(op)); \ + CLR_NZV(); \ + *rd = RS##REG(SRCREG(op)); \ + SET_NZ_VAL(*rd); \ + COUNT_CYCLES(1); \ +} +void tms340x0_device::move_rr_a (UINT16 op) { MOVE_RR(A,A); } +void tms340x0_device::move_rr_b (UINT16 op) { MOVE_RR(B,B); } +void tms340x0_device::move_rr_ax(UINT16 op) { MOVE_RR(A,B); } +void tms340x0_device::move_rr_bx(UINT16 op) { MOVE_RR(B,A); } + +#define MOVE_RN(F,R) \ +{ \ + WFIELD##F(R##REG(DSTREG(op)),R##REG(SRCREG(op))); \ + COUNT_CYCLES(1); \ +} +void tms340x0_device::move0_rn_a (UINT16 op) { MOVE_RN(0,A); } +void tms340x0_device::move0_rn_b (UINT16 op) { MOVE_RN(0,B); } +void tms340x0_device::move1_rn_a (UINT16 op) { MOVE_RN(1,A); } +void tms340x0_device::move1_rn_b (UINT16 op) { MOVE_RN(1,B); } + +#define MOVE_R_DN(F,R) \ +{ \ + INT32 *rd = &R##REG(DSTREG(op)); \ + *rd-=fw_inc[FW(F)]; \ + WFIELD##F(*rd,R##REG(SRCREG(op))); \ + COUNT_CYCLES(2); \ +} +void tms340x0_device::move0_r_dn_a (UINT16 op) { MOVE_R_DN(0,A); } +void tms340x0_device::move0_r_dn_b (UINT16 op) { MOVE_R_DN(0,B); } +void tms340x0_device::move1_r_dn_a (UINT16 op) { MOVE_R_DN(1,A); } +void tms340x0_device::move1_r_dn_b (UINT16 op) { MOVE_R_DN(1,B); } + +#define MOVE_R_NI(F,R) \ +{ \ + INT32 *rd = &R##REG(DSTREG(op)); \ + WFIELD##F(*rd,R##REG(SRCREG(op))); \ + *rd+=fw_inc[FW(F)]; \ + COUNT_CYCLES(1); \ +} +void tms340x0_device::move0_r_ni_a (UINT16 op) { MOVE_R_NI(0,A); } +void tms340x0_device::move0_r_ni_b (UINT16 op) { MOVE_R_NI(0,B); } +void tms340x0_device::move1_r_ni_a (UINT16 op) { MOVE_R_NI(1,A); } +void tms340x0_device::move1_r_ni_b (UINT16 op) { MOVE_R_NI(1,B); } + +#define MOVE_NR(F,R) \ +{ \ + INT32 *rd = &R##REG(DSTREG(op)); \ + CLR_NZV(); \ + *rd = RFIELD##F(R##REG(SRCREG(op))); \ + SET_NZ_VAL(*rd); \ + COUNT_CYCLES(3); \ +} +void tms340x0_device::move0_nr_a (UINT16 op) { MOVE_NR(0,A); } +void tms340x0_device::move0_nr_b (UINT16 op) { MOVE_NR(0,B); } +void tms340x0_device::move1_nr_a (UINT16 op) { MOVE_NR(1,A); } +void tms340x0_device::move1_nr_b (UINT16 op) { MOVE_NR(1,B); } + +#define MOVE_DN_R(F,R) \ +{ \ + INT32 *rd = &R##REG(DSTREG(op)); \ + INT32 *rs = &R##REG(SRCREG(op)); \ + CLR_NZV(); \ + *rs-=fw_inc[FW(F)]; \ + *rd = RFIELD##F(*rs); \ + SET_NZ_VAL(*rd); \ + COUNT_CYCLES(4); \ +} +void tms340x0_device::move0_dn_r_a (UINT16 op) { MOVE_DN_R(0,A); } +void tms340x0_device::move0_dn_r_b (UINT16 op) { MOVE_DN_R(0,B); } +void tms340x0_device::move1_dn_r_a (UINT16 op) { MOVE_DN_R(1,A); } +void tms340x0_device::move1_dn_r_b (UINT16 op) { MOVE_DN_R(1,B); } + +#define MOVE_NI_R(F,R) \ +{ \ + INT32 *rd = &R##REG(DSTREG(op)); \ + INT32 *rs = &R##REG(SRCREG(op)); \ + INT32 data = RFIELD##F(*rs); \ + CLR_NZV(); \ + *rs+=fw_inc[FW(F)]; \ + *rd = data; \ + SET_NZ_VAL(*rd); \ + COUNT_CYCLES(3); \ +} +void tms340x0_device::move0_ni_r_a (UINT16 op) { MOVE_NI_R(0,A); } +void tms340x0_device::move0_ni_r_b (UINT16 op) { MOVE_NI_R(0,B); } +void tms340x0_device::move1_ni_r_a (UINT16 op) { MOVE_NI_R(1,A); } +void tms340x0_device::move1_ni_r_b (UINT16 op) { MOVE_NI_R(1,B); } + +#define MOVE_NN(F,R) \ +{ \ + WFIELD##F(R##REG(DSTREG(op)),RFIELD##F(R##REG(SRCREG(op)))); \ + COUNT_CYCLES(3); \ +} +void tms340x0_device::move0_nn_a (UINT16 op) { MOVE_NN(0,A); } +void tms340x0_device::move0_nn_b (UINT16 op) { MOVE_NN(0,B); } +void tms340x0_device::move1_nn_a (UINT16 op) { MOVE_NN(1,A); } +void tms340x0_device::move1_nn_b (UINT16 op) { MOVE_NN(1,B); } + +#define MOVE_DN_DN(F,R) \ +{ \ + INT32 *rd = &R##REG(DSTREG(op)); \ + INT32 *rs = &R##REG(SRCREG(op)); \ + INT32 data; \ + *rs-=fw_inc[FW(F)]; \ + data = RFIELD##F(*rs); \ + *rd-=fw_inc[FW(F)]; \ + WFIELD##F(*rd,data); \ + COUNT_CYCLES(4); \ +} +void tms340x0_device::move0_dn_dn_a (UINT16 op) { MOVE_DN_DN(0,A); } +void tms340x0_device::move0_dn_dn_b (UINT16 op) { MOVE_DN_DN(0,B); } +void tms340x0_device::move1_dn_dn_a (UINT16 op) { MOVE_DN_DN(1,A); } +void tms340x0_device::move1_dn_dn_b (UINT16 op) { MOVE_DN_DN(1,B); } + +#define MOVE_NI_NI(F,R) \ +{ \ + INT32 *rd = &R##REG(DSTREG(op)); \ + INT32 *rs = &R##REG(SRCREG(op)); \ + INT32 data = RFIELD##F(*rs); \ + *rs+=fw_inc[FW(F)]; \ + WFIELD##F(*rd,data); \ + *rd+=fw_inc[FW(F)]; \ + COUNT_CYCLES(4); \ +} +void tms340x0_device::move0_ni_ni_a (UINT16 op) { MOVE_NI_NI(0,A); } +void tms340x0_device::move0_ni_ni_b (UINT16 op) { MOVE_NI_NI(0,B); } +void tms340x0_device::move1_ni_ni_a (UINT16 op) { MOVE_NI_NI(1,A); } +void tms340x0_device::move1_ni_ni_b (UINT16 op) { MOVE_NI_NI(1,B); } + +#define MOVE_R_NO(F,R) \ +{ \ + INT32 o = PARAM_WORD(); \ + WFIELD##F(R##REG(DSTREG(op))+o,R##REG(SRCREG(op))); \ + COUNT_CYCLES(3); \ +} +void tms340x0_device::move0_r_no_a (UINT16 op) { MOVE_R_NO(0,A); } +void tms340x0_device::move0_r_no_b (UINT16 op) { MOVE_R_NO(0,B); } +void tms340x0_device::move1_r_no_a (UINT16 op) { MOVE_R_NO(1,A); } +void tms340x0_device::move1_r_no_b (UINT16 op) { MOVE_R_NO(1,B); } + +#define MOVE_NO_R(F,R) \ +{ \ + INT32 *rd = &R##REG(DSTREG(op)); \ + INT32 o = PARAM_WORD(); \ + CLR_NZV(); \ + *rd = RFIELD##F(R##REG(SRCREG(op))+o); \ + SET_NZ_VAL(*rd); \ + COUNT_CYCLES(5); \ +} +void tms340x0_device::move0_no_r_a (UINT16 op) { MOVE_NO_R(0,A); } +void tms340x0_device::move0_no_r_b (UINT16 op) { MOVE_NO_R(0,B); } +void tms340x0_device::move1_no_r_a (UINT16 op) { MOVE_NO_R(1,A); } +void tms340x0_device::move1_no_r_b (UINT16 op) { MOVE_NO_R(1,B); } + +#define MOVE_NO_NI(F,R) \ +{ \ + INT32 *rd = &R##REG(DSTREG(op)); \ + INT32 o = PARAM_WORD(); \ + INT32 data = RFIELD##F(R##REG(SRCREG(op))+o); \ + WFIELD##F(*rd,data); \ + *rd+=fw_inc[FW(F)]; \ + COUNT_CYCLES(5); \ +} +void tms340x0_device::move0_no_ni_a (UINT16 op) { MOVE_NO_NI(0,A); } +void tms340x0_device::move0_no_ni_b (UINT16 op) { MOVE_NO_NI(0,B); } +void tms340x0_device::move1_no_ni_a (UINT16 op) { MOVE_NO_NI(1,A); } +void tms340x0_device::move1_no_ni_b (UINT16 op) { MOVE_NO_NI(1,B); } + +#define MOVE_NO_NO(F,R) \ +{ \ + INT32 o1 = PARAM_WORD(); \ + INT32 o2 = PARAM_WORD(); \ + INT32 data = RFIELD##F(R##REG(SRCREG(op))+o1); \ + WFIELD##F(R##REG(DSTREG(op))+o2,data); \ + COUNT_CYCLES(5); \ +} +void tms340x0_device::move0_no_no_a (UINT16 op) { MOVE_NO_NO(0,A); } +void tms340x0_device::move0_no_no_b (UINT16 op) { MOVE_NO_NO(0,B); } +void tms340x0_device::move1_no_no_a (UINT16 op) { MOVE_NO_NO(1,A); } +void tms340x0_device::move1_no_no_b (UINT16 op) { MOVE_NO_NO(1,B); } + +#define MOVE_RA(F,R) \ +{ \ + WFIELD##F(PARAM_LONG(),R##REG(DSTREG(op))); \ + COUNT_CYCLES(3); \ +} +void tms340x0_device::move0_ra_a (UINT16 op) { MOVE_RA(0,A); } +void tms340x0_device::move0_ra_b (UINT16 op) { MOVE_RA(0,B); } +void tms340x0_device::move1_ra_a (UINT16 op) { MOVE_RA(1,A); } +void tms340x0_device::move1_ra_b (UINT16 op) { MOVE_RA(1,B); } + +#define MOVE_AR(F,R) \ +{ \ + INT32 *rd = &R##REG(DSTREG(op)); \ + CLR_NZV(); \ + *rd = RFIELD##F(PARAM_LONG()); \ + SET_NZ_VAL(*rd); \ + COUNT_CYCLES(5); \ +} +void tms340x0_device::move0_ar_a (UINT16 op) { MOVE_AR(0,A); } +void tms340x0_device::move0_ar_b (UINT16 op) { MOVE_AR(0,B); } +void tms340x0_device::move1_ar_a (UINT16 op) { MOVE_AR(1,A); } +void tms340x0_device::move1_ar_b (UINT16 op) { MOVE_AR(1,B); } + +#define MOVE_A_NI(F,R) \ +{ \ + INT32 *rd = &R##REG(DSTREG(op)); \ + WFIELD##F(*rd,RFIELD##F(PARAM_LONG())); \ + *rd+=fw_inc[FW(F)]; \ + COUNT_CYCLES(5); \ +} +void tms340x0_device::move0_a_ni_a (UINT16 op) { MOVE_A_NI(0,A); } +void tms340x0_device::move0_a_ni_b (UINT16 op) { MOVE_A_NI(0,B); } +void tms340x0_device::move1_a_ni_a (UINT16 op) { MOVE_A_NI(1,A); } +void tms340x0_device::move1_a_ni_b (UINT16 op) { MOVE_A_NI(1,B); } + +#define MOVE_AA(F) \ +{ \ + UINT32 bitaddrs=PARAM_LONG(); \ + WFIELD##F(PARAM_LONG(),RFIELD##F(bitaddrs)); \ + COUNT_CYCLES(7); \ +} +void tms340x0_device::move0_aa (UINT16 op) { MOVE_AA(0); } +void tms340x0_device::move1_aa (UINT16 op) { MOVE_AA(1); } + + + +/*************************************************************************** + PROGRAM CONTROL INSTRUCTIONS +***************************************************************************/ + +#define CALL(R) \ +{ \ + PUSH(m_pc); \ + m_pc = R##REG(DSTREG(op)); \ + CORRECT_ODD_PC("CALL"); \ + COUNT_CYCLES(3); \ +} +void tms340x0_device::call_a (UINT16 op) { CALL(A); } +void tms340x0_device::call_b (UINT16 op) { CALL(B); } + +void tms340x0_device::callr(UINT16 op) +{ + PUSH(m_pc+0x10); + m_pc += (PARAM_WORD_NO_INC()<<4)+0x10; + COUNT_CYCLES(3); +} + +void tms340x0_device::calla(UINT16 op) +{ + PUSH(m_pc+0x20); + m_pc = PARAM_LONG_NO_INC(); + CORRECT_ODD_PC("CALLA"); + COUNT_CYCLES(4); +} + +#define DSJ(R) \ +{ \ + if (--R##REG(DSTREG(op))) \ + { \ + m_pc += (PARAM_WORD_NO_INC()<<4)+0x10; \ + COUNT_CYCLES(3); \ + } \ + else \ + { \ + SKIP_WORD(); \ + COUNT_CYCLES(2); \ + } \ +} +void tms340x0_device::dsj_a (UINT16 op) { DSJ(A); } +void tms340x0_device::dsj_b (UINT16 op) { DSJ(B); } + +#define DSJEQ(R) \ +{ \ + if (Z_FLAG()) \ + { \ + if (--R##REG(DSTREG(op))) \ + { \ + m_pc += (PARAM_WORD_NO_INC()<<4)+0x10; \ + COUNT_CYCLES(3); \ + } \ + else \ + { \ + SKIP_WORD(); \ + COUNT_CYCLES(2); \ + } \ + } \ + else \ + { \ + SKIP_WORD(); \ + COUNT_CYCLES(2); \ + } \ +} +void tms340x0_device::dsjeq_a (UINT16 op) { DSJEQ(A); } +void tms340x0_device::dsjeq_b (UINT16 op) { DSJEQ(B); } + +#define DSJNE(R) \ +{ \ + if (!Z_FLAG()) \ + { \ + if (--R##REG(DSTREG(op))) \ + { \ + m_pc += (PARAM_WORD_NO_INC()<<4)+0x10; \ + COUNT_CYCLES(3); \ + } \ + else \ + { \ + SKIP_WORD(); \ + COUNT_CYCLES(2); \ + } \ + } \ + else \ + { \ + SKIP_WORD(); \ + COUNT_CYCLES(2); \ + } \ +} +void tms340x0_device::dsjne_a (UINT16 op) { DSJNE(A); } +void tms340x0_device::dsjne_b (UINT16 op) { DSJNE(B); } + +#define DSJS(R) \ +{ \ + if (op & 0x0400) \ + { \ + if (--R##REG(DSTREG(op))) \ + { \ + m_pc -= ((PARAM_K(op))<<4); \ + COUNT_CYCLES(2); \ + } \ + else \ + COUNT_CYCLES(3); \ + } \ + else \ + { \ + if (--R##REG(DSTREG(op))) \ + { \ + m_pc += ((PARAM_K(op))<<4); \ + COUNT_CYCLES(2); \ + } \ + else \ + COUNT_CYCLES(3); \ + } \ +} +void tms340x0_device::dsjs_a (UINT16 op) { DSJS(A); } +void tms340x0_device::dsjs_b (UINT16 op) { DSJS(B); } + +void tms340x0_device::emu(UINT16 op) +{ + /* in RUN state, this instruction is a NOP */ + COUNT_CYCLES(6); +} + +#define EXGPC(R) \ +{ \ + INT32 *rd = &R##REG(DSTREG(op)); \ + INT32 temppc = *rd; \ + *rd = m_pc; \ + m_pc = temppc; \ + CORRECT_ODD_PC("EXGPC"); \ + COUNT_CYCLES(2); \ +} +void tms340x0_device::exgpc_a (UINT16 op) { EXGPC(A); } +void tms340x0_device::exgpc_b (UINT16 op) { EXGPC(B); } + +#define GETPC(R) \ +{ \ + R##REG(DSTREG(op)) = m_pc; \ + COUNT_CYCLES(1); \ +} +void tms340x0_device::getpc_a (UINT16 op) { GETPC(A); } +void tms340x0_device::getpc_b (UINT16 op) { GETPC(B); } + +#define GETST(R) \ +{ \ + R##REG(DSTREG(op)) = m_st; \ + COUNT_CYCLES(1); \ +} +void tms340x0_device::getst_a (UINT16 op) { GETST(A); } +void tms340x0_device::getst_b (UINT16 op) { GETST(B); } + +#define j_xx_8(TAKE) \ +{ \ + if (DSTREG(op)) \ + { \ + if (TAKE) \ + { \ + m_pc += (PARAM_REL8(op) << 4); \ + COUNT_CYCLES(2); \ + } \ + else \ + COUNT_CYCLES(1); \ + } \ + else \ + { \ + if (TAKE) \ + { \ + m_pc = PARAM_LONG_NO_INC(); \ + CORRECT_ODD_PC("J_XX_8"); \ + COUNT_CYCLES(3); \ + } \ + else \ + { \ + SKIP_LONG(); \ + COUNT_CYCLES(4); \ + } \ + } \ +} + +#define j_xx_0(TAKE) \ +{ \ + if (DSTREG(op)) \ + { \ + if (TAKE) \ + { \ + m_pc += (PARAM_REL8(op) << 4); \ + COUNT_CYCLES(2); \ + } \ + else \ + COUNT_CYCLES(1); \ + } \ + else \ + { \ + if (TAKE) \ + { \ + m_pc += (PARAM_WORD_NO_INC()<<4)+0x10; \ + COUNT_CYCLES(3); \ + } \ + else \ + { \ + SKIP_WORD(); \ + COUNT_CYCLES(2); \ + } \ + } \ +} + +#define j_xx_x(TAKE) \ +{ \ + if (TAKE) \ + { \ + m_pc += (PARAM_REL8(op) << 4); \ + COUNT_CYCLES(2); \ + } \ + else \ + COUNT_CYCLES(1); \ +} + +void tms340x0_device::j_UC_0(UINT16 op) +{ + j_xx_0(1); +} +void tms340x0_device::j_UC_8(UINT16 op) +{ + j_xx_8(1); +} +void tms340x0_device::j_UC_x(UINT16 op) +{ + j_xx_x(1); +} +void tms340x0_device::j_P_0(UINT16 op) +{ + j_xx_0(!N_FLAG() && !Z_FLAG()); +} +void tms340x0_device::j_P_8(UINT16 op) +{ + j_xx_8(!N_FLAG() && !Z_FLAG()); +} +void tms340x0_device::j_P_x(UINT16 op) +{ + j_xx_x(!N_FLAG() && !Z_FLAG()); +} +void tms340x0_device::j_LS_0(UINT16 op) +{ + j_xx_0(C_FLAG() || Z_FLAG()); +} +void tms340x0_device::j_LS_8(UINT16 op) +{ + j_xx_8(C_FLAG() || Z_FLAG()); +} +void tms340x0_device::j_LS_x(UINT16 op) +{ + j_xx_x(C_FLAG() || Z_FLAG()); +} +void tms340x0_device::j_HI_0(UINT16 op) +{ + j_xx_0(!C_FLAG() && !Z_FLAG()); +} +void tms340x0_device::j_HI_8(UINT16 op) +{ + j_xx_8(!C_FLAG() && !Z_FLAG()); +} +void tms340x0_device::j_HI_x(UINT16 op) +{ + j_xx_x(!C_FLAG() && !Z_FLAG()); +} +void tms340x0_device::j_LT_0(UINT16 op) +{ + j_xx_0((N_FLAG() && !V_FLAG()) || (!N_FLAG() && V_FLAG())); +} +void tms340x0_device::j_LT_8(UINT16 op) +{ + j_xx_8((N_FLAG() && !V_FLAG()) || (!N_FLAG() && V_FLAG())); +} +void tms340x0_device::j_LT_x(UINT16 op) +{ + j_xx_x((N_FLAG() && !V_FLAG()) || (!N_FLAG() && V_FLAG())); +} +void tms340x0_device::j_GE_0(UINT16 op) +{ + j_xx_0((N_FLAG() && V_FLAG()) || (!N_FLAG() && !V_FLAG())); +} +void tms340x0_device::j_GE_8(UINT16 op) +{ + j_xx_8((N_FLAG() && V_FLAG()) || (!N_FLAG() && !V_FLAG())); +} +void tms340x0_device::j_GE_x(UINT16 op) +{ + j_xx_x((N_FLAG() && V_FLAG()) || (!N_FLAG() && !V_FLAG())); +} +void tms340x0_device::j_LE_0(UINT16 op) +{ + j_xx_0((N_FLAG() && !V_FLAG()) || (!N_FLAG() && V_FLAG()) || Z_FLAG()); +} +void tms340x0_device::j_LE_8(UINT16 op) +{ + j_xx_8((N_FLAG() && !V_FLAG()) || (!N_FLAG() && V_FLAG()) || Z_FLAG()); +} +void tms340x0_device::j_LE_x(UINT16 op) +{ + j_xx_x((N_FLAG() && !V_FLAG()) || (!N_FLAG() && V_FLAG()) || Z_FLAG()); +} +void tms340x0_device::j_GT_0(UINT16 op) +{ + j_xx_0((N_FLAG() && V_FLAG() && !Z_FLAG()) || (!N_FLAG() && !V_FLAG() && !Z_FLAG())); +} +void tms340x0_device::j_GT_8(UINT16 op) +{ + j_xx_8((N_FLAG() && V_FLAG() && !Z_FLAG()) || (!N_FLAG() && !V_FLAG() && !Z_FLAG())); +} +void tms340x0_device::j_GT_x(UINT16 op) +{ + j_xx_x((N_FLAG() && V_FLAG() && !Z_FLAG()) || (!N_FLAG() && !V_FLAG() && !Z_FLAG())); +} +void tms340x0_device::j_C_0(UINT16 op) +{ + j_xx_0(C_FLAG()); +} +void tms340x0_device::j_C_8(UINT16 op) +{ + j_xx_8(C_FLAG()); +} +void tms340x0_device::j_C_x(UINT16 op) +{ + j_xx_x(C_FLAG()); +} +void tms340x0_device::j_NC_0(UINT16 op) +{ + j_xx_0(!C_FLAG()); +} +void tms340x0_device::j_NC_8(UINT16 op) +{ + j_xx_8(!C_FLAG()); +} +void tms340x0_device::j_NC_x(UINT16 op) +{ + j_xx_x(!C_FLAG()); +} +void tms340x0_device::j_EQ_0(UINT16 op) +{ + j_xx_0(Z_FLAG()); +} +void tms340x0_device::j_EQ_8(UINT16 op) +{ + j_xx_8(Z_FLAG()); +} +void tms340x0_device::j_EQ_x(UINT16 op) +{ + j_xx_x(Z_FLAG()); +} +void tms340x0_device::j_NE_0(UINT16 op) +{ + j_xx_0(!Z_FLAG()); +} +void tms340x0_device::j_NE_8(UINT16 op) +{ + j_xx_8(!Z_FLAG()); +} +void tms340x0_device::j_NE_x(UINT16 op) +{ + j_xx_x(!Z_FLAG()); +} +void tms340x0_device::j_V_0(UINT16 op) +{ + j_xx_0(V_FLAG()); +} +void tms340x0_device::j_V_8(UINT16 op) +{ + j_xx_8(V_FLAG()); +} +void tms340x0_device::j_V_x(UINT16 op) +{ + j_xx_x(V_FLAG()); +} +void tms340x0_device::j_NV_0(UINT16 op) +{ + j_xx_0(!V_FLAG()); +} +void tms340x0_device::j_NV_8(UINT16 op) +{ + j_xx_8(!V_FLAG()); +} +void tms340x0_device::j_NV_x(UINT16 op) +{ + j_xx_x(!V_FLAG()); +} +void tms340x0_device::j_N_0(UINT16 op) +{ + j_xx_0(N_FLAG()); +} +void tms340x0_device::j_N_8(UINT16 op) +{ + j_xx_8(N_FLAG()); +} +void tms340x0_device::j_N_x(UINT16 op) +{ + j_xx_x(N_FLAG()); +} +void tms340x0_device::j_NN_0(UINT16 op) +{ + j_xx_0(!N_FLAG()); +} +void tms340x0_device::j_NN_8(UINT16 op) +{ + j_xx_8(!N_FLAG()); +} +void tms340x0_device::j_NN_x(UINT16 op) +{ + j_xx_x(!N_FLAG()); +} + +#define JUMP(R) \ +{ \ + m_pc = R##REG(DSTREG(op)); \ + CORRECT_ODD_PC("JUMP"); \ + COUNT_CYCLES(2); \ +} +void tms340x0_device::jump_a (UINT16 op) { JUMP(A); } +void tms340x0_device::jump_b (UINT16 op) { JUMP(B); } + +void tms340x0_device::popst(UINT16 op) +{ + SET_ST(POP()); + COUNT_CYCLES(8); +} + +void tms340x0_device::pushst(UINT16 op) +{ + PUSH(m_st); + COUNT_CYCLES(2); +} + +#define PUTST(R) \ +{ \ + SET_ST(R##REG(DSTREG(op))); \ + COUNT_CYCLES(3); \ +} +void tms340x0_device::putst_a (UINT16 op) { PUTST(A); } +void tms340x0_device::putst_b (UINT16 op) { PUTST(B); } + +void tms340x0_device::reti(UINT16 op) +{ + INT32 st = POP(); + m_pc = POP(); + CORRECT_ODD_PC("RETI"); + SET_ST(st); + COUNT_CYCLES(11); +} + +void tms340x0_device::rets(UINT16 op) +{ + UINT32 offs; + m_pc = POP(); + CORRECT_ODD_PC("RETS"); + offs = PARAM_N(op); + if (offs) + { + SP()+=(offs<<4); + } + COUNT_CYCLES(7); +} + +#define REV(R) \ +{ \ + R##REG(DSTREG(op)) = 0x0008; \ + COUNT_CYCLES(1); \ +} +void tms340x0_device::rev_a (UINT16 op) { REV(A); } +void tms340x0_device::rev_b (UINT16 op) { REV(B); } + +void tms340x0_device::trap(UINT16 op) +{ + UINT32 t = PARAM_N(op); + if (t) + { + PUSH(m_pc); + PUSH(m_st); + } + RESET_ST(); + m_pc = RLONG(0xffffffe0-(t<<5)); + CORRECT_ODD_PC("TRAP"); + COUNT_CYCLES(16); +} + + + +/*************************************************************************** + 34020 INSTRUCTIONS +***************************************************************************/ + +/************************************ + +New 34020 ops: + + 0000 1100 000R dddd = ADDXYI IL,Rd + iiii iiii iiii iiii + iiii iiii iiii iiii + + 0000 0000 1111 00SD = BLMOVE S,D + + 0000 0110 0000 0000 = CEXEC S,c,ID,L + cccc cccc S000 0000 + iiic cccc cccc cccc + + 1101 1000 0ccc cccS = CEXEC S,c,ID + iiic cccc cccc cccc + + 0000 1000 1111 0010 = CLIP + + 0000 0110 011R dddd = CMOVCG Rd1,Rd2,S,c,ID + cccc cccc S00R dddd + iiic cccc cccc cccc + + 0000 0110 101R dddd = CMOVCM *Rd+,n,S,c,ID + cccc cccc S00n nnnn + iiic cccc cccc cccc + + 0000 0110 110R dddd = CMOVCM -*Rd,n,S,c,ID + cccc cccc S00n nnnn + iiic cccc cccc cccc + + 0000 0110 0110 0000 = CMOVCS c,ID + cccc cccc 0000 0001 + iiic cccc cccc cccc + + 0000 0110 001R ssss = CMOVGC Rs,c,ID + cccc cccc 0000 0000 + iiic cccc cccc cccc + + 0000 0110 010R ssss = CMOVGC Rs1,Rs2,S,c,ID + cccc cccc S00R ssss + iiic cccc cccc cccc + + 0000 0110 100n nnnn = CMOVMC *Rs+,n,S,c,ID + cccc cccc S00R ssss + iiic cccc cccc cccc + + 0000 1000 001n nnnn = CMOVMC -*Rs,n,S,c,ID + cccc cccc S00R ssss + iiic cccc cccc cccc + + 0000 0110 111R dddd = CMOVMC *Rs+,Rd,S,c,ID + cccc cccc S00R ssss + iiic cccc cccc cccc + + 0011 01kk kkkR dddd = CMPK k,Rd + + 0000 1010 100R dddd = CVDXYL Rd + + 0000 1010 011R dddd = CVMXYL Rd + + 1110 101s sssR dddd = CVSXYL Rs,Rd + + 0000 0010 101R dddd = EXGPS Rd + + 1101 1110 Z001 1010 = FLINE Z + + 0000 1010 1011 1011 = FPIXEQ + + 0000 1010 1101 1011 = FPIXNE + + 0000 0010 110R dddd = GETPS Rd + + 0000 0000 0100 0000 = IDLE + + 0000 1100 0101 0111 = LINIT + + 0000 0000 1000 0000 = MWAIT + + 0000 1010 0011 0111 = PFILL XY + + 0000 1110 0001 0111 = PIXBLT L,M,L + + 0000 1000 0110 0000 = RETM + + 0111 101s sssR dddd = RMO Rs,Rd + + 0000 0010 100R dddd = RPIX Rd + + 0000 0010 0111 0011 = SETCDP + + 0000 0010 1111 1011 = SETCMP + + 0000 0010 0101 0001 = SETCSP + + 0111 111s sssR dddd = SWAPF *Rs,Rd,0 + + 0000 1110 1111 1010 = TFILL XY + + 0000 1000 0000 1111 = TRAPL + + 0000 1000 0101 0111 = VBLT B,L + + 0000 1010 0101 0111 = VFILL L + + 0000 1010 0000 0000 = VLCOL + +************************************/ + + +#define ADD_XYI(R) \ +{ \ + UINT32 a = PARAM_LONG(); \ + XY *b = &R##REG_XY(DSTREG(op)); \ + CLR_NCZV(); \ + b->x += (INT16)(a & 0xffff); \ + b->y += ((INT32)a >> 16); \ + SET_N_LOG(b->x == 0); \ + SET_C_BIT_LO(b->y, 15); \ + SET_Z_LOG(b->y == 0); \ + SET_V_BIT_LO(b->x, 15); \ + COUNT_CYCLES(1); \ +} +void tms340x0_device::addxyi_a(UINT16 op) +{ + if (!m_is_34020) { unimpl(op); return; } + ADD_XYI(A); +} +void tms340x0_device::addxyi_b(UINT16 op) +{ + if (!m_is_34020) { unimpl(op); return; } + ADD_XYI(B); +} + +void tms340x0_device::blmove(UINT16 op) +{ + offs_t src = BREG(0); + offs_t dst = BREG(2); + offs_t bits = BREG(7); + + if (!m_is_34020) { unimpl(op); return; } + + /* src and dst are aligned */ + if (!(src & 0x0f) && !(dst & 0x0f)) + { + while (bits >= 16 && m_icount > 0) + { + TMS34010_WRMEM_WORD(TOBYTE(dst), TMS34010_RDMEM_WORD(TOBYTE(src))); + src += 0x10; + dst += 0x10; + bits -= 0x10; + m_icount -= 2; + } + if (bits != 0 && m_icount > 0) + { + (this->*s_wfield_functions[bits])(dst, (this->*s_rfield_functions[bits])(src)); + dst += bits; + src += bits; + bits = 0; + m_icount -= 2; + } + } + + /* src is aligned, dst is not */ + else if (!(src & 0x0f)) + { + logerror("020:BLMOVE with aligned src and unaligned dst\n"); + } + + /* dst is aligned, src is not */ + else if (!(dst & 0x0f)) + { + logerror("020:BLMOVE with unaligned src and aligned dst\n"); + } + + /* neither are aligned */ + else + { + logerror("020:BLMOVE with completely unaligned src and dst\n"); + } + + /* update the final results */ + BREG(0) = src; + BREG(2) = dst; + BREG(7) = bits; + + /* if we're not done yet, back up the PC */ + if (bits != 0) + m_pc -= 0x10; +} + +void tms340x0_device::cexec_l(UINT16 op) +{ + if (!m_is_34020) { unimpl(op); return; } + logerror("020:cexec_l\n"); +} + +void tms340x0_device::cexec_s(UINT16 op) +{ + if (!m_is_34020) { unimpl(op); return; } + logerror("020:cexec_s\n"); +} + +void tms340x0_device::clip(UINT16 op) +{ + if (!m_is_34020) { unimpl(op); return; } + logerror("020:clip\n"); +} + +void tms340x0_device::cmovcg_a(UINT16 op) +{ + if (!m_is_34020) { unimpl(op); return; } + logerror("020:cmovcg_a\n"); +} + +void tms340x0_device::cmovcg_b(UINT16 op) +{ + if (!m_is_34020) { unimpl(op); return; } + logerror("020:cmovcg_b\n"); +} + +void tms340x0_device::cmovcm_f(UINT16 op) +{ + if (!m_is_34020) { unimpl(op); return; } + logerror("020:cmovcm_f\n"); +} + +void tms340x0_device::cmovcm_b(UINT16 op) +{ + if (!m_is_34020) { unimpl(op); return; } + logerror("020:cmovcm_b\n"); +} + +void tms340x0_device::cmovgc_a(UINT16 op) +{ + if (!m_is_34020) { unimpl(op); return; } + logerror("020:cmovgc_a\n"); +} + +void tms340x0_device::cmovgc_b(UINT16 op) +{ + if (!m_is_34020) { unimpl(op); return; } + logerror("020:cmovgc_b\n"); +} + +void tms340x0_device::cmovgc_a_s(UINT16 op) +{ + if (!m_is_34020) { unimpl(op); return; } + logerror("020:cmovgc_a_s\n"); +} + +void tms340x0_device::cmovgc_b_s(UINT16 op) +{ + if (!m_is_34020) { unimpl(op); return; } + logerror("020:cmovgc_b_s\n"); +} + +void tms340x0_device::cmovmc_f(UINT16 op) +{ + if (!m_is_34020) { unimpl(op); return; } + logerror("020:cmovmc_f\n"); +} + +void tms340x0_device::cmovmc_f_va(UINT16 op) +{ + if (!m_is_34020) { unimpl(op); return; } + logerror("020:cmovmc_f_va\n"); +} + +void tms340x0_device::cmovmc_f_vb(UINT16 op) +{ + if (!m_is_34020) { unimpl(op); return; } + logerror("020:cmovmc_f_vb\n"); +} + +void tms340x0_device::cmovmc_b(UINT16 op) +{ + if (!m_is_34020) { unimpl(op); return; } + logerror("020:cmovmc_b\n"); +} + +#define CMPK(R) \ +{ \ + INT32 r; \ + INT32 *rd = &R##REG(DSTREG(op)); \ + INT32 t = PARAM_K(op); if (!t) t = 32; \ + CLR_NCZV(); \ + r = *rd - t; \ + SET_NZCV_SUB(*rd,t,r); \ + COUNT_CYCLES(1); \ +} +void tms340x0_device::cmp_k_a(UINT16 op) +{ + if (!m_is_34020) { unimpl(op); return; } + CMPK(A); +} +void tms340x0_device::cmp_k_b(UINT16 op) +{ + if (!m_is_34020) { unimpl(op); return; } + CMPK(B); +} + +void tms340x0_device::cvdxyl_a(UINT16 op) +{ + if (!m_is_34020) { unimpl(op); return; } + logerror("020:cvdxyl_a\n"); +} + +void tms340x0_device::cvdxyl_b(UINT16 op) +{ + if (!m_is_34020) { unimpl(op); return; } + logerror("020:cvdxyl_b\n"); +} + +void tms340x0_device::cvmxyl_a(UINT16 op) +{ + if (!m_is_34020) { unimpl(op); return; } + logerror("020:cvmxyl_a\n"); +} + +void tms340x0_device::cvmxyl_b(UINT16 op) +{ + if (!m_is_34020) { unimpl(op); return; } + logerror("020:cvmxyl_b\n"); +} + +void tms340x0_device::cvsxyl_a(UINT16 op) +{ + if (!m_is_34020) { unimpl(op); return; } + logerror("020:cvsxyl_a\n"); +} + +void tms340x0_device::cvsxyl_b(UINT16 op) +{ + if (!m_is_34020) { unimpl(op); return; } + logerror("020:cvsxyl_b\n"); +} + +void tms340x0_device::exgps_a(UINT16 op) +{ + if (!m_is_34020) { unimpl(op); return; } + logerror("020:exgps_a\n"); +} + +void tms340x0_device::exgps_b(UINT16 op) +{ + if (!m_is_34020) { unimpl(op); return; } + logerror("020:exgps_b\n"); +} + +void tms340x0_device::fline(UINT16 op) +{ + if (!m_is_34020) { unimpl(op); return; } + logerror("020:fline\n"); +} + +void tms340x0_device::fpixeq(UINT16 op) +{ + if (!m_is_34020) { unimpl(op); return; } + logerror("020:fpixeq\n"); +} + +void tms340x0_device::fpixne(UINT16 op) +{ + if (!m_is_34020) { unimpl(op); return; } + logerror("020:fpixne\n"); +} + +void tms340x0_device::getps_a(UINT16 op) +{ + if (!m_is_34020) { unimpl(op); return; } + logerror("020:getps_a\n"); +} + +void tms340x0_device::getps_b(UINT16 op) +{ + if (!m_is_34020) { unimpl(op); return; } + logerror("020:getps_b\n"); +} + +void tms340x0_device::idle(UINT16 op) +{ + if (!m_is_34020) { unimpl(op); return; } + logerror("020:idle\n"); +} + +void tms340x0_device::linit(UINT16 op) +{ + if (!m_is_34020) { unimpl(op); return; } + logerror("020:linit\n"); +} + +void tms340x0_device::mwait(UINT16 op) +{ + if (!m_is_34020) { unimpl(op); return; } +} + +void tms340x0_device::pfill_xy(UINT16 op) +{ + if (!m_is_34020) { unimpl(op); return; } + logerror("020:pfill_xy\n"); +} + +void tms340x0_device::pixblt_l_m_l(UINT16 op) +{ + if (!m_is_34020) { unimpl(op); return; } + logerror("020:pixblt_l_m_l\n"); +} + +void tms340x0_device::retm(UINT16 op) +{ + if (!m_is_34020) { unimpl(op); return; } + logerror("020:retm\n"); +} + +#define RMO(R) \ +{ \ + UINT32 res = 0; \ + UINT32 rs = R##REG(SRCREG(op)); \ + INT32 *rd = &R##REG(DSTREG(op)); \ + CLR_Z(); \ + SET_Z_VAL(rs); \ + if (rs) \ + { \ + while (!(rs & 0x00000001)) \ + { \ + res++; \ + rs >>= 1; \ + } \ + } \ + *rd = res; \ + COUNT_CYCLES(1); \ +} + +void tms340x0_device::rmo_a(UINT16 op) { RMO(A); } +void tms340x0_device::rmo_b(UINT16 op) { RMO(B); } + +#define RPIX(R) \ +{ \ + UINT32 v = R##REG(DSTREG(op)); \ + switch (m_pixelshift) \ + { \ + case 0: \ + v = (v & 1) ? 0xffffffff : 0x00000000;\ + COUNT_CYCLES(8); \ + break; \ + case 1: \ + v &= 3; \ + v |= v << 2; \ + v |= v << 4; \ + v |= v << 8; \ + v |= v << 16; \ + COUNT_CYCLES(7); \ + break; \ + case 2: \ + v &= 0x0f; \ + v |= v << 4; \ + v |= v << 8; \ + v |= v << 16; \ + COUNT_CYCLES(6); \ + break; \ + case 3: \ + v &= 0xff; \ + v |= v << 8; \ + v |= v << 16; \ + COUNT_CYCLES(5); \ + break; \ + case 4: \ + v &= 0xffff; \ + v |= v << 16; \ + COUNT_CYCLES(4); \ + break; \ + case 5: \ + COUNT_CYCLES(2); \ + break; \ + } \ + R##REG(DSTREG(op)) = v; \ +} + +void tms340x0_device::rpix_a(UINT16 op) +{ + if (!m_is_34020) { unimpl(op); return; } + RPIX(A); +} + +void tms340x0_device::rpix_b(UINT16 op) +{ + if (!m_is_34020) { unimpl(op); return; } + RPIX(B); +} + +void tms340x0_device::setcdp(UINT16 op) +{ + if (!m_is_34020) { unimpl(op); return; } + logerror("020:setcdp\n"); +} + +void tms340x0_device::setcmp(UINT16 op) +{ + if (!m_is_34020) { unimpl(op); return; } + logerror("020:setcmp\n"); +} + +void tms340x0_device::setcsp(UINT16 op) +{ + if (!m_is_34020) { unimpl(op); return; } + logerror("020:setcsp\n"); +} + +void tms340x0_device::swapf_a(UINT16 op) +{ + if (!m_is_34020) { unimpl(op); return; } + logerror("020:swapf_a\n"); +} + +void tms340x0_device::swapf_b(UINT16 op) +{ + if (!m_is_34020) { unimpl(op); return; } + logerror("020:swapf_b\n"); +} + +void tms340x0_device::tfill_xy(UINT16 op) +{ + if (!m_is_34020) { unimpl(op); return; } + logerror("020:tfill_xy\n"); +} + +void tms340x0_device::trapl(UINT16 op) +{ + if (!m_is_34020) { unimpl(op); return; } + logerror("020:trapl\n"); +} + +void tms340x0_device::vblt_b_l(UINT16 op) +{ + if (!m_is_34020) { unimpl(op); return; } + logerror("020:vblt_b_l\n"); +} + +void tms340x0_device::vfill_l(UINT16 op) +{ + if (!m_is_34020) { unimpl(op); return; } + logerror("020:vfill_l\n"); +} + +void tms340x0_device::vlcol(UINT16 op) +{ + if (!m_is_34020) { unimpl(op); return; } + logerror("020:vlcol\n"); +} diff --git a/src/devices/cpu/tms34010/34010ops.h b/src/devices/cpu/tms34010/34010ops.h new file mode 100644 index 00000000000..6dad233c034 --- /dev/null +++ b/src/devices/cpu/tms34010/34010ops.h @@ -0,0 +1,154 @@ +// license:BSD-3-Clause +// copyright-holders:Alex Pasadyn,Zsolt Vasvari +/*************************************************************************** + + TMS34010: Portable Texas Instruments TMS34010 emulator + + Copyright Alex Pasadyn/Zsolt Vasvari + Parts based on code by Aaron Giles + +***************************************************************************/ + +#pragma once + +#ifndef __34010OPS_H__ +#define __34010OPS_H__ + + + + +/*************************************************************************** + MEMORY I/O MACROS +***************************************************************************/ + +#define TMS34010_RDMEM(A) ((unsigned)m_program->read_byte (A)) +#define TMS34010_RDMEM_WORD(A) ((unsigned)m_program->read_word (A)) +inline UINT32 tms340x0_device::TMS34010_RDMEM_DWORD(offs_t A) +{ + UINT32 result = m_program->read_word(A); + return result | (m_program->read_word(A+2)<<16); +} + +#define TMS34010_WRMEM(A,V) (m_program->write_byte(A,V)) +#define TMS34010_WRMEM_WORD(A,V) (m_program->write_word(A,V)) +inline void tms340x0_device::TMS34010_WRMEM_DWORD(offs_t A, UINT32 V) +{ + m_program->write_word(A,V); + m_program->write_word(A+2,V>>16); +} + + + +/* IO registers accessor */ +#define IOREG(reg) (m_IOregs[reg]) +#define SMART_IOREG(reg) (m_IOregs[m_is_34020 ? (int)REG020_##reg : (int)REG_##reg]) +#define PBH() (IOREG(REG_CONTROL) & 0x0100) +#define PBV() (IOREG(REG_CONTROL) & 0x0200) + + + +/*************************************************************************** + FIELD WRITE MACROS +***************************************************************************/ + +#define WFIELDMAC(MASK,MAX) \ + UINT32 shift = offset & 0x0f; \ + UINT32 masked_data = data & (MASK); \ + UINT32 old; \ + \ + offset = TOBYTE(offset & 0xfffffff0); \ + \ + if (shift >= MAX) \ + { \ + old = (UINT32)TMS34010_RDMEM_DWORD(offset) & ~((MASK) << shift); \ + TMS34010_WRMEM_DWORD(offset, (masked_data << shift) | old); \ + } \ + else \ + { \ + old = (UINT32)TMS34010_RDMEM_WORD(offset) & ~((MASK) << shift); \ + TMS34010_WRMEM_WORD(offset, ((masked_data & (MASK)) << shift) | old); \ + } + +#define WFIELDMAC_BIG(MASK,MAX) \ + UINT32 shift = offset & 0x0f; \ + UINT32 masked_data = data & (MASK); \ + UINT32 old; \ + \ + offset = TOBYTE(offset & 0xfffffff0); \ + \ + old = (UINT32)TMS34010_RDMEM_DWORD(offset) & ~(UINT32)((MASK) << shift); \ + TMS34010_WRMEM_DWORD(offset, (UINT32)(masked_data << shift) | old); \ + if (shift >= MAX) \ + { \ + shift = 32 - shift; \ + old = (UINT32)TMS34010_RDMEM_WORD(offset + 4) & ~((MASK) >> shift); \ + TMS34010_WRMEM_WORD(offset, (masked_data >> shift) | old); \ + } + +#define WFIELDMAC_8() \ + if (offset & 0x07) \ + { \ + WFIELDMAC(0xff,9); \ + } \ + else \ + TMS34010_WRMEM(TOBYTE(offset), data); + +#define RFIELDMAC_8() \ + if (offset & 0x07) \ + { \ + RFIELDMAC(0xff,9); \ + } \ + else \ + return TMS34010_RDMEM(TOBYTE(offset)); + +#define WFIELDMAC_32() \ + if (offset & 0x0f) \ + { \ + UINT32 shift = offset&0x0f; \ + UINT32 old; \ + UINT32 hiword; \ + offset &= 0xfffffff0; \ + old = ((UINT32) TMS34010_RDMEM_DWORD (TOBYTE(offset ))&(0xffffffff>>(0x20-shift))); \ + hiword = ((UINT32) TMS34010_RDMEM_DWORD (TOBYTE(offset+0x20))&(0xffffffff<>(0x20-shift))|hiword); \ + } \ + else \ + TMS34010_WRMEM_DWORD(TOBYTE(offset),data); + + +/*************************************************************************** + FIELD READ MACROS +***************************************************************************/ + +#define RFIELDMAC(MASK,MAX) \ + UINT32 shift = offset & 0x0f; \ + offset = TOBYTE(offset & 0xfffffff0); \ + \ + if (shift >= MAX) \ + ret = (TMS34010_RDMEM_DWORD(offset) >> shift) & (MASK); \ + else \ + ret = (TMS34010_RDMEM_WORD(offset) >> shift) & (MASK); + +#define RFIELDMAC_BIG(MASK,MAX) \ + UINT32 shift = offset & 0x0f; \ + offset = TOBYTE(offset & 0xfffffff0); \ + \ + ret = (UINT32)TMS34010_RDMEM_DWORD(offset) >> shift; \ + if (shift >= MAX) \ + ret |= (TMS34010_RDMEM_WORD(offset + 4) << (32 - shift)); \ + ret &= MASK; + +#define RFIELDMAC_32() \ + if (offset&0x0f) \ + { \ + UINT32 shift = offset&0x0f; \ + offset &= 0xfffffff0; \ + return (((UINT32)TMS34010_RDMEM_DWORD (TOBYTE(offset ))>> shift) | \ + (TMS34010_RDMEM_DWORD (TOBYTE(offset+0x20))<<(0x20-shift)));\ + } \ + else \ + return TMS34010_RDMEM_DWORD(TOBYTE(offset)); + + +#endif /* __34010OPS_H__ */ diff --git a/src/devices/cpu/tms34010/34010tbl.c b/src/devices/cpu/tms34010/34010tbl.c new file mode 100644 index 00000000000..2cef83dcb9c --- /dev/null +++ b/src/devices/cpu/tms34010/34010tbl.c @@ -0,0 +1,782 @@ +// license:BSD-3-Clause +// copyright-holders:Alex Pasadyn,Zsolt Vasvari +/*** TMS34010: Portable TMS34010 emulator *********************************** + + Copyright Alex Pasadyn/Zsolt Vasvari + + Opcode Table + +*****************************************************************************/ + +/* Opcode Table */ +const tms340x0_device::opcode_func tms340x0_device::s_opcode_table[65536 >> 4] = +{ + /* 0x0000 0x0010 0x0020 0x0030 ... 0x00f0 */ + &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::rev_a, &tms340x0_device::rev_b, &tms340x0_device::idle, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, + &tms340x0_device::mwait, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::blmove, + /* 0x0100 */ + &tms340x0_device::emu, &tms340x0_device::unimpl, &tms340x0_device::exgpc_a, &tms340x0_device::exgpc_b, &tms340x0_device::getpc_a, &tms340x0_device::getpc_b, &tms340x0_device::jump_a, &tms340x0_device::jump_b, + &tms340x0_device::getst_a, &tms340x0_device::getst_b, &tms340x0_device::putst_a, &tms340x0_device::putst_b, &tms340x0_device::popst, &tms340x0_device::unimpl, &tms340x0_device::pushst, &tms340x0_device::unimpl, + /* 0x0200 */ + &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::setcsp, &tms340x0_device::unimpl, &tms340x0_device::setcdp, + &tms340x0_device::rpix_a, &tms340x0_device::rpix_b, &tms340x0_device::exgps_a, &tms340x0_device::exgps_b, &tms340x0_device::getps_a, &tms340x0_device::getps_b, &tms340x0_device::unimpl, &tms340x0_device::setcmp, + /* 0x0300 */ + &tms340x0_device::nop, &tms340x0_device::unimpl, &tms340x0_device::clrc, &tms340x0_device::unimpl, &tms340x0_device::movb_aa, &tms340x0_device::unimpl, &tms340x0_device::dint, &tms340x0_device::unimpl, + &tms340x0_device::abs_a, &tms340x0_device::abs_b, &tms340x0_device::neg_a, &tms340x0_device::neg_b, &tms340x0_device::negb_a, &tms340x0_device::negb_b, &tms340x0_device::not_a, &tms340x0_device::not_b, + /* 0x0400 */ + &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, + &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, + /* 0x0500 */ + &tms340x0_device::sext0_a, &tms340x0_device::sext0_b, &tms340x0_device::zext0_a, &tms340x0_device::zext0_b, &tms340x0_device::setf0, &tms340x0_device::setf0, &tms340x0_device::setf0, &tms340x0_device::setf0, + &tms340x0_device::move0_ra_a, &tms340x0_device::move0_ra_b, &tms340x0_device::move0_ar_a, &tms340x0_device::move0_ar_b, &tms340x0_device::move0_aa, &tms340x0_device::unimpl, &tms340x0_device::movb_ra_a, &tms340x0_device::movb_ra_b, + /* 0x0600 */ + &tms340x0_device::cexec_l, &tms340x0_device::unimpl, &tms340x0_device::cmovgc_a, &tms340x0_device::cmovgc_b, &tms340x0_device::cmovgc_a_s, &tms340x0_device::cmovgc_b_s, &tms340x0_device::cmovcg_a, &tms340x0_device::cmovcg_b, + &tms340x0_device::cmovmc_f, &tms340x0_device::cmovmc_f, &tms340x0_device::cmovcm_f, &tms340x0_device::cmovcm_f, &tms340x0_device::cmovcm_b, &tms340x0_device::cmovcm_b, &tms340x0_device::cmovmc_f_va,&tms340x0_device::cmovmc_f_vb, + /* 0x0700 */ + &tms340x0_device::sext1_a, &tms340x0_device::sext1_b, &tms340x0_device::zext1_a, &tms340x0_device::zext1_b, &tms340x0_device::setf1, &tms340x0_device::setf1, &tms340x0_device::setf1, &tms340x0_device::setf1, + &tms340x0_device::move1_ra_a, &tms340x0_device::move1_ra_b, &tms340x0_device::move1_ar_a, &tms340x0_device::move1_ar_b, &tms340x0_device::move1_aa, &tms340x0_device::unimpl, &tms340x0_device::movb_ar_a, &tms340x0_device::movb_ar_b, + /* 0x0800 */ + &tms340x0_device::trapl, &tms340x0_device::unimpl, &tms340x0_device::cmovmc_b, &tms340x0_device::cmovmc_b, &tms340x0_device::unimpl, &tms340x0_device::vblt_b_l, &tms340x0_device::retm, &tms340x0_device::unimpl, + &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::clip, + /* 0x0900 */ + &tms340x0_device::trap, &tms340x0_device::trap, &tms340x0_device::call_a, &tms340x0_device::call_b, &tms340x0_device::reti, &tms340x0_device::unimpl, &tms340x0_device::rets, &tms340x0_device::rets, + &tms340x0_device::mmtm_a, &tms340x0_device::mmtm_b, &tms340x0_device::mmfm_a, &tms340x0_device::mmfm_b, &tms340x0_device::movi_w_a, &tms340x0_device::movi_w_b, &tms340x0_device::movi_l_a, &tms340x0_device::movi_l_b, + /* 0x0a00 */ + &tms340x0_device::vlcol, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::pfill_xy, &tms340x0_device::unimpl, &tms340x0_device::vfill_l, &tms340x0_device::cvmxyl_a, &tms340x0_device::cvmxyl_b, + &tms340x0_device::cvdxyl_a, &tms340x0_device::cvdxyl_b, &tms340x0_device::unimpl, &tms340x0_device::fpixeq, &tms340x0_device::unimpl, &tms340x0_device::fpixne, &tms340x0_device::unimpl, &tms340x0_device::unimpl, + /* 0x0b00 */ + &tms340x0_device::addi_w_a, &tms340x0_device::addi_w_b, &tms340x0_device::addi_l_a, &tms340x0_device::addi_l_b, &tms340x0_device::cmpi_w_a, &tms340x0_device::cmpi_w_b, &tms340x0_device::cmpi_l_a, &tms340x0_device::cmpi_l_b, + &tms340x0_device::andi_a, &tms340x0_device::andi_b, &tms340x0_device::ori_a, &tms340x0_device::ori_b, &tms340x0_device::xori_a, &tms340x0_device::xori_b, &tms340x0_device::subi_w_a, &tms340x0_device::subi_w_b, + /* 0x0c00 */ + &tms340x0_device::addxyi_a, &tms340x0_device::addxyi_b, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::linit, &tms340x0_device::unimpl, &tms340x0_device::unimpl, + &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, + /* 0x0d00 */ + &tms340x0_device::subi_l_a, &tms340x0_device::subi_l_b, &tms340x0_device::unimpl, &tms340x0_device::callr, &tms340x0_device::unimpl, &tms340x0_device::calla, &tms340x0_device::eint, &tms340x0_device::unimpl, + &tms340x0_device::dsj_a, &tms340x0_device::dsj_b, &tms340x0_device::dsjeq_a, &tms340x0_device::dsjeq_b, &tms340x0_device::dsjne_a, &tms340x0_device::dsjne_b, &tms340x0_device::setc, &tms340x0_device::unimpl, + /* 0x0e00 */ + &tms340x0_device::unimpl, &tms340x0_device::pixblt_l_m_l,&tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, + &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::tfill_xy, + /* 0x0f00 */ + &tms340x0_device::pixblt_l_l, &tms340x0_device::unimpl, &tms340x0_device::pixblt_l_xy,&tms340x0_device::unimpl, &tms340x0_device::pixblt_xy_l,&tms340x0_device::unimpl, &tms340x0_device::pixblt_xy_xy,&tms340x0_device::unimpl, + &tms340x0_device::pixblt_b_l, &tms340x0_device::unimpl, &tms340x0_device::pixblt_b_xy,&tms340x0_device::unimpl, &tms340x0_device::fill_l, &tms340x0_device::unimpl, &tms340x0_device::fill_xy, &tms340x0_device::unimpl, + /* 0x1000 */ + &tms340x0_device::addk_a, &tms340x0_device::addk_b, &tms340x0_device::addk_a, &tms340x0_device::addk_b, &tms340x0_device::addk_a, &tms340x0_device::addk_b, &tms340x0_device::addk_a, &tms340x0_device::addk_b, + &tms340x0_device::addk_a, &tms340x0_device::addk_b, &tms340x0_device::addk_a, &tms340x0_device::addk_b, &tms340x0_device::addk_a, &tms340x0_device::addk_b, &tms340x0_device::addk_a, &tms340x0_device::addk_b, + /* 0x1100 */ + &tms340x0_device::addk_a, &tms340x0_device::addk_b, &tms340x0_device::addk_a, &tms340x0_device::addk_b, &tms340x0_device::addk_a, &tms340x0_device::addk_b, &tms340x0_device::addk_a, &tms340x0_device::addk_b, + &tms340x0_device::addk_a, &tms340x0_device::addk_b, &tms340x0_device::addk_a, &tms340x0_device::addk_b, &tms340x0_device::addk_a, &tms340x0_device::addk_b, &tms340x0_device::addk_a, &tms340x0_device::addk_b, + /* 0x1200 */ + &tms340x0_device::addk_a, &tms340x0_device::addk_b, &tms340x0_device::addk_a, &tms340x0_device::addk_b, &tms340x0_device::addk_a, &tms340x0_device::addk_b, &tms340x0_device::addk_a, &tms340x0_device::addk_b, + &tms340x0_device::addk_a, &tms340x0_device::addk_b, &tms340x0_device::addk_a, &tms340x0_device::addk_b, &tms340x0_device::addk_a, &tms340x0_device::addk_b, &tms340x0_device::addk_a, &tms340x0_device::addk_b, + /* 0x1300 */ + &tms340x0_device::addk_a, &tms340x0_device::addk_b, &tms340x0_device::addk_a, &tms340x0_device::addk_b, &tms340x0_device::addk_a, &tms340x0_device::addk_b, &tms340x0_device::addk_a, &tms340x0_device::addk_b, + &tms340x0_device::addk_a, &tms340x0_device::addk_b, &tms340x0_device::addk_a, &tms340x0_device::addk_b, &tms340x0_device::addk_a, &tms340x0_device::addk_b, &tms340x0_device::addk_a, &tms340x0_device::addk_b, + /* 0x1400 */ + &tms340x0_device::subk_a, &tms340x0_device::subk_b, &tms340x0_device::subk_a, &tms340x0_device::subk_b, &tms340x0_device::subk_a, &tms340x0_device::subk_b, &tms340x0_device::subk_a, &tms340x0_device::subk_b, + &tms340x0_device::subk_a, &tms340x0_device::subk_b, &tms340x0_device::subk_a, &tms340x0_device::subk_b, &tms340x0_device::subk_a, &tms340x0_device::subk_b, &tms340x0_device::subk_a, &tms340x0_device::subk_b, + /* 0x1500 */ + &tms340x0_device::subk_a, &tms340x0_device::subk_b, &tms340x0_device::subk_a, &tms340x0_device::subk_b, &tms340x0_device::subk_a, &tms340x0_device::subk_b, &tms340x0_device::subk_a, &tms340x0_device::subk_b, + &tms340x0_device::subk_a, &tms340x0_device::subk_b, &tms340x0_device::subk_a, &tms340x0_device::subk_b, &tms340x0_device::subk_a, &tms340x0_device::subk_b, &tms340x0_device::subk_a, &tms340x0_device::subk_b, + /* 0x1600 */ + &tms340x0_device::subk_a, &tms340x0_device::subk_b, &tms340x0_device::subk_a, &tms340x0_device::subk_b, &tms340x0_device::subk_a, &tms340x0_device::subk_b, &tms340x0_device::subk_a, &tms340x0_device::subk_b, + &tms340x0_device::subk_a, &tms340x0_device::subk_b, &tms340x0_device::subk_a, &tms340x0_device::subk_b, &tms340x0_device::subk_a, &tms340x0_device::subk_b, &tms340x0_device::subk_a, &tms340x0_device::subk_b, + /* 0x1700 */ + &tms340x0_device::subk_a, &tms340x0_device::subk_b, &tms340x0_device::subk_a, &tms340x0_device::subk_b, &tms340x0_device::subk_a, &tms340x0_device::subk_b, &tms340x0_device::subk_a, &tms340x0_device::subk_b, + &tms340x0_device::subk_a, &tms340x0_device::subk_b, &tms340x0_device::subk_a, &tms340x0_device::subk_b, &tms340x0_device::subk_a, &tms340x0_device::subk_b, &tms340x0_device::subk_a, &tms340x0_device::subk_b, + /* 0x1800 */ + &tms340x0_device::movk_a, &tms340x0_device::movk_b, &tms340x0_device::movk_a, &tms340x0_device::movk_b, &tms340x0_device::movk_a, &tms340x0_device::movk_b, &tms340x0_device::movk_a, &tms340x0_device::movk_b, + &tms340x0_device::movk_a, &tms340x0_device::movk_b, &tms340x0_device::movk_a, &tms340x0_device::movk_b, &tms340x0_device::movk_a, &tms340x0_device::movk_b, &tms340x0_device::movk_a, &tms340x0_device::movk_b, + /* 0x1900 */ + &tms340x0_device::movk_a, &tms340x0_device::movk_b, &tms340x0_device::movk_a, &tms340x0_device::movk_b, &tms340x0_device::movk_a, &tms340x0_device::movk_b, &tms340x0_device::movk_a, &tms340x0_device::movk_b, + &tms340x0_device::movk_a, &tms340x0_device::movk_b, &tms340x0_device::movk_a, &tms340x0_device::movk_b, &tms340x0_device::movk_a, &tms340x0_device::movk_b, &tms340x0_device::movk_a, &tms340x0_device::movk_b, + /* 0x1a00 */ + &tms340x0_device::movk_a, &tms340x0_device::movk_b, &tms340x0_device::movk_a, &tms340x0_device::movk_b, &tms340x0_device::movk_a, &tms340x0_device::movk_b, &tms340x0_device::movk_a, &tms340x0_device::movk_b, + &tms340x0_device::movk_a, &tms340x0_device::movk_b, &tms340x0_device::movk_a, &tms340x0_device::movk_b, &tms340x0_device::movk_a, &tms340x0_device::movk_b, &tms340x0_device::movk_a, &tms340x0_device::movk_b, + /* 0x1b00 */ + &tms340x0_device::movk_a, &tms340x0_device::movk_b, &tms340x0_device::movk_a, &tms340x0_device::movk_b, &tms340x0_device::movk_a, &tms340x0_device::movk_b, &tms340x0_device::movk_a, &tms340x0_device::movk_b, + &tms340x0_device::movk_a, &tms340x0_device::movk_b, &tms340x0_device::movk_a, &tms340x0_device::movk_b, &tms340x0_device::movk_a, &tms340x0_device::movk_b, &tms340x0_device::movk_a, &tms340x0_device::movk_b, + /* 0x1c00 */ + &tms340x0_device::btst_k_a, &tms340x0_device::btst_k_b, &tms340x0_device::btst_k_a, &tms340x0_device::btst_k_b, &tms340x0_device::btst_k_a, &tms340x0_device::btst_k_b, &tms340x0_device::btst_k_a, &tms340x0_device::btst_k_b, + &tms340x0_device::btst_k_a, &tms340x0_device::btst_k_b, &tms340x0_device::btst_k_a, &tms340x0_device::btst_k_b, &tms340x0_device::btst_k_a, &tms340x0_device::btst_k_b, &tms340x0_device::btst_k_a, &tms340x0_device::btst_k_b, + /* 0x1d00 */ + &tms340x0_device::btst_k_a, &tms340x0_device::btst_k_b, &tms340x0_device::btst_k_a, &tms340x0_device::btst_k_b, &tms340x0_device::btst_k_a, &tms340x0_device::btst_k_b, &tms340x0_device::btst_k_a, &tms340x0_device::btst_k_b, + &tms340x0_device::btst_k_a, &tms340x0_device::btst_k_b, &tms340x0_device::btst_k_a, &tms340x0_device::btst_k_b, &tms340x0_device::btst_k_a, &tms340x0_device::btst_k_b, &tms340x0_device::btst_k_a, &tms340x0_device::btst_k_b, + /* 0x1e00 */ + &tms340x0_device::btst_k_a, &tms340x0_device::btst_k_b, &tms340x0_device::btst_k_a, &tms340x0_device::btst_k_b, &tms340x0_device::btst_k_a, &tms340x0_device::btst_k_b, &tms340x0_device::btst_k_a, &tms340x0_device::btst_k_b, + &tms340x0_device::btst_k_a, &tms340x0_device::btst_k_b, &tms340x0_device::btst_k_a, &tms340x0_device::btst_k_b, &tms340x0_device::btst_k_a, &tms340x0_device::btst_k_b, &tms340x0_device::btst_k_a, &tms340x0_device::btst_k_b, + /* 0x1f00 */ + &tms340x0_device::btst_k_a, &tms340x0_device::btst_k_b, &tms340x0_device::btst_k_a, &tms340x0_device::btst_k_b, &tms340x0_device::btst_k_a, &tms340x0_device::btst_k_b, &tms340x0_device::btst_k_a, &tms340x0_device::btst_k_b, + &tms340x0_device::btst_k_a, &tms340x0_device::btst_k_b, &tms340x0_device::btst_k_a, &tms340x0_device::btst_k_b, &tms340x0_device::btst_k_a, &tms340x0_device::btst_k_b, &tms340x0_device::btst_k_a, &tms340x0_device::btst_k_b, + /* 0x2000 */ + &tms340x0_device::sla_k_a, &tms340x0_device::sla_k_b, &tms340x0_device::sla_k_a, &tms340x0_device::sla_k_b, &tms340x0_device::sla_k_a, &tms340x0_device::sla_k_b, &tms340x0_device::sla_k_a, &tms340x0_device::sla_k_b, + &tms340x0_device::sla_k_a, &tms340x0_device::sla_k_b, &tms340x0_device::sla_k_a, &tms340x0_device::sla_k_b, &tms340x0_device::sla_k_a, &tms340x0_device::sla_k_b, &tms340x0_device::sla_k_a, &tms340x0_device::sla_k_b, + /* 0x2100 */ + &tms340x0_device::sla_k_a, &tms340x0_device::sla_k_b, &tms340x0_device::sla_k_a, &tms340x0_device::sla_k_b, &tms340x0_device::sla_k_a, &tms340x0_device::sla_k_b, &tms340x0_device::sla_k_a, &tms340x0_device::sla_k_b, + &tms340x0_device::sla_k_a, &tms340x0_device::sla_k_b, &tms340x0_device::sla_k_a, &tms340x0_device::sla_k_b, &tms340x0_device::sla_k_a, &tms340x0_device::sla_k_b, &tms340x0_device::sla_k_a, &tms340x0_device::sla_k_b, + /* 0x2200 */ + &tms340x0_device::sla_k_a, &tms340x0_device::sla_k_b, &tms340x0_device::sla_k_a, &tms340x0_device::sla_k_b, &tms340x0_device::sla_k_a, &tms340x0_device::sla_k_b, &tms340x0_device::sla_k_a, &tms340x0_device::sla_k_b, + &tms340x0_device::sla_k_a, &tms340x0_device::sla_k_b, &tms340x0_device::sla_k_a, &tms340x0_device::sla_k_b, &tms340x0_device::sla_k_a, &tms340x0_device::sla_k_b, &tms340x0_device::sla_k_a, &tms340x0_device::sla_k_b, + /* 0x2300 */ + &tms340x0_device::sla_k_a, &tms340x0_device::sla_k_b, &tms340x0_device::sla_k_a, &tms340x0_device::sla_k_b, &tms340x0_device::sla_k_a, &tms340x0_device::sla_k_b, &tms340x0_device::sla_k_a, &tms340x0_device::sla_k_b, + &tms340x0_device::sla_k_a, &tms340x0_device::sla_k_b, &tms340x0_device::sla_k_a, &tms340x0_device::sla_k_b, &tms340x0_device::sla_k_a, &tms340x0_device::sla_k_b, &tms340x0_device::sla_k_a, &tms340x0_device::sla_k_b, + /* 0x2400 */ + &tms340x0_device::sll_k_a, &tms340x0_device::sll_k_b, &tms340x0_device::sll_k_a, &tms340x0_device::sll_k_b, &tms340x0_device::sll_k_a, &tms340x0_device::sll_k_b, &tms340x0_device::sll_k_a, &tms340x0_device::sll_k_b, + &tms340x0_device::sll_k_a, &tms340x0_device::sll_k_b, &tms340x0_device::sll_k_a, &tms340x0_device::sll_k_b, &tms340x0_device::sll_k_a, &tms340x0_device::sll_k_b, &tms340x0_device::sll_k_a, &tms340x0_device::sll_k_b, + /* 0x2500 */ + &tms340x0_device::sll_k_a, &tms340x0_device::sll_k_b, &tms340x0_device::sll_k_a, &tms340x0_device::sll_k_b, &tms340x0_device::sll_k_a, &tms340x0_device::sll_k_b, &tms340x0_device::sll_k_a, &tms340x0_device::sll_k_b, + &tms340x0_device::sll_k_a, &tms340x0_device::sll_k_b, &tms340x0_device::sll_k_a, &tms340x0_device::sll_k_b, &tms340x0_device::sll_k_a, &tms340x0_device::sll_k_b, &tms340x0_device::sll_k_a, &tms340x0_device::sll_k_b, + /* 0x2600 */ + &tms340x0_device::sll_k_a, &tms340x0_device::sll_k_b, &tms340x0_device::sll_k_a, &tms340x0_device::sll_k_b, &tms340x0_device::sll_k_a, &tms340x0_device::sll_k_b, &tms340x0_device::sll_k_a, &tms340x0_device::sll_k_b, + &tms340x0_device::sll_k_a, &tms340x0_device::sll_k_b, &tms340x0_device::sll_k_a, &tms340x0_device::sll_k_b, &tms340x0_device::sll_k_a, &tms340x0_device::sll_k_b, &tms340x0_device::sll_k_a, &tms340x0_device::sll_k_b, + /* 0x2700 */ + &tms340x0_device::sll_k_a, &tms340x0_device::sll_k_b, &tms340x0_device::sll_k_a, &tms340x0_device::sll_k_b, &tms340x0_device::sll_k_a, &tms340x0_device::sll_k_b, &tms340x0_device::sll_k_a, &tms340x0_device::sll_k_b, + &tms340x0_device::sll_k_a, &tms340x0_device::sll_k_b, &tms340x0_device::sll_k_a, &tms340x0_device::sll_k_b, &tms340x0_device::sll_k_a, &tms340x0_device::sll_k_b, &tms340x0_device::sll_k_a, &tms340x0_device::sll_k_b, + /* 0x2800 */ + &tms340x0_device::sra_k_a, &tms340x0_device::sra_k_b, &tms340x0_device::sra_k_a, &tms340x0_device::sra_k_b, &tms340x0_device::sra_k_a, &tms340x0_device::sra_k_b, &tms340x0_device::sra_k_a, &tms340x0_device::sra_k_b, + &tms340x0_device::sra_k_a, &tms340x0_device::sra_k_b, &tms340x0_device::sra_k_a, &tms340x0_device::sra_k_b, &tms340x0_device::sra_k_a, &tms340x0_device::sra_k_b, &tms340x0_device::sra_k_a, &tms340x0_device::sra_k_b, + /* 0x2900 */ + &tms340x0_device::sra_k_a, &tms340x0_device::sra_k_b, &tms340x0_device::sra_k_a, &tms340x0_device::sra_k_b, &tms340x0_device::sra_k_a, &tms340x0_device::sra_k_b, &tms340x0_device::sra_k_a, &tms340x0_device::sra_k_b, + &tms340x0_device::sra_k_a, &tms340x0_device::sra_k_b, &tms340x0_device::sra_k_a, &tms340x0_device::sra_k_b, &tms340x0_device::sra_k_a, &tms340x0_device::sra_k_b, &tms340x0_device::sra_k_a, &tms340x0_device::sra_k_b, + /* 0x2a00 */ + &tms340x0_device::sra_k_a, &tms340x0_device::sra_k_b, &tms340x0_device::sra_k_a, &tms340x0_device::sra_k_b, &tms340x0_device::sra_k_a, &tms340x0_device::sra_k_b, &tms340x0_device::sra_k_a, &tms340x0_device::sra_k_b, + &tms340x0_device::sra_k_a, &tms340x0_device::sra_k_b, &tms340x0_device::sra_k_a, &tms340x0_device::sra_k_b, &tms340x0_device::sra_k_a, &tms340x0_device::sra_k_b, &tms340x0_device::sra_k_a, &tms340x0_device::sra_k_b, + /* 0x2b00 */ + &tms340x0_device::sra_k_a, &tms340x0_device::sra_k_b, &tms340x0_device::sra_k_a, &tms340x0_device::sra_k_b, &tms340x0_device::sra_k_a, &tms340x0_device::sra_k_b, &tms340x0_device::sra_k_a, &tms340x0_device::sra_k_b, + &tms340x0_device::sra_k_a, &tms340x0_device::sra_k_b, &tms340x0_device::sra_k_a, &tms340x0_device::sra_k_b, &tms340x0_device::sra_k_a, &tms340x0_device::sra_k_b, &tms340x0_device::sra_k_a, &tms340x0_device::sra_k_b, + /* 0x2c00 */ + &tms340x0_device::srl_k_a, &tms340x0_device::srl_k_b, &tms340x0_device::srl_k_a, &tms340x0_device::srl_k_b, &tms340x0_device::srl_k_a, &tms340x0_device::srl_k_b, &tms340x0_device::srl_k_a, &tms340x0_device::srl_k_b, + &tms340x0_device::srl_k_a, &tms340x0_device::srl_k_b, &tms340x0_device::srl_k_a, &tms340x0_device::srl_k_b, &tms340x0_device::srl_k_a, &tms340x0_device::srl_k_b, &tms340x0_device::srl_k_a, &tms340x0_device::srl_k_b, + /* 0x2d00 */ + &tms340x0_device::srl_k_a, &tms340x0_device::srl_k_b, &tms340x0_device::srl_k_a, &tms340x0_device::srl_k_b, &tms340x0_device::srl_k_a, &tms340x0_device::srl_k_b, &tms340x0_device::srl_k_a, &tms340x0_device::srl_k_b, + &tms340x0_device::srl_k_a, &tms340x0_device::srl_k_b, &tms340x0_device::srl_k_a, &tms340x0_device::srl_k_b, &tms340x0_device::srl_k_a, &tms340x0_device::srl_k_b, &tms340x0_device::srl_k_a, &tms340x0_device::srl_k_b, + /* 0x2e00 */ + &tms340x0_device::srl_k_a, &tms340x0_device::srl_k_b, &tms340x0_device::srl_k_a, &tms340x0_device::srl_k_b, &tms340x0_device::srl_k_a, &tms340x0_device::srl_k_b, &tms340x0_device::srl_k_a, &tms340x0_device::srl_k_b, + &tms340x0_device::srl_k_a, &tms340x0_device::srl_k_b, &tms340x0_device::srl_k_a, &tms340x0_device::srl_k_b, &tms340x0_device::srl_k_a, &tms340x0_device::srl_k_b, &tms340x0_device::srl_k_a, &tms340x0_device::srl_k_b, + /* 0x2f00 */ + &tms340x0_device::srl_k_a, &tms340x0_device::srl_k_b, &tms340x0_device::srl_k_a, &tms340x0_device::srl_k_b, &tms340x0_device::srl_k_a, &tms340x0_device::srl_k_b, &tms340x0_device::srl_k_a, &tms340x0_device::srl_k_b, + &tms340x0_device::srl_k_a, &tms340x0_device::srl_k_b, &tms340x0_device::srl_k_a, &tms340x0_device::srl_k_b, &tms340x0_device::srl_k_a, &tms340x0_device::srl_k_b, &tms340x0_device::srl_k_a, &tms340x0_device::srl_k_b, + /* 0x3000 */ + &tms340x0_device::rl_k_a, &tms340x0_device::rl_k_b, &tms340x0_device::rl_k_a, &tms340x0_device::rl_k_b, &tms340x0_device::rl_k_a, &tms340x0_device::rl_k_b, &tms340x0_device::rl_k_a, &tms340x0_device::rl_k_b, + &tms340x0_device::rl_k_a, &tms340x0_device::rl_k_b, &tms340x0_device::rl_k_a, &tms340x0_device::rl_k_b, &tms340x0_device::rl_k_a, &tms340x0_device::rl_k_b, &tms340x0_device::rl_k_a, &tms340x0_device::rl_k_b, + /* 0x3100 */ + &tms340x0_device::rl_k_a, &tms340x0_device::rl_k_b, &tms340x0_device::rl_k_a, &tms340x0_device::rl_k_b, &tms340x0_device::rl_k_a, &tms340x0_device::rl_k_b, &tms340x0_device::rl_k_a, &tms340x0_device::rl_k_b, + &tms340x0_device::rl_k_a, &tms340x0_device::rl_k_b, &tms340x0_device::rl_k_a, &tms340x0_device::rl_k_b, &tms340x0_device::rl_k_a, &tms340x0_device::rl_k_b, &tms340x0_device::rl_k_a, &tms340x0_device::rl_k_b, + /* 0x3200 */ + &tms340x0_device::rl_k_a, &tms340x0_device::rl_k_b, &tms340x0_device::rl_k_a, &tms340x0_device::rl_k_b, &tms340x0_device::rl_k_a, &tms340x0_device::rl_k_b, &tms340x0_device::rl_k_a, &tms340x0_device::rl_k_b, + &tms340x0_device::rl_k_a, &tms340x0_device::rl_k_b, &tms340x0_device::rl_k_a, &tms340x0_device::rl_k_b, &tms340x0_device::rl_k_a, &tms340x0_device::rl_k_b, &tms340x0_device::rl_k_a, &tms340x0_device::rl_k_b, + /* 0x3300 */ + &tms340x0_device::rl_k_a, &tms340x0_device::rl_k_b, &tms340x0_device::rl_k_a, &tms340x0_device::rl_k_b, &tms340x0_device::rl_k_a, &tms340x0_device::rl_k_b, &tms340x0_device::rl_k_a, &tms340x0_device::rl_k_b, + &tms340x0_device::rl_k_a, &tms340x0_device::rl_k_b, &tms340x0_device::rl_k_a, &tms340x0_device::rl_k_b, &tms340x0_device::rl_k_a, &tms340x0_device::rl_k_b, &tms340x0_device::rl_k_a, &tms340x0_device::rl_k_b, + /* 0x3400 */ + &tms340x0_device::cmp_k_a, &tms340x0_device::cmp_k_b, &tms340x0_device::cmp_k_a, &tms340x0_device::cmp_k_b, &tms340x0_device::cmp_k_a, &tms340x0_device::cmp_k_b, &tms340x0_device::cmp_k_a, &tms340x0_device::cmp_k_b, + &tms340x0_device::cmp_k_a, &tms340x0_device::cmp_k_b, &tms340x0_device::cmp_k_a, &tms340x0_device::cmp_k_b, &tms340x0_device::cmp_k_a, &tms340x0_device::cmp_k_b, &tms340x0_device::cmp_k_a, &tms340x0_device::cmp_k_b, + /* 0x3500 */ + &tms340x0_device::cmp_k_a, &tms340x0_device::cmp_k_b, &tms340x0_device::cmp_k_a, &tms340x0_device::cmp_k_b, &tms340x0_device::cmp_k_a, &tms340x0_device::cmp_k_b, &tms340x0_device::cmp_k_a, &tms340x0_device::cmp_k_b, + &tms340x0_device::cmp_k_a, &tms340x0_device::cmp_k_b, &tms340x0_device::cmp_k_a, &tms340x0_device::cmp_k_b, &tms340x0_device::cmp_k_a, &tms340x0_device::cmp_k_b, &tms340x0_device::cmp_k_a, &tms340x0_device::cmp_k_b, + /* 0x3600 */ + &tms340x0_device::cmp_k_a, &tms340x0_device::cmp_k_b, &tms340x0_device::cmp_k_a, &tms340x0_device::cmp_k_b, &tms340x0_device::cmp_k_a, &tms340x0_device::cmp_k_b, &tms340x0_device::cmp_k_a, &tms340x0_device::cmp_k_b, + &tms340x0_device::cmp_k_a, &tms340x0_device::cmp_k_b, &tms340x0_device::cmp_k_a, &tms340x0_device::cmp_k_b, &tms340x0_device::cmp_k_a, &tms340x0_device::cmp_k_b, &tms340x0_device::cmp_k_a, &tms340x0_device::cmp_k_b, + /* 0x3700 */ + &tms340x0_device::cmp_k_a, &tms340x0_device::cmp_k_b, &tms340x0_device::cmp_k_a, &tms340x0_device::cmp_k_b, &tms340x0_device::cmp_k_a, &tms340x0_device::cmp_k_b, &tms340x0_device::cmp_k_a, &tms340x0_device::cmp_k_b, + &tms340x0_device::cmp_k_a, &tms340x0_device::cmp_k_b, &tms340x0_device::cmp_k_a, &tms340x0_device::cmp_k_b, &tms340x0_device::cmp_k_a, &tms340x0_device::cmp_k_b, &tms340x0_device::cmp_k_a, &tms340x0_device::cmp_k_b, + /* 0x3800 */ + &tms340x0_device::dsjs_a, &tms340x0_device::dsjs_b, &tms340x0_device::dsjs_a, &tms340x0_device::dsjs_b, &tms340x0_device::dsjs_a, &tms340x0_device::dsjs_b, &tms340x0_device::dsjs_a, &tms340x0_device::dsjs_b, + &tms340x0_device::dsjs_a, &tms340x0_device::dsjs_b, &tms340x0_device::dsjs_a, &tms340x0_device::dsjs_b, &tms340x0_device::dsjs_a, &tms340x0_device::dsjs_b, &tms340x0_device::dsjs_a, &tms340x0_device::dsjs_b, + /* 0x3900 */ + &tms340x0_device::dsjs_a, &tms340x0_device::dsjs_b, &tms340x0_device::dsjs_a, &tms340x0_device::dsjs_b, &tms340x0_device::dsjs_a, &tms340x0_device::dsjs_b, &tms340x0_device::dsjs_a, &tms340x0_device::dsjs_b, + &tms340x0_device::dsjs_a, &tms340x0_device::dsjs_b, &tms340x0_device::dsjs_a, &tms340x0_device::dsjs_b, &tms340x0_device::dsjs_a, &tms340x0_device::dsjs_b, &tms340x0_device::dsjs_a, &tms340x0_device::dsjs_b, + /* 0x3a00 */ + &tms340x0_device::dsjs_a, &tms340x0_device::dsjs_b, &tms340x0_device::dsjs_a, &tms340x0_device::dsjs_b, &tms340x0_device::dsjs_a, &tms340x0_device::dsjs_b, &tms340x0_device::dsjs_a, &tms340x0_device::dsjs_b, + &tms340x0_device::dsjs_a, &tms340x0_device::dsjs_b, &tms340x0_device::dsjs_a, &tms340x0_device::dsjs_b, &tms340x0_device::dsjs_a, &tms340x0_device::dsjs_b, &tms340x0_device::dsjs_a, &tms340x0_device::dsjs_b, + /* 0x3b00 */ + &tms340x0_device::dsjs_a, &tms340x0_device::dsjs_b, &tms340x0_device::dsjs_a, &tms340x0_device::dsjs_b, &tms340x0_device::dsjs_a, &tms340x0_device::dsjs_b, &tms340x0_device::dsjs_a, &tms340x0_device::dsjs_b, + &tms340x0_device::dsjs_a, &tms340x0_device::dsjs_b, &tms340x0_device::dsjs_a, &tms340x0_device::dsjs_b, &tms340x0_device::dsjs_a, &tms340x0_device::dsjs_b, &tms340x0_device::dsjs_a, &tms340x0_device::dsjs_b, + /* 0x3c00 */ + &tms340x0_device::dsjs_a, &tms340x0_device::dsjs_b, &tms340x0_device::dsjs_a, &tms340x0_device::dsjs_b, &tms340x0_device::dsjs_a, &tms340x0_device::dsjs_b, &tms340x0_device::dsjs_a, &tms340x0_device::dsjs_b, + &tms340x0_device::dsjs_a, &tms340x0_device::dsjs_b, &tms340x0_device::dsjs_a, &tms340x0_device::dsjs_b, &tms340x0_device::dsjs_a, &tms340x0_device::dsjs_b, &tms340x0_device::dsjs_a, &tms340x0_device::dsjs_b, + /* 0x3d00 */ + &tms340x0_device::dsjs_a, &tms340x0_device::dsjs_b, &tms340x0_device::dsjs_a, &tms340x0_device::dsjs_b, &tms340x0_device::dsjs_a, &tms340x0_device::dsjs_b, &tms340x0_device::dsjs_a, &tms340x0_device::dsjs_b, + &tms340x0_device::dsjs_a, &tms340x0_device::dsjs_b, &tms340x0_device::dsjs_a, &tms340x0_device::dsjs_b, &tms340x0_device::dsjs_a, &tms340x0_device::dsjs_b, &tms340x0_device::dsjs_a, &tms340x0_device::dsjs_b, + /* 0x3e00 */ + &tms340x0_device::dsjs_a, &tms340x0_device::dsjs_b, &tms340x0_device::dsjs_a, &tms340x0_device::dsjs_b, &tms340x0_device::dsjs_a, &tms340x0_device::dsjs_b, &tms340x0_device::dsjs_a, &tms340x0_device::dsjs_b, + &tms340x0_device::dsjs_a, &tms340x0_device::dsjs_b, &tms340x0_device::dsjs_a, &tms340x0_device::dsjs_b, &tms340x0_device::dsjs_a, &tms340x0_device::dsjs_b, &tms340x0_device::dsjs_a, &tms340x0_device::dsjs_b, + /* 0x3f00 */ + &tms340x0_device::dsjs_a, &tms340x0_device::dsjs_b, &tms340x0_device::dsjs_a, &tms340x0_device::dsjs_b, &tms340x0_device::dsjs_a, &tms340x0_device::dsjs_b, &tms340x0_device::dsjs_a, &tms340x0_device::dsjs_b, + &tms340x0_device::dsjs_a, &tms340x0_device::dsjs_b, &tms340x0_device::dsjs_a, &tms340x0_device::dsjs_b, &tms340x0_device::dsjs_a, &tms340x0_device::dsjs_b, &tms340x0_device::dsjs_a, &tms340x0_device::dsjs_b, + /* 0x4000 */ + &tms340x0_device::add_a, &tms340x0_device::add_b, &tms340x0_device::add_a, &tms340x0_device::add_b, &tms340x0_device::add_a, &tms340x0_device::add_b, &tms340x0_device::add_a, &tms340x0_device::add_b, + &tms340x0_device::add_a, &tms340x0_device::add_b, &tms340x0_device::add_a, &tms340x0_device::add_b, &tms340x0_device::add_a, &tms340x0_device::add_b, &tms340x0_device::add_a, &tms340x0_device::add_b, + /* 0x4100 */ + &tms340x0_device::add_a, &tms340x0_device::add_b, &tms340x0_device::add_a, &tms340x0_device::add_b, &tms340x0_device::add_a, &tms340x0_device::add_b, &tms340x0_device::add_a, &tms340x0_device::add_b, + &tms340x0_device::add_a, &tms340x0_device::add_b, &tms340x0_device::add_a, &tms340x0_device::add_b, &tms340x0_device::add_a, &tms340x0_device::add_b, &tms340x0_device::add_a, &tms340x0_device::add_b, + /* 0x4200 */ + &tms340x0_device::addc_a, &tms340x0_device::addc_b, &tms340x0_device::addc_a, &tms340x0_device::addc_b, &tms340x0_device::addc_a, &tms340x0_device::addc_b, &tms340x0_device::addc_a, &tms340x0_device::addc_b, + &tms340x0_device::addc_a, &tms340x0_device::addc_b, &tms340x0_device::addc_a, &tms340x0_device::addc_b, &tms340x0_device::addc_a, &tms340x0_device::addc_b, &tms340x0_device::addc_a, &tms340x0_device::addc_b, + /* 0x4300 */ + &tms340x0_device::addc_a, &tms340x0_device::addc_b, &tms340x0_device::addc_a, &tms340x0_device::addc_b, &tms340x0_device::addc_a, &tms340x0_device::addc_b, &tms340x0_device::addc_a, &tms340x0_device::addc_b, + &tms340x0_device::addc_a, &tms340x0_device::addc_b, &tms340x0_device::addc_a, &tms340x0_device::addc_b, &tms340x0_device::addc_a, &tms340x0_device::addc_b, &tms340x0_device::addc_a, &tms340x0_device::addc_b, + /* 0x4400 */ + &tms340x0_device::sub_a, &tms340x0_device::sub_b, &tms340x0_device::sub_a, &tms340x0_device::sub_b, &tms340x0_device::sub_a, &tms340x0_device::sub_b, &tms340x0_device::sub_a, &tms340x0_device::sub_b, + &tms340x0_device::sub_a, &tms340x0_device::sub_b, &tms340x0_device::sub_a, &tms340x0_device::sub_b, &tms340x0_device::sub_a, &tms340x0_device::sub_b, &tms340x0_device::sub_a, &tms340x0_device::sub_b, + /* 0x4500 */ + &tms340x0_device::sub_a, &tms340x0_device::sub_b, &tms340x0_device::sub_a, &tms340x0_device::sub_b, &tms340x0_device::sub_a, &tms340x0_device::sub_b, &tms340x0_device::sub_a, &tms340x0_device::sub_b, + &tms340x0_device::sub_a, &tms340x0_device::sub_b, &tms340x0_device::sub_a, &tms340x0_device::sub_b, &tms340x0_device::sub_a, &tms340x0_device::sub_b, &tms340x0_device::sub_a, &tms340x0_device::sub_b, + /* 0x4600 */ + &tms340x0_device::subb_a, &tms340x0_device::subb_b, &tms340x0_device::subb_a, &tms340x0_device::subb_b, &tms340x0_device::subb_a, &tms340x0_device::subb_b, &tms340x0_device::subb_a, &tms340x0_device::subb_b, + &tms340x0_device::subb_a, &tms340x0_device::subb_b, &tms340x0_device::subb_a, &tms340x0_device::subb_b, &tms340x0_device::subb_a, &tms340x0_device::subb_b, &tms340x0_device::subb_a, &tms340x0_device::subb_b, + /* 0x4700 */ + &tms340x0_device::subb_a, &tms340x0_device::subb_b, &tms340x0_device::subb_a, &tms340x0_device::subb_b, &tms340x0_device::subb_a, &tms340x0_device::subb_b, &tms340x0_device::subb_a, &tms340x0_device::subb_b, + &tms340x0_device::subb_a, &tms340x0_device::subb_b, &tms340x0_device::subb_a, &tms340x0_device::subb_b, &tms340x0_device::subb_a, &tms340x0_device::subb_b, &tms340x0_device::subb_a, &tms340x0_device::subb_b, + /* 0x4800 */ + &tms340x0_device::cmp_a, &tms340x0_device::cmp_b, &tms340x0_device::cmp_a, &tms340x0_device::cmp_b, &tms340x0_device::cmp_a, &tms340x0_device::cmp_b, &tms340x0_device::cmp_a, &tms340x0_device::cmp_b, + &tms340x0_device::cmp_a, &tms340x0_device::cmp_b, &tms340x0_device::cmp_a, &tms340x0_device::cmp_b, &tms340x0_device::cmp_a, &tms340x0_device::cmp_b, &tms340x0_device::cmp_a, &tms340x0_device::cmp_b, + /* 0x4900 */ + &tms340x0_device::cmp_a, &tms340x0_device::cmp_b, &tms340x0_device::cmp_a, &tms340x0_device::cmp_b, &tms340x0_device::cmp_a, &tms340x0_device::cmp_b, &tms340x0_device::cmp_a, &tms340x0_device::cmp_b, + &tms340x0_device::cmp_a, &tms340x0_device::cmp_b, &tms340x0_device::cmp_a, &tms340x0_device::cmp_b, &tms340x0_device::cmp_a, &tms340x0_device::cmp_b, &tms340x0_device::cmp_a, &tms340x0_device::cmp_b, + /* 0x4a00 */ + &tms340x0_device::btst_r_a, &tms340x0_device::btst_r_b, &tms340x0_device::btst_r_a, &tms340x0_device::btst_r_b, &tms340x0_device::btst_r_a, &tms340x0_device::btst_r_b, &tms340x0_device::btst_r_a, &tms340x0_device::btst_r_b, + &tms340x0_device::btst_r_a, &tms340x0_device::btst_r_b, &tms340x0_device::btst_r_a, &tms340x0_device::btst_r_b, &tms340x0_device::btst_r_a, &tms340x0_device::btst_r_b, &tms340x0_device::btst_r_a, &tms340x0_device::btst_r_b, + /* 0x4b00 */ + &tms340x0_device::btst_r_a, &tms340x0_device::btst_r_b, &tms340x0_device::btst_r_a, &tms340x0_device::btst_r_b, &tms340x0_device::btst_r_a, &tms340x0_device::btst_r_b, &tms340x0_device::btst_r_a, &tms340x0_device::btst_r_b, + &tms340x0_device::btst_r_a, &tms340x0_device::btst_r_b, &tms340x0_device::btst_r_a, &tms340x0_device::btst_r_b, &tms340x0_device::btst_r_a, &tms340x0_device::btst_r_b, &tms340x0_device::btst_r_a, &tms340x0_device::btst_r_b, + /* 0x4c00 */ + &tms340x0_device::move_rr_a, &tms340x0_device::move_rr_b, &tms340x0_device::move_rr_a, &tms340x0_device::move_rr_b, &tms340x0_device::move_rr_a, &tms340x0_device::move_rr_b, &tms340x0_device::move_rr_a, &tms340x0_device::move_rr_b, + &tms340x0_device::move_rr_a, &tms340x0_device::move_rr_b, &tms340x0_device::move_rr_a, &tms340x0_device::move_rr_b, &tms340x0_device::move_rr_a, &tms340x0_device::move_rr_b, &tms340x0_device::move_rr_a, &tms340x0_device::move_rr_b, + /* 0x4d00 */ + &tms340x0_device::move_rr_a, &tms340x0_device::move_rr_b, &tms340x0_device::move_rr_a, &tms340x0_device::move_rr_b, &tms340x0_device::move_rr_a, &tms340x0_device::move_rr_b, &tms340x0_device::move_rr_a, &tms340x0_device::move_rr_b, + &tms340x0_device::move_rr_a, &tms340x0_device::move_rr_b, &tms340x0_device::move_rr_a, &tms340x0_device::move_rr_b, &tms340x0_device::move_rr_a, &tms340x0_device::move_rr_b, &tms340x0_device::move_rr_a, &tms340x0_device::move_rr_b, + /* 0x4e00 */ + &tms340x0_device::move_rr_ax, &tms340x0_device::move_rr_bx, &tms340x0_device::move_rr_ax, &tms340x0_device::move_rr_bx, &tms340x0_device::move_rr_ax, &tms340x0_device::move_rr_bx, &tms340x0_device::move_rr_ax, &tms340x0_device::move_rr_bx, + &tms340x0_device::move_rr_ax, &tms340x0_device::move_rr_bx, &tms340x0_device::move_rr_ax, &tms340x0_device::move_rr_bx, &tms340x0_device::move_rr_ax, &tms340x0_device::move_rr_bx, &tms340x0_device::move_rr_ax, &tms340x0_device::move_rr_bx, + /* 0x4f00 */ + &tms340x0_device::move_rr_ax, &tms340x0_device::move_rr_bx, &tms340x0_device::move_rr_ax, &tms340x0_device::move_rr_bx, &tms340x0_device::move_rr_ax, &tms340x0_device::move_rr_bx, &tms340x0_device::move_rr_ax, &tms340x0_device::move_rr_bx, + &tms340x0_device::move_rr_ax, &tms340x0_device::move_rr_bx, &tms340x0_device::move_rr_ax, &tms340x0_device::move_rr_bx, &tms340x0_device::move_rr_ax, &tms340x0_device::move_rr_bx, &tms340x0_device::move_rr_ax, &tms340x0_device::move_rr_bx, + /* 0x5000 */ + &tms340x0_device::and_a, &tms340x0_device::and_b, &tms340x0_device::and_a, &tms340x0_device::and_b, &tms340x0_device::and_a, &tms340x0_device::and_b, &tms340x0_device::and_a, &tms340x0_device::and_b, + &tms340x0_device::and_a, &tms340x0_device::and_b, &tms340x0_device::and_a, &tms340x0_device::and_b, &tms340x0_device::and_a, &tms340x0_device::and_b, &tms340x0_device::and_a, &tms340x0_device::and_b, + /* 0x5100 */ + &tms340x0_device::and_a, &tms340x0_device::and_b, &tms340x0_device::and_a, &tms340x0_device::and_b, &tms340x0_device::and_a, &tms340x0_device::and_b, &tms340x0_device::and_a, &tms340x0_device::and_b, + &tms340x0_device::and_a, &tms340x0_device::and_b, &tms340x0_device::and_a, &tms340x0_device::and_b, &tms340x0_device::and_a, &tms340x0_device::and_b, &tms340x0_device::and_a, &tms340x0_device::and_b, + /* 0x5200 */ + &tms340x0_device::andn_a, &tms340x0_device::andn_b, &tms340x0_device::andn_a, &tms340x0_device::andn_b, &tms340x0_device::andn_a, &tms340x0_device::andn_b, &tms340x0_device::andn_a, &tms340x0_device::andn_b, + &tms340x0_device::andn_a, &tms340x0_device::andn_b, &tms340x0_device::andn_a, &tms340x0_device::andn_b, &tms340x0_device::andn_a, &tms340x0_device::andn_b, &tms340x0_device::andn_a, &tms340x0_device::andn_b, + /* 0x5300 */ + &tms340x0_device::andn_a, &tms340x0_device::andn_b, &tms340x0_device::andn_a, &tms340x0_device::andn_b, &tms340x0_device::andn_a, &tms340x0_device::andn_b, &tms340x0_device::andn_a, &tms340x0_device::andn_b, + &tms340x0_device::andn_a, &tms340x0_device::andn_b, &tms340x0_device::andn_a, &tms340x0_device::andn_b, &tms340x0_device::andn_a, &tms340x0_device::andn_b, &tms340x0_device::andn_a, &tms340x0_device::andn_b, + /* 0x5400 */ + &tms340x0_device::or_a, &tms340x0_device::or_b, &tms340x0_device::or_a, &tms340x0_device::or_b, &tms340x0_device::or_a, &tms340x0_device::or_b, &tms340x0_device::or_a, &tms340x0_device::or_b, + &tms340x0_device::or_a, &tms340x0_device::or_b, &tms340x0_device::or_a, &tms340x0_device::or_b, &tms340x0_device::or_a, &tms340x0_device::or_b, &tms340x0_device::or_a, &tms340x0_device::or_b, + /* 0x5500 */ + &tms340x0_device::or_a, &tms340x0_device::or_b, &tms340x0_device::or_a, &tms340x0_device::or_b, &tms340x0_device::or_a, &tms340x0_device::or_b, &tms340x0_device::or_a, &tms340x0_device::or_b, + &tms340x0_device::or_a, &tms340x0_device::or_b, &tms340x0_device::or_a, &tms340x0_device::or_b, &tms340x0_device::or_a, &tms340x0_device::or_b, &tms340x0_device::or_a, &tms340x0_device::or_b, + /* 0x5600 */ + &tms340x0_device::xor_a, &tms340x0_device::xor_b, &tms340x0_device::xor_a, &tms340x0_device::xor_b, &tms340x0_device::xor_a, &tms340x0_device::xor_b, &tms340x0_device::xor_a, &tms340x0_device::xor_b, + &tms340x0_device::xor_a, &tms340x0_device::xor_b, &tms340x0_device::xor_a, &tms340x0_device::xor_b, &tms340x0_device::xor_a, &tms340x0_device::xor_b, &tms340x0_device::xor_a, &tms340x0_device::xor_b, + /* 0x5700 */ + &tms340x0_device::xor_a, &tms340x0_device::xor_b, &tms340x0_device::xor_a, &tms340x0_device::xor_b, &tms340x0_device::xor_a, &tms340x0_device::xor_b, &tms340x0_device::xor_a, &tms340x0_device::xor_b, + &tms340x0_device::xor_a, &tms340x0_device::xor_b, &tms340x0_device::xor_a, &tms340x0_device::xor_b, &tms340x0_device::xor_a, &tms340x0_device::xor_b, &tms340x0_device::xor_a, &tms340x0_device::xor_b, + /* 0x5800 */ + &tms340x0_device::divs_a, &tms340x0_device::divs_b, &tms340x0_device::divs_a, &tms340x0_device::divs_b, &tms340x0_device::divs_a, &tms340x0_device::divs_b, &tms340x0_device::divs_a, &tms340x0_device::divs_b, + &tms340x0_device::divs_a, &tms340x0_device::divs_b, &tms340x0_device::divs_a, &tms340x0_device::divs_b, &tms340x0_device::divs_a, &tms340x0_device::divs_b, &tms340x0_device::divs_a, &tms340x0_device::divs_b, + /* 0x5900 */ + &tms340x0_device::divs_a, &tms340x0_device::divs_b, &tms340x0_device::divs_a, &tms340x0_device::divs_b, &tms340x0_device::divs_a, &tms340x0_device::divs_b, &tms340x0_device::divs_a, &tms340x0_device::divs_b, + &tms340x0_device::divs_a, &tms340x0_device::divs_b, &tms340x0_device::divs_a, &tms340x0_device::divs_b, &tms340x0_device::divs_a, &tms340x0_device::divs_b, &tms340x0_device::divs_a, &tms340x0_device::divs_b, + /* 0x5a00 */ + &tms340x0_device::divu_a, &tms340x0_device::divu_b, &tms340x0_device::divu_a, &tms340x0_device::divu_b, &tms340x0_device::divu_a, &tms340x0_device::divu_b, &tms340x0_device::divu_a, &tms340x0_device::divu_b, + &tms340x0_device::divu_a, &tms340x0_device::divu_b, &tms340x0_device::divu_a, &tms340x0_device::divu_b, &tms340x0_device::divu_a, &tms340x0_device::divu_b, &tms340x0_device::divu_a, &tms340x0_device::divu_b, + /* 0x5b00 */ + &tms340x0_device::divu_a, &tms340x0_device::divu_b, &tms340x0_device::divu_a, &tms340x0_device::divu_b, &tms340x0_device::divu_a, &tms340x0_device::divu_b, &tms340x0_device::divu_a, &tms340x0_device::divu_b, + &tms340x0_device::divu_a, &tms340x0_device::divu_b, &tms340x0_device::divu_a, &tms340x0_device::divu_b, &tms340x0_device::divu_a, &tms340x0_device::divu_b, &tms340x0_device::divu_a, &tms340x0_device::divu_b, + /* 0x5c00 */ + &tms340x0_device::mpys_a, &tms340x0_device::mpys_b, &tms340x0_device::mpys_a, &tms340x0_device::mpys_b, &tms340x0_device::mpys_a, &tms340x0_device::mpys_b, &tms340x0_device::mpys_a, &tms340x0_device::mpys_b, + &tms340x0_device::mpys_a, &tms340x0_device::mpys_b, &tms340x0_device::mpys_a, &tms340x0_device::mpys_b, &tms340x0_device::mpys_a, &tms340x0_device::mpys_b, &tms340x0_device::mpys_a, &tms340x0_device::mpys_b, + /* 0x5d00 */ + &tms340x0_device::mpys_a, &tms340x0_device::mpys_b, &tms340x0_device::mpys_a, &tms340x0_device::mpys_b, &tms340x0_device::mpys_a, &tms340x0_device::mpys_b, &tms340x0_device::mpys_a, &tms340x0_device::mpys_b, + &tms340x0_device::mpys_a, &tms340x0_device::mpys_b, &tms340x0_device::mpys_a, &tms340x0_device::mpys_b, &tms340x0_device::mpys_a, &tms340x0_device::mpys_b, &tms340x0_device::mpys_a, &tms340x0_device::mpys_b, + /* 0x5e00 */ + &tms340x0_device::mpyu_a, &tms340x0_device::mpyu_b, &tms340x0_device::mpyu_a, &tms340x0_device::mpyu_b, &tms340x0_device::mpyu_a, &tms340x0_device::mpyu_b, &tms340x0_device::mpyu_a, &tms340x0_device::mpyu_b, + &tms340x0_device::mpyu_a, &tms340x0_device::mpyu_b, &tms340x0_device::mpyu_a, &tms340x0_device::mpyu_b, &tms340x0_device::mpyu_a, &tms340x0_device::mpyu_b, &tms340x0_device::mpyu_a, &tms340x0_device::mpyu_b, + /* 0x5f00 */ + &tms340x0_device::mpyu_a, &tms340x0_device::mpyu_b, &tms340x0_device::mpyu_a, &tms340x0_device::mpyu_b, &tms340x0_device::mpyu_a, &tms340x0_device::mpyu_b, &tms340x0_device::mpyu_a, &tms340x0_device::mpyu_b, + &tms340x0_device::mpyu_a, &tms340x0_device::mpyu_b, &tms340x0_device::mpyu_a, &tms340x0_device::mpyu_b, &tms340x0_device::mpyu_a, &tms340x0_device::mpyu_b, &tms340x0_device::mpyu_a, &tms340x0_device::mpyu_b, + /* 0x6000 */ + &tms340x0_device::sla_r_a, &tms340x0_device::sla_r_b, &tms340x0_device::sla_r_a, &tms340x0_device::sla_r_b, &tms340x0_device::sla_r_a, &tms340x0_device::sla_r_b, &tms340x0_device::sla_r_a, &tms340x0_device::sla_r_b, + &tms340x0_device::sla_r_a, &tms340x0_device::sla_r_b, &tms340x0_device::sla_r_a, &tms340x0_device::sla_r_b, &tms340x0_device::sla_r_a, &tms340x0_device::sla_r_b, &tms340x0_device::sla_r_a, &tms340x0_device::sla_r_b, + /* 0x6100 */ + &tms340x0_device::sla_r_a, &tms340x0_device::sla_r_b, &tms340x0_device::sla_r_a, &tms340x0_device::sla_r_b, &tms340x0_device::sla_r_a, &tms340x0_device::sla_r_b, &tms340x0_device::sla_r_a, &tms340x0_device::sla_r_b, + &tms340x0_device::sla_r_a, &tms340x0_device::sla_r_b, &tms340x0_device::sla_r_a, &tms340x0_device::sla_r_b, &tms340x0_device::sla_r_a, &tms340x0_device::sla_r_b, &tms340x0_device::sla_r_a, &tms340x0_device::sla_r_b, + /* 0x6200 */ + &tms340x0_device::sll_r_a, &tms340x0_device::sll_r_b, &tms340x0_device::sll_r_a, &tms340x0_device::sll_r_b, &tms340x0_device::sll_r_a, &tms340x0_device::sll_r_b, &tms340x0_device::sll_r_a, &tms340x0_device::sll_r_b, + &tms340x0_device::sll_r_a, &tms340x0_device::sll_r_b, &tms340x0_device::sll_r_a, &tms340x0_device::sll_r_b, &tms340x0_device::sll_r_a, &tms340x0_device::sll_r_b, &tms340x0_device::sll_r_a, &tms340x0_device::sll_r_b, + /* 0x6300 */ + &tms340x0_device::sll_r_a, &tms340x0_device::sll_r_b, &tms340x0_device::sll_r_a, &tms340x0_device::sll_r_b, &tms340x0_device::sll_r_a, &tms340x0_device::sll_r_b, &tms340x0_device::sll_r_a, &tms340x0_device::sll_r_b, + &tms340x0_device::sll_r_a, &tms340x0_device::sll_r_b, &tms340x0_device::sll_r_a, &tms340x0_device::sll_r_b, &tms340x0_device::sll_r_a, &tms340x0_device::sll_r_b, &tms340x0_device::sll_r_a, &tms340x0_device::sll_r_b, + /* 0x6400 */ + &tms340x0_device::sra_r_a, &tms340x0_device::sra_r_b, &tms340x0_device::sra_r_a, &tms340x0_device::sra_r_b, &tms340x0_device::sra_r_a, &tms340x0_device::sra_r_b, &tms340x0_device::sra_r_a, &tms340x0_device::sra_r_b, + &tms340x0_device::sra_r_a, &tms340x0_device::sra_r_b, &tms340x0_device::sra_r_a, &tms340x0_device::sra_r_b, &tms340x0_device::sra_r_a, &tms340x0_device::sra_r_b, &tms340x0_device::sra_r_a, &tms340x0_device::sra_r_b, + /* 0x6500 */ + &tms340x0_device::sra_r_a, &tms340x0_device::sra_r_b, &tms340x0_device::sra_r_a, &tms340x0_device::sra_r_b, &tms340x0_device::sra_r_a, &tms340x0_device::sra_r_b, &tms340x0_device::sra_r_a, &tms340x0_device::sra_r_b, + &tms340x0_device::sra_r_a, &tms340x0_device::sra_r_b, &tms340x0_device::sra_r_a, &tms340x0_device::sra_r_b, &tms340x0_device::sra_r_a, &tms340x0_device::sra_r_b, &tms340x0_device::sra_r_a, &tms340x0_device::sra_r_b, + /* 0x6600 */ + &tms340x0_device::srl_r_a, &tms340x0_device::srl_r_b, &tms340x0_device::srl_r_a, &tms340x0_device::srl_r_b, &tms340x0_device::srl_r_a, &tms340x0_device::srl_r_b, &tms340x0_device::srl_r_a, &tms340x0_device::srl_r_b, + &tms340x0_device::srl_r_a, &tms340x0_device::srl_r_b, &tms340x0_device::srl_r_a, &tms340x0_device::srl_r_b, &tms340x0_device::srl_r_a, &tms340x0_device::srl_r_b, &tms340x0_device::srl_r_a, &tms340x0_device::srl_r_b, + /* 0x6700 */ + &tms340x0_device::srl_r_a, &tms340x0_device::srl_r_b, &tms340x0_device::srl_r_a, &tms340x0_device::srl_r_b, &tms340x0_device::srl_r_a, &tms340x0_device::srl_r_b, &tms340x0_device::srl_r_a, &tms340x0_device::srl_r_b, + &tms340x0_device::srl_r_a, &tms340x0_device::srl_r_b, &tms340x0_device::srl_r_a, &tms340x0_device::srl_r_b, &tms340x0_device::srl_r_a, &tms340x0_device::srl_r_b, &tms340x0_device::srl_r_a, &tms340x0_device::srl_r_b, + /* 0x6800 */ + &tms340x0_device::rl_r_a, &tms340x0_device::rl_r_b, &tms340x0_device::rl_r_a, &tms340x0_device::rl_r_b, &tms340x0_device::rl_r_a, &tms340x0_device::rl_r_b, &tms340x0_device::rl_r_a, &tms340x0_device::rl_r_b, + &tms340x0_device::rl_r_a, &tms340x0_device::rl_r_b, &tms340x0_device::rl_r_a, &tms340x0_device::rl_r_b, &tms340x0_device::rl_r_a, &tms340x0_device::rl_r_b, &tms340x0_device::rl_r_a, &tms340x0_device::rl_r_b, + /* 0x6900 */ + &tms340x0_device::rl_r_a, &tms340x0_device::rl_r_b, &tms340x0_device::rl_r_a, &tms340x0_device::rl_r_b, &tms340x0_device::rl_r_a, &tms340x0_device::rl_r_b, &tms340x0_device::rl_r_a, &tms340x0_device::rl_r_b, + &tms340x0_device::rl_r_a, &tms340x0_device::rl_r_b, &tms340x0_device::rl_r_a, &tms340x0_device::rl_r_b, &tms340x0_device::rl_r_a, &tms340x0_device::rl_r_b, &tms340x0_device::rl_r_a, &tms340x0_device::rl_r_b, + /* 0x6a00 */ + &tms340x0_device::lmo_a, &tms340x0_device::lmo_b, &tms340x0_device::lmo_a, &tms340x0_device::lmo_b, &tms340x0_device::lmo_a, &tms340x0_device::lmo_b, &tms340x0_device::lmo_a, &tms340x0_device::lmo_b, + &tms340x0_device::lmo_a, &tms340x0_device::lmo_b, &tms340x0_device::lmo_a, &tms340x0_device::lmo_b, &tms340x0_device::lmo_a, &tms340x0_device::lmo_b, &tms340x0_device::lmo_a, &tms340x0_device::lmo_b, + /* 0x6b00 */ + &tms340x0_device::lmo_a, &tms340x0_device::lmo_b, &tms340x0_device::lmo_a, &tms340x0_device::lmo_b, &tms340x0_device::lmo_a, &tms340x0_device::lmo_b, &tms340x0_device::lmo_a, &tms340x0_device::lmo_b, + &tms340x0_device::lmo_a, &tms340x0_device::lmo_b, &tms340x0_device::lmo_a, &tms340x0_device::lmo_b, &tms340x0_device::lmo_a, &tms340x0_device::lmo_b, &tms340x0_device::lmo_a, &tms340x0_device::lmo_b, + /* 0x6c00 */ + &tms340x0_device::mods_a, &tms340x0_device::mods_b, &tms340x0_device::mods_a, &tms340x0_device::mods_b, &tms340x0_device::mods_a, &tms340x0_device::mods_b, &tms340x0_device::mods_a, &tms340x0_device::mods_b, + &tms340x0_device::mods_a, &tms340x0_device::mods_b, &tms340x0_device::mods_a, &tms340x0_device::mods_b, &tms340x0_device::mods_a, &tms340x0_device::mods_b, &tms340x0_device::mods_a, &tms340x0_device::mods_b, + /* 0x6d00 */ + &tms340x0_device::mods_a, &tms340x0_device::mods_b, &tms340x0_device::mods_a, &tms340x0_device::mods_b, &tms340x0_device::mods_a, &tms340x0_device::mods_b, &tms340x0_device::mods_a, &tms340x0_device::mods_b, + &tms340x0_device::mods_a, &tms340x0_device::mods_b, &tms340x0_device::mods_a, &tms340x0_device::mods_b, &tms340x0_device::mods_a, &tms340x0_device::mods_b, &tms340x0_device::mods_a, &tms340x0_device::mods_b, + /* 0x6e00 */ + &tms340x0_device::modu_a, &tms340x0_device::modu_b, &tms340x0_device::modu_a, &tms340x0_device::modu_b, &tms340x0_device::modu_a, &tms340x0_device::modu_b, &tms340x0_device::modu_a, &tms340x0_device::modu_b, + &tms340x0_device::modu_a, &tms340x0_device::modu_b, &tms340x0_device::modu_a, &tms340x0_device::modu_b, &tms340x0_device::modu_a, &tms340x0_device::modu_b, &tms340x0_device::modu_a, &tms340x0_device::modu_b, + /* 0x6f00 */ + &tms340x0_device::modu_a, &tms340x0_device::modu_b, &tms340x0_device::modu_a, &tms340x0_device::modu_b, &tms340x0_device::modu_a, &tms340x0_device::modu_b, &tms340x0_device::modu_a, &tms340x0_device::modu_b, + &tms340x0_device::modu_a, &tms340x0_device::modu_b, &tms340x0_device::modu_a, &tms340x0_device::modu_b, &tms340x0_device::modu_a, &tms340x0_device::modu_b, &tms340x0_device::modu_a, &tms340x0_device::modu_b, + /* 0x7000 */ + &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, + &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, + /* 0x7100 */ + &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, + &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, + /* 0x7200 */ + &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, + &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, + /* 0x7300 */ + &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, + &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, + /* 0x7400 */ + &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, + &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, + /* 0x7500 */ + &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, + &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, + /* 0x7600 */ + &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, + &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, + /* 0x7700 */ + &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, + &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, + /* 0x7800 */ + &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, + &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, + /* 0x7900 */ + &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, + &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, + /* 0x7a00 */ + &tms340x0_device::rmo_a, &tms340x0_device::rmo_b, &tms340x0_device::rmo_a, &tms340x0_device::rmo_b, &tms340x0_device::rmo_a, &tms340x0_device::rmo_b, &tms340x0_device::rmo_a, &tms340x0_device::rmo_b, + &tms340x0_device::rmo_a, &tms340x0_device::rmo_b, &tms340x0_device::rmo_a, &tms340x0_device::rmo_b, &tms340x0_device::rmo_a, &tms340x0_device::rmo_b, &tms340x0_device::rmo_a, &tms340x0_device::rmo_b, + /* 0x7b00 */ + &tms340x0_device::rmo_a, &tms340x0_device::rmo_b, &tms340x0_device::rmo_a, &tms340x0_device::rmo_b, &tms340x0_device::rmo_a, &tms340x0_device::rmo_b, &tms340x0_device::rmo_a, &tms340x0_device::rmo_b, + &tms340x0_device::rmo_a, &tms340x0_device::rmo_b, &tms340x0_device::rmo_a, &tms340x0_device::rmo_b, &tms340x0_device::rmo_a, &tms340x0_device::rmo_b, &tms340x0_device::rmo_a, &tms340x0_device::rmo_b, + /* 0x7c00 */ + &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, + &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, + /* 0x7d00 */ + &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, + &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, + /* 0x7e00 */ + &tms340x0_device::swapf_a, &tms340x0_device::swapf_b, &tms340x0_device::swapf_a, &tms340x0_device::swapf_b, &tms340x0_device::swapf_a, &tms340x0_device::swapf_b, &tms340x0_device::swapf_a, &tms340x0_device::swapf_b, + &tms340x0_device::swapf_a, &tms340x0_device::swapf_b, &tms340x0_device::swapf_a, &tms340x0_device::swapf_b, &tms340x0_device::swapf_a, &tms340x0_device::swapf_b, &tms340x0_device::swapf_a, &tms340x0_device::swapf_b, + /* 0x7f00 */ + &tms340x0_device::swapf_a, &tms340x0_device::swapf_b, &tms340x0_device::swapf_a, &tms340x0_device::swapf_b, &tms340x0_device::swapf_a, &tms340x0_device::swapf_b, &tms340x0_device::swapf_a, &tms340x0_device::swapf_b, + &tms340x0_device::swapf_a, &tms340x0_device::swapf_b, &tms340x0_device::swapf_a, &tms340x0_device::swapf_b, &tms340x0_device::swapf_a, &tms340x0_device::swapf_b, &tms340x0_device::swapf_a, &tms340x0_device::swapf_b, + /* 0x8000 */ + &tms340x0_device::move0_rn_a, &tms340x0_device::move0_rn_b, &tms340x0_device::move0_rn_a, &tms340x0_device::move0_rn_b, &tms340x0_device::move0_rn_a, &tms340x0_device::move0_rn_b, &tms340x0_device::move0_rn_a, &tms340x0_device::move0_rn_b, + &tms340x0_device::move0_rn_a, &tms340x0_device::move0_rn_b, &tms340x0_device::move0_rn_a, &tms340x0_device::move0_rn_b, &tms340x0_device::move0_rn_a, &tms340x0_device::move0_rn_b, &tms340x0_device::move0_rn_a, &tms340x0_device::move0_rn_b, + /* 0x8100 */ + &tms340x0_device::move0_rn_a, &tms340x0_device::move0_rn_b, &tms340x0_device::move0_rn_a, &tms340x0_device::move0_rn_b, &tms340x0_device::move0_rn_a, &tms340x0_device::move0_rn_b, &tms340x0_device::move0_rn_a, &tms340x0_device::move0_rn_b, + &tms340x0_device::move0_rn_a, &tms340x0_device::move0_rn_b, &tms340x0_device::move0_rn_a, &tms340x0_device::move0_rn_b, &tms340x0_device::move0_rn_a, &tms340x0_device::move0_rn_b, &tms340x0_device::move0_rn_a, &tms340x0_device::move0_rn_b, + /* 0x8200 */ + &tms340x0_device::move1_rn_a, &tms340x0_device::move1_rn_b, &tms340x0_device::move1_rn_a, &tms340x0_device::move1_rn_b, &tms340x0_device::move1_rn_a, &tms340x0_device::move1_rn_b, &tms340x0_device::move1_rn_a, &tms340x0_device::move1_rn_b, + &tms340x0_device::move1_rn_a, &tms340x0_device::move1_rn_b, &tms340x0_device::move1_rn_a, &tms340x0_device::move1_rn_b, &tms340x0_device::move1_rn_a, &tms340x0_device::move1_rn_b, &tms340x0_device::move1_rn_a, &tms340x0_device::move1_rn_b, + /* 0x8300 */ + &tms340x0_device::move1_rn_a, &tms340x0_device::move1_rn_b, &tms340x0_device::move1_rn_a, &tms340x0_device::move1_rn_b, &tms340x0_device::move1_rn_a, &tms340x0_device::move1_rn_b, &tms340x0_device::move1_rn_a, &tms340x0_device::move1_rn_b, + &tms340x0_device::move1_rn_a, &tms340x0_device::move1_rn_b, &tms340x0_device::move1_rn_a, &tms340x0_device::move1_rn_b, &tms340x0_device::move1_rn_a, &tms340x0_device::move1_rn_b, &tms340x0_device::move1_rn_a, &tms340x0_device::move1_rn_b, + /* 0x8400 */ + &tms340x0_device::move0_nr_a, &tms340x0_device::move0_nr_b, &tms340x0_device::move0_nr_a, &tms340x0_device::move0_nr_b, &tms340x0_device::move0_nr_a, &tms340x0_device::move0_nr_b, &tms340x0_device::move0_nr_a, &tms340x0_device::move0_nr_b, + &tms340x0_device::move0_nr_a, &tms340x0_device::move0_nr_b, &tms340x0_device::move0_nr_a, &tms340x0_device::move0_nr_b, &tms340x0_device::move0_nr_a, &tms340x0_device::move0_nr_b, &tms340x0_device::move0_nr_a, &tms340x0_device::move0_nr_b, + /* 0x8500 */ + &tms340x0_device::move0_nr_a, &tms340x0_device::move0_nr_b, &tms340x0_device::move0_nr_a, &tms340x0_device::move0_nr_b, &tms340x0_device::move0_nr_a, &tms340x0_device::move0_nr_b, &tms340x0_device::move0_nr_a, &tms340x0_device::move0_nr_b, + &tms340x0_device::move0_nr_a, &tms340x0_device::move0_nr_b, &tms340x0_device::move0_nr_a, &tms340x0_device::move0_nr_b, &tms340x0_device::move0_nr_a, &tms340x0_device::move0_nr_b, &tms340x0_device::move0_nr_a, &tms340x0_device::move0_nr_b, + /* 0x8600 */ + &tms340x0_device::move1_nr_a, &tms340x0_device::move1_nr_b, &tms340x0_device::move1_nr_a, &tms340x0_device::move1_nr_b, &tms340x0_device::move1_nr_a, &tms340x0_device::move1_nr_b, &tms340x0_device::move1_nr_a, &tms340x0_device::move1_nr_b, + &tms340x0_device::move1_nr_a, &tms340x0_device::move1_nr_b, &tms340x0_device::move1_nr_a, &tms340x0_device::move1_nr_b, &tms340x0_device::move1_nr_a, &tms340x0_device::move1_nr_b, &tms340x0_device::move1_nr_a, &tms340x0_device::move1_nr_b, + /* 0x8700 */ + &tms340x0_device::move1_nr_a, &tms340x0_device::move1_nr_b, &tms340x0_device::move1_nr_a, &tms340x0_device::move1_nr_b, &tms340x0_device::move1_nr_a, &tms340x0_device::move1_nr_b, &tms340x0_device::move1_nr_a, &tms340x0_device::move1_nr_b, + &tms340x0_device::move1_nr_a, &tms340x0_device::move1_nr_b, &tms340x0_device::move1_nr_a, &tms340x0_device::move1_nr_b, &tms340x0_device::move1_nr_a, &tms340x0_device::move1_nr_b, &tms340x0_device::move1_nr_a, &tms340x0_device::move1_nr_b, + /* 0x8800 */ + &tms340x0_device::move0_nn_a, &tms340x0_device::move0_nn_b, &tms340x0_device::move0_nn_a, &tms340x0_device::move0_nn_b, &tms340x0_device::move0_nn_a, &tms340x0_device::move0_nn_b, &tms340x0_device::move0_nn_a, &tms340x0_device::move0_nn_b, + &tms340x0_device::move0_nn_a, &tms340x0_device::move0_nn_b, &tms340x0_device::move0_nn_a, &tms340x0_device::move0_nn_b, &tms340x0_device::move0_nn_a, &tms340x0_device::move0_nn_b, &tms340x0_device::move0_nn_a, &tms340x0_device::move0_nn_b, + /* 0x8900 */ + &tms340x0_device::move0_nn_a, &tms340x0_device::move0_nn_b, &tms340x0_device::move0_nn_a, &tms340x0_device::move0_nn_b, &tms340x0_device::move0_nn_a, &tms340x0_device::move0_nn_b, &tms340x0_device::move0_nn_a, &tms340x0_device::move0_nn_b, + &tms340x0_device::move0_nn_a, &tms340x0_device::move0_nn_b, &tms340x0_device::move0_nn_a, &tms340x0_device::move0_nn_b, &tms340x0_device::move0_nn_a, &tms340x0_device::move0_nn_b, &tms340x0_device::move0_nn_a, &tms340x0_device::move0_nn_b, + /* 0x8a00 */ + &tms340x0_device::move1_nn_a, &tms340x0_device::move1_nn_b, &tms340x0_device::move1_nn_a, &tms340x0_device::move1_nn_b, &tms340x0_device::move1_nn_a, &tms340x0_device::move1_nn_b, &tms340x0_device::move1_nn_a, &tms340x0_device::move1_nn_b, + &tms340x0_device::move1_nn_a, &tms340x0_device::move1_nn_b, &tms340x0_device::move1_nn_a, &tms340x0_device::move1_nn_b, &tms340x0_device::move1_nn_a, &tms340x0_device::move1_nn_b, &tms340x0_device::move1_nn_a, &tms340x0_device::move1_nn_b, + /* 0x8b00 */ + &tms340x0_device::move1_nn_a, &tms340x0_device::move1_nn_b, &tms340x0_device::move1_nn_a, &tms340x0_device::move1_nn_b, &tms340x0_device::move1_nn_a, &tms340x0_device::move1_nn_b, &tms340x0_device::move1_nn_a, &tms340x0_device::move1_nn_b, + &tms340x0_device::move1_nn_a, &tms340x0_device::move1_nn_b, &tms340x0_device::move1_nn_a, &tms340x0_device::move1_nn_b, &tms340x0_device::move1_nn_a, &tms340x0_device::move1_nn_b, &tms340x0_device::move1_nn_a, &tms340x0_device::move1_nn_b, + /* 0x8c00 */ + &tms340x0_device::movb_rn_a, &tms340x0_device::movb_rn_b, &tms340x0_device::movb_rn_a, &tms340x0_device::movb_rn_b, &tms340x0_device::movb_rn_a, &tms340x0_device::movb_rn_b, &tms340x0_device::movb_rn_a, &tms340x0_device::movb_rn_b, + &tms340x0_device::movb_rn_a, &tms340x0_device::movb_rn_b, &tms340x0_device::movb_rn_a, &tms340x0_device::movb_rn_b, &tms340x0_device::movb_rn_a, &tms340x0_device::movb_rn_b, &tms340x0_device::movb_rn_a, &tms340x0_device::movb_rn_b, + /* 0x8d00 */ + &tms340x0_device::movb_rn_a, &tms340x0_device::movb_rn_b, &tms340x0_device::movb_rn_a, &tms340x0_device::movb_rn_b, &tms340x0_device::movb_rn_a, &tms340x0_device::movb_rn_b, &tms340x0_device::movb_rn_a, &tms340x0_device::movb_rn_b, + &tms340x0_device::movb_rn_a, &tms340x0_device::movb_rn_b, &tms340x0_device::movb_rn_a, &tms340x0_device::movb_rn_b, &tms340x0_device::movb_rn_a, &tms340x0_device::movb_rn_b, &tms340x0_device::movb_rn_a, &tms340x0_device::movb_rn_b, + /* 0x8e00 */ + &tms340x0_device::movb_nr_a, &tms340x0_device::movb_nr_b, &tms340x0_device::movb_nr_a, &tms340x0_device::movb_nr_b, &tms340x0_device::movb_nr_a, &tms340x0_device::movb_nr_b, &tms340x0_device::movb_nr_a, &tms340x0_device::movb_nr_b, + &tms340x0_device::movb_nr_a, &tms340x0_device::movb_nr_b, &tms340x0_device::movb_nr_a, &tms340x0_device::movb_nr_b, &tms340x0_device::movb_nr_a, &tms340x0_device::movb_nr_b, &tms340x0_device::movb_nr_a, &tms340x0_device::movb_nr_b, + /* 0x8f00 */ + &tms340x0_device::movb_nr_a, &tms340x0_device::movb_nr_b, &tms340x0_device::movb_nr_a, &tms340x0_device::movb_nr_b, &tms340x0_device::movb_nr_a, &tms340x0_device::movb_nr_b, &tms340x0_device::movb_nr_a, &tms340x0_device::movb_nr_b, + &tms340x0_device::movb_nr_a, &tms340x0_device::movb_nr_b, &tms340x0_device::movb_nr_a, &tms340x0_device::movb_nr_b, &tms340x0_device::movb_nr_a, &tms340x0_device::movb_nr_b, &tms340x0_device::movb_nr_a, &tms340x0_device::movb_nr_b, + /* 0x9000 */ + &tms340x0_device::move0_r_ni_a, &tms340x0_device::move0_r_ni_b, &tms340x0_device::move0_r_ni_a, &tms340x0_device::move0_r_ni_b, &tms340x0_device::move0_r_ni_a, &tms340x0_device::move0_r_ni_b, &tms340x0_device::move0_r_ni_a, &tms340x0_device::move0_r_ni_b, + &tms340x0_device::move0_r_ni_a, &tms340x0_device::move0_r_ni_b, &tms340x0_device::move0_r_ni_a, &tms340x0_device::move0_r_ni_b, &tms340x0_device::move0_r_ni_a, &tms340x0_device::move0_r_ni_b, &tms340x0_device::move0_r_ni_a, &tms340x0_device::move0_r_ni_b, + /* 0x9100 */ + &tms340x0_device::move0_r_ni_a, &tms340x0_device::move0_r_ni_b, &tms340x0_device::move0_r_ni_a, &tms340x0_device::move0_r_ni_b, &tms340x0_device::move0_r_ni_a, &tms340x0_device::move0_r_ni_b, &tms340x0_device::move0_r_ni_a, &tms340x0_device::move0_r_ni_b, + &tms340x0_device::move0_r_ni_a, &tms340x0_device::move0_r_ni_b, &tms340x0_device::move0_r_ni_a, &tms340x0_device::move0_r_ni_b, &tms340x0_device::move0_r_ni_a, &tms340x0_device::move0_r_ni_b, &tms340x0_device::move0_r_ni_a, &tms340x0_device::move0_r_ni_b, + /* 0x9200 */ + &tms340x0_device::move1_r_ni_a, &tms340x0_device::move1_r_ni_b, &tms340x0_device::move1_r_ni_a, &tms340x0_device::move1_r_ni_b, &tms340x0_device::move1_r_ni_a, &tms340x0_device::move1_r_ni_b, &tms340x0_device::move1_r_ni_a, &tms340x0_device::move1_r_ni_b, + &tms340x0_device::move1_r_ni_a, &tms340x0_device::move1_r_ni_b, &tms340x0_device::move1_r_ni_a, &tms340x0_device::move1_r_ni_b, &tms340x0_device::move1_r_ni_a, &tms340x0_device::move1_r_ni_b, &tms340x0_device::move1_r_ni_a, &tms340x0_device::move1_r_ni_b, + /* 0x9300 */ + &tms340x0_device::move1_r_ni_a, &tms340x0_device::move1_r_ni_b, &tms340x0_device::move1_r_ni_a, &tms340x0_device::move1_r_ni_b, &tms340x0_device::move1_r_ni_a, &tms340x0_device::move1_r_ni_b, &tms340x0_device::move1_r_ni_a, &tms340x0_device::move1_r_ni_b, + &tms340x0_device::move1_r_ni_a, &tms340x0_device::move1_r_ni_b, &tms340x0_device::move1_r_ni_a, &tms340x0_device::move1_r_ni_b, &tms340x0_device::move1_r_ni_a, &tms340x0_device::move1_r_ni_b, &tms340x0_device::move1_r_ni_a, &tms340x0_device::move1_r_ni_b, + /* 0x9400 */ + &tms340x0_device::move0_ni_r_a, &tms340x0_device::move0_ni_r_b, &tms340x0_device::move0_ni_r_a, &tms340x0_device::move0_ni_r_b, &tms340x0_device::move0_ni_r_a, &tms340x0_device::move0_ni_r_b, &tms340x0_device::move0_ni_r_a, &tms340x0_device::move0_ni_r_b, + &tms340x0_device::move0_ni_r_a, &tms340x0_device::move0_ni_r_b, &tms340x0_device::move0_ni_r_a, &tms340x0_device::move0_ni_r_b, &tms340x0_device::move0_ni_r_a, &tms340x0_device::move0_ni_r_b, &tms340x0_device::move0_ni_r_a, &tms340x0_device::move0_ni_r_b, + /* 0x9500 */ + &tms340x0_device::move0_ni_r_a, &tms340x0_device::move0_ni_r_b, &tms340x0_device::move0_ni_r_a, &tms340x0_device::move0_ni_r_b, &tms340x0_device::move0_ni_r_a, &tms340x0_device::move0_ni_r_b, &tms340x0_device::move0_ni_r_a, &tms340x0_device::move0_ni_r_b, + &tms340x0_device::move0_ni_r_a, &tms340x0_device::move0_ni_r_b, &tms340x0_device::move0_ni_r_a, &tms340x0_device::move0_ni_r_b, &tms340x0_device::move0_ni_r_a, &tms340x0_device::move0_ni_r_b, &tms340x0_device::move0_ni_r_a, &tms340x0_device::move0_ni_r_b, + /* 0x9600 */ + &tms340x0_device::move1_ni_r_a, &tms340x0_device::move1_ni_r_b, &tms340x0_device::move1_ni_r_a, &tms340x0_device::move1_ni_r_b, &tms340x0_device::move1_ni_r_a, &tms340x0_device::move1_ni_r_b, &tms340x0_device::move1_ni_r_a, &tms340x0_device::move1_ni_r_b, + &tms340x0_device::move1_ni_r_a, &tms340x0_device::move1_ni_r_b, &tms340x0_device::move1_ni_r_a, &tms340x0_device::move1_ni_r_b, &tms340x0_device::move1_ni_r_a, &tms340x0_device::move1_ni_r_b, &tms340x0_device::move1_ni_r_a, &tms340x0_device::move1_ni_r_b, + /* 0x9700 */ + &tms340x0_device::move1_ni_r_a, &tms340x0_device::move1_ni_r_b, &tms340x0_device::move1_ni_r_a, &tms340x0_device::move1_ni_r_b, &tms340x0_device::move1_ni_r_a, &tms340x0_device::move1_ni_r_b, &tms340x0_device::move1_ni_r_a, &tms340x0_device::move1_ni_r_b, + &tms340x0_device::move1_ni_r_a, &tms340x0_device::move1_ni_r_b, &tms340x0_device::move1_ni_r_a, &tms340x0_device::move1_ni_r_b, &tms340x0_device::move1_ni_r_a, &tms340x0_device::move1_ni_r_b, &tms340x0_device::move1_ni_r_a, &tms340x0_device::move1_ni_r_b, + /* 0x9800 */ + &tms340x0_device::move0_ni_ni_a, &tms340x0_device::move0_ni_ni_b, &tms340x0_device::move0_ni_ni_a, &tms340x0_device::move0_ni_ni_b, &tms340x0_device::move0_ni_ni_a, &tms340x0_device::move0_ni_ni_b, &tms340x0_device::move0_ni_ni_a, &tms340x0_device::move0_ni_ni_b, + &tms340x0_device::move0_ni_ni_a, &tms340x0_device::move0_ni_ni_b, &tms340x0_device::move0_ni_ni_a, &tms340x0_device::move0_ni_ni_b, &tms340x0_device::move0_ni_ni_a, &tms340x0_device::move0_ni_ni_b, &tms340x0_device::move0_ni_ni_a, &tms340x0_device::move0_ni_ni_b, + /* 0x9900 */ + &tms340x0_device::move0_ni_ni_a, &tms340x0_device::move0_ni_ni_b, &tms340x0_device::move0_ni_ni_a, &tms340x0_device::move0_ni_ni_b, &tms340x0_device::move0_ni_ni_a, &tms340x0_device::move0_ni_ni_b, &tms340x0_device::move0_ni_ni_a, &tms340x0_device::move0_ni_ni_b, + &tms340x0_device::move0_ni_ni_a, &tms340x0_device::move0_ni_ni_b, &tms340x0_device::move0_ni_ni_a, &tms340x0_device::move0_ni_ni_b, &tms340x0_device::move0_ni_ni_a, &tms340x0_device::move0_ni_ni_b, &tms340x0_device::move0_ni_ni_a, &tms340x0_device::move0_ni_ni_b, + /* 0x9a00 */ + &tms340x0_device::move1_ni_ni_a, &tms340x0_device::move1_ni_ni_b, &tms340x0_device::move1_ni_ni_a, &tms340x0_device::move1_ni_ni_b, &tms340x0_device::move1_ni_ni_a, &tms340x0_device::move1_ni_ni_b, &tms340x0_device::move1_ni_ni_a, &tms340x0_device::move1_ni_ni_b, + &tms340x0_device::move1_ni_ni_a, &tms340x0_device::move1_ni_ni_b, &tms340x0_device::move1_ni_ni_a, &tms340x0_device::move1_ni_ni_b, &tms340x0_device::move1_ni_ni_a, &tms340x0_device::move1_ni_ni_b, &tms340x0_device::move1_ni_ni_a, &tms340x0_device::move1_ni_ni_b, + /* 0x9b00 */ + &tms340x0_device::move1_ni_ni_a, &tms340x0_device::move1_ni_ni_b, &tms340x0_device::move1_ni_ni_a, &tms340x0_device::move1_ni_ni_b, &tms340x0_device::move1_ni_ni_a, &tms340x0_device::move1_ni_ni_b, &tms340x0_device::move1_ni_ni_a, &tms340x0_device::move1_ni_ni_b, + &tms340x0_device::move1_ni_ni_a, &tms340x0_device::move1_ni_ni_b, &tms340x0_device::move1_ni_ni_a, &tms340x0_device::move1_ni_ni_b, &tms340x0_device::move1_ni_ni_a, &tms340x0_device::move1_ni_ni_b, &tms340x0_device::move1_ni_ni_a, &tms340x0_device::move1_ni_ni_b, + /* 0x9c00 */ + &tms340x0_device::movb_nn_a, &tms340x0_device::movb_nn_b, &tms340x0_device::movb_nn_a, &tms340x0_device::movb_nn_b, &tms340x0_device::movb_nn_a, &tms340x0_device::movb_nn_b, &tms340x0_device::movb_nn_a, &tms340x0_device::movb_nn_b, + &tms340x0_device::movb_nn_a, &tms340x0_device::movb_nn_b, &tms340x0_device::movb_nn_a, &tms340x0_device::movb_nn_b, &tms340x0_device::movb_nn_a, &tms340x0_device::movb_nn_b, &tms340x0_device::movb_nn_a, &tms340x0_device::movb_nn_b, + /* 0x9d00 */ + &tms340x0_device::movb_nn_a, &tms340x0_device::movb_nn_b, &tms340x0_device::movb_nn_a, &tms340x0_device::movb_nn_b, &tms340x0_device::movb_nn_a, &tms340x0_device::movb_nn_b, &tms340x0_device::movb_nn_a, &tms340x0_device::movb_nn_b, + &tms340x0_device::movb_nn_a, &tms340x0_device::movb_nn_b, &tms340x0_device::movb_nn_a, &tms340x0_device::movb_nn_b, &tms340x0_device::movb_nn_a, &tms340x0_device::movb_nn_b, &tms340x0_device::movb_nn_a, &tms340x0_device::movb_nn_b, + /* 0x9e00 */ + &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, + &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, + /* 0x9f00 */ + &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, + &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, + /* 0xa000 */ + &tms340x0_device::move0_r_dn_a, &tms340x0_device::move0_r_dn_b, &tms340x0_device::move0_r_dn_a, &tms340x0_device::move0_r_dn_b, &tms340x0_device::move0_r_dn_a, &tms340x0_device::move0_r_dn_b, &tms340x0_device::move0_r_dn_a, &tms340x0_device::move0_r_dn_b, + &tms340x0_device::move0_r_dn_a, &tms340x0_device::move0_r_dn_b, &tms340x0_device::move0_r_dn_a, &tms340x0_device::move0_r_dn_b, &tms340x0_device::move0_r_dn_a, &tms340x0_device::move0_r_dn_b, &tms340x0_device::move0_r_dn_a, &tms340x0_device::move0_r_dn_b, + /* 0xa100 */ + &tms340x0_device::move0_r_dn_a, &tms340x0_device::move0_r_dn_b, &tms340x0_device::move0_r_dn_a, &tms340x0_device::move0_r_dn_b, &tms340x0_device::move0_r_dn_a, &tms340x0_device::move0_r_dn_b, &tms340x0_device::move0_r_dn_a, &tms340x0_device::move0_r_dn_b, + &tms340x0_device::move0_r_dn_a, &tms340x0_device::move0_r_dn_b, &tms340x0_device::move0_r_dn_a, &tms340x0_device::move0_r_dn_b, &tms340x0_device::move0_r_dn_a, &tms340x0_device::move0_r_dn_b, &tms340x0_device::move0_r_dn_a, &tms340x0_device::move0_r_dn_b, + /* 0xa200 */ + &tms340x0_device::move1_r_dn_a, &tms340x0_device::move1_r_dn_b, &tms340x0_device::move1_r_dn_a, &tms340x0_device::move1_r_dn_b, &tms340x0_device::move1_r_dn_a, &tms340x0_device::move1_r_dn_b, &tms340x0_device::move1_r_dn_a, &tms340x0_device::move1_r_dn_b, + &tms340x0_device::move1_r_dn_a, &tms340x0_device::move1_r_dn_b, &tms340x0_device::move1_r_dn_a, &tms340x0_device::move1_r_dn_b, &tms340x0_device::move1_r_dn_a, &tms340x0_device::move1_r_dn_b, &tms340x0_device::move1_r_dn_a, &tms340x0_device::move1_r_dn_b, + /* 0xa300 */ + &tms340x0_device::move1_r_dn_a, &tms340x0_device::move1_r_dn_b, &tms340x0_device::move1_r_dn_a, &tms340x0_device::move1_r_dn_b, &tms340x0_device::move1_r_dn_a, &tms340x0_device::move1_r_dn_b, &tms340x0_device::move1_r_dn_a, &tms340x0_device::move1_r_dn_b, + &tms340x0_device::move1_r_dn_a, &tms340x0_device::move1_r_dn_b, &tms340x0_device::move1_r_dn_a, &tms340x0_device::move1_r_dn_b, &tms340x0_device::move1_r_dn_a, &tms340x0_device::move1_r_dn_b, &tms340x0_device::move1_r_dn_a, &tms340x0_device::move1_r_dn_b, + /* 0xa400 */ + &tms340x0_device::move0_dn_r_a, &tms340x0_device::move0_dn_r_b, &tms340x0_device::move0_dn_r_a, &tms340x0_device::move0_dn_r_b, &tms340x0_device::move0_dn_r_a, &tms340x0_device::move0_dn_r_b, &tms340x0_device::move0_dn_r_a, &tms340x0_device::move0_dn_r_b, + &tms340x0_device::move0_dn_r_a, &tms340x0_device::move0_dn_r_b, &tms340x0_device::move0_dn_r_a, &tms340x0_device::move0_dn_r_b, &tms340x0_device::move0_dn_r_a, &tms340x0_device::move0_dn_r_b, &tms340x0_device::move0_dn_r_a, &tms340x0_device::move0_dn_r_b, + /* 0xa500 */ + &tms340x0_device::move0_dn_r_a, &tms340x0_device::move0_dn_r_b, &tms340x0_device::move0_dn_r_a, &tms340x0_device::move0_dn_r_b, &tms340x0_device::move0_dn_r_a, &tms340x0_device::move0_dn_r_b, &tms340x0_device::move0_dn_r_a, &tms340x0_device::move0_dn_r_b, + &tms340x0_device::move0_dn_r_a, &tms340x0_device::move0_dn_r_b, &tms340x0_device::move0_dn_r_a, &tms340x0_device::move0_dn_r_b, &tms340x0_device::move0_dn_r_a, &tms340x0_device::move0_dn_r_b, &tms340x0_device::move0_dn_r_a, &tms340x0_device::move0_dn_r_b, + /* 0xa600 */ + &tms340x0_device::move1_dn_r_a, &tms340x0_device::move1_dn_r_b, &tms340x0_device::move1_dn_r_a, &tms340x0_device::move1_dn_r_b, &tms340x0_device::move1_dn_r_a, &tms340x0_device::move1_dn_r_b, &tms340x0_device::move1_dn_r_a, &tms340x0_device::move1_dn_r_b, + &tms340x0_device::move1_dn_r_a, &tms340x0_device::move1_dn_r_b, &tms340x0_device::move1_dn_r_a, &tms340x0_device::move1_dn_r_b, &tms340x0_device::move1_dn_r_a, &tms340x0_device::move1_dn_r_b, &tms340x0_device::move1_dn_r_a, &tms340x0_device::move1_dn_r_b, + /* 0xa700 */ + &tms340x0_device::move1_dn_r_a, &tms340x0_device::move1_dn_r_b, &tms340x0_device::move1_dn_r_a, &tms340x0_device::move1_dn_r_b, &tms340x0_device::move1_dn_r_a, &tms340x0_device::move1_dn_r_b, &tms340x0_device::move1_dn_r_a, &tms340x0_device::move1_dn_r_b, + &tms340x0_device::move1_dn_r_a, &tms340x0_device::move1_dn_r_b, &tms340x0_device::move1_dn_r_a, &tms340x0_device::move1_dn_r_b, &tms340x0_device::move1_dn_r_a, &tms340x0_device::move1_dn_r_b, &tms340x0_device::move1_dn_r_a, &tms340x0_device::move1_dn_r_b, + /* 0xa800 */ + &tms340x0_device::move0_dn_dn_a, &tms340x0_device::move0_dn_dn_b, &tms340x0_device::move0_dn_dn_a, &tms340x0_device::move0_dn_dn_b, &tms340x0_device::move0_dn_dn_a, &tms340x0_device::move0_dn_dn_b, &tms340x0_device::move0_dn_dn_a, &tms340x0_device::move0_dn_dn_b, + &tms340x0_device::move0_dn_dn_a, &tms340x0_device::move0_dn_dn_b, &tms340x0_device::move0_dn_dn_a, &tms340x0_device::move0_dn_dn_b, &tms340x0_device::move0_dn_dn_a, &tms340x0_device::move0_dn_dn_b, &tms340x0_device::move0_dn_dn_a, &tms340x0_device::move0_dn_dn_b, + /* 0xa900 */ + &tms340x0_device::move0_dn_dn_a, &tms340x0_device::move0_dn_dn_b, &tms340x0_device::move0_dn_dn_a, &tms340x0_device::move0_dn_dn_b, &tms340x0_device::move0_dn_dn_a, &tms340x0_device::move0_dn_dn_b, &tms340x0_device::move0_dn_dn_a, &tms340x0_device::move0_dn_dn_b, + &tms340x0_device::move0_dn_dn_a, &tms340x0_device::move0_dn_dn_b, &tms340x0_device::move0_dn_dn_a, &tms340x0_device::move0_dn_dn_b, &tms340x0_device::move0_dn_dn_a, &tms340x0_device::move0_dn_dn_b, &tms340x0_device::move0_dn_dn_a, &tms340x0_device::move0_dn_dn_b, + /* 0xaa00 */ + &tms340x0_device::move1_dn_dn_a, &tms340x0_device::move1_dn_dn_b, &tms340x0_device::move1_dn_dn_a, &tms340x0_device::move1_dn_dn_b, &tms340x0_device::move1_dn_dn_a, &tms340x0_device::move1_dn_dn_b, &tms340x0_device::move1_dn_dn_a, &tms340x0_device::move1_dn_dn_b, + &tms340x0_device::move1_dn_dn_a, &tms340x0_device::move1_dn_dn_b, &tms340x0_device::move1_dn_dn_a, &tms340x0_device::move1_dn_dn_b, &tms340x0_device::move1_dn_dn_a, &tms340x0_device::move1_dn_dn_b, &tms340x0_device::move1_dn_dn_a, &tms340x0_device::move1_dn_dn_b, + /* 0xab00 */ + &tms340x0_device::move1_dn_dn_a, &tms340x0_device::move1_dn_dn_b, &tms340x0_device::move1_dn_dn_a, &tms340x0_device::move1_dn_dn_b, &tms340x0_device::move1_dn_dn_a, &tms340x0_device::move1_dn_dn_b, &tms340x0_device::move1_dn_dn_a, &tms340x0_device::move1_dn_dn_b, + &tms340x0_device::move1_dn_dn_a, &tms340x0_device::move1_dn_dn_b, &tms340x0_device::move1_dn_dn_a, &tms340x0_device::move1_dn_dn_b, &tms340x0_device::move1_dn_dn_a, &tms340x0_device::move1_dn_dn_b, &tms340x0_device::move1_dn_dn_a, &tms340x0_device::move1_dn_dn_b, + /* 0xac00 */ + &tms340x0_device::movb_r_no_a, &tms340x0_device::movb_r_no_b, &tms340x0_device::movb_r_no_a, &tms340x0_device::movb_r_no_b, &tms340x0_device::movb_r_no_a, &tms340x0_device::movb_r_no_b, &tms340x0_device::movb_r_no_a, &tms340x0_device::movb_r_no_b, + &tms340x0_device::movb_r_no_a, &tms340x0_device::movb_r_no_b, &tms340x0_device::movb_r_no_a, &tms340x0_device::movb_r_no_b, &tms340x0_device::movb_r_no_a, &tms340x0_device::movb_r_no_b, &tms340x0_device::movb_r_no_a, &tms340x0_device::movb_r_no_b, + /* 0xad00 */ + &tms340x0_device::movb_r_no_a, &tms340x0_device::movb_r_no_b, &tms340x0_device::movb_r_no_a, &tms340x0_device::movb_r_no_b, &tms340x0_device::movb_r_no_a, &tms340x0_device::movb_r_no_b, &tms340x0_device::movb_r_no_a, &tms340x0_device::movb_r_no_b, + &tms340x0_device::movb_r_no_a, &tms340x0_device::movb_r_no_b, &tms340x0_device::movb_r_no_a, &tms340x0_device::movb_r_no_b, &tms340x0_device::movb_r_no_a, &tms340x0_device::movb_r_no_b, &tms340x0_device::movb_r_no_a, &tms340x0_device::movb_r_no_b, + /* 0xae00 */ + &tms340x0_device::movb_no_r_a, &tms340x0_device::movb_no_r_b, &tms340x0_device::movb_no_r_a, &tms340x0_device::movb_no_r_b, &tms340x0_device::movb_no_r_a, &tms340x0_device::movb_no_r_b, &tms340x0_device::movb_no_r_a, &tms340x0_device::movb_no_r_b, + &tms340x0_device::movb_no_r_a, &tms340x0_device::movb_no_r_b, &tms340x0_device::movb_no_r_a, &tms340x0_device::movb_no_r_b, &tms340x0_device::movb_no_r_a, &tms340x0_device::movb_no_r_b, &tms340x0_device::movb_no_r_a, &tms340x0_device::movb_no_r_b, + /* 0xaf00 */ + &tms340x0_device::movb_no_r_a, &tms340x0_device::movb_no_r_b, &tms340x0_device::movb_no_r_a, &tms340x0_device::movb_no_r_b, &tms340x0_device::movb_no_r_a, &tms340x0_device::movb_no_r_b, &tms340x0_device::movb_no_r_a, &tms340x0_device::movb_no_r_b, + &tms340x0_device::movb_no_r_a, &tms340x0_device::movb_no_r_b, &tms340x0_device::movb_no_r_a, &tms340x0_device::movb_no_r_b, &tms340x0_device::movb_no_r_a, &tms340x0_device::movb_no_r_b, &tms340x0_device::movb_no_r_a, &tms340x0_device::movb_no_r_b, + /* 0xb000 */ + &tms340x0_device::move0_r_no_a, &tms340x0_device::move0_r_no_b, &tms340x0_device::move0_r_no_a, &tms340x0_device::move0_r_no_b, &tms340x0_device::move0_r_no_a, &tms340x0_device::move0_r_no_b, &tms340x0_device::move0_r_no_a, &tms340x0_device::move0_r_no_b, + &tms340x0_device::move0_r_no_a, &tms340x0_device::move0_r_no_b, &tms340x0_device::move0_r_no_a, &tms340x0_device::move0_r_no_b, &tms340x0_device::move0_r_no_a, &tms340x0_device::move0_r_no_b, &tms340x0_device::move0_r_no_a, &tms340x0_device::move0_r_no_b, + /* 0xb100 */ + &tms340x0_device::move0_r_no_a, &tms340x0_device::move0_r_no_b, &tms340x0_device::move0_r_no_a, &tms340x0_device::move0_r_no_b, &tms340x0_device::move0_r_no_a, &tms340x0_device::move0_r_no_b, &tms340x0_device::move0_r_no_a, &tms340x0_device::move0_r_no_b, + &tms340x0_device::move0_r_no_a, &tms340x0_device::move0_r_no_b, &tms340x0_device::move0_r_no_a, &tms340x0_device::move0_r_no_b, &tms340x0_device::move0_r_no_a, &tms340x0_device::move0_r_no_b, &tms340x0_device::move0_r_no_a, &tms340x0_device::move0_r_no_b, + /* 0xb200 */ + &tms340x0_device::move1_r_no_a, &tms340x0_device::move1_r_no_b, &tms340x0_device::move1_r_no_a, &tms340x0_device::move1_r_no_b, &tms340x0_device::move1_r_no_a, &tms340x0_device::move1_r_no_b, &tms340x0_device::move1_r_no_a, &tms340x0_device::move1_r_no_b, + &tms340x0_device::move1_r_no_a, &tms340x0_device::move1_r_no_b, &tms340x0_device::move1_r_no_a, &tms340x0_device::move1_r_no_b, &tms340x0_device::move1_r_no_a, &tms340x0_device::move1_r_no_b, &tms340x0_device::move1_r_no_a, &tms340x0_device::move1_r_no_b, + /* 0xb300 */ + &tms340x0_device::move1_r_no_a, &tms340x0_device::move1_r_no_b, &tms340x0_device::move1_r_no_a, &tms340x0_device::move1_r_no_b, &tms340x0_device::move1_r_no_a, &tms340x0_device::move1_r_no_b, &tms340x0_device::move1_r_no_a, &tms340x0_device::move1_r_no_b, + &tms340x0_device::move1_r_no_a, &tms340x0_device::move1_r_no_b, &tms340x0_device::move1_r_no_a, &tms340x0_device::move1_r_no_b, &tms340x0_device::move1_r_no_a, &tms340x0_device::move1_r_no_b, &tms340x0_device::move1_r_no_a, &tms340x0_device::move1_r_no_b, + /* 0xb400 */ + &tms340x0_device::move0_no_r_a, &tms340x0_device::move0_no_r_b, &tms340x0_device::move0_no_r_a, &tms340x0_device::move0_no_r_b, &tms340x0_device::move0_no_r_a, &tms340x0_device::move0_no_r_b, &tms340x0_device::move0_no_r_a, &tms340x0_device::move0_no_r_b, + &tms340x0_device::move0_no_r_a, &tms340x0_device::move0_no_r_b, &tms340x0_device::move0_no_r_a, &tms340x0_device::move0_no_r_b, &tms340x0_device::move0_no_r_a, &tms340x0_device::move0_no_r_b, &tms340x0_device::move0_no_r_a, &tms340x0_device::move0_no_r_b, + /* 0xb500 */ + &tms340x0_device::move0_no_r_a, &tms340x0_device::move0_no_r_b, &tms340x0_device::move0_no_r_a, &tms340x0_device::move0_no_r_b, &tms340x0_device::move0_no_r_a, &tms340x0_device::move0_no_r_b, &tms340x0_device::move0_no_r_a, &tms340x0_device::move0_no_r_b, + &tms340x0_device::move0_no_r_a, &tms340x0_device::move0_no_r_b, &tms340x0_device::move0_no_r_a, &tms340x0_device::move0_no_r_b, &tms340x0_device::move0_no_r_a, &tms340x0_device::move0_no_r_b, &tms340x0_device::move0_no_r_a, &tms340x0_device::move0_no_r_b, + /* 0xb600 */ + &tms340x0_device::move1_no_r_a, &tms340x0_device::move1_no_r_b, &tms340x0_device::move1_no_r_a, &tms340x0_device::move1_no_r_b, &tms340x0_device::move1_no_r_a, &tms340x0_device::move1_no_r_b, &tms340x0_device::move1_no_r_a, &tms340x0_device::move1_no_r_b, + &tms340x0_device::move1_no_r_a, &tms340x0_device::move1_no_r_b, &tms340x0_device::move1_no_r_a, &tms340x0_device::move1_no_r_b, &tms340x0_device::move1_no_r_a, &tms340x0_device::move1_no_r_b, &tms340x0_device::move1_no_r_a, &tms340x0_device::move1_no_r_b, + /* 0xb700 */ + &tms340x0_device::move1_no_r_a, &tms340x0_device::move1_no_r_b, &tms340x0_device::move1_no_r_a, &tms340x0_device::move1_no_r_b, &tms340x0_device::move1_no_r_a, &tms340x0_device::move1_no_r_b, &tms340x0_device::move1_no_r_a, &tms340x0_device::move1_no_r_b, + &tms340x0_device::move1_no_r_a, &tms340x0_device::move1_no_r_b, &tms340x0_device::move1_no_r_a, &tms340x0_device::move1_no_r_b, &tms340x0_device::move1_no_r_a, &tms340x0_device::move1_no_r_b, &tms340x0_device::move1_no_r_a, &tms340x0_device::move1_no_r_b, + /* 0xb800 */ + &tms340x0_device::move0_no_no_a, &tms340x0_device::move0_no_no_b, &tms340x0_device::move0_no_no_a, &tms340x0_device::move0_no_no_b, &tms340x0_device::move0_no_no_a, &tms340x0_device::move0_no_no_b, &tms340x0_device::move0_no_no_a, &tms340x0_device::move0_no_no_b, + &tms340x0_device::move0_no_no_a, &tms340x0_device::move0_no_no_b, &tms340x0_device::move0_no_no_a, &tms340x0_device::move0_no_no_b, &tms340x0_device::move0_no_no_a, &tms340x0_device::move0_no_no_b, &tms340x0_device::move0_no_no_a, &tms340x0_device::move0_no_no_b, + /* 0xb900 */ + &tms340x0_device::move0_no_no_a, &tms340x0_device::move0_no_no_b, &tms340x0_device::move0_no_no_a, &tms340x0_device::move0_no_no_b, &tms340x0_device::move0_no_no_a, &tms340x0_device::move0_no_no_b, &tms340x0_device::move0_no_no_a, &tms340x0_device::move0_no_no_b, + &tms340x0_device::move0_no_no_a, &tms340x0_device::move0_no_no_b, &tms340x0_device::move0_no_no_a, &tms340x0_device::move0_no_no_b, &tms340x0_device::move0_no_no_a, &tms340x0_device::move0_no_no_b, &tms340x0_device::move0_no_no_a, &tms340x0_device::move0_no_no_b, + /* 0xba00 */ + &tms340x0_device::move1_no_no_a, &tms340x0_device::move1_no_no_b, &tms340x0_device::move1_no_no_a, &tms340x0_device::move1_no_no_b, &tms340x0_device::move1_no_no_a, &tms340x0_device::move1_no_no_b, &tms340x0_device::move1_no_no_a, &tms340x0_device::move1_no_no_b, + &tms340x0_device::move1_no_no_a, &tms340x0_device::move1_no_no_b, &tms340x0_device::move1_no_no_a, &tms340x0_device::move1_no_no_b, &tms340x0_device::move1_no_no_a, &tms340x0_device::move1_no_no_b, &tms340x0_device::move1_no_no_a, &tms340x0_device::move1_no_no_b, + /* 0xbb00 */ + &tms340x0_device::move1_no_no_a, &tms340x0_device::move1_no_no_b, &tms340x0_device::move1_no_no_a, &tms340x0_device::move1_no_no_b, &tms340x0_device::move1_no_no_a, &tms340x0_device::move1_no_no_b, &tms340x0_device::move1_no_no_a, &tms340x0_device::move1_no_no_b, + &tms340x0_device::move1_no_no_a, &tms340x0_device::move1_no_no_b, &tms340x0_device::move1_no_no_a, &tms340x0_device::move1_no_no_b, &tms340x0_device::move1_no_no_a, &tms340x0_device::move1_no_no_b, &tms340x0_device::move1_no_no_a, &tms340x0_device::move1_no_no_b, + /* 0xbc00 */ + &tms340x0_device::movb_no_no_a, &tms340x0_device::movb_no_no_b, &tms340x0_device::movb_no_no_a, &tms340x0_device::movb_no_no_b, &tms340x0_device::movb_no_no_a, &tms340x0_device::movb_no_no_b, &tms340x0_device::movb_no_no_a, &tms340x0_device::movb_no_no_b, + &tms340x0_device::movb_no_no_a, &tms340x0_device::movb_no_no_b, &tms340x0_device::movb_no_no_a, &tms340x0_device::movb_no_no_b, &tms340x0_device::movb_no_no_a, &tms340x0_device::movb_no_no_b, &tms340x0_device::movb_no_no_a, &tms340x0_device::movb_no_no_b, + /* 0xbd00 */ + &tms340x0_device::movb_no_no_a, &tms340x0_device::movb_no_no_b, &tms340x0_device::movb_no_no_a, &tms340x0_device::movb_no_no_b, &tms340x0_device::movb_no_no_a, &tms340x0_device::movb_no_no_b, &tms340x0_device::movb_no_no_a, &tms340x0_device::movb_no_no_b, + &tms340x0_device::movb_no_no_a, &tms340x0_device::movb_no_no_b, &tms340x0_device::movb_no_no_a, &tms340x0_device::movb_no_no_b, &tms340x0_device::movb_no_no_a, &tms340x0_device::movb_no_no_b, &tms340x0_device::movb_no_no_a, &tms340x0_device::movb_no_no_b, + /* 0xbe00 */ + &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, + &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, + /* 0xbf00 */ + &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, + &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, + /* 0xc000 */ + &tms340x0_device::j_UC_0, &tms340x0_device::j_UC_x, &tms340x0_device::j_UC_x, &tms340x0_device::j_UC_x, &tms340x0_device::j_UC_x, &tms340x0_device::j_UC_x, &tms340x0_device::j_UC_x, &tms340x0_device::j_UC_x, + &tms340x0_device::j_UC_8, &tms340x0_device::j_UC_x, &tms340x0_device::j_UC_x, &tms340x0_device::j_UC_x, &tms340x0_device::j_UC_x, &tms340x0_device::j_UC_x, &tms340x0_device::j_UC_x, &tms340x0_device::j_UC_x, + /* 0xc100 */ + &tms340x0_device::j_P_0, &tms340x0_device::j_P_x, &tms340x0_device::j_P_x, &tms340x0_device::j_P_x, &tms340x0_device::j_P_x, &tms340x0_device::j_P_x, &tms340x0_device::j_P_x, &tms340x0_device::j_P_x, + &tms340x0_device::j_P_8, &tms340x0_device::j_P_x, &tms340x0_device::j_P_x, &tms340x0_device::j_P_x, &tms340x0_device::j_P_x, &tms340x0_device::j_P_x, &tms340x0_device::j_P_x, &tms340x0_device::j_P_x, + /* 0xc200 */ + &tms340x0_device::j_LS_0, &tms340x0_device::j_LS_x, &tms340x0_device::j_LS_x, &tms340x0_device::j_LS_x, &tms340x0_device::j_LS_x, &tms340x0_device::j_LS_x, &tms340x0_device::j_LS_x, &tms340x0_device::j_LS_x, + &tms340x0_device::j_LS_8, &tms340x0_device::j_LS_x, &tms340x0_device::j_LS_x, &tms340x0_device::j_LS_x, &tms340x0_device::j_LS_x, &tms340x0_device::j_LS_x, &tms340x0_device::j_LS_x, &tms340x0_device::j_LS_x, + /* 0xc300 */ + &tms340x0_device::j_HI_0, &tms340x0_device::j_HI_x, &tms340x0_device::j_HI_x, &tms340x0_device::j_HI_x, &tms340x0_device::j_HI_x, &tms340x0_device::j_HI_x, &tms340x0_device::j_HI_x, &tms340x0_device::j_HI_x, + &tms340x0_device::j_HI_8, &tms340x0_device::j_HI_x, &tms340x0_device::j_HI_x, &tms340x0_device::j_HI_x, &tms340x0_device::j_HI_x, &tms340x0_device::j_HI_x, &tms340x0_device::j_HI_x, &tms340x0_device::j_HI_x, + /* 0xc400 */ + &tms340x0_device::j_LT_0, &tms340x0_device::j_LT_x, &tms340x0_device::j_LT_x, &tms340x0_device::j_LT_x, &tms340x0_device::j_LT_x, &tms340x0_device::j_LT_x, &tms340x0_device::j_LT_x, &tms340x0_device::j_LT_x, + &tms340x0_device::j_LT_8, &tms340x0_device::j_LT_x, &tms340x0_device::j_LT_x, &tms340x0_device::j_LT_x, &tms340x0_device::j_LT_x, &tms340x0_device::j_LT_x, &tms340x0_device::j_LT_x, &tms340x0_device::j_LT_x, + /* 0xc500 */ + &tms340x0_device::j_GE_0, &tms340x0_device::j_GE_x, &tms340x0_device::j_GE_x, &tms340x0_device::j_GE_x, &tms340x0_device::j_GE_x, &tms340x0_device::j_GE_x, &tms340x0_device::j_GE_x, &tms340x0_device::j_GE_x, + &tms340x0_device::j_GE_8, &tms340x0_device::j_GE_x, &tms340x0_device::j_GE_x, &tms340x0_device::j_GE_x, &tms340x0_device::j_GE_x, &tms340x0_device::j_GE_x, &tms340x0_device::j_GE_x, &tms340x0_device::j_GE_x, + /* 0xc600 */ + &tms340x0_device::j_LE_0, &tms340x0_device::j_LE_x, &tms340x0_device::j_LE_x, &tms340x0_device::j_LE_x, &tms340x0_device::j_LE_x, &tms340x0_device::j_LE_x, &tms340x0_device::j_LE_x, &tms340x0_device::j_LE_x, + &tms340x0_device::j_LE_8, &tms340x0_device::j_LE_x, &tms340x0_device::j_LE_x, &tms340x0_device::j_LE_x, &tms340x0_device::j_LE_x, &tms340x0_device::j_LE_x, &tms340x0_device::j_LE_x, &tms340x0_device::j_LE_x, + /* 0xc700 */ + &tms340x0_device::j_GT_0, &tms340x0_device::j_GT_x, &tms340x0_device::j_GT_x, &tms340x0_device::j_GT_x, &tms340x0_device::j_GT_x, &tms340x0_device::j_GT_x, &tms340x0_device::j_GT_x, &tms340x0_device::j_GT_x, + &tms340x0_device::j_GT_8, &tms340x0_device::j_GT_x, &tms340x0_device::j_GT_x, &tms340x0_device::j_GT_x, &tms340x0_device::j_GT_x, &tms340x0_device::j_GT_x, &tms340x0_device::j_GT_x, &tms340x0_device::j_GT_x, + /* 0xc800 */ + &tms340x0_device::j_C_0, &tms340x0_device::j_C_x, &tms340x0_device::j_C_x, &tms340x0_device::j_C_x, &tms340x0_device::j_C_x, &tms340x0_device::j_C_x, &tms340x0_device::j_C_x, &tms340x0_device::j_C_x, + &tms340x0_device::j_C_8, &tms340x0_device::j_C_x, &tms340x0_device::j_C_x, &tms340x0_device::j_C_x, &tms340x0_device::j_C_x, &tms340x0_device::j_C_x, &tms340x0_device::j_C_x, &tms340x0_device::j_C_x, + /* 0xc900 */ + &tms340x0_device::j_NC_0, &tms340x0_device::j_NC_x, &tms340x0_device::j_NC_x, &tms340x0_device::j_NC_x, &tms340x0_device::j_NC_x, &tms340x0_device::j_NC_x, &tms340x0_device::j_NC_x, &tms340x0_device::j_NC_x, + &tms340x0_device::j_NC_8, &tms340x0_device::j_NC_x, &tms340x0_device::j_NC_x, &tms340x0_device::j_NC_x, &tms340x0_device::j_NC_x, &tms340x0_device::j_NC_x, &tms340x0_device::j_NC_x, &tms340x0_device::j_NC_x, + /* 0xca00 */ + &tms340x0_device::j_EQ_0, &tms340x0_device::j_EQ_x, &tms340x0_device::j_EQ_x, &tms340x0_device::j_EQ_x, &tms340x0_device::j_EQ_x, &tms340x0_device::j_EQ_x, &tms340x0_device::j_EQ_x, &tms340x0_device::j_EQ_x, + &tms340x0_device::j_EQ_8, &tms340x0_device::j_EQ_x, &tms340x0_device::j_EQ_x, &tms340x0_device::j_EQ_x, &tms340x0_device::j_EQ_x, &tms340x0_device::j_EQ_x, &tms340x0_device::j_EQ_x, &tms340x0_device::j_EQ_x, + /* 0xcb00 */ + &tms340x0_device::j_NE_0, &tms340x0_device::j_NE_x, &tms340x0_device::j_NE_x, &tms340x0_device::j_NE_x, &tms340x0_device::j_NE_x, &tms340x0_device::j_NE_x, &tms340x0_device::j_NE_x, &tms340x0_device::j_NE_x, + &tms340x0_device::j_NE_8, &tms340x0_device::j_NE_x, &tms340x0_device::j_NE_x, &tms340x0_device::j_NE_x, &tms340x0_device::j_NE_x, &tms340x0_device::j_NE_x, &tms340x0_device::j_NE_x, &tms340x0_device::j_NE_x, + /* 0xcc00 */ + &tms340x0_device::j_V_0, &tms340x0_device::j_V_x, &tms340x0_device::j_V_x, &tms340x0_device::j_V_x, &tms340x0_device::j_V_x, &tms340x0_device::j_V_x, &tms340x0_device::j_V_x, &tms340x0_device::j_V_x, + &tms340x0_device::j_V_8, &tms340x0_device::j_V_x, &tms340x0_device::j_V_x, &tms340x0_device::j_V_x, &tms340x0_device::j_V_x, &tms340x0_device::j_V_x, &tms340x0_device::j_V_x, &tms340x0_device::j_V_x, + /* 0xcd00 */ + &tms340x0_device::j_NV_0, &tms340x0_device::j_NV_x, &tms340x0_device::j_NV_x, &tms340x0_device::j_NV_x, &tms340x0_device::j_NV_x, &tms340x0_device::j_NV_x, &tms340x0_device::j_NV_x, &tms340x0_device::j_NV_x, + &tms340x0_device::j_NV_8, &tms340x0_device::j_NV_x, &tms340x0_device::j_NV_x, &tms340x0_device::j_NV_x, &tms340x0_device::j_NV_x, &tms340x0_device::j_NV_x, &tms340x0_device::j_NV_x, &tms340x0_device::j_NV_x, + /* 0xce00 */ + &tms340x0_device::j_N_0, &tms340x0_device::j_N_x, &tms340x0_device::j_N_x, &tms340x0_device::j_N_x, &tms340x0_device::j_N_x, &tms340x0_device::j_N_x, &tms340x0_device::j_N_x, &tms340x0_device::j_N_x, + &tms340x0_device::j_N_8, &tms340x0_device::j_N_x, &tms340x0_device::j_N_x, &tms340x0_device::j_N_x, &tms340x0_device::j_N_x, &tms340x0_device::j_N_x, &tms340x0_device::j_N_x, &tms340x0_device::j_N_x, + /* 0xcf00 */ + &tms340x0_device::j_NN_0, &tms340x0_device::j_NN_x, &tms340x0_device::j_NN_x, &tms340x0_device::j_NN_x, &tms340x0_device::j_NN_x, &tms340x0_device::j_NN_x, &tms340x0_device::j_NN_x, &tms340x0_device::j_NN_x, + &tms340x0_device::j_NN_8, &tms340x0_device::j_NN_x, &tms340x0_device::j_NN_x, &tms340x0_device::j_NN_x, &tms340x0_device::j_NN_x, &tms340x0_device::j_NN_x, &tms340x0_device::j_NN_x, &tms340x0_device::j_NN_x, + /* 0xd000 */ + &tms340x0_device::move0_no_ni_a, &tms340x0_device::move0_no_ni_b, &tms340x0_device::move0_no_ni_a, &tms340x0_device::move0_no_ni_b, &tms340x0_device::move0_no_ni_a, &tms340x0_device::move0_no_ni_b, &tms340x0_device::move0_no_ni_a, &tms340x0_device::move0_no_ni_b, + &tms340x0_device::move0_no_ni_a, &tms340x0_device::move0_no_ni_b, &tms340x0_device::move0_no_ni_a, &tms340x0_device::move0_no_ni_b, &tms340x0_device::move0_no_ni_a, &tms340x0_device::move0_no_ni_b, &tms340x0_device::move0_no_ni_a, &tms340x0_device::move0_no_ni_b, + /* 0xd100 */ + &tms340x0_device::move0_no_ni_a, &tms340x0_device::move0_no_ni_b, &tms340x0_device::move0_no_ni_a, &tms340x0_device::move0_no_ni_b, &tms340x0_device::move0_no_ni_a, &tms340x0_device::move0_no_ni_b, &tms340x0_device::move0_no_ni_a, &tms340x0_device::move0_no_ni_b, + &tms340x0_device::move0_no_ni_a, &tms340x0_device::move0_no_ni_b, &tms340x0_device::move0_no_ni_a, &tms340x0_device::move0_no_ni_b, &tms340x0_device::move0_no_ni_a, &tms340x0_device::move0_no_ni_b, &tms340x0_device::move0_no_ni_a, &tms340x0_device::move0_no_ni_b, + /* 0xd200 */ + &tms340x0_device::move1_no_ni_a, &tms340x0_device::move1_no_ni_b, &tms340x0_device::move1_no_ni_a, &tms340x0_device::move1_no_ni_b, &tms340x0_device::move1_no_ni_a, &tms340x0_device::move1_no_ni_b, &tms340x0_device::move1_no_ni_a, &tms340x0_device::move1_no_ni_b, + &tms340x0_device::move1_no_ni_a, &tms340x0_device::move1_no_ni_b, &tms340x0_device::move1_no_ni_a, &tms340x0_device::move1_no_ni_b, &tms340x0_device::move1_no_ni_a, &tms340x0_device::move1_no_ni_b, &tms340x0_device::move1_no_ni_a, &tms340x0_device::move1_no_ni_b, + /* 0xd300 */ + &tms340x0_device::move1_no_ni_a, &tms340x0_device::move1_no_ni_b, &tms340x0_device::move1_no_ni_a, &tms340x0_device::move1_no_ni_b, &tms340x0_device::move1_no_ni_a, &tms340x0_device::move1_no_ni_b, &tms340x0_device::move1_no_ni_a, &tms340x0_device::move1_no_ni_b, + &tms340x0_device::move1_no_ni_a, &tms340x0_device::move1_no_ni_b, &tms340x0_device::move1_no_ni_a, &tms340x0_device::move1_no_ni_b, &tms340x0_device::move1_no_ni_a, &tms340x0_device::move1_no_ni_b, &tms340x0_device::move1_no_ni_a, &tms340x0_device::move1_no_ni_b, + /* 0xd400 */ + &tms340x0_device::move0_a_ni_a,&tms340x0_device::move0_a_ni_b,&tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, + &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, + /* 0xd500 */ + &tms340x0_device::exgf0_a, &tms340x0_device::exgf0_b, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, + &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, + /* 0xd600 */ + &tms340x0_device::move1_a_ni_a,&tms340x0_device::move1_a_ni_b,&tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, + &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, + /* 0xd700 */ + &tms340x0_device::exgf1_a, &tms340x0_device::exgf1_b, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, + &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, + /* 0xd800 */ + &tms340x0_device::cexec_s, &tms340x0_device::cexec_s, &tms340x0_device::cexec_s, &tms340x0_device::cexec_s, &tms340x0_device::cexec_s, &tms340x0_device::cexec_s, &tms340x0_device::cexec_s, &tms340x0_device::cexec_s, + &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, + /* 0xd900 */ + &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, + &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, + /* 0xda00 */ + &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, + &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, + /* 0xdb00 */ + &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, + &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, + /* 0xdc00 */ + &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, + &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, + /* 0xdd00 */ + &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, + &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, + /* 0xde00 */ + &tms340x0_device::unimpl, &tms340x0_device::fline, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, + &tms340x0_device::unimpl, &tms340x0_device::fline, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, + /* 0xdf00 */ + &tms340x0_device::unimpl, &tms340x0_device::line, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, + &tms340x0_device::unimpl, &tms340x0_device::line, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, + /* 0xe000 */ + &tms340x0_device::add_xy_a, &tms340x0_device::add_xy_b, &tms340x0_device::add_xy_a, &tms340x0_device::add_xy_b, &tms340x0_device::add_xy_a, &tms340x0_device::add_xy_b, &tms340x0_device::add_xy_a, &tms340x0_device::add_xy_b, + &tms340x0_device::add_xy_a, &tms340x0_device::add_xy_b, &tms340x0_device::add_xy_a, &tms340x0_device::add_xy_b, &tms340x0_device::add_xy_a, &tms340x0_device::add_xy_b, &tms340x0_device::add_xy_a, &tms340x0_device::add_xy_b, + /* 0xe100 */ + &tms340x0_device::add_xy_a, &tms340x0_device::add_xy_b, &tms340x0_device::add_xy_a, &tms340x0_device::add_xy_b, &tms340x0_device::add_xy_a, &tms340x0_device::add_xy_b, &tms340x0_device::add_xy_a, &tms340x0_device::add_xy_b, + &tms340x0_device::add_xy_a, &tms340x0_device::add_xy_b, &tms340x0_device::add_xy_a, &tms340x0_device::add_xy_b, &tms340x0_device::add_xy_a, &tms340x0_device::add_xy_b, &tms340x0_device::add_xy_a, &tms340x0_device::add_xy_b, + /* 0xe200 */ + &tms340x0_device::sub_xy_a, &tms340x0_device::sub_xy_b, &tms340x0_device::sub_xy_a, &tms340x0_device::sub_xy_b, &tms340x0_device::sub_xy_a, &tms340x0_device::sub_xy_b, &tms340x0_device::sub_xy_a, &tms340x0_device::sub_xy_b, + &tms340x0_device::sub_xy_a, &tms340x0_device::sub_xy_b, &tms340x0_device::sub_xy_a, &tms340x0_device::sub_xy_b, &tms340x0_device::sub_xy_a, &tms340x0_device::sub_xy_b, &tms340x0_device::sub_xy_a, &tms340x0_device::sub_xy_b, + /* 0xe300 */ + &tms340x0_device::sub_xy_a, &tms340x0_device::sub_xy_b, &tms340x0_device::sub_xy_a, &tms340x0_device::sub_xy_b, &tms340x0_device::sub_xy_a, &tms340x0_device::sub_xy_b, &tms340x0_device::sub_xy_a, &tms340x0_device::sub_xy_b, + &tms340x0_device::sub_xy_a, &tms340x0_device::sub_xy_b, &tms340x0_device::sub_xy_a, &tms340x0_device::sub_xy_b, &tms340x0_device::sub_xy_a, &tms340x0_device::sub_xy_b, &tms340x0_device::sub_xy_a, &tms340x0_device::sub_xy_b, + /* 0xe400 */ + &tms340x0_device::cmp_xy_a, &tms340x0_device::cmp_xy_b, &tms340x0_device::cmp_xy_a, &tms340x0_device::cmp_xy_b, &tms340x0_device::cmp_xy_a, &tms340x0_device::cmp_xy_b, &tms340x0_device::cmp_xy_a, &tms340x0_device::cmp_xy_b, + &tms340x0_device::cmp_xy_a, &tms340x0_device::cmp_xy_b, &tms340x0_device::cmp_xy_a, &tms340x0_device::cmp_xy_b, &tms340x0_device::cmp_xy_a, &tms340x0_device::cmp_xy_b, &tms340x0_device::cmp_xy_a, &tms340x0_device::cmp_xy_b, + /* 0xe500 */ + &tms340x0_device::cmp_xy_a, &tms340x0_device::cmp_xy_b, &tms340x0_device::cmp_xy_a, &tms340x0_device::cmp_xy_b, &tms340x0_device::cmp_xy_a, &tms340x0_device::cmp_xy_b, &tms340x0_device::cmp_xy_a, &tms340x0_device::cmp_xy_b, + &tms340x0_device::cmp_xy_a, &tms340x0_device::cmp_xy_b, &tms340x0_device::cmp_xy_a, &tms340x0_device::cmp_xy_b, &tms340x0_device::cmp_xy_a, &tms340x0_device::cmp_xy_b, &tms340x0_device::cmp_xy_a, &tms340x0_device::cmp_xy_b, + /* 0xe600 */ + &tms340x0_device::cpw_a, &tms340x0_device::cpw_b, &tms340x0_device::cpw_a, &tms340x0_device::cpw_b, &tms340x0_device::cpw_a, &tms340x0_device::cpw_b, &tms340x0_device::cpw_a, &tms340x0_device::cpw_b, + &tms340x0_device::cpw_a, &tms340x0_device::cpw_b, &tms340x0_device::cpw_a, &tms340x0_device::cpw_b, &tms340x0_device::cpw_a, &tms340x0_device::cpw_b, &tms340x0_device::cpw_a, &tms340x0_device::cpw_b, + /* 0xe700 */ + &tms340x0_device::cpw_a, &tms340x0_device::cpw_b, &tms340x0_device::cpw_a, &tms340x0_device::cpw_b, &tms340x0_device::cpw_a, &tms340x0_device::cpw_b, &tms340x0_device::cpw_a, &tms340x0_device::cpw_b, + &tms340x0_device::cpw_a, &tms340x0_device::cpw_b, &tms340x0_device::cpw_a, &tms340x0_device::cpw_b, &tms340x0_device::cpw_a, &tms340x0_device::cpw_b, &tms340x0_device::cpw_a, &tms340x0_device::cpw_b, + /* 0xe800 */ + &tms340x0_device::cvxyl_a, &tms340x0_device::cvxyl_b, &tms340x0_device::cvxyl_a, &tms340x0_device::cvxyl_b, &tms340x0_device::cvxyl_a, &tms340x0_device::cvxyl_b, &tms340x0_device::cvxyl_a, &tms340x0_device::cvxyl_b, + &tms340x0_device::cvxyl_a, &tms340x0_device::cvxyl_b, &tms340x0_device::cvxyl_a, &tms340x0_device::cvxyl_b, &tms340x0_device::cvxyl_a, &tms340x0_device::cvxyl_b, &tms340x0_device::cvxyl_a, &tms340x0_device::cvxyl_b, + /* 0xe900 */ + &tms340x0_device::cvxyl_a, &tms340x0_device::cvxyl_b, &tms340x0_device::cvxyl_a, &tms340x0_device::cvxyl_b, &tms340x0_device::cvxyl_a, &tms340x0_device::cvxyl_b, &tms340x0_device::cvxyl_a, &tms340x0_device::cvxyl_b, + &tms340x0_device::cvxyl_a, &tms340x0_device::cvxyl_b, &tms340x0_device::cvxyl_a, &tms340x0_device::cvxyl_b, &tms340x0_device::cvxyl_a, &tms340x0_device::cvxyl_b, &tms340x0_device::cvxyl_a, &tms340x0_device::cvxyl_b, + /* 0xea00 */ + &tms340x0_device::cvsxyl_a, &tms340x0_device::cvsxyl_b, &tms340x0_device::cvsxyl_a, &tms340x0_device::cvsxyl_b, &tms340x0_device::cvsxyl_a, &tms340x0_device::cvsxyl_b, &tms340x0_device::cvsxyl_a, &tms340x0_device::cvsxyl_b, + &tms340x0_device::cvsxyl_a, &tms340x0_device::cvsxyl_b, &tms340x0_device::cvsxyl_a, &tms340x0_device::cvsxyl_b, &tms340x0_device::cvsxyl_a, &tms340x0_device::cvsxyl_b, &tms340x0_device::cvsxyl_a, &tms340x0_device::cvsxyl_b, + /* 0xeb00 */ + &tms340x0_device::cvsxyl_a, &tms340x0_device::cvsxyl_b, &tms340x0_device::cvsxyl_a, &tms340x0_device::cvsxyl_b, &tms340x0_device::cvsxyl_a, &tms340x0_device::cvsxyl_b, &tms340x0_device::cvsxyl_a, &tms340x0_device::cvsxyl_b, + &tms340x0_device::cvsxyl_a, &tms340x0_device::cvsxyl_b, &tms340x0_device::cvsxyl_a, &tms340x0_device::cvsxyl_b, &tms340x0_device::cvsxyl_a, &tms340x0_device::cvsxyl_b, &tms340x0_device::cvsxyl_a, &tms340x0_device::cvsxyl_b, + /* 0xec00 */ + &tms340x0_device::movx_a, &tms340x0_device::movx_b, &tms340x0_device::movx_a, &tms340x0_device::movx_b, &tms340x0_device::movx_a, &tms340x0_device::movx_b, &tms340x0_device::movx_a, &tms340x0_device::movx_b, + &tms340x0_device::movx_a, &tms340x0_device::movx_b, &tms340x0_device::movx_a, &tms340x0_device::movx_b, &tms340x0_device::movx_a, &tms340x0_device::movx_b, &tms340x0_device::movx_a, &tms340x0_device::movx_b, + /* 0xed00 */ + &tms340x0_device::movx_a, &tms340x0_device::movx_b, &tms340x0_device::movx_a, &tms340x0_device::movx_b, &tms340x0_device::movx_a, &tms340x0_device::movx_b, &tms340x0_device::movx_a, &tms340x0_device::movx_b, + &tms340x0_device::movx_a, &tms340x0_device::movx_b, &tms340x0_device::movx_a, &tms340x0_device::movx_b, &tms340x0_device::movx_a, &tms340x0_device::movx_b, &tms340x0_device::movx_a, &tms340x0_device::movx_b, + /* 0xee00 */ + &tms340x0_device::movy_a, &tms340x0_device::movy_b, &tms340x0_device::movy_a, &tms340x0_device::movy_b, &tms340x0_device::movy_a, &tms340x0_device::movy_b, &tms340x0_device::movy_a, &tms340x0_device::movy_b, + &tms340x0_device::movy_a, &tms340x0_device::movy_b, &tms340x0_device::movy_a, &tms340x0_device::movy_b, &tms340x0_device::movy_a, &tms340x0_device::movy_b, &tms340x0_device::movy_a, &tms340x0_device::movy_b, + /* 0xef00 */ + &tms340x0_device::movy_a, &tms340x0_device::movy_b, &tms340x0_device::movy_a, &tms340x0_device::movy_b, &tms340x0_device::movy_a, &tms340x0_device::movy_b, &tms340x0_device::movy_a, &tms340x0_device::movy_b, + &tms340x0_device::movy_a, &tms340x0_device::movy_b, &tms340x0_device::movy_a, &tms340x0_device::movy_b, &tms340x0_device::movy_a, &tms340x0_device::movy_b, &tms340x0_device::movy_a, &tms340x0_device::movy_b, + /* 0xf000 */ + &tms340x0_device::pixt_rixy_a, &tms340x0_device::pixt_rixy_b, &tms340x0_device::pixt_rixy_a, &tms340x0_device::pixt_rixy_b, &tms340x0_device::pixt_rixy_a, &tms340x0_device::pixt_rixy_b, &tms340x0_device::pixt_rixy_a, &tms340x0_device::pixt_rixy_b, + &tms340x0_device::pixt_rixy_a, &tms340x0_device::pixt_rixy_b, &tms340x0_device::pixt_rixy_a, &tms340x0_device::pixt_rixy_b, &tms340x0_device::pixt_rixy_a, &tms340x0_device::pixt_rixy_b, &tms340x0_device::pixt_rixy_a, &tms340x0_device::pixt_rixy_b, + /* 0xf100 */ + &tms340x0_device::pixt_rixy_a, &tms340x0_device::pixt_rixy_b, &tms340x0_device::pixt_rixy_a, &tms340x0_device::pixt_rixy_b, &tms340x0_device::pixt_rixy_a, &tms340x0_device::pixt_rixy_b, &tms340x0_device::pixt_rixy_a, &tms340x0_device::pixt_rixy_b, + &tms340x0_device::pixt_rixy_a, &tms340x0_device::pixt_rixy_b, &tms340x0_device::pixt_rixy_a, &tms340x0_device::pixt_rixy_b, &tms340x0_device::pixt_rixy_a, &tms340x0_device::pixt_rixy_b, &tms340x0_device::pixt_rixy_a, &tms340x0_device::pixt_rixy_b, + /* 0xf200 */ + &tms340x0_device::pixt_ixyr_a, &tms340x0_device::pixt_ixyr_b, &tms340x0_device::pixt_ixyr_a, &tms340x0_device::pixt_ixyr_b, &tms340x0_device::pixt_ixyr_a, &tms340x0_device::pixt_ixyr_b, &tms340x0_device::pixt_ixyr_a, &tms340x0_device::pixt_ixyr_b, + &tms340x0_device::pixt_ixyr_a, &tms340x0_device::pixt_ixyr_b, &tms340x0_device::pixt_ixyr_a, &tms340x0_device::pixt_ixyr_b, &tms340x0_device::pixt_ixyr_a, &tms340x0_device::pixt_ixyr_b, &tms340x0_device::pixt_ixyr_a, &tms340x0_device::pixt_ixyr_b, + /* 0xf300 */ + &tms340x0_device::pixt_ixyr_a, &tms340x0_device::pixt_ixyr_b, &tms340x0_device::pixt_ixyr_a, &tms340x0_device::pixt_ixyr_b, &tms340x0_device::pixt_ixyr_a, &tms340x0_device::pixt_ixyr_b, &tms340x0_device::pixt_ixyr_a, &tms340x0_device::pixt_ixyr_b, + &tms340x0_device::pixt_ixyr_a, &tms340x0_device::pixt_ixyr_b, &tms340x0_device::pixt_ixyr_a, &tms340x0_device::pixt_ixyr_b, &tms340x0_device::pixt_ixyr_a, &tms340x0_device::pixt_ixyr_b, &tms340x0_device::pixt_ixyr_a, &tms340x0_device::pixt_ixyr_b, + /* 0xf400 */ + &tms340x0_device::pixt_ixyixy_a, &tms340x0_device::pixt_ixyixy_b, &tms340x0_device::pixt_ixyixy_a, &tms340x0_device::pixt_ixyixy_b, &tms340x0_device::pixt_ixyixy_a, &tms340x0_device::pixt_ixyixy_b, &tms340x0_device::pixt_ixyixy_a, &tms340x0_device::pixt_ixyixy_b, + &tms340x0_device::pixt_ixyixy_a, &tms340x0_device::pixt_ixyixy_b, &tms340x0_device::pixt_ixyixy_a, &tms340x0_device::pixt_ixyixy_b, &tms340x0_device::pixt_ixyixy_a, &tms340x0_device::pixt_ixyixy_b, &tms340x0_device::pixt_ixyixy_a, &tms340x0_device::pixt_ixyixy_b, + /* 0xf500 */ + &tms340x0_device::pixt_ixyixy_a, &tms340x0_device::pixt_ixyixy_b, &tms340x0_device::pixt_ixyixy_a, &tms340x0_device::pixt_ixyixy_b, &tms340x0_device::pixt_ixyixy_a, &tms340x0_device::pixt_ixyixy_b, &tms340x0_device::pixt_ixyixy_a, &tms340x0_device::pixt_ixyixy_b, + &tms340x0_device::pixt_ixyixy_a, &tms340x0_device::pixt_ixyixy_b, &tms340x0_device::pixt_ixyixy_a, &tms340x0_device::pixt_ixyixy_b, &tms340x0_device::pixt_ixyixy_a, &tms340x0_device::pixt_ixyixy_b, &tms340x0_device::pixt_ixyixy_a, &tms340x0_device::pixt_ixyixy_b, + /* 0xf600 */ + &tms340x0_device::drav_a, &tms340x0_device::drav_b, &tms340x0_device::drav_a, &tms340x0_device::drav_b, &tms340x0_device::drav_a, &tms340x0_device::drav_b, &tms340x0_device::drav_a, &tms340x0_device::drav_b, + &tms340x0_device::drav_a, &tms340x0_device::drav_b, &tms340x0_device::drav_a, &tms340x0_device::drav_b, &tms340x0_device::drav_a, &tms340x0_device::drav_b, &tms340x0_device::drav_a, &tms340x0_device::drav_b, + /* 0xf700 */ + &tms340x0_device::drav_a, &tms340x0_device::drav_b, &tms340x0_device::drav_a, &tms340x0_device::drav_b, &tms340x0_device::drav_a, &tms340x0_device::drav_b, &tms340x0_device::drav_a, &tms340x0_device::drav_b, + &tms340x0_device::drav_a, &tms340x0_device::drav_b, &tms340x0_device::drav_a, &tms340x0_device::drav_b, &tms340x0_device::drav_a, &tms340x0_device::drav_b, &tms340x0_device::drav_a, &tms340x0_device::drav_b, + /* 0xf800 */ + &tms340x0_device::pixt_ri_a, &tms340x0_device::pixt_ri_b, &tms340x0_device::pixt_ri_a, &tms340x0_device::pixt_ri_b, &tms340x0_device::pixt_ri_a, &tms340x0_device::pixt_ri_b, &tms340x0_device::pixt_ri_a, &tms340x0_device::pixt_ri_b, + &tms340x0_device::pixt_ri_a, &tms340x0_device::pixt_ri_b, &tms340x0_device::pixt_ri_a, &tms340x0_device::pixt_ri_b, &tms340x0_device::pixt_ri_a, &tms340x0_device::pixt_ri_b, &tms340x0_device::pixt_ri_a, &tms340x0_device::pixt_ri_b, + /* 0xf900 */ + &tms340x0_device::pixt_ri_a, &tms340x0_device::pixt_ri_b, &tms340x0_device::pixt_ri_a, &tms340x0_device::pixt_ri_b, &tms340x0_device::pixt_ri_a, &tms340x0_device::pixt_ri_b, &tms340x0_device::pixt_ri_a, &tms340x0_device::pixt_ri_b, + &tms340x0_device::pixt_ri_a, &tms340x0_device::pixt_ri_b, &tms340x0_device::pixt_ri_a, &tms340x0_device::pixt_ri_b, &tms340x0_device::pixt_ri_a, &tms340x0_device::pixt_ri_b, &tms340x0_device::pixt_ri_a, &tms340x0_device::pixt_ri_b, + /* 0xfa00 */ + &tms340x0_device::pixt_ir_a, &tms340x0_device::pixt_ir_b, &tms340x0_device::pixt_ir_a, &tms340x0_device::pixt_ir_b, &tms340x0_device::pixt_ir_a, &tms340x0_device::pixt_ir_b, &tms340x0_device::pixt_ir_a, &tms340x0_device::pixt_ir_b, + &tms340x0_device::pixt_ir_a, &tms340x0_device::pixt_ir_b, &tms340x0_device::pixt_ir_a, &tms340x0_device::pixt_ir_b, &tms340x0_device::pixt_ir_a, &tms340x0_device::pixt_ir_b, &tms340x0_device::pixt_ir_a, &tms340x0_device::pixt_ir_b, + /* 0xfb00 */ + &tms340x0_device::pixt_ir_a, &tms340x0_device::pixt_ir_b, &tms340x0_device::pixt_ir_a, &tms340x0_device::pixt_ir_b, &tms340x0_device::pixt_ir_a, &tms340x0_device::pixt_ir_b, &tms340x0_device::pixt_ir_a, &tms340x0_device::pixt_ir_b, + &tms340x0_device::pixt_ir_a, &tms340x0_device::pixt_ir_b, &tms340x0_device::pixt_ir_a, &tms340x0_device::pixt_ir_b, &tms340x0_device::pixt_ir_a, &tms340x0_device::pixt_ir_b, &tms340x0_device::pixt_ir_a, &tms340x0_device::pixt_ir_b, + /* 0xfc00 */ + &tms340x0_device::pixt_ii_a, &tms340x0_device::pixt_ii_b, &tms340x0_device::pixt_ii_a, &tms340x0_device::pixt_ii_b, &tms340x0_device::pixt_ii_a, &tms340x0_device::pixt_ii_b, &tms340x0_device::pixt_ii_a, &tms340x0_device::pixt_ii_b, + &tms340x0_device::pixt_ii_a, &tms340x0_device::pixt_ii_b, &tms340x0_device::pixt_ii_a, &tms340x0_device::pixt_ii_b, &tms340x0_device::pixt_ii_a, &tms340x0_device::pixt_ii_b, &tms340x0_device::pixt_ii_a, &tms340x0_device::pixt_ii_b, + /* 0xfd00 */ + &tms340x0_device::pixt_ii_a, &tms340x0_device::pixt_ii_b, &tms340x0_device::pixt_ii_a, &tms340x0_device::pixt_ii_b, &tms340x0_device::pixt_ii_a, &tms340x0_device::pixt_ii_b, &tms340x0_device::pixt_ii_a, &tms340x0_device::pixt_ii_b, + &tms340x0_device::pixt_ii_a, &tms340x0_device::pixt_ii_b, &tms340x0_device::pixt_ii_a, &tms340x0_device::pixt_ii_b, &tms340x0_device::pixt_ii_a, &tms340x0_device::pixt_ii_b, &tms340x0_device::pixt_ii_a, &tms340x0_device::pixt_ii_b, + /* 0xfe00 */ + &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, + &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, + /* 0xff00 */ + &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, + &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl, &tms340x0_device::unimpl +}; diff --git a/src/devices/cpu/tms34010/dis34010.c b/src/devices/cpu/tms34010/dis34010.c new file mode 100644 index 00000000000..19e3338a7d2 --- /dev/null +++ b/src/devices/cpu/tms34010/dis34010.c @@ -0,0 +1,115 @@ +// license:BSD-3-Clause +// copyright-holders:Zsolt Vasvari +/* This program is based on DIS68k by Aaron Giles */ + +#include "emu.h" + +static UINT8 *filebuf; +static UINT32 offset; + +#define STANDALONE +#include "34010dsm.c" + + +static const char *const Options[]= +{ + "begin","end","offset",0 +}; + +static void usage (void) +{ + printf ("Usage: DIS34010 [options] \n" + "Available options are:\n" + " -begin - Specify begin offset in file to disassemble in bits [0]\n" + " -end - Specify end offset in file to disassemble in bits [none]\n" + " -offset - Specify address to load program in bits [0]\n" + "All values should be entered in hexadecimal\n"); + exit (1); +} + +int main (int argc,char *argv[]) +{ + UINT8 i,j,n; + char *filename=0,buf[80]; + FILE *f; + UINT32 begin=0,end=(UINT32)-1,filelen,len,pc; + printf ("DIS34010\n" + "Copyright Zsolt Vasvari/Aaron Giles\n"); + + for (i=1,n=0;iargc) usage(); + begin=strtoul(argv[i],0,16) >> 3; + break; + case 1: ++i; if (i>argc) usage(); + end=strtoul(argv[i],0,16) >> 3; + break; + case 2: ++i; if (i>argc) usage(); + offset=strtoul(argv[i],0,16) >> 3; + break; + default: usage(); + } + } + } + + if (!filename) + { + usage(); + return 1; + } + f=fopen (filename,"rb"); + if (!f) + { + printf ("Unable to open %s\n",filename); + return 2; + } + fseek (f,0,SEEK_END); + filelen=ftell (f); + fseek (f,begin,SEEK_SET); + len=(filelen>end)? (end-begin+1):(filelen-begin); + filebuf=malloc(len+16); + if (!filebuf) + { + printf ("Memory allocation error\n"); + fclose (f); + return 3; + } + memset (filebuf,0,len+16); + if (fread(filebuf,1,len,f)!=len) + { + printf ("Read error\n"); + fclose (f); + free (filebuf); + return 4; + } + fclose (f); + pc=0; + while (pc>3; + + printf ("%08X: ",(pc+offset) << 3); + for (j=0;j; +const device_type TMS34020 = &device_creator; + + +/*************************************************************************** + GLOBAL VARIABLES +***************************************************************************/ + +tms340x0_device::tms340x0_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname) + : cpu_device(mconfig, type, name, tag, owner, clock, shortname, __FILE__) + , device_video_interface(mconfig, *this) + , m_program_config("program", ENDIANNESS_LITTLE, 16, 32, 3) + , m_halt_on_reset(FALSE) + , m_pixclock(0) + , m_pixperclock(0) + , m_output_int_cb(*this) +{ +} + + +tms34010_device::tms34010_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : tms340x0_device(mconfig, TMS34010, "TMS34010", tag, owner, clock, "tms34010") +{ + m_is_34020 = 0; +} + + +tms34020_device::tms34020_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : tms340x0_device(mconfig, TMS34020, "TMS34020", tag, owner, clock, "tms34020") +{ + m_is_34020 = 1; +} + + +#include "34010ops.h" + + +/*************************************************************************** + MACROS +***************************************************************************/ + +/* status register definitions */ +#define STBIT_N (1 << 31) +#define STBIT_C (1 << 30) +#define STBIT_Z (1 << 29) +#define STBIT_V (1 << 28) +#define STBIT_P (1 << 25) +#define STBIT_IE (1 << 21) +#define STBIT_FE1 (1 << 11) +#define STBITS_F1 (0x1f << 6) +#define STBIT_FE0 (1 << 5) +#define STBITS_F0 (0x1f << 0) + +/* register definitions and shortcuts */ +#define N_FLAG() (m_st & STBIT_N) +#define Z_FLAG() (m_st & STBIT_Z) +#define C_FLAG() (m_st & STBIT_C) +#define V_FLAG() (m_st & STBIT_V) +#define P_FLAG() (m_st & STBIT_P) +#define IE_FLAG() (m_st & STBIT_IE) +#define FE0_FLAG() (m_st & STBIT_FE0) +#define FE1_FLAG() (m_st & STBIT_FE1) + +/* register file access */ +#define AREG(i) (m_regs[i].reg) +#define AREG_XY(i) (m_regs[i].xy) +#define AREG_X(i) (m_regs[i].xy.x) +#define AREG_Y(i) (m_regs[i].xy.y) +#define BREG(i) (m_regs[30 - (i)].reg) +#define BREG_XY(i) (m_regs[30 - (i)].xy) +#define BREG_X(i) (m_regs[30 - (i)].xy.x) +#define BREG_Y(i) (m_regs[30 - (i)].xy.y) +#define SP() AREG(15) +#define FW(i) ((m_st >> (i ? 6 : 0)) & 0x1f) +#define FWEX(i) ((m_st >> (i ? 6 : 0)) & 0x3f) + +/* opcode decode helpers */ +#define SRCREG(O) (((O) >> 5) & 0x0f) +#define DSTREG(O) ((O) & 0x0f) +#define SKIP_WORD() (m_pc += (2 << 3)) +#define SKIP_LONG() (m_pc += (4 << 3)) +#define PARAM_K(O) (((O) >> 5) & 0x1f) +#define PARAM_N(O) ((O) & 0x1f) +#define PARAM_REL8(O) ((INT8)(O)) + +/* memory I/O */ +#define WFIELD0(a,b) (this->*s_wfield_functions[FW(0)])(a,b) +#define WFIELD1(a,b) (this->*s_wfield_functions[FW(1)])(a,b) +#define RFIELD0(a) (this->*s_rfield_functions[FWEX(0)])(a) +#define RFIELD1(a) (this->*s_rfield_functions[FWEX(1)])(a) +#define WPIXEL(a,b) (this->*m_pixel_write)(a,b) +#define RPIXEL(a) (this->*m_pixel_read)(a) + +/* Implied Operands */ +#define SADDR() BREG(0) +#define SADDR_X() BREG_X(0) +#define SADDR_Y() BREG_Y(0) +#define SADDR_XY() BREG_XY(0) +#define SPTCH() BREG(1) +#define DADDR() BREG(2) +#define DADDR_X() BREG_X(2) +#define DADDR_Y() BREG_Y(2) +#define DADDR_XY() BREG_XY(2) +#define DPTCH() BREG(3) +#define OFFSET() BREG(4) +#define WSTART_X() BREG_X(5) +#define WSTART_Y() BREG_Y(5) +#define WEND_X() BREG_X(6) +#define WEND_Y() BREG_Y(6) +#define DYDX_X() BREG_X(7) +#define DYDX_Y() BREG_Y(7) +#define COLOR0() BREG(8) +#define COLOR1() BREG(9) +#define COUNT() BREG(10) +#define INC1_X() BREG_X(11) +#define INC1_Y() BREG_Y(11) +#define INC2_X() BREG_X(12) +#define INC2_Y() BREG_Y(12) +#define PATTRN() BREG(13) +#define TEMP() BREG(14) + +/* I/O registers */ +#define WINDOW_CHECKING() ((IOREG(REG_CONTROL) >> 6) & 0x03) + + + +/*************************************************************************** + INLINE SHORTCUTS +***************************************************************************/ + +/* Break up Status Register into indiviual flags */ +inline void tms340x0_device::SET_ST(UINT32 st) +{ + m_st = st; + /* interrupts might have been enabled, check it */ + check_interrupt(); +} + +/* Intialize Status to 0x0010 */ +inline void tms340x0_device::RESET_ST() +{ + SET_ST(0x00000010); +} + +/* shortcuts for reading opcodes */ +inline UINT32 tms340x0_device::ROPCODE() +{ + UINT32 pc = TOBYTE(m_pc); + m_pc += 2 << 3; + return m_direct->read_word(pc); +} + +inline INT16 tms340x0_device::PARAM_WORD() +{ + UINT32 pc = TOBYTE(m_pc); + m_pc += 2 << 3; + return m_direct->read_word(pc); +} + +inline INT32 tms340x0_device::PARAM_LONG() +{ + UINT32 pc = TOBYTE(m_pc); + m_pc += 4 << 3; + return (UINT16)m_direct->read_word(pc) | (m_direct->read_word(pc + 2) << 16); +} + +inline INT16 tms340x0_device::PARAM_WORD_NO_INC() +{ + return m_direct->read_word(TOBYTE(m_pc)); +} + +inline INT32 tms340x0_device::PARAM_LONG_NO_INC() +{ + UINT32 pc = TOBYTE(m_pc); + return (UINT16)m_direct->read_word(pc) | (m_direct->read_word(pc + 2) << 16); +} + +/* read memory byte */ +inline UINT32 tms340x0_device::RBYTE(offs_t offset) +{ + UINT32 ret; + RFIELDMAC_8(); + return ret; +} + +/* write memory byte */ +inline void tms340x0_device::WBYTE(offs_t offset, UINT32 data) +{ + WFIELDMAC_8(); +} + +/* read memory long */ +inline UINT32 tms340x0_device::RLONG(offs_t offset) +{ + RFIELDMAC_32(); +} + +/* write memory long */ +inline void tms340x0_device::WLONG(offs_t offset, UINT32 data) +{ + WFIELDMAC_32(); +} + +/* pushes/pops a value from the stack */ +inline void tms340x0_device::PUSH(UINT32 data) +{ + SP() -= 0x20; + WLONG(SP(), data); +} + +inline INT32 tms340x0_device::POP() +{ + INT32 ret = RLONG(SP()); + SP() += 0x20; + return ret; +} + + + +/*************************************************************************** + PIXEL READS +***************************************************************************/ + +#define RP(m1,m2) \ + /* TODO: Plane masking */ \ + return (TMS34010_RDMEM_WORD(TOBYTE(offset & 0xfffffff0)) >> (offset & m1)) & m2; + +UINT32 tms340x0_device::read_pixel_1(offs_t offset) { RP(0x0f,0x01) } +UINT32 tms340x0_device::read_pixel_2(offs_t offset) { RP(0x0e,0x03) } +UINT32 tms340x0_device::read_pixel_4(offs_t offset) { RP(0x0c,0x0f) } +UINT32 tms340x0_device::read_pixel_8(offs_t offset) { RP(0x08,0xff) } +UINT32 tms340x0_device::read_pixel_16(offs_t offset) +{ + /* TODO: Plane masking */ + return TMS34010_RDMEM_WORD(TOBYTE(offset & 0xfffffff0)); +} +UINT32 tms340x0_device::read_pixel_32(offs_t offset) +{ + /* TODO: Plane masking */ + return TMS34010_RDMEM_DWORD(TOBYTE(offset & 0xffffffe0)); +} + +/* Shift register read */ +UINT32 tms340x0_device::read_pixel_shiftreg(offs_t offset) +{ + if (!m_to_shiftreg_cb.isnull()) + m_to_shiftreg_cb(*m_program, offset, &m_shiftreg[0]); + else + fatalerror("To ShiftReg function not set. PC = %08X\n", m_pc); + return m_shiftreg[0]; +} + + + +/*************************************************************************** + PIXEL WRITES +***************************************************************************/ + +/* No Raster Op + No Transparency */ +#define WP(m1,m2) \ + UINT32 a = TOBYTE(offset & 0xfffffff0); \ + UINT32 pix = TMS34010_RDMEM_WORD(a); \ + UINT32 shiftcount = offset & m1; \ + \ + /* TODO: plane masking */ \ + data &= m2; \ + pix = (pix & ~(m2 << shiftcount)) | (data << shiftcount); \ + TMS34010_WRMEM_WORD(a, pix); + +/* No Raster Op + Transparency */ +#define WP_T(m1,m2) \ + /* TODO: plane masking */ \ + data &= m2; \ + if (data) \ + { \ + UINT32 a = TOBYTE(offset & 0xfffffff0); \ + UINT32 pix = TMS34010_RDMEM_WORD(a); \ + UINT32 shiftcount = offset & m1; \ + \ + /* TODO: plane masking */ \ + pix = (pix & ~(m2 << shiftcount)) | (data << shiftcount); \ + TMS34010_WRMEM_WORD(a, pix); \ + } +/* Raster Op + No Transparency */ +#define WP_R(m1,m2) \ + UINT32 a = TOBYTE(offset & 0xfffffff0); \ + UINT32 pix = TMS34010_RDMEM_WORD(a); \ + UINT32 shiftcount = offset & m1; \ + \ + /* TODO: plane masking */ \ + data = (this->*m_raster_op)(data & m2, (pix >> shiftcount) & m2) & m2; \ + pix = (pix & ~(m2 << shiftcount)) | (data << shiftcount); \ + TMS34010_WRMEM_WORD(a, pix); + +/* Raster Op + Transparency */ +#define WP_R_T(m1,m2) \ + UINT32 a = TOBYTE(offset & 0xfffffff0); \ + UINT32 pix = TMS34010_RDMEM_WORD(a); \ + UINT32 shiftcount = offset & m1; \ + \ + /* TODO: plane masking */ \ + data = (this->*m_raster_op)(data & m2, (pix >> shiftcount) & m2) & m2; \ + if (data) \ + { \ + pix = (pix & ~(m2 << shiftcount)) | (data << shiftcount); \ + TMS34010_WRMEM_WORD(a, pix); \ + } + +/* No Raster Op + No Transparency */ +void tms340x0_device::write_pixel_1(offs_t offset, UINT32 data) { WP(0x0f, 0x01); } +void tms340x0_device::write_pixel_2(offs_t offset, UINT32 data) { WP(0x0e, 0x03); } +void tms340x0_device::write_pixel_4(offs_t offset, UINT32 data) { WP(0x0c, 0x0f); } +void tms340x0_device::write_pixel_8(offs_t offset, UINT32 data) { WP(0x08, 0xff); } +void tms340x0_device::write_pixel_16(offs_t offset, UINT32 data) +{ + /* TODO: plane masking */ + TMS34010_WRMEM_WORD(TOBYTE(offset & 0xfffffff0), data); +} +void tms340x0_device::write_pixel_32(offs_t offset, UINT32 data) +{ + /* TODO: plane masking */ + TMS34010_WRMEM_WORD(TOBYTE(offset & 0xffffffe0), data); +} + +/* No Raster Op + Transparency */ +void tms340x0_device::write_pixel_t_1(offs_t offset, UINT32 data) { WP_T(0x0f, 0x01); } +void tms340x0_device::write_pixel_t_2(offs_t offset, UINT32 data) { WP_T(0x0e, 0x03); } +void tms340x0_device::write_pixel_t_4(offs_t offset, UINT32 data) { WP_T(0x0c, 0x0f); } +void tms340x0_device::write_pixel_t_8(offs_t offset, UINT32 data) { WP_T(0x08, 0xff); } +void tms340x0_device::write_pixel_t_16(offs_t offset, UINT32 data) +{ + /* TODO: plane masking */ + if (data) + TMS34010_WRMEM_WORD(TOBYTE(offset & 0xfffffff0), data); +} +void tms340x0_device::write_pixel_t_32(offs_t offset, UINT32 data) +{ + /* TODO: plane masking */ + if (data) + TMS34010_WRMEM_DWORD(TOBYTE(offset & 0xffffffe0), data); +} + +/* Raster Op + No Transparency */ +void tms340x0_device::write_pixel_r_1(offs_t offset, UINT32 data) { WP_R(0x0f, 0x01); } +void tms340x0_device::write_pixel_r_2(offs_t offset, UINT32 data) { WP_R(0x0e, 0x03); } +void tms340x0_device::write_pixel_r_4(offs_t offset, UINT32 data) { WP_R(0x0c, 0x0f); } +void tms340x0_device::write_pixel_r_8(offs_t offset, UINT32 data) { WP_R(0x08, 0xff); } +void tms340x0_device::write_pixel_r_16(offs_t offset, UINT32 data) +{ + /* TODO: plane masking */ + UINT32 a = TOBYTE(offset & 0xfffffff0); + TMS34010_WRMEM_WORD(a, (this->*m_raster_op)(data, TMS34010_RDMEM_WORD(a))); +} +void tms340x0_device::write_pixel_r_32(offs_t offset, UINT32 data) +{ + /* TODO: plane masking */ + UINT32 a = TOBYTE(offset & 0xffffffe0); + TMS34010_WRMEM_DWORD(a, (this->*m_raster_op)(data, TMS34010_RDMEM_DWORD(a))); +} + +/* Raster Op + Transparency */ +void tms340x0_device::write_pixel_r_t_1(offs_t offset, UINT32 data) { WP_R_T(0x0f,0x01); } +void tms340x0_device::write_pixel_r_t_2(offs_t offset, UINT32 data) { WP_R_T(0x0e,0x03); } +void tms340x0_device::write_pixel_r_t_4(offs_t offset, UINT32 data) { WP_R_T(0x0c,0x0f); } +void tms340x0_device::write_pixel_r_t_8(offs_t offset, UINT32 data) { WP_R_T(0x08,0xff); } +void tms340x0_device::write_pixel_r_t_16(offs_t offset, UINT32 data) +{ + /* TODO: plane masking */ + UINT32 a = TOBYTE(offset & 0xfffffff0); + data = (this->*m_raster_op)(data, TMS34010_RDMEM_WORD(a)); + + if (data) + TMS34010_WRMEM_WORD(a, data); +} +void tms340x0_device::write_pixel_r_t_32(offs_t offset, UINT32 data) +{ + /* TODO: plane masking */ + UINT32 a = TOBYTE(offset & 0xffffffe0); + data = (this->*m_raster_op)(data, TMS34010_RDMEM_DWORD(a)); + + if (data) + TMS34010_WRMEM_DWORD(a, data); +} + +/* Shift register write */ +void tms340x0_device::write_pixel_shiftreg(offs_t offset, UINT32 data) +{ + if (!m_from_shiftreg_cb.isnull()) + m_from_shiftreg_cb(*m_program, offset, &m_shiftreg[0]); + else + fatalerror("From ShiftReg function not set. PC = %08X\n", m_pc); +} + + + +/*************************************************************************** + RASTER OPS +***************************************************************************/ + +/* Raster operations */ +UINT32 tms340x0_device::raster_op_1(UINT32 newpix, UINT32 oldpix) { return newpix & oldpix; } +UINT32 tms340x0_device::raster_op_2(UINT32 newpix, UINT32 oldpix) { return newpix & ~oldpix; } +UINT32 tms340x0_device::raster_op_3(UINT32 newpix, UINT32 oldpix) { return 0; } +UINT32 tms340x0_device::raster_op_4(UINT32 newpix, UINT32 oldpix) { return newpix | ~oldpix; } +UINT32 tms340x0_device::raster_op_5(UINT32 newpix, UINT32 oldpix) { return ~(newpix ^ oldpix); } +UINT32 tms340x0_device::raster_op_6(UINT32 newpix, UINT32 oldpix) { return ~oldpix; } +UINT32 tms340x0_device::raster_op_7(UINT32 newpix, UINT32 oldpix) { return ~(newpix | oldpix); } +UINT32 tms340x0_device::raster_op_8(UINT32 newpix, UINT32 oldpix) { return newpix | oldpix; } +UINT32 tms340x0_device::raster_op_9(UINT32 newpix, UINT32 oldpix) { return oldpix; } +UINT32 tms340x0_device::raster_op_10(UINT32 newpix, UINT32 oldpix) { return newpix ^ oldpix; } +UINT32 tms340x0_device::raster_op_11(UINT32 newpix, UINT32 oldpix) { return ~newpix & oldpix; } +UINT32 tms340x0_device::raster_op_12(UINT32 newpix, UINT32 oldpix) { return 0xffff; } +UINT32 tms340x0_device::raster_op_13(UINT32 newpix, UINT32 oldpix) { return ~newpix | oldpix; } +UINT32 tms340x0_device::raster_op_14(UINT32 newpix, UINT32 oldpix) { return ~(newpix & oldpix); } +UINT32 tms340x0_device::raster_op_15(UINT32 newpix, UINT32 oldpix) { return ~newpix; } +UINT32 tms340x0_device::raster_op_16(UINT32 newpix, UINT32 oldpix) { return newpix + oldpix; } +UINT32 tms340x0_device::raster_op_17(UINT32 newpix, UINT32 oldpix) +{ + UINT32 max = (UINT32)0xffffffff >> (32 - IOREG(REG_PSIZE)); + UINT32 res = newpix + oldpix; + return (res > max) ? max : res; +} +UINT32 tms340x0_device::raster_op_18(UINT32 newpix, UINT32 oldpix) { return oldpix - newpix; } +UINT32 tms340x0_device::raster_op_19(UINT32 newpix, UINT32 oldpix) { return (oldpix > newpix) ? oldpix - newpix : 0; } +UINT32 tms340x0_device::raster_op_20(UINT32 newpix, UINT32 oldpix) { return (oldpix > newpix) ? oldpix : newpix; } +UINT32 tms340x0_device::raster_op_21(UINT32 newpix, UINT32 oldpix) { return (oldpix > newpix) ? newpix : oldpix; } + + + +/*************************************************************************** + OPCODE TABLE & IMPLEMENTATIONS +***************************************************************************/ + +#include "34010fld.c" + +/* includes the static function prototypes and the master opcode table */ +#include "34010tbl.c" + +/* includes the actual opcode implementations */ +#include "34010ops.c" +#include "34010gfx.c" + + + +/*************************************************************************** + Internal interrupt check +****************************************************************************/ + +/* Generate pending interrupts. */ +void tms340x0_device::check_interrupt() +{ + int vector = 0; + int irqline = -1; + int irq; + + /* if we're not actively executing, skip it */ + if (!m_executing) + return; + + /* check for NMI first */ + if (IOREG(REG_HSTCTLH) & 0x0100) + { + LOG(("TMS34010 '%s' takes NMI\n", tag())); + + /* ack the NMI */ + IOREG(REG_HSTCTLH) &= ~0x0100; + + /* handle NMI mode bit */ + if (!(IOREG(REG_HSTCTLH) & 0x0200)) + { + PUSH(m_pc); + PUSH(m_st); + } + + /* leap to the vector */ + RESET_ST(); + m_pc = RLONG(0xfffffee0); + COUNT_CYCLES(16); + return; + } + + /* early out if everything else is disabled */ + irq = IOREG(REG_INTPEND) & IOREG(REG_INTENB); + if (!IE_FLAG() || !irq) + return; + + /* host interrupt */ + if (irq & TMS34010_HI) + { + LOG(("TMS34010 '%s' takes HI\n", tag())); + vector = 0xfffffec0; + } + + /* display interrupt */ + else if (irq & TMS34010_DI) + { + LOG(("TMS34010 '%s' takes DI\n", tag())); + vector = 0xfffffea0; + } + + /* window violation interrupt */ + else if (irq & TMS34010_WV) + { + LOG(("TMS34010 '%s' takes WV\n", tag())); + vector = 0xfffffe80; + } + + /* external 1 interrupt */ + else if (irq & TMS34010_INT1) + { + LOG(("TMS34010 '%s' takes INT1\n", tag())); + vector = 0xffffffc0; + irqline = 0; + } + + /* external 2 interrupt */ + else if (irq & TMS34010_INT2) + { + LOG(("TMS34010 '%s' takes INT2\n", tag())); + vector = 0xffffffa0; + irqline = 1; + } + + /* if we took something, generate it */ + if (vector) + { + PUSH(m_pc); + PUSH(m_st); + RESET_ST(); + m_pc = RLONG(vector); + COUNT_CYCLES(16); + + /* call the callback for externals */ + if (irqline >= 0) + standard_irq_callback(irqline); + } +} + + + +/*************************************************************************** + Reset the CPU emulation +***************************************************************************/ + +void tms340x0_device::device_start() +{ + m_scanline_ind16_cb.bind_relative_to(*owner()); + m_scanline_rgb32_cb.bind_relative_to(*owner()); + m_output_int_cb.resolve(); + m_to_shiftreg_cb.bind_relative_to(*owner()); + m_from_shiftreg_cb.bind_relative_to(*owner()); + + m_external_host_access = FALSE; + + m_program = &space(AS_PROGRAM); + m_direct = &m_program->direct(); + + /* set up the state table */ + { + state_add(TMS34010_PC, "PC", m_pc); + state_add(STATE_GENPC, "GENPC", m_pc).noshow(); + state_add(STATE_GENPCBASE, "GENPCBASE", m_ppc).noshow(); + state_add(TMS34010_SP, "SP", m_regs[15].reg); + state_add(STATE_GENSP, "GENSP", m_regs[15].reg).noshow(); + state_add(TMS34010_ST, "ST", m_st); + state_add(STATE_GENFLAGS, "GENFLAGS", m_st).noshow().formatstr("%18s"); + + std::string tempstr; + for (int regnum = 0; regnum < 15; regnum++) + { + state_add(TMS34010_A0 + regnum, strformat(tempstr, "A%d", regnum).c_str(), m_regs[regnum].reg); + } + for (int regnum = 0; regnum < 15; regnum++) + { + state_add(TMS34010_B0 + regnum, strformat(tempstr, "B%d", regnum).c_str(), m_regs[30 - regnum].reg); + } + } + + /* allocate a scanline timer and set it to go off at the start */ + m_scantimer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(tms340x0_device::scanline_callback), this)); + m_scantimer->adjust(attotime::zero); + + save_item(NAME(m_pc)); + save_item(NAME(m_st)); + save_item(NAME(m_reset_deferred)); + save_item(NAME(m_shiftreg)); + save_item(NAME(m_IOregs)); + save_item(NAME(m_convsp)); + save_item(NAME(m_convdp)); + save_item(NAME(m_convmp)); + save_item(NAME(m_pixelshift)); + save_item(NAME(m_gfxcycles)); + save_pointer(NAME(&m_regs[0].reg), ARRAY_LENGTH(m_regs)); + machine().save().register_postload(save_prepost_delegate(FUNC(tms340x0_device::tms34010_state_postload), this)); + + m_icountptr = &m_icount; +} + +void tms340x0_device::device_reset() +{ + m_ppc = 0; + m_st = 0; + m_pixel_write = NULL; + m_pixel_read = NULL; + m_raster_op = NULL; + m_pixel_op = NULL; + m_pixel_op_timing = 0; + m_convsp = 0; + m_convdp = 0; + m_convmp = 0; + m_gfxcycles = 0; + m_pixelshift = 0; + m_hblank_stable = 0; + m_external_host_access = 0; + m_executing = 0; + memset(m_regs, 0, sizeof(m_regs)); + memset(m_IOregs, 0, sizeof(m_IOregs)); + memset(m_shiftreg, 0, sizeof(m_shiftreg)); + + /* fetch the initial PC and reset the state */ + m_pc = RLONG(0xffffffe0) & 0xfffffff0; + RESET_ST(); + + /* HALT the CPU if requested, and remember to re-read the starting PC */ + /* the first time we are run */ + m_reset_deferred = m_halt_on_reset; + + if (m_reset_deferred) + { + io_register_w(*m_program, REG_HSTCTLH, 0x8000, 0xffff); + } +} + + +/*************************************************************************** + Set IRQ line state +***************************************************************************/ + +void tms340x0_device::execute_set_input(int inputnum, int state) +{ + LOG(("TMS34010 '%s' set irq line %d state %d\n", tag(), inputnum, state)); + + /* set the pending interrupt */ + switch (inputnum) + { + case 0: + if (state != CLEAR_LINE) + IOREG(REG_INTPEND) |= TMS34010_INT1; + else + IOREG(REG_INTPEND) &= ~TMS34010_INT1; + break; + + case 1: + if (state != CLEAR_LINE) + IOREG(REG_INTPEND) |= TMS34010_INT2; + else + IOREG(REG_INTPEND) &= ~TMS34010_INT2; + break; + } +} + + + +/*************************************************************************** + Generate internal interrupt +***************************************************************************/ + +TIMER_CALLBACK_MEMBER( tms340x0_device::internal_interrupt_callback ) +{ + int type = param; + + /* call through to the CPU to generate the int */ + IOREG(REG_INTPEND) |= type; + LOG(("TMS34010 '%s' set internal interrupt $%04x\n", tag(), type)); + + /* generate triggers so that spin loops can key off them */ + signal_interrupt_trigger(); +} + + + +/*************************************************************************** + Execute +***************************************************************************/ + +void tms340x0_device::execute_run() +{ + /* Get out if CPU is halted. Absolutely no interrupts must be taken!!! */ + if (IOREG(REG_HSTCTLH) & 0x8000) + { + m_icount = 0; + return; + } + /* if the CPU's reset was deferred, do it now */ + if (m_reset_deferred) + { + m_reset_deferred = FALSE; + m_pc = RLONG(0xffffffe0); + } + + /* check interrupts first */ + m_executing = TRUE; + check_interrupt(); + if ((machine().debug_flags & DEBUG_FLAG_ENABLED) == 0) + { + do + { + UINT16 op; + m_ppc = m_pc; + op = ROPCODE(); + (this->*s_opcode_table[op >> 4])(op); + } while (m_icount > 0); + } + else + { + do + { + UINT16 op; + debugger_instruction_hook(this, m_pc); + m_ppc = m_pc; + op = ROPCODE(); + (this->*s_opcode_table[op >> 4])(op); + } while (m_icount > 0); + } + m_executing = FALSE; +} + + + +/*************************************************************************** + PIXEL OPS +***************************************************************************/ + +const tms340x0_device::pixel_write_func tms340x0_device::s_pixel_write_ops[4][6] = +{ + { &tms340x0_device::write_pixel_1, &tms340x0_device::write_pixel_2, &tms340x0_device::write_pixel_4, &tms340x0_device::write_pixel_8, &tms340x0_device::write_pixel_16, &tms340x0_device::write_pixel_32 }, + { &tms340x0_device::write_pixel_r_1, &tms340x0_device::write_pixel_r_2, &tms340x0_device::write_pixel_r_4, &tms340x0_device::write_pixel_r_8, &tms340x0_device::write_pixel_r_16, &tms340x0_device::write_pixel_r_32 }, + { &tms340x0_device::write_pixel_t_1, &tms340x0_device::write_pixel_t_2, &tms340x0_device::write_pixel_t_4, &tms340x0_device::write_pixel_t_8, &tms340x0_device::write_pixel_t_16, &tms340x0_device::write_pixel_t_32 }, + { &tms340x0_device::write_pixel_r_t_1, &tms340x0_device::write_pixel_r_t_2, &tms340x0_device::write_pixel_r_t_4, &tms340x0_device::write_pixel_r_t_8, &tms340x0_device::write_pixel_r_t_16, &tms340x0_device::write_pixel_r_t_32 } +}; + +const tms340x0_device::pixel_read_func tms340x0_device::s_pixel_read_ops[6] = +{ + &tms340x0_device::read_pixel_1, &tms340x0_device::read_pixel_2, &tms340x0_device::read_pixel_4, &tms340x0_device::read_pixel_8, &tms340x0_device::read_pixel_16, &tms340x0_device::read_pixel_32 +}; + + +void tms340x0_device::set_pixel_function() +{ + UINT32 i1,i2; + + if (IOREG(REG_DPYCTL) & 0x0800) + { + /* Shift Register Transfer */ + m_pixel_write = &tms340x0_device::write_pixel_shiftreg; + m_pixel_read = &tms340x0_device::read_pixel_shiftreg; + return; + } + + switch (IOREG(REG_PSIZE)) + { + default: + case 0x01: i2 = 0; break; + case 0x02: i2 = 1; break; + case 0x04: i2 = 2; break; + case 0x08: i2 = 3; break; + case 0x10: i2 = 4; break; + case 0x20: i2 = 5; break; + } + + if (IOREG(REG_CONTROL) & 0x20) + i1 = m_raster_op ? 3 : 2; + else + i1 = m_raster_op ? 1 : 0; + + m_pixel_write = s_pixel_write_ops[i1][i2]; + m_pixel_read = s_pixel_read_ops [i2]; +} + + + +/*************************************************************************** + RASTER OPS +***************************************************************************/ + +const tms340x0_device::raster_op_func tms340x0_device::s_raster_ops[32] = +{ + NULL, &tms340x0_device::raster_op_1 , &tms340x0_device::raster_op_2 , &tms340x0_device::raster_op_3, + &tms340x0_device::raster_op_4 , &tms340x0_device::raster_op_5 , &tms340x0_device::raster_op_6 , &tms340x0_device::raster_op_7, + &tms340x0_device::raster_op_8 , &tms340x0_device::raster_op_9 , &tms340x0_device::raster_op_10, &tms340x0_device::raster_op_11, + &tms340x0_device::raster_op_12, &tms340x0_device::raster_op_13, &tms340x0_device::raster_op_14, &tms340x0_device::raster_op_15, + &tms340x0_device::raster_op_16, &tms340x0_device::raster_op_17, &tms340x0_device::raster_op_18, &tms340x0_device::raster_op_19, + &tms340x0_device::raster_op_20, &tms340x0_device::raster_op_21, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, +}; + + +void tms340x0_device::set_raster_op() +{ + m_raster_op = s_raster_ops[(IOREG(REG_CONTROL) >> 10) & 0x1f]; +} + + + +/*************************************************************************** + VIDEO TIMING HELPERS +***************************************************************************/ + +TIMER_CALLBACK_MEMBER( tms340x0_device::scanline_callback ) +{ + int vsblnk, veblnk, vtotal; + int vcount = param; + int enabled; + int master; + + /* fetch the core timing parameters */ + const rectangle ¤t_visarea = m_screen->visible_area(); + enabled = SMART_IOREG(DPYCTL) & 0x8000; + master = (m_is_34020 || (SMART_IOREG(DPYCTL) & 0x2000)); + vsblnk = SMART_IOREG(VSBLNK); + veblnk = SMART_IOREG(VEBLNK); + vtotal = SMART_IOREG(VTOTAL); + if (!master) + { + vtotal = MIN(m_screen->height() - 1, vtotal); + vcount = m_screen->vpos(); + } + + /* update the VCOUNT */ + SMART_IOREG(VCOUNT) = vcount; + + /* if we match the display interrupt scanline, signal an interrupt */ + if (enabled && vcount == SMART_IOREG(DPYINT)) + { + /* generate the display interrupt signal */ + internal_interrupt_callback(NULL, TMS34010_DI); + } + + /* at the start of VBLANK, load the starting display address */ + if (vcount == vsblnk) + { + /* 34010 loads DPYADR with DPYSTRT, and inverts if the origin is 0 */ + if (!m_is_34020) + { + IOREG(REG_DPYADR) = IOREG(REG_DPYSTRT); + LOG(("Start of VBLANK, DPYADR = %04X\n", IOREG(REG_DPYADR))); + } + + /* 34020 loads DPYNXx with DPYSTx */ + else + { + IOREG(REG020_DPYNXL) = IOREG(REG020_DPYSTL) & 0xffe0; + IOREG(REG020_DPYNXH) = IOREG(REG020_DPYSTH); + } + } + + /* at the end of the screen, update the display parameters */ + if (vcount == vtotal) + { + /* only do this if we have an incoming pixel clock */ + /* also, only do it if the HEBLNK/HSBLNK values are stable */ + if (master && (!m_scanline_ind16_cb.isnull() || !m_scanline_rgb32_cb.isnull())) + { + int htotal = SMART_IOREG(HTOTAL); + if (htotal > 0 && vtotal > 0) + { + attoseconds_t refresh = HZ_TO_ATTOSECONDS(m_pixclock) * (htotal + 1) * (vtotal + 1); + int width = (htotal + 1) * m_pixperclock; + int height = vtotal + 1; + rectangle visarea; + + /* extract the visible area */ + visarea.min_x = SMART_IOREG(HEBLNK) * m_pixperclock; + visarea.max_x = SMART_IOREG(HSBLNK) * m_pixperclock - 1; + visarea.min_y = veblnk; + visarea.max_y = vsblnk - 1; + + /* if everything looks good, set the info */ + if (visarea.min_x < visarea.max_x && visarea.max_x <= width && visarea.min_y < visarea.max_y && visarea.max_y <= height) + { + /* because many games play with the HEBLNK/HSBLNK for effects, we don't change + if they are the only thing that has changed, unless they are stable for a couple + of frames */ + int current_width = m_screen->width(); + int current_height = m_screen->height(); + + if (width != current_width || height != current_height || visarea.min_y != current_visarea.min_y || visarea.max_y != current_visarea.max_y || + (m_hblank_stable > 2 && (visarea.min_x != current_visarea.min_x || visarea.max_x != current_visarea.max_x))) + { + m_screen->configure(width, height, visarea, refresh); + } + m_hblank_stable++; + } + + LOG(("Configuring screen: HTOTAL=%3d BLANK=%3d-%3d VTOTAL=%3d BLANK=%3d-%3d refresh=%f\n", + htotal, SMART_IOREG(HEBLNK), SMART_IOREG(HSBLNK), vtotal, veblnk, vsblnk, ATTOSECONDS_TO_HZ(refresh))); + + /* interlaced timing not supported */ + if ((SMART_IOREG(DPYCTL) & 0x4000) == 0) + fatalerror("Interlaced video configured on the TMS34010 (unsupported)\n"); + } + } + } + + /* force a partial update within the visible area */ + if (vcount >= current_visarea.min_y && vcount <= current_visarea.max_y && (!m_scanline_ind16_cb.isnull() || !m_scanline_rgb32_cb.isnull())) + m_screen->update_partial(vcount); + + /* if we are in the visible area, increment DPYADR by DUDATE */ + if (vcount >= veblnk && vcount < vsblnk) + { + /* 34010 increments by the DUDATE field in DPYCTL */ + if (!m_is_34020) + { + UINT16 dpyadr = IOREG(REG_DPYADR); + if ((dpyadr & 3) == 0) + dpyadr = ((dpyadr & 0xfffc) - (IOREG(REG_DPYCTL) & 0x03fc)) | (IOREG(REG_DPYSTRT) & 0x0003); + else + dpyadr = (dpyadr & 0xfffc) | ((dpyadr - 1) & 3); + IOREG(REG_DPYADR) = dpyadr; + } + + /* 34020 updates based on the DINC register, including zoom */ + else + { + UINT32 dpynx = IOREG(REG020_DPYNXL) | (IOREG(REG020_DPYNXH) << 16); + UINT32 dinc = IOREG(REG020_DINCL) | (IOREG(REG020_DINCH) << 16); + dpynx = (dpynx & 0xffffffe0) | ((dpynx + dinc) & 0x1f); + if ((dpynx & 0x1f) == 0) + dpynx += dinc & 0xffffffe0; + IOREG(REG020_DPYNXL) = dpynx; + IOREG(REG020_DPYNXH) = dpynx >> 16; + } + } + + /* adjust for the next callback */ + vcount++; + if (vcount > vtotal) + vcount = 0; + + /* note that we add !master (0 or 1) as a attoseconds value; this makes no practical difference */ + /* but helps ensure that masters are updated first before slaves */ + m_scantimer->adjust(m_screen->time_until_pos(vcount) + attotime(0, !master), vcount); +} + + +void tms340x0_device::get_display_params(tms34010_display_params *params) +{ + params->enabled = ((SMART_IOREG(DPYCTL) & 0x8000) != 0); + params->vcount = SMART_IOREG(VCOUNT); + params->veblnk = SMART_IOREG(VEBLNK); + params->vsblnk = SMART_IOREG(VSBLNK); + params->heblnk = SMART_IOREG(HEBLNK) * m_pixperclock; + params->hsblnk = SMART_IOREG(HSBLNK) * m_pixperclock; + + /* 34010 gets its address from DPYADR and DPYTAP */ + if (!m_is_34020) + { + UINT16 dpyadr = IOREG(REG_DPYADR); + if (!(IOREG(REG_DPYCTL) & 0x0400)) + dpyadr ^= 0xfffc; + params->rowaddr = dpyadr >> 4; + params->coladdr = ((dpyadr & 0x007c) << 4) | (IOREG(REG_DPYTAP) & 0x3fff); + params->yoffset = (IOREG(REG_DPYSTRT) - IOREG(REG_DPYADR)) & 3; + } + + /* 34020 gets its address from DPYNX */ + else + { + params->rowaddr = IOREG(REG020_DPYNXH); + params->coladdr = IOREG(REG020_DPYNXL) & 0xffe0; + params->yoffset = 0; + if ((IOREG(REG020_DINCL) & 0x1f) != 0) + params->yoffset = (IOREG(REG020_DPYNXL) & 0x1f) / (IOREG(REG020_DINCL) & 0x1f); + } +} + +UINT32 tms340x0_device::tms340x0_ind16(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) +{ + pen_t blackpen = screen.palette()->black_pen(); + tms34010_display_params params; + int x; + + /* get the display parameters for the screen */ + get_display_params(¶ms); + + /* if the display is enabled, call the scanline callback */ + if (params.enabled) + { + /* call through to the callback */ + LOG((" Update: scan=%3d ROW=%04X COL=%04X\n", cliprect.min_y, params.rowaddr, params.coladdr)); + m_scanline_ind16_cb(screen, bitmap, cliprect.min_y, ¶ms); + } + + /* otherwise, just blank the current scanline */ + else + params.heblnk = params.hsblnk = cliprect.max_x + 1; + + /* blank out the blank regions */ + UINT16 *dest = &bitmap.pix16(cliprect.min_y); + for (x = cliprect.min_x; x < params.heblnk; x++) + dest[x] = blackpen; + for (x = params.hsblnk; x <= cliprect.max_x; x++) + dest[x] = blackpen; + return 0; + +} + +UINT32 tms340x0_device::tms340x0_rgb32(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + pen_t blackpen = rgb_t::black; + tms34010_display_params params; + int x; + + /* get the display parameters for the screen */ + get_display_params(¶ms); + + /* if the display is enabled, call the scanline callback */ + if (params.enabled) + { + /* call through to the callback */ + LOG((" Update: scan=%3d ROW=%04X COL=%04X\n", cliprect.min_y, params.rowaddr, params.coladdr)); + m_scanline_rgb32_cb(screen, bitmap, cliprect.min_y, ¶ms); + } + + /* otherwise, just blank the current scanline */ + else + params.heblnk = params.hsblnk = cliprect.max_x + 1; + + /* blank out the blank regions */ + UINT32 *dest = &bitmap.pix32(cliprect.min_y); + for (x = cliprect.min_x; x < params.heblnk; x++) + dest[x] = blackpen; + for (x = params.hsblnk; x <= cliprect.max_x; x++) + dest[x] = blackpen; + return 0; +} + + +/*************************************************************************** + I/O REGISTER WRITES +***************************************************************************/ + +#if 0 +static const char *const ioreg_name[] = +{ + "HESYNC", "HEBLNK", "HSBLNK", "HTOTAL", + "VESYNC", "VEBLNK", "VSBLNK", "VTOTAL", + "DPYCTL", "DPYSTART", "DPYINT", "CONTROL", + "HSTDATA", "HSTADRL", "HSTADRH", "HSTCTLL", + + "HSTCTLH", "INTENB", "INTPEND", "CONVSP", + "CONVDP", "PSIZE", "PMASK", "RESERVED", + "RESERVED", "RESERVED", "RESERVED", "DPYTAP", + "HCOUNT", "VCOUNT", "DPYADR", "REFCNT" +}; +#endif + +WRITE16_MEMBER( tms34010_device::io_register_w ) +{ + int oldreg, newreg; + + /* Set register */ + oldreg = IOREG(offset); + IOREG(offset) = data; + + switch (offset) + { + case REG_CONTROL: + set_raster_op(); + set_pixel_function(); + break; + + case REG_PSIZE: + set_pixel_function(); + + switch (data) + { + default: + case 0x01: m_pixelshift = 0; break; + case 0x02: m_pixelshift = 1; break; + case 0x04: m_pixelshift = 2; break; + case 0x08: m_pixelshift = 3; break; + case 0x10: m_pixelshift = 4; break; + } + break; + + case REG_PMASK: + if (data) logerror("Plane masking not supported. PC=%08X\n", space.device().safe_pc()); + break; + + case REG_DPYCTL: + set_pixel_function(); + break; + + case REG_HSTCTLH: + /* if the CPU is halting itself, stop execution right away */ + if (mem_mask & 0xff00) + { + if ((data & 0x8000) && !m_external_host_access) + m_icount = 0; + + set_input_line(INPUT_LINE_HALT, (data & 0x8000) ? ASSERT_LINE : CLEAR_LINE); + + /* NMI issued? */ + if (data & 0x0100) + machine().scheduler().synchronize(timer_expired_delegate(FUNC(tms340x0_device::internal_interrupt_callback), this), 0); + } + break; + + case REG_HSTCTLL: + if (mem_mask & 0x00ff) + { + /* the TMS34010 can change MSGOUT, can set INTOUT, and can clear INTIN */ + if (!m_external_host_access) + { + newreg = (oldreg & 0xff8f) | (data & 0x0070); + newreg |= data & 0x0080; + newreg &= data | ~0x0008; + } + + /* the host can change MSGIN, can set INTIN, and can clear INTOUT */ + else + { + newreg = (oldreg & 0xfff8) | (data & 0x0007); + newreg &= data | ~0x0080; + newreg |= data & 0x0008; + } + IOREG(offset) = newreg; + + /* the TMS34010 can set output interrupt? */ + if (!(oldreg & 0x0080) && (newreg & 0x0080)) + { + if (!m_output_int_cb.isnull()) + m_output_int_cb(1); + } + else if ((oldreg & 0x0080) && !(newreg & 0x0080)) + { + if (!m_output_int_cb.isnull()) + m_output_int_cb(0); + } + + /* input interrupt? (should really be state-based, but the functions don't exist!) */ + if (!(oldreg & 0x0008) && (newreg & 0x0008)) + machine().scheduler().synchronize(timer_expired_delegate(FUNC(tms340x0_device::internal_interrupt_callback), this), TMS34010_HI); + else if ((oldreg & 0x0008) && !(newreg & 0x0008)) + IOREG(REG_INTPEND) &= ~TMS34010_HI; + } + break; + + case REG_CONVSP: + m_convsp = 1 << (~data & 0x1f); + break; + + case REG_CONVDP: + m_convdp = 1 << (~data & 0x1f); + break; + + case REG_INTENB: + check_interrupt(); + break; + + case REG_INTPEND: + /* X1P, X2P and HIP are read-only */ + /* WVP and DIP can only have 0's written to them */ + IOREG(REG_INTPEND) = oldreg; + if (!(data & TMS34010_WV)) + IOREG(REG_INTPEND) &= ~TMS34010_WV; + if (!(data & TMS34010_DI)) + IOREG(REG_INTPEND) &= ~TMS34010_DI; + break; + + case REG_HEBLNK: + case REG_HSBLNK: + if (oldreg != data) + m_hblank_stable = 0; + break; + } + +// if (LOG_CONTROL_REGS) +// logerror("%s: %s = %04X (%d)\n", machine().describe_context(), ioreg_name[offset], IOREG(offset), m_screen.vpos()); +} + + +#if 0 +static const char *const ioreg020_name[] = +{ + "VESYNC", "HESYNC", "VEBLNK", "HEBLNK", + "VSBLNK", "HSBLNK", "VTOTAL", "HTOTAL", + "DPYCTL", "DPYSTRT", "DPYINT", "CONTROL", + "HSTDATA", "HSTADRL", "HSTADRH", "HSTCTLL", + + "HSTCTLH", "INTENB", "INTPEND", "CONVSP", + "CONVDP", "PSIZE", "PMASKL", "PMASKH", + "CONVMP", "CONTROL2", "CONFIG", "DPYTAP", + "VCOUNT", "HCOUNT", "DPYADR", "REFADR", + + "DPYSTL", "DPYSTH", "DPYNXL", "DPYNXH", + "DINCL", "DINCH", "RES0", "HESERR", + "RES1", "RES2", "RES3", "RES4", + "SCOUNT", "BSFLTST", "DPYMSK", "RES5", + + "SETVCNT", "SETHCNT", "BSFLTDL", "BSFLTDH", + "RES6", "RES7", "RES8", "RES9", + "IHOST1L", "IHOST1H", "IHOST2L", "IHOST2H", + "IHOST3L", "IHOST3H", "IHOST4L", "IHOST4H" +}; +#endif + +WRITE16_MEMBER( tms34020_device::io_register_w ) +{ + int oldreg, newreg; + + /* Set register */ + oldreg = IOREG(offset); + IOREG(offset) = data; + +// if (LOG_CONTROL_REGS) +// logerror("%s: %s = %04X (%d)\n", machine().describe_context(), ioreg020_name[offset], IOREG(offset), m_screen.vpos()); + + switch (offset) + { + case REG020_CONTROL: + case REG020_CONTROL2: + IOREG(REG020_CONTROL) = data; + IOREG(REG020_CONTROL2) = data; + set_raster_op(); + set_pixel_function(); + break; + + case REG020_PSIZE: + set_pixel_function(); + + switch (data) + { + default: + case 0x01: m_pixelshift = 0; break; + case 0x02: m_pixelshift = 1; break; + case 0x04: m_pixelshift = 2; break; + case 0x08: m_pixelshift = 3; break; + case 0x10: m_pixelshift = 4; break; + case 0x20: m_pixelshift = 5; break; + } + break; + + case REG020_PMASKL: + case REG020_PMASKH: + if (data) logerror("Plane masking not supported. PC=%08X\n", space.device().safe_pc()); + break; + + case REG020_DPYCTL: + set_pixel_function(); + break; + + case REG020_HSTCTLH: + /* if the CPU is halting itself, stop execution right away */ + if ((data & 0x8000) && !m_external_host_access) + m_icount = 0; + set_input_line(INPUT_LINE_HALT, (data & 0x8000) ? ASSERT_LINE : CLEAR_LINE); + + /* NMI issued? */ + if (data & 0x0100) + machine().scheduler().synchronize(timer_expired_delegate(FUNC(tms340x0_device::internal_interrupt_callback), this), 0); + break; + + case REG020_HSTCTLL: + /* the TMS34010 can change MSGOUT, can set INTOUT, and can clear INTIN */ + if (!m_external_host_access) + { + newreg = (oldreg & 0xff8f) | (data & 0x0070); + newreg |= data & 0x0080; + newreg &= data | ~0x0008; + } + + /* the host can change MSGIN, can set INTIN, and can clear INTOUT */ + else + { + newreg = (oldreg & 0xfff8) | (data & 0x0007); + newreg &= data | ~0x0080; + newreg |= data & 0x0008; + } + IOREG(offset) = newreg; + + /* the TMS34010 can set output interrupt? */ + if (!(oldreg & 0x0080) && (newreg & 0x0080)) + { + if (!m_output_int_cb.isnull()) + m_output_int_cb(1); + } + else if ((oldreg & 0x0080) && !(newreg & 0x0080)) + { + if (!m_output_int_cb.isnull()) + m_output_int_cb(0); + } + + /* input interrupt? (should really be state-based, but the functions don't exist!) */ + if (!(oldreg & 0x0008) && (newreg & 0x0008)) + machine().scheduler().synchronize(timer_expired_delegate(FUNC(tms340x0_device::internal_interrupt_callback), this), TMS34010_HI); + else if ((oldreg & 0x0008) && !(newreg & 0x0008)) + IOREG(REG020_INTPEND) &= ~TMS34010_HI; + break; + + case REG020_INTENB: + check_interrupt(); + break; + + case REG020_INTPEND: + /* X1P, X2P and HIP are read-only */ + /* WVP and DIP can only have 0's written to them */ + IOREG(REG020_INTPEND) = oldreg; + if (!(data & TMS34010_WV)) + IOREG(REG020_INTPEND) &= ~TMS34010_WV; + if (!(data & TMS34010_DI)) + IOREG(REG020_INTPEND) &= ~TMS34010_DI; + break; + + case REG020_CONVSP: + if (data & 0x001f) + { + if (data & 0x1f00) + m_convsp = (1 << (~data & 0x1f)) + (1 << (~(data >> 8) & 0x1f)); + else + m_convsp = 1 << (~data & 0x1f); + } + else + m_convsp = data; + break; + + case REG020_CONVDP: + if (data & 0x001f) + { + if (data & 0x1f00) + m_convdp = (1 << (~data & 0x1f)) + (1 << (~(data >> 8) & 0x1f)); + else + m_convdp = 1 << (~data & 0x1f); + } + else + m_convdp = data; + break; + + case REG020_CONVMP: + if (data & 0x001f) + { + if (data & 0x1f00) + m_convmp = (1 << (~data & 0x1f)) + (1 << (~(data >> 8) & 0x1f)); + else + m_convmp = 1 << (~data & 0x1f); + } + else + m_convmp = data; + break; + + case REG020_DPYSTRT: + case REG020_DPYADR: + case REG020_DPYTAP: + break; + + case REG020_HEBLNK: + case REG020_HSBLNK: + if (oldreg != data) + m_hblank_stable = 0; + break; + } +} + + + +/*************************************************************************** + I/O REGISTER READS +***************************************************************************/ + +READ16_MEMBER( tms34010_device::io_register_r ) +{ + int result, total; + +// if (LOG_CONTROL_REGS) +// logerror("%s: read %s\n", machine().describe_context(), ioreg_name[offset]); + + switch (offset) + { + case REG_HCOUNT: + /* scale the horizontal position from screen width to HTOTAL */ + result = m_screen->hpos(); + total = IOREG(REG_HTOTAL) + 1; + result = result * total / m_screen->width(); + + /* offset by the HBLANK end */ + result += IOREG(REG_HEBLNK); + + /* wrap around */ + if (result > total) + result -= total; + return result; + + case REG_REFCNT: + return (total_cycles() / 16) & 0xfffc; + + case REG_INTPEND: + result = IOREG(offset); + + /* Cool Pool loops in mainline code on the appearance of the DI, even though they */ + /* have an IRQ handler. For this reason, we return it signalled a bit early in order */ + /* to make it past these loops. */ + if (SMART_IOREG(VCOUNT) + 1 == SMART_IOREG(DPYINT) && + m_scantimer->remaining() < attotime::from_hz(40000000/8/3)) + result |= TMS34010_DI; + return result; + } + + return IOREG(offset); +} + + +READ16_MEMBER( tms34020_device::io_register_r ) +{ + int result, total; + +// if (LOG_CONTROL_REGS) +// logerror("%s: read %s\n", machine().describe_context(), ioreg_name[offset]); + + switch (offset) + { + case REG020_HCOUNT: + /* scale the horizontal position from screen width to HTOTAL */ + result = m_screen->hpos(); + total = IOREG(REG020_HTOTAL) + 1; + result = result * total / m_screen->width(); + + /* offset by the HBLANK end */ + result += IOREG(REG020_HEBLNK); + + /* wrap around */ + if (result > total) + result -= total; + return result; + + case REG020_REFADR: + { + int refreshrate = (IOREG(REG020_CONFIG) >> 8) & 7; + if (refreshrate < 6) + return (total_cycles() / refreshrate) & 0xffff; + break; + } + } + + return IOREG(offset); +} + + + +/*************************************************************************** + SAVE STATE +***************************************************************************/ + +void tms340x0_device::tms34010_state_postload() +{ + set_raster_op(); + set_pixel_function(); +} + + +/*************************************************************************** + HOST INTERFACE WRITES +***************************************************************************/ + +WRITE16_MEMBER( tms340x0_device::host_w ) +{ + int reg = offset; + unsigned int addr; + + switch (reg) + { + /* upper 16 bits of the address */ + case TMS34010_HOST_ADDRESS_H: + IOREG(REG_HSTADRH) = data; + break; + + /* lower 16 bits of the address */ + case TMS34010_HOST_ADDRESS_L: + IOREG(REG_HSTADRL) = data; + break; + + /* actual data */ + case TMS34010_HOST_DATA: + + /* write to the address */ + addr = (IOREG(REG_HSTADRH) << 16) | IOREG(REG_HSTADRL); + TMS34010_WRMEM_WORD(TOBYTE(addr & 0xfffffff0), data); + + /* optional postincrement */ + if (IOREG(REG_HSTCTLH) & 0x0800) + { + addr += 0x10; + IOREG(REG_HSTADRH) = addr >> 16; + IOREG(REG_HSTADRL) = (UINT16)addr; + } + break; + + /* control register */ + case TMS34010_HOST_CONTROL: + { + m_external_host_access = TRUE; + if (mem_mask&0xff00) io_register_w(*m_program, REG_HSTCTLH, data & 0xff00, 0xff00); + if (mem_mask&0x00ff) io_register_w(*m_program, REG_HSTCTLL, data & 0x00ff, 0x00ff); + m_external_host_access = FALSE; + break; + } + + /* error case */ + default: + logerror("tms34010_host_control_w called on invalid register %d\n", reg); + break; + } +} + + + +/*************************************************************************** + HOST INTERFACE READS +***************************************************************************/ + +READ16_MEMBER( tms340x0_device::host_r ) +{ + int reg = offset; + unsigned int addr; + int result = 0; + + /* swap to the target cpu */ + + switch (reg) + { + /* upper 16 bits of the address */ + case TMS34010_HOST_ADDRESS_H: + result = IOREG(REG_HSTADRH); + break; + + /* lower 16 bits of the address */ + case TMS34010_HOST_ADDRESS_L: + result = IOREG(REG_HSTADRL); + break; + + /* actual data */ + case TMS34010_HOST_DATA: + + /* read from the address */ + addr = (IOREG(REG_HSTADRH) << 16) | IOREG(REG_HSTADRL); + result = TMS34010_RDMEM_WORD(TOBYTE(addr & 0xfffffff0)); + + /* optional postincrement (it says preincrement, but data is preloaded, so it + is effectively a postincrement */ + if (IOREG(REG_HSTCTLH) & 0x1000) + { + addr += 0x10; + IOREG(REG_HSTADRH) = addr >> 16; + IOREG(REG_HSTADRL) = (UINT16)addr; + } + break; + + /* control register */ + case TMS34010_HOST_CONTROL: + result = (IOREG(REG_HSTCTLH) & 0xff00) | (IOREG(REG_HSTCTLL) & 0x00ff); + break; + + /* error case */ + default: + logerror("tms34010_host_control_r called on invalid register %d\n", reg); + break; + } + + return result; +} + + +void tms340x0_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + switch (entry.index()) + { + case STATE_GENFLAGS: + strprintf(str, "%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c", + m_st & 0x80000000 ? 'N':'.', + m_st & 0x40000000 ? 'C':'.', + m_st & 0x20000000 ? 'Z':'.', + m_st & 0x10000000 ? 'V':'.', + m_st & 0x02000000 ? 'P':'.', + m_st & 0x00200000 ? 'I':'.', + m_st & 0x00000800 ? 'E':'.', + m_st & 0x00000400 ? 'F':'.', + m_st & 0x00000200 ? 'F':'.', + m_st & 0x00000100 ? 'F':'.', + m_st & 0x00000080 ? 'F':'.', + m_st & 0x00000040 ? 'F':'.', + m_st & 0x00000020 ? 'E':'.', + m_st & 0x00000010 ? 'F':'.', + m_st & 0x00000008 ? 'F':'.', + m_st & 0x00000004 ? 'F':'.', + m_st & 0x00000002 ? 'F':'.', + m_st & 0x00000001 ? 'F':'.'); + break; + } +} + + +offs_t tms34010_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( tms34010 ); + + return CPU_DISASSEMBLE_NAME(tms34010)(this, buffer, pc, oprom, opram, options); +} + + +offs_t tms34020_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( tms34020 ); + + return CPU_DISASSEMBLE_NAME(tms34020)(this, buffer, pc, oprom, opram, options); +} diff --git a/src/devices/cpu/tms34010/tms34010.h b/src/devices/cpu/tms34010/tms34010.h new file mode 100644 index 00000000000..70d453cda6e --- /dev/null +++ b/src/devices/cpu/tms34010/tms34010.h @@ -0,0 +1,1074 @@ +// license:BSD-3-Clause +// copyright-holders:Alex Pasadyn,Zsolt Vasvari +/*************************************************************************** + + TMS34010: Portable Texas Instruments TMS34010 emulator + + Copyright Alex Pasadyn/Zsolt Vasvari + Parts based on code by Aaron Giles + +***************************************************************************/ + +#pragma once + +#ifndef __TMS34010_H__ +#define __TMS34010_H__ + + +/* register indexes for get_reg and set_reg */ +enum +{ + TMS34010_PC, + TMS34010_SP, + TMS34010_ST, + TMS34010_A0, + TMS34010_A1, + TMS34010_A2, + TMS34010_A3, + TMS34010_A4, + TMS34010_A5, + TMS34010_A6, + TMS34010_A7, + TMS34010_A8, + TMS34010_A9, + TMS34010_A10, + TMS34010_A11, + TMS34010_A12, + TMS34010_A13, + TMS34010_A14, + TMS34010_B0, + TMS34010_B1, + TMS34010_B2, + TMS34010_B3, + TMS34010_B4, + TMS34010_B5, + TMS34010_B6, + TMS34010_B7, + TMS34010_B8, + TMS34010_B9, + TMS34010_B10, + TMS34010_B11, + TMS34010_B12, + TMS34010_B13, + TMS34010_B14, + + TMS34010_GENPC = STATE_GENPC, + TMS34010_GENSP = STATE_GENSP, + TMS34010_GENPCBASE = STATE_GENPCBASE +}; + + +/*************************************************************************** + INTERNAL I/O CONSTANTS +***************************************************************************/ + +enum +{ + REG_HESYNC = 0, + REG_HEBLNK, + REG_HSBLNK, + REG_HTOTAL, + REG_VESYNC, + REG_VEBLNK, + REG_VSBLNK, + REG_VTOTAL, + REG_DPYCTL, + REG_DPYSTRT, + REG_DPYINT, + REG_CONTROL, + REG_HSTDATA, + REG_HSTADRL, + REG_HSTADRH, + REG_HSTCTLL, + + REG_HSTCTLH, + REG_INTENB, + REG_INTPEND, + REG_CONVSP, + REG_CONVDP, + REG_PSIZE, + REG_PMASK, + REG_UNK23, + REG_UNK24, + REG_UNK25, + REG_UNK26, + REG_DPYTAP, + REG_HCOUNT, + REG_VCOUNT, + REG_DPYADR, + REG_REFCNT +}; + +enum +{ + REG020_VESYNC, + REG020_HESYNC, + REG020_VEBLNK, + REG020_HEBLNK, + REG020_VSBLNK, + REG020_HSBLNK, + REG020_VTOTAL, + REG020_HTOTAL, + REG020_DPYCTL, /* matches 010 */ + REG020_DPYSTRT, /* matches 010 */ + REG020_DPYINT, /* matches 010 */ + REG020_CONTROL, /* matches 010 */ + REG020_HSTDATA, /* matches 010 */ + REG020_HSTADRL, /* matches 010 */ + REG020_HSTADRH, /* matches 010 */ + REG020_HSTCTLL, /* matches 010 */ + + REG020_HSTCTLH, /* matches 010 */ + REG020_INTENB, /* matches 010 */ + REG020_INTPEND, /* matches 010 */ + REG020_CONVSP, /* matches 010 */ + REG020_CONVDP, /* matches 010 */ + REG020_PSIZE, /* matches 010 */ + REG020_PMASKL, + REG020_PMASKH, + REG020_CONVMP, + REG020_CONTROL2, + REG020_CONFIG, + REG020_DPYTAP, /* matches 010 */ + REG020_VCOUNT, + REG020_HCOUNT, + REG020_DPYADR, /* matches 010 */ + REG020_REFADR, + + REG020_DPYSTL, + REG020_DPYSTH, + REG020_DPYNXL, + REG020_DPYNXH, + REG020_DINCL, + REG020_DINCH, + REG020_RES0, + REG020_HESERR, + REG020_RES1, + REG020_RES2, + REG020_RES3, + REG020_RES4, + REG020_SCOUNT, + REG020_BSFLTST, + REG020_DPYMSK, + REG020_RES5, + + REG020_SETVCNT, + REG020_SETHCNT, + REG020_BSFLTDL, + REG020_BSFLTDH, + REG020_RES6, + REG020_RES7, + REG020_RES8, + REG020_RES9, + REG020_IHOST1L, + REG020_IHOST1H, + REG020_IHOST2L, + REG020_IHOST2H, + REG020_IHOST3L, + REG020_IHOST3H, + REG020_IHOST4L, + REG020_IHOST4H +}; + +/* Interrupts that are generated by the processor internally */ +#define TMS34010_INT1 0x0002 /* External Interrupt 1 */ +#define TMS34010_INT2 0x0004 /* External Interrupt 2 */ +#define TMS34010_HI 0x0200 /* Host Interrupt */ +#define TMS34010_DI 0x0400 /* Display Interrupt */ +#define TMS34010_WV 0x0800 /* Window Violation Interrupt */ + + +/* Configuration structure */ +struct tms34010_display_params +{ + UINT16 vcount; /* most recent VCOUNT */ + UINT16 veblnk, vsblnk; /* start/end of VBLANK */ + UINT16 heblnk, hsblnk; /* start/end of HBLANK */ + UINT16 rowaddr, coladdr; /* row/column addresses */ + UINT8 yoffset; /* y offset from addresses */ + UINT8 enabled; /* video enabled */ +}; + + +#define MCFG_TMS340X0_HALT_ON_RESET(_value) \ + tms340x0_device::set_halt_on_reset(*device, _value); + +#define MCFG_TMS340X0_PIXEL_CLOCK(_value) \ + tms340x0_device::set_pixel_clock(*device, _value); + +#define MCFG_TMS340X0_PIXELS_PER_CLOCK(_value) \ + tms340x0_device::set_pixels_per_clock(*device, _value); + +typedef device_delegate scanline_ind16_cb_delegate; + +#define TMS340X0_SCANLINE_IND16_CB_MEMBER(_name) void _name(screen_device &screen, bitmap_ind16 &bitmap, int scanline, const tms34010_display_params *params) + +#define MCFG_TMS340X0_SCANLINE_IND16_CB(_class, _method) \ + tms340x0_device::set_scanline_ind16_callback(*device, scanline_ind16_cb_delegate(&_class::_method, #_class "::" #_method, downcast<_class *>(owner))); + + +typedef device_delegate scanline_rgb32_cb_delegate; + +#define TMS340X0_SCANLINE_RGB32_CB_MEMBER(_name) void _name(screen_device &screen, bitmap_rgb32 &bitmap, int scanline, const tms34010_display_params *params) + +#define MCFG_TMS340X0_SCANLINE_RGB32_CB(_class, _method) \ + tms340x0_device::set_scanline_rgb32_callback(*device, scanline_rgb32_cb_delegate(&_class::_method, #_class "::" #_method, downcast<_class *>(owner))); + + +#define MCFG_TMS340X0_OUTPUT_INT_CB(_devcb) \ + devcb = &tms340x0_device::set_output_int_callback(*device, DEVCB_##_devcb); + + +typedef device_delegate to_shiftreg_cb_delegate; + +#define TMS340X0_TO_SHIFTREG_CB_MEMBER(_name) void _name(address_space &space, offs_t address, UINT16 *shiftreg) + +#define MCFG_TMS340X0_TO_SHIFTREG_CB(_class, _method) \ + tms340x0_device::set_to_shiftreg_callback(*device, to_shiftreg_cb_delegate(&_class::_method, #_class "::" #_method, downcast<_class *>(owner))); + + +typedef device_delegate from_shiftreg_cb_delegate; + +#define TMS340X0_FROM_SHIFTREG_CB_MEMBER(_name) void _name(address_space &space, offs_t address, UINT16 *shiftreg) + +#define MCFG_TMS340X0_FROM_SHIFTREG_CB(_class, _method) \ + tms340x0_device::set_from_shiftreg_callback(*device, from_shiftreg_cb_delegate(&_class::_method, #_class "::" #_method, downcast<_class *>(owner))); + + +class tms340x0_device : public cpu_device, + public device_video_interface +{ +public: + // construction/destruction + tms340x0_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname); + + static void set_halt_on_reset(device_t &device, bool halt_on_reset) { downcast(device).m_halt_on_reset = halt_on_reset; } + static void set_pixel_clock(device_t &device, UINT32 pixclock) { downcast(device).m_pixclock = pixclock; } + static void set_pixels_per_clock(device_t &device, int pixperclock) { downcast(device).m_pixperclock = pixperclock; } + static void set_scanline_ind16_callback(device_t &device, scanline_ind16_cb_delegate callback) { downcast(device).m_scanline_ind16_cb = callback; } + static void set_scanline_rgb32_callback(device_t &device, scanline_rgb32_cb_delegate callback) { downcast(device).m_scanline_rgb32_cb = callback; } + template static devcb_base &set_output_int_callback(device_t &device, _Object object) { return downcast(device).m_output_int_cb.set_callback(object); } + static void set_to_shiftreg_callback(device_t &device, to_shiftreg_cb_delegate callback) { downcast(device).m_to_shiftreg_cb = callback; } + static void set_from_shiftreg_callback(device_t &device, from_shiftreg_cb_delegate callback) { downcast(device).m_from_shiftreg_cb = callback; } + + void get_display_params(tms34010_display_params *params); + void tms34010_state_postload(); + + UINT32 tms340x0_ind16(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); + UINT32 tms340x0_rgb32(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); + + virtual DECLARE_WRITE16_MEMBER(io_register_w) = 0; + virtual DECLARE_READ16_MEMBER(io_register_r) = 0; + + DECLARE_WRITE16_MEMBER(host_w); + DECLARE_READ16_MEMBER(host_r); + + TIMER_CALLBACK_MEMBER(internal_interrupt_callback); + TIMER_CALLBACK_MEMBER(scanline_callback); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_execute_interface overrides + virtual UINT32 execute_min_cycles() const { return 1; } + virtual UINT32 execute_max_cycles() const { return 10000; } + virtual UINT32 execute_input_lines() const { return 2; } + virtual void execute_run(); + virtual void execute_set_input(int inputnum, int state); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const { return (spacenum == AS_PROGRAM) ? &m_program_config : NULL; } + + // device_state_interface overrides + virtual void state_string_export(const device_state_entry &entry, std::string &str); + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const { return 2; } + virtual UINT32 disasm_max_opcode_bytes() const { return 10; } + + typedef void (tms340x0_device::*pixel_write_func)(offs_t offset, UINT32 data); + typedef UINT32 (tms340x0_device::*pixel_read_func)(offs_t offset); + typedef UINT32 (tms340x0_device::*raster_op_func)(UINT32 newpix, UINT32 oldpix); + typedef void (tms340x0_device::*wfield_func)(offs_t offset, UINT32 data); + typedef UINT32 (tms340x0_device::*rfield_func)(offs_t offset); + typedef void (tms340x0_device::*opcode_func)(UINT16 op); + typedef UINT32 (tms340x0_device::*pixel_op_func)(UINT32, UINT32, UINT32); + typedef void (tms340x0_device::*pixblt_op_func)(int, int); + typedef void (tms340x0_device::*pixblt_b_op_func)(int); + typedef void (tms340x0_device::*word_write_func)(address_space &space, offs_t offset,UINT16 data); + typedef UINT16 (tms340x0_device::*word_read_func)(address_space &space, offs_t offset); + + static const wfield_func s_wfield_functions[32]; + static const rfield_func s_rfield_functions[64]; + static const opcode_func s_opcode_table[65536 >> 4]; + static const pixel_op_func s_pixel_op_table[32]; + static const UINT8 s_pixel_op_timing_table[33]; + static const pixblt_op_func s_pixblt_op_table[]; + static const pixblt_op_func s_pixblt_r_op_table[]; + static const pixblt_b_op_func s_pixblt_b_op_table[]; + static const pixblt_b_op_func s_fill_op_table[]; + static const pixel_write_func s_pixel_write_ops[4][6]; + static const pixel_read_func s_pixel_read_ops[6]; + static const raster_op_func s_raster_ops[32]; + + address_space_config m_program_config; + + UINT32 m_pc; + UINT32 m_ppc; + UINT32 m_st; + pixel_write_func m_pixel_write; + pixel_read_func m_pixel_read; + raster_op_func m_raster_op; + pixel_op_func m_pixel_op; + UINT32 m_pixel_op_timing; + UINT32 m_convsp; + UINT32 m_convdp; + UINT32 m_convmp; + INT32 m_gfxcycles; + UINT8 m_pixelshift; + UINT8 m_is_34020; + bool m_reset_deferred; + bool m_halt_on_reset; /* /HCS pin, which determines HALT state after reset */ + UINT8 m_hblank_stable; + UINT8 m_external_host_access; + UINT8 m_executing; + address_space *m_program; + direct_read_data *m_direct; + UINT32 m_pixclock; /* the pixel clock (0 means don't adjust screen size) */ + int m_pixperclock; /* pixels per clock */ + emu_timer *m_scantimer; + int m_icount; + + scanline_ind16_cb_delegate m_scanline_ind16_cb; + scanline_rgb32_cb_delegate m_scanline_rgb32_cb; + devcb_write_line m_output_int_cb; /* output interrupt callback */ + to_shiftreg_cb_delegate m_to_shiftreg_cb; /* shift register write */ + from_shiftreg_cb_delegate m_from_shiftreg_cb; /* shift register read */ + + struct XY + { +#ifdef LSB_FIRST + INT16 x; + INT16 y; +#else + INT16 y; + INT16 x; +#endif + }; + + /* A registers 0-15 map to regs[0]-regs[15] */ + /* B registers 0-15 map to regs[30]-regs[15] */ + union + { + INT32 reg; + XY xy; + } m_regs[31]; + + UINT16 m_IOregs[64]; + UINT16 m_shiftreg[(8 * 512 * sizeof(UINT16))/2]; + + UINT32 TMS34010_RDMEM_DWORD(offs_t A); + void TMS34010_WRMEM_DWORD(offs_t A, UINT32 V); + void SET_ST(UINT32 st); + void RESET_ST(); + UINT32 ROPCODE(); + INT16 PARAM_WORD(); + INT32 PARAM_LONG(); + INT16 PARAM_WORD_NO_INC(); + INT32 PARAM_LONG_NO_INC(); + UINT32 RBYTE(offs_t offset); + void WBYTE(offs_t offset, UINT32 data); + UINT32 RLONG(offs_t offset); + void WLONG(offs_t offset, UINT32 data); + void PUSH(UINT32 data); + INT32 POP(); + UINT32 read_pixel_1(offs_t offset); + UINT32 read_pixel_2(offs_t offset); + UINT32 read_pixel_4(offs_t offset); + UINT32 read_pixel_8(offs_t offset); + UINT32 read_pixel_16(offs_t offset); + UINT32 read_pixel_32(offs_t offset); + UINT32 read_pixel_shiftreg(offs_t offset); + void write_pixel_1(offs_t offset, UINT32 data); + void write_pixel_2(offs_t offset, UINT32 data); + void write_pixel_4(offs_t offset, UINT32 data); + void write_pixel_8(offs_t offset, UINT32 data); + void write_pixel_16(offs_t offset, UINT32 data); + void write_pixel_32(offs_t offset, UINT32 data); + void write_pixel_t_1(offs_t offset, UINT32 data); + void write_pixel_t_2(offs_t offset, UINT32 data); + void write_pixel_t_4(offs_t offset, UINT32 data); + void write_pixel_t_8(offs_t offset, UINT32 data); + void write_pixel_t_16(offs_t offset, UINT32 data); + void write_pixel_t_32(offs_t offset, UINT32 data); + void write_pixel_r_1(offs_t offset, UINT32 data); + void write_pixel_r_2(offs_t offset, UINT32 data); + void write_pixel_r_4(offs_t offset, UINT32 data); + void write_pixel_r_8(offs_t offset, UINT32 data); + void write_pixel_r_16(offs_t offset, UINT32 data); + void write_pixel_r_32(offs_t offset, UINT32 data); + void write_pixel_r_t_1(offs_t offset, UINT32 data); + void write_pixel_r_t_2(offs_t offset, UINT32 data); + void write_pixel_r_t_4(offs_t offset, UINT32 data); + void write_pixel_r_t_8(offs_t offset, UINT32 data); + void write_pixel_r_t_16(offs_t offset, UINT32 data); + void write_pixel_r_t_32(offs_t offset, UINT32 data); + void write_pixel_shiftreg(offs_t offset, UINT32 data); + UINT32 raster_op_1(UINT32 newpix, UINT32 oldpix); + UINT32 raster_op_2(UINT32 newpix, UINT32 oldpix); + UINT32 raster_op_3(UINT32 newpix, UINT32 oldpix); + UINT32 raster_op_4(UINT32 newpix, UINT32 oldpix); + UINT32 raster_op_5(UINT32 newpix, UINT32 oldpix); + UINT32 raster_op_6(UINT32 newpix, UINT32 oldpix); + UINT32 raster_op_7(UINT32 newpix, UINT32 oldpix); + UINT32 raster_op_8(UINT32 newpix, UINT32 oldpix); + UINT32 raster_op_9(UINT32 newpix, UINT32 oldpix); + UINT32 raster_op_10(UINT32 newpix, UINT32 oldpix); + UINT32 raster_op_11(UINT32 newpix, UINT32 oldpix); + UINT32 raster_op_12(UINT32 newpix, UINT32 oldpix); + UINT32 raster_op_13(UINT32 newpix, UINT32 oldpix); + UINT32 raster_op_14(UINT32 newpix, UINT32 oldpix); + UINT32 raster_op_15(UINT32 newpix, UINT32 oldpix); + UINT32 raster_op_16(UINT32 newpix, UINT32 oldpix); + UINT32 raster_op_17(UINT32 newpix, UINT32 oldpix); + UINT32 raster_op_18(UINT32 newpix, UINT32 oldpix); + UINT32 raster_op_19(UINT32 newpix, UINT32 oldpix); + UINT32 raster_op_20(UINT32 newpix, UINT32 oldpix); + UINT32 raster_op_21(UINT32 newpix, UINT32 oldpix); + void wfield_01(offs_t offset, UINT32 data); + void wfield_02(offs_t offset, UINT32 data); + void wfield_03(offs_t offset, UINT32 data); + void wfield_04(offs_t offset, UINT32 data); + void wfield_05(offs_t offset, UINT32 data); + void wfield_06(offs_t offset, UINT32 data); + void wfield_07(offs_t offset, UINT32 data); + void wfield_08(offs_t offset, UINT32 data); + void wfield_09(offs_t offset, UINT32 data); + void wfield_10(offs_t offset, UINT32 data); + void wfield_11(offs_t offset, UINT32 data); + void wfield_12(offs_t offset, UINT32 data); + void wfield_13(offs_t offset, UINT32 data); + void wfield_14(offs_t offset, UINT32 data); + void wfield_15(offs_t offset, UINT32 data); + void wfield_16(offs_t offset, UINT32 data); + void wfield_17(offs_t offset, UINT32 data); + void wfield_18(offs_t offset, UINT32 data); + void wfield_19(offs_t offset, UINT32 data); + void wfield_20(offs_t offset, UINT32 data); + void wfield_21(offs_t offset, UINT32 data); + void wfield_22(offs_t offset, UINT32 data); + void wfield_23(offs_t offset, UINT32 data); + void wfield_24(offs_t offset, UINT32 data); + void wfield_25(offs_t offset, UINT32 data); + void wfield_26(offs_t offset, UINT32 data); + void wfield_27(offs_t offset, UINT32 data); + void wfield_28(offs_t offset, UINT32 data); + void wfield_29(offs_t offset, UINT32 data); + void wfield_30(offs_t offset, UINT32 data); + void wfield_31(offs_t offset, UINT32 data); + void wfield_32(offs_t offset, UINT32 data); + UINT32 rfield_z_01(offs_t offset); + UINT32 rfield_z_02(offs_t offset); + UINT32 rfield_z_03(offs_t offset); + UINT32 rfield_z_04(offs_t offset); + UINT32 rfield_z_05(offs_t offset); + UINT32 rfield_z_06(offs_t offset); + UINT32 rfield_z_07(offs_t offset); + UINT32 rfield_z_08(offs_t offset); + UINT32 rfield_z_09(offs_t offset); + UINT32 rfield_z_10(offs_t offset); + UINT32 rfield_z_11(offs_t offset); + UINT32 rfield_z_12(offs_t offset); + UINT32 rfield_z_13(offs_t offset); + UINT32 rfield_z_14(offs_t offset); + UINT32 rfield_z_15(offs_t offset); + UINT32 rfield_z_16(offs_t offset); + UINT32 rfield_z_17(offs_t offset); + UINT32 rfield_z_18(offs_t offset); + UINT32 rfield_z_19(offs_t offset); + UINT32 rfield_z_20(offs_t offset); + UINT32 rfield_z_21(offs_t offset); + UINT32 rfield_z_22(offs_t offset); + UINT32 rfield_z_23(offs_t offset); + UINT32 rfield_z_24(offs_t offset); + UINT32 rfield_z_25(offs_t offset); + UINT32 rfield_z_26(offs_t offset); + UINT32 rfield_z_27(offs_t offset); + UINT32 rfield_z_28(offs_t offset); + UINT32 rfield_z_29(offs_t offset); + UINT32 rfield_z_30(offs_t offset); + UINT32 rfield_z_31(offs_t offset); + UINT32 rfield_32(offs_t offset); + UINT32 rfield_s_01(offs_t offset); + UINT32 rfield_s_02(offs_t offset); + UINT32 rfield_s_03(offs_t offset); + UINT32 rfield_s_04(offs_t offset); + UINT32 rfield_s_05(offs_t offset); + UINT32 rfield_s_06(offs_t offset); + UINT32 rfield_s_07(offs_t offset); + UINT32 rfield_s_08(offs_t offset); + UINT32 rfield_s_09(offs_t offset); + UINT32 rfield_s_10(offs_t offset); + UINT32 rfield_s_11(offs_t offset); + UINT32 rfield_s_12(offs_t offset); + UINT32 rfield_s_13(offs_t offset); + UINT32 rfield_s_14(offs_t offset); + UINT32 rfield_s_15(offs_t offset); + UINT32 rfield_s_16(offs_t offset); + UINT32 rfield_s_17(offs_t offset); + UINT32 rfield_s_18(offs_t offset); + UINT32 rfield_s_19(offs_t offset); + UINT32 rfield_s_20(offs_t offset); + UINT32 rfield_s_21(offs_t offset); + UINT32 rfield_s_22(offs_t offset); + UINT32 rfield_s_23(offs_t offset); + UINT32 rfield_s_24(offs_t offset); + UINT32 rfield_s_25(offs_t offset); + UINT32 rfield_s_26(offs_t offset); + UINT32 rfield_s_27(offs_t offset); + UINT32 rfield_s_28(offs_t offset); + UINT32 rfield_s_29(offs_t offset); + UINT32 rfield_s_30(offs_t offset); + UINT32 rfield_s_31(offs_t offset); + void unimpl(UINT16 op); + void pixblt_l_l(UINT16 op); /* 0f00 */ + void pixblt_l_xy(UINT16 op); /* 0f20 */ + void pixblt_xy_l(UINT16 op); /* 0f40 */ + void pixblt_xy_xy(UINT16 op); /* 0f60 */ + void pixblt_b_l(UINT16 op); /* 0f80 */ + void pixblt_b_xy(UINT16 op); /* 0fa0 */ + void fill_l(UINT16 op); /* 0fc0 */ + void fill_xy(UINT16 op); /* 0fe0 */ + void line(UINT16 op); /* df10/df90 */ + void add_xy_a(UINT16 op); /* e000/e100 */ + void add_xy_b(UINT16 op); /* e000/e100 */ + void sub_xy_a(UINT16 op); /* e200/e300 */ + void sub_xy_b(UINT16 op); /* e200/e300 */ + void cmp_xy_a(UINT16 op); /* e400/e500 */ + void cmp_xy_b(UINT16 op); /* e400/e500 */ + void cpw_a(UINT16 op); /* e600/e700 */ + void cpw_b(UINT16 op); /* e600/e700 */ + void cvxyl_a(UINT16 op); /* e800/e900 */ + void cvxyl_b(UINT16 op); /* e800/e900 */ + void movx_a(UINT16 op); /* ec00/ed00 */ + void movx_b(UINT16 op); /* ec00/ed00 */ + void movy_a(UINT16 op); /* ee00/ef00 */ + void movy_b(UINT16 op); /* ee00/ef00 */ + void pixt_ri_a(UINT16 op); /* f800/f900 */ + void pixt_ri_b(UINT16 op); /* f800/f900 */ + void pixt_rixy_a(UINT16 op); /* f000/f100 */ + void pixt_rixy_b(UINT16 op); /* f000/f100 */ + void pixt_ir_a(UINT16 op); /* fa00/fb00 */ + void pixt_ir_b(UINT16 op); /* fa00/fb00 */ + void pixt_ii_a(UINT16 op); /* fc00/fd00 */ + void pixt_ii_b(UINT16 op); /* fc00/fd00 */ + void pixt_ixyr_a(UINT16 op); /* f200/f300 */ + void pixt_ixyr_b(UINT16 op); /* f200/f300 */ + void pixt_ixyixy_a(UINT16 op); /* f400/f500 */ + void pixt_ixyixy_b(UINT16 op); /* f400/f500 */ + void drav_a(UINT16 op); /* f600/f700 */ + void drav_b(UINT16 op); /* f600/f700 */ + void abs_a(UINT16 op); /* 0380 */ + void abs_b(UINT16 op); /* 0390 */ + void add_a(UINT16 op); /* 4000/4100 */ + void add_b(UINT16 op); /* 4000/4100 */ + void addc_a(UINT16 op); /* 4200/4200 */ + void addc_b(UINT16 op); /* 4200/4200 */ + void addi_w_a(UINT16 op); /* 0b00 */ + void addi_w_b(UINT16 op); /* 0b10 */ + void addi_l_a(UINT16 op); /* 0b20 */ + void addi_l_b(UINT16 op); /* 0b30 */ + void addk_a(UINT16 op); /* 1000-1300 */ + void addk_b(UINT16 op); /* 1000-1300 */ + void and_a(UINT16 op); /* 5000/5100 */ + void and_b(UINT16 op); /* 5000/5100 */ + void andi_a(UINT16 op); /* 0b80 */ + void andi_b(UINT16 op); /* 0b90 */ + void andn_a(UINT16 op); /* 5200-5300 */ + void andn_b(UINT16 op); /* 5200-5300 */ + void btst_k_a(UINT16 op); /* 1c00-1f00 */ + void btst_k_b(UINT16 op); /* 1c00-1f00 */ + void btst_r_a(UINT16 op); /* 4a00-4b00 */ + void btst_r_b(UINT16 op); /* 4a00-4b00 */ + void clrc(UINT16 op); /* 0320 */ + void cmp_a(UINT16 op); /* 4800/4900 */ + void cmp_b(UINT16 op); /* 4800/4900 */ + void cmpi_w_a(UINT16 op); /* 0b40 */ + void cmpi_w_b(UINT16 op); /* 0b50 */ + void cmpi_l_a(UINT16 op); /* 0b60 */ + void cmpi_l_b(UINT16 op); /* 0b70 */ + void dint(UINT16 op); + void divs_a(UINT16 op); /* 5800/5900 */ + void divs_b(UINT16 op); /* 5800/5900 */ + void divu_a(UINT16 op); /* 5a00/5b00 */ + void divu_b(UINT16 op); /* 5a00/5b00 */ + void eint(UINT16 op); + void exgf0_a(UINT16 op); /* d500 */ + void exgf0_b(UINT16 op); /* d510 */ + void exgf1_a(UINT16 op); /* d700 */ + void exgf1_b(UINT16 op); /* d710 */ + void lmo_a(UINT16 op); /* 6a00/6b00 */ + void lmo_b(UINT16 op); /* 6a00/6b00 */ + void mmfm_a(UINT16 op); /* 09a0 */ + void mmfm_b(UINT16 op); /* 09b0 */ + void mmtm_a(UINT16 op); /* 0980 */ + void mmtm_b(UINT16 op); /* 0990 */ + void mods_a(UINT16 op); /* 6c00/6d00 */ + void mods_b(UINT16 op); /* 6c00/6d00 */ + void modu_a(UINT16 op); /* 6e00/6f00 */ + void modu_b(UINT16 op); /* 6e00/6f00 */ + void mpys_a(UINT16 op); /* 5c00/5d00 */ + void mpys_b(UINT16 op); /* 5c00/5d00 */ + void mpyu_a(UINT16 op); /* 5e00/5e00 */ + void mpyu_b(UINT16 op); /* 5e00/5f00 */ + void neg_a(UINT16 op); /* 03a0 */ + void neg_b(UINT16 op); /* 03b0 */ + void negb_a(UINT16 op); /* 03c0 */ + void negb_b(UINT16 op); /* 03d0 */ + void nop(UINT16 op); /* 0300 */ + void not_a(UINT16 op); /* 03e0 */ + void not_b(UINT16 op); /* 03f0 */ + void or_a(UINT16 op); /* 5400-5500 */ + void or_b(UINT16 op); /* 5400-5500 */ + void ori_a(UINT16 op); /* 0ba0 */ + void ori_b(UINT16 op); /* 0bb0 */ + void rl_k_a(UINT16 op); /* 3000-3300 */ + void rl_k_b(UINT16 op); /* 3000-3300 */ + void rl_r_a(UINT16 op); /* 6800/6900 */ + void rl_r_b(UINT16 op); /* 6800/6900 */ + void setc(UINT16 op); /* 0de0 */ + void setf0(UINT16 op); + void setf1(UINT16 op); + void sext0_a(UINT16 op); /* 0500 */ + void sext0_b(UINT16 op); /* 0510 */ + void sext1_a(UINT16 op); /* 0700 */ + void sext1_b(UINT16 op); /* 0710 */ + void sla_k_a(UINT16 op); /* 2000-2300 */ + void sla_k_b(UINT16 op); /* 2000-2300 */ + void sla_r_a(UINT16 op); /* 6000/6100 */ + void sla_r_b(UINT16 op); /* 6000/6100 */ + void sll_k_a(UINT16 op); /* 2400-2700 */ + void sll_k_b(UINT16 op); /* 2400-2700 */ + void sll_r_a(UINT16 op); /* 6200/6300 */ + void sll_r_b(UINT16 op); /* 6200/6300 */ + void sra_k_a(UINT16 op); /* 2800-2b00 */ + void sra_k_b(UINT16 op); /* 2800-2b00 */ + void sra_r_a(UINT16 op); /* 6400/6500 */ + void sra_r_b(UINT16 op); /* 6400/6500 */ + void srl_k_a(UINT16 op); /* 2c00-2f00 */ + void srl_k_b(UINT16 op); /* 2c00-2f00 */ + void srl_r_a(UINT16 op); /* 6600/6700 */ + void srl_r_b(UINT16 op); /* 6600/6700 */ + void sub_a(UINT16 op); /* 4400/4500 */ + void sub_b(UINT16 op); /* 4400/4500 */ + void subb_a(UINT16 op); /* 4600/4700 */ + void subb_b(UINT16 op); /* 4600/4700 */ + void subi_w_a(UINT16 op); /* 0be0 */ + void subi_w_b(UINT16 op); /* 0bf0 */ + void subi_l_a(UINT16 op); /* 0d00 */ + void subi_l_b(UINT16 op); /* 0d10 */ + void subk_a(UINT16 op); /* 1400-1700 */ + void subk_b(UINT16 op); /* 1400-1700 */ + void xor_a(UINT16 op); /* 5600-5700 */ + void xor_b(UINT16 op); /* 5600-5700 */ + void xori_a(UINT16 op); /* 0bc0 */ + void xori_b(UINT16 op); /* 0bd0 */ + void zext0_a(UINT16 op); /* 0520 */ + void zext0_b(UINT16 op); /* 0530 */ + void zext1_a(UINT16 op); /* 0720 */ + void zext1_b(UINT16 op); /* 0720 */ + void movi_w_a(UINT16 op); + void movi_w_b(UINT16 op); + void movi_l_a(UINT16 op); + void movi_l_b(UINT16 op); + void movk_a(UINT16 op); + void movk_b(UINT16 op); + void movb_rn_a(UINT16 op); /* 8c00-8d00 */ + void movb_rn_b(UINT16 op); /* 8c00-8d00 */ + void movb_nr_a(UINT16 op); /* 8e00-8f00 */ + void movb_nr_b(UINT16 op); /* 8e00-8f00 */ + void movb_nn_a(UINT16 op); /* 9c00-9d00 */ + void movb_nn_b(UINT16 op); /* 9c00-9d00 */ + void movb_r_no_a(UINT16 op); /* ac00-ad00 */ + void movb_r_no_b(UINT16 op); /* ac00-ad00 */ + void movb_no_r_a(UINT16 op); /* ae00-af00 */ + void movb_no_r_b(UINT16 op); /* ae00-af00 */ + void movb_no_no_a(UINT16 op); /* bc00-bd00 */ + void movb_no_no_b(UINT16 op); /* bc00-bd00 */ + void movb_ra_a(UINT16 op); + void movb_ra_b(UINT16 op); + void movb_ar_a(UINT16 op); + void movb_ar_b(UINT16 op); + void movb_aa(UINT16 op); + void move_rr_a(UINT16 op); /* 4c00/d00 */ + void move_rr_b(UINT16 op); /* 4c00/d00 */ + void move_rr_ax(UINT16 op); /* 4e00/f00 */ + void move_rr_bx(UINT16 op); /* 4e00/f00 */ + void move0_rn_a(UINT16 op); /* 8000 */ + void move0_rn_b(UINT16 op); + void move1_rn_a(UINT16 op); + void move1_rn_b(UINT16 op); + void move0_r_dn_a(UINT16 op); /* a000 */ + void move0_r_dn_b(UINT16 op); + void move1_r_dn_a(UINT16 op); + void move1_r_dn_b(UINT16 op); + void move0_r_ni_a(UINT16 op); /* 9000 */ + void move0_r_ni_b(UINT16 op); + void move1_r_ni_a(UINT16 op); + void move1_r_ni_b(UINT16 op); + void move0_nr_a(UINT16 op); /* 8400-500 */ + void move0_nr_b(UINT16 op); /* 8400-500 */ + void move1_nr_a(UINT16 op); /* 8600-700 */ + void move1_nr_b(UINT16 op); /* 8600-700 */ + void move0_dn_r_a(UINT16 op); /* A400-500 */ + void move0_dn_r_b(UINT16 op); /* A400-500 */ + void move1_dn_r_a(UINT16 op); /* A600-700 */ + void move1_dn_r_b(UINT16 op); /* A600-700 */ + void move0_ni_r_a(UINT16 op); /* 9400-500 */ + void move0_ni_r_b(UINT16 op); /* 9400-500 */ + void move1_ni_r_a(UINT16 op); /* 9600-700 */ + void move1_ni_r_b(UINT16 op); /* 9600-700 */ + void move0_nn_a(UINT16 op); /* 8800 */ + void move0_nn_b(UINT16 op); + void move1_nn_a(UINT16 op); + void move1_nn_b(UINT16 op); + void move0_dn_dn_a(UINT16 op); /* a800 */ + void move0_dn_dn_b(UINT16 op); + void move1_dn_dn_a(UINT16 op); + void move1_dn_dn_b(UINT16 op); + void move0_ni_ni_a(UINT16 op); /* 9800 */ + void move0_ni_ni_b(UINT16 op); + void move1_ni_ni_a(UINT16 op); + void move1_ni_ni_b(UINT16 op); + void move0_r_no_a(UINT16 op); /* b000 */ + void move0_r_no_b(UINT16 op); + void move1_r_no_a(UINT16 op); + void move1_r_no_b(UINT16 op); + void move0_no_r_a(UINT16 op); /* b400 */ + void move0_no_r_b(UINT16 op); + void move1_no_r_a(UINT16 op); + void move1_no_r_b(UINT16 op); + void move0_no_ni_a(UINT16 op); /* d000 */ + void move0_no_ni_b(UINT16 op); + void move1_no_ni_a(UINT16 op); + void move1_no_ni_b(UINT16 op); + void move0_no_no_a(UINT16 op); /* b800 */ + void move0_no_no_b(UINT16 op); + void move1_no_no_a(UINT16 op); + void move1_no_no_b(UINT16 op); + void move0_ra_a(UINT16 op); + void move0_ra_b(UINT16 op); + void move1_ra_a(UINT16 op); + void move1_ra_b(UINT16 op); + void move0_ar_a(UINT16 op); + void move0_ar_b(UINT16 op); + void move1_ar_a(UINT16 op); + void move1_ar_b(UINT16 op); + void move0_a_ni_a(UINT16 op); /* d400 */ + void move0_a_ni_b(UINT16 op); /* d410 */ + void move1_a_ni_a(UINT16 op); /* d600 */ + void move1_a_ni_b(UINT16 op); /* d610 */ + void move0_aa(UINT16 op); /* 05c0 */ + void move1_aa(UINT16 op); /* 07c0 */ + void call_a(UINT16 op); /* 0920 */ + void call_b(UINT16 op); /* 0930 */ + void callr(UINT16 op); /* 0d3f */ + void calla(UINT16 op); /* 0d5f */ + void dsj_a(UINT16 op); /* 0d80 */ + void dsj_b(UINT16 op); /* 0d90 */ + void dsjeq_a(UINT16 op); /* 0da0 */ + void dsjeq_b(UINT16 op); /* 0db0 */ + void dsjne_a(UINT16 op); /* 0dc0 */ + void dsjne_b(UINT16 op); /* 0dd0 */ + void dsjs_a(UINT16 op); + void dsjs_b(UINT16 op); + void emu(UINT16 op); /* 0100 */ + void exgpc_a(UINT16 op); /* 0120 */ + void exgpc_b(UINT16 op); /* 0130 */ + void getpc_a(UINT16 op); /* 0140 */ + void getpc_b(UINT16 op); /* 0150 */ + void getst_a(UINT16 op); /* 0180 */ + void getst_b(UINT16 op); /* 0190 */ + void j_UC_0(UINT16 op); + void j_UC_8(UINT16 op); + void j_UC_x(UINT16 op); + void j_P_0(UINT16 op); + void j_P_8(UINT16 op); + void j_P_x(UINT16 op); + void j_LS_0(UINT16 op); + void j_LS_8(UINT16 op); + void j_LS_x(UINT16 op); + void j_HI_0(UINT16 op); + void j_HI_8(UINT16 op); + void j_HI_x(UINT16 op); + void j_LT_0(UINT16 op); + void j_LT_8(UINT16 op); + void j_LT_x(UINT16 op); + void j_GE_0(UINT16 op); + void j_GE_8(UINT16 op); + void j_GE_x(UINT16 op); + void j_LE_0(UINT16 op); + void j_LE_8(UINT16 op); + void j_LE_x(UINT16 op); + void j_GT_0(UINT16 op); + void j_GT_8(UINT16 op); + void j_GT_x(UINT16 op); + void j_C_0(UINT16 op); + void j_C_8(UINT16 op); + void j_C_x(UINT16 op); + void j_NC_0(UINT16 op); + void j_NC_8(UINT16 op); + void j_NC_x(UINT16 op); + void j_EQ_0(UINT16 op); + void j_EQ_8(UINT16 op); + void j_EQ_x(UINT16 op); + void j_NE_0(UINT16 op); + void j_NE_8(UINT16 op); + void j_NE_x(UINT16 op); + void j_V_0(UINT16 op); + void j_V_8(UINT16 op); + void j_V_x(UINT16 op); + void j_NV_0(UINT16 op); + void j_NV_8(UINT16 op); + void j_NV_x(UINT16 op); + void j_N_0(UINT16 op); + void j_N_8(UINT16 op); + void j_N_x(UINT16 op); + void j_NN_0(UINT16 op); + void j_NN_8(UINT16 op); + void j_NN_x(UINT16 op); + void jump_a(UINT16 op); /* 0160 */ + void jump_b(UINT16 op); /* 0170 */ + void popst(UINT16 op); /* 01c0 */ + void pushst(UINT16 op); /* 01e0 */ + void putst_a(UINT16 op); /* 01a0 */ + void putst_b(UINT16 op); /* 01b0 */ + void reti(UINT16 op); /* 0940 */ + void rets(UINT16 op); /* 0960/70 */ + void rev_a(UINT16 op); /* 0020 */ + void rev_b(UINT16 op); /* 0030 */ + void trap(UINT16 op); /* 0900/10 */ + void addxyi_a(UINT16 op); + void addxyi_b(UINT16 op); + void blmove(UINT16 op); + void cexec_l(UINT16 op); + void cexec_s(UINT16 op); + void clip(UINT16 op); + void cmovcg_a(UINT16 op); + void cmovcg_b(UINT16 op); + void cmovcm_f(UINT16 op); + void cmovcm_b(UINT16 op); + void cmovgc_a(UINT16 op); + void cmovgc_b(UINT16 op); + void cmovgc_a_s(UINT16 op); + void cmovgc_b_s(UINT16 op); + void cmovmc_f(UINT16 op); + void cmovmc_f_va(UINT16 op); + void cmovmc_f_vb(UINT16 op); + void cmovmc_b(UINT16 op); + void cmp_k_a(UINT16 op); + void cmp_k_b(UINT16 op); + void cvdxyl_a(UINT16 op); + void cvdxyl_b(UINT16 op); + void cvmxyl_a(UINT16 op); + void cvmxyl_b(UINT16 op); + void cvsxyl_a(UINT16 op); + void cvsxyl_b(UINT16 op); + void exgps_a(UINT16 op); + void exgps_b(UINT16 op); + void fline(UINT16 op); + void fpixeq(UINT16 op); + void fpixne(UINT16 op); + void getps_a(UINT16 op); + void getps_b(UINT16 op); + void idle(UINT16 op); + void linit(UINT16 op); + void mwait(UINT16 op); + void pfill_xy(UINT16 op); + void pixblt_l_m_l(UINT16 op); + void retm(UINT16 op); + void rmo_a(UINT16 op); + void rmo_b(UINT16 op); + void rpix_a(UINT16 op); + void rpix_b(UINT16 op); + void setcdp(UINT16 op); + void setcmp(UINT16 op); + void setcsp(UINT16 op); + void swapf_a(UINT16 op); + void swapf_b(UINT16 op); + void tfill_xy(UINT16 op); + void trapl(UINT16 op); + void vblt_b_l(UINT16 op); + void vfill_l(UINT16 op); + void vlcol(UINT16 op); + int apply_window(const char *inst_name,int srcbpp, UINT32 *srcaddr, XY *dst, int *dx, int *dy); + int compute_fill_cycles(int left_partials, int right_partials, int full_words, int op_timing); + int compute_pixblt_cycles(int left_partials, int right_partials, int full_words, int op_timing); + int compute_pixblt_b_cycles(int left_partials, int right_partials, int full_words, int rows, int op_timing, int bpp); + void memory_w(address_space &space, offs_t offset,UINT16 data); + UINT16 memory_r(address_space &space, offs_t offset); + void shiftreg_w(address_space &space, offs_t offset, UINT16 data); + UINT16 shiftreg_r(address_space &space, offs_t offset); + UINT16 dummy_shiftreg_r(address_space &space, offs_t offset); + UINT32 pixel_op00(UINT32 dstpix, UINT32 mask, UINT32 srcpix); + UINT32 pixel_op01(UINT32 dstpix, UINT32 mask, UINT32 srcpix); + UINT32 pixel_op02(UINT32 dstpix, UINT32 mask, UINT32 srcpix); + UINT32 pixel_op03(UINT32 dstpix, UINT32 mask, UINT32 srcpix); + UINT32 pixel_op04(UINT32 dstpix, UINT32 mask, UINT32 srcpix); + UINT32 pixel_op05(UINT32 dstpix, UINT32 mask, UINT32 srcpix); + UINT32 pixel_op06(UINT32 dstpix, UINT32 mask, UINT32 srcpix); + UINT32 pixel_op07(UINT32 dstpix, UINT32 mask, UINT32 srcpix); + UINT32 pixel_op08(UINT32 dstpix, UINT32 mask, UINT32 srcpix); + UINT32 pixel_op09(UINT32 dstpix, UINT32 mask, UINT32 srcpix); + UINT32 pixel_op10(UINT32 dstpix, UINT32 mask, UINT32 srcpix); + UINT32 pixel_op11(UINT32 dstpix, UINT32 mask, UINT32 srcpix); + UINT32 pixel_op12(UINT32 dstpix, UINT32 mask, UINT32 srcpix); + UINT32 pixel_op13(UINT32 dstpix, UINT32 mask, UINT32 srcpix); + UINT32 pixel_op14(UINT32 dstpix, UINT32 mask, UINT32 srcpix); + UINT32 pixel_op15(UINT32 dstpix, UINT32 mask, UINT32 srcpix); + UINT32 pixel_op16(UINT32 dstpix, UINT32 mask, UINT32 srcpix); + UINT32 pixel_op17(UINT32 dstpix, UINT32 mask, UINT32 srcpix); + UINT32 pixel_op18(UINT32 dstpix, UINT32 mask, UINT32 srcpix); + UINT32 pixel_op19(UINT32 dstpix, UINT32 mask, UINT32 srcpix); + UINT32 pixel_op20(UINT32 dstpix, UINT32 mask, UINT32 srcpix); + UINT32 pixel_op21(UINT32 dstpix, UINT32 mask, UINT32 srcpix); + void pixblt_1_op0(int src_is_linear, int dst_is_linear); + void pixblt_2_op0(int src_is_linear, int dst_is_linear); + void pixblt_4_op0(int src_is_linear, int dst_is_linear); + void pixblt_8_op0(int src_is_linear, int dst_is_linear); + void pixblt_16_op0(int src_is_linear, int dst_is_linear); + void pixblt_r_1_op0(int src_is_linear, int dst_is_linear); + void pixblt_r_2_op0(int src_is_linear, int dst_is_linear); + void pixblt_r_4_op0(int src_is_linear, int dst_is_linear); + void pixblt_r_8_op0(int src_is_linear, int dst_is_linear); + void pixblt_r_16_op0(int src_is_linear, int dst_is_linear); + void pixblt_b_1_op0(int dst_is_linear); + void pixblt_b_2_op0(int dst_is_linear); + void pixblt_b_4_op0(int dst_is_linear); + void pixblt_b_8_op0(int dst_is_linear); + void pixblt_b_16_op0(int dst_is_linear); + void fill_1_op0(int dst_is_linear); + void fill_2_op0(int dst_is_linear); + void fill_4_op0(int dst_is_linear); + void fill_8_op0(int dst_is_linear); + void fill_16_op0(int dst_is_linear); + void pixblt_1_op0_trans(int src_is_linear, int dst_is_linear); + void pixblt_2_op0_trans(int src_is_linear, int dst_is_linear); + void pixblt_4_op0_trans(int src_is_linear, int dst_is_linear); + void pixblt_8_op0_trans(int src_is_linear, int dst_is_linear); + void pixblt_16_op0_trans(int src_is_linear, int dst_is_linear); + void pixblt_r_1_op0_trans(int src_is_linear, int dst_is_linear); + void pixblt_r_2_op0_trans(int src_is_linear, int dst_is_linear); + void pixblt_r_4_op0_trans(int src_is_linear, int dst_is_linear); + void pixblt_r_8_op0_trans(int src_is_linear, int dst_is_linear); + void pixblt_r_16_op0_trans(int src_is_linear, int dst_is_linear); + void pixblt_b_1_op0_trans(int dst_is_linear); + void pixblt_b_2_op0_trans(int dst_is_linear); + void pixblt_b_4_op0_trans(int dst_is_linear); + void pixblt_b_8_op0_trans(int dst_is_linear); + void pixblt_b_16_op0_trans(int dst_is_linear); + void fill_1_op0_trans(int dst_is_linear); + void fill_2_op0_trans(int dst_is_linear); + void fill_4_op0_trans(int dst_is_linear); + void fill_8_op0_trans(int dst_is_linear); + void fill_16_op0_trans(int dst_is_linear); + void pixblt_1_opx(int src_is_linear, int dst_is_linear); + void pixblt_2_opx(int src_is_linear, int dst_is_linear); + void pixblt_4_opx(int src_is_linear, int dst_is_linear); + void pixblt_8_opx(int src_is_linear, int dst_is_linear); + void pixblt_16_opx(int src_is_linear, int dst_is_linear); + void pixblt_r_1_opx(int src_is_linear, int dst_is_linear); + void pixblt_r_2_opx(int src_is_linear, int dst_is_linear); + void pixblt_r_4_opx(int src_is_linear, int dst_is_linear); + void pixblt_r_8_opx(int src_is_linear, int dst_is_linear); + void pixblt_r_16_opx(int src_is_linear, int dst_is_linear); + void pixblt_b_1_opx(int dst_is_linear); + void pixblt_b_2_opx(int dst_is_linear); + void pixblt_b_4_opx(int dst_is_linear); + void pixblt_b_8_opx(int dst_is_linear); + void pixblt_b_16_opx(int dst_is_linear); + void fill_1_opx(int dst_is_linear); + void fill_2_opx(int dst_is_linear); + void fill_4_opx(int dst_is_linear); + void fill_8_opx(int dst_is_linear); + void fill_16_opx(int dst_is_linear); + void pixblt_1_opx_trans(int src_is_linear, int dst_is_linear); + void pixblt_2_opx_trans(int src_is_linear, int dst_is_linear); + void pixblt_4_opx_trans(int src_is_linear, int dst_is_linear); + void pixblt_8_opx_trans(int src_is_linear, int dst_is_linear); + void pixblt_16_opx_trans(int src_is_linear, int dst_is_linear); + void pixblt_r_1_opx_trans(int src_is_linear, int dst_is_linear); + void pixblt_r_2_opx_trans(int src_is_linear, int dst_is_linear); + void pixblt_r_4_opx_trans(int src_is_linear, int dst_is_linear); + void pixblt_r_8_opx_trans(int src_is_linear, int dst_is_linear); + void pixblt_r_16_opx_trans(int src_is_linear, int dst_is_linear); + void pixblt_b_1_opx_trans(int dst_is_linear); + void pixblt_b_2_opx_trans(int dst_is_linear); + void pixblt_b_4_opx_trans(int dst_is_linear); + void pixblt_b_8_opx_trans(int dst_is_linear); + void pixblt_b_16_opx_trans(int dst_is_linear); + void fill_1_opx_trans(int dst_is_linear); + void fill_2_opx_trans(int dst_is_linear); + void fill_4_opx_trans(int dst_is_linear); + void fill_8_opx_trans(int dst_is_linear); + void fill_16_opx_trans(int dst_is_linear); + void check_interrupt(); + void set_pixel_function(); + void set_raster_op(); + +}; + + +class tms34010_device : public tms340x0_device +{ +public: + tms34010_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + /* Reads & writes to the 34010 I/O registers; place at 0xc0000000 */ + virtual DECLARE_WRITE16_MEMBER( io_register_w ); + virtual DECLARE_READ16_MEMBER( io_register_r ); + +protected: + virtual UINT64 execute_clocks_to_cycles(UINT64 clocks) const { return (clocks + 8 - 1) / 8; } + virtual UINT64 execute_cycles_to_clocks(UINT64 cycles) const { return (cycles * 8); } + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); +}; + +extern const device_type TMS34010; + +class tms34020_device : public tms340x0_device +{ +public: + tms34020_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + /* Reads & writes to the 34010 I/O registers; place at 0xc0000000 */ + virtual DECLARE_WRITE16_MEMBER( io_register_w ); + virtual DECLARE_READ16_MEMBER( io_register_r ); + +protected: + virtual UINT64 execute_clocks_to_cycles(UINT64 clocks) const { return (clocks + 4 - 1) / 4; } + virtual UINT64 execute_cycles_to_clocks(UINT64 cycles) const { return (cycles * 4); } + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); +}; + +extern const device_type TMS34020; + + + +/* Host control interface */ +#define TMS34010_HOST_ADDRESS_L 0 +#define TMS34010_HOST_ADDRESS_H 1 +#define TMS34010_HOST_DATA 2 +#define TMS34010_HOST_CONTROL 3 + +/* Use this macro in the memory definitions to specify bit-based addresses */ +#define TOBYTE(bitaddr) ((offs_t)(bitaddr) >> 3) +#define TOWORD(bitaddr) ((offs_t)(bitaddr) >> 4) + + +CPU_DISASSEMBLE( tms34010 ); +CPU_DISASSEMBLE( tms34020 ); + +#endif /* __TMS34010_H__ */ diff --git a/src/devices/cpu/tms57002/57002dsm.c b/src/devices/cpu/tms57002/57002dsm.c new file mode 100644 index 00000000000..960054806fc --- /dev/null +++ b/src/devices/cpu/tms57002/57002dsm.c @@ -0,0 +1,95 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +/*************************************************************************** + + 57002dsm.c + + TMS57002 "DASP" emulator. + +***************************************************************************/ + +#include "emu.h" +#include "debugger.h" +#include "tms57002.h" + +static const char *get_memadr(UINT32 opcode, char type) +{ + static char buff[2][10]; + static int index = 0; + char *buf; + + index = 1-index; + buf = buff[index]; + + if(((opcode & 0x400) && (type == 'c')) || (!(opcode & 0x400) && (type == 'd'))) { + if(opcode & 0x100) + sprintf(buf, "%c(%02x)", type, opcode & 0xff); + else if(opcode & 0x80) + sprintf(buf, "%c*+", type); + else + sprintf(buf, "%c*", type); + } else if(opcode & 0x200) + sprintf(buf, "%c*+", type); + else + sprintf(buf, "%c*", type); + return buf; +} + + +CPU_DISASSEMBLE(tms57002) +{ + UINT32 opcode = opram[0] | (opram[1] << 8) | (opram[2] << 16); + UINT8 fa = opcode >> 18; + char *buf = buffer; + if(fa == 0x3f) { + switch((opcode >> 11) & 0x7f) { // category 3 + +#define DASM3 +#include "cpu/tms57002/tms57002.inc" +#undef DASM3 + + default: + sprintf(buf, "unk c3 %02x", (opcode >> 11) & 0x7f); + break; + } + } else { + switch(fa) { // category 1 + case 0x00: + buf[0] = 0; + break; + +#define DASM1 +#include "cpu/tms57002/tms57002.inc" +#undef DASM1 + + default: + sprintf(buf, "unk c1 %02x", fa); + break; + } + + buf += strlen(buf); + if(buf != buffer) { + strcpy(buf, " ; "); + buf += 3; + } + + switch((opcode >> 11) & 0x7f) { // category 2 + case 0x00: + if(buf != buffer) + buf[-3] = 0; + else + sprintf(buf, "nop"); + break; + +#define DASM2 +#include "cpu/tms57002/tms57002.inc" +#undef DASM2 + + default: + sprintf(buf, "unk c2 %02x", (opcode >> 11) & 0x7f); + break; + } + } + + return 1; +} diff --git a/src/devices/cpu/tms57002/tms57002.c b/src/devices/cpu/tms57002/tms57002.c new file mode 100644 index 00000000000..fb55dfa916c --- /dev/null +++ b/src/devices/cpu/tms57002/tms57002.c @@ -0,0 +1,917 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +/*************************************************************************** + + tms57002.c + + TMS57002 "DASP" emulator. + +***************************************************************************/ + + +#include "emu.h" +#include "debugger.h" +#include "tms57002.h" + +const device_type TMS57002 = &device_creator; + +// Can't use a DEVICE_ADDRESS_MAP, not yet anyway +static ADDRESS_MAP_START(internal_pgm, AS_PROGRAM, 32, tms57002_device) + AM_RANGE(0x000, 0x3ff) AM_RAM +ADDRESS_MAP_END + +tms57002_device::tms57002_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : cpu_device(mconfig, TMS57002, "TMS57002", tag, owner, clock, "tms57002", __FILE__), + device_sound_interface(mconfig, *this), + txrd(0), + program_config("program", ENDIANNESS_LITTLE, 32, 8, -2, ADDRESS_MAP_NAME(internal_pgm)), + data_config("data", ENDIANNESS_LITTLE, 8, 20) +{ +} + + +WRITE_LINE_MEMBER(tms57002_device::pload_w) +{ + UINT8 olds = sti; + if(state) + sti &= ~IN_PLOAD; + else + sti |= IN_PLOAD; + if(olds ^ sti) { + if (sti & IN_PLOAD) { + hidx = 0; + hpc = 0; + } + } +} + +WRITE_LINE_MEMBER(tms57002_device::cload_w) +{ + UINT8 olds = sti; + if(state) + sti &= ~IN_CLOAD; + else + sti |= IN_CLOAD; + if(olds ^ sti) { + if (sti & IN_CLOAD) { + hidx = 0; + ca = 0; + } + } +} + +void tms57002_device::device_reset() +{ + sti = (sti & ~(SU_MASK|S_READ|S_WRITE|S_BRANCH|S_HOST)) | (SU_ST0|S_IDLE); + pc = 0; + ca = 0; + hidx = 0; + id = 0; + ba0 = 0; + ba1 = 0; + st0 &= ~(ST0_INCS | ST0_DIRI | ST0_FI | ST0_SIM | ST0_PLRI | + ST0_PBCI | ST0_DIRO | ST0_FO | ST0_SOM | ST0_PLRO | + ST0_PBCO | ST0_CNS); + st1 &= ~(ST1_AOV | ST1_SFAI | ST1_SFAO | ST1_MOVM | ST1_MOV | + ST1_SFMA | ST1_SFMO | ST1_RND | ST1_CRM | ST1_DBP); + + xba = 0; + xoa = 0; + cache_flush(); +} + +WRITE8_MEMBER(tms57002_device::data_w) +{ + switch(sti & (IN_PLOAD|IN_CLOAD)) { + case 0: + hidx = 0; + sti &= ~SU_CVAL; + break; + case IN_PLOAD: + host[hidx++] = data; + if(hidx >= 3) { + UINT32 val = (host[0]<<16) | (host[1]<<8) | host[2]; + hidx = 0; + + switch(sti & SU_MASK) { + case SU_ST0: + st0 = val; + sti = (sti & ~SU_MASK) | SU_ST1; + break; + case SU_ST1: + st1 = val; + sti = (sti & ~SU_MASK) | SU_PRG; + break; + case SU_PRG: + program->write_dword(pc++ << 2, val); + break; + } + } + break; + case IN_CLOAD: + if(sti & SU_CVAL) { + host[hidx++] = data; + if(hidx >= 4) { + UINT32 val = (host[0]<<24) | (host[1]<<16) | (host[2]<<8) | host[3]; + cmem[sa] = val; + sti &= ~SU_CVAL; + allow_update = 0; + } + } else { + sa = data; + hidx = 0; + sti |= SU_CVAL; + } + + break; + case IN_PLOAD|IN_CLOAD: + host[hidx++] = data; + if(hidx >= 4) { + UINT32 val = (host[0]<<24) | (host[1]<<16) | (host[2]<<8) | host[3]; + hidx = 0; + cmem[ca++] = val; + } + break; + }; +} + +READ8_MEMBER(tms57002_device::data_r) +{ + UINT8 res; + if(!(sti & S_HOST)) + return 0xff; + + res = host[hidx]; + hidx++; + if(hidx == 4) { + hidx = 0; + sti &= ~S_HOST; + } + + return res; +} + +READ_LINE_MEMBER(tms57002_device::empty_r) +{ + return 1; +} + +READ_LINE_MEMBER(tms57002_device::dready_r) +{ + return sti & S_HOST ? 0 : 1; +} + +READ_LINE_MEMBER(tms57002_device::pc0_r) +{ + return pc == 0 ? 0 : 1; +} + +WRITE_LINE_MEMBER(tms57002_device::sync_w) +{ + if(sti & (IN_PLOAD | IN_CLOAD)) + return; + + allow_update = 1; + pc = 0; + ca = 0; + id = 0; + if(!(st0 & ST0_INCS)) { + ba0--; + ba1++; + } + xba = (xba-1) & 0x7ffff; + st1 &= ~(ST1_AOV | ST1_MOV); + sti &= ~S_IDLE; +} + +void tms57002_device::xm_init() +{ + UINT32 adr = xoa + xba; + UINT32 mask = 0; + + switch(st0 & ST0_M) { + case ST0_M_64K: mask = 0x0ffff; break; + case ST0_M_256K: mask = 0x3ffff; break; + case ST0_M_1M: mask = 0xfffff; break; + } + if(st0 & ST0_WORD) + adr <<= 2; + else + adr <<= 1; + + if(!(st0 & ST0_SEL)) + adr <<= 1; + + xm_adr = adr & mask; +} + +inline void tms57002_device::xm_step_read() +{ + UINT32 adr = xm_adr; + UINT8 v = data->read_byte(adr); + int done; + if(st0 & ST0_WORD) { + if(st0 & ST0_SEL) { + int off = 16 - ((adr & 3) << 3); + txrd = (txrd & ~(0xff << off)) | (v << off); + done = off == 0; + } else { + int off = 20 - ((adr & 7) << 2); + txrd = (txrd & ~(0xf << off)) | ((v & 0xf) << off); + done = off == 0; + } + } else { + if(st0 & ST0_SEL) { + int off = 16 - ((adr & 1) << 3); + txrd = (txrd & ~(0xff << off)) | (v << off); + done = off == 8; + if(done) + txrd &= 0xffff00; + } else { + int off = 20 - ((adr & 3) << 2); + txrd = (txrd & ~(0xf << off)) | ((v & 0xf) << off); + done = off == 8; + if(done) + txrd &= 0xffff00; + } + } + if(done) { + xrd = txrd; + sti &= ~S_READ; + xm_adr = 0; + } else + xm_adr = adr+1; +} + +inline void tms57002_device::xm_step_write() +{ + UINT32 adr = xm_adr; + UINT8 v; + int done; + if(st0 & ST0_WORD) { + if(st0 & ST0_SEL) { + int off = 16 - ((adr & 3) << 3); + v = xwr >> off; + done = off == 0; + } else { + int off = 20 - ((adr & 7) << 2); + v = (xwr >> off) & 0xf; + done = off == 0; + } + } else { + if(st0 & ST0_SEL) { + int off = 16 - ((adr & 1) << 3); + v = xwr >> off; + done = off == 8; + } else { + int off = 20 - ((adr & 3) << 2); + v = (xwr >> off) & 0xf; + done = off == 8; + } + } + data->write_byte(adr, v); + if(done) { + sti &= ~S_WRITE; + xm_adr = 0; + } else + xm_adr = adr+1; +} + +INT64 tms57002_device::macc_to_output_0(INT64 rounding, UINT64 rmask) +{ + INT64 m = macc; + UINT64 m1; + int over = 0; + + // Overflow detection and shifting + m1 = m & 0xf800000000000ULL; + if(m1 && m1 != 0xf800000000000ULL) + over = 1; + + m = (m + rounding) & rmask; + + // Second overflow detection + m1 = m & 0xf800000000000ULL; + if(m1 && m1 != 0xf800000000000ULL) + over = 1; + + // Overflow handling + if(over) { + st1 |= ST1_MOV; + } + return m; +} + +INT64 tms57002_device::macc_to_output_1(INT64 rounding, UINT64 rmask) +{ + INT64 m = macc; + UINT64 m1; + int over = 0; + + // Overflow detection and shifting + m1 = m & 0xfe00000000000ULL; + if(m1 && m1 != 0xfe00000000000ULL) + over = 1; + m <<= 2; + + m = (m + rounding) & rmask; + + // Second overflow detection + m1 = m & 0xf800000000000ULL; + if(m1 && m1 != 0xf800000000000ULL) + over = 1; + + // Overflow handling + if(over) { + st1 |= ST1_MOV; + } + return m; +} + +INT64 tms57002_device::macc_to_output_2(INT64 rounding, UINT64 rmask) +{ + INT64 m = macc; + UINT64 m1; + int over = 0; + + // Overflow detection and shifting + m1 = m & 0xff80000000000ULL; + if(m1 && m1 != 0xff80000000000ULL) + over = 1; + m <<= 4; + + m = (m + rounding) & rmask; + + // Second overflow detection + m1 = m & 0xf800000000000ULL; + if(m1 && m1 != 0xf800000000000ULL) + over = 1; + + // Overflow handling + if(over) { + st1 |= ST1_MOV; + } + return m; +} + +INT64 tms57002_device::macc_to_output_3(INT64 rounding, UINT64 rmask) +{ + INT64 m = macc; + UINT64 m1; + int over = 0; + + // Overflow detection and shifting + m >>= 8; + + m = (m + rounding) & rmask; + + // Second overflow detection + m1 = m & 0xf800000000000ULL; + if(m1 && m1 != 0xf800000000000ULL) + over = 1; + + // Overflow handling + if(over) { + st1 |= ST1_MOV; + } + return m; +} + +INT64 tms57002_device::macc_to_output_0s(INT64 rounding, UINT64 rmask) +{ + INT64 m = macc; + UINT64 m1; + int over = 0; + + // Overflow detection and shifting + m1 = m & 0xf800000000000ULL; + if(m1 && m1 != 0xf800000000000ULL) + over = 1; + + m = (m + rounding) & rmask; + + // Second overflow detection + m1 = m & 0xf800000000000ULL; + if(m1 && m1 != 0xf800000000000ULL) + over = 1; + + // Overflow handling + if(over) { + st1 |= ST1_MOV; + if(m & 0x8000000000000ULL) + m = 0xffff800000000000ULL; + else + m = 0x00007fffffffffffULL; + } + return m; +} + +INT64 tms57002_device::macc_to_output_1s(INT64 rounding, UINT64 rmask) +{ + INT64 m = macc; + UINT64 m1; + int over = 0; + + // Overflow detection and shifting + m1 = m & 0xfe00000000000ULL; + if(m1 && m1 != 0xfe00000000000ULL) + over = 1; + m <<= 2; + + m = (m + rounding) & rmask; + + // Second overflow detection + m1 = m & 0xf800000000000ULL; + if(m1 && m1 != 0xf800000000000ULL) + over = 1; + + // Overflow handling + if(over) { + st1 |= ST1_MOV; + if(m & 0x8000000000000ULL) + m = 0xffff800000000000ULL; + else + m = 0x00007fffffffffffULL; + } + return m; +} + +INT64 tms57002_device::macc_to_output_2s(INT64 rounding, UINT64 rmask) +{ + INT64 m = macc; + UINT64 m1; + int over = 0; + + // Overflow detection and shifting + m1 = m & 0xff80000000000ULL; + if(m1 && m1 != 0xff80000000000ULL) + over = 1; + m <<= 4; + + m = (m + rounding) & rmask; + + // Second overflow detection + m1 = m & 0xf800000000000ULL; + if(m1 && m1 != 0xf800000000000ULL) + over = 1; + + // Overflow handling + if(over) { + st1 |= ST1_MOV; + if(m & 0x8000000000000ULL) + m = 0xffff800000000000ULL; + else + m = 0x00007fffffffffffULL; + } + return m; +} + +INT64 tms57002_device::macc_to_output_3s(INT64 rounding, UINT64 rmask) +{ + INT64 m = macc; + UINT64 m1; + int over = 0; + + // Overflow detection and shifting + m >>= 8; + + m = (m + rounding) & rmask; + + // Second overflow detection + m1 = m & 0xf800000000000ULL; + if(m1 && m1 != 0xf800000000000ULL) + over = 1; + + // Overflow handling + if(over) { + st1 |= ST1_MOV; + if(m & 0x8000000000000ULL) + m = 0xffff800000000000ULL; + else + m = 0x00007fffffffffffULL; + } + return m; +} + +INT64 tms57002_device::check_macc_overflow_0() +{ + INT64 m = macc; + UINT64 m1; + + // Overflow detection + m1 = m & 0xf800000000000ULL; + if(m1 && m1 != 0xf800000000000ULL) { + st1 |= ST1_MOV; + } + return m; +} + +INT64 tms57002_device::check_macc_overflow_1() +{ + INT64 m = macc; + UINT64 m1; + + // Overflow detection + m1 = m & 0xfe00000000000ULL; + if(m1 && m1 != 0xfe00000000000ULL) { + st1 |= ST1_MOV; + } + return m; +} + +INT64 tms57002_device::check_macc_overflow_2() +{ + INT64 m = macc; + UINT64 m1; + + // Overflow detection + m1 = m & 0xff80000000000ULL; + if(m1 && m1 != 0xff80000000000ULL) { + st1 |= ST1_MOV; + } + return m; +} + +INT64 tms57002_device::check_macc_overflow_3() +{ + return macc; +} + +INT64 tms57002_device::check_macc_overflow_0s() +{ + INT64 m = macc; + UINT64 m1; + + // Overflow detection + m1 = m & 0xf800000000000ULL; + if(m1 && m1 != 0xf800000000000ULL) { + st1 |= ST1_MOV; + if(m & 0x8000000000000ULL) + m = 0xffff800000000000ULL; + else + m = 0x00007fffffffffffULL; + } + return m; +} + +INT64 tms57002_device::check_macc_overflow_1s() +{ + INT64 m = macc; + UINT64 m1; + + // Overflow detection + m1 = m & 0xfe00000000000ULL; + if(m1 && m1 != 0xfe00000000000ULL) { + st1 |= ST1_MOV; + if(m & 0x8000000000000ULL) + m = 0xffff800000000000ULL; + else + m = 0x00007fffffffffffULL; + } + return m; +} + +INT64 tms57002_device::check_macc_overflow_2s() +{ + INT64 m = macc; + UINT64 m1; + + // Overflow detection + m1 = m & 0xff80000000000ULL; + if(m1 && m1 != 0xff80000000000ULL) { + st1 |= ST1_MOV; + if(m & 0x8000000000000ULL) + m = 0xffff800000000000ULL; + else + m = 0x00007fffffffffffULL; + } + return m; +} + +INT64 tms57002_device::check_macc_overflow_3s() +{ + return macc; +} + +void tms57002_device::cache_flush() +{ + int i; + cache.hused = cache.iused = 0; + for(i=0; i != 256; i++) + cache.hashbase[i] = -1; + for(i=0; i != HBS; i++) { + cache.hashnode[i].st1 = 0; + cache.hashnode[i].ipc = -1; + cache.hashnode[i].next = -1; + } + for(i=0; i != IBS; i++) { + cache.inst[i].op = 0; + cache.inst[i].next = -1; + cache.inst[i].param = 0; + } +} + +void tms57002_device::add_one(cstate *cs, unsigned short op, UINT8 param) +{ + short ipc = cache.iused++; + cache.inst[ipc].op = op; + cache.inst[ipc].param = param; + cache.inst[ipc].next = -1; + if(cs->ipc != -1) + cache.inst[cs->ipc].next = ipc; + cs->ipc = ipc; + if(cs->hnode != -1) { + cache.hashnode[cs->hnode].ipc = ipc; + cs->hnode = -1; + } +} + +void tms57002_device::decode_one(UINT32 opcode, cstate *cs, void (tms57002_device::*dec)(UINT32 opcode, unsigned short *op, cstate *cs)) +{ + unsigned short op = 0; + (this->*dec)(opcode, &op, cs); + if(!op) + return; + add_one(cs, op, opcode & 0xff); +} + +short tms57002_device::get_hash(unsigned char adr, UINT32 st1, short *pnode) +{ + short hnode; + st1 &= ST1_CACHE; + *pnode = -1; + hnode = cache.hashbase[adr]; + while(hnode != -1) { + if(cache.hashnode[hnode].st1 == st1) + return cache.hashnode[hnode].ipc; + *pnode = hnode; + hnode = cache.hashnode[hnode].next; + } + return -1; +} + +short tms57002_device::get_hashnode(unsigned char adr, UINT32 st1, short pnode) +{ + short hnode = cache.hused++; + cache.hashnode[hnode].st1 = st1 & ST1_CACHE; + cache.hashnode[hnode].ipc = -1; + cache.hashnode[hnode].next = -1; + if(pnode == -1) + cache.hashbase[adr] = hnode; + else + cache.hashnode[pnode].next = hnode; + return hnode; +} + +int tms57002_device::decode_get_pc() +{ + short pnode, res; + cstate cs; + UINT8 adr = pc; + + res = get_hash(adr, st1, &pnode); + if(res != -1) + return res; + + if(HBS - cache.hused < 256 || IBS - cache.iused < 256*3) { + cache_flush(); + pnode = -1; + } + + cs.hnode = res = get_hashnode(adr, st1, pnode); + cs.ipc = -1; + cs.branch = 0; + + for(;;) { + short ipc; + UINT32 opcode = program->read_dword(adr << 2); + + cs.inc = 0; + + if((opcode & 0xfc0000) == 0xfc0000) + decode_one(opcode, &cs, &tms57002_device::decode_cat3); + else { + decode_one(opcode, &cs, &tms57002_device::decode_cat2_pre); + decode_one(opcode, &cs, &tms57002_device::decode_cat1); + decode_one(opcode, &cs, &tms57002_device::decode_cat2_post); + } + add_one(&cs, cs.inc, 0); + + if(cs.branch) + break; + + adr++; + ipc = get_hash(adr, st1, &pnode); + if(ipc != -1) { + cache.inst[cs.ipc].next = ipc; + break; + } + cs.hnode = get_hashnode(adr, st1, pnode); + } + + return cache.hashnode[res].ipc; +} + +void tms57002_device::execute_run() +{ + int ipc = -1; + + while(icount > 0 && !(sti & (S_IDLE | IN_PLOAD | IN_CLOAD))) { + int iipc; + + debugger_instruction_hook(this, pc); + + if(ipc == -1) + ipc = decode_get_pc(); + + iipc = ipc; + + if(sti & (S_READ|S_WRITE)) { + if(sti & S_READ) + xm_step_read(); + else + xm_step_write(); + } + + for(;;) { + UINT32 c, d; + INT64 r; + const icd *i = cache.inst + ipc; + + ipc = i->next; + switch(i->op) { + case 0: + goto inst; + + case 1: + ++ca; + goto inst; + + case 2: + ++id; + goto inst; + + case 3: + ++ca, ++id; + goto inst; + +#define CINTRP +#include "cpu/tms57002/tms57002.inc" +#undef CINTRP + + default: + fatalerror("Unhandled opcode in tms57002_execute\n"); + } + } + inst: + icount--; + + if(rptc) { + rptc--; + ipc = iipc; + } else if(sti & S_BRANCH) { + sti &= ~S_BRANCH; + ipc = -1; + } else + pc++; // Wraps if it reaches 256, next wraps too + + if(rptc_next) { + rptc = rptc_next; + rptc_next = 0; + } + } + + if(icount > 0) + icount = 0; +} + +void tms57002_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + assert(samples == 1); + + if(st0 & ST0_SIM) { + si[0] = (inputs[0][0] << 8) & 0xffffff; + si[1] = (inputs[1][0] << 8) & 0xffffff; + si[2] = (inputs[2][0] << 8) & 0xffffff; + si[3] = (inputs[3][0] << 8) & 0xffffff; + } else { + si[0] = inputs[0][0] & 0xffffff; + si[1] = inputs[1][0] & 0xffffff; + si[2] = inputs[2][0] & 0xffffff; + si[3] = inputs[3][0] & 0xffffff; + } + outputs[0][0] = INT16(so[0] >> 8); + outputs[1][0] = INT16(so[1] >> 8); + outputs[2][0] = INT16(so[2] >> 8); + outputs[3][0] = INT16(so[3] >> 8); + + sync_w(1); +} + +void tms57002_device::device_start() +{ + sti = S_IDLE; + program = &space(AS_PROGRAM); + data = &space(AS_DATA); + + state_add(STATE_GENPC, "GENPC", pc).noshow(); + state_add(TMS57002_PC, "PC", pc); + state_add(TMS57002_ST0, "ST0", st0); + state_add(TMS57002_ST1, "ST1", st1); + state_add(TMS57002_RPTC, "RPTC", rptc); + state_add(TMS57002_AACC, "AACC", aacc); + state_add(TMS57002_MACC, "MACC", macc).mask(U64(0xfffffffffffff)); + state_add(TMS57002_BA0, "BA0", ba0); + state_add(TMS57002_BA1, "BA1", ba1); + state_add(TMS57002_CREG, "CREG", creg); + state_add(TMS57002_CA, "CA", ca); + state_add(TMS57002_ID, "ID", id); + state_add(TMS57002_XBA, "XBA", xba); + state_add(TMS57002_XOA, "XOA", xoa); + state_add(TMS57002_XRD, "XRD", xrd); + state_add(TMS57002_XWR, "XWR", xwr); + state_add(TMS57002_HIDX, "HIDX", hidx); + state_add(TMS57002_HOST0, "HOST0", host[0]); + state_add(TMS57002_HOST1, "HOST1", host[1]); + state_add(TMS57002_HOST2, "HOST2", host[2]); + state_add(TMS57002_HOST3, "HOST3", host[3]); + + m_icountptr = &icount; + + stream_alloc(4, 4, STREAM_SYNC); + + save_item(NAME(macc)); + + save_item(NAME(cmem)); + save_item(NAME(dmem0)); + save_item(NAME(dmem1)); + + save_item(NAME(si)); + save_item(NAME(so)); + + save_item(NAME(st0)); + save_item(NAME(st1)); + save_item(NAME(sti)); + save_item(NAME(aacc)); + save_item(NAME(xoa)); + save_item(NAME(xba)); + save_item(NAME(xwr)); + save_item(NAME(xrd)); + save_item(NAME(txrd)); + save_item(NAME(creg)); + + save_item(NAME(pc)); + save_item(NAME(ca)); + save_item(NAME(id)); + save_item(NAME(ba0)); + save_item(NAME(ba1)); + save_item(NAME(rptc)); + save_item(NAME(rptc_next)); + save_item(NAME(sa)); + + save_item(NAME(xm_adr)); + + save_item(NAME(host)); + save_item(NAME(hidx)); + save_item(NAME(allow_update)); +} + +UINT32 tms57002_device::execute_min_cycles() const +{ + return 1; +} + +UINT32 tms57002_device::execute_max_cycles() const +{ + return 3; +} + +UINT32 tms57002_device::execute_input_lines() const +{ + return 0; +} + +UINT32 tms57002_device::disasm_min_opcode_bytes() const +{ + return 4; +} + +UINT32 tms57002_device::disasm_max_opcode_bytes() const +{ + return 4; +} + +offs_t tms57002_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( tms57002 ); + return CPU_DISASSEMBLE_NAME(tms57002)(this, buffer, pc, oprom, opram, options); +} + +const address_space_config *tms57002_device::memory_space_config(address_spacenum spacenum) const +{ + switch(spacenum) { + case AS_PROGRAM: return &program_config; + case AS_DATA: return &data_config; + default: return 0; + } +} diff --git a/src/devices/cpu/tms57002/tms57002.h b/src/devices/cpu/tms57002/tms57002.h new file mode 100644 index 00000000000..cd450ab578b --- /dev/null +++ b/src/devices/cpu/tms57002/tms57002.h @@ -0,0 +1,219 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +/*************************************************************************** + + tms57002.h + + TMS57002 "DASP" emulator. + +***************************************************************************/ +#pragma once + +#ifndef __TMS57002_H__ +#define __TMS57002_H__ + +class tms57002_device : public cpu_device, public device_sound_interface { +public: + tms57002_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + DECLARE_READ8_MEMBER(data_r); + DECLARE_WRITE8_MEMBER(data_w); + + DECLARE_WRITE_LINE_MEMBER(pload_w); + DECLARE_WRITE_LINE_MEMBER(cload_w); + DECLARE_READ_LINE_MEMBER(empty_r); + DECLARE_READ_LINE_MEMBER(dready_r); + DECLARE_READ_LINE_MEMBER(pc0_r); + DECLARE_WRITE_LINE_MEMBER(sync_w); + +protected: + virtual void device_start(); + virtual void device_reset(); + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const; + virtual UINT32 execute_min_cycles() const; + virtual UINT32 execute_max_cycles() const; + virtual UINT32 execute_input_lines() const; + virtual void execute_run(); + virtual UINT32 disasm_min_opcode_bytes() const; + virtual UINT32 disasm_max_opcode_bytes() const; + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + +private: + enum { + IN_PLOAD = 0x00000001, + IN_CLOAD = 0x00000002, + SU_CVAL = 0x00000004, + SU_MASK = 0x00000018, SU_ST0 = 0x00, SU_ST1 = 0x08, SU_PRG = 0x10, + S_IDLE = 0x00000020, + S_READ = 0x00000040, + S_WRITE = 0x00000080, + S_BRANCH = 0x00000100, + S_HOST = 0x00000200 + }; + + enum { + ST0_INCS = 0x000001, + ST0_DIRI = 0x000002, + ST0_FI = 0x000004, + ST0_SIM = 0x000008, + ST0_PLRI = 0x000020, + ST0_PBCI = 0x000040, + ST0_DIRO = 0x000080, + ST0_FO = 0x000100, + ST0_SOM = 0x000600, + ST0_PLRO = 0x000800, + ST0_PBCO = 0x001000, + ST0_CNS = 0x002000, + ST0_WORD = 0x004000, + ST0_SEL = 0x008000, + ST0_M = 0x030000, ST0_M_64K = 0x000000, ST0_M_256K = 0x010000, ST0_M_1M = 0x020000, + ST0_SRAM = 0x200000, + + ST1_AOV = 0x000001, + ST1_SFAI = 0x000002, + ST1_SFAO = 0x000004, + ST1_MOVM = 0x000020, + ST1_MOV = 0x000040, + ST1_SFMA = 0x000180, ST1_SFMA_SHIFT = 7, + ST1_SFMO = 0x001800, ST1_SFMO_SHIFT = 11, + ST1_RND = 0x038000, ST1_RND_SHIFT = 15, + ST1_CRM = 0x0C0000, ST1_CRM_SHIFT = 18, ST1_CRM_32 = 0x000000, ST1_CRM_16H = 0x040000, ST1_CRM_16L = 0x080000, + ST1_DBP = 0x100000, + ST1_CAS = 0x200000, + + ST1_CACHE = ST1_SFAI|ST1_SFAO|ST1_MOVM|ST1_SFMA|ST1_SFMO|ST1_RND|ST1_CRM|ST1_DBP + }; + + + enum { BR_UB, BR_CB, BR_IDLE }; + + enum { IBS = 8192, HBS = 4096 }; + + enum { INC_CA = 1, INC_ID = 2 }; + + struct icd { + unsigned short op; + short next; + unsigned char param; + }; + + struct hcd { + unsigned int st1; + short ipc; + short next; + }; + + struct cd { + short hashbase[256]; + hcd hashnode[HBS]; + icd inst[IBS]; + int hused, iused; + }; + + struct cstate { + int branch; + int inc; + short hnode; + short ipc; + }; + + INT64 macc; + + UINT32 cmem[256]; + UINT32 dmem0[256]; + UINT32 dmem1[32]; + + UINT32 si[4], so[4]; + + UINT32 st0, st1, sti; + UINT32 aacc, xoa, xba, xwr, xrd, txrd, creg; + + UINT8 pc, hpc, ca, id, ba0, ba1, rptc, rptc_next, sa; + + UINT32 xm_adr; + + UINT8 host[4], hidx, allow_update; + + cd cache; + + const address_space_config program_config, data_config; + + address_space *program, *data; + int icount; + int unsupported_inst_warning; + + void decode_error(UINT32 opcode); + void decode_cat1(UINT32 opcode, unsigned short *op, cstate *cs); + void decode_cat2_pre(UINT32 opcode, unsigned short *op, cstate *cs); + void decode_cat3(UINT32 opcode, unsigned short *op, cstate *cs); + void decode_cat2_post(UINT32 opcode, unsigned short *op, cstate *cs); + + inline int xmode(UINT32 opcode, char type, cstate *cs); + inline int sfao(UINT32 st1); + inline int dbp(UINT32 st1); + inline int crm(UINT32 st1); + inline int sfai(UINT32 st1); + inline int sfmo(UINT32 st1); + inline int rnd(UINT32 st1); + inline int movm(UINT32 st1); + inline int sfma(UINT32 st1); + + const char *get_memadr(UINT32 opcode, char type); + + void xm_init(); + void xm_step_read(); + void xm_step_write(); + INT64 macc_to_output_0(INT64 rounding, UINT64 rmask); + INT64 macc_to_output_1(INT64 rounding, UINT64 rmask); + INT64 macc_to_output_2(INT64 rounding, UINT64 rmask); + INT64 macc_to_output_3(INT64 rounding, UINT64 rmask); + INT64 macc_to_output_0s(INT64 rounding, UINT64 rmask); + INT64 macc_to_output_1s(INT64 rounding, UINT64 rmask); + INT64 macc_to_output_2s(INT64 rounding, UINT64 rmask); + INT64 macc_to_output_3s(INT64 rounding, UINT64 rmask); + INT64 check_macc_overflow_0(); + INT64 check_macc_overflow_1(); + INT64 check_macc_overflow_2(); + INT64 check_macc_overflow_3(); + INT64 check_macc_overflow_0s(); + INT64 check_macc_overflow_1s(); + INT64 check_macc_overflow_2s(); + INT64 check_macc_overflow_3s(); + void cache_flush(); + void add_one(cstate *cs, unsigned short op, UINT8 param); + void decode_one(UINT32 opcode, cstate *cs, void (tms57002_device::*dec)(UINT32 opcode, unsigned short *op, cstate *cs)); + short get_hash(unsigned char adr, UINT32 st1, short *pnode); + short get_hashnode(unsigned char adr, UINT32 st1, short pnode); + int decode_get_pc(); +}; + +enum { + TMS57002_PC=1, + TMS57002_AACC, + TMS57002_BA0, + TMS57002_BA1, + TMS57002_CREG, + TMS57002_CA, + TMS57002_DREG, + TMS57002_ID, + TMS57002_MACC, + TMS57002_HIDX, + TMS57002_HOST0, + TMS57002_HOST1, + TMS57002_HOST2, + TMS57002_HOST3, + TMS57002_RPTC, + TMS57002_SA, + TMS57002_ST0, + TMS57002_ST1, + TMS57002_TREG, + TMS57002_XBA, + TMS57002_XOA, + TMS57002_XRD, + TMS57002_XWR +}; + +extern const device_type TMS57002; + +#endif diff --git a/src/devices/cpu/tms57002/tms57kdec.c b/src/devices/cpu/tms57002/tms57kdec.c new file mode 100644 index 00000000000..b71d0695141 --- /dev/null +++ b/src/devices/cpu/tms57002/tms57kdec.c @@ -0,0 +1,151 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +/*************************************************************************** + + tms57kdec.c + + TMS57002 "DASP" emulator. + +***************************************************************************/ + +#include "emu.h" +#include "debugger.h" +#include "tms57002.h" + +inline int tms57002_device::xmode(UINT32 opcode, char type, cstate *cs) +{ + if(((opcode & 0x400) && (type == 'c')) || (!(opcode & 0x400) && (type == 'd'))) { + if(opcode & 0x100) + return 0; + else if(opcode & 0x80) + cs->inc |= type == 'c' ? INC_CA : INC_ID; + + return 1; + } + else if(opcode & 0x200) + cs->inc |= type == 'c' ? INC_CA : INC_ID; + + return 1; +} + +inline int tms57002_device::sfao(UINT32 st1) +{ + return st1 & ST1_SFAO ? 1 : 0; +} + +inline int tms57002_device::dbp(UINT32 st1) +{ + return st1 & ST1_DBP ? 1 : 0; +} + +inline int tms57002_device::crm(UINT32 st1) +{ + int crm = (st1 & ST1_CRM) >> ST1_CRM_SHIFT; + return crm <= 2 ? crm : 0; +} + +inline int tms57002_device::sfai(UINT32 st1) +{ + return st1 & ST1_SFAI ? 1 : 0; +} + +inline int tms57002_device::sfmo(UINT32 st1) +{ + return (st1 & ST1_SFMO) >> ST1_SFMO_SHIFT; +} + +inline int tms57002_device::rnd(UINT32 st1) +{ + int rnd = (st1 & ST1_RND) >> ST1_RND_SHIFT; + return rnd <= 4 ? rnd : 0; +} + +inline int tms57002_device::movm(UINT32 st1) +{ + return st1 & ST1_MOVM ? 1 : 0; +} + +inline int tms57002_device::sfma(UINT32 st1) +{ + return (st1 & ST1_SFMA) >> ST1_SFMA_SHIFT; +} + +void tms57002_device::decode_error(UINT32 opcode) +{ + char buf[256]; + UINT8 opr[3]; + if(unsupported_inst_warning) + return; + + unsupported_inst_warning = 1; + opr[0] = opcode; + opr[1] = opcode >> 8; + opr[2] = opcode >> 16; + + disasm_disassemble(buf, pc, opr, opr, 0); + popmessage("tms57002: %s - Contact Mamedev", buf); +} + +void tms57002_device::decode_cat1(UINT32 opcode, unsigned short *op, cstate *cs) +{ + switch(opcode >> 18) { + case 0x00: // nop + break; + +#define CDEC1 +#include "cpu/tms57002/tms57002.inc" +#undef CDEC1 + + default: + decode_error(opcode); + break; + } +} + +void tms57002_device::decode_cat2_pre(UINT32 opcode, unsigned short *op, cstate *cs) +{ + switch((opcode >> 11) & 0x7f) { + case 0x00: // nop + break; + +#define CDEC2A +#include "cpu/tms57002/tms57002.inc" +#undef CDEC2A + + default: + decode_error(opcode); + break; + } +} + +void tms57002_device::decode_cat2_post(UINT32 opcode, unsigned short *op, cstate *cs) +{ + switch((opcode >> 11) & 0x7f) { + case 0x00: // nop + break; + +#define CDEC2B +#include "cpu/tms57002/tms57002.inc" +#undef CDEC2B + + default: + decode_error(opcode); + break; + } +} + +void tms57002_device::decode_cat3(UINT32 opcode, unsigned short *op, cstate *cs) +{ + switch((opcode >> 11) & 0x7f) { + case 0x00: // nop + break; + +#define CDEC3 +#include "cpu/tms57002/tms57002.inc" +#undef CDEC3 + + default: + decode_error(opcode); + break; + } +} diff --git a/src/devices/cpu/tms57002/tmsinstr.lst b/src/devices/cpu/tms57002/tmsinstr.lst new file mode 100644 index 00000000000..bcae2967949 --- /dev/null +++ b/src/devices/cpu/tms57002/tmsinstr.lst @@ -0,0 +1,536 @@ +abs 1 01 1 n + abs + aacc = %a; + if(((INT32)aacc) < 0) { + aacc = - aacc; + if(((INT32)aacc) < 0) + st1 |= ST1_AOV; + } + +add 1 03 1 y + add %d,a + %wa((INT64)(INT32)%d + (INT64)(INT32)%a); + +add 1 04 1 y + add %c,a + %wa((INT64)(INT32)%c + (INT64)(INT32)%a); + +add 1 05 1 y + add %d,m + %sfai(d, %d); + %wa((INT64)(INT32)d + (%mo >> 16)); + +add 1 06 1 y + add %c,m + %wa((INT64)(INT32)%c + (%mo >> 16)); + +add 1 07 1 y + add %d,%c + %wa((INT64)(INT32)%d + (INT64)(INT32)%c); + +adds 1 08 1 y + adds %d + +amac 1 2d 2 y + amac %d,%c,a + +ampy 1 2c 2 y + ampy %d,%c,a + +and 1 14 1 n + and %d,a + %sfai(d, %d); + aacc &= d; + +and 1 15 1 n + and %c,a + aacc &= %c; + +and 1 16 1 n + and %d,%c + %sfai(d, %d); + aacc = %c & d; + +b 3 48 3 n b + b %i + %b(%i); + +bgz 3 50 3 n cb + bgz %i + if(((INT32)aacc) > 0) { + %b(%i); + } + +bioz 3 70 3 n cb + bioz %i + +blz 3 58 3 n cb + blz %i + if(((INT32)aacc) < 0) { + %b(%i); + } + +bnz 3 60 3 n cb + bnz %i + if(aacc) { + %b(%i); + } + +bv 3 78 3 n cb + bv %i + if(st1 & ST1_AOV) { + st1 &= ~ST1_AOV; + %b(%i); + } + +cmpl 1 13 1 n + cmpl + +dimh 2a 14 1 n + dimh si0_l + +dimh 2a 15 1 n + dimh si0_r + +dimh 2a 16 1 n + dimh si1_l + +dimh 2a 17 1 n + dimh si1_r + +diml 2a 18 1 n + diml si0_l + +diml 2a 19 1 n + diml si0_r + +diml 2a 1a 1 n + diml si1_l + +diml 2a 1b 1 n + diml si1_r + +dis 2a 10 1 n + dis si0_l,%d + %wd(si[0]); + +dis 2a 11 1 n + dis si0_r,%d + %wd(si[1]); + +dis 2a 12 1 n + dis si1_l,%d + %wd(si[2]); + +dis 2a 13 1 n + dis si1_r,%d + %wd(si[3]); + +domh 2a 20 1 n + domh so0_l + so[0] = (%mo >> 24) & 0xffffff; + +domh 2a 21 1 n + domh so0_r + so[1] = (%mo >> 24) & 0xffffff; + +domh 2a 22 1 n + domh so1_l + so[2] = (%mo >> 24) & 0xffffff; + +domh 2a 23 1 n + domh so1_r + so[3] = (%mo >> 24) & 0xffffff; + +doml 2a 24 1 n + doml so0_l + +doml 2a 25 1 n + doml so0_r + +doml 2a 26 1 n + doml so1_l + +doml 2a 27 1 n + doml so1_r + +dos 2b 1c 1 n + dos so0_l,%d + +dos 2b 1d 1 n + dos so0_r,%d + +dos 2b 1e 1 n + dos so1_l,%d + +dos 2b 1f 1 n + dos so1_r,%d + +idle 3 08 1 n i + idle + sti |= S_IDLE; + +incd 2a 42 1 y + incd + +lacc 1 12 1 n + lacc %c + aacc = %c; + +lacd 1 11 1 n + lacd %d + %sfai(d, %d); + aacc = d; + +lbrk 3 28 1 n + lbrk %i + +lcaa 2a 08 1 y + lcaa + ca = %a >> 24; + +lcac 3 40 1 n + lcac %i + if(((INT32)aacc) >= 0) + ca = %i; + +lcak 3 18 1 n + lcak %i + ca = %i; + +ldpk 2a 44 1 n f + ldpk 0 + st1 &= ~ST1_DBP; + +ldpk 2a 45 1 n f + ldpk 1 + st1 |= ST1_DBP; + +ld0t 2b 0c 1 y + ld0t %d + +lira 2a 09 1 y + lira + id = %a >> 24; + +lirk 3 20 1 n + lirk %i + id = %i; + +lmhc 1 33 1 n + lmhc %c + macc = ((INT64)(INT32)%c) << 16; + +lmhd 1 31 1 n + lmhd %d + macc = ((INT64)(INT32)%d) << 16; + +lmld 1 32 1 n + lmld %d + macc = (macc & ~0xffffffULL) | %d24; + +lpc 2b 31 1 n + lpc %c + if(sti & S_HOST) + break; + c = %c; + host[0] = c >> 24; + host[1] = c >> 16; + host[2] = c >> 8; + host[3] = c; + hidx = 0; + sti |= S_HOST; + +lpd 2b 30 1 n + lpd %d + +mac 1 24 1 y + mac %d,%c + d = %d24; + if(d & 0x00800000) + d |= 0xff000000; + creg = c = %c; + r = (INT64)(INT32)c * (INT64)(INT32)d; + macc = %ml + (r >> 7); + +mac 1 25 1 y + mac a,%d + +mac 1 26 1 y + mac %c,a + creg = c = %c; + r = (INT64)(INT32)c * (INT64)(INT32)%a; + macc = %ml + (r >> 15); + +macs 1 2e 1 y + macs %c,a + creg = c = %c; + r = (INT64)(INT32)c * (INT64)(INT32)%a; + macc = %ml + (r >> 14); + +macu 1 29 1 y + macu %d,%c + d = %d24; // d is 24bits unsigned + creg = c = %c; + r = (INT64)(INT32)c * (INT64)d; + macc = %ml + (r >> 7); + +macu 1 2a 1 y + macu a,%d + d = %d24; // d is 24bits unsigned + creg = c = %a; + r = (INT64)(INT32)c * (INT64)d; + macc = %ml + (r >> 7); + +mpy 1 21 1 y + mpy %d,%c + d = %d24; + if(d & 0x00800000) + d |= 0xff000000; + creg = c = %c; + r = (INT64)(INT32)c * (INT64)(INT32)d; + macc = r >> 7; + +mpy 1 22 1 y + mpy %c,a + creg = c = %c; + r = (INT64)(INT32)c * (INT64)(INT32)%a; + macc = r >> 15; + +mpy 1 23 1 y + mpy creg,%d + +mpyu 1 28 1 y + mpyu %d,%c + creg = c = %c; + d = %d24; // d is 24bits unsigned + r = (INT64)(INT32)c * (INT64)d; + macc = r >> 7; + +neg 1 02 1 n + neg + +or 1 17 1 n + or %d,a + %sfai(d, %d); + aacc |= d; + +or 1 18 1 n + or %c,a + aacc |= %c; + +or 1 19 1 n + or %d,%c + %sfai(d, %d); + aacc = %c | d; + +raov 2a 38 1 n + raov + +rde 1 39 1 n + rde %c + if(sti & (S_READ|S_WRITE)) + break; + xoa = %c; + xm_init(); + sti |= S_READ; + +ref 2a 0e 1 n + ref + /* nothing to do */ + +rmom 2a 40 1 n f + rmom + st1 &= ~ST1_MOVM; + +rmov 2a 3a 1 n + rmov + st1 &= ~ST1_MOV; + +rnd 2a 68 1 n f + rnd 48 + st1 = (st1 & ~ST1_RND) | (0 << ST1_RND_SHIFT); + +rnd 2a 69 1 n f + rnd 32 + st1 = (st1 & ~ST1_RND) | (1 << ST1_RND_SHIFT); + +rnd 2a 6a 1 n f + rnd 24 + st1 = (st1 & ~ST1_RND) | (2 << ST1_RND_SHIFT); + +rnd 2a 6b 1 n f + rnd 20 + st1 = (st1 & ~ST1_RND) | (3 << ST1_RND_SHIFT); + +rnd 2a 6c 1 n f + rnd 16 + st1 = (st1 & ~ST1_RND) | (4 << ST1_RND_SHIFT); + +rnd 2a 6d 1 n f + rnd <5> + st1 = (st1 & ~ST1_RND) | (5 << ST1_RND_SHIFT); + +rnd 2a 6e 1 n f + rnd <6> + st1 = (st1 & ~ST1_RND) | (6 << ST1_RND_SHIFT); + +rnd 2a 6f 1 n f + rnd <7> + st1 = (st1 & ~ST1_RND) | (7 << ST1_RND_SHIFT); + +rptk 3 10 1 n + rptk %i + rptc_next = %i; + +sacc 2a 01 1 y + sacc %c + %wc(%a); + +sacd 2a 02 1 y + sacd %d + %wd(%a >> 8); + +scrm 2a 48 1 n f + scrm 32 + st1 = (st1 & ~ST1_CRM) | (0 << ST1_CRM_SHIFT); + +scrm 2a 49 1 n f + scrm 16h + st1 = (st1 & ~ST1_CRM) | (1 << ST1_CRM_SHIFT); + +scrm 2a 4a 1 n f + scrm 16l + st1 = (st1 & ~ST1_CRM) | (2 << ST1_CRM_SHIFT); + +scrm 2a 4b 1 n f + scrm <3> + st1 = (st1 & ~ST1_CRM) | (3 << ST1_CRM_SHIFT); + +sfai 2b 54 1 n f + sfai 0 + st1 &= ~ST1_SFAI; + +sfai 2b 55 1 n f + sfai -1 + st1 |= ST1_SFAI; + +sfao 2a 50 1 n f + sfao 0 + st1 &= ~ST1_SFAO; + +sfao 2a 51 1 n f + sfao 7 + st1 |= ST1_SFAI; + +sfma 2b 58 1 n f + sfma 0 + st1 = (st1 & ~ST1_SFMA) | (0 << ST1_SFMA_SHIFT); + +sfma 2b 59 1 n f + sfma 2 + st1 = (st1 & ~ST1_SFMA) | (1 << ST1_SFMA_SHIFT); + +sfma 2b 5a 1 n f + sfma 4 + st1 = (st1 & ~ST1_SFMA) | (2 << ST1_SFMA_SHIFT); + +sfma 2b 5b 1 n f + sfma -16 + st1 = (st1 & ~ST1_SFMA) | (3 << ST1_SFMA_SHIFT); + +sfml 1 34 1 y + sfml + macc = (macc & 0x8000000000000ULL) | ((macc << 1) & 0x7ffffffffffffULL); + +sfmo 2a 60 1 n f + sfmo 0 + st1 = (st1 & ~ST1_SFMO) | (0 << ST1_SFMO_SHIFT); + +sfmo 2a 61 1 n f + sfmo 2 + st1 = (st1 & ~ST1_SFMO) | (1 << ST1_SFMO_SHIFT); + +sfmo 2a 62 1 n f + sfmo 4 + st1 = (st1 & ~ST1_SFMO) | (2 << ST1_SFMO_SHIFT); + +sfmo 2a 63 1 n f + sfmo -8 + st1 = (st1 & ~ST1_SFMO) | (3 << ST1_SFMO_SHIFT); + +sfmr 1 35 1 y + sfmr + macc = (macc & 0x8000000000000ULL) | ((macc >> 1) & 0x7ffffffffffffULL); + +slmh 2a 06 1 y + slmh %d + %wd((%mv >> 24) & 0xffff00); + +slml 2a 07 1 y + slml %d + %wd((%mv >> 8) & 0xffffff); + +smhc 2a 05 1 y + smhc %c + %wc(%mo >> 16); + +smhd 2a 03 1 y + smhd %d + %wd((%mo >> 24) & 0xffffff); + +smld 2a 04 1 y + smld %d + +smom 2a 41 1 n f + smom + st1 |= ST1_MOVM; + +srbd 2a 0f 1 y + srbd %d + %wd(xrd); + +std1 2a 0d 1 y + std1 %d + +sub 1 09 1 y + sub %d,a + %wa((INT64)(INT32)%d - (INT64)(INT32)%a); + +sub 1 0a 1 y + sub %c,a + %wa((INT64)(INT32)%c - (INT64)(INT32)%a); + +sub 1 0b 1 y + sub %d,m + +sub 1 0c 1 y + sub %c,m + +sub 1 0d 1 y + sub %d,%c + %wa((INT64)(INT32)%d - (INT64)(INT32)%c); + +wre 1 38 1 n + wre %d,%c + if(sti & (S_READ|S_WRITE)) + break; + xwr = %d24; + xoa = %c; + xm_init(); + sti |= S_WRITE; + +xor 1 1a 1 n + xor %d,a + +xor 1 1b 1 n + xor %c,a + +xor 1 1c 1 n + xor %d,%c + +zacc 1 10 1 n + zacc + +zmac 1 30 1 n + zmac diff --git a/src/devices/cpu/tms57002/tmsmake.py b/src/devices/cpu/tms57002/tmsmake.py new file mode 100755 index 00000000000..c822599e7d2 --- /dev/null +++ b/src/devices/cpu/tms57002/tmsmake.py @@ -0,0 +1,435 @@ +#!/usr/bin/python + +import sys +import re + + +DASM_ARGS = { + "c": ("%s", "get_memadr(opcode, 'c')"), + "d": ("%s", "get_memadr(opcode, 'd')"), + "i": ("%02x", "opcode & 0xff"), +} + +TYPES = { + "": None, + "d": None, + "b": " cs->branch = BR_UB;", + "cb": " cs->branch = BR_CB;", + "i": " cs->branch = BR_IDLE;", + "f": None, +} + +def expand_c(v): + fmt = ["%s", "(%s & 0xffff0000)", "(%s << 16)"][v["crm"]] + param = ["cmem[i->param]", "cmem[ca]"][v["cmode"]] + return fmt % param + +def expand_d(v): + index = ["(i->param + ", "(id + "][v["dmode"]] + mask = ["ba0) & 0xff] << 8)", "ba1) & 0x1f] << 8)"][v["dbp"]] + return "(dmem%d[" % v["dbp"] + index + mask + +def expand_d24(v): + index = ["(i->param + ", "(id + "][v["dmode"]] + mask = ["ba0) & 0xff]", "ba1) & 0x1f]"][v["dbp"]] + return "dmem%d[" % v["dbp"] + index + mask + +EXPAND_ML = ["macc", "(macc << 2)", "(macc << 4)", "(macc >> 16)" ] + +def expand_mv(v): + c = ["", "s"][v["movm"]] + return "check_macc_overflow_%d%s()" % (v["sfmo"], c) + +EXPAND_WC = ["cmem[i->param] =", "cmem[ca] ="] + + +ROUNDING = [ 0, 1 << (48-32-1), 1 << (48-24-1), 1 << (48-30-1), + 1 << (48-16-1)] + +A = (1 << 64) - 1 +RMASK= [A, + A - (1 << (48-32)) + 1, + A - (1 << (48-24)) + 1, + A - (1 << (48-30)) + 1, + A - (1 << (48-16)) + 1, + ] + +def expand_mo(v): + c = ["", "s"][v["movm"]] + return "macc_to_output_%d%s(0x%016xULL, 0x%016xULL)" % ( + v["sfmo"], c, ROUNDING[v["rnd"]], RMASK[v["rnd"]]) + + +def expand_wd1(v): + index = ["(i->param + ", "(id + "][v["dmode"]] + mask = ["ba0) & 0xff] =", "ba1) & 0x1f] ="][v["dbp"]] + return "dmem%d[" % v["dbp"] + index + mask + +WA2 = ( +" if(r < -0x80000000 || r > 0x7fffffff)\n" +" st1 |= ST1_AOV;\n" +" aacc = r;") + + +PDESC_EXPAND = { + "a": lambda v: ["aacc", "(aacc << 7)"][v["sfao"]], + "c": expand_c, + "d": expand_d, + "d24": expand_d24, + "i": lambda v: "i->param", + + "ml": lambda v: EXPAND_ML[v["sfma"]], + "mo": expand_mo, + "mv": expand_mv, + "wa1": lambda v: "r =", + "wa2": lambda v: WA2, + "wc1": lambda v: EXPAND_WC[v["cmode"]], + "wd1": expand_wd1, + "b1": lambda v: "pc = ", + "b2": lambda v: " sti |= S_BRANCH;", + "sfai1": lambda v: ["", "((INT32)("][v["sfai"]], + "sfai2": lambda v: ["", ")) >> 1"][v["sfai"]], +} + +PDESC = { + "a": (0, ["sfao"]), + "c": (0, ["cmode", "crm"]), + "d": (0, ["dmode", "dbp"]), + "d24": (0, ["dmode", "dbp"]), + "i": (0, []), + "ml": (0, ["sfma"]), + "mo": (0, ["sfmo", "rnd", "movm"]), + "mv": (0, ["sfmo", "movm"]), + "wa": (1, []), + "wc": (1, ["cmode"]), + "wd": (1, ["dmode", "dbp"]), + "b": (1, []), + "sfai": (2, ["sfai"]), +} + +VARIANTS = { + "cmode": (2, "xmode(opcode, 'c', cs)" ), + "dmode": (2, "xmode(opcode, 'd', cs)" ), + "sfai": (2, "sfai(st1)"), + "crm": (3, "crm(st1)"), + "dbp": (2, "dbp(st1)"), + "sfao": (2, "sfao(st1)"), + "sfmo": (4, "sfmo(st1)"), + "rnd": (5, "rnd(st1)"), + "movm": (2, "movm(st1)"), + "sfma": (4, "sfma(st1)"), + # dummy + "post": (1, None), + +} + +VARIANT_CANONICAL_ORDER = [ + "cmode", + "dmode", + "sfai", + "crm", + "dbp", + "sfao", + "sfmo", + "rnd", + "movm", + "sfma", +] + +def EmitWithPrefix(f, out, prefix): + for o in out: + print >>f, prefix + o + +class Instruction: + + def __init__(self, line): + token = line.split() + if len(token) == 5: + token.append("") + assert len(token) == 6 + + self._name = token[0] + self._cat = token[1] + self._id = int(token[2], 16) + self._cyc = int(token[3]) + self._rep = token[4] + self._type = token[5] + self._flags = set() + if self._cat == "2b": + self._flags.add("post") + self._dasm = None + self._run = [] + self._variants = 1 + # sanity checks + assert 0 <= self._id + if self._cat == "1": + assert self._id < 0x40 + else: + assert self._id < 0x80 + assert self._type in TYPES + + def __str__(self): + return repr([self._name, self._cat, self._id, self._variants, self._flags]) + + + def GetDasmInfo(self): + lst = [] + def extract(match): + s = match.group()[1:] + assert s in DASM_ARGS + fmt, val = DASM_ARGS[s] + lst.append(val) + return fmt + s = re.sub("%.", extract, self._dasm) + return s, lst + + + def GetCdecSum(self): + lst = [] + n = 1 + for f in VARIANT_CANONICAL_ORDER: + if f in self._flags: + c, s = VARIANTS[f] + lst.append(" + ") + if n != 1: + lst.append("%d*" % n) + lst.append(s) + n *=c + return "".join(lst) + + + def EmitDasm(self, f, prefix): + opcode, args = self.GetDasmInfo() + args = [", " + a for a in args] + print >>f, "%scase 0x%02x:" % (prefix, self._id) + print >>f, "%s sprintf(buf, \"%s\"%s);" % (prefix, opcode, "".join(args)) + print >>f, "%s break;" % prefix + + + def EmitCdec(self, f, prefix, no, empty): + print >>f, "%scase 0x%02x: // %s" % (prefix, self._id, self._name) + if not empty: + print >>f, "%s *op = %s%s;" % (prefix, no, self.GetCdecSum()) + if self._type == "f": + for l in self._run: + print >>f, prefix + l + else: + l = TYPES[self._type] + if l: + print >>f, prefix + l + print >>f, "%s break;" % prefix + + + def ExpandCintrp(self, line, values): + def extract(match): + s = match.group()[1:] + assert s in PDESC_EXPAND + # call the right expand_XXX function + return PDESC_EXPAND[s](values) + + + return re.sub("%[a-z0-9]+", extract, line) + + + def PreprocessRunString(self): + out = [] + for r in self._run: + if "%wa(" in r: + assert r.endswith(");") + r = r[0:-2].replace("%wa(", "%wa1 ") + ";" + out.append(r) + out.append("%wa2") + elif "%wd(" in r: + assert r.endswith(");") + r = r[0:-2].replace("%wd(", "%wd1 ") + ";" + out.append(r) + elif "%wc(" in r: + assert r.endswith(");") + r = r[0:-2].replace("%wc(", "%wc1 ") + ";" + out.append(r) + elif "%b(" in r: + assert r.endswith(");") + r = r[0:-2].replace("%b(", "%b1") + ";" + out.append(r) + out.append("%b2") + elif "%sfai(" in r: + assert r.endswith(");") + r = r[0:-2].replace("%sfai(", "") + r = r.replace(",", " = %sfai1", 1) + out.append(r + "%sfai2;") + else: + out.append(r) + return out + + + def EmitCintrpRecurse(self, f, prefix, no, flags_fixed, flags_unfixed): + if not flags_unfixed: + vals = [] + for v in VARIANT_CANONICAL_ORDER: + if v in flags_fixed: + #print "@@@@", f + vals.append("%s=%d" % (v, flags_fixed[v])) + out = ["case %d: // %s %s" % (no, self._name, " ".join(vals))] + for line in self.PreprocessRunString(): + exp = self.ExpandCintrp(line, flags_fixed) + # ensure we're not outputing a = a; + if not CheckSelfAssign(exp): + out.append(exp) + out.append(" break;") + out.append("") + EmitWithPrefix(f, out, prefix) + return no + 1 + x = flags_unfixed.pop(-1) + n = VARIANTS[x][0] + for i in range(n): + flags_fixed[x] = i + no = self.EmitCintrpRecurse(f, prefix, no, flags_fixed, flags_unfixed) + flags_unfixed.append(x) + return no + + + def EmitCintrp(self, f, prefix, no): + if not self._run: + return no + flags = [fn for fn in VARIANT_CANONICAL_ORDER + if fn in self._flags] + return self.EmitCintrpRecurse(f, prefix, no, {}, flags) + + + def Finalize(self): + def extract(match): + s = match.group()[1:] + assert s in PDESC + self._flags.update(PDESC[s][1]) + # result does not matter + return "X" + for line in self._run: + # ignore result of substitution + re.sub("%[a-z0-9]+", extract, line) + for f in self._flags: + self._variants *= VARIANTS[f][0] + + + def AddInfo(self, line): + if self._dasm is None: + self._dasm = line.lstrip() + else: + self._run.append(line) + + +def ins_cmp_dasm(a, b): + if a._cat[0] != b._cat[0]: + return cmp(a._cat[0], b._cat[0]) + else: + return cmp(a._id, b._id) + + +def LoadLst(filename): + instructions = [] + ins = None + for n, line in enumerate(open(filename, "rU")): + line = line.rstrip() + if not line and ins: + # new lines separate intructions + ins.Finalize() + ins = None + elif line[0] in [" ", "\t"]: + assert ins + ins.AddInfo(line) + else: + ins = Instruction(line) + instructions.append(ins) + if ins: + ins.Finalize() + return instructions + + +def EmitDasm(f, ins_list): + ins_list.sort(cmp=ins_cmp_dasm) + last_cat = "" + for i in ins_list: + cat = i._cat[0] + if cat != last_cat: + if last_cat: + print >>f, "#endif" + print >>f + print >>f, "#ifdef DASM" + cat + last_cat = cat + i.EmitDasm(f, " ") + print >>f + print >>f, "#endif" + print >>f + + +def EmitCdec(f, ins_list): + ins_list.sort(cmp=ins_cmp_dasm) + no = 4 + last_cat = "" + for i in ins_list: + if not i._run: continue + cat = i._cat.upper() + if cat == "2B": cat = "2A" + if cat == "3": continue + + if cat != last_cat: + if last_cat: + print >>f, "#endif" + print >>f + print >>f, "#ifdef CDEC" + cat + last_cat = cat + + i.EmitCdec(f, "", no, i._cat == "2b") + no += i._variants + print >>f + + no = 4 + for i in ins_list: + if not i._run: continue + cat = i._cat.upper() + if cat == "2A": cat = "2B" + + if cat == "1": + no += i._variants + continue + + if cat != last_cat: + if last_cat: + print >>f, "#endif" + print >>f + print >>f, "#ifdef CDEC" + cat + last_cat = cat + + i.EmitCdec(f, "", no, i._cat == "2a") + no += i._variants + print >>f + print >>f, "#endif" + print >>f + +def EmitCintrp(f, ins_list): + ins_list.sort(cmp=ins_cmp_dasm) + print >>f, "#ifdef CINTRP" + no = 4 + for i in ins_list: + no = i.EmitCintrp(f, "", no) + print >>f, "#endif" + + +def CheckSelfAssign(line): + ls = line.split('=') + if len(ls) != 2: + return False + lhs = ls[0].strip() + rhs = ls[1].strip().rstrip(';') + return lhs == rhs + +ins_list = LoadLst(sys.argv[1]) +try: + f = open(sys.argv[2], "w") +except Exception: + err = sys.exc_info()[1] + sys.stderr.write("cannot write file %s [%s]\n" % (sys.argv[2], err)) + sys.exit(1) + +EmitDasm(f, ins_list) +EmitCdec(f, ins_list) +EmitCintrp(f, ins_list) diff --git a/src/devices/cpu/tms7000/7000dasm.c b/src/devices/cpu/tms7000/7000dasm.c new file mode 100644 index 00000000000..e265ef1db7e --- /dev/null +++ b/src/devices/cpu/tms7000/7000dasm.c @@ -0,0 +1,448 @@ +// license:BSD-3-Clause +// copyright-holders:Tim Lindner +/* + + TMS7000 disassembler + +*/ + +#include "emu.h" +#include "debugger.h" +#include "tms7000.h" + +enum operandtype { DONE, NONE, UI8, I8, UI16, I16, PCREL, PCABS, TRAP }; + +struct oprandinfo { + char opstr[4][12]; + operandtype decode[4]; +}; + +struct tms7000_opcodeinfo { + int opcode; + char name[8]; + int operand; + UINT32 s_flag; +}; + +static const oprandinfo of[] = { +/* 00 */ { {" B,A", "", "", ""}, {NONE, DONE, DONE, DONE} }, +/* 01 */ { {" R%u", ",A", "", ""}, {UI8, NONE, DONE, DONE} }, +/* 02 */ { {" R%u", ",B", "", ""}, {UI8, NONE, DONE, DONE} }, +/* 03 */ { {" R%u", ",R%u", "", ""}, {UI8, UI8, DONE, DONE} }, +/* 04 */ { {" %%>%X", ",A", "", ""}, {UI8, NONE, DONE, DONE} }, +/* 05 */ { {" %%>%X", ",B", "", ""}, {UI8, NONE, DONE, DONE} }, +/* 06 */ { {" %%>%X", ",R%u", "", ""}, {UI8, UI8, DONE, DONE} }, + +/* 07 */ { {" A", ",P%u", "", ""}, {NONE,UI8,DONE,DONE} }, +/* 08 */ { {" B", ",P%u", "", ""}, {NONE,UI8,DONE,DONE} }, +/* 09 */ { {" %%>%02X", ",P%u", "", ""}, {UI8,UI8,DONE,DONE} }, + +/* 10 */ { {" @>%04X", "", "", ""}, {UI16,DONE,DONE,DONE} }, +/* 11 */ { {" R%u", "", "", ""}, {UI8, DONE, DONE, DONE} }, +/* 12 */ { {" @>%04X(B)","", "", ""}, {UI16, DONE, DONE, DONE} }, + +/* 13 */ { {" B,A", ",%s", "", ""}, {NONE, PCREL, DONE, DONE} }, +/* 14 */ { {" R%u,A", ",%s", "", ""}, {UI8, PCREL, DONE, DONE} }, +/* 15 */ { {" R%u,B", ",%s", "", ""}, {UI8, PCREL, DONE, DONE} }, +/* 16 */ { {" R%u", ",R%u", ",%s", ""}, {UI8, UI8, PCREL, DONE} }, +/* 17 */ { {" %%>%X", ",A,%s", "", ""}, {UI8, PCREL, DONE, DONE} }, +/* 18 */ { {" %%>%X", ",B,%s", "", ""}, {UI8, PCREL, DONE, DONE} }, +/* 19 */ { {" %%>%X", ",R%u", ",%s", ""}, {UI8, UI8, PCREL, DONE} }, + +/* 20 */ { {" A,P%u", ",%s", "", ""}, {UI8, PCREL, DONE, DONE} }, +/* 21 */ { {" B,P%u", ",%s", "", ""}, {UI8, PCREL, DONE, DONE} }, +/* 22 */ { {" %%>%02X", ",P%u", ",%s" ""}, {UI8, UI8, PCREL, DONE} }, + +/* 23 */ { {"", "", "", ""}, {DONE, DONE, DONE, DONE} }, +/* 24 */ { {" R%u", "", "", ""}, {UI8, DONE, DONE, DONE} }, + +/* 25 */ { {" A,%s", "", "", ""}, {PCREL, DONE, DONE, DONE} }, +/* 26 */ { {" B,%s", "", "", ""}, {PCREL, DONE, DONE, DONE} }, +/* 27 */ { {" R%u", ",%s", "", ""}, {UI8, PCREL, DONE, DONE} }, + +/* 28 */ { {" %s", "", "", ""}, {PCREL, DONE, DONE, DONE} }, + +/* 29 */ { {" A,B", "", "", ""}, {NONE, DONE, DONE, DONE} }, +/* 30 */ { {" B,A", "", "", ""}, {NONE, DONE, DONE, DONE} }, +/* 31 */ { {" A,R%u", "", "", ""}, {UI8, DONE, DONE, DONE} }, +/* 32 */ { {" B,R%u", "", "", ""}, {UI8, DONE, DONE, DONE} }, +/* 33 */ { {" R%u,A", "", "", ""}, {UI8, DONE, DONE, DONE} }, +/* 34 */ { {" R%u,B", "", "", ""}, {UI8, DONE, DONE, DONE} }, +/* 35 */ { {" R%u", ",R%u", "", ""}, {UI8, UI8, DONE, DONE} }, +/* 36 */ { {" %%>%X,A", "", "", ""}, {UI8, DONE, DONE, DONE} }, +/* 37 */ { {" %%>%X,B", "", "", ""}, {UI8, DONE, DONE, DONE} }, +/* 38 */ { {" %%>%X", ",R%u", "", ""}, {UI8, UI8, DONE, DONE} }, + +/* 39 */ { {" %%>%04X",",R%u", "", ""}, {UI16, UI8, DONE, DONE} }, +/* 40 */ { {" %%>%04X(B)",",R%u", "", ""}, {UI16, UI8, DONE, DONE} }, + +/* 41 */ { {" P%u,A", "", "", ""}, {UI8, DONE, DONE, DONE} }, +/* 42 */ { {" P%u,B", "", "", ""}, {UI8, DONE, DONE, DONE} }, +/* 43 */ { {" %s", "", "", ""}, {PCABS, DONE, DONE, DONE} }, +/* 44 */ { {"", "", "", ""}, {TRAP, DONE, DONE, DONE} }, /* Only For TRAP */ + +/* 45 */ { {" *R%u", "", "", ""}, {UI8, DONE, DONE, DONE} } +}; + +static const tms7000_opcodeinfo opcodes[] = { + {0x69, "ADC", 0, 0 }, + {0x19, "ADC", 1, 0 }, + {0x39, "ADC", 2, 0 }, + {0x49, "ADC", 3, 0 }, + {0x29, "ADC", 4, 0 }, + {0x59, "ADC", 5, 0 }, + {0x79, "ADC", 6, 0 }, + + {0x68, "ADD", 0, 0 }, + {0x18, "ADD", 1, 0 }, + {0x38, "ADD", 2, 0 }, + {0x48, "ADD", 3, 0 }, + {0x28, "ADD", 4, 0 }, + {0x58, "ADD", 5, 0 }, + {0x78, "ADD", 6, 0 }, + + {0x63, "AND", 0, 0 }, + {0x13, "AND", 1, 0 }, + {0x33, "AND", 2, 0 }, + {0x43, "AND", 3, 0 }, + {0x23, "AND", 4, 0 }, + {0x53, "AND", 5, 0 }, + {0x73, "AND", 6, 0 }, + + {0x83, "ANDP", 7, 0 }, + {0x93, "ANDP", 8, 0 }, + {0xA3, "ANDP", 9, 0 }, + + {0x8C, "BR", 43, 0 }, + {0x9C, "BR", 45, 0 }, + {0xAC, "BR", 12, 0 }, + + {0x66, "BTJO", 13, 0 }, + {0x16, "BTJO", 14, 0 }, + {0x36, "BTJO", 15, 0 }, + {0x46, "BTJO", 16, 0 }, + {0x26, "BTJO", 17, 0 }, + {0x56, "BTJO", 18, 0 }, + {0x76, "BTJO", 19, 0 }, + + {0x86, "BTJOP", 20, 0 }, + {0x96, "BTJOP", 21, 0 }, + {0xA6, "BTJOP", 22, 0 }, + + {0x67, "BTJZ", 13, 0 }, + {0x17, "BTJZ", 14, 0 }, + {0x37, "BTJZ", 15, 0 }, + {0x47, "BTJZ", 16, 0 }, + {0x27, "BTJZ", 17, 0 }, + {0x57, "BTJZ", 18, 0 }, + {0x77, "BTJZ", 19, 0 }, + + {0x87, "BTJZP", 20, 0 }, + {0x97, "BTJZP", 21, 0 }, + {0xA7, "BTJZP", 22, 0 }, + + {0x8E, "CALL", 43, DASMFLAG_STEP_OVER }, + {0x9E, "CALL", 45, DASMFLAG_STEP_OVER }, + {0xAE, "CALL", 12, DASMFLAG_STEP_OVER }, + + {0xB5, "CLR A", 23, 0 }, + {0xC5, "CLR B", 23, 0 }, + {0xD5, "CLR", 24, 0 }, + + {0xB0, "CLRC", 23, 0 }, + + {0x6D, "CMP", 0, 0 }, + {0x1D, "CMP", 1, 0 }, + {0x3D, "CMP", 2, 0 }, + {0x4D, "CMP", 3, 0 }, + {0x2D, "CMP", 4, 0 }, + {0x5D, "CMP", 5, 0 }, + {0x7D, "CMP", 6, 0 }, + + {0x8D, "CMPA", 10, 0 }, + {0x9D, "CMPA", 45, 0 }, + {0xAD, "CMPA", 12, 0 }, + + {0x6E, "DAC", 0, 0 }, + {0x1E, "DAC", 1, 0 }, + {0x3E, "DAC", 2, 0 }, + {0x4E, "DAC", 3, 0 }, + {0x2E, "DAC", 4, 0 }, + {0x5E, "DAC", 5, 0 }, + {0x7E, "DAC", 6, 0 }, + + {0xB2, "DEC A", 23, 0 }, + {0xC2, "DEC B", 23, 0 }, + {0xD2, "DEC", 24, 0 }, + + {0xBB, "DECD A", 23, 0 }, + {0xCB, "DECD B", 23, 0 }, + {0xDB, "DECD", 24, 0 }, + + {0x06, "DINT", 23, 0 }, + + {0xBA, "DJNZ", 25, 0 }, + {0xCA, "DJNZ", 26, 0 }, + {0xDA, "DJNZ", 27, 0 }, + + {0x6F, "DSB", 0, 0 }, + {0x1F, "DSB", 1, 0 }, + {0x3F, "DSB", 2, 0 }, + {0x4F, "DSB", 3, 0 }, + {0x2F, "DSB", 4, 0 }, + {0x5F, "DSB", 5, 0 }, + {0x7F, "DSB", 6, 0 }, + + {0x05, "EINT", 23, 0 }, + + {0x01, "IDLE", 23, 0 }, + + {0xB3, "INC A", 23, 0 }, + {0xC3, "INC B", 23, 0 }, + {0xD3, "INC", 24, 0 }, + + {0xB4, "INV A", 23, 0 }, + {0xC4, "INV B", 23, 0 }, + {0xD4, "INV", 24, 0 }, + + {0xE2, "JEQ", 28, 0 }, + {0xE3, "JHS", 28, 0 }, + {0xE7, "JL", 28, 0 }, + {0xE0, "JMP", 28, 0 }, + {0xE1, "JN", 28, 0 }, + {0xE6, "JNZ", 28, 0 }, + {0xE4, "JP", 28, 0 }, + {0xE5, "JPI", 28, 0 }, + + {0x8A, "LDA", 10, 0 }, + {0x9A, "LDA", 45, 0 }, + {0xAA, "LDA", 12, 0 }, + + {0x0D, "LDSP", 23, 0 }, + + {0xC0, "MOV", 29, 0 }, + {0x62, "MOV", 30, 0 }, + {0xD0, "MOV", 31, 0 }, + {0xD1, "MOV", 32, 0 }, + {0x12, "MOV", 33, 0 }, + {0x32, "MOV", 34, 0 }, + {0x42, "MOV", 35, 0 }, + {0x22, "MOV", 36, 0 }, + {0x52, "MOV", 37, 0 }, + {0x72, "MOV", 38, 0 }, + + {0x88, "MOVD", 39, 0 }, + {0x98, "MOVD", 35, 0 }, + {0xA8, "MOVD", 40, 0 }, + + {0x82, "MOVP", 7, 0 }, + {0x92, "MOVP", 8, 0 }, + {0xA2, "MOVP", 9, 0 }, + {0x80, "MOVP", 41, 0 }, + {0x91, "MOVP", 42, 0 }, + + {0x6C, "MPY", 00, 0 }, + {0x1C, "MPY", 01, 0 }, + {0x3C, "MPY", 02, 0 }, + {0x4C, "MPY", 03, 0 }, + {0x2C, "MPY", 04, 0 }, + {0x5C, "MPY", 05, 0 }, + {0x7C, "MPY", 06, 0 }, + + {0x00, "NOP", 23, 0 }, + + {0x64, "OR", 00, 0 }, + {0x14, "OR", 01, 0 }, + {0x34, "OR", 02, 0 }, + {0x44, "OR", 03, 0 }, + {0x24, "OR", 04, 0 }, + {0x54, "OR", 05, 0 }, + {0x74, "OR", 06, 0 }, + + {0x84, "ORP", 7, 0 }, + {0x94, "ORP", 8, 0 }, + {0xA4, "ORP", 9, 0 }, + + {0xB9, "POP A", 23, 0 }, + {0xC9, "POP B", 23, 0 }, + {0xD9, "POP", 24, 0 }, + {0x08, "POP ST", 23, 0 }, + + {0xB8, "PUSH A", 23, 0 }, + {0xC8, "PUSH B", 23, 0 }, + {0xD8, "PUSH", 24, 0 }, + {0x0E, "PUSH ST", 23, 0 }, + + {0x0B, "RETI", 23, DASMFLAG_STEP_OUT }, + {0x0A, "RETS", 23, DASMFLAG_STEP_OUT }, + + {0xBE, "RL A", 23, 0 }, + {0xCE, "RL B", 23, 0 }, + {0xDE, "RL", 11, 0 }, + + {0xBF, "RLC A", 23, 0 }, + {0xCF, "RLC B", 23, 0 }, + {0xDF, "RLC", 11, 0 }, + + {0xBC, "RR A", 23, 0 }, + {0xCC, "RR B", 23, 0 }, + {0xDC, "RR", 11, 0 }, + + {0xBD, "RRC A", 23, 0 }, + {0xCD, "RRC B", 23, 0 }, + {0xDD, "RRC", 11, 0 }, + + {0x6B, "SBB", 0, 0 }, + {0x1B, "SBB", 1, 0 }, + {0x3B, "SBB", 2, 0 }, + {0x4B, "SBB", 3, 0 }, + {0x2B, "SBB", 4, 0 }, + {0x5B, "SBB", 5, 0 }, + {0x7B, "SBB", 6, 0 }, + + {0x07, "SETC", 23, 0 }, + + {0x8B, "STA", 10, 0 }, + {0x9B, "STA", 45, 0 }, + {0xAB, "STA", 12, 0 }, + + {0x09, "STSP", 23, 0 }, + + {0x6A, "SUB", 0, 0 }, + {0x1A, "SUB", 1, 0 }, + {0x3A, "SUB", 2, 0 }, + {0x4A, "SUB", 3, 0 }, + {0x2A, "SUB", 4, 0 }, + {0x5A, "SUB", 5, 0 }, + {0x7A, "SUB", 6, 0 }, + + {0xFF, "TRAP 0", 44, DASMFLAG_STEP_OVER }, + {0xFE, "TRAP 1", 44, DASMFLAG_STEP_OVER }, + {0xFD, "TRAP 2", 44, DASMFLAG_STEP_OVER }, + {0xFC, "TRAP 3", 44, DASMFLAG_STEP_OVER }, + {0xFB, "TRAP 4", 44, DASMFLAG_STEP_OVER }, + {0xFA, "TRAP 5", 44, DASMFLAG_STEP_OVER }, + {0xF9, "TRAP 6", 44, DASMFLAG_STEP_OVER }, + {0xF8, "TRAP 7", 44, DASMFLAG_STEP_OVER }, + {0xF7, "TRAP 8", 44, DASMFLAG_STEP_OVER }, + {0xF6, "TRAP 9", 44, DASMFLAG_STEP_OVER }, + {0xF5, "TRAP 10", 44, DASMFLAG_STEP_OVER }, + {0xF4, "TRAP 11", 44, DASMFLAG_STEP_OVER }, + {0xF3, "TRAP 12", 44, DASMFLAG_STEP_OVER }, + {0xF2, "TRAP 13", 44, DASMFLAG_STEP_OVER }, + {0xF1, "TRAP 14", 44, DASMFLAG_STEP_OVER }, + {0xF0, "TRAP 15", 44, DASMFLAG_STEP_OVER }, + {0xEF, "TRAP 16", 44, DASMFLAG_STEP_OVER }, + {0xEE, "TRAP 17", 44, DASMFLAG_STEP_OVER }, + {0xED, "TRAP 18", 44, DASMFLAG_STEP_OVER }, + {0xEC, "TRAP 19", 44, DASMFLAG_STEP_OVER }, + {0xEB, "TRAP 20", 44, DASMFLAG_STEP_OVER }, + {0xEA, "TRAP 21", 44, DASMFLAG_STEP_OVER }, + {0xE9, "TRAP 22", 44, DASMFLAG_STEP_OVER }, + {0xE8, "TRAP 23", 44, DASMFLAG_STEP_OVER }, + + {0xB7, "SWAP A", 23, 0 }, + {0xC7, "SWAP B", 23, 0 }, + {0xD7, "SWAP", 11, 0 }, + + {0xB0, "TSTA", 23, 0 }, + {0xC1, "TSTB", 23, 0 }, + + {0xB6, "XCHB A", 23, 0 }, + {0xC6, "XCHB B", 23, 0 }, + {0xD6, "XCHB", 11, 0 }, + + {0x65, "XOR", 0, 0 }, + {0x15, "XOR", 1, 0 }, + {0x35, "XOR", 2, 0 }, + {0x45, "XOR", 3, 0 }, + {0x25, "XOR", 4, 0 }, + {0x55, "XOR", 5, 0 }, + {0x75, "XOR", 6, 0 }, + + {0x85, "XORP", 7, 0 }, + {0x95, "XORP", 8, 0 }, + {0xA5, "XORP", 9, 0 }, + + {0x00, "NOP", 23, 0 } +}; + +CPU_DISASSEMBLE( tms7000 ) +{ + int opcode, i/*, size = 1*/; + int pos = 0; + char tmpbuf[32]; + + opcode = oprom[pos++]; + + for( i=0; i; +const device_type TMS7020 = &device_creator; +const device_type TMS7040 = &device_creator; + +// Exelvision (spinoff of TI) TMS7020 added one custom opcode. +const device_type TMS7020_EXL = &device_creator; + +// CMOS devices biggest difference in a 'real world' setting is that the power +// requirements are much lower. This obviously has no use in software emulation. +const device_type TMS70C00 = &device_creator; +const device_type TMS70C20 = &device_creator; +const device_type TMS70C40 = &device_creator; + +// TMS70x1 features more peripheral I/O, the main addition being a serial port. +// TMS70x2 is the same, just with twice more RAM (256 bytes) +const device_type TMS7001 = &device_creator; +const device_type TMS7041 = &device_creator; +const device_type TMS7002 = &device_creator; +const device_type TMS7042 = &device_creator; + +// TMS70C46 is literally a shell around a TMS70C40, with support for external +// memory bus, auto external clock divider on slow memory, and wake-up on keypress. +const device_type TMS70C46 = &device_creator; + +// TMS70Cx2 is an update to TMS70x2 with some extra features. Due to some changes +// in peripheral file I/O, it is not backward compatible to TMS70x2. + + +// flag helpers +#define SR_C 0x80 /* Carry */ +#define SR_N 0x40 /* Negative */ +#define SR_Z 0x20 /* Zero */ +#define SR_I 0x10 /* Interrupt */ + +#define GET_C() (m_sr >> 7 & 1) +#define SET_C(x) m_sr = (m_sr & 0x7f) | ((x) >> 1 & 0x80) +#define SET_NZ(x) m_sr = (m_sr & 0x9f) | ((x) >> 1 & 0x40) | (((x) & 0xff) ? 0 : 0x20) +#define SET_CNZ(x) m_sr = (m_sr & 0x1f) | ((x) >> 1 & 0xc0) | (((x) & 0xff) ? 0 : 0x20) + + +// internal memory maps +static ADDRESS_MAP_START(tms7000_io, AS_IO, 8, tms7000_device) + AM_RANGE(TMS7000_PORTB, TMS7000_PORTB) AM_READNOP +ADDRESS_MAP_END + +static ADDRESS_MAP_START(tms7000_mem, AS_PROGRAM, 8, tms7000_device ) + AM_RANGE(0x0000, 0x007f) AM_RAM // 128 bytes internal RAM + AM_RANGE(0x0080, 0x00ff) AM_READWRITE(tms7000_unmapped_rf_r, tms7000_unmapped_rf_w) + AM_RANGE(0x0104, 0x0105) AM_WRITENOP // no port A write or ddr + AM_RANGE(0x0100, 0x010b) AM_READWRITE(tms7000_pf_r, tms7000_pf_w) +ADDRESS_MAP_END + +static ADDRESS_MAP_START(tms7001_mem, AS_PROGRAM, 8, tms7000_device ) + AM_RANGE(0x0000, 0x007f) AM_RAM // 128 bytes internal RAM + AM_RANGE(0x0080, 0x00ff) AM_READWRITE(tms7000_unmapped_rf_r, tms7000_unmapped_rf_w) + AM_RANGE(0x0100, 0x010b) AM_READWRITE(tms7000_pf_r, tms7000_pf_w) + AM_RANGE(0x0110, 0x0117) AM_READWRITE(tms7002_pf_r, tms7002_pf_w) +ADDRESS_MAP_END + +static ADDRESS_MAP_START(tms7002_mem, AS_PROGRAM, 8, tms7000_device ) + AM_RANGE(0x0000, 0x00ff) AM_RAM // 256 bytes internal RAM + AM_RANGE(0x0100, 0x010b) AM_READWRITE(tms7000_pf_r, tms7000_pf_w) + AM_RANGE(0x0110, 0x0117) AM_READWRITE(tms7002_pf_r, tms7002_pf_w) +ADDRESS_MAP_END + +static ADDRESS_MAP_START(tms7020_mem, AS_PROGRAM, 8, tms7000_device ) + AM_RANGE(0xf000, 0xffff) AM_ROM // 2kB internal ROM + AM_IMPORT_FROM( tms7000_mem ) +ADDRESS_MAP_END + +static ADDRESS_MAP_START(tms7040_mem, AS_PROGRAM, 8, tms7000_device ) + AM_RANGE(0xf000, 0xffff) AM_ROM // 4kB internal ROM + AM_IMPORT_FROM( tms7000_mem ) +ADDRESS_MAP_END + +static ADDRESS_MAP_START(tms7041_mem, AS_PROGRAM, 8, tms7000_device ) + AM_RANGE(0xf000, 0xffff) AM_ROM + AM_IMPORT_FROM( tms7001_mem ) +ADDRESS_MAP_END + +static ADDRESS_MAP_START(tms7042_mem, AS_PROGRAM, 8, tms7000_device ) + AM_RANGE(0xf000, 0xffff) AM_ROM + AM_IMPORT_FROM( tms7002_mem ) +ADDRESS_MAP_END + +static ADDRESS_MAP_START(tms70c46_mem, AS_PROGRAM, 8, tms70c46_device ) + AM_RANGE(0x010c, 0x010c) AM_READWRITE(e_bus_data_r, e_bus_data_w) + AM_RANGE(0x010d, 0x010d) AM_NOP // ? always writes $FF before checking keyboard... maybe INT3 ack? + AM_RANGE(0x010e, 0x010e) AM_READWRITE(dockbus_data_r, dockbus_data_w) + AM_RANGE(0x010f, 0x010f) AM_READWRITE(dockbus_status_r, dockbus_status_w) + AM_RANGE(0x0118, 0x0118) AM_READWRITE(control_r, control_w) + AM_IMPORT_FROM( tms7040_mem ) +ADDRESS_MAP_END + + +// device definitions +tms7000_device::tms7000_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : cpu_device(mconfig, TMS7000, "TMS7000", tag, owner, clock, "tms7000", __FILE__), + m_program_config("program", ENDIANNESS_BIG, 8, 16, 0, ADDRESS_MAP_NAME(tms7000_mem)), + m_io_config("io", ENDIANNESS_BIG, 8, 8, 0, ADDRESS_MAP_NAME(tms7000_io)), + m_info_flags(0) +{ +} + +tms7000_device::tms7000_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, address_map_constructor internal, UINT32 info_flags, const char *shortname, const char *source) + : cpu_device(mconfig, type, name, tag, owner, clock, shortname, source), + m_program_config("program", ENDIANNESS_BIG, 8, 16, 0, internal), + m_io_config("io", ENDIANNESS_BIG, 8, 8, 0, ADDRESS_MAP_NAME(tms7000_io)), + m_info_flags(info_flags) +{ +} + +tms7020_device::tms7020_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : tms7000_device(mconfig, TMS7020, "TMS7020", tag, owner, clock, ADDRESS_MAP_NAME(tms7020_mem), 0, "tms7020", __FILE__) +{ +} + +tms7020_exl_device::tms7020_exl_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : tms7000_device(mconfig, TMS7020_EXL, "TMS7020 (Exelvision)", tag, owner, clock, ADDRESS_MAP_NAME(tms7020_mem), 0, "tms7020_exl", __FILE__) +{ +} + +tms7040_device::tms7040_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : tms7000_device(mconfig, TMS7040, "TMS7040", tag, owner, clock, ADDRESS_MAP_NAME(tms7040_mem), 0, "tms7040", __FILE__) +{ +} + +tms70c00_device::tms70c00_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : tms7000_device(mconfig, TMS70C00, "TMS70C00", tag, owner, clock, ADDRESS_MAP_NAME(tms7000_mem), TMS7000_CHIP_IS_CMOS, "tms70c00", __FILE__) +{ +} + +tms70c20_device::tms70c20_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : tms7000_device(mconfig, TMS70C20, "TMS70C20", tag, owner, clock, ADDRESS_MAP_NAME(tms7020_mem), TMS7000_CHIP_IS_CMOS, "tms70c20", __FILE__) +{ +} + +tms70c40_device::tms70c40_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : tms7000_device(mconfig, TMS70C40, "TMS70C40", tag, owner, clock, ADDRESS_MAP_NAME(tms7040_mem), TMS7000_CHIP_IS_CMOS, "tms70c40", __FILE__) +{ +} + +tms7001_device::tms7001_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : tms7000_device(mconfig, TMS7001, "TMS7001", tag, owner, clock, ADDRESS_MAP_NAME(tms7001_mem), TMS7000_CHIP_FAMILY_70X2, "tms7001", __FILE__) +{ +} + +tms7041_device::tms7041_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : tms7000_device(mconfig, TMS7041, "TMS7041", tag, owner, clock, ADDRESS_MAP_NAME(tms7041_mem), TMS7000_CHIP_FAMILY_70X2, "tms7041", __FILE__) +{ +} + +tms7002_device::tms7002_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : tms7000_device(mconfig, TMS7002, "TMS7002", tag, owner, clock, ADDRESS_MAP_NAME(tms7002_mem), TMS7000_CHIP_FAMILY_70X2, "tms7002", __FILE__) +{ +} + +tms7042_device::tms7042_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : tms7000_device(mconfig, TMS7042, "TMS7042", tag, owner, clock, ADDRESS_MAP_NAME(tms7042_mem), TMS7000_CHIP_FAMILY_70X2, "tms7042", __FILE__) +{ +} + +tms70c46_device::tms70c46_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : tms7000_device(mconfig, TMS70C46, "TMS70C46", tag, owner, clock, ADDRESS_MAP_NAME(tms70c46_mem), TMS7000_CHIP_IS_CMOS, "tms70c46", __FILE__) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void tms7000_device::device_start() +{ + // init/zerofill + m_program = &space(AS_PROGRAM); + m_direct = &m_program->direct(); + m_io = &space(AS_IO); + + m_icountptr = &m_icount; + + m_irq_state[TMS7000_INT1_LINE] = false; + m_irq_state[TMS7000_INT3_LINE] = false; + + m_idle_state = false; + m_idle_halt = false; + m_pc = 0; + m_sp = 0; + m_sr = 0; + m_op = 0; + + memset(m_io_control, 0, 3); + + memset(m_port_latch, 0, 4); + memset(m_port_ddr, 0, 4); + m_port_ddr[1] = 0xff; // ! + + for (int tmr = 0; tmr < 2; tmr++) + { + m_timer_handle[tmr] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(tms7000_device::simple_timer_cb), this)); + m_timer_handle[tmr]->adjust(attotime::never, tmr); + + m_timer_data[tmr] = 0; + m_timer_control[tmr] = 0; + m_timer_decrementer[tmr] = 0; + m_timer_prescaler[tmr] = 0; + m_timer_capture_latch[tmr] = 0; + } + + // register for savestates + save_item(NAME(m_irq_state)); + save_item(NAME(m_idle_state)); + save_item(NAME(m_pc)); + save_item(NAME(m_sp)); + save_item(NAME(m_sr)); + save_item(NAME(m_op)); + + save_item(NAME(m_io_control)); + save_item(NAME(m_port_latch)); + save_item(NAME(m_port_ddr)); + save_item(NAME(m_timer_data)); + save_item(NAME(m_timer_control)); + save_item(NAME(m_timer_decrementer)); + save_item(NAME(m_timer_prescaler)); + save_item(NAME(m_timer_capture_latch)); + + // register for debugger + state_add(TMS7000_PC, "PC", m_pc).formatstr("%02X"); + state_add(TMS7000_SP, "S", m_sp).formatstr("%02X"); + state_add(TMS7000_ST, "ST", m_sr).formatstr("%02X"); + + state_add(STATE_GENPC, "GENPC", m_pc).formatstr("%02X").noshow(); + state_add(STATE_GENSP, "GENSP", m_sp).formatstr("%02X").noshow(); + state_add(STATE_GENFLAGS, "GENFLAGS", m_sr).formatstr("%8s").noshow(); +} + +void tms7000_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + switch (entry.index()) + { + case STATE_GENFLAGS: + strprintf(str, "%c%c%c%c%c%c%c%c", + m_sr & 0x80 ? 'C':'c', + m_sr & 0x40 ? 'N':'n', + m_sr & 0x20 ? 'Z':'z', + m_sr & 0x10 ? 'I':'i', + m_sr & 0x08 ? '?':'.', + m_sr & 0x04 ? '?':'.', + m_sr & 0x02 ? '?':'.', + m_sr & 0x01 ? '?':'.' + ); + break; + + default: break; + } +} + +offs_t tms7000_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( tms7000 ); + return CPU_DISASSEMBLE_NAME(tms7000)(this, buffer, pc, oprom, opram, options); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void tms7000_device::device_reset() +{ + if (m_idle_state) + { + m_pc++; + m_idle_state = false; + } + + // while _RESET is asserted: + // clear ports + write_p(0x04, 0xff); // port a + write_p(0x06, 0xff); // port b + + write_p(0x05, 0x00); // ddr a + write_p(0x09, 0x00); // ddr c + write_p(0x0b, 0x00); // ddr d + + if (!chip_is_cmos()) + { + write_p(0x08, 0xff); // port c + write_p(0x0a, 0xff); // port d + } + + // when _RESET goes inactive (0 to 1) + m_sr = 0; + + write_p(0x00, 0x00); // IOCNT0 + if (chip_is_family_70x2()) + write_p(0x10, 0x00); // IOCNT1 + + m_sp = 0xff; + m_op = 0xff; + execute_one(m_op); + m_icount -= 3; // 17 total +} + + +//------------------------------------------------- +// interrupts +//------------------------------------------------- + +void tms7000_device::execute_set_input(int extline, int state) +{ + if (extline != TMS7000_INT1_LINE && extline != TMS7000_INT3_LINE) + return; + + bool irqstate = (state == CLEAR_LINE) ? false : true; + + // reverse polarity (TMS70cx2-only) + if (m_io_control[2] & (0x01 << (4 * extline))) + irqstate = !irqstate; + + if (m_irq_state[extline] != irqstate) + { + m_irq_state[extline] = irqstate; + + // set/clear internal irq flag + flag_ext_interrupt(extline); + + if (m_irq_state[extline]) + { + // latch timer 1 on INT3 + if (extline == TMS7000_INT3_LINE) + m_timer_capture_latch[0] = m_timer_decrementer[0]; + + // on TMS70cx2, latch timer 2 on INT1 + if (extline == TMS7000_INT1_LINE && chip_is_family_70cx2()) + m_timer_capture_latch[1] = m_timer_decrementer[1]; + + // clear external if it's edge-triggered (TMS70cx2-only) + if (m_io_control[2] & (0x02 << (4 * extline))) + m_irq_state[extline] = false; + + check_interrupts(); + } + } +} + +void tms7000_device::flag_ext_interrupt(int extline) +{ + if (extline != TMS7000_INT1_LINE && extline != TMS7000_INT3_LINE) + return; + + // set/clear for pending external interrupt + if (m_irq_state[extline]) + m_io_control[0] |= (0x02 << (4 * extline)); + else + m_io_control[0] &= ~(0x02 << (4 * extline)); +} + +void tms7000_device::check_interrupts() +{ + // global interrupt bit + if (!(m_sr & SR_I)) + return; + + // check for and handle interrupt + for (int irqline = 0; irqline < 5; irqline++) + { + // INT 1,2,3 are in IOCNT0 d0-d5 + // INT 4,5 are in IOCNT1 d0-d3 + int shift = (irqline > 2) ? irqline * 2 - 6 : irqline * 2; + if ((m_io_control[irqline > 2] >> shift & 3) == 3) + { + // ack + m_io_control[irqline > 2] &= ~(0x02 << shift); + if (irqline == 0 || irqline == 2) + flag_ext_interrupt(irqline / 2); + + do_interrupt(irqline); + return; + } + } +} + +void tms7000_device::do_interrupt(int irqline) +{ + if (m_idle_state) + { + m_icount -= 17; + m_pc++; + m_idle_state = false; + } + else + m_icount -= 19; + + push8(m_sr); + push16(m_pc); + m_sr = 0; + m_pc = read_mem16(0xfffc - irqline * 2); + + standard_irq_callback(irqline); +} + + +//------------------------------------------------- +// timers +//------------------------------------------------- + +void tms7000_device::timer_run(int tmr) +{ + m_timer_prescaler[tmr] = m_timer_control[tmr] & 0x1f; + + // run automatic timer if source is internal + if ((m_timer_control[tmr] & 0xe0) == 0x80) + { + attotime period = attotime::from_hz(clock()) * 8 * (m_timer_prescaler[tmr] + 1); // fOSC/16 - fOSC is freq _before_ internal clockdivider + m_timer_handle[tmr]->adjust(period, tmr); + } +} + +void tms7000_device::timer_reload(int tmr) +{ + // stop possible running timer + m_timer_handle[tmr]->adjust(attotime::never, tmr); + + if (m_timer_control[tmr] & 0x80) + { + m_timer_decrementer[tmr] = m_timer_data[tmr]; + timer_run(tmr); + } +} + +void tms7000_device::timer_tick_pre(int tmr) +{ + // timer prescaler underflow + if (--m_timer_prescaler[tmr] < 0) + { + m_timer_prescaler[tmr] = m_timer_control[tmr] & 0x1f; + timer_tick_low(tmr); + } +} + +void tms7000_device::timer_tick_low(int tmr) +{ + // timer decrementer underflow + if (--m_timer_decrementer[tmr] < 0) + { + timer_reload(tmr); + + // set INT2/INT5 + m_io_control[tmr] |= 0x08; + + // cascaded timer + if (tmr == 0 && (m_timer_control[1] & 0xa0) == 0xa0) + timer_tick_pre(tmr + 1); + } +} + +TIMER_CALLBACK_MEMBER(tms7000_device::simple_timer_cb) +{ + int tmr = param; + + // tick and restart timer + timer_tick_low(tmr); + timer_run(tmr); +} + + +//------------------------------------------------- +// peripheral file - read/write internal ports +// note: TMS7000 family is from $00 to $0b, TMS7002 family adds $10 to $17 +//------------------------------------------------- + +READ8_MEMBER(tms7000_device::tms7000_pf_r) +{ + switch (offset) + { + // i/o control + case 0x00: case 0x10: + return m_io_control[offset >> 4]; + + // timer 1/2 data + case 0x02: case 0x12: + // current decrementer value + return m_timer_decrementer[offset >> 4]; + + // timer 1 control + case 0x03: + // timer capture (latched by INT3) + return m_timer_capture_latch[0]; + + // port data + case 0x04: case 0x06: case 0x08: case 0x0a: + { + // note: port B is write-only, reading it returns the output value as if ddr is 0xff + int port = offset / 2 - 2; + if (!space.debugger_access()) + return (m_io->read_byte(port) & ~m_port_ddr[port]) | (m_port_latch[port] & m_port_ddr[port]); + break; + } + + // port direction (note: TMS7000 doesn't support it for port A) + case 0x05: case 0x09: case 0x0b: + return m_port_ddr[offset / 2 - 2]; + + default: + if (!space.debugger_access()) + logerror("'%s' (%04X): tms7000_pf_r @ $%04x\n", tag(), m_pc, offset); + break; + } + + return 0; +} + +WRITE8_MEMBER(tms7000_device::tms7000_pf_w) +{ + switch (offset) + { + // i/o control (IOCNT0) + case 0x00: + // d0,d2,d4: INT1,2,3 enable + // d1,d3,d5: INT1,2,3 flag (write 1 to clear flag) + // d6-d7: memory mode (currently not implemented) + m_io_control[0] = (m_io_control[0] & (~data & 0x2a)) | (data & 0xd5); + + // possibly need to reactivate flags + if (data & 0x02) + flag_ext_interrupt(TMS7000_INT1_LINE); + if (data & 0x20) + flag_ext_interrupt(TMS7000_INT3_LINE); + + check_interrupts(); + break; + + // i/o control (IOCNT1) + case 0x10: + // d0,d2: INT4,5 enable + // d1,d3: INT4,5 flag (write 1 to clear flag) + m_io_control[1] = (m_io_control[1] & (~data & 0x0a)) | (data & 0x05); + check_interrupts(); + break; + + // timer 1/2 data + case 0x02: case 0x12: + // decrementer reload value + m_timer_data[offset >> 4] = data; + break; + + // timer 1/2 control + case 0x03: + // d5: t1: cmos low-power mode when IDLE opcode is used (not emulated) + // 0(normal), or 1(halt) - indicating it can only wake up with RESET or external interrupt + if (chip_is_cmos()) + { + m_idle_halt = (data & 0x20) ? true : false; + if (m_idle_halt) + logerror("%s: CMOS low-power halt mode enabled\n", tag()); + } + data &= ~0x20; + case 0x13: + // d0-d4: prescaler reload value + // d5: t2: cascade from t1 + // d6: source (internal/external) + // d7: stop/start timer + m_timer_control[offset >> 4] = data; + timer_reload(offset >> 4); + + // on cmos chip, clear INT2/INT5 as well + if (~data & 0x80 && chip_is_cmos()) + m_io_control[offset >> 4] &= ~0x08; + + break; + + // port data (note: TMS7000 doesn't support it for port A) + case 0x04: case 0x06: case 0x08: case 0x0a: + { + // note: in memory expansion modes, some port output pins are used for memory strobes. + // this is currently ignored, since port writes will always be visible externally on peripheral expansion anyway. + int port = offset / 2 - 2; + m_io->write_byte(port, data & m_port_ddr[port]); + m_port_latch[port] = data; + break; + } + + // port direction (note: TMS7000 doesn't support it for port A) + case 0x05: case 0x09: case 0x0b: + // note: changing port direction does not change(refresh) the output pins + m_port_ddr[offset / 2 - 2] = data; + break; + + default: + logerror("'%s' (%04X): tms7000_pf_w @ $%04x = $%02x\n", tag(), m_pc, offset, data); + break; + } +} + + +//------------------------------------------------- +// execute +//------------------------------------------------- + +#include "tms70op.inc" + +void tms7000_device::execute_run() +{ + check_interrupts(); + + do + { + debugger_instruction_hook(this, m_pc); + + m_op = m_direct->read_byte(m_pc++); + execute_one(m_op); + } while (m_icount > 0); +} + +void tms7000_device::execute_one(UINT8 op) +{ + switch (op) + { + case 0x00: nop(); break; + case 0x01: idle(); break; + case 0x05: eint(); break; + case 0x06: dint(); break; + case 0x07: setc(); break; + case 0x08: pop_st(); break; + case 0x09: stsp(); break; + case 0x0a: rets(); break; + case 0x0b: reti(); break; + case 0x0d: ldsp(); break; + case 0x0e: push_st(); break; + + case 0x12: am_r2a(&tms7000_device::op_mov); break; + case 0x13: am_r2a(&tms7000_device::op_and); break; + case 0x14: am_r2a(&tms7000_device::op_or); break; + case 0x15: am_r2a(&tms7000_device::op_xor); break; + case 0x16: am_r2a(&tms7000_device::op_btjo); break; + case 0x17: am_r2a(&tms7000_device::op_btjz); break; + case 0x18: am_r2a(&tms7000_device::op_add); break; + case 0x19: am_r2a(&tms7000_device::op_adc); break; + case 0x1a: am_r2a(&tms7000_device::op_sub); break; + case 0x1b: am_r2a(&tms7000_device::op_sbb); break; + case 0x1c: am_r2a(&tms7000_device::op_mpy); break; + case 0x1d: am_r2a(&tms7000_device::op_cmp); break; + case 0x1e: am_r2a(&tms7000_device::op_dac); break; + case 0x1f: am_r2a(&tms7000_device::op_dsb); break; + + case 0x22: am_i2a(&tms7000_device::op_mov); break; + case 0x23: am_i2a(&tms7000_device::op_and); break; + case 0x24: am_i2a(&tms7000_device::op_or); break; + case 0x25: am_i2a(&tms7000_device::op_xor); break; + case 0x26: am_i2a(&tms7000_device::op_btjo); break; + case 0x27: am_i2a(&tms7000_device::op_btjz); break; + case 0x28: am_i2a(&tms7000_device::op_add); break; + case 0x29: am_i2a(&tms7000_device::op_adc); break; + case 0x2a: am_i2a(&tms7000_device::op_sub); break; + case 0x2b: am_i2a(&tms7000_device::op_sbb); break; + case 0x2c: am_i2a(&tms7000_device::op_mpy); break; + case 0x2d: am_i2a(&tms7000_device::op_cmp); break; + case 0x2e: am_i2a(&tms7000_device::op_dac); break; + case 0x2f: am_i2a(&tms7000_device::op_dsb); break; + + case 0x32: am_r2b(&tms7000_device::op_mov); break; + case 0x33: am_r2b(&tms7000_device::op_and); break; + case 0x34: am_r2b(&tms7000_device::op_or); break; + case 0x35: am_r2b(&tms7000_device::op_xor); break; + case 0x36: am_r2b(&tms7000_device::op_btjo); break; + case 0x37: am_r2b(&tms7000_device::op_btjz); break; + case 0x38: am_r2b(&tms7000_device::op_add); break; + case 0x39: am_r2b(&tms7000_device::op_adc); break; + case 0x3a: am_r2b(&tms7000_device::op_sub); break; + case 0x3b: am_r2b(&tms7000_device::op_sbb); break; + case 0x3c: am_r2b(&tms7000_device::op_mpy); break; + case 0x3d: am_r2b(&tms7000_device::op_cmp); break; + case 0x3e: am_r2b(&tms7000_device::op_dac); break; + case 0x3f: am_r2b(&tms7000_device::op_dsb); break; + + case 0x42: am_r2r(&tms7000_device::op_mov); break; + case 0x43: am_r2r(&tms7000_device::op_and); break; + case 0x44: am_r2r(&tms7000_device::op_or); break; + case 0x45: am_r2r(&tms7000_device::op_xor); break; + case 0x46: am_r2r(&tms7000_device::op_btjo); break; + case 0x47: am_r2r(&tms7000_device::op_btjz); break; + case 0x48: am_r2r(&tms7000_device::op_add); break; + case 0x49: am_r2r(&tms7000_device::op_adc); break; + case 0x4a: am_r2r(&tms7000_device::op_sub); break; + case 0x4b: am_r2r(&tms7000_device::op_sbb); break; + case 0x4c: am_r2r(&tms7000_device::op_mpy); break; + case 0x4d: am_r2r(&tms7000_device::op_cmp); break; + case 0x4e: am_r2r(&tms7000_device::op_dac); break; + case 0x4f: am_r2r(&tms7000_device::op_dsb); break; + + case 0x52: am_i2b(&tms7000_device::op_mov); break; + case 0x53: am_i2b(&tms7000_device::op_and); break; + case 0x54: am_i2b(&tms7000_device::op_or); break; + case 0x55: am_i2b(&tms7000_device::op_xor); break; + case 0x56: am_i2b(&tms7000_device::op_btjo); break; + case 0x57: am_i2b(&tms7000_device::op_btjz); break; + case 0x58: am_i2b(&tms7000_device::op_add); break; + case 0x59: am_i2b(&tms7000_device::op_adc); break; + case 0x5a: am_i2b(&tms7000_device::op_sub); break; + case 0x5b: am_i2b(&tms7000_device::op_sbb); break; + case 0x5c: am_i2b(&tms7000_device::op_mpy); break; + case 0x5d: am_i2b(&tms7000_device::op_cmp); break; + case 0x5e: am_i2b(&tms7000_device::op_dac); break; + case 0x5f: am_i2b(&tms7000_device::op_dsb); break; + + case 0x62: am_b2a(&tms7000_device::op_mov); break; + case 0x63: am_b2a(&tms7000_device::op_and); break; + case 0x64: am_b2a(&tms7000_device::op_or); break; + case 0x65: am_b2a(&tms7000_device::op_xor); break; + case 0x66: am_b2a(&tms7000_device::op_btjo); break; + case 0x67: am_b2a(&tms7000_device::op_btjz); break; + case 0x68: am_b2a(&tms7000_device::op_add); break; + case 0x69: am_b2a(&tms7000_device::op_adc); break; + case 0x6a: am_b2a(&tms7000_device::op_sub); break; + case 0x6b: am_b2a(&tms7000_device::op_sbb); break; + case 0x6c: am_b2a(&tms7000_device::op_mpy); break; + case 0x6d: am_b2a(&tms7000_device::op_cmp); break; + case 0x6e: am_b2a(&tms7000_device::op_dac); break; + case 0x6f: am_b2a(&tms7000_device::op_dsb); break; + + case 0x72: am_i2r(&tms7000_device::op_mov); break; + case 0x73: am_i2r(&tms7000_device::op_and); break; + case 0x74: am_i2r(&tms7000_device::op_or); break; + case 0x75: am_i2r(&tms7000_device::op_xor); break; + case 0x76: am_i2r(&tms7000_device::op_btjo); break; + case 0x77: am_i2r(&tms7000_device::op_btjz); break; + case 0x78: am_i2r(&tms7000_device::op_add); break; + case 0x79: am_i2r(&tms7000_device::op_adc); break; + case 0x7a: am_i2r(&tms7000_device::op_sub); break; + case 0x7b: am_i2r(&tms7000_device::op_sbb); break; + case 0x7c: am_i2r(&tms7000_device::op_mpy); break; + case 0x7d: am_i2r(&tms7000_device::op_cmp); break; + case 0x7e: am_i2r(&tms7000_device::op_dac); break; + case 0x7f: am_i2r(&tms7000_device::op_dsb); break; + + case 0x80: am_p2a(&tms7000_device::op_mov); break; + case 0x82: am_a2p(&tms7000_device::op_mov); break; + case 0x83: am_a2p(&tms7000_device::op_and); break; + case 0x84: am_a2p(&tms7000_device::op_or); break; + case 0x85: am_a2p(&tms7000_device::op_xor); break; + case 0x86: am_a2p(&tms7000_device::op_btjo); break; + case 0x87: am_a2p(&tms7000_device::op_btjz); break; + case 0x88: movd_dir(); break; + case 0x8a: lda_dir(); break; + case 0x8b: sta_dir(); break; + case 0x8c: br_dir(); break; + case 0x8d: cmpa_dir(); break; + case 0x8e: call_dir(); break; + + case 0x91: am_p2b(&tms7000_device::op_mov); break; + case 0x92: am_b2p(&tms7000_device::op_mov); break; + case 0x93: am_b2p(&tms7000_device::op_and); break; + case 0x94: am_b2p(&tms7000_device::op_or); break; + case 0x95: am_b2p(&tms7000_device::op_xor); break; + case 0x96: am_b2p(&tms7000_device::op_btjo); break; + case 0x97: am_b2p(&tms7000_device::op_btjz); break; + case 0x98: movd_ind(); break; + case 0x9a: lda_ind(); break; + case 0x9b: sta_ind(); break; + case 0x9c: br_ind(); break; + case 0x9d: cmpa_ind(); break; + case 0x9e: call_ind(); break; + + case 0xa2: am_i2p(&tms7000_device::op_mov); break; + case 0xa3: am_i2p(&tms7000_device::op_and); break; + case 0xa4: am_i2p(&tms7000_device::op_or); break; + case 0xa5: am_i2p(&tms7000_device::op_xor); break; + case 0xa6: am_i2p(&tms7000_device::op_btjo); break; + case 0xa7: am_i2p(&tms7000_device::op_btjz); break; + case 0xa8: movd_inx(); break; + case 0xaa: lda_inx(); break; + case 0xab: sta_inx(); break; + case 0xac: br_inx(); break; + case 0xad: cmpa_inx(); break; + case 0xae: call_inx(); break; + + case 0xb0: am_a2a(&tms7000_device::op_mov); break; // aka clrc/tsta + case 0xb1: am_b2a(&tms7000_device::op_mov); break; // undocumented + case 0xb2: am_a(&tms7000_device::op_dec); break; + case 0xb3: am_a(&tms7000_device::op_inc); break; + case 0xb4: am_a(&tms7000_device::op_inv); break; + case 0xb5: am_a(&tms7000_device::op_clr); break; + case 0xb6: am_a(&tms7000_device::op_xchb); break; + case 0xb7: am_a(&tms7000_device::op_swap); break; + case 0xb8: push_a(); break; + case 0xb9: pop_a(); break; + case 0xba: am_a(&tms7000_device::op_djnz); break; + case 0xbb: decd_a(); break; + case 0xbc: am_a(&tms7000_device::op_rr); break; + case 0xbd: am_a(&tms7000_device::op_rrc); break; + case 0xbe: am_a(&tms7000_device::op_rl); break; + case 0xbf: am_a(&tms7000_device::op_rlc); break; + + case 0xc0: am_a2b(&tms7000_device::op_mov); break; + case 0xc1: am_b2b(&tms7000_device::op_mov); break; // aka tstb + case 0xc2: am_b(&tms7000_device::op_dec); break; + case 0xc3: am_b(&tms7000_device::op_inc); break; + case 0xc4: am_b(&tms7000_device::op_inv); break; + case 0xc5: am_b(&tms7000_device::op_clr); break; + case 0xc6: am_b(&tms7000_device::op_xchb); break; // result equivalent to tstb + case 0xc7: am_b(&tms7000_device::op_swap); break; + case 0xc8: push_b(); break; + case 0xc9: pop_b(); break; + case 0xca: am_b(&tms7000_device::op_djnz); break; + case 0xcb: decd_b(); break; + case 0xcc: am_b(&tms7000_device::op_rr); break; + case 0xcd: am_b(&tms7000_device::op_rrc); break; + case 0xce: am_b(&tms7000_device::op_rl); break; + case 0xcf: am_b(&tms7000_device::op_rlc); break; + + case 0xd0: am_a2r(&tms7000_device::op_mov); break; + case 0xd1: am_b2r(&tms7000_device::op_mov); break; + case 0xd2: am_r(&tms7000_device::op_dec); break; + case 0xd3: am_r(&tms7000_device::op_inc); break; + case 0xd4: am_r(&tms7000_device::op_inv); break; + case 0xd5: am_r(&tms7000_device::op_clr); break; + case 0xd6: am_r(&tms7000_device::op_xchb); break; + case 0xd7: am_r(&tms7000_device::op_swap); break; + case 0xd8: push_r(); break; + case 0xd9: pop_r(); break; + case 0xda: am_r(&tms7000_device::op_djnz); break; + case 0xdb: decd_r(); break; + case 0xdc: am_r(&tms7000_device::op_rr); break; + case 0xdd: am_r(&tms7000_device::op_rrc); break; + case 0xde: am_r(&tms7000_device::op_rl); break; + case 0xdf: am_r(&tms7000_device::op_rlc); break; + + case 0xe0: jmp(true); break; + case 0xe1: jmp(m_sr & SR_N); break; // jn/jlt + case 0xe2: jmp(m_sr & SR_Z); break; // jz/jeq + case 0xe3: jmp(m_sr & SR_C); break; // jc/jhs + case 0xe4: jmp(!(m_sr & (SR_Z | SR_N))); break; // jp/jgt + case 0xe5: jmp(!(m_sr & SR_N)); break; // jpz/jge - note: error in TI official documentation + case 0xe6: jmp(!(m_sr & SR_Z)); break; // jnz/jne + case 0xe7: jmp(!(m_sr & SR_C)); break; // jnc/jl + + 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: + trap(op << 1); break; + + default: illegal(op); break; + } +} + +void tms7020_exl_device::execute_one(UINT8 op) +{ + // TMS7020 Exelvision EXL 100 custom opcode(s) + if (op == 0xd7) + lvdp(); + else + tms7000_device::execute_one(op); +} + + +//------------------------------------------------- +// TMS70C46 specifics +//------------------------------------------------- + +void tms70c46_device::device_start() +{ + // init/zerofill + m_control = 0; + + // register for savestates + save_item(NAME(m_control)); + + tms7000_device::device_start(); +} + +void tms70c46_device::device_reset() +{ + m_control = 0; + m_io->write_byte(TMS7000_PORTE, 0xff); + + tms7000_device::device_reset(); +} + +READ8_MEMBER(tms70c46_device::control_r) +{ + return m_control; +} + +WRITE8_MEMBER(tms70c46_device::control_w) +{ + // d5: enable external databus + if (~m_control & data & 0x20) + m_io->write_byte(TMS7000_PORTE, 0xff); // go into high impedance + + // d4: enable clock divider when accessing slow memory (not emulated) + // known fast memory areas: internal ROM/RAM, system RAM + // known slow memory areas: system ROM, cartridge ROM/RAM + + // d0-d3(all bits?): clock divider when d4 is set and addressbus is in slow memory area + // needs to be measured, i just know that $30 is full speed, and $38 is about 4 times slower + m_control = data; +} + +// DOCK-BUS: TODO.. +// right now pretend that nothing is connected +// external pins are HD0-HD3(data), HSK(handshake), BAV(bus available) + +READ8_MEMBER(tms70c46_device::dockbus_status_r) +{ + // d0: slave _HSK + // d1: slave _BAV + // d2: unused? + // d3: IRQ active + return 0; +} + +WRITE8_MEMBER(tms70c46_device::dockbus_status_w) +{ + // d0: master _HSK (setting it low(write 1) also clears IRQ) + // d1: master _BAV + // other bits: unused? +} + +READ8_MEMBER(tms70c46_device::dockbus_data_r) +{ + return 0xff; +} + +WRITE8_MEMBER(tms70c46_device::dockbus_data_w) +{ +} diff --git a/src/devices/cpu/tms7000/tms7000.h b/src/devices/cpu/tms7000/tms7000.h new file mode 100644 index 00000000000..92effc0d079 --- /dev/null +++ b/src/devices/cpu/tms7000/tms7000.h @@ -0,0 +1,366 @@ +// license:BSD-3-Clause +// copyright-holders:hap, Tim Lindner +/* + + Texas Instruments TMS7000 + +*/ + +#pragma once + +#ifndef __TMS7000_H__ +#define __TMS7000_H__ + +#include "emu.h" +#include "debugger.h" + + +enum { TMS7000_PC=1, TMS7000_SP, TMS7000_ST }; + +enum +{ + /* note: INT2,4,5 are generated internally */ + TMS7000_INT1_LINE = 0, + TMS7000_INT3_LINE +}; + +enum +{ + TMS7000_PORTA = 0, /* read-only on 70x0 */ + TMS7000_PORTB, /* write-only */ + TMS7000_PORTC, + TMS7000_PORTD, + TMS7000_PORTE /* TMS70C46 only */ +}; + +// chip info flags +#define TMS7000_CHIP_IS_CMOS 0x01 +#define TMS7000_CHIP_FAMILY_70X0 0x00 +#define TMS7000_CHIP_FAMILY_70X2 0x02 +#define TMS7000_CHIP_FAMILY_70CX2 0x04 +#define TMS7000_CHIP_FAMILY_MASK 0x06 + + +class tms7000_device : public cpu_device +{ +public: + // construction/destruction + tms7000_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + tms7000_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, address_map_constructor internal, UINT32 info_flags, const char *shortname, const char *source); + + DECLARE_READ8_MEMBER(tms7000_unmapped_rf_r) { if (!space.debugger_access()) logerror("'%s' (%04X): unmapped_rf_r @ $%04x\n", tag(), m_pc, offset + 0x80); return 0; }; + DECLARE_WRITE8_MEMBER(tms7000_unmapped_rf_w) { logerror("'%s' (%04X): unmapped_rf_w @ $%04x = $%02x\n", tag(), m_pc, offset + 0x80, data); }; + + DECLARE_READ8_MEMBER(tms7000_pf_r); + DECLARE_WRITE8_MEMBER(tms7000_pf_w); + DECLARE_READ8_MEMBER(tms7002_pf_r) { return tms7000_pf_r(space, offset + 0x10); } + DECLARE_WRITE8_MEMBER(tms7002_pf_w) { tms7000_pf_w(space, offset + 0x10, data); } + + bool chip_is_cmos() { return (m_info_flags & TMS7000_CHIP_IS_CMOS) ? true : false; } + UINT32 chip_get_family() { return m_info_flags & TMS7000_CHIP_FAMILY_MASK; } + bool chip_is_family_70x0() { return chip_get_family() == TMS7000_CHIP_FAMILY_70X0; } + bool chip_is_family_70x2() { return chip_get_family() == TMS7000_CHIP_FAMILY_70X2; } + bool chip_is_family_70cx2() { return chip_get_family() == TMS7000_CHIP_FAMILY_70CX2; } + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_execute_interface overrides + virtual UINT64 execute_clocks_to_cycles(UINT64 clocks) const { return (clocks + 2 - 1) / 2; } // internal /2 divider + virtual UINT64 execute_cycles_to_clocks(UINT64 cycles) const { return (cycles * 2); } // internal /2 divider + virtual UINT32 execute_min_cycles() const { return 5; } + virtual UINT32 execute_max_cycles() const { return 49; } + virtual UINT32 execute_input_lines() const { return 2; } + virtual void execute_run(); + virtual void execute_set_input(int extline, int state); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const { return (spacenum == AS_PROGRAM) ? &m_program_config : ( (spacenum == AS_IO) ? &m_io_config : NULL ); } + + // device_state_interface overrides + void state_string_export(const device_state_entry &entry, std::string &str); + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const { return 1; } + virtual UINT32 disasm_max_opcode_bytes() const { return 4; } + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + + virtual void execute_one(UINT8 op); + + address_space_config m_program_config; + address_space_config m_io_config; + + UINT32 m_info_flags; + + address_space *m_program; + direct_read_data *m_direct; + address_space *m_io; + int m_icount; + + bool m_irq_state[2]; + bool m_idle_state; + bool m_idle_halt; + UINT16 m_pc; + UINT8 m_sp; + UINT8 m_sr; + UINT8 m_op; + + UINT8 m_io_control[3]; + + emu_timer *m_timer_handle[2]; + UINT8 m_timer_data[2]; + UINT8 m_timer_control[2]; + int m_timer_decrementer[2]; + int m_timer_prescaler[2]; + UINT16 m_timer_capture_latch[2]; + + UINT8 m_port_latch[4]; + UINT8 m_port_ddr[4]; + + void flag_ext_interrupt(int extline); + void check_interrupts(); + void do_interrupt(int irqline); + + TIMER_CALLBACK_MEMBER(simple_timer_cb); + void timer_run(int tmr); + void timer_reload(int tmr); + void timer_tick_pre(int tmr); + void timer_tick_low(int tmr); + + // internal read/write + inline UINT8 read_r8(UINT8 address) { return m_program->read_byte(address); } + inline void write_r8(UINT8 address, UINT8 data) { m_program->write_byte(address, data); } + inline UINT16 read_r16(UINT8 address) { return m_program->read_byte((address - 1) & 0xff) << 8 | m_program->read_byte(address); } + inline void write_r16(UINT8 address, UINT16 data) { m_program->write_byte((address - 1) & 0xff, data >> 8 & 0xff); m_program->write_byte(address, data & 0xff); } + + inline UINT8 read_p(UINT8 address) { return m_program->read_byte(0x100 + address); } + inline void write_p(UINT8 address, UINT8 data) { m_program->write_byte(0x100 + address, data); } + + inline UINT8 read_mem8(UINT16 address) { return m_program->read_byte(address); } + inline void write_mem8(UINT16 address, UINT8 data) { m_program->write_byte(address, data); } + inline UINT16 read_mem16(UINT16 address) { return m_program->read_byte(address) << 8 | m_program->read_byte((address + 1) & 0xffff); } + inline void write_mem16(UINT16 address, UINT16 data) { m_program->write_byte(address, data >> 8 & 0xff); m_program->write_byte((address + 1) & 0xffff, data & 0xff); } + + inline UINT8 imm8() { return m_direct->read_byte(m_pc++); } + inline UINT16 imm16() { UINT16 ret = m_direct->read_byte(m_pc++) << 8; return ret | m_direct->read_byte(m_pc++); } + + inline UINT8 pull8() { return m_program->read_byte(m_sp--); } + inline void push8(UINT8 data) { m_program->write_byte(++m_sp, data); } + inline UINT16 pull16() { UINT16 ret = m_program->read_byte(m_sp--); return ret | m_program->read_byte(m_sp--) << 8; } + inline void push16(UINT16 data) { m_program->write_byte(++m_sp, data >> 8 & 0xff); m_program->write_byte(++m_sp, data & 0xff); } + + // opcode handlers + void br_dir(); + void br_inx(); + void br_ind(); + void call_dir(); + void call_inx(); + void call_ind(); + void cmpa_dir(); + void cmpa_inx(); + void cmpa_ind(); + void decd_a(); + void decd_b(); + void decd_r(); + void dint(); + void eint(); + void idle(); + void lda_dir(); + void lda_inx(); + void lda_ind(); + void ldsp(); + void movd_dir(); + void movd_inx(); + void movd_ind(); + void nop(); + void pop_a(); + void pop_b(); + void pop_r(); + void pop_st(); + void push_a(); + void push_b(); + void push_r(); + void push_st(); + void reti(); + void rets(); + void setc(); + void sta_dir(); + void sta_inx(); + void sta_ind(); + void stsp(); + void trap(UINT8 address); + void illegal(UINT8 op); + + typedef int (tms7000_device::*op_func)(UINT8, UINT8); + int op_clr(UINT8 param1, UINT8 param2); + int op_dec(UINT8 param1, UINT8 param2); + int op_inc(UINT8 param1, UINT8 param2); + int op_inv(UINT8 param1, UINT8 param2); + int op_rl(UINT8 param1, UINT8 param2); + int op_rlc(UINT8 param1, UINT8 param2); + int op_rr(UINT8 param1, UINT8 param2); + int op_rrc(UINT8 param1, UINT8 param2); + int op_swap(UINT8 param1, UINT8 param2); + int op_xchb(UINT8 param1, UINT8 param2); + + int op_adc(UINT8 param1, UINT8 param2); + int op_add(UINT8 param1, UINT8 param2); + int op_and(UINT8 param1, UINT8 param2); + int op_cmp(UINT8 param1, UINT8 param2); + int op_dac(UINT8 param1, UINT8 param2); + int op_dsb(UINT8 param1, UINT8 param2); + int op_mpy(UINT8 param1, UINT8 param2); + int op_mov(UINT8 param1, UINT8 param2); + int op_or(UINT8 param1, UINT8 param2); + int op_sbb(UINT8 param1, UINT8 param2); + int op_sub(UINT8 param1, UINT8 param2); + int op_xor(UINT8 param1, UINT8 param2); + + inline void shortbranch(bool check); + inline void jmp(bool check); + int op_djnz(UINT8 param1, UINT8 param2); + int op_btjo(UINT8 param1, UINT8 param2); + int op_btjz(UINT8 param1, UINT8 param2); + + void am_a(op_func op); + void am_b(op_func op); + void am_r(op_func op); + void am_a2a(op_func op); + void am_a2b(op_func op); + void am_a2r(op_func op); + void am_a2p(op_func op); + void am_b2a(op_func op); + void am_b2b(op_func op); + void am_b2r(op_func op); + void am_b2p(op_func op); + void am_r2a(op_func op); + void am_r2b(op_func op); + void am_r2r(op_func op); + void am_i2a(op_func op); + void am_i2b(op_func op); + void am_i2r(op_func op); + void am_i2p(op_func op); + void am_p2a(op_func op); + void am_p2b(op_func op); +}; + + +class tms7020_device : public tms7000_device +{ +public: + tms7020_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +class tms7020_exl_device : public tms7000_device +{ +public: + tms7020_exl_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual void execute_one(UINT8 op); + +private: + void lvdp(); +}; + + +class tms7040_device : public tms7000_device +{ +public: + tms7040_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +class tms70c00_device : public tms7000_device +{ +public: + tms70c00_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +class tms70c20_device : public tms7000_device +{ +public: + tms70c20_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +class tms70c40_device : public tms7000_device +{ +public: + tms70c40_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +class tms70c46_device : public tms7000_device +{ +public: + tms70c46_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + DECLARE_READ8_MEMBER(control_r); + DECLARE_WRITE8_MEMBER(control_w); + + DECLARE_READ8_MEMBER(dockbus_status_r); + DECLARE_WRITE8_MEMBER(dockbus_status_w); + DECLARE_READ8_MEMBER(dockbus_data_r); + DECLARE_WRITE8_MEMBER(dockbus_data_w); + + // access I/O port E if databus is disabled + DECLARE_READ8_MEMBER(e_bus_data_r) { return (space.debugger_access()) ? 0xff : ((m_control & 0x20) ? 0xff : m_io->read_byte(TMS7000_PORTE)); } + DECLARE_WRITE8_MEMBER(e_bus_data_w) { if (~m_control & 0x20) m_io->write_byte(TMS7000_PORTE, data); } + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + +private: + UINT8 m_control; +}; + + +class tms7001_device : public tms7000_device +{ +public: + tms7001_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +class tms7041_device : public tms7000_device +{ +public: + tms7041_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +class tms7002_device : public tms7000_device +{ +public: + tms7002_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +class tms7042_device : public tms7000_device +{ +public: + tms7042_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +extern const device_type TMS7000; +extern const device_type TMS7020; +extern const device_type TMS7020_EXL; +extern const device_type TMS7040; +extern const device_type TMS70C00; +extern const device_type TMS70C20; +extern const device_type TMS70C40; +extern const device_type TMS70C46; +extern const device_type TMS7001; +extern const device_type TMS7041; +extern const device_type TMS7002; +extern const device_type TMS7042; + +#endif /* __TMS7000_H__ */ diff --git a/src/devices/cpu/tms7000/tms70op.inc b/src/devices/cpu/tms7000/tms70op.inc new file mode 100644 index 00000000000..f1aeef7be3c --- /dev/null +++ b/src/devices/cpu/tms7000/tms70op.inc @@ -0,0 +1,716 @@ +// license:BSD-3-Clause +// copyright-holders:hap, Tim Lindner + +// TMS7000 opcode handlers + +// addressing modes (not all opcodes have a write cycle) +#define WB_NO -1 +#define AM_WB(write_func, address, param1, param2) \ + int result = (this->*op)(param1, param2); \ + if (result > WB_NO) write_func(address, result) + +void tms7000_device::am_a(op_func op) +{ + m_icount -= 5; + AM_WB(write_r8, 0, read_r8(0), 0); +} + +void tms7000_device::am_b(op_func op) +{ + m_icount -= 5; + AM_WB(write_r8, 1, read_r8(1), 0); +} + +void tms7000_device::am_r(op_func op) +{ + m_icount -= 7; + UINT8 r = imm8(); + AM_WB(write_r8, r, read_r8(r), 0); +} + +void tms7000_device::am_a2a(op_func op) +{ + m_icount -= 6; + AM_WB(write_r8, 0, read_r8(0), read_r8(0)); +} + +void tms7000_device::am_a2b(op_func op) +{ + m_icount -= 6; + AM_WB(write_r8, 1, read_r8(1), read_r8(0)); +} + +void tms7000_device::am_a2p(op_func op) +{ + m_icount -= 10; + UINT8 r = imm8(); + AM_WB(write_p, r, read_p(r), read_r8(0)); +} + +void tms7000_device::am_a2r(op_func op) +{ + m_icount -= 8; + UINT8 r = imm8(); + AM_WB(write_r8, r, read_r8(r), read_r8(0)); +} + +void tms7000_device::am_b2a(op_func op) +{ + m_icount -= 5; + AM_WB(write_r8, 0, read_r8(0), read_r8(1)); +} + +void tms7000_device::am_b2b(op_func op) +{ + m_icount -= 6; + AM_WB(write_r8, 1, read_r8(1), read_r8(1)); +} + +void tms7000_device::am_b2r(op_func op) +{ + m_icount -= 7; + UINT8 r = imm8(); + AM_WB(write_r8, r, read_r8(r), read_r8(1)); +} + +void tms7000_device::am_b2p(op_func op) +{ + m_icount -= 9; + UINT8 r = imm8(); + AM_WB(write_p, r, read_p(r), read_r8(1)); +} + +void tms7000_device::am_r2a(op_func op) +{ + m_icount -= 8; + AM_WB(write_r8, 0, read_r8(0), read_r8(imm8())); +} + +void tms7000_device::am_r2b(op_func op) +{ + m_icount -= 8; + AM_WB(write_r8, 1, read_r8(1), read_r8(imm8())); +} + +void tms7000_device::am_r2r(op_func op) +{ + m_icount -= 10; + UINT8 param2 = read_r8(imm8()); + UINT8 r = imm8(); + AM_WB(write_r8, r, read_r8(r), param2); +} + +void tms7000_device::am_i2a(op_func op) +{ + m_icount -= 7; + AM_WB(write_r8, 0, read_r8(0), imm8()); +} + +void tms7000_device::am_i2b(op_func op) +{ + m_icount -= 7; + AM_WB(write_r8, 1, read_r8(1), imm8()); +} + +void tms7000_device::am_i2r(op_func op) +{ + m_icount -= 9; + UINT8 param2 = imm8(); + UINT8 r = imm8(); + AM_WB(write_r8, r, read_r8(r), param2); +} + +void tms7000_device::am_i2p(op_func op) +{ + m_icount -= 11; + UINT8 param2 = imm8(); + UINT8 r = imm8(); + AM_WB(write_p, r, read_p(r), param2); +} + +void tms7000_device::am_p2a(op_func op) +{ + m_icount -= 9; + AM_WB(write_r8, 0, read_r8(0), read_p(imm8())); +} + +void tms7000_device::am_p2b(op_func op) +{ + m_icount -= 8; + AM_WB(write_r8, 1, read_r8(1), read_p(imm8())); +} + + + +// common opcodes +// 1 param +int tms7000_device::op_clr(UINT8 param1, UINT8 param2) +{ + UINT8 t = 0; + SET_CNZ(t); + return t; +} + +int tms7000_device::op_dec(UINT8 param1, UINT8 param2) +{ + UINT16 t = param1 - 1; + SET_NZ(t); + SET_C(~t); + return t; +} + +int tms7000_device::op_inc(UINT8 param1, UINT8 param2) +{ + UINT16 t = param1 + 1; + SET_CNZ(t); + return t; +} + +int tms7000_device::op_inv(UINT8 param1, UINT8 param2) +{ + UINT8 t = ~param1; + SET_CNZ(t); + return t; +} + +int tms7000_device::op_rl(UINT8 param1, UINT8 param2) +{ + UINT16 t = param1 << 1 | param1 >> 7; + SET_CNZ(t); + return t; +} + +int tms7000_device::op_rlc(UINT8 param1, UINT8 param2) +{ + UINT16 t = param1 << 1 | GET_C(); + SET_CNZ(t); + return t; +} + +int tms7000_device::op_rr(UINT8 param1, UINT8 param2) +{ + UINT16 t = param1 >> 1 | param1 << 8 | (param1 << 7 & 0x80); + SET_CNZ(t); + return t; +} + +int tms7000_device::op_rrc(UINT8 param1, UINT8 param2) +{ + UINT16 t = param1 >> 1 | param1 << 8 | GET_C() << 7; + SET_CNZ(t); + return t; +} + +int tms7000_device::op_swap(UINT8 param1, UINT8 param2) +{ + m_icount -= 3; + UINT16 t = param1 >> 4 | param1 << 4; + SET_CNZ(t); + return t; +} + +int tms7000_device::op_xchb(UINT8 param1, UINT8 param2) +{ + m_icount -= 1; + UINT8 t = read_r8(1); + SET_CNZ(t); + write_r8(1, param1); + return t; +} + +// 2 params +int tms7000_device::op_adc(UINT8 param1, UINT8 param2) +{ + UINT16 t = param1 + param2 + GET_C(); + SET_CNZ(t); + return t; +} + +int tms7000_device::op_add(UINT8 param1, UINT8 param2) +{ + UINT16 t = param1 + param2; + SET_CNZ(t); + return t; +} + +int tms7000_device::op_and(UINT8 param1, UINT8 param2) +{ + UINT8 t = param1 & param2; + SET_CNZ(t); + return t; +} + +int tms7000_device::op_cmp(UINT8 param1, UINT8 param2) +{ + UINT16 t = param1 - param2; + SET_NZ(t); + SET_C(~t); + return WB_NO; +} + +int tms7000_device::op_mpy(UINT8 param1, UINT8 param2) +{ + m_icount -= 39; + UINT16 t = param1 * param2; + SET_CNZ(t >> 8 & 0xff); + write_mem16(0, t); // always writes result to regs A-B + return WB_NO; +} + +int tms7000_device::op_mov(UINT8 param1, UINT8 param2) +{ + UINT8 t = param2; + SET_CNZ(t); + return t; +} + +int tms7000_device::op_or(UINT8 param1, UINT8 param2) +{ + UINT8 t = param1 | param2; + SET_CNZ(t); + return t; +} + +int tms7000_device::op_sbb(UINT8 param1, UINT8 param2) +{ + UINT16 t = param1 - param2 - (!GET_C()); + SET_NZ(t); + SET_C(~t); + return t; +} + +int tms7000_device::op_sub(UINT8 param1, UINT8 param2) +{ + UINT16 t = param1 - param2; + SET_NZ(t); + SET_C(~t); + return t; +} + +int tms7000_device::op_xor(UINT8 param1, UINT8 param2) +{ + UINT8 t = param1 ^ param2; + SET_CNZ(t); + return t; +} + +// BCD arthrimetic handling +static const UINT8 lut_bcd_out[6] = { 0x00, 0x06, 0x00, 0x66, 0x60, 0x66 }; + +int tms7000_device::op_dac(UINT8 param1, UINT8 param2) +{ + m_icount -= 2; + int c = GET_C(); + + UINT8 h1 = param1 >> 4 & 0xf; + UINT8 l1 = param1 >> 0 & 0xf; + UINT8 h2 = param2 >> 4 & 0xf; + UINT8 l2 = param2 >> 0 & 0xf; + + // compute bcd constant + UINT8 d = ((l1 + l2 + c) < 10) ? 0 : 1; + if ((h1 + h2) == 9) + d |= 2; + else if ((h1 + h2) > 9) + d |= 4; + + UINT8 t = param1 + param2 + c + lut_bcd_out[d]; + SET_CNZ(t); + if (d > 2) + m_sr |= SR_C; + + return t; +} + +int tms7000_device::op_dsb(UINT8 param1, UINT8 param2) +{ + m_icount -= 2; + int c = !GET_C(); + + UINT8 h1 = param1 >> 4 & 0xf; + UINT8 l1 = param1 >> 0 & 0xf; + UINT8 h2 = param2 >> 4 & 0xf; + UINT8 l2 = param2 >> 0 & 0xf; + + // compute bcd constant + UINT8 d = ((l1 - c) >= l2) ? 0 : 1; + if (h1 == h2) + d |= 2; + else if (h1 < h2) + d |= 4; + + UINT8 t = param1 - param2 - c - lut_bcd_out[d]; + SET_CNZ(t); + if (d <= 2) + m_sr |= SR_C; + + return t; +} + +// branches +inline void tms7000_device::shortbranch(bool check) +{ + m_icount -= 2; + INT8 d = (INT8)imm8(); + + if (check) + { + m_pc += d; + m_icount -= 2; + } +} + +inline void tms7000_device::jmp(bool check) +{ + m_icount -= 3; + shortbranch(check); +} + +int tms7000_device::op_djnz(UINT8 param1, UINT8 param2) +{ + UINT16 t = param1 - 1; + shortbranch(t != 0); + return t; +} + +int tms7000_device::op_btjo(UINT8 param1, UINT8 param2) +{ + UINT8 t = param1 & param2; + SET_CNZ(t); + shortbranch(t != 0); + return WB_NO; +} + +int tms7000_device::op_btjz(UINT8 param1, UINT8 param2) +{ + UINT8 t = ~param1 & param2; + SET_CNZ(t); + shortbranch(t != 0); + return WB_NO; +} + + + +// other opcodes +// dec double +void tms7000_device::decd_a() +{ + m_icount -= 9; + UINT32 t = read_r16(0) - 1; + write_r16(0, t); + SET_NZ(t >> 8); + SET_C(~(t >> 8)); +} + +void tms7000_device::decd_b() +{ + m_icount -= 9; + UINT32 t = read_r16(1) - 1; + write_r16(1, t); + SET_NZ(t >> 8); + SET_C(~(t >> 8)); +} + +void tms7000_device::decd_r() +{ + m_icount -= 11; + UINT8 r = imm8(); + UINT32 t = read_r16(r) - 1; + write_r16(r, t); + SET_NZ(t >> 8); + SET_C(~(t >> 8)); +} + +// cmpa extended +void tms7000_device::cmpa_dir() +{ + m_icount -= 12; + UINT16 t = read_r8(0) - read_mem8(imm16()); + SET_NZ(t); + SET_C(~t); +} + +void tms7000_device::cmpa_inx() +{ + m_icount -= 14; + UINT16 t = read_r8(0) - read_mem8(imm16() + read_r8(1)); + SET_NZ(t); + SET_C(~t); +} + +void tms7000_device::cmpa_ind() +{ + m_icount -= 11; + UINT16 t = read_r8(0) - read_mem8(read_r16(imm8())); + SET_NZ(t); + SET_C(~t); +} + +// lda extended +void tms7000_device::lda_dir() +{ + m_icount -= 11; + UINT8 t = read_mem8(imm16()); + write_r8(0, t); + SET_CNZ(t); +} + +void tms7000_device::lda_inx() +{ + m_icount -= 13; + UINT8 t = read_mem8(imm16() + read_r8(1)); + write_r8(0, t); + SET_CNZ(t); +} + +void tms7000_device::lda_ind() +{ + m_icount -= 10; + UINT8 t = read_mem8(read_r16(imm8())); + write_r8(0, t); + SET_CNZ(t); +} + +// sta extended +void tms7000_device::sta_dir() +{ + m_icount -= 11; + UINT8 t = read_r8(0); + write_mem8(imm16(), t); + SET_CNZ(t); +} + +void tms7000_device::sta_inx() +{ + m_icount -= 13; + UINT8 t = read_r8(0); + write_mem8(imm16() + read_r8(1), t); + SET_CNZ(t); +} + +void tms7000_device::sta_ind() +{ + m_icount -= 10; + UINT8 t = read_r8(0); + write_mem8(read_r16(imm8()), t); + SET_CNZ(t); +} + +// mov double +void tms7000_device::movd_dir() +{ + m_icount -= 15; + UINT16 t = imm16(); + write_r16(imm8(), t); + SET_CNZ(t >> 8 & 0xff); +} + +void tms7000_device::movd_inx() +{ + m_icount -= 17; + UINT16 t = imm16() + read_r8(1); + write_r16(imm8(), t); + SET_CNZ(t >> 8 & 0xff); +} + +void tms7000_device::movd_ind() +{ + m_icount -= 14; + UINT16 t = read_r16(imm8()); + write_r16(imm8(), t); + SET_CNZ(t >> 8 & 0xff); +} + +// long branch +void tms7000_device::br_dir() +{ + m_icount -= 10; + m_pc = imm16(); +} + +void tms7000_device::br_inx() +{ + m_icount -= 12; + m_pc = imm16() + read_r8(1); +} + +void tms7000_device::br_ind() +{ + m_icount -= 9; + m_pc = read_r16(imm8()); +} + +// call/return +void tms7000_device::call_dir() +{ + m_icount -= 14; + UINT16 t = imm16(); + push16(m_pc); + m_pc = t; +} + +void tms7000_device::call_inx() +{ + m_icount -= 16; + UINT16 t = imm16() + read_r8(1); + push16(m_pc); + m_pc = t; +} + +void tms7000_device::call_ind() +{ + m_icount -= 13; + UINT16 t = read_r16(imm8()); + push16(m_pc); + m_pc = t; +} + +void tms7000_device::trap(UINT8 address) +{ + m_icount -= 14; + push16(m_pc); + m_pc = read_mem16(0xff00 | address); +} + +void tms7000_device::reti() +{ + m_icount -= 9; + m_pc = pull16(); + m_sr = pull8() & 0xf0; + check_interrupts(); +} + +void tms7000_device::rets() +{ + m_icount -= 7; + m_pc = pull16(); +} + +// pop +void tms7000_device::pop_a() +{ + m_icount -= 6; + UINT8 t = pull8(); + write_r8(0, t); + SET_CNZ(t); +} + +void tms7000_device::pop_b() +{ + m_icount -= 6; + UINT8 t = pull8(); + write_r8(1, t); + SET_CNZ(t); +} + +void tms7000_device::pop_r() +{ + m_icount -= 8; + UINT8 t = pull8(); + write_r8(imm8(), t); + SET_CNZ(t); +} + +void tms7000_device::pop_st() +{ + m_icount -= 6; + m_sr = pull8() & 0xf0; + check_interrupts(); +} + +// push +void tms7000_device::push_a() +{ + m_icount -= 6; + UINT8 t = read_r8(0); + push8(t); + SET_CNZ(t); +} + +void tms7000_device::push_b() +{ + m_icount -= 6; + UINT8 t = read_r8(1); + push8(t); + SET_CNZ(t); +} + +void tms7000_device::push_r() +{ + m_icount -= 8; + UINT8 t = read_r8(imm8()); + push8(t); + SET_CNZ(t); +} + +void tms7000_device::push_st() +{ + m_icount -= 6; + push8(m_sr); +} + +// other +void tms7000_device::nop() +{ + m_icount -= 5; +} + +void tms7000_device::idle() +{ + m_icount -= 6; + m_pc--; + m_idle_state = true; +} + +void tms7000_device::dint() +{ + m_icount -= 5; + m_sr &= ~(SR_N | SR_Z | SR_C | SR_I); +} + +void tms7000_device::eint() +{ + m_icount -= 5; + m_sr |= (SR_N | SR_Z | SR_C | SR_I); + check_interrupts(); +} + +void tms7000_device::ldsp() +{ + m_icount -= 5; + m_sp = read_r8(1); +} + +void tms7000_device::stsp() +{ + m_icount -= 6; + write_r8(1, m_sp); +} + +void tms7000_device::setc() +{ + m_icount -= 5; + m_sr = (m_sr & ~SR_N) | SR_C | SR_Z; +} + +// not standard +void tms7020_exl_device::lvdp() +{ + /* on EXL100, opcode D7 ?? (SWAP R) was changed to LVDP, mostly equivalent to: + * MOVP P40,xx + * MOVP P36,A + */ + m_icount -= 10; // TODO: check real timing + imm8(); // always 0x28? discarded? + read_p(0x28); + UINT8 t = read_p(0x24); + write_r8(0, t); + SET_CNZ(t); +} + +// illegal opcode handling +void tms7000_device::illegal(UINT8 op) +{ + m_icount -= 5; // guessed + logerror("%s: illegal opcode $%02X @ $%04x\n", tag(), op, m_pc); +} diff --git a/src/devices/cpu/tms9900/9900dasm.c b/src/devices/cpu/tms9900/9900dasm.c new file mode 100644 index 00000000000..7b3153e6c4c --- /dev/null +++ b/src/devices/cpu/tms9900/9900dasm.c @@ -0,0 +1,812 @@ +// license:BSD-3-Clause +// copyright-holders:Raphael Nabet +/***************************************************************************** + * + * 9900dasm.c + * TMS 9900 family disassembler + * + * Copyright Raphael Nabet + * Based on previous work Copyright John Butler. + * Based on 6502dasm.c 6502/65c02/6510 disassembler by Juergen Buchmueller + * + * - This source code is released as freeware for non-commercial purposes. + * - You are free to use and redistribute this code in modified or + * unmodified form, provided you list me in the credits. + * - If you modify this source code, you must add a notice to each modified + * source file that it has been changed. If you're a nice person, you + * will clearly mark each change too. :) + * - The author of this copywritten work reserves the right to change the + * terms of its usage and license at any time, including retroactively + * - This entire notice must remain in the source code. + * + *****************************************************************************/ + + +#include "emu.h" +#include "debugger.h" +#include "tms9900.h" + +#define MASK 0x0000ffff +#define BITS(val,n1,n2) ((val>>(15-(n2))) & (MASK>>(15-((n2)-(n1))))) + +enum format_t +{ + format_1, /* 2 address instructions */ + format_2a, /* jump instructions */ + format_2b, /* bit I/O instructions */ + format_3_9, /* logical, multiply, and divide instructions */ + format_4, /* CRU instructions */ + format_5, /* register shift instructions */ + format_6, /* single address instructions */ + format_7, /* instructions without operands */ + format_8a, /* immediate instructions (destination register) */ + format_8b, /* immediate instructions (no destination register) */ + format_9, /* extended operation instruction */ + format_10, /* memory map file instruction */ + format_11, /* multiple precision instructions */ + format_12, /* string instructions */ + format_13, /* multiple precision shift instructions */ + format_14, /* bit testing instructions */ + format_15, /* invert order of field instruction */ + format_16, /* field instructions */ + format_17, /* alter register and jump instructions */ + format_18, /* single register operand instructions */ + format_liim,/* format for liim (looks like format 18) */ + format_19, /* move address instruction */ + format_20, /* list search instructions */ + format_21, /* extend precision instruction */ + + illegal +}; + +/* definitions for flags */ +enum +{ + /* processor set on which opcodes are available */ + ps_any = 0x01, /* every processor in the tms9900/ti990 family */ + ps_mapper = 0x02, /* processors with memory mapper (ti990/10, ti990/12, + and tms99000 with mapper coprocessor) */ + ps_tms9995 = 0x04, /* ti990/12, tms9995, and later */ + ps_tms99000 = 0x08, /* ti990/12, tms99000, and later */ + ps_ti990_12 = 0x10, /* ti990/12 only */ + + /* additional flags for special decoding */ + sd_11 = 0x100, /* bit 11 should be cleared in li, ai, andi, ori, ci, stwp, stst */ + sd_11_15 = 0x200 /* bits 11-15 should be cleared in lwpi, limi, idle, rset, rtwp, ckon, ckof, lrex */ +}; + +struct description_t +{ + const char *mnemonic; + format_t format; + int flags; +}; + + +enum opcodes { + /* basic instruction set */ + _a=0, _ab, _c, _cb, _s, _sb, _soc, _socb, _szc, _szcb, + _mov, _movb, _coc, _czc, _xor, _mpy, _div, _xop, _b, _bl, + _blwp, _clr, _seto, _inv, _neg, _abs, _swpb, _inc, _inct, _dec, + _dect, _x, _ldcr, _stcr, _sbo, _sbz, _tb, _jeq, _jgt, _jh, + _jhe, _jl, _jle, _jlt, _jmp, _jnc, _jne, _jno, _joc, _jop, + _sla, _sra, _src, _srl, _ai, _andi, _ci, _li, _ori, _lwpi, + _limi, _stst, _stwp, _rtwp, _idle, _rset, _ckof, _ckon, _lrex, + + /* mapper instruction set */ + _lds, _ldd, _lmf, + + /* tms9995 instruction set */ + _divs, _mpys, _lst, _lwp, + + /* tms99000 instruction set */ + _bind, + + /* ti990/12 instruction set */ + _sram, _slam, _rto, _lto, _cnto, _slsl, _slsp, _bdc, _dbc, _swpm, + _xorm, _orm, _andm, _sm, _am, _mova, _emd, _eint, _dint, _stpc, + _cs, _seqb, _movs, _lim, _lcs, _blsk, _mvsr, _mvsk, _pops, _pshs, + + _cri, _cdi, _negr, _negd, _cre, _cde, _cer, _ced, _nrm, _tmb, + _tcmb, _tsmb, _srj, _arj, _xit, _insf, _xv, _xf, _ar, _cir, + _sr, _mr, _dr, _lr, _str, _iof, _sneb, _crc, _ts, _ad, + _cid, _sd, _md, _dd, _ld, _std, _ep, + + /* tms9940-only instruction set */ + _liim, _dca, _dcs, + + _ill +}; + + +static const description_t descriptions[144+3+1] = +{ + /* basic instruction set */ + { "a", format_1, ps_any }, { "ab", format_1, ps_any }, + { "c", format_1, ps_any }, { "cb", format_1, ps_any }, + { "s", format_1, ps_any }, { "sb", format_1, ps_any }, + { "soc", format_1, ps_any }, { "socb", format_1, ps_any }, + { "szc", format_1, ps_any }, { "szcb", format_1, ps_any }, + { "mov", format_1, ps_any }, { "movb", format_1, ps_any }, + { "coc", format_3_9, ps_any }, { "czc", format_3_9, ps_any }, + { "xor", format_3_9, ps_any }, { "mpy", format_3_9, ps_any }, + { "div", format_3_9, ps_any }, { "xop", format_9, ps_any }, + { "b", format_6, ps_any }, { "bl", format_6, ps_any }, + { "blwp", format_6, ps_any }, { "clr", format_6, ps_any }, + { "seto", format_6, ps_any }, { "inv", format_6, ps_any }, + { "neg", format_6, ps_any }, { "abs", format_6, ps_any }, + { "swpb", format_6, ps_any }, { "inc", format_6, ps_any }, + { "inct", format_6, ps_any }, { "dec", format_6, ps_any }, + { "dect", format_6, ps_any }, { "x", format_6, ps_any }, + { "ldcr", format_4, ps_any }, { "stcr", format_4, ps_any }, + { "sbo", format_2b, ps_any }, { "sbz", format_2b, ps_any }, + { "tb", format_2b, ps_any }, { "jeq", format_2a, ps_any }, + { "jgt", format_2a, ps_any }, { "jh", format_2a, ps_any }, + { "jhe", format_2a, ps_any }, { "jl", format_2a, ps_any }, + { "jle", format_2a, ps_any }, { "jlt", format_2a, ps_any }, + { "jmp", format_2a, ps_any }, { "jnc", format_2a, ps_any }, + { "jne", format_2a, ps_any }, { "jno", format_2a, ps_any }, + { "joc", format_2a, ps_any }, { "jop", format_2a, ps_any }, + { "sla", format_5, ps_any }, { "sra", format_5, ps_any }, + { "src", format_5, ps_any }, { "srl", format_5, ps_any }, + { "ai", format_8a, ps_any|sd_11 }, { "andi", format_8a, ps_any|sd_11 }, + { "ci", format_8a, ps_any|sd_11 }, { "li", format_8a, ps_any|sd_11 }, + { "ori", format_8a, ps_any|sd_11 }, { "lwpi", format_8b, ps_any|sd_11|sd_11_15 }, + { "limi", format_8b, ps_any|sd_11|sd_11_15 }, { "stst", format_18, ps_any|sd_11 }, + { "stwp", format_18, ps_any|sd_11 }, { "rtwp", format_7, ps_any|sd_11|sd_11_15 }, + { "idle", format_7, ps_any|sd_11|sd_11_15 }, { "rset", format_7, ps_any|sd_11|sd_11_15 }, + { "ckof", format_7, ps_any|sd_11|sd_11_15 }, { "ckon", format_7, ps_any|sd_11|sd_11_15 }, + { "lrex", format_7, ps_any|sd_11|sd_11_15 }, + + /* mapper instruction set */ + { "lds", format_6, ps_mapper }, { "ldd", format_6, ps_mapper }, + { "lmf", format_10, ps_mapper }, + + /* tms9995 instruction set */ + { "divs", format_6, ps_tms9995 }, { "mpys", format_6, ps_tms9995 }, + { "lst", format_18, ps_tms9995 }, { "lwp", format_18, ps_tms9995 }, + + /* tms99000 instruction set */ + { "bind", format_6, ps_tms99000 }, + + /* ti990/12 instruction set */ + { "sram", format_13, ps_ti990_12 }, { "slam", format_13, ps_ti990_12 }, + { "rto", format_11, ps_ti990_12 }, { "lto", format_11, ps_ti990_12 }, + { "cnto", format_11, ps_ti990_12 }, { "slsl", format_20, ps_ti990_12 }, + { "slsp", format_20, ps_ti990_12 }, { "bdc", format_11, ps_ti990_12 }, + { "dbc", format_11, ps_ti990_12 }, { "swpm", format_11, ps_ti990_12 }, + { "xorm", format_11, ps_ti990_12 }, { "orm", format_11, ps_ti990_12 }, + { "andm", format_11, ps_ti990_12 }, { "sm", format_11, ps_ti990_12 }, + { "am", format_11, ps_ti990_12 }, { "mova", format_19, ps_ti990_12 }, + { "emd", format_7, ps_ti990_12 }, { "eint", format_7, ps_ti990_12 }, + { "dint", format_7, ps_ti990_12 }, { "stpc", format_18, ps_ti990_12 }, + { "cs", format_12, ps_ti990_12 }, { "seqb", format_12, ps_ti990_12 }, + { "movs", format_12, ps_ti990_12 }, { "lim", format_18, ps_ti990_12 }, + { "lcs", format_18, ps_ti990_12 }, { "blsk", format_8a, ps_ti990_12 }, + { "mvsr", format_12, ps_ti990_12 }, { "mvsk", format_12, ps_ti990_12 }, + { "pops", format_12, ps_ti990_12 }, { "pshs", format_12, ps_ti990_12 }, + { "cri", format_7, ps_ti990_12 }, { "cdi", format_7, ps_ti990_12 }, + { "negr", format_7, ps_ti990_12 }, { "negd", format_7, ps_ti990_12 }, + { "cre", format_7, ps_ti990_12 }, { "cde", format_7, ps_ti990_12 }, + { "cer", format_7, ps_ti990_12 }, { "ced", format_7, ps_ti990_12 }, + { "nrm", format_11, ps_ti990_12 }, { "tmb", format_14, ps_ti990_12 }, + { "tcmb", format_14, ps_ti990_12 }, { "tsmb", format_14, ps_ti990_12 }, + { "srj", format_17, ps_ti990_12 }, { "arj", format_17, ps_ti990_12 }, + { "xit", format_7, ps_ti990_12 }, { "insf", format_16, ps_ti990_12 }, + { "xv", format_16, ps_ti990_12 }, { "xf", format_16, ps_ti990_12 }, + { "ar", format_6, ps_ti990_12 }, { "cir", format_6, ps_ti990_12 }, + { "sr", format_6, ps_ti990_12 }, { "mr", format_6, ps_ti990_12 }, + { "dr", format_6, ps_ti990_12 }, { "lr", format_6, ps_ti990_12 }, + { "str", format_6, ps_ti990_12 }, { "iof", format_15, ps_ti990_12 }, + { "sneb", format_12, ps_ti990_12 }, { "crc", format_12, ps_ti990_12 }, + { "ts", format_12, ps_ti990_12 }, { "ad", format_6, ps_ti990_12 }, + { "cid", format_6, ps_ti990_12 }, { "sd", format_6, ps_ti990_12 }, + { "md", format_6, ps_ti990_12 }, { "dd", format_6, ps_ti990_12 }, + { "ld", format_6, ps_ti990_12 }, { "std", format_6, ps_ti990_12 }, + { "ep", format_21, ps_ti990_12 }, + + /* tms9940-only instruction set */ + /* these instructions are said to be format 9 (xop), but since the xop + level is interpreted as part of the opcode, dca and dcs should be handled + like format 6. liim looks like format 18, but slightly different, + therefore it is handled like a special format. */ + { "liim", format_liim,/*ps_tms9940*/0 }, { "dca", format_6, /*ps_tms9940*/0 }, + { "dcs", format_6, /*ps_tms9940*/0 }, + + { NULL, illegal, ps_any } +}; + + +static const enum opcodes ops_4000_ffff_s12[12]= +{ + _szc, _szcb, _s, _sb, /*4000-7000*/ + _c, _cb, _a, _ab, _mov, _movb, _soc, _socb /*8000-f000*/ +}; + + +static const enum opcodes ops_2000_3fff_s10[8]= +{ + _coc, _czc, _xor, _xop, _ldcr, _stcr, _mpy, _div /*2000-3800*/ +}; + + +static const enum opcodes ops_1000_1fff_s8[16]= +{ + _jmp, _jlt, _jle, _jeq, _jhe, _jgt, _jne, _jnc, /*1000-1700*/ + _joc, _jno, _jl, _jh, _jop, _sbo, _sbz, _tb /*1800-1f00*/ +}; + + +static const enum opcodes ops_0e40_0fff_s6[7]= +{ + _ad, _cid, _sd, _md, _dd, _ld, _std /*0e40-0fc0*/ +}; + + +static const enum opcodes ops_0e00_0e3f_s4[4]= +{ + _iof, _sneb, _crc, _ts /*0e00-0e30*/ +}; + + +static const enum opcodes ops_0c40_0dff_s6[7]= +{ + _ar, _cir, _sr, _mr, _dr, _lr, _str /*0c40-0dc0*/ +}; + + +static const enum opcodes ops_0c10_0c3f_s4[3]= +{ + _insf, _xv, _xf /*0c10-0c30*/ +}; + + +static const enum opcodes ops_0c00_0c0f_s0[16]= +{ + _cri, _cdi, _negr, _negd, _cre, _cde, _cer, _ced, /*0c00-0c07*/ + _nrm, _tmb, _tcmb, _tsmb, _srj, _arj, _xit, _xit /*0c08-0c0f*/ +}; + + + +static const enum opcodes ops_0800_0bff_s8[4]= +{ + _sra, _srl, _sla, _src /*0800-0b00*/ +}; + + +static const enum opcodes ops_0400_07ff_s6[16]= +{ + _blwp, _b, _x, _clr, _neg, _inv, _inc, _inct, /*0400-05c0*/ + _dec, _dect, _bl, _swpb, _seto, _abs, _lds, _ldd /*0600-07c0*/ +}; + + +static const enum opcodes ops_0200_03ff_s5[16]= +{ + _li, _ai, _andi, _ori, _ci, _stwp, _stst, _lwpi, /*0200-02e0*/ + _limi, _lmf, _idle, _rset, _rtwp, _ckon, _ckof, _lrex /*0300-03e0*/ +}; + + +static const enum opcodes ops_0100_01ff_s6[4]= +{ + _ill, _bind, _divs, _mpys /*0100-01c0*/ +}; + + +static const enum opcodes ops_0030_00ff_s4[13]= +{ + _stpc, _cs, _seqb, _movs, _lim, /*0030-0070*/ + _lst, _lwp, _lcs, _blsk, _mvsr, _mvsk, _pops, _pshs /*0080-00f0*/ +}; + + +static const enum opcodes ops_001c_002f_s0[20]= +{ + _sram, _slam, _rto, _lto, /*001c-001f*/ + _cnto, _slsl, _slsp, _bdc, _dbc, _swpm, _xorm, _orm, /*0020-0027*/ + _andm, _sm, _am, _mova, _ill, _emd, _eint, _dint /*0028-002f*/ +}; + + + +static int PC; + + +INLINE UINT16 readop_arg(const UINT8 *opram, unsigned pc) +{ + UINT16 result = opram[PC++ - pc] << 8; + return result | opram[PC++ - pc]; +} + +static int print_arg (char *dest, int mode, int arg, const UINT8 *opram, unsigned pc) +{ + int base; + + switch (mode) + { + case 0x0: /* workspace register */ + return sprintf (dest, "R%d", arg); + case 0x1: /* workspace register indirect */ + return sprintf (dest, "*R%d", arg); + case 0x2: /* symbolic|indexed */ + base = readop_arg(opram, pc); + if (arg) /* indexed */ + return sprintf (dest, "@>%04x(R%d)", base, arg); + else /* symbolic (direct) */ + return sprintf (dest, "@>%04x", base); + case 0x3: /* workspace register indirect auto increment */ + return sprintf (dest, "*R%d+", arg); + } + + return 0; +} + + +/***************************************************************************** + * Disassemble a single command and return the number of bytes it uses. + *****************************************************************************/ +unsigned Dasm9900 (char *buffer, unsigned pc, int model_id, const UINT8 *oprom, const UINT8 *opram) +{ + int OP, OP2, opc; + int sarg, darg, smode, dmode; + signed char displacement; + int byte_count, checkpoint; + int bit_position, bit_width; + unsigned dasmflags = 0; + + const char *mnemonic; + format_t format; + int flags; + + /* + Under tms9900, opcodes >0400->07FF are incompletely decoded: bits 11 is ignored, and so are + bits 12-15 for instructions which do not require a register. On the other hand, ti990/10 + generates an illegal instruction error when bit 11 is set, but still ignores bits 12-15. + Additionally, ti990/12 and tms9995 will generate an illegal error when bits 12-15 are + non-zero. + */ + #define BETTER_0200_DECODING (model_id == TI990_10_ID) + #define COMPLETE_0200_DECODING (/*(model_id == TI990_12_ID) ||*/ (model_id >= TMS9995_ID)) + + int processor_mask = ps_any; + + if ((model_id == TI990_10_ID) /*|| (model_id == TI990_12_ID)*/ || (model_id >= TMS99000_ID)) + processor_mask |= ps_mapper; /* processors with memory mapper (ti990/10, ti990/12, + and tms99000 with mapper coprocessor) */ + if (/*(model_id == TI990_12_ID) ||*/ (model_id >= TMS9995_ID)) + processor_mask |= ps_tms9995; /* ti990/12, tms9995, and later */ + + if (/*(model_id == TI990_12_ID) ||*/ (model_id >= TMS99000_ID)) + processor_mask |= ps_tms99000; /* ti990/12, tms99000, and later */ + + /*if ((model_id == TI990_12_ID)) + processor_mask |= ps_ti990_12;*/ /* ti990/12, tms99000, and later */ + + PC = pc; + OP = oprom[PC++ - pc] << 8; + OP |= oprom[PC++ - pc]; + + /* let's identify the opcode */ + if (OP >= 0x4000) + opc = ops_4000_ffff_s12[(OP - 0x4000) >> 12]; + else if (OP >= 0x2000) + opc = ops_2000_3fff_s10[(OP - 0x2000) >> 10]; + else if (OP >= 0x1000) + opc = ops_1000_1fff_s8[(OP - 0x1000) >> 8]; + else if (OP >= 0x0C00) + { + if (OP >= 0x0E40) + opc = ops_0e40_0fff_s6[(OP - 0x0E40) >> 6]; + else if (OP >= 0x0E00) + opc = ops_0e00_0e3f_s4[(OP - 0x0E00) >> 4]; + else if (OP >= 0x0C40) + opc = ops_0c40_0dff_s6[(OP - 0x0C40) >> 6]; + else if (OP >= 0x0C10) + opc = ops_0c10_0c3f_s4[(OP - 0x0C10) >> 4]; + else + opc = ops_0c00_0c0f_s0[OP - 0x0C00]; + } + else if (OP >= 0x0800) + opc = ops_0800_0bff_s8[(OP - 0x0800) >> 8]; + else if (OP >= 0x0400) + opc = ops_0400_07ff_s6[(OP - 0x0400) >> 6]; + else if (OP >= 0x0200) + { + opc = ops_0200_03ff_s5[(OP - 0x0200) >> 5]; + if (BETTER_0200_DECODING || COMPLETE_0200_DECODING) + { + flags = descriptions[opc].flags; + if ( (COMPLETE_0200_DECODING && (flags & sd_11_15) && (OP & 0x001f)) + || ((flags & sd_11) && (OP & 0x0010)) ) + { + opc = _ill; + if (OP >= 0x03f0) + opc = _ep; /* the ep opcode is located in a "hole" */ + } + } + } + else if (OP >= 0x0100) + opc = ops_0100_01ff_s6[(OP - 0x0100) >> 6]; + else if (OP >= 0x0030) + opc = ops_0030_00ff_s4[(OP - 0x0030) >> 4]; + else if (OP >= 0x001C) + opc = ops_001c_002f_s0[OP - 0x001C]; + else + opc = _ill; + + /* read flags */ + flags = descriptions[opc].flags; + /* set as illegal if the processor does not implement this instruction */ + if (! (flags & processor_mask)) + { + opc = _ill; + flags = descriptions[opc].flags; /* read new flags */ + } + + /* tms9940 replace a few xops with custom instructions */ + if ((opc == _xop) && ((model_id == TMS9940_ID) || (model_id == TMS9985_ID))) + { + switch (BITS(OP,6,9)) + { + case 0: + /* opcode is dca */ + opc = _dca; + break; + + case 1: + /* opcode is dcs */ + opc = _dcs; + break; + + case 2: + case 3: /* should be 2, but instruction decoding is incomplete */ + /* opcode is liim */ + if (BITS(OP,12,15) == 0) + /* ts must be == 0 */ + opc = _liim; + else + /* I don't know what happens when ts != 0. Maybe the CPU does + the complete address decoding, and liim gets a bogus value + instead of the immediate. Since I do not know, I handle this + as an illegal instruction. */ + opc = _ill; + break; + + default: + /* this is still a software xop */ + break; + } + } + + mnemonic = descriptions[opc].mnemonic; + format = descriptions[opc].format; + + /* bl and blwp instructions are subroutines */ + if (mnemonic != NULL && mnemonic[0] == 'b' && mnemonic[1] == 'l') + dasmflags = DASMFLAG_STEP_OVER; + + /* b *r11 and rtwp are returns */ + else if (opc == 0x045b || (mnemonic != NULL && strcmp(mnemonic, "rtwp") == 0)) + dasmflags = DASMFLAG_STEP_OUT; + + switch (format) + { + case format_1: /* 2 address instructions */ + smode = BITS(OP,10,11); + sarg = BITS(OP,12,15); + dmode = BITS(OP,4,5); + darg = BITS(OP,6,9); + + buffer += sprintf (buffer, "%-4s ", mnemonic); + buffer += print_arg (buffer, smode, sarg, opram, pc); + buffer += sprintf (buffer, ","); + buffer += print_arg (buffer, dmode, darg, opram, pc); + break; + + case format_2a: /* jump instructions */ + displacement = (signed char)BITS(OP,8,15); + sprintf (buffer, "%-4s >%04x", mnemonic, 0xffff & (PC + displacement * 2)); + break; + + case format_2b: /* bit I/O instructions */ + displacement = (signed char)BITS(OP,8,15); + sprintf (buffer, "%-4s >%04x", mnemonic, 0xffff & displacement); + break; + + case format_3_9: /* logical, multiply, and divide instructions */ + case format_4: /* CRU instructions */ + case format_9: /* extended operation instruction */ + smode = BITS(OP,10,11); + sarg = BITS(OP,12,15); + darg = BITS(OP,6,9); + + if ((darg == 0) && (format == format_4)) + darg = 16; + + if (format == format_3_9) + { + buffer += sprintf (buffer, "%-4s ", mnemonic); + buffer += print_arg (buffer, smode, sarg, opram, pc); + buffer += sprintf (buffer, ",R%d", darg); + } + else + { + buffer += sprintf (buffer, "%-4s ", mnemonic); + buffer += print_arg (buffer, smode, sarg, opram, pc); + buffer += sprintf (buffer, ",%d", darg); + } + break; + + case format_5: /* register shift instructions */ + sarg = BITS(OP,12,15); + darg = BITS(OP,8,11); + + sprintf (buffer, darg ? "%-4s R%d,%d" : "%-4s R%d,R%d", mnemonic, sarg, darg); + break; + + case format_6: /* single address instructions */ + smode = BITS(OP,10,11); + sarg = BITS(OP,12,15); + + buffer += sprintf (buffer, "%-4s ", mnemonic); + buffer += print_arg (buffer, smode, sarg, opram, pc); + break; + + case format_7: /* instructions without operands */ + sprintf (buffer, "%s", mnemonic); + break; + + case format_8a: /* immediate instructions (destination register) */ + darg = BITS(OP,12,15); + sarg = readop_arg(opram, pc); + + sprintf (buffer, "%-4s R%d,>%04x", mnemonic, darg, sarg); + break; + + case format_8b: /* immediate instructions (no destination register) */ + sarg = readop_arg(opram, pc); + + sprintf (buffer, "%-4s >%04x", mnemonic, sarg); + break; + + case format_10: /* memory map file instruction */ + sarg = BITS(OP,12,15); + darg = BITS(OP,11,11); + + sprintf (buffer, "%-4s R%d,%d", mnemonic, sarg, darg); + break; + + case format_11: /* multiple precision instructions */ + OP2 = readop_arg(opram, pc); + + smode = BITS(OP2,10,11); + sarg = BITS(OP2,12,15); + dmode = BITS(OP2,4,5); + darg = BITS(OP2,6,9); + byte_count = BITS(OP2,0,3); + + buffer += sprintf (buffer, "%-4s ", mnemonic); + buffer += print_arg (buffer, smode, sarg, opram, pc); + buffer += sprintf (buffer, ","); + buffer += print_arg (buffer, dmode, darg, opram, pc); + buffer += sprintf (buffer, byte_count ? ",%d" : ",R%d", byte_count); + break; + + case format_12: /* string instructions */ + OP2 = readop_arg(opram, pc); + + smode = BITS(OP2,10,11); + sarg = BITS(OP2,12,15); + dmode = BITS(OP2,4,5); + darg = BITS(OP2,6,9); + byte_count = BITS(OP2,0,3); + checkpoint = BITS(OP,12,15); + + buffer += sprintf (buffer, "%-4s ", mnemonic); + buffer += print_arg (buffer, smode, sarg, opram, pc); + buffer += sprintf (buffer, ","); + buffer += print_arg (buffer, dmode, darg, opram, pc); + buffer += sprintf (buffer, byte_count ? ",%d,R%d" : ",R%d,R%d", byte_count, checkpoint); + break; + + case format_13: /* multiple precision shift instructions */ + OP2 = readop_arg(opram, pc); + + smode = BITS(OP2,10,11); + sarg = BITS(OP2,12,15); + darg = BITS(OP2,6,9); + byte_count = BITS(OP2,0,3); + + buffer += sprintf (buffer, "%-4s ", mnemonic); + buffer += print_arg (buffer, smode, sarg, opram, pc); + buffer += sprintf (buffer, byte_count ? ",%d" : ",R%d", byte_count); + buffer += sprintf (buffer, darg ? ",%d" : ",R%d", darg); + break; + + case format_14: /* bit testing instructions */ + OP2 = readop_arg(opram, pc); + + smode = BITS(OP2,10,11); + sarg = BITS(OP2,12,15); + darg = BITS(OP2,0,9); + + buffer += sprintf (buffer, "%-4s ", mnemonic); + buffer += print_arg (buffer, smode, sarg, opram, pc); + if (darg == 0x3ff) + buffer += sprintf (buffer, ",R0"); + else + buffer += sprintf (buffer, ",%d", darg); + break; + + case format_15: /* invert order of field instruction */ + OP2 = readop_arg(opram, pc); + + smode = BITS(OP2,10,11); + sarg = BITS(OP2,12,15); + bit_position = BITS(OP2,0,3); + bit_width = BITS(OP,12,15); + + buffer += sprintf (buffer, "%-4s ", mnemonic); + buffer += print_arg (buffer, smode, sarg, opram, pc); + buffer += sprintf (buffer, bit_position ? ",(%d," : ",(R%d,", bit_position); + buffer += sprintf (buffer, bit_width ? "%d)" : "R%d)", bit_width); + break; + + case format_16: /* field instructions */ + OP2 = readop_arg(opram, pc); + + smode = BITS(OP2,10,11); + sarg = BITS(OP2,12,15); + dmode = BITS(OP2,4,5); + darg = BITS(OP2,6,9); + bit_position = BITS(OP2,0,3); + bit_width = BITS(OP,12,15); + + buffer += sprintf (buffer, "%-4s ", mnemonic); + buffer += print_arg (buffer, smode, sarg, opram, pc); + buffer += sprintf (buffer, ","); + buffer += print_arg (buffer, dmode, darg, opram, pc); + buffer += sprintf (buffer, bit_position ? ",(%d," : ",(%d,", bit_position); + buffer += sprintf (buffer, bit_width ? "%d)" : "R%d)", bit_width); + break; + + case format_17: /* alter register and jump instructions */ + OP2 = readop_arg(opram, pc); + + displacement = (signed char)BITS(OP2,8,15); + sarg = BITS(OP2,4,7); + darg = BITS(OP2,0,3); + if (darg) + sprintf (buffer, darg ? "%-4s >%04x,%d,R%d" : "%-4s >%04x,R%d,R%d", + mnemonic, 0xffff & (PC + displacement * 2), sarg, darg); + break; + + case format_18: /* single register operand instructions */ + sarg = BITS(OP,12,15); + + sprintf (buffer, "%-4s R%d", mnemonic, sarg); + break; + + case format_liim: /* liim instruction */ + sarg = BITS(OP,14,15); + + sprintf (buffer, "%-4s %d", mnemonic, sarg); + break; + + case format_19: /* move address instruction */ + OP2 = readop_arg(opram, pc); + + smode = BITS(OP2,10,11); + sarg = BITS(OP2,12,15); + dmode = BITS(OP2,4,5); + darg = BITS(OP2,6,9); + + buffer += sprintf (buffer, "%-4s ", mnemonic); + buffer += print_arg (buffer, smode, sarg, opram, pc); + buffer += sprintf (buffer, ","); + buffer += print_arg (buffer, dmode, darg, opram, pc); + break; + + case format_20: /* list search instructions */ + { + const char *condition_code; + + OP2 = readop_arg(opram, pc); + + smode = BITS(OP2,10,11); + sarg = BITS(OP2,12,15); + dmode = BITS(OP2,4,5); + darg = BITS(OP2,6,9); + + switch (BITS(OP2,0,3)) + { + case 0: + condition_code = "eq"; + break; + case 1: + condition_code = "ne"; + break; + case 2: + condition_code = "he"; + break; + case 3: + condition_code = "l"; + break; + case 4: + condition_code = "ge"; + break; + case 5: + condition_code = "lt"; + break; + case 6: + condition_code = "le"; + break; + case 7: + condition_code = "h"; + break; + case 8: + condition_code = "lte"; + break; + case 9: + condition_code = "gt"; + break; + default: + condition_code = "??"; + break; + } + + buffer += sprintf (buffer, "%-4s %s,", mnemonic, condition_code); + buffer += print_arg (buffer, smode, sarg, opram, pc); + buffer += sprintf (buffer, ","); + buffer += print_arg (buffer, dmode, darg, opram, pc); + break; + } + + case format_21: /* extend precision instruction */ + { + int dest_byte_count; + + OP2 = readop_arg(opram, pc); + + smode = BITS(OP2,10,11); + sarg = BITS(OP2,12,15); + dmode = BITS(OP2,4,5); + darg = BITS(OP2,6,9); + byte_count = BITS(OP2,0,3); + dest_byte_count = BITS(OP,12,15); + + buffer += sprintf (buffer, "%-4s ", mnemonic); + buffer += print_arg (buffer, smode, sarg, opram, pc); + buffer += sprintf (buffer, ","); + buffer += print_arg (buffer, dmode, darg, opram, pc); + buffer += sprintf (buffer, byte_count ? ",%d" : ",R%d", byte_count); + buffer += sprintf (buffer, dest_byte_count ? ",%d" : ",R%d", dest_byte_count); + break; + } + + default: + logerror("debbugger internal error, file %s, line %d\n", __FILE__, __LINE__); + case illegal: + sprintf (buffer, "data >%04x", OP); + break; + } + + return (PC - pc) | DASMFLAG_SUPPORTED | dasmflags; +} + +CPU_DISASSEMBLE( tms9900 ) +{ + return Dasm9900(buffer, pc, TMS9900_ID, oprom, opram); +} + +CPU_DISASSEMBLE( tms9980 ) +{ + return Dasm9900(buffer, pc, TMS9980_ID, oprom, opram); +} + +CPU_DISASSEMBLE( tms9995 ) +{ + return Dasm9900(buffer, pc, TMS9995_ID, oprom, opram); +} diff --git a/src/devices/cpu/tms9900/99xxcore.h b/src/devices/cpu/tms9900/99xxcore.h new file mode 100644 index 00000000000..cb94fac286f --- /dev/null +++ b/src/devices/cpu/tms9900/99xxcore.h @@ -0,0 +1,5319 @@ +// license:BSD-3-Clause +// copyright-holders:Raphael Nabet + +/*************************************************************************** + Legacy TMS99xx core implementation + + PLEASE DO NOT REMOVE THIS FILE from the source tree, even if none of the + drivers make use of it anymore. It still contains documentation and + incomplete implementations of cores that are not (yet) used in drivers. + + It need not be included in the build process, however. + + Michael Zapf, February 2014 + +***************************************************************************/ + +/* + 99xxcore.h : generic tms99xx emulation + + The TMS99XX_MODEL switch tells which emulator we want to build. Set the + switch, then include 99xxcore.h, and you will have an emulator for this + processor. + + Only ti990/10, tms9900, tms9980a/9981, and tms9995 work OK for now. Note + that tms9995 has not been tested extensively. + + tms9940 is WIP: it is probably still buggy (particularily the BCD support), + as it has not been tested. tms9985 has been implemented as a 9940 with + a data bus, which should be mostly correct. + + I think all software aspects of tms9985 and tms9989 are implemented. + You just need to implement bus interfaces, provided you know them. + (I don't...) + + tms99000 cannot be implemented fully yet, due to lack of documentation. + + ti990/12 is not supported at all, and it should probably be implemented as + a separate processor core, anyway. + + Original tms9900 emulator by Edward Swartz + Smoothed out by Raphael Nabet + Originally converted for Mame by M.Coates + Processor timing, support for tms9980 and tms9995, and many bug fixes by R Nabet +*/ + +/* + The first member of the family was actually the ti990/10 minicomputer, + released in 1975. tms9900 was released in 1976, and has the same + instruction set as ti990/10: however, tms9900 is slower, it does not + support privileges and memory mapping, and illegal instructions do not + cause an error interrupt. + + The ti990 family later evoluted into the huge ti990/12 system, with support + for 144 different instructions, and microcode programming in case some user + found it was not enough. ti990/10 was eventually replaced by a cheaper + ti990/10a board, built around a tms99000 microprocessor. + + The tms9980 processor is merely a tms9900 with a 8-bit data bus (instead of + 16-bit on tms9900). + + tms9940 is a microcontroller, and is mostly similar to 9900/9980. The + variant I know has 2kb of ROM, 128 bytes of RAM, a timer, 32 I/O line, some + of which can be reconfigured as a CRU bus, but no external memory bus. It + includes three additional opcodes, which are not supported by any other + member of the family (with the probable exception of TMS9985). + + tms9985 is similar to tms9940, but it supports an external 8-bit-wide + memory bus. At least one variant included 8kb of ROM, 256 bytes of RAM. + It was ill-fated, as it was never released due to technical problems. + + tms9989 is mostly alien to me. I guess it is a close relative of tms9995, + although I am not sure. I have read that the SBP68689 supports tms9995 + opcodes, but that tms9989 does not. + + tms9995 belongs to another generation. It is quite faster than tms9900, + and supports 4 extra opcodes. Its external bus is 8-bit-wide, and it has + 256 bytes of internal 16-bit RAM. + + tms99000 is the successor to both ti9900 and ti990/10. It supports + privileges, and has a coprocessor interface which enables the use of an + external memory mapper. Additionnally, it can use a Macrostore ROM to + emulate additional instructions. + + This feature allowed TI to expand the 99000 family with the tms99105 (which + was said to support 84 instructions types), the tms99110 (which supported + floating point instructions), and possibly another chip (tms99220???) which + included parts of the UCSD P-system in Macrostore. + +References : +* 9900 family systems design, chapter 6, 7, 8 +* TMS 9980A/ TMS 9981 Product Data Book +* TMS 9995 16-Bit Microcomputer Data Manual +* Model 990/10A computer general description, section 4 (p/n 2302633-9701 A) +* 990/99000 assembly language reference manual (p/n 2270509-9701 A) +* Chapter 18 of unidentified book is the only reference on tms9940 I have found so far (Paperport format) + + +Other references can be found on spies.com: + + + +*/ + + +#if (TMS99XX_MODEL == TI990_10_ID) + + #define TMS99XX_PREFIX ti990_10 + #define TMS99XX_GET_INFO CPU_GET_INFO_NAME( ti990_10l ) + #define TMS99XX_device_get_name "TI990/10L" + #define TMS99XX_device_get_shortname "ti990_10l" + +#elif (TMS99XX_MODEL == TMS9900_ID) + + #define TMS99XX_PREFIX tms9900 + #define TMS99XX_GET_INFO CPU_GET_INFO_NAME( tms9900l ) + #define TMS99XX_device_get_name "TMS9900L" + #define TMS99XX_device_get_shortname "tms9900l" + +#elif (TMS99XX_MODEL == TMS9940_ID) + + #define TMS99XX_PREFIX tms9940 + #define TMS99XX_GET_INFO CPU_GET_INFO_NAME( tms9940l ) + #define TMS99XX_device_get_name "TMS9940L" + #define TMS99XX_device_get_shortname "tms9940l" + + #error "tms9940 is not yet supported" + +#elif (TMS99XX_MODEL == TMS9980_ID) + + #define TMS99XX_PREFIX tms9980a + #define TMS99XX_GET_INFO CPU_GET_INFO_NAME( tms9980al ) + #define TMS99XX_device_get_name "TMS9980AL/TMS9981L" + #define TMS99XX_device_get_shortname "tms9980al" + +#elif (TMS99XX_MODEL == TMS9985_ID) + + #define TMS99XX_PREFIX tms9985 + #define TMS99XX_GET_INFO CPU_GET_INFO_NAME( tms9985l ) + #define TMS99XX_device_get_name "TMS9985L" + #define TMS99XX_device_get_shortname "tms9985l" + + #error "tms9985 is not yet supported" + +#elif (TMS99XX_MODEL == TMS9989_ID) + + #define TMS99XX_PREFIX tms9989 + #define TMS99XX_GET_INFO CPU_GET_INFO_NAME( tms9989l ) + #define TMS99XX_device_get_name "TMS9989L" + #define TMS99XX_device_get_shortname "tms9989l" + + #error "tms9989 is not yet supported" + +#elif (TMS99XX_MODEL == TMS9995_ID) + + #define TMS99XX_PREFIX tms9995 + #define TMS99XX_GET_INFO CPU_GET_INFO_NAME( tms9995l ) + #define TMS99XX_device_get_name "TMS9995L" + #define TMS99XX_device_get_shortname "tms9995l" + +#elif (TMS99XX_MODEL == TMS99000_ID) + + #define TMS99XX_PREFIX tms99000 + #define TMS99XX_GET_INFO CPU_GET_INFO_NAME( tms99000l ) + #define TMS99XX_device_get_name "TMS99000L" + #define TMS99XX_device_get_shortname "tms99000l" + + #error "tms99000 is not yet supported" + +#elif (TMS99XX_MODEL == TMS99105A_ID) + + #define TMS99XX_PREFIX tms99105a + #define TMS99XX_GET_INFO CPU_GET_INFO_NAME( tms99105al ) + #define TMS99XX_device_get_name "TMS99105AL" + #define TMS99XX_device_get_shortname "tms99105al" + + #error "tms99105a is not yet supported" + +#elif (TMS99XX_MODEL == TMS99110A_ID) + + #define TMS99XX_PREFIX tms99110a + #define TMS99XX_GET_INFO CPU_GET_INFO_NAME( tms99110al ) + #define TMS99XX_device_get_name "TMS99110AL" + #define TMS99XX_device_get_shortname "tms99110al" + + #error "tms99110a is not yet supported" + +#endif + +/* + Now for some preprocessor wizardry. +*/ +#define concat2(a,b) a##b + +#define GET_INFO(prefix) concat2(prefix,_get_info) +#define RESET_PARAM(prefix) concat2(prefix,reset_param) + +#define TMS99XX_RESET_PARAM RESET_PARAM(TMS99XX_PREFIX) + + + +/* + I include this macro because we may eventually support other 99000 variants such as tms99110, + and this macro will remain true for every 99000 family member, even when we have + (TMS99XX_MODEL != TMS99000_ID). +*/ +#define IS_99000 (TMS99XX_MODEL == TMS99000_ID) + +/* + On microprocessor implementations (other than TMS9940 and, probably, TMS9985), the CKOF, CKON, + IDLE, LREX and RSET cause an external CRU write. CKOF, CKON and LREX do nothing apart of this, + therefore they must be implemented with external hardware (CKON and CKOF are supposed to + enable/disable a line clock interrupt, and LREX to trigger a LOAD interrupt). IDLE and RSET + are functional, but, on the one hand, the design allowed to light a diagnostic LED when + the processor is in IDLE state, and, on the other hand, the RSET instruction is supposed + to reset external devices as well. + + On the TI990/10 and TI990/12 minicomputers, there is no such CRU write. The line clock + interrupt latch is part of the CPU board, LREX is fully functional, the IDLE led is connected + to the board, and the RSET line is part of the TILINE bus connector. + + On the TMS9940, CKOF, CKON, LREX and RSET are not supported. IDLE, on the other hand, is + supported, and the CPU can be configured to output its IDLE state on the P16 I/O pin. +*/ +#define EXTERNAL_INSTRUCTION_DECODING (TMS99XX_MODEL != TI990_10_ID) && (TMS99XX_MODEL != TI9940_ID) && (TMS99XX_MODEL != TI9985_ID) +#define EXTERNAL_INSTRUCTION_CALLBACK (TMS99XX_MODEL == TI990_10_ID) + +/* + ti990/10, ti990/12 and tms99000 support privileges + + privileged instructions: + CKOF, CKON, IDLE, LIMI, LREX, RSET, + LDD, LDS, LMF, (memory mapping instructions) + DINT, EINT, EMD , LCS, LIM, SLSP. (990/12 instructions) + + instructions which are privileged when the effective CRU address is higher than 0xE00: + LDCR, SBO, SBZ, STCR, TB. + + instructions whose behaviour is modified in user mode (only user flags in ST are affected): + RTWP, + LST. (ti990/12 and tms99000 instruction) +*/ +#define HAS_PRIVILEGE ((TMS99XX_MODEL == TI990_10_ID) || IS_99000) + +/* + opcode groups + + * 69 basic opcodes implemented on all family members + * 3 memory mapping opcodes implemented on ti990/10 with mapping option, ti990/12, and + the tim99610 mapper in conjunction with any tms99000 family member: LMF, LDS, LDD + * 3 opcodes implemented on tms9940 (and probably tms9985) only: DCA, DCS, LIIM + * 4 opcodes implemented on ti990/12, tms9989 and above: MPYS, DIVS, LST, LWP + * 1 opcode implemented on ti990/12, and tms99000: BIND + * 72 opcodes implemented on ti990/12 only (some of which are emulated by tms99105 & tms99110) +*/ + +#define HAS_MAPPING ((TMS99XX_MODEL == TI990_10_ID) /*|| IS_99000*/) +#define HAS_9995_OPCODES ((TMS99XX_MODEL == TMS9989_ID) || (TMS99XX_MODEL == TMS9995_ID) || IS_99000) +#define HAS_BIND_OPCODE IS_99000 + +#define HAS_OVERFLOW_INTERRUPT ((TMS99XX_MODEL == TMS9995_ID) || IS_99000) + +/* + Under tms9900, opcodes >0200->03FF are incompletely decoded: bits 11 is ignored, and so are + bits 12-15 for instructions which do not require a register. On the other hand, ti990/10 + generates an illegal instruction error when bit 11 is set, but still ignores bits 12-15. + Additionally, ti990/12 and tms9995 will generate an illegal error when bits 12-15 are + non-zero. +*/ +#define BETTER_0200_DECODING (TMS99XX_MODEL == TI990_10_ID) +#define COMPLETE_0200_DECODING (TMS99XX_MODEL >= TMS9995_ID) + +/* + TI990/10 and tms9900 force unused bits in the ST register to 0. + TMS9995 does not. +*/ +#define USE_ST_MASK (TMS99XX_MODEL <= TMS9985_ID) + +/* + TI990/10, TMS9900 and TMS99000 have a 16-bit-wide memory bus, and use 16-bus accessors. + TMS9940 use 16-bit accessors, too, as it has an internal 16-bit bus, and no external bus. +*/ +#define USE_16_BIT_ACCESSORS ((TMS99XX_MODEL == TI990_10_ID) || (TMS99XX_MODEL == TMS9900_ID) || (TMS99XX_MODEL == TMS9940_ID) || (IS_99000)) + +struct tms99xx_state; + +INLINE void execute(tms99xx_state *cpustate, UINT16 opcode); + +#if EXTERNAL_INSTRUCTION_DECODING +static void external_instruction_notify(tms99xx_state *cpustate, int ext_op_ID); +#endif +static UINT16 decipheraddr(tms99xx_state *cpustate, UINT16 opcode); +static UINT16 decipheraddrbyte(tms99xx_state *cpustate, UINT16 opcode); +static void contextswitch(tms99xx_state *cpustate, UINT16 addr); +#if HAS_MAPPING || HAS_PRIVILEGE +static void contextswitchX(tms99xx_state *cpustate, UINT16 addr); +#else +#define contextswitchX(cs, addr) contextswitch(cs, addr) +#endif +static void field_interrupt(tms99xx_state *cpustate); + +/***************************/ +/* Mame Interface Routines */ +/***************************/ + + +/* tms9900 ST register bits. */ + +/* These bits are set by every compare, move and arithmetic or logical operation : */ +/* (Well, COC, CZC and TB only set the E bit, but these are kind of exceptions.) */ +#define ST_LGT 0x8000 /* Logical Greater Than (strictly) */ +#define ST_AGT 0x4000 /* Arithmetical Greater Than (strictly) */ +#define ST_EQ 0x2000 /* Equal */ + +/* These bits are set by arithmetic operations, when it makes sense to update them. */ +#define ST_C 0x1000 /* Carry */ +#define ST_OV 0x0800 /* OVerflow (overflow with operations on signed integers, */ + /* and when the result of a 32bits:16bits division cannot fit in a 16-bit word.) */ + +/* This bit is set by move and arithmetic operations WHEN THEY USE BYTE OPERANDS. */ +#define ST_OP 0x0400 /* Odd Parity */ + +#if (TMS99XX_MODEL != TMS9940_ID) + +/* This bit is set by the XOP instruction. */ +#define ST_X 0x0200 /* Xop */ + +#endif + +#if (TMS99XX_MODEL == TMS9940_ID) || (TMS99XX_MODEL == TMS9985_ID) + +/* This bit is set by arithmetic operations to support BCD */ +#define ST_DC 0x0100 /* Digit Carry */ + +#endif + +#if HAS_PRIVILEGE + +/* This bit is set in user (i.e. non-supervisor) mode */ +#define ST_PR 0x0100 /* PRivilege */ + +#endif + +#if HAS_MAPPING + +/* This tells which map is currently in use */ +#define ST_MF 0x0080 /* Map File */ + +#endif + +#if (HAS_OVERFLOW_INTERRUPT) + +/* This bit is set in ti990/12, TMS9995 and later chips to generate a level-2 interrupt when +the Overflow status bit is set */ +#define ST_OVIE 0x0020 /* OVerflow Interrupt Enable */ + +#endif + +#if (IS_99000) + +/* This bit enables the macrostore feature on tms99000 */ +/* (It is used on ti990/12 with a different meaning.) */ +#define ST_EMR 0x0010 /* Enable Macrostore Rom */ + +#endif + +#if (TMS99XX_MODEL == TMS9940_ID) || (TMS99XX_MODEL == TMS9985_ID) + +#define ST_IM 0x0003 /* Interrupt Mask */ + +#else + +#define ST_IM 0x000F /* Interrupt Mask */ + +#endif + +/* On models before TMS9995 (TMS9989 ?), unused ST bits are always forced to 0, so we define +a ST_MASK */ +#if (USE_ST_MASK) + #if (TMS99XX_MODEL == TI990_10_ID) + #define ST_MASK 0xFF8F + #elif (TMS99XX_MODEL == TMS9940_ID) || (TMS99XX_MODEL == TMS9985_ID) +#define ST_MASK 0xFD03 + #else + #define ST_MASK 0xFE0F + #endif +#endif + + +/* error interrupt register bits */ + +#if (TMS99XX_MODEL == TI990_10_ID) + +/* This bit is set in user (i.e. non-supervisor) mode */ +#define EIR_MAPERR 0x0800 /* memory MAPping ERRor */ +#define EIR_MER 0x1000 /* Memory parity ERRor */ +#define EIR_ILLOP 0x2000 /* ILLegal OPcode */ +#define EIR_PRIVOP 0x4000 /* PRiviledged OPeration */ +#define EIR_TIMEOUT 0x8000 /* TILINE TIMEOUT */ + +#endif + + +/* Offsets for registers. */ +#define R0 0 +#define R1 2 +#define R2 4 +#define R3 6 +#define R4 8 +#define R5 10 +#define R6 12 +#define R7 14 +#define R8 16 +#define R9 18 +#define R10 20 +#define R11 22 +#define R12 24 +#define R13 26 +#define R14 28 +#define R15 30 + +struct map_file_t +{ + UINT16 L[3], B[3]; /* actual registers */ + UINT32 limit[3], bias[3]; /* equivalent in a more convenient form */ +}; + +struct tms99xx_state +{ +/* "actual" tms9900 registers : */ + UINT16 WP; /* Workspace pointer */ + UINT16 PC; /* Program counter */ + UINT16 STATUS; /* STatus register */ + +/* Now, data used for emulation */ + UINT8 lastparity; + char lds_flag, ldd_flag; + UINT16 IR; /* Instruction register, with the currently parsed opcode */ + + UINT8 interrupt_pending; /* true if an interrupt must be honored... */ + +#if ! ((TMS99XX_MODEL == TMS9940_ID) || (TMS99XX_MODEL == TMS9985_ID)) + UINT8 load_state; /* nonzero if the LOAD* line is active (low) */ +#endif + +#if (TMS99XX_MODEL == TI990_10_ID) || (TMS99XX_MODEL == TMS9900_ID) || (TMS99XX_MODEL == TMS9980_ID) + /* On tms9900, we cache the state of INTREQ* and IC0-IC3 here */ + /* On tms9980/9981, we translate the state of IC0-IC2 to the equivalent state for a tms9900, + and store the result here */ + UINT8 irq_level; /* when INTREQ* is active, interrupt level on IC0-IC3 ; else always 16 */ + UINT8 irq_state; /* nonzero if the INTREQ* line is active (low) */ + /* with TMS9940, bit 0 means INT1, bit 1 decrementer, bit 2 INT2 */ +#elif (TMS99XX_MODEL == TMS9995_ID) + /* tms9995 is quite different : it latches the interrupt inputs */ + UINT8 irq_level; /* We store the level of the request with the highest level here */ + UINT8 int_state; /* interrupt lines state */ + UINT8 int_latch; /* interrupt latches state */ +#endif + + /* interrupt callback */ + /* note that this callback is used by tms9900_set_irq_line(cpustate) and tms9980a_set_irq_line(cpustate) to + retreive the value on IC0-IC3 (non-standard behaviour) */ + device_irq_acknowledge_delegate irq_callback; + legacy_cpu_device *device; + address_space *program; + address_space *io; + int icount; + + UINT8 IDLE; /* nonzero if processor is IDLE - i.e waiting for interrupt while writing + special data on CRU bus */ + +#if HAS_MAPPING + UINT8 mapping_on; /* set by a CRU write */ + map_file_t map_files[3]; /* internal mapper registers */ + UINT8 cur_map; /* equivalent to ST_MF status bit */ + UINT8 cur_src_map; /* set to 2 by LDS */ + UINT8 cur_dst_map; /* set to 2 by LDD */ + +#if (TMS99XX_MODEL == TI990_10_ID) + UINT8 reset_maperr; /* reset mapper error flag line (reset flags in 945417-9701 p. 3-90) */ + + UINT32 mapper_address_latch; /* used to load the map file and for diagnostic purpose */ + UINT16 mapper_cru_read_register; /* read register select code for mapper cru interface */ + UINT8 diaglat; /* set when diagnostic address latch is done */ + UINT8 latch_control[3]; /* latch control */ + +#endif +#endif + +#if (TMS99XX_MODEL == TI990_10_ID) + UINT16 error_interrupt_register; /* one flag for each interrupt condition */ + ti99xx_error_interrupt_func error_interrupt_callback; +#endif + +#if (TMS99XX_MODEL == TMS9985_ID) || (TMS99XX_MODEL == TMS9995_ID) + UINT8 RAM[256]; /* on-chip RAM (I know this is weird, but the internal bus is 16-bit-wide, whereas the external bus is 8-bit-wide) */ +#endif + +#if (TMS99XX_MODEL == TMS9940_ID) || (TMS99XX_MODEL == TMS9985_ID) || (TMS99XX_MODEL == TMS9995_ID) + /* on-chip event counter/timer*/ + UINT8 decrementer_enabled; + UINT16 decrementer_interval; + UINT16 decrementer_count; /* used in event counter mode*/ + emu_timer *timer; /* used in timer mode */ +#endif + +#if (TMS99XX_MODEL == TMS9995_ID) + /* additionnal registers */ + UINT16 flag; /* flag register */ + UINT8 MID_flag; /* MID flag register */ + + /* chip config, which can be set on reset */ + UINT8 memory_wait_states_byte; + UINT8 memory_wait_states_word; + + /* mask option (off on normal tms9995) */ + UINT8 is_mp9537; +#endif + + /* Some instructions (i.e. XOP, BLWP, and MID) disable interrupt recognition until another + instruction is executed : so they set this flag */ + UINT8 disable_interrupt_recognition; + + /* notify the driver of changes in IDLE state */ + ti99xx_idle_func idle_callback; + +#if EXTERNAL_INSTRUCTION_CALLBACK + ti99xx_rset_func rset_callback; + ti99xx_lrex_func lrex_callback; + ti99xx_ckon_ckof_func ckon_ckof_callback; +#endif + + int write_inhibit; + int extra_byte; /* buffer holding the unused byte in a word read */ +}; + +INLINE tms99xx_state *get_safe_token(device_t *device) +{ + assert(device != NULL); +// assert(device->type() == TMS99XX_GET_INFO); + return (tms99xx_state *)downcast(device)->token(); +} + +#if (TMS99XX_MODEL == TMS9995_ID) +static void reset_decrementer(tms99xx_state *cpustate); +#endif + + +#if (TMS99XX_MODEL == TI990_10_ID) + +/* + accessor for the internal ROM +*/ +READ16_HANDLER(ti990_10_internal_r) +{ + //return cpustate->ROM[offset]; + return space.read_word(0x1ffc00+offset); +} + +#endif + +#if (TMS99XX_MODEL == TMS9995_ID) + +/* + accessor for the first 252 bytes of internal RAM +*/ +READ8_HANDLER(tms9995_internal1_r) +{ + tms99xx_state *cpustate = get_safe_token(&space.device()); + return cpustate->RAM[offset]; +} + +WRITE8_HANDLER(tms9995_internal1_w) +{ + tms99xx_state *cpustate = get_safe_token(&space.device()); + cpustate->RAM[offset]=data; +} + +/* + accessor for the last 4 bytes of internal RAM +*/ +READ8_HANDLER(tms9995_internal2_r) +{ + tms99xx_state *cpustate = get_safe_token(&space.device()); + return cpustate->RAM[offset+0xfc]; +} + +WRITE8_HANDLER(tms9995_internal2_w) +{ + tms99xx_state *cpustate = get_safe_token(&space.device()); + cpustate->RAM[offset+0xfc]=data; +} + +#endif + +#if (TMS99XX_MODEL == TI990_10_ID) + + /* on-board ROMs are not emulated (we use a hack) */ + + #define readword(cs, addr) readwordX((cs), (addr), (cs)->cur_map) + static int readwordX(tms99xx_state *cpustate, int addr, int map_file) + { + if ((map_file == 0) && (addr >= 0xf800)) + { /* intercept TPCS and CPU ROM */ + if (addr < 0xfc00) + /* TPCS */ + return cpustate->program->read_word(0x1f0000+addr); + else + /* CPU ROM */ + return cpustate->program->read_word(0x1f0000+addr); /* hack... */ + } + else if (! cpustate->mapping_on) + { + return cpustate->program->read_word(addr); + } + else + { + int map_index; + + if (addr <= cpustate->map_files[map_file].limit[0]) + map_index = 0; + else if (addr <= cpustate->map_files[map_file].limit[1]) + map_index = 1; + else if (addr <= cpustate->map_files[map_file].limit[2]) + map_index = 2; + else + { /* mapping error */ + if ((! (cpustate->error_interrupt_register & EIR_MAPERR)) && ! (cpustate->diaglat)) + cpustate->mapper_address_latch = addr; + if ((! cpustate->reset_maperr) && ! (cpustate->error_interrupt_register & EIR_MAPERR)) + { + cpustate->error_interrupt_register |= EIR_MAPERR; + cpustate->write_inhibit = 1; + } + return cpustate->program->read_word(addr); + } + if ((! (cpustate->error_interrupt_register & EIR_MAPERR)) && ! (cpustate->diaglat)) + cpustate->mapper_address_latch = cpustate->map_files[map_file].bias[map_index]+addr; + if ((cpustate->latch_control[map_index]) && (! cpustate->reset_maperr)) + cpustate->diaglat = 1; + return cpustate->program->read_word(cpustate->map_files[map_file].bias[map_index]+addr); + } + } + + #define writeword(cs, addr, data) writewordX((cs), (addr), (data), (cs)->cur_map) + static void writewordX(tms99xx_state *cpustate, int addr, int data, int map_file) + { + if ((map_file == 0) && (addr >= 0xf800)) + { /* intercept TPCS and CPU ROM */ + if (addr < 0xfc00) + /* TPCS */ + cpustate->program->write_word(0x1f0000+addr, data); + else + /* CPU ROM */ + cpustate->program->write_word(0x1f0000+addr, data); /* hack... */ + } + else if (! cpustate->mapping_on) + { + cpustate->program->write_word(addr, data); + } + else + { + int map_index; + + if (addr <= cpustate->map_files[map_file].limit[0]) + map_index = 0; + else if (addr <= cpustate->map_files[map_file].limit[1]) + map_index = 1; + else if (addr <= cpustate->map_files[map_file].limit[2]) + map_index = 2; + else + { /* mapping error */ + if ((! (cpustate->error_interrupt_register & EIR_MAPERR)) && ! (cpustate->diaglat)) + cpustate->mapper_address_latch = addr; + if ((! cpustate->reset_maperr) && ! (cpustate->error_interrupt_register & EIR_MAPERR)) + { + cpustate->error_interrupt_register |= EIR_MAPERR; + cpustate->write_inhibit = 1; + } + if (cpustate->write_inhibit) + (void)cpustate->program->read_word(addr); + else + cpustate->program->write_word(addr, data); + return; + } + if ((! (cpustate->error_interrupt_register & EIR_MAPERR)) && ! (cpustate->diaglat)) + cpustate->mapper_address_latch = cpustate->map_files[map_file].bias[map_index]+addr; + if ((cpustate->latch_control[map_index]) && (! cpustate->reset_maperr)) + cpustate->diaglat = 1; + cpustate->program->write_word(cpustate->map_files[map_file].bias[map_index]+addr, data); + } + } + + #define readbyte(cs, addr) readbyteX((cs), (addr), (cs)->cur_map) + static int readbyteX(tms99xx_state *cpustate, int addr, int map_file) + { + if ((map_file == 0) && (addr >= 0xf800)) + { /* intercept TPCS and CPU ROM */ + if (addr < 0xfc00) + /* TPCS */ + return cpustate->program->read_byte(0x1f0000+addr); + else + /* CPU ROM */ + return cpustate->program->read_byte(0x1f0000+addr); /* hack... */ + } + else if (! cpustate->mapping_on) + { + return cpustate->program->read_byte(addr); + } + else + { + int map_index; + + if (addr <= cpustate->map_files[map_file].limit[0]) + map_index = 0; + else if (addr <= cpustate->map_files[map_file].limit[1]) + map_index = 1; + else if (addr <= cpustate->map_files[map_file].limit[2]) + map_index = 2; + else + { /* mapping error */ + if ((! (cpustate->error_interrupt_register & EIR_MAPERR)) && ! (cpustate->diaglat)) + cpustate->mapper_address_latch = addr; + if ((! cpustate->reset_maperr) && ! (cpustate->error_interrupt_register & EIR_MAPERR)) + { + cpustate->error_interrupt_register |= EIR_MAPERR; + cpustate->write_inhibit = 1; + } + return cpustate->program->read_byte(addr); + } + if ((! (cpustate->error_interrupt_register & EIR_MAPERR)) && ! (cpustate->diaglat)) + cpustate->mapper_address_latch = cpustate->map_files[map_file].bias[map_index]+addr; + if ((cpustate->latch_control[map_index]) && (! cpustate->reset_maperr)) + cpustate->diaglat = 1; + return cpustate->program->read_byte(cpustate->map_files[map_file].bias[map_index]+addr); + } + } + + #define writebyte(cs, addr, data) writebyteX((cs), (addr), (data), (cs)->cur_map) + static void writebyteX(tms99xx_state *cpustate, int addr, int data, int map_file) + { + if ((map_file == 0) && (addr >= 0xf800)) + { /* intercept TPCS and CPU ROM */ + if (addr < 0xfc00) + /* TPCS */ + cpustate->program->write_byte(0x1f0000+addr, data); + else + /* CPU ROM */ + cpustate->program->write_byte(0x1f0000+addr, data); /* hack... */ + } + else if (! cpustate->mapping_on) + { + cpustate->program->write_byte(addr, data); + } + else + { + int map_index; + + if (addr <= cpustate->map_files[map_file].limit[0]) + map_index = 0; + else if (addr <= cpustate->map_files[map_file].limit[1]) + map_index = 1; + else if (addr <= cpustate->map_files[map_file].limit[2]) + map_index = 2; + else + { /* mapping error */ + if ((! (cpustate->error_interrupt_register & EIR_MAPERR)) && ! (cpustate->diaglat)) + cpustate->mapper_address_latch = addr; + if ((! cpustate->reset_maperr) && ! (cpustate->error_interrupt_register & EIR_MAPERR)) + { + cpustate->error_interrupt_register |= EIR_MAPERR; + cpustate->write_inhibit = 1; + } + if (cpustate->write_inhibit) + (void)cpustate->program->read_byte(addr); + else + cpustate->program->write_byte(addr, data); + return; + } + if ((! (cpustate->error_interrupt_register & EIR_MAPERR)) && ! (cpustate->diaglat)) + cpustate->mapper_address_latch = cpustate->map_files[map_file].bias[map_index]+addr; + if ((cpustate->latch_control[map_index]) && (! cpustate->reset_maperr)) + cpustate->diaglat = 1; + cpustate->program->write_byte(cpustate->map_files[map_file].bias[map_index]+addr, data); + } + } + +#elif (TMS99XX_MODEL == TMS9900_ID) || (TMS99XX_MODEL == TMS9940_ID) + /*16-bit data bus, 16-bit address bus (internal bus in the case of TMS9940)*/ + /*Note that tms9900 actually never accesses a single byte : when performing byte operations, + it reads a 16-bit word, changes the relevant byte, then write a complete word. You should + remember this when writing memory handlers.*/ + /*This does not apply to tms9995 and tms99xxx, but does apply to tms9980 (see below).*/ + + #define readword(cs, addr) (cs)->program->read_word(addr) + #define writeword(cs, addr,data) (cs)->program->write_word((addr), (data)) + + #define readbyte(cs, addr) (cs)->program->read_byte(addr) + #define writebyte(cs, addr,data) (cs)->program->write_byte((addr),(data)) + +#elif (TMS99XX_MODEL == TMS9980_ID) + /*8-bit data bus, 14-bit address*/ + /*Note that tms9980 never accesses a single byte (however crazy it may seem). Although this + makes memory access slower, I have emulated this feature, because if I did otherwise, + there would be some implementation problems in some driver sooner or later.*/ + + INLINE int readword(tms99xx_state *cpustate, int addr) + { + int val; + + cpustate->icount -= 2; + val = cpustate->program->read_byte(addr); + return (val << 8) | cpustate->program->read_byte(addr+1); + } + #define writeword(cs, addr,data) { (cs)->icount -= 2; (cs)->program->write_byte((addr), (data) >> 8); cpustate->program->write_byte((addr) + 1, (data) & 0xff); } + +#if 0 + #define readbyte(cs, addr) ((cs)->icount -= 2, (cs)->program->read_byte(addr)) + #define writebyte(cs, addr,data) { (cs)->icount -= 2; (cs)->program->write_byte((addr),(data)); } +#else + /*This is how it really works*/ + /*Note that every writebyte must match a readbyte (which is indeed the case)*/ + + static int readbyte(tms99xx_state *cpustate, int addr) + { + cpustate->icount -= 2; + if (addr & 1) + { + cpustate->extra_byte = cpustate->program->read_byte(addr-1); + return cpustate->program->read_byte(addr); + } + else + { + int val = cpustate->program->read_byte(addr); + cpustate->extra_byte = cpustate->program->read_byte(addr+1); + return val; + } + } + static void writebyte (tms99xx_state *cpustate, int addr, int data) + { + cpustate->icount -= 2; + if (addr & 1) + { + cpustate->program->write_byte(addr-1, cpustate->extra_byte); + cpustate->program->write_byte(addr, data); + } + else + { + cpustate->program->write_byte(addr, data); + cpustate->program->write_byte(addr+1, cpustate->extra_byte); + } + } +#endif + +#elif (TMS99XX_MODEL == TMS9985_ID) + /*Note that every writebyte must match a readbyte (which is indeed the case)*/ + + static int readword(tms99xx_state *cpustate, int addr) + { + if (addr < 0x2000) + { + } + else if ((addr >= 0x8300) && (addr < 0x8400)) + { + } + else + { + cpustate->icount -= 2; + return (cpustate->program->read_byte(addr) << 8) + cpustate->program->read_byte(addr + 1); + } + } + static void writeword(tms99xx_state *cpustate, int addr, int data) + { + if ((addr >= 0x8300) && (addr < 0x8400)) + { + } + else if (!(addr < 0x2000)) + { + cpustate->icount -= 2; + cpustate->program->write_byte(addr, data >> 8); + cpustate->program->write_byte(addr + 1, data & 0xff); + } + } + + static int readbyte(tms99xx_state *cpustate, int addr) + { + if (addr < 0x2000) + { + } + else if ((addr >= 0x8300) && (addr < 0x8400)) + { + } + else + { + cpustate->icount -= 2; + if (addr & 1) + { + cpustate->extra_byte = cpustate->program->read_byte(addr-1); + return cpustate->program->read_byte(addr); + } + else + { + int val = cpustate->program->read_byte(addr); + cpustate->extra_byte = cpustate->program->read_byte(addr+1); + return val; + } + } + } + static void writebyte(tms99xx_state *cpustate, int addr, int data) + { + if ((addr >= 0x8300) && (addr < 0x8400)) + { + } + else if (!(addr < 0x2000)) + { + cpustate->icount -= 2; + if (addr & 1) + { + cpustate->program->write_byte(addr-1, cpustate->extra_byte); + cpustate->program->write_byte(addr, data); + } + else + { + cpustate->program->write_byte(addr, data); + cpustate->program->write_byte(addr+1, cpustate->extra_byte); + } + } + } + +#elif (TMS99XX_MODEL == TMS9995_ID) + /*8-bit external data bus, with on-chip 16-bit RAM, and 16-bit address bus*/ + /*The code is complex, so we use functions rather than macros*/ + + static TIMER_CALLBACK( decrementer_callback ); + + static int readword(tms99xx_state *cpustate, int addr) + { + if ((addr < 0xf000) || (cpustate->is_mp9537)) + { + int reply; + cpustate->icount -= cpustate->memory_wait_states_word; + reply = cpustate->program->read_byte(addr); + return (reply << 8) | cpustate->program->read_byte(addr + 1); + } + else if (addr < 0xf0fc) + { + return *(UINT16 *)(& cpustate->RAM[addr - 0xf000]); + } + else if (addr < 0xfffa) + { + int reply; + cpustate->icount -= cpustate->memory_wait_states_word; + reply = cpustate->program->read_byte(addr); + return (reply << 8) | cpustate->program->read_byte(addr + 1); + } + else if (addr < 0xfffc) + { + /* read decrementer */ + if (cpustate->decrementer_enabled && !(cpustate->flag & 1)) + /* timer mode, timer enabled */ + return cpustate->device->attotime_to_cycles(cpustate->timer->remaining() / 16); + else + /* event counter mode or timer mode, timer disabled */ + return cpustate->decrementer_count; + } + else + { + return *(UINT16 *)(& cpustate->RAM[addr - 0xff00]); + } + } + + static void writeword (tms99xx_state *cpustate, int addr, int data) + { + if ((addr < 0xf000) || (cpustate->is_mp9537)) + { + cpustate->icount -= cpustate->memory_wait_states_word; + cpustate->program->write_byte(addr, data >> 8); + cpustate->program->write_byte(addr + 1, data & 0xff); + } + else if (addr < 0xf0fc) + { + *(UINT16 *)(& cpustate->RAM[addr - 0xf000]) = data; + } + else if (addr < 0xfffa) + { + cpustate->icount -= cpustate->memory_wait_states_word; + cpustate->program->write_byte(addr, data >> 8); + cpustate->program->write_byte(addr + 1, data & 0xff); + } + else if (addr < 0xfffc) + { + /* write decrementer */ + cpustate->decrementer_interval = data; + reset_decrementer(cpustate); + } + else + { + *(UINT16 *)(& cpustate->RAM[addr - 0xff00]) = data; + } + } + + static int readbyte(tms99xx_state *cpustate, int addr) + { + if ((addr < 0xf000) || (cpustate->is_mp9537)) + { + cpustate->icount -= cpustate->memory_wait_states_byte; + return cpustate->program->read_byte(addr); + } + else if (addr < 0xf0fc) + { + return cpustate->RAM[BYTE_XOR_BE(addr - 0xf000)]; + } + else if (addr < 0xfffa) + { + cpustate->icount -= cpustate->memory_wait_states_byte; + return cpustate->program->read_byte(addr); + } + else if (addr < 0xfffc) + { + /* read decrementer */ + int value; + + if (cpustate->decrementer_enabled && !(cpustate->flag & 1)) + /* timer mode, timer enabled */ + value = cpustate->device->attotime_to_cycles(cpustate->timer->remaining() / 16); + else + /* event counter mode or timer mode, timer disabled */ + value = cpustate->decrementer_count; + + if (addr & 1) + return (value & 0xFF); + else + return (value >> 8); + } + else + { + return cpustate->RAM[BYTE_XOR_BE(addr - 0xff00)]; + } + } + + static void writebyte (tms99xx_state *cpustate, int addr, int data) + { + if ((addr < 0xf000) || (cpustate->is_mp9537)) + { + cpustate->icount -= cpustate->memory_wait_states_byte; + cpustate->program->write_byte(addr, data); + } + else if (addr < 0xf0fc) + { + cpustate->RAM[BYTE_XOR_BE(addr - 0xf000)] = data; + } + else if (addr < 0xfffa) + { + cpustate->icount -= cpustate->memory_wait_states_byte; + cpustate->program->write_byte(addr, data); + } + else if (addr < 0xfffc) + { + /* write decrementer */ + /* Note that a byte write to tms9995 timer messes everything up. */ + cpustate->decrementer_interval = (data << 8) | data; + reset_decrementer(cpustate); + } + else + { + cpustate->RAM[BYTE_XOR_BE(addr - 0xff00)] = data; + } + } + +#else + + #error "memory access not implemented" + +#endif + +#if !HAS_MAPPING + #define readwordX(cs, addr, map_file) readword(cs, addr) + #define writewordX(cs, addr, data, map_file) writeword(cs, (addr), (data)) + #define readbyteX(cs, addr, map_file) readbyte(cs, addr) + #define writebyteX(cs, addr, data, map_file) writebyte(cs, (addr), (data)) +#endif + +#define READREG(reg) readword(cpustate, (cpustate->WP+(reg)) & 0xffff) +#define WRITEREG(reg, data) writeword(cpustate, (cpustate->WP+(reg)) & 0xffff, (data)) + +INLINE UINT16 READREG_DEBUG(tms99xx_state *cpustate, int reg) +{ + int temp = cpustate->icount; + UINT16 result = READREG(reg); + cpustate->icount = temp; + return result; +} + +INLINE void WRITEREG_DEBUG(tms99xx_state *cpustate, int reg, UINT16 data) +{ + int temp = cpustate->icount; + WRITEREG(reg, data); + cpustate->icount = temp; +} + +#if (TMS99XX_MODEL == TI990_10_ID) + READ8_HANDLER(ti990_10_mapper_cru_r) + { + tms99xx_state *cpustate = get_safe_token(&space.device()); + int reply = 0; + + switch(cpustate->mapper_cru_read_register) + { + case 0xb000: + reply = cpustate->map_files[cpustate->cur_map].B[0]; + break; + case 0xb001: + reply = cpustate->map_files[cpustate->cur_map].B[1]; + break; + case 0xb010: + reply = cpustate->map_files[cpustate->cur_map].B[2]; + break; + case 0xb011: + reply = cpustate->map_files[cpustate->cur_map].L[0]; + break; + case 0xb100: + reply = cpustate->map_files[cpustate->cur_map].L[1]; + break; + case 0xb101: + reply = cpustate->map_files[cpustate->cur_map].L[2]; + break; + case 0xb110: + reply = cpustate->mapper_address_latch; + break; + case 0xb111: + reply = cpustate->mapper_address_latch >> 16; + break; + } + + if (offset) + return (reply >> 8) & 0xff; + else + return reply & 0xff; + } + + WRITE8_HANDLER(ti990_10_mapper_cru_w) + { + tms99xx_state *cpustate = get_safe_token(&space.device()); + switch (offset) + { + case 0: + case 1: + case 2: + /* read register select */ + if (data) + cpustate->mapper_cru_read_register |= (1 << offset); + else + cpustate->mapper_cru_read_register &= ~ (1 << offset); + break; + case 3: + /* enable mapping */ + cpustate->mapping_on = data; + break; + case 4: + /* reset flags */ + cpustate->reset_maperr = data; + if (data) + { + cpustate->error_interrupt_register &= ~ EIR_MAPERR; + cpustate->diaglat = 0; + } + break; + case 5: + case 6: + case 7: + /* latch control */ + cpustate->latch_control[7-offset] = data; + break; + } + } + + INLINE void handle_error_interrupt(tms99xx_state *cpustate) + { + if (cpustate->error_interrupt_callback) + (*cpustate->error_interrupt_callback)(cpustate->device, cpustate->error_interrupt_register ? 1 : 0); + } + + READ8_HANDLER(ti990_10_eir_cru_r) + { + tms99xx_state *cpustate = get_safe_token(&space.device()); + return (offset == 1) ? (cpustate->error_interrupt_register & 0xff) : 0; + } + + WRITE8_HANDLER(ti990_10_eir_cru_w) + { + tms99xx_state *cpustate = get_safe_token(&space.device()); + if (offset < 4) /* does not work for EIR_MAPERR */ + { + cpustate->error_interrupt_register &= ~ (1 << offset); + + handle_error_interrupt(cpustate); + } + } + + +#endif + +/* Interrupt mask */ +#define IMASK (cpustate->STATUS & ST_IM) + +/* + CYCLES macro : you provide timings for tms9900 and tms9995, and the macro chooses for you. + + BTW, I have no idea what the timings are for tms9989 and tms99xxx... +*/ +#if TMS99XX_MODEL == TI990_10_ID + /* Use TI990/10 timings*/ + #define CYCLES(a,b,c) cpustate->icount -= a +#elif TMS99XX_MODEL <= TMS9985_ID + /* Use TMS9900/TMS9980 timings*/ + #define CYCLES(a,b,c) cpustate->icount -= b +#else + /* Use TMS9995 timings*/ + #define CYCLES(a,b,c) cpustate->icount -= c*4 +#endif + +#if (TMS99XX_MODEL == TMS9995_ID) + +static void set_flag0(tms99xx_state *cpustate, int val); +static void set_flag1(tms99xx_state *cpustate, int val); + +#endif + +/************************************************************************ + * Status register functions + ************************************************************************/ + +/* + remember that the OP ST bit is maintained in cpustate->lastparity +*/ + +/* + setstat sets the ST_OP bit according to cpustate->lastparity + + It must be called before reading the ST register. +*/ + +static void setstat(tms99xx_state *cpustate) +{ + int i; + UINT8 a; + + cpustate->STATUS &= ~ ST_OP; + + /* We set the parity bit. */ + a = cpustate->lastparity; + + for (i=0; i<8; i++) /* 8 bits to test */ + { + if (a & 1) /* If current bit is set */ + cpustate->STATUS ^= ST_OP; /* we toggle the ST_OP bit */ + + a >>= 1; /* Next bit. */ + } +} + +/* + getstat sets emulator's cpustate->lastparity variable according to 9900's STATUS bits. + It must be called on interrupt return, or when, for some reason, + the emulated program sets the STATUS register directly. +*/ +static void getstat(tms99xx_state *cpustate) +{ +#if (USE_ST_MASK) + cpustate->STATUS &= ST_MASK; /* unused bits are forced to 0 */ +#endif + + if (cpustate->STATUS & ST_OP) + cpustate->lastparity = 1; + else + cpustate->lastparity = 0; + +#if HAS_MAPPING + cpustate->cur_map = (cpustate->STATUS & ST_MF) ? 1 : 0; +#endif +} + +/* + A few words about the following functions. + + A big portability issue is the behavior of the ">>" instruction with the sign bit, which has + not been normalised. Every compiler does whatever it thinks smartest. + My code assumed that when shifting right signed numbers, the operand is left-filled with a + copy of sign bit, and that when shifting unsigned variables, it is left-filled with 0s. + This is probably the most logical behaviour, and it is the behavior of CW PRO3 - most time + (the exception is that ">>=" instructions always copy the sign bit (!)). But some compilers + are bound to disagree. + + So, I had to create special functions with predefined tables included, so that this code work + on every compiler. BUT this is a real slow-down. + So, you might have to include a few lines in assembly to make this work better. + Sorry about this, this problem is really unpleasant and absurd, but it is not my fault. +*/ + + +static const UINT16 right_shift_mask_table[17] = +{ + 0xFFFF, + 0x7FFF, + 0x3FFF, + 0x1FFF, + 0x0FFF, + 0x07FF, + 0x03FF, + 0x01FF, + 0x00FF, + 0x007F, + 0x003F, + 0x001F, + 0x000F, + 0x0007, + 0x0003, + 0x0001, + 0x0000 +}; + +static const UINT16 inverted_right_shift_mask_table[17] = +{ + 0x0000, + 0x8000, + 0xC000, + 0xE000, + 0xF000, + 0xF800, + 0xFC00, + 0xFE00, + 0xFF00, + 0xFF80, + 0xFFC0, + 0xFFE0, + 0xFFF0, + 0xFFF8, + 0xFFFC, + 0xFFFE, + 0xFFFF +}; + +INLINE UINT16 logical_right_shift(UINT16 val, int c) +{ + return((val>>c) & right_shift_mask_table[c]); +} + +INLINE INT16 arithmetic_right_shift(INT16 val, int c) +{ + if (val < 0) + return((val>>c) | inverted_right_shift_mask_table[c]); + else + return((val>>c) & right_shift_mask_table[c]); +} + + + + + +/* + Set lae +*/ +INLINE void setst_lae(tms99xx_state *cpustate, INT16 val) +{ + cpustate->STATUS &= ~ (ST_LGT | ST_AGT | ST_EQ); + + if (val > 0) + cpustate->STATUS |= (ST_LGT | ST_AGT); + else if (val < 0) + cpustate->STATUS |= ST_LGT; + else + cpustate->STATUS |= ST_EQ; +} + + +/* + Set laep (BYTE) +*/ +INLINE void setst_byte_laep(tms99xx_state *cpustate, INT8 val) +{ + cpustate->STATUS &= ~ (ST_LGT | ST_AGT | ST_EQ); + + if (val > 0) + cpustate->STATUS |= (ST_LGT | ST_AGT); + else if (val < 0) + cpustate->STATUS |= ST_LGT; + else + cpustate->STATUS |= ST_EQ; + + cpustate->lastparity = val; +} + +/* + For COC, CZC, and TB +*/ +INLINE void setst_e(tms99xx_state *cpustate, UINT16 val, UINT16 to) +{ + if (val == to) + cpustate->STATUS |= ST_EQ; + else + cpustate->STATUS &= ~ ST_EQ; +} + +/* + For CI, C, CB +*/ +INLINE void setst_c_lae(tms99xx_state *cpustate, UINT16 to, UINT16 val) +{ + cpustate->STATUS &= ~ (ST_LGT | ST_AGT | ST_EQ); + + if (val == to) + cpustate->STATUS |= ST_EQ; + else + { + if ( ((INT16) val) > ((INT16) to) ) + cpustate->STATUS |= ST_AGT; + if ( ((UINT16) val) > ((UINT16) to) ) + cpustate->STATUS |= ST_LGT; + } +} + +/* + Set laeco for add +*/ +INLINE INT16 setst_add_laeco(tms99xx_state *cpustate, int a, int b) +{ + UINT32 res; + INT16 res2; + + cpustate->STATUS &= ~ (ST_LGT | ST_AGT | ST_EQ | ST_C | ST_OV); + + res = (a & 0xffff) + (b & 0xffff); + + if (res & 0x10000) + cpustate->STATUS |= ST_C; + + if ((res ^ b) & (res ^ a) & 0x8000) + cpustate->STATUS |= ST_OV; + +#if (TMS99XX_MODEL == TMS9940_ID) || (TMS99XX_MODEL == TMS9985_ID) + if (((a & b) | ((a | b) & ~ res)) & 0x0800) + cpustate->STATUS |= ST_DC; +#endif + + res2 = (INT16) res; + + if (res2 > 0) + cpustate->STATUS |= ST_LGT | ST_AGT; + else if (res2 < 0) + cpustate->STATUS |= ST_LGT; + else + cpustate->STATUS |= ST_EQ; + + return res2; +} + + +/* + Set laeco for subtract +*/ +INLINE INT16 setst_sub_laeco(tms99xx_state *cpustate, int a, int b) +{ + UINT32 res; + INT16 res2; + + cpustate->STATUS &= ~ (ST_LGT | ST_AGT | ST_EQ | ST_C | ST_OV); + + res = (a & 0xffff) - (b & 0xffff); + + if (! (res & 0x10000)) + cpustate->STATUS |= ST_C; + + if ((a ^ b) & (a ^ res) & 0x8000) + cpustate->STATUS |= ST_OV; + +#if (TMS99XX_MODEL == TMS9940_ID) || (TMS99XX_MODEL == TMS9985_ID) + if (((a & ~ b) | ((a | ~ b) & ~ res)) & 0x0800) + cpustate->STATUS |= ST_DC; +#endif + + res2 = (INT16) res; + + if (res2 > 0) + cpustate->STATUS |= ST_LGT | ST_AGT; + else if (res2 < 0) + cpustate->STATUS |= ST_LGT; + else + cpustate->STATUS |= ST_EQ; + + return res2; +} + + +/* + Set laecop for add (BYTE) +*/ +INLINE INT8 setst_addbyte_laecop(tms99xx_state *cpustate, int a, int b) +{ + unsigned int res; + INT8 res2; + + cpustate->STATUS &= ~ (ST_LGT | ST_AGT | ST_EQ | ST_C | ST_OV | ST_OP); + + res = (a & 0xff) + (b & 0xff); + + if (res & 0x100) + cpustate->STATUS |= ST_C; + + if ((res ^ b) & (res ^ a) & 0x80) + cpustate->STATUS |= ST_OV; + +#if (TMS99XX_MODEL == TMS9940_ID) || (TMS99XX_MODEL == TMS9985_ID) + if (((a & b) | ((a | b) & ~ res)) & 0x08) + cpustate->STATUS |= ST_DC; +#endif + + res2 = (INT8) res; + + if (res2 > 0) + cpustate->STATUS |= ST_LGT | ST_AGT; + else if (res2 < 0) + cpustate->STATUS |= ST_LGT; + else + cpustate->STATUS |= ST_EQ; + + cpustate->lastparity = res2; + + return res2; +} + + +/* + Set laecop for subtract (BYTE) +*/ +INLINE INT8 setst_subbyte_laecop(tms99xx_state *cpustate, int a, int b) +{ + unsigned int res; + INT8 res2; + + cpustate->STATUS &= ~ (ST_LGT | ST_AGT | ST_EQ | ST_C | ST_OV | ST_OP); + + res = (a & 0xff) - (b & 0xff); + + if (! (res & 0x100)) + cpustate->STATUS |= ST_C; + + if ((a ^ b) & (a ^ res) & 0x80) + cpustate->STATUS |= ST_OV; + +#if (TMS99XX_MODEL == TMS9940_ID) || (TMS99XX_MODEL == TMS9985_ID) + if (((a & ~ b) | ((a | ~ b) & ~ res)) & 0x08) + cpustate->STATUS |= ST_DC; +#endif + + res2 = (INT8) res; + + if (res2 > 0) + cpustate->STATUS |= ST_LGT | ST_AGT; + else if (res2 < 0) + cpustate->STATUS |= ST_LGT; + else + cpustate->STATUS |= ST_EQ; + + cpustate->lastparity = res2; + + return res2; +} + + + +/* + For NEG +*/ +INLINE void setst_laeo(tms99xx_state *cpustate, INT16 val) +{ + cpustate->STATUS &= ~ (ST_LGT | ST_AGT | ST_EQ | ST_OV); + + if (val > 0) + cpustate->STATUS |= ST_LGT | ST_AGT; + else if (val < 0) + { + cpustate->STATUS |= ST_LGT; + if (((UINT16) val) == 0x8000) + cpustate->STATUS |= ST_OV; + } + else + cpustate->STATUS |= ST_EQ; +} + + + +/* + Meat of SRA +*/ +INLINE UINT16 setst_sra_laec(tms99xx_state *cpustate, INT16 a, UINT16 c) +{ + cpustate->STATUS &= ~ (ST_LGT | ST_AGT | ST_EQ | ST_C); + + if (c != 0) + { + a = arithmetic_right_shift(a, c-1); + if (a & 1) // The carry bit equals the last bit that is shifted out + cpustate->STATUS |= ST_C; + a = arithmetic_right_shift(a, 1); + } + + if (a > 0) + cpustate->STATUS |= ST_LGT | ST_AGT; + else if (a < 0) + cpustate->STATUS |= ST_LGT; + else + cpustate->STATUS |= ST_EQ; + + return a; +} + + +/* + Meat of SRL. Same algorithm as SRA, except that we fills in with 0s. +*/ +INLINE UINT16 setst_srl_laec(tms99xx_state *cpustate, UINT16 a,UINT16 c) +{ + cpustate->STATUS &= ~ (ST_LGT | ST_AGT | ST_EQ | ST_C); + + if (c != 0) + { + a = logical_right_shift(a, c-1); + if (a & 1) + cpustate->STATUS |= ST_C; + a = logical_right_shift(a, 1); + } + + if (((INT16) a) > 0) + cpustate->STATUS |= ST_LGT | ST_AGT; + else if (((INT16) a) < 0) + cpustate->STATUS |= ST_LGT; + else + cpustate->STATUS |= ST_EQ; + + return a; +} + + +// +// Meat of SRC +// +INLINE UINT16 setst_src_laec(tms99xx_state *cpustate, UINT16 a,UINT16 c) +{ + cpustate->STATUS &= ~ (ST_LGT | ST_AGT | ST_EQ | ST_C); + + if (c != 0) + { + a = logical_right_shift(a, c) | (a << (16-c)); + if (a & 0x8000) // The carry bit equals the last bit that is shifted out + cpustate->STATUS |= ST_C; + } + + if (((INT16) a) > 0) + cpustate->STATUS |= ST_LGT | ST_AGT; + else if (((INT16) a) < 0) + cpustate->STATUS |= ST_LGT; + else + cpustate->STATUS |= ST_EQ; + + return a; +} + + +// +// Meat of SLA +// +INLINE UINT16 setst_sla_laeco(tms99xx_state *cpustate, UINT16 a, UINT16 c) +{ + cpustate->STATUS &= ~ (ST_LGT | ST_AGT | ST_EQ | ST_C | ST_OV); + + if (c != 0) + { + { + register UINT16 mask; + register UINT16 ousted_bits; + + mask = 0xFFFF << (16-c-1); + ousted_bits = a & mask; + + if (ousted_bits) // If ousted_bits is neither all 0s + if (ousted_bits ^ mask) // nor all 1s, + cpustate->STATUS |= ST_OV; // we set overflow + } + + a <<= c-1; + if (a & 0x8000) // The carry bit equals the last bit that is shifted out + cpustate->STATUS |= ST_C; + + a <<= 1; + } + + if (((INT16) a) > 0) + cpustate->STATUS |= ST_LGT | ST_AGT; + else if (((INT16) a) < 0) + cpustate->STATUS |= ST_LGT; + else + cpustate->STATUS |= ST_EQ; + + return a; +} + +/**************************************************************************/ + +static void register_for_save_state(device_t *device) +{ + tms99xx_state *cpustate = get_safe_token(device); + device->save_item(NAME(cpustate->WP)); + device->save_item(NAME(cpustate->PC)); + device->save_item(NAME(cpustate->STATUS)); + device->save_item(NAME(cpustate->interrupt_pending)); + +#if ! ((TMS99XX_MODEL == TMS9940_ID) || (TMS99XX_MODEL == TMS9985_ID)) + device->save_item(NAME(cpustate->load_state)); +#endif + +#if (TMS99XX_MODEL == TI990_10_ID) || (TMS99XX_MODEL == TMS9900_ID) || (TMS99XX_MODEL == TMS9980_ID) + device->save_item(NAME(cpustate->irq_level)); + device->save_item(NAME(cpustate->irq_state)); +#elif (TMS99XX_MODEL == TMS9995_ID) + device->save_item(NAME(cpustate->irq_level)); + device->save_item(NAME(cpustate->int_state)); + device->save_item(NAME(cpustate->int_latch)); +#endif + + device->save_item(NAME(cpustate->IDLE)); + +#if HAS_MAPPING + device->save_item(NAME(cpustate->mapping_on)); + device->save_item(NAME(cpustate->map_files[0].L)); + device->save_item(NAME(cpustate->map_files[0].B)); + device->save_item(NAME(cpustate->map_files[0].limit)); + device->save_item(NAME(cpustate->map_files[0].bias)); + device->save_item(NAME(cpustate->map_files[1].L)); + device->save_item(NAME(cpustate->map_files[1].B)); + device->save_item(NAME(cpustate->map_files[1].limit)); + device->save_item(NAME(cpustate->map_files[1].bias)); + device->save_item(NAME(cpustate->map_files[2].L)); + device->save_item(NAME(cpustate->map_files[2].B)); + device->save_item(NAME(cpustate->map_files[2].limit)); + device->save_item(NAME(cpustate->map_files[2].bias)); + device->save_item(NAME(cpustate->cur_map)); + device->save_item(NAME(cpustate->cur_src_map)); + device->save_item(NAME(cpustate->cur_dst_map)); + +#if (TMS99XX_MODEL == TI990_10_ID) + device->save_item(NAME(cpustate->reset_maperr)); + device->save_item(NAME(cpustate->mapper_address_latch)); + device->save_item(NAME(cpustate->mapper_cru_read_register)); + device->save_item(NAME(cpustate->diaglat)); + device->save_item(NAME(cpustate->latch_control)); +#endif +#endif + +#if (TMS99XX_MODEL == TI990_10_ID) + device->save_item(NAME(cpustate->error_interrupt_register)); +#endif + +#if (TMS99XX_MODEL == TMS9985_ID) || (TMS99XX_MODEL == TMS9995_ID) + device->save_item(NAME(cpustate->RAM)); +#endif + +#if (TMS99XX_MODEL == TMS9940_ID) || (TMS99XX_MODEL == TMS9985_ID) || (TMS99XX_MODEL == TMS9995_ID) + device->save_item(NAME(cpustate->decrementer_enabled)); + device->save_item(NAME(cpustate->decrementer_interval)); + device->save_item(NAME(cpustate->decrementer_count)); +#endif + +#if (TMS99XX_MODEL == TMS9995_ID) + device->save_item(NAME(cpustate->flag)); + device->save_item(NAME(cpustate->MID_flag)); + device->save_item(NAME(cpustate->memory_wait_states_byte)); + device->save_item(NAME(cpustate->memory_wait_states_word)); + device->save_item(NAME(cpustate->is_mp9537)); +#endif + + device->save_item(NAME(cpustate->disable_interrupt_recognition)); +} + + +static CPU_INIT( tms99xx ) +{ + const TMS99XX_RESET_PARAM *param = (const TMS99XX_RESET_PARAM *) device->static_config(); + tms99xx_state *cpustate = get_safe_token(device); + + register_for_save_state(device); + + cpustate->irq_level = 16; + cpustate->irq_callback = irqcallback; + cpustate->device = device; + cpustate->program = &device->space(AS_PROGRAM); + cpustate->io = &device->space(AS_IO); + +#if (TMS99XX_MODEL == TMS9995_ID) + cpustate->timer = device->machine().scheduler().timer_alloc(FUNC(decrementer_callback), cpustate); +#endif + + cpustate->idle_callback = param ? param->idle_callback : NULL; + #if (TMS99XX_MODEL == TI990_10_ID) + cpustate->rset_callback = param ? param->rset_callback : NULL; + cpustate->lrex_callback = param ? param->lrex_callback : NULL; + cpustate->ckon_ckof_callback = param ? param->ckon_ckof_callback : NULL; + + cpustate->error_interrupt_callback = param ? param->error_interrupt_callback : NULL; + #endif + +#if (TMS99XX_MODEL == TMS9995_ID) + /* we can ask at reset time that the CPU always generates one wait state automatically */ + if (param == NULL) + { /* if no param, the default is currently "wait state added" */ + cpustate->memory_wait_states_byte = 4; + cpustate->memory_wait_states_word = 12; + cpustate->is_mp9537 = 0; + } + else + { + cpustate->memory_wait_states_byte = (param->auto_wait_state) ? 4 : 0; + cpustate->memory_wait_states_word = (param->auto_wait_state) ? 12 : 4; + cpustate->is_mp9537 = param->is_mp9537; + } +#endif + +} + +/* + TMS9900 hard reset +*/ +static CPU_RESET( tms99xx ) +{ + tms99xx_state *cpustate = get_safe_token(device); + + cpustate->STATUS = 0; /* TMS9980 and TMS9995 Data Books say so */ + getstat(cpustate); + + #if HAS_MAPPING + cpustate->mapping_on = 0; + { + int i,j; + + for (i=0; i<3; i++) + for (j=0; j<3; j++) + { + cpustate->map_files[i].L[j] = 0; + cpustate->map_files[i].limit[j] = 0xffff; + cpustate->map_files[i].B[j] = 0; + cpustate->map_files[i].bias[j] = 0; + } + } + cpustate->cur_map = 0; /* equivalent to ST_MF status bit */ + cpustate->cur_src_map = 0; /* set to 2 by LDS */ + cpustate->cur_dst_map = 0; /* set to 2 by LDD */ + + cpustate->reset_maperr = 0; + #endif + + if (cpustate->IDLE) + { + cpustate->IDLE = 0; /* clear IDLE condition */ + if (cpustate->idle_callback) + (*cpustate->idle_callback)(device, 0); + } + +#if (TMS99XX_MODEL == TMS9995_ID) + cpustate->MID_flag = 0; + + /* Clear flag bits 0 & 1 */ + set_flag0(cpustate, 0); + set_flag1(cpustate, 0); + + /* Clear internal interrupt latches */ + cpustate->int_latch = 0; + cpustate->flag &= 0xFFE3; +#endif + + /* The ST register and interrupt latches changed, didn't they ? */ + field_interrupt(cpustate); + + contextswitchX(cpustate, 0x0000); + + CYCLES(6, 26, 14); +} + +static CPU_EXIT( tms99xx ) +{ + /* nothing to do ? */ +} + +/* fetch : read one word at * PC, and increment PC. */ +INLINE UINT16 fetch(tms99xx_state *cpustate) +{ + UINT16 value = readword(cpustate, cpustate->PC); + cpustate->PC += 2; + return value; +} + + +static CPU_EXECUTE( tms99xx ) +{ + tms99xx_state *cpustate = get_safe_token(device); + + cpustate->lds_flag = 0; + cpustate->ldd_flag = 0; + + do + { + /* all TMS9900 chips I know do not honor interrupts after XOP, BLWP or MID (after any + interrupt-like instruction, actually), and they do not either after LDS and LDD + (There are good reasons for this). */ + if ((cpustate->interrupt_pending) && (! cpustate->disable_interrupt_recognition)) + { + int level; + + level = cpustate->irq_level; + + + if (cpustate->load_state) + { /* LOAD has the highest priority */ + + contextswitchX(cpustate, 0xFFFC); /* load vector, save PC, WP and ST */ + + cpustate->STATUS &= ~ST_IM; /* clear interrupt mask */ + + /* clear IDLE status if necessary */ + if (cpustate->IDLE) + { + cpustate->IDLE = 0; /* clear IDLE condition */ + if (cpustate->idle_callback) + (*cpustate->idle_callback)(device, 0); + } + + CYCLES(6/*to be confirmed*/, 22, 14); + } + else if (level <= IMASK) + { /* a maskable interrupt is honored only if its level isn't greater than IMASK */ + + contextswitchX(cpustate, level*4); /* load vector, save PC, WP and ST */ + + /* change interrupt mask */ + if (level) + { + cpustate->STATUS = (cpustate->STATUS & ~ST_IM) | (level -1); /* decrement mask */ + cpustate->interrupt_pending = 0; /* as a consequence, the interrupt request will be subsequently ignored */ + } + else + cpustate->STATUS &= ~ST_IM; /* clear mask (is this correct???) */ + +#if (TMS99XX_MODEL == TMS9995_ID) + cpustate->STATUS &= 0xFE00; +#endif + + /* clear IDLE status if necessary */ + if (cpustate->IDLE) + { + cpustate->IDLE = 0; /* clear IDLE condition */ + if (cpustate->idle_callback) + (*cpustate->idle_callback)(device, 0); + } + +#if (TMS99XX_MODEL == TMS9995_ID) + /* Clear bit in latch */ + /* I think tms9989 does this, too */ + if (level != 2) + { /* Only do this on level 1, 3, 4 interrupts */ + int mask = 1 << level; + int flag_mask = (level == 1) ? 4 : mask; + + cpustate->int_latch &= ~ mask; + cpustate->flag &= ~ flag_mask; + + /* unlike tms9900, we can call the callback */ + if (level == 1) + (* cpustate->irq_callback)(cpustate->device, 0); + else if (level == 4) + (* cpustate->irq_callback)(cpustate->device, 1); + } +#endif + + CYCLES(6, 22, 14); + } + else + { + logerror("tms9900l.c : the interrupt_pending flag was set incorrectly\n"); + cpustate->interrupt_pending = 0; + } + } + + debugger_instruction_hook(device, cpustate->PC); + + if (cpustate->IDLE) + { /* IDLE instruction has halted execution */ + #if EXTERNAL_INSTRUCTION_DECODING + external_instruction_notify(cpustate, 2); + CYCLES(Moof!, 2, 2); /* 2 cycles per CRU write */ + #else + cpustate->icount = 0; /* much simpler... */ + #endif + } + else + { /* we execute an instruction */ + cpustate->disable_interrupt_recognition = 0; /* default value */ + cpustate->IR = fetch(cpustate); + execute(cpustate, cpustate->IR); + #if HAS_MAPPING + if (cpustate->lds_flag) + { + cpustate->lds_flag = 0; + cpustate->cur_src_map = 2 /*(cpustate->cur_src_map != 2) ? 2 : cpustate->cur_map*/; + } + else + cpustate->cur_src_map = cpustate->cur_map; + if (cpustate->ldd_flag) + { + cpustate->ldd_flag = 0; + cpustate->cur_dst_map = 2 /*(cpustate->cur_src_map != 2) ? 2 : cpustate->cur_map*/; + } + else + cpustate->cur_dst_map = cpustate->cur_map; + #if (TMS99XX_MODEL == TI990_10_ID) + cpustate->write_inhibit = 0; + #endif + #endif + + #if (HAS_OVERFLOW_INTERRUPT) + #if (TMS99XX_MODEL == TMS9995_ID) + /* Note that TI had some problem implementing this... I don't know if this feature works on + a real-world TMS9995. */ + if ((cpustate->STATUS & ST_OVIE) && (cpustate->STATUS & ST_OV) && (cpustate->irq_level > 2)) + cpustate->irq_level = 2; /* interrupt request */ + #else + #warning "todo..." + #endif + #endif + } + + } while (cpustate->icount > 0); +} + +#if (TMS99XX_MODEL == TI990_10_ID) + +static void tms99xx_set_irq_line(tms99xx_state *cpustate, int irqline, int state) +{ + if (irqline == INPUT_LINE_NMI) + { + cpustate->load_state = state; /* save new state */ + + field_interrupt(cpustate); /* interrupt status changed */ + } + else + { + /*if (cpustate->irq_state == state) + return;*/ + + cpustate->irq_state = state; + + if (state == CLEAR_LINE) + cpustate->irq_level = 16; + /* trick : 16 will always be bigger than the IM (0-15), so there will never be interrupts */ + else + cpustate->irq_level = (* cpustate->irq_callback)(cpustate->device, 0); + + field_interrupt(cpustate); /* interrupt state is likely to have changed */ + } +} + +#elif (TMS99XX_MODEL == TMS9900_ID) + +/* +void tms99xx_set_irq_line(cpustate, INPUT_LINE_NMI, int state) : change the state of the LOAD* line + + state == 0 -> LOAD* goes high (inactive) + state != 0 -> LOAD* goes low (active) + + While LOAD* is low, we keep triggering LOAD interrupts... + + A problem : some peripherals lower the LOAD* line for a fixed time interval (causing the 1st + instruction of the LOAD interrupt routine to be repeated while the line is low), and will be + perfectly happy with the current scheme, but others might be more clever and wait for the IAQ + (Instruction acquisition) line to go high, and this needs a callback function to emulate. +*/ + +/* +void tms99xx_set_irq_line(cpustate, int irqline, int state) : sets the state of the interrupt line. + + irqline is ignored, and should always be 0. + + state == 0 -> INTREQ* goes high (inactive) + state != 0 -> INTREQ* goes low (active) +*/ +/* + R Nabet 991020, revised 991218 : + In short : interrupt code should call "cpu_set_irq_line(0, 0, ASSERT_LINE);" to set an + interrupt request (level-triggered interrupts). Also, there MUST be a call to + "cpu_set_irq_line(0, 0, CLEAR_LINE);" in the machine code, when the interrupt line is released by + the hardware (generally in response to an action performed by the interrupt routines). + On tms9995 (9989 ?), you can use PULSE_LINE, too, since the processor latches the line... + + **Note** : HOLD_LINE *NEVER* makes sense on the TMS9900 (or 9980, 9995...). The reason is the + TMS9900 does NOT tell the world it acknoledges an interrupt, so no matter how much hardware you + use, you cannot know when the CPU takes the interrupt, hence you cannot release the line when + the CPU takes the interrupt. Generally, the interrupt condition is cleared by the interrupt + routine (with some CRU or memory access). + + Note that cpu_generate_interrupt uses HOLD_LINE, so your driver interrupt code + should always use the new style, i.e. return "ignore_interrupt(cpustate)" and call + "cpu_set_irq_line(0, 0, ASSERT_LINE);" explicitely. + + Last, many TMS9900-based hardware use a TMS9901 interrupt-handling chip. If anybody wants + to emulate some hardware which uses it, note that I am writing some emulation in the TI99/4(A) + driver in MESS, so you should ask me. +*/ +/* + * HJB 990430: changed to use irq_callback(cpustate) to retrieve the vector + * instead of using 16 irqlines. + * + * R Nabet 990830 : My mistake, I rewrote all these once again ; I think it is now correct. + * A driver using the TMS9900 should do : + * cpu_0_irq_line_vector_w(0, level); + * cpu_set_irq_line(0,0,ASSERT_LINE); + * + * R Nabet 991108 : revised once again, with advice from Juergen Buchmueller, after a discussion + * with Nicola... + * We use the callback to retreive the interrupt level as soon as INTREQ* is asserted. + * As a consequence, I do not support HOLD_LINE normally... However, we do not really have to + * support HOLD_LINE, since no real world TMS9900-based system can support this. + * FYI, there are two alternatives to retreiving the interrupt level with the callback : + * a) using 16 pseudo-IRQ lines. Mostly OK, though it would require a few core changes. + * However, this could cause some problems if someone tried to set two lines simulteanously... + * And TMS9900 did NOT have 16 lines ! This is why Juergen and I did not retain this solution. + * b) modifying the interrupt system in order to provide an extra int to every xxx_set_irq_line + * function. I think this solution would be fine, but it would require quite a number of + * changes in the MAME core. (And I did not feel the courage to check out 4000 drivers and 25 + * cpu cores ;-) .) + * + * Note that this does not apply to tms9995. +*/ +static void tms99xx_set_irq_line(tms99xx_state *cpustate, int irqline, int state) +{ + if (irqline == INPUT_LINE_NMI) + { + cpustate->load_state = state; /* save new state */ + + field_interrupt(cpustate); /* interrupt status changed */ + } + else + { + /*if (cpustate->irq_state == state) + return;*/ + + cpustate->irq_state = state; + + if (state == CLEAR_LINE) + cpustate->irq_level = 16; + /* trick : 16 will always be bigger than the IM (0-15), so there will never be interrupts */ + else + cpustate->irq_level = (* cpustate->irq_callback)(cpustate->device, 0); + + field_interrupt(cpustate); /* interrupt state is likely to have changed */ + } +} + +#elif (TMS99XX_MODEL == TMS9980_ID) +/* + interrupt system similar to tms9900, but only 3 interrupt pins (IC0-IC2) +*/ + +static void tms99xx_set_irq_line(tms99xx_state *cpustate, int irqline, int state) +{ + if (state == CLEAR_LINE) + { + cpustate->load_state = 0; + cpustate->irq_state = 0; + cpustate->irq_level = 16; + /* trick : 16 will always be bigger than the IM (0-15), so there will never be interrupts */ + } + else + { + int level; + + if (irqline == INPUT_LINE_NMI) + level = 2; /* translate MAME's convention to CPU's representation */ + else + level = (* cpustate->irq_callback)(cpustate->device, 0); + + switch (level) + { + case 0: + case 1: + cpustate->load_state = 0; + cpustate->irq_state = 0; + cpustate->irq_level = 16; + CPU_RESET_NAME(tms99xx)(cpustate->device); + break; + case 2: + cpustate->load_state = 1; + cpustate->irq_state = 0; + cpustate->irq_level = 16; + break; + case 7: + cpustate->load_state = 0; + cpustate->irq_state = 0; + cpustate->irq_level = 16; + break; + default: /* external levels 1, 2, 3, 4 */ + cpustate->load_state = 0; + cpustate->irq_state = 1; + cpustate->irq_level = level - 2; + break; + } + } + + field_interrupt(cpustate); /* interrupt state is likely to have changed */ +} + +#elif (TMS99XX_MODEL == TMS9940_ID) || (TMS99XX_MODEL == TMS9985_ID) +/* + 2 interrupt pins (int1 and int2) +*/ + +static void tms99xx_set_irq_line(tms99xx_state *cpustate, int irqline, int state) +{ + int mask; + + if (irqline == 0) + /* INT1 */ + mask = 1; + else if (irqline == 1) + /* INT2 */ + mask = 4; + else + /* What on earth??? */ + return; + + if (state) + cpustate->irq_state |= mask; + else + cpustate->irq_state &= ~mask; + + field_interrupt(cpustate); /* interrupt state is likely to have changed */ +} + +#elif (TMS99XX_MODEL == TMS9995_ID) +/* + this call-back is called by MESS timer system when the timer reaches 0. +*/ +static TIMER_CALLBACK( decrementer_callback ) +{ + tms99xx_state *cpustate = (tms99xx_state *)ptr; + + /* request decrementer interrupt */ + cpustate->int_latch |= 0x8; + cpustate->flag |= 0x8; + + field_interrupt(cpustate); +} + + +/* + reset and load the timer/decrementer + + Note that I don't know whether toggling flag0/flag1 causes the decrementer to be reloaded or not +*/ +static void reset_decrementer(tms99xx_state *cpustate) +{ + cpustate->timer->adjust(attotime::never); + + /* reload count */ + cpustate->decrementer_count = cpustate->decrementer_interval; + + /* decrementer / timer enabled ? */ + cpustate->decrementer_enabled = ((cpustate->flag & 2) && (cpustate->decrementer_interval)); + + if (cpustate->decrementer_enabled && ! (cpustate->flag & 1)) + { /* timer */ + attotime period = cpustate->device->cycles_to_attotime(cpustate->decrementer_interval * 16L); + cpustate->timer->adjust(period, 0, period); + } +} + +/* + You have two interrupt line : one triggers level-1 interrupts, the other triggers level-4 + interrupts (or decrements the decrementer register). + + According to the hardware, you may use PULSE_LINE (edge-triggered interrupts), or ASSERT_LINE + (level-triggered interrupts). Edge-triggered interrupts are way simpler, but if multiple devices + share the same line, they must use level-triggered interrupts. +*/ +static void tms99xx_set_irq_line(tms99xx_state *cpustate, int irqline, int state) +{ + if (irqline == INPUT_LINE_NMI) + { + cpustate->load_state = state; /* save new state */ + + field_interrupt(cpustate); /* interrupt status changed */ + } + else + { + int mask = (irqline == 0) ? 0x2 : 0x10; + int flag_mask = (irqline == 0) ? 0x4 : 0x10; + + if (((cpustate->int_state & mask) != 0) ^ (state != 0)) + { /* only if state changes */ + if (state) + { + cpustate->int_state |= mask; + + if ((irqline == 1) && (cpustate->flag & 1)) + { /* event counter mode : INT4* triggers no interrupt... */ + if (cpustate->decrementer_enabled) + { /* decrement, then interrupt if reach 0 */ + if ((-- cpustate->decrementer_count) == 0) + { + decrementer_callback(cpustate->device->machine(), cpustate, 0); + cpustate->decrementer_count = cpustate->decrementer_interval; /* reload */ + } + } + } + else + { /* plain interrupt mode */ + cpustate->int_latch |= mask; + cpustate->flag |= flag_mask; + } + } + else + { + cpustate->int_state &= ~ mask; + } + + field_interrupt(cpustate); /* interrupt status changed */ + } + } +} + +#else + +#error "interrupt system not implemented" + +#endif + +/* + * field_interrupt + * + * Determines whether if an interrupt is pending, and sets the relevant flag. + * + * Called when an interrupt pin (LOAD*, INTREQ*, IC0-IC3) is changed, and when the interrupt mask + * is modified. + * + * By using this flag, we save some compares in the execution loop. Subtle, isn't it ;-) ? + * + * R Nabet. + */ +#if (TMS99XX_MODEL == TI990_10_ID) || (TMS99XX_MODEL == TMS9900_ID) || (TMS99XX_MODEL == TMS9980_ID) + +static void field_interrupt(tms99xx_state *cpustate) +{ + cpustate->interrupt_pending = ((cpustate->irq_level <= IMASK) || (cpustate->load_state)); +} + +#elif (TMS99XX_MODEL == TMS9940_ID) || (TMS99XX_MODEL == TMS9985_ID) + +static void field_interrupt(tms99xx_state *cpustate) +{ + if (cpustate->irq_state & 1) + cpustate->irq_level = 1; + else if (cpustate->irq_state & 2) + cpustate->irq_level = 2; + else if (cpustate->irq_state & 4) + cpustate->irq_level = 3; + else + cpustate->irq_level = 4; + /* trick : 4 will always be bigger than the IM (0-3), so there will never be interrupts */ + + cpustate->interrupt_pending = ((cpustate->irq_level <= IMASK) || (cpustate->load_state)); +} + +#elif (TMS99XX_MODEL == TMS9995_ID) + +static void field_interrupt(tms99xx_state *cpustate) +{ + if (cpustate->load_state) + { + cpustate->interrupt_pending = 1; + } + else + { + int current_int; + int level; + + if (cpustate->flag & 1) + /* event counter mode : ignore int4* line... */ + current_int = (cpustate->int_state & ~0x10) | cpustate->int_latch; + else + /* normal behavior */ + current_int = cpustate->int_state | cpustate->int_latch; + + if (current_int) + /* find first bit to 1 */ + /* possible values : 1, 3, 4 */ + for (level=0; ! (current_int & 1); current_int >>= 1, level++) + ; + else + level=16; + + cpustate->irq_level = level; + + cpustate->interrupt_pending = (level <= IMASK); + } +} + +#else + +#error "field_interrupt(cpustate) not written" + +#endif + +static CPU_DISASSEMBLE( tms99xx ) +{ + extern unsigned Dasm9900 (char *buffer, unsigned pc, int model_id, const UINT8 *oprom, const UINT8 *opram); + return Dasm9900(buffer, pc, TMS99XX_MODEL, oprom, opram); +} + + +/*****************************************************************************/ +/* + CRU support code + + The CRU bus is a 1-bit-wide I/O bus. The CPU can read or write bits at random address. + Special instructions are dedicated to reading and writing one or several consecutive bits. + + + + Note that TMS99000 additionally supports parallel CRU operations, although I don't know how + this feature is implemented. +*/ + +enum +{ +#if (TMS99XX_MODEL == TI990_10_ID) + /* 3 MSBs do exist, although they are not connected (don't ask...) */ + CRUAddrBit = 15 +#elif (TMS99XX_MODEL == TMS9900_ID) + /* 3 MSBs are always 0 to support external instructions */ + CRUAddrBit = 12 +#elif (TMS99XX_MODEL == TMS9980_ID) + /* 2 bits unused, and 2 MSBs are always 0 to support external instructions */ + CRUAddrBit = 11 +#elif (TMS99XX_MODEL == TMS9940_ID) + /* 9 internal address lines (8 external) */ + CRUAddrBit = 9 +#elif (TMS99XX_MODEL == TMS9995_ID) + /* no such problem here : data bus lines D0-D2 provide the external instruction code */ + CRUAddrBit = 15 +#else + #warning "I don't know how your processor handles CRU." + CRUAddrBit = 15 +#endif +}; + +enum +{ + rCRUAddrMask = (1 << (CRUAddrBit - 3)) - 1, + wCRUAddrMask = (1 << CRUAddrBit) - 1 +}; + + +#if (TMS99XX_MODEL == TMS9995_ID) + +/* set decrementer mode flag */ +static void set_flag0(tms99xx_state *cpustate, int val) +{ + if (val) + cpustate->flag |= 1; + else + cpustate->flag &= ~ 1; + + reset_decrementer(cpustate); +} + +/* set decrementer enable flag */ +static void set_flag1(tms99xx_state *cpustate, int val) +{ + if (val) + cpustate->flag |= 2; + else + cpustate->flag &= ~ 2; + + reset_decrementer(cpustate); +} + +#endif + +enum cru_error_code +{ + CRU_OK = 0, + CRU_PRIVILEGE_VIOLATION = -1 +}; + +#define WRITEPORT(cs, port, data) (cs)->io->write_byte(port, data) + +#if (TMS99XX_MODEL == TMS9940_ID) || (TMS99XX_MODEL == TMS9985_ID) +/* on tms9940, we have to handle internal CRU ports */ +static void write_single_CRU(tms99xx_state *cpustate, int port, int data) +{ + int mask; + + if (! (port & 0x100)) + { + /*if (cpustate->config & CB0)*/ + /* External CRU */ + WRITEPORT(cpustate, port, (data & 0x01)); + } + else + { + /* internal CRU */ + switch ((port >> 4) & 0xf) + { + case 0x8: + if (port == 0x181) + { + /* clear decrementer interrupt */ + cpustate->irq_state &= ~2; + } + if (port >= 0x183) && (port <= 0x186) + { + /* write configuration register */ + mask = 1 << (port - 0x183); + /* ... */ + } + break; + + case 0x9: + if (port <= 0x19D) + { + /* write decrementer latch */ + mask = 1 << (port - 0x190); + /* ... */ + } + else if (port == 0x19E) + { + /* set decrementer as timer (1) or event counter (0) */ + /* ... */ + } + break; + + case 0xA: + /* multiprocessor system interface */ + mask = 1 << (port - 0x1A0); + /* ... */ + break; + + case 0xB: + /* flags */ + mask = 1 << (port - 0x1B0); + /* ... */ + break; + + case 0xC: + case 0xD: + /* direction for P0-P31 */ + mask = 1 << (port - 0x1C0); + /* ... */ + break; + + case 0xE: + case 0xF: + /* data for P0-P31 */ + mask = 1 << (port - 0x1E0); + /* ... */ + break; + } + } +} +#elif (TMS99XX_MODEL == TMS9995_ID) +/* on tms9995, we have to handle internal CRU ports */ +static void write_single_CRU(tms99xx_state *cpustate, int port, int data) +{ + /* Internal CRU */ + switch (port) + { + case 0xF70: + set_flag0(cpustate, data & 0x01); + break; + case 0xF71: + set_flag1(cpustate, data & 0x01); + break; + case 0xF72: + case 0xF73: + case 0xF74: + break; /* ignored */ + case 0xF75: + case 0xF76: + case 0xF77: + case 0xF78: + case 0xF79: + case 0xF7A: + case 0xF7B: + case 0xF7C: + case 0xF7D: + case 0xF7E: + case 0xF7F: + { /* user defined flags */ + int mask = 1 << (port - 0xF70); + if (data & 0x01) + cpustate->flag |= mask; + else + cpustate->flag &= ~ mask; + } + break; + + case 0x0FED: + /* MID flag */ + cpustate->MID_flag = data & 0x01; + break; + } + /* External CRU */ + /* Even though all the registers above are implemented internally, accesses + are passed to the external bus, too, and an external device might respond + to a write to these CRU address as well (particularly a write to the user + flag registers). */ + WRITEPORT(cpustate, port, (data & 0x01)); +} +#else +#define write_single_CRU(cs, port, data) WRITEPORT(cs, port, data) +#endif + +/* + performs a normal write to CRU bus (used by SBZ, SBO, LDCR : address range 0 -> 0xFFF) +*/ +static cru_error_code writeCRU(tms99xx_state *cpustate, int CRUAddr, int Number, UINT16 Value) +{ + int count; + + /*logerror("PC %4.4x Write CRU %x for %x =%x\n",cpustate->PC,CRUAddr,Number,Value);*/ + + CRUAddr &= wCRUAddrMask; + + /* Write Number bits from CRUAddr */ + + for(count=0; countSTATUS & ST_PR) && (CRUAddr >= 0xE00)) + return CRU_PRIVILEGE_VIOLATION; + #endif + + write_single_CRU(cpustate, CRUAddr, (Value & 0x01)); + Value >>= 1; + CRUAddr = (CRUAddr + 1) & wCRUAddrMask; + } + + return CRU_OK; +} + +#if EXTERNAL_INSTRUCTION_DECODING +/* + Some opcodes perform a dummy write to a special CRU address, so that an external function may be + triggered. + + Only the first 3 MSBs of the address matter : other address bits and the written value itself + are undefined. + + How should we support this ? With callback functions ? Actually, as long as we do not support + hardware which makes use of this feature, it does not really matter :-) . +*/ +static void external_instruction_notify(tms99xx_state *cpustate, int ext_op_ID) +{ +#if 1 + /* I guess we can support this like normal CRU operations */ +#if (TMS99XX_MODEL == TMS9900_ID) + WRITEPORT(cpustate, ext_op_ID << 12, 0); /* or is it 1 ??? */ +#elif (TMS99XX_MODEL == TMS9980_ID) + WRITEPORT(cpustate, (ext_op_ID & 3) << 11, (ext_op_ID & 4) ? 1 : 0); +#elif (TMS99XX_MODEL == TMS9995_ID) + WRITEPORT(cpustate, ext_op_ID << 15, 0); /* or is it 1 ??? */ +#else + #warning "I don't know how your processor handles external opcodes (maybe you don't need them, though)." +#endif + +#else + switch (ext_op_ID) + { + case 2: /* IDLE */ + + break; + case 3: /* RSET */ + + break; + case 5: /* CKON */ + + break; + case 6: /* CKOF */ + + break; + case 7: /* LREX */ + + break; + case 0: + /* normal CRU write !!! */ + logerror("PC %4.4x : external_instruction_notify : wrong ext_op_ID",cpustate->PC); + break; + default: + /* unknown address */ + logerror("PC %4.4x : external_instruction_notify : unknown ext_op_ID",cpustate->PC); + break; + } +#endif +} +#endif + +/* + performs a normal read to CRU bus (used by TB, STCR : address range 0->0xFFF) + + Note that on some hardware, e.g. TI99/4(a), all normal memory operations cause unwanted CRU + read at the same address. This seems to be impossible to emulate efficiently, so, if you need + to emulate this, you're in trouble. +*/ +#define READPORT(cs, port) (cs)->io->read_byte(port) + + +#if (TMS99XX_MODEL == TMS9940_ID) || (TMS99XX_MODEL == TMS9985_ID) +/* on tms9940, we have to handle internal CRU ports */ +static int read_single_CRU(tms99xx_state *cpustate, int port) +{ + int reply; + int shift; + + if (! (port & 0x20)) + { + /*if (cpustate->config & CB0)*/ + /* External CRU */ + reply = READPORT(cpustate, port, (data & 0x01)); + } + else + { + /* internal CRU */ + switch (port) + { + case 0x10: + /* read interrupt state */ + reply = cpustate->irq_state; + break; + + case 0x12: + /* read decrementer LSB */ + /* ... */ + break; + case 0x13: + /* read decrementer MSB */ + /* ... */ + break; + + case 0x14: + /* read multiprocessor system interface LSB */ + /* ... */ + break; + case 0x15: + /* read multiprocessor system interface MSB */ + /* ... */ + break; + + case 0x16: + /* read flags LSB */ + /* ... */ + break; + case 0x17: + /* read flags MSB */ + /* ... */ + break; + + case 0x18: + case 0x19: + case 0x1A: + case 0x1B: + /* direction for P0-P31 */ + shift = (port - 0x18) << 3; + /* ... */ + break; + + case 0x1C: + case 0x1D: + case 0x1E: + case 0x1F: + /* data for P0-P31 */ + shift = (port - 0x1C) << 3; + /* ... */ + break; + + default: + reply = 0; + break; + } + } + + return reply; +} +#elif (TMS99XX_MODEL == TMS9995_ID) +/* on tms9995, we have to handle internal CRU ports */ +static int read_single_CRU(tms99xx_state *cpustate, int port) +{ + switch (port) + { + case 0x1EE: + /* flag, bits 0-7 */ + return cpustate->flag & 0xFF; + case 0x1EF: + /* flag, bits 8-15 */ + return (cpustate->flag >> 8) & 0xFF; + case 0x1FD: + /* MID flag, and external devices */ + if (cpustate->MID_flag) + return READPORT(cpustate, port) | 0x10; + else + return READPORT(cpustate, port) & ~ 0x10; + default: + /* external devices */ + return READPORT(cpustate, port); + } +} +#else +#define read_single_CRU(cs, port) READPORT(cs, port) +#endif + +static int readCRU(tms99xx_state *cpustate, int CRUAddr, int Number) +{ + static const int BitMask[] = + { + 0, /* filler - saves a subtract to find mask */ + 0x0001,0x0003,0x0007,0x000F,0x001F,0x003F,0x007F,0x00FF, + 0x01FF,0x03FF,0x07FF,0x0FFF,0x1FFF,0x3FFF,0x7FFF,0xFFFF + }; + + int Offset,Location,Value; + + /*logerror("Read CRU %x for %x\n",CRUAddr,Number);*/ + + Location = (CRUAddr >> 3) & rCRUAddrMask; + Offset = CRUAddr & 07; + + /* Read 8 bits */ + #if HAS_PRIVILEGE + if ((cpustate->STATUS & ST_PR) && (Location >= (0xE00 >> 3))) + return CRU_PRIVILEGE_VIOLATION; + #endif + Value = read_single_CRU(cpustate, Location); + + if ((Offset+Number) > 8) + { + /* Read next 8 bits */ + Location = (Location + 1) & rCRUAddrMask; + #if HAS_PRIVILEGE + if ((cpustate->STATUS & ST_PR) && (Location >= (0xE00 >> 3))) + return CRU_PRIVILEGE_VIOLATION; + #endif + Value |= read_single_CRU(cpustate, Location) << 8; + + if ((Offset+Number) > 16) + { + /* Read next 8 bits */ + Location = (Location + 1) & rCRUAddrMask; + #if HAS_PRIVILEGE + if ((cpustate->STATUS & ST_PR) && (Location >= (0xE00 >> 3))) + return CRU_PRIVILEGE_VIOLATION; + #endif + Value |= read_single_CRU(cpustate, Location) << 16; + } + } + + /* Allow for Offset */ + Value >>= Offset; + + /* Mask out what we want */ + Value &= BitMask[Number]; + + /* And update */ + return Value; +} + +/*****************************************************************************/ + +#if HAS_MAPPING +/* load a map file from memory */ +static void load_map_file(tms99xx_state *cpustate, UINT16 src_addr, int src_map_file, int dst_file) +{ + int i; + + + /* load mapped address into the memory address register */ + if ((src_map_file == 0) && (src_addr >= 0xf800)) + { /* intercept TPCS and CPU ROM */ + if (src_addr < 0xfc00) + /* TPCS */ + cpustate->mapper_address_latch = 0x1f0000+src_addr; + else + /* CPU ROM */ + cpustate->mapper_address_latch = 0x1f0000+src_addr; /* hack... */ + } + else if (! cpustate->mapping_on) + { + cpustate->mapper_address_latch = src_addr; + } + else + { + int map_index; + + if (src_addr <= cpustate->map_files[src_map_file].limit[0]) + map_index = 0; + else if (src_addr <= cpustate->map_files[src_map_file].limit[1]) + map_index = 1; + else if (src_addr <= cpustate->map_files[src_map_file].limit[2]) + map_index = 2; + else + { + if ((! cpustate->reset_maperr) && ! (cpustate->error_interrupt_register & EIR_MAPERR)) + { + cpustate->error_interrupt_register |= EIR_MAPERR; + cpustate->write_inhibit = 1; + } + cpustate->mapper_address_latch = src_addr; + map_index = -1; + } + if (map_index != -1) + cpustate->mapper_address_latch = cpustate->map_files[src_map_file].bias[map_index]+src_addr; + } + + + for (i=0; i<3; i++) + { + cpustate->map_files[dst_file].L[i] = cpustate->program->read_word(cpustate->mapper_address_latch) & 0xffe0; + cpustate->map_files[dst_file].limit[i] = (cpustate->map_files[dst_file].L[i] ^ 0xffe0) | 0x001f; + cpustate->mapper_address_latch = (cpustate->mapper_address_latch+2) & 0x1fffff; + cpustate->map_files[dst_file].B[i] = cpustate->program->read_word(cpustate->mapper_address_latch); + cpustate->map_files[dst_file].bias[i] = ((unsigned int) cpustate->map_files[dst_file].B[i]) << 5; + cpustate->mapper_address_latch = (cpustate->mapper_address_latch+2) & 0x1fffff; + } +} +#endif + +/* contextswitch : performs a BLWP, i.e. load PC, WP, and save old PC, old WP and ST... */ +static void contextswitch(tms99xx_state *cpustate, UINT16 addr) +{ + UINT16 oldWP, oldpc; + + /* save old state */ + oldWP = cpustate->WP; + oldpc = cpustate->PC; + + /* load vector */ + cpustate->WP = readword(cpustate, addr) & ~1; + cpustate->PC = readword(cpustate, addr+2) & ~1; + + /* write old state to regs */ + WRITEREG(R13, oldWP); + WRITEREG(R14, oldpc); + setstat(cpustate); + WRITEREG(R15, cpustate->STATUS); +} + +#if HAS_MAPPING || HAS_PRIVILEGE + +/* privileged context switch, that occurs after a reset, interrupt or XOP: +we enter privileged mode and select map file 0 before doing the context switch */ +/* For CPU that have no privilege support, contextswitchX would behave +identically to contextswitch, so we can call contextswitch in all cases. */ +static void contextswitchX(tms99xx_state *cpustate, UINT16 addr) +{ + UINT16 oldWP, oldpc, oldST; + + /* save old state */ + oldWP = cpustate->WP; + oldpc = cpustate->PC; + setstat(cpustate); + oldST = cpustate->STATUS; + + /* enter privileged mode and select map file 0 */ + #if HAS_PRIVILEGE + cpustate->STATUS &= ~ ST_PR; + #endif + #if HAS_MAPPING + cpustate->STATUS &= ~ ST_MF; + #endif + getstat(cpustate); + + /* load vector */ + cpustate->WP = readword(cpustate, addr) & ~1; + cpustate->PC = readword(cpustate, addr+2) & ~1; + + /* write old state to regs */ + WRITEREG(R13, oldWP); + WRITEREG(R14, oldpc); + WRITEREG(R15, oldST); +} + +#endif + +/* + * decipheraddr : compute and return the effective address in word instructions. + * + * NOTA : the LSBit is always ignored in word addresses, + * but we do not set it to 0 because of XOP... + */ +static UINT16 decipheraddr(tms99xx_state *cpustate, UINT16 opcode) +{ + register UINT16 ts = opcode & 0x30; + register UINT16 reg = opcode & 0xF; + + reg += reg; + + if (ts == 0) + /* Rx */ + return(reg + cpustate->WP); + else if (ts == 0x10) + { /* *Rx */ + CYCLES(0, 4, 1); + return(readword(cpustate, reg + cpustate->WP)); + } + else if (ts == 0x20) + { + register UINT16 imm; + + imm = fetch(cpustate); + + if (reg) + { /* @>xxxx(Rx) */ + CYCLES(1, 8, 3); + return(readword(cpustate, reg + cpustate->WP) + imm); + } + else + { /* @>xxxx */ + CYCLES(3, 8, 1); + return(imm); + } + } + else /*if (ts == 0x30)*/ + { /* *Rx+ */ + register UINT16 response; + + reg += cpustate->WP; /* reg now contains effective address */ + + CYCLES(1, 8, 3); + + response = readword(cpustate, reg); + writeword(cpustate, reg, response+2); /* we increment register content */ + return(response); + } +} + +/* decipheraddrbyte : compute and return the effective address in byte instructions. */ +static UINT16 decipheraddrbyte(tms99xx_state *cpustate, UINT16 opcode) +{ + register UINT16 ts = opcode & 0x30; + register UINT16 reg = opcode & 0xF; + + reg += reg; + + if (ts == 0) + /* Rx */ + return(reg + cpustate->WP); + else if (ts == 0x10) + { /* *Rx */ + CYCLES(0, 4, 1); + return(readword(cpustate, reg + cpustate->WP)); + } + else if (ts == 0x20) + { + register UINT16 imm; + + imm = fetch(cpustate); + + if (reg) + { /* @>xxxx(Rx) */ + CYCLES(1, 8, 3); + return(readword(cpustate, reg + cpustate->WP) + imm); + } + else + { /* @>xxxx */ + CYCLES(3, 8, 1); + return(imm); + } + } + else /*if (ts == 0x30)*/ + { /* *Rx+ */ + register UINT16 response; + + reg += cpustate->WP; /* reg now contains effective address */ + + CYCLES(1, 6, 3); + + response = readword(cpustate, reg); + writeword(cpustate, reg, response+1); /* we increment register content */ + return(response); + } +} + + +/*************************************************************************/ + +#if (TMS99XX_MODEL == TI990_10_ID) + /* TI990/10 generates an error interrupt */ + /* timings are unknown */ + #define HANDLE_ILLEGAL \ + { \ + cpustate->error_interrupt_register |= EIR_ILLOP; \ + if (cpustate->error_interrupt_callback) \ + (*cpustate->error_interrupt_callback)(cpustate->device, 1); \ + } +#elif TMS99XX_MODEL <= TMS9989_ID + /* TMS9900/TMS9980 merely ignore the instruction */ + #define HANDLE_ILLEGAL cpustate->icount -= 6 +#elif TMS99XX_MODEL == TMS9995_ID + /* TMS9995 generates a MID interrupt */ + #define HANDLE_ILLEGAL \ + { \ + cpustate->MID_flag = 1; \ + contextswitchX(cpustate, 0x0008); \ + cpustate->STATUS = (cpustate->STATUS & 0xFE00) | 0x1; \ + cpustate->disable_interrupt_recognition = 1; \ + } +#else +#define HANDLE_ILLEGAL +#warning "don't know" +#endif + +#if HAS_PRIVILEGE + #if (TMS99XX_MODEL == TI990_10_ID) + /* TI990/10 generates an error interrupt */ + /* timings are unknown */ + #define HANDLE_PRIVILEGE_VIOLATION \ + { \ + cpustate->error_interrupt_register |= EIR_PRIVOP; \ + if (cpustate->error_interrupt_callback) \ + (*cpustate->error_interrupt_callback)(cpustate->device, 1); \ + } + #else + #define HANDLE_PRIVILEGE_VIOLATION + #warning "don't know" + #endif +#endif + +/*========================================================================== + Illegal instructions >0000->01FF (not for 9989 and later) + >0C00->0FFF (not for 990/12 and 99110) +============================================================================*/ + +static void illegal(tms99xx_state *cpustate, UINT16 opcode) +{ + HANDLE_ILLEGAL; +} + + +#if 0 /* ti990/12 only */ +/*========================================================================== + Additionnal instructions, >0000->002F + Additionnal single-register instruction, >0030->003F + --------------------------------------------------------------------------- + + 0 1 2 3-4 5 6 7+8 9 A B-C D E F + --------------------------------- + | o p c o d e | + | o p c o d e | reg # | + --------------------------------- + +============================================================================*/ +static void h0000(tms99xx_state *cpustate, UINT16 opcode) +{ + if (opcode >= 0x30) + { /* STPC STore Program Counter */ + + } + else + { + switch (opcode /*& 0x3F*/) + { + case 0x1C: /* SRAM */ + /* SRAM -- Shift Right Arithmetic Multiple precision */ + case 0x1D: /* SLAM */ + /* SLAM -- Shift Left Arithmetic Multiple precision */ + case 0x1E: + /* RTO --- Right Test for Ones */ + case 0x1F: + /* LTO --- Left Test for Ones */ + case 0x20: + /* CNTO -- CouNT Ones */ + case 0x21: + /* SLSL -- Search LiSt Logical address */ + case 0x22: + /* SLSP -- Search LiSt Physical address */ + case 0x23: + /* BDC --- Binary to Decimal ascii Conversion */ + case 0x24: + /* DBC --- Decimal to Binary ascii Conversion */ + case 0x25: + /* SWPM -- SWaP Multiple precision */ + case 0x26: + /* XORM -- eXclusive OR Multiple precision */ + case 0x27: + /* ORM --- OR Multiple precision */ + case 0x28: + /* ANDM -- AND Multiple precision */ + case 0x29: /* SM */ + /* SM ---- Subtract Multiple precision integer */ + case 0x2A: /* AM */ + /* AM ---- Add Multiple precision integer */ + case 0x2B: + /* MOVA -- MOVe Address */ + case 0x2D: + /* EMD --- Execute Micro-Diagnostics */ + case 0x2E: + /* EINT -- Enable INTerrupts */ + case 0x2F: + /* DINT -- Disable INTerrupts */ + + break; + + default: + HANDLE_ILLEGAL; + break; + } + } +} +#endif + + +#if HAS_9995_OPCODES +/*========================================================================== + Additionnal single-register instructions, >0040->00FF + --------------------------------------------------------------------------- + + 0 1 2 3-4 5 6 7+8 9 A B-C D E F + --------------------------------- + | o p c o d e | reg # | + --------------------------------- + +tms9989 and later : LST, LWP +============================================================================*/ +static void h0040(tms99xx_state *cpustate, UINT16 opcode) +{ + register UINT16 addr; + + addr = opcode & 0xF; + addr = ((addr + addr) + cpustate->WP) & ~1; + + switch ((opcode & 0xF0) >> 4) + { + case 8: /* LST */ + /* LST --- Load STatus register */ + /* ST = *Reg */ + #if HAS_PRIVILEGE + if (cpustate->STATUS & ST_PR) + cpustate->STATUS = (cpustate->STATUS & 0x01DF) | (readword(cpustate, addr) & 0xFE20); + else + cpustate->STATUS = readword(cpustate, addr); + #else + cpustate->STATUS = readword(cpustate, addr); + #endif + getstat(cpustate); /* set last_parity */ + break; + + case 9: /* LWP */ + /* LWP --- Load Workspace Pointer */ + /* WP = *Reg */ + cpustate->WP = readword(cpustate, addr) & ~1; + break; + +#if 0 /* 990/12 opcodes */ + case 4: + /* CS ---- Compare Strings */ + case 5: + /* SEQB -- Search string for EQual Byte */ + case 6: + /* MOVS -- MOVe String */ + case 7: + /* LIM --- Load Interrupt Mask */ + + case 10: + /* LCS --- Load writable Control Store */ + + case 11: /* BLSK */ + /* BLSK -- Branch immediate and push Link to StacK */ + + case 12: + /* MVSR -- MoVe String Reverse */ + case 13: + /* MVSK -- MoVe string from StacK */ + case 14: + /* POPS -- POP String from stack */ + case 15: + /* PSHS -- PuSH String to stack */ + + break; +#endif + + default: + HANDLE_ILLEGAL; + break; + } +} + + +/*========================================================================== + Additionnal single-operand instructions, >0100->01FF + --------------------------------------------------------------------------- + + 0 1 2 3-4 5 6 7+8 9 A B-C D E F + --------------------------------- + | o p c o d e |TS | S | + --------------------------------- + +tms9989 and later : DIVS, MPYS +tms99xxx : BIND +============================================================================*/ +static void h0100(tms99xx_state *cpustate, UINT16 opcode) +{ + register UINT16 src; +#if HAS_MAPPING + int src_map = (opcode & 0x0030) ? cpustate->cur_src_map : cpustate->cur_map; +#endif + + src = decipheraddr(cpustate, opcode) & ~1; + + switch ((opcode & 0xC0) >> 6) + { +#if HAS_BIND_OPCODE + case 1: /* BIND */ + /* BIND -- Branch INDirect */ + cpustate->PC = readwordX(cpustate, src, src_map) & ~1; + CYCLES(Mooof!, Mooof!, 4 /*don't know*/); + break; +#endif + + case 2: /* DIVS */ + /* DIVS -- DIVide Signed */ + /* R0 = (R0:R1)/S R1 = (R0:R1)%S */ + { + INT16 d = readwordX(cpustate, src, src_map); + INT32 divq = (READREG(R0) << 16) | READREG(R1); + INT32 q = divq/d; + + if ((q < -32768L) || (q > 32767L)) + { + cpustate->STATUS |= ST_OV; + CYCLES(Mooof!, Mooof!, 10); + } + else + { + cpustate->STATUS &= ~ST_OV; + setst_lae(cpustate, q); + WRITEREG(R0, q); + WRITEREG(R1, divq%d); + /* tms9995 : 33 is the worst case */ + CYCLES(Mooof!, Mooof!, 33); + } + } + break; + + case 3: /* MPYS */ + /* MPYS -- MultiPlY Signed */ + /* Results: R0:R1 = R0*S */ + { + INT32 prod = ((INT32) (INT16) readwordX(cpustate, src, src_map)); + prod = prod*((INT32) (INT16) READREG(R0)); + + cpustate->STATUS &= ~ (ST_LGT | ST_AGT | ST_EQ); + if (prod > 0) + cpustate->STATUS |= (ST_LGT | ST_AGT); + else if (prod < 0) + cpustate->STATUS |= ST_LGT; + else + cpustate->STATUS |= ST_EQ; + + WRITEREG(R0, prod >> 16); + WRITEREG(R1, prod); + } + CYCLES(Mooof!, Mooof!, 25); + break; + +#if 0 /* Origin unknown */ + case 0: /* EVAD */ + /* EVAD -- EValuate ADdress instruction */ + + break; +#endif + + default: + HANDLE_ILLEGAL; + break; + } +} +#endif + + +/*========================================================================== + Immediate, Control instructions, >0200->03FF + --------------------------------------------------------------------------- + + 0 1 2 3-4 5 6 7+8 9 A B-C D E F + --------------------------------- + | o p c o d e |0| reg # | + --------------------------------- + + LI, AI, ANDI, ORI, CI, STWP, STST, LIMI, LWPI, IDLE, RSET, RTWP, CKON, CKOF, LREX +systems with memory mapper: LMF +============================================================================*/ +static void h0200(tms99xx_state *cpustate, UINT16 opcode) +{ + register UINT16 addr; + register UINT16 value; /* used for anything */ + + addr = opcode & 0xF; + addr = ((addr + addr) + cpustate->WP) & ~1; + + #if HAS_MAPPING + if ((opcode >= 0x0320) && (opcode < 0x0340)) + { /* LMF */ + /* LMF --- Load memory Map File */ + /* Used by the memory mapper on ti990/10 with mapping option, ti990/12, and the TIM99610 + mapper chip to be associated with tms99000. + Syntax: "LMF Rn,m" loads map file m (0 or 1) with six words of memory, starting at address + specified in workspace register Rn (0 through 15). */ + #if HAS_PRIVILEGE + if (cpustate->STATUS & ST_PR) + { + HANDLE_PRIVILEGE_VIOLATION + return; + } + #endif + + /* read address pointer */ + addr = readword(cpustate, addr); + + load_map_file(cpustate, addr, cpustate->cur_map, (opcode & 0x10) ? 1 : 0); + + CYCLES(3, Mooof!, Mooof!); + return; + } + #endif + + #if BETTER_0200_DECODING + /* better instruction decoding on ti990/10 */ + if (opcode & 0x10) + { + HANDLE_ILLEGAL; + return; + } + #elif COMPLETE_0200_DECODING + /* full instruction decoding on tms9995 */ + if (((opcode < 0x2E0) && (opcode & 0x10)) || ((opcode >= 0x2E0) && (opcode & 0x1F))) + { +#if 0 + /* tms99110 opcode (not supported by 990/12) */ + if (opcode == 0x0301) + { /* CR ---- Compare Reals */ + } + else + /* tms99105+tms99110 opcode (not supported by 990/12) */ + if (opcode == 0x0302) + { /* MM ---- Multiply Multiple */ + } + else +#endif + #if 0 /* ti990/12 only */ + if (opcode >= 0x03F0) + { /* EP ---- Extended Precision */ + } + else + #endif + HANDLE_ILLEGAL; + return; + } + #endif + + switch ((opcode & 0x1e0) >> 5) + { + case 0: /* LI */ + /* LI ---- Load Immediate */ + /* *Reg = *PC+ */ + value = fetch(cpustate); + writeword(cpustate, addr, value); + setst_lae(cpustate, value); + CYCLES(3, 12, 3); + break; + + case 1: /* AI */ + /* AI ---- Add Immediate */ + /* *Reg += *PC+ */ + value = fetch(cpustate); + value = setst_add_laeco(cpustate, readword(cpustate, addr), value); + writeword(cpustate, addr, value); + CYCLES(4, 14, 4); + break; + + case 2: /* ANDI */ + /* ANDI -- AND Immediate */ + /* *Reg &= *PC+ */ + value = fetch(cpustate); + value = readword(cpustate, addr) & value; + writeword(cpustate, addr, value); + setst_lae(cpustate, value); + CYCLES(4, 14, 4); + break; + + case 3: /* ORI */ + /* ORI --- OR Immediate */ + /* *Reg |= *PC+ */ + value = fetch(cpustate); + value = readword(cpustate, addr) | value; + writeword(cpustate, addr, value); + setst_lae(cpustate, value); + CYCLES(4, 14, 4); + break; + + case 4: /* CI */ + /* CI ---- Compare Immediate */ + /* status = (*Reg-*PC+) */ + value = fetch(cpustate); + setst_c_lae(cpustate, value, readword(cpustate, addr)); + CYCLES(6, 14, 4); + break; + + case 5: /* STWP */ + /* STWP -- STore Workspace Pointer */ + /* *Reg = WP */ + writeword(cpustate, addr, cpustate->WP); + CYCLES(2, 8, 3); + break; + + case 6: /* STST */ + /* STST -- STore STatus register */ + /* *Reg = ST */ + setstat(cpustate); + writeword(cpustate, addr, cpustate->STATUS); + CYCLES(2, 8, 3); + break; + + case 7: /* LWPI */ + /* LWPI -- Load Workspace Pointer Immediate */ + /* WP = *PC+ */ + cpustate->WP = fetch(cpustate) & ~1; + CYCLES(3, 10, 4); + break; + + case 8: /* LIMI */ + /* LIMI -- Load Interrupt Mask Immediate */ + /* ST&15 |= (*PC+)&15 */ + #if HAS_PRIVILEGE + if (cpustate->STATUS & ST_PR) + { + HANDLE_PRIVILEGE_VIOLATION + break; + } + #endif + + value = fetch(cpustate); + cpustate->STATUS = (cpustate->STATUS & ~ST_IM) | (value & ST_IM); + field_interrupt(cpustate); /*IM has been modified.*/ + CYCLES(3, 16, 5); + break; + + case 9: /* LMF is implemented elsewhere - when it is implemented */ + HANDLE_ILLEGAL; + break; + + case 10: /* IDLE */ + /* IDLE -- IDLE until a reset, interrupt, load */ + /* The TMS99000 locks until an interrupt happen (like with 68k STOP instruction), + and continuously performs a special CRU write (code 2). */ + #if HAS_PRIVILEGE + if (cpustate->STATUS & ST_PR) + { + HANDLE_PRIVILEGE_VIOLATION + break; + } + #endif + cpustate->IDLE = 1; + #if EXTERNAL_INSTRUCTION_DECODING + external_instruction_notify(cpustate, 2); + #endif + if (cpustate->idle_callback) + (*cpustate->idle_callback)(cpustate->device, 1); + CYCLES(4, 12, 7); + /* we take care of further external_instruction_notify(cpustate, 2); in execute(cpustate) */ + break; + + case 12: /* RTWP */ + /* RTWP -- Return with Workspace Pointer */ + /* WP = R13, PC = R14, ST = R15 */ + addr = (cpustate->WP + R13) & ~1; + cpustate->WP = readword(cpustate, addr) & ~1; + addr += 2; + cpustate->PC = readword(cpustate, addr) & ~1; + addr += 2; + #if HAS_PRIVILEGE + if (cpustate->STATUS & ST_PR) + cpustate->STATUS = (cpustate->STATUS & 0x01DF) | (readword(cpustate, addr) & 0xFE20); + else + cpustate->STATUS = readword(cpustate, addr); + #else + cpustate->STATUS = readword(cpustate, addr); + #endif + getstat(cpustate); /* set last_parity */ + + field_interrupt(cpustate); /*IM has been modified.*/ + CYCLES(3, 14, 6); + break; + +#if (TMS99XX_MODEL == TMS9940_ID) || (TMS99XX_MODEL == TMS9985_ID) + + case 11: /* RSET */ + case 13: /* CKON */ + case 14: /* CKOF */ + case 15: /* LREX */ + HANDLE_ILLEGAL; /* These instruction "have been deleted" on the TMS9940 */ + break; + +#else + + case 11: /* RSET */ + /* RSET -- ReSET */ + /* Reset the Interrupt Mask, and perform a special CRU write (code 3). */ + /* The CRU write is supposed to reset external devices. */ + #if HAS_PRIVILEGE + if (cpustate->STATUS & ST_PR) + { + HANDLE_PRIVILEGE_VIOLATION + break; + } + #endif + + cpustate->STATUS &= 0xFFF0; /*clear IM.*/ + field_interrupt(cpustate); /*IM has been modified.*/ + + #if (TMS99XX_MODEL == TMS9995_ID) + /*cpustate->MID_flag = 0;*/ /* not sure about this */ + #endif + #if (TMS99XX_MODEL == TI990_10_ID) + cpustate->error_interrupt_register = 0; + cpustate->mapping_on = 0; + + cpustate->reset_maperr = 0; + cpustate->mapper_cru_read_register = 0; + cpustate->latch_control[0] = cpustate->latch_control[1] = cpustate->latch_control[2] = 0; + + cpustate->diaglat = 0; + #endif + + #if EXTERNAL_INSTRUCTION_DECODING + external_instruction_notify(cpustate, 3); + #endif + + #if EXTERNAL_INSTRUCTION_CALLBACK + if (cpustate->rset_callback) + (*cpustate->rset_callback)(cpustate->device); + #endif + + CYCLES(5, 12, 7); + break; + +#if EXTERNAL_INSTRUCTION_DECODING + + case 13: /* CKON */ + case 14: /* CKOF */ + case 15: /* LREX */ + /* CKON -- ClocK ON */ + /* Perform a special CRU write (code 5). */ + /* An external circuitery could, for instance, enable the line clock interrupt (100Hz or 120Hz, depending on the electrical alimentation frequency). */ + /* CKOF -- ClocK OFf */ + /* Perform a special CRU write (code 6). */ + /* An external circuitery could, for instance, disable the line clock interrupt. */ + /* LREX -- Load or REstart eXecution */ + /* Perform a special CRU write (code 7). */ + /* An external circuitery could, for instance, activate the LOAD* line, + causing a non-maskable LOAD interrupt (vector -1). */ + #if HAS_PRIVILEGE + if (cpustate->STATUS & ST_PR) + { + HANDLE_PRIVILEGE_VIOLATION + break; + } + #endif + + external_instruction_notify(cpustate, (opcode & 0x00e0) >> 5); + + #if EXTERNAL_INSTRUCTION_CALLBACK + #warning "todo..." + #endif + + CYCLES(Mooof!, 12, 7); + break; + +#elif EXTERNAL_INSTRUCTION_CALLBACK + + case 13: /* CKON */ + case 14: /* CKOF */ + /* CKON -- ClocK ON */ + /* Enable the line clock interrupt (100Hz or 120Hz, depending on the electrical alimentation frequency). */ + /* CKOF -- ClocK OFf */ + /* Disable the line clock interrupt. */ + /* We use a callback because the line clock is implemented in machine + code, not in the CPU core. */ + #if HAS_PRIVILEGE + if (cpustate->STATUS & ST_PR) + { + HANDLE_PRIVILEGE_VIOLATION + break; + } + #endif + + if (cpustate->ckon_ckof_callback) + (*cpustate->ckon_ckof_callback)(cpustate->device, (opcode & 0x0020) ? 1 : 0); + + + CYCLES(5, Mooof!, Mooof!); + break; + + case 15: /* LREX */ + /* LREX -- Load or REstart eXecution */ + /* Trigger a LOAD interrupt (vector -1). (We use a callback, and I + have forgotten the reason why.) */ + #if HAS_PRIVILEGE + if (cpustate->STATUS & ST_PR) + { + HANDLE_PRIVILEGE_VIOLATION + break; + } + #endif + + if (cpustate->lrex_callback) + (*cpustate->lrex_callback)(cpustate->device); + + CYCLES(6, Mooof!, Mooof!); + break; + +#else + + #warning "Should not happen..." + +#endif + +#endif + } +} + + +/*========================================================================== + Single-operand instructions, >0400->07FF + --------------------------------------------------------------------------- + + 0 1 2 3-4 5 6 7+8 9 A B-C D E F + --------------------------------- + | o p c o d e |TS | S | + --------------------------------- + + BLWP, B, X, CLR, NEG, INV, INC, INCT, DEC, DECT, BL, SWPB, SETO, ABS +systems with memory mapper: LDD, LDS +============================================================================*/ +static void h0400(tms99xx_state *cpustate, UINT16 opcode) +{ + register UINT16 addr = decipheraddr(cpustate, opcode) & ~1; + register UINT16 value; /* used for anything */ +#if HAS_MAPPING + int src_map = (opcode & 0x0030) ? cpustate->cur_src_map : cpustate->cur_map; +#endif + + switch ((opcode & 0x3C0) >> 6) + { + case 0: /* BLWP */ + /* BLWP -- Branch and Link with Workspace Pointer */ + /* Result: WP = *S+, PC = *S */ + /* New R13=old WP, New R14=Old PC, New R15=Old ST */ + contextswitch(cpustate, addr); + CYCLES(3, 26, 11); + cpustate->disable_interrupt_recognition = 1; + break; + case 1: /* B */ + /* B ----- Branch */ + /* PC = S */ +#if ((TMS99XX_MODEL == TMS9900_ID) || (TMS99XX_MODEL == TMS9980_ID)) + (void) readwordX(cpustate, addr, src_map); +#endif + cpustate->PC = addr; + CYCLES(2, 8, 3); + break; + case 2: /* X */ + /* X ----- eXecute */ + /* Executes instruction *S */ + execute(cpustate, readwordX(cpustate, addr, src_map)); + /* On tms9900, the X instruction actually takes 8 cycles, but we gain 2 cycles on the next + instruction, as we don't need to fetch it. */ + CYCLES(1, 6, 2); + break; + case 3: /* CLR */ + /* CLR --- CLeaR */ + /* *S = 0 */ +#if ((TMS99XX_MODEL == TMS9900_ID) || (TMS99XX_MODEL == TMS9980_ID)) + (void) readwordX(cpustate, addr, src_map); +#endif + writewordX(cpustate, addr, 0, src_map); + CYCLES(2, 10, 3); + break; + case 4: /* NEG */ + /* NEG --- NEGate */ + /* *S = -*S */ + value = - (INT16) readwordX(cpustate, addr, src_map); + if (value) + cpustate->STATUS &= ~ ST_C; + else + cpustate->STATUS |= ST_C; + + #if (TMS99XX_MODEL == TMS9940_ID) || (TMS99XX_MODEL == TMS9985_ID) + if (value & 0x0FFF) + cpustate->STATUS &= ~ ST_DC; + else + cpustate->STATUS |= ST_DC; + #endif + + setst_laeo(cpustate, value); + writewordX(cpustate, addr, value, src_map); + CYCLES(3, 12, 3); + break; + case 5: /* INV */ + /* INV --- INVert */ + /* *S = ~*S */ + value = ~ readwordX(cpustate, addr, src_map); + writewordX(cpustate, addr, value, src_map); + setst_lae(cpustate, value); + CYCLES(2, 10, 3); + break; + case 6: /* INC */ + /* INC --- INCrement */ + /* (*S)++ */ + value = setst_add_laeco(cpustate, readwordX(cpustate, addr, src_map), 1); + writewordX(cpustate, addr, value, src_map); + CYCLES(2, 10, 3); + break; + case 7: /* INCT */ + /* INCT -- INCrement by Two */ + /* (*S) +=2 */ + value = setst_add_laeco(cpustate, readwordX(cpustate, addr, src_map), 2); + writewordX(cpustate, addr, value, src_map); + CYCLES(2, 10, 3); + break; + case 8: /* DEC */ + /* DEC --- DECrement */ + /* (*S)-- */ + value = setst_sub_laeco(cpustate, readwordX(cpustate, addr, src_map), 1); + writewordX(cpustate, addr, value, src_map); + CYCLES(2, 10, 3); + break; + case 9: /* DECT */ + /* DECT -- DECrement by Two */ + /* (*S) -= 2 */ + value = setst_sub_laeco(cpustate, readwordX(cpustate, addr, src_map), 2); + writewordX(cpustate, addr, value, src_map); + CYCLES(2, 10, 3); + break; + case 10: /* BL */ + /* BL ---- Branch and Link */ + /* IP=S, R11=old IP */ +#if ((TMS99XX_MODEL == TMS9900_ID) || (TMS99XX_MODEL == TMS9980_ID)) + (void) readwordX(cpustate, addr, src_map); +#endif + WRITEREG(R11, cpustate->PC); + cpustate->PC = addr; + CYCLES(3, 12, 5); + break; + case 11: /* SWPB */ + /* SWPB -- SWaP Bytes */ + /* *S = swab(*S) */ + value = readwordX(cpustate, addr, src_map); + value = logical_right_shift(value, 8) | (value << 8); + writewordX(cpustate, addr, value, src_map); + CYCLES(2, 10, 13); + break; + case 12: /* SETO */ + /* SETO -- SET to Ones */ + /* *S = #$FFFF */ +#if ((TMS99XX_MODEL == TMS9900_ID) || (TMS99XX_MODEL == TMS9980_ID)) + (void) readwordX(cpustate, addr, src_map); +#endif + writewordX(cpustate, addr, 0xFFFF, src_map); + CYCLES(2, 10, 3); + break; + case 13: /* ABS */ + /* ABS --- ABSolute value */ + /* *S = |*S| */ + /* clearing ST_C seems to be necessary, although ABS will never set it. */ +#if (TMS99XX_MODEL <= TMS9985_ID) + + /* ti990/10 and tms9900/tms9980 only write the result if it has changed */ + cpustate->STATUS &= ~ (ST_LGT | ST_AGT | ST_EQ | ST_C | ST_OV); + + #if (TMS99XX_MODEL == TMS9940_ID) || (TMS99XX_MODEL == TMS9985_ID) + /* I guess ST_DC is cleared here, too*/ + cpustate->STATUS &= ~ ST_DC; + #endif + + value = readwordX(cpustate, addr, src_map); + + CYCLES(5, 12, Mooof!); + + if (((INT16) value) > 0) + cpustate->STATUS |= ST_LGT | ST_AGT; + else if (((INT16) value) < 0) + { + cpustate->STATUS |= ST_LGT; + if (value == 0x8000) + cpustate->STATUS |= ST_OV; + + #if (TMS99XX_MODEL == TMS9940_ID) || (TMS99XX_MODEL == TMS9985_ID) + if (! (value & 0x0FFF)) + cpustate->STATUS |= ST_DC; + #endif + + writewordX(cpustate, addr, - ((INT16) value), src_map); + CYCLES(0, 2, Mooof!); + } + else + cpustate->STATUS |= ST_EQ; + + break; + +#else + + /* tms9995 always write the result */ + cpustate->STATUS &= ~ (ST_LGT | ST_AGT | ST_EQ | ST_C | ST_OV); + value = readwordX(cpustate, addr, src_map); + + CYCLES(Mooof!, Mooof!, 3); + if (((INT16) value) > 0) + cpustate->STATUS |= ST_LGT | ST_AGT; + else if (((INT16) value) < 0) + { + cpustate->STATUS |= ST_LGT; + if (value == 0x8000) + cpustate->STATUS |= ST_OV; + value = - ((INT16) value); + } + else + cpustate->STATUS |= ST_EQ; + + writewordX(cpustate, addr, value, src_map); + + break; + +#endif + + +#if HAS_MAPPING + /* Used by the memory mapper on ti990/10 with mapping option, ti990/12, and the TIM99610 + mapper chip to be associated with tms99000. */ + /* These opcode allow access to another page without the need of switching a page someplace. */ + /* Note that, if I read the 990/10 schematics correctly, two consecutive LDS or LDD would + cause some trouble. */ + case 14: /* LDS */ + /* LDS --- Long Distance Source */ + + #if HAS_PRIVILEGE + if (cpustate->STATUS & ST_PR) + { + HANDLE_PRIVILEGE_VIOLATION + break; + } + #endif + + load_map_file(cpustate, addr, src_map, 2); + cpustate->lds_flag = 1; + cpustate->disable_interrupt_recognition = 1; + break; + case 15: /* LDD */ + /* LDD --- Long Distance Destination */ + #if HAS_PRIVILEGE + if (cpustate->STATUS & ST_PR) + { + HANDLE_PRIVILEGE_VIOLATION + break; + } + #endif + + load_map_file(cpustate, addr, src_map, 2); + cpustate->ldd_flag = 1; + cpustate->disable_interrupt_recognition = 1; + break; + +#else + + default: + /* illegal instructions */ + HANDLE_ILLEGAL; + break; + +#endif + } +} + + +/*========================================================================== + Shift instructions, >0800->0BFF + -------------------------------------------------------------------------- + + 0 1 2 3-4 5 6 7+8 9 A B-C D E F + --------------------------------- + | o p c o d e | C | W | + --------------------------------- + + SRA, SRL, SLA, SRC +============================================================================*/ +static void h0800(tms99xx_state *cpustate, UINT16 opcode) +{ + register UINT16 addr; + register UINT16 cnt = (opcode & 0xF0) >> 4; + register UINT16 value; + + addr = (opcode & 0xF); + addr = ((addr+addr) + cpustate->WP) & ~1; + + CYCLES(3, 12, 5); + + if (cnt == 0) + { + CYCLES(2, 8, 2); + + cnt = READREG(R0) & 0xF; + + if (cnt == 0) + cnt = 16; + } + + CYCLES(cnt, cnt+cnt, cnt); + + switch ((opcode & 0x300) >> 8) + { + case 0: /* SRA */ + /* SRA --- Shift Right Arithmetic */ + /* *W >>= C (*W is filled on the left with a copy of the sign bit) */ + value = setst_sra_laec(cpustate, readword(cpustate, addr), cnt); + writeword(cpustate, addr, value); + break; + case 1: /* SRL */ + /* SRL --- Shift Right Logical */ + /* *W >>= C (*W is filled on the left with 0) */ + value = setst_srl_laec(cpustate, readword(cpustate, addr), cnt); + writeword(cpustate, addr, value); + break; + case 2: /* SLA */ + /* SLA --- Shift Left Arithmetic */ + /* *W <<= C */ + value = setst_sla_laeco(cpustate, readword(cpustate, addr), cnt); + writeword(cpustate, addr, value); + break; + case 3: /* SRC */ + /* SRC --- Shift Right Circular */ + /* *W = rightcircularshift(*W, C) */ + value = setst_src_laec(cpustate, readword(cpustate, addr), cnt); + writeword(cpustate, addr, value); + break; + } +} + + +#if 0 /* 990/12 opcodes */ +/*========================================================================== + Additionnal instructions, >0C00->0C0F + Additionnal single-register instructions, >0C10->0C3F + --------------------------------------------------------------------------- + + 0 1 2 3-4 5 6 7+8 9 A B-C D E F + --------------------------------- + | o p c o d e | + | o p c o d e | reg # | + --------------------------------- + +============================================================================*/ +static void h0c00(tms99xx_state *cpustate, UINT16 opcode) +{ + if (opcode & 0x30) + { + switch ((opcode & 0x30) >> 4) + { + case 1: + /* INSF -- INSert Field */ + break; + case 2: + /* XV ---- eXtract Value */ + break; + case 3: + /* XF ---- eXtract Field */ + break; + } + } + else + { + switch (opcode & 0x0F) + { + /* floating point instructions */ + case 0: + /* CRI --- Convert Real to Integer */ + break; + case 2: + /* NEGR -- NEGate Real */ + break; + case 4: + /* CRE --- Convert Real to Extended integer */ + break; + case 6: + /* CER --- Convert Extended integer to Real */ + break; + + case 1: + /* CDI --- Convert Double precision real to Integer */ + break; + case 3: + /* NEGD -- NEGate Double precision real */ + break; + case 5: + /* CDE --- Convert Double precision real to Extended integer */ + break; + case 7: + /* CED --- Convert Extended integer to Double precision real */ + break; + + case 8: + /* NRM --- NoRMalize */ + break; + + case 9: + /* TMB --- Test Memory Bit */ + break; + case 10: + /* TCMB -- Test and Clear Memory Bit */ + break; + case 11: + /* TSMB -- Test and Set Memory Bit */ + break; + + case 12: + /* SRJ --- Subtract from Register and Jump */ + case 13: + /* ARJ --- Add to Register and Jump */ + + case 14: + case 15: + /* XIT --- eXIT from floating point interpreter */ + /* Generated by some compilers, but equivalent to NOP on TI990/12. May have been used + by some software floating-point emulators. */ + break; + + default: + HANDLE_ILLEGAL; + break; + } + } +} + + +/*========================================================================== + Additionnal single-operand instructions, >0C40->0DFF + >0E40->0FFF + --------------------------------------------------------------------------- + + 0 1 2 3-4 5 6 7+8 9 A B-C D E F + --------------------------------- + | o p c o d e |TS | S | + --------------------------------- + +============================================================================*/ +static void h0c40(tms99xx_state *cpustate, UINT16 opcode) +{ + register UINT16 src; + +#if HAS_MAPPING + int src_map = (opcode & 0x0030) ? cpustate->cur_src_map : cpustate->cur_map; +#endif + + src = decipheraddr(cpustate, opcode) & ~1; + + switch ((opcode & 0x03C0) >> 6) + { + case 1: + /* AR ---- Add Real */ + break; + case 2: + /* CIR --- Convert Integer to Real */ + break; + case 3: + /* SR ---- Subtract Real */ + break; + case 4: + /* MR ---- Multiply Real */ + break; + case 5: + /* DR ---- Divide Real */ + break; + case 6: + /* LR ---- Load Real */ + break; + case 7: + /* STR --- STore Real */ + break; + case 9: + /* AD ---- Add Double */ + break; + case 10: + /* CID --- Convert Integer to Double */ + break; + case 11: + /* SD ---- Subtract Double */ + break; + case 12: + /* MD ---- Multiply Double */ + break; + case 13: + /* DD ---- Divide Double */ + break; + case 14: + /* LD ---- Load Double */ + break; + case 15: + /* SD ---- Store Double */ + break; + default: + HANDLE_ILLEGAL; + break; + } +} + +/*========================================================================== + Additionnal single-register instructions, >0E00->0E3F + --------------------------------------------------------------------------- + + 0 1 2 3-4 5 6 7+8 9 A B-C D E F + --------------------------------- + | o p c o d e | reg # | + --------------------------------- + +============================================================================*/ +static void h0e00(tms99xx_state *cpustate, UINT16 opcode) +{ + switch ((opcode & 0x30) >> 4) + { + case 1: + /* IOF --- Invert Order of Field */ + break; + case 1: + /* SNEB -- Search string for Not Equal Byte */ + break; + case 2: + /* CRC --- Cyclic Redundancy Code calculation */ + break; + case 3: + /* TS ---- Translate String */ + break; + } +} +#endif + + +/*========================================================================== + Jump, CRU bit instructions, >1000->1FFF + --------------------------------------------------------------------------- + + 0 1 2 3-4 5 6 7+8 9 A B-C D E F + --------------------------------- + | o p c o d e | signed offset | + --------------------------------- + + JMP, JLT, JLE, JEQ, JHE, JGT, JNE, JNC, JOC, JNO, JL, JH, JOP + SBO, SBZ, TB +============================================================================*/ +static void h1000(tms99xx_state *cpustate, UINT16 opcode) +{ + /* we convert 8 bit signed word offset to a 16 bit effective word offset. */ + register INT16 offset = ((INT8) opcode); + + + switch ((opcode & 0xF00) >> 8) + { + case 0: /* JMP */ + /* JMP --- unconditional JuMP */ + /* PC += offset */ + cpustate->PC += (offset + offset); + CYCLES(3, 10, 3); + break; + case 1: /* JLT */ + /* JLT --- Jump if Less Than (arithmetic) */ + /* if (A==0 && EQ==0), PC += offset */ + if (! (cpustate->STATUS & (ST_AGT | ST_EQ))) + { + cpustate->PC += (offset + offset); + CYCLES(3, 10, 3); + } + else + CYCLES(2, 8, 3); + break; + case 2: /* JLE */ + /* JLE --- Jump if Lower or Equal (logical) */ + /* if (L==0 || EQ==1), PC += offset */ + if ((! (cpustate->STATUS & ST_LGT)) || (cpustate->STATUS & ST_EQ)) + { + cpustate->PC += (offset + offset); + CYCLES(3, 10, 3); + } + else + CYCLES(2, 8, 3); + break; + case 3: /* JEQ */ + /* JEQ --- Jump if EQual */ + /* if (EQ==1), PC += offset */ + if (cpustate->STATUS & ST_EQ) + { + cpustate->PC += (offset + offset); + CYCLES(3, 10, 3); + } + else + CYCLES(2, 8, 3); + break; + case 4: /* JHE */ + /* JHE --- Jump if Higher or Equal (logical) */ + /* if (L==1 || EQ==1), PC += offset */ + if (cpustate->STATUS & (ST_LGT | ST_EQ)) + { + cpustate->PC += (offset + offset); + CYCLES(3, 10, 3); + } + else + CYCLES(2, 8, 3); + break; + case 5: /* JGT */ + /* JGT --- Jump if Greater Than (arithmetic) */ + /* if (A==1), PC += offset */ + if (cpustate->STATUS & ST_AGT) + { + cpustate->PC += (offset + offset); + CYCLES(3, 10, 3); + } + else + CYCLES(2, 8, 3); + break; + case 6: /* JNE */ + /* JNE --- Jump if Not Equal */ + /* if (EQ==0), PC += offset */ + if (! (cpustate->STATUS & ST_EQ)) + { + cpustate->PC += (offset + offset); + CYCLES(3, 10, 3); + } + else + CYCLES(2, 8, 3); + break; + case 7: /* JNC */ + /* JNC --- Jump if No Carry */ + /* if (C==0), PC += offset */ + if (! (cpustate->STATUS & ST_C)) + { + cpustate->PC += (offset + offset); + CYCLES(3, 10, 3); + } + else + CYCLES(2, 8, 3); + break; + case 8: /* JOC */ + /* JOC --- Jump On Carry */ + /* if (C==1), PC += offset */ + if (cpustate->STATUS & ST_C) + { + cpustate->PC += (offset + offset); + CYCLES(3, 10, 3); + } + else + CYCLES(2, 8, 3); + break; + case 9: /* JNO */ + /* JNO --- Jump if No Overflow */ + /* if (OV==0), PC += offset */ + if (! (cpustate->STATUS & ST_OV)) + { + cpustate->PC += (offset + offset); + CYCLES(3, 10, 3); + } + else + CYCLES(2, 8, 3); + break; + case 10: /* JL */ + /* JL ---- Jump if Lower (logical) */ + /* if (L==0 && EQ==0), PC += offset */ + if (! (cpustate->STATUS & (ST_LGT | ST_EQ))) + { + cpustate->PC += (offset + offset); + CYCLES(3, 10, 3); + } + else + CYCLES(2, 8, 3); + break; + case 11: /* JH */ + /* JH ---- Jump if Higher (logical) */ + /* if (L==1 && EQ==0), PC += offset */ + if ((cpustate->STATUS & ST_LGT) && ! (cpustate->STATUS & ST_EQ)) + { + cpustate->PC += (offset + offset); + CYCLES(3, 10, 3); + } + else + CYCLES(2, 8, 3); + break; + case 12: /* JOP */ + /* JOP --- Jump On (odd) Parity */ + /* if (P==1), PC += offset */ + { + /* Let's set ST_OP. */ + int i; + UINT8 a; + a = cpustate->lastparity; + i = 0; + + while (a != 0) + { + if (a & 1) /* If current bit is set, */ + i++; /* increment bit count. */ + a >>= 1U; /* Next bit. */ + } + + /* Set ST_OP bit. */ + /*if (i & 1) + cpustate->STATUS |= ST_OP; + else + cpustate->STATUS &= ~ ST_OP;*/ + + /* Jump accordingly. */ + if (i & 1) /*(cpustate->STATUS & ST_OP)*/ + { + cpustate->PC += (offset + offset); + CYCLES(3, 10, 3); + } + else + CYCLES(2, 8, 3); + } + + break; + case 13: /* SBO */ + /* SBO --- Set Bit to One */ + /* CRU Bit = 1 */ + #if HAS_PRIVILEGE + if (writeCRU(cpustate, (READREG(R12) >> 1) + offset, 1, 1) == CRU_PRIVILEGE_VIOLATION) + HANDLE_PRIVILEGE_VIOLATION + #else + writeCRU(cpustate, (READREG(R12) >> 1) + offset, 1, 1); + #endif + + CYCLES(4, 12, 8); + break; + + case 14: /* SBZ */ + /* SBZ --- Set Bit to Zero */ + /* CRU Bit = 0 */ + #if HAS_PRIVILEGE + if (writeCRU(cpustate, (READREG(R12) >> 1) + offset, 1, 0) == CRU_PRIVILEGE_VIOLATION) + HANDLE_PRIVILEGE_VIOLATION + #else + writeCRU(cpustate, (READREG(R12) >> 1) + offset, 1, 0); + #endif + + CYCLES(4, 12, 8); + break; + + case 15: /* TB */ + /* TB ---- Test Bit */ + /* EQ = (CRU Bit == 1) */ + #if HAS_PRIVILEGE + { + int value; + + value = readCRU(cpustate, (READREG(R12)>> 1) + offset, 1); + if (value == CRU_PRIVILEGE_VIOLATION) + HANDLE_PRIVILEGE_VIOLATION + else + setst_e(cpustate, value & 1, 1); + } + #else + setst_e(cpustate, readCRU(cpustate, (READREG(R12)>> 1) + offset, 1) & 1, 1); + #endif + CYCLES(5, 12, 8); + break; + } +} + + +/*========================================================================== + General and One-Register instructions >2000->3FFF + --------------------------------------------------------------------------- + + 0 1 2 3-4 5 6 7+8 9 A B-C D E F + --------------------------------- + | opcode | D |TS | S | + --------------------------------- + + COC, CZC, XOR, LDCR, STCR, XOP, MPY, DIV +tms9940 : DCA, DCS, LIIM +==========================================================================*/ + +/* xop, ldcr and stcr are handled elsewhere */ +static void h2000(tms99xx_state *cpustate, UINT16 opcode) +{ + register UINT16 dest = (opcode & 0x3C0) >> 6; + register UINT16 src; + register UINT16 value; + +#if HAS_MAPPING + int src_map = (opcode & 0x0030) ? cpustate->cur_src_map : cpustate->cur_map; +#endif + + src = decipheraddr(cpustate, opcode) & ~1; + dest = ((dest+dest) + cpustate->WP) & ~1; + + switch ((opcode & 0x1C00) >> 10) + { + case 0: /* COC */ + /* COC --- Compare Ones Corresponding */ + /* status E bit = (S&D == S) */ + value = readwordX(cpustate, src, src_map); + setst_e(cpustate, value & readword(cpustate, dest), value); + CYCLES(5, 14, 4); + break; + case 1: /* CZC */ + /* CZC --- Compare Zeroes Corresponding */ + /* status E bit = (S&~D == S) */ + value = readwordX(cpustate, src, src_map); + setst_e(cpustate, value & (~ readword(cpustate, dest)), value); + CYCLES(5, 14, 4); + break; + case 2: /* XOR */ + /* XOR --- eXclusive OR */ + /* D ^= S */ + value = readwordX(cpustate, src, src_map); + value ^= readword(cpustate, dest); + setst_lae(cpustate, value); + writeword(cpustate, dest,value); + CYCLES(3, 14, 4); + break; + /*case 3:*/ /* XOP is implemented elsewhere */ + /*case 4:*/ /* LDCR is implemented elsewhere */ + /*case 5:*/ /* STCR is implemented elsewhere */ + case 6: /* MPY */ + /* MPY --- MultiPlY (unsigned) */ + /* Results: D:D+1 = D*S */ + /* Note that early TMS9995 reportedly performs an extra dummy read in PC space */ + { + unsigned long prod = ((unsigned long) readwordX(cpustate, src, src_map)); + prod = prod * ((unsigned long) readword(cpustate, dest)); + writeword(cpustate, dest, prod >> 16); + writeword(cpustate, (dest+2)&0xffff, prod); + } + /* ti990/10 : from 19 to 35, possibly 19 + (number of bits to 1 in one operand) */ + CYCLES(35, 52, 23); + break; + case 7: /* DIV */ + /* DIV --- DIVide (unsigned) */ + /* D = D/S D+1 = D%S */ + { + UINT16 d = readwordX(cpustate, src, src_map); + UINT16 hi = readword(cpustate, dest); + unsigned long divq = (((unsigned long) hi) << 16) | readword(cpustate, (dest+2)&0xffff); + + if (d <= hi) + { + cpustate->STATUS |= ST_OV; + CYCLES(4, 16, 6); + } + else + { + cpustate->STATUS &= ~ST_OV; + writeword(cpustate, dest, divq/d); + writeword(cpustate, (dest+2)&0xffff, divq%d); + /* tms9900 : from 92 to 124, possibly 92 + 2*(number of bits to 1 (or 0?) in quotient) */ + /* tms9995 : 28 is the worst case */ + /* ti990/10 : from 41 to 58, possibly 41 + (number of bits to 1 (or 0?) in quotient) */ + CYCLES(41, 92, 28); + } + } + break; + } +} + +static void xop(tms99xx_state *cpustate, UINT16 opcode) +{ /* XOP */ + /* XOP --- eXtended OPeration */ + /* WP = *(40h+D), PC = *(42h+D) */ + /* New R13=old WP, New R14=Old IP, New R15=Old ST */ + /* New R11=S */ + /* Xop bit set */ + + register UINT16 immediate = (opcode & 0x3C0) >> 6; + register UINT16 operand; + + +#if (TMS99XX_MODEL == TMS9940_ID) || (TMS99XX_MODEL == TMS9985_ID) + switch (immediate) + { + case 0: /* DCA */ + /* DCA --- Decimal Correct Addition */ + operand = decipheraddrbyte(cpustate, opcode); + { + int value = readbyte(cpustate, operand); + int X = (value >> 4) & 0xf; + int Y = value & 0xf; + + if (Y >= 10) + { + Y -= 10; + cpustate->STATUS |= ST_DC; + X++; + } + else if (cpustate->STATUS & ST_DC) + { + Y += 6; + } + + if (X >= 10) + { + X -= 10; + cpustate->STATUS |= ST_C; + } + else if (cpustate->STATUS & ST_C) + { + X += 6; + } + + writebyte(cpustate, operand, (X << 4) | Y); + } + break; + case 1: /* DCS */ + /* DCS --- Decimal Correct Substraction */ + operand = decipheraddrbyte(cpustate, opcode); + { + int value = readbyte(cpustate, operand); + + if (! (cpustate->STATUS & ST_DC)) + { + value += 10; + } + + if (! (cpustate->STATUS & ST_C)) + { + value += 10 << 4; + } + + cpustate->STATUS ^= ST_DC; + + writebyte(cpustate, operand, value); + } + break; + case 2: /* LIIM */ + case 3: /* LIIM */ + /* LIIM - Load Immediate Interrupt Mask */ + /* Does the same job as LIMI, with a different opcode format. */ + /* Note that, unlike TMS9900, the interrupt mask is only 2-bit long. */ + (void)decipheraddr(cpustate, opcode); /* dummy decode (personnal guess) */ + + cpustate->STATUS = (cpustate->STATUS & ~ST_IM) | (opcode & ST_IM); + break; + default: /* normal XOP */ +#endif + + /* TODO : emulate 990/10 hardware XOP */ + operand = decipheraddr(cpustate, opcode); + + #if ((TMS99XX_MODEL <= TMS9989_ID) && (TMS99XX_MODEL != TI990_10_ID)) + (void)readword(cpustate, operand & ~1); /*dummy read (personnal guess)*/ + #endif + + contextswitchX(cpustate, 0x40 + (immediate << 2)); + + #if ! ((TMS99XX_MODEL == TMS9940_ID) || (TMS99XX_MODEL == TMS9985_ID)) + /* The bit is not set on tms9940 */ + cpustate->STATUS |= ST_X; + #endif + + WRITEREG(R11, operand); + CYCLES(7, 36, 15); + cpustate->disable_interrupt_recognition = 1; + +#if (TMS99XX_MODEL == TMS9940_ID) || (TMS99XX_MODEL == TMS9985_ID) + break; + } +#endif +} + +/* LDCR and STCR */ +static void ldcr_stcr(tms99xx_state *cpustate, UINT16 opcode) +{ + register UINT16 cnt = (opcode & 0x3C0) >> 6; + register UINT16 addr; + int value; + +#if HAS_MAPPING + int src_map = (opcode & 0x0030) ? cpustate->cur_src_map : cpustate->cur_map; +#endif + + if (cnt == 0) + cnt = 16; + + if (cnt <= 8) + addr = decipheraddrbyte(cpustate, opcode); + else + addr = decipheraddr(cpustate, opcode) & ~1; + + if (opcode < 0x3400) + { /* LDCR */ + /* LDCR -- LoaD into CRu */ + /* CRU R12--CRU R12+D-1 set to S */ + if (cnt <= 8) + { +#if (TMS99XX_MODEL != TMS9995_ID) + value = readbyteX(cpustate, addr, src_map); +#else + /* just for once, tms9995 behaves like earlier 8-bit tms99xx chips */ + /* this must be because instruction decoding is too complex */ + value = readwordX(cpustate, addr & ~1, src_map); + if (addr & 1) + value &= 0xFF; + else + value = (value >> 8) & 0xFF; +#endif + + (void)READREG(cnt+cnt); /*dummy read (reasonnable guess for TMS9995 & TMS9900, ti990/10)*/ + + setst_byte_laep(cpustate, value); + } + else + { + value = readwordX(cpustate, addr, src_map); + + (void)READREG(cnt+cnt); /*dummy read (reasonnable guess for TMS9995 & TMS9900, ti990/10)*/ + + setst_lae(cpustate, value); + } + + #if HAS_PRIVILEGE + if (writeCRU(cpustate, (READREG(R12) >> 1), cnt, value) == CRU_PRIVILEGE_VIOLATION) + HANDLE_PRIVILEGE_VIOLATION + #else + writeCRU(cpustate, (READREG(R12) >> 1), cnt, value); + #endif + + CYCLES(4+cnt, 20 + cnt+cnt, 9 + cnt+cnt); + } + else + { /* STCR */ + /* STCR -- STore from CRu */ + /* S = CRU R12--CRU R12+D-1 */ + if (cnt <= 8) + { +#if (TMS99XX_MODEL != TMS9995_ID) + + (void)READREG(cnt+cnt); /*dummy read (reasonable guess for TMS9995 & TMS9900, ti990/10)*/ + // MZ: Read before write + int value2 = readwordX(cpustate, addr & ~1, src_map); + + #if HAS_PRIVILEGE + value = readCRU(cpustate, (READREG(R12) >> 1), cnt); + + if (value == CRU_PRIVILEGE_VIOLATION) + HANDLE_PRIVILEGE_VIOLATION + else + { + setst_byte_laep(cpustate, value); + writewordX(cpustate, addr, ((value << 8) & 0xff00) | (value2 & 0x00ff), src_map); + } + #else + value = readCRU(cpustate, (READREG(R12) >> 1), cnt); + setst_byte_laep(cpustate, value); + + writewordX(cpustate, addr, ((value << 8) & 0xff00) | (value2 & 0x00ff), src_map); + #endif + CYCLES(18+cnt, (cnt != 8) ? 42 : 44, 19 + cnt); +#else + /* just for once, tms9995 behaves like earlier 8-bit tms99xx chips */ + /* this must be because instruction decoding is too complex */ + int value2 = readwordX(cpustate, addr & ~1, src_map); + + (void)READREG(cnt+cnt); /*dummy read (reasonable guess for TMS9995 & TMS9900, ti990/10)*/ + + value = readCRU(cpustate, (READREG(R12) >> 1), cnt); + setst_byte_laep(cpustate, value); + + if (addr & 1) + writewordX(cpustate, addr & ~1, (value & 0x00FF) | (value2 & 0xFF00), src_map); + else + writewordX(cpustate, addr & ~1, (value2 & 0x00FF) | ((value << 8) & 0xFF00), src_map); + + CYCLES(Mooof!, Mooof!, 19 + cnt); +#endif + } + else + { + (void)readwordX(cpustate, addr, src_map); /*dummy read*/ + + (void)READREG(cnt+cnt); /*dummy read (reasonnable guess for TMS9995 & TMS9900, ti990/10)*/ + + #if HAS_PRIVILEGE + value = readCRU(cpustate, (READREG(R12) >> 1), cnt); + if (value == CRU_PRIVILEGE_VIOLATION) + HANDLE_PRIVILEGE_VIOLATION + else + { + setst_lae(cpustate, value); + writewordX(cpustate, addr, value, src_map); + } + #else + value = readCRU(cpustate, (READREG(R12) >> 1), cnt); + setst_lae(cpustate, value); + writewordX(cpustate, addr, value, src_map); + #endif + CYCLES(24+cnt, (cnt != 16) ? 58 : 60, 27 + cnt); + } + } +} + + +/*========================================================================== + Two-Operand instructions >4000->FFFF + --------------------------------------------------------------------------- + + 0 1 2 3-4 5 6 7+8 9 A B-C D E F + ---------------------------------- + |opcode|B|TD | D |TS | S | + ---------------------------------- + + SZC, SZCB, S, SB, C, CB, A, AB, MOV, MOVB, SOC, SOCB +============================================================================*/ + +/* word instructions */ +static void h4000w(tms99xx_state *cpustate, UINT16 opcode) +{ + register UINT16 src; + register UINT16 dest; + register UINT16 value; + +#if HAS_MAPPING + int src_map = (opcode & 0x0030) ? cpustate->cur_src_map : cpustate->cur_map; + int dst_map = (opcode & 0x0c00) ? cpustate->cur_dst_map : cpustate->cur_map; +#endif + + src = decipheraddr(cpustate, opcode) & ~1; + dest = decipheraddr(cpustate, opcode >> 6) & ~1; + + value = readwordX(cpustate, src, src_map); + + switch ((opcode >> 13) & 0x0007) /* ((opcode & 0xE000) >> 13) */ + { + case 2: /* SZC */ + /* SZC --- Set Zeros Corresponding */ + /* D &= ~S */ + value = readwordX(cpustate, dest, dst_map) & (~ value); + setst_lae(cpustate, value); + writewordX(cpustate, dest, value, dst_map); + CYCLES(2, 14, 4); + break; + case 3: /* S */ + /* S ----- Subtract */ + /* D -= S */ + value = setst_sub_laeco(cpustate, readwordX(cpustate, dest, dst_map), value); + writewordX(cpustate, dest, value, dst_map); + CYCLES(2, 14, 4); + break; + case 4: /* C */ + /* C ----- Compare */ + /* ST = (D - S) */ + setst_c_lae(cpustate, readwordX(cpustate, dest, dst_map), value); + CYCLES(5, 14, 4); + break; + case 5: /* A */ + /* A ----- Add */ + /* D += S */ + value = setst_add_laeco(cpustate, readwordX(cpustate, dest, dst_map), value); + writewordX(cpustate, dest, value, dst_map); + CYCLES(2, 14, 4); + break; + case 6: /* MOV */ + /* MOV --- MOVe */ + /* D = S */ + setst_lae(cpustate, value); + #if ((TMS99XX_MODEL >= TMS9900_ID) && (TMS99XX_MODEL <= TMS9985_ID)) + /* MOV performs a dummy read with tms9900/9980 (but neither ti990/10 nor tms9995) */ + (void)readwordX(cpustate, dest, dst_map); + #endif + writewordX(cpustate, dest, value, dst_map); + CYCLES(1, 14, 3); + break; + case 7: /* SOC */ + /* SOC --- Set Ones Corresponding */ + /* D |= S */ + value = value | readwordX(cpustate, dest, dst_map); + setst_lae(cpustate, value); + writewordX(cpustate, dest, value, dst_map); + CYCLES(2, 14, 4); + break; + } +} + +/* byte instruction */ +static void h4000b(tms99xx_state *cpustate, UINT16 opcode) +{ + register UINT16 src; + register UINT16 dest; + register UINT16 value; + +#if HAS_MAPPING + int src_map = (opcode & 0x0030) ? cpustate->cur_src_map : cpustate->cur_map; + int dst_map = (opcode & 0x0c00) ? cpustate->cur_dst_map : cpustate->cur_map; +#endif + + src = decipheraddrbyte(cpustate, opcode); + dest = decipheraddrbyte(cpustate, opcode >> 6); + + value = readbyteX(cpustate, src, src_map); + + switch ((opcode >> 13) & 0x0007) /* ((opcode & 0xE000) >> 13) */ + { + case 2: /* SZCB */ + /* SZCB -- Set Zeros Corresponding, Byte */ + /* D &= ~S */ + value = readbyteX(cpustate, dest, dst_map) & (~ value); + setst_byte_laep(cpustate, value); + writebyteX(cpustate, dest, value, dst_map); + CYCLES(3, 14, 4); + break; + case 3: /* SB */ + /* SB ---- Subtract, Byte */ + /* D -= S */ + value = setst_subbyte_laecop(cpustate, readbyteX(cpustate, dest, dst_map), value); + writebyteX(cpustate, dest, value, dst_map); + CYCLES(3, 14, 4); + break; + case 4: /* CB */ + /* CB ---- Compare Bytes */ + /* ST = (D - S) */ + setst_c_lae(cpustate, readbyteX(cpustate, dest, dst_map)<<8, value<<8); + cpustate->lastparity = value; + CYCLES(5, 14, 4); + break; + case 5: /* AB */ + /* AB ---- Add, Byte */ + /* D += S */ + value = setst_addbyte_laecop(cpustate, readbyteX(cpustate, dest, dst_map), value); + writebyteX(cpustate, dest, value, dst_map); + CYCLES(3, 14, 4); + break; + case 6: /* MOVB */ + /* MOVB -- MOVe Bytes */ + /* D = S */ + setst_byte_laep(cpustate, value); + #if (TMS99XX_MODEL <= TMS9985_ID) + /* On ti990/10 and tms9900, MOVB needs to read destination, because it cannot actually + read one single byte. It reads a word, replaces the relevant byte, then write + the result. A tms9980 should not need to do so, but still does, because it is just + a tms9900 with a 16 to 8 bit multiplexer (instead of a new chip design, like tms9995). */ + (void)readbyteX(cpustate, dest, dst_map); + #endif + writebyteX(cpustate, dest, value, dst_map); + CYCLES(3, 14, 3); + break; + case 7: /* SOCB */ + /* SOCB -- Set Ones Corresponding, Byte */ + /* D |= S */ + value = value | readbyteX(cpustate, dest, dst_map); + setst_byte_laep(cpustate, value); + writebyteX(cpustate, dest, value, dst_map); + CYCLES(3, 14, 4); + break; + } +} + + +INLINE void execute(tms99xx_state *cpustate, UINT16 opcode) +{ +#if (! HAS_9995_OPCODES) + + /* tms9900-like instruction set*/ + + static void (*const jumptable_short[128])(tms99xx_state *,UINT16) = + { + &illegal,&h0200,&h0400,&h0400,&h0800,&h0800,&illegal,&illegal, + &h1000,&h1000,&h1000,&h1000,&h1000,&h1000,&h1000,&h1000, + &h2000,&h2000,&h2000,&h2000,&h2000,&h2000,&xop,&xop, + &ldcr_stcr,&ldcr_stcr,&ldcr_stcr,&ldcr_stcr,&h2000,&h2000,&h2000,&h2000, + &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w, + &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b, + &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w, + &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b, + &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w, + &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b, + &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w, + &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b, + &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w, + &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b, + &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w, + &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b + }; + + (* jumptable_short[opcode >> 9])(cpustate, opcode); + +#else + + /* tms9989 and tms9995 include 4 extra instructions, and one additionnal instruction type */ + /* tms99000 includes yet another additional instruction */ + + static void (*const jumptable_long[256])(tms99xx_state *,UINT16) = + { + &h0040,&h0100,&h0200,&h0200,&h0400,&h0400,&h0400,&h0400, + &h0800,&h0800,&h0800,&h0800,&illegal,&illegal,&illegal,&illegal, + &h1000,&h1000,&h1000,&h1000,&h1000,&h1000,&h1000,&h1000, + &h1000,&h1000,&h1000,&h1000,&h1000,&h1000,&h1000,&h1000, + &h2000,&h2000,&h2000,&h2000,&h2000,&h2000,&h2000,&h2000, + &h2000,&h2000,&h2000,&h2000,&xop,&xop,&xop,&xop, + &ldcr_stcr,&ldcr_stcr,&ldcr_stcr,&ldcr_stcr,&ldcr_stcr,&ldcr_stcr,&ldcr_stcr,&ldcr_stcr, + &h2000,&h2000,&h2000,&h2000,&h2000,&h2000,&h2000,&h2000, + &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w, + &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w, + &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b, + &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b, + &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w, + &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w, + &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b, + &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b, + &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w, + &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w, + &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b, + &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b, + &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w, + &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w, + &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b, + &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b, + &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w, + &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w, + &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b, + &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b, + &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w, + &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w, + &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b, + &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b + }; + + (* jumptable_long[opcode >> 8])(cpustate, opcode); + +#endif +} + +/************************************************************************** + * Generic set_info + **************************************************************************/ + +static CPU_SET_INFO( tms99xx ) +{ + tms99xx_state *cpustate = get_safe_token(device); + switch (state) + { + /* --- the following bits of info are set as 64-bit signed integers --- */ + case CPUINFO_INT_INPUT_STATE + INPUT_LINE_NMI: tms99xx_set_irq_line(cpustate, INPUT_LINE_NMI, info->i); break; + case CPUINFO_INT_INPUT_STATE + 0: tms99xx_set_irq_line(cpustate, 0, info->i); break; + case CPUINFO_INT_INPUT_STATE + 1: tms99xx_set_irq_line(cpustate, 1, info->i); break; + case CPUINFO_INT_INPUT_STATE + 2: tms99xx_set_irq_line(cpustate, 2, info->i); break; + +#if (TMS99XX_MODEL == TI990_10_ID) + case CPUINFO_INT_PC: + { + const unsigned top = (cpustate->cur_map == 0) ? 0xf800 : 0x10000; + + if ((cpustate->cur_map == 0) && (info->i >= 0x1ff800)) + /* intercept TPCS and CPU ROM */ + cpustate->PC = info->i - 0x1f0000; + else if (! cpustate->mapping_on) + cpustate->PC = (info->i < top) ? info->i : 0; + else + { + if ((info->i >= cpustate->map_files[cpustate->cur_map].bias[0]) + && (info->i <= (cpustate->map_files[cpustate->cur_map].bias[0]+cpustate->map_files[cpustate->cur_map].limit[0]))) + cpustate->PC = info->i - cpustate->map_files[cpustate->cur_map].bias[0]; + else if ((info->i > (cpustate->map_files[cpustate->cur_map].bias[1]+cpustate->map_files[cpustate->cur_map].limit[0])) + && (info->i <= (cpustate->map_files[cpustate->cur_map].bias[1]+cpustate->map_files[cpustate->cur_map].limit[1]))) + cpustate->PC = info->i - cpustate->map_files[cpustate->cur_map].bias[1]; + else if ((info->i > (cpustate->map_files[cpustate->cur_map].bias[2]+cpustate->map_files[cpustate->cur_map].limit[0])) + && (info->i > (cpustate->map_files[cpustate->cur_map].bias[2]+cpustate->map_files[cpustate->cur_map].limit[1])) + && (info->i <= (cpustate->map_files[cpustate->cur_map].bias[2]+cpustate->map_files[cpustate->cur_map].limit[2]))) + cpustate->PC = info->i - cpustate->map_files[cpustate->cur_map].bias[2]; + else + { + /*if ((info->i < top) + && (info->i > cpustate->map_files[cpustate->cur_map].limit[0]) + && (info->i > cpustate->map_files[cpustate->cur_map].limit[1]) + && (info->i > cpustate->map_files[cpustate->cur_map].limit[2])) + cpustate->PC = info->i; + else*/ + cpustate->PC = 0; + } + /*if (info->i >= top) + cpustate->PC = 0;*/ + } + cpustate->PC &= 0xfffe; + } + break; +#else + case CPUINFO_INT_PC: +#endif + case CPUINFO_INT_REGISTER + TMS9900_PC: cpustate->PC = info->i & 0xfffe; break; + case CPUINFO_INT_REGISTER + TMS9900_IR: cpustate->IR = info->i; break; + case CPUINFO_INT_SP: + case CPUINFO_INT_REGISTER + TMS9900_WP: cpustate->WP = info->i & 0xfffe; break; + case CPUINFO_INT_REGISTER + TMS9900_STATUS: cpustate->STATUS = info->i; getstat(cpustate); break; + case CPUINFO_INT_REGISTER + TMS9900_R0: WRITEREG_DEBUG(cpustate, R0, info->i); break; + case CPUINFO_INT_REGISTER + TMS9900_R1: WRITEREG_DEBUG(cpustate, R1, info->i); break; + case CPUINFO_INT_REGISTER + TMS9900_R2: WRITEREG_DEBUG(cpustate, R2, info->i); break; + case CPUINFO_INT_REGISTER + TMS9900_R3: WRITEREG_DEBUG(cpustate, R3, info->i); break; + case CPUINFO_INT_REGISTER + TMS9900_R4: WRITEREG_DEBUG(cpustate, R4, info->i); break; + case CPUINFO_INT_REGISTER + TMS9900_R5: WRITEREG_DEBUG(cpustate, R5, info->i); break; + case CPUINFO_INT_REGISTER + TMS9900_R6: WRITEREG_DEBUG(cpustate, R6, info->i); break; + case CPUINFO_INT_REGISTER + TMS9900_R7: WRITEREG_DEBUG(cpustate, R7, info->i); break; + case CPUINFO_INT_REGISTER + TMS9900_R8: WRITEREG_DEBUG(cpustate, R8, info->i); break; + case CPUINFO_INT_REGISTER + TMS9900_R9: WRITEREG_DEBUG(cpustate, R9, info->i); break; + case CPUINFO_INT_REGISTER + TMS9900_R10: WRITEREG_DEBUG(cpustate, R10, info->i); break; + case CPUINFO_INT_REGISTER + TMS9900_R11: WRITEREG_DEBUG(cpustate, R11, info->i); break; + case CPUINFO_INT_REGISTER + TMS9900_R12: WRITEREG_DEBUG(cpustate, R12, info->i); break; + case CPUINFO_INT_REGISTER + TMS9900_R13: WRITEREG_DEBUG(cpustate, R13, info->i); break; + case CPUINFO_INT_REGISTER + TMS9900_R14: WRITEREG_DEBUG(cpustate, R14, info->i); break; + case CPUINFO_INT_REGISTER + TMS9900_R15: WRITEREG_DEBUG(cpustate, R15, info->i); break; + } +} + + + +/************************************************************************** + * Generic get_info + **************************************************************************/ + +void TMS99XX_GET_INFO(legacy_cpu_device *device, UINT32 state, cpuinfo *info) +{ + tms99xx_state *cpustate = (device != NULL && device->token() != NULL) ? get_safe_token(device) : NULL; + switch (state) + { + /* --- the following bits of info are returned as 64-bit signed integers --- */ + case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(tms99xx_state); break; + case CPUINFO_INT_INPUT_LINES: info->i = 3; break; + case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0; break; + case CPUINFO_INT_ENDIANNESS: info->i = ENDIANNESS_BIG; break; + case CPUINFO_INT_CLOCK_MULTIPLIER: info->i = 1; break; + case CPUINFO_INT_CLOCK_DIVIDER: info->i = 1; break; + case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 2; break; + case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 6;/*8 with 990/12, 99105, 99110*/break; + case CPUINFO_INT_MIN_CYCLES: info->i = 1; break; + case CPUINFO_INT_MAX_CYCLES: info->i = 10;/*TODO: compute this value*/break; + +#if (USE_16_BIT_ACCESSORS) + case CPUINFO_INT_DATABUS_WIDTH + AS_PROGRAM: info->i = 16; break; +#else + case CPUINFO_INT_DATABUS_WIDTH + AS_PROGRAM: info->i = 8; break; +#endif + case CPUINFO_INT_ADDRBUS_WIDTH + AS_PROGRAM: +#if (TMS99XX_MODEL == TI990_10_ID) + /* this CPU has a mapper to expand the address space */ + info->i = 21; +#elif (TMS99XX_MODEL == TMS9900_ID) || (TMS99XX_MODEL == TMS9940_ID) || (TMS99XX_MODEL == TMS9985_ID) || (TMS99XX_MODEL == TMS9995_ID) + /* basic 16-bit address bus */ + info->i = 16; +#elif (TMS99XX_MODEL == TMS9980_ID) + /* 2 address MSBits are unconnected */ + info->i = 14; +#else + #warning "Please check how many address bits your CPU has." + info->i = 16; +#endif + break; + case CPUINFO_INT_ADDRBUS_SHIFT + AS_PROGRAM: info->i = 0; break; + case CPUINFO_INT_DATABUS_WIDTH + AS_DATA: info->i = 0; break; + case CPUINFO_INT_ADDRBUS_WIDTH + AS_DATA: info->i = 0; break; + case CPUINFO_INT_ADDRBUS_SHIFT + AS_DATA: info->i = 0; break; + case CPUINFO_INT_DATABUS_WIDTH + AS_IO: info->i = 8; break; + case CPUINFO_INT_ADDRBUS_WIDTH + AS_IO: +#if (TMS99XX_MODEL == TI990_10_ID) + /* 3 MSBs do exist, although they are not connected (don't ask...) */ + info->i = 15; +#elif (TMS99XX_MODEL == TMS9900_ID) + /* 3 MSBs are external instruction code */ + info->i = 12; +#elif (TMS99XX_MODEL == TMS9980_ID) + /* 2 bits unused, and 2 MSBs are external instruction code */ + info->i = 13; +#elif (TMS99XX_MODEL == TMS9940_ID) + /* 9 internal address lines (8 external) */ + info->i = 9; +#elif (TMS99XX_MODEL == TMS9995_ID) + /* 15-bit address and data bus lines D0-D2 provide the external instruction code */ + info->i = 15+3; +#else + #warning "I don't know how your processor handles CRU." + info->i = 15; +#endif + break; + case CPUINFO_INT_ADDRBUS_SHIFT + AS_IO: info->i = 0; break; + +/* not implemented */ +/* case CPUINFO_INT_INPUT_STATE + INPUT_LINE_NMI: info->i = get_irq_line(INPUT_LINE_NMI); break; + case CPUINFO_INT_INPUT_STATE + 0: info->i = get_irq_line(0); break; + case CPUINFO_INT_INPUT_STATE + 1: info->i = get_irq_line(1); break; + case CPUINFO_INT_INPUT_STATE + 2: info->i = get_irq_line(2); break;*/ + + case CPUINFO_INT_PREVIOUSPC: /* not implemented */ break; + +#if (TMS99XX_MODEL == TI990_10_ID) + case CPUINFO_INT_PC: + if ((cpustate->cur_map == 0) && (cpustate->PC >= 0xf800)) + /* intercept TPCS and CPU ROM */ + info->i = 0x1f0000+cpustate->PC; + else if (! cpustate->mapping_on) + info->i = cpustate->PC; + else + { + int map_index; + + if (cpustate->PC <= cpustate->map_files[cpustate->cur_map].limit[0]) + map_index = 0; + else if (cpustate->PC <= cpustate->map_files[cpustate->cur_map].limit[1]) + map_index = 1; + else if (cpustate->PC <= cpustate->map_files[cpustate->cur_map].limit[2]) + map_index = 2; + else + { + info->i = cpustate->PC; + break; + } + + info->i = cpustate->map_files[cpustate->cur_map].bias[map_index]+cpustate->PC; + } + break; +#else + case CPUINFO_INT_PC: +#endif + case CPUINFO_INT_REGISTER + TMS9900_PC: info->i = cpustate->PC; break; + case CPUINFO_INT_REGISTER + TMS9900_IR: info->i = cpustate->IR; break; + case CPUINFO_INT_SP: + case CPUINFO_INT_REGISTER + TMS9900_WP: info->i = cpustate->WP; break; + case CPUINFO_INT_REGISTER + TMS9900_STATUS: setstat(cpustate); info->i = cpustate->STATUS; break; + case CPUINFO_INT_REGISTER + TMS9900_R0: info->i = READREG_DEBUG(cpustate, R0); break; + case CPUINFO_INT_REGISTER + TMS9900_R1: info->i = READREG_DEBUG(cpustate, R1); break; + case CPUINFO_INT_REGISTER + TMS9900_R2: info->i = READREG_DEBUG(cpustate, R2); break; + case CPUINFO_INT_REGISTER + TMS9900_R3: info->i = READREG_DEBUG(cpustate, R3); break; + case CPUINFO_INT_REGISTER + TMS9900_R4: info->i = READREG_DEBUG(cpustate, R4); break; + case CPUINFO_INT_REGISTER + TMS9900_R5: info->i = READREG_DEBUG(cpustate, R5); break; + case CPUINFO_INT_REGISTER + TMS9900_R6: info->i = READREG_DEBUG(cpustate, R6); break; + case CPUINFO_INT_REGISTER + TMS9900_R7: info->i = READREG_DEBUG(cpustate, R7); break; + case CPUINFO_INT_REGISTER + TMS9900_R8: info->i = READREG_DEBUG(cpustate, R8); break; + case CPUINFO_INT_REGISTER + TMS9900_R9: info->i = READREG_DEBUG(cpustate, R9); break; + case CPUINFO_INT_REGISTER + TMS9900_R10: info->i = READREG_DEBUG(cpustate, R10); break; + case CPUINFO_INT_REGISTER + TMS9900_R11: info->i = READREG_DEBUG(cpustate, R11); break; + case CPUINFO_INT_REGISTER + TMS9900_R12: info->i = READREG_DEBUG(cpustate, R12); break; + case CPUINFO_INT_REGISTER + TMS9900_R13: info->i = READREG_DEBUG(cpustate, R13); break; + case CPUINFO_INT_REGISTER + TMS9900_R14: info->i = READREG_DEBUG(cpustate, R14); break; + case CPUINFO_INT_REGISTER + TMS9900_R15: info->i = READREG_DEBUG(cpustate, R15); break; + + /* --- the following bits of info are returned as pointers to data or functions --- */ + case CPUINFO_FCT_SET_INFO: info->setinfo = CPU_SET_INFO_NAME(tms99xx); break; + case CPUINFO_FCT_INIT: info->init = CPU_INIT_NAME(tms99xx); break; + case CPUINFO_FCT_RESET: info->reset = CPU_RESET_NAME(tms99xx); break; + case CPUINFO_FCT_EXIT: info->exit = CPU_EXIT_NAME(tms99xx); break; + case CPUINFO_FCT_EXECUTE: info->execute = CPU_EXECUTE_NAME(tms99xx); break; + case CPUINFO_FCT_BURN: info->burn = NULL; break; + case CPUINFO_FCT_DISASSEMBLE: info->disassemble = CPU_DISASSEMBLE_NAME(tms99xx); break; + case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &cpustate->icount; break; + + /* --- the following bits of info are returned as NULL-terminated strings --- */ + case CPUINFO_STR_NAME: strcpy(info->s, TMS99XX_device_get_name); break; + case CPUINFO_STR_SHORTNAME: strcpy(info->s, TMS99XX_device_get_shortname); break; + + case CPUINFO_STR_FAMILY: strcpy(info->s, "Texas Instruments 9900L"); break; + case CPUINFO_STR_VERSION: strcpy(info->s, "2.0"); break; + case CPUINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break; + case CPUINFO_STR_CREDITS: strcpy(info->s, "C TMS9900 emulator by Edward Swartz, initially converted for Mame by M.Coates, updated by R. Nabet"); break; + + case CPUINFO_STR_FLAGS: + sprintf(info->s, "%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c", + cpustate->WP & 0x8000 ? 'L':'.', + cpustate->WP & 0x4000 ? 'A':'.', + cpustate->WP & 0x2000 ? 'E':'.', + cpustate->WP & 0x1000 ? 'C':'.', + cpustate->WP & 0x0800 ? 'V':'.', + cpustate->WP & 0x0400 ? 'P':'.', + cpustate->WP & 0x0200 ? 'X':'.', + cpustate->WP & 0x0100 ? '?':'.', + cpustate->WP & 0x0080 ? '?':'.', + cpustate->WP & 0x0040 ? '?':'.', + cpustate->WP & 0x0020 ? '?':'.', + cpustate->WP & 0x0010 ? '?':'.', + cpustate->WP & 0x0008 ? 'I':'.', + cpustate->WP & 0x0004 ? 'I':'.', + cpustate->WP & 0x0002 ? 'I':'.', + cpustate->WP & 0x0001 ? 'I':'.'); + break; + + case CPUINFO_STR_REGISTER + TMS9900_PC: sprintf(info->s, "PC :%04X", cpustate->PC); break; + case CPUINFO_STR_REGISTER + TMS9900_IR: sprintf(info->s, "IR :%04X", cpustate->IR); break; + case CPUINFO_STR_REGISTER + TMS9900_WP: sprintf(info->s, "WP :%04X", cpustate->WP); break; + case CPUINFO_STR_REGISTER + TMS9900_STATUS: sprintf(info->s, "ST :%04X", cpustate->STATUS); break; + + case CPUINFO_STR_REGISTER + TMS9900_R0: sprintf(info->s, "R0 :%04X", READREG_DEBUG(cpustate, R0)); break; + case CPUINFO_STR_REGISTER + TMS9900_R1: sprintf(info->s, "R1 :%04X", READREG_DEBUG(cpustate, R1)); break; + case CPUINFO_STR_REGISTER + TMS9900_R2: sprintf(info->s, "R2 :%04X", READREG_DEBUG(cpustate, R2)); break; + case CPUINFO_STR_REGISTER + TMS9900_R3: sprintf(info->s, "R3 :%04X", READREG_DEBUG(cpustate, R3)); break; + case CPUINFO_STR_REGISTER + TMS9900_R4: sprintf(info->s, "R4 :%04X", READREG_DEBUG(cpustate, R4)); break; + case CPUINFO_STR_REGISTER + TMS9900_R5: sprintf(info->s, "R5 :%04X", READREG_DEBUG(cpustate, R5)); break; + case CPUINFO_STR_REGISTER + TMS9900_R6: sprintf(info->s, "R6 :%04X", READREG_DEBUG(cpustate, R6)); break; + case CPUINFO_STR_REGISTER + TMS9900_R7: sprintf(info->s, "R7 :%04X", READREG_DEBUG(cpustate, R7)); break; + case CPUINFO_STR_REGISTER + TMS9900_R8: sprintf(info->s, "R8 :%04X", READREG_DEBUG(cpustate, R8)); break; + case CPUINFO_STR_REGISTER + TMS9900_R9: sprintf(info->s, "R9 :%04X", READREG_DEBUG(cpustate, R9)); break; + case CPUINFO_STR_REGISTER + TMS9900_R10: sprintf(info->s, "R10:%04X", READREG_DEBUG(cpustate, R10)); break; + case CPUINFO_STR_REGISTER + TMS9900_R11: sprintf(info->s, "R11:%04X", READREG_DEBUG(cpustate, R11)); break; + case CPUINFO_STR_REGISTER + TMS9900_R12: sprintf(info->s, "R12:%04X", READREG_DEBUG(cpustate, R12)); break; + case CPUINFO_STR_REGISTER + TMS9900_R13: sprintf(info->s, "R13:%04X", READREG_DEBUG(cpustate, R13)); break; + case CPUINFO_STR_REGISTER + TMS9900_R14: sprintf(info->s, "R14:%04X", READREG_DEBUG(cpustate, R14)); break; + case CPUINFO_STR_REGISTER + TMS9900_R15: sprintf(info->s, "R15:%04X", READREG_DEBUG(cpustate, R15)); break; + } +} diff --git a/src/devices/cpu/tms9900/ti990_10.c b/src/devices/cpu/tms9900/ti990_10.c new file mode 100644 index 00000000000..b6cd8d32d41 --- /dev/null +++ b/src/devices/cpu/tms9900/ti990_10.c @@ -0,0 +1,148 @@ +// license:BSD-3-Clause +// copyright-holders:Michael Zapf + +/* + Texas Instruments TI990/10 CPU board + + The first member of the family was actually the ti990/10 minicomputer, + released in 1975. tms9900 was released in 1976, and has the same + instruction set as ti990/10: however, tms9900 is slower, it does not + support privileges and memory mapping, and illegal instructions do not + cause an error interrupt. + + The ti990 family later evoluted into the huge ti990/12 system, with support + for 144 different instructions, and microcode programming in case some user + found it was not enough. ti990/10 was eventually replaced by a cheaper + ti990/10a board, built around a tms99000 microprocessor. + + tms99000 is the successor to both ti9900 and ti990/10. It supports + privileges, and has a coprocessor interface which enables the use of an + external memory mapper. Additionnally, it can use a Macrostore ROM to + emulate additional instructions. + + **** This is WORK IN PROGRESS **** +*/ + +#include "ti990_10.h" + +/* + The following defines can be set to 0 or 1 to disable or enable certain + output in the log. +*/ +// Emulation setup +#define TRACE_SETUP 0 + +// Emulation details +#define TRACE_EMU 0 + +/**************************************************************************** + Constructor for TI 990/10 + The CRU mask is related to the bits, not to their addresses which are + twice their number. Accordingly, the TMS9900 has a CRU bitmask 0x0fff. +****************************************************************************/ + +ti990_10_device::ti990_10_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : cpu_device(mconfig, TI990_10, "TI990/10 CPU", tag, owner, clock, "ti990_10_cpu", __FILE__), + m_program_config("program", ENDIANNESS_BIG, 16, 16), + m_io_config("cru", ENDIANNESS_BIG, 8, 12), + m_prgspace(NULL), + m_cru(NULL) +{ +} + +ti990_10_device::~ti990_10_device() +{ +} + +void ti990_10_device::device_start() +{ + m_prgspace = &space(AS_PROGRAM); + m_cru = &space(AS_IO); + + // set our instruction counter + m_icountptr = &m_icount; + + state_add(STATE_GENPC, "curpc", PC).formatstr("%4s").noshow(); + state_add(STATE_GENFLAGS, "status", m_state_any).callimport().callexport().formatstr("%16s").noshow(); +} + +void ti990_10_device::device_stop() +{ + if (TRACE_SETUP) logerror("ti990_10: Deleting lookup tables\n"); +} + +/* + TI990_10 hard reset + The device reset is just the emulator's trigger for the reset procedure + which is invoked via the main loop. +*/ +void ti990_10_device::device_reset() +{ + if (TRACE_EMU) logerror("ti990_10: Device reset by emulator\n"); +} + +const address_space_config *ti990_10_device::memory_space_config(address_spacenum spacenum) const +{ + switch (spacenum) + { + case AS_PROGRAM: + return &m_program_config; + + case AS_IO: + return &m_io_config; + + default: + return NULL; + } +} + +void ti990_10_device::execute_run() +{ + do + { + // TODO: Complete the implementation + m_icount--; + } while (m_icount>0); +} + +void ti990_10_device::execute_set_input(int irqline, int state) +{ +} + +// ========================================================================== + +UINT32 ti990_10_device::execute_min_cycles() const +{ + return 2; +} + +// TODO: Compute this value, just a wild guess for the average +UINT32 ti990_10_device::execute_max_cycles() const +{ + return 10; +} + +UINT32 ti990_10_device::execute_input_lines() const +{ + return 2; +} + +// device_disasm_interface overrides +UINT32 ti990_10_device::disasm_min_opcode_bytes() const +{ + return 2; +} + +UINT32 ti990_10_device::disasm_max_opcode_bytes() const +{ + return 6; +} + +// TODO: check 9900dasm +offs_t ti990_10_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( tms9900 ); + return CPU_DISASSEMBLE_NAME(tms9900)(this, buffer, pc, oprom, opram, options); +} + +const device_type TI990_10 = &device_creator; diff --git a/src/devices/cpu/tms9900/ti990_10.h b/src/devices/cpu/tms9900/ti990_10.h new file mode 100644 index 00000000000..f1d4e20ce3a --- /dev/null +++ b/src/devices/cpu/tms9900/ti990_10.h @@ -0,0 +1,61 @@ +// license:BSD-3-Clause +// copyright-holders:Michael Zapf +/* + TI 990 CPU board + See ti990_10.c for documentation +*/ + +#ifndef __TI990_10_H__ +#define __TI990_10_H__ + +#include "emu.h" +#include "debugger.h" +#include "tms99com.h" + +class ti990_10_device : public cpu_device +{ +public: + ti990_10_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + ~ti990_10_device(); + +protected: + // device-level overrides + void device_start(); + void device_stop(); + void device_reset(); + + // device_execute_interface overrides + UINT32 execute_min_cycles() const; + UINT32 execute_max_cycles() const; + UINT32 execute_input_lines() const; + void execute_set_input(int irqline, int state); + void execute_run(); + + // device_disasm_interface overrides + UINT32 disasm_min_opcode_bytes() const; + UINT32 disasm_max_opcode_bytes() const; + offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + + const address_space_config* memory_space_config(address_spacenum spacenum) const; + + const address_space_config m_program_config; + const address_space_config m_io_config; + address_space* m_prgspace; + address_space* m_cru; + + // Cycle counter + int m_icount; + + // Hardware registers + UINT16 WP; // Workspace pointer + UINT16 PC; // Program counter + UINT16 ST; // Status register + +private: + UINT16 m_state_any; +}; + +// device type definition +extern const device_type TI990_10; + +#endif /* __TI990_10_H__ */ diff --git a/src/devices/cpu/tms9900/tms9900.c b/src/devices/cpu/tms9900/tms9900.c new file mode 100644 index 00000000000..0029d9cf392 --- /dev/null +++ b/src/devices/cpu/tms9900/tms9900.c @@ -0,0 +1,2736 @@ +// license:BSD-3-Clause +// copyright-holders:Michael Zapf +/* + Texas Instruments TMS9900 + + +--------------------+ + V_BB | 1 o 64| /HOLD + V_CC | 2 63| /MEMEN + WAIT | 3 62| READY + /LOAD | 4 61| /WE + HOLDA | 5 60| CRUCLK + /RESET | 6 59| V_CC + IAQ | 7 58| - + PHI1 | 8 57| - + PHI2 | 9 56| D15 -+ LSB + LSB +- A14 |10 55| D14 | + | A13 |11 54| D13 | + | A12 |12 53| D12 | + | A11 |13 52| D11 | + Address | A10 |14 +--------+ 51| D10 | Data + bus | A9 |15 | | 50| D9 | bus + 32K * | A8 |16 | | 49| D8 | 16 bit + 16bit | A7 |17 | | 48| D7 | + | A6 |18 | | 47| D6 | + | A5 |19 +--------+ 46| D5 | + | A4 |20 45| D4 | + | A3 |21 44| D3 | + | A2 |22 43| D2 | + | A1 |23 42| D1 | + MSB +- A0 |24 41| D0 -+ MSB + PHI4 |25 40| V_SS + V_SS |26 39| - + V_DD |27 38| - + PHI3 |28 37| - + DBIN |29 36| IC0 -+ MSB + CRUOUT |30 35| IC1 | Interrupt + CRUIN |31 34| IC2 | level + /INTREQ |32 33| IC3 -+ LSB + +--------------------+ + + WAIT out Processor in wait state + /LOAD in Non-maskable interrupt + HOLDA out Hold acknowledge + /RESET in Reset + IAQ out Instruction acquisition + PHI1-4 in Clock phase inputs + DBIN out Data bus in input mode + CRUOUT out Communication register unit data output + CRUIN in Communication register unit data input + /INTREQ in Interrupt request + CRUCLK out Communication register unit clock output + /WE out Data available for memory write + READY in Memory ready for access + /MEMEN out Address bus contains memory address + /HOLD in External device acquires address and data bus lines + + V_BB -5V supply + V_CC +5V supply (pins 2 and 59 connected in parallel) + V_DD +12V supply + V_SS 0V Ground reference (pins 26 and 40 connected in parallel) + + A0-A14 out Address bus (32768 words of 16 bit width) + D0-A15 i/o Data bus + IC0-IC3 in Interrupt level (0-15) + + Note that Texas Instruments' bit numberings define bit 0 as the + most significant bit (different to most other systems). Also, the + system uses big-endian memory organisation: Storing the word 0x1234 at + address 0x0000 means that the byte 0x12 is stored at 0x0000 and byte 0x34 + is stored at 0x0001. + + The processor also knows byte-oriented operations (like add byte (AB), + move byte (MOVB)). This makes it necessary for the CPU to read the word + from the target memory location first, change the respective byte, and + write it back. + + See the TI-99/4A driver for an application of the TMS9900 processor + within an 8-bit data bus board layout (using a data bus multiplexer). + + Subcycle handling + + In this implementation we try to emulate the internal operations as + precisely as possible, following the technical specifications. We need + not try to be clock-precise with every tick; it suffices to perform + the proper number of operations within a given time span. + + For each command the CPU executes a microprogram which requires some + amount of cycles to complete. During this time the external clock continues + to issue pulses which can be used to control wait state creation. As we + do not emulate external clocks this implementation offers an extra output + "clock_out" (which, however, is available for the TMS9995) which pulses + at a rate of 3 MHz. External devices (e.g. memory controllers) may count + the pulses and pull down the READY line (with set_ready) as needed. + + Another possibility for creating wait states is to pull down the line + for some time set by a timer. This is done, for example, by circuits like + GROMs or speech synthesis processors (TMS52xx). + + TODO: + - Fine-tune cycles + - State save + - HOLD state should be tested; I don't have test cases yet + + Michael Zapf, June 2012 +*/ + +#include "tms9900.h" + +/* tms9900 ST register bits. */ +enum +{ + ST_LH = 0x8000, // Logical higher (unsigned comparison) + ST_AGT = 0x4000, // Arithmetical greater than (signed comparison) + ST_EQ = 0x2000, // Equal + ST_C = 0x1000, // Carry + ST_OV = 0x0800, // Overflow (when using signed operations) + ST_OP = 0x0400, // Odd parity (used with byte operations) + ST_X = 0x0200, // XOP + ST_IM = 0x000f // Interrupt mask +}; + +/* + The following defines can be set to 0 or 1 to disable or enable certain + output in the log. +*/ +// Emulation setup +#define TRACE_SETUP 0 + +// Emulation details +#define TRACE_EMU 0 + +// Location and command +#define TRACE_EXEC 0 + +// Memory operation +#define TRACE_MEM 0 + +// Address bus operation +#define TRACE_ADDRESSBUS 0 + +// Cycle count +#define TRACE_CYCLES 0 + +// Clock ticks +#define TRACE_CLOCK 0 + +// Wait states +#define TRACE_WAIT 0 + +// Interrupts +#define TRACE_INT 0 + +// CRU operation +#define TRACE_CRU 0 + +// Status register +#define TRACE_STATUS 0 + +// ALU details +#define TRACE_ALU 0 + +// Microinstruction level +#define TRACE_MICRO 0 + +/**************************************************************************** + Common constructor for TMS9900 and TMS9980A + The CRU mask is related to the bits, not to their addresses which are + twice their number. Accordingly, the TMS9900 has a CRU bitmask 0x0fff. +****************************************************************************/ + +tms99xx_device::tms99xx_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, int databus_width, int prg_addr_bits, int cru_addr_bits, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : cpu_device(mconfig, type, name, tag, owner, clock, shortname, source), + m_program_config("program", ENDIANNESS_BIG, databus_width, prg_addr_bits), + m_io_config("cru", ENDIANNESS_BIG, 8, cru_addr_bits), + m_prgspace(NULL), + m_cru(NULL), + m_prgaddr_mask((1<> 1) & 0x7fff; + } + } + str.assign(flags); +} + +/**************************************************************************/ + +UINT16 tms99xx_device::read_workspace_register_debug(int reg) +{ + int temp = m_icount; + m_prgspace->set_debugger_access(true); + UINT16 value = m_prgspace->read_word((WP+(reg<<1)) & m_prgaddr_mask & 0xfffe); + m_prgspace->set_debugger_access(false); + m_icount = temp; + return value; +} + +void tms99xx_device::write_workspace_register_debug(int reg, UINT16 data) +{ + int temp = m_icount; + m_prgspace->set_debugger_access(true); + m_prgspace->write_word((WP+(reg<<1)) & m_prgaddr_mask & 0xfffe, data); + m_prgspace->set_debugger_access(false); + m_icount = temp; +} + +const address_space_config *tms99xx_device::memory_space_config(address_spacenum spacenum) const +{ + switch (spacenum) + { + case AS_PROGRAM: + return &m_program_config; + + case AS_IO: + return &m_io_config; + + default: + return NULL; + } +} + +/************************************************************************** + Microprograms for the CPU instructions + + The actions which are specific to the respective instruction are + invoked by repeated calls of ALU_xxx; each call increases a state + variable so that on the next call, the next part can be processed. + This saves us a lot of additional functions. +**************************************************************************/ + +/* + Define the indices for the micro-operation table. This is done for the sake + of a simpler microprogram definition as an UINT8[]. +*/ +enum +{ + IAQ = 0, + MEMORY_READ, + MEMORY_WRITE, + REG_READ, + REG_WRITE, + CRU_INPUT, + CRU_OUTPUT, + DATA_DERIVE, + RET, + ABORT, + END, + + ALU_NOP, + ALU_CLR, + ALU_SETADDR, + ALU_ADDONE, + ALU_SETADDR_ADDONE, + ALU_PCADDR_ADVANCE, + ALU_SOURCE, + ALU_ADDREG, + ALU_IMM, + ALU_REG, + ALU_F1, + ALU_COMP, + ALU_F3, + ALU_MPY, + ALU_DIV, + ALU_XOP, + ALU_CLR_SWPB, + ALU_ABS, + ALU_X, + ALU_B, + ALU_BLWP, + ALU_LDCR, + ALU_STCR, + ALU_SBZ_SBO, + ALU_TB, + ALU_JMP, + ALU_SHIFT, + ALU_AI_ORI, + ALU_CI, + ALU_LI, + ALU_LWPI, + ALU_LIMI, + ALU_STWP_STST, + ALU_EXT, + ALU_RTWP, + ALU_INT +}; + + +#define MICROPROGRAM(_MP) \ + static const UINT8 _MP[] = + +/* + This is a kind of subroutine with 6 variants. Might be done in countless + better ways, but will suffice for now. Each variant has at most 8 steps + RET will return to the caller. + The padding simplifies the calculation of the start address: We just + take the Ts field as an index. In the last two cases we add an offset of 8 + if we have an indexed (resp. a byte) operation. +*/ +MICROPROGRAM(data_derivation) +{ + REG_READ, RET, 0, 0, 0, 0, 0, 0, // Rx (00) + 0, 0, 0, 0, 0, 0, 0, 0, + REG_READ, ALU_SETADDR, MEMORY_READ, RET, 0, 0, 0, 0, // *Rx (01) + 0, 0, 0, 0, 0, 0, 0, 0, + ALU_CLR, ALU_PCADDR_ADVANCE, MEMORY_READ, ALU_ADDREG, MEMORY_READ, RET, 0, 0, // @sym (10) + REG_READ, ALU_PCADDR_ADVANCE, MEMORY_READ, ALU_ADDREG, MEMORY_READ, RET, 0, 0, // @sym(Rx) (10) + REG_READ, ALU_SETADDR_ADDONE, ALU_ADDONE, REG_WRITE, MEMORY_READ, RET, 0, 0, // *Rx+ (word) (11) + REG_READ, ALU_SETADDR_ADDONE, REG_WRITE, MEMORY_READ, RET, 0, 0, 0 // *Rx+ (byte) (11) +}; + +MICROPROGRAM(f1_mp) +{ + ALU_NOP, + DATA_DERIVE, + ALU_SOURCE, // Store the word + DATA_DERIVE, + ALU_F1, + MEMORY_WRITE, + END +}; + +MICROPROGRAM(comp_mp) +{ + ALU_NOP, + DATA_DERIVE, + ALU_SOURCE, + DATA_DERIVE, + ALU_COMP, + ALU_NOP, // Compare operations do not write back any data + END +}; + +MICROPROGRAM(f3_mp) +{ + ALU_NOP, + DATA_DERIVE, + ALU_F3, + MEMORY_READ, // We have to distinguish this from the C/CB microprogram above + ALU_F3, + ALU_NOP, // Compare operations do not write back any data + END +}; + +MICROPROGRAM(xor_mp) +{ + ALU_NOP, + DATA_DERIVE, + ALU_F3, + MEMORY_READ, + ALU_F3, + MEMORY_WRITE, // XOR again must write back data, cannot reuse f3_mp + END +}; + +MICROPROGRAM(mult_mp) +{ + ALU_NOP, + DATA_DERIVE, + ALU_MPY, // Save the value; put register number in m_regnumber + MEMORY_READ, + ALU_MPY, // 18 cycles for multiplication + MEMORY_WRITE, // Write the high word + ALU_MPY, // Get low word, increase m_address + MEMORY_WRITE, + END +}; + +MICROPROGRAM(div_mp) +{ + ALU_NOP, + DATA_DERIVE, // Get divisor + ALU_DIV, // 0 Store divisor and get register number + MEMORY_READ, // Read register + ALU_DIV, // 1 Check overflow, increase address (or abort here) + ABORT, + MEMORY_READ, // Read subsequent word (if reg=15 this is behind the workspace) + ALU_DIV, // 2 Calculate quotient (takes variable amount of cycles; at least 32 machine cycles), set register number + MEMORY_WRITE, // Write quotient into register + ALU_DIV, // 3 Get remainder + MEMORY_WRITE, // Write remainder + END +}; + +MICROPROGRAM(xop_mp) +{ + ALU_NOP, + DATA_DERIVE, // Get argument + ALU_XOP, // 0 Save the address of the source operand, set address = 0x0040 + xopNr*4, 6 cycles + MEMORY_READ, // Read the new WP + ALU_XOP, // 1 Save old WP, set new WP, get the source operand address + MEMORY_WRITE, // Write the address of the source operand into the new R11 + ALU_XOP, // 2 + MEMORY_WRITE, // Write the ST into the new R15 + ALU_XOP, // 3 + MEMORY_WRITE, // Write the PC into the new R14 + ALU_XOP, // 4 + MEMORY_WRITE, // Write the WP into the new R13 + ALU_XOP, // 5 Set the X bit in the ST + MEMORY_READ, // Read the new PC + ALU_XOP, // 6 Set the new PC + END +}; + +MICROPROGRAM(clr_swpb_mp) +{ + ALU_NOP, + DATA_DERIVE, + ALU_CLR_SWPB, + MEMORY_WRITE, + END +}; + +MICROPROGRAM(abs_mp) +{ + ALU_NOP, + DATA_DERIVE, + ALU_ABS, // two cycles + MEMORY_WRITE, // skipped when ABS is not performed + ALU_NOP, + END +}; + +MICROPROGRAM(x_mp) +{ + ALU_NOP, + DATA_DERIVE, + ALU_X, + END +}; + +MICROPROGRAM(b_mp) // Branch +{ + ALU_NOP, + DATA_DERIVE, + ALU_B, + END +}; + +MICROPROGRAM(bl_mp) // Branch and Link +{ + ALU_NOP, + DATA_DERIVE, + ALU_B, + ALU_NOP, + MEMORY_WRITE, + END +}; + +MICROPROGRAM(blwp_mp) // Branch and Load WP +{ + ALU_NOP, + DATA_DERIVE, // Get argument + ALU_BLWP, // 0 Save old WP, set new WP, save position + ALU_NOP, + MEMORY_WRITE, // write ST to R15 + ALU_BLWP, // 1 + MEMORY_WRITE, // write PC to R14 + ALU_BLWP, // 2 + MEMORY_WRITE, // write WP to R13 + ALU_BLWP, // 3 Get saved position + MEMORY_READ, // Read new PC + ALU_BLWP, // 4 Set new PC + END +}; + +MICROPROGRAM(ldcr_mp) +{ + ALU_NOP, + DATA_DERIVE, + ALU_SOURCE, + ALU_NOP, + ALU_LDCR, + ALU_NOP, + MEMORY_READ, + ALU_LDCR, + CRU_OUTPUT, + ALU_NOP, + END +}; + +MICROPROGRAM(stcr_mp) +{ + ALU_NOP, + DATA_DERIVE, + ALU_SOURCE, // Store address and value + ALU_STCR, // 0 Set register_number = 12; 0 cycles (already done before) + MEMORY_READ, + ALU_STCR, // 1 Prepare CRU access + ALU_NOP, + CRU_INPUT, + ALU_STCR, // 2 Create result; Cycles = 5 + (8-#C-1) or + (16-#C) + ALU_NOP, + ALU_NOP, + ALU_NOP, + MEMORY_WRITE, + END +}; + +MICROPROGRAM(sbz_sbo_mp) +{ + ALU_SBZ_SBO, + ALU_NOP, + MEMORY_READ, + ALU_SBZ_SBO, + CRU_OUTPUT, + END +}; + +MICROPROGRAM(tb_mp) +{ + ALU_TB, + MEMORY_READ, + ALU_TB, + CRU_INPUT, + ALU_TB, + END +}; + +MICROPROGRAM(jmp_mp) +{ + ALU_NOP, + ALU_JMP, + ALU_JMP, + ALU_NOP, + END +}; + +MICROPROGRAM(shift_mp) +{ + ALU_SHIFT, + MEMORY_READ, + ALU_SHIFT, // 2 cycles if count != 0, else 4 + MEMORY_READ, // skipped if count != 0 + ALU_SHIFT, // skipped if count != 0 (4 cycles) + ALU_SHIFT, + MEMORY_WRITE, + ALU_NOP, + END +}; + +MICROPROGRAM(ai_ori_mp) +{ + ALU_REG, + MEMORY_READ, + ALU_IMM, + MEMORY_READ, + ALU_AI_ORI, + MEMORY_WRITE, + END +}; + +MICROPROGRAM(ci_mp) +{ + ALU_REG, + MEMORY_READ, + ALU_IMM, + MEMORY_READ, + ALU_CI, + ALU_NOP, + END +}; + +MICROPROGRAM(li_mp) +{ + ALU_IMM, + MEMORY_READ, + ALU_LI, // sets status bits + ALU_REG, // set register number + MEMORY_WRITE, + END +}; + +MICROPROGRAM(lwpi_mp) +{ + ALU_IMM, + MEMORY_READ, + ALU_NOP, + ALU_LWPI, // sets WP + END +}; + +MICROPROGRAM(limi_mp) +{ + ALU_IMM, + MEMORY_READ, + ALU_NOP, + ALU_LIMI, // sets interrupt mask in ST + ALU_NOP, + ALU_NOP, + END +}; + +MICROPROGRAM(stwp_stst_mp) +{ + ALU_STWP_STST, + ALU_REG, + MEMORY_WRITE, + END +}; + +MICROPROGRAM(external_mp) +{ + ALU_NOP, + ALU_NOP, + ALU_EXT, + ALU_NOP, + ALU_NOP, + END +}; + +MICROPROGRAM(rtwp_mp) +{ + ALU_NOP, + ALU_RTWP, + MEMORY_READ, + ALU_RTWP, // no cycles + MEMORY_READ, + ALU_RTWP, // no cycles + MEMORY_READ, + ALU_RTWP, + END +}; + +MICROPROGRAM(int_mp) +{ + ALU_NOP, + ALU_INT, // 0 Set address = 0 + MEMORY_READ, + ALU_INT, // 1 Save old WP, set new WP, save position + MEMORY_WRITE, // write ST to R15 + ALU_INT, // 2 + MEMORY_WRITE, // write PC to R14 + ALU_INT, // 3 + MEMORY_WRITE, // write WP to R13 + ALU_INT, // 4 Get saved position + MEMORY_READ, // Read new PC + ALU_INT, // 5 Set new PC + END +}; + +const tms99xx_device::ophandler tms99xx_device::s_microoperation[] = +{ + &tms99xx_device::acquire_instruction, + &tms99xx_device::mem_read, + &tms99xx_device::mem_write, + &tms99xx_device::register_read, + &tms99xx_device::register_write, + &tms99xx_device::cru_input_operation, + &tms99xx_device::cru_output_operation, + &tms99xx_device::data_derivation_subprogram, + &tms99xx_device::return_from_subprogram, + &tms99xx_device::abort_operation, + &tms99xx_device::command_completed, + + &tms99xx_device::alu_nop, + &tms99xx_device::alu_clear, + &tms99xx_device::alu_setaddr, + &tms99xx_device::alu_addone, + &tms99xx_device::alu_setaddr_addone, + &tms99xx_device::alu_pcaddr_advance, + &tms99xx_device::alu_source, + &tms99xx_device::alu_add_register, + &tms99xx_device::alu_imm, + &tms99xx_device::alu_reg, + + &tms99xx_device::alu_f1, + &tms99xx_device::alu_comp, + &tms99xx_device::alu_f3, + &tms99xx_device::alu_multiply, + &tms99xx_device::alu_divide, + &tms99xx_device::alu_xop, + &tms99xx_device::alu_clr_swpb, + &tms99xx_device::alu_abs, + &tms99xx_device::alu_x, + &tms99xx_device::alu_b, + &tms99xx_device::alu_blwp, + &tms99xx_device::alu_ldcr, + &tms99xx_device::alu_stcr, + &tms99xx_device::alu_sbz_sbo, + &tms99xx_device::alu_tb, + &tms99xx_device::alu_jmp, + &tms99xx_device::alu_shift, + &tms99xx_device::alu_ai_ori, + &tms99xx_device::alu_ci, + &tms99xx_device::alu_li, + &tms99xx_device::alu_lwpi, + &tms99xx_device::alu_limi, + &tms99xx_device::alu_stwp_stst, + &tms99xx_device::alu_external, + &tms99xx_device::alu_rtwp, + &tms99xx_device::alu_int +}; + +/***************************************************************************** + CPU instructions +*****************************************************************************/ + +/* + Available instructions +*/ +enum +{ + ILL=0, A, AB, ABS, AI, ANDI, B, BL, BLWP, C, + CB, CI, CKOF, CKON, CLR, COC, CZC, DEC, DECT, DIV, + IDLE, INC, INCT, INV, JEQ, JGT, JH, JHE, JL, JLE, + JLT, JMP, JNC, JNE, JNO, JOC, JOP, LDCR, LI, LIMI, + LREX, LWPI, MOV, MOVB, MPY, NEG, ORI, RSET, RTWP, S, + SB, SBO, SBZ, SETO, SLA, SOC, SOCB, SRA, SRC, SRL, + STCR, STST, STWP, SWPB, SZC, SZCB, TB, X, XOP, XOR, + INTR +}; + +/* + Formats: + + 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + ----+------------------------------------------------+ + 1 | Opcode | B | Td | RegNr | Ts | RegNr | + +--------+---+----+------------+----+------------+ + 2 | Opcode | Displacement | + +-----------------------+------------------------+ + 3 | Opcode | RegNr | Ts | RegNr | + +-----------------+------------+----+------------+ + 4 | Opcode | Count | Ts | RegNr | + +-----------------+------------+----+------------+ + 5 | Opcode | Count | RegNr | + +-----------------------+-----------+------------+ + 6 | Opcode | Ts | RegNr | + +------------------------------+----+------------+ + 7 | Opcode |0| 0| 0| 0| 0 | + +---------------------------------+-+--+--+--+---+ + 8 | Opcode |0| RegNr | + +---------------------------------+-+------------+ + 9 | Opcode | Reg/Nr | Ts | RegNr | + +-----------------+------------+----+------------+ +*/ + +/* + Defines the number of bits from the left which are significant for the + command in the respective format. +*/ +static const int format_mask_len[] = +{ + 0, 4, 8, 6, 6, 8, 10, 16, 12, 6 +}; + +const tms99xx_device::tms_instruction tms99xx_device::s_command[] = +{ + // Opcode, ID, format, microprg + { 0x0200, LI, 8, li_mp }, + { 0x0220, AI, 8, ai_ori_mp }, + { 0x0240, ANDI, 8, ai_ori_mp }, + { 0x0260, ORI, 8, ai_ori_mp }, + { 0x0280, CI, 8, ci_mp }, + { 0x02a0, STWP, 8, stwp_stst_mp }, + { 0x02c0, STST, 8, stwp_stst_mp }, + { 0x02e0, LWPI, 8, lwpi_mp }, + { 0x0300, LIMI, 8, limi_mp }, + { 0x0340, IDLE, 7, external_mp }, + { 0x0360, RSET, 7, external_mp }, + { 0x0380, RTWP, 7, rtwp_mp }, + { 0x03a0, CKON, 7, external_mp }, + { 0x03c0, CKOF, 7, external_mp }, + { 0x03e0, LREX, 7, external_mp }, + { 0x0400, BLWP, 6, blwp_mp }, + { 0x0440, B, 6, b_mp }, + { 0x0480, X, 6, x_mp }, + { 0x04c0, CLR, 6, clr_swpb_mp }, + { 0x0500, NEG, 6, clr_swpb_mp }, + { 0x0540, INV, 6, clr_swpb_mp }, + { 0x0580, INC, 6, clr_swpb_mp }, + { 0x05c0, INCT, 6, clr_swpb_mp }, + { 0x0600, DEC, 6, clr_swpb_mp }, + { 0x0640, DECT, 6, clr_swpb_mp }, + { 0x0680, BL, 6, bl_mp }, + { 0x06c0, SWPB, 6, clr_swpb_mp }, + { 0x0700, SETO, 6, clr_swpb_mp }, + { 0x0740, ABS, 6, abs_mp }, + { 0x0800, SRA, 5, shift_mp }, + { 0x0900, SRL, 5, shift_mp }, + { 0x0a00, SLA, 5, shift_mp }, + { 0x0b00, SRC, 5, shift_mp }, + { 0x1000, JMP, 2, jmp_mp }, + { 0x1100, JLT, 2, jmp_mp }, + { 0x1200, JLE, 2, jmp_mp }, + { 0x1300, JEQ, 2, jmp_mp }, + { 0x1400, JHE, 2, jmp_mp }, + { 0x1500, JGT, 2, jmp_mp }, + { 0x1600, JNE, 2, jmp_mp }, + { 0x1700, JNC, 2, jmp_mp }, + { 0x1800, JOC, 2, jmp_mp }, + { 0x1900, JNO, 2, jmp_mp }, + { 0x1a00, JL, 2, jmp_mp }, + { 0x1b00, JH, 2, jmp_mp }, + { 0x1c00, JOP, 2, jmp_mp }, + { 0x1d00, SBO, 2, sbz_sbo_mp }, + { 0x1e00, SBZ, 2, sbz_sbo_mp }, + { 0x1f00, TB, 2, tb_mp }, + { 0x2000, COC, 3, f3_mp }, + { 0x2400, CZC, 3, f3_mp }, + { 0x2800, XOR, 3, xor_mp }, + { 0x2c00, XOP, 3, xop_mp }, + { 0x3000, LDCR, 4, ldcr_mp }, + { 0x3400, STCR, 4, stcr_mp }, + { 0x3800, MPY, 9, mult_mp }, + { 0x3c00, DIV, 9, div_mp }, + { 0x4000, SZC, 1, f1_mp }, + { 0x5000, SZCB, 1, f1_mp }, + { 0x6000, S, 1, f1_mp }, + { 0x7000, SB, 1, f1_mp }, + { 0x8000, C, 1, comp_mp }, + { 0x9000, CB, 1, comp_mp }, + { 0xa000, A, 1, f1_mp }, + { 0xb000, AB, 1, f1_mp }, + { 0xc000, MOV, 1, f1_mp }, + { 0xd000, MOVB, 1, f1_mp }, + { 0xe000, SOC, 1, f1_mp }, + { 0xf000, SOCB, 1, f1_mp } +}; + +/* + Create a B-tree for looking up the commands. Each node can carry up to + 16 entries, indexed by 4 consecutive bits in the opcode. + + Works as follows: + + Opcode = 0201 (Load immediate value into register 1) + Opcode = 0284 (Compare immediate value with register 4) + + Table: [ Table0, table1, table2, ... tableF ] + | + +-------+ + v + table0: [ table00, table01, table02, ... table0f ] + | + +-------------------------+ + v + table02: [ table020, table021, ... table028, ... table02f ] + | | | + v v v + Entry NULL Entry + for LI for CI + + For each level in the tree, four more bits are compared. The search + terminates when the number of compared bits is equal or higher than + the number of significant bits of the format of this opcode. The entry + points to the respective line in s_command. + + This way we can decode all format 1 commands by a single pass (including the + most frequent command MOV), and almost all commands by less than four passes. + + The disadvantage is that we have to build these tables from the opcode + list at runtime, and many positions are empty. But we do not need more + than 20 tables for the TMS command set. +*/ +void tms99xx_device::build_command_lookup_table() +{ + int i = 0; + int cmdindex = 0; + int bitcount; + const tms_instruction *inst; + UINT16 opcode; + int k = 0; + + m_command_lookup_table = new lookup_entry[16]; + // We use lotables as a list of allocated tables - to be able to delete them + // at the end. + m_lotables[k++] = m_command_lookup_table; + + lookup_entry* table = m_command_lookup_table; + for (int j=0; j < 16; j++) + { + table[j].entry = NULL; + table[j].next_digit = NULL; + } + + do + { + inst = &s_command[i]; + table = m_command_lookup_table; + if (TRACE_SETUP) logerror("tms99xx: === opcode=%04x, len=%d\n", inst->opcode, format_mask_len[inst->format]); + bitcount = 4; + opcode = inst->opcode; + cmdindex = (opcode>>12) & 0x000f; + + while (bitcount < format_mask_len[inst->format]) + { + // Descend + if (table[cmdindex].next_digit == NULL) + { + if (TRACE_SETUP) logerror("tms99xx: create new table at bitcount=%d for index=%d\n", bitcount, cmdindex); + table[cmdindex].next_digit = new lookup_entry[16]; + m_lotables[k++] = table[cmdindex].next_digit; + for (int j=0; j < 16; j++) + { + table[cmdindex].next_digit[j].next_digit = NULL; + table[cmdindex].next_digit[j].entry = NULL; + } + } + else + { + if (TRACE_SETUP) logerror("tms99xx: found a table at bitcount=%d\n", bitcount); + } + + table = table[cmdindex].next_digit; + + bitcount = bitcount+4; + opcode <<= 4; + cmdindex = (opcode>>12) & 0x000f; + if (TRACE_SETUP) logerror("tms99xx: next index=%x\n", cmdindex); + } + + if (TRACE_SETUP) logerror("tms99xx: bitcount=%d\n", bitcount); + // We are at the target level + // Need to fill in the same entry for all values in the bitcount + // (if a command needs 10 bits we have to copy it four + // times for all combinations with 12 bits) + for (int j=0; j < (1<<(bitcount-format_mask_len[inst->format])); j++) + { + if (TRACE_SETUP) logerror("tms99xx: opcode=%04x at position %d\n", inst->opcode, cmdindex+j); + table[cmdindex+j].entry = inst; + } + + i++; + } while (inst->opcode != 0xf000); + + m_lotables[k++] = NULL; + if (TRACE_SETUP) logerror("tms99xx: Allocated %d tables\n", k); +} + +/* + Main execution loop + + For each invocation of execute_run, a number of loop iterations has been + calculated before (m_icount). Each loop iteration is one clock cycle. + The loop must be executed for the number of times that corresponds to the + time until the next timer event. + + In this implementation, each loop iteration also causes the clock line to + pulse once. External devices may use this pulse to decrement counters + which control the READY line. + + Machine cycles to clock input: + + +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ + | | | | | | | | | | | | | | | | | | clock (1 of 4 phases) + +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ + + |-------|-------|-------|-------|---- cycles (2 clock pulses each) + + Wait states only have effect for memory operations. They are processed as + follows: + + 1) The CPU sets the address bus for reading. If READY is low, the CPU + waits for the next clock tick repeatedly until READY is high again. + When this is the case, the data bus is sampled on the next clock tick + and the read operation is complete. + + As we do not have a split-phase read operation in this emulation + we actually read the data bus instantly but wait for the READY line to + be high again. + + 2) The CPU sets the address bus for writing. In the same moment, the data + bus is loaded with the word to be written. On the next clock tick, + the CPU checks the READY line and waits until it is high. When READY + is high at a clock tick, the operation is complete on the next clock tick. +*/ +void tms99xx_device::execute_run() +{ + if (m_reset) service_interrupt(); + + if (TRACE_EMU) logerror("tms99xx: calling execute_run for %d cycles\n", m_icount); + do + { + // Only when last instruction has completed + if (m_program == NULL) + { + if (m_load_state) + { + logerror("tms99xx: LOAD interrupt\n"); + m_irq_level = LOAD_INT; + m_irq_state = false; + service_interrupt(); + } + else + { + // Interrupts are serviced when + // - an interrupt condition is signaled over INTREQ and + // - the level indicated by IC0-IC3 is lower than the interrupt mask value and + // - the previous instruction is not an XOP or BLWP + if (m_irq_state && (m_irq_level <= (ST & 0x000f)) && (m_command != XOP && m_command != BLWP)) + service_interrupt(); + } + } + + if (m_program == NULL && m_idle_state) + { + if (TRACE_WAIT) logerror("tms99xx: idle state\n"); + pulse_clock(1); + if (!m_external_operation.isnull()) + { + m_external_operation(IDLE_OP, 0, 0xff); + m_external_operation(IDLE_OP, 1, 0xff); + } + } + else + { + // Handle HOLD + // A HOLD request is signalled through the input line HOLD. + // The hold state will be entered with the next non-memory access cycle. + if (m_hold_state && + (m_program==NULL || + (m_program[MPC] != IAQ && + m_program[MPC] != MEMORY_READ && m_program[MPC] != MEMORY_WRITE && + m_program[MPC] != REG_READ && m_program[MPC] != REG_WRITE))) + { + if (TRACE_WAIT) logerror("tms99xx: hold\n"); + if (!m_hold_acknowledged) acknowledge_hold(); + pulse_clock(1); + } + else + { + // Normal operation + if (m_check_ready && m_ready == false) + { + // We are in a wait state + set_wait_state(true); + if (TRACE_WAIT) logerror("tms99xx: wait\n"); + // The clock output should be used to change the state of an outer + // device which operates the READY line + pulse_clock(1); + } + else + { + set_wait_state(false); + m_check_ready = false; + + if (m_program==NULL) m_op = IAQ; + else + { + m_op = m_program[MPC]; + } + if (TRACE_MICRO) logerror("tms99xx: MPC = %d, m_op = %d\n", MPC, m_op); + // Call the operation of the microprogram + (this->*s_microoperation[m_op])(); + // If we have multiple passes (as in the TMS9980) + m_pass--; + if (m_pass<=0) + { + m_pass = 1; + MPC++; + m_mem_phase = 1; + if (!m_iaq_line.isnull()) m_iaq_line(CLEAR_LINE); + } + } + } + } + } while (m_icount>0 && !m_reset); + if (TRACE_EMU) logerror("tms99xx: cycles expired; will return soon.\n"); +} + +/**************************************************************************/ + +/* + Interrupt input +*/ +void tms99xx_device::execute_set_input(int irqline, int state) +{ + if (irqline==INT_9900_RESET && state==ASSERT_LINE) + { + m_reset = true; + } + else + { + if (irqline == INT_9900_LOAD) + { + m_load_state = (state==ASSERT_LINE); + m_irq_level = -1; + m_reset = false; + } + else + { + m_irq_state = (state==ASSERT_LINE); + if (state==ASSERT_LINE) + { + m_irq_level = get_intlevel(state); + if (TRACE_INT) logerror("tms99xx: /INT asserted, level=%d, ST=%04x\n", m_irq_level, ST); + } + else + { + if (TRACE_INT) logerror("tms99xx: /INT cleared\n"); + } + } + } +} + +/* + This can be overloaded by variants of TMS99xx. +*/ +int tms99xx_device::get_intlevel(int state) +{ + if (!m_get_intlevel.isnull()) return m_get_intlevel(0); + return 0; +} + +void tms99xx_device::service_interrupt() +{ + m_program = int_mp; + m_command = INTR; + m_idle_state = false; + if (!m_external_operation.isnull()) m_external_operation(IDLE_OP, 0, 0xff); + + m_state = 0; + + if (!m_dbin_line.isnull()) m_dbin_line(ASSERT_LINE); + + // If reset, we just start with execution, otherwise we put the MPC + // on the first microinstruction, which also means that the main loop shall + // leave it where it is. So we pretend we have another pass to do. + m_pass = m_reset? 1 : 2; + + if (m_reset) + { + m_irq_level = RESET_INT; + + m_ready_bufd = true; + m_ready = true; + m_load_state = false; + m_hold_state = false; + m_hold_acknowledged = false; + m_wait_state = false; + IR = 0; + ST = 0; + m_mem_phase = 1; + + m_reset = false; + } + if (TRACE_INT) + { + switch (m_irq_level) + { + case RESET_INT: logerror("tms99xx: **** triggered a RESET interrupt\n"); break; + case LOAD_INT: logerror("tms99xx: **** triggered a LOAD (NMI) interrupt\n"); break; + default: logerror("tms99xx: ** triggered an interrupt on level %d\n", m_irq_level); break; + } + } + + MPC = 0; + m_first_cycle = m_icount; +} + +/* + Issue a pulse on the clock line. +*/ +void tms99xx_device::pulse_clock(int count) +{ + for (int i=0; i < count; i++) + { + if (!m_clock_out_line.isnull()) m_clock_out_line(ASSERT_LINE); + m_ready = m_ready_bufd; // get the latched READY state + if (!m_clock_out_line.isnull()) m_clock_out_line(CLEAR_LINE); + m_icount--; // This is the only location where we count down the cycles. + if (TRACE_CLOCK) + { + if (m_check_ready) logerror("tms99xx: pulse_clock, READY=%d\n", m_ready? 1:0); + else logerror("tms99xx: pulse_clock\n"); + } + } +} + +/* + Enter the hold state. +*/ +void tms99xx_device::set_hold(int state) +{ + m_hold_state = (state==ASSERT_LINE); + if (!m_hold_state) + { + m_hold_acknowledged = false; + if (!m_holda_line.isnull()) m_holda_line(CLEAR_LINE); + } +} + +/* + Acknowledge the HOLD request. +*/ +inline void tms99xx_device::acknowledge_hold() +{ + m_hold_acknowledged = true; + if (!m_holda_line.isnull()) m_holda_line(ASSERT_LINE); +} + +/* + Signal READY to the CPU. When cleared, the CPU enters wait states. This + becomes effective on a clock pulse. +*/ +void tms99xx_device::set_ready(int state) +{ + m_ready_bufd = (state==ASSERT_LINE); +} + +void tms99xx_device::abort_operation() +{ + command_completed(); +} + +/* + Enter or leave the wait state. We only operate the WAIT line when there is a change. +*/ +inline void tms99xx_device::set_wait_state(bool state) +{ + if (m_wait_state != state) + if (!m_wait_line.isnull()) m_wait_line(state? ASSERT_LINE : CLEAR_LINE); + m_wait_state = state; +} + +/* + Acquire the next word as an instruction. The program counter advances by + one word. +*/ +void tms99xx_device::decode(UINT16 inst) +{ + int index = 0; + lookup_entry* table = m_command_lookup_table; + UINT16 opcode = inst; + bool complete = false; + const tms_instruction *decoded; + + m_state = 0; + IR = inst; + m_get_destination = false; + m_byteop = false; + + while (!complete) + { + index = (opcode >> 12) & 0x000f; + if (TRACE_MICRO) logerror("tms99xx: Check next hex digit of instruction %x\n", index); + if (table[index].next_digit != NULL) + { + table = table[index].next_digit; + opcode = opcode << 4; + } + else complete = true; + } + decoded = table[index].entry; + if (decoded == NULL) + { + // not found + logerror("tms99xx: Illegal opcode %04x\n", inst); + IR = 0; + // This will cause another instruction acquisition in the next machine cycle + // with an asserted IAQ line (can be used to indicate this illegal opcode detection). + m_program = NULL; + } + else + { + m_program = decoded->prog; + MPC = -1; + m_command = decoded->id; + if (TRACE_MICRO) logerror("tms99xx: Command decoded as id %d, %s, base opcode %04x\n", m_command, opname[m_command], decoded->opcode); + // Byte operations are either format 1 with the byte flag set + // or format 4 (CRU multi bit operations) with 1-8 bits to transfer. + m_byteop = ((decoded->format==1 && ((IR & 0x1000)!=0)) + || (decoded->format==4 && (((IR >> 6)&0x000f) > 0) && (((IR >> 6)&0x000f) > 9))); + } + m_pass = 1; +} + +inline bool tms99xx_device::byte_operation() +{ + return (IR & 0x1000)!=0; +} + +void tms99xx_device::acquire_instruction() +{ + if (m_mem_phase == 1) + { + if (!m_iaq_line.isnull()) m_iaq_line(ASSERT_LINE); + m_address = PC; + m_first_cycle = m_icount; + } + + mem_read(); + + if (m_mem_phase == 1) + { + decode(m_current_value); + if (TRACE_EXEC) logerror("tms99xx: %04x: %04x (%s)\n", PC, IR, opname[m_command]); + debugger_instruction_hook(this, PC); + PC = (PC + 2) & 0xfffe & m_prgaddr_mask; + // IAQ will be cleared in the main loop + } +} + +/* + Memory read + Clock cycles: 2 + W, W = number of wait states +*/ +void tms99xx_device::mem_read() +{ + // After set_address, any device attached to the address bus may pull down + // READY in order to put the CPU into wait state before the read_word + // operation will be performed + // set_address and read_word should pass the same address as argument + if (m_mem_phase==1) + { + if (!m_dbin_line.isnull()) m_dbin_line(ASSERT_LINE); + m_prgspace->set_address(m_address & m_prgaddr_mask & 0xfffe); + m_check_ready = true; + m_mem_phase = 2; + m_pass = 2; + if (TRACE_ADDRESSBUS) logerror("tms99xx: set address (r) %04x\n", m_address); + + pulse_clock(1); // Concludes the first cycle + // If READY has been found to be low, the CPU will now stay in the wait state loop + } + else + { + // Second phase (after READY was raised again) + m_current_value = m_prgspace->read_word(m_address & m_prgaddr_mask & 0xfffe); + pulse_clock(1); + if (!m_dbin_line.isnull()) m_dbin_line(CLEAR_LINE); + m_mem_phase = 1; // reset to phase 1 + if (TRACE_MEM) logerror("tms99xx: mem r %04x -> %04x\n", m_address, m_current_value); + } +} + +void tms99xx_device::mem_write() +{ + if (m_mem_phase==1) + { + if (!m_dbin_line.isnull()) m_dbin_line(CLEAR_LINE); + // When writing, the data bus is asserted immediately after the address bus + if (TRACE_ADDRESSBUS) logerror("tms99xx: set address (w) %04x\n", m_address); + m_prgspace->set_address(m_address & m_prgaddr_mask & 0xfffe); + if (TRACE_MEM) logerror("tms99xx: mem w %04x <- %04x\n", m_address, m_current_value); + m_prgspace->write_word(m_address & m_prgaddr_mask & 0xfffe, m_current_value); + m_check_ready = true; + m_mem_phase = 2; + m_pass = 2; + pulse_clock(1); + } + else + { + // Second phase (we arrive here when the wait states are over) + pulse_clock(1); + } +} + +void tms99xx_device::register_read() +{ + // Need to set m_address for F1/F3 (we don't know what the data_derive did) + if (m_mem_phase==1) + { + m_address = WP + (m_regnumber<<1); + } + + mem_read(); + + if (m_mem_phase==1) + { + m_register_contents = m_current_value; + } +} + +/* + Memory write: + + Clock cycles: 2 + W, W = number of wait states +*/ +void tms99xx_device::register_write() +{ + // This will be called twice; m_pass is set by the embedded mem_write + UINT16 addr_save = m_address; + m_address = (WP + (m_regnumber<<1)) & m_prgaddr_mask & 0xfffe; + mem_write(); + m_address = addr_save; +} + +/* + CRU support code + + The CRU bus is a 1-bit-wide I/O bus. The CPU can read or write bits at random address. + Special instructions are dedicated to reading and writing one or several consecutive bits. + + The CRU uses the same address bus as the normal memory access. For writing, + the CRUCLK line is pulsed, but not for reading where CRUCLK stays cleared. + This means that each normal memory access also causes read accesses on the + CRU side. The /MEMEN line may be used to distinguish the kinds of accesses + as it stays cleared during CRU operations. + + We do not emulate this here as it seems there are no real applications of + this side effect. Real designs must ensure that CRU read operations are + idempotent (i.e. they must not change the state of the queried device). + + Read returns the number of consecutive CRU bits, with increasing CRU address + from the least significant to the most significant bit; right-aligned + + There seems to be no handling of wait states during CRU operations on the + TMS9900. The TMS9995, in contrast, respects wait states during the transmission + of each single bit. + + Usage of this method: + CRU write: First bit is at rightmost position of m_value. +*/ + +void tms99xx_device::cru_input_operation() +{ + int value, value1; + int offset, location; + + location = (m_cru_address >> 4) & (m_cruaddr_mask>>3); + offset = (m_cru_address>>1) & 0x07; + + // Read 8 bits (containing the desired bits) + value = m_cru->read_byte(location); + + if ((offset + m_count) > 8) // spans two 8 bit cluster + { + // Read next 8 bits + location = (location + 1) & (m_cruaddr_mask>>3); + value1 = m_cru->read_byte(location); + value |= (value1 << 8); + + if ((offset + m_count) > 16) // spans three 8 bit cluster + { + // Read next 8 bits + location = (location + 1) & (m_cruaddr_mask>>3); + value1 = m_cru->read_byte(location); + value |= (value1 << 16); + } + } + + // On each machine cycle (2 clocks) only one CRU bit is transmitted + pulse_clock(m_count<<1); + + // Shift back the bits so that the first bit is at the rightmost place + m_value = (value >> offset); + + // Mask out what we want + m_value &= (0x0000ffff >> (16-m_count)); +} + +void tms99xx_device::cru_output_operation() +{ + int value; + int location; + location = (m_cru_address >> 1) & m_cruaddr_mask; + value = m_value; + + // Write m_count bits from cru_address + for (int i=0; i < m_count; i++) + { + if (TRACE_CRU) logerror("tms99xx: CRU output operation, address %04x, value %d\n", location<<1, value & 0x01); + m_cru->write_byte(location, (value & 0x01)); + value >>= 1; + location = (location + 1) & m_cruaddr_mask; + pulse_clock(2); + } +} + +void tms99xx_device::return_from_subprogram() +{ + // Return from data derivation + // The result should be in m_current_value + // and the address in m_address + m_program = m_caller; + MPC = m_caller_MPC; // will be increased on return +} + +void tms99xx_device::command_completed() +{ + // Pseudo state at the end of the current instruction cycle sequence + if (TRACE_CYCLES) + { + logerror("tms99xx: ------"); + int cycles = m_first_cycle - m_icount; + // Avoid nonsense values due to expired and resumed main loop + if (cycles > 0 && cycles < 10000) logerror(" %d cycles", cycles); + logerror("\n"); + } + m_program = NULL; +} + +/* + This is a switch to a subprogram; there is only one, the data + derivation. In terms of cycles, it does not take any time; execution + continues with the first instruction of the subprogram. +*/ +void tms99xx_device::data_derivation_subprogram() +{ + UINT16 ircopy = IR; + + // Save the return program and position + m_caller = m_program; + m_caller_MPC = MPC; + + // Source or destination argument? + if (m_get_destination) ircopy >>= 6; + + m_regnumber = ircopy & 0x000f; + + m_program = (UINT8*)data_derivation; + MPC = ircopy & 0x0030; + + if (((MPC == 0x0020) && (m_regnumber != 0)) // indexed + || ((MPC == 0x0030) && m_byteop)) // byte operation + { + MPC += 8; // the second option + } + m_get_destination = true; // when we call this the second time before END it's the destination + m_pass = 2; +} + + +/************************************************************************** + Status bit operations +**************************************************************************/ + +inline void tms99xx_device::set_status_bit(int bit, bool state) +{ + if (state) ST |= bit; + else ST &= ~bit; +} + +void tms99xx_device::set_status_parity(UINT8 value) +{ + int count = 0; + for (int i=0; i < 8; i++) + { + if ((value & 0x80)!=0) count++; + value <<= 1; + } + set_status_bit(ST_OP, (count & 1)!=0); +} + +inline void tms99xx_device::compare_and_set_lae(UINT16 value1, UINT16 value2) +{ + set_status_bit(ST_EQ, value1 == value2); + set_status_bit(ST_LH, value1 > value2); + set_status_bit(ST_AGT, (INT16)value1 > (INT16)value2); + if (TRACE_STATUS) logerror("tms99xx: ST = %04x (val1=%04x, val2=%04x)\n", ST, value1, value2); +} + +/************************************************************************** + ALU operations +**************************************************************************/ + +void tms99xx_device::alu_nop() +{ + // Do nothing (or nothing that is externally visible) + pulse_clock(2); + return; +} + +void tms99xx_device::alu_source() +{ + // Copy the current value into the source data register + m_source_even = ((m_address & 1)==0); + m_source_value = m_current_value; + m_source_address = m_address; + pulse_clock(2); +} + +void tms99xx_device::alu_clear() +{ + // Clears the register contents + m_register_contents = 0; + pulse_clock(2); +} + +void tms99xx_device::alu_setaddr() +{ + // Load the current value into the address register + m_address = m_current_value; + pulse_clock(2); +} + +void tms99xx_device::alu_addone() +{ + m_current_value++; + pulse_clock(2); +} + +void tms99xx_device::alu_setaddr_addone() +{ + // Set the address register and increase the recent value + m_address = m_current_value; + m_current_value++; + pulse_clock(2); +} + +void tms99xx_device::alu_pcaddr_advance() +{ + // Set PC as new read address, increase by 2 + m_address = PC; + PC = (PC + 2) & 0xfffe & m_prgaddr_mask; + pulse_clock(2); +} + +void tms99xx_device::alu_add_register() +{ + // Add the register contents to the current value and set as address + m_address = m_current_value + m_register_contents; + pulse_clock(2); +} + +void tms99xx_device::alu_imm() +{ + m_value_copy = m_current_value; + m_address_copy = m_address; + m_address = PC; + PC = (PC + 2) & 0xfffe & m_prgaddr_mask; + pulse_clock(2); +} + +void tms99xx_device::alu_reg() +{ + m_address = (WP + ((IR & 0x000f)<<1)) & m_prgaddr_mask; + pulse_clock(2); +} + +void tms99xx_device::alu_f1() +{ + UINT32 dest_new = 0; + + // Save the destination value + UINT16 prev_dest_value = m_current_value; + + m_destination_even = ((m_address & 1)==0); // this is the destination address; the source address has already been saved + bool byteop = byte_operation(); + + if (byteop) + { + if (!m_destination_even) m_current_value <<= 8; + if (!m_source_even) m_source_value <<= 8; + // We have to strip away the low byte, or byte operations may fail + // e.g. 0x10ff + 0x0101 = 0x1200 + // or 0x2000 - 0x0101 = 0x1eff + m_source_value &= 0xff00; + m_current_value &= 0xff00; + } + + switch (m_command) + { + case A: + case AB: + // Add the contents of the source data to the destination data + // May exceed 0xffff (for carry check) + dest_new = m_current_value + m_source_value; + + // 1000 + e000 = f000 (L) + // c000 + c000 = 8000 (LC) + // 7000 + 4000 = b000 (LO) + // 2000 + f000 = 1000 (LAC) + // c000 + b000 = 7000 (LACO) + // 2000 + e000 = 0000 (EC) + // 8000 + 8000 = 0000 (ECO) + + // When adding, a carry occurs when we exceed the 0xffff value. + set_status_bit(ST_C, (dest_new & 0x10000) != 0); + // If the result has a sign bit that is different from both arguments, we have an overflow + // (i.e. getting a negative value from two positive values and vice versa) + set_status_bit(ST_OV, ((dest_new ^ m_current_value) & (dest_new ^ m_source_value) & 0x8000)!=0); + break; + + case S: + case SB: + // Subtract the contents of the source data from the destination data + dest_new = m_current_value + ((~m_source_value) & 0xffff) + 1; + // LAECO(P) + // 8000 - 8000 = 0000 (EC) + // 2000 - 8000 = a000 (LO) + // 8000 - 2000 = 6000 (LACO) + // 2000 - 1000 = 1000 (LAC) + // 1000 - 2000 = f000 (L) + // 1000 - 1000 = 0000 (EC) + // 1000 - f000 = 2000 (LA) + // f000 - 2000 = d000 (LC) + + // Subtraction means adding the 2s complement, so the carry bit + // is set whenever adding the 2s complement exceeds ffff + // In fact the CPU adds the one's complement, then adds a one. This + // explains why subtracting 0 sets the carry bit. + set_status_bit(ST_C, (dest_new & 0x10000) != 0); + + // If the arguments have different sign bits and the result has a + // sign bit different from the destination value, we have an overflow + // e.g. value1 = 0x7fff, value2 = 0xffff; value1-value2 = 0x8000 + // or value1 = 0x8000, value2 = 0x0001; value1-value2 = 0x7fff + // value1 is the destination value + set_status_bit(ST_OV, (m_current_value ^ m_source_value) & (m_current_value ^ dest_new) & 0x8000); + break; + + case SOC: + case SOCB: + // OR the contents of the source data on the destination data + dest_new = m_current_value | m_source_value; + break; + + case SZC: + case SZCB: + // AND the one's complement of the contents of the source data on the destination data + dest_new = m_current_value & ~m_source_value; + break; + + case MOV: + case MOVB: + // Copy the source data to the destination data + dest_new = m_source_value; + break; + } + + if (byteop) + { + set_status_parity((UINT8)(dest_new>>8)); + + // destnew is the new value to be written (high byte); needs to be + // merged with the existing word + if (m_destination_even) + m_current_value = (prev_dest_value & 0x00ff) | (dest_new & 0xff00); + else + m_current_value = (prev_dest_value & 0xff00) | ((dest_new >> 8) & 0x00ff); + compare_and_set_lae((UINT16)(dest_new & 0xff00), 0); + } + else + { + m_current_value = (UINT16)(dest_new & 0xffff); + compare_and_set_lae((UINT16)(dest_new & 0xffff), 0); + } + + pulse_clock(2); +} + +void tms99xx_device::alu_comp() +{ + m_destination_even = ((m_address & 1)==0); // this is the destination address; the source address has already been saved + if (byte_operation()) + { + if (!m_destination_even) m_current_value <<= 8; + if (!m_source_even) m_source_value <<= 8; + set_status_parity((UINT8)(m_source_value>>8)); + compare_and_set_lae(m_source_value & 0xff00, m_current_value & 0xff00); + } + else + compare_and_set_lae(m_source_value, m_current_value); + + pulse_clock(2); +} + +void tms99xx_device::alu_f3() +{ + switch (m_state) + { + case 0: + // Get register address + m_address = WP + ((IR >> 5) & 0x001e); + m_source_value = m_current_value; + break; + case 1: + if (m_command == COC) + { + set_status_bit(ST_EQ, (m_current_value & m_source_value) == m_source_value); + } + else + { + if (m_command == CZC) + { + set_status_bit(ST_EQ, (~m_current_value & m_source_value) == m_source_value); + } + else + { + // XOR + // The workspace register address is still in m_address + m_current_value = (m_current_value ^ m_source_value); + compare_and_set_lae(m_current_value, 0); + } + } + if (TRACE_STATUS) logerror("tms99xx: ST = %04x\n", ST); + break; + } + + m_state++; + pulse_clock(2); +} + +void tms99xx_device::alu_multiply() +{ + UINT32 result = 0; + + switch (m_state) + { + case 0: // After data derivation + m_source_value = m_current_value; + m_address = ((IR >> 5) & 0x001e) + WP; + break; + case 1: // After reading the register (multiplier) + if (TRACE_ALU) logerror("tms99xx: Multiply %04x by %04x\n", m_current_value, m_source_value); + result = (m_source_value & 0x0000ffff) * (m_current_value & 0x0000ffff); + m_current_value = (result >> 16) & 0xffff; + m_value_copy = result & 0xffff; + pulse_clock(34); // add 36 clock cycles (18 machine cycles); last one in main loop + break; + case 2: // After writing the high word to the destination register + m_current_value = m_value_copy; // Prepare to save low word + m_address = (m_address + 2) & m_prgaddr_mask; + break; + } + pulse_clock(2); + m_state++; +} + +void tms99xx_device::alu_divide() +{ + // Format is DIV Divisor,REG(dividend) + UINT32 uval32; + bool overflow = true; + UINT16 value1; + + switch (m_state) + { + case 0: + m_source_value = m_current_value; // store divisor + // Set address of register + m_address = WP + ((IR >> 5) & 0x001e); + m_address_copy = m_address; + break; + case 1: + // We have an overflow when the quotient cannot be stored in 16 bits + // This is the case when the dividend / divisor >= 0x10000, + // or equivalently, dividend / 0x10000 >= divisor + + if (m_current_value < m_source_value) // also if source=0 + { + MPC++; // skip the abort + overflow = false; + } + set_status_bit(ST_OV, overflow); + m_value_copy = m_current_value; // Save the high word + m_address = (m_address + 2) & m_prgaddr_mask; // Read next word + break; + case 2: + // W2 is in m_current_value + // Create full word and perform division + uval32 = (m_value_copy << 16) | m_current_value; + + if (TRACE_ALU) logerror("tms99xx: Dividing %08x by %04x\n", uval32, m_source_value); + m_current_value = uval32 / m_source_value; + m_value_copy = uval32 % m_source_value; + + if (TRACE_ALU) logerror("tms99xx: Quotient %04x, remainder %04x\n", m_current_value, m_value_copy); + + m_address = m_address_copy; + + // The number of ALU cycles depends on the number of steps in + // the division algorithm. The number of cycles is between 32 and + // 48 (*2 for clock cycles) + // As I don't have a description of the actual algorithm, I'll use + // the following heuristic: We use 32 ALU cycles in general, then + // we need as many cycles as it takes to + // shift away the dividend. Thus, bigger dividends need more cycles. + + pulse_clock(62); // one pulse is at the start, one at the end + value1 = m_value_copy & 0xffff; + + while (value1 != 0) + { + value1 = (value1 >> 1) & 0xffff; + pulse_clock(2); + } + // We still have m_regnumber; this is where m_current_value will go to + break; + case 3: + // Prepare to write the remainder + m_current_value = m_value_copy; + m_address = m_address + 2; + if (TRACE_STATUS) logerror("tms99xx: ST = %04x (div)\n", ST); + break; + } + pulse_clock(2); + m_state++; +} + +void tms99xx_device::alu_xop() +{ + switch (m_state) + { + case 0: + // We have the effective address of the source operand in m_address + m_address_saved = m_address; + // Now we take the XOP number from the instruction register + // and calculate the vector location + // [0010 11xx xx tt SSSS] shift 6 right, then *4 => shift 4 right + m_address = 0x0040 + ((IR >> 4) & 0x003c); + // Takes some additional cycles + pulse_clock(4); + break; + case 1: + m_value_copy = WP; // save the old WP + WP = m_current_value & m_prgaddr_mask & 0xfffe; // the new WP has been read in the previous microoperation + m_current_value = m_address_saved; // we saved the address of the source operand; retrieve it + m_address = WP + 0x0016; // Next register is R11 + break; + case 2: + m_address = WP + 0x001e; + m_current_value = ST; + break; + case 3: + m_address = WP + 0x001c; + m_current_value = PC; + break; + case 4: + m_address = WP + 0x001a; + m_current_value = m_value_copy; // old WP into new R13 + break; + case 5: + m_address = 0x0042 + ((IR >> 4) & 0x003c); // location of new PC + set_status_bit(ST_X, true); + break; + case 6: + PC = m_current_value & m_prgaddr_mask & 0xfffe; + break; + } + pulse_clock(2); + m_state++; +} + +void tms99xx_device::alu_clr_swpb() +{ + UINT32 dest_new = 0; + UINT32 src_val = m_current_value & 0x0000ffff; + UINT16 sign = 0; + + bool setstatus = true; + bool check_ov = true; + + switch (m_command) + { + case CLR: + // no status bits + m_current_value = 0x0000; + setstatus = false; + break; + case SETO: + // no status bits + m_current_value = 0xffff; + setstatus = false; + break; + case INV: + // LAE + dest_new = ~src_val & 0xffff; + check_ov = false; + break; + case NEG: + // LAECO + // Overflow occurs for value=0x8000 + dest_new = ((~src_val) & 0x0000ffff) + 1; + check_ov = false; + set_status_bit(ST_OV, src_val == 0x8000); + break; + case INC: + // LAECO + // Overflow for result value = 0x8000 + // Carry for result value = 0x0000 + dest_new = src_val + 1; + break; + case INCT: + // LAECO + // Overflow for result value = 0x8000 / 0x8001 + // Carry for result value = 0x0000 / 0x0001 + dest_new = src_val + 2; + break; + case DEC: + // LAECO + // Carry for result value != 0xffff + // Overflow for result value == 0x7fff + dest_new = src_val + 0xffff; + sign = 0x8000; + break; + case DECT: + // Carry for result value != 0xffff / 0xfffe + // Overflow for result value = 0x7fff / 0x7ffe + dest_new = src_val + 0xfffe; + sign = 0x8000; + break; + case SWPB: + m_current_value = ((m_current_value << 8) | (m_current_value >> 8)) & 0xffff; + setstatus = false; + break; + } + + if (setstatus) + { + if (check_ov) set_status_bit(ST_OV, ((src_val & 0x8000)==sign) && ((dest_new & 0x8000)!=sign)); + set_status_bit(ST_C, (dest_new & 0x10000) != 0); + m_current_value = dest_new & 0xffff; + compare_and_set_lae(m_current_value, 0); + } + + pulse_clock(2); + // No states here +} + +void tms99xx_device::alu_abs() +{ + // LAECO (from original word!) + // O if >8000 + // C is alwas reset + set_status_bit(ST_OV, m_current_value == 0x8000); + set_status_bit(ST_C, false); + compare_and_set_lae(m_current_value, 0); + + if ((m_current_value & 0x8000)!=0) + { + m_current_value = (((~m_current_value) & 0x0000ffff) + 1) & 0xffff; + pulse_clock(2); // If ABS is performed it takes one machine cycle more + } + else + { + MPC++; // skips over the next micro operation (MEMORY_WRITE) + } + pulse_clock(2); +} + +void tms99xx_device::alu_x() +{ + if (TRACE_ALU) logerror("tms99xx: Substituting current command by %04x\n", m_current_value); + decode(m_current_value); + pulse_clock(2); +} + +/* + Also used by other microprograms +*/ +void tms99xx_device::alu_b() +{ + // no status bits + // Although we got the contents of the source data, we do not use them + // but directly branch there. That is, we are only interested in the + // address of the source data. + // If we have a B *R5 and R5 contains the value 0xa000, the CPU actually + // retrieves the value at 0xa000, but in fact it will load the PC + // with the address 0xa000 + m_current_value = PC; + PC = m_address & m_prgaddr_mask & 0xfffe; + m_address = WP + 22; + if (TRACE_ALU) logerror("tms99xx: Set new PC = %04x\n", PC); + pulse_clock(2); +} + +void tms99xx_device::alu_blwp() +{ + switch (m_state) + { + case 0: + m_value_copy = WP; + WP = m_current_value & m_prgaddr_mask & 0xfffe; // set new WP (*m_destination) + m_address_saved = (m_address + 2) & m_prgaddr_mask; // Save the location of the WP + m_address = WP + 30; + m_current_value = ST; // get status register + break; + case 1: + m_current_value = PC; // get program counter + m_address = m_address - 2; + break; + case 2: + m_current_value = m_value_copy; // retrieve the old WP + m_address = m_address - 2; + break; + case 3: + m_address = m_address_saved; // point to PC component of branch vector + break; + case 4: + PC = m_current_value & m_prgaddr_mask & 0xfffe; + if (TRACE_ALU) logerror("tms9900: Context switch complete; WP=%04x, PC=%04x, ST=%04x\n", WP, PC, ST); + break; + } + pulse_clock(2); + m_state++; +} + +void tms99xx_device::alu_ldcr() +{ + UINT16 value; + + // Spec: "If the source operand address is odd, the address is truncated + // to an even address prior to data transfer." + // (Editor/Assembler, page 151) + // This refers to transfers with more than 8 bits. In this case, for + // LDCR the first bit is taken from the least significant bit of the + // source word. If the address is odd (e.g. 0x1001), it is + // treated as 0x1000, that is, truncated to an even address. + // For transfers with 1-8 bits, the first bit is the least significant + // bit of the source byte (any address). + + if (m_state == 0) + { + m_address = WP + 24; + } + else + { + value = m_source_value; // copied by ALU_SOURCE + m_count = (IR >> 6) & 0x000f; + if (m_count == 0) m_count = 16; + if (m_count <= 8) + { + if (m_source_even) value>>=8; + set_status_parity((UINT8)(value & 0xff)); + compare_and_set_lae(value<<8, 0); + } + else + { + compare_and_set_lae(value, 0); + } + m_cru_address = m_current_value; + m_value = value; + if (TRACE_CRU) logerror("tms99xx: Load CRU address %04x (%d bits), value = %04x\n", m_cru_address, m_count, m_value); + } + m_state++; + pulse_clock(2); +} + +void tms99xx_device::alu_stcr() +{ + UINT16 value; + int n = 2; + // For STCR transfers with more than 8 bits, the first CRU bit is + // always put into the least significant bit of the destination word. + // If the address is odd (e.g. 0x1001), it is treated as 0x1000, that is, + // truncated to an even boundary. + // For transfers with 1-8 bits, the destination address is handled as + // in MOVB operations, i.e. the other byte of the word is kept unchanged. + + switch (m_state) + { + case 0: // After getting the destination operand and saving the address/value + m_address = WP + 24; + n = 0; + break; + case 1: // After getting R12 + m_cru_address = m_current_value; + m_count = (IR >> 6) & 0x000f; + if (m_count == 0) m_count = 16; + break; + case 2: // After the cru operation; value starts at LSB of m_value + value = m_value & 0xffff; + if (m_count < 9) + { + if (TRACE_CRU) logerror("tms99xx: Store CRU at %04x (%d bits) in %04x, result = %02x\n", m_cru_address, m_count, m_source_address, value); + set_status_parity((UINT8)(value & 0xff)); + compare_and_set_lae(value<<8, 0); + if (m_source_even) + m_current_value = (m_source_value & 0x00ff) | (value<<8); + else + m_current_value = (m_source_value & 0xff00) | (value & 0xff); + + pulse_clock(2*(5 + (8-m_count))); + } + else + { + if (TRACE_CRU) logerror("tms99xx: Store CRU at %04x (%d bits) in %04x, result = %04x\n", m_cru_address, m_count, m_source_address, value); + m_current_value = value; + compare_and_set_lae(value, 0); + pulse_clock(2*(5 + (16-m_count))); + } + m_address = m_source_address; + break; + } + + m_state++; + pulse_clock(n); +} + +void tms99xx_device::alu_sbz_sbo() +{ + INT8 displacement; + if (m_state==0) + { + m_address = WP + 24; + } + else + { + m_value = (m_command==SBO)? 1 : 0; + displacement = (INT8)(IR & 0xff); + m_cru_address = m_current_value + (displacement<<1); + m_count = 1; + } + m_state++; + pulse_clock(2); +} + +void tms99xx_device::alu_tb() +{ + INT8 displacement; + switch (m_state) + { + case 0: + m_address = WP + 24; + break; + case 1: + displacement = (INT8)(IR & 0xff); + m_cru_address = m_current_value + (displacement<<1); + m_count = 1; + break; + case 2: + set_status_bit(ST_EQ, m_value!=0); + if (TRACE_STATUS) logerror("tms99xx: ST = %04x\n", ST); + break; + } + m_state++; + pulse_clock(2); +} + +void tms99xx_device::alu_jmp() +{ + INT8 displacement; + bool cond = false; + + if (m_state==0) + { + switch (m_command) + { + case JMP: + cond = true; + break; + case JLT: // LAECOP == x00xxx + cond = ((ST & (ST_AGT | ST_EQ))==0); + break; + case JLE: // LAECOP == 0xxxxx + cond = ((ST & ST_LH)==0); + break; + case JEQ: // LAECOP == xx1xxx + cond = ((ST & ST_EQ)!=0); + break; + case JHE: // LAECOP == 1x0xxx, 0x1xxx + cond = ((ST & (ST_LH | ST_EQ)) != 0); + break; + case JGT: // LAECOP == x1xxxx + cond = ((ST & ST_AGT)!=0); + break; + case JNE: // LAECOP == xx0xxx + cond = ((ST & ST_EQ)==0); + break; + case JNC: // LAECOP == xxx0xx + cond = ((ST & ST_C)==0); + break; + case JOC: // LAECOP == xxx1xx + cond = ((ST & ST_C)!=0); + break; + case JNO: // LAECOP == xxxx0x + cond = ((ST & ST_OV)==0); + break; + case JL: // LAECOP == 0x0xxx + cond = ((ST & (ST_LH | ST_EQ)) == 0); + break; + case JH: // LAECOP == 1xxxxx + cond = ((ST & ST_LH)!=0); + break; + case JOP: // LAECOP == xxxxx1 + cond = ((ST & ST_OP)!=0); + break; + } + if (!cond) + { + if (TRACE_ALU) logerror("tms99xx: Jump condition false\n"); + MPC+=1; // skip next ALU call + } + else + if (TRACE_ALU) logerror("tms99xx: Jump condition true\n"); + } + else + { + displacement = (IR & 0xff); + PC = (PC + (displacement<<1)) & m_prgaddr_mask & 0xfffe; + } + m_state++; + pulse_clock(2); +} + +void tms99xx_device::alu_shift() +{ + bool carry = false; + bool overflow = false; + UINT16 sign = 0; + UINT32 value; + int count; + + switch (m_state) + { + case 0: + m_address = WP + ((IR & 0x000f)<<1); + pulse_clock(2); + break; + case 1: + // we have the value of the register in m_current_value + // Save it (we may have to read R0) + m_value_copy = m_current_value; + m_address_saved = m_address; + m_address = WP; + m_current_value = (IR >> 4) & 0x000f; + + if (m_current_value != 0) + { + // skip the next read and ALU operation + MPC = MPC+2; + m_state++; + } + else + { + if (TRACE_ALU) logerror("tms99xx: Shift operation gets count from R0\n"); + pulse_clock(2); + } + pulse_clock(2); + break; + case 2: + // after READ + pulse_clock(2); + pulse_clock(2); + break; + case 3: + count = m_current_value & 0x000f; // from the instruction or from R0 + if (count==0) count = 16; + + value = m_value_copy; + + // we are re-implementing the shift operations because we have to pulse + // the clock at each single shift anyway. + // Also, it is easier to implement the status bit setting. + // Note that count is never 0 + if (m_command == SRA) sign = value & 0x8000; + + for (int i=0; i < count; i++) + { + switch (m_command) + { + case SRL: + case SRA: + carry = ((value & 1)!=0); + value = (value >> 1) | sign; + break; + case SLA: + carry = ((value & 0x8000)!=0); + value <<= 1; + if (carry != ((value&0x8000)!=0)) overflow = true; + break; + case SRC: + carry = ((value & 1)!=0); + value = (value>>1) | (carry? 0x8000 : 0x0000); + break; + } + pulse_clock(2); + } + + m_current_value = value & 0xffff; + set_status_bit(ST_C, carry); + set_status_bit(ST_OV, overflow); + compare_and_set_lae(m_current_value, 0); + m_address = m_address_saved; // Register address + if (TRACE_STATUS) logerror("tms99xx: ST = %04x (val=%04x)\n", ST, m_current_value); + break; + } + m_state++; +} + +void tms99xx_device::alu_ai_ori() +{ + UINT32 dest_new = 0; + switch (m_command) + { + case AI: + dest_new = m_current_value + m_value_copy; + // See status bit handling for Add + set_status_bit(ST_C, (dest_new & 0x10000) != 0); + set_status_bit(ST_OV, ((dest_new ^ m_current_value) & (dest_new ^ m_value_copy) & 0x8000)!=0); + break; + case ANDI: + dest_new = m_current_value & m_value_copy; + break; + case ORI: + dest_new = m_current_value | m_value_copy; + break; + } + m_current_value = dest_new & 0xffff; + m_address = m_address_copy; + compare_and_set_lae(m_current_value, 0); + pulse_clock(2); +} + +void tms99xx_device::alu_ci() +{ + compare_and_set_lae(m_value_copy, m_current_value); + pulse_clock(2); +} + +void tms99xx_device::alu_li() +{ + compare_and_set_lae(m_current_value, 0); + pulse_clock(2); +} + +void tms99xx_device::alu_lwpi() +{ + WP = m_current_value & m_prgaddr_mask & 0xfffe; + pulse_clock(2); +} + +void tms99xx_device::alu_limi() +{ + ST = (ST & 0xfff0) | (m_current_value & 0x000f); + if (TRACE_STATUS) logerror("tms99xx: ST = %04x\n", ST); + pulse_clock(2); +} + +void tms99xx_device::alu_stwp_stst() +{ + if (m_command==STST) m_current_value = ST; + else m_current_value = WP; + pulse_clock(2); +} + +void tms99xx_device::alu_external() +{ + // Call some possibly attached external device + // We pass the bit pattern of the address bus to the external function + + // IDLE = 0000 0011 0100 0000 + // RSET = 0000 0011 0110 0000 + // CKON = 0000 0011 1010 0000 + // CKOF = 0000 0011 1100 0000 + // LREX = 0000 0011 1110 0000 + // --- + if (m_command == IDLE) + m_idle_state = true; + + if (!m_external_operation.isnull()) m_external_operation((IR >> 5) & 0x07, 1, 0xff); + pulse_clock(2); +} + +void tms99xx_device::alu_rtwp() +{ + switch (m_state) + { + case 0: + m_address = WP + 30; // R15 + pulse_clock(2); + break; + case 1: + ST = m_current_value; + m_address -= 2; // R14 + break; + case 2: + PC = m_current_value & m_prgaddr_mask & 0xfffe; + m_address -= 2; // R13 + break; + case 3: + WP = m_current_value & m_prgaddr_mask & 0xfffe; + pulse_clock(2); + break; + } + m_state++; +} + + +void tms99xx_device::alu_int() +{ + if (TRACE_EMU) logerror("tms99xx: INT state %d; irq_level %d\n", m_state, m_irq_level); + switch (m_state) + { + case 0: + if (m_irq_level == RESET_INT) + { + m_address = 0; + pulse_clock(2); + } + else + { + if (m_irq_level == LOAD_INT) m_address = 0xfffc; // will be truncated for TMS9980 + else + { + m_address = (m_irq_level << 2); + } + } + break; + case 1: + m_address_copy = m_address; + m_value_copy = WP; // old WP + WP = m_current_value & m_prgaddr_mask & 0xfffe; // new WP + m_current_value = ST; + m_address = (WP + 30) & m_prgaddr_mask; + break; + case 2: + m_current_value = PC; + m_address = (WP + 28) & m_prgaddr_mask; + break; + case 3: + m_current_value = m_value_copy; // old WP + m_address = (WP + 26) & m_prgaddr_mask; + break; + case 4: + m_address = (m_address_copy + 2) & 0xfffe & m_prgaddr_mask; + if (TRACE_ALU) logerror("tms99xx: read from %04x\n", m_address); + break; + case 5: + PC = m_current_value & m_prgaddr_mask & 0xfffe; + if (m_irq_level > 0 ) + { + ST = (ST & 0xfff0) | (m_irq_level - 1); + } + break; + } + m_state++; + pulse_clock(2); +} + +/**************************************************************************/ +UINT32 tms99xx_device::execute_min_cycles() const +{ + return 2; +} + +// TODO: Compute this value, just a wild guess for the average +UINT32 tms99xx_device::execute_max_cycles() const +{ + return 10; +} + +UINT32 tms99xx_device::execute_input_lines() const +{ + return 2; +} + +// clocks to cycles, cycles to clocks = id +// execute_default_irq_vector = 0 +// execute_burn = nop + +// device_disasm_interface overrides +UINT32 tms99xx_device::disasm_min_opcode_bytes() const +{ + return 2; +} + +UINT32 tms99xx_device::disasm_max_opcode_bytes() const +{ + return 6; +} + +offs_t tms99xx_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( tms9900 ); + return CPU_DISASSEMBLE_NAME(tms9900)(this, buffer, pc, oprom, opram, options); +} + + +const device_type TMS9900 = &device_creator; diff --git a/src/devices/cpu/tms9900/tms9900.h b/src/devices/cpu/tms9900/tms9900.h new file mode 100644 index 00000000000..8e7f19042c6 --- /dev/null +++ b/src/devices/cpu/tms9900/tms9900.h @@ -0,0 +1,403 @@ +// license:BSD-3-Clause +// copyright-holders:Michael Zapf +/* + TMS9900 processor + This is a re-implementation of the TMS9900 featuring a cycle-precise + behaviour. + + See tms9900.c for documentation +*/ + +#ifndef __TMS9900_H__ +#define __TMS9900_H__ + +#include "emu.h" +#include "debugger.h" +#include "tms99com.h" + +enum +{ + INT_9900_RESET = 0, + INT_9900_LOAD = 1, + INT_9900_INTREQ = 2 +}; + +enum +{ + LOAD_INT = -1, + RESET_INT = -2 +}; + +static const char opname[][5] = +{ "ILL ", "A ", "AB ", "ABS ", "AI ", "ANDI", "B ", "BL ", "BLWP", "C ", + "CB ", "CI ", "CKOF", "CKON", "CLR ", "COC ", "CZC ", "DEC ", "DECT", "DIV ", + "IDLE", "INC ", "INCT", "INV ", "JEQ ", "JGT ", "JH ", "JHE ", "JL ", "JLE ", + "JLT ", "JMP ", "JNC ", "JNE ", "JNO ", "JOC ", "JOP ", "LDCR", "LI ", "LIMI", + "LREX", "LWPI", "MOV ", "MOVB", "MPY ", "NEG ", "ORI ", "RSET", "RTWP", "S ", + "SB ", "SBO ", "SBZ ", "SETO", "SLA ", "SOC ", "SOCB", "SRA ", "SRC ", "SRL ", + "STCR", "STST", "STWP", "SWPB", "SZC ", "SZCB", "TB ", "X ", "XOP ", "XOR ", + "*int" +}; + +class tms99xx_device : public cpu_device +{ +public: + tms99xx_device(const machine_config &mconfig, device_type type, const char *name, + const char *tag, int databus_width, int prg_addr_bits, int cru_addr_bits, + device_t *owner, UINT32 clock, const char *shortname, const char *source); + + ~tms99xx_device(); + + // READY input line. When asserted (high), the memory is ready for data exchange. + void set_ready(int state); + + // HOLD input line. When asserted (low), the CPU is requested to release the + // data and address bus and enter the HOLD state. The entrance of this state + // is acknowledged by the HOLDA output line. + void set_hold(int state); + + // Callbacks + template static devcb_base &static_set_extop_callback(device_t &device, _Object object) { return downcast(device).m_external_operation.set_callback(object); } + template static devcb_base &static_set_intlevel_callback(device_t &device, _Object object) { return downcast(device).m_get_intlevel.set_callback(object); } + template static devcb_base &static_set_iaq_callback(device_t &device, _Object object) { return downcast(device).m_iaq_line.set_callback(object); } + template static devcb_base &static_set_clkout_callback(device_t &device, _Object object) { return downcast(device).m_clock_out_line.set_callback(object); } + template static devcb_base &static_set_wait_callback(device_t &device, _Object object) { return downcast(device).m_wait_line.set_callback(object); } + template static devcb_base &static_set_holda_callback(device_t &device, _Object object) { return downcast(device).m_holda_line.set_callback(object); } + template static devcb_base &static_set_dbin_callback(device_t &device, _Object object) { return downcast(device).m_dbin_line.set_callback(object); } + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_stop(); + virtual void device_reset(); + + virtual void resolve_lines(); + + // device_execute_interface overrides + virtual UINT32 execute_min_cycles() const; + virtual UINT32 execute_max_cycles() const; + virtual UINT32 execute_input_lines() const; + virtual void execute_set_input(int irqline, int state); + virtual void execute_run(); + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const; + virtual UINT32 disasm_max_opcode_bytes() const; + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + + const address_space_config* memory_space_config(address_spacenum spacenum) const; + + // Let these methods be overloaded by the TMS9980. + virtual void mem_read(void); + virtual void mem_write(void); + virtual void acquire_instruction(void); + void decode(UINT16 inst); + + const address_space_config m_program_config; + const address_space_config m_io_config; + address_space* m_prgspace; + address_space* m_cru; + + virtual UINT16 read_workspace_register_debug(int reg); + virtual void write_workspace_register_debug(int reg, UINT16 data); + + // Cycle counter + int m_icount; + + // TMS9900 hardware registers + UINT16 WP; // Workspace pointer + UINT16 PC; // Program counter + UINT16 ST; // Status register + + // Internal register + UINT16 IR; // Instruction register + + // Stored address + UINT16 m_address; + + // Stores the recently read word or the word to be written + UINT16 m_current_value; + + // Decoded command + UINT16 m_command; + + // Is it a byte operation? Only format 1 commands with the byte flag set + // and CRU commands with less than 9 bits to transfer are byte operations. + bool m_byteop; + + // Issue clock pulses. Note that each machine cycle has two clock cycles. + void pulse_clock(int count); + + // For multi-pass operations. For instance, memory word accesses are + // executed as two consecutive byte accesses. CRU accesses are repeated + // single-bit accesses. (Needed for TMS9980) + int m_pass; + + // Data bus width. Needed for TMS9980. + int m_databus_width; + + // Check the READY line? + bool m_check_ready; + + // Phase of the memory access + int m_mem_phase; + + // Max address + const UINT16 m_prgaddr_mask; + const UINT16 m_cruaddr_mask; + + bool m_load_state; + bool m_irq_state; + bool m_reset; + + // Determine the interrupt level using the IC0-IC3 lines + int get_intlevel(int state); + + // Interrupt level as acquired from input lines (TMS9900: IC0-IC3, TMS9980: IC0-IC2) + // We assume all values right-justified, i.e. TMS9980 also counts up by one + int m_irq_level; + + // Used to display the number of consumed cycles in the log. + int m_first_cycle; + + /************************************************************************/ + + // Clock output. This is not a pin of the TMS9900 because the TMS9900 + // needs an external clock, and usually one of those external lines is + // used for this purpose. + devcb_write_line m_clock_out_line; + + // Wait output. When asserted (high), the CPU is in a wait state. + devcb_write_line m_wait_line; + + // HOLD Acknowledge line. When asserted (high), the CPU is in HOLD state. + devcb_write_line m_holda_line; + + // Signal to the outside world that we are now getting an instruction + devcb_write_line m_iaq_line; + + // Get the value of the interrupt level lines + devcb_read8 m_get_intlevel; + + // DBIN line. When asserted (high), the CPU has disabled the data bus output buffers. + devcb_write_line m_dbin_line; + + // Trigger external operation. This is achieved by putting a special value in + // the most significant three bits of the address bus (TMS9995: data bus) and + // pulsing the CRUCLK line. + // Accordingly, we have + // + // A0 A1 A2 A3 A4 A5 ... A12 A13 A14 A15 + // 0 0 0 x x x x x x - normal CRU access + // 0 1 0 x x x x x x - IDLE + // 0 1 1 x x x x x x - RSET + // 1 0 1 x x x x x x - CKON + // 1 1 0 x x x x x x - CKOF + // 1 1 1 x x x x x x - LREX + // + // so the TMS9900 can only use CRU addresses 0 - 1ffe for CRU operations. + // By moving these three bits to the data bus, the TMS9995 can allow for the + // full range 0000-fffe for its CRU operations. + // + // We could realize this via the CRU access as well, but the data bus access + // is not that simple to emulate. For the sake of homogenity between the + // chip emulations we use a dedicated callback. + devcb_write8 m_external_operation; + + +private: + // Indicates if this is a byte-oriented command + inline bool byte_operation(); + + // Processor states + bool m_idle_state; + + // READY handling. The READY line is operated before the phi1 clock + // pulse rises. As the ready line is only set once in this emulation we + // keep the level in a buffer (like a latch) + bool m_ready_bufd; // buffered state + bool m_ready; // sampled value + + bool m_wait_state; + bool m_hold_state; + + // State / debug management + UINT16 m_state_any; + static const char* s_statename[]; + void state_import(const device_state_entry &entry); + void state_export(const device_state_entry &entry); + void state_string_export(const device_state_entry &entry, std::string &str); + + // Interrupt handling + void service_interrupt(); + + // ================ Microprogram support ======================== + + // Set up lookup table + void build_command_lookup_table(); + + // Sequence of micro-operations + typedef const UINT8* microprogram; + + // Method pointer + typedef void (tms99xx_device::*ophandler)(void); + + // Opcode list entry + struct tms_instruction + { + UINT16 opcode; + int id; + int format; + microprogram prog; // Microprogram + }; + + // Lookup table entry + struct lookup_entry + { + lookup_entry *next_digit; + const tms_instruction *entry; + }; + + // Pointer to the lookup table + lookup_entry* m_command_lookup_table; + + // List of allocated tables (used for easy clean-up on exit) + lookup_entry* m_lotables[32]; + + // List of pointers for micro-operations + static const tms99xx_device::ophandler s_microoperation[]; + + // Opcode table + static const tms99xx_device::tms_instruction s_command[]; + + // Micro-operation declarations + void register_read(void); + void register_write(void); + void cru_input_operation(void); + void cru_output_operation(void); + void data_derivation_subprogram(void); + void return_from_subprogram(void); + void command_completed(void); + + void alu_nop(void); + void alu_clear(void); + void alu_source(void); + void alu_setaddr(void); + void alu_addone(void); + void alu_setaddr_addone(void); + void alu_pcaddr_advance(void); + void alu_add_register(void); + + void alu_imm(void); + void alu_reg(void); + + void alu_f1(void); + void alu_comp(void); + void alu_f3(void); + void alu_multiply(void); + void alu_divide(void); + void alu_xop(void); + void alu_clr_swpb(void); + void alu_abs(void); + void alu_x(void); + void alu_b(void); + void alu_bl(void); + void alu_blwp(void); + void alu_ldcr(void); + void alu_stcr(void); + void alu_sbz_sbo(void); + void alu_tb(void); + void alu_jmp(void); + void alu_shift(void); + void alu_ai_ori(void); + void alu_ci(void); + void alu_li(void); + void alu_lwpi(void); + void alu_limi(void); + void alu_stwp_stst(void); + void alu_external(void); + void alu_rtwp(void); + void alu_int(void); + + void abort_operation(void); + + // Micro-operation + UINT8 m_op; + + // Micro-operation program counter (as opposed to the program counter PC) + int MPC; + + // Current microprogram + const UINT8* m_program; + + // Calling microprogram (used when data derivation is called) + const UINT8* m_caller; + int m_caller_MPC; + + // State of the micro-operation. Needed for repeated ALU calls. + int m_state; + + // Has HOLD been acknowledged yet? + bool m_hold_acknowledged; + + // Signal the wait state via the external line + inline void set_wait_state(bool state); + + // Used to acknowledge HOLD and enter the HOLD state + inline void acknowledge_hold(); + + // Was the source operand a byte from an even address? + bool m_source_even; + + // Was the destination operand a byte from an even address? + bool m_destination_even; + + // Intermediate storage for the source operand + UINT16 m_source_address; + UINT16 m_source_value; + UINT16 m_address_saved; + + // Another copy of the address + UINT16 m_address_copy; + + // Stores the recently read register contents + UINT16 m_register_contents; + + // Stores the register number for the next register access + int m_regnumber; + + // CRU support: Stores the CRU address + UINT16 m_cru_address; + + // CRU support: Stores the number of bits to be transferred + int m_count; + + // Copy of the value + UINT16 m_value_copy; + + // Another internal register, storing intermediate values + // Using 32 bits to support MPY + UINT32 m_value; + + // For two-argument commands. Indicates whether this is the second operand. + bool m_get_destination; + + // Status register update + inline void set_status_bit(int bit, bool state); + inline void compare_and_set_lae(UINT16 value1, UINT16 value2); + void set_status_parity(UINT8 value); +}; + +/*****************************************************************************/ + +class tms9900_device : public tms99xx_device +{ +public: + tms9900_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +// device type definition +extern const device_type TMS9900; + +#endif /* __TMS9900_H__ */ diff --git a/src/devices/cpu/tms9900/tms9980a.c b/src/devices/cpu/tms9900/tms9980a.c new file mode 100644 index 00000000000..054a293a403 --- /dev/null +++ b/src/devices/cpu/tms9900/tms9980a.c @@ -0,0 +1,300 @@ +// license:BSD-3-Clause +// copyright-holders:Michael Zapf +/* + Cycle-precise implementation of the TMS9980A. + Subclassed from tms99xx_device in tms9900.c. + + +----------------+ + /HOLD | 1 \/ 40| /MEMEN + HOLDA | 2 39| READY + IAQ | 3 38| /WE + LSB +- A13,CRUOUT | 4 37| CRUCLK + | A12 | 5 36| Vdd + | A11 | 6 35| Vss + | A10 | 7 34| CKIN + Address A9 | 8 33| D7 --+ + bus A8 | 9 32| D6 | + | A7 |10 31| D5 Data + 16KiB A6 |11 30| D4 bus + | A5 |12 29| D3 | + | A4 |13 28| D2 2 * 8 bit + | A3 |14 27| D1 | + | A2 |15 26| D0 --+ + | A1 |16 25| INT0 --+ + MSB +-- A0 |17 24| INT1 | Interrupt levels + DBIN |18 23| INT2 --+ + CRUIN |19 22| /PHI3 + Vcc |20 21| Vbb + +----------------+ + + The TMS9980A is similar to the TMS9900, with the following differences: + + - Address bus is only 14 bit wide (16 KiB) + - Data bus is 16 bit wide and multiplexed on 8 lines (2 bytes per access) + - CRU space is limited to 2048 bits (due to fewer address lines) + - Only three interrupt level lines, for a maximum of 8 levels. + - No INTREQ, RESET, and LOAD lines. All interrupts are signaled via INT0 - + INT2. Reset=00x, Load=010, Level1=011, Level2=100, Level3=101, Level4=110, + all interrupts cleared=111. + - Memory accesses are always 2 bytes (even address byte, odd address byte) + even for byte operations. Thus the 9980A, like the TMS9900, needs to + pre-fetch the word at the destination before overwriting it. + - On the cycle level both TMS9900 and TMS9980A are equal, except for the + additional cycles needed for memory read and write access. Accordingly, + the emulation shares the core and the microprograms and redefines the + memory access and the interrupt handling only. + - The 9980A has the same external instructions as the TMS9900, but it + indicates the command via A0, A1, and A13 (instead of A0-A2). + + For pin definitions see tms9900.c + + Michael Zapf, 2012 +*/ + +#include "tms9980a.h" + +/* + The following defines can be set to 0 or 1 to disable or enable certain + output in the log. +*/ + +// Memory operation +#define TRACE_MEM 0 + +// Address bus operation +#define TRACE_ADDRESSBUS 0 + +// Log operation +#define TRACE_OP 0 + +// Interrupts +#define TRACE_INT 0 + +/**************************************************************************** + Constructor +****************************************************************************/ + +tms9980a_device::tms9980a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : tms99xx_device(mconfig, TMS9980A, "TMS9980A", tag, 8, 14, 11, owner, clock, "tms9980a", __FILE__) +{ +} + +/* + External connections +*/ +void tms9980a_device::resolve_lines() +{ + // Resolve our external connections + m_external_operation.resolve(); + m_iaq_line.resolve(); + m_clock_out_line.resolve(); + m_holda_line.resolve(); + m_dbin_line.resolve(); +} + +UINT16 tms9980a_device::read_workspace_register_debug(int reg) +{ + int temp = m_icount; + int addr = (WP+(reg<<1)) & 0xfffe & m_prgaddr_mask; + UINT16 value = (m_prgspace->read_byte(addr) << 8) | (m_prgspace->read_byte(addr+1) & 0xff); + m_icount = temp; + return value; +} + +void tms9980a_device::write_workspace_register_debug(int reg, UINT16 data) +{ + int temp = m_icount; + int addr = (WP+(reg<<1)) & 0xfffe & m_prgaddr_mask; + m_prgspace->write_byte(addr, data>>8); + m_prgspace->write_byte(addr+1, data & 0xff); + m_icount = temp; +} + +/* + Interrupt input. Keep in mind that the TMS9980A does not have any INTREQ + line but signals interrupts via IC0-IC2 only. Thus we cannot take down any + single interrupt; only all interrupts can be cleared at once using level 7. + The state parameter is actually not needed. +*/ +void tms9980a_device::execute_set_input(int irqline, int state) +{ + // We model the three lines IC0-IC2 as 8 separate input lines, although we + // cannot assert more than one at a time. The state value is not needed, + // as level 7 means to clean all interrupts, but we consider it for the + // sake of consistency. + + int level = irqline; + + // Just to stay consistent. + if (state==CLEAR_LINE) level = INT_9980A_CLEAR; + + switch (level) + { + case INT_9980A_RESET: + case 1: + level = RESET_INT; + m_reset = true; + break; + case INT_9980A_LOAD: + level = LOAD_INT; + break; + case INT_9980A_LEVEL1: + case INT_9980A_LEVEL2: + case INT_9980A_LEVEL3: + case INT_9980A_LEVEL4: + level = level - 2; + break; + case INT_9980A_CLEAR: + // Clear all interrupts + m_load_state = false; + m_irq_state = false; + if (TRACE_INT) logerror("tms9980a: clear interrupts\n"); + break; + } + + m_irq_level = level; + + if (m_irq_level != INT_9980A_CLEAR) + { + if (m_irq_level == LOAD_INT) + { + // Some boards start up with LOAD interrupt, so we clear the reset flag + m_reset = false; + m_load_state = true; + } + else m_irq_state = true; + if (TRACE_INT) logerror("tms9980a: interrupt level=%d, ST=%04x\n", m_irq_level, ST); + } +} + +/*****************************************************************************/ + +/* + Memory read: + Clock cycles: 4 + 2W, W = number of wait states +*/ +void tms9980a_device::mem_read() +{ + UINT8 value; + switch (m_mem_phase) + { + case 1: + m_pass = 4; // make the CPU visit this method more than once + if (!m_dbin_line.isnull()) m_dbin_line(ASSERT_LINE); + m_prgspace->set_address(m_address & m_prgaddr_mask & ~1); + if (TRACE_ADDRESSBUS) logerror("tms9980a: set address bus %04x\n", m_address & m_prgaddr_mask & ~1); + m_check_ready = true; + break; + case 2: + // Sample the value on the data bus (high byte) + value = m_prgspace->read_byte(m_address & m_prgaddr_mask & ~1); + if (TRACE_MEM) logerror("tms9980a: memory read high byte %04x -> %02x\n", m_address & m_prgaddr_mask & ~1, value); + m_current_value = (value << 8) & 0xff00; + break; + case 3: + m_prgspace->set_address((m_address & m_prgaddr_mask) | 1); + if (TRACE_ADDRESSBUS) logerror("tms9980a: set address bus %04x\n", (m_address & m_prgaddr_mask) | 1); + break; + case 4: + // Sample the value on the data bus (low byte) + value = m_prgspace->read_byte((m_address & m_prgaddr_mask) | 1); + m_current_value = m_current_value | (value & 0x00ff); + if (TRACE_MEM) logerror("tms9980a: memory read low byte %04x -> %02x -> complete word %04x\n", (m_address & m_prgaddr_mask) | 1, value, m_current_value); + break; + } + pulse_clock(1); + m_mem_phase = (m_mem_phase % 4) +1; +} + + +void tms9980a_device::mem_write() +{ + switch (m_mem_phase) + { + case 1: + m_pass = 4; // make the CPU visit this method once more + if (!m_dbin_line.isnull()) m_dbin_line(CLEAR_LINE); + m_prgspace->set_address(m_address & m_prgaddr_mask & ~1); + if (TRACE_ADDRESSBUS) logerror("tms9980a: set address bus %04x\n", m_address & m_prgaddr_mask & ~1); + m_prgspace->write_byte(m_address & 0x3ffe & ~1, (m_current_value >> 8)&0xff); + if (TRACE_MEM) logerror("tms9980a: memory write high byte %04x <- %02x\n", m_address & m_prgaddr_mask & ~1, (m_current_value >> 8)&0xff); + m_check_ready = true; + break; + case 2: + // no action here, just wait for READY + break; + case 3: + m_prgspace->set_address((m_address & m_prgaddr_mask) | 1); + if (TRACE_ADDRESSBUS) logerror("tms9980a: set address bus %04x\n", (m_address & m_prgaddr_mask) | 1); + m_prgspace->write_byte((m_address & m_prgaddr_mask) | 1, m_current_value & 0xff); + if (TRACE_MEM) logerror("tms9980a: memory write low byte %04x <- %02x\n", (m_address & m_prgaddr_mask) | 1, m_current_value & 0xff); + break; + case 4: + // no action here, just wait for READY + break; + } + pulse_clock(1); + m_mem_phase = (m_mem_phase % 4) +1; +} + +void tms9980a_device::acquire_instruction() +{ + if (m_mem_phase == 1) + { + if (!m_iaq_line.isnull()) m_iaq_line(ASSERT_LINE); + m_address = PC; + m_first_cycle = m_icount; + } + mem_read(); + + if (m_mem_phase == 1) // changed by mem_read and wrapped + { + decode(m_current_value); + if (TRACE_OP) logerror("tms9980a: ===== Next operation %04x (%s) at %04x =====\n", IR, opname[m_command], PC); + debugger_instruction_hook(this, PC); + PC = (PC + 2) & 0xfffe & m_prgaddr_mask; + } + // IAQ will be cleared in the main loop +} + + + +/**************************************************************************/ +UINT32 tms9980a_device::execute_min_cycles() const +{ + return 2; +} + +// TODO: Compute this value, just a wild guess for the average +UINT32 tms9980a_device::execute_max_cycles() const +{ + return 10; +} + +UINT32 tms9980a_device::execute_input_lines() const +{ + return 8; +} + +// clocks to cycles, cycles to clocks = id +// execute_default_irq_vector = 0 +// execute_burn = nop + +// device_disasm_interface overrides +UINT32 tms9980a_device::disasm_min_opcode_bytes() const +{ + return 2; +} + +UINT32 tms9980a_device::disasm_max_opcode_bytes() const +{ + return 6; +} + +offs_t tms9980a_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( tms9980 ); + return CPU_DISASSEMBLE_NAME(tms9980)(this, buffer, pc, oprom, opram, options); +} + +const device_type TMS9980A = &device_creator; diff --git a/src/devices/cpu/tms9900/tms9980a.h b/src/devices/cpu/tms9900/tms9980a.h new file mode 100644 index 00000000000..82492d6073a --- /dev/null +++ b/src/devices/cpu/tms9900/tms9980a.h @@ -0,0 +1,56 @@ +// license:BSD-3-Clause +// copyright-holders:Michael Zapf +/* + TMS9980A. + See tms9980a.c and tms9900.c for documentation +*/ + +#ifndef __TMS9980A_H__ +#define __TMS9980A_H__ + +#include "emu.h" +#include "debugger.h" +#include "tms9900.h" + +enum +{ + INT_9980A_RESET = 0, + INT_9980A_LOAD = 2, + INT_9980A_LEVEL1 = 3, + INT_9980A_LEVEL2 = 4, + INT_9980A_LEVEL3 = 5, + INT_9980A_LEVEL4 = 6, + INT_9980A_CLEAR= 7 +}; + +class tms9980a_device : public tms99xx_device +{ +public: + tms9980a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + void mem_read(void); + void mem_write(void); + void acquire_instruction(void); + + void resolve_lines(); + + UINT16 read_workspace_register_debug(int reg); + void write_workspace_register_debug(int reg, UINT16 data); + + UINT32 execute_min_cycles() const; + UINT32 execute_max_cycles() const; + UINT32 execute_input_lines() const; + void execute_set_input(int irqline, int state); + + UINT32 disasm_min_opcode_bytes() const; + UINT32 disasm_max_opcode_bytes() const; + offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + address_space_config m_program_config80; + address_space_config m_io_config80; +}; + +// device type definition +extern const device_type TMS9980A; + +#endif /* __TMS9980A_H__ */ diff --git a/src/devices/cpu/tms9900/tms9995.c b/src/devices/cpu/tms9900/tms9995.c new file mode 100644 index 00000000000..ae9248fd82d --- /dev/null +++ b/src/devices/cpu/tms9900/tms9995.c @@ -0,0 +1,3466 @@ +// license:BSD-3-Clause +// copyright-holders:Michael Zapf +/* + Texas Instruments TMS9995 + + +----------------+ + XTAL1 | 1 \/ 40| A15,CRUOUT + XTAL2,CLKIN | 2 39| A14 + CLKOUT | 3 38| A13 + D7 | 4 37| A12 + D6 | 5 36| A11 + D5 | 6 35| A10 + D4 | 7 34| A9 + D3 | 8 33| A8 + D2 | 9 32| A7 + Vcc |10 31| Vss + D1 |11 30| A6 + D0 |12 29| A5 + CRUIN |13 28| A4 + /INT4,/EC |14 27| A3 + /INT1 |15 26| A2 + IAQ,HOLDA |16 25| A1 + /DBIN |17 24| A0 + /HOLD |18 23| READY + /WE,/CRUCLK |19 22| /RESET + /MEMEN |20 21| /NMI + +----------------+ + + XTAL1 in Crystal input pin for internal oscillator + XTAL2 in Crystal input pin for internal oscillator, or + CLKIN in Input pin for external oscillator + CLKOUT out Clock output signal (1:4 of the input signal frequency) + CRUIN in CRU input data + /INT4 in Interrupt level 4 input + /EC in Event counter + /INT1 in Interrupt level 1 input + IAQ out Instruction acquisition + HOLDA out Hold acknowledge + /WE out Data available for memory write + /CRUCLK out Communication register unit clock output + /MEMEN out Address bus contains memory address + /NMI in Non-maskable interrupt (/LOAD on TMS9900) + /RESET in Reset interrupt + READY in Memory/External CRU device ready for access + CRUOUT out Communication register unit data output + + Vcc +5V supply + Vss 0V Ground reference + + A0-A15 out Address bus + D0-D7 in/out Data bus + + Note that Texas Instruments' bit numberings define bit 0 as the + most significant bit (different to most other systems). Also, the + system uses big-endian memory organisation: Storing the word 0x1234 at + address 0x0000 means that the byte 0x12 is stored at 0x0000 and byte 0x34 + is stored at 0x0001. + + The TMS9995 is a 16 bit microprocessor like the TMS9900, operating on + 16-bit words and using 16-bit opcodes. Memory transfer of 16-bit words + is achieved by a transfer of the most significant byte, followed by + the least significant byte. + + The 8-bit databus width allows the processor to exchange single bytes with + the external memory. + + See tms9900.c for some more details on the cycle-precise implementation. + + This implementation also features all control lines and the instruction + prefetch mechanism. Prefetching is explicitly triggered within the + microprograms. The TMS9995 specification does not reveal the exact + operations during the microprogram execution, so we have to look at the + required cycle numbers to guess what is happening. + + Auto wait state: + + In order to enable automatic wait state creation, the READY line must be + cleared on reset time. A good position to do this is MACHINE_RESET in + the driver. + + + References (see comments below) + ---------- + [1] Texas Instruments 9900 Microprocessor series: TMS9995 16-bit Microcomputer + + TODO: + - State save + - Test HOLD + + Michael Zapf, June 2012 +*/ + +#include "tms9995.h" + +/* tms9995 ST register bits. */ +enum +{ + ST_LH = 0x8000, // Logical higher (unsigned comparison) + ST_AGT = 0x4000, // Arithmetical greater than (signed comparison) + ST_EQ = 0x2000, // Equal + ST_C = 0x1000, // Carry + ST_OV = 0x0800, // Overflow (when using signed operations) + ST_OP = 0x0400, // Odd parity (used with byte operations) + ST_X = 0x0200, // XOP + ST_OE = 0x0020, // Overflow interrupt enabled + ST_IM = 0x000f // Interrupt mask +}; + +enum +{ + PENDING_NMI = 1, + PENDING_MID = 2, + PENDING_LEVEL1 = 4, + PENDING_OVERFLOW = 8, + PENDING_DECR = 16, + PENDING_LEVEL4 = 32 +}; + +/***************************************************************** + Debugging + Set to 0 (disable) or 1 (enable) +******************************************************************/ + +// Log addresses of executed opcodes +#define TRACE_EXEC 0 + +// Log cycles +#define TRACE_CYCLES 0 + +// Log configuration +#define TRACE_CONFIG 1 + +// Log emulation details +#define TRACE_EMU 0 + +// Log wait/hold states +#define TRACE_WAITHOLD 0 + +// Log microinstruction processing +#define TRACE_MICRO 0 + +// Log interrupts +#define TRACE_INT 0 + +// Log interrupts (detailed phases) +#define TRACE_INTD 0 + +// Log clock pulses +#define TRACE_CLOCK 0 + +// Log READY line input +#define TRACE_READY 0 + +// Log memory access +#define TRACE_MEM 0 + +// Log address bus operation +#define TRACE_ADDRESSBUS 0 + +// Log CRU operations +#define TRACE_CRU 0 + +// Log status register +#define TRACE_STATUS 0 + +// Log operation +#define TRACE_OP 0 + +// Log decrementer operation +#define TRACE_DEC 0 + +// Log with max detail +#define TRACE_DETAIL 0 + +/**************************************************************************** + Constructor +****************************************************************************/ + +tms9995_device::tms9995_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : cpu_device(mconfig, TMS9995, "TMS9995", tag, owner, clock, "tms9995", __FILE__), + m_state_any(0), + PC(0), + PC_debug(0), + m_program_config("program", ENDIANNESS_BIG, 8, 16), + m_io_config("cru", ENDIANNESS_BIG, 8, 16), + m_prgspace(NULL), + m_cru(NULL), + m_external_operation(*this), + m_iaq_line(*this), + m_clock_out_line(*this), + m_holda_line(*this), + m_dbin_line(*this) +{ + m_mp9537 = false; + m_check_overflow = false; +} + +/* + Called from subclass. +*/ +tms9995_device::tms9995_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : cpu_device(mconfig, TMS9995, name, tag, owner, clock, shortname, source), + m_state_any(0), + PC(0), + PC_debug(0), + m_program_config("program", ENDIANNESS_BIG, 8, 16), + m_io_config("cru", ENDIANNESS_BIG, 8, 16), + m_prgspace(NULL), + m_cru(NULL), + m_external_operation(*this), + m_iaq_line(*this), + m_clock_out_line(*this), + m_holda_line(*this), + m_dbin_line(*this) +{ + m_check_overflow = false; +} + + +enum +{ + TMS9995_PC=0, TMS9995_WP, TMS9995_STATUS, TMS9995_IR, + TMS9995_R0, TMS9995_R1, TMS9995_R2, TMS9995_R3, + TMS9995_R4, TMS9995_R5, TMS9995_R6, TMS9995_R7, + TMS9995_R8, TMS9995_R9, TMS9995_R10, TMS9995_R11, + TMS9995_R12, TMS9995_R13, TMS9995_R14, TMS9995_R15 +}; + +void tms9995_device::device_start() +{ + // TODO: Restore save state suport + + m_prgspace = &space(AS_PROGRAM); // dimemory.h + m_cru = &space(AS_IO); + + // Resolve our external connections + m_external_operation.resolve(); + m_iaq_line.resolve(); + m_clock_out_line.resolve(); + m_holda_line.resolve(); + m_dbin_line.resolve(); + + // set our instruction counter + m_icountptr = &m_icount; + + // Clear the interrupt flags + m_int_pending = 0; + + m_mid_flag = false; + m_mid_active = false; + m_nmi_active = false; + m_int_overflow = false; + m_int_decrementer = false; + + m_idle_state = false; + + m_source_value = 0; + + // add the states for the debugger + for (int i=0; i < 20; i++) + { + // callimport = need to use the state_import method to write to the state variable + // callexport = need to use the state_export method to read the state variable + state_add(i, s_statename[i], m_state_any).callimport().callexport().formatstr("%04X"); + } + state_add(STATE_GENPC, "curpc", PC_debug).formatstr("%4s").noshow(); + state_add(STATE_GENFLAGS, "status", m_state_any).callimport().callexport().formatstr("%16s").noshow(); + + // Set up the lookup table for command decoding + build_command_lookup_table(); + + if (TRACE_CONFIG) logerror("%s: Variant = %s, Overflow int = %s\n", tag(), m_mp9537? "MP9537 (no on-chip RAM)" : "with on-chip RAM", m_check_overflow? "check" : "no check"); +} + +void tms9995_device::device_stop() +{ + int k = 0; + if (TRACE_CONFIG) logerror("%s: Deleting lookup tables\n", tag()); + while (m_lotables[k]!=NULL) delete[] m_lotables[k++]; +} + +/* + TMS9995 hard reset + The device reset is just the emulator's trigger for the reset procedure + which is invoked via the main loop. + + This also allows us to check the READY line at reset time, which is used + to enable automatic wait state creation. +*/ +void tms9995_device::device_reset() +{ + m_reset = true; // for the main loop + m_servicing_interrupt = false; // only for debugging + m_request_auto_wait_state = false; + memset(m_flag, 0, sizeof(m_flag)); +} + +const char* tms9995_device::s_statename[20] = +{ + "PC ", "WP ", "ST ", "IR ", + "R0 ", "R1 ", "R2 ", "R3 ", + "R4 ", "R5 ", "R6 ", "R7 ", + "R8 ", "R9 ", "R10", "R11", + "R12", "R13", "R14", "R15" +}; + +/* + Write the contents of a register by external input (debugger) + Note: this is untested any may fail because of the prefetch feature of the CPU. + In particular it may be required to adjust the PC. +*/ +void tms9995_device::state_import(const device_state_entry &entry) +{ + int index = entry.index(); + switch (entry.index()) + { + case STATE_GENFLAGS: + // no action here; we do not allow import, as the flags are all + // bits of the STATUS register + break; + case TMS9995_PC: + PC = (UINT16)m_state_any & 0xfffe; + break; + case TMS9995_WP: + WP = (UINT16)m_state_any & 0xfffe; + break; + case TMS9995_STATUS: + ST = (UINT16)m_state_any; + break; + case TMS9995_IR: + m_instruction->IR = (UINT16)m_state_any; + break; + default: + // Workspace registers + if (index <= TMS9995_R15) + write_workspace_register_debug(index-TMS9995_R0, (UINT16)m_state_any); + break; + } +} + +/* + Reads the contents of a register for display in the debugger. +*/ +void tms9995_device::state_export(const device_state_entry &entry) +{ + int index = entry.index(); + switch (entry.index()) + { + case STATE_GENFLAGS: + m_state_any = ST; + break; + case TMS9995_PC: + m_state_any = PC_debug; + break; + case TMS9995_WP: + m_state_any = WP; + break; + case TMS9995_STATUS: + m_state_any = ST; + break; + case TMS9995_IR: + m_state_any = m_instruction->IR; + break; + default: + // Workspace registers + if (index <= TMS9995_R15) + m_state_any = read_workspace_register_debug(index-TMS9995_R0); + break; + } +} + +/* + state_string_export - export state as a string for the debugger +*/ +void tms9995_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + static const char *statestr = "LAECOPX-----IIII"; + char flags[17]; + memset(flags, 0x00, ARRAY_LENGTH(flags)); + UINT16 val = 0x8000; + if (entry.index()==STATE_GENFLAGS) + { + for (int i=0; i < 16; i++) + { + flags[i] = ((val & ST)!=0)? statestr[i] : '.'; + val = (val >> 1) & 0x7fff; + } + } + str.assign(flags); +} + +/* + Provide access to the workspace registers via the debugger. We have to + take care whether this is in onchip RAM or outside. +*/ +UINT16 tms9995_device::read_workspace_register_debug(int reg) +{ + int temp = m_icount; + UINT16 value; + + int addrb = (WP + (reg << 1)) & 0xfffe; + + if (is_onchip(addrb)) + { + value = (m_onchip_memory[addrb & 0x00fe]<<8) | m_onchip_memory[(addrb & 0x00fe) + 1]; + } + else + { + m_prgspace->set_debugger_access(true); + value = (m_prgspace->read_byte(addrb) << 8) & 0xff00; + value |= m_prgspace->read_byte(addrb+1); + m_prgspace->set_debugger_access(false); + } + m_icount = temp; + return value; +} + +void tms9995_device::write_workspace_register_debug(int reg, UINT16 data) +{ + int temp = m_icount; + int addrb = (WP + (reg << 1)) & 0xfffe; + + if (is_onchip(addrb)) + { + m_onchip_memory[addrb & 0x00fe] = (data >> 8) & 0xff; + m_onchip_memory[(addrb & 0x00fe) + 1] = data & 0xff; + } + else + { + m_prgspace->set_debugger_access(true); + m_prgspace->write_byte(addrb, (data >> 8) & 0xff); + m_prgspace->write_byte(addrb+1, data & 0xff); + m_prgspace->set_debugger_access(false); + } + m_icount = temp; +} + +const address_space_config *tms9995_device::memory_space_config(address_spacenum spacenum) const +{ + switch (spacenum) + { + case AS_PROGRAM: + return &m_program_config; + + case AS_IO: + return &m_io_config; + + default: + return NULL; + } +} + +/************************************************************************** + Microprograms for the CPU instructions + + The actions which are specific to the respective instruction are + invoked by repeated calls of ALU_xxx; each call increases a state + variable so that on the next call, the next part can be processed. + This saves us a lot of additional functions. +**************************************************************************/ + +/* + Define the indices for the micro-operation table. This is done for the sake + of a simpler microprogram definition as an UINT8[]. +*/ +enum +{ + PREFETCH, + PREFETCH_NO_INT, + MEMORY_READ, + MEMORY_WRITE, + WORD_READ, + WORD_WRITE, + OPERAND_ADDR, + INCREG, + INDX, + SET_IMM, + RETADDR, + RETADDR1, + CRU_INPUT, + CRU_OUTPUT, + ABORT, + END, + + ALU_NOP, + ALU_ADD_S_SXC, + ALU_B, + ALU_BLWP, + ALU_C, + ALU_CI, + ALU_CLR_SETO, + ALU_DIV, + ALU_DIVS, + ALU_EXTERNAL, + ALU_F3, + ALU_IMM_ARITHM, + ALU_JUMP, + ALU_LDCR, + ALU_LI, + ALU_LIMIWP, + ALU_LSTWP, + ALU_MOV, + ALU_MPY, + ALU_RTWP, + ALU_SBO_SBZ, + ALU_SHIFT, + ALU_SINGLE_ARITHM, + ALU_STCR, + ALU_STSTWP, + ALU_TB, + ALU_X, + ALU_XOP, + ALU_INT +}; + +#define MICROPROGRAM(_MP) \ + static const UINT8 _MP[] = + +/* + Cycles: + XXXX 1 => needs one cycle + xxxx 1 (1) => needs one cycle when accessing internal memory, two for external mem + PREFETCH 0 (1) => occurs during the last step in parallel, needs one more when fetching from outside + DECODE not shown here; assumed to happen during the next memory cycle; if there is none, + add another cycle + + OPERAND_ADDR x => needs x cycles for address derivation; see the separate table + + Prefetch always needs 1 or 2 cycles; the previous command occurs in parallel + to the prefetch, so we assign a 0 to the previous microprogram step +*/ + +MICROPROGRAM(operand_address_derivation) +{ + RETADDR, 0, 0, 0, // Register direct 0 + WORD_READ, RETADDR, 0, 0, // Register indirect 1 (1) + WORD_READ, RETADDR, 0, 0, // Symbolic 1 (1) + WORD_READ, INCREG, WORD_WRITE, RETADDR1, // Reg indirect auto-increment 3 (1) (1) + WORD_READ, INDX, WORD_READ, RETADDR // Indexed 3 (1) (1) +}; + +MICROPROGRAM(add_s_sxc_mp) +{ + OPERAND_ADDR, // x + MEMORY_READ, // 1 (1) + OPERAND_ADDR, // y + MEMORY_READ, // 1 (1) + ALU_ADD_S_SXC, // 0 (see above, occurs in parallel with PREFETCH) + PREFETCH, // 1 (1) + MEMORY_WRITE, // 1 (1) + decode in parallel (0) + END +}; + +MICROPROGRAM(b_mp) +{ + OPERAND_ADDR, // x + ALU_NOP, // 1 Don't read, just use the address + ALU_B, // 0 + PREFETCH, // 1 (1) + ALU_NOP, // 1 Don't save the return address + END +}; + +MICROPROGRAM(bl_mp) +{ + OPERAND_ADDR, // x + ALU_NOP, // 1 Don't read, just use the address + ALU_B, // 0 Re-use the alu operation from B + PREFETCH, // 1 (1) + ALU_NOP, // 1 + MEMORY_WRITE, // 1 (1) Write R11 + ALU_NOP, // 1 + END +}; + +MICROPROGRAM(blwp_mp) +{ + OPERAND_ADDR, // x Determine source address + MEMORY_READ, // 1 (1) + ALU_BLWP, // 1 Got new WP, save it; increase address, save + MEMORY_WRITE, // 1 (1) save old ST to new R15 + ALU_BLWP, // 1 + MEMORY_WRITE, // 1 (1) save old PC to new R14 + ALU_BLWP, // 1 + MEMORY_WRITE, // 1 (1) save old WP to new R13 + ALU_BLWP, // 1 retrieve address + MEMORY_READ, // 1 (1) Read new PC + ALU_BLWP, // 0 Set new PC + PREFETCH, // 1 (1) + ALU_NOP, // 1 + END +}; + +MICROPROGRAM(c_mp) +{ + OPERAND_ADDR, // x + MEMORY_READ, // 1 (1) + OPERAND_ADDR, // y + MEMORY_READ, // 1 (1) + ALU_C, // 0 + PREFETCH, // 1 (1) + ALU_NOP, // 1 decode + END +}; + +MICROPROGRAM(ci_mp) +{ + MEMORY_READ, // 1 (1) (reg) + SET_IMM, // 0 belongs to next cycle + MEMORY_READ, // 1 (1) (imm) + ALU_CI, // 0 set status + PREFETCH, // 1 (1) + ALU_NOP, // 1 decode + END +}; + +MICROPROGRAM(coc_czc_mp) +{ + OPERAND_ADDR, // x + MEMORY_READ, // 1 (1) + ALU_F3, // 0 + MEMORY_READ, // 1 (1) + ALU_F3, // 0 + PREFETCH, // 1 (1) + ALU_NOP, // 1 decode + END +}; + +MICROPROGRAM(clr_seto_mp) +{ + OPERAND_ADDR, // x + ALU_NOP, // 1 + ALU_CLR_SETO, // 0 + PREFETCH, // 1 (1) + MEMORY_WRITE, // 1 (1) + END +}; + +MICROPROGRAM(divide_mp) // TODO: Verify cycles on the real machine +{ + OPERAND_ADDR, // x Address of divisor S in Q=W1W2/S + MEMORY_READ, // 1 (1) Get S + ALU_DIV, // 1 + MEMORY_READ, // 1 (1) Get W1 + ALU_DIV, // 1 Check for overflow; skip next instruction if not + ABORT, // 1 + MEMORY_READ, // 1 (1) Get W2 + ALU_DIV, // d Calculate quotient + MEMORY_WRITE, // 1 (1) Write quotient to &W1 + ALU_DIV, // 0 + PREFETCH, // 1 (1) + MEMORY_WRITE, // 1 (1) Write remainder to &W2 + END +}; + +MICROPROGRAM(divide_signed_mp) // TODO: Verify cycles on the real machine +{ + OPERAND_ADDR, // x Address of divisor S in Q=W1W2/S + MEMORY_READ, // 1 (1) Get S + ALU_DIVS, // 1 + MEMORY_READ, // 1 (1) Get W1 + ALU_DIVS, // 1 + MEMORY_READ, // 1 (1) Get W2 + ALU_DIVS, // 1 Check for overflow, skip next instruction if not + ABORT, // 1 + ALU_DIVS, // d Calculate quotient + MEMORY_WRITE, // 1 (1) Write quotient to &W1 + ALU_DIVS, // 0 + PREFETCH, // 1 + MEMORY_WRITE, // 1 (1) Write remainder to &W2 + END +}; + +MICROPROGRAM(external_mp) +{ + ALU_NOP, // 1 + ALU_NOP, // 1 + ALU_NOP, // 1 + ALU_NOP, // 1 + ALU_NOP, // 1 + ALU_EXTERNAL, // 0 + PREFETCH, // 1 (1) + ALU_NOP, // 1 + END +}; + +MICROPROGRAM(imm_arithm_mp) +{ + MEMORY_READ, // 1 (1) + SET_IMM, // 0 + MEMORY_READ, // 1 (1) + ALU_IMM_ARITHM, // 0 + PREFETCH, // 1 (1) + MEMORY_WRITE, // 1 (1) + END +}; + +MICROPROGRAM(jump_mp) +{ + ALU_NOP, // 1 + ALU_JUMP, // 0 + PREFETCH, // 1 (1) + ALU_NOP, // 1 + END +}; + +MICROPROGRAM(ldcr_mp) // TODO: Verify cycles +{ + ALU_LDCR, // 1 + OPERAND_ADDR, // x + MEMORY_READ, // 1 (1) Get source data + ALU_LDCR, // 1 Save it, point to R12 + WORD_READ, // 1 (1) Get R12 + ALU_LDCR, // 1 Prepare CRU operation + CRU_OUTPUT, // c + ALU_NOP, // 0 + PREFETCH, // 1 (1) + ALU_NOP, // 1 + END +}; + +MICROPROGRAM(li_mp) +{ + SET_IMM, // 0 + MEMORY_READ, // 1 (1) + ALU_LI, // 0 + PREFETCH, // 1 (1) + MEMORY_WRITE, // 1 (1) + END +}; + +MICROPROGRAM(limi_lwpi_mp) +{ + SET_IMM, // 0 + MEMORY_READ, // 1 (1) + ALU_NOP, // 1 + ALU_LIMIWP, // 0 lwpi, 1 limi + PREFETCH, // 1 (1) + ALU_NOP, // 1 + END +}; + +MICROPROGRAM(lst_lwp_mp) +{ + MEMORY_READ, // 1 (1) + ALU_NOP, // 1 + ALU_LSTWP, // 0 lwp, 1 lst + PREFETCH, // 1 (1) + ALU_NOP, // 1 + END +}; + +MICROPROGRAM(mov_mp) +{ + OPERAND_ADDR, // 0 + MEMORY_READ, // 1 (1) + OPERAND_ADDR, // 0 + ALU_MOV, // 0 + PREFETCH, // 1 (1) + MEMORY_WRITE, // 1 (1) + END +}; + +MICROPROGRAM(multiply_mp) +{ + OPERAND_ADDR, // x + MEMORY_READ, // 1 (1) + ALU_MPY, // 1 + MEMORY_READ, // 1 (1) + ALU_MPY, // 17 + MEMORY_WRITE, // 1 (1) + ALU_MPY, // 0 + PREFETCH, // 1 (1) + MEMORY_WRITE, // 1 (1) + END +}; + +MICROPROGRAM(rtwp_mp) +{ + ALU_RTWP, // 1 + MEMORY_READ, // 1 (1) + ALU_RTWP, // 0 + MEMORY_READ, // 1 (1) + ALU_RTWP, // 0 + MEMORY_READ, // 1 (1) + ALU_RTWP, // 0 + PREFETCH, // 1 (1) + ALU_NOP, // 1 + END +}; + +MICROPROGRAM(sbo_sbz_mp) +{ + ALU_SBO_SBZ, // 1 Set address = &R12 + WORD_READ, // 1 (1) Read R12 + ALU_SBO_SBZ, // 1 Add offset + CRU_OUTPUT, // 1 output via CRU + PREFETCH, // 1 (1) + ALU_NOP, // 1 + ALU_NOP, // 1 + END +}; + +MICROPROGRAM(shift_mp) +{ + MEMORY_READ, // 1 (1) + ALU_SHIFT, // 2 skip next operation if count != 0 + MEMORY_READ, // 1 (1) if count=0 we must read R0 + ALU_SHIFT, // c do the shift + PREFETCH, // 1 (1) + MEMORY_WRITE, // 1 (1) + END +}; + +MICROPROGRAM(single_arithm_mp) +{ + OPERAND_ADDR, // x + MEMORY_READ, // 1 (1) + ALU_SINGLE_ARITHM, // 0 + PREFETCH, // 1 (1) + MEMORY_WRITE, // 1 (1) + END +}; + +MICROPROGRAM(stcr_mp) // TODO: Verify on real machine +{ + ALU_STCR, // 1 Check for byte operation + OPERAND_ADDR, // x Source operand + ALU_STCR, // 1 Save, set R12 + WORD_READ, // 1 (1) Read R12 + ALU_STCR, // 1 + CRU_INPUT, // c + ALU_STCR, // 13 + PREFETCH, // 1 (1) + MEMORY_WRITE, // 1 (1) + END +}; + +MICROPROGRAM(stst_stwp_mp) +{ + ALU_STSTWP, // 0 + ALU_NOP, // 1 + PREFETCH, // 1 (1) + MEMORY_WRITE, // 1 (1) + END +}; + +MICROPROGRAM(tb_mp) +{ + ALU_TB, // 1 + WORD_READ, // 1 (1) + ALU_TB, // 1 + CRU_INPUT, // 2 + ALU_TB, // 0 + PREFETCH, // 1 (1) + ALU_NOP, // 1 + ALU_NOP, // 1 + END +}; + +MICROPROGRAM(x_mp) +{ + OPERAND_ADDR, // x + MEMORY_READ, // 1 (1) + ALU_X, // 1 + END // should not be reached +}; + +MICROPROGRAM(xop_mp) +{ + OPERAND_ADDR, // x Determine source address + ALU_XOP, // 1 Save it; determine XOP number + MEMORY_READ, // 1 (1) Read new WP + ALU_XOP, // 1 + MEMORY_WRITE, // 1 (1) save source address to new R11 + ALU_XOP, // 1 + MEMORY_WRITE, // 1 (1) save old ST to new R15 + ALU_XOP, // 1 + MEMORY_WRITE, // 1 (1) save old PC to new R14 + ALU_XOP, // 1 + MEMORY_WRITE, // 1 (1) save old WP to new R13 + ALU_XOP, // 1 + MEMORY_READ, // 1 (1) Read new PC + ALU_XOP, // 0 set new PC, set X flag + PREFETCH, // 1 (1) + ALU_NOP, // 1 + ALU_NOP, // 1 + END +}; + +MICROPROGRAM(xor_mp) +{ + OPERAND_ADDR, // x + MEMORY_READ, // 1 (1) + ALU_F3, // 0 + MEMORY_READ, // 1 (1) + ALU_F3, // 0 + PREFETCH, // 1 (1) + MEMORY_WRITE, // 1 (1) + END +}; + +MICROPROGRAM(int_mp) +{ + ALU_INT, // 1 + MEMORY_READ, // 1 (1) + ALU_INT, // 2 + MEMORY_WRITE, // 1 (1) + ALU_INT, // 1 + MEMORY_WRITE, // 1 (1) + ALU_INT, // 1 + MEMORY_WRITE, // 1 (1) + ALU_INT, // 1 + MEMORY_READ, // 1 (1) + ALU_INT, // 0 + PREFETCH_NO_INT, // 1 (1) (prefetch happens in parallel to the previous operation) + ALU_NOP, // 1 (+decode in parallel; actually performed right after prefetch) + ALU_NOP, // 1 + END +}; + +const tms9995_device::ophandler tms9995_device::s_microoperation[] = +{ + &tms9995_device::int_prefetch_and_decode, + &tms9995_device::prefetch_and_decode, + &tms9995_device::mem_read, + &tms9995_device::mem_write, + &tms9995_device::word_read, + &tms9995_device::word_write, + &tms9995_device::operand_address_subprogram, + &tms9995_device::increment_register, + &tms9995_device::indexed_addressing, + &tms9995_device::set_immediate, + &tms9995_device::return_with_address, + &tms9995_device::return_with_address_copy, + &tms9995_device::cru_input_operation, + &tms9995_device::cru_output_operation, + &tms9995_device::abort_operation, + &tms9995_device::command_completed, + + &tms9995_device::alu_nop, + &tms9995_device::alu_add_s_sxc, + &tms9995_device::alu_b, + &tms9995_device::alu_blwp, + &tms9995_device::alu_c, + &tms9995_device::alu_ci, + &tms9995_device::alu_clr_seto, + &tms9995_device::alu_divide, + &tms9995_device::alu_divide_signed, + &tms9995_device::alu_external, + &tms9995_device::alu_f3, + &tms9995_device::alu_imm_arithm, + &tms9995_device::alu_jump, + &tms9995_device::alu_ldcr, + &tms9995_device::alu_li, + &tms9995_device::alu_limi_lwpi, + &tms9995_device::alu_lst_lwp, + &tms9995_device::alu_mov, + &tms9995_device::alu_multiply, + &tms9995_device::alu_rtwp, + &tms9995_device::alu_sbo_sbz, + &tms9995_device::alu_shift, + &tms9995_device::alu_single_arithm, + &tms9995_device::alu_stcr, + &tms9995_device::alu_stst_stwp, + &tms9995_device::alu_tb, + &tms9995_device::alu_x, + &tms9995_device::alu_xop, + &tms9995_device::alu_int +}; + +/***************************************************************************** + CPU instructions +*****************************************************************************/ + +/* + Available instructions + MID is not a real instruction but stands for an invalid operation which + triggers a "macro instruction detect" interrupt. Neither is INTR which + indicates an interrupt handling in progress. +*/ +enum +{ + MID=0, A, AB, ABS, AI, ANDI, B, BL, BLWP, C, + CB, CI, CKOF, CKON, CLR, COC, CZC, DEC, DECT, DIV, + DIVS, IDLE, INC, INCT, INV, JEQ, JGT, JH, JHE, JL, + JLE, JLT, JMP, JNC, JNE, JNO, JOC, JOP, LDCR, LI, + LIMI, LREX, LST, LWP, LWPI, MOV, MOVB, MPY, MPYS, NEG, + ORI, RSET, RTWP, S, SB, SBO, SBZ, SETO, SLA, SOC, + SOCB, SRA, SRC, SRL, STCR, STST, STWP, SWPB, SZC, SZCB, + TB, X, XOP, XOR, INTR +}; + +static const char opname[][5] = +{ "MID ", "A ", "AB ", "ABS ", "AI ", "ANDI", "B ", "BL ", "BLWP", "C ", + "CB ", "CI ", "CKOF", "CKON", "CLR ", "COC ", "CZC ", "DEC ", "DECT", "DIV ", + "DIVS", "IDLE", "INC ", "INCT", "INV ", "JEQ ", "JGT ", "JH ", "JHE ", "JL ", + "JLE ", "JLT ", "JMP ", "JNC ", "JNE ", "JNO ", "JOC ", "JOP ", "LDCR", "LI ", + "LIMI", "LREX", "LST ", "LWP ", "LWPI", "MOV ", "MOVB", "MPY ", "MPYS", "NEG ", + "ORI ", "RSET", "RTWP", "S ", "SB ", "SBO ", "SBZ ", "SETO", "SLA ", "SOC ", + "SOCB", "SRA ", "SRC ", "SRL ", "STCR", "STST", "STWP", "SWPB", "SZC ", "SZCB", + "TB ", "X ", "XOP ", "XOR ", "*int" +}; + +/* + Formats: + + 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + ----+------------------------------------------------+ + 1 | Opcode | B | Td | RegNr | Ts | RegNr | + +--------+---+----+------------+----+------------+ + 2 | Opcode | Displacement | + +-----------------------+------------------------+ + 3 | Opcode | RegNr | Ts | RegNr | + +-----------------+------------+----+------------+ + 4 | Opcode | Count | Ts | RegNr | + +-----------------+------------+----+------------+ + 5 | Opcode | Count | RegNr | + +-----------------------+-----------+------------+ + 6 | Opcode | Ts | RegNr | + +------------------------------+----+------------+ + 7 | Opcode |0| 0| 0| 0| 0 | + +---------------------------------+-+--+--+--+---+ + 8 | Opcode |0| RegNr | + +---------------------------------+-+------------+ + 9 | Opcode | Reg/Nr | Ts | RegNr | + +-----------------+------------+----+------------+ + 10 | Opcode | Ts | RegNr | (DIVS, MPYS) + +------------------------------+----+------------+ + 11 | Opcode | RegNr | (LST, LWP) + +-----------------------------------+------------+ +*/ + +/* + Defines the number of bits from the left which are significant for the + command in the respective format. +*/ +static const int format_mask_len[] = +{ + 0, 4, 8, 6, 6, 8, 10, 16, 12, 6, 10, 12 +}; + +const tms9995_device::tms_instruction tms9995_device::s_command[] = +{ + // Base opcode list + // Opcode, ID, format, microprg + { 0x0080, LST, 11, lst_lwp_mp }, + { 0x0090, LWP, 11, lst_lwp_mp }, + { 0x0180, DIVS, 10, divide_signed_mp }, + { 0x01C0, MPYS, 10, multiply_mp }, + { 0x0200, LI, 8, li_mp }, + { 0x0220, AI, 8, imm_arithm_mp }, + { 0x0240, ANDI, 8, imm_arithm_mp }, + { 0x0260, ORI, 8, imm_arithm_mp }, + { 0x0280, CI, 8, ci_mp }, + { 0x02a0, STWP, 8, stst_stwp_mp }, + { 0x02c0, STST, 8, stst_stwp_mp }, + { 0x02e0, LWPI, 8, limi_lwpi_mp }, + { 0x0300, LIMI, 8, limi_lwpi_mp }, + { 0x0340, IDLE, 7, external_mp }, + { 0x0360, RSET, 7, external_mp }, + { 0x0380, RTWP, 7, rtwp_mp }, + { 0x03a0, CKON, 7, external_mp }, + { 0x03c0, CKOF, 7, external_mp }, + { 0x03e0, LREX, 7, external_mp }, + { 0x0400, BLWP, 6, blwp_mp }, + { 0x0440, B, 6, b_mp }, + { 0x0480, X, 6, x_mp }, + { 0x04c0, CLR, 6, clr_seto_mp }, + { 0x0500, NEG, 6, single_arithm_mp }, + { 0x0540, INV, 6, single_arithm_mp }, + { 0x0580, INC, 6, single_arithm_mp }, + { 0x05c0, INCT, 6, single_arithm_mp }, + { 0x0600, DEC, 6, single_arithm_mp }, + { 0x0640, DECT, 6, single_arithm_mp }, + { 0x0680, BL, 6, bl_mp }, + { 0x06c0, SWPB, 6, single_arithm_mp }, + { 0x0700, SETO, 6, clr_seto_mp }, + { 0x0740, ABS, 6, single_arithm_mp }, + { 0x0800, SRA, 5, shift_mp }, + { 0x0900, SRL, 5, shift_mp }, + { 0x0a00, SLA, 5, shift_mp }, + { 0x0b00, SRC, 5, shift_mp }, + { 0x1000, JMP, 2, jump_mp }, + { 0x1100, JLT, 2, jump_mp }, + { 0x1200, JLE, 2, jump_mp }, + { 0x1300, JEQ, 2, jump_mp }, + { 0x1400, JHE, 2, jump_mp }, + { 0x1500, JGT, 2, jump_mp }, + { 0x1600, JNE, 2, jump_mp }, + { 0x1700, JNC, 2, jump_mp }, + { 0x1800, JOC, 2, jump_mp }, + { 0x1900, JNO, 2, jump_mp }, + { 0x1a00, JL, 2, jump_mp }, + { 0x1b00, JH, 2, jump_mp }, + { 0x1c00, JOP, 2, jump_mp }, + { 0x1d00, SBO, 2, sbo_sbz_mp }, + { 0x1e00, SBZ, 2, sbo_sbz_mp }, + { 0x1f00, TB, 2, tb_mp }, + { 0x2000, COC, 3, coc_czc_mp }, + { 0x2400, CZC, 3, coc_czc_mp }, + { 0x2800, XOR, 3, xor_mp }, + { 0x2c00, XOP, 3, xop_mp }, + { 0x3000, LDCR, 4, ldcr_mp }, + { 0x3400, STCR, 4, stcr_mp }, + { 0x3800, MPY, 9, multiply_mp }, + { 0x3c00, DIV, 9, divide_mp }, + { 0x4000, SZC, 1, add_s_sxc_mp }, + { 0x5000, SZCB, 1, add_s_sxc_mp }, + { 0x6000, S, 1, add_s_sxc_mp }, + { 0x7000, SB, 1, add_s_sxc_mp }, + { 0x8000, C, 1, c_mp }, + { 0x9000, CB, 1, c_mp }, + { 0xa000, A, 1, add_s_sxc_mp }, + { 0xb000, AB, 1, add_s_sxc_mp }, + { 0xc000, MOV, 1, mov_mp }, + { 0xd000, MOVB, 1, mov_mp }, + { 0xe000, SOC, 1, add_s_sxc_mp }, + { 0xf000, SOCB, 1, add_s_sxc_mp } +}; + +/* + Create a B-tree for looking up the commands. Each node can carry up to + 16 entries, indexed by 4 consecutive bits in the opcode. + + See tms9900.c for a detailed description. +*/ +void tms9995_device::build_command_lookup_table() +{ + int i = 0; + int cmdindex = 0; + int bitcount; + const tms_instruction *inst; + UINT16 opcode; + int k = 0; + + m_command_lookup_table = new lookup_entry[16]; + // We use lotables as a list of allocated tables - to be able to delete them + // at the end. + m_lotables[k++] = m_command_lookup_table; + + lookup_entry* table = m_command_lookup_table; + for (int j=0; j < 16; j++) + { + table[j].entry = NULL; + table[j].next_digit = NULL; + } + + do + { + inst = &s_command[i]; + table = m_command_lookup_table; + if (TRACE_EMU) logerror("tms9995: === opcode=%04x, len=%d\n", inst->opcode, format_mask_len[inst->format]); + bitcount = 4; + opcode = inst->opcode; + cmdindex = (opcode>>12) & 0x000f; + + while (bitcount < format_mask_len[inst->format]) + { + // Descend + if (table[cmdindex].next_digit == NULL) + { + if (TRACE_EMU) logerror("tms9995: create new table at bitcount=%d for index=%d\n", bitcount, cmdindex); + table[cmdindex].next_digit = new lookup_entry[16]; + m_lotables[k++] = table[cmdindex].next_digit; + for (int j=0; j < 16; j++) + { + table[cmdindex].next_digit[j].next_digit = NULL; + table[cmdindex].next_digit[j].entry = NULL; + } + } + else + { + if (TRACE_EMU) logerror("tms9995: found a table at bitcount=%d\n", bitcount); + } + + table = table[cmdindex].next_digit; + + bitcount = bitcount+4; + opcode <<= 4; + cmdindex = (opcode>>12) & 0x000f; + if (TRACE_EMU) logerror("tms9995: next index=%x\n", cmdindex); + } + + if (TRACE_EMU) logerror("tms9995: bitcount=%d\n", bitcount); + // We are at the target level + // Need to fill in the same entry for all values in the bitcount + // (if a command needs 10 bits we have to copy it four + // times for all combinations with 12 bits) + for (int j=0; j < (1<<(bitcount-format_mask_len[inst->format])); j++) + { + if (TRACE_EMU) logerror("tms9995: opcode=%04x at position %d\n", inst->opcode, cmdindex+j); + table[cmdindex+j].entry = inst; + } + + i++; + } while (inst->opcode != 0xf000); + + m_lotables[k++] = NULL; + if (TRACE_EMU) logerror("tms9995: Allocated %d tables\n", k); +} + +/* + Main execution loop + + For each invocation of execute_run, a number of loop iterations has been + calculated before (m_icount). Each loop iteration is one clock cycle. + The loop must be executed for the number of times that corresponds to the + time until the next timer event. +*/ +void tms9995_device::execute_run() +{ + if (m_reset) service_interrupt(); + + if (TRACE_EMU) logerror("tms9995: calling execute_run for %d cycles\n", m_icount); + do + { + // Normal operation + if (m_check_ready && m_ready == false) + { + // We are in a wait state + if (TRACE_WAITHOLD) logerror("tms9995: wait state\n"); + // The clock output should be used to change the state of an outer + // device which operates the READY line + pulse_clock(1); + } + else + { + if (m_check_hold && m_hold_state) + { + set_hold_state(true); + if (TRACE_WAITHOLD) logerror("tms9995: hold state\n"); + pulse_clock(1); + } + else + { + set_hold_state(false); + + m_check_ready = false; + + if (TRACE_MICRO) logerror("tms9995: main loop, operation %s, MPC = %d\n", opname[m_instruction->command], MPC); + (this->*s_microoperation[m_instruction->program[MPC]])(); + + // For multi-pass operations where the MPC should not advance + // or when we have put in a new microprogram + m_pass--; + if (m_pass<=0) + { + m_pass = 1; + MPC++; + } + } + } + } while (m_icount>0 && !m_reset); + if (TRACE_EMU) logerror("tms9995: cycles expired; will return soon.\n"); +} + +/**************************************************************************/ + +/* + Interrupt input + output + m_nmi_state + m_irq_level + flag[2], flag[4] +*/ +void tms9995_device::execute_set_input(int irqline, int state) +{ + if (irqline==INT_9995_RESET && state==ASSERT_LINE) + { + m_reset = true; + } + else + { + if (irqline == INPUT_LINE_NMI) + { + m_nmi_active = (state==ASSERT_LINE); + if (TRACE_INT) logerror("tms9995: NMI interrupt line state=%d\n", state); + } + else + { + if (irqline == INT_9995_INT1) + { + m_int1_active = m_flag[2] = (state==ASSERT_LINE); + if (TRACE_INT) logerror("tms9995: Line INT1 state=%d\n", state); + } + else + { + if (irqline == INT_9995_INT4) + { + if (TRACE_INT) logerror("tms9995: Line INT4/EC state=%d\n", state); + if (m_flag[0]==false) + { + if (TRACE_INT) logerror("tms9995: set as interrupt\n"); + m_int4_active = m_flag[4] = (state==ASSERT_LINE); + } + else + { + if (TRACE_INT) logerror("tms9995: set as event count\n"); + trigger_decrementer(); + } + } + else + { + logerror("tms9995: Accessed invalid interrupt line %d\n", irqline); + } + } + } + } +} + +/* + Issue a pulse on the clock line. +*/ +void tms9995_device::pulse_clock(int count) +{ + for (int i=0; i < count; i++) + { + if (!m_clock_out_line.isnull()) m_clock_out_line(ASSERT_LINE); + m_ready = m_ready_bufd && !m_request_auto_wait_state; // get the latched READY state + if (!m_clock_out_line.isnull()) m_clock_out_line(CLEAR_LINE); + m_icount--; // This is the only location where we count down the cycles. + if (TRACE_CLOCK) + { + if (m_check_ready) logerror("tms9995: pulse_clock, READY=%d, auto_wait=%d\n", m_ready_bufd? 1:0, m_auto_wait? 1:0); + else logerror("tms9995: pulse_clock\n"); + } + m_request_auto_wait_state = false; + if (m_flag[0] == false && m_flag[1] == true) + { + // Section 2.3.1.2.2: "by decreasing the count in the Decrementing + // Register by one for each fourth CLKOUT cycle" + m_decrementer_clkdiv = (m_decrementer_clkdiv+1)%4; + if (m_decrementer_clkdiv==0) trigger_decrementer(); + } + } +} + +/* + Enter the hold state. +*/ +void tms9995_device::set_hold(int state) +{ + m_hold_state = (state==ASSERT_LINE); + if (TRACE_WAITHOLD) logerror("tms9995: set HOLD = %d\n", state); + if (!m_hold_state) + { + if (!m_holda_line.isnull()) m_holda_line(CLEAR_LINE); + } +} + +/* + Signal READY to the CPU. When cleared, the CPU enters wait states. This + becomes effective on a clock pulse. +*/ +void tms9995_device::set_ready(int state) +{ + m_ready_bufd = (state==ASSERT_LINE); + if (TRACE_READY) logerror("tms9995: set READY = %d\n", m_ready_bufd? 1 : 0); +} + +/* + When the divide operations fail, we get to this operation. +*/ +void tms9995_device::abort_operation() +{ + int_prefetch_and_decode(); // do not forget to prefetch + // And don't forget that prefetch is a 2-pass operation, so this method + // will be called a second time. Only when the lowbyte has been fetched, + // continue with the next step + if (m_mem_phase==1) command_completed(); +} + +/* + Enter or leave the hold state. We only operate the HOLDA line when there is a change. +*/ +inline void tms9995_device::set_hold_state(bool state) +{ + if (m_hold_state != state) + if (!m_holda_line.isnull()) m_holda_line(state? ASSERT_LINE : CLEAR_LINE); + m_hold_state = state; +} + +/* + Decode the instruction. This is done in parallel to other operations + so we just do it together with the prefetch. +*/ +void tms9995_device::decode(UINT16 inst) +{ + int index = 0; + lookup_entry* table = m_command_lookup_table; + UINT16 opcode = inst; + bool complete = false; + const tms_instruction *decoded; + + int dindex = (m_instindex==0)? 1:0; + + m_mid_active = false; + + while (!complete) + { + index = (opcode >> 12) & 0x000f; + if (TRACE_EMU) logerror("tms9995: Check next hex digit of instruction %x\n", index); + if (table[index].next_digit != NULL) + { + table = table[index].next_digit; + opcode = opcode << 4; + } + else complete = true; + } + decoded = table[index].entry; + if (decoded == NULL) + { + // not found + logerror("tms9995: Undefined opcode %04x at logical address %04x, will trigger MID\n", inst, PC); + m_decoded[dindex].IR = 0; + m_decoded[dindex].command = MID; + } + else + { + m_decoded[dindex].IR = inst; + m_decoded[dindex].command = decoded->id; + m_decoded[dindex].program = decoded->prog; + m_decoded[dindex].byteop = ((decoded->format == 1) && ((inst & 0x1000)!=0)); + m_decoded[dindex].state = 0; + if (TRACE_EMU) logerror("tms9995: Command decoded as id %d, %s, base opcode %04x\n", decoded->id, opname[decoded->id], decoded->opcode); + m_pass = 1; + } +} + +/* + Fetch the next instruction and check pending interrupts before. + Getting an instruction is a normal memory access (plus an asserted IAQ line), + so this is subject to wait state handling. We have to allow for a two-pass + handling. +*/ +void tms9995_device::int_prefetch_and_decode() +{ + bool check_int = (m_instruction->command != XOP && m_instruction->command != BLWP); + int intmask = ST & 0x000f; + + if (m_mem_phase == 1) + { + // Check interrupt lines + if (m_nmi_active) + { + if (TRACE_INT) logerror("tms9995: Checking interrupts ... NMI active\n"); + m_int_pending |= PENDING_NMI; + m_idle_state = false; + PC = (PC + 2) & 0xfffe; // we have not prefetched the next instruction + return; + } + else + { + m_int_pending = 0; + + if (check_int) + { + if (m_int1_active && intmask >= 1) m_int_pending |= PENDING_LEVEL1; + if (m_int_overflow && intmask >= 2) m_int_pending |= PENDING_OVERFLOW; + if (m_int_decrementer && intmask >= 3) m_int_pending |= PENDING_DECR; + if (m_int4_active && intmask >= 4) m_int_pending |= PENDING_LEVEL4; + } + + if (m_int_pending!=0) + { + if (m_idle_state) + { + m_idle_state = false; + if (TRACE_INT) logerror("tms9995: Interrupt occurred, terminate IDLE state\n"); + } + PC = PC + 2; // PC must be advanced (see flow chart), but no prefetch + if (TRACE_INT) logerror("tms9995: Interrupts pending; no prefetch; advance PC to %04x\n", PC); + return; + } + else + { + if (TRACE_INT) logerror("tms9995: Checking interrupts ... none pending\n"); + // No pending interrupts + if (m_idle_state) + { + if (TRACE_WAITHOLD) logerror("tms9995: IDLE state\n"); + // We are IDLE, stay in the loop and do not advance the PC + m_pass = 2; + pulse_clock(1); + return; + } + } + } + } + + // We reach this point in phase 1 if there is no interrupt and in all other phases + prefetch_and_decode(); +} + +/* + The actual prefetch operation, but without the interrupt check. This one is + needed when we complete the interrupt handling and need to get the next + instruction. According to the flow chart in [1], the prefetch after the + interrupt handling ignores other pending interrupts. +*/ +void tms9995_device::prefetch_and_decode() +{ + if (m_mem_phase==1) + { + // Fetch next instruction + // Save these values; they have been computed during the current instruction execution + m_address_copy = m_address; + m_value_copy = m_current_value; + if (!m_iaq_line.isnull()) m_iaq_line(ASSERT_LINE); + m_address = PC; + if (TRACE_OP) logerror("tms9995: **** Prefetching new instruction at %04x ****\n", PC); + } + + word_read(); // changes m_mem_phase + + if (m_mem_phase==1) + { + // We're back in phase 1, i.e. the whole prefetch is done + decode(m_current_value); // This is for free; in reality it is in parallel with the next memory operation + m_address = m_address_copy; // restore m_address + m_current_value = m_value_copy; // restore m_current_value + PC = (PC + 2) & 0xfffe; // advance PC + if (!m_iaq_line.isnull()) m_iaq_line(CLEAR_LINE); + if (TRACE_OP) logerror("tms9995: ++++ Prefetch done ++++\n"); + } +} + +/* + Used by the normal command completion as well as by the X operation. We + assume that we have a fully decoded operation which was previously + prefetched. +*/ +void tms9995_device::next_command() +{ + int next = (m_instindex==0)? 1:0; + + if (m_decoded[next].command == MID) + { + m_mid_flag = true; + m_mid_active = true; + service_interrupt(); + } + else + { + m_instindex = next; + m_instruction = &m_decoded[m_instindex]; + m_get_destination = false; + // This is a preset for opcodes which do not need an opcode address derivation + m_address = WP + ((m_instruction->IR & 0x000f)<<1); + MPC = -1; + if (TRACE_OP) logerror("tms9995: ===== Next operation %04x (%s) at %04x =====\n", m_instruction->IR, opname[m_instruction->command], PC-2); + + if (TRACE_EXEC) + { + if (m_servicing_interrupt) logerror("i%04x\n", PC-2); + else logerror("%04x\n", PC-2); + } + PC_debug = PC - 2; + debugger_instruction_hook(this, PC_debug); + m_first_cycle = m_icount; + } +} + +/* + End of command execution +*/ +void tms9995_device::command_completed() +{ + // Pseudo state at the end of the current instruction cycle sequence + if (TRACE_CYCLES) + { + logerror("tms9995: +++++ Instruction %04x (%s) completed", m_instruction->IR, opname[m_instruction->command]); + int cycles = m_first_cycle - m_icount; + // Avoid nonsense values due to expired and resumed main loop + if (cycles > 0 && cycles < 10000) logerror(", consumed %d cycles", cycles); + logerror(" +++++\n"); + } + + if (m_int_pending != 0) + { + service_interrupt(); + } + else + { + if ((ST & ST_OE)!=0 && (ST & ST_OV)!=0 && (ST & 0x000f)>2) + { + service_interrupt(); + } + else + { + next_command(); + } + } +} + +/* + Handle pending interrupts. +*/ +void tms9995_device::service_interrupt() +{ + int vectorpos = 0; + + if (m_reset) + { + vectorpos = 0; + m_intmask = 0; // clear interrupt mask + + m_nmi_state = false; + m_hold_state = false; + m_mem_phase = 1; + m_check_hold = false; + m_word_access = false; + m_int1_active = false; + m_int4_active = false; + m_decrementer_clkdiv = 0; + + m_pass = 0; + m_instindex = 0; + m_instruction = &m_decoded[m_instindex]; + + memset(m_flag, 0, sizeof(m_flag)); + + ST = 0; + + // The auto-wait state generation is turned on when the READY line is cleared + // on RESET. + m_auto_wait = !m_ready_bufd; + if (TRACE_CONFIG) logerror("tms9995: RESET; automatic wait state creation is %s\n", m_auto_wait? "enabled":"disabled"); + // We reset the READY flag, or the CPU will not start + m_ready_bufd = true; + } + else + { + if (m_mid_active) + { + vectorpos = 0x0008; + m_intmask = 0x0001; + PC = (PC + 2) & 0xfffe; + if (TRACE_INT) logerror("tms9995: ***** MID pending\n"); + m_mid_active = false; + } + else + { + if ((m_int_pending & PENDING_NMI)!=0) + { + vectorpos = 0xfffc; + m_int_pending &= ~PENDING_NMI; + m_intmask = 0; + if (TRACE_INT) logerror("tms9995: ***** NMI pending\n"); + } + else + { + if ((m_int_pending & PENDING_LEVEL1)!=0) + { + vectorpos = 0x0004; + m_int_pending &= ~PENDING_LEVEL1; + m_flag[2] = false; + m_intmask = 0; + if (TRACE_INT) logerror("tms9995: ***** INT1 pending\n"); + } + else + { + if ((m_int_pending & PENDING_OVERFLOW)!=0) + { + vectorpos = 0x0008; + m_int_pending &= ~PENDING_OVERFLOW; + m_intmask = 0x0001; + if (TRACE_INT) logerror("tms9995: ***** OVERFL pending\n"); + } + else + { + if ((m_int_pending & PENDING_DECR)!=0) + { + vectorpos = 0x000c; + m_intmask = 0x0002; + m_int_pending &= ~PENDING_DECR; + m_flag[3] = false; + m_int_decrementer = false; + if (TRACE_DEC) logerror("tms9995: ***** DECR pending\n"); + } + else + { + vectorpos = 0x0010; + m_intmask = 0x0003; + m_int_pending &= ~PENDING_LEVEL4; + m_flag[4] = false; + if (TRACE_INT) logerror("tms9995: ***** INT4 pending\n"); + } + } + } + } + } + } + + if (TRACE_INT) logerror("tms9995: ********* triggered an interrupt with vector %04x/%04x\n", vectorpos, vectorpos+2); + + // just for debugging purposes + m_servicing_interrupt = true; + + // The microinstructions will do the context switch + m_address = vectorpos; + m_instruction->program = int_mp; + m_instruction->state = 0; + m_instruction->byteop = false; + m_instruction->command = INTR; + m_pass = m_reset? 1 : 2; + m_from_reset = m_reset; + + if (m_reset) + { + m_instruction->IR = 0x0000; + m_reset = false; + } + MPC = 0; + m_first_cycle = m_icount; + m_check_ready = false; // set to default +} + +/* + Read memory. This method expects as input m_address, and delivers the value + in m_current_value. For a single byte read, the byte is put into the high byte. + This method uses the m_pass variable to achieve a two-pass handling for + getting the complete word (high byte, low byte). + + input: + m_address + m_lowbyte + output: + m_current_value + + m_address is unchanged + + Make sure that m_lowbyte is false on the first call. +*/ +void tms9995_device::mem_read() +{ + // First determine whether the memory is inside the CPU + // On-chip memory is F000 ... F0F9, F0FA-FFF9 = off-chip, FFFA/B = Decrementer + // FFFC-FFFF = NMI vector (on-chip) + // There is a variant of the TMS9995 with no on-chip RAM which was used + // for the TI-99/8 (9537). + + if ((m_address & 0xfffe)==0xfffa && !m_mp9537) + { + if (TRACE_DEC) logerror("tms9995: read decrementer\n"); + // Decrementer mapped into the address space + m_current_value = m_decrementer_value; + if (m_instruction->byteop) + { + if ((m_address & 1)!=1) m_current_value <<= 8; + m_current_value &= 0xff00; + } + pulse_clock(1); + return; + } + + if (is_onchip(m_address)) + { + // If we have a word access, we have to align the address + // This is the case for word operations and for certain phases of + // byte operations (e.g. when retrieving the index register) + if (m_word_access || !m_instruction->byteop) m_address &= 0xfffe; + + if (TRACE_MEM) logerror("tms9995: read onchip memory (single pass, address %04x)\n", m_address); + + // Ignore the READY state + m_check_ready = false; + // We put fffc-ffff back into the f000-f0ff area + m_current_value = m_onchip_memory[m_address & 0x00ff]<<8; + if (m_word_access || !m_instruction->byteop) + { + // We have a word operation; add the low byte right here (just 1 cycle) + m_current_value |= (m_onchip_memory[(m_address & 0x00ff)+1] & 0xff); + } + pulse_clock(1); + } + else + { + // This is an off-chip access + m_check_ready = true; + UINT8 value; + UINT16 address = m_address; + + switch (m_mem_phase) + { + case 1: + // Set address + // If this is a word access, 4 passes, else 2 passes + if (!m_dbin_line.isnull()) m_dbin_line(ASSERT_LINE); + if (m_word_access || !m_instruction->byteop) + { + m_pass = 4; + // For word accesses, we always start at the even address + address &= 0xfffe; + } + else m_pass = 2; + + m_check_hold = false; + if (TRACE_ADDRESSBUS) logerror("tms9995: set address bus %04x\n", m_address & ~1); + m_prgspace->set_address(address); + m_request_auto_wait_state = m_auto_wait; + pulse_clock(1); + break; + case 2: + // Sample the value on the data bus (high byte) + if (m_word_access || !m_instruction->byteop) address &= 0xfffe; + value = m_prgspace->read_byte(address); + if (TRACE_MEM) logerror("tms9995: memory read byte %04x -> %02x\n", m_address & ~1, value); + m_current_value = (value << 8) & 0xff00; + break; + case 3: + // Set address + 1 (unless byte command) + if (TRACE_ADDRESSBUS) logerror("tms9995: set address bus %04x\n", m_address | 1); + m_prgspace->set_address(m_address | 1); + pulse_clock(1); + break; + case 4: + // Read low byte + value = m_prgspace->read_byte(m_address | 1); + m_current_value |= value; + if (TRACE_MEM) logerror("tms9995: memory read byte %04x -> %02x, complete word = %04x\n", m_address | 1, value, m_current_value); + m_check_hold = true; + break; + } + + m_mem_phase = (m_mem_phase % 4) +1; + + // Reset to 1 when we are done + if (m_pass==1) m_mem_phase = 1; + } +} + +/* + Read a word. This is independent of the byte flag of the instruction. + We need this variant especially when we have to retrieve a register value + in indexed addressing within a byte-oriented operation. +*/ +inline void tms9995_device::word_read() +{ + m_word_access = true; + mem_read(); + m_word_access = false; +} + +/* + Write memory. This method expects as input m_address and m_current_value. + For a single byte write, the byte to be written is expected to be in the + high byte of m_current_value. + This method uses the m_pass variable to achieve a two-pass handling for + writing the complete word (high byte, low byte). + + input: + m_address + m_lowbyte + m_current_value + + output: + - + m_address is unchanged + + Make sure that m_lowbyte is false on the first call. +*/ +void tms9995_device::mem_write() +{ + if ((m_address & 0xfffe)==0xfffa && !m_mp9537) + { + if (m_instruction->byteop) + { + // According to [1], section 2.3.1.2.2: + // "The decrementer should always be accessed as a full word. [...] + // Writing a single byte to either of the bytes of the decrementer + // will result in the data byte being written into the byte specifically addressed + // and random bits being written into the other byte of the decrementer." + + // So we just don't care about the low byte. + if (m_address == 0xfffb) m_current_value >>= 8; + + // dito: "This also loads the Decrementing Register with the same count." + m_starting_count_storage_register = m_decrementer_value = m_current_value; + } + else + { + m_starting_count_storage_register = m_decrementer_value = m_current_value; + } + if (TRACE_DEC) logerror("tms9995: Setting decrementer to %04x, PC=%04x\n", m_current_value, PC); + pulse_clock(1); + return; + } + + if (is_onchip(m_address)) + { + // If we have a word access, we have to align the address + // This is the case for word operations and for certain phases of + // byte operations (e.g. when retrieving the index register) + if (m_word_access || !m_instruction->byteop) m_address &= 0xfffe; + + if (TRACE_MEM) logerror("tms9995: write to onchip memory (single pass, address %04x, value=%04x)\n", m_address, m_current_value); + m_check_ready = false; + m_onchip_memory[m_address & 0x00ff] = (m_current_value >> 8) & 0xff; + if (m_word_access || !m_instruction->byteop) + { + m_onchip_memory[(m_address & 0x00ff)+1] = m_current_value & 0xff; + } + pulse_clock(1); + } + else + { + // This is an off-chip access + m_check_ready = true; + UINT16 address = m_address; + switch (m_mem_phase) + { + case 1: + // Set address + // If this is a word access, 4 passes, else 2 passes + if (!m_dbin_line.isnull()) m_dbin_line(CLEAR_LINE); + + if (m_word_access || !m_instruction->byteop) + { + m_pass = 4; + address &= 0xfffe; + } + else m_pass = 2; + + m_check_hold = false; + if (TRACE_ADDRESSBUS) logerror("tms9995: set address bus %04x\n", address); + m_prgspace->set_address(address); + if (TRACE_MEM) logerror("tms9995: memory write byte %04x <- %02x\n", address, (m_current_value >> 8)&0xff); + m_prgspace->write_byte(address, (m_current_value >> 8)&0xff); + pulse_clock(1); + break; + + case 2: + // no action here, just wait for READY + break; + case 3: + // Set address + 1 (unless byte command) + if (TRACE_ADDRESSBUS) logerror("tms9995: set address bus %04x\n", m_address | 1); + m_prgspace->set_address(m_address | 1); + if (TRACE_MEM) logerror("tms9995: memory write byte %04x <- %02x\n", m_address | 1, m_current_value & 0xff); + m_prgspace->write_byte(m_address | 1, m_current_value & 0xff); + pulse_clock(1); + break; + case 4: + // no action here, just wait for READY + m_check_hold = true; + break; + } + + m_mem_phase = (m_mem_phase % 4) +1; + + // Reset to 1 when we are done + if (m_pass==1) m_mem_phase = 1; + } +} + +/* + Write a word. This is independent of the byte flag of the instruction. +*/ +inline void tms9995_device::word_write() +{ + m_word_access = true; + mem_write(); + m_word_access = false; +} + +/* + Returns from the operand address derivation. +*/ +void tms9995_device::return_with_address() +{ + // Return from operand address derivation + // The result should be in m_address + m_instruction->program = m_caller; + MPC = m_caller_MPC; // will be increased on return + m_address = m_current_value + m_address_add; + if (TRACE_DETAIL) logerror("tms9995: +++ return from operand address derivation +++\n"); + // no clock pulse +} + +/* + Returns from the operand address derivation, but using the saved address. + This is required when we use the auto-increment feature. +*/ +void tms9995_device::return_with_address_copy() +{ + // Return from operand address derivation + m_instruction->program = m_caller; + MPC = m_caller_MPC; // will be increased on return + m_address = m_address_saved; + if (TRACE_DETAIL) logerror("tms9995: +++ return from operand address derivation (auto inc) +++\n"); + // no clock pulse +} + +/* + CRU support code + See common explanations in tms9900.c + + The TMS9995 CRU address space is larger than the CRU space of the TMS9900: + 0000-fffe (even addresses) instead of 0000-1ffe. Unlike the TMS9900, the + 9995 uses the data bus lines D0-D2 to indicate external operations. + + Internal CRU locations (read/write) + ----------------------------------- + 1EE0 Flag 0 Decrementer as event counter + 1EE2 Flag 1 Decrementer enable + 1EE4 Flag 2 Level 1 interrupt present (read only, also set when interrupt mask disallows interrupts) + 1EE6 Flag 3 Level 3 interrupt present (see above) + 1EE8 Flag 4 Level 4 interrupt present (see above) + ... + 1EFE Flag 15 + 1FDA MID flag (only indication, does not trigger when set) + + The TMS9995 allows for wait states during external CRU access. Therefore + we read one block of 8 bits in one go (as given by the MESS architecture) + but we do iterations for each bit, checking every time for the READY line + in the main loop. + + (write) + m_cru_output + m_cru_address + m_cru_value + m_count + +*/ + +#define CRUREADMASK 0x0fff +#define CRUWRITEMASK 0x7fff + +void tms9995_device::cru_output_operation() +{ + if (TRACE_CRU) logerror("tms9995: CRU output operation, address %04x, value %d\n", m_cru_address, m_cru_value & 0x01); + + if (m_cru_address == 0x1fda) + { + // [1], section 2.3.3.2.2: "setting the MID flag to one with a CRU instruction + // will not cause the MID interrupt to be requested." + m_check_ready = false; + m_mid_flag = (m_cru_value & 0x01); + } + else + { + if ((m_cru_address & 0xffe0) == 0x1ee0) + { + m_check_ready = false; + // FLAG2, FLAG3, and FLAG4 are read-only + if (TRACE_CRU) logerror("tms9995: set CRU address %04x to %d\n", m_cru_address, m_cru_value&1); + if ((m_cru_address != 0x1ee4) && (m_cru_address != 0x1ee6) && (m_cru_address != 0x1ee8)) + m_flag[(m_cru_address>>1)&0x000f] = (m_cru_value & 0x01); + } + else + { + // External access + m_check_ready = true; + } + } + + // All CRU write operations are visible to the outside world, even when we + // have internal access. This makes it possible to assign special + // functions to the internal flag bits which are realized outside + // of the CPU. However, no wait states are generated for internal + // accesses. ([1], section 2.3.3.2) + + m_cru->write_byte((m_cru_address >> 1)& CRUWRITEMASK, (m_cru_value & 0x01)); + m_cru_value >>= 1; + m_cru_address = (m_cru_address + 2) & 0xfffe; + m_count--; + + // Repeat this operation + m_pass = (m_count > 0)? 2 : 1; + pulse_clock(2); +} + +/* + Input: (read) + m_cru_multi_first + m_cru_address + Output: + m_cru_value (right-shifted; i.e. first bit is LSB of the 16 bit word, + also for byte operations) +*/ + +void tms9995_device::cru_input_operation() +{ + UINT16 crubit; + UINT8 crubyte; + + // Reading is different, since MESS uses 8 bit transfers + // We read 8 bits in one go, then iterate another min(n-1,7) times to allow + // for wait states. + + // read_byte for CRU delivers the first bit on the rightmost position + + int offset = (m_cru_address>>1) & 0x07; + + if (m_cru_first_read || m_cru_bits_left == 0) + { + // Read next 8 bits + // 00000000 0rrrrrrr r + // v + // ........ ........ X....... ........ + // + crubyte = m_cru->read_byte((m_cru_address >> 4)& CRUREADMASK); + if (TRACE_DETAIL) logerror("tms9995: Need to get next 8 bits (addresses %04x-%04x): %02x\n", (m_cru_address&0xfff0)+14, m_cru_address&0xfff0, crubyte); + m_cru_read = crubyte << 15; + m_cru_bits_left = 8; + + if (m_cru_first_read) + { + m_cru_read >>= offset; + m_cru_bits_left -= offset; + m_parity = 0; + m_cru_value = 0; + m_cru_first_read = false; + m_pass = m_count; + } + if (TRACE_DETAIL) logerror("tms9995: adjusted value for shift: %06x\n", m_cru_read); + } + + crubit = (m_cru_read & 0x8000); + m_cru_value = (m_cru_value >> 1) & 0x7fff; + + // During internal reading, the CRUIN line will be ignored. We emulate this + // by overwriting the bit which we got from outside. Also, READY is ignored. + if (m_cru_address == 0x1fda) + { + crubit = m_mid_flag? 0x8000 : 0x0000; + m_check_ready = false; + } + else + { + if ((m_cru_address & 0xffe0)==0x1ee0) + { + crubit = (m_flag[(m_cru_address>>1)&0x000f]==true)? 0x8000 : 0x0000; + m_check_ready = false; + } + else + { + m_check_ready = true; + } + } + + if (TRACE_CRU) logerror("tms9995: CRU input operation, address %04x, value %d\n", m_cru_address, (crubit & 0x8000)>>15); + + m_cru_value |= crubit; + if (crubit!=0) m_parity++; + + m_cru_address = (m_cru_address + 2) & 0xfffe; + m_cru_bits_left--; + + if (m_pass > 1) + { + m_cru_read >>= 1; + } + else + { + // This is the final shift. For both byte and word length transfers, + // the first bit is always m_cru_value & 0x0001. + m_cru_value >>= (16 - m_count); + } + pulse_clock(2); +} + +/* + Decrementer. +*/ +void tms9995_device::trigger_decrementer() +{ + if (m_starting_count_storage_register>0) // null will turn off the decrementer + { + m_decrementer_value--; + if (m_decrementer_value==0) + { + if (TRACE_DEC) logerror("tms9995: decrementer reached 0\n"); + m_decrementer_value = m_starting_count_storage_register; + if (m_flag[1]==true) + { + if (TRACE_DEC) logerror("tms9995: decrementer flags interrupt\n"); + m_flag[3] = true; + m_int_decrementer = true; + } + } + } +} + +/* + This is a switch to a subprogram. In terms of cycles + it does not take any time; execution continues with the first instruction + of the subprogram. + + input: + m_get_destination + m_instruction + WP + m_current_value + m_address + output: + m_source_value = m_current_value before invocation + m_current_value = m_address + m_address_add = 0 + m_lowbyte = false + m_get_destination = true + m_regnumber = register number + m_address = address of register + */ +void tms9995_device::operand_address_subprogram() +{ + UINT16 ircopy = m_instruction->IR; + if (m_get_destination) ircopy = ircopy >> 6; + + // Save the return program and position + m_caller = m_instruction->program; + m_caller_MPC = MPC; + + m_instruction->program = (UINT8*)operand_address_derivation; + MPC = (ircopy & 0x0030) >> 2; + m_regnumber = (ircopy & 0x000f); + m_address = (WP + (m_regnumber<<1)) & 0xffff; + + m_source_value = m_current_value; // will be overwritten when reading the destination + m_current_value = m_address; // needed for first case + + if (MPC==8) // Symbolic + { + if (m_regnumber != 0) + { + if (TRACE_DETAIL) logerror("tms9995: indexed addressing\n"); + MPC = 16; // indexed + } + else + { + if (TRACE_DETAIL) logerror("tms9995: symbolic addressing\n"); + m_address = PC; + PC = (PC + 2) & 0xfffe; + } + } + + m_get_destination = true; + m_mem_phase = 1; + m_address_add = 0; + MPC--; // will be increased in the mail loop + if (TRACE_DETAIL) logerror("tms9995: *** Operand address derivation; address=%04x; index=%d\n", m_address, MPC+1); +} + +/* + Used for register auto-increment. We have to save the address read from the + register content so that we can return it at the end. +*/ +void tms9995_device::increment_register() +{ + m_address_saved = m_current_value; // need a special return so we do not lose the value + m_current_value += m_instruction->byteop? 1 : 2; + m_address = (WP + (m_regnumber<<1)) & 0xffff; + m_mem_phase = 1; + pulse_clock(1); +} + +/* + Used for indexed addressing. We store the contents of the index register + in m_address_add which is set to 0 by default. Then we set the address + pointer to the PC location and advance it. +*/ +void tms9995_device::indexed_addressing() +{ + m_address_add = m_current_value; + m_address = PC; + PC = (PC + 2) & 0xfffe; + m_mem_phase = 1; + pulse_clock(1); +} + +void tms9995_device::set_immediate() +{ + // Need to determine the register address + m_address_saved = WP + ((m_instruction->IR & 0x000f)<<1); + m_address = PC; + m_source_value = m_current_value; // needed for AI, ANDI, ORI + PC = (PC + 2) & 0xfffe; + m_mem_phase = 1; +} + +/************************************************************************** + Status bit operations +**************************************************************************/ + +inline void tms9995_device::set_status_bit(int bit, bool state) +{ + if (state) ST |= bit; + else ST &= ~bit; + m_int_overflow = (m_check_overflow && bit == ST_OV && ((ST & ST_OE)!=0) && state == true); +} + +void tms9995_device::set_status_parity(UINT8 value) +{ + int count = 0; + for (int i=0; i < 8; i++) + { + if ((value & 0x80)!=0) count++; + value <<= 1; + } + set_status_bit(ST_OP, (count & 1)!=0); +} + +inline void tms9995_device::compare_and_set_lae(UINT16 value1, UINT16 value2) +{ + set_status_bit(ST_EQ, value1 == value2); + set_status_bit(ST_LH, value1 > value2); + set_status_bit(ST_AGT, (INT16)value1 > (INT16)value2); +} + +/************************************************************************** + ALU operations. The activities as implemented here are performed + during the internal operations of the CPU, according to the current + instruction. + + Some ALU operations are followed by the prefetch operation. In fact, + this prefetch happens in parallel to the ALU operation. In these + situations we do not pulse the clock here but leave this to the prefetch + operation. +**************************************************************************/ + +void tms9995_device::alu_nop() +{ + // Do nothing (or nothing that is externally visible) + pulse_clock(1); + return; +} + +void tms9995_device::alu_add_s_sxc() +{ + // We have the source operand value in m_source_value and the destination + // value in m_current_value + // The destination address is still in m_address + // Prefetch will not change m_current_value and m_address + + UINT32 dest_new = 0; + + switch (m_instruction->command) + { + case A: + case AB: + // When adding, a carry occurs when we exceed the 0xffff value. + dest_new = m_current_value + m_source_value; + set_status_bit(ST_C, (dest_new & 0x10000) != 0); + + // If the result has a sign bit that is different from both arguments, we have an overflow + // (i.e. getting a negative value from two positive values and vice versa) + set_status_bit(ST_OV, ((dest_new ^ m_current_value) & (dest_new ^ m_source_value) & 0x8000)!=0); + break; + case S: + case SB: + dest_new = m_current_value + ((~m_source_value) & 0xffff) + 1; + // Subtraction means adding the 2s complement, so the carry bit + // is set whenever adding the 2s complement exceeds ffff + // In fact the CPU adds the one's complement, then adds a one. This + // explains why subtracting 0 sets the carry bit. + set_status_bit(ST_C, (dest_new & 0x10000) != 0); + + // If the arguments have different sign bits and the result has a + // sign bit different from the destination value, we have an overflow + // e.g. value1 = 0x7fff, value2 = 0xffff; value1-value2 = 0x8000 + // or value1 = 0x8000, value2 = 0x0001; value1-value2 = 0x7fff + // value1 is the destination value + set_status_bit(ST_OV, (m_current_value ^ m_source_value) & (m_current_value ^ dest_new) & 0x8000); + break; + case SOC: + case SOCB: + dest_new = m_current_value | m_source_value; + break; + + case SZC: + case SZCB: + dest_new = m_current_value & ~m_source_value; + break; + } + + m_current_value = (UINT16)(dest_new & 0xffff); + + compare_and_set_lae((UINT16)(dest_new & 0xffff),0); + if (m_instruction->byteop) + { + set_status_parity((UINT8)(dest_new>>8)); + } + if (TRACE_STATUS) logerror("tms9995: ST = %04x (val=%04x)\n", ST, m_current_value); + // No clock pulse (will be done by prefetch) +} + +/* + Branch / Branch and link. We put the source address into the PC after + copying the PC into m_current_value. The address is R11. The B instruction + will just ignore these settings, but BL will use them. +*/ +void tms9995_device::alu_b() +{ + m_current_value = PC; + PC = m_address & 0xfffe; + m_address = WP + 22; +} + +/* + Branch and load workspace pointer. This is a branch to a subprogram with + context switch. +*/ +void tms9995_device::alu_blwp() +{ + int n = 1; + switch (m_instruction->state) + { + case 0: + // new WP in m_current_value + m_value_copy = WP; + WP = m_current_value & 0xfffe; + m_address_saved = m_address + 2; + m_address = WP + 30; + m_current_value = ST; + break; + case 1: + m_current_value = PC; + m_address = m_address - 2; + break; + case 2: + m_current_value = m_value_copy; // old WP + m_address = m_address - 2; + break; + case 3: + m_address = m_address_saved; + break; + case 4: + PC = m_current_value & 0xfffe; + n = 0; + if (TRACE_OP) logerror("tms9995: Context switch complete; WP=%04x, PC=%04x, ST=%04x\n", WP, PC, ST); + break; + } + m_instruction->state++; + pulse_clock(n); +} + +/* + Compare is similar to add, s, soc, szc, but we do not write a result. +*/ +void tms9995_device::alu_c() +{ + // We have the source operand value in m_source_value and the destination + // value in m_current_value + // The destination address is still in m_address + // Prefetch will not change m_current_value and m_address + if (m_instruction->byteop) + { + set_status_parity((UINT8)(m_source_value>>8)); + } + compare_and_set_lae(m_source_value, m_current_value); + if (TRACE_STATUS) logerror("tms9995: ST = %04x (val1=%04x, val2=%04x)\n", ST, m_source_value, m_current_value); +} + +/* + Compare with immediate value. +*/ +void tms9995_device::alu_ci() +{ + // We have the register value in m_source_value, the register address in m_address_saved + // and the immediate value in m_current_value + compare_and_set_lae(m_source_value, m_current_value); + if (TRACE_STATUS) logerror("tms9995: ST = %04x (val1=%04x, val2=%04x)\n", ST, m_source_value, m_current_value); +} + +void tms9995_device::alu_clr_seto() +{ + if (TRACE_OP) logerror("tms9995: clr/seto: Setting values for address %04x\n", m_address); + switch (m_instruction->command) + { + case CLR: + m_current_value = 0; + break; + case SETO: + m_current_value = 0xffff; + break; + } + // No clock pulse, as next instruction is prefetch +} + +/* + Unsigned division. +*/ +void tms9995_device::alu_divide() +{ + int n=1; + UINT32 uval32; + + bool overflow = true; + UINT16 value1; + + switch (m_instruction->state) + { + case 0: + m_source_value = m_current_value; + // Set address of register + m_address = WP + ((m_instruction->IR >> 5) & 0x001e); + m_address_copy = m_address; + break; + case 1: + // Value of register is in m_current_value + // We have an overflow when the quotient cannot be stored in 16 bits + // This is the case when the dividend / divisor >= 0x10000, + // or equivalently, dividend / 0x10000 >= divisor + + // Check overflow for unsigned DIV + if (m_current_value < m_source_value) // also if source=0 + { + MPC++; // skip the abort + overflow = false; + } + set_status_bit(ST_OV, overflow); + m_value_copy = m_current_value; // Save the high word + m_address = m_address + 2; + break; + case 2: + // W2 is in m_current_value + uval32 = (m_value_copy << 16) | m_current_value; + // Calculate + // The number of ALU cycles depends on the number of steps in + // the division algorithm. The number of cycles is between 1 and 16 + // As in TMS9900, this is a guess; it depends on the actual algorithm + // used in the chip. + + m_current_value = uval32 / m_source_value; + m_value_copy = uval32 % m_source_value; + m_address = m_address_copy; + + value1 = m_value_copy & 0xffff; + while (value1 != 0) + { + value1 = (value1 >> 1) & 0xffff; + n++; + } + + break; + case 3: + // now write the remainder + m_current_value = m_value_copy; + m_address = m_address + 2; + break; + } + m_instruction->state++; + pulse_clock(n); +} + +/* + Signed Division + We cannot handle this by the same ALU operation because we can NOT decide + whether there is an overflow before we have retrieved the whole 32 bit + word. Also, the overflow detection is pretty complicated for signed + division when done before the actual calculation. +*/ +void tms9995_device::alu_divide_signed() +{ + int n=1; + bool overflow = true; + UINT16 w1, w2, dwait; + INT16 divisor; + INT32 dividend; + + switch (m_instruction->state) + { + case 0: + // Got the source value (divisor) + m_source_value = m_current_value; + m_address = WP; // DIVS always uses R0,R1 + break; + case 1: + // Value of register is in m_current_value + m_value_copy = m_current_value; + m_address += 2; + break; + case 2: + // Now we have the dividend low word in m_current_value, + // the dividend high word in m_value_copy, and + // the divisor in m_source_value. + + w1 = m_value_copy; + w2 = m_current_value; + divisor = m_source_value; + dividend = w1 << 16 | w2; + + // Now check for overflow + // We need to go for four cases + // if the divisor is not 0 anyway + if (divisor != 0) + { + if (dividend >= 0) + { + if (divisor > 0) + { + overflow = (dividend > ((divisor<<15) - 1)); + } + else + { + overflow = (dividend > (((-divisor)<<15) + (-divisor) - 1)); + } + } + else + { + if (divisor > 0) + { + overflow = ((-dividend) > ((divisor<<15) + divisor - 1)); + } + else + { + overflow = ((-dividend) > (((-divisor)<<15) - 1)); + } + } + } + else + { + overflow = true; // divisor is 0 + } + set_status_bit(ST_OV, overflow); + if (!overflow) MPC++; // Skip the next microinstruction when there is no overflow + break; + case 3: + // We are here because there was no overflow + dividend = m_value_copy << 16 | m_current_value; + // Do the calculation + m_current_value = (UINT16)(dividend / (INT16)m_source_value); + m_value_copy = (UINT16)(dividend % (INT16)m_source_value); + m_address = WP; + + // As we have not implemented the real division algorithm we must + // simulate the number of steps required for calculating the result. + // This is just a guess. + dwait = m_value_copy; + while (dwait != 0) + { + dwait = (dwait >> 1) & 0xffff; + n++; + } + // go write the quotient into R0 + break; + case 4: + // Now write the remainder + m_current_value = m_value_copy; + m_address += 2; + n = 0; + break; + } + m_instruction->state++; + pulse_clock(n); +} + +/* + External operations. +*/ +void tms9995_device::alu_external() +{ + // Call some possibly attached external device + // A specific bit pattern is put on the data bus, and the CRUOUT line is + // pulsed. In our case we use a special callback function since we cannot + // emulate this behavior in this implementation. + + // Opcodes D012 value + // -----------------vvv------ + // IDLE = 0000 0011 0100 0000 + // RSET = 0000 0011 0110 0000 + // CKON = 0000 0011 1010 0000 + // CKOF = 0000 0011 1100 0000 + // LREX = 0000 0011 1110 0000 + + // Only IDLE has a visible effect on the CPU without external support: the + // CPU will stop execution until an interrupt occurs. CKON, CKOF, LREX have + // no effect without external support. Neither has RSET, it does *not* + // cause a reset of the CPU or of the remaining computer system. + // It only clears the interrupt mask and outputs the + // external code on the data bus. A special line decoder could then trigger + // a reset from outside. + + if (m_instruction->command == IDLE) + { + if (TRACE_OP) logerror("tms9995: Entering IDLE state\n"); + m_idle_state = true; + } + + if (m_instruction->command == RSET) + { + ST &= 0xfff0; + if (TRACE_OP) logerror("tms9995: RSET, new ST = %04x\n", ST); + } + + if (!m_external_operation.isnull()) m_external_operation((m_instruction->IR >> 5) & 0x07, 1, 0xff); +} + +/* + Logical compare and XOR +*/ +void tms9995_device::alu_f3() +{ + switch (m_instruction->state) + { + case 0: + // We have the contents of the source in m_current_value and its address + // in m_address + m_source_value = m_current_value; + // Get register address + m_address = WP + ((m_instruction->IR >> 5) & 0x001e); + break; + case 1: + // Register contents -> m_current_value + // Source contents -> m_source_value + if (m_instruction->command == COC) + { + set_status_bit(ST_EQ, (m_current_value & m_source_value) == m_source_value); + } + else + { + if (m_instruction->command == CZC) + { + set_status_bit(ST_EQ, (~m_current_value & m_source_value) == m_source_value); + } + else + { + // XOR + // The workspace register address is still in m_address + m_current_value = (m_current_value ^ m_source_value); + compare_and_set_lae(m_current_value, 0); + } + } + if (TRACE_STATUS) logerror("tms9995: ST = %04x\n", ST); + break; + } + m_instruction->state++; +} + +/* + Handles AI, ANDI, ORI. +*/ +void tms9995_device::alu_imm_arithm() +{ + UINT32 dest_new = 0; + + // We have the register value in m_source_value, the register address in m_address_saved + // and the immediate value in m_current_value + switch (m_instruction->command) + { + case AI: + dest_new = m_current_value + m_source_value; + set_status_bit(ST_C, (dest_new & 0x10000) != 0); + + // If the result has a sign bit that is different from both arguments, we have an overflow + // (i.e. getting a negative value from two positive values and vice versa) + set_status_bit(ST_OV, ((dest_new ^ m_current_value) & (dest_new ^ m_source_value) & 0x8000)!=0); + break; + case ANDI: + dest_new = m_current_value & m_source_value; + break; + case ORI: + dest_new = m_current_value | m_source_value; + break; + } + + m_current_value = (UINT16)(dest_new & 0xffff); + compare_and_set_lae(m_current_value, 0); + m_address = m_address_saved; + if (TRACE_STATUS) logerror("tms9995: ST = %04x (val=%04x)\n", ST, m_current_value); +} + +/* + Handles all jump instructions. +*/ +void tms9995_device::alu_jump() +{ + bool cond = false; + INT8 displacement = (m_instruction->IR & 0xff); + + switch (m_instruction->command) + { + case JMP: + cond = true; + break; + case JLT: // LAECOP == x00xxx + cond = ((ST & (ST_AGT | ST_EQ))==0); + break; + case JLE: // LAECOP == 0xxxxx + cond = ((ST & ST_LH)==0); + break; + case JEQ: // LAECOP == xx1xxx + cond = ((ST & ST_EQ)!=0); + break; + case JHE: // LAECOP == 1x0xxx, 0x1xxx + cond = ((ST & (ST_LH | ST_EQ)) != 0); + break; + case JGT: // LAECOP == x1xxxx + cond = ((ST & ST_AGT)!=0); + break; + case JNE: // LAECOP == xx0xxx + cond = ((ST & ST_EQ)==0); + break; + case JNC: // LAECOP == xxx0xx + cond = ((ST & ST_C)==0); + break; + case JOC: // LAECOP == xxx1xx + cond = ((ST & ST_C)!=0); + break; + case JNO: // LAECOP == xxxx0x + cond = ((ST & ST_OV)==0); + break; + case JL: // LAECOP == 0x0xxx + cond = ((ST & (ST_LH | ST_EQ)) == 0); + break; + case JH: // LAECOP == 1xxxxx + cond = ((ST & ST_LH)!=0); + break; + case JOP: // LAECOP == xxxxx1 + cond = ((ST & ST_OP)!=0); + break; + } + + if (!cond) + { + if (TRACE_OP) logerror("tms9995: Jump condition false\n"); + } + else + { + if (TRACE_OP) logerror("tms9995: Jump condition true\n"); + PC = (PC + (displacement<<1)) & 0xfffe; + } +} + +/* + Implements LDCR. +*/ +void tms9995_device::alu_ldcr() +{ + switch (m_instruction->state) + { + case 0: + m_count = (m_instruction->IR >> 6) & 0x000f; + if (m_count==0) m_count = 16; + m_instruction->byteop = (m_count<9); + break; + case 1: + // We have read the byte or word into m_current_value. + compare_and_set_lae(m_current_value, 0); + if (TRACE_STATUS) logerror("tms9995: ST = %04x (val=%04x)\n", ST, m_current_value); + if (m_instruction->byteop) + { + m_current_value = (m_current_value>>8) & 0xff; + set_status_parity((UINT8)m_current_value); + } + m_cru_value = m_current_value; + m_address = WP + 24; + break; + case 2: + // Prepare CRU operation + m_cru_address = m_current_value; + break; + } + m_instruction->state++; + pulse_clock(1); +} + +/* + Implements LI. Almost everything has been done in the microprogram; + this part is reached with m_address_saved = register address, + and m_current_value = *m_address; +*/ +void tms9995_device::alu_li() +{ + // Retrieve the address of the register + // The immediate value is still in m_current_value + m_address = m_address_saved; + compare_and_set_lae(m_current_value, 0); + if (TRACE_STATUS) logerror("tms9995: ST = %04x (val=%04x)\n", ST, m_current_value); +} + +void tms9995_device::alu_limi_lwpi() +{ + // The immediate value is in m_current_value + if (m_instruction->command == LIMI) + { + ST = (ST & 0xfff0) | (m_current_value & 0x000f); + if (TRACE_OP) logerror("tms9995: LIMI sets ST = %04x\n", ST); + pulse_clock(1); // needs one more than LWPI + } + else + { + WP = m_current_value & 0xfffe; + if (TRACE_OP) logerror("tms9995: LWPI sets new WP = %04x\n", WP); + } +} + +/* + Load status and load workspace pointer. This is a TMS9995-specific + operation. +*/ +void tms9995_device::alu_lst_lwp() +{ + if (m_instruction->command==LST) + { + ST = m_current_value; + if (TRACE_OP) logerror("tms9995: new ST = %04x\n", ST); + pulse_clock(1); + } + else + { + WP = m_current_value & 0xfffe; + if (TRACE_OP) logerror("tms9995: new WP = %04x\n", WP); + } +} + +/* + The MOV operation on the TMS9995 is definitely more efficient than in the + TMS9900. As we have only 8 data bus lines we can read or write bytes + with only one cycle. The TMS9900 always has to read the memory word first + in order to write back a complete word, also when doing byte operations. +*/ +void tms9995_device::alu_mov() +{ + m_current_value = m_source_value; + if (m_instruction->byteop) + { + set_status_parity((UINT8)(m_current_value>>8)); + } + compare_and_set_lae(m_current_value, 0); + if (TRACE_STATUS) logerror("tms9995: ST = %04x (val=%04x)\n", ST, m_current_value); + // No clock pulse, as next instruction is prefetch +} + +/* + Unsigned and signed multiplication +*/ +void tms9995_device::alu_multiply() +{ + int n = 0; + UINT32 result = 0; + INT32 results = 0; + + if (m_instruction->command==MPY) + { + switch (m_instruction->state) + { + case 0: + // m_current_value <- multiplier (source) + m_source_value = m_current_value; + // m_address is the second multiplier (in a register) + m_address = ((m_instruction->IR >> 5) & 0x001e) + WP; + n = 1; + break; + case 1: + // m_current_value <- register content + result = (m_source_value & 0x0000ffff) * (m_current_value & 0x0000ffff); + m_current_value = (result >> 16) & 0xffff; + m_value_copy = result & 0xffff; + // m_address is still the register + n = 17; + break; + case 2: + m_address += 2; + m_current_value = m_value_copy; + // now write the lower 16 bit. + // If the register was R15, do not use R0 but continue writing after + // R15's address + break; + } + } + else + { + switch (m_instruction->state) + { + case 0: + // m_current_value <- multiplier (source) + m_source_value = m_current_value; + // m_address is the second multiplier (in R0) + m_address = WP; + n = 1; + break; + case 1: + // m_current_value <- register content + results = ((INT16)m_source_value) * ((INT16)m_current_value); + m_current_value = (results >> 16) & 0xffff; + m_value_copy = results & 0xffff; + // m_address is still the register + n = 16; + break; + case 2: + m_address += 2; + m_current_value = m_value_copy; + // now write the lower 16 bit. + break; + } + } + m_instruction->state++; + pulse_clock(n); +} + +void tms9995_device::alu_rtwp() +{ + switch (m_instruction->state) + { + case 0: + m_address = WP + 30; // R15 + pulse_clock(1); + break; + case 1: + ST = m_current_value; + m_address -= 2; // R14 + break; + case 2: + PC = m_current_value & 0xfffe; + m_address -= 2; // R13 + break; + case 3: + WP = m_current_value & 0xfffe; + + // Just for debugging purposes + m_servicing_interrupt = false; + + if (TRACE_OP) logerror("tms9995: RTWP restored old context (WP=%04x, PC=%04x, ST=%04x)\n", WP, PC, ST); + break; + } + m_instruction->state++; +} + +void tms9995_device::alu_sbo_sbz() +{ + INT8 displacement; + + if (m_instruction->state==0) + { + m_address = WP + 24; + } + else + { + m_cru_value = (m_instruction->command==SBO)? 1 : 0; + displacement = (INT8)(m_instruction->IR & 0xff); + m_cru_address = m_current_value + (displacement<<1); + m_count = 1; + } + m_instruction->state++; + pulse_clock(1); +} + +/* + Perform the shift operation +*/ +void tms9995_device::alu_shift() +{ + bool carry = false; + bool overflow = false; + UINT16 sign = 0; + UINT32 value; + int count; + + switch (m_instruction->state) + { + case 0: + // we have the value of the register in m_current_value + // Save it (we may have to read R0) + m_value_copy = m_current_value; + m_address_saved = m_address; + m_address = WP; + // store this in m_current_value where the R0 value will be put + m_current_value = (m_instruction->IR >> 4)& 0x000f; + if (m_current_value != 0) + { + // skip the next read operation + MPC++; + } + else + { + if (TRACE_DETAIL) logerror("tms9995: Shift operation gets count from R0\n"); + } + pulse_clock(1); + pulse_clock(1); + break; + + case 1: + count = m_current_value & 0x000f; // from the instruction or from R0 + if (count==0) count = 16; + + value = m_value_copy; + + // we are re-implementing the shift operations because we have to pulse + // the clock at each single shift anyway. + // Also, it is easier to implement the status bit setting. + // Note that count is never 0 + if (m_instruction->command == SRA) sign = value & 0x8000; + + for (int i=0; i < count; i++) + { + switch (m_instruction->command) + { + case SRL: + case SRA: + carry = ((value & 1)!=0); + value = (value >> 1) | sign; + break; + case SLA: + carry = ((value & 0x8000)!=0); + value <<= 1; + if (carry != ((value&0x8000)!=0)) overflow = true; + break; + case SRC: + carry = ((value & 1)!=0); + value = (value>>1) | (carry? 0x8000 : 0x0000); + break; + } + pulse_clock(1); + } + + m_current_value = value & 0xffff; + set_status_bit(ST_C, carry); + set_status_bit(ST_OV, overflow); + compare_and_set_lae(m_current_value, 0); + m_address = m_address_saved; // Register address + if (TRACE_STATUS) logerror("tms9995: ST = %04x (val=%04x)\n", ST, m_current_value); + break; + } + m_instruction->state++; +} + +/* + Handles ABS, DEC, DECT, INC, INCT, NEG, INV +*/ +void tms9995_device::alu_single_arithm() +{ + UINT32 dest_new = 0; + UINT32 src_val = m_current_value & 0x0000ffff; + UINT16 sign = 0; + bool check_ov = true; + + switch (m_instruction->command) + { + case ABS: + // LAECO (from original word!) + // O if >8000 + // C is always reset + set_status_bit(ST_OV, m_current_value == 0x8000); + set_status_bit(ST_C, false); + compare_and_set_lae(m_current_value, 0); + + if ((m_current_value & 0x8000)!=0) + { + dest_new = ((~src_val) & 0x0000ffff) + 1; + } + else + { + dest_new = src_val; + } + m_current_value = dest_new & 0xffff; + return; + case DEC: + // LAECO + // Carry for result value != 0xffff + // Overflow for result value == 0x7fff + dest_new = src_val + 0xffff; + sign = 0x8000; + break; + case DECT: + // Carry for result value != 0xffff / 0xfffe + // Overflow for result value = 0x7fff / 0x7ffe + dest_new = src_val + 0xfffe; + sign = 0x8000; + break; + case INC: + // LAECO + // Overflow for result value = 0x8000 + // Carry for result value = 0x0000 + dest_new = src_val + 1; + break; + case INCT: + // LAECO + // Overflow for result value = 0x8000 / 0x8001 + // Carry for result value = 0x0000 / 0x0001 + dest_new = src_val + 2; + break; + case INV: + // LAE + dest_new = ~src_val & 0xffff; + check_ov = false; + break; + case NEG: + // LAECO + // Overflow occurs for value=0x8000 + // Carry occurs for value=0 + dest_new = ((~src_val) & 0x0000ffff) + 1; + check_ov = false; + set_status_bit(ST_OV, src_val == 0x8000); + break; + case SWPB: + m_current_value = ((m_current_value << 8) | (m_current_value >> 8)) & 0xffff; + // I don't know what they are doing right now, but we lose a lot of cycles + // according to the spec (which can indeed be proved on a real system) + + // Maybe this command is used as a forced wait between accesses to the + // video system. Usually we have two byte writes to set an address in + // the VDP, with a SWPB in between. Most software for the TI-99/4A using + // the TMS9900 will run into trouble when executed on the TI-99/8 with + // the much faster TMS9995. So the SWPB may be used to as an intentional + // slowdown. + + // No status bits affected + pulse_clock(10); + return; + } + + if (check_ov) set_status_bit(ST_OV, ((src_val & 0x8000)==sign) && ((dest_new & 0x8000)!=sign)); + set_status_bit(ST_C, (dest_new & 0x10000) != 0); + m_current_value = dest_new & 0xffff; + compare_and_set_lae(m_current_value, 0); + + if (TRACE_STATUS) logerror("tms9995: ST = %04x (val=%04x)\n", ST, m_current_value); + // No clock pulse, as next instruction is prefetch +} + +/* + Store CRU. +*/ +void tms9995_device::alu_stcr() +{ + int n = 1; + switch (m_instruction->state) + { + case 0: + m_count = (m_instruction->IR >> 6) & 0x000f; + if (m_count == 0) m_count = 16; + m_instruction->byteop = (m_count < 9); + break; + case 1: + m_address_saved = m_address; + m_address = WP + 24; + break; + case 2: + m_cru_address = m_current_value; + m_cru_first_read = true; + break; + case 3: + // I don't know what is happening here, but it takes quite some time. + // May be shift operations. + m_current_value = m_cru_value; + m_address = m_address_saved; + compare_and_set_lae(m_current_value, 0); + n = 13; + if (m_instruction->byteop) + { + set_status_parity((UINT8)m_current_value); + m_current_value <<= 8; + } + else n += 8; + if (TRACE_STATUS) logerror("tms9995: ST = %04x (val=%04x)\n", ST, m_current_value); + break; + } + m_instruction->state++; + pulse_clock(n); +} + + +/* + Store status and store workspace pointer. We need to determine the + address of the register here. +*/ +void tms9995_device::alu_stst_stwp() +{ + m_address = WP + ((m_instruction->IR & 0x000f)<<1); + m_current_value = (m_instruction->command==STST)? ST : WP; +} + +/* + Test CRU bit. +*/ +void tms9995_device::alu_tb() +{ + INT8 displacement; + + switch (m_instruction->state) + { + case 0: + m_address = WP + 24; + pulse_clock(1); + break; + case 1: + displacement = (INT8)(m_instruction->IR & 0xff); + m_cru_address = m_current_value + (displacement<<1); + m_cru_first_read = true; + m_count = 1; + pulse_clock(1); + break; + case 2: + set_status_bit(ST_EQ, m_cru_value!=0); + if (TRACE_STATUS) logerror("tms9995: ST = %04x\n", ST); + break; + } + m_instruction->state++; +} + +/* + Execute. This operation is substituted after reading the word at the + given address. +*/ +void tms9995_device::alu_x() +{ + // We have the word in m_current_value. This word must now be decoded + // as if it has been acquired by the normal procedure. + decode(m_current_value); + pulse_clock(1); + + // Switch to the prefetched and decoded instruction + next_command(); +} + +/* + XOP operation. +*/ +void tms9995_device::alu_xop() +{ + switch (m_instruction->state) + { + case 0: + // we have the source address in m_address + m_address_saved = m_address; + // Format is xxxx xxnn nnxx xxxx + m_address = 0x0040 + ((m_instruction->IR & 0x03c0)>>4); + pulse_clock(1); + break; + case 1: + // m_current_value is new WP + m_value_copy = WP; // store this for later + WP = m_current_value & 0xfffe; + m_address = WP + 0x0016; // Address of new R11 + m_current_value = m_address_saved; + pulse_clock(1); + break; + case 2: + m_address = WP + 0x001e; + m_current_value = ST; + pulse_clock(1); + break; + case 3: + m_address = WP + 0x001c; + m_current_value = PC; + pulse_clock(1); + break; + case 4: + m_address = WP + 0x001a; + m_current_value = m_value_copy; + pulse_clock(1); + break; + case 5: + m_address = 0x0042 + ((m_instruction->IR & 0x03c0)>>4); + pulse_clock(1); + break; + case 6: + PC = m_current_value & 0xfffe; + set_status_bit(ST_X, true); + break; + } + m_instruction->state++; +} + +/* + Handle an interrupt. The behavior as implemented here follows + exactly the flowchart in [1] +*/ +void tms9995_device::alu_int() +{ + int pulse = 1; + + switch (m_instruction->state) + { + case 0: + PC = (PC - 2) & 0xfffe; + m_address_saved = m_address; + if (TRACE_INTD) logerror("tms9995: interrupt service (0): Prepare to read vector\n"); + break; + case 1: + pulse = 2; // two cycles (with the one at the end) + m_source_value = WP; // old WP + WP = m_current_value & 0xfffe; // new WP + m_current_value = ST; + m_address = (WP + 30)&0xfffe; + if (TRACE_INTD) logerror("tms9995: interrupt service (1): Read new WP = %04x, save ST to %04x\n", WP, m_address); + break; + case 2: + m_address = (WP + 28)&0xfffe; + m_current_value = PC; + if (TRACE_INTD) logerror("tms9995: interrupt service (2): Save PC to %04x\n", m_address); + break; + case 3: + m_address = (WP + 26)&0xfffe; + m_current_value = m_source_value; // old WP + if (TRACE_INTD) logerror("tms9995: interrupt service (3): Save WP to %04x\n", m_address); + break; + case 4: + m_address = (m_address_saved + 2) & 0xfffe; + if (TRACE_INTD) logerror("tms9995: interrupt service (4): Read PC from %04x\n", m_address); + break; + case 5: + PC = m_current_value & 0xfffe; + ST = (ST & 0xfe00) | m_intmask; + if (TRACE_INTD) logerror("tms9995: interrupt service (5): Context switch complete; WP=%04x, PC=%04x, ST=%04x\n", WP, PC, ST); + + if (((m_int_pending & PENDING_MID)!=0) && m_nmi_active) + { + if (TRACE_INTD) logerror("tms9995: interrupt service (6): NMI active after context switch\n"); + m_int_pending &= ~PENDING_MID; + m_address = 0xfffc; + m_intmask = 0; + MPC = 0; // redo the interrupt service for the NMI + } + else + { + if (m_from_reset) + { + if (TRACE_INTD) logerror("tms9995: interrupt service (6): RESET completed\n"); + // We came from the RESET interrupt + m_from_reset = false; + ST &= 0x01ff; + m_mid_flag = false; + m_mid_active = false; + // FLAG0 and FLAG1 are also set to zero after RESET ([1], sect. 2.3.1.2.2) + for (int i=0; i < 5; i++) m_flag[i] = false; + m_check_hold = true; + } + } + pulse = 0; + break; + + // If next instruction is MID opcode we will detect this in command_completed + } + m_instruction->state++; + pulse_clock(pulse); +} + +/**************************************************************************/ +UINT32 tms9995_device::execute_min_cycles() const +{ + return 2; +} + +UINT32 tms9995_device::execute_max_cycles() const +{ + return 44; +} + +UINT32 tms9995_device::execute_input_lines() const +{ + return 2; +} + +UINT32 tms9995_device::disasm_min_opcode_bytes() const +{ + return 2; +} + +UINT32 tms9995_device::disasm_max_opcode_bytes() const +{ + return 6; +} + +offs_t tms9995_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( tms9995 ); + return CPU_DISASSEMBLE_NAME(tms9995)(this, buffer, pc, oprom, opram, options); +} + + +const device_type TMS9995 = &device_creator; +const device_type TMS9995_MP9537 = &device_creator; diff --git a/src/devices/cpu/tms9900/tms9995.h b/src/devices/cpu/tms9900/tms9995.h new file mode 100644 index 00000000000..81e2e560505 --- /dev/null +++ b/src/devices/cpu/tms9900/tms9995.h @@ -0,0 +1,446 @@ +// license:BSD-3-Clause +// copyright-holders:Michael Zapf +/* + tms9995.h + + See tms9995.c for documentation + Also see tms9900.h for types of TMS99xx processors. +*/ + +#ifndef __TMS9995_H__ +#define __TMS9995_H__ + +#include "emu.h" +#include "debugger.h" +#include "tms99com.h" + +// device type definition +extern const device_type TMS9995; +extern const device_type TMS9995_MP9537; + +enum +{ + INT_9995_RESET = 0, + INT_9995_INTREQ = 1, + INT_9995_INT1 = 2, + INT_9995_INT4 = 3 +}; + +#define MCFG_TMS9995_EXTOP_HANDLER( _extop) \ + devcb = &tms9995_device::static_set_extop_callback( *device, DEVCB_##_extop ); + +#define MCFG_TMS9995_IAQ_HANDLER( _iaq ) \ + devcb = &tms9995_device::static_set_iaq_callback( *device, DEVCB_##_iaq ); + +#define MCFG_TMS9995_CLKOUT_HANDLER( _clkout ) \ + devcb = &tms9995_device::static_set_clkout_callback( *device, DEVCB_##_clkout ); + +#define MCFG_TMS9995_HOLDA_HANDLER( _holda ) \ + devcb = &tms9995_device::static_set_holda_callback( *device, DEVCB_##_holda ); + +#define MCFG_TMS9995_DBIN_HANDLER( _dbin ) \ + devcb = &tms9995_device::static_set_dbin_callback( *device, DEVCB_##_dbin ); + +#define MCFG_TMS9995_ENABLE_OVINT( _ovint ) \ + downcast(device)->set_overflow_interrupt( _ovint ); + + +class tms9995_device : public cpu_device +{ +public: + tms9995_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + tms9995_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + // READY input line. When asserted (high), the memory is ready for data exchange. + // We chose to use a direct method instead of a delegate to keep performance + // footprint low; this method may be called very frequently. + void set_ready(int state); + + // HOLD input line. When asserted (low), the CPU is requested to release the + // data and address bus and enter the HOLD state. The entrance of this state + // is acknowledged by the HOLDA output line. + void set_hold(int state); + + // Callbacks + template static devcb_base &static_set_extop_callback(device_t &device, _Object object) { return downcast(device).m_external_operation.set_callback(object); } + template static devcb_base &static_set_iaq_callback(device_t &device, _Object object) { return downcast(device).m_iaq_line.set_callback(object); } + template static devcb_base &static_set_clkout_callback(device_t &device, _Object object) { return downcast(device).m_clock_out_line.set_callback(object); } + template static devcb_base &static_set_holda_callback(device_t &device, _Object object) { return downcast(device).m_holda_line.set_callback(object); } + template static devcb_base &static_set_dbin_callback(device_t &device, _Object object) { return downcast(device).m_dbin_line.set_callback(object); } + + // For debugger access + UINT8 debug_read_onchip_memory(offs_t addr) { return m_onchip_memory[addr & 0xff]; }; + bool is_onchip(offs_t addrb) { return (((addrb & 0xff00)==0xf000 && (addrb < 0xf0fc)) || ((addrb & 0xfffc)==0xfffc)) && !m_mp9537; } + + void set_overflow_interrupt( int enable ) { m_check_overflow = (enable!=0); } + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_stop(); + virtual void device_reset(); + + // device_execute_interface overrides + virtual UINT32 execute_min_cycles() const; + virtual UINT32 execute_max_cycles() const; + virtual UINT32 execute_input_lines() const; + virtual void execute_set_input(int irqline, int state); + virtual void execute_run(); + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const; + virtual UINT32 disasm_max_opcode_bytes() const; + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + + const address_space_config* memory_space_config(address_spacenum spacenum) const; + + UINT64 execute_clocks_to_cycles(UINT64 clocks) const { return clocks / 4.0; } + UINT64 execute_cycles_to_clocks(UINT64 cycles) const { return cycles * 4.0; } + + // Variant of the TMS9995 without internal RAM and decrementer + bool m_mp9537; + +private: + // State / debug management + UINT16 m_state_any; + static const char* s_statename[]; + void state_import(const device_state_entry &entry); + void state_export(const device_state_entry &entry); + void state_string_export(const device_state_entry &entry, std::string &str); + UINT16 read_workspace_register_debug(int reg); + void write_workspace_register_debug(int reg, UINT16 data); + + // TMS9995 hardware registers + UINT16 WP; // Workspace pointer + UINT16 PC; // Program counter + UINT16 ST; // Status register + + // The TMS9995 has a prefetch feature which causes a wrong display of the PC. + // We use this additional member for the debugger only. + UINT16 PC_debug; + + // 256 bytes of onchip memory + UINT8 m_onchip_memory[256]; + + const address_space_config m_program_config; + const address_space_config m_io_config; + address_space* m_prgspace; + address_space* m_cru; + + + // Processor states + bool m_idle_state; + bool m_nmi_state; + bool m_irq_state; + bool m_hold_state; + + // READY handling. The READY line is operated before the clock + // pulse falls. As the ready line is only set once in this emulation we + // keep the level in a buffer (like a latch) + bool m_ready_bufd; // buffered state + bool m_ready; // sampled value + + // Auto-wait state generation + bool m_request_auto_wait_state; + bool m_auto_wait; + + // Cycle counter + int m_icount; + + // Phase of the memory access + int m_mem_phase; + + // Check the READY line? + bool m_check_ready; + + // Check the HOLD line + bool m_check_hold; + + // For multi-pass operations. For instance, memory word accesses are + // executed as two consecutive byte accesses. CRU accesses are repeated + // single-bit accesses. + int m_pass; + + // For parity operations + int m_parity; + + // For Format 1 instruction; determines whether the next operand address + // derivation is for the source or address operand + bool m_get_destination; + + // Used for situations when a command is byte-oriented, but the memory access + // must be word-oriented. Example: MOVB *R1,R0; we must read the full word + // from R1 to get the address. + bool m_word_access; + + // Interrupt handling + bool m_nmi_active; + bool m_int1_active; + bool m_int4_active; + bool m_int_decrementer; + bool m_int_overflow; + + bool m_reset; + bool m_from_reset; + bool m_mid_flag; + bool m_mid_active; + + int m_decrementer_clkdiv; + bool m_servicing_interrupt; + + // Flag field + int m_int_pending; + + // The TMS9995 is capable of raising an internal interrupt on + // arithmetic overflow, depending on the status register Overflow Enable bit. + // However, the specs also say that this feature is non-functional in the + // currently available chip. Thus we have an option to turn it off so that + // software will not change its behavior on overflows. + bool m_check_overflow; + + // Service pending interrupts + void service_interrupt(); + + // Issue clock pulses. The TMS9995 uses one (output) clock cycle per machine cycle. + inline void pulse_clock(int count); + + // Signal the hold state via the external line + inline void set_hold_state(bool state); + + // Only used for the DIV(S) operations. It seems sufficient to let the + // command terminate at this point, so this method just calls command_terminated. + void abort_operation(void); + + // Decode the given 16-bit value which has been retrieved by a prefetch or + // during an X operation. + void decode(UINT16 inst); + + // Store the interrupt mask part of the ST. This is used when processing + // an interrupt, passing the new mask from the service_interrupt part to + // the program part. + int m_intmask; + + // Stored address + UINT16 m_address; + + // Stores the recently read word or the word to be written + UINT16 m_current_value; + + // Stores the value of the source operand in multi-operand instructions + UINT16 m_source_value; + + // During indexed addressing, this value is added to get the final address value. + UINT16 m_address_add; + + // During indirect/auto-increment addressing, this copy of the address must + // be preserved while writing the new value to the register. + UINT16 m_address_saved; + + // Another copy of the address + UINT16 m_address_copy; + + // Copy of the value + UINT16 m_value_copy; + + // Stores the recent register number. Only used to pass the register + // number during the operand address derivation. + int m_regnumber; + + // Stores the number of bits or shift operations + int m_count; + + // ============== Decrementer ======================= + void trigger_decrementer(); + + // Start value + UINT16 m_starting_count_storage_register; + + // Current decrementer value. + UINT16 m_decrementer_value; + + // ============== CRU support ====================== + + UINT16 m_cru_address; + UINT16 m_cru_value; + bool m_cru_first_read; + int m_cru_bits_left; + UINT32 m_cru_read; + + // CPU-internal CRU flags + bool m_flag[16]; + + // ============== Prefetch support ===================== + + struct decoded_instruction + { + UINT16 IR; + UINT16 command; + const UINT8* program; + bool byteop; + int state; + }; + + int m_instindex; + + // We implement the prefetch mechanism by two separate datasets for + // the decoded commands. When the previous command has completed, the + // pointer is just switched to the other one. + tms9995_device::decoded_instruction m_decoded[2]; + tms9995_device::decoded_instruction* m_instruction; + + // ================ Microprogram support ======================== + + // Set up lookup table + void build_command_lookup_table(); + + // Sequence of micro-operations + typedef const UINT8* microprogram; + + // Method pointer + typedef void (tms9995_device::*ophandler)(void); + + // Opcode list entry + struct tms_instruction + { + UINT16 opcode; + int id; + int format; + microprogram prog; // Microprogram + }; + + // Lookup table entry + struct lookup_entry + { + lookup_entry *next_digit; + const tms_instruction *entry; + }; + + // Pointer to the lookup table; the entry point for searching the command + lookup_entry* m_command_lookup_table; + + // List of allocated tables (used for easy clean-up on exit) + lookup_entry* m_lotables[32]; + + // List of pointers for micro-operations + static const tms9995_device::ophandler s_microoperation[]; + + static const tms9995_device::tms_instruction s_command[]; + + // Micro-operation program counter (as opposed to the program counter PC) + int MPC; + + // Calling microprogram (used when data derivation is called) + const UINT8* m_caller; + int m_caller_MPC; + + // Table of microprograms + static const microprogram mp_table[]; + + // Used to display the number of consumed cycles in the log. + int m_first_cycle; + + // Status register update + inline void set_status_bit(int bit, bool state); + inline void compare_and_set_lae(UINT16 value1, UINT16 value2); + void set_status_parity(UINT8 value); + + // Micro-operation declarations + void int_prefetch_and_decode(); + void prefetch_and_decode(); + void mem_read(); + void mem_write(); + inline void word_read(); + inline void word_write(); + void operand_address_subprogram(); + void increment_register(); + void indexed_addressing(); + void set_immediate(); + void return_with_address(); + void return_with_address_copy(); + void cru_input_operation(); + void cru_output_operation(); + void command_completed(); + void next_command(); + + // ALU operations for specific commands + void alu_nop(); + void alu_add_s_sxc(); + void alu_b(); + void alu_blwp(); + void alu_c(); + void alu_ci(); + void alu_clr_seto(); + void alu_divide(); + void alu_divide_signed(); + void alu_external(); + void alu_f3(); + void alu_imm_arithm(); + void alu_jump(); + void alu_ldcr(); + void alu_li(); + void alu_limi_lwpi(); + void alu_lst_lwp(); + void alu_mov(); + void alu_multiply(); + void alu_multiply_signed(); + void alu_rtwp(); + void alu_sbo_sbz(); + void alu_shift(); + void alu_single_arithm(); + void alu_stcr(); + void alu_stst_stwp(); + void alu_tb(); + void alu_x(); + void alu_xop(); + void alu_int(); + + // ================ Connections ==================== + + // Trigger external operation. This is achieved by putting a special value in + // the most significant three bits of the data bus and pulsing the CRUCLK line. + // Accordingly, we have + // + // D0 D1 D2 + // 0 0 0 normal CRU access + // 0 1 0 IDLE + // 0 1 1 RSET + // 1 0 1 CKON + // 1 1 0 CKOF + // 1 1 1 LREX + // + // We could realize this via the CRU access as well, but the data bus access + // is not that simple to emulate. For the sake of homogenity between the + // chip emulations we use a dedicated callback. + devcb_write8 m_external_operation; + + // Signal to the outside world that we are now getting an instruction (IAQ). + // In the real hardware this line is shared with the HOLDA line, and the + // /MEMEN line is used to decide which signal we have on the line. We do not + // emulate the /MEMEN line, so we have to use two separate lines. + devcb_write_line m_iaq_line; + + // Clock output. + devcb_write_line m_clock_out_line; + + // Asserted when the CPU is in a HOLD state + devcb_write_line m_holda_line; + + // DBIN line. When asserted (high), the CPU has disabled the data bus output buffers. + devcb_write_line m_dbin_line; +}; + + +/* + Variant of the TMS9995 without on-chip RAM; used in the TI-99/8 console +*/ +class tms9995_mp9537_device : public tms9995_device +{ +public: + tms9995_mp9537_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : tms9995_device(mconfig, TMS9995_MP9537, "TMS9995-MP9537", tag, owner, clock, "tms9995_mp9537", __FILE__) + { + m_mp9537 = true; + } +}; + +#endif /* __TMS9995_H__ */ diff --git a/src/devices/cpu/tms9900/tms99com.h b/src/devices/cpu/tms9900/tms99com.h new file mode 100644 index 00000000000..3a1aeeb57ee --- /dev/null +++ b/src/devices/cpu/tms9900/tms99com.h @@ -0,0 +1,93 @@ +// license:BSD-3-Clause +// copyright-holders:Michael Zapf +/* + Common definitions for all TMS processors + + Types of TMS99xx processors: + TI990/9 Early implementation, used in a few real-world applications, 1974 + very similar to mapper-less 990/10 and tms9900, but the Load + process is different + + TI990/10 Original multi-chip implementation for minicomputer systems, 1975 + + TI990/12 Multi-chip implementation, faster than 990/10. Huge instruction set + + TMS9900 Mono-chip implementation, 1976. Used in the TI-99/4(A) computer. + + TMS9940 Microcontroller with 2kb ROM, 128b RAM, decrementer, CRU bus, 1979 + + TMS9980 8-bit variant of tms9900. Two distinct chips actually : tms9980a + and tms9981 with an extra clock and simplified power supply + + TMS9985 9940 with 8kb ROM, 256b RAM, and a 8-bit external bus, c. 1978 (never released) + + TMS9989 Improved 9980, used in military hardware. + + SBP68689 Improved 9989, built as an ASIC as 9989 was running scarce + + TMS9995 TMS9985-like, with many improvements (but no ROM). Used in the + TI-99/8 prototype and the Geneve computer. + + TMS99000 Improved mono-chip implementation, meant to replace 990/10, 1981 + TMS99105 This chip is available in several variants which are similar + TMS99110 but emulate additional instructions, thanks to the so-called + macrostore feature. + + In this implementation we only consider TMS9900, 9980, and 9995. The + remaining types are implemented on an own code base as they introduce + significant changes (e.g. privileged mode, address mapper). +*/ + +#ifndef __TMS99COMMON_H__ +#define __TMS99COMMON_H__ + +#define MCFG_TMS99xx_ADD(_tag, _device, _clock, _prgmap, _iomap ) \ + MCFG_DEVICE_ADD(_tag, _device, _clock) \ + MCFG_DEVICE_PROGRAM_MAP(_prgmap) \ + MCFG_DEVICE_IO_MAP(_iomap) + +#define MCFG_TMS99xx_EXTOP_HANDLER( _extop) \ + devcb = &tms99xx_device::static_set_extop_callback( *device, DEVCB_##_extop ); + +#define MCFG_TMS99xx_INTLEVEL_HANDLER( _intlevel ) \ + devcb = &tms99xx_device::static_set_intlevel_callback( *device, DEVCB_##_intlevel ); + +#define MCFG_TMS99xx_IAQ_HANDLER( _iaq ) \ + devcb = &tms99xx_device::static_set_iaq_callback( *device, DEVCB_##_iaq ); + +#define MCFG_TMS99xx_CLKOUT_HANDLER( _clkout ) \ + devcb = &tms99xx_device::static_set_clkout_callback( *device, DEVCB_##_clkout ); + +#define MCFG_TMS99xx_WAIT_HANDLER( _wait ) \ + devcb = &tms99xx_device::static_set_wait_callback( *device, DEVCB_##_wait ); + +#define MCFG_TMS99xx_HOLDA_HANDLER( _holda ) \ + devcb = &tms99xx_device::static_set_holda_callback( *device, DEVCB_##_holda ); + +#define MCFG_TMS99xx_DBIN_HANDLER( _dbin ) \ + devcb = &tms99xx_device::static_set_dbin_callback( *device, DEVCB_##_dbin ); + +enum +{ + TI990_10_ID = 1, + TMS9900_ID = 3, + TMS9940_ID = 4, + TMS9980_ID = 5, + TMS9985_ID = 6, + TMS9989_ID = 7, + TMS9995_ID = 9, + TMS99000_ID = 10, + TMS99105A_ID = 11, + TMS99110A_ID = 12 +}; + +enum +{ + IDLE_OP = 2, + RSET_OP = 3, + CKOF_OP = 5, + CKON_OP = 6, + LREX_OP = 7 +}; + +#endif /* __TMS99COMMON_H__ */ diff --git a/src/devices/cpu/ucom4/ucom4.c b/src/devices/cpu/ucom4/ucom4.c new file mode 100644 index 00000000000..0c6bd280358 --- /dev/null +++ b/src/devices/cpu/ucom4/ucom4.c @@ -0,0 +1,484 @@ +// license:BSD-3-Clause +// copyright-holders:hap +/* + + NEC uCOM-4 MCU family cores + + References: + - 1981 NEC Microcomputers Catalog (later editions may have errors!) + - Supplement to uCOM-43 Single Chip Microcomputer Users' Manual + I've also looked at asterick's JavaScript D553 emulator for verification, with permission. + + TODO: + - what happens with uCOM-43 opcodes on an uCOM-44/45 MCU? + - what's the data after the ROM data for? (eg. 2000-2047, official ROM size is 2000) + - is DPh internally 3-bit or 4-bit? (currently assume 4-bit, it could have effect + on specific uCOM-43 exchange opcodes) + - RAM access from 0x50-0x7f on data_96x4 + - invalid port accesses via DPl + - documentation is conflicting if IRQ is level or edge triggered + +*/ + +#include "ucom4.h" +#include "debugger.h" + + +// uCOM-43 products: 2000x8 ROM, RAM size custom, supports full instruction set +const device_type NEC_D553 = &device_creator; // 42-pin PMOS, 35 pins for I/O, Open Drain output, 96x4 RAM +const device_type NEC_D557L = &device_creator; // 28-pin PMOS, 21 pins for I/O, Open Drain output, 96x4 RAM +const device_type NEC_D650 = &device_creator; // 42-pin CMOS, 35 pins for I/O, push-pull output, 96x4 RAM + +// uCOM-44 products: 1000x8 ROM, 64x4 RAM, does not support external interrupt +const device_type NEC_D552 = &device_creator; // 42-pin PMOS, 35 pins for I/O, Open Drain output + +// uCOM-45 products: ROM size custom, 32x4 RAM +//.. + + +// internal memory maps +static ADDRESS_MAP_START(program_1k, AS_PROGRAM, 8, ucom4_cpu_device) + AM_RANGE(0x0000, 0x03ff) AM_ROM +ADDRESS_MAP_END + +static ADDRESS_MAP_START(program_2k, AS_PROGRAM, 8, ucom4_cpu_device) + AM_RANGE(0x0000, 0x07ff) AM_ROM +ADDRESS_MAP_END + + +static ADDRESS_MAP_START(data_64x4, AS_DATA, 8, ucom4_cpu_device) + AM_RANGE(0x00, 0x3f) AM_RAM +ADDRESS_MAP_END + +static ADDRESS_MAP_START(data_96x4, AS_DATA, 8, ucom4_cpu_device) + AM_RANGE(0x00, 0x3f) AM_RAM + AM_RANGE(0x40, 0x4f) AM_RAM + AM_RANGE(0x70, 0x7f) AM_RAM +ADDRESS_MAP_END + + +// device definitions +upd553_cpu_device::upd553_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : ucom4_cpu_device(mconfig, NEC_D553, "uPD553", tag, owner, clock, NEC_UCOM43, 3 /* stack levels */, 11 /* prg width */, ADDRESS_MAP_NAME(program_2k), 7 /* data width */, ADDRESS_MAP_NAME(data_96x4), "upd553", __FILE__) +{ } + +upd557l_cpu_device::upd557l_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : ucom4_cpu_device(mconfig, NEC_D557L, "uPD557L", tag, owner, clock, NEC_UCOM43, 3, 11, ADDRESS_MAP_NAME(program_2k), 7, ADDRESS_MAP_NAME(data_96x4), "upd557l", __FILE__) +{ } + +upd650_cpu_device::upd650_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : ucom4_cpu_device(mconfig, NEC_D650, "uPD650", tag, owner, clock, NEC_UCOM43, 3, 11, ADDRESS_MAP_NAME(program_2k), 7, ADDRESS_MAP_NAME(data_96x4), "upd650", __FILE__) +{ } + +upd552_cpu_device::upd552_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : ucom4_cpu_device(mconfig, NEC_D552, "uPD552", tag, owner, clock, NEC_UCOM44, 1, 10, ADDRESS_MAP_NAME(program_1k), 6, ADDRESS_MAP_NAME(data_64x4), "upd552", __FILE__) +{ } + + +// disasm +void ucom4_cpu_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + switch (entry.index()) + { + // obviously not from a single flags register + case STATE_GENFLAGS: + strprintf(str, "%c%c%c%c%c", + m_inte_f ? 'E':'e', + m_int_f ? 'I':'i', + m_timer_f ? 'T':'t', + m_carry_s_f ? 'S':'s', + m_carry_f ? 'C':'c' + ); + break; + + default: break; + } +} + +offs_t ucom4_cpu_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE(ucom4); + return CPU_DISASSEMBLE_NAME(ucom4)(this, buffer, pc, oprom, opram, options); +} + + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +enum +{ + UCOM4_PC=1, UCOM4_DPL, UCOM4_DPH, + UCOM4_ACC +}; + +void ucom4_cpu_device::device_start() +{ + assert(NEC_UCOM4_PORTA == 0); + + m_program = &space(AS_PROGRAM); + m_data = &space(AS_DATA); + m_prgmask = (1 << m_prgwidth) - 1; + m_datamask = (1 << m_datawidth) - 1; + m_dph_mask = m_datamask >> 4; + + m_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(ucom4_cpu_device::simple_timer_cb), this)); + + // resolve callbacks + m_read_a.resolve_safe(0); + m_read_b.resolve_safe(0); + m_read_c.resolve_safe(0); + m_read_d.resolve_safe(0); + + m_write_c.resolve_safe(); + m_write_d.resolve_safe(); + m_write_e.resolve_safe(); + m_write_f.resolve_safe(); + m_write_g.resolve_safe(); + m_write_h.resolve_safe(); + m_write_i.resolve_safe(); + + // zerofill + memset(m_stack, 0, sizeof(m_stack)); + memset(m_port_out, 0, sizeof(m_port_out)); + m_op = 0; + m_prev_op = 0; + m_skip = false; + m_pc = 0; + m_prev_pc = 0; + m_acc = 0; + m_dpl = 0; + m_dph = 0; + m_carry_f = 0; + m_carry_s_f = 0; + m_timer_f = 0; + m_int_f = 0; + m_inte_f = 0; + m_int_line = CLEAR_LINE; + + // register for savestates + save_item(NAME(m_stack)); + save_item(NAME(m_port_out)); + save_item(NAME(m_op)); + save_item(NAME(m_prev_op)); + save_item(NAME(m_skip)); + save_item(NAME(m_pc)); + save_item(NAME(m_prev_pc)); + save_item(NAME(m_acc)); + save_item(NAME(m_dpl)); + save_item(NAME(m_dph)); + save_item(NAME(m_carry_f)); + save_item(NAME(m_carry_s_f)); + save_item(NAME(m_timer_f)); + save_item(NAME(m_int_f)); + save_item(NAME(m_int_line)); + + // register state for debugger + state_add(UCOM4_PC, "PC", m_pc).formatstr("%04X"); + state_add(UCOM4_DPL, "DPL", m_dpl).formatstr("%01X"); + state_add(UCOM4_DPH, "DPH", m_dph).formatstr("%01X"); + state_add(UCOM4_ACC, "ACC", m_acc).formatstr("%01X"); + + state_add(STATE_GENPC, "curpc", m_pc).formatstr("%04X").noshow(); + state_add(STATE_GENFLAGS, "GENFLAGS", m_carry_f).formatstr("%5s").noshow(); // dummy + + m_icountptr = &m_icount; +} + + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void ucom4_cpu_device::device_reset() +{ + m_pc = 0; + m_op = 0; + m_skip = false; + + m_timer->adjust(attotime::never); + + // clear interrupt + m_int_line = CLEAR_LINE; + m_int_f = 0; + m_inte_f = (m_family == NEC_UCOM43) ? 0 : 1; + + // clear i/o + for (int i = NEC_UCOM4_PORTC; i <= NEC_UCOM4_PORTI; i++) + output_w(i, 0xf); +} + + + +//------------------------------------------------- +// i/o handling +//------------------------------------------------- + +// default: +// A,B are inputs, C,D are input/output, E,F,G,H,I are output + +UINT8 ucom4_cpu_device::input_r(int index) +{ + index &= 0xf; + UINT8 inp = 0; + + switch (index) + { + case NEC_UCOM4_PORTA: inp = m_read_a(index, 0xff); break; + case NEC_UCOM4_PORTB: inp = m_read_b(index, 0xff); break; + case NEC_UCOM4_PORTC: inp = m_read_c(index, 0xff) | m_port_out[index]; break; + case NEC_UCOM4_PORTD: inp = m_read_d(index, 0xff) | m_port_out[index]; break; + + default: + logerror("%s read from unknown port %c at $%03X\n", tag(), 'A' + index, m_prev_pc); + break; + } + + return inp & 0xf; +} + +void ucom4_cpu_device::output_w(int index, UINT8 data) +{ + index &= 0xf; + data &= 0xf; + + switch (index) + { + case NEC_UCOM4_PORTC: m_write_c(index, data, 0xff); break; + case NEC_UCOM4_PORTD: m_write_d(index, data, 0xff); break; + case NEC_UCOM4_PORTE: m_write_e(index, data, 0xff); break; + case NEC_UCOM4_PORTF: m_write_f(index, data, 0xff); break; + case NEC_UCOM4_PORTG: m_write_g(index, data, 0xff); break; + case NEC_UCOM4_PORTH: m_write_h(index, data, 0xff); break; + case NEC_UCOM4_PORTI: m_write_i(index, data & 7, 0xff); break; + + default: + logerror("%s write to unknown port %c = $%X at $%03X\n", tag(), 'A' + index, data, m_prev_pc); + break; + } + + m_port_out[index] = data; +} + +// uPD557L: +// ports B,H,I are stripped, port G is reduced to 1 pin + +UINT8 upd557l_cpu_device::input_r(int index) +{ + index &= 0xf; + + if (index == NEC_UCOM4_PORTB) + logerror("%s read from unknown port %c at $%03X\n", tag(), 'A' + index, m_prev_pc); + else + return ucom4_cpu_device::input_r(index); + + return 0; +} + +void upd557l_cpu_device::output_w(int index, UINT8 data) +{ + index &= 0xf; + data &= 0xf; + + if (index == NEC_UCOM4_PORTH || index == NEC_UCOM4_PORTI) + logerror("%s write to unknown port %c = $%X at $%03X\n", tag(), 'A' + index, data, m_prev_pc); + else + { + // only G0 for port G + if (index == NEC_UCOM4_PORTG) + data &= 1; + + ucom4_cpu_device::output_w(index, data); + } +} + + + +//------------------------------------------------- +// interrupt +//------------------------------------------------- + +void ucom4_cpu_device::execute_set_input(int line, int state) +{ + switch (line) + { + case 0: + // edge triggered + if (m_int_line == CLEAR_LINE && state) + m_int_f = 1; + m_int_line = state; + + break; + + default: + break; + } +} + +void ucom4_cpu_device::do_interrupt() +{ + m_icount--; + push_stack(); + m_pc = 0xf << 2; + m_int_f = 0; + m_inte_f = (m_family == NEC_UCOM43) ? 0 : 1; + + standard_irq_callback(0); +} + + + +//------------------------------------------------- +// execute +//------------------------------------------------- + +inline void ucom4_cpu_device::increment_pc() +{ + // upper bits (field register) don't auto-increment + m_pc = (m_pc & ~0xff) | ((m_pc + 1) & 0xff); +} + +inline void ucom4_cpu_device::fetch_arg() +{ + // 2-byte opcodes: STM/LDI/CLI/CI, JMP/CAL, OCD + if ((m_op & 0xfc) == 0x14 || (m_op & 0xf0) == 0xa0 || m_op == 0x1e) + { + m_icount--; + m_arg = m_program->read_byte(m_pc); + increment_pc(); + } +} + +void ucom4_cpu_device::execute_run() +{ + while (m_icount > 0) + { + // handle interrupt, but not during LI($9x) or EI($31) or while skipping + if (m_int_f && m_inte_f && (m_op & 0xf0) != 0x90 && m_op != 0x31 && !m_skip) + { + do_interrupt(); + if (m_icount <= 0) + break; + } + + // remember previous state + m_prev_op = m_op; + m_prev_pc = m_pc; + + // fetch next opcode + debugger_instruction_hook(this, m_pc); + m_icount--; + m_op = m_program->read_byte(m_pc); + m_bitmask = 1 << (m_op & 0x03); + increment_pc(); + fetch_arg(); + + if (m_skip) + { + m_skip = false; + m_op = 0; // nop + } + + // handle opcode + switch (m_op & 0xf0) + { + case 0x80: op_ldz(); break; + case 0x90: op_li(); break; + case 0xa0: op_jmpcal(); break; + case 0xb0: op_czp(); break; + + case 0xc0: case 0xd0: case 0xe0: case 0xf0: op_jcp(); break; + + default: + switch (m_op) + { + case 0x00: op_nop(); break; + case 0x01: op_di(); break; + case 0x02: op_s(); break; + case 0x03: op_tit(); break; + case 0x04: op_tc(); break; + case 0x05: op_ttm(); break; + case 0x06: op_daa(); break; + case 0x07: op_tal(); break; + case 0x08: op_ad(); break; + case 0x09: op_ads(); break; + case 0x0a: op_das(); break; + case 0x0b: op_clc(); break; + case 0x0c: op_cm(); break; + case 0x0d: op_inc(); break; + case 0x0e: op_op(); break; + case 0x0f: op_dec(); break; + case 0x10: op_cma(); break; + case 0x11: op_cia(); break; + case 0x12: op_tla(); break; + case 0x13: op_ded(); break; + case 0x14: op_stm(); break; + case 0x15: op_ldi(); break; + case 0x16: op_cli(); break; + case 0x17: op_ci(); break; + case 0x18: op_exl(); break; + case 0x19: op_adc(); break; + case 0x1a: op_xc(); break; + case 0x1b: op_stc(); break; + case 0x1c: op_illegal(); break; + case 0x1d: op_inm(); break; + case 0x1e: op_ocd(); break; + case 0x1f: op_dem(); break; + + case 0x30: op_rar(); break; + case 0x31: op_ei(); break; + case 0x32: op_ip(); break; + case 0x33: op_ind(); break; + + case 0x40: op_ia(); break; + case 0x41: op_jpa(); break; + case 0x42: op_taz(); break; + case 0x43: op_taw(); break; + case 0x44: op_oe(); break; + case 0x45: op_illegal(); break; + case 0x46: op_tly(); break; + case 0x47: op_thx(); break; + case 0x48: op_rt(); break; + case 0x49: op_rts(); break; + case 0x4a: op_xaz(); break; + case 0x4b: op_xaw(); break; + case 0x4c: op_xls(); break; + case 0x4d: op_xhr(); break; + case 0x4e: op_xly(); break; + case 0x4f: op_xhx(); break; + + default: + switch (m_op & 0xfc) + { + case 0x20: op_fbf(); break; + case 0x24: op_tab(); break; + case 0x28: op_xm(); break; + case 0x2c: op_xmd(); break; + + case 0x34: op_cmb(); break; + case 0x38: op_lm(); break; + case 0x3c: op_xmi(); break; + + case 0x50: op_tpb(); break; + case 0x54: op_tpa(); break; + case 0x58: op_tmb(); break; + case 0x5c: op_fbt(); break; + case 0x60: op_rpb(); break; + case 0x64: op_reb(); break; + case 0x68: op_rmb(); break; + case 0x6c: op_rfb(); break; + case 0x70: op_spb(); break; + case 0x74: op_seb(); break; + case 0x78: op_smb(); break; + case 0x7c: op_sfb(); break; + } + break; // 0xfc + + } + break; // 0xff + + } // big switch + } +} diff --git a/src/devices/cpu/ucom4/ucom4.h b/src/devices/cpu/ucom4/ucom4.h new file mode 100644 index 00000000000..9b0651b6703 --- /dev/null +++ b/src/devices/cpu/ucom4/ucom4.h @@ -0,0 +1,354 @@ +// license:BSD-3-Clause +// copyright-holders:hap +/* + + NEC uCOM-4 MCU family cores + +*/ + +#ifndef _UCOM4_H_ +#define _UCOM4_H_ + +#include "emu.h" + + +// I/O ports setup +#define MCFG_UCOM4_READ_A_CB(_devcb) \ + ucom4_cpu_device::set_read_a_callback(*device, DEVCB_##_devcb); + +#define MCFG_UCOM4_READ_B_CB(_devcb) \ + ucom4_cpu_device::set_read_b_callback(*device, DEVCB_##_devcb); + +#define MCFG_UCOM4_READ_C_CB(_devcb) \ + ucom4_cpu_device::set_read_c_callback(*device, DEVCB_##_devcb); +#define MCFG_UCOM4_WRITE_C_CB(_devcb) \ + ucom4_cpu_device::set_write_c_callback(*device, DEVCB_##_devcb); + +#define MCFG_UCOM4_READ_D_CB(_devcb) \ + ucom4_cpu_device::set_read_d_callback(*device, DEVCB_##_devcb); +#define MCFG_UCOM4_WRITE_D_CB(_devcb) \ + ucom4_cpu_device::set_write_d_callback(*device, DEVCB_##_devcb); + +#define MCFG_UCOM4_WRITE_E_CB(_devcb) \ + ucom4_cpu_device::set_write_e_callback(*device, DEVCB_##_devcb); + +#define MCFG_UCOM4_WRITE_F_CB(_devcb) \ + ucom4_cpu_device::set_write_f_callback(*device, DEVCB_##_devcb); + +#define MCFG_UCOM4_WRITE_G_CB(_devcb) \ + ucom4_cpu_device::set_write_g_callback(*device, DEVCB_##_devcb); + +#define MCFG_UCOM4_WRITE_H_CB(_devcb) \ + ucom4_cpu_device::set_write_h_callback(*device, DEVCB_##_devcb); + +#define MCFG_UCOM4_WRITE_I_CB(_devcb) \ + ucom4_cpu_device::set_write_i_callback(*device, DEVCB_##_devcb); + +enum +{ + NEC_UCOM4_PORTA = 0, + NEC_UCOM4_PORTB, + NEC_UCOM4_PORTC, + NEC_UCOM4_PORTD, + NEC_UCOM4_PORTE, + NEC_UCOM4_PORTF, + NEC_UCOM4_PORTG, + NEC_UCOM4_PORTH, + NEC_UCOM4_PORTI +}; + +enum +{ + NEC_UCOM43 = 0, + NEC_UCOM44, + NEC_UCOM45 +}; + + +// pinout reference + +/* + _______ _______ + CL1 1 |* \_/ | 42 CL0 + PC0 2 | | 41 Vgg + PC1 3 | | 40 PB3 + PC2 4 | | 39 PB2 + PC3 5 | | 38 PB1 + /INT 6 | | 37 PB0 + RESET 7 | | 36 PA3 + PD0 8 | | 35 PA2 + PD1 9 | uPD552 | 34 PA1 + PD2 10 | uPD553 | 33 PA0 + PD3 11 | uPD650* | 32 PI2 + PE0 12 | | 31 PI1 + PE1 13 | | 30 PI0 + PE2 14 | | 29 PH3 + PE3 15 | | 28 PH2 + PF0 16 | | 27 PH1 + PF1 17 | | 26 PH0 + PF2 18 | | 25 PG3 + PF3 19 | | 24 PG2 + TEST 20 | | 23 PG1 + Vss 21 |_________________| 22 PG0 + + *: pin 21 is Vcc, pin 41 is Vss + +*/ + + +class ucom4_cpu_device : public cpu_device +{ +public: + // construction/destruction + ucom4_cpu_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, int family, int stack_levels, int prgwidth, address_map_constructor program, int datawidth, address_map_constructor data, const char *shortname, const char *source) + : cpu_device(mconfig, type, name, tag, owner, clock, shortname, source) + , m_program_config("program", ENDIANNESS_BIG, 8, prgwidth, 0, program) + , m_data_config("data", ENDIANNESS_BIG, 8, datawidth, 0, data) + , m_prgwidth(prgwidth) + , m_datawidth(datawidth) + , m_family(family) + , m_stack_levels(stack_levels) + , m_read_a(*this) + , m_read_b(*this) + , m_read_c(*this) + , m_read_d(*this) + , m_write_c(*this) + , m_write_d(*this) + , m_write_e(*this) + , m_write_f(*this) + , m_write_g(*this) + , m_write_h(*this) + , m_write_i(*this) + { } + + // static configuration helpers + template static devcb_base &set_read_a_callback(device_t &device, _Object object) { return downcast(device).m_read_a.set_callback(object); } + template static devcb_base &set_read_b_callback(device_t &device, _Object object) { return downcast(device).m_read_b.set_callback(object); } + template static devcb_base &set_read_c_callback(device_t &device, _Object object) { return downcast(device).m_read_c.set_callback(object); } + template static devcb_base &set_read_d_callback(device_t &device, _Object object) { return downcast(device).m_read_d.set_callback(object); } + + template static devcb_base &set_write_c_callback(device_t &device, _Object object) { return downcast(device).m_write_c.set_callback(object); } + template static devcb_base &set_write_d_callback(device_t &device, _Object object) { return downcast(device).m_write_d.set_callback(object); } + template static devcb_base &set_write_e_callback(device_t &device, _Object object) { return downcast(device).m_write_e.set_callback(object); } + template static devcb_base &set_write_f_callback(device_t &device, _Object object) { return downcast(device).m_write_f.set_callback(object); } + template static devcb_base &set_write_g_callback(device_t &device, _Object object) { return downcast(device).m_write_g.set_callback(object); } + template static devcb_base &set_write_h_callback(device_t &device, _Object object) { return downcast(device).m_write_h.set_callback(object); } + template static devcb_base &set_write_i_callback(device_t &device, _Object object) { return downcast(device).m_write_i.set_callback(object); } + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_execute_interface overrides + virtual UINT64 execute_clocks_to_cycles(UINT64 clocks) const { return (clocks + 4 - 1) / 4; } // 4 cycles per machine cycle + virtual UINT64 execute_cycles_to_clocks(UINT64 cycles) const { return (cycles * 4); } // " + virtual UINT32 execute_min_cycles() const { return 1; } + virtual UINT32 execute_max_cycles() const { return 2; } + virtual UINT32 execute_input_lines() const { return 1; } + virtual void execute_set_input(int line, int state); + virtual void execute_run(); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const { return(spacenum == AS_PROGRAM) ? &m_program_config : ((spacenum == AS_DATA) ? &m_data_config : NULL); } + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const { return 1; } + virtual UINT32 disasm_max_opcode_bytes() const { return 2; } + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + + void state_string_export(const device_state_entry &entry, std::string &str); + + address_space_config m_program_config; + address_space_config m_data_config; + address_space *m_program; + address_space *m_data; + + int m_prgwidth; + int m_datawidth; + int m_prgmask; + int m_datamask; + int m_family; // MCU family (43/44/45) + int m_stack_levels; // number of callstack levels + UINT16 m_stack[3]; // max 3 + UINT8 m_port_out[0x10]; // last value written to output port + UINT8 m_op; + UINT8 m_prev_op; // previous opcode + UINT8 m_arg; // opcode argument for 2-byte opcodes + UINT8 m_bitmask; // opcode bit argument + bool m_skip; // skip next opcode + int m_icount; + emu_timer *m_timer; + + UINT16 m_pc; // program counter + UINT16 m_prev_pc; + UINT8 m_acc; // 4-bit accumulator + UINT8 m_dpl; // 4-bit data pointer low (RAM x) + UINT8 m_dph; // 4-bit(?) data pointer high (RAM y) + UINT8 m_dph_mask; + UINT8 m_carry_f; // carry flag + UINT8 m_carry_s_f; // carry save flag + UINT8 m_timer_f; // timer out flag + UINT8 m_int_f; // interrupt flag + UINT8 m_inte_f; // interrupt enable flag + int m_int_line; // interrupt pin state + + // i/o handlers + devcb_read8 m_read_a; + devcb_read8 m_read_b; + devcb_read8 m_read_c; + devcb_read8 m_read_d; + + devcb_write8 m_write_c; + devcb_write8 m_write_d; + devcb_write8 m_write_e; + devcb_write8 m_write_f; + devcb_write8 m_write_g; + devcb_write8 m_write_h; + devcb_write8 m_write_i; + + virtual UINT8 input_r(int index); + virtual void output_w(int index, UINT8 data); + + // misc internal helpers + void increment_pc(); + void fetch_arg(); + void do_interrupt(); + + UINT8 ram_r(); + void ram_w(UINT8 data); + void pop_stack(); + void push_stack(); + + bool check_op_43(); + TIMER_CALLBACK_MEMBER( simple_timer_cb ); + UINT8 ucom43_reg_r(int index); + void ucom43_reg_w(int index, UINT8 data); + + // opcode handlers + void op_illegal(); + + void op_li(); + void op_lm(); + void op_ldi(); + void op_ldz(); + void op_s(); + void op_tal(); + void op_tla(); + + void op_xm(); + void op_xmi(); + void op_xmd(); + void op_ad(); + void op_adc(); + void op_ads(); + void op_daa(); + void op_das(); + + void op_exl(); + void op_cma(); + void op_cia(); + void op_clc(); + void op_stc(); + void op_tc(); + void op_inc(); + void op_dec(); + void op_ind(); + void op_ded(); + + void op_rmb(); + void op_smb(); + void op_reb(); + void op_seb(); + void op_rpb(); + void op_spb(); + void op_jmpcal(); + void op_jcp(); + void op_jpa(); + void op_czp(); + void op_rt(); + void op_rts(); + + void op_ci(); + void op_cm(); + void op_cmb(); + void op_tab(); + void op_cli(); + void op_tmb(); + void op_tpa(); + void op_tpb(); + + void op_tit(); + void op_ia(); + void op_ip(); + void op_oe(); + void op_op(); + void op_ocd(); + void op_nop(); + + void op_taw(); + void op_taz(); + void op_thx(); + void op_tly(); + void op_xaw(); + void op_xaz(); + void op_xhr(); + void op_xhx(); + void op_xls(); + void op_xly(); + void op_xc(); + + void op_sfb(); + void op_rfb(); + void op_fbt(); + void op_fbf(); + void op_rar(); + void op_inm(); + void op_dem(); + void op_stm(); + void op_ttm(); + void op_ei(); + void op_di(); +}; + + +class upd553_cpu_device : public ucom4_cpu_device +{ +public: + upd553_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +class upd557l_cpu_device : public ucom4_cpu_device +{ +public: + upd557l_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual UINT8 input_r(int index); + virtual void output_w(int index, UINT8 data); +}; + + +class upd650_cpu_device : public ucom4_cpu_device +{ +public: + upd650_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +class upd552_cpu_device : public ucom4_cpu_device +{ +public: + upd552_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + + +extern const device_type NEC_D553; +extern const device_type NEC_D557L; +extern const device_type NEC_D650; +extern const device_type NEC_D552; + + +#endif /* _UCOM4_H_ */ diff --git a/src/devices/cpu/ucom4/ucom4d.c b/src/devices/cpu/ucom4/ucom4d.c new file mode 100644 index 00000000000..14adfefbc79 --- /dev/null +++ b/src/devices/cpu/ucom4/ucom4d.c @@ -0,0 +1,153 @@ +// license:BSD-3-Clause +// copyright-holders:hap +/* + + NEC uCOM-4 MCU family disassembler + +*/ + +#include "emu.h" +#include "debugger.h" +#include "ucom4.h" + + +enum e_mnemonics +{ + mLI, mL, mLM, mLDI, mLDZ, mS, mTAL, mTLA, + mX, mXI, mXD, mXM, mXMI, mXMD, mAD, mADC, mADS, mDAA, mDAS, + mEXL, mCLA, mCMA, mCIA, mCLC, mSTC, mTC, mINC, mDEC, mIND, mDED, + mRMB, mSMB, mREB, mSEB, mRPB, mSPB, mJMP, mJCP, mJPA, mCAL, mCZP, mRT, mRTS, + mCI, mCM, mCMB, mTAB, mCLI, mTMB, mTPA, mTPB, + mTIT, mIA, mIP, mOE, mOP, mOCD, mNOP, + mILL, + mTAW, mTAZ, mTHX, mTLY, mXAW, mXAZ, mXHR, mXHX, mXLS, mXLY, mXC, + mSFB, mRFB, mFBT, mFBF, mRAR, mINM, mDEM, mSTM, mTTM, mEI, mDI +}; + +static const char *const s_mnemonics[] = +{ + "LI", "L", "LM", "LDI", "LDZ", "S", "TAL", "TLA", + "X", "XI", "XD", "XM", "XMI", "XMD", "AD", "ADC", "ADS", "DAA", "DAS", + "EXL", "CLA", "CMA", "CIA", "CLC", "STC", "TC", "INC", "DEC", "IND", "DED", + "RMB", "SMB", "REB", "SEB", "RPB", "SPB", "JMP", "JCP", "JPA", "CAL", "CZP", "RT", "RTS", + "CI", "CM", "CMB", "TAB", "CLI", "TMB", "TPA", "TPB", + "TIT", "IA", "IP", "OE", "OP", "OCD", "NOP", + "?", + "TAW", "TAZ", "THX", "TLY", "XAW", "XAZ", "XHR", "XHX", "XLS", "XLY", "XC", + "SFB", "RFB", "FBT", "FBF", "RAR", "INM", "DEM", "STM", "TTM", "EI", "DI" +}; + +// number of bits per opcode parameter, 2 digits means opcode is 2 bytes +static const UINT8 s_bits[] = +{ + 4, 0, 2, 80, 4, 0, 0, 0, + 0, 0, 0, 2, 2, 2, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 2, 2, 2, 2, 2, 2, 83, 6, 0, 83, 4, 0, 0, + 40, 0, 2, 2, 40, 2, 2, 2, + 0, 0, 0, 0, 0, 80, 0, + 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 2, 2, 2, 2, 0, 0, 0, 80, 0, 0, 0 +}; + +#define _OVER DASMFLAG_STEP_OVER +#define _OUT DASMFLAG_STEP_OUT + +static const UINT32 s_flags[] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, _OVER, _OVER, _OUT, _OUT, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + + +static const UINT8 ucom4_mnemonic[0x100] = +{ + /* 0x00 */ + mNOP, mDI, mS, mTIT, mTC, mTTM, mDAA, mTAL, + mAD, mADS, mDAS, mCLC, mCM, mINC, mOP, mDEC, + mCMA, mCIA, mTLA, mDED, mSTM, mLDI, mCLI, mCI, + mEXL, mADC, mXC, mSTC, mILL, mINM, mOCD, mDEM, + /* 0x20 */ + mFBF, mFBF, mFBF, mFBF, mTAB, mTAB, mTAB, mTAB, + mX, mXM, mXM, mXM, mXD, mXMD, mXMD, mXMD, + mRAR, mEI, mIP, mIND, mCMB, mCMB, mCMB, mCMB, + mL, mLM, mLM, mLM, mXI, mXMI, mXMI, mXMI, + /* 0x40 */ + mIA, mJPA, mTAZ, mTAW, mOE, mILL, mTLY, mTHX, + mRT, mRTS, mXAZ, mXAW, mXLS, mXHR, mXLY, mXHX, + mTPB, mTPB, mTPB, mTPB, mTPA, mTPA, mTPA, mTPA, + mTMB, mTMB, mTMB, mTMB, mFBT, mFBT, mFBT, mFBT, + /* 0x60 */ + mRPB, mRPB, mRPB, mRPB, mREB, mREB, mREB, mREB, + mRMB, mRMB, mRMB, mRMB, mRFB, mRFB, mRFB, mRFB, + mSPB, mSPB, mSPB, mSPB, mSEB, mSEB, mSEB, mSEB, + mSMB, mSMB, mSMB, mSMB, mSFB, mSFB, mSFB, mSFB, + /* 0x80 */ + mLDZ, mLDZ, mLDZ, mLDZ, mLDZ, mLDZ, mLDZ, mLDZ, + mLDZ, mLDZ, mLDZ, mLDZ, mLDZ, mLDZ, mLDZ, mLDZ, + mCLA, mLI, mLI, mLI, mLI, mLI, mLI, mLI, + mLI, mLI, mLI, mLI, mLI, mLI, mLI, mLI, + /* 0xa0 */ + mJMP, mJMP, mJMP, mJMP, mJMP, mJMP, mJMP, mJMP, + mCAL, mCAL, mCAL, mCAL, mCAL, mCAL, mCAL, mCAL, + mCZP, mCZP, mCZP, mCZP, mCZP, mCZP, mCZP, mCZP, + mCZP, mCZP, mCZP, mCZP, mCZP, mCZP, mCZP, mCZP, + /* 0xc0 */ + mJCP, mJCP, mJCP, mJCP, mJCP, mJCP, mJCP, mJCP, + mJCP, mJCP, mJCP, mJCP, mJCP, mJCP, mJCP, mJCP, + mJCP, mJCP, mJCP, mJCP, mJCP, mJCP, mJCP, mJCP, + mJCP, mJCP, mJCP, mJCP, mJCP, mJCP, mJCP, mJCP, + mJCP, mJCP, mJCP, mJCP, mJCP, mJCP, mJCP, mJCP, + mJCP, mJCP, mJCP, mJCP, mJCP, mJCP, mJCP, mJCP, + mJCP, mJCP, mJCP, mJCP, mJCP, mJCP, mJCP, mJCP, + mJCP, mJCP, mJCP, mJCP, mJCP, mJCP, mJCP, mJCP +}; + + + +CPU_DISASSEMBLE(ucom4) +{ + int pos = 0; + UINT8 op = oprom[pos++]; + UINT8 instr = ucom4_mnemonic[op]; + + char *dst = buffer; + dst += sprintf(dst, "%-4s ", s_mnemonics[instr]); + + // opcode parameter + int bits = s_bits[instr]; + if (bits) + { + UINT16 param = op & ((1 << (bits % 10)) - 1); + if (bits / 10) + { + UINT8 op2 = oprom[pos++]; + param = (param << (bits / 10)) | (op2 & ((1 << (bits / 10)) - 1)); + bits = (bits % 10) + (bits / 10); + } + + // special case for CZP + if (instr == mCZP) + { + param <<= 2; + bits += 2; + } + + if (bits <= 4) + dst += sprintf(dst, "%d", param); + else if (bits <= 8) + dst += sprintf(dst, "$%02X", param); + else + dst += sprintf(dst, "$%03X", param); + } + + return pos | s_flags[instr] | DASMFLAG_SUPPORTED; +} diff --git a/src/devices/cpu/ucom4/ucom4op.c b/src/devices/cpu/ucom4/ucom4op.c new file mode 100644 index 00000000000..a9c5c0fe892 --- /dev/null +++ b/src/devices/cpu/ucom4/ucom4op.c @@ -0,0 +1,719 @@ +// license:BSD-3-Clause +// copyright-holders:hap + +// uCOM-4 opcode handlers + +#include "ucom4.h" + + +// internal helpers + +inline UINT8 ucom4_cpu_device::ram_r() +{ + UINT16 address = m_dph << 4 | m_dpl; + return m_data->read_byte(address & m_datamask) & 0xf; +} + +inline void ucom4_cpu_device::ram_w(UINT8 data) +{ + UINT16 address = m_dph << 4 | m_dpl; + m_data->write_byte(address & m_datamask, data & 0xf); +} + +void ucom4_cpu_device::pop_stack() +{ + m_pc = m_stack[0] & m_prgmask; + for (int i = 0; i < m_stack_levels-1; i++) + m_stack[i] = m_stack[i+1]; +} + +void ucom4_cpu_device::push_stack() +{ + for (int i = m_stack_levels-1; i >= 1; i--) + m_stack[i] = m_stack[i-1]; + m_stack[0] = m_pc; +} + + + +// basic instruction set + +void ucom4_cpu_device::op_illegal() +{ + logerror("%s unknown opcode $%02X at $%03X\n", tag(), m_op, m_prev_pc); +} + + +// Load + +void ucom4_cpu_device::op_li() +{ + // LI X: Load ACC with X + // note: only execute the first one in a sequence of LI + if ((m_prev_op & 0xf0) != (m_op & 0xf0)) + m_acc = m_op & 0x0f; +} + +void ucom4_cpu_device::op_lm() +{ + // LM X: Load ACC with RAM, xor DPh with X + m_acc = ram_r(); + m_dph ^= (m_op & 0x03); +} + +void ucom4_cpu_device::op_ldi() +{ + // LDI X: Load DP with X + m_dph = m_arg >> 4 & 0xf; + m_dpl = m_arg & 0x0f; +} + +void ucom4_cpu_device::op_ldz() +{ + // LDZ X: Load DPh with 0, Load DPl with X + m_dph = 0; + m_dpl = m_op & 0x0f; +} + + +// Store + +void ucom4_cpu_device::op_s() +{ + // S: Store ACC into RAM + ram_w(m_acc); +} + + +// Transfer + +void ucom4_cpu_device::op_tal() +{ + // TAL: Transfer ACC to DPl + m_dpl = m_acc; +} + +void ucom4_cpu_device::op_tla() +{ + // TLA: Transfer DPl to ACC + m_acc = m_dpl; +} + + +// Exchange + +void ucom4_cpu_device::op_xm() +{ + // XM X: Exchange ACC with RAM, xor DPh with X + UINT8 old_acc = m_acc; + m_acc = ram_r(); + ram_w(old_acc); + m_dph ^= (m_op & 0x03); +} + +void ucom4_cpu_device::op_xmi() +{ + // XMI X: Exchange ACC with RAM, xor DPh with X, Increment DPl, skip next on carry + op_xm(); + m_dpl = (m_dpl + 1) & 0xf; + m_skip = (m_dpl == 0); +} + +void ucom4_cpu_device::op_xmd() +{ + // XMD X: Exchange ACC with RAM, xor DPh with X, Decrement DPl, skip next on carry + op_xm(); + m_dpl = (m_dpl - 1) & 0xf; + m_skip = (m_dpl == 0xf); +} + + +// Arithmetic + +void ucom4_cpu_device::op_ad() +{ + // AD: Add RAM to ACC, skip next on carry + m_acc += ram_r(); + m_skip = ((m_acc & 0x10) != 0); + m_acc &= 0xf; +} + +void ucom4_cpu_device::op_adc() +{ + // ADC: Add RAM and carry to ACC, store Carry F/F + m_acc += ram_r() + m_carry_f; + m_carry_f = m_acc >> 4 & 1; + m_acc &= 0xf; +} + +void ucom4_cpu_device::op_ads() +{ + // ADS: Add RAM and carry to ACC, store Carry F/F, skip next on carry + op_adc(); + m_skip = (m_carry_f != 0); +} + +void ucom4_cpu_device::op_daa() +{ + // DAA: Add 6 to ACC to adjust decimal for BCD Addition + m_acc = (m_acc + 6) & 0xf; +} + +void ucom4_cpu_device::op_das() +{ + // DAS: Add 10 to ACC to adjust decimal for BCD Subtraction + m_acc = (m_acc + 10) & 0xf; +} + + +// Logical + +void ucom4_cpu_device::op_exl() +{ + // EXL: Xor ACC with RAM + m_acc ^= ram_r(); +} + + +// Accumulator + +void ucom4_cpu_device::op_cma() +{ + // CMA: Complement ACC + m_acc ^= 0xf; +} + +void ucom4_cpu_device::op_cia() +{ + // CIA: Complement ACC, Increment ACC + m_acc = ((m_acc ^ 0xf) + 1) & 0xf; +} + + +// Carry Flag + +void ucom4_cpu_device::op_clc() +{ + // CLC: Reset Carry F/F + m_carry_f = 0; +} + +void ucom4_cpu_device::op_stc() +{ + // STC: Set Carry F/F + m_carry_f = 1; +} + +void ucom4_cpu_device::op_tc() +{ + // TC: skip next on Carry F/F + m_skip = (m_carry_f != 0); +} + + +// Increment and Decrement + +void ucom4_cpu_device::op_inc() +{ + // INC: Increment ACC, skip next on carry + m_acc = (m_acc + 1) & 0xf; + m_skip = (m_acc == 0); +} + +void ucom4_cpu_device::op_dec() +{ + // DEC: Decrement ACC, skip next on carry + m_acc = (m_acc - 1) & 0xf; + m_skip = (m_acc == 0xf); +} + +void ucom4_cpu_device::op_ind() +{ + // IND: Increment DPl, skip next on carry + m_dpl = (m_dpl + 1) & 0xf; + m_skip = (m_dpl == 0); +} + +void ucom4_cpu_device::op_ded() +{ + // DED: Decrement DPl, skip next on carry + m_dpl = (m_dpl - 1) & 0xf; + m_skip = (m_dpl == 0xf); +} + + +// Bit Manipulation + +void ucom4_cpu_device::op_rmb() +{ + // RMB B: Reset a single bit of RAM + ram_w(ram_r() & ~m_bitmask); +} + +void ucom4_cpu_device::op_smb() +{ + // SMB B: Set a single bit of RAM + ram_w(ram_r() | m_bitmask); +} + +void ucom4_cpu_device::op_reb() +{ + // REB B: Reset a single bit of output port E + m_icount--; + output_w(NEC_UCOM4_PORTE, m_port_out[NEC_UCOM4_PORTE] & ~m_bitmask); +} + +void ucom4_cpu_device::op_seb() +{ + // SEB B: Set a single bit of output port E + m_icount--; + output_w(NEC_UCOM4_PORTE, m_port_out[NEC_UCOM4_PORTE] | m_bitmask); +} + +void ucom4_cpu_device::op_rpb() +{ + // RPB B: Reset a single bit of output port (DPl) + output_w(m_dpl, m_port_out[m_dpl] & ~m_bitmask); +} + +void ucom4_cpu_device::op_spb() +{ + // SPB B: Set a single bit of output port (DPl) + output_w(m_dpl, m_port_out[m_dpl] | m_bitmask); +} + + +// Jump, Call and Return + +void ucom4_cpu_device::op_jmpcal() +{ + // JMP A: Jump to Address / CAL A: Call Address + if (m_op & 0x08) + push_stack(); + m_pc = ((m_op & 0x07) << 8 | m_arg) & m_prgmask; +} + +void ucom4_cpu_device::op_jcp() +{ + // JCP A: Jump to Address in current page + m_pc = (m_pc & ~0x3f) | (m_op & 0x3f); +} + +void ucom4_cpu_device::op_jpa() +{ + // JPA: Jump to (ACC) in current page + m_icount--; + m_pc = (m_pc & ~0x3f) | (m_acc << 2); +} + +void ucom4_cpu_device::op_czp() +{ + // CZP A: Call Address (short) + push_stack(); + m_pc = (m_op & 0x0f) << 2; +} + +void ucom4_cpu_device::op_rt() +{ + // RT: Return from subroutine + m_icount--; + pop_stack(); +} + +void ucom4_cpu_device::op_rts() +{ + // RTS: Return from subroutine, skip next + op_rt(); + m_skip = true; +} + + +// Skip + +void ucom4_cpu_device::op_ci() +{ + // CI X: skip next on ACC equals X + m_skip = (m_acc == (m_arg & 0x0f)); + + if ((m_arg & 0xf0) != 0xc0) + logerror("%s CI opcode unexpected upper arg $%02X at $%03X\n", tag(), m_arg & 0xf0, m_prev_pc); +} + +void ucom4_cpu_device::op_cm() +{ + // CM: skip next on ACC equals RAM + m_skip = (m_acc == ram_r()); +} + +void ucom4_cpu_device::op_cmb() +{ + // CMB B: skip next on bit(ACC) equals bit(RAM) + m_skip = ((m_acc & m_bitmask) == (ram_r() & m_bitmask)); +} + +void ucom4_cpu_device::op_tab() +{ + // TAB B: skip next on bit(ACC) + m_skip = ((m_acc & m_bitmask) != 0); +} + +void ucom4_cpu_device::op_cli() +{ + // CLI X: skip next on DPl equals X + m_skip = (m_dpl == (m_arg & 0x0f)); + + if ((m_arg & 0xf0) != 0xe0) + logerror("%s CLI opcode unexpected upper arg $%02X at $%03X\n", tag(), m_arg & 0xf0, m_prev_pc); +} + +void ucom4_cpu_device::op_tmb() +{ + // TMB B: skip next on bit(RAM) + m_skip = ((ram_r() & m_bitmask) != 0); +} + +void ucom4_cpu_device::op_tpa() +{ + // TPA B: skip next on bit(input port A) + m_skip = ((input_r(NEC_UCOM4_PORTA) & m_bitmask) != 0); +} + +void ucom4_cpu_device::op_tpb() +{ + // TPB B: skip next on bit(input port (DPl)) + m_skip = ((input_r(m_dpl) & m_bitmask) != 0); +} + + +// Interrupt + +void ucom4_cpu_device::op_tit() +{ + // TIT: skip next on Interrupt F/F, reset Interrupt F/F + m_skip = (m_int_f != 0); + m_int_f = 0; +} + + +// Parallel I/O + +void ucom4_cpu_device::op_ia() +{ + // IA: Input port A to ACC + m_icount--; + m_acc = input_r(NEC_UCOM4_PORTA); +} + +void ucom4_cpu_device::op_ip() +{ + // IP: Input port (DPl) to ACC + m_acc = input_r(m_dpl); +} + +void ucom4_cpu_device::op_oe() +{ + // OE: Output ACC to port E + m_icount--; + output_w(NEC_UCOM4_PORTE, m_acc); +} + +void ucom4_cpu_device::op_op() +{ + // OP: Output ACC to port (DPl) + output_w(m_dpl, m_acc); +} + +void ucom4_cpu_device::op_ocd() +{ + // OCD X: Output X to ports C and D + output_w(NEC_UCOM4_PORTD, m_arg >> 4); + output_w(NEC_UCOM4_PORTC, m_arg & 0xf); +} + + +// CPU Control + +void ucom4_cpu_device::op_nop() +{ + // NOP: No Operation +} + + + +// uCOM-43 extended instructions + +inline bool ucom4_cpu_device::check_op_43() +{ + // these opcodes are officially only supported on uCOM-43 + if (m_family != NEC_UCOM43) + logerror("%s using uCOM-43 opcode $%02X at $%03X\n", tag(), m_op, m_prev_pc); + + return (m_family == NEC_UCOM43); +} + +TIMER_CALLBACK_MEMBER( ucom4_cpu_device::simple_timer_cb ) +{ + m_timer_f = 1; +} + +// extra registers reside in RAM +enum +{ + UCOM43_X = 0, + UCOM43_Y, + UCOM43_R, + UCOM43_S, + UCOM43_W, + UCOM43_Z, + UCOM43_F +}; + +inline UINT8 ucom4_cpu_device::ucom43_reg_r(int index) +{ + return m_data->read_byte(m_datamask - index) & 0xf; +} + +inline void ucom4_cpu_device::ucom43_reg_w(int index, UINT8 data) +{ + m_data->write_byte(m_datamask - index, data & 0xf); +} + + + +// Transfer + +void ucom4_cpu_device::op_taw() +{ + if (!check_op_43()) return; + + // TAW: Transfer ACC to W + m_icount--; + ucom43_reg_w(UCOM43_W, m_acc); +} + +void ucom4_cpu_device::op_taz() +{ + if (!check_op_43()) return; + + // TAZ: Transfer ACC to Z + m_icount--; + ucom43_reg_w(UCOM43_Z, m_acc); +} + +void ucom4_cpu_device::op_thx() +{ + if (!check_op_43()) return; + + // THX: Transfer DPh to X + m_icount--; + ucom43_reg_w(UCOM43_X, m_dph); +} + +void ucom4_cpu_device::op_tly() +{ + if (!check_op_43()) return; + + // TLY: Transfer DPl to Y + m_icount--; + ucom43_reg_w(UCOM43_Y, m_dpl); +} + + +// Exchange + +void ucom4_cpu_device::op_xaw() +{ + if (!check_op_43()) return; + + // XAW: Exchange ACC with W + m_icount--; + UINT8 old_acc = m_acc; + m_acc = ucom43_reg_r(UCOM43_W); + ucom43_reg_w(UCOM43_W, old_acc); +} + +void ucom4_cpu_device::op_xaz() +{ + if (!check_op_43()) return; + + // XAZ: Exchange ACC with Z + m_icount--; + UINT8 old_acc = m_acc; + m_acc = ucom43_reg_r(UCOM43_Z); + ucom43_reg_w(UCOM43_Z, old_acc); +} + +void ucom4_cpu_device::op_xhr() +{ + if (!check_op_43()) return; + + // XHR: Exchange DPh with R + m_icount--; + UINT8 old_dph = m_dph; + m_dph = ucom43_reg_r(UCOM43_R); + ucom43_reg_w(UCOM43_R, old_dph); +} + +void ucom4_cpu_device::op_xhx() +{ + if (!check_op_43()) return; + + // XHX: Exchange DPh with X + m_icount--; + UINT8 old_dph = m_dph; + m_dph = ucom43_reg_r(UCOM43_X); + ucom43_reg_w(UCOM43_X, old_dph); +} + +void ucom4_cpu_device::op_xls() +{ + if (!check_op_43()) return; + + // XLS: Exchange DPl with S + m_icount--; + UINT8 old_dpl = m_dpl; + m_dpl = ucom43_reg_r(UCOM43_S); + ucom43_reg_w(UCOM43_S, old_dpl); +} + +void ucom4_cpu_device::op_xly() +{ + if (!check_op_43()) return; + + // XLY: Exchange DPl with Y + m_icount--; + UINT8 old_dpl = m_dpl; + m_dpl = ucom43_reg_r(UCOM43_Y); + ucom43_reg_w(UCOM43_Y, old_dpl); +} + +void ucom4_cpu_device::op_xc() +{ + if (!check_op_43()) return; + + // XC: Exchange Carry F/F with Carry Save F/F + UINT8 c = m_carry_f; + m_carry_f = m_carry_s_f; + m_carry_s_f = c; +} + + +// Flag + +void ucom4_cpu_device::op_sfb() +{ + if (!check_op_43()) return; + + // SFB B: Set a single bit of FLAG + m_icount--; + ucom43_reg_w(UCOM43_F, ucom43_reg_r(UCOM43_F) | m_bitmask); +} + +void ucom4_cpu_device::op_rfb() +{ + if (!check_op_43()) return; + + // RFB B: Reset a single bit of FLAG + m_icount--; + ucom43_reg_w(UCOM43_F, ucom43_reg_r(UCOM43_F) & ~m_bitmask); +} + +void ucom4_cpu_device::op_fbt() +{ + if (!check_op_43()) return; + + // FBT B: skip next on bit(FLAG) + m_icount--; + m_skip = ((ucom43_reg_r(UCOM43_F) & m_bitmask) != 0); +} + +void ucom4_cpu_device::op_fbf() +{ + if (!check_op_43()) return; + + // FBF B: skip next on not bit(FLAG) + m_icount--; + m_skip = ((ucom43_reg_r(UCOM43_F) & m_bitmask) == 0); +} + + +// Accumulator + +void ucom4_cpu_device::op_rar() +{ + if (!check_op_43()) return; + + // RAR: Rotate ACC Right through Carry F/F + UINT8 c = m_acc & 1; + m_acc = m_acc >> 1 | m_carry_f << 3; + m_carry_f = c; +} + + +// Increment and Decrement + +void ucom4_cpu_device::op_inm() +{ + if (!check_op_43()) return; + + // INM: Increment RAM, skip next on carry + UINT8 val = (ram_r() + 1) & 0xf; + ram_w(val); + m_skip = (val == 0); +} + +void ucom4_cpu_device::op_dem() +{ + if (!check_op_43()) return; + + // DEM: Decrement RAM, skip next on carry + UINT8 val = (ram_r() - 1) & 0xf; + ram_w(val); + m_skip = (val == 0xf); +} + + +// Timer + +void ucom4_cpu_device::op_stm() +{ + if (!check_op_43()) return; + + // STM X: Reset Timer F/F, Start Timer with X + m_timer_f = 0; + + // on the default clockrate of 400kHz, the minimum time interval is + // 630usec and the maximum interval is 40320usec(630*64) + attotime base = attotime::from_ticks(4 * 63, unscaled_clock()); + m_timer->adjust(base * ((m_arg & 0x3f) + 1)); + + if ((m_arg & 0xc0) != 0x80) + logerror("%s STM opcode unexpected upper arg $%02X at $%03X\n", tag(), m_arg & 0xc0, m_prev_pc); +} + +void ucom4_cpu_device::op_ttm() +{ + if (!check_op_43()) return; + + // TTM: skip next on Timer F/F + m_skip = (m_timer_f != 0); +} + + +// Interrupt + +void ucom4_cpu_device::op_ei() +{ + if (!check_op_43()) return; + + // EI: Set Interrupt Enable F/F + m_inte_f = 1; +} + +void ucom4_cpu_device::op_di() +{ + if (!check_op_43()) return; + + // DI: Reset Interrupt Enable F/F + m_inte_f = 0; +} diff --git a/src/devices/cpu/uml.c b/src/devices/cpu/uml.c new file mode 100644 index 00000000000..f7b0584431f --- /dev/null +++ b/src/devices/cpu/uml.c @@ -0,0 +1,1029 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + uml.c + + Universal machine language definitions and classes. + +**************************************************************************** + + Future improvements/changes: + + * UML optimizer: + - constant folding + + * Write a back-end validator: + - checks all combinations of memory/register/immediate on all params + - checks behavior of all opcodes + + * Extend registers to 16? Depends on if PPC can use them + + * Support for FPU exceptions + + * New instructions? + - FCOPYI, ICOPYF + copy raw between float and integer registers + + - VALID opcode_desc,handle,param + checksum/compare code referenced by opcode_desc; if not + matching, generate exception with handle,param + + - RECALL handle + change code at caller to call handle in the future + +***************************************************************************/ + +#include "emu.h" +#include "drcuml.h" +#include "drcumlsh.h" + +using namespace uml; + + + +//************************************************************************** +// DEBUGGING +//************************************************************************** + +#define VALIDATE_BACKEND (0) +#define LOG_SIMPLIFICATIONS (0) + + + +//************************************************************************** +// CONSTANTS +//************************************************************************** + +// opcode validation condition/flag valid bitmasks +#define OPFLAGS_NONE 0x00 +#define OPFLAGS_C FLAG_C +#define OPFLAGS_SZ (FLAG_S | FLAG_Z) +#define OPFLAGS_SZC (FLAG_S | FLAG_Z | FLAG_C) +#define OPFLAGS_SZV (FLAG_S | FLAG_Z | FLAG_V) +#define OPFLAGS_SZVC (FLAG_S | FLAG_Z | FLAG_V | FLAG_C) +#define OPFLAGS_UZC (FLAG_U | FLAG_Z | FLAG_C) +#define OPFLAGS_ALL 0x1f +#define OPFLAGS_P1 0x81 +#define OPFLAGS_P2 0x82 +#define OPFLAGS_P3 0x83 +#define OPFLAGS_P4 0x84 + +// parameter input/output states +#define PIO_IN 0x01 +#define PIO_OUT 0x02 +#define PIO_INOUT (PIO_IN | PIO_OUT) + +// parameter sizes +#define PSIZE_4 SIZE_DWORD +#define PSIZE_8 SIZE_QWORD +#define PSIZE_OP 0x80 +#define PSIZE_P1 0x81 +#define PSIZE_P2 0x82 +#define PSIZE_P3 0x83 +#define PSIZE_P4 0x84 + +// basic parameter types +#define PTYPES_NONE 0 +#define PTYPES_IMM (1 << parameter::PTYPE_IMMEDIATE) +#define PTYPES_IREG (1 << parameter::PTYPE_INT_REGISTER) +#define PTYPES_FREG (1 << parameter::PTYPE_FLOAT_REGISTER) +#define PTYPES_VREG (1 << parameter::PTYPE_VECTOR_REGISTER) +#define PTYPES_MVAR (1 << parameter::PTYPE_MAPVAR) +#define PTYPES_MEM (1 << parameter::PTYPE_MEMORY) +#define PTYPES_SIZE (1 << parameter::PTYPE_SIZE) +#define PTYPES_SCSIZE (1 << parameter::PTYPE_SIZE_SCALE) +#define PTYPES_SPSIZE (1 << parameter::PTYPE_SIZE_SPACE) +#define PTYPES_HANDLE (1 << parameter::PTYPE_CODE_HANDLE) +#define PTYPES_LABEL (1 << parameter::PTYPE_CODE_LABEL) +#define PTYPES_CFUNC (1 << parameter::PTYPE_C_FUNCTION) +#define PTYPES_ROUND (1 << parameter::PTYPE_ROUNDING) +#define PTYPES_STR (1 << parameter::PTYPE_STRING) + +// special parameter types +#define PTYPES_PTR (PTYPES_MEM | 0x1000) +#define PTYPES_STATE (PTYPES_MEM | 0x2000) + +// combinations of types +#define PTYPES_IRM (PTYPES_IREG | PTYPES_MEM) +#define PTYPES_FRM (PTYPES_FREG | PTYPES_MEM) +#define PTYPES_IMV (PTYPES_IMM | PTYPES_MVAR) +#define PTYPES_IANY (PTYPES_IRM | PTYPES_IMV) +#define PTYPES_FANY (PTYPES_FRM) + + + +//************************************************************************** +// TABLES +//************************************************************************** + +// macro to simplify the table +#define PINFO(inout, size, types) { PIO_##inout, PSIZE_##size, PTYPES_##types } +#define OPINFO0(op,str,sizes,cond,iflag,oflag,mflag) { OP_##op, str, sizes, cond, OPFLAGS_##iflag, OPFLAGS_##oflag, OPFLAGS_##mflag, { { 0 } } }, +#define OPINFO1(op,str,sizes,cond,iflag,oflag,mflag,p0) { OP_##op, str, sizes, cond, OPFLAGS_##iflag, OPFLAGS_##oflag, OPFLAGS_##mflag, { p0 } }, +#define OPINFO2(op,str,sizes,cond,iflag,oflag,mflag,p0,p1) { OP_##op, str, sizes, cond, OPFLAGS_##iflag, OPFLAGS_##oflag, OPFLAGS_##mflag, { p0, p1 } }, +#define OPINFO3(op,str,sizes,cond,iflag,oflag,mflag,p0,p1,p2) { OP_##op, str, sizes, cond, OPFLAGS_##iflag, OPFLAGS_##oflag, OPFLAGS_##mflag, { p0, p1, p2 } }, +#define OPINFO4(op,str,sizes,cond,iflag,oflag,mflag,p0,p1,p2,p3) { OP_##op, str, sizes, cond, OPFLAGS_##iflag, OPFLAGS_##oflag, OPFLAGS_##mflag, { p0, p1, p2, p3 } }, + +// opcode validation table +const opcode_info instruction::s_opcode_info_table[OP_MAX] = +{ + OPINFO0(INVALID, "invalid", 4, false, NONE, NONE, NONE) + + // Compile-time opcodes + OPINFO1(HANDLE, "handle", 4, false, NONE, NONE, NONE, PINFO(IN, OP, HANDLE)) + OPINFO2(HASH, "hash", 4, false, NONE, NONE, NONE, PINFO(IN, OP, IMV), PINFO(IN, OP, IMV)) + OPINFO1(LABEL, "label", 4, false, NONE, NONE, NONE, PINFO(IN, OP, LABEL)) + OPINFO1(COMMENT, "comment", 4, false, NONE, NONE, NONE, PINFO(IN, OP, STR)) + OPINFO2(MAPVAR, "mapvar", 4, false, NONE, NONE, NONE, PINFO(OUT, OP, MVAR), PINFO(IN, OP, IMV)) + + // Control Flow Operations + OPINFO0(NOP, "nop", 4, false, NONE, NONE, NONE) + OPINFO1(DEBUG, "debug", 4, false, NONE, NONE, ALL, PINFO(IN, OP, IANY)) + OPINFO1(EXIT, "exit", 4, true, NONE, NONE, ALL, PINFO(IN, OP, IANY)) + OPINFO3(HASHJMP, "hashjmp", 4, false, NONE, NONE, ALL, PINFO(IN, OP, IANY), PINFO(IN, OP, IANY), PINFO(IN, OP, HANDLE)) + OPINFO1(JMP, "jmp", 4, true, NONE, NONE, NONE, PINFO(IN, OP, LABEL)) + OPINFO2(EXH, "exh", 4, true, NONE, NONE, ALL, PINFO(IN, OP, HANDLE), PINFO(IN, OP, IANY)) + OPINFO1(CALLH, "callh", 4, true, NONE, NONE, ALL, PINFO(IN, OP, HANDLE)) + OPINFO0(RET, "ret", 4, true, NONE, NONE, ALL) + OPINFO2(CALLC, "callc", 4, true, NONE, NONE, ALL, PINFO(IN, OP, CFUNC), PINFO(IN, OP, PTR)) + OPINFO2(RECOVER, "recover", 4, false, NONE, NONE, ALL, PINFO(OUT, OP, IRM), PINFO(IN, OP, MVAR)) + + // Internal Register Operations + OPINFO1(SETFMOD, "setfmod", 4, false, NONE, NONE, ALL, PINFO(IN, OP, IANY)) + OPINFO1(GETFMOD, "getfmod", 4, false, NONE, NONE, ALL, PINFO(OUT, OP, IRM)) + OPINFO1(GETEXP, "getexp", 4, false, NONE, NONE, ALL, PINFO(OUT, OP, IRM)) + OPINFO2(GETFLGS, "getflgs", 4, false, P2, NONE, ALL, PINFO(OUT, OP, IRM), PINFO(IN, OP, IMV)) + OPINFO1(SAVE, "save", 4, false, ALL, NONE, ALL, PINFO(OUT, OP, STATE)) + OPINFO1(RESTORE, "restore", 4, false, NONE, ALL, ALL, PINFO(IN, OP, STATE)) + + // Integer Operations + OPINFO4(LOAD, "!load", 4|8, false, NONE, NONE, ALL, PINFO(OUT, OP, IRM), PINFO(IN, OP, PTR), PINFO(IN, 4, IANY), PINFO(IN, OP, SCSIZE)) + OPINFO4(LOADS, "!loads", 4|8, false, NONE, NONE, ALL, PINFO(OUT, OP, IRM), PINFO(IN, OP, PTR), PINFO(IN, 4, IANY), PINFO(IN, OP, SCSIZE)) + OPINFO4(STORE, "!store", 4|8, false, NONE, NONE, ALL, PINFO(IN, OP, PTR), PINFO(IN, 4, IANY), PINFO(IN, OP, IANY), PINFO(IN, OP, SCSIZE)) + OPINFO3(READ, "!read", 4|8, false, NONE, NONE, ALL, PINFO(OUT, OP, IRM), PINFO(IN, 4, IANY), PINFO(IN, OP, SPSIZE)) + OPINFO4(READM, "!readm", 4|8, false, NONE, NONE, ALL, PINFO(OUT, OP, IRM), PINFO(IN, 4, IANY), PINFO(IN, OP, IANY), PINFO(IN, OP, SPSIZE)) + OPINFO3(WRITE, "!write", 4|8, false, NONE, NONE, ALL, PINFO(IN, 4, IANY), PINFO(IN, OP, IANY), PINFO(IN, OP, SPSIZE)) + OPINFO4(WRITEM, "!writem", 4|8, false, NONE, NONE, ALL, PINFO(IN, 4, IANY), PINFO(IN, OP, IANY), PINFO(IN, OP, IANY), PINFO(IN, OP, SPSIZE)) + OPINFO2(CARRY, "!carry", 4|8, false, NONE, C, ALL, PINFO(IN, OP, IANY), PINFO(IN, OP, IANY)) + OPINFO1(SET, "!set", 4|8, true, NONE, NONE, ALL, PINFO(OUT, OP, IRM)) + OPINFO2(MOV, "!mov", 4|8, true, NONE, NONE, NONE, PINFO(OUT, OP, IRM), PINFO(IN, OP, IANY)) + OPINFO3(SEXT, "!sext", 4|8, false, NONE, SZ, ALL, PINFO(OUT, OP, IRM), PINFO(IN, P3, IANY), PINFO(IN, OP, SIZE)) + OPINFO4(ROLAND, "!roland", 4|8, false, NONE, SZ, ALL, PINFO(OUT, OP, IRM), PINFO(IN, OP, IANY), PINFO(IN, OP, IANY), PINFO(IN, OP, IANY)) + OPINFO4(ROLINS, "!rolins", 4|8, false, NONE, SZ, ALL, PINFO(INOUT, OP, IRM), PINFO(IN, OP, IANY), PINFO(IN, OP, IANY), PINFO(IN, OP, IANY)) + OPINFO3(ADD, "!add", 4|8, false, NONE, SZVC, ALL, PINFO(OUT, OP, IRM), PINFO(IN, OP, IANY), PINFO(IN, OP, IANY)) + OPINFO3(ADDC, "!addc", 4|8, false, C, SZVC, ALL, PINFO(OUT, OP, IRM), PINFO(IN, OP, IANY), PINFO(IN, OP, IANY)) + OPINFO3(SUB, "!sub", 4|8, false, NONE, SZVC, ALL, PINFO(OUT, OP, IRM), PINFO(IN, OP, IANY), PINFO(IN, OP, IANY)) + OPINFO3(SUBB, "!subb", 4|8, false, C, SZVC, ALL, PINFO(OUT, OP, IRM), PINFO(IN, OP, IANY), PINFO(IN, OP, IANY)) + OPINFO2(CMP, "!cmp", 4|8, false, NONE, SZVC, ALL, PINFO(IN, OP, IANY), PINFO(IN, OP, IANY)) + OPINFO4(MULU, "!mulu", 4|8, false, NONE, SZV, ALL, PINFO(OUT, OP, IRM), PINFO(OUT, OP, IRM), PINFO(IN, OP, IANY), PINFO(IN, OP, IANY)) + OPINFO4(MULS, "!muls", 4|8, false, NONE, SZV, ALL, PINFO(OUT, OP, IRM), PINFO(OUT, OP, IRM), PINFO(IN, OP, IANY), PINFO(IN, OP, IANY)) + OPINFO4(DIVU, "!divu", 4|8, false, NONE, SZV, ALL, PINFO(OUT, OP, IRM), PINFO(OUT, OP, IRM), PINFO(IN, OP, IANY), PINFO(IN, OP, IANY)) + OPINFO4(DIVS, "!divs", 4|8, false, NONE, SZV, ALL, PINFO(OUT, OP, IRM), PINFO(OUT, OP, IRM), PINFO(IN, OP, IANY), PINFO(IN, OP, IANY)) + OPINFO3(AND, "!and", 4|8, false, NONE, SZ, ALL, PINFO(OUT, OP, IRM), PINFO(IN, OP, IANY), PINFO(IN, OP, IANY)) + OPINFO2(TEST, "!test", 4|8, false, NONE, SZ, ALL, PINFO(IN, OP, IANY), PINFO(IN, OP, IANY)) + OPINFO3(OR, "!or", 4|8, false, NONE, SZ, ALL, PINFO(OUT, OP, IRM), PINFO(IN, OP, IANY), PINFO(IN, OP, IANY)) + OPINFO3(XOR, "!xor", 4|8, false, NONE, SZ, ALL, PINFO(OUT, OP, IRM), PINFO(IN, OP, IANY), PINFO(IN, OP, IANY)) + OPINFO2(LZCNT, "!lzcnt", 4|8, false, NONE, SZ, ALL, PINFO(OUT, OP, IRM), PINFO(IN, OP, IANY)) + OPINFO2(BSWAP, "!bswap", 4|8, false, NONE, SZ, ALL, PINFO(OUT, OP, IRM), PINFO(IN, OP, IANY)) + OPINFO3(SHL, "!shl", 4|8, false, NONE, SZC, ALL, PINFO(OUT, OP, IRM), PINFO(IN, OP, IANY), PINFO(IN, OP, IANY)) + OPINFO3(SHR, "!shr", 4|8, false, NONE, SZC, ALL, PINFO(OUT, OP, IRM), PINFO(IN, OP, IANY), PINFO(IN, OP, IANY)) + OPINFO3(SAR, "!sar", 4|8, false, NONE, SZC, ALL, PINFO(OUT, OP, IRM), PINFO(IN, OP, IANY), PINFO(IN, OP, IANY)) + OPINFO3(ROL, "!rol", 4|8, false, NONE, SZC, ALL, PINFO(OUT, OP, IRM), PINFO(IN, OP, IANY), PINFO(IN, OP, IANY)) + OPINFO3(ROLC, "!rolc", 4|8, false, C, SZC, ALL, PINFO(OUT, OP, IRM), PINFO(IN, OP, IANY), PINFO(IN, OP, IANY)) + OPINFO3(ROR, "!ror", 4|8, false, NONE, SZC, ALL, PINFO(OUT, OP, IRM), PINFO(IN, OP, IANY), PINFO(IN, OP, IANY)) + OPINFO3(RORC, "!rorc", 4|8, false, C, SZC, ALL, PINFO(OUT, OP, IRM), PINFO(IN, OP, IANY), PINFO(IN, OP, IANY)) + + // Floating Point Operations + OPINFO3(FLOAD, "f#load", 4|8, false, NONE, NONE, ALL, PINFO(OUT, OP, FRM), PINFO(IN, OP, PTR), PINFO(IN, 4, IANY)) + OPINFO3(FSTORE, "f#store", 4|8, false, NONE, NONE, ALL, PINFO(IN, OP, PTR), PINFO(IN, 4, IANY), PINFO(IN, OP, FRM)) + OPINFO3(FREAD, "f#read", 4|8, false, NONE, NONE, ALL, PINFO(OUT, OP, FRM), PINFO(IN, 4, IANY), PINFO(IN, OP, SPSIZE)) + OPINFO3(FWRITE, "f#write", 4|8, false, NONE, NONE, ALL, PINFO(IN, 4, IANY), PINFO(IN, OP, FANY), PINFO(IN, OP, SPSIZE)) + OPINFO2(FMOV, "f#mov", 4|8, true, NONE, NONE, NONE, PINFO(OUT, OP, FRM), PINFO(IN, OP, FANY)) + OPINFO4(FTOINT, "f#toint", 4|8, false, NONE, NONE, ALL, PINFO(OUT, P3, IRM), PINFO(IN, OP, FANY), PINFO(IN, OP, SIZE), PINFO(IN, OP, ROUND)) + OPINFO3(FFRINT, "f#frint", 4|8, false, NONE, NONE, ALL, PINFO(OUT, OP, FRM), PINFO(IN, P3, IANY), PINFO(IN, OP, SIZE)) + OPINFO3(FFRFLT, "f#frflt", 4|8, false, NONE, NONE, ALL, PINFO(OUT, OP, FRM), PINFO(IN, P3, FANY), PINFO(IN, OP, SIZE)) + OPINFO2(FRNDS, "f#rnds", 8, false, NONE, NONE, ALL, PINFO(OUT, OP, FRM), PINFO(IN, P3, FANY)) + OPINFO3(FADD, "f#add", 4|8, false, NONE, NONE, ALL, PINFO(OUT, OP, FRM), PINFO(IN, OP, FANY), PINFO(IN, OP, FANY)) + OPINFO3(FSUB, "f#sub", 4|8, false, NONE, NONE, ALL, PINFO(OUT, OP, FRM), PINFO(IN, OP, FANY), PINFO(IN, OP, FANY)) + OPINFO2(FCMP, "f#cmp", 4|8, false, NONE, UZC, ALL, PINFO(IN, OP, FANY), PINFO(IN, OP, FANY)) + OPINFO3(FMUL, "f#mul", 4|8, false, NONE, NONE, ALL, PINFO(OUT, OP, FRM), PINFO(IN, OP, FANY), PINFO(IN, OP, FANY)) + OPINFO3(FDIV, "f#div", 4|8, false, NONE, NONE, ALL, PINFO(OUT, OP, FRM), PINFO(IN, OP, FANY), PINFO(IN, OP, FANY)) + OPINFO2(FNEG, "f#neg", 4|8, false, NONE, NONE, ALL, PINFO(OUT, OP, FRM), PINFO(IN, OP, FANY)) + OPINFO2(FABS, "f#abs", 4|8, false, NONE, NONE, ALL, PINFO(OUT, OP, FRM), PINFO(IN, OP, FANY)) + OPINFO2(FSQRT, "f#sqrt", 4|8, false, NONE, NONE, ALL, PINFO(OUT, OP, FRM), PINFO(IN, OP, FANY)) + OPINFO2(FRECIP, "f#recip", 4|8, false, NONE, NONE, ALL, PINFO(OUT, OP, FRM), PINFO(IN, OP, FANY)) + OPINFO2(FRSQRT, "f#rsqrt", 4|8, false, NONE, NONE, ALL, PINFO(OUT, OP, FRM), PINFO(IN, OP, FANY)) +}; + + + +//************************************************************************** +// INLINE FUNCTIONS +//************************************************************************** + +//------------------------------------------------- +// rol32 - perform a 32-bit left rotate +//------------------------------------------------- + +inline UINT32 rol32(UINT32 source, UINT8 count) +{ + count &= 31; + return (source << count) | (source >> (32 - count)); +} + + +//------------------------------------------------- +// rol64 - perform a 64-bit left rotate +//------------------------------------------------- + +inline UINT64 rol64(UINT64 source, UINT8 count) +{ + count &= 63; + return (source << count) | (source >> (64 - count)); +} + + + +//************************************************************************** +// UML CODE HANDLE +//************************************************************************** + +//------------------------------------------------- +// code_handle - constructor +//------------------------------------------------- + +uml::code_handle::code_handle(drcuml_state &drcuml, const char *name) + : m_code(reinterpret_cast(drcuml.cache().alloc_near(sizeof(drccodeptr)))), + m_string(name), + m_next(NULL), + m_drcuml(drcuml) +{ + if (m_code == NULL) + throw std::bad_alloc(); + *m_code = NULL; +} + + +//------------------------------------------------- +// set_codeptr - set a new code pointer +//------------------------------------------------- + +void uml::code_handle::set_codeptr(drccodeptr code) +{ + assert(*m_code == NULL); + assert_in_cache(m_drcuml.cache(), code); + *m_code = code; +} + + + +//************************************************************************** +// UML INSTRUCTION +//************************************************************************** + +//------------------------------------------------- +// instruction - constructor +//------------------------------------------------- + +uml::instruction::instruction() + : m_opcode(OP_INVALID), + m_condition(COND_ALWAYS), + m_flags(0), + m_size(4), + m_numparams(0) +{ +} + + +//------------------------------------------------- +// configure - configure an opcode with no +// parameters +//------------------------------------------------- + +void uml::instruction::configure(opcode_t op, UINT8 size, condition_t condition) +{ + // fill in the instruction + m_opcode = (opcode_t)(UINT8)op; + m_size = size; + m_condition = condition; + m_flags = 0; + m_numparams = 0; + + // validate + validate(); +} + + +//------------------------------------------------- +// configure - configure an opcode with 1 +// parameter +//------------------------------------------------- + +void uml::instruction::configure(opcode_t op, UINT8 size, parameter p0, condition_t condition) +{ + // fill in the instruction + m_opcode = (opcode_t)(UINT8)op; + m_size = size; + m_condition = condition; + m_flags = 0; + m_numparams = 1; + m_param[0] = p0; + + // validate + validate(); +} + + +//------------------------------------------------- +// configure - configure an opcode with 2 +// parameters +//------------------------------------------------- + +void uml::instruction::configure(opcode_t op, UINT8 size, parameter p0, parameter p1, condition_t condition) +{ + // fill in the instruction + m_opcode = (opcode_t)(UINT8)op; + m_size = size; + m_condition = condition; + m_flags = 0; + m_numparams = 2; + m_param[0] = p0; + m_param[1] = p1; + + // validate + validate(); +} + + +//------------------------------------------------- +// configure - configure an opcode with 3 +// parameters +//------------------------------------------------- + +void uml::instruction::configure(opcode_t op, UINT8 size, parameter p0, parameter p1, parameter p2, condition_t condition) +{ + // fill in the instruction + m_opcode = (opcode_t)(UINT8)op; + m_size = size; + m_condition = condition; + m_flags = 0; + m_numparams = 3; + m_param[0] = p0; + m_param[1] = p1; + m_param[2] = p2; + + // validate + validate(); +} + + +//------------------------------------------------- +// configure - configure an opcode with 4 +// parameters +//------------------------------------------------- + +void uml::instruction::configure(opcode_t op, UINT8 size, parameter p0, parameter p1, parameter p2, parameter p3, condition_t condition) +{ + // fill in the instruction + m_opcode = (opcode_t)(UINT8)op; + m_size = size; + m_condition = condition; + m_flags = 0; + m_numparams = 4; + m_param[0] = p0; + m_param[1] = p1; + m_param[2] = p2; + m_param[3] = p3; + + // validate + validate(); +} + + +//------------------------------------------------- +// simplify - simplify instructions that have +// immediate values we can evaluate at compile +// time +//------------------------------------------------- + +void uml::instruction::simplify() +{ + // can't simplify if flags are in play + if (m_flags != 0) + return; + + static const UINT64 instsizemask[] = { 0, 0, 0, 0, 0xffffffff, 0, 0, 0, U64(0xffffffffffffffff) }; + static const UINT64 paramsizemask[] = { 0xff, 0xffff, 0xffffffff, U64(0xffffffffffffffff) }; + + // loop until we've simplified all we can + opcode_t origop; + do + { + // switch off the opcode + origop = m_opcode; + switch (m_opcode) + { + // READM: convert to READ if the mask is wide open + case OP_READM: + if (m_param[2].is_immediate_value(paramsizemask[m_param[3].size()])) + { + m_opcode = OP_READ; + m_numparams = 2; + m_param[2] = m_param[3]; + } + break; + + // WRITEM: convert to WRITE if the mask is wide open + case OP_WRITEM: + if (m_param[2].is_immediate_value(paramsizemask[m_param[3].size()])) + { + m_opcode = OP_WRITE; + m_numparams = 2; + m_param[2] = m_param[3]; + } + break; + + // SET: convert to MOV if constant condition + case OP_SET: + if (m_condition == COND_ALWAYS) + convert_to_mov_immediate(1); + break; + + // MOV: convert to NOP if move-to-self + case OP_MOV: + if (m_param[0] == m_param[1]) + nop(); + break; + + // SEXT: convert immediates to MOV + case OP_SEXT: + if (m_param[1].is_immediate()) + switch (m_param[2].size()) + { + case SIZE_BYTE: convert_to_mov_immediate((INT8)m_param[1].immediate()); break; + case SIZE_WORD: convert_to_mov_immediate((INT16)m_param[1].immediate()); break; + case SIZE_DWORD: convert_to_mov_immediate((INT32)m_param[1].immediate()); break; + case SIZE_QWORD: convert_to_mov_immediate((INT64)m_param[1].immediate()); break; + case SIZE_DQWORD: fatalerror("Invalid SEXT target size\n"); + } + break; + + // ROLAND: convert to MOV if all immediate, or to ROL or AND if one is not needed, or to SHL/SHR if the mask is right + case OP_ROLAND: + if (m_param[1].is_immediate() && m_param[2].is_immediate() && m_param[3].is_immediate()) + { + assert(m_size == 4 || m_size == 8); + if (m_size == 4) + convert_to_mov_immediate(rol32(m_param[1].immediate(), m_param[2].immediate()) & m_param[3].immediate()); + else + convert_to_mov_immediate(rol64(m_param[1].immediate(), m_param[2].immediate()) & m_param[3].immediate()); + } + else if (m_param[2].is_immediate_value(0)) + { + m_opcode = OP_AND; + m_numparams = 3; + m_param[2] = m_param[3]; + } + else if (m_param[3].is_immediate_value(instsizemask[m_size])) + { + m_opcode = OP_ROL; + m_numparams = 3; + } + else if (m_param[2].is_immediate() && m_param[3].is_immediate_value((U64(0xffffffffffffffff) << m_param[2].immediate()) & instsizemask[m_size])) + { + m_opcode = OP_SHL; + m_numparams = 3; + } + else if (m_param[2].is_immediate() && m_param[3].is_immediate_value(instsizemask[m_size] >> (8 * m_size - m_param[2].immediate()))) + { + m_opcode = OP_SHR; + m_numparams = 3; + m_param[2] = 8 * m_size - m_param[2].immediate(); + } + break; + + // ROLINS: convert to ROLAND if the mask is full + case OP_ROLINS: + if (m_param[3].is_immediate_value(instsizemask[m_size])) + m_opcode = OP_ROLAND; + break; + + // ADD: convert to MOV if immediate, or if adding 0 + case OP_ADD: + if (m_param[1].is_immediate() && m_param[2].is_immediate()) + convert_to_mov_immediate(m_param[1].immediate() + m_param[2].immediate()); + else if (m_param[1].is_immediate_value(0)) + convert_to_mov_param(2); + else if (m_param[2].is_immediate_value(0)) + convert_to_mov_param(1); + break; + + // SUB: convert to MOV if immediate, or if subtracting 0 + case OP_SUB: + if (m_param[1].is_immediate() && m_param[2].is_immediate()) + convert_to_mov_immediate(m_param[1].immediate() - m_param[2].immediate()); + else if (m_param[2].is_immediate_value(0)) + convert_to_mov_param(1); + break; + + // CMP: no-op if no flags needed, compare i0 to i0 if the parameters are equal + case OP_CMP: + if (m_flags == 0) + nop(); + else if (m_param[0] == m_param[1]) + cmp(I0, I0); + break; + + // MULU: convert simple form to MOV if immediate, or if multiplying by 0 + case OP_MULU: + if (m_param[0] == m_param[1]) + { + if (m_param[2].is_immediate_value(0) || m_param[3].is_immediate_value(0)) + convert_to_mov_immediate(0); + else if (m_param[2].is_immediate() && m_param[3].is_immediate()) + { + if (m_size == 4) + convert_to_mov_immediate((UINT32)((UINT32)m_param[1].immediate() * (UINT32)m_param[2].immediate())); + else if (m_size == 8) + convert_to_mov_immediate((UINT64)((UINT64)m_param[1].immediate() * (UINT64)m_param[2].immediate())); + } + } + break; + + // MULS: convert simple form to MOV if immediate, or if multiplying by 0 + case OP_MULS: + if (m_param[0] == m_param[1]) + { + if (m_param[2].is_immediate_value(0) || m_param[3].is_immediate_value(0)) + convert_to_mov_immediate(0); + else if (m_param[2].is_immediate() && m_param[3].is_immediate()) + { + if (m_size == 4) + convert_to_mov_immediate((INT32)((INT32)m_param[1].immediate() * (INT32)m_param[2].immediate())); + else if (m_size == 8) + convert_to_mov_immediate((INT64)((INT64)m_param[1].immediate() * (INT64)m_param[2].immediate())); + } + } + break; + + // DIVU: convert simple form to MOV if immediate, or if dividing with 0 + case OP_DIVU: + if (m_param[0] == m_param[1] && !m_param[3].is_immediate_value(0)) + { + if (m_param[2].is_immediate_value(0)) + convert_to_mov_immediate(0); + else if (m_param[2].is_immediate() && m_param[3].is_immediate()) + { + if (m_size == 4) + convert_to_mov_immediate((UINT32)((UINT32)m_param[1].immediate() / (UINT32)m_param[2].immediate())); + else if (m_size == 8) + convert_to_mov_immediate((UINT64)((UINT64)m_param[1].immediate() / (UINT64)m_param[2].immediate())); + } + } + break; + + // DIVS: convert simple form to MOV if immediate, or if dividing with 0 + case OP_DIVS: + if (m_param[0] == m_param[1] && !m_param[3].is_immediate_value(0)) + { + if (m_param[2].is_immediate_value(0)) + convert_to_mov_immediate(0); + else if (m_param[2].is_immediate() && m_param[3].is_immediate()) + { + if (m_size == 4) + convert_to_mov_immediate((INT32)((INT32)m_param[1].immediate() / (INT32)m_param[2].immediate())); + else if (m_size == 8) + convert_to_mov_immediate((INT64)((INT64)m_param[1].immediate() / (INT64)m_param[2].immediate())); + } + } + break; + + // AND: convert to MOV if immediate, or if anding against 0 or 0xffffffff + case OP_AND: + if (m_param[1].is_immediate_value(0) || m_param[2].is_immediate_value(0)) + convert_to_mov_immediate(0); + else if (m_param[1].is_immediate() && m_param[2].is_immediate()) + convert_to_mov_immediate(m_param[1].immediate() & m_param[2].immediate()); + else if (m_param[1].is_immediate_value(instsizemask[m_size])) + convert_to_mov_param(2); + else if (m_param[2].is_immediate_value(instsizemask[m_size])) + convert_to_mov_param(1); + break; + + // TEST: no-op if no flags needed + case OP_TEST: + if (m_flags == 0) + nop(); + break; + + // OR: convert to MOV if immediate, or if oring against 0 or 0xffffffff + case OP_OR: + if (m_param[1].is_immediate_value(instsizemask[m_size]) || m_param[2].is_immediate_value(instsizemask[m_size])) + convert_to_mov_immediate(instsizemask[m_size]); + else if (m_param[1].is_immediate() && m_param[2].is_immediate()) + convert_to_mov_immediate(m_param[1].immediate() | m_param[2].immediate()); + else if (m_param[1].is_immediate_value(0)) + convert_to_mov_param(2); + else if (m_param[2].is_immediate_value(0)) + convert_to_mov_param(1); + break; + + // XOR: convert to MOV if immediate, or if xoring against 0 + case OP_XOR: + if (m_param[1].is_immediate() && m_param[2].is_immediate()) + convert_to_mov_immediate(m_param[1].immediate() ^ m_param[2].immediate()); + else if (m_param[1].is_immediate_value(0)) + convert_to_mov_param(2); + else if (m_param[2].is_immediate_value(0)) + convert_to_mov_param(1); + break; + + // LZCNT: convert to MOV if immediate + case OP_LZCNT: + if (m_param[1].is_immediate()) + { + if (m_size == 4) + convert_to_mov_immediate(count_leading_zeros(m_param[1].immediate())); + else if (m_size == 8) + { + if ((m_param[1].immediate() >> 32) == 0) + convert_to_mov_immediate(32 + count_leading_zeros(m_param[1].immediate())); + else + convert_to_mov_immediate(count_leading_zeros(m_param[1].immediate() >> 32)); + } + } + break; + + // BSWAP: convert to MOV if immediate + case OP_BSWAP: + if (m_param[1].is_immediate()) + { + if (m_size == 4) + convert_to_mov_immediate(FLIPENDIAN_INT32(m_param[1].immediate())); + else if (m_size == 8) + convert_to_mov_immediate(FLIPENDIAN_INT64(m_param[1].immediate())); + } + break; + + // SHL: convert to MOV if immediate or shifting by 0 + case OP_SHL: + if (m_param[1].is_immediate() && m_param[2].is_immediate()) + convert_to_mov_immediate(m_param[1].immediate() << m_param[2].immediate()); + else if (m_param[2].is_immediate_value(0)) + convert_to_mov_param(1); + break; + + // SHR: convert to MOV if immediate or shifting by 0 + case OP_SHR: + if (m_param[1].is_immediate() && m_param[2].is_immediate()) + { + if (m_size == 4) + convert_to_mov_immediate((UINT32)m_param[1].immediate() >> m_param[2].immediate()); + else if (m_size == 8) + convert_to_mov_immediate((UINT64)m_param[1].immediate() >> m_param[2].immediate()); + } + else if (m_param[2].is_immediate_value(0)) + convert_to_mov_param(1); + break; + + // SAR: convert to MOV if immediate or shifting by 0 + case OP_SAR: + if (m_param[1].is_immediate() && m_param[2].is_immediate()) + { + if (m_size == 4) + convert_to_mov_immediate((INT32)m_param[1].immediate() >> m_param[2].immediate()); + else if (m_size == 8) + convert_to_mov_immediate((INT64)m_param[1].immediate() >> m_param[2].immediate()); + } + else if (m_param[2].is_immediate_value(0)) + convert_to_mov_param(1); + break; + + // ROL: convert to NOP if immediate or rotating by 0 + case OP_ROL: + if (m_param[1].is_immediate() && m_param[2].is_immediate()) + { + if (m_size == 4) + convert_to_mov_immediate(rol32(m_param[1].immediate(), m_param[2].immediate())); + else if (m_size == 8) + convert_to_mov_immediate(rol64(m_param[1].immediate(), m_param[2].immediate())); + } + else if (m_param[2].is_immediate_value(0)) + convert_to_mov_param(1); + break; + + // ROR: convert to NOP if immediate or rotating by 0 + case OP_ROR: + if (m_param[1].is_immediate() && m_param[2].is_immediate()) + { + if (m_size == 4) + convert_to_mov_immediate(rol32(m_param[1].immediate(), 32 - m_param[2].immediate())); + else if (m_size == 8) + convert_to_mov_immediate(rol64(m_param[1].immediate(), 64 - m_param[2].immediate())); + } + else if (m_param[2].is_immediate_value(0)) + convert_to_mov_param(1); + break; + + // FMOV: convert to NOP if move-to-self + case OP_FMOV: + if (m_param[0] == m_param[1]) + nop(); + break; + + default: + break; + } + + /* + if (LOG_SIMPLIFICATIONS && memcmp(&orig, inst, sizeof(orig)) != 0) + { + std::string disasm1, disasm2; + orig.disasm(disasm1, block->drcuml); + inst->disasm(disasm2, block->drcuml); + osd_printf_debug("Simplified: %-50.50s -> %s\n", disasm1.c_str(), disasm2.c_str()); + } + */ + + // loop until we stop changing opcodes + } while (m_opcode != origop); +} + + +//------------------------------------------------- +// validate - verify that the instruction created +// meets all requirements +//------------------------------------------------- + +void uml::instruction::validate() +{ +#ifdef MAME_DEBUG + const opcode_info &opinfo = s_opcode_info_table[m_opcode]; + assert(opinfo.opcode == m_opcode); + + // validate raw information + assert(m_opcode != OP_INVALID && m_opcode < OP_MAX); + assert(m_size == 1 || m_size == 2 || m_size == 4 || m_size == 8); + + // validate against opcode limits + assert((opinfo.sizes & m_size) != 0); + assert(m_condition == COND_ALWAYS || opinfo.condition); + + // validate each parameter + for (int pnum = 0; pnum < m_numparams; pnum++) + { + // ensure the type is valid + const parameter ¶m = m_param[pnum]; + assert((opinfo.param[pnum].typemask >> param.type()) & 1); + } + + // make sure we aren't missing any parameters + if (m_numparams < ARRAY_LENGTH(opinfo.param)) + assert(opinfo.param[m_numparams].typemask == 0); +#endif +} + + +//------------------------------------------------- +// input_flags - return the effective input flags +// based on any conditions encoded in an +// instruction +//------------------------------------------------- + +UINT8 uml::instruction::input_flags() const +{ + static const UINT8 flags_for_condition[] = + { + FLAG_Z, // COND_Z + FLAG_Z, // COND_NZ + FLAG_S, // COND_S + FLAG_S, // COND_NS + FLAG_C, // COND_C + FLAG_C, // COND_NC + FLAG_V, // COND_V + FLAG_V, // COND_NV + FLAG_U, // COND_U + FLAG_U, // COND_NU + FLAG_C | FLAG_Z, // COND_A + FLAG_C | FLAG_Z, // COND_BE + FLAG_S | FLAG_V | FLAG_Z, // COND_G + FLAG_S | FLAG_V | FLAG_Z, // COND_LE + FLAG_S | FLAG_V, // COND_L + FLAG_S | FLAG_V // COND_GE + }; + + UINT8 flags = s_opcode_info_table[m_opcode].inflags; + if (flags & 0x80) + flags = m_param[flags - OPFLAGS_P1].immediate() & OPFLAGS_ALL; + if (m_condition != COND_ALWAYS) + flags |= flags_for_condition[m_condition & 0x0f]; + return flags; +} + + +//------------------------------------------------- +// output_flags - return the effective output +// flags based on any conditions encoded in an +// instruction +//------------------------------------------------- + +UINT8 uml::instruction::output_flags() const +{ + UINT8 flags = s_opcode_info_table[m_opcode].outflags; + if (flags & 0x80) + flags = m_param[flags - OPFLAGS_P1].immediate() & OPFLAGS_ALL; + return flags; +} + + +//------------------------------------------------- +// modified_flags - return the effective output +// flags based on any conditions encoded in an +// instruction +//------------------------------------------------- + +UINT8 uml::instruction::modified_flags() const +{ + return s_opcode_info_table[m_opcode].modflags; +} + + +//------------------------------------------------- +// disasm - disassemble an instruction to the +// given buffer +//------------------------------------------------- + +const char *uml::instruction::disasm(std::string &buffer, drcuml_state *drcuml) const +{ + static const char *const conditions[] = { "z", "nz", "s", "ns", "c", "nc", "v", "nv", "u", "nu", "a", "be", "g", "le", "l", "ge" }; + static const char *const pound_size[] = { "?", "?", "?", "?", "s", "?", "?", "?", "d" }; + static const char *const bang_size[] = { "?", "b", "h", "?", "", "?", "?", "?", "d" }; + static const char *const fmods[] = { "trunc", "round", "ceil", "floor", "default" }; + static const char *const spaces[] = { "program", "data", "io", "3", "4", "5", "6", "7" }; + static const char *const sizes[] = { "byte", "word", "dword", "qword" }; + + const opcode_info &opinfo = s_opcode_info_table[m_opcode]; + + assert(m_opcode != OP_INVALID && m_opcode < OP_MAX); + + // start with the raw mnemonic and substitute sizes + buffer.clear(); + for (const char *opsrc = opinfo.mnemonic; *opsrc != 0; opsrc++) + if (*opsrc == '!') + strcatprintf(buffer, "%s", bang_size[m_size]); + else if (*opsrc == '#') + strcatprintf(buffer, "%s", pound_size[m_size]); + else + buffer.push_back(*opsrc); + + // pad to 8 spaces + int pad = 8 - buffer.length(); + for (int ch = 0; ch < pad; ch++) + buffer.push_back(' '); + + // iterate through parameters + for (int pnum = 0; pnum < m_numparams; pnum++) + { + const parameter ¶m = m_param[pnum]; + + // start with a comma for all except the first parameter + if (pnum != 0) + buffer.push_back(','); + + // ouput based on type + switch (param.type()) + { + // immediates have several special cases + case parameter::PTYPE_IMMEDIATE: + { + // determine the size of the immediate + int size; + switch (opinfo.param[pnum].size) + { + case PSIZE_4: size = 4; break; + case PSIZE_8: size = 8; break; + case PSIZE_P1: size = 1 << m_param[0].size(); break; + case PSIZE_P2: size = 1 << m_param[1].size(); break; + case PSIZE_P3: size = 1 << m_param[2].size(); break; + case PSIZE_P4: size = 1 << m_param[3].size(); break; + default: + case PSIZE_OP: size = m_size; break; + } + + // truncate to size + UINT64 value = param.immediate(); + if (size == 1) value = (UINT8)value; + if (size == 2) value = (UINT16)value; + if (size == 4) value = (UINT32)value; + if ((UINT32)value == value) + strcatprintf(buffer, "$%X", (UINT32)value); + else + strcatprintf(buffer, "$%X%08X", (UINT32)(value >> 32), (UINT32)value); + } + break; + + // immediates have several special cases + case parameter::PTYPE_SIZE: + strcatprintf(buffer, "%s", sizes[param.size()]); + break; + + // size + address space immediate + case parameter::PTYPE_SIZE_SPACE: + strcatprintf(buffer, "%s_%s", spaces[param.space()], sizes[param.size()]); + break; + + // size + scale immediate + case parameter::PTYPE_SIZE_SCALE: + { + int scale = param.scale(); + int size = param.size(); + if (scale == size) + strcatprintf(buffer, "%s", sizes[size]); + else + strcatprintf(buffer, "%s_x%d", sizes[size], 1 << scale); + } + break; + + // fmod immediate + case parameter::PTYPE_ROUNDING: + strcatprintf(buffer, "%s", fmods[param.rounding()]); + break; + + // integer registers + case parameter::PTYPE_INT_REGISTER: + strcatprintf(buffer, "i%d", param.ireg() - REG_I0); + break; + + // floating point registers + case parameter::PTYPE_FLOAT_REGISTER: + strcatprintf(buffer, "f%d", param.freg() - REG_F0); + break; + + // map variables + case parameter::PTYPE_MAPVAR: + strcatprintf(buffer, "m%d", param.mapvar() - MAPVAR_M0); + break; + + // memory + case parameter::PTYPE_MEMORY: + { + const char *symbol; + UINT32 symoffset; + + // symbol + if (drcuml != NULL && (symbol = drcuml->symbol_find(param.memory(), &symoffset)) != NULL) + { + if (symoffset == 0) + strcatprintf(buffer, "[%s]", symbol); + else + strcatprintf(buffer, "[%s+$%X]", symbol, symoffset); + } + + // cache memory + else if (drcuml != NULL && drcuml->cache().contains_pointer(param.memory())) + strcatprintf(buffer, "[+$%X]", (UINT32)(FPTR)((drccodeptr)param.memory() - drcuml->cache().near())); + + // general memory + else + strcatprintf(buffer, "[[$%p]]", param.memory()); + break; + } + + // string pointer + case parameter::PTYPE_STRING: + strcatprintf(buffer, "%s", (const char *)(FPTR)param.string()); + break; + + // handle pointer + case parameter::PTYPE_CODE_HANDLE: + strcatprintf(buffer, "%s", param.handle().string()); + break; + + default: + strcatprintf(buffer, "???"); + break; + } + } + + // if there's a condition, append it + if (m_condition != COND_ALWAYS) + strcatprintf(buffer, ",%s", conditions[m_condition & 0x0f]); + + // if there are flags, append them + if (m_flags != 0) + { + buffer.push_back(','); + if (m_flags & FLAG_U) + buffer.push_back('U'); + if (m_flags & FLAG_S) + buffer.push_back('S'); + if (m_flags & FLAG_Z) + buffer.push_back('Z'); + if (m_flags & FLAG_V) + buffer.push_back('V'); + if (m_flags & FLAG_C) + buffer.push_back('C'); + } + return buffer.c_str(); +} diff --git a/src/devices/cpu/uml.h b/src/devices/cpu/uml.h new file mode 100644 index 00000000000..96960bd910e --- /dev/null +++ b/src/devices/cpu/uml.h @@ -0,0 +1,661 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + uml.h + + Universal machine language definitions and classes. + +***************************************************************************/ + +#pragma once + +#ifndef __UML_H__ +#define __UML_H__ + +#include "drccache.h" + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// opaque structure describing UML generation state +class drcuml_state; + +struct drcuml_machine_state; + + +// use a namespace to wrap all the UML instruction concepts so that +// we can keep names short +namespace uml +{ + // integer registers + const int REG_I0 = 0x400; + const int REG_I_COUNT = 10; + const int REG_I_END = REG_I0 + REG_I_COUNT; + + // floating point registers + const int REG_F0 = 0x800; + const int REG_F_COUNT = 10; + const int REG_F_END = REG_F0 + REG_F_COUNT; + + // vector registers + const int REG_V0 = 0xc00; + const int REG_V_COUNT = 10; + const int REG_V_END = REG_V0 + REG_V_COUNT; + + // map variables + const int MAPVAR_M0 = 0x1000; + const int MAPVAR_COUNT = 10; + const int MAPVAR_END = MAPVAR_M0 + MAPVAR_COUNT; + + // flag definitions + const UINT8 FLAG_C = 0x01; // carry flag + const UINT8 FLAG_V = 0x02; // overflow flag (defined for integer only) + const UINT8 FLAG_Z = 0x04; // zero flag + const UINT8 FLAG_S = 0x08; // sign flag (defined for integer only) + const UINT8 FLAG_U = 0x10; // unordered flag (defined for FP only) + + // testable conditions; note that these are defined such that (condition ^ 1) is + // always the opposite + enum condition_t + { + COND_ALWAYS = 0, + + COND_Z = 0x80, // requires Z + COND_NZ, // requires Z + COND_S, // requires S + COND_NS, // requires S + COND_C, // requires C + COND_NC, // requires C + COND_V, // requires V + COND_NV, // requires V + COND_U, // requires U + COND_NU, // requires U + COND_A, // requires CZ + COND_BE, // requires CZ + COND_G, // requires SVZ + COND_LE, // requires SVZ + COND_L, // requires SV + COND_GE, // requires SV + + COND_MAX, + + // basic condition code aliases + COND_E = COND_Z, + COND_NE = COND_NZ, + COND_B = COND_C, + COND_AE = COND_NC + }; + + // floating point rounding modes + enum float_rounding_mode + { + ROUND_TRUNC = 0, // truncate + ROUND_ROUND, // round + ROUND_CEIL, // round up + ROUND_FLOOR, // round down + ROUND_DEFAULT + }; + + // operand sizes + enum operand_size + { + SIZE_BYTE = 0, // 1-byte + SIZE_WORD, // 2-byte + SIZE_DWORD, // 4-byte + SIZE_QWORD, // 8-byte + SIZE_DQWORD, // 16-byte (vector) + SIZE_SHORT = SIZE_DWORD, // 4-byte (float) + SIZE_DOUBLE = SIZE_QWORD // 8-byte (float) + }; + + // memory scale factors + enum memory_scale + { + SCALE_x1 = 0, // index * 1 + SCALE_x2, // index * 2 + SCALE_x4, // index * 4 + SCALE_x8, // index * 8 + SCALE_DEFAULT + }; + + // spaces + enum memory_space + { + SPACE_PROGRAM = AS_PROGRAM, + SPACE_DATA = AS_DATA, + SPACE_IO = AS_IO + }; + + // opcodes + enum opcode_t + { + OP_INVALID, + + // compile-time opcodes + OP_HANDLE, // HANDLE handle + OP_HASH, // HASH mode,pc + OP_LABEL, // LABEL imm + OP_COMMENT, // COMMENT string + OP_MAPVAR, // MAPVAR mapvar,value + + // control flow operations + OP_NOP, // NOP + OP_DEBUG, // DEBUG pc + OP_EXIT, // EXIT src1[,c] + OP_HASHJMP, // HASHJMP mode,pc,handle + OP_JMP, // JMP imm[,c] + OP_EXH, // EXH handle,param[,c] + OP_CALLH, // CALLH handle[,c] + OP_RET, // RET [c] + OP_CALLC, // CALLC func,ptr[,c] + OP_RECOVER, // RECOVER dst,mapvar + + // internal register operations + OP_SETFMOD, // SETFMOD src + OP_GETFMOD, // GETFMOD dst + OP_GETEXP, // GETEXP dst + OP_GETFLGS, // GETFLGS dst[,f] + OP_SAVE, // SAVE mem + OP_RESTORE, // RESTORE mem + + // integer operations + OP_LOAD, // LOAD dst,base,index,size + OP_LOADS, // LOADS dst,base,index,size + OP_STORE, // STORE base,index,src,size + OP_READ, // READ dst,src1,space/size + OP_READM, // READM dst,src1,mask,space/size + OP_WRITE, // WRITE dst,src1,space/size + OP_WRITEM, // WRITEM dst,mask,src1,space/size + OP_CARRY, // CARRY src,bitnum + OP_SET, // SET dst,c + OP_MOV, // MOV dst,src[,c] + OP_SEXT, // SEXT dst,src,size + OP_ROLAND, // ROLAND dst,src,shift,mask + OP_ROLINS, // ROLINS dst,src,shift,mask + OP_ADD, // ADD dst,src1,src2[,f] + OP_ADDC, // ADDC dst,src1,src2[,f] + OP_SUB, // SUB dst,src1,src2[,f] + OP_SUBB, // SUBB dst,src1,src2[,f] + OP_CMP, // CMP src1,src2[,f] + OP_MULU, // MULU dst,edst,src1,src2[,f] + OP_MULS, // MULS dst,edst,src1,src2[,f] + OP_DIVU, // DIVU dst,edst,src1,src2[,f] + OP_DIVS, // DIVS dst,edst,src1,src2[,f] + OP_AND, // AND dst,src1,src2[,f] + OP_TEST, // TEST src1,src2[,f] + OP_OR, // OR dst,src1,src2[,f] + OP_XOR, // XOR dst,src1,src2[,f] + OP_LZCNT, // LZCNT dst,src + OP_BSWAP, // BSWAP dst,src + OP_SHL, // SHL dst,src,count[,f] + OP_SHR, // SHR dst,src,count[,f] + OP_SAR, // SAR dst,src,count[,f] + OP_ROL, // ROL dst,src,count[,f] + OP_ROLC, // ROLC dst,src,count[,f] + OP_ROR, // ROL dst,src,count[,f] + OP_RORC, // ROLC dst,src,count[,f] + + // floating point operations + OP_FLOAD, // FLOAD dst,base,index + OP_FSTORE, // FSTORE base,index,src + OP_FREAD, // FREAD dst,space,src1 + OP_FWRITE, // FWRITE space,dst,src1 + OP_FMOV, // FMOV dst,src1[,c] + OP_FTOINT, // FTOINT dst,src1,size,round + OP_FFRINT, // FFRINT dst,src1,size + OP_FFRFLT, // FFRFLT dst,src1,size + OP_FRNDS, // FRNDS dst,src1 + OP_FADD, // FADD dst,src1,src2 + OP_FSUB, // FSUB dst,src1,src2 + OP_FCMP, // FCMP src1,src2 + OP_FMUL, // FMUL dst,src1,src2 + OP_FDIV, // FDIV dst,src1,src2 + OP_FNEG, // FNEG dst,src1 + OP_FABS, // FABS dst,src1 + OP_FSQRT, // FSQRT dst,src1 + OP_FRECIP, // FRECIP dst,src1 + OP_FRSQRT, // FRSQRT dst,src1 + + OP_MAX + }; + + // C function callback deinition + typedef void (*c_function)(void *ptr); + + // class describing a global code handle + class code_handle + { + friend class ::drcuml_state; + friend class ::simple_list; + + // construction/destruction + code_handle(drcuml_state &drcuml, const char *name); + + public: + // getters + code_handle *next() const { return m_next; } + drccodeptr codeptr() const { return *m_code; } + drccodeptr *codeptr_addr() { return m_code; } + const char *string() const { return m_string.c_str(); } + + // setters + void set_codeptr(drccodeptr code); + + private: + // internal state + drccodeptr * m_code; // pointer in the cache to the associated code + std::string m_string; // pointer to string attached to handle + code_handle * m_next; // link to next handle in the list + drcuml_state & m_drcuml; // pointer to owning object + }; + + // class describing a local code label + class code_label + { + public: + // construction + code_label(UINT32 label = 0) : m_label(label) { } + + // operators + operator UINT32 &() { return m_label; } + bool operator==(const code_label &rhs) const { return (m_label == rhs.m_label); } + bool operator!=(const code_label &rhs) const { return (m_label != rhs.m_label); } + + // getters + UINT32 label() const { return m_label; } + + private: + UINT32 m_label; + }; + + // a parameter for a UML instructon is encoded like this + class parameter + { + public: + // opcode parameter types + enum parameter_type + { + PTYPE_NONE = 0, // invalid + PTYPE_IMMEDIATE, // immediate; value = sign-extended to 64 bits + PTYPE_INT_REGISTER, // integer register; value = REG_I0 - REG_I_END + PTYPE_FLOAT_REGISTER, // floating point register; value = REG_F0 - REG_F_END + PTYPE_VECTOR_REGISTER, // vector register; value = REG_V0 - REG_V_END + PTYPE_MAPVAR, // map variable; value = MAPVAR_M0 - MAPVAR_END + PTYPE_MEMORY, // memory; value = pointer to memory + PTYPE_SIZE, // size; value = operand_size + PTYPE_SIZE_SCALE, // scale + size; value = memory_scale * 16 + operand_size + PTYPE_SIZE_SPACE, // space + size; value = memory_space * 16 + operand_size + PTYPE_CODE_HANDLE, // code handle; value = pointer to handle + PTYPE_CODE_LABEL, // code label; value = label index + PTYPE_C_FUNCTION, // C function; value = pointer to C code + PTYPE_ROUNDING, // floating point rounding mode; value = float_rounding_mode + PTYPE_STRING, // string parameter; value = pointer to string + PTYPE_MAX + }; + + // represents the value of an opcode parameter + typedef UINT64 parameter_value; + + // construction + parameter() : m_type(PTYPE_NONE), m_value(0) { } + parameter(const parameter ¶m) : m_type(param.m_type), m_value(param.m_value) { } + parameter(UINT64 val) : m_type(PTYPE_IMMEDIATE), m_value(val) { } + parameter(operand_size size, memory_scale scale) : m_type(PTYPE_SIZE_SCALE), m_value((scale << 4) | size) { assert(size >= SIZE_BYTE && size <= SIZE_DQWORD); assert(scale >= SCALE_x1 && scale <= SCALE_x8); } + parameter(operand_size size, memory_space space) : m_type(PTYPE_SIZE_SPACE), m_value((space << 4) | size) { assert(size >= SIZE_BYTE && size <= SIZE_DQWORD); assert(space >= SPACE_PROGRAM && space <= SPACE_IO); } + parameter(code_handle &handle) : m_type(PTYPE_CODE_HANDLE), m_value(reinterpret_cast(&handle)) { } + parameter(code_label &label) : m_type(PTYPE_CODE_LABEL), m_value(label) { } + + // creators for types that don't safely default + static inline parameter make_ireg(int regnum) { assert(regnum >= REG_I0 && regnum < REG_I_END); return parameter(PTYPE_INT_REGISTER, regnum); } + static inline parameter make_freg(int regnum) { assert(regnum >= REG_F0 && regnum < REG_F_END); return parameter(PTYPE_FLOAT_REGISTER, regnum); } + static inline parameter make_vreg(int regnum) { assert(regnum >= REG_V0 && regnum < REG_V_END); return parameter(PTYPE_VECTOR_REGISTER, regnum); } + static inline parameter make_mapvar(int mvnum) { assert(mvnum >= MAPVAR_M0 && mvnum < MAPVAR_END); return parameter(PTYPE_MAPVAR, mvnum); } + static inline parameter make_memory(void *base) { return parameter(PTYPE_MEMORY, reinterpret_cast(base)); } + static inline parameter make_memory(const void *base) { return parameter(PTYPE_MEMORY, reinterpret_cast(const_cast(base))); } + static inline parameter make_size(operand_size size) { assert(size >= SIZE_BYTE && size <= SIZE_DQWORD); return parameter(PTYPE_SIZE, size); } + static inline parameter make_string(const char *string) { return parameter(PTYPE_STRING, reinterpret_cast(const_cast(string))); } + static inline parameter make_cfunc(c_function func) { return parameter(PTYPE_C_FUNCTION, reinterpret_cast(func)); } + static inline parameter make_rounding(float_rounding_mode mode) { assert(mode >= ROUND_TRUNC && mode <= ROUND_DEFAULT); return parameter(PTYPE_ROUNDING, mode); } + + // operators + bool operator==(const parameter &rhs) const { return (m_type == rhs.m_type && m_value == rhs.m_value); } + bool operator!=(const parameter &rhs) const { return (m_type != rhs.m_type || m_value != rhs.m_value); } + + // getters + parameter_type type() const { return m_type; } + UINT64 immediate() const { assert(m_type == PTYPE_IMMEDIATE); return m_value; } + int ireg() const { assert(m_type == PTYPE_INT_REGISTER); assert(m_value >= REG_I0 && m_value < REG_I_END); return m_value; } + int freg() const { assert(m_type == PTYPE_FLOAT_REGISTER); assert(m_value >= REG_F0 && m_value < REG_F_END); return m_value; } + int vreg() const { assert(m_type == PTYPE_VECTOR_REGISTER); assert(m_value >= REG_V0 && m_value < REG_V_END); return m_value; } + int mapvar() const { assert(m_type == PTYPE_MAPVAR); assert(m_value >= MAPVAR_M0 && m_value < MAPVAR_END); return m_value; } + void *memory() const { assert(m_type == PTYPE_MEMORY); return reinterpret_cast(m_value); } + operand_size size() const { assert(m_type == PTYPE_SIZE || m_type == PTYPE_SIZE_SCALE || m_type == PTYPE_SIZE_SPACE); return operand_size(m_value & 15); } + memory_scale scale() const { assert(m_type == PTYPE_SIZE_SCALE); return memory_scale(m_value >> 4); } + memory_space space() const { assert(m_type == PTYPE_SIZE_SPACE); return memory_space(m_value >> 4); } + code_handle &handle() const { assert(m_type == PTYPE_CODE_HANDLE); return *reinterpret_cast(m_value); } + code_label label() const { assert(m_type == PTYPE_CODE_LABEL); return code_label(m_value); } + c_function cfunc() const { assert(m_type == PTYPE_C_FUNCTION); return reinterpret_cast(m_value); } + float_rounding_mode rounding() const { assert(m_type == PTYPE_ROUNDING); return float_rounding_mode(m_value); } + const char *string() const { assert(m_type == PTYPE_STRING); return reinterpret_cast(m_value); } + + // type queries + bool is_immediate() const { return (m_type == PTYPE_IMMEDIATE); } + bool is_int_register() const { return (m_type == PTYPE_INT_REGISTER); } + bool is_float_register() const { return (m_type == PTYPE_FLOAT_REGISTER); } + bool is_vector_register() const { return (m_type == PTYPE_VECTOR_REGISTER); } + bool is_mapvar() const { return (m_type == PTYPE_MAPVAR); } + bool is_memory() const { return (m_type == PTYPE_MEMORY); } + bool is_size() const { return (m_type == PTYPE_SIZE); } + bool is_size_scale() const { return (m_type == PTYPE_SIZE_SCALE); } + bool is_size_space() const { return (m_type == PTYPE_SIZE_SPACE); } + bool is_code_handle() const { return (m_type == PTYPE_CODE_HANDLE); } + bool is_code_label() const { return (m_type == PTYPE_CODE_LABEL); } + bool is_c_function() const { return (m_type == PTYPE_C_FUNCTION); } + bool is_rounding() const { return (m_type == PTYPE_ROUNDING); } + bool is_string() const { return (m_type == PTYPE_STRING); } + + // other queries + bool is_immediate_value(UINT64 value) const { return (m_type == PTYPE_IMMEDIATE && m_value == value); } + + private: + // private constructor + parameter(parameter_type type, parameter_value value) : m_type(type), m_value(value) { } + + // internals + parameter_type m_type; // parameter type + parameter_value m_value; // parameter value + }; + + // structure describing rules for opcode encoding + struct opcode_info + { + struct parameter_info + { + UINT8 output; // input or output? + UINT8 size; // size of the parameter + UINT16 typemask; // types allowed + }; + + opcode_t opcode; // the opcode itself + const char * mnemonic; // mnemonic string + UINT8 sizes; // allowed sizes + bool condition; // conditions allowed? + UINT8 inflags; // input flags + UINT8 outflags; // output flags + UINT8 modflags; // modified flags + parameter_info param[4]; // information about parameters + }; + + // a single UML instructon is encoded like this + class instruction + { + public: + // construction/destruction + instruction(); + + // getters + opcode_t opcode() const { return m_opcode; } + condition_t condition() const { return m_condition; } + UINT8 flags() const { return m_flags; } + UINT8 size() const { return m_size; } + UINT8 numparams() const { return m_numparams; } + const parameter ¶m(int index) const { assert(index < m_numparams); return m_param[index]; } + + // setters + void set_flags(UINT8 flags) { m_flags = flags; } + void set_mapvar(int paramnum, UINT32 value) { assert(paramnum < m_numparams); assert(m_param[paramnum].is_mapvar()); m_param[paramnum] = value; } + + // misc + const char *disasm(std::string &str, drcuml_state *drcuml = NULL) const; + UINT8 input_flags() const; + UINT8 output_flags() const; + UINT8 modified_flags() const; + void simplify(); + + // compile-time opcodes + void handle(code_handle &hand) { configure(OP_HANDLE, 4, hand); } + void hash(UINT32 mode, UINT32 pc) { configure(OP_HASH, 4, mode, pc); } + void label(code_label lab) { configure(OP_LABEL, 4, lab); } + void comment(const char *string) { configure(OP_COMMENT, 4, parameter::make_string(string)); } + void mapvar(parameter mapvar, UINT32 value) { assert(mapvar.is_mapvar()); configure(OP_MAPVAR, 4, mapvar, value); } + + // control flow operations + void nop() { configure(OP_NOP, 4); } + void debug(UINT32 pc) { configure(OP_DEBUG, 4, pc); } + void exit(parameter param) { configure(OP_EXIT, 4, param); } + void exit(condition_t cond, parameter param) { configure(OP_EXIT, 4, param, cond); } + void hashjmp(parameter mode, parameter pc, code_handle &handle) { configure(OP_HASHJMP, 4, mode, pc, handle); } + void jmp(code_label label) { configure(OP_JMP, 4, label); } + void jmp(condition_t cond, code_label label) { configure(OP_JMP, 4, label, cond); } + void exh(code_handle &handle, parameter param) { configure(OP_EXH, 4, handle, param); } + void exh(condition_t cond, code_handle &handle, parameter param) { configure(OP_EXH, 4, handle, param, cond); } + void callh(code_handle &handle) { configure(OP_CALLH, 4, handle); } + void callh(condition_t cond, code_handle &handle) { configure(OP_CALLH, 4, handle, cond); } + void ret() { configure(OP_RET, 4); } + void ret(condition_t cond) { configure(OP_RET, 4, cond); } + void callc(c_function func, void *ptr) { configure(OP_CALLC, 4, parameter::make_cfunc(func), parameter::make_memory(ptr)); } + void callc(condition_t cond, c_function func, void *ptr) { configure(OP_CALLC, 4, parameter::make_cfunc(func), parameter::make_memory(ptr), cond); } + void recover(parameter dst, parameter mapvar) { assert(mapvar.is_mapvar()); configure(OP_RECOVER, 4, dst, mapvar); } + + // internal register operations + void setfmod(parameter mode) { configure(OP_SETFMOD, 4, mode); } + void getfmod(parameter dst) { configure(OP_GETFMOD, 4, dst); } + void getexp(parameter dst) { configure(OP_GETEXP, 4, dst); } + void getflgs(parameter dst, UINT32 flags) { configure(OP_GETFLGS, 4, dst, flags); } + void save(drcuml_machine_state *dst) { configure(OP_SAVE, 4, parameter::make_memory(dst)); } + void restore(drcuml_machine_state *src) { configure(OP_RESTORE, 4, parameter::make_memory(src)); } + + // 32-bit integer operations + void load(parameter dst, const void *base, parameter index, operand_size size, memory_scale scale = SCALE_DEFAULT) { configure(OP_LOAD, 4, dst, parameter::make_memory(base), index, parameter(size, scale)); } + void loads(parameter dst, const void *base, parameter index, operand_size size, memory_scale scale = SCALE_DEFAULT) { configure(OP_LOADS, 4, dst, parameter::make_memory(base), index, parameter(size, scale)); } + void store(void *base, parameter index, parameter src1, operand_size size, memory_scale scale = SCALE_DEFAULT) { configure(OP_STORE, 4, parameter::make_memory(base), index, src1, parameter(size, scale)); } + void read(parameter dst, parameter src1, operand_size size, memory_space space = SPACE_PROGRAM) { configure(OP_READ, 4, dst, src1, parameter(size, space)); } + void readm(parameter dst, parameter src1, parameter mask, operand_size size, memory_space space = SPACE_PROGRAM) { configure(OP_READM, 4, dst, src1, mask, parameter(size, space)); } + void write(parameter dst, parameter src1, operand_size size, memory_space space = SPACE_PROGRAM) { configure(OP_WRITE, 4, dst, src1, parameter(size, space)); } + void writem(parameter dst, parameter src1, parameter mask, operand_size size, memory_space space = SPACE_PROGRAM) { configure(OP_WRITEM, 4, dst, src1, mask, parameter(size, space)); } + void carry(parameter src, parameter bitnum) { configure(OP_CARRY, 4, src, bitnum); } + void set(condition_t cond, parameter dst) { configure(OP_SET, 4, dst, cond); } + void mov(parameter dst, parameter src1) { configure(OP_MOV, 4, dst, src1); } + void mov(condition_t cond, parameter dst, parameter src1) { configure(OP_MOV, 4, dst, src1, cond); } + void sext(parameter dst, parameter src1, operand_size size) { configure(OP_SEXT, 4, dst, src1, parameter::make_size(size)); } + void roland(parameter dst, parameter src, parameter shift, parameter mask) { configure(OP_ROLAND, 4, dst, src, shift, mask); } + void rolins(parameter dst, parameter src, parameter shift, parameter mask) { configure(OP_ROLINS, 4, dst, src, shift, mask); } + void add(parameter dst, parameter src1, parameter src2) { configure(OP_ADD, 4, dst, src1, src2); } + void addc(parameter dst, parameter src1, parameter src2) { configure(OP_ADDC, 4, dst, src1, src2); } + void sub(parameter dst, parameter src1, parameter src2) { configure(OP_SUB, 4, dst, src1, src2); } + void subb(parameter dst, parameter src1, parameter src2) { configure(OP_SUBB, 4, dst, src1, src2); } + void cmp(parameter src1, parameter src2) { configure(OP_CMP, 4, src1, src2); } + void mulu(parameter dst, parameter edst, parameter src1, parameter src2) { configure(OP_MULU, 4, dst, edst, src1, src2); } + void muls(parameter dst, parameter edst, parameter src1, parameter src2) { configure(OP_MULS, 4, dst, edst, src1, src2); } + void divu(parameter dst, parameter edst, parameter src1, parameter src2) { configure(OP_DIVU, 4, dst, edst, src1, src2); } + void divs(parameter dst, parameter edst, parameter src1, parameter src2) { configure(OP_DIVS, 4, dst, edst, src1, src2); } + void _and(parameter dst, parameter src1, parameter src2) { configure(OP_AND, 4, dst, src1, src2); } + void test(parameter src1, parameter src2) { configure(OP_TEST, 4, src1, src2); } + void _or(parameter dst, parameter src1, parameter src2) { configure(OP_OR, 4, dst, src1, src2); } + void _xor(parameter dst, parameter src1, parameter src2) { configure(OP_XOR, 4, dst, src1, src2); } + void lzcnt(parameter dst, parameter src) { configure(OP_LZCNT, 4, dst, src); } + void bswap(parameter dst, parameter src) { configure(OP_BSWAP, 4, dst, src); } + void shl(parameter dst, parameter src, parameter count) { configure(OP_SHL, 4, dst, src, count); } + void shr(parameter dst, parameter src, parameter count) { configure(OP_SHR, 4, dst, src, count); } + void sar(parameter dst, parameter src, parameter count) { configure(OP_SAR, 4, dst, src, count); } + void rol(parameter dst, parameter src, parameter count) { configure(OP_ROL, 4, dst, src, count); } + void rolc(parameter dst, parameter src, parameter count) { configure(OP_ROLC, 4, dst, src, count); } + void ror(parameter dst, parameter src, parameter count) { configure(OP_ROR, 4, dst, src, count); } + void rorc(parameter dst, parameter src, parameter count) { configure(OP_RORC, 4, dst, src, count); } + + // 64-bit integer operations + void dload(parameter dst, const void *base, parameter index, operand_size size, memory_scale scale = SCALE_DEFAULT) { configure(OP_LOAD, 8, dst, parameter::make_memory(base), index, parameter(size, scale)); } + void dloads(parameter dst, const void *base, parameter index, operand_size size, memory_scale scale = SCALE_DEFAULT) { configure(OP_LOADS, 8, dst, parameter::make_memory(base), index, parameter(size, scale)); } + void dstore(void *base, parameter index, parameter src1, operand_size size, memory_scale scale = SCALE_DEFAULT) { configure(OP_STORE, 8, parameter::make_memory(base), index, src1, parameter(size, scale)); } + void dread(parameter dst, parameter src1, operand_size size, memory_space space = SPACE_PROGRAM) { configure(OP_READ, 8, dst, src1, parameter(size, space)); } + void dreadm(parameter dst, parameter src1, parameter mask, operand_size size, memory_space space = SPACE_PROGRAM) { configure(OP_READM, 8, dst, src1, mask, parameter(size, space)); } + void dwrite(parameter dst, parameter src1, operand_size size, memory_space space = SPACE_PROGRAM) { configure(OP_WRITE, 8, dst, src1, parameter(size, space)); } + void dwritem(parameter dst, parameter src1, parameter mask, operand_size size, memory_space space = SPACE_PROGRAM) { configure(OP_WRITEM, 8, dst, src1, mask, parameter(size, space)); } + void dcarry(parameter src, parameter bitnum) { configure(OP_CARRY, 8, src, bitnum); } + void dset(condition_t cond, parameter dst) { configure(OP_SET, 8, dst, cond); } + void dmov(parameter dst, parameter src1) { configure(OP_MOV, 8, dst, src1); } + void dmov(condition_t cond, parameter dst, parameter src1) { configure(OP_MOV, 8, dst, src1, cond); } + void dsext(parameter dst, parameter src1, operand_size size) { configure(OP_SEXT, 8, dst, src1, parameter::make_size(size)); } + void droland(parameter dst, parameter src, parameter shift, parameter mask) { configure(OP_ROLAND, 8, dst, src, shift, mask); } + void drolins(parameter dst, parameter src, parameter shift, parameter mask) { configure(OP_ROLINS, 8, dst, src, shift, mask); } + void dadd(parameter dst, parameter src1, parameter src2) { configure(OP_ADD, 8, dst, src1, src2); } + void daddc(parameter dst, parameter src1, parameter src2) { configure(OP_ADDC, 8, dst, src1, src2); } + void dsub(parameter dst, parameter src1, parameter src2) { configure(OP_SUB, 8, dst, src1, src2); } + void dsubb(parameter dst, parameter src1, parameter src2) { configure(OP_SUBB, 8, dst, src1, src2); } + void dcmp(parameter src1, parameter src2) { configure(OP_CMP, 8, src1, src2); } + void dmulu(parameter dst, parameter edst, parameter src1, parameter src2) { configure(OP_MULU, 8, dst, edst, src1, src2); } + void dmuls(parameter dst, parameter edst, parameter src1, parameter src2) { configure(OP_MULS, 8, dst, edst, src1, src2); } + void ddivu(parameter dst, parameter edst, parameter src1, parameter src2) { configure(OP_DIVU, 8, dst, edst, src1, src2); } + void ddivs(parameter dst, parameter edst, parameter src1, parameter src2) { configure(OP_DIVS, 8, dst, edst, src1, src2); } + void dand(parameter dst, parameter src1, parameter src2) { configure(OP_AND, 8, dst, src1, src2); } + void dtest(parameter src1, parameter src2) { configure(OP_TEST, 8, src1, src2); } + void dor(parameter dst, parameter src1, parameter src2) { configure(OP_OR, 8, dst, src1, src2); } + void dxor(parameter dst, parameter src1, parameter src2) { configure(OP_XOR, 8, dst, src1, src2); } + void dlzcnt(parameter dst, parameter src) { configure(OP_LZCNT, 8, dst, src); } + void dbswap(parameter dst, parameter src) { configure(OP_BSWAP, 8, dst, src); } + void dshl(parameter dst, parameter src, parameter count) { configure(OP_SHL, 8, dst, src, count); } + void dshr(parameter dst, parameter src, parameter count) { configure(OP_SHR, 8, dst, src, count); } + void dsar(parameter dst, parameter src, parameter count) { configure(OP_SAR, 8, dst, src, count); } + void drol(parameter dst, parameter src, parameter count) { configure(OP_ROL, 8, dst, src, count); } + void drolc(parameter dst, parameter src, parameter count) { configure(OP_ROLC, 8, dst, src, count); } + void dror(parameter dst, parameter src, parameter count) { configure(OP_ROR, 8, dst, src, count); } + void drorc(parameter dst, parameter src, parameter count) { configure(OP_RORC, 8, dst, src, count); } + + // 32-bit floating point operations + void fsload(parameter dst, const void *base, parameter index) { configure(OP_FLOAD, 4, dst, parameter::make_memory(base), index); } + void fsstore(void *base, parameter index, parameter src1) { configure(OP_FSTORE, 4, parameter::make_memory(base), index, src1); } + void fsread(parameter dst, parameter src1, memory_space space) { configure(OP_FREAD, 4, dst, src1, parameter(SIZE_SHORT, space)); } + void fswrite(parameter dst, parameter src1, memory_space space) { configure(OP_FWRITE, 4, dst, src1, parameter(SIZE_SHORT, space)); } + void fsmov(parameter dst, parameter src1) { configure(OP_FMOV, 4, dst, src1); } + void fsmov(condition_t cond, parameter dst, parameter src1) { configure(OP_FMOV, 4, dst, src1, cond); } + void fstoint(parameter dst, parameter src1, operand_size size, float_rounding_mode round) { configure(OP_FTOINT, 4, dst, src1, parameter::make_size(size), parameter::make_rounding(round)); } + void fsfrint(parameter dst, parameter src1, operand_size size) { configure(OP_FFRINT, 4, dst, src1, parameter::make_size(size)); } + void fsfrflt(parameter dst, parameter src1, operand_size size) { configure(OP_FFRFLT, 4, dst, src1, parameter::make_size(size)); } + void fsadd(parameter dst, parameter src1, parameter src2) { configure(OP_FADD, 4, dst, src1, src2); } + void fssub(parameter dst, parameter src1, parameter src2) { configure(OP_FSUB, 4, dst, src1, src2); } + void fscmp(parameter src1, parameter src2) { configure(OP_FCMP, 4, src1, src2); } + void fsmul(parameter dst, parameter src1, parameter src2) { configure(OP_FMUL, 4, dst, src1, src2); } + void fsdiv(parameter dst, parameter src1, parameter src2) { configure(OP_FDIV, 4, dst, src1, src2); } + void fsneg(parameter dst, parameter src1) { configure(OP_FNEG, 4, dst, src1); } + void fsabs(parameter dst, parameter src1) { configure(OP_FABS, 4, dst, src1); } + void fssqrt(parameter dst, parameter src1) { configure(OP_FSQRT, 4, dst, src1); } + void fsrecip(parameter dst, parameter src1) { configure(OP_FRECIP, 4, dst, src1); } + void fsrsqrt(parameter dst, parameter src1) { configure(OP_FRSQRT, 4, dst, src1); } + + // 64-bit floating point operations + void fdload(parameter dst, const void *base, parameter index) { configure(OP_FLOAD, 8, dst, parameter::make_memory(base), index); } + void fdstore(void *base, parameter index, parameter src1) { configure(OP_FSTORE, 8, parameter::make_memory(base), index, src1); } + void fdread(parameter dst, parameter src1, memory_space space) { configure(OP_FREAD, 8, dst, src1, parameter(SIZE_DOUBLE, space)); } + void fdwrite(parameter dst, parameter src1, memory_space space) { configure(OP_FWRITE, 8, dst, src1, parameter(SIZE_DOUBLE, space)); } + void fdmov(parameter dst, parameter src1) { configure(OP_FMOV, 8, dst, src1); } + void fdmov(condition_t cond, parameter dst, parameter src1) { configure(OP_FMOV, 8, dst, src1, cond); } + void fdtoint(parameter dst, parameter src1, operand_size size, float_rounding_mode round) { configure(OP_FTOINT, 8, dst, src1, parameter::make_size(size), parameter::make_rounding(round)); } + void fdfrint(parameter dst, parameter src1, operand_size size) { configure(OP_FFRINT, 8, dst, src1, parameter::make_size(size)); } + void fdfrflt(parameter dst, parameter src1, operand_size size) { configure(OP_FFRFLT, 8, dst, src1, parameter::make_size(size)); } + void fdrnds(parameter dst, parameter src1) { configure(OP_FRNDS, 8, dst, src1); } + void fdadd(parameter dst, parameter src1, parameter src2) { configure(OP_FADD, 8, dst, src1, src2); } + void fdsub(parameter dst, parameter src1, parameter src2) { configure(OP_FSUB, 8, dst, src1, src2); } + void fdcmp(parameter src1, parameter src2) { configure(OP_FCMP, 8, src1, src2); } + void fdmul(parameter dst, parameter src1, parameter src2) { configure(OP_FMUL, 8, dst, src1, src2); } + void fddiv(parameter dst, parameter src1, parameter src2) { configure(OP_FDIV, 8, dst, src1, src2); } + void fdneg(parameter dst, parameter src1) { configure(OP_FNEG, 8, dst, src1); } + void fdabs(parameter dst, parameter src1) { configure(OP_FABS, 8, dst, src1); } + void fdsqrt(parameter dst, parameter src1) { configure(OP_FSQRT, 8, dst, src1); } + void fdrecip(parameter dst, parameter src1) { configure(OP_FRECIP, 8, dst, src1); } + void fdrsqrt(parameter dst, parameter src1) { configure(OP_FRSQRT, 8, dst, src1); } + + // constants + static const int MAX_PARAMS = 4; + + private: + // internal configuration + void configure(opcode_t op, UINT8 size, condition_t cond = COND_ALWAYS); + void configure(opcode_t op, UINT8 size, parameter p0, condition_t cond = COND_ALWAYS); + void configure(opcode_t op, UINT8 size, parameter p0, parameter p1, condition_t cond = COND_ALWAYS); + void configure(opcode_t op, UINT8 size, parameter p0, parameter p1, parameter p2, condition_t cond = COND_ALWAYS); + void configure(opcode_t op, UINT8 size, parameter p0, parameter p1, parameter p2, parameter p3, condition_t cond = COND_ALWAYS); + + // opcode validation and simplification + void validate(); + void convert_to_mov_immediate(UINT64 immediate) { m_opcode = OP_MOV; m_numparams = 2; m_param[1] = immediate; } + void convert_to_mov_param(int pnum) { m_opcode = OP_MOV; m_numparams = 2; m_param[1] = m_param[pnum]; } + + // internal state + opcode_t m_opcode; // opcode + condition_t m_condition; // condition + UINT8 m_flags; // flags + UINT8 m_size; // operation size + UINT8 m_numparams; // number of parameters + parameter m_param[MAX_PARAMS];// up to 4 parameters + + static const opcode_info s_opcode_info_table[OP_MAX]; + }; + + // structure describing rules for parameter encoding + struct parameter_info + { + UINT8 output; // input or output? + UINT8 size; // size of the parameter + UINT16 typemask; // types allowed + }; + + // global inline functions to specify a register parameter by index + inline parameter ireg(int n) { return parameter::make_ireg(REG_I0 + n); } + inline parameter freg(int n) { return parameter::make_freg(REG_F0 + n); } + inline parameter vreg(int n) { return parameter::make_vreg(REG_V0 + n); } + inline parameter mapvar(int n) { return parameter::make_mapvar(MAPVAR_M0 + n); } + + // global inline functions to define memory parameters + inline parameter mem(const void *ptr) { return parameter::make_memory(ptr); } + + // global register objects for direct access + const parameter I0(parameter::make_ireg(REG_I0 + 0)); + const parameter I1(parameter::make_ireg(REG_I0 + 1)); + const parameter I2(parameter::make_ireg(REG_I0 + 2)); + const parameter I3(parameter::make_ireg(REG_I0 + 3)); + const parameter I4(parameter::make_ireg(REG_I0 + 4)); + const parameter I5(parameter::make_ireg(REG_I0 + 5)); + const parameter I6(parameter::make_ireg(REG_I0 + 6)); + const parameter I7(parameter::make_ireg(REG_I0 + 7)); + const parameter I8(parameter::make_ireg(REG_I0 + 8)); + const parameter I9(parameter::make_ireg(REG_I0 + 9)); + + const parameter F0(parameter::make_freg(REG_F0 + 0)); + const parameter F1(parameter::make_freg(REG_F0 + 1)); + const parameter F2(parameter::make_freg(REG_F0 + 2)); + const parameter F3(parameter::make_freg(REG_F0 + 3)); + const parameter F4(parameter::make_freg(REG_F0 + 4)); + const parameter F5(parameter::make_freg(REG_F0 + 5)); + const parameter F6(parameter::make_freg(REG_F0 + 6)); + const parameter F7(parameter::make_freg(REG_F0 + 7)); + const parameter F8(parameter::make_freg(REG_F0 + 8)); + const parameter F9(parameter::make_freg(REG_F0 + 9)); + + const parameter V0(parameter::make_vreg(REG_V0 + 0)); + const parameter V1(parameter::make_vreg(REG_V0 + 1)); + const parameter V2(parameter::make_vreg(REG_V0 + 2)); + const parameter V3(parameter::make_vreg(REG_V0 + 3)); + const parameter V4(parameter::make_vreg(REG_V0 + 4)); + const parameter V5(parameter::make_vreg(REG_V0 + 5)); + const parameter V6(parameter::make_vreg(REG_V0 + 6)); + const parameter V7(parameter::make_vreg(REG_V0 + 7)); + const parameter V8(parameter::make_vreg(REG_V0 + 8)); + const parameter V9(parameter::make_vreg(REG_V0 + 9)); + + const parameter M0(parameter::make_mapvar(MAPVAR_M0 + 0)); + const parameter M1(parameter::make_mapvar(MAPVAR_M0 + 1)); + const parameter M2(parameter::make_mapvar(MAPVAR_M0 + 2)); + const parameter M3(parameter::make_mapvar(MAPVAR_M0 + 3)); + const parameter M4(parameter::make_mapvar(MAPVAR_M0 + 4)); + const parameter M5(parameter::make_mapvar(MAPVAR_M0 + 5)); + const parameter M6(parameter::make_mapvar(MAPVAR_M0 + 6)); + const parameter M7(parameter::make_mapvar(MAPVAR_M0 + 7)); + const parameter M8(parameter::make_mapvar(MAPVAR_M0 + 8)); + const parameter M9(parameter::make_mapvar(MAPVAR_M0 + 9)); +} + + +#endif /* __UML_H__ */ diff --git a/src/devices/cpu/unsp/unsp.c b/src/devices/cpu/unsp/unsp.c new file mode 100644 index 00000000000..5b3d89ca822 --- /dev/null +++ b/src/devices/cpu/unsp/unsp.c @@ -0,0 +1,867 @@ +// license:BSD-3-Clause +// copyright-holders:Ryan Holtz +/**************************\ +* +* SunPlus u'nSP core +* +* by Harmony +* +\**************************/ + +#include "emu.h" +#include "debugger.h" +#include "unsp.h" + + +const device_type UNSP = &device_creator; + + +unsp_device::unsp_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : cpu_device(mconfig, UNSP, "u'nSP", tag, owner, clock, "unsp", __FILE__) + , m_program_config("program", ENDIANNESS_BIG, 16, 23, -1) +{ +} + + +offs_t unsp_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( unsp ); + return CPU_DISASSEMBLE_NAME(unsp)(this, buffer, pc, oprom, opram, options); +} + + +/*****************************************************************************/ + +#define OP0 (op >> 12) +#define OPA ((op >> 9) & 7) +#define OP1 ((op >> 6) & 7) +#define OPN ((op >> 3) & 7) +#define OPB (op & 7) +#define OPIMM (op & 0x3f) + +#define UNSP_LPC (((UNSP_REG(SR) & 0x3f) << 16) | UNSP_REG(PC)) + +#define UNSP_REG(reg) m_r[UNSP_##reg - 1] +#define UNSP_REG_I(reg) m_r[reg] +#define UNSP_LREG_I(reg) (((UNSP_REG(SR) << 6) & 0x3f0000) | UNSP_REG_I(reg)) + +#define UNSP_N 0x0200 +#define UNSP_Z 0x0100 +#define UNSP_S 0x0080 +#define UNSP_C 0x0040 + +#define STANDARD_ALU_CASES \ + case 0: \ + lres = r0 + r1; \ + unsp_update_nzsc(lres, r0, r1); \ + break; \ + case 1: \ + lres = r0 + r1; \ + if(UNSP_REG(SR) & UNSP_C) lres++; \ + unsp_update_nzsc(lres, r0, r1); \ + break; \ + case 3: \ + lres = r0 + (~r1 & 0x0000ffff); \ + if(UNSP_REG(SR) & UNSP_C) lres++; \ + unsp_update_nzsc(lres, r0, r1); \ + break; \ + case 2: \ + case 4: \ + lres = r0 + (~r1 & 0x0000ffff) + 1; \ + unsp_update_nzsc(lres, r0, r1); \ + break; \ + case 6: \ + lres = -r1; \ + unsp_update_nz(lres); \ + break; \ + case 8: \ + lres = r0 ^ r1; \ + unsp_update_nz(lres); \ + break; \ + case 9: \ + lres = r1; \ + unsp_update_nz(lres); \ + break; \ + case 10: \ + lres = r0 | r1; \ + unsp_update_nz(lres); \ + break; \ + case 11: \ + case 12: \ + lres = r0 & r1; \ + unsp_update_nz(lres); \ + break + +#define WRITEBACK_OPA \ + if(OP0 != 4 && OP0 < 12) \ + { \ + UNSP_REG_I(OPA) = (UINT16)lres; \ + } + +/*****************************************************************************/ + +void unsp_device::unimplemented_opcode(UINT16 op) +{ + fatalerror("UNSP: unknown opcode %04x at %04x\n", op, UNSP_LPC); +} + +/*****************************************************************************/ + +UINT16 unsp_device::READ16(UINT32 address) +{ + return m_program->read_word(address<<1); +} + +void unsp_device::WRITE16(UINT32 address, UINT16 data) +{ + m_program->write_word(address<<1, data); +} + +/*****************************************************************************/ + +void unsp_device::device_start() +{ + memset(m_r, 0, sizeof(UINT16) * UNSP_GPR_COUNT); + m_irq = 0; + m_fiq = 0; + m_curirq = 0; + m_sirq = 0; + m_sb = 0; + m_saved_sb = 0; + m_debugger_temp = 0; + + m_program = &space(AS_PROGRAM); + + state_add( UNSP_SP, "SP", UNSP_REG(SP)).formatstr("%04X"); + state_add( UNSP_R1, "R1", UNSP_REG(R1)).formatstr("%04X"); + state_add( UNSP_R2, "R2", UNSP_REG(R2)).formatstr("%04X"); + state_add( UNSP_R3, "R3", UNSP_REG(R3)).formatstr("%04X"); + state_add( UNSP_R4, "R4", UNSP_REG(R4)).formatstr("%04X"); + state_add( UNSP_BP, "BP", UNSP_REG(BP)).formatstr("%04X"); + state_add( UNSP_SR, "SR", UNSP_REG(SR)).formatstr("%04X"); + state_add( UNSP_PC, "PC", m_debugger_temp).callimport().callexport().formatstr("%06X"); + state_add( UNSP_IRQ, "IRQ", m_irq).formatstr("%1u"); + state_add( UNSP_FIQ, "FIQ", m_fiq).formatstr("%1u"); + state_add( UNSP_SB, "SB", m_sb).formatstr("%1u"); + + state_add(STATE_GENPC, "GENPC", m_debugger_temp).callexport().noshow(); + + m_icountptr = &m_icount; +} + +void unsp_device::state_export(const device_state_entry &entry) +{ + switch (entry.index()) + { + case UNSP_PC: + m_debugger_temp = UNSP_LPC; + break; + + case STATE_GENPC: + m_debugger_temp = UNSP_LPC; + break; + } +} + +void unsp_device::state_import(const device_state_entry &entry) +{ + switch (entry.index()) + { + case UNSP_PC: + UNSP_REG(PC) = m_debugger_temp & 0x0000ffff; + UNSP_REG(SR) = (UNSP_REG(SR) & 0xffc0) | ((m_debugger_temp & 0x003f0000) >> 16); + break; + } +} + +void unsp_device::device_reset() +{ + memset(m_r, 0, sizeof(UINT16) * UNSP_GPR_COUNT); + + UNSP_REG(PC) = READ16(0xfff7); + m_irq = 0; + m_fiq = 0; +} + +/*****************************************************************************/ + +void unsp_device::unsp_update_nz(UINT32 value) +{ + UNSP_REG(SR) &= ~(UNSP_N | UNSP_Z); + if(value & 0x8000) + { + UNSP_REG(SR) |= UNSP_N; + } + if((UINT16)value == 0) + { + UNSP_REG(SR) |= UNSP_Z; + } +} + +void unsp_device::unsp_update_nzsc(UINT32 value, UINT16 r0, UINT16 r1) +{ + UNSP_REG(SR) &= ~(UNSP_C | UNSP_S); + unsp_update_nz(value); + if(value != (UINT16)value) + { + UNSP_REG(SR) |= UNSP_C; + } + + if((INT16)r0 < (INT16)r1) + { + UNSP_REG(SR) |= UNSP_S; + } +} + +void unsp_device::unsp_push(UINT16 value, UINT16 *reg) +{ + WRITE16((*reg)--, value); +} + +UINT16 unsp_device::unsp_pop(UINT16 *reg) +{ + return READ16(++(*reg)); +} + +void unsp_device::execute_run() +{ + UINT32 op; + UINT32 lres; + UINT16 r0, r1; + lres = 0; + + while (m_icount > 0) + { + debugger_instruction_hook(this, UNSP_LPC); + op = READ16(UNSP_LPC); + + UNSP_REG(PC)++; + + if(OP0 < 0xf && OPA == 0x7 && OP1 < 2) + { + switch(OP0) + { + case 0: // JB + if(!(UNSP_REG(SR) & UNSP_C)) + { + UNSP_REG(PC) += (OP1 == 0) ? OPIMM : (0 - OPIMM); + } + break; + case 1: // JAE + if(UNSP_REG(SR) & UNSP_C) + { + UNSP_REG(PC) += (OP1 == 0) ? OPIMM : (0 - OPIMM); + } + break; + case 2: // JGE + if(!(UNSP_REG(SR) & UNSP_S)) + { + UNSP_REG(PC) += (OP1 == 0) ? OPIMM : (0 - OPIMM); + } + break; + case 3: // JL + if(UNSP_REG(SR) & UNSP_S) + { + UNSP_REG(PC) += (OP1 == 0) ? OPIMM : (0 - OPIMM); + } + break; + case 4: // JNE + if(!(UNSP_REG(SR) & UNSP_Z)) + { + UNSP_REG(PC) += (OP1 == 0) ? OPIMM : (0 - OPIMM); + } + break; + case 5: // JE + if(UNSP_REG(SR) & UNSP_Z) + { + UNSP_REG(PC) += (OP1 == 0) ? OPIMM : (0 - OPIMM); + } + break; + case 6: // JPL + if(!(UNSP_REG(SR) & UNSP_N)) + { + UNSP_REG(PC) += (OP1 == 0) ? OPIMM : (0 - OPIMM); + } + break; + case 7: // JMI + if(UNSP_REG(SR) & UNSP_N) + { + UNSP_REG(PC) += (OP1 == 0) ? OPIMM : (0 - OPIMM); + } + break; + case 8: // JBE + if((UNSP_REG(SR) & (UNSP_Z | UNSP_C)) != UNSP_C) + { + UNSP_REG(PC) += (OP1 == 0) ? OPIMM : (0 - OPIMM); + } + break; + case 9: // JA + if((UNSP_REG(SR) & (UNSP_Z | UNSP_C)) == UNSP_C) + { + UNSP_REG(PC) += (OP1 == 0) ? OPIMM : (0 - OPIMM); + } + break; + case 10: // JLE + if(UNSP_REG(SR) & (UNSP_Z | UNSP_S)) + { + UNSP_REG(PC) += (OP1 == 0) ? OPIMM : (0 - OPIMM); + } + break; + case 11: // JG + if(!(UNSP_REG(SR) & (UNSP_Z | UNSP_S))) + { + UNSP_REG(PC) += (OP1 == 0) ? OPIMM : (0 - OPIMM); + } + break; + case 14: // JMP + UNSP_REG(PC) += (OP1 == 0) ? OPIMM : (0 - OPIMM); + break; + } + } + else + { + switch((OP1 << 4) | OP0) + { + // r, [bp+imm6] + case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x06: case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: + r0 = UNSP_REG_I(OPA); + r1 = READ16(UNSP_REG(BP) + OPIMM); + switch(OP0) + { + STANDARD_ALU_CASES; + case 13: // store r, [bp+imm6] + WRITE16(UNSP_REG(BP) + OPIMM, UNSP_REG_I(OPA)); + break; + default: + unimplemented_opcode(op); + break; + } + WRITEBACK_OPA; + break; + + // r, imm6 + case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x16: case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: + r0 = UNSP_REG_I(OPA); + r1 = OPIMM; + switch(OP0) + { + STANDARD_ALU_CASES; + default: + unimplemented_opcode(op); + break; + } + WRITEBACK_OPA; + break; + + // Pop / Interrupt return + case 0x29: + if(op == 0x9a90) // retf + { + UNSP_REG(SR) = unsp_pop(&UNSP_REG(SP)); + UNSP_REG(PC) = unsp_pop(&UNSP_REG(SP)); + break; + } + else if(op == 0x9a98) // reti + { + int i; + UNSP_REG(SR) = unsp_pop(&UNSP_REG(SP)); + UNSP_REG(PC) = unsp_pop(&UNSP_REG(SP)); + if(m_fiq & 2) + { + m_fiq &= 1; + } + else if(m_irq & 2) + { + m_irq &= 1; + } + m_sirq &= ~(1 << m_curirq); + for(i = 0; i < 9; i++) + { + if((m_sirq & (1 << i)) != 0 && i != m_curirq) + { + m_sirq &= ~(1 << i); + m_curirq = 0; + execute_set_input(UNSP_IRQ0_LINE + i, 1); + i = -1; + break; + } + } + if(i != -1) + { + m_curirq = 0; + } + break; + } + else + { + r0 = OPN; + r1 = OPA; + while(r0--) + { + UNSP_REG_I(++r1) = unsp_pop(&UNSP_REG_I(OPB)); + } + } + break; + + // Push + case 0x2d: + r0 = OPN; + r1 = OPA; + while(r0--) + { + unsp_push(UNSP_REG_I(r1--), &UNSP_REG_I(OPB)); + } + break; + + // ALU, Indirect + case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x36: case 0x38: case 0x39: case 0x3a: case 0x3b: case 0x3c: case 0x3d: + switch(OPN & 3) + { + case 0: // r, [r] + r0 = UNSP_REG_I(OPA); + r1 = READ16((OPN & 4) ? UNSP_LREG_I(OPB) : UNSP_REG_I(OPB)); + switch(OP0) + { + STANDARD_ALU_CASES; + case 13: // store r, [r] + WRITE16((OPN & 4) ? UNSP_LREG_I(OPB) : UNSP_REG_I(OPB), UNSP_REG_I(OPA)); + break; + default: + unimplemented_opcode(op); + break; + } + WRITEBACK_OPA; + break; + case 1: // r, [r--] + r0 = UNSP_REG_I(OPA); + r1 = READ16((OPN & 4) ? UNSP_LREG_I(OPB) : UNSP_REG_I(OPB)); + switch(OP0) + { + STANDARD_ALU_CASES; + case 13: // store r, [r--] + WRITE16((OPN & 4) ? UNSP_LREG_I(OPB) : UNSP_REG_I(OPB), UNSP_REG_I(OPA)); + break; + default: + unimplemented_opcode(op); + break; + } + UNSP_REG_I(OPB)--; + WRITEBACK_OPA; + break; + case 2: // r, [r++] + r0 = UNSP_REG_I(OPA); + r1 = READ16((OPN & 4) ? UNSP_LREG_I(OPB) : UNSP_REG_I(OPB)); + switch(OP0) + { + STANDARD_ALU_CASES; + case 13: // store r, [r++] + WRITE16((OPN & 4) ? UNSP_LREG_I(OPB) : UNSP_REG_I(OPB), UNSP_REG_I(OPA)); + break; + default: + unimplemented_opcode(op); + break; + } + UNSP_REG_I(OPB)++; + WRITEBACK_OPA; + break; + case 3: // r, [++r] + UNSP_REG_I(OPB)++; + r0 = UNSP_REG_I(OPA); + r1 = READ16((OPN & 4) ? UNSP_LREG_I(OPB) : UNSP_REG_I(OPB)); + switch(OP0) + { + STANDARD_ALU_CASES; + default: + unimplemented_opcode(op); + break; + } + WRITEBACK_OPA; + break; + } + break; + + // ALU, 16-bit ops + case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x46: case 0x48: case 0x49: case 0x4a: case 0x4b: case 0x4c: + switch(OPN) + { + // r, r + case 0: + r0 = UNSP_REG_I(OPA); + r1 = UNSP_REG_I(OPB); + switch(OP0) + { + STANDARD_ALU_CASES; + default: + unimplemented_opcode(op); + break; + } + WRITEBACK_OPA; + break; + + // ALU, 16-bit Immediate + case 1: // r, r, imm16 + if(!((OP0 == 4 || OP0 == 6 || OP0 == 9 || OP0 == 12) && OPA != OPB)) + { + r0 = UNSP_REG_I(OPB); + r1 = READ16(UNSP_LPC); + UNSP_REG(PC)++; + switch(OP0) + { + STANDARD_ALU_CASES; + default: + unimplemented_opcode(op); + break; + } + WRITEBACK_OPA; + } + else + { + unimplemented_opcode(op); + } + break; + + // ALU, Direct 16 + case 2: // r, [imm16] + r0 = UNSP_REG_I(OPB); + r1 = READ16(READ16(UNSP_LPC)); + UNSP_REG(PC)++; + switch(OP0) + { + STANDARD_ALU_CASES; + default: + unimplemented_opcode(op); + break; + } + WRITEBACK_OPA; + break; + + // ALU, Direct 16 + case 3: // [imm16], r + r0 = UNSP_REG_I(OPB); + r1 = UNSP_REG_I(OPA); + switch(OP0) + { + STANDARD_ALU_CASES; + default: + unimplemented_opcode(op); + break; + } + if(OP0 != 4 && OP0 < 12) + { + WRITE16(READ16(UNSP_LPC), (UINT16)lres); + } + UNSP_REG(PC)++; + break; + + // ALU, Shifted + default: + { + UINT32 shift = (UNSP_REG_I(OPB) << 4) | m_sb; + if(shift & 0x80000) + { + shift |= 0xf00000; + } + shift >>= (OPN - 3); + m_sb = shift & 0x0f; + r1 = (shift >> 4) & 0x0000ffff; + + switch(OP0) + { + case 9: // load r, r asr n + unsp_update_nz(r1); + UNSP_REG_I(OPA) = r1; + break; + default: + unimplemented_opcode(op); + break; + } + break; + } + } + break; + + case 0x4d: + if(OPN == 3) + { + if(OPA == OPB) + { + WRITE16(READ16(UNSP_LPC), UNSP_REG_I(OPB)); + UNSP_REG(PC)++; + } + else + { + unimplemented_opcode(op); + } + } + else + { + unimplemented_opcode(op); + } + break; + + // ALU, Shifted + case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x56: case 0x58: case 0x59: case 0x5a: case 0x5b: case 0x5c: + if(OPN & 4) + { + switch(OP0) + { + case 9: // load r, r >> imm2 + lres = ((UNSP_REG_I(OPB) << 4) | m_sb) >> (OPN - 3); + m_sb = lres & 0x0f; + unsp_update_nz((UINT16)(lres >> 4)); + UNSP_REG_I(OPA) = (UINT16)(lres >> 4); + break; + default: + unimplemented_opcode(op); + break; + } + } + else + { + UINT32 shift = ((m_sb << 16) | UNSP_REG_I(OPB)) << (OPN + 1); + m_sb = (shift >> 16) & 0x0f; + r0 = UNSP_REG_I(OPA); + r1 = shift & 0x0000ffff; + + switch(OP0) + { + case 0: // add r, r << imm2 + lres = r0 + r1; + unsp_update_nzsc(lres, r0, r1); + UNSP_REG_I(OPA) = (UINT16)lres; + break; + case 9: // load r, r << imm2 + lres = r1; + unsp_update_nz(lres); + UNSP_REG_I(OPA) = (UINT16)lres; + break; + case 10: // or r, r << imm2 + lres = r0 | r1; + unsp_update_nz(lres); + UNSP_REG_I(OPA) = (UINT16)lres; + break; + default: + unimplemented_opcode(op); + break; + } + } + break; + + // ALU, Rotated + case 0x60: case 0x61: case 0x62: case 0x63: case 0x64: case 0x66: case 0x68: case 0x69: case 0x6a: case 0x6b: case 0x6c: + if(OPN & 4) // ROR + { + lres = ((((m_sb << 16) | UNSP_REG_I(OPB)) << 4) | m_sb) >> (OPN - 3); + m_sb = lres & 0x0f; + r1 = (UINT16)(lres >> 4); + } + else + { + lres = ((((m_sb << 16) | UNSP_REG_I(OPB)) << 4) | m_sb) << (OPN + 1); + m_sb = (lres >> 20) & 0x0f; + r1 = (UINT16)(lres >> 4); + } + + switch(OP0) + { + case 9: // load r, r ror imm2 + unsp_update_nz(r1); + UNSP_REG_I(OPA) = r1; + break; + default: + unimplemented_opcode(op); + break; + } + break; + + // ALU, Direct 8 + case 0x70: case 0x71: case 0x72: case 0x73: case 0x74: case 0x76: case 0x78: case 0x79: case 0x7a: case 0x7b: case 0x7c: + //print("%s %s, [%02x]", alu[OP0], reg[OPA], OPIMM); + unimplemented_opcode(op); + break; + + // Call + case 0x1f: + if(OPA == 0) + { + r1 = READ16(UNSP_LPC); + UNSP_REG(PC)++; + unsp_push(UNSP_REG(PC), &UNSP_REG(SP)); + unsp_push(UNSP_REG(SR), &UNSP_REG(SP)); + UNSP_REG(PC) = r1; + UNSP_REG(SR) &= 0xffc0; + UNSP_REG(SR) |= OPIMM; + } + else + { + unimplemented_opcode(op); + } + break; + + // Far Jump + case 0x2f: case 0x3f: case 0x6f: case 0x7f: + if (OPA == 7 && OP1 == 2) + { + UNSP_REG(PC) = READ16(UNSP_LPC); + UNSP_REG(SR) &= 0xffc0; + UNSP_REG(SR) |= OPIMM; + } + break; + + // Multiply, Unsigned * Signed + case 0x0f: + if(OPN == 1 && OPA != 7) + { + lres = UNSP_REG_I(OPA) * UNSP_REG_I(OPB); + if(UNSP_REG_I(OPB) & 0x8000) + { + lres -= UNSP_REG_I(OPA) << 16; + } + UNSP_REG(R4) = lres >> 16; + UNSP_REG(R3) = (UINT16)lres; + break; + } + else + { + unimplemented_opcode(op); + } + break; + + // Multiply, Signed * Signed + case 0x4f: + if(OPN == 1 && OPA != 7) + { + lres = UNSP_REG_I(OPA) * UNSP_REG_I(OPB); + if(UNSP_REG_I(OPB) & 0x8000) + { + lres -= UNSP_REG_I(OPA) << 16; + } + if(UNSP_REG_I(OPA) & 0x8000) + { + lres -= UNSP_REG_I(OPB) << 16; + } + UNSP_REG(R4) = lres >> 16; + UNSP_REG(R3) = (UINT16)lres; + break; + } + else + { + unimplemented_opcode(op); + } + break; + + // Interrupt flags + case 0x5f: + if(OPA == 0) + { + switch(OPIMM) + { + case 0: + m_irq &= ~1; + m_fiq &= ~1; + break; + case 1: + m_irq |= 1; + m_fiq &= ~1; + break; + case 2: + m_irq &= ~1; + m_fiq |= 1; + break; + case 3: + m_irq |= 1; + m_fiq |= 1; + break; + case 8: // irq off + m_irq &= ~1; + break; + case 9: // irq on + m_irq |= 1; + break; + case 12: // fiq off + m_fiq &= ~1; + break; + case 13: // fiq on + m_fiq |= 1; + break; + case 37: // nop + break; + } + } + else + { + unimplemented_opcode(op); + } + break; + } + } + + m_icount -= 5; + m_icount = MAX(m_icount, 0); + } +} + + +/*****************************************************************************/ + +void unsp_device::execute_set_input(int irqline, int state) +{ + UINT16 irq_vector = 0; + + m_sirq &= ~(1 << irqline); + + if(!state) + { + logerror("clearing irq %d (%04x, %04x)\n", irqline, m_sirq, m_curirq); + return; + } + + switch (irqline) + { + case UNSP_IRQ0_LINE: + case UNSP_IRQ1_LINE: + case UNSP_IRQ2_LINE: + case UNSP_IRQ3_LINE: + case UNSP_IRQ4_LINE: + case UNSP_IRQ5_LINE: + case UNSP_IRQ6_LINE: + case UNSP_IRQ7_LINE: + if(m_fiq & 2) + { + // FIQ is being serviced, ignore this IRQ trigger. + m_sirq |= state << irqline; + return; + } + if(m_irq != 1) + { + // IRQ is disabled, ignore this IRQ trigger. + m_sirq |= state << irqline; + return; + } + m_irq |= 2; + m_curirq |= (1 << irqline); + logerror("taking irq %d (%04x, %04x)\n", irqline, m_sirq, m_curirq); + irq_vector = 0xfff8 + (irqline - UNSP_IRQ0_LINE); + break; + case UNSP_FIQ_LINE: + if(m_fiq != 1) + { + // FIQ is disabled, ignore this FIQ trigger. + m_sirq |= state << irqline; + return; + } + m_fiq |= 2; + m_curirq |= (1 << irqline); + logerror("taking fiq %d (%04x, %04x)\n", irqline, m_sirq, m_curirq); + irq_vector = 0xfff6; + break; + case UNSP_BRK_LINE: + break; + } + + m_saved_sb = m_sb; + unsp_push(UNSP_REG(PC), &UNSP_REG(SP)); + unsp_push(UNSP_REG(SR), &UNSP_REG(SP)); + UNSP_REG(PC) = READ16(irq_vector); + UNSP_REG(SR) = 0; +} diff --git a/src/devices/cpu/unsp/unsp.h b/src/devices/cpu/unsp/unsp.h new file mode 100644 index 00000000000..8d1ca02dd7e --- /dev/null +++ b/src/devices/cpu/unsp/unsp.h @@ -0,0 +1,113 @@ +// license:BSD-3-Clause +// copyright-holders:Ryan Holtz +/**************************\ +* +* SunPlus u'nSP emulator +* +* by Harmony +* +\**************************/ + +#pragma once + +#ifndef __UNSP_H__ +#define __UNSP_H__ + +enum +{ + UNSP_SP = 1, + UNSP_R1, + UNSP_R2, + UNSP_R3, + UNSP_R4, + UNSP_BP, + UNSP_SR, + UNSP_PC, + + UNSP_GPR_COUNT = UNSP_PC, + + UNSP_IRQ, + UNSP_FIQ, + UNSP_SB + +}; + +enum +{ + UNSP_IRQ0_LINE = 0, + UNSP_IRQ1_LINE, + UNSP_IRQ2_LINE, + UNSP_IRQ3_LINE, + UNSP_IRQ4_LINE, + UNSP_IRQ5_LINE, + UNSP_IRQ6_LINE, + UNSP_IRQ7_LINE, + UNSP_FIQ_LINE, + UNSP_BRK_LINE, + + UNSP_NUM_LINES +}; + + +class unsp_device : public cpu_device +{ +public: + // construction/destruction + unsp_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_execute_interface overrides + virtual UINT32 execute_min_cycles() const { return 5; } + virtual UINT32 execute_max_cycles() const { return 5; } + virtual UINT32 execute_input_lines() const { return 0; } + virtual void execute_run(); + virtual void execute_set_input(int inputnum, int state); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const { return (spacenum == AS_PROGRAM) ? &m_program_config : NULL; } + + // device_state_interface overrides + virtual void state_import(const device_state_entry &entry); + virtual void state_export(const device_state_entry &entry); + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const { return 2; } + virtual UINT32 disasm_max_opcode_bytes() const { return 4; } + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + +private: + address_space_config m_program_config; + + UINT16 m_r[16]; + UINT8 m_irq; + UINT8 m_fiq; + UINT16 m_curirq; + UINT16 m_sirq; + UINT8 m_sb; + UINT8 m_saved_sb; + + address_space *m_program; + int m_icount; + + UINT32 m_debugger_temp; + + void unimplemented_opcode(UINT16 op); + inline UINT16 READ16(UINT32 address); + inline void WRITE16(UINT32 address, UINT16 data); + inline void unsp_update_nz(UINT32 value); + inline void unsp_update_nzsc(UINT32 value, UINT16 r0, UINT16 r1); + inline void unsp_push(UINT16 value, UINT16 *reg); + inline UINT16 unsp_pop(UINT16 *reg); + + +}; + + +extern const device_type UNSP; + + +#endif /* __UNSP_H__ */ diff --git a/src/devices/cpu/unsp/unspdasm.c b/src/devices/cpu/unsp/unspdasm.c new file mode 100644 index 00000000000..19399dbf157 --- /dev/null +++ b/src/devices/cpu/unsp/unspdasm.c @@ -0,0 +1,272 @@ +// license:BSD-3-Clause +// copyright-holders:Ryan Holtz +/**************************\ +* +* SunPlus u'nSP disassembler +* +* by Harmony +* +\**************************/ + +#include "emu.h" +#include + +static char *output; + +static void ATTR_PRINTF(1,2) print(const char *fmt, ...) +{ + va_list vl; + + va_start(vl, fmt); + vsprintf(output, fmt, vl); + va_end(vl); +} + +/*****************************************************************************/ + +static const char *reg[] = +{ + "sp", "r1", "r2", "r3", "r4", "bp", "sr", "pc" +}; + +static const char *jmp[] = +{ + "jb", "jae", "jge", "jl", "jne", "je", "jpl", "jmi", + "jbe", "ja", "jle", "jg", "jvc", "jvs", "jmp", "" +}; + +static const char *alu[] = +{ + "add", "adc", "sub", "sbc", + "cmp", "", "neg", "", + "xor", "load", "or", "and", + "test", "store", "", "" +}; + +/*****************************************************************************/ + +#define OP0 (op >> 12) +#define OPA ((op >> 9) & 7) +#define OP1 ((op >> 6) & 7) +#define OPN ((op >> 3) & 7) +#define OPB (op & 7) +#define OPIMM (op & 0x3f) +#define OP2X ((OP0 < 14 && OP1 == 4 && (OPN >= 1 && OPN <= 3)) || (OP0 == 15 && (OP1 == 1 || OP1 == 2))) + +/*****************************************************************************/ + +#define UNSP_DASM_OK ((OP2X ? 2 : 1) | DASMFLAG_SUPPORTED) + +CPU_DISASSEMBLE( unsp ) +{ + UINT16 op = *(UINT16 *)oprom; + UINT16 imm16 = *(UINT16 *)(oprom + 2); + op = BIG_ENDIANIZE_INT16(op); + imm16 = BIG_ENDIANIZE_INT16(imm16); + + output = buffer; + + print(""); + + if(OP0 < 0xf && OPA == 0x7 && OP1 < 2) + { + print("%s %04x", jmp[OP0], OP1 ? (pc - OPIMM + 1) : (pc + OPIMM + 1)); + return UNSP_DASM_OK; + } + + switch((OP1 << 4) | OP0) + { + // ALU, Indexed + case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x06: case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: + print("%s %s, [bp+%02x]", alu[OP0], reg[OPA], OPIMM); + return UNSP_DASM_OK; + + // ALU, Immediate + case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x16: case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: + print("%s %s, %02x", alu[OP0], reg[OPA], OPIMM); + return UNSP_DASM_OK; + + // Pop / Interrupt return + case 0x29: + if(op == 0x9a90) + { + print("retf"); + return UNSP_DASM_OK; + } + else if(op == 0x9a98) + { + print("reti"); + return UNSP_DASM_OK; + } + else if((OPA + 1) < 8 && ((OPA + OPN) < 8)) + { + print("pop %s, %s [%s]", reg[OPA+1], reg[OPA+OPN], reg[OPB]); + return UNSP_DASM_OK; + } + break; + + // Push + case 0x2d: + if((OPA + 1) >= OPN && OPA < (OPN + 7)) + { + print("push %s, %s [%s]", reg[(OPA+1)-OPN], reg[OPA], reg[OPB]); + return UNSP_DASM_OK; + } + break; + + // ALU, Indirect + case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x36: case 0x38: case 0x39: case 0x3a: case 0x3b: case 0x3c: case 0x3d: + switch(OPN & 3) + { + case 0: + print("%s %s, [%s%s]", alu[OP0], reg[OPA], (OPN & 4) ? "ds:" : "", reg[OPB]); + return UNSP_DASM_OK; + case 1: + print("%s %s, [%s%s--]", alu[OP0], reg[OPA], (OPN & 4) ? "ds:" : "", reg[OPB]); + return UNSP_DASM_OK; + case 2: + print("%s %s, [%s%s++]", alu[OP0], reg[OPA], (OPN & 4) ? "ds:" : "", reg[OPB]); + return UNSP_DASM_OK; + case 3: + print("%s %s, [%s++%s]", alu[OP0], reg[OPA], (OPN & 4) ? "ds:" : "", reg[OPB]); + return UNSP_DASM_OK; + } + return UNSP_DASM_OK; + + // ALU, 16-bit ops + case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x46: case 0x48: case 0x49: case 0x4a: case 0x4b: case 0x4c: + switch(OPN) + { + // ALU, Register + case 0: + print("%s %s, %s", alu[OP0], reg[OPA], reg[OPB]); + return UNSP_DASM_OK; + + // ALU, 16-bit Immediate + case 1: + if(!((OP0 == 4 || OP0 == 6 || OP0 == 9 || OP0 == 12) && OPA != OPB)) + { + if(OP0 != 4 && OP0 != 12) + { + print("%s %s, %s, %04x", alu[OP0], reg[OPA], reg[OPB], imm16); + return UNSP_DASM_OK; + } + else + { + print("%s %s, %04x", alu[OP0], reg[OPB], imm16); + return UNSP_DASM_OK; + } + } + break; + + // ALU, Direct 16 + case 2: + print("%s %s, [%04x]", alu[OP0], reg[OPA], imm16); + return UNSP_DASM_OK; + + // ALU, Direct 16 + case 3: + print("%s [%04x], %s, %s", alu[OP0], imm16, reg[OPA], reg[OPB]); + return UNSP_DASM_OK; + + // ALU, Shifted + default: + print("%s %s, %s asr %d", alu[OP0], reg[OPA], reg[OPB], (OPN & 3) + 1); + return UNSP_DASM_OK; + } + case 0x4d: + if(OPN == 3) + { + if(OPA == OPB) + { + print("store [%04x], %s", imm16, reg[OPB]); + } + } + return UNSP_DASM_OK; + + // ALU, Shifted + case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x56: case 0x58: case 0x59: case 0x5a: case 0x5b: case 0x5c: + print("%s %s, %s %s %d", alu[OP0], reg[OPA], reg[OPB], (OPN & 4) ? ">>" : "<<", (OPN & 3) + 1); + return UNSP_DASM_OK; + + // ALU, Rotated + case 0x60: case 0x61: case 0x62: case 0x63: case 0x64: case 0x66: case 0x68: case 0x69: case 0x6a: case 0x6b: case 0x6c: + print("%s %s, %s %s %d", alu[OP0], reg[OPA], reg[OPB], (OPN & 4) ? "ror" : "rol", (OPN & 3) + 1); + return UNSP_DASM_OK; + + // ALU, Direct 8 + case 0x70: case 0x71: case 0x72: case 0x73: case 0x74: case 0x76: case 0x78: case 0x79: case 0x7a: case 0x7b: case 0x7c: + print("%s %s, [%02x]", alu[OP0], reg[OPA], OPIMM); + return UNSP_DASM_OK; + + // Call + case 0x1f: + if(OPA == 0) + { + print("call %06x", ((OPIMM << 16) | imm16) << 1); + } + return UNSP_DASM_OK; + + // Far Jump + case 0x2f: case 0x3f: case 0x6f: case 0x7f: + if (OPA == 7 && OP1 == 2) + { + print("goto %06x", ((OPIMM << 16) | imm16) << 1); + } + return UNSP_DASM_OK; + + // Multiply, Unsigned * Signed + case 0x0f: + if(OPN == 1 && OPA != 7) + { + print("mulus %s, %s", reg[OPA], reg[OPB]); + } + return UNSP_DASM_OK; + + // Multiply, Signed * Signed + case 0x4f: + if(OPN == 1 && OPA != 7) + { + print("mulss %s, %s", reg[OPA], reg[OPB]); + } + return UNSP_DASM_OK; + + // Interrupt flags + case 0x5f: + if(OPA == 0) + { + switch(OPIMM) + { + case 0: + print("int off"); + break; + case 1: + print("int irq"); + break; + case 2: + print("int fiq"); + break; + case 3: + print("int irq,fiq"); + break; + case 8: + print("irq off"); + break; + case 9: + print("irq on"); + break; + case 12: + print("fiq off"); + break; + case 14: + print("fiq on"); + break; + case 37: + print("nop"); + break; + } + } + return UNSP_DASM_OK; + } + return UNSP_DASM_OK; +} diff --git a/src/devices/cpu/upd7725/dasm7725.c b/src/devices/cpu/upd7725/dasm7725.c new file mode 100644 index 00000000000..987002412ac --- /dev/null +++ b/src/devices/cpu/upd7725/dasm7725.c @@ -0,0 +1,234 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont,byuu +/*************************************************************************** + + dasm7725.c + Disassembler for the portable uPD7725 emulator. + Written by byuu + MAME conversion by R. Belmont + +***************************************************************************/ + +#include "emu.h" +#include "upd7725.h" + +CPU_DISASSEMBLE( upd7725 ) +{ + static char output[256]; + UINT32 opcode = oprom[2] | (oprom[1] << 8) | (oprom[0] << 16); + UINT32 type = (opcode >> 22); + +// printf("dasm: PC %x opcode %08x\n", pc, opcode); + + memset(output, 0, sizeof(output)); + + if(type == 0 || type == 1) { //OP,RT + UINT8 pselect = (opcode >> 20)&0x3; //P select + UINT8 alu = (opcode >> 16)&0xf; //ALU operation mode + UINT8 asl = (opcode >> 15)&0x1; //accumulator select + UINT8 dpl = (opcode >> 13)&0x3; //DP low modify + UINT8 dphm = (opcode >> 9)&0xf; //DP high XOR modify + UINT8 rpdcr = (opcode >> 8)&0x1; //RP decrement + UINT8 src = (opcode >> 4)&0xf; //move source + UINT8 dst = (opcode >> 0)&0xf; //move destination + + switch(alu) { + case 0: strcat(output, "nop "); break; + case 1: strcat(output, "or "); break; + case 2: strcat(output, "and "); break; + case 3: strcat(output, "xor "); break; + case 4: strcat(output, "sub "); break; + case 5: strcat(output, "add "); break; + case 6: strcat(output, "sbb "); break; + case 7: strcat(output, "adc "); break; + case 8: strcat(output, "dec "); break; + case 9: strcat(output, "inc "); break; + case 10: strcat(output, "cmp "); break; + case 11: strcat(output, "shr1 "); break; + case 12: strcat(output, "shl1 "); break; + case 13: strcat(output, "shl2 "); break; + case 14: strcat(output, "shl4 "); break; + case 15: strcat(output, "xchg "); break; + } + + if(alu < 8) { + switch(pselect) { + case 0: strcat(output, "ram,"); break; + case 1: strcat(output, "idb,"); break; + case 2: strcat(output, "m,"); break; + case 3: strcat(output, "n,"); break; + } + } + + switch(asl) { + case 0: strcat(output, "a"); break; + case 1: strcat(output, "b"); break; + } + + if(dst) { + strcat(output, " | mov "); + + switch(src) { + case 0: strcat(output, "trb,"); break; + case 1: strcat(output, "a,"); break; + case 2: strcat(output, "b,"); break; + case 3: strcat(output, "tr,"); break; + case 4: strcat(output, "dp,"); break; + case 5: strcat(output, "rp,"); break; + case 6: strcat(output, "ro,"); break; + case 7: strcat(output, "sgn,"); break; + case 8: strcat(output, "dr,"); break; + case 9: strcat(output, "drnf,"); break; + case 10: strcat(output, "sr,"); break; + case 11: strcat(output, "sim,"); break; + case 12: strcat(output, "sil,"); break; + case 13: strcat(output, "k,"); break; + case 14: strcat(output, "l,"); break; + case 15: strcat(output, "mem,"); break; + } + + switch(dst) { + case 0: strcat(output, "non"); break; + case 1: strcat(output, "a"); break; + case 2: strcat(output, "b"); break; + case 3: strcat(output, "tr"); break; + case 4: strcat(output, "dp"); break; + case 5: strcat(output, "rp"); break; + case 6: strcat(output, "dr"); break; + case 7: strcat(output, "sr"); break; + case 8: strcat(output, "sol"); break; + case 9: strcat(output, "som"); break; + case 10: strcat(output, "k"); break; + case 11: strcat(output, "klr"); break; + case 12: strcat(output, "klm"); break; + case 13: strcat(output, "l"); break; + case 14: strcat(output, "trb"); break; + case 15: strcat(output, "mem"); break; + } + } + + if(dpl) { + switch(dpl) { + case 0: strcat(output, " | dpnop"); break; + case 1: strcat(output, " | dpinc"); break; + case 2: strcat(output, " | dpdec"); break; + case 3: strcat(output, " | dpclr"); break; + } + } + + if(dphm) { + switch(dphm) { + case 0: strcat(output, " | m0"); break; + case 1: strcat(output, " | m1"); break; + case 2: strcat(output, " | m2"); break; + case 3: strcat(output, " | m3"); break; + case 4: strcat(output, " | m4"); break; + case 5: strcat(output, " | m5"); break; + case 6: strcat(output, " | m6"); break; + case 7: strcat(output, " | m7"); break; + case 8: strcat(output, " | m8"); break; + case 9: strcat(output, " | m9"); break; + case 10: strcat(output, " | ma"); break; + case 11: strcat(output, " | mb"); break; + case 12: strcat(output, " | mc"); break; + case 13: strcat(output, " | md"); break; + case 14: strcat(output, " | me"); break; + case 15: strcat(output, " | mf"); break; + } + } + + if(rpdcr == 1) { + strcat(output, " | rpdec"); + } + + if(type == 1) { + strcat(output, " | ret"); + } + } + + if(type == 2) { //JP + UINT16 brch = (opcode >> 13) & 0x1ff; //branch + UINT16 na = (opcode >> 2) & 0x7ff; //next address + + switch(brch) { + case 0x000: strcat(output, "jmpso "); break; + case 0x080: strcat(output, "jnca "); break; + case 0x082: strcat(output, "jca "); break; + case 0x084: strcat(output, "jncb "); break; + case 0x086: strcat(output, "jcb "); break; + case 0x088: strcat(output, "jnza "); break; + case 0x08a: strcat(output, "jza "); break; + case 0x08c: strcat(output, "jnzb "); break; + case 0x08e: strcat(output, "jzb "); break; + case 0x090: strcat(output, "jnova0 "); break; + case 0x092: strcat(output, "jova0 "); break; + case 0x094: strcat(output, "jnovb0 "); break; + case 0x096: strcat(output, "jovb0 "); break; + case 0x098: strcat(output, "jnova1 "); break; + case 0x09a: strcat(output, "jova1 "); break; + case 0x09c: strcat(output, "jnovb1 "); break; + case 0x09e: strcat(output, "jovb1 "); break; + case 0x0a0: strcat(output, "jnsa0 "); break; + case 0x0a2: strcat(output, "jsa0 "); break; + case 0x0a4: strcat(output, "jnsb0 "); break; + case 0x0a6: strcat(output, "jsb0 "); break; + case 0x0a8: strcat(output, "jnsa1 "); break; + case 0x0aa: strcat(output, "jsa1 "); break; + case 0x0ac: strcat(output, "jnsb1 "); break; + case 0x0ae: strcat(output, "jsb1 "); break; + case 0x0b0: strcat(output, "jdpl0 "); break; + case 0x0b1: strcat(output, "jdpln0 "); break; + case 0x0b2: strcat(output, "jdplf "); break; + case 0x0b3: strcat(output, "jdplnf "); break; + case 0x0b4: strcat(output, "jnsiak "); break; + case 0x0b6: strcat(output, "jsiak "); break; + case 0x0b8: strcat(output, "jnsoak "); break; + case 0x0ba: strcat(output, "jsoak "); break; + case 0x0bc: strcat(output, "jnrqm "); break; + case 0x0be: strcat(output, "jrqm "); break; + case 0x100: strcat(output, "ljmp "); break; + case 0x101: strcat(output, "hjmp "); break; + case 0x140: strcat(output, "lcall "); break; + case 0x141: strcat(output, "hcall "); break; + default: strcat(output, "?????? "); break; + } + + char temp[16]; + + sprintf(temp, "$%x", na); + strcat(output, temp); + } + + if(type == 3) { //LD + strcat(output, "ld "); + UINT16 id = opcode >> 6; + UINT8 dst = (opcode >> 0) & 0xf; //destination + + char temp[16]; + sprintf(temp, "$%x,", id); + strcat(output, temp); + + switch(dst) { + case 0: strcat(output, "non"); break; + case 1: strcat(output, "a"); break; + case 2: strcat(output, "b"); break; + case 3: strcat(output, "tr"); break; + case 4: strcat(output, "dp"); break; + case 5: strcat(output, "rp"); break; + case 6: strcat(output, "dr"); break; + case 7: strcat(output, "sr"); break; + case 8: strcat(output, "sol"); break; + case 9: strcat(output, "som"); break; + case 10: strcat(output, "k"); break; + case 11: strcat(output, "klr"); break; + case 12: strcat(output, "klm"); break; + case 13: strcat(output, "l"); break; + case 14: strcat(output, "trb"); break; + case 15: strcat(output, "mem"); break; + } + } + + strcpy(buffer, output); + + return 1 | DASMFLAG_SUPPORTED; +} diff --git a/src/devices/cpu/upd7725/upd7725.c b/src/devices/cpu/upd7725/upd7725.c new file mode 100644 index 00000000000..d422eae21b0 --- /dev/null +++ b/src/devices/cpu/upd7725/upd7725.c @@ -0,0 +1,622 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont,byuu +/*************************************************************************** + + upd7725.c + + Core implementation for the portable NEC uPD7725/uPD96050 emulator + + Original by byuu in the public domain. + MAME conversion by R. Belmont + +****************************************************************************/ + +#include "emu.h" +#include "debugger.h" +#include "upd7725.h" + + +//************************************************************************** +// DEVICE INTERFACE +//************************************************************************** + +// device type definition +const device_type UPD7725 = &device_creator; +const device_type UPD96050 = &device_creator; + +necdsp_device::necdsp_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, UINT32 clock, UINT32 abits, UINT32 dbits, const char *name, const char *shortname, const char *source) + : cpu_device(mconfig, type, name, tag, owner, clock, shortname, source), + m_program_config("program", ENDIANNESS_BIG, 32, abits, -2), // data bus width, address bus width, -2 means DWORD-addressable + m_data_config("data", ENDIANNESS_BIG, 16, dbits, -1), // -1 for WORD-addressable + m_irq(0), + m_program(NULL), + m_data(NULL), + m_direct(NULL), + m_in_int_cb(*this), + //m_in_si_cb(*this), + //m_in_sck_cb(*this), + //m_in_sien_cb(*this), + //m_in_soen_cb(*this), + //m_in_dack_cb(*this), + m_out_p0_cb(*this), + m_out_p1_cb(*this) + //m_out_so_cb(*this), + //m_out_sorq_cb(*this), + //m_out_drq_cb(*this) +{ +} + + +upd7725_device::upd7725_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : necdsp_device(mconfig, UPD7725, tag, owner, clock, 11, 11, "uPD7725", "upd7725", __FILE__) +{ +} + +upd96050_device::upd96050_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : necdsp_device(mconfig, UPD96050, tag, owner, clock, 14, 12, "uPD96050", "upd96050", __FILE__) +{ +} + +//------------------------------------------------- +// device_start - start up the device +//------------------------------------------------- + +void necdsp_device::device_start() +{ + // get our address spaces + m_program = &space(AS_PROGRAM); + m_data = &space(AS_DATA); + m_direct = &m_program->direct(); + + // register our state for the debugger + std::string tempstr; + state_add(STATE_GENPC, "GENPC", regs.pc).noshow(); + state_add(UPD7725_PC, "PC", regs.pc); + state_add(UPD7725_RP, "RP", regs.rp); + state_add(UPD7725_DP, "DP", regs.dp); + state_add(UPD7725_SP, "SP", regs.sp); + state_add(UPD7725_K, "K", regs.k); + state_add(UPD7725_L, "L", regs.l); + state_add(UPD7725_M, "M", regs.m); + state_add(UPD7725_N, "N", regs.n); + state_add(UPD7725_A, "A", regs.a); + state_add(UPD7725_B, "B", regs.b); + state_add(UPD7725_TR, "TR", regs.tr); + state_add(UPD7725_TRB, "TRB", regs.trb); + state_add(UPD7725_DR, "DR", regs.dr); + state_add(UPD7725_SI, "SI", regs.si); + state_add(UPD7725_SO, "SO", regs.so); + state_add(UPD7725_IDB, "IDB", regs.idb); + + // resolve callbacks + m_in_int_cb.resolve_safe(0); + //m_in_si_cb.resolve_safe(0); + //m_in_sck_cb.resolve_safe(0); + //m_in_sien_cb.resolve_safe(0); + //m_in_soen_cb.resolve_safe(0); + //m_in_dack_cb.resolve_safe(0); + m_out_p0_cb.resolve_safe(); + m_out_p1_cb.resolve_safe(); + //m_out_so_cb.resolve_safe(); + //m_out_sorq_cb.resolve_safe(); + //m_out_drq_cb.resolve_safe(); + + // save state registrations + save_item(NAME(regs.pc)); + save_item(NAME(regs.rp)); + save_item(NAME(regs.dp)); + save_item(NAME(regs.sp)); + save_item(NAME(regs.k)); + save_item(NAME(regs.l)); + save_item(NAME(regs.m)); + save_item(NAME(regs.n)); + save_item(NAME(regs.a)); + save_item(NAME(regs.b)); + save_item(NAME(regs.tr)); + save_item(NAME(regs.trb)); + save_item(NAME(regs.dr)); + save_item(NAME(regs.so)); + save_item(NAME(regs.idb)); + save_item(NAME(regs.sr.rqm)); + save_item(NAME(regs.sr.usf0)); + save_item(NAME(regs.sr.usf1)); + save_item(NAME(regs.sr.drs)); + save_item(NAME(regs.sr.dma)); + save_item(NAME(regs.sr.drc)); + save_item(NAME(regs.sr.soc)); + save_item(NAME(regs.sr.sic)); + save_item(NAME(regs.sr.ei)); + save_item(NAME(regs.sr.p0)); + save_item(NAME(regs.sr.p1)); + save_item(NAME(regs.stack)); + save_item(NAME(dataRAM)); + + m_icountptr = &m_icount; +} + +//------------------------------------------------- +// device_reset - reset the device +//------------------------------------------------- + +void necdsp_device::device_reset() +{ + for (unsigned i = 0; i < 2048; i++) + { + dataRAM[i] = 0x0000; + } + + regs.pc = 0x0000; + regs.rp = 0x0000; + regs.dp = 0x0000; + regs.sp = 0x0; + regs.k = 0x0000; + regs.l = 0x0000; + regs.m = 0x0000; + regs.n = 0x0000; + regs.a = 0x0000; + regs.b = 0x0000; + regs.flaga = 0x00; + regs.flagb = 0x00; + regs.tr = 0x0000; + regs.trb = 0x0000; + regs.sr = 0x0000; + regs.dr = 0x0000; + regs.si = 0x0000; + regs.so = 0x0000; + regs.idb = 0x0000; +} + +//------------------------------------------------- +// memory_space_config - return the configuration +// of the specified address space, or NULL if +// the space doesn't exist +//------------------------------------------------- + +const address_space_config *necdsp_device::memory_space_config(address_spacenum spacenum) const +{ + return (spacenum == AS_PROGRAM) ? &m_program_config : &m_data_config; +} + + +//------------------------------------------------- +// state_import - import state into the device, +// after it has been set +//------------------------------------------------- + +void necdsp_device::state_import(const device_state_entry &entry) +{ +} + + +//------------------------------------------------- +// state_export - export state from the device, +// to a known location where it can be read +//------------------------------------------------- + +void necdsp_device::state_export(const device_state_entry &entry) +{ +} + + +//------------------------------------------------- +// state_string_export - export state as a string +// for the debugger +//------------------------------------------------- + +void necdsp_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + switch (entry.index()) + { + case UPD7725_FLAGA: + strprintf(str, "%s %s %c%c %s %s %s %s", + regs.flaga.s1 ? "S1" : "s1", + regs.flaga.s0 ? "S0" : "s0", + regs.flaga.c ? 'C' : 'c', + regs.flaga.z ? 'Z' : 'z', + regs.flaga.ov1 ? "OV1" : "ov1", + regs.flaga.ov0 ? "OV0" : "ov0", + regs.flaga.ov0p ? "OV0P" : "ov0p", + regs.flaga.ov0pp ? "OV0PP" : "ov0pp"); + break; + + case UPD7725_FLAGB: + strprintf(str, "%s %s %c%c %s %s %s %s", + regs.flagb.s1 ? "S1" : "s1", + regs.flagb.s0 ? "S0" : "s0", + regs.flagb.c ? 'C' : 'c', + regs.flagb.z ? 'Z' : 'z', + regs.flagb.ov1 ? "OV1" : "ov1", + regs.flagb.ov0 ? "OV0" : "ov0", + regs.flagb.ov0p ? "OV0P" : "ov0p", + regs.flagb.ov0pp ? "OV0PP" : "ov0pp"); + break; + } +} + +//------------------------------------------------- +// execute_min_cycles - return minimum number of +// cycles it takes for one instruction to execute +//------------------------------------------------- + +UINT32 necdsp_device::execute_min_cycles() const +{ + return 4; +} + + +//------------------------------------------------- +// execute_max_cycles - return maximum number of +// cycles it takes for one instruction to execute +//------------------------------------------------- + +UINT32 necdsp_device::execute_max_cycles() const +{ + return 4; +} + + +//------------------------------------------------- +// execute_input_lines - return the number of +// input/interrupt lines +//------------------------------------------------- + +UINT32 necdsp_device::execute_input_lines() const +{ + return 3; // TODO: there should be 11: INT, SCK, /SIEN, /SOEN, SI, and /DACK, plus SO, /SORQ and DRQ; for now, just INT, P0, and P1 are enough. +} + + +//------------------------------------------------- +// execute_set_input - +//------------------------------------------------- + +void necdsp_device::execute_set_input(int inputnum, int state) +{ + switch (inputnum) + { + case NECDSP_INPUT_LINE_INT: + //TODO: detect rising edge; if rising edge found AND IE = 1, push PC, pc = 0x100; else do nothing + m_irq = state; // set old state to current state + break; + // add more when needed + } +} + +//------------------------------------------------- +// disasm_min_opcode_bytes - return the length +// of the shortest instruction, in bytes +//------------------------------------------------- + +UINT32 necdsp_device::disasm_min_opcode_bytes() const +{ + return 4; +} + + +//------------------------------------------------- +// disasm_max_opcode_bytes - return the length +// of the longest instruction, in bytes +//------------------------------------------------- + +UINT32 necdsp_device::disasm_max_opcode_bytes() const +{ + return 4; +} + +//------------------------------------------------- +// disasm_disassemble - call the disassembly +// helper function +//------------------------------------------------- + +offs_t necdsp_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( upd7725 ); + return CPU_DISASSEMBLE_NAME(upd7725)(this, buffer, pc, oprom, opram, options); +} + +void necdsp_device::execute_run() +{ + UINT32 opcode; + + do + { + // call debugger hook if necessary + if (device_t::machine().debug_flags & DEBUG_FLAG_ENABLED) + { + debugger_instruction_hook(this, regs.pc); + } + + opcode = m_direct->read_dword(regs.pc<<2)>>8; + regs.pc++; + switch(opcode >> 22) + { + case 0: exec_op(opcode); break; + case 1: exec_rt(opcode); break; + case 2: exec_jp(opcode); break; + case 3: exec_ld(opcode); break; + } + + INT32 result = (INT32)regs.k * regs.l; //sign + 30-bit result + regs.m = result >> 15; //store sign + top 15-bits + regs.n = result << 1; //store low 15-bits + zero + + m_icount--; + + } while (m_icount > 0); +} + +void necdsp_device::exec_op(UINT32 opcode) { + UINT8 pselect = (opcode >> 20)&0x3; //P select + UINT8 alu = (opcode >> 16)&0xf; //ALU operation mode + UINT8 asl = (opcode >> 15)&0x1; //accumulator select + UINT8 dpl = (opcode >> 13)&0x3; //DP low modify + UINT8 dphm = (opcode >> 9)&0xf; //DP high XOR modify + UINT8 rpdcr = (opcode >> 8)&0x1; //RP decrement + UINT8 src = (opcode >> 4)&0xf; //move source + UINT8 dst = (opcode >> 0)&0xf; //move destination + + switch(src) { + case 0: regs.idb = regs.trb; break; + case 1: regs.idb = regs.a; break; + case 2: regs.idb = regs.b; break; + case 3: regs.idb = regs.tr; break; + case 4: regs.idb = regs.dp; break; + case 5: regs.idb = regs.rp; break; + case 6: regs.idb = m_data->read_word(regs.rp<<1); break; + case 7: regs.idb = 0x8000 - regs.flaga.s1; break; //SGN + case 8: regs.idb = regs.dr; regs.sr.rqm = 1; break; + case 9: regs.idb = regs.dr; break; + case 10: regs.idb = regs.sr; break; + case 11: regs.idb = regs.si; break; //MSB + case 12: regs.idb = regs.si; break; //LSB + case 13: regs.idb = regs.k; break; + case 14: regs.idb = regs.l; break; + case 15: regs.idb = dataRAM[regs.dp]; break; + } + + if(alu) { + UINT16 p=0, q=0, r=0; + Flag flag; + bool c=0; + + flag.c = 0; + flag.s1 = 0; + flag.ov0 = 0; + flag.ov1 = 0; + flag.ov0p = 0; + flag.ov0pp = 0; + + switch(pselect) { + case 0: p = dataRAM[regs.dp]; break; + case 1: p = regs.idb; break; + case 2: p = regs.m; break; + case 3: p = regs.n; break; + } + + switch(asl) { + case 0: q = regs.a; flag = regs.flaga; c = regs.flagb.c; break; + case 1: q = regs.b; flag = regs.flagb; c = regs.flaga.c; break; + } + + switch(alu) { + case 1: r = q | p; break; //OR + case 2: r = q & p; break; //AND + case 3: r = q ^ p; break; //XOR + case 4: r = q - p; break; //SUB + case 5: r = q + p; break; //ADD + case 6: r = q - p - c; break; //SBB + case 7: r = q + p + c; break; //ADC + case 8: r = q - 1; p = 1; break; //DEC + case 9: r = q + 1; p = 1; break; //INC + case 10: r = ~q; break; //CMP + case 11: r = (q >> 1) | (q & 0x8000); break; //SHR1 (ASR) + case 12: r = (q << 1) | (c ? 1 : 0); break; //SHL1 (ROL) + case 13: r = (q << 2) | 3; break; //SHL2 + case 14: r = (q << 4) | 15; break; //SHL4 + case 15: r = (q << 8) | (q >> 8); break; //XCHG + } + + flag.s0 = (r & 0x8000); + flag.z = (r == 0); + flag.ov0pp = flag.ov0p; + flag.ov0p = flag.ov0; + + switch(alu) { + case 1: case 2: case 3: case 10: case 13: case 14: case 15: { + flag.c = 0; + flag.ov0 = flag.ov0p = flag.ov0pp = 0; // ASSUMPTION: previous ov0 values are nulled here to make ov1 zero + break; + } + case 4: case 5: case 6: case 7: case 8: case 9: { + if(alu & 1) { + //addition + flag.ov0 = (q ^ r) & ~(q ^ p) & 0x8000; + flag.c = (r < q); + } else { + //subtraction + flag.ov0 = (q ^ r) & (q ^ p) & 0x8000; + flag.c = (r > q); + } + break; + } + case 11: { + flag.c = q & 1; + flag.ov0 = flag.ov0p = flag.ov0pp = 0; // ASSUMPTION: previous ov0 values are nulled here to make ov1 zero + break; + } + case 12: { + flag.c = q >> 15; + flag.ov0 = flag.ov0p = flag.ov0pp = 0; // ASSUMPTION: previous ov0 values are nulled here to make ov1 zero + break; + } + } + // flag.ov1 is only set if the number of overflows of the past 3 opcodes (of type 4,5,6,7,8,9) is odd + flag.ov1 = (flag.ov0 + flag.ov0p + flag.ov0pp) & 1; + // flag.s1 is based on ov1: s1 = ov1 ^ s0; + flag.s1 = flag.ov1 ^ flag.s0; + + switch(asl) { + case 0: regs.a = r; regs.flaga = flag; break; + case 1: regs.b = r; regs.flagb = flag; break; + } + } + + exec_ld((regs.idb << 6) + dst); + + switch(dpl) { + case 1: regs.dp = (regs.dp & 0xf0) + ((regs.dp + 1) & 0x0f); break; //DPINC + case 2: regs.dp = (regs.dp & 0xf0) + ((regs.dp - 1) & 0x0f); break; //DPDEC + case 3: regs.dp = (regs.dp & 0xf0); break; //DPCLR + } + + regs.dp ^= dphm << 4; + + if(rpdcr) regs.rp--; +} + +void necdsp_device::exec_rt(UINT32 opcode) { + exec_op(opcode); + regs.pc = regs.stack[--regs.sp]; + regs.sp &= 0xf; +} + +void necdsp_device::exec_jp(UINT32 opcode) { + UINT16 brch = (opcode >> 13) & 0x1ff; //branch + UINT16 na = (opcode >> 2) & 0x7ff; //next address + UINT16 bank = (opcode >> 0) & 0x3; //bank address + + UINT16 jps = (regs.pc & 0x2000) | (bank << 11) | (na << 0); + UINT16 jpl = (bank << 11) | (na << 0); + + switch(brch) { + case 0x000: regs.pc = regs.so; return; //JMPSO + + case 0x080: if(regs.flaga.c == 0) regs.pc = jps; return; //JNCA + case 0x082: if(regs.flaga.c == 1) regs.pc = jps; return; //JCA + case 0x084: if(regs.flagb.c == 0) regs.pc = jps; return; //JNCB + case 0x086: if(regs.flagb.c == 1) regs.pc = jps; return; //JCB + + case 0x088: if(regs.flaga.z == 0) regs.pc = jps; return; //JNZA + case 0x08a: if(regs.flaga.z == 1) regs.pc = jps; return; //JZA + case 0x08c: if(regs.flagb.z == 0) regs.pc = jps; return; //JNZB + case 0x08e: if(regs.flagb.z == 1) regs.pc = jps; return; //JZB + + case 0x090: if(regs.flaga.ov0 == 0) regs.pc = jps; return; //JNOVA0 + case 0x092: if(regs.flaga.ov0 == 1) regs.pc = jps; return; //JOVA0 + case 0x094: if(regs.flagb.ov0 == 0) regs.pc = jps; return; //JNOVB0 + case 0x096: if(regs.flagb.ov0 == 1) regs.pc = jps; return; //JOVB0 + + case 0x098: if(regs.flaga.ov1 == 0) regs.pc = jps; return; //JNOVA1 + case 0x09a: if(regs.flaga.ov1 == 1) regs.pc = jps; return; //JOVA1 + case 0x09c: if(regs.flagb.ov1 == 0) regs.pc = jps; return; //JNOVB1 + case 0x09e: if(regs.flagb.ov1 == 1) regs.pc = jps; return; //JOVB1 + + case 0x0a0: if(regs.flaga.s0 == 0) regs.pc = jps; return; //JNSA0 + case 0x0a2: if(regs.flaga.s0 == 1) regs.pc = jps; return; //JSA0 + case 0x0a4: if(regs.flagb.s0 == 0) regs.pc = jps; return; //JNSB0 + case 0x0a6: if(regs.flagb.s0 == 1) regs.pc = jps; return; //JSB0 + + case 0x0a8: if(regs.flaga.s1 == 0) regs.pc = jps; return; //JNSA1 + case 0x0aa: if(regs.flaga.s1 == 1) regs.pc = jps; return; //JSA1 + case 0x0ac: if(regs.flagb.s1 == 0) regs.pc = jps; return; //JNSB1 + case 0x0ae: if(regs.flagb.s1 == 1) regs.pc = jps; return; //JSB1 + + case 0x0b0: if((regs.dp & 0x0f) == 0x00) regs.pc = jps; return; //JDPL0 + case 0x0b1: if((regs.dp & 0x0f) != 0x00) regs.pc = jps; return; //JDPLN0 + case 0x0b2: if((regs.dp & 0x0f) == 0x0f) regs.pc = jps; return; //JDPLF + case 0x0b3: if((regs.dp & 0x0f) != 0x0f) regs.pc = jps; return; //JDPLNF + + case 0x0bc: if(regs.sr.rqm == 0) regs.pc = jps; return; //JNRQM + case 0x0be: if(regs.sr.rqm == 1) regs.pc = jps; return; //JRQM + + case 0x100: regs.pc = 0x0000 | jpl; return; //LJMP + case 0x101: regs.pc = 0x2000 | jpl; return; //HJMP + + case 0x140: regs.stack[regs.sp++] = regs.pc; regs.pc = 0x0000 | jpl; regs.sp &= 0xf; return; //LCALL + case 0x141: regs.stack[regs.sp++] = regs.pc; regs.pc = 0x2000 | jpl; regs.sp &= 0xf; return; //HCALL + } +} + +void necdsp_device::exec_ld(UINT32 opcode) { + UINT16 id = opcode >> 6; //immediate data + UINT8 dst = (opcode >> 0) & 0xf; //destination + + regs.idb = id; + + switch(dst) { + case 0: break; + case 1: regs.a = id; break; + case 2: regs.b = id; break; + case 3: regs.tr = id; break; + case 4: regs.dp = id; break; + case 5: regs.rp = id; break; + case 6: regs.dr = id; regs.sr.rqm = 1; break; + case 7: regs.sr = (regs.sr & 0x907c) | (id & ~0x907c); + m_out_p0_cb(regs.sr&0x1); + m_out_p1_cb((regs.sr&0x2)>>1); + break; + case 8: regs.so = id; break; //LSB + case 9: regs.so = id; break; //MSB + case 10: regs.k = id; break; + case 11: regs.k = id; regs.l = m_data->read_word(regs.rp<<1); break; + case 12: regs.l = id; regs.k = dataRAM[regs.dp | 0x40]; break; + case 13: regs.l = id; break; + case 14: regs.trb = id; break; + case 15: dataRAM[regs.dp] = id; break; + } +} + +UINT8 necdsp_device::snesdsp_read(bool mode) { + if (!mode) + { + return regs.sr >> 8; + } + + if (regs.sr.drc == 0) + { + //16-bit + if(regs.sr.drs == 0) + { + regs.sr.drs = 1; + return regs.dr >> 0; + } + else + { + regs.sr.rqm = 0; + regs.sr.drs = 0; + return regs.dr >> 8; + } + } + else + { + //8-bit + regs.sr.rqm = 0; + return regs.dr >> 0; + } +} + +void necdsp_device::snesdsp_write(bool mode, UINT8 data) { + if (!mode) return; + + if (regs.sr.drc == 0) + { + //16-bit + if (regs.sr.drs == 0) + { + regs.sr.drs = 1; + regs.dr = (regs.dr & 0xff00) | (data << 0); + } + else + { + regs.sr.rqm = 0; + regs.sr.drs = 0; + regs.dr = (data << 8) | (regs.dr & 0x00ff); + } + } + else + { + //8-bit + regs.sr.rqm = 0; + regs.dr = (regs.dr & 0xff00) | (data << 0); + } +} diff --git a/src/devices/cpu/upd7725/upd7725.h b/src/devices/cpu/upd7725/upd7725.h new file mode 100644 index 00000000000..d10094073c3 --- /dev/null +++ b/src/devices/cpu/upd7725/upd7725.h @@ -0,0 +1,264 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont,byuu +/*************************************************************************** + + upd7725.h + + Core implementation for the portable NEC uPD7725/uPD96050 emulator + +****************************************************************************/ + +#pragma once + +#ifndef __UPD7725_H__ +#define __UPD7725_H__ + +//************************************************************************** +// ENUMERATIONS +//************************************************************************** + +// input lines +enum +{ + NECDSP_INPUT_LINE_INT = 0 + // add more here as needed +}; + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class necdsp_device; +class upd7725_device; +class upd96050_device; + + +#define MCFG_NECDSP_IN_INT_CB(_devcb) \ + devcb = &necdsp_device::set_in_int_callback(*device, DEVCB_##_devcb); + +#define MCFG_NECDSP_IN_SI_CB(_devcb) \ + devcb = &necdsp_device::set_in_si_callback(*device, DEVCB_##_devcb); + +#define MCFG_NECDSP_IN_SCK_CB(_devcb) \ + devcb = &necdsp_device::set_in_sck_callback(*device, DEVCB_##_devcb); + +#define MCFG_NECDSP_IN_SIEN_CB(_devcb) \ + devcb = &necdsp_device::set_in_sien_callback(*device, DEVCB_##_devcb); + +#define MCFG_NECDSP_IN_SOEN_CB(_devcb) \ + devcb = &necdsp_device::set_in_soen_callback(*device, DEVCB_##_devcb); + +#define MCFG_NECDSP_IN_DACK_CB(_devcb) \ + devcb = &necdsp_device::set_in_dack_callback(*device, DEVCB_##_devcb); + +#define MCFG_NECDSP_OUT_P0_CB(_devcb) \ + devcb = &necdsp_device::set_out_p0_callback(*device, DEVCB_##_devcb); + +#define MCFG_NECDSP_OUT_P1_CB(_devcb) \ + devcb = &necdsp_device::set_out_p1_callback(*device, DEVCB_##_devcb); + +#define MCFG_NECDSP_OUT_SO_CB(_devcb) \ + devcb = &necdsp_device::set_out_so_callback(*device, DEVCB_##_devcb); + +#define MCFG_NECDSP_OUT_SORQ_CB(_devcb) \ + devcb = &necdsp_device::set_out_sorq_callback(*device, DEVCB_##_devcb); + +#define MCFG_NECDSP_OUT_DRQ_CB(_devcb) \ + devcb = &necdsp_device::set_out_drq_callback(*device, DEVCB_##_devcb); + + +// ======================> necdsp_device + +class necdsp_device : public cpu_device +{ +protected: + // construction/destruction + necdsp_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, UINT32 clock, UINT32 abits, UINT32 dbits, const char *name, const char *shortname, const char *source); + +public: + + template static devcb_base &set_in_int_callback(device_t &device, _Object object) { return downcast(device).m_in_int_cb.set_callback(object); } + //template static devcb_base &set_in_si_callback(device_t &device, _Object object) { return downcast(device).m_in_si_cb.set_callback(object); } + //template static devcb_base &set_in_sck_callback(device_t &device, _Object object) { return downcast(device).m_in_sck_cb.set_callback(object); } + //template static devcb_base &set_in_sien_callback(device_t &device, _Object object) { return downcast(device).m_in_sien_cb.set_callback(object); } + //template static devcb_base &set_in_soen_callback(device_t &device, _Object object) { return downcast(device).m_in_soen_cb.set_callback(object); } + //template static devcb_base &set_in_dack_callback(device_t &device, _Object object) { return downcast(device).m_in_dack_cb.set_callback(object); } + template static devcb_base &set_out_p0_callback(device_t &device, _Object object) { return downcast(device).m_out_p0_cb.set_callback(object); } + template static devcb_base &set_out_p1_callback(device_t &device, _Object object) { return downcast(device).m_out_p1_cb.set_callback(object); } + //template static devcb_base &set_out_so_callback(device_t &device, _Object object) { return downcast(device).m_out_so_cb.set_callback(object); } + //template static devcb_base &set_out_sorq_callback(device_t &device, _Object object) { return downcast(device).m_out_sorq_cb.set_callback(object); } + //template static devcb_base &set_out_drq_callback(device_t &device, _Object object) { return downcast(device).m_out_drq_cb.set_callback(object); } + + UINT8 snesdsp_read(bool mode); + void snesdsp_write(bool mode, UINT8 data); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_execute_interface overrides + virtual UINT32 execute_min_cycles() const; + virtual UINT32 execute_max_cycles() const; + virtual UINT32 execute_input_lines() const; + virtual void execute_run(); + virtual void execute_set_input(int inputnum, int state); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const; + + // device_state_interface overrides + virtual void state_import(const device_state_entry &entry); + virtual void state_export(const device_state_entry &entry); + virtual void state_string_export(const device_state_entry &entry, std::string &str); + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const; + virtual UINT32 disasm_max_opcode_bytes() const; + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + + // inline data + const address_space_config m_program_config, m_data_config; + + UINT16 dataRAM[2048]; + +private: + struct Flag + { + bool s1, s0, c, z, ov1, ov0, ov0p, ov0pp; + + inline operator unsigned() const + { + return (s1 << 7) + (s0 << 6) + (c << 5) + (z << 4) + (ov1 << 3) + (ov0 << 2) + (ov0p << 1) + (ov0pp << 0); + } + + inline unsigned operator=(unsigned d) + { + s1 = d & 0x80; s0 = d & 0x40; c = d & 0x20; z = d & 0x10; ov1 = d & 0x08; ov0 = d & 0x04; ov0p = d & 0x02; ov0pp = d & 0x01; + return d; + } + }; + + struct Status + { + bool rqm, usf1, usf0, drs, dma, drc, soc, sic, ei, p1, p0; + + inline operator unsigned() const + { + return (rqm << 15) + (usf1 << 14) + (usf0 << 13) + (drs << 12) + + (dma << 11) + (drc << 10) + (soc << 9) + (sic << 8) + + (ei << 7) + (p1 << 1) + (p0 << 0); + } + + inline unsigned operator=(unsigned d) + { + rqm = d & 0x8000; usf1 = d & 0x4000; usf0 = d & 0x2000; drs = d & 0x1000; + dma = d & 0x0800; drc = d & 0x0400; soc = d & 0x0200; sic = d & 0x0100; + ei = d & 0x0080; p1 = d & 0x0002; p0 = d & 0x0001; + return d; + } + }; + + struct Regs + { + UINT16 pc; //program counter + UINT16 stack[16]; //LIFO + UINT16 rp; //ROM pointer + UINT16 dp; //data pointer + UINT8 sp; //stack pointer + INT16 k; + INT16 l; + INT16 m; + INT16 n; + INT16 a; //accumulator + INT16 b; //accumulator + Flag flaga; + Flag flagb; + UINT16 tr; //temporary register + UINT16 trb; //temporary register + Status sr; //status register + UINT16 dr; //data register + UINT16 si; + UINT16 so; + UINT16 idb; + } regs; + + void exec_op(UINT32 opcode); + void exec_rt(UINT32 opcode); + void exec_jp(UINT32 opcode); + void exec_ld(UINT32 opcode); + + void stack_push(); + void stack_pull(); + + int m_icount; + int m_irq; // old irq line state, for detecting rising edges. + + address_space *m_program, *m_data; + direct_read_data *m_direct; + +protected: +// device callbacks + devcb_read_line m_in_int_cb; + //devcb_read8 m_in_si_cb; + //devcb_read_line m_in_sck_cb; + //devcb_read_line m_in_sien_cb; + //devcb_read_line m_in_soen_cb; + //devcb_read_line m_in_dack_cb; + devcb_write_line m_out_p0_cb; + devcb_write_line m_out_p1_cb; + //devcb_write8 m_out_so_cb; + //devcb_write_line m_out_sorq_cb; + //devcb_write_line m_out_drq_cb; +}; + +class upd7725_device : public necdsp_device +{ +public: + // construction/destruction + upd7725_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class upd96050_device : public necdsp_device +{ +public: + // construction/destruction + upd96050_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + UINT16 dataram_r(UINT16 addr) { return dataRAM[addr]; } + void dataram_w(UINT16 addr, UINT16 data) { dataRAM[addr] = data; } +}; + +// device type definition +extern const device_type UPD7725; +extern const device_type UPD96050; + +//************************************************************************** +// ENUMERATIONS +//************************************************************************** + +// registers +enum +{ + UPD7725_PC = 1, + UPD7725_RP, + UPD7725_DP, + UPD7725_K, + UPD7725_L, + UPD7725_M, + UPD7725_N, + UPD7725_A, + UPD7725_B, + UPD7725_FLAGA, + UPD7725_FLAGB, + UPD7725_SR, + UPD7725_DR, + UPD7725_SP, + UPD7725_TR, + UPD7725_TRB, + UPD7725_SI, + UPD7725_SO, + UPD7725_IDB +}; + +#endif /* __UPD7725_H__ */ diff --git a/src/devices/cpu/upd7810/upd7810.c b/src/devices/cpu/upd7810/upd7810.c new file mode 100644 index 00000000000..f22ccb07b4f --- /dev/null +++ b/src/devices/cpu/upd7810/upd7810.c @@ -0,0 +1,1984 @@ +// license:BSD-3-Clause +// copyright-holders:Juergen Buchmueller +/***************************************************************************** + * + * upd7810.c + * Portable uPD7810/11, 7810H/11H, 78C10/C11/C14 emulator V0.3 + * + * This work is based on the + * "NEC Electronics User's Manual, April 1987" + * + * NS20030115: + * - fixed INRW_wa() + * - TODO: add 7807, differences are listed below. + * I only added support for these opcodes needed by homedata.c (yes, I am + * lazy): + * 4C CE (MOV A,PT) + * 48 AC (EXA) + * 48 AD (EXR) + * 48 AE (EXH) + * 48 AF (EXX) + * 50 xx (SKN bit) + * 58 xx (SETB) + * 5B xx (CLR) + * 5D xx (SK bit) + * + * 2008-02-24 (Wilbert Pol): + * - Added preliminary support for uPD7801 + * For the uPD7801 only the basic instruction set was added. The current timer + * and serial i/o implementations are most likely incorrect. + * - Added basic support for uPD78C05 and uPD78C06 + * Documentation of the actual instruction set layout is missing, so we took + * the uPD7801 instruction set and only kept the instructions mentioned in + * the little documentation available on the uPD78c05A/06A. The serial i/o + * implementation has not been tested and is probably incorrect. + * + *****************************************************************************/ +/* Hau around 23 May 2004 + gta, gti, dgt fixed + working reg opcodes fixed + sio input fixed +-- + PeT around 19 February 2002 + type selection/gamemaster support added + gamemaster init hack? added + ORAX added + jre negativ fixed + prefixed opcodes skipping fixed + interrupts fixed and improved + sub(and related)/add/daa flags fixed + mvi ports,... fixed + rll, rlr, drll, drlr fixed + rets fixed + l0, l1 skipping fixed + calt fixed +*/ + +/* + +7807 DESCRIPTION + + + + PA0 1 64 Vcc + PA1 2 63 Vdd + PA2 3 62 PD7/AD7 + PA3 4 61 PD6/AD6 + PA4 5 60 PD5/AD5 + PA5 6 59 PD4/AD4 + PA6 7 58 PD3/AD3 + PA7 8 57 PD2/AD2 + PB0 9 56 PD1/AD1 + PB1 10 55 PD0/AD0 + PB2 11 54 PF7/AB15 + PB3 12 53 PF6/AB14 + PB4 13 52 PF5/AB13 + PB5 14 51 PF4/AB12 + PB6 15 50 PF3/AB11 + PB7 16 49 PF2/AB10 + PC0 17 48 PF1/AB9 + PC1 18 47 PF0/AB8 + PC2 19 46 ALE + PC3 20 45 WR* + PC4 21 44 RD* + PC5 22 43 HLDA + PC6 23 42 HOLD + PC7 24 41 PT7 + NMI* 25 40 PT6 + INT1 26 39 PT5 + MODE1 27 38 PT4 +RESET* 28 37 PT3 + MODE0 29 36 PT2 + X2 30 35 PT1 + X1 31 34 PT0 + Vss 32 33 Vth + +PA, PB, PC, PD, and PF is bidirectional I/O port +and PT is comparator input port in uPD7808. +uPD7807 uses PD port as data I/O and bottom address output, +and uses PF port as top address output. + +NMI* is non maskable interrupt input signal (negative edge trigger). + +INT1 is interrupt input (positive edge trigger). It can be used as +AC zero-cross input or trigger source of 16bit timer counter. + +MODE0 and MODE1 is input terminal which decides total amount of +external memory of uPD7807 (4KByte, 16KBYte, and 64KByte). +It also decides number of PF ports used as top address output. + 4KByte mode: PF0~PF3=address output, PF4~PF7=data I/O port +16KByte mode: PF0~PF5=address output, PF6~PF7=data I/O port +64KByte mode: PF0~PF7=address output + +RESET* is system rest terminal. + +X1 and X2 does clock signal generation (connect OSC and condenser). + +Vth is used to determine threshold voltage for PT port. +PT0~PT7 is connected to + input of each comparator, +and Vth deterimnes voltage connected to - input of PT0~PT7. +But the voltage of Vth is not directly connected to comapators. +It is connected via 16-level programmable voltage separate circuit. + +HOLD and HLDA is terminal for DMA. RD*, WR*, and ALE is bus +interface signal (they are same type of Intel 8085). +Unlike 8085, I/O address space is not available, so IO /M* signal +does not exist. Read/write of external memory can be done +by RD*, WR*, and ALE only. + +Vcc and Vss is main power source. Vdd is backup power source +for internal RWM (32 Byte). + + +PA and PB is I/O port. They have control register MA and MB. +If control register is set to 1, the port is input. +If control register is set to 0, the port is output. +They are set to 1 by reset. + +PT is input-only port. It is consisted of input terminal PT0~PT7 +and Vth (set threshold voltage). Each PT input has analog comparator +and latch, and + input of analog comparator is connected to +PT terminal. Every - input of analog comparator is connected +to devided voltage of Vth. Voltage dividing level can be set by +bottom 4bits of MT (mode T) register. The range is 1/16~16/16 of Vth. + +Other internal I/Os are +8bit timer (x2): Upcounter. If the counter matches to specified value, +the timer is reset and counts again from 0. +You can also set it to generate interrupt, or invert output flip-flop +when the counter matches to specified value. +Furthermore, you can output that flip-flop output to PC4/TO output, +connect it to clock input of timer/event counter or watchdog timer. +Or you can use it as bitrate clock of serial interface. +Note: There is only 1 output flip-flop for 2 timers. +If you use it for timer output of 1 timer, another timer cannot be used +for other than interrupt generator. +Clock input for timer can be switched between internal clock (2 type) +or PC3/TI input. You can set 1 timer's match-output as another timer's +clock input, so that you can use them as 1 16bit timer. + +16bit timer/event counter (x1): It can be used as +- Interval timer +- External event counter +- Frequency measurement +- Pulse width measurement +- Programmable rectangle wave output +- One pulse output +Related terminals are PC5/CI input, PC6/CO0 output, and PC7/CO1. +You can measure CI input's H duration, or you can output timing signal +(with phase difference) to CO0 and CO1. + +serial I/F (x1): has 3 modes. +- Asynchronous mode +- Synchronous mode +- I/O interface mode +In all 3 modes, bitrate can be internal fixed clock, or timer output, +or external clock. +In asynchronous mode, you can +- switch 7bit/8bit data +- set parity ON/OFF and EVEN/ODD +- set 1/2 stop bit + + + + +DIFFERENCES BETWEEN 7810 and 7807 + +-------------------------- +8bit transfer instructions +-------------------------- + +7810 +inst. 1st byte 2nd byte state action +EXX 00001001 4 Swap BC DE HL +EXA 00001000 4 Swap VA EA +EXH 01010000 4 Swap HL +BLOCK 00110001 13(C+1) (DE)+ <- (HL)+, C <- C - 1, until CY + +7807 +inst. 1st byte 2nd byte state action +EXR 01001000 10101101 8 Swap VA BC DE HL EA +EXX 01001000 10101111 8 Swap BC DE HL +EXA 01001000 10101100 8 Swap VA EA +EXH 01001000 10101110 8 Swap HL +BLOCK D+ 00010000 13(C+1) (DE)+ <- (HL)+, C <- C - 1, until CY +BLOCK D- 00010001 13(C+1) (DE)- <- (HL)-, C <- C - 1, until CY + + +--------------------------- +16bit transfer instructions +--------------------------- +All instructions are same except operand sr4 of DMOV instruction. +7810 +V0-sr4 -function + 0-ECNT-timer/event counter upcounter + 1-ECPT-timer/event counter capture + +7807 +V1-V0- sr4 -function + 0- 0-ECNT -timer/event counter upcounter + 0- 1-ECPT0-timer/event counter capture 0 + 1- 0-ECPT1-timer/event counter capture 1 + + +----------------------------------------- +8bit operation instructions for registers +----------------------------------------- +All instructions are same. + + +-------------------------------------- +8bit operation instructions for memory +-------------------------------------- +All instructions are same. + + +----------------------------------------- +Operation instructions for immediate data +----------------------------------------- +uPD7807 has read-only PT port and special register group sr5 for it. +ins. 1st byte 2nd byte 3rd 4th state func +GTI sr5, byte 01100100 s0101sss dd 14 !CY sr5 - byte - 1 +LTI sr5, byte 01100100 s0111sss dd 14 CY sr5 - byte +NEI sr5, byte 01100100 s1101sss dd 14 !Z sr5 - byte +EQI sr5, byte 01100100 s1111sss dd 14 Z sr5 - byte +ONI sr5, byte 01100100 s1001sss dd 14 !Z sr5 & byte +OFFI sr5, byte 01100100 s1011sss dd 14 Z sr5 & byte + +S5-S4-S3-S2-S1-S0-sr -sr1-sr2-sr5-register function + 0 0 1 1 1 0 --- PT --- PT comparator input port T data + 1 0 0 1 0 0 WDM WDM --- --- watchdog timer mode register + 1 0 0 1 0 1 MT --- --- --- port T mode + +7807 doesn't have registers below + 0 0 1 0 0 0 ANM ANM ANM A/D channel mode + 1 0 0 0 0 0 --- CR0 --- A/D conversion result 0 + 1 0 0 0 0 1 --- CR1 --- A/D conversion result 1 + 1 0 0 0 1 0 --- CR2 --- A/D conversion result 2 + 1 0 0 0 1 1 --- CR3 --- A/D conversion result 3 + 1 0 1 0 0 0 ZCM --- --- zero cross mode + +Special register operand (includes registers for I/O ports) has +6 groups - sr, sr1, sr2, sr3, sr4, and sr5. Among these groups, +sr, sr1, sr2, and sr5 includes registers described in the table +below, and expressed as bit pattern S5-S0. + +S5S4S3S2S1S0 sr sr1 sr2 sr5 register function +0 0 0 0 0 0 PA PA PA PA port A +0 0 0 0 0 1 PB PB PB PB port B +0 0 0 0 1 0 PC PC PC PC port C +0 0 0 0 1 1 PD PD PD PD port D +0 0 0 1 0 1 PF PF PF PF port F +0 0 0 1 1 0 MKH MKH MKH MKH mask high +0 0 0 1 1 1 MKL MKL MKL MKL mask low +0 0 1 0 0 1 SMH SMH SMH SMH serial mode high +0 0 1 0 1 0 SML --- --- --- serial mode low +0 0 1 0 1 1 EOM EOM EOM EOM timer/event counter output mode +0 0 1 1 0 0 ETMM --- --- --- timer/event counter mode +0 0 1 1 0 1 TMM TMM TMM TMM timer mode +0 0 1 1 1 0 --- PT --- PT port T +0 1 0 0 0 0 MM --- --- --- memory mapping +0 1 0 0 0 1 MCC --- --- --- mode control C +0 1 0 0 1 0 MA --- --- --- mode A +0 1 0 0 1 1 MB --- --- --- mode B +0 1 0 1 0 0 MC --- --- --- mode C +0 1 0 1 1 1 MF --- --- --- mode F +0 1 1 0 0 0 TXB --- --- --- Tx buffer +0 1 1 0 0 1 --- RXB --- --- Rx buffer +0 1 1 0 1 0 TM0 --- --- --- timer register 0 +0 1 1 0 1 1 TM1 --- --- --- timer register 1 +1 0 0 1 0 0 WDM WDM --- --- watchdog timer mode +1 0 0 1 0 1 MT --- --- --- mode T + +For sr and sr1, all 6bits (S5, S4, S3, S2, S1, and S0) are used. +For sr2 and sr5, only 4bits (S3, S2, S1, AND S0) are used. +They are expressed as 'ssssss' and 's sss' in operation code. +Note that 's sss' (of sr2 and sr5) is located separately. +S0 is rightmost bit (LSB). + + +-------------------------------------------- +Operation instructions for working registers +-------------------------------------------- +All instructions are same. + + +-------------------------------------------------------------------------- +16bit operation instructions and divider/multiplier operation instructions +-------------------------------------------------------------------------- +All instructions are same. + + +------------------------------------------ +Increment/decrement operation instructions +------------------------------------------ +All instructions are same. + + +---------------------------- +Other operation instructions +---------------------------- +7807 has CMC instruction (inverts CY flag). +ins. 1st byte 2nd byte 3rd 4th state func +CMC 01001000 10101010 8 CY <- !CY + + +--------------------------- +Rotation/shift instructions +--------------------------- +All instructions are same. + + +----------------------------- +Jump/call/return instructions +----------------------------- +All instructions are same. + + +----------------- +Skip instructions +----------------- +7807 doesn't have this +ins. 1st byte 2nd byte 3rd 4th state func +BIT bit, wa 01011bbb wwwwwwww 10* bit skip if (V.wa).bit = 1 + +Instead, 7807 has these bit manipulation instructions. +ins. 1st byte 2nd byte 3rd 4th state func +MOV CY, bit 01011111 bbbbbbbb 10* CY <- (bit) +MOV bit, CY 01011010 bbbbbbbb 13* (bit) <- CY +AND CY, bit 00110001 bbbbbbbb 10* CY <- CY & (bit) +OR CY, bit 01011100 bbbbbbbb 10* CY <- CY | (bit) +XOR CY, bit 01011110 bbbbbbbb 10* CY <- CY ^ (bit) +SETB bit 01011000 bbbbbbbb 13* (bit) <- 1 +CLR bit 01011011 bbbbbbbb 13* (bit) <- 0 +NOT bit 01011001 bbbbbbbb 13* (bit) <- !(bit) +SK bit 01011101 bbbbbbbb 10* (b) skip if (bit) = 1 +SKN bit 01010000 bbbbbbbb 10* !(b) skip if (bit) = 0 + + +------------------------ +CPU control instructions +------------------------ +ins. 1st byte 2nd byte 3rd 4th state func +HLT 01001000 00111011 11/12 halt +11 state in uPD7807 and uPD7810, 12 state in uPD78C10. + +STOP 01001000 10111011 12 stop +7807 doesn't have STOP instruction. + +*/ + +#include "emu.h" +#include "debugger.h" +#include "upd7810.h" +#include "upd7810_macros.h" + + +const device_type UPD7810 = &device_creator; +const device_type UPD7807 = &device_creator; +const device_type UPD7801 = &device_creator; +const device_type UPD78C05 = &device_creator; +const device_type UPD78C06 = &device_creator; + + +upd7810_device::upd7810_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : cpu_device(mconfig, UPD7810, "uPD7810", tag, owner, clock, "upd7810", __FILE__) + , m_to_func(*this) + , m_co0_func(*this) + , m_co1_func(*this) + , m_txd_func(*this) + , m_rxd_func(*this) + , m_an0_func(*this) + , m_an1_func(*this) + , m_an2_func(*this) + , m_an3_func(*this) + , m_an4_func(*this) + , m_an5_func(*this) + , m_an6_func(*this) + , m_an7_func(*this) + , m_program_config("program", ENDIANNESS_LITTLE, 8, 16, 0) + , m_io_config("io", ENDIANNESS_LITTLE, 8, 8, 0) +{ + m_opXX = s_opXX_7810; + m_op48 = s_op48; + m_op4C = s_op4C; + m_op4D = s_op4D; + m_op60 = s_op60; + m_op64 = s_op64; + m_op70 = s_op70; + m_op74 = s_op74; +} + +upd7810_device::upd7810_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : cpu_device(mconfig, type, name, tag, owner, clock, shortname, source) + , m_to_func(*this) + , m_co0_func(*this) + , m_co1_func(*this) + , m_txd_func(*this) + , m_rxd_func(*this) + , m_an0_func(*this) + , m_an1_func(*this) + , m_an2_func(*this) + , m_an3_func(*this) + , m_an4_func(*this) + , m_an5_func(*this) + , m_an6_func(*this) + , m_an7_func(*this) + , m_program_config("program", ENDIANNESS_LITTLE, 8, 16, 0) + , m_io_config("io", ENDIANNESS_LITTLE, 8, 8, 0) +{ +} + +upd7807_device::upd7807_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : upd7810_device(mconfig, UPD7807, "uPD7807", tag, owner, clock, "upd7807", __FILE__) +{ + m_opXX = s_opXX_7807; + m_op48 = s_op48; + m_op4C = s_op4C; + m_op4D = s_op4D; + m_op60 = s_op60; + m_op64 = s_op64; + m_op70 = s_op70; + m_op74 = s_op74; +} + +upd7801_device::upd7801_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : upd7810_device(mconfig, UPD7801, "uPD7801", tag, owner, clock, "upd7801", __FILE__) +{ + m_op48 = s_op48_7801; + m_op4C = s_op4C_7801; + m_op4D = s_op4D_7801; + m_op60 = s_op60_7801; + m_op64 = s_op64_7801; + m_op70 = s_op70_7801; + m_op74 = s_op74_7801; + m_opXX = s_opXX_7801; +} + +upd78c05_device::upd78c05_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : upd7810_device(mconfig, UPD78C05, "uPD78C05", tag, owner, clock, "upd78c05", __FILE__) +{ + m_op48 = s_op48_78c05; + m_op4C = s_op4C_78c05; + m_op4D = s_op4D_78c05; + m_op60 = s_op60_78c05; + m_op64 = s_op64_78c05; + m_op70 = s_op70_78c05; + m_op74 = s_op74_78c05; + m_opXX = s_opXX_78c05; +} + +upd78c05_device::upd78c05_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : upd7810_device(mconfig, type, name, tag, owner, clock, shortname, source) +{ +} + +upd78c06_device::upd78c06_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : upd78c05_device(mconfig, UPD78C06, "uPD78C06", tag, owner, clock, "upd78c06", __FILE__) +{ + m_op48 = s_op48_78c06; + m_op4C = s_op4C_78c06; + m_op4D = s_op4D_78c06; + m_op60 = s_op60_78c06; + m_op64 = s_op64_78c06; + m_op70 = s_op70_78c06; + m_op74 = s_op74_78c06; + m_opXX = s_opXX_78c06; +} + +offs_t upd7810_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( upd7810 ); + return CPU_DISASSEMBLE_NAME(upd7810)(this, buffer, pc, oprom, opram, options); +} + +offs_t upd7807_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( upd7807 ); + return CPU_DISASSEMBLE_NAME(upd7807)(this, buffer, pc, oprom, opram, options); +} + +offs_t upd7801_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( upd7801 ); + return CPU_DISASSEMBLE_NAME(upd7801)(this, buffer, pc, oprom, opram, options); +} + +offs_t upd78c05_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( upd78c05 ); + return CPU_DISASSEMBLE_NAME(upd78c05)(this, buffer, pc, oprom, opram, options); +} + +UINT8 upd7810_device::RP(offs_t port) +{ + UINT8 data = 0xff; + switch (port) + { + case UPD7810_PORTA: + if (m_ma) // NS20031301 no need to read if the port is set as output + m_pa_in = m_io->read_byte(port); + data = (m_pa_in & m_ma) | (m_pa_out & ~m_ma); + break; + case UPD7810_PORTB: + if (m_mb) // NS20031301 no need to read if the port is set as output + m_pb_in = m_io->read_byte(port); + data = (m_pb_in & m_mb) | (m_pb_out & ~m_mb); + break; + case UPD7810_PORTC: + if (m_mc) // NS20031301 no need to read if the port is set as output + m_pc_in = m_io->read_byte(port); + data = (m_pc_in & m_mc) | (m_pc_out & ~m_mc); + if (m_mcc & 0x01) /* PC0 = TxD output */ + data = (data & ~0x01) | (m_txd & 1 ? 0x01 : 0x00); + if (m_mcc & 0x02) /* PC1 = RxD input */ + data = (data & ~0x02) | (m_rxd & 1 ? 0x02 : 0x00); + if (m_mcc & 0x04) /* PC2 = SCK input/output */ + data = (data & ~0x04) | (m_sck & 1 ? 0x04 : 0x00); + if (m_mcc & 0x08) /* PC3 = TI/INT2 input */ + data = (data & ~0x08) | (m_int2 & 1 ? 0x08 : 0x00); + if (m_mcc & 0x10) /* PC4 = TO output */ + data = (data & ~0x10) | (m_to & 1 ? 0x10 : 0x00); + if (m_mcc & 0x20) /* PC5 = CI input */ + data = (data & ~0x20) | (m_ci & 1 ? 0x20 : 0x00); + if (m_mcc & 0x40) /* PC6 = CO0 output */ + data = (data & ~0x40) | (m_co0 & 1 ? 0x40 : 0x00); + if (m_mcc & 0x80) /* PC7 = CO1 output */ + data = (data & ~0x80) | (m_co1 & 1 ? 0x80 : 0x00); + break; + case UPD7810_PORTD: + m_pd_in = m_io->read_byte(port); + switch (m_mm & 0x07) + { + case 0x00: /* PD input mode, PF port mode */ + data = m_pd_in; + break; + case 0x01: /* PD output mode, PF port mode */ + data = m_pd_out; + break; + default: /* PD extension mode, PF port/extension mode */ + data = 0xff; /* what do we see on the port here? */ + break; + } + break; + case UPD7810_PORTF: + m_pf_in = m_io->read_byte(port); + switch (m_mm & 0x06) + { + case 0x00: /* PD input/output mode, PF port mode */ + data = (m_pf_in & m_mf) | (m_pf_out & ~m_mf); + break; + case 0x02: /* PD extension mode, PF0-3 extension mode, PF4-7 port mode */ + data = (m_pf_in & m_mf) | (m_pf_out & ~m_mf); + data |= 0x0f; /* what would we see on the lower bits here? */ + break; + case 0x04: /* PD extension mode, PF0-5 extension mode, PF6-7 port mode */ + data = (m_pf_in & m_mf) | (m_pf_out & ~m_mf); + data |= 0x3f; /* what would we see on the lower bits here? */ + break; + case 0x06: + data = 0xff; /* what would we see on the lower bits here? */ + break; + } + break; + case UPD7807_PORTT: // NS20031301 partial implementation + data = m_io->read_byte(port); + break; + default: + logerror("uPD7810 internal error: RP() called with invalid port number\n"); + } + return data; +} + +void upd7810_device::WP(offs_t port, UINT8 data) +{ + switch (port) + { + case UPD7810_PORTA: + m_pa_out = data; +// data = (data & ~m_ma) | (m_pa_in & m_ma); + data = (data & ~m_ma) | (m_ma); // NS20031401 + m_io->write_byte(port, data); + break; + case UPD7810_PORTB: + m_pb_out = data; +// data = (data & ~m_mb) | (m_pb_in & m_mb); + data = (data & ~m_mb) | (m_mb); // NS20031401 + m_io->write_byte(port, data); + break; + case UPD7810_PORTC: + m_pc_out = data; +// data = (data & ~m_mc) | (m_pc_in & m_mc); + data = (data & ~m_mc) | (m_mc); // NS20031401 + if (m_mcc & 0x01) /* PC0 = TxD output */ + data = (data & ~0x01) | (m_txd & 1 ? 0x01 : 0x00); + if (m_mcc & 0x02) /* PC1 = RxD input */ + data = (data & ~0x02) | (m_rxd & 1 ? 0x02 : 0x00); + if (m_mcc & 0x04) /* PC2 = SCK input/output */ + data = (data & ~0x04) | (m_sck & 1 ? 0x04 : 0x00); + if (m_mcc & 0x08) /* PC3 = TI/INT2 input */ + data = (data & ~0x08) | (m_int2 & 1 ? 0x08 : 0x00); + if (m_mcc & 0x10) /* PC4 = TO output */ + data = (data & ~0x10) | (m_to & 1 ? 0x10 : 0x00); + if (m_mcc & 0x20) /* PC5 = CI input */ + data = (data & ~0x20) | (m_ci & 1 ? 0x20 : 0x00); + if (m_mcc & 0x40) /* PC6 = CO0 output */ + data = (data & ~0x40) | (m_co0 & 1 ? 0x40 : 0x00); + if (m_mcc & 0x80) /* PC7 = CO1 output */ + data = (data & ~0x80) | (m_co1 & 1 ? 0x80 : 0x00); + m_io->write_byte(port, data); + break; + case UPD7810_PORTD: + m_pd_out = data; + switch (m_mm & 0x07) + { + case 0x00: /* PD input mode, PF port mode */ + data = m_pd_in; + break; + case 0x01: /* PD output mode, PF port mode */ + data = m_pd_out; + break; + default: /* PD extension mode, PF port/extension mode */ + return; + } + m_io->write_byte(port, data); + break; + case UPD7810_PORTF: + m_pf_out = data; + data = (data & ~m_mf) | (m_pf_in & m_mf); + switch (m_mm & 0x06) + { + case 0x00: /* PD input/output mode, PF port mode */ + break; + case 0x02: /* PD extension mode, PF0-3 extension mode, PF4-7 port mode */ + data |= 0x0f; /* what would come out for the lower bits here? */ + break; + case 0x04: /* PD extension mode, PF0-5 extension mode, PF6-7 port mode */ + data |= 0x3f; /* what would come out for the lower bits here? */ + break; + case 0x06: + data |= 0xff; /* what would come out for the lower bits here? */ + break; + } + m_io->write_byte(port, data); + break; + default: + logerror("uPD7810 internal error: RP() called with invalid port number\n"); + } +} + +void upd7810_device::upd7810_take_irq() +{ + UINT16 vector = 0; + int irqline = 0; + + /* global interrupt disable? */ + if (0 == IFF) + return; + + /* check the interrupts in priority sequence */ + if (IRR & INTNMI) + { + /* Nonmaskable interrupt */ + irqline = INPUT_LINE_NMI; + vector = 0x0004; + IRR &= ~INTNMI; + } + else + if ((IRR & INTFT0) && 0 == (MKL & 0x02)) + { + vector = 0x0008; + if (!((IRR & INTFT1) && 0 == (MKL & 0x04))) + IRR&=~INTFT0; + } + else + if ((IRR & INTFT1) && 0 == (MKL & 0x04)) + { + vector = 0x0008; + IRR&=~INTFT1; + } + else + if ((IRR & INTF1) && 0 == (MKL & 0x08)) + { + irqline = UPD7810_INTF1; + vector = 0x0010; + if (!((IRR & INTF2) && 0 == (MKL & 0x10))) + IRR&=~INTF1; + } + else + if ((IRR & INTF2) && 0 == (MKL & 0x10)) + { + irqline = UPD7810_INTF2; + vector = 0x0010; + IRR&=~INTF2; + } + else + if ((IRR & INTFE0) && 0 == (MKL & 0x20)) + { + vector = 0x0018; + if (!((IRR & INTFE1) && 0 == (MKL & 0x40))) + IRR&=~INTFE0; + } + else + if ((IRR & INTFE1) && 0 == (MKL & 0x40)) + { + vector = 0x0018; + IRR&=~INTFE1; + } + else + if ((IRR & INTFEIN) && 0 == (MKL & 0x80)) + { + vector = 0x0020; + } + else + if ((IRR & INTFAD) && 0 == (MKH & 0x01)) + { + vector = 0x0020; + } + else + if ((IRR & INTFSR) && 0 == (MKH & 0x02)) + { + vector = 0x0028; + IRR&=~INTFSR; + } + else + if ((IRR & INTFST) && 0 == (MKH & 0x04)) + { + vector = 0x0028; + IRR&=~INTFST; + } + + if (vector) + { + /* acknowledge external IRQ */ + if (irqline) + standard_irq_callback(irqline); + SP--; + WM( SP, PSW ); + SP--; + WM( SP, PCH ); + SP--; + WM( SP, PCL ); + IFF = 0; + PSW &= ~(SK|L0|L1); + PC = vector; + } +} + +void upd7801_device::upd7810_take_irq() +{ + UINT16 vector = 0; + int irqline = 0; + + /* global interrupt disable? */ + if (0 == IFF) + return; + + /* 1 - SOFTI - vector at 0x0060 */ + /* 2 - INT0 - Masked by MK0 bit */ + if ( IRR & INTF0 && 0 == (MKL & 0x01 ) ) + { + irqline = UPD7810_INTF0; + vector = 0x0004; + IRR &= ~INTF0; + } + /* 3 - INTT - Masked by MKT bit */ + if ( IRR & INTFT0 && 0 == ( MKL & 0x02 ) ) + { + vector = 0x0008; + IRR &= ~INTFT0; + } + /* 4 - INT1 - Masked by MK1 bit */ + if ( IRR & INTF1 && 0 == ( MKL & 0x04 ) ) + { + irqline = UPD7810_INTF1; + vector = 0x0010; + IRR &= ~INTF1; + } + /* 5 - INT2 - Masked by MK2 bit */ + if ( IRR & INTF2 && 0 == ( MKL & 0x08 ) ) + { + irqline = UPD7810_INTF2; + vector = 0x0020; + IRR &= ~INTF2; + } + /* 6 - INTS - Masked by MKS bit */ + if ( IRR & INTFST && 0 == ( MKL & 0x10 ) ) + { + vector = 0x0040; + IRR &= ~INTFST; + } + + if (vector) + { + /* acknowledge external IRQ */ + if (irqline) + standard_irq_callback(irqline); + SP--; + WM( SP, PSW ); + SP--; + WM( SP, PCH ); + SP--; + WM( SP, PCL ); + IFF = 0; + PSW &= ~(SK|L0|L1); + PC = vector; + } +} + +void upd7810_device::upd7810_co0_output_change() +{ + /* Output LV0 Content to CO0 */ + CO0 = LV0; + + /* LV0 Level Inversion */ + if (EOM & 0x02) + LV0 ^= 1; + + m_co0_func(CO0); +} +void upd7810_device::upd7810_co1_output_change() +{ + /* Output LV1 Content to CO1 */ + CO1 = LV1; + + /* LV1 Level Inversion */ + if (EOM & 0x20) + LV1 ^= 1; + + m_co1_func(CO1); +} + +void upd7810_device::upd7810_write_EOM() +{ + switch (EOM & 0x0c) + { + case 0x04: /* To Reset LV0 */ + LV0 = 0; + EOM &= 0xfb; /* LRE0 is reset to 0 */ + break; + case 0x08: /* To Set LV0 */ + LV0 = 1; + EOM &= 0xf7; /* LRE1 is reset to 0 */ + break; + } + /* Output LV0 Content */ + if (EOM & 0x01) { + upd7810_co0_output_change(); + EOM &= 0xfe; /* LO0 is reset to 0 */ + } + + switch (EOM & 0xc0) + { + case 0x40: /* To Reset LV1 */ + LV1 = 0; + EOM &= 0xbf; /* LRE2 is reset to 0 */ + break; + case 0x80: /* To Set LV1 */ + LV1 = 1; + EOM &= 0x7f; /* LRE3 is reset to 0 */ + break; + } + /* Output LV1 Content */ + if (EOM & 0x10) { + upd7810_co1_output_change(); + EOM &= 0xef; /* LO1 is reset to 0 */ + } +} + +void upd7810_device::upd7810_write_TXB() +{ + m_txbuf = 1; +} + +#define PAR7(n) ((((n)>>6)^((n)>>5)^((n)>>4)^((n)>>3)^((n)>>2)^((n)>>1)^((n)))&1) +#define PAR8(n) ((((n)>>7)^((n)>>6)^((n)>>5)^((n)>>4)^((n)>>3)^((n)>>2)^((n)>>1)^((n)))&1) + +void upd7810_device::upd7810_sio_output() +{ + /* shift out more bits? */ + if (m_txcnt > 0) + { + TXD = m_txs & 1; + m_txd_func(TXD); + m_txs >>= 1; + m_txcnt--; + if (0 == m_txcnt) + IRR |= INTFST; /* serial transfer completed */ + } + else + if (SMH & 0x04) /* send enable ? */ + { + /* nothing written into the transmitter buffer ? */ + if (0 == m_txbuf) + return; + m_txbuf = 0; + + if (SML & 0x03) /* asynchronous mode ? */ + { + switch (SML & 0xfc) + { + case 0x48: /* 7bits, no parity, 1 stop bit */ + case 0x68: /* 7bits, no parity, 1 stop bit (parity select = 1 but parity is off) */ + /* insert start bit in bit0, stop bit int bit8 */ + m_txs = (TXB << 1) | (1 << 8); + m_txcnt = 9; + break; + case 0x4c: /* 8bits, no parity, 1 stop bit */ + case 0x6c: /* 8bits, no parity, 1 stop bit (parity select = 1 but parity is off) */ + /* insert start bit in bit0, stop bit int bit9 */ + m_txs = (TXB << 1) | (1 << 9); + m_txcnt = 10; + break; + case 0x58: /* 7bits, odd parity, 1 stop bit */ + /* insert start bit in bit0, parity in bit 8, stop bit in bit9 */ + m_txs = (TXB << 1) | (PAR7(TXB) << 8) | (1 << 9); + m_txcnt = 10; + break; + case 0x5c: /* 8bits, odd parity, 1 stop bit */ + /* insert start bit in bit0, parity in bit 9, stop bit int bit10 */ + m_txs = (TXB << 1) | (PAR8(TXB) << 9) | (1 << 10); + m_txcnt = 11; + break; + case 0x78: /* 7bits, even parity, 1 stop bit */ + /* insert start bit in bit0, parity in bit 8, stop bit in bit9 */ + m_txs = (TXB << 1) | ((PAR7(TXB) ^ 1) << 8) | (1 << 9); + m_txcnt = 10; + break; + case 0x7c: /* 8bits, even parity, 1 stop bit */ + /* insert start bit in bit0, parity in bit 9, stop bit int bit10 */ + m_txs = (TXB << 1) | ((PAR8(TXB) ^ 1) << 9) | (1 << 10); + m_txcnt = 11; + break; + case 0xc8: /* 7bits, no parity, 2 stop bits */ + case 0xe8: /* 7bits, no parity, 2 stop bits (parity select = 1 but parity is off) */ + /* insert start bit in bit0, stop bits int bit8+9 */ + m_txs = (TXB << 1) | (3 << 8); + m_txcnt = 10; + break; + case 0xcc: /* 8bits, no parity, 2 stop bits */ + case 0xec: /* 8bits, no parity, 2 stop bits (parity select = 1 but parity is off) */ + /* insert start bit in bit0, stop bits in bits9+10 */ + m_txs = (TXB << 1) | (3 << 9); + m_txcnt = 11; + break; + case 0xd8: /* 7bits, odd parity, 2 stop bits */ + /* insert start bit in bit0, parity in bit 8, stop bits in bits9+10 */ + m_txs = (TXB << 1) | (PAR7(TXB) << 8) | (3 << 9); + m_txcnt = 11; + break; + case 0xdc: /* 8bits, odd parity, 2 stop bits */ + /* insert start bit in bit0, parity in bit 9, stop bits int bit10+11 */ + m_txs = (TXB << 1) | (PAR8(TXB) << 9) | (3 << 10); + m_txcnt = 12; + break; + case 0xf8: /* 7bits, even parity, 2 stop bits */ + /* insert start bit in bit0, parity in bit 8, stop bits in bit9+10 */ + m_txs = (TXB << 1) | ((PAR7(TXB) ^ 1) << 8) | (3 << 9); + m_txcnt = 11; + break; + case 0xfc: /* 8bits, even parity, 2 stop bits */ + /* insert start bit in bit0, parity in bit 9, stop bits int bits10+10 */ + m_txs = (TXB << 1) | ((PAR8(TXB) ^ 1) << 9) | (1 << 10); + m_txcnt = 12; + break; + } + } + else + { + /* synchronous mode */ + m_txs = TXB; + m_txcnt = 8; + } + } +} + +void upd7810_device::upd7810_sio_input() +{ + /* sample next bit? */ + if (m_rxcnt > 0) + { + RXD = m_rxd_func(); + m_rxs = (m_rxs >> 1) | ((UINT16)RXD << 15); + m_rxcnt--; + if (0 == m_rxcnt) + { + /* reset the TSK bit */ + SMH &= ~0x40; + /* serial receive completed interrupt */ + IRR |= INTFSR; + /* now extract the data from the shift register */ + if (SML & 0x03) /* asynchronous mode ? */ + { + switch (SML & 0xfc) + { + case 0x48: /* 7bits, no parity, 1 stop bit */ + case 0x68: /* 7bits, no parity, 1 stop bit (parity select = 1 but parity is off) */ + m_rxs >>= 16 - 9; + RXB = (m_rxs >> 1) & 0x7f; + if ((1 << 8) != (m_rxs & (1 | (1 << 8)))) + IRR |= INTER; /* framing error */ + break; + case 0x4c: /* 8bits, no parity, 1 stop bit */ + case 0x6c: /* 8bits, no parity, 1 stop bit (parity select = 1 but parity is off) */ + m_rxs >>= 16 - 10; + RXB = (m_rxs >> 1) & 0xff; + if ((1 << 9) != (m_rxs & (1 | (1 << 9)))) + IRR |= INTER; /* framing error */ + break; + case 0x58: /* 7bits, odd parity, 1 stop bit */ + m_rxs >>= 16 - 10; + RXB = (m_rxs >> 1) & 0x7f; + if ((1 << 9) != (m_rxs & (1 | (1 << 9)))) + IRR |= INTER; /* framing error */ + if (PAR7(RXB) != ((m_rxs >> 8) & 1)) + IRR |= INTER; /* parity error */ + break; + case 0x5c: /* 8bits, odd parity, 1 stop bit */ + m_rxs >>= 16 - 11; + RXB = (m_rxs >> 1) & 0xff; + if ((1 << 10) != (m_rxs & (1 | (1 << 10)))) + IRR |= INTER; /* framing error */ + if (PAR8(RXB) != ((m_rxs >> 9) & 1)) + IRR |= INTER; /* parity error */ + break; + case 0x78: /* 7bits, even parity, 1 stop bit */ + m_rxs >>= 16 - 10; + RXB = (m_rxs >> 1) & 0x7f; + if ((1 << 9) != (m_rxs & (1 | (1 << 9)))) + IRR |= INTER; /* framing error */ + if (PAR7(RXB) != ((m_rxs >> 8) & 1)) + IRR |= INTER; /* parity error */ + break; + case 0x7c: /* 8bits, even parity, 1 stop bit */ + m_rxs >>= 16 - 11; + RXB = (m_rxs >> 1) & 0xff; + if ((1 << 10) != (m_rxs & (1 | (1 << 10)))) + IRR |= INTER; /* framing error */ + if (PAR8(RXB) != ((m_rxs >> 9) & 1)) + IRR |= INTER; /* parity error */ + break; + case 0xc8: /* 7bits, no parity, 2 stop bits */ + case 0xe8: /* 7bits, no parity, 2 stop bits (parity select = 1 but parity is off) */ + m_rxs >>= 16 - 10; + RXB = (m_rxs >> 1) & 0x7f; + if ((3 << 9) != (m_rxs & (1 | (3 << 9)))) + IRR |= INTER; /* framing error */ + if (PAR7(RXB) != ((m_rxs >> 8) & 1)) + IRR |= INTER; /* parity error */ + break; + case 0xcc: /* 8bits, no parity, 2 stop bits */ + case 0xec: /* 8bits, no parity, 2 stop bits (parity select = 1 but parity is off) */ + m_rxs >>= 16 - 11; + RXB = (m_rxs >> 1) & 0xff; + if ((3 << 10) != (m_rxs & (1 | (3 << 10)))) + IRR |= INTER; /* framing error */ + if (PAR8(RXB) != ((m_rxs >> 9) & 1)) + IRR |= INTER; /* parity error */ + break; + case 0xd8: /* 7bits, odd parity, 2 stop bits */ + m_rxs >>= 16 - 11; + RXB = (m_rxs >> 1) & 0x7f; + if ((3 << 10) != (m_rxs & (1 | (3 << 10)))) + IRR |= INTER; /* framing error */ + if (PAR7(RXB) != ((m_rxs >> 8) & 1)) + IRR |= INTER; /* parity error */ + break; + case 0xdc: /* 8bits, odd parity, 2 stop bits */ + m_rxs >>= 16 - 12; + RXB = (m_rxs >> 1) & 0xff; + if ((3 << 11) != (m_rxs & (1 | (3 << 11)))) + IRR |= INTER; /* framing error */ + if (PAR8(RXB) != ((m_rxs >> 9) & 1)) + IRR |= INTER; /* parity error */ + break; + case 0xf8: /* 7bits, even parity, 2 stop bits */ + m_rxs >>= 16 - 11; + RXB = (m_rxs >> 1) & 0x7f; + if ((3 << 10) != (m_rxs & (1 | (3 << 10)))) + IRR |= INTER; /* framing error */ + if (PAR7(RXB) != ((m_rxs >> 8) & 1)) + IRR |= INTER; /* parity error */ + break; + case 0xfc: /* 8bits, even parity, 2 stop bits */ + m_rxs >>= 16 - 12; + RXB = (m_rxs >> 1) & 0xff; + if ((3 << 11) != (m_rxs & (1 | (3 << 11)))) + IRR |= INTER; /* framing error */ + if (PAR8(RXB) != ((m_rxs >> 9) & 1)) + IRR |= INTER; /* parity error */ + break; + } + } + else + { + m_rxs >>= 16 - 8; + RXB = m_rxs; +// m_rxcnt = 8; + } + } + } + else + if (SMH & 0x08) /* receive enable ? */ + { + if (SML & 0x03) /* asynchronous mode ? */ + { + switch (SML & 0xfc) + { + case 0x48: /* 7bits, no parity, 1 stop bit */ + case 0x68: /* 7bits, no parity, 1 stop bit (parity select = 1 but parity is off) */ + m_rxcnt = 9; + break; + case 0x4c: /* 8bits, no parity, 1 stop bit */ + case 0x6c: /* 8bits, no parity, 1 stop bit (parity select = 1 but parity is off) */ + m_rxcnt = 10; + break; + case 0x58: /* 7bits, odd parity, 1 stop bit */ + m_rxcnt = 10; + break; + case 0x5c: /* 8bits, odd parity, 1 stop bit */ + m_rxcnt = 11; + break; + case 0x78: /* 7bits, even parity, 1 stop bit */ + m_rxcnt = 10; + break; + case 0x7c: /* 8bits, even parity, 1 stop bit */ + m_rxcnt = 11; + break; + case 0xc8: /* 7bits, no parity, 2 stop bits */ + case 0xe8: /* 7bits, no parity, 2 stop bits (parity select = 1 but parity is off) */ + m_rxcnt = 10; + break; + case 0xcc: /* 8bits, no parity, 2 stop bits */ + case 0xec: /* 8bits, no parity, 2 stop bits (parity select = 1 but parity is off) */ + m_rxcnt = 11; + break; + case 0xd8: /* 7bits, odd parity, 2 stop bits */ + m_rxcnt = 11; + break; + case 0xdc: /* 8bits, odd parity, 2 stop bits */ + m_rxcnt = 12; + break; + case 0xf8: /* 7bits, even parity, 2 stop bits */ + m_rxcnt = 11; + break; + case 0xfc: /* 8bits, even parity, 2 stop bits */ + m_rxcnt = 12; + break; + } + } + else + /* TSK bit set ? */ + if (SMH & 0x40) + { + m_rxcnt = 8; + } + } +} + +void upd7810_device::upd7810_handle_timer0(int cycles, int clkdiv) +{ + OVC0 += cycles; + while (OVC0 >= clkdiv) + { + OVC0 -= clkdiv; + CNT0++; + if (CNT0 == TM0) + { + CNT0 = 0; + IRR |= INTFT0; + /* timer F/F source is timer 0 ? */ + if (0x00 == (TMM & 0x03)) + { + TO ^= 1; + m_to_func(TO); + } + /* timer 1 chained with timer 0 ? */ + if ((TMM & 0xe0) == 0x60) + { + CNT1++; + if (CNT1 == TM1) + { + CNT1 = 0; + IRR |= INTFT1; + /* timer F/F source is timer 1 ? */ + if (0x01 == (TMM & 0x03)) + { + TO ^= 1; + m_to_func(TO); + } + } + } + } + } +} + +void upd7810_device::upd7810_handle_timer1(int cycles, int clkdiv) +{ + OVC1 += cycles; + while (OVC1 >= clkdiv) + { + OVC1 -= clkdiv; + CNT1++; + if (CNT1 == TM1) + { + CNT1 = 0; + IRR |= INTFT1; + /* timer F/F source is timer 1 ? */ + if (0x01 == (TMM & 0x03)) + { + TO ^= 1; + m_to_func(TO); + } + } + } +} + +void upd7810_device::handle_timers(int cycles) +{ + /**** TIMER 0 ****/ + if (TMM & 0x10) /* timer 0 upcounter reset ? */ + CNT0 = 0; + else + { + switch (TMM & 0x0c) /* timer 0 clock source */ + { + case 0x00: /* clock divided by 12 */ + upd7810_handle_timer0(cycles, 12); + break; + case 0x04: /* clock divided by 384 */ + upd7810_handle_timer0(cycles, 384); + break; + case 0x08: /* external signal at TI */ + break; + case 0x0c: /* disabled */ + break; + } + } + + /**** TIMER 1 ****/ + if (TMM & 0x80) /* timer 1 upcounter reset ? */ + CNT1 = 0; + else + { + switch (TMM & 0x60) /* timer 1 clock source */ + { + case 0x00: /* clock divided by 12 */ + upd7810_handle_timer1(cycles, 12); + break; + case 0x20: /* clock divided by 384 */ + upd7810_handle_timer1(cycles, 384); + break; + case 0x40: /* external signal at TI */ + break; + case 0x60: /* clocked with timer 0 */ + break; + } + } + + /**** TIMER F/F ****/ + /* timer F/F source is clock divided by 3 ? */ + if (0x02 == (TMM & 0x03)) + { + OVCF += cycles; + while (OVCF >= 3) + { + TO ^= 1; + m_to_func(TO); + OVCF -= 3; + } + } + + /**** ETIMER ****/ + /* ECNT clear */ + if (0x00 == (ETMM & 0x0c)) + ECNT = 0; + else + if (0x00 == (ETMM & 0x03) || (0x01 == (ETMM & 0x03) && CI)) + { + OVCE += cycles; + /* clock divided by 12 */ + while (OVCE >= 12) + { + OVCE -= 12; + ECNT++; + /* Interrupt Control Circuit */ + if (ETM0 == ECNT) + IRR |= INTFE0; + if (ETM1 == ECNT) + IRR |= INTFE1; + /* Conditions When ECNT Causes a CO0 Output Change */ + if (((0x00 == (ETMM & 0x30)) && (ETM0 == ECNT)) || /* set CO0 if ECNT == ETM0 */ + /* ((0x10 == (ETMM & 0x30)) prohibited */ + ((0x20 == (ETMM & 0x30)) && (ETM0 == ECNT)) || /* set CO0 if ECNT == ETM0 or at falling CI input */ + ((0x30 == (ETMM & 0x30)) && (ETM0 == ECNT || ETM1 == ECNT))) /* latch CO0 if ECNT == ETM0 or ECNT == ETM1 */ + { + upd7810_co0_output_change(); + } + /* Conditions When ECNT Causes a CO1 Output Change */ + if (((0x00 == (ETMM & 0xc0)) && (ETM1 == ECNT)) || /* set CO1 if ECNT == ETM1 */ + /* ((0x40 == (ETMM & 0xc0)) prohibited */ + ((0x80 == (ETMM & 0xc0)) && (ETM1 == ECNT)) || /* set CO1 if ECNT == ETM1 or at falling CI input */ + ((0xc0 == (ETMM & 0xc0)) && (ETM0 == ECNT || ETM1 == ECNT))) /* latch CO1 if ECNT == ETM0 or ECNT == ETM1 */ + { + upd7810_co1_output_change(); + } + /* How and When ECNT is Cleared */ + switch (ETMM & 0x0c) + { + case 0x00: /* clear ECNT */ + break; + case 0x04: /* free running */ + if (0 == ECNT) + ITF |= INTOV; /* set overflow flag if counter wrapped */ + break; + case 0x08: /* reset at falling edge of CI or TO */ + break; + case 0x0c: /* reset if ECNT == ETM1 */ + if (ETM1 == ECNT) + ECNT = 0; + break; + } + } + } + + /**** SIO ****/ + switch (SMH & 0x03) + { + case 0x00: /* interval timer F/F */ + break; + case 0x01: /* internal clock divided by 384 */ + OVCS += cycles; + while (OVCS >= 384) + { + OVCS -= 384; + if (0 == (EDGES ^= 1)) + upd7810_sio_input(); + else + upd7810_sio_output(); + } + break; + case 0x02: /* internal clock divided by 24 */ + OVCS += cycles; + while (OVCS >= 24) + { + OVCS -= 24; + if (0 == (EDGES ^= 1)) + upd7810_sio_input(); + else + upd7810_sio_output(); + } + break; + } + + /**** ADC ****/ + m_adcnt += cycles; + if (PANM != ANM) + { + /* reset A/D converter */ + m_adcnt = 0; + if (ANM & 0x10) + m_adtot = 144; + else + m_adtot = 192; + m_adout = 0; + m_shdone = 0; + if (ANM & 0x01) + { + /* select mode */ + m_adin = (ANM >> 1) & 0x07; + } + else + { + /* scan mode */ + m_adin = 0; + m_adrange = (ANM >> 1) & 0x04; + } + } + PANM = ANM; + if (ANM & 0x01) + { + /* select mode */ + if (m_shdone == 0) + { + switch (m_adin) + { + case 0: m_tmpcr = m_an0_func(); break; + case 1: m_tmpcr = m_an1_func(); break; + case 2: m_tmpcr = m_an2_func(); break; + case 3: m_tmpcr = m_an3_func(); break; + case 4: m_tmpcr = m_an4_func(); break; + case 5: m_tmpcr = m_an5_func(); break; + case 6: m_tmpcr = m_an6_func(); break; + case 7: m_tmpcr = m_an7_func(); break; + } + m_shdone = 1; + } + if (m_adcnt > m_adtot) + { + m_adcnt -= m_adtot; + switch (m_adout) + { + case 0: CR0 = m_tmpcr; break; + case 1: CR1 = m_tmpcr; break; + case 2: CR2 = m_tmpcr; break; + case 3: CR3 = m_tmpcr; break; + } + m_adout = (m_adout + 1) & 0x03; + if (m_adout == 0) + IRR |= INTFAD; + m_shdone = 0; + } + } + else + { + /* scan mode */ + if (m_shdone == 0) + { + switch (m_adin | m_adrange) + { + case 0: m_tmpcr = m_an0_func(); break; + case 1: m_tmpcr = m_an1_func(); break; + case 2: m_tmpcr = m_an2_func(); break; + case 3: m_tmpcr = m_an3_func(); break; + case 4: m_tmpcr = m_an4_func(); break; + case 5: m_tmpcr = m_an5_func(); break; + case 6: m_tmpcr = m_an6_func(); break; + case 7: m_tmpcr = m_an7_func(); break; + } + m_shdone = 1; + } + if (m_adcnt > m_adtot) + { + m_adcnt -= m_adtot; + switch (m_adout) + { + case 0: CR0 = m_tmpcr; break; + case 1: CR1 = m_tmpcr; break; + case 2: CR2 = m_tmpcr; break; + case 3: CR3 = m_tmpcr; break; + } + m_adin = (m_adin + 1) & 0x07; + m_adout = (m_adout + 1) & 0x03; + if (m_adout == 0) + IRR |= INTFAD; + m_shdone = 0; + } + } + +} + +void upd7801_device::handle_timers(int cycles) +{ + if ( m_ovc0 ) + { + m_ovc0 -= cycles; + + /* Check if timer expired */ + if ( m_ovc0 <= 0 ) + { + IRR |= INTFT0; + + /* Reset the timer flip/fliop */ + TO = 0; + m_to_func(TO); + + /* Reload the timer */ + m_ovc0 = 16 * ( TM0 + ( ( TM1 & 0x0f ) << 8 ) ); + } + } +} + +void upd78c05_device::handle_timers(int cycles) +{ + if ( m_ovc0 ) { + m_ovc0 -= cycles; + + if ( m_ovc0 <= 0 ) { + IRR |= INTFT0; + if (0x00 == (TMM & 0x03)) { + TO ^= 1; + m_to_func(TO); + } + + while ( m_ovc0 <= 0 ) { + m_ovc0 += ( ( TMM & 0x04 ) ? 16 * 8 : 8 ) * TM0; + } + } + } +} + +void upd7810_device::base_device_start() +{ + m_program = &space(AS_PROGRAM); + m_direct = &m_program->direct(); + m_io = &space(AS_IO); + + m_to_func.resolve_safe(); + m_co0_func.resolve_safe(); + m_co1_func.resolve_safe(); + m_txd_func.resolve_safe(); + m_rxd_func.resolve_safe(0); + m_an0_func.resolve_safe(0); + m_an1_func.resolve_safe(0); + m_an2_func.resolve_safe(0); + m_an3_func.resolve_safe(0); + m_an4_func.resolve_safe(0); + m_an5_func.resolve_safe(0); + m_an6_func.resolve_safe(0); + m_an7_func.resolve_safe(0); + + save_item(NAME(m_ppc.w.l)); + save_item(NAME(m_pc.w.l)); + save_item(NAME(m_sp.w.l)); + save_item(NAME(m_psw)); + save_item(NAME(m_op)); + save_item(NAME(m_op2)); + save_item(NAME(m_iff)); + save_item(NAME(m_ea.w.l)); + save_item(NAME(m_va.w.l)); + save_item(NAME(m_bc.w.l)); + save_item(NAME(m_de.w.l)); + save_item(NAME(m_hl.w.l)); + save_item(NAME(m_ea2.w.l)); + save_item(NAME(m_va2.w.l)); + save_item(NAME(m_bc2.w.l)); + save_item(NAME(m_de2.w.l)); + save_item(NAME(m_hl2.w.l)); + save_item(NAME(m_cnt.d)); + save_item(NAME(m_tm.d)); + save_item(NAME(m_ecnt.d)); + save_item(NAME(m_etm.d)); + save_item(NAME(m_ma)); + save_item(NAME(m_mb)); + save_item(NAME(m_mcc)); + save_item(NAME(m_mc)); + save_item(NAME(m_mm)); + save_item(NAME(m_mf)); + save_item(NAME(m_tmm)); + save_item(NAME(m_etmm)); + save_item(NAME(m_eom)); + save_item(NAME(m_sml)); + save_item(NAME(m_smh)); + save_item(NAME(m_anm)); + save_item(NAME(m_mkl)); + save_item(NAME(m_mkh)); + save_item(NAME(m_zcm)); + save_item(NAME(m_pa_out)); + save_item(NAME(m_pb_out)); + save_item(NAME(m_pc_out)); + save_item(NAME(m_pd_out)); + save_item(NAME(m_pf_out)); + save_item(NAME(m_cr0)); + save_item(NAME(m_cr1)); + save_item(NAME(m_cr2)); + save_item(NAME(m_cr3)); + save_item(NAME(m_txb)); + save_item(NAME(m_rxb)); + save_item(NAME(m_txd)); + save_item(NAME(m_rxd)); + save_item(NAME(m_sck)); + save_item(NAME(m_ti)); + save_item(NAME(m_to)); + save_item(NAME(m_ci)); + save_item(NAME(m_lv0)); + save_item(NAME(m_lv1)); + save_item(NAME(m_co0)); + save_item(NAME(m_co1)); + save_item(NAME(m_irr)); + save_item(NAME(m_itf)); + save_item(NAME(m_ovc0)); + save_item(NAME(m_ovc1)); + save_item(NAME(m_ovcf)); + save_item(NAME(m_ovcs)); + save_item(NAME(m_edges)); + save_item(NAME(m_nmi)); + save_item(NAME(m_int1)); + save_item(NAME(m_int2)); + + m_icountptr = &m_icount; +} + +void upd7810_device::device_start() +{ + base_device_start(); + + state_add( UPD7810_PC, "PC", m_pc.w.l).formatstr("%04X"); + state_add( UPD7810_SP, "SP", m_sp.w.l).formatstr("%04X"); + state_add( UPD7810_PSW, "PSW", m_psw).formatstr("%02X"); + state_add( UPD7810_A, "A", m_va.b.l).formatstr("%02X"); + state_add( UPD7810_V, "V", m_va.b.h).formatstr("%02X"); + state_add( UPD7810_EA, "EA", m_ea.w.l).formatstr("%04X"); + state_add( UPD7810_BC, "BC", m_bc.w.l).formatstr("%04X"); + state_add( UPD7810_DE, "DE", m_de.w.l).formatstr("%04X"); + state_add( UPD7810_HL, "HL", m_hl.w.l).formatstr("%04X"); + state_add( UPD7810_A2, "A'", m_va2.b.l).formatstr("%02X"); + state_add( UPD7810_V2, "V'", m_va2.b.h).formatstr("%02X"); + state_add( UPD7810_EA2, "EA'", m_ea2.w.l).formatstr("%04X"); + state_add( UPD7810_BC2, "BC'", m_bc2.w.l).formatstr("%04X"); + state_add( UPD7810_DE2, "DE'", m_de2.w.l).formatstr("%04X"); + state_add( UPD7810_HL2, "HL'", m_hl2.w.l).formatstr("%04X"); + state_add( UPD7810_CNT0, "CNT0", m_cnt.b.l).formatstr("%02X"); + state_add( UPD7810_CNT1, "CNT1", m_cnt.b.h).formatstr("%02X"); + state_add( UPD7810_TM0, "TM0", m_tm.b.l).formatstr("%02X"); + state_add( UPD7810_TM1, "TM1", m_tm.b.h).formatstr("%02X"); + state_add( UPD7810_ECNT, "ECNT", m_ecnt.w.l).formatstr("%04X"); + state_add( UPD7810_ECPT, "ECPT", m_ecnt.w.h).formatstr("%04X"); + state_add( UPD7810_ETM0, "ETM0", m_etm.w.l).formatstr("%04X"); + state_add( UPD7810_ETM1, "ETM1", m_etm.w.h).formatstr("%04X"); + state_add( UPD7810_MA, "MA", m_ma).formatstr("%02X"); + state_add( UPD7810_MB, "MB", m_mb).formatstr("%02X"); + state_add( UPD7810_MCC, "MCC", m_mcc).formatstr("%02X"); + state_add( UPD7810_MC, "MC", m_mc).formatstr("%02X"); + state_add( UPD7810_MM, "MM", m_mm).formatstr("%02X"); + state_add( UPD7810_MF, "MF", m_mf).formatstr("%02X"); + state_add( UPD7810_TMM, "TMM", m_tmm).formatstr("%02X"); + state_add( UPD7810_ETMM, "ETMM", m_etmm).formatstr("%02X"); + state_add( UPD7810_EOM, "EOM", m_eom).formatstr("%02X"); + state_add( UPD7810_SML, "SML", m_sml).formatstr("%02X"); + state_add( UPD7810_SMH, "SMH", m_smh).formatstr("%02X"); + state_add( UPD7810_ANM, "ANM", m_anm).formatstr("%02X"); + state_add( UPD7810_MKL, "MKL", m_mkl).formatstr("%02X"); + state_add( UPD7810_MKH, "MKH", m_mkh).formatstr("%02X"); + state_add( UPD7810_ZCM, "ZCM", m_zcm).formatstr("%02X"); + state_add( UPD7810_CR0, "CR0", m_cr0).formatstr("%02X"); + state_add( UPD7810_CR1, "CR1", m_cr1).formatstr("%02X"); + state_add( UPD7810_CR2, "CR2", m_cr2).formatstr("%02X"); + state_add( UPD7810_CR3, "CR3", m_cr3).formatstr("%02X"); + state_add( UPD7810_RXB, "RXB", m_rxb).formatstr("%02X"); + state_add( UPD7810_TXB, "TXB", m_txb).formatstr("%02X"); + state_add( UPD7810_TXD, "TXD", m_txd).formatstr("%3u"); + state_add( UPD7810_RXD, "RXD", m_rxd).formatstr("%3u"); + state_add( UPD7810_SCK, "SCK", m_sck).formatstr("%3u"); + state_add( UPD7810_TI, "TI", m_ti).formatstr("%3u"); + state_add( UPD7810_TO, "TO", m_to).formatstr("%3u"); + state_add( UPD7810_CI, "CI", m_ci).formatstr("%3u"); + state_add( UPD7810_LV0, "LV0", m_lv0).formatstr("%3u"); + state_add( UPD7810_LV1, "LV1", m_lv1).formatstr("%3u"); + state_add( UPD7810_CO0, "CO0", m_co0).formatstr("%3u"); + state_add( UPD7810_CO1, "CO1", m_co1).formatstr("%3u"); + + state_add( STATE_GENPC, "GENPC", m_pc.w.l ).formatstr("%04X").noshow(); + state_add( STATE_GENPCBASE, "GENPCBASE", m_ppc.w.l ).formatstr("%04X").noshow(); + state_add( STATE_GENSP, "GENSP", m_sp.w.l ).formatstr("%04X").noshow(); + state_add( STATE_GENFLAGS, "GENFLAGS", m_psw ).formatstr("%17s").noshow(); +} + +void upd78c05_device::device_start() +{ + base_device_start(); + + state_add( UPD7810_PC, "PC", m_pc.w.l).formatstr("%04X"); + state_add( UPD7810_SP, "SP", m_sp.w.l).formatstr("%04X"); + state_add( UPD7810_PSW, "PSW", m_psw).formatstr("%02X"); + state_add( UPD7810_A, "A", m_va.b.l).formatstr("%02X"); + state_add( UPD7810_V, "V", m_va.b.h).formatstr("%02X"); + state_add( UPD7810_EA, "EA", m_ea.w.l).formatstr("%04X"); + state_add( UPD7810_BC, "BC", m_bc.w.l).formatstr("%04X"); + state_add( UPD7810_DE, "DE", m_de.w.l).formatstr("%04X"); + state_add( UPD7810_HL, "HL", m_hl.w.l).formatstr("%04X"); + state_add( UPD7810_CNT0, "CNT0", m_cnt.b.l).formatstr("%02X"); + state_add( UPD7810_CNT1, "CNT1", m_cnt.b.h).formatstr("%02X"); + state_add( UPD7810_TM0, "TM0", m_tm.b.l).formatstr("%02X"); + state_add( UPD7810_TM1, "TM1", m_tm.b.h).formatstr("%02X"); + state_add( UPD7810_ECNT, "ECNT", m_ecnt.w.l).formatstr("%04X"); + state_add( UPD7810_ECPT, "ECPT", m_ecnt.w.h).formatstr("%04X"); + state_add( UPD7810_ETM0, "ETM0", m_etm.w.l).formatstr("%04X"); + state_add( UPD7810_ETM1, "ETM1", m_etm.w.h).formatstr("%04X"); + state_add( UPD7810_MB, "MB", m_mb).formatstr("%02X"); + state_add( UPD7810_TMM, "TMM", m_tmm).formatstr("%02X"); + state_add( UPD7810_MKL, "MKL", m_mkl).formatstr("%02X"); + + state_add( STATE_GENPC, "GENPC", m_pc.w.l ).formatstr("%04X").noshow(); + state_add( STATE_GENPCBASE, "GENPCBASE", m_ppc.w.l ).formatstr("%04X").noshow(); + state_add( STATE_GENSP, "GENSP", m_sp.w.l ).formatstr("%04X").noshow(); + state_add( STATE_GENFLAGS, "GENFLAGS", m_psw ).formatstr("%17s").noshow(); + +} + +void upd7810_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + switch (entry.index()) + { + case STATE_GENFLAGS: + strprintf(str, "%s:%s:%s:%s:%s:%s", + m_psw & 0x40 ? "ZF":"--", + m_psw & 0x20 ? "SK":"--", + m_psw & 0x10 ? "HC":"--", + m_psw & 0x08 ? "L1":"--", + m_psw & 0x04 ? "L0":"--", + m_psw & 0x01 ? "CY":"--"); + break; + } +} + +void upd7810_device::device_reset() +{ + m_ppc.d = 0; + m_pc.d = 0; + m_sp.d = 0; + m_op = 0; + m_op2 = 0; + m_iff = 0; + m_psw = 0; + m_ea.d = 0; + m_va.d = 0; + m_bc.d = 0; + m_de.d = 0; + m_hl.d = 0; + m_ea2.d = 0; + m_va2.d = 0; + m_bc2.d = 0; + m_de2.d = 0; + m_hl2.d = 0; + m_cnt.d = 0; + m_tm.d = 0; + m_ecnt.d = 0; + m_etm.d = 0; + m_ma = 0; + m_mb = 0; + m_mcc = 0; + m_mc = 0; + m_mm = 0; + m_mf = 0; + m_tmm = 0; + m_etmm = 0; + m_eom = 0; + m_sml = 0; + m_smh = 0; + m_anm = 0; + m_mkl = 0; + m_mkh = 0; + m_zcm = 0; + m_pa_in = 0; + m_pb_in = 0; + m_pc_in = 0; + m_pd_in = 0; + m_pf_in = 0; + m_pa_out = 0; + m_pb_out = 0; + m_pc_out = 0; + m_pd_out = 0; + m_pf_out = 0; + m_cr0 = 0; + m_cr1 = 0; + m_cr2 = 0; + m_cr3 = 0; + m_txb = 0; + m_rxb = 0; + m_txd = 0; + m_rxd = 0; + m_sck = 0; + m_ti = 0; + m_to = 0; + m_ci = 0; + m_lv0 = 0; + m_lv1 = 0; + m_co0 = 0; + m_co1 = 0; + m_irr = 0; + m_itf = 0; + m_nmi = 0; + m_int1 = 0; + m_int2 = 1; /* physical (inverted) INT2 line state */ + + m_txs = 0; + m_rxs = 0; + m_txcnt = 0; + m_rxcnt = 0; + m_txbuf = 0; + m_ovc0 = 0; + m_ovc1 = 0; + m_ovce = 0; + m_ovcf = 0; + m_ovcs = 0; + m_edges = 0; + m_adcnt = 0; + m_adtot = 0; + m_tmpcr = 0; + m_shdone = 0; + m_adout = 0; + m_adin = 0; + m_adrange = 0; + + PANM = 0xff; + ETMM = 0xff; + TMM = 0xff; + MA = 0xff; + MB = 0xff; + MC = 0xff; + MF = 0xff; + MKL = 0xff; + MKH = 0xff; //? +} + +void upd7801_device::device_reset() +{ + upd7810_device::device_reset(); + MA = 0; /* Port A is output port on the uPD7801 */ + m_ovc0 = 0; +} + +void upd78c05_device::device_reset() +{ + upd7810_device::device_reset(); + MA = 0; /* All outputs */ + MC = 0xFF; /* All inputs */ + V = 0xFF; /* The vector register is always pointing to FF00 */ + TM0 = 0xFF; /* Timer seems to be running from boot */ + m_ovc0 = ( ( TMM & 0x04 ) ? 16 * 8 : 8 ) * TM0; +} + +void upd7810_device::execute_run() +{ + do + { + int cc = 0; + + debugger_instruction_hook(this, PC); + + PPC = PC; + RDOP(OP); + + /* + * clear L0 and/or L1 flags for all opcodes except + * L0 for "MVI L,xx" or "LXI H,xxxx" + * L1 for "MVI A,xx" + */ + PSW &= ~m_opXX[OP].mask_l0_l1; + + /* skip flag set and not SOFTI opcode? */ + if ((PSW & SK) && (OP != 0x72)) + { + if (m_opXX[OP].cycles) + { + cc = m_opXX[OP].cycles_skip; + PC += m_opXX[OP].oplen - 1; + } + else + { + RDOP(OP2); + switch (OP) + { + case 0x48: + cc = m_op48[OP2].cycles_skip; + PC += m_op48[OP2].oplen - 2; + break; + case 0x4c: + cc = m_op4C[OP2].cycles_skip; + PC += m_op4C[OP2].oplen - 2; + break; + case 0x4d: + cc = m_op4D[OP2].cycles_skip; + PC += m_op4D[OP2].oplen - 2; + break; + case 0x60: + cc = m_op60[OP2].cycles_skip; + PC += m_op60[OP2].oplen - 2; + break; + case 0x64: + cc = m_op64[OP2].cycles_skip; + PC += m_op64[OP2].oplen - 2; + break; + case 0x70: + cc = m_op70[OP2].cycles_skip; + PC += m_op70[OP2].oplen - 2; + break; + case 0x74: + cc = m_op74[OP2].cycles_skip; + PC += m_op74[OP2].oplen - 2; + break; + default: + fatalerror("uPD7810 internal error: check cycle counts for main\n"); + } + } + PSW &= ~SK; + handle_timers( cc ); + } + else + { + cc = m_opXX[OP].cycles; + handle_timers( cc ); + (this->*m_opXX[OP].opfunc)(); + } + m_icount -= cc; + upd7810_take_irq(); + + } while (m_icount > 0); +} + +void upd7801_device::execute_set_input(int irqline, int state) +{ + /* The uPD7801 can check for falling and rising edges changes on the INT2 input */ + switch ( irqline ) + { + case UPD7810_INTF0: + /* INT0 is level sensitive */ + if ( state == ASSERT_LINE ) + IRR |= INTF0; + else + IRR &= INTF0; + break; + + case UPD7810_INTF1: + /* INT1 is rising edge sensitive */ + if ( m_int1 == CLEAR_LINE && state == ASSERT_LINE ) + IRR |= INTF1; + + m_int1 = state; + break; + + case UPD7810_INTF2: + /* INT2 is rising or falling edge sensitive */ + /* Check if the ES bit is set then check for rising edge, otherwise falling edge */ + if ( MKL & 0x20 ) + { + if ( m_int2 == CLEAR_LINE && state == ASSERT_LINE ) + { + IRR |= INTF2; + } + } + else + { + if ( m_int2 == ASSERT_LINE && state == CLEAR_LINE ) + { + IRR |= INTF2; + } + } + m_int2 = state; + break; + } +} + +void upd7810_device::execute_set_input(int irqline, int state) +{ + switch (irqline) { + case INPUT_LINE_NMI: + /* NMI is falling edge sensitive */ + if ( m_nmi == CLEAR_LINE && state == ASSERT_LINE ) + IRR |= INTNMI; + + m_nmi = state; + break; + case UPD7810_INTF1: + /* INT1 is rising edge sensitive */ + if ( m_int1 == CLEAR_LINE && state == ASSERT_LINE ) + IRR |= INTF1; + + m_int1 = state; + break; + case UPD7810_INTF2: + /* INT2 is falling edge sensitive */ + /* we store the physical state (inverse of the logical state) */ + /* to keep the handling of port C consistent with the upd7801 */ + if ( (!m_int2) == CLEAR_LINE && state == ASSERT_LINE ) + IRR |= INTF2; + + m_int2 = !state; + break; + default: + logerror("upd7810_set_irq_line invalid irq line #%d\n", irqline); + break; + } + /* resetting interrupt requests is done with the SKIT/SKNIT opcodes only! */ +} diff --git a/src/devices/cpu/upd7810/upd7810.h b/src/devices/cpu/upd7810/upd7810.h new file mode 100644 index 00000000000..cdea4f376b8 --- /dev/null +++ b/src/devices/cpu/upd7810/upd7810.h @@ -0,0 +1,1430 @@ +// license:BSD-3-Clause +// copyright-holders:Juergen Buchmueller +#pragma once + +#ifndef __UPD7810_H__ +#define __UPD7810_H__ + + +/* + all types have internal ram at 0xff00-0xffff + 7810 + 7811 (4kbyte),7812(8),7814(16) have internal rom at 0x0000 +*/ + + +enum +{ + UPD7810_PC=1, UPD7810_SP, UPD7810_PSW, + UPD7810_EA, UPD7810_V, UPD7810_A, UPD7810_VA, + UPD7810_BC, UPD7810_B, UPD7810_C, UPD7810_DE, UPD7810_D, UPD7810_E, UPD7810_HL, UPD7810_H, UPD7810_L, + UPD7810_EA2, UPD7810_V2, UPD7810_A2, UPD7810_VA2, + UPD7810_BC2, UPD7810_B2, UPD7810_C2, UPD7810_DE2, UPD7810_D2, UPD7810_E2, UPD7810_HL2, UPD7810_H2, UPD7810_L2, + UPD7810_CNT0, UPD7810_CNT1, UPD7810_TM0, UPD7810_TM1, UPD7810_ECNT, UPD7810_ECPT, UPD7810_ETM0, UPD7810_ETM1, + UPD7810_MA, UPD7810_MB, UPD7810_MCC, UPD7810_MC, UPD7810_MM, UPD7810_MF, + UPD7810_TMM, UPD7810_ETMM, UPD7810_EOM, UPD7810_SML, UPD7810_SMH, + UPD7810_ANM, UPD7810_MKL, UPD7810_MKH, UPD7810_ZCM, + UPD7810_TXB, UPD7810_RXB, UPD7810_CR0, UPD7810_CR1, UPD7810_CR2, UPD7810_CR3, + UPD7810_AN0, UPD7810_AN1, UPD7810_AN2, UPD7810_AN3, UPD7810_AN4, UPD7810_AN5, UPD7810_AN6, UPD7810_AN7, + UPD7810_TXD, UPD7810_RXD, UPD7810_SCK, UPD7810_TI, UPD7810_TO, UPD7810_CI, UPD7810_CO0, UPD7810_CO1, + UPD7810_LV0, UPD7810_LV1 +}; + +/* port numbers for PA,PB,PC,PD and PF */ +enum +{ + UPD7810_PORTA, UPD7810_PORTB, UPD7810_PORTC, UPD7810_PORTD, UPD7810_PORTF +}; + +enum +{ + UPD7807_PORTA, UPD7807_PORTB, UPD7807_PORTC, UPD7807_PORTD, UPD7807_PORTF, + UPD7807_PORTT +}; + +/* IRQ lines */ +#define UPD7810_INTF1 0 +#define UPD7810_INTF2 1 +#define UPD7810_INTF0 2 +#define UPD7810_INTFE1 4 + + + +#define MCFG_UPD7810_TO(_devcb) \ + upd7810_device::set_to_func(*device, DEVCB_##_devcb); + +#define MCFG_UPD7810_CO0(_devcb) \ + upd7810_device::set_co0_func(*device, DEVCB_##_devcb); + +#define MCFG_UPD7810_CO1(_devcb) \ + upd7810_device::set_co1_func(*device, DEVCB_##_devcb); + +#define MCFG_UPD7810_TXD(_devcb) \ + upd7810_device::set_txd_func(*device, DEVCB_##_devcb); + +#define MCFG_UPD7810_RXD(_devcb) \ + upd7810_device::set_rxd_func(*device, DEVCB_##_devcb); + +#define MCFG_UPD7810_AN0(_devcb) \ + upd7810_device::set_an0_func(*device, DEVCB_##_devcb); + +#define MCFG_UPD7810_AN1(_devcb) \ + upd7810_device::set_an1_func(*device, DEVCB_##_devcb); + +#define MCFG_UPD7810_AN2(_devcb) \ + upd7810_device::set_an2_func(*device, DEVCB_##_devcb); + +#define MCFG_UPD7810_AN3(_devcb) \ + upd7810_device::set_an3_func(*device, DEVCB_##_devcb); + +#define MCFG_UPD7810_AN4(_devcb) \ + upd7810_device::set_an4_func(*device, DEVCB_##_devcb); + +#define MCFG_UPD7810_AN5(_devcb) \ + upd7810_device::set_an5_func(*device, DEVCB_##_devcb); + +#define MCFG_UPD7810_AN6(_devcb) \ + upd7810_device::set_an6_func(*device, DEVCB_##_devcb); + +#define MCFG_UPD7810_AN7(_devcb) \ + upd7810_device::set_an7_func(*device, DEVCB_##_devcb); + + +class upd7810_device : public cpu_device +{ +public: + // construction/destruction + upd7810_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + upd7810_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + // static configuration helpers + template static devcb_base &set_to_func(device_t &device, _Object object) { return downcast(device).m_to_func.set_callback(object); } + template static devcb_base &set_co0_func(device_t &device, _Object object) { return downcast(device).m_co0_func.set_callback(object); } + template static devcb_base &set_co1_func(device_t &device, _Object object) { return downcast(device).m_co1_func.set_callback(object); } + template static devcb_base &set_txd_func(device_t &device, _Object object) { return downcast(device).m_txd_func.set_callback(object); } + template static devcb_base &set_rxd_func(device_t &device, _Object object) { return downcast(device).m_rxd_func.set_callback(object); } + template static devcb_base &set_an0_func(device_t &device, _Object object) { return downcast(device).m_an0_func.set_callback(object); } + template static devcb_base &set_an1_func(device_t &device, _Object object) { return downcast(device).m_an1_func.set_callback(object); } + template static devcb_base &set_an2_func(device_t &device, _Object object) { return downcast(device).m_an2_func.set_callback(object); } + template static devcb_base &set_an3_func(device_t &device, _Object object) { return downcast(device).m_an3_func.set_callback(object); } + template static devcb_base &set_an4_func(device_t &device, _Object object) { return downcast(device).m_an4_func.set_callback(object); } + template static devcb_base &set_an5_func(device_t &device, _Object object) { return downcast(device).m_an5_func.set_callback(object); } + template static devcb_base &set_an6_func(device_t &device, _Object object) { return downcast(device).m_an6_func.set_callback(object); } + template static devcb_base &set_an7_func(device_t &device, _Object object) { return downcast(device).m_an7_func.set_callback(object); } + +protected: + // flags + enum + { + CY = 0x01, + F1 = 0x02, + L0 = 0x04, + L1 = 0x08, + HC = 0x10, + SK = 0x20, + Z = 0x40, + F7 = 0x80 + }; + + // IRR flags + enum + { + INTNMI = 0x0001, + INTFT0 = 0x0002, + INTFT1 = 0x0004, + INTF1 = 0x0008, + INTF2 = 0x0010, + INTFE0 = 0x0020, + INTFE1 = 0x0040, + INTFEIN = 0x0080, + INTFAD = 0x0100, + INTFSR = 0x0200, + INTFST = 0x0400, + INTER = 0x0800, + INTOV = 0x1000, + INTF0 = 0x2000 + }; + + // ITF flags + enum + { + INTAN4 = 0x0001, + INTAN5 = 0x0002, + INTAN6 = 0x0004, + INTAN7 = 0x0008, + INTSB = 0x0010 + }; + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_execute_interface overrides + virtual UINT32 execute_min_cycles() const { return 1; } + virtual UINT32 execute_max_cycles() const { return 40; } + virtual UINT32 execute_input_lines() const { return 2; } + virtual void execute_run(); + virtual void execute_set_input(int inputnum, int state); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const { return (spacenum == AS_PROGRAM) ? &m_program_config : ( (spacenum == AS_IO) ? &m_io_config : NULL ); } + + // device_state_interface overrides + void state_string_export(const device_state_entry &entry, std::string &str); + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const { return 1; } + virtual UINT32 disasm_max_opcode_bytes() const { return 4; } + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + + virtual void handle_timers(int cycles); + virtual void upd7810_take_irq(); + + void upd7810_handle_timer0(int cycles, int clkdiv); + void upd7810_handle_timer1(int cycles, int clkdiv); + + void upd7810_co0_output_change(); + void upd7810_co1_output_change(); + + devcb_write_line m_to_func; + devcb_write_line m_co0_func; + devcb_write_line m_co1_func; + devcb_write_line m_txd_func; + devcb_read_line m_rxd_func; + devcb_read8 m_an0_func; + devcb_read8 m_an1_func; + devcb_read8 m_an2_func; + devcb_read8 m_an3_func; + devcb_read8 m_an4_func; + devcb_read8 m_an5_func; + devcb_read8 m_an6_func; + devcb_read8 m_an7_func; + + typedef void (upd7810_device::*opcode_func)(); + + struct opcode_s { + opcode_func opfunc; + UINT8 oplen; + UINT8 cycles; + UINT8 cycles_skip; + UINT8 mask_l0_l1; + }; + + static const struct opcode_s s_op48[256]; + static const struct opcode_s s_op4C[256]; + static const struct opcode_s s_op4D[256]; + static const struct opcode_s s_op60[256]; + static const struct opcode_s s_op64[256]; + static const struct opcode_s s_op70[256]; + static const struct opcode_s s_op74[256]; + static const struct opcode_s s_opXX_7810[256]; + static const struct opcode_s s_opXX_7807[256]; + static const struct opcode_s s_op48_7801[256]; + static const struct opcode_s s_op4C_7801[256]; + static const struct opcode_s s_op4D_7801[256]; + static const struct opcode_s s_op60_7801[256]; + static const struct opcode_s s_op64_7801[256]; + static const struct opcode_s s_op70_7801[256]; + static const struct opcode_s s_op74_7801[256]; + static const struct opcode_s s_opXX_7801[256]; + static const struct opcode_s s_op48_78c05[256]; + static const struct opcode_s s_op4C_78c05[256]; + static const struct opcode_s s_op4D_78c05[256]; + static const struct opcode_s s_op60_78c05[256]; + static const struct opcode_s s_op64_78c05[256]; + static const struct opcode_s s_op70_78c05[256]; + static const struct opcode_s s_op74_78c05[256]; + static const struct opcode_s s_opXX_78c05[256]; + static const struct opcode_s s_op48_78c06[256]; + static const struct opcode_s s_op4C_78c06[256]; + static const struct opcode_s s_op4D_78c06[256]; + static const struct opcode_s s_op60_78c06[256]; + static const struct opcode_s s_op64_78c06[256]; + static const struct opcode_s s_op70_78c06[256]; + static const struct opcode_s s_op74_78c06[256]; + static const struct opcode_s s_opXX_78c06[256]; + + address_space_config m_program_config; + address_space_config m_io_config; + + PAIR m_ppc; /* previous program counter */ + PAIR m_pc; /* program counter */ + PAIR m_sp; /* stack pointer */ + UINT8 m_op; /* opcode */ + UINT8 m_op2; /* opcode part 2 */ + UINT8 m_iff; /* interrupt enable flip flop */ + UINT8 m_psw; /* processor status word */ + PAIR m_ea; /* extended accumulator */ + PAIR m_va; /* accumulator + vector register */ + PAIR m_bc; /* 8bit B and C registers / 16bit BC register */ + PAIR m_de; /* 8bit D and E registers / 16bit DE register */ + PAIR m_hl; /* 8bit H and L registers / 16bit HL register */ + PAIR m_ea2; /* alternate register set */ + PAIR m_va2; + PAIR m_bc2; + PAIR m_de2; + PAIR m_hl2; + PAIR m_cnt; /* 8 bit timer counter */ + PAIR m_tm; /* 8 bit timer 0/1 comparator inputs */ + PAIR m_ecnt; /* timer counter register / capture register */ + PAIR m_etm; /* timer 0/1 comparator inputs */ + UINT8 m_ma; /* port A input or output mask */ + UINT8 m_mb; /* port B input or output mask */ + UINT8 m_mcc; /* port C control/port select */ + UINT8 m_mc; /* port C input or output mask */ + UINT8 m_mm; /* memory mapping */ + UINT8 m_mf; /* port F input or output mask */ + UINT8 m_tmm; /* timer 0 and timer 1 operating parameters */ + UINT8 m_etmm; /* 16-bit multifunction timer/event counter */ + UINT8 m_eom; /* 16-bit timer/event counter output control */ + UINT8 m_sml; /* serial interface parameters low */ + UINT8 m_smh; /* -"- high */ + UINT8 m_panm; /* previous analog to digital converter operating parameters */ + UINT8 m_anm; /* analog to digital converter operating parameters */ + UINT8 m_mkl; /* interrupt mask low */ + UINT8 m_mkh; /* -"- high */ + UINT8 m_zcm; /* bias circuitry for ac zero-cross detection */ + UINT8 m_pa_in; /* port A,B,C,D,F inputs */ + UINT8 m_pb_in; + UINT8 m_pc_in; + UINT8 m_pd_in; + UINT8 m_pf_in; + UINT8 m_pa_out; /* port A,B,C,D,F outputs */ + UINT8 m_pb_out; + UINT8 m_pc_out; + UINT8 m_pd_out; + UINT8 m_pf_out; + UINT8 m_cr0; /* analog digital conversion register 0 */ + UINT8 m_cr1; /* analog digital conversion register 1 */ + UINT8 m_cr2; /* analog digital conversion register 2 */ + UINT8 m_cr3; /* analog digital conversion register 3 */ + UINT8 m_txb; /* transmitter buffer */ + UINT8 m_rxb; /* receiver buffer */ + UINT8 m_txd; /* port C control line states */ + UINT8 m_rxd; + UINT8 m_sck; + UINT8 m_ti; + UINT8 m_to; + UINT8 m_ci; + UINT8 m_lv0; /* level flip flop for co0 */ + UINT8 m_lv1; /* level flip flop for co1 */ + UINT8 m_co0; + UINT8 m_co1; + UINT16 m_irr; /* interrupt request register */ + UINT16 m_itf; /* interrupt test flag register */ + int m_nmi; /* keep track of current nmi state. Needed for 7810 irq checking. */ + int m_int1; /* keep track of current int1 state. Needed for irq checking. */ + int m_int2; /* keep track to current int2 state. Needed for irq checking. */ + + /* internal helper variables */ + UINT16 m_txs; /* transmitter shift register */ + UINT16 m_rxs; /* receiver shift register */ + UINT8 m_txcnt; /* transmitter shift register bit count */ + UINT8 m_rxcnt; /* receiver shift register bit count */ + UINT8 m_txbuf; /* transmitter buffer was written */ + INT32 m_ovc0; /* overflow counter for timer 0 (for clock div 12/384) */ + INT32 m_ovc1; /* overflow counter for timer 0 (for clock div 12/384) */ + INT32 m_ovce; /* overflow counter for ecnt */ + INT32 m_ovcf; /* overflow counter for fixed clock div 3 mode */ + INT32 m_ovcs; /* overflow counter for serial I/O */ + UINT8 m_edges; /* rising/falling edge flag for serial I/O */ + UINT16 m_adcnt; /* A/D converter cycle count */ + UINT8 m_adtot; /* A/D converter total cycles per conversion */ + UINT8 m_tmpcr; /* temporary analog digital conversion register */ + int m_shdone; /* A/D converter sample and hold done */ + int m_adout; /* currently selected A/D converter output register */ + int m_adin; /* currently selected A/D converter input */ + int m_adrange;/* in scan mode, A/D converter range (AN0-AN3 or AN4-AN7) */ + + const struct opcode_s *m_opXX; /* opcode table */ + const struct opcode_s *m_op48; + const struct opcode_s *m_op4C; + const struct opcode_s *m_op4D; + const struct opcode_s *m_op60; + const struct opcode_s *m_op64; + const struct opcode_s *m_op70; + const struct opcode_s *m_op74; + address_space *m_program; + direct_read_data *m_direct; + address_space *m_io; + int m_icount; + + UINT8 RP(offs_t port); + void WP(offs_t port, UINT8 data); + void upd7810_write_EOM(); + void upd7810_write_TXB(); + void upd7810_sio_output(); + void upd7810_sio_input(); + void illegal(); + void illegal2(); + void SLRC_A(); + void SLRC_B(); + void SLRC_C(); + void SLLC_A(); + void SLLC_B(); + void SLLC_C(); + void SK_NV(); + void SK_CY(); + void SK_HC(); + void SK_Z(); + void SKN_NV(); + void SKN_CY(); + void SKN_HC(); + void SKN_Z(); + void SLR_A(); + void SLR_B(); + void SLR_C(); + void SLL_A(); + void SLL_B(); + void SLL_C(); + void JEA(); + void CALB(); + void CLC(); + void STC(); + void MUL_A(); + void MUL_B(); + void MUL_C(); + void RLR_A(); + void RLR_B(); + void RLR_C(); + void RLL_A(); + void RLL_B(); + void RLL_C(); + void RLD(); + void RRD(); + void NEGA(); + void HALT(); + void DIV_A(); + void DIV_B(); + void DIV_C(); + void SKIT_NMI(); + void SKIT_FT0(); + void SKIT_FT1(); + void SKIT_F1(); + void SKIT_F2(); + void SKIT_FE0(); + void SKIT_FE1(); + void SKIT_FEIN(); + void SKIT_FAD(); + void SKIT_FSR(); + void SKIT_FST(); + void SKIT_ER(); + void SKIT_OV(); + void SKIT_AN4(); + void SKIT_AN5(); + void SKIT_AN6(); + void SKIT_AN7(); + void SKIT_SB(); + void SKNIT_NMI(); + void SKNIT_FT0(); + void SKNIT_FT1(); + void SKNIT_F1(); + void SKNIT_F2(); + void SKNIT_FE0(); + void SKNIT_FE1(); + void SKNIT_FEIN(); + void SKNIT_FAD(); + void SKNIT_FSR(); + void SKNIT_FST(); + void SKNIT_ER(); + void SKNIT_OV(); + void SKNIT_AN4(); + void SKNIT_AN5(); + void SKNIT_AN6(); + void SKNIT_AN7(); + void SKNIT_SB(); + void LDEAX_D(); + void LDEAX_H(); + void LDEAX_Dp(); + void LDEAX_Hp(); + void LDEAX_D_xx(); + void LDEAX_H_A(); + void LDEAX_H_B(); + void LDEAX_H_EA(); + void LDEAX_H_xx(); + void STEAX_D(); + void STEAX_H(); + void STEAX_Dp(); + void STEAX_Hp(); + void STEAX_D_xx(); + void STEAX_H_A(); + void STEAX_H_B(); + void STEAX_H_EA(); + void STEAX_H_xx(); + void DSLR_EA(); + void DSLL_EA(); + void TABLE(); + void DRLR_EA(); + void DRLL_EA(); + void STOP(); + void DMOV_EA_ECNT(); + void DMOV_EA_ECPT(); + void DMOV_ETM0_EA(); + void DMOV_ETM1_EA(); + void MOV_A_PA(); + void MOV_A_PB(); + void MOV_A_PC(); + void MOV_A_PD(); + void MOV_A_PF(); + void MOV_A_MKH(); + void MOV_A_MKL(); + void MOV_A_ANM(); + void MOV_A_SMH(); + void MOV_A_EOM(); + void MOV_A_TMM(); + void MOV_A_PT(); + void MOV_A_RXB(); + void MOV_A_CR0(); + void MOV_A_CR1(); + void MOV_A_CR2(); + void MOV_A_CR3(); + void MOV_PA_A(); + void MOV_PB_A(); + void MOV_PC_A(); + void MOV_PD_A(); + void MOV_PF_A(); + void MOV_MKH_A(); + void MOV_MKL_A(); + void MOV_ANM_A(); + void MOV_SMH_A(); + void MOV_SML_A(); + void MOV_EOM_A(); + void MOV_ETMM_A(); + void MOV_TMM_A(); + void MOV_MM_A(); + void MOV_MCC_A(); + void MOV_MA_A(); + void MOV_MB_A(); + void MOV_MC_A(); + void MOV_MF_A(); + void MOV_TXB_A(); + void MOV_TM0_A(); + void MOV_TM1_A(); + void MOV_ZCM_A(); + void ANA_V_A(); + void ANA_A_A(); + void ANA_B_A(); + void ANA_C_A(); + void ANA_D_A(); + void ANA_E_A(); + void ANA_H_A(); + void ANA_L_A(); + void XRA_V_A(); + void XRA_A_A(); + void XRA_B_A(); + void XRA_C_A(); + void XRA_D_A(); + void XRA_E_A(); + void XRA_H_A(); + void XRA_L_A(); + void ORA_V_A(); + void ORA_A_A(); + void ORA_B_A(); + void ORA_C_A(); + void ORA_D_A(); + void ORA_E_A(); + void ORA_H_A(); + void ORA_L_A(); + void ADDNC_V_A(); + void ADDNC_A_A(); + void ADDNC_B_A(); + void ADDNC_C_A(); + void ADDNC_D_A(); + void ADDNC_E_A(); + void ADDNC_H_A(); + void ADDNC_L_A(); + void GTA_V_A(); + void GTA_A_A(); + void GTA_B_A(); + void GTA_C_A(); + void GTA_D_A(); + void GTA_E_A(); + void GTA_H_A(); + void GTA_L_A(); + void SUBNB_V_A(); + void SUBNB_A_A(); + void SUBNB_B_A(); + void SUBNB_C_A(); + void SUBNB_D_A(); + void SUBNB_E_A(); + void SUBNB_H_A(); + void SUBNB_L_A(); + void LTA_V_A(); + void LTA_A_A(); + void LTA_B_A(); + void LTA_C_A(); + void LTA_D_A(); + void LTA_E_A(); + void LTA_H_A(); + void LTA_L_A(); + void ADD_V_A(); + void ADD_A_A(); + void ADD_B_A(); + void ADD_C_A(); + void ADD_D_A(); + void ADD_E_A(); + void ADD_H_A(); + void ADD_L_A(); + void ADC_V_A(); + void ADC_A_A(); + void ADC_B_A(); + void ADC_C_A(); + void ADC_D_A(); + void ADC_E_A(); + void ADC_H_A(); + void ADC_L_A(); + void SUB_V_A(); + void SUB_A_A(); + void SUB_B_A(); + void SUB_C_A(); + void SUB_D_A(); + void SUB_E_A(); + void SUB_H_A(); + void SUB_L_A(); + void NEA_V_A(); + void NEA_A_A(); + void NEA_B_A(); + void NEA_C_A(); + void NEA_D_A(); + void NEA_E_A(); + void NEA_H_A(); + void NEA_L_A(); + void SBB_V_A(); + void SBB_A_A(); + void SBB_B_A(); + void SBB_C_A(); + void SBB_D_A(); + void SBB_E_A(); + void SBB_H_A(); + void SBB_L_A(); + void EQA_V_A(); + void EQA_A_A(); + void EQA_B_A(); + void EQA_C_A(); + void EQA_D_A(); + void EQA_E_A(); + void EQA_H_A(); + void EQA_L_A(); + void ANA_A_V(); + void ANA_A_B(); + void ANA_A_C(); + void ANA_A_D(); + void ANA_A_E(); + void ANA_A_H(); + void ANA_A_L(); + void XRA_A_V(); + void XRA_A_B(); + void XRA_A_C(); + void XRA_A_D(); + void XRA_A_E(); + void XRA_A_H(); + void XRA_A_L(); + void ORA_A_V(); + void ORA_A_B(); + void ORA_A_C(); + void ORA_A_D(); + void ORA_A_E(); + void ORA_A_H(); + void ORA_A_L(); + void ADDNC_A_V(); + void ADDNC_A_B(); + void ADDNC_A_C(); + void ADDNC_A_D(); + void ADDNC_A_E(); + void ADDNC_A_H(); + void ADDNC_A_L(); + void GTA_A_V(); + void GTA_A_B(); + void GTA_A_C(); + void GTA_A_D(); + void GTA_A_E(); + void GTA_A_H(); + void GTA_A_L(); + void SUBNB_A_V(); + void SUBNB_A_B(); + void SUBNB_A_C(); + void SUBNB_A_D(); + void SUBNB_A_E(); + void SUBNB_A_H(); + void SUBNB_A_L(); + void LTA_A_V(); + void LTA_A_B(); + void LTA_A_C(); + void LTA_A_D(); + void LTA_A_E(); + void LTA_A_H(); + void LTA_A_L(); + void ADD_A_V(); + void ADD_A_B(); + void ADD_A_C(); + void ADD_A_D(); + void ADD_A_E(); + void ADD_A_H(); + void ADD_A_L(); + void ONA_A_V(); + void ONA_A_A(); + void ONA_A_B(); + void ONA_A_C(); + void ONA_A_D(); + void ONA_A_E(); + void ONA_A_H(); + void ONA_A_L(); + void ADC_A_V(); + void ADC_A_B(); + void ADC_A_C(); + void ADC_A_D(); + void ADC_A_E(); + void ADC_A_H(); + void ADC_A_L(); + void OFFA_A_V(); + void OFFA_A_A(); + void OFFA_A_B(); + void OFFA_A_C(); + void OFFA_A_D(); + void OFFA_A_E(); + void OFFA_A_H(); + void OFFA_A_L(); + void SUB_A_V(); + void SUB_A_B(); + void SUB_A_C(); + void SUB_A_D(); + void SUB_A_E(); + void SUB_A_H(); + void SUB_A_L(); + void NEA_A_V(); + void NEA_A_B(); + void NEA_A_C(); + void NEA_A_D(); + void NEA_A_E(); + void NEA_A_H(); + void NEA_A_L(); + void SBB_A_V(); + void SBB_A_B(); + void SBB_A_C(); + void SBB_A_D(); + void SBB_A_E(); + void SBB_A_H(); + void SBB_A_L(); + void EQA_A_V(); + void EQA_A_B(); + void EQA_A_C(); + void EQA_A_D(); + void EQA_A_E(); + void EQA_A_H(); + void EQA_A_L(); + void MVI_PA_xx(); + void MVI_PB_xx(); + void MVI_PC_xx(); + void MVI_PD_xx(); + void MVI_PF_xx(); + void MVI_MKH_xx(); + void MVI_MKL_xx(); + void ANI_PA_xx(); + void ANI_PB_xx(); + void ANI_PC_xx(); + void ANI_PD_xx(); + void ANI_PF_xx(); + void ANI_MKH_xx(); + void ANI_MKL_xx(); + void XRI_PA_xx(); + void XRI_PB_xx(); + void XRI_PC_xx(); + void XRI_PD_xx(); + void XRI_PF_xx(); + void XRI_MKH_xx(); + void XRI_MKL_xx(); + void ORI_PA_xx(); + void ORI_PB_xx(); + void ORI_PC_xx(); + void ORI_PD_xx(); + void ORI_PF_xx(); + void ORI_MKH_xx(); + void ORI_MKL_xx(); + void ADINC_PA_xx(); + void ADINC_PB_xx(); + void ADINC_PC_xx(); + void ADINC_PD_xx(); + void ADINC_PF_xx(); + void ADINC_MKH_xx(); + void ADINC_MKL_xx(); + void GTI_PA_xx(); + void GTI_PB_xx(); + void GTI_PC_xx(); + void GTI_PD_xx(); + void GTI_PF_xx(); + void GTI_MKH_xx(); + void GTI_MKL_xx(); + void SUINB_PA_xx(); + void SUINB_PB_xx(); + void SUINB_PC_xx(); + void SUINB_PD_xx(); + void SUINB_PF_xx(); + void SUINB_MKH_xx(); + void SUINB_MKL_xx(); + void LTI_PA_xx(); + void LTI_PB_xx(); + void LTI_PC_xx(); + void LTI_PD_xx(); + void LTI_PF_xx(); + void LTI_MKH_xx(); + void LTI_MKL_xx(); + void ADI_PA_xx(); + void ADI_PB_xx(); + void ADI_PC_xx(); + void ADI_PD_xx(); + void ADI_PF_xx(); + void ADI_MKH_xx(); + void ADI_MKL_xx(); + void ONI_PA_xx(); + void ONI_PB_xx(); + void ONI_PC_xx(); + void ONI_PD_xx(); + void ONI_PF_xx(); + void ONI_MKH_xx(); + void ONI_MKL_xx(); + void ACI_PA_xx(); + void ACI_PB_xx(); + void ACI_PC_xx(); + void ACI_PD_xx(); + void ACI_PF_xx(); + void ACI_MKH_xx(); + void ACI_MKL_xx(); + void OFFI_PA_xx(); + void OFFI_PB_xx(); + void OFFI_PC_xx(); + void OFFI_PD_xx(); + void OFFI_PF_xx(); + void OFFI_MKH_xx(); + void OFFI_MKL_xx(); + void SUI_PA_xx(); + void SUI_PB_xx(); + void SUI_PC_xx(); + void SUI_PD_xx(); + void SUI_PF_xx(); + void SUI_MKH_xx(); + void SUI_MKL_xx(); + void NEI_PA_xx(); + void NEI_PB_xx(); + void NEI_PC_xx(); + void NEI_PD_xx(); + void NEI_PF_xx(); + void NEI_MKH_xx(); + void NEI_MKL_xx(); + void SBI_PA_xx(); + void SBI_PB_xx(); + void SBI_PC_xx(); + void SBI_PD_xx(); + void SBI_PF_xx(); + void SBI_MKH_xx(); + void SBI_MKL_xx(); + void EQI_PA_xx(); + void EQI_PB_xx(); + void EQI_PC_xx(); + void EQI_PD_xx(); + void EQI_PF_xx(); + void EQI_MKH_xx(); + void EQI_MKL_xx(); + void MVI_ANM_xx(); + void MVI_SMH_xx(); + void MVI_EOM_xx(); + void MVI_TMM_xx(); + void ANI_ANM_xx(); + void ANI_SMH_xx(); + void ANI_EOM_xx(); + void ANI_TMM_xx(); + void XRI_ANM_xx(); + void XRI_SMH_xx(); + void XRI_EOM_xx(); + void XRI_TMM_xx(); + void ORI_ANM_xx(); + void ORI_SMH_xx(); + void ORI_EOM_xx(); + void ORI_TMM_xx(); + void ADINC_ANM_xx(); + void ADINC_SMH_xx(); + void ADINC_EOM_xx(); + void ADINC_TMM_xx(); + void GTI_ANM_xx(); + void GTI_SMH_xx(); + void GTI_EOM_xx(); + void GTI_TMM_xx(); + void SUINB_ANM_xx(); + void SUINB_SMH_xx(); + void SUINB_EOM_xx(); + void SUINB_TMM_xx(); + void LTI_ANM_xx(); + void LTI_SMH_xx(); + void LTI_EOM_xx(); + void LTI_TMM_xx(); + void ADI_ANM_xx(); + void ADI_SMH_xx(); + void ADI_EOM_xx(); + void ADI_TMM_xx(); + void ONI_ANM_xx(); + void ONI_SMH_xx(); + void ONI_EOM_xx(); + void ONI_TMM_xx(); + void ACI_ANM_xx(); + void ACI_SMH_xx(); + void ACI_EOM_xx(); + void ACI_TMM_xx(); + void OFFI_ANM_xx(); + void OFFI_SMH_xx(); + void OFFI_EOM_xx(); + void OFFI_TMM_xx(); + void SUI_ANM_xx(); + void SUI_SMH_xx(); + void SUI_EOM_xx(); + void SUI_TMM_xx(); + void NEI_ANM_xx(); + void NEI_SMH_xx(); + void NEI_EOM_xx(); + void NEI_TMM_xx(); + void SBI_ANM_xx(); + void SBI_SMH_xx(); + void SBI_EOM_xx(); + void SBI_TMM_xx(); + void EQI_ANM_xx(); + void EQI_SMH_xx(); + void EQI_EOM_xx(); + void EQI_TMM_xx(); + void SSPD_w(); + void LSPD_w(); + void SBCD_w(); + void LBCD_w(); + void SDED_w(); + void LDED_w(); + void SHLD_w(); + void LHLD_w(); + void EADD_EA_A(); + void EADD_EA_B(); + void EADD_EA_C(); + void ESUB_EA_A(); + void ESUB_EA_B(); + void ESUB_EA_C(); + void MOV_V_w(); + void MOV_A_w(); + void MOV_B_w(); + void MOV_C_w(); + void MOV_D_w(); + void MOV_E_w(); + void MOV_H_w(); + void MOV_L_w(); + void MOV_w_V(); + void MOV_w_A(); + void MOV_w_B(); + void MOV_w_C(); + void MOV_w_D(); + void MOV_w_E(); + void MOV_w_H(); + void MOV_w_L(); + void ANAX_B(); + void ANAX_D(); + void ANAX_H(); + void ANAX_Dp(); + void ANAX_Hp(); + void ANAX_Dm(); + void ANAX_Hm(); + void XRAX_B(); + void XRAX_D(); + void XRAX_H(); + void XRAX_Dp(); + void XRAX_Hp(); + void XRAX_Dm(); + void XRAX_Hm(); + void ORAX_B(); + void ORAX_D(); + void ORAX_H(); + void ORAX_Dp(); + void ORAX_Hp(); + void ORAX_Dm(); + void ORAX_Hm(); + void ADDNCX_B(); + void ADDNCX_D(); + void ADDNCX_H(); + void ADDNCX_Dp(); + void ADDNCX_Hp(); + void ADDNCX_Dm(); + void ADDNCX_Hm(); + void GTAX_B(); + void GTAX_D(); + void GTAX_H(); + void GTAX_Dp(); + void GTAX_Hp(); + void GTAX_Dm(); + void GTAX_Hm(); + void SUBNBX_B(); + void SUBNBX_D(); + void SUBNBX_H(); + void SUBNBX_Dp(); + void SUBNBX_Hp(); + void SUBNBX_Dm(); + void SUBNBX_Hm(); + void LTAX_B(); + void LTAX_D(); + void LTAX_H(); + void LTAX_Dp(); + void LTAX_Hp(); + void LTAX_Dm(); + void LTAX_Hm(); + void ADDX_B(); + void ADDX_D(); + void ADDX_H(); + void ADDX_Dp(); + void ADDX_Hp(); + void ADDX_Dm(); + void ADDX_Hm(); + void ONAX_B(); + void ONAX_D(); + void ONAX_H(); + void ONAX_Dp(); + void ONAX_Hp(); + void ONAX_Dm(); + void ONAX_Hm(); + void ADCX_B(); + void ADCX_D(); + void ADCX_H(); + void ADCX_Dp(); + void ADCX_Hp(); + void ADCX_Dm(); + void ADCX_Hm(); + void OFFAX_B(); + void OFFAX_D(); + void OFFAX_H(); + void OFFAX_Dp(); + void OFFAX_Hp(); + void OFFAX_Dm(); + void OFFAX_Hm(); + void SUBX_B(); + void SUBX_D(); + void SUBX_H(); + void SUBX_Dp(); + void SUBX_Hp(); + void SUBX_Dm(); + void SUBX_Hm(); + void NEAX_B(); + void NEAX_D(); + void NEAX_H(); + void NEAX_Dp(); + void NEAX_Hp(); + void NEAX_Dm(); + void NEAX_Hm(); + void SBBX_B(); + void SBBX_D(); + void SBBX_H(); + void SBBX_Dp(); + void SBBX_Hp(); + void SBBX_Dm(); + void SBBX_Hm(); + void EQAX_B(); + void EQAX_D(); + void EQAX_H(); + void EQAX_Dp(); + void EQAX_Hp(); + void EQAX_Dm(); + void EQAX_Hm(); + void ANI_V_xx(); + void ANI_A_xx(); + void ANI_B_xx(); + void ANI_C_xx(); + void ANI_D_xx(); + void ANI_E_xx(); + void ANI_H_xx(); + void ANI_L_xx(); + void XRI_V_xx(); + void XRI_A_xx(); + void XRI_B_xx(); + void XRI_C_xx(); + void XRI_D_xx(); + void XRI_E_xx(); + void XRI_H_xx(); + void XRI_L_xx(); + void ORI_V_xx(); + void ORI_A_xx(); + void ORI_B_xx(); + void ORI_C_xx(); + void ORI_D_xx(); + void ORI_E_xx(); + void ORI_H_xx(); + void ORI_L_xx(); + void ADINC_V_xx(); + void ADINC_A_xx(); + void ADINC_B_xx(); + void ADINC_C_xx(); + void ADINC_D_xx(); + void ADINC_E_xx(); + void ADINC_H_xx(); + void ADINC_L_xx(); + void GTI_V_xx(); + void GTI_A_xx(); + void GTI_B_xx(); + void GTI_C_xx(); + void GTI_D_xx(); + void GTI_E_xx(); + void GTI_H_xx(); + void GTI_L_xx(); + void SUINB_V_xx(); + void SUINB_A_xx(); + void SUINB_B_xx(); + void SUINB_C_xx(); + void SUINB_D_xx(); + void SUINB_E_xx(); + void SUINB_H_xx(); + void SUINB_L_xx(); + void LTI_V_xx(); + void LTI_A_xx(); + void LTI_B_xx(); + void LTI_C_xx(); + void LTI_D_xx(); + void LTI_E_xx(); + void LTI_H_xx(); + void LTI_L_xx(); + void ADI_V_xx(); + void ADI_A_xx(); + void ADI_B_xx(); + void ADI_C_xx(); + void ADI_D_xx(); + void ADI_E_xx(); + void ADI_H_xx(); + void ADI_L_xx(); + void ONI_V_xx(); + void ONI_A_xx(); + void ONI_B_xx(); + void ONI_C_xx(); + void ONI_D_xx(); + void ONI_E_xx(); + void ONI_H_xx(); + void ONI_L_xx(); + void ACI_V_xx(); + void ACI_A_xx(); + void ACI_B_xx(); + void ACI_C_xx(); + void ACI_D_xx(); + void ACI_E_xx(); + void ACI_H_xx(); + void ACI_L_xx(); + void OFFI_V_xx(); + void OFFI_A_xx(); + void OFFI_B_xx(); + void OFFI_C_xx(); + void OFFI_D_xx(); + void OFFI_E_xx(); + void OFFI_H_xx(); + void OFFI_L_xx(); + void SUI_V_xx(); + void SUI_A_xx(); + void SUI_B_xx(); + void SUI_C_xx(); + void SUI_D_xx(); + void SUI_E_xx(); + void SUI_H_xx(); + void SUI_L_xx(); + void NEI_V_xx(); + void NEI_A_xx(); + void NEI_B_xx(); + void NEI_C_xx(); + void NEI_D_xx(); + void NEI_E_xx(); + void NEI_H_xx(); + void NEI_L_xx(); + void SBI_V_xx(); + void SBI_A_xx(); + void SBI_B_xx(); + void SBI_C_xx(); + void SBI_D_xx(); + void SBI_E_xx(); + void SBI_H_xx(); + void SBI_L_xx(); + void EQI_V_xx(); + void EQI_A_xx(); + void EQI_B_xx(); + void EQI_C_xx(); + void EQI_D_xx(); + void EQI_E_xx(); + void EQI_H_xx(); + void EQI_L_xx(); + void ANAW_wa(); + void DAN_EA_BC(); + void DAN_EA_DE(); + void DAN_EA_HL(); + void XRAW_wa(); + void DXR_EA_BC(); + void DXR_EA_DE(); + void DXR_EA_HL(); + void ORAW_wa(); + void DOR_EA_BC(); + void DOR_EA_DE(); + void DOR_EA_HL(); + void ADDNCW_wa(); + void DADDNC_EA_BC(); + void DADDNC_EA_DE(); + void DADDNC_EA_HL(); + void GTAW_wa(); + void DGT_EA_BC(); + void DGT_EA_DE(); + void DGT_EA_HL(); + void SUBNBW_wa(); + void DSUBNB_EA_BC(); + void DSUBNB_EA_DE(); + void DSUBNB_EA_HL(); + void LTAW_wa(); + void DLT_EA_BC(); + void DLT_EA_DE(); + void DLT_EA_HL(); + void ADDW_wa(); + void DADD_EA_BC(); + void DADD_EA_DE(); + void DADD_EA_HL(); + void ONAW_wa(); + void DON_EA_BC(); + void DON_EA_DE(); + void DON_EA_HL(); + void ADCW_wa(); + void DADC_EA_BC(); + void DADC_EA_DE(); + void DADC_EA_HL(); + void OFFAW_wa(); + void DOFF_EA_BC(); + void DOFF_EA_DE(); + void DOFF_EA_HL(); + void SUBW_wa(); + void DSUB_EA_BC(); + void DSUB_EA_DE(); + void DSUB_EA_HL(); + void NEAW_wa(); + void DNE_EA_BC(); + void DNE_EA_DE(); + void DNE_EA_HL(); + void SBBW_wa(); + void DSBB_EA_BC(); + void DSBB_EA_DE(); + void DSBB_EA_HL(); + void EQAW_wa(); + void DEQ_EA_BC(); + void DEQ_EA_DE(); + void DEQ_EA_HL(); + void NOP(); + void LDAW_wa(); + void INX_SP(); + void DCX_SP(); + void LXI_S_w(); + void ANIW_wa_xx(); + void MOV_A_EAH(); + void MOV_A_EAL(); + void MOV_A_B(); + void MOV_A_C(); + void MOV_A_D(); + void MOV_A_E(); + void MOV_A_H(); + void MOV_A_L(); + void EXA(); + void EXX(); + void EXR(); + void INX_BC(); + void DCX_BC(); + void LXI_B_w(); + void ORIW_wa_xx(); + void MOV_EAH_A(); + void MOV_EAL_A(); + void MOV_B_A(); + void MOV_C_A(); + void MOV_D_A(); + void MOV_E_A(); + void MOV_H_A(); + void MOV_L_A(); + void INRW_wa(); + void JB(); + void INX_DE(); + void DCX_DE(); + void LXI_D_w(); + void GTIW_wa_xx(); + void LDAX_B(); + void LDAX_D(); + void LDAX_H(); + void LDAX_Dp(); + void LDAX_Hp(); + void LDAX_Dm(); + void LDAX_Hm(); + void DCRW_wa(); + void BLOCK(); + void INX_HL(); + void DCX_HL(); + void LXI_H_w(); + void LTIW_wa_xx(); + void STAX_B(); + void STAX_D(); + void STAX_H(); + void STAX_Dp(); + void STAX_Hp(); + void STAX_Dm(); + void STAX_Hm(); + void CALL_w(); + void INR_A(); + void INR_B(); + void INR_C(); + void LXI_EA_s(); + void ONIW_wa_xx(); + void PRE_48(); + void MVIX_BC_xx(); + void MVIX_DE_xx(); + void MVIX_HL_xx(); + void PRE_4C(); + void PRE_4D(); + void JRE(); + void EXH(); + void DCR_A(); + void DCR_B(); + void DCR_C(); + void JMP_w(); + void OFFIW_wa_xx(); + void BIT_0_wa(); + void BIT_1_wa(); + void BIT_2_wa(); + void BIT_3_wa(); + void BIT_4_wa(); + void BIT_5_wa(); + void BIT_6_wa(); + void BIT_7_wa(); + void SKN_bit(); + void SETB(); + void CLR(); + void SK_bit(); + void PRE_60(); + void DAA(); + void RETI(); + void STAW_wa(); + void PRE_64(); + void NEIW_wa_xx(); + void MVI_V_xx(); + void MVI_A_xx(); + void MVI_B_xx(); + void MVI_C_xx(); + void MVI_D_xx(); + void MVI_E_xx(); + void MVI_H_xx(); + void MVI_L_xx(); + void PRE_70(); + void MVIW_wa_xx(); + void SOFTI(); + void PRE_74(); + void EQIW_wa_xx(); + void CALF(); + void CALT(); + void POP_VA(); + void POP_BC(); + void POP_DE(); + void POP_HL(); + void POP_EA(); + void DMOV_EA_BC(); + void DMOV_EA_DE(); + void DMOV_EA_HL(); + void INX_EA(); + void DCX_EA(); + void EI(); + void LDAX_D_xx(); + void LDAX_H_A(); + void LDAX_H_B(); + void LDAX_H_EA(); + void LDAX_H_xx(); + void PUSH_VA(); + void PUSH_BC(); + void PUSH_DE(); + void PUSH_HL(); + void PUSH_EA(); + void DMOV_BC_EA(); + void DMOV_DE_EA(); + void DMOV_HL_EA(); + void RET(); + void RETS(); + void DI(); + void STAX_D_xx(); + void STAX_H_A(); + void STAX_H_B(); + void STAX_H_EA(); + void STAX_H_xx(); + void JR(); + void CALT_7801(); + void DCR_A_7801(); + void DCR_B_7801(); + void DCR_C_7801(); + void DCRW_wa_7801(); + void INR_A_7801(); + void INR_B_7801(); + void INR_C_7801(); + void INRW_wa_7801(); + void IN(); + void OUT(); + void MOV_A_S(); + void MOV_S_A(); + void PEN(); + void PER(); + void PEX(); + void SIO(); + void SKIT_F0(); + void SKNIT_F0(); + void STM(); + void STM_7801(); + void MOV_MC_A_7801(); + void base_device_start(); +}; + + +class upd7807_device : public upd7810_device +{ +public: + // construction/destruction + upd7807_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); +}; + + +class upd7801_device : public upd7810_device +{ +public: + // construction/destruction + upd7801_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual void device_reset(); + virtual void execute_set_input(int inputnum, int state); + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + virtual void handle_timers(int cycles); + virtual void upd7810_take_irq(); +}; + + +class upd78c05_device : public upd7810_device +{ +public: + // construction/destruction + upd78c05_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + upd78c05_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + +protected: + virtual void device_start(); + virtual void device_reset(); + virtual UINT64 execute_clocks_to_cycles(UINT64 clocks) const { return (clocks + 4 - 1) / 4; } + virtual UINT64 execute_cycles_to_clocks(UINT64 cycles) const { return (cycles * 4); } + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + virtual void handle_timers(int cycles); +}; + + +class upd78c06_device : public upd78c05_device +{ +public: + // construction/destruction + upd78c06_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +extern const device_type UPD7810; +extern const device_type UPD7807; +extern const device_type UPD7801; +extern const device_type UPD78C05; +extern const device_type UPD78C06; + + +#endif /* __UPD7810_H__ */ diff --git a/src/devices/cpu/upd7810/upd7810_dasm.c b/src/devices/cpu/upd7810/upd7810_dasm.c new file mode 100644 index 00000000000..63e7291ff5e --- /dev/null +++ b/src/devices/cpu/upd7810/upd7810_dasm.c @@ -0,0 +1,5465 @@ +// license:BSD-3-Clause +// copyright-holders:Juergen Buchmueller +/***************************************************************************** + * + * Portable uPD7810/11, 7810H/11H, 78C10/C11/C14 disassembler + * + * NS20030112: added 7807. + * + *****************************************************************************/ + +#include "emu.h" +#include "debugger.h" +#include "upd7810.h" + +struct dasm_s { + UINT8 token; + const void *args; +}; + +enum +{ + illegal=1, + ACI, + ADC, + ADCW, + ADCX, + ADD, + ADDNC, + ADDNCW, + ADDNCX, + ADDW, + ADDX, + ADI, + ADINC, + ANA, + ANAW, + ANAX, + AND, + ANI, + ANIW, + BIT, + BLOCK, + CALB, + CALF, + CALL, + CALT, + CLC, + CLR, /* 7807 */ + CMC, /* 7807 */ + DAA, + DADC, + DADD, + DADDNC, + DAN, + DCR, + DCRW, + DCX, + DEQ, + DGT, + DI, + DIV, + DLT, + DMOV, + DNE, + DOFF, + DON, + DOR, + DRLL, + DRLR, + DSBB, + DSLL, + DSLR, + DSUB, + DSUBNB, + DXR, + EADD, + EI, + EQA, + EQAW, + EQAX, + EQI, + EQIW, + ESUB, + EX, /* 7801 */ + EXA, + EXH, + EXX, + EXR, /* 7807 */ + GTA, + GTAW, + GTAX, + GTI, + GTIW, + HALT, + IN, /* 7801 */ + INR, + INRW, + INX, + JB, + JEA, + JMP, + JR, + JRE, + LBCD, + LDAW, + LDAX, + LDEAX, + LDED, + LHLD, + LSPD, + LTA, + LTAW, + LTAX, + LTI, + LTIW, + LXI, + MOV, + MUL, + MVI, + MVIW, + MVIX, + NEA, + NEAW, + NEAX, + NEGA, + NEI, + NEIW, + NOP, + NOT, /* 7807 */ + OFFA, + OFFAW, + OFFAX, + OFFI, + OFFIW, + ONA, + ONAW, + ONAX, + ONI, + ONIW, + OR, /* 7807 */ + ORA, + ORAW, + ORAX, + ORI, + ORIW, + OUT, /* 7801 */ + PER, /* 7801 */ + PEX, /* 7801 */ + POP, + PUSH, + RET, + RETI, + RETS, + RLD, + RLL, + RLR, + RRD, + SBB, + SBBW, + SBBX, + SBCD, + SBI, + SDED, + SETB, /* 7807 */ + SHLD, + SIO, /* 7801 */ + SK, + SKIT, + SKN, + SKNIT, + SLL, + SLLC, + SLR, + SLRC, + SOFTI, + SSPD, + STAW, + STAX, + STC, + STEAX, + STM, /* 7801 */ + STOP, + SUB, + SUBNB, + SUBNBW, + SUBNBX, + SUBW, + SUBX, + SUI, + SUINB, + TABLE, + XOR, /* 7807 */ + XRA, + XRAW, + XRAX, + XRI +}; + +static const char *const token[] = +{ + "", + "illegal", + "ACI", + "ADC", + "ADCW", + "ADCX", + "ADD", + "ADDNC", + "ADDNCW", + "ADDNCX", + "ADDW", + "ADDX", + "ADI", + "ADINC", + "ANA", + "ANAW", + "ANAX", + "AND", + "ANI", + "ANIW", + "BIT", + "BLOCK", + "CALB", + "CALF", + "CALL", + "CALT", + "CLC", + "CLR", /* 7807 */ + "CMC", /* 7807 */ + "DAA", + "DADC", + "DADD", + "DADDNC", + "DAN", + "DCR", + "DCRW", + "DCX", + "DEQ", + "DGT", + "DI", + "DIV", + "DLT", + "DMOV", + "DNE", + "DOFF", + "DON", + "DOR", + "DRLL", + "DRLR", + "DSBB", + "DSLL", + "DSLR", + "DSUB", + "DSUBNB", + "DXR", + "EADD", + "EI", + "EQA", + "EQAW", + "EQAX", + "EQI", + "EQIW", + "ESUB", + "EX", /* 7801 */ + "EXA", + "EXH", + "EXX", + "EXR", /* 7807 */ + "GTA", + "GTAW", + "GTAX", + "GTI", + "GTIW", + "HALT", + "IN", /* 7801 */ + "INR", + "INRW", + "INX", + "JB", + "JEA", + "JMP", + "JR", + "JRE", + "LBCD", + "LDAW", + "LDAX", + "LDEAX", + "LDED", + "LHLD", + "LSPD", + "LTA", + "LTAW", + "LTAX", + "LTI", + "LTIW", + "LXI", + "MOV", + "MUL", + "MVI", + "MVIW", + "MVIX", + "NEA", + "NEAW", + "NEAX", + "NEGA", + "NEI", + "NEIW", + "NOP", + "NOT", /* 7807 */ + "OFFA", + "OFFAW", + "OFFAX", + "OFFI", + "OFFIW", + "ONA", + "ONAW", + "ONAX", + "ONI", + "ONIW", + "OR", /* 7807 */ + "ORA", + "ORAW", + "ORAX", + "ORI", + "ORIW", + "OUT", /* 7801 */ + "PER", /* 7801 */ + "PEX", /* 7801 */ + "POP", + "PUSH", + "RET", + "RETI", + "RETS", + "RLD", + "RLL", + "RLR", + "RRD", + "SBB", + "SBBW", + "SBBX", + "SBCD", + "SBI", + "SDED", + "SETB", /* 7807 */ + "SHLD", + "SIO", /* 7801 */ + "SK", + "SKIT", + "SKN", + "SKNIT", + "SLL", + "SLLC", + "SLR", + "SLRC", + "SOFTI", + "SSPD", + "STAW", + "STAX", + "STC", + "STEAX", + "STM", /*7801 */ + "STOP", + "SUB", + "SUBNB", + "SUBNBW", + "SUBNBX", + "SUBW", + "SUBX", + "SUI", + "SUINB", + "TABLE", + "XOR", /* 7807 */ + "XRA", + "XRAW", + "XRAX", + "XRI" +}; + + +/* prefix 48 */ +static const struct dasm_s dasm48_7810[256] = +{ + {illegal,0 }, /* 00: 0100 1000 0000 0000 */ + {SLRC,"A" }, /* 01: 0100 1000 0000 0001 */ + {SLRC,"B" }, /* 02: 0100 1000 0000 0010 */ + {SLRC,"C" }, /* 03: 0100 1000 0000 0011 */ + {illegal,0 }, /* 04: 0100 1000 0000 0100 */ + {SLLC,"A" }, /* 05: 0100 1000 0000 0101 */ + {SLLC,"B" }, /* 06: 0100 1000 0000 0110 */ + {SLLC,"C" }, /* 07: 0100 1000 0000 0111 */ + {SK,"NV" }, /* 08: 0100 1000 0000 1000 */ + {illegal,0 }, /* 09: 0100 1000 0000 1001 */ + {SK,"CY" }, /* 0a: 0100 1000 0000 1010 */ + {SK,"HC" }, /* 0b: 0100 1000 0000 1011 */ + {SK,"Z" }, /* 0c: 0100 1000 0000 1100 */ + {illegal,0 }, /* 0d: 0100 1000 0000 1101 */ + {illegal,0 }, /* 0e: 0100 1000 0000 1110 */ + {illegal,0 }, /* 0f: 0100 1000 0000 1111 */ + + {illegal,0 }, /* 10: 0100 1000 0001 0000 */ + {illegal,0 }, /* 11: 0100 1000 0001 0001 */ + {illegal,0 }, /* 12: 0100 1000 0001 0010 */ + {illegal,0 }, /* 13: 0100 1000 0001 0011 */ + {illegal,0 }, /* 14: 0100 1000 0001 0100 */ + {illegal,0 }, /* 15: 0100 1000 0001 0101 */ + {illegal,0 }, /* 16: 0100 1000 0001 0110 */ + {illegal,0 }, /* 17: 0100 1000 0001 0111 */ + {SKN,"NV" }, /* 18: 0100 1000 0001 1000 */ + {illegal,0 }, /* 19: 0100 1000 0001 1001 */ + {SKN,"CY" }, /* 1a: 0100 1000 0001 1010 */ + {SKN,"HC" }, /* 1b: 0100 1000 0001 1011 */ + {SKN,"Z" }, /* 1c: 0100 1000 0001 1100 */ + {illegal,0 }, /* 1d: 0100 1000 0001 1101 */ + {illegal,0 }, /* 1e: 0100 1000 0001 1110 */ + {illegal,0 }, /* 1f: 0100 1000 0001 1111 */ + + {illegal,0 }, /* 20: 0100 1000 0010 0000 */ + {SLR,"A" }, /* 21: 0100 1000 0010 0001 */ + {SLR,"B" }, /* 22: 0100 1000 0010 0010 */ + {SLR,"C" }, /* 23: 0100 1000 0010 0011 */ + {illegal,0 }, /* 24: 0100 1000 0010 0100 */ + {SLL,"A" }, /* 25: 0100 1000 0010 0101 */ + {SLL,"B" }, /* 26: 0100 1000 0010 0110 */ + {SLL,"C" }, /* 27: 0100 1000 0010 0111 */ + {JEA,0 }, /* 28: 0100 1000 0010 1000 */ + {CALB,0 }, /* 29: 0100 1000 0010 1001 */ + {CLC,0 }, /* 2a: 0100 1000 0010 1010 */ + {STC,0 }, /* 2b: 0100 1000 0010 1011 */ + {illegal,0 }, /* 2c: 0100 1000 0010 1100 */ + {MUL,"A" }, /* 2d: 0100 1000 0010 1101 */ + {MUL,"B" }, /* 2e: 0100 1000 0010 1110 */ + {MUL,"C" }, /* 2f: 0100 1000 0010 1111 */ + + {illegal,0 }, /* 30: 0100 1000 0011 0000 */ + {RLR,"A" }, /* 31: 0100 1000 0011 0001 */ + {RLR,"B" }, /* 32: 0100 1000 0011 0010 */ + {RLR,"C" }, /* 33: 0100 1000 0011 0011 */ + {illegal,0 }, /* 34: 0100 1000 0011 0100 */ + {RLL,"A" }, /* 35: 0100 1000 0011 0101 */ + {RLL,"B" }, /* 36: 0100 1000 0011 0110 */ + {RLL,"C" }, /* 37: 0100 1000 0011 0111 */ + {RLD,0 }, /* 38: 0100 1000 0011 1000 */ + {RRD,0 }, /* 39: 0100 1000 0011 1001 */ + {NEGA,0 }, /* 3a: 0100 1000 0011 1010 */ + {HALT,0 }, /* 3b: 0100 1000 0011 1011 */ + {illegal,0 }, /* 3c: 0100 1000 0011 1100 */ + {DIV,"A" }, /* 3d: 0100 1000 0011 1101 */ + {DIV,"B" }, /* 3e: 0100 1000 0011 1110 */ + {DIV,"C" }, /* 3f: 0100 1000 0011 1111 */ + + {SKIT,"NMI" }, /* 40: 0100 1000 0100 0000 */ + {SKIT,"FT0" }, /* 41: 0100 1000 0100 0001 */ + {SKIT,"FT1" }, /* 42: 0100 1000 0100 0010 */ + {SKIT,"F1" }, /* 43: 0100 1000 0100 0011 */ + {SKIT,"F2" }, /* 44: 0100 1000 0100 0100 */ + {SKIT,"FE0" }, /* 45: 0100 1000 0100 0101 */ + {SKIT,"FE1" }, /* 46: 0100 1000 0100 0110 */ + {SKIT,"FEIN" }, /* 47: 0100 1000 0100 0111 */ + {SKIT,"FAD" }, /* 48: 0100 1000 0100 1000 */ + {SKIT,"FSR" }, /* 49: 0100 1000 0100 1001 */ + {SKIT,"FST" }, /* 4a: 0100 1000 0100 1010 */ + {SKIT,"ER" }, /* 4b: 0100 1000 0100 1011 */ + {SKIT,"OV" }, /* 4c: 0100 1000 0100 1100 */ + {illegal,0 }, /* 4d: 0100 1000 0100 1101 */ + {illegal,0 }, /* 4e: 0100 1000 0100 1110 */ + {illegal,0 }, /* 4f: 0100 1000 0100 1111 */ + + {SKIT,"AN4" }, /* 50: 0100 1000 0101 0000 */ + {SKIT,"AN5" }, /* 51: 0100 1000 0101 0001 */ + {SKIT,"AN6" }, /* 52: 0100 1000 0101 0010 */ + {SKIT,"AN7" }, /* 53: 0100 1000 0101 0011 */ + {SKIT,"SB" }, /* 54: 0100 1000 0101 0100 */ + {illegal,0 }, /* 55: 0100 1000 0101 0101 */ + {illegal,0 }, /* 56: 0100 1000 0101 0110 */ + {illegal,0 }, /* 57: 0100 1000 0101 0111 */ + {illegal,0 }, /* 58: 0100 1000 0101 1000 */ + {illegal,0 }, /* 59: 0100 1000 0101 1001 */ + {illegal,0 }, /* 5a: 0100 1000 0101 1010 */ + {illegal,0 }, /* 5b: 0100 1000 0101 1011 */ + {illegal,0 }, /* 5c: 0100 1000 0101 1100 */ + {illegal,0 }, /* 5d: 0100 1000 0101 1101 */ + {illegal,0 }, /* 5e: 0100 1000 0101 1110 */ + {illegal,0 }, /* 5f: 0100 1000 0101 1111 */ + + {SKNIT,"NMI" }, /* 60: 0100 1000 0110 0000 */ + {SKNIT,"FT0" }, /* 61: 0100 1000 0110 0001 */ + {SKNIT,"FT1" }, /* 62: 0100 1000 0110 0010 */ + {SKNIT,"F1" }, /* 63: 0100 1000 0110 0011 */ + {SKNIT,"F2" }, /* 64: 0100 1000 0110 0100 */ + {SKNIT,"FE0" }, /* 65: 0100 1000 0110 0101 */ + {SKNIT,"FE1" }, /* 66: 0100 1000 0110 0110 */ + {SKNIT,"FEIN" }, /* 67: 0100 1000 0110 0111 */ + {SKNIT,"FAD" }, /* 68: 0100 1000 0110 1000 */ + {SKNIT,"FSR" }, /* 69: 0100 1000 0110 1001 */ + {SKNIT,"FST" }, /* 6a: 0100 1000 0110 1010 */ + {SKNIT,"ER" }, /* 6b: 0100 1000 0110 1011 */ + {SKNIT,"OV" }, /* 6c: 0100 1000 0110 1100 */ + {illegal,0 }, /* 6d: 0100 1000 0110 1101 */ + {illegal,0 }, /* 6e: 0100 1000 0110 1110 */ + {illegal,0 }, /* 6f: 0100 1000 0110 1111 */ + + {SKNIT,"AN4" }, /* 70: 0100 1000 0111 0000 */ + {SKNIT,"AN5" }, /* 71: 0100 1000 0111 0001 */ + {SKNIT,"AN6" }, /* 72: 0100 1000 0111 0010 */ + {SKNIT,"AN7" }, /* 73: 0100 1000 0111 0011 */ + {SKNIT,"SB" }, /* 74: 0100 1000 0111 0100 */ + {illegal,0 }, /* 75: 0100 1000 0111 0101 */ + {illegal,0 }, /* 76: 0100 1000 0111 0110 */ + {illegal,0 }, /* 77: 0100 1000 0111 0111 */ + {illegal,0 }, /* 78: 0100 1000 0111 1000 */ + {illegal,0 }, /* 79: 0100 1000 0111 1001 */ + {illegal,0 }, /* 7a: 0100 1000 0111 1010 */ + {illegal,0 }, /* 7b: 0100 1000 0111 1011 */ + {illegal,0 }, /* 7c: 0100 1000 0111 1100 */ + {illegal,0 }, /* 7d: 0100 1000 0111 1101 */ + {illegal,0 }, /* 7e: 0100 1000 0111 1110 */ + {illegal,0 }, /* 7f: 0100 1000 0111 1111 */ + + {illegal,0 }, /* 80: 0100 1000 1000 0000 */ + {illegal,0 }, /* 81: 0100 1000 1000 0001 */ + {LDEAX,"(DE)" }, /* 82: 0100 1000 1000 0010 */ + {LDEAX,"(HL)" }, /* 83: 0100 1000 1000 0011 */ + {LDEAX,"(DE++)" }, /* 84: 0100 1000 1000 0100 */ + {LDEAX,"(HL++)" }, /* 85: 0100 1000 1000 0101 */ + {illegal,0 }, /* 86: 0100 1000 1000 0110 */ + {illegal,0 }, /* 87: 0100 1000 1000 0111 */ + {illegal,0 }, /* 88: 0100 1000 1000 1000 */ + {illegal,0 }, /* 89: 0100 1000 1000 1001 */ + {illegal,0 }, /* 8a: 0100 1000 1000 1010 */ + {LDEAX,"(DE+%b)"}, /* 8b: 0100 1000 1000 1011 xxxx xxxx */ + {LDEAX,"(HL+A)" }, /* 8c: 0100 1000 1000 1100 */ + {LDEAX,"(HL+B)" }, /* 8d: 0100 1000 1000 1101 */ + {LDEAX,"(HL+EA)"}, /* 8e: 0100 1000 1000 1110 */ + {LDEAX,"(HL+%b)"}, /* 8f: 0100 1000 1000 1111 xxxx xxxx */ + + {illegal,0 }, /* 90: 0100 1000 1000 0000 */ + {illegal,0 }, /* 91: 0100 1000 1000 0001 */ + {STEAX,"(DE)" }, /* 92: 0100 1000 1000 0010 */ + {STEAX,"(HL)" }, /* 93: 0100 1000 1000 0011 */ + {STEAX,"(DE++)" }, /* 94: 0100 1000 1000 0100 */ + {STEAX,"(HL++)" }, /* 95: 0100 1000 1000 0101 */ + {illegal,0 }, /* 96: 0100 1000 1000 0110 */ + {illegal,0 }, /* 97: 0100 1000 1000 0111 */ + {illegal,0 }, /* 98: 0100 1000 1000 1000 */ + {illegal,0 }, /* 99: 0100 1000 1000 1001 */ + {illegal,0 }, /* 9a: 0100 1000 1000 1010 */ + {STEAX,"(DE+%b)"}, /* 9b: 0100 1000 1000 1011 xxxx xxxx */ + {STEAX,"(HL+A)" }, /* 9c: 0100 1000 1000 1100 */ + {STEAX,"(HL+B)" }, /* 9d: 0100 1000 1000 1101 */ + {STEAX,"(HL+EA)"}, /* 9e: 0100 1000 1000 1110 */ + {STEAX,"(HL+%b)"}, /* 9f: 0100 1000 1000 1111 xxxx xxxx */ + + {DSLR,"EA" }, /* a0: 0100 1000 1010 0000 */ + {illegal,0 }, /* a1: 0100 1000 1010 0001 */ + {illegal,0 }, /* a2: 0100 1000 1010 0010 */ + {illegal,0 }, /* a3: 0100 1000 1010 0011 */ + {DSLL,"EA" }, /* a4: 0100 1000 1010 0100 */ + {illegal,0 }, /* a5: 0100 1000 1010 0101 */ + {illegal,0 }, /* a6: 0100 1000 1010 0110 */ + {illegal,0 }, /* a7: 0100 1000 1010 0111 */ + {TABLE,0 }, /* a8: 0100 1000 1010 1000 */ + {illegal,0 }, /* a9: 0100 1000 1010 1001 */ + {illegal,0 }, /* aa: 0100 1000 1010 1010 */ + {illegal,0 }, /* ab: 0100 1000 1010 1011 */ + {illegal,0 }, /* ac: 0100 1000 1010 1100 */ + {illegal,0 }, /* ad: 0100 1000 1010 1101 */ + {illegal,0 }, /* ae: 0100 1000 1010 1110 */ + {illegal,0 }, /* af: 0100 1000 1010 1111 */ + + {DRLR,"EA" }, /* b0: 0100 1000 1011 0000 */ + {illegal,0 }, /* b1: 0100 1000 1011 0001 */ + {illegal,0 }, /* b2: 0100 1000 1011 0010 */ + {illegal,0 }, /* b3: 0100 1000 1011 0011 */ + {DRLL,"EA" }, /* b4: 0100 1000 1011 0100 */ + {illegal,0 }, /* b5: 0100 1000 1011 0101 */ + {illegal,0 }, /* b6: 0100 1000 1011 0110 */ + {illegal,0 }, /* b7: 0100 1000 1011 0111 */ + {illegal,0 }, /* b8: 0100 1000 1011 1000 */ + {illegal,0 }, /* b9: 0100 1000 1011 1001 */ + {illegal,0 }, /* ba: 0100 1000 1011 1010 */ + {STOP,0 }, /* bb: 0100 1000 1011 1011 */ /* 7810 */ + {illegal,0 }, /* bc: 0100 1000 1011 1100 */ + {illegal,0 }, /* bd: 0100 1000 1011 1101 */ + {illegal,0 }, /* be: 0100 1000 1011 1110 */ + {illegal,0 }, /* bf: 0100 1000 1011 1111 */ + + {DMOV,"EA,ECNT" }, /* c0: 0100 1000 1100 0000 */ + {DMOV,"EA,ECPT" }, /* c1: 0100 1000 1100 0001 */ /* 7810 */ + {illegal,0 }, /* c2: 0100 1000 1100 0010 */ + {illegal,0 }, /* c3: 0100 1000 1100 0011 */ + {illegal,0 }, /* c4: 0100 1000 1100 0100 */ + {illegal,0 }, /* c5: 0100 1000 1100 0101 */ + {illegal,0 }, /* c6: 0100 1000 1100 0110 */ + {illegal,0 }, /* c7: 0100 1000 1100 0111 */ + {illegal,0 }, /* c8: 0100 1000 1100 1000 */ + {illegal,0 }, /* c9: 0100 1000 1100 1001 */ + {illegal,0 }, /* ca: 0100 1000 1100 1010 */ + {illegal,0 }, /* cb: 0100 1000 1100 1011 */ + {illegal,0 }, /* cc: 0100 1000 1100 1100 */ + {illegal,0 }, /* cd: 0100 1000 1100 1101 */ + {illegal,0 }, /* ce: 0100 1000 1100 1110 */ + {illegal,0 }, /* cf: 0100 1000 1100 1111 */ + + {illegal,0 }, /* d0: 0100 1000 1101 0000 */ + {illegal,0 }, /* d1: 0100 1000 1101 0001 */ + {DMOV,"ETM0,EA" }, /* d2: 0100 1000 1101 0010 */ + {DMOV,"ETM1,EA" }, /* d3: 0100 1000 1101 0011 */ + {illegal,0 }, /* d4: 0100 1000 1101 0100 */ + {illegal,0 }, /* d5: 0100 1000 1101 0101 */ + {illegal,0 }, /* d6: 0100 1000 1101 0110 */ + {illegal,0 }, /* d7: 0100 1000 1101 0111 */ + {illegal,0 }, /* d8: 0100 1000 1101 1000 */ + {illegal,0 }, /* d9: 0100 1000 1101 1001 */ + {illegal,0 }, /* da: 0100 1000 1101 1010 */ + {illegal,0 }, /* db: 0100 1000 1101 1011 */ + {illegal,0 }, /* dc: 0100 1000 1101 1100 */ + {illegal,0 }, /* dd: 0100 1000 1101 1101 */ + {illegal,0 }, /* de: 0100 1000 1101 1110 */ + {illegal,0 }, /* df: 0100 1000 1101 1111 */ + + {illegal,0 }, /* e0: 0100 1000 1110 0000 */ + {illegal,0 }, /* e1: 0100 1000 1110 0001 */ + {illegal,0 }, /* e2: 0100 1000 1110 0010 */ + {illegal,0 }, /* e3: 0100 1000 1110 0011 */ + {illegal,0 }, /* e4: 0100 1000 1110 0100 */ + {illegal,0 }, /* e5: 0100 1000 1110 0101 */ + {illegal,0 }, /* e6: 0100 1000 1110 0110 */ + {illegal,0 }, /* e7: 0100 1000 1110 0111 */ + {illegal,0 }, /* e8: 0100 1000 1110 1000 */ + {illegal,0 }, /* e9: 0100 1000 1110 1001 */ + {illegal,0 }, /* ea: 0100 1000 1110 1010 */ + {illegal,0 }, /* eb: 0100 1000 1110 1011 */ + {illegal,0 }, /* ec: 0100 1000 1110 1100 */ + {illegal,0 }, /* ed: 0100 1000 1110 1101 */ + {illegal,0 }, /* ee: 0100 1000 1110 1110 */ + {illegal,0 }, /* ef: 0100 1000 1110 1111 */ + + {illegal,0 }, /* f0: 0100 1000 1111 0000 */ + {illegal,0 }, /* f1: 0100 1000 1111 0001 */ + {illegal,0 }, /* f2: 0100 1000 1111 0010 */ + {illegal,0 }, /* f3: 0100 1000 1111 0011 */ + {illegal,0 }, /* f4: 0100 1000 1111 0100 */ + {illegal,0 }, /* f5: 0100 1000 1111 0101 */ + {illegal,0 }, /* f6: 0100 1000 1111 0110 */ + {illegal,0 }, /* f7: 0100 1000 1111 0111 */ + {illegal,0 }, /* f8: 0100 1000 1111 1000 */ + {illegal,0 }, /* f9: 0100 1000 1111 1001 */ + {illegal,0 }, /* fa: 0100 1000 1111 1010 */ + {illegal,0 }, /* fb: 0100 1000 1111 1011 */ + {illegal,0 }, /* fc: 0100 1000 1111 1100 */ + {illegal,0 }, /* fd: 0100 1000 1111 1101 */ + {illegal,0 }, /* fe: 0100 1000 1111 1110 */ + {illegal,0 } /* ff: 0100 1000 1111 1111 */ +}; + +static const struct dasm_s dasm48_7807[256] = +{ + {illegal,0 }, /* 00: 0100 1000 0000 0000 */ + {SLRC,"A" }, /* 01: 0100 1000 0000 0001 */ + {SLRC,"B" }, /* 02: 0100 1000 0000 0010 */ + {SLRC,"C" }, /* 03: 0100 1000 0000 0011 */ + {illegal,0 }, /* 04: 0100 1000 0000 0100 */ + {SLLC,"A" }, /* 05: 0100 1000 0000 0101 */ + {SLLC,"B" }, /* 06: 0100 1000 0000 0110 */ + {SLLC,"C" }, /* 07: 0100 1000 0000 0111 */ + {SK,"NV" }, /* 08: 0100 1000 0000 1000 */ + {illegal,0 }, /* 09: 0100 1000 0000 1001 */ + {SK,"CY" }, /* 0a: 0100 1000 0000 1010 */ + {SK,"HC" }, /* 0b: 0100 1000 0000 1011 */ + {SK,"Z" }, /* 0c: 0100 1000 0000 1100 */ + {illegal,0 }, /* 0d: 0100 1000 0000 1101 */ + {illegal,0 }, /* 0e: 0100 1000 0000 1110 */ + {illegal,0 }, /* 0f: 0100 1000 0000 1111 */ + + {illegal,0 }, /* 10: 0100 1000 0001 0000 */ + {illegal,0 }, /* 11: 0100 1000 0001 0001 */ + {illegal,0 }, /* 12: 0100 1000 0001 0010 */ + {illegal,0 }, /* 13: 0100 1000 0001 0011 */ + {illegal,0 }, /* 14: 0100 1000 0001 0100 */ + {illegal,0 }, /* 15: 0100 1000 0001 0101 */ + {illegal,0 }, /* 16: 0100 1000 0001 0110 */ + {illegal,0 }, /* 17: 0100 1000 0001 0111 */ + {SKN,"NV" }, /* 18: 0100 1000 0001 1000 */ + {illegal,0 }, /* 19: 0100 1000 0001 1001 */ + {SKN,"CY" }, /* 1a: 0100 1000 0001 1010 */ + {SKN,"HC" }, /* 1b: 0100 1000 0001 1011 */ + {SKN,"Z" }, /* 1c: 0100 1000 0001 1100 */ + {illegal,0 }, /* 1d: 0100 1000 0001 1101 */ + {illegal,0 }, /* 1e: 0100 1000 0001 1110 */ + {illegal,0 }, /* 1f: 0100 1000 0001 1111 */ + + {illegal,0 }, /* 20: 0100 1000 0010 0000 */ + {SLR,"A" }, /* 21: 0100 1000 0010 0001 */ + {SLR,"B" }, /* 22: 0100 1000 0010 0010 */ + {SLR,"C" }, /* 23: 0100 1000 0010 0011 */ + {illegal,0 }, /* 24: 0100 1000 0010 0100 */ + {SLL,"A" }, /* 25: 0100 1000 0010 0101 */ + {SLL,"B" }, /* 26: 0100 1000 0010 0110 */ + {SLL,"C" }, /* 27: 0100 1000 0010 0111 */ + {JEA,0 }, /* 28: 0100 1000 0010 1000 */ + {CALB,0 }, /* 29: 0100 1000 0010 1001 */ + {CLC,0 }, /* 2a: 0100 1000 0010 1010 */ + {STC,0 }, /* 2b: 0100 1000 0010 1011 */ + {illegal,0 }, /* 2c: 0100 1000 0010 1100 */ + {MUL,"A" }, /* 2d: 0100 1000 0010 1101 */ + {MUL,"B" }, /* 2e: 0100 1000 0010 1110 */ + {MUL,"C" }, /* 2f: 0100 1000 0010 1111 */ + + {illegal,0 }, /* 30: 0100 1000 0011 0000 */ + {RLR,"A" }, /* 31: 0100 1000 0011 0001 */ + {RLR,"B" }, /* 32: 0100 1000 0011 0010 */ + {RLR,"C" }, /* 33: 0100 1000 0011 0011 */ + {illegal,0 }, /* 34: 0100 1000 0011 0100 */ + {RLL,"A" }, /* 35: 0100 1000 0011 0101 */ + {RLL,"B" }, /* 36: 0100 1000 0011 0110 */ + {RLL,"C" }, /* 37: 0100 1000 0011 0111 */ + {RLD,0 }, /* 38: 0100 1000 0011 1000 */ + {RRD,0 }, /* 39: 0100 1000 0011 1001 */ + {NEGA,0 }, /* 3a: 0100 1000 0011 1010 */ + {HALT,0 }, /* 3b: 0100 1000 0011 1011 */ + {illegal,0 }, /* 3c: 0100 1000 0011 1100 */ + {DIV,"A" }, /* 3d: 0100 1000 0011 1101 */ + {DIV,"B" }, /* 3e: 0100 1000 0011 1110 */ + {DIV,"C" }, /* 3f: 0100 1000 0011 1111 */ + + {SKIT,"NMI" }, /* 40: 0100 1000 0100 0000 */ + {SKIT,"FT0" }, /* 41: 0100 1000 0100 0001 */ + {SKIT,"FT1" }, /* 42: 0100 1000 0100 0010 */ + {SKIT,"F1" }, /* 43: 0100 1000 0100 0011 */ + {SKIT,"F2" }, /* 44: 0100 1000 0100 0100 */ + {SKIT,"FE0" }, /* 45: 0100 1000 0100 0101 */ + {SKIT,"FE1" }, /* 46: 0100 1000 0100 0110 */ + {SKIT,"FEIN" }, /* 47: 0100 1000 0100 0111 */ + {SKIT,"FAD" }, /* 48: 0100 1000 0100 1000 */ + {SKIT,"FSR" }, /* 49: 0100 1000 0100 1001 */ + {SKIT,"FST" }, /* 4a: 0100 1000 0100 1010 */ + {SKIT,"ER" }, /* 4b: 0100 1000 0100 1011 */ + {SKIT,"OV" }, /* 4c: 0100 1000 0100 1100 */ + {illegal,0 }, /* 4d: 0100 1000 0100 1101 */ + {illegal,0 }, /* 4e: 0100 1000 0100 1110 */ + {illegal,0 }, /* 4f: 0100 1000 0100 1111 */ + + {SKIT,"AN4" }, /* 50: 0100 1000 0101 0000 */ + {SKIT,"AN5" }, /* 51: 0100 1000 0101 0001 */ + {SKIT,"AN6" }, /* 52: 0100 1000 0101 0010 */ + {SKIT,"AN7" }, /* 53: 0100 1000 0101 0011 */ + {SKIT,"SB" }, /* 54: 0100 1000 0101 0100 */ + {illegal,0 }, /* 55: 0100 1000 0101 0101 */ + {illegal,0 }, /* 56: 0100 1000 0101 0110 */ + {illegal,0 }, /* 57: 0100 1000 0101 0111 */ + {illegal,0 }, /* 58: 0100 1000 0101 1000 */ + {illegal,0 }, /* 59: 0100 1000 0101 1001 */ + {illegal,0 }, /* 5a: 0100 1000 0101 1010 */ + {illegal,0 }, /* 5b: 0100 1000 0101 1011 */ + {illegal,0 }, /* 5c: 0100 1000 0101 1100 */ + {illegal,0 }, /* 5d: 0100 1000 0101 1101 */ + {illegal,0 }, /* 5e: 0100 1000 0101 1110 */ + {illegal,0 }, /* 5f: 0100 1000 0101 1111 */ + + {SKNIT,"NMI" }, /* 60: 0100 1000 0110 0000 */ + {SKNIT,"FT0" }, /* 61: 0100 1000 0110 0001 */ + {SKNIT,"FT1" }, /* 62: 0100 1000 0110 0010 */ + {SKNIT,"F1" }, /* 63: 0100 1000 0110 0011 */ + {SKNIT,"F2" }, /* 64: 0100 1000 0110 0100 */ + {SKNIT,"FE0" }, /* 65: 0100 1000 0110 0101 */ + {SKNIT,"FE1" }, /* 66: 0100 1000 0110 0110 */ + {SKNIT,"FEIN" }, /* 67: 0100 1000 0110 0111 */ + {SKNIT,"FAD" }, /* 68: 0100 1000 0110 1000 */ + {SKNIT,"FSR" }, /* 69: 0100 1000 0110 1001 */ + {SKNIT,"FST" }, /* 6a: 0100 1000 0110 1010 */ + {SKNIT,"ER" }, /* 6b: 0100 1000 0110 1011 */ + {SKNIT,"OV" }, /* 6c: 0100 1000 0110 1100 */ + {illegal,0 }, /* 6d: 0100 1000 0110 1101 */ + {illegal,0 }, /* 6e: 0100 1000 0110 1110 */ + {illegal,0 }, /* 6f: 0100 1000 0110 1111 */ + + {SKNIT,"AN4" }, /* 70: 0100 1000 0111 0000 */ + {SKNIT,"AN5" }, /* 71: 0100 1000 0111 0001 */ + {SKNIT,"AN6" }, /* 72: 0100 1000 0111 0010 */ + {SKNIT,"AN7" }, /* 73: 0100 1000 0111 0011 */ + {SKNIT,"SB" }, /* 74: 0100 1000 0111 0100 */ + {illegal,0 }, /* 75: 0100 1000 0111 0101 */ + {illegal,0 }, /* 76: 0100 1000 0111 0110 */ + {illegal,0 }, /* 77: 0100 1000 0111 0111 */ + {illegal,0 }, /* 78: 0100 1000 0111 1000 */ + {illegal,0 }, /* 79: 0100 1000 0111 1001 */ + {illegal,0 }, /* 7a: 0100 1000 0111 1010 */ + {illegal,0 }, /* 7b: 0100 1000 0111 1011 */ + {illegal,0 }, /* 7c: 0100 1000 0111 1100 */ + {illegal,0 }, /* 7d: 0100 1000 0111 1101 */ + {illegal,0 }, /* 7e: 0100 1000 0111 1110 */ + {illegal,0 }, /* 7f: 0100 1000 0111 1111 */ + + {illegal,0 }, /* 80: 0100 1000 1000 0000 */ + {illegal,0 }, /* 81: 0100 1000 1000 0001 */ + {LDEAX,"(DE)" }, /* 82: 0100 1000 1000 0010 */ + {LDEAX,"(HL)" }, /* 83: 0100 1000 1000 0011 */ + {LDEAX,"(DE++)" }, /* 84: 0100 1000 1000 0100 */ + {LDEAX,"(HL++)" }, /* 85: 0100 1000 1000 0101 */ + {illegal,0 }, /* 86: 0100 1000 1000 0110 */ + {illegal,0 }, /* 87: 0100 1000 1000 0111 */ + {illegal,0 }, /* 88: 0100 1000 1000 1000 */ + {illegal,0 }, /* 89: 0100 1000 1000 1001 */ + {illegal,0 }, /* 8a: 0100 1000 1000 1010 */ + {LDEAX,"(DE+%b)"}, /* 8b: 0100 1000 1000 1011 xxxx xxxx */ + {LDEAX,"(HL+A)" }, /* 8c: 0100 1000 1000 1100 */ + {LDEAX,"(HL+B)" }, /* 8d: 0100 1000 1000 1101 */ + {LDEAX,"(HL+EA)"}, /* 8e: 0100 1000 1000 1110 */ + {LDEAX,"(HL+%b)"}, /* 8f: 0100 1000 1000 1111 xxxx xxxx */ + + {illegal,0 }, /* 90: 0100 1000 1000 0000 */ + {illegal,0 }, /* 91: 0100 1000 1000 0001 */ + {STEAX,"(DE)" }, /* 92: 0100 1000 1000 0010 */ + {STEAX,"(HL)" }, /* 93: 0100 1000 1000 0011 */ + {STEAX,"(DE++)" }, /* 94: 0100 1000 1000 0100 */ + {STEAX,"(HL++)" }, /* 95: 0100 1000 1000 0101 */ + {illegal,0 }, /* 96: 0100 1000 1000 0110 */ + {illegal,0 }, /* 97: 0100 1000 1000 0111 */ + {illegal,0 }, /* 98: 0100 1000 1000 1000 */ + {illegal,0 }, /* 99: 0100 1000 1000 1001 */ + {illegal,0 }, /* 9a: 0100 1000 1000 1010 */ + {STEAX,"(DE+%b)"}, /* 9b: 0100 1000 1000 1011 xxxx xxxx */ + {STEAX,"(HL+A)" }, /* 9c: 0100 1000 1000 1100 */ + {STEAX,"(HL+B)" }, /* 9d: 0100 1000 1000 1101 */ + {STEAX,"(HL+EA)"}, /* 9e: 0100 1000 1000 1110 */ + {STEAX,"(HL+%b)"}, /* 9f: 0100 1000 1000 1111 xxxx xxxx */ + + {DSLR,"EA" }, /* a0: 0100 1000 1010 0000 */ + {illegal,0 }, /* a1: 0100 1000 1010 0001 */ + {illegal,0 }, /* a2: 0100 1000 1010 0010 */ + {illegal,0 }, /* a3: 0100 1000 1010 0011 */ + {DSLL,"EA" }, /* a4: 0100 1000 1010 0100 */ + {illegal,0 }, /* a5: 0100 1000 1010 0101 */ + {illegal,0 }, /* a6: 0100 1000 1010 0110 */ + {illegal,0 }, /* a7: 0100 1000 1010 0111 */ + {TABLE,0 }, /* a8: 0100 1000 1010 1000 */ + {illegal,0 }, /* a9: 0100 1000 1010 1001 */ + {CMC,0 }, /* aa: 0100 1000 1010 1010 */ /* 7807 */ + {illegal,0 }, /* ab: 0100 1000 1010 1011 */ + {EXA,0 }, /* ac: 0100 1000 1010 1100 */ /* 7807 */ + {EXR,0 }, /* ad: 0100 1000 1010 1101 */ /* 7807 */ + {EXH,0 }, /* ae: 0100 1000 1010 1110 */ /* 7807 */ + {EXX,0 }, /* af: 0100 1000 1010 1111 */ /* 7807 */ + + {DRLR,"EA" }, /* b0: 0100 1000 1011 0000 */ + {illegal,0 }, /* b1: 0100 1000 1011 0001 */ + {illegal,0 }, /* b2: 0100 1000 1011 0010 */ + {illegal,0 }, /* b3: 0100 1000 1011 0011 */ + {DRLL,"EA" }, /* b4: 0100 1000 1011 0100 */ + {illegal,0 }, /* b5: 0100 1000 1011 0101 */ + {illegal,0 }, /* b6: 0100 1000 1011 0110 */ + {illegal,0 }, /* b7: 0100 1000 1011 0111 */ + {illegal,0 }, /* b8: 0100 1000 1011 1000 */ + {illegal,0 }, /* b9: 0100 1000 1011 1001 */ + {illegal,0 }, /* ba: 0100 1000 1011 1010 */ + {illegal,0 }, /* bb: 0100 1000 1011 1011 */ + {illegal,0 }, /* bc: 0100 1000 1011 1100 */ + {illegal,0 }, /* bd: 0100 1000 1011 1101 */ + {illegal,0 }, /* be: 0100 1000 1011 1110 */ + {illegal,0 }, /* bf: 0100 1000 1011 1111 */ + + {DMOV,"EA,ECNT" }, /* c0: 0100 1000 1100 0000 */ + {DMOV,"EA,ECPT0"}, /* c1: 0100 1000 1100 0001 */ /* 7807 */ + {DMOV,"EA,ECPT1"}, /* c2: 0100 1000 1100 0010 */ /* 7807 */ + {illegal,0 }, /* c3: 0100 1000 1100 0011 */ + {illegal,0 }, /* c4: 0100 1000 1100 0100 */ + {illegal,0 }, /* c5: 0100 1000 1100 0101 */ + {illegal,0 }, /* c6: 0100 1000 1100 0110 */ + {illegal,0 }, /* c7: 0100 1000 1100 0111 */ + {illegal,0 }, /* c8: 0100 1000 1100 1000 */ + {illegal,0 }, /* c9: 0100 1000 1100 1001 */ + {illegal,0 }, /* ca: 0100 1000 1100 1010 */ + {illegal,0 }, /* cb: 0100 1000 1100 1011 */ + {illegal,0 }, /* cc: 0100 1000 1100 1100 */ + {illegal,0 }, /* cd: 0100 1000 1100 1101 */ + {illegal,0 }, /* ce: 0100 1000 1100 1110 */ + {illegal,0 }, /* cf: 0100 1000 1100 1111 */ + + {illegal,0 }, /* d0: 0100 1000 1101 0000 */ + {illegal,0 }, /* d1: 0100 1000 1101 0001 */ + {DMOV,"ETM0,EA" }, /* d2: 0100 1000 1101 0010 */ + {DMOV,"ETM1,EA" }, /* d3: 0100 1000 1101 0011 */ + {illegal,0 }, /* d4: 0100 1000 1101 0100 */ + {illegal,0 }, /* d5: 0100 1000 1101 0101 */ + {illegal,0 }, /* d6: 0100 1000 1101 0110 */ + {illegal,0 }, /* d7: 0100 1000 1101 0111 */ + {illegal,0 }, /* d8: 0100 1000 1101 1000 */ + {illegal,0 }, /* d9: 0100 1000 1101 1001 */ + {illegal,0 }, /* da: 0100 1000 1101 1010 */ + {illegal,0 }, /* db: 0100 1000 1101 1011 */ + {illegal,0 }, /* dc: 0100 1000 1101 1100 */ + {illegal,0 }, /* dd: 0100 1000 1101 1101 */ + {illegal,0 }, /* de: 0100 1000 1101 1110 */ + {illegal,0 }, /* df: 0100 1000 1101 1111 */ + + {illegal,0 }, /* e0: 0100 1000 1110 0000 */ + {illegal,0 }, /* e1: 0100 1000 1110 0001 */ + {illegal,0 }, /* e2: 0100 1000 1110 0010 */ + {illegal,0 }, /* e3: 0100 1000 1110 0011 */ + {illegal,0 }, /* e4: 0100 1000 1110 0100 */ + {illegal,0 }, /* e5: 0100 1000 1110 0101 */ + {illegal,0 }, /* e6: 0100 1000 1110 0110 */ + {illegal,0 }, /* e7: 0100 1000 1110 0111 */ + {illegal,0 }, /* e8: 0100 1000 1110 1000 */ + {illegal,0 }, /* e9: 0100 1000 1110 1001 */ + {illegal,0 }, /* ea: 0100 1000 1110 1010 */ + {illegal,0 }, /* eb: 0100 1000 1110 1011 */ + {illegal,0 }, /* ec: 0100 1000 1110 1100 */ + {illegal,0 }, /* ed: 0100 1000 1110 1101 */ + {illegal,0 }, /* ee: 0100 1000 1110 1110 */ + {illegal,0 }, /* ef: 0100 1000 1110 1111 */ + + {illegal,0 }, /* f0: 0100 1000 1111 0000 */ + {illegal,0 }, /* f1: 0100 1000 1111 0001 */ + {illegal,0 }, /* f2: 0100 1000 1111 0010 */ + {illegal,0 }, /* f3: 0100 1000 1111 0011 */ + {illegal,0 }, /* f4: 0100 1000 1111 0100 */ + {illegal,0 }, /* f5: 0100 1000 1111 0101 */ + {illegal,0 }, /* f6: 0100 1000 1111 0110 */ + {illegal,0 }, /* f7: 0100 1000 1111 0111 */ + {illegal,0 }, /* f8: 0100 1000 1111 1000 */ + {illegal,0 }, /* f9: 0100 1000 1111 1001 */ + {illegal,0 }, /* fa: 0100 1000 1111 1010 */ + {illegal,0 }, /* fb: 0100 1000 1111 1011 */ + {illegal,0 }, /* fc: 0100 1000 1111 1100 */ + {illegal,0 }, /* fd: 0100 1000 1111 1101 */ + {illegal,0 }, /* fe: 0100 1000 1111 1110 */ + {illegal,0 } /* ff: 0100 1000 1111 1111 */ +}; + +/* prefix 4C */ +static const struct dasm_s dasm4C_7810[256] = +{ + {illegal,0 }, /* 00: 0100 1100 0000 0000 */ + {illegal,0 }, /* 01: 0100 1100 0000 0001 */ + {illegal,0 }, /* 02: 0100 1100 0000 0010 */ + {illegal,0 }, /* 03: 0100 1100 0000 0011 */ + {illegal,0 }, /* 04: 0100 1100 0000 0100 */ + {illegal,0 }, /* 05: 0100 1100 0000 0101 */ + {illegal,0 }, /* 06: 0100 1100 0000 0110 */ + {illegal,0 }, /* 07: 0100 1100 0000 0111 */ + {illegal,0 }, /* 08: 0100 1100 0000 1000 */ + {illegal,0 }, /* 09: 0100 1100 0000 1001 */ + {illegal,0 }, /* 0a: 0100 1100 0000 1010 */ + {illegal,0 }, /* 0b: 0100 1100 0000 1011 */ + {illegal,0 }, /* 0c: 0100 1100 0000 1100 */ + {illegal,0 }, /* 0d: 0100 1100 0000 1101 */ + {illegal,0 }, /* 0e: 0100 1100 0000 1110 */ + {illegal,0 }, /* 0f: 0100 1100 0000 1111 */ + + {illegal,0 }, /* 10: 0100 1100 0001 0000 */ + {illegal,0 }, /* 11: 0100 1100 0001 0001 */ + {illegal,0 }, /* 12: 0100 1100 0001 0010 */ + {illegal,0 }, /* 13: 0100 1100 0001 0011 */ + {illegal,0 }, /* 14: 0100 1100 0001 0100 */ + {illegal,0 }, /* 15: 0100 1100 0001 0101 */ + {illegal,0 }, /* 16: 0100 1100 0001 0110 */ + {illegal,0 }, /* 17: 0100 1100 0001 0111 */ + {illegal,0 }, /* 18: 0100 1100 0001 1000 */ + {illegal,0 }, /* 19: 0100 1100 0001 1001 */ + {illegal,0 }, /* 1a: 0100 1100 0001 1010 */ + {illegal,0 }, /* 1b: 0100 1100 0001 1011 */ + {illegal,0 }, /* 1c: 0100 1100 0001 1100 */ + {illegal,0 }, /* 1d: 0100 1100 0001 1101 */ + {illegal,0 }, /* 1e: 0100 1100 0001 1110 */ + {illegal,0 }, /* 1f: 0100 1100 0001 1111 */ + + {illegal,0 }, /* 20: 0100 1100 0010 0000 */ + {illegal,0 }, /* 21: 0100 1100 0010 0001 */ + {illegal,0 }, /* 22: 0100 1100 0010 0010 */ + {illegal,0 }, /* 23: 0100 1100 0010 0011 */ + {illegal,0 }, /* 24: 0100 1100 0010 0100 */ + {illegal,0 }, /* 25: 0100 1100 0010 0101 */ + {illegal,0 }, /* 26: 0100 1100 0010 0110 */ + {illegal,0 }, /* 27: 0100 1100 0010 0111 */ + {illegal,0 }, /* 28: 0100 1100 0010 1000 */ + {illegal,0 }, /* 29: 0100 1100 0010 1001 */ + {illegal,0 }, /* 2a: 0100 1100 0010 1010 */ + {illegal,0 }, /* 2b: 0100 1100 0010 1011 */ + {illegal,0 }, /* 2c: 0100 1100 0010 1100 */ + {illegal,0 }, /* 2d: 0100 1100 0010 1101 */ + {illegal,0 }, /* 2e: 0100 1100 0010 1110 */ + {illegal,0 }, /* 2f: 0100 1100 0010 1111 */ + + {illegal,0 }, /* 30: 0100 1100 0011 0000 */ + {illegal,0 }, /* 31: 0100 1100 0011 0001 */ + {illegal,0 }, /* 32: 0100 1100 0011 0010 */ + {illegal,0 }, /* 33: 0100 1100 0011 0011 */ + {illegal,0 }, /* 34: 0100 1100 0011 0100 */ + {illegal,0 }, /* 35: 0100 1100 0011 0101 */ + {illegal,0 }, /* 36: 0100 1100 0011 0110 */ + {illegal,0 }, /* 37: 0100 1100 0011 0111 */ + {illegal,0 }, /* 38: 0100 1100 0011 1000 */ + {illegal,0 }, /* 39: 0100 1100 0011 1001 */ + {illegal,0 }, /* 3a: 0100 1100 0011 1010 */ + {illegal,0 }, /* 3b: 0100 1100 0011 1011 */ + {illegal,0 }, /* 3c: 0100 1100 0011 1100 */ + {illegal,0 }, /* 3d: 0100 1100 0011 1101 */ + {illegal,0 }, /* 3e: 0100 1100 0011 1110 */ + {illegal,0 }, /* 3f: 0100 1100 0011 1111 */ + + {illegal,0 }, /* 40: 0100 1100 0100 0000 */ + {illegal,0 }, /* 41: 0100 1100 0100 0001 */ + {illegal,0 }, /* 42: 0100 1100 0100 0010 */ + {illegal,0 }, /* 43: 0100 1100 0100 0011 */ + {illegal,0 }, /* 44: 0100 1100 0100 0100 */ + {illegal,0 }, /* 45: 0100 1100 0100 0101 */ + {illegal,0 }, /* 46: 0100 1100 0100 0110 */ + {illegal,0 }, /* 47: 0100 1100 0100 0111 */ + {illegal,0 }, /* 48: 0100 1100 0100 1000 */ + {illegal,0 }, /* 49: 0100 1100 0100 1001 */ + {illegal,0 }, /* 4a: 0100 1100 0100 1010 */ + {illegal,0 }, /* 4b: 0100 1100 0100 1011 */ + {illegal,0 }, /* 4c: 0100 1100 0100 1100 */ + {illegal,0 }, /* 4d: 0100 1100 0100 1101 */ + {illegal,0 }, /* 4e: 0100 1100 0100 1110 */ + {illegal,0 }, /* 4f: 0100 1100 0100 1111 */ + + {illegal,0 }, /* 50: 0100 1100 0101 0000 */ + {illegal,0 }, /* 51: 0100 1100 0101 0001 */ + {illegal,0 }, /* 52: 0100 1100 0101 0010 */ + {illegal,0 }, /* 53: 0100 1100 0101 0011 */ + {illegal,0 }, /* 54: 0100 1100 0101 0100 */ + {illegal,0 }, /* 55: 0100 1100 0101 0101 */ + {illegal,0 }, /* 56: 0100 1100 0101 0110 */ + {illegal,0 }, /* 57: 0100 1100 0101 0111 */ + {illegal,0 }, /* 58: 0100 1100 0101 1000 */ + {illegal,0 }, /* 59: 0100 1100 0101 1001 */ + {illegal,0 }, /* 5a: 0100 1100 0101 1010 */ + {illegal,0 }, /* 5b: 0100 1100 0101 1011 */ + {illegal,0 }, /* 5c: 0100 1100 0101 1100 */ + {illegal,0 }, /* 5d: 0100 1100 0101 1101 */ + {illegal,0 }, /* 5e: 0100 1100 0101 1110 */ + {illegal,0 }, /* 5f: 0100 1100 0101 1111 */ + + {illegal,0 }, /* 60: 0100 1100 0110 0000 */ + {illegal,0 }, /* 61: 0100 1100 0110 0001 */ + {illegal,0 }, /* 62: 0100 1100 0110 0010 */ + {illegal,0 }, /* 63: 0100 1100 0110 0011 */ + {illegal,0 }, /* 64: 0100 1100 0110 0100 */ + {illegal,0 }, /* 65: 0100 1100 0110 0101 */ + {illegal,0 }, /* 66: 0100 1100 0110 0110 */ + {illegal,0 }, /* 67: 0100 1100 0110 0111 */ + {illegal,0 }, /* 68: 0100 1100 0110 1000 */ + {illegal,0 }, /* 69: 0100 1100 0110 1001 */ + {illegal,0 }, /* 6a: 0100 1100 0110 1010 */ + {illegal,0 }, /* 6b: 0100 1100 0110 1011 */ + {illegal,0 }, /* 6c: 0100 1100 0110 1100 */ + {illegal,0 }, /* 6d: 0100 1100 0110 1101 */ + {illegal,0 }, /* 6e: 0100 1100 0110 1110 */ + {illegal,0 }, /* 6f: 0100 1100 0110 1111 */ + + {illegal,0 }, /* 70: 0100 1100 0111 0000 */ + {illegal,0 }, /* 71: 0100 1100 0111 0001 */ + {illegal,0 }, /* 72: 0100 1100 0111 0010 */ + {illegal,0 }, /* 73: 0100 1100 0111 0011 */ + {illegal,0 }, /* 74: 0100 1100 0111 0100 */ + {illegal,0 }, /* 75: 0100 1100 0111 0101 */ + {illegal,0 }, /* 76: 0100 1100 0111 0110 */ + {illegal,0 }, /* 77: 0100 1100 0111 0111 */ + {illegal,0 }, /* 78: 0100 1100 0111 1000 */ + {illegal,0 }, /* 79: 0100 1100 0111 1001 */ + {illegal,0 }, /* 7a: 0100 1100 0111 1010 */ + {illegal,0 }, /* 7b: 0100 1100 0111 1011 */ + {illegal,0 }, /* 7c: 0100 1100 0111 1100 */ + {illegal,0 }, /* 7d: 0100 1100 0111 1101 */ + {illegal,0 }, /* 7e: 0100 1100 0111 1110 */ + {illegal,0 }, /* 7f: 0100 1100 0111 1111 */ + + {illegal,0 }, /* 80: 0100 1100 1000 0000 */ + {illegal,0 }, /* 81: 0100 1100 1000 0001 */ + {illegal,0 }, /* 82: 0100 1100 1000 0010 */ + {illegal,0 }, /* 83: 0100 1100 1000 0011 */ + {illegal,0 }, /* 84: 0100 1100 1000 0100 */ + {illegal,0 }, /* 85: 0100 1100 1000 0101 */ + {illegal,0 }, /* 86: 0100 1100 1000 0110 */ + {illegal,0 }, /* 87: 0100 1100 1000 0111 */ + {illegal,0 }, /* 88: 0100 1100 1000 1000 */ + {illegal,0 }, /* 89: 0100 1100 1000 1001 */ + {illegal,0 }, /* 8a: 0100 1100 1000 1010 */ + {illegal,0 }, /* 8b: 0100 1100 1000 1011 */ + {illegal,0 }, /* 8c: 0100 1100 1000 1100 */ + {illegal,0 }, /* 8d: 0100 1100 1000 1101 */ + {illegal,0 }, /* 8e: 0100 1100 1000 1110 */ + {illegal,0 }, /* 8f: 0100 1100 1000 1111 */ + + {illegal,0 }, /* 90: 0100 1100 1001 0000 */ + {illegal,0 }, /* 91: 0100 1100 1001 0001 */ + {illegal,0 }, /* 92: 0100 1100 1001 0010 */ + {illegal,0 }, /* 93: 0100 1100 1001 0011 */ + {illegal,0 }, /* 94: 0100 1100 1001 0100 */ + {illegal,0 }, /* 95: 0100 1100 1001 0101 */ + {illegal,0 }, /* 96: 0100 1100 1001 0110 */ + {illegal,0 }, /* 97: 0100 1100 1001 0111 */ + {illegal,0 }, /* 98: 0100 1100 1001 1000 */ + {illegal,0 }, /* 99: 0100 1100 1001 1001 */ + {illegal,0 }, /* 9a: 0100 1100 1001 1010 */ + {illegal,0 }, /* 9b: 0100 1100 1001 1011 */ + {illegal,0 }, /* 9c: 0100 1100 1001 1100 */ + {illegal,0 }, /* 9d: 0100 1100 1001 1101 */ + {illegal,0 }, /* 9e: 0100 1100 1001 1110 */ + {illegal,0 }, /* 9f: 0100 1100 1001 1111 */ + + {illegal,0 }, /* a0: 0100 1100 1010 0000 */ + {illegal,0 }, /* a1: 0100 1100 1010 0001 */ + {illegal,0 }, /* a2: 0100 1100 1010 0010 */ + {illegal,0 }, /* a3: 0100 1100 1010 0011 */ + {illegal,0 }, /* a4: 0100 1100 1010 0100 */ + {illegal,0 }, /* a5: 0100 1100 1010 0101 */ + {illegal,0 }, /* a6: 0100 1100 1010 0110 */ + {illegal,0 }, /* a7: 0100 1100 1010 0111 */ + {illegal,0 }, /* a8: 0100 1100 1010 1000 */ + {illegal,0 }, /* a9: 0100 1100 1010 1001 */ + {illegal,0 }, /* aa: 0100 1100 1010 1010 */ + {illegal,0 }, /* ab: 0100 1100 1010 1011 */ + {illegal,0 }, /* ac: 0100 1100 1010 1100 */ + {illegal,0 }, /* ad: 0100 1100 1010 1101 */ + {illegal,0 }, /* ae: 0100 1100 1010 1110 */ + {illegal,0 }, /* af: 0100 1100 1010 1111 */ + + {illegal,0 }, /* b0: 0100 1100 1011 0000 */ + {illegal,0 }, /* b1: 0100 1100 1011 0001 */ + {illegal,0 }, /* b2: 0100 1100 1011 0010 */ + {illegal,0 }, /* b3: 0100 1100 1011 0011 */ + {illegal,0 }, /* b4: 0100 1100 1011 0100 */ + {illegal,0 }, /* b5: 0100 1100 1011 0101 */ + {illegal,0 }, /* b6: 0100 1100 1011 0110 */ + {illegal,0 }, /* b7: 0100 1100 1011 0111 */ + {illegal,0 }, /* b8: 0100 1100 1011 1000 */ + {illegal,0 }, /* b9: 0100 1100 1011 1001 */ + {illegal,0 }, /* ba: 0100 1100 1011 1010 */ + {illegal,0 }, /* bb: 0100 1100 1011 1011 */ + {illegal,0 }, /* bc: 0100 1100 1011 1100 */ + {illegal,0 }, /* bd: 0100 1100 1011 1101 */ + {illegal,0 }, /* be: 0100 1100 1011 1110 */ + {illegal,0 }, /* bf: 0100 1100 1011 1111 */ + + {MOV,"A,PA" }, /* c0: 0100 1100 1100 0000 */ + {MOV,"A,PB" }, /* c1: 0100 1100 1100 0001 */ + {MOV,"A,PC" }, /* c2: 0100 1100 1100 0010 */ + {MOV,"A,PD" }, /* c3: 0100 1100 1100 0011 */ + {illegal,0 }, /* c4: 0100 1100 1100 0100 */ + {MOV,"A,PF" }, /* c5: 0100 1100 1100 0101 */ + {MOV,"A,MKH" }, /* c6: 0100 1100 1100 0110 */ + {MOV,"A,MKL" }, /* c7: 0100 1100 1100 0111 */ + {MOV,"A,ANM" }, /* c8: 0100 1100 1100 1000 */ /* 7810 */ + {MOV,"A,SMH" }, /* c9: 0100 1100 1100 1001 */ + {illegal,0 }, /* ca: 0100 1100 1100 1010 */ + {MOV,"A,EOM" }, /* cb: 0100 1100 1100 1011 */ + {illegal,0 }, /* cc: 0100 1100 1100 1100 */ + {MOV,"A,TMM" }, /* cd: 0100 1100 1100 1101 */ + {illegal,0 }, /* ce: 0100 1100 1100 1110 */ + {illegal,0 }, /* cf: 0100 1100 1100 1111 */ + + {illegal,0 }, /* d0: 0100 1100 1101 0000 */ + {illegal,0 }, /* d1: 0100 1100 1101 0001 */ + {illegal,0 }, /* d2: 0100 1100 1101 0010 */ + {illegal,0 }, /* d3: 0100 1100 1101 0011 */ + {illegal,0 }, /* d4: 0100 1100 1101 0100 */ + {illegal,0 }, /* d5: 0100 1100 1101 0101 */ + {illegal,0 }, /* d6: 0100 1100 1101 0110 */ + {illegal,0 }, /* d7: 0100 1100 1101 0111 */ + {illegal,0 }, /* d8: 0100 1100 1101 1000 */ + {MOV,"A,RXB" }, /* d9: 0100 1100 1101 1001 */ + {illegal,0 }, /* da: 0100 1100 1101 1010 */ + {illegal,0 }, /* db: 0100 1100 1101 1011 */ + {illegal,0 }, /* dc: 0100 1100 1101 1100 */ + {illegal,0 }, /* dd: 0100 1100 1101 1101 */ + {illegal,0 }, /* de: 0100 1100 1101 1110 */ + {illegal,0 }, /* df: 0100 1100 1101 1111 */ + + {MOV,"A,CR0" }, /* e0: 0100 1100 1110 0000 */ /* 7810 */ + {MOV,"A,CR1" }, /* e1: 0100 1100 1110 0001 */ /* 7810 */ + {MOV,"A,CR2" }, /* e2: 0100 1100 1110 0010 */ /* 7810 */ + {MOV,"A,CR3" }, /* e3: 0100 1100 1110 0011 */ /* 7810 */ + {illegal,0 }, /* e4: 0100 1100 1110 0100 */ + {illegal,0 }, /* e5: 0100 1100 1110 0101 */ + {illegal,0 }, /* e6: 0100 1100 1110 0110 */ + {illegal,0 }, /* e7: 0100 1100 1110 0111 */ + {illegal,0 }, /* e8: 0100 1100 1110 1000 */ + {illegal,0 }, /* e9: 0100 1100 1110 1001 */ + {illegal,0 }, /* ea: 0100 1100 1110 1010 */ + {illegal,0 }, /* eb: 0100 1100 1110 1011 */ + {illegal,0 }, /* ec: 0100 1100 1110 1100 */ + {illegal,0 }, /* ed: 0100 1100 1110 1101 */ + {illegal,0 }, /* ee: 0100 1100 1110 1110 */ + {illegal,0 }, /* ef: 0100 1100 1110 1111 */ + + {illegal,0 }, /* f0: 0100 1100 1111 0000 */ + {illegal,0 }, /* f1: 0100 1100 1111 0001 */ + {illegal,0 }, /* f2: 0100 1100 1111 0010 */ + {illegal,0 }, /* f3: 0100 1100 1111 0011 */ + {illegal,0 }, /* f4: 0100 1100 1111 0100 */ + {illegal,0 }, /* f5: 0100 1100 1111 0101 */ + {illegal,0 }, /* f6: 0100 1100 1111 0110 */ + {illegal,0 }, /* f7: 0100 1100 1111 0111 */ + {illegal,0 }, /* f8: 0100 1100 1111 1000 */ + {illegal,0 }, /* f9: 0100 1100 1111 1001 */ + {illegal,0 }, /* fa: 0100 1100 1111 1010 */ + {illegal,0 }, /* fb: 0100 1100 1111 1011 */ + {illegal,0 }, /* fc: 0100 1100 1111 1100 */ + {illegal,0 }, /* fd: 0100 1100 1111 1101 */ + {illegal,0 }, /* fe: 0100 1100 1111 1110 */ + {illegal,0 } /* ff: 0100 1100 1111 1111 */ +}; + +static const struct dasm_s dasm4C_7807[256] = +{ + {illegal,0 }, /* 00: 0100 1100 0000 0000 */ + {illegal,0 }, /* 01: 0100 1100 0000 0001 */ + {illegal,0 }, /* 02: 0100 1100 0000 0010 */ + {illegal,0 }, /* 03: 0100 1100 0000 0011 */ + {illegal,0 }, /* 04: 0100 1100 0000 0100 */ + {illegal,0 }, /* 05: 0100 1100 0000 0101 */ + {illegal,0 }, /* 06: 0100 1100 0000 0110 */ + {illegal,0 }, /* 07: 0100 1100 0000 0111 */ + {illegal,0 }, /* 08: 0100 1100 0000 1000 */ + {illegal,0 }, /* 09: 0100 1100 0000 1001 */ + {illegal,0 }, /* 0a: 0100 1100 0000 1010 */ + {illegal,0 }, /* 0b: 0100 1100 0000 1011 */ + {illegal,0 }, /* 0c: 0100 1100 0000 1100 */ + {illegal,0 }, /* 0d: 0100 1100 0000 1101 */ + {illegal,0 }, /* 0e: 0100 1100 0000 1110 */ + {illegal,0 }, /* 0f: 0100 1100 0000 1111 */ + + {illegal,0 }, /* 10: 0100 1100 0001 0000 */ + {illegal,0 }, /* 11: 0100 1100 0001 0001 */ + {illegal,0 }, /* 12: 0100 1100 0001 0010 */ + {illegal,0 }, /* 13: 0100 1100 0001 0011 */ + {illegal,0 }, /* 14: 0100 1100 0001 0100 */ + {illegal,0 }, /* 15: 0100 1100 0001 0101 */ + {illegal,0 }, /* 16: 0100 1100 0001 0110 */ + {illegal,0 }, /* 17: 0100 1100 0001 0111 */ + {illegal,0 }, /* 18: 0100 1100 0001 1000 */ + {illegal,0 }, /* 19: 0100 1100 0001 1001 */ + {illegal,0 }, /* 1a: 0100 1100 0001 1010 */ + {illegal,0 }, /* 1b: 0100 1100 0001 1011 */ + {illegal,0 }, /* 1c: 0100 1100 0001 1100 */ + {illegal,0 }, /* 1d: 0100 1100 0001 1101 */ + {illegal,0 }, /* 1e: 0100 1100 0001 1110 */ + {illegal,0 }, /* 1f: 0100 1100 0001 1111 */ + + {illegal,0 }, /* 20: 0100 1100 0010 0000 */ + {illegal,0 }, /* 21: 0100 1100 0010 0001 */ + {illegal,0 }, /* 22: 0100 1100 0010 0010 */ + {illegal,0 }, /* 23: 0100 1100 0010 0011 */ + {illegal,0 }, /* 24: 0100 1100 0010 0100 */ + {illegal,0 }, /* 25: 0100 1100 0010 0101 */ + {illegal,0 }, /* 26: 0100 1100 0010 0110 */ + {illegal,0 }, /* 27: 0100 1100 0010 0111 */ + {illegal,0 }, /* 28: 0100 1100 0010 1000 */ + {illegal,0 }, /* 29: 0100 1100 0010 1001 */ + {illegal,0 }, /* 2a: 0100 1100 0010 1010 */ + {illegal,0 }, /* 2b: 0100 1100 0010 1011 */ + {illegal,0 }, /* 2c: 0100 1100 0010 1100 */ + {illegal,0 }, /* 2d: 0100 1100 0010 1101 */ + {illegal,0 }, /* 2e: 0100 1100 0010 1110 */ + {illegal,0 }, /* 2f: 0100 1100 0010 1111 */ + + {illegal,0 }, /* 30: 0100 1100 0011 0000 */ + {illegal,0 }, /* 31: 0100 1100 0011 0001 */ + {illegal,0 }, /* 32: 0100 1100 0011 0010 */ + {illegal,0 }, /* 33: 0100 1100 0011 0011 */ + {illegal,0 }, /* 34: 0100 1100 0011 0100 */ + {illegal,0 }, /* 35: 0100 1100 0011 0101 */ + {illegal,0 }, /* 36: 0100 1100 0011 0110 */ + {illegal,0 }, /* 37: 0100 1100 0011 0111 */ + {illegal,0 }, /* 38: 0100 1100 0011 1000 */ + {illegal,0 }, /* 39: 0100 1100 0011 1001 */ + {illegal,0 }, /* 3a: 0100 1100 0011 1010 */ + {illegal,0 }, /* 3b: 0100 1100 0011 1011 */ + {illegal,0 }, /* 3c: 0100 1100 0011 1100 */ + {illegal,0 }, /* 3d: 0100 1100 0011 1101 */ + {illegal,0 }, /* 3e: 0100 1100 0011 1110 */ + {illegal,0 }, /* 3f: 0100 1100 0011 1111 */ + + {illegal,0 }, /* 40: 0100 1100 0100 0000 */ + {illegal,0 }, /* 41: 0100 1100 0100 0001 */ + {illegal,0 }, /* 42: 0100 1100 0100 0010 */ + {illegal,0 }, /* 43: 0100 1100 0100 0011 */ + {illegal,0 }, /* 44: 0100 1100 0100 0100 */ + {illegal,0 }, /* 45: 0100 1100 0100 0101 */ + {illegal,0 }, /* 46: 0100 1100 0100 0110 */ + {illegal,0 }, /* 47: 0100 1100 0100 0111 */ + {illegal,0 }, /* 48: 0100 1100 0100 1000 */ + {illegal,0 }, /* 49: 0100 1100 0100 1001 */ + {illegal,0 }, /* 4a: 0100 1100 0100 1010 */ + {illegal,0 }, /* 4b: 0100 1100 0100 1011 */ + {illegal,0 }, /* 4c: 0100 1100 0100 1100 */ + {illegal,0 }, /* 4d: 0100 1100 0100 1101 */ + {illegal,0 }, /* 4e: 0100 1100 0100 1110 */ + {illegal,0 }, /* 4f: 0100 1100 0100 1111 */ + + {illegal,0 }, /* 50: 0100 1100 0101 0000 */ + {illegal,0 }, /* 51: 0100 1100 0101 0001 */ + {illegal,0 }, /* 52: 0100 1100 0101 0010 */ + {illegal,0 }, /* 53: 0100 1100 0101 0011 */ + {illegal,0 }, /* 54: 0100 1100 0101 0100 */ + {illegal,0 }, /* 55: 0100 1100 0101 0101 */ + {illegal,0 }, /* 56: 0100 1100 0101 0110 */ + {illegal,0 }, /* 57: 0100 1100 0101 0111 */ + {illegal,0 }, /* 58: 0100 1100 0101 1000 */ + {illegal,0 }, /* 59: 0100 1100 0101 1001 */ + {illegal,0 }, /* 5a: 0100 1100 0101 1010 */ + {illegal,0 }, /* 5b: 0100 1100 0101 1011 */ + {illegal,0 }, /* 5c: 0100 1100 0101 1100 */ + {illegal,0 }, /* 5d: 0100 1100 0101 1101 */ + {illegal,0 }, /* 5e: 0100 1100 0101 1110 */ + {illegal,0 }, /* 5f: 0100 1100 0101 1111 */ + + {illegal,0 }, /* 60: 0100 1100 0110 0000 */ + {illegal,0 }, /* 61: 0100 1100 0110 0001 */ + {illegal,0 }, /* 62: 0100 1100 0110 0010 */ + {illegal,0 }, /* 63: 0100 1100 0110 0011 */ + {illegal,0 }, /* 64: 0100 1100 0110 0100 */ + {illegal,0 }, /* 65: 0100 1100 0110 0101 */ + {illegal,0 }, /* 66: 0100 1100 0110 0110 */ + {illegal,0 }, /* 67: 0100 1100 0110 0111 */ + {illegal,0 }, /* 68: 0100 1100 0110 1000 */ + {illegal,0 }, /* 69: 0100 1100 0110 1001 */ + {illegal,0 }, /* 6a: 0100 1100 0110 1010 */ + {illegal,0 }, /* 6b: 0100 1100 0110 1011 */ + {illegal,0 }, /* 6c: 0100 1100 0110 1100 */ + {illegal,0 }, /* 6d: 0100 1100 0110 1101 */ + {illegal,0 }, /* 6e: 0100 1100 0110 1110 */ + {illegal,0 }, /* 6f: 0100 1100 0110 1111 */ + + {illegal,0 }, /* 70: 0100 1100 0111 0000 */ + {illegal,0 }, /* 71: 0100 1100 0111 0001 */ + {illegal,0 }, /* 72: 0100 1100 0111 0010 */ + {illegal,0 }, /* 73: 0100 1100 0111 0011 */ + {illegal,0 }, /* 74: 0100 1100 0111 0100 */ + {illegal,0 }, /* 75: 0100 1100 0111 0101 */ + {illegal,0 }, /* 76: 0100 1100 0111 0110 */ + {illegal,0 }, /* 77: 0100 1100 0111 0111 */ + {illegal,0 }, /* 78: 0100 1100 0111 1000 */ + {illegal,0 }, /* 79: 0100 1100 0111 1001 */ + {illegal,0 }, /* 7a: 0100 1100 0111 1010 */ + {illegal,0 }, /* 7b: 0100 1100 0111 1011 */ + {illegal,0 }, /* 7c: 0100 1100 0111 1100 */ + {illegal,0 }, /* 7d: 0100 1100 0111 1101 */ + {illegal,0 }, /* 7e: 0100 1100 0111 1110 */ + {illegal,0 }, /* 7f: 0100 1100 0111 1111 */ + + {illegal,0 }, /* 80: 0100 1100 1000 0000 */ + {illegal,0 }, /* 81: 0100 1100 1000 0001 */ + {illegal,0 }, /* 82: 0100 1100 1000 0010 */ + {illegal,0 }, /* 83: 0100 1100 1000 0011 */ + {illegal,0 }, /* 84: 0100 1100 1000 0100 */ + {illegal,0 }, /* 85: 0100 1100 1000 0101 */ + {illegal,0 }, /* 86: 0100 1100 1000 0110 */ + {illegal,0 }, /* 87: 0100 1100 1000 0111 */ + {illegal,0 }, /* 88: 0100 1100 1000 1000 */ + {illegal,0 }, /* 89: 0100 1100 1000 1001 */ + {illegal,0 }, /* 8a: 0100 1100 1000 1010 */ + {illegal,0 }, /* 8b: 0100 1100 1000 1011 */ + {illegal,0 }, /* 8c: 0100 1100 1000 1100 */ + {illegal,0 }, /* 8d: 0100 1100 1000 1101 */ + {illegal,0 }, /* 8e: 0100 1100 1000 1110 */ + {illegal,0 }, /* 8f: 0100 1100 1000 1111 */ + + {illegal,0 }, /* 90: 0100 1100 1001 0000 */ + {illegal,0 }, /* 91: 0100 1100 1001 0001 */ + {illegal,0 }, /* 92: 0100 1100 1001 0010 */ + {illegal,0 }, /* 93: 0100 1100 1001 0011 */ + {illegal,0 }, /* 94: 0100 1100 1001 0100 */ + {illegal,0 }, /* 95: 0100 1100 1001 0101 */ + {illegal,0 }, /* 96: 0100 1100 1001 0110 */ + {illegal,0 }, /* 97: 0100 1100 1001 0111 */ + {illegal,0 }, /* 98: 0100 1100 1001 1000 */ + {illegal,0 }, /* 99: 0100 1100 1001 1001 */ + {illegal,0 }, /* 9a: 0100 1100 1001 1010 */ + {illegal,0 }, /* 9b: 0100 1100 1001 1011 */ + {illegal,0 }, /* 9c: 0100 1100 1001 1100 */ + {illegal,0 }, /* 9d: 0100 1100 1001 1101 */ + {illegal,0 }, /* 9e: 0100 1100 1001 1110 */ + {illegal,0 }, /* 9f: 0100 1100 1001 1111 */ + + {illegal,0 }, /* a0: 0100 1100 1010 0000 */ + {illegal,0 }, /* a1: 0100 1100 1010 0001 */ + {illegal,0 }, /* a2: 0100 1100 1010 0010 */ + {illegal,0 }, /* a3: 0100 1100 1010 0011 */ + {illegal,0 }, /* a4: 0100 1100 1010 0100 */ + {illegal,0 }, /* a5: 0100 1100 1010 0101 */ + {illegal,0 }, /* a6: 0100 1100 1010 0110 */ + {illegal,0 }, /* a7: 0100 1100 1010 0111 */ + {illegal,0 }, /* a8: 0100 1100 1010 1000 */ + {illegal,0 }, /* a9: 0100 1100 1010 1001 */ + {illegal,0 }, /* aa: 0100 1100 1010 1010 */ + {illegal,0 }, /* ab: 0100 1100 1010 1011 */ + {illegal,0 }, /* ac: 0100 1100 1010 1100 */ + {illegal,0 }, /* ad: 0100 1100 1010 1101 */ + {illegal,0 }, /* ae: 0100 1100 1010 1110 */ + {illegal,0 }, /* af: 0100 1100 1010 1111 */ + + {illegal,0 }, /* b0: 0100 1100 1011 0000 */ + {illegal,0 }, /* b1: 0100 1100 1011 0001 */ + {illegal,0 }, /* b2: 0100 1100 1011 0010 */ + {illegal,0 }, /* b3: 0100 1100 1011 0011 */ + {illegal,0 }, /* b4: 0100 1100 1011 0100 */ + {illegal,0 }, /* b5: 0100 1100 1011 0101 */ + {illegal,0 }, /* b6: 0100 1100 1011 0110 */ + {illegal,0 }, /* b7: 0100 1100 1011 0111 */ + {illegal,0 }, /* b8: 0100 1100 1011 1000 */ + {illegal,0 }, /* b9: 0100 1100 1011 1001 */ + {illegal,0 }, /* ba: 0100 1100 1011 1010 */ + {illegal,0 }, /* bb: 0100 1100 1011 1011 */ + {illegal,0 }, /* bc: 0100 1100 1011 1100 */ + {illegal,0 }, /* bd: 0100 1100 1011 1101 */ + {illegal,0 }, /* be: 0100 1100 1011 1110 */ + {illegal,0 }, /* bf: 0100 1100 1011 1111 */ + + {MOV,"A,PA" }, /* c0: 0100 1100 1100 0000 */ + {MOV,"A,PB" }, /* c1: 0100 1100 1100 0001 */ + {MOV,"A,PC" }, /* c2: 0100 1100 1100 0010 */ + {MOV,"A,PD" }, /* c3: 0100 1100 1100 0011 */ + {illegal,0 }, /* c4: 0100 1100 1100 0100 */ + {MOV,"A,PF" }, /* c5: 0100 1100 1100 0101 */ + {MOV,"A,MKH" }, /* c6: 0100 1100 1100 0110 */ + {MOV,"A,MKL" }, /* c7: 0100 1100 1100 0111 */ + {illegal,0 }, /* c8: 0100 1100 1100 1000 */ + {MOV,"A,SMH" }, /* c9: 0100 1100 1100 1001 */ + {illegal,0 }, /* ca: 0100 1100 1100 1010 */ + {MOV,"A,EOM" }, /* cb: 0100 1100 1100 1011 */ + {illegal,0 }, /* cc: 0100 1100 1100 1100 */ + {MOV,"A,TMM" }, /* cd: 0100 1100 1100 1101 */ + {MOV,"A,PT" }, /* ce: 0100 1100 1100 1110 */ /* 7807 */ + {illegal,0 }, /* cf: 0100 1100 1100 1111 */ + + {illegal,0 }, /* d0: 0100 1100 1101 0000 */ + {illegal,0 }, /* d1: 0100 1100 1101 0001 */ + {illegal,0 }, /* d2: 0100 1100 1101 0010 */ + {illegal,0 }, /* d3: 0100 1100 1101 0011 */ + {illegal,0 }, /* d4: 0100 1100 1101 0100 */ + {illegal,0 }, /* d5: 0100 1100 1101 0101 */ + {illegal,0 }, /* d6: 0100 1100 1101 0110 */ + {illegal,0 }, /* d7: 0100 1100 1101 0111 */ + {illegal,0 }, /* d8: 0100 1100 1101 1000 */ + {MOV,"A,RXB" }, /* d9: 0100 1100 1101 1001 */ + {illegal,0 }, /* da: 0100 1100 1101 1010 */ + {illegal,0 }, /* db: 0100 1100 1101 1011 */ + {illegal,0 }, /* dc: 0100 1100 1101 1100 */ + {illegal,0 }, /* dd: 0100 1100 1101 1101 */ + {illegal,0 }, /* de: 0100 1100 1101 1110 */ + {illegal,0 }, /* df: 0100 1100 1101 1111 */ + + {illegal,0 }, /* e0: 0100 1100 1110 0000 */ + {illegal,0 }, /* e1: 0100 1100 1110 0001 */ + {illegal,0 }, /* e2: 0100 1100 1110 0010 */ + {illegal,0 }, /* e3: 0100 1100 1110 0011 */ + {illegal,0 }, /* e4: 0100 1100 1110 0100 */ + {illegal,0 }, /* e5: 0100 1100 1110 0101 */ + {illegal,0 }, /* e6: 0100 1100 1110 0110 */ + {illegal,0 }, /* e7: 0100 1100 1110 0111 */ + {illegal,0 }, /* e8: 0100 1100 1110 1000 */ + {illegal,0 }, /* e9: 0100 1100 1110 1001 */ + {illegal,0 }, /* ea: 0100 1100 1110 1010 */ + {illegal,0 }, /* eb: 0100 1100 1110 1011 */ + {illegal,0 }, /* ec: 0100 1100 1110 1100 */ + {illegal,0 }, /* ed: 0100 1100 1110 1101 */ + {illegal,0 }, /* ee: 0100 1100 1110 1110 */ + {illegal,0 }, /* ef: 0100 1100 1110 1111 */ + + {illegal,0 }, /* f0: 0100 1100 1111 0000 */ + {illegal,0 }, /* f1: 0100 1100 1111 0001 */ + {illegal,0 }, /* f2: 0100 1100 1111 0010 */ + {illegal,0 }, /* f3: 0100 1100 1111 0011 */ + {illegal,0 }, /* f4: 0100 1100 1111 0100 */ + {illegal,0 }, /* f5: 0100 1100 1111 0101 */ + {illegal,0 }, /* f6: 0100 1100 1111 0110 */ + {illegal,0 }, /* f7: 0100 1100 1111 0111 */ + {illegal,0 }, /* f8: 0100 1100 1111 1000 */ + {illegal,0 }, /* f9: 0100 1100 1111 1001 */ + {illegal,0 }, /* fa: 0100 1100 1111 1010 */ + {illegal,0 }, /* fb: 0100 1100 1111 1011 */ + {illegal,0 }, /* fc: 0100 1100 1111 1100 */ + {illegal,0 }, /* fd: 0100 1100 1111 1101 */ + {illegal,0 }, /* fe: 0100 1100 1111 1110 */ + {illegal,0 } /* ff: 0100 1100 1111 1111 */ +}; + +/* prefix 4D */ +static const struct dasm_s dasm4D_7810[256] = +{ + {illegal,0 }, /* 00: 0100 1101 0000 0000 */ + {illegal,0 }, /* 01: 0100 1101 0000 0001 */ + {illegal,0 }, /* 02: 0100 1101 0000 0010 */ + {illegal,0 }, /* 03: 0100 1101 0000 0011 */ + {illegal,0 }, /* 04: 0100 1101 0000 0100 */ + {illegal,0 }, /* 05: 0100 1101 0000 0101 */ + {illegal,0 }, /* 06: 0100 1101 0000 0110 */ + {illegal,0 }, /* 07: 0100 1101 0000 0111 */ + {illegal,0 }, /* 08: 0100 1101 0000 1000 */ + {illegal,0 }, /* 09: 0100 1101 0000 1001 */ + {illegal,0 }, /* 0a: 0100 1101 0000 1010 */ + {illegal,0 }, /* 0b: 0100 1101 0000 1011 */ + {illegal,0 }, /* 0c: 0100 1101 0000 1100 */ + {illegal,0 }, /* 0d: 0100 1101 0000 1101 */ + {illegal,0 }, /* 0e: 0100 1101 0000 1110 */ + {illegal,0 }, /* 0f: 0100 1101 0000 1111 */ + + {illegal,0 }, /* 10: 0100 1101 0001 0000 */ + {illegal,0 }, /* 11: 0100 1101 0001 0001 */ + {illegal,0 }, /* 12: 0100 1101 0001 0010 */ + {illegal,0 }, /* 13: 0100 1101 0001 0011 */ + {illegal,0 }, /* 14: 0100 1101 0001 0100 */ + {illegal,0 }, /* 15: 0100 1101 0001 0101 */ + {illegal,0 }, /* 16: 0100 1101 0001 0110 */ + {illegal,0 }, /* 17: 0100 1101 0001 0111 */ + {illegal,0 }, /* 18: 0100 1101 0001 1000 */ + {illegal,0 }, /* 19: 0100 1101 0001 1001 */ + {illegal,0 }, /* 1a: 0100 1101 0001 1010 */ + {illegal,0 }, /* 1b: 0100 1101 0001 1011 */ + {illegal,0 }, /* 1c: 0100 1101 0001 1100 */ + {illegal,0 }, /* 1d: 0100 1101 0001 1101 */ + {illegal,0 }, /* 1e: 0100 1101 0001 1110 */ + {illegal,0 }, /* 1f: 0100 1101 0001 1111 */ + + {illegal,0 }, /* 20: 0100 1101 0010 0000 */ + {illegal,0 }, /* 21: 0100 1101 0010 0001 */ + {illegal,0 }, /* 22: 0100 1101 0010 0010 */ + {illegal,0 }, /* 23: 0100 1101 0010 0011 */ + {illegal,0 }, /* 24: 0100 1101 0010 0100 */ + {illegal,0 }, /* 25: 0100 1101 0010 0101 */ + {illegal,0 }, /* 26: 0100 1101 0010 0110 */ + {illegal,0 }, /* 27: 0100 1101 0010 0111 */ + {illegal,0 }, /* 28: 0100 1101 0010 1000 */ + {illegal,0 }, /* 29: 0100 1101 0010 1001 */ + {illegal,0 }, /* 2a: 0100 1101 0010 1010 */ + {illegal,0 }, /* 2b: 0100 1101 0010 1011 */ + {illegal,0 }, /* 2c: 0100 1101 0010 1100 */ + {illegal,0 }, /* 2d: 0100 1101 0010 1101 */ + {illegal,0 }, /* 2e: 0100 1101 0010 1110 */ + {illegal,0 }, /* 2f: 0100 1101 0010 1111 */ + + {illegal,0 }, /* 30: 0100 1101 0011 0000 */ + {illegal,0 }, /* 31: 0100 1101 0011 0001 */ + {illegal,0 }, /* 32: 0100 1101 0011 0010 */ + {illegal,0 }, /* 33: 0100 1101 0011 0011 */ + {illegal,0 }, /* 34: 0100 1101 0011 0100 */ + {illegal,0 }, /* 35: 0100 1101 0011 0101 */ + {illegal,0 }, /* 36: 0100 1101 0011 0110 */ + {illegal,0 }, /* 37: 0100 1101 0011 0111 */ + {illegal,0 }, /* 38: 0100 1101 0011 1000 */ + {illegal,0 }, /* 39: 0100 1101 0011 1001 */ + {illegal,0 }, /* 3a: 0100 1101 0011 1010 */ + {illegal,0 }, /* 3b: 0100 1101 0011 1011 */ + {illegal,0 }, /* 3c: 0100 1101 0011 1100 */ + {illegal,0 }, /* 3d: 0100 1101 0011 1101 */ + {illegal,0 }, /* 3e: 0100 1101 0011 1110 */ + {illegal,0 }, /* 3f: 0100 1101 0011 1111 */ + + {illegal,0 }, /* 40: 0100 1101 0100 0000 */ + {illegal,0 }, /* 41: 0100 1101 0100 0001 */ + {illegal,0 }, /* 42: 0100 1101 0100 0010 */ + {illegal,0 }, /* 43: 0100 1101 0100 0011 */ + {illegal,0 }, /* 44: 0100 1101 0100 0100 */ + {illegal,0 }, /* 45: 0100 1101 0100 0101 */ + {illegal,0 }, /* 46: 0100 1101 0100 0110 */ + {illegal,0 }, /* 47: 0100 1101 0100 0111 */ + {illegal,0 }, /* 48: 0100 1101 0100 1000 */ + {illegal,0 }, /* 49: 0100 1101 0100 1001 */ + {illegal,0 }, /* 4a: 0100 1101 0100 1010 */ + {illegal,0 }, /* 4b: 0100 1101 0100 1011 */ + {illegal,0 }, /* 4c: 0100 1101 0100 1100 */ + {illegal,0 }, /* 4d: 0100 1101 0100 1101 */ + {illegal,0 }, /* 4e: 0100 1101 0100 1110 */ + {illegal,0 }, /* 4f: 0100 1101 0100 1111 */ + + {illegal,0 }, /* 50: 0100 1101 0101 0000 */ + {illegal,0 }, /* 51: 0100 1101 0101 0001 */ + {illegal,0 }, /* 52: 0100 1101 0101 0010 */ + {illegal,0 }, /* 53: 0100 1101 0101 0011 */ + {illegal,0 }, /* 54: 0100 1101 0101 0100 */ + {illegal,0 }, /* 55: 0100 1101 0101 0101 */ + {illegal,0 }, /* 56: 0100 1101 0101 0110 */ + {illegal,0 }, /* 57: 0100 1101 0101 0111 */ + {illegal,0 }, /* 58: 0100 1101 0101 1000 */ + {illegal,0 }, /* 59: 0100 1101 0101 1001 */ + {illegal,0 }, /* 5a: 0100 1101 0101 1010 */ + {illegal,0 }, /* 5b: 0100 1101 0101 1011 */ + {illegal,0 }, /* 5c: 0100 1101 0101 1100 */ + {illegal,0 }, /* 5d: 0100 1101 0101 1101 */ + {illegal,0 }, /* 5e: 0100 1101 0101 1110 */ + {illegal,0 }, /* 5f: 0100 1101 0101 1111 */ + + {illegal,0 }, /* 60: 0100 1101 0110 0000 */ + {illegal,0 }, /* 61: 0100 1101 0110 0001 */ + {illegal,0 }, /* 62: 0100 1101 0110 0010 */ + {illegal,0 }, /* 63: 0100 1101 0110 0011 */ + {illegal,0 }, /* 64: 0100 1101 0110 0100 */ + {illegal,0 }, /* 65: 0100 1101 0110 0101 */ + {illegal,0 }, /* 66: 0100 1101 0110 0110 */ + {illegal,0 }, /* 67: 0100 1101 0110 0111 */ + {illegal,0 }, /* 68: 0100 1101 0110 1000 */ + {illegal,0 }, /* 69: 0100 1101 0110 1001 */ + {illegal,0 }, /* 6a: 0100 1101 0110 1010 */ + {illegal,0 }, /* 6b: 0100 1101 0110 1011 */ + {illegal,0 }, /* 6c: 0100 1101 0110 1100 */ + {illegal,0 }, /* 6d: 0100 1101 0110 1101 */ + {illegal,0 }, /* 6e: 0100 1101 0110 1110 */ + {illegal,0 }, /* 6f: 0100 1101 0110 1111 */ + + {illegal,0 }, /* 70: 0100 1101 0111 0000 */ + {illegal,0 }, /* 71: 0100 1101 0111 0001 */ + {illegal,0 }, /* 72: 0100 1101 0111 0010 */ + {illegal,0 }, /* 73: 0100 1101 0111 0011 */ + {illegal,0 }, /* 74: 0100 1101 0111 0100 */ + {illegal,0 }, /* 75: 0100 1101 0111 0101 */ + {illegal,0 }, /* 76: 0100 1101 0111 0110 */ + {illegal,0 }, /* 77: 0100 1101 0111 0111 */ + {illegal,0 }, /* 78: 0100 1101 0111 1000 */ + {illegal,0 }, /* 79: 0100 1101 0111 1001 */ + {illegal,0 }, /* 7a: 0100 1101 0111 1010 */ + {illegal,0 }, /* 7b: 0100 1101 0111 1011 */ + {illegal,0 }, /* 7c: 0100 1101 0111 1100 */ + {illegal,0 }, /* 7d: 0100 1101 0111 1101 */ + {illegal,0 }, /* 7e: 0100 1101 0111 1110 */ + {illegal,0 }, /* 7f: 0100 1101 0111 1111 */ + + {illegal,0 }, /* 80: 0100 1101 1000 0000 */ + {illegal,0 }, /* 81: 0100 1101 1000 0001 */ + {illegal,0 }, /* 82: 0100 1101 1000 0010 */ + {illegal,0 }, /* 83: 0100 1101 1000 0011 */ + {illegal,0 }, /* 84: 0100 1101 1000 0100 */ + {illegal,0 }, /* 85: 0100 1101 1000 0101 */ + {illegal,0 }, /* 86: 0100 1101 1000 0110 */ + {illegal,0 }, /* 87: 0100 1101 1000 0111 */ + {illegal,0 }, /* 88: 0100 1101 1000 1000 */ + {illegal,0 }, /* 89: 0100 1101 1000 1001 */ + {illegal,0 }, /* 8a: 0100 1101 1000 1010 */ + {illegal,0 }, /* 8b: 0100 1101 1000 1011 */ + {illegal,0 }, /* 8c: 0100 1101 1000 1100 */ + {illegal,0 }, /* 8d: 0100 1101 1000 1101 */ + {illegal,0 }, /* 8e: 0100 1101 1000 1110 */ + {illegal,0 }, /* 8f: 0100 1101 1000 1111 */ + + {illegal,0 }, /* 90: 0100 1101 1001 0000 */ + {illegal,0 }, /* 91: 0100 1101 1001 0001 */ + {illegal,0 }, /* 92: 0100 1101 1001 0010 */ + {illegal,0 }, /* 93: 0100 1101 1001 0011 */ + {illegal,0 }, /* 94: 0100 1101 1001 0100 */ + {illegal,0 }, /* 95: 0100 1101 1001 0101 */ + {illegal,0 }, /* 96: 0100 1101 1001 0110 */ + {illegal,0 }, /* 97: 0100 1101 1001 0111 */ + {illegal,0 }, /* 98: 0100 1101 1001 1000 */ + {illegal,0 }, /* 99: 0100 1101 1001 1001 */ + {illegal,0 }, /* 9a: 0100 1101 1001 1010 */ + {illegal,0 }, /* 9b: 0100 1101 1001 1011 */ + {illegal,0 }, /* 9c: 0100 1101 1001 1100 */ + {illegal,0 }, /* 9d: 0100 1101 1001 1101 */ + {illegal,0 }, /* 9e: 0100 1101 1001 1110 */ + {illegal,0 }, /* 9f: 0100 1101 1001 1111 */ + + {illegal,0 }, /* a0: 0100 1101 1010 0000 */ + {illegal,0 }, /* a1: 0100 1101 1010 0001 */ + {illegal,0 }, /* a2: 0100 1101 1010 0010 */ + {illegal,0 }, /* a3: 0100 1101 1010 0011 */ + {illegal,0 }, /* a4: 0100 1101 1010 0100 */ + {illegal,0 }, /* a5: 0100 1101 1010 0101 */ + {illegal,0 }, /* a6: 0100 1101 1010 0110 */ + {illegal,0 }, /* a7: 0100 1101 1010 0111 */ + {illegal,0 }, /* a8: 0100 1101 1010 1000 */ + {illegal,0 }, /* a9: 0100 1101 1010 1001 */ + {illegal,0 }, /* aa: 0100 1101 1010 1010 */ + {illegal,0 }, /* ab: 0100 1101 1010 1011 */ + {illegal,0 }, /* ac: 0100 1101 1010 1100 */ + {illegal,0 }, /* ad: 0100 1101 1010 1101 */ + {illegal,0 }, /* ae: 0100 1101 1010 1110 */ + {illegal,0 }, /* af: 0100 1101 1010 1111 */ + + {illegal,0 }, /* b0: 0100 1101 1011 0000 */ + {illegal,0 }, /* b1: 0100 1101 1011 0001 */ + {illegal,0 }, /* b2: 0100 1101 1011 0010 */ + {illegal,0 }, /* b3: 0100 1101 1011 0011 */ + {illegal,0 }, /* b4: 0100 1101 1011 0100 */ + {illegal,0 }, /* b5: 0100 1101 1011 0101 */ + {illegal,0 }, /* b6: 0100 1101 1011 0110 */ + {illegal,0 }, /* b7: 0100 1101 1011 0111 */ + {illegal,0 }, /* b8: 0100 1101 1011 1000 */ + {illegal,0 }, /* b9: 0100 1101 1011 1001 */ + {illegal,0 }, /* ba: 0100 1101 1011 1010 */ + {illegal,0 }, /* bb: 0100 1101 1011 1011 */ + {illegal,0 }, /* bc: 0100 1101 1011 1100 */ + {illegal,0 }, /* bd: 0100 1101 1011 1101 */ + {illegal,0 }, /* be: 0100 1101 1011 1110 */ + {illegal,0 }, /* bf: 0100 1101 1011 1111 */ + + {MOV,"PA,A" }, /* c0: 0100 1101 1100 0000 */ + {MOV,"PB,A" }, /* c1: 0100 1101 1100 0001 */ + {MOV,"PC,A" }, /* c2: 0100 1101 1100 0010 */ + {MOV,"PD,A" }, /* c3: 0100 1101 1100 0011 */ + {illegal,0 }, /* c4: 0100 1101 1100 0100 */ + {MOV,"PF,A" }, /* c5: 0100 1101 1100 0101 */ + {MOV,"MKH,A" }, /* c6: 0100 1101 1100 0110 */ + {MOV,"MKL,A" }, /* c7: 0100 1101 1100 0111 */ + {MOV,"ANM,A" }, /* c8: 0100 1101 1100 1000 */ /* 7810 */ + {MOV,"SMH,A" }, /* c9: 0100 1101 1100 1001 */ + {MOV,"SML,A" }, /* ca: 0100 1101 1100 1010 */ + {MOV,"EOM,A" }, /* cb: 0100 1101 1100 1011 */ + {MOV,"ETMM,A" }, /* cc: 0100 1101 1100 1100 */ + {MOV,"TMM,A" }, /* cd: 0100 1101 1100 1101 */ + {illegal,0 }, /* ce: 0100 1101 1100 1110 */ + {illegal,0 }, /* cf: 0100 1101 1100 1111 */ + + {MOV,"MM,A" }, /* d0: 0100 1101 1101 0000 */ + {MOV,"MCC,A" }, /* d1: 0100 1101 1101 0001 */ + {MOV,"MA,A" }, /* d2: 0100 1101 1101 0010 */ + {MOV,"MB,A" }, /* d3: 0100 1101 1101 0011 */ + {MOV,"MC,A" }, /* d4: 0100 1101 1101 0100 */ + {illegal,0 }, /* d5: 0100 1101 1101 0101 */ + {illegal,0 }, /* d6: 0100 1101 1101 0110 */ + {MOV,"MF,A" }, /* d7: 0100 1101 1101 0111 */ + {MOV,"TXB,A" }, /* d8: 0100 1101 1101 1000 */ + {illegal,0 }, /* d9: 0100 1101 1101 1001 */ + {MOV,"TM0,A" }, /* da: 0100 1101 1101 1010 */ + {MOV,"TM1,A" }, /* db: 0100 1101 1101 1011 */ + {illegal,0 }, /* dc: 0100 1101 1101 1100 */ + {illegal,0 }, /* dd: 0100 1101 1101 1101 */ + {illegal,0 }, /* de: 0100 1101 1101 1110 */ + {illegal,0 }, /* df: 0100 1101 1101 1111 */ + + {illegal,0 }, /* e0: 0100 1101 1110 0000 */ + {illegal,0 }, /* e1: 0100 1101 1110 0001 */ + {illegal,0 }, /* e2: 0100 1101 1110 0010 */ + {illegal,0 }, /* e3: 0100 1101 1110 0011 */ + {illegal,0 }, /* e4: 0100 1101 1110 0100 */ + {illegal,0 }, /* e5: 0100 1101 1110 0101 */ + {illegal,0 }, /* e6: 0100 1101 1110 0110 */ + {illegal,0 }, /* e7: 0100 1101 1110 0111 */ + {MOV,"ZCM,A" }, /* e8: 0100 1101 1110 1000 */ /* 7810 */ + {illegal,0 }, /* e9: 0100 1101 1110 1001 */ + {illegal,0 }, /* ea: 0100 1101 1110 1010 */ + {illegal,0 }, /* eb: 0100 1101 1110 1011 */ + {illegal,0 }, /* ec: 0100 1101 1110 1100 */ + {illegal,0 }, /* ed: 0100 1101 1110 1101 */ + {illegal,0 }, /* ee: 0100 1101 1110 1110 */ + {illegal,0 }, /* ef: 0100 1101 1110 1111 */ + + {illegal,0 }, /* f0: 0100 1101 1111 0000 */ + {illegal,0 }, /* f1: 0100 1101 1111 0001 */ + {illegal,0 }, /* f2: 0100 1101 1111 0010 */ + {illegal,0 }, /* f3: 0100 1101 1111 0011 */ + {illegal,0 }, /* f4: 0100 1101 1111 0100 */ + {illegal,0 }, /* f5: 0100 1101 1111 0101 */ + {illegal,0 }, /* f6: 0100 1101 1111 0110 */ + {illegal,0 }, /* f7: 0100 1101 1111 0111 */ + {illegal,0 }, /* f8: 0100 1101 1111 1000 */ + {illegal,0 }, /* f9: 0100 1101 1111 1001 */ + {illegal,0 }, /* fa: 0100 1101 1111 1010 */ + {illegal,0 }, /* fb: 0100 1101 1111 1011 */ + {illegal,0 }, /* fc: 0100 1101 1111 1100 */ + {illegal,0 }, /* fd: 0100 1101 1111 1101 */ + {illegal,0 }, /* fe: 0100 1101 1111 1110 */ + {illegal,0 } /* ff: 0100 1101 1111 1111 */ +}; + +static const struct dasm_s dasm4D_7807[256] = +{ + {illegal,0 }, /* 00: 0100 1101 0000 0000 */ + {illegal,0 }, /* 01: 0100 1101 0000 0001 */ + {illegal,0 }, /* 02: 0100 1101 0000 0010 */ + {illegal,0 }, /* 03: 0100 1101 0000 0011 */ + {illegal,0 }, /* 04: 0100 1101 0000 0100 */ + {illegal,0 }, /* 05: 0100 1101 0000 0101 */ + {illegal,0 }, /* 06: 0100 1101 0000 0110 */ + {illegal,0 }, /* 07: 0100 1101 0000 0111 */ + {illegal,0 }, /* 08: 0100 1101 0000 1000 */ + {illegal,0 }, /* 09: 0100 1101 0000 1001 */ + {illegal,0 }, /* 0a: 0100 1101 0000 1010 */ + {illegal,0 }, /* 0b: 0100 1101 0000 1011 */ + {illegal,0 }, /* 0c: 0100 1101 0000 1100 */ + {illegal,0 }, /* 0d: 0100 1101 0000 1101 */ + {illegal,0 }, /* 0e: 0100 1101 0000 1110 */ + {illegal,0 }, /* 0f: 0100 1101 0000 1111 */ + + {illegal,0 }, /* 10: 0100 1101 0001 0000 */ + {illegal,0 }, /* 11: 0100 1101 0001 0001 */ + {illegal,0 }, /* 12: 0100 1101 0001 0010 */ + {illegal,0 }, /* 13: 0100 1101 0001 0011 */ + {illegal,0 }, /* 14: 0100 1101 0001 0100 */ + {illegal,0 }, /* 15: 0100 1101 0001 0101 */ + {illegal,0 }, /* 16: 0100 1101 0001 0110 */ + {illegal,0 }, /* 17: 0100 1101 0001 0111 */ + {illegal,0 }, /* 18: 0100 1101 0001 1000 */ + {illegal,0 }, /* 19: 0100 1101 0001 1001 */ + {illegal,0 }, /* 1a: 0100 1101 0001 1010 */ + {illegal,0 }, /* 1b: 0100 1101 0001 1011 */ + {illegal,0 }, /* 1c: 0100 1101 0001 1100 */ + {illegal,0 }, /* 1d: 0100 1101 0001 1101 */ + {illegal,0 }, /* 1e: 0100 1101 0001 1110 */ + {illegal,0 }, /* 1f: 0100 1101 0001 1111 */ + + {illegal,0 }, /* 20: 0100 1101 0010 0000 */ + {illegal,0 }, /* 21: 0100 1101 0010 0001 */ + {illegal,0 }, /* 22: 0100 1101 0010 0010 */ + {illegal,0 }, /* 23: 0100 1101 0010 0011 */ + {illegal,0 }, /* 24: 0100 1101 0010 0100 */ + {illegal,0 }, /* 25: 0100 1101 0010 0101 */ + {illegal,0 }, /* 26: 0100 1101 0010 0110 */ + {illegal,0 }, /* 27: 0100 1101 0010 0111 */ + {illegal,0 }, /* 28: 0100 1101 0010 1000 */ + {illegal,0 }, /* 29: 0100 1101 0010 1001 */ + {illegal,0 }, /* 2a: 0100 1101 0010 1010 */ + {illegal,0 }, /* 2b: 0100 1101 0010 1011 */ + {illegal,0 }, /* 2c: 0100 1101 0010 1100 */ + {illegal,0 }, /* 2d: 0100 1101 0010 1101 */ + {illegal,0 }, /* 2e: 0100 1101 0010 1110 */ + {illegal,0 }, /* 2f: 0100 1101 0010 1111 */ + + {illegal,0 }, /* 30: 0100 1101 0011 0000 */ + {illegal,0 }, /* 31: 0100 1101 0011 0001 */ + {illegal,0 }, /* 32: 0100 1101 0011 0010 */ + {illegal,0 }, /* 33: 0100 1101 0011 0011 */ + {illegal,0 }, /* 34: 0100 1101 0011 0100 */ + {illegal,0 }, /* 35: 0100 1101 0011 0101 */ + {illegal,0 }, /* 36: 0100 1101 0011 0110 */ + {illegal,0 }, /* 37: 0100 1101 0011 0111 */ + {illegal,0 }, /* 38: 0100 1101 0011 1000 */ + {illegal,0 }, /* 39: 0100 1101 0011 1001 */ + {illegal,0 }, /* 3a: 0100 1101 0011 1010 */ + {illegal,0 }, /* 3b: 0100 1101 0011 1011 */ + {illegal,0 }, /* 3c: 0100 1101 0011 1100 */ + {illegal,0 }, /* 3d: 0100 1101 0011 1101 */ + {illegal,0 }, /* 3e: 0100 1101 0011 1110 */ + {illegal,0 }, /* 3f: 0100 1101 0011 1111 */ + + {illegal,0 }, /* 40: 0100 1101 0100 0000 */ + {illegal,0 }, /* 41: 0100 1101 0100 0001 */ + {illegal,0 }, /* 42: 0100 1101 0100 0010 */ + {illegal,0 }, /* 43: 0100 1101 0100 0011 */ + {illegal,0 }, /* 44: 0100 1101 0100 0100 */ + {illegal,0 }, /* 45: 0100 1101 0100 0101 */ + {illegal,0 }, /* 46: 0100 1101 0100 0110 */ + {illegal,0 }, /* 47: 0100 1101 0100 0111 */ + {illegal,0 }, /* 48: 0100 1101 0100 1000 */ + {illegal,0 }, /* 49: 0100 1101 0100 1001 */ + {illegal,0 }, /* 4a: 0100 1101 0100 1010 */ + {illegal,0 }, /* 4b: 0100 1101 0100 1011 */ + {illegal,0 }, /* 4c: 0100 1101 0100 1100 */ + {illegal,0 }, /* 4d: 0100 1101 0100 1101 */ + {illegal,0 }, /* 4e: 0100 1101 0100 1110 */ + {illegal,0 }, /* 4f: 0100 1101 0100 1111 */ + + {illegal,0 }, /* 50: 0100 1101 0101 0000 */ + {illegal,0 }, /* 51: 0100 1101 0101 0001 */ + {illegal,0 }, /* 52: 0100 1101 0101 0010 */ + {illegal,0 }, /* 53: 0100 1101 0101 0011 */ + {illegal,0 }, /* 54: 0100 1101 0101 0100 */ + {illegal,0 }, /* 55: 0100 1101 0101 0101 */ + {illegal,0 }, /* 56: 0100 1101 0101 0110 */ + {illegal,0 }, /* 57: 0100 1101 0101 0111 */ + {illegal,0 }, /* 58: 0100 1101 0101 1000 */ + {illegal,0 }, /* 59: 0100 1101 0101 1001 */ + {illegal,0 }, /* 5a: 0100 1101 0101 1010 */ + {illegal,0 }, /* 5b: 0100 1101 0101 1011 */ + {illegal,0 }, /* 5c: 0100 1101 0101 1100 */ + {illegal,0 }, /* 5d: 0100 1101 0101 1101 */ + {illegal,0 }, /* 5e: 0100 1101 0101 1110 */ + {illegal,0 }, /* 5f: 0100 1101 0101 1111 */ + + {illegal,0 }, /* 60: 0100 1101 0110 0000 */ + {illegal,0 }, /* 61: 0100 1101 0110 0001 */ + {illegal,0 }, /* 62: 0100 1101 0110 0010 */ + {illegal,0 }, /* 63: 0100 1101 0110 0011 */ + {illegal,0 }, /* 64: 0100 1101 0110 0100 */ + {illegal,0 }, /* 65: 0100 1101 0110 0101 */ + {illegal,0 }, /* 66: 0100 1101 0110 0110 */ + {illegal,0 }, /* 67: 0100 1101 0110 0111 */ + {illegal,0 }, /* 68: 0100 1101 0110 1000 */ + {illegal,0 }, /* 69: 0100 1101 0110 1001 */ + {illegal,0 }, /* 6a: 0100 1101 0110 1010 */ + {illegal,0 }, /* 6b: 0100 1101 0110 1011 */ + {illegal,0 }, /* 6c: 0100 1101 0110 1100 */ + {illegal,0 }, /* 6d: 0100 1101 0110 1101 */ + {illegal,0 }, /* 6e: 0100 1101 0110 1110 */ + {illegal,0 }, /* 6f: 0100 1101 0110 1111 */ + + {illegal,0 }, /* 70: 0100 1101 0111 0000 */ + {illegal,0 }, /* 71: 0100 1101 0111 0001 */ + {illegal,0 }, /* 72: 0100 1101 0111 0010 */ + {illegal,0 }, /* 73: 0100 1101 0111 0011 */ + {illegal,0 }, /* 74: 0100 1101 0111 0100 */ + {illegal,0 }, /* 75: 0100 1101 0111 0101 */ + {illegal,0 }, /* 76: 0100 1101 0111 0110 */ + {illegal,0 }, /* 77: 0100 1101 0111 0111 */ + {illegal,0 }, /* 78: 0100 1101 0111 1000 */ + {illegal,0 }, /* 79: 0100 1101 0111 1001 */ + {illegal,0 }, /* 7a: 0100 1101 0111 1010 */ + {illegal,0 }, /* 7b: 0100 1101 0111 1011 */ + {illegal,0 }, /* 7c: 0100 1101 0111 1100 */ + {illegal,0 }, /* 7d: 0100 1101 0111 1101 */ + {illegal,0 }, /* 7e: 0100 1101 0111 1110 */ + {illegal,0 }, /* 7f: 0100 1101 0111 1111 */ + + {illegal,0 }, /* 80: 0100 1101 1000 0000 */ + {illegal,0 }, /* 81: 0100 1101 1000 0001 */ + {illegal,0 }, /* 82: 0100 1101 1000 0010 */ + {illegal,0 }, /* 83: 0100 1101 1000 0011 */ + {illegal,0 }, /* 84: 0100 1101 1000 0100 */ + {illegal,0 }, /* 85: 0100 1101 1000 0101 */ + {illegal,0 }, /* 86: 0100 1101 1000 0110 */ + {illegal,0 }, /* 87: 0100 1101 1000 0111 */ + {illegal,0 }, /* 88: 0100 1101 1000 1000 */ + {illegal,0 }, /* 89: 0100 1101 1000 1001 */ + {illegal,0 }, /* 8a: 0100 1101 1000 1010 */ + {illegal,0 }, /* 8b: 0100 1101 1000 1011 */ + {illegal,0 }, /* 8c: 0100 1101 1000 1100 */ + {illegal,0 }, /* 8d: 0100 1101 1000 1101 */ + {illegal,0 }, /* 8e: 0100 1101 1000 1110 */ + {illegal,0 }, /* 8f: 0100 1101 1000 1111 */ + + {illegal,0 }, /* 90: 0100 1101 1001 0000 */ + {illegal,0 }, /* 91: 0100 1101 1001 0001 */ + {illegal,0 }, /* 92: 0100 1101 1001 0010 */ + {illegal,0 }, /* 93: 0100 1101 1001 0011 */ + {illegal,0 }, /* 94: 0100 1101 1001 0100 */ + {illegal,0 }, /* 95: 0100 1101 1001 0101 */ + {illegal,0 }, /* 96: 0100 1101 1001 0110 */ + {illegal,0 }, /* 97: 0100 1101 1001 0111 */ + {illegal,0 }, /* 98: 0100 1101 1001 1000 */ + {illegal,0 }, /* 99: 0100 1101 1001 1001 */ + {illegal,0 }, /* 9a: 0100 1101 1001 1010 */ + {illegal,0 }, /* 9b: 0100 1101 1001 1011 */ + {illegal,0 }, /* 9c: 0100 1101 1001 1100 */ + {illegal,0 }, /* 9d: 0100 1101 1001 1101 */ + {illegal,0 }, /* 9e: 0100 1101 1001 1110 */ + {illegal,0 }, /* 9f: 0100 1101 1001 1111 */ + + {illegal,0 }, /* a0: 0100 1101 1010 0000 */ + {illegal,0 }, /* a1: 0100 1101 1010 0001 */ + {illegal,0 }, /* a2: 0100 1101 1010 0010 */ + {illegal,0 }, /* a3: 0100 1101 1010 0011 */ + {illegal,0 }, /* a4: 0100 1101 1010 0100 */ + {illegal,0 }, /* a5: 0100 1101 1010 0101 */ + {illegal,0 }, /* a6: 0100 1101 1010 0110 */ + {illegal,0 }, /* a7: 0100 1101 1010 0111 */ + {illegal,0 }, /* a8: 0100 1101 1010 1000 */ + {illegal,0 }, /* a9: 0100 1101 1010 1001 */ + {illegal,0 }, /* aa: 0100 1101 1010 1010 */ + {illegal,0 }, /* ab: 0100 1101 1010 1011 */ + {illegal,0 }, /* ac: 0100 1101 1010 1100 */ + {illegal,0 }, /* ad: 0100 1101 1010 1101 */ + {illegal,0 }, /* ae: 0100 1101 1010 1110 */ + {illegal,0 }, /* af: 0100 1101 1010 1111 */ + + {illegal,0 }, /* b0: 0100 1101 1011 0000 */ + {illegal,0 }, /* b1: 0100 1101 1011 0001 */ + {illegal,0 }, /* b2: 0100 1101 1011 0010 */ + {illegal,0 }, /* b3: 0100 1101 1011 0011 */ + {illegal,0 }, /* b4: 0100 1101 1011 0100 */ + {illegal,0 }, /* b5: 0100 1101 1011 0101 */ + {illegal,0 }, /* b6: 0100 1101 1011 0110 */ + {illegal,0 }, /* b7: 0100 1101 1011 0111 */ + {illegal,0 }, /* b8: 0100 1101 1011 1000 */ + {illegal,0 }, /* b9: 0100 1101 1011 1001 */ + {illegal,0 }, /* ba: 0100 1101 1011 1010 */ + {illegal,0 }, /* bb: 0100 1101 1011 1011 */ + {illegal,0 }, /* bc: 0100 1101 1011 1100 */ + {illegal,0 }, /* bd: 0100 1101 1011 1101 */ + {illegal,0 }, /* be: 0100 1101 1011 1110 */ + {illegal,0 }, /* bf: 0100 1101 1011 1111 */ + + {MOV,"PA,A" }, /* c0: 0100 1101 1100 0000 */ + {MOV,"PB,A" }, /* c1: 0100 1101 1100 0001 */ + {MOV,"PC,A" }, /* c2: 0100 1101 1100 0010 */ + {MOV,"PD,A" }, /* c3: 0100 1101 1100 0011 */ + {illegal,0 }, /* c4: 0100 1101 1100 0100 */ + {MOV,"PF,A" }, /* c5: 0100 1101 1100 0101 */ + {MOV,"MKH,A" }, /* c6: 0100 1101 1100 0110 */ + {MOV,"MKL,A" }, /* c7: 0100 1101 1100 0111 */ + {illegal,0 }, /* c8: 0100 1101 1100 1000 */ + {MOV,"SMH,A" }, /* c9: 0100 1101 1100 1001 */ + {MOV,"SML,A" }, /* ca: 0100 1101 1100 1010 */ + {MOV,"EOM,A" }, /* cb: 0100 1101 1100 1011 */ + {MOV,"ETMM,A" }, /* cc: 0100 1101 1100 1100 */ + {MOV,"TMM,A" }, /* cd: 0100 1101 1100 1101 */ + {illegal,0 }, /* ce: 0100 1101 1100 1110 */ + {illegal,0 }, /* cf: 0100 1101 1100 1111 */ + + {MOV,"MM,A" }, /* d0: 0100 1101 1101 0000 */ + {MOV,"MCC,A" }, /* d1: 0100 1101 1101 0001 */ + {MOV,"MA,A" }, /* d2: 0100 1101 1101 0010 */ + {MOV,"MB,A" }, /* d3: 0100 1101 1101 0011 */ + {MOV,"MC,A" }, /* d4: 0100 1101 1101 0100 */ + {illegal,0 }, /* d5: 0100 1101 1101 0101 */ + {illegal,0 }, /* d6: 0100 1101 1101 0110 */ + {MOV,"MF,A" }, /* d7: 0100 1101 1101 0111 */ + {MOV,"TXB,A" }, /* d8: 0100 1101 1101 1000 */ + {illegal,0 }, /* d9: 0100 1101 1101 1001 */ + {MOV,"TM0,A" }, /* da: 0100 1101 1101 1010 */ + {MOV,"TM1,A" }, /* db: 0100 1101 1101 1011 */ + {illegal,0 }, /* dc: 0100 1101 1101 1100 */ + {illegal,0 }, /* dd: 0100 1101 1101 1101 */ + {illegal,0 }, /* de: 0100 1101 1101 1110 */ + {illegal,0 }, /* df: 0100 1101 1101 1111 */ + + {illegal,0 }, /* e0: 0100 1101 1110 0000 */ + {illegal,0 }, /* e1: 0100 1101 1110 0001 */ + {illegal,0 }, /* e2: 0100 1101 1110 0010 */ + {illegal,0 }, /* e3: 0100 1101 1110 0011 */ + {illegal,0 }, /* e4: 0100 1101 1110 0100 */ + {MOV,"MT,A" }, /* e5: 0100 1101 1110 0101 */ /* 7807 */ + {illegal,0 }, /* e6: 0100 1101 1110 0110 */ + {illegal,0 }, /* e7: 0100 1101 1110 0111 */ + {illegal,0 }, /* e8: 0100 1101 1110 1000 */ + {illegal,0 }, /* e9: 0100 1101 1110 1001 */ + {illegal,0 }, /* ea: 0100 1101 1110 1010 */ + {illegal,0 }, /* eb: 0100 1101 1110 1011 */ + {illegal,0 }, /* ec: 0100 1101 1110 1100 */ + {illegal,0 }, /* ed: 0100 1101 1110 1101 */ + {illegal,0 }, /* ee: 0100 1101 1110 1110 */ + {illegal,0 }, /* ef: 0100 1101 1110 1111 */ + + {illegal,0 }, /* f0: 0100 1101 1111 0000 */ + {illegal,0 }, /* f1: 0100 1101 1111 0001 */ + {illegal,0 }, /* f2: 0100 1101 1111 0010 */ + {illegal,0 }, /* f3: 0100 1101 1111 0011 */ + {illegal,0 }, /* f4: 0100 1101 1111 0100 */ + {illegal,0 }, /* f5: 0100 1101 1111 0101 */ + {illegal,0 }, /* f6: 0100 1101 1111 0110 */ + {illegal,0 }, /* f7: 0100 1101 1111 0111 */ + {illegal,0 }, /* f8: 0100 1101 1111 1000 */ + {illegal,0 }, /* f9: 0100 1101 1111 1001 */ + {illegal,0 }, /* fa: 0100 1101 1111 1010 */ + {illegal,0 }, /* fb: 0100 1101 1111 1011 */ + {illegal,0 }, /* fc: 0100 1101 1111 1100 */ + {illegal,0 }, /* fd: 0100 1101 1111 1101 */ + {illegal,0 }, /* fe: 0100 1101 1111 1110 */ + {illegal,0 } /* ff: 0100 1101 1111 1111 */ +}; + +/* prefix 60 */ +static const struct dasm_s dasm60[256] = +{ + {illegal,0 }, /* 00: 0110 0000 0000 0000 */ + {illegal,0 }, /* 01: 0110 0000 0000 0001 */ + {illegal,0 }, /* 02: 0110 0000 0000 0010 */ + {illegal,0 }, /* 03: 0110 0000 0000 0011 */ + {illegal,0 }, /* 04: 0110 0000 0000 0100 */ + {illegal,0 }, /* 05: 0110 0000 0000 0101 */ + {illegal,0 }, /* 06: 0110 0000 0000 0110 */ + {illegal,0 }, /* 07: 0110 0000 0000 0111 */ + {ANA,"V,A" }, /* 08: 0110 0000 0000 1000 */ + {ANA,"A,A" }, /* 09: 0110 0000 0000 1001 */ + {ANA,"B,A" }, /* 0a: 0110 0000 0000 1010 */ + {ANA,"C,A" }, /* 0b: 0110 0000 0000 1011 */ + {ANA,"D,A" }, /* 0c: 0110 0000 0000 1100 */ + {ANA,"E,A" }, /* 0d: 0110 0000 0000 1101 */ + {ANA,"H,A" }, /* 0e: 0110 0000 0000 1110 */ + {ANA,"L,A" }, /* 0f: 0110 0000 0000 1111 */ + + {XRA,"V,A" }, /* 10: 0110 0000 0001 0000 */ + {XRA,"A,A" }, /* 11: 0110 0000 0001 0001 */ + {XRA,"B,A" }, /* 12: 0110 0000 0001 0010 */ + {XRA,"C,A" }, /* 13: 0110 0000 0001 0011 */ + {XRA,"D,A" }, /* 14: 0110 0000 0001 0100 */ + {XRA,"E,A" }, /* 15: 0110 0000 0001 0101 */ + {XRA,"H,A" }, /* 16: 0110 0000 0001 0110 */ + {XRA,"L,A" }, /* 17: 0110 0000 0001 0111 */ + {ORA,"V,A" }, /* 18: 0110 0000 0001 1000 */ + {ORA,"A,A" }, /* 19: 0110 0000 0001 1001 */ + {ORA,"B,A" }, /* 1a: 0110 0000 0001 1010 */ + {ORA,"C,A" }, /* 1b: 0110 0000 0001 1011 */ + {ORA,"D,A" }, /* 1c: 0110 0000 0001 1100 */ + {ORA,"E,A" }, /* 1d: 0110 0000 0001 1101 */ + {ORA,"H,A" }, /* 1e: 0110 0000 0001 1110 */ + {ORA,"L,A" }, /* 1f: 0110 0000 0001 1111 */ + + {ADDNC,"V,A" }, /* 20: 0110 0000 0010 0000 */ + {ADDNC,"A,A" }, /* 21: 0110 0000 0010 0001 */ + {ADDNC,"B,A" }, /* 22: 0110 0000 0010 0010 */ + {ADDNC,"C,A" }, /* 23: 0110 0000 0010 0011 */ + {ADDNC,"D,A" }, /* 24: 0110 0000 0010 0100 */ + {ADDNC,"E,A" }, /* 25: 0110 0000 0010 0101 */ + {ADDNC,"H,A" }, /* 26: 0110 0000 0010 0110 */ + {ADDNC,"L,A" }, /* 27: 0110 0000 0010 0111 */ + {GTA,"V,A" }, /* 28: 0110 0000 0010 1000 */ + {GTA,"A,A" }, /* 29: 0110 0000 0010 1001 */ + {GTA,"B,A" }, /* 2a: 0110 0000 0010 1010 */ + {GTA,"C,A" }, /* 2b: 0110 0000 0010 1011 */ + {GTA,"D,A" }, /* 2c: 0110 0000 0010 1100 */ + {GTA,"E,A" }, /* 2d: 0110 0000 0010 1101 */ + {GTA,"H,A" }, /* 2e: 0110 0000 0010 1110 */ + {GTA,"L,A" }, /* 2f: 0110 0000 0010 1111 */ + + {SUBNB,"V,A" }, /* 30: 0110 0000 0011 0000 */ + {SUBNB,"A,A" }, /* 31: 0110 0000 0011 0001 */ + {SUBNB,"B,A" }, /* 32: 0110 0000 0011 0010 */ + {SUBNB,"C,A" }, /* 33: 0110 0000 0011 0011 */ + {SUBNB,"D,A" }, /* 34: 0110 0000 0011 0100 */ + {SUBNB,"E,A" }, /* 35: 0110 0000 0011 0101 */ + {SUBNB,"H,A" }, /* 36: 0110 0000 0011 0110 */ + {SUBNB,"L,A" }, /* 37: 0110 0000 0011 0111 */ + {LTA,"V,A" }, /* 38: 0110 0000 0011 1000 */ + {LTA,"A,A" }, /* 39: 0110 0000 0011 1001 */ + {LTA,"B,A" }, /* 3a: 0110 0000 0011 1010 */ + {LTA,"C,A" }, /* 3b: 0110 0000 0011 1011 */ + {LTA,"D,A" }, /* 3c: 0110 0000 0011 1100 */ + {LTA,"E,A" }, /* 3d: 0110 0000 0011 1101 */ + {LTA,"H,A" }, /* 3e: 0110 0000 0011 1110 */ + {LTA,"L,A" }, /* 3f: 0110 0000 0011 1111 */ + + {ADD,"V,A" }, /* 40: 0110 0000 0100 0000 */ + {ADD,"A,A" }, /* 41: 0110 0000 0100 0001 */ + {ADD,"B,A" }, /* 42: 0110 0000 0100 0010 */ + {ADD,"C,A" }, /* 43: 0110 0000 0100 0011 */ + {ADD,"D,A" }, /* 44: 0110 0000 0100 0100 */ + {ADD,"E,A" }, /* 45: 0110 0000 0100 0101 */ + {ADD,"H,A" }, /* 46: 0110 0000 0100 0110 */ + {ADD,"L,A" }, /* 47: 0110 0000 0100 0111 */ + {illegal,0 }, /* 48: 0110 0000 0100 1000 */ + {illegal,0 }, /* 49: 0110 0000 0100 1001 */ + {illegal,0 }, /* 4a: 0110 0000 0100 1010 */ + {illegal,0 }, /* 4b: 0110 0000 0100 1011 */ + {illegal,0 }, /* 4c: 0110 0000 0100 1100 */ + {illegal,0 }, /* 4d: 0110 0000 0100 1101 */ + {illegal,0 }, /* 4e: 0110 0000 0100 1110 */ + {illegal,0 }, /* 4f: 0110 0000 0100 1111 */ + + {ADC,"V,A" }, /* 50: 0110 0000 0101 0000 */ + {ADC,"A,A" }, /* 51: 0110 0000 0101 0001 */ + {ADC,"B,A" }, /* 52: 0110 0000 0101 0010 */ + {ADC,"C,A" }, /* 53: 0110 0000 0101 0011 */ + {ADC,"D,A" }, /* 54: 0110 0000 0101 0100 */ + {ADC,"E,A" }, /* 55: 0110 0000 0101 0101 */ + {ADC,"H,A" }, /* 56: 0110 0000 0101 0110 */ + {ADC,"L,A" }, /* 57: 0110 0000 0101 0111 */ + {illegal,0 }, /* 58: 0110 0000 0101 1000 */ + {illegal,0 }, /* 59: 0110 0000 0101 1001 */ + {illegal,0 }, /* 5a: 0110 0000 0101 1010 */ + {illegal,0 }, /* 5b: 0110 0000 0101 1011 */ + {illegal,0 }, /* 5c: 0110 0000 0101 1100 */ + {illegal,0 }, /* 5d: 0110 0000 0101 1101 */ + {illegal,0 }, /* 5e: 0110 0000 0101 1110 */ + {illegal,0 }, /* 5f: 0110 0000 0101 1111 */ + + {SUB,"V,A" }, /* 60: 0110 0000 0110 0000 */ + {SUB,"A,A" }, /* 61: 0110 0000 0110 0001 */ + {SUB,"B,A" }, /* 62: 0110 0000 0110 0010 */ + {SUB,"C,A" }, /* 63: 0110 0000 0110 0011 */ + {SUB,"D,A" }, /* 64: 0110 0000 0110 0100 */ + {SUB,"E,A" }, /* 65: 0110 0000 0110 0101 */ + {SUB,"H,A" }, /* 66: 0110 0000 0110 0110 */ + {SUB,"L,A" }, /* 67: 0110 0000 0110 0111 */ + {NEA,"V,A" }, /* 68: 0110 0000 0110 1000 */ + {NEA,"A,A" }, /* 69: 0110 0000 0110 1001 */ + {NEA,"B,A" }, /* 6a: 0110 0000 0110 1010 */ + {NEA,"C,A" }, /* 6b: 0110 0000 0110 1011 */ + {NEA,"D,A" }, /* 6c: 0110 0000 0110 1100 */ + {NEA,"E,A" }, /* 6d: 0110 0000 0110 1101 */ + {NEA,"H,A" }, /* 6e: 0110 0000 0110 1110 */ + {NEA,"L,A" }, /* 6f: 0110 0000 0110 1111 */ + + {SBB,"V,A" }, /* 70: 0110 0000 0111 0000 */ + {SBB,"A,A" }, /* 71: 0110 0000 0111 0001 */ + {SBB,"B,A" }, /* 72: 0110 0000 0111 0010 */ + {SBB,"C,A" }, /* 73: 0110 0000 0111 0011 */ + {SBB,"D,A" }, /* 74: 0110 0000 0111 0100 */ + {SBB,"E,A" }, /* 75: 0110 0000 0111 0101 */ + {SBB,"H,A" }, /* 76: 0110 0000 0111 0110 */ + {SBB,"L,A" }, /* 77: 0110 0000 0111 0111 */ + {EQA,"V,A" }, /* 78: 0110 0000 0111 1000 */ + {EQA,"A,A" }, /* 79: 0110 0000 0111 1001 */ + {EQA,"B,A" }, /* 7a: 0110 0000 0111 1010 */ + {EQA,"C,A" }, /* 7b: 0110 0000 0111 1011 */ + {EQA,"D,A" }, /* 7c: 0110 0000 0111 1100 */ + {EQA,"E,A" }, /* 7d: 0110 0000 0111 1101 */ + {EQA,"H,A" }, /* 7e: 0110 0000 0111 1110 */ + {EQA,"L,A" }, /* 7f: 0110 0000 0111 1111 */ + + {illegal,0 }, /* 80: 0110 0000 1000 0000 */ + {illegal,0 }, /* 81: 0110 0000 1000 0001 */ + {illegal,0 }, /* 82: 0110 0000 1000 0010 */ + {illegal,0 }, /* 83: 0110 0000 1000 0011 */ + {illegal,0 }, /* 84: 0110 0000 1000 0100 */ + {illegal,0 }, /* 85: 0110 0000 1000 0101 */ + {illegal,0 }, /* 86: 0110 0000 1000 0110 */ + {illegal,0 }, /* 87: 0110 0000 1000 0111 */ + {ANA,"A,V" }, /* 88: 0110 0000 1000 1000 */ + {ANA,"A,A" }, /* 89: 0110 0000 1000 1001 */ + {ANA,"A,B" }, /* 8a: 0110 0000 1000 1010 */ + {ANA,"A,C" }, /* 8b: 0110 0000 1000 1011 */ + {ANA,"A,D" }, /* 8c: 0110 0000 1000 1100 */ + {ANA,"A,E" }, /* 8d: 0110 0000 1000 1101 */ + {ANA,"A,H" }, /* 8e: 0110 0000 1000 1110 */ + {ANA,"A,L" }, /* 8f: 0110 0000 1000 1111 */ + + {XRA,"A,V" }, /* 90: 0110 0000 1001 0000 */ + {XRA,"A,A" }, /* 91: 0110 0000 1001 0001 */ + {XRA,"A,B" }, /* 92: 0110 0000 1001 0010 */ + {XRA,"A,C" }, /* 93: 0110 0000 1001 0011 */ + {XRA,"A,D" }, /* 94: 0110 0000 1001 0100 */ + {XRA,"A,E" }, /* 95: 0110 0000 1001 0101 */ + {XRA,"A,H" }, /* 96: 0110 0000 1001 0110 */ + {XRA,"A,L" }, /* 97: 0110 0000 1001 0111 */ + {ORA,"A,V" }, /* 98: 0110 0000 1001 1000 */ + {ORA,"A,A" }, /* 99: 0110 0000 1001 1001 */ + {ORA,"A,B" }, /* 9a: 0110 0000 1001 1010 */ + {ORA,"A,C" }, /* 9b: 0110 0000 1001 1011 */ + {ORA,"A,D" }, /* 9c: 0110 0000 1001 1100 */ + {ORA,"A,E" }, /* 9d: 0110 0000 1001 1101 */ + {ORA,"A,H" }, /* 9e: 0110 0000 1001 1110 */ + {ORA,"A,L" }, /* 9f: 0110 0000 1001 1111 */ + + {ADDNC,"A,V" }, /* a0: 0110 0000 1010 0000 */ + {ADDNC,"A,A" }, /* a1: 0110 0000 1010 0001 */ + {ADDNC,"A,B" }, /* a2: 0110 0000 1010 0010 */ + {ADDNC,"A,C" }, /* a3: 0110 0000 1010 0011 */ + {ADDNC,"A,D" }, /* a4: 0110 0000 1010 0100 */ + {ADDNC,"A,E" }, /* a5: 0110 0000 1010 0101 */ + {ADDNC,"A,H" }, /* a6: 0110 0000 1010 0110 */ + {ADDNC,"A,L" }, /* a7: 0110 0000 1010 0111 */ + {GTA,"A,V" }, /* a8: 0110 0000 1010 1000 */ + {GTA,"A,A" }, /* a9: 0110 0000 1010 1001 */ + {GTA,"A,B" }, /* aa: 0110 0000 1010 1010 */ + {GTA,"A,C" }, /* ab: 0110 0000 1010 1011 */ + {GTA,"A,D" }, /* ac: 0110 0000 1010 1100 */ + {GTA,"A,E" }, /* ad: 0110 0000 1010 1101 */ + {GTA,"A,H" }, /* ae: 0110 0000 1010 1110 */ + {GTA,"A,L" }, /* af: 0110 0000 1010 1111 */ + + {SUBNB,"A,V" }, /* b0: 0110 0000 1011 0000 */ + {SUBNB,"A,A" }, /* b1: 0110 0000 1011 0001 */ + {SUBNB,"A,B" }, /* b2: 0110 0000 1011 0010 */ + {SUBNB,"A,C" }, /* b3: 0110 0000 1011 0011 */ + {SUBNB,"A,D" }, /* b4: 0110 0000 1011 0100 */ + {SUBNB,"A,E" }, /* b5: 0110 0000 1011 0101 */ + {SUBNB,"A,H" }, /* b6: 0110 0000 1011 0110 */ + {SUBNB,"A,L" }, /* b7: 0110 0000 1011 0111 */ + {LTA,"A,V" }, /* b8: 0110 0000 1011 1000 */ + {LTA,"A,A" }, /* b9: 0110 0000 1011 1001 */ + {LTA,"A,B" }, /* ba: 0110 0000 1011 1010 */ + {LTA,"A,C" }, /* bb: 0110 0000 1011 1011 */ + {LTA,"A,D" }, /* bc: 0110 0000 1011 1100 */ + {LTA,"A,E" }, /* bd: 0110 0000 1011 1101 */ + {LTA,"A,H" }, /* be: 0110 0000 1011 1110 */ + {LTA,"A,L" }, /* bf: 0110 0000 1011 1111 */ + + {ADD,"A,V" }, /* c0: 0110 0000 1100 0000 */ + {ADD,"A,A" }, /* c1: 0110 0000 1100 0001 */ + {ADD,"A,B" }, /* c2: 0110 0000 1100 0010 */ + {ADD,"A,C" }, /* c3: 0110 0000 1100 0011 */ + {ADD,"A,D" }, /* c4: 0110 0000 1100 0100 */ + {ADD,"A,E" }, /* c5: 0110 0000 1100 0101 */ + {ADD,"A,H" }, /* c6: 0110 0000 1100 0110 */ + {ADD,"A,L" }, /* c7: 0110 0000 1100 0111 */ + {ONA,"A,V" }, /* c8: 0110 0000 1100 1000 */ + {ONA,"A,A" }, /* c9: 0110 0000 1100 1001 */ + {ONA,"A,B" }, /* ca: 0110 0000 1100 1010 */ + {ONA,"A,C" }, /* cb: 0110 0000 1100 1011 */ + {ONA,"A,D" }, /* cc: 0110 0000 1100 1100 */ + {ONA,"A,E" }, /* cd: 0110 0000 1100 1101 */ + {ONA,"A,H" }, /* ce: 0110 0000 1100 1110 */ + {ONA,"A,L" }, /* cf: 0110 0000 1100 1111 */ + + {ADC,"A,V" }, /* d0: 0110 0000 1101 0000 */ + {ADC,"A,A" }, /* d1: 0110 0000 1101 0001 */ + {ADC,"A,B" }, /* d2: 0110 0000 1101 0010 */ + {ADC,"A,C" }, /* d3: 0110 0000 1101 0011 */ + {ADC,"A,D" }, /* d4: 0110 0000 1101 0100 */ + {ADC,"A,E" }, /* d5: 0110 0000 1101 0101 */ + {ADC,"A,H" }, /* d6: 0110 0000 1101 0110 */ + {ADC,"A,L" }, /* d7: 0110 0000 1101 0111 */ + {OFFA,"A,V" }, /* d8: 0110 0000 1101 1000 */ + {OFFA,"A,A" }, /* d9: 0110 0000 1101 1001 */ + {OFFA,"A,B" }, /* da: 0110 0000 1101 1010 */ + {OFFA,"A,C" }, /* db: 0110 0000 1101 1011 */ + {OFFA,"A,D" }, /* dc: 0110 0000 1101 1100 */ + {OFFA,"A,E" }, /* dd: 0110 0000 1101 1101 */ + {OFFA,"A,H" }, /* de: 0110 0000 1101 1110 */ + {OFFA,"A,L" }, /* df: 0110 0000 1101 1111 */ + + {SUB,"A,V" }, /* e0: 0110 0000 1110 0000 */ + {SUB,"A,A" }, /* e1: 0110 0000 1110 0001 */ + {SUB,"A,B" }, /* e2: 0110 0000 1110 0010 */ + {SUB,"A,C" }, /* e3: 0110 0000 1110 0011 */ + {SUB,"A,D" }, /* e4: 0110 0000 1110 0100 */ + {SUB,"A,E" }, /* e5: 0110 0000 1110 0101 */ + {SUB,"A,H" }, /* e6: 0110 0000 1110 0110 */ + {SUB,"A,L" }, /* e7: 0110 0000 1110 0111 */ + {NEA,"A,V" }, /* e8: 0110 0000 1110 1000 */ + {NEA,"A,A" }, /* e9: 0110 0000 1110 1001 */ + {NEA,"A,B" }, /* ea: 0110 0000 1110 1010 */ + {NEA,"A,C" }, /* eb: 0110 0000 1110 1011 */ + {NEA,"A,D" }, /* ec: 0110 0000 1110 1100 */ + {NEA,"A,E" }, /* ed: 0110 0000 1110 1101 */ + {NEA,"A,H" }, /* ee: 0110 0000 1110 1110 */ + {NEA,"A,L" }, /* ef: 0110 0000 1110 1111 */ + + {SBB,"A,V" }, /* f0: 0110 0000 1111 0000 */ + {SBB,"A,A" }, /* f1: 0110 0000 1111 0001 */ + {SBB,"A,B" }, /* f2: 0110 0000 1111 0010 */ + {SBB,"A,C" }, /* f3: 0110 0000 1111 0011 */ + {SBB,"A,D" }, /* f4: 0110 0000 1111 0100 */ + {SBB,"A,E" }, /* f5: 0110 0000 1111 0101 */ + {SBB,"A,H" }, /* f6: 0110 0000 1111 0110 */ + {SBB,"A,L" }, /* f7: 0110 0000 1111 0111 */ + {EQA,"A,V" }, /* f8: 0110 0000 1111 1000 */ + {EQA,"A,A" }, /* f9: 0110 0000 1111 1001 */ + {EQA,"A,B" }, /* fa: 0110 0000 1111 1010 */ + {EQA,"A,C" }, /* fb: 0110 0000 1111 1011 */ + {EQA,"A,D" }, /* fc: 0110 0000 1111 1100 */ + {EQA,"A,E" }, /* fd: 0110 0000 1111 1101 */ + {EQA,"A,H" }, /* fe: 0110 0000 1111 1110 */ + {EQA,"A,L" } /* ff: 0110 0000 1111 1111 */ +}; + +/* prefix 64 */ +static const struct dasm_s dasm64_7810[256] = +{ + {MVI,"PA,%b" }, /* 00: 0110 0100 0000 0000 xxxx xxxx */ + {MVI,"PB,%b" }, /* 01: 0110 0100 0000 0001 xxxx xxxx */ + {MVI,"PC,%b" }, /* 02: 0110 0100 0000 0010 xxxx xxxx */ + {MVI,"PD,%b" }, /* 03: 0110 0100 0000 0011 xxxx xxxx */ + {illegal,0 }, /* 04: 0110 0100 0000 0100 xxxx xxxx */ + {MVI,"PF,%b" }, /* 05: 0110 0100 0000 0101 xxxx xxxx */ + {MVI,"MKH,%b" }, /* 06: 0110 0100 0000 0110 xxxx xxxx */ + {MVI,"MKL,%b" }, /* 07: 0110 0100 0000 0111 xxxx xxxx */ + {ANI,"PA,%b" }, /* 08: 0110 0100 0000 1000 xxxx xxxx */ + {ANI,"PB,%b" }, /* 09: 0110 0100 0000 1001 xxxx xxxx */ + {ANI,"PC,%b" }, /* 0a: 0110 0100 0000 1010 xxxx xxxx */ + {ANI,"PD,%b" }, /* 0b: 0110 0100 0000 1011 xxxx xxxx */ + {illegal,0 }, /* 0c: 0110 0100 0000 1100 xxxx xxxx */ + {ANI,"PF,%b" }, /* 0d: 0110 0100 0000 1101 xxxx xxxx */ + {ANI,"MKH,%b" }, /* 0e: 0110 0100 0000 1110 xxxx xxxx */ + {ANI,"MKL,%b" }, /* 0f: 0110 0100 0000 1111 xxxx xxxx */ + + {XRI,"PA,%b" }, /* 10: 0110 0100 0001 0000 xxxx xxxx */ + {XRI,"PB,%b" }, /* 11: 0110 0100 0001 0001 xxxx xxxx */ + {XRI,"PC,%b" }, /* 12: 0110 0100 0001 0010 xxxx xxxx */ + {XRI,"PD,%b" }, /* 13: 0110 0100 0001 0011 xxxx xxxx */ + {illegal,0 }, /* 14: 0110 0100 0001 0100 xxxx xxxx */ + {XRI,"PF,%b" }, /* 15: 0110 0100 0001 0101 xxxx xxxx */ + {XRI,"MKH,%b" }, /* 16: 0110 0100 0001 0110 xxxx xxxx */ + {XRI,"MKL,%b" }, /* 17: 0110 0100 0001 0111 xxxx xxxx */ + {ORI,"PA,%b" }, /* 18: 0110 0100 0001 1000 xxxx xxxx */ + {ORI,"PB,%b" }, /* 19: 0110 0100 0001 1001 xxxx xxxx */ + {ORI,"PC,%b" }, /* 1a: 0110 0100 0001 1010 xxxx xxxx */ + {ORI,"PD,%b" }, /* 1b: 0110 0100 0001 1011 xxxx xxxx */ + {illegal,0 }, /* 1c: 0110 0100 0001 1100 xxxx xxxx */ + {ORI,"PF,%b" }, /* 1d: 0110 0100 0001 1101 xxxx xxxx */ + {ORI,"MKH,%b" }, /* 1e: 0110 0100 0001 1110 xxxx xxxx */ + {ORI,"MKL,%b" }, /* 1f: 0110 0100 0001 1111 xxxx xxxx */ + + {ADINC,"PA,%b" }, /* 20: 0110 0100 0010 0000 xxxx xxxx */ + {ADINC,"PB,%b" }, /* 21: 0110 0100 0010 0001 xxxx xxxx */ + {ADINC,"PC,%b" }, /* 22: 0110 0100 0010 0010 xxxx xxxx */ + {ADINC,"PD,%b" }, /* 23: 0110 0100 0010 0011 xxxx xxxx */ + {illegal,0 }, /* 24: 0110 0100 0010 0100 xxxx xxxx */ + {ADINC,"PF,%b" }, /* 25: 0110 0100 0010 0101 xxxx xxxx */ + {ADINC,"MKH,%b" }, /* 26: 0110 0100 0010 0110 xxxx xxxx */ + {ADINC,"MKL,%b" }, /* 27: 0110 0100 0010 0111 xxxx xxxx */ + {GTI,"PA,%b" }, /* 28: 0110 0100 0010 1000 xxxx xxxx */ + {GTI,"PB,%b" }, /* 29: 0110 0100 0010 1001 xxxx xxxx */ + {GTI,"PC,%b" }, /* 2a: 0110 0100 0010 1010 xxxx xxxx */ + {GTI,"PD,%b" }, /* 2b: 0110 0100 0010 1011 xxxx xxxx */ + {illegal,0 }, /* 2c: 0110 0100 0010 1100 xxxx xxxx */ + {GTI,"PF,%b" }, /* 2d: 0110 0100 0010 1101 xxxx xxxx */ + {GTI,"MKH,%b" }, /* 2e: 0110 0100 0010 1110 xxxx xxxx */ + {GTI,"MKL,%b" }, /* 2f: 0110 0100 0010 1111 xxxx xxxx */ + + {SUINB,"PA,%b" }, /* 30: 0110 0100 0011 0000 xxxx xxxx */ + {SUINB,"PB,%b" }, /* 31: 0110 0100 0011 0001 xxxx xxxx */ + {SUINB,"PC,%b" }, /* 32: 0110 0100 0011 0010 xxxx xxxx */ + {SUINB,"PD,%b" }, /* 33: 0110 0100 0011 0011 xxxx xxxx */ + {illegal,0 }, /* 34: 0110 0100 0011 0100 xxxx xxxx */ + {SUINB,"PF,%b" }, /* 35: 0110 0100 0011 0101 xxxx xxxx */ + {SUINB,"MKH,%b" }, /* 36: 0110 0100 0011 0110 xxxx xxxx */ + {SUINB,"MKL,%b" }, /* 37: 0110 0100 0011 0111 xxxx xxxx */ + {LTI,"PA,%b" }, /* 38: 0110 0100 0011 1000 xxxx xxxx */ + {LTI,"PB,%b" }, /* 39: 0110 0100 0011 1001 xxxx xxxx */ + {LTI,"PC,%b" }, /* 3a: 0110 0100 0011 1010 xxxx xxxx */ + {LTI,"PD,%b" }, /* 3b: 0110 0100 0011 1011 xxxx xxxx */ + {illegal,0 }, /* 3c: 0110 0100 0011 1100 xxxx xxxx */ + {LTI,"PF,%b" }, /* 3d: 0110 0100 0011 1101 xxxx xxxx */ + {LTI,"MKH,%b" }, /* 3e: 0110 0100 0011 1110 xxxx xxxx */ + {LTI,"MKL,%b" }, /* 3f: 0110 0100 0011 1111 xxxx xxxx */ + + {ADI,"PA,%b" }, /* 40: 0110 0100 0100 0000 xxxx xxxx */ + {ADI,"PB,%b" }, /* 41: 0110 0100 0100 0001 xxxx xxxx */ + {ADI,"PC,%b" }, /* 42: 0110 0100 0100 0010 xxxx xxxx */ + {ADI,"PD,%b" }, /* 43: 0110 0100 0100 0011 xxxx xxxx */ + {illegal,0 }, /* 44: 0110 0100 0100 0100 xxxx xxxx */ + {ADI,"PF,%b" }, /* 45: 0110 0100 0100 0101 xxxx xxxx */ + {ADI,"MKH,%b" }, /* 46: 0110 0100 0100 0110 xxxx xxxx */ + {ADI,"MKL,%b" }, /* 47: 0110 0100 0100 0111 xxxx xxxx */ + {ONI,"PA,%b" }, /* 48: 0110 0100 0100 1000 xxxx xxxx */ + {ONI,"PB,%b" }, /* 49: 0110 0100 0100 1001 xxxx xxxx */ + {ONI,"PC,%b" }, /* 4a: 0110 0100 0100 1010 xxxx xxxx */ + {ONI,"PD,%b" }, /* 4b: 0110 0100 0100 1011 xxxx xxxx */ + {illegal,0 }, /* 4c: 0110 0100 0100 1100 xxxx xxxx */ + {ONI,"PF,%b" }, /* 4d: 0110 0100 0100 1101 xxxx xxxx */ + {ONI,"MKH,%b" }, /* 4e: 0110 0100 0100 1110 xxxx xxxx */ + {ONI,"MKL,%b" }, /* 4f: 0110 0100 0100 1111 xxxx xxxx */ + + {ACI,"PA,%b" }, /* 50: 0110 0100 0101 0000 xxxx xxxx */ + {ACI,"PB,%b" }, /* 51: 0110 0100 0101 0001 xxxx xxxx */ + {ACI,"PC,%b" }, /* 52: 0110 0100 0101 0010 xxxx xxxx */ + {ACI,"PD,%b" }, /* 53: 0110 0100 0101 0011 xxxx xxxx */ + {illegal,0 }, /* 54: 0110 0100 0101 0100 xxxx xxxx */ + {ACI,"PF,%b" }, /* 55: 0110 0100 0101 0101 xxxx xxxx */ + {ACI,"MKH,%b" }, /* 56: 0110 0100 0101 0110 xxxx xxxx */ + {ACI,"MKL,%b" }, /* 57: 0110 0100 0101 0111 xxxx xxxx */ + {OFFI,"PA,%b" }, /* 58: 0110 0100 0101 1000 xxxx xxxx */ + {OFFI,"PB,%b" }, /* 59: 0110 0100 0101 1001 xxxx xxxx */ + {OFFI,"PC,%b" }, /* 5a: 0110 0100 0101 1010 xxxx xxxx */ + {OFFI,"PD,%b" }, /* 5b: 0110 0100 0101 1011 xxxx xxxx */ + {illegal,0 }, /* 5c: 0110 0100 0101 1100 xxxx xxxx */ + {OFFI,"PF,%b" }, /* 5d: 0110 0100 0101 1101 xxxx xxxx */ + {OFFI,"MKH,%b" }, /* 5e: 0110 0100 0101 1110 xxxx xxxx */ + {OFFI,"MKL,%b" }, /* 5f: 0110 0100 0101 1111 xxxx xxxx */ + + {SUI,"PA,%b" }, /* 60: 0110 0100 0110 0000 xxxx xxxx */ + {SUI,"PB,%b" }, /* 61: 0110 0100 0110 0001 xxxx xxxx */ + {SUI,"PC,%b" }, /* 62: 0110 0100 0110 0010 xxxx xxxx */ + {SUI,"PD,%b" }, /* 63: 0110 0100 0110 0011 xxxx xxxx */ + {illegal,0 }, /* 64: 0110 0100 0110 0100 xxxx xxxx */ + {SUI,"PF,%b" }, /* 65: 0110 0100 0110 0101 xxxx xxxx */ + {SUI,"MKH,%b" }, /* 66: 0110 0100 0110 0110 xxxx xxxx */ + {SUI,"MKL,%b" }, /* 67: 0110 0100 0110 0111 xxxx xxxx */ + {NEI,"PA,%b" }, /* 68: 0110 0100 0110 1000 xxxx xxxx */ + {NEI,"PB,%b" }, /* 69: 0110 0100 0110 1001 xxxx xxxx */ + {NEI,"PC,%b" }, /* 6a: 0110 0100 0110 1010 xxxx xxxx */ + {NEI,"PD,%b" }, /* 6b: 0110 0100 0110 1011 xxxx xxxx */ + {illegal,0 }, /* 6c: 0110 0100 0110 1100 xxxx xxxx */ + {NEI,"PF,%b" }, /* 6d: 0110 0100 0110 1101 xxxx xxxx */ + {NEI,"MKH,%b" }, /* 6e: 0110 0100 0110 1110 xxxx xxxx */ + {NEI,"MKL,%b" }, /* 6f: 0110 0100 0110 1111 xxxx xxxx */ + + {SBI,"PA,%b" }, /* 70: 0110 0100 0111 0000 xxxx xxxx */ + {SBI,"PB,%b" }, /* 71: 0110 0100 0111 0001 xxxx xxxx */ + {SBI,"PC,%b" }, /* 72: 0110 0100 0111 0010 xxxx xxxx */ + {SBI,"PD,%b" }, /* 73: 0110 0100 0111 0011 xxxx xxxx */ + {illegal,0 }, /* 74: 0110 0100 0111 0100 xxxx xxxx */ + {SBI,"PF,%b" }, /* 75: 0110 0100 0111 0101 xxxx xxxx */ + {SBI,"MKH,%b" }, /* 76: 0110 0100 0111 0110 xxxx xxxx */ + {SBI,"MKL,%b" }, /* 77: 0110 0100 0111 0111 xxxx xxxx */ + {EQI,"PA,%b" }, /* 78: 0110 0100 0111 1000 xxxx xxxx */ + {EQI,"PB,%b" }, /* 79: 0110 0100 0111 1001 xxxx xxxx */ + {EQI,"PC,%b" }, /* 7a: 0110 0100 0111 1010 xxxx xxxx */ + {EQI,"PD,%b" }, /* 7b: 0110 0100 0111 1011 xxxx xxxx */ + {illegal,0 }, /* 7c: 0110 0100 0111 1100 xxxx xxxx */ + {EQI,"PF,%b" }, /* 7d: 0110 0100 0111 1101 xxxx xxxx */ + {EQI,"MKH,%b" }, /* 7e: 0110 0100 0111 1110 xxxx xxxx */ + {EQI,"MKL,%b" }, /* 7f: 0110 0100 0111 1111 xxxx xxxx */ + + {MVI,"ANM,%b" }, /* 80: 0110 0100 1000 0000 xxxx xxxx */ /* 7810 */ + {MVI,"SMH,%b" }, /* 81: 0110 0100 1000 0001 xxxx xxxx */ + {illegal,0 }, /* 82: 0110 0100 1000 0010 xxxx xxxx */ + {MVI,"EOM,%b" }, /* 83: 0110 0100 1000 0011 xxxx xxxx */ + {illegal,0 }, /* 84: 0110 0100 1000 0100 xxxx xxxx */ + {MVI,"TMM,%b" }, /* 85: 0110 0100 1000 0101 xxxx xxxx */ + {illegal,0 }, /* 86: 0110 0100 1000 0110 xxxx xxxx */ + {illegal,0 }, /* 87: 0110 0100 1000 0111 xxxx xxxx */ + {ANI,"ANM,%b" }, /* 88: 0110 0100 1000 1000 xxxx xxxx */ /* 7810 */ + {ANI,"SMH,%b" }, /* 89: 0110 0100 1000 1001 xxxx xxxx */ + {illegal,0 }, /* 8a: 0110 0100 1000 1010 xxxx xxxx */ + {ANI,"EOM,%b" }, /* 8b: 0110 0100 1000 1011 xxxx xxxx */ + {illegal,0 }, /* 8c: 0110 0100 1000 1100 xxxx xxxx */ + {ANI,"TMM,%b" }, /* 8d: 0110 0100 1000 1101 xxxx xxxx */ + {illegal,0 }, /* 8e: 0110 0100 1000 1110 xxxx xxxx */ + {illegal,0 }, /* 8f: 0110 0100 1000 1111 xxxx xxxx */ + + {XRI,"ANM,%b" }, /* 90: 0110 0100 1001 0000 xxxx xxxx */ /* 7810 */ + {XRI,"SMH,%b" }, /* 91: 0110 0100 1001 0001 xxxx xxxx */ + {illegal,0 }, /* 92: 0110 0100 1001 0010 xxxx xxxx */ + {XRI,"EOM,%b" }, /* 93: 0110 0100 1001 0011 xxxx xxxx */ + {illegal,0 }, /* 94: 0110 0100 1001 0100 xxxx xxxx */ + {XRI,"TMM,%b" }, /* 95: 0110 0100 1001 0101 xxxx xxxx */ + {illegal,0 }, /* 96: 0110 0100 1001 0110 xxxx xxxx */ + {illegal,0 }, /* 97: 0110 0100 1001 0111 xxxx xxxx */ + {ORI,"ANM,%b" }, /* 98: 0110 0100 1001 1000 xxxx xxxx */ /* 7810 */ + {ORI,"SMH,%b" }, /* 99: 0110 0100 1001 1001 xxxx xxxx */ + {illegal,0 }, /* 9a: 0110 0100 1001 1010 xxxx xxxx */ + {ORI,"EOM,%b" }, /* 9b: 0110 0100 1001 1011 xxxx xxxx */ + {illegal,0 }, /* 9c: 0110 0100 1001 1100 xxxx xxxx */ + {ORI,"TMM,%b" }, /* 9d: 0110 0100 1001 1101 xxxx xxxx */ + {illegal,0 }, /* 9e: 0110 0100 1001 1110 xxxx xxxx */ + {illegal,0 }, /* 9f: 0110 0100 1001 1111 xxxx xxxx */ + + {ADINC,"ANM,%b" }, /* a0: 0110 0100 1010 0000 xxxx xxxx */ /* 7810 */ + {ADINC,"SMH,%b" }, /* a1: 0110 0100 1010 0001 xxxx xxxx */ + {illegal,0 }, /* a2: 0110 0100 1010 0010 xxxx xxxx */ + {ADINC,"EOM,%b" }, /* a3: 0110 0100 1010 0011 xxxx xxxx */ + {illegal,0 }, /* a4: 0110 0100 1010 0100 xxxx xxxx */ + {ADINC,"TMM,%b" }, /* a5: 0110 0100 1010 0101 xxxx xxxx */ + {illegal,0 }, /* a6: 0110 0100 1010 0110 xxxx xxxx */ + {illegal,0 }, /* a7: 0110 0100 1010 0111 xxxx xxxx */ + {GTI,"ANM,%b" }, /* a8: 0110 0100 1010 1000 xxxx xxxx */ /* 7810 */ + {GTI,"SMH,%b" }, /* a9: 0110 0100 1010 1001 xxxx xxxx */ + {illegal,0 }, /* aa: 0110 0100 1010 1010 xxxx xxxx */ + {GTI,"EOM,%b" }, /* ab: 0110 0100 1010 1011 xxxx xxxx */ + {illegal,0 }, /* ac: 0110 0100 1010 1100 xxxx xxxx */ + {GTI,"TMM,%b" }, /* ad: 0110 0100 1010 1101 xxxx xxxx */ + {illegal,0 }, /* ae: 0110 0100 1010 1110 xxxx xxxx */ + {illegal,0 }, /* af: 0110 0100 1010 1111 xxxx xxxx */ + + {SUINB,"ANM,%b" }, /* b0: 0110 0100 1011 0000 xxxx xxxx */ /* 7810 */ + {SUINB,"SMH,%b" }, /* b1: 0110 0100 1011 0001 xxxx xxxx */ + {illegal,0 }, /* b2: 0110 0100 1011 0010 xxxx xxxx */ + {SUINB,"EOM,%b" }, /* b3: 0110 0100 1011 0011 xxxx xxxx */ + {illegal,0 }, /* b4: 0110 0100 1011 0100 xxxx xxxx */ + {SUINB,"TMM,%b" }, /* b5: 0110 0100 1011 0101 xxxx xxxx */ + {illegal,0 }, /* b6: 0110 0100 1011 0110 xxxx xxxx */ + {illegal,0 }, /* b7: 0110 0100 1011 0111 xxxx xxxx */ + {LTI,"ANM,%b" }, /* b8: 0110 0100 1011 1000 xxxx xxxx */ /* 7810 */ + {LTI,"SMH,%b" }, /* b9: 0110 0100 1011 1001 xxxx xxxx */ + {illegal,0 }, /* ba: 0110 0100 1011 1010 xxxx xxxx */ + {LTI,"EOM,%b" }, /* bb: 0110 0100 1011 1011 xxxx xxxx */ + {illegal,0 }, /* bc: 0110 0100 1011 1100 xxxx xxxx */ + {LTI,"TMM,%b" }, /* bd: 0110 0100 1011 1101 xxxx xxxx */ + {illegal,0 }, /* be: 0110 0100 1011 1110 xxxx xxxx */ + {illegal,0 }, /* bf: 0110 0100 1011 1111 xxxx xxxx */ + + {ADI,"ANM,%b" }, /* c0: 0110 0100 1100 0000 xxxx xxxx */ /* 7810 */ + {ADI,"SMH,%b" }, /* c1: 0110 0100 1100 0001 xxxx xxxx */ + {illegal,0 }, /* c2: 0110 0100 1100 0010 xxxx xxxx */ + {ADI,"EOM,%b" }, /* c3: 0110 0100 1100 0011 xxxx xxxx */ + {illegal,0 }, /* c4: 0110 0100 1100 0100 xxxx xxxx */ + {ADI,"TMM,%b" }, /* c5: 0110 0100 1100 0101 xxxx xxxx */ + {illegal,0 }, /* c6: 0110 0100 1100 0110 xxxx xxxx */ + {illegal,0 }, /* c7: 0110 0100 1100 0111 xxxx xxxx */ + {ONI,"ANM,%b" }, /* c8: 0110 0100 1100 1000 xxxx xxxx */ /* 7810 */ + {ONI,"SMH,%b" }, /* c9: 0110 0100 1100 1001 xxxx xxxx */ + {illegal,0 }, /* ca: 0110 0100 1100 1010 xxxx xxxx */ + {ONI,"EOM,%b" }, /* cb: 0110 0100 1100 1011 xxxx xxxx */ + {illegal,0 }, /* cc: 0110 0100 1100 1100 xxxx xxxx */ + {ONI,"TMM,%b" }, /* cd: 0110 0100 1100 1101 xxxx xxxx */ + {illegal,0 }, /* ce: 0110 0100 1100 1110 xxxx xxxx */ + {illegal,0 }, /* cf: 0110 0100 1100 1111 xxxx xxxx */ + + {ACI,"ANM,%b" }, /* d0: 0110 0100 1101 0000 xxxx xxxx */ /* 7810 */ + {ACI,"SMH,%b" }, /* d1: 0110 0100 1101 0001 xxxx xxxx */ + {illegal,0 }, /* d2: 0110 0100 1101 0010 xxxx xxxx */ + {ACI,"EOM,%b" }, /* d3: 0110 0100 1101 0011 xxxx xxxx */ + {illegal,0 }, /* d4: 0110 0100 1101 0100 xxxx xxxx */ + {ACI,"TMM,%b" }, /* d5: 0110 0100 1101 0101 xxxx xxxx */ + {illegal,0 }, /* d6: 0110 0100 1101 0110 xxxx xxxx */ + {illegal,0 }, /* d7: 0110 0100 1101 0111 xxxx xxxx */ + {OFFI,"ANM,%b" }, /* d8: 0110 0100 1101 1000 xxxx xxxx */ /* 7810 */ + {OFFI,"SMH,%b" }, /* d9: 0110 0100 1101 1001 xxxx xxxx */ + {illegal,0 }, /* da: 0110 0100 1101 1010 xxxx xxxx */ + {OFFI,"EOM,%b" }, /* db: 0110 0100 1101 1011 xxxx xxxx */ + {illegal,0 }, /* dc: 0110 0100 1101 1100 xxxx xxxx */ + {OFFI,"TMM,%b" }, /* dd: 0110 0100 1101 1101 xxxx xxxx */ + {illegal,0 }, /* de: 0110 0100 1101 1110 xxxx xxxx */ + {illegal,0 }, /* df: 0110 0100 1101 1111 xxxx xxxx */ + + {SUI,"ANM,%b" }, /* e0: 0110 0100 1110 0000 xxxx xxxx */ /* 7810 */ + {SUI,"SMH,%b" }, /* e1: 0110 0100 1110 0001 xxxx xxxx */ + {illegal,0 }, /* e2: 0110 0100 1110 0010 xxxx xxxx */ + {SUI,"EOM,%b" }, /* e3: 0110 0100 1110 0011 xxxx xxxx */ + {illegal,0 }, /* e4: 0110 0100 1110 0100 xxxx xxxx */ + {SUI,"TMM,%b" }, /* e5: 0110 0100 1110 0101 xxxx xxxx */ + {illegal,0 }, /* e6: 0110 0100 1110 0110 xxxx xxxx */ + {illegal,0 }, /* e7: 0110 0100 1110 0111 xxxx xxxx */ + {NEI,"ANM,%b" }, /* e8: 0110 0100 1110 1000 xxxx xxxx */ /* 7810 */ + {NEI,"SMH,%b" }, /* e9: 0110 0100 1110 1001 xxxx xxxx */ + {illegal,0 }, /* ea: 0110 0100 1110 1010 xxxx xxxx */ + {NEI,"EOM,%b" }, /* eb: 0110 0100 1110 1011 xxxx xxxx */ + {illegal,0 }, /* ec: 0110 0100 1110 1100 xxxx xxxx */ + {NEI,"TMM,%b" }, /* ed: 0110 0100 1110 1101 xxxx xxxx */ + {illegal,0 }, /* ee: 0110 0100 1110 1110 xxxx xxxx */ + {illegal,0 }, /* ef: 0110 0100 1110 1111 xxxx xxxx */ + + {SBI,"ANM,%b" }, /* f0: 0110 0100 1111 0000 xxxx xxxx */ /* 7810 */ + {SBI,"SMH,%b" }, /* f1: 0110 0100 1111 0001 xxxx xxxx */ + {illegal,0 }, /* f2: 0110 0100 1111 0010 xxxx xxxx */ + {SBI,"EOM,%b" }, /* f3: 0110 0100 1111 0011 xxxx xxxx */ + {illegal,0 }, /* f4: 0110 0100 1111 0100 xxxx xxxx */ + {SBI,"TMM,%b" }, /* f5: 0110 0100 1111 0101 xxxx xxxx */ + {illegal,0 }, /* f6: 0110 0100 1111 0110 xxxx xxxx */ + {illegal,0 }, /* f7: 0110 0100 1111 0111 xxxx xxxx */ + {EQI,"ANM,%b" }, /* f8: 0110 0100 1111 1000 xxxx xxxx */ /* 7810 */ + {EQI,"SMH,%b" }, /* f9: 0110 0100 1111 1001 xxxx xxxx */ + {illegal,0 }, /* fa: 0110 0100 1111 1010 xxxx xxxx */ + {EQI,"EOM,%b" }, /* fb: 0110 0100 1111 1011 xxxx xxxx */ + {illegal,0 }, /* fc: 0110 0100 1111 1100 xxxx xxxx */ + {EQI,"TMM,%b" }, /* fd: 0110 0100 1111 1101 xxxx xxxx */ + {illegal,0 }, /* fe: 0110 0100 1111 1110 xxxx xxxx */ + {illegal,0 } /* ff: 0110 0100 1111 1111 xxxx xxxx */ +}; + +static const struct dasm_s dasm64_7807[256] = +{ + {MVI,"PA,%b" }, /* 00: 0110 0100 0000 0000 xxxx xxxx */ + {MVI,"PB,%b" }, /* 01: 0110 0100 0000 0001 xxxx xxxx */ + {MVI,"PC,%b" }, /* 02: 0110 0100 0000 0010 xxxx xxxx */ + {MVI,"PD,%b" }, /* 03: 0110 0100 0000 0011 xxxx xxxx */ + {illegal,0 }, /* 04: 0110 0100 0000 0100 xxxx xxxx */ + {MVI,"PF,%b" }, /* 05: 0110 0100 0000 0101 xxxx xxxx */ + {MVI,"MKH,%b" }, /* 06: 0110 0100 0000 0110 xxxx xxxx */ + {MVI,"MKL,%b" }, /* 07: 0110 0100 0000 0111 xxxx xxxx */ + {ANI,"PA,%b" }, /* 08: 0110 0100 0000 1000 xxxx xxxx */ + {ANI,"PB,%b" }, /* 09: 0110 0100 0000 1001 xxxx xxxx */ + {ANI,"PC,%b" }, /* 0a: 0110 0100 0000 1010 xxxx xxxx */ + {ANI,"PD,%b" }, /* 0b: 0110 0100 0000 1011 xxxx xxxx */ + {illegal,0 }, /* 0c: 0110 0100 0000 1100 xxxx xxxx */ + {ANI,"PF,%b" }, /* 0d: 0110 0100 0000 1101 xxxx xxxx */ + {ANI,"MKH,%b" }, /* 0e: 0110 0100 0000 1110 xxxx xxxx */ + {ANI,"MKL,%b" }, /* 0f: 0110 0100 0000 1111 xxxx xxxx */ + + {XRI,"PA,%b" }, /* 10: 0110 0100 0001 0000 xxxx xxxx */ + {XRI,"PB,%b" }, /* 11: 0110 0100 0001 0001 xxxx xxxx */ + {XRI,"PC,%b" }, /* 12: 0110 0100 0001 0010 xxxx xxxx */ + {XRI,"PD,%b" }, /* 13: 0110 0100 0001 0011 xxxx xxxx */ + {illegal,0 }, /* 14: 0110 0100 0001 0100 xxxx xxxx */ + {XRI,"PF,%b" }, /* 15: 0110 0100 0001 0101 xxxx xxxx */ + {XRI,"MKH,%b" }, /* 16: 0110 0100 0001 0110 xxxx xxxx */ + {XRI,"MKL,%b" }, /* 17: 0110 0100 0001 0111 xxxx xxxx */ + {ORI,"PA,%b" }, /* 18: 0110 0100 0001 1000 xxxx xxxx */ + {ORI,"PB,%b" }, /* 19: 0110 0100 0001 1001 xxxx xxxx */ + {ORI,"PC,%b" }, /* 1a: 0110 0100 0001 1010 xxxx xxxx */ + {ORI,"PD,%b" }, /* 1b: 0110 0100 0001 1011 xxxx xxxx */ + {illegal,0 }, /* 1c: 0110 0100 0001 1100 xxxx xxxx */ + {ORI,"PF,%b" }, /* 1d: 0110 0100 0001 1101 xxxx xxxx */ + {ORI,"MKH,%b" }, /* 1e: 0110 0100 0001 1110 xxxx xxxx */ + {ORI,"MKL,%b" }, /* 1f: 0110 0100 0001 1111 xxxx xxxx */ + + {ADINC,"PA,%b" }, /* 20: 0110 0100 0010 0000 xxxx xxxx */ + {ADINC,"PB,%b" }, /* 21: 0110 0100 0010 0001 xxxx xxxx */ + {ADINC,"PC,%b" }, /* 22: 0110 0100 0010 0010 xxxx xxxx */ + {ADINC,"PD,%b" }, /* 23: 0110 0100 0010 0011 xxxx xxxx */ + {illegal,0 }, /* 24: 0110 0100 0010 0100 xxxx xxxx */ + {ADINC,"PF,%b" }, /* 25: 0110 0100 0010 0101 xxxx xxxx */ + {ADINC,"MKH,%b" }, /* 26: 0110 0100 0010 0110 xxxx xxxx */ + {ADINC,"MKL,%b" }, /* 27: 0110 0100 0010 0111 xxxx xxxx */ + {GTI,"PA,%b" }, /* 28: 0110 0100 0010 1000 xxxx xxxx */ + {GTI,"PB,%b" }, /* 29: 0110 0100 0010 1001 xxxx xxxx */ + {GTI,"PC,%b" }, /* 2a: 0110 0100 0010 1010 xxxx xxxx */ + {GTI,"PD,%b" }, /* 2b: 0110 0100 0010 1011 xxxx xxxx */ + {illegal,0 }, /* 2c: 0110 0100 0010 1100 xxxx xxxx */ + {GTI,"PF,%b" }, /* 2d: 0110 0100 0010 1101 xxxx xxxx */ + {GTI,"MKH,%b" }, /* 2e: 0110 0100 0010 1110 xxxx xxxx */ + {GTI,"MKL,%b" }, /* 2f: 0110 0100 0010 1111 xxxx xxxx */ + + {SUINB,"PA,%b" }, /* 30: 0110 0100 0011 0000 xxxx xxxx */ + {SUINB,"PB,%b" }, /* 31: 0110 0100 0011 0001 xxxx xxxx */ + {SUINB,"PC,%b" }, /* 32: 0110 0100 0011 0010 xxxx xxxx */ + {SUINB,"PD,%b" }, /* 33: 0110 0100 0011 0011 xxxx xxxx */ + {illegal,0 }, /* 34: 0110 0100 0011 0100 xxxx xxxx */ + {SUINB,"PF,%b" }, /* 35: 0110 0100 0011 0101 xxxx xxxx */ + {SUINB,"MKH,%b" }, /* 36: 0110 0100 0011 0110 xxxx xxxx */ + {SUINB,"MKL,%b" }, /* 37: 0110 0100 0011 0111 xxxx xxxx */ + {LTI,"PA,%b" }, /* 38: 0110 0100 0011 1000 xxxx xxxx */ + {LTI,"PB,%b" }, /* 39: 0110 0100 0011 1001 xxxx xxxx */ + {LTI,"PC,%b" }, /* 3a: 0110 0100 0011 1010 xxxx xxxx */ + {LTI,"PD,%b" }, /* 3b: 0110 0100 0011 1011 xxxx xxxx */ + {illegal,0 }, /* 3c: 0110 0100 0011 1100 xxxx xxxx */ + {LTI,"PF,%b" }, /* 3d: 0110 0100 0011 1101 xxxx xxxx */ + {LTI,"MKH,%b" }, /* 3e: 0110 0100 0011 1110 xxxx xxxx */ + {LTI,"MKL,%b" }, /* 3f: 0110 0100 0011 1111 xxxx xxxx */ + + {ADI,"PA,%b" }, /* 40: 0110 0100 0100 0000 xxxx xxxx */ + {ADI,"PB,%b" }, /* 41: 0110 0100 0100 0001 xxxx xxxx */ + {ADI,"PC,%b" }, /* 42: 0110 0100 0100 0010 xxxx xxxx */ + {ADI,"PD,%b" }, /* 43: 0110 0100 0100 0011 xxxx xxxx */ + {illegal,0 }, /* 44: 0110 0100 0100 0100 xxxx xxxx */ + {ADI,"PF,%b" }, /* 45: 0110 0100 0100 0101 xxxx xxxx */ + {ADI,"MKH,%b" }, /* 46: 0110 0100 0100 0110 xxxx xxxx */ + {ADI,"MKL,%b" }, /* 47: 0110 0100 0100 0111 xxxx xxxx */ + {ONI,"PA,%b" }, /* 48: 0110 0100 0100 1000 xxxx xxxx */ + {ONI,"PB,%b" }, /* 49: 0110 0100 0100 1001 xxxx xxxx */ + {ONI,"PC,%b" }, /* 4a: 0110 0100 0100 1010 xxxx xxxx */ + {ONI,"PD,%b" }, /* 4b: 0110 0100 0100 1011 xxxx xxxx */ + {illegal,0 }, /* 4c: 0110 0100 0100 1100 xxxx xxxx */ + {ONI,"PF,%b" }, /* 4d: 0110 0100 0100 1101 xxxx xxxx */ + {ONI,"MKH,%b" }, /* 4e: 0110 0100 0100 1110 xxxx xxxx */ + {ONI,"MKL,%b" }, /* 4f: 0110 0100 0100 1111 xxxx xxxx */ + + {ACI,"PA,%b" }, /* 50: 0110 0100 0101 0000 xxxx xxxx */ + {ACI,"PB,%b" }, /* 51: 0110 0100 0101 0001 xxxx xxxx */ + {ACI,"PC,%b" }, /* 52: 0110 0100 0101 0010 xxxx xxxx */ + {ACI,"PD,%b" }, /* 53: 0110 0100 0101 0011 xxxx xxxx */ + {illegal,0 }, /* 54: 0110 0100 0101 0100 xxxx xxxx */ + {ACI,"PF,%b" }, /* 55: 0110 0100 0101 0101 xxxx xxxx */ + {ACI,"MKH,%b" }, /* 56: 0110 0100 0101 0110 xxxx xxxx */ + {ACI,"MKL,%b" }, /* 57: 0110 0100 0101 0111 xxxx xxxx */ + {OFFI,"PA,%b" }, /* 58: 0110 0100 0101 1000 xxxx xxxx */ + {OFFI,"PB,%b" }, /* 59: 0110 0100 0101 1001 xxxx xxxx */ + {OFFI,"PC,%b" }, /* 5a: 0110 0100 0101 1010 xxxx xxxx */ + {OFFI,"PD,%b" }, /* 5b: 0110 0100 0101 1011 xxxx xxxx */ + {illegal,0 }, /* 5c: 0110 0100 0101 1100 xxxx xxxx */ + {OFFI,"PF,%b" }, /* 5d: 0110 0100 0101 1101 xxxx xxxx */ + {OFFI,"MKH,%b" }, /* 5e: 0110 0100 0101 1110 xxxx xxxx */ + {OFFI,"MKL,%b" }, /* 5f: 0110 0100 0101 1111 xxxx xxxx */ + + {SUI,"PA,%b" }, /* 60: 0110 0100 0110 0000 xxxx xxxx */ + {SUI,"PB,%b" }, /* 61: 0110 0100 0110 0001 xxxx xxxx */ + {SUI,"PC,%b" }, /* 62: 0110 0100 0110 0010 xxxx xxxx */ + {SUI,"PD,%b" }, /* 63: 0110 0100 0110 0011 xxxx xxxx */ + {illegal,0 }, /* 64: 0110 0100 0110 0100 xxxx xxxx */ + {SUI,"PF,%b" }, /* 65: 0110 0100 0110 0101 xxxx xxxx */ + {SUI,"MKH,%b" }, /* 66: 0110 0100 0110 0110 xxxx xxxx */ + {SUI,"MKL,%b" }, /* 67: 0110 0100 0110 0111 xxxx xxxx */ + {NEI,"PA,%b" }, /* 68: 0110 0100 0110 1000 xxxx xxxx */ + {NEI,"PB,%b" }, /* 69: 0110 0100 0110 1001 xxxx xxxx */ + {NEI,"PC,%b" }, /* 6a: 0110 0100 0110 1010 xxxx xxxx */ + {NEI,"PD,%b" }, /* 6b: 0110 0100 0110 1011 xxxx xxxx */ + {illegal,0 }, /* 6c: 0110 0100 0110 1100 xxxx xxxx */ + {NEI,"PF,%b" }, /* 6d: 0110 0100 0110 1101 xxxx xxxx */ + {NEI,"MKH,%b" }, /* 6e: 0110 0100 0110 1110 xxxx xxxx */ + {NEI,"MKL,%b" }, /* 6f: 0110 0100 0110 1111 xxxx xxxx */ + + {SBI,"PA,%b" }, /* 70: 0110 0100 0111 0000 xxxx xxxx */ + {SBI,"PB,%b" }, /* 71: 0110 0100 0111 0001 xxxx xxxx */ + {SBI,"PC,%b" }, /* 72: 0110 0100 0111 0010 xxxx xxxx */ + {SBI,"PD,%b" }, /* 73: 0110 0100 0111 0011 xxxx xxxx */ + {illegal,0 }, /* 74: 0110 0100 0111 0100 xxxx xxxx */ + {SBI,"PF,%b" }, /* 75: 0110 0100 0111 0101 xxxx xxxx */ + {SBI,"MKH,%b" }, /* 76: 0110 0100 0111 0110 xxxx xxxx */ + {SBI,"MKL,%b" }, /* 77: 0110 0100 0111 0111 xxxx xxxx */ + {EQI,"PA,%b" }, /* 78: 0110 0100 0111 1000 xxxx xxxx */ + {EQI,"PB,%b" }, /* 79: 0110 0100 0111 1001 xxxx xxxx */ + {EQI,"PC,%b" }, /* 7a: 0110 0100 0111 1010 xxxx xxxx */ + {EQI,"PD,%b" }, /* 7b: 0110 0100 0111 1011 xxxx xxxx */ + {illegal,0 }, /* 7c: 0110 0100 0111 1100 xxxx xxxx */ + {EQI,"PF,%b" }, /* 7d: 0110 0100 0111 1101 xxxx xxxx */ + {EQI,"MKH,%b" }, /* 7e: 0110 0100 0111 1110 xxxx xxxx */ + {EQI,"MKL,%b" }, /* 7f: 0110 0100 0111 1111 xxxx xxxx */ + + {illegal,0 }, /* 80: 0110 0100 1000 0000 xxxx xxxx */ + {MVI,"SMH,%b" }, /* 81: 0110 0100 1000 0001 xxxx xxxx */ + {illegal,0 }, /* 82: 0110 0100 1000 0010 xxxx xxxx */ + {MVI,"EOM,%b" }, /* 83: 0110 0100 1000 0011 xxxx xxxx */ + {illegal,0 }, /* 84: 0110 0100 1000 0100 xxxx xxxx */ + {MVI,"TMM,%b" }, /* 85: 0110 0100 1000 0101 xxxx xxxx */ + {illegal,0 }, /* 86: 0110 0100 1000 0110 xxxx xxxx */ + {illegal,0 }, /* 87: 0110 0100 1000 0111 xxxx xxxx */ + {illegal,0 }, /* 88: 0110 0100 1000 1000 xxxx xxxx */ + {ANI,"SMH,%b" }, /* 89: 0110 0100 1000 1001 xxxx xxxx */ + {illegal,0 }, /* 8a: 0110 0100 1000 1010 xxxx xxxx */ + {ANI,"EOM,%b" }, /* 8b: 0110 0100 1000 1011 xxxx xxxx */ + {illegal,0 }, /* 8c: 0110 0100 1000 1100 xxxx xxxx */ + {ANI,"TMM,%b" }, /* 8d: 0110 0100 1000 1101 xxxx xxxx */ + {illegal,0 }, /* 8e: 0110 0100 1000 1110 xxxx xxxx */ + {illegal,0 }, /* 8f: 0110 0100 1000 1111 xxxx xxxx */ + + {illegal,0 }, /* 90: 0110 0100 1001 0000 xxxx xxxx */ + {XRI,"SMH,%b" }, /* 91: 0110 0100 1001 0001 xxxx xxxx */ + {illegal,0 }, /* 92: 0110 0100 1001 0010 xxxx xxxx */ + {XRI,"EOM,%b" }, /* 93: 0110 0100 1001 0011 xxxx xxxx */ + {illegal,0 }, /* 94: 0110 0100 1001 0100 xxxx xxxx */ + {XRI,"TMM,%b" }, /* 95: 0110 0100 1001 0101 xxxx xxxx */ + {illegal,0 }, /* 96: 0110 0100 1001 0110 xxxx xxxx */ + {illegal,0 }, /* 97: 0110 0100 1001 0111 xxxx xxxx */ + {illegal,0 }, /* 98: 0110 0100 1001 1000 xxxx xxxx */ + {ORI,"SMH,%b" }, /* 99: 0110 0100 1001 1001 xxxx xxxx */ + {illegal,0 }, /* 9a: 0110 0100 1001 1010 xxxx xxxx */ + {ORI,"EOM,%b" }, /* 9b: 0110 0100 1001 1011 xxxx xxxx */ + {illegal,0 }, /* 9c: 0110 0100 1001 1100 xxxx xxxx */ + {ORI,"TMM,%b" }, /* 9d: 0110 0100 1001 1101 xxxx xxxx */ + {illegal,0 }, /* 9e: 0110 0100 1001 1110 xxxx xxxx */ + {illegal,0 }, /* 9f: 0110 0100 1001 1111 xxxx xxxx */ + + {illegal,0 }, /* a0: 0110 0100 1010 0000 xxxx xxxx */ + {ADINC,"SMH,%b" }, /* a1: 0110 0100 1010 0001 xxxx xxxx */ + {illegal,0 }, /* a2: 0110 0100 1010 0010 xxxx xxxx */ + {ADINC,"EOM,%b" }, /* a3: 0110 0100 1010 0011 xxxx xxxx */ + {illegal,0 }, /* a4: 0110 0100 1010 0100 xxxx xxxx */ + {ADINC,"TMM,%b" }, /* a5: 0110 0100 1010 0101 xxxx xxxx */ + {illegal,0 }, /* a6: 0110 0100 1010 0110 xxxx xxxx */ + {illegal,0 }, /* a7: 0110 0100 1010 0111 xxxx xxxx */ + {illegal,0 }, /* a8: 0110 0100 1010 1000 xxxx xxxx */ + {GTI,"SMH,%b" }, /* a9: 0110 0100 1010 1001 xxxx xxxx */ + {illegal,0 }, /* aa: 0110 0100 1010 1010 xxxx xxxx */ + {GTI,"EOM,%b" }, /* ab: 0110 0100 1010 1011 xxxx xxxx */ + {illegal,0 }, /* ac: 0110 0100 1010 1100 xxxx xxxx */ + {GTI,"TMM,%b" }, /* ad: 0110 0100 1010 1101 xxxx xxxx */ + {GTI,"PT,%b" }, /* ae: 0110 0100 1010 1110 xxxx xxxx */ + {illegal,0 }, /* af: 0110 0100 1010 1111 xxxx xxxx */ + + {illegal,0 }, /* b0: 0110 0100 1011 0000 xxxx xxxx */ + {SUINB,"SMH,%b" }, /* b1: 0110 0100 1011 0001 xxxx xxxx */ + {illegal,0 }, /* b2: 0110 0100 1011 0010 xxxx xxxx */ + {SUINB,"EOM,%b" }, /* b3: 0110 0100 1011 0011 xxxx xxxx */ + {illegal,0 }, /* b4: 0110 0100 1011 0100 xxxx xxxx */ + {SUINB,"TMM,%b" }, /* b5: 0110 0100 1011 0101 xxxx xxxx */ + {illegal,0 }, /* b6: 0110 0100 1011 0110 xxxx xxxx */ + {illegal,0 }, /* b7: 0110 0100 1011 0111 xxxx xxxx */ + {illegal,0 }, /* b8: 0110 0100 1011 1000 xxxx xxxx */ + {LTI,"SMH,%b" }, /* b9: 0110 0100 1011 1001 xxxx xxxx */ + {illegal,0 }, /* ba: 0110 0100 1011 1010 xxxx xxxx */ + {LTI,"EOM,%b" }, /* bb: 0110 0100 1011 1011 xxxx xxxx */ + {illegal,0 }, /* bc: 0110 0100 1011 1100 xxxx xxxx */ + {LTI,"TMM,%b" }, /* bd: 0110 0100 1011 1101 xxxx xxxx */ + {LTI,"PT,%b" }, /* be: 0110 0100 1011 1110 xxxx xxxx */ + {illegal,0 }, /* bf: 0110 0100 1011 1111 xxxx xxxx */ + + {illegal,0 }, /* c0: 0110 0100 1100 0000 xxxx xxxx */ + {ADI,"SMH,%b" }, /* c1: 0110 0100 1100 0001 xxxx xxxx */ + {illegal,0 }, /* c2: 0110 0100 1100 0010 xxxx xxxx */ + {ADI,"EOM,%b" }, /* c3: 0110 0100 1100 0011 xxxx xxxx */ + {illegal,0 }, /* c4: 0110 0100 1100 0100 xxxx xxxx */ + {ADI,"TMM,%b" }, /* c5: 0110 0100 1100 0101 xxxx xxxx */ + {illegal,0 }, /* c6: 0110 0100 1100 0110 xxxx xxxx */ + {illegal,0 }, /* c7: 0110 0100 1100 0111 xxxx xxxx */ + {illegal,0 }, /* c8: 0110 0100 1100 1000 xxxx xxxx */ + {ONI,"SMH,%b" }, /* c9: 0110 0100 1100 1001 xxxx xxxx */ + {illegal,0 }, /* ca: 0110 0100 1100 1010 xxxx xxxx */ + {ONI,"EOM,%b" }, /* cb: 0110 0100 1100 1011 xxxx xxxx */ + {illegal,0 }, /* cc: 0110 0100 1100 1100 xxxx xxxx */ + {ONI,"TMM,%b" }, /* cd: 0110 0100 1100 1101 xxxx xxxx */ + {ONI,"PT,%b" }, /* ce: 0110 0100 1100 1110 xxxx xxxx */ + {illegal,0 }, /* cf: 0110 0100 1100 1111 xxxx xxxx */ + + {illegal,0 }, /* d0: 0110 0100 1101 0000 xxxx xxxx */ + {ACI,"SMH,%b" }, /* d1: 0110 0100 1101 0001 xxxx xxxx */ + {illegal,0 }, /* d2: 0110 0100 1101 0010 xxxx xxxx */ + {ACI,"EOM,%b" }, /* d3: 0110 0100 1101 0011 xxxx xxxx */ + {illegal,0 }, /* d4: 0110 0100 1101 0100 xxxx xxxx */ + {ACI,"TMM,%b" }, /* d5: 0110 0100 1101 0101 xxxx xxxx */ + {illegal,0 }, /* d6: 0110 0100 1101 0110 xxxx xxxx */ + {illegal,0 }, /* d7: 0110 0100 1101 0111 xxxx xxxx */ + {illegal,0 }, /* d8: 0110 0100 1101 1000 xxxx xxxx */ + {OFFI,"SMH,%b" }, /* d9: 0110 0100 1101 1001 xxxx xxxx */ + {illegal,0 }, /* da: 0110 0100 1101 1010 xxxx xxxx */ + {OFFI,"EOM,%b" }, /* db: 0110 0100 1101 1011 xxxx xxxx */ + {illegal,0 }, /* dc: 0110 0100 1101 1100 xxxx xxxx */ + {OFFI,"TMM,%b" }, /* dd: 0110 0100 1101 1101 xxxx xxxx */ + {OFFI,"PT,%b" }, /* de: 0110 0100 1101 1110 xxxx xxxx */ + {illegal,0 }, /* df: 0110 0100 1101 1111 xxxx xxxx */ + + {illegal,0 }, /* e0: 0110 0100 1110 0000 xxxx xxxx */ + {SUI,"SMH,%b" }, /* e1: 0110 0100 1110 0001 xxxx xxxx */ + {illegal,0 }, /* e2: 0110 0100 1110 0010 xxxx xxxx */ + {SUI,"EOM,%b" }, /* e3: 0110 0100 1110 0011 xxxx xxxx */ + {illegal,0 }, /* e4: 0110 0100 1110 0100 xxxx xxxx */ + {SUI,"TMM,%b" }, /* e5: 0110 0100 1110 0101 xxxx xxxx */ + {illegal,0 }, /* e6: 0110 0100 1110 0110 xxxx xxxx */ + {illegal,0 }, /* e7: 0110 0100 1110 0111 xxxx xxxx */ + {illegal,0 }, /* e8: 0110 0100 1110 1000 xxxx xxxx */ + {NEI,"SMH,%b" }, /* e9: 0110 0100 1110 1001 xxxx xxxx */ + {illegal,0 }, /* ea: 0110 0100 1110 1010 xxxx xxxx */ + {NEI,"EOM,%b" }, /* eb: 0110 0100 1110 1011 xxxx xxxx */ + {illegal,0 }, /* ec: 0110 0100 1110 1100 xxxx xxxx */ + {NEI,"TMM,%b" }, /* ed: 0110 0100 1110 1101 xxxx xxxx */ + {NEI,"PT,%b" }, /* ee: 0110 0100 1110 1110 xxxx xxxx */ + {illegal,0 }, /* ef: 0110 0100 1110 1111 xxxx xxxx */ + + {illegal,0 }, /* f0: 0110 0100 1111 0000 xxxx xxxx */ + {SBI,"SMH,%b" }, /* f1: 0110 0100 1111 0001 xxxx xxxx */ + {illegal,0 }, /* f2: 0110 0100 1111 0010 xxxx xxxx */ + {SBI,"EOM,%b" }, /* f3: 0110 0100 1111 0011 xxxx xxxx */ + {illegal,0 }, /* f4: 0110 0100 1111 0100 xxxx xxxx */ + {SBI,"TMM,%b" }, /* f5: 0110 0100 1111 0101 xxxx xxxx */ + {illegal,0 }, /* f6: 0110 0100 1111 0110 xxxx xxxx */ + {illegal,0 }, /* f7: 0110 0100 1111 0111 xxxx xxxx */ + {illegal,0 }, /* f8: 0110 0100 1111 1000 xxxx xxxx */ + {EQI,"SMH,%b" }, /* f9: 0110 0100 1111 1001 xxxx xxxx */ + {illegal,0 }, /* fa: 0110 0100 1111 1010 xxxx xxxx */ + {EQI,"EOM,%b" }, /* fb: 0110 0100 1111 1011 xxxx xxxx */ + {illegal,0 }, /* fc: 0110 0100 1111 1100 xxxx xxxx */ + {EQI,"TMM,%b" }, /* fd: 0110 0100 1111 1101 xxxx xxxx */ + {EQI,"PT,%b" }, /* fe: 0110 0100 1111 1110 xxxx xxxx */ + {illegal,0 } /* ff: 0110 0100 1111 1111 xxxx xxxx */ +}; + +/* prefix 70 */ +static const struct dasm_s dasm70[256] = +{ + {illegal,0 }, /* 00: 0111 0000 0000 0000 */ + {illegal,0 }, /* 01: 0111 0000 0000 0001 */ + {illegal,0 }, /* 02: 0111 0000 0000 0010 */ + {illegal,0 }, /* 03: 0111 0000 0000 0011 */ + {illegal,0 }, /* 04: 0111 0000 0000 0100 */ + {illegal,0 }, /* 05: 0111 0000 0000 0101 */ + {illegal,0 }, /* 06: 0111 0000 0000 0110 */ + {illegal,0 }, /* 07: 0111 0000 0000 0111 */ + {illegal,0 }, /* 08: 0111 0000 0000 1000 */ + {illegal,0 }, /* 09: 0111 0000 0000 1001 */ + {illegal,0 }, /* 0a: 0111 0000 0000 1010 */ + {illegal,0 }, /* 0b: 0111 0000 0000 1011 */ + {illegal,0 }, /* 0c: 0111 0000 0000 1100 */ + {illegal,0 }, /* 0d: 0111 0000 0000 1101 */ + {SSPD,"%w" }, /* 0e: 0111 0000 0000 1110 llll llll hhhh hhhh */ + {LSPD,"%w" }, /* 0f: 0111 0000 0000 1111 llll llll hhhh hhhh */ + + {illegal,0 }, /* 10: 0111 0000 0001 0000 */ + {illegal,0 }, /* 11: 0111 0000 0001 0001 */ + {illegal,0 }, /* 12: 0111 0000 0001 0010 */ + {illegal,0 }, /* 13: 0111 0000 0001 0011 */ + {illegal,0 }, /* 14: 0111 0000 0001 0100 */ + {illegal,0 }, /* 15: 0111 0000 0001 0101 */ + {illegal,0 }, /* 16: 0111 0000 0001 0110 */ + {illegal,0 }, /* 17: 0111 0000 0001 0111 */ + {illegal,0 }, /* 18: 0111 0000 0001 1000 */ + {illegal,0 }, /* 19: 0111 0000 0001 1001 */ + {illegal,0 }, /* 1a: 0111 0000 0001 1010 */ + {illegal,0 }, /* 1b: 0111 0000 0001 1011 */ + {illegal,0 }, /* 1c: 0111 0000 0001 1100 */ + {illegal,0 }, /* 1d: 0111 0000 0001 1101 */ + {SBCD,"%w" }, /* 1e: 0111 0000 0001 1110 llll llll hhhh hhhh */ + {LBCD,"%w" }, /* 1f: 0111 0000 0001 1111 llll llll hhhh hhhh */ + + {illegal,0 }, /* 20: 0111 0000 0010 0000 */ + {illegal,0 }, /* 21: 0111 0000 0010 0001 */ + {illegal,0 }, /* 22: 0111 0000 0010 0010 */ + {illegal,0 }, /* 23: 0111 0000 0010 0011 */ + {illegal,0 }, /* 24: 0111 0000 0010 0100 */ + {illegal,0 }, /* 25: 0111 0000 0010 0101 */ + {illegal,0 }, /* 26: 0111 0000 0010 0110 */ + {illegal,0 }, /* 27: 0111 0000 0010 0111 */ + {illegal,0 }, /* 28: 0111 0000 0010 1000 */ + {illegal,0 }, /* 29: 0111 0000 0010 1001 */ + {illegal,0 }, /* 2a: 0111 0000 0010 1010 */ + {illegal,0 }, /* 2b: 0111 0000 0010 1011 */ + {illegal,0 }, /* 2c: 0111 0000 0010 1100 */ + {illegal,0 }, /* 2d: 0111 0000 0010 1101 */ + {SDED,"%w" }, /* 2e: 0111 0000 0010 1110 llll llll hhhh hhhh */ + {LDED,"%w" }, /* 2f: 0111 0000 0010 1111 llll llll hhhh hhhh */ + + {illegal,0 }, /* 30: 0111 0000 0011 0000 */ + {illegal,0 }, /* 31: 0111 0000 0011 0001 */ + {illegal,0 }, /* 32: 0111 0000 0011 0010 */ + {illegal,0 }, /* 33: 0111 0000 0011 0011 */ + {illegal,0 }, /* 34: 0111 0000 0011 0100 */ + {illegal,0 }, /* 35: 0111 0000 0011 0101 */ + {illegal,0 }, /* 36: 0111 0000 0011 0110 */ + {illegal,0 }, /* 37: 0111 0000 0011 0111 */ + {illegal,0 }, /* 38: 0111 0000 0011 1000 */ + {illegal,0 }, /* 39: 0111 0000 0011 1001 */ + {illegal,0 }, /* 3a: 0111 0000 0011 1010 */ + {illegal,0 }, /* 3b: 0111 0000 0011 1011 */ + {illegal,0 }, /* 3c: 0111 0000 0011 1100 */ + {illegal,0 }, /* 3d: 0111 0000 0011 1101 */ + {SHLD,"%w" }, /* 3e: 0111 0000 0011 1110 llll llll hhhh hhhh */ + {LHLD,"%w" }, /* 3f: 0111 0000 0011 1111 llll llll hhhh hhhh */ + + {EADD,"EA,V" }, /* 40: 0111 0000 0100 0000 */ + {EADD,"EA,A" }, /* 41: 0111 0000 0100 0001 */ + {EADD,"EA,B" }, /* 42: 0111 0000 0100 0010 */ + {EADD,"EA,C" }, /* 43: 0111 0000 0100 0011 */ + {illegal,0 }, /* 44: 0111 0000 0100 0100 */ + {illegal,0 }, /* 45: 0111 0000 0100 0101 */ + {illegal,0 }, /* 46: 0111 0000 0100 0110 */ + {illegal,0 }, /* 47: 0111 0000 0100 0111 */ + {illegal,0 }, /* 48: 0111 0000 0100 1000 */ + {illegal,0 }, /* 49: 0111 0000 0100 1001 */ + {illegal,0 }, /* 4a: 0111 0000 0100 1010 */ + {illegal,0 }, /* 4b: 0111 0000 0100 1011 */ + {illegal,0 }, /* 4c: 0111 0000 0100 1100 */ + {illegal,0 }, /* 4d: 0111 0000 0100 1101 */ + {illegal,0 }, /* 4e: 0111 0000 0100 1110 */ + {illegal,0 }, /* 4f: 0111 0000 0100 1111 */ + + {illegal,0 }, /* 50: 0111 0000 0101 0000 */ + {illegal,0 }, /* 51: 0111 0000 0101 0001 */ + {illegal,0 }, /* 52: 0111 0000 0101 0010 */ + {illegal,0 }, /* 53: 0111 0000 0101 0011 */ + {illegal,0 }, /* 54: 0111 0000 0101 0100 */ + {illegal,0 }, /* 55: 0111 0000 0101 0101 */ + {illegal,0 }, /* 56: 0111 0000 0101 0110 */ + {illegal,0 }, /* 57: 0111 0000 0101 0111 */ + {illegal,0 }, /* 58: 0111 0000 0101 1000 */ + {illegal,0 }, /* 59: 0111 0000 0101 1001 */ + {illegal,0 }, /* 5a: 0111 0000 0101 1010 */ + {illegal,0 }, /* 5b: 0111 0000 0101 1011 */ + {illegal,0 }, /* 5c: 0111 0000 0101 1100 */ + {illegal,0 }, /* 5d: 0111 0000 0101 1101 */ + {illegal,0 }, /* 5e: 0111 0000 0101 1110 */ + {illegal,0 }, /* 5f: 0111 0000 0101 1111 */ + + {ESUB,"EA,V" }, /* 60: 0111 0000 0110 0000 */ + {ESUB,"EA,A" }, /* 61: 0111 0000 0110 0001 */ + {ESUB,"EA,B" }, /* 62: 0111 0000 0110 0010 */ + {ESUB,"EA,C" }, /* 63: 0111 0000 0110 0011 */ + {illegal,0 }, /* 64: 0111 0000 0110 0100 */ + {illegal,0 }, /* 65: 0111 0000 0110 0101 */ + {illegal,0 }, /* 66: 0111 0000 0110 0110 */ + {illegal,0 }, /* 67: 0111 0000 0110 0111 */ + {MOV,"V,(%w)" }, /* 68: 0111 0000 0110 1000 llll llll hhhh hhhh */ + {MOV,"A,(%w)" }, /* 69: 0111 0000 0110 1001 llll llll hhhh hhhh */ + {MOV,"B,(%w)" }, /* 6a: 0111 0000 0110 1010 llll llll hhhh hhhh */ + {MOV,"C,(%w)" }, /* 6b: 0111 0000 0110 1011 llll llll hhhh hhhh */ + {MOV,"D,(%w)" }, /* 6c: 0111 0000 0110 1100 llll llll hhhh hhhh */ + {MOV,"E,(%w)" }, /* 6d: 0111 0000 0110 1101 llll llll hhhh hhhh */ + {MOV,"H,(%w)" }, /* 6e: 0111 0000 0110 1110 llll llll hhhh hhhh */ + {MOV,"L,(%w)" }, /* 6f: 0111 0000 0110 1111 llll llll hhhh hhhh */ + + {illegal,0 }, /* 70: 0111 0000 0111 0000 */ + {illegal,0 }, /* 71: 0111 0000 0111 0001 */ + {illegal,0 }, /* 72: 0111 0000 0111 0010 */ + {illegal,0 }, /* 73: 0111 0000 0111 0011 */ + {illegal,0 }, /* 74: 0111 0000 0111 0100 */ + {illegal,0 }, /* 75: 0111 0000 0111 0101 */ + {illegal,0 }, /* 76: 0111 0000 0111 0110 */ + {illegal,0 }, /* 77: 0111 0000 0111 0111 */ + {MOV,"(%w),V" }, /* 78: 0111 0000 0111 1000 llll llll hhhh hhhh */ + {MOV,"(%w),A" }, /* 79: 0111 0000 0111 1001 llll llll hhhh hhhh */ + {MOV,"(%w),B" }, /* 7a: 0111 0000 0111 1010 llll llll hhhh hhhh */ + {MOV,"(%w),C" }, /* 7b: 0111 0000 0111 1011 llll llll hhhh hhhh */ + {MOV,"(%w),D" }, /* 7c: 0111 0000 0111 1100 llll llll hhhh hhhh */ + {MOV,"(%w),E" }, /* 7d: 0111 0000 0111 1101 llll llll hhhh hhhh */ + {MOV,"(%w),H" }, /* 7e: 0111 0000 0111 1110 llll llll hhhh hhhh */ + {MOV,"(%w),L" }, /* 7f: 0111 0000 0111 1111 llll llll hhhh hhhh */ + + {illegal,0 }, /* 80: 0111 0000 1000 0000 */ + {illegal,0 }, /* 81: 0111 0000 1000 0001 */ + {illegal,0 }, /* 82: 0111 0000 1000 0010 */ + {illegal,0 }, /* 83: 0111 0000 1000 0011 */ + {illegal,0 }, /* 84: 0111 0000 1000 0100 */ + {illegal,0 }, /* 85: 0111 0000 1000 0101 */ + {illegal,0 }, /* 86: 0111 0000 1000 0110 */ + {illegal,0 }, /* 87: 0111 0000 1000 0111 */ + {illegal,0 }, /* 88: 0111 0000 1000 1000 */ + {ANAX,"(BC)" }, /* 89: 0111 0000 1000 1001 */ + {ANAX,"(DE)" }, /* 8a: 0111 0000 1000 1010 */ + {ANAX,"(HL)" }, /* 8b: 0111 0000 1000 1011 */ + {ANAX,"(DE+)" }, /* 8c: 0111 0000 1000 1100 */ + {ANAX,"(HL+)" }, /* 8d: 0111 0000 1000 1101 */ + {ANAX,"(DE-)" }, /* 8e: 0111 0000 1000 1110 */ + {ANAX,"(HL-)" }, /* 8f: 0111 0000 1000 1111 */ + + {illegal,0 }, /* 90: 0111 0000 1001 0000 */ + {XRAX,"(BC)" }, /* 91: 0111 0000 1001 0001 */ + {XRAX,"(DE)" }, /* 92: 0111 0000 1001 0010 */ + {XRAX,"(HL)" }, /* 93: 0111 0000 1001 0011 */ + {XRAX,"(DE+)" }, /* 94: 0111 0000 1001 0100 */ + {XRAX,"(HL+)" }, /* 95: 0111 0000 1001 0101 */ + {XRAX,"(DE-)" }, /* 96: 0111 0000 1001 0110 */ + {XRAX,"(HL-)" }, /* 97: 0111 0000 1001 0111 */ + {illegal,0 }, /* 98: 0111 0000 1001 1000 */ + {ORAX,"(BC)" }, /* 99: 0111 0000 1001 1001 */ + {ORAX,"(DE)" }, /* 9a: 0111 0000 1001 1010 */ + {ORAX,"(HL)" }, /* 9b: 0111 0000 1001 1011 */ + {ORAX,"(DE+)" }, /* 9c: 0111 0000 1001 1100 */ + {ORAX,"(HL+)" }, /* 9d: 0111 0000 1001 1101 */ + {ORAX,"(DE-)" }, /* 9e: 0111 0000 1001 1110 */ + {ORAX,"(HL-)" }, /* 9f: 0111 0000 1001 1111 */ + + {illegal,0 }, /* a0: 0111 0000 1010 0000 */ + {ADDNCX,"(BC)" }, /* a1: 0111 0000 1010 0001 */ + {ADDNCX,"(DE)" }, /* a2: 0111 0000 1010 0010 */ + {ADDNCX,"(HL)" }, /* a3: 0111 0000 1010 0011 */ + {ADDNCX,"(DE+)" }, /* a4: 0111 0000 1010 0100 */ + {ADDNCX,"(HL+)" }, /* a5: 0111 0000 1010 0101 */ + {ADDNCX,"(DE-)" }, /* a6: 0111 0000 1010 0110 */ + {ADDNCX,"(HL-)" }, /* a7: 0111 0000 1010 0111 */ + {illegal,0 }, /* a8: 0111 0000 1010 1000 */ + {GTAX,"(BC)" }, /* a9: 0111 0000 1010 1001 */ + {GTAX,"(DE)" }, /* aa: 0111 0000 1010 1010 */ + {GTAX,"(HL)" }, /* ab: 0111 0000 1010 1011 */ + {GTAX,"(DE+)" }, /* ac: 0111 0000 1010 1100 */ + {GTAX,"(HL+)" }, /* ad: 0111 0000 1010 1101 */ + {GTAX,"(DE-)" }, /* ae: 0111 0000 1010 1110 */ + {GTAX,"(HL-)" }, /* af: 0111 0000 1010 1111 */ + + {illegal,0 }, /* b0: 0111 0000 1011 0000 */ + {SUBNBX,"(BC)" }, /* b1: 0111 0000 1011 0001 */ + {SUBNBX,"(DE)" }, /* b2: 0111 0000 1011 0010 */ + {SUBNBX,"(HL)" }, /* b3: 0111 0000 1011 0011 */ + {SUBNBX,"(DE+)" }, /* b4: 0111 0000 1011 0100 */ + {SUBNBX,"(HL+)" }, /* b5: 0111 0000 1011 0101 */ + {SUBNBX,"(DE-)" }, /* b6: 0111 0000 1011 0110 */ + {SUBNBX,"(HL-)" }, /* b7: 0111 0000 1011 0111 */ + {illegal,0 }, /* b8: 0111 0000 1011 1000 */ + {LTAX,"(BC)" }, /* b9: 0111 0000 1011 1001 */ + {LTAX,"(DE)" }, /* ba: 0111 0000 1011 1010 */ + {LTAX,"(HL)" }, /* bb: 0111 0000 1011 1011 */ + {LTAX,"(DE+)" }, /* bc: 0111 0000 1011 1100 */ + {LTAX,"(HL+)" }, /* bd: 0111 0000 1011 1101 */ + {LTAX,"(DE-)" }, /* be: 0111 0000 1011 1110 */ + {LTAX,"(HL-)" }, /* bf: 0111 0000 1011 1111 */ + + {illegal,0 }, /* c0: 0111 0000 1100 0000 */ + {ADDX,"(BC)" }, /* c1: 0111 0000 1100 0001 */ + {ADDX,"(DE)" }, /* c2: 0111 0000 1100 0010 */ + {ADDX,"(HL)" }, /* c3: 0111 0000 1100 0011 */ + {ADDX,"(DE+)" }, /* c4: 0111 0000 1100 0100 */ + {ADDX,"(HL+)" }, /* c5: 0111 0000 1100 0101 */ + {ADDX,"(DE-)" }, /* c6: 0111 0000 1100 0110 */ + {ADDX,"(HL-)" }, /* c7: 0111 0000 1100 0111 */ + {illegal,0 }, /* c8: 0111 0000 1100 1000 */ + {ONAX,"(BC)" }, /* c9: 0111 0000 1100 1001 */ + {ONAX,"(DE)" }, /* ca: 0111 0000 1100 1010 */ + {ONAX,"(HL)" }, /* cb: 0111 0000 1100 1011 */ + {ONAX,"(DE+)" }, /* cc: 0111 0000 1100 1100 */ + {ONAX,"(HL+)" }, /* cd: 0111 0000 1100 1101 */ + {ONAX,"(DE-)" }, /* ce: 0111 0000 1100 1110 */ + {ONAX,"(HL-)" }, /* cf: 0111 0000 1100 1111 */ + + {illegal,0 }, /* d0: 0111 0000 1101 0000 */ + {ADCX,"(BC)" }, /* d1: 0111 0000 1101 0001 */ + {ADCX,"(DE)" }, /* d2: 0111 0000 1101 0010 */ + {ADCX,"(HL)" }, /* d3: 0111 0000 1101 0011 */ + {ADCX,"(DE+)" }, /* d4: 0111 0000 1101 0100 */ + {ADCX,"(HL+)" }, /* d5: 0111 0000 1101 0101 */ + {ADCX,"(DE-)" }, /* d6: 0111 0000 1101 0110 */ + {ADCX,"(HL-)" }, /* d7: 0111 0000 1101 0111 */ + {illegal,0 }, /* d8: 0111 0000 1101 1000 */ + {OFFAX,"(BC)" }, /* d9: 0111 0000 1101 1001 */ + {OFFAX,"(DE)" }, /* da: 0111 0000 1101 1010 */ + {OFFAX,"(HL)" }, /* db: 0111 0000 1101 1011 */ + {OFFAX,"(DE+)" }, /* dc: 0111 0000 1101 1100 */ + {OFFAX,"(HL+)" }, /* dd: 0111 0000 1101 1101 */ + {OFFAX,"(DE-)" }, /* de: 0111 0000 1101 1110 */ + {OFFAX,"(HL-)" }, /* df: 0111 0000 1101 1111 */ + + {illegal,0 }, /* e0: 0111 0000 1110 0000 */ + {SUBX,"(BC)" }, /* e1: 0111 0000 1110 0001 */ + {SUBX,"(DE)" }, /* e2: 0111 0000 1110 0010 */ + {SUBX,"(HL)" }, /* e3: 0111 0000 1110 0011 */ + {SUBX,"(DE+)" }, /* e4: 0111 0000 1110 0100 */ + {SUBX,"(HL+)" }, /* e5: 0111 0000 1110 0101 */ + {SUBX,"(DE-)" }, /* e6: 0111 0000 1110 0110 */ + {SUBX,"(HL-)" }, /* e7: 0111 0000 1110 0111 */ + {illegal,0 }, /* e8: 0111 0000 1110 1000 */ + {NEAX,"(BC)" }, /* e9: 0111 0000 1110 1001 */ + {NEAX,"(DE)" }, /* ea: 0111 0000 1110 1010 */ + {NEAX,"(HL)" }, /* eb: 0111 0000 1110 1011 */ + {NEAX,"(DE+)" }, /* ec: 0111 0000 1110 1100 */ + {NEAX,"(HL+)" }, /* ed: 0111 0000 1110 1101 */ + {NEAX,"(DE-)" }, /* ee: 0111 0000 1110 1110 */ + {NEAX,"(HL-)" }, /* ef: 0111 0000 1110 1111 */ + + {illegal,0 }, /* f0: 0111 0000 1111 0000 */ + {SBBX,"(BC)" }, /* f1: 0111 0000 1111 0001 */ + {SBBX,"(DE)" }, /* f2: 0111 0000 1111 0010 */ + {SBBX,"(HL)" }, /* f3: 0111 0000 1111 0011 */ + {SBBX,"(DE+)" }, /* f4: 0111 0000 1111 0100 */ + {SBBX,"(HL+)" }, /* f5: 0111 0000 1111 0101 */ + {SBBX,"(DE-)" }, /* f6: 0111 0000 1111 0110 */ + {SBBX,"(HL-)" }, /* f7: 0111 0000 1111 0111 */ + {illegal,0 }, /* f8: 0111 0000 1111 1000 */ + {EQAX,"(BC)" }, /* f9: 0111 0000 1111 1001 */ + {EQAX,"(DE)" }, /* fa: 0111 0000 1111 1010 */ + {EQAX,"(HL)" }, /* fb: 0111 0000 1111 1011 */ + {EQAX,"(DE+)" }, /* fc: 0111 0000 1111 1100 */ + {EQAX,"(HL+)" }, /* fd: 0111 0000 1111 1101 */ + {EQAX,"(DE-)" }, /* fe: 0111 0000 1111 1110 */ + {EQAX,"(HL-)" } /* ff: 0111 0000 1111 1111 */ +}; + +/* prefix 74 */ +static const struct dasm_s dasm74[256] = +{ + {illegal,0 }, /* 00: 0111 0100 0000 0000 */ + {illegal,0 }, /* 01: 0111 0100 0000 0001 */ + {illegal,0 }, /* 02: 0111 0100 0000 0010 */ + {illegal,0 }, /* 03: 0111 0100 0000 0011 */ + {illegal,0 }, /* 04: 0111 0100 0000 0100 */ + {illegal,0 }, /* 05: 0111 0100 0000 0101 */ + {illegal,0 }, /* 06: 0111 0100 0000 0110 */ + {illegal,0 }, /* 07: 0111 0100 0000 0111 */ + {ANI,"V,%b" }, /* 08: 0111 0100 0000 1000 xxxx xxxx */ + {ANI,"A,%b" }, /* 09: 0111 0100 0000 1001 xxxx xxxx */ + {ANI,"B,%b" }, /* 0a: 0111 0100 0000 1010 xxxx xxxx */ + {ANI,"C,%b" }, /* 0b: 0111 0100 0000 1011 xxxx xxxx */ + {ANI,"D,%b" }, /* 0c: 0111 0100 0000 1100 xxxx xxxx */ + {ANI,"E,%b" }, /* 0d: 0111 0100 0000 1101 xxxx xxxx */ + {ANI,"H,%b" }, /* 0e: 0111 0100 0000 1110 xxxx xxxx */ + {ANI,"L,%b" }, /* 0f: 0111 0100 0000 1111 xxxx xxxx */ + + {XRI,"V,%b" }, /* 10: 0111 0100 0001 0000 xxxx xxxx */ + {XRI,"A,%b" }, /* 11: 0111 0100 0001 0001 xxxx xxxx */ + {XRI,"B,%b" }, /* 12: 0111 0100 0001 0010 xxxx xxxx */ + {XRI,"C,%b" }, /* 13: 0111 0100 0001 0011 xxxx xxxx */ + {XRI,"D,%b" }, /* 14: 0111 0100 0001 0100 xxxx xxxx */ + {XRI,"E,%b" }, /* 15: 0111 0100 0001 0101 xxxx xxxx */ + {XRI,"H,%b" }, /* 16: 0111 0100 0001 0110 xxxx xxxx */ + {XRI,"L,%b" }, /* 17: 0111 0100 0001 0111 xxxx xxxx */ + {ORI,"V,%b" }, /* 18: 0111 0100 0001 1000 xxxx xxxx */ + {ORI,"A,%b" }, /* 19: 0111 0100 0001 1001 xxxx xxxx */ + {ORI,"B,%b" }, /* 1a: 0111 0100 0001 1010 xxxx xxxx */ + {ORI,"C,%b" }, /* 1b: 0111 0100 0001 1011 xxxx xxxx */ + {ORI,"D,%b" }, /* 1c: 0111 0100 0001 1100 xxxx xxxx */ + {ORI,"E,%b" }, /* 1d: 0111 0100 0001 1101 xxxx xxxx */ + {ORI,"H,%b" }, /* 1e: 0111 0100 0001 1110 xxxx xxxx */ + {ORI,"L,%b" }, /* 1f: 0111 0100 0001 1111 xxxx xxxx */ + + {ADINC,"V,%b" }, /* 20: 0111 0100 0010 0000 xxxx xxxx */ + {ADINC,"A,%b" }, /* 21: 0111 0100 0010 0001 xxxx xxxx */ + {ADINC,"B,%b" }, /* 22: 0111 0100 0010 0010 xxxx xxxx */ + {ADINC,"C,%b" }, /* 23: 0111 0100 0010 0011 xxxx xxxx */ + {ADINC,"D,%b" }, /* 24: 0111 0100 0010 0100 xxxx xxxx */ + {ADINC,"E,%b" }, /* 25: 0111 0100 0010 0101 xxxx xxxx */ + {ADINC,"H,%b" }, /* 26: 0111 0100 0010 0110 xxxx xxxx */ + {ADINC,"L,%b" }, /* 27: 0111 0100 0010 0111 xxxx xxxx */ + {GTI,"V,%b" }, /* 28: 0111 0100 0010 1000 xxxx xxxx */ + {GTI,"A,%b" }, /* 29: 0111 0100 0010 1001 xxxx xxxx */ + {GTI,"B,%b" }, /* 2a: 0111 0100 0010 1010 xxxx xxxx */ + {GTI,"C,%b" }, /* 2b: 0111 0100 0010 1011 xxxx xxxx */ + {GTI,"D,%b" }, /* 2c: 0111 0100 0010 1100 xxxx xxxx */ + {GTI,"E,%b" }, /* 2d: 0111 0100 0010 1101 xxxx xxxx */ + {GTI,"H,%b" }, /* 2e: 0111 0100 0010 1110 xxxx xxxx */ + {GTI,"L,%b" }, /* 2f: 0111 0100 0010 1111 xxxx xxxx */ + + {SUINB,"V,%b" }, /* 30: 0111 0100 0011 0000 xxxx xxxx */ + {SUINB,"A,%b" }, /* 31: 0111 0100 0011 0001 xxxx xxxx */ + {SUINB,"B,%b" }, /* 32: 0111 0100 0011 0010 xxxx xxxx */ + {SUINB,"C,%b" }, /* 33: 0111 0100 0011 0011 xxxx xxxx */ + {SUINB,"D,%b" }, /* 34: 0111 0100 0011 0100 xxxx xxxx */ + {SUINB,"E,%b" }, /* 35: 0111 0100 0011 0101 xxxx xxxx */ + {SUINB,"H,%b" }, /* 36: 0111 0100 0011 0110 xxxx xxxx */ + {SUINB,"L,%b" }, /* 37: 0111 0100 0011 0111 xxxx xxxx */ + {LTI,"V,%b" }, /* 38: 0111 0100 0011 1000 xxxx xxxx */ + {LTI,"A,%b" }, /* 39: 0111 0100 0011 1001 xxxx xxxx */ + {LTI,"B,%b" }, /* 3a: 0111 0100 0011 1010 xxxx xxxx */ + {LTI,"C,%b" }, /* 3b: 0111 0100 0011 1011 xxxx xxxx */ + {LTI,"D,%b" }, /* 3c: 0111 0100 0011 1100 xxxx xxxx */ + {LTI,"E,%b" }, /* 3d: 0111 0100 0011 1101 xxxx xxxx */ + {LTI,"H,%b" }, /* 3e: 0111 0100 0011 1110 xxxx xxxx */ + {LTI,"L,%b" }, /* 3f: 0111 0100 0011 1111 xxxx xxxx */ + + {ADI,"V,%b" }, /* 40: 0111 0100 0100 0000 xxxx xxxx */ + {ADI,"A,%b" }, /* 41: 0111 0100 0100 0001 xxxx xxxx */ + {ADI,"B,%b" }, /* 42: 0111 0100 0100 0010 xxxx xxxx */ + {ADI,"C,%b" }, /* 43: 0111 0100 0100 0011 xxxx xxxx */ + {ADI,"D,%b" }, /* 44: 0111 0100 0100 0100 xxxx xxxx */ + {ADI,"E,%b" }, /* 45: 0111 0100 0100 0101 xxxx xxxx */ + {ADI,"H,%b" }, /* 46: 0111 0100 0100 0110 xxxx xxxx */ + {ADI,"L,%b" }, /* 47: 0111 0100 0100 0111 xxxx xxxx */ + {ONI,"V,%b" }, /* 48: 0111 0100 0100 1000 xxxx xxxx */ + {ONI,"A,%b" }, /* 49: 0111 0100 0100 1001 xxxx xxxx */ + {ONI,"B,%b" }, /* 4a: 0111 0100 0100 1010 xxxx xxxx */ + {ONI,"C,%b" }, /* 4b: 0111 0100 0100 1011 xxxx xxxx */ + {ONI,"D,%b" }, /* 4c: 0111 0100 0100 1100 xxxx xxxx */ + {ONI,"E,%b" }, /* 4d: 0111 0100 0100 1101 xxxx xxxx */ + {ONI,"H,%b" }, /* 4e: 0111 0100 0100 1110 xxxx xxxx */ + {ONI,"L,%b" }, /* 4f: 0111 0100 0100 1111 xxxx xxxx */ + + {ACI,"V,%b" }, /* 50: 0111 0100 0101 0000 xxxx xxxx */ + {ACI,"A,%b" }, /* 51: 0111 0100 0101 0001 xxxx xxxx */ + {ACI,"B,%b" }, /* 52: 0111 0100 0101 0010 xxxx xxxx */ + {ACI,"C,%b" }, /* 53: 0111 0100 0101 0011 xxxx xxxx */ + {ACI,"D,%b" }, /* 54: 0111 0100 0101 0100 xxxx xxxx */ + {ACI,"E,%b" }, /* 55: 0111 0100 0101 0101 xxxx xxxx */ + {ACI,"H,%b" }, /* 56: 0111 0100 0101 0110 xxxx xxxx */ + {ACI,"L,%b" }, /* 57: 0111 0100 0101 0111 xxxx xxxx */ + {OFFI,"V,%b" }, /* 58: 0111 0100 0101 1000 xxxx xxxx */ + {OFFI,"A,%b" }, /* 59: 0111 0100 0101 1001 xxxx xxxx */ + {OFFI,"B,%b" }, /* 5a: 0111 0100 0101 1010 xxxx xxxx */ + {OFFI,"C,%b" }, /* 5b: 0111 0100 0101 1011 xxxx xxxx */ + {OFFI,"D,%b" }, /* 5c: 0111 0100 0101 1100 xxxx xxxx */ + {OFFI,"E,%b" }, /* 5d: 0111 0100 0101 1101 xxxx xxxx */ + {OFFI,"H,%b" }, /* 5e: 0111 0100 0101 1110 xxxx xxxx */ + {OFFI,"L,%b" }, /* 5f: 0111 0100 0101 1111 xxxx xxxx */ + + {SUI,"V,%b" }, /* 60: 0111 0100 0110 0000 xxxx xxxx */ + {SUI,"A,%b" }, /* 61: 0111 0100 0110 0001 xxxx xxxx */ + {SUI,"B,%b" }, /* 62: 0111 0100 0110 0010 xxxx xxxx */ + {SUI,"C,%b" }, /* 63: 0111 0100 0110 0011 xxxx xxxx */ + {SUI,"D,%b" }, /* 64: 0111 0100 0110 0100 xxxx xxxx */ + {SUI,"E,%b" }, /* 65: 0111 0100 0110 0101 xxxx xxxx */ + {SUI,"H,%b" }, /* 66: 0111 0100 0110 0110 xxxx xxxx */ + {SUI,"L,%b" }, /* 67: 0111 0100 0110 0111 xxxx xxxx */ + {NEI,"V,%b" }, /* 68: 0111 0100 0110 1000 xxxx xxxx */ + {NEI,"A,%b" }, /* 69: 0111 0100 0110 1001 xxxx xxxx */ + {NEI,"B,%b" }, /* 6a: 0111 0100 0110 1010 xxxx xxxx */ + {NEI,"C,%b" }, /* 6b: 0111 0100 0110 1011 xxxx xxxx */ + {NEI,"D,%b" }, /* 6c: 0111 0100 0110 1100 xxxx xxxx */ + {NEI,"E,%b" }, /* 6d: 0111 0100 0110 1101 xxxx xxxx */ + {NEI,"H,%b" }, /* 6e: 0111 0100 0110 1110 xxxx xxxx */ + {NEI,"L,%b" }, /* 6f: 0111 0100 0110 1111 xxxx xxxx */ + + {SBI,"V,%b" }, /* 70: 0111 0100 0111 0000 xxxx xxxx */ + {SBI,"A,%b" }, /* 71: 0111 0100 0111 0001 xxxx xxxx */ + {SBI,"B,%b" }, /* 72: 0111 0100 0111 0010 xxxx xxxx */ + {SBI,"C,%b" }, /* 73: 0111 0100 0111 0011 xxxx xxxx */ + {SBI,"D,%b" }, /* 74: 0111 0100 0111 0100 xxxx xxxx */ + {SBI,"E,%b" }, /* 75: 0111 0100 0111 0101 xxxx xxxx */ + {SBI,"H,%b" }, /* 76: 0111 0100 0111 0110 xxxx xxxx */ + {SBI,"L,%b" }, /* 77: 0111 0100 0111 0111 xxxx xxxx */ + {EQI,"V,%b" }, /* 78: 0111 0100 0111 1000 xxxx xxxx */ + {EQI,"A,%b" }, /* 79: 0111 0100 0111 1001 xxxx xxxx */ + {EQI,"B,%b" }, /* 7a: 0111 0100 0111 1010 xxxx xxxx */ + {EQI,"C,%b" }, /* 7b: 0111 0100 0111 1011 xxxx xxxx */ + {EQI,"D,%b" }, /* 7c: 0111 0100 0111 1100 xxxx xxxx */ + {EQI,"E,%b" }, /* 7d: 0111 0100 0111 1101 xxxx xxxx */ + {EQI,"H,%b" }, /* 7e: 0111 0100 0111 1110 xxxx xxxx */ + {EQI,"L,%b" }, /* 7f: 0111 0100 0111 1111 xxxx xxxx */ + + {illegal,0 }, /* 80: 0111 0100 1000 0000 */ + {illegal,0 }, /* 81: 0111 0100 1000 0001 */ + {illegal,0 }, /* 82: 0111 0100 1000 0010 */ + {illegal,0 }, /* 83: 0111 0100 1000 0011 */ + {illegal,0 }, /* 84: 0111 0100 1000 0100 */ + {illegal,0 }, /* 85: 0111 0100 1000 0101 */ + {illegal,0 }, /* 86: 0111 0100 1000 0110 */ + {illegal,0 }, /* 87: 0111 0100 1000 0111 */ + {ANAW,"%a" }, /* 88: 0111 0100 1000 1000 oooo oooo */ + {illegal,0 }, /* 89: 0111 0100 1000 1001 */ + {illegal,0 }, /* 8a: 0111 0100 1000 1010 */ + {illegal,0 }, /* 8b: 0111 0100 1000 1011 */ + {illegal,0 }, /* 8c: 0111 0100 1000 1100 */ + {DAN,"EA,BC" }, /* 8d: 0111 0100 1000 1101 */ + {DAN,"EA,DE" }, /* 8e: 0111 0100 1000 1110 */ + {DAN,"EA,HL" }, /* 8f: 0111 0100 1000 1111 */ + + {XRAW,"%a" }, /* 90: 0111 0100 1001 0000 oooo oooo */ + {illegal,0 }, /* 91: 0111 0100 1001 0001 */ + {illegal,0 }, /* 92: 0111 0100 1001 0010 */ + {illegal,0 }, /* 93: 0111 0100 1001 0011 */ + {illegal,0 }, /* 94: 0111 0100 1001 0100 */ + {DXR,"EA,BC" }, /* 95: 0111 0100 1001 0101 */ + {DXR,"EA,DE" }, /* 96: 0111 0100 1001 0110 */ + {DXR,"EA,HL" }, /* 97: 0111 0100 1001 0111 */ + {ORAW,"%a" }, /* 98: 0111 0100 1001 1000 oooo oooo */ + {illegal,0 }, /* 99: 0111 0100 1001 1001 */ + {illegal,0 }, /* 9a: 0111 0100 1001 1010 */ + {illegal,0 }, /* 9b: 0111 0100 1001 1011 */ + {illegal,0 }, /* 9c: 0111 0100 1001 1100 */ + {DOR,"EA,BC" }, /* 9d: 0111 0100 1001 1101 */ + {DOR,"EA,DE" }, /* 9e: 0111 0100 1001 1110 */ + {DOR,"EA,HL" }, /* 9f: 0111 0100 1001 1111 */ + + {ADDNCW,"%a" }, /* a0: 0111 0100 1010 0000 oooo oooo */ + {illegal,0 }, /* a1: 0111 0100 1010 0001 */ + {illegal,0 }, /* a2: 0111 0100 1010 0010 */ + {illegal,0 }, /* a3: 0111 0100 1010 0011 */ + {illegal,0 }, /* a4: 0111 0100 1010 0100 */ + {DADDNC,"EA,BC" }, /* a5: 0111 0100 1010 0101 */ + {DADDNC,"EA,DE" }, /* a6: 0111 0100 1010 0110 */ + {DADDNC,"EA,HL" }, /* a7: 0111 0100 1010 0111 */ + {GTAW,"%a" }, /* a8: 0111 0100 1010 1000 oooo oooo */ + {illegal,0 }, /* a9: 0111 0100 1010 1001 */ + {illegal,0 }, /* aa: 0111 0100 1010 1010 */ + {illegal,0 }, /* ab: 0111 0100 1010 1011 */ + {illegal,0 }, /* ac: 0111 0100 1010 1100 */ + {DGT,"EA,BC" }, /* ad: 0111 0100 1010 1101 */ + {DGT,"EA,DE" }, /* ae: 0111 0100 1010 1110 */ + {DGT,"EA,HL" }, /* af: 0111 0100 1010 1111 */ + + {SUBNBW,"%a" }, /* b0: 0111 0100 1011 0000 oooo oooo */ + {illegal,0 }, /* b1: 0111 0100 1011 0001 */ + {illegal,0 }, /* b2: 0111 0100 1011 0010 */ + {illegal,0 }, /* b3: 0111 0100 1011 0011 */ + {illegal,0 }, /* b4: 0111 0100 1011 0100 */ + {DSUBNB,"EA,BC" }, /* b5: 0111 0100 1011 0101 */ + {DSUBNB,"EA,DE" }, /* b6: 0111 0100 1011 0110 */ + {DSUBNB,"EA,HL" }, /* b7: 0111 0100 1011 0111 */ + {LTAW,"%a" }, /* b8: 0111 0100 1011 1000 oooo oooo */ + {illegal,0 }, /* b9: 0111 0100 1011 1001 */ + {illegal,0 }, /* ba: 0111 0100 1011 1010 */ + {illegal,0 }, /* bb: 0111 0100 1011 1011 */ + {illegal,0 }, /* bc: 0111 0100 1011 1100 */ + {DLT,"EA,BC" }, /* bd: 0111 0100 1011 1101 */ + {DLT,"EA,DE" }, /* be: 0111 0100 1011 1110 */ + {DLT,"EA,HL" }, /* bf: 0111 0100 1011 1111 */ + + {ADDW,"%a" }, /* c0: 0111 0100 1100 0000 oooo oooo */ + {illegal,0 }, /* c1: 0111 0100 1100 0001 */ + {illegal,0 }, /* c2: 0111 0100 1100 0010 */ + {illegal,0 }, /* c3: 0111 0100 1100 0011 */ + {illegal,0 }, /* c4: 0111 0100 1100 0100 */ + {DADD,"EA,BC" }, /* c5: 0111 0100 1100 0101 */ + {DADD,"EA,DE" }, /* c6: 0111 0100 1100 0110 */ + {DADD,"EA,HL" }, /* c7: 0111 0100 1100 0111 */ + {ONAW,"%a" }, /* c8: 0111 0100 1100 1000 oooo oooo */ + {illegal,0 }, /* c9: 0111 0100 1100 1001 */ + {illegal,0 }, /* ca: 0111 0100 1100 1010 */ + {illegal,0 }, /* cb: 0111 0100 1100 1011 */ + {illegal,0 }, /* cc: 0111 0100 1100 1100 */ + {DON,"EA,BC" }, /* cd: 0111 0100 1100 1101 */ + {DON,"EA,DE" }, /* ce: 0111 0100 1100 1110 */ + {DON,"EA,HL" }, /* cf: 0111 0100 1100 1111 */ + + {ADCW,"%a" }, /* d0: 0111 0100 1101 0000 oooo oooo */ + {illegal,0 }, /* d1: 0111 0100 1101 0001 */ + {illegal,0 }, /* d2: 0111 0100 1101 0010 */ + {illegal,0 }, /* d3: 0111 0100 1101 0011 */ + {illegal,0 }, /* d4: 0111 0100 1101 0100 */ + {DADC,"EA,BC" }, /* d5: 0111 0100 1101 0101 */ + {DADC,"EA,DE" }, /* d6: 0111 0100 1101 0110 */ + {DADC,"EA,HL" }, /* d7: 0111 0100 1101 0111 */ + {OFFAW,"%a" }, /* d8: 0111 0100 1101 1000 oooo oooo */ + {illegal,0 }, /* d9: 0111 0100 1101 1001 */ + {illegal,0 }, /* da: 0111 0100 1101 1010 */ + {illegal,0 }, /* db: 0111 0100 1101 1011 */ + {illegal,0 }, /* dc: 0111 0100 1101 1100 */ + {DOFF,"EA,BC" }, /* dd: 0111 0100 1101 1101 */ + {DOFF,"EA,DE" }, /* de: 0111 0100 1101 1110 */ + {DOFF,"EA,HL" }, /* df: 0111 0100 1101 1111 */ + + {SUBW,"%a" }, /* e0: 0111 0100 1110 0000 oooo oooo */ + {illegal,0 }, /* e1: 0111 0100 1110 0001 */ + {illegal,0 }, /* e2: 0111 0100 1110 0010 */ + {illegal,0 }, /* e3: 0111 0100 1110 0011 */ + {illegal,0 }, /* e4: 0111 0100 1110 0100 */ + {DSUB,"EA,BC" }, /* e5: 0111 0100 1110 0101 */ + {DSUB,"EA,DE" }, /* e6: 0111 0100 1110 0110 */ + {DSUB,"EA,HL" }, /* e7: 0111 0100 1110 0111 */ + {NEAW,"%a" }, /* e8: 0111 0100 1110 1000 oooo oooo */ + {illegal,0 }, /* e9: 0111 0100 1110 1001 */ + {illegal,0 }, /* ea: 0111 0100 1110 1010 */ + {illegal,0 }, /* eb: 0111 0100 1110 1011 */ + {illegal,0 }, /* ec: 0111 0100 1110 1100 */ + {DNE,"EA,BC" }, /* ed: 0111 0100 1110 1101 */ + {DNE,"EA,DE" }, /* ee: 0111 0100 1110 1110 */ + {DNE,"EA,HL" }, /* ef: 0111 0100 1110 1111 */ + + {SBBW,"%a" }, /* f0: 0111 0100 1111 0000 oooo oooo */ + {illegal,0 }, /* f1: 0111 0100 1111 0001 */ + {illegal,0 }, /* f2: 0111 0100 1111 0010 */ + {illegal,0 }, /* f3: 0111 0100 1111 0011 */ + {illegal,0 }, /* f4: 0111 0100 1111 0100 */ + {DSBB,"EA,BC" }, /* f5: 0111 0100 1111 0101 */ + {DSBB,"EA,DE" }, /* f6: 0111 0100 1111 0110 */ + {DSBB,"EA,HL" }, /* f7: 0111 0100 1111 0111 */ + {EQAW,"%a" }, /* f8: 0111 0100 1111 1000 oooo oooo */ + {illegal,0 }, /* f9: 0111 0100 1111 1001 */ + {illegal,0 }, /* fa: 0111 0100 1111 1010 */ + {illegal,0 }, /* fb: 0111 0100 1111 1011 */ + {illegal,0 }, /* fc: 0111 0100 1111 1100 */ + {DEQ,"EA,BC" }, /* fd: 0111 0100 1111 1101 */ + {DEQ,"EA,DE" }, /* fe: 0111 0100 1111 1110 */ + {DEQ,"EA,HL" } /* ff: 0111 0100 1111 1111 */ +}; + +/* main opcodes */ +static const struct dasm_s dasmXX_7810[256] = +{ + {NOP,0 }, /* 00: 0000 0000 */ + {LDAW,"%a" }, /* 01: 0000 0001 oooo oooo */ + {INX,"SP" }, /* 02: 0000 0010 */ + {DCX,"SP" }, /* 03: 0000 0011 */ + {LXI,"SP,%w" }, /* 04: 0000 0100 llll llll hhhh hhhh */ + {ANIW,"%a,%b" }, /* 05: 0000 0101 oooo oooo xxxx xxxx */ + {illegal,0 }, /* 06: */ + {ANI,"A,%b" }, /* 07: 0000 0111 xxxx xxxx */ + {MOV,"A,EAH" }, /* 08: 0000 1000 */ + {MOV,"A,EAL" }, /* 09: 0000 1001 */ + {MOV,"A,B" }, /* 0a: 0000 1010 */ + {MOV,"A,C" }, /* 0b: 0000 1011 */ + {MOV,"A,D" }, /* 0c: 0000 1100 */ + {MOV,"A,E" }, /* 0d: 0000 1101 */ + {MOV,"A,H" }, /* 0e: 0000 1110 */ + {MOV,"A,L" }, /* 0f: 0000 1111 */ + + {EXA,0 }, /* 10: 0001 0000 */ /* 7810 */ + {EXX,0 }, /* 11: 0001 0001 */ /* 7810 */ + {INX,"BC" }, /* 12: 0001 0010 */ + {DCX,"BC" }, /* 13: 0001 0011 */ + {LXI,"BC,%w" }, /* 14: 0001 0100 llll llll hhhh hhhh */ + {ORIW,"%a,%b" }, /* 15: 0001 0101 oooo oooo xxxx xxxx */ + {XRI,"A,%b" }, /* 16: 0001 0110 xxxx xxxx */ + {ORI,"A,%b" }, /* 17: 0001 0111 xxxx xxxx */ + {MOV,"EAH,A" }, /* 18: 0001 1000 */ + {MOV,"EAL,A" }, /* 19: 0001 1001 */ + {MOV,"B,A" }, /* 1a: 0001 1010 */ + {MOV,"C,A" }, /* 1b: 0001 1011 */ + {MOV,"D,A" }, /* 1c: 0001 1100 */ + {MOV,"E,A" }, /* 1d: 0001 1101 */ + {MOV,"H,A" }, /* 1e: 0001 1110 */ + {MOV,"L,A" }, /* 1f: 0001 1111 */ + + {INRW,"%a" }, /* 20: 0010 0000 oooo oooo */ + {JB,0 }, /* 21: 0010 0001 */ + {INX,"DE" }, /* 22: 0010 0010 */ + {DCX,"DE" }, /* 23: 0010 0011 */ + {LXI,"DE,%w" }, /* 24: 0010 0100 llll llll hhhh hhhh */ + {GTIW,"%a,%b" }, /* 25: 0010 0101 oooo oooo xxxx xxxx */ + {ADINC,"A,%b" }, /* 26: 0010 0110 xxxx xxxx */ + {GTI,"A,%b" }, /* 27: 0010 0111 xxxx xxxx */ + {illegal,0 }, /* 28: 0010 1000 */ + {LDAX,"(BC)" }, /* 29: 0010 1001 */ + {LDAX,"(DE)" }, /* 2a: 0010 1010 */ + {LDAX,"(HL)" }, /* 2b: 0010 1011 */ + {LDAX,"(DE+)" }, /* 2c: 0010 1100 */ + {LDAX,"(HL+)" }, /* 2d: 0010 1101 */ + {LDAX,"(DE-)" }, /* 2e: 0010 1110 */ + {LDAX,"(HL-)" }, /* 2f: 0010 1111 */ + + {DCRW,"%a" }, /* 30: 0011 0000 oooo oooo */ + {BLOCK,0 }, /* 31: 0011 0001 */ /* 7810 */ + {INX,"HL", }, /* 32: 0011 0010 */ + {DCX,"HL", }, /* 33: 0011 0011 */ + {LXI,"HL,%w" }, /* 34: 0011 0100 llll llll hhhh hhhh */ + {LTIW,"%a,%b" }, /* 35: 0011 0101 oooo oooo xxxx xxxx */ + {SUINB,"A,%b" }, /* 36: 0011 0110 xxxx xxxx */ + {LTI,"A,%b" }, /* 37: 0011 0111 xxxx xxxx */ + {illegal,0 }, /* 38: */ + {STAX,"(BC)" }, /* 39: 0011 1001 */ + {STAX,"(DE)" }, /* 3a: 0011 1010 */ + {STAX,"(HL)" }, /* 3b: 0011 1011 */ + {STAX,"(DE+)" }, /* 3c: 0011 1100 */ + {STAX,"(HL+)" }, /* 3d: 0011 1101 */ + {STAX,"(DE-)" }, /* 3e: 0011 1110 */ + {STAX,"(HL-)" }, /* 3f: 0011 1111 */ + + {CALL,"%w" }, /* 40: 0100 0000 llll llll hhhh hhhh */ + {INR,"A" }, /* 41: 0100 0001 */ + {INR,"B" }, /* 42: 0100 0010 */ + {INR,"C" }, /* 43: 0100 0011 */ + {LXI,"EA,%w" }, /* 44: 0100 0100 llll llll hhhh hhhh */ + {ONIW,"%a,%b" }, /* 45: 0100 0101 oooo oooo xxxx xxxx */ + {ADI,"A,%b" }, /* 46: 0100 0110 xxxx xxxx */ + {ONI,"A,%b" }, /* 47: 0100 0111 xxxx xxxx */ + {0,dasm48_7810 }, /* 48: prefix */ + {MVIX,"BC,%b" }, /* 49: 0100 1001 xxxx xxxx */ + {MVIX,"DE,%b" }, /* 4a: 0100 1010 xxxx xxxx */ + {MVIX,"HL,%b" }, /* 4b: 0100 1011 xxxx xxxx */ + {0,dasm4C_7810 }, /* 4c: prefix */ + {0,dasm4D_7810 }, /* 4d: prefix */ + {JRE,"%d" }, /* 4e: 0100 111d dddd dddd */ + {JRE,"%d" }, /* 4f: 0100 111d dddd dddd */ + + {EXH,0 }, /* 50: 0101 0000 */ /* 7810 */ + {DCR,"A" }, /* 51: 0101 0001 */ + {DCR,"B" }, /* 52: 0101 0010 */ + {DCR,"C" }, /* 53: 0101 0011 */ + {JMP,"%w" }, /* 54: 0101 0100 llll llll hhhh hhhh */ + {OFFIW,"%a,%b" }, /* 55: 0101 0101 oooo oooo xxxx xxxx */ + {ACI,"A,%b" }, /* 56: 0101 0110 xxxx xxxx */ + {OFFI,"A,%b" }, /* 57: 0101 0111 xxxx xxxx */ + {BIT,"0,%a", }, /* 58: 0101 1000 oooo oooo */ /* 7810 */ + {BIT,"1,%a", }, /* 59: 0101 1001 oooo oooo */ /* 7810 */ + {BIT,"2,%a", }, /* 5a: 0101 1010 oooo oooo */ /* 7810 */ + {BIT,"3,%a", }, /* 5b: 0101 1011 oooo oooo */ /* 7810 */ + {BIT,"4,%a", }, /* 5c: 0101 1100 oooo oooo */ /* 7810 */ + {BIT,"5,%a", }, /* 5d: 0101 1101 oooo oooo */ /* 7810 */ + {BIT,"6,%a", }, /* 5e: 0101 1110 oooo oooo */ /* 7810 */ + {BIT,"7,%a", }, /* 5f: 0101 1111 oooo oooo */ /* 7810 */ + + {0,dasm60 }, /* 60: prefix */ + {DAA,0 }, /* 61: 0110 0001 */ + {RETI,0 }, /* 62: 0110 0010 */ + {STAW,"%a" }, /* 63: 0110 0011 oooo oooo */ + {0,dasm64_7810 }, /* 64: prefix */ + {NEIW,"%a,%b" }, /* 65: 0110 0101 oooo oooo xxxx xxxx */ + {SUI,"A,%b" }, /* 66: 0110 0110 xxxx xxxx */ + {NEI,"A,%b" }, /* 67: 0110 0111 xxxx xxxx */ + {MVI,"V,%b" }, /* 68: 0110 1000 xxxx xxxx */ + {MVI,"A,%b" }, /* 69: 0110 1001 xxxx xxxx */ + {MVI,"B,%b" }, /* 6a: 0110 1010 xxxx xxxx */ + {MVI,"C,%b" }, /* 6b: 0110 1011 xxxx xxxx */ + {MVI,"D,%b" }, /* 6c: 0110 1100 xxxx xxxx */ + {MVI,"E,%b" }, /* 6d: 0110 1101 xxxx xxxx */ + {MVI,"H,%b" }, /* 6e: 0110 1110 xxxx xxxx */ + {MVI,"L,%b" }, /* 6f: 0110 1111 xxxx xxxx */ + + {0,dasm70 }, /* 70: prefix */ + {MVIW,"%a,%b" }, /* 71: 0111 0001 oooo oooo xxxx xxxx */ + {SOFTI,0 }, /* 72: 0111 0010 */ + {illegal,0 }, /* 73: */ + {0,dasm74 }, /* 74: prefix */ + {EQIW,"%a,%b" }, /* 75: 0111 0101 oooo oooo xxxx xxxx */ + {SBI,"A,%b" }, /* 76: 0111 0110 xxxx xxxx */ + {EQI,"A,%b" }, /* 77: 0111 0111 xxxx xxxx */ + {CALF,"%f" }, /* 78: 0111 1ddd dddd dddd */ + {CALF,"%f" }, /* 79: 0111 1ddd dddd dddd */ + {CALF,"%f" }, /* 7a: 0111 1ddd dddd dddd */ + {CALF,"%f" }, /* 7b: 0111 1ddd dddd dddd */ + {CALF,"%f" }, /* 7c: 0111 1ddd dddd dddd */ + {CALF,"%f" }, /* 7d: 0111 1ddd dddd dddd */ + {CALF,"%f" }, /* 7e: 0111 1ddd dddd dddd */ + {CALF,"%f" }, /* 7f: 0111 1ddd dddd dddd */ + + {CALT,"%t" }, /* 80: 100t tttt */ + {CALT,"%t" }, /* 81: 100t tttt */ + {CALT,"%t" }, /* 82: 100t tttt */ + {CALT,"%t" }, /* 83: 100t tttt */ + {CALT,"%t" }, /* 84: 100t tttt */ + {CALT,"%t" }, /* 85: 100t tttt */ + {CALT,"%t" }, /* 86: 100t tttt */ + {CALT,"%t" }, /* 87: 100t tttt */ + {CALT,"%t" }, /* 88: 100t tttt */ + {CALT,"%t" }, /* 89: 100t tttt */ + {CALT,"%t" }, /* 8a: 100t tttt */ + {CALT,"%t" }, /* 8b: 100t tttt */ + {CALT,"%t" }, /* 8c: 100t tttt */ + {CALT,"%t" }, /* 8d: 100t tttt */ + {CALT,"%t" }, /* 8e: 100t tttt */ + {CALT,"%t" }, /* 8f: 100t tttt */ + + {CALT,"%t" }, /* 90: 100t tttt */ + {CALT,"%t" }, /* 91: 100t tttt */ + {CALT,"%t" }, /* 92: 100t tttt */ + {CALT,"%t" }, /* 93: 100t tttt */ + {CALT,"%t" }, /* 94: 100t tttt */ + {CALT,"%t" }, /* 95: 100t tttt */ + {CALT,"%t" }, /* 96: 100t tttt */ + {CALT,"%t" }, /* 97: 100t tttt */ + {CALT,"%t" }, /* 98: 100t tttt */ + {CALT,"%t" }, /* 99: 100t tttt */ + {CALT,"%t" }, /* 9a: 100t tttt */ + {CALT,"%t" }, /* 9b: 100t tttt */ + {CALT,"%t" }, /* 9c: 100t tttt */ + {CALT,"%t" }, /* 9d: 100t tttt */ + {CALT,"%t" }, /* 9e: 100t tttt */ + {CALT,"%t" }, /* 9f: 100t tttt */ + + {POP,"VA" }, /* a0: 1010 0000 */ + {POP,"BC" }, /* a1: 1010 0001 */ + {POP,"DE" }, /* a2: 1010 0010 */ + {POP,"HL", }, /* a3: 1010 0011 */ + {POP,"EA" }, /* a4: 1010 0100 */ + {DMOV,"EA,BC" }, /* a5: 1010 0101 */ + {DMOV,"EA,DE" }, /* a6: 1010 0110 */ + {DMOV,"EA,HL" }, /* a7: 1010 0111 */ + {INX,"EA" }, /* a8: 1010 1000 */ + {DCX,"EA" }, /* a9: 1010 1001 */ + {EI,0 }, /* aa: 1010 1010 */ + {LDAX,"(DE+%b)" }, /* ab: 1010 1011 dddd dddd */ + {LDAX,"(HL+A)" }, /* ac: 1010 1100 */ + {LDAX,"(HL+B)" }, /* ad: 1010 1101 */ + {LDAX,"(HL+EA)" }, /* ae: 1010 1110 */ + {LDAX,"(HL+%b)" }, /* af: 1010 1111 dddd dddd */ + + {PUSH,"VA" }, /* b0: 1011 0000 */ + {PUSH,"BC" }, /* b1: 1011 0001 */ + {PUSH,"DE" }, /* b2: 1011 0010 */ + {PUSH,"HL", }, /* b3: 1011 0011 */ + {PUSH,"EA" }, /* b4: 1011 0100 */ + {DMOV,"BC,EA" }, /* b5: 1011 0101 */ + {DMOV,"DE,EA" }, /* b6: 1011 0110 */ + {DMOV,"HL,EA" }, /* b7: 1011 0111 */ + {RET,0 }, /* b8: 1011 1000 */ + {RETS,0 }, /* b9: 1011 1001 */ + {DI,0 }, /* ba: 1011 1010 */ + {STAX,"(DE+%b)" }, /* bb: 1011 1011 dddd dddd */ + {STAX,"(HL+A)" }, /* bc: 1011 1100 */ + {STAX,"(HL+B)" }, /* bd: 1011 1101 */ + {STAX,"(HL+EA)" }, /* be: 1011 1110 */ + {STAX,"(HL+%b)" }, /* bf: 1011 1111 dddd dddd */ + + {JR,"%o" }, /* c0: 11oo oooo */ + {JR,"%o" }, /* c1: 11oo oooo */ + {JR,"%o" }, /* c2: 11oo oooo */ + {JR,"%o" }, /* c3: 11oo oooo */ + {JR,"%o" }, /* c4: 11oo oooo */ + {JR,"%o" }, /* c5: 11oo oooo */ + {JR,"%o" }, /* c6: 11oo oooo */ + {JR,"%o" }, /* c7: 11oo oooo */ + {JR,"%o" }, /* c8: 11oo oooo */ + {JR,"%o" }, /* c9: 11oo oooo */ + {JR,"%o" }, /* ca: 11oo oooo */ + {JR,"%o" }, /* cb: 11oo oooo */ + {JR,"%o" }, /* cc: 11oo oooo */ + {JR,"%o" }, /* cd: 11oo oooo */ + {JR,"%o" }, /* ce: 11oo oooo */ + {JR,"%o" }, /* cf: 11oo oooo */ + + {JR,"%o" }, /* d0: 11oo oooo */ + {JR,"%o" }, /* d1: 11oo oooo */ + {JR,"%o" }, /* d2: 11oo oooo */ + {JR,"%o" }, /* d3: 11oo oooo */ + {JR,"%o" }, /* d4: 11oo oooo */ + {JR,"%o" }, /* d5: 11oo oooo */ + {JR,"%o" }, /* d6: 11oo oooo */ + {JR,"%o" }, /* d7: 11oo oooo */ + {JR,"%o" }, /* d8: 11oo oooo */ + {JR,"%o" }, /* d9: 11oo oooo */ + {JR,"%o" }, /* da: 11oo oooo */ + {JR,"%o" }, /* db: 11oo oooo */ + {JR,"%o" }, /* dc: 11oo oooo */ + {JR,"%o" }, /* dd: 11oo oooo */ + {JR,"%o" }, /* de: 11oo oooo */ + {JR,"%o" }, /* df: 11oo oooo */ + + {JR,"%o" }, /* e0: 11oo oooo */ + {JR,"%o" }, /* e1: 11oo oooo */ + {JR,"%o" }, /* e2: 11oo oooo */ + {JR,"%o" }, /* e3: 11oo oooo */ + {JR,"%o" }, /* e4: 11oo oooo */ + {JR,"%o" }, /* e5: 11oo oooo */ + {JR,"%o" }, /* e6: 11oo oooo */ + {JR,"%o" }, /* e7: 11oo oooo */ + {JR,"%o" }, /* e8: 11oo oooo */ + {JR,"%o" }, /* e9: 11oo oooo */ + {JR,"%o" }, /* ea: 11oo oooo */ + {JR,"%o" }, /* eb: 11oo oooo */ + {JR,"%o" }, /* ec: 11oo oooo */ + {JR,"%o" }, /* ed: 11oo oooo */ + {JR,"%o" }, /* ee: 11oo oooo */ + {JR,"%o" }, /* ef: 11oo oooo */ + + {JR,"%o" }, /* f0: 11oo oooo */ + {JR,"%o" }, /* f1: 11oo oooo */ + {JR,"%o" }, /* f2: 11oo oooo */ + {JR,"%o" }, /* f3: 11oo oooo */ + {JR,"%o" }, /* f4: 11oo oooo */ + {JR,"%o" }, /* f5: 11oo oooo */ + {JR,"%o" }, /* f6: 11oo oooo */ + {JR,"%o" }, /* f7: 11oo oooo */ + {JR,"%o" }, /* f8: 11oo oooo */ + {JR,"%o" }, /* f9: 11oo oooo */ + {JR,"%o" }, /* fa: 11oo oooo */ + {JR,"%o" }, /* fb: 11oo oooo */ + {JR,"%o" }, /* fc: 11oo oooo */ + {JR,"%o" }, /* fd: 11oo oooo */ + {JR,"%o" }, /* fe: 11oo oooo */ + {JR,"%o" } /* ff: 11oo oooo */ +}; + +static const struct dasm_s dasmXX_7807[256] = +{ + {NOP,0 }, /* 00: 0000 0000 */ + {LDAW,"%a" }, /* 01: 0000 0001 oooo oooo */ + {INX,"SP" }, /* 02: 0000 0010 */ + {DCX,"SP" }, /* 03: 0000 0011 */ + {LXI,"SP,%w" }, /* 04: 0000 0100 llll llll hhhh hhhh */ + {ANIW,"%a,%b" }, /* 05: 0000 0101 oooo oooo xxxx xxxx */ + {illegal,0 }, /* 06: */ + {ANI,"A,%b" }, /* 07: 0000 0111 xxxx xxxx */ + {MOV,"A,EAH" }, /* 08: 0000 1000 */ + {MOV,"A,EAL" }, /* 09: 0000 1001 */ + {MOV,"A,B" }, /* 0a: 0000 1010 */ + {MOV,"A,C" }, /* 0b: 0000 1011 */ + {MOV,"A,D" }, /* 0c: 0000 1100 */ + {MOV,"A,E" }, /* 0d: 0000 1101 */ + {MOV,"A,H" }, /* 0e: 0000 1110 */ + {MOV,"A,L" }, /* 0f: 0000 1111 */ + + {BLOCK,"D+" }, /* 10: 0001 0000 */ /* 7807 */ + {BLOCK,"D-" }, /* 11: 0001 0001 */ /* 7807 */ + {INX,"BC" }, /* 12: 0001 0010 */ + {DCX,"BC" }, /* 13: 0001 0011 */ + {LXI,"BC,%w" }, /* 14: 0001 0100 llll llll hhhh hhhh */ + {ORIW,"%a,%b" }, /* 15: 0001 0101 oooo oooo xxxx xxxx */ + {XRI,"A,%b" }, /* 16: 0001 0110 xxxx xxxx */ + {ORI,"A,%b" }, /* 17: 0001 0111 xxxx xxxx */ + {MOV,"EAH,A" }, /* 18: 0001 1000 */ + {MOV,"EAL,A" }, /* 19: 0001 1001 */ + {MOV,"B,A" }, /* 1a: 0001 1010 */ + {MOV,"C,A" }, /* 1b: 0001 1011 */ + {MOV,"D,A" }, /* 1c: 0001 1100 */ + {MOV,"E,A" }, /* 1d: 0001 1101 */ + {MOV,"H,A" }, /* 1e: 0001 1110 */ + {MOV,"L,A" }, /* 1f: 0001 1111 */ + + {INRW,"%a" }, /* 20: 0010 0000 oooo oooo */ + {JB,0 }, /* 21: 0010 0001 */ + {INX,"DE" }, /* 22: 0010 0010 */ + {DCX,"DE" }, /* 23: 0010 0011 */ + {LXI,"DE,%w" }, /* 24: 0010 0100 llll llll hhhh hhhh */ + {GTIW,"%a,%b" }, /* 25: 0010 0101 oooo oooo xxxx xxxx */ + {ADINC,"A,%b" }, /* 26: 0010 0110 xxxx xxxx */ + {GTI,"A,%b" }, /* 27: 0010 0111 xxxx xxxx */ + {illegal,0 }, /* 28: 0010 1000 */ + {LDAX,"(BC)" }, /* 29: 0010 1001 */ + {LDAX,"(DE)" }, /* 2a: 0010 1010 */ + {LDAX,"(HL)" }, /* 2b: 0010 1011 */ + {LDAX,"(DE+)" }, /* 2c: 0010 1100 */ + {LDAX,"(HL+)" }, /* 2d: 0010 1101 */ + {LDAX,"(DE-)" }, /* 2e: 0010 1110 */ + {LDAX,"(HL-)" }, /* 2f: 0010 1111 */ + + {DCRW,"%a" }, /* 30: 0011 0000 oooo oooo */ + {AND,"CY,%i" }, /* 31: 0011 0001 bbbb bbbb */ /* 7807 */ + {INX,"HL", }, /* 32: 0011 0010 */ + {DCX,"HL", }, /* 33: 0011 0011 */ + {LXI,"HL,%w" }, /* 34: 0011 0100 llll llll hhhh hhhh */ + {LTIW,"%a,%b" }, /* 35: 0011 0101 oooo oooo xxxx xxxx */ + {SUINB,"A,%b" }, /* 36: 0011 0110 xxxx xxxx */ + {LTI,"A,%b" }, /* 37: 0011 0111 xxxx xxxx */ + {illegal,0 }, /* 38: */ + {STAX,"(BC)" }, /* 39: 0011 1001 */ + {STAX,"(DE)" }, /* 3a: 0011 1010 */ + {STAX,"(HL)" }, /* 3b: 0011 1011 */ + {STAX,"(DE+)" }, /* 3c: 0011 1100 */ + {STAX,"(HL+)" }, /* 3d: 0011 1101 */ + {STAX,"(DE-)" }, /* 3e: 0011 1110 */ + {STAX,"(HL-)" }, /* 3f: 0011 1111 */ + + {CALL,"%w" }, /* 40: 0100 0000 llll llll hhhh hhhh */ + {INR,"A" }, /* 41: 0100 0001 */ + {INR,"B" }, /* 42: 0100 0010 */ + {INR,"C" }, /* 43: 0100 0011 */ + {LXI,"EA,%w" }, /* 44: 0100 0100 llll llll hhhh hhhh */ + {ONIW,"%a,%b" }, /* 45: 0100 0101 oooo oooo xxxx xxxx */ + {ADI,"A,%b" }, /* 46: 0100 0110 xxxx xxxx */ + {ONI,"A,%b" }, /* 47: 0100 0111 xxxx xxxx */ + {0,dasm48_7807 }, /* 48: prefix */ + {MVIX,"BC,%b" }, /* 49: 0100 1001 xxxx xxxx */ + {MVIX,"DE,%b" }, /* 4a: 0100 1010 xxxx xxxx */ + {MVIX,"HL,%b" }, /* 4b: 0100 1011 xxxx xxxx */ + {0,dasm4C_7807 }, /* 4c: prefix */ + {0,dasm4D_7807 }, /* 4d: prefix */ + {JRE,"%d" }, /* 4e: 0100 111d dddd dddd */ + {JRE,"%d" }, /* 4f: 0100 111d dddd dddd */ + {SKN,"%i" }, /* 50: 0101 0000 bbbb bbbb */ /* 7807 */ + {DCR,"A" }, /* 51: 0101 0001 */ + {DCR,"B" }, /* 52: 0101 0010 */ + {DCR,"C" }, /* 53: 0101 0011 */ + {JMP,"%w" }, /* 54: 0101 0100 llll llll hhhh hhhh */ + {OFFIW,"%a,%b" }, /* 55: 0101 0101 oooo oooo xxxx xxxx */ + {ACI,"A,%b" }, /* 56: 0101 0110 xxxx xxxx */ + {OFFI,"A,%b" }, /* 57: 0101 0111 xxxx xxxx */ + {SETB,"%i" }, /* 58: 0101 1000 bbbb bbbb */ /* 7807 */ + {NOT,"%i" }, /* 59: 0101 1001 bbbb bbbb */ /* 7807 */ + {MOV,"%i,CY" }, /* 5a: 0101 1010 bbbb bbbb */ /* 7807 */ + {CLR,"%i" }, /* 5b: 0101 1011 bbbb bbbb */ /* 7807 */ + {OR,"CY,%i" }, /* 5c: 0101 1100 bbbb bbbb */ /* 7807 */ + {SK,"%i" }, /* 5d: 0101 1101 bbbb bbbb */ /* 7807 */ + {XOR,"CY,%i" }, /* 5e: 0101 1110 bbbb bbbb */ /* 7807 */ + {MOV,"CY,%i" }, /* 5f: 0101 1111 bbbb bbbb */ /* 7807 */ + + {0,dasm60 }, /* 60: prefix */ + {DAA,0 }, /* 61: 0110 0001 */ + {RETI,0 }, /* 62: 0110 0010 */ + {STAW,"%a" }, /* 63: 0110 0011 oooo oooo */ + {0,dasm64_7807 }, /* 64: prefix */ + {NEIW,"%a,%b" }, /* 65: 0110 0101 oooo oooo xxxx xxxx */ + {SUI,"A,%b" }, /* 66: 0110 0110 xxxx xxxx */ + {NEI,"A,%b" }, /* 67: 0110 0111 xxxx xxxx */ + {MVI,"V,%b" }, /* 68: 0110 1000 xxxx xxxx */ + {MVI,"A,%b" }, /* 69: 0110 1001 xxxx xxxx */ + {MVI,"B,%b" }, /* 6a: 0110 1010 xxxx xxxx */ + {MVI,"C,%b" }, /* 6b: 0110 1011 xxxx xxxx */ + {MVI,"D,%b" }, /* 6c: 0110 1100 xxxx xxxx */ + {MVI,"E,%b" }, /* 6d: 0110 1101 xxxx xxxx */ + {MVI,"H,%b" }, /* 6e: 0110 1110 xxxx xxxx */ + {MVI,"L,%b" }, /* 6f: 0110 1111 xxxx xxxx */ + + {0,dasm70 }, /* 70: prefix */ + {MVIW,"%a,%b" }, /* 71: 0111 0001 oooo oooo xxxx xxxx */ + {SOFTI,0 }, /* 72: 0111 0010 */ + {illegal,0 }, /* 73: */ + {0,dasm74 }, /* 74: prefix */ + {EQIW,"%a,%b" }, /* 75: 0111 0101 oooo oooo xxxx xxxx */ + {SBI,"A,%b" }, /* 76: 0111 0110 xxxx xxxx */ + {EQI,"A,%b" }, /* 77: 0111 0111 xxxx xxxx */ + {CALF,"%f" }, /* 78: 0111 1ddd dddd dddd */ + {CALF,"%f" }, /* 79: 0111 1ddd dddd dddd */ + {CALF,"%f" }, /* 7a: 0111 1ddd dddd dddd */ + {CALF,"%f" }, /* 7b: 0111 1ddd dddd dddd */ + {CALF,"%f" }, /* 7c: 0111 1ddd dddd dddd */ + {CALF,"%f" }, /* 7d: 0111 1ddd dddd dddd */ + {CALF,"%f" }, /* 7e: 0111 1ddd dddd dddd */ + {CALF,"%f" }, /* 7f: 0111 1ddd dddd dddd */ + + {CALT,"%t" }, /* 80: 100t tttt */ + {CALT,"%t" }, /* 81: 100t tttt */ + {CALT,"%t" }, /* 82: 100t tttt */ + {CALT,"%t" }, /* 83: 100t tttt */ + {CALT,"%t" }, /* 84: 100t tttt */ + {CALT,"%t" }, /* 85: 100t tttt */ + {CALT,"%t" }, /* 86: 100t tttt */ + {CALT,"%t" }, /* 87: 100t tttt */ + {CALT,"%t" }, /* 88: 100t tttt */ + {CALT,"%t" }, /* 89: 100t tttt */ + {CALT,"%t" }, /* 8a: 100t tttt */ + {CALT,"%t" }, /* 8b: 100t tttt */ + {CALT,"%t" }, /* 8c: 100t tttt */ + {CALT,"%t" }, /* 8d: 100t tttt */ + {CALT,"%t" }, /* 8e: 100t tttt */ + {CALT,"%t" }, /* 8f: 100t tttt */ + + {CALT,"%t" }, /* 90: 100t tttt */ + {CALT,"%t" }, /* 91: 100t tttt */ + {CALT,"%t" }, /* 92: 100t tttt */ + {CALT,"%t" }, /* 93: 100t tttt */ + {CALT,"%t" }, /* 94: 100t tttt */ + {CALT,"%t" }, /* 95: 100t tttt */ + {CALT,"%t" }, /* 96: 100t tttt */ + {CALT,"%t" }, /* 97: 100t tttt */ + {CALT,"%t" }, /* 98: 100t tttt */ + {CALT,"%t" }, /* 99: 100t tttt */ + {CALT,"%t" }, /* 9a: 100t tttt */ + {CALT,"%t" }, /* 9b: 100t tttt */ + {CALT,"%t" }, /* 9c: 100t tttt */ + {CALT,"%t" }, /* 9d: 100t tttt */ + {CALT,"%t" }, /* 9e: 100t tttt */ + {CALT,"%t" }, /* 9f: 100t tttt */ + + {POP,"VA" }, /* a0: 1010 0000 */ + {POP,"BC" }, /* a1: 1010 0001 */ + {POP,"DE" }, /* a2: 1010 0010 */ + {POP,"HL", }, /* a3: 1010 0011 */ + {POP,"EA" }, /* a4: 1010 0100 */ + {DMOV,"EA,BC" }, /* a5: 1010 0101 */ + {DMOV,"EA,DE" }, /* a6: 1010 0110 */ + {DMOV,"EA,HL" }, /* a7: 1010 0111 */ + {INX,"EA" }, /* a8: 1010 1000 */ + {DCX,"EA" }, /* a9: 1010 1001 */ + {EI,0 }, /* aa: 1010 1010 */ + {LDAX,"(DE+%b)" }, /* ab: 1010 1011 dddd dddd */ + {LDAX,"(HL+A)" }, /* ac: 1010 1100 */ + {LDAX,"(HL+B)" }, /* ad: 1010 1101 */ + {LDAX,"(HL+EA)" }, /* ae: 1010 1110 */ + {LDAX,"(HL+%b)" }, /* af: 1010 1111 dddd dddd */ + + {PUSH,"VA" }, /* b0: 1011 0000 */ + {PUSH,"BC" }, /* b1: 1011 0001 */ + {PUSH,"DE" }, /* b2: 1011 0010 */ + {PUSH,"HL", }, /* b3: 1011 0011 */ + {PUSH,"EA" }, /* b4: 1011 0100 */ + {DMOV,"BC,EA" }, /* b5: 1011 0101 */ + {DMOV,"DE,EA" }, /* b6: 1011 0110 */ + {DMOV,"HL,EA" }, /* b7: 1011 0111 */ + {RET,0 }, /* b8: 1011 1000 */ + {RETS,0 }, /* b9: 1011 1001 */ + {DI,0 }, /* ba: 1011 1010 */ + {STAX,"(DE+%b)" }, /* bb: 1011 1011 dddd dddd */ + {STAX,"(HL+A)" }, /* bc: 1011 1100 */ + {STAX,"(HL+B)" }, /* bd: 1011 1101 */ + {STAX,"(HL+EA)" }, /* be: 1011 1110 */ + {STAX,"(HL+%b)" }, /* bf: 1011 1111 dddd dddd */ + + {JR,"%o" }, /* c0: 11oo oooo */ + {JR,"%o" }, /* c1: 11oo oooo */ + {JR,"%o" }, /* c2: 11oo oooo */ + {JR,"%o" }, /* c3: 11oo oooo */ + {JR,"%o" }, /* c4: 11oo oooo */ + {JR,"%o" }, /* c5: 11oo oooo */ + {JR,"%o" }, /* c6: 11oo oooo */ + {JR,"%o" }, /* c7: 11oo oooo */ + {JR,"%o" }, /* c8: 11oo oooo */ + {JR,"%o" }, /* c9: 11oo oooo */ + {JR,"%o" }, /* ca: 11oo oooo */ + {JR,"%o" }, /* cb: 11oo oooo */ + {JR,"%o" }, /* cc: 11oo oooo */ + {JR,"%o" }, /* cd: 11oo oooo */ + {JR,"%o" }, /* ce: 11oo oooo */ + {JR,"%o" }, /* cf: 11oo oooo */ + + {JR,"%o" }, /* d0: 11oo oooo */ + {JR,"%o" }, /* d1: 11oo oooo */ + {JR,"%o" }, /* d2: 11oo oooo */ + {JR,"%o" }, /* d3: 11oo oooo */ + {JR,"%o" }, /* d4: 11oo oooo */ + {JR,"%o" }, /* d5: 11oo oooo */ + {JR,"%o" }, /* d6: 11oo oooo */ + {JR,"%o" }, /* d7: 11oo oooo */ + {JR,"%o" }, /* d8: 11oo oooo */ + {JR,"%o" }, /* d9: 11oo oooo */ + {JR,"%o" }, /* da: 11oo oooo */ + {JR,"%o" }, /* db: 11oo oooo */ + {JR,"%o" }, /* dc: 11oo oooo */ + {JR,"%o" }, /* dd: 11oo oooo */ + {JR,"%o" }, /* de: 11oo oooo */ + {JR,"%o" }, /* df: 11oo oooo */ + + {JR,"%o" }, /* e0: 11oo oooo */ + {JR,"%o" }, /* e1: 11oo oooo */ + {JR,"%o" }, /* e2: 11oo oooo */ + {JR,"%o" }, /* e3: 11oo oooo */ + {JR,"%o" }, /* e4: 11oo oooo */ + {JR,"%o" }, /* e5: 11oo oooo */ + {JR,"%o" }, /* e6: 11oo oooo */ + {JR,"%o" }, /* e7: 11oo oooo */ + {JR,"%o" }, /* e8: 11oo oooo */ + {JR,"%o" }, /* e9: 11oo oooo */ + {JR,"%o" }, /* ea: 11oo oooo */ + {JR,"%o" }, /* eb: 11oo oooo */ + {JR,"%o" }, /* ec: 11oo oooo */ + {JR,"%o" }, /* ed: 11oo oooo */ + {JR,"%o" }, /* ee: 11oo oooo */ + {JR,"%o" }, /* ef: 11oo oooo */ + + {JR,"%o" }, /* f0: 11oo oooo */ + {JR,"%o" }, /* f1: 11oo oooo */ + {JR,"%o" }, /* f2: 11oo oooo */ + {JR,"%o" }, /* f3: 11oo oooo */ + {JR,"%o" }, /* f4: 11oo oooo */ + {JR,"%o" }, /* f5: 11oo oooo */ + {JR,"%o" }, /* f6: 11oo oooo */ + {JR,"%o" }, /* f7: 11oo oooo */ + {JR,"%o" }, /* f8: 11oo oooo */ + {JR,"%o" }, /* f9: 11oo oooo */ + {JR,"%o" }, /* fa: 11oo oooo */ + {JR,"%o" }, /* fb: 11oo oooo */ + {JR,"%o" }, /* fc: 11oo oooo */ + {JR,"%o" }, /* fd: 11oo oooo */ + {JR,"%o" }, /* fe: 11oo oooo */ + {JR,"%o" } /* ff: 11oo oooo */ +}; + +/********************************************************* + * + * uPD7801 + * + *********************************************************/ + +static const struct dasm_s dasm48_7801[256] = { + /* 0x00 - 0x3F */ + { SKIT, "F0" }, { SKIT, "FT" }, { SKIT, "F1" }, { SKIT, "F2" }, + { SKIT, "FS" }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { SK, "CY" }, { illegal, 0 }, + { SK, "Z" }, { illegal, 0 }, { PUSH, "VA" }, { POP, "VA" }, + + { SKNIT, "F0" }, { SKNIT, "FT" }, { SKNIT, "F1" }, { SKNIT, "F2" }, + { SKNIT, "FS" }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { SKN, "CY" }, { illegal, 0 }, + { SKN, "Z" }, { illegal, 0 }, { PUSH, "BC" }, { POP, "BC" }, + + { EI, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { DI, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { CLC, 0 }, { STC, 0 }, + { PER, 0 }, { PEX, 0 }, { PUSH, "DE" }, { POP, "DE" }, + + { RLL, "A" }, { RLR, "A" }, { RLL, "C" }, { RLR, "C" }, + { SLL, "A" }, { SLR, "A" }, { SLL, "C" }, { SLR, "C" }, + { RLD, 0 }, { RRD, 0 }, { illegal, 0 }, { illegal, 0 }, + { PER, 0 }, { illegal, 0 }, { PUSH, "HL" }, { POP, "HL" }, + + /* 0x40 - 0x7F */ + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + /* 0x80 - 0xBF */ + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + /* 0xC0 - 0xFF */ + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 } +}; + +static const struct dasm_s dasm4c_7801[256] = { + /* 0x00 - 0x3F */ + { IN, 0 }, { IN, 0 }, { IN, 0 }, { IN, 0 }, + { IN, 0 }, { IN, 0 }, { IN, 0 }, { IN, 0 }, + { IN, 0 }, { IN, 0 }, { IN, 0 }, { IN, 0 }, + { IN, 0 }, { IN, 0 }, { IN, 0 }, { IN, 0 }, + + { IN, 0 }, { IN, 0 }, { IN, 0 }, { IN, 0 }, + { IN, 0 }, { IN, 0 }, { IN, 0 }, { IN, 0 }, + { IN, 0 }, { IN, 0 }, { IN, 0 }, { IN, 0 }, + { IN, 0 }, { IN, 0 }, { IN, 0 }, { IN, 0 }, + + { IN, 0 }, { IN, 0 }, { IN, 0 }, { IN, 0 }, + { IN, 0 }, { IN, 0 }, { IN, 0 }, { IN, 0 }, + { IN, 0 }, { IN, 0 }, { IN, 0 }, { IN, 0 }, + { IN, 0 }, { IN, 0 }, { IN, 0 }, { IN, 0 }, + + { IN, 0 }, { IN, 0 }, { IN, 0 }, { IN, 0 }, + { IN, 0 }, { IN, 0 }, { IN, 0 }, { IN, 0 }, + { IN, 0 }, { IN, 0 }, { IN, 0 }, { IN, 0 }, + { IN, 0 }, { IN, 0 }, { IN, 0 }, { IN, 0 }, + + /* 0x40 - 0x7F */ + { IN, 0 }, { IN, 0 }, { IN, 0 }, { IN, 0 }, + { IN, 0 }, { IN, 0 }, { IN, 0 }, { IN, 0 }, + { IN, 0 }, { IN, 0 }, { IN, 0 }, { IN, 0 }, + { IN, 0 }, { IN, 0 }, { IN, 0 }, { IN, 0 }, + + { IN, 0 }, { IN, 0 }, { IN, 0 }, { IN, 0 }, + { IN, 0 }, { IN, 0 }, { IN, 0 }, { IN, 0 }, + { IN, 0 }, { IN, 0 }, { IN, 0 }, { IN, 0 }, + { IN, 0 }, { IN, 0 }, { IN, 0 }, { IN, 0 }, + + { IN, 0 }, { IN, 0 }, { IN, 0 }, { IN, 0 }, + { IN, 0 }, { IN, 0 }, { IN, 0 }, { IN, 0 }, + { IN, 0 }, { IN, 0 }, { IN, 0 }, { IN, 0 }, + { IN, 0 }, { IN, 0 }, { IN, 0 }, { IN, 0 }, + + { IN, 0 }, { IN, 0 }, { IN, 0 }, { IN, 0 }, + { IN, 0 }, { IN, 0 }, { IN, 0 }, { IN, 0 }, + { IN, 0 }, { IN, 0 }, { IN, 0 }, { IN, 0 }, + { IN, 0 }, { IN, 0 }, { IN, 0 }, { IN, 0 }, + + /* 0x80 - 0xBF */ + { IN, 0 }, { IN, 0 }, { IN, 0 }, { IN, 0 }, + { IN, 0 }, { IN, 0 }, { IN, 0 }, { IN, 0 }, + { IN, 0 }, { IN, 0 }, { IN, 0 }, { IN, 0 }, + { IN, 0 }, { IN, 0 }, { IN, 0 }, { IN, 0 }, + + { IN, 0 }, { IN, 0 }, { IN, 0 }, { IN, 0 }, + { IN, 0 }, { IN, 0 }, { IN, 0 }, { IN, 0 }, + { IN, 0 }, { IN, 0 }, { IN, 0 }, { IN, 0 }, + { IN, 0 }, { IN, 0 }, { IN, 0 }, { IN, 0 }, + + { IN, 0 }, { IN, 0 }, { IN, 0 }, { IN, 0 }, + { IN, 0 }, { IN, 0 }, { IN, 0 }, { IN, 0 }, + { IN, 0 }, { IN, 0 }, { IN, 0 }, { IN, 0 }, + { IN, 0 }, { IN, 0 }, { IN, 0 }, { IN, 0 }, + + { IN, 0 }, { IN, 0 }, { IN, 0 }, { IN, 0 }, + { IN, 0 }, { IN, 0 }, { IN, 0 }, { IN, 0 }, + { IN, 0 }, { IN, 0 }, { IN, 0 }, { IN, 0 }, + { IN, 0 }, { IN, 0 }, { IN, 0 }, { IN, 0 }, + + /* 0xC0 - 0xFF */ + { MOV, "A,PA" }, { MOV, "A,PB" }, { MOV, "A,PC" }, { MOV, "A,MK" }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { MOV, "A,S" }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 } +}; + +static const struct dasm_s dasm4d_7801[256] = { + /* 0x00 - 0x3F */ + { OUT, 0 }, { OUT, 0 }, { OUT, 0 }, { OUT, 0 }, + { OUT, 0 }, { OUT, 0 }, { OUT, 0 }, { OUT, 0 }, + { OUT, 0 }, { OUT, 0 }, { OUT, 0 }, { OUT, 0 }, + { OUT, 0 }, { OUT, 0 }, { OUT, 0 }, { OUT, 0 }, + + { OUT, 0 }, { OUT, 0 }, { OUT, 0 }, { OUT, 0 }, + { OUT, 0 }, { OUT, 0 }, { OUT, 0 }, { OUT, 0 }, + { OUT, 0 }, { OUT, 0 }, { OUT, 0 }, { OUT, 0 }, + { OUT, 0 }, { OUT, 0 }, { OUT, 0 }, { OUT, 0 }, + + { OUT, 0 }, { OUT, 0 }, { OUT, 0 }, { OUT, 0 }, + { OUT, 0 }, { OUT, 0 }, { OUT, 0 }, { OUT, 0 }, + { OUT, 0 }, { OUT, 0 }, { OUT, 0 }, { OUT, 0 }, + { OUT, 0 }, { OUT, 0 }, { OUT, 0 }, { OUT, 0 }, + + { OUT, 0 }, { OUT, 0 }, { OUT, 0 }, { OUT, 0 }, + { OUT, 0 }, { OUT, 0 }, { OUT, 0 }, { OUT, 0 }, + { OUT, 0 }, { OUT, 0 }, { OUT, 0 }, { OUT, 0 }, + { OUT, 0 }, { OUT, 0 }, { OUT, 0 }, { OUT, 0 }, + + /* 0x40 - 0x7F */ + { OUT, 0 }, { OUT, 0 }, { OUT, 0 }, { OUT, 0 }, + { OUT, 0 }, { OUT, 0 }, { OUT, 0 }, { OUT, 0 }, + { OUT, 0 }, { OUT, 0 }, { OUT, 0 }, { OUT, 0 }, + { OUT, 0 }, { OUT, 0 }, { OUT, 0 }, { OUT, 0 }, + + { OUT, 0 }, { OUT, 0 }, { OUT, 0 }, { OUT, 0 }, + { OUT, 0 }, { OUT, 0 }, { OUT, 0 }, { OUT, 0 }, + { OUT, 0 }, { OUT, 0 }, { OUT, 0 }, { OUT, 0 }, + { OUT, 0 }, { OUT, 0 }, { OUT, 0 }, { OUT, 0 }, + + { OUT, 0 }, { OUT, 0 }, { OUT, 0 }, { OUT, 0 }, + { OUT, 0 }, { OUT, 0 }, { OUT, 0 }, { OUT, 0 }, + { OUT, 0 }, { OUT, 0 }, { OUT, 0 }, { OUT, 0 }, + { OUT, 0 }, { OUT, 0 }, { OUT, 0 }, { OUT, 0 }, + + { OUT, 0 }, { OUT, 0 }, { OUT, 0 }, { OUT, 0 }, + { OUT, 0 }, { OUT, 0 }, { OUT, 0 }, { OUT, 0 }, + { OUT, 0 }, { OUT, 0 }, { OUT, 0 }, { OUT, 0 }, + { OUT, 0 }, { OUT, 0 }, { OUT, 0 }, { OUT, 0 }, + + /* 0x80 - 0xBF */ + { OUT, 0 }, { OUT, 0 }, { OUT, 0 }, { OUT, 0 }, + { OUT, 0 }, { OUT, 0 }, { OUT, 0 }, { OUT, 0 }, + { OUT, 0 }, { OUT, 0 }, { OUT, 0 }, { OUT, 0 }, + { OUT, 0 }, { OUT, 0 }, { OUT, 0 }, { OUT, 0 }, + + { OUT, 0 }, { OUT, 0 }, { OUT, 0 }, { OUT, 0 }, + { OUT, 0 }, { OUT, 0 }, { OUT, 0 }, { OUT, 0 }, + { OUT, 0 }, { OUT, 0 }, { OUT, 0 }, { OUT, 0 }, + { OUT, 0 }, { OUT, 0 }, { OUT, 0 }, { OUT, 0 }, + + { OUT, 0 }, { OUT, 0 }, { OUT, 0 }, { OUT, 0 }, + { OUT, 0 }, { OUT, 0 }, { OUT, 0 }, { OUT, 0 }, + { OUT, 0 }, { OUT, 0 }, { OUT, 0 }, { OUT, 0 }, + { OUT, 0 }, { OUT, 0 }, { OUT, 0 }, { OUT, 0 }, + + { OUT, 0 }, { OUT, 0 }, { OUT, 0 }, { OUT, 0 }, + { OUT, 0 }, { OUT, 0 }, { OUT, 0 }, { OUT, 0 }, + { OUT, 0 }, { OUT, 0 }, { OUT, 0 }, { OUT, 0 }, + { OUT, 0 }, { OUT, 0 }, { OUT, 0 }, { OUT, 0 }, + + /* 0xC0 - 0xFF */ + { MOV, "PA,A" }, { MOV, "PB,A" }, { MOV, "PC,A" }, { MOV, "MK,A" }, + { MOV, "MB,A" }, { MOV, "MC,A" }, { MOV, "TM0,A" }, { MOV, "TM1,A" }, + { MOV, "S,A" }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 } +}; + +static const struct dasm_s dasm60_7801[256] = { + /* 0x00 - 0x3F */ + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { ANA, "V,A" }, { ANA, "A,A" }, { ANA, "B,A" }, { ANA, "C,A" }, + { ANA, "D,A" }, { ANA, "E,A" }, { ANA, "H,A" }, { ANA, "L,A" }, + + { XRA, "V,A" }, { XRA, "A,A" }, { XRA, "B,A" }, { XRA, "C,A" }, + { XRA, "D,A" }, { XRA, "E,A" }, { XRA, "H,A" }, { XRA, "L,A" }, + { ORA, "V,A" }, { ORA, "A,A" }, { ORA, "B,A" }, { ORA, "C,A" }, + { ORA, "D,A" }, { ORA, "E,A" }, { ORA, "H,A" }, { ORA, "L,A" }, + + { ADDNC, "V,A" }, { ADDNC, "A,A" }, { ADDNC, "B,A" }, { ADDNC, "C,A" }, + { ADDNC, "D,A" }, { ADDNC, "E,A" }, { ADDNC, "H,A" }, { ADDNC, "L,A" }, + { GTA, "V,A" }, { GTA, "A,A" }, { GTA, "B,A" }, { GTA, "C,A" }, + { GTA, "D,A" }, { GTA, "E,A" }, { GTA, "H,A" }, { GTA, "L,A" }, + + { SUBNB, "V,A" }, { SUBNB, "A,A" }, { SUBNB, "B,A" }, { SUBNB, "C,A" }, + { SUBNB, "D,A" }, { SUBNB, "E,A" }, { SUBNB, "H,A" }, { SUBNB, "L,A" }, + { LTA, "V,A" }, { LTA, "A,A" }, { LTA, "B,A" }, { LTA, "C,A" }, + { LTA, "D,A" }, { LTA, "E,A" }, { LTA, "H,A" }, { LTA, "L,A" }, + + /* 0x40 - 0x7F */ + { ADD, "V,A" }, { ADD, "A,A" }, { ADD, "B,A" }, { ADD, "C,A" }, + { ADD, "D,A" }, { ADD, "E,A" }, { ADD, "H,A" }, { ADD, "L,A" }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + { ADC, "V,A" }, { ADC, "A,A" }, { ADC, "B,A" }, { ADC, "C,A" }, + { ADC, "D,A" }, { ADC, "E,A" }, { ADC, "H,A" }, { ADC, "L,A" }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + { SUB, "V,A" }, { SUB, "A,A" }, { SUB, "B,A" }, { SUB, "C,A" }, + { SUB, "D,A" }, { SUB, "E,A" }, { SUB, "H,A" }, { SUB, "L,A" }, + { NEA, "V,A" }, { NEA, "A,A" }, { NEA, "B,A" }, { NEA, "C,A" }, + { NEA, "D,A" }, { NEA, "E,A" }, { NEA, "H,A" }, { NEA, "L,A" }, + + { SBB, "V,A" }, { SBB, "A,A" }, { SBB, "B,A" }, { SBB, "C,A" }, + { SBB, "D,A" }, { SBB, "E,A" }, { SBB, "H,A" }, { SBB, "L,A" }, + { EQA, "V,A" }, { EQA, "A,A" }, { EQA, "B,A" }, { EQA, "C,A" }, + { EQA, "D,A" }, { EQA, "E,A" }, { EQA, "H,A" }, { EQA, "L,A" }, + + /* 0x80 - 0xBF */ + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { ANA, "A,V" }, { ANA, "A,A" }, { ANA, "A,B" }, { ANA, "A,C" }, + { ANA, "A,D" }, { ANA, "A,E" }, { ANA, "A,H" }, { ANA, "A,L" }, + + { XRA, "A,V" }, { XRA, "A,A" }, { XRA, "A,B" }, { XRA, "A,C" }, + { XRA, "A,D" }, { XRA, "A,E" }, { XRA, "A,H" }, { XRA, "A,L" }, + { ORA, "A,V" }, { ORA, "A,A" }, { ORA, "A,B" }, { ORA, "A,C" }, + { ORA, "A,D" }, { ORA, "A,E" }, { ORA, "A,H" }, { ORA, "A,L" }, + + { ADDNC, "A,V" }, { ADDNC, "A,A" }, { ADDNC, "A,B" }, { ADDNC, "A,C" }, + { ADDNC, "A,D" }, { ADDNC, "A,E" }, { ADDNC, "A,H" }, { ADDNC, "A,L" }, + { GTA, "A,V" }, { GTA, "A,A" }, { GTA, "A,B" }, { GTA, "A,C" }, + { GTA, "A,D" }, { GTA, "A,E" }, { GTA, "A,H" }, { GTA, "A,L" }, + + { SUBNB, "A,V" }, { SUBNB, "A,A" }, { SUBNB, "A,B" }, { SUBNB, "A,C" }, + { SUBNB, "A,D" }, { SUBNB, "A,E" }, { SUBNB, "A,H" }, { SUBNB, "A,L" }, + { LTA, "A,V" }, { LTA, "A,A" }, { LTA, "A,B" }, { LTA, "A,C" }, + { LTA, "A,D" }, { LTA, "A,E" }, { LTA, "A,H" }, { LTA, "A,L" }, + + /* 0xC0 - 0xFF */ + { ADD, "A,V" }, { ADD, "A,A" }, { ADD, "A,B" }, { ADD, "A,C" }, + { ADD, "A,D" }, { ADD, "A,E" }, { ADD, "A,H" }, { ADD, "A,L" }, + { ONA, "A,V" }, { ONA, "A,A" }, { ONA, "A,B" }, { ONA, "A,C" }, + { ONA, "A,D" }, { ONA, "A,E" }, { ONA, "A,H" }, { ONA, "A,L" }, + + { ADC, "A,V" }, { ADC, "A,A" }, { ADC, "A,B" }, { ADC, "A,C" }, + { ADC, "A,D" }, { ADC, "A,E" }, { ADC, "A,H" }, { ADC, "A,L" }, + { OFFA, "A,V" }, { OFFA, "A,A" }, { OFFA, "A,B" }, { OFFA, "A,C" }, + { OFFA, "A,D" }, { OFFA, "A,E" }, { OFFA, "A,H" }, { OFFA, "A,L" }, + + { SUB, "A,V" }, { SUB, "A,A" }, { SUB, "A,B" }, { SUB, "A,C" }, + { SUB, "A,D" }, { SUB, "A,E" }, { SUB, "A,H" }, { SUB, "A,L" }, + { NEA, "A,V" }, { NEA, "A,A" }, { NEA, "A,B" }, { NEA, "A,C" }, + { NEA, "A,D" }, { NEA, "A,E" }, { NEA, "A,H" }, { NEA, "A,L" }, + + { SBB, "A,V" }, { SBB, "A,A" }, { SBB, "A,B" }, { SBB, "A,C" }, + { SBB, "A,D" }, { SBB, "A,E" }, { SBB, "A,H" }, { SBB, "A,L" }, + { EQA, "A,V" }, { EQA, "A,A" }, { EQA, "A,B" }, { EQA, "A,C" }, + { EQA, "A,D" }, { EQA, "A,E" }, { EQA, "A,H" }, { EQA, "A,L" } +}; + +static const struct dasm_s dasm64_7801[256] = { + /* 0x00 - 0x3F */ + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { ANI, "V,%b" }, { ANI, "A,%b" }, { ANI, "B,%b" }, { ANI, "C,%b" }, + { ANI, "D,%b" }, { ANI, "E,%b" }, { ANI, "H,%b" }, { ANI, "L,%b" }, + + { XRI, "V,%b" }, { XRI, "A,%b" }, { XRI, "B,%b" }, { XRI, "C,%b" }, + { XRI, "D,%b" }, { XRI, "E,%b" }, { XRI, "H,%b" }, { XRI, "L,%b" }, + { ORI, "V,%b" }, { ORI, "A,%b" }, { ORI, "B,%b" }, { ORI, "C,%b" }, + { ORI, "D,%b" }, { ORI, "E,%b" }, { ORI, "H,%b" }, { ORI, "L,%b" }, + + { ADINC, "V,%b" }, { ADINC, "A,%b" }, { ADINC, "B,%b" }, { ADINC, "C,%b" }, + { ADINC, "D,%b" }, { ADINC, "E,%b" }, { ADINC, "H,%b" }, { ADINC, "L,%b" }, + { GTI, "V,%b" }, { GTI, "A,%b" }, { GTI, "B,%b" }, { GTI, "C,%b" }, + { GTI, "D,%b" }, { GTI, "E,%b" }, { GTI, "H,%b" }, { GTI, "L,%b" }, + + { SUINB, "V,%b" }, { SUINB, "A,%b" }, { SUINB, "B,%b" }, { SUINB, "C,%b" }, + { SUINB, "D,%b" }, { SUINB, "E,%b" }, { SUINB, "H,%b" }, { SUINB, "L,%b" }, + { LTI, "V,%b" }, { LTI, "A,%b" }, { LTI, "B,%b" }, { LTI, "C,%b" }, + { LTI, "D,%b" }, { LTI, "E,%b" }, { LTI, "H,%b" }, { LTI, "L,%b" }, + + /* 0x40 - 0x7F */ + { ADI, "V,%b" }, { ADI, "A,%b" }, { ADI, "B,%b" }, { ADI, "C,%b" }, + { ADI, "D,%b" }, { ADI, "E,%b" }, { ADI, "H,%b" }, { ADI, "L,%b" }, + { ONI, "V,%b" }, { ONI, "A,%b" }, { ONI, "B,%b" }, { ONI, "C,%b" }, + { ONI, "D,%b" }, { ONI, "E,%b" }, { ONI, "H,%b" }, { ONI, "L,%b" }, + + { ACI, "V,%b" }, { ACI, "A,%b" }, { ACI, "B,%b" }, { ACI, "C,%b" }, + { ACI, "D,%b" }, { ACI, "E,%b" }, { ACI, "H,%b" }, { ACI, "L,%b" }, + { OFFI, "V,%b" }, { OFFI, "A,%b" }, { OFFI, "B,%b" }, { OFFI, "C,%b" }, + { OFFI, "D,%b" }, { OFFI, "E,%b" }, { OFFI, "H,%b" }, { OFFI, "L,%b" }, + + { SUI, "V,%b" }, { SUI, "A,%b" }, { SUI, "B,%b" }, { SUI, "C,%b" }, + { SUI, "D,%b" }, { SUI, "E,%b" }, { SUI, "H,%b" }, { SUI, "L,%b" }, + { NEI, "V,%b" }, { NEI, "A,%b" }, { NEI, "B,%b" }, { NEI, "C,%b" }, + { NEI, "D,%b" }, { NEI, "E,%b" }, { NEI, "H,%b" }, { NEI, "L,%b" }, + + { SBI, "V,%b" }, { SBI, "A,%b" }, { SBI, "B,%b" }, { SBI, "C,%b" }, + { SBI, "D,%b" }, { SBI, "E,%b" }, { SBI, "H,%b" }, { SBI, "L,%b" }, + { EQI, "V,%b" }, { EQI, "A,%b" }, { EQI, "B,%b" }, { EQI, "C,%b" }, + { EQI, "D,%b" }, { EQI, "E,%b" }, { EQI, "H,%b" }, { EQI, "L,%b" }, + + /* 0x80 - 0xBF */ + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { ANI, "PA,%b" }, { ANI, "PB,%b" }, { ANI, "PC,%b" }, { ANI, "MK,%b" }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + { XRI, "PA,%b" }, { XRI, "PB,%b" }, { XRI, "PC,%b" }, { XRI, "MK,%b" }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { ORI, "PA,%b" }, { ORI, "PB,%b" }, { ORI, "PC,%b" }, { ORI, "MK,%b" }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + { ADINC, "PA,%b" }, { ADINC, "PB,%b" }, { ADINC, "PC,%b" }, { ADINC, "MK,%b" }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { GTI, "PA,%b" }, { GTI, "PB,%b" }, { GTI, "PC,%b" }, { GTI, "MK,%b" }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + { SUINB, "PA,%b" }, { SUINB, "PB,%b" }, { SUINB, "PC,%b" }, { SUINB, "MK,%b" }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { LTI, "PA,%b" }, { LTI, "PB,%b" }, { LTI, "PC,%b" }, { LTI, "MK,%b" }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + /* 0xC0 - 0xFF */ + { ADI, "PA,%b" }, { ADI, "PB,%b" }, { ADI, "PC,%b" }, { ADI, "MK,%b" }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { ONI, "PA,%b" }, { ONI, "PB,%b" }, { ONI, "PC,%b" }, { ONI, "MK,%b" }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + { ACI, "PA,%b" }, { ACI, "PB,%b" }, { ACI, "PC,%b" }, { ACI, "MK,%b" }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { OFFI, "PA,%b" }, { OFFI, "PB,%b" }, { OFFI, "PC,%b" }, { OFFI, "MK,%b" }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + { SUI, "PA,%b" }, { SUI, "PB,%b" }, { SUI, "PC,%b" }, { SUI, "MK,%b" }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { NEI, "PA,%b" }, { NEI, "PB,%b" }, { NEI, "PC,%b" }, { NEI, "MK,%b" }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + { SBI, "PA,%b" }, { SBI, "PB,%b" }, { SBI, "PC,%b" }, { SBI, "MK,%b" }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { EQI, "PA,%b" }, { EQI, "PB,%b" }, { EQI, "PC,%b" }, { EQI, "MK,%b" }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 } +}; + +static const struct dasm_s dasm70_7801[256] = { + /* 0x00 - 0x3F */ + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { SSPD, "%w" }, { LSPD, "%w" }, + + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { SBCD, "%w" }, { LBCD, "%w" }, + + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { SDED, "%w" }, { LDED, "%w" }, + + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { SHLD, "%w" }, { LHLD, "%w" }, + + /* 0x40 - 0x7F */ + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { MOV, "V,%w" }, { MOV, "A,%w" }, { MOV, "B,%w" }, { MOV, "C,%w" }, + { MOV, "D,%w" }, { MOV, "E,%w" }, { MOV, "H,%w" }, { MOV, "L,%w" }, + + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { MOV, "%w,V" }, { MOV, "%w,A" }, { MOV, "%w,B" }, { MOV, "%w,C" }, + { MOV, "%w,D" }, { MOV, "%w,E" }, { MOV, "%w,H" }, { MOV, "%w,L" }, + + /* 0x80 - 0xBF */ + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { ANAX, "BC" }, { ANAX, "DE" }, { ANAX, "HL" }, + { ANAX, "DE+" }, { ANAX, "HL+" }, { ANAX, "DE-" }, { ANAX, "HL-" }, + + { illegal, 0 }, { XRAX, "BC" }, { XRAX, "DE" }, { XRAX, "HL" }, + { XRAX, "DE+" }, { XRAX, "HL+" }, { XRAX, "DE-" }, { XRAX, "HL-" }, + { illegal, 0 }, { ORAX, "BC" }, { ORAX, "DE" }, { ORAX, "HL" }, + { ORAX, "DE+" }, { ORAX, "HL+" }, { ORAX, "DE-" }, { ORAX, "HL-" }, + + { illegal, 0 }, { ADDNCX, "BC" }, { ADDNCX, "DE" }, { ADDNCX, "HL" }, + { ADDNCX, "DE+" }, { ADDNCX, "HL+" }, { ADDNCX, "DE-" }, { ADDNCX, "HL-" }, + { illegal, 0 }, { GTAX, "BC" }, { GTAX, "DE" }, { GTAX, "HL" }, + { GTAX, "DE+" }, { GTAX, "HL+" }, { GTAX, "DE-" }, { GTAX, "HL-" }, + + { illegal, 0 }, { SUBNBX, "BC" }, { SUBNBX, "DE" }, { SUBNBX, "HL" }, + { SUBNBX, "DE+" }, { SUBNBX, "HL+" }, { SUBNBX, }, { SUBNBX, "HL-" }, + { illegal, 0 }, { LTAX, "BC" }, { LTAX, "DE" }, { LTAX, "HL" }, + { LTAX, "DE+" }, { LTAX, "HL+" }, { LTAX, "DE-" }, { LTAX, "HL-" }, + + /* 0xC0 - 0xFF */ + { illegal, 0 }, { ADDX, "BC" }, { ADDX, "DE" }, { ADDX, "HL" }, + { ADDX, "DE+" }, { ADDX, "HL+" }, { ADDX, "DE-" }, { ADDX, "HL-" }, + { illegal, 0 }, { ONAX, "BC" }, { ONAX, "DE" }, { ONAX, "HL" }, + { ONAX, "DE+" }, { ONAX, "HL+" }, { ONAX, "DE-" }, { ONAX, "HL-" }, + + { illegal, 0 }, { ADCX, "BC" }, { ADCX, "DE" }, { ADCX, "HL" }, + { ADCX, "DE+" }, { ADCX, "HL+" }, { ADCX, "DE-" }, { ADCX, "HL-" }, + { illegal, 0 }, { OFFAX, "BC" }, { OFFAX, "DE" }, { OFFAX, "HL" }, + { OFFAX, "DE+" }, { OFFAX, "HL+" }, { OFFAX, "DE-" }, { OFFAX, "HL-" }, + + { illegal, 0 }, { SUBX, "BC" }, { SUBX, "DE" }, { SUBX, "HL" }, + { SUBX, "DE+" }, { SUBX, "HL+" }, { SUBX, "DE-" }, { SUBX, "HL-" }, + { illegal, 0 }, { NEAX, "BC" }, { NEAX, "DE" }, { NEAX, "HL" }, + { NEAX, "DE+" }, { NEAX, "HL+" }, { NEAX, "DE-" }, { NEAX, "HL-" }, + + { illegal, 0 }, { SBBX, "BC" }, { SBBX, "DE" }, { SBBX, "HL" }, + { SBBX, "DE+" }, { SBBX, "HL+" }, { SBBX, "DE-" }, { SBBX, "HL-" }, + { illegal, 0 }, { EQAX, "BC" }, { EQAX, "DE" }, { EQAX, "HL" }, + { EQAX, "DE+" }, { EQAX, "HL+" }, { EQAX, "DE-" }, { EQAX, "HL-" }, +}; + +static const struct dasm_s dasm74_7801[256] = { + /* 0x00 - 0x3F */ + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + /* 0x40 - 0x7F */ + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + /* 0x80 - 0xBF */ + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { ANAW, "%a" }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + { XRAW, "%a" }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { ORAW, "%a" }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + { ADDNCW, "%a" }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { GTAW, "%a" }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + { SUBNBW, "%a" }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { LTAW, "%a" }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + /* 0xC0 - 0xFF */ + { ADDW, "%a" }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { ONAW, "%a" }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + { ADCW, "%a" }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { OFFAW, "%a" }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + { SUBW, "%a" }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { NEAW, "%a" }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + { SBBW, "%a" }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { EQAW, "%a" }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 } +}; + +static const struct dasm_s dasmXX_7801[256] = { + /* 0x00 - 0x3F */ + { NOP, 0 }, { HALT, 0 }, { INX, "SP" }, { DCX, "SP" }, + { LXI, "SP,%w" }, { ANIW, "%a,%b" }, { illegal, 0 }, { ANI, "A,%b" }, + { RET, 0 }, { SIO, 0 }, { MOV, "A,B" }, { MOV, "A,C" }, + { MOV, "A,D" }, { MOV, "A,E" }, { MOV, "A,H" }, { MOV, "A,L" }, + + { EX, 0 }, { EXX, 0 }, { INX, "BC" }, { DCX, "BC" }, + { LXI, "BC,%w" }, { ORIW, "%a,%b" }, { XRI, "A,%b" }, { ORI, "A,%b" }, + { RETS, 0 }, { STM, 0 }, { MOV, "B,A" }, { MOV, "C,A" }, + { MOV, "D,A" }, { MOV, "E,A" }, { MOV, "H,A" }, { MOV, "L,A" }, + + { INRW, "%a" }, { TABLE, 0 }, { INX, "DE" }, { DCX, "DE" }, + { LXI, "DE,%w" }, { GTIW, "%a,%b" }, { ADINC, "A,%b" }, { GTI, "A,%b" }, + { LDAW, "%a" }, { LDAX, "BC" }, { LDAX, "DE" }, { LDAX, "HL" }, + { LDAX, "DE+" }, { LDAX, "HL+" }, { LDAX, "DE-" }, { LDAX, "HL-" }, + + { DCRW, "%a" }, { BLOCK, 0 }, { INX, "HL" }, { DCX, "HL" }, + { LXI, "HL,%w" }, { LTIW, "%a,%b" }, { SUINB, "A,%b" }, { LTI, "A,%b" }, + { STAW, "%a" }, { STAX, "BC" }, { STAX, "DE" }, { STAX, "HL" }, + { STAX, "DE+" }, { STAX, "HL+" }, { STAX, "DE-" }, { STAX, "HL-" }, + + /* 0x40 - 0x7F */ + { illegal, 0 }, { INR, "A" }, { INR, "B" }, { INR, "C" }, + { CALL, "%w" }, { ONIW, "%a,%b" }, { ADI, "A,%b" }, { ONI, "A,%b" }, + { 0, dasm48_7801 }, { MVIX, "BC,%b" }, { MVIX, "DE,%b" }, { MVIX, "HL,%b" }, + { 0, dasm4c_7801 }, { 0, dasm4d_7801 }, { JRE, "%d" }, { JRE, "%d" }, + + { illegal, 0 }, { DCR, "A" }, { DCR, "B" }, { DCR, "C" }, + { JMP, "%w" }, { OFFIW, "%a,%b" }, { ACI, "A,%b" }, { OFFI, "A,%b" }, + { BIT, "0,%a" }, { BIT, "1,%a" }, { BIT," 2,%a" }, { BIT, "3,%a" }, + { BIT, "4,%a" }, { BIT, "5,%a" }, { BIT, "6,%a" }, { BIT, "7,%a" }, + + { 0, dasm60_7801 }, { DAA, 0 }, { RETI, 0 }, { CALB, 0 }, + { 0, dasm64_7801 }, { NEIW, "%a,%b" }, { SUI, "A,%b" }, { NEI, "A,%b" }, + { MVI, "V,%b" }, { MVI, "A,%b" }, { MVI, "B,%b" }, { MVI, "C,%b" }, + { MVI, "D,%b" }, { MVI, "E,%b" }, { MVI, "H,%b" }, { MVI, "L,%b" }, + + { 0, dasm70_7801 }, { MVIW, "%a,%b" }, { SOFTI, 0 }, { JB, 0 }, + { 0, dasm74_7801 }, { EQIW, "%a,%b" }, { SBI, "A,%b" }, { EQI, "A,%b" }, + { CALF, "%f" }, { CALF, "%f" }, { CALF, "%f" }, { CALF, "%f" }, + { CALF, "%f" }, { CALF, "%f" }, { CALF, "%f" }, { CALF, "%f" }, + + /* 0x80 - 0xBF */ + { CALT, "%t" }, { CALT, "%t" }, { CALT, "%t" }, { CALT, "%t" }, + { CALT, "%t" }, { CALT, "%t" }, { CALT, "%t" }, { CALT, "%t" }, + { CALT, "%t" }, { CALT, "%t" }, { CALT, "%t" }, { CALT, "%t" }, + { CALT, "%t" }, { CALT, "%t" }, { CALT, "%t" }, { CALT, "%t" }, + + { CALT, "%t" }, { CALT, "%t" }, { CALT, "%t" }, { CALT, "%t" }, + { CALT, "%t" }, { CALT, "%t" }, { CALT, "%t" }, { CALT, "%t" }, + { CALT, "%t" }, { CALT, "%t" }, { CALT, "%t" }, { CALT, "%t" }, + { CALT, "%t" }, { CALT, "%t" }, { CALT, "%t" }, { CALT, "%t" }, + + { CALT, "%t" }, { CALT, "%t" }, { CALT, "%t" }, { CALT, "%t" }, + { CALT, "%t" }, { CALT, "%t" }, { CALT, "%t" }, { CALT, "%t" }, + { CALT, "%t" }, { CALT, "%t" }, { CALT, "%t" }, { CALT, "%t" }, + { CALT, "%t" }, { CALT, "%t" }, { CALT, "%t" }, { CALT, "%t" }, + + { CALT, "%t" }, { CALT, "%t" }, { CALT, "%t" }, { CALT, "%t" }, + { CALT, "%t" }, { CALT, "%t" }, { CALT, "%t" }, { CALT, "%t" }, + { CALT, "%t" }, { CALT, "%t" }, { CALT, "%t" }, { CALT, "%t" }, + { CALT, "%t" }, { CALT, "%t" }, { CALT, "%t" }, { CALT, "%t" }, + + /* 0xC0 - 0xFF */ + { JR, "%o" }, { JR, "%o" }, { JR, "%o" }, { JR, "%o" }, + { JR, "%o" }, { JR, "%o" }, { JR, "%o" }, { JR, "%o" }, + { JR, "%o" }, { JR, "%o" }, { JR, "%o" }, { JR, "%o" }, + { JR, "%o" }, { JR, "%o" }, { JR, "%o" }, { JR, "%o" }, + + { JR, "%o" }, { JR, "%o" }, { JR, "%o" }, { JR, "%o" }, + { JR, "%o" }, { JR, "%o" }, { JR, "%o" }, { JR, "%o" }, + { JR, "%o" }, { JR, "%o" }, { JR, "%o" }, { JR, "%o" }, + { JR, "%o" }, { JR, "%o" }, { JR, "%o" }, { JR, "%o" }, + + { JR, "%o" }, { JR, "%o" }, { JR, "%o" }, { JR, "%o" }, + { JR, "%o" }, { JR, "%o" }, { JR, "%o" }, { JR, "%o" }, + { JR, "%o" }, { JR, "%o" }, { JR, "%o" }, { JR, "%o" }, + { JR, "%o" }, { JR, "%o" }, { JR, "%o" }, { JR, "%o" }, + + { JR, "%o" }, { JR, "%o" }, { JR, "%o" }, { JR, "%o" }, + { JR, "%o" }, { JR, "%o" }, { JR, "%o" }, { JR, "%o" }, + { JR, "%o" }, { JR, "%o" }, { JR, "%o" }, { JR, "%o" }, + { JR, "%o" }, { JR, "%o" }, { JR, "%o" }, { JR, "%o" } +}; + +/********************************************************* + * + * uPD7801 + * + *********************************************************/ + +static const struct dasm_s dasm48_78c05[256] = { + /* 0x00 - 0x3F */ + { SKIT, "F0" }, { SKIT, "FT" }, { SKIT, "F1" }, { illegal, 0 }, /* TODO: PDF doesn't mention SKIT and SK */ + { SKIT, "FS" }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { SK, "CY" }, { illegal, 0 }, + { SK, "Z" }, { illegal, 0 }, { PUSH, "VA" }, { POP, "VA" }, + + { SKNIT, "F0" }, { SKNIT, "FT" }, { SKNIT, "F1" }, { illegal, 0 }, + { SKNIT, "FS" }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { SKN, "CY" }, { illegal, 0 }, + { SKN, "Z" }, { illegal, 0 }, { PUSH, "BC" }, { POP, "BC" }, + + { EI, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { DI, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { CLC, 0 }, { STC, 0 }, + { illegal, 0 }, { PEX, 0 }, { PUSH, "DE" }, { POP, "DE" }, + + { RLL, "A" }, { RLR, "A" }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { RLD, 0 }, { RRD, 0 }, { illegal, 0 }, { illegal, 0 }, + { PER, 0 }, { illegal, 0 }, { PUSH, "HL" }, { POP, "HL" }, + + /* 0x40 - 0x7F */ + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + /* 0x80 - 0xBF */ + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + /* 0xC0 - 0xFF */ + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 } +}; + +static const struct dasm_s dasm4c_78c05[256] = { + /* 0x00 - 0x3F */ + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + /* 0x40 - 0x7F */ + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + /* 0x80 - 0xBF */ + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + /* 0xC0 - 0xFF */ + { MOV, "A,PA" }, { MOV, "A,PB" }, { MOV, "A,PC" }, { MOV, "A,MK" }, + { MOV, "A,MB" }, { MOV, "A,MC" }, { MOV, "A,TM0" }, { MOV, "A,TM1" }, + { MOV, "A,S" }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, /* TODO: Figure out what regsiter C9 indicates */ + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 } +}; + +static const struct dasm_s dasm4d_78c05[256] = { + /* 0x00 - 0x3F */ + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + /* 0x40 - 0x7F */ + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + /* 0x80 - 0xBF */ + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + /* 0xC0 - 0xFF */ + { MOV, "PA,A" }, { MOV, "PB,A" }, { MOV, "PC,A" }, { MOV, "MK,A" }, + { MOV, "MB,A" }, { MOV, "MC,A" }, { MOV, "TM0,A" }, { MOV, "TM1,A" }, + { MOV, "S,A" }, { MOV, "TMM,A" }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 } +}; + +static const struct dasm_s dasm60_78c05[256] = { + /* 0x00 - 0x3F */ + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { ANA, "A,A" }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + { illegal, 0 }, { XRA, "A,A" }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { ORA, "A,A" }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + { illegal, 0 }, { ADDNC, "A,A" }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { GTA, "A,A" }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + { illegal, 0 }, { SUBNB, "A,A" }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { LTA, "A,A" }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + /* 0x40 - 0x7F */ + { illegal, 0 }, { ADD, "A,A" }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + { illegal, 0 }, { ADC, "A,A" }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + { illegal, 0 }, { SUB, "A,A" }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { NEA, "A,A" }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + { illegal, 0 }, { SBB, "A,A" }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { EQA, "A,A" }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + /* 0x80 - 0xBF */ + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { ANA, "A,A" }, { ANA, "A,B" }, { ANA, "A,C" }, + { ANA, "A,D" }, { ANA, "A,E" }, { ANA, "A,H" }, { ANA, "A,L" }, + + { illegal, 0 }, { XRA, "A,A" }, { XRA, "A,B" }, { XRA, "A,C" }, + { XRA, "A,D" }, { XRA, "A,E" }, { XRA, "A,H" }, { XRA, "A,L" }, + { illegal, 0 }, { ORA, "A,A" }, { ORA, "A,B" }, { ORA, "A,C" }, + { ORA, "A,D" }, { ORA, "A,E" }, { ORA, "A,H" }, { ORA, "A,L" }, + + { illegal, 0 }, { ADDNC, "A,A" }, { ADDNC, "A,B" }, { ADDNC, "A,C" }, + { ADDNC, "A,D" }, { ADDNC, "A,E" }, { ADDNC, "A,H" }, { ADDNC, "A,L" }, + { illegal, 0 }, { GTA, "A,A" }, { GTA, "A,B" }, { GTA, "A,C" }, + { GTA, "A,D" }, { GTA, "A,E" }, { GTA, "A,H" }, { GTA, "A,L" }, + + { illegal, 0 }, { SUBNB, "A,A" }, { SUBNB, "A,B" }, { SUBNB, "A,C" }, + { SUBNB, "A,D" }, { SUBNB, "A,E" }, { SUBNB, "A,H" }, { SUBNB, "A,L" }, + { illegal, 0 }, { LTA, "A,A" }, { LTA, "A,B" }, { LTA, "A,C" }, + { LTA, "A,D" }, { LTA, "A,E" }, { LTA, "A,H" }, { LTA, "A,L" }, + + /* 0xC0 - 0xFF */ + { illegal, 0 }, { ADD, "A,A" }, { ADD, "A,B" }, { ADD, "A,C" }, + { ADD, "A,D" }, { ADD, "A,E" }, { ADD, "A,H" }, { ADD, "A,L" }, + { illegal, 0 }, { ONA, "A,A" }, { ONA, "A,B" }, { ONA, "A,C" }, + { ONA, "A,D" }, { ONA, "A,E" }, { ONA, "A,H" }, { ONA, "A,L" }, + + { illegal, 0 }, { ADC, "A,A" }, { ADC, "A,B" }, { ADC, "A,C" }, + { ADC, "A,D" }, { ADC, "A,E" }, { ADC, "A,H" }, { ADC, "A,L" }, + { illegal, 0 }, { OFFA, "A,A" }, { OFFA, "A,B" }, { OFFA, "A,C" }, + { OFFA, "A,D" }, { OFFA, "A,E" }, { OFFA, "A,H" }, { OFFA, "A,L" }, + + { illegal, 0 }, { SUB, "A,A" }, { SUB, "A,B" }, { SUB, "A,C" }, + { SUB, "A,D" }, { SUB, "A,E" }, { SUB, "A,H" }, { SUB, "A,L" }, + { illegal, 0 }, { NEA, "A,A" }, { NEA, "A,B" }, { NEA, "A,C" }, + { NEA, "A,D" }, { NEA, "A,E" }, { NEA, "A,H" }, { NEA, "A,L" }, + + { illegal, 0 }, { SBB, "A,A" }, { SBB, "A,B" }, { SBB, "A,C" }, + { SBB, "A,D" }, { SBB, "A,E" }, { SBB, "A,H" }, { SBB, "A,L" }, + { illegal, 0 }, { EQA, "A,A" }, { EQA, "A,B" }, { EQA, "A,C" }, + { EQA, "A,D" }, { EQA, "A,E" }, { EQA, "A,H" }, { EQA, "A,L" } +}; + +static const struct dasm_s dasm64_78c05[256] = { + /* 0x00 - 0x3F */ + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { ANI, "A,%b" }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + { illegal, 0 }, { XRI, "A,%b" }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { ORI, "A,%b" }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + { illegal, 0 }, { ADINC, "A,%b" }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { GTI, "A,%b" }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + { illegal, 0 }, { SUINB, "A,%b" }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { LTI, "A,%b" }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + /* 0x40 - 0x7F */ + { illegal, 0 }, { ADI, "A,%b" }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { ONI, "A,%b" }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + { illegal, 0 }, { ACI, "A,%b" }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { OFFI, "A,%b" }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + { illegal, 0 }, { SUI, "A,%b" }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { NEI, "A,%b" }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + { illegal, 0 }, { SBI, "A,%b" }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { EQI, "A,%b" }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + /* 0x80 - 0xBF */ + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { ANI, "PA,%b" }, { ANI, "PB,%b" }, { ANI, "PC,%b" }, { ANI, "MK,%b" }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + { XRI, "PA,%b" }, { XRI, "PB,%b" }, { XRI, "PC,%b" }, { XRI, "MK,%b" }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { ORI, "PA,%b" }, { ORI, "PB,%b" }, { ORI, "PC,%b" }, { ORI, "MK,%b" }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + { ADINC, "PA,%b" }, { ADINC, "PB,%b" }, { ADINC, "PC,%b" }, { ADINC, "MK,%b" }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { GTI, "PA,%b" }, { GTI, "PB,%b" }, { GTI, "PC,%b" }, { GTI, "MK,%b" }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + { SUINB, "PA,%b" }, { SUINB, "PB,%b" }, { SUINB, "PC,%b" }, { SUINB, "MK,%b" }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { LTI, "PA,%b" }, { LTI, "PB,%b" }, { LTI, "PC,%b" }, { LTI, "MK,%b" }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + /* 0xC0 - 0xFF */ + { ADI, "PA,%b" }, { ADI, "PB,%b" }, { ADI, "PC,%b" }, { ADI, "MK,%b" }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { ONI, "PA,%b" }, { ONI, "PB,%b" }, { ONI, "PC,%b" }, { ONI, "MK,%b" }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + { ACI, "PA,%b" }, { ACI, "PB,%b" }, { ACI, "PC,%b" }, { ACI, "MK,%b" }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { SUI, "PA,%b" }, { SUI, "PB,%b" }, { SUI, "PC,%b" }, { SUI, "MK,%b" }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + { NEI, "PA,%b" }, { NEI, "PB,%b" }, { NEI, "PC,%b" }, { NEI, "MK,%b" }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { SBI, "PA,%b" }, { SBI, "PB,%b" }, { SBI, "PC,%b" }, { SBI, "MK,%b" }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + { SBI, "PA,%b" }, { SBI, "PB,%b" }, { SBI, "PC,%b" }, { SBI, "MK,%b" }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { EQI, "PA,%b" }, { EQI, "PB,%b" }, { EQI, "PC,%b" }, { EQI, "MK,%b" }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 } +}; + +static const struct dasm_s dasm70_78c05[256] = { + /* 0x00 - 0x3F */ + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { SSPD, "%w" }, { LSPD, "%w" }, + + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { SBCD, "%w" }, { LBCD, "%w" }, + + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { SDED, "%w" }, { LDED, "%w" }, + + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { SHLD, "%w" }, { LHLD, "%w" }, + + /* 0x40 - 0x7F */ + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { MOV, "A,%w" }, { MOV, "B,%w" }, { MOV, "C,%w" }, + { MOV, "D,%w" }, { MOV, "E,%w" }, { MOV, "H,%w" }, { MOV, "L,%w" }, + + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { MOV, "%w,A" }, { MOV, "%w,B" }, { MOV, "%w,C" }, + { MOV, "%w,D" }, { MOV, "%w,E" }, { MOV, "%w,H" }, { MOV, "%w,L" }, + + /* 0x80 - 0xBF */ + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { ANAX, "BC" }, { ANAX, "DE" }, { ANAX, "HL" }, + { ANAX, "DE+" }, { ANAX, "HL+" }, { ANAX, "DE-" }, { ANAX, "HL-" }, + + { illegal, 0 }, { XRAX, "BC" }, { XRAX, "DE" }, { XRAX, "HL" }, + { XRAX, "DE+" }, { XRAX, "HL+" }, { XRAX, "DE-" }, { XRAX, "HL-" }, + { illegal, 0 }, { ORAX, "BC" }, { ORAX, "DE" }, { ORAX, "HL" }, + { ORAX, "DE+" }, { ORAX, "HL+" }, { ORAX, "DE-" }, { ORAX, "HL-" }, + + { illegal, 0 }, { ADDNCX, "BC" }, { ADDNCX, "DE" }, { ADDNCX, "HL" }, + { ADDNCX, "DE+" }, { ADDNCX, "HL+" }, { ADDNCX, "DE-" }, { ADDNCX, "HL-" }, + { illegal, 0 }, { GTAX, "BC" }, { GTAX, "DE" }, { GTAX, "HL" }, + { GTAX, "DE+" }, { GTAX, "HL+" }, { GTAX, "DE-" }, { GTAX, "HL-" }, + + { illegal, 0 }, { SUBNBX, "BC" }, { SUBNBX, "DE" }, { SUBNBX, "HL" }, + { SUBNBX, "DE+" }, { SUBNBX, "HL+" }, { SUBNBX, "DE-" }, { SUBNBX, "HL-" }, + { illegal, 0 }, { LTAX, "BC" }, { LTAX, "DE" }, { LTAX, "HL" }, + { LTAX, "DE+" }, { LTAX, "HL+" }, { LTAX, "DE-" }, { LTAX, "HL-" }, + + /* 0xC0 - 0xFF */ + { illegal, 0 }, { ADDX, "BC" }, { ADDX, "DE" }, { ADDX, "HL" }, + { ADDX, "DE+" }, { ADDX, "HL+" }, { ADDX, "DE-" }, { ADDX, "HL-" }, + { illegal, 0 }, { ONAX, "BC" }, { ONAX, "DE" }, { ONAX, "HL" }, + { ONAX, "DE+" }, { ONAX, "HL+" }, { ONAX, "DE-" }, { ONAX, "HL-" }, + + { illegal, 0 }, { ADCX, "BC" }, { ADCX, "DE" }, { ADCX, "HL" }, + { ADCX, "DE+" }, { ADCX, "HL+" }, { ADCX, "DE-" }, { ADCX, "HL-" }, + { illegal, 0 }, { OFFAX, "BC" }, { OFFAX, "DE" }, { OFFAX, "HL" }, + { OFFAX, "DE+" }, { OFFAX, "HL+" }, { OFFAX, "DE-" }, { OFFAX, "HL-" }, + + { illegal, 0 }, { SUBX, "BC" }, { SUBX, "DE" }, { SUBX, "HL" }, + { SUBX, "DE+" }, { SUBX, "HL+" }, { SUBX, "DE-" }, { SUBX, "HL-" }, + { illegal, 0 }, { NEAX, "BC" }, { NEAX, "DE" }, { NEAX, "HL" }, + { NEAX, "DE+" }, { NEAX, "HL+" }, { NEAX, "DE-" }, { NEAX, "HL-" }, + + { illegal, 0 }, { SBBX, "BC" }, { SBBX, "DE" }, { SBBX, "HL" }, + { SBBX, "DE+" }, { SBBX, "HL+" }, { SBBX, "DE-" }, { SBBX, "HL-" }, + { illegal, 0 }, { EQAX, "BC" }, { EQAX, "DE" }, { EQAX, "HL" }, + { EQAX, "DE+" }, { EQAX, "HL+" }, { EQAX, "DE-" }, { EQAX, "HL-" }, +}; + +static const struct dasm_s dasm74_78c05[256] = { + /* 0x00 - 0x3F */ + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + /* 0x40 - 0x7F */ + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + /* 0x80 - 0xBF */ + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { ANAW, "%a" }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + { XRAW, "%a" }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { ORAW, "%a" }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + { ADDNCW, "%a" }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { GTAW, "%a" }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + { SUBNBW, "%a" }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { LTAW, "%a" }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + /* 0xC0 - 0xFF */ + { ADDW, "%a" }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { ONAW, "%a" }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + { ADCW, "%a" }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { OFFAW, "%a" }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + { SUBW, "%a" }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { NEAW, "%a" }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + { SBBW, "%a" }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { EQAW, "%a" }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, +}; + +static const struct dasm_s dasmXX_78c05[256] = { + /* 0x00 - 0x3F */ + { NOP, 0 }, { HALT, 0 }, { INX, "SP" }, { DCX, "SP" }, + { LXI, "SP,%w" }, { ANIW, "%a,%b" }, { illegal, 0 }, { ANI, "A,%b" }, + { RET, 0 }, { SIO, 0 }, { MOV, "A,B" }, { MOV, "A,C" }, + { MOV, "A,D" }, { MOV, "A,E" }, { MOV, "A,H" }, { MOV, "A,L" }, + + { illegal, 0 }, { illegal, 0 }, { INX, "BC" }, { DCX, "BC" }, + { LXI, "BC,%w" }, { ORIW, "%a,%b" }, { XRI, "A,%b" }, { ORI, "A,%b" }, + { RETS, 0 }, { STM, 0 }, { MOV, "B,A" }, { MOV, "C,A" }, + { MOV, "D,A" }, { MOV, "E,A" }, { MOV, "H,A" }, { MOV, "L,A" }, + + { INRW, "%a" }, { illegal, 0 }, { INX, "DE" }, { DCX, "DE" }, + { LXI, "DE,%w" }, { GTIW, "%a,%b" }, { ADINC, "A,%b" }, { GTI, "A,%b" }, + { LDAW, "%a" }, { LDAX, "BC" }, { LDAX, "DE" }, { LDAX, "HL" }, + { LDAX, "DE+" }, { LDAX, "HL+" }, { LDAX, "DE-" }, { LDAX, "HL-" }, + + { DCRW, "%a" }, { illegal, 0 }, { INX, "HL" }, { DCX, "HL" }, + { LXI, "HL,%w" }, { LTIW, "%a,%b" }, { SUINB, "A,%b" }, { LTI, "A,%b" }, + { STAW, "%a" }, { STAX, "BC" }, { STAX, "DE" }, { STAX, "HL" }, + { STAX, "DE+" }, { STAX, "HL+" }, { STAX, "DE-" }, { STAX, "HL-" }, + + /* 0x40 - 0x7F */ + { illegal, 0 }, { INR, "A" }, { INR, "B" }, { INR, "C" }, + { CALL, "%w" }, { ONIW, "%a,%b" }, { ADI, "A,%b" }, { ONI, "A,%b" }, + { 0, dasm48_78c05 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { 0, dasm4c_78c05 }, { 0, dasm4d_78c05 }, { JRE, "%d" }, { JRE, "%d" }, + + { illegal, 0 }, { DCR, "A" }, { DCR, "B" }, { DCR, "C" }, + { JMP, "%w" }, { OFFIW, "%a,%b" }, { ACI, "A,%b" }, { OFFI, "A,%b" }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, { illegal, 0 }, + + { 0, dasm60_78c05 }, { DAA, 0 }, { RETI, 0 }, { CALB, 0 }, + { 0, dasm64_78c05 }, { NEIW, "%a,%b" }, { SUI, "A,%b" }, { NEI, "A,%b" }, + { illegal, 0 }, { MVI, "A,%b" }, { MVI, "B,%b" }, { MVI, "C,%b" }, + { MVI, "D,%b" }, { MVI, "E,%b" }, { MVI, "H,%b" }, { MVI, "L,%b" }, + + { 0, dasm70_78c05 }, { MVIW, "%a,%b" }, { SOFTI, 0 }, { JB, 0 }, + { 0, dasm74_78c05 }, { EQIW, "%a,%b" }, { SBI, "A,%b" }, { EQI, "A,%b" }, + { CALF, "%f" }, { CALF, "%f" }, { CALF, "%f" }, { CALF, "%f" }, + { CALF, "%f" }, { CALF, "%f" }, { CALF, "%f" }, { CALF, "%f" }, + + /* 0x80 - 0xBF */ + { CALT, "%t" }, { CALT, "%t" }, { CALT, "%t" }, { CALT, "%t" }, + { CALT, "%t" }, { CALT, "%t" }, { CALT, "%t" }, { CALT, "%t" }, + { CALT, "%t" }, { CALT, "%t" }, { CALT, "%t" }, { CALT, "%t" }, + { CALT, "%t" }, { CALT, "%t" }, { CALT, "%t" }, { CALT, "%t" }, + + { CALT, "%t" }, { CALT, "%t" }, { CALT, "%t" }, { CALT, "%t" }, + { CALT, "%t" }, { CALT, "%t" }, { CALT, "%t" }, { CALT, "%t" }, + { CALT, "%t" }, { CALT, "%t" }, { CALT, "%t" }, { CALT, "%t" }, + { CALT, "%t" }, { CALT, "%t" }, { CALT, "%t" }, { CALT, "%t" }, + + { CALT, "%t" }, { CALT, "%t" }, { CALT, "%t" }, { CALT, "%t" }, + { CALT, "%t" }, { CALT, "%t" }, { CALT, "%t" }, { CALT, "%t" }, + { CALT, "%t" }, { CALT, "%t" }, { CALT, "%t" }, { CALT, "%t" }, + { CALT, "%t" }, { CALT, "%t" }, { CALT, "%t" }, { CALT, "%t" }, + + { CALT, "%t" }, { CALT, "%t" }, { CALT, "%t" }, { CALT, "%t" }, + { CALT, "%t" }, { CALT, "%t" }, { CALT, "%t" }, { CALT, "%t" }, + { CALT, "%t" }, { CALT, "%t" }, { CALT, "%t" }, { CALT, "%t" }, + { CALT, "%t" }, { CALT, "%t" }, { CALT, "%t" }, { CALT, "%t" }, + + /* 0xC0 - 0xFF */ + { JR, "%o" }, { JR, "%o" }, { JR, "%o" }, { JR, "%o" }, + { JR, "%o" }, { JR, "%o" }, { JR, "%o" }, { JR, "%o" }, + { JR, "%o" }, { JR, "%o" }, { JR, "%o" }, { JR, "%o" }, + { JR, "%o" }, { JR, "%o" }, { JR, "%o" }, { JR, "%o" }, + + { JR, "%o" }, { JR, "%o" }, { JR, "%o" }, { JR, "%o" }, + { JR, "%o" }, { JR, "%o" }, { JR, "%o" }, { JR, "%o" }, + { JR, "%o" }, { JR, "%o" }, { JR, "%o" }, { JR, "%o" }, + { JR, "%o" }, { JR, "%o" }, { JR, "%o" }, { JR, "%o" }, + + { JR, "%o" }, { JR, "%o" }, { JR, "%o" }, { JR, "%o" }, + { JR, "%o" }, { JR, "%o" }, { JR, "%o" }, { JR, "%o" }, + { JR, "%o" }, { JR, "%o" }, { JR, "%o" }, { JR, "%o" }, + { JR, "%o" }, { JR, "%o" }, { JR, "%o" }, { JR, "%o" }, + + { JR, "%o" }, { JR, "%o" }, { JR, "%o" }, { JR, "%o" }, + { JR, "%o" }, { JR, "%o" }, { JR, "%o" }, { JR, "%o" }, + { JR, "%o" }, { JR, "%o" }, { JR, "%o" }, { JR, "%o" }, + { JR, "%o" }, { JR, "%o" }, { JR, "%o" }, { JR, "%o" } +}; + + +/* register names for bit manipulation instructions */ +static const char *const regname[32] = +{ + "illegal", "illegal", "illegal", "illegal", + "illegal", "illegal", "illegal", "illegal", + "illegal", "illegal", "illegal", "illegal", + "illegal", "illegal", "illegal", "illegal", + "PA", "PB", "PC", "PD", + "illegal", "PF", "MKH", "MKL", + "illegal", "SMH", "illegal", "EOM", + "illegal", "TMM", "PT", "illegal" +}; + +static offs_t Dasm( char *buffer, offs_t pc, const struct dasm_s *dasmXX, const UINT8 *oprom, const UINT8 *opram, int is_7810 ) +{ + int idx = 0; + UINT8 op = oprom[idx++], op2, t; + int offset; + UINT16 ea; + const char *a; + UINT32 flags = 0; + + t = dasmXX[op].token; + a = (const char *)dasmXX[op].args; + + /* 0 token means prefix opcode (use table from args) */ + if (0 == t) + { + struct dasm_s *p_dasm = (struct dasm_s *)a; + + op2 = oprom[idx++]; + t = p_dasm[op2].token; + a = (const char *)p_dasm[op2].args; + } + + buffer += sprintf(buffer, "%-8.8s", token[t]); + + if (t == CALB || t == CALF || t == CALL || t == CALT) + flags = DASMFLAG_STEP_OVER; + else if (t == RET || t == RETI) + flags = DASMFLAG_STEP_OUT; + + while (a && *a) + { + if ('%' == *a) + { + a++; + switch (*a) + { + case 'a': /* address V * 256 + offset */ + op2 = opram[idx++]; + buffer += sprintf(buffer, "VV:%02X", op2); + break; + case 'b': /* immediate byte */ + buffer += sprintf(buffer, "$%02X", opram[idx++]); + break; + case 'w': /* immediate word */ + ea = opram[idx++]; + ea += opram[idx++] << 8; + buffer += sprintf(buffer, "$%04X", ea); + break; + case 'd': /* JRE address */ + op2 = oprom[idx++]; + offset = (op & 1) ? -(256 - op2): + op2; + buffer += sprintf(buffer, "$%04X", ( pc + idx + offset ) & 0xFFFF ); + break; + case 't': /* CALT address */ + ea = 0x80 + 2 * (op & (is_7810 ? 0x1f : 0x3f)); + buffer += sprintf(buffer, "($%04X)", ea); + break; + case 'f': /* CALF address */ + op2 = oprom[idx++]; + ea = 0x800 + 0x100 * (op & 0x07) + op2; + buffer += sprintf(buffer, "$%04X", ea); + break; + case 'o': /* JR offset */ + offset = ( ( op & 0x20 ) ? -0x20 : 0 ) + ( op & 0x1F ); + buffer += sprintf(buffer, "$%04X", ( pc + idx + offset ) & 0xFFFF ); + break; + case 'i': /* bit manipulation */ + op2 = oprom[idx++]; + buffer += sprintf(buffer, "%s,%d", regname[op2 & 0x1f], op2 >> 5); + break; + default: + *buffer++ = *a; + } + } + else + *buffer++ = *a; + a++; + } + *buffer = '\0'; + + return idx | flags | DASMFLAG_SUPPORTED; +} + +CPU_DISASSEMBLE( upd7810 ) +{ + return Dasm( buffer, pc, dasmXX_7810, oprom, opram, 1 ); +} + +CPU_DISASSEMBLE( upd7807 ) +{ + return Dasm( buffer, pc, dasmXX_7807, oprom, opram, 1 ); +} + +CPU_DISASSEMBLE( upd7801 ) +{ + return Dasm( buffer, pc, dasmXX_7801, oprom, opram, 0 ); +} + +CPU_DISASSEMBLE( upd78c05 ) +{ + return Dasm( buffer, pc, dasmXX_78c05, oprom, opram, 0 ); +} diff --git a/src/devices/cpu/upd7810/upd7810_macros.h b/src/devices/cpu/upd7810/upd7810_macros.h new file mode 100644 index 00000000000..27783fb5d9a --- /dev/null +++ b/src/devices/cpu/upd7810/upd7810_macros.h @@ -0,0 +1,148 @@ +// license:BSD-3-Clause +// copyright-holders:Juergen Buchmueller +/*************************************************************************** + + uPD7810/11, 7810H/11H, 78C10/C11/C14 private use macros + +***************************************************************************/ + +//************************************************************************** +// REGISTER +//************************************************************************** + +#define PPC m_ppc.w.l +#define PC m_pc.w.l +#define PCL m_pc.b.l +#define PCH m_pc.b.h +#define PCD m_pc.d +#define SP m_sp.w.l +#define SPL m_sp.b.l +#define SPH m_sp.b.h +#define SPD m_sp.d +#define PSW m_psw +#define OP m_op +#define OP2 m_op2 +#define IFF m_iff +#define EA m_ea.w.l +#define EAL m_ea.b.l +#define EAH m_ea.b.h +#define VA m_va.w.l +#define V m_va.b.h +#define A m_va.b.l +#define VAD m_va.d +#define BC m_bc.w.l +#define B m_bc.b.h +#define C m_bc.b.l +#define DE m_de.w.l +#define D m_de.b.h +#define E m_de.b.l +#define HL m_hl.w.l +#define H m_hl.b.h +#define L m_hl.b.l +#define EA2 m_ea2.w.l +#define VA2 m_va2.w.l +#define BC2 m_bc2.w.l +#define DE2 m_de2.w.l +#define HL2 m_hl2.w.l + +#define OVC0 m_ovc0 +#define OVC1 m_ovc1 +#define OVCE m_ovce +#define OVCF m_ovcf +#define OVCS m_ovcs +#define EDGES m_edges + +#define CNT0 m_cnt.b.l +#define CNT1 m_cnt.b.h +#define TM0 m_tm.b.l +#define TM1 m_tm.b.h +#define ECNT m_ecnt.w.l +#define ECPT m_ecnt.w.h +#define ETM0 m_etm.w.l +#define ETM1 m_etm.w.h + +#define MA m_ma +#define MB m_mb +#define MCC m_mcc +#define MC m_mc +#define MM m_mm +#define MF m_mf +#define TMM m_tmm +#define ETMM m_etmm +#define EOM m_eom +#define SML m_sml +#define SMH m_smh +#define PANM m_panm +#define ANM m_anm +#define MKL m_mkl +#define MKH m_mkh +#define ZCM m_zcm + +#define CR0 m_cr0 +#define CR1 m_cr1 +#define CR2 m_cr2 +#define CR3 m_cr3 +#define RXB m_rxb +#define TXB m_txb + +#define RXD m_rxd +#define TXD m_txd +#define SCK m_sck +#define TI m_ti +#define TO m_to +#define CI m_ci +#define LV0 m_lv0 +#define LV1 m_lv1 +#define CO0 m_co0 +#define CO1 m_co1 + +#define IRR m_irr +#define ITF m_itf + + +//************************************************************************** +// MEMORY/OPCODE READ/WRITE +//************************************************************************** + +#define RDOP(O) O = m_direct->read_byte(PCD); PC++ +#define RDOPARG(A) A = m_direct->read_byte(PCD); PC++ +#define RM(A) m_program->read_byte(A) +#define WM(A,V) m_program->write_byte(A,V) + + +//************************************************************************** +// PSW OPERATIONS +//************************************************************************** + +#define ZHC_ADD(after,before,carry) \ + if (after == 0) PSW |= Z; else PSW &= ~Z; \ + if (after == before) \ + PSW = (PSW&~CY) | (carry); \ + else if (after < before) \ + PSW |= CY; \ + else \ + PSW &= ~CY; \ + if ((after & 15) < (before & 15)) \ + PSW |= HC; \ + else \ + PSW &= ~HC; + +#define ZHC_SUB(after,before,carry) \ + if (after == 0) PSW |= Z; else PSW &= ~Z; \ + if (before == after) \ + PSW = (PSW & ~CY) | (carry); \ + else if (after > before) \ + PSW |= CY; \ + else \ + PSW &= ~CY; \ + if ((after & 15) > (before & 15)) \ + PSW |= HC; \ + else \ + PSW &= ~HC; + +#define SKIP_CY if (CY == (PSW & CY)) PSW |= SK +#define SKIP_NC if (0 == (PSW & CY)) PSW |= SK +#define SKIP_Z if (Z == (PSW & Z)) PSW |= SK +#define SKIP_NZ if (0 == (PSW & Z)) PSW |= SK + +#define SET_Z(n) if (n) PSW &= ~Z; else PSW |= Z diff --git a/src/devices/cpu/upd7810/upd7810_opcodes.c b/src/devices/cpu/upd7810/upd7810_opcodes.c new file mode 100644 index 00000000000..ab4589222c1 --- /dev/null +++ b/src/devices/cpu/upd7810/upd7810_opcodes.c @@ -0,0 +1,9485 @@ +// license:BSD-3-Clause +// copyright-holders:Juergen Buchmueller +/***************************************************************************** + * + * Portable uPD7810/11, 7810H/11H, 78C10/C11/C14 emulator V0.2 + * + * 7810ops.inc - opcode functions + * + *****************************************************************************/ + +#include "emu.h" +#include "upd7810.h" +#include "upd7810_macros.h" + +void upd7810_device::illegal() +{ + logerror("uPD7810 '%s': illegal opcode %02x at PC:%04x\n", tag(), OP, PC); +} + +void upd7810_device::illegal2() +{ + logerror("uPD7810 '%s': illegal opcode %02x %02x at PC:%04x\n", tag(), OP, OP2, PC); +} + +/* prefix 48 */ + +/* 48 01: 0100 1000 0000 0001 */ +void upd7810_device::SLRC_A() +{ + PSW = (PSW & ~CY) | (A & CY); + A >>= 1; + SKIP_CY; +} + +/* 48 02: 0100 1000 0000 0010 */ +void upd7810_device::SLRC_B() +{ + PSW = (PSW & ~CY) | (B & CY); + B >>= 1; + SKIP_CY; +} + +/* 48 03: 0100 1000 0000 0011 */ +void upd7810_device::SLRC_C() +{ + PSW = (PSW & ~CY) | (C & CY); + C >>= 1; + SKIP_CY; +} + + +/* 48 05: 0100 1000 0000 0101 */ +void upd7810_device::SLLC_A() +{ + PSW = (PSW & ~CY) | ((A >> 7) & CY); + A <<= 1; + SKIP_CY; +} + +/* 48 06: 0100 1000 0000 0110 */ +void upd7810_device::SLLC_B() +{ + PSW = (PSW & ~CY) | ((B >> 7) & CY); + B <<= 1; + SKIP_CY; +} + +/* 48 07: 0100 1000 0000 0111 */ +void upd7810_device::SLLC_C() +{ + PSW = (PSW & ~CY) | ((C >> 7) & CY); + C <<= 1; + SKIP_CY; +} + +/* 48 08: 0100 1000 0000 1000 */ +void upd7810_device::SK_NV() +{ + /* 48 skip never */ +} + +/* 48 0a: 0100 1000 0000 1010 */ +void upd7810_device::SK_CY() +{ + if (CY == (PSW & CY)) + PSW |= SK; +} + +/* 48 0b: 0100 1000 0000 1011 */ +void upd7810_device::SK_HC() +{ + if (HC == (PSW & HC)) + PSW |= SK; +} + +/* 48 0c: 0100 1000 0000 1100 */ +void upd7810_device::SK_Z() +{ + if (Z == (PSW & Z)) + PSW |= SK; +} + +/* 48 18: 0100 1000 0001 1000 */ +void upd7810_device::SKN_NV() +{ + /* skip not never -> skip always ;-) */ + PSW |= SK; +} + +/* 48 1a: 0100 1000 0001 1010 */ +void upd7810_device::SKN_CY() +{ + if (0 == (PSW & CY)) + PSW |= SK; +} + +/* 48 1b: 0100 1000 0001 1011 */ +void upd7810_device::SKN_HC() +{ + if (0 == (PSW & HC)) + PSW |= SK; +} + +/* 48 1c: 0100 1000 0001 1100 */ +void upd7810_device::SKN_Z() +{ + if (0 == (PSW & Z)) + PSW |= SK; +} + +/* 48 21: 0100 1000 0010 0001 */ +void upd7810_device::SLR_A() +{ + PSW = (PSW & ~CY) | (A & CY); + A >>= 1; +} + +/* 48 22: 0100 1000 0010 0010 */ +void upd7810_device::SLR_B() +{ + PSW = (PSW & ~CY) | (B & CY); + B >>= 1; +} + +/* 48 23: 0100 1000 0010 0011 */ +void upd7810_device::SLR_C() +{ + PSW = (PSW & ~CY) | (C & CY); + C >>= 1; +} + +/* 48 25: 0100 1000 0010 0101 */ +void upd7810_device::SLL_A() +{ + PSW = (PSW & ~CY) | ((A >> 7) & CY); + A <<= 1; +} + +/* 48 26: 0100 1000 0010 0110 */ +void upd7810_device::SLL_B() +{ + PSW = (PSW & ~CY) | ((B >> 7) & CY); + B <<= 1; +} + +/* 48 27: 0100 1000 0010 0111 */ +void upd7810_device::SLL_C() +{ + PSW = (PSW & ~CY) | ((C >> 7) & CY); + C <<= 1; +} + +/* 48 28: 0100 1000 0010 1000 */ +void upd7810_device::JEA() +{ + PC = EA; +} + +/* 48 29: 0100 1000 0010 1001 */ +void upd7810_device::CALB() +{ + SP--; + WM( SPD, PCH ); + SP--; + WM( SPD, PCL ); + + PC = BC; +} + +/* 48 2a: 0100 1000 0010 1010 */ +void upd7810_device::CLC() +{ + PSW &= ~CY; +} + +/* 48 2b: 0100 1000 0010 1011 */ +void upd7810_device::STC() +{ + PSW |= CY; +} + +/* 48 2d: 0100 1000 0010 1101 */ +void upd7810_device::MUL_A() +{ + EA = A * A; +} + +/* 48 2e: 0100 1000 0010 1110 */ +void upd7810_device::MUL_B() +{ + EA = A * B; +} + +/* 48 2f: 0100 1000 0010 1111 */ +void upd7810_device::MUL_C() +{ + EA = A * C; +} + +/* 48 31: 0100 1000 0011 0001 */ +void upd7810_device::RLR_A() +{ + UINT8 carry=(PSW&CY)<<7; + PSW = (PSW & ~CY) | (A & CY); + A = (A >> 1) | carry; +} + +/* 48 32: 0100 1000 0011 0010 */ +void upd7810_device::RLR_B() +{ + UINT8 carry=(PSW&CY)<<7; + PSW = (PSW & ~CY) | (B & CY); + B = (B >> 1) | carry; +} + +/* 48 33: 0100 1000 0011 0011 */ +void upd7810_device::RLR_C() +{ + UINT8 carry=(PSW&CY)<<7; + PSW = (PSW & ~CY) | (C & CY); + C = (C >> 1) | carry; +} + +/* 48 35: 0100 1000 0011 0101 */ +void upd7810_device::RLL_A() +{ + UINT8 carry=PSW&CY; + PSW = (PSW & ~CY) | ((A >> 7) & CY); + A = (A << 1) | carry; +} + +/* 48 36: 0100 1000 0011 0110 */ +void upd7810_device::RLL_B() +{ + UINT8 carry=PSW&CY; + PSW = (PSW & ~CY) | ((B >> 7) & CY); + B = (B << 1) | carry; +} + +/* 48 37: 0100 1000 0011 0111 */ +void upd7810_device::RLL_C() +{ + UINT8 carry=PSW&CY; + PSW = (PSW & ~CY) | ((C >> 7) & CY); + C = (C << 1) | carry; +} + +/* 48 38: 0100 1000 0011 1000 */ +void upd7810_device::RLD() +{ + UINT8 m = RM( HL ), tmp; + tmp = (m << 4) | (A & 0x0f); + A = (A & 0xf0) | (m >> 4); + WM( HL, tmp ); +} + +/* 48 39: 0100 1000 0011 1001 */ +void upd7810_device::RRD() +{ + UINT8 m = RM( HL ), tmp; + tmp = (A << 4) | (m >> 4); + A = (A & 0xf0) | (m & 0x0f); + WM( HL, tmp ); +} + +/* 48 3a: 0100 1000 0011 1010 */ +void upd7810_device::NEGA() +{ + A = ~A + 1; +} + +/* 48 3b: 0100 1000 0011 1011 */ +void upd7810_device::HALT() +{ + int cycles = (m_icount / 4) * 4; + m_icount -= cycles; + handle_timers(cycles); + PC -= 1; /* continue executing HALT */ +} + +/* 48 3d: 0100 1000 0011 1101 */ +void upd7810_device::DIV_A() +{ + if (A) + { + UINT8 remainder; + remainder = EA % A; + EA /= A; + A = remainder; + } + else + EA = 0xffff; /* guess */ +} + +/* 48 3e: 0100 1000 0011 1110 */ +void upd7810_device::DIV_B() +{ + if (B) + { + UINT8 remainder; + remainder = EA % B; + EA /= B; + B = remainder; + } + else + EA = 0xffff; /* guess */ +} + +/* 48 3f: 0100 1000 0011 1111 */ +void upd7810_device::DIV_C() +{ + if (C) + { + UINT8 remainder; + remainder = EA % C; + EA /= C; + C = remainder; + } + else + EA = 0xffff; /* guess */ +} + +/* 48 40: 0100 1000 0100 0000 */ +void upd7810_device::SKIT_NMI() +{ + if (IRR & INTNMI) + PSW |= SK; + IRR &= ~INTNMI; +} + +/* 48 41: 0100 1000 0100 0001 */ +void upd7810_device::SKIT_FT0() +{ + if (IRR & INTFT0) + PSW |= SK; + IRR &= ~INTFT0; +} + +/* 48 42: 0100 1000 0100 0010 */ +void upd7810_device::SKIT_FT1() +{ + if (IRR & INTFT1) + PSW |= SK; + IRR &= ~INTFT1; +} + +/* 48 43: 0100 1000 0100 0011 */ +void upd7810_device::SKIT_F1() +{ + if (IRR & INTF1) + PSW |= SK; + IRR &= ~INTF1; +} + +/* 48 44: 0100 1000 0100 0100 */ +void upd7810_device::SKIT_F2() +{ + if (IRR & INTF2) + PSW |= SK; + IRR &= ~INTF2; +} + +/* 48 45: 0100 1000 0100 0101 */ +void upd7810_device::SKIT_FE0() +{ + if (IRR & INTFE0) + PSW |= SK; + IRR &= ~INTFE0; +} + +/* 48 46: 0100 1000 0100 0110 */ +void upd7810_device::SKIT_FE1() +{ + if (IRR & INTFE1) + PSW |= SK; + IRR &= ~INTFE1; +} + +/* 48 47: 0100 1000 0100 0111 */ +void upd7810_device::SKIT_FEIN() +{ + if (IRR & INTFEIN) + PSW |= SK; + IRR &= ~INTFEIN; +} + +/* 48 48: 0100 1000 0100 1000 */ +void upd7810_device::SKIT_FAD() +{ + if (IRR & INTFAD) + PSW |= SK; + IRR &= ~INTFAD; +} + +/* 48 49: 0100 1000 0100 1001 */ +void upd7810_device::SKIT_FSR() +{ + if (IRR & INTFSR) + PSW |= SK; + IRR &= ~INTFSR; +} + +/* 48 4a: 0100 1000 0100 1010 */ +void upd7810_device::SKIT_FST() +{ + if (IRR & INTFST) + PSW |= SK; + IRR &= ~INTFST; +} + +/* 48 4b: 0100 1000 0100 1011 */ +void upd7810_device::SKIT_ER() +{ + if (IRR & INTER) + PSW |= SK; + IRR &= ~INTER; +} + +/* 48 4c: 0100 1000 0100 1100 */ +void upd7810_device::SKIT_OV() +{ + if (IRR & INTOV) + PSW |= SK; + IRR &= ~INTOV; +} + +/* 48 50: 0100 1000 0101 0000 */ +void upd7810_device::SKIT_AN4() +{ + if (ITF & INTAN4) + PSW |= SK; + ITF &= ~INTAN4; +} + +/* 48 51: 0100 1000 0101 0001 */ +void upd7810_device::SKIT_AN5() +{ + if (ITF & INTAN5) + PSW |= SK; + ITF &= ~INTAN5; +} + +/* 48 52: 0100 1000 0101 0010 */ +void upd7810_device::SKIT_AN6() +{ + if (ITF & INTAN6) + PSW |= SK; + ITF &= ~INTAN6; +} + +/* 48 53: 0100 1000 0101 0011 */ +void upd7810_device::SKIT_AN7() +{ + if (ITF & INTAN7) + PSW |= SK; + ITF &= ~INTAN7; +} + +/* 48 54: 0100 1000 0101 0100 */ +void upd7810_device::SKIT_SB() +{ + if (ITF & INTSB) + PSW |= SK; + ITF &= ~INTSB; +} + +/* 48 60: 0100 1000 0110 0000 */ +void upd7810_device::SKNIT_NMI() +{ + if (0 == (IRR & INTNMI)) + PSW |= SK; + IRR &= ~INTNMI; +} + +/* 48 61: 0100 1000 0110 0001 */ +void upd7810_device::SKNIT_FT0() +{ + if (0 == (IRR & INTFT0)) + PSW |= SK; + IRR &= ~INTFT0; +} + +/* 48 62: 0100 1000 0110 0010 */ +void upd7810_device::SKNIT_FT1() +{ + if (0 == (IRR & INTFT1)) + PSW |= SK; + IRR &= ~INTFT1; +} + +/* 48 63: 0100 1000 0110 0011 */ +void upd7810_device::SKNIT_F1() +{ + if (0 == (IRR & INTF1)) + PSW |= SK; + IRR &= ~INTF1; +} + +/* 48 64: 0100 1000 0110 0100 */ +void upd7810_device::SKNIT_F2() +{ + if (0 == (IRR & INTF2)) + PSW |= SK; + IRR &= ~INTF2; +} + +/* 48 65: 0100 1000 0110 0101 */ +void upd7810_device::SKNIT_FE0() +{ + if (0 == (IRR & INTFE0)) + PSW |= SK; + IRR &= ~INTFE0; +} + +/* 48 66: 0100 1000 0110 0110 */ +void upd7810_device::SKNIT_FE1() +{ + if (0 == (IRR & INTFE1)) + PSW |= SK; + IRR &= ~INTFE1; +} + +/* 48 67: 0100 1000 0110 0111 */ +void upd7810_device::SKNIT_FEIN() +{ + if (0 == (IRR & INTFEIN)) + PSW |= SK; + IRR &= ~INTFEIN; +} + +/* 48 68: 0100 1000 0110 1000 */ +void upd7810_device::SKNIT_FAD() +{ + if (0 == (IRR & INTFAD)) + PSW |= SK; + IRR &= ~INTFAD; +} + +/* 48 69: 0100 1000 0110 1001 */ +void upd7810_device::SKNIT_FSR() +{ + if (0 == (IRR & INTFSR)) + PSW |= SK; + IRR &= ~INTFSR; +} + +/* 48 6a: 0100 1000 0110 1010 */ +void upd7810_device::SKNIT_FST() +{ + if (0 == (IRR & INTFST)) + PSW |= SK; + IRR &= ~INTFST; +} + +/* 48 6b: 0100 1000 0110 1011 */ +void upd7810_device::SKNIT_ER() +{ + if (0 == (IRR & INTER)) + PSW |= SK; + IRR &= ~INTER; +} + +/* 48 6c: 0100 1000 0110 1100 */ +void upd7810_device::SKNIT_OV() +{ + if (0 == (IRR & INTOV)) + PSW |= SK; + IRR &= ~INTOV; +} + +/* 48 70: 0100 1000 0111 0000 */ +void upd7810_device::SKNIT_AN4() +{ + if (0 == (ITF & INTAN4)) + PSW |= SK; + ITF &= ~INTAN4; +} + +/* 48 71: 0100 1000 0111 0001 */ +void upd7810_device::SKNIT_AN5() +{ + if (0 == (ITF & INTAN5)) + PSW |= SK; + ITF &= ~INTAN5; +} + +/* 48 72: 0100 1000 0111 0010 */ +void upd7810_device::SKNIT_AN6() +{ + if (0 == (ITF & INTAN6)) + PSW |= SK; + ITF &= ~INTAN6; +} + +/* 48 73: 0100 1000 0111 0011 */ +void upd7810_device::SKNIT_AN7() +{ + if (0 == (ITF & INTAN7)) + PSW |= SK; + ITF &= ~INTAN7; +} + +/* 48 74: 0100 1000 0111 0100 */ +void upd7810_device::SKNIT_SB() +{ + if (0 == (ITF & INTSB)) + PSW |= SK; + ITF &= ~INTSB; +} + +/* 48 82: 0100 1000 1000 0010 */ +void upd7810_device::LDEAX_D() +{ + EAL = RM( DE ); + EAH = RM( DE + 1 ); +} + +/* 48 83: 0100 1000 1000 0011 */ +void upd7810_device::LDEAX_H() +{ + EAL = RM( HL ); + EAH = RM( HL + 1 ); +} + +/* 48 84: 0100 1000 1000 0100 */ +void upd7810_device::LDEAX_Dp() +{ + EAL = RM( DE ); + EAH = RM( DE + 1 ); + DE += 2; +} + +/* 48 85: 0100 1000 1000 0101 */ +void upd7810_device::LDEAX_Hp() +{ + EAL = RM( HL ); + EAH = RM( HL + 1 ); + HL += 2; +} + +/* 48 8b: 0100 1000 1000 1011 xxxx xxxx */ +void upd7810_device::LDEAX_D_xx() +{ + UINT16 ea; + RDOPARG( ea ); + ea += DE; + EAL = RM( ea ); + EAH = RM( ea + 1 ); +} + +/* 48 8c: 0100 1000 1000 1100 */ +void upd7810_device::LDEAX_H_A() +{ + UINT16 ea = HL + A; + EAL = RM( ea ); + EAH = RM( ea + 1 ); +} + +/* 48 8d: 0100 1000 1000 1101 */ +void upd7810_device::LDEAX_H_B() +{ + UINT16 ea = HL + B; + EAL = RM( ea ); + EAH = RM( ea + 1 ); +} + +/* 48 8e: 0100 1000 1000 1110 */ +void upd7810_device::LDEAX_H_EA() +{ + UINT16 ea = HL + EA; + EAL = RM( ea ); + EAH = RM( ea + 1 ); +} + +/* 48 8f: 0100 1000 1000 1111 xxxx xxxx */ +void upd7810_device::LDEAX_H_xx() +{ + UINT16 ea; + RDOPARG( ea ); + ea += HL; + EAL = RM( ea ); + EAH = RM( ea + 1 ); +} + +/* 48 92: 0100 1000 1000 0010 */ +void upd7810_device::STEAX_D() +{ + WM( DE, EAL ); + WM( DE + 1, EAH ); +} + +/* 48 93: 0100 1000 1000 0011 */ +void upd7810_device::STEAX_H() +{ + WM( HL, EAL ); + WM( HL + 1, EAH ); +} + +/* 48 94: 0100 1000 1000 0100 */ +void upd7810_device::STEAX_Dp() +{ + WM( DE, EAL ); + WM( DE + 1, EAH ); + DE += 2; +} + +/* 48 95: 0100 1000 1000 0101 */ +void upd7810_device::STEAX_Hp() +{ + WM( HL, EAL ); + WM( HL + 1, EAH ); + HL += 2; +} + +/* 48 9b: 0100 1000 1000 1011 xxxx xxxx */ +void upd7810_device::STEAX_D_xx() +{ + UINT16 ea; + RDOPARG( ea ); + ea += DE; + WM( ea, EAL ); + WM( ea + 1, EAH ); +} + +/* 48 9c: 0100 1000 1000 1100 */ +void upd7810_device::STEAX_H_A() +{ + UINT16 ea = HL + A; + WM( ea, EAL ); + WM( ea + 1, EAH ); +} + +/* 48 9d: 0100 1000 1000 1101 */ +void upd7810_device::STEAX_H_B() +{ + UINT16 ea = HL + B; + WM( ea, EAL ); + WM( ea + 1, EAH ); +} + +/* 48 9e: 0100 1000 1000 1110 */ +void upd7810_device::STEAX_H_EA() +{ + UINT16 ea = HL + EA; + WM( ea, EAL ); + WM( ea + 1, EAH ); +} + +/* 48 9f: 0100 1000 1000 1111 xxxx xxxx */ +void upd7810_device::STEAX_H_xx() +{ + UINT16 ea; + RDOPARG( ea ); + ea += HL; + WM( ea, EAL ); + WM( ea + 1, EAH ); +} + +/* 48 a0: 0100 1000 1010 0000 */ +void upd7810_device::DSLR_EA() +{ + PSW = (PSW & ~CY) | (EA & CY); + EA >>= 1; +} + +/* 48 a4: 0100 1000 1010 0100 */ +void upd7810_device::DSLL_EA() +{ + PSW = (PSW & ~CY) | ((EA >> 15) & CY); + EA <<= 1; +} + +/* 48 a8: 0100 1000 1010 1000 */ +void upd7810_device::TABLE() +{ + UINT16 ea = PC + A + 1; + C = RM( ea ); + B = RM( ea + 1 ); +} + +/* 48 b0: 0100 1000 1011 0000 */ +void upd7810_device::DRLR_EA() +{ + UINT8 carry=PSW&CY; + PSW = (PSW & ~CY) | (EA & CY); + EA = (EA >> 1) | (carry << 15); +} + +/* 48 b4: 0100 1000 1011 0100 */ +void upd7810_device::DRLL_EA() +{ + UINT8 carry=PSW&CY; + PSW = (PSW & ~CY) | ((EA >> 15) & CY); + EA = (EA << 1) | carry; +} + +/* 48 bb: 0100 1000 1011 1011 */ +void upd7810_device::STOP() +{ + int cycles = (m_icount / 4) * 4; + m_icount -= cycles; + handle_timers(cycles); + PC -= 1; +} + +/* 48 c0: 0100 1000 1100 0000 */ +void upd7810_device::DMOV_EA_ECNT() +{ + EA = ECNT; +} + +/* 48 c1: 0100 1000 1100 0001 */ +void upd7810_device::DMOV_EA_ECPT() +{ + EA = ECPT; +} + +/* 48 d2: 0100 1000 1101 0010 */ +void upd7810_device::DMOV_ETM0_EA() +{ + ETM0 = EA; +} + +/* 48 d3: 0100 1000 1101 0011 */ +void upd7810_device::DMOV_ETM1_EA() +{ + ETM1 = EA; +} + +/* prefix 4C */ +/* 4c c0: 0100 1100 1100 0000 */ +void upd7810_device::MOV_A_PA() +{ + A = RP( UPD7810_PORTA ); +} + +/* 4c c1: 0100 1100 1100 0001 */ +void upd7810_device::MOV_A_PB() +{ + A = RP( UPD7810_PORTB ); +} + +/* 4c c2: 0100 1100 1100 0010 */ +void upd7810_device::MOV_A_PC() +{ + A = RP( UPD7810_PORTC ); +} + +/* 4c c3: 0100 1100 1100 0011 */ +void upd7810_device::MOV_A_PD() +{ + A = RP( UPD7810_PORTD ); +} + +/* 4c c5: 0100 1100 1100 0101 */ +void upd7810_device::MOV_A_PF() +{ + A = RP( UPD7810_PORTF ); +} + +/* 4c c6: 0100 1100 1100 0110 */ +void upd7810_device::MOV_A_MKH() +{ + A = MKH; +} + +/* 4c c7: 0100 1100 1100 0111 */ +void upd7810_device::MOV_A_MKL() +{ + A = MKL; +} + +/* 4c c8: 0100 1100 1100 1000 */ +void upd7810_device::MOV_A_ANM() +{ + A = ANM; +} + +/* 4c c9: 0100 1100 1100 1001 */ +void upd7810_device::MOV_A_SMH() +{ + A = SMH; +} + +/* 4c cb: 0100 1100 1100 1011 */ +void upd7810_device::MOV_A_EOM() +{ + /* only bits #1 and #5 can be read */ + UINT8 eom = EOM & 0x22; + A = eom; +} + +/* 4c cd: 0100 1100 1100 1101 */ +void upd7810_device::MOV_A_TMM() +{ + A = TMM; +} + +/* 4c ce: 0100 1100 1110 0000 (7807 only) */ +void upd7810_device::MOV_A_PT() +{ + A = RP( UPD7807_PORTT ); +} + +/* 4c d9: 0100 1100 1101 1001 */ +void upd7810_device::MOV_A_RXB() +{ + A = RXB; +} + +/* 4c e0: 0100 1100 1110 0000 */ +void upd7810_device::MOV_A_CR0() +{ + A = CR0; +} + +/* 4c e1: 0100 1100 1110 0001 */ +void upd7810_device::MOV_A_CR1() +{ + A = CR1; +} + +/* 4c e2: 0100 1100 1110 0010 */ +void upd7810_device::MOV_A_CR2() +{ + A = CR2; +} + +/* 4c e3: 0100 1100 1110 0011 */ +void upd7810_device::MOV_A_CR3() +{ + A = CR3; +} + +/* prefix 4D */ +/* 4d c0: 0100 1101 1100 0000 */ +void upd7810_device::MOV_PA_A() +{ + WP( UPD7810_PORTA, A ); +} + +/* 4d c1: 0100 1101 1100 0001 */ +void upd7810_device::MOV_PB_A() +{ + WP( UPD7810_PORTB, A ); +} + +/* 4d c2: 0100 1101 1100 0010 */ +void upd7810_device::MOV_PC_A() +{ + WP( UPD7810_PORTC, A ); +} + +/* 4d c3: 0100 1101 1100 0011 */ +void upd7810_device::MOV_PD_A() +{ + WP( UPD7810_PORTD, A ); +} + +/* 4d c5: 0100 1101 1100 0101 */ +void upd7810_device::MOV_PF_A() +{ + WP( UPD7810_PORTF, A ); +} + +/* 4d c6: 0100 1101 1100 0110 */ +void upd7810_device::MOV_MKH_A() +{ + MKH = A; +} + +/* 4d c7: 0100 1101 1100 0111 */ +void upd7810_device::MOV_MKL_A() +{ + MKL = A; +} + +/* 4d c8: 0100 1101 1100 1000 */ +void upd7810_device::MOV_ANM_A() +{ + ANM = A; +} + +/* 4d c9: 0100 1101 1100 1001 */ +void upd7810_device::MOV_SMH_A() +{ + SMH = A; +} + +/* 4d ca: 0100 1101 1100 1010 */ +void upd7810_device::MOV_SML_A() +{ + SML = A; +} + +/* 4d cb: 0100 1101 1100 1011 */ +void upd7810_device::MOV_EOM_A() +{ + EOM = A; + upd7810_write_EOM(); +} + +/* 4d cc: 0100 1101 1100 1100 */ +void upd7810_device::MOV_ETMM_A() +{ + ETMM = A; +} + +/* 4d cd: 0100 1101 1100 1101 */ +void upd7810_device::MOV_TMM_A() +{ + TMM = A; +} + +/* 4d d0: 0100 1101 1101 0000 */ +void upd7810_device::MOV_MM_A() +{ + MM = A; +} + +/* 4d d1: 0100 1101 1101 0001 */ +void upd7810_device::MOV_MCC_A() +{ + MCC = A; +} + +/* 4d d2: 0100 1101 1101 0010 */ +void upd7810_device::MOV_MA_A() +{ + MA = A; +} + +/* 4d d3: 0100 1101 1101 0011 */ +void upd7810_device::MOV_MB_A() +{ + MB = A; +} + +/* 4d d4: 0100 1101 1101 0100 */ +void upd7810_device::MOV_MC_A() +{ + MC = A; +} + +/* 4d d7: 0100 1101 1101 0111 */ +void upd7810_device::MOV_MF_A() +{ + MF = A; +} + +/* 4d d8: 0100 1101 1101 1000 */ +void upd7810_device::MOV_TXB_A() +{ + TXB = A; + upd7810_write_TXB(); +} + +/* 4d da: 0100 1101 1101 1010 */ +void upd7810_device::MOV_TM0_A() +{ + TM0 = A; +} + +/* 4d db: 0100 1101 1101 1011 */ +void upd7810_device::MOV_TM1_A() +{ + TM1 = A; +} + +/* 4d e8: 0100 1101 1110 1000 */ +void upd7810_device::MOV_ZCM_A() +{ + ZCM = A; +} + +/* prefix 60 */ +/* 60 08: 0110 0000 0000 1000 */ +void upd7810_device::ANA_V_A() +{ + V &= A; + SET_Z(V); +} + +/* 60 09: 0110 0000 0000 1001 */ +void upd7810_device::ANA_A_A() +{ + A &= A; + SET_Z(A); +} + +/* 60 0a: 0110 0000 0000 1010 */ +void upd7810_device::ANA_B_A() +{ + B &= A; + SET_Z(B); +} + +/* 60 0b: 0110 0000 0000 1011 */ +void upd7810_device::ANA_C_A() +{ + C &= A; + SET_Z(C); +} + +/* 60 0c: 0110 0000 0000 1100 */ +void upd7810_device::ANA_D_A() +{ + D &= A; + SET_Z(D); +} + +/* 60 0d: 0110 0000 0000 1101 */ +void upd7810_device::ANA_E_A() +{ + E &= A; + SET_Z(E); +} + +/* 60 0e: 0110 0000 0000 1110 */ +void upd7810_device::ANA_H_A() +{ + H &= A; + SET_Z(H); +} + +/* 60 0f: 0110 0000 0000 1111 */ +void upd7810_device::ANA_L_A() +{ + L &= A; + SET_Z(L); +} + +/* 60 10: 0110 0000 0001 0000 */ +void upd7810_device::XRA_V_A() +{ + V ^= A; + SET_Z(V); +} + +/* 60 11: 0110 0000 0001 0001 */ +void upd7810_device::XRA_A_A() +{ + A ^= A; + SET_Z(A); +} + +/* 60 12: 0110 0000 0001 0010 */ +void upd7810_device::XRA_B_A() +{ + B ^= A; + SET_Z(B); +} + +/* 60 13: 0110 0000 0001 0011 */ +void upd7810_device::XRA_C_A() +{ + C ^= A; + SET_Z(C); +} + +/* 60 14: 0110 0000 0001 0100 */ +void upd7810_device::XRA_D_A() +{ + D ^= A; + SET_Z(D); +} + +/* 60 15: 0110 0000 0001 0101 */ +void upd7810_device::XRA_E_A() +{ + E ^= A; + SET_Z(E); +} + +/* 60 16: 0110 0000 0001 0110 */ +void upd7810_device::XRA_H_A() +{ + H ^= A; + SET_Z(H); +} + +/* 60 17: 0110 0000 0001 0111 */ +void upd7810_device::XRA_L_A() +{ + L ^= A; + SET_Z(L); +} + +/* 60 18: 0110 0000 0001 1000 */ +void upd7810_device::ORA_V_A() +{ + V |= A; + SET_Z(V); +} + +/* 60 19: 0110 0000 0001 1001 */ +void upd7810_device::ORA_A_A() +{ + A |= A; + SET_Z(A); +} + +/* 60 1a: 0110 0000 0001 1010 */ +void upd7810_device::ORA_B_A() +{ + B |= A; + SET_Z(B); +} + +/* 60 1b: 0110 0000 0001 1011 */ +void upd7810_device::ORA_C_A() +{ + C |= A; + SET_Z(C); +} + +/* 60 1c: 0110 0000 0001 1100 */ +void upd7810_device::ORA_D_A() +{ + D |= A; + SET_Z(D); +} + +/* 60 1d: 0110 0000 0001 1101 */ +void upd7810_device::ORA_E_A() +{ + E |= A; + SET_Z(E); +} + +/* 60 1e: 0110 0000 0001 1110 */ +void upd7810_device::ORA_H_A() +{ + H |= A; + SET_Z(H); +} + +/* 60 1f: 0110 0000 0001 1111 */ +void upd7810_device::ORA_L_A() +{ + L |= A; + SET_Z(L); +} + +/* 60 20: 0110 0000 0010 0000 */ +void upd7810_device::ADDNC_V_A() +{ + UINT8 tmp = V + A; + ZHC_ADD( tmp, V, 0 ); + V = tmp; + SKIP_NC; +} + +/* 60 21: 0110 0000 0010 0001 */ +void upd7810_device::ADDNC_A_A() +{ + UINT8 tmp = A + A; + ZHC_ADD( tmp, A, 0 ); + A = tmp; + SKIP_NC; +} + +/* 60 22: 0110 0000 0010 0010 */ +void upd7810_device::ADDNC_B_A() +{ + UINT8 tmp = B + A; + ZHC_ADD( tmp, B, 0 ); + B = tmp; + SKIP_NC; +} + +/* 60 23: 0110 0000 0010 0011 */ +void upd7810_device::ADDNC_C_A() +{ + UINT8 tmp = C + A; + ZHC_ADD( tmp, C, 0 ); + C = tmp; + SKIP_NC; +} + +/* 60 24: 0110 0000 0010 0100 */ +void upd7810_device::ADDNC_D_A() +{ + UINT8 tmp = D + A; + ZHC_ADD( tmp, D, 0 ); + D = tmp; + SKIP_NC; +} + +/* 60 25: 0110 0000 0010 0101 */ +void upd7810_device::ADDNC_E_A() +{ + UINT8 tmp = E + A; + ZHC_ADD( tmp, E, 0 ); + E = tmp; + SKIP_NC; +} + +/* 60 26: 0110 0000 0010 0110 */ +void upd7810_device::ADDNC_H_A() +{ + UINT8 tmp = H + A; + ZHC_ADD( tmp, H, 0 ); + H = tmp; + SKIP_NC; +} + +/* 60 27: 0110 0000 0010 0111 */ +void upd7810_device::ADDNC_L_A() +{ + UINT8 tmp = L + A; + ZHC_ADD( tmp, L, 0 ); + L = tmp; + SKIP_NC; +} + +/* 60 28: 0110 0000 0010 1000 */ +void upd7810_device::GTA_V_A() +{ + UINT16 tmp = V - A - 1; + ZHC_SUB( tmp, V, 0 ); + SKIP_NC; +} + +/* 60 29: 0110 0000 0010 1001 */ +void upd7810_device::GTA_A_A() +{ + UINT16 tmp = A - A - 1; + ZHC_SUB( tmp, A, 0 ); + SKIP_NC; +} + +/* 60 2a: 0110 0000 0010 1010 */ +void upd7810_device::GTA_B_A() +{ + UINT16 tmp = B - A - 1; + ZHC_SUB( tmp, B, 0 ); + SKIP_NC; +} + +/* 60 2b: 0110 0000 0010 1011 */ +void upd7810_device::GTA_C_A() +{ + UINT16 tmp = C - A - 1; + ZHC_SUB( tmp, C, 0 ); + SKIP_NC; +} + +/* 60 2c: 0110 0000 0010 1100 */ +void upd7810_device::GTA_D_A() +{ + UINT16 tmp = D - A - 1; + ZHC_SUB( tmp, D, 0 ); + SKIP_NC; +} + +/* 60 2d: 0110 0000 0010 1101 */ +void upd7810_device::GTA_E_A() +{ + UINT16 tmp = E - A - 1; + ZHC_SUB( tmp, E, 0 ); + SKIP_NC; +} + +/* 60 2e: 0110 0000 0010 1110 */ +void upd7810_device::GTA_H_A() +{ + UINT16 tmp = H - A - 1; + ZHC_SUB( tmp, H, 0 ); + SKIP_NC; +} + +/* 60 2f: 0110 0000 0010 1111 */ +void upd7810_device::GTA_L_A() +{ + UINT16 tmp = L - A - 1; + ZHC_SUB( tmp, L, 0 ); + SKIP_NC; +} + +/* 60 30: 0110 0000 0011 0000 */ +void upd7810_device::SUBNB_V_A() +{ + UINT8 tmp = V - A; + ZHC_SUB( tmp, V, 0 ); + V = tmp; + SKIP_NC; +} + +/* 60 31: 0110 0000 0011 0001 */ +void upd7810_device::SUBNB_A_A() +{ + UINT8 tmp = A - A; + ZHC_SUB( tmp, A, 0 ); + A = tmp; + SKIP_NC; +} + +/* 60 32: 0110 0000 0011 0010 */ +void upd7810_device::SUBNB_B_A() +{ + UINT8 tmp = B - A; + ZHC_SUB( tmp, B, 0 ); + B = tmp; + SKIP_NC; +} + +/* 60 33: 0110 0000 0011 0011 */ +void upd7810_device::SUBNB_C_A() +{ + UINT8 tmp = C - A; + ZHC_SUB( tmp, C, 0 ); + C = tmp; + SKIP_NC; +} + +/* 60 34: 0110 0000 0011 0100 */ +void upd7810_device::SUBNB_D_A() +{ + UINT8 tmp = D - A; + ZHC_SUB( tmp, D, 0 ); + D = tmp; + SKIP_NC; +} + +/* 60 35: 0110 0000 0011 0101 */ +void upd7810_device::SUBNB_E_A() +{ + UINT8 tmp = E - A; + ZHC_SUB( tmp, E, 0 ); + E = tmp; + SKIP_NC; +} + +/* 60 36: 0110 0000 0011 0110 */ +void upd7810_device::SUBNB_H_A() +{ + UINT8 tmp = H - A; + ZHC_SUB( tmp, H, 0 ); + H = tmp; + SKIP_NC; +} + +/* 60 37: 0110 0000 0011 0111 */ +void upd7810_device::SUBNB_L_A() +{ + UINT8 tmp = L - A; + ZHC_SUB( tmp, L, 0 ); + L = tmp; + SKIP_NC; +} + +/* 60 38: 0110 0000 0011 1000 */ +void upd7810_device::LTA_V_A() +{ + UINT8 tmp = V - A; + ZHC_SUB( tmp, V, 0 ); + SKIP_CY; +} + +/* 60 39: 0110 0000 0011 1001 */ +void upd7810_device::LTA_A_A() +{ + UINT8 tmp = A - A; + ZHC_SUB( tmp, A, 0 ); + SKIP_CY; +} + +/* 60 3a: 0110 0000 0011 1010 */ +void upd7810_device::LTA_B_A() +{ + UINT8 tmp = B - A; + ZHC_SUB( tmp, B, 0 ); + SKIP_CY; +} + +/* 60 3b: 0110 0000 0011 1011 */ +void upd7810_device::LTA_C_A() +{ + UINT8 tmp = C - A; + ZHC_SUB( tmp, C, 0 ); + SKIP_CY; +} + +/* 60 3c: 0110 0000 0011 1100 */ +void upd7810_device::LTA_D_A() +{ + UINT8 tmp = D - A; + ZHC_SUB( tmp, D, 0 ); + SKIP_CY; +} + +/* 60 3d: 0110 0000 0011 1101 */ +void upd7810_device::LTA_E_A() +{ + UINT8 tmp = E - A; + ZHC_SUB( tmp, E, 0 ); + SKIP_CY; +} + +/* 60 3e: 0110 0000 0011 1110 */ +void upd7810_device::LTA_H_A() +{ + UINT8 tmp = H - A; + ZHC_SUB( tmp, H, 0 ); + SKIP_CY; +} + +/* 60 3f: 0110 0000 0011 1111 */ +void upd7810_device::LTA_L_A() +{ + UINT8 tmp = L - A; + ZHC_SUB( tmp, L, 0 ); + SKIP_CY; +} + +/* 60 40: 0110 0000 0100 0000 */ +void upd7810_device::ADD_V_A() +{ + UINT8 tmp = V + A; + ZHC_ADD( tmp, V, 0 ); + V = tmp; +} + +/* 60 41: 0110 0000 0100 0001 */ +void upd7810_device::ADD_A_A() +{ + UINT8 tmp = A + A; + ZHC_ADD( tmp, A, 0 ); + A = tmp; +} + +/* 60 42: 0110 0000 0100 0010 */ +void upd7810_device::ADD_B_A() +{ + UINT8 tmp = B + A; + ZHC_ADD( tmp, B, 0 ); + B = tmp; +} + +/* 60 43: 0110 0000 0100 0011 */ +void upd7810_device::ADD_C_A() +{ + UINT8 tmp = C + A; + ZHC_ADD( tmp, C, 0 ); + C = tmp; +} + +/* 60 44: 0110 0000 0100 0100 */ +void upd7810_device::ADD_D_A() +{ + UINT8 tmp = D + A; + ZHC_ADD( tmp, D, 0 ); + D = tmp; +} + +/* 60 45: 0110 0000 0100 0101 */ +void upd7810_device::ADD_E_A() +{ + UINT8 tmp = E + A; + ZHC_ADD( tmp, E, 0 ); + E = tmp; +} + +/* 60 46: 0110 0000 0100 0110 */ +void upd7810_device::ADD_H_A() +{ + UINT8 tmp = H + A; + ZHC_ADD( tmp, H, 0 ); + H = tmp; +} + +/* 60 47: 0110 0000 0100 0111 */ +void upd7810_device::ADD_L_A() +{ + UINT8 tmp = L + A; + ZHC_ADD( tmp, L, 0 ); + L = tmp; +} + +/* 60 50: 0110 0000 0101 0000 */ +void upd7810_device::ADC_V_A() +{ + UINT8 tmp = V + A + (PSW & CY); + ZHC_ADD( tmp, V, (PSW & CY) ); + V = tmp; +} + +/* 60 51: 0110 0000 0101 0001 */ +void upd7810_device::ADC_A_A() +{ + UINT8 tmp = A + A + (PSW & CY); + ZHC_ADD( tmp, A, (PSW & CY) ); + A = tmp; +} + +/* 60 52: 0110 0000 0101 0010 */ +void upd7810_device::ADC_B_A() +{ + UINT8 tmp = B + A + (PSW & CY); + ZHC_ADD( tmp, B, (PSW & CY) ); + B = tmp; +} + +/* 60 53: 0110 0000 0101 0011 */ +void upd7810_device::ADC_C_A() +{ + UINT8 tmp = C + A + (PSW & CY); + ZHC_ADD( tmp, C, (PSW & CY) ); + C = tmp; +} + +/* 60 54: 0110 0000 0101 0100 */ +void upd7810_device::ADC_D_A() +{ + UINT8 tmp = D + A + (PSW & CY); + ZHC_ADD( tmp, D, (PSW & CY) ); + D = tmp; +} + +/* 60 55: 0110 0000 0101 0101 */ +void upd7810_device::ADC_E_A() +{ + UINT8 tmp = E + A + (PSW & CY); + ZHC_ADD( tmp, E, (PSW & CY) ); + E = tmp; +} + +/* 60 56: 0110 0000 0101 0110 */ +void upd7810_device::ADC_H_A() +{ + UINT8 tmp = H + A + (PSW & CY); + ZHC_ADD( tmp, H, (PSW & CY) ); + H = tmp; +} + +/* 60 57: 0110 0000 0101 0111 */ +void upd7810_device::ADC_L_A() +{ + UINT8 tmp = L + A + (PSW & CY); + ZHC_ADD( tmp, L, (PSW & CY) ); + L = tmp; +} + +/* 60 60: 0110 0000 0110 0000 */ +void upd7810_device::SUB_V_A() +{ + UINT8 tmp = V - A; + ZHC_SUB( tmp, V, 0 ); + V = tmp; +} + +/* 60 61: 0110 0000 0110 0001 */ +void upd7810_device::SUB_A_A() +{ + UINT8 tmp = A - A; + ZHC_SUB( tmp, A, 0 ); + A = tmp; +} + +/* 60 62: 0110 0000 0110 0010 */ +void upd7810_device::SUB_B_A() +{ + UINT8 tmp = B - A; + ZHC_SUB( tmp, B, 0 ); + B = tmp; +} + +/* 60 63: 0110 0000 0110 0011 */ +void upd7810_device::SUB_C_A() +{ + UINT8 tmp = C - A; + ZHC_SUB( tmp, C, 0 ); + C = tmp; +} + +/* 60 64: 0110 0000 0110 0100 */ +void upd7810_device::SUB_D_A() +{ + UINT8 tmp = D - A; + ZHC_SUB( tmp, D, 0 ); + D = tmp; +} + +/* 60 65: 0110 0000 0110 0101 */ +void upd7810_device::SUB_E_A() +{ + UINT8 tmp = E - A; + ZHC_SUB( tmp, E, 0 ); + E = tmp; +} + +/* 60 66: 0110 0000 0110 0110 */ +void upd7810_device::SUB_H_A() +{ + UINT8 tmp = H - A; + ZHC_SUB( tmp, H, 0 ); + H = tmp; +} + +/* 60 67: 0110 0000 0110 0111 */ +void upd7810_device::SUB_L_A() +{ + UINT8 tmp = L - A; + ZHC_SUB( tmp, L, 0 ); + L = tmp; +} + +/* 60 68: 0110 0000 0110 1000 */ +void upd7810_device::NEA_V_A() +{ + UINT8 tmp = V - A; + ZHC_SUB( tmp, V, 0 ); + SKIP_NZ; +} + +/* 60 69: 0110 0000 0110 1001 */ +void upd7810_device::NEA_A_A() +{ + UINT8 tmp = A - A; + ZHC_SUB( tmp, A, 0 ); + SKIP_NZ; +} + +/* 60 6a: 0110 0000 0110 1010 */ +void upd7810_device::NEA_B_A() +{ + UINT8 tmp = B - A; + ZHC_SUB( tmp, B, 0 ); + SKIP_NZ; +} + +/* 60 6b: 0110 0000 0110 1011 */ +void upd7810_device::NEA_C_A() +{ + UINT8 tmp = C - A; + ZHC_SUB( tmp, C, 0 ); + SKIP_NZ; +} + +/* 60 6c: 0110 0000 0110 1100 */ +void upd7810_device::NEA_D_A() +{ + UINT8 tmp = D - A; + ZHC_SUB( tmp, D, 0 ); + SKIP_NZ; +} + +/* 60 6d: 0110 0000 0110 1101 */ +void upd7810_device::NEA_E_A() +{ + UINT8 tmp = E - A; + ZHC_SUB( tmp, E, 0 ); + SKIP_NZ; +} + +/* 60 6e: 0110 0000 0110 1110 */ +void upd7810_device::NEA_H_A() +{ + UINT8 tmp = H - A; + ZHC_SUB( tmp, H, 0 ); + SKIP_NZ; +} + +/* 60 6f: 0110 0000 0110 1111 */ +void upd7810_device::NEA_L_A() +{ + UINT8 tmp = L - A; + ZHC_SUB( tmp, L, 0 ); + SKIP_NZ; +} + +/* 60 70: 0110 0000 0111 0000 */ +void upd7810_device::SBB_V_A() +{ + UINT8 tmp = V - A - (PSW & CY); + ZHC_SUB( tmp, V, (PSW & CY) ); + V = tmp; +} + +/* 60 71: 0110 0000 0111 0001 */ +void upd7810_device::SBB_A_A() +{ + UINT8 tmp = A - A - (PSW & CY); + ZHC_SUB( tmp, A, (PSW & CY) ); + A = tmp; +} + +/* 60 72: 0110 0000 0111 0010 */ +void upd7810_device::SBB_B_A() +{ + UINT8 tmp = B - A - (PSW & CY); + ZHC_SUB( tmp, B, (PSW & CY) ); + B = tmp; +} + +/* 60 73: 0110 0000 0111 0011 */ +void upd7810_device::SBB_C_A() +{ + UINT8 tmp = C - A - (PSW & CY); + ZHC_SUB( tmp, C, (PSW & CY) ); + C = tmp; +} + +/* 60 74: 0110 0000 0111 0100 */ +void upd7810_device::SBB_D_A() +{ + UINT8 tmp = D - A - (PSW & CY); + ZHC_SUB( tmp, D, (PSW & CY) ); + D = tmp; +} + +/* 60 75: 0110 0000 0111 0101 */ +void upd7810_device::SBB_E_A() +{ + UINT8 tmp = E - A - (PSW & CY); + ZHC_SUB( tmp, E, (PSW & CY) ); + E = tmp; +} + +/* 60 76: 0110 0000 0111 0110 */ +void upd7810_device::SBB_H_A() +{ + UINT8 tmp = H - A - (PSW & CY); + ZHC_SUB( tmp, H, (PSW & CY) ); + H = tmp; +} + +/* 60 77: 0110 0000 0111 0111 */ +void upd7810_device::SBB_L_A() +{ + UINT8 tmp = L - A - (PSW & CY); + ZHC_SUB( tmp, L, (PSW & CY) ); + L = tmp; +} + +/* 60 78: 0110 0000 0111 1000 */ +void upd7810_device::EQA_V_A() +{ + UINT8 tmp = V - A; + ZHC_SUB( tmp, V, 0 ); + SKIP_Z; +} + +/* 60 79: 0110 0000 0111 1001 */ +void upd7810_device::EQA_A_A() +{ + UINT8 tmp = A - A; + ZHC_SUB( tmp, A, 0 ); + SKIP_Z; +} + +/* 60 7a: 0110 0000 0111 1010 */ +void upd7810_device::EQA_B_A() +{ + UINT8 tmp = B - A; + ZHC_SUB( tmp, B, 0 ); + SKIP_Z; +} + +/* 60 7b: 0110 0000 0111 1011 */ +void upd7810_device::EQA_C_A() +{ + UINT8 tmp = C - A; + ZHC_SUB( tmp, C, 0 ); + SKIP_Z; +} + +/* 60 7c: 0110 0000 0111 1100 */ +void upd7810_device::EQA_D_A() +{ + UINT8 tmp = D - A; + ZHC_SUB( tmp, D, 0 ); + SKIP_Z; +} + +/* 60 7d: 0110 0000 0111 1101 */ +void upd7810_device::EQA_E_A() +{ + UINT8 tmp = E - A; + ZHC_SUB( tmp, E, 0 ); + SKIP_Z; +} + +/* 60 7e: 0110 0000 0111 1110 */ +void upd7810_device::EQA_H_A() +{ + UINT8 tmp = H - A; + ZHC_SUB( tmp, H, 0 ); + SKIP_Z; +} + +/* 60 7f: 0110 0000 0111 1111 */ +void upd7810_device::EQA_L_A() +{ + UINT8 tmp = L - A; + ZHC_SUB( tmp, L, 0 ); + SKIP_Z; +} + +/* 60 88: 0110 0000 1000 1000 */ +void upd7810_device::ANA_A_V() +{ + A &= V; + SET_Z(A); +} + +/* 60 89: 0110 0000 1000 1001 */ +/* ANA_A_A already defined */ + +/* 60 8a: 0110 0000 1000 1010 */ +void upd7810_device::ANA_A_B() +{ + A &= B; + SET_Z(A); +} + +/* 60 8b: 0110 0000 1000 1011 */ +void upd7810_device::ANA_A_C() +{ + A &= C; + SET_Z(A); +} + +/* 60 8c: 0110 0000 1000 1100 */ +void upd7810_device::ANA_A_D() +{ + A &= D; + SET_Z(A); +} + +/* 60 8d: 0110 0000 1000 1101 */ +void upd7810_device::ANA_A_E() +{ + A &= E; + SET_Z(A); +} + +/* 60 8e: 0110 0000 1000 1110 */ +void upd7810_device::ANA_A_H() +{ + A &= H; + SET_Z(A); +} + +/* 60 8f: 0110 0000 1000 1111 */ +void upd7810_device::ANA_A_L() +{ + A &= L; + SET_Z(A); +} + +/* 60 90: 0110 0000 1001 0000 */ +void upd7810_device::XRA_A_V() +{ + A ^= V; + SET_Z(A); +} + +/* 60 91: 0110 0000 1001 0001 */ +/* XRA_A_A already defined */ + +/* 60 92: 0110 0000 1001 0010 */ +void upd7810_device::XRA_A_B() +{ + A ^= B; + SET_Z(A); +} + +/* 60 93: 0110 0000 1001 0011 */ +void upd7810_device::XRA_A_C() +{ + A ^= C; + SET_Z(A); +} + +/* 60 94: 0110 0000 1001 0100 */ +void upd7810_device::XRA_A_D() +{ + A ^= D; + SET_Z(A); +} + +/* 60 95: 0110 0000 1001 0101 */ +void upd7810_device::XRA_A_E() +{ + A ^= E; + SET_Z(A); +} + +/* 60 96: 0110 0000 1001 0110 */ +void upd7810_device::XRA_A_H() +{ + A ^= H; + SET_Z(A); +} + +/* 60 97: 0110 0000 1001 0111 */ +void upd7810_device::XRA_A_L() +{ + A ^= L; + SET_Z(A); +} + +/* 60 98: 0110 0000 1001 1000 */ +void upd7810_device::ORA_A_V() +{ + A |= V; + SET_Z(A); +} + +/* 60 99: 0110 0000 1001 1001 */ +/* ORA_A_A already defined */ + +/* 60 9a: 0110 0000 1001 1010 */ +void upd7810_device::ORA_A_B() +{ + A |= B; + SET_Z(A); +} + +/* 60 9b: 0110 0000 1001 1011 */ +void upd7810_device::ORA_A_C() +{ + A |= C; + SET_Z(A); +} + +/* 60 9c: 0110 0000 1001 1100 */ +void upd7810_device::ORA_A_D() +{ + A |= D; + SET_Z(A); +} + +/* 60 9d: 0110 0000 1001 1101 */ +void upd7810_device::ORA_A_E() +{ + A |= E; + SET_Z(A); +} + +/* 60 9e: 0110 0000 1001 1110 */ +void upd7810_device::ORA_A_H() +{ + A |= H; + SET_Z(A); +} + +/* 60 9f: 0110 0000 1001 1111 */ +void upd7810_device::ORA_A_L() +{ + A |= L; + SET_Z(A); +} + +/* 60 a0: 0110 0000 1010 0000 */ +void upd7810_device::ADDNC_A_V() +{ + UINT8 tmp = A + V; + ZHC_ADD( tmp, A, 0 ); + A = tmp; + SKIP_NC; +} + +/* 60 a1: 0110 0000 1010 0001 */ +/* ADDNC_A_A already defined */ + +/* 60 a2: 0110 0000 1010 0010 */ +void upd7810_device::ADDNC_A_B() +{ + UINT8 tmp = A + B; + ZHC_ADD( tmp, A, 0 ); + A = tmp; + SKIP_NC; +} + +/* 60 a3: 0110 0000 1010 0011 */ +void upd7810_device::ADDNC_A_C() +{ + UINT8 tmp = A + C; + ZHC_ADD( tmp, A, 0 ); + A = tmp; + SKIP_NC; +} + +/* 60 a4: 0110 0000 1010 0100 */ +void upd7810_device::ADDNC_A_D() +{ + UINT8 tmp = A + D; + ZHC_ADD( tmp, A, 0 ); + A = tmp; + SKIP_NC; +} + +/* 60 a5: 0110 0000 1010 0101 */ +void upd7810_device::ADDNC_A_E() +{ + UINT8 tmp = A + E; + ZHC_ADD( tmp, A, 0 ); + A = tmp; + SKIP_NC; +} + +/* 60 a6: 0110 0000 1010 0110 */ +void upd7810_device::ADDNC_A_H() +{ + UINT8 tmp = A + H; + ZHC_ADD( tmp, A, 0 ); + A = tmp; + SKIP_NC; +} + +/* 60 a7: 0110 0000 1010 0111 */ +void upd7810_device::ADDNC_A_L() +{ + UINT8 tmp = A + L; + ZHC_ADD( tmp, A, 0 ); + A = tmp; + SKIP_NC; +} + +/* 60 a8: 0110 0000 1010 1000 */ +void upd7810_device::GTA_A_V() +{ + UINT16 tmp = A - V - 1; + ZHC_SUB( tmp, A, 0 ); + SKIP_NC; +} + +/* 60 a9: 0110 0000 1010 1001 */ +/* GTA_A_A already defined */ + +/* 60 aa: 0110 0000 1010 1010 */ +void upd7810_device::GTA_A_B() +{ + UINT16 tmp = A - B - 1; + ZHC_SUB( tmp, A, 0 ); + SKIP_NC; +} + +/* 60 ab: 0110 0000 1010 1011 */ +void upd7810_device::GTA_A_C() +{ + UINT16 tmp = A - C - 1; + ZHC_SUB( tmp, A, 0 ); + SKIP_NC; +} + +/* 60 ac: 0110 0000 1010 1100 */ +void upd7810_device::GTA_A_D() +{ + UINT16 tmp = A - D - 1; + ZHC_SUB( tmp, A, 0 ); + SKIP_NC; +} + +/* 60 ad: 0110 0000 1010 1101 */ +void upd7810_device::GTA_A_E() +{ + UINT16 tmp = A - E - 1; + ZHC_SUB( tmp, A, 0 ); + SKIP_NC; +} + +/* 60 ae: 0110 0000 1010 1110 */ +void upd7810_device::GTA_A_H() +{ + UINT16 tmp = A - H - 1; + ZHC_SUB( tmp, A, 0 ); + SKIP_NC; +} + +/* 60 af: 0110 0000 1010 1111 */ +void upd7810_device::GTA_A_L() +{ + UINT16 tmp = A - L - 1; + ZHC_SUB( tmp, A, 0 ); + SKIP_NC; +} + +/* 60 b0: 0110 0000 1011 0000 */ +void upd7810_device::SUBNB_A_V() +{ + UINT8 tmp = A - V; + ZHC_SUB( tmp, A, 0 ); + A = tmp; + SKIP_NC; +} + +/* 60 b1: 0110 0000 1011 0001 */ +/* SUBNB_A_A already defined */ + +/* 60 b2: 0110 0000 1011 0010 */ +void upd7810_device::SUBNB_A_B() +{ + UINT8 tmp = A - B; + ZHC_SUB( tmp, A, 0 ); + A = tmp; + SKIP_NC; +} + +/* 60 b3: 0110 0000 1011 0011 */ +void upd7810_device::SUBNB_A_C() +{ + UINT8 tmp = A - C; + ZHC_SUB( tmp, A, 0 ); + A = tmp; + SKIP_NC; +} + +/* 60 b4: 0110 0000 1011 0100 */ +void upd7810_device::SUBNB_A_D() +{ + UINT8 tmp = A - D; + ZHC_SUB( tmp, A, 0 ); + A = tmp; + SKIP_NC; +} + +/* 60 b5: 0110 0000 1011 0101 */ +void upd7810_device::SUBNB_A_E() +{ + UINT8 tmp = A - E; + ZHC_SUB( tmp, A, 0 ); + A = tmp; + SKIP_NC; +} + +/* 60 b6: 0110 0000 1011 0110 */ +void upd7810_device::SUBNB_A_H() +{ + UINT8 tmp = A - H; + ZHC_SUB( tmp, A, 0 ); + A = tmp; + SKIP_NC; +} + +/* 60 b7: 0110 0000 1011 0111 */ +void upd7810_device::SUBNB_A_L() +{ + UINT8 tmp = A - L; + ZHC_SUB( tmp, A, 0 ); + A = tmp; + SKIP_NC; +} + +/* 60 b8: 0110 0000 1011 1000 */ +void upd7810_device::LTA_A_V() +{ + UINT8 tmp = A - V; + ZHC_SUB( tmp, A, 0 ); + SKIP_CY; +} + +/* 60 b9: 0110 0000 1011 1001 */ +/* LTA_A_A already defined */ + +/* 60 ba: 0110 0000 1011 1010 */ +void upd7810_device::LTA_A_B() +{ + UINT8 tmp = A - B; + ZHC_SUB( tmp, A, 0 ); + SKIP_CY; +} + +/* 60 bb: 0110 0000 1011 1011 */ +void upd7810_device::LTA_A_C() +{ + UINT8 tmp = A - C; + ZHC_SUB( tmp, A, 0 ); + SKIP_CY; +} + +/* 60 bc: 0110 0000 1011 1100 */ +void upd7810_device::LTA_A_D() +{ + UINT8 tmp = A - D; + ZHC_SUB( tmp, A, 0 ); + SKIP_CY; +} + +/* 60 bd: 0110 0000 1011 1101 */ +void upd7810_device::LTA_A_E() +{ + UINT8 tmp = A - E; + ZHC_SUB( tmp, A, 0 ); + SKIP_CY; +} + +/* 60 be: 0110 0000 1011 1110 */ +void upd7810_device::LTA_A_H() +{ + UINT8 tmp = A - H; + ZHC_SUB( tmp, A, 0 ); + SKIP_CY; +} + +/* 60 bf: 0110 0000 1011 1111 */ +void upd7810_device::LTA_A_L() +{ + UINT8 tmp = A - L; + ZHC_SUB( tmp, A, 0 ); + SKIP_CY; +} + +/* 60 c0: 0110 0000 1100 0000 */ +void upd7810_device::ADD_A_V() +{ + UINT8 tmp = A + V; + ZHC_ADD( tmp, A, 0 ); + A = tmp; +} + +/* 60 c1: 0110 0000 1100 0001 */ +/* ADD_A_A already defined */ + +/* 60 c2: 0110 0000 1100 0010 */ +void upd7810_device::ADD_A_B() +{ + UINT8 tmp = A + B; + ZHC_ADD( tmp, A, 0 ); + A = tmp; +} + +/* 60 c3: 0110 0000 1100 0011 */ +void upd7810_device::ADD_A_C() +{ + UINT8 tmp = A + C; + ZHC_ADD( tmp, A, 0 ); + A = tmp; +} + +/* 60 c4: 0110 0000 1100 0100 */ +void upd7810_device::ADD_A_D() +{ + UINT8 tmp = A + D; + ZHC_ADD( tmp, A, 0 ); + A = tmp; +} + +/* 60 c5: 0110 0000 1100 0101 */ +void upd7810_device::ADD_A_E() +{ + UINT8 tmp = A + E; + ZHC_ADD( tmp, A, 0 ); + A = tmp; +} + +/* 60 c6: 0110 0000 1100 0110 */ +void upd7810_device::ADD_A_H() +{ + UINT8 tmp = A + H; + ZHC_ADD( tmp, A, 0 ); + A = tmp; +} + +/* 60 c7: 0110 0000 1100 0111 */ +void upd7810_device::ADD_A_L() +{ + UINT8 tmp = A + L; + ZHC_ADD( tmp, A, 0 ); + A = tmp; +} + +/* 60 c8: 0110 0000 1100 1000 */ +void upd7810_device::ONA_A_V() +{ + if (A & V) + PSW = (PSW & ~Z) | SK; + else + PSW |= Z; +} + +/* 60 c9: 0110 0000 1100 1001 */ +void upd7810_device::ONA_A_A() +{ + if (A & A) + PSW = (PSW & ~Z) | SK; + else + PSW |= Z; +} + +/* 60 ca: 0110 0000 1100 1010 */ +void upd7810_device::ONA_A_B() +{ + if (A & B) + PSW = (PSW & ~Z) | SK; + else + PSW |= Z; +} + +/* 60 cb: 0110 0000 1100 1011 */ +void upd7810_device::ONA_A_C() +{ + if (A & C) + PSW = (PSW & ~Z) | SK; + else + PSW |= Z; +} + +/* 60 cc: 0110 0000 1100 1100 */ +void upd7810_device::ONA_A_D() +{ + if (A & D) + PSW = (PSW & ~Z) | SK; + else + PSW |= Z; +} + +/* 60 cd: 0110 0000 1100 1101 */ +void upd7810_device::ONA_A_E() +{ + if (A & E) + PSW = (PSW & ~Z) | SK; + else + PSW |= Z; +} + +/* 60 ce: 0110 0000 1100 1110 */ +void upd7810_device::ONA_A_H() +{ + if (A & H) + PSW = (PSW & ~Z) | SK; + else + PSW |= Z; +} + +/* 60 cf: 0110 0000 1100 1111 */ +void upd7810_device::ONA_A_L() +{ + if (A & L) + PSW = (PSW & ~Z) | SK; + else + PSW |= Z; +} + +/* 60 d0: 0110 0000 1101 0000 */ +void upd7810_device::ADC_A_V() +{ + UINT8 tmp = A + V + (PSW & CY); + ZHC_ADD( tmp, A, (PSW & CY) ); + A = tmp; +} + +/* 60 d1: 0110 0000 1101 0001 */ +/* ADC_A_A already defined */ + +/* 60 d2: 0110 0000 1101 0010 */ +void upd7810_device::ADC_A_B() +{ + UINT8 tmp = A + B + (PSW & CY); + ZHC_ADD( tmp, A, (PSW & CY) ); + A = tmp; +} + +/* 60 d3: 0110 0000 1101 0011 */ +void upd7810_device::ADC_A_C() +{ + UINT8 tmp = A + C + (PSW & CY); + ZHC_ADD( tmp, A, (PSW & CY) ); + A = tmp; +} + +/* 60 d4: 0110 0000 1101 0100 */ +void upd7810_device::ADC_A_D() +{ + UINT8 tmp = A + D + (PSW & CY); + ZHC_ADD( tmp, A, (PSW & CY) ); + A = tmp; +} + +/* 60 d5: 0110 0000 1101 0101 */ +void upd7810_device::ADC_A_E() +{ + UINT8 tmp = A + E + (PSW & CY); + ZHC_ADD( tmp, A, (PSW & CY) ); + A = tmp; +} + +/* 60 d6: 0110 0000 1101 0110 */ +void upd7810_device::ADC_A_H() +{ + UINT8 tmp = A + H + (PSW & CY); + ZHC_ADD( tmp, A, (PSW & CY) ); + A = tmp; +} + +/* 60 d7: 0110 0000 1101 0111 */ +void upd7810_device::ADC_A_L() +{ + UINT8 tmp = A + L + (PSW & CY); + ZHC_ADD( tmp, A, (PSW & CY) ); + A = tmp; +} + +/* 60 d8: 0110 0000 1101 1000 */ +void upd7810_device::OFFA_A_V() +{ + if ( A & V ) + PSW &= ~Z; + else + PSW = PSW | Z | SK; +} + +/* 60 d9: 0110 0000 1101 1001 */ +void upd7810_device::OFFA_A_A() +{ + if ( A & A ) + PSW &= ~Z; + else + PSW = PSW | Z | SK; +} + +/* 60 da: 0110 0000 1101 1010 */ +void upd7810_device::OFFA_A_B() +{ + if ( A & B ) + PSW &= ~Z; + else + PSW = PSW | Z | SK; +} + +/* 60 db: 0110 0000 1101 1011 */ +void upd7810_device::OFFA_A_C() +{ + if ( A & C ) + PSW &= ~Z; + else + PSW = PSW | Z | SK; +} + +/* 60 dc: 0110 0000 1101 1100 */ +void upd7810_device::OFFA_A_D() +{ + if ( A & D ) + PSW &= ~Z; + else + PSW = PSW | Z | SK; +} + +/* 60 dd: 0110 0000 1101 1101 */ +void upd7810_device::OFFA_A_E() +{ + if ( A & E ) + PSW &= ~Z; + else + PSW = PSW | Z | SK; +} + +/* 60 de: 0110 0000 1101 1110 */ +void upd7810_device::OFFA_A_H() +{ + if ( A & H ) + PSW &= ~Z; + else + PSW = PSW | Z | SK; +} + +/* 60 df: 0110 0000 1101 1111 */ +void upd7810_device::OFFA_A_L() +{ + if ( A & L ) + PSW &= ~Z; + else + PSW = PSW | Z | SK; +} + +/* 60 e0: 0110 0000 1110 0000 */ +void upd7810_device::SUB_A_V() +{ + UINT8 tmp = A - V; + ZHC_SUB( tmp, A, 0 ); + A = tmp; +} + +/* 60 e1: 0110 0000 1110 0001 */ +/* SUB_A_A already defined */ + +/* 60 e2: 0110 0000 1110 0010 */ +void upd7810_device::SUB_A_B() +{ + UINT8 tmp = A - B; + ZHC_SUB( tmp, A, 0 ); + A = tmp; +} + +/* 60 e3: 0110 0000 1110 0011 */ +void upd7810_device::SUB_A_C() +{ + UINT8 tmp = A - C; + ZHC_SUB( tmp, A, 0 ); + A = tmp; +} + +/* 60 e4: 0110 0000 1110 0100 */ +void upd7810_device::SUB_A_D() +{ + UINT8 tmp = A - D; + ZHC_SUB( tmp, A, 0 ); + A = tmp; +} + +/* 60 e5: 0110 0000 1110 0101 */ +void upd7810_device::SUB_A_E() +{ + UINT8 tmp = A - E; + ZHC_SUB( tmp, A, 0 ); + A = tmp; +} + +/* 60 e6: 0110 0000 1110 0110 */ +void upd7810_device::SUB_A_H() +{ + UINT8 tmp = A - H; + ZHC_SUB( tmp, A, 0 ); + A = tmp; +} + +/* 60 e7: 0110 0000 1110 0111 */ +void upd7810_device::SUB_A_L() +{ + UINT8 tmp = A - L; + ZHC_SUB( tmp, A, 0 ); + A = tmp; +} + +/* 60 e8: 0110 0000 1110 1000 */ +void upd7810_device::NEA_A_V() +{ + UINT8 tmp = A - V; + ZHC_SUB( tmp, A, 0 ); + SKIP_NZ; +} + +/* 60 e9: 0110 0000 1110 1001 */ +/* NEA_A_A already defined */ + +/* 60 ea: 0110 0000 1110 1010 */ +void upd7810_device::NEA_A_B() +{ + UINT8 tmp = A - B; + ZHC_SUB( tmp, A, 0 ); + SKIP_NZ; +} + +/* 60 eb: 0110 0000 1110 1011 */ +void upd7810_device::NEA_A_C() +{ + UINT8 tmp = A - C; + ZHC_SUB( tmp, A, 0 ); + SKIP_NZ; +} + +/* 60 ec: 0110 0000 1110 1100 */ +void upd7810_device::NEA_A_D() +{ + UINT8 tmp = A - D; + ZHC_SUB( tmp, A, 0 ); + SKIP_NZ; +} + +/* 60 ed: 0110 0000 1110 1101 */ +void upd7810_device::NEA_A_E() +{ + UINT8 tmp = A - E; + ZHC_SUB( tmp, A, 0 ); + SKIP_NZ; +} + +/* 60 ee: 0110 0000 1110 1110 */ +void upd7810_device::NEA_A_H() +{ + UINT8 tmp = A - H; + ZHC_SUB( tmp, A, 0 ); + SKIP_NZ; +} + +/* 60 ef: 0110 0000 1110 1111 */ +void upd7810_device::NEA_A_L() +{ + UINT8 tmp = A - L; + ZHC_SUB( tmp, A, 0 ); + SKIP_NZ; +} + +/* 60 f0: 0110 0000 1111 0000 */ +void upd7810_device::SBB_A_V() +{ + UINT8 tmp = A - V - (PSW & CY); + ZHC_SUB( tmp, A, (PSW & CY) ); + A = tmp; +} + +/* 60 f1: 0110 0000 1111 0001 */ +/* SBB_A_A already defined */ + +/* 60 f2: 0110 0000 1111 0010 */ +void upd7810_device::SBB_A_B() +{ + UINT8 tmp = A - B - (PSW & CY); + ZHC_SUB( tmp, A, (PSW & CY) ); + A = tmp; +} + +/* 60 f3: 0110 0000 1111 0011 */ +void upd7810_device::SBB_A_C() +{ + UINT8 tmp = A - C - (PSW & CY); + ZHC_SUB( tmp, A, (PSW & CY) ); + A = tmp; +} + +/* 60 f4: 0110 0000 1111 0100 */ +void upd7810_device::SBB_A_D() +{ + UINT8 tmp = A - D - (PSW & CY); + ZHC_SUB( tmp, A, (PSW & CY) ); + A = tmp; +} + +/* 60 f5: 0110 0000 1111 0101 */ +void upd7810_device::SBB_A_E() +{ + UINT8 tmp = A - E - (PSW & CY); + ZHC_SUB( tmp, A, (PSW & CY) ); + A = tmp; +} + +/* 60 f6: 0110 0000 1111 0110 */ +void upd7810_device::SBB_A_H() +{ + UINT8 tmp = A - H - (PSW & CY); + ZHC_SUB( tmp, A, (PSW & CY) ); + A = tmp; +} + +/* 60 f7: 0110 0000 1111 0111 */ +void upd7810_device::SBB_A_L() +{ + UINT8 tmp = A - L - (PSW & CY); + ZHC_SUB( tmp, A, (PSW & CY) ); + A = tmp; +} + +/* 60 f8: 0110 0000 1111 1000 */ +void upd7810_device::EQA_A_V() +{ + UINT8 tmp = A - V; + ZHC_SUB( tmp, A, 0 ); + SKIP_Z; +} + +/* 60 f9: 0110 0000 1111 1001 */ +/* EQA_A_A already defined */ + +/* 60 fa: 0110 0000 1111 1010 */ +void upd7810_device::EQA_A_B() +{ + UINT8 tmp = A - B; + ZHC_SUB( tmp, A, 0 ); + SKIP_Z; +} + +/* 60 fb: 0110 0000 1111 1011 */ +void upd7810_device::EQA_A_C() +{ + UINT8 tmp = A - C; + ZHC_SUB( tmp, A, 0 ); + SKIP_Z; +} + +/* 60 fc: 0110 0000 1111 1100 */ +void upd7810_device::EQA_A_D() +{ + UINT8 tmp = A - D; + ZHC_SUB( tmp, A, 0 ); + SKIP_Z; +} + +/* 60 fd: 0110 0000 1111 1101 */ +void upd7810_device::EQA_A_E() +{ + UINT8 tmp = A - E; + ZHC_SUB( tmp, A, 0 ); + SKIP_Z; +} + +/* 60 fe: 0110 0000 1111 1110 */ +void upd7810_device::EQA_A_H() +{ + UINT8 tmp = A - H; + ZHC_SUB( tmp, A, 0 ); + SKIP_Z; +} + +/* 60 ff: 0110 0000 1111 1111 */ +void upd7810_device::EQA_A_L() +{ + UINT8 tmp = A - L; + ZHC_SUB( tmp, A, 0 ); + SKIP_Z; +} + +/* prefix 64 */ +/* 64 00: 0110 0100 0000 0000 xxxx xxxx */ +void upd7810_device::MVI_PA_xx() +{ + UINT8 imm; + RDOPARG( imm ); + WP( UPD7810_PORTA, imm ); +} + +/* 64 01: 0110 0100 0000 0001 xxxx xxxx */ +void upd7810_device::MVI_PB_xx() +{ + UINT8 imm; + RDOPARG( imm ); + WP( UPD7810_PORTB, imm ); +} + +/* 64 02: 0110 0100 0000 0010 xxxx xxxx */ +void upd7810_device::MVI_PC_xx() +{ + UINT8 imm; + RDOPARG( imm ); + WP( UPD7810_PORTC, imm ); +} + +/* 64 03: 0110 0100 0000 0011 xxxx xxxx */ +void upd7810_device::MVI_PD_xx() +{ + UINT8 imm; + RDOPARG( imm ); + WP( UPD7810_PORTD, imm ); +} + +/* 64 05: 0110 0100 0000 0101 xxxx xxxx */ +void upd7810_device::MVI_PF_xx() +{ + UINT8 imm; + RDOPARG( imm ); + WP( UPD7810_PORTF, imm ); +} + +/* 64 06: 0110 0100 0000 0110 xxxx xxxx */ +void upd7810_device::MVI_MKH_xx() +{ + RDOPARG( MKH ); +} + +/* 64 07: 0110 0100 0000 0111 xxxx xxxx */ +void upd7810_device::MVI_MKL_xx() +{ + RDOPARG( MKL ); +} + +/* 64 08: 0110 0100 0000 1000 xxxx xxxx */ +void upd7810_device::ANI_PA_xx() +{ + UINT8 pa = RP( UPD7810_PORTA), imm; + RDOPARG( imm ); + pa &= imm; + WP( UPD7810_PORTA, pa ); + SET_Z(pa); +} + +/* 64 09: 0110 0100 0000 1001 xxxx xxxx */ +void upd7810_device::ANI_PB_xx() +{ + UINT8 pb = RP( UPD7810_PORTB), imm; + RDOPARG( imm ); + pb &= imm; + WP( UPD7810_PORTB, pb ); + SET_Z(pb); +} + +/* 64 0a: 0110 0100 0000 1010 xxxx xxxx */ +void upd7810_device::ANI_PC_xx() +{ + UINT8 pc = RP( UPD7810_PORTC), imm; + RDOPARG( imm ); + pc &= imm; + WP( UPD7810_PORTC, pc ); + SET_Z(pc); +} + +/* 64 0b: 0110 0100 0000 1011 xxxx xxxx */ +void upd7810_device::ANI_PD_xx() +{ + UINT8 pd = RP( UPD7810_PORTD ), imm; + RDOPARG( imm ); + pd &= imm; + WP( UPD7810_PORTD, pd ); + SET_Z(pd); +} + +/* 64 0d: 0110 0100 0000 1101 xxxx xxxx */ +void upd7810_device::ANI_PF_xx() +{ + UINT8 pf = RP( UPD7810_PORTF ), imm; + RDOPARG( imm ); + pf &= imm; + WP( UPD7810_PORTF, pf ); + SET_Z(pf); +} + +/* 64 0e: 0110 0100 0000 1110 xxxx xxxx */ +void upd7810_device::ANI_MKH_xx() +{ + UINT8 imm; + RDOPARG( imm ); + MKH &= imm; + SET_Z(MKH); +} + +/* 64 0f: 0110 0100 0000 1111 xxxx xxxx */ +void upd7810_device::ANI_MKL_xx() +{ + UINT8 imm; + RDOPARG( imm ); + MKL &= imm; + SET_Z(MKL); +} + +/* 64 10: 0110 0100 0001 0000 xxxx xxxx */ +void upd7810_device::XRI_PA_xx() +{ + UINT8 pa = RP( UPD7810_PORTA ), imm; + RDOPARG( imm ); + pa ^= imm; + WP( UPD7810_PORTA, pa ); + SET_Z(pa); +} + +/* 64 11: 0110 0100 0001 0001 xxxx xxxx */ +void upd7810_device::XRI_PB_xx() +{ + UINT8 pb = RP( UPD7810_PORTB ), imm; + RDOPARG( imm ); + pb ^= imm; + WP( UPD7810_PORTB, pb ); + SET_Z(pb); +} + +/* 64 12: 0110 0100 0001 0010 xxxx xxxx */ +void upd7810_device::XRI_PC_xx() +{ + UINT8 pc = RP( UPD7810_PORTC ), imm; + RDOPARG( imm ); + pc ^= imm; + WP( UPD7810_PORTC, pc ); + SET_Z(pc); +} + +/* 64 13: 0110 0100 0001 0011 xxxx xxxx */ +void upd7810_device::XRI_PD_xx() +{ + UINT8 pd = RP( UPD7810_PORTD ), imm; + RDOPARG( imm ); + pd ^= imm; + WP( UPD7810_PORTD, pd ); + SET_Z(pd); +} + +/* 64 15: 0110 0100 0001 0101 xxxx xxxx */ +void upd7810_device::XRI_PF_xx() +{ + UINT8 pf = RP( UPD7810_PORTF ), imm; + RDOPARG( imm ); + pf ^= imm; + WP( UPD7810_PORTF, pf ); + SET_Z(pf); +} + +/* 64 16: 0110 0100 0001 0110 xxxx xxxx */ +void upd7810_device::XRI_MKH_xx() +{ + UINT8 imm; + RDOPARG( imm ); + MKH ^= imm; + SET_Z(MKH); +} + +/* 64 17: 0110 0100 0001 0111 xxxx xxxx */ +void upd7810_device::XRI_MKL_xx() +{ + UINT8 imm; + RDOPARG( imm ); + MKL ^= imm; + SET_Z(MKL); +} + +/* 64 18: 0110 0100 0001 1000 xxxx xxxx */ +void upd7810_device::ORI_PA_xx() +{ + UINT8 pa = RP( UPD7810_PORTA ), imm; + RDOPARG( imm ); + pa |= imm; + WP( UPD7810_PORTA, pa ); + SET_Z(pa); +} + +/* 64 19: 0110 0100 0001 1001 xxxx xxxx */ +void upd7810_device::ORI_PB_xx() +{ + UINT8 pb = RP( UPD7810_PORTB ), imm; + RDOPARG( imm ); + pb |= imm; + WP( UPD7810_PORTB, pb ); + SET_Z(pb); +} + +/* 64 1a: 0110 0100 0001 1010 xxxx xxxx */ +void upd7810_device::ORI_PC_xx() +{ + UINT8 pc = RP( UPD7810_PORTC ), imm; + RDOPARG( imm ); + pc |= imm; + WP( UPD7810_PORTC, pc ); + SET_Z(pc); +} + +/* 64 1b: 0110 0100 0001 1011 xxxx xxxx */ +void upd7810_device::ORI_PD_xx() +{ + UINT8 pd = RP( UPD7810_PORTD ), imm; + RDOPARG( imm ); + pd |= imm; + WP( UPD7810_PORTD, pd ); + SET_Z(pd); +} + +/* 64 1d: 0110 0100 0001 1101 xxxx xxxx */ +void upd7810_device::ORI_PF_xx() +{ + UINT8 pf = RP( UPD7810_PORTF ), imm; + RDOPARG( imm ); + pf |= imm; + WP( UPD7810_PORTF, pf ); + SET_Z(pf); +} + +/* 64 1e: 0110 0100 0001 1110 xxxx xxxx */ +void upd7810_device::ORI_MKH_xx() +{ + UINT8 imm; + RDOPARG( imm ); + MKH |= imm; + SET_Z(MKH); +} + +/* 64 1f: 0110 0100 0001 1111 xxxx xxxx */ +void upd7810_device::ORI_MKL_xx() +{ + UINT8 imm; + RDOPARG( imm ); + MKL |= imm; + SET_Z(MKL); +} + +/* 64 20: 0110 0100 0010 0000 xxxx xxxx */ +void upd7810_device::ADINC_PA_xx() +{ + UINT8 pa = RP( UPD7810_PORTA ); + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = pa + imm; + + ZHC_ADD( tmp, pa, 0 ); + WP( UPD7810_PORTA , tmp ); + SKIP_NC; +} + +/* 64 21: 0110 0100 0010 0001 xxxx xxxx */ +void upd7810_device::ADINC_PB_xx() +{ + UINT8 pb = RP( UPD7810_PORTB ); + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = pb + imm; + + ZHC_ADD( tmp, pb, 0 ); + WP( UPD7810_PORTB, tmp ); + SKIP_NC; +} + +/* 64 22: 0110 0100 0010 0010 xxxx xxxx */ +void upd7810_device::ADINC_PC_xx() +{ + UINT8 pc = RP( UPD7810_PORTC ); + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = pc + imm; + + ZHC_ADD( tmp, pc, 0 ); + WP( UPD7810_PORTC, tmp ); + SKIP_NC; +} + +/* 64 23: 0110 0100 0010 0011 xxxx xxxx */ +void upd7810_device::ADINC_PD_xx() +{ + UINT8 pd = RP( UPD7810_PORTD ); + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = pd + imm; + + ZHC_ADD( tmp, pd, 0 ); + WP( UPD7810_PORTD, tmp ); + SKIP_NC; +} + +/* 64 25: 0110 0100 0010 0101 xxxx xxxx */ +void upd7810_device::ADINC_PF_xx() +{ + UINT8 pf = RP( UPD7810_PORTF ); + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = pf + imm; + + ZHC_ADD( tmp, pf, 0 ); + WP( UPD7810_PORTF, tmp ); + SKIP_NC; +} + +/* 64 26: 0110 0100 0010 0110 xxxx xxxx */ +void upd7810_device::ADINC_MKH_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = MKH + imm; + + ZHC_ADD( tmp, MKH, 0 ); + MKH = tmp; + SKIP_NC; +} + +/* 64 27: 0110 0100 0010 0111 xxxx xxxx */ +void upd7810_device::ADINC_MKL_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = MKL + imm; + + ZHC_ADD( tmp, MKL, 0 ); + MKL = tmp; + SKIP_NC; +} + +/* 64 28: 0110 0100 0010 1000 xxxx xxxx */ +void upd7810_device::GTI_PA_xx() +{ + UINT8 pa = RP( UPD7810_PORTA ), imm; + UINT16 tmp; + + RDOPARG( imm ); + tmp = pa - imm - 1; + ZHC_SUB( tmp, pa, 0 ); + + SKIP_NC; +} + +/* 64 29: 0110 0100 0010 1001 xxxx xxxx */ +void upd7810_device::GTI_PB_xx() +{ + UINT8 pb = RP( UPD7810_PORTB ), imm; + UINT16 tmp; + + RDOPARG( imm ); + tmp = pb - imm - 1; + ZHC_SUB( tmp, pb, 0 ); + + SKIP_NC; +} + +/* 64 2a: 0110 0100 0010 1010 xxxx xxxx */ +void upd7810_device::GTI_PC_xx() +{ + UINT8 pc = RP( UPD7810_PORTC ), imm; + UINT16 tmp; + + RDOPARG( imm ); + tmp = pc - imm - 1; + ZHC_SUB( tmp, pc, 0 ); + + SKIP_NC; +} + +/* 64 2b: 0110 0100 0010 1011 xxxx xxxx */ +void upd7810_device::GTI_PD_xx() +{ + UINT8 pd = RP( UPD7810_PORTD ), imm; + UINT16 tmp; + + RDOPARG( imm ); + tmp = pd - imm - 1; + ZHC_SUB( tmp, pd, 0 ); + + SKIP_NC; +} + +/* 64 2d: 0110 0100 0010 1101 xxxx xxxx */ +void upd7810_device::GTI_PF_xx() +{ + UINT8 pf = RP( UPD7810_PORTF ), imm; + UINT16 tmp; + + RDOPARG( imm ); + tmp = pf - imm - 1; + ZHC_SUB( tmp, pf, 0 ); + + SKIP_NC; +} + +/* 64 2e: 0110 0100 0010 1110 xxxx xxxx */ +void upd7810_device::GTI_MKH_xx() +{ + UINT8 imm; + UINT16 tmp; + + RDOPARG( imm ); + tmp = MKH - imm - 1; + ZHC_SUB( tmp, MKH, 0 ); + + SKIP_NC; +} + +/* 64 2f: 0110 0100 0010 1111 xxxx xxxx */ +void upd7810_device::GTI_MKL_xx() +{ + UINT8 imm; + UINT16 tmp; + + RDOPARG( imm ); + tmp = MKL - imm - 1; + ZHC_SUB( tmp, MKL, 0 ); + + SKIP_NC; +} + +/* 64 30: 0110 0100 0011 0000 xxxx xxxx */ +void upd7810_device::SUINB_PA_xx() +{ + UINT8 pa = RP( UPD7810_PORTA ), tmp, imm; + + RDOPARG( imm ); + tmp = pa - imm; + ZHC_SUB( tmp, pa, 0 ); + pa = tmp; + WP( UPD7810_PORTA, pa ); + SKIP_NC; +} + +/* 64 31: 0110 0100 0011 0001 xxxx xxxx */ +void upd7810_device::SUINB_PB_xx() +{ + UINT8 pb = RP( UPD7810_PORTB ), tmp, imm; + + RDOPARG( imm ); + tmp = pb - imm; + ZHC_SUB( tmp, pb, 0 ); + pb = tmp; + WP( UPD7810_PORTB, pb ); + SKIP_NC; +} + +/* 64 32: 0110 0100 0011 0010 xxxx xxxx */ +void upd7810_device::SUINB_PC_xx() +{ + UINT8 pc = RP( UPD7810_PORTC ), tmp, imm; + + RDOPARG( imm ); + tmp = pc - imm; + ZHC_SUB( tmp, pc, 0 ); + pc = tmp; + WP( UPD7810_PORTC, pc ); + SKIP_NC; +} + +/* 64 33: 0110 0100 0011 0011 xxxx xxxx */ +void upd7810_device::SUINB_PD_xx() +{ + UINT8 pd = RP( UPD7810_PORTD ), tmp, imm; + + RDOPARG( imm ); + tmp = pd - imm; + ZHC_SUB( tmp, pd, 0 ); + pd = tmp; + WP( UPD7810_PORTD, pd ); + SKIP_NC; +} + +/* 64 35: 0110 0100 0011 0101 xxxx xxxx */ +void upd7810_device::SUINB_PF_xx() +{ + UINT8 pf = RP( UPD7810_PORTF ), tmp, imm; + + RDOPARG( imm ); + tmp = pf - imm; + ZHC_SUB( tmp, pf, 0 ); + pf = tmp; + WP( UPD7810_PORTF, pf ); + SKIP_NC; +} + +/* 64 36: 0110 0100 0011 0110 xxxx xxxx */ +void upd7810_device::SUINB_MKH_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = MKH - imm; + ZHC_SUB( tmp, MKH, 0 ); + MKH = tmp; + SKIP_NC; +} + +/* 64 37: 0110 0100 0011 0111 xxxx xxxx */ +void upd7810_device::SUINB_MKL_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = MKL - imm; + ZHC_SUB( tmp, MKL, 0 ); + MKL = tmp; + SKIP_NC; +} + +/* 64 38: 0110 0100 0011 1000 xxxx xxxx */ +void upd7810_device::LTI_PA_xx() +{ + UINT8 pa = RP( UPD7810_PORTA ), tmp, imm; + RDOPARG( imm ); + tmp = pa - imm; + ZHC_SUB( tmp, pa, 0 ); + SKIP_CY; +} + +/* 64 39: 0110 0100 0011 1001 xxxx xxxx */ +void upd7810_device::LTI_PB_xx() +{ + UINT8 pb = RP( UPD7810_PORTB ), tmp, imm; + RDOPARG( imm ); + tmp = pb - imm; + ZHC_SUB( tmp, pb, 0 ); + SKIP_CY; +} + +/* 64 3a: 0110 0100 0011 1010 xxxx xxxx */ +void upd7810_device::LTI_PC_xx() +{ + UINT8 pc = RP( UPD7810_PORTC ), tmp, imm; + RDOPARG( imm ); + tmp = pc - imm; + ZHC_SUB( tmp, pc, 0 ); + SKIP_CY; +} + +/* 64 3b: 0110 0100 0011 1011 xxxx xxxx */ +void upd7810_device::LTI_PD_xx() +{ + UINT8 pd = RP( UPD7810_PORTD ), tmp, imm; + RDOPARG( imm ); + tmp = pd - imm; + ZHC_SUB( tmp, pd, 0 ); + SKIP_CY; +} + +/* 64 3d: 0110 0100 0011 1101 xxxx xxxx */ +void upd7810_device::LTI_PF_xx() +{ + UINT8 pf = RP( UPD7810_PORTF ), tmp, imm; + RDOPARG( imm ); + tmp = pf - imm; + ZHC_SUB( tmp, pf, 0 ); + SKIP_CY; +} + +/* 64 3e: 0110 0100 0011 1110 xxxx xxxx */ +void upd7810_device::LTI_MKH_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = MKH - imm; + ZHC_SUB( tmp, MKH, 0 ); + SKIP_CY; +} + +/* 64 3f: 0110 0100 0011 1111 xxxx xxxx */ +void upd7810_device::LTI_MKL_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = MKL - imm; + ZHC_SUB( tmp, MKL, 0 ); + SKIP_CY; +} + +/* 64 40: 0110 0100 0100 0000 xxxx xxxx */ +void upd7810_device::ADI_PA_xx() +{ + UINT8 pa = RP( UPD7810_PORTA ), tmp, imm; + + RDOPARG( imm ); + tmp = pa + imm; + ZHC_ADD( tmp, pa, 0 ); + pa = tmp; + WP( UPD7810_PORTA, pa ); +} + +/* 64 41: 0110 0100 0100 0001 xxxx xxxx */ +void upd7810_device::ADI_PB_xx() +{ + UINT8 pb = RP( UPD7810_PORTB ), tmp, imm; + + RDOPARG( imm ); + tmp = pb + imm; + ZHC_ADD( tmp, pb, 0 ); + pb = tmp; + WP( UPD7810_PORTB, pb ); +} + +/* 64 42: 0110 0100 0100 0010 xxxx xxxx */ +void upd7810_device::ADI_PC_xx() +{ + UINT8 pc = RP( UPD7810_PORTC ), tmp, imm; + + RDOPARG( imm ); + tmp = pc + imm; + ZHC_ADD( tmp, pc, 0 ); + pc = tmp; + WP( UPD7810_PORTC, pc ); +} + +/* 64 43: 0110 0100 0100 0011 xxxx xxxx */ +void upd7810_device::ADI_PD_xx() +{ + UINT8 pd = RP( UPD7810_PORTD ), tmp, imm; + + RDOPARG( imm ); + tmp = pd + imm; + ZHC_ADD( tmp, pd, 0 ); + pd = tmp; + WP( UPD7810_PORTD, pd ); +} + +/* 64 45: 0110 0100 0100 0101 xxxx xxxx */ +void upd7810_device::ADI_PF_xx() +{ + UINT8 pf = RP( UPD7810_PORTF ), tmp, imm; + + RDOPARG( imm ); + tmp = pf + imm; + ZHC_ADD( tmp, pf, 0 ); + pf = tmp; + WP( UPD7810_PORTF, pf ); +} + +/* 64 46: 0110 0100 0100 0110 xxxx xxxx */ +void upd7810_device::ADI_MKH_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = MKH + imm; + ZHC_ADD( tmp, MKH, 0 ); + MKH = tmp; +} + +/* 64 47: 0110 0100 0100 0111 xxxx xxxx */ +void upd7810_device::ADI_MKL_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = MKL + imm; + ZHC_ADD( tmp, MKL, 0 ); + MKL = tmp; +} + +/* 64 48: 0110 0100 0100 1000 xxxx xxxx */ +void upd7810_device::ONI_PA_xx() +{ + UINT8 pa = RP( UPD7810_PORTA ), imm; + + RDOPARG( imm ); + if (pa & imm) + PSW |= SK; +} + +/* 64 49: 0110 0100 0100 1001 xxxx xxxx */ +void upd7810_device::ONI_PB_xx() +{ + UINT8 pb = RP( UPD7810_PORTB ), imm; + + RDOPARG( imm ); + if (pb & imm) + PSW |= SK; +} + +/* 64 4a: 0110 0100 0100 1010 xxxx xxxx */ +void upd7810_device::ONI_PC_xx() +{ + UINT8 pc = RP( UPD7810_PORTC ), imm; + + RDOPARG( imm ); + if (pc & imm) + PSW |= SK; +} + +/* 64 4b: 0110 0100 0100 1011 xxxx xxxx */ +void upd7810_device::ONI_PD_xx() +{ + UINT8 pd = RP( UPD7810_PORTD ), imm; + + RDOPARG( imm ); + if (pd & imm) + PSW |= SK; +} + +/* 64 4d: 0110 0100 0100 1101 xxxx xxxx */ +void upd7810_device::ONI_PF_xx() +{ + UINT8 pf = RP( UPD7810_PORTF ), imm; + + RDOPARG( imm ); + if (pf & imm) + PSW |= SK; +} + +/* 64 4e: 0110 0100 0100 1110 xxxx xxxx */ +void upd7810_device::ONI_MKH_xx() +{ + UINT8 imm; + + RDOPARG( imm ); + if (MKH & imm) + PSW |= SK; +} + +/* 64 4f: 0110 0100 0100 1111 xxxx xxxx */ +void upd7810_device::ONI_MKL_xx() +{ + UINT8 imm; + + RDOPARG( imm ); + if (MKL & imm) + PSW |= SK; +} + +/* 64 50: 0110 0100 0101 0000 xxxx xxxx */ +void upd7810_device::ACI_PA_xx() +{ + UINT8 pa = RP( UPD7810_PORTA ), tmp, imm; + + RDOPARG( imm ); + tmp = pa + imm + (PSW & CY); + ZHC_ADD( tmp, pa, (PSW & CY) ); + pa = tmp; + WP( UPD7810_PORTA, pa ); +} + +/* 64 51: 0110 0100 0101 0001 xxxx xxxx */ +void upd7810_device::ACI_PB_xx() +{ + UINT8 pb = RP( UPD7810_PORTB ), tmp, imm; + + RDOPARG( imm ); + tmp = pb + imm + (PSW & CY); + ZHC_ADD( tmp, pb, (PSW & CY) ); + pb = tmp; + WP( UPD7810_PORTB, pb ); +} + +/* 64 52: 0110 0100 0101 0010 xxxx xxxx */ +void upd7810_device::ACI_PC_xx() +{ + UINT8 pc = RP( UPD7810_PORTC ), tmp, imm; + + RDOPARG( imm ); + tmp = pc + imm + (PSW & CY); + ZHC_ADD( tmp, pc, (PSW & CY) ); + pc = tmp; + WP( UPD7810_PORTC, pc ); +} + +/* 64 53: 0110 0100 0101 0011 xxxx xxxx */ +void upd7810_device::ACI_PD_xx() +{ + UINT8 pd = RP( UPD7810_PORTD ), tmp, imm; + + RDOPARG( imm ); + tmp = pd + imm + (PSW & CY); + ZHC_ADD( tmp, pd, (PSW & CY) ); + pd = tmp; + WP( UPD7810_PORTD, pd ); +} + +/* 64 55: 0110 0100 0101 0101 xxxx xxxx */ +void upd7810_device::ACI_PF_xx() +{ + UINT8 pf = RP( UPD7810_PORTF ), tmp, imm; + + RDOPARG( imm ); + tmp = pf + imm + (PSW & CY); + ZHC_ADD( tmp, pf, (PSW & CY) ); + pf = tmp; + WP( UPD7810_PORTF, pf ); +} + +/* 64 56: 0110 0100 0101 0110 xxxx xxxx */ +void upd7810_device::ACI_MKH_xx() +{ + UINT8 imm, tmp; + + RDOPARG( imm ); + tmp = MKH + imm + (PSW & CY); + ZHC_ADD( tmp, MKH, (PSW & CY) ); + MKH = tmp; +} + +/* 64 57: 0110 0100 0101 0111 xxxx xxxx */ +void upd7810_device::ACI_MKL_xx() +{ + UINT8 imm, tmp; + + RDOPARG( imm ); + tmp = MKL + imm + (PSW & CY); + ZHC_ADD( tmp, MKL, (PSW & CY) ); + MKL = tmp; +} + +/* 64 58: 0110 0100 0101 1000 xxxx xxxx */ +void upd7810_device::OFFI_PA_xx() +{ + UINT8 pa = RP( UPD7810_PORTA ), imm; + + RDOPARG( imm ); + if (0 == (pa & imm)) + PSW |= SK; +} + +/* 64 59: 0110 0100 0101 1001 xxxx xxxx */ +void upd7810_device::OFFI_PB_xx() +{ + UINT8 pb = RP( UPD7810_PORTB ), imm; + + RDOPARG( imm ); + if (0 == (pb & imm)) + PSW |= SK; +} + +/* 64 5a: 0110 0100 0101 1010 xxxx xxxx */ +void upd7810_device::OFFI_PC_xx() +{ + UINT8 pc = RP( UPD7810_PORTC ), imm; + + RDOPARG( imm ); + if (0 == (pc & imm)) + PSW |= SK; +} + +/* 64 5b: 0110 0100 0101 1011 xxxx xxxx */ +void upd7810_device::OFFI_PD_xx() +{ + UINT8 pd = RP( UPD7810_PORTD ), imm; + + RDOPARG( imm ); + if (0 == (pd & imm)) + PSW |= SK; +} + +/* 64 5d: 0110 0100 0101 1101 xxxx xxxx */ +void upd7810_device::OFFI_PF_xx() +{ + UINT8 pf = RP( UPD7810_PORTF ), imm; + + RDOPARG( imm ); + if (0 == (pf & imm)) + PSW |= SK; +} + +/* 64 5e: 0110 0100 0101 1110 xxxx xxxx */ +void upd7810_device::OFFI_MKH_xx() +{ + UINT8 imm; + + RDOPARG( imm ); + if (0 == (MKH & imm)) + PSW |= SK; +} + +/* 64 5f: 0110 0100 0101 1111 xxxx xxxx */ +void upd7810_device::OFFI_MKL_xx() +{ + UINT8 imm; + + RDOPARG( imm ); + if (0 == (MKL & imm)) + PSW |= SK; +} + +/* 64 60: 0110 0100 0110 0000 xxxx xxxx */ +void upd7810_device::SUI_PA_xx() +{ + UINT8 pa = RP( UPD7810_PORTA ), tmp, imm; + + RDOPARG( imm ); + tmp = pa - imm; + ZHC_SUB( tmp, pa, 0 ); + pa = tmp; + WP( UPD7810_PORTA, pa ); +} + +/* 64 61: 0110 0100 0110 0001 xxxx xxxx */ +void upd7810_device::SUI_PB_xx() +{ + UINT8 pb = RP( UPD7810_PORTB ), tmp, imm; + + RDOPARG( imm ); + tmp = pb - imm; + ZHC_SUB( tmp, pb, 0 ); + pb = tmp; + WP( UPD7810_PORTB, pb ); +} + +/* 64 62: 0110 0100 0110 0010 xxxx xxxx */ +void upd7810_device::SUI_PC_xx() +{ + UINT8 pc = RP( UPD7810_PORTC ), tmp, imm; + + RDOPARG( imm ); + tmp = pc - imm; + ZHC_SUB( tmp, pc, 0 ); + pc = tmp; + WP( UPD7810_PORTC, pc ); +} + +/* 64 63: 0110 0100 0110 0011 xxxx xxxx */ +void upd7810_device::SUI_PD_xx() +{ + UINT8 pd = RP( UPD7810_PORTD ), tmp, imm; + + RDOPARG( imm ); + tmp = pd - imm; + ZHC_SUB( tmp, pd, 0 ); + pd = tmp; + WP( UPD7810_PORTD, pd ); +} + +/* 64 65: 0110 0100 0110 0101 xxxx xxxx */ +void upd7810_device::SUI_PF_xx() +{ + UINT8 pf = RP( UPD7810_PORTF ), tmp, imm; + + RDOPARG( imm ); + tmp = pf - imm; + ZHC_SUB( tmp, pf, 0 ); + pf = tmp; + WP( UPD7810_PORTF, pf ); +} + +/* 64 66: 0110 0100 0110 0110 xxxx xxxx */ +void upd7810_device::SUI_MKH_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = MKH - imm; + ZHC_SUB( tmp, MKH, 0 ); + MKH = tmp; +} + +/* 64 67: 0110 0100 0110 0111 xxxx xxxx */ +void upd7810_device::SUI_MKL_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = MKL - imm; + ZHC_SUB( tmp, MKL, 0 ); + MKL = tmp; +} + +/* 64 68: 0110 0100 0110 1000 xxxx xxxx */ +void upd7810_device::NEI_PA_xx() +{ + UINT8 pa = RP( UPD7810_PORTA ), tmp, imm; + + RDOPARG( imm ); + tmp = pa - imm; + ZHC_SUB( tmp, pa, 0 ); + SKIP_NZ; +} + +/* 64 69: 0110 0100 0110 1001 xxxx xxxx */ +void upd7810_device::NEI_PB_xx() +{ + UINT8 pb = RP( UPD7810_PORTB ), tmp, imm; + + RDOPARG( imm ); + tmp = pb - imm; + ZHC_SUB( tmp, pb, 0 ); + SKIP_NZ; +} + +/* 64 6a: 0110 0100 0110 1010 xxxx xxxx */ +void upd7810_device::NEI_PC_xx() +{ + UINT8 pc = RP( UPD7810_PORTC ), tmp, imm; + + RDOPARG( imm ); + tmp = pc - imm; + ZHC_SUB( tmp, pc, 0 ); + SKIP_NZ; +} + +/* 64 6b: 0110 0100 0110 1011 xxxx xxxx */ +void upd7810_device::NEI_PD_xx() +{ + UINT8 pd = RP( UPD7810_PORTD ), tmp, imm; + + RDOPARG( imm ); + tmp = pd - imm; + ZHC_SUB( tmp, pd, 0 ); + SKIP_NZ; +} + +/* 64 6d: 0110 0100 0110 1101 xxxx xxxx */ +void upd7810_device::NEI_PF_xx() +{ + UINT8 pf = RP( UPD7810_PORTF ), tmp, imm; + + RDOPARG( imm ); + tmp = pf - imm; + ZHC_SUB( tmp, pf, 0 ); + SKIP_NZ; +} + +/* 64 6e: 0110 0100 0110 1110 xxxx xxxx */ +void upd7810_device::NEI_MKH_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = MKH - imm; + ZHC_SUB( tmp, MKH, 0 ); + SKIP_NZ; +} + +/* 64 6f: 0110 0100 0110 1111 xxxx xxxx */ +void upd7810_device::NEI_MKL_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = MKL - imm; + ZHC_SUB( tmp, MKL, 0 ); + SKIP_NZ; +} + +/* 64 70: 0110 0100 0111 0000 xxxx xxxx */ +void upd7810_device::SBI_PA_xx() +{ + UINT8 pa = RP( UPD7810_PORTA ), tmp, imm; + + RDOPARG( imm ); + tmp = pa - imm - (PSW & CY); + ZHC_SUB( tmp, pa, (PSW & CY) ); + pa = tmp; + WP( UPD7810_PORTA, pa ); +} + +/* 64 71: 0110 0100 0111 0001 xxxx xxxx */ +void upd7810_device::SBI_PB_xx() +{ + UINT8 pb = RP( UPD7810_PORTB ), tmp, imm; + + RDOPARG( imm ); + tmp = pb - imm - (PSW & CY); + ZHC_SUB( tmp, pb, (PSW & CY) ); + pb = tmp; + WP( UPD7810_PORTB, pb ); +} + +/* 64 72: 0110 0100 0111 0010 xxxx xxxx */ +void upd7810_device::SBI_PC_xx() +{ + UINT8 pc = RP( UPD7810_PORTC ), tmp, imm; + + RDOPARG( imm ); + tmp = pc - imm - (PSW & CY); + ZHC_SUB( tmp, pc, (PSW & CY) ); + pc = tmp; + WP( UPD7810_PORTC, pc ); +} + +/* 64 73: 0110 0100 0111 0011 xxxx xxxx */ +void upd7810_device::SBI_PD_xx() +{ + UINT8 pd = RP( UPD7810_PORTD ), tmp, imm; + + RDOPARG( imm ); + tmp = pd - imm - (PSW & CY); + ZHC_SUB( tmp, pd, (PSW & CY) ); + pd = tmp; + WP( UPD7810_PORTD, pd ); +} + +/* 64 75: 0110 0100 0111 0101 xxxx xxxx */ +void upd7810_device::SBI_PF_xx() +{ + UINT8 pf = RP( UPD7810_PORTF ), tmp, imm; + + RDOPARG( imm ); + tmp = pf - imm - (PSW & CY); + ZHC_SUB( tmp, pf, (PSW & CY) ); + pf = tmp; + WP( UPD7810_PORTF, pf ); +} + +/* 64 76: 0110 0100 0111 0110 xxxx xxxx */ +void upd7810_device::SBI_MKH_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = MKH - imm - (PSW & CY); + ZHC_SUB( tmp, MKH, (PSW & CY) ); + MKH = tmp; +} + +/* 64 77: 0110 0100 0111 0111 xxxx xxxx */ +void upd7810_device::SBI_MKL_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = MKL - imm - (PSW & CY); + ZHC_SUB( tmp, MKL, (PSW & CY) ); + MKL = tmp; +} + +/* 64 78: 0110 0100 0111 1000 xxxx xxxx */ +void upd7810_device::EQI_PA_xx() +{ + UINT8 pa = RP( UPD7810_PORTA ), tmp, imm; + + RDOPARG( imm ); + tmp = pa - imm; + ZHC_SUB( tmp, pa, 0 ); + SKIP_Z; +} + +/* 64 79: 0110 0100 0111 1001 xxxx xxxx */ +void upd7810_device::EQI_PB_xx() +{ + UINT8 pb = RP( UPD7810_PORTB ), tmp, imm; + + RDOPARG( imm ); + tmp = pb - imm; + ZHC_SUB( tmp, pb, 0 ); + SKIP_Z; +} + +/* 64 7a: 0110 0100 0111 1010 xxxx xxxx */ +void upd7810_device::EQI_PC_xx() +{ + UINT8 pc = RP( UPD7810_PORTC ), tmp, imm; + + RDOPARG( imm ); + tmp = pc - imm; + ZHC_SUB( tmp, pc, 0 ); + SKIP_Z; +} + +/* 64 7b: 0110 0100 0111 1011 xxxx xxxx */ +void upd7810_device::EQI_PD_xx() +{ + UINT8 pd = RP( UPD7810_PORTD ), tmp, imm; + + RDOPARG( imm ); + tmp = pd - imm; + ZHC_SUB( tmp, pd, 0 ); + SKIP_Z; +} + +/* 64 7d: 0110 0100 0111 1101 xxxx xxxx */ +void upd7810_device::EQI_PF_xx() +{ + UINT8 pf = RP( UPD7810_PORTF ), tmp, imm; + + RDOPARG( imm ); + tmp = pf - imm; + ZHC_SUB( tmp, pf, 0 ); + SKIP_Z; +} + +/* 64 7e: 0110 0100 0111 1110 xxxx xxxx */ +void upd7810_device::EQI_MKH_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = MKH - imm; + ZHC_SUB( tmp, MKH, 0 ); + SKIP_Z; +} + +/* 64 7f: 0110 0100 0111 1111 xxxx xxxx */ +void upd7810_device::EQI_MKL_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = MKL - imm; + ZHC_SUB( tmp, MKL, 0 ); + SKIP_Z; +} + +/* 64 80: 0110 0100 1000 0000 xxxx xxxx */ +void upd7810_device::MVI_ANM_xx() +{ + RDOPARG( ANM ); +} + +/* 64 81: 0110 0100 1000 0001 xxxx xxxx */ +void upd7810_device::MVI_SMH_xx() +{ + RDOPARG( SMH ); +} + +/* 64 83: 0110 0100 1000 0011 xxxx xxxx */ +void upd7810_device::MVI_EOM_xx() +{ + RDOPARG( EOM ); + upd7810_write_EOM(); +} + +/* 64 85: 0110 0100 1000 0101 xxxx xxxx */ +void upd7810_device::MVI_TMM_xx() +{ + RDOPARG( TMM ); +} + +/* 64 88: 0110 0100 1000 1000 xxxx xxxx */ +void upd7810_device::ANI_ANM_xx() +{ + UINT8 imm; + + RDOPARG( imm ); + ANM &= imm; + SET_Z(ANM); +} + +/* 64 89: 0110 0100 1000 1001 xxxx xxxx */ +void upd7810_device::ANI_SMH_xx() +{ + UINT8 imm; + + RDOPARG( imm ); + SMH &= imm; + SET_Z(SMH); +} + +/* 64 8b: 0110 0100 1000 1011 xxxx xxxx */ +void upd7810_device::ANI_EOM_xx() +{ + /* only bits #1 and #5 can be read */ + UINT8 eom = EOM & 0x22; + UINT8 imm; + + RDOPARG( imm ); + /* only bits #1 and #5 can be read */ + EOM = eom & imm; + SET_Z(EOM); + upd7810_write_EOM(); +} + +/* 64 8d: 0110 0100 1000 1101 xxxx xxxx */ +void upd7810_device::ANI_TMM_xx() +{ + UINT8 imm; + + RDOPARG( imm ); + TMM &= imm; + SET_Z(TMM); +} + +/* 64 90: 0110 0100 1001 0000 xxxx xxxx */ +void upd7810_device::XRI_ANM_xx() +{ + UINT8 imm; + + RDOPARG( imm ); + ANM ^= imm; + SET_Z(ANM); +} + +/* 64 91: 0110 0100 1001 0001 xxxx xxxx */ +void upd7810_device::XRI_SMH_xx() +{ + UINT8 imm; + + RDOPARG( imm ); + SMH ^= imm; + SET_Z(SMH); +} + +/* 64 93: 0110 0100 1001 0011 xxxx xxxx */ +void upd7810_device::XRI_EOM_xx() +{ + /* only bits #1 and #5 can be read */ + UINT8 eom = EOM & 0x22; + UINT8 imm; + + RDOPARG( imm ); + /* only bits #1 and #5 can be read */ + EOM = eom ^ imm; + SET_Z(EOM); + upd7810_write_EOM(); +} + +/* 64 95: 0110 0100 1001 0101 xxxx xxxx */ +void upd7810_device::XRI_TMM_xx() +{ + UINT8 imm; + + RDOPARG( imm ); + TMM ^= imm; + SET_Z(TMM); +} + +/* 64 98: 0110 0100 1001 1000 xxxx xxxx */ +void upd7810_device::ORI_ANM_xx() +{ + UINT8 imm; + + RDOPARG( imm ); + ANM |= imm; + SET_Z(ANM); +} + +/* 64 99: 0110 0100 1001 1001 xxxx xxxx */ +void upd7810_device::ORI_SMH_xx() +{ + UINT8 imm; + + RDOPARG( imm ); + SMH |= imm; + SET_Z(SMH); +} + +/* 64 9b: 0110 0100 1001 1011 xxxx xxxx */ +void upd7810_device::ORI_EOM_xx() +{ + /* only bits #1 and #5 can be read */ + UINT8 eom = EOM & 0x22; + UINT8 imm; + + RDOPARG( imm ); + /* only bits #1 and #5 can be read */ + EOM = eom | imm; + SET_Z(EOM); + upd7810_write_EOM(); +} + +/* 64 9d: 0110 0100 1001 1101 xxxx xxxx */ +void upd7810_device::ORI_TMM_xx() +{ + UINT8 imm; + + RDOPARG( imm ); + TMM |= imm; + SET_Z(TMM); +} + +/* 64 a0: 0110 0100 1010 0000 xxxx xxxx */ +void upd7810_device::ADINC_ANM_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = ANM + imm; + + ZHC_ADD( tmp, ANM, 0 ); + ANM = tmp; + SKIP_NC; +} + +/* 64 a1: 0110 0100 1010 0001 xxxx xxxx */ +void upd7810_device::ADINC_SMH_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = SMH + imm; + + ZHC_ADD( tmp, SMH, 0 ); + SMH = tmp; + SKIP_NC; +} + +/* 64 a3: 0110 0100 1010 0011 xxxx xxxx */ +void upd7810_device::ADINC_EOM_xx() +{ + /* only bits #1 and #5 can be read */ + UINT8 eom = EOM & 0x22; + UINT8 tmp, imm; + + RDOPARG( imm ); + /* only bits #1 and #5 can be read */ + tmp = eom + imm; + + ZHC_ADD( tmp, eom, 0 ); + EOM = tmp; + SKIP_NC; + upd7810_write_EOM(); +} + +/* 64 a5: 0110 0100 1010 0101 xxxx xxxx */ +void upd7810_device::ADINC_TMM_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = TMM + imm; + + ZHC_ADD( tmp, TMM, 0 ); + TMM = tmp; + SKIP_NC; +} + +/* 64 a8: 0110 0100 1010 1000 xxxx xxxx */ +void upd7810_device::GTI_ANM_xx() +{ + UINT8 imm; + UINT16 tmp; + + RDOPARG( imm ); + tmp = ANM - imm - 1; + ZHC_SUB( tmp, ANM, 0 ); + + SKIP_NC; +} + +/* 64 a9: 0110 0100 1010 1001 xxxx xxxx */ +void upd7810_device::GTI_SMH_xx() +{ + UINT8 imm; + UINT16 tmp; + + RDOPARG( imm ); + tmp = SMH - imm - 1; + ZHC_SUB( tmp, SMH, 0 ); + + SKIP_NC; +} + +/* 64 ab: 0110 0100 1010 1011 xxxx xxxx */ +void upd7810_device::GTI_EOM_xx() +{ + /* only bits #1 and #5 can be read */ + UINT8 eom = EOM & 0x22; + UINT8 imm; + UINT16 tmp; + + RDOPARG( imm ); + tmp = eom - imm - 1; + ZHC_SUB( tmp, eom, 0 ); + + SKIP_NC; +} + +/* 64 ad: 0110 0100 1010 1101 xxxx xxxx */ +void upd7810_device::GTI_TMM_xx() +{ + UINT8 imm; + UINT16 tmp; + + RDOPARG( imm ); + tmp = TMM - imm - 1; + ZHC_SUB( tmp, TMM, 0 ); + + SKIP_NC; +} + +/* 64 b0: 0110 0100 1011 0000 xxxx xxxx */ +void upd7810_device::SUINB_ANM_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = ANM - imm; + ZHC_SUB( tmp, ANM, 0 ); + ANM = tmp; + SKIP_NC; +} + +/* 64 b1: 0110 0100 1011 0001 xxxx xxxx */ +void upd7810_device::SUINB_SMH_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = SMH - imm; + ZHC_SUB( tmp, SMH, 0 ); + SMH = tmp; + SKIP_NC; +} + +/* 64 b3: 0110 0100 1011 0011 xxxx xxxx */ +void upd7810_device::SUINB_EOM_xx() +{ + /* only bits #1 and #5 can be read */ + UINT8 eom = EOM & 0x22; + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = eom - imm; + ZHC_SUB( tmp, eom, 0 ); + EOM = tmp; + SKIP_NC; + upd7810_write_EOM(); +} + +/* 64 b5: 0110 0100 1011 0101 xxxx xxxx */ +void upd7810_device::SUINB_TMM_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = TMM - imm; + ZHC_SUB( tmp, TMM, 0 ); + TMM = tmp; + SKIP_NC; +} + +/* 64 b8: 0110 0100 1011 1000 xxxx xxxx */ +void upd7810_device::LTI_ANM_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = ANM - imm; + ZHC_SUB( tmp, ANM, 0 ); + SKIP_CY; +} + +/* 64 b9: 0110 0100 1011 1001 xxxx xxxx */ +void upd7810_device::LTI_SMH_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = SMH - imm; + ZHC_SUB( tmp, SMH, 0 ); + SKIP_CY; +} + +/* 64 bb: 0110 0100 1011 1011 xxxx xxxx */ +void upd7810_device::LTI_EOM_xx() +{ + /* only bits #1 and #5 can be read */ + UINT8 eom = EOM & 0x22; + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = eom - imm; + ZHC_SUB( tmp, eom, 0 ); + SKIP_CY; +} + +/* 64 bd: 0110 0100 1011 1101 xxxx xxxx */ +void upd7810_device::LTI_TMM_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = TMM - imm; + ZHC_SUB( tmp, TMM, 0 ); + SKIP_CY; +} + +/* 64 c0: 0110 0100 1100 0000 xxxx xxxx */ +void upd7810_device::ADI_ANM_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = ANM + imm; + + ZHC_ADD( tmp, ANM, 0 ); + ANM = tmp; +} + +/* 64 c1: 0110 0100 1100 0001 xxxx xxxx */ +void upd7810_device::ADI_SMH_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = SMH + imm; + + ZHC_ADD( tmp, SMH, 0 ); + SMH = tmp; +} + +/* 64 c3: 0110 0100 1100 0011 xxxx xxxx */ +void upd7810_device::ADI_EOM_xx() +{ + /* only bits #1 and #5 can be read */ + UINT8 eom = EOM & 0x22; + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = eom + imm; + + ZHC_ADD( tmp, eom, 0 ); + EOM = tmp; + upd7810_write_EOM(); +} + +/* 64 c5: 0110 0100 1100 0101 xxxx xxxx */ +void upd7810_device::ADI_TMM_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = TMM + imm; + + ZHC_ADD( tmp, TMM, 0 ); + TMM = tmp; +} + +/* 64 c8: 0110 0100 1100 1000 xxxx xxxx */ +void upd7810_device::ONI_ANM_xx() +{ + UINT8 imm; + + RDOPARG( imm ); + if (ANM & imm) + PSW |= SK; +} + +/* 64 c9: 0110 0100 1100 1001 xxxx xxxx */ +void upd7810_device::ONI_SMH_xx() +{ + UINT8 imm; + + RDOPARG( imm ); + if (SMH & imm) + PSW |= SK; +} + +/* 64 cb: 0110 0100 1100 1011 xxxx xxxx */ +void upd7810_device::ONI_EOM_xx() +{ + /* only bits #1 and #5 can be read */ + UINT8 eom = EOM & 0x22; + UINT8 imm; + + RDOPARG( imm ); + if (eom & imm) + PSW |= SK; +} + +/* 64 cd: 0110 0100 1100 1101 xxxx xxxx */ +void upd7810_device::ONI_TMM_xx() +{ + UINT8 imm; + + RDOPARG( imm ); + if (TMM & imm) + PSW |= SK; +} + +/* 64 d0: 0110 0100 1101 0000 xxxx xxxx */ +void upd7810_device::ACI_ANM_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = ANM + imm + (PSW & CY); + + ZHC_ADD( tmp, ANM, (PSW & CY) ); + ANM = tmp; +} + +/* 64 d1: 0110 0100 1101 0001 xxxx xxxx */ +void upd7810_device::ACI_SMH_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = SMH + imm + (PSW & CY); + + ZHC_ADD( tmp, SMH, (PSW & CY) ); + SMH = tmp; +} + +/* 64 d3: 0110 0100 1101 0011 xxxx xxxx */ +void upd7810_device::ACI_EOM_xx() +{ + /* only bits #1 and #5 can be read */ + UINT8 eom = EOM & 0x22; + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = eom + imm + (PSW & CY); + + ZHC_ADD( tmp, eom, (PSW & CY) ); + EOM = tmp; + upd7810_write_EOM(); +} + +/* 64 d5: 0110 0100 1101 0101 xxxx xxxx */ +void upd7810_device::ACI_TMM_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = TMM + imm + (PSW & CY); + + ZHC_ADD( tmp, TMM, (PSW & CY) ); + TMM = tmp; +} + +/* 64 d8: 0110 0100 1101 1000 xxxx xxxx */ +void upd7810_device::OFFI_ANM_xx() +{ + UINT8 imm; + + RDOPARG( imm ); + if (0 == (ANM & imm)) + PSW |= SK; +} + +/* 64 d9: 0110 0100 1101 1001 xxxx xxxx */ +void upd7810_device::OFFI_SMH_xx() +{ + UINT8 imm; + + RDOPARG( imm ); + if (0 == (SMH & imm)) + PSW |= SK; +} + +/* 64 db: 0110 0100 1101 1011 xxxx xxxx */ +void upd7810_device::OFFI_EOM_xx() +{ + /* only bits #1 and #5 can be read */ + UINT8 eom = EOM & 0x22; + UINT8 imm; + + RDOPARG( imm ); + if (0 == (eom & imm)) + PSW |= SK; +} + +/* 64 dd: 0110 0100 1101 1101 xxxx xxxx */ +void upd7810_device::OFFI_TMM_xx() +{ + UINT8 imm; + + RDOPARG( imm ); + if (0 == (TMM & imm)) + PSW |= SK; +} + +/* 64 e0: 0110 0100 1110 0000 xxxx xxxx */ +void upd7810_device::SUI_ANM_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = ANM - imm; + ZHC_SUB( tmp, ANM, 0 ); + ANM = tmp; +} + +/* 64 e1: 0110 0100 1110 0001 xxxx xxxx */ +void upd7810_device::SUI_SMH_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = SMH - imm; + ZHC_SUB( tmp, SMH, 0 ); + SMH = tmp; +} + +/* 64 e3: 0110 0100 1110 0011 xxxx xxxx */ +void upd7810_device::SUI_EOM_xx() +{ + /* only bits #1 and #5 can be read */ + UINT8 eom = EOM & 0x22; + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = eom - imm; + ZHC_SUB( tmp, eom, 0 ); + EOM = tmp; + upd7810_write_EOM(); +} + +/* 64 e5: 0110 0100 1110 0101 xxxx xxxx */ +void upd7810_device::SUI_TMM_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = TMM - imm; + ZHC_SUB( tmp, TMM, 0 ); + TMM = tmp; +} + +/* 64 e8: 0110 0100 1110 1000 xxxx xxxx */ +void upd7810_device::NEI_ANM_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = ANM - imm; + ZHC_SUB( tmp, ANM, 0 ); + SKIP_NZ; +} + +/* 64 e9: 0110 0100 1110 1001 xxxx xxxx */ +void upd7810_device::NEI_SMH_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = SMH - imm; + ZHC_SUB( tmp, SMH, 0 ); + SKIP_NZ; +} + +/* 64 eb: 0110 0100 1110 1011 xxxx xxxx */ +void upd7810_device::NEI_EOM_xx() +{ + /* only bits #1 and #5 can be read */ + UINT8 eom = EOM & 0x22; + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = eom - imm; + ZHC_SUB( tmp, eom, 0 ); + SKIP_NZ; +} + +/* 64 ed: 0110 0100 1110 1101 xxxx xxxx */ +void upd7810_device::NEI_TMM_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = TMM - imm; + ZHC_SUB( tmp, TMM, 0 ); + SKIP_NZ; +} + +/* 64 f0: 0110 0100 1111 0000 xxxx xxxx */ +void upd7810_device::SBI_ANM_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = ANM - imm - (PSW & CY); + ZHC_SUB( tmp, ANM, (PSW & CY) ); + ANM = tmp; +} + +/* 64 f1: 0110 0100 1111 0001 xxxx xxxx */ +void upd7810_device::SBI_SMH_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = SMH - imm - (PSW & CY); + ZHC_SUB( tmp, SMH, (PSW & CY) ); + SMH = tmp; +} + +/* 64 f3: 0110 0100 1111 0011 xxxx xxxx */ +void upd7810_device::SBI_EOM_xx() +{ + /* only bits #1 and #5 can be read */ + UINT8 eom = EOM & 0x22; + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = eom - imm - (PSW & CY); + ZHC_SUB( tmp, eom, (PSW & CY) ); + EOM = tmp; + upd7810_write_EOM(); +} + +/* 64 f5: 0110 0100 1111 0101 xxxx xxxx */ +void upd7810_device::SBI_TMM_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = TMM - imm - (PSW & CY); + ZHC_SUB( tmp, TMM, (PSW & CY) ); + TMM = tmp; +} + +/* 64 f8: 0110 0100 1111 1000 xxxx xxxx */ +void upd7810_device::EQI_ANM_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = ANM - imm; + ZHC_SUB( tmp, ANM, 0 ); + SKIP_Z; +} + +/* 64 f9: 0110 0100 1111 1001 xxxx xxxx */ +void upd7810_device::EQI_SMH_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = SMH - imm; + ZHC_SUB( tmp, SMH, 0 ); + SKIP_Z; +} + +/* 64 fb: 0110 0100 1111 1011 xxxx xxxx */ +void upd7810_device::EQI_EOM_xx() +{ + /* only bits #1 and #5 can be read */ + UINT8 eom = EOM & 0x22; + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = eom - imm; + ZHC_SUB( tmp, eom, 0 ); + SKIP_Z; +} + +/* 64 fd: 0110 0100 1111 1101 xxxx xxxx */ +void upd7810_device::EQI_TMM_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = TMM - imm; + ZHC_SUB( tmp, TMM, 0 ); + SKIP_Z; +} + +/* prefix 70 */ +/* 70 0e: 0111 0000 0000 1110 llll llll hhhh hhhh */ +void upd7810_device::SSPD_w() +{ + PAIR ea; + ea.d = 0; + + RDOPARG( ea.b.l ); + RDOPARG( ea.b.h ); + WM( ea.d, SPL ); + WM( ea.d + 1, SPH ); +} + +/* 70 0f: 0111 0000 0000 1111 llll llll hhhh hhhh */ +void upd7810_device::LSPD_w() +{ + PAIR ea; + ea.d = 0; + + RDOPARG( ea.b.l ); + RDOPARG( ea.b.h ); + SPL = RM( ea.d ); + SPH = RM( ea.d + 1 ); +} + +/* 70 1e: 0111 0000 0001 1110 llll llll hhhh hhhh */ +void upd7810_device::SBCD_w() +{ + PAIR ea; + ea.d = 0; + + RDOPARG( ea.b.l ); + RDOPARG( ea.b.h ); + WM( ea.d, C ); + WM( ea.d + 1, B ); +} + +/* 70 1f: 0111 0000 0001 1111 llll llll hhhh hhhh */ +void upd7810_device::LBCD_w() +{ + PAIR ea; + ea.d = 0; + + RDOPARG( ea.b.l ); + RDOPARG( ea.b.h ); + C = RM( ea.d ); + B = RM( ea.d + 1 ); +} + +/* 70 2e: 0111 0000 0010 1110 llll llll hhhh hhhh */ +void upd7810_device::SDED_w() +{ + PAIR ea; + ea.d = 0; + + RDOPARG( ea.b.l ); + RDOPARG( ea.b.h ); + WM( ea.d, E ); + WM( ea.d + 1, D ); +} + +/* 70 2f: 0111 0000 0010 1111 llll llll hhhh hhhh */ +void upd7810_device::LDED_w() +{ + PAIR ea; + ea.d = 0; + + RDOPARG( ea.b.l ); + RDOPARG( ea.b.h ); + E = RM( ea.d ); + D = RM( ea.d + 1 ); +} + +/* 70 3e: 0111 0000 0011 1110 llll llll hhhh hhhh */ +void upd7810_device::SHLD_w() +{ + PAIR ea; + ea.d = 0; + + RDOPARG( ea.b.l ); + RDOPARG( ea.b.h ); + WM( ea.d, L ); + WM( ea.d + 1, H ); +} + +/* 70 3f: 0111 0000 0011 1111 llll llll hhhh hhhh */ +void upd7810_device::LHLD_w() +{ + PAIR ea; + ea.d = 0; + + RDOPARG( ea.b.l ); + RDOPARG( ea.b.h ); + L = RM( ea.d ); + H = RM( ea.d + 1 ); +} + +/* 70 41: 0111 0000 0100 0001 */ +void upd7810_device::EADD_EA_A() +{ + UINT16 tmp; + tmp = EA + A; + ZHC_ADD( tmp, EA, 0 ); + EA = tmp; +} + +/* 70 42: 0111 0000 0100 0010 */ +void upd7810_device::EADD_EA_B() +{ + UINT16 tmp; + tmp = EA + B; + ZHC_ADD( tmp, EA, 0 ); + EA = tmp; +} + +/* 70 43: 0111 0000 0100 0011 */ +void upd7810_device::EADD_EA_C() +{ + UINT16 tmp; + tmp = EA + C; + ZHC_ADD( tmp, EA, 0 ); + EA = tmp; +} + +/* 70 61: 0111 0000 0110 0001 */ +void upd7810_device::ESUB_EA_A() +{ + UINT16 tmp; + tmp = EA - A; + ZHC_SUB( tmp, EA, 0 ); + EA = tmp; +} + +/* 70 62: 0111 0000 0110 0010 */ +void upd7810_device::ESUB_EA_B() +{ + UINT16 tmp; + tmp = EA - B; + ZHC_SUB( tmp, EA, 0 ); + EA = tmp; +} + +/* 70 63: 0111 0000 0110 0011 */ +void upd7810_device::ESUB_EA_C() +{ + UINT16 tmp; + tmp = EA - C; + ZHC_SUB( tmp, EA, 0 ); + EA = tmp; +} + +/* 70 68: 0111 0000 0110 1000 llll llll hhhh hhhh */ +void upd7810_device::MOV_V_w() +{ + PAIR ea; + ea.d = 0; + + RDOPARG( ea.b.l ); + RDOPARG( ea.b.h ); + V = RM( ea.d ); +} + +/* 70 69: 0111 0000 0110 1001 llll llll hhhh hhhh */ +void upd7810_device::MOV_A_w() +{ + PAIR ea; + ea.d = 0; + + RDOPARG( ea.b.l ); + RDOPARG( ea.b.h ); + A = RM( ea.d ); +} + +/* 70 6a: 0111 0000 0110 1010 llll llll hhhh hhhh */ +void upd7810_device::MOV_B_w() +{ + PAIR ea; + ea.d = 0; + + RDOPARG( ea.b.l ); + RDOPARG( ea.b.h ); + B = RM( ea.d ); +} + +/* 70 6b: 0111 0000 0110 1011 llll llll hhhh hhhh */ +void upd7810_device::MOV_C_w() +{ + PAIR ea; + ea.d = 0; + + RDOPARG( ea.b.l ); + RDOPARG( ea.b.h ); + C = RM( ea.d ); +} + +/* 70 6c: 0111 0000 0110 1100 llll llll hhhh hhhh */ +void upd7810_device::MOV_D_w() +{ + PAIR ea; + ea.d = 0; + + RDOPARG( ea.b.l ); + RDOPARG( ea.b.h ); + D = RM( ea.d ); +} + +/* 70 6d: 0111 0000 0110 1101 llll llll hhhh hhhh */ +void upd7810_device::MOV_E_w() +{ + PAIR ea; + ea.d = 0; + + RDOPARG( ea.b.l ); + RDOPARG( ea.b.h ); + E = RM( ea.d ); +} + +/* 70 6e: 0111 0000 0110 1110 llll llll hhhh hhhh */ +void upd7810_device::MOV_H_w() +{ + PAIR ea; + ea.d = 0; + + RDOPARG( ea.b.l ); + RDOPARG( ea.b.h ); + H = RM( ea.d ); +} + +/* 70 6f: 0111 0000 0110 1111 llll llll hhhh hhhh */ +void upd7810_device::MOV_L_w() +{ + PAIR ea; + ea.d = 0; + + RDOPARG( ea.b.l ); + RDOPARG( ea.b.h ); + L = RM( ea.d ); +} + +/* 70 78: 0111 0000 0111 1000 llll llll hhhh hhhh */ +void upd7810_device::MOV_w_V() +{ + PAIR ea; + ea.d = 0; + + RDOPARG( ea.b.l ); + RDOPARG( ea.b.h ); + WM( ea.d, V ); +} + +/* 70 79: 0111 0000 0111 1001 llll llll hhhh hhhh */ +void upd7810_device::MOV_w_A() +{ + PAIR ea; + ea.d = 0; + + RDOPARG( ea.b.l ); + RDOPARG( ea.b.h ); + WM( ea.d, A ); +} + +/* 70 7a: 0111 0000 0111 1010 llll llll hhhh hhhh */ +void upd7810_device::MOV_w_B() +{ + PAIR ea; + ea.d = 0; + + RDOPARG( ea.b.l ); + RDOPARG( ea.b.h ); + WM( ea.d, B ); +} + +/* 70 7b: 0111 0000 0111 1011 llll llll hhhh hhhh */ +void upd7810_device::MOV_w_C() +{ + PAIR ea; + ea.d = 0; + + RDOPARG( ea.b.l ); + RDOPARG( ea.b.h ); + WM( ea.d, C ); +} + +/* 70 7c: 0111 0000 0111 1100 llll llll hhhh hhhh */ +void upd7810_device::MOV_w_D() +{ + PAIR ea; + ea.d = 0; + + RDOPARG( ea.b.l ); + RDOPARG( ea.b.h ); + WM( ea.d, D ); +} + +/* 70 7d: 0111 0000 0111 1101 llll llll hhhh hhhh */ +void upd7810_device::MOV_w_E() +{ + PAIR ea; + ea.d = 0; + + RDOPARG( ea.b.l ); + RDOPARG( ea.b.h ); + WM( ea.d, E ); +} + +/* 70 7e: 0111 0000 0111 1110 llll llll hhhh hhhh */ +void upd7810_device::MOV_w_H() +{ + PAIR ea; + ea.d = 0; + + RDOPARG( ea.b.l ); + RDOPARG( ea.b.h ); + WM( ea.d, H ); +} + +/* 70 7f: 0111 0000 0111 1111 llll llll hhhh hhhh */ +void upd7810_device::MOV_w_L() +{ + PAIR ea; + ea.d = 0; + + RDOPARG( ea.b.l ); + RDOPARG( ea.b.h ); + WM( ea.d, L ); +} + +/* 70 89: 0111 0000 1000 1001 */ +void upd7810_device::ANAX_B() +{ + A &= RM( BC ); + SET_Z(A); +} + +/* 70 8a: 0111 0000 1000 1010 */ +void upd7810_device::ANAX_D() +{ + A &= RM( DE ); + SET_Z(A); +} + +/* 70 8b: 0111 0000 1000 1011 */ +void upd7810_device::ANAX_H() +{ + A &= RM( HL ); + SET_Z(A); +} + +/* 70 8c: 0111 0000 1000 1100 */ +void upd7810_device::ANAX_Dp() +{ + A &= RM( DE ); + DE++; + SET_Z(A); +} + +/* 70 8d: 0111 0000 1000 1101 */ +void upd7810_device::ANAX_Hp() +{ + A &= RM( HL ); + HL++; + SET_Z(A); +} + +/* 70 8e: 0111 0000 1000 1110 */ +void upd7810_device::ANAX_Dm() +{ + A &= RM( DE ); + DE--; + SET_Z(A); +} + +/* 70 8f: 0111 0000 1000 1111 */ +void upd7810_device::ANAX_Hm() +{ + A &= RM( HL ); + HL--; + SET_Z(A); +} + +/* 70 91: 0111 0000 1001 0001 */ +void upd7810_device::XRAX_B() +{ + A ^= RM( BC ); + SET_Z(A); +} + +/* 70 92: 0111 0000 1001 0010 */ +void upd7810_device::XRAX_D() +{ + A ^= RM( DE ); + SET_Z(A); +} + +/* 70 93: 0111 0000 1001 0011 */ +void upd7810_device::XRAX_H() +{ + A ^= RM( HL ); + SET_Z(A); +} + +/* 70 94: 0111 0000 1001 0100 */ +void upd7810_device::XRAX_Dp() +{ + A ^= RM( DE ); + DE++; + SET_Z(A); +} + +/* 70 95: 0111 0000 1001 0101 */ +void upd7810_device::XRAX_Hp() +{ + A ^= RM( HL ); + HL++; + SET_Z(A); +} + +/* 70 96: 0111 0000 1001 0110 */ +void upd7810_device::XRAX_Dm() +{ + A ^= RM( DE ); + DE--; + SET_Z(A); +} + +/* 70 97: 0111 0000 1001 0111 */ +void upd7810_device::XRAX_Hm() +{ + A ^= RM( HL ); + HL--; + SET_Z(A); +} + +/* 70 99: 0111 0000 1001 1001 */ +void upd7810_device::ORAX_B() +{ + A |= RM( BC ); + SET_Z(A); +} + +/* 70 9a: 0111 0000 1001 1010 */ +void upd7810_device::ORAX_D() +{ + A |= RM( DE ); + SET_Z(A); +} + +/* 70 9b: 0111 0000 1001 1011 */ +void upd7810_device::ORAX_H() +{ + A |= RM( HL ); + SET_Z(A); +} + +/* 70 9c: 0111 0000 1001 0100 */ +void upd7810_device::ORAX_Dp() +{ + A |= RM( DE ); + DE++; + SET_Z(A); +} + +/* 70 9d: 0111 0000 1001 1101 */ +void upd7810_device::ORAX_Hp() +{ + A |= RM( HL ); + HL++; + SET_Z(A); +} + +/* 70 9e: 0111 0000 1001 1110 */ +void upd7810_device::ORAX_Dm() +{ + A |= RM( DE ); + DE--; + SET_Z(A); +} + +/* 70 9f: 0111 0000 1001 1111 */ +void upd7810_device::ORAX_Hm() +{ + A |= RM( HL ); + HL--; + SET_Z(A); +} + +/* 70 a1: 0111 0000 1010 0001 */ +void upd7810_device::ADDNCX_B() +{ + UINT8 tmp = A + RM( BC ); + ZHC_ADD( tmp, A, 0 ); + A = tmp; + SKIP_NC; +} + +/* 70 a2: 0111 0000 1010 0010 */ +void upd7810_device::ADDNCX_D() +{ + UINT8 tmp = A + RM( DE ); + ZHC_ADD( tmp, A, 0 ); + A = tmp; + SKIP_NC; +} + +/* 70 a3: 0111 0000 1010 0011 */ +void upd7810_device::ADDNCX_H() +{ + UINT8 tmp = A + RM( HL ); + ZHC_ADD( tmp, A, 0 ); + A = tmp; + SKIP_NC; +} + +/* 70 a4: 0111 0000 1010 0100 */ +void upd7810_device::ADDNCX_Dp() +{ + UINT8 tmp = A + RM( DE ); + DE++; + ZHC_ADD( tmp, A, 0 ); + A = tmp; + SKIP_NC; +} + +/* 70 a5: 0111 0000 1010 0101 */ +void upd7810_device::ADDNCX_Hp() +{ + UINT8 tmp = A + RM( HL ); + HL++; + ZHC_ADD( tmp, A, 0 ); + A = tmp; + SKIP_NC; +} + +/* 70 a6: 0111 0000 1010 0110 */ +void upd7810_device::ADDNCX_Dm() +{ + UINT8 tmp = A + RM( DE ); + DE--; + ZHC_ADD( tmp, A, 0 ); + A = tmp; + SKIP_NC; +} + +/* 70 a7: 0111 0000 1010 0111 */ +void upd7810_device::ADDNCX_Hm() +{ + UINT8 tmp = A + RM( HL ); + HL--; + ZHC_ADD( tmp, A, 0 ); + A = tmp; + SKIP_NC; +} + +/* 70 a9: 0111 0000 1010 1001 */ +void upd7810_device::GTAX_B() +{ + UINT16 tmp = A - RM( BC ) - 1; + ZHC_SUB( tmp, A, 0 ); + SKIP_NC; +} + +/* 70 aa: 0111 0000 1010 1010 */ +void upd7810_device::GTAX_D() +{ + UINT16 tmp = A - RM( DE ) - 1; + ZHC_SUB( tmp, A, 0 ); + SKIP_NC; +} + +/* 70 ab: 0111 0000 1010 1011 */ +void upd7810_device::GTAX_H() +{ + UINT16 tmp = A - RM( HL ) - 1; + ZHC_SUB( tmp, A, 0 ); + SKIP_NC; +} + +/* 70 ac: 0111 0000 1010 1100 */ +void upd7810_device::GTAX_Dp() +{ + UINT16 tmp = A - RM( DE ) - 1; + DE++; + ZHC_SUB( tmp, A, 0 ); + SKIP_NC; +} + +/* 70 ad: 0111 0000 1010 1101 */ +void upd7810_device::GTAX_Hp() +{ + UINT16 tmp = A - RM( HL ) - 1; + HL++; + ZHC_SUB( tmp, A, 0 ); + SKIP_NC; +} + +/* 70 ae: 0111 0000 1010 1110 */ +void upd7810_device::GTAX_Dm() +{ + UINT16 tmp = A - RM( DE ) - 1; + DE--; + ZHC_SUB( tmp, A, 0 ); + SKIP_NC; +} + +/* 70 af: 0111 0000 1010 1111 */ +void upd7810_device::GTAX_Hm() +{ + UINT16 tmp = A - RM( HL ) - 1; + HL--; + ZHC_SUB( tmp, A, 0 ); + SKIP_NC; +} + +/* 70 b1: 0111 0000 1011 0001 */ +void upd7810_device::SUBNBX_B() +{ + UINT8 tmp = A - RM( BC ); + ZHC_SUB( tmp, A, 0 ); + A = tmp; + SKIP_NC; +} + +/* 70 b2: 0111 0000 1011 0010 */ +void upd7810_device::SUBNBX_D() +{ + UINT8 tmp = A - RM( DE ); + ZHC_SUB( tmp, A, 0 ); + A = tmp; + SKIP_NC; +} + +/* 70 b3: 0111 0000 1011 0011 */ +void upd7810_device::SUBNBX_H() +{ + UINT8 tmp = A - RM( HL ); + ZHC_SUB( tmp, A, 0 ); + A = tmp; + SKIP_NC; +} + +/* 70 b4: 0111 0000 1011 0100 */ +void upd7810_device::SUBNBX_Dp() +{ + UINT8 tmp = A - RM( DE ); + DE++; + ZHC_SUB( tmp, A, 0 ); + A = tmp; + SKIP_NC; +} + +/* 70 b5: 0111 0000 1011 0101 */ +void upd7810_device::SUBNBX_Hp() +{ + UINT8 tmp = A - RM( HL ); + HL++; + ZHC_SUB( tmp, A, 0 ); + A = tmp; + SKIP_NC; +} + +/* 70 b6: 0111 0000 1011 0110 */ +void upd7810_device::SUBNBX_Dm() +{ + UINT8 tmp = A - RM( DE ); + DE--; + ZHC_SUB( tmp, A, 0 ); + A = tmp; + SKIP_NC; +} + +/* 70 b7: 0111 0000 1011 0111 */ +void upd7810_device::SUBNBX_Hm() +{ + UINT8 tmp = A - RM( HL ); + HL--; + ZHC_SUB( tmp, A, 0 ); + A = tmp; + SKIP_NC; +} + +/* 70 b9: 0111 0000 1011 1001 */ +void upd7810_device::LTAX_B() +{ + UINT8 tmp = A - RM( BC ); + ZHC_SUB( tmp, A, 0 ); + SKIP_CY; +} + +/* 70 ba: 0111 0000 1011 1010 */ +void upd7810_device::LTAX_D() +{ + UINT8 tmp = A - RM( DE ); + ZHC_SUB( tmp, A, 0 ); + SKIP_CY; +} + +/* 70 bb: 0111 0000 1011 1011 */ +void upd7810_device::LTAX_H() +{ + UINT8 tmp = A - RM( HL ); + ZHC_SUB( tmp, A, 0 ); + SKIP_CY; +} + +/* 70 bc: 0111 0000 1011 1100 */ +void upd7810_device::LTAX_Dp() +{ + UINT8 tmp = A - RM( DE ); + DE++; + ZHC_SUB( tmp, A, 0 ); + SKIP_CY; +} + +/* 70 bd: 0111 0000 1011 1101 */ +void upd7810_device::LTAX_Hp() +{ + UINT8 tmp = A - RM( HL ); + HL++; + ZHC_SUB( tmp, A, 0 ); + SKIP_CY; +} + +/* 70 be: 0111 0000 1011 1110 */ +void upd7810_device::LTAX_Dm() +{ + UINT8 tmp = A - RM( DE ); + DE--; + ZHC_SUB( tmp, A, 0 ); + SKIP_CY; +} + +/* 70 bf: 0111 0000 1011 1111 */ +void upd7810_device::LTAX_Hm() +{ + UINT8 tmp = A - RM( HL ); + HL--; + ZHC_SUB( tmp, A, 0 ); + SKIP_CY; +} + +/* 70 c1: 0111 0000 1100 0001 */ +void upd7810_device::ADDX_B() +{ + UINT8 tmp = A + RM( BC ); + ZHC_ADD( tmp, A, 0 ); + A = tmp; +} + +/* 70 c2: 0111 0000 1100 0010 */ +void upd7810_device::ADDX_D() +{ + UINT8 tmp = A + RM( DE ); + ZHC_ADD( tmp, A, 0 ); + A = tmp; +} + +/* 70 c3: 0111 0000 1100 0011 */ +void upd7810_device::ADDX_H() +{ + UINT8 tmp = A + RM( HL ); + ZHC_ADD( tmp, A, 0 ); + A = tmp; +} + +/* 70 c4: 0111 0000 1100 0100 */ +void upd7810_device::ADDX_Dp() +{ + UINT8 tmp = A + RM( DE ); + DE++; + ZHC_ADD( tmp, A, 0 ); + A = tmp; +} + +/* 70 c5: 0111 0000 1100 0101 */ +void upd7810_device::ADDX_Hp() +{ + UINT8 tmp = A + RM( HL ); + HL++; + ZHC_ADD( tmp, A, 0 ); + A = tmp; +} + +/* 70 c6: 0111 0000 1100 0110 */ +void upd7810_device::ADDX_Dm() +{ + UINT8 tmp = A + RM( DE ); + DE--; + ZHC_ADD( tmp, A, 0 ); + A = tmp; +} + +/* 70 c7: 0111 0000 1100 0111 */ +void upd7810_device::ADDX_Hm() +{ + UINT8 tmp = A + RM( HL ); + HL--; + ZHC_ADD( tmp, A, 0 ); + A = tmp; +} + +/* 70 c9: 0111 0000 1100 1001 */ +void upd7810_device::ONAX_B() +{ + if (A & RM( BC )) + PSW = (PSW & ~Z) | SK; + else + PSW |= Z; +} + +/* 70 ca: 0111 0000 1100 1010 */ +void upd7810_device::ONAX_D() +{ + if (A & RM( DE )) + PSW = (PSW & ~Z) | SK; + else + PSW |= Z; +} + +/* 70 cb: 0111 0000 1100 1011 */ +void upd7810_device::ONAX_H() +{ + if (A & RM( HL )) + PSW = (PSW & ~Z) | SK; + else + PSW |= Z; +} + +/* 70 cc: 0111 0000 1100 1100 */ +void upd7810_device::ONAX_Dp() +{ + if (A & RM( DE )) + PSW = (PSW & ~Z) | SK; + else + PSW |= Z; + DE++; +} + +/* 70 cd: 0111 0000 1100 1101 */ +void upd7810_device::ONAX_Hp() +{ + if (A & RM( HL )) + PSW = (PSW & ~Z) | SK; + else + PSW |= Z; + HL++; +} + +/* 70 ce: 0111 0000 1100 1110 */ +void upd7810_device::ONAX_Dm() +{ + if (A & RM( DE )) + PSW = (PSW & ~Z) | SK; + else + PSW |= Z; + DE--; +} + +/* 70 cf: 0111 0000 1100 1111 */ +void upd7810_device::ONAX_Hm() +{ + if (A & RM( HL )) + PSW = (PSW & ~Z) | SK; + else + PSW |= Z; + HL--; +} + +/* 70 d1: 0111 0000 1101 0001 */ +void upd7810_device::ADCX_B() +{ + UINT8 tmp = A + RM( BC ) + (PSW & CY); + ZHC_ADD( tmp, A, 0 ); + A = tmp; +} + +/* 70 d2: 0111 0000 1101 0010 */ +void upd7810_device::ADCX_D() +{ + UINT8 tmp = A + RM( DE ) + (PSW & CY); + ZHC_ADD( tmp, A, 0 ); + A = tmp; +} + +/* 70 d3: 0111 0000 1101 0011 */ +void upd7810_device::ADCX_H() +{ + UINT8 tmp = A + RM( HL ) + (PSW & CY); + ZHC_ADD( tmp, A, 0 ); + A = tmp; +} + +/* 70 d4: 0111 0000 1101 0100 */ +void upd7810_device::ADCX_Dp() +{ + UINT8 tmp = A + RM( DE ) + (PSW & CY); + DE++; + ZHC_ADD( tmp, A, 0 ); + A = tmp; +} + +/* 70 d5: 0111 0000 1101 0101 */ +void upd7810_device::ADCX_Hp() +{ + UINT8 tmp = A + RM( HL ) + (PSW & CY); + HL++; + ZHC_ADD( tmp, A, 0 ); + A = tmp; +} + +/* 70 d6: 0111 0000 1101 0110 */ +void upd7810_device::ADCX_Dm() +{ + UINT8 tmp = A + RM( DE ) + (PSW & CY); + DE--; + ZHC_ADD( tmp, A, 0 ); + A = tmp; +} + +/* 70 d7: 0111 0000 1101 0111 */ +void upd7810_device::ADCX_Hm() +{ + UINT8 tmp = A + RM( HL ) + (PSW & CY); + HL--; + ZHC_ADD( tmp, A, 0 ); + A = tmp; +} + +/* 70 d9: 0111 0000 1101 1001 */ +void upd7810_device::OFFAX_B() +{ + if ( A & RM( BC ) ) + PSW &= ~Z; + else + PSW = PSW | Z | SK; +} + +/* 70 da: 0111 0000 1101 1010 */ +void upd7810_device::OFFAX_D() +{ + if ( A & RM( DE ) ) + PSW &= ~Z; + else + PSW = PSW | Z | SK; +} + +/* 70 db: 0111 0000 1101 1011 */ +void upd7810_device::OFFAX_H() +{ + if ( A & RM( HL ) ) + PSW &= ~Z; + else + PSW = PSW | Z | SK; +} + +/* 70 dc: 0111 0000 1101 1100 */ +void upd7810_device::OFFAX_Dp() +{ + if ( A & RM( DE ) ) + PSW &= ~Z; + else + PSW = PSW | Z | SK; + DE++; +} + +/* 70 dd: 0111 0000 1101 1101 */ +void upd7810_device::OFFAX_Hp() +{ + if ( A & RM( HL ) ) + PSW &= ~Z; + else + PSW = PSW | Z | SK; + HL++; +} + +/* 70 de: 0111 0000 1101 1110 */ +void upd7810_device::OFFAX_Dm() +{ + if ( A & RM( DE ) ) + PSW &= ~Z; + else + PSW = PSW | Z | SK; + DE--; +} + +/* 70 df: 0111 0000 1101 1111 */ +void upd7810_device::OFFAX_Hm() +{ + if ( A & RM( HL ) ) + PSW &= ~Z; + else + PSW = PSW | Z | SK; + HL--; +} + +/* 70 e1: 0111 0000 1110 0001 */ +void upd7810_device::SUBX_B() +{ + UINT8 tmp = A - RM( BC ); + ZHC_SUB( tmp, A, 0 ); + A = tmp; +} + +/* 70 e2: 0111 0000 1110 0010 */ +void upd7810_device::SUBX_D() +{ + UINT8 tmp = A - RM( DE ); + ZHC_SUB( tmp, A, 0 ); + A = tmp; +} + +/* 70 e3: 0111 0000 1110 0011 */ +void upd7810_device::SUBX_H() +{ + UINT8 tmp = A - RM( HL ); + ZHC_SUB( tmp, A, 0 ); + A = tmp; +} + +/* 70 e4: 0111 0000 1110 0100 */ +void upd7810_device::SUBX_Dp() +{ + UINT8 tmp = A - RM( DE ); + ZHC_SUB( tmp, A, 0 ); + A = tmp; + DE++; +} + +/* 70 e5: 0111 0000 1110 0101 */ +void upd7810_device::SUBX_Hp() +{ + UINT8 tmp = A - RM( HL ); + ZHC_SUB( tmp, A, 0 ); + A = tmp; + HL++; +} + +/* 70 e6: 0111 0000 1110 0110 */ +void upd7810_device::SUBX_Dm() +{ + UINT8 tmp = A - RM( DE ); + ZHC_SUB( tmp, A, 0 ); + A = tmp; + DE--; +} + +/* 70 e7: 0111 0000 1110 0111 */ +void upd7810_device::SUBX_Hm() +{ + UINT8 tmp = A - RM( HL ); + ZHC_SUB( tmp, A, 0 ); + A = tmp; + HL--; +} + +/* 70 e9: 0111 0000 1110 1001 */ +void upd7810_device::NEAX_B() +{ + UINT8 tmp = A - RM( BC ); + ZHC_SUB( tmp, A, 0 ); + SKIP_NZ; +} + +/* 70 ea: 0111 0000 1110 1010 */ +void upd7810_device::NEAX_D() +{ + UINT8 tmp = A - RM( DE ); + ZHC_SUB( tmp, A, 0 ); + SKIP_NZ; +} + +/* 70 eb: 0111 0000 1110 1011 */ +void upd7810_device::NEAX_H() +{ + UINT8 tmp = A - RM( HL ); + ZHC_SUB( tmp, A, 0 ); + SKIP_NZ; +} + +/* 70 ec: 0111 0000 1110 1100 */ +void upd7810_device::NEAX_Dp() +{ + UINT8 tmp = A - RM( DE ); + DE++; + ZHC_SUB( tmp, A, 0 ); + SKIP_NZ; +} + +/* 70 ed: 0111 0000 1110 1101 */ +void upd7810_device::NEAX_Hp() +{ + UINT8 tmp = A - RM( HL ); + HL++; + ZHC_SUB( tmp, A, 0 ); + SKIP_NZ; +} + +/* 70 ee: 0111 0000 1110 1110 */ +void upd7810_device::NEAX_Dm() +{ + UINT8 tmp = A - RM( DE ); + DE--; + ZHC_SUB( tmp, A, 0 ); + SKIP_NZ; +} + +/* 70 ef: 0111 0000 1110 1111 */ +void upd7810_device::NEAX_Hm() +{ + UINT8 tmp = A - RM( HL ); + HL--; + ZHC_SUB( tmp, A, 0 ); + SKIP_NZ; +} + +/* 70 f1: 0111 0000 1111 0001 */ +void upd7810_device::SBBX_B() +{ + UINT8 tmp = A - RM( BC ) - (PSW & CY); + ZHC_SUB( tmp, A, (PSW & CY) ); + A = tmp; +} + +/* 70 f2: 0111 0000 1111 0010 */ +void upd7810_device::SBBX_D() +{ + UINT8 tmp = A - RM( DE ) - (PSW & CY); + ZHC_SUB( tmp, A, (PSW & CY) ); + A = tmp; +} + +/* 70 f3: 0111 0000 1111 0011 */ +void upd7810_device::SBBX_H() +{ + UINT8 tmp = A - RM( HL ) - (PSW & CY); + ZHC_SUB( tmp, A, (PSW & CY) ); + A = tmp; +} + +/* 70 f4: 0111 0000 1111 0100 */ +void upd7810_device::SBBX_Dp() +{ + UINT8 tmp = A - RM( DE ) - (PSW & CY); + DE++; + ZHC_SUB( tmp, A, (PSW & CY) ); + A = tmp; +} + +/* 70 f5: 0111 0000 1111 0101 */ +void upd7810_device::SBBX_Hp() +{ + UINT8 tmp = A - RM( HL ) - (PSW & CY); + HL++; + ZHC_SUB( tmp, A, (PSW & CY) ); + A = tmp; +} + +/* 70 f6: 0111 0000 1111 0110 */ +void upd7810_device::SBBX_Dm() +{ + UINT8 tmp = A - RM( DE ) - (PSW & CY); + DE--; + ZHC_SUB( tmp, A, (PSW & CY) ); + A = tmp; +} + +/* 70 f7: 0111 0000 1111 0111 */ +void upd7810_device::SBBX_Hm() +{ + UINT8 tmp = A - RM( HL ) - (PSW & CY); + HL--; + ZHC_SUB( tmp, A, (PSW & CY) ); + A = tmp; +} + +/* 70 f9: 0111 0000 1111 1001 */ +void upd7810_device::EQAX_B() +{ + UINT8 tmp = A - RM( BC ); + ZHC_SUB( tmp, A, 0 ); + SKIP_Z; +} + +/* 70 fa: 0111 0000 1111 1010 */ +void upd7810_device::EQAX_D() +{ + UINT8 tmp = A - RM( DE ); + ZHC_SUB( tmp, A, 0 ); + SKIP_Z; +} + +/* 70 fb: 0111 0000 1111 1011 */ +void upd7810_device::EQAX_H() +{ + UINT8 tmp = A - RM( HL ); + ZHC_SUB( tmp, A, 0 ); + SKIP_Z; +} + +/* 70 fc: 0111 0000 1111 1100 */ +void upd7810_device::EQAX_Dp() +{ + UINT8 tmp = A - RM( DE ); + DE++; + ZHC_SUB( tmp, A, 0 ); + SKIP_Z; +} + +/* 70 fd: 0111 0000 1111 1101 */ +void upd7810_device::EQAX_Hp() +{ + UINT8 tmp = A - RM( HL ); + HL++; + ZHC_SUB( tmp, A, 0 ); + SKIP_Z; +} + +/* 70 fe: 0111 0000 1111 1110 */ +void upd7810_device::EQAX_Dm() +{ + UINT8 tmp = A - RM( DE ); + DE--; + ZHC_SUB( tmp, A, 0 ); + SKIP_Z; +} + +/* 70 ff: 0111 0000 1111 1111 */ +void upd7810_device::EQAX_Hm() +{ + UINT8 tmp = A - RM( HL ); + HL--; + ZHC_SUB( tmp, A, 0 ); + SKIP_Z; +} + +/* prefix 74 */ +/* 74 08: 0111 0100 0000 1000 xxxx xxxx */ +void upd7810_device::ANI_V_xx() +{ + UINT8 imm; + RDOPARG( imm ); + V &= imm; + SET_Z(V); +} + +/* 74 09: 0111 0100 0000 1001 xxxx xxxx */ +void upd7810_device::ANI_A_xx() +{ + UINT8 imm; + RDOPARG( imm ); + A &= imm; + SET_Z(A); +} + +/* 74 0a: 0111 0100 0000 1010 xxxx xxxx */ +void upd7810_device::ANI_B_xx() +{ + UINT8 imm; + RDOPARG( imm ); + B &= imm; + SET_Z(B); +} + +/* 74 0b: 0111 0100 0000 1011 xxxx xxxx */ +void upd7810_device::ANI_C_xx() +{ + UINT8 imm; + RDOPARG( imm ); + C &= imm; + SET_Z(C); +} + +/* 74 0c: 0111 0100 0000 1100 xxxx xxxx */ +void upd7810_device::ANI_D_xx() +{ + UINT8 imm; + RDOPARG( imm ); + D &= imm; + SET_Z(D); +} + +/* 74 0d: 0111 0100 0000 1101 xxxx xxxx */ +void upd7810_device::ANI_E_xx() +{ + UINT8 imm; + RDOPARG( imm ); + E &= imm; + SET_Z(E); +} + +/* 74 0e: 0111 0100 0000 1110 xxxx xxxx */ +void upd7810_device::ANI_H_xx() +{ + UINT8 imm; + RDOPARG( imm ); + H &= imm; + SET_Z(H); +} + +/* 74 0f: 0111 0100 0000 1111 xxxx xxxx */ +void upd7810_device::ANI_L_xx() +{ + UINT8 imm; + RDOPARG( imm ); + L &= imm; + SET_Z(L); +} + +/* 74 10: 0111 0100 0001 0000 xxxx xxxx */ +void upd7810_device::XRI_V_xx() +{ + UINT8 imm; + RDOPARG( imm ); + V ^= imm; + SET_Z(V); +} + +/* 74 11: 0111 0100 0001 0001 xxxx xxxx */ +void upd7810_device::XRI_A_xx() +{ + UINT8 imm; + RDOPARG( imm ); + A ^= imm; + SET_Z(A); +} + +/* 74 12: 0111 0100 0001 0010 xxxx xxxx */ +void upd7810_device::XRI_B_xx() +{ + UINT8 imm; + RDOPARG( imm ); + B ^= imm; + SET_Z(B); +} + +/* 74 13: 0111 0100 0001 0011 xxxx xxxx */ +void upd7810_device::XRI_C_xx() +{ + UINT8 imm; + RDOPARG( imm ); + C ^= imm; + SET_Z(C); +} + +/* 74 14: 0111 0100 0001 0100 xxxx xxxx */ +void upd7810_device::XRI_D_xx() +{ + UINT8 imm; + RDOPARG( imm ); + D ^= imm; + SET_Z(D); +} + +/* 74 15: 0111 0100 0001 0101 xxxx xxxx */ +void upd7810_device::XRI_E_xx() +{ + UINT8 imm; + RDOPARG( imm ); + E ^= imm; + SET_Z(E); +} + +/* 74 16: 0111 0100 0001 0110 xxxx xxxx */ +void upd7810_device::XRI_H_xx() +{ + UINT8 imm; + RDOPARG( imm ); + H ^= imm; + SET_Z(H); +} + +/* 74 17: 0111 0100 0001 0111 xxxx xxxx */ +void upd7810_device::XRI_L_xx() +{ + UINT8 imm; + RDOPARG( imm ); + L ^= imm; + SET_Z(L); +} + +/* 74 18: 0111 0100 0001 1000 xxxx xxxx */ +void upd7810_device::ORI_V_xx() +{ + UINT8 imm; + RDOPARG( imm ); + V |= imm; + SET_Z(V); +} + +/* 74 19: 0111 0100 0001 1001 xxxx xxxx */ +void upd7810_device::ORI_A_xx() +{ + UINT8 imm; + RDOPARG( imm ); + A |= imm; + SET_Z(A); +} + +/* 74 1a: 0111 0100 0001 1010 xxxx xxxx */ +void upd7810_device::ORI_B_xx() +{ + UINT8 imm; + RDOPARG( imm ); + B |= imm; + SET_Z(B); +} + +/* 74 1b: 0111 0100 0001 1011 xxxx xxxx */ +void upd7810_device::ORI_C_xx() +{ + UINT8 imm; + RDOPARG( imm ); + C |= imm; + SET_Z(C); +} + +/* 74 1c: 0111 0100 0001 1100 xxxx xxxx */ +void upd7810_device::ORI_D_xx() +{ + UINT8 imm; + RDOPARG( imm ); + D |= imm; + SET_Z(D); +} + +/* 74 1d: 0111 0100 0001 1101 xxxx xxxx */ +void upd7810_device::ORI_E_xx() +{ + UINT8 imm; + RDOPARG( imm ); + E |= imm; + SET_Z(E); +} + +/* 74 1e: 0111 0100 0001 1110 xxxx xxxx */ +void upd7810_device::ORI_H_xx() +{ + UINT8 imm; + RDOPARG( imm ); + H |= imm; + SET_Z(H); +} + +/* 74 1f: 0111 0100 0001 1111 xxxx xxxx */ +void upd7810_device::ORI_L_xx() +{ + UINT8 imm; + RDOPARG( imm ); + L |= imm; + SET_Z(L); +} + +/* 74 20: 0111 0100 0010 0000 xxxx xxxx */ +void upd7810_device::ADINC_V_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = V + imm; + + ZHC_ADD( tmp, V, 0 ); + V = tmp; + SKIP_NC; +} + +/* 74 21: 0111 0100 0010 0001 xxxx xxxx */ +void upd7810_device::ADINC_A_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = A + imm; + + ZHC_ADD( tmp, A, 0 ); + A = tmp; + SKIP_NC; +} + +/* 74 22: 0111 0100 0010 0010 xxxx xxxx */ +void upd7810_device::ADINC_B_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = B + imm; + + ZHC_ADD( tmp, B, 0 ); + B = tmp; + SKIP_NC; +} + +/* 74 23: 0111 0100 0010 0011 xxxx xxxx */ +void upd7810_device::ADINC_C_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = C + imm; + + ZHC_ADD( tmp, C, 0 ); + C = tmp; + SKIP_NC; +} + +/* 74 24: 0111 0100 0010 0100 xxxx xxxx */ +void upd7810_device::ADINC_D_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = D + imm; + + ZHC_ADD( tmp, D, 0 ); + D = tmp; + SKIP_NC; +} + +/* 74 25: 0111 0100 0010 0101 xxxx xxxx */ +void upd7810_device::ADINC_E_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = E + imm; + + ZHC_ADD( tmp, E, 0 ); + E = tmp; + SKIP_NC; +} + +/* 74 26: 0111 0100 0010 0110 xxxx xxxx */ +void upd7810_device::ADINC_H_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = H + imm; + + ZHC_ADD( tmp, H, 0 ); + H = tmp; + SKIP_NC; +} + +/* 74 27: 0111 0100 0010 0111 xxxx xxxx */ +void upd7810_device::ADINC_L_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = L + imm; + + ZHC_ADD( tmp, L, 0 ); + L = tmp; + SKIP_NC; +} + +/* 74 28: 0111 0100 0010 1000 xxxx xxxx */ +void upd7810_device::GTI_V_xx() +{ + UINT8 imm; + UINT16 tmp; + + RDOPARG( imm ); + tmp = V - imm - 1; + ZHC_SUB( tmp, V, 0 ); + + SKIP_NC; +} + +/* 74 29: 0111 0100 0010 1001 xxxx xxxx */ +void upd7810_device::GTI_A_xx() +{ + UINT8 imm; + UINT16 tmp; + + RDOPARG( imm ); + tmp = A - imm - 1; + ZHC_SUB( tmp, A, 0 ); + + SKIP_NC; +} + +/* 74 2a: 0111 0100 0010 1010 xxxx xxxx */ +void upd7810_device::GTI_B_xx() +{ + UINT8 imm; + UINT16 tmp; + + RDOPARG( imm ); + tmp = B - imm - 1; + ZHC_SUB( tmp, B, 0 ); + + SKIP_NC; +} + +/* 74 2b: 0111 0100 0010 1011 xxxx xxxx */ +void upd7810_device::GTI_C_xx() +{ + UINT8 imm; + UINT16 tmp; + + RDOPARG( imm ); + tmp = C - imm - 1; + ZHC_SUB( tmp, C, 0 ); + + SKIP_NC; +} + +/* 74 2c: 0111 0100 0010 1100 xxxx xxxx */ +void upd7810_device::GTI_D_xx() +{ + UINT8 imm; + UINT16 tmp; + + RDOPARG( imm ); + tmp = D - imm - 1; + ZHC_SUB( tmp, D, 0 ); + + SKIP_NC; +} + +/* 74 2d: 0111 0100 0010 1101 xxxx xxxx */ +void upd7810_device::GTI_E_xx() +{ + UINT8 imm; + UINT16 tmp; + + RDOPARG( imm ); + tmp = E - imm - 1; + ZHC_SUB( tmp, E, 0 ); + + SKIP_NC; +} + +/* 74 2e: 0111 0100 0010 1110 xxxx xxxx */ +void upd7810_device::GTI_H_xx() +{ + UINT8 imm; + UINT16 tmp; + + RDOPARG( imm ); + tmp = H - imm - 1; + ZHC_SUB( tmp, H, 0 ); + + SKIP_NC; +} + +/* 74 2f: 0111 0100 0010 1111 xxxx xxxx */ +void upd7810_device::GTI_L_xx() +{ + UINT8 imm; + UINT16 tmp; + + RDOPARG( imm ); + tmp = L - imm - 1; + ZHC_SUB( tmp, L, 0 ); + + SKIP_NC; +} + +/* 74 30: 0111 0100 0011 0000 xxxx xxxx */ +void upd7810_device::SUINB_V_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = V - imm; + ZHC_SUB( tmp, V, 0 ); + V = tmp; + SKIP_NC; +} + +/* 74 31: 0111 0100 0011 0001 xxxx xxxx */ +void upd7810_device::SUINB_A_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = A - imm; + ZHC_SUB( tmp, A, 0 ); + A = tmp; + SKIP_NC; +} + +/* 74 32: 0111 0100 0011 0010 xxxx xxxx */ +void upd7810_device::SUINB_B_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = B - imm; + ZHC_SUB( tmp, B, 0 ); + B = tmp; + SKIP_NC; +} + +/* 74 33: 0111 0100 0011 0011 xxxx xxxx */ +void upd7810_device::SUINB_C_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = C - imm; + ZHC_SUB( tmp, C, 0 ); + C = tmp; + SKIP_NC; +} + +/* 74 34: 0111 0100 0011 0100 xxxx xxxx */ +void upd7810_device::SUINB_D_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = D - imm; + ZHC_SUB( tmp, D, 0 ); + D = tmp; + SKIP_NC; +} + +/* 74 35: 0111 0100 0011 0101 xxxx xxxx */ +void upd7810_device::SUINB_E_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = E - imm; + ZHC_SUB( tmp, E, 0 ); + E = tmp; + SKIP_NC; +} + +/* 74 36: 0111 0100 0011 0110 xxxx xxxx */ +void upd7810_device::SUINB_H_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = H - imm; + ZHC_SUB( tmp, H, 0 ); + H = tmp; + SKIP_NC; +} + +/* 74 37: 0111 0100 0011 0111 xxxx xxxx */ +void upd7810_device::SUINB_L_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = L - imm; + ZHC_SUB( tmp, L, 0 ); + L = tmp; + SKIP_NC; +} + +/* 74 38: 0111 0100 0011 1000 xxxx xxxx */ +void upd7810_device::LTI_V_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = V - imm; + ZHC_SUB( tmp, V, 0 ); + SKIP_CY; +} + +/* 74 39: 0111 0100 0011 1001 xxxx xxxx */ +void upd7810_device::LTI_A_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = A - imm; + ZHC_SUB( tmp, A, 0 ); + SKIP_CY; +} + +/* 74 3a: 0111 0100 0011 1010 xxxx xxxx */ +void upd7810_device::LTI_B_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = B - imm; + ZHC_SUB( tmp, B, 0 ); + SKIP_CY; +} + +/* 74 3b: 0111 0100 0011 1011 xxxx xxxx */ +void upd7810_device::LTI_C_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = C - imm; + ZHC_SUB( tmp, C, 0 ); + SKIP_CY; +} + +/* 74 3c: 0111 0100 0011 1100 xxxx xxxx */ +void upd7810_device::LTI_D_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = D - imm; + ZHC_SUB( tmp, D, 0 ); + SKIP_CY; +} + +/* 74 3d: 0111 0100 0011 1101 xxxx xxxx */ +void upd7810_device::LTI_E_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = E - imm; + ZHC_SUB( tmp, E, 0 ); + SKIP_CY; +} + +/* 74 3e: 0111 0100 0011 1110 xxxx xxxx */ +void upd7810_device::LTI_H_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = H - imm; + ZHC_SUB( tmp, H, 0 ); + SKIP_CY; +} + +/* 74 3f: 0111 0100 0011 1111 xxxx xxxx */ +void upd7810_device::LTI_L_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = L - imm; + ZHC_SUB( tmp, L, 0 ); + SKIP_CY; +} + +/* 74 40: 0111 0100 0100 0000 xxxx xxxx */ +void upd7810_device::ADI_V_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = V + imm; + + ZHC_ADD( tmp, V, 0 ); + V = tmp; +} + +/* 74 41: 0111 0100 0100 0001 xxxx xxxx */ +void upd7810_device::ADI_A_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = A + imm; + + ZHC_ADD( tmp, A, 0 ); + A = tmp; +} + +/* 74 42: 0111 0100 0100 0010 xxxx xxxx */ +void upd7810_device::ADI_B_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = B + imm; + + ZHC_ADD( tmp, B, 0 ); + B = tmp; +} + +/* 74 43: 0111 0100 0100 0011 xxxx xxxx */ +void upd7810_device::ADI_C_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = C + imm; + + ZHC_ADD( tmp, C, 0 ); + C = tmp; +} + +/* 74 44: 0111 0100 0100 0100 xxxx xxxx */ +void upd7810_device::ADI_D_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = D + imm; + + ZHC_ADD( tmp, D, 0 ); + D = tmp; +} + +/* 74 45: 0111 0100 0100 0101 xxxx xxxx */ +void upd7810_device::ADI_E_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = E + imm; + + ZHC_ADD( tmp, E, 0 ); + E = tmp; +} + +/* 74 46: 0111 0100 0100 0110 xxxx xxxx */ +void upd7810_device::ADI_H_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = H + imm; + + ZHC_ADD( tmp, H, 0 ); + H = tmp; +} + +/* 74 47: 0111 0100 0100 0111 xxxx xxxx */ +void upd7810_device::ADI_L_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = L + imm; + + ZHC_ADD( tmp, L, 0 ); + L = tmp; +} + +/* 74 48: 0111 0100 0100 1000 xxxx xxxx */ +void upd7810_device::ONI_V_xx() +{ + UINT8 imm; + + RDOPARG( imm ); + if (V & imm) + PSW |= SK; +} + +/* 74 49: 0111 0100 0100 1001 xxxx xxxx */ +void upd7810_device::ONI_A_xx() +{ + UINT8 imm; + + RDOPARG( imm ); + if (A & imm) + PSW |= SK; +} + +/* 74 4a: 0111 0100 0100 1010 xxxx xxxx */ +void upd7810_device::ONI_B_xx() +{ + UINT8 imm; + + RDOPARG( imm ); + if (B & imm) + PSW |= SK; +} + +/* 74 4b: 0111 0100 0100 1011 xxxx xxxx */ +void upd7810_device::ONI_C_xx() +{ + UINT8 imm; + + RDOPARG( imm ); + if (C & imm) + PSW |= SK; +} + +/* 74 4c: 0111 0100 0100 1100 xxxx xxxx */ +void upd7810_device::ONI_D_xx() +{ + UINT8 imm; + + RDOPARG( imm ); + if (D & imm) + PSW |= SK; +} + +/* 74 4d: 0111 0100 0100 1101 xxxx xxxx */ +void upd7810_device::ONI_E_xx() +{ + UINT8 imm; + + RDOPARG( imm ); + if (E & imm) + PSW |= SK; +} + +/* 74 4e: 0111 0100 0100 1110 xxxx xxxx */ +void upd7810_device::ONI_H_xx() +{ + UINT8 imm; + + RDOPARG( imm ); + if (H & imm) + PSW |= SK; +} + +/* 74 4f: 0111 0100 0100 1111 xxxx xxxx */ +void upd7810_device::ONI_L_xx() +{ + UINT8 imm; + + RDOPARG( imm ); + if (L & imm) + PSW |= SK; +} + +/* 74 50: 0111 0100 0101 0000 xxxx xxxx */ +void upd7810_device::ACI_V_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = V + imm + (PSW & CY); + ZHC_ADD( tmp, V, (PSW & CY) ); + V = tmp; +} + +/* 74 51: 0111 0100 0101 0001 xxxx xxxx */ +void upd7810_device::ACI_A_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = A + imm + (PSW & CY); + ZHC_ADD( tmp, A, (PSW & CY) ); + A = tmp; +} + +/* 74 52: 0111 0100 0101 0010 xxxx xxxx */ +void upd7810_device::ACI_B_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = B + imm + (PSW & CY); + ZHC_ADD( tmp, B, (PSW & CY) ); + B = tmp; +} + +/* 74 53: 0111 0100 0101 0011 xxxx xxxx */ +void upd7810_device::ACI_C_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = C + imm + (PSW & CY); + ZHC_ADD( tmp, C, (PSW & CY) ); + C = tmp; +} + +/* 74 54: 0111 0100 0101 0100 xxxx xxxx */ +void upd7810_device::ACI_D_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = D + imm + (PSW & CY); + ZHC_ADD( tmp, D, (PSW & CY) ); + D = tmp; +} + +/* 74 55: 0111 0100 0101 0101 xxxx xxxx */ +void upd7810_device::ACI_E_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = E + imm + (PSW & CY); + ZHC_ADD( tmp, E, (PSW & CY) ); + E = tmp; +} + +/* 74 56: 0111 0100 0101 0110 xxxx xxxx */ +void upd7810_device::ACI_H_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = H + imm + (PSW & CY); + ZHC_ADD( tmp, H, (PSW & CY) ); + H = tmp; +} + +/* 74 57: 0111 0100 0101 0111 xxxx xxxx */ +void upd7810_device::ACI_L_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = L + imm + (PSW & CY); + ZHC_ADD( tmp, L, (PSW & CY) ); + L = tmp; +} + +/* 74 58: 0111 0100 0101 1000 xxxx xxxx */ +void upd7810_device::OFFI_V_xx() +{ + UINT8 imm; + + RDOPARG( imm ); + if (0 == (V & imm)) + PSW |= SK; +} + +/* 74 59: 0111 0100 0101 1001 xxxx xxxx */ +void upd7810_device::OFFI_A_xx() +{ + UINT8 imm; + + RDOPARG( imm ); + if (0 == (A & imm)) + PSW |= SK; +} + +/* 74 5a: 0111 0100 0101 1010 xxxx xxxx */ +void upd7810_device::OFFI_B_xx() +{ + UINT8 imm; + + RDOPARG( imm ); + if (0 == (B & imm)) + PSW |= SK; +} + +/* 74 5b: 0111 0100 0101 1011 xxxx xxxx */ +void upd7810_device::OFFI_C_xx() +{ + UINT8 imm; + + RDOPARG( imm ); + if (0 == (C & imm)) + PSW |= SK; +} + +/* 74 5c: 0111 0100 0101 1100 xxxx xxxx */ +void upd7810_device::OFFI_D_xx() +{ + UINT8 imm; + + RDOPARG( imm ); + if (0 == (D & imm)) + PSW |= SK; +} + +/* 74 5d: 0111 0100 0101 1101 xxxx xxxx */ +void upd7810_device::OFFI_E_xx() +{ + UINT8 imm; + + RDOPARG( imm ); + if (0 == (E & imm)) + PSW |= SK; +} + +/* 74 5e: 0111 0100 0101 1110 xxxx xxxx */ +void upd7810_device::OFFI_H_xx() +{ + UINT8 imm; + + RDOPARG( imm ); + if (0 == (H & imm)) + PSW |= SK; +} + +/* 74 5f: 0111 0100 0101 1111 xxxx xxxx */ +void upd7810_device::OFFI_L_xx() +{ + UINT8 imm; + + RDOPARG( imm ); + if (0 == (L & imm)) + PSW |= SK; +} + +/* 74 60: 0111 0100 0110 0000 xxxx xxxx */ +void upd7810_device::SUI_V_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = V - imm; + ZHC_SUB( tmp, V, 0 ); + V = tmp; +} + +/* 74 61: 0111 0100 0110 0001 xxxx xxxx */ +void upd7810_device::SUI_A_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = A - imm; + ZHC_SUB( tmp, A, 0 ); + A = tmp; +} + +/* 74 62: 0111 0100 0110 0010 xxxx xxxx */ +void upd7810_device::SUI_B_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = B - imm; + ZHC_SUB( tmp, B, 0 ); + B = tmp; +} + +/* 74 63: 0111 0100 0110 0011 xxxx xxxx */ +void upd7810_device::SUI_C_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = C - imm; + ZHC_SUB( tmp, C, 0 ); + C = tmp; +} + +/* 74 64: 0111 0100 0110 0100 xxxx xxxx */ +void upd7810_device::SUI_D_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = D - imm; + ZHC_SUB( tmp, D, 0 ); + D = tmp; +} + +/* 74 65: 0111 0100 0110 0101 xxxx xxxx */ +void upd7810_device::SUI_E_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = E - imm; + ZHC_SUB( tmp, E, 0 ); + E = tmp; +} + +/* 74 66: 0111 0100 0110 0110 xxxx xxxx */ +void upd7810_device::SUI_H_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = H - imm; + ZHC_SUB( tmp, H, 0 ); + H = tmp; +} + +/* 74 67: 0111 0100 0110 0111 xxxx xxxx */ +void upd7810_device::SUI_L_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = L - imm; + ZHC_SUB( tmp, L, 0 ); + L = tmp; +} + +/* 74 68: 0111 0100 0110 1000 xxxx xxxx */ +void upd7810_device::NEI_V_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = V - imm; + ZHC_SUB( tmp, V, 0 ); + SKIP_NZ; +} + +/* 74 69: 0111 0100 0110 1001 xxxx xxxx */ +void upd7810_device::NEI_A_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = A - imm; + ZHC_SUB( tmp, A, 0 ); + SKIP_NZ; +} + +/* 74 6a: 0111 0100 0110 1010 xxxx xxxx */ +void upd7810_device::NEI_B_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = B - imm; + ZHC_SUB( tmp, B, 0 ); + SKIP_NZ; +} + +/* 74 6b: 0111 0100 0110 1011 xxxx xxxx */ +void upd7810_device::NEI_C_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = C - imm; + ZHC_SUB( tmp, C, 0 ); + SKIP_NZ; +} + +/* 74 6c: 0111 0100 0110 1100 xxxx xxxx */ +void upd7810_device::NEI_D_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = D - imm; + ZHC_SUB( tmp, D, 0 ); + SKIP_NZ; +} + +/* 74 6d: 0111 0100 0110 1101 xxxx xxxx */ +void upd7810_device::NEI_E_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = E - imm; + ZHC_SUB( tmp, E, 0 ); + SKIP_NZ; +} + +/* 74 6e: 0111 0100 0110 1110 xxxx xxxx */ +void upd7810_device::NEI_H_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = H - imm; + ZHC_SUB( tmp, H, 0 ); + SKIP_NZ; +} + +/* 74 6f: 0111 0100 0110 1111 xxxx xxxx */ +void upd7810_device::NEI_L_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = L - imm; + ZHC_SUB( tmp, L, 0 ); + SKIP_NZ; +} + +/* 74 70: 0111 0100 0111 0000 xxxx xxxx */ +void upd7810_device::SBI_V_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = V - imm - (PSW & CY); + ZHC_SUB( tmp, V, (PSW & CY) ); + V = tmp; +} + +/* 74 71: 0111 0100 0111 0001 xxxx xxxx */ +void upd7810_device::SBI_A_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = A - imm - (PSW & CY); + ZHC_SUB( tmp, A, (PSW & CY) ); + A = tmp; +} + +/* 74 72: 0111 0100 0111 0010 xxxx xxxx */ +void upd7810_device::SBI_B_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = B - imm - (PSW & CY); + ZHC_SUB( tmp, B, (PSW & CY) ); + B = tmp; +} + +/* 74 73: 0111 0100 0111 0011 xxxx xxxx */ +void upd7810_device::SBI_C_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = C - imm - (PSW & CY); + ZHC_SUB( tmp, C, (PSW & CY) ); + C = tmp; +} + +/* 74 74: 0111 0100 0111 0100 xxxx xxxx */ +void upd7810_device::SBI_D_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = D - imm - (PSW & CY); + ZHC_SUB( tmp, D, (PSW & CY) ); + D = tmp; +} + +/* 74 75: 0111 0100 0111 0101 xxxx xxxx */ +void upd7810_device::SBI_E_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = E - imm - (PSW & CY); + ZHC_SUB( tmp, E, (PSW & CY) ); + E = tmp; +} + +/* 74 76: 0111 0100 0111 0110 xxxx xxxx */ +void upd7810_device::SBI_H_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = H - imm - (PSW & CY); + ZHC_SUB( tmp, H, (PSW & CY) ); + H = tmp; +} + +/* 74 77: 0111 0100 0111 0111 xxxx xxxx */ +void upd7810_device::SBI_L_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = L - imm - (PSW & CY); + ZHC_SUB( tmp, L, (PSW & CY) ); + L = tmp; +} + +/* 74 78: 0111 0100 0111 1000 xxxx xxxx */ +void upd7810_device::EQI_V_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = V - imm; + ZHC_SUB( tmp, V, 0 ); + SKIP_Z; +} + +/* 74 79: 0111 0100 0111 1001 xxxx xxxx */ +void upd7810_device::EQI_A_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = A - imm; + ZHC_SUB( tmp, A, 0 ); + SKIP_Z; +} + +/* 74 7a: 0111 0100 0111 1010 xxxx xxxx */ +void upd7810_device::EQI_B_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = B - imm; + ZHC_SUB( tmp, B, 0 ); + SKIP_Z; +} + +/* 74 7b: 0111 0100 0111 1011 xxxx xxxx */ +void upd7810_device::EQI_C_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = C - imm; + ZHC_SUB( tmp, C, 0 ); + SKIP_Z; +} + +/* 74 7c: 0111 0100 0111 1100 xxxx xxxx */ +void upd7810_device::EQI_D_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = D - imm; + ZHC_SUB( tmp, D, 0 ); + SKIP_Z; +} + +/* 74 7d: 0111 0100 0111 1101 xxxx xxxx */ +void upd7810_device::EQI_E_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = E - imm; + ZHC_SUB( tmp, E, 0 ); + SKIP_Z; +} + +/* 74 7e: 0111 0100 0111 1110 xxxx xxxx */ +void upd7810_device::EQI_H_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = H - imm; + ZHC_SUB( tmp, H, 0 ); + SKIP_Z; +} + +/* 74 7f: 0111 0100 0111 1111 xxxx xxxx */ +void upd7810_device::EQI_L_xx() +{ + UINT8 tmp, imm; + + RDOPARG( imm ); + tmp = L - imm; + ZHC_SUB( tmp, L, 0 ); + SKIP_Z; +} + +/* 74 88: 0111 0100 1000 1000 oooo oooo */ +void upd7810_device::ANAW_wa() +{ + PAIR ea = m_va; + RDOPARG( ea.b.l ); + + A &= RM( ea.d ); + SET_Z(A); +} + +/* 74 8d: 0111 0100 1000 1101 */ +void upd7810_device::DAN_EA_BC() +{ + EA &= BC; + SET_Z(EA); +} + +/* 74 8e: 0111 0100 1000 1110 */ +void upd7810_device::DAN_EA_DE() +{ + EA &= DE; + SET_Z(EA); +} + +/* 74 8f: 0111 0100 1000 1111 */ +void upd7810_device::DAN_EA_HL() +{ + EA &= HL; + SET_Z(EA); +} + +/* 74 90: 0111 0100 1001 0000 oooo oooo */ +void upd7810_device::XRAW_wa() +{ + PAIR ea = m_va; + RDOPARG( ea.b.l ); + + A ^= RM( ea.d ); + SET_Z(A); +} + +/* 74 95: 0111 0100 1001 0101 */ +void upd7810_device::DXR_EA_BC() +{ + EA ^= BC; + SET_Z(EA); +} + +/* 74 96: 0111 0100 1001 0110 */ +void upd7810_device::DXR_EA_DE() +{ + EA ^= DE; + SET_Z(EA); +} + +/* 74 97: 0111 0100 1001 0111 */ +void upd7810_device::DXR_EA_HL() +{ + EA ^= HL; + SET_Z(EA); +} + +/* 74 98: 0111 0100 1001 1000 oooo oooo */ +void upd7810_device::ORAW_wa() +{ + PAIR ea = m_va; + RDOPARG( ea.b.l ); + + A |= RM( ea.d ); + SET_Z(A); +} + +/* 74 9d: 0111 0100 1001 1101 */ +void upd7810_device::DOR_EA_BC() +{ + EA |= BC; + SET_Z(EA); +} + +/* 74 9e: 0111 0100 1001 1110 */ +void upd7810_device::DOR_EA_DE() +{ + EA |= DE; + SET_Z(EA); +} + +/* 74 9f: 0111 0100 1001 1111 */ +void upd7810_device::DOR_EA_HL() +{ + EA |= HL; + SET_Z(EA); +} + +/* 74 a0: 0111 0100 1010 0000 oooo oooo */ +void upd7810_device::ADDNCW_wa() +{ + PAIR ea = m_va; + UINT8 tmp; + + RDOPARG( ea.b.l ); + + tmp = A + RM( ea.d ); + ZHC_ADD( tmp, A, 0 ); + A = tmp; + SKIP_NC; +} + +/* 74 a5: 0111 0100 1010 0101 */ +void upd7810_device::DADDNC_EA_BC() +{ + UINT16 tmp = EA + BC; + + ZHC_ADD( tmp, EA, 0 ); + EA = tmp; + SKIP_NC; +} + +/* 74 a6: 0111 0100 1010 0110 */ +void upd7810_device::DADDNC_EA_DE() +{ + UINT16 tmp = EA + DE; + + ZHC_ADD( tmp, EA, 0 ); + EA = tmp; + SKIP_NC; +} + +/* 74 a7: 0111 0100 1010 0111 */ +void upd7810_device::DADDNC_EA_HL() +{ + UINT16 tmp = EA + HL; + + ZHC_ADD( tmp, EA, 0 ); + EA = tmp; + SKIP_NC; +} + +/* 74 a8: 0111 0100 1010 1000 oooo oooo */ +void upd7810_device::GTAW_wa() +{ + PAIR ea = m_va; + UINT16 tmp; + + RDOPARG( ea.b.l ); + tmp = A - RM( ea.d ) - 1; + ZHC_SUB( tmp, A, 0 ); + SKIP_NC; +} + +/* 74 ad: 0111 0100 1010 1101 */ +void upd7810_device::DGT_EA_BC() +{ + UINT32 tmp = EA - BC - 1; + ZHC_SUB( tmp, EA, 0 ); + SKIP_NC; +} + +/* 74 ae: 0111 0100 1010 1110 */ +void upd7810_device::DGT_EA_DE() +{ + UINT32 tmp = EA - DE - 1; + ZHC_SUB( tmp, EA, 0 ); + SKIP_NC; +} + +/* 74 af: 0111 0100 1010 1111 */ +void upd7810_device::DGT_EA_HL() +{ + UINT32 tmp = EA - HL - 1; + ZHC_SUB( tmp, EA, 0 ); + SKIP_NC; +} + +/* 74 b0: 0111 0100 1011 0000 oooo oooo */ +void upd7810_device::SUBNBW_wa() +{ + PAIR ea = m_va; + UINT8 tmp; + + RDOPARG( ea.b.l ); + tmp = A - RM( ea.d ); + ZHC_SUB( tmp, A, 0 ); + A = tmp; + SKIP_NC; +} + +/* 74 b5: 0111 0100 1011 0101 */ +void upd7810_device::DSUBNB_EA_BC() +{ + UINT16 tmp = EA - BC; + ZHC_SUB( tmp, EA, 0 ); + EA = tmp; + SKIP_NC; +} + +/* 74 b6: 0111 0100 1011 0110 */ +void upd7810_device::DSUBNB_EA_DE() +{ + UINT16 tmp = EA - DE; + ZHC_SUB( tmp, EA, 0 ); + EA = tmp; + SKIP_NC; +} + +/* 74 b7: 0111 0100 1011 0111 */ +void upd7810_device::DSUBNB_EA_HL() +{ + UINT16 tmp; + + tmp = EA - HL; + ZHC_SUB( tmp, EA, 0 ); + EA = tmp; + SKIP_NC; +} + +/* 74 b8: 0111 0100 1011 1000 oooo oooo */ +void upd7810_device::LTAW_wa() +{ + PAIR ea = m_va; + UINT8 tmp; + + RDOPARG( ea.b.l ); + tmp = A - RM( ea.d ); + ZHC_SUB( tmp, A, 0 ); + SKIP_CY; +} + +/* 74 bd: 0111 0100 1011 1101 */ +void upd7810_device::DLT_EA_BC() +{ + UINT16 tmp = EA - BC; + ZHC_SUB( tmp, EA, 0 ); + SKIP_CY; +} + +/* 74 be: 0111 0100 1011 1110 */ +void upd7810_device::DLT_EA_DE() +{ + UINT16 tmp = EA - DE; + ZHC_SUB( tmp, EA, 0 ); + SKIP_CY; +} + +/* 74 bf: 0111 0100 1011 1111 */ +void upd7810_device::DLT_EA_HL() +{ + UINT16 tmp = EA - HL; + ZHC_SUB( tmp, EA, 0 ); + SKIP_CY; +} + +/* 74 c0: 0111 0100 1100 0000 oooo oooo */ +void upd7810_device::ADDW_wa() +{ + PAIR ea = m_va; + UINT8 tmp; + RDOPARG( ea.b.l ); + tmp = A + RM( ea.d ); + ZHC_ADD( tmp, A, 0 ); + A = tmp; +} + +/* 74 c5: 0111 0100 1100 0101 */ +void upd7810_device::DADD_EA_BC() +{ + UINT16 tmp = EA + BC; + ZHC_ADD( tmp, EA, 0 ); + EA = tmp; +} + +/* 74 c6: 0111 0100 1100 0110 */ +void upd7810_device::DADD_EA_DE() +{ + UINT16 tmp = EA + DE; + ZHC_ADD( tmp, EA, 0 ); + EA = tmp; +} + +/* 74 c7: 0111 0100 1100 0111 */ +void upd7810_device::DADD_EA_HL() +{ + UINT16 tmp = EA + HL; + ZHC_ADD( tmp, EA, 0 ); + EA = tmp; +} + +/* 74 c8: 0111 0100 1100 1000 oooo oooo */ +void upd7810_device::ONAW_wa() +{ + PAIR ea = m_va; + RDOPARG( ea.b.l ); + + if (A & RM( ea.d )) + PSW = (PSW & ~Z) | SK; + else + PSW |= Z; +} + +/* 74 cd: 0111 0100 1100 1101 */ +void upd7810_device::DON_EA_BC() +{ + if (EA & BC) + PSW = (PSW & ~Z) | SK; + else + PSW |= Z; +} + +/* 74 ce: 0111 0100 1100 1110 */ +void upd7810_device::DON_EA_DE() +{ + if (EA & DE) + PSW = (PSW & ~Z) | SK; + else + PSW |= Z; +} + +/* 74 cf: 0111 0100 1100 1111 */ +void upd7810_device::DON_EA_HL() +{ + if (EA & HL) + PSW = (PSW & ~Z) | SK; + else + PSW |= Z; +} + +/* 74 d0: 0111 0100 1101 0000 oooo oooo */ +void upd7810_device::ADCW_wa() +{ + PAIR ea = m_va; + UINT8 tmp; + + RDOPARG( ea.b.l ); + tmp = A + RM( ea.d ) + (PSW & CY); + ZHC_ADD( tmp, A, (PSW & CY) ); + A = tmp; +} + +/* 74 d5: 0111 0100 1101 0101 */ +void upd7810_device::DADC_EA_BC() +{ + UINT16 tmp = EA + BC + (PSW & CY); + ZHC_ADD( tmp, EA, (PSW & CY) ); + EA = tmp; +} + +/* 74 d6: 0111 0100 1101 0110 */ +void upd7810_device::DADC_EA_DE() +{ + UINT16 tmp = EA + DE + (PSW & CY); + ZHC_ADD( tmp, EA, (PSW & CY) ); + EA = tmp; +} + +/* 74 d7: 0111 0100 1101 0111 */ +void upd7810_device::DADC_EA_HL() +{ + UINT16 tmp = EA + HL + (PSW & CY); + ZHC_ADD( tmp, EA, (PSW & CY) ); + EA = tmp; +} + +/* 74 d8: 0111 0100 1101 1000 oooo oooo */ +void upd7810_device::OFFAW_wa() +{ + PAIR ea = m_va; + RDOPARG( ea.b.l ); + + if ( A & RM( ea.d ) ) + PSW &= ~Z; + else + PSW = PSW | Z | SK; +} + +/* 74 dd: 0111 0100 1101 1101 */ +void upd7810_device::DOFF_EA_BC() +{ + if ( EA & BC ) + PSW &= ~Z; + else + PSW = PSW | Z | SK; +} + +/* 74 de: 0111 0100 1101 1110 */ +void upd7810_device::DOFF_EA_DE() +{ + if ( EA & DE ) + PSW &= ~Z; + else + PSW = PSW | Z | SK; +} + +/* 74 df: 0111 0100 1101 1111 */ +void upd7810_device::DOFF_EA_HL() +{ + if ( EA & HL ) + PSW &= ~Z; + else + PSW = PSW | Z | SK; +} + +/* 74 e0: 0111 0100 1110 0000 oooo oooo */ +void upd7810_device::SUBW_wa() +{ + PAIR ea = m_va; + UINT8 tmp; + + RDOPARG( ea.b.l ); + tmp = A - RM( ea.d ); + ZHC_SUB( tmp, A, 0 ); + A = tmp; +} + +/* 74 e5: 0111 0100 1110 0101 */ +void upd7810_device::DSUB_EA_BC() +{ + UINT16 tmp = EA - BC; + ZHC_SUB( tmp, EA, 0 ); + EA = tmp; +} + +/* 74 e6: 0111 0100 1110 0110 */ +void upd7810_device::DSUB_EA_DE() +{ + UINT16 tmp = EA - DE; + ZHC_SUB( tmp, EA, 0 ); + EA = tmp; +} + +/* 74 e7: 0111 0100 1110 0111 */ +void upd7810_device::DSUB_EA_HL() +{ + UINT16 tmp = EA - HL; + ZHC_SUB( tmp, EA, 0 ); + EA = tmp; +} + +/* 74 e8: 0111 0100 1110 1000 oooo oooo */ +void upd7810_device::NEAW_wa() +{ + PAIR ea = m_va; + UINT8 tmp; + + RDOPARG( ea.b.l ); + tmp = A - RM( ea.d ); + ZHC_SUB( tmp, A, 0 ); + SKIP_NZ; +} + +/* 74 ed: 0111 0100 1110 1101 */ +void upd7810_device::DNE_EA_BC() +{ + UINT16 tmp; + + tmp = EA - BC; + ZHC_SUB( tmp, EA, 0 ); + SKIP_NZ; +} + +/* 74 ee: 0111 0100 1110 1110 */ +void upd7810_device::DNE_EA_DE() +{ + UINT16 tmp; + + tmp = EA - DE; + ZHC_SUB( tmp, EA, 0 ); + SKIP_NZ; +} + +/* 74 ef: 0111 0100 1110 1111 */ +void upd7810_device::DNE_EA_HL() +{ + UINT16 tmp; + + tmp = EA - HL; + ZHC_SUB( tmp, EA, 0 ); + SKIP_NZ; +} + +/* 74 f0: 0111 0100 1111 0000 oooo oooo */ +void upd7810_device::SBBW_wa() +{ + PAIR ea = m_va; + UINT8 tmp; + + RDOPARG( ea.b.l ); + tmp = A - RM( ea.d ) - (PSW & CY); + ZHC_SUB( tmp, A, (PSW & CY) ); + A = tmp; +} + +/* 74 f5: 0111 0100 1111 0101 */ +void upd7810_device::DSBB_EA_BC() +{ + UINT16 tmp = EA - BC - (PSW & CY); + ZHC_SUB( tmp, EA, (PSW & CY) ); + EA = tmp; +} + +/* 74 f6: 0111 0100 1111 0110 */ +void upd7810_device::DSBB_EA_DE() +{ + UINT16 tmp = EA - DE - (PSW & CY); + ZHC_SUB( tmp, EA, (PSW & CY) ); + EA = tmp; +} + +/* 74 f7: 0111 0100 1111 0111 */ +void upd7810_device::DSBB_EA_HL() +{ + UINT16 tmp = EA - HL - (PSW & CY); + ZHC_SUB( tmp, EA, (PSW & CY) ); + EA = tmp; +} + +/* 74 f8: 0111 0100 1111 1000 oooo oooo */ +void upd7810_device::EQAW_wa() +{ + PAIR ea = m_va; + UINT8 tmp; + + RDOPARG( ea.b.l ); + tmp = A - RM( ea.d ); + ZHC_SUB( tmp, A, 0 ); + SKIP_Z; +} + +/* 74 fd: 0111 0100 1111 1101 */ +void upd7810_device::DEQ_EA_BC() +{ + UINT16 tmp; + + tmp = EA - BC; + ZHC_SUB( tmp, EA, 0 ); + SKIP_Z; +} + +/* 74 fe: 0111 0100 1111 1110 */ +void upd7810_device::DEQ_EA_DE() +{ + UINT16 tmp; + + tmp = EA - DE; + ZHC_SUB( tmp, EA, 0 ); + SKIP_Z; +} + +/* 74 ff: 0111 0100 1111 1111 */ +void upd7810_device::DEQ_EA_HL() +{ + UINT16 tmp; + + tmp = EA - HL; + ZHC_SUB( tmp, EA, 0 ); + SKIP_Z; +} + +/************************************************ + * main opcodes + ************************************************/ + +/* 00: 0000 0000 */ +void upd7810_device::NOP() +{ +} + +/* 01: 0000 0001 oooo oooo */ +void upd7810_device::LDAW_wa() +{ + PAIR ea = m_va; + + RDOPARG( ea.b.l ); + + A = RM( ea.d ); +} + +/* 02: 0000 0010 */ +void upd7810_device::INX_SP() +{ + SP++; +} + +/* 03: 0000 0011 */ +void upd7810_device::DCX_SP() +{ + SP--; +} + +/* 04: 0000 0100 llll llll hhhh hhhh */ +void upd7810_device::LXI_S_w() +{ + RDOPARG( SPL ); + RDOPARG( SPH ); +} + +/* 05: 0000 0101 oooo oooo xxxx xxxx */ +void upd7810_device::ANIW_wa_xx() +{ + PAIR ea = m_va; + UINT8 m, imm; + + RDOPARG( ea.b.l ); + RDOPARG( imm ); + m = RM( ea.d ); + m &= imm; + WM( ea.d, m ); + SET_Z(m); +} + +/* 07: 0000 0111 xxxx xxxx */ +/* ANI_A_xx already defined (long form) */ + +/* 08: 0000 1000 */ +void upd7810_device::MOV_A_EAH() +{ + A = EAH; +} + +/* 09: 0000 1001 */ +void upd7810_device::MOV_A_EAL() +{ + A = EAL; +} + +/* 0a: 0000 1010 */ +void upd7810_device::MOV_A_B() +{ + A = B; +} + +/* 0b: 0000 1011 */ +void upd7810_device::MOV_A_C() +{ + A = C; +} + +/* 0c: 0000 1100 */ +void upd7810_device::MOV_A_D() +{ + A = D; +} + +/* 0d: 0000 1101 */ +void upd7810_device::MOV_A_E() +{ + A = E; +} + +/* 0e: 0000 1110 */ +void upd7810_device::MOV_A_H() +{ + A = H; +} + +/* 0f: 0000 1111 */ +void upd7810_device::MOV_A_L() +{ + A = L; +} + +/* 10: 0001 0000 */ +void upd7810_device::EXA() +{ + UINT16 tmp; + tmp = EA; EA = EA2; EA2 = tmp; + tmp = VA; VA = VA2; VA2 = tmp; +} + +/* 11: 0001 0001 */ +void upd7810_device::EXX() +{ + UINT16 tmp; + tmp = BC; BC = BC2; BC2 = tmp; + tmp = DE; DE = DE2; DE2 = tmp; + tmp = HL; HL = HL2; HL2 = tmp; +} + +/* 48 AD (7807 only) */ +void upd7810_device::EXR() +{ + UINT16 tmp; + tmp = BC; BC = BC2; BC2 = tmp; + tmp = DE; DE = DE2; DE2 = tmp; + tmp = HL; HL = HL2; HL2 = tmp; + tmp = EA; EA = EA2; EA2 = tmp; + tmp = VA; VA = VA2; VA2 = tmp; +} + +/* 12: 0001 0010 */ +void upd7810_device::INX_BC() +{ + BC++; +} + +/* 13: 0001 0011 */ +void upd7810_device::DCX_BC() +{ + BC--; +} + +/* 14: 0001 0100 llll llll hhhh hhhh */ +void upd7810_device::LXI_B_w() +{ + RDOPARG( C ); + RDOPARG( B ); +} + +/* 15: 0001 0101 oooo oooo xxxx xxxx */ +void upd7810_device::ORIW_wa_xx() +{ + PAIR ea = m_va; + UINT8 m, imm; + + RDOPARG( ea.b.l ); + RDOPARG( imm ); + m = RM( ea.d ); + m |= imm; + WM( ea.d, m ); + SET_Z(m); +} + +/* 16: 0001 0110 xxxx xxxx */ +/* XRI_A_xx already defined (long form) */ + +/* 17: 0001 0111 xxxx xxxx */ +/* ORI_A_xx already defined (long form) */ + +/* 18: 0001 1000 */ +void upd7810_device::MOV_EAH_A() +{ + EAH = A; +} + +/* 19: 0001 1001 */ +void upd7810_device::MOV_EAL_A() +{ + EAL = A; +} + +/* 1a: 0001 1010 */ +void upd7810_device::MOV_B_A() +{ + B = A; +} + +/* 1b: 0001 1011 */ +void upd7810_device::MOV_C_A() +{ + C = A; +} + +/* 1c: 0001 1100 */ +void upd7810_device::MOV_D_A() +{ + D = A; +} + +/* 1d: 0001 1101 */ +void upd7810_device::MOV_E_A() +{ + E = A; +} + +/* 1e: 0001 1110 */ +void upd7810_device::MOV_H_A() +{ + H = A; +} + +/* 1f: 0001 1111 */ +void upd7810_device::MOV_L_A() +{ + L = A; +} + +/* 20: 0010 0000 oooo oooo */ +void upd7810_device::INRW_wa() +{ + PAIR ea = m_va; + UINT8 tmp, m; + + RDOPARG( ea.b.l ); + m = RM( ea.d ); + tmp = m + 1; + ZHC_ADD( tmp, m, 0 ); + WM( ea.d, tmp ); + SKIP_CY; +} + +/* 21: 0010 0001 */ +void upd7810_device::JB() +{ + PC = BC; +} + +/* 22: 0010 0010 */ +void upd7810_device::INX_DE() +{ + DE++; +} + +/* 23: 0010 0011 */ +void upd7810_device::DCX_DE() +{ + DE--; +} + +/* 24: 0010 0100 llll llll hhhh hhhh */ +void upd7810_device::LXI_D_w() +{ + RDOPARG( E ); + RDOPARG( D ); +} + +/* 25: 0010 0101 oooo oooo xxxx xxxx */ +void upd7810_device::GTIW_wa_xx() +{ + PAIR ea = m_va; + UINT8 m, imm; + UINT16 tmp; + + RDOPARG( ea.b.l ); + RDOPARG( imm ); + m = RM( ea.d ); + tmp = m - imm - 1; + ZHC_SUB( tmp, m, 0 ); + SKIP_NC; +} + +/* 26: 0010 0110 xxxx xxxx */ +/* ADINC_A_xx already defined (long form) */ + +/* 27: 0010 0111 xxxx xxxx */ +/* GTI_A_xx already defined (long form) */ + +/* 29: 0010 1001 */ +void upd7810_device::LDAX_B() +{ + A = RM( BC ); +} + +/* 2a: 0010 1010 */ +void upd7810_device::LDAX_D() +{ + A = RM( DE ); +} + +/* 2b: 0010 1011 */ +void upd7810_device::LDAX_H() +{ + A = RM( HL ); +} + +/* 2c: 0010 1100 */ +void upd7810_device::LDAX_Dp() +{ + A = RM( DE ); + DE++; +} + +/* 2d: 0010 1101 dddd dddd */ +void upd7810_device::LDAX_Hp() +{ + A = RM( HL ); + HL++; +} + +/* 2e: 0010 1110 dddd dddd */ +void upd7810_device::LDAX_Dm() +{ + A = RM( DE ); + DE--; +} + +/* 2f: 0010 1111 dddd dddd */ +void upd7810_device::LDAX_Hm() +{ + A = RM( HL ); + HL--; +} + +/* 30: 0011 0000 oooo oooo */ +void upd7810_device::DCRW_wa() +{ + PAIR ea = m_va; + UINT8 tmp, m; + + RDOPARG( ea.b.l ); + m = RM( ea.d ); + tmp = m - 1; + ZHC_SUB( tmp, m, 0 ); + WM( ea.d, tmp ); + SKIP_CY; +} + +/* 31: 0011 0001 */ +void upd7810_device::BLOCK() +{ + WM( DE, RM( HL ) ); + DE++; + HL++; + C--; + if (C == 0xff) + PSW |= CY; + else + { + PSW &= ~CY; + PC--; + } +} + +/* 32: 0011 0010 */ +void upd7810_device::INX_HL() +{ + HL++; +} + +/* 33: 0011 0011 */ +void upd7810_device::DCX_HL() +{ + HL--; +} + +/* 34: 0011 0100 llll llll hhhh hhhh */ +void upd7810_device::LXI_H_w() +{ + if (PSW & L0) { /* overlay active? */ + PC+=2; + return; + } + RDOPARG( L ); + RDOPARG( H ); + PSW |= L0; +} + +/* 35: 0011 0101 oooo oooo xxxx xxxx */ +void upd7810_device::LTIW_wa_xx() +{ + PAIR ea = m_va; + UINT8 tmp, m, imm; + + RDOPARG( ea.b.l ); + RDOPARG( imm ); + m = RM( ea.d ); + tmp = m - imm; + ZHC_SUB( tmp, m, 0 ); + SKIP_CY; +} + +/* 36: 0011 0110 xxxx xxxx */ +/* SUINB_A_xx already defined (long form) */ + +/* 37: 0011 0111 xxxx xxxx */ +/* LTI_A_xx already defined (long form) */ + +/* 39: 0011 1001 */ +void upd7810_device::STAX_B() +{ + WM( BC, A ); +} + +/* 3a: 0011 1010 */ +void upd7810_device::STAX_D() +{ + WM( DE, A ); +} + +/* 3b: 0011 1011 */ +void upd7810_device::STAX_H() +{ + WM( HL, A ); +} + +/* 3c: 0011 1100 */ +void upd7810_device::STAX_Dp() +{ + WM( DE, A ); + DE++; +} + +/* 3d: 0011 1101 */ +void upd7810_device::STAX_Hp() +{ + WM( HL, A ); + HL++; +} + +/* 3e: 0011 1110 */ +void upd7810_device::STAX_Dm() +{ + WM( DE, A ); + DE--; +} + +/* 3f: 0011 1111 */ +void upd7810_device::STAX_Hm() +{ + WM( HL, A ); + HL--; +} + +/* 40: 0100 0000 llll llll hhhh hhhh */ +void upd7810_device::CALL_w() +{ + PAIR w; + w.d = 0; + + RDOPARG( w.b.l ); + RDOPARG( w.b.h ); + + SP--; + WM( SPD, PCH ); + SP--; + WM( SPD, PCL ); + + PC = w.w.l; +} + +/* 41: 0100 0001 */ +void upd7810_device::INR_A() +{ + UINT8 tmp = A + 1; + ZHC_ADD( tmp, A, 0 ); + A = tmp; + SKIP_CY; +} + +/* 42: 0100 0010 */ +void upd7810_device::INR_B() +{ + UINT8 tmp = B + 1; + ZHC_ADD( tmp, B, 0 ); + B = tmp; + SKIP_CY; +} + +/* 43: 0100 0011 */ +void upd7810_device::INR_C() +{ + UINT8 tmp = C + 1; + ZHC_ADD( tmp, C, 0 ); + C = tmp; + SKIP_CY; +} + +/* 44: 0100 0100 llll llll hhhh hhhh */ +void upd7810_device::LXI_EA_s() +{ + RDOPARG( EAL ); + RDOPARG( EAH ); +} + +/* 45: 0100 0101 oooo oooo xxxx xxxx */ +void upd7810_device::ONIW_wa_xx() +{ + PAIR ea = m_va; + UINT8 imm; + + RDOPARG( ea.b.l ); + RDOPARG( imm ); + + if (RM( ea.d ) & imm) + PSW |= SK; +} + +/* 46: 0100 0110 xxxx xxxx */ +/* ADI_A_xx already defined (long form) */ + +/* 47: 0100 0111 xxxx xxxx */ +/* ONI_A_xx already defined (long form) */ + +/* 48: prefix */ +void upd7810_device::PRE_48() +{ + RDOP(OP2); + m_icount -= m_op48[OP2].cycles; + handle_timers(m_op48[OP2].cycles); + (this->*m_op48[OP2].opfunc)(); +} + +/* 49: 0100 1001 xxxx xxxx */ +void upd7810_device::MVIX_BC_xx() +{ + UINT8 imm; + RDOPARG( imm ); + WM( BC, imm ); +} + +/* 4a: 0100 1010 xxxx xxxx */ +void upd7810_device::MVIX_DE_xx() +{ + UINT8 imm; + RDOPARG( imm ); + WM( DE, imm ); +} + +/* 4b: 0100 1011 xxxx xxxx */ +void upd7810_device::MVIX_HL_xx() +{ + UINT8 imm; + RDOPARG( imm ); + WM( HL, imm ); +} + +/* 4c: prefix */ +void upd7810_device::PRE_4C() +{ + RDOP(OP2); + m_icount -= m_op4C[OP2].cycles; + handle_timers(m_op4C[OP2].cycles); + (this->*m_op4C[OP2].opfunc)(); +} + +/* 4d: prefix */ +void upd7810_device::PRE_4D() +{ + RDOP(OP2); + m_icount -= m_op4D[OP2].cycles; + handle_timers(m_op4D[OP2].cycles); + (this->*m_op4D[OP2].opfunc)(); +} + +/* 4e: 0100 111d dddd dddd */ +void upd7810_device::JRE() +{ + UINT8 offs; + RDOPARG( offs ); + if (OP & 0x01) + PC -= 256 - offs; + else + PC += offs; +} + +/* 50: 0101 0000 */ +void upd7810_device::EXH() +{ + UINT16 tmp; + tmp = HL; HL = HL2; HL2 = tmp; +} + +/* 51: 0101 0001 */ +void upd7810_device::DCR_A() +{ + UINT8 tmp = A - 1; + ZHC_SUB( tmp, A, 0 ); + A = tmp; + SKIP_CY; +} + +/* 52: 0101 0010 */ +void upd7810_device::DCR_B() +{ + UINT8 tmp = B - 1; + ZHC_SUB( tmp, B, 0 ); + B = tmp; + SKIP_CY; +} + +/* 53: 0101 0011 */ +void upd7810_device::DCR_C() +{ + UINT8 tmp = C - 1; + ZHC_SUB( tmp, C, 0 ); + C = tmp; + SKIP_CY; +} + +/* 54: 0101 0100 llll llll hhhh hhhh */ +void upd7810_device::JMP_w() +{ + PAIR w; + w.d = 0; + + RDOPARG( w.b.l ); + RDOPARG( w.b.h ); + + PCD = w.d; +} + +/* 55: 0101 0101 oooo oooo xxxx xxxx */ +void upd7810_device::OFFIW_wa_xx() +{ + PAIR ea = m_va; + UINT8 imm; + + RDOPARG( ea.b.l ); + RDOPARG( imm ); + + if (0 == (RM( ea.d ) & imm)) + PSW |= SK; +} + +/* 56: 0101 0110 xxxx xxxx */ +/* ACI_A_xx already defined (long form) */ + +/* 57: 0101 0111 xxxx xxxx */ +/* OFFI_A_xx already defined (long form) */ + +/* 58: 0101 1000 oooo oooo (7810 only) */ +void upd7810_device::BIT_0_wa() +{ + PAIR ea = m_va; + + RDOPARG( ea.b.l ); + + if (RM( ea.d ) & 0x01) + PSW |= SK; +} + +/* 59: 0101 1001 oooo oooo (7810 only) */ +void upd7810_device::BIT_1_wa() +{ + PAIR ea = m_va; + + RDOPARG( ea.b.l ); + + if (RM( ea.d ) & 0x02) + PSW |= SK; +} + +/* 5a: 0101 1010 oooo oooo (7810 only) */ +void upd7810_device::BIT_2_wa() +{ + PAIR ea = m_va; + + RDOPARG( ea.b.l ); + + if (RM( ea.d ) & 0x04) + PSW |= SK; +} + +/* 5b: 0101 1011 oooo oooo (7810 only) */ +void upd7810_device::BIT_3_wa() +{ + PAIR ea = m_va; + + RDOPARG( ea.b.l ); + + if (RM( ea.d ) & 0x08) + PSW |= SK; +} + +/* 5c: 0101 1100 oooo oooo (7810 only) */ +void upd7810_device::BIT_4_wa() +{ + PAIR ea = m_va; + + RDOPARG( ea.b.l ); + + if (RM( ea.d ) & 0x10) + PSW |= SK; +} + +/* 5d: 0101 1101 oooo oooo (7810 only) */ +void upd7810_device::BIT_5_wa() +{ + PAIR ea = m_va; + + RDOPARG( ea.b.l ); + + if (RM( ea.d ) & 0x20) + PSW |= SK; +} + +/* 5e: 0101 1110 oooo oooo (7810 only) */ +void upd7810_device::BIT_6_wa() +{ + PAIR ea = m_va; + + RDOPARG( ea.b.l ); + + if (RM( ea.d ) & 0x40) + PSW |= SK; +} + +/* 5f: 0101 1111 oooo oooo (7810 only) */ +void upd7810_device::BIT_7_wa() +{ + PAIR ea = m_va; + + RDOPARG( ea.b.l ); + + if (RM( ea.d ) & 0x80) + PSW |= SK; +} + +/* 5d: 0101 1111 bbbb bbbb (7807 only) */ +void upd7810_device::SKN_bit() +{ + UINT8 imm; + int val; + + RDOPARG( imm ); + + switch( imm & 0x1f ) + { + case 0x10: /* PA */ + val = RP( UPD7810_PORTA ); + break; + case 0x11: /* PB */ + val = RP( UPD7810_PORTB ); + break; + case 0x12: /* PC */ + val = RP( UPD7810_PORTC ); + break; + case 0x13: /* PD */ + val = RP( UPD7810_PORTD ); + break; + case 0x15: /* PF */ + val = RP( UPD7810_PORTF ); + break; + case 0x16: /* MKH */ + val = MKH; + break; + case 0x17: /* MKL */ + val = MKL; + break; + case 0x19: /* SMH */ + val = SMH; + break; + case 0x1b: /* EOM */ + val = EOM; + break; + case 0x1d: /* TMM */ + val = TMM; + break; + case 0x1e: /* PT */ + val = RP( UPD7807_PORTT ); + break; + default: + logerror("uPD7810 '%s': illegal opcode %02x %02x at PC:%04x\n", tag(), OP, imm, PC); + val = 0; + break; + } + + if (~val & (1 << (imm >> 5))) + PSW |= SK; +} + +/* 58: 0101 1000 bbbb bbbb (7807 only) */ +void upd7810_device::SETB() +{ + UINT8 imm; + int bit; + + RDOPARG( imm ); + bit = imm >> 5; + + switch( imm & 0x1f ) + { + case 0x10: /* PA */ + WP( UPD7810_PORTA, RP( UPD7810_PORTA ) | (1 << bit)); + break; + case 0x11: /* PB */ + WP( UPD7810_PORTB, RP( UPD7810_PORTB ) | (1 << bit)); + break; + case 0x12: /* PC */ + WP( UPD7810_PORTC, RP( UPD7810_PORTC ) | (1 << bit)); + break; + case 0x13: /* PD */ + WP( UPD7810_PORTD, RP( UPD7810_PORTD ) | (1 << bit)); + break; + case 0x15: /* PF */ + WP( UPD7810_PORTF, RP( UPD7810_PORTF ) | (1 << bit)); + break; + case 0x16: /* MKH */ + MKH |= (1 << bit); + break; + case 0x17: /* MKL */ + MKL |= (1 << bit); + break; + case 0x19: /* SMH */ + SMH |= (1 << bit); + break; + case 0x1b: /* EOM */ + EOM |= (1 << bit); + break; + case 0x1d: /* TMM */ + TMM |= (1 << bit); + break; +// case 0x1e: /* PT */ +// PT is input only +// break; + default: + logerror("uPD7810 '%s': illegal opcode %02x %02x at PC:%04x\n", tag(), OP, imm, PC); + break; + } +} + +/* 5b: 0101 1011 bbbb bbbb (7807 only) */ +void upd7810_device::CLR() +{ + UINT8 imm; + int bit; + + RDOPARG( imm ); + bit = imm >> 5; + + switch( imm & 0x1f ) + { + case 0x10: /* PA */ + WP( UPD7810_PORTA, RP( UPD7810_PORTA ) & ~(1 << bit)); + break; + case 0x11: /* PB */ + WP( UPD7810_PORTB, RP( UPD7810_PORTB ) & ~(1 << bit)); + break; + case 0x12: /* PC */ + WP( UPD7810_PORTC, RP( UPD7810_PORTC ) & ~(1 << bit)); + break; + case 0x13: /* PD */ + WP( UPD7810_PORTD, RP( UPD7810_PORTD ) & ~(1 << bit)); + break; + case 0x15: /* PF */ + WP( UPD7810_PORTF, RP( UPD7810_PORTF ) & ~(1 << bit)); + break; + case 0x16: /* MKH */ + MKH &= ~(1 << bit); + break; + case 0x17: /* MKL */ + MKL &= ~(1 << bit); + break; + case 0x19: /* SMH */ + SMH &= ~(1 << bit); + break; + case 0x1b: /* EOM */ + EOM &= ~(1 << bit); + break; + case 0x1d: /* TMM */ + TMM &= ~(1 << bit); + break; +// case 0x1e: /* PT */ +// PT is input only +// break; + default: + logerror("uPD7810 '%s': illegal opcode %02x %02x at PC:%04x\n", tag(), OP, imm, PC); + break; + } +} + +/* 5d: 0101 1111 bbbb bbbb (7807 only) */ +void upd7810_device::SK_bit() +{ + UINT8 imm; + int val; + + RDOPARG( imm ); + + switch( imm & 0x1f ) + { + case 0x10: /* PA */ + val = RP( UPD7810_PORTA ); + break; + case 0x11: /* PB */ + val = RP( UPD7810_PORTB ); + break; + case 0x12: /* PC */ + val = RP( UPD7810_PORTC ); + break; + case 0x13: /* PD */ + val = RP( UPD7810_PORTD ); + break; + case 0x15: /* PF */ + val = RP( UPD7810_PORTF ); + break; + case 0x16: /* MKH */ + val = MKH; + break; + case 0x17: /* MKL */ + val = MKL; + break; + case 0x19: /* SMH */ + val = SMH; + break; + case 0x1b: /* EOM */ + val = EOM; + break; + case 0x1d: /* TMM */ + val = TMM; + break; + case 0x1e: /* PT */ + val = RP( UPD7807_PORTT ); + break; + default: + logerror("uPD7810 '%s': illegal opcode %02x %02x at PC:%04x\n", tag(), OP, imm, PC); + val = 0; + break; + } + + if (val & (1 << (imm >> 5))) + PSW |= SK; +} + +/* 60:*/ +void upd7810_device::PRE_60() +{ + RDOP(OP2); + m_icount -= m_op60[OP2].cycles; + handle_timers(m_op60[OP2].cycles); + (this->*m_op60[OP2].opfunc)(); +} + +/* 61: 0110 0001 */ +void upd7810_device::DAA() +{ + UINT8 l = A & 0x0f, h = A >> 4, tmp, adj = 0x00, old_cy = PSW & CY; + + if (0 == (PSW & HC)) + { + if (l < 10) + { + if (!(h < 10 && 0 == (PSW & CY))) + adj = 0x60; + } + else + { + if (h < 9 && 0 == (PSW & CY)) + adj = 0x06; + else + adj = 0x66; + } + } + else + if (l < 3) + { + if (h < 10 && 0 == (PSW & CY)) + adj = 0x06; + else + adj = 0x66; + } + tmp = A + adj; + ZHC_ADD( tmp, A, PSW & CY ); + PSW |= old_cy; + A = tmp; +} + +/* 62: 0110 0010 */ +void upd7810_device::RETI() +{ + PCL = RM( SPD ); + SP++; + PCH = RM( SPD ); + SP++; + PSW = RM( SPD ); + SP++; +} + +/* 63: 0110 0011 oooo oooo */ +void upd7810_device::STAW_wa() +{ + PAIR ea = m_va; + + RDOPARG( ea.b.l ); + + WM( ea.d, A ); +} + +/* 64: prefix */ +void upd7810_device::PRE_64() +{ + RDOP(OP2); + m_icount -= m_op64[OP2].cycles; + handle_timers(m_op64[OP2].cycles); + (this->*m_op64[OP2].opfunc)(); +} + +/* 65: 0110 0101 oooo oooo xxxx xxxx */ +void upd7810_device::NEIW_wa_xx() +{ + PAIR ea = m_va; + UINT8 tmp, m, imm; + + RDOPARG( ea.b.l ); + RDOPARG( imm ); + m = RM( ea.d ); + tmp = m - imm; + ZHC_SUB( tmp, m, 0 ); + SKIP_NZ; +} + +/* 66: 0110 0110 xxxx xxxx */ +/* SUI_A_xx already defined (long form) */ + +/* 67: 0110 0111 xxxx xxxx */ +/* NEI_A_xx already defined (long form) */ + +/* 68: 0110 1000 xxxx xxxx */ +void upd7810_device::MVI_V_xx() +{ + RDOPARG( V ); +} + +/* 69: 0110 1001 xxxx xxxx */ +void upd7810_device::MVI_A_xx() +{ + if (PSW & L1) { /* overlay active? */ + PC++; + return; /* NOP */ + } + RDOPARG( A ); + PSW |= L1; +} + +/* 6a: 0110 1010 xxxx xxxx */ +void upd7810_device::MVI_B_xx() +{ + RDOPARG( B ); +} + +/* 6b: 0110 1011 xxxx xxxx */ +void upd7810_device::MVI_C_xx() +{ + RDOPARG( C ); +} + +/* 6c: 0110 1100 xxxx xxxx */ +void upd7810_device::MVI_D_xx() +{ + RDOPARG( D ); +} + +/* 6d: 0110 1101 xxxx xxxx */ +void upd7810_device::MVI_E_xx() +{ + RDOPARG( E ); +} + +/* 6e: 0110 1110 xxxx xxxx */ +void upd7810_device::MVI_H_xx() +{ + RDOPARG( H ); +} + +/* 6f: 0110 1111 xxxx xxxx */ +void upd7810_device::MVI_L_xx() +{ + if (PSW & L0) { /* overlay active? */ + PC++; + return; /* NOP */ + } + RDOPARG( L ); + PSW |= L0; +} + +/* 70: prefix */ +void upd7810_device::PRE_70() +{ + RDOP(OP2); + m_icount -= m_op70[OP2].cycles; + handle_timers(m_op70[OP2].cycles); + (this->*m_op70[OP2].opfunc)(); +} + +/* 71: 0111 0001 oooo oooo xxxx xxxx */ +void upd7810_device::MVIW_wa_xx() +{ + PAIR ea = m_va; + UINT8 imm; + + RDOPARG( ea.b.l ); + RDOPARG( imm ); + + WM( ea.d, imm ); +} + +/* 72: 0111 0010 */ +void upd7810_device::SOFTI() +{ + SP--; + WM( SPD, PSW ); + SP--; + WM( SPD, PCH ); + SP--; + WM( SPD, PCL ); + + PC = 0x0060; +} + +/* 74: prefix */ +void upd7810_device::PRE_74() +{ + RDOP(OP2); + m_icount -= m_op74[OP2].cycles; + handle_timers(m_op74[OP2].cycles); + (this->*m_op74[OP2].opfunc)(); +} + +/* 75: 0111 0101 oooo oooo xxxx xxxx */ +void upd7810_device::EQIW_wa_xx() +{ + PAIR ea = m_va; + UINT8 tmp, m, imm; + + RDOPARG( ea.b.l ); + RDOPARG( imm ); + m = RM( ea.d ); + tmp = m - imm; + ZHC_SUB( tmp, m, 0 ); + SKIP_Z; +} + +/* 76: 0111 0110 xxxx xxxx */ +/* SBI_A_xx already defined (long form) */ + +/* 77: 0111 0111 xxxx xxxx */ +/* EQI_A_xx already defined (long form) */ + +/* 78: 0111 1ddd dddd dddd */ +void upd7810_device::CALF() +{ + PAIR w; + w.d = 0; + + RDOPARG( w.b.l ); + w.b.h = 0x08 + (OP & 0x07); + + SP--; + WM( SPD, PCH ); + SP--; + WM( SPD, PCL ); + + PCD = w.d; +} + +/* 80: 100t tttt */ +void upd7810_device::CALT() +{ + PAIR w; + w.d = 0; + + w.w.l = 0x80 + 2 * (OP & 0x1f); + + SP--; + WM( SPD, PCH ); + SP--; + WM( SPD, PCL ); + + PCL=RM(w.w.l); + PCH=RM(w.w.l+1); +} + +/* a0: 1010 0000 */ +void upd7810_device::POP_VA() +{ + A = RM( SPD ); + SP++; + V = RM( SPD ); + SP++; +} + +/* a1: 1010 0001 */ +void upd7810_device::POP_BC() +{ + C = RM( SPD ); + SP++; + B = RM( SPD ); + SP++; +} + +/* a2: 1010 0010 */ +void upd7810_device::POP_DE() +{ + E = RM( SPD ); + SP++; + D = RM( SPD ); + SP++; +} + +/* a3: 1010 0011 */ +void upd7810_device::POP_HL() +{ + L = RM( SPD ); + SP++; + H = RM( SPD ); + SP++; +} + +/* a4: 1010 0100 */ +void upd7810_device::POP_EA() +{ + EAL = RM( SPD ); + SP++; + EAH = RM( SPD ); + SP++; +} + +/* a5: 1010 0101 */ +void upd7810_device::DMOV_EA_BC() +{ + EA = BC; +} + +/* a6: 1010 0110 */ +void upd7810_device::DMOV_EA_DE() +{ + EA = DE; +} + +/* a7: 1010 0111 */ +void upd7810_device::DMOV_EA_HL() +{ + EA = HL; +} + +/* a8: 1010 1000 */ +void upd7810_device::INX_EA() +{ + EA++; +} + +/* a9: 1010 1001 */ +void upd7810_device::DCX_EA() +{ + EA--; +} + +/* aa: 1010 1010 */ +void upd7810_device::EI() +{ + IFF = 1; +} + +/* ab: 1010 1011 dddd dddd */ +void upd7810_device::LDAX_D_xx() +{ + UINT16 ea; + RDOPARG( ea ); + ea += DE; + A = RM( ea ); +} + +/* ac: 1010 1100 */ +void upd7810_device::LDAX_H_A() +{ + UINT16 ea; + ea = HL + A; + A = RM( ea ); +} + +/* ad: 1010 1101 */ +void upd7810_device::LDAX_H_B() +{ + UINT16 ea; + ea = HL + B; + A = RM( ea ); +} + +/* ae: 1010 1110 */ +void upd7810_device::LDAX_H_EA() +{ + UINT16 ea; + ea = HL + EA; + A = RM( ea ); +} + +/* af: 1010 1111 dddd dddd */ +void upd7810_device::LDAX_H_xx() +{ + UINT16 ea; + RDOPARG( ea ); + ea += HL; + A = RM( ea ); +} + +/* b0: 1011 0000 */ +void upd7810_device::PUSH_VA() +{ + SP--; + WM( SPD, V ); + SP--; + WM( SPD, A ); +} + +/* b1: 1011 0001 */ +void upd7810_device::PUSH_BC() +{ + SP--; + WM( SPD, B ); + SP--; + WM( SPD, C ); +} + +/* b2: 1011 0010 */ +void upd7810_device::PUSH_DE() +{ + SP--; + WM( SPD, D ); + SP--; + WM( SPD, E ); +} + +/* b3: 1011 0011 */ +void upd7810_device::PUSH_HL() +{ + SP--; + WM( SPD, H ); + SP--; + WM( SPD, L ); +} + +/* b4: 1011 0100 */ +void upd7810_device::PUSH_EA() +{ + SP--; + WM( SPD, EAH ); + SP--; + WM( SPD, EAL ); +} + +/* b5: 1011 0101 */ +void upd7810_device::DMOV_BC_EA() +{ + BC = EA; +} + +/* b6: 1011 0110 */ +void upd7810_device::DMOV_DE_EA() +{ + DE = EA; +} + +/* b7: 1011 0111 */ +void upd7810_device::DMOV_HL_EA() +{ + HL = EA; +} + +/* b8: 1011 1000 */ +void upd7810_device::RET() +{ + PCL = RM( SPD ); + SP++; + PCH = RM( SPD ); + SP++; +} + +/* b9: 1011 1001 */ +void upd7810_device::RETS() +{ + PCL = RM( SPD ); + SP++; + PCH = RM( SPD ); + SP++; + PSW|=SK; /* skip one instruction */ +} + +/* ba: 1011 1010 */ +void upd7810_device::DI() +{ + IFF = 0; +} + +/* bb: 1011 1011 dddd dddd */ +void upd7810_device::STAX_D_xx() +{ + UINT16 ea; + RDOPARG(ea); + ea += DE; + WM( ea, A ); +} + +/* bc: 1011 1100 */ +void upd7810_device::STAX_H_A() +{ + UINT16 ea = A; + ea += HL; + WM( ea, A ); +} + +/* bd: 1011 1101 */ +void upd7810_device::STAX_H_B() +{ + UINT16 ea = B; + ea += HL; + WM( ea, A ); +} + +/* be: 1011 1110 */ +void upd7810_device::STAX_H_EA() +{ + UINT16 ea = EA; + ea += HL; + WM( ea, A ); +} + +/* bf: 1011 1111 dddd dddd */ +void upd7810_device::STAX_H_xx() +{ + UINT16 ea; + RDOPARG( ea ); + ea += HL; + WM( ea, A ); +} + +/* c0: 11dd dddd */ +void upd7810_device::JR() +{ + INT8 offs = (INT8)(OP << 2) >> 2; + PC += offs; +} + +/*********************/ +/* */ +/* 7801 instructions */ +/* */ +/*********************/ + +void upd7810_device::CALT_7801() +{ + PAIR w; + w.d = 0; + + w.w.l = 0x80 + 2 * (OP & 0x3f); + + SP--; + WM( SPD, PCH ); + SP--; + WM( SPD, PCL ); + + PCL=RM(w.w.l); + PCH=RM(w.w.l+1); +} + +/* DCR(W) and INR(W) instructions do not modify the CY register on at least 78c05 and 78c06 */ +void upd7810_device::DCR_A_7801() +{ + UINT32 old_CY = PSW & CY; + DCR_A(); + PSW = ( PSW & ~CY ) | old_CY; +} + +void upd7810_device::DCR_B_7801() +{ + UINT32 old_CY = PSW & CY; + DCR_B(); + PSW = ( PSW & ~CY ) | old_CY; +} + +void upd7810_device::DCR_C_7801() +{ + UINT32 old_CY = PSW & CY; + DCR_C(); + PSW = ( PSW & ~CY ) | old_CY; +} + +void upd7810_device::DCRW_wa_7801() +{ + UINT32 old_CY = PSW & CY; + DCRW_wa(); + PSW = ( PSW & ~CY ) | old_CY; +} + +void upd7810_device::INR_A_7801() +{ + UINT32 old_CY = PSW & CY; + INR_A(); + PSW = ( PSW & ~CY ) | old_CY; +} + +void upd7810_device::INR_B_7801() +{ + UINT32 old_CY = PSW & CY; + INR_B(); + PSW = ( PSW & ~CY ) | old_CY; +} + +void upd7810_device::INR_C_7801() +{ + UINT32 old_CY = PSW & CY; + INR_C(); + PSW = ( PSW & ~CY ) | old_CY; +} + +void upd7810_device::INRW_wa_7801() +{ + UINT32 old_CY = PSW & CY; + INRW_wa(); + PSW = ( PSW & ~CY ) | old_CY; +} + +void upd7810_device::IN() +{ + logerror("unimplemented instruction: IN\n"); +} + +void upd7810_device::OUT() +{ + logerror("unimplemented instruction: OUT\n"); +} + +void upd7810_device::MOV_A_S() +{ + logerror("unimplemented instruction: MOV_A_S\n"); +} + +void upd7810_device::MOV_S_A() +{ + logerror("unimplemented instruction: MOV_A_S\n"); +} + +void upd7810_device::PEN() +{ + logerror("unimplemented instruction: PEN\n"); +} + +void upd7810_device::PER() +{ + logerror("unimplemented instruction: PER\n"); +} + +void upd7810_device::PEX() +{ + logerror("unimplemented instruction: PEX\n"); +} + +void upd7810_device::SIO() +{ + logerror("unimplemented instruction: SIO\n"); +} + +void upd7810_device::SKIT_F0() +{ + if (IRR & INTF0) + PSW |= SK; + IRR &= ~INTF0; +} + +void upd7810_device::SKNIT_F0() +{ + logerror("unimplemented instruction: SKNIT_F0\n"); +} + +void upd7810_device::STM() +{ + m_ovc0 = ( ( TMM & 0x04 ) ? 16 * 8 : 8 ) * TM0; +} + +void upd7810_device::STM_7801() +{ + /* Set the timer flip/fliop */ + TO = 1; + m_to_func(TO); + + /* Reload the timer */ + m_ovc0 = 16 * ( TM0 + ( ( TM1 & 0x0f ) << 8 ) ); +} + +void upd7810_device::MOV_MC_A_7801() +{ + /* On the 7801 the mode C bits function as follows: */ + /* Cn=1 Cn=0 */ + /* PC0 Input Output */ + /* PC1 Input Output */ + /* PC2 Input -SCS Input */ + /* PC3 Output SAK Output */ + /* PC4 Output To Output */ + /* PC5 Output IO/-M Output */ + /* PC6 Output HLDA Output */ + /* PC7 Input HOLD Input */ + MC = 0x84 | ( ( A & 0x02 ) ? 0x02 : 0x00 ) | ( ( A & 0x01 ) ? 0x01 : 0x00 ); +} diff --git a/src/devices/cpu/upd7810/upd7810_table.c b/src/devices/cpu/upd7810/upd7810_table.c new file mode 100644 index 00000000000..f150af4fc2f --- /dev/null +++ b/src/devices/cpu/upd7810/upd7810_table.c @@ -0,0 +1,6252 @@ +// license:BSD-3-Clause +// copyright-holders:Juergen Buchmueller +/***************************************************************************** + * + * Portable uPD7810/11, 7810H/11H, 78C10/C11/C14 emulator V0.2 + * + * 7810tbl.inc - function pointer tables + * + *****************************************************************************/ + +#include "emu.h" +#include "upd7810.h" + +const struct upd7810_device::opcode_s upd7810_device::s_op48[256] = +{ + {&upd7810_device::illegal, 2, 8, 8,L0|L1}, /* 00: 0100 1000 0000 0000 */ + {&upd7810_device::SLRC_A, 2, 8, 8,L0|L1}, /* 01: 0100 1000 0000 0001 */ + {&upd7810_device::SLRC_B, 2, 8, 8,L0|L1}, /* 02: 0100 1000 0000 0010 */ + {&upd7810_device::SLRC_C, 2, 8, 8,L0|L1}, /* 03: 0100 1000 0000 0011 */ + {&upd7810_device::illegal, 2, 8, 8,L0|L1}, /* 04: 0100 1000 0000 0100 */ + {&upd7810_device::SLLC_A, 2, 8, 8,L0|L1}, /* 05: 0100 1000 0000 0101 */ + {&upd7810_device::SLLC_B, 2, 8, 8,L0|L1}, /* 06: 0100 1000 0000 0110 */ + {&upd7810_device::SLLC_C, 2, 8, 8,L0|L1}, /* 07: 0100 1000 0000 0111 */ + {&upd7810_device::SK_NV, 2, 8, 8,L0|L1}, /* 08: 0100 1000 0000 1000 */ + {&upd7810_device::illegal, 2, 8, 8,L0|L1}, /* 09: 0100 1000 0000 1001 */ + {&upd7810_device::SK_CY, 2, 8, 8,L0|L1}, /* 0a: 0100 1000 0000 1010 */ + {&upd7810_device::SK_HC, 2, 8, 8,L0|L1}, /* 0b: 0100 1000 0000 1011 */ + {&upd7810_device::SK_Z, 2, 8, 8,L0|L1}, /* 0c: 0100 1000 0000 1100 */ + {&upd7810_device::illegal, 2, 8, 8,L0|L1}, /* 0d: 0100 1000 0000 1101 */ + {&upd7810_device::illegal, 2, 8, 8,L0|L1}, /* 0e: 0100 1000 0000 1110 */ + {&upd7810_device::illegal, 2, 8, 8,L0|L1}, /* 0f: 0100 1000 0000 1111 */ + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 10: 0100 1000 0001 0000 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 11: 0100 1000 0001 0001 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 12: 0100 1000 0001 0010 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 13: 0100 1000 0001 0011 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 14: 0100 1000 0001 0100 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 15: 0100 1000 0001 0101 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 16: 0100 1000 0001 0110 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 17: 0100 1000 0001 0111 */ + {&upd7810_device::SKN_NV, 2, 8, 8,L0|L1}, /* 18: 0100 1000 0001 1000 */ + {&upd7810_device::illegal, 2, 8, 8,L0|L1}, /* 19: 0100 1000 0001 1001 */ + {&upd7810_device::SKN_CY, 2, 8, 8,L0|L1}, /* 1a: 0100 1000 0001 1010 */ + {&upd7810_device::SKN_HC, 2, 8, 8,L0|L1}, /* 1b: 0100 1000 0001 1011 */ + {&upd7810_device::SKN_Z, 2, 8, 8,L0|L1}, /* 1c: 0100 1000 0001 1100 */ + {&upd7810_device::illegal, 2, 8, 8,L0|L1}, /* 1d: 0100 1000 0001 1101 */ + {&upd7810_device::illegal, 2, 8, 8,L0|L1}, /* 1e: 0100 1000 0001 1110 */ + {&upd7810_device::illegal, 2, 8, 8,L0|L1}, /* 1f: 0100 1000 0001 1111 */ + + {&upd7810_device::illegal, 2, 8, 8,L0|L1}, /* 20: 0100 1000 0010 0000 */ + {&upd7810_device::SLR_A, 2, 8, 8,L0|L1}, /* 21: 0100 1000 0010 0001 */ + {&upd7810_device::SLR_B, 2, 8, 8,L0|L1}, /* 22: 0100 1000 0010 0010 */ + {&upd7810_device::SLR_C, 2, 8, 8,L0|L1}, /* 23: 0100 1000 0010 0011 */ + {&upd7810_device::illegal, 2, 8, 8,L0|L1}, /* 24: 0100 1000 0010 0100 */ + {&upd7810_device::SLL_A, 2, 8, 8,L0|L1}, /* 25: 0100 1000 0010 0101 */ + {&upd7810_device::SLL_B, 2, 8, 8,L0|L1}, /* 26: 0100 1000 0010 0110 */ + {&upd7810_device::SLL_C, 2, 8, 8,L0|L1}, /* 27: 0100 1000 0010 0111 */ + {&upd7810_device::JEA, 2, 8, 8,L0|L1}, /* 28: 0100 1000 0010 1000 */ + {&upd7810_device::CALB, 2,17,17,L0|L1}, /* 29: 0100 1000 0010 1001 */ + {&upd7810_device::CLC, 2, 8, 8,L0|L1}, /* 2a: 0100 1000 0010 1010 */ + {&upd7810_device::STC, 2, 8, 8,L0|L1}, /* 2b: 0100 1000 0010 1011 */ + {&upd7810_device::illegal, 2,32,32,L0|L1}, /* 2c: 0100 1000 0010 1100 */ + {&upd7810_device::MUL_A, 2,32,32,L0|L1}, /* 2d: 0100 1000 0010 1101 */ + {&upd7810_device::MUL_B, 2,32,32,L0|L1}, /* 2e: 0100 1000 0010 1110 */ + {&upd7810_device::MUL_C, 2,32,32,L0|L1}, /* 2f: 0100 1000 0010 1111 */ + + {&upd7810_device::illegal, 2, 8, 8,L0|L1}, /* 30: 0100 1000 0011 0000 */ + {&upd7810_device::RLR_A, 2, 8, 8,L0|L1}, /* 31: 0100 1000 0011 0001 */ + {&upd7810_device::RLR_B, 2, 8, 8,L0|L1}, /* 32: 0100 1000 0011 0010 */ + {&upd7810_device::RLR_C, 2, 8, 8,L0|L1}, /* 33: 0100 1000 0011 0011 */ + {&upd7810_device::illegal, 2, 8, 8,L0|L1}, /* 34: 0100 1000 0011 0100 */ + {&upd7810_device::RLL_A, 2, 8, 8,L0|L1}, /* 35: 0100 1000 0011 0101 */ + {&upd7810_device::RLL_B, 2, 8, 8,L0|L1}, /* 36: 0100 1000 0011 0110 */ + {&upd7810_device::RLL_C, 2, 8, 8,L0|L1}, /* 37: 0100 1000 0011 0111 */ + {&upd7810_device::RLD, 2,17,17,L0|L1}, /* 38: 0100 1000 0011 1000 */ + {&upd7810_device::RRD, 2,17,17,L0|L1}, /* 39: 0100 1000 0011 1001 */ + {&upd7810_device::NEGA, 2, 8, 8,L0|L1}, /* 3a: 0100 1000 0011 1010 */ + {&upd7810_device::HALT, 2,12,12,L0|L1}, /* 3b: 0100 1000 0011 1011 */ + {&upd7810_device::illegal, 2, 8, 8,L0|L1}, /* 3c: 0100 1000 0011 1100 */ + {&upd7810_device::DIV_A, 2,59,59,L0|L1}, /* 3d: 0100 1000 0011 1101 */ + {&upd7810_device::DIV_B, 2,59,59,L0|L1}, /* 3e: 0100 1000 0011 1110 */ + {&upd7810_device::DIV_C, 2,59,59,L0|L1}, /* 3f: 0100 1000 0011 1111 */ + + {&upd7810_device::SKIT_NMI, 2, 8, 8,L0|L1}, /* 40: 0100 1000 0100 0000 */ + {&upd7810_device::SKIT_FT0, 2, 8, 8,L0|L1}, /* 41: 0100 1000 0100 0001 */ + {&upd7810_device::SKIT_FT1, 2, 8, 8,L0|L1}, /* 42: 0100 1000 0100 0010 */ + {&upd7810_device::SKIT_F1, 2, 8, 8,L0|L1}, /* 43: 0100 1000 0100 0011 */ + {&upd7810_device::SKIT_F2, 2, 8, 8,L0|L1}, /* 44: 0100 1000 0100 0100 */ + {&upd7810_device::SKIT_FE0, 2, 8, 8,L0|L1}, /* 45: 0100 1000 0100 0101 */ + {&upd7810_device::SKIT_FE1, 2, 8, 8,L0|L1}, /* 46: 0100 1000 0100 0110 */ + {&upd7810_device::SKIT_FEIN, 2, 8, 8,L0|L1}, /* 47: 0100 1000 0100 0111 */ + {&upd7810_device::SKIT_FAD, 2, 8, 8,L0|L1}, /* 48: 0100 1000 0100 1000 */ + {&upd7810_device::SKIT_FSR, 2, 8, 8,L0|L1}, /* 49: 0100 1000 0100 1001 */ + {&upd7810_device::SKIT_FST, 2, 8, 8,L0|L1}, /* 4a: 0100 1000 0100 1010 */ + {&upd7810_device::SKIT_ER, 2, 8, 8,L0|L1}, /* 4b: 0100 1000 0100 1011 */ + {&upd7810_device::SKIT_OV, 2, 8, 8,L0|L1}, /* 4c: 0100 1000 0100 1100 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 4d: 0100 1000 0100 1101 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 4e: 0100 1000 0100 1110 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 4f: 0100 1000 0100 1111 */ + + {&upd7810_device::SKIT_AN4, 2, 8, 8,L0|L1}, /* 50: 0100 1000 0101 0000 */ + {&upd7810_device::SKIT_AN5, 2, 8, 8,L0|L1}, /* 51: 0100 1000 0101 0001 */ + {&upd7810_device::SKIT_AN6, 2, 8, 8,L0|L1}, /* 52: 0100 1000 0101 0010 */ + {&upd7810_device::SKIT_AN7, 2, 8, 8,L0|L1}, /* 53: 0100 1000 0101 0011 */ + {&upd7810_device::SKIT_SB, 2, 8, 8,L0|L1}, /* 54: 0100 1000 0101 0100 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 55: 0100 1000 0101 0101 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 56: 0100 1000 0101 0110 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 57: 0100 1000 0101 0111 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 58: 0100 1000 0101 1000 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 59: 0100 1000 0101 1001 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 5a: 0100 1000 0101 1010 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 5b: 0100 1000 0101 1011 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 5c: 0100 1000 0101 1100 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 5d: 0100 1000 0101 1101 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 5e: 0100 1000 0101 1110 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 5f: 0100 1000 0101 1111 */ + + {&upd7810_device::SKNIT_NMI, 2, 8, 8,L0|L1}, /* 60: 0100 1000 0110 0000 */ + {&upd7810_device::SKNIT_FT0, 2, 8, 8,L0|L1}, /* 61: 0100 1000 0110 0001 */ + {&upd7810_device::SKNIT_FT1, 2, 8, 8,L0|L1}, /* 62: 0100 1000 0110 0010 */ + {&upd7810_device::SKNIT_F1, 2, 8, 8,L0|L1}, /* 63: 0100 1000 0110 0011 */ + {&upd7810_device::SKNIT_F2, 2, 8, 8,L0|L1}, /* 64: 0100 1000 0110 0100 */ + {&upd7810_device::SKNIT_FE0, 2, 8, 8,L0|L1}, /* 65: 0100 1000 0110 0101 */ + {&upd7810_device::SKNIT_FE1, 2, 8, 8,L0|L1}, /* 66: 0100 1000 0110 0110 */ + {&upd7810_device::SKNIT_FEIN, 2, 8, 8,L0|L1}, /* 67: 0100 1000 0110 0111 */ + {&upd7810_device::SKNIT_FAD, 2, 8, 8,L0|L1}, /* 68: 0100 1000 0110 1000 */ + {&upd7810_device::SKNIT_FSR, 2, 8, 8,L0|L1}, /* 69: 0100 1000 0110 1001 */ + {&upd7810_device::SKNIT_FST, 2, 8, 8,L0|L1}, /* 6a: 0100 1000 0110 1010 */ + {&upd7810_device::SKNIT_ER, 2, 8, 8,L0|L1}, /* 6b: 0100 1000 0110 1011 */ + {&upd7810_device::SKNIT_OV, 2, 8, 8,L0|L1}, /* 6c: 0100 1000 0110 1100 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 6d: 0100 1000 0110 1101 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 6e: 0100 1000 0110 1110 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 6f: 0100 1000 0110 1111 */ + + {&upd7810_device::SKNIT_AN4, 2, 8, 8,L0|L1}, /* 70: 0100 1000 0111 0000 */ + {&upd7810_device::SKNIT_AN5, 2, 8, 8,L0|L1}, /* 71: 0100 1000 0111 0001 */ + {&upd7810_device::SKNIT_AN6, 2, 8, 8,L0|L1}, /* 72: 0100 1000 0111 0010 */ + {&upd7810_device::SKNIT_AN7, 2, 8, 8,L0|L1}, /* 73: 0100 1000 0111 0011 */ + {&upd7810_device::SKNIT_SB, 2, 8, 8,L0|L1}, /* 74: 0100 1000 0111 0100 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 75: 0100 1000 0111 0101 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 76: 0100 1000 0111 0110 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 77: 0100 1000 0111 0111 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 78: 0100 1000 0111 1000 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 79: 0100 1000 0111 1001 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 7a: 0100 1000 0111 1010 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 7b: 0100 1000 0111 1011 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 7c: 0100 1000 0111 1100 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 7d: 0100 1000 0111 1101 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 7e: 0100 1000 0111 1110 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 7f: 0100 1000 0111 1111 */ + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 80: 0100 1000 1000 0000 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 81: 0100 1000 1000 0001 */ + {&upd7810_device::LDEAX_D, 2,14,11,L0|L1}, /* 82: 0100 1000 1000 0010 */ + {&upd7810_device::LDEAX_H, 2,14,11,L0|L1}, /* 83: 0100 1000 1000 0011 */ + {&upd7810_device::LDEAX_Dp, 2,14,11,L0|L1}, /* 84: 0100 1000 1000 0100 */ + {&upd7810_device::LDEAX_Hp, 2,14,11,L0|L1}, /* 85: 0100 1000 1000 0101 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 86: 0100 1000 1000 0110 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 87: 0100 1000 1000 0111 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 88: 0100 1000 1000 1000 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 89: 0100 1000 1000 1001 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 8a: 0100 1000 1000 1010 */ + {&upd7810_device::LDEAX_D_xx, 3,20,20,L0|L1}, /* 8b: 0100 1000 1000 1011 xxxx xxxx */ + {&upd7810_device::LDEAX_H_A, 2,20,20,L0|L1}, /* 8c: 0100 1000 1000 1100 */ + {&upd7810_device::LDEAX_H_B, 2,20,20,L0|L1}, /* 8d: 0100 1000 1000 1101 */ + {&upd7810_device::LDEAX_H_EA, 2,20,20,L0|L1}, /* 8e: 0100 1000 1000 1110 */ + {&upd7810_device::LDEAX_H_xx, 3,20,20,L0|L1}, /* 8f: 0100 1000 1000 1111 xxxx xxxx */ + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 90: 0100 1000 1000 0000 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 91: 0100 1000 1000 0001 */ + {&upd7810_device::STEAX_D, 2,14,11,L0|L1}, /* 92: 0100 1000 1000 0010 */ + {&upd7810_device::STEAX_H, 2,14,11,L0|L1}, /* 93: 0100 1000 1000 0011 */ + {&upd7810_device::STEAX_Dp, 2,14,11,L0|L1}, /* 94: 0100 1000 1000 0100 */ + {&upd7810_device::STEAX_Hp, 2,14,11,L0|L1}, /* 95: 0100 1000 1000 0101 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 96: 0100 1000 1000 0110 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 97: 0100 1000 1000 0111 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 98: 0100 1000 1000 1000 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 99: 0100 1000 1000 1001 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 9a: 0100 1000 1000 1010 */ + {&upd7810_device::STEAX_D_xx, 3,20,20,L0|L1}, /* 9b: 0100 1000 1000 1011 xxxx xxxx */ + {&upd7810_device::STEAX_H_A, 2,20,20,L0|L1}, /* 9c: 0100 1000 1000 1100 */ + {&upd7810_device::STEAX_H_B, 2,20,20,L0|L1}, /* 9d: 0100 1000 1000 1101 */ + {&upd7810_device::STEAX_H_EA, 2,20,20,L0|L1}, /* 9e: 0100 1000 1000 1110 */ + {&upd7810_device::STEAX_H_xx, 3,20,20,L0|L1}, /* 9f: 0100 1000 1000 1111 xxxx xxxx */ + + {&upd7810_device::DSLR_EA, 2, 8, 8,L0|L1}, /* a0: 0100 1000 1010 0000 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* a1: 0100 1000 1010 0001 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* a2: 0100 1000 1010 0010 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* a3: 0100 1000 1010 0011 */ + {&upd7810_device::DSLL_EA, 2, 8, 8,L0|L1}, /* a4: 0100 1000 1010 0100 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* a5: 0100 1000 1010 0101 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* a6: 0100 1000 1010 0110 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* a7: 0100 1000 1010 0111 */ + {&upd7810_device::TABLE, 2,17,17,L0|L1}, /* a8: 0100 1000 1010 1000 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* a9: 0100 1000 1010 1001 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* aa: 0100 1000 1010 1010 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* ab: 0100 1000 1010 1011 */ +// {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* ac: 0100 1000 1010 1100 */ +// {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* ad: 0100 1000 1010 1101 */ +// {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* ae: 0100 1000 1010 1110 */ +// {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* af: 0100 1000 1010 1111 */ + {&upd7810_device::EXA, 2, 8, 8,L0|L1}, /* ac: 0100 1000 1010 1100 */ /* 7807 */ + {&upd7810_device::EXR, 2, 8, 8,L0|L1}, /* ad: 0100 1000 1010 1101 */ /* 7807 */ + {&upd7810_device::EXH, 2, 8, 8,L0|L1}, /* ae: 0100 1000 1010 1110 */ /* 7807 */ + {&upd7810_device::EXX, 2, 8, 8,L0|L1}, /* af: 0100 1000 1010 1111 */ /* 7807 */ + {&upd7810_device::DRLR_EA, 2, 8, 8,L0|L1}, /* b0: 0100 1000 1011 0000 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* b1: 0100 1000 1011 0001 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* b2: 0100 1000 1011 0010 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* b3: 0100 1000 1011 0011 */ + {&upd7810_device::DRLL_EA, 2, 8, 8,L0|L1}, /* b4: 0100 1000 1011 0100 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* b5: 0100 1000 1011 0101 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* b6: 0100 1000 1011 0110 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* b7: 0100 1000 1011 0111 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* b8: 0100 1000 1011 1000 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* b9: 0100 1000 1011 1001 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* ba: 0100 1000 1011 1010 */ + {&upd7810_device::STOP, 2,12,12,L0|L1}, /* bb: 0100 1000 1011 1011 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* bc: 0100 1000 1011 1100 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* bd: 0100 1000 1011 1101 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* be: 0100 1000 1011 1110 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* bf: 0100 1000 1011 1111 */ + + {&upd7810_device::DMOV_EA_ECNT, 2,14,11,L0|L1}, /* c0: 0100 1000 1100 0000 */ + {&upd7810_device::DMOV_EA_ECPT, 2,14,11,L0|L1}, /* c1: 0100 1000 1100 0001 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* c2: 0100 1000 1100 0010 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* c3: 0100 1000 1100 0011 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* c4: 0100 1000 1100 0100 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* c5: 0100 1000 1100 0101 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* c6: 0100 1000 1100 0110 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* c7: 0100 1000 1100 0111 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* c8: 0100 1000 1100 1000 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* c9: 0100 1000 1100 1001 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* ca: 0100 1000 1100 1010 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* cb: 0100 1000 1100 1011 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* cc: 0100 1000 1100 1100 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* cd: 0100 1000 1100 1101 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* ce: 0100 1000 1100 1110 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* cf: 0100 1000 1100 1111 */ + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* d0: 0100 1000 1101 0000 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* d1: 0100 1000 1101 0001 */ + {&upd7810_device::DMOV_ETM0_EA, 2,14,11,L0|L1}, /* d2: 0100 1000 1101 0010 */ + {&upd7810_device::DMOV_ETM1_EA, 2,14,11,L0|L1}, /* d3: 0100 1000 1101 0011 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* d4: 0100 1000 1101 0100 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* d5: 0100 1000 1101 0101 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* d6: 0100 1000 1101 0110 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* d7: 0100 1000 1101 0111 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* d8: 0100 1000 1101 1000 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* d9: 0100 1000 1101 1001 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* da: 0100 1000 1101 1010 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* db: 0100 1000 1101 1011 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* dc: 0100 1000 1101 1100 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* dd: 0100 1000 1101 1101 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* de: 0100 1000 1101 1110 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* df: 0100 1000 1101 1111 */ + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* e0: 0100 1000 1110 0000 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* e1: 0100 1000 1110 0001 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* e2: 0100 1000 1110 0010 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* e3: 0100 1000 1110 0011 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* e4: 0100 1000 1110 0100 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* e5: 0100 1000 1110 0101 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* e6: 0100 1000 1110 0110 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* e7: 0100 1000 1110 0111 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* e8: 0100 1000 1110 1000 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* e9: 0100 1000 1110 1001 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* ea: 0100 1000 1110 1010 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* eb: 0100 1000 1110 1011 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* ec: 0100 1000 1110 1100 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* ed: 0100 1000 1110 1101 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* ee: 0100 1000 1110 1110 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* ef: 0100 1000 1110 1111 */ + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* f0: 0100 1000 1111 0000 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* f1: 0100 1000 1111 0001 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* f2: 0100 1000 1111 0010 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* f3: 0100 1000 1111 0011 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* f4: 0100 1000 1111 0100 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* f5: 0100 1000 1111 0101 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* f6: 0100 1000 1111 0110 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* f7: 0100 1000 1111 0111 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* f8: 0100 1000 1111 1000 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* f9: 0100 1000 1111 1001 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* fa: 0100 1000 1111 1010 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* fb: 0100 1000 1111 1011 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* fc: 0100 1000 1111 1100 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* fd: 0100 1000 1111 1101 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* fe: 0100 1000 1111 1110 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1} /* ff: 0100 1000 1111 1111 */ +}; + +/* prefix 4C */ +const struct upd7810_device::opcode_s upd7810_device::s_op4C[256] = +{ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 00: 0100 1100 0000 0000 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 01: 0100 1100 0000 0001 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 02: 0100 1100 0000 0010 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 03: 0100 1100 0000 0011 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 04: 0100 1100 0000 0100 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 05: 0100 1100 0000 0101 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 06: 0100 1100 0000 0110 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 07: 0100 1100 0000 0111 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 08: 0100 1100 0000 1000 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 09: 0100 1100 0000 1001 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 0a: 0100 1100 0000 1010 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 0b: 0100 1100 0000 1011 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 0c: 0100 1100 0000 1100 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 0d: 0100 1100 0000 1101 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 0e: 0100 1100 0000 1110 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 0f: 0100 1100 0000 1111 */ + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 10: 0100 1100 0001 0000 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 11: 0100 1100 0001 0001 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 12: 0100 1100 0001 0010 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 13: 0100 1100 0001 0011 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 14: 0100 1100 0001 0100 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 15: 0100 1100 0001 0101 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 16: 0100 1100 0001 0110 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 17: 0100 1100 0001 0111 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 18: 0100 1100 0001 1000 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 19: 0100 1100 0001 1001 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 1a: 0100 1100 0001 1010 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 1b: 0100 1100 0001 1011 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 1c: 0100 1100 0001 1100 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 1d: 0100 1100 0001 1101 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 1e: 0100 1100 0001 1110 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 1f: 0100 1100 0001 1111 */ + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 20: 0100 1100 0010 0000 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 21: 0100 1100 0010 0001 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 22: 0100 1100 0010 0010 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 23: 0100 1100 0010 0011 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 24: 0100 1100 0010 0100 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 25: 0100 1100 0010 0101 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 26: 0100 1100 0010 0110 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 27: 0100 1100 0010 0111 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 28: 0100 1100 0010 1000 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 29: 0100 1100 0010 1001 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 2a: 0100 1100 0010 1010 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 2b: 0100 1100 0010 1011 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 2c: 0100 1100 0010 1100 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 2d: 0100 1100 0010 1101 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 2e: 0100 1100 0010 1110 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 2f: 0100 1100 0010 1111 */ + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 30: 0100 1100 0011 0000 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 31: 0100 1100 0011 0001 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 32: 0100 1100 0011 0010 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 33: 0100 1100 0011 0011 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 34: 0100 1100 0011 0100 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 35: 0100 1100 0011 0101 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 36: 0100 1100 0011 0110 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 37: 0100 1100 0011 0111 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 38: 0100 1100 0011 1000 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 39: 0100 1100 0011 1001 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 3a: 0100 1100 0011 1010 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 3b: 0100 1100 0011 1011 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 3c: 0100 1100 0011 1100 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 3d: 0100 1100 0011 1101 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 3e: 0100 1100 0011 1110 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 3f: 0100 1100 0011 1111 */ + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 40: 0100 1100 0100 0000 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 41: 0100 1100 0100 0001 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 42: 0100 1100 0100 0010 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 43: 0100 1100 0100 0011 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 44: 0100 1100 0100 0100 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 45: 0100 1100 0100 0101 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 46: 0100 1100 0100 0110 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 47: 0100 1100 0100 0111 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 48: 0100 1100 0100 1000 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 49: 0100 1100 0100 1001 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 4a: 0100 1100 0100 1010 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 4b: 0100 1100 0100 1011 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 4c: 0100 1100 0100 1100 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 4d: 0100 1100 0100 1101 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 4e: 0100 1100 0100 1110 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 4f: 0100 1100 0100 1111 */ + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 50: 0100 1100 0101 0000 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 51: 0100 1100 0101 0001 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 52: 0100 1100 0101 0010 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 53: 0100 1100 0101 0011 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 54: 0100 1100 0101 0100 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 55: 0100 1100 0101 0101 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 56: 0100 1100 0101 0110 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 57: 0100 1100 0101 0111 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 58: 0100 1100 0101 1000 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 59: 0100 1100 0101 1001 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 5a: 0100 1100 0101 1010 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 5b: 0100 1100 0101 1011 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 5c: 0100 1100 0101 1100 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 5d: 0100 1100 0101 1101 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 5e: 0100 1100 0101 1110 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 5f: 0100 1100 0101 1111 */ + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 60: 0100 1100 0110 0000 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 61: 0100 1100 0110 0001 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 62: 0100 1100 0110 0010 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 63: 0100 1100 0110 0011 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 64: 0100 1100 0110 0100 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 65: 0100 1100 0110 0101 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 66: 0100 1100 0110 0110 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 67: 0100 1100 0110 0111 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 68: 0100 1100 0110 1000 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 69: 0100 1100 0110 1001 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 6a: 0100 1100 0110 1010 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 6b: 0100 1100 0110 1011 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 6c: 0100 1100 0110 1100 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 6d: 0100 1100 0110 1101 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 6e: 0100 1100 0110 1110 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 6f: 0100 1100 0110 1111 */ + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 70: 0100 1100 0111 0000 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 71: 0100 1100 0111 0001 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 72: 0100 1100 0111 0010 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 73: 0100 1100 0111 0011 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 74: 0100 1100 0111 0100 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 75: 0100 1100 0111 0101 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 76: 0100 1100 0111 0110 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 77: 0100 1100 0111 0111 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 78: 0100 1100 0111 1000 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 79: 0100 1100 0111 1001 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 7a: 0100 1100 0111 1010 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 7b: 0100 1100 0111 1011 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 7c: 0100 1100 0111 1100 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 7d: 0100 1100 0111 1101 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 7e: 0100 1100 0111 1110 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 7f: 0100 1100 0111 1111 */ + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 80: 0100 1100 1000 0000 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 81: 0100 1100 1000 0001 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 82: 0100 1100 1000 0010 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 83: 0100 1100 1000 0011 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 84: 0100 1100 1000 0100 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 85: 0100 1100 1000 0101 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 86: 0100 1100 1000 0110 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 87: 0100 1100 1000 0111 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 88: 0100 1100 1000 1000 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 89: 0100 1100 1000 1001 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 8a: 0100 1100 1000 1010 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 8b: 0100 1100 1000 1011 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 8c: 0100 1100 1000 1100 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 8d: 0100 1100 1000 1101 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 8e: 0100 1100 1000 1110 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 8f: 0100 1100 1000 1111 */ + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 90: 0100 1100 1001 0000 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 91: 0100 1100 1001 0001 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 92: 0100 1100 1001 0010 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 93: 0100 1100 1001 0011 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 94: 0100 1100 1001 0100 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 95: 0100 1100 1001 0101 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 96: 0100 1100 1001 0110 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 97: 0100 1100 1001 0111 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 98: 0100 1100 1001 1000 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 99: 0100 1100 1001 1001 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 9a: 0100 1100 1001 1010 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 9b: 0100 1100 1001 1011 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 9c: 0100 1100 1001 1100 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 9d: 0100 1100 1001 1101 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 9e: 0100 1100 1001 1110 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 9f: 0100 1100 1001 1111 */ + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* a0: 0100 1100 1010 0000 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* a1: 0100 1100 1010 0001 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* a2: 0100 1100 1010 0010 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* a3: 0100 1100 1010 0011 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* a4: 0100 1100 1010 0100 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* a5: 0100 1100 1010 0101 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* a6: 0100 1100 1010 0110 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* a7: 0100 1100 1010 0111 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* a8: 0100 1100 1010 1000 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* a9: 0100 1100 1010 1001 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* aa: 0100 1100 1010 1010 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* ab: 0100 1100 1010 1011 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* ac: 0100 1100 1010 1100 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* ad: 0100 1100 1010 1101 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* ae: 0100 1100 1010 1110 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* af: 0100 1100 1010 1111 */ + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* b0: 0100 1100 1011 0000 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* b1: 0100 1100 1011 0001 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* b2: 0100 1100 1011 0010 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* b3: 0100 1100 1011 0011 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* b4: 0100 1100 1011 0100 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* b5: 0100 1100 1011 0101 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* b6: 0100 1100 1011 0110 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* b7: 0100 1100 1011 0111 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* b8: 0100 1100 1011 1000 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* b9: 0100 1100 1011 1001 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* ba: 0100 1100 1011 1010 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* bb: 0100 1100 1011 1011 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* bc: 0100 1100 1011 1100 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* bd: 0100 1100 1011 1101 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* be: 0100 1100 1011 1110 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* bf: 0100 1100 1011 1111 */ + + {&upd7810_device::MOV_A_PA, 2,10,10,L0|L1}, /* c0: 0100 1100 1100 0000 */ + {&upd7810_device::MOV_A_PB, 2,10,10,L0|L1}, /* c1: 0100 1100 1100 0001 */ + {&upd7810_device::MOV_A_PC, 2,10,10,L0|L1}, /* c2: 0100 1100 1100 0010 */ + {&upd7810_device::MOV_A_PD, 2,10,10,L0|L1}, /* c3: 0100 1100 1100 0011 */ + {&upd7810_device::illegal2, 2,10,10,L0|L1}, /* c4: 0100 1100 1100 0100 */ + {&upd7810_device::MOV_A_PF, 2,10,10,L0|L1}, /* c5: 0100 1100 1100 0101 */ + {&upd7810_device::MOV_A_MKH, 2,10,10,L0|L1}, /* c6: 0100 1100 1100 0110 */ + {&upd7810_device::MOV_A_MKL, 2,10,10,L0|L1}, /* c7: 0100 1100 1100 0111 */ + {&upd7810_device::MOV_A_ANM, 2,10,10,L0|L1}, /* c8: 0100 1100 1100 1000 */ + {&upd7810_device::MOV_A_SMH, 2,10,10,L0|L1}, /* c9: 0100 1100 1100 1001 */ + {&upd7810_device::illegal2, 2,10,10,L0|L1}, /* ca: 0100 1100 1100 1010 */ + {&upd7810_device::MOV_A_EOM, 2,10,10,L0|L1}, /* cb: 0100 1100 1100 1011 */ + {&upd7810_device::illegal2, 2,10,10,L0|L1}, /* cc: 0100 1100 1100 1100 */ + {&upd7810_device::MOV_A_TMM, 2,10,10,L0|L1}, /* cd: 0100 1100 1100 1101 */ +// {&upd7810_device::illegal2, 2,10,10,L0|L1}, /* ce: 0100 1100 1100 1110 */ + {&upd7810_device::MOV_A_PT, 2,10,10,L0|L1}, /* ce: 0100 1100 1100 1110 */ /* 7807 */ + {&upd7810_device::illegal2, 2,10,10,L0|L1}, /* cf: 0100 1100 1100 1111 */ + + {&upd7810_device::illegal2, 2,10,10,L0|L1}, /* d0: 0100 1100 1101 0000 */ + {&upd7810_device::illegal2, 2,10,10,L0|L1}, /* d1: 0100 1100 1101 0001 */ + {&upd7810_device::illegal2, 2,10,10,L0|L1}, /* d2: 0100 1100 1101 0010 */ + {&upd7810_device::illegal2, 2,10,10,L0|L1}, /* d3: 0100 1100 1101 0011 */ + {&upd7810_device::illegal2, 2,10,10,L0|L1}, /* d4: 0100 1100 1101 0100 */ + {&upd7810_device::illegal2, 2,10,10,L0|L1}, /* d5: 0100 1100 1101 0101 */ + {&upd7810_device::illegal2, 2,10,10,L0|L1}, /* d6: 0100 1100 1101 0110 */ + {&upd7810_device::illegal2, 2,10,10,L0|L1}, /* d7: 0100 1100 1101 0111 */ + {&upd7810_device::illegal2, 2,10,10,L0|L1}, /* d8: 0100 1100 1101 1000 */ + {&upd7810_device::MOV_A_RXB, 2,10,10,L0|L1}, /* d9: 0100 1100 1101 1001 */ + {&upd7810_device::illegal2, 2,10,10,L0|L1}, /* da: 0100 1100 1101 1010 */ + {&upd7810_device::illegal2, 2,10,10,L0|L1}, /* db: 0100 1100 1101 1011 */ + {&upd7810_device::illegal2, 2,10,10,L0|L1}, /* dc: 0100 1100 1101 1100 */ + {&upd7810_device::illegal2, 2,10,10,L0|L1}, /* dd: 0100 1100 1101 1101 */ + {&upd7810_device::illegal2, 2,10,10,L0|L1}, /* de: 0100 1100 1101 1110 */ + {&upd7810_device::illegal2, 2,10,10,L0|L1}, /* df: 0100 1100 1101 1111 */ + + {&upd7810_device::MOV_A_CR0, 2,10,10,L0|L1}, /* e0: 0100 1100 1110 0000 */ + {&upd7810_device::MOV_A_CR1, 2,10,10,L0|L1}, /* e1: 0100 1100 1110 0001 */ + {&upd7810_device::MOV_A_CR2, 2,10,10,L0|L1}, /* e2: 0100 1100 1110 0010 */ + {&upd7810_device::MOV_A_CR3, 2,10,10,L0|L1}, /* e3: 0100 1100 1110 0011 */ + {&upd7810_device::illegal2, 2,10,10,L0|L1}, /* e4: 0100 1100 1110 0100 */ + {&upd7810_device::illegal2, 2,10,10,L0|L1}, /* e5: 0100 1100 1110 0101 */ + {&upd7810_device::illegal2, 2,10,10,L0|L1}, /* e6: 0100 1100 1110 0110 */ + {&upd7810_device::illegal2, 2,10,10,L0|L1}, /* e7: 0100 1100 1110 0111 */ + {&upd7810_device::illegal2, 2,10,10,L0|L1}, /* e8: 0100 1100 1110 1000 */ + {&upd7810_device::illegal2, 2,10,10,L0|L1}, /* e9: 0100 1100 1110 1001 */ + {&upd7810_device::illegal2, 2,10,10,L0|L1}, /* ea: 0100 1100 1110 1010 */ + {&upd7810_device::illegal2, 2,10,10,L0|L1}, /* eb: 0100 1100 1110 1011 */ + {&upd7810_device::illegal2, 2,10,10,L0|L1}, /* ec: 0100 1100 1110 1100 */ + {&upd7810_device::illegal2, 2,10,10,L0|L1}, /* ed: 0100 1100 1110 1101 */ + {&upd7810_device::illegal2, 2,10,10,L0|L1}, /* ee: 0100 1100 1110 1110 */ + {&upd7810_device::illegal2, 2,10,10,L0|L1}, /* ef: 0100 1100 1110 1111 */ + + {&upd7810_device::illegal2, 2,10,10,L0|L1}, /* f0: 0100 1100 1111 0000 */ + {&upd7810_device::illegal2, 2,10,10,L0|L1}, /* f1: 0100 1100 1111 0001 */ + {&upd7810_device::illegal2, 2,10,10,L0|L1}, /* f2: 0100 1100 1111 0010 */ + {&upd7810_device::illegal2, 2,10,10,L0|L1}, /* f3: 0100 1100 1111 0011 */ + {&upd7810_device::illegal2, 2,10,10,L0|L1}, /* f4: 0100 1100 1111 0100 */ + {&upd7810_device::illegal2, 2,10,10,L0|L1}, /* f5: 0100 1100 1111 0101 */ + {&upd7810_device::illegal2, 2,10,10,L0|L1}, /* f6: 0100 1100 1111 0110 */ + {&upd7810_device::illegal2, 2,10,10,L0|L1}, /* f7: 0100 1100 1111 0111 */ + {&upd7810_device::illegal2, 2,10,10,L0|L1}, /* f8: 0100 1100 1111 1000 */ + {&upd7810_device::illegal2, 2,10,10,L0|L1}, /* f9: 0100 1100 1111 1001 */ + {&upd7810_device::illegal2, 2,10,10,L0|L1}, /* fa: 0100 1100 1111 1010 */ + {&upd7810_device::illegal2, 2,10,10,L0|L1}, /* fb: 0100 1100 1111 1011 */ + {&upd7810_device::illegal2, 2,10,10,L0|L1}, /* fc: 0100 1100 1111 1100 */ + {&upd7810_device::illegal2, 2,10,10,L0|L1}, /* fd: 0100 1100 1111 1101 */ + {&upd7810_device::illegal2, 2,10,10,L0|L1}, /* fe: 0100 1100 1111 1110 */ + {&upd7810_device::illegal2, 2,10,10,L0|L1}, /* ff: 0100 1100 1111 1111 */ +}; + +/* prefix 4D */ +const struct upd7810_device::opcode_s upd7810_device::s_op4D[256] = +{ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 00: 0100 1101 0000 0000 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 01: 0100 1101 0000 0001 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 02: 0100 1101 0000 0010 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 03: 0100 1101 0000 0011 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 04: 0100 1101 0000 0100 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 05: 0100 1101 0000 0101 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 06: 0100 1101 0000 0110 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 07: 0100 1101 0000 0111 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 08: 0100 1101 0000 1000 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 09: 0100 1101 0000 1001 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 0a: 0100 1101 0000 1010 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 0b: 0100 1101 0000 1011 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 0c: 0100 1101 0000 1100 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 0d: 0100 1101 0000 1101 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 0e: 0100 1101 0000 1110 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 0f: 0100 1101 0000 1111 */ + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 10: 0100 1101 0001 0000 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 11: 0100 1101 0001 0001 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 12: 0100 1101 0001 0010 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 13: 0100 1101 0001 0011 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 14: 0100 1101 0001 0100 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 15: 0100 1101 0001 0101 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 16: 0100 1101 0001 0110 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 17: 0100 1101 0001 0111 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 18: 0100 1101 0001 1000 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 19: 0100 1101 0001 1001 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 1a: 0100 1101 0001 1010 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 1b: 0100 1101 0001 1011 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 1c: 0100 1101 0001 1100 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 1d: 0100 1101 0001 1101 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 1e: 0100 1101 0001 1110 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 1f: 0100 1101 0001 1111 */ + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 20: 0100 1101 0010 0000 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 21: 0100 1101 0010 0001 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 22: 0100 1101 0010 0010 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 23: 0100 1101 0010 0011 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 24: 0100 1101 0010 0100 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 25: 0100 1101 0010 0101 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 26: 0100 1101 0010 0110 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 27: 0100 1101 0010 0111 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 28: 0100 1101 0010 1000 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 29: 0100 1101 0010 1001 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 2a: 0100 1101 0010 1010 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 2b: 0100 1101 0010 1011 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 2c: 0100 1101 0010 1100 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 2d: 0100 1101 0010 1101 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 2e: 0100 1101 0010 1110 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 2f: 0100 1101 0010 1111 */ + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 30: 0100 1101 0011 0000 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 31: 0100 1101 0011 0001 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 32: 0100 1101 0011 0010 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 33: 0100 1101 0011 0011 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 34: 0100 1101 0011 0100 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 35: 0100 1101 0011 0101 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 36: 0100 1101 0011 0110 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 37: 0100 1101 0011 0111 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 38: 0100 1101 0011 1000 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 39: 0100 1101 0011 1001 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 3a: 0100 1101 0011 1010 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 3b: 0100 1101 0011 1011 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 3c: 0100 1101 0011 1100 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 3d: 0100 1101 0011 1101 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 3e: 0100 1101 0011 1110 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 3f: 0100 1101 0011 1111 */ + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 40: 0100 1101 0100 0000 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 41: 0100 1101 0100 0001 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 42: 0100 1101 0100 0010 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 43: 0100 1101 0100 0011 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 44: 0100 1101 0100 0100 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 45: 0100 1101 0100 0101 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 46: 0100 1101 0100 0110 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 47: 0100 1101 0100 0111 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 48: 0100 1101 0100 1000 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 49: 0100 1101 0100 1001 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 4a: 0100 1101 0100 1010 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 4b: 0100 1101 0100 1011 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 4c: 0100 1101 0100 1100 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 4d: 0100 1101 0100 1101 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 4e: 0100 1101 0100 1110 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 4f: 0100 1101 0100 1111 */ + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 50: 0100 1101 0101 0000 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 51: 0100 1101 0101 0001 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 52: 0100 1101 0101 0010 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 53: 0100 1101 0101 0011 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 54: 0100 1101 0101 0100 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 55: 0100 1101 0101 0101 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 56: 0100 1101 0101 0110 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 57: 0100 1101 0101 0111 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 58: 0100 1101 0101 1000 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 59: 0100 1101 0101 1001 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 5a: 0100 1101 0101 1010 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 5b: 0100 1101 0101 1011 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 5c: 0100 1101 0101 1100 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 5d: 0100 1101 0101 1101 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 5e: 0100 1101 0101 1110 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 5f: 0100 1101 0101 1111 */ + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 60: 0100 1101 0110 0000 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 61: 0100 1101 0110 0001 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 62: 0100 1101 0110 0010 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 63: 0100 1101 0110 0011 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 64: 0100 1101 0110 0100 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 65: 0100 1101 0110 0101 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 66: 0100 1101 0110 0110 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 67: 0100 1101 0110 0111 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 68: 0100 1101 0110 1000 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 69: 0100 1101 0110 1001 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 6a: 0100 1101 0110 1010 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 6b: 0100 1101 0110 1011 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 6c: 0100 1101 0110 1100 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 6d: 0100 1101 0110 1101 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 6e: 0100 1101 0110 1110 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 6f: 0100 1101 0110 1111 */ + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 70: 0100 1101 0111 0000 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 71: 0100 1101 0111 0001 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 72: 0100 1101 0111 0010 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 73: 0100 1101 0111 0011 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 74: 0100 1101 0111 0100 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 75: 0100 1101 0111 0101 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 76: 0100 1101 0111 0110 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 77: 0100 1101 0111 0111 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 78: 0100 1101 0111 1000 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 79: 0100 1101 0111 1001 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 7a: 0100 1101 0111 1010 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 7b: 0100 1101 0111 1011 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 7c: 0100 1101 0111 1100 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 7d: 0100 1101 0111 1101 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 7e: 0100 1101 0111 1110 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 7f: 0100 1101 0111 1111 */ + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 80: 0100 1101 1000 0000 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 81: 0100 1101 1000 0001 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 82: 0100 1101 1000 0010 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 83: 0100 1101 1000 0011 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 84: 0100 1101 1000 0100 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 85: 0100 1101 1000 0101 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 86: 0100 1101 1000 0110 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 87: 0100 1101 1000 0111 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 88: 0100 1101 1000 1000 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 89: 0100 1101 1000 1001 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 8a: 0100 1101 1000 1010 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 8b: 0100 1101 1000 1011 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 8c: 0100 1101 1000 1100 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 8d: 0100 1101 1000 1101 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 8e: 0100 1101 1000 1110 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 8f: 0100 1101 1000 1111 */ + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 90: 0100 1101 1001 0000 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 91: 0100 1101 1001 0001 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 92: 0100 1101 1001 0010 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 93: 0100 1101 1001 0011 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 94: 0100 1101 1001 0100 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 95: 0100 1101 1001 0101 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 96: 0100 1101 1001 0110 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 97: 0100 1101 1001 0111 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 98: 0100 1101 1001 1000 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 99: 0100 1101 1001 1001 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 9a: 0100 1101 1001 1010 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 9b: 0100 1101 1001 1011 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 9c: 0100 1101 1001 1100 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 9d: 0100 1101 1001 1101 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 9e: 0100 1101 1001 1110 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 9f: 0100 1101 1001 1111 */ + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* a0: 0100 1101 1010 0000 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* a1: 0100 1101 1010 0001 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* a2: 0100 1101 1010 0010 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* a3: 0100 1101 1010 0011 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* a4: 0100 1101 1010 0100 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* a5: 0100 1101 1010 0101 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* a6: 0100 1101 1010 0110 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* a7: 0100 1101 1010 0111 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* a8: 0100 1101 1010 1000 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* a9: 0100 1101 1010 1001 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* aa: 0100 1101 1010 1010 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* ab: 0100 1101 1010 1011 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* ac: 0100 1101 1010 1100 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* ad: 0100 1101 1010 1101 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* ae: 0100 1101 1010 1110 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* af: 0100 1101 1010 1111 */ + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* b0: 0100 1101 1011 0000 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* b1: 0100 1101 1011 0001 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* b2: 0100 1101 1011 0010 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* b3: 0100 1101 1011 0011 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* b4: 0100 1101 1011 0100 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* b5: 0100 1101 1011 0101 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* b6: 0100 1101 1011 0110 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* b7: 0100 1101 1011 0111 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* b8: 0100 1101 1011 1000 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* b9: 0100 1101 1011 1001 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* ba: 0100 1101 1011 1010 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* bb: 0100 1101 1011 1011 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* bc: 0100 1101 1011 1100 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* bd: 0100 1101 1011 1101 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* be: 0100 1101 1011 1110 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* bf: 0100 1101 1011 1111 */ + + {&upd7810_device::MOV_PA_A, 2,10,10,L0|L1}, /* c0: 0100 1101 1100 0000 */ + {&upd7810_device::MOV_PB_A, 2,10,10,L0|L1}, /* c1: 0100 1101 1100 0001 */ + {&upd7810_device::MOV_PC_A, 2,10,10,L0|L1}, /* c2: 0100 1101 1100 0010 */ + {&upd7810_device::MOV_PD_A, 2,10,10,L0|L1}, /* c3: 0100 1101 1100 0011 */ + {&upd7810_device::illegal2, 2,10,10,L0|L1}, /* c4: 0100 1101 1100 0100 */ + {&upd7810_device::MOV_PF_A, 2,10,10,L0|L1}, /* c5: 0100 1101 1100 0101 */ + {&upd7810_device::MOV_MKH_A, 2,10,10,L0|L1}, /* c6: 0100 1101 1100 0110 */ + {&upd7810_device::MOV_MKL_A, 2,10,10,L0|L1}, /* c7: 0100 1101 1100 0111 */ + {&upd7810_device::MOV_ANM_A, 2,10,10,L0|L1}, /* c8: 0100 1101 1100 1000 */ + {&upd7810_device::MOV_SMH_A, 2,10,10,L0|L1}, /* c9: 0100 1101 1100 1001 */ + {&upd7810_device::MOV_SML_A, 2,10,10,L0|L1}, /* ca: 0100 1101 1100 1010 */ + {&upd7810_device::MOV_EOM_A, 2,10,10,L0|L1}, /* cb: 0100 1101 1100 1011 */ + {&upd7810_device::MOV_ETMM_A, 2,10,10,L0|L1}, /* cc: 0100 1101 1100 1100 */ + {&upd7810_device::MOV_TMM_A, 2,10,10,L0|L1}, /* cd: 0100 1101 1100 1101 */ + {&upd7810_device::illegal2, 2,10,10,L0|L1}, /* ce: 0100 1101 1100 1110 */ + {&upd7810_device::illegal2, 2,10,10,L0|L1}, /* cf: 0100 1101 1100 1111 */ + + {&upd7810_device::MOV_MM_A, 2,10,10,L0|L1}, /* d0: 0100 1101 1101 0000 */ + {&upd7810_device::MOV_MCC_A, 2,10,10,L0|L1}, /* d1: 0100 1101 1101 0001 */ + {&upd7810_device::MOV_MA_A, 2,10,10,L0|L1}, /* d2: 0100 1101 1101 0010 */ + {&upd7810_device::MOV_MB_A, 2,10,10,L0|L1}, /* d3: 0100 1101 1101 0011 */ + {&upd7810_device::MOV_MC_A, 2,10,10,L0|L1}, /* d4: 0100 1101 1101 0100 */ + {&upd7810_device::illegal2, 2,10,10,L0|L1}, /* d5: 0100 1101 1101 0101 */ + {&upd7810_device::illegal2, 2,10,10,L0|L1}, /* d6: 0100 1101 1101 0110 */ + {&upd7810_device::MOV_MF_A, 2,10,10,L0|L1}, /* d7: 0100 1101 1101 0111 */ + {&upd7810_device::MOV_TXB_A, 2,10,10,L0|L1}, /* d8: 0100 1101 1101 1000 */ + {&upd7810_device::illegal2, 2,10,10,L0|L1}, /* d9: 0100 1101 1101 1001 */ + {&upd7810_device::MOV_TM0_A, 2,10,10,L0|L1}, /* da: 0100 1101 1101 1010 */ + {&upd7810_device::MOV_TM1_A, 2,10,10,L0|L1}, /* db: 0100 1101 1101 1011 */ + {&upd7810_device::illegal2, 2,10,10,L0|L1}, /* dc: 0100 1101 1101 1100 */ + {&upd7810_device::illegal2, 2,10,10,L0|L1}, /* dd: 0100 1101 1101 1101 */ + {&upd7810_device::illegal2, 2,10,10,L0|L1}, /* de: 0100 1101 1101 1110 */ + {&upd7810_device::illegal2, 2,10,10,L0|L1}, /* df: 0100 1101 1101 1111 */ + + {&upd7810_device::illegal2, 2,10,10,L0|L1}, /* e0: 0100 1101 1110 0000 */ + {&upd7810_device::illegal2, 2,10,10,L0|L1}, /* e1: 0100 1101 1110 0001 */ + {&upd7810_device::illegal2, 2,10,10,L0|L1}, /* e2: 0100 1101 1110 0010 */ + {&upd7810_device::illegal2, 2,10,10,L0|L1}, /* e3: 0100 1101 1110 0011 */ + {&upd7810_device::illegal2, 2,10,10,L0|L1}, /* e4: 0100 1101 1110 0100 */ + {&upd7810_device::illegal2, 2,10,10,L0|L1}, /* e5: 0100 1101 1110 0101 */ + {&upd7810_device::illegal2, 2,10,10,L0|L1}, /* e6: 0100 1101 1110 0110 */ + {&upd7810_device::illegal2, 2,10,10,L0|L1}, /* e7: 0100 1101 1110 0111 */ + {&upd7810_device::MOV_ZCM_A, 2,10,10,L0|L1}, /* e8: 0100 1101 1110 1000 */ + {&upd7810_device::illegal2, 2,10,10,L0|L1}, /* e9: 0100 1101 1110 1001 */ + {&upd7810_device::illegal2, 2,10,10,L0|L1}, /* ea: 0100 1101 1110 1010 */ + {&upd7810_device::illegal2, 2,10,10,L0|L1}, /* eb: 0100 1101 1110 1011 */ + {&upd7810_device::illegal2, 2,10,10,L0|L1}, /* ec: 0100 1101 1110 1100 */ + {&upd7810_device::illegal2, 2,10,10,L0|L1}, /* ed: 0100 1101 1110 1101 */ + {&upd7810_device::illegal2, 2,10,10,L0|L1}, /* ee: 0100 1101 1110 1110 */ + {&upd7810_device::illegal2, 2,10,10,L0|L1}, /* ef: 0100 1101 1110 1111 */ + + {&upd7810_device::illegal2, 2,10,10,L0|L1}, /* f0: 0100 1101 1111 0000 */ + {&upd7810_device::illegal2, 2,10,10,L0|L1}, /* f1: 0100 1101 1111 0001 */ + {&upd7810_device::illegal2, 2,10,10,L0|L1}, /* f2: 0100 1101 1111 0010 */ + {&upd7810_device::illegal2, 2,10,10,L0|L1}, /* f3: 0100 1101 1111 0011 */ + {&upd7810_device::illegal2, 2,10,10,L0|L1}, /* f4: 0100 1101 1111 0100 */ + {&upd7810_device::illegal2, 2,10,10,L0|L1}, /* f5: 0100 1101 1111 0101 */ + {&upd7810_device::illegal2, 2,10,10,L0|L1}, /* f6: 0100 1101 1111 0110 */ + {&upd7810_device::illegal2, 2,10,10,L0|L1}, /* f7: 0100 1101 1111 0111 */ + {&upd7810_device::illegal2, 2,10,10,L0|L1}, /* f8: 0100 1101 1111 1000 */ + {&upd7810_device::illegal2, 2,10,10,L0|L1}, /* f9: 0100 1101 1111 1001 */ + {&upd7810_device::illegal2, 2,10,10,L0|L1}, /* fa: 0100 1101 1111 1010 */ + {&upd7810_device::illegal2, 2,10,10,L0|L1}, /* fb: 0100 1101 1111 1011 */ + {&upd7810_device::illegal2, 2,10,10,L0|L1}, /* fc: 0100 1101 1111 1100 */ + {&upd7810_device::illegal2, 2,10,10,L0|L1}, /* fd: 0100 1101 1111 1101 */ + {&upd7810_device::illegal2, 2,10,10,L0|L1}, /* fe: 0100 1101 1111 1110 */ + {&upd7810_device::illegal2, 2,10,10,L0|L1} /* ff: 0100 1101 1111 1111 */ +}; + +/* prefix 60 */ +const struct upd7810_device::opcode_s upd7810_device::s_op60[256] = +{ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 00: 0110 0000 0000 0000 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 01: 0110 0000 0000 0001 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 02: 0110 0000 0000 0010 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 03: 0110 0000 0000 0011 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 04: 0110 0000 0000 0100 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 05: 0110 0000 0000 0101 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 06: 0110 0000 0000 0110 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 07: 0110 0000 0000 0111 */ + {&upd7810_device::ANA_V_A, 2, 8, 8,L0|L1}, /* 08: 0110 0000 0000 1000 */ + {&upd7810_device::ANA_A_A, 2, 8, 8,L0|L1}, /* 09: 0110 0000 0000 1001 */ + {&upd7810_device::ANA_B_A, 2, 8, 8,L0|L1}, /* 0a: 0110 0000 0000 1010 */ + {&upd7810_device::ANA_C_A, 2, 8, 8,L0|L1}, /* 0b: 0110 0000 0000 1011 */ + {&upd7810_device::ANA_D_A, 2, 8, 8,L0|L1}, /* 0c: 0110 0000 0000 1100 */ + {&upd7810_device::ANA_E_A, 2, 8, 8,L0|L1}, /* 0d: 0110 0000 0000 1101 */ + {&upd7810_device::ANA_H_A, 2, 8, 8,L0|L1}, /* 0e: 0110 0000 0000 1110 */ + {&upd7810_device::ANA_L_A, 2, 8, 8,L0|L1}, /* 0f: 0110 0000 0000 1111 */ + + {&upd7810_device::XRA_V_A, 2, 8, 8,L0|L1}, /* 10: 0110 0000 0001 0000 */ + {&upd7810_device::XRA_A_A, 2, 8, 8,L0|L1}, /* 11: 0110 0000 0001 0001 */ + {&upd7810_device::XRA_B_A, 2, 8, 8,L0|L1}, /* 12: 0110 0000 0001 0010 */ + {&upd7810_device::XRA_C_A, 2, 8, 8,L0|L1}, /* 13: 0110 0000 0001 0011 */ + {&upd7810_device::XRA_D_A, 2, 8, 8,L0|L1}, /* 14: 0110 0000 0001 0100 */ + {&upd7810_device::XRA_E_A, 2, 8, 8,L0|L1}, /* 15: 0110 0000 0001 0101 */ + {&upd7810_device::XRA_H_A, 2, 8, 8,L0|L1}, /* 16: 0110 0000 0001 0110 */ + {&upd7810_device::XRA_L_A, 2, 8, 8,L0|L1}, /* 17: 0110 0000 0001 0111 */ + {&upd7810_device::ORA_V_A, 2, 8, 8,L0|L1}, /* 18: 0110 0000 0001 1000 */ + {&upd7810_device::ORA_A_A, 2, 8, 8,L0|L1}, /* 19: 0110 0000 0001 1001 */ + {&upd7810_device::ORA_B_A, 2, 8, 8,L0|L1}, /* 1a: 0110 0000 0001 1010 */ + {&upd7810_device::ORA_C_A, 2, 8, 8,L0|L1}, /* 1b: 0110 0000 0001 1011 */ + {&upd7810_device::ORA_D_A, 2, 8, 8,L0|L1}, /* 1c: 0110 0000 0001 1100 */ + {&upd7810_device::ORA_E_A, 2, 8, 8,L0|L1}, /* 1d: 0110 0000 0001 1101 */ + {&upd7810_device::ORA_H_A, 2, 8, 8,L0|L1}, /* 1e: 0110 0000 0001 1110 */ + {&upd7810_device::ORA_L_A, 2, 8, 8,L0|L1}, /* 1f: 0110 0000 0001 1111 */ + + {&upd7810_device::ADDNC_V_A, 2, 8, 8,L0|L1}, /* 20: 0110 0000 0010 0000 */ + {&upd7810_device::ADDNC_A_A, 2, 8, 8,L0|L1}, /* 21: 0110 0000 0010 0001 */ + {&upd7810_device::ADDNC_B_A, 2, 8, 8,L0|L1}, /* 22: 0110 0000 0010 0010 */ + {&upd7810_device::ADDNC_C_A, 2, 8, 8,L0|L1}, /* 23: 0110 0000 0010 0011 */ + {&upd7810_device::ADDNC_D_A, 2, 8, 8,L0|L1}, /* 24: 0110 0000 0010 0100 */ + {&upd7810_device::ADDNC_E_A, 2, 8, 8,L0|L1}, /* 25: 0110 0000 0010 0101 */ + {&upd7810_device::ADDNC_H_A, 2, 8, 8,L0|L1}, /* 26: 0110 0000 0010 0110 */ + {&upd7810_device::ADDNC_L_A, 2, 8, 8,L0|L1}, /* 27: 0110 0000 0010 0111 */ + {&upd7810_device::GTA_V_A, 2, 8, 8,L0|L1}, /* 28: 0110 0000 0010 1000 */ + {&upd7810_device::GTA_A_A, 2, 8, 8,L0|L1}, /* 29: 0110 0000 0010 1001 */ + {&upd7810_device::GTA_B_A, 2, 8, 8,L0|L1}, /* 2a: 0110 0000 0010 1010 */ + {&upd7810_device::GTA_C_A, 2, 8, 8,L0|L1}, /* 2b: 0110 0000 0010 1011 */ + {&upd7810_device::GTA_D_A, 2, 8, 8,L0|L1}, /* 2c: 0110 0000 0010 1100 */ + {&upd7810_device::GTA_E_A, 2, 8, 8,L0|L1}, /* 2d: 0110 0000 0010 1101 */ + {&upd7810_device::GTA_H_A, 2, 8, 8,L0|L1}, /* 2e: 0110 0000 0010 1110 */ + {&upd7810_device::GTA_L_A, 2, 8, 8,L0|L1}, /* 2f: 0110 0000 0010 1111 */ + + {&upd7810_device::SUBNB_V_A, 2, 8, 8,L0|L1}, /* 30: 0110 0000 0011 0000 */ + {&upd7810_device::SUBNB_A_A, 2, 8, 8,L0|L1}, /* 31: 0110 0000 0011 0001 */ + {&upd7810_device::SUBNB_B_A, 2, 8, 8,L0|L1}, /* 32: 0110 0000 0011 0010 */ + {&upd7810_device::SUBNB_C_A, 2, 8, 8,L0|L1}, /* 33: 0110 0000 0011 0011 */ + {&upd7810_device::SUBNB_D_A, 2, 8, 8,L0|L1}, /* 34: 0110 0000 0011 0100 */ + {&upd7810_device::SUBNB_E_A, 2, 8, 8,L0|L1}, /* 35: 0110 0000 0011 0101 */ + {&upd7810_device::SUBNB_H_A, 2, 8, 8,L0|L1}, /* 36: 0110 0000 0011 0110 */ + {&upd7810_device::SUBNB_L_A, 2, 8, 8,L0|L1}, /* 37: 0110 0000 0011 0111 */ + {&upd7810_device::LTA_V_A, 2, 8, 8,L0|L1}, /* 38: 0110 0000 0011 1000 */ + {&upd7810_device::LTA_A_A, 2, 8, 8,L0|L1}, /* 39: 0110 0000 0011 1001 */ + {&upd7810_device::LTA_B_A, 2, 8, 8,L0|L1}, /* 3a: 0110 0000 0011 1010 */ + {&upd7810_device::LTA_C_A, 2, 8, 8,L0|L1}, /* 3b: 0110 0000 0011 1011 */ + {&upd7810_device::LTA_D_A, 2, 8, 8,L0|L1}, /* 3c: 0110 0000 0011 1100 */ + {&upd7810_device::LTA_E_A, 2, 8, 8,L0|L1}, /* 3d: 0110 0000 0011 1101 */ + {&upd7810_device::LTA_H_A, 2, 8, 8,L0|L1}, /* 3e: 0110 0000 0011 1110 */ + {&upd7810_device::LTA_L_A, 2, 8, 8,L0|L1}, /* 3f: 0110 0000 0011 1111 */ + + {&upd7810_device::ADD_V_A, 2, 8, 8,L0|L1}, /* 40: 0110 0000 0100 0000 */ + {&upd7810_device::ADD_A_A, 2, 8, 8,L0|L1}, /* 41: 0110 0000 0100 0001 */ + {&upd7810_device::ADD_B_A, 2, 8, 8,L0|L1}, /* 42: 0110 0000 0100 0010 */ + {&upd7810_device::ADD_C_A, 2, 8, 8,L0|L1}, /* 43: 0110 0000 0100 0011 */ + {&upd7810_device::ADD_D_A, 2, 8, 8,L0|L1}, /* 44: 0110 0000 0100 0100 */ + {&upd7810_device::ADD_E_A, 2, 8, 8,L0|L1}, /* 45: 0110 0000 0100 0101 */ + {&upd7810_device::ADD_H_A, 2, 8, 8,L0|L1}, /* 46: 0110 0000 0100 0110 */ + {&upd7810_device::ADD_L_A, 2, 8, 8,L0|L1}, /* 47: 0110 0000 0100 0111 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 48: 0110 0000 0100 1000 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 49: 0110 0000 0100 1001 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 4a: 0110 0000 0100 1010 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 4b: 0110 0000 0100 1011 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 4c: 0110 0000 0100 1100 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 4d: 0110 0000 0100 1101 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 4e: 0110 0000 0100 1110 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 4f: 0110 0000 0100 1111 */ + + {&upd7810_device::ADC_V_A, 2, 8, 8,L0|L1}, /* 50: 0110 0000 0101 0000 */ + {&upd7810_device::ADC_A_A, 2, 8, 8,L0|L1}, /* 51: 0110 0000 0101 0001 */ + {&upd7810_device::ADC_B_A, 2, 8, 8,L0|L1}, /* 52: 0110 0000 0101 0010 */ + {&upd7810_device::ADC_C_A, 2, 8, 8,L0|L1}, /* 53: 0110 0000 0101 0011 */ + {&upd7810_device::ADC_D_A, 2, 8, 8,L0|L1}, /* 54: 0110 0000 0101 0100 */ + {&upd7810_device::ADC_E_A, 2, 8, 8,L0|L1}, /* 55: 0110 0000 0101 0101 */ + {&upd7810_device::ADC_H_A, 2, 8, 8,L0|L1}, /* 56: 0110 0000 0101 0110 */ + {&upd7810_device::ADC_L_A, 2, 8, 8,L0|L1}, /* 57: 0110 0000 0101 0111 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 58: 0110 0000 0101 1000 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 59: 0110 0000 0101 1001 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 5a: 0110 0000 0101 1010 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 5b: 0110 0000 0101 1011 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 5c: 0110 0000 0101 1100 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 5d: 0110 0000 0101 1101 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 5e: 0110 0000 0101 1110 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 5f: 0110 0000 0101 1111 */ + + {&upd7810_device::SUB_V_A, 2, 8, 8,L0|L1}, /* 60: 0110 0000 0110 0000 */ + {&upd7810_device::SUB_A_A, 2, 8, 8,L0|L1}, /* 61: 0110 0000 0110 0001 */ + {&upd7810_device::SUB_B_A, 2, 8, 8,L0|L1}, /* 62: 0110 0000 0110 0010 */ + {&upd7810_device::SUB_C_A, 2, 8, 8,L0|L1}, /* 63: 0110 0000 0110 0011 */ + {&upd7810_device::SUB_D_A, 2, 8, 8,L0|L1}, /* 64: 0110 0000 0110 0100 */ + {&upd7810_device::SUB_E_A, 2, 8, 8,L0|L1}, /* 65: 0110 0000 0110 0101 */ + {&upd7810_device::SUB_H_A, 2, 8, 8,L0|L1}, /* 66: 0110 0000 0110 0110 */ + {&upd7810_device::SUB_L_A, 2, 8, 8,L0|L1}, /* 67: 0110 0000 0110 0111 */ + {&upd7810_device::NEA_V_A, 2, 8, 8,L0|L1}, /* 68: 0110 0000 0110 1000 */ + {&upd7810_device::NEA_A_A, 2, 8, 8,L0|L1}, /* 69: 0110 0000 0110 1001 */ + {&upd7810_device::NEA_B_A, 2, 8, 8,L0|L1}, /* 6a: 0110 0000 0110 1010 */ + {&upd7810_device::NEA_C_A, 2, 8, 8,L0|L1}, /* 6b: 0110 0000 0110 1011 */ + {&upd7810_device::NEA_D_A, 2, 8, 8,L0|L1}, /* 6c: 0110 0000 0110 1100 */ + {&upd7810_device::NEA_E_A, 2, 8, 8,L0|L1}, /* 6d: 0110 0000 0110 1101 */ + {&upd7810_device::NEA_H_A, 2, 8, 8,L0|L1}, /* 6e: 0110 0000 0110 1110 */ + {&upd7810_device::NEA_L_A, 2, 8, 8,L0|L1}, /* 6f: 0110 0000 0110 1111 */ + + {&upd7810_device::SBB_V_A, 2, 8, 8,L0|L1}, /* 70: 0110 0000 0111 0000 */ + {&upd7810_device::SBB_A_A, 2, 8, 8,L0|L1}, /* 71: 0110 0000 0111 0001 */ + {&upd7810_device::SBB_B_A, 2, 8, 8,L0|L1}, /* 72: 0110 0000 0111 0010 */ + {&upd7810_device::SBB_C_A, 2, 8, 8,L0|L1}, /* 73: 0110 0000 0111 0011 */ + {&upd7810_device::SBB_D_A, 2, 8, 8,L0|L1}, /* 74: 0110 0000 0111 0100 */ + {&upd7810_device::SBB_E_A, 2, 8, 8,L0|L1}, /* 75: 0110 0000 0111 0101 */ + {&upd7810_device::SBB_H_A, 2, 8, 8,L0|L1}, /* 76: 0110 0000 0111 0110 */ + {&upd7810_device::SBB_L_A, 2, 8, 8,L0|L1}, /* 77: 0110 0000 0111 0111 */ + {&upd7810_device::EQA_V_A, 2, 8, 8,L0|L1}, /* 78: 0110 0000 0111 1000 */ + {&upd7810_device::EQA_A_A, 2, 8, 8,L0|L1}, /* 79: 0110 0000 0111 1001 */ + {&upd7810_device::EQA_B_A, 2, 8, 8,L0|L1}, /* 7a: 0110 0000 0111 1010 */ + {&upd7810_device::EQA_C_A, 2, 8, 8,L0|L1}, /* 7b: 0110 0000 0111 1011 */ + {&upd7810_device::EQA_D_A, 2, 8, 8,L0|L1}, /* 7c: 0110 0000 0111 1100 */ + {&upd7810_device::EQA_E_A, 2, 8, 8,L0|L1}, /* 7d: 0110 0000 0111 1101 */ + {&upd7810_device::EQA_H_A, 2, 8, 8,L0|L1}, /* 7e: 0110 0000 0111 1110 */ + {&upd7810_device::EQA_L_A, 2, 8, 8,L0|L1}, /* 7f: 0110 0000 0111 1111 */ + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 80: 0110 0000 1000 0000 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 81: 0110 0000 1000 0001 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 82: 0110 0000 1000 0010 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 83: 0110 0000 1000 0011 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 84: 0110 0000 1000 0100 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 85: 0110 0000 1000 0101 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 86: 0110 0000 1000 0110 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 87: 0110 0000 1000 0111 */ + {&upd7810_device::ANA_A_V, 2, 8, 8,L0|L1}, /* 88: 0110 0000 1000 1000 */ + {&upd7810_device::ANA_A_A, 2, 8, 8,L0|L1}, /* 89: 0110 0000 1000 1001 */ + {&upd7810_device::ANA_A_B, 2, 8, 8,L0|L1}, /* 8a: 0110 0000 1000 1010 */ + {&upd7810_device::ANA_A_C, 2, 8, 8,L0|L1}, /* 8b: 0110 0000 1000 1011 */ + {&upd7810_device::ANA_A_D, 2, 8, 8,L0|L1}, /* 8c: 0110 0000 1000 1100 */ + {&upd7810_device::ANA_A_E, 2, 8, 8,L0|L1}, /* 8d: 0110 0000 1000 1101 */ + {&upd7810_device::ANA_A_H, 2, 8, 8,L0|L1}, /* 8e: 0110 0000 1000 1110 */ + {&upd7810_device::ANA_A_L, 2, 8, 8,L0|L1}, /* 8f: 0110 0000 1000 1111 */ + + {&upd7810_device::XRA_A_V, 2, 8, 8,L0|L1}, /* 90: 0110 0000 1001 0000 */ + {&upd7810_device::XRA_A_A, 2, 8, 8,L0|L1}, /* 91: 0110 0000 1001 0001 */ + {&upd7810_device::XRA_A_B, 2, 8, 8,L0|L1}, /* 92: 0110 0000 1001 0010 */ + {&upd7810_device::XRA_A_C, 2, 8, 8,L0|L1}, /* 93: 0110 0000 1001 0011 */ + {&upd7810_device::XRA_A_D, 2, 8, 8,L0|L1}, /* 94: 0110 0000 1001 0100 */ + {&upd7810_device::XRA_A_E, 2, 8, 8,L0|L1}, /* 95: 0110 0000 1001 0101 */ + {&upd7810_device::XRA_A_H, 2, 8, 8,L0|L1}, /* 96: 0110 0000 1001 0110 */ + {&upd7810_device::XRA_A_L, 2, 8, 8,L0|L1}, /* 97: 0110 0000 1001 0111 */ + {&upd7810_device::ORA_A_V, 2, 8, 8,L0|L1}, /* 98: 0110 0000 1001 1000 */ + {&upd7810_device::ORA_A_A, 2, 8, 8,L0|L1}, /* 99: 0110 0000 1001 1001 */ + {&upd7810_device::ORA_A_B, 2, 8, 8,L0|L1}, /* 9a: 0110 0000 1001 1010 */ + {&upd7810_device::ORA_A_C, 2, 8, 8,L0|L1}, /* 9b: 0110 0000 1001 1011 */ + {&upd7810_device::ORA_A_D, 2, 8, 8,L0|L1}, /* 9c: 0110 0000 1001 1100 */ + {&upd7810_device::ORA_A_E, 2, 8, 8,L0|L1}, /* 9d: 0110 0000 1001 1101 */ + {&upd7810_device::ORA_A_H, 2, 8, 8,L0|L1}, /* 9e: 0110 0000 1001 1110 */ + {&upd7810_device::ORA_A_L, 2, 8, 8,L0|L1}, /* 9f: 0110 0000 1001 1111 */ + + {&upd7810_device::ADDNC_A_V, 2, 8, 8,L0|L1}, /* a0: 0110 0000 1010 0000 */ + {&upd7810_device::ADDNC_A_A, 2, 8, 8,L0|L1}, /* a1: 0110 0000 1010 0001 */ + {&upd7810_device::ADDNC_A_B, 2, 8, 8,L0|L1}, /* a2: 0110 0000 1010 0010 */ + {&upd7810_device::ADDNC_A_C, 2, 8, 8,L0|L1}, /* a3: 0110 0000 1010 0011 */ + {&upd7810_device::ADDNC_A_D, 2, 8, 8,L0|L1}, /* a4: 0110 0000 1010 0100 */ + {&upd7810_device::ADDNC_A_E, 2, 8, 8,L0|L1}, /* a5: 0110 0000 1010 0101 */ + {&upd7810_device::ADDNC_A_H, 2, 8, 8,L0|L1}, /* a6: 0110 0000 1010 0110 */ + {&upd7810_device::ADDNC_A_L, 2, 8, 8,L0|L1}, /* a7: 0110 0000 1010 0111 */ + {&upd7810_device::GTA_A_V, 2, 8, 8,L0|L1}, /* a8: 0110 0000 1010 1000 */ + {&upd7810_device::GTA_A_A, 2, 8, 8,L0|L1}, /* a9: 0110 0000 1010 1001 */ + {&upd7810_device::GTA_A_B, 2, 8, 8,L0|L1}, /* aa: 0110 0000 1010 1010 */ + {&upd7810_device::GTA_A_C, 2, 8, 8,L0|L1}, /* ab: 0110 0000 1010 1011 */ + {&upd7810_device::GTA_A_D, 2, 8, 8,L0|L1}, /* ac: 0110 0000 1010 1100 */ + {&upd7810_device::GTA_A_E, 2, 8, 8,L0|L1}, /* ad: 0110 0000 1010 1101 */ + {&upd7810_device::GTA_A_H, 2, 8, 8,L0|L1}, /* ae: 0110 0000 1010 1110 */ + {&upd7810_device::GTA_A_L, 2, 8, 8,L0|L1}, /* af: 0110 0000 1010 1111 */ + + {&upd7810_device::SUBNB_A_V, 2, 8, 8,L0|L1}, /* b0: 0110 0000 1011 0000 */ + {&upd7810_device::SUBNB_A_A, 2, 8, 8,L0|L1}, /* b1: 0110 0000 1011 0001 */ + {&upd7810_device::SUBNB_A_B, 2, 8, 8,L0|L1}, /* b2: 0110 0000 1011 0010 */ + {&upd7810_device::SUBNB_A_C, 2, 8, 8,L0|L1}, /* b3: 0110 0000 1011 0011 */ + {&upd7810_device::SUBNB_A_D, 2, 8, 8,L0|L1}, /* b4: 0110 0000 1011 0100 */ + {&upd7810_device::SUBNB_A_E, 2, 8, 8,L0|L1}, /* b5: 0110 0000 1011 0101 */ + {&upd7810_device::SUBNB_A_H, 2, 8, 8,L0|L1}, /* b6: 0110 0000 1011 0110 */ + {&upd7810_device::SUBNB_A_L, 2, 8, 8,L0|L1}, /* b7: 0110 0000 1011 0111 */ + {&upd7810_device::LTA_A_V, 2, 8, 8,L0|L1}, /* b8: 0110 0000 1011 1000 */ + {&upd7810_device::LTA_A_A, 2, 8, 8,L0|L1}, /* b9: 0110 0000 1011 1001 */ + {&upd7810_device::LTA_A_B, 2, 8, 8,L0|L1}, /* ba: 0110 0000 1011 1010 */ + {&upd7810_device::LTA_A_C, 2, 8, 8,L0|L1}, /* bb: 0110 0000 1011 1011 */ + {&upd7810_device::LTA_A_D, 2, 8, 8,L0|L1}, /* bc: 0110 0000 1011 1100 */ + {&upd7810_device::LTA_A_E, 2, 8, 8,L0|L1}, /* bd: 0110 0000 1011 1101 */ + {&upd7810_device::LTA_A_H, 2, 8, 8,L0|L1}, /* be: 0110 0000 1011 1110 */ + {&upd7810_device::LTA_A_L, 2, 8, 8,L0|L1}, /* bf: 0110 0000 1011 1111 */ + + {&upd7810_device::ADD_A_V, 2, 8, 8,L0|L1}, /* c0: 0110 0000 1100 0000 */ + {&upd7810_device::ADD_A_A, 2, 8, 8,L0|L1}, /* c1: 0110 0000 1100 0001 */ + {&upd7810_device::ADD_A_B, 2, 8, 8,L0|L1}, /* c2: 0110 0000 1100 0010 */ + {&upd7810_device::ADD_A_C, 2, 8, 8,L0|L1}, /* c3: 0110 0000 1100 0011 */ + {&upd7810_device::ADD_A_D, 2, 8, 8,L0|L1}, /* c4: 0110 0000 1100 0100 */ + {&upd7810_device::ADD_A_E, 2, 8, 8,L0|L1}, /* c5: 0110 0000 1100 0101 */ + {&upd7810_device::ADD_A_H, 2, 8, 8,L0|L1}, /* c6: 0110 0000 1100 0110 */ + {&upd7810_device::ADD_A_L, 2, 8, 8,L0|L1}, /* c7: 0110 0000 1100 0111 */ + {&upd7810_device::ONA_A_V, 2, 8, 8,L0|L1}, /* c8: 0110 0000 1100 1000 */ + {&upd7810_device::ONA_A_A, 2, 8, 8,L0|L1}, /* c9: 0110 0000 1100 1001 */ + {&upd7810_device::ONA_A_B, 2, 8, 8,L0|L1}, /* ca: 0110 0000 1100 1010 */ + {&upd7810_device::ONA_A_C, 2, 8, 8,L0|L1}, /* cb: 0110 0000 1100 1011 */ + {&upd7810_device::ONA_A_D, 2, 8, 8,L0|L1}, /* cc: 0110 0000 1100 1100 */ + {&upd7810_device::ONA_A_E, 2, 8, 8,L0|L1}, /* cd: 0110 0000 1100 1101 */ + {&upd7810_device::ONA_A_H, 2, 8, 8,L0|L1}, /* ce: 0110 0000 1100 1110 */ + {&upd7810_device::ONA_A_L, 2, 8, 8,L0|L1}, /* cf: 0110 0000 1100 1111 */ + + {&upd7810_device::ADC_A_V, 2, 8, 8,L0|L1}, /* d0: 0110 0000 1101 0000 */ + {&upd7810_device::ADC_A_A, 2, 8, 8,L0|L1}, /* d1: 0110 0000 1101 0001 */ + {&upd7810_device::ADC_A_B, 2, 8, 8,L0|L1}, /* d2: 0110 0000 1101 0010 */ + {&upd7810_device::ADC_A_C, 2, 8, 8,L0|L1}, /* d3: 0110 0000 1101 0011 */ + {&upd7810_device::ADC_A_D, 2, 8, 8,L0|L1}, /* d4: 0110 0000 1101 0100 */ + {&upd7810_device::ADC_A_E, 2, 8, 8,L0|L1}, /* d5: 0110 0000 1101 0101 */ + {&upd7810_device::ADC_A_H, 2, 8, 8,L0|L1}, /* d6: 0110 0000 1101 0110 */ + {&upd7810_device::ADC_A_L, 2, 8, 8,L0|L1}, /* d7: 0110 0000 1101 0111 */ + {&upd7810_device::OFFA_A_V, 2, 8, 8,L0|L1}, /* d8: 0110 0000 1101 1000 */ + {&upd7810_device::OFFA_A_A, 2, 8, 8,L0|L1}, /* d9: 0110 0000 1101 1001 */ + {&upd7810_device::OFFA_A_B, 2, 8, 8,L0|L1}, /* da: 0110 0000 1101 1010 */ + {&upd7810_device::OFFA_A_C, 2, 8, 8,L0|L1}, /* db: 0110 0000 1101 1011 */ + {&upd7810_device::OFFA_A_D, 2, 8, 8,L0|L1}, /* dc: 0110 0000 1101 1100 */ + {&upd7810_device::OFFA_A_E, 2, 8, 8,L0|L1}, /* dd: 0110 0000 1101 1101 */ + {&upd7810_device::OFFA_A_H, 2, 8, 8,L0|L1}, /* de: 0110 0000 1101 1110 */ + {&upd7810_device::OFFA_A_L, 2, 8, 8,L0|L1}, /* df: 0110 0000 1101 1111 */ + + {&upd7810_device::SUB_A_V, 2, 8, 8,L0|L1}, /* e0: 0110 0000 1110 0000 */ + {&upd7810_device::SUB_A_A, 2, 8, 8,L0|L1}, /* e1: 0110 0000 1110 0001 */ + {&upd7810_device::SUB_A_B, 2, 8, 8,L0|L1}, /* e2: 0110 0000 1110 0010 */ + {&upd7810_device::SUB_A_C, 2, 8, 8,L0|L1}, /* e3: 0110 0000 1110 0011 */ + {&upd7810_device::SUB_A_D, 2, 8, 8,L0|L1}, /* e4: 0110 0000 1110 0100 */ + {&upd7810_device::SUB_A_E, 2, 8, 8,L0|L1}, /* e5: 0110 0000 1110 0101 */ + {&upd7810_device::SUB_A_H, 2, 8, 8,L0|L1}, /* e6: 0110 0000 1110 0110 */ + {&upd7810_device::SUB_A_L, 2, 8, 8,L0|L1}, /* e7: 0110 0000 1110 0111 */ + {&upd7810_device::NEA_A_V, 2, 8, 8,L0|L1}, /* e8: 0110 0000 1110 1000 */ + {&upd7810_device::NEA_A_A, 2, 8, 8,L0|L1}, /* e9: 0110 0000 1110 1001 */ + {&upd7810_device::NEA_A_B, 2, 8, 8,L0|L1}, /* ea: 0110 0000 1110 1010 */ + {&upd7810_device::NEA_A_C, 2, 8, 8,L0|L1}, /* eb: 0110 0000 1110 1011 */ + {&upd7810_device::NEA_A_D, 2, 8, 8,L0|L1}, /* ec: 0110 0000 1110 1100 */ + {&upd7810_device::NEA_A_E, 2, 8, 8,L0|L1}, /* ed: 0110 0000 1110 1101 */ + {&upd7810_device::NEA_A_H, 2, 8, 8,L0|L1}, /* ee: 0110 0000 1110 1110 */ + {&upd7810_device::NEA_A_L, 2, 8, 8,L0|L1}, /* ef: 0110 0000 1110 1111 */ + + {&upd7810_device::SBB_A_V, 2, 8, 8,L0|L1}, /* f0: 0110 0000 1111 0000 */ + {&upd7810_device::SBB_A_A, 2, 8, 8,L0|L1}, /* f1: 0110 0000 1111 0001 */ + {&upd7810_device::SBB_A_B, 2, 8, 8,L0|L1}, /* f2: 0110 0000 1111 0010 */ + {&upd7810_device::SBB_A_C, 2, 8, 8,L0|L1}, /* f3: 0110 0000 1111 0011 */ + {&upd7810_device::SBB_A_D, 2, 8, 8,L0|L1}, /* f4: 0110 0000 1111 0100 */ + {&upd7810_device::SBB_A_E, 2, 8, 8,L0|L1}, /* f5: 0110 0000 1111 0101 */ + {&upd7810_device::SBB_A_H, 2, 8, 8,L0|L1}, /* f6: 0110 0000 1111 0110 */ + {&upd7810_device::SBB_A_L, 2, 8, 8,L0|L1}, /* f7: 0110 0000 1111 0111 */ + {&upd7810_device::EQA_A_V, 2, 8, 8,L0|L1}, /* f8: 0110 0000 1111 1000 */ + {&upd7810_device::EQA_A_A, 2, 8, 8,L0|L1}, /* f9: 0110 0000 1111 1001 */ + {&upd7810_device::EQA_A_B, 2, 8, 8,L0|L1}, /* fa: 0110 0000 1111 1010 */ + {&upd7810_device::EQA_A_C, 2, 8, 8,L0|L1}, /* fb: 0110 0000 1111 1011 */ + {&upd7810_device::EQA_A_D, 2, 8, 8,L0|L1}, /* fc: 0110 0000 1111 1100 */ + {&upd7810_device::EQA_A_E, 2, 8, 8,L0|L1}, /* fd: 0110 0000 1111 1101 */ + {&upd7810_device::EQA_A_H, 2, 8, 8,L0|L1}, /* fe: 0110 0000 1111 1110 */ + {&upd7810_device::EQA_A_L, 2, 8, 8,L0|L1} /* ff: 0110 0000 1111 1111 */ +}; + +/* prefix 64 */ +const struct upd7810_device::opcode_s upd7810_device::s_op64[256] = +{ + {&upd7810_device::MVI_PA_xx, 3,14,11,L0|L1}, /* 00: 0110 0100 0000 0000 xxxx xxxx */ + {&upd7810_device::MVI_PB_xx, 3,14,11,L0|L1}, /* 01: 0110 0100 0000 0001 xxxx xxxx */ + {&upd7810_device::MVI_PC_xx, 3,14,11,L0|L1}, /* 02: 0110 0100 0000 0010 xxxx xxxx */ + {&upd7810_device::MVI_PD_xx, 3,14,11,L0|L1}, /* 03: 0110 0100 0000 0011 xxxx xxxx */ + {&upd7810_device::illegal2, 3,11,11,L0|L1}, /* 04: 0110 0100 0000 0100 xxxx xxxx */ + {&upd7810_device::MVI_PF_xx, 3,14,11,L0|L1}, /* 05: 0110 0100 0000 0101 xxxx xxxx */ + {&upd7810_device::MVI_MKH_xx, 3,14,11,L0|L1}, /* 06: 0110 0100 0000 0110 xxxx xxxx */ + {&upd7810_device::MVI_MKL_xx, 3,14,11,L0|L1}, /* 07: 0110 0100 0000 0111 xxxx xxxx */ + {&upd7810_device::ANI_PA_xx, 3,20,11,L0|L1}, /* 08: 0110 0100 0000 1000 xxxx xxxx */ + {&upd7810_device::ANI_PB_xx, 3,20,11,L0|L1}, /* 09: 0110 0100 0000 1001 xxxx xxxx */ + {&upd7810_device::ANI_PC_xx, 3,20,11,L0|L1}, /* 0a: 0110 0100 0000 1010 xxxx xxxx */ + {&upd7810_device::ANI_PD_xx, 3,20,11,L0|L1}, /* 0b: 0110 0100 0000 1011 xxxx xxxx */ + {&upd7810_device::illegal2, 3,11,11,L0|L1}, /* 0c: 0110 0100 0000 1100 xxxx xxxx */ + {&upd7810_device::ANI_PF_xx, 3,20,11,L0|L1}, /* 0d: 0110 0100 0000 1101 xxxx xxxx */ + {&upd7810_device::ANI_MKH_xx, 3,20,11,L0|L1}, /* 0e: 0110 0100 0000 1110 xxxx xxxx */ + {&upd7810_device::ANI_MKL_xx, 3,20,11,L0|L1}, /* 0f: 0110 0100 0000 1111 xxxx xxxx */ + + {&upd7810_device::XRI_PA_xx, 3,20,11,L0|L1}, /* 10: 0110 0100 0001 0000 xxxx xxxx */ + {&upd7810_device::XRI_PB_xx, 3,20,11,L0|L1}, /* 11: 0110 0100 0001 0001 xxxx xxxx */ + {&upd7810_device::XRI_PC_xx, 3,20,11,L0|L1}, /* 12: 0110 0100 0001 0010 xxxx xxxx */ + {&upd7810_device::XRI_PD_xx, 3,20,11,L0|L1}, /* 13: 0110 0100 0001 0011 xxxx xxxx */ + {&upd7810_device::illegal2, 3,11,11,L0|L1}, /* 14: 0110 0100 0001 0100 xxxx xxxx */ + {&upd7810_device::XRI_PF_xx, 3,20,11,L0|L1}, /* 15: 0110 0100 0001 0101 xxxx xxxx */ + {&upd7810_device::XRI_MKH_xx, 3,20,11,L0|L1}, /* 16: 0110 0100 0001 0110 xxxx xxxx */ + {&upd7810_device::XRI_MKL_xx, 3,20,11,L0|L1}, /* 17: 0110 0100 0001 0111 xxxx xxxx */ + {&upd7810_device::ORI_PA_xx, 3,20,11,L0|L1}, /* 18: 0110 0100 0001 1000 xxxx xxxx */ + {&upd7810_device::ORI_PB_xx, 3,20,11,L0|L1}, /* 19: 0110 0100 0001 1001 xxxx xxxx */ + {&upd7810_device::ORI_PC_xx, 3,20,11,L0|L1}, /* 1a: 0110 0100 0001 1010 xxxx xxxx */ + {&upd7810_device::ORI_PD_xx, 3,20,11,L0|L1}, /* 1b: 0110 0100 0001 1011 xxxx xxxx */ + {&upd7810_device::illegal2, 3,11,11,L0|L1}, /* 1c: 0110 0100 0001 1100 xxxx xxxx */ + {&upd7810_device::ORI_PF_xx, 3,20,11,L0|L1}, /* 1d: 0110 0100 0001 1101 xxxx xxxx */ + {&upd7810_device::ORI_MKH_xx, 3,20,11,L0|L1}, /* 1e: 0110 0100 0001 1110 xxxx xxxx */ + {&upd7810_device::ORI_MKL_xx, 3,20,11,L0|L1}, /* 1f: 0110 0100 0001 1111 xxxx xxxx */ + + {&upd7810_device::ADINC_PA_xx, 3,20,11,L0|L1}, /* 20: 0110 0100 0010 0000 xxxx xxxx */ + {&upd7810_device::ADINC_PB_xx, 3,20,11,L0|L1}, /* 21: 0110 0100 0010 0001 xxxx xxxx */ + {&upd7810_device::ADINC_PC_xx, 3,20,11,L0|L1}, /* 22: 0110 0100 0010 0010 xxxx xxxx */ + {&upd7810_device::ADINC_PD_xx, 3,20,11,L0|L1}, /* 23: 0110 0100 0010 0011 xxxx xxxx */ + {&upd7810_device::illegal2, 3,11,11,L0|L1}, /* 24: 0110 0100 0010 0100 xxxx xxxx */ + {&upd7810_device::ADINC_PF_xx, 3,20,11,L0|L1}, /* 25: 0110 0100 0010 0101 xxxx xxxx */ + {&upd7810_device::ADINC_MKH_xx, 3,20,11,L0|L1}, /* 26: 0110 0100 0010 0110 xxxx xxxx */ + {&upd7810_device::ADINC_MKL_xx, 3,20,11,L0|L1}, /* 27: 0110 0100 0010 0111 xxxx xxxx */ + {&upd7810_device::GTI_PA_xx, 3,20,11,L0|L1}, /* 28: 0110 0100 0010 1000 xxxx xxxx */ + {&upd7810_device::GTI_PB_xx, 3,20,11,L0|L1}, /* 29: 0110 0100 0010 1001 xxxx xxxx */ + {&upd7810_device::GTI_PC_xx, 3,20,11,L0|L1}, /* 2a: 0110 0100 0010 1010 xxxx xxxx */ + {&upd7810_device::GTI_PD_xx, 3,20,11,L0|L1}, /* 2b: 0110 0100 0010 1011 xxxx xxxx */ + {&upd7810_device::illegal2, 3,11,11,L0|L1}, /* 2c: 0110 0100 0010 1100 xxxx xxxx */ + {&upd7810_device::GTI_PF_xx, 3,20,11,L0|L1}, /* 2d: 0110 0100 0010 1101 xxxx xxxx */ + {&upd7810_device::GTI_MKH_xx, 3,20,11,L0|L1}, /* 2e: 0110 0100 0010 1110 xxxx xxxx */ + {&upd7810_device::GTI_MKL_xx, 3,20,11,L0|L1}, /* 2f: 0110 0100 0010 1111 xxxx xxxx */ + + {&upd7810_device::SUINB_PA_xx, 3,20,11,L0|L1}, /* 30: 0110 0100 0011 0000 xxxx xxxx */ + {&upd7810_device::SUINB_PB_xx, 3,20,11,L0|L1}, /* 31: 0110 0100 0011 0001 xxxx xxxx */ + {&upd7810_device::SUINB_PC_xx, 3,20,11,L0|L1}, /* 32: 0110 0100 0011 0010 xxxx xxxx */ + {&upd7810_device::SUINB_PD_xx, 3,20,11,L0|L1}, /* 33: 0110 0100 0011 0011 xxxx xxxx */ + {&upd7810_device::illegal2, 3,11,11,L0|L1}, /* 34: 0110 0100 0011 0100 xxxx xxxx */ + {&upd7810_device::SUINB_PF_xx, 3,20,11,L0|L1}, /* 35: 0110 0100 0011 0101 xxxx xxxx */ + {&upd7810_device::SUINB_MKH_xx, 3,20,11,L0|L1}, /* 36: 0110 0100 0011 0110 xxxx xxxx */ + {&upd7810_device::SUINB_MKL_xx, 3,20,11,L0|L1}, /* 37: 0110 0100 0011 0111 xxxx xxxx */ + {&upd7810_device::LTI_PA_xx, 3,20,11,L0|L1}, /* 38: 0110 0100 0011 1000 xxxx xxxx */ + {&upd7810_device::LTI_PB_xx, 3,20,11,L0|L1}, /* 39: 0110 0100 0011 1001 xxxx xxxx */ + {&upd7810_device::LTI_PC_xx, 3,20,11,L0|L1}, /* 3a: 0110 0100 0011 1010 xxxx xxxx */ + {&upd7810_device::LTI_PD_xx, 3,20,11,L0|L1}, /* 3b: 0110 0100 0011 1011 xxxx xxxx */ + {&upd7810_device::illegal2, 3,11,11,L0|L1}, /* 3c: 0110 0100 0011 1100 xxxx xxxx */ + {&upd7810_device::LTI_PF_xx, 3,20,11,L0|L1}, /* 3d: 0110 0100 0011 1101 xxxx xxxx */ + {&upd7810_device::LTI_MKH_xx, 3,20,11,L0|L1}, /* 3e: 0110 0100 0011 1110 xxxx xxxx */ + {&upd7810_device::LTI_MKL_xx, 3,20,11,L0|L1}, /* 3f: 0110 0100 0011 1111 xxxx xxxx */ + + {&upd7810_device::ADI_PA_xx, 3,20,11,L0|L1}, /* 40: 0110 0100 0100 0000 xxxx xxxx */ + {&upd7810_device::ADI_PB_xx, 3,20,11,L0|L1}, /* 41: 0110 0100 0100 0001 xxxx xxxx */ + {&upd7810_device::ADI_PC_xx, 3,20,11,L0|L1}, /* 42: 0110 0100 0100 0010 xxxx xxxx */ + {&upd7810_device::ADI_PD_xx, 3,20,11,L0|L1}, /* 43: 0110 0100 0100 0011 xxxx xxxx */ + {&upd7810_device::illegal2, 3,11,11,L0|L1}, /* 44: 0110 0100 0100 0100 xxxx xxxx */ + {&upd7810_device::ADI_PF_xx, 3,20,11,L0|L1}, /* 45: 0110 0100 0100 0101 xxxx xxxx */ + {&upd7810_device::ADI_MKH_xx, 3,20,11,L0|L1}, /* 46: 0110 0100 0100 0110 xxxx xxxx */ + {&upd7810_device::ADI_MKL_xx, 3,20,11,L0|L1}, /* 47: 0110 0100 0100 0111 xxxx xxxx */ + {&upd7810_device::ONI_PA_xx, 3,20,11,L0|L1}, /* 48: 0110 0100 0100 1000 xxxx xxxx */ + {&upd7810_device::ONI_PB_xx, 3,20,11,L0|L1}, /* 49: 0110 0100 0100 1001 xxxx xxxx */ + {&upd7810_device::ONI_PC_xx, 3,20,11,L0|L1}, /* 4a: 0110 0100 0100 1010 xxxx xxxx */ + {&upd7810_device::ONI_PD_xx, 3,20,11,L0|L1}, /* 4b: 0110 0100 0100 1011 xxxx xxxx */ + {&upd7810_device::illegal2, 3,11,11,L0|L1}, /* 4c: 0110 0100 0100 1100 xxxx xxxx */ + {&upd7810_device::ONI_PF_xx, 3,20,11,L0|L1}, /* 4d: 0110 0100 0100 1101 xxxx xxxx */ + {&upd7810_device::ONI_MKH_xx, 3,20,11,L0|L1}, /* 4e: 0110 0100 0100 1110 xxxx xxxx */ + {&upd7810_device::ONI_MKL_xx, 3,20,11,L0|L1}, /* 4f: 0110 0100 0100 1111 xxxx xxxx */ + + {&upd7810_device::ACI_PA_xx, 3,20,11,L0|L1}, /* 50: 0110 0100 0101 0000 xxxx xxxx */ + {&upd7810_device::ACI_PB_xx, 3,20,11,L0|L1}, /* 51: 0110 0100 0101 0001 xxxx xxxx */ + {&upd7810_device::ACI_PC_xx, 3,20,11,L0|L1}, /* 52: 0110 0100 0101 0010 xxxx xxxx */ + {&upd7810_device::ACI_PD_xx, 3,20,11,L0|L1}, /* 53: 0110 0100 0101 0011 xxxx xxxx */ + {&upd7810_device::illegal2, 3,11,11,L0|L1}, /* 54: 0110 0100 0101 0100 xxxx xxxx */ + {&upd7810_device::ACI_PF_xx, 3,20,11,L0|L1}, /* 55: 0110 0100 0101 0101 xxxx xxxx */ + {&upd7810_device::ACI_MKH_xx, 3,20,11,L0|L1}, /* 56: 0110 0100 0101 0110 xxxx xxxx */ + {&upd7810_device::ACI_MKL_xx, 3,20,11,L0|L1}, /* 57: 0110 0100 0101 0111 xxxx xxxx */ + {&upd7810_device::OFFI_PA_xx, 3,20,11,L0|L1}, /* 58: 0110 0100 0101 1000 xxxx xxxx */ + {&upd7810_device::OFFI_PB_xx, 3,20,11,L0|L1}, /* 59: 0110 0100 0101 1001 xxxx xxxx */ + {&upd7810_device::OFFI_PC_xx, 3,20,11,L0|L1}, /* 5a: 0110 0100 0101 1010 xxxx xxxx */ + {&upd7810_device::OFFI_PD_xx, 3,20,11,L0|L1}, /* 5b: 0110 0100 0101 1011 xxxx xxxx */ + {&upd7810_device::illegal2, 3,11,11,L0|L1}, /* 5c: 0110 0100 0101 1100 xxxx xxxx */ + {&upd7810_device::OFFI_PF_xx, 3,20,11,L0|L1}, /* 5d: 0110 0100 0101 1101 xxxx xxxx */ + {&upd7810_device::OFFI_MKH_xx, 3,20,11,L0|L1}, /* 5e: 0110 0100 0101 1110 xxxx xxxx */ + {&upd7810_device::OFFI_MKL_xx, 3,20,11,L0|L1}, /* 5f: 0110 0100 0101 1111 xxxx xxxx */ + + {&upd7810_device::SUI_PA_xx, 3,20,11,L0|L1}, /* 60: 0110 0100 0110 0000 xxxx xxxx */ + {&upd7810_device::SUI_PB_xx, 3,20,11,L0|L1}, /* 61: 0110 0100 0110 0001 xxxx xxxx */ + {&upd7810_device::SUI_PC_xx, 3,20,11,L0|L1}, /* 62: 0110 0100 0110 0010 xxxx xxxx */ + {&upd7810_device::SUI_PD_xx, 3,20,11,L0|L1}, /* 63: 0110 0100 0110 0011 xxxx xxxx */ + {&upd7810_device::illegal2, 3,11,11,L0|L1}, /* 64: 0110 0100 0110 0100 xxxx xxxx */ + {&upd7810_device::SUI_PF_xx, 3,20,11,L0|L1}, /* 65: 0110 0100 0110 0101 xxxx xxxx */ + {&upd7810_device::SUI_MKH_xx, 3,20,11,L0|L1}, /* 66: 0110 0100 0110 0110 xxxx xxxx */ + {&upd7810_device::SUI_MKL_xx, 3,20,11,L0|L1}, /* 67: 0110 0100 0110 0111 xxxx xxxx */ + {&upd7810_device::NEI_PA_xx, 3,20,11,L0|L1}, /* 68: 0110 0100 0110 1000 xxxx xxxx */ + {&upd7810_device::NEI_PB_xx, 3,20,11,L0|L1}, /* 69: 0110 0100 0110 1001 xxxx xxxx */ + {&upd7810_device::NEI_PC_xx, 3,20,11,L0|L1}, /* 6a: 0110 0100 0110 1010 xxxx xxxx */ + {&upd7810_device::NEI_PD_xx, 3,20,11,L0|L1}, /* 6b: 0110 0100 0110 1011 xxxx xxxx */ + {&upd7810_device::illegal2, 3,11,11,L0|L1}, /* 6c: 0110 0100 0110 1100 xxxx xxxx */ + {&upd7810_device::NEI_PF_xx, 3,20,11,L0|L1}, /* 6d: 0110 0100 0110 1101 xxxx xxxx */ + {&upd7810_device::NEI_MKH_xx, 3,20,11,L0|L1}, /* 6e: 0110 0100 0110 1110 xxxx xxxx */ + {&upd7810_device::NEI_MKL_xx, 3,20,11,L0|L1}, /* 6f: 0110 0100 0110 1111 xxxx xxxx */ + + {&upd7810_device::SBI_PA_xx, 3,20,11,L0|L1}, /* 70: 0110 0100 0111 0000 xxxx xxxx */ + {&upd7810_device::SBI_PB_xx, 3,20,11,L0|L1}, /* 71: 0110 0100 0111 0001 xxxx xxxx */ + {&upd7810_device::SBI_PC_xx, 3,20,11,L0|L1}, /* 72: 0110 0100 0111 0010 xxxx xxxx */ + {&upd7810_device::SBI_PD_xx, 3,20,11,L0|L1}, /* 73: 0110 0100 0111 0011 xxxx xxxx */ + {&upd7810_device::illegal2, 3,11,11,L0|L1}, /* 74: 0110 0100 0111 0100 xxxx xxxx */ + {&upd7810_device::SBI_PF_xx, 3,20,11,L0|L1}, /* 75: 0110 0100 0111 0101 xxxx xxxx */ + {&upd7810_device::SBI_MKH_xx, 3,20,11,L0|L1}, /* 76: 0110 0100 0111 0110 xxxx xxxx */ + {&upd7810_device::SBI_MKL_xx, 3,20,11,L0|L1}, /* 77: 0110 0100 0111 0111 xxxx xxxx */ + {&upd7810_device::EQI_PA_xx, 3,20,11,L0|L1}, /* 78: 0110 0100 0111 1000 xxxx xxxx */ + {&upd7810_device::EQI_PB_xx, 3,20,11,L0|L1}, /* 79: 0110 0100 0111 1001 xxxx xxxx */ + {&upd7810_device::EQI_PC_xx, 3,20,11,L0|L1}, /* 7a: 0110 0100 0111 1010 xxxx xxxx */ + {&upd7810_device::EQI_PD_xx, 3,20,11,L0|L1}, /* 7b: 0110 0100 0111 1011 xxxx xxxx */ + {&upd7810_device::illegal2, 3,11,11,L0|L1}, /* 7c: 0110 0100 0111 1100 xxxx xxxx */ + {&upd7810_device::EQI_PF_xx, 3,20,11,L0|L1}, /* 7d: 0110 0100 0111 1101 xxxx xxxx */ + {&upd7810_device::EQI_MKH_xx, 3,20,11,L0|L1}, /* 7e: 0110 0100 0111 1110 xxxx xxxx */ + {&upd7810_device::EQI_MKL_xx, 3,20,11,L0|L1}, /* 7f: 0110 0100 0111 1111 xxxx xxxx */ + + {&upd7810_device::MVI_ANM_xx, 3,14,11,L0|L1}, /* 80: 0110 0100 1000 0000 xxxx xxxx */ + {&upd7810_device::MVI_SMH_xx, 3,14,11,L0|L1}, /* 81: 0110 0100 1000 0001 xxxx xxxx */ + {&upd7810_device::illegal2, 3,11,11,L0|L1}, /* 82: 0110 0100 1000 0010 xxxx xxxx */ + {&upd7810_device::MVI_EOM_xx, 3,14,11,L0|L1}, /* 83: 0110 0100 1000 0011 xxxx xxxx */ + {&upd7810_device::illegal2, 3,11,11,L0|L1}, /* 84: 0110 0100 1000 0100 xxxx xxxx */ + {&upd7810_device::MVI_TMM_xx, 3,14,11,L0|L1}, /* 85: 0110 0100 1000 0101 xxxx xxxx */ + {&upd7810_device::illegal2, 3,11,11,L0|L1}, /* 86: 0110 0100 1000 0110 xxxx xxxx */ + {&upd7810_device::illegal2, 3,11,11,L0|L1}, /* 87: 0110 0100 1000 0111 xxxx xxxx */ + {&upd7810_device::ANI_ANM_xx, 3,20,11,L0|L1}, /* 88: 0110 0100 1000 1000 xxxx xxxx */ + {&upd7810_device::ANI_SMH_xx, 3,20,11,L0|L1}, /* 89: 0110 0100 1000 1001 xxxx xxxx */ + {&upd7810_device::illegal2, 3,11,11,L0|L1}, /* 8a: 0110 0100 1000 1010 xxxx xxxx */ + {&upd7810_device::ANI_EOM_xx, 3,20,11,L0|L1}, /* 8b: 0110 0100 1000 1011 xxxx xxxx */ + {&upd7810_device::illegal2, 3,11,11,L0|L1}, /* 8c: 0110 0100 1000 1100 xxxx xxxx */ + {&upd7810_device::ANI_TMM_xx, 3,20,11,L0|L1}, /* 8d: 0110 0100 1000 1101 xxxx xxxx */ + {&upd7810_device::illegal2, 3,11,11,L0|L1}, /* 8e: 0110 0100 1000 1110 xxxx xxxx */ + {&upd7810_device::illegal2, 3,11,11,L0|L1}, /* 8f: 0110 0100 1000 1111 xxxx xxxx */ + + {&upd7810_device::XRI_ANM_xx, 3,20,11,L0|L1}, /* 90: 0110 0100 1001 0000 xxxx xxxx */ + {&upd7810_device::XRI_SMH_xx, 3,20,11,L0|L1}, /* 91: 0110 0100 1001 0001 xxxx xxxx */ + {&upd7810_device::illegal2, 3,11,11,L0|L1}, /* 92: 0110 0100 1001 0010 xxxx xxxx */ + {&upd7810_device::XRI_EOM_xx, 3,20,11,L0|L1}, /* 93: 0110 0100 1001 0011 xxxx xxxx */ + {&upd7810_device::illegal2, 3,11,11,L0|L1}, /* 94: 0110 0100 1001 0100 xxxx xxxx */ + {&upd7810_device::XRI_TMM_xx, 3,20,11,L0|L1}, /* 95: 0110 0100 1001 0101 xxxx xxxx */ + {&upd7810_device::illegal2, 3,11,11,L0|L1}, /* 96: 0110 0100 1001 0110 xxxx xxxx */ + {&upd7810_device::illegal2, 3,11,11,L0|L1}, /* 97: 0110 0100 1001 0111 xxxx xxxx */ + {&upd7810_device::ORI_ANM_xx, 3,20,11,L0|L1}, /* 98: 0110 0100 1001 1000 xxxx xxxx */ + {&upd7810_device::ORI_SMH_xx, 3,20,11,L0|L1}, /* 99: 0110 0100 1001 1001 xxxx xxxx */ + {&upd7810_device::illegal2, 3,11,11,L0|L1}, /* 9a: 0110 0100 1001 1010 xxxx xxxx */ + {&upd7810_device::ORI_EOM_xx, 3,20,11,L0|L1}, /* 9b: 0110 0100 1001 1011 xxxx xxxx */ + {&upd7810_device::illegal2, 3,11,11,L0|L1}, /* 9c: 0110 0100 1001 1100 xxxx xxxx */ + {&upd7810_device::ORI_TMM_xx, 3,20,11,L0|L1}, /* 9d: 0110 0100 1001 1101 xxxx xxxx */ + {&upd7810_device::illegal2, 3,11,11,L0|L1}, /* 9e: 0110 0100 1001 1110 xxxx xxxx */ + {&upd7810_device::illegal2, 3,11,11,L0|L1}, /* 9f: 0110 0100 1001 1111 xxxx xxxx */ + + {&upd7810_device::ADINC_ANM_xx, 3,20,11,L0|L1}, /* a0: 0110 0100 1010 0000 xxxx xxxx */ + {&upd7810_device::ADINC_SMH_xx, 3,20,11,L0|L1}, /* a1: 0110 0100 1010 0001 xxxx xxxx */ + {&upd7810_device::illegal2, 3,11,11,L0|L1}, /* a2: 0110 0100 1010 0010 xxxx xxxx */ + {&upd7810_device::ADINC_EOM_xx, 3,20,11,L0|L1}, /* a3: 0110 0100 1010 0011 xxxx xxxx */ + {&upd7810_device::illegal2, 3,11,11,L0|L1}, /* a4: 0110 0100 1010 0100 xxxx xxxx */ + {&upd7810_device::ADINC_TMM_xx, 3,20,11,L0|L1}, /* a5: 0110 0100 1010 0101 xxxx xxxx */ + {&upd7810_device::illegal2, 3,11,11,L0|L1}, /* a6: 0110 0100 1010 0110 xxxx xxxx */ + {&upd7810_device::illegal2, 3,11,11,L0|L1}, /* a7: 0110 0100 1010 0111 xxxx xxxx */ + {&upd7810_device::GTI_ANM_xx, 3,20,11,L0|L1}, /* a8: 0110 0100 1010 1000 xxxx xxxx */ + {&upd7810_device::GTI_SMH_xx, 3,20,11,L0|L1}, /* a9: 0110 0100 1010 1001 xxxx xxxx */ + {&upd7810_device::illegal2, 3,11,11,L0|L1}, /* aa: 0110 0100 1010 1010 xxxx xxxx */ + {&upd7810_device::GTI_EOM_xx, 3,20,11,L0|L1}, /* ab: 0110 0100 1010 1011 xxxx xxxx */ + {&upd7810_device::illegal2, 3,11,11,L0|L1}, /* ac: 0110 0100 1010 1100 xxxx xxxx */ + {&upd7810_device::GTI_TMM_xx, 3,20,11,L0|L1}, /* ad: 0110 0100 1010 1101 xxxx xxxx */ + {&upd7810_device::illegal2, 3,11,11,L0|L1}, /* ae: 0110 0100 1010 1110 xxxx xxxx */ + {&upd7810_device::illegal2, 3,11,11,L0|L1}, /* af: 0110 0100 1010 1111 xxxx xxxx */ + + {&upd7810_device::SUINB_ANM_xx, 3,20,11,L0|L1}, /* b0: 0110 0100 1011 0000 xxxx xxxx */ + {&upd7810_device::SUINB_SMH_xx, 3,20,11,L0|L1}, /* b1: 0110 0100 1011 0001 xxxx xxxx */ + {&upd7810_device::illegal2, 3,11,11,L0|L1}, /* b2: 0110 0100 1011 0010 xxxx xxxx */ + {&upd7810_device::SUINB_EOM_xx, 3,20,11,L0|L1}, /* b3: 0110 0100 1011 0011 xxxx xxxx */ + {&upd7810_device::illegal2, 3,11,11,L0|L1}, /* b4: 0110 0100 1011 0100 xxxx xxxx */ + {&upd7810_device::SUINB_TMM_xx, 3,20,11,L0|L1}, /* b5: 0110 0100 1011 0101 xxxx xxxx */ + {&upd7810_device::illegal2, 3,11,11,L0|L1}, /* b6: 0110 0100 1011 0110 xxxx xxxx */ + {&upd7810_device::illegal2, 3,11,11,L0|L1}, /* b7: 0110 0100 1011 0111 xxxx xxxx */ + {&upd7810_device::LTI_ANM_xx, 3,20,11,L0|L1}, /* b8: 0110 0100 1011 1000 xxxx xxxx */ + {&upd7810_device::LTI_SMH_xx, 3,20,11,L0|L1}, /* b9: 0110 0100 1011 1001 xxxx xxxx */ + {&upd7810_device::illegal2, 3,11,11,L0|L1}, /* ba: 0110 0100 1011 1010 xxxx xxxx */ + {&upd7810_device::LTI_EOM_xx, 3,20,11,L0|L1}, /* bb: 0110 0100 1011 1011 xxxx xxxx */ + {&upd7810_device::illegal2, 3,11,11,L0|L1}, /* bc: 0110 0100 1011 1100 xxxx xxxx */ + {&upd7810_device::LTI_TMM_xx, 3,20,11,L0|L1}, /* bd: 0110 0100 1011 1101 xxxx xxxx */ + {&upd7810_device::illegal2, 3,11,11,L0|L1}, /* be: 0110 0100 1011 1110 xxxx xxxx */ + {&upd7810_device::illegal2, 3,11,11,L0|L1}, /* bf: 0110 0100 1011 1111 xxxx xxxx */ + + {&upd7810_device::ADI_ANM_xx, 3,20,11,L0|L1}, /* c0: 0110 0100 1100 0000 xxxx xxxx */ + {&upd7810_device::ADI_SMH_xx, 3,20,11,L0|L1}, /* c1: 0110 0100 1100 0001 xxxx xxxx */ + {&upd7810_device::illegal2, 3,11,11,L0|L1}, /* c2: 0110 0100 1100 0010 xxxx xxxx */ + {&upd7810_device::ADI_EOM_xx, 3,20,11,L0|L1}, /* c3: 0110 0100 1100 0011 xxxx xxxx */ + {&upd7810_device::illegal2, 3,11,11,L0|L1}, /* c4: 0110 0100 1100 0100 xxxx xxxx */ + {&upd7810_device::ADI_TMM_xx, 3,20,11,L0|L1}, /* c5: 0110 0100 1100 0101 xxxx xxxx */ + {&upd7810_device::illegal2, 3,11,11,L0|L1}, /* c6: 0110 0100 1100 0110 xxxx xxxx */ + {&upd7810_device::illegal2, 3,11,11,L0|L1}, /* c7: 0110 0100 1100 0111 xxxx xxxx */ + {&upd7810_device::ONI_ANM_xx, 3,20,11,L0|L1}, /* c8: 0110 0100 1100 1000 xxxx xxxx */ + {&upd7810_device::ONI_SMH_xx, 3,20,11,L0|L1}, /* c9: 0110 0100 1100 1001 xxxx xxxx */ + {&upd7810_device::illegal2, 3,11,11,L0|L1}, /* ca: 0110 0100 1100 1010 xxxx xxxx */ + {&upd7810_device::ONI_EOM_xx, 3,20,11,L0|L1}, /* cb: 0110 0100 1100 1011 xxxx xxxx */ + {&upd7810_device::illegal2, 3,11,11,L0|L1}, /* cc: 0110 0100 1100 1100 xxxx xxxx */ + {&upd7810_device::ONI_TMM_xx, 3,20,11,L0|L1}, /* cd: 0110 0100 1100 1101 xxxx xxxx */ + {&upd7810_device::illegal2, 3,11,11,L0|L1}, /* ce: 0110 0100 1100 1110 xxxx xxxx */ + {&upd7810_device::illegal2, 3,11,11,L0|L1}, /* cf: 0110 0100 1100 1111 xxxx xxxx */ + + {&upd7810_device::ACI_ANM_xx, 3,20,11,L0|L1}, /* d0: 0110 0100 1101 0000 xxxx xxxx */ + {&upd7810_device::ACI_SMH_xx, 3,20,11,L0|L1}, /* d1: 0110 0100 1101 0001 xxxx xxxx */ + {&upd7810_device::illegal2, 3,11,11,L0|L1}, /* d2: 0110 0100 1101 0010 xxxx xxxx */ + {&upd7810_device::ACI_EOM_xx, 3,20,11,L0|L1}, /* d3: 0110 0100 1101 0011 xxxx xxxx */ + {&upd7810_device::illegal2, 3,11,11,L0|L1}, /* d4: 0110 0100 1101 0100 xxxx xxxx */ + {&upd7810_device::ACI_TMM_xx, 3,20,11,L0|L1}, /* d5: 0110 0100 1101 0101 xxxx xxxx */ + {&upd7810_device::illegal2, 3,11,11,L0|L1}, /* d6: 0110 0100 1101 0110 xxxx xxxx */ + {&upd7810_device::illegal2, 3,11,11,L0|L1}, /* d7: 0110 0100 1101 0111 xxxx xxxx */ + {&upd7810_device::OFFI_ANM_xx, 3,20,11,L0|L1}, /* d8: 0110 0100 1101 1000 xxxx xxxx */ + {&upd7810_device::OFFI_SMH_xx, 3,20,11,L0|L1}, /* d9: 0110 0100 1101 1001 xxxx xxxx */ + {&upd7810_device::illegal2, 3,11,11,L0|L1}, /* da: 0110 0100 1101 1010 xxxx xxxx */ + {&upd7810_device::OFFI_EOM_xx, 3,20,11,L0|L1}, /* db: 0110 0100 1101 1011 xxxx xxxx */ + {&upd7810_device::illegal2, 3,11,11,L0|L1}, /* dc: 0110 0100 1101 1100 xxxx xxxx */ + {&upd7810_device::OFFI_TMM_xx, 3,20,11,L0|L1}, /* dd: 0110 0100 1101 1101 xxxx xxxx */ + {&upd7810_device::illegal2, 3,11,11,L0|L1}, /* de: 0110 0100 1101 1110 xxxx xxxx */ + {&upd7810_device::illegal2, 3,11,11,L0|L1}, /* df: 0110 0100 1101 1111 xxxx xxxx */ + + {&upd7810_device::SUI_ANM_xx, 3,20,11,L0|L1}, /* e0: 0110 0100 1110 0000 xxxx xxxx */ + {&upd7810_device::SUI_SMH_xx, 3,20,11,L0|L1}, /* e1: 0110 0100 1110 0001 xxxx xxxx */ + {&upd7810_device::illegal2, 3,11,11,L0|L1}, /* e2: 0110 0100 1110 0010 xxxx xxxx */ + {&upd7810_device::SUI_EOM_xx, 3,20,11,L0|L1}, /* e3: 0110 0100 1110 0011 xxxx xxxx */ + {&upd7810_device::illegal2, 3,11,11,L0|L1}, /* e4: 0110 0100 1110 0100 xxxx xxxx */ + {&upd7810_device::SUI_TMM_xx, 3,20,11,L0|L1}, /* e5: 0110 0100 1110 0101 xxxx xxxx */ + {&upd7810_device::illegal2, 3,11,11,L0|L1}, /* e6: 0110 0100 1110 0110 xxxx xxxx */ + {&upd7810_device::illegal2, 3,11,11,L0|L1}, /* e7: 0110 0100 1110 0111 xxxx xxxx */ + {&upd7810_device::NEI_ANM_xx, 3,20,11,L0|L1}, /* e8: 0110 0100 1110 1000 xxxx xxxx */ + {&upd7810_device::NEI_SMH_xx, 3,20,11,L0|L1}, /* e9: 0110 0100 1110 1001 xxxx xxxx */ + {&upd7810_device::illegal2, 3,11,11,L0|L1}, /* ea: 0110 0100 1110 1010 xxxx xxxx */ + {&upd7810_device::NEI_EOM_xx, 3,20,11,L0|L1}, /* eb: 0110 0100 1110 1011 xxxx xxxx */ + {&upd7810_device::illegal2, 3,11,11,L0|L1}, /* ec: 0110 0100 1110 1100 xxxx xxxx */ + {&upd7810_device::NEI_TMM_xx, 3,20,11,L0|L1}, /* ed: 0110 0100 1110 1101 xxxx xxxx */ + {&upd7810_device::illegal2, 3,11,11,L0|L1}, /* ee: 0110 0100 1110 1110 xxxx xxxx */ + {&upd7810_device::illegal2, 3,11,11,L0|L1}, /* ef: 0110 0100 1110 1111 xxxx xxxx */ + + {&upd7810_device::SBI_ANM_xx, 3,20,11,L0|L1}, /* f0: 0110 0100 1111 0000 xxxx xxxx */ + {&upd7810_device::SBI_SMH_xx, 3,20,11,L0|L1}, /* f1: 0110 0100 1111 0001 xxxx xxxx */ + {&upd7810_device::illegal2, 3,11,11,L0|L1}, /* f2: 0110 0100 1111 0010 xxxx xxxx */ + {&upd7810_device::SBI_EOM_xx, 3,20,11,L0|L1}, /* f3: 0110 0100 1111 0011 xxxx xxxx */ + {&upd7810_device::illegal2, 3,11,11,L0|L1}, /* f4: 0110 0100 1111 0100 xxxx xxxx */ + {&upd7810_device::SBI_TMM_xx, 3,20,11,L0|L1}, /* f5: 0110 0100 1111 0101 xxxx xxxx */ + {&upd7810_device::illegal2, 3,11,11,L0|L1}, /* f6: 0110 0100 1111 0110 xxxx xxxx */ + {&upd7810_device::illegal2, 3,11,11,L0|L1}, /* f7: 0110 0100 1111 0111 xxxx xxxx */ + {&upd7810_device::EQI_ANM_xx, 3,20,11,L0|L1}, /* f8: 0110 0100 1111 1000 xxxx xxxx */ + {&upd7810_device::EQI_SMH_xx, 3,20,11,L0|L1}, /* f9: 0110 0100 1111 1001 xxxx xxxx */ + {&upd7810_device::illegal2, 3,11,11,L0|L1}, /* fa: 0110 0100 1111 1010 xxxx xxxx */ + {&upd7810_device::EQI_EOM_xx, 3,20,11,L0|L1}, /* fb: 0110 0100 1111 1011 xxxx xxxx */ + {&upd7810_device::illegal2, 3,11,11,L0|L1}, /* fc: 0110 0100 1111 1100 xxxx xxxx */ + {&upd7810_device::EQI_TMM_xx, 3,20,11,L0|L1}, /* fd: 0110 0100 1111 1101 xxxx xxxx */ + {&upd7810_device::illegal2, 3,11,11,L0|L1}, /* fe: 0110 0100 1111 1110 xxxx xxxx */ + {&upd7810_device::illegal2, 3,11,11,L0|L1} /* ff: 0110 0100 1111 1111 xxxx xxxx */ +}; + +/* prefix 70 */ +const struct upd7810_device::opcode_s upd7810_device::s_op70[256] = +{ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 00: 0111 0000 0000 0000 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 01: 0111 0000 0000 0001 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 02: 0111 0000 0000 0010 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 03: 0111 0000 0000 0011 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 04: 0111 0000 0000 0100 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 05: 0111 0000 0000 0101 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 06: 0111 0000 0000 0110 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 07: 0111 0000 0000 0111 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 08: 0111 0000 0000 1000 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 09: 0111 0000 0000 1001 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 0a: 0111 0000 0000 1010 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 0b: 0111 0000 0000 1011 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 0c: 0111 0000 0000 1100 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 0d: 0111 0000 0000 1101 */ + {&upd7810_device::SSPD_w, 4,20,20,L0|L1}, /* 0e: 0111 0000 0000 1110 llll llll hhhh hhhh */ + {&upd7810_device::LSPD_w, 4,20,20,L0|L1}, /* 0f: 0111 0000 0000 1111 llll llll hhhh hhhh */ + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 10: 0111 0000 0001 0000 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 11: 0111 0000 0001 0001 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 12: 0111 0000 0001 0010 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 13: 0111 0000 0001 0011 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 14: 0111 0000 0001 0100 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 15: 0111 0000 0001 0101 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 16: 0111 0000 0001 0110 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 17: 0111 0000 0001 0111 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 18: 0111 0000 0001 1000 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 19: 0111 0000 0001 1001 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 1a: 0111 0000 0001 1010 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 1b: 0111 0000 0001 1011 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 1c: 0111 0000 0001 1100 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 1d: 0111 0000 0001 1101 */ + {&upd7810_device::SBCD_w, 4,20,20,L0|L1}, /* 1e: 0111 0000 0001 1110 llll llll hhhh hhhh */ + {&upd7810_device::LBCD_w, 4,20,20,L0|L1}, /* 1f: 0111 0000 0001 1111 llll llll hhhh hhhh */ + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 20: 0111 0000 0010 0000 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 21: 0111 0000 0010 0001 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 22: 0111 0000 0010 0010 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 23: 0111 0000 0010 0011 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 24: 0111 0000 0010 0100 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 25: 0111 0000 0010 0101 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 26: 0111 0000 0010 0110 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 27: 0111 0000 0010 0111 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 28: 0111 0000 0010 1000 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 29: 0111 0000 0010 1001 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 2a: 0111 0000 0010 1010 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 2b: 0111 0000 0010 1011 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 2c: 0111 0000 0010 1100 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 2d: 0111 0000 0010 1101 */ + {&upd7810_device::SDED_w, 4,20,20,L0|L1}, /* 2e: 0111 0000 0010 1110 llll llll hhhh hhhh */ + {&upd7810_device::LDED_w, 4,20,20,L0|L1}, /* 2f: 0111 0000 0010 1111 llll llll hhhh hhhh */ + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 30: 0111 0000 0011 0000 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 31: 0111 0000 0011 0001 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 32: 0111 0000 0011 0010 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 33: 0111 0000 0011 0011 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 34: 0111 0000 0011 0100 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 35: 0111 0000 0011 0101 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 36: 0111 0000 0011 0110 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 37: 0111 0000 0011 0111 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 38: 0111 0000 0011 1000 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 39: 0111 0000 0011 1001 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 3a: 0111 0000 0011 1010 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 3b: 0111 0000 0011 1011 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 3c: 0111 0000 0011 1100 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 3d: 0111 0000 0011 1101 */ + {&upd7810_device::SHLD_w, 4,20,20,L0|L1}, /* 3e: 0111 0000 0011 1110 llll llll hhhh hhhh */ + {&upd7810_device::LHLD_w, 4,20,20,L0|L1}, /* 3f: 0111 0000 0011 1111 llll llll hhhh hhhh */ + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 40: 0111 0000 0100 0000 */ + {&upd7810_device::EADD_EA_A, 2,11,11,L0|L1}, /* 41: 0111 0000 0100 0001 */ + {&upd7810_device::EADD_EA_B, 2,11,11,L0|L1}, /* 42: 0111 0000 0100 0010 */ + {&upd7810_device::EADD_EA_C, 2,11,11,L0|L1}, /* 43: 0111 0000 0100 0011 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 44: 0111 0000 0100 0100 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 45: 0111 0000 0100 0101 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 46: 0111 0000 0100 0110 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 47: 0111 0000 0100 0111 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 48: 0111 0000 0100 1000 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 49: 0111 0000 0100 1001 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 4a: 0111 0000 0100 1010 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 4b: 0111 0000 0100 1011 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 4c: 0111 0000 0100 1100 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 4d: 0111 0000 0100 1101 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 4e: 0111 0000 0100 1110 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 4f: 0111 0000 0100 1111 */ + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 50: 0111 0000 0101 0000 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 51: 0111 0000 0101 0001 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 52: 0111 0000 0101 0010 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 53: 0111 0000 0101 0011 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 54: 0111 0000 0101 0100 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 55: 0111 0000 0101 0101 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 56: 0111 0000 0101 0110 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 57: 0111 0000 0101 0111 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 58: 0111 0000 0101 1000 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 59: 0111 0000 0101 1001 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 5a: 0111 0000 0101 1010 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 5b: 0111 0000 0101 1011 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 5c: 0111 0000 0101 1100 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 5d: 0111 0000 0101 1101 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 5e: 0111 0000 0101 1110 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 5f: 0111 0000 0101 1111 */ + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 60: 0111 0000 0110 0000 */ + {&upd7810_device::ESUB_EA_A, 2,11,11,L0|L1}, /* 61: 0111 0000 0110 0001 */ + {&upd7810_device::ESUB_EA_B, 2,11,11,L0|L1}, /* 62: 0111 0000 0110 0010 */ + {&upd7810_device::ESUB_EA_C, 2,11,11,L0|L1}, /* 63: 0111 0000 0110 0011 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 64: 0111 0000 0110 0100 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 65: 0111 0000 0110 0101 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 66: 0111 0000 0110 0110 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 67: 0111 0000 0110 0111 */ + {&upd7810_device::MOV_V_w, 4,17,17,L0|L1}, /* 68: 0111 0000 0110 1000 llll llll hhhh hhhh */ + {&upd7810_device::MOV_A_w, 4,17,17,L0|L1}, /* 69: 0111 0000 0110 1001 llll llll hhhh hhhh */ + {&upd7810_device::MOV_B_w, 4,17,17,L0|L1}, /* 6a: 0111 0000 0110 1010 llll llll hhhh hhhh */ + {&upd7810_device::MOV_C_w, 4,17,17,L0|L1}, /* 6b: 0111 0000 0110 1011 llll llll hhhh hhhh */ + {&upd7810_device::MOV_D_w, 4,17,17,L0|L1}, /* 6c: 0111 0000 0110 1100 llll llll hhhh hhhh */ + {&upd7810_device::MOV_E_w, 4,17,17,L0|L1}, /* 6d: 0111 0000 0110 1101 llll llll hhhh hhhh */ + {&upd7810_device::MOV_H_w, 4,17,17,L0|L1}, /* 6e: 0111 0000 0110 1110 llll llll hhhh hhhh */ + {&upd7810_device::MOV_L_w, 4,17,17,L0|L1}, /* 6f: 0111 0000 0110 1111 llll llll hhhh hhhh */ + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 70: 0111 0000 0111 0000 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 71: 0111 0000 0111 0001 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 72: 0111 0000 0111 0010 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 73: 0111 0000 0111 0011 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 74: 0111 0000 0111 0100 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 75: 0111 0000 0111 0101 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 76: 0111 0000 0111 0110 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 77: 0111 0000 0111 0111 */ + {&upd7810_device::MOV_w_V, 4,17,17,L0|L1}, /* 78: 0111 0000 0111 1000 llll llll hhhh hhhh */ + {&upd7810_device::MOV_w_A, 4,17,17,L0|L1}, /* 79: 0111 0000 0111 1001 llll llll hhhh hhhh */ + {&upd7810_device::MOV_w_B, 4,17,17,L0|L1}, /* 7a: 0111 0000 0111 1010 llll llll hhhh hhhh */ + {&upd7810_device::MOV_w_C, 4,17,17,L0|L1}, /* 7b: 0111 0000 0111 1011 llll llll hhhh hhhh */ + {&upd7810_device::MOV_w_D, 4,17,17,L0|L1}, /* 7c: 0111 0000 0111 1100 llll llll hhhh hhhh */ + {&upd7810_device::MOV_w_E, 4,17,17,L0|L1}, /* 7d: 0111 0000 0111 1101 llll llll hhhh hhhh */ + {&upd7810_device::MOV_w_H, 4,17,17,L0|L1}, /* 7e: 0111 0000 0111 1110 llll llll hhhh hhhh */ + {&upd7810_device::MOV_w_L, 4,17,17,L0|L1}, /* 7f: 0111 0000 0111 1111 llll llll hhhh hhhh */ + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 80: 0111 0000 1000 0000 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 81: 0111 0000 1000 0001 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 82: 0111 0000 1000 0010 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 83: 0111 0000 1000 0011 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 84: 0111 0000 1000 0100 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 85: 0111 0000 1000 0101 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 86: 0111 0000 1000 0110 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 87: 0111 0000 1000 0111 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 88: 0111 0000 1000 1000 */ + {&upd7810_device::ANAX_B, 2,11,11,L0|L1}, /* 89: 0111 0000 1000 1001 */ + {&upd7810_device::ANAX_D, 2,11,11,L0|L1}, /* 8a: 0111 0000 1000 1010 */ + {&upd7810_device::ANAX_H, 2,11,11,L0|L1}, /* 8b: 0111 0000 1000 1011 */ + {&upd7810_device::ANAX_Dp, 2,11,11,L0|L1}, /* 8c: 0111 0000 1000 1100 */ + {&upd7810_device::ANAX_Hp, 2,11,11,L0|L1}, /* 8d: 0111 0000 1000 1101 */ + {&upd7810_device::ANAX_Dm, 2,11,11,L0|L1}, /* 8e: 0111 0000 1000 1110 */ + {&upd7810_device::ANAX_Hm, 2,11,11,L0|L1}, /* 8f: 0111 0000 1000 1111 */ + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 90: 0111 0000 1001 0000 */ + {&upd7810_device::XRAX_B, 2,11,11,L0|L1}, /* 91: 0111 0000 1001 0001 */ + {&upd7810_device::XRAX_D, 2,11,11,L0|L1}, /* 92: 0111 0000 1001 0010 */ + {&upd7810_device::XRAX_H, 2,11,11,L0|L1}, /* 93: 0111 0000 1001 0011 */ + {&upd7810_device::XRAX_Dp, 2,11,11,L0|L1}, /* 94: 0111 0000 1001 0100 */ + {&upd7810_device::XRAX_Hp, 2,11,11,L0|L1}, /* 95: 0111 0000 1001 0101 */ + {&upd7810_device::XRAX_Dm, 2,11,11,L0|L1}, /* 96: 0111 0000 1001 0110 */ + {&upd7810_device::XRAX_Hm, 2,11,11,L0|L1}, /* 97: 0111 0000 1001 0111 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 98: 0111 0000 1001 1000 */ +// orax added, timings not verified + {&upd7810_device::ORAX_B, 2,11, 8,L0|L1}, /* 99: 0111 0000 1001 1001 */ + {&upd7810_device::ORAX_D, 2,11, 8,L0|L1}, /* 9a: 0111 0000 1001 1010 */ + {&upd7810_device::ORAX_H, 2,11, 8,L0|L1}, /* 9b: 0111 0000 1001 1011 */ + {&upd7810_device::ORAX_Dp, 2,11, 8,L0|L1}, /* 9c: 0111 0000 1001 1100 */ + {&upd7810_device::ORAX_Hp, 2,11, 8,L0|L1}, /* 9d: 0111 0000 1001 1101 */ + {&upd7810_device::ORAX_Dm, 2,11, 8,L0|L1}, /* 9e: 0111 0000 1001 1110 */ + {&upd7810_device::ORAX_Hm, 2,11, 8,L0|L1}, /* 9f: 0111 0000 1001 1111 */ + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* a0: 0111 0000 1010 0000 */ + {&upd7810_device::ADDNCX_B, 2,11, 8,L0|L1}, /* a1: 0111 0000 1010 0001 */ + {&upd7810_device::ADDNCX_D, 2,11, 8,L0|L1}, /* a2: 0111 0000 1010 0010 */ + {&upd7810_device::ADDNCX_H, 2,11, 8,L0|L1}, /* a3: 0111 0000 1010 0011 */ + {&upd7810_device::ADDNCX_Dp, 2,11, 8,L0|L1}, /* a4: 0111 0000 1010 0100 */ + {&upd7810_device::ADDNCX_Hp, 2,11, 8,L0|L1}, /* a5: 0111 0000 1010 0101 */ + {&upd7810_device::ADDNCX_Dm, 2,11, 8,L0|L1}, /* a6: 0111 0000 1010 0110 */ + {&upd7810_device::ADDNCX_Hm, 2,11, 8,L0|L1}, /* a7: 0111 0000 1010 0111 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* a8: 0111 0000 1010 1000 */ + {&upd7810_device::GTAX_B, 2,11,11,L0|L1}, /* a9: 0111 0000 1010 1001 */ + {&upd7810_device::GTAX_D, 2,11,11,L0|L1}, /* aa: 0111 0000 1010 1010 */ + {&upd7810_device::GTAX_H, 2,11,11,L0|L1}, /* ab: 0111 0000 1010 1011 */ + {&upd7810_device::GTAX_Dp, 2,11,11,L0|L1}, /* ac: 0111 0000 1010 1100 */ + {&upd7810_device::GTAX_Hp, 2,11,11,L0|L1}, /* ad: 0111 0000 1010 1101 */ + {&upd7810_device::GTAX_Dm, 2,11,11,L0|L1}, /* ae: 0111 0000 1010 1110 */ + {&upd7810_device::GTAX_Hm, 2,11,11,L0|L1}, /* af: 0111 0000 1010 1111 */ + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* b0: 0111 0000 1011 0000 */ + {&upd7810_device::SUBNBX_B, 2,11,11,L0|L1}, /* b1: 0111 0000 1011 0001 */ + {&upd7810_device::SUBNBX_D, 2,11,11,L0|L1}, /* b2: 0111 0000 1011 0010 */ + {&upd7810_device::SUBNBX_H, 2,11,11,L0|L1}, /* b3: 0111 0000 1011 0011 */ + {&upd7810_device::SUBNBX_Dp, 2,11,11,L0|L1}, /* b4: 0111 0000 1011 0100 */ + {&upd7810_device::SUBNBX_Hp, 2,11,11,L0|L1}, /* b5: 0111 0000 1011 0101 */ + {&upd7810_device::SUBNBX_Dm, 2,11,11,L0|L1}, /* b6: 0111 0000 1011 0110 */ + {&upd7810_device::SUBNBX_Hm, 2,11,11,L0|L1}, /* b7: 0111 0000 1011 0111 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* b8: 0111 0000 1011 1000 */ + {&upd7810_device::LTAX_B, 2,11,11,L0|L1}, /* b9: 0111 0000 1011 1001 */ + {&upd7810_device::LTAX_D, 2,11,11,L0|L1}, /* ba: 0111 0000 1011 1010 */ + {&upd7810_device::LTAX_H, 2,11,11,L0|L1}, /* bb: 0111 0000 1011 1011 */ + {&upd7810_device::LTAX_Dp, 2,11,11,L0|L1}, /* bc: 0111 0000 1011 1100 */ + {&upd7810_device::LTAX_Hp, 2,11,11,L0|L1}, /* bd: 0111 0000 1011 1101 */ + {&upd7810_device::LTAX_Dm, 2,11,11,L0|L1}, /* be: 0111 0000 1011 1110 */ + {&upd7810_device::LTAX_Hm, 2,11,11,L0|L1}, /* bf: 0111 0000 1011 1111 */ + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* c0: 0111 0000 1100 0000 */ + {&upd7810_device::ADDX_B, 2,11, 8,L0|L1}, /* c1: 0111 0000 1100 0001 */ + {&upd7810_device::ADDX_D, 2,11, 8,L0|L1}, /* c2: 0111 0000 1100 0010 */ + {&upd7810_device::ADDX_H, 2,11, 8,L0|L1}, /* c3: 0111 0000 1100 0011 */ + {&upd7810_device::ADDX_Dp, 2,11, 8,L0|L1}, /* c4: 0111 0000 1100 0100 */ + {&upd7810_device::ADDX_Hp, 2,11, 8,L0|L1}, /* c5: 0111 0000 1100 0101 */ + {&upd7810_device::ADDX_Dm, 2,11, 8,L0|L1}, /* c6: 0111 0000 1100 0110 */ + {&upd7810_device::ADDX_Hm, 2,11, 8,L0|L1}, /* c7: 0111 0000 1100 0111 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* c8: 0111 0000 1100 1000 */ + {&upd7810_device::ONAX_B, 2,11, 8,L0|L1}, /* c9: 0111 0000 1100 1001 */ + {&upd7810_device::ONAX_D, 2,11, 8,L0|L1}, /* ca: 0111 0000 1100 1010 */ + {&upd7810_device::ONAX_H, 2,11, 8,L0|L1}, /* cb: 0111 0000 1100 1011 */ + {&upd7810_device::ONAX_Dp, 2,11, 8,L0|L1}, /* cc: 0111 0000 1100 1100 */ + {&upd7810_device::ONAX_Hp, 2,11, 8,L0|L1}, /* cd: 0111 0000 1100 1101 */ + {&upd7810_device::ONAX_Dm, 2,11, 8,L0|L1}, /* ce: 0111 0000 1100 1110 */ + {&upd7810_device::ONAX_Hm, 2,11, 8,L0|L1}, /* cf: 0111 0000 1100 1111 */ + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* d0: 0111 0000 1101 0000 */ + {&upd7810_device::ADCX_B, 2,11, 8,L0|L1}, /* d1: 0111 0000 1101 0001 */ + {&upd7810_device::ADCX_D, 2,11, 8,L0|L1}, /* d2: 0111 0000 1101 0010 */ + {&upd7810_device::ADCX_H, 2,11, 8,L0|L1}, /* d3: 0111 0000 1101 0011 */ + {&upd7810_device::ADCX_Dp, 2,11, 8,L0|L1}, /* d4: 0111 0000 1101 0100 */ + {&upd7810_device::ADCX_Hp, 2,11, 8,L0|L1}, /* d5: 0111 0000 1101 0101 */ + {&upd7810_device::ADCX_Dm, 2,11, 8,L0|L1}, /* d6: 0111 0000 1101 0110 */ + {&upd7810_device::ADCX_Hm, 2,11, 8,L0|L1}, /* d7: 0111 0000 1101 0111 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* d8: 0111 0000 1101 1000 */ + {&upd7810_device::OFFAX_B, 2,11, 8,L0|L1}, /* d9: 0111 0000 1101 1001 */ + {&upd7810_device::OFFAX_D, 2,11, 8,L0|L1}, /* da: 0111 0000 1101 1010 */ + {&upd7810_device::OFFAX_H, 2,11, 8,L0|L1}, /* db: 0111 0000 1101 1011 */ + {&upd7810_device::OFFAX_Dp, 2,11, 8,L0|L1}, /* dc: 0111 0000 1101 1100 */ + {&upd7810_device::OFFAX_Hp, 2,11, 8,L0|L1}, /* dd: 0111 0000 1101 1101 */ + {&upd7810_device::OFFAX_Dm, 2,11, 8,L0|L1}, /* de: 0111 0000 1101 1110 */ + {&upd7810_device::OFFAX_Hm, 2,11, 8,L0|L1}, /* df: 0111 0000 1101 1111 */ + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* e0: 0111 0000 1110 0000 */ + {&upd7810_device::SUBX_B, 2,11,11,L0|L1}, /* e1: 0111 0000 1110 0001 */ + {&upd7810_device::SUBX_D, 2,11,11,L0|L1}, /* e2: 0111 0000 1110 0010 */ + {&upd7810_device::SUBX_H, 2,11,11,L0|L1}, /* e3: 0111 0000 1110 0011 */ + {&upd7810_device::SUBX_Dp, 2,11,11,L0|L1}, /* e4: 0111 0000 1110 0100 */ + {&upd7810_device::SUBX_Hp, 2,11,11,L0|L1}, /* e5: 0111 0000 1110 0101 */ + {&upd7810_device::SUBX_Dm, 2,11,11,L0|L1}, /* e6: 0111 0000 1110 0110 */ + {&upd7810_device::SUBX_Hm, 2,11,11,L0|L1}, /* e7: 0111 0000 1110 0111 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* e8: 0111 0000 1110 1000 */ + {&upd7810_device::NEAX_B, 2,11,11,L0|L1}, /* e9: 0111 0000 1110 1001 */ + {&upd7810_device::NEAX_D, 2,11,11,L0|L1}, /* ea: 0111 0000 1110 1010 */ + {&upd7810_device::NEAX_H, 2,11,11,L0|L1}, /* eb: 0111 0000 1110 1011 */ + {&upd7810_device::NEAX_Dp, 2,11,11,L0|L1}, /* ec: 0111 0000 1110 1100 */ + {&upd7810_device::NEAX_Hp, 2,11,11,L0|L1}, /* ed: 0111 0000 1110 1101 */ + {&upd7810_device::NEAX_Dm, 2,11,11,L0|L1}, /* ee: 0111 0000 1110 1110 */ + {&upd7810_device::NEAX_Hm, 2,11,11,L0|L1}, /* ef: 0111 0000 1110 1111 */ + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* f0: 0111 0000 1111 0000 */ + {&upd7810_device::SBBX_B, 2,11,11,L0|L1}, /* f1: 0111 0000 1111 0001 */ + {&upd7810_device::SBBX_D, 2,11,11,L0|L1}, /* f2: 0111 0000 1111 0010 */ + {&upd7810_device::SBBX_H, 2,11,11,L0|L1}, /* f3: 0111 0000 1111 0011 */ + {&upd7810_device::SBBX_Dp, 2,11,11,L0|L1}, /* f4: 0111 0000 1111 0100 */ + {&upd7810_device::SBBX_Hp, 2,11,11,L0|L1}, /* f5: 0111 0000 1111 0101 */ + {&upd7810_device::SBBX_Dm, 2,11,11,L0|L1}, /* f6: 0111 0000 1111 0110 */ + {&upd7810_device::SBBX_Hm, 2,11,11,L0|L1}, /* f7: 0111 0000 1111 0111 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* f8: 0111 0000 1111 1000 */ + {&upd7810_device::EQAX_B, 2,11,11,L0|L1}, /* f9: 0111 0000 1111 1001 */ + {&upd7810_device::EQAX_D, 2,11,11,L0|L1}, /* fa: 0111 0000 1111 1010 */ + {&upd7810_device::EQAX_H, 2,11,11,L0|L1}, /* fb: 0111 0000 1111 1011 */ + {&upd7810_device::EQAX_Dp, 2,11,11,L0|L1}, /* fc: 0111 0000 1111 1100 */ + {&upd7810_device::EQAX_Hp, 2,11,11,L0|L1}, /* fd: 0111 0000 1111 1101 */ + {&upd7810_device::EQAX_Dm, 2,11,11,L0|L1}, /* fe: 0111 0000 1111 1110 */ + {&upd7810_device::EQAX_Hm, 2,11,11,L0|L1} /* ff: 0111 0000 1111 1111 */ +}; + +/* prefix 74 */ +const struct upd7810_device::opcode_s upd7810_device::s_op74[256] = +{ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 00: 0111 0100 0000 0000 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 01: 0111 0100 0000 0001 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 02: 0111 0100 0000 0010 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 03: 0111 0100 0000 0011 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 04: 0111 0100 0000 0100 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 05: 0111 0100 0000 0101 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 06: 0111 0100 0000 0110 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 07: 0111 0100 0000 0111 */ + {&upd7810_device::ANI_V_xx, 3,11,11,L0|L1}, /* 08: 0111 0100 0000 1000 xxxx xxxx */ + {&upd7810_device::ANI_A_xx, 3,11,11,L0|L1}, /* 09: 0111 0100 0000 1001 xxxx xxxx */ + {&upd7810_device::ANI_B_xx, 3,11,11,L0|L1}, /* 0a: 0111 0100 0000 1010 xxxx xxxx */ + {&upd7810_device::ANI_C_xx, 3,11,11,L0|L1}, /* 0b: 0111 0100 0000 1011 xxxx xxxx */ + {&upd7810_device::ANI_D_xx, 3,11,11,L0|L1}, /* 0c: 0111 0100 0000 1100 xxxx xxxx */ + {&upd7810_device::ANI_E_xx, 3,11,11,L0|L1}, /* 0d: 0111 0100 0000 1101 xxxx xxxx */ + {&upd7810_device::ANI_H_xx, 3,11,11,L0|L1}, /* 0e: 0111 0100 0000 1110 xxxx xxxx */ + {&upd7810_device::ANI_L_xx, 3,11,11,L0|L1}, /* 0f: 0111 0100 0000 1111 xxxx xxxx */ + + {&upd7810_device::XRI_V_xx, 3,11,11,L0|L1}, /* 10: 0111 0100 0001 0000 xxxx xxxx */ + {&upd7810_device::XRI_A_xx, 3,11,11,L0|L1}, /* 11: 0111 0100 0001 0001 xxxx xxxx */ + {&upd7810_device::XRI_B_xx, 3,11,11,L0|L1}, /* 12: 0111 0100 0001 0010 xxxx xxxx */ + {&upd7810_device::XRI_C_xx, 3,11,11,L0|L1}, /* 13: 0111 0100 0001 0011 xxxx xxxx */ + {&upd7810_device::XRI_D_xx, 3,11,11,L0|L1}, /* 14: 0111 0100 0001 0100 xxxx xxxx */ + {&upd7810_device::XRI_E_xx, 3,11,11,L0|L1}, /* 15: 0111 0100 0001 0101 xxxx xxxx */ + {&upd7810_device::XRI_H_xx, 3,11,11,L0|L1}, /* 16: 0111 0100 0001 0110 xxxx xxxx */ + {&upd7810_device::XRI_L_xx, 3,11,11,L0|L1}, /* 17: 0111 0100 0001 0111 xxxx xxxx */ + {&upd7810_device::ORI_V_xx, 3,11,11,L0|L1}, /* 18: 0111 0100 0001 1000 xxxx xxxx */ + {&upd7810_device::ORI_A_xx, 3,11,11,L0|L1}, /* 19: 0111 0100 0001 1001 xxxx xxxx */ + {&upd7810_device::ORI_B_xx, 3,11,11,L0|L1}, /* 1a: 0111 0100 0001 1010 xxxx xxxx */ + {&upd7810_device::ORI_C_xx, 3,11,11,L0|L1}, /* 1b: 0111 0100 0001 1011 xxxx xxxx */ + {&upd7810_device::ORI_D_xx, 3,11,11,L0|L1}, /* 1c: 0111 0100 0001 1100 xxxx xxxx */ + {&upd7810_device::ORI_E_xx, 3,11,11,L0|L1}, /* 1d: 0111 0100 0001 1101 xxxx xxxx */ + {&upd7810_device::ORI_H_xx, 3,11,11,L0|L1}, /* 1e: 0111 0100 0001 1110 xxxx xxxx */ + {&upd7810_device::ORI_L_xx, 3,11,11,L0|L1}, /* 1f: 0111 0100 0001 1111 xxxx xxxx */ + + {&upd7810_device::ADINC_V_xx, 3,11,11,L0|L1}, /* 20: 0111 0100 0010 0000 xxxx xxxx */ + {&upd7810_device::ADINC_A_xx, 3,11,11,L0|L1}, /* 21: 0111 0100 0010 0001 xxxx xxxx */ + {&upd7810_device::ADINC_B_xx, 3,11,11,L0|L1}, /* 22: 0111 0100 0010 0010 xxxx xxxx */ + {&upd7810_device::ADINC_C_xx, 3,11,11,L0|L1}, /* 23: 0111 0100 0010 0011 xxxx xxxx */ + {&upd7810_device::ADINC_D_xx, 3,11,11,L0|L1}, /* 24: 0111 0100 0010 0100 xxxx xxxx */ + {&upd7810_device::ADINC_E_xx, 3,11,11,L0|L1}, /* 25: 0111 0100 0010 0101 xxxx xxxx */ + {&upd7810_device::ADINC_H_xx, 3,11,11,L0|L1}, /* 26: 0111 0100 0010 0110 xxxx xxxx */ + {&upd7810_device::ADINC_L_xx, 3,11,11,L0|L1}, /* 27: 0111 0100 0010 0111 xxxx xxxx */ + {&upd7810_device::GTI_V_xx, 3,11,11,L0|L1}, /* 28: 0111 0100 0010 1000 xxxx xxxx */ + {&upd7810_device::GTI_A_xx, 3,11,11,L0|L1}, /* 29: 0111 0100 0010 1001 xxxx xxxx */ + {&upd7810_device::GTI_B_xx, 3,11,11,L0|L1}, /* 2a: 0111 0100 0010 1010 xxxx xxxx */ + {&upd7810_device::GTI_C_xx, 3,11,11,L0|L1}, /* 2b: 0111 0100 0010 1011 xxxx xxxx */ + {&upd7810_device::GTI_D_xx, 3,11,11,L0|L1}, /* 2c: 0111 0100 0010 1100 xxxx xxxx */ + {&upd7810_device::GTI_E_xx, 3,11,11,L0|L1}, /* 2d: 0111 0100 0010 1101 xxxx xxxx */ + {&upd7810_device::GTI_H_xx, 3,11,11,L0|L1}, /* 2e: 0111 0100 0010 1110 xxxx xxxx */ + {&upd7810_device::GTI_L_xx, 3,11,11,L0|L1}, /* 2f: 0111 0100 0010 1111 xxxx xxxx */ + + {&upd7810_device::SUINB_V_xx, 3,11,11,L0|L1}, /* 30: 0111 0100 0011 0000 xxxx xxxx */ + {&upd7810_device::SUINB_A_xx, 3,11,11,L0|L1}, /* 31: 0111 0100 0011 0001 xxxx xxxx */ + {&upd7810_device::SUINB_B_xx, 3,11,11,L0|L1}, /* 32: 0111 0100 0011 0010 xxxx xxxx */ + {&upd7810_device::SUINB_C_xx, 3,11,11,L0|L1}, /* 33: 0111 0100 0011 0011 xxxx xxxx */ + {&upd7810_device::SUINB_D_xx, 3,11,11,L0|L1}, /* 34: 0111 0100 0011 0100 xxxx xxxx */ + {&upd7810_device::SUINB_E_xx, 3,11,11,L0|L1}, /* 35: 0111 0100 0011 0101 xxxx xxxx */ + {&upd7810_device::SUINB_H_xx, 3,11,11,L0|L1}, /* 36: 0111 0100 0011 0110 xxxx xxxx */ + {&upd7810_device::SUINB_L_xx, 3,11,11,L0|L1}, /* 37: 0111 0100 0011 0111 xxxx xxxx */ + {&upd7810_device::LTI_V_xx, 3,11,11,L0|L1}, /* 38: 0111 0100 0011 1000 xxxx xxxx */ + {&upd7810_device::LTI_A_xx, 3,11,11,L0|L1}, /* 39: 0111 0100 0011 1001 xxxx xxxx */ + {&upd7810_device::LTI_B_xx, 3,11,11,L0|L1}, /* 3a: 0111 0100 0011 1010 xxxx xxxx */ + {&upd7810_device::LTI_C_xx, 3,11,11,L0|L1}, /* 3b: 0111 0100 0011 1011 xxxx xxxx */ + {&upd7810_device::LTI_D_xx, 3,11,11,L0|L1}, /* 3c: 0111 0100 0011 1100 xxxx xxxx */ + {&upd7810_device::LTI_E_xx, 3,11,11,L0|L1}, /* 3d: 0111 0100 0011 1101 xxxx xxxx */ + {&upd7810_device::LTI_H_xx, 3,11,11,L0|L1}, /* 3e: 0111 0100 0011 1110 xxxx xxxx */ + {&upd7810_device::LTI_L_xx, 3,11,11,L0|L1}, /* 3f: 0111 0100 0011 1111 xxxx xxxx */ + + {&upd7810_device::ADI_V_xx, 3,11,11,L0|L1}, /* 40: 0111 0100 0100 0000 xxxx xxxx */ + {&upd7810_device::ADI_A_xx, 3,11,11,L0|L1}, /* 41: 0111 0100 0100 0001 xxxx xxxx */ + {&upd7810_device::ADI_B_xx, 3,11,11,L0|L1}, /* 42: 0111 0100 0100 0010 xxxx xxxx */ + {&upd7810_device::ADI_C_xx, 3,11,11,L0|L1}, /* 43: 0111 0100 0100 0011 xxxx xxxx */ + {&upd7810_device::ADI_D_xx, 3,11,11,L0|L1}, /* 44: 0111 0100 0100 0100 xxxx xxxx */ + {&upd7810_device::ADI_E_xx, 3,11,11,L0|L1}, /* 45: 0111 0100 0100 0101 xxxx xxxx */ + {&upd7810_device::ADI_H_xx, 3,11,11,L0|L1}, /* 46: 0111 0100 0100 0110 xxxx xxxx */ + {&upd7810_device::ADI_L_xx, 3,11,11,L0|L1}, /* 47: 0111 0100 0100 0111 xxxx xxxx */ + {&upd7810_device::ONI_V_xx, 3,11,11,L0|L1}, /* 48: 0111 0100 0100 1000 xxxx xxxx */ + {&upd7810_device::ONI_A_xx, 3,11,11,L0|L1}, /* 49: 0111 0100 0100 1001 xxxx xxxx */ + {&upd7810_device::ONI_B_xx, 3,11,11,L0|L1}, /* 4a: 0111 0100 0100 1010 xxxx xxxx */ + {&upd7810_device::ONI_C_xx, 3,11,11,L0|L1}, /* 4b: 0111 0100 0100 1011 xxxx xxxx */ + {&upd7810_device::ONI_D_xx, 3,11,11,L0|L1}, /* 4c: 0111 0100 0100 1100 xxxx xxxx */ + {&upd7810_device::ONI_E_xx, 3,11,11,L0|L1}, /* 4d: 0111 0100 0100 1101 xxxx xxxx */ + {&upd7810_device::ONI_H_xx, 3,11,11,L0|L1}, /* 4e: 0111 0100 0100 1110 xxxx xxxx */ + {&upd7810_device::ONI_L_xx, 3,11,11,L0|L1}, /* 4f: 0111 0100 0100 1111 xxxx xxxx */ + + {&upd7810_device::ACI_V_xx, 3,11,11,L0|L1}, /* 50: 0111 0100 0101 0000 xxxx xxxx */ + {&upd7810_device::ACI_A_xx, 3,11,11,L0|L1}, /* 51: 0111 0100 0101 0001 xxxx xxxx */ + {&upd7810_device::ACI_B_xx, 3,11,11,L0|L1}, /* 52: 0111 0100 0101 0010 xxxx xxxx */ + {&upd7810_device::ACI_C_xx, 3,11,11,L0|L1}, /* 53: 0111 0100 0101 0011 xxxx xxxx */ + {&upd7810_device::ACI_D_xx, 3,11,11,L0|L1}, /* 54: 0111 0100 0101 0100 xxxx xxxx */ + {&upd7810_device::ACI_E_xx, 3,11,11,L0|L1}, /* 55: 0111 0100 0101 0101 xxxx xxxx */ + {&upd7810_device::ACI_H_xx, 3,11,11,L0|L1}, /* 56: 0111 0100 0101 0110 xxxx xxxx */ + {&upd7810_device::ACI_L_xx, 3,11,11,L0|L1}, /* 57: 0111 0100 0101 0111 xxxx xxxx */ + {&upd7810_device::OFFI_V_xx, 3,11,11,L0|L1}, /* 58: 0111 0100 0101 1000 xxxx xxxx */ + {&upd7810_device::OFFI_A_xx, 3,11,11,L0|L1}, /* 59: 0111 0100 0101 1001 xxxx xxxx */ + {&upd7810_device::OFFI_B_xx, 3,11,11,L0|L1}, /* 5a: 0111 0100 0101 1010 xxxx xxxx */ + {&upd7810_device::OFFI_C_xx, 3,11,11,L0|L1}, /* 5b: 0111 0100 0101 1011 xxxx xxxx */ + {&upd7810_device::OFFI_D_xx, 3,11,11,L0|L1}, /* 5c: 0111 0100 0101 1100 xxxx xxxx */ + {&upd7810_device::OFFI_E_xx, 3,11,11,L0|L1}, /* 5d: 0111 0100 0101 1101 xxxx xxxx */ + {&upd7810_device::OFFI_H_xx, 3,11,11,L0|L1}, /* 5e: 0111 0100 0101 1110 xxxx xxxx */ + {&upd7810_device::OFFI_L_xx, 3,11,11,L0|L1}, /* 5f: 0111 0100 0101 1111 xxxx xxxx */ + + {&upd7810_device::SUI_V_xx, 3,11,11,L0|L1}, /* 60: 0111 0100 0110 0000 xxxx xxxx */ + {&upd7810_device::SUI_A_xx, 3,11,11,L0|L1}, /* 61: 0111 0100 0110 0001 xxxx xxxx */ + {&upd7810_device::SUI_B_xx, 3,11,11,L0|L1}, /* 62: 0111 0100 0110 0010 xxxx xxxx */ + {&upd7810_device::SUI_C_xx, 3,11,11,L0|L1}, /* 63: 0111 0100 0110 0011 xxxx xxxx */ + {&upd7810_device::SUI_D_xx, 3,11,11,L0|L1}, /* 64: 0111 0100 0110 0100 xxxx xxxx */ + {&upd7810_device::SUI_E_xx, 3,11,11,L0|L1}, /* 65: 0111 0100 0110 0101 xxxx xxxx */ + {&upd7810_device::SUI_H_xx, 3,11,11,L0|L1}, /* 66: 0111 0100 0110 0110 xxxx xxxx */ + {&upd7810_device::SUI_L_xx, 3,11,11,L0|L1}, /* 67: 0111 0100 0110 0111 xxxx xxxx */ + {&upd7810_device::NEI_V_xx, 3,11,11,L0|L1}, /* 68: 0111 0100 0110 1000 xxxx xxxx */ + {&upd7810_device::NEI_A_xx, 3,11,11,L0|L1}, /* 69: 0111 0100 0110 1001 xxxx xxxx */ + {&upd7810_device::NEI_B_xx, 3,11,11,L0|L1}, /* 6a: 0111 0100 0110 1010 xxxx xxxx */ + {&upd7810_device::NEI_C_xx, 3,11,11,L0|L1}, /* 6b: 0111 0100 0110 1011 xxxx xxxx */ + {&upd7810_device::NEI_D_xx, 3,11,11,L0|L1}, /* 6c: 0111 0100 0110 1100 xxxx xxxx */ + {&upd7810_device::NEI_E_xx, 3,11,11,L0|L1}, /* 6d: 0111 0100 0110 1101 xxxx xxxx */ + {&upd7810_device::NEI_H_xx, 3,11,11,L0|L1}, /* 6e: 0111 0100 0110 1110 xxxx xxxx */ + {&upd7810_device::NEI_L_xx, 3,11,11,L0|L1}, /* 6f: 0111 0100 0110 1111 xxxx xxxx */ + + {&upd7810_device::SBI_V_xx, 3,11,11,L0|L1}, /* 70: 0111 0100 0111 0000 xxxx xxxx */ + {&upd7810_device::SBI_A_xx, 3,11,11,L0|L1}, /* 71: 0111 0100 0111 0001 xxxx xxxx */ + {&upd7810_device::SBI_B_xx, 3,11,11,L0|L1}, /* 72: 0111 0100 0111 0010 xxxx xxxx */ + {&upd7810_device::SBI_C_xx, 3,11,11,L0|L1}, /* 73: 0111 0100 0111 0011 xxxx xxxx */ + {&upd7810_device::SBI_D_xx, 3,11,11,L0|L1}, /* 74: 0111 0100 0111 0100 xxxx xxxx */ + {&upd7810_device::SBI_E_xx, 3,11,11,L0|L1}, /* 75: 0111 0100 0111 0101 xxxx xxxx */ + {&upd7810_device::SBI_H_xx, 3,11,11,L0|L1}, /* 76: 0111 0100 0111 0110 xxxx xxxx */ + {&upd7810_device::SBI_L_xx, 3,11,11,L0|L1}, /* 77: 0111 0100 0111 0111 xxxx xxxx */ + {&upd7810_device::EQI_V_xx, 3,11,11,L0|L1}, /* 78: 0111 0100 0111 1000 xxxx xxxx */ + {&upd7810_device::EQI_A_xx, 3,11,11,L0|L1}, /* 79: 0111 0100 0111 1001 xxxx xxxx */ + {&upd7810_device::EQI_B_xx, 3,11,11,L0|L1}, /* 7a: 0111 0100 0111 1010 xxxx xxxx */ + {&upd7810_device::EQI_C_xx, 3,11,11,L0|L1}, /* 7b: 0111 0100 0111 1011 xxxx xxxx */ + {&upd7810_device::EQI_D_xx, 3,11,11,L0|L1}, /* 7c: 0111 0100 0111 1100 xxxx xxxx */ + {&upd7810_device::EQI_E_xx, 3,11,11,L0|L1}, /* 7d: 0111 0100 0111 1101 xxxx xxxx */ + {&upd7810_device::EQI_H_xx, 3,11,11,L0|L1}, /* 7e: 0111 0100 0111 1110 xxxx xxxx */ + {&upd7810_device::EQI_L_xx, 3,11,11,L0|L1}, /* 7f: 0111 0100 0111 1111 xxxx xxxx */ + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 80: 0111 0100 1000 0000 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 81: 0111 0100 1000 0001 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 82: 0111 0100 1000 0010 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 83: 0111 0100 1000 0011 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 84: 0111 0100 1000 0100 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 85: 0111 0100 1000 0101 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 86: 0111 0100 1000 0110 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 87: 0111 0100 1000 0111 */ + {&upd7810_device::ANAW_wa, 3,14,11,L0|L1}, /* 88: 0111 0100 1000 1000 oooo oooo */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 89: 0111 0100 1000 1001 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 8a: 0111 0100 1000 1010 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 8b: 0111 0100 1000 1011 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 8c: 0111 0100 1000 1100 */ + {&upd7810_device::DAN_EA_BC, 2,11,11,L0|L1}, /* 8d: 0111 0100 1000 1101 */ + {&upd7810_device::DAN_EA_DE, 2,11,11,L0|L1}, /* 8e: 0111 0100 1000 1110 */ + {&upd7810_device::DAN_EA_HL, 2,11,11,L0|L1}, /* 8f: 0111 0100 1000 1111 */ + + {&upd7810_device::XRAW_wa, 3,14,11,L0|L1}, /* 90: 0111 0100 1001 0000 oooo oooo */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 91: 0111 0100 1001 0001 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 92: 0111 0100 1001 0010 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 93: 0111 0100 1001 0011 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 94: 0111 0100 1001 0100 */ + {&upd7810_device::DXR_EA_BC, 2,11,11,L0|L1}, /* 95: 0111 0100 1001 0101 */ + {&upd7810_device::DXR_EA_DE, 2,11,11,L0|L1}, /* 96: 0111 0100 1001 0110 */ + {&upd7810_device::DXR_EA_HL, 2,11,11,L0|L1}, /* 97: 0111 0100 1001 0111 */ + {&upd7810_device::ORAW_wa, 3,14,11,L0|L1}, /* 98: 0111 0100 1001 1000 oooo oooo */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 99: 0111 0100 1001 1001 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 9a: 0111 0100 1001 1010 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 9b: 0111 0100 1001 1011 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* 9c: 0111 0100 1001 1100 */ + {&upd7810_device::DOR_EA_BC, 2,11,11,L0|L1}, /* 9d: 0111 0100 1001 1101 */ + {&upd7810_device::DOR_EA_DE, 2,11,11,L0|L1}, /* 9e: 0111 0100 1001 1110 */ + {&upd7810_device::DOR_EA_HL, 2,11,11,L0|L1}, /* 9f: 0111 0100 1001 1111 */ + + {&upd7810_device::ADDNCW_wa, 3,14,11,L0|L1}, /* a0: 0111 0100 1010 0000 oooo oooo */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* a1: 0111 0100 1010 0001 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* a2: 0111 0100 1010 0010 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* a3: 0111 0100 1010 0011 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* a4: 0111 0100 1010 0100 */ + {&upd7810_device::DADDNC_EA_BC, 2,11,11,L0|L1}, /* a5: 0111 0100 1010 0101 */ + {&upd7810_device::DADDNC_EA_DE, 2,11,11,L0|L1}, /* a6: 0111 0100 1010 0110 */ + {&upd7810_device::DADDNC_EA_HL, 2,11,11,L0|L1}, /* a7: 0111 0100 1010 0111 */ + {&upd7810_device::GTAW_wa, 3,14,11,L0|L1}, /* a8: 0111 0100 1010 1000 oooo oooo */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* a9: 0111 0100 1010 1001 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* aa: 0111 0100 1010 1010 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* ab: 0111 0100 1010 1011 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* ac: 0111 0100 1010 1100 */ + {&upd7810_device::DGT_EA_BC, 2,11,11,L0|L1}, /* ad: 0111 0100 1010 1101 */ + {&upd7810_device::DGT_EA_DE, 2,11,11,L0|L1}, /* ae: 0111 0100 1010 1110 */ + {&upd7810_device::DGT_EA_HL, 2,11,11,L0|L1}, /* af: 0111 0100 1010 1111 */ + + {&upd7810_device::SUBNBW_wa, 3,14,11,L0|L1}, /* b0: 0111 0100 1011 0000 oooo oooo */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* b1: 0111 0100 1011 0001 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* b2: 0111 0100 1011 0010 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* b3: 0111 0100 1011 0011 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* b4: 0111 0100 1011 0100 */ + {&upd7810_device::DSUBNB_EA_BC, 2,11,11,L0|L1}, /* b5: 0111 0100 1011 0101 */ + {&upd7810_device::DSUBNB_EA_DE, 2,11,11,L0|L1}, /* b6: 0111 0100 1011 0110 */ + {&upd7810_device::DSUBNB_EA_HL, 2,11,11,L0|L1}, /* b7: 0111 0100 1011 0111 */ + {&upd7810_device::LTAW_wa, 3,14,11,L0|L1}, /* b8: 0111 0100 1011 1000 oooo oooo */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* b9: 0111 0100 1011 1001 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* ba: 0111 0100 1011 1010 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* bb: 0111 0100 1011 1011 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* bc: 0111 0100 1011 1100 */ + {&upd7810_device::DLT_EA_BC, 2,11,11,L0|L1}, /* bd: 0111 0100 1011 1101 */ + {&upd7810_device::DLT_EA_DE, 2,11,11,L0|L1}, /* be: 0111 0100 1011 1110 */ + {&upd7810_device::DLT_EA_HL, 2,11,11,L0|L1}, /* bf: 0111 0100 1011 1111 */ + + {&upd7810_device::ADDW_wa, 3,14,11,L0|L1}, /* c0: 0111 0100 1100 0000 oooo oooo */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* c1: 0111 0100 1100 0001 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* c2: 0111 0100 1100 0010 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* c3: 0111 0100 1100 0011 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* c4: 0111 0100 1100 0100 */ + {&upd7810_device::DADD_EA_BC, 2,11,11,L0|L1}, /* c5: 0111 0100 1100 0101 */ + {&upd7810_device::DADD_EA_DE, 2,11,11,L0|L1}, /* c6: 0111 0100 1100 0110 */ + {&upd7810_device::DADD_EA_HL, 2,11,11,L0|L1}, /* c7: 0111 0100 1100 0111 */ + {&upd7810_device::ONAW_wa, 3,14,11,L0|L1}, /* c8: 0111 0100 1100 1000 oooo oooo */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* c9: 0111 0100 1100 1001 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* ca: 0111 0100 1100 1010 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* cb: 0111 0100 1100 1011 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* cc: 0111 0100 1100 1100 */ + {&upd7810_device::DON_EA_BC, 2,11,11,L0|L1}, /* cd: 0111 0100 1100 1101 */ + {&upd7810_device::DON_EA_DE, 2,11,11,L0|L1}, /* ce: 0111 0100 1100 1110 */ + {&upd7810_device::DON_EA_HL, 2,11,11,L0|L1}, /* cf: 0111 0100 1100 1111 */ + + {&upd7810_device::ADCW_wa, 3,14,11,L0|L1}, /* d0: 0111 0100 1101 0000 oooo oooo */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* d1: 0111 0100 1101 0001 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* d2: 0111 0100 1101 0010 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* d3: 0111 0100 1101 0011 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* d4: 0111 0100 1101 0100 */ + {&upd7810_device::DADC_EA_BC, 2,11,11,L0|L1}, /* d5: 0111 0100 1101 0101 */ + {&upd7810_device::DADC_EA_DE, 2,11,11,L0|L1}, /* d6: 0111 0100 1101 0110 */ + {&upd7810_device::DADC_EA_HL, 2,11,11,L0|L1}, /* d7: 0111 0100 1101 0111 */ + {&upd7810_device::OFFAW_wa, 3,14,11,L0|L1}, /* d8: 0111 0100 1101 1000 oooo oooo */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* d9: 0111 0100 1101 1001 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* da: 0111 0100 1101 1010 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* db: 0111 0100 1101 1011 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* dc: 0111 0100 1101 1100 */ + {&upd7810_device::DOFF_EA_BC, 2,11,11,L0|L1}, /* dd: 0111 0100 1101 1101 */ + {&upd7810_device::DOFF_EA_DE, 2,11,11,L0|L1}, /* de: 0111 0100 1101 1110 */ + {&upd7810_device::DOFF_EA_HL, 2,11,11,L0|L1}, /* df: 0111 0100 1101 1111 */ + + {&upd7810_device::SUBW_wa, 3,14,11,L0|L1}, /* e0: 0111 0100 1110 0000 oooo oooo */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* e1: 0111 0100 1110 0001 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* e2: 0111 0100 1110 0010 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* e3: 0111 0100 1110 0011 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* e4: 0111 0100 1110 0100 */ + {&upd7810_device::DSUB_EA_BC, 2,11,11,L0|L1}, /* e5: 0111 0100 1110 0101 */ + {&upd7810_device::DSUB_EA_DE, 2,11,11,L0|L1}, /* e6: 0111 0100 1110 0110 */ + {&upd7810_device::DSUB_EA_HL, 2,11,11,L0|L1}, /* e7: 0111 0100 1110 0111 */ + {&upd7810_device::NEAW_wa, 3,14,11,L0|L1}, /* e8: 0111 0100 1110 1000 oooo oooo */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* e9: 0111 0100 1110 1001 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* ea: 0111 0100 1110 1010 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* eb: 0111 0100 1110 1011 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* ec: 0111 0100 1110 1100 */ + {&upd7810_device::DNE_EA_BC, 2,11,11,L0|L1}, /* ed: 0111 0100 1110 1101 */ + {&upd7810_device::DNE_EA_DE, 2,11,11,L0|L1}, /* ee: 0111 0100 1110 1110 */ + {&upd7810_device::DNE_EA_HL, 2,11,11,L0|L1}, /* ef: 0111 0100 1110 1111 */ + + {&upd7810_device::SBBW_wa, 3,14,11,L0|L1}, /* f0: 0111 0100 1111 0000 oooo oooo */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* f1: 0111 0100 1111 0001 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* f2: 0111 0100 1111 0010 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* f3: 0111 0100 1111 0011 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* f4: 0111 0100 1111 0100 */ + {&upd7810_device::DSBB_EA_BC, 2,11,11,L0|L1}, /* f5: 0111 0100 1111 0101 */ + {&upd7810_device::DSBB_EA_DE, 2,11,11,L0|L1}, /* f6: 0111 0100 1111 0110 */ + {&upd7810_device::DSBB_EA_HL, 2,11,11,L0|L1}, /* f7: 0111 0100 1111 0111 */ + {&upd7810_device::EQAW_wa, 3,14,11,L0|L1}, /* f8: 0111 0100 1111 1000 oooo oooo */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* f9: 0111 0100 1111 1001 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* fa: 0111 0100 1111 1010 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* fb: 0111 0100 1111 1011 */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, /* fc: 0111 0100 1111 1100 */ + {&upd7810_device::DEQ_EA_BC, 2,11,11,L0|L1}, /* fd: 0111 0100 1111 1101 */ + {&upd7810_device::DEQ_EA_DE, 2,11,11,L0|L1}, /* fe: 0111 0100 1111 1110 */ + {&upd7810_device::DEQ_EA_HL, 2,11,11,L0|L1} /* ff: 0111 0100 1111 1111 */ +}; + +/* main opcodes */ +const struct upd7810_device::opcode_s upd7810_device::s_opXX_7810[256] = +{ + {&upd7810_device::NOP, 1, 4, 4,L0|L1}, /* 00: 0000 0000 */ + {&upd7810_device::LDAW_wa, 2,10,10,L0|L1}, /* 01: 0000 0001 oooo oooo */ + {&upd7810_device::INX_SP, 1, 7, 7,L0|L1}, /* 02: 0000 0010 */ + {&upd7810_device::DCX_SP, 1, 7, 7,L0|L1}, /* 03: 0000 0011 */ + {&upd7810_device::LXI_S_w, 3,10,10,L0|L1}, /* 04: 0000 0100 llll llll hhhh hhhh */ + {&upd7810_device::ANIW_wa_xx, 3,19,19,L0|L1}, /* 05: 0000 0101 oooo oooo xxxx xxxx */ + {&upd7810_device::illegal, 1, 4, 4,L0|L1}, /* 06: */ + {&upd7810_device::ANI_A_xx, 2, 7, 7,L0|L1}, /* 07: 0000 0111 xxxx xxxx */ + {&upd7810_device::MOV_A_EAH, 1, 4, 4,L0|L1}, /* 08: 0000 1000 */ + {&upd7810_device::MOV_A_EAL, 1, 4, 4,L0|L1}, /* 09: 0000 1001 */ + {&upd7810_device::MOV_A_B, 1, 4, 4,L0|L1}, /* 0a: 0000 1010 */ + {&upd7810_device::MOV_A_C, 1, 4, 4,L0|L1}, /* 0b: 0000 1011 */ + {&upd7810_device::MOV_A_D, 1, 4, 4,L0|L1}, /* 0c: 0000 1100 */ + {&upd7810_device::MOV_A_E, 1, 4, 4,L0|L1}, /* 0d: 0000 1101 */ + {&upd7810_device::MOV_A_H, 1, 4, 4,L0|L1}, /* 0e: 0000 1110 */ + {&upd7810_device::MOV_A_L, 1, 4, 4,L0|L1}, /* 0f: 0000 1111 */ + + {&upd7810_device::EXA, 1, 4, 4,L0|L1}, /* 10: 0001 0000 */ + {&upd7810_device::EXX, 1, 4, 4,L0|L1}, /* 11: 0001 0001 */ + {&upd7810_device::INX_BC, 1, 7, 7,L0|L1}, /* 12: 0001 0010 */ + {&upd7810_device::DCX_BC, 1, 7, 7,L0|L1}, /* 13: 0001 0011 */ + {&upd7810_device::LXI_B_w, 3,10,10,L0|L1}, /* 14: 0001 0100 llll llll hhhh hhhh */ + {&upd7810_device::ORIW_wa_xx, 3,19,19,L0|L1}, /* 15: 0001 0101 oooo oooo xxxx xxxx */ + {&upd7810_device::XRI_A_xx, 2, 7, 7,L0|L1}, /* 16: 0001 0110 xxxx xxxx */ + {&upd7810_device::ORI_A_xx, 2, 7, 7,L0|L1}, /* 17: 0001 0111 xxxx xxxx */ + {&upd7810_device::MOV_EAH_A, 1, 4, 4,L0|L1}, /* 18: 0001 1000 */ + {&upd7810_device::MOV_EAL_A, 1, 4, 4,L0|L1}, /* 19: 0001 1001 */ + {&upd7810_device::MOV_B_A, 1, 4, 4,L0|L1}, /* 1a: 0001 1010 */ + {&upd7810_device::MOV_C_A, 1, 4, 4,L0|L1}, /* 1b: 0001 1011 */ + {&upd7810_device::MOV_D_A, 1, 4, 4,L0|L1}, /* 1c: 0001 1100 */ + {&upd7810_device::MOV_E_A, 1, 4, 4,L0|L1}, /* 1d: 0001 1101 */ + {&upd7810_device::MOV_H_A, 1, 4, 4,L0|L1}, /* 1e: 0001 1110 */ + {&upd7810_device::MOV_L_A, 1, 4, 4,L0|L1}, /* 1f: 0001 1111 */ + + {&upd7810_device::INRW_wa, 2,16,16,L0|L1}, /* 20: 0010 0000 oooo oooo */ + {&upd7810_device::JB, 1, 4, 4,L0|L1}, /* 21: 0010 0001 */ + {&upd7810_device::INX_DE, 1, 7, 7,L0|L1}, /* 22: 0010 0010 */ + {&upd7810_device::DCX_DE, 1, 7, 7,L0|L1}, /* 23: 0010 0011 */ + {&upd7810_device::LXI_D_w, 3,10,10,L0|L1}, /* 24: 0010 0100 llll llll hhhh hhhh */ + {&upd7810_device::GTIW_wa_xx, 3,19,19,L0|L1}, /* 25: 0010 0101 oooo oooo xxxx xxxx */ + {&upd7810_device::ADINC_A_xx, 2, 7, 7,L0|L1}, /* 26: 0010 0110 xxxx xxxx */ + {&upd7810_device::GTI_A_xx, 2, 7, 7,L0|L1}, /* 27: 0010 0111 xxxx xxxx */ + {&upd7810_device::illegal, 1, 4, 4,L0|L1}, /* 28: */ + {&upd7810_device::LDAX_B, 2, 7, 7,L0|L1}, /* 29: 0010 1001 dddd dddd */ + {&upd7810_device::LDAX_D, 2, 7, 7,L0|L1}, /* 2a: 0010 1010 dddd dddd */ + {&upd7810_device::LDAX_H, 2, 7, 7,L0|L1}, /* 2b: 0010 1011 dddd dddd */ + {&upd7810_device::LDAX_Dp, 2, 7, 7,L0|L1}, /* 2c: 0010 1100 dddd dddd */ + {&upd7810_device::LDAX_Hp, 2, 7, 7,L0|L1}, /* 2d: 0010 1101 dddd dddd */ + {&upd7810_device::LDAX_Dm, 2, 7, 7,L0|L1}, /* 2e: 0010 1110 dddd dddd */ + {&upd7810_device::LDAX_Hm, 2, 7, 7,L0|L1}, /* 2f: 0010 1111 dddd dddd */ + + {&upd7810_device::DCRW_wa, 2,16,16,L0|L1}, /* 30: 0011 0000 oooo oooo */ + {&upd7810_device::BLOCK, 1,13,13,L0|L1}, /* 31: 0011 0001 */ /* 7810 */ + {&upd7810_device::INX_HL, 1, 7, 7,L0|L1}, /* 32: 0011 0010 */ + {&upd7810_device::DCX_HL, 1, 7, 7,L0|L1}, /* 33: 0011 0011 */ + {&upd7810_device::LXI_H_w, 3,10,10, L1}, /* 34: 0011 0100 llll llll hhhh hhhh */ + {&upd7810_device::LTIW_wa_xx, 3,19,19,L0|L1}, /* 35: 0011 0101 oooo oooo xxxx xxxx */ + {&upd7810_device::SUINB_A_xx, 2, 7, 7,L0|L1}, /* 36: 0011 0110 xxxx xxxx */ + {&upd7810_device::LTI_A_xx, 2, 7, 7,L0|L1}, /* 37: 0011 0111 xxxx xxxx */ + {&upd7810_device::illegal, 1, 4, 4,L0|L1}, /* 38: */ + {&upd7810_device::STAX_B, 2, 7, 7,L0|L1}, /* 39: 0011 1001 dddd dddd */ + {&upd7810_device::STAX_D, 2, 7, 7,L0|L1}, /* 3a: 0011 1010 dddd dddd */ + {&upd7810_device::STAX_H, 2, 7, 7,L0|L1}, /* 3b: 0011 1011 dddd dddd */ + {&upd7810_device::STAX_Dp, 2, 7, 7,L0|L1}, /* 3c: 0011 1100 dddd dddd */ + {&upd7810_device::STAX_Hp, 2, 7, 7,L0|L1}, /* 3d: 0011 1101 dddd dddd */ + {&upd7810_device::STAX_Dm, 2, 7, 7,L0|L1}, /* 3e: 0011 1110 dddd dddd */ + {&upd7810_device::STAX_Hm, 2, 7, 7,L0|L1}, /* 3f: 0011 1111 dddd dddd */ + + {&upd7810_device::CALL_w, 3,16,16,L0|L1}, /* 40: 0100 0000 llll llll hhhh hhhh */ + {&upd7810_device::INR_A, 1, 4, 4,L0|L1}, /* 41: 0100 0001 */ + {&upd7810_device::INR_B, 1, 4, 4,L0|L1}, /* 42: 0100 0010 */ + {&upd7810_device::INR_C, 1, 4, 4,L0|L1}, /* 43: 0100 0011 */ + {&upd7810_device::LXI_EA_s, 3,10,10,L0|L1}, /* 44: 0100 0100 llll llll hhhh hhhh */ + {&upd7810_device::ONIW_wa_xx, 3,19,19,L0|L1}, /* 45: 0100 0101 oooo oooo xxxx xxxx */ + {&upd7810_device::ADI_A_xx, 2, 7, 7,L0|L1}, /* 46: 0100 0110 xxxx xxxx */ + {&upd7810_device::ONI_A_xx, 2, 7, 7,L0|L1}, /* 47: 0100 0111 xxxx xxxx */ + {&upd7810_device::PRE_48, 1, 0, 0,L0|L1}, /* 48: prefix */ + {&upd7810_device::MVIX_BC_xx, 2,10,10,L0|L1}, /* 49: 0100 1001 xxxx xxxx */ + {&upd7810_device::MVIX_DE_xx, 2,10,10,L0|L1}, /* 4a: 0100 1010 xxxx xxxx */ + {&upd7810_device::MVIX_HL_xx, 2,10,10,L0|L1}, /* 4b: 0100 1011 xxxx xxxx */ + {&upd7810_device::PRE_4C, 1, 0, 0,L0|L1}, /* 4c: prefix */ + {&upd7810_device::PRE_4D, 1, 4, 4,L0|L1}, /* 4d: prefix */ + {&upd7810_device::JRE, 2,10,10,L0|L1}, /* 4e: 0100 111d dddd dddd */ + {&upd7810_device::JRE, 2,10,10,L0|L1}, /* 4f: 0100 111d dddd dddd */ + + {&upd7810_device::EXH, 1, 4, 4,L0|L1}, /* 50: 0101 0000 */ /* 7810 */ + {&upd7810_device::DCR_A, 1, 4, 4,L0|L1}, /* 51: 0101 0001 */ + {&upd7810_device::DCR_B, 1, 4, 4,L0|L1}, /* 52: 0101 0010 */ + {&upd7810_device::DCR_C, 1, 4, 4,L0|L1}, /* 53: 0101 0011 */ + {&upd7810_device::JMP_w, 3,10,10,L0|L1}, /* 54: 0101 0100 llll llll hhhh hhhh */ + {&upd7810_device::OFFIW_wa_xx, 3,19,19,L0|L1}, /* 55: 0101 0101 oooo oooo xxxx xxxx */ + {&upd7810_device::ACI_A_xx, 2, 7, 7,L0|L1}, /* 56: 0101 0110 xxxx xxxx */ + {&upd7810_device::OFFI_A_xx, 2, 7, 7,L0|L1}, /* 57: 0101 0111 xxxx xxxx */ + {&upd7810_device::BIT_0_wa, 2,10,10,L0|L1}, /* 58: 0101 1000 oooo oooo */ /* 7810 */ + {&upd7810_device::BIT_1_wa, 2,10,10,L0|L1}, /* 59: 0101 1001 oooo oooo */ /* 7810 */ + {&upd7810_device::BIT_2_wa, 2,10,10,L0|L1}, /* 5a: 0101 1010 oooo oooo */ /* 7810 */ + {&upd7810_device::BIT_3_wa, 2,10,10,L0|L1}, /* 5b: 0101 1011 oooo oooo */ /* 7810 */ + {&upd7810_device::BIT_4_wa, 2,10,10,L0|L1}, /* 5c: 0101 1100 oooo oooo */ /* 7810 */ + {&upd7810_device::BIT_5_wa, 2,10,10,L0|L1}, /* 5d: 0101 1101 oooo oooo */ /* 7810 */ + {&upd7810_device::BIT_6_wa, 2,10,10,L0|L1}, /* 5e: 0101 1110 oooo oooo */ /* 7810 */ + {&upd7810_device::BIT_7_wa, 2,10,10,L0|L1}, /* 5f: 0101 1111 oooo oooo */ /* 7810 */ + + {&upd7810_device::PRE_60, 1, 0, 0,L0|L1}, /* 60: */ + {&upd7810_device::DAA, 1, 4, 4,L0|L1}, /* 61: 0110 0001 */ + {&upd7810_device::RETI, 1,13,13,L0|L1}, /* 62: 0110 0010 */ + {&upd7810_device::STAW_wa, 2,10,10,L0|L1}, /* 63: 0110 0011 oooo oooo */ + {&upd7810_device::PRE_64, 1, 0, 0,L0|L1}, /* 64: */ + {&upd7810_device::NEIW_wa_xx, 3,19,19,L0|L1}, /* 65: 0110 0101 oooo oooo xxxx xxxx */ + {&upd7810_device::SUI_A_xx, 2, 7, 7,L0|L1}, /* 66: 0110 0110 xxxx xxxx */ + {&upd7810_device::NEI_A_xx, 2, 7, 7,L0|L1}, /* 67: 0110 0111 xxxx xxxx */ + {&upd7810_device::MVI_V_xx, 2, 7, 7,L0|L1}, /* 68: 0110 1000 xxxx xxxx */ + {&upd7810_device::MVI_A_xx, 2, 7, 7,L0 }, /* 69: 0110 1001 xxxx xxxx */ + {&upd7810_device::MVI_B_xx, 2, 7, 7,L0|L1}, /* 6a: 0110 1010 xxxx xxxx */ + {&upd7810_device::MVI_C_xx, 2, 7, 7,L0|L1}, /* 6b: 0110 1011 xxxx xxxx */ + {&upd7810_device::MVI_D_xx, 2, 7, 7,L0|L1}, /* 6c: 0110 1100 xxxx xxxx */ + {&upd7810_device::MVI_E_xx, 2, 7, 7,L0|L1}, /* 6d: 0110 1101 xxxx xxxx */ + {&upd7810_device::MVI_H_xx, 2, 7, 7,L0|L1}, /* 6e: 0110 1110 xxxx xxxx */ + {&upd7810_device::MVI_L_xx, 2, 7, 7, L1}, /* 6f: 0110 1111 xxxx xxxx */ + + {&upd7810_device::PRE_70, 1, 0, 0,L0|L1}, /* 70: */ + {&upd7810_device::MVIW_wa_xx, 3,13,13,L0|L1}, /* 71: 0111 0001 oooo oooo xxxx xxxx */ + {&upd7810_device::SOFTI, 1,16,16,L0|L1}, /* 72: 0111 0010 */ + {&upd7810_device::illegal, 1, 0, 0,L0|L1}, /* 73: */ + {&upd7810_device::PRE_74, 1, 0, 0,L0|L1}, /* 74: prefix */ + {&upd7810_device::EQIW_wa_xx, 3,19,19,L0|L1}, /* 75: 0111 0101 oooo oooo xxxx xxxx */ + {&upd7810_device::SBI_A_xx, 2, 7, 7,L0|L1}, /* 76: 0111 0110 xxxx xxxx */ + {&upd7810_device::EQI_A_xx, 2, 7, 7,L0|L1}, /* 77: 0111 0111 xxxx xxxx */ + {&upd7810_device::CALF, 2,13,13,L0|L1}, /* 78: 0111 1xxx xxxx xxxx */ + {&upd7810_device::CALF, 2,13,13,L0|L1}, /* 79: 0111 1xxx xxxx xxxx */ + {&upd7810_device::CALF, 2,13,13,L0|L1}, /* 7a: 0111 1xxx xxxx xxxx */ + {&upd7810_device::CALF, 2,13,13,L0|L1}, /* 7b: 0111 1xxx xxxx xxxx */ + {&upd7810_device::CALF, 2,13,13,L0|L1}, /* 7c: 0111 1xxx xxxx xxxx */ + {&upd7810_device::CALF, 2,13,13,L0|L1}, /* 7d: 0111 1xxx xxxx xxxx */ + {&upd7810_device::CALF, 2,13,13,L0|L1}, /* 7e: 0111 1xxx xxxx xxxx */ + {&upd7810_device::CALF, 2,13,13,L0|L1}, /* 7f: 0111 1xxx xxxx xxxx */ + + {&upd7810_device::CALT, 1,16,16,L0|L1}, /* 80: 100x xxxx */ + {&upd7810_device::CALT, 1,16,16,L0|L1}, /* 81: 100x xxxx */ + {&upd7810_device::CALT, 1,16,16,L0|L1}, /* 82: 100x xxxx */ + {&upd7810_device::CALT, 1,16,16,L0|L1}, /* 83: 100x xxxx */ + {&upd7810_device::CALT, 1,16,16,L0|L1}, /* 84: 100x xxxx */ + {&upd7810_device::CALT, 1,16,16,L0|L1}, /* 85: 100x xxxx */ + {&upd7810_device::CALT, 1,16,16,L0|L1}, /* 86: 100x xxxx */ + {&upd7810_device::CALT, 1,16,16,L0|L1}, /* 87: 100x xxxx */ + {&upd7810_device::CALT, 1,16,16,L0|L1}, /* 88: 100x xxxx */ + {&upd7810_device::CALT, 1,16,16,L0|L1}, /* 89: 100x xxxx */ + {&upd7810_device::CALT, 1,16,16,L0|L1}, /* 8a: 100x xxxx */ + {&upd7810_device::CALT, 1,16,16,L0|L1}, /* 8b: 100x xxxx */ + {&upd7810_device::CALT, 1,16,16,L0|L1}, /* 8c: 100x xxxx */ + {&upd7810_device::CALT, 1,16,16,L0|L1}, /* 8d: 100x xxxx */ + {&upd7810_device::CALT, 1,16,16,L0|L1}, /* 8e: 100x xxxx */ + {&upd7810_device::CALT, 1,16,16,L0|L1}, /* 8f: 100x xxxx */ + + {&upd7810_device::CALT, 1,16,16,L0|L1}, /* 90: 100x xxxx */ + {&upd7810_device::CALT, 1,16,16,L0|L1}, /* 91: 100x xxxx */ + {&upd7810_device::CALT, 1,16,16,L0|L1}, /* 92: 100x xxxx */ + {&upd7810_device::CALT, 1,16,16,L0|L1}, /* 93: 100x xxxx */ + {&upd7810_device::CALT, 1,16,16,L0|L1}, /* 94: 100x xxxx */ + {&upd7810_device::CALT, 1,16,16,L0|L1}, /* 95: 100x xxxx */ + {&upd7810_device::CALT, 1,16,16,L0|L1}, /* 96: 100x xxxx */ + {&upd7810_device::CALT, 1,16,16,L0|L1}, /* 97: 100x xxxx */ + {&upd7810_device::CALT, 1,16,16,L0|L1}, /* 98: 100x xxxx */ + {&upd7810_device::CALT, 1,16,16,L0|L1}, /* 99: 100x xxxx */ + {&upd7810_device::CALT, 1,16,16,L0|L1}, /* 9a: 100x xxxx */ + {&upd7810_device::CALT, 1,16,16,L0|L1}, /* 9b: 100x xxxx */ + {&upd7810_device::CALT, 1,16,16,L0|L1}, /* 9c: 100x xxxx */ + {&upd7810_device::CALT, 1,16,16,L0|L1}, /* 9d: 100x xxxx */ + {&upd7810_device::CALT, 1,16,16,L0|L1}, /* 9e: 100x xxxx */ + {&upd7810_device::CALT, 1,16,16,L0|L1}, /* 9f: 100x xxxx */ + + {&upd7810_device::POP_VA, 1,10,10,L0|L1}, /* a0: 1010 0000 */ + {&upd7810_device::POP_BC, 1,10,10,L0|L1}, /* a1: 1010 0001 */ + {&upd7810_device::POP_DE, 1,10,10,L0|L1}, /* a2: 1010 0010 */ + {&upd7810_device::POP_HL, 1,10,10,L0|L1}, /* a3: 1010 0011 */ + {&upd7810_device::POP_EA, 1,10,10,L0|L1}, /* a4: 1010 0100 */ + {&upd7810_device::DMOV_EA_BC, 1, 4, 4,L0|L1}, /* a5: 1010 0101 */ + {&upd7810_device::DMOV_EA_DE, 1, 4, 4,L0|L1}, /* a6: 1010 0110 */ + {&upd7810_device::DMOV_EA_HL, 1, 4, 4,L0|L1}, /* a7: 1010 0111 */ + {&upd7810_device::INX_EA, 1, 7, 7,L0|L1}, /* a8: 1010 1000 */ + {&upd7810_device::DCX_EA, 1, 7, 7,L0|L1}, /* a9: 1010 1001 */ + {&upd7810_device::EI, 1, 4, 4,L0|L1}, /* aa: 1010 1010 */ + {&upd7810_device::LDAX_D_xx, 2, 7, 7,L0|L1}, /* ab: 1010 1011 dddd dddd */ + {&upd7810_device::LDAX_H_A, 1, 7, 7,L0|L1}, /* ac: 1010 1100 */ + {&upd7810_device::LDAX_H_B, 1, 7, 7,L0|L1}, /* ad: 1010 1101 */ + {&upd7810_device::LDAX_H_EA, 1, 7, 7,L0|L1}, /* ae: 1010 1110 */ + {&upd7810_device::LDAX_H_xx, 2, 7, 7,L0|L1}, /* af: 1010 1111 dddd dddd */ + + {&upd7810_device::PUSH_VA, 1,13,13,L0|L1}, /* b0: 1011 0000 */ + {&upd7810_device::PUSH_BC, 1,13,13,L0|L1}, /* b1: 1011 0001 */ + {&upd7810_device::PUSH_DE, 1,13,13,L0|L1}, /* b2: 1011 0010 */ + {&upd7810_device::PUSH_HL, 1,13,13,L0|L1}, /* b3: 1011 0011 */ + {&upd7810_device::PUSH_EA, 1,13,13,L0|L1}, /* b4: 1011 0100 */ + {&upd7810_device::DMOV_BC_EA, 1, 4, 4,L0|L1}, /* b5: 1011 0101 */ + {&upd7810_device::DMOV_DE_EA, 1, 4, 4,L0|L1}, /* b6: 1011 0110 */ + {&upd7810_device::DMOV_HL_EA, 1, 4, 4,L0|L1}, /* b7: 1011 0111 */ + {&upd7810_device::RET, 1,10,10,L0|L1}, /* b8: 1011 1000 */ + {&upd7810_device::RETS, 1,10,10,L0|L1}, /* b9: 1011 1001 */ + {&upd7810_device::DI, 1, 4, 4,L0|L1}, /* ba: 1011 1010 */ + {&upd7810_device::STAX_D_xx, 2, 7, 7,L0|L1}, /* bb: 1011 1011 dddd dddd */ + {&upd7810_device::STAX_H_A, 1, 7, 7,L0|L1}, /* bc: 1011 1100 */ + {&upd7810_device::STAX_H_B, 1, 7, 7,L0|L1}, /* bd: 1011 1101 */ + {&upd7810_device::STAX_H_EA, 1, 7, 7,L0|L1}, /* be: 1011 1110 */ + {&upd7810_device::STAX_H_xx, 2, 7, 7,L0|L1}, /* bf: 1011 1111 dddd dddd */ + + {&upd7810_device::JR, 1,10,10,L0|L1}, /* c0: 1100 0000 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* c1: 1100 0001 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* c2: 1100 0010 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* c3: 1100 0011 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* c4: 1100 0100 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* c5: 1100 0101 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* c6: 1100 0110 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* c7: 1100 0111 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* c8: 1100 1000 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* c9: 1100 1001 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* ca: 1100 1010 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* cb: 1100 1011 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* cc: 1100 1100 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* cd: 1100 1101 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* ce: 1100 1110 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* cf: 1100 1111 */ + + {&upd7810_device::JR, 1,10,10,L0|L1}, /* d0: 1101 0000 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* d1: 1101 0001 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* d2: 1101 0010 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* d3: 1101 0011 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* d4: 1101 0100 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* d5: 1101 0101 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* d6: 1101 0110 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* d7: 1101 0111 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* d8: 1101 1000 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* d9: 1101 1001 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* da: 1101 1010 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* db: 1101 1011 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* dc: 1101 1100 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* dd: 1101 1101 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* de: 1101 1110 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* df: 1101 1111 */ + + {&upd7810_device::JR, 1,10,10,L0|L1}, /* e0: 1110 0000 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* e1: 1110 0001 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* e2: 1110 0010 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* e3: 1110 0011 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* e4: 1110 0100 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* e5: 1110 0101 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* e6: 1110 0110 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* e7: 1110 0111 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* e8: 1110 1000 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* e9: 1110 1001 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* ea: 1110 1010 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* eb: 1110 1011 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* ec: 1110 1100 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* ed: 1110 1101 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* ee: 1110 1110 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* ef: 1110 1111 */ + + {&upd7810_device::JR, 1,10,10,L0|L1}, /* f0: 1111 0000 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* f1: 1111 0001 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* f2: 1111 0010 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* f3: 1111 0011 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* f4: 1111 0100 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* f5: 1111 0101 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* f6: 1111 0110 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* f7: 1111 0111 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* f8: 1111 1000 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* f9: 1111 1001 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* fa: 1111 1010 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* fb: 1111 1011 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* fc: 1111 1100 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* fd: 1111 1101 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* fe: 1111 1110 */ + {&upd7810_device::JR, 1,10,10,L0|L1} /* ff: 1111 1111 */ +}; + +const struct upd7810_device::opcode_s upd7810_device::s_opXX_7807[256] = +{ + {&upd7810_device::NOP, 1, 4, 4,L0|L1}, /* 00: 0000 0000 */ + {&upd7810_device::LDAW_wa, 2,10,10,L0|L1}, /* 01: 0000 0001 oooo oooo */ + {&upd7810_device::INX_SP, 1, 7, 7,L0|L1}, /* 02: 0000 0010 */ + {&upd7810_device::DCX_SP, 1, 7, 7,L0|L1}, /* 03: 0000 0011 */ + {&upd7810_device::LXI_S_w, 3,10,10,L0|L1}, /* 04: 0000 0100 llll llll hhhh hhhh */ + {&upd7810_device::ANIW_wa_xx, 3,19,19,L0|L1}, /* 05: 0000 0101 oooo oooo xxxx xxxx */ + {&upd7810_device::illegal, 1, 4, 4,L0|L1}, /* 06: */ + {&upd7810_device::ANI_A_xx, 2, 7, 7,L0|L1}, /* 07: 0000 0111 xxxx xxxx */ + {&upd7810_device::MOV_A_EAH, 1, 4, 4,L0|L1}, /* 08: 0000 1000 */ + {&upd7810_device::MOV_A_EAL, 1, 4, 4,L0|L1}, /* 09: 0000 1001 */ + {&upd7810_device::MOV_A_B, 1, 4, 4,L0|L1}, /* 0a: 0000 1010 */ + {&upd7810_device::MOV_A_C, 1, 4, 4,L0|L1}, /* 0b: 0000 1011 */ + {&upd7810_device::MOV_A_D, 1, 4, 4,L0|L1}, /* 0c: 0000 1100 */ + {&upd7810_device::MOV_A_E, 1, 4, 4,L0|L1}, /* 0d: 0000 1101 */ + {&upd7810_device::MOV_A_H, 1, 4, 4,L0|L1}, /* 0e: 0000 1110 */ + {&upd7810_device::MOV_A_L, 1, 4, 4,L0|L1}, /* 0f: 0000 1111 */ + + {&upd7810_device::illegal, 1,13, 4,L0|L1}, /* 10: 0001 0000 */ /* 7807 */ + {&upd7810_device::illegal, 1,13, 4,L0|L1}, /* 11: 0001 0001 */ /* 7807 */ + {&upd7810_device::INX_BC, 1, 7, 7,L0|L1}, /* 12: 0001 0010 */ + {&upd7810_device::DCX_BC, 1, 7, 7,L0|L1}, /* 13: 0001 0011 */ + {&upd7810_device::LXI_B_w, 3,10,10,L0|L1}, /* 14: 0001 0100 llll llll hhhh hhhh */ + {&upd7810_device::ORIW_wa_xx, 3,19,19,L0|L1}, /* 15: 0001 0101 oooo oooo xxxx xxxx */ + {&upd7810_device::XRI_A_xx, 2, 7, 7,L0|L1}, /* 16: 0001 0110 xxxx xxxx */ + {&upd7810_device::ORI_A_xx, 2, 7, 7,L0|L1}, /* 17: 0001 0111 xxxx xxxx */ + {&upd7810_device::MOV_EAH_A, 1, 4, 4,L0|L1}, /* 18: 0001 1000 */ + {&upd7810_device::MOV_EAL_A, 1, 4, 4,L0|L1}, /* 19: 0001 1001 */ + {&upd7810_device::MOV_B_A, 1, 4, 4,L0|L1}, /* 1a: 0001 1010 */ + {&upd7810_device::MOV_C_A, 1, 4, 4,L0|L1}, /* 1b: 0001 1011 */ + {&upd7810_device::MOV_D_A, 1, 4, 4,L0|L1}, /* 1c: 0001 1100 */ + {&upd7810_device::MOV_E_A, 1, 4, 4,L0|L1}, /* 1d: 0001 1101 */ + {&upd7810_device::MOV_H_A, 1, 4, 4,L0|L1}, /* 1e: 0001 1110 */ + {&upd7810_device::MOV_L_A, 1, 4, 4,L0|L1}, /* 1f: 0001 1111 */ + + {&upd7810_device::INRW_wa, 2,16,16,L0|L1}, /* 20: 0010 0000 oooo oooo */ + {&upd7810_device::JB, 1, 4, 4,L0|L1}, /* 21: 0010 0001 */ + {&upd7810_device::INX_DE, 1, 7, 7,L0|L1}, /* 22: 0010 0010 */ + {&upd7810_device::DCX_DE, 1, 7, 7,L0|L1}, /* 23: 0010 0011 */ + {&upd7810_device::LXI_D_w, 3,10,10,L0|L1}, /* 24: 0010 0100 llll llll hhhh hhhh */ + {&upd7810_device::GTIW_wa_xx, 3,19,19,L0|L1}, /* 25: 0010 0101 oooo oooo xxxx xxxx */ + {&upd7810_device::ADINC_A_xx, 2, 7, 7,L0|L1}, /* 26: 0010 0110 xxxx xxxx */ + {&upd7810_device::GTI_A_xx, 2, 7, 7,L0|L1}, /* 27: 0010 0111 xxxx xxxx */ + {&upd7810_device::illegal, 1, 4, 4,L0|L1}, /* 28: */ + {&upd7810_device::LDAX_B, 2, 7, 7,L0|L1}, /* 29: 0010 1001 dddd dddd */ + {&upd7810_device::LDAX_D, 2, 7, 7,L0|L1}, /* 2a: 0010 1010 dddd dddd */ + {&upd7810_device::LDAX_H, 2, 7, 7,L0|L1}, /* 2b: 0010 1011 dddd dddd */ + {&upd7810_device::LDAX_Dp, 2, 7, 7,L0|L1}, /* 2c: 0010 1100 dddd dddd */ + {&upd7810_device::LDAX_Hp, 2, 7, 7,L0|L1}, /* 2d: 0010 1101 dddd dddd */ + {&upd7810_device::LDAX_Dm, 2, 7, 7,L0|L1}, /* 2e: 0010 1110 dddd dddd */ + {&upd7810_device::LDAX_Hm, 2, 7, 7,L0|L1}, /* 2f: 0010 1111 dddd dddd */ + + {&upd7810_device::DCRW_wa, 2,16,16,L0|L1}, /* 30: 0011 0000 oooo oooo */ + {&upd7810_device::illegal, 2, 8, 8,L0|L1}, /* 31: 0011 0001 bbbb bbbb */ /* 7807 */ + {&upd7810_device::INX_HL, 1, 7, 7,L0|L1}, /* 32: 0011 0010 */ + {&upd7810_device::DCX_HL, 1, 7, 7,L0|L1}, /* 33: 0011 0011 */ + {&upd7810_device::LXI_H_w, 3,10,10, L1}, /* 34: 0011 0100 llll llll hhhh hhhh */ + {&upd7810_device::LTIW_wa_xx, 3,19,19,L0|L1}, /* 35: 0011 0101 oooo oooo xxxx xxxx */ + {&upd7810_device::SUINB_A_xx, 2, 7, 7,L0|L1}, /* 36: 0011 0110 xxxx xxxx */ + {&upd7810_device::LTI_A_xx, 2, 7, 7,L0|L1}, /* 37: 0011 0111 xxxx xxxx */ + {&upd7810_device::illegal, 1, 4, 4,L0|L1}, /* 38: */ + {&upd7810_device::STAX_B, 2, 7, 7,L0|L1}, /* 39: 0011 1001 dddd dddd */ + {&upd7810_device::STAX_D, 2, 7, 7,L0|L1}, /* 3a: 0011 1010 dddd dddd */ + {&upd7810_device::STAX_H, 2, 7, 7,L0|L1}, /* 3b: 0011 1011 dddd dddd */ + {&upd7810_device::STAX_Dp, 2, 7, 7,L0|L1}, /* 3c: 0011 1100 dddd dddd */ + {&upd7810_device::STAX_Hp, 2, 7, 7,L0|L1}, /* 3d: 0011 1101 dddd dddd */ + {&upd7810_device::STAX_Dm, 2, 7, 7,L0|L1}, /* 3e: 0011 1110 dddd dddd */ + {&upd7810_device::STAX_Hm, 2, 7, 7,L0|L1}, /* 3f: 0011 1111 dddd dddd */ + + {&upd7810_device::CALL_w, 3,16,16,L0|L1}, /* 40: 0100 0000 llll llll hhhh hhhh */ + {&upd7810_device::INR_A, 1, 4, 4,L0|L1}, /* 41: 0100 0001 */ + {&upd7810_device::INR_B, 1, 4, 4,L0|L1}, /* 42: 0100 0010 */ + {&upd7810_device::INR_C, 1, 4, 4,L0|L1}, /* 43: 0100 0011 */ + {&upd7810_device::LXI_EA_s, 3,10,10,L0|L1}, /* 44: 0100 0100 llll llll hhhh hhhh */ + {&upd7810_device::ONIW_wa_xx, 3,19,19,L0|L1}, /* 45: 0100 0101 oooo oooo xxxx xxxx */ + {&upd7810_device::ADI_A_xx, 2, 7, 7,L0|L1}, /* 46: 0100 0110 xxxx xxxx */ + {&upd7810_device::ONI_A_xx, 2, 7, 7,L0|L1}, /* 47: 0100 0111 xxxx xxxx */ + {&upd7810_device::PRE_48, 1, 0, 0,L0|L1}, /* 48: prefix */ + {&upd7810_device::MVIX_BC_xx, 2,10,10,L0|L1}, /* 49: 0100 1001 xxxx xxxx */ + {&upd7810_device::MVIX_DE_xx, 2,10,10,L0|L1}, /* 4a: 0100 1010 xxxx xxxx */ + {&upd7810_device::MVIX_HL_xx, 2,10,10,L0|L1}, /* 4b: 0100 1011 xxxx xxxx */ + {&upd7810_device::PRE_4C, 1, 0, 0,L0|L1}, /* 4c: prefix */ + {&upd7810_device::PRE_4D, 1, 4, 4,L0|L1}, /* 4d: prefix */ + {&upd7810_device::JRE, 2,10,10,L0|L1}, /* 4e: 0100 111d dddd dddd */ + {&upd7810_device::JRE, 2,10,10,L0|L1}, /* 4f: 0100 111d dddd dddd */ + + {&upd7810_device::SKN_bit, 2,13,13,L0|L1}, /* 50: 0101 0000 bbbb bbbb */ /* 7807 */ + {&upd7810_device::DCR_A, 1, 4, 4,L0|L1}, /* 51: 0101 0001 */ + {&upd7810_device::DCR_B, 1, 4, 4,L0|L1}, /* 52: 0101 0010 */ + {&upd7810_device::DCR_C, 1, 4, 4,L0|L1}, /* 53: 0101 0011 */ + {&upd7810_device::JMP_w, 3,10,10,L0|L1}, /* 54: 0101 0100 llll llll hhhh hhhh */ + {&upd7810_device::OFFIW_wa_xx, 3,19,19,L0|L1}, /* 55: 0101 0101 oooo oooo xxxx xxxx */ + {&upd7810_device::ACI_A_xx, 2, 7, 7,L0|L1}, /* 56: 0101 0110 xxxx xxxx */ + {&upd7810_device::OFFI_A_xx, 2, 7, 7,L0|L1}, /* 57: 0101 0111 xxxx xxxx */ + {&upd7810_device::SETB, 2,13,13,L0|L1}, /* 58: 0101 1000 bbbb bbbb */ /* 7807 */ + {&upd7810_device::illegal, 2, 8, 8,L0|L1}, /* 59: 0101 1001 bbbb bbbb */ /* 7807 */ + {&upd7810_device::illegal, 2, 8, 8,L0|L1}, /* 5a: 0101 1010 bbbb bbbb */ /* 7807 */ + {&upd7810_device::CLR, 2,13,13,L0|L1}, /* 5b: 0101 1011 bbbb bbbb */ /* 7807 */ + {&upd7810_device::illegal, 2, 8, 8,L0|L1}, /* 5c: 0101 1100 bbbb bbbb */ /* 7807 */ + {&upd7810_device::SK_bit, 2,10,10,L0|L1}, /* 5d: 0101 1101 bbbb bbbb */ /* 7807 */ + {&upd7810_device::illegal, 2, 8, 8,L0|L1}, /* 5e: 0101 1110 bbbb bbbb */ /* 7807 */ + {&upd7810_device::illegal, 2, 8, 8,L0|L1}, /* 5f: 0101 1111 bbbb bbbb */ /* 7807 */ + + {&upd7810_device::PRE_60, 1, 0, 0,L0|L1}, /* 60: */ + {&upd7810_device::DAA, 1, 4, 4,L0|L1}, /* 61: 0110 0001 */ + {&upd7810_device::RETI, 1,13,13,L0|L1}, /* 62: 0110 0010 */ + {&upd7810_device::STAW_wa, 2,10,10,L0|L1}, /* 63: 0110 0011 oooo oooo */ + {&upd7810_device::PRE_64, 1, 0, 0,L0|L1}, /* 64: */ + {&upd7810_device::NEIW_wa_xx, 3,19,19,L0|L1}, /* 65: 0110 0101 oooo oooo xxxx xxxx */ + {&upd7810_device::SUI_A_xx, 2, 7, 7,L0|L1}, /* 66: 0110 0110 xxxx xxxx */ + {&upd7810_device::NEI_A_xx, 2, 7, 7,L0|L1}, /* 67: 0110 0111 xxxx xxxx */ + {&upd7810_device::MVI_V_xx, 2, 7, 7,L0|L1}, /* 68: 0110 1000 xxxx xxxx */ + {&upd7810_device::MVI_A_xx, 2, 7, 7,L0 }, /* 69: 0110 1001 xxxx xxxx */ + {&upd7810_device::MVI_B_xx, 2, 7, 7,L0|L1}, /* 6a: 0110 1010 xxxx xxxx */ + {&upd7810_device::MVI_C_xx, 2, 7, 7,L0|L1}, /* 6b: 0110 1011 xxxx xxxx */ + {&upd7810_device::MVI_D_xx, 2, 7, 7,L0|L1}, /* 6c: 0110 1100 xxxx xxxx */ + {&upd7810_device::MVI_E_xx, 2, 7, 7,L0|L1}, /* 6d: 0110 1101 xxxx xxxx */ + {&upd7810_device::MVI_H_xx, 2, 7, 7,L0|L1}, /* 6e: 0110 1110 xxxx xxxx */ + {&upd7810_device::MVI_L_xx, 2, 7, 7, L1}, /* 6f: 0110 1111 xxxx xxxx */ + + {&upd7810_device::PRE_70, 1, 0, 0,L0|L1}, /* 70: */ + {&upd7810_device::MVIW_wa_xx, 3,13,13,L0|L1}, /* 71: 0111 0001 oooo oooo xxxx xxxx */ + {&upd7810_device::SOFTI, 1,16,16,L0|L1}, /* 72: 0111 0010 */ + {&upd7810_device::illegal, 1, 0, 0,L0|L1}, /* 73: */ + {&upd7810_device::PRE_74, 1, 0, 0,L0|L1}, /* 74: prefix */ + {&upd7810_device::EQIW_wa_xx, 3,19,19,L0|L1}, /* 75: 0111 0101 oooo oooo xxxx xxxx */ + {&upd7810_device::SBI_A_xx, 2, 7, 7,L0|L1}, /* 76: 0111 0110 xxxx xxxx */ + {&upd7810_device::EQI_A_xx, 2, 7, 7,L0|L1}, /* 77: 0111 0111 xxxx xxxx */ + {&upd7810_device::CALF, 2,13,13,L0|L1}, /* 78: 0111 1xxx xxxx xxxx */ + {&upd7810_device::CALF, 2,13,13,L0|L1}, /* 79: 0111 1xxx xxxx xxxx */ + {&upd7810_device::CALF, 2,13,13,L0|L1}, /* 7a: 0111 1xxx xxxx xxxx */ + {&upd7810_device::CALF, 2,13,13,L0|L1}, /* 7b: 0111 1xxx xxxx xxxx */ + {&upd7810_device::CALF, 2,13,13,L0|L1}, /* 7c: 0111 1xxx xxxx xxxx */ + {&upd7810_device::CALF, 2,13,13,L0|L1}, /* 7d: 0111 1xxx xxxx xxxx */ + {&upd7810_device::CALF, 2,13,13,L0|L1}, /* 7e: 0111 1xxx xxxx xxxx */ + {&upd7810_device::CALF, 2,13,13,L0|L1}, /* 7f: 0111 1xxx xxxx xxxx */ + + {&upd7810_device::CALT, 1,16,16,L0|L1}, /* 80: 100x xxxx */ + {&upd7810_device::CALT, 1,16,16,L0|L1}, /* 81: 100x xxxx */ + {&upd7810_device::CALT, 1,16,16,L0|L1}, /* 82: 100x xxxx */ + {&upd7810_device::CALT, 1,16,16,L0|L1}, /* 83: 100x xxxx */ + {&upd7810_device::CALT, 1,16,16,L0|L1}, /* 84: 100x xxxx */ + {&upd7810_device::CALT, 1,16,16,L0|L1}, /* 85: 100x xxxx */ + {&upd7810_device::CALT, 1,16,16,L0|L1}, /* 86: 100x xxxx */ + {&upd7810_device::CALT, 1,16,16,L0|L1}, /* 87: 100x xxxx */ + {&upd7810_device::CALT, 1,16,16,L0|L1}, /* 88: 100x xxxx */ + {&upd7810_device::CALT, 1,16,16,L0|L1}, /* 89: 100x xxxx */ + {&upd7810_device::CALT, 1,16,16,L0|L1}, /* 8a: 100x xxxx */ + {&upd7810_device::CALT, 1,16,16,L0|L1}, /* 8b: 100x xxxx */ + {&upd7810_device::CALT, 1,16,16,L0|L1}, /* 8c: 100x xxxx */ + {&upd7810_device::CALT, 1,16,16,L0|L1}, /* 8d: 100x xxxx */ + {&upd7810_device::CALT, 1,16,16,L0|L1}, /* 8e: 100x xxxx */ + {&upd7810_device::CALT, 1,16,16,L0|L1}, /* 8f: 100x xxxx */ + + {&upd7810_device::CALT, 1,16,16,L0|L1}, /* 90: 100x xxxx */ + {&upd7810_device::CALT, 1,16,16,L0|L1}, /* 91: 100x xxxx */ + {&upd7810_device::CALT, 1,16,16,L0|L1}, /* 92: 100x xxxx */ + {&upd7810_device::CALT, 1,16,16,L0|L1}, /* 93: 100x xxxx */ + {&upd7810_device::CALT, 1,16,16,L0|L1}, /* 94: 100x xxxx */ + {&upd7810_device::CALT, 1,16,16,L0|L1}, /* 95: 100x xxxx */ + {&upd7810_device::CALT, 1,16,16,L0|L1}, /* 96: 100x xxxx */ + {&upd7810_device::CALT, 1,16,16,L0|L1}, /* 97: 100x xxxx */ + {&upd7810_device::CALT, 1,16,16,L0|L1}, /* 98: 100x xxxx */ + {&upd7810_device::CALT, 1,16,16,L0|L1}, /* 99: 100x xxxx */ + {&upd7810_device::CALT, 1,16,16,L0|L1}, /* 9a: 100x xxxx */ + {&upd7810_device::CALT, 1,16,16,L0|L1}, /* 9b: 100x xxxx */ + {&upd7810_device::CALT, 1,16,16,L0|L1}, /* 9c: 100x xxxx */ + {&upd7810_device::CALT, 1,16,16,L0|L1}, /* 9d: 100x xxxx */ + {&upd7810_device::CALT, 1,16,16,L0|L1}, /* 9e: 100x xxxx */ + {&upd7810_device::CALT, 1,16,16,L0|L1}, /* 9f: 100x xxxx */ + + {&upd7810_device::POP_VA, 1,10,10,L0|L1}, /* a0: 1010 0000 */ + {&upd7810_device::POP_BC, 1,10,10,L0|L1}, /* a1: 1010 0001 */ + {&upd7810_device::POP_DE, 1,10,10,L0|L1}, /* a2: 1010 0010 */ + {&upd7810_device::POP_HL, 1,10,10,L0|L1}, /* a3: 1010 0011 */ + {&upd7810_device::POP_EA, 1,10,10,L0|L1}, /* a4: 1010 0100 */ + {&upd7810_device::DMOV_EA_BC, 1, 4, 4,L0|L1}, /* a5: 1010 0101 */ + {&upd7810_device::DMOV_EA_DE, 1, 4, 4,L0|L1}, /* a6: 1010 0110 */ + {&upd7810_device::DMOV_EA_HL, 1, 4, 4,L0|L1}, /* a7: 1010 0111 */ + {&upd7810_device::INX_EA, 1, 7, 7,L0|L1}, /* a8: 1010 1000 */ + {&upd7810_device::DCX_EA, 1, 7, 7,L0|L1}, /* a9: 1010 1001 */ + {&upd7810_device::EI, 1, 4, 4,L0|L1}, /* aa: 1010 1010 */ + {&upd7810_device::LDAX_D_xx, 2, 7, 7,L0|L1}, /* ab: 1010 1011 dddd dddd */ + {&upd7810_device::LDAX_H_A, 1, 7, 7,L0|L1}, /* ac: 1010 1100 */ + {&upd7810_device::LDAX_H_B, 1, 7, 7,L0|L1}, /* ad: 1010 1101 */ + {&upd7810_device::LDAX_H_EA, 1, 7, 7,L0|L1}, /* ae: 1010 1110 */ + {&upd7810_device::LDAX_H_xx, 2, 7, 7,L0|L1}, /* af: 1010 1111 dddd dddd */ + + {&upd7810_device::PUSH_VA, 1,13,13,L0|L1}, /* b0: 1011 0000 */ + {&upd7810_device::PUSH_BC, 1,13,13,L0|L1}, /* b1: 1011 0001 */ + {&upd7810_device::PUSH_DE, 1,13,13,L0|L1}, /* b2: 1011 0010 */ + {&upd7810_device::PUSH_HL, 1,13,13,L0|L1}, /* b3: 1011 0011 */ + {&upd7810_device::PUSH_EA, 1,13,13,L0|L1}, /* b4: 1011 0100 */ + {&upd7810_device::DMOV_BC_EA, 1, 4, 4,L0|L1}, /* b5: 1011 0101 */ + {&upd7810_device::DMOV_DE_EA, 1, 4, 4,L0|L1}, /* b6: 1011 0110 */ + {&upd7810_device::DMOV_HL_EA, 1, 4, 4,L0|L1}, /* b7: 1011 0111 */ + {&upd7810_device::RET, 1,10,10,L0|L1}, /* b8: 1011 1000 */ + {&upd7810_device::RETS, 1,10,10,L0|L1}, /* b9: 1011 1001 */ + {&upd7810_device::DI, 1, 4, 4,L0|L1}, /* ba: 1011 1010 */ + {&upd7810_device::STAX_D_xx, 2, 7, 7,L0|L1}, /* bb: 1011 1011 dddd dddd */ + {&upd7810_device::STAX_H_A, 1, 7, 7,L0|L1}, /* bc: 1011 1100 */ + {&upd7810_device::STAX_H_B, 1, 7, 7,L0|L1}, /* bd: 1011 1101 */ + {&upd7810_device::STAX_H_EA, 1, 7, 7,L0|L1}, /* be: 1011 1110 */ + {&upd7810_device::STAX_H_xx, 2, 7, 7,L0|L1}, /* bf: 1011 1111 dddd dddd */ + + {&upd7810_device::JR, 1,10,10,L0|L1}, /* c0: 1100 0000 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* c1: 1100 0001 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* c2: 1100 0010 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* c3: 1100 0011 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* c4: 1100 0100 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* c5: 1100 0101 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* c6: 1100 0110 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* c7: 1100 0111 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* c8: 1100 1000 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* c9: 1100 1001 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* ca: 1100 1010 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* cb: 1100 1011 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* cc: 1100 1100 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* cd: 1100 1101 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* ce: 1100 1110 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* cf: 1100 1111 */ + + {&upd7810_device::JR, 1,10,10,L0|L1}, /* d0: 1101 0000 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* d1: 1101 0001 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* d2: 1101 0010 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* d3: 1101 0011 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* d4: 1101 0100 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* d5: 1101 0101 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* d6: 1101 0110 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* d7: 1101 0111 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* d8: 1101 1000 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* d9: 1101 1001 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* da: 1101 1010 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* db: 1101 1011 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* dc: 1101 1100 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* dd: 1101 1101 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* de: 1101 1110 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* df: 1101 1111 */ + + {&upd7810_device::JR, 1,10,10,L0|L1}, /* e0: 1110 0000 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* e1: 1110 0001 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* e2: 1110 0010 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* e3: 1110 0011 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* e4: 1110 0100 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* e5: 1110 0101 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* e6: 1110 0110 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* e7: 1110 0111 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* e8: 1110 1000 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* e9: 1110 1001 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* ea: 1110 1010 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* eb: 1110 1011 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* ec: 1110 1100 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* ed: 1110 1101 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* ee: 1110 1110 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* ef: 1110 1111 */ + + {&upd7810_device::JR, 1,10,10,L0|L1}, /* f0: 1111 0000 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* f1: 1111 0001 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* f2: 1111 0010 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* f3: 1111 0011 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* f4: 1111 0100 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* f5: 1111 0101 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* f6: 1111 0110 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* f7: 1111 0111 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* f8: 1111 1000 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* f9: 1111 1001 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* fa: 1111 1010 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* fb: 1111 1011 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* fc: 1111 1100 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* fd: 1111 1101 */ + {&upd7810_device::JR, 1,10,10,L0|L1}, /* fe: 1111 1110 */ + {&upd7810_device::JR, 1,10,10,L0|L1} /* ff: 1111 1111 */ +}; + + +/*********************************************************************** + * + * uPD7801 + * + **********************************************************************/ + +const struct upd7810_device::opcode_s upd7810_device::s_op48_7801[256] = +{ + /* 0x00 - 0x1F */ + {&upd7810_device::SKIT_F0, 2, 8, 8,L0|L1}, {&upd7810_device::SKIT_FT0, 2, 8, 8,L0|L1}, + {&upd7810_device::SKIT_F1, 2, 8, 8,L0|L1}, {&upd7810_device::SKIT_F2, 2, 8, 8,L0|L1}, + {&upd7810_device::SKIT_FST, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::SK_CY, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::SK_Z, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::PUSH_VA, 2,17,17,L0|L1}, {&upd7810_device::POP_VA, 2,15,15,L0|L1}, + + {&upd7810_device::SKNIT_F0, 2, 8, 8,L0|L1}, {&upd7810_device::SKNIT_FT0, 2, 8, 8,L0|L1}, + {&upd7810_device::SKNIT_F1, 2, 8, 8,L0|L1}, {&upd7810_device::SKNIT_F2, 2, 8, 8,L0|L1}, + {&upd7810_device::SKNIT_FST, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal, 2, 8, 8,L0|L1}, + {&upd7810_device::SKN_CY, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::SKN_Z, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::PUSH_BC, 2,17,17,L0|L1}, {&upd7810_device::POP_BC, 2,15,15,L0|L1}, + + /* 0x20 - 0x3F */ + {&upd7810_device::EI, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::DI, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::CLC, 2, 8, 8,L0|L1}, {&upd7810_device::STC, 2, 8, 8,L0|L1}, + {&upd7810_device::PEN, 2,11,11,L0|L1}, {&upd7810_device::PEX, 2,11,11,L0|L1}, + {&upd7810_device::PUSH_DE, 2,17,17,L0|L1}, {&upd7810_device::POP_DE, 2,15,15,L0|L1}, + + {&upd7810_device::RLL_A, 2, 8, 8,L0|L1}, {&upd7810_device::RLR_A, 2, 8, 8,L0|L1}, + {&upd7810_device::RLL_C, 2, 8, 8,L0|L1}, {&upd7810_device::RLR_C, 2, 8, 8,L0|L1}, + {&upd7810_device::SLL_A, 2, 8, 8,L0|L1}, {&upd7810_device::SLR_A, 2, 8, 8,L0|L1}, + {&upd7810_device::SLL_C, 2, 8, 8,L0|L1}, {&upd7810_device::SLR_C, 2, 8, 8,L0|L1}, + {&upd7810_device::RLD, 2,17,17,L0|L1}, {&upd7810_device::RRD, 2,17,17,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::PER, 2,11,11,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::PUSH_HL, 2,17,17,L0|L1}, {&upd7810_device::POP_HL, 2,15,15,L0|L1}, + + /* 0x40 - 0x5F */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + /* 0x60 - 0x7F */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + /* 0x80 - 0x9F */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + /* 0xA0 - 0xBF */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + /* 0xC0 - 0xDF */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + /* 0xE0 - 0xFF */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1} +}; + +const struct upd7810_device::opcode_s upd7810_device::s_op4C_7801[256] = +{ + /* 0x00 - 0x1F */ + {&upd7810_device::IN, 2,10,10,L0|L1}, {&upd7810_device::IN, 2,10,10,L0|L1}, + {&upd7810_device::IN, 2,10,10,L0|L1}, {&upd7810_device::IN, 2,10,10,L0|L1}, + {&upd7810_device::IN, 2,10,10,L0|L1}, {&upd7810_device::IN, 2,10,10,L0|L1}, + {&upd7810_device::IN, 2,10,10,L0|L1}, {&upd7810_device::IN, 2,10,10,L0|L1}, + {&upd7810_device::IN, 2,10,10,L0|L1}, {&upd7810_device::IN, 2,10,10,L0|L1}, + {&upd7810_device::IN, 2,10,10,L0|L1}, {&upd7810_device::IN, 2,10,10,L0|L1}, + {&upd7810_device::IN, 2,10,10,L0|L1}, {&upd7810_device::IN, 2,10,10,L0|L1}, + {&upd7810_device::IN, 2,10,10,L0|L1}, {&upd7810_device::IN, 2,10,10,L0|L1}, + + {&upd7810_device::IN, 2,10,10,L0|L1}, {&upd7810_device::IN, 2,10,10,L0|L1}, + {&upd7810_device::IN, 2,10,10,L0|L1}, {&upd7810_device::IN, 2,10,10,L0|L1}, + {&upd7810_device::IN, 2,10,10,L0|L1}, {&upd7810_device::IN, 2,10,10,L0|L1}, + {&upd7810_device::IN, 2,10,10,L0|L1}, {&upd7810_device::IN, 2,10,10,L0|L1}, + {&upd7810_device::IN, 2,10,10,L0|L1}, {&upd7810_device::IN, 2,10,10,L0|L1}, + {&upd7810_device::IN, 2,10,10,L0|L1}, {&upd7810_device::IN, 2,10,10,L0|L1}, + {&upd7810_device::IN, 2,10,10,L0|L1}, {&upd7810_device::IN, 2,10,10,L0|L1}, + {&upd7810_device::IN, 2,10,10,L0|L1}, {&upd7810_device::IN, 2,10,10,L0|L1}, + + /* 0x20 - 0x3F */ + {&upd7810_device::IN, 2,10,10,L0|L1}, {&upd7810_device::IN, 2,10,10,L0|L1}, + {&upd7810_device::IN, 2,10,10,L0|L1}, {&upd7810_device::IN, 2,10,10,L0|L1}, + {&upd7810_device::IN, 2,10,10,L0|L1}, {&upd7810_device::IN, 2,10,10,L0|L1}, + {&upd7810_device::IN, 2,10,10,L0|L1}, {&upd7810_device::IN, 2,10,10,L0|L1}, + {&upd7810_device::IN, 2,10,10,L0|L1}, {&upd7810_device::IN, 2,10,10,L0|L1}, + {&upd7810_device::IN, 2,10,10,L0|L1}, {&upd7810_device::IN, 2,10,10,L0|L1}, + {&upd7810_device::IN, 2,10,10,L0|L1}, {&upd7810_device::IN, 2,10,10,L0|L1}, + {&upd7810_device::IN, 2,10,10,L0|L1}, {&upd7810_device::IN, 2,10,10,L0|L1}, + + {&upd7810_device::IN, 2,10,10,L0|L1}, {&upd7810_device::IN, 2,10,10,L0|L1}, + {&upd7810_device::IN, 2,10,10,L0|L1}, {&upd7810_device::IN, 2,10,10,L0|L1}, + {&upd7810_device::IN, 2,10,10,L0|L1}, {&upd7810_device::IN, 2,10,10,L0|L1}, + {&upd7810_device::IN, 2,10,10,L0|L1}, {&upd7810_device::IN, 2,10,10,L0|L1}, + {&upd7810_device::IN, 2,10,10,L0|L1}, {&upd7810_device::IN, 2,10,10,L0|L1}, + {&upd7810_device::IN, 2,10,10,L0|L1}, {&upd7810_device::IN, 2,10,10,L0|L1}, + {&upd7810_device::IN, 2,10,10,L0|L1}, {&upd7810_device::IN, 2,10,10,L0|L1}, + {&upd7810_device::IN, 2,10,10,L0|L1}, {&upd7810_device::IN, 2,10,10,L0|L1}, + + /* 0x40 - 0x5F */ + {&upd7810_device::IN, 2,10,10,L0|L1}, {&upd7810_device::IN, 2,10,10,L0|L1}, + {&upd7810_device::IN, 2,10,10,L0|L1}, {&upd7810_device::IN, 2,10,10,L0|L1}, + {&upd7810_device::IN, 2,10,10,L0|L1}, {&upd7810_device::IN, 2,10,10,L0|L1}, + {&upd7810_device::IN, 2,10,10,L0|L1}, {&upd7810_device::IN, 2,10,10,L0|L1}, + {&upd7810_device::IN, 2,10,10,L0|L1}, {&upd7810_device::IN, 2,10,10,L0|L1}, + {&upd7810_device::IN, 2,10,10,L0|L1}, {&upd7810_device::IN, 2,10,10,L0|L1}, + {&upd7810_device::IN, 2,10,10,L0|L1}, {&upd7810_device::IN, 2,10,10,L0|L1}, + {&upd7810_device::IN, 2,10,10,L0|L1}, {&upd7810_device::IN, 2,10,10,L0|L1}, + + {&upd7810_device::IN, 2,10,10,L0|L1}, {&upd7810_device::IN, 2,10,10,L0|L1}, + {&upd7810_device::IN, 2,10,10,L0|L1}, {&upd7810_device::IN, 2,10,10,L0|L1}, + {&upd7810_device::IN, 2,10,10,L0|L1}, {&upd7810_device::IN, 2,10,10,L0|L1}, + {&upd7810_device::IN, 2,10,10,L0|L1}, {&upd7810_device::IN, 2,10,10,L0|L1}, + {&upd7810_device::IN, 2,10,10,L0|L1}, {&upd7810_device::IN, 2,10,10,L0|L1}, + {&upd7810_device::IN, 2,10,10,L0|L1}, {&upd7810_device::IN, 2,10,10,L0|L1}, + {&upd7810_device::IN, 2,10,10,L0|L1}, {&upd7810_device::IN, 2,10,10,L0|L1}, + {&upd7810_device::IN, 2,10,10,L0|L1}, {&upd7810_device::IN, 2,10,10,L0|L1}, + + /* 0x60 - 0x7F */ + {&upd7810_device::IN, 2,10,10,L0|L1}, {&upd7810_device::IN, 2,10,10,L0|L1}, + {&upd7810_device::IN, 2,10,10,L0|L1}, {&upd7810_device::IN, 2,10,10,L0|L1}, + {&upd7810_device::IN, 2,10,10,L0|L1}, {&upd7810_device::IN, 2,10,10,L0|L1}, + {&upd7810_device::IN, 2,10,10,L0|L1}, {&upd7810_device::IN, 2,10,10,L0|L1}, + {&upd7810_device::IN, 2,10,10,L0|L1}, {&upd7810_device::IN, 2,10,10,L0|L1}, + {&upd7810_device::IN, 2,10,10,L0|L1}, {&upd7810_device::IN, 2,10,10,L0|L1}, + {&upd7810_device::IN, 2,10,10,L0|L1}, {&upd7810_device::IN, 2,10,10,L0|L1}, + {&upd7810_device::IN, 2,10,10,L0|L1}, {&upd7810_device::IN, 2,10,10,L0|L1}, + + {&upd7810_device::IN, 2,10,10,L0|L1}, {&upd7810_device::IN, 2,10,10,L0|L1}, + {&upd7810_device::IN, 2,10,10,L0|L1}, {&upd7810_device::IN, 2,10,10,L0|L1}, + {&upd7810_device::IN, 2,10,10,L0|L1}, {&upd7810_device::IN, 2,10,10,L0|L1}, + {&upd7810_device::IN, 2,10,10,L0|L1}, {&upd7810_device::IN, 2,10,10,L0|L1}, + {&upd7810_device::IN, 2,10,10,L0|L1}, {&upd7810_device::IN, 2,10,10,L0|L1}, + {&upd7810_device::IN, 2,10,10,L0|L1}, {&upd7810_device::IN, 2,10,10,L0|L1}, + {&upd7810_device::IN, 2,10,10,L0|L1}, {&upd7810_device::IN, 2,10,10,L0|L1}, + {&upd7810_device::IN, 2,10,10,L0|L1}, {&upd7810_device::IN, 2,10,10,L0|L1}, + + /* 0x80 - 0x9F */ + {&upd7810_device::IN, 2,10,10,L0|L1}, {&upd7810_device::IN, 2,10,10,L0|L1}, + {&upd7810_device::IN, 2,10,10,L0|L1}, {&upd7810_device::IN, 2,10,10,L0|L1}, + {&upd7810_device::IN, 2,10,10,L0|L1}, {&upd7810_device::IN, 2,10,10,L0|L1}, + {&upd7810_device::IN, 2,10,10,L0|L1}, {&upd7810_device::IN, 2,10,10,L0|L1}, + {&upd7810_device::IN, 2,10,10,L0|L1}, {&upd7810_device::IN, 2,10,10,L0|L1}, + {&upd7810_device::IN, 2,10,10,L0|L1}, {&upd7810_device::IN, 2,10,10,L0|L1}, + {&upd7810_device::IN, 2,10,10,L0|L1}, {&upd7810_device::IN, 2,10,10,L0|L1}, + {&upd7810_device::IN, 2,10,10,L0|L1}, {&upd7810_device::IN, 2,10,10,L0|L1}, + + {&upd7810_device::IN, 2,10,10,L0|L1}, {&upd7810_device::IN, 2,10,10,L0|L1}, + {&upd7810_device::IN, 2,10,10,L0|L1}, {&upd7810_device::IN, 2,10,10,L0|L1}, + {&upd7810_device::IN, 2,10,10,L0|L1}, {&upd7810_device::IN, 2,10,10,L0|L1}, + {&upd7810_device::IN, 2,10,10,L0|L1}, {&upd7810_device::IN, 2,10,10,L0|L1}, + {&upd7810_device::IN, 2,10,10,L0|L1}, {&upd7810_device::IN, 2,10,10,L0|L1}, + {&upd7810_device::IN, 2,10,10,L0|L1}, {&upd7810_device::IN, 2,10,10,L0|L1}, + {&upd7810_device::IN, 2,10,10,L0|L1}, {&upd7810_device::IN, 2,10,10,L0|L1}, + {&upd7810_device::IN, 2,10,10,L0|L1}, {&upd7810_device::IN, 2,10,10,L0|L1}, + + /* 0xA0 - 0xBF */ + {&upd7810_device::IN, 2,10,10,L0|L1}, {&upd7810_device::IN, 2,10,10,L0|L1}, + {&upd7810_device::IN, 2,10,10,L0|L1}, {&upd7810_device::IN, 2,10,10,L0|L1}, + {&upd7810_device::IN, 2,10,10,L0|L1}, {&upd7810_device::IN, 2,10,10,L0|L1}, + {&upd7810_device::IN, 2,10,10,L0|L1}, {&upd7810_device::IN, 2,10,10,L0|L1}, + {&upd7810_device::IN, 2,10,10,L0|L1}, {&upd7810_device::IN, 2,10,10,L0|L1}, + {&upd7810_device::IN, 2,10,10,L0|L1}, {&upd7810_device::IN, 2,10,10,L0|L1}, + {&upd7810_device::IN, 2,10,10,L0|L1}, {&upd7810_device::IN, 2,10,10,L0|L1}, + {&upd7810_device::IN, 2,10,10,L0|L1}, {&upd7810_device::IN, 2,10,10,L0|L1}, + + {&upd7810_device::IN, 2,10,10,L0|L1}, {&upd7810_device::IN, 2,10,10,L0|L1}, + {&upd7810_device::IN, 2,10,10,L0|L1}, {&upd7810_device::IN, 2,10,10,L0|L1}, + {&upd7810_device::IN, 2,10,10,L0|L1}, {&upd7810_device::IN, 2,10,10,L0|L1}, + {&upd7810_device::IN, 2,10,10,L0|L1}, {&upd7810_device::IN, 2,10,10,L0|L1}, + {&upd7810_device::IN, 2,10,10,L0|L1}, {&upd7810_device::IN, 2,10,10,L0|L1}, + {&upd7810_device::IN, 2,10,10,L0|L1}, {&upd7810_device::IN, 2,10,10,L0|L1}, + {&upd7810_device::IN, 2,10,10,L0|L1}, {&upd7810_device::IN, 2,10,10,L0|L1}, + {&upd7810_device::IN, 2,10,10,L0|L1}, {&upd7810_device::IN, 2,10,10,L0|L1}, + + /* 0xC0 - 0xDF */ + {&upd7810_device::MOV_A_PA, 2,10,10,L0|L1}, {&upd7810_device::MOV_A_PB, 2,10,10,L0|L1}, + {&upd7810_device::MOV_A_PC, 2,10,10,L0|L1}, {&upd7810_device::MOV_A_MKL, 2,10,10,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::MOV_A_S, 2,10,10,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + /* 0xE0 - 0xFF */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1} +}; + +/* prefix 4D */ +const struct upd7810_device::opcode_s upd7810_device::s_op4D_7801[256] = +{ + /* 0x00 - 0x1F */ + {&upd7810_device::OUT, 2,10,10,L0|L1}, {&upd7810_device::OUT, 2,10,10,L0|L1}, + {&upd7810_device::OUT, 2,10,10,L0|L1}, {&upd7810_device::OUT, 2,10,10,L0|L1}, + {&upd7810_device::OUT, 2,10,10,L0|L1}, {&upd7810_device::OUT, 2,10,10,L0|L1}, + {&upd7810_device::OUT, 2,10,10,L0|L1}, {&upd7810_device::OUT, 2,10,10,L0|L1}, + {&upd7810_device::OUT, 2,10,10,L0|L1}, {&upd7810_device::OUT, 2,10,10,L0|L1}, + {&upd7810_device::OUT, 2,10,10,L0|L1}, {&upd7810_device::OUT, 2,10,10,L0|L1}, + {&upd7810_device::OUT, 2,10,10,L0|L1}, {&upd7810_device::OUT, 2,10,10,L0|L1}, + {&upd7810_device::OUT, 2,10,10,L0|L1}, {&upd7810_device::OUT, 2,10,10,L0|L1}, + + {&upd7810_device::OUT, 2,10,10,L0|L1}, {&upd7810_device::OUT, 2,10,10,L0|L1}, + {&upd7810_device::OUT, 2,10,10,L0|L1}, {&upd7810_device::OUT, 2,10,10,L0|L1}, + {&upd7810_device::OUT, 2,10,10,L0|L1}, {&upd7810_device::OUT, 2,10,10,L0|L1}, + {&upd7810_device::OUT, 2,10,10,L0|L1}, {&upd7810_device::OUT, 2,10,10,L0|L1}, + {&upd7810_device::OUT, 2,10,10,L0|L1}, {&upd7810_device::OUT, 2,10,10,L0|L1}, + {&upd7810_device::OUT, 2,10,10,L0|L1}, {&upd7810_device::OUT, 2,10,10,L0|L1}, + {&upd7810_device::OUT, 2,10,10,L0|L1}, {&upd7810_device::OUT, 2,10,10,L0|L1}, + {&upd7810_device::OUT, 2,10,10,L0|L1}, {&upd7810_device::OUT, 2,10,10,L0|L1}, + + /* 0x20 - 0x3F */ + {&upd7810_device::OUT, 2,10,10,L0|L1}, {&upd7810_device::OUT, 2,10,10,L0|L1}, + {&upd7810_device::OUT, 2,10,10,L0|L1}, {&upd7810_device::OUT, 2,10,10,L0|L1}, + {&upd7810_device::OUT, 2,10,10,L0|L1}, {&upd7810_device::OUT, 2,10,10,L0|L1}, + {&upd7810_device::OUT, 2,10,10,L0|L1}, {&upd7810_device::OUT, 2,10,10,L0|L1}, + {&upd7810_device::OUT, 2,10,10,L0|L1}, {&upd7810_device::OUT, 2,10,10,L0|L1}, + {&upd7810_device::OUT, 2,10,10,L0|L1}, {&upd7810_device::OUT, 2,10,10,L0|L1}, + {&upd7810_device::OUT, 2,10,10,L0|L1}, {&upd7810_device::OUT, 2,10,10,L0|L1}, + {&upd7810_device::OUT, 2,10,10,L0|L1}, {&upd7810_device::OUT, 2,10,10,L0|L1}, + + {&upd7810_device::OUT, 2,10,10,L0|L1}, {&upd7810_device::OUT, 2,10,10,L0|L1}, + {&upd7810_device::OUT, 2,10,10,L0|L1}, {&upd7810_device::OUT, 2,10,10,L0|L1}, + {&upd7810_device::OUT, 2,10,10,L0|L1}, {&upd7810_device::OUT, 2,10,10,L0|L1}, + {&upd7810_device::OUT, 2,10,10,L0|L1}, {&upd7810_device::OUT, 2,10,10,L0|L1}, + {&upd7810_device::OUT, 2,10,10,L0|L1}, {&upd7810_device::OUT, 2,10,10,L0|L1}, + {&upd7810_device::OUT, 2,10,10,L0|L1}, {&upd7810_device::OUT, 2,10,10,L0|L1}, + {&upd7810_device::OUT, 2,10,10,L0|L1}, {&upd7810_device::OUT, 2,10,10,L0|L1}, + {&upd7810_device::OUT, 2,10,10,L0|L1}, {&upd7810_device::OUT, 2,10,10,L0|L1}, + + /* 0x40 - 0x5F */ + {&upd7810_device::OUT, 2,10,10,L0|L1}, {&upd7810_device::OUT, 2,10,10,L0|L1}, + {&upd7810_device::OUT, 2,10,10,L0|L1}, {&upd7810_device::OUT, 2,10,10,L0|L1}, + {&upd7810_device::OUT, 2,10,10,L0|L1}, {&upd7810_device::OUT, 2,10,10,L0|L1}, + {&upd7810_device::OUT, 2,10,10,L0|L1}, {&upd7810_device::OUT, 2,10,10,L0|L1}, + {&upd7810_device::OUT, 2,10,10,L0|L1}, {&upd7810_device::OUT, 2,10,10,L0|L1}, + {&upd7810_device::OUT, 2,10,10,L0|L1}, {&upd7810_device::OUT, 2,10,10,L0|L1}, + {&upd7810_device::OUT, 2,10,10,L0|L1}, {&upd7810_device::OUT, 2,10,10,L0|L1}, + {&upd7810_device::OUT, 2,10,10,L0|L1}, {&upd7810_device::OUT, 2,10,10,L0|L1}, + + {&upd7810_device::OUT, 2,10,10,L0|L1}, {&upd7810_device::OUT, 2,10,10,L0|L1}, + {&upd7810_device::OUT, 2,10,10,L0|L1}, {&upd7810_device::OUT, 2,10,10,L0|L1}, + {&upd7810_device::OUT, 2,10,10,L0|L1}, {&upd7810_device::OUT, 2,10,10,L0|L1}, + {&upd7810_device::OUT, 2,10,10,L0|L1}, {&upd7810_device::OUT, 2,10,10,L0|L1}, + {&upd7810_device::OUT, 2,10,10,L0|L1}, {&upd7810_device::OUT, 2,10,10,L0|L1}, + {&upd7810_device::OUT, 2,10,10,L0|L1}, {&upd7810_device::OUT, 2,10,10,L0|L1}, + {&upd7810_device::OUT, 2,10,10,L0|L1}, {&upd7810_device::OUT, 2,10,10,L0|L1}, + {&upd7810_device::OUT, 2,10,10,L0|L1}, {&upd7810_device::OUT, 2,10,10,L0|L1}, + + /* 0x60 - 0x7F */ + {&upd7810_device::OUT, 2,10,10,L0|L1}, {&upd7810_device::OUT, 2,10,10,L0|L1}, + {&upd7810_device::OUT, 2,10,10,L0|L1}, {&upd7810_device::OUT, 2,10,10,L0|L1}, + {&upd7810_device::OUT, 2,10,10,L0|L1}, {&upd7810_device::OUT, 2,10,10,L0|L1}, + {&upd7810_device::OUT, 2,10,10,L0|L1}, {&upd7810_device::OUT, 2,10,10,L0|L1}, + {&upd7810_device::OUT, 2,10,10,L0|L1}, {&upd7810_device::OUT, 2,10,10,L0|L1}, + {&upd7810_device::OUT, 2,10,10,L0|L1}, {&upd7810_device::OUT, 2,10,10,L0|L1}, + {&upd7810_device::OUT, 2,10,10,L0|L1}, {&upd7810_device::OUT, 2,10,10,L0|L1}, + {&upd7810_device::OUT, 2,10,10,L0|L1}, {&upd7810_device::OUT, 2,10,10,L0|L1}, + + {&upd7810_device::OUT, 2,10,10,L0|L1}, {&upd7810_device::OUT, 2,10,10,L0|L1}, + {&upd7810_device::OUT, 2,10,10,L0|L1}, {&upd7810_device::OUT, 2,10,10,L0|L1}, + {&upd7810_device::OUT, 2,10,10,L0|L1}, {&upd7810_device::OUT, 2,10,10,L0|L1}, + {&upd7810_device::OUT, 2,10,10,L0|L1}, {&upd7810_device::OUT, 2,10,10,L0|L1}, + {&upd7810_device::OUT, 2,10,10,L0|L1}, {&upd7810_device::OUT, 2,10,10,L0|L1}, + {&upd7810_device::OUT, 2,10,10,L0|L1}, {&upd7810_device::OUT, 2,10,10,L0|L1}, + {&upd7810_device::OUT, 2,10,10,L0|L1}, {&upd7810_device::OUT, 2,10,10,L0|L1}, + {&upd7810_device::OUT, 2,10,10,L0|L1}, {&upd7810_device::OUT, 2,10,10,L0|L1}, + + /* 0x80 - 0x9F */ + {&upd7810_device::OUT, 2,10,10,L0|L1}, {&upd7810_device::OUT, 2,10,10,L0|L1}, + {&upd7810_device::OUT, 2,10,10,L0|L1}, {&upd7810_device::OUT, 2,10,10,L0|L1}, + {&upd7810_device::OUT, 2,10,10,L0|L1}, {&upd7810_device::OUT, 2,10,10,L0|L1}, + {&upd7810_device::OUT, 2,10,10,L0|L1}, {&upd7810_device::OUT, 2,10,10,L0|L1}, + {&upd7810_device::OUT, 2,10,10,L0|L1}, {&upd7810_device::OUT, 2,10,10,L0|L1}, + {&upd7810_device::OUT, 2,10,10,L0|L1}, {&upd7810_device::OUT, 2,10,10,L0|L1}, + {&upd7810_device::OUT, 2,10,10,L0|L1}, {&upd7810_device::OUT, 2,10,10,L0|L1}, + {&upd7810_device::OUT, 2,10,10,L0|L1}, {&upd7810_device::OUT, 2,10,10,L0|L1}, + + {&upd7810_device::OUT, 2,10,10,L0|L1}, {&upd7810_device::OUT, 2,10,10,L0|L1}, + {&upd7810_device::OUT, 2,10,10,L0|L1}, {&upd7810_device::OUT, 2,10,10,L0|L1}, + {&upd7810_device::OUT, 2,10,10,L0|L1}, {&upd7810_device::OUT, 2,10,10,L0|L1}, + {&upd7810_device::OUT, 2,10,10,L0|L1}, {&upd7810_device::OUT, 2,10,10,L0|L1}, + {&upd7810_device::OUT, 2,10,10,L0|L1}, {&upd7810_device::OUT, 2,10,10,L0|L1}, + {&upd7810_device::OUT, 2,10,10,L0|L1}, {&upd7810_device::OUT, 2,10,10,L0|L1}, + {&upd7810_device::OUT, 2,10,10,L0|L1}, {&upd7810_device::OUT, 2,10,10,L0|L1}, + {&upd7810_device::OUT, 2,10,10,L0|L1}, {&upd7810_device::OUT, 2,10,10,L0|L1}, + + /* 0xA0 - 0xBF */ + {&upd7810_device::OUT, 2,10,10,L0|L1}, {&upd7810_device::OUT, 2,10,10,L0|L1}, + {&upd7810_device::OUT, 2,10,10,L0|L1}, {&upd7810_device::OUT, 2,10,10,L0|L1}, + {&upd7810_device::OUT, 2,10,10,L0|L1}, {&upd7810_device::OUT, 2,10,10,L0|L1}, + {&upd7810_device::OUT, 2,10,10,L0|L1}, {&upd7810_device::OUT, 2,10,10,L0|L1}, + {&upd7810_device::OUT, 2,10,10,L0|L1}, {&upd7810_device::OUT, 2,10,10,L0|L1}, + {&upd7810_device::OUT, 2,10,10,L0|L1}, {&upd7810_device::OUT, 2,10,10,L0|L1}, + {&upd7810_device::OUT, 2,10,10,L0|L1}, {&upd7810_device::OUT, 2,10,10,L0|L1}, + {&upd7810_device::OUT, 2,10,10,L0|L1}, {&upd7810_device::OUT, 2,10,10,L0|L1}, + + {&upd7810_device::OUT, 2,10,10,L0|L1}, {&upd7810_device::OUT, 2,10,10,L0|L1}, + {&upd7810_device::OUT, 2,10,10,L0|L1}, {&upd7810_device::OUT, 2,10,10,L0|L1}, + {&upd7810_device::OUT, 2,10,10,L0|L1}, {&upd7810_device::OUT, 2,10,10,L0|L1}, + {&upd7810_device::OUT, 2,10,10,L0|L1}, {&upd7810_device::OUT, 2,10,10,L0|L1}, + {&upd7810_device::OUT, 2,10,10,L0|L1}, {&upd7810_device::OUT, 2,10,10,L0|L1}, + {&upd7810_device::OUT, 2,10,10,L0|L1}, {&upd7810_device::OUT, 2,10,10,L0|L1}, + {&upd7810_device::OUT, 2,10,10,L0|L1}, {&upd7810_device::OUT, 2,10,10,L0|L1}, + {&upd7810_device::OUT, 2,10,10,L0|L1}, {&upd7810_device::OUT, 2,10,10,L0|L1}, + + /* 0xC0 - 0xDF */ + {&upd7810_device::MOV_PA_A, 2,10,10,L0|L1}, {&upd7810_device::MOV_PB_A, 2,10,10,L0|L1}, + {&upd7810_device::MOV_PC_A, 2,10,10,L0|L1}, {&upd7810_device::MOV_MKL_A, 2,10,10,L0|L1}, + {&upd7810_device::MOV_MB_A, 2,10,10,L0|L1}, {&upd7810_device::MOV_MC_A_7801, 2,10,10,L0|L1}, + {&upd7810_device::MOV_TM0_A, 2,10,10,L0|L1}, {&upd7810_device::MOV_TM1_A, 2,10,10,L0|L1}, + {&upd7810_device::MOV_S_A, 2,10,10,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + /* 0xE0 - 0xFF */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1} +}; + +/* prefix 60 */ +const struct upd7810_device::opcode_s upd7810_device::s_op60_7801[256] = +{ + /* 0x00 - 0x1F */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::ANA_V_A, 2, 8, 8,L0|L1}, {&upd7810_device::ANA_A_A, 2, 8, 8,L0|L1}, + {&upd7810_device::ANA_B_A, 2, 8, 8,L0|L1}, {&upd7810_device::ANA_C_A, 2, 8, 8,L0|L1}, + {&upd7810_device::ANA_D_A, 2, 8, 8,L0|L1}, {&upd7810_device::ANA_E_A, 2, 8, 8,L0|L1}, + {&upd7810_device::ANA_H_A, 2, 8, 8,L0|L1}, {&upd7810_device::ANA_L_A, 2, 8, 8,L0|L1}, + + {&upd7810_device::XRA_V_A, 2, 8, 8,L0|L1}, {&upd7810_device::XRA_A_A, 2, 8, 8,L0|L1}, + {&upd7810_device::XRA_B_A, 2, 8, 8,L0|L1}, {&upd7810_device::XRA_C_A, 2, 8, 8,L0|L1}, + {&upd7810_device::XRA_D_A, 2, 8, 8,L0|L1}, {&upd7810_device::XRA_E_A, 2, 8, 8,L0|L1}, + {&upd7810_device::XRA_H_A, 2, 8, 8,L0|L1}, {&upd7810_device::XRA_L_A, 2, 8, 8,L0|L1}, + {&upd7810_device::ORA_V_A, 2, 8, 8,L0|L1}, {&upd7810_device::ORA_A_A, 2, 8, 8,L0|L1}, + {&upd7810_device::ORA_B_A, 2, 8, 8,L0|L1}, {&upd7810_device::ORA_C_A, 2, 8, 8,L0|L1}, + {&upd7810_device::ORA_D_A, 2, 8, 8,L0|L1}, {&upd7810_device::ORA_E_A, 2, 8, 8,L0|L1}, + {&upd7810_device::ORA_H_A, 2, 8, 8,L0|L1}, {&upd7810_device::ORA_L_A, 2, 8, 8,L0|L1}, + + /* 0x20 - 0x3F */ + {&upd7810_device::ADDNC_V_A, 2, 8, 8,L0|L1}, {&upd7810_device::ADDNC_A_A, 2, 8, 8,L0|L1}, + {&upd7810_device::ADDNC_B_A, 2, 8, 8,L0|L1}, {&upd7810_device::ADDNC_C_A, 2, 8, 8,L0|L1}, + {&upd7810_device::ADDNC_D_A, 2, 8, 8,L0|L1}, {&upd7810_device::ADDNC_E_A, 2, 8, 8,L0|L1}, + {&upd7810_device::ADDNC_H_A, 2, 8, 8,L0|L1}, {&upd7810_device::ADDNC_L_A, 2, 8, 8,L0|L1}, + {&upd7810_device::GTA_V_A, 2, 8, 8,L0|L1}, {&upd7810_device::GTA_A_A, 2, 8, 8,L0|L1}, + {&upd7810_device::GTA_B_A, 2, 8, 8,L0|L1}, {&upd7810_device::GTA_C_A, 2, 8, 8,L0|L1}, + {&upd7810_device::GTA_D_A, 2, 8, 8,L0|L1}, {&upd7810_device::GTA_E_A, 2, 8, 8,L0|L1}, + {&upd7810_device::GTA_H_A, 2, 8, 8,L0|L1}, {&upd7810_device::GTA_L_A, 2, 8, 8,L0|L1}, + + {&upd7810_device::SUBNB_V_A, 2, 8, 8,L0|L1}, {&upd7810_device::SUBNB_A_A, 2, 8, 8,L0|L1}, + {&upd7810_device::SUBNB_B_A, 2, 8, 8,L0|L1}, {&upd7810_device::SUBNB_C_A, 2, 8, 8,L0|L1}, + {&upd7810_device::SUBNB_D_A, 2, 8, 8,L0|L1}, {&upd7810_device::SUBNB_E_A, 2, 8, 8,L0|L1}, + {&upd7810_device::SUBNB_H_A, 2, 8, 8,L0|L1}, {&upd7810_device::SUBNB_L_A, 2, 8, 8,L0|L1}, + {&upd7810_device::LTA_V_A, 2, 8, 8,L0|L1}, {&upd7810_device::LTA_A_A, 2, 8, 8,L0|L1}, + {&upd7810_device::LTA_B_A, 2, 8, 8,L0|L1}, {&upd7810_device::LTA_C_A, 2, 8, 8,L0|L1}, + {&upd7810_device::LTA_D_A, 2, 8, 8,L0|L1}, {&upd7810_device::LTA_E_A, 2, 8, 8,L0|L1}, + {&upd7810_device::LTA_H_A, 2, 8, 8,L0|L1}, {&upd7810_device::LTA_L_A, 2, 8, 8,L0|L1}, + + /* 0x40 - 0x5F */ + {&upd7810_device::ADD_V_A, 2, 8, 8,L0|L1}, {&upd7810_device::ADD_A_A, 2, 8, 8,L0|L1}, + {&upd7810_device::ADD_B_A, 2, 8, 8,L0|L1}, {&upd7810_device::ADD_C_A, 2, 8, 8,L0|L1}, + {&upd7810_device::ADD_D_A, 2, 8, 8,L0|L1}, {&upd7810_device::ADD_E_A, 2, 8, 8,L0|L1}, + {&upd7810_device::ADD_H_A, 2, 8, 8,L0|L1}, {&upd7810_device::ADD_L_A, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + {&upd7810_device::ADC_V_A, 2, 8, 8,L0|L1}, {&upd7810_device::ADC_A_A, 2, 8, 8,L0|L1}, + {&upd7810_device::ADC_B_A, 2, 8, 8,L0|L1}, {&upd7810_device::ADC_C_A, 2, 8, 8,L0|L1}, + {&upd7810_device::ADC_D_A, 2, 8, 8,L0|L1}, {&upd7810_device::ADC_E_A, 2, 8, 8,L0|L1}, + {&upd7810_device::ADC_H_A, 2, 8, 8,L0|L1}, {&upd7810_device::ADC_L_A, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + /* 0x60 - 0x7F */ + {&upd7810_device::SUB_V_A, 2, 8, 8,L0|L1}, {&upd7810_device::SUB_A_A, 2, 8, 8,L0|L1}, + {&upd7810_device::SUB_B_A, 2, 8, 8,L0|L1}, {&upd7810_device::SUB_C_A, 2, 8, 8,L0|L1}, + {&upd7810_device::SUB_D_A, 2, 8, 8,L0|L1}, {&upd7810_device::SUB_E_A, 2, 8, 8,L0|L1}, + {&upd7810_device::SUB_H_A, 2, 8, 8,L0|L1}, {&upd7810_device::SUB_L_A, 2, 8, 8,L0|L1}, + {&upd7810_device::NEA_V_A, 2, 8, 8,L0|L1}, {&upd7810_device::NEA_A_A, 2, 8, 8,L0|L1}, + {&upd7810_device::NEA_B_A, 2, 8, 8,L0|L1}, {&upd7810_device::NEA_C_A, 2, 8, 8,L0|L1}, + {&upd7810_device::NEA_D_A, 2, 8, 8,L0|L1}, {&upd7810_device::NEA_E_A, 2, 8, 8,L0|L1}, + {&upd7810_device::NEA_H_A, 2, 8, 8,L0|L1}, {&upd7810_device::NEA_L_A, 2, 8, 8,L0|L1}, + + {&upd7810_device::SBB_V_A, 2, 8, 8,L0|L1}, {&upd7810_device::SBB_A_A, 2, 8, 8,L0|L1}, + {&upd7810_device::SBB_B_A, 2, 8, 8,L0|L1}, {&upd7810_device::SBB_C_A, 2, 8, 8,L0|L1}, + {&upd7810_device::SBB_D_A, 2, 8, 8,L0|L1}, {&upd7810_device::SBB_E_A, 2, 8, 8,L0|L1}, + {&upd7810_device::SBB_H_A, 2, 8, 8,L0|L1}, {&upd7810_device::SBB_L_A, 2, 8, 8,L0|L1}, + {&upd7810_device::EQA_V_A, 2, 8, 8,L0|L1}, {&upd7810_device::EQA_A_A, 2, 8, 8,L0|L1}, + {&upd7810_device::EQA_B_A, 2, 8, 8,L0|L1}, {&upd7810_device::EQA_C_A, 2, 8, 8,L0|L1}, + {&upd7810_device::EQA_D_A, 2, 8, 8,L0|L1}, {&upd7810_device::EQA_E_A, 2, 8, 8,L0|L1}, + {&upd7810_device::EQA_H_A, 2, 8, 8,L0|L1}, {&upd7810_device::EQA_L_A, 2, 8, 8,L0|L1}, + + /* 0x80 - 0x9F */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::ANA_A_V, 2, 8, 8,L0|L1}, {&upd7810_device::ANA_A_A, 2, 8, 8,L0|L1}, + {&upd7810_device::ANA_A_B, 2, 8, 8,L0|L1}, {&upd7810_device::ANA_A_C, 2, 8, 8,L0|L1}, + {&upd7810_device::ANA_A_D, 2, 8, 8,L0|L1}, {&upd7810_device::ANA_A_E, 2, 8, 8,L0|L1}, + {&upd7810_device::ANA_A_H, 2, 8, 8,L0|L1}, {&upd7810_device::ANA_A_L, 2, 8, 8,L0|L1}, + + {&upd7810_device::XRA_A_V, 2, 8, 8,L0|L1}, {&upd7810_device::XRA_A_A, 2, 8, 8,L0|L1}, + {&upd7810_device::XRA_A_B, 2, 8, 8,L0|L1}, {&upd7810_device::XRA_A_C, 2, 8, 8,L0|L1}, + {&upd7810_device::XRA_A_D, 2, 8, 8,L0|L1}, {&upd7810_device::XRA_A_E, 2, 8, 8,L0|L1}, + {&upd7810_device::XRA_A_H, 2, 8, 8,L0|L1}, {&upd7810_device::XRA_A_L, 2, 8, 8,L0|L1}, + {&upd7810_device::ORA_A_V, 2, 8, 8,L0|L1}, {&upd7810_device::ORA_A_A, 2, 8, 8,L0|L1}, + {&upd7810_device::ORA_A_B, 2, 8, 8,L0|L1}, {&upd7810_device::ORA_A_C, 2, 8, 8,L0|L1}, + {&upd7810_device::ORA_A_D, 2, 8, 8,L0|L1}, {&upd7810_device::ORA_A_E, 2, 8, 8,L0|L1}, + {&upd7810_device::ORA_A_H, 2, 8, 8,L0|L1}, {&upd7810_device::ORA_A_L, 2, 8, 8,L0|L1}, + + /* 0xA0 - 0xBF */ + {&upd7810_device::ADDNC_A_V, 2, 8, 8,L0|L1}, {&upd7810_device::ADDNC_A_A, 2, 8, 8,L0|L1}, + {&upd7810_device::ADDNC_A_B, 2, 8, 8,L0|L1}, {&upd7810_device::ADDNC_A_C, 2, 8, 8,L0|L1}, + {&upd7810_device::ADDNC_A_D, 2, 8, 8,L0|L1}, {&upd7810_device::ADDNC_A_E, 2, 8, 8,L0|L1}, + {&upd7810_device::ADDNC_A_H, 2, 8, 8,L0|L1}, {&upd7810_device::ADDNC_A_L, 2, 8, 8,L0|L1}, + {&upd7810_device::GTA_A_V, 2, 8, 8,L0|L1}, {&upd7810_device::GTA_A_A, 2, 8, 8,L0|L1}, + {&upd7810_device::GTA_A_B, 2, 8, 8,L0|L1}, {&upd7810_device::GTA_A_C, 2, 8, 8,L0|L1}, + {&upd7810_device::GTA_A_D, 2, 8, 8,L0|L1}, {&upd7810_device::GTA_A_E, 2, 8, 8,L0|L1}, + {&upd7810_device::GTA_A_H, 2, 8, 8,L0|L1}, {&upd7810_device::GTA_A_L, 2, 8, 8,L0|L1}, + + {&upd7810_device::SUBNB_A_V, 2, 8, 8,L0|L1}, {&upd7810_device::SUBNB_A_A, 2, 8, 8,L0|L1}, + {&upd7810_device::SUBNB_A_B, 2, 8, 8,L0|L1}, {&upd7810_device::SUBNB_A_C, 2, 8, 8,L0|L1}, + {&upd7810_device::SUBNB_A_D, 2, 8, 8,L0|L1}, {&upd7810_device::SUBNB_A_E, 2, 8, 8,L0|L1}, + {&upd7810_device::SUBNB_A_H, 2, 8, 8,L0|L1}, {&upd7810_device::SUBNB_A_L, 2, 8, 8,L0|L1}, + {&upd7810_device::LTA_A_V, 2, 8, 8,L0|L1}, {&upd7810_device::LTA_A_A, 2, 8, 8,L0|L1}, + {&upd7810_device::LTA_A_B, 2, 8, 8,L0|L1}, {&upd7810_device::LTA_A_C, 2, 8, 8,L0|L1}, + {&upd7810_device::LTA_A_D, 2, 8, 8,L0|L1}, {&upd7810_device::LTA_A_E, 2, 8, 8,L0|L1}, + {&upd7810_device::LTA_A_H, 2, 8, 8,L0|L1}, {&upd7810_device::LTA_A_L, 2, 8, 8,L0|L1}, + + /* 0xC0 - 0xDF */ + {&upd7810_device::ADD_A_V, 2, 8, 8,L0|L1}, {&upd7810_device::ADD_A_A, 2, 8, 8,L0|L1}, + {&upd7810_device::ADD_A_B, 2, 8, 8,L0|L1}, {&upd7810_device::ADD_A_C, 2, 8, 8,L0|L1}, + {&upd7810_device::ADD_A_D, 2, 8, 8,L0|L1}, {&upd7810_device::ADD_A_E, 2, 8, 8,L0|L1}, + {&upd7810_device::ADD_A_H, 2, 8, 8,L0|L1}, {&upd7810_device::ADD_A_L, 2, 8, 8,L0|L1}, + {&upd7810_device::ONA_A_V, 2, 8, 8,L0|L1}, {&upd7810_device::ONA_A_A, 2, 8, 8,L0|L1}, + {&upd7810_device::ONA_A_B, 2, 8, 8,L0|L1}, {&upd7810_device::ONA_A_C, 2, 8, 8,L0|L1}, + {&upd7810_device::ONA_A_D, 2, 8, 8,L0|L1}, {&upd7810_device::ONA_A_E, 2, 8, 8,L0|L1}, + {&upd7810_device::ONA_A_H, 2, 8, 8,L0|L1}, {&upd7810_device::ONA_A_L, 2, 8, 8,L0|L1}, + + {&upd7810_device::ADC_A_V, 2, 8, 8,L0|L1}, {&upd7810_device::ADC_A_A, 2, 8, 8,L0|L1}, + {&upd7810_device::ADC_A_B, 2, 8, 8,L0|L1}, {&upd7810_device::ADC_A_C, 2, 8, 8,L0|L1}, + {&upd7810_device::ADC_A_D, 2, 8, 8,L0|L1}, {&upd7810_device::ADC_A_E, 2, 8, 8,L0|L1}, + {&upd7810_device::ADC_A_H, 2, 8, 8,L0|L1}, {&upd7810_device::ADC_A_L, 2, 8, 8,L0|L1}, + {&upd7810_device::OFFA_A_V, 2, 8, 8,L0|L1}, {&upd7810_device::OFFA_A_A, 2, 8, 8,L0|L1}, + {&upd7810_device::OFFA_A_B, 2, 8, 8,L0|L1}, {&upd7810_device::OFFA_A_C, 2, 8, 8,L0|L1}, + {&upd7810_device::OFFA_A_D, 2, 8, 8,L0|L1}, {&upd7810_device::OFFA_A_E, 2, 8, 8,L0|L1}, + {&upd7810_device::OFFA_A_H, 2, 8, 8,L0|L1}, {&upd7810_device::OFFA_A_L, 2, 8, 8,L0|L1}, + + /* 0xE0 - 0xFF */ + {&upd7810_device::SUB_A_V, 2, 8, 8,L0|L1}, {&upd7810_device::SUB_A_A, 2, 8, 8,L0|L1}, + {&upd7810_device::SUB_A_B, 2, 8, 8,L0|L1}, {&upd7810_device::SUB_A_C, 2, 8, 8,L0|L1}, + {&upd7810_device::SUB_A_D, 2, 8, 8,L0|L1}, {&upd7810_device::SUB_A_E, 2, 8, 8,L0|L1}, + {&upd7810_device::SUB_A_H, 2, 8, 8,L0|L1}, {&upd7810_device::SUB_A_L, 2, 8, 8,L0|L1}, + {&upd7810_device::NEA_A_V, 2, 8, 8,L0|L1}, {&upd7810_device::NEA_A_A, 2, 8, 8,L0|L1}, + {&upd7810_device::NEA_A_B, 2, 8, 8,L0|L1}, {&upd7810_device::NEA_A_C, 2, 8, 8,L0|L1}, + {&upd7810_device::NEA_A_D, 2, 8, 8,L0|L1}, {&upd7810_device::NEA_A_E, 2, 8, 8,L0|L1}, + {&upd7810_device::NEA_A_H, 2, 8, 8,L0|L1}, {&upd7810_device::NEA_A_L, 2, 8, 8,L0|L1}, + + {&upd7810_device::SBB_A_V, 2, 8, 8,L0|L1}, {&upd7810_device::SBB_A_A, 2, 8, 8,L0|L1}, + {&upd7810_device::SBB_A_B, 2, 8, 8,L0|L1}, {&upd7810_device::SBB_A_C, 2, 8, 8,L0|L1}, + {&upd7810_device::SBB_A_D, 2, 8, 8,L0|L1}, {&upd7810_device::SBB_A_E, 2, 8, 8,L0|L1}, + {&upd7810_device::SBB_A_H, 2, 8, 8,L0|L1}, {&upd7810_device::SBB_A_L, 2, 8, 8,L0|L1}, + {&upd7810_device::EQA_A_V, 2, 8, 8,L0|L1}, {&upd7810_device::EQA_A_A, 2, 8, 8,L0|L1}, + {&upd7810_device::EQA_A_B, 2, 8, 8,L0|L1}, {&upd7810_device::EQA_A_C, 2, 8, 8,L0|L1}, + {&upd7810_device::EQA_A_D, 2, 8, 8,L0|L1}, {&upd7810_device::EQA_A_E, 2, 8, 8,L0|L1}, + {&upd7810_device::EQA_A_H, 2, 8, 8,L0|L1}, {&upd7810_device::EQA_A_L, 2, 8, 8,L0|L1} +}; + +/* prefix 64 */ +const struct upd7810_device::opcode_s upd7810_device::s_op64_7801[256] = +{ + /* 0x00 - 0x1F */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::ANI_V_xx, 3,11,11,L0|L1}, {&upd7810_device::ANI_A_xx, 3,11,11,L0|L1}, + {&upd7810_device::ANI_B_xx, 3,11,11,L0|L1}, {&upd7810_device::ANI_C_xx, 3,11,11,L0|L1}, + {&upd7810_device::ANI_D_xx, 3,11,11,L0|L1}, {&upd7810_device::ANI_E_xx, 3,11,11,L0|L1}, + {&upd7810_device::ANI_H_xx, 3,11,11,L0|L1}, {&upd7810_device::ANI_L_xx, 3,11,11,L0|L1}, + + {&upd7810_device::XRI_V_xx, 3,11,11,L0|L1}, {&upd7810_device::XRI_A_xx, 3,11,11,L0|L1}, + {&upd7810_device::XRI_B_xx, 3,11,11,L0|L1}, {&upd7810_device::XRI_C_xx, 3,11,11,L0|L1}, + {&upd7810_device::XRI_D_xx, 3,11,11,L0|L1}, {&upd7810_device::XRI_E_xx, 3,11,11,L0|L1}, + {&upd7810_device::XRI_H_xx, 3,11,11,L0|L1}, {&upd7810_device::XRI_L_xx, 3,11,11,L0|L1}, + {&upd7810_device::ORI_V_xx, 3,11,11,L0|L1}, {&upd7810_device::ORI_A_xx, 3,11,11,L0|L1}, + {&upd7810_device::ORI_B_xx, 3,11,11,L0|L1}, {&upd7810_device::ORI_C_xx, 3,11,11,L0|L1}, + {&upd7810_device::ORI_D_xx, 3,11,11,L0|L1}, {&upd7810_device::ORI_E_xx, 3,11,11,L0|L1}, + {&upd7810_device::ORI_H_xx, 3,11,11,L0|L1}, {&upd7810_device::ORI_L_xx, 3,11,11,L0|L1}, + + /* 0x20 - 0x3F */ + {&upd7810_device::ADINC_V_xx, 3,11,11,L0|L1}, {&upd7810_device::ADINC_A_xx, 3,11,11,L0|L1}, + {&upd7810_device::ADINC_B_xx, 3,11,11,L0|L1}, {&upd7810_device::ADINC_C_xx, 3,11,11,L0|L1}, + {&upd7810_device::ADINC_D_xx, 3,11,11,L0|L1}, {&upd7810_device::ADINC_E_xx, 3,11,11,L0|L1}, + {&upd7810_device::ADINC_H_xx, 3,11,11,L0|L1}, {&upd7810_device::ADINC_L_xx, 3,11,11,L0|L1}, + {&upd7810_device::GTI_V_xx, 3,11,11,L0|L1}, {&upd7810_device::GTI_A_xx, 3,11,11,L0|L1}, + {&upd7810_device::GTI_B_xx, 3,11,11,L0|L1}, {&upd7810_device::GTI_C_xx, 3,11,11,L0|L1}, + {&upd7810_device::GTI_D_xx, 3,11,11,L0|L1}, {&upd7810_device::GTI_E_xx, 3,11,11,L0|L1}, + {&upd7810_device::GTI_H_xx, 3,11,11,L0|L1}, {&upd7810_device::GTI_L_xx, 3,11,11,L0|L1}, + + {&upd7810_device::SUINB_V_xx, 3,11,11,L0|L1}, {&upd7810_device::SUINB_A_xx, 3,11,11,L0|L1}, + {&upd7810_device::SUINB_B_xx, 3,11,11,L0|L1}, {&upd7810_device::SUINB_C_xx, 3,11,11,L0|L1}, + {&upd7810_device::SUINB_D_xx, 3,11,11,L0|L1}, {&upd7810_device::SUINB_E_xx, 3,11,11,L0|L1}, + {&upd7810_device::SUINB_H_xx, 3,11,11,L0|L1}, {&upd7810_device::SUINB_L_xx, 3,11,11,L0|L1}, + {&upd7810_device::LTI_V_xx, 3,11,11,L0|L1}, {&upd7810_device::LTI_A_xx, 3,11,11,L0|L1}, + {&upd7810_device::LTI_B_xx, 3,11,11,L0|L1}, {&upd7810_device::LTI_C_xx, 3,11,11,L0|L1}, + {&upd7810_device::LTI_D_xx, 3,11,11,L0|L1}, {&upd7810_device::LTI_E_xx, 3,11,11,L0|L1}, + {&upd7810_device::LTI_H_xx, 3,11,11,L0|L1}, {&upd7810_device::LTI_L_xx, 3,11,11,L0|L1}, + + /* 0x40 - 0x5F */ + {&upd7810_device::ADI_V_xx, 3,11,11,L0|L1}, {&upd7810_device::ADI_A_xx, 3,11,11,L0|L1}, + {&upd7810_device::ADI_B_xx, 3,11,11,L0|L1}, {&upd7810_device::ADI_C_xx, 3,11,11,L0|L1}, + {&upd7810_device::ADI_D_xx, 3,11,11,L0|L1}, {&upd7810_device::ADI_E_xx, 3,11,11,L0|L1}, + {&upd7810_device::ADI_H_xx, 3,11,11,L0|L1}, {&upd7810_device::ADI_L_xx, 3,11,11,L0|L1}, + {&upd7810_device::ONI_V_xx, 3,11,11,L0|L1}, {&upd7810_device::ONI_A_xx, 3,11,11,L0|L1}, + {&upd7810_device::ONI_B_xx, 3,11,11,L0|L1}, {&upd7810_device::ONI_C_xx, 3,11,11,L0|L1}, + {&upd7810_device::ONI_D_xx, 3,11,11,L0|L1}, {&upd7810_device::ONI_E_xx, 3,11,11,L0|L1}, + {&upd7810_device::ONI_H_xx, 3,11,11,L0|L1}, {&upd7810_device::ONI_L_xx, 3,11,11,L0|L1}, + + {&upd7810_device::ACI_V_xx, 3,11,11,L0|L1}, {&upd7810_device::ACI_A_xx, 3,11,11,L0|L1}, + {&upd7810_device::ACI_B_xx, 3,11,11,L0|L1}, {&upd7810_device::ACI_C_xx, 3,11,11,L0|L1}, + {&upd7810_device::ACI_D_xx, 3,11,11,L0|L1}, {&upd7810_device::ACI_E_xx, 3,11,11,L0|L1}, + {&upd7810_device::ACI_H_xx, 3,11,11,L0|L1}, {&upd7810_device::ACI_L_xx, 3,11,11,L0|L1}, + {&upd7810_device::OFFI_V_xx, 3,11,11,L0|L1}, {&upd7810_device::OFFI_A_xx, 3,11,11,L0|L1}, + {&upd7810_device::OFFI_B_xx, 3,11,11,L0|L1}, {&upd7810_device::OFFI_C_xx, 3,11,11,L0|L1}, + {&upd7810_device::OFFI_D_xx, 3,11,11,L0|L1}, {&upd7810_device::OFFI_E_xx, 3,11,11,L0|L1}, + {&upd7810_device::OFFI_H_xx, 3,11,11,L0|L1}, {&upd7810_device::OFFI_L_xx, 3,11,11,L0|L1}, + + /* 0x60 - 0x7F */ + {&upd7810_device::SUI_V_xx, 3,11,11,L0|L1}, {&upd7810_device::SUI_A_xx, 3,11,11,L0|L1}, + {&upd7810_device::SUI_B_xx, 3,11,11,L0|L1}, {&upd7810_device::SUI_C_xx, 3,11,11,L0|L1}, + {&upd7810_device::SUI_D_xx, 3,11,11,L0|L1}, {&upd7810_device::SUI_E_xx, 3,11,11,L0|L1}, + {&upd7810_device::SUI_H_xx, 3,11,11,L0|L1}, {&upd7810_device::SUI_L_xx, 3,11,11,L0|L1}, + {&upd7810_device::NEI_V_xx, 3,11,11,L0|L1}, {&upd7810_device::NEI_A_xx, 3,11,11,L0|L1}, + {&upd7810_device::NEI_B_xx, 3,11,11,L0|L1}, {&upd7810_device::NEI_C_xx, 3,11,11,L0|L1}, + {&upd7810_device::NEI_D_xx, 3,11,11,L0|L1}, {&upd7810_device::NEI_E_xx, 3,11,11,L0|L1}, + {&upd7810_device::NEI_H_xx, 3,11,11,L0|L1}, {&upd7810_device::NEI_L_xx, 3,11,11,L0|L1}, + + {&upd7810_device::SBI_V_xx, 3,11,11,L0|L1}, {&upd7810_device::SBI_A_xx, 3,11,11,L0|L1}, + {&upd7810_device::SBI_B_xx, 3,11,11,L0|L1}, {&upd7810_device::SBI_C_xx, 3,11,11,L0|L1}, + {&upd7810_device::SBI_D_xx, 3,11,11,L0|L1}, {&upd7810_device::SBI_E_xx, 3,11,11,L0|L1}, + {&upd7810_device::SBI_H_xx, 3,11,11,L0|L1}, {&upd7810_device::SBI_L_xx, 3,11,11,L0|L1}, + {&upd7810_device::EQI_V_xx, 3,11,11,L0|L1}, {&upd7810_device::EQI_A_xx, 3,11,11,L0|L1}, + {&upd7810_device::EQI_B_xx, 3,11,11,L0|L1}, {&upd7810_device::EQI_C_xx, 3,11,11,L0|L1}, + {&upd7810_device::EQI_D_xx, 3,11,11,L0|L1}, {&upd7810_device::EQI_E_xx, 3,11,11,L0|L1}, + {&upd7810_device::EQI_H_xx, 3,11,11,L0|L1}, {&upd7810_device::EQI_L_xx, 3,11,11,L0|L1}, + + /* 0x80 - 0x9F */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::ANI_PA_xx, 3,17,17,L0|L1}, {&upd7810_device::ANI_PB_xx, 3,17,17,L0|L1}, + {&upd7810_device::ANI_PC_xx, 3,17,17,L0|L1}, {&upd7810_device::ANI_MKL_xx, 3,17,17,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + {&upd7810_device::XRI_PA_xx, 3,17,17,L0|L1}, {&upd7810_device::XRI_PB_xx, 3,17,17,L0|L1}, + {&upd7810_device::XRI_PC_xx, 3,17,17,L0|L1}, {&upd7810_device::XRI_MKL_xx, 3,17,17,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::ORI_PA_xx, 3,17,17,L0|L1}, {&upd7810_device::ORI_PB_xx, 3,17,17,L0|L1}, + {&upd7810_device::ORI_PC_xx, 3,17,17,L0|L1}, {&upd7810_device::ORI_MKL_xx, 3,17,17,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + /* 0xA0 - 0xBF */ + {&upd7810_device::ADINC_PA_xx, 3,17,17,L0|L1}, {&upd7810_device::ADINC_PB_xx, 3,17,17,L0|L1}, + {&upd7810_device::ADINC_PC_xx, 3,17,17,L0|L1}, {&upd7810_device::ADINC_MKL_xx, 3,17,17,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::GTI_PA_xx, 3,14,14,L0|L1}, {&upd7810_device::GTI_PB_xx, 3,14,14,L0|L1}, + {&upd7810_device::GTI_PC_xx, 3,14,14,L0|L1}, {&upd7810_device::GTI_MKL_xx, 3,14,14,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + {&upd7810_device::SUINB_PA_xx, 3,17,17,L0|L1}, {&upd7810_device::SUINB_PB_xx, 3,17,17,L0|L1}, + {&upd7810_device::SUINB_PC_xx, 3,17,17,L0|L1}, {&upd7810_device::SUINB_MKL_xx, 3,17,17,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::LTI_PA_xx, 3,14,14,L0|L1}, {&upd7810_device::LTI_PB_xx, 3,14,14,L0|L1}, + {&upd7810_device::LTI_PC_xx, 3,14,14,L0|L1}, {&upd7810_device::LTI_MKL_xx, 3,14,14,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + /* 0xC0 - 0xDF */ + {&upd7810_device::ADI_PA_xx, 3,17,17,L0|L1}, {&upd7810_device::ADI_PB_xx, 3,17,17,L0|L1}, + {&upd7810_device::ADI_PC_xx, 3,17,17,L0|L1}, {&upd7810_device::ADI_MKL_xx, 3,17,17,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::ONI_PA_xx, 3,14,14,L0|L1}, {&upd7810_device::ONI_PB_xx, 3,14,14,L0|L1}, + {&upd7810_device::ONI_PC_xx, 3,14,14,L0|L1}, {&upd7810_device::ONI_MKL_xx, 3,14,14,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + {&upd7810_device::ACI_PA_xx, 3,17,17,L0|L1}, {&upd7810_device::ACI_PB_xx, 3,17,17,L0|L1}, + {&upd7810_device::ACI_PC_xx, 3,17,17,L0|L1}, {&upd7810_device::ACI_MKL_xx, 3,17,17,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::OFFI_PA_xx, 3,14,14,L0|L1}, {&upd7810_device::OFFI_PB_xx, 3,14,14,L0|L1}, + {&upd7810_device::OFFI_PC_xx, 3,14,14,L0|L1}, {&upd7810_device::OFFI_MKL_xx, 3,14,14,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + /* 0xE0 - 0xFF */ + {&upd7810_device::SUI_PA_xx, 3,17,17,L0|L1}, {&upd7810_device::SUI_PB_xx, 3,17,17,L0|L1}, + {&upd7810_device::SUI_PC_xx, 3,17,17,L0|L1}, {&upd7810_device::SUI_MKL_xx, 3,17,17,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::NEI_PA_xx, 3,14,14,L0|L1}, {&upd7810_device::NEI_PB_xx, 3,14,14,L0|L1}, + {&upd7810_device::NEI_PC_xx, 3,14,14,L0|L1}, {&upd7810_device::NEI_MKL_xx, 3,14,14,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + {&upd7810_device::SBI_PA_xx, 3,17,17,L0|L1}, {&upd7810_device::SBI_PB_xx, 3,17,17,L0|L1}, + {&upd7810_device::SBI_PC_xx, 3,17,17,L0|L1}, {&upd7810_device::SBI_MKL_xx, 3,17,17,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::EQI_PA_xx, 3,14,14,L0|L1}, {&upd7810_device::EQI_PB_xx, 3,14,14,L0|L1}, + {&upd7810_device::EQI_PC_xx, 3,14,14,L0|L1}, {&upd7810_device::EQI_MKL_xx, 3,14,14,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1} +}; + +/* prefix 70 */ +const struct upd7810_device::opcode_s upd7810_device::s_op70_7801[256] = +{ + /* 0x00 - 0x1F */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::SSPD_w, 4,20,20,L0|L1}, {&upd7810_device::LSPD_w, 4,20,20,L0|L1}, + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::SBCD_w, 4,20,20,L0|L1}, {&upd7810_device::LBCD_w, 4,20,20,L0|L1}, + + /* 0x20 - 0x3F */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::SDED_w, 4,20,20,L0|L1}, {&upd7810_device::LDED_w, 4,20,20,L0|L1}, + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::SHLD_w, 4,20,20,L0|L1}, {&upd7810_device::LHLD_w, 4,20,20,L0|L1}, + + /* 0x40 - 0x5F */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + /* 0x60 - 0x7F */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::MOV_V_w, 4,17,17,L0|L1}, {&upd7810_device::MOV_A_w, 4,17,17,L0|L1}, + {&upd7810_device::MOV_B_w, 4,17,17,L0|L1}, {&upd7810_device::MOV_C_w, 4,17,17,L0|L1}, + {&upd7810_device::MOV_D_w, 4,17,17,L0|L1}, {&upd7810_device::MOV_E_w, 4,17,17,L0|L1}, + {&upd7810_device::MOV_H_w, 4,17,17,L0|L1}, {&upd7810_device::MOV_L_w, 4,17,17,L0|L1}, + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::MOV_w_V, 4,17,17,L0|L1}, {&upd7810_device::MOV_w_A, 4,17,17,L0|L1}, + {&upd7810_device::MOV_w_B, 4,17,17,L0|L1}, {&upd7810_device::MOV_w_C, 4,17,17,L0|L1}, + {&upd7810_device::MOV_w_D, 4,17,17,L0|L1}, {&upd7810_device::MOV_w_E, 4,17,17,L0|L1}, + {&upd7810_device::MOV_w_H, 4,17,17,L0|L1}, {&upd7810_device::MOV_w_L, 4,17,17,L0|L1}, + + /* 0x80 - 0x9F */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::ANAX_B, 2,11,11,L0|L1}, + {&upd7810_device::ANAX_D, 2,11,11,L0|L1}, {&upd7810_device::ANAX_H, 2,11,11,L0|L1}, + {&upd7810_device::ANAX_Dp, 2,11,11,L0|L1}, {&upd7810_device::ANAX_Hp, 2,11,11,L0|L1}, + {&upd7810_device::ANAX_Dm, 2,11,11,L0|L1}, {&upd7810_device::ANAX_Hm, 2,11,11,L0|L1}, + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::XRAX_B, 2,11,11,L0|L1}, + {&upd7810_device::XRAX_D, 2,11,11,L0|L1}, {&upd7810_device::XRAX_H, 2,11,11,L0|L1}, + {&upd7810_device::XRAX_Dp, 2,11,11,L0|L1}, {&upd7810_device::XRAX_Hp, 2,11,11,L0|L1}, + {&upd7810_device::XRAX_Dm, 2,11,11,L0|L1}, {&upd7810_device::XRAX_Hm, 2,11,11,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::ORAX_B, 2,11,11,L0|L1}, + {&upd7810_device::ORAX_D, 2,11,11,L0|L1}, {&upd7810_device::ORAX_H, 2,11,11,L0|L1}, + {&upd7810_device::ORAX_Dp, 2,11,11,L0|L1}, {&upd7810_device::ORAX_Hp, 2,11,11,L0|L1}, + {&upd7810_device::ORAX_Dm, 2,11,11,L0|L1}, {&upd7810_device::ORAX_Hm, 2,11,11,L0|L1}, + + /* 0xA0 - 0xBF */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::ADDNCX_B, 2,11,11,L0|L1}, + {&upd7810_device::ADDNCX_D, 2,11,11,L0|L1}, {&upd7810_device::ADDNCX_H, 2,11,11,L0|L1}, + {&upd7810_device::ADDNCX_Dp, 2,11,11,L0|L1}, {&upd7810_device::ADDNCX_Hp, 2,11,11,L0|L1}, + {&upd7810_device::ADDNCX_Dm, 2,11,11,L0|L1}, {&upd7810_device::ADDNCX_Hm, 2,11,11,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::GTAX_B, 2,11,11,L0|L1}, + {&upd7810_device::GTAX_D, 2,11,11,L0|L1}, {&upd7810_device::GTAX_H, 2,11,11,L0|L1}, + {&upd7810_device::GTAX_Dp, 2,11,11,L0|L1}, {&upd7810_device::GTAX_Hp, 2,11,11,L0|L1}, + {&upd7810_device::GTAX_Dm, 2,11,11,L0|L1}, {&upd7810_device::GTAX_Hm, 2,11,11,L0|L1}, + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::SUBNBX_B, 2,11,11,L0|L1}, + {&upd7810_device::SUBNBX_D, 2,11,11,L0|L1}, {&upd7810_device::SUBNBX_H, 2,11,11,L0|L1}, + {&upd7810_device::SUBNBX_Dp, 2,11,11,L0|L1}, {&upd7810_device::SUBNBX_Hp, 2,11,11,L0|L1}, + {&upd7810_device::SUBNBX_Dm, 2,11,11,L0|L1}, {&upd7810_device::SUBNBX_Hm, 2,11,11,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::LTAX_B, 2,11,11,L0|L1}, + {&upd7810_device::LTAX_D, 2,11,11,L0|L1}, {&upd7810_device::LTAX_H, 2,11,11,L0|L1}, + {&upd7810_device::LTAX_Dp, 2,11,11,L0|L1}, {&upd7810_device::LTAX_Hp, 2,11,11,L0|L1}, + {&upd7810_device::LTAX_Dm, 2,11,11,L0|L1}, {&upd7810_device::LTAX_Hm, 2,11,11,L0|L1}, + + /* 0xC0 - 0xDF */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::ADDX_B, 2,11,11,L0|L1}, + {&upd7810_device::ADDX_D, 2,11,11,L0|L1}, {&upd7810_device::ADDX_H, 2,11,11,L0|L1}, + {&upd7810_device::ADDX_Dp, 2,11,11,L0|L1}, {&upd7810_device::ADDX_Hp, 2,11,11,L0|L1}, + {&upd7810_device::ADDX_Dm, 2,11,11,L0|L1}, {&upd7810_device::ADDX_Hm, 2,11,11,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::ONAX_B, 2,11,11,L0|L1}, + {&upd7810_device::ONAX_D, 2,11,11,L0|L1}, {&upd7810_device::ONAX_H, 2,11,11,L0|L1}, + {&upd7810_device::ONAX_Dp, 2,11,11,L0|L1}, {&upd7810_device::ONAX_Hp, 2,11,11,L0|L1}, + {&upd7810_device::ONAX_Dm, 2,11,11,L0|L1}, {&upd7810_device::ONAX_Hm, 2,11,11,L0|L1}, + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::ADCX_B, 2,11,11,L0|L1}, + {&upd7810_device::ADCX_D, 2,11,11,L0|L1}, {&upd7810_device::ADCX_H, 2,11,11,L0|L1}, + {&upd7810_device::ADCX_Dp, 2,11,11,L0|L1}, {&upd7810_device::ADCX_Hp, 2,11,11,L0|L1}, + {&upd7810_device::ADCX_Dm, 2,11,11,L0|L1}, {&upd7810_device::ADCX_Hm, 2,11,11,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::OFFAX_B, 2,11,11,L0|L1}, + {&upd7810_device::OFFAX_D, 2,11,11,L0|L1}, {&upd7810_device::OFFAX_H, 2,11,11,L0|L1}, + {&upd7810_device::OFFAX_Dp, 2,11,11,L0|L1}, {&upd7810_device::OFFAX_Hp, 2,11,11,L0|L1}, + {&upd7810_device::OFFAX_Dm, 2,11,11,L0|L1}, {&upd7810_device::OFFAX_Hm, 2,11,11,L0|L1}, + + /* 0xE0 - 0xFF */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::SUBX_B, 2,11,11,L0|L1}, + {&upd7810_device::SUBX_D, 2,11,11,L0|L1}, {&upd7810_device::SUBX_H, 2,11,11,L0|L1}, + {&upd7810_device::SUBX_Dp, 2,11,11,L0|L1}, {&upd7810_device::SUBX_Hp, 2,11,11,L0|L1}, + {&upd7810_device::SUBX_Dm, 2,11,11,L0|L1}, {&upd7810_device::SUBX_Hm, 2,11,11,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::NEAX_B, 2,11,11,L0|L1}, + {&upd7810_device::NEAX_D, 2,11,11,L0|L1}, {&upd7810_device::NEAX_H, 2,11,11,L0|L1}, + {&upd7810_device::NEAX_Dp, 2,11,11,L0|L1}, {&upd7810_device::NEAX_Hp, 2,11,11,L0|L1}, + {&upd7810_device::NEAX_Dm, 2,11,11,L0|L1}, {&upd7810_device::NEAX_Hm, 2,11,11,L0|L1}, + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::SBBX_B, 2,11,11,L0|L1}, + {&upd7810_device::SBBX_D, 2,11,11,L0|L1}, {&upd7810_device::SBBX_H, 2,11,11,L0|L1}, + {&upd7810_device::SBBX_Dp, 2,11,11,L0|L1}, {&upd7810_device::SBBX_Hp, 2,11,11,L0|L1}, + {&upd7810_device::SBBX_Dm, 2,11,11,L0|L1}, {&upd7810_device::SBBX_Hm, 2,11,11,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::EQAX_B, 2,11,11,L0|L1}, + {&upd7810_device::EQAX_D, 2,11,11,L0|L1}, {&upd7810_device::EQAX_H, 2,11,11,L0|L1}, + {&upd7810_device::EQAX_Dp, 2,11,11,L0|L1}, {&upd7810_device::EQAX_Hp, 2,11,11,L0|L1}, + {&upd7810_device::EQAX_Dm, 2,11,11,L0|L1}, {&upd7810_device::EQAX_Hm, 2,11,11,L0|L1} +}; + +/* prefix 74 */ +const struct upd7810_device::opcode_s upd7810_device::s_op74_7801[256] = +{ + /* 0x00 - 0x1F */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + /* 0x20 - 0x3F */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + /* 0x40 - 0x5F */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + /* 0x60 - 0x7F */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + /* 0x80 - 0x9F */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::ANAW_wa, 3,14,14,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + {&upd7810_device::XRAW_wa, 3,14,14,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::ORAW_wa, 3,14,14,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + /* 0xA0 - 0xBF */ + {&upd7810_device::ADDNCW_wa, 3,14,14,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::GTAW_wa, 3,14,14,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + {&upd7810_device::SUBNBW_wa, 3,14,14,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::LTAW_wa, 3,14,14,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + /* 0xC0 - 0xDF */ + {&upd7810_device::ADDW_wa, 3,14,14,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::ONAW_wa, 3,14,14,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + {&upd7810_device::ADCW_wa, 3,14,14,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::OFFAW_wa, 3,14,14,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + /* 0xE0 - 0xFF */ + {&upd7810_device::SUBW_wa, 3,14,14,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::NEAW_wa, 3,14,14,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + {&upd7810_device::SBBW_wa, 3,14,14,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::EQAW_wa, 3,14,14,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1} +}; + +const struct upd7810_device::opcode_s upd7810_device::s_opXX_7801[256] = +{ + /* 0x00 - 0x1F */ + {&upd7810_device::NOP, 1, 4, 4,L0|L1}, {&upd7810_device::HALT, 1, 6, 6,L0|L1}, + {&upd7810_device::INX_SP, 1, 7, 7,L0|L1}, {&upd7810_device::DCX_SP, 1, 7, 7,L0|L1}, + {&upd7810_device::LXI_S_w, 3,10,10,L0|L1}, {&upd7810_device::ANIW_wa_xx, 3,16,16,L0|L1}, + {&upd7810_device::illegal, 1, 4, 4,L0|L1}, {&upd7810_device::ANI_A_xx, 2, 7, 7,L0|L1}, + {&upd7810_device::RET, 1,11,11,L0|L1}, {&upd7810_device::SIO, 1, 4, 4,L0|L1}, + {&upd7810_device::MOV_A_B, 1, 4, 4,L0|L1}, {&upd7810_device::MOV_A_C, 1, 4, 4,L0|L1}, + {&upd7810_device::MOV_A_D, 1, 4, 4,L0|L1}, {&upd7810_device::MOV_A_E, 1, 4, 4,L0|L1}, + {&upd7810_device::MOV_A_H, 1, 4, 4,L0|L1}, {&upd7810_device::MOV_A_L, 1, 4, 4,L0|L1}, + + {&upd7810_device::EXA, 1, 4, 4,L0|L1}, {&upd7810_device::EXX, 1, 4, 4,L0|L1}, + {&upd7810_device::INX_BC, 1, 7, 7,L0|L1}, {&upd7810_device::DCX_BC, 1, 7, 7,L0|L1}, + {&upd7810_device::LXI_B_w, 3,10,10,L0|L1}, {&upd7810_device::ORIW_wa_xx, 3,16,16,L0|L1}, + {&upd7810_device::XRI_A_xx, 2, 7, 7,L0|L1}, {&upd7810_device::ORI_A_xx, 2, 7, 7,L0|L1}, + {&upd7810_device::RETS, 1,11,11,L0|L1}, {&upd7810_device::STM_7801, 1, 4, 4,L0|L1}, + {&upd7810_device::MOV_B_A, 1, 4, 4,L0|L1}, {&upd7810_device::MOV_C_A, 1, 4, 4,L0|L1}, + {&upd7810_device::MOV_D_A, 1, 4, 4,L0|L1}, {&upd7810_device::MOV_E_A, 1, 4, 4,L0|L1}, + {&upd7810_device::MOV_H_A, 1, 4, 4,L0|L1}, {&upd7810_device::MOV_L_A, 1, 4, 4,L0|L1}, + + /* 0x20 - 0x3F */ + {&upd7810_device::INRW_wa_7801, 2,13,13,L0|L1}, {&upd7810_device::TABLE, 1,19,19,L0|L1}, + {&upd7810_device::INX_DE, 1, 7, 7,L0|L1}, {&upd7810_device::DCX_DE, 1, 7, 7,L0|L1}, + {&upd7810_device::LXI_D_w, 3,10,10,L0|L1}, {&upd7810_device::GTIW_wa_xx, 3,13,13,L0|L1}, + {&upd7810_device::ADINC_A_xx, 2, 7, 7,L0|L1}, {&upd7810_device::GTI_A_xx, 2, 7, 7,L0|L1}, + {&upd7810_device::LDAW_wa, 2,10,10,L0|L1}, {&upd7810_device::LDAX_B, 1, 7, 7,L0|L1}, + {&upd7810_device::LDAX_D, 1, 7, 7,L0|L1}, {&upd7810_device::LDAX_H, 1, 7, 7,L0|L1}, + {&upd7810_device::LDAX_Dp, 1, 7, 7,L0|L1}, {&upd7810_device::LDAX_Hp, 1, 7, 7,L0|L1}, + {&upd7810_device::LDAX_Dm, 1, 7, 7,L0|L1}, {&upd7810_device::LDAX_Hm, 1, 7, 7,L0|L1}, + + {&upd7810_device::DCRW_wa_7801, 2,13,13,L0|L1}, {&upd7810_device::BLOCK, 1,13,13,L0|L1}, + {&upd7810_device::INX_HL, 1, 7, 7,L0|L1}, {&upd7810_device::DCX_HL, 1, 7, 7,L0|L1}, + {&upd7810_device::LXI_H_w, 3,10,10, L1}, {&upd7810_device::LTIW_wa_xx, 3,13,13,L0|L1}, + {&upd7810_device::SUINB_A_xx, 2, 7, 7,L0|L1}, {&upd7810_device::LTI_A_xx, 2, 7, 7,L0|L1}, + {&upd7810_device::STAW_wa, 2,10,10,L0|L1}, {&upd7810_device::STAX_B, 1, 7, 7,L0|L1}, + {&upd7810_device::STAX_D, 1, 7, 7,L0|L1}, {&upd7810_device::STAX_H, 1, 7, 7,L0|L1}, + {&upd7810_device::STAX_Dp, 1, 7, 7,L0|L1}, {&upd7810_device::STAX_Hp, 1, 7, 7,L0|L1}, + {&upd7810_device::STAX_Dm, 1, 7, 7,L0|L1}, {&upd7810_device::STAX_Hm, 1, 7, 7,L0|L1}, + + /* 0x40 - 0x5F */ + {&upd7810_device::illegal, 1, 4, 4,L0|L1}, {&upd7810_device::INR_A_7801, 1, 4, 4,L0|L1}, + {&upd7810_device::INR_B_7801, 1, 4, 4,L0|L1}, {&upd7810_device::INR_C_7801, 1, 4, 4,L0|L1}, + {&upd7810_device::CALL_w, 3,16,16,L0|L1}, {&upd7810_device::ONIW_wa_xx, 3,13,13,L0|L1}, + {&upd7810_device::ADI_A_xx, 2, 7, 7,L0|L1}, {&upd7810_device::ONI_A_xx, 2, 7, 7,L0|L1}, + {&upd7810_device::PRE_48, 1, 0, 0,L0|L1}, {&upd7810_device::MVIX_BC_xx, 2,10,10,L0|L1}, + {&upd7810_device::MVIX_DE_xx, 2,10,10,L0|L1}, {&upd7810_device::MVIX_HL_xx, 2,10,10,L0|L1}, + {&upd7810_device::PRE_4C, 1, 0, 0,L0|L1}, {&upd7810_device::PRE_4D, 1, 0, 0,L0|L1}, + {&upd7810_device::JRE, 2,17,17,L0|L1}, {&upd7810_device::JRE, 2,17,17,L0|L1}, + + {&upd7810_device::illegal, 1, 4, 4,L0|L1}, {&upd7810_device::DCR_A_7801, 1, 4, 4,L0|L1}, + {&upd7810_device::DCR_B_7801, 1, 4, 4,L0|L1}, {&upd7810_device::DCR_C_7801, 1, 4, 4,L0|L1}, + {&upd7810_device::JMP_w, 3,10,10,L0|L1}, {&upd7810_device::OFFIW_wa_xx, 3,13,13,L0|L1}, + {&upd7810_device::ACI_A_xx, 2, 7, 7,L0|L1}, {&upd7810_device::OFFI_A_xx, 2, 7, 7,L0|L1}, + {&upd7810_device::BIT_0_wa, 2,10,10,L0|L1}, {&upd7810_device::BIT_1_wa, 2,10,10,L0|L1}, + {&upd7810_device::BIT_2_wa, 2,10,10,L0|L1}, {&upd7810_device::BIT_3_wa, 2,10,10,L0|L1}, + {&upd7810_device::BIT_4_wa, 2,10,10,L0|L1}, {&upd7810_device::BIT_5_wa, 2,10,10,L0|L1}, + {&upd7810_device::BIT_6_wa, 2,10,10,L0|L1}, {&upd7810_device::BIT_7_wa, 2,10,10,L0|L1}, + + /* 0x60 - 0x7F */ + {&upd7810_device::PRE_60, 1, 0, 0,L0|L1}, {&upd7810_device::DAA, 1, 4, 4,L0|L1}, + {&upd7810_device::RETI, 1,15,15,L0|L1}, {&upd7810_device::CALB, 2,13,13,L0|L1}, + {&upd7810_device::PRE_64, 1, 0, 0,L0|L1}, {&upd7810_device::NEIW_wa_xx, 3,13,13,L0|L1}, + {&upd7810_device::SUI_A_xx, 2, 7, 7,L0|L1}, {&upd7810_device::NEI_A_xx, 2, 7, 7,L0|L1}, + {&upd7810_device::MVI_V_xx, 2, 7, 7,L0|L1}, {&upd7810_device::MVI_A_xx, 2, 7, 7,L0 }, + {&upd7810_device::MVI_B_xx, 2, 7, 7,L0|L1}, {&upd7810_device::MVI_C_xx, 2, 7, 7,L0|L1}, + {&upd7810_device::MVI_D_xx, 2, 7, 7,L0|L1}, {&upd7810_device::MVI_E_xx, 2, 7, 7,L0|L1}, + {&upd7810_device::MVI_H_xx, 2, 7, 7,L0|L1}, {&upd7810_device::MVI_L_xx, 2, 7, 7, L1}, + + {&upd7810_device::PRE_70, 1, 0, 0,L0|L1}, {&upd7810_device::MVIW_wa_xx, 3,13,13,L0|L1}, + {&upd7810_device::SOFTI, 1,19,19,L0|L1}, {&upd7810_device::JB, 1, 4, 4,L0|L1}, + {&upd7810_device::PRE_74, 1, 0, 0,L0|L1}, {&upd7810_device::EQIW_wa_xx, 3,13,13,L0|L1}, + {&upd7810_device::SBI_A_xx, 2, 7, 7,L0|L1}, {&upd7810_device::EQI_A_xx, 2, 7, 7,L0|L1}, + {&upd7810_device::CALF, 2,16,16,L0|L1}, {&upd7810_device::CALF, 2,16,16,L0|L1}, + {&upd7810_device::CALF, 2,16,16,L0|L1}, {&upd7810_device::CALF, 2,16,16,L0|L1}, + {&upd7810_device::CALF, 2,16,16,L0|L1}, {&upd7810_device::CALF, 2,16,16,L0|L1}, + {&upd7810_device::CALF, 2,16,16,L0|L1}, {&upd7810_device::CALF, 2,16,16,L0|L1}, + + /* 0x80 - 0x9F */ + {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, + {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, + {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, + {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, + {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, + {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, + {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, + {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, + + {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, + {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, + {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, + {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, + {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, + {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, + {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, + {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, + + /* 0xA0 - 0xBF */ + {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, + {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, + {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, + {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, + {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, + {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, + {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, + {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, + + {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, + {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, + {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, + {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, + {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, + {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, + {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, + {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, + + /* 0xC0 - 0xDF */ + {&upd7810_device::JR, 1,13,13,L0|L1}, {&upd7810_device::JR, 1,13,13,L0|L1}, + {&upd7810_device::JR, 1,13,13,L0|L1}, {&upd7810_device::JR, 1,13,13,L0|L1}, + {&upd7810_device::JR, 1,13,13,L0|L1}, {&upd7810_device::JR, 1,13,13,L0|L1}, + {&upd7810_device::JR, 1,13,13,L0|L1}, {&upd7810_device::JR, 1,13,13,L0|L1}, + {&upd7810_device::JR, 1,13,13,L0|L1}, {&upd7810_device::JR, 1,13,13,L0|L1}, + {&upd7810_device::JR, 1,13,13,L0|L1}, {&upd7810_device::JR, 1,13,13,L0|L1}, + {&upd7810_device::JR, 1,13,13,L0|L1}, {&upd7810_device::JR, 1,13,13,L0|L1}, + {&upd7810_device::JR, 1,13,13,L0|L1}, {&upd7810_device::JR, 1,13,13,L0|L1}, + + {&upd7810_device::JR, 1,13,13,L0|L1}, {&upd7810_device::JR, 1,13,13,L0|L1}, + {&upd7810_device::JR, 1,13,13,L0|L1}, {&upd7810_device::JR, 1,13,13,L0|L1}, + {&upd7810_device::JR, 1,13,13,L0|L1}, {&upd7810_device::JR, 1,13,13,L0|L1}, + {&upd7810_device::JR, 1,13,13,L0|L1}, {&upd7810_device::JR, 1,13,13,L0|L1}, + {&upd7810_device::JR, 1,13,13,L0|L1}, {&upd7810_device::JR, 1,13,13,L0|L1}, + {&upd7810_device::JR, 1,13,13,L0|L1}, {&upd7810_device::JR, 1,13,13,L0|L1}, + {&upd7810_device::JR, 1,13,13,L0|L1}, {&upd7810_device::JR, 1,13,13,L0|L1}, + {&upd7810_device::JR, 1,13,13,L0|L1}, {&upd7810_device::JR, 1,13,13,L0|L1}, + + /* 0xE0 - 0xFF */ + {&upd7810_device::JR, 1,13,13,L0|L1}, {&upd7810_device::JR, 1,13,13,L0|L1}, + {&upd7810_device::JR, 1,13,13,L0|L1}, {&upd7810_device::JR, 1,13,13,L0|L1}, + {&upd7810_device::JR, 1,13,13,L0|L1}, {&upd7810_device::JR, 1,13,13,L0|L1}, + {&upd7810_device::JR, 1,13,13,L0|L1}, {&upd7810_device::JR, 1,13,13,L0|L1}, + {&upd7810_device::JR, 1,13,13,L0|L1}, {&upd7810_device::JR, 1,13,13,L0|L1}, + {&upd7810_device::JR, 1,13,13,L0|L1}, {&upd7810_device::JR, 1,13,13,L0|L1}, + {&upd7810_device::JR, 1,13,13,L0|L1}, {&upd7810_device::JR, 1,13,13,L0|L1}, + {&upd7810_device::JR, 1,13,13,L0|L1}, {&upd7810_device::JR, 1,13,13,L0|L1}, + + {&upd7810_device::JR, 1,13,13,L0|L1}, {&upd7810_device::JR, 1,13,13,L0|L1}, + {&upd7810_device::JR, 1,13,13,L0|L1}, {&upd7810_device::JR, 1,13,13,L0|L1}, + {&upd7810_device::JR, 1,13,13,L0|L1}, {&upd7810_device::JR, 1,13,13,L0|L1}, + {&upd7810_device::JR, 1,13,13,L0|L1}, {&upd7810_device::JR, 1,13,13,L0|L1}, + {&upd7810_device::JR, 1,13,13,L0|L1}, {&upd7810_device::JR, 1,13,13,L0|L1}, + {&upd7810_device::JR, 1,13,13,L0|L1}, {&upd7810_device::JR, 1,13,13,L0|L1}, + {&upd7810_device::JR, 1,13,13,L0|L1}, {&upd7810_device::JR, 1,13,13,L0|L1}, + {&upd7810_device::JR, 1,13,13,L0|L1}, {&upd7810_device::JR, 1,13,13,L0|L1} +}; + +/*********************************************************************** + * + * uPD78C05(A) + * + **********************************************************************/ + +const struct upd7810_device::opcode_s upd7810_device::s_op48_78c05[256] = +{ + /* 0x00 - 0x1F */ + {&upd7810_device::SKIT_F0, 2, 8, 8,L0|L1}, {&upd7810_device::SKIT_FT0, 2, 8, 8,L0|L1}, + {&upd7810_device::SKIT_F1, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::SKIT_FST, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::SK_CY, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::SK_Z, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::PUSH_VA, 2,17,17,L0|L1}, {&upd7810_device::POP_VA, 2,14,14,L0|L1}, + + {&upd7810_device::SKNIT_F0, 2, 8, 8,L0|L1}, {&upd7810_device::SKNIT_FT0, 2, 8, 8,L0|L1}, + {&upd7810_device::SKNIT_F1, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::SKNIT_FST, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::SKN_CY, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::SKN_Z, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::PUSH_BC, 2,17,17,L0|L1}, {&upd7810_device::POP_BC, 2,14,14,L0|L1}, + + /* 0x20 - 0x3F */ + {&upd7810_device::EI, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::DI, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::CLC, 2, 8, 8,L0|L1}, {&upd7810_device::STC, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::PEX, 2,11,11,L0|L1}, + {&upd7810_device::PUSH_DE, 2,17,17,L0|L1}, {&upd7810_device::POP_DE, 2,14,14,L0|L1}, + + {&upd7810_device::RLL_A, 2, 8, 8,L0|L1}, {&upd7810_device::RLR_A, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::RLD, 2,17,17,L0|L1}, {&upd7810_device::RRD, 2,17,17,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::PER, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::PUSH_HL, 2,17,17,L0|L1}, {&upd7810_device::POP_HL, 2,14,14,L0|L1}, + + /* 0x40 - 0x5F */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + /* 0x60 - 0x7F */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + /* 0x80 - 0x9F */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + /* 0xA0 - 0xBF */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + /* 0xC0 - 0xDF */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + /* 0xE0 - 0xFF */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1} +}; + +const struct upd7810_device::opcode_s upd7810_device::s_op4C_78c05[256] = +{ + /* 0x00 - 0x1F */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + /* 0x20 - 0x3F */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + /* 0x40 - 0x5F */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + /* 0x60 - 0x7F */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + /* 0x80 - 0x9F */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + /* 0xA0 - 0xBF */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + /* 0xC0 - 0xDF */ + {&upd7810_device::MOV_A_PA, 2,10,10,L0|L1}, {&upd7810_device::MOV_A_PB, 2,10,10,L0|L1}, + {&upd7810_device::MOV_A_PC, 2,10,10,L0|L1}, {&upd7810_device::MOV_A_MKL, 2,10,10,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::MOV_A_S, 2,10,10,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + /* 0xE0 - 0xFF */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1} +}; + +/* prefix 4D */ +const struct upd7810_device::opcode_s upd7810_device::s_op4D_78c05[256] = +{ + /* 0x00 - 0x1F */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + /* 0x20 - 0x3F */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + /* 0x40 - 0x5F */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + /* 0x60 - 0x7F */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + /* 0x80 - 0x9F */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + /* 0xA0 - 0xBF */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + /* 0xC0 - 0xDF */ + {&upd7810_device::MOV_PA_A, 2,10,10,L0|L1}, {&upd7810_device::MOV_PB_A, 2,10,10,L0|L1}, + {&upd7810_device::MOV_PC_A, 2,10,10,L0|L1}, {&upd7810_device::MOV_MKL_A, 2,10,10,L0|L1}, + {&upd7810_device::MOV_MB_A, 2,10,10,L0|L1}, {&upd7810_device::MOV_MC_A, 2,10,10,L0|L1}, + {&upd7810_device::MOV_TM0_A, 2,10,10,L0|L1}, {&upd7810_device::MOV_TM1_A, 2,10,10,L0|L1}, + {&upd7810_device::MOV_S_A, 2,10,10,L0|L1}, {&upd7810_device::MOV_TMM_A, 2,10,10,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + /* 0xE0 - 0xFF */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1} +}; + +/* prefix 60 */ +const struct upd7810_device::opcode_s upd7810_device::s_op60_78c05[256] = +{ + /* 0x00 - 0x1F */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::ANA_A_A, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::XRA_A_A, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::ORA_A_A, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + /* 0x20 - 0x3F */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::ADDNC_A_A, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::GTA_A_A, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::SUBNB_A_A, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::LTA_A_A, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + /* 0x40 - 0x5F */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::ADD_A_A, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::ADC_A_A, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + /* 0x60 - 0x7F */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::SUB_A_A, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::NEA_A_A, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::SBB_A_A, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::EQA_A_A, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + /* 0x80 - 0x9F */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::ANA_A_A, 2, 8, 8,L0|L1}, + {&upd7810_device::ANA_A_B, 2, 8, 8,L0|L1}, {&upd7810_device::ANA_A_C, 2, 8, 8,L0|L1}, + {&upd7810_device::ANA_A_D, 2, 8, 8,L0|L1}, {&upd7810_device::ANA_A_E, 2, 8, 8,L0|L1}, + {&upd7810_device::ANA_A_H, 2, 8, 8,L0|L1}, {&upd7810_device::ANA_A_L, 2, 8, 8,L0|L1}, + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::XRA_A_A, 2, 8, 8,L0|L1}, + {&upd7810_device::XRA_A_B, 2, 8, 8,L0|L1}, {&upd7810_device::XRA_A_C, 2, 8, 8,L0|L1}, + {&upd7810_device::XRA_A_D, 2, 8, 8,L0|L1}, {&upd7810_device::XRA_A_E, 2, 8, 8,L0|L1}, + {&upd7810_device::XRA_A_H, 2, 8, 8,L0|L1}, {&upd7810_device::XRA_A_L, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::ORA_A_A, 2, 8, 8,L0|L1}, + {&upd7810_device::ORA_A_B, 2, 8, 8,L0|L1}, {&upd7810_device::ORA_A_C, 2, 8, 8,L0|L1}, + {&upd7810_device::ORA_A_D, 2, 8, 8,L0|L1}, {&upd7810_device::ORA_A_E, 2, 8, 8,L0|L1}, + {&upd7810_device::ORA_A_H, 2, 8, 8,L0|L1}, {&upd7810_device::ORA_A_L, 2, 8, 8,L0|L1}, + + /* 0xA0 - 0xBF */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::ADDNC_A_A, 2, 8, 8,L0|L1}, + {&upd7810_device::ADDNC_A_B, 2, 8, 8,L0|L1}, {&upd7810_device::ADDNC_A_C, 2, 8, 8,L0|L1}, + {&upd7810_device::ADDNC_A_D, 2, 8, 8,L0|L1}, {&upd7810_device::ADDNC_A_E, 2, 8, 8,L0|L1}, + {&upd7810_device::ADDNC_A_H, 2, 8, 8,L0|L1}, {&upd7810_device::ADDNC_A_L, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::GTA_A_A, 2, 8, 8,L0|L1}, + {&upd7810_device::GTA_A_B, 2, 8, 8,L0|L1}, {&upd7810_device::GTA_A_C, 2, 8, 8,L0|L1}, + {&upd7810_device::GTA_A_D, 2, 8, 8,L0|L1}, {&upd7810_device::GTA_A_E, 2, 8, 8,L0|L1}, + {&upd7810_device::GTA_A_H, 2, 8, 8,L0|L1}, {&upd7810_device::GTA_A_L, 2, 8, 8,L0|L1}, + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::SUBNB_A_A, 2, 8, 8,L0|L1}, + {&upd7810_device::SUBNB_A_B, 2, 8, 8,L0|L1}, {&upd7810_device::SUBNB_A_C, 2, 8, 8,L0|L1}, + {&upd7810_device::SUBNB_A_D, 2, 8, 8,L0|L1}, {&upd7810_device::SUBNB_A_E, 2, 8, 8,L0|L1}, + {&upd7810_device::SUBNB_A_H, 2, 8, 8,L0|L1}, {&upd7810_device::SUBNB_A_L, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::LTA_A_A, 2, 8, 8,L0|L1}, + {&upd7810_device::LTA_A_B, 2, 8, 8,L0|L1}, {&upd7810_device::LTA_A_C, 2, 8, 8,L0|L1}, + {&upd7810_device::LTA_A_D, 2, 8, 8,L0|L1}, {&upd7810_device::LTA_A_E, 2, 8, 8,L0|L1}, + {&upd7810_device::LTA_A_H, 2, 8, 8,L0|L1}, {&upd7810_device::LTA_A_L, 2, 8, 8,L0|L1}, + + /* 0xC0 - 0xDF */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::ADD_A_A, 2, 8, 8,L0|L1}, + {&upd7810_device::ADD_A_B, 2, 8, 8,L0|L1}, {&upd7810_device::ADD_A_C, 2, 8, 8,L0|L1}, + {&upd7810_device::ADD_A_D, 2, 8, 8,L0|L1}, {&upd7810_device::ADD_A_E, 2, 8, 8,L0|L1}, + {&upd7810_device::ADD_A_H, 2, 8, 8,L0|L1}, {&upd7810_device::ADD_A_L, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::ONA_A_A, 2, 8, 8,L0|L1}, + {&upd7810_device::ONA_A_B, 2, 8, 8,L0|L1}, {&upd7810_device::ONA_A_C, 2, 8, 8,L0|L1}, + {&upd7810_device::ONA_A_D, 2, 8, 8,L0|L1}, {&upd7810_device::ONA_A_E, 2, 8, 8,L0|L1}, + {&upd7810_device::ONA_A_H, 2, 8, 8,L0|L1}, {&upd7810_device::ONA_A_L, 2, 8, 8,L0|L1}, + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::ADC_A_A, 2, 8, 8,L0|L1}, + {&upd7810_device::ADC_A_B, 2, 8, 8,L0|L1}, {&upd7810_device::ADC_A_C, 2, 8, 8,L0|L1}, + {&upd7810_device::ADC_A_D, 2, 8, 8,L0|L1}, {&upd7810_device::ADC_A_E, 2, 8, 8,L0|L1}, + {&upd7810_device::ADC_A_H, 2, 8, 8,L0|L1}, {&upd7810_device::ADC_A_L, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::OFFA_A_A, 2, 8, 8,L0|L1}, + {&upd7810_device::OFFA_A_B, 2, 8, 8,L0|L1}, {&upd7810_device::OFFA_A_C, 2, 8, 8,L0|L1}, + {&upd7810_device::OFFA_A_D, 2, 8, 8,L0|L1}, {&upd7810_device::OFFA_A_E, 2, 8, 8,L0|L1}, + {&upd7810_device::OFFA_A_H, 2, 8, 8,L0|L1}, {&upd7810_device::OFFA_A_L, 2, 8, 8,L0|L1}, + + /* 0xE0 - 0xFF */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::SUB_A_A, 2, 8, 8,L0|L1}, + {&upd7810_device::SUB_A_B, 2, 8, 8,L0|L1}, {&upd7810_device::SUB_A_C, 2, 8, 8,L0|L1}, + {&upd7810_device::SUB_A_D, 2, 8, 8,L0|L1}, {&upd7810_device::SUB_A_E, 2, 8, 8,L0|L1}, + {&upd7810_device::SUB_A_H, 2, 8, 8,L0|L1}, {&upd7810_device::SUB_A_L, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::NEA_A_A, 2, 8, 8,L0|L1}, + {&upd7810_device::NEA_A_B, 2, 8, 8,L0|L1}, {&upd7810_device::NEA_A_C, 2, 8, 8,L0|L1}, + {&upd7810_device::NEA_A_D, 2, 8, 8,L0|L1}, {&upd7810_device::NEA_A_E, 2, 8, 8,L0|L1}, + {&upd7810_device::NEA_A_H, 2, 8, 8,L0|L1}, {&upd7810_device::NEA_A_L, 2, 8, 8,L0|L1}, + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::SBB_A_A, 2, 8, 8,L0|L1}, + {&upd7810_device::SBB_A_B, 2, 8, 8,L0|L1}, {&upd7810_device::SBB_A_C, 2, 8, 8,L0|L1}, + {&upd7810_device::SBB_A_D, 2, 8, 8,L0|L1}, {&upd7810_device::SBB_A_E, 2, 8, 8,L0|L1}, + {&upd7810_device::SBB_A_H, 2, 8, 8,L0|L1}, {&upd7810_device::SBB_A_L, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::EQA_A_A, 2, 8, 8,L0|L1}, + {&upd7810_device::EQA_A_B, 2, 8, 8,L0|L1}, {&upd7810_device::EQA_A_C, 2, 8, 8,L0|L1}, + {&upd7810_device::EQA_A_D, 2, 8, 8,L0|L1}, {&upd7810_device::EQA_A_E, 2, 8, 8,L0|L1}, + {&upd7810_device::EQA_A_H, 2, 8, 8,L0|L1}, {&upd7810_device::EQA_A_L, 2, 8, 8,L0|L1} +}; + +/* prefix 64 */ +const struct upd7810_device::opcode_s upd7810_device::s_op64_78c05[256] = +{ + /* 0x00 - 0x1F */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::ANI_A_xx, 3,11,11,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::XRI_A_xx, 3,11,11,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::ORI_A_xx, 3,11,11,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + /* 0x20 - 0x3F */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::ADINC_A_xx, 3,11,11,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::GTI_A_xx, 3,11,11,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::SUINB_A_xx, 3,11,11,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 3, 8, 8,L0|L1}, {&upd7810_device::LTI_A_xx, 3,11,11,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + /* 0x40 - 0x5F */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::ADI_A_xx, 3,11,11,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::ONI_A_xx, 3,11,11,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + {&upd7810_device::illegal2, 3, 8, 8,L0|L1}, {&upd7810_device::ACI_A_xx, 3,11,11,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 3, 8, 8,L0|L1}, {&upd7810_device::OFFI_A_xx, 3,11,11,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + /* 0x60 - 0x7F */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::SUI_A_xx, 3,11,11,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::NEI_A_xx, 3,11,11,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::SBI_A_xx, 3,11,11,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::EQI_A_xx, 3,11,11,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + /* 0x80 - 0x9F */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::ANI_PA_xx, 3,17,17,L0|L1}, {&upd7810_device::ANI_PB_xx, 3,17,17,L0|L1}, + {&upd7810_device::ANI_PC_xx, 3,17,17,L0|L1}, {&upd7810_device::ANI_MKL_xx, 3,17,17,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + {&upd7810_device::XRI_PA_xx, 3,17,17,L0|L1}, {&upd7810_device::XRI_PB_xx, 3,17,17,L0|L1}, + {&upd7810_device::XRI_PC_xx, 3,17,17,L0|L1}, {&upd7810_device::XRI_MKL_xx, 3,17,17,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::ORI_PA_xx, 3,17,17,L0|L1}, {&upd7810_device::ORI_PB_xx, 3,17,17,L0|L1}, + {&upd7810_device::ORI_PC_xx, 3,17,17,L0|L1}, {&upd7810_device::ORI_MKL_xx, 3,17,17,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + /* 0xA0 - 0xBF */ + {&upd7810_device::ADINC_PA_xx, 3,17,17,L0|L1}, {&upd7810_device::ADINC_PB_xx, 3,17,17,L0|L1}, + {&upd7810_device::ADINC_PC_xx, 3,17,17,L0|L1}, {&upd7810_device::ADINC_MKL_xx, 3,17,17,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::GTI_PA_xx, 3,14,14,L0|L1}, {&upd7810_device::GTI_PB_xx, 3,14,14,L0|L1}, + {&upd7810_device::GTI_PC_xx, 3,14,14,L0|L1}, {&upd7810_device::GTI_MKL_xx, 3,14,14,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + {&upd7810_device::SUINB_PA_xx, 3,17,17,L0|L1}, {&upd7810_device::SUINB_PB_xx, 3,17,17,L0|L1}, + {&upd7810_device::SUINB_PC_xx, 3,17,17,L0|L1}, {&upd7810_device::SUINB_MKL_xx, 3,17,17,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::LTI_PA_xx, 3,14,14,L0|L1}, {&upd7810_device::LTI_PB_xx, 3,14,14,L0|L1}, + {&upd7810_device::LTI_PC_xx, 3,14,14,L0|L1}, {&upd7810_device::LTI_MKL_xx, 3,14,14,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + /* 0xC0 - 0xDF */ + {&upd7810_device::ADI_PA_xx, 3,17,17,L0|L1}, {&upd7810_device::ADI_PB_xx, 3,17,17,L0|L1}, + {&upd7810_device::ADI_PC_xx, 3,17,17,L0|L1}, {&upd7810_device::ADI_MKL_xx, 3,17,17,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::ONI_PA_xx, 3,14,14,L0|L1}, {&upd7810_device::ONI_PB_xx, 3,14,14,L0|L1}, + {&upd7810_device::ONI_PC_xx, 3,14,14,L0|L1}, {&upd7810_device::ONI_MKL_xx, 3,14,14,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + {&upd7810_device::ACI_PA_xx, 3,17,17,L0|L1}, {&upd7810_device::ACI_PB_xx, 3,17,17,L0|L1}, + {&upd7810_device::ACI_PC_xx, 3,17,17,L0|L1}, {&upd7810_device::ACI_MKL_xx, 3,17,17,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::OFFI_PA_xx, 3,14,14,L0|L1}, {&upd7810_device::OFFI_PB_xx, 3,14,14,L0|L1}, + {&upd7810_device::OFFI_PC_xx, 3,14,14,L0|L1}, {&upd7810_device::OFFI_MKL_xx, 3,14,14,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + /* 0xE0 - 0xFF */ + {&upd7810_device::SUI_PA_xx, 3,17,17,L0|L1}, {&upd7810_device::SUI_PB_xx, 3,17,17,L0|L1}, + {&upd7810_device::SUI_PC_xx, 3,17,17,L0|L1}, {&upd7810_device::SUI_MKL_xx, 3,17,17,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::NEI_PA_xx, 3,14,14,L0|L1}, {&upd7810_device::NEI_PB_xx, 3,14,14,L0|L1}, + {&upd7810_device::NEI_PC_xx, 3,14,14,L0|L1}, {&upd7810_device::NEI_MKL_xx, 3,14,14,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + {&upd7810_device::SBI_PA_xx, 3,17,17,L0|L1}, {&upd7810_device::SBI_PB_xx, 3,17,17,L0|L1}, + {&upd7810_device::SBI_PC_xx, 3,17,17,L0|L1}, {&upd7810_device::SBI_MKL_xx, 3,17,17,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::EQI_PA_xx, 3,14,14,L0|L1}, {&upd7810_device::EQI_PB_xx, 3,14,14,L0|L1}, + {&upd7810_device::EQI_PC_xx, 3,14,14,L0|L1}, {&upd7810_device::EQI_MKL_xx, 3,14,14,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1} +}; + +/* prefix 70 */ +const struct upd7810_device::opcode_s upd7810_device::s_op70_78c05[256] = +{ + /* 0x00 - 0x1F */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::SSPD_w, 4,20,20,L0|L1}, {&upd7810_device::LSPD_w, 4,20,20,L0|L1}, + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::SBCD_w, 4,20,20,L0|L1}, {&upd7810_device::LBCD_w, 4,20,20,L0|L1}, + + /* 0x20 - 0x3F */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::SDED_w, 4,20,20,L0|L1}, {&upd7810_device::LDED_w, 4,20,20,L0|L1}, + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::SHLD_w, 4,20,20,L0|L1}, {&upd7810_device::LHLD_w, 4,20,20,L0|L1}, + + /* 0x40 - 0x5F */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + /* 0x60 - 0x7F */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::MOV_A_w, 4,17,17,L0|L1}, + {&upd7810_device::MOV_B_w, 4,17,17,L0|L1}, {&upd7810_device::MOV_C_w, 4,17,17,L0|L1}, + {&upd7810_device::MOV_D_w, 4,17,17,L0|L1}, {&upd7810_device::MOV_E_w, 4,17,17,L0|L1}, + {&upd7810_device::MOV_H_w, 4,17,17,L0|L1}, {&upd7810_device::MOV_L_w, 4,17,17,L0|L1}, + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::MOV_w_A, 4,17,17,L0|L1}, + {&upd7810_device::MOV_w_B, 4,17,17,L0|L1}, {&upd7810_device::MOV_w_C, 4,17,17,L0|L1}, + {&upd7810_device::MOV_w_D, 4,17,17,L0|L1}, {&upd7810_device::MOV_w_E, 4,17,17,L0|L1}, + {&upd7810_device::MOV_w_H, 4,17,17,L0|L1}, {&upd7810_device::MOV_w_L, 4,17,17,L0|L1}, + + /* 0x80 - 0x9F */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::ANAX_B, 2,11,11,L0|L1}, + {&upd7810_device::ANAX_D, 2,11,11,L0|L1}, {&upd7810_device::ANAX_H, 2,11,11,L0|L1}, + {&upd7810_device::ANAX_Dp, 2,11,11,L0|L1}, {&upd7810_device::ANAX_Hp, 2,11,11,L0|L1}, + {&upd7810_device::ANAX_Dm, 2,11,11,L0|L1}, {&upd7810_device::ANAX_Hm, 2,11,11,L0|L1}, + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::XRAX_B, 2,11,11,L0|L1}, + {&upd7810_device::XRAX_D, 2,11,11,L0|L1}, {&upd7810_device::XRAX_H, 2,11,11,L0|L1}, + {&upd7810_device::XRAX_Dp, 2,11,11,L0|L1}, {&upd7810_device::XRAX_Hp, 2,11,11,L0|L1}, + {&upd7810_device::XRAX_Dm, 2,11,11,L0|L1}, {&upd7810_device::XRAX_Hm, 2,11,11,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::ORAX_B, 2,11,11,L0|L1}, + {&upd7810_device::ORAX_D, 2,11,11,L0|L1}, {&upd7810_device::ORAX_H, 2,11,11,L0|L1}, + {&upd7810_device::ORAX_Dp, 2,11,11,L0|L1}, {&upd7810_device::ORAX_Hp, 2,11,11,L0|L1}, + {&upd7810_device::ORAX_Dm, 2,11,11,L0|L1}, {&upd7810_device::ORAX_Hm, 2,11,11,L0|L1}, + + /* 0xA0 - 0xBF */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::ADDNCX_B, 2,11,11,L0|L1}, + {&upd7810_device::ADDNCX_D, 2,11,11,L0|L1}, {&upd7810_device::ADDNCX_H, 2,11,11,L0|L1}, + {&upd7810_device::ADDNCX_Dp, 2,11,11,L0|L1}, {&upd7810_device::ADDNCX_Hp, 2,11,11,L0|L1}, + {&upd7810_device::ADDNCX_Dm, 2,11,11,L0|L1}, {&upd7810_device::ADDNCX_Hm, 2,11,11,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::GTAX_B, 2,11,11,L0|L1}, + {&upd7810_device::GTAX_D, 2,11,11,L0|L1}, {&upd7810_device::GTAX_H, 2,11,11,L0|L1}, + {&upd7810_device::GTAX_Dp, 2,11,11,L0|L1}, {&upd7810_device::GTAX_Hp, 2,11,11,L0|L1}, + {&upd7810_device::GTAX_Dm, 2,11,11,L0|L1}, {&upd7810_device::GTAX_Hm, 2,11,11,L0|L1}, + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::SUBNBX_B, 2,11,11,L0|L1}, + {&upd7810_device::SUBNBX_D, 2,11,11,L0|L1}, {&upd7810_device::SUBNBX_H, 2,11,11,L0|L1}, + {&upd7810_device::SUBNBX_Dp, 2,11,11,L0|L1}, {&upd7810_device::SUBNBX_Hp, 2,11,11,L0|L1}, + {&upd7810_device::SUBNBX_Dm, 2,11,11,L0|L1}, {&upd7810_device::SUBNBX_Hm, 2,11,11,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::LTAX_B, 2,11,11,L0|L1}, + {&upd7810_device::LTAX_D, 2,11,11,L0|L1}, {&upd7810_device::LTAX_H, 2,11,11,L0|L1}, + {&upd7810_device::LTAX_Dp, 2,11,11,L0|L1}, {&upd7810_device::LTAX_Hp, 2,11,11,L0|L1}, + {&upd7810_device::LTAX_Dm, 2,11,11,L0|L1}, {&upd7810_device::LTAX_Hm, 2,11,11,L0|L1}, + + /* 0xC0 - 0xDF */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::ADDX_B, 2,11,11,L0|L1}, + {&upd7810_device::ADDX_D, 2,11,11,L0|L1}, {&upd7810_device::ADDX_H, 2,11,11,L0|L1}, + {&upd7810_device::ADDX_Dp, 2,11,11,L0|L1}, {&upd7810_device::ADDX_Hp, 2,11,11,L0|L1}, + {&upd7810_device::ADDX_Dm, 2,11,11,L0|L1}, {&upd7810_device::ADDX_Hm, 2,11,11,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::ONAX_B, 2,11,11,L0|L1}, + {&upd7810_device::ONAX_D, 2,11,11,L0|L1}, {&upd7810_device::ONAX_H, 2,11,11,L0|L1}, + {&upd7810_device::ONAX_Dp, 2,11,11,L0|L1}, {&upd7810_device::ONAX_Hp, 2,11,11,L0|L1}, + {&upd7810_device::ONAX_Dm, 2,11,11,L0|L1}, {&upd7810_device::ONAX_Hm, 2,11,11,L0|L1}, + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::ADCX_B, 2,11,11,L0|L1}, + {&upd7810_device::ADCX_D, 2,11,11,L0|L1}, {&upd7810_device::ADCX_H, 2,11,11,L0|L1}, + {&upd7810_device::ADCX_Dp, 2,11,11,L0|L1}, {&upd7810_device::ADCX_Hp, 2,11,11,L0|L1}, + {&upd7810_device::ADCX_Dm, 2,11,11,L0|L1}, {&upd7810_device::ADCX_Hm, 2,11,11,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::OFFAX_B, 2,11,11,L0|L1}, + {&upd7810_device::OFFAX_D, 2,11,11,L0|L1}, {&upd7810_device::OFFAX_H, 2,11,11,L0|L1}, + {&upd7810_device::OFFAX_Dp, 2,11,11,L0|L1}, {&upd7810_device::OFFAX_Hp, 2,11,11,L0|L1}, + {&upd7810_device::OFFAX_Dm, 2,11,11,L0|L1}, {&upd7810_device::OFFAX_Hm, 2,11,11,L0|L1}, + + /* 0xE0 - 0xFF */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::SUBX_B, 2,11,11,L0|L1}, + {&upd7810_device::SUBX_D, 2,11,11,L0|L1}, {&upd7810_device::SUBX_H, 2,11,11,L0|L1}, + {&upd7810_device::SUBX_Dp, 2,11,11,L0|L1}, {&upd7810_device::SUBX_Hp, 2,11,11,L0|L1}, + {&upd7810_device::SUBX_Dm, 2,11,11,L0|L1}, {&upd7810_device::SUBX_Hm, 2,11,11,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::NEAX_B, 2,11,11,L0|L1}, + {&upd7810_device::NEAX_D, 2,11,11,L0|L1}, {&upd7810_device::NEAX_H, 2,11,11,L0|L1}, + {&upd7810_device::NEAX_Dp, 2,11,11,L0|L1}, {&upd7810_device::NEAX_Hp, 2,11,11,L0|L1}, + {&upd7810_device::NEAX_Dm, 2,11,11,L0|L1}, {&upd7810_device::NEAX_Hm, 2,11,11,L0|L1}, + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::SBBX_B, 2,11,11,L0|L1}, + {&upd7810_device::SBBX_D, 2,11,11,L0|L1}, {&upd7810_device::SBBX_H, 2,11,11,L0|L1}, + {&upd7810_device::SBBX_Dp, 2,11,11,L0|L1}, {&upd7810_device::SBBX_Hp, 2,11,11,L0|L1}, + {&upd7810_device::SBBX_Dm, 2,11,11,L0|L1}, {&upd7810_device::SBBX_Hm, 2,11,11,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::EQAX_B, 2,11,11,L0|L1}, + {&upd7810_device::EQAX_D, 2,11,11,L0|L1}, {&upd7810_device::EQAX_H, 2,11,11,L0|L1}, + {&upd7810_device::EQAX_Dp, 2,11,11,L0|L1}, {&upd7810_device::EQAX_Hp, 2,11,11,L0|L1}, + {&upd7810_device::EQAX_Dm, 2,11,11,L0|L1}, {&upd7810_device::EQAX_Hm, 2,11,11,L0|L1} +}; + +/* prefix 74 */ +const struct upd7810_device::opcode_s upd7810_device::s_op74_78c05[256] = +{ + /* 0x00 - 0x1F */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + /* 0x20 - 0x3F */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + /* 0x40 - 0x5F */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + /* 0x60 - 0x7F */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + /* 0x80 - 0x9F */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::ANAW_wa, 3,14,14,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + {&upd7810_device::XRAW_wa, 3,14,14,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::ORAW_wa, 3,14,14,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + /* 0xA0 - 0xBF */ + {&upd7810_device::ADDNCW_wa, 3,14,14,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::GTAW_wa, 3,14,14,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + {&upd7810_device::SUBNBW_wa, 3,14,14,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::LTAW_wa, 3,14,14,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + /* 0xC0 - 0xDF */ + {&upd7810_device::ADDW_wa, 3,14,14,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::ONAW_wa, 3,14,14,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + {&upd7810_device::ADCW_wa, 3,14,14,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::OFFAW_wa, 3,14,14,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + /* 0xE0 - 0xFF */ + {&upd7810_device::SUBW_wa, 3,14,14,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::NEAW_wa, 3,14,14,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + {&upd7810_device::SBBW_wa, 3,14,14,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::EQAW_wa, 3,14,14,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1} +}; + +const struct upd7810_device::opcode_s upd7810_device::s_opXX_78c05[256] = +{ + /* 0x00 - 0x1F */ + {&upd7810_device::NOP, 1, 4, 4,L0|L1}, {&upd7810_device::HALT, 1, 6, 6,L0|L1}, + {&upd7810_device::INX_SP, 1, 7, 7,L0|L1}, {&upd7810_device::DCX_SP, 1, 7, 7,L0|L1}, + {&upd7810_device::LXI_S_w, 3,10,10,L0|L1}, {&upd7810_device::ANIW_wa_xx, 3,16,16,L0|L1}, + {&upd7810_device::illegal, 1, 4, 4,L0|L1}, {&upd7810_device::ANI_A_xx, 2, 7, 7,L0|L1}, + {&upd7810_device::RET, 1,10,10,L0|L1}, {&upd7810_device::SIO, 1, 4, 4,L0|L1}, + {&upd7810_device::MOV_A_B, 1, 4, 4,L0|L1}, {&upd7810_device::MOV_A_C, 1, 4, 4,L0|L1}, + {&upd7810_device::MOV_A_D, 1, 4, 4,L0|L1}, {&upd7810_device::MOV_A_E, 1, 4, 4,L0|L1}, + {&upd7810_device::MOV_A_H, 1, 4, 4,L0|L1}, {&upd7810_device::MOV_A_L, 1, 4, 4,L0|L1}, + + {&upd7810_device::illegal, 1, 4, 4,L0|L1}, {&upd7810_device::illegal, 1, 4, 4,L0|L1}, + {&upd7810_device::INX_BC, 1, 7, 7,L0|L1}, {&upd7810_device::DCX_BC, 1, 7, 7,L0|L1}, + {&upd7810_device::LXI_B_w, 3,10,10,L0|L1}, {&upd7810_device::ORIW_wa_xx, 3,16,16,L0|L1}, + {&upd7810_device::XRI_A_xx, 2, 7, 7,L0|L1}, {&upd7810_device::ORI_A_xx, 2, 7, 7,L0|L1}, + {&upd7810_device::RETS, 1,10,10,L0|L1}, {&upd7810_device::STM, 1, 4, 4,L0|L1}, + {&upd7810_device::MOV_B_A, 1, 4, 4,L0|L1}, {&upd7810_device::MOV_C_A, 1, 4, 4,L0|L1}, + {&upd7810_device::MOV_D_A, 1, 4, 4,L0|L1}, {&upd7810_device::MOV_E_A, 1, 4, 4,L0|L1}, + {&upd7810_device::MOV_H_A, 1, 4, 4,L0|L1}, {&upd7810_device::MOV_L_A, 1, 4, 4,L0|L1}, + + /* 0x20 - 0x3F */ + {&upd7810_device::INRW_wa_7801, 2,13,13,L0|L1}, {&upd7810_device::illegal, 1, 4, 4,L0|L1}, + {&upd7810_device::INX_DE, 1, 7, 7,L0|L1}, {&upd7810_device::DCX_DE, 1, 7, 7,L0|L1}, + {&upd7810_device::LXI_D_w, 3,10,10,L0|L1}, {&upd7810_device::GTIW_wa_xx, 3,13,13,L0|L1}, + {&upd7810_device::ADINC_A_xx, 2, 7, 7,L0|L1}, {&upd7810_device::GTI_A_xx, 2, 7, 7,L0|L1}, + {&upd7810_device::LDAW_wa, 2,10,10,L0|L1}, {&upd7810_device::LDAX_B, 1, 7, 7,L0|L1}, + {&upd7810_device::LDAX_D, 1, 7, 7,L0|L1}, {&upd7810_device::LDAX_H, 1, 7, 7,L0|L1}, + {&upd7810_device::LDAX_Dp, 1, 7, 7,L0|L1}, {&upd7810_device::LDAX_Hp, 1, 7, 7,L0|L1}, + {&upd7810_device::LDAX_Dm, 1, 7, 7,L0|L1}, {&upd7810_device::LDAX_Hm, 1, 7, 7,L0|L1}, + + {&upd7810_device::DCRW_wa_7801, 2,13,13,L0|L1}, {&upd7810_device::illegal, 1, 4, 4,L0|L1}, + {&upd7810_device::INX_HL, 1, 7, 7,L0|L1}, {&upd7810_device::DCX_HL, 1, 7, 7,L0|L1}, + {&upd7810_device::LXI_H_w, 3,10,10, L1}, {&upd7810_device::LTIW_wa_xx, 3,13,13,L0|L1}, + {&upd7810_device::SUINB_A_xx, 2, 7, 7,L0|L1}, {&upd7810_device::LTI_A_xx, 2, 7, 7,L0|L1}, + {&upd7810_device::STAW_wa, 2,10,10,L0|L1}, {&upd7810_device::STAX_B, 1, 7, 7,L0|L1}, + {&upd7810_device::STAX_D, 1, 7, 7,L0|L1}, {&upd7810_device::STAX_H, 1, 7, 7,L0|L1}, + {&upd7810_device::STAX_Dp, 1, 7, 7,L0|L1}, {&upd7810_device::STAX_Hp, 1, 7, 7,L0|L1}, + {&upd7810_device::STAX_Dm, 1, 7, 7,L0|L1}, {&upd7810_device::STAX_Hm, 1, 7, 7,L0|L1}, + + /* 0x40 - 0x5F */ + {&upd7810_device::illegal, 1, 4, 4,L0|L1}, {&upd7810_device::INR_A_7801, 1, 4, 4,L0|L1}, + {&upd7810_device::INR_B_7801, 1, 4, 4,L0|L1}, {&upd7810_device::INR_C_7801, 1, 4, 4,L0|L1}, + {&upd7810_device::CALL_w, 3,16,16,L0|L1}, {&upd7810_device::ONIW_wa_xx, 3,13,13,L0|L1}, + {&upd7810_device::ADI_A_xx, 2, 7, 7,L0|L1}, {&upd7810_device::ONI_A_xx, 2, 7, 7,L0|L1}, + {&upd7810_device::PRE_48, 1, 0, 0,L0|L1}, {&upd7810_device::illegal, 1, 4, 4,L0|L1}, + {&upd7810_device::illegal, 1, 4, 4,L0|L1}, {&upd7810_device::illegal, 1, 4, 4,L0|L1}, + {&upd7810_device::PRE_4C, 1, 0, 0,L0|L1}, {&upd7810_device::PRE_4D, 1, 0, 0,L0|L1}, + {&upd7810_device::JRE, 2,13,13,L0|L1}, {&upd7810_device::JRE, 2,13,13,L0|L1}, + + {&upd7810_device::illegal, 1, 4, 4,L0|L1}, {&upd7810_device::DCR_A_7801, 1, 4, 4,L0|L1}, + {&upd7810_device::DCR_B_7801, 1, 4, 4,L0|L1}, {&upd7810_device::DCR_C_7801, 1, 4, 4,L0|L1}, + {&upd7810_device::JMP_w, 3,10,10,L0|L1}, {&upd7810_device::OFFIW_wa_xx, 3,13,13,L0|L1}, + {&upd7810_device::ACI_A_xx, 2, 7, 7,L0|L1}, {&upd7810_device::OFFI_A_xx, 2, 7, 7,L0|L1}, + {&upd7810_device::illegal, 1, 4, 4,L0|L1}, {&upd7810_device::illegal, 1, 4, 4,L0|L1}, + {&upd7810_device::illegal, 1, 4, 4,L0|L1}, {&upd7810_device::illegal, 1, 4, 4,L0|L1}, + {&upd7810_device::illegal, 1, 4, 4,L0|L1}, {&upd7810_device::illegal, 1, 4, 4,L0|L1}, + {&upd7810_device::illegal, 1, 4, 4,L0|L1}, {&upd7810_device::illegal, 1, 4, 4,L0|L1}, + + /* 0x60 - 0x7F */ + {&upd7810_device::PRE_60, 1, 0, 0,L0|L1}, {&upd7810_device::DAA, 1, 4, 4,L0|L1}, + {&upd7810_device::RETI, 1,13,13,L0|L1}, {&upd7810_device::CALB, 2,13,13,L0|L1}, + {&upd7810_device::PRE_64, 1, 0, 0,L0|L1}, {&upd7810_device::NEIW_wa_xx, 3,13,13,L0|L1}, + {&upd7810_device::SUI_A_xx, 2, 7, 7,L0|L1}, {&upd7810_device::NEI_A_xx, 2, 7, 7,L0|L1}, + {&upd7810_device::illegal, 1, 4, 4,L0|L1}, {&upd7810_device::MVI_A_xx, 2, 7, 7,L0 }, + {&upd7810_device::MVI_B_xx, 2, 7, 7,L0|L1}, {&upd7810_device::MVI_C_xx, 2, 7, 7,L0|L1}, + {&upd7810_device::MVI_D_xx, 2, 7, 7,L0|L1}, {&upd7810_device::MVI_E_xx, 2, 7, 7,L0|L1}, + {&upd7810_device::MVI_H_xx, 2, 7, 7,L0|L1}, {&upd7810_device::MVI_L_xx, 2, 7, 7, L1}, + + {&upd7810_device::PRE_70, 1, 0, 0,L0|L1}, {&upd7810_device::MVIW_wa_xx, 3,13,13,L0|L1}, + {&upd7810_device::SOFTI, 1,19,19,L0|L1}, {&upd7810_device::JB, 1, 4, 4,L0|L1}, + {&upd7810_device::PRE_74, 1, 0, 0,L0|L1}, {&upd7810_device::EQIW_wa_xx, 3,13,13,L0|L1}, + {&upd7810_device::SBI_A_xx, 2, 7, 7,L0|L1}, {&upd7810_device::EQI_A_xx, 2, 7, 7,L0|L1}, + {&upd7810_device::CALF, 2,13,13,L0|L1}, {&upd7810_device::CALF, 2,13,13,L0|L1}, + {&upd7810_device::CALF, 2,13,13,L0|L1}, {&upd7810_device::CALF, 2,13,13,L0|L1}, + {&upd7810_device::CALF, 2,13,13,L0|L1}, {&upd7810_device::CALF, 2,13,13,L0|L1}, + {&upd7810_device::CALF, 2,13,13,L0|L1}, {&upd7810_device::CALF, 2,13,13,L0|L1}, + + /* 0x80 - 0x9F */ + {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, + {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, + {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, + {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, + {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, + {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, + {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, + {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, + + {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, + {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, + {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, + {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, + {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, + {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, + {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, + {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, + + /* 0xA0 - 0xBF */ + {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, + {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, + {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, + {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, + {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, + {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, + {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, + {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, + + {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, + {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, + {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, + {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, + {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, + {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, + {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, + {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, + + /* 0xC0 - 0xDF */ + {&upd7810_device::JR, 1,10,10,L0|L1}, {&upd7810_device::JR, 1,10,10,L0|L1}, + {&upd7810_device::JR, 1,10,10,L0|L1}, {&upd7810_device::JR, 1,10,10,L0|L1}, + {&upd7810_device::JR, 1,10,10,L0|L1}, {&upd7810_device::JR, 1,10,10,L0|L1}, + {&upd7810_device::JR, 1,10,10,L0|L1}, {&upd7810_device::JR, 1,10,10,L0|L1}, + {&upd7810_device::JR, 1,10,10,L0|L1}, {&upd7810_device::JR, 1,10,10,L0|L1}, + {&upd7810_device::JR, 1,10,10,L0|L1}, {&upd7810_device::JR, 1,10,10,L0|L1}, + {&upd7810_device::JR, 1,10,10,L0|L1}, {&upd7810_device::JR, 1,10,10,L0|L1}, + {&upd7810_device::JR, 1,10,10,L0|L1}, {&upd7810_device::JR, 1,10,10,L0|L1}, + + {&upd7810_device::JR, 1,10,10,L0|L1}, {&upd7810_device::JR, 1,10,10,L0|L1}, + {&upd7810_device::JR, 1,10,10,L0|L1}, {&upd7810_device::JR, 1,10,10,L0|L1}, + {&upd7810_device::JR, 1,10,10,L0|L1}, {&upd7810_device::JR, 1,10,10,L0|L1}, + {&upd7810_device::JR, 1,10,10,L0|L1}, {&upd7810_device::JR, 1,10,10,L0|L1}, + {&upd7810_device::JR, 1,10,10,L0|L1}, {&upd7810_device::JR, 1,10,10,L0|L1}, + {&upd7810_device::JR, 1,10,10,L0|L1}, {&upd7810_device::JR, 1,10,10,L0|L1}, + {&upd7810_device::JR, 1,10,10,L0|L1}, {&upd7810_device::JR, 1,10,10,L0|L1}, + {&upd7810_device::JR, 1,10,10,L0|L1}, {&upd7810_device::JR, 1,10,10,L0|L1}, + + /* 0xE0 - 0xFF */ + {&upd7810_device::JR, 1,10,10,L0|L1}, {&upd7810_device::JR, 1,10,10,L0|L1}, + {&upd7810_device::JR, 1,10,10,L0|L1}, {&upd7810_device::JR, 1,10,10,L0|L1}, + {&upd7810_device::JR, 1,10,10,L0|L1}, {&upd7810_device::JR, 1,10,10,L0|L1}, + {&upd7810_device::JR, 1,10,10,L0|L1}, {&upd7810_device::JR, 1,10,10,L0|L1}, + {&upd7810_device::JR, 1,10,10,L0|L1}, {&upd7810_device::JR, 1,10,10,L0|L1}, + {&upd7810_device::JR, 1,10,10,L0|L1}, {&upd7810_device::JR, 1,10,10,L0|L1}, + {&upd7810_device::JR, 1,10,10,L0|L1}, {&upd7810_device::JR, 1,10,10,L0|L1}, + {&upd7810_device::JR, 1,10,10,L0|L1}, {&upd7810_device::JR, 1,10,10,L0|L1}, + + {&upd7810_device::JR, 1,10,10,L0|L1}, {&upd7810_device::JR, 1,10,10,L0|L1}, + {&upd7810_device::JR, 1,10,10,L0|L1}, {&upd7810_device::JR, 1,10,10,L0|L1}, + {&upd7810_device::JR, 1,10,10,L0|L1}, {&upd7810_device::JR, 1,10,10,L0|L1}, + {&upd7810_device::JR, 1,10,10,L0|L1}, {&upd7810_device::JR, 1,10,10,L0|L1}, + {&upd7810_device::JR, 1,10,10,L0|L1}, {&upd7810_device::JR, 1,10,10,L0|L1}, + {&upd7810_device::JR, 1,10,10,L0|L1}, {&upd7810_device::JR, 1,10,10,L0|L1}, + {&upd7810_device::JR, 1,10,10,L0|L1}, {&upd7810_device::JR, 1,10,10,L0|L1}, + {&upd7810_device::JR, 1,10,10,L0|L1}, {&upd7810_device::JR, 1,10,10,L0|L1} +}; + +/*********************************************************************** + * + * uPD78C06(A) - Same as uPD78C05 but with different instruction timing + * + **********************************************************************/ + +const struct upd7810_device::opcode_s upd7810_device::s_op48_78c06[256] = +{ + /* 0x00 - 0x1F */ + {&upd7810_device::SKIT_F0, 2,12,12,L0|L1}, {&upd7810_device::SKIT_FT0, 2,12,12,L0|L1}, + {&upd7810_device::SKIT_F1, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::SKIT_FST, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::SK_CY, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::SK_Z, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::PUSH_VA, 2,21,21,L0|L1}, {&upd7810_device::POP_VA, 2,18,18,L0|L1}, + + {&upd7810_device::SKNIT_F0, 2,12,12,L0|L1}, {&upd7810_device::SKNIT_FT0, 2,12,12,L0|L1}, + {&upd7810_device::SKNIT_F1, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::SKNIT_FST, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::SKN_CY, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::SKN_Z, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::PUSH_BC, 2,21,21,L0|L1}, {&upd7810_device::POP_BC, 2,18,18,L0|L1}, + + /* 0x20 - 0x3F */ + {&upd7810_device::EI, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::DI, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::CLC, 2,12,12,L0|L1}, {&upd7810_device::STC, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::PEX, 2,15,15,L0|L1}, + {&upd7810_device::PUSH_DE, 2,21,21,L0|L1}, {&upd7810_device::POP_DE, 2,18,18,L0|L1}, + + {&upd7810_device::RLL_A, 2,12,12,L0|L1}, {&upd7810_device::RLR_A, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::RLD, 2,21,21,L0|L1}, {&upd7810_device::RRD, 2,21,21,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::PER, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::PUSH_HL, 2,21,21,L0|L1}, {&upd7810_device::POP_HL, 2,18,18,L0|L1}, + + /* 0x40 - 0x5F */ + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + + /* 0x60 - 0x7F */ + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + + /* 0x80 - 0x9F */ + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + + /* 0xA0 - 0xBF */ + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + + /* 0xC0 - 0xDF */ + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + + /* 0xE0 - 0xFF */ + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1} +}; + +const struct upd7810_device::opcode_s upd7810_device::s_op4C_78c06[256] = +{ + /* 0x00 - 0x1F */ + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + + /* 0x20 - 0x3F */ + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + + /* 0x40 - 0x5F */ + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + + /* 0x60 - 0x7F */ + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + + /* 0x80 - 0x9F */ + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + + /* 0xA0 - 0xBF */ + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + + /* 0xC0 - 0xDF */ + {&upd7810_device::MOV_A_PA, 2,14,14,L0|L1}, {&upd7810_device::MOV_A_PB, 2,14,14,L0|L1}, + {&upd7810_device::MOV_A_PC, 2,14,14,L0|L1}, {&upd7810_device::MOV_A_MKL, 2,14,14,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::MOV_A_S, 2,14,14,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + + /* 0xE0 - 0xFF */ + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1} +}; + +/* prefix 4D */ +const struct upd7810_device::opcode_s upd7810_device::s_op4D_78c06[256] = +{ + /* 0x00 - 0x1F */ + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + + /* 0x20 - 0x3F */ + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + + /* 0x40 - 0x5F */ + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + + /* 0x60 - 0x7F */ + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + + /* 0x80 - 0x9F */ + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + + /* 0xA0 - 0xBF */ + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + + /* 0xC0 - 0xDF */ + {&upd7810_device::MOV_PA_A, 2,14,14,L0|L1}, {&upd7810_device::MOV_PB_A, 2,14,14,L0|L1}, + {&upd7810_device::MOV_PC_A, 2,14,14,L0|L1}, {&upd7810_device::MOV_MKL_A, 2,14,14,L0|L1}, + {&upd7810_device::MOV_MB_A, 2,14,14,L0|L1}, {&upd7810_device::MOV_MC_A, 2,14,14,L0|L1}, + {&upd7810_device::MOV_TM0_A, 2,14,14,L0|L1}, {&upd7810_device::MOV_TM1_A, 2,14,14,L0|L1}, + {&upd7810_device::MOV_S_A, 2,14,14,L0|L1}, {&upd7810_device::MOV_TMM_A, 2,14,14,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + + /* 0xE0 - 0xFF */ + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1} +}; + +/* prefix 60 */ +const struct upd7810_device::opcode_s upd7810_device::s_op60_78c06[256] = +{ + /* 0x00 - 0x1F */ + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::ANA_A_A, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::XRA_A_A, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::ORA_A_A, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + + /* 0x20 - 0x3F */ + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::ADDNC_A_A, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::GTA_A_A, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::SUBNB_A_A, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::LTA_A_A, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + + /* 0x40 - 0x5F */ + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::ADD_A_A, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::ADC_A_A, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + + /* 0x60 - 0x7F */ + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::SUB_A_A, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::NEA_A_A, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::SBB_A_A, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::EQA_A_A, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + + /* 0x80 - 0x9F */ + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::ANA_A_A, 2,12,12,L0|L1}, + {&upd7810_device::ANA_A_B, 2,12,12,L0|L1}, {&upd7810_device::ANA_A_C, 2,12,12,L0|L1}, + {&upd7810_device::ANA_A_D, 2,12,12,L0|L1}, {&upd7810_device::ANA_A_E, 2,12,12,L0|L1}, + {&upd7810_device::ANA_A_H, 2,12,12,L0|L1}, {&upd7810_device::ANA_A_L, 2,12,12,L0|L1}, + + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::XRA_A_A, 2,12,12,L0|L1}, + {&upd7810_device::XRA_A_B, 2,12,12,L0|L1}, {&upd7810_device::XRA_A_C, 2,12,12,L0|L1}, + {&upd7810_device::XRA_A_D, 2,12,12,L0|L1}, {&upd7810_device::XRA_A_E, 2,12,12,L0|L1}, + {&upd7810_device::XRA_A_H, 2,12,12,L0|L1}, {&upd7810_device::XRA_A_L, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::ORA_A_A, 2,12,12,L0|L1}, + {&upd7810_device::ORA_A_B, 2,12,12,L0|L1}, {&upd7810_device::ORA_A_C, 2,12,12,L0|L1}, + {&upd7810_device::ORA_A_D, 2,12,12,L0|L1}, {&upd7810_device::ORA_A_E, 2,12,12,L0|L1}, + {&upd7810_device::ORA_A_H, 2,12,12,L0|L1}, {&upd7810_device::ORA_A_L, 2,12,12,L0|L1}, + + /* 0xA0 - 0xBF */ + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::ADDNC_A_A, 2,12,12,L0|L1}, + {&upd7810_device::ADDNC_A_B, 2,12,12,L0|L1}, {&upd7810_device::ADDNC_A_C, 2,12,12,L0|L1}, + {&upd7810_device::ADDNC_A_D, 2,12,12,L0|L1}, {&upd7810_device::ADDNC_A_E, 2,12,12,L0|L1}, + {&upd7810_device::ADDNC_A_H, 2,12,12,L0|L1}, {&upd7810_device::ADDNC_A_L, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::GTA_A_A, 2,12,12,L0|L1}, + {&upd7810_device::GTA_A_B, 2,12,12,L0|L1}, {&upd7810_device::GTA_A_C, 2,12,12,L0|L1}, + {&upd7810_device::GTA_A_D, 2,12,12,L0|L1}, {&upd7810_device::GTA_A_E, 2,12,12,L0|L1}, + {&upd7810_device::GTA_A_H, 2,12,12,L0|L1}, {&upd7810_device::GTA_A_L, 2,12,12,L0|L1}, + + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::SUBNB_A_A, 2,12,12,L0|L1}, + {&upd7810_device::SUBNB_A_B, 2,12,12,L0|L1}, {&upd7810_device::SUBNB_A_C, 2,12,12,L0|L1}, + {&upd7810_device::SUBNB_A_D, 2,12,12,L0|L1}, {&upd7810_device::SUBNB_A_E, 2,12,12,L0|L1}, + {&upd7810_device::SUBNB_A_H, 2,12,12,L0|L1}, {&upd7810_device::SUBNB_A_L, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::LTA_A_A, 2,12,12,L0|L1}, + {&upd7810_device::LTA_A_B, 2,12,12,L0|L1}, {&upd7810_device::LTA_A_C, 2,12,12,L0|L1}, + {&upd7810_device::LTA_A_D, 2,12,12,L0|L1}, {&upd7810_device::LTA_A_E, 2,12,12,L0|L1}, + {&upd7810_device::LTA_A_H, 2,12,12,L0|L1}, {&upd7810_device::LTA_A_L, 2,12,12,L0|L1}, + + /* 0xC0 - 0xDF */ + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::ADD_A_A, 2,12,12,L0|L1}, + {&upd7810_device::ADD_A_B, 2,12,12,L0|L1}, {&upd7810_device::ADD_A_C, 2,12,12,L0|L1}, + {&upd7810_device::ADD_A_D, 2,12,12,L0|L1}, {&upd7810_device::ADD_A_E, 2,12,12,L0|L1}, + {&upd7810_device::ADD_A_H, 2,12,12,L0|L1}, {&upd7810_device::ADD_A_L, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::ONA_A_A, 2,12,12,L0|L1}, + {&upd7810_device::ONA_A_B, 2,12,12,L0|L1}, {&upd7810_device::ONA_A_C, 2,12,12,L0|L1}, + {&upd7810_device::ONA_A_D, 2,12,12,L0|L1}, {&upd7810_device::ONA_A_E, 2,12,12,L0|L1}, + {&upd7810_device::ONA_A_H, 2,12,12,L0|L1}, {&upd7810_device::ONA_A_L, 2,12,12,L0|L1}, + + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::ADC_A_A, 2,12,12,L0|L1}, + {&upd7810_device::ADC_A_B, 2,12,12,L0|L1}, {&upd7810_device::ADC_A_C, 2,12,12,L0|L1}, + {&upd7810_device::ADC_A_D, 2,12,12,L0|L1}, {&upd7810_device::ADC_A_E, 2,12,12,L0|L1}, + {&upd7810_device::ADC_A_H, 2,12,12,L0|L1}, {&upd7810_device::ADC_A_L, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::OFFA_A_A, 2,12,12,L0|L1}, + {&upd7810_device::OFFA_A_B, 2,12,12,L0|L1}, {&upd7810_device::OFFA_A_C, 2,12,12,L0|L1}, + {&upd7810_device::OFFA_A_D, 2,12,12,L0|L1}, {&upd7810_device::OFFA_A_E, 2,12,12,L0|L1}, + {&upd7810_device::OFFA_A_H, 2,12,12,L0|L1}, {&upd7810_device::OFFA_A_L, 2,12,12,L0|L1}, + + /* 0xE0 - 0xFF */ + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::SUB_A_A, 2,12,12,L0|L1}, + {&upd7810_device::SUB_A_B, 2,12,12,L0|L1}, {&upd7810_device::SUB_A_C, 2,12,12,L0|L1}, + {&upd7810_device::SUB_A_D, 2,12,12,L0|L1}, {&upd7810_device::SUB_A_E, 2,12,12,L0|L1}, + {&upd7810_device::SUB_A_H, 2,12,12,L0|L1}, {&upd7810_device::SUB_A_L, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::NEA_A_A, 2,12,12,L0|L1}, + {&upd7810_device::NEA_A_B, 2,12,12,L0|L1}, {&upd7810_device::NEA_A_C, 2,12,12,L0|L1}, + {&upd7810_device::NEA_A_D, 2,12,12,L0|L1}, {&upd7810_device::NEA_A_E, 2,12,12,L0|L1}, + {&upd7810_device::NEA_A_H, 2,12,12,L0|L1}, {&upd7810_device::NEA_A_L, 2,12,12,L0|L1}, + + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::SBB_A_A, 2,12,12,L0|L1}, + {&upd7810_device::SBB_A_B, 2,12,12,L0|L1}, {&upd7810_device::SBB_A_C, 2,12,12,L0|L1}, + {&upd7810_device::SBB_A_D, 2,12,12,L0|L1}, {&upd7810_device::SBB_A_E, 2,12,12,L0|L1}, + {&upd7810_device::SBB_A_H, 2,12,12,L0|L1}, {&upd7810_device::SBB_A_L, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::EQA_A_A, 2,12,12,L0|L1}, + {&upd7810_device::EQA_A_B, 2,12,12,L0|L1}, {&upd7810_device::EQA_A_C, 2,12,12,L0|L1}, + {&upd7810_device::EQA_A_D, 2,12,12,L0|L1}, {&upd7810_device::EQA_A_E, 2,12,12,L0|L1}, + {&upd7810_device::EQA_A_H, 2,12,12,L0|L1}, {&upd7810_device::EQA_A_L, 2,12,12,L0|L1} +}; + +/* prefix 64 */ +const struct upd7810_device::opcode_s upd7810_device::s_op64_78c06[256] = +{ + /* 0x00 - 0x1F */ + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::ANI_A_xx, 3,17,17,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::XRI_A_xx, 3,17,17,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::ORI_A_xx, 3,17,17,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + + /* 0x20 - 0x3F */ + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::ADINC_A_xx, 3,17,17,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::GTI_A_xx, 3,17,17,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::SUINB_A_xx, 3,17,17,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 3,12,12,L0|L1}, {&upd7810_device::LTI_A_xx, 3,17,17,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + + /* 0x40 - 0x5F */ + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::ADI_A_xx, 3,17,17,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::ONI_A_xx, 3,17,17,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + + {&upd7810_device::illegal2, 3,12,12,L0|L1}, {&upd7810_device::ACI_A_xx, 3,17,17,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 3,12,12,L0|L1}, {&upd7810_device::OFFI_A_xx, 3,17,17,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + + /* 0x60 - 0x7F */ + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::SUI_A_xx, 3,17,17,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::NEI_A_xx, 3,17,17,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::SBI_A_xx, 3,17,17,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::EQI_A_xx, 3,17,17,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + + /* 0x80 - 0x9F */ + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::ANI_PA_xx, 3,23,23,L0|L1}, {&upd7810_device::ANI_PB_xx, 3,23,23,L0|L1}, + {&upd7810_device::ANI_PC_xx, 3,23,23,L0|L1}, {&upd7810_device::ANI_MKL_xx, 3,23,23,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + + {&upd7810_device::XRI_PA_xx, 3,23,23,L0|L1}, {&upd7810_device::XRI_PB_xx, 3,23,23,L0|L1}, + {&upd7810_device::XRI_PC_xx, 3,23,23,L0|L1}, {&upd7810_device::XRI_MKL_xx, 3,23,23,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::ORI_PA_xx, 3,23,23,L0|L1}, {&upd7810_device::ORI_PB_xx, 3,23,23,L0|L1}, + {&upd7810_device::ORI_PC_xx, 3,23,23,L0|L1}, {&upd7810_device::ORI_MKL_xx, 3,23,23,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + + /* 0xA0 - 0xBF */ + {&upd7810_device::ADINC_PA_xx, 3,23,23,L0|L1}, {&upd7810_device::ADINC_PB_xx, 3,23,23,L0|L1}, + {&upd7810_device::ADINC_PC_xx, 3,23,23,L0|L1}, {&upd7810_device::ADINC_MKL_xx, 3,23,23,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::GTI_PA_xx, 3,20,20,L0|L1}, {&upd7810_device::GTI_PB_xx, 3,20,20,L0|L1}, + {&upd7810_device::GTI_PC_xx, 3,20,20,L0|L1}, {&upd7810_device::GTI_MKL_xx, 3,20,20,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + + {&upd7810_device::SUINB_PA_xx, 3,23,23,L0|L1}, {&upd7810_device::SUINB_PB_xx, 3,23,23,L0|L1}, + {&upd7810_device::SUINB_PC_xx, 3,23,23,L0|L1}, {&upd7810_device::SUINB_MKL_xx, 3,23,23,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::LTI_PA_xx, 3,20,20,L0|L1}, {&upd7810_device::LTI_PB_xx, 3,20,20,L0|L1}, + {&upd7810_device::LTI_PC_xx, 3,20,20,L0|L1}, {&upd7810_device::LTI_MKL_xx, 3,20,20,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + + /* 0xC0 - 0xDF */ + {&upd7810_device::ADI_PA_xx, 3,23,23,L0|L1}, {&upd7810_device::ADI_PB_xx, 3,23,23,L0|L1}, + {&upd7810_device::ADI_PC_xx, 3,23,23,L0|L1}, {&upd7810_device::ADI_MKL_xx, 3,23,23,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::ONI_PA_xx, 3,20,20,L0|L1}, {&upd7810_device::ONI_PB_xx, 3,20,20,L0|L1}, + {&upd7810_device::ONI_PC_xx, 3,20,20,L0|L1}, {&upd7810_device::ONI_MKL_xx, 3,20,20,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + + {&upd7810_device::ACI_PA_xx, 3,23,23,L0|L1}, {&upd7810_device::ACI_PB_xx, 3,23,23,L0|L1}, + {&upd7810_device::ACI_PC_xx, 3,23,23,L0|L1}, {&upd7810_device::ACI_MKL_xx, 3,23,23,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::OFFI_PA_xx, 3,20,20,L0|L1}, {&upd7810_device::OFFI_PB_xx, 3,20,20,L0|L1}, + {&upd7810_device::OFFI_PC_xx, 3,20,20,L0|L1}, {&upd7810_device::OFFI_MKL_xx, 3,20,20,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + + /* 0xE0 - 0xFF */ + {&upd7810_device::SUI_PA_xx, 3,23,23,L0|L1}, {&upd7810_device::SUI_PB_xx, 3,23,23,L0|L1}, + {&upd7810_device::SUI_PC_xx, 3,23,23,L0|L1}, {&upd7810_device::SUI_MKL_xx, 3,23,23,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::NEI_PA_xx, 3,20,20,L0|L1}, {&upd7810_device::NEI_PB_xx, 3,20,20,L0|L1}, + {&upd7810_device::NEI_PC_xx, 3,20,20,L0|L1}, {&upd7810_device::NEI_MKL_xx, 3,20,20,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + + {&upd7810_device::SBI_PA_xx, 3,23,23,L0|L1}, {&upd7810_device::SBI_PB_xx, 3,23,23,L0|L1}, + {&upd7810_device::SBI_PC_xx, 3,23,23,L0|L1}, {&upd7810_device::SBI_MKL_xx, 3,23,23,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::EQI_PA_xx, 3,20,20,L0|L1}, {&upd7810_device::EQI_PB_xx, 3,20,20,L0|L1}, + {&upd7810_device::EQI_PC_xx, 3,20,20,L0|L1}, {&upd7810_device::EQI_MKL_xx, 3,20,20,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1} +}; + +/* prefix 70 */ +const struct upd7810_device::opcode_s upd7810_device::s_op70_78c06[256] = +{ + /* 0x00 - 0x1F */ + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::SSPD_w, 4,28,28,L0|L1}, {&upd7810_device::LSPD_w, 4,28,28,L0|L1}, + + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::SBCD_w, 4,28,28,L0|L1}, {&upd7810_device::LBCD_w, 4,28,28,L0|L1}, + + /* 0x20 - 0x3F */ + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::SDED_w, 4,28,28,L0|L1}, {&upd7810_device::LDED_w, 4,28,28,L0|L1}, + + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::SHLD_w, 4,28,28,L0|L1}, {&upd7810_device::LHLD_w, 4,28,28,L0|L1}, + + /* 0x40 - 0x5F */ + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + + /* 0x60 - 0x7F */ + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::MOV_A_w, 4,25,25,L0|L1}, + {&upd7810_device::MOV_B_w, 4,25,25,L0|L1}, {&upd7810_device::MOV_C_w, 4,25,25,L0|L1}, + {&upd7810_device::MOV_D_w, 4,25,25,L0|L1}, {&upd7810_device::MOV_E_w, 4,25,25,L0|L1}, + {&upd7810_device::MOV_H_w, 4,25,25,L0|L1}, {&upd7810_device::MOV_L_w, 4,25,25,L0|L1}, + + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::MOV_w_A, 4,25,25,L0|L1}, + {&upd7810_device::MOV_w_B, 4,25,25,L0|L1}, {&upd7810_device::MOV_w_C, 4,25,25,L0|L1}, + {&upd7810_device::MOV_w_D, 4,25,25,L0|L1}, {&upd7810_device::MOV_w_E, 4,25,25,L0|L1}, + {&upd7810_device::MOV_w_H, 4,25,25,L0|L1}, {&upd7810_device::MOV_w_L, 4,25,25,L0|L1}, + + /* 0x80 - 0x9F */ + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::ANAX_B, 2,15,15,L0|L1}, + {&upd7810_device::ANAX_D, 2,15,15,L0|L1}, {&upd7810_device::ANAX_H, 2,15,15,L0|L1}, + {&upd7810_device::ANAX_Dp, 2,15,15,L0|L1}, {&upd7810_device::ANAX_Hp, 2,15,15,L0|L1}, + {&upd7810_device::ANAX_Dm, 2,15,15,L0|L1}, {&upd7810_device::ANAX_Hm, 2,15,15,L0|L1}, + + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::XRAX_B, 2,15,15,L0|L1}, + {&upd7810_device::XRAX_D, 2,15,15,L0|L1}, {&upd7810_device::XRAX_H, 2,15,15,L0|L1}, + {&upd7810_device::XRAX_Dp, 2,15,15,L0|L1}, {&upd7810_device::XRAX_Hp, 2,15,15,L0|L1}, + {&upd7810_device::XRAX_Dm, 2,15,15,L0|L1}, {&upd7810_device::XRAX_Hm, 2,15,15,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::ORAX_B, 2,15,15,L0|L1}, + {&upd7810_device::ORAX_D, 2,15,15,L0|L1}, {&upd7810_device::ORAX_H, 2,15,15,L0|L1}, + {&upd7810_device::ORAX_Dp, 2,15,15,L0|L1}, {&upd7810_device::ORAX_Hp, 2,15,15,L0|L1}, + {&upd7810_device::ORAX_Dm, 2,15,15,L0|L1}, {&upd7810_device::ORAX_Hm, 2,15,15,L0|L1}, + + /* 0xA0 - 0xBF */ + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::ADDNCX_B, 2,15,15,L0|L1}, + {&upd7810_device::ADDNCX_D, 2,15,15,L0|L1}, {&upd7810_device::ADDNCX_H, 2,15,15,L0|L1}, + {&upd7810_device::ADDNCX_Dp, 2,15,15,L0|L1}, {&upd7810_device::ADDNCX_Hp, 2,15,15,L0|L1}, + {&upd7810_device::ADDNCX_Dm, 2,15,15,L0|L1}, {&upd7810_device::ADDNCX_Hm, 2,15,15,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::GTAX_B, 2,15,15,L0|L1}, + {&upd7810_device::GTAX_D, 2,15,15,L0|L1}, {&upd7810_device::GTAX_H, 2,15,15,L0|L1}, + {&upd7810_device::GTAX_Dp, 2,15,15,L0|L1}, {&upd7810_device::GTAX_Hp, 2,15,15,L0|L1}, + {&upd7810_device::GTAX_Dm, 2,15,15,L0|L1}, {&upd7810_device::GTAX_Hm, 2,15,15,L0|L1}, + + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::SUBNBX_B, 2,15,15,L0|L1}, + {&upd7810_device::SUBNBX_D, 2,15,15,L0|L1}, {&upd7810_device::SUBNBX_H, 2,15,15,L0|L1}, + {&upd7810_device::SUBNBX_Dp, 2,15,15,L0|L1}, {&upd7810_device::SUBNBX_Hp, 2,15,15,L0|L1}, + {&upd7810_device::SUBNBX_Dm, 2,15,15,L0|L1}, {&upd7810_device::SUBNBX_Hm, 2,15,15,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::LTAX_B, 2,15,15,L0|L1}, + {&upd7810_device::LTAX_D, 2,15,15,L0|L1}, {&upd7810_device::LTAX_H, 2,15,15,L0|L1}, + {&upd7810_device::LTAX_Dp, 2,15,15,L0|L1}, {&upd7810_device::LTAX_Hp, 2,15,15,L0|L1}, + {&upd7810_device::LTAX_Dm, 2,15,15,L0|L1}, {&upd7810_device::LTAX_Hm, 2,15,15,L0|L1}, + + /* 0xC0 - 0xDF */ + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::ADDX_B, 2,15,15,L0|L1}, + {&upd7810_device::ADDX_D, 2,15,15,L0|L1}, {&upd7810_device::ADDX_H, 2,15,15,L0|L1}, + {&upd7810_device::ADDX_Dp, 2,15,15,L0|L1}, {&upd7810_device::ADDX_Hp, 2,15,15,L0|L1}, + {&upd7810_device::ADDX_Dm, 2,15,15,L0|L1}, {&upd7810_device::ADDX_Hm, 2,15,15,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::ONAX_B, 2,15,15,L0|L1}, + {&upd7810_device::ONAX_D, 2,15,15,L0|L1}, {&upd7810_device::ONAX_H, 2,15,15,L0|L1}, + {&upd7810_device::ONAX_Dp, 2,15,15,L0|L1}, {&upd7810_device::ONAX_Hp, 2,15,15,L0|L1}, + {&upd7810_device::ONAX_Dm, 2,15,15,L0|L1}, {&upd7810_device::ONAX_Hm, 2,15,15,L0|L1}, + + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::ADCX_B, 2,15,15,L0|L1}, + {&upd7810_device::ADCX_D, 2,15,15,L0|L1}, {&upd7810_device::ADCX_H, 2,15,15,L0|L1}, + {&upd7810_device::ADCX_Dp, 2,15,15,L0|L1}, {&upd7810_device::ADCX_Hp, 2,15,15,L0|L1}, + {&upd7810_device::ADCX_Dm, 2,15,15,L0|L1}, {&upd7810_device::ADCX_Hm, 2,15,15,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::OFFAX_B, 2,15,15,L0|L1}, + {&upd7810_device::OFFAX_D, 2,15,15,L0|L1}, {&upd7810_device::OFFAX_H, 2,15,15,L0|L1}, + {&upd7810_device::OFFAX_Dp, 2,15,15,L0|L1}, {&upd7810_device::OFFAX_Hp, 2,15,15,L0|L1}, + {&upd7810_device::OFFAX_Dm, 2,15,15,L0|L1}, {&upd7810_device::OFFAX_Hm, 2,15,15,L0|L1}, + + /* 0xE0 - 0xFF */ + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::SUBX_B, 2,15,15,L0|L1}, + {&upd7810_device::SUBX_D, 2,15,15,L0|L1}, {&upd7810_device::SUBX_H, 2,15,15,L0|L1}, + {&upd7810_device::SUBX_Dp, 2,15,15,L0|L1}, {&upd7810_device::SUBX_Hp, 2,15,15,L0|L1}, + {&upd7810_device::SUBX_Dm, 2,15,15,L0|L1}, {&upd7810_device::SUBX_Hm, 2,15,15,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::NEAX_B, 2,15,15,L0|L1}, + {&upd7810_device::NEAX_D, 2,15,15,L0|L1}, {&upd7810_device::NEAX_H, 2,15,15,L0|L1}, + {&upd7810_device::NEAX_Dp, 2,15,15,L0|L1}, {&upd7810_device::NEAX_Hp, 2,15,15,L0|L1}, + {&upd7810_device::NEAX_Dm, 2,15,15,L0|L1}, {&upd7810_device::NEAX_Hm, 2,15,15,L0|L1}, + + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::SBBX_B, 2,15,15,L0|L1}, + {&upd7810_device::SBBX_D, 2,15,15,L0|L1}, {&upd7810_device::SBBX_H, 2,15,15,L0|L1}, + {&upd7810_device::SBBX_Dp, 2,15,15,L0|L1}, {&upd7810_device::SBBX_Hp, 2,15,15,L0|L1}, + {&upd7810_device::SBBX_Dm, 2,15,15,L0|L1}, {&upd7810_device::SBBX_Hm, 2,15,15,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::EQAX_B, 2,15,15,L0|L1}, + {&upd7810_device::EQAX_D, 2,15,15,L0|L1}, {&upd7810_device::EQAX_H, 2,15,15,L0|L1}, + {&upd7810_device::EQAX_Dp, 2,15,15,L0|L1}, {&upd7810_device::EQAX_Hp, 2,15,15,L0|L1}, + {&upd7810_device::EQAX_Dm, 2,15,15,L0|L1}, {&upd7810_device::EQAX_Hm, 2,15,15,L0|L1} +}; + +/* prefix 74 */ +const struct upd7810_device::opcode_s upd7810_device::s_op74_78c06[256] = +{ + /* 0x00 - 0x1F */ + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + + /* 0x20 - 0x3F */ + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + + /* 0x40 - 0x5F */ + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + + /* 0x60 - 0x7F */ + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + + /* 0x80 - 0x9F */ + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::ANAW_wa, 3,14,14,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + + {&upd7810_device::XRAW_wa, 3,14,14,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::ORAW_wa, 3,14,14,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + + /* 0xA0 - 0xBF */ + {&upd7810_device::ADDNCW_wa, 3,14,14,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::GTAW_wa, 3,14,14,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + + {&upd7810_device::SUBNBW_wa, 3,14,14,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::LTAW_wa, 3,14,14,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + + /* 0xC0 - 0xDF */ + {&upd7810_device::ADDW_wa, 3,14,14,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::ONAW_wa, 3,14,14,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + + {&upd7810_device::ADCW_wa, 3,14,14,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::OFFAW_wa, 3,14,14,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + + /* 0xE0 - 0xFF */ + {&upd7810_device::SUBW_wa, 3,14,14,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::NEAW_wa, 3,14,14,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + + {&upd7810_device::SBBW_wa, 3,14,14,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::EQAW_wa, 3,14,14,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1}, + {&upd7810_device::illegal2, 2,12,12,L0|L1}, {&upd7810_device::illegal2, 2,12,12,L0|L1} +}; + +const struct upd7810_device::opcode_s upd7810_device::s_opXX_78c06[256] = +{ + /* 0x00 - 0x1F */ + {&upd7810_device::NOP, 1, 6, 6,L0|L1}, {&upd7810_device::HALT, 1, 6, 6,L0|L1}, + {&upd7810_device::INX_SP, 1, 9, 9,L0|L1}, {&upd7810_device::DCX_SP, 1, 9, 9,L0|L1}, + {&upd7810_device::LXI_S_w, 3,16,16,L0|L1}, {&upd7810_device::ANIW_wa_xx, 3,22,22,L0|L1}, + {&upd7810_device::illegal, 1, 6, 6,L0|L1}, {&upd7810_device::ANI_A_xx, 2,11,11,L0|L1}, + {&upd7810_device::RET, 1,12,12,L0|L1}, {&upd7810_device::SIO, 1, 6, 6,L0|L1}, + {&upd7810_device::MOV_A_B, 1, 6, 6,L0|L1}, {&upd7810_device::MOV_A_C, 1, 6, 6,L0|L1}, + {&upd7810_device::MOV_A_D, 1, 6, 6,L0|L1}, {&upd7810_device::MOV_A_E, 1, 6, 6,L0|L1}, + {&upd7810_device::MOV_A_H, 1, 6, 6,L0|L1}, {&upd7810_device::MOV_A_L, 1, 6, 6,L0|L1}, + + {&upd7810_device::illegal, 1, 6, 6,L0|L1}, {&upd7810_device::illegal, 1, 6, 6,L0|L1}, + {&upd7810_device::INX_BC, 1, 9, 9,L0|L1}, {&upd7810_device::DCX_BC, 1, 9, 9,L0|L1}, + {&upd7810_device::LXI_B_w, 3,16,16,L0|L1}, {&upd7810_device::ORIW_wa_xx, 3,22,2,L0|L1}, + {&upd7810_device::XRI_A_xx, 2,11,11,L0|L1}, {&upd7810_device::ORI_A_xx, 2,11,11,L0|L1}, + {&upd7810_device::RETS, 1,12,12,L0|L1}, {&upd7810_device::STM, 1, 6, 6,L0|L1}, + {&upd7810_device::MOV_B_A, 1, 6, 6,L0|L1}, {&upd7810_device::MOV_C_A, 1, 6, 6,L0|L1}, + {&upd7810_device::MOV_D_A, 1, 6, 6,L0|L1}, {&upd7810_device::MOV_E_A, 1, 6, 6,L0|L1}, + {&upd7810_device::MOV_H_A, 1, 6, 6,L0|L1}, {&upd7810_device::MOV_L_A, 1, 6, 6,L0|L1}, + + /* 0x20 - 0x3F */ + {&upd7810_device::INRW_wa_7801, 2,17,17,L0|L1}, {&upd7810_device::illegal, 1, 4, 4,L0|L1}, + {&upd7810_device::INX_DE, 1, 9, 9,L0|L1}, {&upd7810_device::DCX_DE, 1, 9, 9,L0|L1}, + {&upd7810_device::LXI_D_w, 3,16,16,L0|L1}, {&upd7810_device::GTIW_wa_xx, 3,19,19,L0|L1}, + {&upd7810_device::ADINC_A_xx, 2,11,11,L0|L1}, {&upd7810_device::GTI_A_xx, 2,11,11,L0|L1}, + {&upd7810_device::LDAW_wa, 2,14,14,L0|L1}, {&upd7810_device::LDAX_B, 1, 9, 9,L0|L1}, + {&upd7810_device::LDAX_D, 1, 9, 9,L0|L1}, {&upd7810_device::LDAX_H, 1, 9, 9,L0|L1}, + {&upd7810_device::LDAX_Dp, 1, 9, 9,L0|L1}, {&upd7810_device::LDAX_Hp, 1, 9, 9,L0|L1}, + {&upd7810_device::LDAX_Dm, 1, 9, 9,L0|L1}, {&upd7810_device::LDAX_Hm, 1, 9, 9,L0|L1}, + + {&upd7810_device::DCRW_wa_7801, 2,17,17,L0|L1}, {&upd7810_device::illegal, 1, 4, 4,L0|L1}, + {&upd7810_device::INX_HL, 1, 9, 9,L0|L1}, {&upd7810_device::DCX_HL, 1, 9, 9,L0|L1}, + {&upd7810_device::LXI_H_w, 3,16,16, L1}, {&upd7810_device::LTIW_wa_xx, 3,19,19,L0|L1}, + {&upd7810_device::SUINB_A_xx, 2,11,11,L0|L1}, {&upd7810_device::LTI_A_xx, 2,11,11,L0|L1}, + {&upd7810_device::STAW_wa, 2,14,14,L0|L1}, {&upd7810_device::STAX_B, 1, 9, 9,L0|L1}, + {&upd7810_device::STAX_D, 1, 9, 9,L0|L1}, {&upd7810_device::STAX_H, 1, 9, 9,L0|L1}, + {&upd7810_device::STAX_Dp, 1, 9, 9,L0|L1}, {&upd7810_device::STAX_Hp, 1, 9, 9,L0|L1}, + {&upd7810_device::STAX_Dm, 1, 9, 9,L0|L1}, {&upd7810_device::STAX_Hm, 1, 9, 9,L0|L1}, + + /* 0x40 - 0x5F */ + {&upd7810_device::illegal, 1, 6, 6,L0|L1}, {&upd7810_device::INR_A_7801, 1, 6, 6,L0|L1}, + {&upd7810_device::INR_B_7801, 1, 6, 6,L0|L1}, {&upd7810_device::INR_C_7801, 1, 6, 6,L0|L1}, + {&upd7810_device::CALL_w, 3,22,22,L0|L1}, {&upd7810_device::ONIW_wa_xx, 3,19,19,L0|L1}, + {&upd7810_device::ADI_A_xx, 2,11,11,L0|L1}, {&upd7810_device::ONI_A_xx, 2,11,11,L0|L1}, + {&upd7810_device::PRE_48, 1, 0, 0,L0|L1}, {&upd7810_device::illegal, 1, 6, 6,L0|L1}, + {&upd7810_device::illegal, 1, 6, 6,L0|L1}, {&upd7810_device::illegal, 1, 6, 6,L0|L1}, + {&upd7810_device::PRE_4C, 1, 0, 0,L0|L1}, {&upd7810_device::PRE_4D, 1, 0, 0,L0|L1}, + {&upd7810_device::JRE, 2,17,17,L0|L1}, {&upd7810_device::JRE, 2,17,17,L0|L1}, + + {&upd7810_device::illegal, 1, 6, 6,L0|L1}, {&upd7810_device::DCR_A_7801, 1, 6, 6,L0|L1}, + {&upd7810_device::DCR_B_7801, 1, 6, 6,L0|L1}, {&upd7810_device::DCR_C_7801, 1, 6, 6,L0|L1}, + {&upd7810_device::JMP_w, 3,16,16,L0|L1}, {&upd7810_device::OFFIW_wa_xx, 3,19,19,L0|L1}, + {&upd7810_device::ACI_A_xx, 2,11,11,L0|L1}, {&upd7810_device::OFFI_A_xx, 2,11,11,L0|L1}, + {&upd7810_device::illegal, 1, 6, 6,L0|L1}, {&upd7810_device::illegal, 1, 6, 6,L0|L1}, + {&upd7810_device::illegal, 1, 6, 6,L0|L1}, {&upd7810_device::illegal, 1, 6, 6,L0|L1}, + {&upd7810_device::illegal, 1, 6, 6,L0|L1}, {&upd7810_device::illegal, 1, 6, 6,L0|L1}, + {&upd7810_device::illegal, 1, 6, 6,L0|L1}, {&upd7810_device::illegal, 1, 6, 6,L0|L1}, + + /* 0x60 - 0x7F */ + {&upd7810_device::PRE_60, 1, 0, 0,L0|L1}, {&upd7810_device::DAA, 1, 6, 6,L0|L1}, + {&upd7810_device::RETI, 1,15,15,L0|L1}, {&upd7810_device::CALB, 2,13,13,L0|L1}, + {&upd7810_device::PRE_64, 1, 0, 0,L0|L1}, {&upd7810_device::NEIW_wa_xx, 3,19,19,L0|L1}, + {&upd7810_device::SUI_A_xx, 2,11,11,L0|L1}, {&upd7810_device::NEI_A_xx, 2,11,11,L0|L1}, + {&upd7810_device::illegal, 1, 6, 6,L0|L1}, {&upd7810_device::MVI_A_xx, 2,11,11,L0 }, + {&upd7810_device::MVI_B_xx, 2,11,11,L0|L1}, {&upd7810_device::MVI_C_xx, 2,11,11,L0|L1}, + {&upd7810_device::MVI_D_xx, 2,11,11,L0|L1}, {&upd7810_device::MVI_E_xx, 2,11,11,L0|L1}, + {&upd7810_device::MVI_H_xx, 2,11,11,L0|L1}, {&upd7810_device::MVI_L_xx, 2,11,11, L1}, + + {&upd7810_device::PRE_70, 1, 0, 0,L0|L1}, {&upd7810_device::MVIW_wa_xx, 3,13,13,L0|L1}, + {&upd7810_device::SOFTI, 1,19,19,L0|L1}, {&upd7810_device::JB, 1, 6, 6,L0|L1}, + {&upd7810_device::PRE_74, 1, 0, 0,L0|L1}, {&upd7810_device::EQIW_wa_xx, 3,19,19,L0|L1}, + {&upd7810_device::SBI_A_xx, 2,11,11,L0|L1}, {&upd7810_device::EQI_A_xx, 2,11,11,L0|L1}, + {&upd7810_device::CALF, 2,17,17,L0|L1}, {&upd7810_device::CALF, 2,17,17,L0|L1}, + {&upd7810_device::CALF, 2,17,17,L0|L1}, {&upd7810_device::CALF, 2,17,17,L0|L1}, + {&upd7810_device::CALF, 2,17,17,L0|L1}, {&upd7810_device::CALF, 2,17,17,L0|L1}, + {&upd7810_device::CALF, 2,17,17,L0|L1}, {&upd7810_device::CALF, 2,17,17,L0|L1}, + + /* 0x80 - 0x9F */ + {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, + {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, + {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, + {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, + {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, + {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, + {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, + {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, + + {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, + {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, + {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, + {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, + {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, + {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, + {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, + {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, + + /* 0xA0 - 0xBF */ + {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, + {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, + {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, + {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, + {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, + {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, + {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, + {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, + + {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, + {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, + {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, + {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, + {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, + {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, + {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, + {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, {&upd7810_device::CALT_7801, 1,19,19,L0|L1}, + + /* 0xC0 - 0xDF */ + {&upd7810_device::JR, 1,12,12,L0|L1}, {&upd7810_device::JR, 1,12,12,L0|L1}, + {&upd7810_device::JR, 1,12,12,L0|L1}, {&upd7810_device::JR, 1,12,12,L0|L1}, + {&upd7810_device::JR, 1,12,12,L0|L1}, {&upd7810_device::JR, 1,12,12,L0|L1}, + {&upd7810_device::JR, 1,12,12,L0|L1}, {&upd7810_device::JR, 1,12,12,L0|L1}, + {&upd7810_device::JR, 1,12,12,L0|L1}, {&upd7810_device::JR, 1,12,12,L0|L1}, + {&upd7810_device::JR, 1,12,12,L0|L1}, {&upd7810_device::JR, 1,12,12,L0|L1}, + {&upd7810_device::JR, 1,12,12,L0|L1}, {&upd7810_device::JR, 1,12,12,L0|L1}, + {&upd7810_device::JR, 1,12,12,L0|L1}, {&upd7810_device::JR, 1,12,12,L0|L1}, + + {&upd7810_device::JR, 1,12,12,L0|L1}, {&upd7810_device::JR, 1,12,12,L0|L1}, + {&upd7810_device::JR, 1,12,12,L0|L1}, {&upd7810_device::JR, 1,12,12,L0|L1}, + {&upd7810_device::JR, 1,12,12,L0|L1}, {&upd7810_device::JR, 1,12,12,L0|L1}, + {&upd7810_device::JR, 1,12,12,L0|L1}, {&upd7810_device::JR, 1,12,12,L0|L1}, + {&upd7810_device::JR, 1,12,12,L0|L1}, {&upd7810_device::JR, 1,12,12,L0|L1}, + {&upd7810_device::JR, 1,12,12,L0|L1}, {&upd7810_device::JR, 1,12,12,L0|L1}, + {&upd7810_device::JR, 1,12,12,L0|L1}, {&upd7810_device::JR, 1,12,12,L0|L1}, + {&upd7810_device::JR, 1,12,12,L0|L1}, {&upd7810_device::JR, 1,12,12,L0|L1}, + + /* 0xE0 - 0xFF */ + {&upd7810_device::JR, 1,12,12,L0|L1}, {&upd7810_device::JR, 1,12,12,L0|L1}, + {&upd7810_device::JR, 1,12,12,L0|L1}, {&upd7810_device::JR, 1,12,12,L0|L1}, + {&upd7810_device::JR, 1,12,12,L0|L1}, {&upd7810_device::JR, 1,12,12,L0|L1}, + {&upd7810_device::JR, 1,12,12,L0|L1}, {&upd7810_device::JR, 1,12,12,L0|L1}, + {&upd7810_device::JR, 1,12,12,L0|L1}, {&upd7810_device::JR, 1,12,12,L0|L1}, + {&upd7810_device::JR, 1,12,12,L0|L1}, {&upd7810_device::JR, 1,12,12,L0|L1}, + {&upd7810_device::JR, 1,12,12,L0|L1}, {&upd7810_device::JR, 1,12,12,L0|L1}, + {&upd7810_device::JR, 1,12,12,L0|L1}, {&upd7810_device::JR, 1,12,12,L0|L1}, + + {&upd7810_device::JR, 1,12,12,L0|L1}, {&upd7810_device::JR, 1,12,12,L0|L1}, + {&upd7810_device::JR, 1,12,12,L0|L1}, {&upd7810_device::JR, 1,12,12,L0|L1}, + {&upd7810_device::JR, 1,12,12,L0|L1}, {&upd7810_device::JR, 1,12,12,L0|L1}, + {&upd7810_device::JR, 1,12,12,L0|L1}, {&upd7810_device::JR, 1,12,12,L0|L1}, + {&upd7810_device::JR, 1,12,12,L0|L1}, {&upd7810_device::JR, 1,12,12,L0|L1}, + {&upd7810_device::JR, 1,12,12,L0|L1}, {&upd7810_device::JR, 1,12,12,L0|L1}, + {&upd7810_device::JR, 1,12,12,L0|L1}, {&upd7810_device::JR, 1,12,12,L0|L1}, + {&upd7810_device::JR, 1,12,12,L0|L1}, {&upd7810_device::JR, 1,12,12,L0|L1} +}; diff --git a/src/devices/cpu/v30mz/v30mz.c b/src/devices/cpu/v30mz/v30mz.c new file mode 100644 index 00000000000..3bc7c28236a --- /dev/null +++ b/src/devices/cpu/v30mz/v30mz.c @@ -0,0 +1,3732 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol,Bryan McPhail +/**************************************************************************** + + NEC V20/V30/V33 emulator modified to a v30mz emulator + + (Re)Written June-September 2000 by Bryan McPhail (mish@tendril.co.uk) based + on code by Oliver Bergmann (Raul_Bloodworth@hotmail.com) who based code + on the i286 emulator by Fabrice Frances which had initial work based on + David Hedley's pcemu(!). + + This new core features 99% accurate cycle counts for each processor, + there are still some complex situations where cycle counts are wrong, + typically where a few instructions have differing counts for odd/even + source and odd/even destination memory operands. + + Flag settings are also correct for the NEC processors rather than the + I86 versions. + + Changelist: + + 22/02/2003: + Removed cycle counts from memory accesses - they are certainly wrong, + and there is already a memory access cycle penalty in the opcodes + using them. + + Fixed save states. + + Fixed ADJBA/ADJBS/ADJ4A/ADJ4S flags/return values for all situations. + (Fixes bugs in Geostorm and Thunderblaster) + + Fixed carry flag on NEG (I thought this had been fixed circa Mame 0.58, + but it seems I never actually submitted the fix). + + Fixed many cycle counts in instructions and bug in cycle count + macros (odd word cases were testing for odd instruction word address + not data address). + + Todo! + Double check cycle timing is 100%. + Fix memory interface (should be 16 bit). + +****************************************************************************/ + +#include "emu.h" +#include "debugger.h" +#include "v30mz.h" + + +enum SREGS { ES=0, CS, SS, DS }; +enum WREGS { AW=0, CW, DW, BW, SP, BP, IX, IY }; + +#define NEC_NMI_INT_VECTOR 2 + +enum BREGS { + AL = NATIVE_ENDIAN_VALUE_LE_BE(0x0, 0x1), + AH = NATIVE_ENDIAN_VALUE_LE_BE(0x1, 0x0), + CL = NATIVE_ENDIAN_VALUE_LE_BE(0x2, 0x3), + CH = NATIVE_ENDIAN_VALUE_LE_BE(0x3, 0x2), + DL = NATIVE_ENDIAN_VALUE_LE_BE(0x4, 0x5), + DH = NATIVE_ENDIAN_VALUE_LE_BE(0x5, 0x4), + BL = NATIVE_ENDIAN_VALUE_LE_BE(0x6, 0x7), + BH = NATIVE_ENDIAN_VALUE_LE_BE(0x7, 0x6), + SPL = NATIVE_ENDIAN_VALUE_LE_BE(0x8, 0x9), + SPH = NATIVE_ENDIAN_VALUE_LE_BE(0x9, 0x8), + BPL = NATIVE_ENDIAN_VALUE_LE_BE(0xa, 0xb), + BPH = NATIVE_ENDIAN_VALUE_LE_BE(0xb, 0xa), + IXL = NATIVE_ENDIAN_VALUE_LE_BE(0xc, 0xd), + IXH = NATIVE_ENDIAN_VALUE_LE_BE(0xd, 0xc), + IYL = NATIVE_ENDIAN_VALUE_LE_BE(0xe, 0xf), + IYH = NATIVE_ENDIAN_VALUE_LE_BE(0xf, 0xe) +}; + + +#define CF (m_CarryVal!=0) +#define SF (m_SignVal<0) +#define ZF (m_ZeroVal==0) +#define PF m_parity_table[(UINT8)m_ParityVal] +#define AF (m_AuxVal!=0) +#define OF (m_OverVal!=0) +#define MD (m_MF!=0) + + +/***************************************************************************/ +/* cpu state */ +/***************************************************************************/ + + +/* The interrupt number of a pending external interrupt pending NMI is 2. */ +/* For INTR interrupts, the level is caught on the bus during an INTA cycle */ + +#define INT_IRQ 0x01 +#define NMI_IRQ 0x02 + +/***************************************************************************/ + +const device_type V30MZ = &device_creator; + + +v30mz_cpu_device::v30mz_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : cpu_device(mconfig, V30MZ, "V30MZ", tag, owner, clock, "v30mz", __FILE__) + , m_program_config("program", ENDIANNESS_LITTLE, 8, 20, 0) + , m_io_config("io", ENDIANNESS_LITTLE, 8, 16, 0) + , m_ip(0) + , m_TF(0) + , m_int_vector(0) + , m_pc(0) +{ + static const BREGS reg_name[8]={ AL, CL, DL, BL, AH, CH, DH, BH }; + + /* Set up parity lookup table. */ + for (UINT16 i = 0;i < 256; i++) + { + UINT16 c = 0; + for (UINT16 j = i; j > 0; j >>= 1) + { + if (j & 1) c++; + } + m_parity_table[i] = !(c & 1); + } + + for (UINT16 i = 0; i < 256; i++) + { + m_Mod_RM.reg.b[i] = reg_name[(i & 0x38) >> 3]; + m_Mod_RM.reg.w[i] = (WREGS) ( (i & 0x38) >> 3) ; + } + + for (UINT16 i = 0xc0; i < 0x100; i++) + { + m_Mod_RM.RM.w[i] = (WREGS)( i & 7 ); + m_Mod_RM.RM.b[i] = (BREGS)reg_name[i & 7]; + } + + memset(&m_regs, 0x00, sizeof(m_regs)); +} + + +void v30mz_cpu_device::device_start() +{ + m_program = &space(AS_PROGRAM); + m_direct = &m_program->direct(); + m_io = &space(AS_IO); + + save_item(NAME(m_regs.w)); + save_item(NAME(m_sregs)); + save_item(NAME(m_ip)); + save_item(NAME(m_TF)); + save_item(NAME(m_IF)); + save_item(NAME(m_DF)); + save_item(NAME(m_MF)); + save_item(NAME(m_SignVal)); + save_item(NAME(m_int_vector)); + save_item(NAME(m_pending_irq)); + save_item(NAME(m_nmi_state)); + save_item(NAME(m_irq_state)); + save_item(NAME(m_AuxVal)); + save_item(NAME(m_OverVal)); + save_item(NAME(m_ZeroVal)); + save_item(NAME(m_CarryVal)); + save_item(NAME(m_ParityVal)); + save_item(NAME(m_seg_prefix)); + save_item(NAME(m_seg_prefix_next)); + + // Register state for debugger +// state_add( NEC_PC, "PC", m_PC ).callimport().callexport().formatstr("%04X"); + state_add( NEC_IP, "IP", m_ip ).callimport().callexport().formatstr("%04X"); + state_add( NEC_SP, "SP", m_regs.w[SP] ).callimport().callexport().formatstr("%04X"); + state_add( NEC_AW, "AW", m_regs.w[AW] ).callimport().callexport().formatstr("%04X"); + state_add( NEC_CW, "CW", m_regs.w[CS] ).callimport().callexport().formatstr("%04X"); + state_add( NEC_DW, "DW", m_regs.w[DW] ).callimport().callexport().formatstr("%04X"); + state_add( NEC_BW, "BW", m_regs.w[BW] ).callimport().callexport().formatstr("%04X"); + state_add( NEC_BP, "BP", m_regs.w[BP] ).callimport().callexport().formatstr("%04X"); + state_add( NEC_IX, "IX", m_regs.w[IX] ).callimport().callexport().formatstr("%04X"); + state_add( NEC_IY, "IY", m_regs.w[IY] ).callimport().callexport().formatstr("%04X"); + state_add( NEC_ES, "ES", m_sregs[ES] ).callimport().callexport().formatstr("%04X"); + state_add( NEC_CS, "CS", m_sregs[CS] ).callimport().callexport().formatstr("%04X"); + state_add( NEC_SS, "SS", m_sregs[SS] ).callimport().callexport().formatstr("%04X"); + state_add( NEC_DS, "DS", m_sregs[DS] ).callimport().callexport().formatstr("%04X"); + state_add( NEC_VECTOR, "V", m_int_vector).callimport().callexport().formatstr("%02X"); + + state_add(STATE_GENPC, "curpc", m_pc).callimport().callexport().formatstr("%05X"); + state_add(STATE_GENFLAGS, "GENFLAGS", m_TF).callimport().callexport().formatstr("%16s").noshow(); + + m_icountptr = &m_icount; +} + + +void v30mz_cpu_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + switch (entry.index()) + { + case STATE_GENPC: + strprintf(str, "%08X", pc()); + break; + + case STATE_GENFLAGS: + { + UINT16 flags = CompressFlags(); + strprintf(str, "%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c", + flags & 0x8000 ? 'M':'.', + flags & 0x4000 ? '?':'.', + flags & 0x2000 ? '?':'.', + flags & 0x1000 ? '?':'.', + flags & 0x0800 ? 'O':'.', + flags & 0x0400 ? 'D':'.', + flags & 0x0200 ? 'I':'.', + flags & 0x0100 ? 'T':'.', + flags & 0x0080 ? 'S':'.', + flags & 0x0040 ? 'Z':'.', + flags & 0x0020 ? '?':'.', + flags & 0x0010 ? 'A':'.', + flags & 0x0008 ? '?':'.', + flags & 0x0004 ? 'P':'.', + flags & 0x0002 ? 'N':'.', + flags & 0x0001 ? 'C':'.'); + } + break; + } +} + + +void v30mz_cpu_device::device_reset() +{ + m_ZeroVal = 1; + m_ParityVal = 1; + m_regs.w[AW] = 0; + m_regs.w[CW] = 0; + m_regs.w[DW] = 0; + m_regs.w[BW] = 0; + m_regs.w[SP] = 0; + m_regs.w[BP] = 0; + m_regs.w[IX] = 0; + m_regs.w[IY] = 0; + m_sregs[ES] = 0; + m_sregs[CS] = 0xffff; + m_sregs[SS] = 0; + m_sregs[DS] = 0; + m_ip = 0; + m_SignVal = 0; + m_AuxVal = 0; + m_OverVal = 0; + m_CarryVal = 0; + m_TF = 0; + m_IF = 0; + m_DF = 0; + m_MF = 1; + m_int_vector = 0; + m_pending_irq = 0; + m_nmi_state = 0; + m_irq_state = 0; + m_no_interrupt = 0; + m_fire_trap = 0; + m_prefix_base = 0; + m_seg_prefix = false; + m_seg_prefix_next = false; + m_ea = 0; + m_eo = 0; + m_e16 = 0; + m_modrm = 0; + m_dst = 0; + m_src = 0; +} + + +inline UINT32 v30mz_cpu_device::pc() +{ + m_pc = ( m_sregs[CS] << 4 ) + m_ip; + return m_pc; +} + + +inline UINT8 v30mz_cpu_device::read_byte(UINT32 addr) +{ + return m_program->read_byte(addr); +} + + +inline UINT16 v30mz_cpu_device::read_word(UINT32 addr) +{ + return m_program->read_byte(addr) | ( m_program->read_byte(addr+1) << 8 ); +} + + +inline void v30mz_cpu_device::write_byte(UINT32 addr, UINT8 data) +{ + m_program->write_byte(addr, data); +} + + +inline void v30mz_cpu_device::write_word(UINT32 addr, UINT16 data) +{ + m_program->write_byte( addr, data & 0xff ); + m_program->write_byte( addr + 1, data >> 8 ); +} + + +inline UINT8 v30mz_cpu_device::read_port(UINT16 port) +{ + return m_io->read_byte(port); +} + + +inline void v30mz_cpu_device::write_port(UINT16 port, UINT8 data) +{ + m_io->write_byte(port, data); +} + + +inline UINT8 v30mz_cpu_device::fetch_op() +{ + UINT8 data = m_direct->read_byte( pc() ); + m_ip++; + return data; +} + + +inline UINT8 v30mz_cpu_device::fetch() +{ + UINT8 data = m_direct->read_byte( pc() ); + m_ip++; + return data; +} + + +inline UINT16 v30mz_cpu_device::fetch_word() +{ + UINT16 data = fetch(); + data |= ( fetch() << 8 ); + return data; +} + + +inline UINT8 v30mz_cpu_device::repx_op() +{ + UINT8 next = fetch_op(); + bool seg_prefix = false; + int seg = 0; + + switch (next) + { + case 0x26: + seg_prefix = true; + seg = ES; + break; + case 0x2e: + seg_prefix = true; + seg = CS; + break; + case 0x36: + seg_prefix = true; + seg = SS; + break; + case 0x3e: + seg_prefix = true; + seg = DS; + break; + } + + if ( seg_prefix ) + { + m_seg_prefix = true; + m_seg_prefix_next = true; + m_prefix_base = m_sregs[seg] << 4; + next = fetch_op(); + CLK(2); + } + + return next; +} + + +inline void v30mz_cpu_device::CLK(UINT32 cycles) +{ + m_icount -= cycles; +} + + +inline void v30mz_cpu_device::CLKM(UINT32 cycles_reg, UINT32 cycles_mem) +{ + m_icount -= ( m_modrm >= 0xc0 ) ? cycles_reg : cycles_mem; +} + + +inline UINT32 v30mz_cpu_device::default_base(int seg) +{ + if ( m_seg_prefix && (seg==DS || seg==SS) ) + { + return m_prefix_base; + } + else + { + return m_sregs[seg] << 4; + } +} + + +inline UINT32 v30mz_cpu_device::get_ea() +{ + switch( m_modrm & 0xc7 ) + { + case 0x00: + m_eo = m_regs.w[BW] + m_regs.w[IX]; + m_ea = default_base(DS) + m_eo; + break; + case 0x01: + m_eo = m_regs.w[BW] + m_regs.w[IY]; + m_ea = default_base(DS) + m_eo; + break; + case 0x02: + m_eo = m_regs.w[BP] + m_regs.w[IX]; + m_ea = default_base(SS) + m_eo; + break; + case 0x03: + m_eo = m_regs.w[BP] + m_regs.w[IY]; + m_ea = default_base(SS) + m_eo; + break; + case 0x04: + m_eo = m_regs.w[IX]; + m_ea = default_base(DS) + m_eo; + break; + case 0x05: + m_eo = m_regs.w[IY]; + m_ea = default_base(DS) + m_eo; + break; + case 0x06: + m_eo = fetch_word(); + m_ea = default_base(DS) + m_eo; + break; + case 0x07: + m_eo = m_regs.w[BW]; + m_ea = default_base(DS) + m_eo; + break; + + case 0x40: + m_eo = m_regs.w[BW] + m_regs.w[IX] + (INT8)fetch(); + m_ea = default_base(DS) + m_eo; + break; + case 0x41: + m_eo = m_regs.w[BW] + m_regs.w[IY] + (INT8)fetch(); + m_ea = default_base(DS) + m_eo; + break; + case 0x42: + m_eo = m_regs.w[BP] + m_regs.w[IX] + (INT8)fetch(); + m_ea = default_base(SS) + m_eo; + break; + case 0x43: + m_eo = m_regs.w[BP] + m_regs.w[IY] + (INT8)fetch(); + m_ea = default_base(SS) + m_eo; + break; + case 0x44: + m_eo = m_regs.w[IX] + (INT8)fetch(); + m_ea = default_base(DS) + m_eo; + break; + case 0x45: + m_eo = m_regs.w[IY] + (INT8)fetch(); + m_ea = default_base(DS) + m_eo; + break; + case 0x46: + m_eo = m_regs.w[BP] + (INT8)fetch(); + m_ea = default_base(SS) + m_eo; + break; + case 0x47: + m_eo = m_regs.w[BW] + (INT8)fetch(); + m_ea = default_base(DS) + m_eo; + break; + + case 0x80: + m_e16 = fetch_word(); + m_eo = m_regs.w[BW] + m_regs.w[IX] + (INT16)m_e16; + m_ea = default_base(DS) + m_eo; + break; + case 0x81: + m_e16 = fetch_word(); + m_eo = m_regs.w[BW] + m_regs.w[IY] + (INT16)m_e16; + m_ea = default_base(DS) + m_eo; + break; + case 0x82: + m_e16 = fetch_word(); + m_eo = m_regs.w[BP] + m_regs.w[IX] + (INT16)m_e16; + m_ea = default_base(SS) + m_eo; + break; + case 0x83: + m_e16 = fetch_word(); + m_eo = m_regs.w[BP] + m_regs.w[IY] + (INT16)m_e16; + m_ea = default_base(SS) + m_eo; + break; + case 0x84: + m_e16 = fetch_word(); + m_eo = m_regs.w[IX] + (INT16)m_e16; + m_ea = default_base(DS) + m_eo; + break; + case 0x85: + m_e16 = fetch_word(); + m_eo = m_regs.w[IY] + (INT16)m_e16; + m_ea = default_base(DS) + m_eo; + break; + case 0x86: + m_e16 = fetch_word(); + m_eo = m_regs.w[BP] + (INT16)m_e16; + m_ea = default_base(SS) + m_eo; + break; + case 0x87: + m_e16 = fetch_word(); + m_eo = m_regs.w[BW] + (INT16)m_e16; + m_ea = default_base(DS) + m_eo; + break; + } + + return m_ea; +} + + +inline void v30mz_cpu_device::PutbackRMByte(UINT8 data) +{ + if ( m_modrm >= 0xc0 ) + { + m_regs.b[ m_Mod_RM.RM.b[ m_modrm ] ] = data; + } + else + { + write_byte( m_ea, data ); + } +} + + +inline void v30mz_cpu_device::PutbackRMWord(UINT16 data) +{ + if ( m_modrm >= 0xc0 ) + { + m_regs.w[ m_Mod_RM.RM.w[ m_modrm ] ] = data; + } + else + { + write_word( m_ea, data ); + } +} + +inline void v30mz_cpu_device::PutImmRMWord() +{ + if ( m_modrm >= 0xc0 ) + { + m_regs.w[ m_Mod_RM.RM.w[ m_modrm ] ] = fetch_word(); + } + else + { + UINT32 addr = get_ea(); + write_word( addr, fetch_word() ); + } +} + +inline void v30mz_cpu_device::PutRMWord(UINT16 val) +{ + if ( m_modrm >= 0xc0 ) + { + m_regs.w[ m_Mod_RM.RM.w[ m_modrm ] ] = val; + } + else + { + write_word( get_ea(), val ); + } +} + + +inline void v30mz_cpu_device::PutRMByte(UINT8 val) +{ + if ( m_modrm >= 0xc0 ) + { + m_regs.b[ m_Mod_RM.RM.b[ m_modrm ] ] = val; + } + else + { + write_byte( get_ea(), val ); + } +} + + +inline void v30mz_cpu_device::PutImmRMByte() +{ + if ( m_modrm >= 0xc0 ) + { + m_regs.b[ m_Mod_RM.RM.b[ m_modrm ] ] = fetch(); + } + else + { + UINT32 addr = get_ea(); + write_byte( addr, fetch() ); + } +} + + +inline void v30mz_cpu_device::DEF_br8() +{ + m_modrm = fetch(); + m_src = RegByte(); + m_dst = GetRMByte(); +} + + +inline void v30mz_cpu_device::DEF_wr16() +{ + m_modrm = fetch(); + m_src = RegWord(); + m_dst = GetRMWord(); +} + + +inline void v30mz_cpu_device::DEF_r8b() +{ + m_modrm = fetch(); + m_dst = RegByte(); + m_src = GetRMByte(); +} + + +inline void v30mz_cpu_device::DEF_r16w() +{ + m_modrm = fetch(); + m_dst = RegWord(); + m_src = GetRMWord(); +} + + +inline void v30mz_cpu_device::DEF_ald8() +{ + m_src = fetch(); + m_dst = m_regs.b[AL]; +} + + +inline void v30mz_cpu_device::DEF_axd16() +{ + m_src = fetch_word(); + m_dst = m_regs.w[AW]; +} + + + +inline void v30mz_cpu_device::RegByte(UINT8 data) +{ + m_regs.b[ m_Mod_RM.reg.b[ m_modrm ] ] = data; +} + + +inline void v30mz_cpu_device::RegWord(UINT16 data) +{ + m_regs.w[ m_Mod_RM.reg.w[ m_modrm ] ] = data; +} + + +inline UINT8 v30mz_cpu_device::RegByte() +{ + return m_regs.b[ m_Mod_RM.reg.b[ m_modrm ] ]; +} + + +inline UINT16 v30mz_cpu_device::RegWord() +{ + return m_regs.w[ m_Mod_RM.reg.w[ m_modrm ] ]; +} + + +inline UINT16 v30mz_cpu_device::GetRMWord() +{ + if ( m_modrm >= 0xc0 ) + { + return m_regs.w[ m_Mod_RM.RM.w[ m_modrm ] ]; + } + else + { + return read_word( get_ea() ); + } +} + + +inline UINT16 v30mz_cpu_device::GetnextRMWord() +{ + UINT32 addr = ( m_ea & 0xf0000 ) | ( ( m_ea + 2 ) & 0xffff ); + + return read_word( addr ); +} + + +inline UINT8 v30mz_cpu_device::GetRMByte() +{ + if ( m_modrm >= 0xc0 ) + { + return m_regs.b[ m_Mod_RM.RM.b[ m_modrm ] ]; + } + else + { + return read_byte( get_ea() ); + } +} + + +inline void v30mz_cpu_device::PutMemB(int seg, UINT16 offset, UINT8 data) +{ + write_byte( default_base( seg ) + offset, data); +} + + +inline void v30mz_cpu_device::PutMemW(int seg, UINT16 offset, UINT16 data) +{ + PutMemB( seg, offset, data & 0xff); + PutMemB( seg, offset+1, data >> 8); +} + + +inline UINT8 v30mz_cpu_device::GetMemB(int seg, UINT16 offset) +{ + return read_byte( default_base(seg) + offset ); +} + + +inline UINT16 v30mz_cpu_device::GetMemW(int seg, UINT16 offset) +{ + return GetMemB(seg, offset) | ( GetMemB(seg, offset + 1) << 8 ); +} + + +// Setting flags + +inline void v30mz_cpu_device::set_CFB(UINT32 x) +{ + m_CarryVal = x & 0x100; +} + +inline void v30mz_cpu_device::set_CFW(UINT32 x) +{ + m_CarryVal = x & 0x10000; +} + +inline void v30mz_cpu_device::set_AF(UINT32 x,UINT32 y,UINT32 z) +{ + m_AuxVal = (x ^ (y ^ z)) & 0x10; +} + +inline void v30mz_cpu_device::set_SF(UINT32 x) +{ + m_SignVal = x; +} + +inline void v30mz_cpu_device::set_ZF(UINT32 x) +{ + m_ZeroVal = x; +} + +inline void v30mz_cpu_device::set_PF(UINT32 x) +{ + m_ParityVal = x; +} + +inline void v30mz_cpu_device::set_SZPF_Byte(UINT32 x) +{ + m_SignVal = m_ZeroVal = m_ParityVal = (INT8)x; +} + +inline void v30mz_cpu_device::set_SZPF_Word(UINT32 x) +{ + m_SignVal = m_ZeroVal = m_ParityVal = (INT16)x; +} + +inline void v30mz_cpu_device::set_OFW_Add(UINT32 x,UINT32 y,UINT32 z) +{ + m_OverVal = (x ^ y) & (x ^ z) & 0x8000; +} + +inline void v30mz_cpu_device::set_OFB_Add(UINT32 x,UINT32 y,UINT32 z) +{ + m_OverVal = (x ^ y) & (x ^ z) & 0x80; +} + +inline void v30mz_cpu_device::set_OFW_Sub(UINT32 x,UINT32 y,UINT32 z) +{ + m_OverVal = (z ^ y) & (z ^ x) & 0x8000; +} + +inline void v30mz_cpu_device::set_OFB_Sub(UINT32 x,UINT32 y,UINT32 z) +{ + m_OverVal = (z ^ y) & (z ^ x) & 0x80; +} + + +inline UINT16 v30mz_cpu_device::CompressFlags() +{ + return (CF ? 1 : 0) + | (PF ? 4 : 0) + | (AF ? 0x10 : 0) + | (ZF ? 0x40 : 0) + | (SF ? 0x80 : 0) + | (m_TF << 8) + | (m_IF << 9) + | (m_DF << 10) + | (OF << 11) + | (MD << 15); +} + +inline void v30mz_cpu_device::ExpandFlags(UINT16 f) +{ + m_CarryVal = (f) & 1; + m_ParityVal = !((f) & 4); + m_AuxVal = (f) & 16; + m_ZeroVal = !((f) & 64); + m_SignVal = (f) & 128 ? -1 : 0; + m_TF = ((f) & 256) == 256; + m_IF = ((f) & 512) == 512; + m_DF = ((f) & 1024) == 1024; + m_OverVal = (f) & 2048; + m_MF = ((f) & 0x8000) == 0x8000; +} + +inline void v30mz_cpu_device::i_insb() +{ + PutMemB( ES, m_regs.w[IY], read_port( m_regs.w[DW] ) ); + m_regs.w[IY] += -2 * m_DF + 1; + CLK(6); +} + +inline void v30mz_cpu_device::i_insw() +{ + PutMemB( ES, m_regs.w[IY], read_port( m_regs.w[DW] ) ); + PutMemB( ES, (m_regs.w[IY] + 1) & 0xffff, read_port((m_regs.w[DW]+1)&0xffff)); + m_regs.w[IY] += -4 * m_DF + 2; + CLK(6); +} + +inline void v30mz_cpu_device::i_outsb() +{ + write_port( m_regs.w[DW], GetMemB( DS, m_regs.w[IX] ) ); + m_regs.w[IX] += -2 * m_DF + 1; + CLK(7); +} + +inline void v30mz_cpu_device::i_outsw() +{ + write_port( m_regs.w[DW], GetMemB( DS, m_regs.w[IX] ) ); + write_port( (m_regs.w[DW]+1)&0xffff, GetMemB( DS, (m_regs.w[IX]+1)&0xffff ) ); + m_regs.w[IX] += -4 * m_DF + 2; + CLK(7); +} + +inline void v30mz_cpu_device::i_movsb() +{ + UINT8 tmp = GetMemB( DS, m_regs.w[IX] ); + PutMemB( ES, m_regs.w[IY], tmp); + m_regs.w[IY] += -2 * m_DF + 1; + m_regs.w[IX] += -2 * m_DF + 1; + CLK(5); +} + +inline void v30mz_cpu_device::i_movsw() +{ + UINT16 tmp = GetMemW( DS, m_regs.w[IX] ); + PutMemW( ES, m_regs.w[IY], tmp ); + m_regs.w[IY] += -4 * m_DF + 2; + m_regs.w[IX] += -4 * m_DF + 2; + CLK(5); +} + +inline void v30mz_cpu_device::i_cmpsb() +{ + m_src = GetMemB( ES, m_regs.w[IY] ); + m_dst = GetMemB( DS, m_regs.w[IX] ); + SUBB(); + m_regs.w[IY] += -2 * m_DF + 1; + m_regs.w[IX] += -2 * m_DF + 1; + CLK(6); +} + +inline void v30mz_cpu_device::i_cmpsw() +{ + m_src = GetMemW( ES, m_regs.w[IY] ); + m_dst = GetMemW( DS, m_regs.w[IX] ); + SUBW(); + m_regs.w[IY] += -4 * m_DF + 2; + m_regs.w[IX] += -4 * m_DF + 2; + CLK(6); +} + +inline void v30mz_cpu_device::i_stosb() +{ + PutMemB( ES, m_regs.w[IY], m_regs.b[AL] ); + m_regs.w[IY] += -2 * m_DF + 1; + CLK(3); +} + +inline void v30mz_cpu_device::i_stosw() +{ + PutMemW( ES, m_regs.w[IY], m_regs.w[AW] ); + m_regs.w[IY] += -4 * m_DF + 2; + CLK(3); +} + +inline void v30mz_cpu_device::i_lodsb() +{ + m_regs.b[AL] = GetMemB( DS, m_regs.w[IX] ); + m_regs.w[IX] += -2 * m_DF + 1; + CLK(3); +} + +inline void v30mz_cpu_device::i_lodsw() +{ + m_regs.w[AW] = GetMemW( DS, m_regs.w[IX] ); + m_regs.w[IX] += -4 * m_DF + 2; + CLK(3); +} + +inline void v30mz_cpu_device::i_scasb() +{ + m_src = GetMemB( ES, m_regs.w[IY] ); + m_dst = m_regs.b[AL]; + SUBB(); + m_regs.w[IY] += -2 * m_DF + 1; + CLK(4); +} + +inline void v30mz_cpu_device::i_scasw() +{ + m_src = GetMemW( ES, m_regs.w[IY] ); + m_dst = m_regs.w[AW]; + SUBW(); + m_regs.w[IY] += -4 * m_DF + 2; + CLK(4); +} + + +inline void v30mz_cpu_device::i_popf() +{ + UINT32 tmp = POP(); + + ExpandFlags(tmp); + CLK(3); + if (m_TF) + { + m_fire_trap = 1; + } +} + + +inline void v30mz_cpu_device::ADDB() +{ + UINT32 res = m_dst + m_src; + + set_CFB(res); + set_OFB_Add(res,m_src,m_dst); + set_AF(res,m_src,m_dst); + set_SZPF_Byte(res); + m_dst = res & 0xff; +} + + +inline void v30mz_cpu_device::ADDW() +{ + UINT32 res = m_dst + m_src; + + set_CFW(res); + set_OFW_Add(res,m_src,m_dst); + set_AF(res,m_src,m_dst); + set_SZPF_Word(res); + m_dst = res & 0xffff; +} + + +inline void v30mz_cpu_device::SUBB() +{ + UINT32 res = m_dst - m_src; + + set_CFB(res); + set_OFB_Sub(res,m_src,m_dst); + set_AF(res,m_src,m_dst); + set_SZPF_Byte(res); + m_dst = res & 0xff; +} + + +inline void v30mz_cpu_device::SUBW() +{ + UINT32 res = m_dst - m_src; + + set_CFW(res); + set_OFW_Sub(res,m_src,m_dst); + set_AF(res,m_src,m_dst); + set_SZPF_Word(res); + m_dst = res & 0xffff; +} + + +inline void v30mz_cpu_device::ORB() +{ + m_dst |= m_src; + m_CarryVal = m_OverVal = m_AuxVal = 0; + set_SZPF_Byte(m_dst); +} + + +inline void v30mz_cpu_device::ORW() +{ + m_dst |= m_src; + m_CarryVal = m_OverVal = m_AuxVal = 0; + set_SZPF_Word(m_dst); +} + + +inline void v30mz_cpu_device::ANDB() +{ + m_dst &= m_src; + m_CarryVal = m_OverVal = m_AuxVal = 0; + set_SZPF_Byte(m_dst); +} + + +inline void v30mz_cpu_device::ANDW() +{ + m_dst &= m_src; + m_CarryVal = m_OverVal = m_AuxVal = 0; + set_SZPF_Word(m_dst); +} + + +inline void v30mz_cpu_device::XORB() +{ + m_dst ^= m_src; + m_CarryVal = m_OverVal = m_AuxVal = 0; + set_SZPF_Byte(m_dst); +} + + +inline void v30mz_cpu_device::XORW() +{ + m_dst ^= m_src; + m_CarryVal = m_OverVal = m_AuxVal = 0; + set_SZPF_Word(m_dst); +} + + +inline void v30mz_cpu_device::ROL_BYTE() +{ + m_CarryVal = m_dst & 0x80; + m_dst = (m_dst << 1) | ( CF ? 1 : 0 ); +} + +inline void v30mz_cpu_device::ROL_WORD() +{ + m_CarryVal = m_dst & 0x8000; + m_dst = (m_dst << 1) | ( CF ? 1 : 0 ); +} + +inline void v30mz_cpu_device::ROR_BYTE() +{ + m_CarryVal = m_dst & 0x1; + m_dst = (m_dst >> 1) | (CF ? 0x80 : 0x00); +} + +inline void v30mz_cpu_device::ROR_WORD() +{ + m_CarryVal = m_dst & 0x1; + m_dst = (m_dst >> 1) + (CF ? 0x8000 : 0x0000); +} + +inline void v30mz_cpu_device::ROLC_BYTE() +{ + m_dst = (m_dst << 1) | ( CF ? 1 : 0 ); + set_CFB(m_dst); +} + +inline void v30mz_cpu_device::ROLC_WORD() +{ + m_dst = (m_dst << 1) | ( CF ? 1 : 0 ); + set_CFW(m_dst); +} + +inline void v30mz_cpu_device::RORC_BYTE() +{ + m_dst |= ( CF ? 0x100 : 0x00); + m_CarryVal = m_dst & 0x01; + m_dst >>= 1; +} + +inline void v30mz_cpu_device::RORC_WORD() +{ + m_dst |= ( CF ? 0x10000 : 0); + m_CarryVal = m_dst & 0x01; + m_dst >>= 1; +} + +inline void v30mz_cpu_device::SHL_BYTE(UINT8 c) +{ + m_icount -= c; + m_dst <<= c; + set_CFB(m_dst); + set_SZPF_Byte(m_dst); + PutbackRMByte(m_dst); +} + +inline void v30mz_cpu_device::SHL_WORD(UINT8 c) +{ + m_icount -= c; + m_dst <<= c; + set_CFW(m_dst); + set_SZPF_Word(m_dst); + PutbackRMWord(m_dst); +} + +inline void v30mz_cpu_device::SHR_BYTE(UINT8 c) +{ + m_icount -= c; + m_dst >>= c-1; + m_CarryVal = m_dst & 0x1; + m_dst >>= 1; + set_SZPF_Byte(m_dst); + PutbackRMByte(m_dst); +} + +inline void v30mz_cpu_device::SHR_WORD(UINT8 c) +{ + m_icount -= c; + m_dst >>= c-1; + m_CarryVal = m_dst & 0x1; + m_dst >>= 1; + set_SZPF_Word(m_dst); + PutbackRMWord(m_dst); +} + +inline void v30mz_cpu_device::SHRA_BYTE(UINT8 c) +{ + m_icount -= c; + m_dst = ((INT8)m_dst) >> (c-1); + m_CarryVal = m_dst & 0x1; + m_dst = m_dst >> 1; + set_SZPF_Byte(m_dst); + PutbackRMByte(m_dst); +} + +inline void v30mz_cpu_device::SHRA_WORD(UINT8 c) +{ + m_icount -= c; + m_dst = ((INT16)m_dst) >> (c-1); + m_CarryVal = m_dst & 0x1; + m_dst = m_dst >> 1; + set_SZPF_Word(m_dst); + PutbackRMWord(m_dst); +} + + +inline void v30mz_cpu_device::XchgAWReg(UINT8 reg) +{ + UINT16 tmp = m_regs.w[reg]; + + m_regs.w[reg] = m_regs.w[AW]; + m_regs.w[AW] = tmp; +} + + +inline void v30mz_cpu_device::IncWordReg(UINT8 reg) +{ + UINT32 tmp = m_regs.w[reg]; + UINT32 tmp1 = tmp+1; + + m_OverVal = (tmp == 0x7fff); + set_AF(tmp1,tmp,1); + set_SZPF_Word(tmp1); + m_regs.w[reg] = tmp1; +} + + +inline void v30mz_cpu_device::DecWordReg(UINT8 reg) +{ + UINT32 tmp = m_regs.w[reg]; + UINT32 tmp1 = tmp-1; + + m_OverVal = (tmp == 0x8000); + set_AF(tmp1,tmp,1); + set_SZPF_Word(tmp1); + m_regs.w[reg] = tmp1; +} + + +inline void v30mz_cpu_device::PUSH(UINT16 data) +{ + m_regs.w[SP] -= 2; + write_word( ( m_sregs[SS] << 4 ) + m_regs.w[SP], data ); +} + + +inline UINT16 v30mz_cpu_device::POP() +{ + UINT16 data = read_word( ( m_sregs[SS] << 4 ) + m_regs.w[SP] ); + + m_regs.w[SP] += 2; + return data; +} + + +inline void v30mz_cpu_device::JMP(bool cond) +{ + int rel = (int)((INT8)fetch()); + + if (cond) + { + m_ip += rel; + CLK(9); + } + CLK(1); +} + + +inline void v30mz_cpu_device::ADJ4(INT8 param1,INT8 param2) +{ + if (AF || ((m_regs.b[AL] & 0xf) > 9)) + { + UINT16 tmp; + tmp = m_regs.b[AL] + param1; + m_regs.b[AL] = tmp; + m_AuxVal = 1; + m_CarryVal |= tmp & 0x100; + } + if (CF || (m_regs.b[AL]>0x9f)) + { + m_regs.b[AL] += param2; + m_CarryVal = 1; + } + set_SZPF_Byte(m_regs.b[AL]); +} + + +inline void v30mz_cpu_device::ADJB(INT8 param1, INT8 param2) +{ + if (AF || ((m_regs.b[AL] & 0xf) > 9)) + { + m_regs.b[AL] += param1; + m_regs.b[AH] += param2; + m_AuxVal = 1; + m_CarryVal = 1; + } + else + { + m_AuxVal = 0; + m_CarryVal = 0; + } + m_regs.b[AL] &= 0x0F; +} + + +void v30mz_cpu_device::interrupt(int int_num) +{ + PUSH( CompressFlags() ); + CLK(2); + m_TF = m_IF = 0; + + if (int_num == -1) + { + int_num = standard_irq_callback(0); + + m_irq_state = CLEAR_LINE; + m_pending_irq &= ~INT_IRQ; + } + + UINT16 dest_off = read_word( int_num * 4 + 0 ); + UINT16 dest_seg = read_word( int_num * 4 + 2 ); + + PUSH(m_sregs[CS]); + PUSH(m_ip); + m_ip = dest_off; + m_sregs[CS] = dest_seg; +} + + +void v30mz_cpu_device::execute_set_input( int inptnum, int state ) +{ + if (inptnum == INPUT_LINE_NMI) + { + if ( m_nmi_state == state ) + { + return; + } + m_nmi_state = state; + if (state != CLEAR_LINE) + { + m_pending_irq |= NMI_IRQ; + } + } + else + { + m_irq_state = state; + if (state == CLEAR_LINE) + { + m_pending_irq &= ~INT_IRQ; + } + else + { + m_pending_irq |= INT_IRQ; + } + } +} + + +offs_t v30mz_cpu_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( nec ); + return CPU_DISASSEMBLE_NAME(nec)(this, buffer, pc, oprom, opram, options); +} + + +void v30mz_cpu_device::execute_run() +{ + while(m_icount > 0 ) + { + if ( m_seg_prefix_next ) + { + m_seg_prefix = true; + m_seg_prefix_next = false; + } + else + { + m_seg_prefix = false; + + /* Dispatch IRQ */ + if ( m_pending_irq && m_no_interrupt == 0 ) + { + if ( m_pending_irq & NMI_IRQ ) + { + interrupt(NEC_NMI_INT_VECTOR); + m_pending_irq &= ~NMI_IRQ; + } + else if ( m_IF ) + { + /* the actual vector is retrieved after pushing flags */ + /* and clearing the IF */ + interrupt(-1); + } + } + + /* No interrupt allowed between last instruction and this one */ + if ( m_no_interrupt ) + { + m_no_interrupt--; + } + + /* trap should allow one instruction to be executed */ + if ( m_fire_trap ) + { + if ( m_fire_trap >= 2 ) + { + interrupt(1); + m_fire_trap = 0; + } + else + { + m_fire_trap++; + } + } + } + + debugger_instruction_hook( this, pc() ); + + UINT8 op = fetch_op(); + + switch(op) + { + case 0x00: // i_add_br8 + DEF_br8(); + ADDB(); + PutbackRMByte(m_dst); + CLKM(1,3); + break; + + case 0x01: // i_add_wr16 + DEF_wr16(); + ADDW(); + PutbackRMWord(m_dst); + CLKM(1,3); + break; + + case 0x02: // i_add_r8b + DEF_r8b(); + ADDB(); + RegByte(m_dst); + CLKM(1,2); + break; + + case 0x03: // i_add_r16w + DEF_r16w(); + ADDW(); + RegWord(m_dst); + CLKM(1,2); + break; + + case 0x04: // i_add_ald8 + DEF_ald8(); + ADDB(); + m_regs.b[AL] = m_dst; + CLK(1); + break; + + case 0x05: // i_add_axd16 + DEF_axd16(); + ADDW(); + m_regs.w[AW] = m_dst; + CLK(1); + break; + + case 0x06: // i_push_es + PUSH(m_sregs[ES]); + CLK(2); + break; + + case 0x07: // i_pop_es + m_sregs[ES] = POP(); + CLK(3); + break; + + case 0x08: // i_or_br8 + DEF_br8(); + ORB(); + PutbackRMByte(m_dst); + CLKM(1,3); + break; + + case 0x09: // i_or_wr16 + DEF_wr16(); + ORW(); + PutbackRMWord(m_dst); + CLKM(1,3); + break; + + case 0x0a: // i_or_r8b + DEF_r8b(); + ORB(); + RegByte(m_dst); + CLKM(1,2); + break; + + case 0x0b: // i_or_r16w + DEF_r16w(); + ORW(); + RegWord(m_dst); + CLKM(1,2); + break; + + case 0x0c: // i_or_ald8 + DEF_ald8(); + ORB(); + m_regs.b[AL] = m_dst; + CLK(1); + break; + + case 0x0d: // i_or_axd16 + DEF_axd16(); + ORW(); + m_regs.w[AW] = m_dst; + CLK(1); + break; + + case 0x0e: // i_push_cs + PUSH(m_sregs[CS]); + CLK(2); + break; + + case 0x0f: // i_pre_nec + { + UINT32 tmp, tmp2; + + switch ( fetch() ) + { + case 0x10: /* Test */ + m_modrm = fetch(); + tmp = GetRMByte(); + tmp2 = m_regs.b[CL] & 0x7; + m_ZeroVal = (tmp & (1<>4)*10 + (tmp&0xf); + int v2 = (tmp2>>4)*10 + (tmp2&0xf); + int result = v1 + v2 + m_CarryVal; + m_CarryVal = result > 99 ? 1 : 0; + result = result % 100; + v1 = ((result/10)<<4) | (result % 10); + PutMemB(ES, di,v1); + if (v1) + { + m_ZeroVal = 1; + } + si++; + di++; + } + } + break; + case 0x22: + { + int count = (m_regs.b[CL]+1)/2; + UINT16 di = m_regs.w[IY]; + UINT16 si = m_regs.w[IX]; + if (m_seg_prefix) + { + logerror("%s: %06x: Warning: seg_prefix defined for sub4s\n", tag(), pc()); + } + m_ZeroVal = m_CarryVal = 0; + for (int i=0; i>4)*10 + (tmp&0xf); + int v2 = (tmp2>>4)*10 + (tmp2&0xf); + if (v1 < (v2+m_CarryVal)) + { + v1+=100; + result = v1-(v2+m_CarryVal); + m_CarryVal = 1; + } + else + { + result = v1-(v2+m_CarryVal); + m_CarryVal = 0; + } + v1 = ((result/10)<<4) | (result % 10); + PutMemB(ES, di,v1); + if (v1) + { + m_ZeroVal = 1; + } + si++; + di++; + } + } + break; + case 0x26: + { + int count = (m_regs.b[CL]+1)/2; + UINT16 di = m_regs.w[IY]; + UINT16 si = m_regs.w[IX]; + if (m_seg_prefix) + { + logerror("%s: %06x: Warning: seg_prefix defined for cmp4s\n", tag(), pc()); + } + m_ZeroVal = m_CarryVal = 0; + for (int i=0; i>4)*10 + (tmp&0xf); + int v2 = (tmp2>>4)*10 + (tmp2&0xf); + if (v1 < (v2+m_CarryVal)) + { + v1+=100; + result = v1-(v2+m_CarryVal); + m_CarryVal = 1; + } + else + { + result = v1-(v2+m_CarryVal); + m_CarryVal = 0; + } + v1 = ((result/10)<<4) | (result % 10); + if (v1) + { + m_ZeroVal = 1; + } + si++; + di++; + } + } + break; + case 0x28: + m_modrm = fetch(); + tmp = GetRMByte(); + tmp <<= 4; + tmp |= m_regs.b[AL] & 0xf; + m_regs.b[AL] = (m_regs.b[AL] & 0xf0) | ((tmp>>8)&0xf); + tmp &= 0xff; + PutbackRMByte(tmp); + CLKM(9,15); + break; + case 0x2a: + m_modrm = fetch(); + tmp = GetRMByte(); + tmp2 = (m_regs.b[AL] & 0xf)<<4; + m_regs.b[AL] = (m_regs.b[AL] & 0xf0) | (tmp&0xf); + tmp = tmp2 | (tmp>>4); + PutbackRMByte(tmp); + CLKM(13,19); + break; + case 0x31: + m_modrm = fetch(); m_modrm = 0; logerror("%s: %06x: Unimplemented bitfield INS\n", tag(), pc()); break; + case 0x33: + m_modrm = fetch(); m_modrm = 0; logerror("%s: %06x: Unimplemented bitfield EXT\n", tag(), pc()); break; + case 0x92: /* V25/35 FINT */ + CLK(2); + break; + case 0xe0: + m_modrm = fetch(); + m_modrm = 0; + logerror("%s: %06x: V33 unimplemented BRKXA (break to expansion address)\n", tag(), pc()); + break; + case 0xf0: + m_modrm = fetch(); + m_modrm = 0; + logerror("%s: %06x: V33 unimplemented RETXA (return from expansion address)\n", tag(), pc()); + break; + case 0xff: + m_modrm = fetch(); + m_modrm = 0; + logerror("%s: %06x: unimplemented BRKEM (break to 8080 emulation mode)\n", tag(), pc()); + break; + default: + logerror("%s: %06x: Unknown V20 instruction\n", tag(), pc()); + break; + } + } + break; + + + case 0x10: // i_adc_br8 + DEF_br8(); + m_src += CF ? 1 : 0; + ADDB(); + PutbackRMByte(m_dst); + CLKM(1,3); + break; + + case 0x11: // i_adc_wr16 + DEF_wr16(); + m_src += CF ? 1 : 0; + ADDW(); + PutbackRMWord(m_dst); + CLKM(1,3); + break; + + case 0x12: // i_adc_r8b + DEF_r8b(); + m_src += CF ? 1 : 0; + ADDB(); + RegByte(m_dst); + CLKM(1,2); + break; + + case 0x13: // i_adc_r16w + DEF_r16w(); + m_src += CF ? 1 : 0; + ADDW(); + RegWord(m_dst); + CLKM(1,2); + break; + + case 0x14: // i_adc_ald8 + DEF_ald8(); + m_src += CF ? 1 : 0; + ADDB(); + m_regs.b[AL] = m_dst; + CLK(1); + break; + + case 0x15: // i_adc_axd16 + DEF_axd16(); + m_src += CF ? 1 : 0; + ADDW(); + m_regs.w[AW] = m_dst; + CLK(1); + break; + + case 0x16: // i_push_ss + PUSH(m_sregs[SS]); + CLK(2); + break; + + case 0x17: // i_pop_ss + m_sregs[SS] = POP(); + CLK(3); + m_no_interrupt = 1; + break; + + + case 0x18: // i_sbb_br8 + DEF_br8(); + m_src += CF ? 1 : 0; + SUBB(); + PutbackRMByte(m_dst); + CLKM(1,3); + break; + + case 0x19: // i_sbb_wr16 + DEF_wr16(); + m_src += CF ? 1 : 0; + SUBW(); + PutbackRMWord(m_dst); + CLKM(1,3); + break; + + case 0x1a: // i_sbb_r8b + DEF_r8b(); + m_src += CF ? 1 : 0; + SUBB(); + RegByte(m_dst); + CLKM(1,2); + break; + + case 0x1b: // i_sbb_r16w + DEF_r16w(); + m_src += CF ? 1 : 0; + SUBW(); + RegWord(m_dst); + CLKM(1,2); + break; + + case 0x1c: // i_sbb_ald8 + DEF_ald8(); + m_src += CF ? 1 : 0; + SUBB(); + m_regs.b[AL] = m_dst; + CLK(1); + break; + + case 0x1d: // i_sbb_axd16 + DEF_axd16(); + m_src += CF ? 1 : 0; + SUBW(); + m_regs.w[AW] = m_dst; + CLK(1); + break; + + case 0x1e: // i_push_ds + PUSH(m_sregs[DS]); + CLK(2); + break; + + case 0x1f: // i_pop_ds + m_sregs[DS] = POP(); + CLK(3); + break; + + + case 0x20: // i_and_br8 + DEF_br8(); + ANDB(); + PutbackRMByte(m_dst); + CLKM(1,3); + break; + + case 0x21: // i_and_wr16 + DEF_wr16(); + ANDW(); + PutbackRMWord(m_dst); + CLKM(1,3); + break; + + case 0x22: // i_and_r8b + DEF_r8b(); + ANDB(); + RegByte(m_dst); + CLKM(1,2); + break; + + case 0x23: // i_and_r16w + DEF_r16w(); + ANDW(); + RegWord(m_dst); + CLKM(1,2); + break; + + case 0x24: // i_and_ald8 + DEF_ald8(); + ANDB(); + m_regs.b[AL] = m_dst; + CLK(1); + break; + + case 0x25: // i_and_axd16 + DEF_axd16(); + ANDW(); + m_regs.w[AW] = m_dst; + CLK(1); + break; + + case 0x26: // i_es + m_seg_prefix_next = true; + m_prefix_base = m_sregs[ES]<<4; + CLK(1); + break; + + case 0x27: // i_daa + ADJ4(6,0x60); + CLK(10); + break; + + + case 0x28: // i_sub_br8 + DEF_br8(); + SUBB(); + PutbackRMByte(m_dst); + CLKM(1,3); + break; + + case 0x29: // i_sub_wr16 + DEF_wr16(); + SUBW(); + PutbackRMWord(m_dst); + CLKM(1,3); + break; + + case 0x2a: // i_sub_r8b + DEF_r8b(); + SUBB(); + RegByte(m_dst); + CLKM(1,2); + break; + + case 0x2b: // i_sub_r16w + DEF_r16w(); + SUBW(); + RegWord(m_dst); + CLKM(1,2); + break; + + case 0x2c: // i_sub_ald8 + DEF_ald8(); + SUBB(); + m_regs.b[AL] = m_dst; + CLK(1); + break; + + case 0x2d: // i_sub_axd16 + DEF_axd16(); + SUBW(); + m_regs.w[AW] = m_dst; + CLK(1); + break; + + case 0x2e: // i_cs + m_seg_prefix_next = true; + m_prefix_base = m_sregs[CS]<<4; + CLK(1); + break; + + case 0x2f: // i_das + ADJ4(-6,-0x60); + CLK(10); + break; + + + case 0x30: // i_xor_br8 + DEF_br8(); + XORB(); + PutbackRMByte(m_dst); + CLKM(1,3); + break; + + case 0x31: // i_xor_wr16 + DEF_wr16(); + XORW(); + PutbackRMWord(m_dst); + CLKM(1,3); + break; + + case 0x32: // i_xor_r8b + DEF_r8b(); + XORB(); + RegByte(m_dst); + CLKM(1,2); + break; + + case 0x33: // i_xor_r16w + DEF_r16w(); + XORW(); + RegWord(m_dst); + CLKM(1,2); + break; + + case 0x34: // i_xor_ald8 + DEF_ald8(); + XORB(); + m_regs.b[AL] = m_dst; + CLK(1); + break; + + case 0x35: // i_xor_axd16 + DEF_axd16(); + XORW(); + m_regs.w[AW] = m_dst; + CLK(1); + break; + + case 0x36: // i_ss + m_seg_prefix_next = true; + m_prefix_base = m_sregs[SS]<<4; + CLK(1); + break; + + case 0x37: // i_aaa + ADJB(6, (m_regs.b[AL] > 0xf9) ? 2 : 1); + CLK(9); + break; + + + case 0x38: // i_cmp_br8 + DEF_br8(); + SUBB(); + CLKM(1,2); + break; + + case 0x39: // i_cmp_wr16 + DEF_wr16(); + SUBW(); + CLKM(1,2); + break; + + case 0x3a: // i_cmp_r8b + DEF_r8b(); + SUBB(); + CLKM(1,2); + break; + + case 0x3b: // i_cmp_r16w + DEF_r16w(); + SUBW(); + CLKM(1,2); + break; + + case 0x3c: // i_cmp_ald8 + DEF_ald8(); + SUBB(); + CLK(1); + break; + + case 0x3d: // i_cmp_axd16 + DEF_axd16(); + SUBW(); + CLK(1); + break; + + case 0x3e: // i_ds + m_seg_prefix_next = true; + m_prefix_base = m_sregs[DS]<<4; + CLK(1); + break; + + case 0x3f: // i_aas + ADJB(-6, (m_regs.b[AL] < 6) ? -2 : -1); + CLK(9); + break; + + + case 0x40: // i_inc_ax + IncWordReg(AW); + CLK(1); + break; + + case 0x41: // i_inc_cx + IncWordReg(CW); + CLK(1); + break; + + case 0x42: // i_inc_dx + IncWordReg(DW); + CLK(1); + break; + + case 0x43: // i_inc_bx + IncWordReg(BW); + CLK(1); + break; + + case 0x44: // i_inc_sp + IncWordReg(SP); + CLK(1); + break; + + case 0x45: // i_inc_bp + IncWordReg(BP); + CLK(1); + break; + + case 0x46: // i_inc_si + IncWordReg(IX); + CLK(1); + break; + + case 0x47: // i_inc_di + IncWordReg(IY); + CLK(1); + break; + + + case 0x48: // i_dec_ax + DecWordReg(AW); + CLK(1); + break; + + case 0x49: // i_dec_cx + DecWordReg(CW); + CLK(1); + break; + + case 0x4a: // i_dec_dx + DecWordReg(DW); + CLK(1); + break; + + case 0x4b: // i_dec_bx + DecWordReg(BW); + CLK(1); + break; + + case 0x4c: // i_dec_sp + DecWordReg(SP); + CLK(1); + break; + + case 0x4d: // i_dec_bp + DecWordReg(BP); + CLK(1); + break; + + case 0x4e: // i_dec_si + DecWordReg(IX); + CLK(1); + break; + + case 0x4f: // i_dec_di + DecWordReg(IY); + CLK(1); + break; + + + case 0x50: // i_push_ax + PUSH(m_regs.w[AW]); + CLK(1); + break; + + case 0x51: // i_push_cx + PUSH(m_regs.w[CW]); + CLK(1); + break; + + case 0x52: // i_push_dx + PUSH(m_regs.w[DW]); + CLK(1); + break; + + case 0x53: // i_push_bx + PUSH(m_regs.w[BW]); + CLK(1); + break; + + case 0x54: // i_push_sp + PUSH(m_regs.w[SP]); + CLK(1); + break; + + case 0x55: // i_push_bp + PUSH(m_regs.w[BP]); + CLK(1); + break; + + case 0x56: // i_push_si + PUSH(m_regs.w[IX]); + CLK(1); + break; + + case 0x57: // i_push_di + PUSH(m_regs.w[IY]); + CLK(1); + break; + + + case 0x58: // i_pop_ax + m_regs.w[AW] = POP(); + CLK(1); + break; + + case 0x59: // i_pop_cx + m_regs.w[CW] = POP(); + CLK(1); + break; + + case 0x5a: // i_pop_dx + m_regs.w[DW] = POP(); + CLK(1); + break; + + case 0x5b: // i_pop_bx + m_regs.w[BW] = POP(); + CLK(1); + break; + + case 0x5c: // i_pop_sp + m_regs.w[SP] = POP(); + CLK(1); + break; + + case 0x5d: // i_pop_bp + m_regs.w[BP] = POP(); + CLK(1); + break; + + case 0x5e: // i_pop_si + m_regs.w[IX] = POP(); + CLK(1); + break; + + case 0x5f: // i_pop_di + m_regs.w[IY] = POP(); + CLK(1); + break; + + + case 0x60: // i_pusha + { + UINT32 tmp = m_regs.w[SP]; + + PUSH(m_regs.w[AW]); + PUSH(m_regs.w[CW]); + PUSH(m_regs.w[DW]); + PUSH(m_regs.w[BW]); + PUSH(tmp); + PUSH(m_regs.w[BP]); + PUSH(m_regs.w[IX]); + PUSH(m_regs.w[IY]); + CLK(9); + } + break; + + case 0x61: // i_popa + m_regs.w[IY] = POP(); + m_regs.w[IX] = POP(); + m_regs.w[BP] = POP(); + POP(); + m_regs.w[BW] = POP(); + m_regs.w[DW] = POP(); + m_regs.w[CW] = POP(); + m_regs.w[AW] = POP(); + CLK(8); + break; + + case 0x62: // i_chkind + { + UINT32 low,high,tmp; + m_modrm = fetch(); + low = GetRMWord(); + high = GetnextRMWord(); + tmp = RegWord(); + if (tmphigh) + { + interrupt(5); + CLK(20); + } + else + { + CLK(13); + } + logerror("%s: %06x: bound %04x high %04x low %04x tmp\n", tag(), pc(), high, low, tmp); + } + break; + + case 0x64: // i_repnc + { + UINT8 next = repx_op(); + UINT16 c = m_regs.w[CW]; + + switch (next) + { + case 0x6c: CLK(2); if (c) do { i_insb(); c--; } while (c>0 && !CF); m_regs.w[CW]=c; m_seg_prefix = false; m_seg_prefix_next = false; break; + case 0x6d: CLK(2); if (c) do { i_insw(); c--; } while (c>0 && !CF); m_regs.w[CW]=c; m_seg_prefix = false; m_seg_prefix_next = false; break; + case 0x6e: CLK(2); if (c) do { i_outsb(); c--; } while (c>0 && !CF); m_regs.w[CW]=c; m_seg_prefix = false; m_seg_prefix_next = false; break; + case 0x6f: CLK(2); if (c) do { i_outsw(); c--; } while (c>0 && !CF); m_regs.w[CW]=c; m_seg_prefix = false; m_seg_prefix_next = false; break; + case 0xa4: CLK(2); if (c) do { i_movsb(); c--; } while (c>0 && !CF); m_regs.w[CW]=c; m_seg_prefix = false; m_seg_prefix_next = false; break; + case 0xa5: CLK(2); if (c) do { i_movsw(); c--; } while (c>0 && !CF); m_regs.w[CW]=c; m_seg_prefix = false; m_seg_prefix_next = false; break; + case 0xa6: CLK(2); if (c) do { i_cmpsb(); c--; } while (c>0 && !CF); m_regs.w[CW]=c; m_seg_prefix = false; m_seg_prefix_next = false; break; + case 0xa7: CLK(2); if (c) do { i_cmpsw(); c--; } while (c>0 && !CF); m_regs.w[CW]=c; m_seg_prefix = false; m_seg_prefix_next = false; break; + case 0xaa: CLK(2); if (c) do { i_stosb(); c--; } while (c>0 && !CF); m_regs.w[CW]=c; m_seg_prefix = false; m_seg_prefix_next = false; break; + case 0xab: CLK(2); if (c) do { i_stosw(); c--; } while (c>0 && !CF); m_regs.w[CW]=c; m_seg_prefix = false; m_seg_prefix_next = false; break; + case 0xac: CLK(2); if (c) do { i_lodsb(); c--; } while (c>0 && !CF); m_regs.w[CW]=c; m_seg_prefix = false; m_seg_prefix_next = false; break; + case 0xad: CLK(2); if (c) do { i_lodsw(); c--; } while (c>0 && !CF); m_regs.w[CW]=c; m_seg_prefix = false; m_seg_prefix_next = false; break; + case 0xae: CLK(2); if (c) do { i_scasb(); c--; } while (c>0 && !CF); m_regs.w[CW]=c; m_seg_prefix = false; m_seg_prefix_next = false; break; + case 0xaf: CLK(2); if (c) do { i_scasw(); c--; } while (c>0 && !CF); m_regs.w[CW]=c; m_seg_prefix = false; m_seg_prefix_next = false; break; + default: + logerror("%s: %06x: REPNC invalid\n", tag(), pc() ); + // Decrement IP so the normal instruction will be executed next + m_ip--; + break; + } + } + break; + + + case 0x65: // i_repc + { + UINT8 next = repx_op(); + UINT16 c = m_regs.w[CW]; + + switch (next) + { + case 0x6c: CLK(2); if (c) do { i_insb(); c--; } while (c>0 && CF); m_regs.w[CW]=c; m_seg_prefix = false; m_seg_prefix_next = false; break; + case 0x6d: CLK(2); if (c) do { i_insw(); c--; } while (c>0 && CF); m_regs.w[CW]=c; m_seg_prefix = false; m_seg_prefix_next = false; break; + case 0x6e: CLK(2); if (c) do { i_outsb(); c--; } while (c>0 && CF); m_regs.w[CW]=c; m_seg_prefix = false; m_seg_prefix_next = false; break; + case 0x6f: CLK(2); if (c) do { i_outsw(); c--; } while (c>0 && CF); m_regs.w[CW]=c; m_seg_prefix = false; m_seg_prefix_next = false; break; + case 0xa4: CLK(2); if (c) do { i_movsb(); c--; } while (c>0 && CF); m_regs.w[CW]=c; m_seg_prefix = false; m_seg_prefix_next = false; break; + case 0xa5: CLK(2); if (c) do { i_movsw(); c--; } while (c>0 && CF); m_regs.w[CW]=c; m_seg_prefix = false; m_seg_prefix_next = false; break; + case 0xa6: CLK(2); if (c) do { i_cmpsb(); c--; } while (c>0 && CF); m_regs.w[CW]=c; m_seg_prefix = false; m_seg_prefix_next = false; break; + case 0xa7: CLK(2); if (c) do { i_cmpsw(); c--; } while (c>0 && CF); m_regs.w[CW]=c; m_seg_prefix = false; m_seg_prefix_next = false; break; + case 0xaa: CLK(2); if (c) do { i_stosb(); c--; } while (c>0 && CF); m_regs.w[CW]=c; m_seg_prefix = false; m_seg_prefix_next = false; break; + case 0xab: CLK(2); if (c) do { i_stosw(); c--; } while (c>0 && CF); m_regs.w[CW]=c; m_seg_prefix = false; m_seg_prefix_next = false; break; + case 0xac: CLK(2); if (c) do { i_lodsb(); c--; } while (c>0 && CF); m_regs.w[CW]=c; m_seg_prefix = false; m_seg_prefix_next = false; break; + case 0xad: CLK(2); if (c) do { i_lodsw(); c--; } while (c>0 && CF); m_regs.w[CW]=c; m_seg_prefix = false; m_seg_prefix_next = false; break; + case 0xae: CLK(2); if (c) do { i_scasb(); c--; } while (c>0 && CF); m_regs.w[CW]=c; m_seg_prefix = false; m_seg_prefix_next = false; break; + case 0xaf: CLK(2); if (c) do { i_scasw(); c--; } while (c>0 && CF); m_regs.w[CW]=c; m_seg_prefix = false; m_seg_prefix_next = false; break; + default: + logerror("%s: %06x: REPC invalid\n", tag(), pc()); + // Decrement IP so the normal instruction will be executed next + m_ip--; + break; + } + } + break; + + + case 0x68: // i_push_d16 + PUSH( fetch_word() ); + CLK(1); + break; + + case 0x69: // i_imul_d16 + { + UINT32 tmp; + DEF_r16w(); + tmp = fetch_word(); + m_dst = (INT32)((INT16)m_src)*(INT32)((INT16)tmp); + m_CarryVal = m_OverVal = (((INT32)m_dst) >> 15 != 0) && (((INT32)m_dst) >> 15 != -1); + RegWord(m_dst); + CLKM(3,4); + } + break; + + case 0x6a: // i_push_d8 + PUSH( (UINT16)((INT16)((INT8)fetch())) ); + CLK(1); + break; + + case 0x6b: // i_imul_d8 + { + UINT32 src2; + DEF_r16w(); + src2= (UINT16)((INT16)((INT8)fetch())); + m_dst = (INT32)((INT16)m_src)*(INT32)((INT16)src2); + m_CarryVal = m_OverVal = (((INT32)m_dst) >> 15 != 0) && (((INT32)m_dst) >> 15 != -1); + RegWord(m_dst); + CLKM(3,4); + } + break; + + case 0x6c: // i_insb + i_insb(); + break; + + case 0x6d: // i_insw + i_insw(); + break; + + case 0x6e: // i_outsb + i_outsb(); + break; + + case 0x6f: // i_outsw + i_outsw(); + break; + + + case 0x70: // i_jo + JMP( OF); + break; + + case 0x71: // i_jno + JMP(!OF); + break; + + case 0x72: // i_jc + JMP( CF); + break; + + case 0x73: // i_jnc + JMP(!CF); + break; + + case 0x74: // i_jz + JMP( ZF); + break; + + case 0x75: // i_jnz + JMP(!ZF); + break; + + case 0x76: // i_jce + JMP(CF || ZF); + break; + + case 0x77: // i_jnce + JMP(!(CF || ZF)); + break; + + case 0x78: // i_js + JMP( SF); + break; + + case 0x79: // i_jns + JMP(!SF); + break; + + case 0x7a: // i_jp + JMP( PF); + break; + + case 0x7b: // i_jnp + JMP(!PF); + break; + + case 0x7c: // i_jl + JMP((SF!=OF)&&(!ZF)); + break; + + case 0x7d: // i_jnl + JMP((ZF)||(SF==OF)); + break; + + case 0x7e: // i_jle + JMP((ZF)||(SF!=OF)); + break; + + case 0x7f: // i_jnle + JMP((SF==OF)&&(!ZF)); + break; + + + case 0x80: // i_80pre + m_modrm = fetch(); + m_dst = GetRMByte(); + m_src = fetch(); + if (m_modrm >=0xc0 ) { CLK(1); } + else if ((m_modrm & 0x38)==0x38) { CLK(2); } + else { CLK(3); } + switch (m_modrm & 0x38) + { + case 0x00: ADDB(); PutbackRMByte(m_dst); break; + case 0x08: ORB(); PutbackRMByte(m_dst); break; + case 0x10: m_src += CF ? 1 : 0; ADDB(); PutbackRMByte(m_dst); break; + case 0x18: m_src += CF ? 1 : 0; SUBB(); PutbackRMByte(m_dst); break; + case 0x20: ANDB(); PutbackRMByte(m_dst); break; + case 0x28: SUBB(); PutbackRMByte(m_dst); break; + case 0x30: XORB(); PutbackRMByte(m_dst); break; + case 0x38: SUBB(); break; /* CMP */ + } + break; + + + case 0x81: // i_81pre + m_modrm = fetch(); + m_dst = GetRMWord(); + m_src = fetch_word(); + if (m_modrm >=0xc0 ) { CLK(1); } + else if ((m_modrm & 0x38)==0x38) { CLK(2); } + else { CLK(3); } + switch (m_modrm & 0x38) + { + case 0x00: ADDW(); PutbackRMWord(m_dst); break; + case 0x08: ORW(); PutbackRMWord(m_dst); break; + case 0x10: m_src += CF ? 1 : 0; ADDW(); PutbackRMWord(m_dst); break; + case 0x18: m_src += CF ? 1 : 0; SUBW(); PutbackRMWord(m_dst); break; + case 0x20: ANDW(); PutbackRMWord(m_dst); break; + case 0x28: SUBW(); PutbackRMWord(m_dst); break; + case 0x30: XORW(); PutbackRMWord(m_dst); break; + case 0x38: SUBW(); break; /* CMP */ + } + break; + + + case 0x82: // i_82pre + m_modrm = fetch(); + m_dst = GetRMByte(); + m_src = (INT8)fetch(); + if (m_modrm >=0xc0 ) { CLK(1); } + else if ((m_modrm & 0x38)==0x38) { CLK(2); } + else { CLK(3); } + switch (m_modrm & 0x38) + { + case 0x00: ADDB(); PutbackRMByte(m_dst); break; + case 0x08: ORB(); PutbackRMByte(m_dst); break; + case 0x10: m_src += CF ? 1 : 0; ADDB(); PutbackRMByte(m_dst); break; + case 0x18: m_src += CF ? 1 : 0; SUBB(); PutbackRMByte(m_dst); break; + case 0x20: ANDB(); PutbackRMByte(m_dst); break; + case 0x28: SUBB(); PutbackRMByte(m_dst); break; + case 0x30: XORB(); PutbackRMByte(m_dst); break; + case 0x38: SUBB(); break; /* CMP */ + } + break; + + + case 0x83: // i_83pre + m_modrm = fetch(); + m_dst = GetRMWord(); + m_src = ((INT16)((INT8)fetch())); + if ( m_modrm >= 0xc0 ) { CLK(1); } + else if (( m_modrm & 0x38 ) == 0x38) { CLK(2); } + else { CLK(3); } + switch (m_modrm & 0x38) + { + case 0x00: ADDW(); PutbackRMWord(m_dst); break; + case 0x08: ORW(); PutbackRMWord(m_dst); break; + case 0x10: m_src += CF ? 1 : 0; ADDW(); PutbackRMWord(m_dst); break; + case 0x18: m_src += CF ? 1 : 0; SUBW(); PutbackRMWord(m_dst); break; + case 0x20: ANDW(); PutbackRMWord(m_dst); break; + case 0x28: SUBW(); PutbackRMWord(m_dst); break; + case 0x30: XORW(); PutbackRMWord(m_dst); break; + case 0x38: SUBW(); break; /* CMP */ + } + break; + + + case 0x84: // i_test_br8 + DEF_br8(); + ANDB(); + CLKM(1,2); + break; + + case 0x85: // i_test_wr16 + DEF_wr16(); + ANDW(); + CLKM(1,2); + break; + + case 0x86: // i_xchg_br8 + DEF_br8(); + RegByte(m_dst); + PutbackRMByte(m_src); + CLKM(3,5); + break; + + case 0x87: // i_xchg_wr16 + DEF_wr16(); + RegWord(m_dst); + PutbackRMWord(m_src); + CLKM(3,5); + break; + + + case 0x88: // i_mov_br8 + m_modrm = fetch(); + m_src = RegByte(); + PutRMByte(m_src); + CLK(1); + break; + + case 0x89: // i_mov_wr16 + m_modrm = fetch(); + m_src = RegWord(); + PutRMWord(m_src); + CLK(1); + break; + + case 0x8a: // i_mov_r8b + m_modrm = fetch(); + m_src = GetRMByte(); + RegByte(m_src); + CLK(1); + break; + + case 0x8b: // i_mov_r16w + m_modrm = fetch(); + m_src = GetRMWord(); + RegWord(m_src); + CLK(1); + break; + + case 0x8c: // i_mov_wsreg + m_modrm = fetch(); + PutRMWord(m_sregs[(m_modrm & 0x38) >> 3]); + CLKM(1,3); + break; + + case 0x8d: // i_lea + m_modrm = fetch(); + get_ea(); + RegWord(m_eo); + CLK(1); + break; + + case 0x8e: // i_mov_sregw + m_modrm = fetch(); + m_src = GetRMWord(); + CLKM(2,3); + switch (m_modrm & 0x38) + { + case 0x00: /* mov es,ew */ + m_sregs[ES] = m_src; + break; + case 0x08: /* mov cs,ew */ + m_sregs[CS] = m_src; + break; + case 0x10: /* mov ss,ew */ + m_sregs[SS] = m_src; + break; + case 0x18: /* mov ds,ew */ + m_sregs[DS] = m_src; + break; + default: + logerror("%s: %06x: Mov Sreg - Invalid register\n", tag(), pc()); + } + m_no_interrupt = 1; + break; + + case 0x8f: // i_popw + m_modrm = fetch(); + PutRMWord( POP() ); + CLKM(1,3); + break; + + case 0x90: // i_nop + CLK(1); + break; + + case 0x91: // i_xchg_axcx + XchgAWReg(CW); + CLK(3); + break; + + case 0x92: // i_xchg_axdx + XchgAWReg(DW); + CLK(3); + break; + + case 0x93: // i_xchg_axbx + XchgAWReg(BW); + CLK(3); + break; + + case 0x94: // i_xchg_axsp + XchgAWReg(SP); + CLK(3); + break; + + case 0x95: // i_xchg_axbp + XchgAWReg(BP); + CLK(3); + break; + + case 0x96: // i_xchg_axsi + XchgAWReg(IX); + CLK(3); + break; + + case 0x97: // i_xchg_axdi + XchgAWReg(IY); + CLK(3); + break; + + + case 0x98: // i_cbw + m_regs.b[AH] = (m_regs.b[AL] & 0x80) ? 0xff : 0; + CLK(1); + break; + + case 0x99: // i_cwd + m_regs.w[DW] = (m_regs.b[AH] & 0x80) ? 0xffff : 0; + CLK(1); + break; + + case 0x9a: // i_call_far + { + UINT16 tmp = fetch_word(); + UINT16 tmp2 = fetch_word(); + PUSH(m_sregs[CS]); + PUSH(m_ip); + m_ip = tmp; + m_sregs[CS] = tmp2; + CLK(10); + } + break; + + case 0x9b: // i_wait + logerror("%s: %06x: Hardware POLL\n", tag(), pc()); + break; + + case 0x9c: // i_pushf + PUSH( CompressFlags() ); + CLK(2); + break; + + case 0x9d: // i_popf + i_popf(); + break; + + case 0x9e: // i_sahf + { + UINT32 tmp = (CompressFlags() & 0xff00) | (m_regs.b[AH] & 0xd5); + ExpandFlags(tmp); + CLK(4); + } + break; + + case 0x9f: // i_lahf + m_regs.b[AH] = CompressFlags(); + CLK(2); + break; + + + case 0xa0: // i_mov_aldisp + { + UINT32 addr = fetch_word(); + m_regs.b[AL] = GetMemB(DS, addr); + CLK(1); + } + break; + + case 0xa1: // i_mov_axdisp + { + UINT32 addr = fetch_word(); + m_regs.b[AL] = GetMemB(DS, addr); + m_regs.b[AH] = GetMemB(DS, addr+1); + CLK(1); + } + break; + + case 0xa2: // i_mov_dispal + { + UINT32 addr = fetch_word(); + PutMemB(DS, addr, m_regs.b[AL]); + CLK(1); + } + break; + + case 0xa3: // i_mov_dispax + { + UINT32 addr = fetch_word(); + PutMemB(DS, addr, m_regs.b[AL]); + PutMemB(DS, addr+1, m_regs.b[AH]); + CLK(1); + } + break; + + case 0xa4: // i_movsb + i_movsb(); + break; + + case 0xa5: // i_movsw + i_movsw(); + break; + + case 0xa6: // i_cmpsb + i_cmpsb(); + break; + + case 0xa7: // i_cmpsw + i_cmpsw(); + break; + + + case 0xa8: // i_test_ald8 + DEF_ald8(); + ANDB(); + CLK(1); + break; + + case 0xa9: // i_test_axd16 + DEF_axd16(); + ANDW(); + CLK(1); + break; + + case 0xaa: // i_stosb + i_stosb(); + break; + + case 0xab: // i_stosw + i_stosw(); + break; + + case 0xac: // i_lodsb + i_lodsb(); + break; + + case 0xad: // i_lodsw + i_lodsw(); + break; + + case 0xae: // i_scasb + i_scasb(); + break; + + case 0xaf: // i_scasw + i_scasw(); + break; + + + case 0xb0: // i_mov_ald8 + m_regs.b[AL] = fetch(); + CLK(1); + break; + + case 0xb1: // i_mov_cld8 + m_regs.b[CL] = fetch(); + CLK(1); + break; + + case 0xb2: // i_mov_dld8 + m_regs.b[DL] = fetch(); + CLK(1); + break; + + case 0xb3: // i_mov_bld8 + m_regs.b[BL] = fetch(); + CLK(1); + break; + + case 0xb4: // i_mov_ahd8 + m_regs.b[AH] = fetch(); + CLK(1); + break; + + case 0xb5: // i_mov_chd8 + m_regs.b[CH] = fetch(); + CLK(1); + break; + + case 0xb6: // i_mov_dhd8 + m_regs.b[DH] = fetch(); + CLK(1); + break; + + case 0xb7: // i_mov_bhd8 + m_regs.b[BH] = fetch(); + CLK(1); + break; + + + case 0xb8: // i_mov_axd16 + m_regs.b[AL] = fetch(); + m_regs.b[AH] = fetch(); + CLK(1); + break; + + case 0xb9: // i_mov_cxd16 + m_regs.b[CL] = fetch(); + m_regs.b[CH] = fetch(); + CLK(1); + break; + + case 0xba: // i_mov_dxd16 + m_regs.b[DL] = fetch(); + m_regs.b[DH] = fetch(); + CLK(1); + break; + + case 0xbb: // i_mov_bxd16 + m_regs.b[BL] = fetch(); + m_regs.b[BH] = fetch(); + CLK(1); + break; + + case 0xbc: // i_mov_spd16 + m_regs.b[SPL] = fetch(); + m_regs.b[SPH] = fetch(); + CLK(1); + break; + + case 0xbd: // i_mov_bpd16 + m_regs.b[BPL] = fetch(); + m_regs.b[BPH] = fetch(); + CLK(1); + break; + + case 0xbe: // i_mov_sid16 + m_regs.b[IXL] = fetch(); + m_regs.b[IXH] = fetch(); + CLK(1); + break; + + case 0xbf: // i_mov_did16 + m_regs.b[IYL] = fetch(); + m_regs.b[IYH] = fetch(); + CLK(1); + break; + + + case 0xc0: // i_rotshft_bd8 + { + UINT8 c; + m_modrm = fetch(); + m_src = GetRMByte(); + m_dst = m_src; + c = fetch(); + CLKM(3,5); + if (c) + { + switch ( m_modrm & 0x38 ) + { + case 0x00: do { ROL_BYTE(); c--; } while (c>0); PutbackRMByte(m_dst); break; + case 0x08: do { ROR_BYTE(); c--; } while (c>0); PutbackRMByte(m_dst); break; + case 0x10: do { ROLC_BYTE(); c--; } while (c>0); PutbackRMByte(m_dst); break; + case 0x18: do { RORC_BYTE(); c--; } while (c>0); PutbackRMByte(m_dst); break; + case 0x20: SHL_BYTE(c); break; + case 0x28: SHR_BYTE(c); break; + case 0x30: logerror("%s: %06x: Undefined opcode 0xc0 0x30 (SHLA)\n", tag(), pc()); break; + case 0x38: SHRA_BYTE(c); break; + } + } + } + break; + + case 0xc1: // i_rotshft_wd8 + { + UINT8 c; + m_modrm = fetch(); + m_src = GetRMWord(); + m_dst = m_src; + c = fetch(); + CLKM(3,5); + if (c) + { + switch ( m_modrm & 0x38 ) + { + case 0x00: do { ROL_WORD(); c--; } while (c>0); PutbackRMWord(m_dst); break; + case 0x08: do { ROR_WORD(); c--; } while (c>0); PutbackRMWord(m_dst); break; + case 0x10: do { ROLC_WORD(); c--; } while (c>0); PutbackRMWord(m_dst); break; + case 0x18: do { RORC_WORD(); c--; } while (c>0); PutbackRMWord(m_dst); break; + case 0x20: SHL_WORD(c); break; + case 0x28: SHR_WORD(c); break; + case 0x30: logerror("%s: %06x: Undefined opcode 0xc1 0x30 (SHLA)\n", tag(), pc()); break; + case 0x38: SHRA_WORD(c); break; + } + } + } + break; + + + case 0xc2: // i_ret_d16 + { + UINT32 count = fetch_word(); + m_ip = POP(); + m_regs.w[SP] += count; + CLK(6); + } + break; + + case 0xc3: // i_ret + m_ip = POP(); + CLK(6); + break; + + case 0xc4: // i_les_dw + m_modrm = fetch(); + RegWord( GetRMWord() ); + m_sregs[ES] = GetnextRMWord(); + CLK(6); + break; + + case 0xc5: // i_lds_dw + m_modrm = fetch(); + RegWord( GetRMWord() ); + m_sregs[DS] = GetnextRMWord(); + CLK(6); + break; + + case 0xc6: // i_mov_bd8 + m_modrm = fetch(); + PutImmRMByte(); + CLK(1); + break; + + case 0xc7: // i_mov_wd16 + m_modrm = fetch(); + PutImmRMWord(); + CLK(1); + break; + + + case 0xc8: // i_enter + { + UINT16 nb = fetch(); + UINT32 level; + + CLK(8); + nb |= fetch() << 8; + level = fetch(); + PUSH(m_regs.w[BP]); + m_regs.w[BP] = m_regs.w[SP]; + m_regs.w[SP] -= nb; + for (int i=1; i0); PutbackRMByte(m_dst); break; + case 0x08: do { ROR_BYTE(); c--; } while (c>0); PutbackRMByte(m_dst); break; + case 0x10: do { ROLC_BYTE(); c--; } while (c>0); PutbackRMByte(m_dst); break; + case 0x18: do { RORC_BYTE(); c--; } while (c>0); PutbackRMByte(m_dst); break; + case 0x20: SHL_BYTE(c); break; + case 0x28: SHR_BYTE(c); break; + case 0x30: logerror("%s: %06x: Undefined opcode 0xd2 0x30 (SHLA)\n", tag(), pc()); break; + case 0x38: SHRA_BYTE(c); break; + } + } + } + break; + + case 0xd3: // i_rotshft_wcl + { + UINT8 c; + + m_modrm = fetch(); + m_src = GetRMWord(); + m_dst = m_src; + c = m_regs.b[CL]; + CLKM(3,5); + if (c) + { + switch ( m_modrm & 0x38 ) + { + case 0x00: do { ROL_WORD(); c--; } while (c>0); PutbackRMWord(m_dst); break; + case 0x08: do { ROR_WORD(); c--; } while (c>0); PutbackRMWord(m_dst); break; + case 0x10: do { ROLC_WORD(); c--; } while (c>0); PutbackRMWord(m_dst); break; + case 0x18: do { RORC_WORD(); c--; } while (c>0); PutbackRMWord(m_dst); break; + case 0x20: SHL_WORD(c); break; + case 0x28: SHR_WORD(c); break; + case 0x30: logerror("%s: %06x: Undefined opcode 0xd3 0x30 (SHLA)\n", tag(), pc()); break; + case 0x38: SHRA_WORD(c); break; + } + } + } + break; + + case 0xd4: // i_aam + fetch(); + m_regs.b[AH] = m_regs.b[AL] / 10; + m_regs.b[AL] %= 10; + set_SZPF_Word(m_regs.w[AW]); + CLK(17); + break; + + case 0xd5: // i_aad + fetch(); + m_regs.b[AL] = m_regs.b[AH] * 10 + m_regs.b[AL]; + m_regs.b[AH] = 0; + set_SZPF_Byte(m_regs.b[AL]); + CLK(5); + break; + + case 0xd6: // i_setalc + m_regs.b[AL] = (CF) ? 0xff : 0x00; + CLK(3); + logerror("%s: %06x: Undefined opcode (SETALC)\n", tag(), pc() ); + break; + + case 0xd7: // i_trans + m_regs.b[AL] = GetMemB( DS, m_regs.w[BW] + m_regs.b[AL] ); + CLK(5); + break; + + case 0xd8: // i_fpo + m_modrm = fetch(); + CLK(1); + logerror("%s: %06x: Unimplemented floating point control %04x\n", tag(), pc(), m_modrm); + break; + + + case 0xe0: // i_loopne + { + INT8 disp = (INT8)fetch(); + + m_regs.w[CW]--; + if (!ZF && m_regs.w[CW]) + { + m_ip = m_ip + disp; + CLK(3); + } + CLK(3); + } + break; + + case 0xe1: // i_loope + { + INT8 disp = (INT8)fetch(); + + m_regs.w[CW]--; + if (ZF && m_regs.w[CW]) + { + m_ip = m_ip + disp; + CLK(3); + } + CLK(3); + } + break; + + case 0xe2: // i_loop + { + INT8 disp = (INT8)fetch(); + + m_regs.w[CW]--; + if (m_regs.w[CW]) + { + m_ip = m_ip + disp; + CLK(3); + } + CLK(2); + } + break; + + case 0xe3: // i_jcxz + { + INT8 disp = (INT8)fetch(); + + if (m_regs.w[CW] == 0) + { + m_ip = m_ip + disp; + CLK(3); + } + CLK(1); + } + break; + + case 0xe4: // i_inal + m_regs.b[AL] = read_port( fetch() ); + CLK(6); + break; + + case 0xe5: // i_inax + { + UINT8 port = fetch(); + + m_regs.b[AL] = read_port(port); + m_regs.b[AH] = read_port(port+1); + CLK(6); + } + break; + + case 0xe6: // i_outal + write_port( fetch(), m_regs.b[AL]); + CLK(6); + break; + + case 0xe7: // i_outax + { + UINT8 port = fetch(); + + write_port(port, m_regs.b[AL]); + write_port(port+1, m_regs.b[AH]); + CLK(6); + } + break; + + + case 0xe8: // i_call_d16 + { + INT16 tmp = (INT16)fetch_word(); + + PUSH(m_ip); + m_ip = m_ip + tmp; + CLK(5); + } + break; + + case 0xe9: // i_jmp_d16 + { + INT16 offset = (INT16)fetch_word(); + m_ip += offset; + CLK(4); + } + break; + + case 0xea: // i_jmp_far + { + UINT16 tmp = fetch_word(); + UINT16 tmp1 = fetch_word(); + + m_sregs[CS] = tmp1; + m_ip = tmp; + CLK(7); + } + break; + + case 0xeb: // i_jmp_d8 + { + int tmp = (int)((INT8)fetch()); + + CLK(4); + if (tmp==-2 && m_no_interrupt==0 && (m_pending_irq==0) && m_icount>0) + { + m_icount%=12; /* cycle skip */ + } + m_ip = (UINT16)(m_ip+tmp); + } + break; + + case 0xec: // i_inaldx + m_regs.b[AL] = read_port(m_regs.w[DW]); + CLK(6); + break; + + case 0xed: // i_inaxdx + { + UINT32 port = m_regs.w[DW]; + + m_regs.b[AL] = read_port(port); + m_regs.b[AH] = read_port(port+1); + CLK(6); + } + break; + + case 0xee: // i_outdxal + write_port(m_regs.w[DW], m_regs.b[AL]); + CLK(6); + break; + + case 0xef: // i_outdxax + { + UINT32 port = m_regs.w[DW]; + + write_port(port, m_regs.b[AL]); + write_port(port+1, m_regs.b[AH]); + CLK(6); + } + break; + + + case 0xf0: // i_lock + logerror("%s: %06x: Warning - BUSLOCK\n", tag(), pc()); + m_no_interrupt = 1; + CLK(1); + break; + + case 0xf2: // i_repne + { + UINT8 next = repx_op(); + UINT16 c = m_regs.w[CW]; + + switch (next) + { + case 0x6c: CLK(3); if (c) do { i_insb(); c--; } while (c>0); m_regs.w[CW]=c; m_seg_prefix = false; m_seg_prefix_next = false; break; + case 0x6d: CLK(3); if (c) do { i_insw(); c--; } while (c>0); m_regs.w[CW]=c; m_seg_prefix = false; m_seg_prefix_next = false; break; + case 0x6e: CLK(3); if (c) do { i_outsb(); c--; } while (c>0); m_regs.w[CW]=c; m_seg_prefix = false; m_seg_prefix_next = false; break; + case 0x6f: CLK(3); if (c) do { i_outsw(); c--; } while (c>0); m_regs.w[CW]=c; m_seg_prefix = false; m_seg_prefix_next = false; break; + case 0xa4: CLK(3); if (c) do { i_movsb(); c--; } while (c>0); m_regs.w[CW]=c; m_seg_prefix = false; m_seg_prefix_next = false; break; + case 0xa5: CLK(3); if (c) do { i_movsw(); c--; } while (c>0); m_regs.w[CW]=c; m_seg_prefix = false; m_seg_prefix_next = false; break; + case 0xa6: CLK(3); if (c) do { i_cmpsb(); c--; } while (c>0 && !ZF); m_regs.w[CW]=c; m_seg_prefix = false; m_seg_prefix_next = false; break; + case 0xa7: CLK(3); if (c) do { i_cmpsw(); c--; } while (c>0 && !ZF); m_regs.w[CW]=c; m_seg_prefix = false; m_seg_prefix_next = false; break; + case 0xaa: CLK(3); if (c) do { i_stosb(); c--; } while (c>0); m_regs.w[CW]=c; m_seg_prefix = false; m_seg_prefix_next = false; break; + case 0xab: CLK(3); if (c) do { i_stosw(); c--; } while (c>0); m_regs.w[CW]=c; m_seg_prefix = false; m_seg_prefix_next = false; break; + case 0xac: CLK(3); if (c) do { i_lodsb(); c--; } while (c>0); m_regs.w[CW]=c; m_seg_prefix = false; m_seg_prefix_next = false; break; + case 0xad: CLK(3); if (c) do { i_lodsw(); c--; } while (c>0); m_regs.w[CW]=c; m_seg_prefix = false; m_seg_prefix_next = false; break; + case 0xae: CLK(3); if (c) do { i_scasb(); c--; } while (c>0 && !ZF); m_regs.w[CW]=c; m_seg_prefix = false; m_seg_prefix_next = false; break; + case 0xaf: CLK(3); if (c) do { i_scasw(); c--; } while (c>0 && !ZF); m_regs.w[CW]=c; m_seg_prefix = false; m_seg_prefix_next = false; break; + default: + logerror("%s: %06x: REPNE invalid\n", tag(), pc()); + // Decrement IP so the normal instruction will be executed next + m_ip--; + break; + } + } + break; + + case 0xf3: // i_repe + { + UINT8 next = repx_op(); + UINT16 c = m_regs.w[CW]; + + switch (next) + { + case 0x6c: CLK(3); if (c) do { i_insb(); c--; } while (c>0); m_regs.w[CW]=c; m_seg_prefix = false; m_seg_prefix_next = false; break; + case 0x6d: CLK(3); if (c) do { i_insw(); c--; } while (c>0); m_regs.w[CW]=c; m_seg_prefix = false; m_seg_prefix_next = false; break; + case 0x6e: CLK(3); if (c) do { i_outsb(); c--; } while (c>0); m_regs.w[CW]=c; m_seg_prefix = false; m_seg_prefix_next = false; break; + case 0x6f: CLK(3); if (c) do { i_outsw(); c--; } while (c>0); m_regs.w[CW]=c; m_seg_prefix = false; m_seg_prefix_next = false; break; + case 0xa4: CLK(3); if (c) do { i_movsb(); c--; } while (c>0); m_regs.w[CW]=c; m_seg_prefix = false; m_seg_prefix_next = false; break; + case 0xa5: CLK(3); if (c) do { i_movsw(); c--; } while (c>0); m_regs.w[CW]=c; m_seg_prefix = false; m_seg_prefix_next = false; break; + case 0xa6: CLK(3); if (c) do { i_cmpsb(); c--; } while (c>0 && ZF); m_regs.w[CW]=c; m_seg_prefix = false; m_seg_prefix_next = false; break; + case 0xa7: CLK(3); if (c) do { i_cmpsw(); c--; } while (c>0 && ZF); m_regs.w[CW]=c; m_seg_prefix = false; m_seg_prefix_next = false; break; + case 0xaa: CLK(3); if (c) do { i_stosb(); c--; } while (c>0); m_regs.w[CW]=c; m_seg_prefix = false; m_seg_prefix_next = false; break; + case 0xab: CLK(3); if (c) do { i_stosw(); c--; } while (c>0); m_regs.w[CW]=c; m_seg_prefix = false; m_seg_prefix_next = false; break; + case 0xac: CLK(3); if (c) do { i_lodsb(); c--; } while (c>0); m_regs.w[CW]=c; m_seg_prefix = false; m_seg_prefix_next = false; break; + case 0xad: CLK(3); if (c) do { i_lodsw(); c--; } while (c>0); m_regs.w[CW]=c; m_seg_prefix = false; m_seg_prefix_next = false; break; + case 0xae: CLK(3); if (c) do { i_scasb(); c--; } while (c>0 && ZF); m_regs.w[CW]=c; m_seg_prefix = false; m_seg_prefix_next = false; break; + case 0xaf: CLK(3); if (c) do { i_scasw(); c--; } while (c>0 && ZF); m_regs.w[CW]=c; m_seg_prefix = false; m_seg_prefix_next = false; break; + default: + logerror("%s: %06x: REPE invalid\n", tag(), pc()); + // Decrement IP so the normal instruction will be executed next + m_ip--; + break; + } + } + break; + + case 0xf4: // i_hlt + logerror("%s: %06x: HALT\n", tag(), pc()); + m_icount = 0; + break; + + case 0xf5: // i_cmc + m_CarryVal ^= 1; + CLK(4); + break; + + case 0xf6: // i_f6pre + { + UINT32 tmp; + UINT32 uresult,uresult2; + INT32 result,result2; + + m_modrm = fetch(); + tmp = GetRMByte(); + switch ( m_modrm & 0x38 ) + { + case 0x00: /* TEST */ + tmp &= fetch(); + m_CarryVal = m_OverVal = 0; + set_SZPF_Byte(tmp); + CLKM(1,2); + break; + case 0x08: + logerror("%s: %06x: Undefined opcode 0xf6 0x08\n", tag(), pc()); + break; + case 0x10: /* NOT */ + PutbackRMByte(~tmp); + CLKM(1,3); + break; + case 0x18: /* NEG */ + m_CarryVal = (tmp!=0) ? 1 : 0; + tmp = (~tmp)+1; + set_SZPF_Byte(tmp); + PutbackRMByte(tmp&0xff); + CLKM(1,3); + break; + case 0x20: /* MULU */ + uresult = m_regs.b[AL] * tmp; + m_regs.w[AW] = (UINT16)uresult; + m_CarryVal = m_OverVal = (m_regs.b[AH]!=0) ? 1 : 0; + CLKM(3,4); + break; + case 0x28: /* MUL */ + result = (INT16)((INT8)m_regs.b[AL])*(INT16)((INT8)tmp); + m_regs.w[AW] = (UINT16)result; + m_CarryVal = m_OverVal = (m_regs.b[AH]!=0) ? 1 : 0; + CLKM(3,4); + break; + case 0x30: /* DIVU */ + if (tmp) + { + uresult = m_regs.w[AW]; + uresult2 = uresult % tmp; + if ((uresult /= tmp) > 0xff) + { + interrupt(0); + } + else + { + m_regs.b[AL] = uresult; + m_regs.b[AH] = uresult2; + } + } + else + { + interrupt(0); + } + CLKM(15,16); + break; + case 0x38: /* DIV */ + if (tmp) + { + result = (INT16)m_regs.w[AW]; + result2 = result % (INT16)((INT8)tmp); + if ((result /= (INT16)((INT8)tmp)) > 0xff) + { + interrupt(0); + } + else + { + m_regs.b[AL] = result; + m_regs.b[AH] = result2; + } + } + else + { + interrupt(0); + } + CLKM(17,18); + break; + } + } + break; + + + case 0xf7: // i_f7pre + { + UINT32 tmp,tmp2; + UINT32 uresult,uresult2; + INT32 result,result2; + + m_modrm = fetch(); + tmp = GetRMWord(); + switch ( m_modrm & 0x38 ) + { + case 0x00: /* TEST */ + tmp2 = fetch_word(); + tmp &= tmp2; + m_CarryVal = m_OverVal = 0; + set_SZPF_Word(tmp); + CLKM(1,2); + break; + case 0x08: + logerror("%s: %06x: Undefined opcode 0xf7 0x08\n", tag(), pc()); + break; + case 0x10: /* NOT */ + PutbackRMWord(~tmp); + CLKM(1,3); + break; + case 0x18: /* NEG */ + m_CarryVal = (tmp!=0) ? 1 : 0; + tmp = (~tmp) + 1; + set_SZPF_Word(tmp); + PutbackRMWord(tmp); + CLKM(1,3); + break; + case 0x20: /* MULU */ + uresult = m_regs.w[AW]*tmp; + m_regs.w[AW] = uresult & 0xffff; + m_regs.w[DW] = ((UINT32)uresult)>>16; + m_CarryVal = m_OverVal = (m_regs.w[DW] != 0) ? 1 : 0; + CLKM(3,4); + break; + case 0x28: /* MUL */ + result = (INT32)((INT16)m_regs.w[AW]) * (INT32)((INT16)tmp); + m_regs.w[AW] = result & 0xffff; + m_regs.w[DW] = result >> 16; + m_CarryVal = m_OverVal = (m_regs.w[DW] != 0) ? 1 : 0; + CLKM(3,4); + break; + case 0x30: /* DIVU */ + if (tmp) + { + uresult = (((UINT32)m_regs.w[DW]) << 16) | m_regs.w[AW]; + uresult2 = uresult % tmp; + if ((uresult /= tmp) > 0xffff) + { + interrupt(0); + } + else + { + m_regs.w[AW] = uresult; + m_regs.w[DW] = uresult2; + } + } + else + { + interrupt(0); + } + CLKM(23,24); + break; + case 0x38: /* DIV */ + if (tmp) + { + result = ((UINT32)m_regs.w[DW] << 16) + m_regs.w[AW]; + result2 = result % (INT32)((INT16)tmp); + if ((result /= (INT32)((INT16)tmp)) > 0xffff) + { + interrupt(0); + } + else + { + m_regs.w[AW] = result; + m_regs.w[DW] = result2; + } + } + else + { + interrupt(0); + } + CLKM(24,25); + break; + } + } + break; + + + case 0xf8: // i_clc + m_CarryVal = 0; + CLK(4); + break; + + case 0xf9: // i_stc + m_CarryVal = 1; + CLK(4); + break; + + case 0xfa: // i_di + m_IF = 0; + CLK(4); + break; + + case 0xfb: // i_ei + m_IF = 1; + CLK(4); + break; + + case 0xfc: // i_cld + m_DF = 0; + CLK(4); + break; + + case 0xfd: // i_std + m_DF = 1; + CLK(4); + break; + + case 0xfe: // i_fepre + { + UINT32 tmp, tmp1; + m_modrm = fetch(); + tmp = GetRMByte(); + switch ( m_modrm & 0x38 ) + { + case 0x00: /* INC */ + tmp1 = tmp+1; + m_OverVal = (tmp==0x7f); + set_AF(tmp1,tmp,1); + set_SZPF_Byte(tmp1); + PutbackRMByte(tmp1); + CLKM(1,3); + break; + case 0x08: /* DEC */ + tmp1 = tmp-1; + m_OverVal = (tmp==0x80); + set_AF(tmp1,tmp,1); + set_SZPF_Byte(tmp1); + PutbackRMByte(tmp1); + CLKM(1,3); + break; + default: + logerror("%s: %06x: FE Pre with unimplemented mod\n", tag(), pc()); + break; + } + } + break; + + case 0xff: // i_ffpre + { + UINT32 tmp, tmp1; + m_modrm = fetch(); + tmp = GetRMWord(); + switch ( m_modrm & 0x38 ) + { + case 0x00: /* INC */ + tmp1 = tmp+1; + m_OverVal = (tmp==0x7fff); + set_AF(tmp1,tmp,1); + set_SZPF_Word(tmp1); + PutbackRMWord(tmp1); + CLKM(1,3); + break; + case 0x08: /* DEC */ + tmp1 = tmp-1; + m_OverVal = (tmp==0x8000); + set_AF(tmp1,tmp,1); + set_SZPF_Word(tmp1); + PutbackRMWord(tmp1); + CLKM(1,3); + break; + case 0x10: /* CALL */ + PUSH(m_ip); + m_ip = tmp; + CLKM(5,6); + break; + case 0x18: /* CALL FAR */ + tmp1 = m_sregs[CS]; + m_sregs[CS] = GetnextRMWord(); + PUSH(tmp1); + PUSH(m_ip); + m_ip = tmp; + CLKM(5,12); + break; + case 0x20: /* JMP */ + m_ip = tmp; + CLKM(4,5); + break; + case 0x28: /* JMP FAR */ + m_ip = tmp; + m_sregs[CS] = GetnextRMWord(); + CLK(10); + break; + case 0x30: + PUSH(tmp); + CLK(1); + break; + default: + logerror("%s: %06x: FF Pre with unimplemented mod\n", tag(), pc()); + break; + } + } + break; + + default: + m_icount -= 10; + logerror("%s: %06x: Invalid Opcode %02x\n", tag(), pc(), op); + break; + + } + } +} diff --git a/src/devices/cpu/v30mz/v30mz.h b/src/devices/cpu/v30mz/v30mz.h new file mode 100644 index 00000000000..35f6ca7dbe8 --- /dev/null +++ b/src/devices/cpu/v30mz/v30mz.h @@ -0,0 +1,226 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol,Bryan McPhail +#ifndef __V30MZ_H__ +#define __V30MZ_H__ + + +struct nec_config +{ + const UINT8* v25v35_decryptiontable; // internal decryption table +}; + +enum +{ + NEC_PC=0, + NEC_IP, NEC_AW, NEC_CW, NEC_DW, NEC_BW, NEC_SP, NEC_BP, NEC_IX, NEC_IY, + NEC_FLAGS, NEC_ES, NEC_CS, NEC_SS, NEC_DS, + NEC_VECTOR, NEC_PENDING +}; + + +///////////////////////////////////////////////////////////////// + +extern const device_type V30MZ; + +class v30mz_cpu_device : public cpu_device +{ +public: + // construction/destruction + v30mz_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_execute_interface overrides + virtual UINT32 execute_min_cycles() const { return 1; } + virtual UINT32 execute_max_cycles() const { return 80; } + virtual UINT32 execute_input_lines() const { return 1; } + virtual void execute_run(); + virtual void execute_set_input(int inputnum, int state); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const { return (spacenum == AS_PROGRAM) ? &m_program_config : ( (spacenum == AS_IO) ? &m_io_config : NULL ); } + + // device_state_interface overrides + void state_string_export(const device_state_entry &entry, std::string &str); + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const { return 1; } + virtual UINT32 disasm_max_opcode_bytes() const { return 7; } + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + + void interrupt(int int_num); + + inline UINT32 pc(); + // Accessing memory and io + inline UINT8 read_byte(UINT32 addr); + inline UINT16 read_word(UINT32 addr); + inline void write_byte(UINT32 addr, UINT8 data); + inline void write_word(UINT32 addr, UINT16 data); + inline UINT8 read_port(UINT16 port); + inline void write_port(UINT16 port, UINT8 data); + + // Executing instructions + inline UINT8 fetch_op(); + inline UINT8 fetch(); + inline UINT16 fetch_word(); + inline UINT8 repx_op(); + + // Cycles passed while executing instructions + inline void CLK(UINT32 cycles); + inline void CLKM(UINT32 cycles_reg, UINT32 cycles_mem); + + // Memory handling while executing instructions + inline UINT32 default_base(int seg); + inline UINT32 get_ea(); + inline void PutbackRMByte(UINT8 data); + inline void PutbackRMWord(UINT16 data); + inline void RegByte(UINT8 data); + inline void RegWord(UINT16 data); + inline UINT8 RegByte(); + inline UINT16 RegWord(); + inline UINT16 GetRMWord(); + inline UINT16 GetnextRMWord(); + inline UINT8 GetRMByte(); + inline void PutMemB(int seg, UINT16 offset, UINT8 data); + inline void PutMemW(int seg, UINT16 offset, UINT16 data); + inline UINT8 GetMemB(int seg, UINT16 offset); + inline UINT16 GetMemW(int seg, UINT16 offset); + inline void PutImmRMWord(); + inline void PutRMWord(UINT16 val); + inline void PutRMByte(UINT8 val); + inline void PutImmRMByte(); + inline void DEF_br8(); + inline void DEF_wr16(); + inline void DEF_r8b(); + inline void DEF_r16w(); + inline void DEF_ald8(); + inline void DEF_axd16(); + + // Flags + inline void set_CFB(UINT32 x); + inline void set_CFW(UINT32 x); + inline void set_AF(UINT32 x,UINT32 y,UINT32 z); + inline void set_SF(UINT32 x); + inline void set_ZF(UINT32 x); + inline void set_PF(UINT32 x); + inline void set_SZPF_Byte(UINT32 x); + inline void set_SZPF_Word(UINT32 x); + inline void set_OFW_Add(UINT32 x,UINT32 y,UINT32 z); + inline void set_OFB_Add(UINT32 x,UINT32 y,UINT32 z); + inline void set_OFW_Sub(UINT32 x,UINT32 y,UINT32 z); + inline void set_OFB_Sub(UINT32 x,UINT32 y,UINT32 z); + inline UINT16 CompressFlags(); + inline void ExpandFlags(UINT16 f); + + // rep instructions + inline void i_insb(); + inline void i_insw(); + inline void i_outsb(); + inline void i_outsw(); + inline void i_movsb(); + inline void i_movsw(); + inline void i_cmpsb(); + inline void i_cmpsw(); + inline void i_stosb(); + inline void i_stosw(); + inline void i_lodsb(); + inline void i_lodsw(); + inline void i_scasb(); + inline void i_scasw(); + inline void i_popf(); + + // sub implementations + inline void ADDB(); + inline void ADDW(); + inline void SUBB(); + inline void SUBW(); + inline void ORB(); + inline void ORW(); + inline void ANDB(); + inline void ANDW(); + inline void XORB(); + inline void XORW(); + inline void ROL_BYTE(); + inline void ROL_WORD(); + inline void ROR_BYTE(); + inline void ROR_WORD(); + inline void ROLC_BYTE(); + inline void ROLC_WORD(); + inline void RORC_BYTE(); + inline void RORC_WORD(); + inline void SHL_BYTE(UINT8 c); + inline void SHL_WORD(UINT8 c); + inline void SHR_BYTE(UINT8 c); + inline void SHR_WORD(UINT8 c); + inline void SHRA_BYTE(UINT8 c); + inline void SHRA_WORD(UINT8 c); + inline void XchgAWReg(UINT8 reg); + inline void IncWordReg(UINT8 reg); + inline void DecWordReg(UINT8 reg); + inline void PUSH(UINT16 data); + inline UINT16 POP(); + inline void JMP(bool cond); + inline void ADJ4(INT8 param1, INT8 param2); + inline void ADJB(INT8 param1, INT8 param2); + +protected: + address_space_config m_program_config; + address_space_config m_io_config; + + union + { /* eight general registers */ + UINT16 w[8]; /* viewed as 16 bits registers */ + UINT8 b[16]; /* or as 8 bit registers */ + } m_regs; + UINT16 m_sregs[4]; + + UINT16 m_ip; + + INT32 m_SignVal; + UINT32 m_AuxVal, m_OverVal, m_ZeroVal, m_CarryVal, m_ParityVal; /* 0 or non-0 valued flags */ + UINT8 m_TF, m_IF, m_DF, m_MF; /* 0 or 1 valued flags */ /* OB[19.07.99] added Mode Flag V30 */ + UINT32 m_int_vector; + UINT32 m_pending_irq; + UINT32 m_nmi_state; + UINT32 m_irq_state; + UINT8 m_no_interrupt; + UINT8 m_fire_trap; + + address_space *m_program; + direct_read_data *m_direct; + address_space *m_io; + int m_icount; + + UINT32 m_prefix_base; /* base address of the latest prefix segment */ + bool m_seg_prefix; /* prefix segment indicator */ + bool m_seg_prefix_next; /* prefix segment for next instruction */ + + UINT32 m_ea; + UINT16 m_eo; + UINT16 m_e16; + + // Used during execution of instructions + UINT8 m_modrm; + UINT32 m_dst; + UINT32 m_src; + UINT32 m_pc; + + // Lookup tables + UINT8 m_parity_table[256]; + struct { + struct { + int w[256]; + int b[256]; + } reg; + struct { + int w[256]; + int b[256]; + } RM; + } m_Mod_RM; +}; + + +#endif /* __V30MZ_H__ */ diff --git a/src/devices/cpu/v60/am.inc b/src/devices/cpu/v60/am.inc new file mode 100644 index 00000000000..aa9c9687c8e --- /dev/null +++ b/src/devices/cpu/v60/am.inc @@ -0,0 +1,83 @@ +// license:BSD-3-Clause +// copyright-holders:Farfetch'd, R. Belmont +// NOTE for bit string / field addressing +// ************************************ +// m_moddim must be passed as 10 for bit string instructions, +// and as 11 for bit field instructions + + + + +// Addressing mode functions and tables +#include "am1.inc" // ReadAM +#include "am2.inc" // ReadAMAddress +#include "am3.inc" // WriteAM + +/* + Input: + m_modadd + m_moddim + + Output: + m_amout + amLength +*/ + +UINT32 v60_device::ReadAM() +{ + m_modm = m_modm?1:0; + m_modval = OpRead8(m_modadd); + return (this->*s_AMTable1[m_modm][m_modval >> 5])(); +} + +UINT32 v60_device::BitReadAM() +{ + m_modm = m_modm?1:0; + m_modval = OpRead8(m_modadd); + return (this->*s_BAMTable1[m_modm][m_modval >> 5])(); +} + + + +/* + Input: + m_modadd + m_moddim + + Output: + m_amout + m_amflag + amLength +*/ + +UINT32 v60_device::ReadAMAddress() +{ + m_modm = m_modm?1:0; + m_modval = OpRead8(m_modadd); + return (this->*s_AMTable2[m_modm][m_modval >> 5])(); +} + +UINT32 v60_device::BitReadAMAddress() +{ + m_modm = m_modm?1:0; + m_modval = OpRead8(m_modadd); + return (this->*s_BAMTable2[m_modm][m_modval >> 5])(); +} + +/* + Input: + m_modadd + m_moddim + m_modwritevalb / H/W + + Output: + m_amout + amLength +*/ + +UINT32 v60_device::WriteAM() +{ + m_modm = m_modm?1:0; + m_modval = OpRead8(m_modadd); + return (this->*s_AMTable3[m_modm][m_modval >> 5])(); +} diff --git a/src/devices/cpu/v60/am1.inc b/src/devices/cpu/v60/am1.inc new file mode 100644 index 00000000000..cc5e0f4a1fd --- /dev/null +++ b/src/devices/cpu/v60/am1.inc @@ -0,0 +1,1385 @@ +// license:BSD-3-Clause +// copyright-holders:Farfetch'd, R. Belmont +// AM1 Functions (for ReadAM) +// ************************** + +UINT32 v60_device::am1Register() +{ + switch (m_moddim) + { + case 0: + m_amout = (UINT8)m_reg[m_modval & 0x1F]; + break; + case 1: + m_amout = (UINT16)m_reg[m_modval & 0x1F]; + break; + case 2: + m_amout = m_reg[m_modval & 0x1F]; + break; + } + + return 1; +} + +UINT32 v60_device::am1RegisterIndirect() +{ + switch (m_moddim) + { + case 0: + m_amout = m_program->read_byte(m_reg[m_modval & 0x1F]); + break; + case 1: + m_amout = m_program->read_word_unaligned(m_reg[m_modval & 0x1F]); + break; + case 2: + m_amout = m_program->read_dword_unaligned(m_reg[m_modval & 0x1F]); + break; + } + + return 1; +} + +UINT32 v60_device::bam1RegisterIndirect() +{ + m_bamoffset = 0; + m_amout = m_program->read_dword_unaligned(m_reg[m_modval & 0x1F]); + return 1; +} + +UINT32 v60_device::am1RegisterIndirectIndexed() +{ + switch (m_moddim) + { + case 0: + m_amout = m_program->read_byte(m_reg[m_modval2 & 0x1F] + m_reg[m_modval & 0x1F]); + break; + case 1: + m_amout = m_program->read_word_unaligned(m_reg[m_modval2 & 0x1F] + m_reg[m_modval & 0x1F] * 2); + break; + case 2: + m_amout = m_program->read_dword_unaligned(m_reg[m_modval2 & 0x1F] + m_reg[m_modval & 0x1F] * 4); + break; + } + + return 2; +} + +UINT32 v60_device::bam1RegisterIndirectIndexed() +{ + m_bamoffset = m_reg[m_modval & 0x1F]; + m_amout = m_program->read_dword_unaligned(m_reg[m_modval2 & 0x1F] + m_bamoffset / 8); + m_bamoffset&=7; + return 2; +} + +UINT32 v60_device::am1Autoincrement() +{ + switch (m_moddim) + { + case 0: + m_amout = m_program->read_byte(m_reg[m_modval & 0x1F]); + m_reg[m_modval & 0x1F]++; + break; + case 1: + m_amout = m_program->read_word_unaligned(m_reg[m_modval & 0x1F]); + m_reg[m_modval & 0x1F] +=2; + break; + case 2: + m_amout = m_program->read_dword_unaligned(m_reg[m_modval & 0x1F]); + m_reg[m_modval & 0x1F] +=4; + break; + } + + return 1; +} + +UINT32 v60_device::bam1Autoincrement() +{ + m_bamoffset = 0; + m_amout = m_program->read_dword_unaligned(m_reg[m_modval & 0x1F]); + switch (m_moddim) + { + case 10: + m_reg[m_modval & 0x1F] +=1; + break; + case 11: + m_reg[m_modval & 0x1F] +=4; + break; + default: + fatalerror("CPU - BAM1 - 7\n"); + break; + } + return 1; +} + +UINT32 v60_device::am1Autodecrement() +{ + switch (m_moddim) + { + case 0: + m_reg[m_modval & 0x1F]--; + m_amout = m_program->read_byte(m_reg[m_modval & 0x1F]); + break; + case 1: + m_reg[m_modval & 0x1F]-=2; + m_amout = m_program->read_word_unaligned(m_reg[m_modval & 0x1F]); + break; + case 2: + m_reg[m_modval & 0x1F]-=4; + m_amout = m_program->read_dword_unaligned(m_reg[m_modval & 0x1F]); + break; + } + + return 1; +} + +UINT32 v60_device::bam1Autodecrement() +{ + m_bamoffset = 0; + switch (m_moddim) + { + case 10: + m_reg[m_modval & 0x1F]-=1; + break; + case 11: + m_reg[m_modval & 0x1F]-=4; + break; + default: + fatalerror("CPU - BAM1 - 7\n"); + break; + } + m_amout = m_program->read_dword_unaligned(m_reg[m_modval & 0x1F]); + return 1; +} + +UINT32 v60_device::am1Displacement8() +{ + switch (m_moddim) + { + case 0: + m_amout = m_program->read_byte(m_reg[m_modval & 0x1F] + (INT8)OpRead8(m_modadd + 1)); + break; + case 1: + m_amout = m_program->read_word_unaligned(m_reg[m_modval & 0x1F] + (INT8)OpRead8(m_modadd + 1)); + break; + case 2: + m_amout = m_program->read_dword_unaligned(m_reg[m_modval & 0x1F] + (INT8)OpRead8(m_modadd + 1)); + break; + } + + return 2; +} + +UINT32 v60_device::bam1Displacement8() +{ + m_bamoffset = m_program->read_byte(m_modadd + 1); + m_amout = m_program->read_dword_unaligned(m_reg[m_modval & 0x1F] + m_bamoffset / 8); + m_bamoffset&=7; + return 2; +} + + +UINT32 v60_device::am1Displacement16() +{ + switch (m_moddim) + { + case 0: + m_amout = m_program->read_byte(m_reg[m_modval & 0x1F] + (INT16)OpRead16(m_modadd + 1)); + break; + case 1: + m_amout = m_program->read_word_unaligned(m_reg[m_modval & 0x1F] + (INT16)OpRead16(m_modadd + 1)); + break; + case 2: + m_amout = m_program->read_dword_unaligned(m_reg[m_modval & 0x1F] + (INT16)OpRead16(m_modadd + 1)); + break; + } + + return 3; +} + +UINT32 v60_device::bam1Displacement16() +{ + m_bamoffset = OpRead16(m_modadd + 1); + m_amout = m_program->read_dword_unaligned(m_reg[m_modval & 0x1F] + m_bamoffset / 8); + m_bamoffset&=7; + return 3; +} + +UINT32 v60_device::am1Displacement32() +{ + switch (m_moddim) + { + case 0: + m_amout = m_program->read_byte(m_reg[m_modval & 0x1F] + OpRead32(m_modadd + 1)); + break; + case 1: + m_amout = m_program->read_word_unaligned(m_reg[m_modval & 0x1F] + OpRead32(m_modadd + 1)); + break; + case 2: + m_amout = m_program->read_dword_unaligned(m_reg[m_modval & 0x1F] + OpRead32(m_modadd + 1)); + break; + } + + return 5; +} + +UINT32 v60_device::bam1Displacement32() +{ + m_bamoffset = OpRead32(m_modadd + 1); + m_amout = m_program->read_dword_unaligned(m_reg[m_modval & 0x1F] + m_bamoffset / 8); + m_bamoffset&=7; + return 5; +} + +UINT32 v60_device::am1DisplacementIndexed8() +{ + switch (m_moddim) + { + case 0: + m_amout = m_program->read_byte(m_reg[m_modval2 & 0x1F] + (INT8)OpRead8(m_modadd + 2) + m_reg[m_modval & 0x1F]); + break; + case 1: + m_amout = m_program->read_word_unaligned(m_reg[m_modval2 & 0x1F] + (INT8)OpRead8(m_modadd + 2) + m_reg[m_modval & 0x1F] * 2); + break; + case 2: + m_amout = m_program->read_dword_unaligned(m_reg[m_modval2 & 0x1F] + (INT8)OpRead8(m_modadd + 2) + m_reg[m_modval & 0x1F] * 4); + break; + } + + return 3; +} + +UINT32 v60_device::bam1DisplacementIndexed8() +{ + m_bamoffset = m_reg[m_modval & 0x1F]; + m_amout = m_program->read_dword_unaligned(m_reg[m_modval2 & 0x1F] + (INT8)OpRead8(m_modadd + 2) + m_bamoffset / 8); + m_bamoffset&=7; + return 3; +} + +UINT32 v60_device::am1DisplacementIndexed16() +{ + switch (m_moddim) + { + case 0: + m_amout = m_program->read_byte(m_reg[m_modval2 & 0x1F] + (INT16)OpRead16(m_modadd + 2) + m_reg[m_modval & 0x1F]); + break; + case 1: + m_amout = m_program->read_word_unaligned(m_reg[m_modval2 & 0x1F] + (INT16)OpRead16(m_modadd + 2) + m_reg[m_modval & 0x1F] * 2); + break; + case 2: + m_amout = m_program->read_dword_unaligned(m_reg[m_modval2 & 0x1F] + (INT16)OpRead16(m_modadd + 2) + m_reg[m_modval & 0x1F] * 4); + break; + } + + return 4; +} + +UINT32 v60_device::bam1DisplacementIndexed16() +{ + m_bamoffset = m_reg[m_modval & 0x1F]; + m_amout = m_program->read_dword_unaligned(m_reg[m_modval2 & 0x1F] + (INT16)OpRead16(m_modadd + 2) + m_bamoffset / 8); + m_bamoffset&=7; + return 4; +} + +UINT32 v60_device::am1DisplacementIndexed32() +{ + switch (m_moddim) + { + case 0: + m_amout = m_program->read_byte(m_reg[m_modval2 & 0x1F] + OpRead32(m_modadd + 2) + m_reg[m_modval & 0x1F]); + break; + case 1: + m_amout = m_program->read_word_unaligned(m_reg[m_modval2 & 0x1F] + OpRead32(m_modadd + 2) + m_reg[m_modval & 0x1F] * 2); + break; + case 2: + m_amout = m_program->read_dword_unaligned(m_reg[m_modval2 & 0x1F] + OpRead32(m_modadd + 2) + m_reg[m_modval & 0x1F] * 4); + break; + } + + return 6; +} + +UINT32 v60_device::bam1DisplacementIndexed32() +{ + m_bamoffset = m_reg[m_modval & 0x1F]; + m_amout = m_program->read_dword_unaligned(m_reg[m_modval2 & 0x1F] + OpRead32(m_modadd + 2) + m_bamoffset / 8); + m_bamoffset&=7; + return 6; +} + + +UINT32 v60_device::am1PCDisplacement8() +{ + switch (m_moddim) + { + case 0: + m_amout = m_program->read_byte(PC + (INT8)OpRead8(m_modadd + 1)); + break; + case 1: + m_amout = m_program->read_word_unaligned(PC + (INT8)OpRead8(m_modadd + 1)); + break; + case 2: + m_amout = m_program->read_dword_unaligned(PC + (INT8)OpRead8(m_modadd + 1)); + break; + } + + return 2; +} + +UINT32 v60_device::bam1PCDisplacement8() +{ + m_bamoffset = OpRead8(m_modadd + 1); + m_amout = m_program->read_dword_unaligned(PC + m_bamoffset / 8); + m_bamoffset&=7; + return 2; +} + +UINT32 v60_device::am1PCDisplacement16() +{ + switch (m_moddim) + { + case 0: + m_amout = m_program->read_byte(PC + (INT16)OpRead16(m_modadd + 1)); + break; + case 1: + m_amout = m_program->read_word_unaligned(PC + (INT16)OpRead16(m_modadd + 1)); + break; + case 2: + m_amout = m_program->read_dword_unaligned(PC + (INT16)OpRead16(m_modadd + 1)); + break; + } + + return 3; +} + +UINT32 v60_device::bam1PCDisplacement16() +{ + m_bamoffset = OpRead16(m_modadd + 1); + m_amout = m_program->read_dword_unaligned(PC + m_bamoffset / 8); + m_bamoffset&=7; + return 3; +} + +UINT32 v60_device::am1PCDisplacement32() +{ + switch (m_moddim) + { + case 0: + m_amout = m_program->read_byte(PC + OpRead32(m_modadd + 1)); + break; + case 1: + m_amout = m_program->read_word_unaligned(PC + OpRead32(m_modadd + 1)); + break; + case 2: + m_amout = m_program->read_dword_unaligned(PC + OpRead32(m_modadd + 1)); + break; + } + + return 5; +} + +UINT32 v60_device::bam1PCDisplacement32() +{ + m_bamoffset = OpRead32(m_modadd + 1); + m_amout = m_program->read_dword_unaligned(PC + m_bamoffset / 8); + m_bamoffset&=7; + return 5; +} + +UINT32 v60_device::am1PCDisplacementIndexed8() +{ + switch (m_moddim) + { + case 0: + m_amout = m_program->read_byte(PC + (INT8)OpRead8(m_modadd + 2) + m_reg[m_modval & 0x1F]); + break; + case 1: + m_amout = m_program->read_word_unaligned(PC + (INT8)OpRead8(m_modadd + 2) + m_reg[m_modval & 0x1F] * 2); + break; + case 2: + m_amout = m_program->read_dword_unaligned(PC + (INT8)OpRead8(m_modadd + 2) + m_reg[m_modval & 0x1F] * 4); + break; + } + + return 3; +} + +UINT32 v60_device::bam1PCDisplacementIndexed8() +{ + m_bamoffset = m_reg[m_modval & 0x1F]; + m_amout = m_program->read_dword_unaligned(PC + (INT8)OpRead8(m_modadd + 2) + m_bamoffset / 8); + m_bamoffset&=7; + return 3; +} + + +UINT32 v60_device::am1PCDisplacementIndexed16() +{ + switch (m_moddim) + { + case 0: + m_amout = m_program->read_byte(PC + (INT16)OpRead16(m_modadd + 2) + m_reg[m_modval & 0x1F]); + break; + case 1: + m_amout = m_program->read_word_unaligned(PC + (INT16)OpRead16(m_modadd + 2) + m_reg[m_modval & 0x1F] * 2); + break; + case 2: + m_amout = m_program->read_dword_unaligned(PC + (INT16)OpRead16(m_modadd + 2) + m_reg[m_modval & 0x1F] * 4); + break; + } + + return 4; +} + +UINT32 v60_device::bam1PCDisplacementIndexed16() +{ + m_bamoffset = m_reg[m_modval & 0x1F]; + m_amout = m_program->read_dword_unaligned(PC + (INT16)OpRead16(m_modadd + 2) + m_bamoffset / 8); + m_bamoffset&=7; + return 4; +} + +UINT32 v60_device::am1PCDisplacementIndexed32() +{ + switch (m_moddim) + { + case 0: + m_amout = m_program->read_byte(PC + OpRead32(m_modadd + 2) + m_reg[m_modval & 0x1F]); + break; + case 1: + m_amout = m_program->read_word_unaligned(PC + OpRead32(m_modadd + 2) + m_reg[m_modval & 0x1F] * 2); + break; + case 2: + m_amout = m_program->read_dword_unaligned(PC + OpRead32(m_modadd + 2) + m_reg[m_modval & 0x1F] * 4); + break; + } + + return 6; +} + +UINT32 v60_device::bam1PCDisplacementIndexed32() +{ + m_bamoffset = m_reg[m_modval & 0x1F]; + m_amout = m_program->read_dword_unaligned(PC + OpRead32(m_modadd + 2) + m_bamoffset / 8); + m_bamoffset&=7; + return 6; +} + +UINT32 v60_device::am1DisplacementIndirect8() +{ + switch (m_moddim) + { + case 0: + m_amout = m_program->read_byte(m_program->read_dword_unaligned(m_reg[m_modval & 0x1F] + (INT8)OpRead8(m_modadd + 1))); + break; + case 1: + m_amout = m_program->read_word_unaligned(m_program->read_dword_unaligned(m_reg[m_modval & 0x1F] + (INT8)OpRead8(m_modadd + 1))); + break; + case 2: + m_amout = m_program->read_dword_unaligned(m_program->read_dword_unaligned(m_reg[m_modval & 0x1F] + (INT8)OpRead8(m_modadd + 1))); + break; + } + + return 2; +} + +UINT32 v60_device::bam1DisplacementIndirect8() +{ + m_bamoffset = 0; + m_amout = m_program->read_dword_unaligned(m_program->read_dword_unaligned(m_reg[m_modval & 0x1F] + (INT8)OpRead8(m_modadd + 1))); + return 2; +} + +UINT32 v60_device::am1DisplacementIndirect16() +{ + switch (m_moddim) + { + case 0: + m_amout = m_program->read_byte(m_program->read_dword_unaligned(m_reg[m_modval & 0x1F] + (INT16)OpRead16(m_modadd + 1))); + break; + case 1: + m_amout = m_program->read_word_unaligned(m_program->read_dword_unaligned(m_reg[m_modval & 0x1F] + (INT16)OpRead16(m_modadd + 1))); + break; + case 2: + m_amout = m_program->read_dword_unaligned(m_program->read_dword_unaligned(m_reg[m_modval & 0x1F] + (INT16)OpRead16(m_modadd + 1))); + break; + } + + return 3; +} + +UINT32 v60_device::bam1DisplacementIndirect16() +{ + m_bamoffset = 0; + m_amout = m_program->read_dword_unaligned(m_program->read_dword_unaligned(m_reg[m_modval & 0x1F] + (INT16)OpRead16(m_modadd + 1))); + return 3; +} + +UINT32 v60_device::am1DisplacementIndirect32() +{ + switch (m_moddim) + { + case 0: + m_amout = m_program->read_byte(m_program->read_dword_unaligned(m_reg[m_modval & 0x1F] + OpRead32(m_modadd + 1))); + break; + case 1: + m_amout = m_program->read_word_unaligned(m_program->read_dword_unaligned(m_reg[m_modval & 0x1F] + OpRead32(m_modadd + 1))); + break; + case 2: + m_amout = m_program->read_dword_unaligned(m_program->read_dword_unaligned(m_reg[m_modval & 0x1F] + OpRead32(m_modadd + 1))); + break; + } + + return 5; +} + +UINT32 v60_device::bam1DisplacementIndirect32() +{ + m_bamoffset = 0; + m_amout = m_program->read_dword_unaligned(m_program->read_dword_unaligned(m_reg[m_modval & 0x1F] + OpRead32(m_modadd + 1))); + return 5; +} + +UINT32 v60_device::am1DisplacementIndirectIndexed8() +{ + switch (m_moddim) + { + case 0: + m_amout = m_program->read_byte(m_program->read_dword_unaligned(m_reg[m_modval2 & 0x1F] + (INT8)OpRead8(m_modadd + 2)) + m_reg[m_modval & 0x1F]); + break; + case 1: + m_amout = m_program->read_word_unaligned(m_program->read_dword_unaligned(m_reg[m_modval2 & 0x1F] + (INT8)OpRead8(m_modadd + 2)) + m_reg[m_modval & 0x1F] * 2); + break; + case 2: + m_amout = m_program->read_dword_unaligned(m_program->read_dword_unaligned(m_reg[m_modval2 & 0x1F] + (INT8)OpRead8(m_modadd + 2)) + m_reg[m_modval & 0x1F] * 4); + break; + } + + return 3; +} + +UINT32 v60_device::bam1DisplacementIndirectIndexed8() +{ + m_bamoffset = m_reg[m_modval & 0x1F]; + m_amout = m_program->read_dword_unaligned(m_program->read_dword_unaligned(m_reg[m_modval2 & 0x1F] + (INT8)OpRead8(m_modadd + 2)) + m_bamoffset / 8); + m_bamoffset&=7; + return 3; +} + +UINT32 v60_device::am1DisplacementIndirectIndexed16() +{ + switch (m_moddim) + { + case 0: + m_amout = m_program->read_byte(m_program->read_dword_unaligned(m_reg[m_modval2 & 0x1F] + (INT16)OpRead16(m_modadd + 2)) + m_reg[m_modval & 0x1F]); + break; + case 1: + m_amout = m_program->read_word_unaligned(m_program->read_dword_unaligned(m_reg[m_modval2 & 0x1F] + (INT16)OpRead16(m_modadd + 2)) + m_reg[m_modval & 0x1F] * 2); + break; + case 2: + m_amout = m_program->read_dword_unaligned(m_program->read_dword_unaligned(m_reg[m_modval2 & 0x1F] + (INT16)OpRead16(m_modadd + 2)) + m_reg[m_modval & 0x1F] * 4); + break; + } + + return 4; +} + +UINT32 v60_device::bam1DisplacementIndirectIndexed16() +{ + m_bamoffset = m_reg[m_modval & 0x1F]; + m_amout = m_program->read_dword_unaligned(m_program->read_dword_unaligned(m_reg[m_modval2 & 0x1F] + (INT16)OpRead16(m_modadd + 2)) + m_bamoffset / 8); + m_bamoffset&=7; + return 4; +} + +UINT32 v60_device::am1DisplacementIndirectIndexed32() +{ + switch (m_moddim) + { + case 0: + m_amout = m_program->read_byte(m_program->read_dword_unaligned(m_reg[m_modval2 & 0x1F] + OpRead32(m_modadd + 2)) + m_reg[m_modval & 0x1F]); + break; + case 1: + m_amout = m_program->read_word_unaligned(m_program->read_dword_unaligned(m_reg[m_modval2 & 0x1F] + OpRead32(m_modadd + 2)) + m_reg[m_modval & 0x1F] * 2); + break; + case 2: + m_amout = m_program->read_dword_unaligned(m_program->read_dword_unaligned(m_reg[m_modval2 & 0x1F] + OpRead32(m_modadd + 2)) + m_reg[m_modval & 0x1F] * 4); + break; + } + + return 6; +} + +UINT32 v60_device::bam1DisplacementIndirectIndexed32() +{ + m_bamoffset = m_reg[m_modval & 0x1F]; + m_amout = m_program->read_dword_unaligned(m_program->read_dword_unaligned(m_reg[m_modval2 & 0x1F] + OpRead32(m_modadd + 2)) + m_bamoffset / 8); + m_bamoffset&=7; + return 6; +} + +UINT32 v60_device::am1PCDisplacementIndirect8() +{ + switch (m_moddim) + { + case 0: + m_amout = m_program->read_byte(m_program->read_dword_unaligned(PC + (INT8)OpRead8(m_modadd + 1))); + break; + case 1: + m_amout = m_program->read_word_unaligned(m_program->read_dword_unaligned(PC + (INT8)OpRead8(m_modadd + 1))); + break; + case 2: + m_amout = m_program->read_dword_unaligned(m_program->read_dword_unaligned(PC + (INT8)OpRead8(m_modadd + 1))); + break; + } + + return 2; +} + +UINT32 v60_device::bam1PCDisplacementIndirect8() +{ + m_bamoffset = 0; + m_amout = m_program->read_dword_unaligned(m_program->read_dword_unaligned(PC + (INT8)OpRead8(m_modadd + 1))); + return 2; +} + +UINT32 v60_device::am1PCDisplacementIndirect16() +{ + switch (m_moddim) + { + case 0: + m_amout = m_program->read_byte(m_program->read_dword_unaligned(PC + (INT16)OpRead16(m_modadd + 1))); + break; + case 1: + m_amout = m_program->read_word_unaligned(m_program->read_dword_unaligned(PC + (INT16)OpRead16(m_modadd + 1))); + break; + case 2: + m_amout = m_program->read_dword_unaligned(m_program->read_dword_unaligned(PC + (INT16)OpRead16(m_modadd + 1))); + break; + } + + return 3; +} + +UINT32 v60_device::bam1PCDisplacementIndirect16() +{ + m_bamoffset = 0; + m_amout = m_program->read_dword_unaligned(m_program->read_dword_unaligned(PC + (INT16)OpRead16(m_modadd + 1))); + return 3; +} + +UINT32 v60_device::am1PCDisplacementIndirect32() +{ + switch (m_moddim) + { + case 0: + m_amout = m_program->read_byte(m_program->read_dword_unaligned(PC + OpRead32(m_modadd + 1))); + break; + case 1: + m_amout = m_program->read_word_unaligned(m_program->read_dword_unaligned(PC + OpRead32(m_modadd + 1))); + break; + case 2: + m_amout = m_program->read_dword_unaligned(m_program->read_dword_unaligned(PC + OpRead32(m_modadd + 1))); + break; + } + + return 5; +} + +UINT32 v60_device::bam1PCDisplacementIndirect32() +{ + m_bamoffset = 0; + m_amout = m_program->read_dword_unaligned(m_program->read_dword_unaligned(PC + OpRead32(m_modadd + 1))); + return 5; +} + +UINT32 v60_device::am1PCDisplacementIndirectIndexed8() +{ + switch (m_moddim) + { + case 0: + m_amout = m_program->read_byte(m_program->read_dword_unaligned(PC + (INT8)OpRead8(m_modadd + 2)) + m_reg[m_modval & 0x1F]); + break; + case 1: + m_amout = m_program->read_word_unaligned(m_program->read_dword_unaligned(PC + (INT8)OpRead8(m_modadd + 2)) + m_reg[m_modval & 0x1F] * 2); + break; + case 2: + m_amout = m_program->read_dword_unaligned(m_program->read_dword_unaligned(PC + (INT8)OpRead8(m_modadd + 2)) + m_reg[m_modval & 0x1F] * 4); + break; + } + + return 3; +} + +UINT32 v60_device::bam1PCDisplacementIndirectIndexed8() +{ + m_bamoffset = m_reg[m_modval & 0x1F]; + m_amout = m_program->read_dword_unaligned(m_program->read_dword_unaligned(PC + (INT8)OpRead8(m_modadd + 2)) + m_bamoffset / 8); + m_bamoffset&=7; + return 3; +} + +UINT32 v60_device::am1PCDisplacementIndirectIndexed16() +{ + switch (m_moddim) + { + case 0: + m_amout = m_program->read_byte(m_program->read_dword_unaligned(PC + (INT16)OpRead16(m_modadd + 2)) + m_reg[m_modval & 0x1F]); + break; + case 1: + m_amout = m_program->read_word_unaligned(m_program->read_dword_unaligned(PC + (INT16)OpRead16(m_modadd + 2)) + m_reg[m_modval & 0x1F] * 2); + break; + case 2: + m_amout = m_program->read_dword_unaligned(m_program->read_dword_unaligned(PC + (INT16)OpRead16(m_modadd + 2)) + m_reg[m_modval & 0x1F] * 4); + break; + } + + return 4; +} + +UINT32 v60_device::bam1PCDisplacementIndirectIndexed16() +{ + m_bamoffset = m_reg[m_modval & 0x1F]; + m_amout = m_program->read_dword_unaligned(m_program->read_dword_unaligned(PC + (INT16)OpRead16(m_modadd + 2)) + m_bamoffset / 8); + m_bamoffset&=7; + return 4; +} + +UINT32 v60_device::am1PCDisplacementIndirectIndexed32() +{ + switch (m_moddim) + { + case 0: + m_amout = m_program->read_byte(m_program->read_dword_unaligned(PC + OpRead32(m_modadd + 2)) + m_reg[m_modval & 0x1F]); + break; + case 1: + m_amout = m_program->read_word_unaligned(m_program->read_dword_unaligned(PC + OpRead32(m_modadd + 2)) + m_reg[m_modval & 0x1F] * 2); + break; + case 2: + m_amout = m_program->read_dword_unaligned(m_program->read_dword_unaligned(PC + OpRead32(m_modadd + 2)) + m_reg[m_modval & 0x1F] * 4); + break; + } + + return 6; +} + +UINT32 v60_device::bam1PCDisplacementIndirectIndexed32() +{ + m_bamoffset = m_reg[m_modval & 0x1F]; + m_amout = m_program->read_dword_unaligned(m_program->read_dword_unaligned(PC + OpRead32(m_modadd + 2)) + m_bamoffset / 8); + m_bamoffset&=7; + return 6; +} + +UINT32 v60_device::am1DoubleDisplacement8() +{ + switch (m_moddim) + { + case 0: + m_amout = m_program->read_byte(m_program->read_dword_unaligned(m_reg[m_modval & 0x1F] + (INT8)OpRead8(m_modadd + 1)) + (INT8)OpRead8(m_modadd + 2)); + break; + + case 1: + m_amout = m_program->read_word_unaligned(m_program->read_dword_unaligned(m_reg[m_modval & 0x1F] + (INT8)OpRead8(m_modadd + 1)) + (INT8)OpRead8(m_modadd + 2)); + break; + + case 2: + m_amout = m_program->read_dword_unaligned(m_program->read_dword_unaligned(m_reg[m_modval & 0x1F] + (INT8)OpRead8(m_modadd + 1)) + (INT8)OpRead8(m_modadd + 2)); + break; + } + + return 3; +} + +UINT32 v60_device::bam1DoubleDisplacement8() +{ + m_bamoffset = OpRead8(m_modadd + 2); + m_amout = m_program->read_dword_unaligned(m_program->read_dword_unaligned(m_reg[m_modval & 0x1F] + (INT8)OpRead8(m_modadd + 1)) + m_bamoffset / 8); + m_bamoffset&=7; + return 3; +} + +UINT32 v60_device::am1DoubleDisplacement16() +{ + switch (m_moddim) + { + case 0: + m_amout = m_program->read_byte(m_program->read_dword_unaligned(m_reg[m_modval & 0x1F] + (INT16)OpRead16(m_modadd + 1)) + (INT16)OpRead16(m_modadd + 3)); + break; + + case 1: + m_amout = m_program->read_word_unaligned(m_program->read_dword_unaligned(m_reg[m_modval & 0x1F] + (INT16)OpRead16(m_modadd + 1)) + (INT16)OpRead16(m_modadd + 3)); + break; + + case 2: + m_amout = m_program->read_dword_unaligned(m_program->read_dword_unaligned(m_reg[m_modval & 0x1F] + (INT16)OpRead16(m_modadd + 1)) + (INT16)OpRead16(m_modadd + 3)); + break; + } + + return 5; +} + +UINT32 v60_device::bam1DoubleDisplacement16() +{ + m_bamoffset = OpRead16(m_modadd + 3); + m_amout = m_program->read_dword_unaligned(m_program->read_dword_unaligned(m_reg[m_modval & 0x1F] + (INT16)OpRead16(m_modadd + 1)) + m_bamoffset / 8); + m_bamoffset&=7; + return 5; +} + +UINT32 v60_device::am1DoubleDisplacement32() +{ + switch (m_moddim) + { + case 0: + m_amout = m_program->read_byte(m_program->read_dword_unaligned(m_reg[m_modval & 0x1F] + OpRead32(m_modadd + 1)) + OpRead32(m_modadd + 5)); + break; + + case 1: + m_amout = m_program->read_word_unaligned(m_program->read_dword_unaligned(m_reg[m_modval & 0x1F] + OpRead32(m_modadd + 1)) + OpRead32(m_modadd + 5)); + break; + + case 2: + m_amout = m_program->read_dword_unaligned(m_program->read_dword_unaligned(m_reg[m_modval & 0x1F] + OpRead32(m_modadd + 1)) + OpRead32(m_modadd + 5)); + break; + } + + return 9; +} + +UINT32 v60_device::bam1DoubleDisplacement32() +{ + m_bamoffset = OpRead32(m_modadd + 5); + m_amout = m_program->read_dword_unaligned(m_program->read_dword_unaligned(m_reg[m_modval & 0x1F] + OpRead32(m_modadd + 1)) + m_bamoffset / 8); + m_bamoffset&=7; + return 9; +} + +UINT32 v60_device::am1PCDoubleDisplacement8() +{ + switch (m_moddim) + { + case 0: + m_amout = m_program->read_byte(m_program->read_dword_unaligned(PC + (INT8)OpRead8(m_modadd + 1)) + (INT8)OpRead8(m_modadd + 2)); + break; + + case 1: + m_amout = m_program->read_word_unaligned(m_program->read_dword_unaligned(PC + (INT8)OpRead8(m_modadd + 1)) + (INT8)OpRead8(m_modadd + 2)); + break; + + case 2: + m_amout = m_program->read_dword_unaligned(m_program->read_dword_unaligned(PC + (INT8)OpRead8(m_modadd + 1)) + (INT8)OpRead8(m_modadd + 2)); + break; + } + + return 3; +} + +UINT32 v60_device::bam1PCDoubleDisplacement8() +{ + m_bamoffset = OpRead8(m_modadd + 2); + m_amout = m_program->read_dword_unaligned(m_program->read_dword_unaligned(PC + (INT8)OpRead8(m_modadd + 1)) + m_bamoffset / 8); + m_bamoffset&=7; + return 3; +} + +UINT32 v60_device::am1PCDoubleDisplacement16() +{ + switch (m_moddim) + { + case 0: + m_amout = m_program->read_byte(m_program->read_dword_unaligned(PC + (INT16)OpRead16(m_modadd + 1)) + (INT16)OpRead16(m_modadd + 3)); + break; + + case 1: + m_amout = m_program->read_word_unaligned(m_program->read_dword_unaligned(PC + (INT16)OpRead16(m_modadd + 1)) + (INT16)OpRead16(m_modadd + 3)); + break; + + case 2: + m_amout = m_program->read_dword_unaligned(m_program->read_dword_unaligned(PC + (INT16)OpRead16(m_modadd + 1)) + (INT16)OpRead16(m_modadd + 3)); + break; + } + + return 5; +} + +UINT32 v60_device::bam1PCDoubleDisplacement16() +{ + m_bamoffset = OpRead16(m_modadd + 3); + m_amout = m_program->read_dword_unaligned(m_program->read_dword_unaligned(PC + (INT16)OpRead16(m_modadd + 1)) + m_bamoffset / 8); + m_bamoffset&=7; + return 5; +} + + +UINT32 v60_device::am1PCDoubleDisplacement32() +{ + switch (m_moddim) + { + case 0: + m_amout = m_program->read_byte(m_program->read_dword_unaligned(PC + OpRead32(m_modadd + 1)) + OpRead32(m_modadd + 5)); + break; + + case 1: + m_amout = m_program->read_word_unaligned(m_program->read_dword_unaligned(PC + OpRead32(m_modadd + 1)) + OpRead32(m_modadd + 5)); + break; + + case 2: + m_amout = m_program->read_dword_unaligned(m_program->read_dword_unaligned(PC + OpRead32(m_modadd + 1)) + OpRead32(m_modadd + 5)); + break; + } + + return 9; +} + +UINT32 v60_device::bam1PCDoubleDisplacement32() +{ + m_bamoffset = OpRead32(m_modadd + 5); + m_amout = m_program->read_dword_unaligned(m_program->read_dword_unaligned(PC + OpRead32(m_modadd + 1)) + m_bamoffset / 8); + m_bamoffset&=7; + return 9; +} + +UINT32 v60_device::am1DirectAddress() +{ + switch (m_moddim) + { + case 0: + m_amout = m_program->read_byte(OpRead32(m_modadd + 1)); + break; + + case 1: + m_amout = m_program->read_word_unaligned(OpRead32(m_modadd + 1)); + break; + + case 2: + m_amout = m_program->read_dword_unaligned(OpRead32(m_modadd + 1)); + break; + } + + return 5; +} + +UINT32 v60_device::bam1DirectAddress() +{ + m_bamoffset = 0; + m_amout = m_program->read_dword_unaligned(OpRead32(m_modadd + 1)); + return 5; +} + +UINT32 v60_device::am1DirectAddressIndexed() +{ + switch (m_moddim) + { + case 0: + m_amout = m_program->read_byte(OpRead32(m_modadd + 2) + m_reg[m_modval & 0x1F]); + break; + + case 1: + m_amout = m_program->read_word_unaligned(OpRead32(m_modadd + 2) + m_reg[m_modval & 0x1F] * 2); + break; + + case 2: + m_amout = m_program->read_dword_unaligned(OpRead32(m_modadd + 2) + m_reg[m_modval & 0x1F] * 4); + break; + } + + return 6; +} + +UINT32 v60_device::bam1DirectAddressIndexed() +{ + m_bamoffset = m_reg[m_modval & 0x1F]; + m_amout = m_program->read_dword_unaligned(OpRead32(m_modadd + 2) + m_bamoffset / 8); + m_bamoffset&=7; + return 6; +} + +UINT32 v60_device::am1DirectAddressDeferred() +{ + switch (m_moddim) + { + case 0: + m_amout = m_program->read_byte(m_program->read_dword_unaligned(OpRead32(m_modadd + 1))); + break; + + case 1: + m_amout = m_program->read_word_unaligned(m_program->read_dword_unaligned(OpRead32(m_modadd + 1))); + break; + + case 2: + m_amout = m_program->read_dword_unaligned(m_program->read_dword_unaligned(OpRead32(m_modadd + 1))); + break; + } + + return 5; +} + +UINT32 v60_device::bam1DirectAddressDeferred() +{ + m_bamoffset = 0; + m_amout = m_program->read_dword_unaligned(m_program->read_dword_unaligned(OpRead32(m_modadd + 1))); + return 5; +} + +UINT32 v60_device::am1DirectAddressDeferredIndexed() +{ + switch (m_moddim) + { + case 0: + m_amout = m_program->read_byte(m_program->read_dword_unaligned(OpRead32(m_modadd + 2)) + m_reg[m_modval & 0x1F]); + break; + + case 1: + m_amout = m_program->read_word_unaligned(m_program->read_dword_unaligned(OpRead32(m_modadd + 2)) + m_reg[m_modval & 0x1F] * 2); + break; + + case 2: + m_amout = m_program->read_dword_unaligned(m_program->read_dword_unaligned(OpRead32(m_modadd + 2)) + m_reg[m_modval & 0x1F] * 4); + break; + } + + return 6; +} + +UINT32 v60_device::bam1DirectAddressDeferredIndexed() +{ + m_bamoffset = m_reg[m_modval & 0x1F]; + m_amout = m_program->read_dword_unaligned(m_program->read_dword_unaligned(OpRead32(m_modadd + 2)) + m_bamoffset / 8); + m_bamoffset&=7; + return 6; +} + +UINT32 v60_device::am1Immediate() +{ + switch (m_moddim) + { + case 0: + m_amout = OpRead8(m_modadd + 1); + return 2; + + case 1: + m_amout = OpRead16(m_modadd + 1); + return 3; + + case 2: + m_amout = OpRead32(m_modadd + 1); + return 5; + } + + // It should not be here! Written to avoid warning + assert(0); + return 1; +} + +UINT32 v60_device::am1ImmediateQuick() +{ + m_amout = m_modval & 0xF; + return 1; +} + + + + +// AM1 Tables (for ReadAM) +// *********************** + +UINT32 v60_device::am1Error1() +{ + fatalerror("CPU - AM1 - 1 (PC=%06x)\n", PC); + return 0; /* never reached, fatalerror won't return */ +} + +UINT32 v60_device::bam1Error1() +{ + fatalerror("CPU - BAM1 - 1 (PC=%06x)\n", PC); + return 0; /* never reached, fatalerror won't return */ +} + +UINT32 v60_device::am1Error2() +{ + fatalerror("CPU - AM1 - 2 (PC=%06x)\n", PC); + return 0; /* never reached, fatalerror won't return */ +} + +UINT32 v60_device::bam1Error2() +{ + fatalerror("CPU - BAM1 - 2 (PC=%06x)\n", PC); + return 0; /* never reached, fatalerror won't return */ +} + +#ifdef UNUSED_FUNCTION +UINT32 v60_device::am1Error3() +{ + fatalerror("CPU - AM1 - 3 (PC=%06x)\n", PC); + return 0; /* never reached, fatalerror won't return */ +} + +UINT32 v60_device::bam1Error3() +{ + fatalerror("CPU - BAM1 - 3 (PC=%06x)\n", PC); + return 0; /* never reached, fatalerror won't return */ +} +#endif + +UINT32 v60_device::am1Error4() +{ + fatalerror("CPU - AM1 - 4 (PC=%06x)\n", PC); + return 0; /* never reached, fatalerror won't return */ +} + +UINT32 v60_device::bam1Error4() +{ + fatalerror("CPU - BAM1 - 4 (PC=%06x)\n", PC); + return 0; /* never reached, fatalerror won't return */ +} + +UINT32 v60_device::am1Error5() +{ + fatalerror("CPU - AM1 - 5 (PC=%06x)\n", PC); + return 0; /* never reached, fatalerror won't return */ +} + +UINT32 v60_device::bam1Error5() +{ + fatalerror("CPU - BAM1 - 5 (PC=%06x)\n", PC); + return 0; /* never reached, fatalerror won't return */ +} + +UINT32 v60_device::bam1Error6() +{ + fatalerror("CPU - BAM1 - 6 (PC=%06x)\n", PC); + return 0; /* never reached, fatalerror won't return */ +} + +const v60_device::am_func v60_device::s_AMTable1_G7a[16] = +{ + &v60_device::am1PCDisplacementIndexed8, + &v60_device::am1PCDisplacementIndexed16, + &v60_device::am1PCDisplacementIndexed32, + &v60_device::am1DirectAddressIndexed, + &v60_device::am1Error5, + &v60_device::am1Error5, + &v60_device::am1Error5, + &v60_device::am1Error5, + &v60_device::am1PCDisplacementIndirectIndexed8, + &v60_device::am1PCDisplacementIndirectIndexed16, + &v60_device::am1PCDisplacementIndirectIndexed32, + &v60_device::am1DirectAddressDeferredIndexed, + &v60_device::am1Error5, + &v60_device::am1Error5, + &v60_device::am1Error5, + &v60_device::am1Error5 +}; + +const v60_device::am_func v60_device::s_BAMTable1_G7a[16] = +{ + &v60_device::bam1PCDisplacementIndexed8, + &v60_device::bam1PCDisplacementIndexed16, + &v60_device::bam1PCDisplacementIndexed32, + &v60_device::bam1DirectAddressIndexed, + &v60_device::bam1Error5, + &v60_device::bam1Error5, + &v60_device::bam1Error5, + &v60_device::bam1Error5, + &v60_device::bam1PCDisplacementIndirectIndexed8, + &v60_device::bam1PCDisplacementIndirectIndexed16, + &v60_device::bam1PCDisplacementIndirectIndexed32, + &v60_device::bam1DirectAddressDeferredIndexed, + &v60_device::bam1Error5, + &v60_device::bam1Error5, + &v60_device::bam1Error5, + &v60_device::bam1Error5 +}; + + +UINT32 v60_device::am1Group7a() +{ + if (!(m_modval2 & 0x10)) + return am1Error4(); + + return (this->*s_AMTable1_G7a[m_modval2 & 0xF])(); +} + +UINT32 v60_device::bam1Group7a() +{ + if (!(m_modval2 & 0x10)) + return bam1Error4(); + + return (this->*s_BAMTable1_G7a[m_modval2 & 0xF])(); +} + +const v60_device::am_func v60_device::s_AMTable1_G7[32] = +{ + &v60_device::am1ImmediateQuick, + &v60_device::am1ImmediateQuick, + &v60_device::am1ImmediateQuick, + &v60_device::am1ImmediateQuick, + &v60_device::am1ImmediateQuick, + &v60_device::am1ImmediateQuick, + &v60_device::am1ImmediateQuick, + &v60_device::am1ImmediateQuick, + &v60_device::am1ImmediateQuick, + &v60_device::am1ImmediateQuick, + &v60_device::am1ImmediateQuick, + &v60_device::am1ImmediateQuick, + &v60_device::am1ImmediateQuick, + &v60_device::am1ImmediateQuick, + &v60_device::am1ImmediateQuick, + &v60_device::am1ImmediateQuick, + &v60_device::am1PCDisplacement8, + &v60_device::am1PCDisplacement16, + &v60_device::am1PCDisplacement32, + &v60_device::am1DirectAddress, + &v60_device::am1Immediate, + &v60_device::am1Error2, + &v60_device::am1Error2, + &v60_device::am1Error2, + &v60_device::am1PCDisplacementIndirect8, + &v60_device::am1PCDisplacementIndirect16, + &v60_device::am1PCDisplacementIndirect32, + &v60_device::am1DirectAddressDeferred, + &v60_device::am1PCDoubleDisplacement8, + &v60_device::am1PCDoubleDisplacement16, + &v60_device::am1PCDoubleDisplacement32, + &v60_device::am1Error2 +}; + +const v60_device::am_func v60_device::s_BAMTable1_G7[32] = +{ + &v60_device::bam1Error6, + &v60_device::bam1Error6, + &v60_device::bam1Error6, + &v60_device::bam1Error6, + &v60_device::bam1Error6, + &v60_device::bam1Error6, + &v60_device::bam1Error6, + &v60_device::bam1Error6, + &v60_device::bam1Error6, + &v60_device::bam1Error6, + &v60_device::bam1Error6, + &v60_device::bam1Error6, + &v60_device::bam1Error6, + &v60_device::bam1Error6, + &v60_device::bam1Error6, + &v60_device::bam1Error6, + &v60_device::bam1PCDisplacement8, + &v60_device::bam1PCDisplacement16, + &v60_device::bam1PCDisplacement32, + &v60_device::bam1DirectAddress, + &v60_device::bam1Error6, + &v60_device::bam1Error2, + &v60_device::bam1Error2, + &v60_device::bam1Error2, + &v60_device::bam1PCDisplacementIndirect8, + &v60_device::bam1PCDisplacementIndirect16, + &v60_device::bam1PCDisplacementIndirect32, + &v60_device::bam1DirectAddressDeferred, + &v60_device::bam1PCDoubleDisplacement8, + &v60_device::bam1PCDoubleDisplacement16, + &v60_device::bam1PCDoubleDisplacement32, + &v60_device::bam1Error2 +}; + + + +const v60_device::am_func v60_device::s_AMTable1_G6[8] = +{ + &v60_device::am1DisplacementIndexed8, + &v60_device::am1DisplacementIndexed16, + &v60_device::am1DisplacementIndexed32, + &v60_device::am1RegisterIndirectIndexed, + &v60_device::am1DisplacementIndirectIndexed8, + &v60_device::am1DisplacementIndirectIndexed16, + &v60_device::am1DisplacementIndirectIndexed32, + &v60_device::am1Group7a +}; + +const v60_device::am_func v60_device::s_BAMTable1_G6[8] = +{ + &v60_device::bam1DisplacementIndexed8, + &v60_device::bam1DisplacementIndexed16, + &v60_device::bam1DisplacementIndexed32, + &v60_device::bam1RegisterIndirectIndexed, + &v60_device::bam1DisplacementIndirectIndexed8, + &v60_device::bam1DisplacementIndirectIndexed16, + &v60_device::bam1DisplacementIndirectIndexed32, + &v60_device::bam1Group7a +}; + + +UINT32 v60_device::am1Group6() +{ + m_modval2 = OpRead8(m_modadd + 1); + return (this->*s_AMTable1_G6[m_modval2 >> 5])(); +} + +UINT32 v60_device::bam1Group6() +{ + m_modval2 = OpRead8(m_modadd + 1); + return (this->*s_BAMTable1_G6[m_modval2 >> 5])(); +} + + +UINT32 v60_device::am1Group7() +{ + return (this->*s_AMTable1_G7[m_modval & 0x1F])(); +} + +UINT32 v60_device::bam1Group7() +{ + return (this->*s_BAMTable1_G7[m_modval & 0x1F])(); +} + +const v60_device::am_func v60_device::s_AMTable1[2][8] = +{ + { + &v60_device::am1Displacement8, + &v60_device::am1Displacement16, + &v60_device::am1Displacement32, + &v60_device::am1RegisterIndirect, + &v60_device::am1DisplacementIndirect8, + &v60_device::am1DisplacementIndirect16, + &v60_device::am1DisplacementIndirect32, + &v60_device::am1Group7 + }, + + { + &v60_device::am1DoubleDisplacement8, + &v60_device::am1DoubleDisplacement16, + &v60_device::am1DoubleDisplacement32, + &v60_device::am1Register, + &v60_device::am1Autoincrement, + &v60_device::am1Autodecrement, + &v60_device::am1Group6, + &v60_device::am1Error1 + } +}; + + +const v60_device::am_func v60_device::s_BAMTable1[2][8] = +{ + { + &v60_device::bam1Displacement8, + &v60_device::bam1Displacement16, + &v60_device::bam1Displacement32, + &v60_device::bam1RegisterIndirect, + &v60_device::bam1DisplacementIndirect8, + &v60_device::bam1DisplacementIndirect16, + &v60_device::bam1DisplacementIndirect32, + &v60_device::bam1Group7 + }, + + { + &v60_device::bam1DoubleDisplacement8, + &v60_device::bam1DoubleDisplacement16, + &v60_device::bam1DoubleDisplacement32, + &v60_device::bam1Error6, + &v60_device::bam1Autoincrement, + &v60_device::bam1Autodecrement, + &v60_device::bam1Group6, + &v60_device::bam1Error1 + } +}; diff --git a/src/devices/cpu/v60/am2.inc b/src/devices/cpu/v60/am2.inc new file mode 100644 index 00000000000..2b01d324979 --- /dev/null +++ b/src/devices/cpu/v60/am2.inc @@ -0,0 +1,1254 @@ +// license:BSD-3-Clause +// copyright-holders:Farfetch'd, R. Belmont +// AM2 Functions (for ReadAMAddress) +// ********************************* + +UINT32 v60_device::am2Register() +{ + m_amflag = 1; + m_amout = m_modval & 0x1F; + return 1; +} + +UINT32 v60_device::am2RegisterIndirect() +{ + m_amflag = 0; + m_amout = m_reg[m_modval & 0x1F]; + return 1; +} + +UINT32 v60_device::bam2RegisterIndirect() +{ + m_amflag = 0; + m_amout = m_reg[m_modval & 0x1F]; + m_bamoffset = 0; + return 1; +} + +UINT32 v60_device::am2RegisterIndirectIndexed() +{ + m_amflag = 0; + + switch (m_moddim) + { + case 0: + m_amout = m_reg[m_modval2 & 0x1F] + m_reg[m_modval & 0x1F]; + break; + case 1: + m_amout = m_reg[m_modval2 & 0x1F] + m_reg[m_modval & 0x1F] * 2; + break; + case 2: + m_amout = m_reg[m_modval2 & 0x1F] + m_reg[m_modval & 0x1F] * 4; + break; + case 3: + m_amout = m_reg[m_modval2 & 0x1F] + m_reg[m_modval & 0x1F] * 8; + break; + } + + return 2; +} + +UINT32 v60_device::bam2RegisterIndirectIndexed() +{ + m_amflag = 0; + m_amout = m_reg[m_modval2 & 0x1F]; + m_bamoffset = m_reg[m_modval & 0x1F]; + return 2; +} + +UINT32 v60_device::am2Autoincrement() +{ + m_amflag = 0; + m_amout = m_reg[m_modval & 0x1F]; + + switch (m_moddim) + { + case 0: + m_reg[m_modval & 0x1F] += 1; + break; + case 1: + m_reg[m_modval & 0x1F] += 2; + break; + case 2: + m_reg[m_modval & 0x1F] += 4; + break; + case 3: + m_reg[m_modval & 0x1F] += 8; + break; + } + + return 1; +} + +UINT32 v60_device::bam2Autoincrement() +{ + m_amflag = 0; + m_amout = m_reg[m_modval & 0x1F]; + m_bamoffset = 0; + + switch (m_moddim) + { + case 10: + m_reg[m_modval & 0x1F] +=1; + break; + case 11: + m_reg[m_modval & 0x1F] +=4; + break; + default: + fatalerror("CPU - AM2 - 7 (t0 PC=%x)\n", PC); + break; + } + + return 1; +} + +UINT32 v60_device::am2Autodecrement() +{ + m_amflag = 0; + + switch (m_moddim) + { + case 0: + m_reg[m_modval & 0x1F] -= 1; + break; + case 1: + m_reg[m_modval & 0x1F] -= 2; + break; + case 2: + m_reg[m_modval & 0x1F] -= 4; + break; + case 3: + m_reg[m_modval & 0x1F] -= 8; + break; + } + + m_amout = m_reg[m_modval & 0x1F]; + return 1; +} + +UINT32 v60_device::bam2Autodecrement() +{ + m_amflag = 0; + m_bamoffset = 0; + + switch (m_moddim) + { + case 10: + m_reg[m_modval & 0x1F]-=1; + break; + case 11: + m_reg[m_modval & 0x1F]-=4; + break; + default: + fatalerror("CPU - BAM2 - 7 (PC=%06x)\n", PC); + break; + } + + m_amout = m_reg[m_modval & 0x1F]; + return 1; +} + + +UINT32 v60_device::am2Displacement8() +{ + m_amflag = 0; + m_amout = m_reg[m_modval & 0x1F] + (INT8)OpRead8(m_modadd + 1); + + return 2; +} + +UINT32 v60_device::bam2Displacement8() +{ + m_amflag = 0; + m_amout = m_reg[m_modval & 0x1F]; + m_bamoffset = (INT8)OpRead8(m_modadd + 1); + + return 2; +} + +UINT32 v60_device::am2Displacement16() +{ + m_amflag = 0; + m_amout = m_reg[m_modval & 0x1F] + (INT16)OpRead16(m_modadd + 1); + + return 3; +} + +UINT32 v60_device::bam2Displacement16() +{ + m_amflag = 0; + m_amout = m_reg[m_modval & 0x1F]; + m_bamoffset = (INT16)OpRead16(m_modadd + 1); + + return 3; +} + +UINT32 v60_device::am2Displacement32() +{ + m_amflag = 0; + m_amout = m_reg[m_modval & 0x1F] + OpRead32(m_modadd + 1); + + return 5; +} + +UINT32 v60_device::bam2Displacement32() +{ + m_amflag = 0; + m_amout = m_reg[m_modval & 0x1F]; + m_bamoffset = OpRead32(m_modadd + 1); + + return 5; +} + +UINT32 v60_device::am2DisplacementIndexed8() +{ + m_amflag = 0; + + switch (m_moddim) + { + case 0: + m_amout = m_reg[m_modval2 & 0x1F] + (INT8)OpRead8(m_modadd + 2) + m_reg[m_modval & 0x1F]; + break; + case 1: + m_amout = m_reg[m_modval2 & 0x1F] + (INT8)OpRead8(m_modadd + 2) + m_reg[m_modval & 0x1F] * 2; + break; + case 2: + m_amout = m_reg[m_modval2 & 0x1F] + (INT8)OpRead8(m_modadd + 2) + m_reg[m_modval & 0x1F] * 4; + break; + case 3: + m_amout = m_reg[m_modval2 & 0x1F] + (INT8)OpRead8(m_modadd + 2) + m_reg[m_modval & 0x1F] * 8; + break; + } + + return 3; +} + +UINT32 v60_device::bam2DisplacementIndexed8() +{ + m_amflag = 0; + m_amout = m_reg[m_modval2 & 0x1F] + (INT8)OpRead8(m_modadd + 2); + m_bamoffset = m_reg[m_modval & 0x1F]; + + return 3; +} + +UINT32 v60_device::am2DisplacementIndexed16() +{ + m_amflag = 0; + + switch (m_moddim) + { + case 0: + m_amout = m_reg[m_modval2 & 0x1F] + (INT16)OpRead16(m_modadd + 2) + m_reg[m_modval & 0x1F]; + break; + case 1: + m_amout = m_reg[m_modval2 & 0x1F] + (INT16)OpRead16(m_modadd + 2) + m_reg[m_modval & 0x1F] * 2; + break; + case 2: + m_amout = m_reg[m_modval2 & 0x1F] + (INT16)OpRead16(m_modadd + 2) + m_reg[m_modval & 0x1F] * 4; + break; + case 3: + m_amout = m_reg[m_modval2 & 0x1F] + (INT16)OpRead16(m_modadd + 2) + m_reg[m_modval & 0x1F] * 8; + break; + } + + return 4; +} + +UINT32 v60_device::bam2DisplacementIndexed16() +{ + m_amflag = 0; + m_amout = m_reg[m_modval2 & 0x1F] + (INT16)OpRead16(m_modadd + 2); + m_bamoffset = m_reg[m_modval & 0x1F]; + + return 4; +} + +UINT32 v60_device::am2DisplacementIndexed32() +{ + m_amflag = 0; + + switch (m_moddim) + { + case 0: + m_amout = m_reg[m_modval2 & 0x1F] + OpRead32(m_modadd + 2) + m_reg[m_modval & 0x1F]; + break; + case 1: + m_amout = m_reg[m_modval2 & 0x1F] + OpRead32(m_modadd + 2) + m_reg[m_modval & 0x1F] * 2; + break; + case 2: + m_amout = m_reg[m_modval2 & 0x1F] + OpRead32(m_modadd + 2) + m_reg[m_modval & 0x1F] * 4; + break; + case 3: + m_amout = m_reg[m_modval2 & 0x1F] + OpRead32(m_modadd + 2) + m_reg[m_modval & 0x1F] * 8; + break; + } + + return 6; +} + +UINT32 v60_device::bam2DisplacementIndexed32() +{ + m_amflag = 0; + m_amout = m_reg[m_modval2 & 0x1F] + OpRead32(m_modadd + 2); + m_bamoffset = m_reg[m_modval & 0x1F]; + + return 6; +} + +UINT32 v60_device::am2PCDisplacement8() +{ + m_amflag = 0; + m_amout = PC + (INT8)OpRead8(m_modadd + 1); + + return 2; +} + +UINT32 v60_device::bam2PCDisplacement8() +{ + m_amflag = 0; + m_amout = PC; + m_bamoffset = (INT8)OpRead8(m_modadd + 1); + + return 2; +} + +UINT32 v60_device::am2PCDisplacement16() +{ + m_amflag = 0; + m_amout = PC + (INT16)OpRead16(m_modadd + 1); + + return 3; +} + +UINT32 v60_device::bam2PCDisplacement16() +{ + m_amflag = 0; + m_amout = PC; + m_bamoffset = (INT16)OpRead16(m_modadd + 1); + + return 3; +} + +UINT32 v60_device::am2PCDisplacement32() +{ + m_amflag = 0; + m_amout = PC + OpRead32(m_modadd + 1); + + return 5; +} + +UINT32 v60_device::bam2PCDisplacement32() +{ + m_amflag = 0; + m_amout = PC; + m_bamoffset = OpRead32(m_modadd + 1); + + return 5; +} + + +UINT32 v60_device::am2PCDisplacementIndexed8() +{ + m_amflag = 0; + + switch (m_moddim) + { + case 0: + m_amout = PC + (INT8)OpRead8(m_modadd + 2) + m_reg[m_modval & 0x1F]; + break; + case 1: + m_amout = PC + (INT8)OpRead8(m_modadd + 2) + m_reg[m_modval & 0x1F] * 2; + break; + case 2: + m_amout = PC + (INT8)OpRead8(m_modadd + 2) + m_reg[m_modval & 0x1F] * 4; + break; + case 3: + m_amout = PC + (INT8)OpRead8(m_modadd + 2) + m_reg[m_modval & 0x1F] * 8; + break; + } + + return 3; +} + +UINT32 v60_device::bam2PCDisplacementIndexed8() +{ + m_amflag = 0; + m_amout = PC + (INT8)OpRead8(m_modadd + 2); + m_bamoffset = m_reg[m_modval & 0x1F]; + + return 3; +} + +UINT32 v60_device::am2PCDisplacementIndexed16() +{ + m_amflag = 0; + + switch (m_moddim) + { + case 0: + m_amout = PC + (INT16)OpRead16(m_modadd + 2) + m_reg[m_modval & 0x1F]; + break; + case 1: + m_amout = PC + (INT16)OpRead16(m_modadd + 2) + m_reg[m_modval & 0x1F] * 2; + break; + case 2: + m_amout = PC + (INT16)OpRead16(m_modadd + 2) + m_reg[m_modval & 0x1F] * 4; + break; + case 3: + m_amout = PC + (INT16)OpRead16(m_modadd + 2) + m_reg[m_modval & 0x1F] * 8; + break; + } + + return 4; +} + +UINT32 v60_device::bam2PCDisplacementIndexed16() +{ + m_amflag = 0; + m_amout = PC + (INT16)OpRead16(m_modadd + 2); + m_bamoffset = m_reg[m_modval & 0x1F]; + + return 4; +} + +UINT32 v60_device::am2PCDisplacementIndexed32() +{ + m_amflag = 0; + + switch (m_moddim) + { + case 0: + m_amout = PC + OpRead32(m_modadd + 2) + m_reg[m_modval & 0x1F]; + break; + case 1: + m_amout = PC + OpRead32(m_modadd + 2) + m_reg[m_modval & 0x1F] * 2; + break; + case 2: + m_amout = PC + OpRead32(m_modadd + 2) + m_reg[m_modval & 0x1F] * 4; + break; + case 3: + m_amout = PC + OpRead32(m_modadd + 2) + m_reg[m_modval & 0x1F] * 8; + break; + } + + return 6; +} + +UINT32 v60_device::bam2PCDisplacementIndexed32() +{ + m_amflag = 0; + m_amout = PC + OpRead32(m_modadd + 2); + m_bamoffset = m_reg[m_modval & 0x1F]; + + return 6; +} + +UINT32 v60_device::am2DisplacementIndirect8() +{ + m_amflag = 0; + m_amout = m_program->read_dword_unaligned(m_reg[m_modval & 0x1F] + (INT8)OpRead8(m_modadd + 1)); + + return 2; +} + +UINT32 v60_device::bam2DisplacementIndirect8() +{ + m_amflag = 0; + m_amout = m_program->read_dword_unaligned(m_reg[m_modval & 0x1F] + (INT8)OpRead8(m_modadd + 1)); + m_bamoffset = 0; + return 2; +} + +UINT32 v60_device::am2DisplacementIndirect16() +{ + m_amflag = 0; + m_amout = m_program->read_dword_unaligned(m_reg[m_modval & 0x1F] + (INT16)OpRead16(m_modadd + 1)); + + return 3; +} + +UINT32 v60_device::bam2DisplacementIndirect16() +{ + m_amflag = 0; + m_amout = m_program->read_dword_unaligned(m_reg[m_modval & 0x1F] + (INT16)OpRead16(m_modadd + 1)); + m_bamoffset = 0; + return 3; +} + +UINT32 v60_device::am2DisplacementIndirect32() +{ + m_amflag = 0; + m_amout = m_program->read_dword_unaligned(m_reg[m_modval & 0x1F] + OpRead32(m_modadd + 1)); + + return 5; +} + +UINT32 v60_device::bam2DisplacementIndirect32() +{ + m_amflag = 0; + m_amout = m_program->read_dword_unaligned(m_reg[m_modval & 0x1F] + OpRead32(m_modadd + 1)); + m_bamoffset = 0; + + return 5; +} + +UINT32 v60_device::am2DisplacementIndirectIndexed8() +{ + m_amflag = 0; + + switch (m_moddim) + { + case 0: + m_amout = m_program->read_dword_unaligned(m_reg[m_modval2 & 0x1F] + (INT8)OpRead8(m_modadd + 2)) + m_reg[m_modval & 0x1F]; + break; + case 1: + m_amout = m_program->read_dword_unaligned(m_reg[m_modval2 & 0x1F] + (INT8)OpRead8(m_modadd + 2)) + m_reg[m_modval & 0x1F] * 2; + break; + case 2: + m_amout = m_program->read_dword_unaligned(m_reg[m_modval2 & 0x1F] + (INT8)OpRead8(m_modadd + 2)) + m_reg[m_modval & 0x1F] * 4; + break; + case 3: + m_amout = m_program->read_dword_unaligned(m_reg[m_modval2 & 0x1F] + (INT8)OpRead8(m_modadd + 2)) + m_reg[m_modval & 0x1F] * 8; + break; + } + + return 3; +} + +UINT32 v60_device::bam2DisplacementIndirectIndexed8() +{ + m_amflag = 0; + m_amout = m_program->read_dword_unaligned(m_reg[m_modval2 & 0x1F] + (INT8)OpRead8(m_modadd + 2)); + m_bamoffset = m_reg[m_modval & 0x1F]; + + return 3; +} + +UINT32 v60_device::am2DisplacementIndirectIndexed16() +{ + m_amflag = 0; + + switch (m_moddim) + { + case 0: + m_amout = m_program->read_dword_unaligned(m_reg[m_modval2 & 0x1F] + (INT16)OpRead16(m_modadd + 2)) + m_reg[m_modval & 0x1F]; + break; + case 1: + m_amout = m_program->read_dword_unaligned(m_reg[m_modval2 & 0x1F] + (INT16)OpRead16(m_modadd + 2)) + m_reg[m_modval & 0x1F] * 2; + break; + case 2: + m_amout = m_program->read_dword_unaligned(m_reg[m_modval2 & 0x1F] + (INT16)OpRead16(m_modadd + 2)) + m_reg[m_modval & 0x1F] * 4; + break; + case 3: + m_amout = m_program->read_dword_unaligned(m_reg[m_modval2 & 0x1F] + (INT16)OpRead16(m_modadd + 2)) + m_reg[m_modval & 0x1F] * 8; + break; + } + + return 4; +} + +UINT32 v60_device::bam2DisplacementIndirectIndexed16() +{ + m_amflag = 0; + m_amout = m_program->read_dword_unaligned(m_reg[m_modval2 & 0x1F] + (INT16)OpRead16(m_modadd + 2)); + m_bamoffset = m_reg[m_modval & 0x1F]; + + return 4; +} + +UINT32 v60_device::am2DisplacementIndirectIndexed32() +{ + m_amflag = 0; + + switch (m_moddim) + { + case 0: + m_amout = m_program->read_dword_unaligned(m_reg[m_modval2 & 0x1F] + OpRead32(m_modadd + 2)) + m_reg[m_modval & 0x1F]; + break; + case 1: + m_amout = m_program->read_dword_unaligned(m_reg[m_modval2 & 0x1F] + OpRead32(m_modadd + 2)) + m_reg[m_modval & 0x1F] * 2; + break; + case 2: + m_amout = m_program->read_dword_unaligned(m_reg[m_modval2 & 0x1F] + OpRead32(m_modadd + 2)) + m_reg[m_modval & 0x1F] * 4; + break; + case 3: + m_amout = m_program->read_dword_unaligned(m_reg[m_modval2 & 0x1F] + OpRead32(m_modadd + 2)) + m_reg[m_modval & 0x1F] * 8; + break; + } + + return 6; +} + +UINT32 v60_device::bam2DisplacementIndirectIndexed32() +{ + m_amflag = 0; + m_amout = m_program->read_dword_unaligned(m_reg[m_modval2 & 0x1F] + OpRead32(m_modadd + 2)); + m_bamoffset = m_reg[m_modval & 0x1F]; + + return 6; +} + +UINT32 v60_device::am2PCDisplacementIndirect8() +{ + m_amflag = 0; + m_amout = m_program->read_dword_unaligned(PC + (INT8)OpRead8(m_modadd + 1)); + + return 2; +} + +UINT32 v60_device::bam2PCDisplacementIndirect8() +{ + m_amflag = 0; + m_amout = m_program->read_dword_unaligned(PC + (INT8)OpRead8(m_modadd + 1)); + m_bamoffset = 0; + + return 2; +} + +UINT32 v60_device::am2PCDisplacementIndirect16() +{ + m_amflag = 0; + m_amout = m_program->read_dword_unaligned(PC + (INT16)OpRead16(m_modadd + 1)); + + return 3; +} + +UINT32 v60_device::bam2PCDisplacementIndirect16() +{ + m_amflag = 0; + m_amout = m_program->read_dword_unaligned(PC + (INT16)OpRead16(m_modadd + 1)); + m_bamoffset = 0; + + return 3; +} + +UINT32 v60_device::am2PCDisplacementIndirect32() +{ + m_amflag = 0; + m_amout = m_program->read_dword_unaligned(PC + OpRead32(m_modadd + 1)); + + return 5; +} + +UINT32 v60_device::bam2PCDisplacementIndirect32() +{ + m_amflag = 0; + m_amout = m_program->read_dword_unaligned(PC + OpRead32(m_modadd + 1)); + m_bamoffset = 0; + + return 5; +} + +UINT32 v60_device::am2PCDisplacementIndirectIndexed8() +{ + m_amflag = 0; + + switch (m_moddim) + { + case 0: + m_amout = m_program->read_dword_unaligned(PC + (INT8)OpRead8(m_modadd + 2)) + m_reg[m_modval & 0x1F]; + break; + case 1: + m_amout = m_program->read_dword_unaligned(PC + (INT8)OpRead8(m_modadd + 2)) + m_reg[m_modval & 0x1F] * 2; + break; + case 2: + m_amout = m_program->read_dword_unaligned(PC + (INT8)OpRead8(m_modadd + 2)) + m_reg[m_modval & 0x1F] * 4; + break; + case 3: + m_amout = m_program->read_dword_unaligned(PC + (INT8)OpRead8(m_modadd + 2)) + m_reg[m_modval & 0x1F] * 8; + break; + } + + return 3; +} + +UINT32 v60_device::bam2PCDisplacementIndirectIndexed8() +{ + m_amflag = 0; + m_amout = m_program->read_dword_unaligned(PC + (INT8)OpRead8(m_modadd + 2)); + m_bamoffset = m_reg[m_modval & 0x1F]; + + return 3; +} + +UINT32 v60_device::am2PCDisplacementIndirectIndexed16() +{ + m_amflag = 0; + + switch (m_moddim) + { + case 0: + m_amout = m_program->read_dword_unaligned(PC + (INT16)OpRead16(m_modadd + 2)) + m_reg[m_modval & 0x1F]; + break; + case 1: + m_amout = m_program->read_dword_unaligned(PC + (INT16)OpRead16(m_modadd + 2)) + m_reg[m_modval & 0x1F] * 2; + break; + case 2: + m_amout = m_program->read_dword_unaligned(PC + (INT16)OpRead16(m_modadd + 2)) + m_reg[m_modval & 0x1F] * 4; + break; + case 3: + m_amout = m_program->read_dword_unaligned(PC + (INT16)OpRead16(m_modadd + 2)) + m_reg[m_modval & 0x1F] * 8; + break; + } + + return 4; +} + + +UINT32 v60_device::bam2PCDisplacementIndirectIndexed16() +{ + m_amflag = 0; + m_amout = m_program->read_dword_unaligned(PC + (INT16)OpRead16(m_modadd + 2)); + m_bamoffset = m_reg[m_modval & 0x1F]; + + return 4; +} + + +UINT32 v60_device::am2PCDisplacementIndirectIndexed32() +{ + m_amflag = 0; + + switch (m_moddim) + { + case 0: + m_amout = m_program->read_dword_unaligned(PC + OpRead32(m_modadd + 2)) + m_reg[m_modval & 0x1F]; + break; + case 1: + m_amout = m_program->read_dword_unaligned(PC + OpRead32(m_modadd + 2)) + m_reg[m_modval & 0x1F] * 2; + break; + case 2: + m_amout = m_program->read_dword_unaligned(PC + OpRead32(m_modadd + 2)) + m_reg[m_modval & 0x1F] * 4; + break; + case 3: + m_amout = m_program->read_dword_unaligned(PC + OpRead32(m_modadd + 2)) + m_reg[m_modval & 0x1F] * 8; + break; + } + + return 6; +} + +UINT32 v60_device::bam2PCDisplacementIndirectIndexed32() +{ + m_amflag = 0; + m_amout = m_program->read_dword_unaligned(PC + OpRead32(m_modadd + 2)); + m_bamoffset = m_reg[m_modval & 0x1F]; + + return 6; +} + +UINT32 v60_device::am2DoubleDisplacement8() +{ + m_amflag = 0; + m_amout = m_program->read_dword_unaligned(m_reg[m_modval & 0x1F] + (INT8)OpRead8(m_modadd + 1)) + (INT8)OpRead8(m_modadd + 2); + + return 3; +} + +UINT32 v60_device::bam2DoubleDisplacement8() +{ + m_amflag = 0; + m_amout = m_program->read_dword_unaligned(m_reg[m_modval & 0x1F] + (INT8)OpRead8(m_modadd + 1)); + m_bamoffset = (INT8)OpRead8(m_modadd + 2); + + return 3; +} + +UINT32 v60_device::am2DoubleDisplacement16() +{ + m_amflag = 0; + m_amout = m_program->read_dword_unaligned(m_reg[m_modval & 0x1F] + (INT16)OpRead16(m_modadd + 1)) + (INT16)OpRead16(m_modadd + 3); + + return 5; +} + +UINT32 v60_device::bam2DoubleDisplacement16() +{ + m_amflag = 0; + m_amout = m_program->read_dword_unaligned(m_reg[m_modval & 0x1F] + (INT16)OpRead16(m_modadd + 1)); + m_bamoffset = (INT8)OpRead8(m_modadd + 3); + + return 5; +} + +UINT32 v60_device::am2DoubleDisplacement32() +{ + m_amflag = 0; + m_amout = m_program->read_dword_unaligned(m_reg[m_modval & 0x1F] + OpRead32(m_modadd + 1)) + OpRead32(m_modadd + 5); + + return 9; +} + +UINT32 v60_device::bam2DoubleDisplacement32() +{ + m_amflag = 0; + m_amout = m_program->read_dword_unaligned(m_reg[m_modval & 0x1F] + OpRead32(m_modadd + 1)); + m_bamoffset = OpRead32(m_modadd + 5); + + return 9; +} + + +UINT32 v60_device::am2PCDoubleDisplacement8() +{ + m_amflag = 0; + m_amout = m_program->read_dword_unaligned(PC + (INT8)OpRead8(m_modadd + 1)) + (INT8)OpRead8(m_modadd + 2); + + return 3; +} + +UINT32 v60_device::bam2PCDoubleDisplacement8() +{ + m_amflag = 0; + m_amout = m_program->read_dword_unaligned(PC + (INT8)OpRead8(m_modadd + 1)); + m_bamoffset = (INT8)OpRead8(m_modadd + 2); + + return 3; +} + +UINT32 v60_device::am2PCDoubleDisplacement16() +{ + m_amflag = 0; + m_amout = m_program->read_dword_unaligned(PC + (INT16)OpRead16(m_modadd + 1)) + (INT16)OpRead16(m_modadd + 3); + + return 5; +} + +UINT32 v60_device::bam2PCDoubleDisplacement16() +{ + m_amflag = 0; + m_amout = m_program->read_dword_unaligned(PC + (INT16)OpRead16(m_modadd + 1)); + m_bamoffset = (INT8)OpRead8(m_modadd + 3); + + return 5; +} + +UINT32 v60_device::am2PCDoubleDisplacement32() +{ + m_amflag = 0; + m_amout = m_program->read_dword_unaligned(PC + OpRead32(m_modadd + 1)) + OpRead32(m_modadd + 5); + + return 9; +} + +UINT32 v60_device::bam2PCDoubleDisplacement32() +{ + m_amflag = 0; + m_amout = m_program->read_dword_unaligned(PC + OpRead32(m_modadd + 1)); + m_bamoffset = OpRead32(m_modadd + 5); + + return 9; +} + +UINT32 v60_device::am2DirectAddress() +{ + m_amflag = 0; + m_amout = OpRead32(m_modadd + 1); + + return 5; +} + +UINT32 v60_device::bam2DirectAddress() +{ + m_amflag = 0; + m_amout = OpRead32(m_modadd + 1); + m_bamoffset = 0; + + return 5; +} + +UINT32 v60_device::am2DirectAddressIndexed() +{ + m_amflag = 0; + + switch (m_moddim) + { + case 0: + m_amout = OpRead32(m_modadd + 2) + m_reg[m_modval & 0x1F]; + break; + case 1: + m_amout = OpRead32(m_modadd + 2) + m_reg[m_modval & 0x1F] * 2; + break; + case 2: + m_amout = OpRead32(m_modadd + 2) + m_reg[m_modval & 0x1F] * 4; + break; + case 3: + m_amout = OpRead32(m_modadd + 2) + m_reg[m_modval & 0x1F] * 8; + break; + } + + return 6; +} + +UINT32 v60_device::bam2DirectAddressIndexed() +{ + m_amflag = 0; + m_amout = OpRead32(m_modadd + 2); + m_bamoffset = m_reg[m_modval & 0x1F]; + + return 6; +} + +UINT32 v60_device::am2DirectAddressDeferred() +{ + m_amflag = 0; + m_amout = m_program->read_dword_unaligned(OpRead32(m_modadd + 1)); + + return 5; +} + +UINT32 v60_device::bam2DirectAddressDeferred() +{ + m_amflag = 0; + m_amout = m_program->read_dword_unaligned(OpRead32(m_modadd + 1)); + m_bamoffset = 0; + + return 5; +} + +UINT32 v60_device::am2DirectAddressDeferredIndexed() +{ + m_amflag = 0; + + switch (m_moddim) + { + case 0: + m_amout = m_program->read_dword_unaligned(OpRead32(m_modadd + 2)) + m_reg[m_modval & 0x1F]; + break; + case 1: + m_amout = m_program->read_dword_unaligned(OpRead32(m_modadd + 2)) + m_reg[m_modval & 0x1F] * 2; + break; + case 2: + m_amout = m_program->read_dword_unaligned(OpRead32(m_modadd + 2)) + m_reg[m_modval & 0x1F] * 4; + break; + case 3: + m_amout = m_program->read_dword_unaligned(OpRead32(m_modadd + 2)) + m_reg[m_modval & 0x1F] * 8; + break; + } + + return 6; +} + +UINT32 v60_device::bam2DirectAddressDeferredIndexed() +{ + m_amflag = 0; + m_amout = m_program->read_dword_unaligned(OpRead32(m_modadd + 2)); + m_bamoffset = m_reg[m_modval & 0x1F]; + + return 6; +} + +UINT32 v60_device::am2Immediate() +{ + // ignore LDPR + return am1Immediate(); +} + +UINT32 v60_device::am2ImmediateQuick() +{ + // ignore LDPR + return am1ImmediateQuick(); +} + + +// AM2 Tables (for ReadAMAddress) +// ****************************** + +UINT32 v60_device::am2Error1() +{ + // f1lap trips this, why? + logerror("CPU - AM2 - 1 (PC=%06x)", PC); + return 0; +} + +UINT32 v60_device::am2Error2() +{ + fatalerror("CPU - AM2 - 2 (PC=%06x)\n", PC); + return 0; /* never reached, fatalerror won't return */ +} + +#ifdef UNUSED_FUNCTION +UINT32 v60_device::am2Error3() +{ + fatalerror("CPU - AM2 - 3 (PC=%06x)\n", PC); + return 0; /* never reached, fatalerror won't return */ +} +#endif + +UINT32 v60_device::am2Error4() +{ + fatalerror("CPU - AM2 - 4 (PC=%06x)\n", PC); + return 0; /* never reached, fatalerror won't return */ +} + +UINT32 v60_device::am2Error5() +{ + fatalerror("CPU - AM2 - 5 (PC=%06x)\n", PC); + return 0; /* never reached, fatalerror won't return */ +} + +UINT32 v60_device::bam2Error1() +{ + fatalerror("CPU - BAM2 - 1 (PC=%06x)\n", PC); + return 0; /* never reached, fatalerror won't return */ +} + +UINT32 v60_device::bam2Error2() +{ + fatalerror("CPU - BAM2 - 2 (PC=%06x)\n", PC); + return 0; /* never reached, fatalerror won't return */ +} + +#ifdef UNUSED_FUNCTION +UINT32 v60_device::bam2Error3() +{ + fatalerror("CPU - BAM2 - 3 (PC=%06x)\n", PC); + return 0; /* never reached, fatalerror won't return */ +} +#endif + +UINT32 v60_device::bam2Error4() +{ + fatalerror("CPU - BAM2 - 4 (PC=%06x)\n", PC); + return 0; /* never reached, fatalerror won't return */ +} + +UINT32 v60_device::bam2Error5() +{ + fatalerror("CPU - BAM2 - 5 (PC=%06x)\n", PC); + return 0; /* never reached, fatalerror won't return */ +} + +UINT32 v60_device::bam2Error6() +{ + fatalerror("CPU - BAM2 - 6 (PC=%06x)\n", PC); + return 0; /* never reached, fatalerror won't return */ +} + + +const v60_device::am_func v60_device::s_AMTable2_G7a[16] = +{ + &v60_device::am2PCDisplacementIndexed8, + &v60_device::am2PCDisplacementIndexed16, + &v60_device::am2PCDisplacementIndexed32, + &v60_device::am2DirectAddressIndexed, + &v60_device::am2Error5, + &v60_device::am2Error5, + &v60_device::am2Error5, + &v60_device::am2Error5, + &v60_device::am2PCDisplacementIndirectIndexed8, + &v60_device::am2PCDisplacementIndirectIndexed16, + &v60_device::am2PCDisplacementIndirectIndexed32, + &v60_device::am2DirectAddressDeferredIndexed, + &v60_device::am2Error5, + &v60_device::am2Error5, + &v60_device::am2Error5, + &v60_device::am2Error5 +}; + +const v60_device::am_func v60_device::s_BAMTable2_G7a[16] = +{ + &v60_device::bam2PCDisplacementIndexed8, + &v60_device::bam2PCDisplacementIndexed16, + &v60_device::bam2PCDisplacementIndexed32, + &v60_device::bam2DirectAddressIndexed, + &v60_device::bam2Error5, + &v60_device::bam2Error5, + &v60_device::bam2Error5, + &v60_device::bam2Error5, + &v60_device::bam2PCDisplacementIndirectIndexed8, + &v60_device::bam2PCDisplacementIndirectIndexed16, + &v60_device::bam2PCDisplacementIndirectIndexed32, + &v60_device::bam2DirectAddressDeferredIndexed, + &v60_device::bam2Error5, + &v60_device::bam2Error5, + &v60_device::bam2Error5, + &v60_device::bam2Error5 +}; + +UINT32 v60_device::am2Group7a() +{ + if (!(m_modval2 & 0x10)) + return am2Error4(); + + return (this->*s_AMTable2_G7a[m_modval2 & 0xF])(); +} + +UINT32 v60_device::bam2Group7a() +{ + if (!(m_modval2 & 0x10)) + return bam2Error4(); + + return (this->*s_BAMTable2_G7a[m_modval2 & 0xF])(); +} + +const v60_device::am_func v60_device::s_AMTable2_G7[32] = +{ + &v60_device::am2ImmediateQuick, + &v60_device::am2ImmediateQuick, + &v60_device::am2ImmediateQuick, + &v60_device::am2ImmediateQuick, + &v60_device::am2ImmediateQuick, + &v60_device::am2ImmediateQuick, + &v60_device::am2ImmediateQuick, + &v60_device::am2ImmediateQuick, + &v60_device::am2ImmediateQuick, + &v60_device::am2ImmediateQuick, + &v60_device::am2ImmediateQuick, + &v60_device::am2ImmediateQuick, + &v60_device::am2ImmediateQuick, + &v60_device::am2ImmediateQuick, + &v60_device::am2ImmediateQuick, + &v60_device::am2ImmediateQuick, + &v60_device::am2PCDisplacement8, + &v60_device::am2PCDisplacement16, + &v60_device::am2PCDisplacement32, + &v60_device::am2DirectAddress, + &v60_device::am2Immediate, + &v60_device::am2Error2, + &v60_device::am2Error2, + &v60_device::am2Error2, + &v60_device::am2PCDisplacementIndirect8, + &v60_device::am2PCDisplacementIndirect16, + &v60_device::am2PCDisplacementIndirect32, + &v60_device::am2DirectAddressDeferred, + &v60_device::am2PCDoubleDisplacement8, + &v60_device::am2PCDoubleDisplacement16, + &v60_device::am2PCDoubleDisplacement32, + &v60_device::am2Error2 +}; + +const v60_device::am_func v60_device::s_BAMTable2_G7[32] = +{ + &v60_device::bam2Error6, + &v60_device::bam2Error6, + &v60_device::bam2Error6, + &v60_device::bam2Error6, + &v60_device::bam2Error6, + &v60_device::bam2Error6, + &v60_device::bam2Error6, + &v60_device::bam2Error6, + &v60_device::bam2Error6, + &v60_device::bam2Error6, + &v60_device::bam2Error6, + &v60_device::bam2Error6, + &v60_device::bam2Error6, + &v60_device::bam2Error6, + &v60_device::bam2Error6, + &v60_device::bam2Error6, + &v60_device::bam2PCDisplacement8, + &v60_device::bam2PCDisplacement16, + &v60_device::bam2PCDisplacement32, + &v60_device::bam2DirectAddress, + &v60_device::bam2Error6, + &v60_device::bam2Error2, + &v60_device::bam2Error2, + &v60_device::bam2Error2, + &v60_device::bam2PCDisplacementIndirect8, + &v60_device::bam2PCDisplacementIndirect16, + &v60_device::bam2PCDisplacementIndirect32, + &v60_device::bam2DirectAddressDeferred, + &v60_device::bam2PCDoubleDisplacement8, + &v60_device::bam2PCDoubleDisplacement16, + &v60_device::bam2PCDoubleDisplacement32, + &v60_device::bam2Error2 +}; + +const v60_device::am_func v60_device::s_AMTable2_G6[8] = +{ + &v60_device::am2DisplacementIndexed8, + &v60_device::am2DisplacementIndexed16, + &v60_device::am2DisplacementIndexed32, + &v60_device::am2RegisterIndirectIndexed, + &v60_device::am2DisplacementIndirectIndexed8, + &v60_device::am2DisplacementIndirectIndexed16, + &v60_device::am2DisplacementIndirectIndexed32, + &v60_device::am2Group7a +}; + +const v60_device::am_func v60_device::s_BAMTable2_G6[8] = +{ + &v60_device::bam2DisplacementIndexed8, + &v60_device::bam2DisplacementIndexed16, + &v60_device::bam2DisplacementIndexed32, + &v60_device::bam2RegisterIndirectIndexed, + &v60_device::bam2DisplacementIndirectIndexed8, + &v60_device::bam2DisplacementIndirectIndexed16, + &v60_device::bam2DisplacementIndirectIndexed32, + &v60_device::bam2Group7a +}; + + + + +UINT32 v60_device::am2Group6() +{ + m_modval2 = OpRead8(m_modadd + 1); + return (this->*s_AMTable2_G6[m_modval2 >> 5])(); +} +UINT32 v60_device::bam2Group6() +{ + m_modval2 = OpRead8(m_modadd + 1); + return (this->*s_BAMTable2_G6[m_modval2 >> 5])(); +} + +UINT32 v60_device::am2Group7() +{ + return (this->*s_AMTable2_G7[m_modval & 0x1F])(); +} +UINT32 v60_device::bam2Group7() +{ + return (this->*s_BAMTable2_G7[m_modval & 0x1F])(); +} + + +const v60_device::am_func v60_device::s_AMTable2[2][8] = +{ + { + &v60_device::am2Displacement8, + &v60_device::am2Displacement16, + &v60_device::am2Displacement32, + &v60_device::am2RegisterIndirect, + &v60_device::am2DisplacementIndirect8, + &v60_device::am2DisplacementIndirect16, + &v60_device::am2DisplacementIndirect32, + &v60_device::am2Group7 + }, + + { + &v60_device::am2DoubleDisplacement8, + &v60_device::am2DoubleDisplacement16, + &v60_device::am2DoubleDisplacement32, + &v60_device::am2Register, + &v60_device::am2Autoincrement, + &v60_device::am2Autodecrement, + &v60_device::am2Group6, + &v60_device::am2Error1 + } +}; + +const v60_device::am_func v60_device::s_BAMTable2[2][8] = +{ + { + &v60_device::bam2Displacement8, + &v60_device::bam2Displacement16, + &v60_device::bam2Displacement32, + &v60_device::bam2RegisterIndirect, + &v60_device::bam2DisplacementIndirect8, + &v60_device::bam2DisplacementIndirect16, + &v60_device::bam2DisplacementIndirect32, + &v60_device::bam2Group7 + }, + + { + &v60_device::bam2DoubleDisplacement8, + &v60_device::bam2DoubleDisplacement16, + &v60_device::bam2DoubleDisplacement32, + &v60_device::bam2Error6, + &v60_device::bam2Autoincrement, + &v60_device::bam2Autodecrement, + &v60_device::bam2Group6, + &v60_device::bam2Error1 + } +}; diff --git a/src/devices/cpu/v60/am3.inc b/src/devices/cpu/v60/am3.inc new file mode 100644 index 00000000000..93af406f266 --- /dev/null +++ b/src/devices/cpu/v60/am3.inc @@ -0,0 +1,885 @@ +// license:BSD-3-Clause +// copyright-holders:Farfetch'd, R. Belmont +// AM3 Functions (for ReadAM) +// ************************** + +UINT32 v60_device::am3Register() +{ + switch (m_moddim) + { + case 0: + SETREG8(m_reg[m_modval & 0x1F], m_modwritevalb); + break; + case 1: + SETREG16(m_reg[m_modval & 0x1F], m_modwritevalh); + break; + case 2: + m_reg[m_modval & 0x1F] = m_modwritevalw; + break; + } + + return 1; +} + +UINT32 v60_device::am3RegisterIndirect() +{ + switch (m_moddim) + { + case 0: + m_program->write_byte(m_reg[m_modval & 0x1F], m_modwritevalb); + break; + case 1: + m_program->write_word_unaligned(m_reg[m_modval & 0x1F], m_modwritevalh); + break; + case 2: + m_program->write_dword_unaligned(m_reg[m_modval & 0x1F], m_modwritevalw); + break; + } + + return 1; +} + +UINT32 v60_device::am3RegisterIndirectIndexed() +{ + switch (m_moddim) + { + case 0: + m_program->write_byte(m_reg[m_modval2 & 0x1F] + m_reg[m_modval & 0x1F], m_modwritevalb); + break; + case 1: + m_program->write_word_unaligned(m_reg[m_modval2 & 0x1F] + m_reg[m_modval & 0x1F] * 2, m_modwritevalh); + break; + case 2: + m_program->write_dword_unaligned(m_reg[m_modval2 & 0x1F] + m_reg[m_modval & 0x1F] * 4, m_modwritevalw); + break; + } + + return 2; +} + +UINT32 v60_device::am3Autoincrement() +{ + switch (m_moddim) + { + case 0: + m_program->write_byte(m_reg[m_modval & 0x1F], m_modwritevalb); + m_reg[m_modval & 0x1F] += 1; + break; + case 1: + m_program->write_word_unaligned(m_reg[m_modval & 0x1F], m_modwritevalh); + m_reg[m_modval & 0x1F] += 2; + break; + case 2: + m_program->write_dword_unaligned(m_reg[m_modval & 0x1F], m_modwritevalw); + m_reg[m_modval & 0x1F] += 4; + break; + } + + return 1; +} + +UINT32 v60_device::am3Autodecrement() +{ + switch (m_moddim) + { + case 0: + m_reg[m_modval & 0x1F] -= 1; + m_program->write_byte(m_reg[m_modval & 0x1F], m_modwritevalb); + break; + case 1: + m_reg[m_modval & 0x1F] -= 2; + m_program->write_word_unaligned(m_reg[m_modval & 0x1F], m_modwritevalh); + break; + case 2: + m_reg[m_modval & 0x1F] -= 4; + m_program->write_dword_unaligned(m_reg[m_modval & 0x1F], m_modwritevalw); + break; + } + + return 1; +} + +UINT32 v60_device::am3Displacement8() +{ + switch (m_moddim) + { + case 0: + m_program->write_byte(m_reg[m_modval & 0x1F] + (INT8)OpRead8(m_modadd + 1), m_modwritevalb); + break; + case 1: + m_program->write_word_unaligned(m_reg[m_modval & 0x1F] + (INT8)OpRead8(m_modadd + 1), m_modwritevalh); + break; + case 2: + m_program->write_dword_unaligned(m_reg[m_modval & 0x1F] + (INT8)OpRead8(m_modadd + 1), m_modwritevalw); + break; + } + + return 2; +} + +UINT32 v60_device::am3Displacement16() +{ + switch (m_moddim) + { + case 0: + m_program->write_byte(m_reg[m_modval & 0x1F] + (INT16)OpRead16(m_modadd + 1), m_modwritevalb); + break; + case 1: + m_program->write_word_unaligned(m_reg[m_modval & 0x1F] + (INT16)OpRead16(m_modadd + 1), m_modwritevalh); + break; + case 2: + m_program->write_dword_unaligned(m_reg[m_modval & 0x1F] + (INT16)OpRead16(m_modadd + 1), m_modwritevalw); + break; + } + + return 3; +} + +UINT32 v60_device::am3Displacement32() +{ + switch (m_moddim) + { + case 0: + m_program->write_byte(m_reg[m_modval & 0x1F] + OpRead32(m_modadd + 1), m_modwritevalb); + break; + case 1: + m_program->write_word_unaligned(m_reg[m_modval & 0x1F] + OpRead32(m_modadd + 1), m_modwritevalh); + break; + case 2: + m_program->write_dword_unaligned(m_reg[m_modval & 0x1F] + OpRead32(m_modadd + 1), m_modwritevalw); + break; + } + + return 5; +} + + +UINT32 v60_device::am3DisplacementIndexed8() +{ + switch (m_moddim) + { + case 0: + m_program->write_byte(m_reg[m_modval2 & 0x1F] + (INT8)OpRead8(m_modadd + 2) + m_reg[m_modval & 0x1F], m_modwritevalb); + break; + case 1: + m_program->write_word_unaligned(m_reg[m_modval2 & 0x1F] + (INT8)OpRead8(m_modadd + 2) + m_reg[m_modval & 0x1F] * 2, m_modwritevalh); + break; + case 2: + m_program->write_dword_unaligned(m_reg[m_modval2 & 0x1F] + (INT8)OpRead8(m_modadd + 2) + m_reg[m_modval & 0x1F] * 4, m_modwritevalw); + break; + } + + return 3; +} + +UINT32 v60_device::am3DisplacementIndexed16() +{ + switch (m_moddim) + { + case 0: + m_program->write_byte(m_reg[m_modval2 & 0x1F] + (INT16)OpRead16(m_modadd + 2) + m_reg[m_modval & 0x1F], m_modwritevalb); + break; + case 1: + m_program->write_word_unaligned(m_reg[m_modval2 & 0x1F] + (INT16)OpRead16(m_modadd + 2) + m_reg[m_modval & 0x1F] * 2, m_modwritevalh); + break; + case 2: + m_program->write_dword_unaligned(m_reg[m_modval2 & 0x1F] + (INT16)OpRead16(m_modadd + 2) + m_reg[m_modval & 0x1F] * 4, m_modwritevalw); + break; + } + + return 4; +} + +UINT32 v60_device::am3DisplacementIndexed32() +{ + switch (m_moddim) + { + case 0: + m_program->write_byte(m_reg[m_modval2 & 0x1F] + OpRead32(m_modadd + 2) + m_reg[m_modval & 0x1F], m_modwritevalb); + break; + case 1: + m_program->write_word_unaligned(m_reg[m_modval2 & 0x1F] + OpRead32(m_modadd + 2) + m_reg[m_modval & 0x1F] * 2, m_modwritevalh); + break; + case 2: + m_program->write_dword_unaligned(m_reg[m_modval2 & 0x1F] + OpRead32(m_modadd + 2) + m_reg[m_modval & 0x1F] * 4, m_modwritevalw); + break; + } + + return 6; +} + + +UINT32 v60_device::am3PCDisplacement8() +{ + switch (m_moddim) + { + case 0: + m_program->write_byte(PC + (INT8)OpRead8(m_modadd + 1), m_modwritevalb); + break; + case 1: + m_program->write_word_unaligned(PC + (INT8)OpRead8(m_modadd + 1), m_modwritevalh); + break; + case 2: + m_program->write_dword_unaligned(PC + (INT8)OpRead8(m_modadd + 1), m_modwritevalw); + break; + } + + return 2; +} + +UINT32 v60_device::am3PCDisplacement16() +{ + switch (m_moddim) + { + case 0: + m_program->write_byte(PC + (INT16)OpRead16(m_modadd + 1), m_modwritevalb); + break; + case 1: + m_program->write_word_unaligned(PC + (INT16)OpRead16(m_modadd + 1), m_modwritevalh); + break; + case 2: + m_program->write_dword_unaligned(PC + (INT16)OpRead16(m_modadd + 1), m_modwritevalw); + break; + } + + return 3; +} + +UINT32 v60_device::am3PCDisplacement32() +{ + switch (m_moddim) + { + case 0: + m_program->write_byte(PC + OpRead32(m_modadd + 1), m_modwritevalb); + break; + case 1: + m_program->write_word_unaligned(PC + OpRead32(m_modadd + 1), m_modwritevalh); + break; + case 2: + m_program->write_dword_unaligned(PC + OpRead32(m_modadd + 1), m_modwritevalw); + break; + } + + return 5; +} + +UINT32 v60_device::am3PCDisplacementIndexed8() +{ + switch (m_moddim) + { + case 0: + m_program->write_byte(PC + (INT8)OpRead8(m_modadd + 2) + m_reg[m_modval & 0x1F], m_modwritevalb); + break; + case 1: + m_program->write_word_unaligned(PC + (INT8)OpRead8(m_modadd + 2) + m_reg[m_modval & 0x1F] * 2, m_modwritevalh); + break; + case 2: + m_program->write_dword_unaligned(PC + (INT8)OpRead8(m_modadd + 2) + m_reg[m_modval & 0x1F] * 4, m_modwritevalw); + break; + } + + return 3; +} + +UINT32 v60_device::am3PCDisplacementIndexed16() +{ + switch (m_moddim) + { + case 0: + m_program->write_byte(PC + (INT16)OpRead16(m_modadd + 2) + m_reg[m_modval & 0x1F], m_modwritevalb); + break; + case 1: + m_program->write_word_unaligned(PC + (INT16)OpRead16(m_modadd + 2) + m_reg[m_modval & 0x1F] * 2, m_modwritevalh); + break; + case 2: + m_program->write_dword_unaligned(PC + (INT16)OpRead16(m_modadd + 2) + m_reg[m_modval & 0x1F] * 4, m_modwritevalw); + break; + } + + return 4; +} + +UINT32 v60_device::am3PCDisplacementIndexed32() +{ + switch (m_moddim) + { + case 0: + m_program->write_byte(PC + OpRead32(m_modadd + 2) + m_reg[m_modval & 0x1F], m_modwritevalb); + break; + case 1: + m_program->write_word_unaligned(PC + OpRead32(m_modadd + 2) + m_reg[m_modval & 0x1F] * 2, m_modwritevalh); + break; + case 2: + m_program->write_dword_unaligned(PC + OpRead32(m_modadd + 2) + m_reg[m_modval & 0x1F] * 4, m_modwritevalw); + break; + } + + return 6; +} + +UINT32 v60_device::am3DisplacementIndirect8() +{ + switch (m_moddim) + { + case 0: + m_program->write_byte(m_program->read_dword_unaligned(m_reg[m_modval & 0x1F] + (INT8)OpRead8(m_modadd + 1)), m_modwritevalb); + break; + case 1: + m_program->write_word_unaligned(m_program->read_dword_unaligned(m_reg[m_modval & 0x1F] + (INT8)OpRead8(m_modadd + 1)), m_modwritevalh); + break; + case 2: + m_program->write_dword_unaligned(m_program->read_dword_unaligned(m_reg[m_modval & 0x1F] + (INT8)OpRead8(m_modadd + 1)), m_modwritevalw); + break; + } + + return 2; +} + +UINT32 v60_device::am3DisplacementIndirect16() +{ + switch (m_moddim) + { + case 0: + m_program->write_byte(m_program->read_dword_unaligned(m_reg[m_modval & 0x1F] + (INT16)OpRead16(m_modadd + 1)), m_modwritevalb); + break; + case 1: + m_program->write_word_unaligned(m_program->read_dword_unaligned(m_reg[m_modval & 0x1F] + (INT16)OpRead16(m_modadd + 1)), m_modwritevalh); + break; + case 2: + m_program->write_dword_unaligned(m_program->read_dword_unaligned(m_reg[m_modval & 0x1F] + (INT16)OpRead16(m_modadd + 1)), m_modwritevalw); + break; + } + + return 3; +} + +UINT32 v60_device::am3DisplacementIndirect32() +{ + switch (m_moddim) + { + case 0: + m_program->write_byte(m_program->read_dword_unaligned(m_reg[m_modval & 0x1F] + OpRead32(m_modadd + 1)), m_modwritevalb); + break; + case 1: + m_program->write_word_unaligned(m_program->read_dword_unaligned(m_reg[m_modval & 0x1F] + OpRead32(m_modadd + 1)), m_modwritevalh); + break; + case 2: + m_program->write_dword_unaligned(m_program->read_dword_unaligned(m_reg[m_modval & 0x1F] + OpRead32(m_modadd + 1)), m_modwritevalw); + break; + } + + return 5; +} + + +UINT32 v60_device::am3DisplacementIndirectIndexed8() +{ + switch (m_moddim) + { + case 0: + m_program->write_byte(m_program->read_dword_unaligned(m_reg[m_modval2 & 0x1F] + (INT8)OpRead8(m_modadd + 2)) + m_reg[m_modval & 0x1F], m_modwritevalb); + break; + case 1: + m_program->write_word_unaligned(m_program->read_dword_unaligned(m_reg[m_modval2 & 0x1F] + (INT8)OpRead8(m_modadd + 2)) + m_reg[m_modval & 0x1F] * 2, m_modwritevalh); + break; + case 2: + m_program->write_dword_unaligned(m_program->read_dword_unaligned(m_reg[m_modval2 & 0x1F] + (INT8)OpRead8(m_modadd + 2)) + m_reg[m_modval & 0x1F] * 4, m_modwritevalw); + break; + } + + return 3; +} + +UINT32 v60_device::am3DisplacementIndirectIndexed16() +{ + switch (m_moddim) + { + case 0: + m_program->write_byte(m_program->read_dword_unaligned(m_reg[m_modval2 & 0x1F] + (INT16)OpRead16(m_modadd + 2)) + m_reg[m_modval & 0x1F], m_modwritevalb); + break; + case 1: + m_program->write_word_unaligned(m_program->read_dword_unaligned(m_reg[m_modval2 & 0x1F] + (INT16)OpRead16(m_modadd + 2)) + m_reg[m_modval & 0x1F] * 2, m_modwritevalh); + break; + case 2: + m_program->write_dword_unaligned(m_program->read_dword_unaligned(m_reg[m_modval2 & 0x1F] + (INT16)OpRead16(m_modadd + 2)) + m_reg[m_modval & 0x1F] * 4, m_modwritevalw); + break; + } + + return 4; +} + +UINT32 v60_device::am3DisplacementIndirectIndexed32() +{ + switch (m_moddim) + { + case 0: + m_program->write_byte(m_program->read_dword_unaligned(m_reg[m_modval2 & 0x1F] + OpRead32(m_modadd + 2)) + m_reg[m_modval & 0x1F], m_modwritevalb); + break; + case 1: + m_program->write_word_unaligned(m_program->read_dword_unaligned(m_reg[m_modval2 & 0x1F] + OpRead32(m_modadd + 2)) + m_reg[m_modval & 0x1F] * 2, m_modwritevalh); + break; + case 2: + m_program->write_dword_unaligned(m_program->read_dword_unaligned(m_reg[m_modval2 & 0x1F] + OpRead32(m_modadd + 2)) + m_reg[m_modval & 0x1F] * 4, m_modwritevalw); + break; + } + + return 6; +} + +UINT32 v60_device::am3PCDisplacementIndirect8() +{ + switch (m_moddim) + { + case 0: + m_program->write_byte(m_program->read_dword_unaligned(PC + (INT8)OpRead8(m_modadd + 1)), m_modwritevalb); + break; + case 1: + m_program->write_word_unaligned(m_program->read_dword_unaligned(PC + (INT8)OpRead8(m_modadd + 1)), m_modwritevalh); + break; + case 2: + m_program->write_dword_unaligned(m_program->read_dword_unaligned(PC + (INT8)OpRead8(m_modadd + 1)), m_modwritevalw); + break; + } + + return 2; +} + +UINT32 v60_device::am3PCDisplacementIndirect16() +{ + switch (m_moddim) + { + case 0: + m_program->write_byte(m_program->read_dword_unaligned(PC + (INT16)OpRead16(m_modadd + 1)), m_modwritevalb); + break; + case 1: + m_program->write_word_unaligned(m_program->read_dword_unaligned(PC + (INT16)OpRead16(m_modadd + 1)), m_modwritevalh); + break; + case 2: + m_program->write_dword_unaligned(m_program->read_dword_unaligned(PC + (INT16)OpRead16(m_modadd + 1)), m_modwritevalw); + break; + } + + return 3; +} + +UINT32 v60_device::am3PCDisplacementIndirect32() +{ + switch (m_moddim) + { + case 0: + m_program->write_byte(m_program->read_dword_unaligned(PC + OpRead32(m_modadd + 1)), m_modwritevalb); + break; + case 1: + m_program->write_word_unaligned(m_program->read_dword_unaligned(PC + OpRead32(m_modadd + 1)), m_modwritevalh); + break; + case 2: + m_program->write_dword_unaligned(m_program->read_dword_unaligned(PC + OpRead32(m_modadd + 1)), m_modwritevalw); + break; + } + + return 5; +} + + +UINT32 v60_device::am3PCDisplacementIndirectIndexed8() +{ + switch (m_moddim) + { + case 0: + m_program->write_byte(m_program->read_dword_unaligned(PC + (INT8)OpRead8(m_modadd + 2)) + m_reg[m_modval & 0x1F], m_modwritevalb); + break; + case 1: + m_program->write_word_unaligned(m_program->read_dword_unaligned(PC + (INT8)OpRead8(m_modadd + 2)) + m_reg[m_modval & 0x1F] * 2, m_modwritevalh); + break; + case 2: + m_program->write_dword_unaligned(m_program->read_dword_unaligned(PC + (INT8)OpRead8(m_modadd + 2)) + m_reg[m_modval & 0x1F] * 4, m_modwritevalw); + break; + } + + return 3; +} + +UINT32 v60_device::am3PCDisplacementIndirectIndexed16() +{ + switch (m_moddim) + { + case 0: + m_program->write_byte(m_program->read_dword_unaligned(PC + (INT16)OpRead16(m_modadd + 2)) + m_reg[m_modval & 0x1F], m_modwritevalb); + break; + case 1: + m_program->write_word_unaligned(m_program->read_dword_unaligned(PC + (INT16)OpRead16(m_modadd + 2)) + m_reg[m_modval & 0x1F] * 2, m_modwritevalh); + break; + case 2: + m_program->write_dword_unaligned(m_program->read_dword_unaligned(PC + (INT16)OpRead16(m_modadd + 2)) + m_reg[m_modval & 0x1F] * 4, m_modwritevalw); + break; + } + + return 4; +} + +UINT32 v60_device::am3PCDisplacementIndirectIndexed32() +{ + switch (m_moddim) + { + case 0: + m_program->write_byte(m_program->read_dword_unaligned(PC + OpRead32(m_modadd + 2)) + m_reg[m_modval & 0x1F], m_modwritevalb); + break; + case 1: + m_program->write_word_unaligned(m_program->read_dword_unaligned(PC + OpRead32(m_modadd + 2)) + m_reg[m_modval & 0x1F] * 2, m_modwritevalh); + break; + case 2: + m_program->write_dword_unaligned(m_program->read_dword_unaligned(PC + OpRead32(m_modadd + 2)) + m_reg[m_modval & 0x1F] * 4, m_modwritevalw); + break; + } + + return 6; +} + + +UINT32 v60_device::am3DoubleDisplacement8() +{ + switch (m_moddim) + { + case 0: + m_program->write_byte(m_program->read_dword_unaligned(m_reg[m_modval & 0x1F] + (INT8)OpRead8(m_modadd + 1)) + (INT8)OpRead8(m_modadd + 2), m_modwritevalb); + break; + case 1: + m_program->write_word_unaligned(m_program->read_dword_unaligned(m_reg[m_modval & 0x1F] + (INT8)OpRead8(m_modadd + 1)) + (INT8)OpRead8(m_modadd + 2), m_modwritevalh); + break; + case 2: + m_program->write_dword_unaligned(m_program->read_dword_unaligned(m_reg[m_modval & 0x1F] + (INT8)OpRead8(m_modadd + 1)) + (INT8)OpRead8(m_modadd + 2), m_modwritevalw); + break; + } + + return 3; +} + +UINT32 v60_device::am3DoubleDisplacement16() +{ + switch (m_moddim) + { + case 0: + m_program->write_byte(m_program->read_dword_unaligned(m_reg[m_modval & 0x1F] + (INT16)OpRead16(m_modadd + 1)) + (INT16)OpRead16(m_modadd + 3), m_modwritevalb); + break; + case 1: + m_program->write_word_unaligned(m_program->read_dword_unaligned(m_reg[m_modval & 0x1F] + (INT16)OpRead16(m_modadd + 1)) + (INT16)OpRead16(m_modadd + 3), m_modwritevalh); + break; + case 2: + m_program->write_dword_unaligned(m_program->read_dword_unaligned(m_reg[m_modval & 0x1F] + (INT16)OpRead16(m_modadd + 1)) + (INT16)OpRead16(m_modadd + 3), m_modwritevalw); + break; + } + + return 5; +} + +UINT32 v60_device::am3DoubleDisplacement32() +{ + switch (m_moddim) + { + case 0: + m_program->write_byte(m_program->read_dword_unaligned(m_reg[m_modval & 0x1F] + OpRead32(m_modadd + 1)) + OpRead32(m_modadd + 5), m_modwritevalb); + break; + case 1: + m_program->write_word_unaligned(m_program->read_dword_unaligned(m_reg[m_modval & 0x1F] + OpRead32(m_modadd + 1)) + OpRead32(m_modadd + 5), m_modwritevalh); + break; + case 2: + m_program->write_dword_unaligned(m_program->read_dword_unaligned(m_reg[m_modval & 0x1F] + OpRead32(m_modadd + 1)) + OpRead32(m_modadd + 5), m_modwritevalw); + break; + } + + return 9; +} + + +UINT32 v60_device::am3PCDoubleDisplacement8() +{ + switch (m_moddim) + { + case 0: + m_program->write_byte(m_program->read_dword_unaligned(PC + (INT8)OpRead8(m_modadd + 1)) + (INT8)OpRead8(m_modadd + 2), m_modwritevalb); + break; + case 1: + m_program->write_word_unaligned(m_program->read_dword_unaligned(PC + (INT8)OpRead8(m_modadd + 1)) + (INT8)OpRead8(m_modadd + 2), m_modwritevalh); + break; + case 2: + m_program->write_dword_unaligned(m_program->read_dword_unaligned(PC + (INT8)OpRead8(m_modadd + 1)) + (INT8)OpRead8(m_modadd + 2), m_modwritevalw); + break; + } + + return 3; +} + +UINT32 v60_device::am3PCDoubleDisplacement16() +{ + switch (m_moddim) + { + case 0: + m_program->write_byte(m_program->read_dword_unaligned(PC + (INT16)OpRead16(m_modadd + 1)) + (INT16)OpRead16(m_modadd + 3), m_modwritevalb); + break; + case 1: + m_program->write_word_unaligned(m_program->read_dword_unaligned(PC + (INT16)OpRead16(m_modadd + 1)) + (INT16)OpRead16(m_modadd + 3), m_modwritevalh); + break; + case 2: + m_program->write_dword_unaligned(m_program->read_dword_unaligned(PC + (INT16)OpRead16(m_modadd + 1)) + (INT16)OpRead16(m_modadd + 3), m_modwritevalw); + break; + } + + return 5; +} + +UINT32 v60_device::am3PCDoubleDisplacement32() +{ + switch (m_moddim) + { + case 0: + m_program->write_byte(m_program->read_dword_unaligned(PC + OpRead32(m_modadd + 1)) + OpRead32(m_modadd + 5), m_modwritevalb); + break; + case 1: + m_program->write_word_unaligned(m_program->read_dword_unaligned(PC + OpRead32(m_modadd + 1)) + OpRead32(m_modadd + 5), m_modwritevalh); + break; + case 2: + m_program->write_dword_unaligned(m_program->read_dword_unaligned(PC + OpRead32(m_modadd + 1)) + OpRead32(m_modadd + 5), m_modwritevalw); + break; + } + + return 9; +} + +UINT32 v60_device::am3DirectAddress() +{ + switch (m_moddim) + { + case 0: + m_program->write_byte(OpRead32(m_modadd + 1), m_modwritevalb); + break; + case 1: + m_program->write_word_unaligned(OpRead32(m_modadd + 1), m_modwritevalh); + break; + case 2: + m_program->write_dword_unaligned(OpRead32(m_modadd + 1), m_modwritevalw); + break; + } + + return 5; +} + +UINT32 v60_device::am3DirectAddressIndexed() +{ + switch (m_moddim) + { + case 0: + m_program->write_byte(OpRead32(m_modadd + 2) + m_reg[m_modval & 0x1F], m_modwritevalb); + break; + case 1: + m_program->write_word_unaligned(OpRead32(m_modadd + 2) + m_reg[m_modval & 0x1F] * 2, m_modwritevalh); + break; + case 2: + m_program->write_dword_unaligned(OpRead32(m_modadd + 2) + m_reg[m_modval & 0x1F] * 4, m_modwritevalw); + break; + } + + return 6; +} + +UINT32 v60_device::am3DirectAddressDeferred() +{ + switch (m_moddim) + { + case 0: + m_program->write_byte(m_program->read_dword_unaligned(OpRead32(m_modadd + 1)), m_modwritevalb); + break; + case 1: + m_program->write_word_unaligned(m_program->read_dword_unaligned(OpRead32(m_modadd + 1)), m_modwritevalh); + break; + case 2: + m_program->write_dword_unaligned(m_program->read_dword_unaligned(OpRead32(m_modadd + 1)), m_modwritevalw); + break; + } + + return 5; +} + +UINT32 v60_device::am3DirectAddressDeferredIndexed() +{ + switch (m_moddim) + { + case 0: + m_program->write_byte(m_program->read_dword_unaligned(OpRead32(m_modadd + 2)) + m_reg[m_modval & 0x1F], m_modwritevalb); + break; + case 1: + m_program->write_word_unaligned(m_program->read_dword_unaligned(OpRead32(m_modadd + 2)) + m_reg[m_modval & 0x1F], m_modwritevalh); + break; + case 2: + m_program->write_dword_unaligned(m_program->read_dword_unaligned(OpRead32(m_modadd + 2)) + m_reg[m_modval & 0x1F], m_modwritevalw); + break; + } + + return 6; +} + +UINT32 v60_device::am3Immediate() +{ + fatalerror("CPU - AM3 - IMM (PC=%06x)\n", PC); + return 0; /* never reached, fatalerror won't return */ +} + +UINT32 v60_device::am3ImmediateQuick() +{ + fatalerror("CPU - AM3 - IMMQ (PC=%06x)\n", PC); + return 0; /* never reached, fatalerror won't return */ +} + + + +// AM3 Tables (for ReadAMAddress) +// ****************************** + +UINT32 v60_device::am3Error1() +{ + fatalerror("CPU - AM3 - 1 (PC=%06x)\n", PC); + return 0; /* never reached, fatalerror won't return */ +} + +UINT32 v60_device::am3Error2() +{ + fatalerror("CPU - AM3 - 2 (PC=%06x)\n", PC); + return 0; /* never reached, fatalerror won't return */ +} + +#ifdef UNUSED_FUNCTION +UINT32 v60_device::am3Error3() +{ + fatalerror("CPU - AM3 - 3 (PC=%06x)\n", PC); + return 0; /* never reached, fatalerror won't return */ +} +#endif + +UINT32 v60_device::am3Error4() +{ + fatalerror("CPU - AM3 - 4 (PC=%06x)\n", PC); + return 0; /* never reached, fatalerror won't return */ +} + +UINT32 v60_device::am3Error5() +{ + fatalerror("CPU - AM3 - 5 (PC=%06x)\n", PC); + return 0; /* never reached, fatalerror won't return */ +} + +const v60_device::am_func v60_device::s_AMTable3_G7a[16] = +{ + &v60_device::am3PCDisplacementIndexed8, + &v60_device::am3PCDisplacementIndexed16, + &v60_device::am3PCDisplacementIndexed32, + &v60_device::am3DirectAddressIndexed, + &v60_device::am3Error5, + &v60_device::am3Error5, + &v60_device::am3Error5, + &v60_device::am3Error5, + &v60_device::am3PCDisplacementIndirectIndexed8, + &v60_device::am3PCDisplacementIndirectIndexed16, + &v60_device::am3PCDisplacementIndirectIndexed32, + &v60_device::am3DirectAddressDeferredIndexed, + &v60_device::am3Error5, + &v60_device::am3Error5, + &v60_device::am3Error5, + &v60_device::am3Error5 +}; + +UINT32 v60_device::am3Group7a() +{ + if (!(m_modval2 & 0x10)) + return am3Error4(); + + return (this->*s_AMTable3_G7a[m_modval2 & 0xF])(); +} + +const v60_device::am_func v60_device::s_AMTable3_G7[32] = +{ + &v60_device::am3ImmediateQuick, + &v60_device::am3ImmediateQuick, + &v60_device::am3ImmediateQuick, + &v60_device::am3ImmediateQuick, + &v60_device::am3ImmediateQuick, + &v60_device::am3ImmediateQuick, + &v60_device::am3ImmediateQuick, + &v60_device::am3ImmediateQuick, + &v60_device::am3ImmediateQuick, + &v60_device::am3ImmediateQuick, + &v60_device::am3ImmediateQuick, + &v60_device::am3ImmediateQuick, + &v60_device::am3ImmediateQuick, + &v60_device::am3ImmediateQuick, + &v60_device::am3ImmediateQuick, + &v60_device::am3ImmediateQuick, + &v60_device::am3PCDisplacement8, + &v60_device::am3PCDisplacement16, + &v60_device::am3PCDisplacement32, + &v60_device::am3DirectAddress, + &v60_device::am3Immediate, + &v60_device::am3Error2, + &v60_device::am3Error2, + &v60_device::am3Error2, + &v60_device::am3PCDisplacementIndirect8, + &v60_device::am3PCDisplacementIndirect16, + &v60_device::am3PCDisplacementIndirect32, + &v60_device::am3DirectAddressDeferred, + &v60_device::am3PCDoubleDisplacement8, + &v60_device::am3PCDoubleDisplacement16, + &v60_device::am3PCDoubleDisplacement32, + &v60_device::am3Error2 +}; + +const v60_device::am_func v60_device::s_AMTable3_G6[8] = +{ + &v60_device::am3DisplacementIndexed8, + &v60_device::am3DisplacementIndexed16, + &v60_device::am3DisplacementIndexed32, + &v60_device::am3RegisterIndirectIndexed, + &v60_device::am3DisplacementIndirectIndexed8, + &v60_device::am3DisplacementIndirectIndexed16, + &v60_device::am3DisplacementIndirectIndexed32, + &v60_device::am3Group7a +}; + + + + +UINT32 v60_device::am3Group6() +{ + m_modval2 = OpRead8(m_modadd + 1); + return (this->*s_AMTable3_G6[m_modval2 >> 5])(); +} + + +UINT32 v60_device::am3Group7() +{ + return (this->*s_AMTable3_G7[m_modval & 0x1F])(); +} + + + +const v60_device::am_func v60_device::s_AMTable3[2][8] = +{ + { + &v60_device::am3Displacement8, + &v60_device::am3Displacement16, + &v60_device::am3Displacement32, + &v60_device::am3RegisterIndirect, + &v60_device::am3DisplacementIndirect8, + &v60_device::am3DisplacementIndirect16, + &v60_device::am3DisplacementIndirect32, + &v60_device::am3Group7 + }, + + { + &v60_device::am3DoubleDisplacement8, + &v60_device::am3DoubleDisplacement16, + &v60_device::am3DoubleDisplacement32, + &v60_device::am3Register, + &v60_device::am3Autoincrement, + &v60_device::am3Autodecrement, + &v60_device::am3Group6, + &v60_device::am3Error1 + } +}; diff --git a/src/devices/cpu/v60/op12.inc b/src/devices/cpu/v60/op12.inc new file mode 100644 index 00000000000..319e9995595 --- /dev/null +++ b/src/devices/cpu/v60/op12.inc @@ -0,0 +1,2393 @@ +// license:BSD-3-Clause +// copyright-holders:Farfetch'd, R. Belmont +/* + * MUL* and MULU* do not set OV correctly + * DIVX: the second operand should be treated as dword instead of word + * GETATE, GETPTE and GETRA should not be used + * UPDPSW: _CY and _OV must be cleared or unchanged? I suppose + * cleared, like TEST being done on the mask operand. + * MOVT: I cannot understand exactly what happens to the result + * when an overflow occurs + * + * Unimplemented opcodes: + * ROTC, UPDATE, UPDPTE + */ + + +/* + * Macro to access data in operands decoded with ReadAMAddress() + */ + +#define F12LOADOPBYTE(num) \ + if (m_flag##num) \ + appb = (UINT8)m_reg[m_op##num]; \ + else \ + appb = m_program->read_byte(m_op##num); + +#define F12LOADOPHALF(num) \ + if (m_flag##num) \ + apph = (UINT16)m_reg[m_op##num]; \ + else \ + apph = m_program->read_word_unaligned(m_op##num); + +#define F12LOADOPWORD(num) \ + if (m_flag##num) \ + appw = m_reg[m_op##num]; \ + else \ + appw = m_program->read_dword_unaligned(m_op##num); + +#define F12STOREOPBYTE(num) \ + if (m_flag##num) \ + SETREG8(m_reg[m_op##num], appb); \ + else \ + m_program->write_byte(m_op##num, appb); + +#define F12STOREOPHALF(num) \ + if (m_flag##num) \ + SETREG16(m_reg[m_op##num], apph); \ + else \ + m_program->write_word_unaligned(m_op##num, apph); + +#define F12STOREOPWORD(num) \ + if (m_flag##num) \ + m_reg[m_op##num] = appw; \ + else \ + m_program->write_dword_unaligned(m_op##num, appw); + +#define F12LOADOP1BYTE() F12LOADOPBYTE(1) +#define F12LOADOP1HALF() F12LOADOPHALF(1) +#define F12LOADOP1WORD() F12LOADOPWORD(1) + +#define F12LOADOP2BYTE() F12LOADOPBYTE(2) +#define F12LOADOP2HALF() F12LOADOPHALF(2) +#define F12LOADOP2WORD() F12LOADOPWORD(2) + +#define F12STOREOP1BYTE() F12STOREOPBYTE(1) +#define F12STOREOP1HALF() F12STOREOPHALF(1) +#define F12STOREOP1WORD() F12STOREOPWORD(1) + +#define F12STOREOP2BYTE() F12STOREOPBYTE(2) +#define F12STOREOP2HALF() F12STOREOPHALF(2) +#define F12STOREOP2WORD() F12STOREOPWORD(2) + +#define F12END() \ + return m_amlength1 + m_amlength2 + 2; + + +// Decode the first operand of the instruction and prepare +// writing to the second operand. +void v60_device::F12DecodeFirstOperand(am_func DecodeOp1, UINT8 dim1) +{ + m_instflags = OpRead8(PC + 1); + + // Check if F1 or F2 + if (m_instflags & 0x80) + { + m_moddim = dim1; + m_modm = m_instflags & 0x40; + m_modadd = PC + 2; + m_amlength1 = (this->*DecodeOp1)(); + m_op1 = m_amout; + m_flag1 = m_amflag; + } + else + { + // Check D flag + if (m_instflags & 0x20) + { + m_moddim = dim1; + m_modm = m_instflags & 0x40; + m_modadd = PC + 2; + m_amlength1 = (this->*DecodeOp1)(); + m_op1 = m_amout; + m_flag1 = m_amflag; + } + else + { + if (DecodeOp1 == &v60_device::ReadAM) + { + switch (dim1) + { + case 0: + m_op1 = (UINT8)m_reg[m_instflags & 0x1F]; + break; + case 1: + m_op1 = (UINT16)m_reg[m_instflags & 0x1F]; + break; + case 2: + m_op1 = m_reg[m_instflags & 0x1F]; + break; + } + + m_flag1 = 0; + } + else + { + m_flag1 = 1; + m_op1 = m_instflags & 0x1F; + } + + m_amlength1 = 0; + } + } +} + +void v60_device::F12WriteSecondOperand(UINT8 dim2) +{ + m_moddim = dim2; + + // Check if F1 or F2 + if (m_instflags & 0x80) + { + m_modm = m_instflags & 0x20; + m_modadd = PC + 2 + m_amlength1; + m_moddim = dim2; + m_amlength2 = WriteAM(); + } + else + { + // Check D flag + if (m_instflags & 0x20) + { + switch (dim2) + { + case 0: + SETREG8(m_reg[m_instflags & 0x1F], m_modwritevalb); + break; + case 1: + SETREG16(m_reg[m_instflags & 0x1F], m_modwritevalh); + break; + case 2: + m_reg[m_instflags & 0x1F] = m_modwritevalw; + break; + } + + m_amlength2 = 0; + } + else + { + m_modm = m_instflags & 0x40; + m_modadd = PC + 2; + m_moddim = dim2; + m_amlength2 = WriteAM(); + } + } +} + + + +// Decode both format 1 / 2 operands +void v60_device::F12DecodeOperands(am_func DecodeOp1, UINT8 dim1, am_func DecodeOp2, UINT8 dim2) +{ + UINT8 _if12 = OpRead8(PC + 1); + + // Check if F1 or F2 + if (_if12 & 0x80) + { + m_moddim = dim1; + m_modm = _if12 & 0x40; + m_modadd = PC + 2; + m_amlength1 = (this->*DecodeOp1)(); + m_op1 = m_amout; + m_flag1 = m_amflag; + + m_moddim = dim2; + m_modm = _if12 & 0x20; + m_modadd = PC + 2 + m_amlength1; + m_amlength2 = (this->*DecodeOp2)(); + m_op2 = m_amout; + m_flag2 = m_amflag; + } + else + { + // Check D flag + if (_if12 & 0x20) + { + if (DecodeOp2 == &v60_device::ReadAMAddress) + { + m_op2 = _if12 & 0x1F; + m_flag2 = 1; + } + else + { + switch (dim2) + { + case 0: + m_op2 = (UINT8)m_reg[_if12 & 0x1F]; + break; + case 1: + m_op2 = (UINT16)m_reg[_if12 & 0x1F]; + break; + case 2: + m_op2 = m_reg[_if12 & 0x1F]; + break; + } + } + + m_amlength2 = 0; + + m_moddim = dim1; + m_modm = _if12 & 0x40; + m_modadd = PC + 2; + m_amlength1 = (this->*DecodeOp1)(); + m_op1 = m_amout; + m_flag1 = m_amflag; + } + else + { + if (DecodeOp1 == &v60_device::ReadAMAddress) + { + m_op1 = _if12 & 0x1F; + m_flag1 = 1; + } + else + { + switch (dim1) + { + case 0: + m_op1 = (UINT8)m_reg[_if12 & 0x1F]; + break; + case 1: + m_op1 = (UINT16)m_reg[_if12 & 0x1F]; + break; + case 2: + m_op1 = m_reg[_if12 & 0x1F]; + break; + } + } + m_amlength1 = 0; + + m_moddim = dim2; + m_modm = _if12 & 0x40; + m_modadd = PC + 2 + m_amlength1; + m_amlength2 = (this->*DecodeOp2)(); + m_op2 = m_amout; + m_flag2 = m_amflag; + } + } +} + +UINT32 v60_device::opADDB() /* TRUSTED (C too!)*/ +{ + UINT8 appb; + F12DecodeOperands(&v60_device::ReadAM, 0,&v60_device::ReadAMAddress, 0); + + F12LOADOP2BYTE(); + + ADDB(appb, (UINT8)m_op1); + + F12STOREOP2BYTE(); + F12END(); +} + +UINT32 v60_device::opADDH() /* TRUSTED (C too!)*/ +{ + UINT16 apph; + F12DecodeOperands(&v60_device::ReadAM, 1,&v60_device::ReadAMAddress, 1); + + F12LOADOP2HALF(); + + ADDW(apph, (UINT16)m_op1); + + F12STOREOP2HALF(); + F12END(); +} + +UINT32 v60_device::opADDW() /* TRUSTED (C too!) */ +{ + UINT32 appw; + F12DecodeOperands(&v60_device::ReadAM, 2,&v60_device::ReadAMAddress, 2); + + F12LOADOP2WORD(); + + ADDL(appw, (UINT32)m_op1); + + F12STOREOP2WORD(); + F12END(); +} + +UINT32 v60_device::opADDCB() +{ + UINT8 appb, temp; + + F12DecodeOperands(&v60_device::ReadAM, 0,&v60_device::ReadAMAddress, 0); + + F12LOADOP2BYTE(); + + temp = ((UINT8)m_op1 + (_CY?1:0)); + ADDB(appb, temp); + + F12STOREOP2BYTE(); + F12END(); +} + +UINT32 v60_device::opADDCH() +{ + UINT16 apph, temp; + + F12DecodeOperands(&v60_device::ReadAM, 1,&v60_device::ReadAMAddress, 1); + + F12LOADOP2HALF(); + + temp = ((UINT16)m_op1 + (_CY?1:0)); + ADDW(apph, temp); + + F12STOREOP2HALF(); + F12END(); +} + +UINT32 v60_device::opADDCW() +{ + UINT32 appw, temp; + + F12DecodeOperands(&v60_device::ReadAM, 2,&v60_device::ReadAMAddress, 2); + + F12LOADOP2WORD(); + + temp = m_op1 + (_CY?1:0); + ADDL(appw, temp); + + F12STOREOP2WORD(); + F12END(); +} + +UINT32 v60_device::opANDB() /* TRUSTED */ +{ + UINT8 appb; + F12DecodeOperands(&v60_device::ReadAM, 0,&v60_device::ReadAMAddress, 0); + + F12LOADOP2BYTE(); + + appb &= m_op1; + _OV = 0; + _S = ((appb & 0x80) != 0); + _Z = (appb == 0); + + F12STOREOP2BYTE(); + F12END(); +} + +UINT32 v60_device::opANDH() /* TRUSTED */ +{ + UINT16 apph; + F12DecodeOperands(&v60_device::ReadAM, 1,&v60_device::ReadAMAddress, 1); + + F12LOADOP2HALF(); + + apph &= m_op1; + _OV = 0; + _S = ((apph & 0x8000) != 0); + _Z = (apph == 0); + + F12STOREOP2HALF(); + F12END(); +} + +UINT32 v60_device::opANDW() /* TRUSTED */ +{ + UINT32 appw; + F12DecodeOperands(&v60_device::ReadAM, 2,&v60_device::ReadAMAddress, 2); + + F12LOADOP2WORD(); + + appw &= m_op1; + _OV = 0; + _S = ((appw & 0x80000000) != 0); + _Z = (appw == 0); + + F12STOREOP2WORD(); + F12END(); +} + +UINT32 v60_device::opCALL() /* TRUSTED */ +{ + F12DecodeOperands(&v60_device::ReadAMAddress, 0,&v60_device::ReadAMAddress, 2); + + SP -= 4; + m_program->write_dword_unaligned(SP, AP); + AP = m_op2; + + SP -= 4; + m_program->write_dword_unaligned(SP, PC + m_amlength1 + m_amlength2 + 2); + PC = m_op1; + + return 0; +} + +UINT32 v60_device::opCHKAR() +{ + F12DecodeOperands(&v60_device::ReadAM, 0,&v60_device::ReadAM, 0); + + // No MMU and memory permissions yet @@@ + _Z = 1; + _CY = 0; + _S = 0; + + F12END(); +} + +UINT32 v60_device::opCHKAW() +{ + F12DecodeOperands(&v60_device::ReadAM, 0,&v60_device::ReadAM, 0); + + // No MMU and memory permissions yet @@@ + _Z = 1; + _CY = 0; + _S = 0; + + F12END(); +} + +UINT32 v60_device::opCHKAE() +{ + F12DecodeOperands(&v60_device::ReadAM, 0,&v60_device::ReadAM, 0); + + // No MMU and memory permissions yet @@@ + _Z = 1; + _CY = 0; + _S = 0; + + F12END(); +} + +UINT32 v60_device::opCHLVL() +{ + UINT32 oldPSW; + + F12DecodeOperands(&v60_device::ReadAM, 0,&v60_device::ReadAM, 0); + + if (m_op1 > 3) + { + fatalerror("Illegal data field on opCHLVL, PC=%x\n", PC); + } + + oldPSW = v60_update_psw_for_exception(0, m_op1); + + SP -= 4; + m_program->write_dword_unaligned(SP, m_op2); + + SP -= 4; + m_program->write_dword_unaligned(SP, EXCEPTION_CODE_AND_SIZE(0x1800 + m_op1 * 0x100, 8)); + + SP -= 4; + m_program->write_dword_unaligned(SP, oldPSW); + + SP -= 4; + m_program->write_dword_unaligned(SP, PC + m_amlength1 + m_amlength2 + 2); + + PC = GETINTVECT(24 + m_op1); + + return 0; +} + +UINT32 v60_device::opCLR1() /* TRUSTED */ +{ + UINT32 appw; + F12DecodeOperands(&v60_device::ReadAM, 2,&v60_device::ReadAMAddress, 2); + + F12LOADOP2WORD(); + + _CY = ((appw & (1 << m_op1)) != 0); + _Z = !(_CY); + + appw &= ~(1 << m_op1); + + F12STOREOP2WORD(); + F12END(); +} + +UINT32 v60_device::opCMPB() /* TRUSTED (C too!) */ +{ + UINT8 appb; + F12DecodeOperands(&v60_device::ReadAM, 0,&v60_device::ReadAM, 0); + + appb = (UINT8)m_op2; + SUBB(appb, (UINT8)m_op1); + + F12END(); +} + +UINT32 v60_device::opCMPH() /* TRUSTED (C too!) */ +{ + UINT16 apph; + F12DecodeOperands(&v60_device::ReadAM, 1,&v60_device::ReadAM, 1); + + apph = (UINT16)m_op2; + SUBW(apph, (UINT16)m_op1); + + F12END(); +} + + +UINT32 v60_device::opCMPW() /* TRUSTED (C too!)*/ +{ + F12DecodeOperands(&v60_device::ReadAM, 2,&v60_device::ReadAM, 2); + + SUBL(m_op2, (UINT32)m_op1); + + F12END(); +} + +UINT32 v60_device::opDIVB() /* TRUSTED */ +{ + UINT8 appb; + F12DecodeOperands(&v60_device::ReadAM, 0,&v60_device::ReadAMAddress, 0); + + F12LOADOP2BYTE(); + + _OV = ((appb == 0x80) && (m_op1 == 0xFF)); + if (m_op1 && !_OV) + appb= (INT8)appb / (INT8)m_op1; + _Z = (appb == 0); + _S = ((appb & 0x80) != 0); + + F12STOREOP2BYTE(); + F12END(); +} + +UINT32 v60_device::opDIVH() /* TRUSTED */ +{ + UINT16 apph; + F12DecodeOperands(&v60_device::ReadAM, 1,&v60_device::ReadAMAddress, 1); + + F12LOADOP2HALF(); + + _OV = ((apph == 0x8000) && (m_op1 == 0xFFFF)); + if (m_op1 && !_OV) + apph = (INT16)apph / (INT16)m_op1; + _Z = (apph == 0); + _S = ((apph & 0x8000) != 0); + + F12STOREOP2HALF(); + F12END(); +} + +UINT32 v60_device::opDIVW() /* TRUSTED */ +{ + UINT32 appw; + F12DecodeOperands(&v60_device::ReadAM, 2,&v60_device::ReadAMAddress, 2); + + F12LOADOP2WORD(); + + _OV = ((appw == 0x80000000) && (m_op1 == 0xFFFFFFFF)); + if (m_op1 && !_OV) + appw = (INT32)appw / (INT32)m_op1; + _Z = (appw == 0); + _S = ((appw & 0x80000000) != 0); + + F12STOREOP2WORD(); + F12END(); +} + +UINT32 v60_device::opDIVX() +{ + UINT32 a, b; + INT64 dv; + + F12DecodeOperands(&v60_device::ReadAM, 2,&v60_device::ReadAMAddress, 3); + + if (m_flag2) + { + a = m_reg[m_op2 & 0x1F]; + b = m_reg[(m_op2 & 0x1F) + 1]; + } + else + { + a = m_program->read_dword_unaligned(m_op2); + b = m_program->read_dword_unaligned(m_op2 + 4); + } + + dv = ((UINT64)b << 32) | ((UINT64)a); + + a = dv / (INT64)((INT32)m_op1); + b = dv % (INT64)((INT32)m_op1); + + _S = ((a & 0x80000000) != 0); + _Z = (a == 0); + + if (m_flag2) + { + m_reg[m_op2 & 0x1F] = a; + m_reg[(m_op2 & 0x1F) + 1] = b; + } + else + { + m_program->write_dword_unaligned(m_op2, a); + m_program->write_dword_unaligned(m_op2 + 4, b); + } + + F12END(); +} + +UINT32 v60_device::opDIVUX() +{ + UINT32 a, b; + UINT64 dv; + + F12DecodeOperands(&v60_device::ReadAM, 2,&v60_device::ReadAMAddress, 3); + + if (m_flag2) + { + a = m_reg[m_op2 & 0x1F]; + b = m_reg[(m_op2 & 0x1F) + 1]; + } + else + { + a = m_program->read_dword_unaligned(m_op2); + b = m_program->read_dword_unaligned(m_op2 + 4); + } + + dv = (UINT64)(((UINT64)b << 32) | (UINT64)a); + a = (UINT32)(dv / (UINT64)m_op1); + b = (UINT32)(dv % (UINT64)m_op1); + + _S = ((a & 0x80000000) != 0); + _Z = (a == 0); + + if (m_flag2) + { + m_reg[m_op2 & 0x1F] = a; + m_reg[(m_op2 & 0x1F) + 1] = b; + } + else + { + m_program->write_dword_unaligned(m_op2, a); + m_program->write_dword_unaligned(m_op2 + 4, b); + } + + F12END(); +} + + +UINT32 v60_device::opDIVUB() /* TRUSTED */ +{ + UINT8 appb; + F12DecodeOperands(&v60_device::ReadAM, 0,&v60_device::ReadAMAddress, 0); + + F12LOADOP2BYTE(); + + _OV = 0; + if (m_op1) appb /= (UINT8)m_op1; + _Z = (appb == 0); + _S = ((appb & 0x80) != 0); + + F12STOREOP2BYTE(); + F12END(); +} + +UINT32 v60_device::opDIVUH() /* TRUSTED */ +{ + UINT16 apph; + F12DecodeOperands(&v60_device::ReadAM, 1,&v60_device::ReadAMAddress, 1); + + F12LOADOP2HALF(); + + _OV = 0; + if (m_op1) apph /= (UINT16)m_op1; + _Z = (apph == 0); + _S = ((apph & 0x8000) != 0); + + F12STOREOP2HALF(); + F12END(); +} + +UINT32 v60_device::opDIVUW() /* TRUSTED */ +{ + UINT32 appw; + F12DecodeOperands(&v60_device::ReadAM, 2,&v60_device::ReadAMAddress, 2); + + F12LOADOP2WORD(); + + _OV = 0; + if (m_op1) appw /= m_op1; + _Z = (appw == 0); + _S = ((appw & 0x80000000) != 0); + + F12STOREOP2WORD(); + F12END(); +} + +UINT32 v60_device::opINB() +{ + F12DecodeFirstOperand(&v60_device::ReadAMAddress, 0); + m_modwritevalb = m_io->read_byte(m_op1); + + if ( m_stall_io ) + { + m_stall_io = 0; + return 0; + } + + F12WriteSecondOperand(0); + F12END(); +} + +UINT32 v60_device::opINH() +{ + F12DecodeFirstOperand(&v60_device::ReadAMAddress, 1); + m_modwritevalh = m_io->read_word_unaligned(m_op1); + + if ( m_stall_io ) + { + m_stall_io = 0; + return 0; + } + + F12WriteSecondOperand(1); + F12END(); +} + +UINT32 v60_device::opINW() +{ + F12DecodeFirstOperand(&v60_device::ReadAMAddress, 2); + m_modwritevalw = m_io->read_dword_unaligned(m_op1); + + if ( m_stall_io ) + { + m_stall_io = 0; + return 0; + } + + F12WriteSecondOperand(2); + F12END(); +} + +UINT32 v60_device::opLDPR() +{ + F12DecodeOperands(&v60_device::ReadAMAddress, 2,&v60_device::ReadAM, 2); + if (m_op2 <= 28) + { + if (m_flag1 &&(!(OpRead8(PC + 1)&0x80 && OpRead8(PC + 2) == 0xf4 ) )) + m_reg[m_op2 + 36] = m_reg[m_op1]; + else + m_reg[m_op2 + 36] = m_op1; + } + else + { + fatalerror("Invalid operand on LDPR PC=%x\n", PC); + } + F12END(); +} + +UINT32 v60_device::opLDTASK() +{ + int i; + F12DecodeOperands(&v60_device::ReadAMAddress, 2,&v60_device::ReadAM, 2); + + v60WritePSW(v60ReadPSW() & 0xefffffff); + + TR = m_op2; + + TKCW = m_program->read_dword_unaligned(m_op2); + m_op2 += 4; + if(SYCW & 0x100) { + L0SP = m_program->read_dword_unaligned(m_op2); + m_op2 += 4; + } + if(SYCW & 0x200) { + L1SP = m_program->read_dword_unaligned(m_op2); + m_op2 += 4; + } + if(SYCW & 0x400) { + L2SP = m_program->read_dword_unaligned(m_op2); + m_op2 += 4; + } + if(SYCW & 0x800) { + L3SP = m_program->read_dword_unaligned(m_op2); + m_op2 += 4; + } + + v60ReloadStack(); + + // 31 registers supported, _not_ 32 + for(i = 0; i < 31; i++) + if(m_op1 & (1 << i)) { + m_reg[i] = m_program->read_dword_unaligned(m_op2); + m_op2 += 4; + } + + // #### Ignore the virtual addressing crap. + + F12END(); +} + +UINT32 v60_device::opMOVD() /* TRUSTED */ +{ + UINT32 a, b; + + F12DecodeOperands(&v60_device::ReadAMAddress, 3,&v60_device::ReadAMAddress, 3); + + if (m_flag1) + { + a = m_reg[m_op1 & 0x1F]; + b = m_reg[(m_op1 & 0x1F) + 1]; + } + else + { + a = m_program->read_dword_unaligned(m_op1); + b = m_program->read_dword_unaligned(m_op1 + 4); + } + + if (m_flag2) + { + m_reg[m_op2 & 0x1F] = a; + m_reg[(m_op2 & 0x1F) + 1] = b; + } + else + { + m_program->write_dword_unaligned(m_op2, a); + m_program->write_dword_unaligned(m_op2 + 4, b); + } + + F12END(); +} + +UINT32 v60_device::opMOVB() /* TRUSTED */ +{ + F12DecodeFirstOperand(&v60_device::ReadAM, 0); + m_modwritevalb = (UINT8)m_op1; + F12WriteSecondOperand(0); + F12END(); +} + +UINT32 v60_device::opMOVH() /* TRUSTED */ +{ + F12DecodeFirstOperand(&v60_device::ReadAM, 1); + m_modwritevalh = (UINT16)m_op1; + F12WriteSecondOperand(1); + F12END(); +} + +UINT32 v60_device::opMOVW() /* TRUSTED */ +{ + F12DecodeFirstOperand(&v60_device::ReadAM, 2); + m_modwritevalw = m_op1; + F12WriteSecondOperand(2); + F12END(); +} + +UINT32 v60_device::opMOVEAB() /* TRUSTED */ +{ + F12DecodeFirstOperand(&v60_device::ReadAMAddress, 0); + m_modwritevalw = m_op1; + F12WriteSecondOperand(2); + F12END(); +} + +UINT32 v60_device::opMOVEAH() /* TRUSTED */ +{ + F12DecodeFirstOperand(&v60_device::ReadAMAddress, 1); + m_modwritevalw = m_op1; + F12WriteSecondOperand(2); + F12END(); +} + +UINT32 v60_device::opMOVEAW() /* TRUSTED */ +{ + F12DecodeFirstOperand(&v60_device::ReadAMAddress, 2); + m_modwritevalw = m_op1; + F12WriteSecondOperand(2); + F12END(); +} + +UINT32 v60_device::opMOVSBH() /* TRUSTED */ +{ + F12DecodeFirstOperand(&v60_device::ReadAM, 0); + m_modwritevalh = (INT8)(m_op1 & 0xFF); + F12WriteSecondOperand(1); + F12END(); +} + +UINT32 v60_device::opMOVSBW() /* TRUSTED */ +{ + F12DecodeFirstOperand(&v60_device::ReadAM, 0); + m_modwritevalw = (INT8)(m_op1 & 0xFF); + F12WriteSecondOperand(2); + F12END(); +} + +UINT32 v60_device::opMOVSHW() /* TRUSTED */ +{ + F12DecodeFirstOperand(&v60_device::ReadAM, 1); + m_modwritevalw = (INT16)(m_op1 & 0xFFFF); + F12WriteSecondOperand(2); + F12END(); +} + +UINT32 v60_device::opMOVTHB() +{ + F12DecodeFirstOperand(&v60_device::ReadAM, 1); + m_modwritevalb = (UINT8)(m_op1 & 0xFF); + + // Check for overflow: the truncated bits must match the sign + // of the result, otherwise overflow + if (((m_modwritevalb & 0x80) == 0x80 && ((m_op1 & 0xFF00) == 0xFF00)) || + ((m_modwritevalb & 0x80) == 0 && ((m_op1 & 0xFF00) == 0x0000))) + _OV = 0; + else + _OV = 1; + + F12WriteSecondOperand(0); + F12END(); +} + +UINT32 v60_device::opMOVTWB() +{ + F12DecodeFirstOperand(&v60_device::ReadAM, 2); + m_modwritevalb = (UINT8)(m_op1 & 0xFF); + + // Check for overflow: the truncated bits must match the sign + // of the result, otherwise overflow + if (((m_modwritevalb & 0x80) == 0x80 && ((m_op1 & 0xFFFFFF00) == 0xFFFFFF00)) || + ((m_modwritevalb & 0x80) == 0 && ((m_op1 & 0xFFFFFF00) == 0x00000000))) + _OV = 0; + else + _OV = 1; + + F12WriteSecondOperand(0); + F12END(); +} + +UINT32 v60_device::opMOVTWH() +{ + F12DecodeFirstOperand(&v60_device::ReadAM, 2); + m_modwritevalh = (UINT16)(m_op1 & 0xFFFF); + + // Check for overflow: the truncated bits must match the sign + // of the result, otherwise overflow + if (((m_modwritevalh & 0x8000) == 0x8000 && ((m_op1 & 0xFFFF0000) == 0xFFFF0000)) || + ((m_modwritevalh & 0x8000) == 0 && ((m_op1 & 0xFFFF0000) == 0x00000000))) + _OV = 0; + else + _OV = 1; + + F12WriteSecondOperand(1); + F12END(); +} + + +UINT32 v60_device::opMOVZBH() /* TRUSTED */ +{ + F12DecodeFirstOperand(&v60_device::ReadAM, 0); + m_modwritevalh = (UINT16)m_op1; + F12WriteSecondOperand(1); + F12END(); +} + +UINT32 v60_device::opMOVZBW() /* TRUSTED */ +{ + F12DecodeFirstOperand(&v60_device::ReadAM, 0); + m_modwritevalw = m_op1; + F12WriteSecondOperand(2); + F12END(); +} + +UINT32 v60_device::opMOVZHW() /* TRUSTED */ +{ + F12DecodeFirstOperand(&v60_device::ReadAM, 1); + m_modwritevalw = m_op1; + F12WriteSecondOperand(2); + F12END(); +} + +UINT32 v60_device::opMULB() +{ + UINT8 appb; + UINT32 tmp; + F12DecodeOperands(&v60_device::ReadAM, 0,&v60_device::ReadAMAddress, 0); + + F12LOADOP2BYTE(); + + // @@@ OV not set!! + tmp = (INT8)appb * (INT32)(INT8)m_op1; + appb = tmp; + _Z = (appb == 0); + _S = ((appb & 0x80) != 0); + _OV = ((tmp >> 8) != 0); + + F12STOREOP2BYTE(); + F12END(); +} + +UINT32 v60_device::opMULH() +{ + UINT16 apph; + UINT32 tmp; + F12DecodeOperands(&v60_device::ReadAM, 1,&v60_device::ReadAMAddress, 1); + + F12LOADOP2HALF(); + + // @@@ OV not set!! + tmp = (INT16)apph * (INT32)(INT16)m_op1; + apph = tmp; + _Z = (apph == 0); + _S = ((apph & 0x8000) != 0); + _OV = ((tmp >> 16) != 0); + + F12STOREOP2HALF(); + F12END(); +} + +UINT32 v60_device::opMULW() +{ + UINT32 appw; + UINT64 tmp; + F12DecodeOperands(&v60_device::ReadAM, 2,&v60_device::ReadAMAddress, 2); + + F12LOADOP2WORD(); + + // @@@ OV not set!! + tmp = (INT32)appw * (INT64)(INT32)m_op1; + appw = tmp; + _Z = (appw == 0); + _S = ((appw & 0x80000000) != 0); + _OV = ((tmp >> 32) != 0); + + F12STOREOP2WORD(); + F12END(); +} + +UINT32 v60_device::opMULUB() +{ + UINT8 appb; + UINT32 tmp; + F12DecodeOperands(&v60_device::ReadAM, 0,&v60_device::ReadAMAddress, 0); + + F12LOADOP2BYTE(); + + // @@@ OV not set!! + tmp = appb * (UINT8)m_op1; + appb = tmp; + _Z = (appb == 0); + _S = ((appb & 0x80) != 0); + _OV = ((tmp >> 8) != 0); + + F12STOREOP2BYTE(); + F12END(); +} + +UINT32 v60_device::opMULUH() +{ + UINT16 apph; + UINT32 tmp; + F12DecodeOperands(&v60_device::ReadAM, 1,&v60_device::ReadAMAddress, 1); + + F12LOADOP2HALF(); + + // @@@ OV not set!! + tmp = apph * (UINT16)m_op1; + apph = tmp; + _Z = (apph == 0); + _S = ((apph & 0x8000) != 0); + _OV = ((tmp >> 16) != 0); + + F12STOREOP2HALF(); + F12END(); +} + +UINT32 v60_device::opMULUW() +{ + UINT32 appw; + UINT64 tmp; + F12DecodeOperands(&v60_device::ReadAM, 2,&v60_device::ReadAMAddress, 2); + + F12LOADOP2WORD(); + + // @@@ OV not set!! + tmp = (UINT64)appw * (UINT64)m_op1; + appw = tmp; + _Z = (appw == 0); + _S = ((appw & 0x80000000) != 0); + _OV = ((tmp >> 32) != 0); + + F12STOREOP2WORD(); + F12END(); +} + +UINT32 v60_device::opNEGB() /* TRUSTED (C too!)*/ +{ + F12DecodeFirstOperand(&v60_device::ReadAM, 0); + + m_modwritevalb = 0; + SUBB(m_modwritevalb, (INT8)m_op1); + + F12WriteSecondOperand(0); + F12END(); +} + +UINT32 v60_device::opNEGH() /* TRUSTED (C too!)*/ +{ + F12DecodeFirstOperand(&v60_device::ReadAM, 1); + + m_modwritevalh = 0; + SUBW(m_modwritevalh, (INT16)m_op1); + + F12WriteSecondOperand(1); + F12END(); +} + +UINT32 v60_device::opNEGW() /* TRUSTED (C too!)*/ +{ + F12DecodeFirstOperand(&v60_device::ReadAM, 2); + + m_modwritevalw = 0; + SUBL(m_modwritevalw, (INT32)m_op1); + + F12WriteSecondOperand(2); + F12END(); +} + +UINT32 v60_device::opNOTB() /* TRUSTED */ +{ + F12DecodeFirstOperand(&v60_device::ReadAM, 0); + m_modwritevalb=~m_op1; + + _OV = 0; + _S = ((m_modwritevalb & 0x80) != 0); + _Z = (m_modwritevalb == 0); + + F12WriteSecondOperand(0); + F12END(); +} + +UINT32 v60_device::opNOTH() /* TRUSTED */ +{ + F12DecodeFirstOperand(&v60_device::ReadAM, 1); + m_modwritevalh=~m_op1; + + _OV = 0; + _S = ((m_modwritevalh & 0x8000) != 0); + _Z = (m_modwritevalh == 0); + + F12WriteSecondOperand(1); + F12END(); +} + +UINT32 v60_device::opNOTW() /* TRUSTED */ +{ + F12DecodeFirstOperand(&v60_device::ReadAM, 2); + m_modwritevalw=~m_op1; + + _OV = 0; + _S = ((m_modwritevalw & 0x80000000) != 0); + _Z = (m_modwritevalw == 0); + + F12WriteSecondOperand(2); + F12END(); +} + +UINT32 v60_device::opNOT1() /* TRUSTED */ +{ + UINT32 appw; + F12DecodeOperands(&v60_device::ReadAM, 2,&v60_device::ReadAMAddress, 2); + + F12LOADOP2WORD(); + + _CY = ((appw & (1 << m_op1)) != 0); + _Z = !(_CY); + + if (_CY) + appw &= ~(1 << m_op1); + else + appw |= (1 << m_op1); + + F12STOREOP2WORD(); + F12END(); +} + +UINT32 v60_device::opORB() /* TRUSTED (C too!)*/ +{ + UINT8 appb; + F12DecodeOperands(&v60_device::ReadAM, 0,&v60_device::ReadAMAddress, 0); + + F12LOADOP2BYTE(); + + ORB(appb, (UINT8)m_op1); + + F12STOREOP2BYTE(); + F12END(); +} + +UINT32 v60_device::opORH() /* TRUSTED (C too!)*/ +{ + UINT16 apph; + F12DecodeOperands(&v60_device::ReadAM, 1,&v60_device::ReadAMAddress, 1); + + F12LOADOP2HALF(); + + ORW(apph, (UINT16)m_op1); + + F12STOREOP2HALF(); + F12END(); +} + +UINT32 v60_device::opORW() /* TRUSTED (C too!) */ +{ + UINT32 appw; + F12DecodeOperands(&v60_device::ReadAM, 2,&v60_device::ReadAMAddress, 2); + + F12LOADOP2WORD(); + + ORL(appw, (UINT32)m_op1); + + F12STOREOP2WORD(); + F12END(); +} + +UINT32 v60_device::opOUTB() +{ + F12DecodeOperands(&v60_device::ReadAM, 0,&v60_device::ReadAMAddress, 2); + m_io->write_byte(m_op2,(UINT8)m_op1); + F12END(); +} + +UINT32 v60_device::opOUTH() +{ + F12DecodeOperands(&v60_device::ReadAM, 1,&v60_device::ReadAMAddress, 2); + m_io->write_word_unaligned(m_op2,(UINT16)m_op1); + F12END(); +} + +UINT32 v60_device::opOUTW() +{ + F12DecodeOperands(&v60_device::ReadAM, 2,&v60_device::ReadAMAddress, 2); + m_io->write_dword_unaligned(m_op2, m_op1); + F12END(); +} + +UINT32 v60_device::opREMB() +{ + UINT8 appb; + F12DecodeOperands(&v60_device::ReadAM, 0,&v60_device::ReadAMAddress, 0); + + F12LOADOP2BYTE(); + + _OV = 0; + if (m_op1) + appb= (INT8)appb % (INT8)m_op1; + _Z = (appb == 0); + _S = ((appb & 0x80) != 0); + + F12STOREOP2BYTE(); + F12END(); +} + +UINT32 v60_device::opREMH() +{ + UINT16 apph; + F12DecodeOperands(&v60_device::ReadAM, 1,&v60_device::ReadAMAddress, 1); + + F12LOADOP2HALF(); + + _OV = 0; + if (m_op1) + apph = (INT16)apph % (INT16)m_op1; + _Z = (apph == 0); + _S = ((apph & 0x8000) != 0); + + F12STOREOP2HALF(); + F12END(); +} + +UINT32 v60_device::opREMW() +{ + UINT32 appw; + F12DecodeOperands(&v60_device::ReadAM, 2,&v60_device::ReadAMAddress, 2); + + F12LOADOP2WORD(); + + _OV = 0; + if (m_op1) + appw = (INT32)appw % (INT32)m_op1; + _Z = (appw == 0); + _S = ((appw & 0x80000000) != 0); + + F12STOREOP2WORD(); + F12END(); +} + +UINT32 v60_device::opREMUB() +{ + UINT8 appb; + F12DecodeOperands(&v60_device::ReadAM, 0,&v60_device::ReadAMAddress, 0); + + F12LOADOP2BYTE(); + + _OV = 0; + if (m_op1) + appb %= (UINT8)m_op1; + _Z = (appb == 0); + _S = ((appb & 0x80) != 0); + + F12STOREOP2BYTE(); + F12END(); +} + +UINT32 v60_device::opREMUH() +{ + UINT16 apph; + F12DecodeOperands(&v60_device::ReadAM, 1,&v60_device::ReadAMAddress, 1); + + F12LOADOP2HALF(); + + _OV = 0; + if (m_op1) + apph %= (UINT16)m_op1; + _Z = (apph == 0); + _S = ((apph & 0x8000) != 0); + + F12STOREOP2HALF(); + F12END(); +} + +UINT32 v60_device::opREMUW() +{ + UINT32 appw; + F12DecodeOperands(&v60_device::ReadAM, 2,&v60_device::ReadAMAddress, 2); + + F12LOADOP2WORD(); + + _OV = 0; + if (m_op1) + appw %= m_op1; + _Z = (appw == 0); + _S = ((appw & 0x80000000) != 0); + + F12STOREOP2WORD(); + F12END(); +} + +UINT32 v60_device::opROTB() /* TRUSTED */ +{ + UINT8 appb; + INT8 i, count; + + F12DecodeOperands(&v60_device::ReadAM, 0,&v60_device::ReadAMAddress, 0); + + F12LOADOP2BYTE(); + + count = (INT8)(m_op1 & 0xFF); + if (count > 0) + { + for (i = 0;i < count;i++) + appb = (appb << 1) | ((appb & 0x80) >> 7); + + _CY = (appb & 0x1) != 0; + } + else if (count < 0) + { + count=-count; + for (i = 0;i < count;i++) + appb = (appb >> 1) | ((appb & 0x1) << 7); + + _CY = (appb & 0x80) != 0; + } + else + _CY = 0; + + _OV = 0; + _S = (appb & 0x80) != 0; + _Z = (appb == 0); + + F12STOREOP2BYTE(); + F12END(); +} + +UINT32 v60_device::opROTH() /* TRUSTED */ +{ + UINT16 apph; + INT8 i, count; + + F12DecodeOperands(&v60_device::ReadAM, 0,&v60_device::ReadAMAddress, 1); + + F12LOADOP2HALF(); + + count = (INT8)(m_op1 & 0xFF); + if (count > 0) + { + for (i = 0;i < count;i++) + apph = (apph << 1) | ((apph & 0x8000) >> 15); + + _CY = (apph & 0x1) != 0; + } + else if (count < 0) + { + count=-count; + for (i = 0;i < count;i++) + apph = (apph >> 1) | ((apph & 0x1) << 15); + + _CY = (apph & 0x8000) != 0; + } + else + _CY = 0; + + _OV = 0; + _S = (apph & 0x8000) != 0; + _Z = (apph == 0); + + F12STOREOP2HALF(); + F12END(); +} + +UINT32 v60_device::opROTW() /* TRUSTED */ +{ + UINT32 appw; + INT8 i, count; + + F12DecodeOperands(&v60_device::ReadAM, 0,&v60_device::ReadAMAddress, 2); + + F12LOADOP2WORD(); + + count = (INT8)(m_op1 & 0xFF); + if (count > 0) + { + for (i = 0;i < count;i++) + appw = (appw << 1) | ((appw & 0x80000000) >> 31); + + _CY = (appw & 0x1) != 0; + } + else if (count < 0) + { + count=-count; + for (i = 0;i < count;i++) + appw = (appw >> 1) | ((appw & 0x1) << 31); + + _CY = (appw & 0x80000000) != 0; + } + else + _CY = 0; + + _OV = 0; + _S = (appw & 0x80000000) != 0; + _Z = (appw == 0); + + F12STOREOP2WORD(); + F12END(); +} + +UINT32 v60_device::opROTCB() /* TRUSTED */ +{ + UINT8 appb; + INT8 i, cy, count; + + F12DecodeOperands(&v60_device::ReadAM, 0,&v60_device::ReadAMAddress, 0); + + F12LOADOP2BYTE(); + NORMALIZEFLAGS(); + + count = (INT8)(m_op1 & 0xFF); + if (count > 0) + { + for (i = 0;i < count;i++) + { + cy = _CY; + _CY = (UINT8)((appb & 0x80) >> 7); + appb = (appb << 1) | cy; + } + } + else if (count < 0) + { + count=-count; + for (i = 0;i < count;i++) + { + cy = _CY; + _CY = (appb & 1); + appb = (appb >> 1) | (cy << 7); + } + } + else + _CY = 0; + + _OV = 0; + _S = (appb & 0x80) != 0; + _Z = (appb == 0); + + F12STOREOP2BYTE(); + F12END(); +} + +UINT32 v60_device::opROTCH() /* TRUSTED */ +{ + UINT16 apph; + INT8 i, cy, count; + + F12DecodeOperands(&v60_device::ReadAM, 0,&v60_device::ReadAMAddress, 1); + + F12LOADOP2HALF(); + NORMALIZEFLAGS(); + + count = (INT8)(m_op1 & 0xFF); + if (count > 0) + { + for (i = 0;i < count;i++) + { + cy = _CY; + _CY = (UINT8)((apph & 0x8000) >> 15); + apph = (apph << 1) | cy; + } + } + else if (count < 0) + { + count=-count; + for (i = 0;i < count;i++) + { + cy = _CY; + _CY = (UINT8)(apph & 1); + apph = (apph >> 1) | ((UINT16)cy << 15); + } + } + else + _CY = 0; + + _OV = 0; + _S = (apph & 0x8000) != 0; + _Z = (apph == 0); + + F12STOREOP2HALF(); + F12END(); +} + +UINT32 v60_device::opROTCW() /* TRUSTED */ +{ + UINT32 appw; + INT8 i, cy, count; + + F12DecodeOperands(&v60_device::ReadAM, 0,&v60_device::ReadAMAddress, 2); + + F12LOADOP2WORD(); + NORMALIZEFLAGS(); + + count = (INT8)(m_op1 & 0xFF); + if (count > 0) + { + for (i = 0;i < count;i++) + { + cy = _CY; + _CY = (UINT8)((appw & 0x80000000) >> 31); + appw = (appw << 1) | cy; + } + } + else if (count < 0) + { + count=-count; + for (i = 0;i < count;i++) + { + cy = _CY; + _CY = (UINT8)(appw & 1); + appw = (appw >> 1) | ((UINT32)cy << 31); + } + } + else + _CY = 0; + + _OV = 0; + _S = (appw & 0x80000000) != 0; + _Z = (appw == 0); + + F12STOREOP2WORD(); + F12END(); +} + +UINT32 v60_device::opRVBIT() +{ + F12DecodeFirstOperand(&v60_device::ReadAM, 0); + + m_modwritevalb =(UINT8) + (((m_op1 & (1 << 0)) << 7) | + ((m_op1 & (1 << 1)) << 5) | + ((m_op1 & (1 << 2)) << 3) | + ((m_op1 & (1 << 3)) << 1) | + ((m_op1 & (1 << 4)) >> 1) | + ((m_op1 & (1 << 5)) >> 3) | + ((m_op1 & (1 << 6)) >> 5) | + ((m_op1 & (1 << 7)) >> 7)); + + F12WriteSecondOperand(0); + F12END(); +} + +UINT32 v60_device::opRVBYT() /* TRUSTED */ +{ + F12DecodeFirstOperand(&v60_device::ReadAM, 2); + + m_modwritevalw = ((m_op1 & 0x000000FF) << 24) | + ((m_op1 & 0x0000FF00) << 8) | + ((m_op1 & 0x00FF0000) >> 8) | + ((m_op1 & 0xFF000000) >> 24); + + F12WriteSecondOperand(2); + F12END(); +} + +UINT32 v60_device::opSET1() /* TRUSTED */ +{ + UINT32 appw; + F12DecodeOperands(&v60_device::ReadAM, 2,&v60_device::ReadAMAddress, 2); + + F12LOADOP2WORD(); + + _CY = ((appw & (1 << m_op1)) != 0); + _Z = !(_CY); + + appw |= (1 << m_op1); + + F12STOREOP2WORD(); + F12END(); +} + + +UINT32 v60_device::opSETF() +{ + F12DecodeFirstOperand(&v60_device::ReadAM, 0); + + // Normalize the flags + NORMALIZEFLAGS(); + + switch (m_op1 & 0xF) + { + case 0: + if (!_OV) m_modwritevalb = 0; + else m_modwritevalb = 1; + break; + case 1: + if (_OV) m_modwritevalb = 0; + else m_modwritevalb = 1; + break; + case 2: + if (!_CY) m_modwritevalb = 0; + else m_modwritevalb = 1; + break; + case 3: + if (_CY) m_modwritevalb = 0; + else m_modwritevalb = 1; + break; + case 4: + if (!_Z) m_modwritevalb = 0; + else m_modwritevalb = 1; + break; + case 5: + if (_Z) m_modwritevalb = 0; + else m_modwritevalb = 1; + break; + case 6: + if (!(_CY | _Z)) m_modwritevalb = 0; + else m_modwritevalb = 1; + break; + case 7: + if ((_CY | _Z)) m_modwritevalb = 0; + else m_modwritevalb = 1; + break; + case 8: + if (!_S) m_modwritevalb = 0; + else m_modwritevalb = 1; + break; + case 9: + if (_S) m_modwritevalb = 0; + else m_modwritevalb = 1; + break; + case 10: + m_modwritevalb = 1; + break; + case 11: + m_modwritevalb = 0; + break; + case 12: + if (!(_S^_OV)) m_modwritevalb = 0; + else m_modwritevalb = 1; + break; + case 13: + if ((_S^_OV)) m_modwritevalb = 0; + else m_modwritevalb = 1; + break; + case 14: + if (!((_S^_OV)|_Z)) m_modwritevalb = 0; + else m_modwritevalb = 1; + break; + case 15: + if (((_S^_OV)|_Z)) m_modwritevalb = 0; + else m_modwritevalb = 1; + break; + } + + F12WriteSecondOperand(0); + + F12END(); +} + +/* +#define SHIFTLEFT_OY(val, count, bitsize) \ +{\ + UINT32 tmp = ((val) >> (bitsize - 1)) & 1; \ + tmp <<= count; \ + tmp -= 1; \ + tmp <<= (bitsize - (count)); \ + _OV = (((val) & tmp) != tmp); \ + _CY = (((val) & (1 << (count - 1))) != 0); \ +} +*/ + +// During the shift, the overflow is set if the sign bit changes at any point during the shift +#define SHIFTLEFT_OV(val, count, bitsize) \ +{\ + UINT32 tmp; \ + if (count == 32) \ + tmp = 0xFFFFFFFF; \ + else \ + tmp = ((1 << (count)) - 1); \ + tmp <<= (bitsize - (count)); \ + if (((val) >> (bitsize - 1)) & 1) \ + _OV = (((val) & tmp) != tmp); \ + else \ + _OV = (((val) & tmp) != 0); \ +} + +#define SHIFTLEFT_CY(val, count, bitsize) \ + _CY = (UINT8)(((val) >> (bitsize - count)) & 1); + + + +#define SHIFTARITHMETICRIGHT_OV(val, count, bitsize) \ + _OV = 0; + +#define SHIFTARITHMETICRIGHT_CY(val, count, bitsize) \ + _CY = (UINT8)(((val) >> (count - 1)) & 1); + + + +UINT32 v60_device::opSHAB() +{ + UINT8 appb; + INT8 count; + + F12DecodeOperands(&v60_device::ReadAM, 0,&v60_device::ReadAMAddress, 0); + + F12LOADOP2BYTE(); + + count = (INT8)(m_op1 & 0xFF); + + // Special case: destination unchanged, flags set + if (count == 0) + { + _CY = _OV = 0; + SetSZPF_Byte(appb); + } + else if (count > 0) + { + SHIFTLEFT_OV(appb, count, 8); + + // @@@ Undefined what happens to CY when count >= bitsize + SHIFTLEFT_CY(appb, count, 8); + + // do the actual shift... + if (count >= 8) + appb = 0; + else + appb <<= count; + + // and set zero and sign + SetSZPF_Byte(appb); + } + else + { + count = -count; + + SHIFTARITHMETICRIGHT_OV(appb, count, 8); + SHIFTARITHMETICRIGHT_CY(appb, count, 8); + + if (count >= 8) + appb = (appb & 0x80) ? 0xFF : 0; + else + appb = ((INT8)appb) >> count; + + SetSZPF_Byte(appb); + } + +// osd_printf_debug("SHAB: %x _CY: %d _Z: %d _OV: %d _S: %d\n", appb, _CY, _Z, _OV, _S); + + F12STOREOP2BYTE(); + F12END(); +} + +UINT32 v60_device::opSHAH() +{ + UINT16 apph; + INT8 count; + + F12DecodeOperands(&v60_device::ReadAM, 0,&v60_device::ReadAMAddress, 1); + + F12LOADOP2HALF(); + + count = (INT8)(m_op1 & 0xFF); + + // Special case: destination unchanged, flags set + if (count == 0) + { + _CY = _OV = 0; + SetSZPF_Word(apph); + } + else if (count > 0) + { + SHIFTLEFT_OV(apph, count, 16); + + // @@@ Undefined what happens to CY when count >= bitsize + SHIFTLEFT_CY(apph, count, 16); + + // do the actual shift... + if (count >= 16) + apph = 0; + else + apph <<= count; + + // and set zero and sign + SetSZPF_Word(apph); + } + else + { + count = -count; + + SHIFTARITHMETICRIGHT_OV(apph, count, 16); + SHIFTARITHMETICRIGHT_CY(apph, count, 16); + + if (count >= 16) + apph = (apph & 0x8000) ? 0xFFFF : 0; + else + apph = ((INT16)apph) >> count; + + SetSZPF_Word(apph); + } + +// osd_printf_debug("SHAH: %x >> %d = %x _CY: %d _Z: %d _OV: %d _S: %d\n", oldval, count, apph, _CY, _Z, _OV, _S); + + F12STOREOP2HALF(); + F12END(); +} + +UINT32 v60_device::opSHAW() +{ + UINT32 appw; + INT8 count; + + F12DecodeOperands(&v60_device::ReadAM, 0,&v60_device::ReadAMAddress, 2); + + F12LOADOP2WORD(); + + count = (INT8)(m_op1 & 0xFF); + + // Special case: destination unchanged, flags set + if (count == 0) + { + _CY = _OV = 0; + SetSZPF_Long(appw); + } + else if (count > 0) + { + SHIFTLEFT_OV(appw, count, 32); + + // @@@ Undefined what happens to CY when count >= bitsize + SHIFTLEFT_CY(appw, count, 32); + + // do the actual shift... + if (count >= 32) + appw = 0; + else + appw <<= count; + + // and set zero and sign + SetSZPF_Long(appw); + } + else + { + count = -count; + + SHIFTARITHMETICRIGHT_OV(appw, count, 32); + SHIFTARITHMETICRIGHT_CY(appw, count, 32); + + if (count >= 32) + appw = (appw & 0x80000000) ? 0xFFFFFFFF : 0; + else + appw = ((INT32)appw) >> count; + + SetSZPF_Long(appw); + } + +// osd_printf_debug("SHAW: %x >> %d = %x _CY: %d _Z: %d _OV: %d _S: %d\n", oldval, count, appw, _CY, _Z, _OV, _S); + + F12STOREOP2WORD(); + F12END(); +} + + +UINT32 v60_device::opSHLB() /* TRUSTED */ +{ + UINT8 appb; + INT8 count; + UINT32 tmp; + + F12DecodeOperands(&v60_device::ReadAM, 0,&v60_device::ReadAMAddress, 0); + + F12LOADOP2BYTE(); + + count = (INT8)(m_op1 & 0xFF); + if (count > 0) + { + // left shift flags: + // carry gets the last bit shifted out, + // overflow is always CLEARed + + _OV = 0; // default to no overflow + + // now handle carry + tmp = appb & 0xff; + tmp <<= count; + SetCFB(tmp); // set carry properly + + // do the actual shift... + appb <<= count; + + // and set zero and sign + SetSZPF_Byte(appb); + } + else + { + if (count == 0) + { + // special case: clear carry and overflow, do nothing else + _CY = _OV = 0; + SetSZPF_Byte(appb); // doc. is unclear if this is true... + } + else + { + // right shift flags: + // carry = last bit shifted out + // overflow always cleared + tmp = appb & 0xff; + tmp >>= ((-count) - 1); + _CY = (UINT8)(tmp & 0x1); + _OV = 0; + + appb >>= -count; + SetSZPF_Byte(appb); + } + } + +// osd_printf_debug("SHLB: %x _CY: %d _Z: %d _OV: %d _S: %d\n", appb, _CY, _Z, _OV, _S); + + F12STOREOP2BYTE(); + F12END(); +} + +UINT32 v60_device::opSHLH() /* TRUSTED */ +{ + UINT16 apph; + INT8 count; + UINT32 tmp; + + F12DecodeOperands(&v60_device::ReadAM, 0,&v60_device::ReadAMAddress, 1); + + F12LOADOP2HALF(); + + count = (INT8)(m_op1 & 0xFF); +// osd_printf_debug("apph: %x count: %d ", apph, count); + if (count > 0) + { + // left shift flags: + // carry gets the last bit shifted out, + // overflow is always CLEARed + + _OV = 0; + + // now handle carry + tmp = apph & 0xffff; + tmp <<= count; + SetCFW(tmp); // set carry properly + + // do the actual shift... + apph <<= count; + + // and set zero and sign + SetSZPF_Word(apph); + } + else + { + if (count == 0) + { + // special case: clear carry and overflow, do nothing else + _CY = _OV = 0; + SetSZPF_Word(apph); // doc. is unclear if this is true... + } + else + { + // right shift flags: + // carry = last bit shifted out + // overflow always cleared + tmp = apph & 0xffff; + tmp >>= ((-count) - 1); + _CY = (UINT8)(tmp & 0x1); + _OV = 0; + + apph >>= -count; + SetSZPF_Word(apph); + } + } + +// osd_printf_debug("SHLH: %x _CY: %d _Z: %d _OV: %d _S: %d\n", apph, _CY, _Z, _OV, _S); + + F12STOREOP2HALF(); + F12END(); +} + +UINT32 v60_device::opSHLW() /* TRUSTED */ +{ + UINT32 appw; + INT8 count; + UINT64 tmp; + + F12DecodeOperands(&v60_device::ReadAM, 0,&v60_device::ReadAMAddress, 2); + + F12LOADOP2WORD(); + + count = (INT8)(m_op1 & 0xFF); + if (count > 0) + { + // left shift flags: + // carry gets the last bit shifted out, + // overflow is always CLEARed + + _OV = 0; + + // now handle carry + tmp = appw & 0xffffffff; + tmp <<= count; + SetCFL(tmp); // set carry properly + + // do the actual shift... + appw <<= count; + + // and set zero and sign + SetSZPF_Long(appw); + } + else + { + if (count == 0) + { + // special case: clear carry and overflow, do nothing else + _CY = _OV = 0; + SetSZPF_Long(appw); // doc. is unclear if this is true... + } + else + { + // right shift flags: + // carry = last bit shifted out + // overflow always cleared + tmp = (UINT64)(appw & 0xffffffff); + tmp >>= ((-count) - 1); + _CY = (UINT8)(tmp & 0x1); + _OV = 0; + + appw >>= -count; + SetSZPF_Long(appw); + } + } + +// osd_printf_debug("SHLW: %x _CY: %d _Z: %d _OV: %d _S: %d\n", appw, _CY, _Z, _OV, _S); + + F12STOREOP2WORD(); + F12END(); +} + +UINT32 v60_device::opSTPR() +{ + F12DecodeFirstOperand(&v60_device::ReadAM, 2); + if (m_op1 <= 28) + m_modwritevalw = m_reg[m_op1 + 36]; + else + { + fatalerror("Invalid operand on STPR PC=%x\n", PC); + } + F12WriteSecondOperand(2); + F12END(); +} + + +UINT32 v60_device::opSUBB() /* TRUSTED (C too!) */ +{ + UINT8 appb; + F12DecodeOperands(&v60_device::ReadAM, 0,&v60_device::ReadAMAddress, 0); + + F12LOADOP2BYTE(); + + SUBB(appb, (UINT8)m_op1); + + F12STOREOP2BYTE(); + F12END(); +} + +UINT32 v60_device::opSUBH() /* TRUSTED (C too!) */ +{ + UINT16 apph; + F12DecodeOperands(&v60_device::ReadAM, 1,&v60_device::ReadAMAddress, 1); + + F12LOADOP2HALF(); + + SUBW(apph, (UINT16)m_op1); + + F12STOREOP2HALF(); + F12END(); +} + +UINT32 v60_device::opSUBW() /* TRUSTED (C too!) */ +{ + UINT32 appw; + F12DecodeOperands(&v60_device::ReadAM, 2,&v60_device::ReadAMAddress, 2); + + F12LOADOP2WORD(); + + SUBL(appw, (UINT32)m_op1); + + F12STOREOP2WORD(); + F12END(); +} + + +UINT32 v60_device::opSUBCB() +{ + UINT8 appb; + UINT8 src; + F12DecodeOperands(&v60_device::ReadAM, 0,&v60_device::ReadAMAddress, 0); + + F12LOADOP2BYTE(); + + src = (UINT8)m_op1 + (_CY?1:0); + SUBB(appb, src); + + F12STOREOP2BYTE(); + F12END(); +} + +UINT32 v60_device::opSUBCH() +{ + UINT16 apph; + UINT16 src; + + F12DecodeOperands(&v60_device::ReadAM, 1,&v60_device::ReadAMAddress, 1); + + F12LOADOP2HALF(); + + src = (UINT16)m_op1 + (_CY?1:0); + SUBW(apph, src); + + F12STOREOP2HALF(); + F12END(); +} + +UINT32 v60_device::opSUBCW() +{ + UINT32 appw; + UINT32 src; + + F12DecodeOperands(&v60_device::ReadAM, 2,&v60_device::ReadAMAddress, 2); + + F12LOADOP2WORD(); + + src = (UINT32)m_op1 + (_CY?1:0); + SUBL(appw, src); + + F12STOREOP2WORD(); + F12END(); +} + +UINT32 v60_device::opTEST1() +{ + F12DecodeOperands(&v60_device::ReadAM, 2,&v60_device::ReadAM, 2); + + _CY = ((m_op2 & (1 << m_op1)) != 0); + _Z = !(_CY); + + F12END(); +} + +UINT32 v60_device::opUPDPSWW() +{ + F12DecodeOperands(&v60_device::ReadAM, 2,&v60_device::ReadAM, 2); + + /* can only modify condition code and control fields */ + m_op2 &= 0xFFFFFF; + m_op1 &= 0xFFFFFF; + v60WritePSW((v60ReadPSW() & (~m_op2)) | (m_op1 & m_op2)); + + F12END(); +} + +UINT32 v60_device::opUPDPSWH() +{ + F12DecodeOperands(&v60_device::ReadAM, 2,&v60_device::ReadAM, 2); + + /* can only modify condition code fields */ + m_op2 &= 0xFFFF; + m_op1 &= 0xFFFF; + v60WritePSW((v60ReadPSW() & (~m_op2)) | (m_op1 & m_op2)); + + F12END(); +} + +UINT32 v60_device::opXCHB() /* TRUSTED */ +{ + UINT8 appb, temp; + + F12DecodeOperands(&v60_device::ReadAMAddress, 0,&v60_device::ReadAMAddress, 0); + + F12LOADOP1BYTE(); + temp = appb; + F12LOADOP2BYTE(); + F12STOREOP1BYTE(); + appb = temp; + F12STOREOP2BYTE(); + + F12END() +} + +UINT32 v60_device::opXCHH() /* TRUSTED */ +{ + UINT16 apph, temp; + + F12DecodeOperands(&v60_device::ReadAMAddress, 1,&v60_device::ReadAMAddress, 1); + + F12LOADOP1HALF(); + temp = apph; + F12LOADOP2HALF(); + F12STOREOP1HALF(); + apph = temp; + F12STOREOP2HALF(); + + F12END() +} + +UINT32 v60_device::opXCHW() /* TRUSTED */ +{ + UINT32 appw, temp; + + F12DecodeOperands(&v60_device::ReadAMAddress, 2,&v60_device::ReadAMAddress, 2); + + F12LOADOP1WORD(); + temp = appw; + F12LOADOP2WORD(); + F12STOREOP1WORD(); + appw = temp; + F12STOREOP2WORD(); + + F12END() +} + +UINT32 v60_device::opXORB() /* TRUSTED (C too!) */ +{ + UINT8 appb; + F12DecodeOperands(&v60_device::ReadAM, 0,&v60_device::ReadAMAddress, 0); + + F12LOADOP2BYTE(); + + XORB(appb, (UINT8)m_op1); + + F12STOREOP2BYTE(); + F12END(); +} + +UINT32 v60_device::opXORH() /* TRUSTED (C too!) */ +{ + UINT16 apph; + F12DecodeOperands(&v60_device::ReadAM, 1,&v60_device::ReadAMAddress, 1); + + F12LOADOP2HALF(); + + XORW(apph, (UINT16)m_op1); + + F12STOREOP2HALF(); + F12END(); +} + +UINT32 v60_device::opXORW() /* TRUSTED (C too!) */ +{ + UINT32 appw; + F12DecodeOperands(&v60_device::ReadAM, 2,&v60_device::ReadAMAddress, 2); + + F12LOADOP2WORD(); + + XORL(appw, (UINT32)m_op1); + + F12STOREOP2WORD(); + F12END(); +} + +UINT32 v60_device::opMULX() +{ + INT32 a, b; + INT64 res; + + F12DecodeOperands(&v60_device::ReadAM, 2,&v60_device::ReadAMAddress, 3); + + if (m_flag2) + { + a = m_reg[m_op2 & 0x1F]; + } + else + { + a = m_program->read_dword_unaligned(m_op2); + } + + res = (INT64)a * (INT64)(INT32)m_op1; + + b = (INT32)((res >> 32)&0xffffffff); + a = (INT32)(res & 0xffffffff); + + _S = ((b & 0x80000000) != 0); + _Z = (a == 0 && b == 0); + + if (m_flag2) + { + m_reg[m_op2 & 0x1F] = a; + m_reg[(m_op2 & 0x1F) + 1] = b; + } + else + { + m_program->write_dword_unaligned(m_op2, a); + m_program->write_dword_unaligned(m_op2 + 4, b); + } + + F12END(); +} + +UINT32 v60_device::opMULUX() +{ + INT32 a, b; + UINT64 res; + + F12DecodeOperands(&v60_device::ReadAM, 2,&v60_device::ReadAMAddress, 3); + + if (m_flag2) + { + a = m_reg[m_op2 & 0x1F]; + } + else + { + a = m_program->read_dword_unaligned(m_op2); + } + + res = (UINT64)a * (UINT64)m_op1; + b = (INT32)((res >> 32)&0xffffffff); + a = (INT32)(res & 0xffffffff); + + _S = ((b & 0x80000000) != 0); + _Z = (a == 0 && b == 0); + + if (m_flag2) + { + m_reg[m_op2 & 0x1F] = a; + m_reg[(m_op2 & 0x1F) + 1] = b; + } + else + { + m_program->write_dword_unaligned(m_op2, a); + m_program->write_dword_unaligned(m_op2 + 4, b); + } + + F12END(); +} diff --git a/src/devices/cpu/v60/op2.inc b/src/devices/cpu/v60/op2.inc new file mode 100644 index 00000000000..98a8612f345 --- /dev/null +++ b/src/devices/cpu/v60/op2.inc @@ -0,0 +1,354 @@ +// license:BSD-3-Clause +// copyright-holders:Farfetch'd, R. Belmont + +#define F2END() \ + return 2 + m_amlength1 + m_amlength2; + +#define F2LOADOPFLOAT(num) \ + if (m_flag##num) \ + appf = u2f(m_reg[m_op##num]); \ + else \ + appf = u2f(m_program->read_dword_unaligned(m_op##num)); + +#define F2STOREOPFLOAT(num) \ + if (m_flag##num) \ + m_reg[m_op##num] = f2u(appf); \ + else \ + m_program->write_dword_unaligned(m_op##num, f2u(appf)); + +void v60_device::F2DecodeFirstOperand(am_func DecodeOp1, UINT8 dim1) +{ + m_moddim = dim1; + m_modm = m_instflags & 0x40; + m_modadd = PC + 2; + m_amlength1 = (this->*DecodeOp1)(); + m_op1 = m_amout; + m_flag1 = m_amflag; +} + +void v60_device::F2DecodeSecondOperand(am_func DecodeOp2, UINT8 dim2) +{ + m_moddim = dim2; + m_modm = m_instflags & 0x20; + m_modadd = PC + 2 + m_amlength1; + m_amlength2 = (this->*DecodeOp2)(); + m_op2 = m_amout; + m_flag2 = m_amflag; +} + +void v60_device::F2WriteSecondOperand(UINT8 dim2) +{ + m_moddim = dim2; + m_modm = m_instflags & 0x20; + m_modadd = PC + 2 + m_amlength1; + m_amlength2 = WriteAM(); +} + +UINT32 v60_device::opCVTWS() +{ + float val; + + F2DecodeFirstOperand(&v60_device::ReadAM, 2); + + // Convert to float + val = (float)(INT32)m_op1; + m_modwritevalw = f2u(val); + + _OV = 0; + _CY = (val < 0.0f); + _S = ((m_modwritevalw & 0x80000000) != 0); + _Z = (val == 0.0f); + + F2WriteSecondOperand(2); + F2END(); +} + +UINT32 v60_device::opCVTSW() +{ + float val; + + F2DecodeFirstOperand(&v60_device::ReadAM, 2); + + // Convert to UINT32 + val = u2f(m_op1); + m_modwritevalw = (UINT32)val; + + _OV = 0; + _CY =(val < 0.0f); + _S = ((m_modwritevalw & 0x80000000) != 0); + _Z = (val == 0.0f); + + F2WriteSecondOperand(2); + F2END(); +} + +UINT32 v60_device::opMOVFS() +{ + F2DecodeFirstOperand(&v60_device::ReadAM, 2); + m_modwritevalw = m_op1; + F2WriteSecondOperand(2); + F2END(); +} + +UINT32 v60_device::opNEGFS() +{ + float appf; + + F2DecodeFirstOperand(&v60_device::ReadAM, 2); + F2DecodeSecondOperand(&v60_device::ReadAMAddress, 2); + + appf = -u2f(m_op1); + + _OV = 0; + _CY = (appf < 0.0f); + _S = ((f2u(appf) & 0x80000000) != 0); + _Z = (appf == 0.0f); + + F2STOREOPFLOAT(2); + F2END() +} + +UINT32 v60_device::opABSFS() +{ + float appf; + + F2DecodeFirstOperand(&v60_device::ReadAM, 2); + F2DecodeSecondOperand(&v60_device::ReadAMAddress, 2); + + appf = u2f(m_op1); + + if(appf < 0) + appf = -appf; + + _OV = 0; + _CY = 0; + _S = ((f2u(appf) & 0x80000000) != 0); + _Z = (appf == 0.0f); + + F2STOREOPFLOAT(2); + F2END() +} + +UINT32 v60_device::opADDFS() +{ + UINT32 appw; + float appf; + + F2DecodeFirstOperand(&v60_device::ReadAM, 2); + F2DecodeSecondOperand(&v60_device::ReadAMAddress, 2); + + F2LOADOPFLOAT(2); + + appf += u2f(m_op1); + + appw = f2u(appf); + _OV = _CY = 0; + _S = ((appw & 0x80000000) != 0); + _Z = (appw == 0); + + F2STOREOPFLOAT(2); + F2END() +} + +UINT32 v60_device::opSUBFS() +{ + UINT32 appw; + float appf; + + F2DecodeFirstOperand(&v60_device::ReadAM, 2); + F2DecodeSecondOperand(&v60_device::ReadAMAddress, 2); + + F2LOADOPFLOAT(2); + + appf -= u2f(m_op1); + + appw = f2u(appf); + _OV = _CY = 0; + _S = ((appw & 0x80000000) != 0); + _Z = (appw == 0); + + F2STOREOPFLOAT(2); + F2END() +} + +UINT32 v60_device::opMULFS() +{ + UINT32 appw; + float appf; + + F2DecodeFirstOperand(&v60_device::ReadAM, 2); + F2DecodeSecondOperand(&v60_device::ReadAMAddress, 2); + + F2LOADOPFLOAT(2); + + appf *= u2f(m_op1); + + appw = f2u(appf); + _OV = _CY = 0; + _S = ((appw & 0x80000000) != 0); + _Z = (appw == 0); + + F2STOREOPFLOAT(2); + F2END() +} + +UINT32 v60_device::opDIVFS() +{ + UINT32 appw; + float appf; + + F2DecodeFirstOperand(&v60_device::ReadAM, 2); + F2DecodeSecondOperand(&v60_device::ReadAMAddress, 2); + + F2LOADOPFLOAT(2); + + appf /= u2f(m_op1); + + appw = f2u(appf); + _OV = _CY = 0; + _S = ((appw & 0x80000000) != 0); + _Z = (appw == 0); + + F2STOREOPFLOAT(2); + F2END() +} + +UINT32 v60_device::opSCLFS() +{ + UINT32 appw; + float appf; + + F2DecodeFirstOperand(&v60_device::ReadAM, 1); + F2DecodeSecondOperand(&v60_device::ReadAMAddress, 2); + + F2LOADOPFLOAT(2); + + if ((INT16)m_op1 < 0) + appf /= 1 << -(INT16)m_op1; + else + appf *= 1 << m_op1; + + appw = f2u(appf); + _OV = _CY = 0; + _S = ((appw & 0x80000000) != 0); + _Z = (appw == 0); + + F2STOREOPFLOAT(2); + F2END() +} + +UINT32 v60_device::opCMPF() +{ + float appf; + + F2DecodeFirstOperand(&v60_device::ReadAM, 2); + F2DecodeSecondOperand(&v60_device::ReadAM, 2); + + appf = u2f(m_op2) - u2f(m_op1); + + _Z = (appf == 0); + _S = (appf < 0); + _OV = 0; + _CY = 0; + + F2END(); +} + +UINT32 v60_device::op5FUNHANDLED() +{ + fatalerror("Unhandled 5F opcode at %08x\n", PC); + return 0; /* never reached, fatalerror won't return */ +} + +UINT32 v60_device::op5CUNHANDLED() +{ + fatalerror("Unhandled 5C opcode at %08x\n", PC); + return 0; /* never reached, fatalerror won't return */ +} + +const v60_device::am_func v60_device::s_Op5FTable[32] = +{ + &v60_device::opCVTWS, + &v60_device::opCVTSW, + &v60_device::op5FUNHANDLED, + &v60_device::op5FUNHANDLED, + &v60_device::op5FUNHANDLED, + &v60_device::op5FUNHANDLED, + &v60_device::op5FUNHANDLED, + &v60_device::op5FUNHANDLED, + &v60_device::op5FUNHANDLED, + &v60_device::op5FUNHANDLED, + &v60_device::op5FUNHANDLED, + &v60_device::op5FUNHANDLED, + &v60_device::op5FUNHANDLED, + &v60_device::op5FUNHANDLED, + &v60_device::op5FUNHANDLED, + &v60_device::op5FUNHANDLED, + &v60_device::op5FUNHANDLED, + &v60_device::op5FUNHANDLED, + &v60_device::op5FUNHANDLED, + &v60_device::op5FUNHANDLED, + &v60_device::op5FUNHANDLED, + &v60_device::op5FUNHANDLED, + &v60_device::op5FUNHANDLED, + &v60_device::op5FUNHANDLED, + &v60_device::op5FUNHANDLED, + &v60_device::op5FUNHANDLED, + &v60_device::op5FUNHANDLED, + &v60_device::op5FUNHANDLED, + &v60_device::op5FUNHANDLED, + &v60_device::op5FUNHANDLED, + &v60_device::op5FUNHANDLED, + &v60_device::op5FUNHANDLED +}; + +const v60_device::am_func v60_device::s_Op5CTable[32] = +{ + &v60_device::opCMPF, + &v60_device::op5CUNHANDLED, + &v60_device::op5CUNHANDLED, + &v60_device::op5CUNHANDLED, + &v60_device::op5CUNHANDLED, + &v60_device::op5CUNHANDLED, + &v60_device::op5CUNHANDLED, + &v60_device::op5CUNHANDLED, + &v60_device::opMOVFS, + &v60_device::opNEGFS, + &v60_device::opABSFS, + &v60_device::op5CUNHANDLED, + &v60_device::op5CUNHANDLED, + &v60_device::op5CUNHANDLED, + &v60_device::op5CUNHANDLED, + &v60_device::op5CUNHANDLED, + + &v60_device::opSCLFS, + &v60_device::op5CUNHANDLED, + &v60_device::op5CUNHANDLED, + &v60_device::op5CUNHANDLED, + &v60_device::op5CUNHANDLED, + &v60_device::op5CUNHANDLED, + &v60_device::op5CUNHANDLED, + &v60_device::op5CUNHANDLED, + &v60_device::opADDFS, + &v60_device::opSUBFS, + &v60_device::opMULFS, + &v60_device::opDIVFS, + &v60_device::op5CUNHANDLED, + &v60_device::op5CUNHANDLED, + &v60_device::op5CUNHANDLED, + &v60_device::op5CUNHANDLED +}; + + +UINT32 v60_device::op5F() +{ + m_instflags = OpRead8(PC + 1); + return (this->*s_Op5FTable[m_instflags & 0x1F])(); +} + + +UINT32 v60_device::op5C() +{ + m_instflags = OpRead8(PC + 1); + return (this->*s_Op5CTable[m_instflags & 0x1F])(); +} diff --git a/src/devices/cpu/v60/op3.inc b/src/devices/cpu/v60/op3.inc new file mode 100644 index 00000000000..0f014d40909 --- /dev/null +++ b/src/devices/cpu/v60/op3.inc @@ -0,0 +1,641 @@ +// license:BSD-3-Clause +// copyright-holders:Farfetch'd, R. Belmont +UINT32 v60_device::opINCB() /* TRUSTED */ +{ + UINT8 appb; + m_modadd = PC + 1; + m_moddim = 0; + + m_amlength1 = ReadAMAddress(); + + if (m_amflag) + appb = (UINT8)m_reg[m_amout]; + else + appb = m_program->read_byte(m_amout); + + ADDB(appb, 1); + + if (m_amflag) + SETREG8(m_reg[m_amout], appb); + else + m_program->write_byte(m_amout, appb); + + return m_amlength1 + 1; +} + +UINT32 v60_device::opINCH() /* TRUSTED */ +{ + UINT16 apph; + m_modadd = PC + 1; + m_moddim = 1; + + m_amlength1 = ReadAMAddress(); + + if (m_amflag) + apph = (UINT16)m_reg[m_amout]; + else + apph = m_program->read_word_unaligned(m_amout); + + ADDW(apph, 1); + + if (m_amflag) + SETREG16(m_reg[m_amout], apph); + else + m_program->write_word_unaligned(m_amout, apph); + + return m_amlength1 + 1; +} + +UINT32 v60_device::opINCW() /* TRUSTED */ +{ + UINT32 appw; + m_modadd = PC + 1; + m_moddim = 2; + + m_amlength1 = ReadAMAddress(); + + if (m_amflag) + appw = m_reg[m_amout]; + else + appw = m_program->read_dword_unaligned(m_amout); + + ADDL(appw, 1); + + if (m_amflag) + m_reg[m_amout] = appw; + else + m_program->write_dword_unaligned(m_amout, appw); + + return m_amlength1 + 1; +} + +UINT32 v60_device::opDECB() /* TRUSTED */ +{ + UINT8 appb; + m_modadd = PC + 1; + m_moddim = 0; + + m_amlength1 = ReadAMAddress(); + + if (m_amflag) + appb = (UINT8)m_reg[m_amout]; + else + appb = m_program->read_byte(m_amout); + + SUBB(appb, 1); + + if (m_amflag) + SETREG8(m_reg[m_amout], appb); + else + m_program->write_byte(m_amout, appb); + + return m_amlength1 + 1; +} + +UINT32 v60_device::opDECH() /* TRUSTED */ +{ + UINT16 apph; + m_modadd = PC + 1; + m_moddim = 1; + + m_amlength1 = ReadAMAddress(); + + if (m_amflag) + apph = (UINT16)m_reg[m_amout]; + else + apph = m_program->read_word_unaligned(m_amout); + + SUBW(apph, 1); + + if (m_amflag) + SETREG16(m_reg[m_amout], apph); + else + m_program->write_word_unaligned(m_amout, apph); + + return m_amlength1 + 1; +} + +UINT32 v60_device::opDECW() /* TRUSTED */ +{ + UINT32 appw; + m_modadd = PC + 1; + m_moddim = 2; + + m_amlength1 = ReadAMAddress(); + + if (m_amflag) + appw = m_reg[m_amout]; + else + appw = m_program->read_dword_unaligned(m_amout); + + SUBL(appw, 1); + + if (m_amflag) + m_reg[m_amout] = appw; + else + m_program->write_dword_unaligned(m_amout, appw); + + return m_amlength1 + 1; +} + +UINT32 v60_device::opJMP() /* TRUSTED */ +{ + m_modadd = PC + 1; + m_moddim = 0; + + // Read the address of the operand + ReadAMAddress(); + + // It cannot be a register!! + assert(m_amflag == 0); + + // Jump there + PC = m_amout; + + return 0; +} + +UINT32 v60_device::opJSR() /* TRUSTED */ +{ + m_modadd = PC + 1; + m_moddim = 0; + + // Read the address of the operand + m_amlength1 = ReadAMAddress(); + + // It cannot be a register!! + assert(m_amflag == 0); + + // Save NextPC into the stack + SP -= 4; + m_program->write_dword_unaligned(SP, PC + m_amlength1 + 1); + + // Jump there + PC = m_amout; + + return 0; +} + +UINT32 v60_device::opPREPARE() /* somewhat TRUSTED */ +{ + m_modadd = PC + 1; + m_moddim = 2; + + // Read the operand + m_amlength1 = ReadAM(); + + // step 1: save frame pointer on the stack + SP -= 4; + m_program->write_dword_unaligned(SP, FP); + + // step 2: FP = new SP + FP = SP; + + // step 3: SP -= operand + SP -= m_amout; + + return m_amlength1 + 1; +} + +UINT32 v60_device::opRET() /* TRUSTED */ +{ + m_modadd = PC + 1; + m_moddim = 2; + + // Read the operand + ReadAM(); + + // Read return address from stack + PC = m_program->read_dword_unaligned(SP); + SP +=4; + + // Restore AP from stack + AP = m_program->read_dword_unaligned(SP); + SP +=4; + + // Skip stack frame + SP += m_amout; + + return 0; +} + +UINT32 v60_device::opTRAP() +{ + UINT32 oldPSW; + + m_modadd = PC + 1; + m_moddim = 0; + + // Read the operand + m_amlength1 = ReadAM(); + + // Normalize the flags + NORMALIZEFLAGS(); + + switch ((m_amout >> 4) & 0xF) + { + case 0: + if (!_OV) return m_amlength1 + 1; + else break; + case 1: + if (_OV) return m_amlength1 + 1; + else break; + case 2: + if (!_CY) return m_amlength1 + 1; + else break; + case 3: + if (_CY) return m_amlength1 + 1; + else break; + case 4: + if (!_Z) return m_amlength1 + 1; + else break; + case 5: + if (_Z) return m_amlength1 + 1; + else break; + case 6: + if (!(_CY | _Z)) return m_amlength1 + 1; + else break; + case 7: + if ((_CY | _Z)) return m_amlength1 + 1; + else break; + case 8: + if (!_S) return m_amlength1 + 1; + else break; + case 9: + if (_S) return m_amlength1 + 1; + else break; + case 10: + break; + case 11: + return m_amlength1 + 1; + case 12: + if (!(_S^_OV)) return m_amlength1 + 1; + else break; + case 13: + if ((_S^_OV)) return m_amlength1 + 1; + else break; + case 14: + if (!((_S^_OV)|_Z)) return m_amlength1 + 1; + else break; + case 15: + if (((_S^_OV)|_Z)) return m_amlength1 + 1; + else break; + } + + oldPSW = v60_update_psw_for_exception(0, 0); + + // Issue the software trap with interrupts + SP -= 4; + m_program->write_dword_unaligned(SP, EXCEPTION_CODE_AND_SIZE(0x3000 + 0x100 * (m_amout & 0xF), 4)); + + SP -= 4; + m_program->write_dword_unaligned(SP, oldPSW); + + SP -= 4; + m_program->write_dword_unaligned(SP, PC + m_amlength1 + 1); + + PC = GETINTVECT(48 + (m_amout & 0xF)); + + return 0; +} + +UINT32 v60_device::opRETIU() /* TRUSTED */ +{ + UINT32 newPSW; + m_modadd = PC + 1; + m_moddim = 1; + + // Read the operand + ReadAM(); + + // Restore PC and PSW from stack + PC = m_program->read_dword_unaligned(SP); + SP += 4; + + newPSW = m_program->read_dword_unaligned(SP); + SP += 4; + + // Destroy stack frame + SP += m_amout; + + v60WritePSW(newPSW); + + return 0; +} + +UINT32 v60_device::opRETIS() +{ + UINT32 newPSW; + + m_modadd = PC + 1; + m_moddim = 1; + + // Read the operand + ReadAM(); + + // Restore PC and PSW from stack + PC = m_program->read_dword_unaligned(SP); + SP += 4; + + newPSW = m_program->read_dword_unaligned(SP); + SP += 4; + + // Destroy stack frame + SP += m_amout; + + v60WritePSW(newPSW); + + return 0; +} + +UINT32 v60_device::opSTTASK() +{ + int i; + UINT32 adr; + + m_modadd = PC + 1; + m_moddim = 2; + + m_amlength1 = ReadAM(); + + adr = TR; + + v60WritePSW(v60ReadPSW() | 0x10000000); + v60SaveStack(); + + m_program->write_dword_unaligned(adr, TKCW); + adr += 4; + if(SYCW & 0x100) { + m_program->write_dword_unaligned(adr, L0SP); + adr += 4; + } + if(SYCW & 0x200) { + m_program->write_dword_unaligned(adr, L1SP); + adr += 4; + } + if(SYCW & 0x400) { + m_program->write_dword_unaligned(adr, L2SP); + adr += 4; + } + if(SYCW & 0x800) { + m_program->write_dword_unaligned(adr, L3SP); + adr += 4; + } + + // 31 registers supported, _not_ 32 + for(i = 0; i < 31; i++) + if(m_amout & (1 << i)) { + m_program->write_dword_unaligned(adr, m_reg[i]); + adr += 4; + } + + // #### Ignore the virtual addressing crap. + + return m_amlength1 + 1; +} + +UINT32 v60_device::opGETPSW() +{ + m_modadd = PC + 1; + m_moddim = 2; + m_modwritevalw = v60ReadPSW(); + + // Write PSW to the operand + m_amlength1 = WriteAM(); + + return m_amlength1 + 1; +} + +UINT32 v60_device::opTASI() +{ + UINT8 appb; + m_modadd = PC + 1; + m_moddim = 0; + + // Load the address of the operand + m_amlength1 = ReadAMAddress(); + + // Load UINT8 from the address + if (m_amflag) + appb = (UINT8)m_reg[m_amout & 0x1F]; + else + appb = m_program->read_byte(m_amout); + + // Set the flags for SUB appb, FF + SUBB(appb, 0xff); + + // Write FF in the operand + if (m_amflag) + SETREG8(m_reg[m_amout & 0x1F], 0xFF); + else + m_program->write_byte(m_amout, 0xFF); + + return m_amlength1 + 1; +} + +UINT32 v60_device::opCLRTLB() +{ + m_modadd = PC + 1; + m_moddim = 2; + + // Read the operand + m_amlength1 = ReadAM(); + + // @@@ TLB not yet emulated + + return m_amlength1 + 1; +} + +UINT32 v60_device::opPOPM() +{ + int i; + + m_modadd = PC + 1; + m_moddim = 2; + + // Read the bit register list + m_amlength1 = ReadAM(); + + for (i = 0;i < 31;i++) + if (m_amout & (1 << i)) + { + m_reg[i] = m_program->read_dword_unaligned(SP); + SP += 4; + } + + if (m_amout & (1 << 31)) + { + v60WritePSW((v60ReadPSW() & 0xffff0000) | m_program->read_word_unaligned(SP)); + SP += 4; + } + + return m_amlength1 + 1; +} + +UINT32 v60_device::opPUSHM() +{ + int i; + + m_modadd = PC + 1; + m_moddim = 2; + + // Read the bit register list + m_amlength1 = ReadAM(); + + if (m_amout & (1 << 31)) + { + SP -= 4; + m_program->write_dword_unaligned(SP, v60ReadPSW()); + } + + for (i = 0;i < 31;i++) + if (m_amout & (1 << (30 - i))) + { + SP -= 4; + m_program->write_dword_unaligned(SP, m_reg[(30 - i)]); + } + + + return m_amlength1 + 1; +} + +UINT32 v60_device::opTESTB() /* TRUSTED */ +{ + m_modadd = PC + 1; + m_moddim = 0; + + // Read the operand + m_amlength1 = ReadAM(); + + _Z = (m_amout == 0); + _S = ((m_amout & 0x80) != 0); + _CY = 0; + _OV = 0; + + return m_amlength1 + 1; +} + +UINT32 v60_device::opTESTH() /* TRUSTED */ +{ + m_modadd = PC + 1; + m_moddim = 1; + + // Read the operand + m_amlength1 = ReadAM(); + + _Z = (m_amout == 0); + _S = ((m_amout & 0x8000) != 0); + _CY = 0; + _OV = 0; + + return m_amlength1 + 1; +} + +UINT32 v60_device::opTESTW() /* TRUSTED */ +{ + m_modadd = PC + 1; + m_moddim = 2; + + // Read the operand + m_amlength1 = ReadAM(); + + _Z = (m_amout == 0); + _S = ((m_amout & 0x80000000) != 0); + _CY = 0; + _OV = 0; + + return m_amlength1 + 1; +} + +UINT32 v60_device::opPUSH() +{ + m_modadd = PC + 1; + m_moddim = 2; + + m_amlength1 = ReadAM(); + + SP-=4; + m_program->write_dword_unaligned(SP, m_amout); + + return m_amlength1 + 1; +} + +UINT32 v60_device::opPOP() +{ + m_modadd = PC + 1; + m_moddim = 2; + m_modwritevalw = m_program->read_dword_unaligned(SP); + SP +=4; + m_amlength1 = WriteAM(); + + return m_amlength1 + 1; +} + + +UINT32 v60_device::opINCB_0() { m_modm = 0; return opINCB(); } +UINT32 v60_device::opINCB_1() { m_modm = 1; return opINCB(); } +UINT32 v60_device::opINCH_0() { m_modm = 0; return opINCH(); } +UINT32 v60_device::opINCH_1() { m_modm = 1; return opINCH(); } +UINT32 v60_device::opINCW_0() { m_modm = 0; return opINCW(); } +UINT32 v60_device::opINCW_1() { m_modm = 1; return opINCW(); } + +UINT32 v60_device::opDECB_0() { m_modm = 0; return opDECB(); } +UINT32 v60_device::opDECB_1() { m_modm = 1; return opDECB(); } +UINT32 v60_device::opDECH_0() { m_modm = 0; return opDECH(); } +UINT32 v60_device::opDECH_1() { m_modm = 1; return opDECH(); } +UINT32 v60_device::opDECW_0() { m_modm = 0; return opDECW(); } +UINT32 v60_device::opDECW_1() { m_modm = 1; return opDECW(); } + +UINT32 v60_device::opJMP_0() { m_modm = 0; return opJMP(); } +UINT32 v60_device::opJMP_1() { m_modm = 1; return opJMP(); } + +UINT32 v60_device::opJSR_0() { m_modm = 0; return opJSR(); } +UINT32 v60_device::opJSR_1() { m_modm = 1; return opJSR(); } + +UINT32 v60_device::opPREPARE_0() { m_modm = 0; return opPREPARE(); } +UINT32 v60_device::opPREPARE_1() { m_modm = 1; return opPREPARE(); } + +UINT32 v60_device::opRET_0() { m_modm = 0; return opRET(); } +UINT32 v60_device::opRET_1() { m_modm = 1; return opRET(); } + +UINT32 v60_device::opTRAP_0() { m_modm = 0; return opTRAP(); } +UINT32 v60_device::opTRAP_1() { m_modm = 1; return opTRAP(); } + +UINT32 v60_device::opRETIU_0() { m_modm = 0; return opRETIU(); } +UINT32 v60_device::opRETIU_1() { m_modm = 1; return opRETIU(); } + +UINT32 v60_device::opRETIS_0() { m_modm = 0; return opRETIS(); } +UINT32 v60_device::opRETIS_1() { m_modm = 1; return opRETIS(); } + +UINT32 v60_device::opGETPSW_0() { m_modm = 0; return opGETPSW(); } +UINT32 v60_device::opGETPSW_1() { m_modm = 1; return opGETPSW(); } + +UINT32 v60_device::opTASI_0() { m_modm = 0; return opTASI(); } +UINT32 v60_device::opTASI_1() { m_modm = 1; return opTASI(); } + +UINT32 v60_device::opCLRTLB_0() { m_modm = 0; return opCLRTLB(); } +UINT32 v60_device::opCLRTLB_1() { m_modm = 1; return opCLRTLB(); } + +UINT32 v60_device::opPOPM_0() { m_modm = 0; return opPOPM(); } +UINT32 v60_device::opPOPM_1() { m_modm = 1; return opPOPM(); } + +UINT32 v60_device::opPUSHM_0() { m_modm = 0; return opPUSHM(); } +UINT32 v60_device::opPUSHM_1() { m_modm = 1; return opPUSHM(); } + +UINT32 v60_device::opTESTB_0() { m_modm = 0; return opTESTB(); } +UINT32 v60_device::opTESTB_1() { m_modm = 1; return opTESTB(); } + +UINT32 v60_device::opTESTH_0() { m_modm = 0; return opTESTH(); } +UINT32 v60_device::opTESTH_1() { m_modm = 1; return opTESTH(); } + +UINT32 v60_device::opTESTW_0() { m_modm = 0; return opTESTW(); } +UINT32 v60_device::opTESTW_1() { m_modm = 1; return opTESTW(); } + +UINT32 v60_device::opPUSH_0() { m_modm = 0; return opPUSH(); } +UINT32 v60_device::opPUSH_1() { m_modm = 1; return opPUSH(); } + +UINT32 v60_device::opPOP_0() { m_modm = 0; return opPOP(); } +UINT32 v60_device::opPOP_1() { m_modm = 1; return opPOP(); } + +UINT32 v60_device::opSTTASK_0() { m_modm = 0; return opSTTASK(); } +UINT32 v60_device::opSTTASK_1() { m_modm = 1; return opSTTASK(); } diff --git a/src/devices/cpu/v60/op4.inc b/src/devices/cpu/v60/op4.inc new file mode 100644 index 00000000000..ca5b4cef4c6 --- /dev/null +++ b/src/devices/cpu/v60/op4.inc @@ -0,0 +1,354 @@ +// license:BSD-3-Clause +// copyright-holders:Farfetch'd, R. Belmont +/* + FULLY TRUSTED +*/ + +UINT32 v60_device::opBGT8() /* TRUSTED */ +{ + NORMALIZEFLAGS(); + + if (!((_S ^ _OV) | _Z)) + { + PC += (INT8)OpRead8(PC + 1); + return 0; + } + + return 2; +} + +UINT32 v60_device::opBGT16() /* TRUSTED */ +{ + NORMALIZEFLAGS(); + + if (!((_S ^ _OV) | _Z)) + { + PC += (INT16)OpRead16(PC + 1); + return 0; + } + + return 3; +} + + +UINT32 v60_device::opBGE8() /* TRUSTED */ +{ + NORMALIZEFLAGS(); + + if (!(_S ^ _OV)) + { + PC += (INT8)OpRead8(PC + 1); + return 0; + } + + return 2; +} + +UINT32 v60_device::opBGE16() /* TRUSTED */ +{ + NORMALIZEFLAGS(); + + if (!(_S ^ _OV)) + { + PC += (INT16)OpRead16(PC + 1); + return 0; + } + + return 3; +} + +UINT32 v60_device::opBLT8() /* TRUSTED */ +{ + NORMALIZEFLAGS(); + + if ((_S ^ _OV)) + { + PC += (INT8)OpRead8(PC + 1); + return 0; + } + + return 2; +} + +UINT32 v60_device::opBLT16() /* TRUSTED */ +{ + NORMALIZEFLAGS(); + + if ((_S ^ _OV)) + { + PC += (INT16)OpRead16(PC + 1); + return 0; + } + + return 3; +} + + +UINT32 v60_device::opBLE8() /* TRUSTED */ +{ + NORMALIZEFLAGS(); + + if (((_S ^ _OV) | _Z)) + { + PC += (INT8)OpRead8(PC + 1); + return 0; + } + + return 2; +} + +UINT32 v60_device::opBLE16() /* TRUSTED */ +{ + NORMALIZEFLAGS(); + + if (((_S ^ _OV) | _Z)) + { + PC += (INT16)OpRead16(PC + 1); + return 0; + } + + return 3; +} + +UINT32 v60_device::opBH8() /* TRUSTED */ +{ + if (!(_CY | _Z)) + { + PC += (INT8)OpRead8(PC + 1); + return 0; + } + + return 2; +} + +UINT32 v60_device::opBH16() /* TRUSTED */ +{ + if (!(_CY | _Z)) + { + PC += (INT16)OpRead16(PC + 1); + return 0; + } + + return 3; +} + +UINT32 v60_device::opBNH8() /* TRUSTED */ +{ + if ((_CY | _Z)) + { + PC += (INT8)OpRead8(PC + 1); + return 0; + } + + return 2; +} + +UINT32 v60_device::opBNH16() /* TRUSTED */ +{ + if ((_CY | _Z)) + { + PC += (INT16)OpRead16(PC + 1); + return 0; + } + + return 3; +} + +UINT32 v60_device::opBNL8() /* TRUSTED */ +{ + if (!(_CY)) + { + PC += (INT8)OpRead8(PC + 1); + return 0; + } + + return 2; +} + +UINT32 v60_device::opBNL16() /* TRUSTED */ +{ + if (!(_CY)) + { + PC += (INT16)OpRead16(PC + 1); + return 0; + } + + return 3; +} + +UINT32 v60_device::opBL8() /* TRUSTED */ +{ + if ((_CY)) + { + PC += (INT8)OpRead8(PC + 1); + return 0; + } + + return 2; +} + +UINT32 v60_device::opBL16() /* TRUSTED */ +{ + if ((_CY)) + { + PC += (INT16)OpRead16(PC + 1); + return 0; + } + + return 3; +} + +UINT32 v60_device::opBNE8() /* TRUSTED */ +{ + if (!(_Z)) + { + PC += (INT8)OpRead8(PC + 1); + return 0; + } + + return 2; +} + +UINT32 v60_device::opBNE16() /* TRUSTED */ +{ + if (!(_Z)) + { + PC += (INT16)OpRead16(PC + 1); + return 0; + } + + return 3; +} + +UINT32 v60_device::opBE8() /* TRUSTED */ +{ + if ((_Z)) + { + PC += (INT8)OpRead8(PC + 1); + return 0; + } + + return 2; +} + +UINT32 v60_device::opBE16() /* TRUSTED */ +{ + if ((_Z)) + { + PC += (INT16)OpRead16(PC + 1); + return 0; + } + + return 3; +} + +UINT32 v60_device::opBNV8() /* TRUSTED */ +{ + if (!(_OV)) + { + PC += (INT8)OpRead8(PC + 1); + return 0; + } + + return 2; +} + +UINT32 v60_device::opBNV16() /* TRUSTED */ +{ + if (!(_OV)) + { + PC += (INT16)OpRead16(PC + 1); + return 0; + } + + return 3; +} + +UINT32 v60_device::opBV8() /* TRUSTED */ +{ + if ((_OV)) + { + PC += (INT8)OpRead8(PC + 1); + return 0; + } + + return 2; +} + +UINT32 v60_device::opBV16() /* TRUSTED */ +{ + if ((_OV)) + { + PC += (INT16)OpRead16(PC + 1); + return 0; + } + + return 3; +} + +UINT32 v60_device::opBP8() /* TRUSTED */ +{ + if (!(_S)) + { + PC += (INT8)OpRead8(PC + 1); + return 0; + } + + return 2; +} + +UINT32 v60_device::opBP16() /* TRUSTED */ +{ + if (!(_S)) + { + PC += (INT16)OpRead16(PC + 1); + return 0; + } + + return 3; +} + +UINT32 v60_device::opBN8() /* TRUSTED */ +{ + if ((_S)) + { + PC += (INT8)OpRead8(PC + 1); + return 0; + } + + return 2; +} + +UINT32 v60_device::opBN16() /* TRUSTED */ +{ + if ((_S)) + { + PC += (INT16)OpRead16(PC + 1); + return 0; + } + + return 3; +} + +UINT32 v60_device::opBR8() /* TRUSTED */ +{ + PC += (INT8)OpRead8(PC + 1); + return 0; +} + +UINT32 v60_device::opBR16() /* TRUSTED */ +{ + PC += (INT16)OpRead16(PC + 1); + return 0; +} + +UINT32 v60_device::opBSR() /* TRUSTED */ +{ + // Save Next PC onto the stack + SP -= 4; + m_program->write_dword_unaligned(SP, PC + 3); + + // Jump to subroutine + PC += (INT16)OpRead16(PC + 1); + return 0; +} diff --git a/src/devices/cpu/v60/op5.inc b/src/devices/cpu/v60/op5.inc new file mode 100644 index 00000000000..be6084eb6e1 --- /dev/null +++ b/src/devices/cpu/v60/op5.inc @@ -0,0 +1,87 @@ +// license:BSD-3-Clause +// copyright-holders:Farfetch'd, R. Belmont +/* + * HALT: must add log + */ + +UINT32 v60_device::opBRK() +{ +/* + UINT32 oldPSW = v60_update_psw_for_exception(0, 0); + + SP -=4; + m_program->write_dword_unaligned(SP, EXCEPTION_CODE_AND_SIZE(0x0d00, 4)); + SP -=4; + m_program->write_dword_unaligned(SP, oldPSW); + SP -=4; + m_program->write_dword_unaligned(SP, PC + 1); + PC = GETINTVECT(13); +*/ + logerror("Skipping BRK opcode! PC=%x", PC); + + return 1; +} + +UINT32 v60_device::opBRKV() +{ + UINT32 oldPSW = v60_update_psw_for_exception(0, 0); + + SP -=4; + m_program->write_dword_unaligned(SP, PC); + SP -=4; + m_program->write_dword_unaligned(SP, EXCEPTION_CODE_AND_SIZE(0x1501, 4)); + SP -=4; + m_program->write_dword_unaligned(SP, oldPSW); + SP -=4; + m_program->write_dword_unaligned(SP, PC + 1); + PC = GETINTVECT(21); + + return 0; +} + +UINT32 v60_device::opCLRTLBA() +{ + // @@@ TLB not yet supported + logerror("Skipping CLRTLBA opcode! PC=%x\n", PC); + return 1; +} + +UINT32 v60_device::opDISPOSE() +{ + SP = FP; + FP = m_program->read_dword_unaligned(SP); + SP +=4; + + return 1; +} + +UINT32 v60_device::opHALT() +{ + // @@@ It should wait for an interrupt to occur + //logerror("HALT found: skipping"); + return 1; +} + +UINT32 v60_device::opNOP() /* TRUSTED */ +{ + return 1; +} + +UINT32 v60_device::opRSR() +{ + PC = m_program->read_dword_unaligned(SP); + SP +=4; + + return 0; +} + +UINT32 v60_device::opTRAPFL() +{ + if ((TKCW & 0x1F0) & ((v60ReadPSW() & 0x1F00) >> 4)) + { + // @@@ FPU exception + fatalerror("Hit TRAPFL! PC=%x\n", PC); + } + + return 1; +} diff --git a/src/devices/cpu/v60/op6.inc b/src/devices/cpu/v60/op6.inc new file mode 100644 index 00000000000..087680534f9 --- /dev/null +++ b/src/devices/cpu/v60/op6.inc @@ -0,0 +1,254 @@ +// license:BSD-3-Clause +// copyright-holders:Farfetch'd, R. Belmont +/* + FULLY TRUSTED +*/ + +UINT32 v60_device::opTB(int reg) /* TRUSTED */ +{ + if (m_reg[reg] == 0) + { + PC += (INT16)OpRead16(PC + 2); + return 0; + } + + return 4; +} + +UINT32 v60_device::opDBGT(int reg) /* TRUSTED */ +{ + m_reg[reg]--; + + NORMALIZEFLAGS(); + if ((m_reg[reg] != 0) && !((_S ^ _OV) | _Z)) + { + PC += (INT16)OpRead16(PC + 2); + return 0; + } + + return 4; +} + +UINT32 v60_device::opDBLE(int reg) /* TRUSTED */ +{ + m_reg[reg]--; + + NORMALIZEFLAGS(); + if ((m_reg[reg] != 0) && ((_S ^ _OV) | _Z)) + { + PC += (INT16)OpRead16(PC + 2); + return 0; + } + + return 4; +} + + +UINT32 v60_device::opDBGE(int reg) /* TRUSTED */ +{ + m_reg[reg]--; + + NORMALIZEFLAGS(); + if ((m_reg[reg] != 0) && !(_S ^ _OV)) + { + PC += (INT16)OpRead16(PC + 2); + return 0; + } + + return 4; +} + +UINT32 v60_device::opDBLT(int reg) /* TRUSTED */ +{ + m_reg[reg]--; + + NORMALIZEFLAGS(); + if ((m_reg[reg] != 0) && (_S ^ _OV)) + { + PC += (INT16)OpRead16(PC + 2); + return 0; + } + + return 4; +} + +UINT32 v60_device::opDBH(int reg) /* TRUSTED */ +{ + m_reg[reg]--; + + if ((m_reg[reg] != 0) && !(_CY | _Z)) + { + PC += (INT16)OpRead16(PC + 2); + return 0; + } + + return 4; +} + +UINT32 v60_device::opDBNH(int reg) /* TRUSTED */ +{ + m_reg[reg]--; + + if ((m_reg[reg] != 0) && (_CY | _Z)) + { + PC += (INT16)OpRead16(PC + 2); + return 0; + } + + return 4; +} + + +UINT32 v60_device::opDBL(int reg) /* TRUSTED */ +{ + m_reg[reg]--; + + if ((m_reg[reg] != 0) && (_CY)) + { + PC += (INT16)OpRead16(PC + 2); + return 0; + } + + return 4; +} + +UINT32 v60_device::opDBNL(int reg) /* TRUSTED */ +{ + m_reg[reg]--; + + if ((m_reg[reg] != 0) && !(_CY)) + { + PC += (INT16)OpRead16(PC + 2); + return 0; + } + + return 4; +} + +UINT32 v60_device::opDBE(int reg) /* TRUSTED */ +{ + m_reg[reg]--; + + if ((m_reg[reg] != 0) && (_Z)) + { + PC += (INT16)OpRead16(PC + 2); + return 0; + } + + return 4; +} + +UINT32 v60_device::opDBNE(int reg) /* TRUSTED */ +{ + m_reg[reg]--; + + if ((m_reg[reg] != 0) && !(_Z)) + { + PC += (INT16)OpRead16(PC + 2); + return 0; + } + + return 4; +} + +UINT32 v60_device::opDBV(int reg) /* TRUSTED */ +{ + m_reg[reg]--; + + if ((m_reg[reg] != 0) && (_OV)) + { + PC += (INT16)OpRead16(PC + 2); + return 0; + } + + return 4; +} + +UINT32 v60_device::opDBNV(int reg) /* TRUSTED */ +{ + m_reg[reg]--; + + if ((m_reg[reg] != 0) && !(_OV)) + { + PC += (INT16)OpRead16(PC + 2); + return 0; + } + + return 4; +} + +UINT32 v60_device::opDBN(int reg) /* TRUSTED */ +{ + m_reg[reg]--; + + if ((m_reg[reg] != 0) && (_S)) + { + PC += (INT16)OpRead16(PC + 2); + return 0; + } + + return 4; +} + +UINT32 v60_device::opDBP(int reg) /* TRUSTED */ +{ + m_reg[reg]--; + + if ((m_reg[reg] != 0) && !(_S)) + { + PC += (INT16)OpRead16(PC + 2); + return 0; + } + + return 4; +} + +UINT32 v60_device::opDBR(int reg) /* TRUSTED */ +{ + m_reg[reg]--; + + if (m_reg[reg] != 0) + { + PC += (INT16)OpRead16(PC + 2); + return 0; + } + + return 4; +} + +const v60_device::op6_func v60_device::s_OpC6Table[8] = /* TRUSTED */ +{ + &v60_device::opDBV, + &v60_device::opDBL, + &v60_device::opDBE, + &v60_device::opDBNH, + &v60_device::opDBN, + &v60_device::opDBR, + &v60_device::opDBLT, + &v60_device::opDBLE +}; + +const v60_device::op6_func v60_device::s_OpC7Table[8] = /* TRUSTED */ +{ + &v60_device::opDBNV, + &v60_device::opDBNL, + &v60_device::opDBNE, + &v60_device::opDBH, + &v60_device::opDBP, + &v60_device::opTB, + &v60_device::opDBGE, + &v60_device::opDBGT +}; + + +UINT32 v60_device::opC6() /* TRUSTED */ +{ + UINT8 appb = OpRead8(PC + 1); + return (this->*s_OpC6Table[appb >> 5])(appb & 0x1f); +} + +UINT32 v60_device::opC7() /* TRUSTED */ +{ + UINT8 appb = OpRead8(PC + 1); + return (this->*s_OpC7Table[appb >> 5])(appb & 0x1f); +} diff --git a/src/devices/cpu/v60/op7a.inc b/src/devices/cpu/v60/op7a.inc new file mode 100644 index 00000000000..67a7b0fb82c --- /dev/null +++ b/src/devices/cpu/v60/op7a.inc @@ -0,0 +1,1212 @@ +// license:BSD-3-Clause +// copyright-holders:Farfetch'd, R. Belmont +/* + * CMPC: What happens to _S flag if the strings are identical? + * I suppose that it will be cleared. And is it set or cleared + * when the first one is a substring of the second? I suppose + * cleared (since _S should be (src > dst)) + * MOVC: Why MOVCS does not exist in downward version? + * SHCHDB / SHCHDH: R27 is filled with the offset from the start or from the end? + * + * Strange stuff: + * SCHC opcodes does *not* modify _Z flag as stated in V60 manual: + * they do the opposite (set if not found, reset if found) + */ + +#define F7AEND() \ + return m_amlength1 + m_amlength2 + 4; + +#define F7BEND() \ + return m_amlength1 + m_amlength2 + 3; + +#define F7CEND() \ + return m_amlength1 + m_amlength2 + 3; + +#define F7BCREATEBITMASK(x) \ + x = ((1 << (x)) - 1) + +#define F7CCREATEBITMASK(x) \ + x = ((1 << (x)) - 1) + +void v60_device::F7aDecodeOperands(am_func DecodeOp1, UINT8 dim1, am_func DecodeOp2, UINT8 dim2) +{ + UINT8 appb; + // Decode first operand + m_moddim = dim1; + m_modm = m_subop & 0x40; + m_modadd = PC + 2; + m_amlength1 = (this->*DecodeOp1)(); + m_flag1 = m_amflag; + m_op1 = m_amout; + + // Decode length + appb = OpRead8(PC + 2 + m_amlength1); + if (appb & 0x80) + m_lenop1 = m_reg[appb & 0x1F]; + else + m_lenop1 = appb; + + // Decode second operand + m_moddim = dim2; + m_modm = m_subop & 0x20; + m_modadd = PC + 3 + m_amlength1; + m_amlength2 = (this->*DecodeOp2)(); + m_flag2 = m_amflag; + m_op2 = m_amout; + + // Decode length + appb = OpRead8(PC + 3 + m_amlength1 + m_amlength2); + if (appb & 0x80) + m_lenop2 = m_reg[appb & 0x1F]; + else + m_lenop2 = appb; +} + +void v60_device::F7bDecodeFirstOperand(am_func DecodeOp1, UINT8 dim1) +{ + UINT8 appb; + // Decode first operand + m_moddim = dim1; + m_modm = m_subop & 0x40; + m_modadd = PC + 2; + m_amlength1 = (this->*DecodeOp1)(); + m_flag1 = m_amflag; + m_op1 = m_amout; + + // Decode ext + appb = OpRead8(PC + 2 + m_amlength1); + if (appb & 0x80) + m_lenop1 = m_reg[appb & 0x1F]; + else + m_lenop1 = appb; +} + + +void v60_device::F7bWriteSecondOperand(UINT8 dim2) +{ + m_moddim = dim2; + m_modm = m_subop & 0x20; + m_modadd = PC + 3 + m_amlength1; + m_amlength2 = WriteAM(); +} + + +void v60_device::F7bDecodeOperands(am_func DecodeOp1, UINT8 dim1, am_func DecodeOp2, UINT8 dim2) +{ + // Decode first operand + F7bDecodeFirstOperand(DecodeOp1, dim1); + m_bamoffset1 = m_bamoffset; + + // Decode second operand + m_moddim = dim2; + m_modm = m_subop & 0x20; + m_modadd = PC + 3 + m_amlength1; + m_amlength2 = (this->*DecodeOp2)(); + m_flag2 = m_amflag; + m_op2 = m_amout; + m_bamoffset2 = m_bamoffset; +} + +void v60_device::F7cDecodeOperands(am_func DecodeOp1, UINT8 dim1, am_func DecodeOp2, UINT8 dim2) +{ + UINT8 appb; + // Decode first operand + m_moddim = dim1; + m_modm = m_subop & 0x40; + m_modadd = PC + 2; + m_amlength1 = (this->*DecodeOp1)(); + m_flag1 = m_amflag; + m_op1 = m_amout; + + // Decode second operand + m_moddim = dim2; + m_modm = m_subop & 0x20; + m_modadd = PC + 2 + m_amlength1; + m_amlength2 = (this->*DecodeOp2)(); + m_flag2 = m_amflag; + m_op2 = m_amout; + + // Decode ext + appb = OpRead8(PC + 2 + m_amlength1 + m_amlength2); + if (appb & 0x80) + m_lenop1 = m_reg[appb & 0x1F]; + else + m_lenop1 = appb; +} + +#define F7CLOADOP1BYTE(appb) \ + if (m_flag1) \ + appb = (UINT8)(m_reg[m_op1]&0xFF); \ + else \ + appb = m_program->read_byte(m_op1); + +#define F7CLOADOP2BYTE(appb) \ + if (m_flag2) \ + appb = (UINT8)(m_reg[m_op2]&0xFF); \ + else \ + appb = m_program->read_byte(m_op2); + + +#define F7CSTOREOP2BYTE() \ + if (m_flag2) \ + SETREG8(m_reg[m_op2], appb); \ + else \ + m_program->write_byte(m_op2, appb); + +#define F7CSTOREOP2HALF() \ + if (m_flag2) \ + SETREG16(m_reg[m_op2], apph); \ + else \ + m_program->write_word_unaligned(m_op2, apph); + +UINT32 v60_device::opCMPSTRB(UINT8 bFill, UINT8 bStop) +{ + UINT32 i, dest; + UINT8 c1, c2; + + F7aDecodeOperands(&v60_device::ReadAMAddress, 0,&v60_device::ReadAMAddress, 0); + + // Filling + if (bFill) + { + if (m_lenop1 < m_lenop2) + { + for (i = m_lenop1; i < m_lenop2; i++) + m_program->write_byte(m_op1 + i,(UINT8)R26); + } + else if (m_lenop2 < m_lenop1) + { + for (i = m_lenop2; i < m_lenop1; i++) + m_program->write_byte(m_op2 + i,(UINT8)R26); + } + } + + dest = (m_lenop1 < m_lenop2 ? m_lenop1 : m_lenop2); + + _Z = 0; + _S = 0; + if (bStop) _CY = 1; + + for (i = 0; i < dest; i++) + { + c1 = m_program->read_byte(m_op1 + i); + c2 = m_program->read_byte(m_op2 + i); + + if (c1 > c2) + { + _S = 1; break; + } + else if (c2 > c1) + { + _S = 0; break; + } + + if (bStop) + if (c1 == (UINT8)R26 || c2 == (UINT8)R26) + { + _CY = 0; + break; + } + } + + R28 = m_lenop1 + i; + R27 = m_lenop2 + i; + + if (i == dest) + { + if (m_lenop1 > m_lenop2) + _S = 1; + else if (m_lenop2 > m_lenop1) + _S = 0; + else + _Z = 1; + } + + F7AEND(); +} + +UINT32 v60_device::opCMPSTRH(UINT8 bFill, UINT8 bStop) +{ + UINT32 i, dest; + UINT16 c1, c2; + + F7aDecodeOperands(&v60_device::ReadAMAddress, 0,&v60_device::ReadAMAddress, 0); + + // Filling + if (bFill) + { + if (m_lenop1 < m_lenop2) + { + for (i = m_lenop1; i < m_lenop2; i++) + m_program->write_word_unaligned(m_op1 + i * 2,(UINT16)R26); + } + else if (m_lenop2 < m_lenop1) + { + for (i = m_lenop2; i < m_lenop1; i++) + m_program->write_word_unaligned(m_op2 + i * 2,(UINT16)R26); + } + } + + dest = (m_lenop1 < m_lenop2 ? m_lenop1 : m_lenop2); + + _Z = 0; + _S = 0; + if (bStop) _CY = 1; + + for (i = 0; i < dest; i++) + { + c1 = m_program->read_word_unaligned(m_op1 + i * 2); + c2 = m_program->read_word_unaligned(m_op2 + i * 2); + + if (c1 > c2) + { + _S = 1; break; + } + else if (c2 > c1) + { + _S = 0; break; + } + + if (bStop) + if (c1 == (UINT16)R26 || c2 == (UINT16)R26) + { + _CY = 0; + break; + } + } + + R28 = m_lenop1 + i * 2; + R27 = m_lenop2 + i * 2; + + if (i == dest) + { + if (m_lenop1 > m_lenop2) + _S = 1; + else if (m_lenop2 > m_lenop1) + _S = 0; + else + _Z = 1; + } + + F7AEND(); +} + + + +UINT32 v60_device::opMOVSTRUB(UINT8 bFill, UINT8 bStop) /* TRUSTED (0, 0) (1, 0) */ +{ + UINT32 i, dest; + UINT8 c1; + +// if (bStop) +// { +// int a = 1; +// } + + F7aDecodeOperands(&v60_device::ReadAMAddress, 0,&v60_device::ReadAMAddress, 0); + + dest = (m_lenop1 < m_lenop2 ? m_lenop1 : m_lenop2); + + for (i = 0; i < dest; i++) + { + m_program->write_byte(m_op2 + i,(c1 = m_program->read_byte(m_op1 + i))); + + if (bStop && c1 == (UINT8)R26) + break; + } + + R28 = m_op1 + i; + R27 = m_op2 + i; + + if (bFill && m_lenop1 < m_lenop2) + { + for (;i < m_lenop2; i++) + m_program->write_byte(m_op2 + i,(UINT8)R26); + + R27 = m_op2 + i; + } + + + F7AEND(); +} + +UINT32 v60_device::opMOVSTRDB(UINT8 bFill, UINT8 bStop) +{ + UINT32 i, dest; + UINT8 c1; + + F7aDecodeOperands(&v60_device::ReadAMAddress, 0,&v60_device::ReadAMAddress, 0); + + dest = (m_lenop1 < m_lenop2 ? m_lenop1 : m_lenop2); + + for (i = 0; i < dest; i++) + { + m_program->write_byte(m_op2 + (dest - i - 1),(c1 = m_program->read_byte(m_op1 + (dest - i - 1)))); + + if (bStop && c1 == (UINT8)R26) + break; + } + + R28 = m_op1 + (m_lenop1 - i - 1); + R27 = m_op2 + (m_lenop2 - i - 1); + + if (bFill && m_lenop1 < m_lenop2) + { + for (;i < m_lenop2; i++) + m_program->write_byte(m_op2 + dest + (m_lenop2 - i - 1),(UINT8)R26); + + R27 = m_op2 + (m_lenop2 - i - 1); + } + + + F7AEND(); +} + + +UINT32 v60_device::opMOVSTRUH(UINT8 bFill, UINT8 bStop) /* TRUSTED (0, 0) (1, 0) */ +{ + UINT32 i, dest; + UINT16 c1; + +// if (bStop) +// { int a = 1; } + + F7aDecodeOperands(&v60_device::ReadAMAddress, 1,&v60_device::ReadAMAddress, 1); + + dest = (m_lenop1 < m_lenop2 ? m_lenop1 : m_lenop2); + + for (i = 0; i < dest; i++) + { + m_program->write_word_unaligned(m_op2 + i * 2,(c1 = m_program->read_word_unaligned(m_op1 + i * 2))); + + if (bStop && c1 == (UINT16)R26) + break; + } + + R28 = m_op1 + i * 2; + R27 = m_op2 + i * 2; + + if (bFill && m_lenop1 < m_lenop2) + { + for (;i < m_lenop2; i++) + m_program->write_word_unaligned(m_op2 + i * 2,(UINT16)R26); + + R27 = m_op2 + i * 2; + } + + F7AEND(); +} + +UINT32 v60_device::opMOVSTRDH(UINT8 bFill, UINT8 bStop) +{ + UINT32 i, dest; + UINT16 c1; + +// if (bFill | bStop) +// { int a = 1; } + + F7aDecodeOperands(&v60_device::ReadAMAddress, 1,&v60_device::ReadAMAddress, 1); + +// if (m_lenop1 != m_lenop2) +// { int a = 1; } + + dest = (m_lenop1 < m_lenop2 ? m_lenop1 : m_lenop2); + + for (i = 0; i < dest; i++) + { + m_program->write_word_unaligned(m_op2 + (dest - i - 1) * 2,(c1 = m_program->read_word_unaligned(m_op1 + (dest - i - 1) * 2))); + + if (bStop && c1 == (UINT16)R26) + break; + } + + R28 = m_op1 + (m_lenop1 - i - 1) * 2; + R27 = m_op2 + (m_lenop2 - i - 1) * 2; + + if (bFill && m_lenop1 < m_lenop2) + { + for (;i < m_lenop2; i++) + m_program->write_word_unaligned(m_op2 + (m_lenop2 - i - 1) * 2,(UINT16)R26); + + R27 = m_op2 + (m_lenop2 - i - 1) * 2; + } + + F7AEND(); +} + +UINT32 v60_device::opSEARCHUB(UINT8 bSearch) +{ + UINT8 appb; + UINT32 i; + + F7bDecodeOperands(&v60_device::ReadAMAddress, 0,&v60_device::ReadAM, 0); + + for (i = 0; i < m_lenop1; i++) + { + appb = (m_program->read_byte(m_op1 + i) == (UINT8)m_op2); + if ((bSearch && appb) || (!bSearch && !appb)) + break; + } + + R28 = m_op1 + i; + R27 = i; + + // This is the opposite as stated in V60 manual... + if (i != m_lenop1) + _Z = 0; + else + _Z = 1; + + F7BEND(); +} + +UINT32 v60_device::opSEARCHUH(UINT8 bSearch) +{ + UINT8 appb; + UINT32 i; + + F7bDecodeOperands(&v60_device::ReadAMAddress, 1,&v60_device::ReadAM, 1); + + for (i = 0; i < m_lenop1; i++) + { + appb = (m_program->read_word_unaligned(m_op1 + i * 2) == (UINT16)m_op2); + if ((bSearch && appb) || (!bSearch && !appb)) + break; + } + + R28 = m_op1 + i * 2; + R27 = i; + + if (i != m_lenop1) + _Z = 0; + else + _Z = 1; + + F7BEND(); +} + +UINT32 v60_device::opSEARCHDB(UINT8 bSearch) +{ + UINT8 appb; + INT32 i; + + F7bDecodeOperands(&v60_device::ReadAMAddress, 0,&v60_device::ReadAM, 0); + + for (i = m_lenop1; i >= 0; i--) + { + appb = (m_program->read_byte(m_op1 + i) == (UINT8)m_op2); + if ((bSearch && appb) || (!bSearch && !appb)) + break; + } + + R28 = m_op1 + i; + R27 = i; + + // This is the opposite as stated in V60 manual... + if ((UINT32)i != m_lenop1) + _Z = 0; + else + _Z = 1; + + F7BEND(); +} + +UINT32 v60_device::opSEARCHDH(UINT8 bSearch) +{ + UINT8 appb; + INT32 i; + + F7bDecodeOperands(&v60_device::ReadAMAddress, 1,&v60_device::ReadAM, 1); + + for (i = m_lenop1 - 1; i >= 0; i--) + { + appb = (m_program->read_word_unaligned(m_op1 + i * 2) == (UINT16)m_op2); + if ((bSearch && appb) || (!bSearch && !appb)) + break; + } + + R28 = m_op1 + i * 2; + R27 = i; + + if ((UINT32)i != m_lenop1) + _Z = 0; + else + _Z = 1; + + F7BEND(); +} + + +UINT32 v60_device::opSCHCUB() { return opSEARCHUB(1); } +UINT32 v60_device::opSCHCUH() { return opSEARCHUH(1); } +UINT32 v60_device::opSCHCDB() { return opSEARCHDB(1); } +UINT32 v60_device::opSCHCDH() { return opSEARCHDH(1); } +UINT32 v60_device::opSKPCUB() { return opSEARCHUB(0); } +UINT32 v60_device::opSKPCUH() { return opSEARCHUH(0); } +UINT32 v60_device::opSKPCDB() { return opSEARCHDB(0); } +UINT32 v60_device::opSKPCDH() { return opSEARCHDH(0); } + +UINT32 v60_device::opCMPCB() { return opCMPSTRB(0, 0); } +UINT32 v60_device::opCMPCH() { return opCMPSTRH(0, 0); } +UINT32 v60_device::opCMPCFB() { return opCMPSTRB(1, 0); } +UINT32 v60_device::opCMPCFH() { return opCMPSTRH(1, 0); } +UINT32 v60_device::opCMPCSB() { return opCMPSTRB(0, 1); } +UINT32 v60_device::opCMPCSH() { return opCMPSTRH(0, 1); } + +UINT32 v60_device::opMOVCUB() { return opMOVSTRUB(0, 0); } +UINT32 v60_device::opMOVCUH() { return opMOVSTRUH(0, 0); } +UINT32 v60_device::opMOVCFUB() { return opMOVSTRUB(1, 0); } +UINT32 v60_device::opMOVCFUH() { return opMOVSTRUH(1, 0); } +UINT32 v60_device::opMOVCSUB() { return opMOVSTRUB(0, 1); } +UINT32 v60_device::opMOVCSUH() { return opMOVSTRUH(0, 1); } + +UINT32 v60_device::opMOVCDB() { return opMOVSTRDB(0, 0); } +UINT32 v60_device::opMOVCDH() { return opMOVSTRDH(0, 0); } +UINT32 v60_device::opMOVCFDB() { return opMOVSTRDB(1, 0); } +UINT32 v60_device::opMOVCFDH() { return opMOVSTRDH(1, 0); } + +UINT32 v60_device::opEXTBFZ() /* TRUSTED */ +{ + F7bDecodeFirstOperand(&v60_device::BitReadAM, 11); + + F7BCREATEBITMASK(m_lenop1); + + m_modwritevalw = (m_op1 >> m_bamoffset) & m_lenop1; + + F7bWriteSecondOperand(2); + + F7BEND(); +} + +UINT32 v60_device::opEXTBFS() /* TRUSTED */ +{ + F7bDecodeFirstOperand(&v60_device::BitReadAM, 11); + + F7BCREATEBITMASK(m_lenop1); + + m_modwritevalw = (m_op1 >> m_bamoffset) & m_lenop1; + if (m_modwritevalw & ((m_lenop1 + 1) >> 1)) + m_modwritevalw |= ~m_lenop1; + + F7bWriteSecondOperand(2); + + F7BEND(); +} + +UINT32 v60_device::opEXTBFL() +{ + UINT32 appw; + + F7bDecodeFirstOperand(&v60_device::BitReadAM, 11); + + appw = m_lenop1; + F7BCREATEBITMASK(m_lenop1); + + m_modwritevalw = (m_op1 >> m_bamoffset) & m_lenop1; + m_modwritevalw <<= 32 - appw; + + F7bWriteSecondOperand(2); + + F7BEND(); +} + +UINT32 v60_device::opSCHBS(UINT32 bSearch1) +{ + UINT32 i, data; + UINT32 offset; + + F7bDecodeFirstOperand(&v60_device::BitReadAMAddress, 10); + + // Read first UINT8 + m_op1 += m_bamoffset / 8; + data = m_program->read_byte(m_op1); + offset = m_bamoffset & 7; + + // Scan bitstring + for (i = 0; i < m_lenop1; i++) + { + // Update the work register + R28 = m_op1; + + // There is a 0 / 1 at current offset? + if ((bSearch1 && (data&(1 << offset))) || + (!bSearch1 && !(data&(1 << offset)))) + break; + + // Next bit please + offset++; + if (offset == 8) + { + // Next UINT8 please + offset = 0; + m_op1++; + data = m_program->read_byte(m_op1); + } + } + + // Set zero if bit not found + _Z = (i == m_lenop1); + + // Write to destination the final offset + m_modwritevalw = i; + F7bWriteSecondOperand(2); + + F7BEND(); +} + +UINT32 v60_device::opSCH0BSU() { return opSCHBS(0); } +UINT32 v60_device::opSCH1BSU() { return opSCHBS(1); } + +UINT32 v60_device::opINSBFR() +{ + UINT32 appw; + F7cDecodeOperands(&v60_device::ReadAM, 2,&v60_device::BitReadAMAddress, 11); + + F7CCREATEBITMASK(m_lenop1); + + m_op2 += m_bamoffset / 8; + appw = m_program->read_dword_unaligned(m_op2); + m_bamoffset &= 7; + + appw &= ~(m_lenop1 << m_bamoffset); + appw |= (m_lenop1 & m_op1) << m_bamoffset; + + m_program->write_dword_unaligned(m_op2, appw); + + F7CEND(); +} + +UINT32 v60_device::opINSBFL() +{ + UINT32 appw; + F7cDecodeOperands(&v60_device::ReadAM, 2,&v60_device::BitReadAMAddress, 11); + + m_op1 >>= (32 - m_lenop1); + + F7CCREATEBITMASK(m_lenop1); + + m_op2 += m_bamoffset / 8; + appw = m_program->read_dword_unaligned(m_op2); + m_bamoffset &= 7; + + appw &= ~(m_lenop1 << m_bamoffset); + appw |= (m_lenop1 & m_op1) << m_bamoffset; + + m_program->write_dword_unaligned(m_op2, appw); + + F7CEND(); +} + +UINT32 v60_device::opMOVBSD() +{ + UINT32 i; + UINT8 srcdata, dstdata; + + F7bDecodeOperands(&v60_device::BitReadAMAddress, 10, &v60_device::BitReadAMAddress, 10); + +// if (m_lenop1 != 1) +// { int a = 1; } + + m_bamoffset1 += m_lenop1 - 1; + m_bamoffset2 += m_lenop1 - 1; + + m_op1 += m_bamoffset1 / 8; + m_op2 += m_bamoffset2 / 8; + + m_bamoffset1 &= 7; + m_bamoffset2 &= 7; + + srcdata = m_program->read_byte(m_op1); + dstdata = m_program->read_byte(m_op2); + + for (i = 0; i < m_lenop1; i++) + { + // Update work registers + R28 = m_op1; + R27 = m_op2; + + dstdata &= ~(1 << m_bamoffset2); + dstdata |= ((srcdata >> m_bamoffset1) & 1) << m_bamoffset2; + + if (m_bamoffset1 == 0) + { + m_bamoffset1 = 8; + m_op1--; + srcdata = m_program->read_byte(m_op1); + } + if (m_bamoffset2 == 0) + { + m_program->write_byte(m_op2, dstdata); + m_bamoffset2 = 8; + m_op2--; + dstdata = m_program->read_byte(m_op2); + } + + m_bamoffset1--; + m_bamoffset2--; + } + + // Flush of the final data + if (m_bamoffset2 != 7) + m_program->write_byte(m_op2, dstdata); + + F7BEND(); +} + +UINT32 v60_device::opMOVBSU() +{ + UINT32 i; + UINT8 srcdata, dstdata; + + F7bDecodeOperands(&v60_device::BitReadAMAddress, 10, &v60_device::BitReadAMAddress, 10); + + m_op1 += m_bamoffset1 / 8; + m_op2 += m_bamoffset2 / 8; + + m_bamoffset1 &= 7; + m_bamoffset2 &= 7; + + srcdata = m_program->read_byte(m_op1); + dstdata = m_program->read_byte(m_op2); + + for (i = 0; i < m_lenop1; i++) + { + // Update work registers + R28 = m_op1; + R27 = m_op2; + + dstdata &= ~(1 << m_bamoffset2); + dstdata |= ((srcdata >> m_bamoffset1) & 1) << m_bamoffset2; + + m_bamoffset1++; + m_bamoffset2++; + if (m_bamoffset1 == 8) + { + m_bamoffset1 = 0; + m_op1++; + srcdata = m_program->read_byte(m_op1); + } + if (m_bamoffset2 == 8) + { + m_program->write_byte(m_op2, dstdata); + m_bamoffset2 = 0; + m_op2++; + dstdata = m_program->read_byte(m_op2); + } + } + + // Flush of the final data + if (m_bamoffset2 != 0) + m_program->write_byte(m_op2, dstdata); + + F7BEND(); +} + +// RADM 0x20f4b8 holds the time left + +UINT32 v60_device::opADDDC() +{ + UINT8 appb; + UINT8 src, dst; + + F7cDecodeOperands(&v60_device::ReadAM, 0, &v60_device::ReadAMAddress, 0); + + if (m_lenop1 != 0) + { + logerror("ADDDC %x (pat: %x)\n", m_op1, m_lenop1); + } + + F7CLOADOP2BYTE(appb); + + src = (UINT8)(m_op1 >> 4) * 10 + (UINT8)(m_op1 & 0xF); + dst = (appb >> 4) * 10 + (appb & 0xF); + + appb = src + dst + (_CY?1:0); + + if (appb >= 100) + { + appb -= 100; + _CY = 1; + } + else + _CY = 0; + + // compute z flag: + // cleared if result non-zero or carry generated + // unchanged otherwise + if (appb != 0 || _CY) + _Z = 0; + + appb = ((appb / 10) << 4) | (appb % 10); + + F7CSTOREOP2BYTE(); + F7CEND(); +} + +UINT32 v60_device::opSUBDC() +{ + INT8 appb; + UINT32 src, dst; + + F7cDecodeOperands(&v60_device::ReadAM, 0, &v60_device::ReadAMAddress, 0); + + if (m_lenop1 != 0) + { + logerror("SUBDC %x (pat: %x)\n", m_op1, m_lenop1); + } + + F7CLOADOP2BYTE(appb); + + src = (UINT32)(m_op1 >> 4) * 10 + (UINT32)(m_op1 & 0xF); + dst = ((appb & 0xF0) >> 4) * 10 + (appb & 0xF); + + // Note that this APPB must be SIGNED! + appb = (INT32)dst - (INT32)src - (_CY?1:0); + + if (appb < 0) + { + appb += 100; + _CY = 1; + } + else + _CY = 0; + + // compute z flag: + // cleared if result non-zero or carry generated + // unchanged otherwise + if (appb != 0 || _CY) + _Z = 0; + + appb = ((appb / 10) << 4) | (appb % 10); + + F7CSTOREOP2BYTE(); + F7CEND(); +} + +UINT32 v60_device::opSUBRDC() +{ + INT8 appb; + UINT32 src, dst; + + F7cDecodeOperands(&v60_device::ReadAM, 0, &v60_device::ReadAMAddress, 0); + + if (m_lenop1 != 0) + { + logerror("SUBRDC %x (pat: %x)\n", m_op1, m_lenop1); + } + + F7CLOADOP2BYTE(appb); + + src = (UINT32)(m_op1 >> 4) * 10 + (UINT32)(m_op1 & 0xF); + dst = ((appb & 0xF0) >> 4) * 10 + (appb & 0xF); + + // Note that this APPB must be SIGNED! + appb = (INT32)src - (INT32)dst - (_CY?1:0); + + if (appb < 0) + { + appb += 100; + _CY = 1; + } + else + _CY = 0; + + // compute z flag: + // cleared if result non-zero or carry generated + // unchanged otherwise + if (appb != 0 || _CY) + _Z = 0; + + appb = ((appb / 10) << 4) | (appb % 10); + + F7CSTOREOP2BYTE(); + F7CEND(); +} + +UINT32 v60_device::opCVTDPZ() +{ + UINT16 apph; + + F7cDecodeOperands(&v60_device::ReadAM, 0, &v60_device::ReadAMAddress, 1); + + apph = (UINT16)(((m_op1 >> 4) & 0xF) | ((m_op1 & 0xF) << 8)); + apph |= (m_lenop1); + apph |= (m_lenop1 << 8); + + // Z flag is unchanged if src is zero, cleared otherwise + if (m_op1 != 0) _Z = 0; + + F7CSTOREOP2HALF(); + F7CEND(); +} + +UINT32 v60_device::opCVTDZP() +{ + UINT8 appb; + F7cDecodeOperands(&v60_device::ReadAM, 1, &v60_device::ReadAMAddress, 0); + + if ((m_op1 & 0xF0) != (m_lenop1 & 0xF0) || ((m_op1 >> 8) & 0xF0) != (m_lenop1 & 0xF0)) + { + // Decimal exception + logerror("CVTD.ZP Decimal exception #1!\n"); + } + + if ((m_op1 & 0xF) > 9 || ((m_op1 >> 8) & 0xF) > 9) + { + // Decimal exception + logerror("CVTD.ZP Decimal exception #2!\n"); + } + + appb = (UINT8)(((m_op1 >> 8) & 0xF) | ((m_op1 & 0xF) << 4)); + if (appb != 0) _Z = 0; + + F7CSTOREOP2BYTE(); + F7CEND(); +} + +UINT32 v60_device::op58UNHANDLED() +{ + fatalerror("Unhandled 58 opcode at PC: /%06x\n", PC); + return 0; /* never reached, fatalerror won't return */ +} + +UINT32 v60_device::op5AUNHANDLED() +{ + fatalerror("Unhandled 5A opcode at PC: /%06x\n", PC); + return 0; /* never reached, fatalerror won't return */ +} + +UINT32 v60_device::op5BUNHANDLED() +{ + fatalerror("Unhandled 5B opcode at PC: /%06x\n", PC); + return 0; /* never reached, fatalerror won't return */ +} + +UINT32 v60_device::op5DUNHANDLED() +{ + fatalerror("Unhandled 5D opcode at PC: /%06x\n", PC); + return 0; /* never reached, fatalerror won't return */ +} + +UINT32 v60_device::op59UNHANDLED() +{ + fatalerror("Unhandled 59 opcode at PC: /%06x\n", PC); + return 0; /* never reached, fatalerror won't return */ +} + +const v60_device::am_func v60_device::s_Op59Table[32] = +{ + &v60_device::opADDDC, + &v60_device::opSUBDC, + &v60_device::opSUBRDC, + &v60_device::op59UNHANDLED, + &v60_device::op59UNHANDLED, + &v60_device::op59UNHANDLED, + &v60_device::op59UNHANDLED, + &v60_device::op59UNHANDLED, + &v60_device::op59UNHANDLED, + &v60_device::op59UNHANDLED, + &v60_device::op59UNHANDLED, + &v60_device::op59UNHANDLED, + &v60_device::op59UNHANDLED, + &v60_device::op59UNHANDLED, + &v60_device::op59UNHANDLED, + &v60_device::op59UNHANDLED, + &v60_device::opCVTDPZ, + &v60_device::op59UNHANDLED, + &v60_device::op59UNHANDLED, + &v60_device::op59UNHANDLED, + &v60_device::op59UNHANDLED, + &v60_device::op59UNHANDLED, + &v60_device::op59UNHANDLED, + &v60_device::op59UNHANDLED, + &v60_device::opCVTDZP, + &v60_device::op59UNHANDLED, + &v60_device::op59UNHANDLED, + &v60_device::op59UNHANDLED, + &v60_device::op59UNHANDLED, + &v60_device::op59UNHANDLED, + &v60_device::op59UNHANDLED, + &v60_device::op59UNHANDLED +}; + + +const v60_device::am_func v60_device::s_Op5BTable[32] = +{ + &v60_device::opSCH0BSU, + &v60_device::op5BUNHANDLED, + &v60_device::opSCH1BSU, + &v60_device::op5BUNHANDLED, + &v60_device::op5BUNHANDLED, + &v60_device::op5BUNHANDLED, + &v60_device::op5BUNHANDLED, + &v60_device::op5BUNHANDLED, + &v60_device::opMOVBSU, + &v60_device::opMOVBSD, + &v60_device::op5BUNHANDLED, + &v60_device::op5BUNHANDLED, + &v60_device::op5BUNHANDLED, + &v60_device::op5BUNHANDLED, + &v60_device::op5BUNHANDLED, + &v60_device::op5BUNHANDLED, + &v60_device::op5BUNHANDLED, + &v60_device::op5BUNHANDLED, + &v60_device::op5BUNHANDLED, + &v60_device::op5BUNHANDLED, + &v60_device::op5BUNHANDLED, + &v60_device::op5BUNHANDLED, + &v60_device::op5BUNHANDLED, + &v60_device::op5BUNHANDLED, + &v60_device::op5BUNHANDLED, + &v60_device::op5BUNHANDLED, + &v60_device::op5BUNHANDLED, + &v60_device::op5BUNHANDLED, + &v60_device::op5BUNHANDLED, + &v60_device::op5BUNHANDLED, + &v60_device::op5BUNHANDLED, + &v60_device::op5BUNHANDLED +}; + + +const v60_device::am_func v60_device::s_Op5DTable[32] = +{ + &v60_device::op5DUNHANDLED, + &v60_device::op5DUNHANDLED, + &v60_device::op5DUNHANDLED, + &v60_device::op5DUNHANDLED, + &v60_device::op5DUNHANDLED, + &v60_device::op5DUNHANDLED, + &v60_device::op5DUNHANDLED, + &v60_device::op5DUNHANDLED, + &v60_device::opEXTBFS, + &v60_device::opEXTBFZ, + &v60_device::opEXTBFL, + &v60_device::op5DUNHANDLED, + &v60_device::op5DUNHANDLED, + &v60_device::op5DUNHANDLED, + &v60_device::op5DUNHANDLED, + &v60_device::op5DUNHANDLED, + &v60_device::op5DUNHANDLED, + &v60_device::op5DUNHANDLED, + &v60_device::op5DUNHANDLED, + &v60_device::op5DUNHANDLED, + &v60_device::op5DUNHANDLED, + &v60_device::op5DUNHANDLED, + &v60_device::op5DUNHANDLED, + &v60_device::op5DUNHANDLED, + &v60_device::opINSBFR, + &v60_device::opINSBFL, + &v60_device::op5DUNHANDLED, + &v60_device::op5DUNHANDLED, + &v60_device::op5DUNHANDLED, + &v60_device::op5DUNHANDLED, + &v60_device::op5DUNHANDLED, + &v60_device::op5DUNHANDLED +}; + +const v60_device::am_func v60_device::s_Op58Table[32] = +{ + &v60_device::opCMPCB, + &v60_device::opCMPCFB, + &v60_device::opCMPCSB, + &v60_device::op58UNHANDLED, + &v60_device::op58UNHANDLED, + &v60_device::op58UNHANDLED, + &v60_device::op58UNHANDLED, + &v60_device::op58UNHANDLED, + &v60_device::opMOVCUB, + &v60_device::opMOVCDB, + &v60_device::opMOVCFUB, + &v60_device::opMOVCFDB, + &v60_device::opMOVCSUB, + &v60_device::op58UNHANDLED, + &v60_device::op58UNHANDLED, + &v60_device::op58UNHANDLED, + &v60_device::op58UNHANDLED, + &v60_device::op58UNHANDLED, + &v60_device::op58UNHANDLED, + &v60_device::op58UNHANDLED, + &v60_device::op58UNHANDLED, + &v60_device::op58UNHANDLED, + &v60_device::op58UNHANDLED, + &v60_device::op58UNHANDLED, + &v60_device::opSCHCUB, + &v60_device::opSCHCDB, + &v60_device::opSKPCUB, + &v60_device::opSKPCDB, + &v60_device::op58UNHANDLED, + &v60_device::op58UNHANDLED, + &v60_device::op58UNHANDLED, + &v60_device::op58UNHANDLED +}; + +const v60_device::am_func v60_device::s_Op5ATable[32] = +{ + &v60_device::opCMPCH, + &v60_device::opCMPCFH, + &v60_device::opCMPCSH, + &v60_device::op5AUNHANDLED, + &v60_device::op5AUNHANDLED, + &v60_device::op5AUNHANDLED, + &v60_device::op5AUNHANDLED, + &v60_device::op5AUNHANDLED, + &v60_device::opMOVCUH, + &v60_device::opMOVCDH, + &v60_device::opMOVCFUH, + &v60_device::opMOVCFDH, + &v60_device::opMOVCSUH, + &v60_device::op5AUNHANDLED, + &v60_device::op5AUNHANDLED, + &v60_device::op5AUNHANDLED, + &v60_device::op5AUNHANDLED, + &v60_device::op5AUNHANDLED, + &v60_device::op5AUNHANDLED, + &v60_device::op5AUNHANDLED, + &v60_device::op5AUNHANDLED, + &v60_device::op5AUNHANDLED, + &v60_device::op5AUNHANDLED, + &v60_device::op5AUNHANDLED, + &v60_device::opSCHCUH, + &v60_device::opSCHCDH, + &v60_device::opSKPCUH, + &v60_device::opSKPCDH, + &v60_device::op5AUNHANDLED, + &v60_device::op5AUNHANDLED, + &v60_device::op5AUNHANDLED, + &v60_device::op5AUNHANDLED +}; + +UINT32 v60_device::op58() +{ + m_subop = OpRead8(PC + 1); + + return (this->*s_Op58Table[m_subop & 0x1F])(); +} + +UINT32 v60_device::op5A() +{ + m_subop = OpRead8(PC + 1); + + return (this->*s_Op5ATable[m_subop & 0x1F])(); +} + +UINT32 v60_device::op5B() +{ + m_subop = OpRead8(PC + 1); + + return (this->*s_Op5BTable[m_subop & 0x1F])(); +} + +UINT32 v60_device::op5D() +{ + m_subop = OpRead8(PC + 1); + + return (this->*s_Op5DTable[m_subop & 0x1F])(); +} + +UINT32 v60_device::op59() +{ + m_subop = OpRead8(PC + 1); + + return (this->*s_Op59Table[m_subop & 0x1F])(); +} diff --git a/src/devices/cpu/v60/optable.inc b/src/devices/cpu/v60/optable.inc new file mode 100644 index 00000000000..87de19686bc --- /dev/null +++ b/src/devices/cpu/v60/optable.inc @@ -0,0 +1,261 @@ +// license:BSD-3-Clause +// copyright-holders:Farfetch'd, R. Belmont +const v60_device::am_func v60_device::s_OpCodeTable[256] = +{ + /* 0x00 */ &v60_device::opHALT, + /* 0x01 */ &v60_device::opLDTASK, + /* 0x02 */ &v60_device::opSTPR, + /* 0x03 */ &v60_device::opUNHANDLED, + /* 0x04 */ &v60_device::opUNHANDLED, + /* 0x05 */ &v60_device::opUNHANDLED, + /* 0x06 */ &v60_device::opUNHANDLED, + /* 0x07 */ &v60_device::opUNHANDLED, + /* 0x08 */ &v60_device::opRVBIT, + /* 0x09 */ &v60_device::opMOVB, + /* 0x0a */ &v60_device::opMOVSBH, + /* 0x0b */ &v60_device::opMOVZBH, + /* 0x0c */ &v60_device::opMOVSBW, + /* 0x0d */ &v60_device::opMOVZBW, + /* 0x0e */ &v60_device::opUNHANDLED, + /* 0x0f */ &v60_device::opUNHANDLED, + /* 0x10 */ &v60_device::opCLRTLBA, + /* 0x11 */ &v60_device::opUNHANDLED, + /* 0x12 */ &v60_device::opLDPR, + /* 0x13 */ &v60_device::opUPDPSWW, + /* 0x14 */ &v60_device::opUNHANDLED, + /* 0x15 */ &v60_device::opUNHANDLED, + /* 0x16 */ &v60_device::opUNHANDLED, + /* 0x17 */ &v60_device::opUNHANDLED, + /* 0x18 */ &v60_device::opUNHANDLED, + /* 0x19 */ &v60_device::opMOVTHB, + /* 0x1a */ &v60_device::opUNHANDLED, + /* 0x1b */ &v60_device::opMOVH, + /* 0x1c */ &v60_device::opMOVSHW, + /* 0x1d */ &v60_device::opMOVZHW, + /* 0x1e */ &v60_device::opUNHANDLED, + /* 0x1f */ &v60_device::opUNHANDLED, + /* 0x20 */ &v60_device::opINB, + /* 0x21 */ &v60_device::opOUTB, + /* 0x22 */ &v60_device::opINH, + /* 0x23 */ &v60_device::opOUTH, + /* 0x24 */ &v60_device::opINW, + /* 0x25 */ &v60_device::opOUTW, + /* 0x26 */ &v60_device::opUNHANDLED, + /* 0x27 */ &v60_device::opUNHANDLED, + /* 0x28 */ &v60_device::opUNHANDLED, + /* 0x29 */ &v60_device::opMOVTWB, + /* 0x2a */ &v60_device::opUNHANDLED, + /* 0x2b */ &v60_device::opMOVTWH, + /* 0x2c */ &v60_device::opRVBYT, + /* 0x2d */ &v60_device::opMOVW, + /* 0x2e */ &v60_device::opUNHANDLED, + /* 0x2f */ &v60_device::opUNHANDLED, + /* 0x30 */ &v60_device::opUNHANDLED, + /* 0x31 */ &v60_device::opUNHANDLED, + /* 0x32 */ &v60_device::opUNHANDLED, + /* 0x33 */ &v60_device::opUNHANDLED, + /* 0x34 */ &v60_device::opUNHANDLED, + /* 0x35 */ &v60_device::opUNHANDLED, + /* 0x36 */ &v60_device::opUNHANDLED, + /* 0x37 */ &v60_device::opUNHANDLED, + /* 0x38 */ &v60_device::opNOTB, + /* 0x39 */ &v60_device::opNEGB, + /* 0x3a */ &v60_device::opNOTH, + /* 0x3b */ &v60_device::opNEGH, + /* 0x3c */ &v60_device::opNOTW, + /* 0x3d */ &v60_device::opNEGW, + /* 0x3e */ &v60_device::opUNHANDLED, + /* 0x3f */ &v60_device::opMOVD, + /* 0x40 */ &v60_device::opMOVEAB, + /* 0x41 */ &v60_device::opXCHB, + /* 0x42 */ &v60_device::opMOVEAH, + /* 0x43 */ &v60_device::opXCHH, + /* 0x44 */ &v60_device::opMOVEAW, + /* 0x45 */ &v60_device::opXCHW, + /* 0x46 */ &v60_device::opUNHANDLED, + /* 0x47 */ &v60_device::opSETF, + /* 0x48 */ &v60_device::opBSR, + /* 0x49 */ &v60_device::opCALL, + /* 0x4a */ &v60_device::opUPDPSWH, + /* 0x4b */ &v60_device::opCHLVL, + /* 0x4c */ &v60_device::opUNHANDLED, + /* 0x4d */ &v60_device::opCHKAR, + /* 0x4e */ &v60_device::opCHKAW, + /* 0x4f */ &v60_device::opCHKAE, + /* 0x50 */ &v60_device::opREMB, + /* 0x51 */ &v60_device::opREMUB, + /* 0x52 */ &v60_device::opREMH, + /* 0x53 */ &v60_device::opREMUH, + /* 0x54 */ &v60_device::opREMW, + /* 0x55 */ &v60_device::opREMUW, + /* 0x56 */ &v60_device::opUNHANDLED, + /* 0x57 */ &v60_device::opUNHANDLED, + /* 0x58 */ &v60_device::op58, + /* 0x59 */ &v60_device::op59, + /* 0x5a */ &v60_device::op5A, + /* 0x5b */ &v60_device::op5B, + /* 0x5c */ &v60_device::op5C, + /* 0x5d */ &v60_device::op5D, + /* 0x5e */ &v60_device::opUNHANDLED, + /* 0x5f */ &v60_device::op5F, + /* 0x60 */ &v60_device::opBV8, + /* 0x61 */ &v60_device::opBNV8, + /* 0x62 */ &v60_device::opBL8, + /* 0x63 */ &v60_device::opBNL8, + /* 0x64 */ &v60_device::opBE8, + /* 0x65 */ &v60_device::opBNE8, + /* 0x66 */ &v60_device::opBNH8, + /* 0x67 */ &v60_device::opBH8, + /* 0x68 */ &v60_device::opBN8, + /* 0x69 */ &v60_device::opBP8, + /* 0x6a */ &v60_device::opBR8, + /* 0x6b */ &v60_device::opUNHANDLED, + /* 0x6C */ &v60_device::opBLT8, + /* 0x6c */ &v60_device::opBGE8, + /* 0x6e */ &v60_device::opBLE8, + /* 0x6f */ &v60_device::opBGT8, + /* 0x70 */ &v60_device::opBV16, + /* 0x71 */ &v60_device::opBNV16, + /* 0x72 */ &v60_device::opBL16, + /* 0x73 */ &v60_device::opBNL16, + /* 0x74 */ &v60_device::opBE16, + /* 0x75 */ &v60_device::opBNE16, + /* 0x76 */ &v60_device::opBNH16, + /* 0x77 */ &v60_device::opBH16, + /* 0x78 */ &v60_device::opBN16, + /* 0x79 */ &v60_device::opBP16, + /* 0x7a */ &v60_device::opBR16, + /* 0x7b */ &v60_device::opUNHANDLED, + /* 0x7c */ &v60_device::opBLT16, + /* 0x7d */ &v60_device::opBGE16, + /* 0x7e */ &v60_device::opBLE16, + /* 0x7f */ &v60_device::opBGT16, + /* 0x80 */ &v60_device::opADDB, + /* 0x81 */ &v60_device::opMULB, + /* 0x82 */ &v60_device::opADDH, + /* 0x83 */ &v60_device::opMULH, + /* 0x84 */ &v60_device::opADDW, + /* 0x85 */ &v60_device::opMULW, + /* 0x86 */ &v60_device::opMULX, + /* 0x87 */ &v60_device::opTEST1, + /* 0x88 */ &v60_device::opORB, + /* 0x89 */ &v60_device::opROTB, + /* 0x8a */ &v60_device::opORH, + /* 0x8b */ &v60_device::opROTH, + /* 0x8c */ &v60_device::opORW, + /* 0x8d */ &v60_device::opROTW, + /* 0x8e */ &v60_device::opUNHANDLED, + /* 0x8f */ &v60_device::opUNHANDLED, + /* 0x90 */ &v60_device::opADDCB, + /* 0x91 */ &v60_device::opMULUB, + /* 0x92 */ &v60_device::opADDCH, + /* 0x93 */ &v60_device::opMULUH, + /* 0x94 */ &v60_device::opADDCW, + /* 0x95 */ &v60_device::opMULUW, + /* 0x96 */ &v60_device::opMULUX, + /* 0x97 */ &v60_device::opSET1, + /* 0x98 */ &v60_device::opSUBCB, + /* 0x99 */ &v60_device::opROTCB, + /* 0x9a */ &v60_device::opSUBCH, + /* 0x9b */ &v60_device::opROTCH, + /* 0x9c */ &v60_device::opSUBCW, + /* 0x9d */ &v60_device::opROTCW, + /* 0x9e */ &v60_device::opUNHANDLED, + /* 0x9f */ &v60_device::opUNHANDLED, + /* 0xa0 */ &v60_device::opANDB, + /* 0xa1 */ &v60_device::opDIVB, + /* 0xa2 */ &v60_device::opANDH, + /* 0xa3 */ &v60_device::opDIVH, + /* 0xa4 */ &v60_device::opANDW, + /* 0xa5 */ &v60_device::opDIVW, + /* 0xa6 */ &v60_device::opDIVX, + /* 0xa7 */ &v60_device::opCLR1, + /* 0xa8 */ &v60_device::opSUBB, + /* 0xa9 */ &v60_device::opSHLB, + /* 0xaa */ &v60_device::opSUBH, + /* 0xab */ &v60_device::opSHLH, + /* 0xac */ &v60_device::opSUBW, + /* 0xad */ &v60_device::opSHLW, + /* 0xae */ &v60_device::opUNHANDLED, + /* 0xaf */ &v60_device::opUNHANDLED, + /* 0xb0 */ &v60_device::opXORB, + /* 0xb1 */ &v60_device::opDIVUB, + /* 0xb2 */ &v60_device::opXORH, + /* 0xb3 */ &v60_device::opDIVUH, + /* 0xb4 */ &v60_device::opXORW, + /* 0xb5 */ &v60_device::opDIVUW, + /* 0xb6 */ &v60_device::opDIVUX, + /* 0xb7 */ &v60_device::opNOT1, + /* 0xb8 */ &v60_device::opCMPB, + /* 0xb9 */ &v60_device::opSHAB, + /* 0xba */ &v60_device::opCMPH, + /* 0xbb */ &v60_device::opSHAH, + /* 0xbc */ &v60_device::opCMPW, + /* 0xbd */ &v60_device::opSHAW, + /* 0xbe */ &v60_device::opUNHANDLED, + /* 0xbf */ &v60_device::opUNHANDLED, + /* 0xc0 */ &v60_device::opUNHANDLED, + /* 0xc1 */ &v60_device::opUNHANDLED, + /* 0xc2 */ &v60_device::opUNHANDLED, + /* 0xc3 */ &v60_device::opUNHANDLED, + /* 0xc4 */ &v60_device::opUNHANDLED, + /* 0xc5 */ &v60_device::opUNHANDLED, + /* 0xc6 */ &v60_device::opC6, + /* 0xc7 */ &v60_device::opC7, + /* 0xc8 */ &v60_device::opBRK, + /* 0xc9 */ &v60_device::opBRKV, + /* 0xca */ &v60_device::opRSR, + /* 0xcb */ &v60_device::opTRAPFL, + /* 0xcc */ &v60_device::opDISPOSE, + /* 0xcd */ &v60_device::opNOP, + /* 0xce */ &v60_device::opUNHANDLED, + /* 0xcf */ &v60_device::opUNHANDLED, + /* 0xd0 */ &v60_device::opDECB_0, + /* 0xd1 */ &v60_device::opDECB_1, + /* 0xd2 */ &v60_device::opDECH_0, + /* 0xd3 */ &v60_device::opDECH_1, + /* 0xd4 */ &v60_device::opDECW_0, + /* 0xd5 */ &v60_device::opDECW_1, + /* 0xd6 */ &v60_device::opJMP_0, + /* 0xd7 */ &v60_device::opJMP_1, + /* 0xd8 */ &v60_device::opINCB_0, + /* 0xd9 */ &v60_device::opINCB_1, + /* 0xda */ &v60_device::opINCH_0, + /* 0xdb */ &v60_device::opINCH_1, + /* 0xdc */ &v60_device::opINCW_0, + /* 0xdd */ &v60_device::opINCW_1, + /* 0xde */ &v60_device::opPREPARE_0, + /* 0xdf */ &v60_device::opPREPARE_1, + /* 0xe0 */ &v60_device::opTASI_0, + /* 0xe1 */ &v60_device::opTASI_1, + /* 0xe2 */ &v60_device::opRET_0, + /* 0xe3 */ &v60_device::opRET_1, + /* 0xe4 */ &v60_device::opPOPM_0, + /* 0xe5 */ &v60_device::opPOPM_1, + /* 0xe6 */ &v60_device::opPOP_0, + /* 0xe7 */ &v60_device::opPOP_1, + /* 0xe8 */ &v60_device::opJSR_0, + /* 0xe9 */ &v60_device::opJSR_1, + /* 0xea */ &v60_device::opRETIU_0, + /* 0xeb */ &v60_device::opRETIU_1, + /* 0xec */ &v60_device::opPUSHM_0, + /* 0xed */ &v60_device::opPUSHM_1, + /* 0xee */ &v60_device::opPUSH_0, + /* 0xef */ &v60_device::opPUSH_1, + /* 0xf0 */ &v60_device::opTESTB_0, + /* 0xf1 */ &v60_device::opTESTB_1, + /* 0xf2 */ &v60_device::opTESTH_0, + /* 0xf3 */ &v60_device::opTESTH_1, + /* 0xf4 */ &v60_device::opTESTW_0, + /* 0xf5 */ &v60_device::opTESTW_1, + /* 0xf6 */ &v60_device::opGETPSW_0, + /* 0xf7 */ &v60_device::opGETPSW_1, + /* 0xf8 */ &v60_device::opTRAP_0, + /* 0xf9 */ &v60_device::opTRAP_1, + /* 0xfa */ &v60_device::opRETIS_0, + /* 0xfb */ &v60_device::opRETIS_1, + /* 0xfc */ &v60_device::opSTTASK_0, + /* 0xfd */ &v60_device::opSTTASK_1, + /* 0xfe */ &v60_device::opCLRTLB_0, + /* 0xff */ &v60_device::opCLRTLB_1, +}; diff --git a/src/devices/cpu/v60/v60.c b/src/devices/cpu/v60/v60.c new file mode 100644 index 00000000000..2a770739e25 --- /dev/null +++ b/src/devices/cpu/v60/v60.c @@ -0,0 +1,619 @@ +// license:BSD-3-Clause +// copyright-holders:Farfetch'd, R. Belmont +// V60.C +// Undiscover the beast! +// Main hacking and coding by Farfetch'd +// Portability fixes by R. Belmont +// +// Emulation for the NEC V60 (uPD70615) and V70 (uPD70632) CPUs +// + +/* +Taken from the NEC Semiconductor Selection Guide Guide Book (Oct. 1995): + +uPD70615 (V60) +Features: +- Virtual memory (paging method) +- Level protection architecture - 4-level hierarchical protection function + for system multi-programming. +- Abundant general registers - Thirty two 32-bit general registers for + optimizing compiler +- Refined instruction set - 2-address method: Arbitrary addressing mode + can be used independently for source operand and destination operand. +- Abundant address modes and data types - Auto increment/decrement mode + for string process, and memory indirect addressing for pointer operation +- High cost-to performance chip +- No multiprocessor system - no FRM function for increasing system + reliability using two or more processors. +- No V20/V30 simulation mode +Address bus: 24 bits +Data bus: 16 bits +Memory space: 4G bytes +Operating frequency: 16 MHz +Package: 120-pin QFP + +uPD70616 (V60) +Features: +- Virtual memory (paging method) +- Level protection architecture - 4-level hierarchical protection function + for system multi-programming. +- Abundant general registers - Thirty two 32-bit general registers for + optimizing compiler +- Refined instruction set - 2-address method: Arbitrary addressing mode + can be used independently for source operand and destination operand. +- Abundant address modes and data types - Auto increment/decrement mode + for string process, and memory indirect addressing for pointer operation +- Multiprocessor system - FRM function for increasing system reliability + using two or more processors. +- V20/V30 simulation mode +Address bus: 24 bits +Data bus: 16 bits +Memory space: 4G bytes +Operating frequency: 16 MHz +Package: 68-pin PGA + +uPD70632 (V70) +Features: +- Virtual memory (paging method) +- Level protection architecture - 4-level hierarchical protection function + for system multi-programming. +- Abundant general registers - Thirty two 32-bit general registers for + optimizing compiler +- Refined instruction set - 2-address method: Arbitrary addressing mode + can be used independently for source operand and destination operand. +- Abundant address modes and data types - Auto increment/decrement mode + for string process, and memory indirect addressing for pointer operation +- Multiprocessor system - FRM function for increasing system reliability + using two or more processors. +- V20/V30 simulation mode +Address bus: 32 bits +Data bus: 32 bits +Memory space: 4G bytes +Operating frequency: 20 MHz +Package: 132-pin PGA, 200-pin QFP +*/ + +#include "emu.h" +#include "debugger.h" +#include "v60.h" + +const device_type V60 = &device_creator; +const device_type V70 = &device_creator; + + +v60_device::v60_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : cpu_device(mconfig, V60, "V60", tag, owner, clock, "v60", __FILE__) + , m_program_config("program", ENDIANNESS_LITTLE, 16, 24, 0) + , m_io_config("io", ENDIANNESS_LITTLE, 16, 24, 0) + , m_fetch_xor(BYTE_XOR_LE(0)) + , m_start_pc(0xfffff0) +{ + // Set m_PIR (Processor ID) for NEC m_ LSB is reserved to NEC, + // so I don't know what it contains. + m_reg[45] = 0x00006000; +} + + +v60_device::v60_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : cpu_device(mconfig, type, name, tag, owner, clock, shortname, source) + , m_program_config("program", ENDIANNESS_LITTLE, 32, 32, 0) + , m_io_config("io", ENDIANNESS_LITTLE, 16, 24, 0) + , m_fetch_xor(BYTE4_XOR_LE(0)) + , m_start_pc(0xfffffff0) +{ + // Set m_PIR (Processor ID) for NEC v70. LSB is reserved to NEC, + // so I don't know what it contains. + m_reg[45] = 0x00007000; +} + +v70_device::v70_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : v60_device(mconfig, V70, "V70", tag, owner, clock, "v70", __FILE__) +{ +} + + +offs_t v60_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( v60 ); + return CPU_DISASSEMBLE_NAME(v60)(this, buffer, pc, oprom, opram, options); +} + + +offs_t v70_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( v70 ); + return CPU_DISASSEMBLE_NAME(v70)(this, buffer, pc, oprom, opram, options); +} + + +// memory accessors +#if defined(LSB_FIRST) && !defined(ALIGN_INTS) +#define OpRead8(a) (m_direct->read_byte(a)) +#define OpRead16(a) (m_direct->read_word(a)) +#define OpRead32(a) (m_direct->read_dword(a)) +#else +#define OpRead8(a) (m_direct->read_byte((a), m_fetch_xor)) +#define OpRead16(a) ((m_direct->read_byte(((a)+0), m_fetch_xor) << 0) | \ + (m_direct->read_byte(((a)+1), m_fetch_xor) << 8)) +#define OpRead32(a) ((m_direct->read_byte(((a)+0), m_fetch_xor) << 0) | \ + (m_direct->read_byte(((a)+1), m_fetch_xor) << 8) | \ + (m_direct->read_byte(((a)+2), m_fetch_xor) << 16) | \ + (m_direct->read_byte(((a)+3), m_fetch_xor) << 24)) +#endif + + +// macros stolen from MAME for flags calc +// note that these types are in x86 naming: +// byte = 8 bit, word = 16 bit, long = 32 bit + +// parameter x = result, y = source 1, z = source 2 + +#define SetOFL_Add(x, y,z) (_OV = (((x) ^ (y)) & ((x) ^ (z)) & 0x80000000) ? 1: 0) +#define SetOFW_Add(x, y,z) (_OV = (((x) ^ (y)) & ((x) ^ (z)) & 0x8000) ? 1 : 0) +#define SetOFB_Add(x, y,z) (_OV = (((x) ^ (y)) & ((x) ^ (z)) & 0x80) ? 1 : 0) + +#define SetOFL_Sub(x, y,z) (_OV = (((z) ^ (y)) & ((z) ^ (x)) & 0x80000000) ? 1 : 0) +#define SetOFW_Sub(x, y,z) (_OV = (((z) ^ (y)) & ((z) ^ (x)) & 0x8000) ? 1 : 0) +#define SetOFB_Sub(x, y,z) (_OV = (((z) ^ (y)) & ((z) ^ (x)) & 0x80) ? 1 : 0) + +#define SetCFB(x) {_CY = ((x) & 0x100) ? 1 : 0; } +#define SetCFW(x) {_CY = ((x) & 0x10000) ? 1 : 0; } +#define SetCFL(x) {_CY = ((x) & (((UINT64)1) << 32)) ? 1 : 0; } + +#define SetSF(x) (_S = (x)) +#define SetZF(x) (_Z = (x)) + +#define SetSZPF_Byte(x) {_Z = ((UINT8)(x) == 0); _S = ((x)&0x80) ? 1 : 0; } +#define SetSZPF_Word(x) {_Z = ((UINT16)(x) == 0); _S = ((x)&0x8000) ? 1 : 0; } +#define SetSZPF_Long(x) {_Z = ((UINT32)(x) == 0); _S = ((x)&0x80000000) ? 1 : 0; } + +#define ORB(dst, src) { (dst) |= (src); _CY = _OV = 0; SetSZPF_Byte(dst); } +#define ORW(dst, src) { (dst) |= (src); _CY = _OV = 0; SetSZPF_Word(dst); } +#define ORL(dst, src) { (dst) |= (src); _CY = _OV = 0; SetSZPF_Long(dst); } + +#define ANDB(dst, src) { (dst) &= (src); _CY = _OV = 0; SetSZPF_Byte(dst); } +#define ANDW(dst, src) { (dst) &= (src); _CY = _OV = 0; SetSZPF_Word(dst); } +#define ANDL(dst, src) { (dst) &= (src); _CY = _OV = 0; SetSZPF_Long(dst); } + +#define XORB(dst, src) { (dst) ^= (src); _CY = _OV = 0; SetSZPF_Byte(dst); } +#define XORW(dst, src) { (dst) ^= (src); _CY = _OV = 0; SetSZPF_Word(dst); } +#define XORL(dst, src) { (dst) ^= (src); _CY = _OV = 0; SetSZPF_Long(dst); } + +#define SUBB(dst, src) { unsigned res = (dst) - (src); SetCFB(res); SetOFB_Sub(res, src, dst); SetSZPF_Byte(res); dst = (UINT8)res; } +#define SUBW(dst, src) { unsigned res = (dst) - (src); SetCFW(res); SetOFW_Sub(res, src, dst); SetSZPF_Word(res); dst = (UINT16)res; } +#define SUBL(dst, src) { UINT64 res = (UINT64)(dst) - (INT64)(src); SetCFL(res); SetOFL_Sub(res, src, dst); SetSZPF_Long(res); dst = (UINT32)res; } + +#define ADDB(dst, src) { unsigned res = (dst) + (src); SetCFB(res); SetOFB_Add(res, src, dst); SetSZPF_Byte(res); dst = (UINT8)res; } +#define ADDW(dst, src) { unsigned res = (dst) + (src); SetCFW(res); SetOFW_Add(res, src, dst); SetSZPF_Word(res); dst = (UINT16)res; } +#define ADDL(dst, src) { UINT64 res = (UINT64)(dst) + (UINT64)(src); SetCFL(res); SetOFL_Add(res, src, dst); SetSZPF_Long(res); dst = (UINT32)res; } + +#define SETREG8(a, b) (a) = ((a) & ~0xff) | ((b) & 0xff) +#define SETREG16(a, b) (a) = ((a) & ~0xffff) | ((b) & 0xffff) + + +/* + * Prevent warnings on NetBSD. All identifiers beginning with an underscore + * followed by an uppercase letter are reserved by the C standard (ISO / IEC + * 9899:1999, 7.1.3) to be used by the implementation. It'd be best to rename + * all such instances, but this is less intrusive and error-prone. + */ +#undef _S + +#define _CY m_flags.CY +#define _OV m_flags.OV +#define _S m_flags.S +#define _Z m_flags.Z + + +// Defines of all v60 register... +#define R0 m_reg[0] +#define R1 m_reg[1] +#define R2 m_reg[2] +#define R3 m_reg[3] +#define R4 m_reg[4] +#define R5 m_reg[5] +#define R6 m_reg[6] +#define R7 m_reg[7] +#define R8 m_reg[8] +#define R9 m_reg[9] +#define R10 m_reg[10] +#define R11 m_reg[11] +#define R12 m_reg[12] +#define R13 m_reg[13] +#define R14 m_reg[14] +#define R15 m_reg[15] +#define R16 m_reg[16] +#define R17 m_reg[17] +#define R18 m_reg[18] +#define R19 m_reg[19] +#define R20 m_reg[20] +#define R21 m_reg[21] +#define R22 m_reg[22] +#define R23 m_reg[23] +#define R24 m_reg[24] +#define R25 m_reg[25] +#define R26 m_reg[26] +#define R27 m_reg[27] +#define R28 m_reg[28] +#define AP m_reg[29] +#define FP m_reg[30] +#define SP m_reg[31] + +#define PC m_reg[32] +#define PSW m_reg[33] + +// Privileged registers +#define ISP m_reg[36] +#define L0SP m_reg[37] +#define L1SP m_reg[38] +#define L2SP m_reg[39] +#define L3SP m_reg[40] +#define SBR m_reg[41] +#define TR m_reg[42] +#define SYCW m_reg[43] +#define TKCW m_reg[44] +#define PIR m_reg[45] +//10-14 reserved +#define PSW2 m_reg[51] +#define ATBR0 m_reg[52] +#define ATLR0 m_reg[53] +#define ATBR1 m_reg[54] +#define ATLR1 m_reg[55] +#define ATBR2 m_reg[56] +#define ATLR2 m_reg[57] +#define ATBR3 m_reg[58] +#define ATLR3 m_reg[59] +#define TRMODE m_reg[60] +#define ADTR0 m_reg[61] +#define ADTR1 m_reg[62] +#define ADTMR0 m_reg[63] +#define ADTMR1 m_reg[64] +//29-31 reserved + +// Defines... +#define NORMALIZEFLAGS() \ +{ \ + _S = _S ? 1 : 0; \ + _OV = _OV ? 1 : 0; \ + _Z = _Z ? 1 : 0; \ + _CY = _CY ? 1 : 0; \ +} + + +void v60_device::v60SaveStack() +{ + if (PSW & 0x10000000) + ISP = SP; + else + m_reg[37 + ((PSW >> 24) & 3)] = SP; +} + +void v60_device::v60ReloadStack() +{ + if (PSW & 0x10000000) + SP = ISP; + else + SP = m_reg[37 + ((PSW >> 24) & 3)]; +} + +UINT32 v60_device::v60ReadPSW() +{ + PSW &= 0xfffffff0; + PSW |= (_Z?1:0) | (_S?2:0) | (_OV?4:0) | (_CY?8:0); + return PSW; +} + +void v60_device::v60WritePSW(UINT32 newval) +{ + /* determine if we need to save / restore the stacks */ + int updateStack = 0; + + /* if the interrupt state is changing, we definitely need to update */ + if ((newval ^ PSW) & 0x10000000) + updateStack = 1; + + /* if we are not in interrupt mode and the level is changing, we also must update */ + else if (!(PSW & 0x10000000) && ((newval ^ PSW) & 0x03000000)) + updateStack = 1; + + /* save the previous stack value */ + if (updateStack) + v60SaveStack(); + + /* set the new value and update the flags */ + PSW = newval; + _Z = (UINT8)(PSW & 1); + _S = (UINT8)(PSW & 2); + _OV = (UINT8)(PSW & 4); + _CY = (UINT8)(PSW & 8); + + /* fetch the new stack value */ + if (updateStack) + v60ReloadStack(); +} + + +UINT32 v60_device::v60_update_psw_for_exception(int is_interrupt, int target_level) +{ + UINT32 oldPSW = v60ReadPSW(); + UINT32 newPSW = oldPSW; + + // Change to interrupt context + newPSW &= ~(3 << 24); // PSW.EL = 0 + newPSW |= target_level << 24; // set target level + newPSW &= ~(1 << 18); // PSW.IE = 0 + newPSW &= ~(1 << 16); // PSW.TE = 0 + newPSW &= ~(1 << 27); // PSW.TP = 0 + newPSW &= ~(1 << 17); // PSW.AE = 0 + newPSW &= ~(1 << 29); // PSW.EM = 0 + if (is_interrupt) + newPSW |= (1 << 28);// PSW.IS = 1 + newPSW |= (1 << 31); // PSW.ASA = 1 + v60WritePSW(newPSW); + + return oldPSW; +} + + +#define GETINTVECT(nint) m_program->read_dword((SBR & ~0xfff) + (nint) * 4) +#define EXCEPTION_CODE_AND_SIZE(code, size) (((code) << 16) | (size)) + + +// Addressing mode decoding functions +#include "am.inc" + +// Opcode functions +#include "op12.inc" +#include "op2.inc" +#include "op3.inc" +#include "op4.inc" +#include "op5.inc" +#include "op6.inc" +#include "op7a.inc" + +UINT32 v60_device::opUNHANDLED() +{ + fatalerror("Unhandled OpCode found : %02x at %08x\n", OpRead16(PC), PC); + //return 0; /* never reached, fatalerror won't return */ +} + +// Opcode jump table +#include "optable.inc" + +void v60_device::device_start() +{ + m_stall_io = 0; + m_irq_line = CLEAR_LINE; + m_nmi_line = CLEAR_LINE; + + for ( int i = 0; i < 68; i++ ) + { + // Don't set SP (31), PCi (32), PSW (33), SBR (41), SYCW (43), TKCW (44), PIR (45), PSW2 (51) + if ( i != 31 && i != 32 && i != 33 && i != 41 && i != 43 && i != 44 && i != 45 && i != 51 ) + { + m_reg[i] = 0; + } + } + + m_flags.CY = 0; + m_flags.OV = 0; + m_flags.S = 0; + m_flags.Z = 0; + + m_op1 = 0; + m_op2 = 0; + m_flag1 = 0; + m_flag2 = 0; + m_instflags = 0; + m_lenop1 = 0; + m_lenop2 = 0; + m_subop = 0; + m_bamoffset1 = 0; + m_bamoffset2 = 0; + m_amflag = 0; + m_amout = 0; + m_bamoffset = 0; + m_amlength1 = 0; + m_amlength2 = 0; + m_modadd = 0; + m_modm = 0; + m_modval = 0; + m_modval2 = 0; + m_modwritevalb = 0; + m_modwritevalh = 0; + m_modwritevalw = 0; + m_moddim = 0; + + m_program = &space(AS_PROGRAM); + m_direct = &m_program->direct(); + m_io = &space(AS_IO); + + save_item(NAME(m_reg)); + save_item(NAME(m_irq_line)); + save_item(NAME(m_nmi_line)); + save_item(NAME(m_PPC)); + save_item(NAME(_CY)); + save_item(NAME(_OV)); + save_item(NAME(_S)); + save_item(NAME(_Z)); + + state_add( V60_R0, "R0", R0).formatstr("%08X"); + state_add( V60_R1, "R1", R1).formatstr("%08X"); + state_add( V60_R2, "R2", R2).formatstr("%08X"); + state_add( V60_R3, "R3", R3).formatstr("%08X"); + state_add( V60_R4, "R4", R4).formatstr("%08X"); + state_add( V60_R5, "R5", R5).formatstr("%08X"); + state_add( V60_R6, "R6", R6).formatstr("%08X"); + state_add( V60_R7, "R7", R7).formatstr("%08X"); + state_add( V60_R8, "R8", R8).formatstr("%08X"); + state_add( V60_R9, "R9", R9).formatstr("%08X"); + state_add( V60_R10, "R10", R10).formatstr("%08X"); + state_add( V60_R11, "R11", R11).formatstr("%08X"); + state_add( V60_R12, "R12", R12).formatstr("%08X"); + state_add( V60_R13, "R13", R13).formatstr("%08X"); + state_add( V60_R14, "R14", R14).formatstr("%08X"); + state_add( V60_R15, "R15", R15).formatstr("%08X"); + state_add( V60_R16, "R16", R16).formatstr("%08X"); + state_add( V60_R17, "R17", R17).formatstr("%08X"); + state_add( V60_R18, "R18", R18).formatstr("%08X"); + state_add( V60_R19, "R19", R19).formatstr("%08X"); + state_add( V60_R20, "R20", R20).formatstr("%08X"); + state_add( V60_R21, "R21", R21).formatstr("%08X"); + state_add( V60_R22, "R22", R22).formatstr("%08X"); + state_add( V60_R23, "R23", R23).formatstr("%08X"); + state_add( V60_R24, "R24", R24).formatstr("%08X"); + state_add( V60_R25, "R25", R25).formatstr("%08X"); + state_add( V60_R26, "R26", R26).formatstr("%08X"); + state_add( V60_R27, "R27", R27).formatstr("%08X"); + state_add( V60_R28, "R28", R28).formatstr("%08X"); + state_add( V60_AP, "AP", AP).formatstr("%08X"); + state_add( V60_FP, "FP", FP).formatstr("%08X"); + state_add( V60_SP, "SP", SP).formatstr("%08X"); + state_add( V60_PC, "PC", PC).formatstr("%08X"); + state_add( V60_PSW, "PSW", m_debugger_temp).callimport().callexport().formatstr("%08X"); + state_add( V60_ISP, "ISP", ISP).formatstr("%08X"); + state_add( V60_L0SP, "L0SP", L0SP).formatstr("%08X"); + state_add( V60_L1SP, "L1SP", L1SP).formatstr("%08X"); + state_add( V60_L2SP, "L2SP", L2SP).formatstr("%08X"); + state_add( V60_L3SP, "L3SP", L3SP).formatstr("%08X"); + state_add( V60_SBR, "SBR", SBR).formatstr("%08X"); + state_add( V60_TR, "TR", TR).formatstr("%08X"); + state_add( V60_SYCW, "SYCW", SYCW).formatstr("%08X"); + state_add( V60_TKCW, "TKCW", TKCW).formatstr("%08X"); + state_add( V60_PIR, "PIR", PIR).formatstr("%08X"); + state_add( V60_PSW2, "PSW2", PSW2).formatstr("%08X"); + state_add( V60_ATBR0, "ATBR0", ATBR0).formatstr("%08X"); + state_add( V60_ATLR0, "ATLR0", ATLR0).formatstr("%08X"); + state_add( V60_ATBR1, "ATBR1", ATBR1).formatstr("%08X"); + state_add( V60_ATLR1, "ATLR1", ATLR1).formatstr("%08X"); + state_add( V60_ATBR2, "ATBR2", ATBR2).formatstr("%08X"); + state_add( V60_ATLR2, "ATLR2", ATLR2).formatstr("%08X"); + state_add( V60_ATBR3, "ATBR3", ATBR3).formatstr("%08X"); + state_add( V60_ATLR3, "ATLR3", ATLR3).formatstr("%08X"); + state_add( V60_TRMODE, "TRMODE", TRMODE).formatstr("%08X"); + state_add( V60_ADTR0, "ADTR0", ADTR0).formatstr("%08X"); + state_add( V60_ADTR1, "ADTR1", ADTR1).formatstr("%08X"); + state_add( V60_ADTMR0, "ADTMR0", ADTMR0).formatstr("%08X"); + state_add( V60_ADTMR1, "ADTMR1", ADTMR1).formatstr("%08X"); + + state_add( STATE_GENPC, "GENPC", PC).noshow(); + state_add( STATE_GENPCBASE, "GENPCBASE", m_PPC ).noshow(); + state_add( STATE_GENSP, "GENSP", SP ).noshow(); + state_add( STATE_GENFLAGS, "GENFLAGS", m_debugger_temp).noshow(); + + m_icountptr = &m_icount; +} + + +void v60_device::state_export(const device_state_entry &entry) +{ + switch (entry.index()) + { + case V60_PSW: + m_debugger_temp = v60ReadPSW(); + break; + } +} + + +void v60_device::state_import(const device_state_entry &entry) +{ + switch (entry.index()) + { + case V60_PSW: + v60WritePSW( m_debugger_temp ); + break; + } +} + + +void v60_device::device_reset() +{ + PSW = 0x10000000; + PC = m_start_pc; + SBR = 0x00000000; + SYCW = 0x00000070; + TKCW = 0x0000e000; + PSW2 = 0x0000f002; + + _CY = 0; + _OV = 0; + _S = 0; + _Z = 0; +} + + +void v60_device::stall() +{ + m_stall_io = 1; +} + + +void v60_device::v60_do_irq(int vector) +{ + UINT32 oldPSW = v60_update_psw_for_exception(1, 0); + + // Push PC and PSW onto the stack + SP-=4; + m_program->write_dword_unaligned(SP, oldPSW); + SP-=4; + m_program->write_dword_unaligned(SP, PC); + + // Jump to vector for user interrupt + PC = GETINTVECT(vector); +} + +void v60_device::v60_try_irq() +{ + if(m_irq_line == CLEAR_LINE) + return; + if((PSW & (1 << 18)) != 0) { + int vector; + if(m_irq_line != ASSERT_LINE) + m_irq_line = CLEAR_LINE; + + vector = standard_irq_callback(0); + + v60_do_irq(vector + 0x40); + } +} + +void v60_device::execute_set_input(int irqline, int state) +{ + if(irqline == INPUT_LINE_NMI) { + switch(state) { + case ASSERT_LINE: + if(m_nmi_line == CLEAR_LINE) { + m_nmi_line = ASSERT_LINE; + v60_do_irq(2); + } + break; + case CLEAR_LINE: + m_nmi_line = CLEAR_LINE; + break; + } + } else { + m_irq_line = state; + v60_try_irq(); + } +} + +// Actual cycles / instruction is unknown + +void v60_device::execute_run() +{ + if (m_irq_line != CLEAR_LINE) + v60_try_irq(); + + while (m_icount > 0) + { + UINT32 inc; + m_PPC = PC; + debugger_instruction_hook(this, PC); + m_icount -= 8; /* fix me -- this is just an average */ + inc = (this->*s_OpCodeTable[OpRead8(PC)])(); + PC += inc; + if (m_irq_line != CLEAR_LINE) + v60_try_irq(); + } +} diff --git a/src/devices/cpu/v60/v60.h b/src/devices/cpu/v60/v60.h new file mode 100644 index 00000000000..28cba0b15c9 --- /dev/null +++ b/src/devices/cpu/v60/v60.h @@ -0,0 +1,794 @@ +// license:BSD-3-Clause +// copyright-holders:Farfetch'd, R. Belmont +#pragma once + +#ifndef __V60_H__ +#define __V60_H__ + + +enum +{ + V60_R0 = 1, + V60_R1, + V60_R2, + V60_R3, + V60_R4, + V60_R5, + V60_R6, + V60_R7, + V60_R8, + V60_R9, + V60_R10, + V60_R11, + V60_R12, + V60_R13, + V60_R14, + V60_R15, + V60_R16, + V60_R17, + V60_R18, + V60_R19, + V60_R20, + V60_R21, + V60_R22, + V60_R23, + V60_R24, + V60_R25, + V60_R26, + V60_R27, + V60_R28, + V60_AP, + V60_FP, + V60_SP, + V60_PC, + V60_PSW, + V60_U1, + V60_U2, + V60_ISP, + V60_L0SP, + V60_L1SP, + V60_L2SP, + V60_L3SP, + V60_SBR, + V60_TR, + V60_SYCW, + V60_TKCW, + V60_PIR, + V60_Res1, + V60_Res2, + V60_Res3, + V60_Res4, + V60_Res5, + V60_PSW2, + V60_ATBR0, + V60_ATLR0, + V60_ATBR1, + V60_ATLR1, + V60_ATBR2, + V60_ATLR2, + V60_ATBR3, + V60_ATLR3, + V60_TRMODE, + V60_ADTR0, + V60_ADTR1, + V60_ADTMR0, + V60_ADTMR1, + V60_Res6, + V60_Res7, + V60_Res8, + V60_REGMAX +}; + + +class v60_device : public cpu_device +{ +public: + // construction/destruction + v60_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + v60_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + void stall(); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_execute_interface overrides + virtual UINT32 execute_min_cycles() const { return 1; } + virtual UINT32 execute_max_cycles() const { return 1; } + virtual UINT32 execute_input_lines() const { return 1; } + virtual void execute_run(); + virtual void execute_set_input(int inputnum, int state); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const { return (spacenum == AS_PROGRAM) ? &m_program_config : ( (spacenum == AS_IO) ? &m_io_config : NULL ); } + + // device_state_interface overrides + virtual void state_import(const device_state_entry &entry); + virtual void state_export(const device_state_entry &entry); + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const { return 1; } + virtual UINT32 disasm_max_opcode_bytes() const { return 22; } + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + +private: + typedef UINT32 (v60_device::*am_func)(); + typedef UINT32 (v60_device::*op6_func)(int reg); + + static const am_func s_AMTable1_G7a[16]; + static const am_func s_BAMTable1_G7a[16]; + static const am_func s_AMTable1_G7[32]; + static const am_func s_BAMTable1_G7[32]; + static const am_func s_AMTable1_G6[8]; + static const am_func s_BAMTable1_G6[8]; + static const am_func s_AMTable1[2][8]; + static const am_func s_BAMTable1[2][8]; + static const am_func s_AMTable2_G7a[16]; + static const am_func s_BAMTable2_G7a[16]; + static const am_func s_AMTable2_G7[32]; + static const am_func s_BAMTable2_G7[32]; + static const am_func s_AMTable2_G6[8]; + static const am_func s_BAMTable2_G6[8]; + static const am_func s_AMTable2[2][8]; + static const am_func s_BAMTable2[2][8]; + static const am_func s_AMTable3_G7a[16]; + static const am_func s_AMTable3_G7[32]; + static const am_func s_AMTable3_G6[8]; + static const am_func s_AMTable3[2][8]; + static const am_func s_Op5FTable[32]; + static const am_func s_Op5CTable[32]; + static const op6_func s_OpC6Table[8]; + static const op6_func s_OpC7Table[8]; + static const am_func s_Op59Table[32]; + static const am_func s_Op5BTable[32]; + static const am_func s_Op5DTable[32]; + static const am_func s_Op58Table[32]; + static const am_func s_Op5ATable[32]; + static const am_func s_OpCodeTable[256]; + + address_space_config m_program_config; + address_space_config m_io_config; + + offs_t m_fetch_xor; + offs_t m_start_pc; + UINT32 m_reg[68]; + struct { + UINT8 CY; + UINT8 OV; + UINT8 S; + UINT8 Z; + } m_flags; + UINT8 m_irq_line; + UINT8 m_nmi_line; + address_space *m_program; + direct_read_data * m_direct; + address_space *m_io; + UINT32 m_PPC; + int m_icount; + int m_stall_io; + + UINT32 m_op1, m_op2; + UINT8 m_flag1, m_flag2; + UINT8 m_instflags; + UINT32 m_lenop1, m_lenop2; + UINT8 m_subop; + UINT32 m_bamoffset1, m_bamoffset2; + + // Output variables for ReadAMAddress(cpustate) + UINT8 m_amflag; + UINT32 m_amout; + UINT32 m_bamoffset; + + // Appo temp var + UINT32 m_amlength1, m_amlength2; + + // Global vars used by AM functions + UINT32 m_modadd; + UINT8 m_modm; + UINT8 m_modval; + UINT8 m_modval2; + UINT8 m_modwritevalb; + UINT16 m_modwritevalh; + UINT32 m_modwritevalw; + UINT8 m_moddim; + + UINT32 m_debugger_temp; + + + inline void v60SaveStack(); + inline void v60ReloadStack(); + inline UINT32 v60ReadPSW(); + inline void v60WritePSW(UINT32 newval); + inline UINT32 v60_update_psw_for_exception(int is_interrupt, int target_level); + + UINT32 am1Register(); + UINT32 am1RegisterIndirect(); + UINT32 bam1RegisterIndirect(); + UINT32 am1RegisterIndirectIndexed(); + UINT32 bam1RegisterIndirectIndexed(); + UINT32 am1Autoincrement(); + UINT32 bam1Autoincrement(); + UINT32 am1Autodecrement(); + UINT32 bam1Autodecrement(); + UINT32 am1Displacement8(); + UINT32 bam1Displacement8(); + UINT32 am1Displacement16(); + UINT32 bam1Displacement16(); + UINT32 am1Displacement32(); + UINT32 bam1Displacement32(); + UINT32 am1DisplacementIndexed8(); + UINT32 bam1DisplacementIndexed8(); + UINT32 am1DisplacementIndexed16(); + UINT32 bam1DisplacementIndexed16(); + UINT32 am1DisplacementIndexed32(); + UINT32 bam1DisplacementIndexed32(); + UINT32 am1PCDisplacement8(); + UINT32 bam1PCDisplacement8(); + UINT32 am1PCDisplacement16(); + UINT32 bam1PCDisplacement16(); + UINT32 am1PCDisplacement32(); + UINT32 bam1PCDisplacement32(); + UINT32 am1PCDisplacementIndexed8(); + UINT32 bam1PCDisplacementIndexed8(); + UINT32 am1PCDisplacementIndexed16(); + UINT32 bam1PCDisplacementIndexed16(); + UINT32 am1PCDisplacementIndexed32(); + UINT32 bam1PCDisplacementIndexed32(); + UINT32 am1DisplacementIndirect8(); + UINT32 bam1DisplacementIndirect8(); + UINT32 am1DisplacementIndirect16(); + UINT32 bam1DisplacementIndirect16(); + UINT32 am1DisplacementIndirect32(); + UINT32 bam1DisplacementIndirect32(); + UINT32 am1DisplacementIndirectIndexed8(); + UINT32 bam1DisplacementIndirectIndexed8(); + UINT32 am1DisplacementIndirectIndexed16(); + UINT32 bam1DisplacementIndirectIndexed16(); + UINT32 am1DisplacementIndirectIndexed32(); + UINT32 bam1DisplacementIndirectIndexed32(); + UINT32 am1PCDisplacementIndirect8(); + UINT32 bam1PCDisplacementIndirect8(); + UINT32 am1PCDisplacementIndirect16(); + UINT32 bam1PCDisplacementIndirect16(); + UINT32 am1PCDisplacementIndirect32(); + UINT32 bam1PCDisplacementIndirect32(); + UINT32 am1PCDisplacementIndirectIndexed8(); + UINT32 bam1PCDisplacementIndirectIndexed8(); + UINT32 am1PCDisplacementIndirectIndexed16(); + UINT32 bam1PCDisplacementIndirectIndexed16(); + UINT32 am1PCDisplacementIndirectIndexed32(); + UINT32 bam1PCDisplacementIndirectIndexed32(); + UINT32 am1DoubleDisplacement8(); + UINT32 bam1DoubleDisplacement8(); + UINT32 am1DoubleDisplacement16(); + UINT32 bam1DoubleDisplacement16(); + UINT32 am1DoubleDisplacement32(); + UINT32 bam1DoubleDisplacement32(); + UINT32 am1PCDoubleDisplacement8(); + UINT32 bam1PCDoubleDisplacement8(); + UINT32 am1PCDoubleDisplacement16(); + UINT32 bam1PCDoubleDisplacement16(); + UINT32 am1PCDoubleDisplacement32(); + UINT32 bam1PCDoubleDisplacement32(); + UINT32 am1DirectAddress(); + UINT32 bam1DirectAddress(); + UINT32 am1DirectAddressIndexed(); + UINT32 bam1DirectAddressIndexed(); + UINT32 am1DirectAddressDeferred(); + UINT32 bam1DirectAddressDeferred(); + UINT32 am1DirectAddressDeferredIndexed(); + UINT32 bam1DirectAddressDeferredIndexed(); + UINT32 am1Immediate(); + UINT32 am1ImmediateQuick(); + UINT32 am1Error1(); + UINT32 bam1Error1(); + UINT32 am1Error2(); + UINT32 bam1Error2(); + UINT32 am1Error3(); + UINT32 bam1Error3(); + UINT32 am1Error4(); + UINT32 bam1Error4(); + UINT32 am1Error5(); + UINT32 bam1Error5(); + UINT32 bam1Error6(); + UINT32 am1Group7a(); + UINT32 bam1Group7a(); + UINT32 am1Group6(); + UINT32 bam1Group6(); + UINT32 am1Group7(); + UINT32 bam1Group7(); + UINT32 am2Register(); + UINT32 am2RegisterIndirect(); + UINT32 bam2RegisterIndirect(); + UINT32 am2RegisterIndirectIndexed(); + UINT32 bam2RegisterIndirectIndexed(); + UINT32 am2Autoincrement(); + UINT32 bam2Autoincrement(); + UINT32 am2Autodecrement(); + UINT32 bam2Autodecrement(); + UINT32 am2Displacement8(); + UINT32 bam2Displacement8(); + UINT32 am2Displacement16(); + UINT32 bam2Displacement16(); + UINT32 am2Displacement32(); + UINT32 bam2Displacement32(); + UINT32 am2DisplacementIndexed8(); + UINT32 bam2DisplacementIndexed8(); + UINT32 am2DisplacementIndexed16(); + UINT32 bam2DisplacementIndexed16(); + UINT32 am2DisplacementIndexed32(); + UINT32 bam2DisplacementIndexed32(); + UINT32 am2PCDisplacement8(); + UINT32 bam2PCDisplacement8(); + UINT32 am2PCDisplacement16(); + UINT32 bam2PCDisplacement16(); + UINT32 am2PCDisplacement32(); + UINT32 bam2PCDisplacement32(); + UINT32 am2PCDisplacementIndexed8(); + UINT32 bam2PCDisplacementIndexed8(); + UINT32 am2PCDisplacementIndexed16(); + UINT32 bam2PCDisplacementIndexed16(); + UINT32 am2PCDisplacementIndexed32(); + UINT32 bam2PCDisplacementIndexed32(); + UINT32 am2DisplacementIndirect8(); + UINT32 bam2DisplacementIndirect8(); + UINT32 am2DisplacementIndirect16(); + UINT32 bam2DisplacementIndirect16(); + UINT32 am2DisplacementIndirect32(); + UINT32 bam2DisplacementIndirect32(); + UINT32 am2DisplacementIndirectIndexed8(); + UINT32 bam2DisplacementIndirectIndexed8(); + UINT32 am2DisplacementIndirectIndexed16(); + UINT32 bam2DisplacementIndirectIndexed16(); + UINT32 am2DisplacementIndirectIndexed32(); + UINT32 bam2DisplacementIndirectIndexed32(); + UINT32 am2PCDisplacementIndirect8(); + UINT32 bam2PCDisplacementIndirect8(); + UINT32 am2PCDisplacementIndirect16(); + UINT32 bam2PCDisplacementIndirect16(); + UINT32 am2PCDisplacementIndirect32(); + UINT32 bam2PCDisplacementIndirect32(); + UINT32 am2PCDisplacementIndirectIndexed8(); + UINT32 bam2PCDisplacementIndirectIndexed8(); + UINT32 am2PCDisplacementIndirectIndexed16(); + UINT32 bam2PCDisplacementIndirectIndexed16(); + UINT32 am2PCDisplacementIndirectIndexed32(); + UINT32 bam2PCDisplacementIndirectIndexed32(); + UINT32 am2DoubleDisplacement8(); + UINT32 bam2DoubleDisplacement8(); + UINT32 am2DoubleDisplacement16(); + UINT32 bam2DoubleDisplacement16(); + UINT32 am2DoubleDisplacement32(); + UINT32 bam2DoubleDisplacement32(); + UINT32 am2PCDoubleDisplacement8(); + UINT32 bam2PCDoubleDisplacement8(); + UINT32 am2PCDoubleDisplacement16(); + UINT32 bam2PCDoubleDisplacement16(); + UINT32 am2PCDoubleDisplacement32(); + UINT32 bam2PCDoubleDisplacement32(); + UINT32 am2DirectAddress(); + UINT32 bam2DirectAddress(); + UINT32 am2DirectAddressIndexed(); + UINT32 bam2DirectAddressIndexed(); + UINT32 am2DirectAddressDeferred(); + UINT32 bam2DirectAddressDeferred(); + UINT32 am2DirectAddressDeferredIndexed(); + UINT32 bam2DirectAddressDeferredIndexed(); + UINT32 am2Immediate(); + UINT32 am2ImmediateQuick(); + UINT32 am2Error1(); + UINT32 am2Error2(); + UINT32 am2Error3(); + UINT32 am2Error4(); + UINT32 am2Error5(); + UINT32 bam2Error1(); + UINT32 bam2Error2(); + UINT32 bam2Error3(); + UINT32 bam2Error4(); + UINT32 bam2Error5(); + UINT32 bam2Error6(); + UINT32 am2Group7a(); + UINT32 bam2Group7a(); + UINT32 am2Group6(); + UINT32 bam2Group6(); + UINT32 am2Group7(); + UINT32 bam2Group7(); + UINT32 am3Register(); + UINT32 am3RegisterIndirect(); + UINT32 am3RegisterIndirectIndexed(); + UINT32 am3Autoincrement(); + UINT32 am3Autodecrement(); + UINT32 am3Displacement8(); + UINT32 am3Displacement16(); + UINT32 am3Displacement32(); + UINT32 am3DisplacementIndexed8(); + UINT32 am3DisplacementIndexed16(); + UINT32 am3DisplacementIndexed32(); + UINT32 am3PCDisplacement8(); + UINT32 am3PCDisplacement16(); + UINT32 am3PCDisplacement32(); + UINT32 am3PCDisplacementIndexed8(); + UINT32 am3PCDisplacementIndexed16(); + UINT32 am3PCDisplacementIndexed32(); + UINT32 am3DisplacementIndirect8(); + UINT32 am3DisplacementIndirect16(); + UINT32 am3DisplacementIndirect32(); + UINT32 am3DisplacementIndirectIndexed8(); + UINT32 am3DisplacementIndirectIndexed16(); + UINT32 am3DisplacementIndirectIndexed32(); + UINT32 am3PCDisplacementIndirect8(); + UINT32 am3PCDisplacementIndirect16(); + UINT32 am3PCDisplacementIndirect32(); + UINT32 am3PCDisplacementIndirectIndexed8(); + UINT32 am3PCDisplacementIndirectIndexed16(); + UINT32 am3PCDisplacementIndirectIndexed32(); + UINT32 am3DoubleDisplacement8(); + UINT32 am3DoubleDisplacement16(); + UINT32 am3DoubleDisplacement32(); + UINT32 am3PCDoubleDisplacement8(); + UINT32 am3PCDoubleDisplacement16(); + UINT32 am3PCDoubleDisplacement32(); + UINT32 am3DirectAddress(); + UINT32 am3DirectAddressIndexed(); + UINT32 am3DirectAddressDeferred(); + UINT32 am3DirectAddressDeferredIndexed(); + UINT32 am3Immediate(); + UINT32 am3ImmediateQuick(); + UINT32 am3Error1(); + UINT32 am3Error2(); + UINT32 am3Error3(); + UINT32 am3Error4(); + UINT32 am3Error5(); + UINT32 am3Group7a(); + UINT32 am3Group6(); + UINT32 am3Group7(); + UINT32 ReadAM(); + UINT32 BitReadAM(); + UINT32 ReadAMAddress(); + UINT32 BitReadAMAddress(); + UINT32 WriteAM(); + void F12DecodeFirstOperand(am_func DecodeOp1, UINT8 dim1); + void F12WriteSecondOperand(UINT8 dim2); + void F12DecodeOperands(am_func DecodeOp1, UINT8 dim1, am_func DecodeOp2, UINT8 dim2); + UINT32 opADDB(); + UINT32 opADDH(); + UINT32 opADDW(); + UINT32 opADDCB(); + UINT32 opADDCH(); + UINT32 opADDCW(); + UINT32 opANDB(); + UINT32 opANDH(); + UINT32 opANDW(); + UINT32 opCALL(); + UINT32 opCHKAR(); + UINT32 opCHKAW(); + UINT32 opCHKAE(); + UINT32 opCHLVL(); + UINT32 opCLR1(); + UINT32 opCMPB(); + UINT32 opCMPH(); + UINT32 opCMPW(); + UINT32 opDIVB(); + UINT32 opDIVH(); + UINT32 opDIVW(); + UINT32 opDIVX(); + UINT32 opDIVUX(); + UINT32 opDIVUB(); + UINT32 opDIVUH(); + UINT32 opDIVUW(); + UINT32 opINB(); + UINT32 opINH(); + UINT32 opINW(); + UINT32 opLDPR(); + UINT32 opLDTASK(); + UINT32 opMOVD(); + UINT32 opMOVB(); + UINT32 opMOVH(); + UINT32 opMOVW(); + UINT32 opMOVEAB(); + UINT32 opMOVEAH(); + UINT32 opMOVEAW(); + UINT32 opMOVSBH(); + UINT32 opMOVSBW(); + UINT32 opMOVSHW(); + UINT32 opMOVTHB(); + UINT32 opMOVTWB(); + UINT32 opMOVTWH(); + UINT32 opMOVZBH(); + UINT32 opMOVZBW(); + UINT32 opMOVZHW(); + UINT32 opMULB(); + UINT32 opMULH(); + UINT32 opMULW(); + UINT32 opMULUB(); + UINT32 opMULUH(); + UINT32 opMULUW(); + UINT32 opNEGB(); + UINT32 opNEGH(); + UINT32 opNEGW(); + UINT32 opNOTB(); + UINT32 opNOTH(); + UINT32 opNOTW(); + UINT32 opNOT1(); + UINT32 opORB(); + UINT32 opORH(); + UINT32 opORW(); + UINT32 opOUTB(); + UINT32 opOUTH(); + UINT32 opOUTW(); + UINT32 opREMB(); + UINT32 opREMH(); + UINT32 opREMW(); + UINT32 opREMUB(); + UINT32 opREMUH(); + UINT32 opREMUW(); + UINT32 opROTB(); + UINT32 opROTH(); + UINT32 opROTW(); + UINT32 opROTCB(); + UINT32 opROTCH(); + UINT32 opROTCW(); + UINT32 opRVBIT(); + UINT32 opRVBYT(); + UINT32 opSET1(); + UINT32 opSETF(); + UINT32 opSHAB(); + UINT32 opSHAH(); + UINT32 opSHAW(); + UINT32 opSHLB(); + UINT32 opSHLH(); + UINT32 opSHLW(); + UINT32 opSTPR(); + UINT32 opSUBB(); + UINT32 opSUBH(); + UINT32 opSUBW(); + UINT32 opSUBCB(); + UINT32 opSUBCH(); + UINT32 opSUBCW(); + UINT32 opTEST1(); + UINT32 opUPDPSWW(); + UINT32 opUPDPSWH(); + UINT32 opXCHB(); + UINT32 opXCHH(); + UINT32 opXCHW(); + UINT32 opXORB(); + UINT32 opXORH(); + UINT32 opXORW(); + UINT32 opMULX(); + UINT32 opMULUX(); + void F2DecodeFirstOperand(am_func DecodeOp1, UINT8 dim1); + void F2DecodeSecondOperand(am_func DecodeOp2, UINT8 dim2); + void F2WriteSecondOperand(UINT8 dim2); + UINT32 opCVTWS(); + UINT32 opCVTSW(); + UINT32 opMOVFS(); + UINT32 opNEGFS(); + UINT32 opABSFS(); + UINT32 opADDFS(); + UINT32 opSUBFS(); + UINT32 opMULFS(); + UINT32 opDIVFS(); + UINT32 opSCLFS(); + UINT32 opCMPF(); + UINT32 op5FUNHANDLED(); + UINT32 op5CUNHANDLED(); + UINT32 op5F(); + UINT32 op5C(); + UINT32 opINCB(); + UINT32 opINCH(); + UINT32 opINCW(); + UINT32 opDECB(); + UINT32 opDECH(); + UINT32 opDECW(); + UINT32 opJMP(); + UINT32 opJSR(); + UINT32 opPREPARE(); + UINT32 opRET(); + UINT32 opTRAP(); + UINT32 opRETIU(); + UINT32 opRETIS(); + UINT32 opSTTASK(); + UINT32 opGETPSW(); + UINT32 opTASI(); + UINT32 opCLRTLB(); + UINT32 opPOPM(); + UINT32 opPUSHM(); + UINT32 opTESTB(); + UINT32 opTESTH(); + UINT32 opTESTW(); + UINT32 opPUSH(); + UINT32 opPOP(); + UINT32 opINCB_0(); + UINT32 opINCB_1(); + UINT32 opINCH_0(); + UINT32 opINCH_1(); + UINT32 opINCW_0(); + UINT32 opINCW_1(); + UINT32 opDECB_0(); + UINT32 opDECB_1(); + UINT32 opDECH_0(); + UINT32 opDECH_1(); + UINT32 opDECW_0(); + UINT32 opDECW_1(); + UINT32 opJMP_0(); + UINT32 opJMP_1(); + UINT32 opJSR_0(); + UINT32 opJSR_1(); + UINT32 opPREPARE_0(); + UINT32 opPREPARE_1(); + UINT32 opRET_0(); + UINT32 opRET_1(); + UINT32 opTRAP_0(); + UINT32 opTRAP_1(); + UINT32 opRETIU_0(); + UINT32 opRETIU_1(); + UINT32 opRETIS_0(); + UINT32 opRETIS_1(); + UINT32 opGETPSW_0(); + UINT32 opGETPSW_1(); + UINT32 opTASI_0(); + UINT32 opTASI_1(); + UINT32 opCLRTLB_0(); + UINT32 opCLRTLB_1(); + UINT32 opPOPM_0(); + UINT32 opPOPM_1(); + UINT32 opPUSHM_0(); + UINT32 opPUSHM_1(); + UINT32 opTESTB_0(); + UINT32 opTESTB_1(); + UINT32 opTESTH_0(); + UINT32 opTESTH_1(); + UINT32 opTESTW_0(); + UINT32 opTESTW_1(); + UINT32 opPUSH_0(); + UINT32 opPUSH_1(); + UINT32 opPOP_0(); + UINT32 opPOP_1(); + UINT32 opSTTASK_0(); + UINT32 opSTTASK_1(); + UINT32 opBGT8(); + UINT32 opBGT16(); + UINT32 opBGE8(); + UINT32 opBGE16(); + UINT32 opBLT8(); + UINT32 opBLT16(); + UINT32 opBLE8(); + UINT32 opBLE16(); + UINT32 opBH8(); + UINT32 opBH16(); + UINT32 opBNH8(); + UINT32 opBNH16(); + UINT32 opBNL8(); + UINT32 opBNL16(); + UINT32 opBL8(); + UINT32 opBL16(); + UINT32 opBNE8(); + UINT32 opBNE16(); + UINT32 opBE8(); + UINT32 opBE16(); + UINT32 opBNV8(); + UINT32 opBNV16(); + UINT32 opBV8(); + UINT32 opBV16(); + UINT32 opBP8(); + UINT32 opBP16(); + UINT32 opBN8(); + UINT32 opBN16(); + UINT32 opBR8(); + UINT32 opBR16(); + UINT32 opBSR(); + UINT32 opBRK(); + UINT32 opBRKV(); + UINT32 opCLRTLBA(); + UINT32 opDISPOSE(); + UINT32 opHALT(); + UINT32 opNOP(); + UINT32 opRSR(); + UINT32 opTRAPFL(); + UINT32 opTB(int reg); + UINT32 opDBGT(int reg); + UINT32 opDBLE(int reg); + UINT32 opDBGE(int reg); + UINT32 opDBLT(int reg); + UINT32 opDBH(int reg); + UINT32 opDBNH(int reg); + UINT32 opDBL(int reg); + UINT32 opDBNL(int reg); + UINT32 opDBE(int reg); + UINT32 opDBNE(int reg); + UINT32 opDBV(int reg); + UINT32 opDBNV(int reg); + UINT32 opDBN(int reg); + UINT32 opDBP(int reg); + UINT32 opDBR(int reg); + UINT32 opC6(); + UINT32 opC7(); + void F7aDecodeOperands(am_func DecodeOp1, UINT8 dim1, am_func DecodeOp2, UINT8 dim2); + void F7bDecodeFirstOperand(am_func DecodeOp1, UINT8 dim1); + void F7bWriteSecondOperand(UINT8 dim2); + void F7bDecodeOperands(am_func DecodeOp1, UINT8 dim1, am_func DecodeOp2, UINT8 dim2); + void F7cDecodeOperands(am_func DecodeOp1, UINT8 dim1, am_func DecodeOp2, UINT8 dim2); + UINT32 opCMPSTRB(UINT8 bFill, UINT8 bStop); + UINT32 opCMPSTRH(UINT8 bFill, UINT8 bStop); + UINT32 opMOVSTRUB(UINT8 bFill, UINT8 bStop); + UINT32 opMOVSTRDB(UINT8 bFill, UINT8 bStop); + UINT32 opMOVSTRUH(UINT8 bFill, UINT8 bStop); + UINT32 opMOVSTRDH(UINT8 bFill, UINT8 bStop); + UINT32 opSEARCHUB(UINT8 bSearch); + UINT32 opSEARCHUH(UINT8 bSearch); + UINT32 opSEARCHDB(UINT8 bSearch); + UINT32 opSEARCHDH(UINT8 bSearch); + UINT32 opSCHCUB(); + UINT32 opSCHCUH(); + UINT32 opSCHCDB(); + UINT32 opSCHCDH(); + UINT32 opSKPCUB(); + UINT32 opSKPCUH(); + UINT32 opSKPCDB(); + UINT32 opSKPCDH(); + UINT32 opCMPCB(); + UINT32 opCMPCH(); + UINT32 opCMPCFB(); + UINT32 opCMPCFH(); + UINT32 opCMPCSB(); + UINT32 opCMPCSH(); + UINT32 opMOVCUB(); + UINT32 opMOVCUH(); + UINT32 opMOVCFUB(); + UINT32 opMOVCFUH(); + UINT32 opMOVCSUB(); + UINT32 opMOVCSUH(); + UINT32 opMOVCDB(); + UINT32 opMOVCDH(); + UINT32 opMOVCFDB(); + UINT32 opMOVCFDH(); + UINT32 opEXTBFZ(); + UINT32 opEXTBFS(); + UINT32 opEXTBFL(); + UINT32 opSCHBS(UINT32 bSearch1); + UINT32 opSCH0BSU(); + UINT32 opSCH1BSU(); + UINT32 opINSBFR(); + UINT32 opINSBFL(); + UINT32 opMOVBSD(); + UINT32 opMOVBSU(); + UINT32 opADDDC(); + UINT32 opSUBDC(); + UINT32 opSUBRDC(); + UINT32 opCVTDPZ(); + UINT32 opCVTDZP(); + UINT32 op58UNHANDLED(); + UINT32 op5AUNHANDLED(); + UINT32 op5BUNHANDLED(); + UINT32 op5DUNHANDLED(); + UINT32 op59UNHANDLED(); + UINT32 op58(); + UINT32 op5A(); + UINT32 op5B(); + UINT32 op5D(); + UINT32 op59(); + UINT32 opUNHANDLED(); + void v60_do_irq(int vector); + void v60_try_irq(); + +}; + + +class v70_device : public v60_device +{ +public: + // construction/destruction + v70_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); +}; + + +extern const device_type V60; +extern const device_type V70; + + +#endif /* __V60_H__ */ diff --git a/src/devices/cpu/v60/v60d.c b/src/devices/cpu/v60/v60d.c new file mode 100644 index 00000000000..a32268fc2b4 --- /dev/null +++ b/src/devices/cpu/v60/v60d.c @@ -0,0 +1,1499 @@ +// license:BSD-3-Clause +// copyright-holders:Farfetch'd, R. Belmont + +#include "emu.h" +#include "debugger.h" +#include "v60.h" + +// Register names +static const char *const v60_reg_names[69] = { + "R0", "R1", "R2", "R3", + "R4", "R5", "R6", "R7", + "R8", "R9", "R10", "R11", + "R12", "R13", "R14", "R15", + "R16", "R17", "R18", "R19", + "R20", "R21", "R22", "R23", + "R24", "R25", "R26", "R27", + "R28", "AP", "FP", "SP", + "PC", "PSW","Unk","Unk", + "ISP", "L0SP", "L1SP", "L2SP", + "L3SP", "SBR","TR","SYCW", + "TKCW", "PIR", "Reserved","Reserved", + "Reserved","Reserved","Reserved","PSW2", + "ATBR0", "ATLR0", "ATBR1", "ATLR1", + "ATBR2", "ATLR2", "ATBR3", "ATLR3", + "TRMODE", "ADTR0", "ADTR1","ADTMR0", + "ADTMR1","Reserved","Reserved","Reserved" +}; + +static const UINT8 *rombase; +static offs_t pcbase; + +#define readop(a) rombase[(a) - pcbase] + +static signed char read8(unsigned pc) +{ + return readop(pc); +} + +static signed short read16(unsigned pc) +{ + return readop(pc) | (readop(pc+1) << 8); +} + +static signed int read32(unsigned pc) +{ + return readop(pc) | (readop(pc+1) << 8)| (readop(pc+2) << 16)| (readop(pc+3) << 24); +} + +static void out_AM_Register(int reg, char *out) +{ + strcat(out, v60_reg_names[reg]); +} + +static void out_AM_RegisterIndirect(int reg, int opsize, char *out) +{ + if(opsize & 0x80) + *out++ = '@'; + sprintf(out, "[%s]", v60_reg_names[reg]); +} + +static void out_AM_RegisterIndirectIndexed(int rn, int rx, int opsize, char *out) +{ + if(opsize & 0x80) + sprintf(out, "%s@[%s]", v60_reg_names[rx], v60_reg_names[rn]); + else + sprintf(out, "[%s](%s)", v60_reg_names[rn], v60_reg_names[rx]); + +} + +static void out_AM_Autoincrement(int reg, int opsize, char *out) +{ + if(opsize & 0x80) + *out++ = '@'; + sprintf(out, "[%s+]", v60_reg_names[reg]); +} + +static void out_AM_Autodecrement(int reg, int opsize, char *out) +{ + if(opsize & 0x80) + *out++ = '@'; + sprintf(out, "[-%s]", v60_reg_names[reg]); +} + +static void out_AM_Displacement(int reg, int disp, int opsize, char *out) +{ + sprintf(out, "%s%X%s[%s]", + disp >= 0 ? "" : "-", disp >= 0 ? disp : -disp, + opsize & 0x80 ? "@" : "", + v60_reg_names[reg]); +} + +static void out_AM_DisplacementIndexed(int rn, int rx, int disp, int opsize, char *out) +{ + if(opsize & 0x80) + sprintf(out, "%s@%s%X[%s]", v60_reg_names[rx], disp >= 0 ? "" : "-", disp >= 0 ? disp : -disp,v60_reg_names[rn]); + else + sprintf(out, "%s%X[%s](%s)", disp >= 0 ? "" : "-", disp >= 0 ? disp : -disp,v60_reg_names[rn], v60_reg_names[rx]); +} + +static void out_AM_PCDisplacement(unsigned pc, int disp, int opsize, char *out) +{ + sprintf(out, "%X%s[PC]", pc+disp, opsize & 0x80 ? "@" : ""); +} + +static void out_AM_PCDisplacementIndexed(unsigned pc, int disp, int rx, int opsize, char *out) +{ + if(opsize & 0x80) + sprintf(out, "%s@%X[PC]", v60_reg_names[rx], pc+disp); + else + sprintf(out, "%X[PC](%s)", pc+disp, v60_reg_names[rx]); +} + +static void out_AM_DisplacementIndirect(int reg, int disp, int opsize, char *out) +{ + sprintf(out, "%s[%s%X[%s]]", + opsize & 0x80 ? "@" : "", + disp >= 0 ? "" : "-", disp >= 0 ? disp : -disp, + v60_reg_names[reg]); +} + +static void out_AM_DisplacementIndirectIndexed(int rn, int rx, int disp, int opsize, char *out) +{ + if(opsize & 0x80) + sprintf(out, "%s@[%s%X[%s]]", v60_reg_names[rx], disp >= 0 ? "" : "-", disp >= 0 ? disp : -disp,v60_reg_names[rn]); + else + sprintf(out, "[%s%X[%s]](%s)", disp >= 0 ? "" : "-", disp >= 0 ? disp : -disp,v60_reg_names[rn], v60_reg_names[rx]); +} + +static void out_AM_PCDisplacementIndirect(unsigned pc, int disp, int opsize, char *out) +{ + sprintf(out, "%s[%X[PC]]", opsize & 0x80 ? "@" : "", pc+disp); +} + +static void out_AM_PCDisplacementIndirectIndexed(unsigned pc, int disp, int rx, int opsize, char *out) +{ + if(opsize & 0x80) + sprintf(out, "%s@[%X[PC]]", v60_reg_names[rx], pc+disp); + else + sprintf(out, "[%X[PC]](%s)", pc+disp, v60_reg_names[rx]); +} + +static void out_AM_DoubleDisplacement(int reg, int disp2, int disp1, int opsize, char *out) +{ + sprintf(out, "%s%X%s[%s%X[%s]]", + disp1 >= 0 ? "" : "-", disp1 >= 0 ? disp1 : -disp1, + opsize & 0x80 ? "@" : "", + disp2 >= 0 ? "" : "-", disp2 >= 0 ? disp2 : -disp2, + v60_reg_names[reg]); +} + +static void out_AM_PCDoubleDisplacement(unsigned pc, int disp2, int disp1, int opsize, char *out) +{ + sprintf(out, "%s%X%s[%X[PC]]", + disp1 >= 0 ? "" : "-", disp1 >= 0 ? disp1 : -disp1, + opsize & 0x80 ? "@" : "", + disp2 + pc); +} + +static void out_AM_DirectAddress(unsigned addr, int opsize, char *out) +{ + if(opsize & 0x80) + *out++ = '@'; + sprintf(out, "%X", addr); +} + +static void out_AM_DirectAddressIndexed(unsigned addr, int rx, int opsize, char *out) +{ + if(opsize & 0x80) + sprintf(out, "%s@%X", v60_reg_names[rx], addr); + else + sprintf(out, "%X(%s)", addr, v60_reg_names[rx]); +} + +static void out_AM_DirectAddressDeferred(unsigned addr, int opsize, char *out) +{ + if(opsize & 0x80) + *out++ = '@'; + sprintf(out, "[%X]", addr); +} + +static void out_AM_DirectAddressDeferredIndexed(unsigned addr, int rx, int opsize, char *out) +{ + if(opsize & 0x80) + sprintf(out, "%s@[%X]", v60_reg_names[rx], addr); + else + sprintf(out, "[%X](%s)", addr, v60_reg_names[rx]); +} + +static void out_AM_Immediate(unsigned value, int opsize, char *out) +{ + if(opsize == 0) + value &= 0xff; + else if(opsize == 1) + value &= 0xffff; + + sprintf(out, "#%X", value); +} + +static int decode_AM(unsigned ipc, unsigned pc, int m, int opsize, char *out) +{ + unsigned char mod = readop(pc); + if(m) { + switch(mod>>5) { + case 0: // Double displacement (8 bit) + out_AM_DoubleDisplacement(mod&0x1F, read8(pc+1), read8(pc+2), opsize, out); + return 3; + + case 1: // Double displacement (16 bit) + out_AM_DoubleDisplacement(mod&0x1F, read16(pc+1), read16(pc+3), opsize, out); + return 5; + + case 2: // Double displacement (32 bit) + out_AM_DoubleDisplacement(mod&0x1F, read32(pc+1), read32(pc+5), opsize, out); + return 9; + + case 3: // Register + out_AM_Register(mod&0x1F, out); + return 1; + + case 4: // Autoincrement + out_AM_Autoincrement(mod&0x1F, opsize, out); + return 1; + + case 5: // Autodecrement + out_AM_Autodecrement(mod&0x1F, opsize, out); + return 1; + + case 6: + switch (readop(pc+1)>>5) + { + case 0: // Displacement indexed (8 bit) + out_AM_DisplacementIndexed(readop(pc+1)&0x1F, mod&0x1F, read8(pc+2), opsize, out); + return 3; + + case 1: // Displacement indexed (16 bit) + out_AM_DisplacementIndexed(readop(pc+1)&0x1F, mod&0x1F, read16(pc+2), opsize, out); + return 4; + + case 2: // Displacement indexed (32 bit) + out_AM_DisplacementIndexed(readop(pc+1)&0x1F, mod&0x1F, read32(pc+2), opsize, out); + return 6; + + case 3: // Register indirect indexed + out_AM_RegisterIndirectIndexed(readop(pc+1)&0x1F, mod&0x1F, opsize, out); + return 2; + + case 4: // Displacement indirect indexed (8 bit) + out_AM_DisplacementIndirectIndexed(readop(pc+1)&0x1F, mod&0x1F, read8(pc+2), opsize, out); + return 3; + + case 5: // Displacement indirect indexed (16 bit) + out_AM_DisplacementIndirectIndexed(readop(pc+1)&0x1F, mod&0x1F, read16(pc+2), opsize, out); + return 4; + + case 6: // Displacement indirect indexed (32 bit) + out_AM_DisplacementIndirectIndexed(readop(pc+1)&0x1F, mod&0x1F, read32(pc+2), opsize, out); + return 6; + + case 7: + switch (readop(pc+1)&0x1F) + { + case 16: // PC Displacement Indexed (8 bit) + out_AM_PCDisplacementIndexed(ipc, read8(pc+2), mod&0x1F, opsize, out); + return 3; + + case 17: // PC Displacement Indexed (16 bit) + out_AM_PCDisplacementIndexed(ipc, read16(pc+2), mod&0x1F, opsize, out); + return 4; + + case 18: // PC Displacement Indexed (32 bit) + out_AM_PCDisplacementIndexed(ipc, read32(pc+2), mod&0x1F, opsize, out); + return 6; + + case 19: // Direct Address Indexed + out_AM_DirectAddressIndexed(read32(pc+2), mod&0x1F, opsize, out); + return 6; + + case 24: // PC Displacement Indirect Indexed(8 bit) + out_AM_PCDisplacementIndirectIndexed(ipc, read8(pc+2), mod&0x1F, opsize, out); + return 3; + + case 25: // PC Displacement Indirect Indexed (16 bit) + out_AM_PCDisplacementIndirectIndexed(ipc, read16(pc+2), mod&0x1F, opsize, out); + return 4; + + case 26: // PC Displacement Indirect Indexed (32 bit) + out_AM_PCDisplacementIndirectIndexed(ipc, read32(pc+2), mod&0x1F, opsize, out); + return 6; + + case 27: // Direct Address Deferred Indexed + out_AM_DirectAddressDeferredIndexed(read32(pc+2), mod&0x1F, opsize, out); + return 6; + + default: + strcat(out, "!ERRAM3"); + return 1; + } + + default: + strcat(out, "!ERRAM2"); + return 1; + } + + default: + strcat(out, "!ERRAM1"); + return 1; + } + } else { + switch(mod>>5) { + case 0: // Displacement (8 bit) + out_AM_Displacement(mod&0x1F, read8(pc+1), opsize, out); + return 2; + + case 1: // Displacement (16 bit) + out_AM_Displacement(mod&0x1F, read16(pc+1), opsize, out); + return 3; + + case 2: // Displacement (32 bit) + out_AM_Displacement(mod&0x1F, read32(pc+1), opsize, out); + return 5; + + case 3: // Register indirect + out_AM_RegisterIndirect(mod&0x1F, opsize, out); + return 1; + + case 4: // Displacement indirect (8 bit) + out_AM_DisplacementIndirect(mod&0x1F, read8(pc+1), opsize, out); + return 2; + + case 5: // Displacement indirect (16 bit) + out_AM_DisplacementIndirect(mod&0x1F, read16(pc+1), opsize, out); + return 3; + + case 6: // Displacement indirect (32 bit) + out_AM_DisplacementIndirect(mod&0x1F, read32(pc+1), opsize, out); + return 5; + + case 7: + switch(mod&0x1F) { + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + case 14: + case 15: + out_AM_Immediate(mod&0x1F, opsize, out); + return 1; + + case 16: // PC Displacement (8 bit) + out_AM_PCDisplacement(ipc, read8(pc+1), opsize, out); + return 2; + + case 17: // PC Displacement (16 bit) + out_AM_PCDisplacement(ipc, read16(pc+1), opsize, out); + return 3; + + case 18: // PC Displacement (32 bit) + out_AM_PCDisplacement(ipc, read32(pc+1), opsize, out); + return 5; + + case 19: // Direct Address + out_AM_DirectAddress(read32(pc+1), opsize, out); + return 5; + + + case 20: + switch(opsize&0x7F) { + case 0: // Immediate (8 bit) + out_AM_Immediate(read8(pc+1), opsize, out); + return 2; + + case 1: // Immediate (16 bit) + out_AM_Immediate(read16(pc+1), opsize, out); + return 3; + + case 2: // Immediate (32 bit) + out_AM_Immediate(read32(pc+1), opsize, out); + return 5; + + default: + strcat(out, "!ERRAM6"); + return 1; + } + + case 24: // PC Displacement Indirect (8 bit) + out_AM_PCDisplacementIndirect(ipc, read8(pc+1), opsize, out); + return 2; + + case 25: // PC Displacement Indirect (16 bit) + out_AM_PCDisplacementIndirect(ipc, read16(pc+1), opsize, out); + return 3; + + case 26: // PC Displacement Indirect (32 bit) + out_AM_PCDisplacementIndirect(ipc, read32(pc+1), opsize, out); + return 5; + + case 27: // Direct Address Deferred + out_AM_DirectAddressDeferred(read32(pc+1), opsize, out); + return 5; + + case 28: // PC Double Displacement (8 bit) + out_AM_PCDoubleDisplacement(ipc, read8(pc+1), read8(pc+2), opsize, out); + return 3; + + case 29: // PC Double Displacement (16 bit) + out_AM_PCDoubleDisplacement(ipc, read16(pc+1), read16(pc+3), opsize, out); + return 5; + + case 30: // PC Double Displacement (32 bit) + out_AM_PCDoubleDisplacement(ipc, read32(pc+1), read32(pc+5), opsize, out); + return 9; + + default: + strcat(out, "!ERRAM5"); + return 1; + } + + default: + strcat(out, "!ERRAM4"); + return 1; + } + } +} + + +static int decode_F1(const char *opnm, int opsize1, int opsize2, unsigned ipc, unsigned pc, char *out) +{ + unsigned char code = readop(pc); + sprintf(out, "%-8s", opnm); + if(code & 0x20) { + int ret = decode_AM(ipc, pc+1, code & 0x40, opsize1, out + strlen(out)) + 2; + strcat(out, ", "); + out_AM_Register(code & 0x1f, out + strlen(out)); + return ret; + } else { + out_AM_Register(code & 0x1f, out + strlen(out)); + strcat(out, ", "); + return decode_AM(ipc, pc+1, code & 0x40, opsize1, out + strlen(out)) + 2; + } +} + +static int decode_F2(const char *opnm, int opsize1, int opsize2, unsigned ipc, unsigned pc, char *out) +{ + int ret; + unsigned char code = readop(pc); + sprintf(out, "%-8s", opnm); + ret = decode_AM(ipc, pc+1, code & 0x40, opsize1, out + strlen(out)); + strcat(out, ", "); + ret += decode_AM(ipc, pc+1+ret, code & 0x20, opsize2, out + strlen(out)); + return ret+2; +} + +static int decode_F1F2(const char *opnm, int opsize1, int opsize2, unsigned ipc, unsigned pc, char *out) +{ + if(readop(pc) & 0x80) + return decode_F2(opnm, opsize1, opsize2, ipc, pc, out); + else + return decode_F1(opnm, opsize1, opsize2, ipc, pc, out); +} + +static int decode_F3(const char *opnm, int opsize1, int opsize2, unsigned ipc, unsigned pc, char *out) +{ + sprintf(out, "%-8s", opnm); + return decode_AM(ipc, pc, readop(pc-1) & 1, opsize1, out + strlen(out)) + 1; +} + +static int decode_F4a(const char *opnm, int opsize1, int opsize2, unsigned ipc, unsigned pc, char *out) +{ + sprintf(out, "%-8s%X", opnm, ipc+read8(pc)); + return 2; +} + +static int decode_F4b(const char *opnm, int opsize1, int opsize2, unsigned ipc, unsigned pc, char *out) +{ + sprintf(out, "%-8s%X", opnm, ipc+read16(pc)); + return 3; +} + +static int decode_F5(const char *opnm, int opsize1, int opsize2, unsigned ipc, unsigned pc, char *out) +{ + strcpy(out, opnm); + return 1; +} + +static int decode_F6(const char *opnm, int opsize1, int opsize2, unsigned ipc, unsigned pc, char *out) +{ + sprintf(out, "%-8s%s, %X[PC]", opnm, v60_reg_names[readop(pc) & 0x1f], ipc+read16(pc+1)); + return 4; +} + +static int decode_F7a(const char *opnm, int opsize1, int opsize2, unsigned ipc, unsigned pc, char *out) +{ + int ret; + unsigned char code = readop(pc); + unsigned char code2; + + sprintf(out, "%-8s", opnm); + ret = decode_AM(ipc, pc+1, code & 0x40, opsize1, out + strlen(out)); + strcat(out, ", "); + + code2 = readop(pc+1+ret); + if(code2 & 0x80) + out_AM_Register(code2 & 0x1f, out + strlen(out)); + else + out_AM_Immediate(code2, 1, out + strlen(out)); + strcat(out, ", "); + + ret += decode_AM(ipc, pc+2+ret, code & 0x20, opsize2, out + strlen(out)); + strcat(out, ", "); + + code2 = readop(pc+2+ret); + if(code2 & 0x80) + out_AM_Register(code2 & 0x1f, out + strlen(out)); + else + out_AM_Immediate(code2, 1, out + strlen(out)); + + return ret+4; +} + +static int decode_F7b(const char *opnm, int opsize1, int opsize2, unsigned ipc, unsigned pc, char *out) +{ + int ret; + unsigned char code = readop(pc); + unsigned char code2; + + sprintf(out, "%-8s", opnm); + ret = decode_AM(ipc, pc+1, code & 0x40, opsize1, out + strlen(out)); + strcat(out, ", "); + + code2 = readop(pc+1+ret); + if(code2 & 0x80) + out_AM_Register(code2 & 0x1f, out + strlen(out)); + else + out_AM_Immediate(code2, 1, out + strlen(out)); + strcat(out, ", "); + + ret += decode_AM(ipc, pc+2+ret, code & 0x20, opsize2, out + strlen(out)); + + return ret+3; +} + +static int decode_F7c(const char *opnm, int opsize1, int opsize2, unsigned ipc, unsigned pc, char *out) +{ + int ret; + unsigned char code = readop(pc); + unsigned char code2; + + sprintf(out, "%-8s", opnm); + ret = decode_AM(ipc, pc+1, code & 0x40, opsize1, out + strlen(out)); + strcat(out, ", "); + + ret += decode_AM(ipc, pc+1+ret, code & 0x20, opsize2, out + strlen(out)); + strcat(out, ", "); + + code2 = readop(pc+1+ret); + if(code2 & 0x80) + out_AM_Register(code2 & 0x1f, out + strlen(out)); + else + out_AM_Immediate(code2, 1, out + strlen(out)); + + return ret+3; +} + +static int dopUNHANDLED(unsigned ipc, unsigned pc, char *out) +{ + sprintf(out, "$%02X", readop(pc)); + return 1; +} + +static int dop58UNHANDLED(unsigned ipc, unsigned pc, char *out) +{ + sprintf(out, "$58"); + return 1; +} + +static int dop59UNHANDLED(unsigned ipc, unsigned pc, char *out) +{ + sprintf(out, "$59"); + return 1; +} + +static int dop5AUNHANDLED(unsigned ipc, unsigned pc, char *out) +{ + sprintf(out, "$5A"); + return 1; +} + +static int dop5BUNHANDLED(unsigned ipc, unsigned pc, char *out) +{ + sprintf(out, "$5B"); + return 1; +} + +static int dop5CUNHANDLED(unsigned ipc, unsigned pc, char *out) +{ + sprintf(out, "$5C"); + return 1; +} + +static int dop5DUNHANDLED(unsigned ipc, unsigned pc, char *out) +{ + sprintf(out, "$5D"); + return 1; +} + +static int dop5EUNHANDLED(unsigned ipc, unsigned pc, char *out) +{ + sprintf(out, "$5E"); + return 1; +} + +static int dop5FUNHANDLED(unsigned ipc, unsigned pc, char *out) +{ + sprintf(out, "$5F"); + return 1; +} + +#define DEFINE_EASY_OPCODE(name, opnm, ftype, opsize1, opsize2) \ + static int dop ## name(unsigned ipc, unsigned pc, char *out) \ + { \ + return decode_ ## ftype(opnm, opsize1, opsize2, ipc, pc, out); \ + } + +#define DEFINE_EASY_OPCODE_EX(name, opnm, ftype, opsize1, opsize2, flags) \ + static int dop ## name(unsigned ipc, unsigned pc, char *out) \ + { \ + return decode_ ## ftype(opnm, opsize1, opsize2, ipc, pc, out) | (flags); \ + } + +#define DEFINE_TRIPLE_OPCODE(name, string, ftype) \ + DEFINE_EASY_OPCODE(name##B,string ".b", ftype, 0, 0) \ + DEFINE_EASY_OPCODE(name##H,string ".h", ftype, 1, 1) \ + DEFINE_EASY_OPCODE(name##W,string ".w", ftype, 2, 2) + +#define DEFINE_DOUBLE_OPCODE(name, string, ftype) \ + DEFINE_EASY_OPCODE(name##B,string ".b", ftype, 0, 0) \ + DEFINE_EASY_OPCODE(name##H,string ".h", ftype, 1, 1) + +#define DEFINE_FPU_OPCODE(name,string,ftype) \ + DEFINE_EASY_OPCODE(name##S,string ".s", ftype, 2, 2) \ + DEFINE_EASY_OPCODE(name##L,string ".l", ftype, 2, 2) + + +DEFINE_FPU_OPCODE(ABSF, "absf", F2) +DEFINE_TRIPLE_OPCODE(ADD, "add", F1F2) +DEFINE_TRIPLE_OPCODE(ADDC, "addc", F1F2) +DEFINE_EASY_OPCODE(ADDDC, "adddc", F7c, 0, 0) +DEFINE_FPU_OPCODE(ADDF, "addf", F2) +DEFINE_TRIPLE_OPCODE(AND, "and", F1F2) +DEFINE_EASY_OPCODE(ANDBSU, "andbsu", F7b, 0x80, 0x80) +DEFINE_EASY_OPCODE(ANDBSD, "andbsd", F7b, 0x80, 0x80) +DEFINE_EASY_OPCODE(ANDNBSU, "andnbsu", F7b, 0x80, 0x80) +DEFINE_EASY_OPCODE(ANDNBSD, "andnbsd", F7b, 0x80, 0x80) +DEFINE_EASY_OPCODE(BGT8, "bgt", F4a, 0, 0) +DEFINE_EASY_OPCODE(BGT16, "bgt", F4b, 0, 0) +DEFINE_EASY_OPCODE(BGE8, "bge", F4a, 0, 0) +DEFINE_EASY_OPCODE(BGE16, "bge", F4b, 0, 0) +DEFINE_EASY_OPCODE(BLT8, "blt", F4a, 0, 0) +DEFINE_EASY_OPCODE(BLT16, "blt", F4b, 0, 0) +DEFINE_EASY_OPCODE(BLE8, "ble", F4a, 0, 0) +DEFINE_EASY_OPCODE(BLE16, "ble", F4b, 0, 0) +DEFINE_EASY_OPCODE(BH8, "bh", F4a, 0, 0) +DEFINE_EASY_OPCODE(BH16, "bh", F4b, 0, 0) +DEFINE_EASY_OPCODE(BNL8, "bnl", F4a, 0, 0) +DEFINE_EASY_OPCODE(BNL16, "bnl", F4b, 0, 0) +DEFINE_EASY_OPCODE(BL8, "bl", F4a, 0, 0) +DEFINE_EASY_OPCODE(BL16, "bl", F4b, 0, 0) +DEFINE_EASY_OPCODE(BNH8, "bnh", F4a, 0, 0) +DEFINE_EASY_OPCODE(BNH16, "bnh", F4b, 0, 0) +DEFINE_EASY_OPCODE(BE8, "be", F4a, 0, 0) +DEFINE_EASY_OPCODE(BE16, "be", F4b, 0, 0) +DEFINE_EASY_OPCODE(BNE8, "bne", F4a, 0, 0) +DEFINE_EASY_OPCODE(BNE16, "bne", F4b, 0, 0) +DEFINE_EASY_OPCODE(BV8, "bv", F4a, 0, 0) +DEFINE_EASY_OPCODE(BV16, "bv", F4b, 0, 0) +DEFINE_EASY_OPCODE(BNV8, "bnv", F4a, 0, 0) +DEFINE_EASY_OPCODE(BNV16, "bnv", F4b, 0, 0) +DEFINE_EASY_OPCODE(BN8, "bn", F4a, 0, 0) +DEFINE_EASY_OPCODE(BN16, "bn", F4b, 0, 0) +DEFINE_EASY_OPCODE(BP8, "bp", F4a, 0, 0) +DEFINE_EASY_OPCODE(BP16, "bp", F4b, 0, 0) +DEFINE_EASY_OPCODE(BR8, "br", F4a, 0, 0) +DEFINE_EASY_OPCODE(BR16, "br", F4b, 0, 0) +DEFINE_EASY_OPCODE(BRK, "brk", F5, 0, 0) +DEFINE_EASY_OPCODE(BRKV, "brkv", F5, 0, 0) +DEFINE_EASY_OPCODE_EX(BSR, "bsr", F4b, 0, 0, DASMFLAG_STEP_OVER) +DEFINE_EASY_OPCODE_EX(CALL, "call", F1F2, 0, 2, DASMFLAG_STEP_OVER) +DEFINE_EASY_OPCODE(CAXI, "caxi", F1, 2, 2) +DEFINE_EASY_OPCODE(CHKAR, "chkar", F1F2, 0, 0) // ? +DEFINE_EASY_OPCODE(CHKAW, "chkaw", F1F2, 0, 0) // ? +DEFINE_EASY_OPCODE(CHKAE, "chkae", F1F2, 0, 0) +DEFINE_EASY_OPCODE(CHLVL, "chlvl", F1F2, 0, 0) +DEFINE_EASY_OPCODE(CLR1, "clr1", F1F2, 2, 2) +DEFINE_EASY_OPCODE(CLRTLB, "clrtlb", F3, 0, 0) // ? +DEFINE_EASY_OPCODE(CLRTLBA, "clrtlba", F5, 0, 0) +DEFINE_TRIPLE_OPCODE(CMP, "cmp", F1F2) +DEFINE_EASY_OPCODE(CMPBFS, "cmpbfs", F7b, 0x82, 2) +DEFINE_EASY_OPCODE(CMPBFZ, "cmpbfz", F7b, 0x82, 2) +DEFINE_EASY_OPCODE(CMPBFL, "cmpbfl", F7b, 0x82, 2) +DEFINE_DOUBLE_OPCODE(CMPC, "cmpc", F7a) +DEFINE_DOUBLE_OPCODE(CMPCF, "cmpcf", F7a) +DEFINE_DOUBLE_OPCODE(CMPCS, "cmpcs", F7a) +DEFINE_FPU_OPCODE(CMPF, "cmpf", F2) +DEFINE_EASY_OPCODE(CVTSL, "cvt.sl", F2, 0, 1) +DEFINE_EASY_OPCODE(CVTLS, "cvt.ls", F2, 1, 0) +DEFINE_EASY_OPCODE(CVTWS, "cvt.ws", F2, 2, 0) +DEFINE_EASY_OPCODE(CVTWL, "cvt.wl", F2, 2, 1) +DEFINE_EASY_OPCODE(CVTSW, "cvt.sw", F2, 0, 2) +DEFINE_EASY_OPCODE(CVTLW, "cvt.lw", F2, 1, 2) +DEFINE_EASY_OPCODE(CVTDPZ, "cvtd.pz", F7c, 0, 1) +DEFINE_EASY_OPCODE(CVTDZP, "cvtd.zp", F7c, 1, 0) +DEFINE_EASY_OPCODE_EX(DBGT, "dbgt", F6, 0, 0, DASMFLAG_STEP_OVER) +DEFINE_EASY_OPCODE_EX(DBGE, "dbge", F6, 0, 0, DASMFLAG_STEP_OVER) +DEFINE_EASY_OPCODE_EX(DBLT, "dbgt", F6, 0, 0, DASMFLAG_STEP_OVER) +DEFINE_EASY_OPCODE_EX(DBLE, "dbge", F6, 0, 0, DASMFLAG_STEP_OVER) +DEFINE_EASY_OPCODE_EX(DBH, "dbh", F6, 0, 0, DASMFLAG_STEP_OVER) +DEFINE_EASY_OPCODE_EX(DBNL, "dbnl", F6, 0, 0, DASMFLAG_STEP_OVER) +DEFINE_EASY_OPCODE_EX(DBL, "dbl", F6, 0, 0, DASMFLAG_STEP_OVER) +DEFINE_EASY_OPCODE_EX(DBNH, "dbnh", F6, 0, 0, DASMFLAG_STEP_OVER) +DEFINE_EASY_OPCODE_EX(DBE, "dbe", F6, 0, 0, DASMFLAG_STEP_OVER) +DEFINE_EASY_OPCODE_EX(DBNE, "dbne", F6, 0, 0, DASMFLAG_STEP_OVER) +DEFINE_EASY_OPCODE_EX(DBV, "dbe", F6, 0, 0, DASMFLAG_STEP_OVER) +DEFINE_EASY_OPCODE_EX(DBNV, "dbne", F6, 0, 0, DASMFLAG_STEP_OVER) +DEFINE_EASY_OPCODE_EX(DBN, "dbn", F6, 0, 0, DASMFLAG_STEP_OVER) +DEFINE_EASY_OPCODE_EX(DBP, "dbp", F6, 0, 0, DASMFLAG_STEP_OVER) +DEFINE_EASY_OPCODE_EX(DBR, "dbr", F6, 0, 0, DASMFLAG_STEP_OVER) +DEFINE_TRIPLE_OPCODE(DEC, "dec", F3) +DEFINE_EASY_OPCODE(DISPOSE, "dispose", F5, 0, 0) +DEFINE_TRIPLE_OPCODE(DIV, "div", F1F2) +DEFINE_FPU_OPCODE(DIVF, "divf", F2) +DEFINE_TRIPLE_OPCODE(DIVU, "divu", F1F2) +DEFINE_EASY_OPCODE(DIVX, "divx", F1F2, 2, 3) +DEFINE_EASY_OPCODE(DIVUX, "divux", F1F2, 2, 3) +DEFINE_EASY_OPCODE(EXTBFS, "extbfs", F7b, 0x82, 2) +DEFINE_EASY_OPCODE(EXTBFZ, "extbfz", F7b, 0x82, 2) +DEFINE_EASY_OPCODE(EXTBFL, "extbfl", F7b, 0x82, 2) +DEFINE_EASY_OPCODE(GETATE, "getate", F1F2, 0, 3) // ? +DEFINE_EASY_OPCODE(GETPSW, "getpsw", F3, 2, 0) +DEFINE_EASY_OPCODE(GETPTE, "getpte", F1F2, 0, 2) // ? +DEFINE_EASY_OPCODE(GETRA, "getra", F1F2, 0, 2) // ? +DEFINE_EASY_OPCODE(HALT, "halt", F5, 0, 0) +DEFINE_TRIPLE_OPCODE(IN, "in", F1F2) +DEFINE_TRIPLE_OPCODE(INC, "inc", F3) +DEFINE_EASY_OPCODE(INSBFL, "insbfl", F7c, 2, 0x82) +DEFINE_EASY_OPCODE(INSBFR, "insbfr", F7c, 2, 0x82) +DEFINE_EASY_OPCODE(JMP, "jmp", F3, 0, 0) +DEFINE_EASY_OPCODE_EX(JSR, "jsr", F3, 0, 0, DASMFLAG_STEP_OVER) +DEFINE_EASY_OPCODE(LDPR, "ldpr", F1F2, 2, 2) +DEFINE_EASY_OPCODE(LDTASK, "ldtask", F1F2, 2, 2) +DEFINE_TRIPLE_OPCODE(MOV, "mov", F1F2) +DEFINE_EASY_OPCODE(MOVBSU, "movbsu", F7b, 0x80, 0x80) +DEFINE_EASY_OPCODE(MOVBSD, "movbsd", F7b, 0x80, 0x80) +DEFINE_DOUBLE_OPCODE(MOVCU, "movcu", F7a) +DEFINE_DOUBLE_OPCODE(MOVCD, "movcd", F7a) +DEFINE_DOUBLE_OPCODE(MOVCFU, "movcfu", F7a) +DEFINE_DOUBLE_OPCODE(MOVCFD, "movcfd", F7a) +DEFINE_DOUBLE_OPCODE(MOVCS, "movcs", F7a) +DEFINE_EASY_OPCODE(MOVD, "mov.d", F1F2, 3, 3) +DEFINE_EASY_OPCODE(MOVEAB, "movea.b", F1F2, 0, 2) +DEFINE_EASY_OPCODE(MOVEAH, "movea.h", F1F2, 1, 2) +DEFINE_EASY_OPCODE(MOVEAW, "movea.w", F1F2, 2, 2) +DEFINE_FPU_OPCODE(MOVF, "movf", F2) +DEFINE_EASY_OPCODE(MOVSBH, "movs.bh", F1F2, 0, 1) +DEFINE_EASY_OPCODE(MOVSBW, "movs.bw", F1F2, 0, 2) +DEFINE_EASY_OPCODE(MOVSHW, "movs.hw", F1F2, 1, 2) +DEFINE_EASY_OPCODE(MOVTHB, "movt.hb", F1F2, 1, 0) +DEFINE_EASY_OPCODE(MOVTWB, "movt.wb", F1F2, 2, 0) +DEFINE_EASY_OPCODE(MOVTWH, "movt.wh", F1F2, 2, 1) +DEFINE_EASY_OPCODE(MOVZBH, "movz.bh", F1F2, 0, 1) +DEFINE_EASY_OPCODE(MOVZBW, "movz.bw", F1F2, 0, 2) +DEFINE_EASY_OPCODE(MOVZHW, "movz.hw", F1F2, 1, 2) +DEFINE_TRIPLE_OPCODE(MUL, "mul", F1F2) +DEFINE_FPU_OPCODE(MULF, "mulf", F2) +DEFINE_TRIPLE_OPCODE(MULU, "mulu", F1F2) +DEFINE_EASY_OPCODE(MULX, "mulx", F1F2, 2, 3) +DEFINE_EASY_OPCODE(MULUX, "mulux", F1F2, 2, 3) +DEFINE_TRIPLE_OPCODE(NEG, "neg", F1F2) +DEFINE_FPU_OPCODE(NEGF, "negf", F2) +DEFINE_EASY_OPCODE(NOP, "nop", F5, 0, 0) +DEFINE_TRIPLE_OPCODE(NOT, "not", F1F2) +DEFINE_EASY_OPCODE(NOT1, "not1", F1F2, 2, 2) +DEFINE_EASY_OPCODE(NOTBSU, "notbsu", F7b, 0x80, 0x80) +DEFINE_EASY_OPCODE(NOTBSD, "notbsd", F7b, 0x80, 0x80) +DEFINE_TRIPLE_OPCODE(OR, "or", F1F2) +DEFINE_EASY_OPCODE(ORBSU, "orbsu", F7b, 0x80, 0x80) +DEFINE_EASY_OPCODE(ORBSD, "orbsd", F7b, 0x80, 0x80) +DEFINE_EASY_OPCODE(ORNBSU, "ornbsu", F7b, 0x80, 0x80) +DEFINE_EASY_OPCODE(ORNBSD, "ornbsd", F7b, 0x80, 0x80) +DEFINE_TRIPLE_OPCODE(OUT, "out", F1F2) +DEFINE_EASY_OPCODE(POP, "pop", F3, 2, 0) +DEFINE_EASY_OPCODE(POPM, "popm", F3, 2, 0) +DEFINE_EASY_OPCODE(PREPARE, "prepare", F3, 2, 0) +DEFINE_EASY_OPCODE(PUSH, "push", F3, 2, 0) +DEFINE_EASY_OPCODE(PUSHM, "pushm", F3, 2, 0) +DEFINE_TRIPLE_OPCODE(REM, "rem", F1F2) +DEFINE_TRIPLE_OPCODE(REMU, "remu", F1F2) +DEFINE_EASY_OPCODE_EX(RET, "ret", F3, 2, 0, DASMFLAG_STEP_OUT) +DEFINE_EASY_OPCODE_EX(RETIU, "retiu", F3, 1, 0, DASMFLAG_STEP_OUT) +DEFINE_EASY_OPCODE_EX(RETIS, "retis", F3, 1, 0, DASMFLAG_STEP_OUT) +DEFINE_EASY_OPCODE(ROTB, "rot.b", F1F2, 0, 0) +DEFINE_EASY_OPCODE(ROTH, "rot.h", F1F2, 0, 1) +DEFINE_EASY_OPCODE(ROTW, "rot.w", F1F2, 0, 2) +DEFINE_EASY_OPCODE(ROTCB, "rotc.b", F1F2, 0, 0) +DEFINE_EASY_OPCODE(ROTCH, "rotc.h", F1F2, 0, 1) +DEFINE_EASY_OPCODE(ROTCW, "rotc.w", F1F2, 0, 2) +DEFINE_EASY_OPCODE_EX(RSR, "rsr", F5, 0, 0, DASMFLAG_STEP_OUT) +DEFINE_EASY_OPCODE(RVBIT, "rvbit", F1F2, 0, 0) +DEFINE_EASY_OPCODE(RVBYT, "rvbyt", F1F2, 2, 2) +DEFINE_EASY_OPCODE(SCH0BSU, "sch0bsu", F7b, 0x80, 2) +DEFINE_EASY_OPCODE(SCH0BSD, "sch0bsd", F7b, 0x80, 2) +DEFINE_EASY_OPCODE(SCH1BSU, "sch1bsu", F7b, 0x80, 2) +DEFINE_EASY_OPCODE(SCH1BSD, "sch1bsd", F7b, 0x80, 2) +DEFINE_EASY_OPCODE(SCHCUB, "schcu.b", F7b, 0, 0) +DEFINE_EASY_OPCODE(SCHCDB, "schcd.b", F7b, 0, 0) +DEFINE_EASY_OPCODE(SCHCUH, "schcu.h", F7b, 1, 1) +DEFINE_EASY_OPCODE(SCHCDH, "schcd.h", F7b, 1, 1) +DEFINE_EASY_OPCODE(SCLFS, "sclf.s", F2, 1, 2) +DEFINE_EASY_OPCODE(SCLFL, "sclf.l", F2, 1, 2) +DEFINE_EASY_OPCODE(SET1, "set1", F1F2, 2, 2) +DEFINE_EASY_OPCODE(SETF, "setf", F1F2, 0, 0) +DEFINE_EASY_OPCODE(SHAB, "sha.b", F1F2, 0, 0) +DEFINE_EASY_OPCODE(SHAH, "sha.h", F1F2, 0, 1) +DEFINE_EASY_OPCODE(SHAW, "sha.w", F1F2, 0, 2) +DEFINE_EASY_OPCODE(SHLB, "shl.b", F1F2, 0, 0) +DEFINE_EASY_OPCODE(SHLH, "shl.h", F1F2, 0, 1) +DEFINE_EASY_OPCODE(SHLW, "shl.w", F1F2, 0, 2) +DEFINE_EASY_OPCODE(SKPCUB, "skpcu.b", F7b, 0, 0) +DEFINE_EASY_OPCODE(SKPCDB, "skpcd.b", F7b, 0, 0) +DEFINE_EASY_OPCODE(SKPCUH, "skpcu.h", F7b, 1, 1) +DEFINE_EASY_OPCODE(SKPCDH, "skpcd.h", F7b, 1, 1) +DEFINE_EASY_OPCODE(STPR, "stpr", F1F2, 2, 2) +DEFINE_EASY_OPCODE(STTASK, "sttask", F3, 2, 0) +DEFINE_TRIPLE_OPCODE(SUB, "sub", F1F2) +DEFINE_TRIPLE_OPCODE(SUBC, "subc", F1F2) +DEFINE_EASY_OPCODE(SUBDC, "subdc", F7c, 0, 0) +DEFINE_EASY_OPCODE(SUBRDC, "subrdc", F7c, 0, 0) +DEFINE_FPU_OPCODE(SUBF, "subf", F2) +DEFINE_EASY_OPCODE(TASI, "tasi", F3, 0, 0) +DEFINE_EASY_OPCODE(TB, "tb", F6, 0, 0) +DEFINE_TRIPLE_OPCODE(TEST, "test", F3) +DEFINE_EASY_OPCODE(TEST1, "test1", F1F2, 2, 2) +DEFINE_EASY_OPCODE_EX(TRAP, "trap", F3, 0, 0, DASMFLAG_STEP_OVER) +DEFINE_EASY_OPCODE(TRAPFL, "trapfl", F5, 0, 0) +DEFINE_EASY_OPCODE(UPDATE, "update", F1F2, 0, 3) // ? +DEFINE_EASY_OPCODE(UPDPSWH, "updpsw.h", F1F2, 2, 2) +DEFINE_EASY_OPCODE(UPDPSWW, "updpsw.w", F1F2, 2, 2) +DEFINE_EASY_OPCODE(UPDPTE, "updpte", F1F2, 0, 2) // ? +DEFINE_TRIPLE_OPCODE(XCH, "xch", F1) +DEFINE_TRIPLE_OPCODE(XOR, "xor", F1F2) +DEFINE_EASY_OPCODE(XORBSU, "xorbsu", F7b, 0x80, 0x80) +DEFINE_EASY_OPCODE(XORBSD, "xorbsd", F7b, 0x80, 0x80) +DEFINE_EASY_OPCODE(XORNBSU, "xornbsu", F7b, 0x80, 0x80) +DEFINE_EASY_OPCODE(XORNBSD, "xornbsd", F7b, 0x80, 0x80) + +static int (*const dasm_optable_58[32])(unsigned ipc, unsigned pc, char *out) = +{ + /* 0x00 */ dopCMPCB, + /* 0x01 */ dopCMPCFB, + /* 0x02 */ dopCMPCSB, + /* 0x03 */ dop58UNHANDLED, + /* 0x04 */ dop58UNHANDLED, + /* 0x05 */ dop58UNHANDLED, + /* 0x06 */ dop58UNHANDLED, + /* 0x07 */ dop58UNHANDLED, + /* 0x08 */ dopMOVCUB, + /* 0x09 */ dopMOVCDB, + /* 0x0A */ dopMOVCFUB, + /* 0x0B */ dopMOVCFDB, + /* 0x0C */ dopMOVCSB, + /* 0x0D */ dop58UNHANDLED, + /* 0x0E */ dop58UNHANDLED, + /* 0x0F */ dop58UNHANDLED, + /* 0x10 */ dop58UNHANDLED, + /* 0x11 */ dop58UNHANDLED, + /* 0x12 */ dop58UNHANDLED, + /* 0x13 */ dop58UNHANDLED, + /* 0x14 */ dop58UNHANDLED, + /* 0x15 */ dop58UNHANDLED, + /* 0x16 */ dop58UNHANDLED, + /* 0x17 */ dop58UNHANDLED, + /* 0x18 */ dopSCHCUB, + /* 0x19 */ dopSCHCDB, + /* 0x1A */ dopSKPCUB, + /* 0x1B */ dopSKPCDB, + /* 0x1C */ dop58UNHANDLED, + /* 0x1D */ dop58UNHANDLED, + /* 0x1E */ dop58UNHANDLED, + /* 0x1F */ dop58UNHANDLED +}; + +static int (*const dasm_optable_59[32])(unsigned ipc, unsigned pc, char *out) = +{ + /* 0x00 */ dopADDDC, + /* 0x01 */ dopSUBDC, + /* 0x02 */ dopSUBRDC, + /* 0x03 */ dop59UNHANDLED, + /* 0x04 */ dop59UNHANDLED, + /* 0x05 */ dop59UNHANDLED, + /* 0x06 */ dop59UNHANDLED, + /* 0x07 */ dop59UNHANDLED, + /* 0x08 */ dop59UNHANDLED, + /* 0x09 */ dop59UNHANDLED, + /* 0x0A */ dop59UNHANDLED, + /* 0x0B */ dop59UNHANDLED, + /* 0x0C */ dop59UNHANDLED, + /* 0x0D */ dop59UNHANDLED, + /* 0x0E */ dop59UNHANDLED, + /* 0x0F */ dop59UNHANDLED, + /* 0x10 */ dopCVTDPZ, + /* 0x11 */ dop59UNHANDLED, + /* 0x12 */ dop59UNHANDLED, + /* 0x13 */ dop59UNHANDLED, + /* 0x14 */ dop59UNHANDLED, + /* 0x15 */ dop59UNHANDLED, + /* 0x16 */ dop59UNHANDLED, + /* 0x17 */ dop59UNHANDLED, + /* 0x18 */ dopCVTDZP, + /* 0x19 */ dop59UNHANDLED, + /* 0x1A */ dop59UNHANDLED, + /* 0x1B */ dop59UNHANDLED, + /* 0x1C */ dop59UNHANDLED, + /* 0x1D */ dop59UNHANDLED, + /* 0x1E */ dop59UNHANDLED, + /* 0x1F */ dop59UNHANDLED +}; + +static int (*const dasm_optable_5A[32])(unsigned ipc, unsigned pc, char *out) = +{ + /* 0x00 */ dopCMPCH, + /* 0x01 */ dopCMPCFH, + /* 0x02 */ dopCMPCSH, + /* 0x03 */ dop5AUNHANDLED, + /* 0x04 */ dop5AUNHANDLED, + /* 0x05 */ dop5AUNHANDLED, + /* 0x06 */ dop5AUNHANDLED, + /* 0x07 */ dop5AUNHANDLED, + /* 0x08 */ dopMOVCUH, + /* 0x09 */ dopMOVCDH, + /* 0x0A */ dopMOVCFUH, + /* 0x0B */ dopMOVCFDH, + /* 0x0C */ dopMOVCSH, + /* 0x0D */ dop5AUNHANDLED, + /* 0x0E */ dop5AUNHANDLED, + /* 0x0F */ dop5AUNHANDLED, + /* 0x10 */ dop5AUNHANDLED, + /* 0x11 */ dop5AUNHANDLED, + /* 0x12 */ dop5AUNHANDLED, + /* 0x13 */ dop5AUNHANDLED, + /* 0x14 */ dop5AUNHANDLED, + /* 0x15 */ dop5AUNHANDLED, + /* 0x16 */ dop5AUNHANDLED, + /* 0x17 */ dop5AUNHANDLED, + /* 0x18 */ dopSCHCUH, + /* 0x19 */ dopSCHCDH, + /* 0x1A */ dopSKPCUH, + /* 0x1B */ dopSKPCDH, + /* 0x1C */ dop5AUNHANDLED, + /* 0x1D */ dop5AUNHANDLED, + /* 0x1E */ dop5AUNHANDLED, + /* 0x1F */ dop5AUNHANDLED +}; + +static int (*const dasm_optable_5B[32])(unsigned ipc, unsigned pc, char *out) = +{ + /* 0x00 */ dopSCH0BSU, + /* 0x01 */ dopSCH0BSD, + /* 0x02 */ dopSCH1BSU, + /* 0x03 */ dopSCH1BSD, + /* 0x04 */ dop5BUNHANDLED, + /* 0x05 */ dop5BUNHANDLED, + /* 0x06 */ dop5BUNHANDLED, + /* 0x07 */ dop5BUNHANDLED, + /* 0x08 */ dopMOVBSU, + /* 0x09 */ dopMOVBSD, + /* 0x0A */ dopNOTBSU, + /* 0x0B */ dopNOTBSD, + /* 0x0C */ dop5BUNHANDLED, + /* 0x0D */ dop5BUNHANDLED, + /* 0x0E */ dop5BUNHANDLED, + /* 0x0F */ dop5BUNHANDLED, + /* 0x10 */ dopANDBSU, + /* 0x11 */ dopANDBSD, + /* 0x12 */ dopANDNBSU, + /* 0x13 */ dopANDNBSD, + /* 0x14 */ dopORBSU, + /* 0x15 */ dopORBSD, + /* 0x16 */ dopORNBSU, + /* 0x17 */ dopORNBSD, + /* 0x18 */ dopXORBSU, + /* 0x19 */ dopXORBSD, + /* 0x1A */ dopXORNBSU, + /* 0x1B */ dopXORNBSD, + /* 0x1C */ dop5BUNHANDLED, + /* 0x1D */ dop5BUNHANDLED, + /* 0x1E */ dop5BUNHANDLED, + /* 0x1F */ dop5BUNHANDLED +}; + +static int (*const dasm_optable_5C[32])(unsigned ipc, unsigned pc, char *out) = +{ + /* 0x00 */ dopCMPFS, + /* 0x01 */ dop5CUNHANDLED, + /* 0x02 */ dop5CUNHANDLED, + /* 0x03 */ dop5CUNHANDLED, + /* 0x04 */ dop5CUNHANDLED, + /* 0x05 */ dop5CUNHANDLED, + /* 0x06 */ dop5CUNHANDLED, + /* 0x07 */ dop5CUNHANDLED, + /* 0x08 */ dopMOVFS, + /* 0x09 */ dopNEGFS, + /* 0x0A */ dopABSFS, + /* 0x0B */ dop5CUNHANDLED, + /* 0x0C */ dop5CUNHANDLED, + /* 0x0D */ dop5CUNHANDLED, + /* 0x0E */ dop5CUNHANDLED, + /* 0x0F */ dop5CUNHANDLED, + /* 0x10 */ dopSCLFS, + /* 0x11 */ dop5CUNHANDLED, + /* 0x12 */ dop5CUNHANDLED, + /* 0x13 */ dop5CUNHANDLED, + /* 0x14 */ dop5CUNHANDLED, + /* 0x15 */ dop5CUNHANDLED, + /* 0x16 */ dop5CUNHANDLED, + /* 0x17 */ dop5CUNHANDLED, + /* 0x18 */ dopADDFS, + /* 0x19 */ dopSUBFS, + /* 0x1A */ dopMULFS, + /* 0x1B */ dopDIVFS, + /* 0x1C */ dop5CUNHANDLED, + /* 0x1D */ dop5CUNHANDLED, + /* 0x1E */ dop5CUNHANDLED, + /* 0x1F */ dop5CUNHANDLED +}; + +static int (*const dasm_optable_5D[32])(unsigned ipc, unsigned pc, char *out) = +{ + /* 0x00 */ dopCMPBFS, + /* 0x01 */ dopCMPBFZ, + /* 0x02 */ dopCMPBFL, + /* 0x03 */ dop5DUNHANDLED, + /* 0x04 */ dop5DUNHANDLED, + /* 0x05 */ dop5DUNHANDLED, + /* 0x06 */ dop5DUNHANDLED, + /* 0x07 */ dop5DUNHANDLED, + /* 0x08 */ dopEXTBFS, + /* 0x09 */ dopEXTBFZ, + /* 0x0A */ dopEXTBFL, + /* 0x0B */ dop5DUNHANDLED, + /* 0x0C */ dop5DUNHANDLED, + /* 0x0D */ dop5DUNHANDLED, + /* 0x0E */ dop5DUNHANDLED, + /* 0x0F */ dop5DUNHANDLED, + /* 0x10 */ dop5DUNHANDLED, + /* 0x11 */ dop5DUNHANDLED, + /* 0x12 */ dop5DUNHANDLED, + /* 0x13 */ dop5DUNHANDLED, + /* 0x14 */ dop5DUNHANDLED, + /* 0x15 */ dop5DUNHANDLED, + /* 0x16 */ dop5DUNHANDLED, + /* 0x17 */ dop5DUNHANDLED, + /* 0x18 */ dopINSBFR, + /* 0x19 */ dopINSBFL, + /* 0x1A */ dop5DUNHANDLED, + /* 0x1B */ dop5DUNHANDLED, + /* 0x1C */ dop5DUNHANDLED, + /* 0x1D */ dop5DUNHANDLED, + /* 0x1E */ dop5DUNHANDLED, + /* 0x1F */ dop5DUNHANDLED +}; + +static int (*const dasm_optable_5E[32])(unsigned ipc, unsigned pc, char *out) = +{ + /* 0x00 */ dopCMPFL, + /* 0x01 */ dop5EUNHANDLED, + /* 0x02 */ dop5EUNHANDLED, + /* 0x03 */ dop5EUNHANDLED, + /* 0x04 */ dop5EUNHANDLED, + /* 0x05 */ dop5EUNHANDLED, + /* 0x06 */ dop5EUNHANDLED, + /* 0x07 */ dop5EUNHANDLED, + /* 0x08 */ dopMOVFL, + /* 0x09 */ dopNEGFL, + /* 0x0A */ dopABSFL, + /* 0x0B */ dop5EUNHANDLED, + /* 0x0C */ dop5EUNHANDLED, + /* 0x0D */ dop5EUNHANDLED, + /* 0x0E */ dop5EUNHANDLED, + /* 0x0F */ dop5EUNHANDLED, + /* 0x10 */ dopSCLFL, + /* 0x11 */ dop5EUNHANDLED, + /* 0x12 */ dop5EUNHANDLED, + /* 0x13 */ dop5EUNHANDLED, + /* 0x14 */ dop5EUNHANDLED, + /* 0x15 */ dop5EUNHANDLED, + /* 0x16 */ dop5EUNHANDLED, + /* 0x17 */ dop5EUNHANDLED, + /* 0x18 */ dopADDFL, + /* 0x19 */ dopSUBFL, + /* 0x1A */ dopMULFL, + /* 0x1B */ dopDIVFL, + /* 0x1C */ dop5EUNHANDLED, + /* 0x1D */ dop5EUNHANDLED, + /* 0x1E */ dop5EUNHANDLED, + /* 0x1F */ dop5EUNHANDLED +}; + +static int (*const dasm_optable_5F[32])(unsigned ipc, unsigned pc, char *out) = +{ + /* 0x00 */ dopCVTWS, + /* 0x01 */ dopCVTSW, + /* 0x02 */ dop5FUNHANDLED, + /* 0x03 */ dop5FUNHANDLED, + /* 0x04 */ dop5FUNHANDLED, + /* 0x05 */ dop5FUNHANDLED, + /* 0x06 */ dop5FUNHANDLED, + /* 0x07 */ dop5FUNHANDLED, + /* 0x08 */ dopCVTLS, + /* 0x09 */ dopCVTLW, + /* 0x0A */ dop5FUNHANDLED, + /* 0x0B */ dop5FUNHANDLED, + /* 0x0C */ dop5FUNHANDLED, + /* 0x0D */ dop5FUNHANDLED, + /* 0x0E */ dop5FUNHANDLED, + /* 0x0F */ dop5FUNHANDLED, + /* 0x10 */ dopCVTSL, + /* 0x11 */ dopCVTWL, + /* 0x12 */ dop5FUNHANDLED, + /* 0x13 */ dop5FUNHANDLED, + /* 0x14 */ dop5FUNHANDLED, + /* 0x15 */ dop5FUNHANDLED, + /* 0x16 */ dop5FUNHANDLED, + /* 0x17 */ dop5FUNHANDLED, + /* 0x18 */ dop5FUNHANDLED, + /* 0x19 */ dop5FUNHANDLED, + /* 0x1A */ dop5FUNHANDLED, + /* 0x1B */ dop5FUNHANDLED, + /* 0x1C */ dop5FUNHANDLED, + /* 0x1D */ dop5FUNHANDLED, + /* 0x1E */ dop5FUNHANDLED, + /* 0x1F */ dop5FUNHANDLED +}; + +static int (*const dasm_optable_C6[8])(unsigned ipc, unsigned pc, char *out) = +{ + /* 0x0 */ dopDBV, + /* 0x1 */ dopDBL, + /* 0x2 */ dopDBE, + /* 0x3 */ dopDBNH, + /* 0x4 */ dopDBN, + /* 0x5 */ dopDBR, + /* 0x6 */ dopDBLT, + /* 0x7 */ dopDBLE +}; + +static int (*const dasm_optable_C7[8])(unsigned ipc, unsigned pc, char *out) = +{ + /* 0x0 */ dopDBNV, + /* 0x1 */ dopDBNL, + /* 0x2 */ dopDBNE, + /* 0x3 */ dopDBH, + /* 0x4 */ dopDBP, + /* 0x5 */ dopTB, + /* 0x6 */ dopDBGE, + /* 0x7 */ dopDBGT +}; + +static int dop58(unsigned ipc, unsigned pc, char *out) +{ + return dasm_optable_58[readop(pc) & 0x1f](ipc, pc, out); +} + +static int dop59(unsigned ipc, unsigned pc, char *out) +{ + return dasm_optable_59[readop(pc) & 0x1f](ipc, pc, out); +} + +static int dop5A(unsigned ipc, unsigned pc, char *out) +{ + return dasm_optable_5A[readop(pc) & 0x1f](ipc, pc, out); +} + +static int dop5B(unsigned ipc, unsigned pc, char *out) +{ + return dasm_optable_5B[readop(pc) & 0x1f](ipc, pc, out); +} + +static int dop5C(unsigned ipc, unsigned pc, char *out) +{ + return dasm_optable_5C[readop(pc) & 0x1f](ipc, pc, out); +} + +static int dop5D(unsigned ipc, unsigned pc, char *out) +{ + return dasm_optable_5D[readop(pc) & 0x1f](ipc, pc, out); +} + +static int dop5E(unsigned ipc, unsigned pc, char *out) +{ + return dasm_optable_5E[readop(pc) & 0x1f](ipc, pc, out); +} + +static int dop5F(unsigned ipc, unsigned pc, char *out) +{ + return dasm_optable_5F[readop(pc) & 0x1f](ipc, pc, out); +} + +static int dopC6(unsigned ipc, unsigned pc, char *out) +{ + return dasm_optable_C6[readop(pc) >> 5](ipc, pc, out); +} + +static int dopC7(unsigned ipc, unsigned pc, char *out) +{ + return dasm_optable_C7[readop(pc) >> 5](ipc, pc, out); +} + +static int (*const dasm_optable[256])(unsigned ipc, unsigned pc, char *out) = +{ + /* 0x00 */ dopHALT, + /* 0x01 */ dopLDTASK, + /* 0x02 */ dopSTPR, + /* 0x03 */ dopGETRA, + /* 0x04 */ dopGETPTE, + /* 0x05 */ dopGETATE, + /* 0x06 */ dopUNHANDLED, + /* 0x07 */ dopUNHANDLED, + /* 0x08 */ dopRVBIT, + /* 0x09 */ dopMOVB, + /* 0x0A */ dopMOVSBH, + /* 0x0B */ dopMOVZBH, + /* 0x0C */ dopMOVSBW, + /* 0x0D */ dopMOVZBW, + /* 0x0E */ dopUNHANDLED, + /* 0x0F */ dopUNHANDLED, + /* 0x10 */ dopCLRTLBA, + /* 0x11 */ dopUNHANDLED, + /* 0x12 */ dopLDPR, + /* 0x13 */ dopUPDPSWW, + /* 0x14 */ dopUPDPTE, + /* 0x15 */ dopUPDATE, + /* 0x16 */ dopUNHANDLED, + /* 0x17 */ dopUNHANDLED, + /* 0x18 */ dopUNHANDLED, + /* 0x19 */ dopMOVTHB, + /* 0x1A */ dopUNHANDLED, + /* 0x1B */ dopMOVH, + /* 0x1C */ dopMOVSHW, + /* 0x1D */ dopMOVZHW, + /* 0x1E */ dopUNHANDLED, + /* 0x1F */ dopUNHANDLED, + /* 0x20 */ dopINB, + /* 0x21 */ dopOUTB, + /* 0x22 */ dopINH, + /* 0x23 */ dopOUTH, + /* 0x24 */ dopINW, + /* 0x25 */ dopOUTW, + /* 0x26 */ dopUNHANDLED, + /* 0x27 */ dopUNHANDLED, + /* 0x28 */ dopUNHANDLED, + /* 0x29 */ dopMOVTWB, + /* 0x2A */ dopUNHANDLED, + /* 0x2B */ dopMOVTWH, + /* 0x2C */ dopRVBYT, + /* 0x2D */ dopMOVW, + /* 0x2E */ dopUNHANDLED, + /* 0x2F */ dopUNHANDLED, + /* 0x30 */ dopUNHANDLED, + /* 0x31 */ dopUNHANDLED, + /* 0x32 */ dopUNHANDLED, + /* 0x33 */ dopUNHANDLED, + /* 0x34 */ dopUNHANDLED, + /* 0x35 */ dopUNHANDLED, + /* 0x36 */ dopUNHANDLED, + /* 0x37 */ dopUNHANDLED, + /* 0x38 */ dopNOTB, + /* 0x39 */ dopNEGB, + /* 0x3A */ dopNOTH, + /* 0x3B */ dopNEGH, + /* 0x3C */ dopNOTW, + /* 0x3D */ dopNEGW, + /* 0x3E */ dopUNHANDLED, + /* 0x3F */ dopMOVD, + /* 0x40 */ dopMOVEAB, + /* 0x41 */ dopXCHB, + /* 0x42 */ dopMOVEAH, + /* 0x43 */ dopXCHH, + /* 0x44 */ dopMOVEAW, + /* 0x45 */ dopXCHW, + /* 0x46 */ dopUNHANDLED, + /* 0x47 */ dopSETF, + /* 0x48 */ dopBSR, + /* 0x49 */ dopCALL, + /* 0x4A */ dopUPDPSWH, + /* 0x4B */ dopCHLVL, + /* 0x4C */ dopCAXI, + /* 0x4D */ dopCHKAR, + /* 0x4E */ dopCHKAW, + /* 0x4F */ dopCHKAE, + /* 0x50 */ dopREMB, + /* 0x51 */ dopREMUB, + /* 0x52 */ dopREMH, + /* 0x53 */ dopREMUH, + /* 0x54 */ dopREMW, + /* 0x55 */ dopREMUW, + /* 0x56 */ dopUNHANDLED, + /* 0x57 */ dopUNHANDLED, + /* 0x58 */ dop58, + /* 0x59 */ dop59, + /* 0x5A */ dop5A, + /* 0x5B */ dop5B, + /* 0x5C */ dop5C, + /* 0x5D */ dop5D, + /* 0x5E */ dop5E, + /* 0x5F */ dop5F, + /* 0x60 */ dopBV8, + /* 0x61 */ dopBNV8, + /* 0x62 */ dopBL8, + /* 0x63 */ dopBNL8, + /* 0x64 */ dopBE8, + /* 0x65 */ dopBNE8, + /* 0x66 */ dopBNH8, + /* 0x67 */ dopBH8, + /* 0x68 */ dopBN8, + /* 0x69 */ dopBP8, + /* 0x6A */ dopBR8, + /* 0x6B */ dopUNHANDLED, + /* 0x6C */ dopBLT8, + /* 0x6D */ dopBGE8, + /* 0x6E */ dopBLE8, + /* 0x6F */ dopBGT8, + /* 0x70 */ dopBV16, + /* 0x71 */ dopBNV16, + /* 0x72 */ dopBL16, + /* 0x73 */ dopBNL16, + /* 0x74 */ dopBE16, + /* 0x75 */ dopBNE16, + /* 0x76 */ dopBNH16, + /* 0x77 */ dopBH16, + /* 0x78 */ dopBN16, + /* 0x79 */ dopBP16, + /* 0x7A */ dopBR16, + /* 0x7B */ dopUNHANDLED, + /* 0x7C */ dopBLT16, + /* 0x7D */ dopBGE16, + /* 0x7E */ dopBLE16, + /* 0x7F */ dopBGT16, + /* 0x80 */ dopADDB, + /* 0x81 */ dopMULB, + /* 0x82 */ dopADDH, + /* 0x83 */ dopMULH, + /* 0x84 */ dopADDW, + /* 0x85 */ dopMULW, + /* 0x86 */ dopMULX, + /* 0x87 */ dopTEST1, + /* 0x88 */ dopORB, + /* 0x89 */ dopROTB, + /* 0x8A */ dopORH, + /* 0x8B */ dopROTH, + /* 0x8C */ dopORW, + /* 0x8D */ dopROTW, + /* 0x8E */ dopUNHANDLED, + /* 0x8F */ dopUNHANDLED, + /* 0x90 */ dopADDCB, + /* 0x91 */ dopMULUB, + /* 0x92 */ dopADDCH, + /* 0x93 */ dopMULUH, + /* 0x94 */ dopADDCW, + /* 0x95 */ dopMULUW, + /* 0x96 */ dopMULUX, + /* 0x97 */ dopSET1, + /* 0x98 */ dopSUBCB, + /* 0x99 */ dopROTCB, + /* 0x9A */ dopSUBCH, + /* 0x9B */ dopROTCH, + /* 0x9C */ dopSUBCW, + /* 0x9D */ dopROTCW, + /* 0x9E */ dopUNHANDLED, + /* 0x9F */ dopUNHANDLED, + /* 0xA0 */ dopANDB, + /* 0xA1 */ dopDIVB, + /* 0xA2 */ dopANDH, + /* 0xA3 */ dopDIVH, + /* 0xA4 */ dopANDW, + /* 0xA5 */ dopDIVW, + /* 0xA6 */ dopDIVX, + /* 0xA7 */ dopCLR1, + /* 0xA8 */ dopSUBB, + /* 0xA9 */ dopSHLB, + /* 0xAA */ dopSUBH, + /* 0xAB */ dopSHLH, + /* 0xAC */ dopSUBW, + /* 0xAD */ dopSHLW, + /* 0xAE */ dopUNHANDLED, + /* 0xAF */ dopUNHANDLED, + /* 0xB0 */ dopXORB, + /* 0xB1 */ dopDIVUB, + /* 0xB2 */ dopXORH, + /* 0xB3 */ dopDIVUH, + /* 0xB4 */ dopXORW, + /* 0xB5 */ dopDIVUW, + /* 0xB6 */ dopDIVUX, + /* 0xB7 */ dopNOT1, + /* 0xB8 */ dopCMPB, + /* 0xB9 */ dopSHAB, + /* 0xBA */ dopCMPH, + /* 0xBB */ dopSHAH, + /* 0xBC */ dopCMPW, + /* 0xBD */ dopSHAW, + /* 0xBE */ dopUNHANDLED, + /* 0xBF */ dopUNHANDLED, + /* 0xC0 */ dopUNHANDLED, + /* 0xC1 */ dopUNHANDLED, + /* 0xC2 */ dopUNHANDLED, + /* 0xC3 */ dopUNHANDLED, + /* 0xC4 */ dopUNHANDLED, + /* 0xC5 */ dopUNHANDLED, + /* 0xC6 */ dopC6, + /* 0xC7 */ dopC7, + /* 0xC8 */ dopBRK, + /* 0xC9 */ dopBRKV, + /* 0xCA */ dopRSR, + /* 0xCB */ dopTRAPFL, + /* 0xCC */ dopDISPOSE, + /* 0xCD */ dopNOP, + /* 0xCE */ dopUNHANDLED, + /* 0xCF */ dopUNHANDLED, + /* 0xD0 */ dopDECB, + /* 0xD1 */ dopDECB, + /* 0xD2 */ dopDECH, + /* 0xD3 */ dopDECH, + /* 0xD4 */ dopDECW, + /* 0xD5 */ dopDECW, + /* 0xD6 */ dopJMP, + /* 0xD7 */ dopJMP, + /* 0xD8 */ dopINCB, + /* 0xD9 */ dopINCB, + /* 0xDA */ dopINCH, + /* 0xDB */ dopINCH, + /* 0xDC */ dopINCW, + /* 0xDD */ dopINCW, + /* 0xDE */ dopPREPARE, + /* 0xDF */ dopPREPARE, + /* 0xE0 */ dopTASI, + /* 0xE1 */ dopTASI, + /* 0xE2 */ dopRET, + /* 0xE3 */ dopRET, + /* 0xE4 */ dopPOPM, + /* 0xE5 */ dopPOPM, + /* 0xE6 */ dopPOP, + /* 0xE7 */ dopPOP, + /* 0xE8 */ dopJSR, + /* 0xE9 */ dopJSR, + /* 0xEA */ dopRETIU, + /* 0xEB */ dopRETIU, + /* 0xEC */ dopPUSHM, + /* 0xED */ dopPUSHM, + /* 0xEE */ dopPUSH, + /* 0xEF */ dopPUSH, + /* 0xF0 */ dopTESTB, + /* 0xF1 */ dopTESTB, + /* 0xF2 */ dopTESTH, + /* 0xF3 */ dopTESTH, + /* 0xF4 */ dopTESTW, + /* 0xF5 */ dopTESTW, + /* 0xF6 */ dopGETPSW, + /* 0xF7 */ dopGETPSW, + /* 0xF8 */ dopTRAP, + /* 0xF9 */ dopTRAP, + /* 0xFA */ dopRETIS, + /* 0xFB */ dopRETIS, + /* 0xFC */ dopSTTASK, + /* 0xFD */ dopSTTASK, + /* 0xFE */ dopCLRTLB, + /* 0xFF */ dopCLRTLB +}; + +CPU_DISASSEMBLE( v60 ) +{ + rombase = oprom; + pcbase = pc; + return dasm_optable[oprom[0]](pc, pc+1, buffer) | DASMFLAG_SUPPORTED; +} + +CPU_DISASSEMBLE( v70 ) +{ + rombase = oprom; + pcbase = pc; + return dasm_optable[oprom[0]](pc, pc+1, buffer) | DASMFLAG_SUPPORTED; +} diff --git a/src/devices/cpu/v810/v810.c b/src/devices/cpu/v810/v810.c new file mode 100644 index 00000000000..fa41ce71986 --- /dev/null +++ b/src/devices/cpu/v810/v810.c @@ -0,0 +1,1395 @@ +// license:LGPL-2.1+ +// copyright-holders:Angelo Salese, Tomasz Slanina +/****************************************************************** + NEC V810 (upd70732) core + Tomasz Slanina - analog[at]op.pl + Angelo Salese - lordkale[at]libero.it + + Change Log + - 23/08/2012 - Implemented remaining BSU opcodes (Angelo Salese) + - 21/08/2012 - Fixed SET.F behaviour (Angelo Salese) + - 20/08/2012 - Fixed a sign bug with CVT.WS opcode (Angelo Salese) + - 16/08/2012 - Added XB, XH, MPYHW, MOVBSU, ORBSU and ANDNBSU opcodes + (Angelo Salese) + - 19/11/2010 - Fixed interrupt handing and flag position in PSW register + (Miodrag Milanovic) + - 18/11/2010 - Added bare bones irq support (Miodrag Milanovic) + - 20/07/2004 - first public release + + + TODO: + - CY flag in few floating point opcodes + (all floating point opcodes are NOT tested!) + - traps/interrupts/exceptions + - bitstring opcodes currently makes the emulation to drop to 0% + - timing + - missing opcodes : trap, caxi + +******************************************************************/ + +#include "emu.h" +#include "debugger.h" +#include "v810.h" + +#define clkIF 3 +#define clkMEM 3 + + +const device_type V810 = &device_creator; + + +v810_device::v810_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : cpu_device(mconfig, V810, "V810", tag, owner, clock, "v810", __FILE__) + , m_program_config("program", ENDIANNESS_LITTLE, 32, 32, 0) + , m_io_config("io", ENDIANNESS_LITTLE, 32, 32, 0) +{ +} + + +offs_t v810_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( v810 ); + return CPU_DISASSEMBLE_NAME(v810)(this, buffer, pc, oprom, opram, options); +} + + +#define R0 m_reg[0] +#define R1 m_reg[1] +#define R2 m_reg[2] +#define SP m_reg[3] +#define R4 m_reg[4] +#define R5 m_reg[5] +#define R6 m_reg[6] +#define R7 m_reg[7] +#define R8 m_reg[8] +#define R9 m_reg[9] +#define R10 m_reg[10] +#define R11 m_reg[11] +#define R12 m_reg[12] +#define R13 m_reg[13] +#define R14 m_reg[14] +#define R15 m_reg[15] +#define R16 m_reg[16] +#define R17 m_reg[17] +#define R18 m_reg[18] +#define R19 m_reg[19] +#define R20 m_reg[20] +#define R21 m_reg[21] +#define R22 m_reg[22] +#define R23 m_reg[23] +#define R24 m_reg[24] +#define R25 m_reg[25] +#define R26 m_reg[26] +#define R27 m_reg[27] +#define R28 m_reg[28] +#define R29 m_reg[29] +#define R30 m_reg[30] +#define R31 m_reg[31] + +#define EIPC m_reg[32] +#define EIPSW m_reg[33] +#define FEPC m_reg[34] +#define FEPSW m_reg[35] +#define ECR m_reg[36] +#define PSW m_reg[37] +#define PIR m_reg[38] +#define TKCW m_reg[39] +#define CHCW m_reg[56] +#define ADTRE m_reg[57] + +#define PC m_reg[64] + +/* Flags */ +#define GET_Z ( PSW & 0x00000001) +#define GET_S ((PSW & 0x00000002)>>1) +#define GET_OV ((PSW & 0x00000004)>>2) +#define GET_CY ((PSW & 0x00000008)>>3) +#define GET_ID ((PSW & 0x00001000)>>12) +#define GET_AE ((PSW & 0x00002000)>>13) +#define GET_EP ((PSW & 0x00004000)>>14) +#define GET_NP ((PSW & 0x00008000)>>15) + +#define SET_Z(val) (PSW = (PSW & ~0x00000001) | (val)) +#define SET_S(val) (PSW = (PSW & ~0x00000002) | ((val) << 1)) +#define SET_OV(val) (PSW = (PSW & ~0x00000004) | ((val) << 2)) +#define SET_CY(val) (PSW = (PSW & ~0x00000008) | ((val) << 3)) +#define SET_ID(val) (PSW = (PSW & ~0x00001000) | ((val) << 12)) +#define SET_AE(val) (PSW = (PSW & ~0x00002000) | ((val) << 13)) +#define SET_EP(val) (PSW = (PSW & ~0x00004000) | ((val) << 14)) +#define SET_NP(val) (PSW = (PSW & ~0x00008000) | ((val) << 15)) + +#define R_B(addr) (m_program->read_byte(addr)) +#define R_H(addr) (m_program->read_word(addr)) +#define R_W(addr) (m_program->read_dword(addr)) + + +#define W_B(addr, val) (m_program->write_byte(addr,val)) +#define W_H(addr, val) (m_program->write_word(addr,val)) +#define W_W(addr, val) (m_program->write_dword(addr,val)) + + +#define RIO_B(addr) (m_io->read_byte(addr)) +#define RIO_H(addr) (m_io->read_word(addr)) +#define RIO_W(addr) (m_io->read_dword(addr)) + + +#define WIO_B(addr, val) (m_io->write_byte(addr,val)) +#define WIO_H(addr, val) (m_io->write_word(addr,val)) +#define WIO_W(addr, val) (m_io->write_dword(addr,val)) + +#define R_OP(addr) (m_direct->read_word(addr)) + +#define GET1 (op&0x1f) +#define GET2 ((op>>5)&0x1f) +#define I5(x) (((x)&0x1f)|(((x)&0x10)?0xffffffe0:0)) +#define UI5(x) ((x)&0x1f) +#define I16(x) (((x)&0xffff)|(((x)&0x8000)?0xffff0000:0)) +#define UI16(x) ((x)&0xffff) +#define D16(x) (((x)&0xffff)|(((x)&0x8000)?0xffff0000:0)) +#define D26(x,y) ((y)|((x&0x3ff)<<16 )|((x&0x200)?0xfc000000:0)) +#define D9(x) ((x&0x1ff)|((x&0x100)?0xfffffe00:0)) +#define SO(opcode) (((opcode)&0xfc00)>>10) + +#define CHECK_CY(x) PSW=(PSW & ~8)|(((x) & (((UINT64)1) << 32)) ? 8 : 0) +#define CHECK_OVADD(x,y,z) PSW=(PSW & ~0x00000004) |(( ((x) ^ (z)) & ((y) ^ (z)) & 0x80000000) ? 4: 0) +#define CHECK_OVSUB(x,y,z) PSW=(PSW & ~0x00000004) |(( ((y) ^ (z)) & ((x) ^ (y)) & 0x80000000) ? 4: 0) +#define CHECK_ZS(x) PSW=(PSW & ~3)|((UINT32)(x)==0)|(((x)&0x80000000) ? 2: 0) + + +#define ADD(dst, src) { UINT64 res=(UINT64)(dst)+(UINT64)(src); SetCF(res); SetOF_Add(res,src,dst); SetSZPF(res); dst=(UINT32)res; } +#define SUB(dst, src) { UINT64 res=(UINT64)(dst)-(INT64)(src); SetCF(res); SetOF_Sub(res,src,dst); SetSZPF(res); dst=(UINT32)res; } + + + + +void v810_device::SETREG(UINT32 reg,UINT32 val) +{ + if(reg) + m_reg[reg]=val; +} + +UINT32 v810_device::GETREG(UINT32 reg) +{ + if(reg) + return m_reg[reg]; + else + return 0; +} + +UINT32 v810_device::opUNDEF(UINT32 op) +{ + logerror("V810: Unknown opcode %x @ %x",op,PC-2); + return clkIF; +} + +UINT32 v810_device::opMOVr(UINT32 op) // mov reg1, reg2 +{ + SETREG(GET2,GETREG(GET1)); + return clkIF; +} + +UINT32 v810_device::opMOVEA(UINT32 op) // movea imm16, reg1, reg2 +{ + UINT32 op1=GETREG(GET1); + UINT32 op2=R_OP(PC); + PC+=2; + op2=I16(op2); + SETREG(GET2,op1+op2); + return clkIF; +} + +UINT32 v810_device::opMOVHI(UINT32 op) // movhi imm16, reg1 ,reg2 +{ + UINT32 op2=R_OP(PC); + PC+=2; + op2=UI16(op2); + op2<<=16; + SETREG(GET2,GETREG(GET1)+op2); + return clkIF; +} + +UINT32 v810_device::opMOVi(UINT32 op) // mov imm5,r2 +{ + SETREG(GET2,I5(op)); + return clkIF; +} + +UINT32 v810_device::opADDr(UINT32 op) // add r1,r2 +{ + UINT32 op1=GETREG(GET1); + UINT32 op2=GETREG(GET2); + UINT64 res=(UINT64)op2+(UINT64)op1; + CHECK_CY(res); + CHECK_OVADD(op1,op2,res); + CHECK_ZS(res); + SETREG(GET2,res); + return clkIF; +} + +UINT32 v810_device::opADDi(UINT32 op) // add imm5,r2 +{ + UINT32 op1=I5(op); + UINT32 op2=GETREG(GET2); + UINT64 res=(UINT64)op2+(UINT64)op1; + CHECK_CY(res); + CHECK_OVADD(op1,op2,res); + CHECK_ZS(res); + SETREG(GET2,res); + return clkIF; +} + + +UINT32 v810_device::opADDI(UINT32 op) // addi imm16, reg1, reg2 +{ + UINT32 op1=GETREG(GET1); + UINT32 op2=R_OP(PC); + UINT64 res; + PC+=2; + op2=I16(op2); + res=(UINT64)op2+(UINT64)op1; + CHECK_CY(res); + CHECK_OVADD(op1,op2,res); + CHECK_ZS(res); + SETREG(GET2,res); + return clkIF; +} + +UINT32 v810_device::opSUBr(UINT32 op) // sub r1,r2 +{ + UINT32 op1=GETREG(GET1); + UINT32 op2=GETREG(GET2); + UINT64 res=(UINT64)op2-(UINT64)op1; + CHECK_CY(res); + CHECK_OVSUB(op1,op2,res); + CHECK_ZS(res); + SETREG(GET2,res); + return clkIF; +} + + +UINT32 v810_device::opCMPr(UINT32 op) // cmp r1,r2 +{ + UINT32 op1=GETREG(GET1); + UINT32 op2=GETREG(GET2); + UINT64 res=(UINT64)op2-(UINT64)op1; + CHECK_CY(res); + CHECK_OVSUB(op1,op2,res); + CHECK_ZS(res); + return clkIF; +} + +UINT32 v810_device::opCMPi(UINT32 op) // cmpi imm5,r2 +{ + UINT32 op1=I5(op); + UINT32 op2=GETREG(GET2); + UINT64 res=(UINT64)op2-(UINT64)op1; + CHECK_CY(res); + CHECK_OVSUB(op1,op2,res); + CHECK_ZS(res); + return clkIF; +} + +UINT32 v810_device::opSETFi(UINT32 op) // setf imm5,r2 +{ + UINT32 op1=I5(op); + UINT8 res=0; + op1&=0xf; + switch(op1) + { + case 0: //bv + res=GET_OV; + break; + + case 1: //bl + res=GET_CY; + break; + + case 2: //be + res=GET_Z; + break; + + case 3: //bnh + res=GET_Z||GET_CY; + break; + + case 4: //bn + res=GET_S; + break; + + case 5: //br + res=1; + break; + + case 6: //blt + res=GET_S^GET_OV; + break; + + case 7: //ble + res=GET_Z||(GET_S^GET_OV); + break; + + case 8: //bnv + res=!GET_OV; + break; + + case 9: //bnl + res=!GET_CY; + break; + + case 10: //bne + res=!GET_Z; + break; + + case 11: //bh + res=!(GET_Z||GET_CY); + break; + + case 12: //bp + res=!GET_S; + break; + + case 13: //nop + + break; + + case 14: //bge + res=!(GET_OV^GET_S); + break; + + case 15: //bgt + res=!(GET_Z||(GET_OV^GET_S)); + break; + } + SETREG(GET2,res); + return clkIF; +} + + +UINT32 v810_device::opANDr(UINT32 op) // and r1,r2 +{ + UINT32 op1=GETREG(GET1); + UINT32 op2=GETREG(GET2); + op2&=op1; + CHECK_ZS(op2); + SET_OV(0); + SETREG(GET2,op2); + return clkIF; +} + +UINT32 v810_device::opANDI(UINT32 op) // andi imm16,r1,r2 +{ + UINT32 op1=GETREG(GET1); + UINT32 op2=R_OP(PC); + PC+=2; + op2=UI16(op2); + op2&=op1; + CHECK_ZS(op2); + SET_OV(0); + SET_S(0); + SETREG(GET2,op2); + return clkIF; +} + +UINT32 v810_device::opORr(UINT32 op) // or r1,r2 +{ + UINT32 op1=GETREG(GET1); + UINT32 op2=GETREG(GET2); + op2|=op1; + CHECK_ZS(op2); + SET_OV(0); + SETREG(GET2,op2); + return clkIF; +} + +UINT32 v810_device::opORI(UINT32 op) // ori imm16,r1,r2 +{ + UINT32 op1=GETREG(GET1); + UINT32 op2=R_OP(PC); + PC+=2; + op2=UI16(op2); + op2|=op1; + CHECK_ZS(op2); + SET_OV(0); + SET_S(0); + SETREG(GET2,op2); + return clkIF; +} + +UINT32 v810_device::opXORr(UINT32 op) // xor r1,r2 +{ + UINT32 op1=GETREG(GET1); + UINT32 op2=GETREG(GET2); + op2^=op1; + CHECK_ZS(op2); + SET_OV(0); + SETREG(GET2,op2); + return clkIF; +} + + +UINT32 v810_device::opLDSR(UINT32 op) // ldsr reg2,regID +{ + UINT32 op1=UI5(op); + SETREG(32+op1,GETREG(GET2)); + return clkIF; +} + +UINT32 v810_device::opSTSR(UINT32 op) // ldsr regID,reg2 +{ + UINT32 op1=UI5(op); + SETREG(GET2,GETREG(32+op1)); + return clkIF; +} + + +UINT32 v810_device::opXORI(UINT32 op) // xori imm16,r1,r2 +{ + UINT32 op1=GETREG(GET1); + UINT32 op2=R_OP(PC); + PC+=2; + op2=UI16(op2); + op2^=op1; + CHECK_ZS(op2); + SET_OV(0); + SET_S(0); + SETREG(GET2,op2); + return clkIF; +} + +UINT32 v810_device::opNOTr(UINT32 op) // not r1,r2 +{ + UINT32 op1=GETREG(GET1); + UINT32 op2=~op1; + CHECK_ZS(op2); + SET_OV(0); + SETREG(GET2,op2); + return clkIF; +} + +UINT32 v810_device::opSHLr(UINT32 op) // shl r1,r2 +{ + UINT64 tmp; + UINT32 count=GETREG(GET1); + count&=0x1f; + + SET_OV(0); + SET_CY(0); + + if(count) + { + tmp=GETREG(GET2); + tmp<<=count; + CHECK_CY(tmp); + SETREG(GET2,tmp&0xffffffff); + CHECK_ZS(GETREG(GET2)); + } + return clkIF; +} + +UINT32 v810_device::opSHLi(UINT32 op) // shl imm5,r2 +{ + UINT64 tmp; + UINT32 count=UI5(op); + + SET_OV(0); + SET_CY(0); + + if(count) + { + tmp=GETREG(GET2); + tmp<<=count; + CHECK_CY(tmp); + SETREG(GET2,tmp&0xffffffff); + } + CHECK_ZS(GETREG(GET2)); + return clkIF; +} + +UINT32 v810_device::opSHRr(UINT32 op) // shr r1,r2 +{ + UINT64 tmp; + UINT32 count=GETREG(GET1); + count&=0x1f; + SET_OV(0); + SET_CY(0); + if(count) + { + tmp=GETREG(GET2); + tmp>>=count-1; + SET_CY(tmp&1); + SETREG(GET2,(tmp>>1)&0xffffffff); + } + CHECK_ZS(GETREG(GET2)); + return clkIF; +} + +UINT32 v810_device::opSHRi(UINT32 op) // shr imm5,r2 +{ + UINT64 tmp; + UINT32 count=UI5(op); + SET_OV(0); + SET_CY(0); + if(count) + { + tmp=GETREG(GET2); + tmp>>=count-1; + SET_CY(tmp&1); + tmp>>=1; + SETREG(GET2,tmp&0xffffffff); + } + CHECK_ZS(GETREG(GET2)); + return clkIF; +} + +UINT32 v810_device::opSARr(UINT32 op) // sar r1,r2 +{ + INT32 tmp; + UINT32 count=GETREG(GET1); + count&=0x1f; + SET_OV(0); + SET_CY(0); + if(count) + { + tmp=GETREG(GET2); + tmp>>=count-1; + SET_CY(tmp&1); + tmp>>=1; + SETREG(GET2,tmp); + } + CHECK_ZS(GETREG(GET2)); + return clkIF; +} + +UINT32 v810_device::opSARi(UINT32 op) // sar imm5,r2 +{ + INT32 tmp; + UINT32 count=UI5(op); + SET_OV(0); + SET_CY(0); + if(count) + { + tmp=GETREG(GET2); + tmp>>=count-1; + SET_CY(tmp&1); + tmp>>=1; + SETREG(GET2,tmp); + } + CHECK_ZS(GETREG(GET2)); + return clkIF; +} + +UINT32 v810_device::opJMPr(UINT32 op) +{ + PC=GETREG(GET1)&~1; + return clkIF+2; +} + + +UINT32 v810_device::opJR(UINT32 op) +{ + UINT32 tmp=R_OP(PC); + PC=PC-2+(D26(op,tmp)&~1); + return clkIF+2; +} + +UINT32 v810_device::opJAL(UINT32 op) +{ + UINT32 tmp=R_OP(PC); + PC+=2; + R31=PC; + PC+=D26(op,tmp); + PC-=4; + PC&=~1; + return clkIF+2; +} + + +UINT32 v810_device::opEI(UINT32 op) +{ + SET_ID(0); + return clkIF; +} + +UINT32 v810_device::opDI(UINT32 op) +{ + SET_ID(1); + return clkIF; +} + +UINT32 v810_device::opTRAP(UINT32 op) +{ + printf("V810: TRAP @ %X\n",PC-2); + return clkIF; +} + +UINT32 v810_device::opRETI(UINT32 op) +{ + if(GET_NP) { + PC = FEPC; + PSW = FEPSW; + } else { + PC = EIPC; + PSW = EIPSW; + } + return clkIF; +} + +UINT32 v810_device::opHALT(UINT32 op) +{ + printf("V810: HALT @ %X\n",PC-2); + return clkIF; +} + +UINT32 v810_device::opB(UINT32 op) +{ + int doBranch=0; + switch((op>>9)&0xf) + { + case 0: //bv + doBranch=GET_OV; + break; + + case 1: //bl + doBranch=GET_CY; + break; + + case 2: //be + doBranch=GET_Z; + break; + + case 3: //bnh + doBranch=GET_Z||GET_CY; + break; + + case 4: //bn + doBranch=GET_S; + break; + + case 5: //br + doBranch=1; + break; + + case 6: //blt + doBranch=GET_S^GET_OV; + break; + + case 7: //ble + doBranch=GET_Z||(GET_S^GET_OV); + break; + + case 8: //bnv + doBranch=!GET_OV; + break; + + case 9: //bnl + doBranch=!GET_CY; + break; + + case 10: //bne + doBranch=!GET_Z; + break; + + case 11: //bh + doBranch=!(GET_Z||GET_CY); + break; + + case 12: //bp + doBranch=!GET_S; + break; + + case 13: //nop + + break; + + case 14: //bge + doBranch=!(GET_OV^GET_S); + break; + + case 15: //bgt + doBranch=!(GET_Z||(GET_OV^GET_S)); + break; + } + if(doBranch) + { + PC=PC-2+(D9(op)&~1); + } + return clkIF; +} + +UINT32 v810_device::opLDB(UINT32 op) // ld.b disp16[reg1],reg2 +{ + UINT32 tmp=R_OP(PC); + PC+=2; + tmp=D16(tmp); + tmp+=GETREG(GET1); + tmp=R_B(tmp); + tmp|=(tmp&0x80)?0xffffff00:0; + SETREG(GET2,tmp); + return clkIF+clkMEM; +} + +UINT32 v810_device::opLDH(UINT32 op) // ld.h disp16[reg1],reg2 +{ + UINT32 tmp=R_OP(PC); + PC+=2; + tmp=D16(tmp); + tmp+=GETREG(GET1); + tmp=R_H(tmp&~1); + tmp|=(tmp&0x8000)?0xffff0000:0; + SETREG(GET2,tmp); + return clkIF+clkMEM; +} + +UINT32 v810_device::opLDW(UINT32 op) // ld.w disp16[reg1],reg2 +{ + UINT32 tmp=R_OP(PC); + PC+=2; + tmp=D16(tmp); + tmp+=GETREG(GET1); + tmp=R_W(tmp&~3); + SETREG(GET2,tmp); + return clkIF+clkMEM; +} + +UINT32 v810_device::opINB(UINT32 op) // in.b disp16[reg1],reg2 +{ + UINT32 tmp=R_OP(PC); + PC+=2; + tmp=D16(tmp); + tmp+=GETREG(GET1); + tmp=RIO_B(tmp); + SETREG(GET2,tmp); + return clkIF+clkMEM; +} + +UINT32 v810_device::opCAXI(UINT32 op) // caxi disp16[reg1],reg2 +{ + printf("V810 CAXI execute\n"); + PC+=2; + return clkIF; +} + +UINT32 v810_device::opINH(UINT32 op) // in.h disp16[reg1],reg2 +{ + UINT32 tmp=R_OP(PC); + PC+=2; + tmp=D16(tmp); + tmp+=GETREG(GET1); + tmp=RIO_H(tmp&~1); + SETREG(GET2,tmp); + return clkIF+clkMEM; +} + +UINT32 v810_device::opINW(UINT32 op) // in.w disp16[reg1],reg2 +{ + UINT32 tmp=R_OP(PC); + PC+=2; + tmp=D16(tmp); + tmp+=GETREG(GET1); + tmp=RIO_W(tmp&~3); + SETREG(GET2,tmp); + return clkIF+clkMEM; +} + +UINT32 v810_device::opSTB(UINT32 op) // st.b reg2, disp16[reg1] +{ + UINT32 tmp=R_OP(PC); + PC+=2; + tmp=D16(tmp); + tmp+=GETREG(GET1); + W_B(tmp,GETREG(GET2)&0xff); + return clkIF+clkMEM; +} + +UINT32 v810_device::opSTH(UINT32 op) // st.h reg2, disp16[reg1] +{ + UINT32 tmp=R_OP(PC); + PC+=2; + tmp=D16(tmp); + tmp+=GETREG(GET1); + W_H(tmp&~1,GETREG(GET2)&0xffff); + return clkIF+clkMEM; +} + +UINT32 v810_device::opSTW(UINT32 op) // st.w reg2, disp16[reg1] +{ + UINT32 tmp=R_OP(PC); + PC+=2; + tmp=D16(tmp); + tmp+=GETREG(GET1); + W_W(tmp&~3,GETREG(GET2)); + return clkIF+clkMEM; +} + +UINT32 v810_device::opOUTB(UINT32 op) // out.b reg2, disp16[reg1] +{ + UINT32 tmp=R_OP(PC); + PC+=2; + tmp=D16(tmp); + tmp+=GETREG(GET1); + WIO_B(tmp,GETREG(GET2)&0xff); + return clkIF+clkMEM; +} + +UINT32 v810_device::opOUTH(UINT32 op) // out.h reg2, disp16[reg1] +{ + UINT32 tmp=R_OP(PC); + PC+=2; + tmp=D16(tmp); + tmp+=GETREG(GET1); + WIO_H(tmp&~1,GETREG(GET2)&0xffff); + return clkIF+clkMEM; +} + +UINT32 v810_device::opOUTW(UINT32 op) // out.w reg2, disp16[reg1] +{ + UINT32 tmp=R_OP(PC); + PC+=2; + tmp=D16(tmp); + tmp+=GETREG(GET1); + WIO_W(tmp&~3,GETREG(GET2)); + return clkIF+clkMEM; +} + +UINT32 v810_device::opMULr(UINT32 op) // mul r1,r2 +{ + UINT32 op1=GETREG(GET1); + UINT32 op2=GETREG(GET2); + UINT64 tmp; + tmp=(INT64)(INT32)op1*(INT64)(INT32)op2; + op2=tmp&0xffffffff; + tmp>>=32; + CHECK_ZS(tmp);//z = bad! + SET_Z( (tmp|op2)==0 ); + SET_OV((tmp!=0)); + SET_CY((tmp!=0)); + SETREG(GET2,op2); + SETREG(30,tmp); + return clkIF; +} + +UINT32 v810_device::opMULUr(UINT32 op) // mulu r1,r2 +{ + UINT32 op1=GETREG(GET1); + UINT32 op2=GETREG(GET2); + UINT64 tmp; + tmp=(UINT64)op1*(UINT64)op2; + op2=tmp&0xffffffff; + tmp>>=32; + CHECK_ZS(tmp);//z = bad! + SET_Z( (tmp|op2)==0 ); + SET_OV((tmp!=0)); + SET_CY((tmp!=0)); + SETREG(GET2,op2); + SETREG(30,tmp); + return clkIF; +} + +UINT32 v810_device::opDIVr(UINT32 op) // div r1,r2 +{ + UINT32 op1=GETREG(GET1); + UINT32 op2=GETREG(GET2); + if(op1) + { + SETREG(30,(INT32)((INT32)op2%(INT32)op1)); + SETREG(GET2,(INT32)((INT32)op2/(INT32)op1)); + SET_OV((op1^op2^GETREG(GET2)) == 0x80000000); + CHECK_ZS(GETREG(GET2)); + } + else + printf("DIVr divide by zero?\n"); + return clkIF; +} + +UINT32 v810_device::opDIVUr(UINT32 op) // divu r1,r2 +{ + UINT32 op1=GETREG(GET1); + UINT32 op2=GETREG(GET2); + if(op1) + { + SETREG(30,(INT32)(op2%op1)); + SETREG(GET2,(INT32)(op2/op1)); + SET_OV((op1^op2^GETREG(GET2)) == 0x80000000); + CHECK_ZS(GETREG(GET2)); + } + else + printf("DIVUr divide by zero?\n"); + return clkIF; +} + +void v810_device::opADDF(UINT32 op) +{ + //TODO: CY + float val1=u2f(GETREG(GET1)); + float val2=u2f(GETREG(GET2)); + SET_OV(0); + val2+=val1; + SET_Z((val2==0.0f)?1:0); + SET_S((val2<0.0f)?1:0); + SETREG(GET2,f2u(val2)); +} + +void v810_device::opSUBF(UINT32 op) +{ + float val1=u2f(GETREG(GET1)); + float val2=u2f(GETREG(GET2)); + SET_OV(0); + SET_CY((val2> 8); + SET_Z((val==0.0f)?1:0); + SET_S((val<0.0f)?1:0); + SETREG(GET2,val); +} + + +void v810_device::opXH(UINT32 op) +{ + int val=GETREG(GET2); + SET_OV(0); + val = ((val & 0xffff0000)>>16) | ((val & 0xffff)<<16); + SET_Z((val==0.0f)?1:0); + SET_S((val<0.0f)?1:0); + SETREG(GET2,val); +} + +UINT32 v810_device::opFpoint(UINT32 op) +{ + UINT32 tmp=R_OP(PC); + PC+=2; + switch((tmp&0xfc00)>>10) + { + case 0x0: opCMPF(op);break; + case 0x2: opCVTW(op);break; + case 0x3: opCVTS(op);break; + case 0x4: opADDF(op);break; + case 0x5: opSUBF(op);break; + case 0x6: opMULF(op);break; + case 0x7: opDIVF(op);break; + case 0x8: opXB(op); break; // * + case 0x9: opXH(op); break; // * + case 0xb: opTRNC(op);break; + case 0xc: opMPYHW(op); break; // * + // * <- Virtual Boy specific? + default: printf("Floating point %02x\n",(tmp&0xfc00) >> 10);break; + } + return clkIF+1; +} + +/* TODO: clocks */ +UINT32 v810_device::opBSU(UINT32 op) +{ + if(!(op & 8)) + fatalerror("V810: unknown BSU opcode %04x\n",op); + + { + UINT32 srcbit,dstbit,src,dst,size; + UINT32 dsttmp,tmp; + UINT8 srctmp; + +// printf("BDST %08x BSRC %08x SIZE %08x DST %08x SRC %08x\n",R26,R27,R28,R29,R30); + + dstbit = R26 & 0x1f; + srcbit = R27 & 0x1f; + size = R28; + dst = R29 & ~3; + src = R30 & ~3; + + switch(op & 0xf) + { + case 0x8: // ORBSU + srctmp = (R_W(src) >> srcbit) & 1; + dsttmp = R_W(dst); + + tmp = dsttmp | (srctmp << dstbit); + + W_W(dst,tmp); + break; + case 0x9: // ANDBSU + srctmp = ((R_W(src) >> srcbit) & 1) ^ 1; + dsttmp = R_W(dst); + + tmp = dsttmp & (~(srctmp << dstbit)); + + W_W(dst,tmp); + break; + case 0xa: // XORBSU + srctmp = (R_W(src) >> srcbit) & 1; + dsttmp = R_W(dst); + + tmp = dsttmp ^ (srctmp << dstbit); + + W_W(dst,tmp); + break; + case 0xb: // MOVBSU + srctmp = (R_W(src) >> srcbit) & 1; + dsttmp = (R_W(dst) & ~(1 << dstbit)); + + tmp = (srctmp << dstbit) | dsttmp; + + W_W(dst,tmp); + break; + case 0xc: // ORNBSU + srctmp = ((R_W(src) >> srcbit) & 1) ^ 1; + dsttmp = R_W(dst); + + tmp = dsttmp | (srctmp << dstbit); + + W_W(dst,tmp); + break; + case 0xd: // ANDNBSU + srctmp = (R_W(src) >> srcbit) & 1; + dsttmp = R_W(dst); + + tmp = dsttmp & (~(srctmp << dstbit)); + + W_W(dst,tmp); + break; + case 0xe: // XORNBSU + srctmp = ((R_W(src) >> srcbit) & 1) ^ 1; + dsttmp = R_W(dst); + + tmp = dsttmp ^ (srctmp << dstbit); + + W_W(dst,tmp); + break; + case 0xf: // NOTBSU + srctmp = ((R_W(src) >> srcbit) & 1) ^ 1; + dsttmp = (R_W(dst) & ~(1 << dstbit)); + + tmp = (srctmp << dstbit) | dsttmp; + + W_W(dst,tmp); + break; + default: fatalerror("V810: unemulated BSU opcode %04x\n",op); + } + + srcbit++; + dstbit++; + + srcbit&=0x1f; + dstbit&=0x1f; + + if(srcbit == 0) + src+=4; + + if(dstbit == 0) + dst+=4; + + size --; + + R26 = dstbit; + R27 = srcbit; + R28 = size; + R29 = dst; + R30 = src; + + if(size != 0) + PC-=2; + } + + return clkIF+1; //TODO: correct? +} + +const v810_device::opcode_func v810_device::s_OpCodeTable[64] = +{ + /* 0x00 */ &v810_device::opMOVr, // mov r1,r2 1 + /* 0x01 */ &v810_device::opADDr, // add r1,r2 1 + /* 0x02 */ &v810_device::opSUBr, // sub r1,r2 1 + /* 0x03 */ &v810_device::opCMPr, // cmp2 r1,r2 1 + /* 0x04 */ &v810_device::opSHLr, // shl r1,r2 1 + /* 0x05 */ &v810_device::opSHRr, // shr r1,r2 1 + /* 0x06 */ &v810_device::opJMPr, // jmp [r1] 1 + /* 0x07 */ &v810_device::opSARr, // sar r1,r2 1 + /* 0x08 */ &v810_device::opMULr, // mul r1,r2 1 + /* 0x09 */ &v810_device::opDIVr, // div r1,r2 1 + /* 0x0a */ &v810_device::opMULUr, // mulu r1,r2 1 + /* 0x0b */ &v810_device::opDIVUr, // divu r1,r2 1 + /* 0x0c */ &v810_device::opORr, // or r1,r2 1 + /* 0x0d */ &v810_device::opANDr, // and r1,r2 1 + /* 0x0e */ &v810_device::opXORr, // xor r1,r2 1 + /* 0x0f */ &v810_device::opNOTr, // not r1,r2 1 + /* 0x10 */ &v810_device::opMOVi, // mov imm5,r2 2 + /* 0x11 */ &v810_device::opADDi, // add imm5,r2 2 + /* 0x12 */ &v810_device::opSETFi, // setf imm5,r2 2 + /* 0x13 */ &v810_device::opCMPi, // cmp imm5,r2 2 + /* 0x14 */ &v810_device::opSHLi, // shl imm5,r2 2 + /* 0x15 */ &v810_device::opSHRi, // shr imm5,r2 2 + /* 0x16 */ &v810_device::opEI, // ei 2 + /* 0x17 */ &v810_device::opSARi, // sar imm5,r2 2 + /* 0x18 */ &v810_device::opTRAP, + /* 0x19 */ &v810_device::opRETI, + /* 0x1a */ &v810_device::opHALT, // halt 2 + /* 0x1b */ &v810_device::opUNDEF, + /* 0x1c */ &v810_device::opLDSR, // ldsr reg2,regID 2 + /* 0x1d */ &v810_device::opSTSR, // stsr regID,reg2 2 + /* 0x1e */ &v810_device::opDI, // DI 2 + /* 0x1f */ &v810_device::opBSU, + /* 0x20 */ &v810_device::opB, // Branch (7 bit opcode) + /* 0x21 */ &v810_device::opB, // Branch (7 bit opcode) + /* 0x22 */ &v810_device::opB, // Branch (7 bit opcode) + /* 0x23 */ &v810_device::opB, // Branch (7 bit opcode) + /* 0x24 */ &v810_device::opB, // Branch (7 bit opcode) + /* 0x25 */ &v810_device::opB, // Branch (7 bit opcode) + /* 0x26 */ &v810_device::opB, // Branch (7 bit opcode) + /* 0x27 */ &v810_device::opB, // Branch (7 bit opcode) + /* 0x28 */ &v810_device::opMOVEA, // movea imm16, reg1, reg2 5 + /* 0x29 */ &v810_device::opADDI, // addi imm16, reg1, reg2 5 + /* 0x2a */ &v810_device::opJR, // jr disp26 4 + /* 0x2b */ &v810_device::opJAL, // jal disp26 4 + /* 0x2c */ &v810_device::opORI, // ori imm16, reg1, reg2 5 + /* 0x2d */ &v810_device::opANDI, // andi imm16, reg1, reg2 5 + /* 0x2e */ &v810_device::opXORI, // xori imm16, reg1, reg2 5 + /* 0x2f */ &v810_device::opMOVHI, // movhi imm16, reg1 ,reg2 5 + /* 0x30 */ &v810_device::opLDB, // ld.b disp16[reg1],reg2 6a + /* 0x31 */ &v810_device::opLDH, // ld.h disp16[reg1],reg2 6a + /* 0x32 */ &v810_device::opUNDEF, + /* 0x33 */ &v810_device::opLDW, // ld.w disp16[reg1],reg2 6a + /* 0x34 */ &v810_device::opSTB, // st.b reg2, disp16[reg1] 6b + /* 0x35 */ &v810_device::opSTH, // st.h reg2, disp16[reg1] 6b + /* 0x36 */ &v810_device::opUNDEF, + /* 0x37 */ &v810_device::opSTW, // st.w reg2, disp16[reg1] 6b + /* 0x38 */ &v810_device::opINB, // in.b disp16[reg1], reg2 6a + /* 0x39 */ &v810_device::opINH, // in.h disp16[reg1], reg2 6a + /* 0x3a */ &v810_device::opCAXI, // caxi disp16[reg1],reg2 6a + /* 0x3b */ &v810_device::opINW, // in.w disp16[reg1], reg2 6a + /* 0x3c */ &v810_device::opOUTB, // out.b reg2, disp16[reg1] 6b + /* 0x3d */ &v810_device::opOUTH, // out.h reg2, disp16[reg1] 6b + /* 0x3e */ &v810_device::opFpoint, //floating point opcodes + /* 0x3f */ &v810_device::opOUTW // out.w reg2, disp16[reg1] 6b +}; + +void v810_device::device_start() +{ + m_irq_state = CLEAR_LINE; + m_irq_line = 0; + m_nmi_line = CLEAR_LINE; + m_program = &space(AS_PROGRAM); + m_direct = &m_program->direct(); + m_io = &space(AS_IO); + + m_irq_line = 0; + m_irq_state = 0; + m_nmi_line = 0; + memset(m_reg, 0x00, sizeof(m_reg)); + + save_item(NAME(m_reg)); + save_item(NAME(m_irq_line)); + save_item(NAME(m_irq_state)); + save_item(NAME(m_nmi_line)); + save_item(NAME(m_PPC)); + + state_add( V810_PC, "PC", PC).formatstr("%08X"); + state_add( V810_R0, "R0", R0).formatstr("%08X"); + state_add( V810_R1, "R1", R1).formatstr("%08X"); + state_add( V810_R2, "R2", R2).formatstr("%08X"); + state_add( V810_SP, "SP", SP).formatstr("%08X"); + state_add( V810_R4, "R4", R4).formatstr("%08X"); + state_add( V810_R5, "R5", R5).formatstr("%08X"); + state_add( V810_R6, "R6", R6).formatstr("%08X"); + state_add( V810_R7, "R7", R7).formatstr("%08X"); + state_add( V810_R8, "R8", R8).formatstr("%08X"); + state_add( V810_R9, "R9", R9).formatstr("%08X"); + state_add( V810_R10, "R10", R10).formatstr("%08X"); + state_add( V810_R11, "R11", R11).formatstr("%08X"); + state_add( V810_R12, "R12", R12).formatstr("%08X"); + state_add( V810_R13, "R13", R13).formatstr("%08X"); + state_add( V810_R14, "R14", R14).formatstr("%08X"); + state_add( V810_R15, "R15", R15).formatstr("%08X"); + state_add( V810_R16, "R16", R16).formatstr("%08X"); + state_add( V810_R17, "R17", R17).formatstr("%08X"); + state_add( V810_R18, "R18", R18).formatstr("%08X"); + state_add( V810_R19, "R19", R19).formatstr("%08X"); + state_add( V810_R20, "R20", R20).formatstr("%08X"); + state_add( V810_R21, "R21", R21).formatstr("%08X"); + state_add( V810_R22, "R22", R22).formatstr("%08X"); + state_add( V810_R23, "R23", R23).formatstr("%08X"); + state_add( V810_R24, "R24", R24).formatstr("%08X"); + state_add( V810_R25, "R25", R25).formatstr("%08X"); + state_add( V810_R26, "R26", R26).formatstr("%08X"); + state_add( V810_R27, "R27", R27).formatstr("%08X"); + state_add( V810_R28, "R28", R28).formatstr("%08X"); + state_add( V810_R29, "R29", R29).formatstr("%08X"); + state_add( V810_R30, "R30", R30).formatstr("%08X"); + state_add( V810_R31, "R31", R31).formatstr("%08X"); + state_add( V810_EIPC, "EIPC", EIPC).formatstr("%08X"); + state_add( V810_PSW, "PSW", PSW).formatstr("%08X"); + state_add( V810_EIPSW, "EIPSW", EIPSW).formatstr("%08X"); + state_add( V810_FEPC, "FEPC", FEPC).formatstr("%08X"); + state_add( V810_FEPSW, "FEPSW", FEPSW).formatstr("%08X"); + state_add( V810_ECR, "ECR", ECR).formatstr("%08X"); + state_add( V810_PIR, "PIR", PIR).formatstr("%08X"); + state_add( V810_TKCW, "TKCW", TKCW).formatstr("%08X"); + state_add( V810_CHCW, "CHCW", CHCW).formatstr("%08X"); + state_add( V810_ADTRE, "ADTRE", ADTRE).formatstr("%08X"); + + state_add(STATE_GENPC, "GENPC", PC).noshow(); + state_add(STATE_GENSP, "GENSP", SP).noshow(); + state_add(STATE_GENFLAGS, "GENFLAGS", PSW).formatstr("%8s").noshow(); + state_add(STATE_GENPCBASE, "GENPCBASE", m_PPC).noshow(); + + m_icountptr = &m_icount; +} + +void v810_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + switch (entry.index()) + { + case STATE_GENFLAGS: + strprintf(str, "%c%c%c%c%c%c%c%c", + GET_AE ? 'A':'.', + GET_NP ? 'N':'.', + GET_EP ? 'E':'.', + GET_ID ? 'I':'.', + GET_CY ? 'C':'.', + GET_OV ? 'V':'.', + GET_S ? 'S':'.', + GET_Z ? 'Z':'.' + ); + break; + } +} + +void v810_device::device_reset() +{ + int i; + for(i=0;i<64;i++) m_reg[i]=0; + PC = 0xfffffff0; + PSW = 0x1000; + ECR = 0x0000fff0; +} + +void v810_device::take_interrupt() +{ + EIPC = PC; + EIPSW = PSW; + + PC = 0xfffffe00 | (m_irq_line << 4); + ECR = 0xfe00 | (m_irq_line << 4); + + UINT8 num = m_irq_line + 1; + if (num==0x10) num=0x0f; + + PSW &= 0xfff0ffff; // clear interrupt level + SET_EP(1); + SET_ID(1); + PSW |= num << 16; + + m_icount-= clkIF; +} + +void v810_device::execute_run() +{ + if (m_irq_state != CLEAR_LINE) { + if (!(GET_NP | GET_EP | GET_ID)) { + if (m_irq_line >=((PSW & 0xF0000) >> 16)) { + take_interrupt(); + } + } + } + while(m_icount>0) + { + UINT32 op; + + m_PPC=PC; + debugger_instruction_hook(this, PC); + op=R_OP(PC); + PC+=2; + int cnt; + cnt = (this->*s_OpCodeTable[op>>10])(op); + m_icount-= cnt; + } +} + + +void v810_device::execute_set_input( int irqline, int state) +{ + m_irq_state = state; + m_irq_line = irqline; +} diff --git a/src/devices/cpu/v810/v810.h b/src/devices/cpu/v810/v810.h new file mode 100644 index 00000000000..c5fcf163147 --- /dev/null +++ b/src/devices/cpu/v810/v810.h @@ -0,0 +1,204 @@ +// license:LGPL-2.1+ +// copyright-holders:Angelo Salese, Tomasz Slanina +#pragma once + +#ifndef __V810_H__ +#define __V810_H__ + + +enum +{ + V810_R0=1, + V810_R1, + V810_R2, /* R2 - handler stack pointer */ + V810_SP, /* R3 - stack pointer */ + V810_R4, /* R4 - global pointer */ + V810_R5, /* R5 - text pointer */ + V810_R6, + V810_R7, + V810_R8, + V810_R9, + V810_R10, + V810_R11, + V810_R12, + V810_R13, + V810_R14, + V810_R15, + V810_R16, + V810_R17, + V810_R18, + V810_R19, + V810_R20, + V810_R21, + V810_R22, + V810_R23, + V810_R24, + V810_R25, + V810_R26, + V810_R27, + V810_R28, + V810_R29, + V810_R30, + V810_R31, /* R31 - link pointer */ + + /* System Registers */ + V810_EIPC, /* Exception/interrupt saving - PC */ + V810_EIPSW,/* Exception/interrupt saving - PSW */ + V810_FEPC, /* Duplexed exception/NMI saving - PC */ + V810_FEPSW,/* Duplexed exception/NMI saving - PSW */ + V810_ECR, /* Exception cause register */ + V810_PSW, /* Program status word */ + V810_PIR, /* Processor ID register */ + V810_TKCW, /* Task control word */ + V810_res08, + V810_res09, + V810_res10, + V810_res11, + V810_res12, + V810_res13, + V810_res14, + V810_res15, + V810_res16, + V810_res17, + V810_res18, + V810_res19, + V810_res20, + V810_res21, + V810_res22, + V810_res23, + V810_CHCW, /* Cache control word */ + V810_ADTRE, /* Address trap register */ + V810_res26, + V810_res27, + V810_res28, + V810_res29, + V810_res30, + V810_res31, + + V810_PC +}; + + +class v810_device : public cpu_device +{ +public: + // construction/destruction + v810_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_execute_interface overrides + virtual UINT32 execute_min_cycles() const { return 3; } + virtual UINT32 execute_max_cycles() const { return 6; } + virtual UINT32 execute_input_lines() const { return 16; } + virtual void execute_run(); + virtual void execute_set_input(int inputnum, int state); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const { return (spacenum == AS_PROGRAM) ? &m_program_config : ((spacenum == AS_IO) ? &m_io_config : NULL); } + + // device_state_interface overrides + void state_string_export(const device_state_entry &entry, std::string &str); + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const { return 2; } + virtual UINT32 disasm_max_opcode_bytes() const { return 4; } + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + +private: + typedef UINT32 (v810_device::*opcode_func)(UINT32 op); + static const opcode_func s_OpCodeTable[64]; + + address_space_config m_program_config; + address_space_config m_io_config; + + UINT32 m_reg[65]; + UINT8 m_irq_line; + UINT8 m_irq_state; + UINT8 m_nmi_line; + address_space *m_program; + direct_read_data *m_direct; + address_space *m_io; + UINT32 m_PPC; + int m_icount; + + inline void SETREG(UINT32 reg,UINT32 val); + inline UINT32 GETREG(UINT32 reg); + UINT32 opUNDEF(UINT32 op); + UINT32 opMOVr(UINT32 op); + UINT32 opMOVEA(UINT32 op); + UINT32 opMOVHI(UINT32 op); + UINT32 opMOVi(UINT32 op); + UINT32 opADDr(UINT32 op); + UINT32 opADDi(UINT32 op); + UINT32 opADDI(UINT32 op); + UINT32 opSUBr(UINT32 op); + UINT32 opCMPr(UINT32 op); + UINT32 opCMPi(UINT32 op); + UINT32 opSETFi(UINT32 op); + UINT32 opANDr(UINT32 op); + UINT32 opANDI(UINT32 op); + UINT32 opORr(UINT32 op); + UINT32 opORI(UINT32 op); + UINT32 opXORr(UINT32 op); + UINT32 opLDSR(UINT32 op); + UINT32 opSTSR(UINT32 op); + UINT32 opXORI(UINT32 op); + UINT32 opNOTr(UINT32 op); + UINT32 opSHLr(UINT32 op); + UINT32 opSHLi(UINT32 op); + UINT32 opSHRr(UINT32 op); + UINT32 opSHRi(UINT32 op); + UINT32 opSARr(UINT32 op); + UINT32 opSARi(UINT32 op); + UINT32 opJMPr(UINT32 op); + UINT32 opJR(UINT32 op); + UINT32 opJAL(UINT32 op); + UINT32 opEI(UINT32 op); + UINT32 opDI(UINT32 op); + UINT32 opTRAP(UINT32 op); + UINT32 opRETI(UINT32 op); + UINT32 opHALT(UINT32 op); + UINT32 opB(UINT32 op); + UINT32 opLDB(UINT32 op); + UINT32 opLDH(UINT32 op); + UINT32 opLDW(UINT32 op); + UINT32 opINB(UINT32 op); + UINT32 opCAXI(UINT32 op); + UINT32 opINH(UINT32 op); + UINT32 opINW(UINT32 op); + UINT32 opSTB(UINT32 op); + UINT32 opSTH(UINT32 op); + UINT32 opSTW(UINT32 op); + UINT32 opOUTB(UINT32 op); + UINT32 opOUTH(UINT32 op); + UINT32 opOUTW(UINT32 op); + UINT32 opMULr(UINT32 op); + UINT32 opMULUr(UINT32 op); + UINT32 opDIVr(UINT32 op); + UINT32 opDIVUr(UINT32 op); + void opADDF(UINT32 op); + void opSUBF(UINT32 op); + void opMULF(UINT32 op); + void opDIVF(UINT32 op); + void opTRNC(UINT32 op); + void opCMPF(UINT32 op); + void opCVTS(UINT32 op); + void opCVTW(UINT32 op); + void opMPYHW(UINT32 op); + void opXB(UINT32 op); + void opXH(UINT32 op); + UINT32 opFpoint(UINT32 op); + UINT32 opBSU(UINT32 op); + void take_interrupt(); + +}; + + +extern const device_type V810; + + +#endif /* __V810_H__ */ diff --git a/src/devices/cpu/v810/v810dasm.c b/src/devices/cpu/v810/v810dasm.c new file mode 100644 index 00000000000..2f541cc73c4 --- /dev/null +++ b/src/devices/cpu/v810/v810dasm.c @@ -0,0 +1,177 @@ +// license:LGPL-2.1+ +// copyright-holders:Tomasz Slanina +/******************************************** + NEC V810 (upd70732) disassembler + Tomasz Slanina - analog[at]op.pl +*******************************************/ + +#include "emu.h" +#include "debugger.h" +#include "v810.h" + +#define I5(x) (((x)&0x1f)|(((x)&0x10)?0xffffffe0:0)) +#define UI5(x) ((x)&0x1f) +#define I16(x) (((x)&0xffff)|(((x)&0x8000)?0xffff0000:0)) +#define UI16(x) ((x)&0xffff) +#define D16(x) (((x)&0xffff)|(((x)&0x8000)?0xffff0000:0)) +#define D26(x,y) ((y)|((x&0x3ff)<<16 )|((x&0x200)?0xfc000000:0)) +#define D9(x) ((x&0x1ff)|((x&0x100)?0xfffffe00:0)) + +static const char *const dRegs[]= +{ +"R0","R1","R2","SP","R4", +"R5","R6","R7","R8","R9", +"R10","R11","R12","R13", +"R14","R15","R16","R17", +"R18","R19","R20","R21", +"R22","R23","R24","R25", +"R26","R27","R28","R29", +"R30","R31", +"EIPC","EIPSW","FEPC","FEPSW","ECR", +"PSW","PIR","TKCW","","", +"","","","","", +"","","","","", +"","","","","CHCW","ADTRE", +"","","","","","" +}; + +#define GET1s(opcode) dRegs[(opcode)&0x1f] +#define GET2s(opcode) dRegs[((opcode)>>5)&0x1f] +#define GETRs(opcode) dRegs[32+((opcode)&0x1f)] + +CPU_DISASSEMBLE( v810 ) +{ + UINT32 flags = 0; + UINT32 opc,opc2; + unsigned size; + opc = oprom[0] | (oprom[1] << 8); + opc2 = oprom[2] | (oprom[3] << 8); + + switch(opc>>10) + { + case 0x00: sprintf(buffer,"MOV %s,%s",GET1s(opc),GET2s(opc)); size=2; break; + case 0x01: sprintf(buffer,"ADD %s,%s",GET1s(opc),GET2s(opc)); size=2; break; + case 0x02: sprintf(buffer,"SUB %s,%s",GET1s(opc),GET2s(opc)); size=2; break; + case 0x03: sprintf(buffer,"CMP %s,%s",GET1s(opc),GET2s(opc)); size=2; break; + case 0x04: sprintf(buffer,"SHL %s,%s",GET1s(opc),GET2s(opc)); size=2; break; + case 0x05: sprintf(buffer,"SHR %s,%s",GET1s(opc),GET2s(opc)); size=2; break; + case 0x06: sprintf(buffer,"JMP [%s]",GET1s(opc)); size=2; if ((opc&0x1f) == 31) flags = DASMFLAG_STEP_OUT; break; + case 0x07: sprintf(buffer,"SAR %s,%s",GET1s(opc),GET2s(opc)); size=2; break; + case 0x08: sprintf(buffer,"MUL %s,%s",GET1s(opc),GET2s(opc)); size=2; break; + case 0x09: sprintf(buffer,"DIV %s,%s",GET1s(opc),GET2s(opc)); size=2; break; + case 0x0a: sprintf(buffer,"MULU %s,%s",GET1s(opc),GET2s(opc)); size=2; break; + case 0x0b: sprintf(buffer,"DIVU %s,%s",GET1s(opc),GET2s(opc)); size=2; break; + case 0x0c: sprintf(buffer,"OR %s,%s",GET1s(opc),GET2s(opc)); size=2; break; + case 0x0d: sprintf(buffer,"AND %s,%s",GET1s(opc),GET2s(opc)); size=2; break; + case 0x0e: sprintf(buffer,"XOR %s,%s",GET1s(opc),GET2s(opc)); size=2; break; + case 0x0f: sprintf(buffer,"NOT %s,%s",GET1s(opc),GET2s(opc)); size=2; break; + case 0x10: sprintf(buffer,"MOV %X,%s",I5(opc),GET2s(opc)); size=2; break; + case 0x11: sprintf(buffer,"ADD %X,%s",I5(opc),GET2s(opc)); size=2; break; + case 0x12: sprintf(buffer,"SETF %X,%s",I5(opc),GET2s(opc)); size=2; break; + case 0x13: sprintf(buffer,"CMP %X,%s",I5(opc),GET2s(opc)); size=2; break; + case 0x14: sprintf(buffer,"SHL %X,%s",UI5(opc),GET2s(opc)); size=2; break; + case 0x15: sprintf(buffer,"SHR %X,%s",UI5(opc),GET2s(opc)); size=2; break; + case 0x16: sprintf(buffer,"EI"); size=2; break; + case 0x17: sprintf(buffer,"SAR %X,%s",UI5(opc),GET2s(opc)); size=2; break; + case 0x18: sprintf(buffer,"TRAP %X",I5(opc)); size=2; break; + case 0x19: sprintf(buffer,"RETI"); size=2; flags = DASMFLAG_STEP_OUT; break; + case 0x1a: sprintf(buffer,"HALT"); size=2; break; + case 0x1b: sprintf(buffer,"Unk 0x1B"); size=2; break; + case 0x1c: sprintf(buffer,"LDSR %s,%s",GET2s(opc),GETRs(opc));size=2; break; + case 0x1d: sprintf(buffer,"STSR %s,%s",GETRs(opc),GET2s(opc));size=2; break; + case 0x1e: sprintf(buffer,"DI"); size=2; break; + case 0x1f: + switch(opc&0x1f) + { + case 0x00: sprintf(buffer,"SCH0BSU"); break; + case 0x01: sprintf(buffer,"SCH0BSD"); break; + case 0x02: sprintf(buffer,"SCH1BSU"); break; + case 0x03: sprintf(buffer,"SCH1BSD"); break; + case 0x04: sprintf(buffer,"UnkS 4"); break; + case 0x05: sprintf(buffer,"UnkS 5"); break; + case 0x06: sprintf(buffer,"UnkS 6"); break; + case 0x08: sprintf(buffer,"ORBSU"); break; + case 0x09: sprintf(buffer,"ANDBSU"); break; + case 0x0a: sprintf(buffer,"XORBSU"); break; + case 0x0b: sprintf(buffer,"MOVBSU"); break; + case 0x0c: sprintf(buffer,"ORNBSU"); break; + case 0x0d: sprintf(buffer,"ANDNBSU"); break; + case 0x0e: sprintf(buffer,"XORNBSU"); break; + case 0x0f: sprintf(buffer,"NOTBSU"); break; + default: sprintf(buffer,"UnkBS 0x%X",opc&0x1f); break; + } + size=2; + break; + case 0x20: + case 0x21: + case 0x22: + case 0x23: + case 0x24: + case 0x25: + case 0x26: + case 0x27: switch( (opc>>9) &0xf) + { + case 0x0: sprintf(buffer,"BV %X",pc+D9(opc)); break; + case 0x1: sprintf(buffer,"BL %X",pc+D9(opc)); break; + case 0x2: sprintf(buffer,"BE %X",pc+D9(opc)); break; + case 0x3: sprintf(buffer,"BNH %X",pc+D9(opc)); break; + case 0x4: sprintf(buffer,"BN %X",pc+D9(opc)); break; + case 0x5: sprintf(buffer,"BR %X",pc+D9(opc)); break; + case 0x6: sprintf(buffer,"BLT %X",pc+D9(opc)); break; + case 0x7: sprintf(buffer,"BLE %X",pc+D9(opc)); break; + case 0x8: sprintf(buffer,"BNV %X",pc+D9(opc)); break; + case 0x9: sprintf(buffer,"BNL %X",pc+D9(opc)); break; + case 0xa: sprintf(buffer,"BNE %X",pc+D9(opc)); break; + case 0xb: sprintf(buffer,"BH %X",pc+D9(opc)); break; + case 0xc: sprintf(buffer,"BP %X",pc+D9(opc)); break; + case 0xd: sprintf(buffer,"NOP"); break; + case 0xe: sprintf(buffer,"BGE %X",pc+D9(opc)); break; + case 0xf: sprintf(buffer,"BGT %X",pc+D9(opc)); break; + } + size=2; + break; + + case 0x28: sprintf(buffer,"MOVEA %X, %s, %s",I16(opc2),GET1s(opc),GET2s(opc));size=4; break; + case 0x29: sprintf(buffer,"ADDI %X, %s, %s",I16(opc2),GET1s(opc),GET2s(opc));size=4; break; + case 0x2a: sprintf(buffer,"JR %X",pc+D26(opc,opc2));size=4; break; + case 0x2b: sprintf(buffer,"JAL %X",pc+D26(opc,opc2));size=4; flags = DASMFLAG_STEP_OVER; break; + case 0x2c: sprintf(buffer,"ORI %X, %s, %s",UI16(opc2),GET1s(opc),GET2s(opc));size=4; break; + case 0x2d: sprintf(buffer,"ANDI %X, %s, %s",UI16(opc2),GET1s(opc),GET2s(opc));size=4; break; + case 0x2e: sprintf(buffer,"XORI %X, %s, %s",UI16(opc2),GET1s(opc),GET2s(opc));size=4; break; + case 0x2f: sprintf(buffer,"MOVHI %X, %s, %s",UI16(opc2),GET1s(opc),GET2s(opc));size=4; break; + case 0x30: sprintf(buffer,"LDB %X[%s], %s",D16(opc2),GET1s(opc),GET2s(opc));size=4; break; + case 0x31: sprintf(buffer,"LDH %X[%s], %s",D16(opc2),GET1s(opc),GET2s(opc));size=4; break; + case 0x32: sprintf(buffer,"Unk 0x32"); size=2; break; + case 0x33: sprintf(buffer,"LDW %X[%s], %s",D16(opc2),GET1s(opc),GET2s(opc));size=4; break; + case 0x34: sprintf(buffer,"STB %s, %X[%s]",GET2s(opc),D16(opc2),GET1s(opc));size=4; break; + case 0x35: sprintf(buffer,"STH %s, %X[%s]",GET2s(opc),D16(opc2),GET1s(opc));size=4; break; + case 0x36: sprintf(buffer,"Unk 0x36"); size=2; break; + case 0x37: sprintf(buffer,"STW %s, %X[%s]",GET2s(opc),D16(opc2),GET1s(opc));size=4; break; + case 0x38: sprintf(buffer,"INB %X[%s], %s",D16(opc2),GET1s(opc),GET2s(opc));size=4; break; + case 0x39: sprintf(buffer,"INH %X[%s], %s",D16(opc2),GET1s(opc),GET2s(opc));size=4; break; + case 0x3a: sprintf(buffer,"CAXI %X[%s], %s",D16(opc2),GET1s(opc),GET2s(opc));size=4; break; + case 0x3b: sprintf(buffer,"INW %X[%s], %s",D16(opc2),GET1s(opc),GET2s(opc));size=4; break; + + case 0x3c: sprintf(buffer,"OUTB %s, %X[%s]",GET2s(opc),D16(opc2),GET1s(opc));size=4; break; + case 0x3d: sprintf(buffer,"OUTH %s, %X[%s]",GET2s(opc),D16(opc2),GET1s(opc));size=4; break; + case 0x3e: + switch((opc2&0xfc00)>>10) + { + case 0x0: sprintf(buffer,"CMPF.S %s, %s",GET1s(opc),GET2s(opc)); break; + case 0x2: sprintf(buffer,"CVT.WS %s, %s",GET1s(opc),GET2s(opc)); break; + case 0x3: sprintf(buffer,"CVT.SW %s, %s",GET1s(opc),GET2s(opc)); break; + case 0x4: sprintf(buffer,"ADDF.S %s, %s",GET1s(opc),GET2s(opc)); break; + case 0x5: sprintf(buffer,"SUBF.S %s, %s",GET1s(opc),GET2s(opc)); break; + case 0x6: sprintf(buffer,"MULF.S %s, %s",GET1s(opc),GET2s(opc)); break; + case 0x7: sprintf(buffer,"DIVF.S %s, %s",GET1s(opc),GET2s(opc)); break; + case 0xb: sprintf(buffer,"TRNC.SW %s, %s",GET1s(opc),GET2s(opc)); break; + default : sprintf(buffer,"Unkf 0x%X",(opc2&0xfc00)>>10); break; + } + size=4; + break; + case 0x3f: sprintf(buffer,"OUTW %s, %X[%s]",GET2s(opc),D16(opc2),GET1s(opc));size=4; break; + + default : size=2; + } + return size | flags | DASMFLAG_SUPPORTED; +} diff --git a/src/devices/cpu/vtlb.c b/src/devices/cpu/vtlb.c new file mode 100644 index 00000000000..f5a488100f7 --- /dev/null +++ b/src/devices/cpu/vtlb.c @@ -0,0 +1,310 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + vtlb.c + + Generic virtual TLB implementation. + +***************************************************************************/ + +#include "emu.h" +#include "vtlb.h" + + + +/*************************************************************************** + DEBUGGING +***************************************************************************/ + +#define PRINTF_TLB (0) + + + +/*************************************************************************** + TYPE DEFINITIONS +***************************************************************************/ + +/* VTLB state */ +struct vtlb_state +{ + cpu_device * cpudevice; /* CPU device */ + address_spacenum space; /* address space */ + int dynamic; /* number of dynamic entries */ + int fixed; /* number of fixed entries */ + int dynindex; /* index of next dynamic entry */ + int pageshift; /* bits to shift to get page index */ + int addrwidth; /* logical address bus width */ + std::vector live; /* array of live entries by table index */ + std::vector fixedpages; /* number of pages each fixed entry covers */ + std::vector table; /* table of entries by address */ +}; + + + +/*************************************************************************** + INITIALIZATION/TEARDOWN +***************************************************************************/ + +/*------------------------------------------------- + vtlb_alloc - allocate a new VTLB for the + given CPU +-------------------------------------------------*/ + +vtlb_state *vtlb_alloc(device_t *cpu, address_spacenum space, int fixed_entries, int dynamic_entries) +{ + vtlb_state *vtlb; + + /* allocate memory for the core structure */ + vtlb = auto_alloc_clear(cpu->machine(), vtlb_state); + + /* fill in CPU information */ + vtlb->cpudevice = downcast(cpu); + vtlb->space = space; + vtlb->dynamic = dynamic_entries; + vtlb->fixed = fixed_entries; + const address_space_config *spaceconfig = device_get_space_config(*cpu, space); + assert(spaceconfig != NULL); + vtlb->pageshift = spaceconfig->m_page_shift; + vtlb->addrwidth = spaceconfig->m_logaddr_width; + + /* validate CPU information */ + assert((1 << vtlb->pageshift) > VTLB_FLAGS_MASK); + assert(vtlb->addrwidth > vtlb->pageshift); + + /* allocate the entry array */ + vtlb->live.resize(fixed_entries + dynamic_entries); + memset(&vtlb->live[0], 0, vtlb->live.size()*sizeof(vtlb->live[0])); + cpu->save_item(NAME(vtlb->live)); + + /* allocate the lookup table */ + vtlb->table.resize((size_t) 1 << (vtlb->addrwidth - vtlb->pageshift)); + memset(&vtlb->table[0], 0, vtlb->table.size()*sizeof(vtlb->table[0])); + cpu->save_item(NAME(vtlb->table)); + + /* allocate the fixed page count array */ + if (fixed_entries > 0) + { + vtlb->fixedpages.resize(fixed_entries); + memset(&vtlb->fixedpages[0], 0, fixed_entries*sizeof(vtlb->fixedpages[0])); + cpu->save_item(NAME(vtlb->fixedpages)); + } + return vtlb; +} + + +/*------------------------------------------------- + vtlb_free - free an allocated VTLB +-------------------------------------------------*/ + +void vtlb_free(vtlb_state *vtlb) +{ + auto_free(vtlb->cpudevice->machine(), vtlb); +} + + + +/*************************************************************************** + FILLING +***************************************************************************/ + +/*------------------------------------------------- + vtlb_fill - rcalled by the CPU core in + response to an unmapped access +-------------------------------------------------*/ + +int vtlb_fill(vtlb_state *vtlb, offs_t address, int intention) +{ + offs_t tableindex = address >> vtlb->pageshift; + vtlb_entry entry = vtlb->table[tableindex]; + offs_t taddress; + + if (PRINTF_TLB) + printf("vtlb_fill: %08X(%X) ... ", address, intention); + + /* should not be called here if the entry is in the table already */ +// assert((entry & (1 << intention)) == 0); + + /* if we have no dynamic entries, we always fail */ + if (vtlb->dynamic == 0) + { + if (PRINTF_TLB) + printf("failed: no dynamic entries\n"); + return FALSE; + } + + /* ask the CPU core to translate for us */ + taddress = address; + if (!vtlb->cpudevice->translate(vtlb->space, intention, taddress)) + { + if (PRINTF_TLB) + printf("failed: no translation\n"); + return FALSE; + } + + /* if this is the first successful translation for this address, allocate a new entry */ + if ((entry & VTLB_FLAGS_MASK) == 0) + { + int liveindex = vtlb->dynindex++ % vtlb->dynamic; + + /* if an entry already exists at this index, free it */ + if (vtlb->live[liveindex] != 0) + vtlb->table[vtlb->live[liveindex] - 1] = 0; + + /* claim this new entry */ + vtlb->live[liveindex] = tableindex + 1; + + /* form a new blank entry */ + entry = (taddress >> vtlb->pageshift) << vtlb->pageshift; + entry |= VTLB_FLAG_VALID; + + if (PRINTF_TLB) + printf("success (%08X), new entry\n", taddress); + } + + /* otherwise, ensure that different intentions do not produce different addresses */ + else + { + assert((entry >> vtlb->pageshift) == (taddress >> vtlb->pageshift)); + assert(entry & VTLB_FLAG_VALID); + + if (PRINTF_TLB) + printf("success (%08X), existing entry\n", taddress); + } + + /* add the intention to the list of valid intentions and store */ + entry |= 1 << (intention & (TRANSLATE_TYPE_MASK | TRANSLATE_USER_MASK)); + vtlb->table[tableindex] = entry; + return TRUE; +} + + +/*------------------------------------------------- + vtlb_load - load a fixed VTLB entry +-------------------------------------------------*/ + +void vtlb_load(vtlb_state *vtlb, int entrynum, int numpages, offs_t address, vtlb_entry value) +{ + offs_t tableindex = address >> vtlb->pageshift; + int liveindex = vtlb->dynamic + entrynum; + int pagenum; + + /* must be in range */ + assert(entrynum >= 0 && entrynum < vtlb->fixed); + + if (PRINTF_TLB) + printf("vtlb_load %d for %d pages at %08X == %08X\n", entrynum, numpages, address, value); + + /* if an entry already exists at this index, free it */ + if (vtlb->live[liveindex] != 0) + { + int pagecount = vtlb->fixedpages[entrynum]; + int oldtableindex = vtlb->live[liveindex] - 1; + for (pagenum = 0; pagenum < pagecount; pagenum++) + vtlb->table[oldtableindex + pagenum] = 0; + } + + /* claim this new entry */ + vtlb->live[liveindex] = tableindex + 1; + + /* store the raw value, making sure the "fixed" flag is set */ + value |= VTLB_FLAG_FIXED; + vtlb->fixedpages[entrynum] = numpages; + for (pagenum = 0; pagenum < numpages; pagenum++) + vtlb->table[tableindex + pagenum] = value + (pagenum << vtlb->pageshift); +} + +/*------------------------------------------------- + vtlb_dynload - load a dynamic VTLB entry +-------------------------------------------------*/ + +void vtlb_dynload(vtlb_state *vtlb, UINT32 index, offs_t address, vtlb_entry value) +{ + vtlb_entry entry = vtlb->table[index]; + + if (vtlb->dynamic == 0) + { + if (PRINTF_TLB) + printf("failed: no dynamic entries\n"); + return; + } + + int liveindex = vtlb->dynindex++ % vtlb->dynamic; + /* is entry already live? */ + if (!(entry & VTLB_FLAG_VALID)) + { + /* if an entry already exists at this index, free it */ + if (vtlb->live[liveindex] != 0) + vtlb->table[vtlb->live[liveindex] - 1] = 0; + + /* claim this new entry */ + vtlb->live[liveindex] = index + 1; + } + /* form a new blank entry */ + entry = (address >> vtlb->pageshift) << vtlb->pageshift; + entry |= VTLB_FLAG_VALID | value; + + if (PRINTF_TLB) + printf("success (%08X), new entry\n", address); + + vtlb->table[index] = entry; +} + +/*************************************************************************** + FLUSHING +***************************************************************************/ + +/*------------------------------------------------- + vtlb_flush_dynamic - flush all knowledge + from the dynamic part of the VTLB +-------------------------------------------------*/ + +void vtlb_flush_dynamic(vtlb_state *vtlb) +{ + int liveindex; + + if (PRINTF_TLB) + printf("vtlb_flush_dynamic\n"); + + /* loop over live entries and release them from the table */ + for (liveindex = 0; liveindex < vtlb->dynamic; liveindex++) + if (vtlb->live[liveindex] != 0) + { + offs_t tableindex = vtlb->live[liveindex] - 1; + vtlb->table[tableindex] = 0; + vtlb->live[liveindex] = 0; + } +} + + +/*------------------------------------------------- + vtlb_flush_address - flush knowledge of a + particular address from the VTLB +-------------------------------------------------*/ + +void vtlb_flush_address(vtlb_state *vtlb, offs_t address) +{ + offs_t tableindex = address >> vtlb->pageshift; + + if (PRINTF_TLB) + printf("vtlb_flush_address %08X\n", address); + + /* free the entry in the table; for speed, we leave the entry in the live array */ + vtlb->table[tableindex] = 0; +} + + + +/*************************************************************************** + ACCESSORS +***************************************************************************/ + +/*------------------------------------------------- + vtlb_table - return a pointer to the base of + the linear VTLB lookup table +-------------------------------------------------*/ + +const vtlb_entry *vtlb_table(vtlb_state *vtlb) +{ + return &vtlb->table[0]; +} diff --git a/src/devices/cpu/vtlb.h b/src/devices/cpu/vtlb.h new file mode 100644 index 00000000000..f63a0ac50f6 --- /dev/null +++ b/src/devices/cpu/vtlb.h @@ -0,0 +1,88 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + vtlb.h + + Generic virtual TLB implementation. + +***************************************************************************/ + +#pragma once + +#ifndef __VTLB_H__ +#define __VTLB_H__ + + + +/*************************************************************************** + CONSTANTS +***************************************************************************/ + +#define VTLB_FLAGS_MASK 0xff + +#define VTLB_READ_ALLOWED 0x01 /* (1 << TRANSLATE_READ) */ +#define VTLB_WRITE_ALLOWED 0x02 /* (1 << TRANSLATE_WRITE) */ +#define VTLB_FETCH_ALLOWED 0x04 /* (1 << TRANSLATE_FETCH) */ +#define VTLB_FLAG_VALID 0x08 +#define VTLB_USER_READ_ALLOWED 0x10 /* (1 << TRANSLATE_READ_USER) */ +#define VTLB_USER_WRITE_ALLOWED 0x20 /* (1 << TRANSLATE_WRITE_USER) */ +#define VTLB_USER_FETCH_ALLOWED 0x40 /* (1 << TRANSLATE_FETCH_USER) */ +#define VTLB_FLAG_FIXED 0x80 + + + +/*************************************************************************** + TYPE DEFINITIONS +***************************************************************************/ + +/* represents an entry in the VTLB */ +typedef UINT32 vtlb_entry; + + +/* opaque structure describing VTLB state */ +struct vtlb_state; + + + +/*************************************************************************** + FUNCTION PROTOTYPES +***************************************************************************/ + + +/* ----- initialization/teardown ----- */ + +/* allocate a new VTLB for the given CPU */ +vtlb_state *vtlb_alloc(device_t *cpu, address_spacenum space, int fixed_entries, int dynamic_entries); + +/* free an allocated VTLB */ +void vtlb_free(vtlb_state *vtlb); + + +/* ----- filling ----- */ + +/* called by the CPU core in response to an unmapped access */ +int vtlb_fill(vtlb_state *vtlb, offs_t address, int intention); + +/* load a fixed VTLB entry */ +void vtlb_load(vtlb_state *vtlb, int entrynum, int numpages, offs_t address, vtlb_entry value); + +/* load a dynamic VTLB entry */ +void vtlb_dynload(vtlb_state *vtlb, UINT32 index, offs_t address, vtlb_entry value); + +/* ----- flushing ----- */ + +/* flush all knowledge from the dynamic part of the VTLB */ +void vtlb_flush_dynamic(vtlb_state *vtlb); + +/* flush knowledge of a particular address from the VTLB */ +void vtlb_flush_address(vtlb_state *vtlb, offs_t address); + + +/* ----- accessors ----- */ + +/* return a pointer to the base of the linear VTLB lookup table */ +const vtlb_entry *vtlb_table(vtlb_state *vtlb); + + +#endif /* __VTLB_H__ */ diff --git a/src/devices/cpu/x86emit.h b/src/devices/cpu/x86emit.h new file mode 100644 index 00000000000..45e1c456737 --- /dev/null +++ b/src/devices/cpu/x86emit.h @@ -0,0 +1,3188 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + x86emit.h + + Generic x86/x64 code emitters. + +**************************************************************************** + + Important note: + + It is assumed in 64-bit mode that all byte register accesses are + intended to be to the low 8 bits (SPL,BPL,SIL,DIL) and not to the + upper half (AH,CH,DH,BH). + +***************************************************************************/ + + +//************************************************************************** +// SHARED DEFINITIONS +//************************************************************************** + +#ifndef __X86EMIT_H__ +#define __X86EMIT_H__ + +// use x86code * to reference generated code +typedef UINT8 x86code; + +// this structure tracks information about a link +struct emit_link +{ + x86code * target; + UINT8 size; +}; + +// structure for describing memory references +class x86_memref +{ +public: + x86_memref(UINT8 basereg, UINT8 indreg, UINT8 scale, INT32 disp) + : m_base(basereg), + m_index(indreg), + m_scale(scale), + m_disp(disp) { } + + x86_memref operator+(INT32 offset) { return x86_memref(m_base, m_index, m_scale, m_disp + offset); } + + UINT8 m_base; + UINT8 m_index; + UINT8 m_scale; + INT32 m_disp; +}; + +#endif + + + +//************************************************************************** +// 32-BIT and 64-BIT SPECIFIC DEFINITIONS +//************************************************************************** + +#ifdef X86EMIT_SIZE + +#if (X86EMIT_SIZE != 32 && X86EMIT_SIZE != 64) +#error Must specify X86EMIT_SIZE as either 32 or 64! +#endif + +// put emitters into their own namespace so they don't clash +#if (X86EMIT_SIZE == 32) +namespace x86emit +#else +namespace x64emit +#endif +{ +//************************************************************************** +// CONSTANTS +//************************************************************************** + +// opcode size flag; low 4 bits must match REX low 4 bits, hence the odd numbers here +const UINT8 OP_16BIT = 0x10; +const UINT8 OP_32BIT = 0x00; +const UINT8 OP_64BIT = 0x08; + +// 16 registers on x64, only 8 on x86 +#if (X86EMIT_SIZE == 64) +const int REG_MAX = 16; +#else +const int REG_MAX = 8; +#endif + +// invalid register index for "none" +const UINT8 REG_NONE = REG_MAX; + +// 8-bit registers -- note that we assume a flat model for 64-bit +const UINT8 REG_AL = 0; +const UINT8 REG_CL = 1; +const UINT8 REG_DL = 2; +const UINT8 REG_BL = 3; +#if (X86EMIT_SIZE == 32) +const UINT8 REG_AH = 4; +const UINT8 REG_CH = 5; +const UINT8 REG_DH = 6; +const UINT8 REG_BH = 7; +#else +const UINT8 REG_SPL = 4; +const UINT8 REG_BPL = 5; +const UINT8 REG_SIL = 6; +const UINT8 REG_DIL = 7; +const UINT8 REG_R8L = 8; +const UINT8 REG_R9L = 9; +const UINT8 REG_R10L = 10; +const UINT8 REG_R11L = 11; +const UINT8 REG_R12L = 12; +const UINT8 REG_R13L = 13; +const UINT8 REG_R14L = 14; +const UINT8 REG_R15L = 15; +#endif + +// 16-bit registers +const UINT8 REG_AX = 0; +const UINT8 REG_CX = 1; +const UINT8 REG_DX = 2; +const UINT8 REG_BX = 3; +const UINT8 REG_SP = 4; +const UINT8 REG_BP = 5; +const UINT8 REG_SI = 6; +const UINT8 REG_DI = 7; +#if (X86EMIT_SIZE == 64) +const UINT8 REG_R8W = 8; +const UINT8 REG_R9W = 9; +const UINT8 REG_R10W = 10; +const UINT8 REG_R11W = 11; +const UINT8 REG_R12W = 12; +const UINT8 REG_R13W = 13; +const UINT8 REG_R14W = 14; +const UINT8 REG_R15W = 15; +#endif + +// 32-bit registers +const UINT8 REG_EAX = 0; +const UINT8 REG_ECX = 1; +const UINT8 REG_EDX = 2; +const UINT8 REG_EBX = 3; +const UINT8 REG_ESP = 4; +const UINT8 REG_EBP = 5; +const UINT8 REG_ESI = 6; +const UINT8 REG_EDI = 7; +#if (X86EMIT_SIZE == 64) +const UINT8 REG_R8D = 8; +const UINT8 REG_R9D = 9; +const UINT8 REG_R10D = 10; +const UINT8 REG_R11D = 11; +const UINT8 REG_R12D = 12; +const UINT8 REG_R13D = 13; +const UINT8 REG_R14D = 14; +const UINT8 REG_R15D = 15; +#endif + +// 64-bit registers +#if (X86EMIT_SIZE == 64) +const UINT8 REG_RAX = 0; +const UINT8 REG_RCX = 1; +const UINT8 REG_RDX = 2; +const UINT8 REG_RBX = 3; +const UINT8 REG_RSP = 4; +const UINT8 REG_RBP = 5; +const UINT8 REG_RSI = 6; +const UINT8 REG_RDI = 7; +const UINT8 REG_R8 = 8; +const UINT8 REG_R9 = 9; +const UINT8 REG_R10 = 10; +const UINT8 REG_R11 = 11; +const UINT8 REG_R12 = 12; +const UINT8 REG_R13 = 13; +const UINT8 REG_R14 = 14; +const UINT8 REG_R15 = 15; +#endif + +// 64-bit MMX registers +const UINT8 REG_MM0 = 0; +const UINT8 REG_MM1 = 1; +const UINT8 REG_MM2 = 2; +const UINT8 REG_MM3 = 3; +const UINT8 REG_MM4 = 4; +const UINT8 REG_MM5 = 5; +const UINT8 REG_MM6 = 6; +const UINT8 REG_MM7 = 7; +#if (X86EMIT_SIZE == 64) +const UINT8 REG_MM8 = 8; +const UINT8 REG_MM9 = 9; +const UINT8 REG_MM10 = 10; +const UINT8 REG_MM11 = 11; +const UINT8 REG_MM12 = 12; +const UINT8 REG_MM13 = 13; +const UINT8 REG_MM14 = 14; +const UINT8 REG_MM15 = 15; +#endif + +// 128-bit XMM registers +const UINT8 REG_XMM0 = 0; +const UINT8 REG_XMM1 = 1; +const UINT8 REG_XMM2 = 2; +const UINT8 REG_XMM3 = 3; +const UINT8 REG_XMM4 = 4; +const UINT8 REG_XMM5 = 5; +const UINT8 REG_XMM6 = 6; +const UINT8 REG_XMM7 = 7; +#if (X86EMIT_SIZE == 64) +const UINT8 REG_XMM8 = 8; +const UINT8 REG_XMM9 = 9; +const UINT8 REG_XMM10 = 10; +const UINT8 REG_XMM11 = 11; +const UINT8 REG_XMM12 = 12; +const UINT8 REG_XMM13 = 13; +const UINT8 REG_XMM14 = 14; +const UINT8 REG_XMM15 = 15; +#endif + +// conditions +const UINT8 COND_A = 7; +const UINT8 COND_AE = 3; +const UINT8 COND_B = 2; +const UINT8 COND_BE = 6; +const UINT8 COND_C = 2; +const UINT8 COND_E = 4; +const UINT8 COND_Z = 4; +const UINT8 COND_G = 15; +const UINT8 COND_GE = 13; +const UINT8 COND_L = 12; +const UINT8 COND_LE = 14; +const UINT8 COND_NA = 6; +const UINT8 COND_NAE = 2; +const UINT8 COND_NB = 3; +const UINT8 COND_NBE = 7; +const UINT8 COND_NC = 3; +const UINT8 COND_NE = 5; +const UINT8 COND_NG = 14; +const UINT8 COND_NGE = 12; +const UINT8 COND_NL = 13; +const UINT8 COND_NLE = 15; +const UINT8 COND_NO = 1; +const UINT8 COND_NP = 11; +const UINT8 COND_NS = 9; +const UINT8 COND_NZ = 5; +const UINT8 COND_O = 0; +const UINT8 COND_P = 10; +const UINT8 COND_PE = 10; +const UINT8 COND_PO = 11; +const UINT8 COND_S = 8; + +// floating point rounding modes +const UINT8 FPRND_NEAR = 0; +const UINT8 FPRND_DOWN = 1; +const UINT8 FPRND_UP = 2; +const UINT8 FPRND_CHOP = 3; + + + +//************************************************************************** +// OPCODE DEFINITIONS +//************************************************************************** + +// opcode flags (in upper 8 bits of opcode) +const UINT32 OPFLAG_8BITREG = (1 << 24); +const UINT32 OPFLAG_8BITRM = (1 << 25); + +// single byte opcodes +const UINT32 OP_ADD_Eb_Gb = (0x00 | OPFLAG_8BITRM | OPFLAG_8BITREG); +const UINT32 OP_ADD_Ev_Gv = 0x01; +const UINT32 OP_ADD_Gb_Eb = (0x02 | OPFLAG_8BITRM | OPFLAG_8BITREG); +const UINT32 OP_ADD_Gv_Ev = 0x03; +const UINT32 OP_ADD_AL_Ib = 0x04; +const UINT32 OP_ADD_rAX_Iz = 0x05; +const UINT32 OP_PUSH_ES = 0x06; +const UINT32 OP_POP_ES = 0x07; +const UINT32 OP_OR_Eb_Gb = (0x08 | OPFLAG_8BITRM | OPFLAG_8BITREG); +const UINT32 OP_OR_Ev_Gv = 0x09; +const UINT32 OP_OR_Gb_Eb = (0x0a | OPFLAG_8BITRM | OPFLAG_8BITREG); +const UINT32 OP_OR_Gv_Ev = 0x0b; +const UINT32 OP_OR_AL_Ib = 0x0c; +const UINT32 OP_OR_eAX_Iv = 0x0d; +const UINT32 OP_PUSH_CS = 0x0e; +const UINT32 OP_EXTENDED = 0x0f; + +const UINT32 OP_ADC_Eb_Gb = (0x10 | OPFLAG_8BITRM | OPFLAG_8BITREG); +const UINT32 OP_ADC_Ev_Gv = 0x11; +const UINT32 OP_ADC_Gb_Eb = (0x12 | OPFLAG_8BITRM | OPFLAG_8BITREG); +const UINT32 OP_ADC_Gv_Ev = 0x13; +const UINT32 OP_ADC_AL_Ib = 0x14; +const UINT32 OP_ADC_rAX_Iz = 0x15; +const UINT32 OP_PUSH_SS = 0x16; +const UINT32 OP_POP_SS = 0x17; +const UINT32 OP_SBB_Eb_Gb = (0x18 | OPFLAG_8BITRM | OPFLAG_8BITREG); +const UINT32 OP_SBB_Ev_Gv = 0x19; +const UINT32 OP_SBB_Gb_Eb = (0x1a | OPFLAG_8BITRM | OPFLAG_8BITREG); +const UINT32 OP_SBB_Gv_Ev = 0x1b; +const UINT32 OP_SBB_AL_Ib = 0x1c; +const UINT32 OP_SBB_eAX_Iv = 0x1d; +const UINT32 OP_PUSH_DS = 0x1e; +const UINT32 OP_POP_DS = 0x1f; + +const UINT32 OP_AND_Eb_Gb = (0x20 | OPFLAG_8BITRM | OPFLAG_8BITREG); +const UINT32 OP_AND_Ev_Gv = 0x21; +const UINT32 OP_AND_Gb_Eb = (0x22 | OPFLAG_8BITRM | OPFLAG_8BITREG); +const UINT32 OP_AND_Gv_Ev = 0x23; +const UINT32 OP_AND_AL_Ib = 0x24; +const UINT32 OP_AND_rAX_Iz = 0x25; +const UINT32 PREFIX_ES = 0x26; +const UINT32 OP_DAA = 0x27; +const UINT32 OP_SUB_Eb_Gb = (0x28 | OPFLAG_8BITRM | OPFLAG_8BITREG); +const UINT32 OP_SUB_Ev_Gv = 0x29; +const UINT32 OP_SUB_Gb_Eb = (0x2a | OPFLAG_8BITRM | OPFLAG_8BITREG); +const UINT32 OP_SUB_Gv_Ev = 0x2b; +const UINT32 OP_SUB_AL_Ib = 0x2c; +const UINT32 OP_SUB_eAX_Iv = 0x2d; +const UINT32 PREFIX_CS = 0x2e; +const UINT32 OP_DAS = 0x2f; + +const UINT32 OP_XOR_Eb_Gb = (0x30 | OPFLAG_8BITRM | OPFLAG_8BITREG); +const UINT32 OP_XOR_Ev_Gv = 0x31; +const UINT32 OP_XOR_Gb_Eb = (0x32 | OPFLAG_8BITRM | OPFLAG_8BITREG); +const UINT32 OP_XOR_Gv_Ev = 0x33; +const UINT32 OP_XOR_AL_Ib = 0x34; +const UINT32 OP_XOR_rAX_Iz = 0x35; +const UINT32 PREFIX_SS = 0x36; +const UINT32 OP_AAA = 0x37; +const UINT32 OP_CMP_Eb_Gb = (0x38 | OPFLAG_8BITRM | OPFLAG_8BITREG); +const UINT32 OP_CMP_Ev_Gv = 0x39; +const UINT32 OP_CMP_Gb_Eb = (0x3a | OPFLAG_8BITRM | OPFLAG_8BITREG); +const UINT32 OP_CMP_Gv_Ev = 0x3b; +const UINT32 OP_CMP_AL_Ib = 0x3c; +const UINT32 OP_CMP_eAX_Iv = 0x3d; +const UINT32 PREFIX_DS = 0x3e; +const UINT32 OP_AAS = 0x3f; + +const UINT32 OP_REX = 0x40; +const UINT32 OP_REX_B = 0x41; +const UINT32 OP_REX_X = 0x42; +const UINT32 OP_REX_XB = 0x43; +const UINT32 OP_REX_R = 0x44; +const UINT32 OP_REX_RB = 0x45; +const UINT32 OP_REX_RX = 0x46; +const UINT32 OP_REX_RXB = 0x47; +const UINT32 OP_REX_W = 0x48; +const UINT32 OP_REX_WB = 0x49; +const UINT32 OP_REX_WX = 0x4a; +const UINT32 OP_REX_WXB = 0x4b; +const UINT32 OP_REX_WR = 0x4c; +const UINT32 OP_REX_WRB = 0x4d; +const UINT32 OP_REX_WRX = 0x4e; +const UINT32 OP_REX_WRXB = 0x4f; + +const UINT32 OP_PUSH_rAX = 0x50; +const UINT32 OP_PUSH_rCX = 0x51; +const UINT32 OP_PUSH_rDX = 0x52; +const UINT32 OP_PUSH_rBX = 0x53; +const UINT32 OP_PUSH_rSP = 0x54; +const UINT32 OP_PUSH_rBP = 0x55; +const UINT32 OP_PUSH_rSI = 0x56; +const UINT32 OP_PUSH_rDI = 0x57; +const UINT32 OP_POP_rAX = 0x58; +const UINT32 OP_POP_rCX = 0x59; +const UINT32 OP_POP_rDX = 0x5a; +const UINT32 OP_POP_rBX = 0x5b; +const UINT32 OP_POP_rSP = 0x5c; +const UINT32 OP_POP_rBP = 0x5d; +const UINT32 OP_POP_rSI = 0x5e; +const UINT32 OP_POP_rDI = 0x5f; + +const UINT32 OP_PUSHA = 0x60; +const UINT32 OP_POPA = 0x61; +const UINT32 OP_BOUND_Gv_Ma = 0x62; +const UINT32 OP_ARPL_Ew_Gw = 0x63; +const UINT32 OP_MOVSXD_Gv_Ev = 0x63; +const UINT32 PREFIX_FS = 0x64; +const UINT32 PREFIX_GS = 0x65; +const UINT32 PREFIX_OPSIZE = 0x66; +const UINT32 PREFIX_ADSIZE = 0x67; +const UINT32 OP_PUSH_Iz = 0x68; +const UINT32 OP_IMUL_Gv_Ev_Iz = 0x69; +const UINT32 OP_PUSH_Ib = 0x6a; +const UINT32 OP_IMUL_Gv_Ev_Ib = 0x6b; +const UINT32 OP_INS_Yb_DX = 0x6c; +const UINT32 OP_INS_Yz_DX = 0x6d; +const UINT32 OP_OUTS_DX_Xb = 0x6e; +const UINT32 OP_OUTS_DX_Xz = 0x6f; + +const UINT32 OP_JCC_O_Jb = 0x70; +const UINT32 OP_JCC_NO_Jb = 0x71; +const UINT32 OP_JCC_B_Jb = 0x72; +const UINT32 OP_JCC_C_Jb = 0x72; +const UINT32 OP_JCC_NAE_Jb = 0x72; +const UINT32 OP_JCC_AE_Jb = 0x73; +const UINT32 OP_JCC_NB_Jb = 0x73; +const UINT32 OP_JCC_NC_Jb = 0x73; +const UINT32 OP_JCC_E_Jb = 0x74; +const UINT32 OP_JCC_Z_Jb = 0x74; +const UINT32 OP_JCC_NE_Jb = 0x75; +const UINT32 OP_JCC_NZ_Jb = 0x75; +const UINT32 OP_JCC_BE_Jb = 0x76; +const UINT32 OP_JCC_NA_Jb = 0x76; +const UINT32 OP_JCC_A_Jb = 0x77; +const UINT32 OP_JCC_NBE_Jb = 0x77; +const UINT32 OP_JCC_S_Jb = 0x78; +const UINT32 OP_JCC_NS_Jb = 0x79; +const UINT32 OP_JCC_P_Jb = 0x7a; +const UINT32 OP_JCC_PE_Jb = 0x7a; +const UINT32 OP_JCC_NP_Jb = 0x7b; +const UINT32 OP_JCC_PO_Jb = 0x7b; +const UINT32 OP_JCC_L_Jb = 0x7c; +const UINT32 OP_JCC_NGE_Jb = 0x7c; +const UINT32 OP_JCC_NL_Jb = 0x7d; +const UINT32 OP_JCC_GE_Jb = 0x7d; +const UINT32 OP_JCC_LE_Jb = 0x7e; +const UINT32 OP_JCC_NG_Jb = 0x7e; +const UINT32 OP_JCC_NLE_Jb = 0x7f; +const UINT32 OP_JCC_G_Jb = 0x7f; + +const UINT32 OP_G1_Eb_Ib = (0x80 | OPFLAG_8BITRM); +const UINT32 OP_G1_Ev_Iz = 0x81; +const UINT32 OP_G1_Eb_Ibx = (0x82 | OPFLAG_8BITRM); +const UINT32 OP_G1_Ev_Ib = 0x83; +const UINT32 OP_TEST_Eb_Gb = (0x84 | OPFLAG_8BITRM | OPFLAG_8BITREG); +const UINT32 OP_TEST_Ev_Gv = 0x85; +const UINT32 OP_XCHG_Eb_Gb = (0x86 | OPFLAG_8BITRM | OPFLAG_8BITREG); +const UINT32 OP_XCHG_Ev_Gv = 0x87; +const UINT32 OP_MOV_Eb_Gb = (0x88 | OPFLAG_8BITRM | OPFLAG_8BITREG); +const UINT32 OP_MOV_Ev_Gv = 0x89; +const UINT32 OP_MOV_Gb_Eb = (0x8a | OPFLAG_8BITRM | OPFLAG_8BITREG); +const UINT32 OP_MOV_Gv_Ev = 0x8b; +const UINT32 OP_MOV_Ev_Sw = 0x8c; +const UINT32 OP_LEA_Gv_M = 0x8d; +const UINT32 OP_MOV_Sw_Ew = 0x8e; +const UINT32 OP_G1A_Ev = 0x8f; + +const UINT32 OP_NOP = 0x90; +const UINT32 OP_PAUSE = 0x90; +const UINT32 OP_XCHG_rCX = 0x91; +const UINT32 OP_XCHG_rDX = 0x92; +const UINT32 OP_XCHG_rBX = 0x93; +const UINT32 OP_XCHG_rSP = 0x94; +const UINT32 OP_XCHG_rBP = 0x95; +const UINT32 OP_XCHG_rSI = 0x96; +const UINT32 OP_XCHG_rDI = 0x97; +const UINT32 OP_CBW = 0x98; +const UINT32 OP_CWDE = 0x98; +const UINT32 OP_CDQE = 0x98; +const UINT32 OP_CWD = 0x99; +const UINT32 OP_CDQ = 0x99; +const UINT32 OP_CQO = 0x99; +const UINT32 OP_CALLF_Ap = 0x9a; +const UINT32 OP_FWAIT = 0x9b; +const UINT32 OP_PUSHF_Fv = 0x9c; +const UINT32 OP_POPF_Fv = 0x9d; +const UINT32 OP_SAHF = 0x9e; +const UINT32 OP_LAHF = 0x9f; + +const UINT32 OP_MOV_AL_Ob = 0xa0; +const UINT32 OP_MOV_rAX_Ov = 0xa1; +const UINT32 OP_MOV_Ob_AL = 0xa2; +const UINT32 OP_MOV_Ov_rAX = 0xa3; +const UINT32 OP_MOVS_Xb_Yb = 0xa4; +const UINT32 OP_MOVS_Xv_Yv = 0xa5; +const UINT32 OP_CMPS_Xb_Yb = 0xa6; +const UINT32 OP_CMPS_Xv_Yv = 0xa7; +const UINT32 OP_TEST_AL_Ib = 0xa8; +const UINT32 OP_TEST_rAX_Iz = 0xa9; +const UINT32 OP_STOS_Yb_AL = 0xaa; +const UINT32 OP_STOS_Yv_rAX = 0xab; +const UINT32 OP_LODS_AL_Xb = 0xac; +const UINT32 OP_LODS_rAX_Xv = 0xad; +const UINT32 OP_SCAS_AL_Yb = 0xae; +const UINT32 OP_SCAC_rAX_Yv = 0xaf; + +const UINT32 OP_MOV_AL_Ib = 0xb0; +const UINT32 OP_MOV_CL_Ib = 0xb1; +const UINT32 OP_MOV_DL_Ib = 0xb2; +const UINT32 OP_MOV_BL_Ib = 0xb3; +const UINT32 OP_MOV_AH_Ib = 0xb4; +const UINT32 OP_MOV_CH_Ib = 0xb5; +const UINT32 OP_MOV_DH_Ib = 0xb6; +const UINT32 OP_MOV_BH_Ib = 0xb7; +const UINT32 OP_MOV_rAX_Iv = 0xb8; +const UINT32 OP_MOV_rCX_Iv = 0xb9; +const UINT32 OP_MOV_rDX_Iv = 0xba; +const UINT32 OP_MOV_rBX_Iv = 0xbb; +const UINT32 OP_MOV_rSP_Iv = 0xbc; +const UINT32 OP_MOV_rBP_Iv = 0xbd; +const UINT32 OP_MOV_rSI_Iv = 0xbe; +const UINT32 OP_MOV_rDI_Iv = 0xbf; + +const UINT32 OP_G2_Eb_Ib = (0xc0 | OPFLAG_8BITRM); +const UINT32 OP_G2_Ev_Ib = 0xc1; +const UINT32 OP_RETN_Iw = 0xc2; +const UINT32 OP_RETN = 0xc3; +const UINT32 OP_LES_Gz_Mp = 0xc4; +const UINT32 OP_LDS_Gz_Mp = 0xc5; +const UINT32 OP_G11_Eb_Ib = (0xc6 | OPFLAG_8BITRM); +const UINT32 OP_G11_Ev_Iz = 0xc7; +const UINT32 OP_ENTER_Iw_Ib = 0xc8; +const UINT32 OP_LEAVE = 0xc9; +const UINT32 OP_RETF_Iw = 0xca; +const UINT32 OP_RETF = 0xcb; +const UINT32 OP_INT_3 = 0xcc; +const UINT32 OP_INT_Ib = 0xcd; +const UINT32 OP_INTO = 0xce; +const UINT32 OP_IRET = 0xcf; + +const UINT32 OP_G2_Eb_1 = (0xd0 | OPFLAG_8BITRM); +const UINT32 OP_G2_Ev_1 = 0xd1; +const UINT32 OP_G2_Eb_CL = (0xd2 | OPFLAG_8BITRM); +const UINT32 OP_G2_Ev_CL = 0xd3; +const UINT32 OP_AAM = 0xd4; +const UINT32 OP_AAD = 0xd5; +const UINT32 OP_XLAT = 0xd7; +const UINT32 OP_ESC_D8 = 0xd8; +const UINT32 OP_ESC_D9 = 0xd9; +const UINT32 OP_ESC_DA = 0xda; +const UINT32 OP_ESC_DB = 0xdb; +const UINT32 OP_ESC_DC = 0xdc; +const UINT32 OP_ESC_DD = 0xdd; +const UINT32 OP_ESC_DE = 0xde; +const UINT32 OP_ESC_DF = 0xdf; + +const UINT32 OP_LOOPNE_Jb = 0xe0; +const UINT32 OP_LOOPE_Jb = 0xe1; +const UINT32 OP_LOOP_Jb = 0xe2; +const UINT32 OP_JrCXZ_Jb = 0xe3; +const UINT32 OP_IN_AL_Ib = 0xe4; +const UINT32 OP_IN_eAX_Ib = 0xe5; +const UINT32 OP_OUT_Ib_AL = 0xe6; +const UINT32 OP_OUT_Ib_eAX = 0xe7; +const UINT32 OP_CALL_Jz = 0xe8; +const UINT32 OP_JMP_Jz = 0xe9; +const UINT32 OP_JMPF_AP = 0xea; +const UINT32 OP_JMP_Jb = 0xeb; +const UINT32 OP_IN_AL_DX = 0xec; +const UINT32 OP_IN_eAX_D = 0xed; +const UINT32 OP_OUT_DX_AL = 0xee; +const UINT32 OP_OUT_DX_eAX = 0xef; + +const UINT32 PREFIX_LOCK = 0xf0; +const UINT32 PREFIX_REPNE = 0xf2; +const UINT32 PREFIX_REPE = 0xf3; +const UINT32 OP_HLT = 0xf4; +const UINT32 OP_CMC = 0xf5; +const UINT32 OP_G3_Eb = (0xf6 | OPFLAG_8BITRM); +const UINT32 OP_G3_Ev = 0xf7; +const UINT32 OP_CLC = 0xf8; +const UINT32 OP_STC = 0xf9; +const UINT32 OP_CLI = 0xfa; +const UINT32 OP_STI = 0xfb; +const UINT32 OP_CLD = 0xfc; +const UINT32 OP_STD = 0xfd; +const UINT32 OP_G4 = 0xfe; +const UINT32 OP_G5 = 0xff; + + +// double byte opcodes +const UINT32 OP_G6 = 0x0f00; +const UINT32 OP_G7 = 0x0f01; +const UINT32 OP_LAR_Gv_Ew = 0x0f02; +const UINT32 OP_LSL_Gv_Ew = 0x0f03; +const UINT32 OP_SYSCALL = 0x0f05; +const UINT32 OP_CLTS = 0x0f06; +const UINT32 OP_SYSRET = 0x0f07; +const UINT32 OP_INVD = 0x0f08; +const UINT32 OP_WBINVD = 0x0f09; +const UINT32 OP_UD2 = 0x0f0b; +const UINT32 OP_NOP0d_Ev = 0x0f0d; + +const UINT32 OP_MOVUPS_Vps_Wps = 0x0f10; +const UINT32 OP_MOVSS_Vss_Wss = 0xf30f10; +const UINT32 OP_MOVUPD_Vpd_Wpd = 0x660f10; +const UINT32 OP_MOVSD_Vsd_Wsd = 0xf20f10; +const UINT32 OP_MOVUPS_Wps_Vps = 0x0f11; +const UINT32 OP_MOVSS_Wss_Vss = 0xf30f11; +const UINT32 OP_MOVUPD_Wpd_Vpd = 0x660f11; +const UINT32 OP_MOVSD_Wsd_Vsd = 0xf20f11; +const UINT32 OP_MOVLPS_Vq_Mq = 0x0f12; +const UINT32 OP_MOVLPD_Vq_Mq = 0x660f12; +const UINT32 OP_MOVHLPS_Vq_Uq = 0x0f12; +const UINT32 OP_MOVDDUP_Vq_Wq = 0xf20f12; +const UINT32 OP_MOVSLDUP_Vq_Wq = 0xf30f12; +const UINT32 OP_MOVLPS_Mq_Vq = 0x0f13; +const UINT32 OP_MOVLPD_Mq_Vq = 0x660f13; +const UINT32 OP_UNPCKLPS_Vps_Wq = 0x0f14; +const UINT32 OP_UNPCKLPD_Vpd_Wq = 0x660f14; +const UINT32 OP_UNPCKHPS_Vps_Wq = 0x0f15; +const UINT32 OP_UNPCKHPD_Vpd_Wq = 0x660f15; +const UINT32 OP_MOVHPS_Vq_Mq = 0x0f16; +const UINT32 OP_MOVHPD_Vq_Mq = 0x660f16; +const UINT32 OP_MOVLHPS_Vq_Uq = 0x0f16; +const UINT32 OP_MOVSHDUP_Vq_Wq = 0xf30f16; +const UINT32 OP_MOVHPS_Mq_Vq = 0x0f17; +const UINT32 OP_MOVHPD_Mq_Vq = 0x660f17; +const UINT32 OP_PREFETCH_G16 = 0x0f18; +const UINT32 OP_NOP1f_Ev = 0x0f1f; + +const UINT32 OP_MOV_Rd_Cd = 0x0f20; +const UINT32 OP_MOV_Rd_Dd = 0x0f21; +const UINT32 OP_MOV_Cd_Rd = 0x0f22; +const UINT32 OP_MOV_Dd_Rd = 0x0f23; +const UINT32 OP_MOVAPS_Vps_Wps = 0x0f28; +const UINT32 OP_MOVAPD_Vpd_Wpd = 0x660f28; +const UINT32 OP_MOVAPS_Wps_Vps = 0x0f29; +const UINT32 OP_MOVAPD_Wpd_Vpd = 0x660f29; +const UINT32 OP_CVTPI2PS_Vps_Qq = 0x0f2a; +const UINT32 OP_CVTSI2SS_Vss_Ed = 0xf30f2a; +const UINT32 OP_CVTPI2PD_Vpd_Qq = 0x660f2a; +const UINT32 OP_CVTSI2SD_Vsd_Ed = 0xf20f2a; +const UINT32 OP_MOVNTPS_Mps_Vps = 0x0f2b; +const UINT32 OP_MOVNTPD_Mpd_Vpd = 0x660f2b; +const UINT32 OP_CVTTPS2PI_Pq_Wq = 0x0f2c; +const UINT32 OP_CVTTSS2SI_Gd_Wss = 0xf30f2c; +const UINT32 OP_CVTTPD2PI_Pq_Wpd = 0x660f2c; +const UINT32 OP_CVTTSD2SI_Gd_Wsd = 0xf20f2c; +const UINT32 OP_CVTPS2PI_Pq_Wq = 0x0f2d; +const UINT32 OP_CVTSS2SI_Gd_Wss = 0xf30f2d; +const UINT32 OP_CVTPD2PI_Pq_Wpd = 0x660f2d; +const UINT32 OP_CVTSD2SI_Gd_Wsd = 0xf20f2d; +const UINT32 OP_UCOMISS_Vss_Wss = 0x0f2e; +const UINT32 OP_UCOMISD_Vsd_Wsd = 0x660f2e; +const UINT32 OP_COMISS_Vss_Wss = 0x0f2f; +const UINT32 OP_COMISD_Vsd_Wsd = 0x660f2f; + +const UINT32 OP_WRMSR = 0x0f30; +const UINT32 OP_RDTSC = 0x0f31; +const UINT32 OP_RDMSR = 0x0f32; +const UINT32 OP_RDPMC = 0x0f33; +const UINT32 OP_SYSENTER = 0x0f34; +const UINT32 OP_SYSEXIT = 0x0f35; +const UINT32 OP_GETSEC = 0x0f37; + +const UINT32 OP_CMOV_O_Gv_Ev = 0x0f40; +const UINT32 OP_CMOV_NO_Gv_Ev = 0x0f41; +const UINT32 OP_CMOV_B_Gv_Ev = 0x0f42; +const UINT32 OP_CMOV_C_Gv_Ev = 0x0f42; +const UINT32 OP_CMOV_AE_Gv_Ev = 0x0f43; +const UINT32 OP_CMOV_NC_Gv_Ev = 0x0f43; +const UINT32 OP_CMOV_E_Gv_Ev = 0x0f44; +const UINT32 OP_CMOV_Z_Gv_Ev = 0x0f44; +const UINT32 OP_CMOV_NE_Gv_Ev = 0x0f45; +const UINT32 OP_CMOV_NZ_Gv_Ev = 0x0f45; +const UINT32 OP_CMOV_BE_Gv_Ev = 0x0f46; +const UINT32 OP_CMOV_A_Gv_Ev = 0x0f47; +const UINT32 OP_CMOV_S_Gv_Ev = 0x0f48; +const UINT32 OP_CMOV_NS_Gv_Ev = 0x0f49; +const UINT32 OP_CMOV_P_Gv_Ev = 0x0f4a; +const UINT32 OP_CMOV_PE_Gv_Ev = 0x0f4a; +const UINT32 OP_CMOV_NP_Gv_Ev = 0x0f4b; +const UINT32 OP_CMOV_PO_Gv_Ev = 0x0f4b; +const UINT32 OP_CMOV_L_Gv_Ev = 0x0f4c; +const UINT32 OP_CMOV_NGE_Gv_Ev = 0x0f4c; +const UINT32 OP_CMOV_NL_Gv_Ev = 0x0f4d; +const UINT32 OP_CMOV_GE_Gv_Ev = 0x0f4d; +const UINT32 OP_CMOV_LE_Gv_Ev = 0x0f4e; +const UINT32 OP_CMOV_NG_Gv_Ev = 0x0f4e; +const UINT32 OP_CMOV_NLE_Gv_Ev = 0x0f4f; +const UINT32 OP_CMOV_G_Gv_Ev = 0x0f4f; + +const UINT32 OP_MOVMSKPS_Gd_Ups = 0x0f50; +const UINT32 OP_MOVMSKPD_Gd_Upd = 0x660f50; +const UINT32 OP_SQRTPS_Vps_Wps = 0x0f51; +const UINT32 OP_SQRTSS_Vss_Wss = 0xf30f51; +const UINT32 OP_SQRTPD_Vpd_Wpd = 0x660f51; +const UINT32 OP_SQRTSD_Vsd_Wsd = 0xf20f51; +const UINT32 OP_RSQRTPS_Vps_Wps = 0x0f52; +const UINT32 OP_RSQRTSS_Vss_Wss = 0xf30f52; +const UINT32 OP_RCPPS_Vps_Wps = 0x0f53; +const UINT32 OP_RCPSS_Vss_Wss = 0xf30f53; +const UINT32 OP_ANDPS_Vps_Wps = 0x0f54; +const UINT32 OP_ANDPD_Vpd_Wpd = 0x660f54; +const UINT32 OP_ANDNPS_Vps_Wps = 0x0f55; +const UINT32 OP_ANDNPD_Vpd_Wpd = 0x660f55; +const UINT32 OP_ORPS_Vps_Wps = 0x0f56; +const UINT32 OP_ORPD_Vpd_Wpd = 0x660f56; +const UINT32 OP_XORPS_Vps_Wps = 0x0f57; +const UINT32 OP_XORPD_Vpd_Wpd = 0x660f57; +const UINT32 OP_ADDPS_Vps_Wps = 0x0f58; +const UINT32 OP_ADDSS_Vss_Wss = 0xf30f58; +const UINT32 OP_ADDPD_Vpd_Wpd = 0x660f58; +const UINT32 OP_ADDSD_Vsd_Wsd = 0xf20f58; +const UINT32 OP_MULPS_Vps_Wps = 0x0f59; +const UINT32 OP_MULSS_Vss_Wss = 0xf30f59; +const UINT32 OP_MULPD_Vpd_Wpd = 0x660f59; +const UINT32 OP_MULSD_Vsd_Wsd = 0xf20f59; +const UINT32 OP_CVTPS2PD_Vpd_Wq = 0x0f5a; +const UINT32 OP_CVTSS2SD_Vsd_Wss = 0xf30f5a; +const UINT32 OP_CVTPD2PS_Vps_Wpd = 0x660f5a; +const UINT32 OP_CVTSD2SS_Vss_Wsd = 0xf20f5a; +const UINT32 OP_CVTDQ2PS_Vps_Wdq = 0x0f5b; +const UINT32 OP_CVTPS2DQ_Vdq_Wps = 0x660f5b; +const UINT32 OP_CVTTPS2DQ_Vdq_Wps = 0xf30f5b; +const UINT32 OP_SUBPS_Vps_Wps = 0x0f5c; +const UINT32 OP_SUBSS_Vss_Wss = 0xf30f5c; +const UINT32 OP_SUBPD_Vpd_Wpd = 0x660f5c; +const UINT32 OP_SUBSD_Vsd_Wsd = 0xf20f5c; +const UINT32 OP_MINPS_Vps_Wps = 0x0f5d; +const UINT32 OP_MINSS_Vss_Wss = 0xf30f5d; +const UINT32 OP_MINPD_Vpd_Wpd = 0x660f5d; +const UINT32 OP_MINSD_Vsd_Wsd = 0xf20f5d; +const UINT32 OP_DIVPS_Vps_Wps = 0x0f5e; +const UINT32 OP_DIVSS_Vss_Wss = 0xf30f5e; +const UINT32 OP_DIVPD_Vpd_Wpd = 0x660f5e; +const UINT32 OP_DIVSD_Vsd_Wsd = 0xf20f5e; +const UINT32 OP_MAXPS_Vps_Wps = 0x0f5f; +const UINT32 OP_MAXSS_Vss_Wss = 0xf30f5f; +const UINT32 OP_MAXPD_Vpd_Wpd = 0x660f5f; +const UINT32 OP_MAXSD_Vsd_Wsd = 0xf20f5f; + +const UINT32 OP_PUNPCKLBW_Pq_Qd = 0x0f60; +const UINT32 OP_PUNPCKLBW_Vdq_Wdq = 0x660f60; +const UINT32 OP_PUNPCKLWD_Pq_Qd = 0x0f61; +const UINT32 OP_PUNPCKLWD_Vdq_Wdq = 0x660f61; +const UINT32 OP_PUNPCKLDQ_Pq_Qd = 0x0f62; +const UINT32 OP_PUNPCKLDQ_Vdq_Wdq = 0x660f62; +const UINT32 OP_PACKSSWB_Pq_Qq = 0x0f63; +const UINT32 OP_PACKSSWB_Vdq_Wdq = 0x660f63; +const UINT32 OP_PCMPGTB_Pq_Qq = 0x0f64; +const UINT32 OP_PCMPGTB_Vdq_Wdq = 0x660f64; +const UINT32 OP_PCMPGTW_Pq_Qq = 0x0f65; +const UINT32 OP_PCMPGTW_Vdq_Wdq = 0x660f65; +const UINT32 OP_PCMPGTD_Pq_Qq = 0x0f66; +const UINT32 OP_PCMPGTD_Vdq_Wdq = 0x660f66; +const UINT32 OP_PACKUSWB_Pq_Qq = 0x0f67; +const UINT32 OP_PACKUSWB_Vdq_Wdq = 0x660f67; +const UINT32 OP_PUNPCKHBW_Pq_Qq = 0x0f68; +const UINT32 OP_PUNPCKHBW_Vdq_Qdq = 0x660f68; +const UINT32 OP_PUNPCKHWD_Pq_Qq = 0x0f69; +const UINT32 OP_PUNPCKHWD_Vdq_Qdq = 0x660f69; +const UINT32 OP_PUNPCKHDQ_Pq_Qq = 0x0f6a; +const UINT32 OP_PUNPCKHDQ_Vdq_Qdq = 0x660f6a; +const UINT32 OP_PACKSSDW_Pq_Qq = 0x0f6b; +const UINT32 OP_PACKSSDW_Vdq_Qdq = 0x660f6b; +const UINT32 OP_PUNPCKLQDQ_Vdq_Wdq = 0x660f6c; +const UINT32 OP_PUNPCKHQDQ_Vdq_Wdq = 0x660f6d; +const UINT32 OP_MOVD_Pd_Ed = 0x0f6e; +const UINT32 OP_MOVD_Vd_Ed = 0x660f6e; +const UINT32 OP_MOVQ_Pq_Qq = 0x0f6f; +const UINT32 OP_MOVDQA_Vdq_Wdq = 0x660f6f; +const UINT32 OP_MOVDQU_Vdq_Wdq = 0xf30f6f; + +const UINT32 OP_PSHUFW_Pq_Qq_Ib = 0x0f70; +const UINT32 OP_PSHUFD_Vdq_Wdq_Ib = 0x660f70; +const UINT32 OP_PSHUFHW_Vdq_Wdq_Ib = 0xf30f70; +const UINT32 OP_PSHUFLW_Vdq_Wdq_Ib = 0xf20f70; +const UINT32 OP_G12 = 0x0f71; +const UINT32 OP_G13 = 0x0f72; +const UINT32 OP_G14 = 0x0f73; +const UINT32 OP_PCMPEQB_Pq_Qq = 0x0f74; +const UINT32 OP_PCMPEQB_Vdq_Wdq = 0x660f74; +const UINT32 OP_PCMPEQW_Pq_Qq = 0x0f75; +const UINT32 OP_PCMPEQW_Vdq_Wdq = 0x660f75; +const UINT32 OP_PCMPEQD_Pq_Qq = 0x0f76; +const UINT32 OP_PCMPEQD_Vdq_Wdq = 0x660f76; +const UINT32 OP_EMMS = 0x0f77; +const UINT32 OP_VMREAD_Ed_Gd = 0x0f78; +const UINT32 OP_VMWRITE_Gd_Ed = 0x0f79; +const UINT32 OP_HADDPD_Vpd_Wpd = 0x660f7c; +const UINT32 OP_HADDPS_Vps_Wps = 0xf20f7c; +const UINT32 OP_HSUBPD_Vpd_Wpd = 0x660f7d; +const UINT32 OP_HSUBPS_Vps_Wps = 0xf20f7d; +const UINT32 OP_MOVD_Ed_Pd = 0x0f7e; +const UINT32 OP_MOVD_Ed_Vd = 0x660f7e; +const UINT32 OP_MOVQ_Vq_Wq = 0xf30f7e; +const UINT32 OP_MOVQ_Qq_Pq = 0x0f7f; +const UINT32 OP_MOVDQA_Wdq_Vdq = 0x660f7f; +const UINT32 OP_MOVDQU_Wdq_Vdq = 0xf30f7f; + +const UINT32 OP_JCC_O_Jv = 0x0f80; +const UINT32 OP_JCC_NO_Jv = 0x0f81; +const UINT32 OP_JCC_B_Jv = 0x0f82; +const UINT32 OP_JCC_C_Jv = 0x0f82; +const UINT32 OP_JCC_NAE_Jv = 0x0f82; +const UINT32 OP_JCC_AE_Jv = 0x0f83; +const UINT32 OP_JCC_NB_Jv = 0x0f83; +const UINT32 OP_JCC_NC_Jv = 0x0f83; +const UINT32 OP_JCC_E_Jv = 0x0f84; +const UINT32 OP_JCC_Z_Jv = 0x0f84; +const UINT32 OP_JCC_NE_Jv = 0x0f85; +const UINT32 OP_JCC_NZ_Jv = 0x0f85; +const UINT32 OP_JCC_BE_Jv = 0x0f86; +const UINT32 OP_JCC_NA_Jv = 0x0f86; +const UINT32 OP_JCC_A_Jv = 0x0f87; +const UINT32 OP_JCC_NBE_Jv = 0x0f87; +const UINT32 OP_JCC_S_Jv = 0x0f88; +const UINT32 OP_JCC_NS_Jv = 0x0f89; +const UINT32 OP_JCC_P_Jv = 0x0f8a; +const UINT32 OP_JCC_PE_Jv = 0x0f8a; +const UINT32 OP_JCC_NP_Jv = 0x0f8b; +const UINT32 OP_JCC_PO_Jv = 0x0f8b; +const UINT32 OP_JCC_L_Jv = 0x0f8c; +const UINT32 OP_JCC_NGE_Jv = 0x0f8c; +const UINT32 OP_JCC_NL_Jv = 0x0f8d; +const UINT32 OP_JCC_GE_Jv = 0x0f8d; +const UINT32 OP_JCC_LE_Jv = 0x0f8e; +const UINT32 OP_JCC_NG_Jv = 0x0f8e; +const UINT32 OP_JCC_NLE_Jv = 0x0f8f; +const UINT32 OP_JCC_G_Jv = 0x0f8f; + +const UINT32 OP_SETCC_O_Eb = (0x0f90 | OPFLAG_8BITRM); +const UINT32 OP_SETCC_NO_Eb = (0x0f91 | OPFLAG_8BITRM); +const UINT32 OP_SETCC_B_Eb = (0x0f92 | OPFLAG_8BITRM); +const UINT32 OP_SETCC_C_Eb = (0x0f92 | OPFLAG_8BITRM); +const UINT32 OP_SETCC_NAE_Eb = (0x0f92 | OPFLAG_8BITRM); +const UINT32 OP_SETCC_AE_Eb = (0x0f93 | OPFLAG_8BITRM); +const UINT32 OP_SETCC_NB_Eb = (0x0f93 | OPFLAG_8BITRM); +const UINT32 OP_SETCC_NC_Eb = (0x0f93 | OPFLAG_8BITRM); +const UINT32 OP_SETCC_E_Eb = (0x0f94 | OPFLAG_8BITRM); +const UINT32 OP_SETCC_Z_Eb = (0x0f94 | OPFLAG_8BITRM); +const UINT32 OP_SETCC_NE_Eb = (0x0f95 | OPFLAG_8BITRM); +const UINT32 OP_SETCC_NZ_Eb = (0x0f95 | OPFLAG_8BITRM); +const UINT32 OP_SETCC_BE_Eb = (0x0f96 | OPFLAG_8BITRM); +const UINT32 OP_SETCC_NA_Eb = (0x0f96 | OPFLAG_8BITRM); +const UINT32 OP_SETCC_A_Eb = (0x0f97 | OPFLAG_8BITRM); +const UINT32 OP_SETCC_NBE_Eb = (0x0f97 | OPFLAG_8BITRM); +const UINT32 OP_SETCC_S_Eb = (0x0f98 | OPFLAG_8BITRM); +const UINT32 OP_SETCC_NS_Eb = (0x0f99 | OPFLAG_8BITRM); +const UINT32 OP_SETCC_P_Eb = (0x0f9a | OPFLAG_8BITRM); +const UINT32 OP_SETCC_PE_Eb = (0x0f9a | OPFLAG_8BITRM); +const UINT32 OP_SETCC_NP_Eb = (0x0f9b | OPFLAG_8BITRM); +const UINT32 OP_SETCC_PO_Eb = (0x0f9b | OPFLAG_8BITRM); +const UINT32 OP_SETCC_L_Eb = (0x0f9c | OPFLAG_8BITRM); +const UINT32 OP_SETCC_NGE_Eb = (0x0f9c | OPFLAG_8BITRM); +const UINT32 OP_SETCC_NL_Eb = (0x0f9d | OPFLAG_8BITRM); +const UINT32 OP_SETCC_GE_Eb = (0x0f9d | OPFLAG_8BITRM); +const UINT32 OP_SETCC_LE_Eb = (0x0f9e | OPFLAG_8BITRM); +const UINT32 OP_SETCC_NG_Eb = (0x0f9e | OPFLAG_8BITRM); +const UINT32 OP_SETCC_NLE_Eb = (0x0f9f | OPFLAG_8BITRM); +const UINT32 OP_SETCC_G_Eb = (0x0f9f | OPFLAG_8BITRM); + +const UINT32 OP_PUSH_FS = 0x0fa0; +const UINT32 OP_POP_FS = 0x0fa1; +const UINT32 OP_CPUID = 0x0fa2; +const UINT32 OP_BT_Ev_Gv = 0x0fa3; +const UINT32 OP_SHLD_Ev_Gv_Ib = 0x0fa4; +const UINT32 OP_SHLD_Ev_Gv_CL = 0x0fa5; +const UINT32 OP_PUSH_GS = 0x0fa8; +const UINT32 OP_POP_GS = 0x0fa9; +const UINT32 OP_RSM = 0x0faa; +const UINT32 OP_BTS_Ev_Gv = 0x0fab; +const UINT32 OP_SHRD_Ev_Gv_Ib = 0x0fac; +const UINT32 OP_SHRD_Ev_Gv_CL = 0x0fad; +const UINT32 OP_G16 = 0x0fae; +const UINT32 OP_IMUL_Gv_Ev = 0x0faf; + +const UINT32 OP_CMPXCHG_Eb_Gb = (0x0fb0 | OPFLAG_8BITRM | OPFLAG_8BITREG); +const UINT32 OP_CMPXCHG_Ev_Gv = 0x0fb1; +const UINT32 OP_LSS_Mp = 0x0fb2; +const UINT32 OP_BTR_Ev_Gv = 0x0fb3; +const UINT32 OP_LFS_Mp = 0x0fb4; +const UINT32 OP_LGS_Mp = 0x0fb5; +const UINT32 OP_MOVZX_Gv_Eb = (0x0fb6 | OPFLAG_8BITRM); +const UINT32 OP_MOVZX_Gv_Ew = 0x0fb7; +const UINT32 OP_JMPE = 0x0fb8; +const UINT32 OP_POPCNT_Gv_Ev = 0xf30fb8; +const UINT32 OP_G10_INVALID = 0x0fb9; +const UINT32 OP_G8_Ev_Ib = 0x0fba; +const UINT32 OP_BTC_Ev_Gv = 0x0fbb; +const UINT32 OP_BSF_Gv_Ev = 0x0fbc; +const UINT32 OP_BSR_Gv_Ev = 0x0fbd; +const UINT32 OP_MOVSX_Gv_Eb = (0x0fbe | OPFLAG_8BITRM); +const UINT32 OP_MOVSX_Gv_Ew = 0x0fbf; + +const UINT32 OP_XADD_Eb_Gb = (0x0fc0 | OPFLAG_8BITRM | OPFLAG_8BITREG); +const UINT32 OP_XADD_Ev_Gv = 0x0fc1; +const UINT32 OP_CMPPS_Vps_Wps_Ib = 0x0fc2; +const UINT32 OP_CMPSS_Vss_Wss_Ib = 0xf30fc2; +const UINT32 OP_CMPPD_Vpd_Wpd_Ib = 0x660fc2; +const UINT32 OP_CMPSD_Vsd_Wsd_Ib = 0xf20fc2; +const UINT32 OP_MOVNTI_Md_Gd = 0x0fc3; +const UINT32 OP_PINSRW_Pw_Ew_Ib = 0x0fc4; +const UINT32 OP_PINSRW_Vw_Ew_Ib = 0x660fc4; +const UINT32 OP_PEXTRW_Gw_Pw_Ib = 0x0fc5; +const UINT32 OP_PEXTRW_Gw_Vw_Ib = 0x660fc5; +const UINT32 OP_SHUFPS_Vps_Wps_Ib = 0x0fc6; +const UINT32 OP_SHUFPD_Vpd_Wpd_Ib = 0x660fc6; +const UINT32 OP_G9 = 0x0fc7; +const UINT32 OP_BSWAP_EAX = 0x0fc8; +const UINT32 OP_BSWAP_ECX = 0x0fc9; +const UINT32 OP_BSWAP_EDX = 0x0fca; +const UINT32 OP_BSWAP_EBX = 0x0fcb; +const UINT32 OP_BSWAP_ESP = 0x0fcc; +const UINT32 OP_BSWAP_EBP = 0x0fcd; +const UINT32 OP_BSWAP_ESI = 0x0fce; +const UINT32 OP_BSWAP_EDI = 0x0fcf; + +const UINT32 OP_ADDSUBPD_Vpd_Wpd = 0x0fd0; +const UINT32 OP_ADDSUBPS_Vps_Wps = 0xf20fd0; +const UINT32 OP_PSRLW_Pq_Qq = 0x0fd1; +const UINT32 OP_PSRLW_Vdq_Wdq = 0x660fd1; +const UINT32 OP_PSRLD_Pq_Qq = 0x0fd2; +const UINT32 OP_PSRLD_Vdq_Wdq = 0x660fd2; +const UINT32 OP_PSRLQ_Pq_Qq = 0x0fd3; +const UINT32 OP_PSRLQ_Vdq_Wdq = 0x660fd3; +const UINT32 OP_PADDQ_Pq_Qq = 0x0fd4; +const UINT32 OP_PADDQ_Vdq_Wdq = 0x660fd4; +const UINT32 OP_PMULLW_Pq_Qq = 0x0fd5; +const UINT32 OP_PMULLW_Vdq_Wdq = 0x660fd5; +const UINT32 OP_MOVQ_Wq_Vq = 0x0fd6; +const UINT32 OP_MOVQ2DQ_Vdq_Qq = 0xf30fd6; +const UINT32 OP_MOVDQ2Q_Pq_Vq = 0xf20fd6; +const UINT32 OP_PMOVMSKB_Gd_Pq = 0x0fd7; +const UINT32 OP_PMOVMSKB_Gd_Vdq = 0x660fd7; +const UINT32 OP_PSUBUSB_Pq_Qq = 0x0fd8; +const UINT32 OP_PSUBUSB_Vdq_Wdq = 0x660fd8; +const UINT32 OP_PSUBUSW_Pq_Qq = 0x0fd9; +const UINT32 OP_PSUBUSW_Vdq_Wdq = 0x660fd9; +const UINT32 OP_PMINUB_Pq_Qq = 0x0fda; +const UINT32 OP_PMINUB_Vdq_Wdq = 0x660fda; +const UINT32 OP_PAND_Pq_Qq = 0x0fdb; +const UINT32 OP_PAND_Vdq_Wdq = 0x660fdb; +const UINT32 OP_PADDUSB_Pq_Qq = 0x0fdc; +const UINT32 OP_PADDUSB_Vdq_Wdq = 0x660fdc; +const UINT32 OP_PADDUSW_Pq_Qq = 0x0fdd; +const UINT32 OP_PADDUSW_Vdq_Wdq = 0x660fdd; +const UINT32 OP_PMAXUB_Pq_Qq = 0x0fde; +const UINT32 OP_PMAXUB_Vdq_Wdq = 0x660fde; +const UINT32 OP_PANDN_Pq_Qq = 0x0fdf; +const UINT32 OP_PANDN_Vdq_Wdq = 0x660fdf; + +const UINT32 OP_PAVGB_Pq_Qq = 0x0fe0; +const UINT32 OP_PAVGB_Vdq_Wdq = 0x660fe0; +const UINT32 OP_PSRAW_Pq_Qq = 0x0fe1; +const UINT32 OP_PSRAW_Vdq_Wdq = 0x660fe1; +const UINT32 OP_PSRAD_Pq_Qq = 0x0fe2; +const UINT32 OP_PSRAD_Vdq_Wdq = 0x660fe2; +const UINT32 OP_PAVGW_Pq_Qq = 0x0fe3; +const UINT32 OP_PAVGW_Vdq_Wdq = 0x660fe3; +const UINT32 OP_PMULHUW_Pq_Qq = 0x0fe4; +const UINT32 OP_PMULHUW_Vdq_Wdq = 0x660fe4; +const UINT32 OP_PMULHW_Pq_Qq = 0x0fe5; +const UINT32 OP_PMULHW_Vdq_Wdq = 0x660fe5; +const UINT32 OP_CVTPD2DQ_Vdq_Wpd = 0xf20fe6; +const UINT32 OP_CVTTPD2DQ_Vdq_Wpd = 0x660fe6; +const UINT32 OP_CVTDQ2PD_Vpd_Wq = 0xf30fe6; +const UINT32 OP_MOVNTQ_Mq_Vq = 0x0fe7; +const UINT32 OP_MOVNTDQ_Mdq_Vdq = 0x660fe7; +const UINT32 OP_PSUBSB_Pq_Qq = 0x0fe8; +const UINT32 OP_PSUBSB_Vdq_Wdq = 0x660fe8; +const UINT32 OP_PSUBSW_Pq_Qq = 0x0fe9; +const UINT32 OP_PSUBSW_Vdq_Wdq = 0x660fe9; +const UINT32 OP_PMINSW_Pq_Qq = 0x0fea; +const UINT32 OP_PMINSW_Vdq_Wdq = 0x660fea; +const UINT32 OP_POR_Pq_Qq = 0x0feb; +const UINT32 OP_POR_Vdq_Wdq = 0x660feb; +const UINT32 OP_PADDSB_Pq_Qq = 0x0fec; +const UINT32 OP_PADDSB_Vdq_Wdq = 0x660fec; +const UINT32 OP_PADDSW_Pq_Qq = 0x0fed; +const UINT32 OP_PADDSW_Vdq_Wdq = 0x660fed; +const UINT32 OP_PMAXSW_Pq_Qq = 0x0fee; +const UINT32 OP_PMAXSW_Vdq_Wdq = 0x660fee; +const UINT32 OP_PXOR_Pq_Qq = 0x0fef; +const UINT32 OP_PXOR_Vdq_Wdq = 0x660fef; + +const UINT32 OP_LDDQU_Vdq_Mdq = 0xf20ff0; +const UINT32 OP_PSLLW_Pq_Qq = 0x0ff1; +const UINT32 OP_PSLLW_Vdq_Wdq = 0x660ff1; +const UINT32 OP_PSLLD_Pq_Qq = 0x0ff2; +const UINT32 OP_PSLLD_Vdq_Wdq = 0x660ff2; +const UINT32 OP_PSLLQ_Pq_Qq = 0x0ff3; +const UINT32 OP_PSLLQ_Vdq_Wdq = 0x660ff3; +const UINT32 OP_PMULUDQ_Pq_Qq = 0x0ff4; +const UINT32 OP_PMULUDQ_Vdq_Wdq = 0x660ff4; +const UINT32 OP_PMADDWD_Pq_Qq = 0x0ff5; +const UINT32 OP_PMADDWD_Vdq_Wdq = 0x660ff5; +const UINT32 OP_PSADBW_Pq_Qq = 0x0ff6; +const UINT32 OP_PSADBW_Vdq_Wdq = 0x660ff6; +const UINT32 OP_MASKMOVQ_Pq_Qq = 0x0ff7; +const UINT32 OP_MASKMOVDQU_Vdq_Wdq = 0x660ff7; +const UINT32 OP_PSUBB_Pq_Qq = 0x0ff8; +const UINT32 OP_PSUBB_Vdq_Wdq = 0x660ff8; +const UINT32 OP_PSUBW_Pq_Qq = 0x0ff9; +const UINT32 OP_PSUBW_Vdq_Wdq = 0x660ff9; +const UINT32 OP_PSUBD_Pq_Qq = 0x0ffa; +const UINT32 OP_PSUBD_Vdq_Wdq = 0x660ffa; +const UINT32 OP_PSUBQ_Pq_Qq = 0x0ffb; +const UINT32 OP_PSUBQ_Vdq_Wdq = 0x660ffb; +const UINT32 OP_PADDB_Pq_Qq = 0x0ffc; +const UINT32 OP_PADDB_Vdq_Wdq = 0x660ffc; +const UINT32 OP_PADDW_Pq_Qq = 0x0ffd; +const UINT32 OP_PADDW_Vdq_Wdq = 0x660ffd; +const UINT32 OP_PADDD_Pq_Qq = 0x0ffe; +const UINT32 OP_PADDD_Vdq_Wdq = 0x660ffe; + + +// triple byte opcodes (0f 38) +const UINT32 OP_PSHUFB_Pq_Qq = 0x0f3800; +const UINT32 OP_PSHUFB_Vdq_Wdq = 0x660f3800; +const UINT32 OP_PHADDW_Pq_Qq = 0x0f3801; +const UINT32 OP_PHADDW_Vdq_Wdq = 0x660f3801; +const UINT32 OP_PHADDD_Pq_Qq = 0x0f3802; +const UINT32 OP_PHADDD_Vdq_Wdq = 0x660f3802; +const UINT32 OP_PHADDSW_Pq_Qq = 0x0f3803; +const UINT32 OP_PHADDSW_Vdq_Wdq = 0x660f3803; +const UINT32 OP_PMADDUBSW_Pq_Qq = 0x0f3804; +const UINT32 OP_PMADDUBSW_Vdq_Wdq = 0x660f3804; +const UINT32 OP_PHSUBW_Pq_Qq = 0x0f3805; +const UINT32 OP_PHSUBW_Vdq_Wdq = 0x660f3805; +const UINT32 OP_PHSUBD_Pq_Qq = 0x0f3806; +const UINT32 OP_PHSUBD_Vdq_Wdq = 0x660f3806; +const UINT32 OP_PHSUBSW_Pq_Qq = 0x0f3807; +const UINT32 OP_PHSUBSW_Vdq_Wdq = 0x660f3807; +const UINT32 OP_PSIGNB_Pq_Qq = 0x0f3808; +const UINT32 OP_PSIGNB_Vdq_Wdq = 0x660f3808; +const UINT32 OP_PSIGNW_Pq_Qq = 0x0f3809; +const UINT32 OP_PSIGNW_Vdq_Wdq = 0x660f3809; +const UINT32 OP_PSIGND_Pq_Qq = 0x0f380a; +const UINT32 OP_PSIGND_Vdq_Wdq = 0x660f380a; +const UINT32 OP_PMULHRSW_Pq_Qq = 0x0f380b; +const UINT32 OP_PMULHRSW_Vdq_Wdq = 0x660f380b; + +const UINT32 OP_PBLENDVB_Vdq_Wdq = 0x660f3810; +const UINT32 OP_PBLENDVPS_Vdq_Wdq = 0x660f3814; +const UINT32 OP_PBLENDVPD_Vdq_Wdq = 0x660f3815; +const UINT32 OP_PTEST_Vdq_Wdq = 0x660f3817; +const UINT32 OP_PABSB_Pq_Qq = 0x0f381c; +const UINT32 OP_PABSB_Vdq_Wdq = 0x660f381c; +const UINT32 OP_PABSW_Pq_Qq = 0x0f381d; +const UINT32 OP_PABSW_Vdq_Wdq = 0x660f381d; +const UINT32 OP_PABSD_Pq_Qq = 0x0f381e; +const UINT32 OP_PABSD_Vdq_Wdq = 0x660f381e; + +const UINT32 OP_PMOVSXBW_Vdq_Udq = 0x660f3820; +const UINT32 OP_PMOVSXBD_Vdq_Udq = 0x660f3821; +const UINT32 OP_PMOVSXBQ_Vdq_Udq = 0x660f3822; +const UINT32 OP_PMOVSXWD_Vdq_Udq = 0x660f3823; +const UINT32 OP_PMOVSXWQ_Vdq_Udq = 0x660f3824; +const UINT32 OP_PMOVSXDQ_Vdq_Udq = 0x660f3825; +const UINT32 OP_PMULDQ_Vdq_Udq = 0x660f3828; +const UINT32 OP_PCMPEQQ_Vdq_Udq = 0x660f3829; +const UINT32 OP_MOVNTDQA_Vdq_Udq = 0x660f382a; +const UINT32 OP_PACKUSDW_Vdq_Udq = 0x660f382b; + +const UINT32 OP_PMOVZXBW_Vdq_Udq = 0x660f3830; +const UINT32 OP_PMOVZXBD_Vdq_Udq = 0x660f3831; +const UINT32 OP_PMOVZXBQ_Vdq_Udq = 0x660f3832; +const UINT32 OP_PMOVZXWD_Vdq_Udq = 0x660f3833; +const UINT32 OP_PMOVZXWQ_Vdq_Udq = 0x660f3834; +const UINT32 OP_PMOVZXDQ_Vdq_Udq = 0x660f3835; +const UINT32 OP_PMINSB_Vdq_Udq = 0x660f3838; +const UINT32 OP_PMINSD_Vdq_Udq = 0x660f3839; +const UINT32 OP_PMINUW_Vdq_Udq = 0x660f383a; +const UINT32 OP_PMINUD_Vdq_Udq = 0x660f383b; +const UINT32 OP_PMAXSB_Vdq_Udq = 0x660f383c; +const UINT32 OP_PMAXSD_Vdq_Udq = 0x660f383d; +const UINT32 OP_PMAXUW_Vdq_Udq = 0x660f383e; +const UINT32 OP_PMAXUD_Vdq_Udq = 0x660f383f; + +const UINT32 OP_MULLD_Vdq_Wdq = 0x660f3840; +const UINT32 OP_PHMINPOSUW_Vdq_Wdq = 0x660f3841; + +const UINT32 OP_NVEPT_Gd_Mdq = 0x660f3880; +const UINT32 OP_NVVPID_Gd_Mdq = 0x660f3881; + +const UINT32 OP_MOVBE_Gv_Mv = 0x0f38f0; +const UINT32 OP_CRC32_Gd_Eb = 0xf20f38f0; +const UINT32 OP_MOVBE_Mv_Gv = 0x0f38f1; +const UINT32 OP_CRC32_Gd_Ev = 0xf20f38f1; + + +// triple byte opcodes (0f 3a) +const UINT32 OP_ROUNDPS_Vdq_Wdq_Ib = 0x660f3a08; +const UINT32 OP_ROUNDPD_Vdq_Wdq_Ib = 0x660f3a09; +const UINT32 OP_ROUNDSS_Vss_Wss_Ib = 0x660f3a0a; +const UINT32 OP_ROUNDSD_Vsd_Wsd_Ib = 0x660f3a0b; +const UINT32 OP_BLENDPS_Vdq_Wdq_Ib = 0x660f3a0c; +const UINT32 OP_BLENDPD_Vdq_Wdq_Ib = 0x660f3a0d; +const UINT32 OP_PBLENDW_Vdq_Wdq_Ib = 0x660f3a0e; +const UINT32 OP_PALIGNR_Pq_Qq_Ib = 0x0f3a0f; +const UINT32 OP_PALIGNR_Vdq_Wdq_Ib = 0x660f3a0f; + +const UINT32 OP_EXTRB_Rd_Vdq_Ib = 0x660f3a14; +const UINT32 OP_EXTRW_Rd_Vdq_Ib = 0x660f3a15; +const UINT32 OP_EXTRD_Rd_Vdq_Ib = 0x660f3a16; +const UINT32 OP_EXTRACTPS_Ed_Vdq_Ib = 0x660f3a17; + +const UINT32 OP_PINSRB_Vdq_Rd_Ib = 0x660f3a20; +const UINT32 OP_INSERTPS_Vdq_Udq_Ib = 0x660f3a21; +const UINT32 OP_PINSRD_Vdq_Ed_Ib = 0x660f3a22; + +const UINT32 OP_DPPS_Vdq_Wdq_Ib = 0x660f3a40; +const UINT32 OP_DPPD_Vdq_Wdq_Ib = 0x660f3a41; +const UINT32 OP_MPSADBW_Vdq_Wdq_Ib = 0x660f3a42; + +const UINT32 OP_PCMPESTRM_Vdq_Wdq_Ib = 0x660f3a60; +const UINT32 OP_PCMPESTRI_Vdq_Wdq_Ib = 0x660f3a61; +const UINT32 OP_PCMPISTRM_Vdq_Wdq_Ib = 0x660f3a62; +const UINT32 OP_PCMPISTRI_Vdq_Wdq_Ib = 0x660f3a63; + + +// floating point opcodes +const UINT32 OP_FADD_ST0_STn = 0xd8c0; +const UINT32 OP_FMUL_ST0_STn = 0xd8c8; +const UINT32 OP_FCOM_ST0_STn = 0xd8d0; +const UINT32 OP_FCOMP_ST0_STn = 0xd8d8; +const UINT32 OP_FSUB_ST0_STn = 0xd8e0; +const UINT32 OP_FSUBR_ST0_STn = 0xd8e8; +const UINT32 OP_FDIV_ST0_STn = 0xd8f0; +const UINT32 OP_FDIVR_ST0_STn = 0xd8f8; +const UINT32 OP_FLD_ST0_STn = 0xd9c0; +const UINT32 OP_FXCH_ST0_STn = 0xd9c8; +const UINT32 OP_FNOP = 0xd9d0; +const UINT32 OP_FCHS = 0xd9e0; +const UINT32 OP_FABS = 0xd9e1; +const UINT32 OP_FTST = 0xd9e4; +const UINT32 OP_FXAM = 0xd9e5; +const UINT32 OP_FLD1 = 0xd9e8; +const UINT32 OP_FLDL2T = 0xd9e9; +const UINT32 OP_FLDL2E = 0xd9ea; +const UINT32 OP_FLDPI = 0xd9eb; +const UINT32 OP_FLDLG2 = 0xd9ec; +const UINT32 OP_FLDLN2 = 0xd9ed; +const UINT32 OP_FLDZ = 0xd9ee; +const UINT32 OP_F2XM1 = 0xd9f0; +const UINT32 OP_FYL2X = 0xd9f1; +const UINT32 OP_FPTAN = 0xd9f2; +const UINT32 OP_FPATAN = 0xd9f3; +const UINT32 OP_FXTRACT = 0xd9f4; +const UINT32 OP_FPREM1 = 0xd9f5; +const UINT32 OP_FDECSTP = 0xd9f6; +const UINT32 OP_FINCSTP = 0xd9f7; +const UINT32 OP_FPREM = 0xd9f8; +const UINT32 OP_FYL2XP1 = 0xd9f9; +const UINT32 OP_FSQRT = 0xd9fa; +const UINT32 OP_FSINCOS = 0xd9fb; +const UINT32 OP_FRNDINT = 0xd9fc; +const UINT32 OP_FSCALE = 0xd9fd; +const UINT32 OP_FSIN = 0xd9fe; +const UINT32 OP_FCOS = 0xd9ff; +const UINT32 OP_FCMOVB_ST0_STn = 0xdac0; +const UINT32 OP_FCMOVE_ST0_STn = 0xdac8; +const UINT32 OP_FCMOVBE_ST0_STn = 0xdad0; +const UINT32 OP_FCMOVU_ST0_STn = 0xdad8; +const UINT32 OP_FUCOMPP = 0xdae9; +const UINT32 OP_FCMOVNB_ST0_STn = 0xdbc0; +const UINT32 OP_FCMOVNE_ST0_STn = 0xdbc8; +const UINT32 OP_FCMOVNBE_ST0_STn = 0xdbd0; +const UINT32 OP_FCMOVNU_ST0_STn = 0xdbd8; +const UINT32 OP_FCLEX = 0xdbe2; +const UINT32 OP_FINIT = 0xdbe3; +const UINT32 OP_FUCOMI_ST0_STn = 0xdbe8; +const UINT32 OP_FCOMI_ST0_STn = 0xdbf0; +const UINT32 OP_FADD_STn_ST0 = 0xdcc0; +const UINT32 OP_FMUL_STn_ST0 = 0xdcc8; +const UINT32 OP_FSUBR_STn_ST0 = 0xdce0; +const UINT32 OP_FSUB_STn_ST0 = 0xdce8; +const UINT32 OP_FDIVR_STn_ST0 = 0xdcf0; +const UINT32 OP_FDIV_STn_ST0 = 0xdcf8; +const UINT32 OP_FFREE_STn = 0xddc0; +const UINT32 OP_FST_STn = 0xddd0; +const UINT32 OP_FSTP_STn = 0xddd8; +const UINT32 OP_FUCOM_STn_ST0 = 0xdde0; +const UINT32 OP_FUCOMP_STn = 0xdde8; +const UINT32 OP_FADDP_STn_ST0 = 0xdec0; +const UINT32 OP_FMULP_STn_ST0 = 0xdec8; +const UINT32 OP_FCOMPP = 0xded9; +const UINT32 OP_FSUBRP_STn_ST0 = 0xdee0; +const UINT32 OP_FSUBP_STn_ST0 = 0xdee8; +const UINT32 OP_FDIVRP_STn_ST0 = 0xdef0; +const UINT32 OP_FDIVP_STn_ST0 = 0xdef8; +const UINT32 OP_FSTSW_AX = 0xdfe0; +const UINT32 OP_FCOMIP_ST0_STn = 0xdff0; + + + +//************************************************************************** +// MEMORY REFERENCES +//************************************************************************** + +inline x86_memref MBD(UINT8 base, INT32 disp) { return x86_memref(base, REG_NONE, 1, disp); } +inline x86_memref MBISD(UINT8 base, UINT8 ind, UINT8 scale, INT32 disp) { return x86_memref(base, ind, scale, disp); } + +#if (X86EMIT_SIZE == 32) +inline x86_memref MABS(const void *mem) { return x86_memref(REG_NONE, REG_NONE, 1, reinterpret_cast(const_cast(mem))); } +inline x86_memref MABSI(const void *mem, UINT8 index) { return x86_memref(index, REG_NONE, 1, reinterpret_cast(const_cast(mem))); } +inline x86_memref MABSI(const void *mem, UINT8 index, UINT8 scale) { return x86_memref(REG_NONE, index, scale, reinterpret_cast(const_cast(mem))); } +#endif + + + +//************************************************************************** +// CORE FUNCTIONS +//************************************************************************** + +//------------------------------------------------- +// make_modrm - assemble a modrm byte from the +// three components +//------------------------------------------------- + +inline UINT8 make_modrm(UINT8 mode, UINT8 reg, UINT8 rm) +{ + assert(mode < 4); + assert(reg < REG_MAX); + assert(rm < REG_MAX); + return (mode << 6) | ((reg & 7) << 3) | (rm & 7); +} + + +//------------------------------------------------- +// make_sib - assemble an sib byte from the +// three components +//------------------------------------------------- + +inline UINT8 make_sib(UINT8 scale, UINT8 index, UINT8 base) +{ + static const UINT8 scale_lookup[9] = { 0<<6, 0<<6, 1<<6, 0<<6, 2<<6, 0<<6, 0<<6, 0<<6, 3<<6 }; + assert(scale == 1 || scale == 2 || scale == 4 || scale == 8); + assert(index < REG_MAX); + assert(base < REG_MAX); + return scale_lookup[scale] | ((index & 7) << 3) | (base & 7); +} + + +//------------------------------------------------- +// emit_byte - emit a byte +//------------------------------------------------- + +inline void emit_byte(x86code *&emitptr, UINT8 byte) +{ + *((UINT8 *)emitptr) = byte; + emitptr += 1; +} + + +//------------------------------------------------- +// emit_word - emit a word +//------------------------------------------------- + +inline void emit_word(x86code *&emitptr, UINT16 word) +{ + *((UINT16 *)emitptr) = word; + emitptr += 2; +} + + +//------------------------------------------------- +// emit_dword - emit a dword +//------------------------------------------------- + +inline void emit_dword(x86code *&emitptr, UINT32 dword) +{ + *((UINT32 *)emitptr) = dword; + emitptr += 4; +} + + +//------------------------------------------------- +// emit_qword - emit a dword +//------------------------------------------------- + +inline void emit_qword(x86code *&emitptr, UINT64 qword) +{ + *((UINT64 *)emitptr) = qword; + emitptr += 8; +} + + + +//************************************************************************** +// GENERIC OPCODE EMITTERS +//************************************************************************** + +//------------------------------------------------- +// emit_op - emit a 1, 2, or 3-byte opcode, +// along with any necessary REX prefixes for x64 +//------------------------------------------------- + +inline void emit_op(x86code *&emitptr, UINT32 op, UINT8 opsize, UINT8 reg, UINT8 sib, UINT8 rm) +{ + if (opsize == OP_16BIT) + emit_byte(emitptr, PREFIX_OPSIZE); + +#if (X86EMIT_SIZE == 64) +{ + UINT8 rex; + + assert(opsize == OP_16BIT || opsize == OP_32BIT || opsize == OP_64BIT); + + rex = (opsize & 8) | ((reg & 8) >> 1) | ((sib & 8) >> 2) | ((rm & 8) >> 3); + if (rex != 0 || ((op & OPFLAG_8BITREG) && reg >= 4) || ((op & OPFLAG_8BITRM) && rm >= 4)) + emit_byte(emitptr, OP_REX + rex); +} +#else + assert(opsize != OP_64BIT); +#endif + + if ((op & 0xff0000) != 0) + emit_byte(emitptr, op >> 16); + if ((op & 0xff00) != 0) + emit_byte(emitptr, op >> 8); + emit_byte(emitptr, op); +} + + +//------------------------------------------------- +// emit_op_simple - emit a simple opcode +//------------------------------------------------- + +inline void emit_op_simple(x86code *&emitptr, UINT32 op, UINT8 opsize) +{ + emit_op(emitptr, op, opsize, 0, 0, 0); +} + + +//------------------------------------------------- +// emit_op_reg - emit a simple opcode that has +// a register parameter +//------------------------------------------------- + +inline void emit_op_reg(x86code *&emitptr, UINT32 op, UINT8 opsize, UINT8 reg) +{ + emit_op(emitptr, op, opsize, 0, 0, reg); +} + + +//------------------------------------------------- +// emit_op_modrm_reg - emit an opcode with a +// register modrm byte +//------------------------------------------------- + +inline void emit_op_modrm_reg(x86code *&emitptr, UINT32 op, UINT8 opsize, UINT8 reg, UINT8 rm) +{ + assert(reg < REG_MAX); + assert(rm < REG_MAX); + + emit_op(emitptr, op, opsize, reg, 0, rm); + emit_byte(emitptr, make_modrm(3, reg, rm)); +} + + +//------------------------------------------------- +// emit_op_modrm_mem - emit an opcode with a +// memory modrm byte +//------------------------------------------------- + +inline void emit_op_modrm_mem(x86code *&emitptr, UINT32 op, UINT8 opsize, UINT8 reg, x86_memref memref) +{ + assert(reg < REG_MAX); + assert(memref.m_base < REG_MAX || memref.m_base == REG_NONE); + assert(memref.m_index < REG_MAX || memref.m_index == REG_NONE); + + // turn off the OPFLAG_8BITRM flag since it only applies to register operands + op &= ~OPFLAG_8BITRM; + + // displacement only case + if (memref.m_base == REG_NONE && memref.m_index == REG_NONE) + { +#if (X86EMIT_SIZE == 32) + emit_op(emitptr, op, opsize, reg, 0, 5); + emit_byte(emitptr, make_modrm(0, reg, 5)); + emit_dword(emitptr, memref.m_disp); +#else + fatalerror("Invalid absolute mode in 64-bits!\n"); +#endif + } + + // base only case + else if (memref.m_index == REG_NONE && (memref.m_base & 7) != REG_ESP) + { + emit_op(emitptr, op, opsize, reg, 0, memref.m_base); + + // mode 0 for no offset + if (memref.m_disp == 0 && (memref.m_base & 7) != REG_EBP) + emit_byte(emitptr, make_modrm(0, reg, memref.m_base)); + + // mode 1 for 1-byte offset + else if ((INT8)memref.m_disp == memref.m_disp) + { + emit_byte(emitptr, make_modrm(1, reg, memref.m_base)); + emit_byte(emitptr, (INT8)memref.m_disp); + } + + // mode 2 for 4-byte offset + else + { + emit_byte(emitptr, make_modrm(2, reg, memref.m_base)); + emit_dword(emitptr, memref.m_disp); + } + } + + // full BISD case + else + { + assert(memref.m_index != REG_ESP); + emit_op(emitptr, op, opsize, reg, memref.m_index, memref.m_base); + + // a "none" index == REG_ESP + if (memref.m_index == REG_NONE) + memref.m_index = REG_ESP; + + // no base is a special case + if (memref.m_base == REG_NONE) + { + emit_byte(emitptr, make_modrm(0, reg, 4)); + emit_byte(emitptr, make_sib(memref.m_scale, memref.m_index, REG_EBP)); + emit_dword(emitptr, memref.m_disp); + } + + // mode 0 for no offset + else if (memref.m_disp == 0 && (memref.m_base & 7) != REG_EBP) + { + emit_byte(emitptr, make_modrm(0, reg, 4)); + emit_byte(emitptr, make_sib(memref.m_scale, memref.m_index, memref.m_base)); + } + + // mode 1 for 1-byte offset + else if ((INT8)memref.m_disp == memref.m_disp) + { + emit_byte(emitptr, make_modrm(1, reg, 4)); + emit_byte(emitptr, make_sib(memref.m_scale, memref.m_index, memref.m_base)); + emit_byte(emitptr, (INT8)memref.m_disp); + } + + // mode 2 for 4-byte offset + else + { + emit_byte(emitptr, make_modrm(2, reg, 4)); + emit_byte(emitptr, make_sib(memref.m_scale, memref.m_index, memref.m_base)); + emit_dword(emitptr, memref.m_disp); + } + } +} + + + +//************************************************************************** +// GENERIC OPCODE + IMMEDIATE EMITTERS +//************************************************************************** + +//------------------------------------------------- +// emit_op_modrm_reg_imm8 - emit an opcode with a +// register modrm byte and an 8-bit immediate +//------------------------------------------------- + +inline void emit_op_modrm_reg_imm8(x86code *&emitptr, UINT32 op, UINT8 opsize, UINT8 reg, UINT8 rm, UINT8 imm) +{ + emit_op_modrm_reg(emitptr, op, opsize, reg, rm); + emit_byte(emitptr, imm); +} + + +//------------------------------------------------- +// emit_op_modrm_mem_imm8 - emit an opcode with a +// memory modrm byte and an 8-bit immediate +//------------------------------------------------- + +inline void emit_op_modrm_mem_imm8(x86code *&emitptr, UINT32 op, UINT8 opsize, UINT8 reg, x86_memref memref, UINT8 imm) +{ + emit_op_modrm_mem(emitptr, op, opsize, reg, memref); + emit_byte(emitptr, imm); +} + + +//------------------------------------------------- +// emit_op_modrm_reg_imm16 - emit an opcode with a +// register modrm byte and a 16-bit immediate +//------------------------------------------------- + +inline void emit_op_modrm_reg_imm16(x86code *&emitptr, UINT32 op, UINT8 opsize, UINT8 reg, UINT8 rm, UINT16 imm) +{ + emit_op_modrm_reg(emitptr, op, opsize, reg, rm); + emit_word(emitptr, imm); +} + + +//------------------------------------------------- +// emit_op_modrm_mem_imm16 - emit an opcode with a +// memory modrm byte and a 16-bit immediate +//------------------------------------------------- + +inline void emit_op_modrm_mem_imm16(x86code *&emitptr, UINT32 op, UINT8 opsize, UINT8 reg, x86_memref memref, UINT16 imm) +{ + emit_op_modrm_mem(emitptr, op, opsize, reg, memref); + emit_word(emitptr, imm); +} + + +//------------------------------------------------- +// emit_op_modrm_reg_imm816 - emit an opcode with +// a register modrm byte and an 8-bit or 16-bit +// immediate +//------------------------------------------------- + +inline void emit_op_modrm_reg_imm816(x86code *&emitptr, UINT32 op8, UINT32 op16, UINT8 opsize, UINT8 reg, UINT8 rm, UINT16 imm) +{ + if ((INT8)imm == (INT16)imm) + { + emit_op_modrm_reg(emitptr, op8, opsize, reg, rm); + emit_byte(emitptr, imm); + } + else + { + emit_op_modrm_reg(emitptr, op16, opsize, reg, rm); + emit_word(emitptr, imm); + } +} + + +//------------------------------------------------- +// emit_op_modrm_mem_imm816 - emit an opcode with +// a memory modrm byte and an 8-bit or 16-bit +// immediate +//------------------------------------------------- + +inline void emit_op_modrm_mem_imm816(x86code *&emitptr, UINT32 op8, UINT32 op16, UINT8 opsize, UINT8 reg, x86_memref memref, UINT16 imm) +{ + if ((INT8)imm == (INT16)imm) + { + emit_op_modrm_mem(emitptr, op8, opsize, reg, memref); + emit_byte(emitptr, imm); + } + else + { + emit_op_modrm_mem(emitptr, op16, opsize, reg, memref); + emit_word(emitptr, imm); + } +} + + +//------------------------------------------------- +// emit_op_modrm_reg_imm32 - emit an opcode with a +// register modrm byte and a 32-bit immediate +//------------------------------------------------- + +inline void emit_op_modrm_reg_imm32(x86code *&emitptr, UINT32 op, UINT8 opsize, UINT8 reg, UINT8 rm, UINT32 imm) +{ + emit_op_modrm_reg(emitptr, op, opsize, reg, rm); + emit_dword(emitptr, imm); +} + + +//------------------------------------------------- +// emit_op_modrm_mem_imm32 - emit an opcode with a +// memory modrm byte and a 32-bit immediate +//------------------------------------------------- + +inline void emit_op_modrm_mem_imm32(x86code *&emitptr, UINT32 op, UINT8 opsize, UINT8 reg, x86_memref memref, UINT32 imm) +{ + emit_op_modrm_mem(emitptr, op, opsize, reg, memref); + emit_dword(emitptr, imm); +} + + +//------------------------------------------------- +// emit_op_modrm_reg_imm832 - emit an opcode with +// a register modrm byte and an 8-bit or 32-bit +// immediate +//------------------------------------------------- + +inline void emit_op_modrm_reg_imm832(x86code *&emitptr, UINT32 op8, UINT32 op32, UINT8 opsize, UINT8 reg, UINT8 rm, UINT32 imm) +{ + if ((INT8)imm == (INT32)imm) + { + emit_op_modrm_reg(emitptr, op8, opsize, reg, rm); + emit_byte(emitptr, imm); + } + else + { + emit_op_modrm_reg(emitptr, op32, opsize, reg, rm); + emit_dword(emitptr, imm); + } +} + + +//------------------------------------------------- +// emit_op_modrm_mem_imm832 - emit an opcode with +// a memory modrm byte and an 8-bit or 32-bit +// immediate +//------------------------------------------------- + +inline void emit_op_modrm_mem_imm832(x86code *&emitptr, UINT32 op8, UINT32 op32, UINT8 opsize, UINT8 reg, x86_memref memref, UINT32 imm) +{ + if ((INT8)imm == (INT32)imm) + { + emit_op_modrm_mem(emitptr, op8, opsize, reg, memref); + emit_byte(emitptr, imm); + } + else + { + emit_op_modrm_mem(emitptr, op32, opsize, reg, memref); + emit_dword(emitptr, imm); + } +} + + + +//************************************************************************** +// SIMPLE OPCODE EMITTERS +//************************************************************************** + +inline void emit_nop(x86code *&emitptr) { emit_op_simple(emitptr, OP_NOP, OP_32BIT); } +inline void emit_int_3(x86code *&emitptr) { emit_op_simple(emitptr, OP_INT_3, OP_32BIT); } +inline void emit_ret(x86code *&emitptr) { emit_op_simple(emitptr, OP_RETN, OP_32BIT); } +inline void emit_cdq(x86code *&emitptr) { emit_op_simple(emitptr, OP_CDQ, OP_32BIT); } +inline void emit_clc(x86code *&emitptr) { emit_op_simple(emitptr, OP_CLC, OP_32BIT); } +inline void emit_stc(x86code *&emitptr) { emit_op_simple(emitptr, OP_STC, OP_32BIT); } +inline void emit_cmc(x86code *&emitptr) { emit_op_simple(emitptr, OP_CMC, OP_32BIT); } +inline void emit_pushf(x86code *&emitptr) { emit_op_simple(emitptr, OP_PUSHF_Fv, OP_32BIT); } +inline void emit_popf(x86code *&emitptr) { emit_op_simple(emitptr, OP_POPF_Fv, OP_32BIT); } +inline void emit_cpuid(x86code *&emitptr) { emit_op_simple(emitptr, OP_CPUID, OP_32BIT); } + +#if (X86EMIT_SIZE == 32) +inline void emit_pushad(x86code *&emitptr) { emit_op_simple(emitptr, OP_PUSHA, OP_32BIT); } +inline void emit_popad(x86code *&emitptr) { emit_op_simple(emitptr, OP_POPA, OP_32BIT); } +inline void emit_lahf(x86code *&emitptr) { emit_op_simple(emitptr, OP_LAHF, OP_32BIT); } +inline void emit_sahf(x86code *&emitptr) { emit_op_simple(emitptr, OP_SAHF, OP_32BIT); } +#endif + +#if (X86EMIT_SIZE == 64) +inline void emit_cqo(x86code *&emitptr) { emit_op_simple(emitptr, OP_CQO, OP_64BIT); } +#endif + + + +//************************************************************************** +// CALL/JUMP EMITTERS +//************************************************************************** + +//------------------------------------------------- +// resolve_link - resolve a link in a jump +// instruction +//------------------------------------------------- + +inline void resolve_link(x86code *&destptr, const emit_link &linkinfo) +{ + INT64 delta = destptr - linkinfo.target; + if (linkinfo.size == 1) + { + assert((INT8)delta == delta); + ((INT8 *)linkinfo.target)[-1] = (INT8)delta; + } + else if (linkinfo.size == 2) + { + assert((INT16)delta == delta); + ((INT16 *)linkinfo.target)[-1] = (INT16)delta; + } + else + { + assert((INT32)delta == delta); + ((INT32 *)linkinfo.target)[-1] = (INT32)delta; + } +} + + +//------------------------------------------------- +// emit_call_* +//------------------------------------------------- + +inline void emit_call_link(x86code *&emitptr, emit_link &linkinfo) +{ + emit_op_simple(emitptr, OP_CALL_Jz, OP_32BIT); + emit_dword(emitptr, 0); + linkinfo.target = emitptr; + linkinfo.size = 4; +} + +inline void emit_call(x86code *&emitptr, x86code *target) +{ + emit_link link; + emit_call_link(emitptr, link); + resolve_link(target, link); +} + + +//------------------------------------------------- +// emit_jmp_* +//------------------------------------------------- + +inline void emit_jmp_short_link(x86code *&emitptr, emit_link &linkinfo) +{ + emit_op_simple(emitptr, OP_JMP_Jb, OP_32BIT); + emit_byte(emitptr, 0); + linkinfo.target = emitptr; + linkinfo.size = 1; +} + +inline void emit_jmp_near_link(x86code *&emitptr, emit_link &linkinfo) +{ + emit_op_simple(emitptr, OP_JMP_Jz, OP_32BIT); + emit_dword(emitptr, 0); + linkinfo.target = emitptr; + linkinfo.size = 4; +} + +inline void emit_jmp(x86code *&emitptr, x86code *target) +{ + INT32 delta = target - (emitptr + 2); + emit_link link; + + if ((INT8)delta == delta) + emit_jmp_short_link(emitptr, link); + else + emit_jmp_near_link(emitptr, link); + resolve_link(target, link); +} + + +//------------------------------------------------- +// emit_jcc_* +//------------------------------------------------- + +inline void emit_jcc_short_link(x86code *&emitptr, UINT8 cond, emit_link &linkinfo) +{ + emit_op_simple(emitptr, OP_JCC_O_Jb + cond, OP_32BIT); + emit_byte(emitptr, 0); + linkinfo.target = emitptr; + linkinfo.size = 1; +} + +inline void emit_jcc_near_link(x86code *&emitptr, UINT8 cond, emit_link &linkinfo) +{ + emit_op_simple(emitptr, OP_JCC_O_Jv + cond, OP_32BIT); + emit_dword(emitptr, 0); + linkinfo.target = emitptr; + linkinfo.size = 4; +} + +inline void emit_jcc(x86code *&emitptr, UINT8 cond, x86code *target) +{ + INT32 delta = emitptr + 2 - target; + emit_link link; + + if ((INT8)delta == delta) + emit_jcc_short_link(emitptr, cond, link); + else + emit_jcc_near_link(emitptr, cond, link); + resolve_link(target, link); +} + + +//------------------------------------------------- +// emit_jecxz_* +//------------------------------------------------- + +inline void emit_jecxz_link(x86code *&emitptr, emit_link &linkinfo) +{ + emit_op_simple(emitptr, OP_JrCXZ_Jb, OP_32BIT); + emit_byte(emitptr, 0); + linkinfo.target = emitptr; + linkinfo.size = 1; +} + +inline void emit_jecxz(x86code *&emitptr, x86code *target) +{ + emit_link link; + emit_jecxz_link(emitptr, link); + resolve_link(target, link); +} + +#if (X86EMIT_SIZE == 64) + +inline void emit_jrcxz_link(x86code *&emitptr, emit_link &linkinfo) +{ + emit_op_simple(emitptr, OP_JrCXZ_Jb, OP_64BIT); + emit_byte(emitptr, 0); + linkinfo.target = emitptr; + linkinfo.size = 1; +} + +inline void emit_jrcxz(x86code *&emitptr, x86code *target) +{ + emit_link link; + emit_jrcxz_link(emitptr, link); + resolve_link(target, link); +} + +#endif + + +//------------------------------------------------- +// emit_call/jmp_* +//------------------------------------------------- + +#if (X86EMIT_SIZE == 32) +inline void emit_call_r32(x86code *&emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G5, OP_32BIT, 2, dreg); } +inline void emit_call_m32(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_G5, OP_32BIT, 2, memref); } +inline void emit_jmp_r32(x86code *&emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G5, OP_32BIT, 4, dreg); } +inline void emit_jmp_m32(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_G5, OP_32BIT, 4, memref); } +#else +inline void emit_call_r64(x86code *&emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G5, OP_32BIT, 2, dreg); } +inline void emit_call_m64(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_G5, OP_32BIT, 2, memref); } +inline void emit_jmp_r64(x86code *&emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G5, OP_32BIT, 4, dreg); } +inline void emit_jmp_m64(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_G5, OP_32BIT, 4, memref); } +#endif + + +//------------------------------------------------- +// emit_ret_* +//------------------------------------------------- + +inline void emit_ret_imm(x86code *&emitptr, UINT16 imm) +{ + emit_op_simple(emitptr, OP_RETN_Iw, OP_32BIT); + emit_word(emitptr, imm); +} + + + +//************************************************************************** +// PUSH/POP EMITTERS +//************************************************************************** + +inline void emit_push_imm(x86code *&emitptr, INT32 imm) +{ + if ((INT8)imm == imm) + { + emit_op_simple(emitptr, OP_PUSH_Ib, OP_32BIT); + emit_byte(emitptr, (INT8)imm); + } + else + { + emit_op_simple(emitptr, OP_PUSH_Iz, OP_32BIT); + emit_dword(emitptr, imm); + } +} + +#if (X86EMIT_SIZE == 32) + +inline void emit_push_r32(x86code *&emitptr, UINT8 reg) { emit_op_reg(emitptr, OP_PUSH_rAX + (reg & 7), OP_32BIT, reg); } +inline void emit_push_m32(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_G5, OP_32BIT, 6, memref); } +inline void emit_pop_r32(x86code *&emitptr, UINT8 reg) { emit_op_reg(emitptr, OP_POP_rAX + (reg & 7), OP_32BIT, reg); } +inline void emit_pop_m32(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_G1A_Ev, OP_32BIT, 0, memref); } + +#else + +inline void emit_push_r64(x86code *&emitptr, UINT8 reg) { emit_op_reg(emitptr, OP_PUSH_rAX + (reg & 7), OP_32BIT, reg); } +inline void emit_push_m64(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_G5, OP_32BIT, 6, memref); } +inline void emit_pop_r64(x86code *&emitptr, UINT8 reg) { emit_op_reg(emitptr, OP_POP_rAX + (reg & 7), OP_32BIT, reg); } +inline void emit_pop_m64(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_G1A_Ev, OP_32BIT, 0, memref); } + +#endif + + + +//************************************************************************** +// MOVE EMITTERS +//************************************************************************** + +//------------------------------------------------- +// emit_mov_r8_* +//------------------------------------------------- + +inline void emit_mov_r8_imm(x86code *&emitptr, UINT8 dreg, UINT8 imm) +{ + emit_op_reg(emitptr, OP_MOV_AL_Ib | (dreg & 7), OP_32BIT, dreg); + emit_byte(emitptr, imm); +} + +inline void emit_mov_r8_r8(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_MOV_Gb_Eb, OP_32BIT, dreg, sreg); } +inline void emit_mov_r8_m8(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_MOV_Gb_Eb, OP_32BIT, dreg, memref); } +inline void emit_mov_m8_r8(x86code *&emitptr, x86_memref memref, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_MOV_Eb_Gb, OP_32BIT, sreg, memref); } +inline void emit_mov_m8_imm(x86code *&emitptr, x86_memref memref, UINT8 imm) { emit_op_modrm_mem_imm8(emitptr, OP_G11_Eb_Ib, OP_32BIT, 0, memref, imm); } + + +//------------------------------------------------- +// emit_xchg_r8_* +//------------------------------------------------- + +inline void emit_xchg_r8_r8(x86code *&emitptr, UINT8 dreg, UINT8 sreg) +{ + if (dreg == REG_EAX) + emit_op_reg(emitptr, OP_NOP | (sreg & 7), OP_32BIT, sreg); + else if (sreg == REG_EAX) + emit_op_reg(emitptr, OP_NOP | (dreg & 7), OP_32BIT, dreg); + else + emit_op_modrm_reg(emitptr, OP_XCHG_Eb_Gb, OP_32BIT, dreg, sreg); +} + + +//------------------------------------------------- +// emit_mov_r16_* +//------------------------------------------------- + +inline void emit_mov_r16_imm(x86code *&emitptr, UINT8 dreg, UINT16 imm) +{ + emit_op_reg(emitptr, OP_MOV_rAX_Iv | (dreg & 7), OP_16BIT, dreg); + emit_word(emitptr, imm); +} + +inline void emit_mov_r16_r16(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_MOV_Gv_Ev, OP_16BIT, dreg, sreg); } +inline void emit_mov_r16_m16(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_MOV_Gv_Ev, OP_16BIT, dreg, memref); } +inline void emit_mov_m16_imm(x86code *&emitptr, x86_memref memref, UINT16 imm) { emit_op_modrm_mem_imm16(emitptr, OP_G11_Ev_Iz, OP_16BIT, 0, memref, imm); } +inline void emit_mov_m16_r16(x86code *&emitptr, x86_memref memref, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_MOV_Ev_Gv, OP_16BIT, sreg, memref); } +inline void emit_movsx_r16_r8(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_MOVSX_Gv_Eb, OP_16BIT, dreg, sreg); } +inline void emit_movsx_r16_m8(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_MOVSX_Gv_Eb, OP_16BIT, dreg, memref); } +inline void emit_movzx_r16_r8(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_MOVZX_Gv_Eb, OP_16BIT, dreg, sreg); } +inline void emit_movzx_r16_m8(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_MOVZX_Gv_Eb, OP_16BIT, dreg, memref); } +inline void emit_cmovcc_r16_r16(x86code *&emitptr, UINT8 cond, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_CMOV_O_Gv_Ev + cond, OP_16BIT, dreg, sreg); } +inline void emit_cmovcc_r16_m16(x86code *&emitptr, UINT8 cond, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_CMOV_O_Gv_Ev + cond, OP_16BIT, dreg, memref); } + + +//------------------------------------------------- +// emit_xchg_r16_* +//------------------------------------------------- + +inline void emit_xchg_r16_r16(x86code *&emitptr, UINT8 dreg, UINT8 sreg) +{ + if (dreg == REG_EAX) + emit_op_reg(emitptr, OP_NOP | (sreg & 7), OP_16BIT, sreg); + else if (sreg == REG_EAX) + emit_op_reg(emitptr, OP_NOP | (dreg & 7), OP_16BIT, dreg); + else + emit_op_modrm_reg(emitptr, OP_XCHG_Ev_Gv, OP_16BIT, dreg, sreg); +} + + +//------------------------------------------------- +// emit_mov_r32_* +//------------------------------------------------- + +inline void emit_mov_r32_imm(x86code *&emitptr, UINT8 dreg, UINT32 imm) +{ + emit_op_reg(emitptr, OP_MOV_rAX_Iv | (dreg & 7), OP_32BIT, dreg); + emit_dword(emitptr, imm); +} + +inline void emit_mov_r32_r32(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_MOV_Gv_Ev, OP_32BIT, dreg, sreg); } +inline void emit_mov_r32_m32(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_MOV_Gv_Ev, OP_32BIT, dreg, memref); } +inline void emit_mov_m32_imm(x86code *&emitptr, x86_memref memref, UINT32 imm) { emit_op_modrm_mem_imm32(emitptr, OP_G11_Ev_Iz, OP_32BIT, 0, memref, imm); } +inline void emit_mov_m32_r32(x86code *&emitptr, x86_memref memref, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_MOV_Ev_Gv, OP_32BIT, sreg, memref); } +inline void emit_movsx_r32_r8(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_MOVSX_Gv_Eb, OP_32BIT, dreg, sreg); } +inline void emit_movsx_r32_m8(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_MOVSX_Gv_Eb, OP_32BIT, dreg, memref); } +inline void emit_movsx_r32_r16(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_MOVSX_Gv_Ew, OP_32BIT, dreg, sreg); } +inline void emit_movsx_r32_m16(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_MOVSX_Gv_Ew, OP_32BIT, dreg, memref); } +inline void emit_movzx_r32_r8(x86code *&emitptr, UINT8 dreg, UINT8 sreg) +{ +#if (X86EMIT_SIZE == 32) + if (sreg >= 4) + { + emit_op_modrm_reg(emitptr, OP_MOV_Gv_Ev, OP_32BIT, dreg, sreg); // mov dreg,sreg + emit_op_modrm_reg_imm832(emitptr, OP_G1_Ev_Ib, OP_G1_Ev_Iz, OP_32BIT, 4, dreg, 0xff); // and dreg,0xff + } + else +#endif + emit_op_modrm_reg(emitptr, OP_MOVZX_Gv_Eb, OP_32BIT, dreg, sreg); +} +inline void emit_movzx_r32_m8(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_MOVZX_Gv_Eb, OP_32BIT, dreg, memref); } +inline void emit_movzx_r32_r16(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_MOVZX_Gv_Ew, OP_32BIT, dreg, sreg); } +inline void emit_movzx_r32_m16(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_MOVZX_Gv_Ew, OP_32BIT, dreg, memref); } +inline void emit_cmovcc_r32_r32(x86code *&emitptr, UINT8 cond, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_CMOV_O_Gv_Ev + cond, OP_32BIT, dreg, sreg); } +inline void emit_cmovcc_r32_m32(x86code *&emitptr, UINT8 cond, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_CMOV_O_Gv_Ev + cond, OP_32BIT, dreg, memref); } + + +//------------------------------------------------- +// emit_xchg_r32_* +//------------------------------------------------- + +inline void emit_xchg_r32_r32(x86code *&emitptr, UINT8 dreg, UINT8 sreg) +{ + if (dreg == REG_EAX) + emit_op_reg(emitptr, OP_NOP | (sreg & 7), OP_32BIT, sreg); + else if (sreg == REG_EAX) + emit_op_reg(emitptr, OP_NOP | (dreg & 7), OP_32BIT, dreg); + else + emit_op_modrm_reg(emitptr, OP_XCHG_Ev_Gv, OP_32BIT, dreg, sreg); +} + + +//------------------------------------------------- +// emit_mov_r64_* +//------------------------------------------------- + +#if (X86EMIT_SIZE == 64) + +inline void emit_mov_r64_imm(x86code *&emitptr, UINT8 dreg, UINT64 imm) +{ + if ((UINT32)imm == imm) + { + emit_op_reg(emitptr, OP_MOV_rAX_Iv | (dreg & 7), OP_32BIT, dreg); + emit_dword(emitptr, imm); + } + else if ((INT32)imm == imm) + emit_op_modrm_reg_imm32(emitptr, OP_G11_Ev_Iz, OP_64BIT, 0, dreg, imm); + else + { + emit_op_reg(emitptr, OP_MOV_rAX_Iv | (dreg & 7), OP_64BIT, dreg); + emit_qword(emitptr, imm); + } +} + +inline void emit_mov_r64_r64(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_MOV_Gv_Ev, OP_64BIT, dreg, sreg); } +inline void emit_mov_r64_m64(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_MOV_Gv_Ev, OP_64BIT, dreg, memref); } +inline void emit_mov_m64_imm(x86code *&emitptr, x86_memref memref, UINT32 imm) { emit_op_modrm_mem_imm32(emitptr, OP_G11_Ev_Iz, OP_64BIT, 0, memref, imm); } +inline void emit_mov_m64_r64(x86code *&emitptr, x86_memref memref, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_MOV_Ev_Gv, OP_64BIT, sreg, memref); } +inline void emit_movsx_r64_r8(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_MOVSX_Gv_Eb, OP_64BIT, dreg, sreg); } +inline void emit_movsx_r64_m8(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_MOVSX_Gv_Eb, OP_64BIT, dreg, memref); } +inline void emit_movsx_r64_r16(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_MOVSX_Gv_Ew, OP_64BIT, dreg, sreg); } +inline void emit_movsx_r64_m16(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_MOVSX_Gv_Ew, OP_64BIT, dreg, memref); } +inline void emit_movsxd_r64_r32(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_MOVSXD_Gv_Ev, OP_64BIT, dreg, sreg); } +inline void emit_movsxd_r64_m32(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_MOVSXD_Gv_Ev, OP_64BIT, dreg, memref); } +inline void emit_movzx_r64_r8(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_MOVZX_Gv_Eb, OP_64BIT, dreg, sreg); } +inline void emit_movzx_r64_m8(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_MOVZX_Gv_Eb, OP_64BIT, dreg, memref); } +inline void emit_movzx_r64_r16(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_MOVZX_Gv_Ew, OP_64BIT, dreg, sreg); } +inline void emit_movzx_r64_m16(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_MOVZX_Gv_Ew, OP_64BIT, dreg, memref); } +inline void emit_cmovcc_r64_r64(x86code *&emitptr, UINT8 cond, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_CMOV_O_Gv_Ev + cond, OP_64BIT, dreg, sreg); } +inline void emit_cmovcc_r64_m64(x86code *&emitptr, UINT8 cond, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_CMOV_O_Gv_Ev + cond, OP_64BIT, dreg, memref); } + + +//------------------------------------------------- +// emit_xchg_r64_* +//------------------------------------------------- + +inline void emit_xchg_r64_r64(x86code *&emitptr, UINT8 dreg, UINT8 sreg) +{ + if (dreg == REG_EAX) + emit_op_reg(emitptr, OP_NOP | (sreg & 7), OP_64BIT, sreg); + else if (sreg == REG_EAX) + emit_op_reg(emitptr, OP_NOP | (dreg & 7), OP_64BIT, dreg); + else + emit_op_modrm_reg(emitptr, OP_XCHG_Ev_Gv, OP_64BIT, dreg, sreg); +} + +#endif + + +//************************************************************************** +// ARITHMETIC EMITTERS +//************************************************************************** + +//------------------------------------------------- +// emit_arith_r8_* +//------------------------------------------------- + +inline void emit_add_r8_imm(x86code *&emitptr, UINT8 dreg, UINT8 imm) { emit_op_modrm_reg_imm8(emitptr, OP_G1_Eb_Ib, OP_32BIT, 0, dreg, imm); } +inline void emit_add_m8_imm(x86code *&emitptr, x86_memref memref, UINT8 imm) { emit_op_modrm_mem_imm8(emitptr, OP_G1_Eb_Ib, OP_32BIT, 0, memref, imm); } +inline void emit_add_r8_r8(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_ADD_Gb_Eb, OP_32BIT, dreg, sreg); } +inline void emit_add_r8_m8(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_ADD_Gb_Eb, OP_32BIT, dreg, memref); } +inline void emit_add_m8_r8(x86code *&emitptr, x86_memref memref, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_ADD_Eb_Gb, OP_32BIT, sreg, memref); } + +inline void emit_or_r8_imm(x86code *&emitptr, UINT8 dreg, UINT8 imm) { emit_op_modrm_reg_imm8(emitptr, OP_G1_Eb_Ib, OP_32BIT, 1, dreg, imm); } +inline void emit_or_m8_imm(x86code *&emitptr, x86_memref memref, UINT8 imm) { emit_op_modrm_mem_imm8(emitptr, OP_G1_Eb_Ib, OP_32BIT, 1, memref, imm); } +inline void emit_or_r8_r8(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_OR_Gb_Eb, OP_32BIT, dreg, sreg); } +inline void emit_or_r8_m8(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_OR_Gb_Eb, OP_32BIT, dreg, memref); } +inline void emit_or_m8_r8(x86code *&emitptr, x86_memref memref, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_OR_Eb_Gb, OP_32BIT, sreg, memref); } + +inline void emit_adc_r8_imm(x86code *&emitptr, UINT8 dreg, UINT8 imm) { emit_op_modrm_reg_imm8(emitptr, OP_G1_Eb_Ib, OP_32BIT, 2, dreg, imm); } +inline void emit_adc_m8_imm(x86code *&emitptr, x86_memref memref, UINT8 imm) { emit_op_modrm_mem_imm8(emitptr, OP_G1_Eb_Ib, OP_32BIT, 2, memref, imm); } +inline void emit_adc_r8_r8(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_ADC_Gb_Eb, OP_32BIT, dreg, sreg); } +inline void emit_adc_r8_m8(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_ADC_Gb_Eb, OP_32BIT, dreg, memref); } +inline void emit_adc_m8_r8(x86code *&emitptr, x86_memref memref, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_ADC_Eb_Gb, OP_32BIT, sreg, memref); } + +inline void emit_sbb_r8_imm(x86code *&emitptr, UINT8 dreg, UINT8 imm) { emit_op_modrm_reg_imm8(emitptr, OP_G1_Eb_Ib, OP_32BIT, 3, dreg, imm); } +inline void emit_sbb_m8_imm(x86code *&emitptr, x86_memref memref, UINT8 imm) { emit_op_modrm_mem_imm8(emitptr, OP_G1_Eb_Ib, OP_32BIT, 3, memref, imm); } +inline void emit_sbb_r8_r8(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_SBB_Gb_Eb, OP_32BIT, dreg, sreg); } +inline void emit_sbb_r8_m8(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_SBB_Gb_Eb, OP_32BIT, dreg, memref); } +inline void emit_sbb_m8_r8(x86code *&emitptr, x86_memref memref, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_SBB_Eb_Gb, OP_32BIT, sreg, memref); } + +inline void emit_and_r8_imm(x86code *&emitptr, UINT8 dreg, UINT8 imm) { emit_op_modrm_reg_imm8(emitptr, OP_G1_Eb_Ib, OP_32BIT, 4, dreg, imm); } +inline void emit_and_m8_imm(x86code *&emitptr, x86_memref memref, UINT8 imm) { emit_op_modrm_mem_imm8(emitptr, OP_G1_Eb_Ib, OP_32BIT, 4, memref, imm); } +inline void emit_and_r8_r8(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_AND_Gb_Eb, OP_32BIT, dreg, sreg); } +inline void emit_and_r8_m8(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_AND_Gb_Eb, OP_32BIT, dreg, memref); } +inline void emit_and_m8_r8(x86code *&emitptr, x86_memref memref, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_AND_Eb_Gb, OP_32BIT, sreg, memref); } + +inline void emit_sub_r8_imm(x86code *&emitptr, UINT8 dreg, UINT8 imm) { emit_op_modrm_reg_imm8(emitptr, OP_G1_Eb_Ib, OP_32BIT, 5, dreg, imm); } +inline void emit_sub_m8_imm(x86code *&emitptr, x86_memref memref, UINT8 imm) { emit_op_modrm_mem_imm8(emitptr, OP_G1_Eb_Ib, OP_32BIT, 5, memref, imm); } +inline void emit_sub_r8_r8(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_SUB_Gb_Eb, OP_32BIT, dreg, sreg); } +inline void emit_sub_r8_m8(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_SUB_Gb_Eb, OP_32BIT, dreg, memref); } +inline void emit_sub_m8_r8(x86code *&emitptr, x86_memref memref, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_SUB_Eb_Gb, OP_32BIT, sreg, memref); } + +inline void emit_xor_r8_imm(x86code *&emitptr, UINT8 dreg, UINT8 imm) { emit_op_modrm_reg_imm8(emitptr, OP_G1_Eb_Ib, OP_32BIT, 6, dreg, imm); } +inline void emit_xor_m8_imm(x86code *&emitptr, x86_memref memref, UINT8 imm) { emit_op_modrm_mem_imm8(emitptr, OP_G1_Eb_Ib, OP_32BIT, 6, memref, imm); } +inline void emit_xor_r8_r8(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_XOR_Gb_Eb, OP_32BIT, dreg, sreg); } +inline void emit_xor_r8_m8(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_XOR_Gb_Eb, OP_32BIT, dreg, memref); } +inline void emit_xor_m8_r8(x86code *&emitptr, x86_memref memref, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_XOR_Eb_Gb, OP_32BIT, sreg, memref); } + +inline void emit_cmp_r8_imm(x86code *&emitptr, UINT8 dreg, UINT8 imm) { emit_op_modrm_reg_imm8(emitptr, OP_G1_Eb_Ib, OP_32BIT, 7, dreg, imm); } +inline void emit_cmp_m8_imm(x86code *&emitptr, x86_memref memref, UINT8 imm) { emit_op_modrm_mem_imm8(emitptr, OP_G1_Eb_Ib, OP_32BIT, 7, memref, imm); } +inline void emit_cmp_r8_r8(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_CMP_Gb_Eb, OP_32BIT, dreg, sreg); } +inline void emit_cmp_r8_m8(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_CMP_Gb_Eb, OP_32BIT, dreg, memref); } +inline void emit_cmp_m8_r8(x86code *&emitptr, x86_memref memref, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_CMP_Eb_Gb, OP_32BIT, sreg, memref); } + +inline void emit_test_r8_imm(x86code *&emitptr, UINT8 dreg, UINT8 imm) { emit_op_modrm_reg_imm8(emitptr, OP_G3_Eb, OP_32BIT, 0, dreg, imm); } +inline void emit_test_m8_imm(x86code *&emitptr, x86_memref memref, UINT8 imm) { emit_op_modrm_mem_imm8(emitptr, OP_G3_Eb, OP_32BIT, 0, memref, imm); } +inline void emit_test_r8_r8(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_TEST_Eb_Gb, OP_32BIT, sreg, dreg); } +inline void emit_test_m8_r8(x86code *&emitptr, x86_memref memref, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_TEST_Eb_Gb, OP_32BIT, sreg, memref); } + + +//------------------------------------------------- +// emit_arith_r16_* +//------------------------------------------------- + +inline void emit_add_r16_imm(x86code *&emitptr, UINT8 dreg, UINT16 imm) { emit_op_modrm_reg_imm816(emitptr, OP_G1_Ev_Ib, OP_G1_Ev_Iz, OP_16BIT, 0, dreg, imm); } +inline void emit_add_m16_imm(x86code *&emitptr, x86_memref memref, UINT16 imm) { emit_op_modrm_mem_imm816(emitptr, OP_G1_Ev_Ib, OP_G1_Ev_Iz, OP_16BIT, 0, memref, imm); } +inline void emit_add_r16_r16(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_ADD_Gv_Ev, OP_16BIT, dreg, sreg); } +inline void emit_add_r16_m16(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_ADD_Gv_Ev, OP_16BIT, dreg, memref); } +inline void emit_add_m16_r16(x86code *&emitptr, x86_memref memref, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_ADD_Ev_Gv, OP_16BIT, sreg, memref); } + +inline void emit_or_r16_imm(x86code *&emitptr, UINT8 dreg, UINT16 imm) { emit_op_modrm_reg_imm816(emitptr, OP_G1_Ev_Ib, OP_G1_Ev_Iz, OP_16BIT, 1, dreg, imm); } +inline void emit_or_m16_imm(x86code *&emitptr, x86_memref memref, UINT16 imm) { emit_op_modrm_mem_imm816(emitptr, OP_G1_Ev_Ib, OP_G1_Ev_Iz, OP_16BIT, 1, memref, imm); } +inline void emit_or_r16_r16(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_OR_Gv_Ev, OP_16BIT, dreg, sreg); } +inline void emit_or_r16_m16(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_OR_Gv_Ev, OP_16BIT, dreg, memref); } +inline void emit_or_m16_r16(x86code *&emitptr, x86_memref memref, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_OR_Ev_Gv, OP_16BIT, sreg, memref); } + +inline void emit_adc_r16_imm(x86code *&emitptr, UINT8 dreg, UINT16 imm) { emit_op_modrm_reg_imm816(emitptr, OP_G1_Ev_Ib, OP_G1_Ev_Iz, OP_16BIT, 2, dreg, imm); } +inline void emit_adc_m16_imm(x86code *&emitptr, x86_memref memref, UINT16 imm) { emit_op_modrm_mem_imm816(emitptr, OP_G1_Ev_Ib, OP_G1_Ev_Iz, OP_16BIT, 2, memref, imm); } +inline void emit_adc_r16_r16(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_ADC_Gv_Ev, OP_16BIT, dreg, sreg); } +inline void emit_adc_r16_m16(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_ADC_Gv_Ev, OP_16BIT, dreg, memref); } +inline void emit_adc_m16_r16(x86code *&emitptr, x86_memref memref, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_ADC_Ev_Gv, OP_16BIT, sreg, memref); } + +inline void emit_sbb_r16_imm(x86code *&emitptr, UINT8 dreg, UINT16 imm) { emit_op_modrm_reg_imm816(emitptr, OP_G1_Ev_Ib, OP_G1_Ev_Iz, OP_16BIT, 3, dreg, imm); } +inline void emit_sbb_m16_imm(x86code *&emitptr, x86_memref memref, UINT16 imm) { emit_op_modrm_mem_imm816(emitptr, OP_G1_Ev_Ib, OP_G1_Ev_Iz, OP_16BIT, 3, memref, imm); } +inline void emit_sbb_r16_r16(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_SBB_Gv_Ev, OP_16BIT, dreg, sreg); } +inline void emit_sbb_r16_m16(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_SBB_Gv_Ev, OP_16BIT, dreg, memref); } +inline void emit_sbb_m16_r16(x86code *&emitptr, x86_memref memref, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_SBB_Ev_Gv, OP_16BIT, sreg, memref); } + +inline void emit_and_r16_imm(x86code *&emitptr, UINT8 dreg, UINT16 imm) { emit_op_modrm_reg_imm816(emitptr, OP_G1_Ev_Ib, OP_G1_Ev_Iz, OP_16BIT, 4, dreg, imm); } +inline void emit_and_m16_imm(x86code *&emitptr, x86_memref memref, UINT16 imm) { emit_op_modrm_mem_imm816(emitptr, OP_G1_Ev_Ib, OP_G1_Ev_Iz, OP_16BIT, 4, memref, imm); } +inline void emit_and_r16_r16(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_AND_Gv_Ev, OP_16BIT, dreg, sreg); } +inline void emit_and_r16_m16(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_AND_Gv_Ev, OP_16BIT, dreg, memref); } +inline void emit_and_m16_r16(x86code *&emitptr, x86_memref memref, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_AND_Ev_Gv, OP_16BIT, sreg, memref); } + +inline void emit_sub_r16_imm(x86code *&emitptr, UINT8 dreg, UINT16 imm) { emit_op_modrm_reg_imm816(emitptr, OP_G1_Ev_Ib, OP_G1_Ev_Iz, OP_16BIT, 5, dreg, imm); } +inline void emit_sub_m16_imm(x86code *&emitptr, x86_memref memref, UINT16 imm) { emit_op_modrm_mem_imm816(emitptr, OP_G1_Ev_Ib, OP_G1_Ev_Iz, OP_16BIT, 5, memref, imm); } +inline void emit_sub_r16_r16(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_SUB_Gv_Ev, OP_16BIT, dreg, sreg); } +inline void emit_sub_r16_m16(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_SUB_Gv_Ev, OP_16BIT, dreg, memref); } +inline void emit_sub_m16_r16(x86code *&emitptr, x86_memref memref, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_SUB_Ev_Gv, OP_16BIT, sreg, memref); } + +inline void emit_xor_r16_imm(x86code *&emitptr, UINT8 dreg, UINT16 imm) { emit_op_modrm_reg_imm816(emitptr, OP_G1_Ev_Ib, OP_G1_Ev_Iz, OP_16BIT, 6, dreg, imm); } +inline void emit_xor_m16_imm(x86code *&emitptr, x86_memref memref, UINT16 imm) { emit_op_modrm_mem_imm816(emitptr, OP_G1_Ev_Ib, OP_G1_Ev_Iz, OP_16BIT, 6, memref, imm); } +inline void emit_xor_r16_r16(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_XOR_Gv_Ev, OP_16BIT, dreg, sreg); } +inline void emit_xor_r16_m16(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_XOR_Gv_Ev, OP_16BIT, dreg, memref); } +inline void emit_xor_m16_r16(x86code *&emitptr, x86_memref memref, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_XOR_Ev_Gv, OP_16BIT, sreg, memref); } + +inline void emit_cmp_r16_imm(x86code *&emitptr, UINT8 dreg, UINT16 imm) { emit_op_modrm_reg_imm816(emitptr, OP_G1_Ev_Ib, OP_G1_Ev_Iz, OP_16BIT, 7, dreg, imm); } +inline void emit_cmp_m16_imm(x86code *&emitptr, x86_memref memref, UINT16 imm) { emit_op_modrm_mem_imm816(emitptr, OP_G1_Ev_Ib, OP_G1_Ev_Iz, OP_16BIT, 7, memref, imm); } +inline void emit_cmp_r16_r16(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_CMP_Gv_Ev, OP_16BIT, dreg, sreg); } +inline void emit_cmp_r16_m16(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_CMP_Gv_Ev, OP_16BIT, dreg, memref); } +inline void emit_cmp_m16_r16(x86code *&emitptr, x86_memref memref, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_CMP_Ev_Gv, OP_16BIT, sreg, memref); } + +inline void emit_test_r16_imm(x86code *&emitptr, UINT8 dreg, UINT16 imm) { emit_op_modrm_reg_imm16(emitptr, OP_G3_Ev, OP_16BIT, 0, dreg, imm); } +inline void emit_test_m16_imm(x86code *&emitptr, x86_memref memref, UINT16 imm) { emit_op_modrm_mem_imm16(emitptr, OP_G3_Ev, OP_16BIT, 0, memref, imm); } +inline void emit_test_r16_r16(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_TEST_Ev_Gv, OP_16BIT, sreg, dreg); } +inline void emit_test_m16_r16(x86code *&emitptr, x86_memref memref, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_TEST_Ev_Gv, OP_16BIT, sreg, memref); } + + +//------------------------------------------------- +// emit_arith_r32_* +//------------------------------------------------- + +inline void emit_add_r32_imm(x86code *&emitptr, UINT8 dreg, UINT32 imm) { emit_op_modrm_reg_imm832(emitptr, OP_G1_Ev_Ib, OP_G1_Ev_Iz, OP_32BIT, 0, dreg, imm); } +inline void emit_add_m32_imm(x86code *&emitptr, x86_memref memref, UINT32 imm) { emit_op_modrm_mem_imm832(emitptr, OP_G1_Ev_Ib, OP_G1_Ev_Iz, OP_32BIT, 0, memref, imm); } +inline void emit_add_r32_r32(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_ADD_Gv_Ev, OP_32BIT, dreg, sreg); } +inline void emit_add_r32_m32(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_ADD_Gv_Ev, OP_32BIT, dreg, memref); } +inline void emit_add_m32_r32(x86code *&emitptr, x86_memref memref, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_ADD_Ev_Gv, OP_32BIT, sreg, memref); } + +inline void emit_or_r32_imm(x86code *&emitptr, UINT8 dreg, UINT32 imm) { emit_op_modrm_reg_imm832(emitptr, OP_G1_Ev_Ib, OP_G1_Ev_Iz, OP_32BIT, 1, dreg, imm); } +inline void emit_or_m32_imm(x86code *&emitptr, x86_memref memref, UINT32 imm) { emit_op_modrm_mem_imm832(emitptr, OP_G1_Ev_Ib, OP_G1_Ev_Iz, OP_32BIT, 1, memref, imm); } +inline void emit_or_r32_r32(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_OR_Gv_Ev, OP_32BIT, dreg, sreg); } +inline void emit_or_r32_m32(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_OR_Gv_Ev, OP_32BIT, dreg, memref); } +inline void emit_or_m32_r32(x86code *&emitptr, x86_memref memref, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_OR_Ev_Gv, OP_32BIT, sreg, memref); } + +inline void emit_adc_r32_imm(x86code *&emitptr, UINT8 dreg, UINT32 imm) { emit_op_modrm_reg_imm832(emitptr, OP_G1_Ev_Ib, OP_G1_Ev_Iz, OP_32BIT, 2, dreg, imm); } +inline void emit_adc_m32_imm(x86code *&emitptr, x86_memref memref, UINT32 imm) { emit_op_modrm_mem_imm832(emitptr, OP_G1_Ev_Ib, OP_G1_Ev_Iz, OP_32BIT, 2, memref, imm); } +inline void emit_adc_r32_r32(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_ADC_Gv_Ev, OP_32BIT, dreg, sreg); } +inline void emit_adc_r32_m32(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_ADC_Gv_Ev, OP_32BIT, dreg, memref); } +inline void emit_adc_m32_r32(x86code *&emitptr, x86_memref memref, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_ADC_Ev_Gv, OP_32BIT, sreg, memref); } + +inline void emit_sbb_r32_imm(x86code *&emitptr, UINT8 dreg, UINT32 imm) { emit_op_modrm_reg_imm832(emitptr, OP_G1_Ev_Ib, OP_G1_Ev_Iz, OP_32BIT, 3, dreg, imm); } +inline void emit_sbb_m32_imm(x86code *&emitptr, x86_memref memref, UINT32 imm) { emit_op_modrm_mem_imm832(emitptr, OP_G1_Ev_Ib, OP_G1_Ev_Iz, OP_32BIT, 3, memref, imm); } +inline void emit_sbb_r32_r32(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_SBB_Gv_Ev, OP_32BIT, dreg, sreg); } +inline void emit_sbb_r32_m32(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_SBB_Gv_Ev, OP_32BIT, dreg, memref); } +inline void emit_sbb_m32_r32(x86code *&emitptr, x86_memref memref, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_SBB_Ev_Gv, OP_32BIT, sreg, memref); } + +inline void emit_and_r32_imm(x86code *&emitptr, UINT8 dreg, UINT32 imm) { emit_op_modrm_reg_imm832(emitptr, OP_G1_Ev_Ib, OP_G1_Ev_Iz, OP_32BIT, 4, dreg, imm); } +inline void emit_and_m32_imm(x86code *&emitptr, x86_memref memref, UINT32 imm) { emit_op_modrm_mem_imm832(emitptr, OP_G1_Ev_Ib, OP_G1_Ev_Iz, OP_32BIT, 4, memref, imm); } +inline void emit_and_r32_r32(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_AND_Gv_Ev, OP_32BIT, dreg, sreg); } +inline void emit_and_r32_m32(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_AND_Gv_Ev, OP_32BIT, dreg, memref); } +inline void emit_and_m32_r32(x86code *&emitptr, x86_memref memref, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_AND_Ev_Gv, OP_32BIT, sreg, memref); } + +inline void emit_sub_r32_imm(x86code *&emitptr, UINT8 dreg, UINT32 imm) { emit_op_modrm_reg_imm832(emitptr, OP_G1_Ev_Ib, OP_G1_Ev_Iz, OP_32BIT, 5, dreg, imm); } +inline void emit_sub_m32_imm(x86code *&emitptr, x86_memref memref, UINT32 imm) { emit_op_modrm_mem_imm832(emitptr, OP_G1_Ev_Ib, OP_G1_Ev_Iz, OP_32BIT, 5, memref, imm); } +inline void emit_sub_r32_r32(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_SUB_Gv_Ev, OP_32BIT, dreg, sreg); } +inline void emit_sub_r32_m32(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_SUB_Gv_Ev, OP_32BIT, dreg, memref); } +inline void emit_sub_m32_r32(x86code *&emitptr, x86_memref memref, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_SUB_Ev_Gv, OP_32BIT, sreg, memref); } + +inline void emit_xor_r32_imm(x86code *&emitptr, UINT8 dreg, UINT32 imm) { emit_op_modrm_reg_imm832(emitptr, OP_G1_Ev_Ib, OP_G1_Ev_Iz, OP_32BIT, 6, dreg, imm); } +inline void emit_xor_m32_imm(x86code *&emitptr, x86_memref memref, UINT32 imm) { emit_op_modrm_mem_imm832(emitptr, OP_G1_Ev_Ib, OP_G1_Ev_Iz, OP_32BIT, 6, memref, imm); } +inline void emit_xor_r32_r32(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_XOR_Gv_Ev, OP_32BIT, dreg, sreg); } +inline void emit_xor_r32_m32(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_XOR_Gv_Ev, OP_32BIT, dreg, memref); } +inline void emit_xor_m32_r32(x86code *&emitptr, x86_memref memref, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_XOR_Ev_Gv, OP_32BIT, sreg, memref); } + +inline void emit_cmp_r32_imm(x86code *&emitptr, UINT8 dreg, UINT32 imm) { emit_op_modrm_reg_imm832(emitptr, OP_G1_Ev_Ib, OP_G1_Ev_Iz, OP_32BIT, 7, dreg, imm); } +inline void emit_cmp_m32_imm(x86code *&emitptr, x86_memref memref, UINT32 imm) { emit_op_modrm_mem_imm832(emitptr, OP_G1_Ev_Ib, OP_G1_Ev_Iz, OP_32BIT, 7, memref, imm); } +inline void emit_cmp_r32_r32(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_CMP_Gv_Ev, OP_32BIT, dreg, sreg); } +inline void emit_cmp_r32_m32(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_CMP_Gv_Ev, OP_32BIT, dreg, memref); } +inline void emit_cmp_m32_r32(x86code *&emitptr, x86_memref memref, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_CMP_Ev_Gv, OP_32BIT, sreg, memref); } + +inline void emit_test_r32_imm(x86code *&emitptr, UINT8 dreg, UINT32 imm) { emit_op_modrm_reg_imm32(emitptr, OP_G3_Ev, OP_32BIT, 0, dreg, imm); } +inline void emit_test_m32_imm(x86code *&emitptr, x86_memref memref, UINT32 imm) { emit_op_modrm_mem_imm32(emitptr, OP_G3_Ev, OP_32BIT, 0, memref, imm); } +inline void emit_test_r32_r32(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_TEST_Ev_Gv, OP_32BIT, sreg, dreg); } +inline void emit_test_m32_r32(x86code *&emitptr, x86_memref memref, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_TEST_Ev_Gv, OP_32BIT, sreg, memref); } + + +//------------------------------------------------- +// emit_arith_r64_* +//------------------------------------------------- + +#if (X86EMIT_SIZE == 64) + +inline void emit_add_r64_imm(x86code *&emitptr, UINT8 dreg, UINT32 imm) { emit_op_modrm_reg_imm832(emitptr, OP_G1_Ev_Ib, OP_G1_Ev_Iz, OP_64BIT, 0, dreg, imm); } +inline void emit_add_m64_imm(x86code *&emitptr, x86_memref memref, UINT32 imm) { emit_op_modrm_mem_imm832(emitptr, OP_G1_Ev_Ib, OP_G1_Ev_Iz, OP_64BIT, 0, memref, imm); } +inline void emit_add_r64_r64(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_ADD_Gv_Ev, OP_64BIT, dreg, sreg); } +inline void emit_add_r64_m64(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_ADD_Gv_Ev, OP_64BIT, dreg, memref); } +inline void emit_add_m64_r64(x86code *&emitptr, x86_memref memref, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_ADD_Ev_Gv, OP_64BIT, sreg, memref); } + +inline void emit_or_r64_imm(x86code *&emitptr, UINT8 dreg, UINT32 imm) { emit_op_modrm_reg_imm832(emitptr, OP_G1_Ev_Ib, OP_G1_Ev_Iz, OP_64BIT, 1, dreg, imm); } +inline void emit_or_m64_imm(x86code *&emitptr, x86_memref memref, UINT32 imm) { emit_op_modrm_mem_imm832(emitptr, OP_G1_Ev_Ib, OP_G1_Ev_Iz, OP_64BIT, 1, memref, imm); } +inline void emit_or_r64_r64(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_OR_Gv_Ev, OP_64BIT, dreg, sreg); } +inline void emit_or_r64_m64(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_OR_Gv_Ev, OP_64BIT, dreg, memref); } +inline void emit_or_m64_r64(x86code *&emitptr, x86_memref memref, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_OR_Ev_Gv, OP_64BIT, sreg, memref); } + +inline void emit_adc_r64_imm(x86code *&emitptr, UINT8 dreg, UINT32 imm) { emit_op_modrm_reg_imm832(emitptr, OP_G1_Ev_Ib, OP_G1_Ev_Iz, OP_64BIT, 2, dreg, imm); } +inline void emit_adc_m64_imm(x86code *&emitptr, x86_memref memref, UINT32 imm) { emit_op_modrm_mem_imm832(emitptr, OP_G1_Ev_Ib, OP_G1_Ev_Iz, OP_64BIT, 2, memref, imm); } +inline void emit_adc_r64_r64(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_ADC_Gv_Ev, OP_64BIT, dreg, sreg); } +inline void emit_adc_r64_m64(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_ADC_Gv_Ev, OP_64BIT, dreg, memref); } +inline void emit_adc_m64_r64(x86code *&emitptr, x86_memref memref, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_ADC_Ev_Gv, OP_64BIT, sreg, memref); } + +inline void emit_sbb_r64_imm(x86code *&emitptr, UINT8 dreg, UINT32 imm) { emit_op_modrm_reg_imm832(emitptr, OP_G1_Ev_Ib, OP_G1_Ev_Iz, OP_64BIT, 3, dreg, imm); } +inline void emit_sbb_m64_imm(x86code *&emitptr, x86_memref memref, UINT32 imm) { emit_op_modrm_mem_imm832(emitptr, OP_G1_Ev_Ib, OP_G1_Ev_Iz, OP_64BIT, 3, memref, imm); } +inline void emit_sbb_r64_r64(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_SBB_Gv_Ev, OP_64BIT, dreg, sreg); } +inline void emit_sbb_r64_m64(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_SBB_Gv_Ev, OP_64BIT, dreg, memref); } +inline void emit_sbb_m64_r64(x86code *&emitptr, x86_memref memref, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_SBB_Ev_Gv, OP_64BIT, sreg, memref); } + +inline void emit_and_r64_imm(x86code *&emitptr, UINT8 dreg, UINT32 imm) { emit_op_modrm_reg_imm832(emitptr, OP_G1_Ev_Ib, OP_G1_Ev_Iz, OP_64BIT, 4, dreg, imm); } +inline void emit_and_m64_imm(x86code *&emitptr, x86_memref memref, UINT32 imm) { emit_op_modrm_mem_imm832(emitptr, OP_G1_Ev_Ib, OP_G1_Ev_Iz, OP_64BIT, 4, memref, imm); } +inline void emit_and_r64_r64(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_AND_Gv_Ev, OP_64BIT, dreg, sreg); } +inline void emit_and_r64_m64(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_AND_Gv_Ev, OP_64BIT, dreg, memref); } +inline void emit_and_m64_r64(x86code *&emitptr, x86_memref memref, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_AND_Ev_Gv, OP_64BIT, sreg, memref); } + +inline void emit_sub_r64_imm(x86code *&emitptr, UINT8 dreg, UINT32 imm) { emit_op_modrm_reg_imm832(emitptr, OP_G1_Ev_Ib, OP_G1_Ev_Iz, OP_64BIT, 5, dreg, imm); } +inline void emit_sub_m64_imm(x86code *&emitptr, x86_memref memref, UINT32 imm) { emit_op_modrm_mem_imm832(emitptr, OP_G1_Ev_Ib, OP_G1_Ev_Iz, OP_64BIT, 5, memref, imm); } +inline void emit_sub_r64_r64(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_SUB_Gv_Ev, OP_64BIT, dreg, sreg); } +inline void emit_sub_r64_m64(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_SUB_Gv_Ev, OP_64BIT, dreg, memref); } +inline void emit_sub_m64_r64(x86code *&emitptr, x86_memref memref, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_SUB_Ev_Gv, OP_64BIT, sreg, memref); } + +inline void emit_xor_r64_imm(x86code *&emitptr, UINT8 dreg, UINT32 imm) { emit_op_modrm_reg_imm832(emitptr, OP_G1_Ev_Ib, OP_G1_Ev_Iz, OP_64BIT, 6, dreg, imm); } +inline void emit_xor_m64_imm(x86code *&emitptr, x86_memref memref, UINT32 imm) { emit_op_modrm_mem_imm832(emitptr, OP_G1_Ev_Ib, OP_G1_Ev_Iz, OP_64BIT, 6, memref, imm); } +inline void emit_xor_r64_r64(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_XOR_Gv_Ev, OP_64BIT, dreg, sreg); } +inline void emit_xor_r64_m64(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_XOR_Gv_Ev, OP_64BIT, dreg, memref); } +inline void emit_xor_m64_r64(x86code *&emitptr, x86_memref memref, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_XOR_Ev_Gv, OP_64BIT, sreg, memref); } + +inline void emit_cmp_r64_imm(x86code *&emitptr, UINT8 dreg, UINT32 imm) { emit_op_modrm_reg_imm832(emitptr, OP_G1_Ev_Ib, OP_G1_Ev_Iz, OP_64BIT, 7, dreg, imm); } +inline void emit_cmp_m64_imm(x86code *&emitptr, x86_memref memref, UINT32 imm) { emit_op_modrm_mem_imm832(emitptr, OP_G1_Ev_Ib, OP_G1_Ev_Iz, OP_64BIT, 7, memref, imm); } +inline void emit_cmp_r64_r64(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_CMP_Gv_Ev, OP_64BIT, dreg, sreg); } +inline void emit_cmp_r64_m64(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_CMP_Gv_Ev, OP_64BIT, dreg, memref); } +inline void emit_cmp_m64_r64(x86code *&emitptr, x86_memref memref, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_CMP_Ev_Gv, OP_64BIT, sreg, memref); } + +inline void emit_test_r64_imm(x86code *&emitptr, UINT8 dreg, UINT32 imm) { emit_op_modrm_reg_imm32(emitptr, OP_G3_Ev, OP_64BIT, 0, dreg, imm); } +inline void emit_test_m64_imm(x86code *&emitptr, x86_memref memref, UINT32 imm) { emit_op_modrm_mem_imm32(emitptr, OP_G3_Ev, OP_64BIT, 0, memref, imm); } +inline void emit_test_r64_r64(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_TEST_Ev_Gv, OP_64BIT, sreg, dreg); } +inline void emit_test_m64_r64(x86code *&emitptr, x86_memref memref, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_TEST_Ev_Gv, OP_64BIT, sreg, memref); } + +#endif + + + +//************************************************************************** +// SHIFT EMITTERS +//************************************************************************** + +//------------------------------------------------- +// emit_shift_reg_imm +//------------------------------------------------- + +inline void emit_shift_reg_imm(x86code *&emitptr, UINT32 op1, UINT32 opn, UINT8 opsize, UINT8 opindex, UINT8 dreg, UINT8 imm) +{ + if (imm == 1) + emit_op_modrm_reg(emitptr, op1, opsize, opindex, dreg); + else + emit_op_modrm_reg_imm8(emitptr, opn, opsize, opindex, dreg, imm); +} + +inline void emit_shift_mem_imm(x86code *&emitptr, UINT32 op1, UINT32 opn, UINT8 opsize, UINT8 opindex, x86_memref memref, UINT8 imm) +{ + if (imm == 1) + emit_op_modrm_mem(emitptr, op1, opsize, opindex, memref); + else + emit_op_modrm_mem_imm8(emitptr, opn, opsize, opindex, memref, imm); +} + + +//------------------------------------------------- +// emit_shift_r8_* +//------------------------------------------------- + +inline void emit_rol_r8_imm(x86code *&emitptr, UINT8 dreg, UINT8 imm) { emit_shift_reg_imm(emitptr, OP_G2_Eb_1, OP_G2_Eb_Ib, OP_32BIT, 0, dreg, imm); } +inline void emit_rol_m8_imm(x86code *&emitptr, x86_memref memref, UINT8 imm) { emit_shift_mem_imm(emitptr, OP_G2_Eb_1, OP_G2_Eb_Ib, OP_32BIT, 0, memref, imm); } +inline void emit_rol_r8_cl(x86code *&emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G2_Eb_CL, OP_32BIT, 0, dreg); } +inline void emit_rol_m8_cl(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_G2_Eb_CL, OP_32BIT, 0, memref); } + +inline void emit_ror_r8_imm(x86code *&emitptr, UINT8 dreg, UINT8 imm) { emit_shift_reg_imm(emitptr, OP_G2_Eb_1, OP_G2_Eb_Ib, OP_32BIT, 1, dreg, imm); } +inline void emit_ror_m8_imm(x86code *&emitptr, x86_memref memref, UINT8 imm) { emit_shift_mem_imm(emitptr, OP_G2_Eb_1, OP_G2_Eb_Ib, OP_32BIT, 1, memref, imm); } +inline void emit_ror_r8_cl(x86code *&emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G2_Eb_CL, OP_32BIT, 1, dreg); } +inline void emit_ror_m8_cl(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_G2_Eb_CL, OP_32BIT, 1, memref); } + +inline void emit_rcl_r8_imm(x86code *&emitptr, UINT8 dreg, UINT8 imm) { emit_shift_reg_imm(emitptr, OP_G2_Eb_1, OP_G2_Eb_Ib, OP_32BIT, 2, dreg, imm); } +inline void emit_rcl_m8_imm(x86code *&emitptr, x86_memref memref, UINT8 imm) { emit_shift_mem_imm(emitptr, OP_G2_Eb_1, OP_G2_Eb_Ib, OP_32BIT, 2, memref, imm); } +inline void emit_rcl_r8_cl(x86code *&emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G2_Eb_CL, OP_32BIT, 2, dreg); } +inline void emit_rcl_m8_cl(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_G2_Eb_CL, OP_32BIT, 2, memref); } + +inline void emit_rcr_r8_imm(x86code *&emitptr, UINT8 dreg, UINT8 imm) { emit_shift_reg_imm(emitptr, OP_G2_Eb_1, OP_G2_Eb_Ib, OP_32BIT, 3, dreg, imm); } +inline void emit_rcr_m8_imm(x86code *&emitptr, x86_memref memref, UINT8 imm) { emit_shift_mem_imm(emitptr, OP_G2_Eb_1, OP_G2_Eb_Ib, OP_32BIT, 3, memref, imm); } +inline void emit_rcr_r8_cl(x86code *&emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G2_Eb_CL, OP_32BIT, 3, dreg); } +inline void emit_rcr_m8_cl(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_G2_Eb_CL, OP_32BIT, 3, memref); } + +inline void emit_shl_r8_imm(x86code *&emitptr, UINT8 dreg, UINT8 imm) { emit_shift_reg_imm(emitptr, OP_G2_Eb_1, OP_G2_Eb_Ib, OP_32BIT, 4, dreg, imm); } +inline void emit_shl_m8_imm(x86code *&emitptr, x86_memref memref, UINT8 imm) { emit_shift_mem_imm(emitptr, OP_G2_Eb_1, OP_G2_Eb_Ib, OP_32BIT, 4, memref, imm); } +inline void emit_shl_r8_cl(x86code *&emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G2_Eb_CL, OP_32BIT, 4, dreg); } +inline void emit_shl_m8_cl(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_G2_Eb_CL, OP_32BIT, 4, memref); } + +inline void emit_shr_r8_imm(x86code *&emitptr, UINT8 dreg, UINT8 imm) { emit_shift_reg_imm(emitptr, OP_G2_Eb_1, OP_G2_Eb_Ib, OP_32BIT, 5, dreg, imm); } +inline void emit_shr_m8_imm(x86code *&emitptr, x86_memref memref, UINT8 imm) { emit_shift_mem_imm(emitptr, OP_G2_Eb_1, OP_G2_Eb_Ib, OP_32BIT, 5, memref, imm); } +inline void emit_shr_r8_cl(x86code *&emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G2_Eb_CL, OP_32BIT, 5, dreg); } +inline void emit_shr_m8_cl(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_G2_Eb_CL, OP_32BIT, 5, memref); } + +inline void emit_sar_r8_imm(x86code *&emitptr, UINT8 dreg, UINT8 imm) { emit_shift_reg_imm(emitptr, OP_G2_Eb_1, OP_G2_Eb_Ib, OP_32BIT, 7, dreg, imm); } +inline void emit_sar_m8_imm(x86code *&emitptr, x86_memref memref, UINT8 imm) { emit_shift_mem_imm(emitptr, OP_G2_Eb_1, OP_G2_Eb_Ib, OP_32BIT, 7, memref, imm); } +inline void emit_sar_r8_cl(x86code *&emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G2_Eb_CL, OP_32BIT, 7, dreg); } +inline void emit_sar_m8_cl(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_G2_Eb_CL, OP_32BIT, 7, memref); } + + +//------------------------------------------------- +// emit_shift_r16_* +//------------------------------------------------- + +inline void emit_rol_r16_imm(x86code *&emitptr, UINT8 dreg, UINT8 imm) { emit_shift_reg_imm(emitptr, OP_G2_Ev_1, OP_G2_Ev_Ib, OP_16BIT, 0, dreg, imm); } +inline void emit_rol_m16_imm(x86code *&emitptr, x86_memref memref, UINT8 imm) { emit_shift_mem_imm(emitptr, OP_G2_Ev_1, OP_G2_Ev_Ib, OP_16BIT, 0, memref, imm); } +inline void emit_rol_r16_cl(x86code *&emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G2_Ev_CL, OP_16BIT, 0, dreg); } +inline void emit_rol_m16_cl(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_G2_Ev_CL, OP_16BIT, 0, memref); } + +inline void emit_ror_r16_imm(x86code *&emitptr, UINT8 dreg, UINT8 imm) { emit_shift_reg_imm(emitptr, OP_G2_Ev_1, OP_G2_Ev_Ib, OP_16BIT, 1, dreg, imm); } +inline void emit_ror_m16_imm(x86code *&emitptr, x86_memref memref, UINT8 imm) { emit_shift_mem_imm(emitptr, OP_G2_Ev_1, OP_G2_Ev_Ib, OP_16BIT, 1, memref, imm); } +inline void emit_ror_r16_cl(x86code *&emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G2_Ev_CL, OP_16BIT, 1, dreg); } +inline void emit_ror_m16_cl(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_G2_Ev_CL, OP_16BIT, 1, memref); } + +inline void emit_rcl_r16_imm(x86code *&emitptr, UINT8 dreg, UINT8 imm) { emit_shift_reg_imm(emitptr, OP_G2_Ev_1, OP_G2_Ev_Ib, OP_16BIT, 2, dreg, imm); } +inline void emit_rcl_m16_imm(x86code *&emitptr, x86_memref memref, UINT8 imm) { emit_shift_mem_imm(emitptr, OP_G2_Ev_1, OP_G2_Ev_Ib, OP_16BIT, 2, memref, imm); } +inline void emit_rcl_r16_cl(x86code *&emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G2_Ev_CL, OP_16BIT, 2, dreg); } +inline void emit_rcl_m16_cl(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_G2_Ev_CL, OP_16BIT, 2, memref); } + +inline void emit_rcr_r16_imm(x86code *&emitptr, UINT8 dreg, UINT8 imm) { emit_shift_reg_imm(emitptr, OP_G2_Ev_1, OP_G2_Ev_Ib, OP_16BIT, 3, dreg, imm); } +inline void emit_rcr_m16_imm(x86code *&emitptr, x86_memref memref, UINT8 imm) { emit_shift_mem_imm(emitptr, OP_G2_Ev_1, OP_G2_Ev_Ib, OP_16BIT, 3, memref, imm); } +inline void emit_rcr_r16_cl(x86code *&emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G2_Ev_CL, OP_16BIT, 3, dreg); } +inline void emit_rcr_m16_cl(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_G2_Ev_CL, OP_16BIT, 3, memref); } + +inline void emit_shl_r16_imm(x86code *&emitptr, UINT8 dreg, UINT8 imm) { emit_shift_reg_imm(emitptr, OP_G2_Ev_1, OP_G2_Ev_Ib, OP_16BIT, 4, dreg, imm); } +inline void emit_shl_m16_imm(x86code *&emitptr, x86_memref memref, UINT8 imm) { emit_shift_mem_imm(emitptr, OP_G2_Ev_1, OP_G2_Ev_Ib, OP_16BIT, 4, memref, imm); } +inline void emit_shl_r16_cl(x86code *&emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G2_Ev_CL, OP_16BIT, 4, dreg); } +inline void emit_shl_m16_cl(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_G2_Ev_CL, OP_16BIT, 4, memref); } + +inline void emit_shr_r16_imm(x86code *&emitptr, UINT8 dreg, UINT8 imm) { emit_shift_reg_imm(emitptr, OP_G2_Ev_1, OP_G2_Ev_Ib, OP_16BIT, 5, dreg, imm); } +inline void emit_shr_m16_imm(x86code *&emitptr, x86_memref memref, UINT8 imm) { emit_shift_mem_imm(emitptr, OP_G2_Ev_1, OP_G2_Ev_Ib, OP_16BIT, 5, memref, imm); } +inline void emit_shr_r16_cl(x86code *&emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G2_Ev_CL, OP_16BIT, 5, dreg); } +inline void emit_shr_m16_cl(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_G2_Ev_CL, OP_16BIT, 5, memref); } + +inline void emit_sar_r16_imm(x86code *&emitptr, UINT8 dreg, UINT8 imm) { emit_shift_reg_imm(emitptr, OP_G2_Ev_1, OP_G2_Ev_Ib, OP_16BIT, 7, dreg, imm); } +inline void emit_sar_m16_imm(x86code *&emitptr, x86_memref memref, UINT8 imm) { emit_shift_mem_imm(emitptr, OP_G2_Ev_1, OP_G2_Ev_Ib, OP_16BIT, 7, memref, imm); } +inline void emit_sar_r16_cl(x86code *&emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G2_Ev_CL, OP_16BIT, 7, dreg); } +inline void emit_sar_m16_cl(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_G2_Ev_CL, OP_16BIT, 7, memref); } + + +//------------------------------------------------- +// emit_shift_r32_* +//------------------------------------------------- + +inline void emit_rol_r32_imm(x86code *&emitptr, UINT8 dreg, UINT8 imm) { emit_shift_reg_imm(emitptr, OP_G2_Ev_1, OP_G2_Ev_Ib, OP_32BIT, 0, dreg, imm); } +inline void emit_rol_m32_imm(x86code *&emitptr, x86_memref memref, UINT8 imm) { emit_shift_mem_imm(emitptr, OP_G2_Ev_1, OP_G2_Ev_Ib, OP_32BIT, 0, memref, imm); } +inline void emit_rol_r32_cl(x86code *&emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G2_Ev_CL, OP_32BIT, 0, dreg); } +inline void emit_rol_m32_cl(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_G2_Ev_CL, OP_32BIT, 0, memref); } + +inline void emit_ror_r32_imm(x86code *&emitptr, UINT8 dreg, UINT8 imm) { emit_shift_reg_imm(emitptr, OP_G2_Ev_1, OP_G2_Ev_Ib, OP_32BIT, 1, dreg, imm); } +inline void emit_ror_m32_imm(x86code *&emitptr, x86_memref memref, UINT8 imm) { emit_shift_mem_imm(emitptr, OP_G2_Ev_1, OP_G2_Ev_Ib, OP_32BIT, 1, memref, imm); } +inline void emit_ror_r32_cl(x86code *&emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G2_Ev_CL, OP_32BIT, 1, dreg); } +inline void emit_ror_m32_cl(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_G2_Ev_CL, OP_32BIT, 1, memref); } + +inline void emit_rcl_r32_imm(x86code *&emitptr, UINT8 dreg, UINT8 imm) { emit_shift_reg_imm(emitptr, OP_G2_Ev_1, OP_G2_Ev_Ib, OP_32BIT, 2, dreg, imm); } +inline void emit_rcl_m32_imm(x86code *&emitptr, x86_memref memref, UINT8 imm) { emit_shift_mem_imm(emitptr, OP_G2_Ev_1, OP_G2_Ev_Ib, OP_32BIT, 2, memref, imm); } +inline void emit_rcl_r32_cl(x86code *&emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G2_Ev_CL, OP_32BIT, 2, dreg); } +inline void emit_rcl_m32_cl(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_G2_Ev_CL, OP_32BIT, 2, memref); } + +inline void emit_rcr_r32_imm(x86code *&emitptr, UINT8 dreg, UINT8 imm) { emit_shift_reg_imm(emitptr, OP_G2_Ev_1, OP_G2_Ev_Ib, OP_32BIT, 3, dreg, imm); } +inline void emit_rcr_m32_imm(x86code *&emitptr, x86_memref memref, UINT8 imm) { emit_shift_mem_imm(emitptr, OP_G2_Ev_1, OP_G2_Ev_Ib, OP_32BIT, 3, memref, imm); } +inline void emit_rcr_r32_cl(x86code *&emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G2_Ev_CL, OP_32BIT, 3, dreg); } +inline void emit_rcr_m32_cl(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_G2_Ev_CL, OP_32BIT, 3, memref); } + +inline void emit_shl_r32_imm(x86code *&emitptr, UINT8 dreg, UINT8 imm) { emit_shift_reg_imm(emitptr, OP_G2_Ev_1, OP_G2_Ev_Ib, OP_32BIT, 4, dreg, imm); } +inline void emit_shl_m32_imm(x86code *&emitptr, x86_memref memref, UINT8 imm) { emit_shift_mem_imm(emitptr, OP_G2_Ev_1, OP_G2_Ev_Ib, OP_32BIT, 4, memref, imm); } +inline void emit_shl_r32_cl(x86code *&emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G2_Ev_CL, OP_32BIT, 4, dreg); } +inline void emit_shl_m32_cl(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_G2_Ev_CL, OP_32BIT, 4, memref); } + +inline void emit_shr_r32_imm(x86code *&emitptr, UINT8 dreg, UINT8 imm) { emit_shift_reg_imm(emitptr, OP_G2_Ev_1, OP_G2_Ev_Ib, OP_32BIT, 5, dreg, imm); } +inline void emit_shr_m32_imm(x86code *&emitptr, x86_memref memref, UINT8 imm) { emit_shift_mem_imm(emitptr, OP_G2_Ev_1, OP_G2_Ev_Ib, OP_32BIT, 5, memref, imm); } +inline void emit_shr_r32_cl(x86code *&emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G2_Ev_CL, OP_32BIT, 5, dreg); } +inline void emit_shr_m32_cl(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_G2_Ev_CL, OP_32BIT, 5, memref); } + +inline void emit_sar_r32_imm(x86code *&emitptr, UINT8 dreg, UINT8 imm) { emit_shift_reg_imm(emitptr, OP_G2_Ev_1, OP_G2_Ev_Ib, OP_32BIT, 7, dreg, imm); } +inline void emit_sar_m32_imm(x86code *&emitptr, x86_memref memref, UINT8 imm) { emit_shift_mem_imm(emitptr, OP_G2_Ev_1, OP_G2_Ev_Ib, OP_32BIT, 7, memref, imm); } +inline void emit_sar_r32_cl(x86code *&emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G2_Ev_CL, OP_32BIT, 7, dreg); } +inline void emit_sar_m32_cl(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_G2_Ev_CL, OP_32BIT, 7, memref); } + +inline void emit_shld_r32_r32_imm(x86code *&emitptr, UINT8 dreg, UINT8 sreg, UINT8 imm) { emit_op_modrm_reg_imm8(emitptr, OP_SHLD_Ev_Gv_Ib, OP_32BIT, sreg, dreg, imm); } +inline void emit_shld_m32_r32_imm(x86code *&emitptr, x86_memref memref, UINT8 sreg, UINT8 imm) { emit_op_modrm_mem_imm8(emitptr, OP_SHLD_Ev_Gv_Ib, OP_32BIT, sreg, memref, imm); } +inline void emit_shld_r32_r32_cl(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_SHLD_Ev_Gv_CL, OP_32BIT, sreg, dreg); } +inline void emit_shld_m32_r32_cl(x86code *&emitptr, x86_memref memref, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_SHLD_Ev_Gv_CL, OP_32BIT, sreg, memref); } + +inline void emit_shrd_r32_r32_imm(x86code *&emitptr, UINT8 dreg, UINT8 sreg, UINT8 imm) { emit_op_modrm_reg_imm8(emitptr, OP_SHRD_Ev_Gv_Ib, OP_32BIT, sreg, dreg, imm); } +inline void emit_shrd_m32_r32_imm(x86code *&emitptr, x86_memref memref, UINT8 sreg, UINT8 imm) { emit_op_modrm_mem_imm8(emitptr, OP_SHRD_Ev_Gv_Ib, OP_32BIT, sreg, memref, imm); } +inline void emit_shrd_r32_r32_cl(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_SHRD_Ev_Gv_CL, OP_32BIT, sreg, dreg); } +inline void emit_shrd_m32_r32_cl(x86code *&emitptr, x86_memref memref, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_SHRD_Ev_Gv_CL, OP_32BIT, sreg, memref); } + + +//------------------------------------------------- +// emit_shift_r64_* +//------------------------------------------------- + +#if (X86EMIT_SIZE == 64) + +inline void emit_rol_r64_imm(x86code *&emitptr, UINT8 dreg, UINT8 imm) { emit_shift_reg_imm(emitptr, OP_G2_Ev_1, OP_G2_Ev_Ib, OP_64BIT, 0, dreg, imm); } +inline void emit_rol_m64_imm(x86code *&emitptr, x86_memref memref, UINT8 imm) { emit_shift_mem_imm(emitptr, OP_G2_Ev_1, OP_G2_Ev_Ib, OP_64BIT, 0, memref, imm); } +inline void emit_rol_r64_cl(x86code *&emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G2_Ev_CL, OP_64BIT, 0, dreg); } +inline void emit_rol_m64_cl(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_G2_Ev_CL, OP_64BIT, 0, memref); } + +inline void emit_ror_r64_imm(x86code *&emitptr, UINT8 dreg, UINT8 imm) { emit_shift_reg_imm(emitptr, OP_G2_Ev_1, OP_G2_Ev_Ib, OP_64BIT, 1, dreg, imm); } +inline void emit_ror_m64_imm(x86code *&emitptr, x86_memref memref, UINT8 imm) { emit_shift_mem_imm(emitptr, OP_G2_Ev_1, OP_G2_Ev_Ib, OP_64BIT, 1, memref, imm); } +inline void emit_ror_r64_cl(x86code *&emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G2_Ev_CL, OP_64BIT, 1, dreg); } +inline void emit_ror_m64_cl(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_G2_Ev_CL, OP_64BIT, 1, memref); } + +inline void emit_rcl_r64_imm(x86code *&emitptr, UINT8 dreg, UINT8 imm) { emit_shift_reg_imm(emitptr, OP_G2_Ev_1, OP_G2_Ev_Ib, OP_64BIT, 2, dreg, imm); } +inline void emit_rcl_m64_imm(x86code *&emitptr, x86_memref memref, UINT8 imm) { emit_shift_mem_imm(emitptr, OP_G2_Ev_1, OP_G2_Ev_Ib, OP_64BIT, 2, memref, imm); } +inline void emit_rcl_r64_cl(x86code *&emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G2_Ev_CL, OP_64BIT, 2, dreg); } +inline void emit_rcl_m64_cl(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_G2_Ev_CL, OP_64BIT, 2, memref); } + +inline void emit_rcr_r64_imm(x86code *&emitptr, UINT8 dreg, UINT8 imm) { emit_shift_reg_imm(emitptr, OP_G2_Ev_1, OP_G2_Ev_Ib, OP_64BIT, 3, dreg, imm); } +inline void emit_rcr_m64_imm(x86code *&emitptr, x86_memref memref, UINT8 imm) { emit_shift_mem_imm(emitptr, OP_G2_Ev_1, OP_G2_Ev_Ib, OP_64BIT, 3, memref, imm); } +inline void emit_rcr_r64_cl(x86code *&emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G2_Ev_CL, OP_64BIT, 3, dreg); } +inline void emit_rcr_m64_cl(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_G2_Ev_CL, OP_64BIT, 3, memref); } + +inline void emit_shl_r64_imm(x86code *&emitptr, UINT8 dreg, UINT8 imm) { emit_shift_reg_imm(emitptr, OP_G2_Ev_1, OP_G2_Ev_Ib, OP_64BIT, 4, dreg, imm); } +inline void emit_shl_m64_imm(x86code *&emitptr, x86_memref memref, UINT8 imm) { emit_shift_mem_imm(emitptr, OP_G2_Ev_1, OP_G2_Ev_Ib, OP_64BIT, 4, memref, imm); } +inline void emit_shl_r64_cl(x86code *&emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G2_Ev_CL, OP_64BIT, 4, dreg); } +inline void emit_shl_m64_cl(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_G2_Ev_CL, OP_64BIT, 4, memref); } + +inline void emit_shr_r64_imm(x86code *&emitptr, UINT8 dreg, UINT8 imm) { emit_shift_reg_imm(emitptr, OP_G2_Ev_1, OP_G2_Ev_Ib, OP_64BIT, 5, dreg, imm); } +inline void emit_shr_m64_imm(x86code *&emitptr, x86_memref memref, UINT8 imm) { emit_shift_mem_imm(emitptr, OP_G2_Ev_1, OP_G2_Ev_Ib, OP_64BIT, 5, memref, imm); } +inline void emit_shr_r64_cl(x86code *&emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G2_Ev_CL, OP_64BIT, 5, dreg); } +inline void emit_shr_m64_cl(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_G2_Ev_CL, OP_64BIT, 5, memref); } + +inline void emit_sar_r64_imm(x86code *&emitptr, UINT8 dreg, UINT8 imm) { emit_shift_reg_imm(emitptr, OP_G2_Ev_1, OP_G2_Ev_Ib, OP_64BIT, 7, dreg, imm); } +inline void emit_sar_m64_imm(x86code *&emitptr, x86_memref memref, UINT8 imm) { emit_shift_mem_imm(emitptr, OP_G2_Ev_1, OP_G2_Ev_Ib, OP_64BIT, 7, memref, imm); } +inline void emit_sar_r64_cl(x86code *&emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G2_Ev_CL, OP_64BIT, 7, dreg); } +inline void emit_sar_m64_cl(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_G2_Ev_CL, OP_64BIT, 7, memref); } + +inline void emit_shld_r64_r64_imm(x86code *&emitptr, UINT8 dreg, UINT8 sreg, UINT8 imm) { emit_op_modrm_reg_imm8(emitptr, OP_SHLD_Ev_Gv_Ib, OP_64BIT, sreg, dreg, imm); } +inline void emit_shld_m64_r64_imm(x86code *&emitptr, x86_memref memref, UINT8 sreg, UINT8 imm) { emit_op_modrm_mem_imm8(emitptr, OP_SHLD_Ev_Gv_Ib, OP_64BIT, sreg, memref, imm); } +inline void emit_shld_r64_r64_cl(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_SHLD_Ev_Gv_CL, OP_64BIT, sreg, dreg); } +inline void emit_shld_m64_r64_cl(x86code *&emitptr, x86_memref memref, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_SHLD_Ev_Gv_CL, OP_64BIT, sreg, memref); } + +inline void emit_shrd_r64_r64_imm(x86code *&emitptr, UINT8 dreg, UINT8 sreg, UINT8 imm) { emit_op_modrm_reg_imm8(emitptr, OP_SHRD_Ev_Gv_Ib, OP_64BIT, sreg, dreg, imm); } +inline void emit_shrd_m64_r64_imm(x86code *&emitptr, x86_memref memref, UINT8 sreg, UINT8 imm) { emit_op_modrm_mem_imm8(emitptr, OP_SHRD_Ev_Gv_Ib, OP_64BIT, sreg, memref, imm); } +inline void emit_shrd_r64_r64_cl(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_SHRD_Ev_Gv_CL, OP_64BIT, sreg, dreg); } +inline void emit_shrd_m64_r64_cl(x86code *&emitptr, x86_memref memref, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_SHRD_Ev_Gv_CL, OP_64BIT, sreg, memref); } + +#endif + + + +//************************************************************************** +// GROUP3 EMITTERS +//************************************************************************** + +//------------------------------------------------- +// emit_group3_r8_* +//------------------------------------------------- + +inline void emit_not_r8(x86code *&emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G3_Ev, OP_32BIT, 2, dreg); } +inline void emit_not_m8(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_G3_Ev, OP_32BIT, 2, memref); } + +inline void emit_neg_r8(x86code *&emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G3_Ev, OP_32BIT, 3, dreg); } +inline void emit_neg_m8(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_G3_Ev, OP_32BIT, 3, memref); } + +inline void emit_mul_r8(x86code *&emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G3_Ev, OP_32BIT, 4, dreg); } +inline void emit_mul_m8(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_G3_Ev, OP_32BIT, 4, memref); } + +inline void emit_imul_r8(x86code *&emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G3_Ev, OP_32BIT, 5, dreg); } +inline void emit_imul_m8(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_G3_Ev, OP_32BIT, 5, memref); } + +inline void emit_div_r8(x86code *&emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G3_Ev, OP_32BIT, 6, dreg); } +inline void emit_div_m8(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_G3_Ev, OP_32BIT, 6, memref); } + +inline void emit_idiv_r8(x86code *&emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G3_Ev, OP_32BIT, 7, dreg); } +inline void emit_idiv_m8(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_G3_Ev, OP_32BIT, 7, memref); } + + +//------------------------------------------------- +// emit_group3_r16_* +//------------------------------------------------- + +inline void emit_not_r16(x86code *&emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G3_Ev, OP_16BIT, 2, dreg); } +inline void emit_not_m16(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_G3_Ev, OP_16BIT, 2, memref); } + +inline void emit_neg_r16(x86code *&emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G3_Ev, OP_16BIT, 3, dreg); } +inline void emit_neg_m16(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_G3_Ev, OP_16BIT, 3, memref); } + +inline void emit_mul_r16(x86code *&emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G3_Ev, OP_16BIT, 4, dreg); } +inline void emit_mul_m16(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_G3_Ev, OP_16BIT, 4, memref); } + +inline void emit_imul_r16(x86code *&emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G3_Ev, OP_16BIT, 5, dreg); } +inline void emit_imul_m16(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_G3_Ev, OP_16BIT, 5, memref); } + +inline void emit_div_r16(x86code *&emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G3_Ev, OP_16BIT, 6, dreg); } +inline void emit_div_m16(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_G3_Ev, OP_16BIT, 6, memref); } + +inline void emit_idiv_r16(x86code *&emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G3_Ev, OP_16BIT, 7, dreg); } +inline void emit_idiv_m16(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_G3_Ev, OP_16BIT, 7, memref); } + + +//------------------------------------------------- +// emit_group3_r32_* +//------------------------------------------------- + +inline void emit_not_r32(x86code *&emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G3_Ev, OP_32BIT, 2, dreg); } +inline void emit_not_m32(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_G3_Ev, OP_32BIT, 2, memref); } + +inline void emit_neg_r32(x86code *&emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G3_Ev, OP_32BIT, 3, dreg); } +inline void emit_neg_m32(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_G3_Ev, OP_32BIT, 3, memref); } + +inline void emit_mul_r32(x86code *&emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G3_Ev, OP_32BIT, 4, dreg); } +inline void emit_mul_m32(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_G3_Ev, OP_32BIT, 4, memref); } + +inline void emit_imul_r32(x86code *&emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G3_Ev, OP_32BIT, 5, dreg); } +inline void emit_imul_m32(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_G3_Ev, OP_32BIT, 5, memref); } + +inline void emit_div_r32(x86code *&emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G3_Ev, OP_32BIT, 6, dreg); } +inline void emit_div_m32(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_G3_Ev, OP_32BIT, 6, memref); } + +inline void emit_idiv_r32(x86code *&emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G3_Ev, OP_32BIT, 7, dreg); } +inline void emit_idiv_m32(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_G3_Ev, OP_32BIT, 7, memref); } + + +//------------------------------------------------- +// emit_group3_r64_* +//------------------------------------------------- + +#if (X86EMIT_SIZE == 64) + +inline void emit_not_r64(x86code *&emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G3_Ev, OP_64BIT, 2, dreg); } +inline void emit_not_m64(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_G3_Ev, OP_64BIT, 2, memref); } + +inline void emit_neg_r64(x86code *&emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G3_Ev, OP_64BIT, 3, dreg); } +inline void emit_neg_m64(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_G3_Ev, OP_64BIT, 3, memref); } + +inline void emit_mul_r64(x86code *&emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G3_Ev, OP_64BIT, 4, dreg); } +inline void emit_mul_m64(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_G3_Ev, OP_64BIT, 4, memref); } + +inline void emit_imul_r64(x86code *&emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G3_Ev, OP_64BIT, 5, dreg); } +inline void emit_imul_m64(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_G3_Ev, OP_64BIT, 5, memref); } + +inline void emit_div_r64(x86code *&emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G3_Ev, OP_64BIT, 6, dreg); } +inline void emit_div_m64(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_G3_Ev, OP_64BIT, 6, memref); } + +inline void emit_idiv_r64(x86code *&emitptr, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_G3_Ev, OP_64BIT, 7, dreg); } +inline void emit_idiv_m64(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_G3_Ev, OP_64BIT, 7, memref); } + +#endif + + + +//************************************************************************** +// IMUL EMITTERS +//************************************************************************** + +//------------------------------------------------- +// emit_imul_r16_* +//------------------------------------------------- + +inline void emit_imul_r16_r16(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_IMUL_Gv_Ev, OP_16BIT, dreg, sreg); } +inline void emit_imul_r16_m16(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_IMUL_Gv_Ev, OP_16BIT, dreg, memref); } +inline void emit_imul_r16_r16_imm(x86code *&emitptr, UINT8 dreg, UINT8 sreg, INT16 imm) { emit_op_modrm_reg_imm816(emitptr, OP_IMUL_Gv_Ev_Ib, OP_IMUL_Gv_Ev_Iz, OP_16BIT, dreg, sreg, imm); } +inline void emit_imul_r16_m16_imm(x86code *&emitptr, UINT8 dreg, x86_memref memref, INT16 imm) { emit_op_modrm_mem_imm816(emitptr, OP_IMUL_Gv_Ev_Ib, OP_IMUL_Gv_Ev_Iz, OP_16BIT, dreg, memref, imm); } + +inline void emit_imul_r32_r32(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_IMUL_Gv_Ev, OP_32BIT, dreg, sreg); } +inline void emit_imul_r32_m32(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_IMUL_Gv_Ev, OP_32BIT, dreg, memref); } +inline void emit_imul_r32_r32_imm(x86code *&emitptr, UINT8 dreg, UINT8 sreg, INT32 imm) { emit_op_modrm_reg_imm832(emitptr, OP_IMUL_Gv_Ev_Ib, OP_IMUL_Gv_Ev_Iz, OP_32BIT, dreg, sreg, imm); } +inline void emit_imul_r32_m32_imm(x86code *&emitptr, UINT8 dreg, x86_memref memref, INT32 imm) { emit_op_modrm_mem_imm832(emitptr, OP_IMUL_Gv_Ev_Ib, OP_IMUL_Gv_Ev_Iz, OP_32BIT, dreg, memref, imm); } + +#if (X86EMIT_SIZE == 64) + +inline void emit_imul_r64_r64(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_IMUL_Gv_Ev, OP_64BIT, dreg, sreg); } +inline void emit_imul_r64_m64(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_IMUL_Gv_Ev, OP_64BIT, dreg, memref); } +inline void emit_imul_r64_r64_imm(x86code *&emitptr, UINT8 dreg, UINT8 sreg, INT32 imm) { emit_op_modrm_reg_imm832(emitptr, OP_IMUL_Gv_Ev_Ib, OP_IMUL_Gv_Ev_Iz, OP_64BIT, dreg, sreg, imm); } +inline void emit_imul_r64_m64_imm(x86code *&emitptr, UINT8 dreg, x86_memref memref, INT32 imm) { emit_op_modrm_mem_imm832(emitptr, OP_IMUL_Gv_Ev_Ib, OP_IMUL_Gv_Ev_Iz, OP_64BIT, dreg, memref, imm); } + +#endif + + + +//************************************************************************** +// BIT OPERATION EMITTERS +//************************************************************************** + +//------------------------------------------------- +// emit_bswap_* +//------------------------------------------------- + +inline void emit_bswap_r32(x86code *&emitptr, UINT8 dreg) { emit_op_reg(emitptr, OP_BSWAP_EAX + (dreg & 7), OP_32BIT, dreg); } +inline void emit_bswap_r64(x86code *&emitptr, UINT8 dreg) { emit_op_reg(emitptr, OP_BSWAP_EAX + (dreg & 7), OP_64BIT, dreg); } + + +//------------------------------------------------- +// emit_bsr/bsf_r16_* +//------------------------------------------------- + +inline void emit_bsf_r16_r16(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_BSF_Gv_Ev, OP_16BIT, dreg, sreg); } +inline void emit_bsf_r16_m16(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_BSF_Gv_Ev, OP_16BIT, dreg, memref); } +inline void emit_bsr_r16_r16(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_BSR_Gv_Ev, OP_16BIT, dreg, sreg); } +inline void emit_bsr_r16_m16(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_BSR_Gv_Ev, OP_16BIT, dreg, memref); } + +inline void emit_bsf_r32_r32(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_BSF_Gv_Ev, OP_32BIT, dreg, sreg); } +inline void emit_bsf_r32_m32(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_BSF_Gv_Ev, OP_32BIT, dreg, memref); } +inline void emit_bsr_r32_r32(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_BSR_Gv_Ev, OP_32BIT, dreg, sreg); } +inline void emit_bsr_r32_m32(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_BSR_Gv_Ev, OP_32BIT, dreg, memref); } + +#if (X86EMIT_SIZE == 64) +inline void emit_bsf_r64_r64(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_BSF_Gv_Ev, OP_64BIT, dreg, sreg); } +inline void emit_bsf_r64_m64(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_BSF_Gv_Ev, OP_64BIT, dreg, memref); } +inline void emit_bsr_r64_r64(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_BSR_Gv_Ev, OP_64BIT, dreg, sreg); } +inline void emit_bsr_r64_m64(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_BSR_Gv_Ev, OP_64BIT, dreg, memref); } +#endif + + +//------------------------------------------------- +// emit_bit_r16_* +//------------------------------------------------- + +inline void emit_bt_r16_r16(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_BT_Ev_Gv, OP_16BIT, sreg, dreg); } +inline void emit_bt_m16_r16(x86code *&emitptr, x86_memref memref, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_BT_Ev_Gv, OP_16BIT, sreg, memref); } +inline void emit_bt_r16_imm(x86code *&emitptr, UINT8 dreg, UINT8 imm) { emit_op_modrm_reg_imm8(emitptr, OP_G8_Ev_Ib, OP_16BIT, 4, dreg, imm); } +inline void emit_bt_m16_imm(x86code *&emitptr, x86_memref memref, UINT8 imm) { emit_op_modrm_mem_imm8(emitptr, OP_G8_Ev_Ib, OP_16BIT, 4, memref, imm); } + +inline void emit_bts_r16_r16(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_BTS_Ev_Gv, OP_16BIT, sreg, dreg); } +inline void emit_bts_m16_r16(x86code *&emitptr, x86_memref memref, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_BTS_Ev_Gv, OP_16BIT, sreg, memref); } +inline void emit_bts_r16_imm(x86code *&emitptr, UINT8 dreg, UINT8 imm) { emit_op_modrm_reg_imm8(emitptr, OP_G8_Ev_Ib, OP_16BIT, 5, dreg, imm); } +inline void emit_bts_m16_imm(x86code *&emitptr, x86_memref memref, UINT8 imm) { emit_op_modrm_mem_imm8(emitptr, OP_G8_Ev_Ib, OP_16BIT, 5, memref, imm); } + +inline void emit_btr_r16_r16(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_BTR_Ev_Gv, OP_16BIT, sreg, dreg); } +inline void emit_btr_m16_r16(x86code *&emitptr, x86_memref memref, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_BTR_Ev_Gv, OP_16BIT, sreg, memref); } +inline void emit_btr_r16_imm(x86code *&emitptr, UINT8 dreg, UINT8 imm) { emit_op_modrm_reg_imm8(emitptr, OP_G8_Ev_Ib, OP_16BIT, 6, dreg, imm); } +inline void emit_btr_m16_imm(x86code *&emitptr, x86_memref memref, UINT8 imm) { emit_op_modrm_mem_imm8(emitptr, OP_G8_Ev_Ib, OP_16BIT, 6, memref, imm); } + +inline void emit_btc_r16_r16(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_BTC_Ev_Gv, OP_16BIT, sreg, dreg); } +inline void emit_btc_m16_r16(x86code *&emitptr, x86_memref memref, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_BTC_Ev_Gv, OP_16BIT, sreg, memref); } +inline void emit_btc_r16_imm(x86code *&emitptr, UINT8 dreg, UINT8 imm) { emit_op_modrm_reg_imm8(emitptr, OP_G8_Ev_Ib, OP_16BIT, 7, dreg, imm); } +inline void emit_btc_m16_imm(x86code *&emitptr, x86_memref memref, UINT8 imm) { emit_op_modrm_mem_imm8(emitptr, OP_G8_Ev_Ib, OP_16BIT, 7, memref, imm); } + + +//------------------------------------------------- +// emit_bit_r32_* +//------------------------------------------------- + +inline void emit_bt_r32_r32(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_BT_Ev_Gv, OP_32BIT, sreg, dreg); } +inline void emit_bt_m32_r32(x86code *&emitptr, x86_memref memref, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_BT_Ev_Gv, OP_32BIT, sreg, memref); } +inline void emit_bt_r32_imm(x86code *&emitptr, UINT8 dreg, UINT8 imm) { emit_op_modrm_reg_imm8(emitptr, OP_G8_Ev_Ib, OP_32BIT, 4, dreg, imm); } +inline void emit_bt_m32_imm(x86code *&emitptr, x86_memref memref, UINT8 imm) { emit_op_modrm_mem_imm8(emitptr, OP_G8_Ev_Ib, OP_32BIT, 4, memref, imm); } + +inline void emit_bts_r32_r32(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_BTS_Ev_Gv, OP_32BIT, sreg, dreg); } +inline void emit_bts_m32_r32(x86code *&emitptr, x86_memref memref, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_BTS_Ev_Gv, OP_32BIT, sreg, memref); } +inline void emit_bts_r32_imm(x86code *&emitptr, UINT8 dreg, UINT8 imm) { emit_op_modrm_reg_imm8(emitptr, OP_G8_Ev_Ib, OP_32BIT, 5, dreg, imm); } +inline void emit_bts_m32_imm(x86code *&emitptr, x86_memref memref, UINT8 imm) { emit_op_modrm_mem_imm8(emitptr, OP_G8_Ev_Ib, OP_32BIT, 5, memref, imm); } + +inline void emit_btr_r32_r32(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_BTR_Ev_Gv, OP_32BIT, sreg, dreg); } +inline void emit_btr_m32_r32(x86code *&emitptr, x86_memref memref, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_BTR_Ev_Gv, OP_32BIT, sreg, memref); } +inline void emit_btr_r32_imm(x86code *&emitptr, UINT8 dreg, UINT8 imm) { emit_op_modrm_reg_imm8(emitptr, OP_G8_Ev_Ib, OP_32BIT, 6, dreg, imm); } +inline void emit_btr_m32_imm(x86code *&emitptr, x86_memref memref, UINT8 imm) { emit_op_modrm_mem_imm8(emitptr, OP_G8_Ev_Ib, OP_32BIT, 6, memref, imm); } + +inline void emit_btc_r32_r32(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_BTC_Ev_Gv, OP_32BIT, sreg, dreg); } +inline void emit_btc_m32_r32(x86code *&emitptr, x86_memref memref, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_BTC_Ev_Gv, OP_32BIT, sreg, memref); } +inline void emit_btc_r32_imm(x86code *&emitptr, UINT8 dreg, UINT8 imm) { emit_op_modrm_reg_imm8(emitptr, OP_G8_Ev_Ib, OP_32BIT, 7, dreg, imm); } +inline void emit_btc_m32_imm(x86code *&emitptr, x86_memref memref, UINT8 imm) { emit_op_modrm_mem_imm8(emitptr, OP_G8_Ev_Ib, OP_32BIT, 7, memref, imm); } + + +//------------------------------------------------- +// emit_bit_r64_* +//------------------------------------------------- + +#if (X86EMIT_SIZE == 64) + +inline void emit_bt_r64_r64(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_BT_Ev_Gv, OP_64BIT, sreg, dreg); } +inline void emit_bt_m64_r64(x86code *&emitptr, x86_memref memref, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_BT_Ev_Gv, OP_64BIT, sreg, memref); } +inline void emit_bt_r64_imm(x86code *&emitptr, UINT8 dreg, UINT8 imm) { emit_op_modrm_reg_imm8(emitptr, OP_G8_Ev_Ib, OP_64BIT, 4, dreg, imm); } +inline void emit_bt_m64_imm(x86code *&emitptr, x86_memref memref, UINT8 imm) { emit_op_modrm_mem_imm8(emitptr, OP_G8_Ev_Ib, OP_64BIT, 4, memref, imm); } + +inline void emit_bts_r64_r64(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_BTS_Ev_Gv, OP_64BIT, sreg, dreg); } +inline void emit_bts_m64_r64(x86code *&emitptr, x86_memref memref, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_BTS_Ev_Gv, OP_64BIT, sreg, memref); } +inline void emit_bts_r64_imm(x86code *&emitptr, UINT8 dreg, UINT8 imm) { emit_op_modrm_reg_imm8(emitptr, OP_G8_Ev_Ib, OP_64BIT, 5, dreg, imm); } +inline void emit_bts_m64_imm(x86code *&emitptr, x86_memref memref, UINT8 imm) { emit_op_modrm_mem_imm8(emitptr, OP_G8_Ev_Ib, OP_64BIT, 5, memref, imm); } + +inline void emit_btr_r64_r64(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_BTR_Ev_Gv, OP_64BIT, sreg, dreg); } +inline void emit_btr_m64_r64(x86code *&emitptr, x86_memref memref, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_BTR_Ev_Gv, OP_64BIT, sreg, memref); } +inline void emit_btr_r64_imm(x86code *&emitptr, UINT8 dreg, UINT8 imm) { emit_op_modrm_reg_imm8(emitptr, OP_G8_Ev_Ib, OP_64BIT, 6, dreg, imm); } +inline void emit_btr_m64_imm(x86code *&emitptr, x86_memref memref, UINT8 imm) { emit_op_modrm_mem_imm8(emitptr, OP_G8_Ev_Ib, OP_64BIT, 6, memref, imm); } + +inline void emit_btc_r64_r64(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_BTC_Ev_Gv, OP_64BIT, sreg, dreg); } +inline void emit_btc_m64_r64(x86code *&emitptr, x86_memref memref, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_BTC_Ev_Gv, OP_64BIT, sreg, memref); } +inline void emit_btc_r64_imm(x86code *&emitptr, UINT8 dreg, UINT8 imm) { emit_op_modrm_reg_imm8(emitptr, OP_G8_Ev_Ib, OP_64BIT, 7, dreg, imm); } +inline void emit_btc_m64_imm(x86code *&emitptr, x86_memref memref, UINT8 imm) { emit_op_modrm_mem_imm8(emitptr, OP_G8_Ev_Ib, OP_64BIT, 7, memref, imm); } + +#endif + + + +//************************************************************************** +// LEA EMITTERS +//************************************************************************** + +inline void emit_lea_r32_m32(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_LEA_Gv_M, OP_32BIT, dreg, memref); } + +#if (X86EMIT_SIZE == 64) +inline void emit_lea_r64_m64(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_LEA_Gv_M, OP_64BIT, dreg, memref); } +#endif + + + +//************************************************************************** +// SET EMITTERS +//************************************************************************** + +//------------------------------------------------- +// emit_setcc_* +//------------------------------------------------- + +inline void emit_setcc_r8(x86code *&emitptr, UINT8 cond, UINT8 dreg) { emit_op_modrm_reg(emitptr, OP_SETCC_O_Eb + cond, OP_32BIT, 0, dreg); } +inline void emit_setcc_m8(x86code *&emitptr, UINT8 cond, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_SETCC_O_Eb + cond, OP_32BIT, 0, memref); } + + + +//************************************************************************** +// SIMPLE FPU EMITTERS +//************************************************************************** + +#if (X86EMIT_SIZE == 32) + +inline void emit_fnop(x86code *&emitptr) { emit_op_simple(emitptr, OP_FNOP, OP_32BIT); } +inline void emit_fchs(x86code *&emitptr) { emit_op_simple(emitptr, OP_FCHS, OP_32BIT); } +inline void emit_fabs(x86code *&emitptr) { emit_op_simple(emitptr, OP_FABS, OP_32BIT); } +inline void emit_ftst(x86code *&emitptr) { emit_op_simple(emitptr, OP_FTST, OP_32BIT); } +inline void emit_fxam(x86code *&emitptr) { emit_op_simple(emitptr, OP_FXAM, OP_32BIT); } +inline void emit_fld1(x86code *&emitptr) { emit_op_simple(emitptr, OP_FLD1, OP_32BIT); } +inline void emit_fldl2t(x86code *&emitptr) { emit_op_simple(emitptr, OP_FLDL2T, OP_32BIT); } +inline void emit_fldl2e(x86code *&emitptr) { emit_op_simple(emitptr, OP_FLDL2E, OP_32BIT); } +inline void emit_fldpi(x86code *&emitptr) { emit_op_simple(emitptr, OP_FLDPI, OP_32BIT); } +inline void emit_fldlg2(x86code *&emitptr) { emit_op_simple(emitptr, OP_FLDLG2, OP_32BIT); } +inline void emit_fldln2(x86code *&emitptr) { emit_op_simple(emitptr, OP_FLDLN2, OP_32BIT); } +inline void emit_fldz(x86code *&emitptr) { emit_op_simple(emitptr, OP_FLDZ, OP_32BIT); } +inline void emit_f2xm1(x86code *&emitptr) { emit_op_simple(emitptr, OP_F2XM1, OP_32BIT); } +inline void emit_fyl2x(x86code *&emitptr) { emit_op_simple(emitptr, OP_FYL2X, OP_32BIT); } +inline void emit_fptan(x86code *&emitptr) { emit_op_simple(emitptr, OP_FPTAN, OP_32BIT); } +inline void emit_fpatan(x86code *&emitptr) { emit_op_simple(emitptr, OP_FPATAN, OP_32BIT); } +inline void emit_fxtract(x86code *&emitptr) { emit_op_simple(emitptr, OP_FXTRACT, OP_32BIT); } +inline void emit_fprem1(x86code *&emitptr) { emit_op_simple(emitptr, OP_FPREM1, OP_32BIT); } +inline void emit_fdecstp(x86code *&emitptr) { emit_op_simple(emitptr, OP_FDECSTP, OP_32BIT); } +inline void emit_fincstp(x86code *&emitptr) { emit_op_simple(emitptr, OP_FINCSTP, OP_32BIT); } +inline void emit_fprem(x86code *&emitptr) { emit_op_simple(emitptr, OP_FPREM, OP_32BIT); } +inline void emit_fyl2xp1(x86code *&emitptr) { emit_op_simple(emitptr, OP_FYL2XP1, OP_32BIT); } +inline void emit_fsqrt(x86code *&emitptr) { emit_op_simple(emitptr, OP_FSQRT, OP_32BIT); } +inline void emit_fsincos(x86code *&emitptr) { emit_op_simple(emitptr, OP_FSINCOS, OP_32BIT); } +inline void emit_frndint(x86code *&emitptr) { emit_op_simple(emitptr, OP_FRNDINT, OP_32BIT); } +inline void emit_fscale(x86code *&emitptr) { emit_op_simple(emitptr, OP_FSCALE, OP_32BIT); } +inline void emit_fsin(x86code *&emitptr) { emit_op_simple(emitptr, OP_FSIN, OP_32BIT); } +inline void emit_fcos(x86code *&emitptr) { emit_op_simple(emitptr, OP_FCOS, OP_32BIT); } +inline void emit_fucompp(x86code *&emitptr) { emit_op_simple(emitptr, OP_FUCOMPP, OP_32BIT); } +inline void emit_fclex(x86code *&emitptr) { emit_op_simple(emitptr, OP_FCLEX, OP_32BIT); } +inline void emit_finit(x86code *&emitptr) { emit_op_simple(emitptr, OP_FINIT, OP_32BIT); } +inline void emit_fcompp(x86code *&emitptr) { emit_op_simple(emitptr, OP_FCOMPP, OP_32BIT); } +inline void emit_fstsw_ax(x86code *&emitptr) { emit_op_simple(emitptr, OP_FSTSW_AX, OP_32BIT); } + +#endif + + + +//************************************************************************** +// REGISTER-BASED FPU EMITTERS +//************************************************************************** + +#if (X86EMIT_SIZE == 32) + +inline void emit_ffree_stn(x86code *&emitptr, UINT8 reg) { emit_op_simple(emitptr, OP_FFREE_STn + reg, OP_32BIT); } +inline void emit_fst_stn(x86code *&emitptr, UINT8 reg) { emit_op_simple(emitptr, OP_FST_STn + reg, OP_32BIT); } +inline void emit_fstp_stn(x86code *&emitptr, UINT8 reg) { emit_op_simple(emitptr, OP_FSTP_STn + reg, OP_32BIT); } +inline void emit_fucomp_stn(x86code *&emitptr, UINT8 reg) { emit_op_simple(emitptr, OP_FUCOMP_STn + reg, OP_32BIT); } + +inline void emit_fadd_st0_stn(x86code *&emitptr, UINT8 reg) { emit_op_simple(emitptr, OP_FADD_ST0_STn + reg, OP_32BIT); } +inline void emit_fmul_st0_stn(x86code *&emitptr, UINT8 reg) { emit_op_simple(emitptr, OP_FMUL_ST0_STn + reg, OP_32BIT); } +inline void emit_fcom_st0_stn(x86code *&emitptr, UINT8 reg) { emit_op_simple(emitptr, OP_FCOM_ST0_STn + reg, OP_32BIT); } +inline void emit_fcomp_st0_stn(x86code *&emitptr, UINT8 reg) { emit_op_simple(emitptr, OP_FCOMP_ST0_STn + reg, OP_32BIT); } +inline void emit_fsub_st0_stn(x86code *&emitptr, UINT8 reg) { emit_op_simple(emitptr, OP_FSUB_ST0_STn + reg, OP_32BIT); } +inline void emit_fsubr_st0_stn(x86code *&emitptr, UINT8 reg) { emit_op_simple(emitptr, OP_FSUBR_ST0_STn + reg, OP_32BIT); } +inline void emit_fdiv_st0_stn(x86code *&emitptr, UINT8 reg) { emit_op_simple(emitptr, OP_FDIV_ST0_STn + reg, OP_32BIT); } +inline void emit_fdivr_st0_stn(x86code *&emitptr, UINT8 reg) { emit_op_simple(emitptr, OP_FDIVR_ST0_STn + reg, OP_32BIT); } +inline void emit_fld_st0_stn(x86code *&emitptr, UINT8 reg) { emit_op_simple(emitptr, OP_FLD_ST0_STn + reg, OP_32BIT); } +inline void emit_fxch_st0_stn(x86code *&emitptr, UINT8 reg) { emit_op_simple(emitptr, OP_FXCH_ST0_STn + reg, OP_32BIT); } +inline void emit_fcmovb_st0_stn(x86code *&emitptr, UINT8 reg) { emit_op_simple(emitptr, OP_FCMOVB_ST0_STn + reg, OP_32BIT); } +inline void emit_fcmove_st0_stn(x86code *&emitptr, UINT8 reg) { emit_op_simple(emitptr, OP_FCMOVE_ST0_STn + reg, OP_32BIT); } +inline void emit_fcmovbe_st0_stn(x86code *&emitptr, UINT8 reg) { emit_op_simple(emitptr, OP_FCMOVBE_ST0_STn + reg, OP_32BIT); } +inline void emit_fcmovu_st0_stn(x86code *&emitptr, UINT8 reg) { emit_op_simple(emitptr, OP_FCMOVU_ST0_STn + reg, OP_32BIT); } +inline void emit_fcmovnb_st0_stn(x86code *&emitptr, UINT8 reg) { emit_op_simple(emitptr, OP_FCMOVNB_ST0_STn + reg, OP_32BIT); } +inline void emit_fcmovne_st0_stn(x86code *&emitptr, UINT8 reg) { emit_op_simple(emitptr, OP_FCMOVNE_ST0_STn + reg, OP_32BIT); } +inline void emit_fcmovnbe_st0_stn(x86code *&emitptr, UINT8 reg) { emit_op_simple(emitptr, OP_FCMOVNBE_ST0_STn + reg, OP_32BIT); } +inline void emit_fcmovnu_st0_stn(x86code *&emitptr, UINT8 reg) { emit_op_simple(emitptr, OP_FCMOVNU_ST0_STn + reg, OP_32BIT); } +inline void emit_fucomi_st0_stn(x86code *&emitptr, UINT8 reg) { emit_op_simple(emitptr, OP_FUCOMI_ST0_STn + reg, OP_32BIT); } +inline void emit_fcomi_st0_stn(x86code *&emitptr, UINT8 reg) { emit_op_simple(emitptr, OP_FCOMI_ST0_STn + reg, OP_32BIT); } +inline void emit_fcomip_st0_stn(x86code *&emitptr, UINT8 reg) { emit_op_simple(emitptr, OP_FCOMIP_ST0_STn + reg, OP_32BIT); } + +inline void emit_fadd_stn_st0(x86code *&emitptr, UINT8 reg) { emit_op_simple(emitptr, OP_FADD_STn_ST0 + reg, OP_32BIT); } +inline void emit_fmul_stn_st0(x86code *&emitptr, UINT8 reg) { emit_op_simple(emitptr, OP_FMUL_STn_ST0 + reg, OP_32BIT); } +inline void emit_fsubr_stn_st0(x86code *&emitptr, UINT8 reg) { emit_op_simple(emitptr, OP_FSUBR_STn_ST0 + reg, OP_32BIT); } +inline void emit_fsub_stn_st0(x86code *&emitptr, UINT8 reg) { emit_op_simple(emitptr, OP_FSUB_STn_ST0 + reg, OP_32BIT); } +inline void emit_fdivr_stn_st0(x86code *&emitptr, UINT8 reg) { emit_op_simple(emitptr, OP_FDIVR_STn_ST0 + reg, OP_32BIT); } +inline void emit_fdiv_stn_st0(x86code *&emitptr, UINT8 reg) { emit_op_simple(emitptr, OP_FDIV_STn_ST0 + reg, OP_32BIT); } +inline void emit_fucom_stn_st0(x86code *&emitptr, UINT8 reg) { emit_op_simple(emitptr, OP_FUCOM_STn_ST0 + reg, OP_32BIT); } +inline void emit_faddp_stn_st0(x86code *&emitptr, UINT8 reg) { emit_op_simple(emitptr, OP_FADDP_STn_ST0 + reg, OP_32BIT); } +inline void emit_fmulp_stn_st0(x86code *&emitptr, UINT8 reg) { emit_op_simple(emitptr, OP_FMULP_STn_ST0 + reg, OP_32BIT); } +inline void emit_fsubrp_stn_st0(x86code *&emitptr, UINT8 reg) { emit_op_simple(emitptr, OP_FSUBRP_STn_ST0 + reg, OP_32BIT); } +inline void emit_fsubp_stn_st0(x86code *&emitptr, UINT8 reg) { emit_op_simple(emitptr, OP_FSUBP_STn_ST0 + reg, OP_32BIT); } +inline void emit_fdivrp_stn_st0(x86code *&emitptr, UINT8 reg) { emit_op_simple(emitptr, OP_FDIVRP_STn_ST0 + reg, OP_32BIT); } +inline void emit_fdivp_stn_st0(x86code *&emitptr, UINT8 reg) { emit_op_simple(emitptr, OP_FDIVP_STn_ST0 + reg, OP_32BIT); } + +inline void emit_faddp(x86code *&emitptr) { emit_faddp_stn_st0(emitptr, 1); } +inline void emit_fmulp(x86code *&emitptr) { emit_fmulp_stn_st0(emitptr, 1); } +inline void emit_fsubrp(x86code *&emitptr) { emit_fsubrp_stn_st0(emitptr, 1); } +inline void emit_fsubp(x86code *&emitptr) { emit_fsubp_stn_st0(emitptr, 1); } +inline void emit_fdivrp(x86code *&emitptr) { emit_fdivrp_stn_st0(emitptr, 1); } +inline void emit_fdivp(x86code *&emitptr) { emit_fdivp_stn_st0(emitptr, 1); } + +#endif + + + +//************************************************************************** +// MEMORY FPU EMITTERS +//************************************************************************** + +#if (X86EMIT_SIZE == 32) + +inline void emit_fadd_m32(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_ESC_D8, OP_32BIT, 0, memref); } +inline void emit_fmul_m32(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_ESC_D8, OP_32BIT, 1, memref); } +inline void emit_fcom_m32(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_ESC_D8, OP_32BIT, 2, memref); } +inline void emit_fcomp_m32(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_ESC_D8, OP_32BIT, 3, memref); } +inline void emit_fsub_m32(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_ESC_D8, OP_32BIT, 4, memref); } +inline void emit_fsubr_m32(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_ESC_D8, OP_32BIT, 5, memref); } +inline void emit_fdiv_m32(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_ESC_D8, OP_32BIT, 6, memref); } +inline void emit_fdivr_m32(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_ESC_D8, OP_32BIT, 7, memref); } + +inline void emit_fld_m32(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_ESC_D9, OP_32BIT, 0, memref); } +inline void emit_fst_m32(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_ESC_D9, OP_32BIT, 2, memref); } +inline void emit_fstp_m32(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_ESC_D9, OP_32BIT, 3, memref); } +inline void emit_fldenv_m(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_ESC_D9, OP_32BIT, 4, memref); } +inline void emit_fldcw_m16(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_ESC_D9, OP_32BIT, 5, memref); } +inline void emit_fstenv_m(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_ESC_D9, OP_32BIT, 6, memref); } +inline void emit_fstcw_m16(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_ESC_D9, OP_32BIT, 7, memref); } + +inline void emit_fiadd_m32(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_ESC_DA, OP_32BIT, 0, memref); } +inline void emit_fimul_m32(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_ESC_DA, OP_32BIT, 1, memref); } +inline void emit_ficom_m32(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_ESC_DA, OP_32BIT, 2, memref); } +inline void emit_ficomp_m32(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_ESC_DA, OP_32BIT, 3, memref); } +inline void emit_fisub_m32(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_ESC_DA, OP_32BIT, 4, memref); } +inline void emit_fisubr_m32(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_ESC_DA, OP_32BIT, 5, memref); } +inline void emit_fidiv_m32(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_ESC_DA, OP_32BIT, 6, memref); } +inline void emit_fidivr_m32(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_ESC_DA, OP_32BIT, 7, memref); } + +inline void emit_fild_m32(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_ESC_DB, OP_32BIT, 0, memref); } +inline void emit_fisttp_m32(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_ESC_DB, OP_32BIT, 1, memref); } +inline void emit_fist_m32(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_ESC_DB, OP_32BIT, 2, memref); } +inline void emit_fistp_m32(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_ESC_DB, OP_32BIT, 3, memref); } +inline void emit_fld_m80(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_ESC_DB, OP_32BIT, 5, memref); } +inline void emit_fstp_m80(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_ESC_DB, OP_32BIT, 7, memref); } + +inline void emit_fadd_m64(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_ESC_DC, OP_32BIT, 0, memref); } +inline void emit_fmul_m64(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_ESC_DC, OP_32BIT, 1, memref); } +inline void emit_fcom_m64(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_ESC_DC, OP_32BIT, 2, memref); } +inline void emit_fcomp_m64(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_ESC_DC, OP_32BIT, 3, memref); } +inline void emit_fsub_m64(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_ESC_DC, OP_32BIT, 4, memref); } +inline void emit_fsubr_m64(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_ESC_DC, OP_32BIT, 5, memref); } +inline void emit_fdiv_m64(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_ESC_DC, OP_32BIT, 6, memref); } +inline void emit_fdivr_m64(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_ESC_DC, OP_32BIT, 7, memref); } + +inline void emit_fld_m64(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_ESC_DD, OP_32BIT, 0, memref); } +inline void emit_fisttp_m64(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_ESC_DD, OP_32BIT, 1, memref); } +inline void emit_fst_m64(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_ESC_DD, OP_32BIT, 2, memref); } +inline void emit_fstp_m64(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_ESC_DD, OP_32BIT, 3, memref); } +inline void emit_frstor_m(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_ESC_DD, OP_32BIT, 4, memref); } +inline void emit_fsave_m(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_ESC_DD, OP_32BIT, 6, memref); } +inline void emit_fstsw_m16(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_ESC_DD, OP_32BIT, 7, memref); } + +inline void emit_fiadd_m16(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_ESC_DE, OP_32BIT, 0, memref); } +inline void emit_fimul_m16(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_ESC_DE, OP_32BIT, 1, memref); } +inline void emit_ficom_m16(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_ESC_DE, OP_32BIT, 2, memref); } +inline void emit_ficomp_m16(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_ESC_DE, OP_32BIT, 3, memref); } +inline void emit_fisub_m16(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_ESC_DE, OP_32BIT, 4, memref); } +inline void emit_fisubr_m16(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_ESC_DE, OP_32BIT, 5, memref); } +inline void emit_fidiv_m16(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_ESC_DE, OP_32BIT, 6, memref); } +inline void emit_fidivr_m16(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_ESC_DE, OP_32BIT, 7, memref); } + +inline void emit_fild_m16(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_ESC_DF, OP_32BIT, 0, memref); } +inline void emit_fisttp_m16(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_ESC_DF, OP_32BIT, 1, memref); } +inline void emit_fist_m16(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_ESC_DF, OP_32BIT, 2, memref); } +inline void emit_fistp_m16(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_ESC_DF, OP_32BIT, 3, memref); } +inline void emit_fbld_m80(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_ESC_DF, OP_32BIT, 4, memref); } +inline void emit_fild_m64(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_ESC_DF, OP_32BIT, 5, memref); } +inline void emit_fbstp_m80(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_ESC_DF, OP_32BIT, 6, memref); } +inline void emit_fistp_m64(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_ESC_DF, OP_32BIT, 7, memref); } + +#endif + + + +//************************************************************************** +// GROUP16 EMITTERS +//************************************************************************** + +inline void emit_ldmxcsr_m32(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_G16, OP_32BIT, 2, memref); } +inline void emit_stmxcsr_m32(x86code *&emitptr, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_G16, OP_32BIT, 3, memref); } + + + +//************************************************************************** +// MISC SSE EMITTERS +//************************************************************************** + +inline void emit_movd_r128_r32(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_MOVD_Vd_Ed, OP_32BIT, dreg, sreg); } +inline void emit_movd_r128_m32(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_MOVD_Vd_Ed, OP_32BIT, dreg, memref); } +inline void emit_movd_r32_r128(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_MOVD_Ed_Vd, OP_32BIT, sreg, dreg); } +inline void emit_movd_m32_r128(x86code *&emitptr, x86_memref memref, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_MOVD_Ed_Vd, OP_32BIT, sreg, memref); } + +#if (X86EMIT_SIZE == 64) + +inline void emit_movq_r128_r64(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_MOVD_Vd_Ed, OP_64BIT, dreg, sreg); } +inline void emit_movq_r128_m64(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_MOVD_Vd_Ed, OP_64BIT, dreg, memref); } +inline void emit_movq_r64_r128(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_MOVD_Ed_Vd, OP_64BIT, sreg, dreg); } +inline void emit_movq_m64_r128(x86code *&emitptr, x86_memref memref, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_MOVD_Ed_Vd, OP_64BIT, sreg, memref); } + +#endif + + + +//************************************************************************** +// SSE SCALAR SINGLE EMITTERS +//************************************************************************** + +inline void emit_movss_r128_r128(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_MOVSS_Vss_Wss, OP_32BIT, dreg, sreg); } +inline void emit_movss_r128_m32(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_MOVSS_Vss_Wss, OP_32BIT, dreg, memref); } +inline void emit_movss_m32_r128(x86code *&emitptr, x86_memref memref, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_MOVSS_Wss_Vss, OP_32BIT, sreg, memref); } + +inline void emit_addss_r128_r128(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_ADDSS_Vss_Wss, OP_32BIT, dreg, sreg); } +inline void emit_addss_r128_m32(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_ADDSS_Vss_Wss, OP_32BIT, dreg, memref); } + +inline void emit_subss_r128_r128(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_SUBSS_Vss_Wss, OP_32BIT, dreg, sreg); } +inline void emit_subss_r128_m32(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_SUBSS_Vss_Wss, OP_32BIT, dreg, memref); } + +inline void emit_mulss_r128_r128(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_MULSS_Vss_Wss, OP_32BIT, dreg, sreg); } +inline void emit_mulss_r128_m32(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_MULSS_Vss_Wss, OP_32BIT, dreg, memref); } + +inline void emit_divss_r128_r128(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_DIVSS_Vss_Wss, OP_32BIT, dreg, sreg); } +inline void emit_divss_r128_m32(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_DIVSS_Vss_Wss, OP_32BIT, dreg, memref); } + +inline void emit_rcpss_r128_r128(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_RCPSS_Vss_Wss, OP_32BIT, dreg, sreg); } +inline void emit_rcpss_r128_m32(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_RCPSS_Vss_Wss, OP_32BIT, dreg, memref); } + +inline void emit_sqrtss_r128_r128(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_SQRTSS_Vss_Wss, OP_32BIT, dreg, sreg); } +inline void emit_sqrtss_r128_m32(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_SQRTSS_Vss_Wss, OP_32BIT, dreg, memref); } + +inline void emit_rsqrtss_r128_r128(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_RSQRTSS_Vss_Wss, OP_32BIT, dreg, sreg); } +inline void emit_rsqrtss_r128_m32(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_RSQRTSS_Vss_Wss, OP_32BIT, dreg, memref); } + +inline void emit_comiss_r128_r128(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_COMISS_Vss_Wss, OP_32BIT, dreg, sreg); } +inline void emit_comiss_r128_m32(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_COMISS_Vss_Wss, OP_32BIT, dreg, memref); } + +inline void emit_ucomiss_r128_r128(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_UCOMISS_Vss_Wss, OP_32BIT, dreg, sreg); } +inline void emit_ucomiss_r128_m32(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_UCOMISS_Vss_Wss, OP_32BIT, dreg, memref); } + +inline void emit_cvtsi2ss_r128_r32(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_CVTSI2SS_Vss_Ed, OP_32BIT, dreg, sreg); } +inline void emit_cvtsi2ss_r128_m32(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_CVTSI2SS_Vss_Ed, OP_32BIT, dreg, memref); } + +#if (X86EMIT_SIZE == 64) +inline void emit_cvtsi2ss_r128_r64(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_CVTSI2SS_Vss_Ed, OP_64BIT, dreg, sreg); } +inline void emit_cvtsi2ss_r128_m64(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_CVTSI2SS_Vss_Ed, OP_64BIT, dreg, memref); } +#endif + +inline void emit_cvtsd2ss_r128_r128(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_CVTSD2SS_Vss_Wsd, OP_32BIT, dreg, sreg); } +inline void emit_cvtsd2ss_r128_m64(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_CVTSD2SS_Vss_Wsd, OP_32BIT, dreg, memref); } + +inline void emit_cvtss2si_r32_r128(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_CVTSS2SI_Gd_Wss, OP_32BIT, dreg, sreg); } +inline void emit_cvtss2si_r32_m32(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_CVTSS2SI_Gd_Wss, OP_32BIT, dreg, memref); } + +#if (X86EMIT_SIZE == 64) +inline void emit_cvtss2si_r64_r128(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_CVTSS2SI_Gd_Wss, OP_64BIT, dreg, sreg); } +inline void emit_cvtss2si_r64_m32(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_CVTSS2SI_Gd_Wss, OP_64BIT, dreg, memref); } +#endif + +inline void emit_cvttss2si_r32_r128(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_CVTTSS2SI_Gd_Wss, OP_32BIT, dreg, sreg); } +inline void emit_cvttss2si_r32_m32(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_CVTTSS2SI_Gd_Wss, OP_32BIT, dreg, memref); } + +#if (X86EMIT_SIZE == 64) +inline void emit_cvttss2si_r64_r128(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_CVTTSS2SI_Gd_Wss, OP_64BIT, dreg, sreg); } +inline void emit_cvttss2si_r64_m32(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_CVTTSS2SI_Gd_Wss, OP_64BIT, dreg, memref); } +#endif + +inline void emit_roundss_r128_r128_imm(x86code *&emitptr, UINT8 dreg, UINT8 sreg, UINT8 imm) { emit_op_modrm_reg(emitptr, OP_ROUNDSS_Vss_Wss_Ib, OP_32BIT, dreg, sreg); emit_byte(emitptr, imm); } +inline void emit_roundss_r128_m32_imm(x86code *&emitptr, UINT8 dreg, x86_memref memref, UINT8 imm) { emit_op_modrm_mem(emitptr, OP_ROUNDSS_Vss_Wss_Ib, OP_32BIT, dreg, memref); emit_byte(emitptr, imm); } + + + +//************************************************************************** +// SSE PACKED SINGLE EMITTERS +//************************************************************************** + +inline void emit_movps_r128_r128(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_MOVAPS_Vps_Wps, OP_32BIT, dreg, sreg); } +inline void emit_movps_r128_m128(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_MOVAPS_Vps_Wps, OP_32BIT, dreg, memref); } +inline void emit_movps_m128_r128(x86code *&emitptr, x86_memref memref, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_MOVAPS_Wps_Vps, OP_32BIT, sreg, memref); } + +inline void emit_addps_r128_r128(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_ADDPS_Vps_Wps, OP_32BIT, dreg, sreg); } +inline void emit_addps_r128_m128(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_ADDPS_Vps_Wps, OP_32BIT, dreg, memref); } + +inline void emit_subps_r128_r128(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_SUBPS_Vps_Wps, OP_32BIT, dreg, sreg); } +inline void emit_subps_r128_m128(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_SUBPS_Vps_Wps, OP_32BIT, dreg, memref); } + +inline void emit_mulps_r128_r128(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_MULPS_Vps_Wps, OP_32BIT, dreg, sreg); } +inline void emit_mulps_r128_m128(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_MULPS_Vps_Wps, OP_32BIT, dreg, memref); } + +inline void emit_divps_r128_r128(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_DIVPS_Vps_Wps, OP_32BIT, dreg, sreg); } +inline void emit_divps_r128_m128(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_DIVPS_Vps_Wps, OP_32BIT, dreg, memref); } + +inline void emit_rcpps_r128_r128(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_RCPPS_Vps_Wps, OP_32BIT, dreg, sreg); } +inline void emit_rcpps_r128_m128(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_RCPPS_Vps_Wps, OP_32BIT, dreg, memref); } + +inline void emit_sqrtps_r128_r128(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_SQRTPS_Vps_Wps, OP_32BIT, dreg, sreg); } +inline void emit_sqrtps_r128_m128(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_SQRTPS_Vps_Wps, OP_32BIT, dreg, memref); } + +inline void emit_rsqrtps_r128_r128(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_RSQRTPS_Vps_Wps, OP_32BIT, dreg, sreg); } +inline void emit_rsqrtps_r128_m128(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_RSQRTPS_Vps_Wps, OP_32BIT, dreg, memref); } + +inline void emit_andps_r128_r128(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_ANDPS_Vps_Wps, OP_32BIT, dreg, sreg); } +inline void emit_andps_r128_m128(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_ANDPS_Vps_Wps, OP_32BIT, dreg, memref); } + +inline void emit_andnps_r128_r128(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_ANDNPS_Vps_Wps, OP_32BIT, dreg, sreg); } +inline void emit_andnps_r128_m128(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_ANDNPS_Vps_Wps, OP_32BIT, dreg, memref); } + +inline void emit_orps_r128_r128(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_ORPS_Vps_Wps, OP_32BIT, dreg, sreg); } +inline void emit_orps_r128_m128(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_ORPS_Vps_Wps, OP_32BIT, dreg, memref); } + +inline void emit_xorps_r128_r128(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_XORPS_Vps_Wps, OP_32BIT, dreg, sreg); } +inline void emit_xorps_r128_m128(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_XORPS_Vps_Wps, OP_32BIT, dreg, memref); } + +inline void emit_cvtdq2ps_r128_r128(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_CVTDQ2PS_Vps_Wdq, OP_32BIT, dreg, sreg); } +inline void emit_cvtdq2ps_r128_m128(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_CVTDQ2PS_Vps_Wdq, OP_32BIT, dreg, memref); } + +inline void emit_cvtpd2ps_r128_r128(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_CVTPD2PS_Vps_Wpd, OP_32BIT, dreg, sreg); } +inline void emit_cvtpd2ps_r128_m128(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_CVTPD2PS_Vps_Wpd, OP_32BIT, dreg, memref); } + +inline void emit_cvtps2dq_r128_r128(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_CVTPS2DQ_Vdq_Wps, OP_32BIT, dreg, sreg); } +inline void emit_cvtps2dq_r128_m128(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_CVTPS2DQ_Vdq_Wps, OP_32BIT, dreg, memref); } + +inline void emit_cvttps2dq_r128_r128(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_CVTTPS2DQ_Vdq_Wps, OP_32BIT, dreg, sreg); } +inline void emit_cvttps2dq_r128_m128(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_CVTTPS2DQ_Vdq_Wps, OP_32BIT, dreg, memref); } + +inline void emit_roundps_r128_r128_imm(x86code *&emitptr, UINT8 dreg, UINT8 sreg, UINT8 imm) { emit_op_modrm_reg(emitptr, OP_ROUNDPS_Vdq_Wdq_Ib, OP_32BIT, dreg, sreg); emit_byte(emitptr, imm); } +inline void emit_roundps_r128_m128_imm(x86code *&emitptr, UINT8 dreg, x86_memref memref, UINT8 imm) { emit_op_modrm_mem(emitptr, OP_ROUNDPS_Vdq_Wdq_Ib, OP_32BIT, dreg, memref); emit_byte(emitptr, imm); } + + + +//************************************************************************** +// SSE SCALAR DOUBLE EMITTERS +//************************************************************************** + +inline void emit_movsd_r128_r128(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_MOVSD_Vsd_Wsd, OP_32BIT, dreg, sreg); } +inline void emit_movsd_r128_m64(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_MOVSD_Vsd_Wsd, OP_32BIT, dreg, memref); } +inline void emit_movsd_m64_r128(x86code *&emitptr, x86_memref memref, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_MOVSD_Wsd_Vsd, OP_32BIT, sreg, memref); } + +inline void emit_addsd_r128_r128(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_ADDSD_Vsd_Wsd, OP_32BIT, dreg, sreg); } +inline void emit_addsd_r128_m64(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_ADDSD_Vsd_Wsd, OP_32BIT, dreg, memref); } + +inline void emit_subsd_r128_r128(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_SUBSD_Vsd_Wsd, OP_32BIT, dreg, sreg); } +inline void emit_subsd_r128_m64(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_SUBSD_Vsd_Wsd, OP_32BIT, dreg, memref); } + +inline void emit_mulsd_r128_r128(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_MULSD_Vsd_Wsd, OP_32BIT, dreg, sreg); } +inline void emit_mulsd_r128_m64(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_MULSD_Vsd_Wsd, OP_32BIT, dreg, memref); } + +inline void emit_divsd_r128_r128(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_DIVSD_Vsd_Wsd, OP_32BIT, dreg, sreg); } +inline void emit_divsd_r128_m64(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_DIVSD_Vsd_Wsd, OP_32BIT, dreg, memref); } + +inline void emit_sqrtsd_r128_r128(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_SQRTSD_Vsd_Wsd, OP_32BIT, dreg, sreg); } +inline void emit_sqrtsd_r128_m64(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_SQRTSD_Vsd_Wsd, OP_32BIT, dreg, memref); } + +inline void emit_comisd_r128_r128(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_COMISD_Vsd_Wsd, OP_32BIT, dreg, sreg); } +inline void emit_comisd_r128_m64(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_COMISD_Vsd_Wsd, OP_32BIT, dreg, memref); } + +inline void emit_ucomisd_r128_r128(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_UCOMISD_Vsd_Wsd, OP_32BIT, dreg, sreg); } +inline void emit_ucomisd_r128_m64(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_UCOMISD_Vsd_Wsd, OP_32BIT, dreg, memref); } + +inline void emit_cvtsi2sd_r128_r32(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_CVTSI2SD_Vsd_Ed, OP_32BIT, dreg, sreg); } +inline void emit_cvtsi2sd_r128_m32(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_CVTSI2SD_Vsd_Ed, OP_32BIT, dreg, memref); } + +#if (X86EMIT_SIZE == 64) +inline void emit_cvtsi2sd_r128_r64(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_CVTSI2SD_Vsd_Ed, OP_64BIT, dreg, sreg); } +inline void emit_cvtsi2sd_r128_m64(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_CVTSI2SD_Vsd_Ed, OP_64BIT, dreg, memref); } +#endif + +inline void emit_cvtss2sd_r128_r128(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_CVTSS2SD_Vsd_Wss, OP_32BIT, dreg, sreg); } +inline void emit_cvtss2sd_r128_m32(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_CVTSS2SD_Vsd_Wss, OP_32BIT, dreg, memref); } + +inline void emit_cvtsd2si_r32_r128(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_CVTSD2SI_Gd_Wsd, OP_32BIT, dreg, sreg); } +inline void emit_cvtsd2si_r32_m64(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_CVTSD2SI_Gd_Wsd, OP_32BIT, dreg, memref); } + +#if (X86EMIT_SIZE == 64) +inline void emit_cvtsd2si_r64_r128(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_CVTSD2SI_Gd_Wsd, OP_64BIT, dreg, sreg); } +inline void emit_cvtsd2si_r64_m64(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_CVTSD2SI_Gd_Wsd, OP_64BIT, dreg, memref); } +#endif + +inline void emit_cvttsd2si_r32_r128(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_CVTTSD2SI_Gd_Wsd, OP_32BIT, dreg, sreg); } +inline void emit_cvttsd2si_r32_m64(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_CVTTSD2SI_Gd_Wsd, OP_32BIT, dreg, memref); } + +#if (X86EMIT_SIZE == 64) +inline void emit_cvttsd2si_r64_r128(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_CVTTSD2SI_Gd_Wsd, OP_64BIT, dreg, sreg); } +inline void emit_cvttsd2si_r64_m64(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_CVTTSD2SI_Gd_Wsd, OP_64BIT, dreg, memref); } +#endif + +inline void emit_roundsd_r128_r128_imm(x86code *&emitptr, UINT8 dreg, UINT8 sreg, UINT8 imm) { emit_op_modrm_reg(emitptr, OP_ROUNDSD_Vsd_Wsd_Ib, OP_32BIT, dreg, sreg); emit_byte(emitptr, imm); } +inline void emit_roundsd_r128_m64_imm(x86code *&emitptr, UINT8 dreg, x86_memref memref, UINT8 imm) { emit_op_modrm_mem(emitptr, OP_ROUNDSD_Vsd_Wsd_Ib, OP_32BIT, dreg, memref); emit_byte(emitptr, imm); } + + + +//************************************************************************** +// SSE PACKED DOUBLE EMITTERS +//************************************************************************** + +inline void emit_movpd_r128_r128(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_MOVAPD_Vpd_Wpd, OP_32BIT, dreg, sreg); } +inline void emit_movpd_r128_m128(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_MOVAPD_Vpd_Wpd, OP_32BIT, dreg, memref); } +inline void emit_movpd_m128_r128(x86code *&emitptr, x86_memref memref, UINT8 sreg) { emit_op_modrm_mem(emitptr, OP_MOVAPD_Wpd_Vpd, OP_32BIT, sreg, memref); } + +inline void emit_addpd_r128_r128(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_ADDPD_Vpd_Wpd, OP_32BIT, dreg, sreg); } +inline void emit_addpd_r128_m128(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_ADDPD_Vpd_Wpd, OP_32BIT, dreg, memref); } + +inline void emit_subpd_r128_r128(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_SUBPD_Vpd_Wpd, OP_32BIT, dreg, sreg); } +inline void emit_subpd_r128_m128(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_SUBPD_Vpd_Wpd, OP_32BIT, dreg, memref); } + +inline void emit_mulpd_r128_r128(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_MULPD_Vpd_Wpd, OP_32BIT, dreg, sreg); } +inline void emit_mulpd_r128_m128(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_MULPD_Vpd_Wpd, OP_32BIT, dreg, memref); } + +inline void emit_divpd_r128_r128(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_DIVPD_Vpd_Wpd, OP_32BIT, dreg, sreg); } +inline void emit_divpd_r128_m128(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_DIVPD_Vpd_Wpd, OP_32BIT, dreg, memref); } + +inline void emit_sqrtpd_r128_r128(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_SQRTPD_Vpd_Wpd, OP_32BIT, dreg, sreg); } +inline void emit_sqrtpd_r128_m128(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_SQRTPD_Vpd_Wpd, OP_32BIT, dreg, memref); } + +inline void emit_andpd_r128_r128(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_ANDPD_Vpd_Wpd, OP_32BIT, dreg, sreg); } +inline void emit_andpd_r128_m128(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_ANDPD_Vpd_Wpd, OP_32BIT, dreg, memref); } + +inline void emit_andnpd_r128_r128(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_ANDNPD_Vpd_Wpd, OP_32BIT, dreg, sreg); } +inline void emit_andnpd_r128_m128(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_ANDNPD_Vpd_Wpd, OP_32BIT, dreg, memref); } + +inline void emit_orpd_r128_r128(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_ORPD_Vpd_Wpd, OP_32BIT, dreg, sreg); } +inline void emit_orpd_r128_m128(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_ORPD_Vpd_Wpd, OP_32BIT, dreg, memref); } + +inline void emit_xorpd_r128_r128(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_XORPD_Vpd_Wpd, OP_32BIT, dreg, sreg); } +inline void emit_xorpd_r128_m128(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_XORPD_Vpd_Wpd, OP_32BIT, dreg, memref); } + +inline void emit_cvtdq2pd_r128_r128(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_CVTDQ2PD_Vpd_Wq, OP_32BIT, dreg, sreg); } +inline void emit_cvtdq2pd_r128_m128(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_CVTDQ2PD_Vpd_Wq, OP_32BIT, dreg, memref); } + +inline void emit_cvtps2pd_r128_r128(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_CVTPS2PD_Vpd_Wq, OP_32BIT, dreg, sreg); } +inline void emit_cvtps2pd_r128_m128(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_CVTPS2PD_Vpd_Wq, OP_32BIT, dreg, memref); } + +inline void emit_cvtpd2dq_r128_r128(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_CVTPD2DQ_Vdq_Wpd, OP_32BIT, dreg, sreg); } +inline void emit_cvtpd2dq_r128_m128(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_CVTPD2DQ_Vdq_Wpd, OP_32BIT, dreg, memref); } + +inline void emit_cvttpd2dq_r128_r128(x86code *&emitptr, UINT8 dreg, UINT8 sreg) { emit_op_modrm_reg(emitptr, OP_CVTTPD2DQ_Vdq_Wpd, OP_32BIT, dreg, sreg); } +inline void emit_cvttpd2dq_r128_m128(x86code *&emitptr, UINT8 dreg, x86_memref memref) { emit_op_modrm_mem(emitptr, OP_CVTTPD2DQ_Vdq_Wpd, OP_32BIT, dreg, memref); } + +inline void emit_roundpd_r128_r128_imm(x86code *&emitptr, UINT8 dreg, UINT8 sreg, UINT8 imm) { emit_op_modrm_reg(emitptr, OP_ROUNDPD_Vdq_Wdq_Ib, OP_32BIT, dreg, sreg); emit_byte(emitptr, imm); } +inline void emit_roundpd_r128_m128_imm(x86code *&emitptr, UINT8 dreg, x86_memref memref, UINT8 imm) { emit_op_modrm_mem(emitptr, OP_ROUNDPD_Vdq_Wdq_Ib, OP_32BIT, dreg, memref); emit_byte(emitptr, imm); } + +} + +#undef X86EMIT_SIZE + +#endif diff --git a/src/devices/cpu/x86log.c b/src/devices/cpu/x86log.c new file mode 100644 index 00000000000..4c311310d96 --- /dev/null +++ b/src/devices/cpu/x86log.c @@ -0,0 +1,300 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + x86log.c + + x86/x64 code logging helpers. + +***************************************************************************/ + +#include "emu.h" +#include "x86log.h" + + + +/*************************************************************************** + CONSTANTS +***************************************************************************/ + +/* comment parameters */ +#define MAX_COMMENTS 4000 +#define MAX_DATA_RANGES 1000 +#define COMMENT_POOL_SIZE (MAX_COMMENTS * 40) + + + +/*************************************************************************** + TYPE DEFINITIONS +***************************************************************************/ + +/* code logging info */ +struct log_comment +{ + x86code * base; + const char * string; +}; + + +/* data ranges */ +struct data_range_t +{ + x86code * base; + x86code * end; + int size; +}; + + +/* the code logging context */ +struct x86log_context +{ + std::string filename; /* name of the file */ + FILE * file; /* file we are logging to */ + + data_range_t data_range[MAX_DATA_RANGES]; /* list of data ranges */ + int data_range_count; /* number of data ranges */ + + log_comment comment_list[MAX_COMMENTS]; /* list of comments */ + int comment_count; /* number of live comments */ + + char comment_pool[COMMENT_POOL_SIZE];/* string pool to hold comments */ + char * comment_pool_next; /* pointer to next string pool location */ +}; + + + +/*************************************************************************** + FUNCTION PROTOTYPES +***************************************************************************/ + +static void reset_log(x86log_context *log); +extern int i386_dasm_one_ex(char *buffer, UINT64 eip, const UINT8 *oprom, int mode); + + + +/*************************************************************************** + EXTERNAL INTERFACES +***************************************************************************/ + +/*------------------------------------------------- + x86log_create_context - create a new context +-------------------------------------------------*/ + +x86log_context *x86log_create_context(const char *filename) +{ + x86log_context *log; + + /* allocate the log */ + log = global_alloc_clear(x86log_context); + + /* allocate the filename */ + log->filename.assign(filename); + + /* reset things */ + reset_log(log); + return log; +} + + +/*------------------------------------------------- + x86log_free_context - release a context +-------------------------------------------------*/ + +void x86log_free_context(x86log_context *log) +{ + /* close any open files */ + if (log->file != NULL) + fclose(log->file); + + /* free the structure */ + global_free(log); +} + + +/*------------------------------------------------- + x86log_add_comment - add a comment associated + with a given code pointer +-------------------------------------------------*/ + +void x86log_add_comment(x86log_context *log, x86code *base, const char *format, ...) +{ + char *string = log->comment_pool_next; + log_comment *comment; + va_list va; + + assert(log->comment_count < MAX_COMMENTS); + assert(log->comment_pool_next + strlen(format) + 256 < log->comment_pool + COMMENT_POOL_SIZE); + + /* we assume comments are registered in order; enforce this */ + assert(log->comment_count == 0 || base >= log->comment_list[log->comment_count - 1].base); + + /* if we exceed the maxima, skip it */ + if (log->comment_count >= MAX_COMMENTS) + return; + if (log->comment_pool_next + strlen(format) + 256 >= log->comment_pool + COMMENT_POOL_SIZE) + return; + + /* do the printf to the string pool */ + va_start(va, format); + log->comment_pool_next += vsprintf(log->comment_pool_next, format, va) + 1; + va_end(va); + + /* fill in the new comment */ + comment = &log->comment_list[log->comment_count++]; + comment->base = base; + comment->string = string; +} + + +/*------------------------------------------------- + x86log_mark_as_data - mark a given range as + data for logging purposes +-------------------------------------------------*/ + +void x86log_mark_as_data(x86log_context *log, x86code *base, x86code *end, int size) +{ + data_range_t *data; + + assert(log->data_range_count < MAX_DATA_RANGES); + assert(end >= base); + assert(size == 1 || size == 2 || size == 4 || size == 8); + + /* we assume data ranges are registered in order; enforce this */ + assert(log->data_range_count == 0 || base > log->data_range[log->data_range_count - 1].end); + + /* if we exceed the maxima, skip it */ + if (log->data_range_count >= MAX_DATA_RANGES) + return; + + /* fill in the new range */ + data = &log->data_range[log->data_range_count++]; + data->base = base; + data->end = end; + data->size = size; +} + + +/*------------------------------------------------- + x86log_disasm_code_range - disassemble a range + of code and reset accumulated information +-------------------------------------------------*/ + +void x86log_disasm_code_range(x86log_context *log, const char *label, x86code *start, x86code *stop) +{ + const log_comment *lastcomment = &log->comment_list[log->comment_count]; + const log_comment *curcomment = &log->comment_list[0]; + const data_range_t *lastdata = &log->data_range[log->data_range_count]; + const data_range_t *curdata = &log->data_range[0]; + x86code *cur = start; + + /* print the optional label */ + if (label != NULL) + x86log_printf(log, "\n%s\n", label); + + /* loop from the start until the cache top */ + while (cur < stop) + { + char buffer[100]; + int bytes; + + /* skip past any past data ranges */ + while (curdata < lastdata && cur > curdata->end) + curdata++; + + /* skip past any past comments */ + while (curcomment < lastcomment && cur > curcomment->base) + curcomment++; + + /* if we're in a data range, output the next chunk and continue */ + if (cur >= curdata->base && cur <= curdata->end) + { + bytes = curdata->size; + switch (curdata->size) + { + default: + case 1: sprintf(buffer, "db %02X", *cur); break; + case 2: sprintf(buffer, "dw %04X", *(UINT16 *)cur); break; + case 4: sprintf(buffer, "dd %08X", *(UINT32 *)cur); break; + case 8: sprintf(buffer, "dq %08X%08X", ((UINT32 *)cur)[1], ((UINT32 *)cur)[0]); break; + } + } + + /* if we're not in the data range, skip filler opcodes */ + else if (*cur == 0xcc) + { + cur++; + continue; + } + + /* otherwise, do a disassembly of the current instruction */ + else + { +#ifdef PTR64 + bytes = i386_dasm_one_ex(buffer, (FPTR)cur, cur, 64) & DASMFLAG_LENGTHMASK; +#else + bytes = i386_dasm_one_ex(buffer, (FPTR)cur, cur, 32) & DASMFLAG_LENGTHMASK; +#endif + } + + /* if we have a matching comment, output it */ + if (curcomment < lastcomment && cur == curcomment->base) + { + /* if we have additional matching comments at the same address, output them first */ + for ( ; curcomment + 1 < lastcomment && cur == curcomment[1].base; curcomment++) + x86log_printf(log, "%p: %-50s; %s\n", cur, "", curcomment->string); + x86log_printf(log, "%p: %-50s; %s\n", cur, buffer, curcomment->string); + } + + /* if we don't, just print the disassembly and move on */ + else + x86log_printf(log, "%p: %s\n", cur, buffer); + + /* advance past this instruction */ + cur += bytes; + } + + /* reset our state */ + reset_log(log); +} + + +/*------------------------------------------------- + x86log_printf - manually printf information to + the log file +-------------------------------------------------*/ + +void x86log_printf(x86log_context *log, const char *format, ...) +{ + va_list va; + + /* open the file, creating it if necessary */ + if (log->file == NULL) + log->file = fopen(log->filename.c_str(), "w"); + if (log->file == NULL) + return; + + /* do the printf */ + va_start(va, format); + vfprintf(log->file, format, va); + va_end(va); + + /* flush the file */ + fflush(log->file); +} + + + +/*************************************************************************** + LOCAL FUNCTIONS +***************************************************************************/ + +/*------------------------------------------------- + reset_log - reset the state of the log +-------------------------------------------------*/ + +static void reset_log(x86log_context *log) +{ + log->data_range_count = 0; + log->comment_count = 0; + log->comment_pool_next = log->comment_pool; +} diff --git a/src/devices/cpu/x86log.h b/src/devices/cpu/x86log.h new file mode 100644 index 00000000000..68ca2ec5257 --- /dev/null +++ b/src/devices/cpu/x86log.h @@ -0,0 +1,50 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + x86log.h + + x86/x64 code logging helpers. + +***************************************************************************/ + +#pragma once + +#ifndef __X86LOG_H__ +#define __X86LOG_H__ + +#include "x86emit.h" + + +/*************************************************************************** + TYPE DEFINITIONS +***************************************************************************/ + +struct x86log_context; + + + +/*************************************************************************** + FUNCTION PROTOTYPES +***************************************************************************/ + +/* create a new context */ +x86log_context *x86log_create_context(const char *filename); + +/* release a context */ +void x86log_free_context(x86log_context *log); + +/* add a comment associated with a given code pointer */ +void x86log_add_comment(x86log_context *log, x86code *base, const char *format, ...) ATTR_PRINTF(3,4); + +/* mark a given range as data for logging purposes */ +void x86log_mark_as_data(x86log_context *log, x86code *base, x86code *end, int size); + +/* disassemble a range of code and reset accumulated information */ +void x86log_disasm_code_range(x86log_context *log, const char *label, x86code *start, x86code *stop); + +/* manually printf information to the log file */ +void x86log_printf(x86log_context *log, const char *format, ...) ATTR_PRINTF(2,3); + + +#endif /* __X86LOG_H__ */ diff --git a/src/devices/cpu/z180/z180.c b/src/devices/cpu/z180/z180.c new file mode 100644 index 00000000000..134e67dfb72 --- /dev/null +++ b/src/devices/cpu/z180/z180.c @@ -0,0 +1,2579 @@ +// license:BSD-3-Clause +// copyright-holders:Juergen Buchmueller +/***************************************************************************** + * + * z180.c + * Portable Z180 emulator V0.3 + * + *****************************************************************************/ + +/***************************************************************************** + + TODO: + - HALT processing is not yet perfect. The manual states that + during HALT, all dma and internal i/o incl. timers continue to + work. Currently, only timers are implemented. Ideally, the + burn_cycles routine would go away and halt processing be + implemented in cpu_execute. + *****************************************************************************/ + +/***************************************************************************** + +Z180 Info: + +Known clock speeds (from ZiLOG): 6, 8, 10, 20 & 33MHz + +ZiLOG Z180 codes: + + Speed: 10 = 10MHZ + 20 = 20MHz + 33 = 33MHz +Package: P = 60-Pin Plastic DIP + V = 68-Pin PLCC + F = 80-Pin QFP + Temp: S = 0C to +70C + E = -40C to +85C + +Environmanetal Flow: C = Plastic Standard + + +Example from Ms.Pac-Man/Galaga - 20 year Reunion hardare (see src/mame/drivers/20pacgal.c): + + CPU is Z8S18020VSC = Z180, 20MHz, 68-Pin PLCC, 0C to +70C, Plastic Standard + + +Other CPUs that use a compatible Z180 core: + +Hitachi HD647180 series: + Available in QFP80, PLCC84 & DIP90 packages (the QFP80 is not pinout compatible) + The HD647180 also has an internal ROM + + *****************************************************************************/ + +#include "emu.h" +#include "debugger.h" +#include "z180.h" + +#define VERBOSE 0 + +#define LOG(x) do { if (VERBOSE) logerror x; } while (0) + +/* interrupt priorities */ +#define Z180_INT_TRAP 0 /* Undefined opcode */ +#define Z180_INT_NMI 1 /* NMI */ +#define Z180_INT_IRQ0 2 /* Execute IRQ1 */ +#define Z180_INT_IRQ1 3 /* Execute IRQ1 */ +#define Z180_INT_IRQ2 4 /* Execute IRQ2 */ +#define Z180_INT_PRT0 5 /* Internal PRT channel 0 */ +#define Z180_INT_PRT1 6 /* Internal PRT channel 1 */ +#define Z180_INT_DMA0 7 /* Internal DMA channel 0 */ +#define Z180_INT_DMA1 8 /* Internal DMA channel 1 */ +#define Z180_INT_CSIO 9 /* Internal CSI/O */ +#define Z180_INT_ASCI0 10 /* Internal ASCI channel 0 */ +#define Z180_INT_ASCI1 11 /* Internal ASCI channel 1 */ +#define Z180_INT_MAX Z180_INT_ASCI1 + +/****************************************************************************/ +/* The Z180 registers. HALT is set to 1 when the CPU is halted, the refresh */ +/* register is calculated as follows: refresh=(Regs.R&127)|(Regs.R2&128) */ +/****************************************************************************/ + +const device_type Z180 = &device_creator; + + +z180_device::z180_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : cpu_device(mconfig, Z180, "Z180", tag, owner, clock, "z180", __FILE__) + , m_program_config("program", ENDIANNESS_LITTLE, 8, 20, 0) + , m_io_config("io", ENDIANNESS_LITTLE, 8, 16, 0) + , m_decrypted_opcodes_config("program", ENDIANNESS_LITTLE, 8, 20, 0) +{ +} + + +offs_t z180_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( z180 ); + return CPU_DISASSEMBLE_NAME(z180)(this, buffer, pc, oprom, opram, options); +} + + +#define CF 0x01 +#define NF 0x02 +#define PF 0x04 +#define VF PF +#define XF 0x08 +#define HF 0x10 +#define YF 0x20 +#define ZF 0x40 +#define SF 0x80 + +/* I/O line status flags */ +#define Z180_CKA0 0x00000001 /* I/O asynchronous clock 0 (active high) or DREQ0 (mux) */ +#define Z180_CKA1 0x00000002 /* I/O asynchronous clock 1 (active high) or TEND1 (mux) */ +#define Z180_CKS 0x00000004 /* I/O serial clock (active high) */ +#define Z180_CTS0 0x00000100 /* I clear to send 0 (active low) */ +#define Z180_CTS1 0x00000200 /* I clear to send 1 (active low) or RXS (mux) */ +#define Z180_DCD0 0x00000400 /* I data carrier detect (active low) */ +#define Z180_DREQ0 0x00000800 /* I data request DMA ch 0 (active low) or CKA0 (mux) */ +#define Z180_DREQ1 0x00001000 /* I data request DMA ch 1 (active low) */ +#define Z180_RXA0 0x00002000 /* I asynchronous receive data 0 (active high) */ +#define Z180_RXA1 0x00004000 /* I asynchronous receive data 1 (active high) */ +#define Z180_RXS 0x00008000 /* I clocked serial receive data (active high) or CTS1 (mux) */ +#define Z180_RTS0 0x00010000 /* O request to send (active low) */ +#define Z180_TEND0 0x00020000 /* O transfer end 0 (active low) or CKA1 (mux) */ +#define Z180_TEND1 0x00040000 /* O transfer end 1 (active low) */ +#define Z180_A18_TOUT 0x00080000 /* O transfer out (PRT channel, active low) or A18 (mux) */ +#define Z180_TXA0 0x00100000 /* O asynchronous transmit data 0 (active high) */ +#define Z180_TXA1 0x00200000 /* O asynchronous transmit data 1 (active high) */ +#define Z180_TXS 0x00400000 /* O clocked serial transmit data (active high) */ + +/* + * Prevent warnings on NetBSD. All identifiers beginning with an underscore + * followed by an uppercase letter are reserved by the C standard (ISO/IEC + * 9899:1999, 7.1.3) to be used by the implementation. It'd be best to rename + * all such instances, but this is less intrusive and error-prone. + */ +#undef _B +#undef _C +#undef _L + +#define _PPC m_PREPC.d /* previous program counter */ + +#define _PCD m_PC.d +#define _PC m_PC.w.l + +#define _SPD m_SP.d +#define _SP m_SP.w.l + +#define _AFD m_AF.d +#define _AF m_AF.w.l +#define _A m_AF.b.h +#define _F m_AF.b.l + +#define _BCD m_BC.d +#define _BC m_BC.w.l +#define _B m_BC.b.h +#define _C m_BC.b.l + +#define _DED m_DE.d +#define _DE m_DE.w.l +#define _D m_DE.b.h +#define _E m_DE.b.l + +#define _HLD m_HL.d +#define _HL m_HL.w.l +#define _H m_HL.b.h +#define _L m_HL.b.l + +#define _IXD m_IX.d +#define _IX m_IX.w.l +#define _HX m_IX.b.h +#define _LX m_IX.b.l + +#define _IYD m_IY.d +#define _IY m_IY.w.l +#define _HY m_IY.b.h +#define _LY m_IY.b.l + +#define IO(n) m_io[(n)-Z180_CNTLA0] +#define IO_CNTLA0 IO(Z180_CNTLA0) +#define IO_CNTLA1 IO(Z180_CNTLA1) +#define IO_CNTLB0 IO(Z180_CNTLB0) +#define IO_CNTLB1 IO(Z180_CNTLB1) +#define IO_STAT0 IO(Z180_STAT0) +#define IO_STAT1 IO(Z180_STAT1) +#define IO_TDR0 IO(Z180_TDR0) +#define IO_TDR1 IO(Z180_TDR1) +#define IO_RDR0 IO(Z180_RDR0) +#define IO_RDR1 IO(Z180_RDR1) +#define IO_CNTR IO(Z180_CNTR) +#define IO_TRDR IO(Z180_TRDR) +#define IO_TMDR0L IO(Z180_TMDR0L) +#define IO_TMDR0H IO(Z180_TMDR0H) +#define IO_RLDR0L IO(Z180_RLDR0L) +#define IO_RLDR0H IO(Z180_RLDR0H) +#define IO_TCR IO(Z180_TCR) +#define IO_IO11 IO(Z180_IO11) +#define IO_ASEXT0 IO(Z180_ASEXT0) +#define IO_ASEXT1 IO(Z180_ASEXT1) +#define IO_TMDR1L IO(Z180_TMDR1L) +#define IO_TMDR1H IO(Z180_TMDR1H) +#define IO_RLDR1L IO(Z180_RLDR1L) +#define IO_RLDR1H IO(Z180_RLDR1H) +#define IO_FRC IO(Z180_FRC) +#define IO_IO19 IO(Z180_IO19) +#define IO_ASTC0L IO(Z180_ASTC0L) +#define IO_ASTC0H IO(Z180_ASTC0H) +#define IO_ASTC1L IO(Z180_ASTC1L) +#define IO_ASTC1H IO(Z180_ASTC1H) +#define IO_CMR IO(Z180_CMR) +#define IO_CCR IO(Z180_CCR) +#define IO_SAR0L IO(Z180_SAR0L) +#define IO_SAR0H IO(Z180_SAR0H) +#define IO_SAR0B IO(Z180_SAR0B) +#define IO_DAR0L IO(Z180_DAR0L) +#define IO_DAR0H IO(Z180_DAR0H) +#define IO_DAR0B IO(Z180_DAR0B) +#define IO_BCR0L IO(Z180_BCR0L) +#define IO_BCR0H IO(Z180_BCR0H) +#define IO_MAR1L IO(Z180_MAR1L) +#define IO_MAR1H IO(Z180_MAR1H) +#define IO_MAR1B IO(Z180_MAR1B) +#define IO_IAR1L IO(Z180_IAR1L) +#define IO_IAR1H IO(Z180_IAR1H) +#define IO_IAR1B IO(Z180_IAR1B) +#define IO_BCR1L IO(Z180_BCR1L) +#define IO_BCR1H IO(Z180_BCR1H) +#define IO_DSTAT IO(Z180_DSTAT) +#define IO_DMODE IO(Z180_DMODE) +#define IO_DCNTL IO(Z180_DCNTL) +#define IO_IL IO(Z180_IL) +#define IO_ITC IO(Z180_ITC) +#define IO_IO35 IO(Z180_IO35) +#define IO_RCR IO(Z180_RCR) +#define IO_IO37 IO(Z180_IO37) +#define IO_CBR IO(Z180_CBR) +#define IO_BBR IO(Z180_BBR) +#define IO_CBAR IO(Z180_CBAR) +#define IO_IO3B IO(Z180_IO3B) +#define IO_IO3C IO(Z180_IO3C) +#define IO_IO3D IO(Z180_IO3D) +#define IO_OMCR IO(Z180_OMCR) +#define IO_IOCR IO(Z180_IOCR) + +/* 00 ASCI control register A ch 0 */ +#define Z180_CNTLA0_MPE 0x80 +#define Z180_CNTLA0_RE 0x40 +#define Z180_CNTLA0_TE 0x20 +#define Z180_CNTLA0_RTS0 0x10 +#define Z180_CNTLA0_MPBR_EFR 0x08 +#define Z180_CNTLA0_MODE_DATA 0x04 +#define Z180_CNTLA0_MODE_PARITY 0x02 +#define Z180_CNTLA0_MODE_STOPB 0x01 + +#define Z180_CNTLA0_RESET 0x10 +#define Z180_CNTLA0_RMASK 0xff +#define Z180_CNTLA0_WMASK 0xff + +/* 01 ASCI control register A ch 1 */ +#define Z180_CNTLA1_MPE 0x80 +#define Z180_CNTLA1_RE 0x40 +#define Z180_CNTLA1_TE 0x20 +#define Z180_CNTLA1_CKA1D 0x10 +#define Z180_CNTLA1_MPBR_EFR 0x08 +#define Z180_CNTLA1_MODE 0x07 + +#define Z180_CNTLA1_RESET 0x10 +#define Z180_CNTLA1_RMASK 0xff +#define Z180_CNTLA1_WMASK 0xff + +/* 02 ASCI control register B ch 0 */ +#define Z180_CNTLB0_MPBT 0x80 +#define Z180_CNTLB0_MP 0x40 +#define Z180_CNTLB0_CTS_PS 0x20 +#define Z180_CNTLB0_PEO 0x10 +#define Z180_CNTLB0_DR 0x08 +#define Z180_CNTLB0_SS 0x07 + +#define Z180_CNTLB0_RESET 0x07 +#define Z180_CNTLB0_RMASK 0xff +#define Z180_CNTLB0_WMASK 0xff + +/* 03 ASCI control register B ch 1 */ +#define Z180_CNTLB1_MPBT 0x80 +#define Z180_CNTLB1_MP 0x40 +#define Z180_CNTLB1_CTS_PS 0x20 +#define Z180_CNTLB1_PEO 0x10 +#define Z180_CNTLB1_DR 0x08 +#define Z180_CNTLB1_SS 0x07 + +#define Z180_CNTLB1_RESET 0x07 +#define Z180_CNTLB1_RMASK 0xff +#define Z180_CNTLB1_WMASK 0xff + +/* 04 ASCI status register 0 */ +#define Z180_STAT0_RDRF 0x80 +#define Z180_STAT0_OVRN 0x40 +#define Z180_STAT0_PE 0x20 +#define Z180_STAT0_FE 0x10 +#define Z180_STAT0_RIE 0x08 +#define Z180_STAT0_DCD0 0x04 +#define Z180_STAT0_TDRE 0x02 +#define Z180_STAT0_TIE 0x01 + +#define Z180_STAT0_RESET 0x00 +#define Z180_STAT0_RMASK 0xff +#define Z180_STAT0_WMASK 0x09 + +/* 05 ASCI status register 1 */ +#define Z180_STAT1_RDRF 0x80 +#define Z180_STAT1_OVRN 0x40 +#define Z180_STAT1_PE 0x20 +#define Z180_STAT1_FE 0x10 +#define Z180_STAT1_RIE 0x08 +#define Z180_STAT1_CTS1E 0x04 +#define Z180_STAT1_TDRE 0x02 +#define Z180_STAT1_TIE 0x01 + +#define Z180_STAT1_RESET 0x02 +#define Z180_STAT1_RMASK 0xff +#define Z180_STAT1_WMASK 0x0d + +/* 06 ASCI transmit data register 0 */ +#define Z180_TDR0_TDR 0xff + +#define Z180_TDR0_RESET 0x00 +#define Z180_TDR0_RMASK 0xff +#define Z180_TDR0_WMASK 0xff + +/* 07 ASCI transmit data register 1 */ +#define Z180_TDR1_TDR 0xff + +#define Z180_TDR1_RESET 0x00 +#define Z180_TDR1_RMASK 0xff +#define Z180_TDR1_WMASK 0xff + +/* 08 ASCI receive register 0 */ +#define Z180_RDR0_RDR 0xff + +#define Z180_RDR0_RESET 0x00 +#define Z180_RDR0_RMASK 0xff +#define Z180_RDR0_WMASK 0xff + +/* 09 ASCI receive register 1 */ +#define Z180_RDR1_RDR 0xff + +#define Z180_RDR1_RESET 0x00 +#define Z180_RDR1_RMASK 0xff +#define Z180_RDR1_WMASK 0xff + +/* 0a CSI/O control/status register */ +#define Z180_CNTR_EF 0x80 +#define Z180_CNTR_EIE 0x40 +#define Z180_CNTR_RE 0x20 +#define Z180_CNTR_TE 0x10 +#define Z180_CNTR_SS 0x07 + +#define Z180_CNTR_RESET 0x07 +#define Z180_CNTR_RMASK 0xff +#define Z180_CNTR_WMASK 0x7f + +/* 0b CSI/O transmit/receive register */ +#define Z180_TRDR_RESET 0x00 +#define Z180_TRDR_RMASK 0xff +#define Z180_TRDR_WMASK 0xff + +/* 0c TIMER data register ch 0 L */ +#define Z180_TMDR0L_RESET 0x00 +#define Z180_TMDR0L_RMASK 0xff +#define Z180_TMDR0L_WMASK 0xff + +/* 0d TIMER data register ch 0 H */ +#define Z180_TMDR0H_RESET 0x00 +#define Z180_TMDR0H_RMASK 0xff +#define Z180_TMDR0H_WMASK 0xff + +/* 0e TIMER reload register ch 0 L */ +#define Z180_RLDR0L_RESET 0xff +#define Z180_RLDR0L_RMASK 0xff +#define Z180_RLDR0L_WMASK 0xff + +/* 0f TIMER reload register ch 0 H */ +#define Z180_RLDR0H_RESET 0xff +#define Z180_RLDR0H_RMASK 0xff +#define Z180_RLDR0H_WMASK 0xff + +/* 10 TIMER control register */ +#define Z180_TCR_TIF1 0x80 +#define Z180_TCR_TIF0 0x40 +#define Z180_TCR_TIE1 0x20 +#define Z180_TCR_TIE0 0x10 +#define Z180_TCR_TOC1 0x08 +#define Z180_TCR_TOC0 0x04 +#define Z180_TCR_TDE1 0x02 +#define Z180_TCR_TDE0 0x01 + +#define Z180_TCR_RESET 0x00 +#define Z180_TCR_RMASK 0xff +#define Z180_TCR_WMASK 0x3f + +/* 11 reserved */ +#define Z180_IO11_RESET 0x00 +#define Z180_IO11_RMASK 0xff +#define Z180_IO11_WMASK 0xff + +/* 12 (Z8S180/Z8L180) ASCI extension control register 0 */ +#define Z180_ASEXT0_RDRF 0x80 +#define Z180_ASEXT0_DCD0 0x40 +#define Z180_ASEXT0_CTS0 0x20 +#define Z180_ASEXT0_X1_BIT_CLK0 0x10 +#define Z180_ASEXT0_BRG0_MODE 0x08 +#define Z180_ASEXT0_BRK_EN 0x04 +#define Z180_ASEXT0_BRK_DET 0x02 +#define Z180_ASEXT0_BRK_SEND 0x01 + +#define Z180_ASEXT0_RESET 0x00 +#define Z180_ASEXT0_RMASK 0xff +#define Z180_ASEXT0_WMASK 0xfd + +/* 13 (Z8S180/Z8L180) ASCI extension control register 0 */ +#define Z180_ASEXT1_RDRF 0x80 +#define Z180_ASEXT1_X1_BIT_CLK1 0x10 +#define Z180_ASEXT1_BRG1_MODE 0x08 +#define Z180_ASEXT1_BRK_EN 0x04 +#define Z180_ASEXT1_BRK_DET 0x02 +#define Z180_ASEXT1_BRK_SEND 0x01 + +#define Z180_ASEXT1_RESET 0x00 +#define Z180_ASEXT1_RMASK 0xff +#define Z180_ASEXT1_WMASK 0xfd + + +/* 14 TIMER data register ch 1 L */ +#define Z180_TMDR1L_RESET 0x00 +#define Z180_TMDR1L_RMASK 0xff +#define Z180_TMDR1L_WMASK 0xff + +/* 15 TIMER data register ch 1 H */ +#define Z180_TMDR1H_RESET 0x00 +#define Z180_TMDR1H_RMASK 0xff +#define Z180_TMDR1H_WMASK 0xff + +/* 16 TIMER reload register ch 1 L */ +#define Z180_RLDR1L_RESET 0x00 +#define Z180_RLDR1L_RMASK 0xff +#define Z180_RLDR1L_WMASK 0xff + +/* 17 TIMER reload register ch 1 H */ +#define Z180_RLDR1H_RESET 0x00 +#define Z180_RLDR1H_RMASK 0xff +#define Z180_RLDR1H_WMASK 0xff + +/* 18 free running counter */ +#define Z180_FRC_RESET 0x00 +#define Z180_FRC_RMASK 0xff +#define Z180_FRC_WMASK 0xff + +/* 19 reserved */ +#define Z180_IO19_RESET 0x00 +#define Z180_IO19_RMASK 0xff +#define Z180_IO19_WMASK 0xff + +/* 1a ASCI time constant ch 0 L */ +#define Z180_ASTC0L_RESET 0x00 +#define Z180_ASTC0L_RMASK 0xff +#define Z180_ASTC0L_WMASK 0xff + +/* 1b ASCI time constant ch 0 H */ +#define Z180_ASTC0H_RESET 0x00 +#define Z180_ASTC0H_RMASK 0xff +#define Z180_ASTC0H_WMASK 0xff + +/* 1c ASCI time constant ch 1 L */ +#define Z180_ASTC1L_RESET 0x00 +#define Z180_ASTC1L_RMASK 0xff +#define Z180_ASTC1L_WMASK 0xff + +/* 1d ASCI time constant ch 1 H */ +#define Z180_ASTC1H_RESET 0x00 +#define Z180_ASTC1H_RMASK 0xff +#define Z180_ASTC1H_WMASK 0xff + +/* 1e clock multiplier */ +#define Z180_CMR_X2 0x80 + +#define Z180_CMR_RESET 0x7f +#define Z180_CMR_RMASK 0x80 +#define Z180_CMR_WMASK 0x80 + +/* 1f chip control register */ +#define Z180_CCR_CLOCK_DIVIDE 0x80 +#define Z180_CCR_STDBY_IDLE1 0x40 +#define Z180_CCR_BREXT 0x20 +#define Z180_CCR_LNPHI 0x10 +#define Z180_CCR_STDBY_IDLE0 0x08 +#define Z180_CCR_LNIO 0x04 +#define Z180_CCR_LNCPU_CTL 0x02 +#define Z180_CCR_LNAD_DATA 0x01 + +#define Z180_CCR_RESET 0x00 +#define Z180_CCR_RMASK 0xff +#define Z180_CCR_WMASK 0xff + +/* 20 DMA source address register ch 0 L */ +#define Z180_SAR0L_SAR 0xff + +#define Z180_SAR0L_RESET 0x00 +#define Z180_SAR0L_RMASK 0xff +#define Z180_SAR0L_WMASK 0xff + +/* 21 DMA source address register ch 0 H */ +#define Z180_SAR0H_SAR 0xff + +#define Z180_SAR0H_RESET 0x00 +#define Z180_SAR0H_RMASK 0xff +#define Z180_SAR0H_WMASK 0xff + +/* 22 DMA source address register ch 0 B */ +#define Z180_SAR0B_SAR 0x0f + +#define Z180_SAR0B_RESET 0x00 +#define Z180_SAR0B_RMASK 0x0f +#define Z180_SAR0B_WMASK 0x0f + +/* 23 DMA destination address register ch 0 L */ +#define Z180_DAR0L_DAR 0xff + +#define Z180_DAR0L_RESET 0x00 +#define Z180_DAR0L_RMASK 0xff +#define Z180_DAR0L_WMASK 0xff + +/* 24 DMA destination address register ch 0 H */ +#define Z180_DAR0H_DAR 0xff + +#define Z180_DAR0H_RESET 0x00 +#define Z180_DAR0H_RMASK 0xff +#define Z180_DAR0H_WMASK 0xff + +/* 25 DMA destination address register ch 0 B */ +#define Z180_DAR0B_DAR 0x00 + +#define Z180_DAR0B_RESET 0x00 +#define Z180_DAR0B_RMASK 0x0f +#define Z180_DAR0B_WMASK 0x0f + +/* 26 DMA byte count register ch 0 L */ +#define Z180_BCR0L_BCR 0xff + +#define Z180_BCR0L_RESET 0x00 +#define Z180_BCR0L_RMASK 0xff +#define Z180_BCR0L_WMASK 0xff + +/* 27 DMA byte count register ch 0 H */ +#define Z180_BCR0H_BCR 0xff + +#define Z180_BCR0H_RESET 0x00 +#define Z180_BCR0H_RMASK 0xff +#define Z180_BCR0H_WMASK 0xff + +/* 28 DMA memory address register ch 1 L */ +#define Z180_MAR1L_MAR 0xff + +#define Z180_MAR1L_RESET 0x00 +#define Z180_MAR1L_RMASK 0xff +#define Z180_MAR1L_WMASK 0xff + +/* 29 DMA memory address register ch 1 H */ +#define Z180_MAR1H_MAR 0xff + +#define Z180_MAR1H_RESET 0x00 +#define Z180_MAR1H_RMASK 0xff +#define Z180_MAR1H_WMASK 0xff + +/* 2a DMA memory address register ch 1 B */ +#define Z180_MAR1B_MAR 0x0f + +#define Z180_MAR1B_RESET 0x00 +#define Z180_MAR1B_RMASK 0x0f +#define Z180_MAR1B_WMASK 0x0f + +/* 2b DMA I/O address register ch 1 L */ +#define Z180_IAR1L_IAR 0xff + +#define Z180_IAR1L_RESET 0x00 +#define Z180_IAR1L_RMASK 0xff +#define Z180_IAR1L_WMASK 0xff + +/* 2c DMA I/O address register ch 1 H */ +#define Z180_IAR1H_IAR 0xff + +#define Z180_IAR1H_RESET 0x00 +#define Z180_IAR1H_RMASK 0xff +#define Z180_IAR1H_WMASK 0xff + +/* 2d (Z8S180/Z8L180) DMA I/O address register ch 1 B */ +#define Z180_IAR1B_IAR 0x0f + +#define Z180_IAR1B_RESET 0x00 +#define Z180_IAR1B_RMASK 0x0f +#define Z180_IAR1B_WMASK 0x0f + +/* 2e DMA byte count register ch 1 L */ +#define Z180_BCR1L_BCR 0xff + +#define Z180_BCR1L_RESET 0x00 +#define Z180_BCR1L_RMASK 0xff +#define Z180_BCR1L_WMASK 0xff + +/* 2f DMA byte count register ch 1 H */ +#define Z180_BCR1H_BCR 0xff + +#define Z180_BCR1H_RESET 0x00 +#define Z180_BCR1H_RMASK 0xff +#define Z180_BCR1H_WMASK 0xff + +/* 30 DMA status register */ +#define Z180_DSTAT_DE1 0x80 /* DMA enable ch 1 */ +#define Z180_DSTAT_DE0 0x40 /* DMA enable ch 0 */ +#define Z180_DSTAT_DWE1 0x20 /* DMA write enable ch 0 (active low) */ +#define Z180_DSTAT_DWE0 0x10 /* DMA write enable ch 1 (active low) */ +#define Z180_DSTAT_DIE1 0x08 /* DMA IRQ enable ch 1 */ +#define Z180_DSTAT_DIE0 0x04 /* DMA IRQ enable ch 0 */ +#define Z180_DSTAT_DME 0x01 /* DMA enable (read only) */ + +#define Z180_DSTAT_RESET 0x30 +#define Z180_DSTAT_RMASK 0xfd +#define Z180_DSTAT_WMASK 0xcc + +/* 31 DMA mode register */ +#define Z180_DMODE_DM 0x30 +#define Z180_DMODE_SM 0x0c +#define Z180_DMODE_MMOD 0x04 + +#define Z180_DMODE_RESET 0x00 +#define Z180_DMODE_RMASK 0x3e +#define Z180_DMODE_WMASK 0x3e + +/* 32 DMA/WAIT control register */ +#define Z180_DCNTL_MWI1 0x80 +#define Z180_DCNTL_MWI0 0x40 +#define Z180_DCNTL_IWI1 0x20 +#define Z180_DCNTL_IWI0 0x10 +#define Z180_DCNTL_DMS1 0x08 +#define Z180_DCNTL_DMS0 0x04 +#define Z180_DCNTL_DIM1 0x02 +#define Z180_DCNTL_DIM0 0x01 + +#define Z180_DCNTL_RESET 0x00 +#define Z180_DCNTL_RMASK 0xff +#define Z180_DCNTL_WMASK 0xff + +/* 33 INT vector low register */ +#define Z180_IL_IL 0xe0 + +#define Z180_IL_RESET 0x00 +#define Z180_IL_RMASK 0xe0 +#define Z180_IL_WMASK 0xe0 + +/* 34 INT/TRAP control register */ +#define Z180_ITC_TRAP 0x80 +#define Z180_ITC_UFO 0x40 +#define Z180_ITC_ITE2 0x04 +#define Z180_ITC_ITE1 0x02 +#define Z180_ITC_ITE0 0x01 + +#define Z180_ITC_RESET 0x01 +#define Z180_ITC_RMASK 0xc7 +#define Z180_ITC_WMASK 0x87 + +/* 35 reserved */ +#define Z180_IO35_RESET 0x00 +#define Z180_IO35_RMASK 0xff +#define Z180_IO35_WMASK 0xff + +/* 36 refresh control register */ +#define Z180_RCR_REFE 0x80 +#define Z180_RCR_REFW 0x80 +#define Z180_RCR_CYC 0x03 + +#define Z180_RCR_RESET 0xc0 +#define Z180_RCR_RMASK 0xc3 +#define Z180_RCR_WMASK 0xc3 + +/* 37 reserved */ +#define Z180_IO37_RESET 0x00 +#define Z180_IO37_RMASK 0xff +#define Z180_IO37_WMASK 0xff + +/* 38 MMU common base register */ +#define Z180_CBR_CB 0xff + +#define Z180_CBR_RESET 0x00 +#define Z180_CBR_RMASK 0xff +#define Z180_CBR_WMASK 0xff + +/* 39 MMU bank base register */ +#define Z180_BBR_BB 0xff + +#define Z180_BBR_RESET 0x00 +#define Z180_BBR_RMASK 0xff +#define Z180_BBR_WMASK 0xff + +/* 3a MMU common/bank area register */ +#define Z180_CBAR_CA 0xf0 +#define Z180_CBAR_BA 0x0f + +#define Z180_CBAR_RESET 0xf0 +#define Z180_CBAR_RMASK 0xff +#define Z180_CBAR_WMASK 0xff + +/* 3b reserved */ +#define Z180_IO3B_RESET 0x00 +#define Z180_IO3B_RMASK 0xff +#define Z180_IO3B_WMASK 0xff + +/* 3c reserved */ +#define Z180_IO3C_RESET 0x00 +#define Z180_IO3C_RMASK 0xff +#define Z180_IO3C_WMASK 0xff + +/* 3d reserved */ +#define Z180_IO3D_RESET 0x00 +#define Z180_IO3D_RMASK 0xff +#define Z180_IO3D_WMASK 0xff + +/* 3e operation mode control register */ +#define Z180_OMCR_RESET 0x00 +#define Z180_OMCR_RMASK 0xff +#define Z180_OMCR_WMASK 0xff + +/* 3f I/O control register */ +#define Z180_IOCR_RESET 0x00 +#define Z180_IOCR_RMASK 0xff +#define Z180_IOCR_WMASK 0xff + +/*************************************************************************** + CPU PREFIXES + + order is important here - see z180tbl.h +***************************************************************************/ + +#define Z180_PREFIX_op 0 +#define Z180_PREFIX_cb 1 +#define Z180_PREFIX_dd 2 +#define Z180_PREFIX_ed 3 +#define Z180_PREFIX_fd 4 +#define Z180_PREFIX_xycb 5 + +#define Z180_PREFIX_COUNT (Z180_PREFIX_xycb + 1) + + + +static UINT8 SZ[256]; /* zero and sign flags */ +static UINT8 SZ_BIT[256]; /* zero, sign and parity/overflow (=zero) flags for BIT opcode */ +static UINT8 SZP[256]; /* zero, sign and parity flags */ +static UINT8 SZHV_inc[256]; /* zero, sign, half carry and overflow flags INC r8 */ +static UINT8 SZHV_dec[256]; /* zero, sign, half carry and overflow flags DEC r8 */ + +static UINT8 *SZHVC_add; +static UINT8 *SZHVC_sub; + +#include "z180ops.h" +#include "z180tbl.h" + +#include "z180cb.inc" +#include "z180xy.inc" +#include "z180dd.inc" +#include "z180fd.inc" +#include "z180ed.inc" +#include "z180op.inc" + + +const address_space_config *z180_device::memory_space_config(address_spacenum spacenum) const +{ + switch(spacenum) + { + case AS_PROGRAM: return &m_program_config; + case AS_IO: return &m_io_config; + case AS_DECRYPTED_OPCODES: return has_configured_map(AS_DECRYPTED_OPCODES) ? &m_decrypted_opcodes_config : NULL; + default: return NULL; + } +} + +UINT8 z180_device::z180_readcontrol(offs_t port) +{ + /* normal external readport */ + UINT8 data = m_iospace->read_byte(port); + + /* remap internal I/O registers */ + if((port & (IO_IOCR & 0xc0)) == (IO_IOCR & 0xc0)) + port = port - (IO_IOCR & 0xc0); + + /* but ignore the data and read the internal register */ + switch (port + Z180_CNTLA0) + { + case Z180_CNTLA0: + data = IO_CNTLA0 & Z180_CNTLA0_RMASK; + LOG(("Z180 '%s' CNTLA0 rd $%02x ($%02x)\n", tag(), data, m_io[port & 0x3f])); + break; + + case Z180_CNTLA1: + data = IO_CNTLA1 & Z180_CNTLA1_RMASK; + LOG(("Z180 '%s' CNTLA1 rd $%02x ($%02x)\n", tag(), data, m_io[port & 0x3f])); + break; + + case Z180_CNTLB0: + data = IO_CNTLB0 & Z180_CNTLB0_RMASK; + LOG(("Z180 '%s' CNTLB0 rd $%02x ($%02x)\n", tag(), data, m_io[port & 0x3f])); + break; + + case Z180_CNTLB1: + data = IO_CNTLB1 & Z180_CNTLB1_RMASK; + LOG(("Z180 '%s' CNTLB1 rd $%02x ($%02x)\n", tag(), data, m_io[port & 0x3f])); + break; + + case Z180_STAT0: + data = IO_STAT0 & Z180_STAT0_RMASK; +data |= 0x02; // kludge for 20pacgal + LOG(("Z180 '%s' STAT0 rd $%02x ($%02x)\n", tag(), data, m_io[port & 0x3f])); + break; + + case Z180_STAT1: + data = IO_STAT1 & Z180_STAT1_RMASK; + LOG(("Z180 '%s' STAT1 rd $%02x ($%02x)\n", tag(), data, m_io[port & 0x3f])); + break; + + case Z180_TDR0: + data = IO_TDR0 & Z180_TDR0_RMASK; + LOG(("Z180 '%s' TDR0 rd $%02x ($%02x)\n", tag(), data, m_io[port & 0x3f])); + break; + + case Z180_TDR1: + data = IO_TDR1 & Z180_TDR1_RMASK; + LOG(("Z180 '%s' TDR1 rd $%02x ($%02x)\n", tag(), data, m_io[port & 0x3f])); + break; + + case Z180_RDR0: + data = IO_RDR0 & Z180_RDR0_RMASK; + LOG(("Z180 '%s' RDR0 rd $%02x ($%02x)\n", tag(), data, m_io[port & 0x3f])); + break; + + case Z180_RDR1: + data = IO_RDR1 & Z180_RDR1_RMASK; + LOG(("Z180 '%s' RDR1 rd $%02x ($%02x)\n", tag(), data, m_io[port & 0x3f])); + break; + + case Z180_CNTR: + data = IO_CNTR & Z180_CNTR_RMASK; + data &= ~0x10; // Super Famicom Box sets the TE bit then wants it to be toggled after 8 bits transmitted + LOG(("Z180 '%s' CNTR rd $%02x ($%02x)\n", tag(), data, m_io[port & 0x3f])); + break; + + case Z180_TRDR: + data = IO_TRDR & Z180_TRDR_RMASK; + logerror("Z180 '%s' TRDR rd $%02x ($%02x)\n", tag(), data, m_io[port & 0x3f]); + break; + + case Z180_TMDR0L: + data = m_tmdr_value[0] & Z180_TMDR0L_RMASK; + LOG(("Z180 '%s' TMDR0L rd $%02x ($%02x)\n", tag(), data, m_io[port & 0x3f])); + /* if timer is counting, latch the MSB and set the latch flag */ + if ((IO_TCR & Z180_TCR_TDE0) == 0) + { + m_tmdr_latch |= 1; + m_tmdrh[0] = (m_tmdr_value[0] & 0xff00) >> 8; + } + + if(m_read_tcr_tmdr[0]) + { + m_tif[0] = 0; // reset TIF0 + m_read_tcr_tmdr[0] = 0; + } + else + { + m_read_tcr_tmdr[0] = 1; + } + break; + + case Z180_TMDR0H: + /* read latched value? */ + if (m_tmdr_latch & 1) + { + m_tmdr_latch &= ~1; + data = m_tmdrh[0]; + } + else + { + data = (m_tmdr_value[0] & 0xff00) >> 8; + } + + if(m_read_tcr_tmdr[0]) + { + m_tif[0] = 0; // reset TIF0 + m_read_tcr_tmdr[0] = 0; + } + else + { + m_read_tcr_tmdr[0] = 1; + } + LOG(("Z180 '%s' TMDR0H rd $%02x ($%02x)\n", tag(), data, m_io[port & 0x3f])); + break; + + case Z180_RLDR0L: + data = IO_RLDR0L & Z180_RLDR0L_RMASK; + LOG(("Z180 '%s' RLDR0L rd $%02x ($%02x)\n", tag(), data, m_io[port & 0x3f])); + break; + + case Z180_RLDR0H: + data = IO_RLDR0H & Z180_RLDR0H_RMASK; + LOG(("Z180 '%s' RLDR0H rd $%02x ($%02x)\n", tag(), data, m_io[port & 0x3f])); + break; + + case Z180_TCR: + data = (IO_TCR & Z180_TCR_RMASK) | (m_tif[0] << 6) | (m_tif[1] << 7); + + if(m_read_tcr_tmdr[0]) + { + m_tif[0] = 0; // reset TIF0 + m_read_tcr_tmdr[0] = 0; + } + else + { + m_read_tcr_tmdr[0] = 1; + } + + if(m_read_tcr_tmdr[1]) + { + m_tif[1] = 0; // reset TIF1 + m_read_tcr_tmdr[1] = 0; + } + else + { + m_read_tcr_tmdr[1] = 1; + } + + LOG(("Z180 '%s' TCR rd $%02x ($%02x)\n", tag(), data, m_io[port & 0x3f])); + break; + + case Z180_IO11: + data = IO_IO11 & Z180_IO11_RMASK; + LOG(("Z180 '%s' IO11 rd $%02x ($%02x)\n", tag(), data, m_io[port & 0x3f])); + break; + + case Z180_ASEXT0: + data = IO_ASEXT0 & Z180_ASEXT0_RMASK; + LOG(("Z180 '%s' ASEXT0 rd $%02x ($%02x)\n", tag(), data, m_io[port & 0x3f])); + break; + + case Z180_ASEXT1: + data = IO_ASEXT1 & Z180_ASEXT1_RMASK; + LOG(("Z180 '%s' ASEXT1 rd $%02x ($%02x)\n", tag(), data, m_io[port & 0x3f])); + break; + + case Z180_TMDR1L: + data = m_tmdr_value[1] & Z180_TMDR1L_RMASK; + LOG(("Z180 '%s' TMDR1L rd $%02x ($%02x)\n", tag(), data, m_io[port & 0x3f])); + /* if timer is counting, latch the MSB and set the latch flag */ + if ((IO_TCR & Z180_TCR_TDE1) == 0) + { + m_tmdr_latch |= 2; + m_tmdrh[1] = (m_tmdr_value[1] & 0xff00) >> 8; + } + + if(m_read_tcr_tmdr[1]) + { + m_tif[1] = 0; // reset TIF1 + m_read_tcr_tmdr[1] = 0; + } + else + { + m_read_tcr_tmdr[1] = 1; + } + break; + + case Z180_TMDR1H: + /* read latched value? */ + if (m_tmdr_latch & 2) + { + m_tmdr_latch &= ~2; + data = m_tmdrh[1]; + } + else + { + data = (m_tmdr_value[1] & 0xff00) >> 8; + } + + if(m_read_tcr_tmdr[1]) + { + m_tif[1] = 0; // reset TIF1 + m_read_tcr_tmdr[1] = 0; + } + else + { + m_read_tcr_tmdr[1] = 1; + } + LOG(("Z180 '%s' TMDR1H rd $%02x ($%02x)\n", tag(), data, m_io[port & 0x3f])); + break; + + case Z180_RLDR1L: + data = IO_RLDR1L & Z180_RLDR1L_RMASK; + LOG(("Z180 '%s' RLDR1L rd $%02x ($%02x)\n", tag(), data, m_io[port & 0x3f])); + break; + + case Z180_RLDR1H: + data = IO_RLDR1H & Z180_RLDR1H_RMASK; + LOG(("Z180 '%s' RLDR1H rd $%02x ($%02x)\n", tag(), data, m_io[port & 0x3f])); + break; + + case Z180_FRC: + data = IO_FRC & Z180_FRC_RMASK; + LOG(("Z180 '%s' FRC rd $%02x ($%02x)\n", tag(), data, m_io[port & 0x3f])); + break; + + case Z180_IO19: + data = IO_IO19 & Z180_IO19_RMASK; + LOG(("Z180 '%s' IO19 rd $%02x ($%02x)\n", tag(), data, m_io[port & 0x3f])); + break; + + case Z180_ASTC0L: + data = IO_ASTC0L & Z180_ASTC0L_RMASK; + LOG(("Z180 '%s' ASTC0L rd $%02x ($%02x)\n", tag(), data, m_io[port & 0x3f])); + break; + + case Z180_ASTC0H: + data = IO_ASTC0H & Z180_ASTC0H_RMASK; + LOG(("Z180 '%s' ASTC0H rd $%02x ($%02x)\n", tag(), data, m_io[port & 0x3f])); + break; + + case Z180_ASTC1L: + data = IO_ASTC1L & Z180_ASTC1L_RMASK; + LOG(("Z180 '%s' ASTC1L rd $%02x ($%02x)\n", tag(), data, m_io[port & 0x3f])); + break; + + case Z180_ASTC1H: + data = IO_ASTC1H & Z180_ASTC1H_RMASK; + LOG(("Z180 '%s' ASTC1H rd $%02x ($%02x)\n", tag(), data, m_io[port & 0x3f])); + break; + + case Z180_CMR: + data = IO_CMR & Z180_CMR_RMASK; + LOG(("Z180 '%s' CMR rd $%02x ($%02x)\n", tag(), data, m_io[port & 0x3f])); + break; + + case Z180_CCR: + data = IO_CCR & Z180_CCR_RMASK; + LOG(("Z180 '%s' CCR rd $%02x ($%02x)\n", tag(), data, m_io[port & 0x3f])); + break; + + case Z180_SAR0L: + data = IO_SAR0L & Z180_SAR0L_RMASK; + LOG(("Z180 '%s' SAR0L rd $%02x ($%02x)\n", tag(), data, m_io[port & 0x3f])); + break; + + case Z180_SAR0H: + data = IO_SAR0H & Z180_SAR0H_RMASK; + LOG(("Z180 '%s' SAR0H rd $%02x ($%02x)\n", tag(), data, m_io[port & 0x3f])); + break; + + case Z180_SAR0B: + data = IO_SAR0B & Z180_SAR0B_RMASK; + LOG(("Z180 '%s' SAR0B rd $%02x ($%02x)\n", tag(), data, m_io[port & 0x3f])); + break; + + case Z180_DAR0L: + data = IO_DAR0L & Z180_DAR0L_RMASK; + LOG(("Z180 '%s' DAR0L rd $%02x ($%02x)\n", tag(), data, m_io[port & 0x3f])); + break; + + case Z180_DAR0H: + data = IO_DAR0H & Z180_DAR0H_RMASK; + LOG(("Z180 '%s' DAR0H rd $%02x ($%02x)\n", tag(), data, m_io[port & 0x3f])); + break; + + case Z180_DAR0B: + data = IO_DAR0B & Z180_DAR0B_RMASK; + LOG(("Z180 '%s' DAR0B rd $%02x ($%02x)\n", tag(), data, m_io[port & 0x3f])); + break; + + case Z180_BCR0L: + data = IO_BCR0L & Z180_BCR0L_RMASK; + LOG(("Z180 '%s' BCR0L rd $%02x ($%02x)\n", tag(), data, m_io[port & 0x3f])); + break; + + case Z180_BCR0H: + data = IO_BCR0H & Z180_BCR0H_RMASK; + LOG(("Z180 '%s' BCR0H rd $%02x ($%02x)\n", tag(), data, m_io[port & 0x3f])); + break; + + case Z180_MAR1L: + data = IO_MAR1L & Z180_MAR1L_RMASK; + LOG(("Z180 '%s' MAR1L rd $%02x ($%02x)\n", tag(), data, m_io[port & 0x3f])); + break; + + case Z180_MAR1H: + data = IO_MAR1H & Z180_MAR1H_RMASK; + LOG(("Z180 '%s' MAR1H rd $%02x ($%02x)\n", tag(), data, m_io[port & 0x3f])); + break; + + case Z180_MAR1B: + data = IO_MAR1B & Z180_MAR1B_RMASK; + LOG(("Z180 '%s' MAR1B rd $%02x ($%02x)\n", tag(), data, m_io[port & 0x3f])); + break; + + case Z180_IAR1L: + data = IO_IAR1L & Z180_IAR1L_RMASK; + LOG(("Z180 '%s' IAR1L rd $%02x ($%02x)\n", tag(), data, m_io[port & 0x3f])); + break; + + case Z180_IAR1H: + data = IO_IAR1H & Z180_IAR1H_RMASK; + LOG(("Z180 '%s' IAR1H rd $%02x ($%02x)\n", tag(), data, m_io[port & 0x3f])); + break; + + case Z180_IAR1B: + data = IO_IAR1B & Z180_IAR1B_RMASK; + LOG(("Z180 '%s' IAR1B rd $%02x ($%02x)\n", tag(), data, m_io[port & 0x3f])); + break; + + case Z180_BCR1L: + data = IO_BCR1L & Z180_BCR1L_RMASK; + LOG(("Z180 '%s' BCR1L rd $%02x ($%02x)\n", tag(), data, m_io[port & 0x3f])); + break; + + case Z180_BCR1H: + data = IO_BCR1H & Z180_BCR1H_RMASK; + LOG(("Z180 '%s' BCR1H rd $%02x ($%02x)\n", tag(), data, m_io[port & 0x3f])); + break; + + case Z180_DSTAT: + data = IO_DSTAT & Z180_DSTAT_RMASK; + LOG(("Z180 '%s' DSTAT rd $%02x ($%02x)\n", tag(), data, m_io[port & 0x3f])); + break; + + case Z180_DMODE: + data = IO_DMODE & Z180_DMODE_RMASK; + LOG(("Z180 '%s' DMODE rd $%02x ($%02x)\n", tag(), data, m_io[port & 0x3f])); + break; + + case Z180_DCNTL: + data = IO_DCNTL & Z180_DCNTL_RMASK; + LOG(("Z180 '%s' DCNTL rd $%02x ($%02x)\n", tag(), data, m_io[port & 0x3f])); + break; + + case Z180_IL: + data = IO_IL & Z180_IL_RMASK; + LOG(("Z180 '%s' IL rd $%02x ($%02x)\n", tag(), data, m_io[port & 0x3f])); + break; + + case Z180_ITC: + data = IO_ITC & Z180_ITC_RMASK; + LOG(("Z180 '%s' ITC rd $%02x ($%02x)\n", tag(), data, m_io[port & 0x3f])); + break; + + case Z180_IO35: + data = IO_IO35 & Z180_IO35_RMASK; + LOG(("Z180 '%s' IO35 rd $%02x ($%02x)\n", tag(), data, m_io[port & 0x3f])); + break; + + case Z180_RCR: + data = IO_RCR & Z180_RCR_RMASK; + LOG(("Z180 '%s' RCR rd $%02x ($%02x)\n", tag(), data, m_io[port & 0x3f])); + break; + + case Z180_IO37: + data = IO_IO37 & Z180_IO37_RMASK; + LOG(("Z180 '%s' IO37 rd $%02x ($%02x)\n", tag(), data, m_io[port & 0x3f])); + break; + + case Z180_CBR: + data = IO_CBR & Z180_CBR_RMASK; + LOG(("Z180 '%s' CBR rd $%02x ($%02x)\n", tag(), data, m_io[port & 0x3f])); + break; + + case Z180_BBR: + data = IO_BBR & Z180_BBR_RMASK; + LOG(("Z180 '%s' BBR rd $%02x ($%02x)\n", tag(), data, m_io[port & 0x3f])); + break; + + case Z180_CBAR: + data = IO_CBAR & Z180_CBAR_RMASK; + LOG(("Z180 '%s' CBAR rd $%02x ($%02x)\n", tag(), data, m_io[port & 0x3f])); + break; + + case Z180_IO3B: + data = IO_IO3B & Z180_IO3B_RMASK; + LOG(("Z180 '%s' IO3B rd $%02x ($%02x)\n", tag(), data, m_io[port & 0x3f])); + break; + + case Z180_IO3C: + data = IO_IO3C & Z180_IO3C_RMASK; + LOG(("Z180 '%s' IO3C rd $%02x ($%02x)\n", tag(), data, m_io[port & 0x3f])); + break; + + case Z180_IO3D: + data = IO_IO3D & Z180_IO3D_RMASK; + LOG(("Z180 '%s' IO3D rd $%02x ($%02x)\n", tag(), data, m_io[port & 0x3f])); + break; + + case Z180_OMCR: + data = IO_OMCR & Z180_OMCR_RMASK; + LOG(("Z180 '%s' OMCR rd $%02x ($%02x)\n", tag(), data, m_io[port & 0x3f])); + break; + + case Z180_IOCR: + data = IO_IOCR & Z180_IOCR_RMASK; + LOG(("Z180 '%s' IOCR rd $%02x ($%02x)\n", tag(), data, m_io[port & 0x3f])); + break; + } + + return data; +} + +void z180_device::z180_writecontrol(offs_t port, UINT8 data) +{ + /* normal external write port */ + m_iospace->write_byte(port, data); + + /* remap internal I/O registers */ + if((port & (IO_IOCR & 0xc0)) == (IO_IOCR & 0xc0)) + port = port - (IO_IOCR & 0xc0); + + /* store the data in the internal register */ + switch (port + Z180_CNTLA0) + { + case Z180_CNTLA0: + LOG(("Z180 '%s' CNTLA0 wr $%02x ($%02x)\n", tag(), data, data & Z180_CNTLA0_WMASK)); + IO_CNTLA0 = (IO_CNTLA0 & ~Z180_CNTLA0_WMASK) | (data & Z180_CNTLA0_WMASK); + break; + + case Z180_CNTLA1: + LOG(("Z180 '%s' CNTLA1 wr $%02x ($%02x)\n", tag(), data, data & Z180_CNTLA1_WMASK)); + IO_CNTLA1 = (IO_CNTLA1 & ~Z180_CNTLA1_WMASK) | (data & Z180_CNTLA1_WMASK); + break; + + case Z180_CNTLB0: + LOG(("Z180 '%s' CNTLB0 wr $%02x ($%02x)\n", tag(), data, data & Z180_CNTLB0_WMASK)); + IO_CNTLB0 = (IO_CNTLB0 & ~Z180_CNTLB0_WMASK) | (data & Z180_CNTLB0_WMASK); + break; + + case Z180_CNTLB1: + LOG(("Z180 '%s' CNTLB1 wr $%02x ($%02x)\n", tag(), data, data & Z180_CNTLB1_WMASK)); + IO_CNTLB1 = (IO_CNTLB1 & ~Z180_CNTLB1_WMASK) | (data & Z180_CNTLB1_WMASK); + break; + + case Z180_STAT0: + LOG(("Z180 '%s' STAT0 wr $%02x ($%02x)\n", tag(), data, data & Z180_STAT0_WMASK)); + IO_STAT0 = (IO_STAT0 & ~Z180_STAT0_WMASK) | (data & Z180_STAT0_WMASK); + break; + + case Z180_STAT1: + LOG(("Z180 '%s' STAT1 wr $%02x ($%02x)\n", tag(), data, data & Z180_STAT1_WMASK)); + IO_STAT1 = (IO_STAT1 & ~Z180_STAT1_WMASK) | (data & Z180_STAT1_WMASK); + break; + + case Z180_TDR0: + LOG(("Z180 '%s' TDR0 wr $%02x ($%02x)\n", tag(), data, data & Z180_TDR0_WMASK)); + IO_TDR0 = (IO_TDR0 & ~Z180_TDR0_WMASK) | (data & Z180_TDR0_WMASK); + break; + + case Z180_TDR1: + LOG(("Z180 '%s' TDR1 wr $%02x ($%02x)\n", tag(), data, data & Z180_TDR1_WMASK)); + IO_TDR1 = (IO_TDR1 & ~Z180_TDR1_WMASK) | (data & Z180_TDR1_WMASK); + break; + + case Z180_RDR0: + LOG(("Z180 '%s' RDR0 wr $%02x ($%02x)\n", tag(), data, data & Z180_RDR0_WMASK)); + IO_RDR0 = (IO_RDR0 & ~Z180_RDR0_WMASK) | (data & Z180_RDR0_WMASK); + break; + + case Z180_RDR1: + LOG(("Z180 '%s' RDR1 wr $%02x ($%02x)\n", tag(), data, data & Z180_RDR1_WMASK)); + IO_RDR1 = (IO_RDR1 & ~Z180_RDR1_WMASK) | (data & Z180_RDR1_WMASK); + break; + + case Z180_CNTR: + LOG(("Z180 '%s' CNTR wr $%02x ($%02x)\n", tag(), data, data & Z180_CNTR_WMASK)); + IO_CNTR = (IO_CNTR & ~Z180_CNTR_WMASK) | (data & Z180_CNTR_WMASK); + break; + + case Z180_TRDR: + LOG(("Z180 '%s' TRDR wr $%02x ($%02x)\n", tag(), data, data & Z180_TRDR_WMASK)); + IO_TRDR = (IO_TRDR & ~Z180_TRDR_WMASK) | (data & Z180_TRDR_WMASK); + break; + + case Z180_TMDR0L: + LOG(("Z180 '%s' TMDR0L wr $%02x ($%02x)\n", tag(), data, data & Z180_TMDR0L_WMASK)); + IO_TMDR0L = data & Z180_TMDR0L_WMASK; + m_tmdr_value[0] = (m_tmdr_value[0] & 0xff00) | IO_TMDR0L; + break; + + case Z180_TMDR0H: + LOG(("Z180 '%s' TMDR0H wr $%02x ($%02x)\n", tag(), data, data & Z180_TMDR0H_WMASK)); + IO_TMDR0H = data & Z180_TMDR0H_WMASK; + m_tmdr_value[0] = (m_tmdr_value[0] & 0x00ff) | (IO_TMDR0H << 8); + break; + + case Z180_RLDR0L: + LOG(("Z180 '%s' RLDR0L wr $%02x ($%02x)\n", tag(), data, data & Z180_RLDR0L_WMASK)); + IO_RLDR0L = (IO_RLDR0L & ~Z180_RLDR0L_WMASK) | (data & Z180_RLDR0L_WMASK); + break; + + case Z180_RLDR0H: + LOG(("Z180 '%s' RLDR0H wr $%02x ($%02x)\n", tag(), data, data & Z180_RLDR0H_WMASK)); + IO_RLDR0H = (IO_RLDR0H & ~Z180_RLDR0H_WMASK) | (data & Z180_RLDR0H_WMASK); + break; + + case Z180_TCR: + LOG(("Z180 '%s' TCR wr $%02x ($%02x)\n", tag(), data, data & Z180_TCR_WMASK)); + { + UINT16 old = IO_TCR; + /* Force reload on state change */ + IO_TCR = (IO_TCR & ~Z180_TCR_WMASK) | (data & Z180_TCR_WMASK); + if (!(old & Z180_TCR_TDE0) && (IO_TCR & Z180_TCR_TDE0)) + m_tmdr_value[0] = 0; //IO_RLDR0L | (IO_RLDR0H << 8); + if (!(old & Z180_TCR_TDE1) && (IO_TCR & Z180_TCR_TDE1)) + m_tmdr_value[1] = 0; //IO_RLDR1L | (IO_RLDR1H << 8); + } + + break; + + case Z180_IO11: + LOG(("Z180 '%s' IO11 wr $%02x ($%02x)\n", tag(), data, data & Z180_IO11_WMASK)); + IO_IO11 = (IO_IO11 & ~Z180_IO11_WMASK) | (data & Z180_IO11_WMASK); + break; + + case Z180_ASEXT0: + LOG(("Z180 '%s' ASEXT0 wr $%02x ($%02x)\n", tag(), data, data & Z180_ASEXT0_WMASK)); + IO_ASEXT0 = (IO_ASEXT0 & ~Z180_ASEXT0_WMASK) | (data & Z180_ASEXT0_WMASK); + break; + + case Z180_ASEXT1: + LOG(("Z180 '%s' ASEXT1 wr $%02x ($%02x)\n", tag(), data, data & Z180_ASEXT1_WMASK)); + IO_ASEXT1 = (IO_ASEXT1 & ~Z180_ASEXT1_WMASK) | (data & Z180_ASEXT1_WMASK); + break; + + case Z180_TMDR1L: + LOG(("Z180 '%s' TMDR1L wr $%02x ($%02x)\n", tag(), data, data & Z180_TMDR1L_WMASK)); + IO_TMDR1L = data & Z180_TMDR1L_WMASK; + m_tmdr_value[1] = (m_tmdr_value[1] & 0xff00) | IO_TMDR1L; + break; + + case Z180_TMDR1H: + LOG(("Z180 '%s' TMDR1H wr $%02x ($%02x)\n", tag(), data, data & Z180_TMDR1H_WMASK)); + IO_TMDR1H = data & Z180_TMDR1H_WMASK; + m_tmdr_value[1] = (m_tmdr_value[1] & 0x00ff) | IO_TMDR1H; + break; + + case Z180_RLDR1L: + LOG(("Z180 '%s' RLDR1L wr $%02x ($%02x)\n", tag(), data, data & Z180_RLDR1L_WMASK)); + IO_RLDR1L = (IO_RLDR1L & ~Z180_RLDR1L_WMASK) | (data & Z180_RLDR1L_WMASK); + break; + + case Z180_RLDR1H: + LOG(("Z180 '%s' RLDR1H wr $%02x ($%02x)\n", tag(), data, data & Z180_RLDR1H_WMASK)); + IO_RLDR1H = (IO_RLDR1H & ~Z180_RLDR1H_WMASK) | (data & Z180_RLDR1H_WMASK); + break; + + case Z180_FRC: + LOG(("Z180 '%s' FRC wr $%02x ($%02x)\n", tag(), data, data & Z180_FRC_WMASK)); + IO_FRC = (IO_FRC & ~Z180_FRC_WMASK) | (data & Z180_FRC_WMASK); + break; + + case Z180_IO19: + LOG(("Z180 '%s' IO19 wr $%02x ($%02x)\n", tag(), data, data & Z180_IO19_WMASK)); + IO_IO19 = (IO_IO19 & ~Z180_IO19_WMASK) | (data & Z180_IO19_WMASK); + break; + + case Z180_ASTC0L: + LOG(("Z180 '%s' ASTC0L wr $%02x ($%02x)\n", tag(), data, data & Z180_ASTC0L_WMASK)); + IO_ASTC0L = (IO_ASTC0L & ~Z180_ASTC0L_WMASK) | (data & Z180_ASTC0L_WMASK); + break; + + case Z180_ASTC0H: + LOG(("Z180 '%s' ASTC0H wr $%02x ($%02x)\n", tag(), data, data & Z180_ASTC0H_WMASK)); + IO_ASTC0H = (IO_ASTC0H & ~Z180_ASTC0H_WMASK) | (data & Z180_ASTC0H_WMASK); + break; + + case Z180_ASTC1L: + LOG(("Z180 '%s' ASTC1L wr $%02x ($%02x)\n", tag(), data, data & Z180_ASTC1L_WMASK)); + IO_ASTC1L = (IO_ASTC1L & ~Z180_ASTC1L_WMASK) | (data & Z180_ASTC1L_WMASK); + break; + + case Z180_ASTC1H: + LOG(("Z180 '%s' ASTC1H wr $%02x ($%02x)\n", tag(), data, data & Z180_ASTC1H_WMASK)); + IO_ASTC1H = (IO_ASTC1H & ~Z180_ASTC1H_WMASK) | (data & Z180_ASTC1H_WMASK); + break; + + case Z180_CMR: + LOG(("Z180 '%s' CMR wr $%02x ($%02x)\n", tag(), data, data & Z180_CMR_WMASK)); + IO_CMR = (IO_CMR & ~Z180_CMR_WMASK) | (data & Z180_CMR_WMASK); + break; + + case Z180_CCR: + LOG(("Z180 '%s' CCR wr $%02x ($%02x)\n", tag(), data, data & Z180_CCR_WMASK)); + IO_CCR = (IO_CCR & ~Z180_CCR_WMASK) | (data & Z180_CCR_WMASK); + break; + + case Z180_SAR0L: + LOG(("Z180 '%s' SAR0L wr $%02x ($%02x)\n", tag(), data, data & Z180_SAR0L_WMASK)); + IO_SAR0L = (IO_SAR0L & ~Z180_SAR0L_WMASK) | (data & Z180_SAR0L_WMASK); + break; + + case Z180_SAR0H: + LOG(("Z180 '%s' SAR0H wr $%02x ($%02x)\n", tag(), data, data & Z180_SAR0H_WMASK)); + IO_SAR0H = (IO_SAR0H & ~Z180_SAR0H_WMASK) | (data & Z180_SAR0H_WMASK); + break; + + case Z180_SAR0B: + LOG(("Z180 '%s' SAR0B wr $%02x ($%02x)\n", tag(), data, data & Z180_SAR0B_WMASK)); + IO_SAR0B = (IO_SAR0B & ~Z180_SAR0B_WMASK) | (data & Z180_SAR0B_WMASK); + break; + + case Z180_DAR0L: + LOG(("Z180 '%s' DAR0L wr $%02x ($%02x)\n", tag(), data, data & Z180_DAR0L_WMASK)); + IO_DAR0L = (IO_DAR0L & ~Z180_DAR0L_WMASK) | (data & Z180_DAR0L_WMASK); + break; + + case Z180_DAR0H: + LOG(("Z180 '%s' DAR0H wr $%02x ($%02x)\n", tag(), data, data & Z180_DAR0H_WMASK)); + IO_DAR0H = (IO_DAR0H & ~Z180_DAR0H_WMASK) | (data & Z180_DAR0H_WMASK); + break; + + case Z180_DAR0B: + LOG(("Z180 '%s' DAR0B wr $%02x ($%02x)\n", tag(), data, data & Z180_DAR0B_WMASK)); + IO_DAR0B = (IO_DAR0B & ~Z180_DAR0B_WMASK) | (data & Z180_DAR0B_WMASK); + break; + + case Z180_BCR0L: + LOG(("Z180 '%s' BCR0L wr $%02x ($%02x)\n", tag(), data, data & Z180_BCR0L_WMASK)); + IO_BCR0L = (IO_BCR0L & ~Z180_BCR0L_WMASK) | (data & Z180_BCR0L_WMASK); + break; + + case Z180_BCR0H: + LOG(("Z180 '%s' BCR0H wr $%02x ($%02x)\n", tag(), data, data & Z180_BCR0H_WMASK)); + IO_BCR0H = (IO_BCR0H & ~Z180_BCR0H_WMASK) | (data & Z180_BCR0H_WMASK); + break; + + case Z180_MAR1L: + LOG(("Z180 '%s' MAR1L wr $%02x ($%02x)\n", tag(), data, data & Z180_MAR1L_WMASK)); + IO_MAR1L = (IO_MAR1L & ~Z180_MAR1L_WMASK) | (data & Z180_MAR1L_WMASK); + break; + + case Z180_MAR1H: + LOG(("Z180 '%s' MAR1H wr $%02x ($%02x)\n", tag(), data, data & Z180_MAR1H_WMASK)); + IO_MAR1H = (IO_MAR1H & ~Z180_MAR1H_WMASK) | (data & Z180_MAR1H_WMASK); + break; + + case Z180_MAR1B: + LOG(("Z180 '%s' MAR1B wr $%02x ($%02x)\n", tag(), data, data & Z180_MAR1B_WMASK)); + IO_MAR1B = (IO_MAR1B & ~Z180_MAR1B_WMASK) | (data & Z180_MAR1B_WMASK); + break; + + case Z180_IAR1L: + LOG(("Z180 '%s' IAR1L wr $%02x ($%02x)\n", tag(), data, data & Z180_IAR1L_WMASK)); + IO_IAR1L = (IO_IAR1L & ~Z180_IAR1L_WMASK) | (data & Z180_IAR1L_WMASK); + break; + + case Z180_IAR1H: + LOG(("Z180 '%s' IAR1H wr $%02x ($%02x)\n", tag(), data, data & Z180_IAR1H_WMASK)); + IO_IAR1H = (IO_IAR1H & ~Z180_IAR1H_WMASK) | (data & Z180_IAR1H_WMASK); + break; + + case Z180_IAR1B: + LOG(("Z180 '%s' IAR1B wr $%02x ($%02x)\n", tag(), data, data & Z180_IAR1B_WMASK)); + IO_IAR1B = (IO_IAR1B & ~Z180_IAR1B_WMASK) | (data & Z180_IAR1B_WMASK); + break; + + case Z180_BCR1L: + LOG(("Z180 '%s' BCR1L wr $%02x ($%02x)\n", tag(), data, data & Z180_BCR1L_WMASK)); + IO_BCR1L = (IO_BCR1L & ~Z180_BCR1L_WMASK) | (data & Z180_BCR1L_WMASK); + break; + + case Z180_BCR1H: + LOG(("Z180 '%s' BCR1H wr $%02x ($%02x)\n", tag(), data, data & Z180_BCR1H_WMASK)); + IO_BCR1H = (IO_BCR1H & ~Z180_BCR1H_WMASK) | (data & Z180_BCR1H_WMASK); + break; + + case Z180_DSTAT: + LOG(("Z180 '%s' DSTAT wr $%02x ($%02x)\n", tag(), data, data & Z180_DSTAT_WMASK)); + IO_DSTAT = (IO_DSTAT & ~Z180_DSTAT_WMASK) | (data & Z180_DSTAT_WMASK); + if ((data & (Z180_DSTAT_DE1 | Z180_DSTAT_DWE1)) == Z180_DSTAT_DE1) + IO_DSTAT |= Z180_DSTAT_DME; /* DMA enable */ + if ((data & (Z180_DSTAT_DE0 | Z180_DSTAT_DWE0)) == Z180_DSTAT_DE0) + IO_DSTAT |= Z180_DSTAT_DME; /* DMA enable */ + break; + + case Z180_DMODE: + LOG(("Z180 '%s' DMODE wr $%02x ($%02x)\n", tag(), data, data & Z180_DMODE_WMASK)); + IO_DMODE = (IO_DMODE & ~Z180_DMODE_WMASK) | (data & Z180_DMODE_WMASK); + break; + + case Z180_DCNTL: + LOG(("Z180 '%s' DCNTL wr $%02x ($%02x)\n", tag(), data, data & Z180_DCNTL_WMASK)); + IO_DCNTL = (IO_DCNTL & ~Z180_DCNTL_WMASK) | (data & Z180_DCNTL_WMASK); + break; + + case Z180_IL: + LOG(("Z180 '%s' IL wr $%02x ($%02x)\n", tag(), data, data & Z180_IL_WMASK)); + IO_IL = (IO_IL & ~Z180_IL_WMASK) | (data & Z180_IL_WMASK); + break; + + case Z180_ITC: + LOG(("Z180 '%s' ITC wr $%02x ($%02x)\n", tag(), data, data & Z180_ITC_WMASK)); + IO_ITC = (IO_ITC & ~Z180_ITC_WMASK) | (data & Z180_ITC_WMASK); + break; + + case Z180_IO35: + LOG(("Z180 '%s' IO35 wr $%02x ($%02x)\n", tag(), data, data & Z180_IO35_WMASK)); + IO_IO35 = (IO_IO35 & ~Z180_IO35_WMASK) | (data & Z180_IO35_WMASK); + break; + + case Z180_RCR: + LOG(("Z180 '%s' RCR wr $%02x ($%02x)\n", tag(), data, data & Z180_RCR_WMASK)); + IO_RCR = (IO_RCR & ~Z180_RCR_WMASK) | (data & Z180_RCR_WMASK); + break; + + case Z180_IO37: + LOG(("Z180 '%s' IO37 wr $%02x ($%02x)\n", tag(), data, data & Z180_IO37_WMASK)); + IO_IO37 = (IO_IO37 & ~Z180_IO37_WMASK) | (data & Z180_IO37_WMASK); + break; + + case Z180_CBR: + LOG(("Z180 '%s' CBR wr $%02x ($%02x)\n", tag(), data, data & Z180_CBR_WMASK)); + IO_CBR = (IO_CBR & ~Z180_CBR_WMASK) | (data & Z180_CBR_WMASK); + z180_mmu(); + break; + + case Z180_BBR: + LOG(("Z180 '%s' BBR wr $%02x ($%02x)\n", tag(), data, data & Z180_BBR_WMASK)); + IO_BBR = (IO_BBR & ~Z180_BBR_WMASK) | (data & Z180_BBR_WMASK); + z180_mmu(); + break; + + case Z180_CBAR: + LOG(("Z180 '%s' CBAR wr $%02x ($%02x)\n", tag(), data, data & Z180_CBAR_WMASK)); + IO_CBAR = (IO_CBAR & ~Z180_CBAR_WMASK) | (data & Z180_CBAR_WMASK); + z180_mmu(); + break; + + case Z180_IO3B: + LOG(("Z180 '%s' IO3B wr $%02x ($%02x)\n", tag(), data, data & Z180_IO3B_WMASK)); + IO_IO3B = (IO_IO3B & ~Z180_IO3B_WMASK) | (data & Z180_IO3B_WMASK); + break; + + case Z180_IO3C: + LOG(("Z180 '%s' IO3C wr $%02x ($%02x)\n", tag(), data, data & Z180_IO3C_WMASK)); + IO_IO3C = (IO_IO3C & ~Z180_IO3C_WMASK) | (data & Z180_IO3C_WMASK); + break; + + case Z180_IO3D: + LOG(("Z180 '%s' IO3D wr $%02x ($%02x)\n", tag(), data, data & Z180_IO3D_WMASK)); + IO_IO3D = (IO_IO3D & ~Z180_IO3D_WMASK) | (data & Z180_IO3D_WMASK); + break; + + case Z180_OMCR: + LOG(("Z180 '%s' OMCR wr $%02x ($%02x)\n", tag(), data, data & Z180_OMCR_WMASK)); + IO_OMCR = (IO_OMCR & ~Z180_OMCR_WMASK) | (data & Z180_OMCR_WMASK); + break; + + case Z180_IOCR: + LOG(("Z180 '%s' IOCR wr $%02x ($%02x)\n", tag(), data, data & Z180_IOCR_WMASK)); + IO_IOCR = (IO_IOCR & ~Z180_IOCR_WMASK) | (data & Z180_IOCR_WMASK); + break; + } +} + +int z180_device::z180_dma0(int max_cycles) +{ + offs_t sar0 = 65536 * IO_SAR0B + 256 * IO_SAR0H + IO_SAR0L; + offs_t dar0 = 65536 * IO_DAR0B + 256 * IO_DAR0H + IO_DAR0L; + int bcr0 = 256 * IO_BCR0H + IO_BCR0L; + int count = (IO_DMODE & Z180_DMODE_MMOD) ? bcr0 : 1; + int cycles = 0; + + if (bcr0 == 0) + { + IO_DSTAT &= ~Z180_DSTAT_DE0; + return 0; + } + + while (count-- > 0) + { + /* last transfer happening now? */ + if (bcr0 == 1) + { + m_iol |= Z180_TEND0; + } + switch( IO_DMODE & (Z180_DMODE_SM | Z180_DMODE_DM) ) + { + case 0x00: /* memory SAR0+1 to memory DAR0+1 */ + m_program->write_byte(dar0++, m_program->read_byte(sar0++)); + break; + case 0x04: /* memory SAR0-1 to memory DAR0+1 */ + m_program->write_byte(dar0++, m_program->read_byte(sar0--)); + break; + case 0x08: /* memory SAR0 fixed to memory DAR0+1 */ + m_program->write_byte(dar0++, m_program->read_byte(sar0)); + break; + case 0x0c: /* I/O SAR0 fixed to memory DAR0+1 */ + if (m_iol & Z180_DREQ0) + { + m_program->write_byte(dar0++, IN(sar0)); + /* edge sensitive DREQ0 ? */ + if (IO_DCNTL & Z180_DCNTL_DIM0) + { + m_iol &= ~Z180_DREQ0; + count = 0; + } + } + break; + case 0x10: /* memory SAR0+1 to memory DAR0-1 */ + m_program->write_byte(dar0--, m_program->read_byte(sar0++)); + break; + case 0x14: /* memory SAR0-1 to memory DAR0-1 */ + m_program->write_byte(dar0--, m_program->read_byte(sar0--)); + break; + case 0x18: /* memory SAR0 fixed to memory DAR0-1 */ + m_program->write_byte(dar0--, m_program->read_byte(sar0)); + break; + case 0x1c: /* I/O SAR0 fixed to memory DAR0-1 */ + if (m_iol & Z180_DREQ0) + { + m_program->write_byte(dar0--, IN(sar0)); + /* edge sensitive DREQ0 ? */ + if (IO_DCNTL & Z180_DCNTL_DIM0) + { + m_iol &= ~Z180_DREQ0; + count = 0; + } + } + break; + case 0x20: /* memory SAR0+1 to memory DAR0 fixed */ + m_program->write_byte(dar0, m_program->read_byte(sar0++)); + break; + case 0x24: /* memory SAR0-1 to memory DAR0 fixed */ + m_program->write_byte(dar0, m_program->read_byte(sar0--)); + break; + case 0x28: /* reserved */ + break; + case 0x2c: /* reserved */ + break; + case 0x30: /* memory SAR0+1 to I/O DAR0 fixed */ + if (m_iol & Z180_DREQ0) + { + OUT(dar0, m_program->read_byte(sar0++)); + /* edge sensitive DREQ0 ? */ + if (IO_DCNTL & Z180_DCNTL_DIM0) + { + m_iol &= ~Z180_DREQ0; + count = 0; + } + } + break; + case 0x34: /* memory SAR0-1 to I/O DAR0 fixed */ + if (m_iol & Z180_DREQ0) + { + OUT(dar0, m_program->read_byte(sar0--)); + /* edge sensitive DREQ0 ? */ + if (IO_DCNTL & Z180_DCNTL_DIM0) + { + m_iol &= ~Z180_DREQ0; + count = 0; + } + } + break; + case 0x38: /* reserved */ + break; + case 0x3c: /* reserved */ + break; + } + bcr0--; + count--; + cycles += 6; + if (cycles > max_cycles) + break; + } + + IO_SAR0L = sar0; + IO_SAR0H = sar0 >> 8; + IO_SAR0B = sar0 >> 16; + IO_DAR0L = dar0; + IO_DAR0H = dar0 >> 8; + IO_DAR0B = dar0 >> 16; + IO_BCR0L = bcr0; + IO_BCR0H = bcr0 >> 8; + + /* DMA terminal count? */ + if (bcr0 == 0) + { + m_iol &= ~Z180_TEND0; + IO_DSTAT &= ~Z180_DSTAT_DE0; + /* terminal count interrupt enabled? */ + if (IO_DSTAT & Z180_DSTAT_DIE0 && m_IFF1) + m_int_pending[Z180_INT_DMA0] = 1; + } + return cycles; +} + +int z180_device::z180_dma1() +{ + offs_t mar1 = 65536 * IO_MAR1B + 256 * IO_MAR1H + IO_MAR1L; + offs_t iar1 = 256 * IO_IAR1H + IO_IAR1L; + int bcr1 = 256 * IO_BCR1H + IO_BCR1L; + int cycles = 0; + + if ((m_iol & Z180_DREQ1) == 0) + return 0; + + /* counter is zero? */ + if (bcr1 == 0) + { + IO_DSTAT &= ~Z180_DSTAT_DE1; + return 0; + } + + /* last transfer happening now? */ + if (bcr1 == 1) + { + m_iol |= Z180_TEND1; + } + + switch (IO_DCNTL & (Z180_DCNTL_DIM1 | Z180_DCNTL_DIM0)) + { + case 0x00: /* memory MAR1+1 to I/O IAR1 fixed */ + m_iospace->write_byte(iar1, m_program->read_byte(mar1++)); + break; + case 0x01: /* memory MAR1-1 to I/O IAR1 fixed */ + m_iospace->write_byte(iar1, m_program->read_byte(mar1--)); + break; + case 0x02: /* I/O IAR1 fixed to memory MAR1+1 */ + m_program->write_byte(mar1++, m_iospace->read_byte(iar1)); + break; + case 0x03: /* I/O IAR1 fixed to memory MAR1-1 */ + m_program->write_byte(mar1--, m_iospace->read_byte(iar1)); + break; + } + + /* edge sensitive DREQ1 ? */ + if (IO_DCNTL & Z180_DCNTL_DIM1) + m_iol &= ~Z180_DREQ1; + + IO_MAR1L = mar1; + IO_MAR1H = mar1 >> 8; + IO_MAR1B = mar1 >> 16; + IO_BCR1L = bcr1; + IO_BCR1H = bcr1 >> 8; + + /* DMA terminal count? */ + if (bcr1 == 0) + { + m_iol &= ~Z180_TEND1; + IO_DSTAT &= ~Z180_DSTAT_DE1; + if (IO_DSTAT & Z180_DSTAT_DIE1 && m_IFF1) + m_int_pending[Z180_INT_DMA1] = 1; + } + + /* six cycles per transfer (minimum) */ + return 6 + cycles; +} + +void z180_device::z180_write_iolines(UINT32 data) +{ + UINT32 changes = m_iol ^ data; + + /* I/O asynchronous clock 0 (active high) or DREQ0 (mux) */ + if (changes & Z180_CKA0) + { + LOG(("Z180 '%s' CKA0 %d\n", tag(), data & Z180_CKA0 ? 1 : 0)); + m_iol = (m_iol & ~Z180_CKA0) | (data & Z180_CKA0); + } + + /* I/O asynchronous clock 1 (active high) or TEND1 (mux) */ + if (changes & Z180_CKA1) + { + LOG(("Z180 '%s' CKA1 %d\n", tag(), data & Z180_CKA1 ? 1 : 0)); + m_iol = (m_iol & ~Z180_CKA1) | (data & Z180_CKA1); + } + + /* I/O serial clock (active high) */ + if (changes & Z180_CKS) + { + LOG(("Z180 '%s' CKS %d\n", tag(), data & Z180_CKS ? 1 : 0)); + m_iol = (m_iol & ~Z180_CKS) | (data & Z180_CKS); + } + + /* I clear to send 0 (active low) */ + if (changes & Z180_CTS0) + { + LOG(("Z180 '%s' CTS0 %d\n", tag(), data & Z180_CTS0 ? 1 : 0)); + m_iol = (m_iol & ~Z180_CTS0) | (data & Z180_CTS0); + } + + /* I clear to send 1 (active low) or RXS (mux) */ + if (changes & Z180_CTS1) + { + LOG(("Z180 '%s' CTS1 %d\n", tag(), data & Z180_CTS1 ? 1 : 0)); + m_iol = (m_iol & ~Z180_CTS1) | (data & Z180_CTS1); + } + + /* I data carrier detect (active low) */ + if (changes & Z180_DCD0) + { + LOG(("Z180 '%s' DCD0 %d\n", tag(), data & Z180_DCD0 ? 1 : 0)); + m_iol = (m_iol & ~Z180_DCD0) | (data & Z180_DCD0); + } + + /* I data request DMA ch 0 (active low) or CKA0 (mux) */ + if (changes & Z180_DREQ0) + { + LOG(("Z180 '%s' DREQ0 %d\n", tag(), data & Z180_DREQ0 ? 1 : 0)); + m_iol = (m_iol & ~Z180_DREQ0) | (data & Z180_DREQ0); + } + + /* I data request DMA ch 1 (active low) */ + if (changes & Z180_DREQ1) + { + LOG(("Z180 '%s' DREQ1 %d\n", tag(), data & Z180_DREQ1 ? 1 : 0)); + m_iol = (m_iol & ~Z180_DREQ1) | (data & Z180_DREQ1); + } + + /* I asynchronous receive data 0 (active high) */ + if (changes & Z180_RXA0) + { + LOG(("Z180 '%s' RXA0 %d\n", tag(), data & Z180_RXA0 ? 1 : 0)); + m_iol = (m_iol & ~Z180_RXA0) | (data & Z180_RXA0); + } + + /* I asynchronous receive data 1 (active high) */ + if (changes & Z180_RXA1) + { + LOG(("Z180 '%s' RXA1 %d\n", tag(), data & Z180_RXA1 ? 1 : 0)); + m_iol = (m_iol & ~Z180_RXA1) | (data & Z180_RXA1); + } + + /* I clocked serial receive data (active high) or CTS1 (mux) */ + if (changes & Z180_RXS) + { + LOG(("Z180 '%s' RXS %d\n", tag(), data & Z180_RXS ? 1 : 0)); + m_iol = (m_iol & ~Z180_RXS) | (data & Z180_RXS); + } + + /* O request to send (active low) */ + if (changes & Z180_RTS0) + { + LOG(("Z180 '%s' RTS0 won't change output\n", tag())); + } + + /* O transfer end 0 (active low) or CKA1 (mux) */ + if (changes & Z180_TEND0) + { + LOG(("Z180 '%s' TEND0 won't change output\n", tag())); + } + + /* O transfer end 1 (active low) */ + if (changes & Z180_TEND1) + { + LOG(("Z180 '%s' TEND1 won't change output\n", tag())); + } + + /* O transfer out (PRT channel, active low) or A18 (mux) */ + if (changes & Z180_A18_TOUT) + { + LOG(("Z180 '%s' TOUT won't change output\n", tag())); + } + + /* O asynchronous transmit data 0 (active high) */ + if (changes & Z180_TXA0) + { + LOG(("Z180 '%s' TXA0 won't change output\n", tag())); + } + + /* O asynchronous transmit data 1 (active high) */ + if (changes & Z180_TXA1) + { + LOG(("Z180 '%s' TXA1 won't change output\n", tag())); + } + + /* O clocked serial transmit data (active high) */ + if (changes & Z180_TXS) + { + LOG(("Z180 '%s' TXS won't change output\n", tag())); + } +} + + +void z180_device::device_start() +{ + int i, p; + int oldval, newval, val; + UINT8 *padd, *padc, *psub, *psbc; + + if (static_config() != NULL) + { + m_daisy.init(this, (const z80_daisy_config *)static_config()); + } + + /* allocate big flag arrays once */ + SZHVC_add = auto_alloc_array(machine(), UINT8, 2*256*256); + SZHVC_sub = auto_alloc_array(machine(), UINT8, 2*256*256); + + padd = &SZHVC_add[ 0*256]; + padc = &SZHVC_add[256*256]; + psub = &SZHVC_sub[ 0*256]; + psbc = &SZHVC_sub[256*256]; + for (oldval = 0; oldval < 256; oldval++) + { + for (newval = 0; newval < 256; newval++) + { + /* add or adc w/o carry set */ + val = newval - oldval; + *padd = (newval) ? ((newval & 0x80) ? SF : 0) : ZF; + *padd |= (newval & (YF | XF)); /* undocumented flag bits 5+3 */ + + if( (newval & 0x0f) < (oldval & 0x0f) ) *padd |= HF; + if( newval < oldval ) *padd |= CF; + if( (val^oldval^0x80) & (val^newval) & 0x80 ) *padd |= VF; + padd++; + + /* adc with carry set */ + val = newval - oldval - 1; + *padc = (newval) ? ((newval & 0x80) ? SF : 0) : ZF; + *padc |= (newval & (YF | XF)); /* undocumented flag bits 5+3 */ + if( (newval & 0x0f) <= (oldval & 0x0f) ) *padc |= HF; + if( newval <= oldval ) *padc |= CF; + if( (val^oldval^0x80) & (val^newval) & 0x80 ) *padc |= VF; + padc++; + + /* cp, sub or sbc w/o carry set */ + val = oldval - newval; + *psub = NF | ((newval) ? ((newval & 0x80) ? SF : 0) : ZF); + *psub |= (newval & (YF | XF)); /* undocumented flag bits 5+3 */ + if( (newval & 0x0f) > (oldval & 0x0f) ) *psub |= HF; + if( newval > oldval ) *psub |= CF; + if( (val^oldval) & (oldval^newval) & 0x80 ) *psub |= VF; + psub++; + + /* sbc with carry set */ + val = oldval - newval - 1; + *psbc = NF | ((newval) ? ((newval & 0x80) ? SF : 0) : ZF); + *psbc |= (newval & (YF | XF)); /* undocumented flag bits 5+3 */ + if( (newval & 0x0f) >= (oldval & 0x0f) ) *psbc |= HF; + if( newval >= oldval ) *psbc |= CF; + if( (val^oldval) & (oldval^newval) & 0x80 ) *psbc |= VF; + psbc++; + } + } + for (i = 0; i < 256; i++) + { + p = 0; + if( i&0x01 ) ++p; + if( i&0x02 ) ++p; + if( i&0x04 ) ++p; + if( i&0x08 ) ++p; + if( i&0x10 ) ++p; + if( i&0x20 ) ++p; + if( i&0x40 ) ++p; + if( i&0x80 ) ++p; + SZ[i] = i ? i & SF : ZF; + SZ[i] |= (i & (YF | XF)); /* undocumented flag bits 5+3 */ + SZ_BIT[i] = i ? i & SF : ZF | PF; + SZ_BIT[i] |= (i & (YF | XF)); /* undocumented flag bits 5+3 */ + SZP[i] = SZ[i] | ((p & 1) ? 0 : PF); + SZHV_inc[i] = SZ[i]; + if( i == 0x80 ) SZHV_inc[i] |= VF; + if( (i & 0x0f) == 0x00 ) SZHV_inc[i] |= HF; + SZHV_dec[i] = SZ[i] | NF; + if( i == 0x7f ) SZHV_dec[i] |= VF; + if( (i & 0x0f) == 0x0f ) SZHV_dec[i] |= HF; + } + + m_program = &space(AS_PROGRAM); + m_direct = &m_program->direct(); + m_oprogram = has_space(AS_DECRYPTED_OPCODES) ? &space(AS_DECRYPTED_OPCODES) : m_program; + m_odirect = &m_oprogram->direct(); + m_iospace = &space(AS_IO); + + /* set up the state table */ + { + state_add(Z180_PC, "PC", m_PC.w.l); + state_add(STATE_GENPC, "GENPC", _PCD).noshow(); + state_add(STATE_GENPCBASE, "GENPCBASE", m_PREPC.w.l).noshow(); + state_add(Z180_SP, "SP", _SPD); + state_add(STATE_GENSP, "GENSP", m_SP.w.l).noshow(); + state_add(STATE_GENFLAGS, "GENFLAGS", m_AF.b.l).noshow().formatstr("%8s"); + state_add(Z180_A, "A", _A).noshow(); + state_add(Z180_B, "B", _B).noshow(); + state_add(Z180_C, "C", _C).noshow(); + state_add(Z180_D, "D", _D).noshow(); + state_add(Z180_E, "E", _E).noshow(); + state_add(Z180_H, "H", _H).noshow(); + state_add(Z180_L, "L", _L).noshow(); + state_add(Z180_AF, "AF", m_AF.w.l); + state_add(Z180_BC, "BC", m_BC.w.l); + state_add(Z180_DE, "DE", m_DE.w.l); + state_add(Z180_HL, "HL", m_HL.w.l); + state_add(Z180_IX, "IX", m_IX.w.l); + state_add(Z180_IY, "IY", m_IY.w.l); + state_add(Z180_AF2, "AF2", m_AF2.w.l); + state_add(Z180_BC2, "BC2", m_BC2.w.l); + state_add(Z180_DE2, "DE2", m_DE2.w.l); + state_add(Z180_HL2, "HL2", m_HL2.w.l); + state_add(Z180_R, "R", m_rtemp).callimport().callexport(); + state_add(Z180_I, "I", m_I); + state_add(Z180_IM, "IM", m_IM).mask(0x3); + state_add(Z180_IFF1, "IFF1", m_IFF1).mask(0x1); + state_add(Z180_IFF2, "IFF2", m_IFF2).mask(0x1); + state_add(Z180_HALT, "HALT", m_HALT).mask(0x1); + + state_add(Z180_IOLINES, "IOLINES", m_ioltemp).mask(0xffffff).callimport(); + + state_add(Z180_CNTLA0, "CNTLA0", IO_CNTLA0); + state_add(Z180_CNTLA1, "CNTLA1", IO_CNTLA1); + state_add(Z180_CNTLB0, "CNTLB0", IO_CNTLB0); + state_add(Z180_CNTLB1, "CNTLB1", IO_CNTLB1); + state_add(Z180_STAT0, "STAT0", IO_STAT0); + state_add(Z180_STAT1, "STAT1", IO_STAT1); + state_add(Z180_TDR0, "TDR0", IO_TDR0); + state_add(Z180_TDR1, "TDR1", IO_TDR1); + state_add(Z180_RDR0, "RDR0", IO_RDR0); + state_add(Z180_RDR1, "RDR1", IO_RDR1); + state_add(Z180_CNTR, "CNTR", IO_CNTR); + state_add(Z180_TRDR, "TRDR", IO_TRDR); + state_add(Z180_TMDR0L, "TMDR0L", IO_TMDR0L); + state_add(Z180_TMDR0H, "TMDR0H", IO_TMDR0H); + state_add(Z180_RLDR0L, "RLDR0L", IO_RLDR0L); + state_add(Z180_RLDR0H, "RLDR0H", IO_RLDR0H); + state_add(Z180_TCR, "TCR", IO_TCR); + state_add(Z180_IO11, "IO11", IO_IO11); + state_add(Z180_ASEXT0, "ASEXT0", IO_ASEXT0); + state_add(Z180_ASEXT1, "ASEXT1", IO_ASEXT1); + state_add(Z180_TMDR1L, "TMDR1L", IO_TMDR1L); + state_add(Z180_TMDR1H, "TMDR1H", IO_TMDR1H); + state_add(Z180_RLDR1L, "RLDR1L", IO_RLDR1L); + state_add(Z180_RLDR1H, "RLDR1H", IO_RLDR1H); + state_add(Z180_FRC, "FRC", IO_FRC); + state_add(Z180_IO19, "IO19", IO_IO19); + state_add(Z180_ASTC0L, "ASTC0L", IO_ASTC0L); + state_add(Z180_ASTC0H, "ASTC0H", IO_ASTC0H); + state_add(Z180_ASTC1L, "ASTC1L", IO_ASTC1L); + state_add(Z180_ASTC1H, "ASTC1H", IO_ASTC1H); + state_add(Z180_CMR, "CMR", IO_CMR); + state_add(Z180_CCR, "CCR", IO_CCR); + state_add(Z180_SAR0L, "SAR0L", IO_SAR0L); + state_add(Z180_SAR0H, "SAR0H", IO_SAR0H); + state_add(Z180_SAR0B, "SAR0B", IO_SAR0B); + state_add(Z180_DAR0L, "DAR0L", IO_DAR0L); + state_add(Z180_DAR0H, "DAR0H", IO_DAR0H); + state_add(Z180_DAR0B, "DAR0B", IO_DAR0B); + state_add(Z180_BCR0L, "BCR0L", IO_BCR0L); + state_add(Z180_BCR0H, "BCR0H", IO_BCR0H); + state_add(Z180_MAR1L, "MAR1L", IO_MAR1L); + state_add(Z180_MAR1H, "MAR1H", IO_MAR1H); + state_add(Z180_MAR1B, "MAR1B", IO_MAR1B); + state_add(Z180_IAR1L, "IAR1L", IO_IAR1L); + state_add(Z180_IAR1H, "IAR1H", IO_IAR1H); + state_add(Z180_IAR1B, "IAR1B", IO_IAR1B); + state_add(Z180_BCR1L, "BCR1L", IO_BCR1L); + state_add(Z180_BCR1H, "BCR1H", IO_BCR1H); + state_add(Z180_DSTAT, "DSTAT", IO_DSTAT); + state_add(Z180_DMODE, "DMODE", IO_DMODE); + state_add(Z180_DCNTL, "DCNTL", IO_DCNTL); + state_add(Z180_IL, "IL", IO_IL); + state_add(Z180_ITC, "ITC", IO_ITC); + state_add(Z180_IO35, "IO35", IO_IO35); + state_add(Z180_RCR, "RCR", IO_RCR); + state_add(Z180_IO37, "IO37", IO_IO37); + state_add(Z180_CBR, "CBR", IO_CBR).callimport(); + state_add(Z180_BBR, "BBR", IO_BBR).callimport(); + state_add(Z180_CBAR, "CBAR", IO_CBAR).callimport(); + state_add(Z180_IO3B, "IO3B", IO_IO3B); + state_add(Z180_IO3C, "IO3C", IO_IO3C); + state_add(Z180_IO3D, "IO3D", IO_IO3D); + state_add(Z180_OMCR, "OMCR", IO_OMCR); + state_add(Z180_IOCR, "IOCR", IO_IOCR); + } + + save_item(NAME(m_AF.w.l)); + save_item(NAME(m_BC.w.l)); + save_item(NAME(m_DE.w.l)); + save_item(NAME(m_HL.w.l)); + save_item(NAME(m_IX.w.l)); + save_item(NAME(m_IY.w.l)); + save_item(NAME(m_PC.w.l)); + save_item(NAME(m_SP.w.l)); + save_item(NAME(m_AF2.w.l)); + save_item(NAME(m_BC2.w.l)); + save_item(NAME(m_DE2.w.l)); + save_item(NAME(m_HL2.w.l)); + save_item(NAME(m_R)); + save_item(NAME(m_R2)); + save_item(NAME(m_IFF1)); + save_item(NAME(m_IFF2)); + save_item(NAME(m_HALT)); + save_item(NAME(m_IM)); + save_item(NAME(m_I)); + save_item(NAME(m_nmi_state)); + save_item(NAME(m_nmi_pending)); + save_item(NAME(m_irq_state)); + save_item(NAME(m_int_pending)); + save_item(NAME(m_timer_cnt)); + save_item(NAME(m_dma0_cnt)); + save_item(NAME(m_dma1_cnt)); + save_item(NAME(m_after_EI)); + + save_item(NAME(m_tif)); + + save_item(NAME(m_read_tcr_tmdr)); + save_item(NAME(m_tmdr_value)); + save_item(NAME(m_tmdrh)); + save_item(NAME(m_tmdr_latch)); + + save_item(NAME(m_io)); + save_item(NAME(m_iol)); + save_item(NAME(m_ioltemp)); + + save_item(NAME(m_mmu)); + + m_icountptr = &m_icount; +} + +/**************************************************************************** + * Reset registers to their initial values + ****************************************************************************/ +void z180_device::device_reset() +{ + _PPC = 0; + _PCD = 0; + _SPD = 0; + _AFD = 0; + _BCD = 0; + _DED = 0; + _HLD = 0; + _IXD = 0; + _IYD = 0; + m_AF2.d = 0; + m_BC2.d = 0; + m_DE2.d = 0; + m_HL2.d = 0; + m_R = 0; + m_R2 = 0; + m_IFF1 = 0; + m_IFF2 = 0; + m_HALT = 0; + m_IM = 0; + m_I = 0; + m_tmdr_latch = 0; + m_read_tcr_tmdr[0] = 0; + m_read_tcr_tmdr[1] = 0; + m_iol = 0; + memset(m_io, 0, sizeof(m_io)); + memset(m_mmu, 0, sizeof(m_mmu)); + m_tmdrh[0] = 0; + m_tmdrh[1] = 0; + m_tmdr_value[0] = 0xffff; + m_tmdr_value[1] = 0xffff; + m_tif[0] = 0; + m_tif[1] = 0; + m_nmi_state = CLEAR_LINE; + m_nmi_pending = 0; + m_irq_state[0] = CLEAR_LINE; + m_irq_state[1] = CLEAR_LINE; + m_irq_state[2] = CLEAR_LINE; + m_after_EI = 0; + m_ea = 0; + + memcpy(m_cc, (UINT8 *)cc_default, sizeof(m_cc)); + _IX = _IY = 0xffff; /* IX and IY are FFFF after a reset! */ + _F = ZF; /* Zero flag is set */ + + for (int i=0; i <= Z180_INT_MAX; i++) + { + m_int_pending[i] = 0; + } + + m_timer_cnt = 0; + m_dma0_cnt = 0; + m_dma1_cnt = 0; + + /* reset io registers */ + IO_CNTLA0 = Z180_CNTLA0_RESET; + IO_CNTLA1 = Z180_CNTLA1_RESET; + IO_CNTLB0 = Z180_CNTLB0_RESET; + IO_CNTLB1 = Z180_CNTLB1_RESET; + IO_STAT0 = Z180_STAT0_RESET; + IO_STAT1 = Z180_STAT1_RESET; + IO_TDR0 = Z180_TDR0_RESET; + IO_TDR1 = Z180_TDR1_RESET; + IO_RDR0 = Z180_RDR0_RESET; + IO_RDR1 = Z180_RDR1_RESET; + IO_CNTR = Z180_CNTR_RESET; + IO_TRDR = Z180_TRDR_RESET; + IO_TMDR0L = Z180_TMDR0L_RESET; + IO_TMDR0H = Z180_TMDR0H_RESET; + IO_RLDR0L = Z180_RLDR0L_RESET; + IO_RLDR0H = Z180_RLDR0H_RESET; + IO_TCR = Z180_TCR_RESET; + IO_IO11 = Z180_IO11_RESET; + IO_ASEXT0 = Z180_ASEXT0_RESET; + IO_ASEXT1 = Z180_ASEXT1_RESET; + IO_TMDR1L = Z180_TMDR1L_RESET; + IO_TMDR1H = Z180_TMDR1H_RESET; + IO_RLDR1L = Z180_RLDR1L_RESET; + IO_RLDR1H = Z180_RLDR1H_RESET; + IO_FRC = Z180_FRC_RESET; + IO_IO19 = Z180_IO19_RESET; + IO_ASTC0L = Z180_ASTC0L_RESET; + IO_ASTC0H = Z180_ASTC0H_RESET; + IO_ASTC1L = Z180_ASTC1L_RESET; + IO_ASTC1H = Z180_ASTC1H_RESET; + IO_CMR = Z180_CMR_RESET; + IO_CCR = Z180_CCR_RESET; + IO_SAR0L = Z180_SAR0L_RESET; + IO_SAR0H = Z180_SAR0H_RESET; + IO_SAR0B = Z180_SAR0B_RESET; + IO_DAR0L = Z180_DAR0L_RESET; + IO_DAR0H = Z180_DAR0H_RESET; + IO_DAR0B = Z180_DAR0B_RESET; + IO_BCR0L = Z180_BCR0L_RESET; + IO_BCR0H = Z180_BCR0H_RESET; + IO_MAR1L = Z180_MAR1L_RESET; + IO_MAR1H = Z180_MAR1H_RESET; + IO_MAR1B = Z180_MAR1B_RESET; + IO_IAR1L = Z180_IAR1L_RESET; + IO_IAR1H = Z180_IAR1H_RESET; + IO_IAR1B = Z180_IAR1B_RESET; + IO_BCR1L = Z180_BCR1L_RESET; + IO_BCR1H = Z180_BCR1H_RESET; + IO_DSTAT = Z180_DSTAT_RESET; + IO_DMODE = Z180_DMODE_RESET; + IO_DCNTL = Z180_DCNTL_RESET; + IO_IL = Z180_IL_RESET; + IO_ITC = Z180_ITC_RESET; + IO_IO35 = Z180_IO35_RESET; + IO_RCR = Z180_RCR_RESET; + IO_IO37 = Z180_IO37_RESET; + IO_CBR = Z180_CBR_RESET; + IO_BBR = Z180_BBR_RESET; + IO_CBAR = Z180_CBAR_RESET; + IO_IO3B = Z180_IO3B_RESET; + IO_IO3C = Z180_IO3C_RESET; + IO_IO3D = Z180_IO3D_RESET; + IO_OMCR = Z180_OMCR_RESET; + IO_IOCR = Z180_IOCR_RESET; + + m_daisy.reset(); + z180_mmu(); +} + +/* Handle PRT timers, decreasing them after 20 clocks and returning the new icount base that needs to be used for the next check */ +void z180_device::clock_timers() +{ + m_timer_cnt++; + if (m_timer_cnt >= 20) + { + m_timer_cnt = 0; + /* Programmable Reload Timer 0 */ + if(IO_TCR & Z180_TCR_TDE0) + { + if(m_tmdr_value[0] == 0) + { + m_tmdr_value[0] = IO_RLDR0L | (IO_RLDR0H << 8); + m_tif[0] = 1; + } + else + m_tmdr_value[0]--; + } + + /* Programmable Reload Timer 1 */ + if(IO_TCR & Z180_TCR_TDE1) + { + if(m_tmdr_value[1] == 0) + { + m_tmdr_value[1] = IO_RLDR1L | (IO_RLDR1H << 8); + m_tif[1] = 1; + } + else + m_tmdr_value[1]--; + } + + if((IO_TCR & Z180_TCR_TIE0) && m_tif[0]) + { + // check if we can take the interrupt + if(m_IFF1 && !m_after_EI) + { + m_int_pending[Z180_INT_PRT0] = 1; + } + } + + if((IO_TCR & Z180_TCR_TIE1) && m_tif[1]) + { + // check if we can take the interrupt + if(m_IFF1 && !m_after_EI) + { + m_int_pending[Z180_INT_PRT1] = 1; + } + } + + } +} + +int z180_device::check_interrupts() +{ + int i; + int cycles = 0; + + /* check for IRQs before each instruction */ + if (m_IFF1 && !m_after_EI) + { + if (m_irq_state[0] != CLEAR_LINE && (IO_ITC & Z180_ITC_ITE0) == Z180_ITC_ITE0) + m_int_pending[Z180_INT_IRQ0] = 1; + + if (m_irq_state[1] != CLEAR_LINE && (IO_ITC & Z180_ITC_ITE1) == Z180_ITC_ITE1) + m_int_pending[Z180_INT_IRQ1] = 1; + + if (m_irq_state[2] != CLEAR_LINE && (IO_ITC & Z180_ITC_ITE2) == Z180_ITC_ITE2) + m_int_pending[Z180_INT_IRQ2] = 1; + } + + for (i = 0; i <= Z180_INT_MAX; i++) + if (m_int_pending[i]) + { + cycles += take_interrupt(i); + m_int_pending[i] = 0; + break; + } + + return cycles; +} + +/**************************************************************************** + * Handle I/O and timers + ****************************************************************************/ + +void z180_device::handle_io_timers(int cycles) +{ + while (cycles-- > 0) + { + clock_timers(); + } +} + +/**************************************************************************** + * Execute 'cycles' T-states. Return number of T-states really executed + ****************************************************************************/ +void z180_device::execute_run() +{ + int curcycles; + + /* check for NMIs on the way in; they can only be set externally */ + /* via timers, and can't be dynamically enabled, so it is safe */ + /* to just check here */ + if (m_nmi_pending) + { + LOG(("Z180 '%s' take NMI\n", tag())); + _PPC = -1; /* there isn't a valid previous program counter */ + LEAVE_HALT(); /* Check if processor was halted */ + + /* disable DMA transfers!! */ + IO_DSTAT &= ~Z180_DSTAT_DME; + + m_IFF2 = m_IFF1; + m_IFF1 = 0; + PUSH( PC ); + _PCD = 0x0066; + m_icount -= 11; + m_nmi_pending = 0; + handle_io_timers(11); + } + +again: + /* check if any DMA transfer is running */ + if ((IO_DSTAT & Z180_DSTAT_DME) == Z180_DSTAT_DME) + { + /* check if DMA channel 0 is running and also is in burst mode */ + if ((IO_DSTAT & Z180_DSTAT_DE0) == Z180_DSTAT_DE0 && + (IO_DMODE & Z180_DMODE_MMOD) == Z180_DMODE_MMOD) + { + debugger_instruction_hook(this, _PCD); + + /* FIXME z180_dma0 should be handled in handle_io_timers */ + curcycles = z180_dma0(m_icount); + m_icount -= curcycles; + handle_io_timers(curcycles); + } + else + { + do + { + curcycles = check_interrupts(); + m_icount -= curcycles; + handle_io_timers(curcycles); + m_after_EI = 0; + + _PPC = _PCD; + debugger_instruction_hook(this, _PCD); + + if (!m_HALT) + { + m_R++; + m_extra_cycles = 0; + curcycles = exec_op(ROP()); + curcycles += m_extra_cycles; + } + else + curcycles = 3; + + m_icount -= curcycles; + + handle_io_timers(curcycles); + + /* FIXME: + * For simultaneous DREQ0 and DREQ1 requests, channel 0 has priority + * over channel 1. When channel 0 is performing a memory to/from memory + * transfer, channel 1 cannot operate until the channel 0 operation has + * terminated. If channel 1 is operating, channel 0 cannot operate until + * channel 1 releases control of the bus. + * + */ + curcycles = z180_dma0(6); + m_icount -= curcycles; + handle_io_timers(curcycles); + + curcycles = z180_dma1(); + m_icount -= curcycles; + handle_io_timers(curcycles); + + /* If DMA is done break out to the faster loop */ + if ((IO_DSTAT & Z180_DSTAT_DME) != Z180_DSTAT_DME) + break; + } while( m_icount > 0 ); + } + } + + if (m_icount > 0) + { + do + { + curcycles = check_interrupts(); + m_icount -= curcycles; + handle_io_timers(curcycles); + m_after_EI = 0; + + _PPC = _PCD; + debugger_instruction_hook(this, _PCD); + + if (!m_HALT) + { + m_R++; + m_extra_cycles = 0; + curcycles = exec_op(ROP()); + curcycles += m_extra_cycles; + } + else + curcycles = 3; + + m_icount -= curcycles; + handle_io_timers(curcycles); + + /* If DMA is started go to check the mode */ + if ((IO_DSTAT & Z180_DSTAT_DME) == Z180_DSTAT_DME) + goto again; + } while( m_icount > 0 ); + } +} + +/**************************************************************************** + * Burn 'cycles' T-states. Adjust R register for the lost time + ****************************************************************************/ +void z180_device::execute_burn(INT32 cycles) +{ + /* FIXME: This is not appropriate for dma */ + while ( (cycles > 0) ) + { + handle_io_timers(3); + /* NOP takes 3 cycles per instruction */ + m_R += 1; + m_icount -= 3; + cycles -= 3; + } +} + +/**************************************************************************** + * Set IRQ line state + ****************************************************************************/ +void z180_device::execute_set_input(int irqline, int state) +{ + if (irqline == INPUT_LINE_NMI) + { + /* mark an NMI pending on the rising edge */ + if (m_nmi_state == CLEAR_LINE && state != CLEAR_LINE) + m_nmi_pending = 1; + m_nmi_state = state; + } + else + { + LOG(("Z180 '%s' set_irq_line %d = %d\n",tag() , irqline,state)); + + /* update the IRQ state */ + m_irq_state[irqline] = state; + if (m_daisy.present()) + m_irq_state[0] = m_daisy.update_irq_state(); + + /* the main execute loop will take the interrupt */ + } +} + +/* logical to physical address translation */ +bool z180_device::memory_translate(address_spacenum spacenum, int intention, offs_t &address) +{ + if (spacenum == AS_PROGRAM) + { + address = MMU_REMAP_ADDR(address); + } + return true; +} + + +/************************************************************************** + * STATE IMPORT/EXPORT + **************************************************************************/ + +void z180_device::state_import(const device_state_entry &entry) +{ + switch (entry.index()) + { + case Z180_R: + m_R = m_rtemp & 0x7f; + m_R2 = m_rtemp & 0x80; + break; + + case Z180_CBR: + case Z180_BBR: + case Z180_CBAR: + z180_mmu(); + break; + + case Z180_IOLINES: + z180_write_iolines(m_ioltemp); + break; + + default: + fatalerror("CPU_IMPORT_STATE(z80) called for unexpected value\n"); + } +} + + +void z180_device::state_export(const device_state_entry &entry) +{ + switch (entry.index()) + { + case Z180_R: + m_rtemp = (m_R & 0x7f) | (m_R2 & 0x80); + break; + + case Z180_IOLINES: + m_ioltemp = m_iol; + break; + + default: + fatalerror("CPU_EXPORT_STATE(z80) called for unexpected value\n"); + } +} + +void z180_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + switch (entry.index()) + { + case STATE_GENFLAGS: + strprintf(str, "%c%c%c%c%c%c%c%c", + m_AF.b.l & 0x80 ? 'S':'.', + m_AF.b.l & 0x40 ? 'Z':'.', + m_AF.b.l & 0x20 ? '5':'.', + m_AF.b.l & 0x10 ? 'H':'.', + m_AF.b.l & 0x08 ? '3':'.', + m_AF.b.l & 0x04 ? 'P':'.', + m_AF.b.l & 0x02 ? 'N':'.', + m_AF.b.l & 0x01 ? 'C':'.'); + break; + } +} diff --git a/src/devices/cpu/z180/z180.h b/src/devices/cpu/z180/z180.h new file mode 100644 index 00000000000..7529280b95a --- /dev/null +++ b/src/devices/cpu/z180/z180.h @@ -0,0 +1,1788 @@ +// license:BSD-3-Clause +// copyright-holders:Juergen Buchmueller +#pragma once + +#ifndef __Z180_H__ +#define __Z180_H__ + +#include "cpu/z80/z80daisy.h" + + +enum +{ + Z180_PC, + Z180_SP, + Z180_AF, + Z180_BC, + Z180_DE, + Z180_HL, + Z180_IX, + Z180_IY, + Z180_A, + Z180_B, + Z180_C, + Z180_D, + Z180_E, + Z180_H, + Z180_L, + Z180_AF2, + Z180_BC2, + Z180_DE2, + Z180_HL2, + Z180_R, + Z180_I, + Z180_IM, + Z180_IFF1, + Z180_IFF2, + Z180_HALT, + Z180_DC0, + Z180_DC1, + Z180_DC2, + Z180_DC3, + Z180_CNTLA0, /* 00 ASCI control register A ch 0 */ + Z180_CNTLA1, /* 01 ASCI control register A ch 1 */ + Z180_CNTLB0, /* 02 ASCI control register B ch 0 */ + Z180_CNTLB1, /* 03 ASCI control register B ch 1 */ + Z180_STAT0, /* 04 ASCI status register 0 */ + Z180_STAT1, /* 05 ASCI status register 1 */ + Z180_TDR0, /* 06 ASCI transmit data register 0 */ + Z180_TDR1, /* 07 ASCI transmit data register 1 */ + Z180_RDR0, /* 08 ASCI receive data register 0 */ + Z180_RDR1, /* 09 ASCI receive data register 1 */ + Z180_CNTR, /* 0a CSI/O control/status register */ + Z180_TRDR, /* 0b CSI/O transmit/receive register */ + Z180_TMDR0L, /* 0c TIMER data register ch 0 L */ + Z180_TMDR0H, /* 0d TIMER data register ch 0 H */ + Z180_RLDR0L, /* 0e TIMER reload register ch 0 L */ + Z180_RLDR0H, /* 0f TIMER reload register ch 0 H */ + Z180_TCR, /* 10 TIMER control register */ + Z180_IO11, /* 11 reserved */ + Z180_ASEXT0, /* 12 (Z8S180/Z8L180) ASCI extension control register 0 */ + Z180_ASEXT1, /* 13 (Z8S180/Z8L180) ASCI extension control register 0 */ + Z180_TMDR1L, /* 14 TIMER data register ch 1 L */ + Z180_TMDR1H, /* 15 TIMER data register ch 1 H */ + Z180_RLDR1L, /* 16 TIMER reload register ch 1 L */ + Z180_RLDR1H, /* 17 TIMER reload register ch 1 H */ + Z180_FRC, /* 18 free running counter */ + Z180_IO19, /* 19 reserved */ + Z180_ASTC0L, /* 1a ASCI time constant ch 0 L */ + Z180_ASTC0H, /* 1b ASCI time constant ch 0 H */ + Z180_ASTC1L, /* 1c ASCI time constant ch 1 L */ + Z180_ASTC1H, /* 1d ASCI time constant ch 1 H */ + Z180_CMR, /* 1e clock multiplier */ + Z180_CCR, /* 1f chip control register */ + Z180_SAR0L, /* 20 DMA source address register ch 0 L */ + Z180_SAR0H, /* 21 DMA source address register ch 0 H */ + Z180_SAR0B, /* 22 DMA source address register ch 0 B */ + Z180_DAR0L, /* 23 DMA destination address register ch 0 L */ + Z180_DAR0H, /* 24 DMA destination address register ch 0 H */ + Z180_DAR0B, /* 25 DMA destination address register ch 0 B */ + Z180_BCR0L, /* 26 DMA byte count register ch 0 L */ + Z180_BCR0H, /* 27 DMA byte count register ch 0 H */ + Z180_MAR1L, /* 28 DMA memory address register ch 1 L */ + Z180_MAR1H, /* 29 DMA memory address register ch 1 H */ + Z180_MAR1B, /* 2a DMA memory address register ch 1 B */ + Z180_IAR1L, /* 2b DMA I/O address register ch 1 L */ + Z180_IAR1H, /* 2c DMA I/O address register ch 1 H */ + Z180_IAR1B, /* 2d (Z8S180/Z8L180) DMA I/O address register ch 1 B */ + Z180_BCR1L, /* 2e DMA byte count register ch 1 L */ + Z180_BCR1H, /* 2f DMA byte count register ch 1 H */ + Z180_DSTAT, /* 30 DMA status register */ + Z180_DMODE, /* 31 DMA mode register */ + Z180_DCNTL, /* 32 DMA/WAIT control register */ + Z180_IL, /* 33 INT vector low register */ + Z180_ITC, /* 34 INT/TRAP control register */ + Z180_IO35, /* 35 reserved */ + Z180_RCR, /* 36 refresh control register */ + Z180_IO37, /* 37 reserved */ + Z180_CBR, /* 38 MMU common base register */ + Z180_BBR, /* 39 MMU bank base register */ + Z180_CBAR, /* 3a MMU common/bank area register */ + Z180_IO3B, /* 3b reserved */ + Z180_IO3C, /* 3c reserved */ + Z180_IO3D, /* 3d reserved */ + Z180_OMCR, /* 3e operation mode control register */ + Z180_IOCR, /* 3f I/O control register */ + Z180_IOLINES, /* read/write I/O lines */ + + Z180_GENPC = STATE_GENPC, + Z180_GENSP = STATE_GENSP, + Z180_GENPCBASE = STATE_GENPCBASE +}; + +enum +{ + Z180_TABLE_op, + Z180_TABLE_cb, + Z180_TABLE_ed, + Z180_TABLE_xy, + Z180_TABLE_xycb, + Z180_TABLE_ex /* cycles counts for taken jr/jp/call and interrupt latency (rst opcodes) */ +}; + +enum +{ + CPUINFO_PTR_Z180_CYCLE_TABLE = CPUINFO_PTR_CPU_SPECIFIC, + CPUINFO_PTR_Z180_CYCLE_TABLE_LAST = CPUINFO_PTR_Z180_CYCLE_TABLE + Z180_TABLE_ex +}; + + +#define Z180_IRQ0 0 /* Execute IRQ1 */ +#define Z180_IRQ1 1 /* Execute IRQ1 */ +#define Z180_IRQ2 2 /* Execute IRQ2 */ + + +class z180_device : public cpu_device +{ +public: + // construction/destruction + z180_device(const machine_config &mconfig, const char *_tag, device_t *_owner, UINT32 _clock); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_execute_interface overrides + virtual UINT32 execute_min_cycles() const { return 1; } + virtual UINT32 execute_max_cycles() const { return 16; } + virtual UINT32 execute_input_lines() const { return 3; } + virtual UINT32 execute_default_irq_vector() const { return 0xff; } + virtual void execute_run(); + virtual void execute_burn(INT32 cycles); + virtual void execute_set_input(int inputnum, int state); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const; + virtual bool memory_translate(address_spacenum spacenum, int intention, offs_t &address); + + // device_state_interface overrides + virtual void state_import(const device_state_entry &entry); + virtual void state_export(const device_state_entry &entry); + void state_string_export(const device_state_entry &entry, std::string &str); + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const { return 1; } + virtual UINT32 disasm_max_opcode_bytes() const { return 4; } + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + +private: + address_space_config m_program_config; + address_space_config m_io_config; + address_space_config m_decrypted_opcodes_config; + + PAIR m_PREPC,m_PC,m_SP,m_AF,m_BC,m_DE,m_HL,m_IX,m_IY; + PAIR m_AF2,m_BC2,m_DE2,m_HL2; + UINT8 m_R,m_R2,m_IFF1,m_IFF2,m_HALT,m_IM,m_I; + UINT8 m_tmdr_latch; /* flag latched TMDR0H, TMDR1H values */ + UINT8 m_read_tcr_tmdr[2]; /* flag to indicate that TCR or TMDR was read */ + UINT32 m_iol; /* I/O line status bits */ + UINT8 m_io[64]; /* 64 internal 8 bit registers */ + offs_t m_mmu[16]; /* MMU address translation */ + UINT8 m_tmdrh[2]; /* latched TMDR0H and TMDR1H values */ + UINT16 m_tmdr_value[2]; /* TMDR values used byt PRT0 and PRT1 as down counter */ + UINT8 m_tif[2]; /* TIF0 and TIF1 values */ + UINT8 m_nmi_state; /* nmi line state */ + UINT8 m_nmi_pending; /* nmi pending */ + UINT8 m_irq_state[3]; /* irq line states (INT0,INT1,INT2) */ + UINT8 m_int_pending[11 + 1]; /* interrupt pending */ + UINT8 m_after_EI; /* are we in the EI shadow? */ + UINT32 m_ea; + UINT8 m_timer_cnt; /* timer counter / divide by 20 */ + UINT8 m_dma0_cnt; /* dma0 counter / divide by 20 */ + UINT8 m_dma1_cnt; /* dma1 counter / divide by 20 */ + z80_daisy_chain m_daisy; + address_space *m_program; + direct_read_data *m_direct; + address_space *m_oprogram; + direct_read_data *m_odirect; + address_space *m_iospace; + UINT8 m_rtemp; + UINT32 m_ioltemp; + int m_icount; + int m_extra_cycles; /* extra cpu cycles */ + UINT8 *m_cc[6]; + + typedef void (z180_device::*opcode_func)(); + static const opcode_func s_z180ops[6][0x100]; + + inline void z180_mmu(); + inline void RM16( offs_t addr, PAIR *r ); + inline void WM16( offs_t addr, PAIR *r ); + inline UINT8 ROP(); + inline UINT8 ARG(); + inline UINT32 ARG16(); + inline UINT8 INC(UINT8 value); + inline UINT8 DEC(UINT8 value); + inline UINT8 RLC(UINT8 value); + inline UINT8 RRC(UINT8 value); + inline UINT8 RL(UINT8 value); + inline UINT8 RR(UINT8 value); + inline UINT8 SLA(UINT8 value); + inline UINT8 SRA(UINT8 value); + inline UINT8 SLL(UINT8 value); + inline UINT8 SRL(UINT8 value); + inline UINT8 RES(UINT8 bit, UINT8 value); + inline UINT8 SET(UINT8 bit, UINT8 value); + inline int exec_op(const UINT8 opcode); + inline int exec_cb(const UINT8 opcode); + inline int exec_dd(const UINT8 opcode); + inline int exec_ed(const UINT8 opcode); + inline int exec_fd(const UINT8 opcode); + inline int exec_xycb(const UINT8 opcode); + int take_interrupt(int irq); + UINT8 z180_readcontrol(offs_t port); + void z180_writecontrol(offs_t port, UINT8 data); + int z180_dma0(int max_cycles); + int z180_dma1(); + void z180_write_iolines(UINT32 data); + void clock_timers(); + int check_interrupts(); + void handle_io_timers(int cycles); + + void op_00(); + void op_01(); + void op_02(); + void op_03(); + void op_04(); + void op_05(); + void op_06(); + void op_07(); + void op_08(); + void op_09(); + void op_0a(); + void op_0b(); + void op_0c(); + void op_0d(); + void op_0e(); + void op_0f(); + void op_10(); + void op_11(); + void op_12(); + void op_13(); + void op_14(); + void op_15(); + void op_16(); + void op_17(); + void op_18(); + void op_19(); + void op_1a(); + void op_1b(); + void op_1c(); + void op_1d(); + void op_1e(); + void op_1f(); + void op_20(); + void op_21(); + void op_22(); + void op_23(); + void op_24(); + void op_25(); + void op_26(); + void op_27(); + void op_28(); + void op_29(); + void op_2a(); + void op_2b(); + void op_2c(); + void op_2d(); + void op_2e(); + void op_2f(); + void op_30(); + void op_31(); + void op_32(); + void op_33(); + void op_34(); + void op_35(); + void op_36(); + void op_37(); + void op_38(); + void op_39(); + void op_3a(); + void op_3b(); + void op_3c(); + void op_3d(); + void op_3e(); + void op_3f(); + void op_40(); + void op_41(); + void op_42(); + void op_43(); + void op_44(); + void op_45(); + void op_46(); + void op_47(); + void op_48(); + void op_49(); + void op_4a(); + void op_4b(); + void op_4c(); + void op_4d(); + void op_4e(); + void op_4f(); + void op_50(); + void op_51(); + void op_52(); + void op_53(); + void op_54(); + void op_55(); + void op_56(); + void op_57(); + void op_58(); + void op_59(); + void op_5a(); + void op_5b(); + void op_5c(); + void op_5d(); + void op_5e(); + void op_5f(); + void op_60(); + void op_61(); + void op_62(); + void op_63(); + void op_64(); + void op_65(); + void op_66(); + void op_67(); + void op_68(); + void op_69(); + void op_6a(); + void op_6b(); + void op_6c(); + void op_6d(); + void op_6e(); + void op_6f(); + void op_70(); + void op_71(); + void op_72(); + void op_73(); + void op_74(); + void op_75(); + void op_76(); + void op_77(); + void op_78(); + void op_79(); + void op_7a(); + void op_7b(); + void op_7c(); + void op_7d(); + void op_7e(); + void op_7f(); + void op_80(); + void op_81(); + void op_82(); + void op_83(); + void op_84(); + void op_85(); + void op_86(); + void op_87(); + void op_88(); + void op_89(); + void op_8a(); + void op_8b(); + void op_8c(); + void op_8d(); + void op_8e(); + void op_8f(); + void op_90(); + void op_91(); + void op_92(); + void op_93(); + void op_94(); + void op_95(); + void op_96(); + void op_97(); + void op_98(); + void op_99(); + void op_9a(); + void op_9b(); + void op_9c(); + void op_9d(); + void op_9e(); + void op_9f(); + void op_a0(); + void op_a1(); + void op_a2(); + void op_a3(); + void op_a4(); + void op_a5(); + void op_a6(); + void op_a7(); + void op_a8(); + void op_a9(); + void op_aa(); + void op_ab(); + void op_ac(); + void op_ad(); + void op_ae(); + void op_af(); + void op_b0(); + void op_b1(); + void op_b2(); + void op_b3(); + void op_b4(); + void op_b5(); + void op_b6(); + void op_b7(); + void op_b8(); + void op_b9(); + void op_ba(); + void op_bb(); + void op_bc(); + void op_bd(); + void op_be(); + void op_bf(); + void op_c0(); + void op_c1(); + void op_c2(); + void op_c3(); + void op_c4(); + void op_c5(); + void op_c6(); + void op_c7(); + void op_c8(); + void op_c9(); + void op_ca(); + void op_cb(); + void op_cc(); + void op_cd(); + void op_ce(); + void op_cf(); + void op_d0(); + void op_d1(); + void op_d2(); + void op_d3(); + void op_d4(); + void op_d5(); + void op_d6(); + void op_d7(); + void op_d8(); + void op_d9(); + void op_da(); + void op_db(); + void op_dc(); + void op_dd(); + void op_de(); + void op_df(); + void op_e0(); + void op_e1(); + void op_e2(); + void op_e3(); + void op_e4(); + void op_e5(); + void op_e6(); + void op_e7(); + void op_e8(); + void op_e9(); + void op_ea(); + void op_eb(); + void op_ec(); + void op_ed(); + void op_ee(); + void op_ef(); + void op_f0(); + void op_f1(); + void op_f2(); + void op_f3(); + void op_f4(); + void op_f5(); + void op_f6(); + void op_f7(); + void op_f8(); + void op_f9(); + void op_fa(); + void op_fb(); + void op_fc(); + void op_fd(); + void op_fe(); + void op_ff(); + void cb_00(); + void cb_01(); + void cb_02(); + void cb_03(); + void cb_04(); + void cb_05(); + void cb_06(); + void cb_07(); + void cb_08(); + void cb_09(); + void cb_0a(); + void cb_0b(); + void cb_0c(); + void cb_0d(); + void cb_0e(); + void cb_0f(); + void cb_10(); + void cb_11(); + void cb_12(); + void cb_13(); + void cb_14(); + void cb_15(); + void cb_16(); + void cb_17(); + void cb_18(); + void cb_19(); + void cb_1a(); + void cb_1b(); + void cb_1c(); + void cb_1d(); + void cb_1e(); + void cb_1f(); + void cb_20(); + void cb_21(); + void cb_22(); + void cb_23(); + void cb_24(); + void cb_25(); + void cb_26(); + void cb_27(); + void cb_28(); + void cb_29(); + void cb_2a(); + void cb_2b(); + void cb_2c(); + void cb_2d(); + void cb_2e(); + void cb_2f(); + void cb_30(); + void cb_31(); + void cb_32(); + void cb_33(); + void cb_34(); + void cb_35(); + void cb_36(); + void cb_37(); + void cb_38(); + void cb_39(); + void cb_3a(); + void cb_3b(); + void cb_3c(); + void cb_3d(); + void cb_3e(); + void cb_3f(); + void cb_40(); + void cb_41(); + void cb_42(); + void cb_43(); + void cb_44(); + void cb_45(); + void cb_46(); + void cb_47(); + void cb_48(); + void cb_49(); + void cb_4a(); + void cb_4b(); + void cb_4c(); + void cb_4d(); + void cb_4e(); + void cb_4f(); + void cb_50(); + void cb_51(); + void cb_52(); + void cb_53(); + void cb_54(); + void cb_55(); + void cb_56(); + void cb_57(); + void cb_58(); + void cb_59(); + void cb_5a(); + void cb_5b(); + void cb_5c(); + void cb_5d(); + void cb_5e(); + void cb_5f(); + void cb_60(); + void cb_61(); + void cb_62(); + void cb_63(); + void cb_64(); + void cb_65(); + void cb_66(); + void cb_67(); + void cb_68(); + void cb_69(); + void cb_6a(); + void cb_6b(); + void cb_6c(); + void cb_6d(); + void cb_6e(); + void cb_6f(); + void cb_70(); + void cb_71(); + void cb_72(); + void cb_73(); + void cb_74(); + void cb_75(); + void cb_76(); + void cb_77(); + void cb_78(); + void cb_79(); + void cb_7a(); + void cb_7b(); + void cb_7c(); + void cb_7d(); + void cb_7e(); + void cb_7f(); + void cb_80(); + void cb_81(); + void cb_82(); + void cb_83(); + void cb_84(); + void cb_85(); + void cb_86(); + void cb_87(); + void cb_88(); + void cb_89(); + void cb_8a(); + void cb_8b(); + void cb_8c(); + void cb_8d(); + void cb_8e(); + void cb_8f(); + void cb_90(); + void cb_91(); + void cb_92(); + void cb_93(); + void cb_94(); + void cb_95(); + void cb_96(); + void cb_97(); + void cb_98(); + void cb_99(); + void cb_9a(); + void cb_9b(); + void cb_9c(); + void cb_9d(); + void cb_9e(); + void cb_9f(); + void cb_a0(); + void cb_a1(); + void cb_a2(); + void cb_a3(); + void cb_a4(); + void cb_a5(); + void cb_a6(); + void cb_a7(); + void cb_a8(); + void cb_a9(); + void cb_aa(); + void cb_ab(); + void cb_ac(); + void cb_ad(); + void cb_ae(); + void cb_af(); + void cb_b0(); + void cb_b1(); + void cb_b2(); + void cb_b3(); + void cb_b4(); + void cb_b5(); + void cb_b6(); + void cb_b7(); + void cb_b8(); + void cb_b9(); + void cb_ba(); + void cb_bb(); + void cb_bc(); + void cb_bd(); + void cb_be(); + void cb_bf(); + void cb_c0(); + void cb_c1(); + void cb_c2(); + void cb_c3(); + void cb_c4(); + void cb_c5(); + void cb_c6(); + void cb_c7(); + void cb_c8(); + void cb_c9(); + void cb_ca(); + void cb_cb(); + void cb_cc(); + void cb_cd(); + void cb_ce(); + void cb_cf(); + void cb_d0(); + void cb_d1(); + void cb_d2(); + void cb_d3(); + void cb_d4(); + void cb_d5(); + void cb_d6(); + void cb_d7(); + void cb_d8(); + void cb_d9(); + void cb_da(); + void cb_db(); + void cb_dc(); + void cb_dd(); + void cb_de(); + void cb_df(); + void cb_e0(); + void cb_e1(); + void cb_e2(); + void cb_e3(); + void cb_e4(); + void cb_e5(); + void cb_e6(); + void cb_e7(); + void cb_e8(); + void cb_e9(); + void cb_ea(); + void cb_eb(); + void cb_ec(); + void cb_ed(); + void cb_ee(); + void cb_ef(); + void cb_f0(); + void cb_f1(); + void cb_f2(); + void cb_f3(); + void cb_f4(); + void cb_f5(); + void cb_f6(); + void cb_f7(); + void cb_f8(); + void cb_f9(); + void cb_fa(); + void cb_fb(); + void cb_fc(); + void cb_fd(); + void cb_fe(); + void cb_ff(); + void illegal_1(); + void dd_00(); + void dd_01(); + void dd_02(); + void dd_03(); + void dd_04(); + void dd_05(); + void dd_06(); + void dd_07(); + void dd_08(); + void dd_09(); + void dd_0a(); + void dd_0b(); + void dd_0c(); + void dd_0d(); + void dd_0e(); + void dd_0f(); + void dd_10(); + void dd_11(); + void dd_12(); + void dd_13(); + void dd_14(); + void dd_15(); + void dd_16(); + void dd_17(); + void dd_18(); + void dd_19(); + void dd_1a(); + void dd_1b(); + void dd_1c(); + void dd_1d(); + void dd_1e(); + void dd_1f(); + void dd_20(); + void dd_21(); + void dd_22(); + void dd_23(); + void dd_24(); + void dd_25(); + void dd_26(); + void dd_27(); + void dd_28(); + void dd_29(); + void dd_2a(); + void dd_2b(); + void dd_2c(); + void dd_2d(); + void dd_2e(); + void dd_2f(); + void dd_30(); + void dd_31(); + void dd_32(); + void dd_33(); + void dd_34(); + void dd_35(); + void dd_36(); + void dd_37(); + void dd_38(); + void dd_39(); + void dd_3a(); + void dd_3b(); + void dd_3c(); + void dd_3d(); + void dd_3e(); + void dd_3f(); + void dd_40(); + void dd_41(); + void dd_42(); + void dd_43(); + void dd_44(); + void dd_45(); + void dd_46(); + void dd_47(); + void dd_48(); + void dd_49(); + void dd_4a(); + void dd_4b(); + void dd_4c(); + void dd_4d(); + void dd_4e(); + void dd_4f(); + void dd_50(); + void dd_51(); + void dd_52(); + void dd_53(); + void dd_54(); + void dd_55(); + void dd_56(); + void dd_57(); + void dd_58(); + void dd_59(); + void dd_5a(); + void dd_5b(); + void dd_5c(); + void dd_5d(); + void dd_5e(); + void dd_5f(); + void dd_60(); + void dd_61(); + void dd_62(); + void dd_63(); + void dd_64(); + void dd_65(); + void dd_66(); + void dd_67(); + void dd_68(); + void dd_69(); + void dd_6a(); + void dd_6b(); + void dd_6c(); + void dd_6d(); + void dd_6e(); + void dd_6f(); + void dd_70(); + void dd_71(); + void dd_72(); + void dd_73(); + void dd_74(); + void dd_75(); + void dd_76(); + void dd_77(); + void dd_78(); + void dd_79(); + void dd_7a(); + void dd_7b(); + void dd_7c(); + void dd_7d(); + void dd_7e(); + void dd_7f(); + void dd_80(); + void dd_81(); + void dd_82(); + void dd_83(); + void dd_84(); + void dd_85(); + void dd_86(); + void dd_87(); + void dd_88(); + void dd_89(); + void dd_8a(); + void dd_8b(); + void dd_8c(); + void dd_8d(); + void dd_8e(); + void dd_8f(); + void dd_90(); + void dd_91(); + void dd_92(); + void dd_93(); + void dd_94(); + void dd_95(); + void dd_96(); + void dd_97(); + void dd_98(); + void dd_99(); + void dd_9a(); + void dd_9b(); + void dd_9c(); + void dd_9d(); + void dd_9e(); + void dd_9f(); + void dd_a0(); + void dd_a1(); + void dd_a2(); + void dd_a3(); + void dd_a4(); + void dd_a5(); + void dd_a6(); + void dd_a7(); + void dd_a8(); + void dd_a9(); + void dd_aa(); + void dd_ab(); + void dd_ac(); + void dd_ad(); + void dd_ae(); + void dd_af(); + void dd_b0(); + void dd_b1(); + void dd_b2(); + void dd_b3(); + void dd_b4(); + void dd_b5(); + void dd_b6(); + void dd_b7(); + void dd_b8(); + void dd_b9(); + void dd_ba(); + void dd_bb(); + void dd_bc(); + void dd_bd(); + void dd_be(); + void dd_bf(); + void dd_c0(); + void dd_c1(); + void dd_c2(); + void dd_c3(); + void dd_c4(); + void dd_c5(); + void dd_c6(); + void dd_c7(); + void dd_c8(); + void dd_c9(); + void dd_ca(); + void dd_cb(); + void dd_cc(); + void dd_cd(); + void dd_ce(); + void dd_cf(); + void dd_d0(); + void dd_d1(); + void dd_d2(); + void dd_d3(); + void dd_d4(); + void dd_d5(); + void dd_d6(); + void dd_d7(); + void dd_d8(); + void dd_d9(); + void dd_da(); + void dd_db(); + void dd_dc(); + void dd_dd(); + void dd_de(); + void dd_df(); + void dd_e0(); + void dd_e1(); + void dd_e2(); + void dd_e3(); + void dd_e4(); + void dd_e5(); + void dd_e6(); + void dd_e7(); + void dd_e8(); + void dd_e9(); + void dd_ea(); + void dd_eb(); + void dd_ec(); + void dd_ed(); + void dd_ee(); + void dd_ef(); + void dd_f0(); + void dd_f1(); + void dd_f2(); + void dd_f3(); + void dd_f4(); + void dd_f5(); + void dd_f6(); + void dd_f7(); + void dd_f8(); + void dd_f9(); + void dd_fa(); + void dd_fb(); + void dd_fc(); + void dd_fd(); + void dd_fe(); + void dd_ff(); + void illegal_2(); + void ed_00(); + void ed_01(); + void ed_02(); + void ed_03(); + void ed_04(); + void ed_05(); + void ed_06(); + void ed_07(); + void ed_08(); + void ed_09(); + void ed_0a(); + void ed_0b(); + void ed_0c(); + void ed_0d(); + void ed_0e(); + void ed_0f(); + void ed_10(); + void ed_11(); + void ed_12(); + void ed_13(); + void ed_14(); + void ed_15(); + void ed_16(); + void ed_17(); + void ed_18(); + void ed_19(); + void ed_1a(); + void ed_1b(); + void ed_1c(); + void ed_1d(); + void ed_1e(); + void ed_1f(); + void ed_20(); + void ed_21(); + void ed_22(); + void ed_23(); + void ed_24(); + void ed_25(); + void ed_26(); + void ed_27(); + void ed_28(); + void ed_29(); + void ed_2a(); + void ed_2b(); + void ed_2c(); + void ed_2d(); + void ed_2e(); + void ed_2f(); + void ed_30(); + void ed_31(); + void ed_32(); + void ed_33(); + void ed_34(); + void ed_35(); + void ed_36(); + void ed_37(); + void ed_38(); + void ed_39(); + void ed_3a(); + void ed_3b(); + void ed_3c(); + void ed_3d(); + void ed_3e(); + void ed_3f(); + void ed_40(); + void ed_41(); + void ed_42(); + void ed_43(); + void ed_44(); + void ed_45(); + void ed_46(); + void ed_47(); + void ed_48(); + void ed_49(); + void ed_4a(); + void ed_4b(); + void ed_4c(); + void ed_4d(); + void ed_4e(); + void ed_4f(); + void ed_50(); + void ed_51(); + void ed_52(); + void ed_53(); + void ed_54(); + void ed_55(); + void ed_56(); + void ed_57(); + void ed_58(); + void ed_59(); + void ed_5a(); + void ed_5b(); + void ed_5c(); + void ed_5d(); + void ed_5e(); + void ed_5f(); + void ed_60(); + void ed_61(); + void ed_62(); + void ed_63(); + void ed_64(); + void ed_65(); + void ed_66(); + void ed_67(); + void ed_68(); + void ed_69(); + void ed_6a(); + void ed_6b(); + void ed_6c(); + void ed_6d(); + void ed_6e(); + void ed_6f(); + void ed_70(); + void ed_71(); + void ed_72(); + void ed_73(); + void ed_74(); + void ed_75(); + void ed_76(); + void ed_77(); + void ed_78(); + void ed_79(); + void ed_7a(); + void ed_7b(); + void ed_7c(); + void ed_7d(); + void ed_7e(); + void ed_7f(); + void ed_80(); + void ed_81(); + void ed_82(); + void ed_83(); + void ed_84(); + void ed_85(); + void ed_86(); + void ed_87(); + void ed_88(); + void ed_89(); + void ed_8a(); + void ed_8b(); + void ed_8c(); + void ed_8d(); + void ed_8e(); + void ed_8f(); + void ed_90(); + void ed_91(); + void ed_92(); + void ed_93(); + void ed_94(); + void ed_95(); + void ed_96(); + void ed_97(); + void ed_98(); + void ed_99(); + void ed_9a(); + void ed_9b(); + void ed_9c(); + void ed_9d(); + void ed_9e(); + void ed_9f(); + void ed_a0(); + void ed_a1(); + void ed_a2(); + void ed_a3(); + void ed_a4(); + void ed_a5(); + void ed_a6(); + void ed_a7(); + void ed_a8(); + void ed_a9(); + void ed_aa(); + void ed_ab(); + void ed_ac(); + void ed_ad(); + void ed_ae(); + void ed_af(); + void ed_b0(); + void ed_b1(); + void ed_b2(); + void ed_b3(); + void ed_b4(); + void ed_b5(); + void ed_b6(); + void ed_b7(); + void ed_b8(); + void ed_b9(); + void ed_ba(); + void ed_bb(); + void ed_bc(); + void ed_bd(); + void ed_be(); + void ed_bf(); + void ed_c0(); + void ed_c1(); + void ed_c2(); + void ed_c3(); + void ed_c4(); + void ed_c5(); + void ed_c6(); + void ed_c7(); + void ed_c8(); + void ed_c9(); + void ed_ca(); + void ed_cb(); + void ed_cc(); + void ed_cd(); + void ed_ce(); + void ed_cf(); + void ed_d0(); + void ed_d1(); + void ed_d2(); + void ed_d3(); + void ed_d4(); + void ed_d5(); + void ed_d6(); + void ed_d7(); + void ed_d8(); + void ed_d9(); + void ed_da(); + void ed_db(); + void ed_dc(); + void ed_dd(); + void ed_de(); + void ed_df(); + void ed_e0(); + void ed_e1(); + void ed_e2(); + void ed_e3(); + void ed_e4(); + void ed_e5(); + void ed_e6(); + void ed_e7(); + void ed_e8(); + void ed_e9(); + void ed_ea(); + void ed_eb(); + void ed_ec(); + void ed_ed(); + void ed_ee(); + void ed_ef(); + void ed_f0(); + void ed_f1(); + void ed_f2(); + void ed_f3(); + void ed_f4(); + void ed_f5(); + void ed_f6(); + void ed_f7(); + void ed_f8(); + void ed_f9(); + void ed_fa(); + void ed_fb(); + void ed_fc(); + void ed_fd(); + void ed_fe(); + void ed_ff(); + void fd_00(); + void fd_01(); + void fd_02(); + void fd_03(); + void fd_04(); + void fd_05(); + void fd_06(); + void fd_07(); + void fd_08(); + void fd_09(); + void fd_0a(); + void fd_0b(); + void fd_0c(); + void fd_0d(); + void fd_0e(); + void fd_0f(); + void fd_10(); + void fd_11(); + void fd_12(); + void fd_13(); + void fd_14(); + void fd_15(); + void fd_16(); + void fd_17(); + void fd_18(); + void fd_19(); + void fd_1a(); + void fd_1b(); + void fd_1c(); + void fd_1d(); + void fd_1e(); + void fd_1f(); + void fd_20(); + void fd_21(); + void fd_22(); + void fd_23(); + void fd_24(); + void fd_25(); + void fd_26(); + void fd_27(); + void fd_28(); + void fd_29(); + void fd_2a(); + void fd_2b(); + void fd_2c(); + void fd_2d(); + void fd_2e(); + void fd_2f(); + void fd_30(); + void fd_31(); + void fd_32(); + void fd_33(); + void fd_34(); + void fd_35(); + void fd_36(); + void fd_37(); + void fd_38(); + void fd_39(); + void fd_3a(); + void fd_3b(); + void fd_3c(); + void fd_3d(); + void fd_3e(); + void fd_3f(); + void fd_40(); + void fd_41(); + void fd_42(); + void fd_43(); + void fd_44(); + void fd_45(); + void fd_46(); + void fd_47(); + void fd_48(); + void fd_49(); + void fd_4a(); + void fd_4b(); + void fd_4c(); + void fd_4d(); + void fd_4e(); + void fd_4f(); + void fd_50(); + void fd_51(); + void fd_52(); + void fd_53(); + void fd_54(); + void fd_55(); + void fd_56(); + void fd_57(); + void fd_58(); + void fd_59(); + void fd_5a(); + void fd_5b(); + void fd_5c(); + void fd_5d(); + void fd_5e(); + void fd_5f(); + void fd_60(); + void fd_61(); + void fd_62(); + void fd_63(); + void fd_64(); + void fd_65(); + void fd_66(); + void fd_67(); + void fd_68(); + void fd_69(); + void fd_6a(); + void fd_6b(); + void fd_6c(); + void fd_6d(); + void fd_6e(); + void fd_6f(); + void fd_70(); + void fd_71(); + void fd_72(); + void fd_73(); + void fd_74(); + void fd_75(); + void fd_76(); + void fd_77(); + void fd_78(); + void fd_79(); + void fd_7a(); + void fd_7b(); + void fd_7c(); + void fd_7d(); + void fd_7e(); + void fd_7f(); + void fd_80(); + void fd_81(); + void fd_82(); + void fd_83(); + void fd_84(); + void fd_85(); + void fd_86(); + void fd_87(); + void fd_88(); + void fd_89(); + void fd_8a(); + void fd_8b(); + void fd_8c(); + void fd_8d(); + void fd_8e(); + void fd_8f(); + void fd_90(); + void fd_91(); + void fd_92(); + void fd_93(); + void fd_94(); + void fd_95(); + void fd_96(); + void fd_97(); + void fd_98(); + void fd_99(); + void fd_9a(); + void fd_9b(); + void fd_9c(); + void fd_9d(); + void fd_9e(); + void fd_9f(); + void fd_a0(); + void fd_a1(); + void fd_a2(); + void fd_a3(); + void fd_a4(); + void fd_a5(); + void fd_a6(); + void fd_a7(); + void fd_a8(); + void fd_a9(); + void fd_aa(); + void fd_ab(); + void fd_ac(); + void fd_ad(); + void fd_ae(); + void fd_af(); + void fd_b0(); + void fd_b1(); + void fd_b2(); + void fd_b3(); + void fd_b4(); + void fd_b5(); + void fd_b6(); + void fd_b7(); + void fd_b8(); + void fd_b9(); + void fd_ba(); + void fd_bb(); + void fd_bc(); + void fd_bd(); + void fd_be(); + void fd_bf(); + void fd_c0(); + void fd_c1(); + void fd_c2(); + void fd_c3(); + void fd_c4(); + void fd_c5(); + void fd_c6(); + void fd_c7(); + void fd_c8(); + void fd_c9(); + void fd_ca(); + void fd_cb(); + void fd_cc(); + void fd_cd(); + void fd_ce(); + void fd_cf(); + void fd_d0(); + void fd_d1(); + void fd_d2(); + void fd_d3(); + void fd_d4(); + void fd_d5(); + void fd_d6(); + void fd_d7(); + void fd_d8(); + void fd_d9(); + void fd_da(); + void fd_db(); + void fd_dc(); + void fd_dd(); + void fd_de(); + void fd_df(); + void fd_e0(); + void fd_e1(); + void fd_e2(); + void fd_e3(); + void fd_e4(); + void fd_e5(); + void fd_e6(); + void fd_e7(); + void fd_e8(); + void fd_e9(); + void fd_ea(); + void fd_eb(); + void fd_ec(); + void fd_ed(); + void fd_ee(); + void fd_ef(); + void fd_f0(); + void fd_f1(); + void fd_f2(); + void fd_f3(); + void fd_f4(); + void fd_f5(); + void fd_f6(); + void fd_f7(); + void fd_f8(); + void fd_f9(); + void fd_fa(); + void fd_fb(); + void fd_fc(); + void fd_fd(); + void fd_fe(); + void fd_ff(); + void xycb_00(); + void xycb_01(); + void xycb_02(); + void xycb_03(); + void xycb_04(); + void xycb_05(); + void xycb_06(); + void xycb_07(); + void xycb_08(); + void xycb_09(); + void xycb_0a(); + void xycb_0b(); + void xycb_0c(); + void xycb_0d(); + void xycb_0e(); + void xycb_0f(); + void xycb_10(); + void xycb_11(); + void xycb_12(); + void xycb_13(); + void xycb_14(); + void xycb_15(); + void xycb_16(); + void xycb_17(); + void xycb_18(); + void xycb_19(); + void xycb_1a(); + void xycb_1b(); + void xycb_1c(); + void xycb_1d(); + void xycb_1e(); + void xycb_1f(); + void xycb_20(); + void xycb_21(); + void xycb_22(); + void xycb_23(); + void xycb_24(); + void xycb_25(); + void xycb_26(); + void xycb_27(); + void xycb_28(); + void xycb_29(); + void xycb_2a(); + void xycb_2b(); + void xycb_2c(); + void xycb_2d(); + void xycb_2e(); + void xycb_2f(); + void xycb_30(); + void xycb_31(); + void xycb_32(); + void xycb_33(); + void xycb_34(); + void xycb_35(); + void xycb_36(); + void xycb_37(); + void xycb_38(); + void xycb_39(); + void xycb_3a(); + void xycb_3b(); + void xycb_3c(); + void xycb_3d(); + void xycb_3e(); + void xycb_3f(); + void xycb_40(); + void xycb_41(); + void xycb_42(); + void xycb_43(); + void xycb_44(); + void xycb_45(); + void xycb_46(); + void xycb_47(); + void xycb_48(); + void xycb_49(); + void xycb_4a(); + void xycb_4b(); + void xycb_4c(); + void xycb_4d(); + void xycb_4e(); + void xycb_4f(); + void xycb_50(); + void xycb_51(); + void xycb_52(); + void xycb_53(); + void xycb_54(); + void xycb_55(); + void xycb_56(); + void xycb_57(); + void xycb_58(); + void xycb_59(); + void xycb_5a(); + void xycb_5b(); + void xycb_5c(); + void xycb_5d(); + void xycb_5e(); + void xycb_5f(); + void xycb_60(); + void xycb_61(); + void xycb_62(); + void xycb_63(); + void xycb_64(); + void xycb_65(); + void xycb_66(); + void xycb_67(); + void xycb_68(); + void xycb_69(); + void xycb_6a(); + void xycb_6b(); + void xycb_6c(); + void xycb_6d(); + void xycb_6e(); + void xycb_6f(); + void xycb_70(); + void xycb_71(); + void xycb_72(); + void xycb_73(); + void xycb_74(); + void xycb_75(); + void xycb_76(); + void xycb_77(); + void xycb_78(); + void xycb_79(); + void xycb_7a(); + void xycb_7b(); + void xycb_7c(); + void xycb_7d(); + void xycb_7e(); + void xycb_7f(); + void xycb_80(); + void xycb_81(); + void xycb_82(); + void xycb_83(); + void xycb_84(); + void xycb_85(); + void xycb_86(); + void xycb_87(); + void xycb_88(); + void xycb_89(); + void xycb_8a(); + void xycb_8b(); + void xycb_8c(); + void xycb_8d(); + void xycb_8e(); + void xycb_8f(); + void xycb_90(); + void xycb_91(); + void xycb_92(); + void xycb_93(); + void xycb_94(); + void xycb_95(); + void xycb_96(); + void xycb_97(); + void xycb_98(); + void xycb_99(); + void xycb_9a(); + void xycb_9b(); + void xycb_9c(); + void xycb_9d(); + void xycb_9e(); + void xycb_9f(); + void xycb_a0(); + void xycb_a1(); + void xycb_a2(); + void xycb_a3(); + void xycb_a4(); + void xycb_a5(); + void xycb_a6(); + void xycb_a7(); + void xycb_a8(); + void xycb_a9(); + void xycb_aa(); + void xycb_ab(); + void xycb_ac(); + void xycb_ad(); + void xycb_ae(); + void xycb_af(); + void xycb_b0(); + void xycb_b1(); + void xycb_b2(); + void xycb_b3(); + void xycb_b4(); + void xycb_b5(); + void xycb_b6(); + void xycb_b7(); + void xycb_b8(); + void xycb_b9(); + void xycb_ba(); + void xycb_bb(); + void xycb_bc(); + void xycb_bd(); + void xycb_be(); + void xycb_bf(); + void xycb_c0(); + void xycb_c1(); + void xycb_c2(); + void xycb_c3(); + void xycb_c4(); + void xycb_c5(); + void xycb_c6(); + void xycb_c7(); + void xycb_c8(); + void xycb_c9(); + void xycb_ca(); + void xycb_cb(); + void xycb_cc(); + void xycb_cd(); + void xycb_ce(); + void xycb_cf(); + void xycb_d0(); + void xycb_d1(); + void xycb_d2(); + void xycb_d3(); + void xycb_d4(); + void xycb_d5(); + void xycb_d6(); + void xycb_d7(); + void xycb_d8(); + void xycb_d9(); + void xycb_da(); + void xycb_db(); + void xycb_dc(); + void xycb_dd(); + void xycb_de(); + void xycb_df(); + void xycb_e0(); + void xycb_e1(); + void xycb_e2(); + void xycb_e3(); + void xycb_e4(); + void xycb_e5(); + void xycb_e6(); + void xycb_e7(); + void xycb_e8(); + void xycb_e9(); + void xycb_ea(); + void xycb_eb(); + void xycb_ec(); + void xycb_ed(); + void xycb_ee(); + void xycb_ef(); + void xycb_f0(); + void xycb_f1(); + void xycb_f2(); + void xycb_f3(); + void xycb_f4(); + void xycb_f5(); + void xycb_f6(); + void xycb_f7(); + void xycb_f8(); + void xycb_f9(); + void xycb_fa(); + void xycb_fb(); + void xycb_fc(); + void xycb_fd(); + void xycb_fe(); + void xycb_ff(); + +}; + + +extern const device_type Z180; + + +#endif /* __Z180_H__ */ diff --git a/src/devices/cpu/z180/z180cb.inc b/src/devices/cpu/z180/z180cb.inc new file mode 100644 index 00000000000..3a58725024e --- /dev/null +++ b/src/devices/cpu/z180/z180cb.inc @@ -0,0 +1,293 @@ +// license:BSD-3-Clause +// copyright-holders:Juergen Buchmueller +/********************************************************** + * opcodes with CB prefix + * rotate, shift and bit operations + **********************************************************/ +OP(cb,00) { _B = RLC(_B); } /* RLC B */ +OP(cb,01) { _C = RLC(_C); } /* RLC C */ +OP(cb,02) { _D = RLC(_D); } /* RLC D */ +OP(cb,03) { _E = RLC(_E); } /* RLC E */ +OP(cb,04) { _H = RLC(_H); } /* RLC H */ +OP(cb,05) { _L = RLC(_L); } /* RLC L */ +OP(cb,06) { WM( _HL, RLC(RM(_HL)) ); } /* RLC (HL) */ +OP(cb,07) { _A = RLC(_A); } /* RLC A */ + +OP(cb,08) { _B = RRC(_B); } /* RRC B */ +OP(cb,09) { _C = RRC(_C); } /* RRC C */ +OP(cb,0a) { _D = RRC(_D); } /* RRC D */ +OP(cb,0b) { _E = RRC(_E); } /* RRC E */ +OP(cb,0c) { _H = RRC(_H); } /* RRC H */ +OP(cb,0d) { _L = RRC(_L); } /* RRC L */ +OP(cb,0e) { WM( _HL, RRC(RM(_HL)) ); } /* RRC (HL) */ +OP(cb,0f) { _A = RRC(_A); } /* RRC A */ + +OP(cb,10) { _B = RL(_B); } /* RL B */ +OP(cb,11) { _C = RL(_C); } /* RL C */ +OP(cb,12) { _D = RL(_D); } /* RL D */ +OP(cb,13) { _E = RL(_E); } /* RL E */ +OP(cb,14) { _H = RL(_H); } /* RL H */ +OP(cb,15) { _L = RL(_L); } /* RL L */ +OP(cb,16) { WM( _HL, RL(RM(_HL)) ); } /* RL (HL) */ +OP(cb,17) { _A = RL(_A); } /* RL A */ + +OP(cb,18) { _B = RR(_B); } /* RR B */ +OP(cb,19) { _C = RR(_C); } /* RR C */ +OP(cb,1a) { _D = RR(_D); } /* RR D */ +OP(cb,1b) { _E = RR(_E); } /* RR E */ +OP(cb,1c) { _H = RR(_H); } /* RR H */ +OP(cb,1d) { _L = RR(_L); } /* RR L */ +OP(cb,1e) { WM( _HL, RR(RM(_HL)) ); } /* RR (HL) */ +OP(cb,1f) { _A = RR(_A); } /* RR A */ + +OP(cb,20) { _B = SLA(_B); } /* SLA B */ +OP(cb,21) { _C = SLA(_C); } /* SLA C */ +OP(cb,22) { _D = SLA(_D); } /* SLA D */ +OP(cb,23) { _E = SLA(_E); } /* SLA E */ +OP(cb,24) { _H = SLA(_H); } /* SLA H */ +OP(cb,25) { _L = SLA(_L); } /* SLA L */ +OP(cb,26) { WM( _HL, SLA(RM(_HL)) ); } /* SLA (HL) */ +OP(cb,27) { _A = SLA(_A); } /* SLA A */ + +OP(cb,28) { _B = SRA(_B); } /* SRA B */ +OP(cb,29) { _C = SRA(_C); } /* SRA C */ +OP(cb,2a) { _D = SRA(_D); } /* SRA D */ +OP(cb,2b) { _E = SRA(_E); } /* SRA E */ +OP(cb,2c) { _H = SRA(_H); } /* SRA H */ +OP(cb,2d) { _L = SRA(_L); } /* SRA L */ +OP(cb,2e) { WM( _HL, SRA(RM(_HL)) ); } /* SRA (HL) */ +OP(cb,2f) { _A = SRA(_A); } /* SRA A */ + +OP(cb,30) { _B = SLL(_B); } /* SLL B */ +OP(cb,31) { _C = SLL(_C); } /* SLL C */ +OP(cb,32) { _D = SLL(_D); } /* SLL D */ +OP(cb,33) { _E = SLL(_E); } /* SLL E */ +OP(cb,34) { _H = SLL(_H); } /* SLL H */ +OP(cb,35) { _L = SLL(_L); } /* SLL L */ +OP(cb,36) { WM( _HL, SLL(RM(_HL)) ); } /* SLL (HL) */ +OP(cb,37) { _A = SLL(_A); } /* SLL A */ + +OP(cb,38) { _B = SRL(_B); } /* SRL B */ +OP(cb,39) { _C = SRL(_C); } /* SRL C */ +OP(cb,3a) { _D = SRL(_D); } /* SRL D */ +OP(cb,3b) { _E = SRL(_E); } /* SRL E */ +OP(cb,3c) { _H = SRL(_H); } /* SRL H */ +OP(cb,3d) { _L = SRL(_L); } /* SRL L */ +OP(cb,3e) { WM( _HL, SRL(RM(_HL)) ); } /* SRL (HL) */ +OP(cb,3f) { _A = SRL(_A); } /* SRL A */ + +OP(cb,40) { BIT(0,_B); } /* BIT 0,B */ +OP(cb,41) { BIT(0,_C); } /* BIT 0,C */ +OP(cb,42) { BIT(0,_D); } /* BIT 0,D */ +OP(cb,43) { BIT(0,_E); } /* BIT 0,E */ +OP(cb,44) { BIT(0,_H); } /* BIT 0,H */ +OP(cb,45) { BIT(0,_L); } /* BIT 0,L */ +OP(cb,46) { BIT(0,RM(_HL)); } /* BIT 0,(HL) */ +OP(cb,47) { BIT(0,_A); } /* BIT 0,A */ + +OP(cb,48) { BIT(1,_B); } /* BIT 1,B */ +OP(cb,49) { BIT(1,_C); } /* BIT 1,C */ +OP(cb,4a) { BIT(1,_D); } /* BIT 1,D */ +OP(cb,4b) { BIT(1,_E); } /* BIT 1,E */ +OP(cb,4c) { BIT(1,_H); } /* BIT 1,H */ +OP(cb,4d) { BIT(1,_L); } /* BIT 1,L */ +OP(cb,4e) { BIT(1,RM(_HL)); } /* BIT 1,(HL) */ +OP(cb,4f) { BIT(1,_A); } /* BIT 1,A */ + +OP(cb,50) { BIT(2,_B); } /* BIT 2,B */ +OP(cb,51) { BIT(2,_C); } /* BIT 2,C */ +OP(cb,52) { BIT(2,_D); } /* BIT 2,D */ +OP(cb,53) { BIT(2,_E); } /* BIT 2,E */ +OP(cb,54) { BIT(2,_H); } /* BIT 2,H */ +OP(cb,55) { BIT(2,_L); } /* BIT 2,L */ +OP(cb,56) { BIT(2,RM(_HL)); } /* BIT 2,(HL) */ +OP(cb,57) { BIT(2,_A); } /* BIT 2,A */ + +OP(cb,58) { BIT(3,_B); } /* BIT 3,B */ +OP(cb,59) { BIT(3,_C); } /* BIT 3,C */ +OP(cb,5a) { BIT(3,_D); } /* BIT 3,D */ +OP(cb,5b) { BIT(3,_E); } /* BIT 3,E */ +OP(cb,5c) { BIT(3,_H); } /* BIT 3,H */ +OP(cb,5d) { BIT(3,_L); } /* BIT 3,L */ +OP(cb,5e) { BIT(3,RM(_HL)); } /* BIT 3,(HL) */ +OP(cb,5f) { BIT(3,_A); } /* BIT 3,A */ + +OP(cb,60) { BIT(4,_B); } /* BIT 4,B */ +OP(cb,61) { BIT(4,_C); } /* BIT 4,C */ +OP(cb,62) { BIT(4,_D); } /* BIT 4,D */ +OP(cb,63) { BIT(4,_E); } /* BIT 4,E */ +OP(cb,64) { BIT(4,_H); } /* BIT 4,H */ +OP(cb,65) { BIT(4,_L); } /* BIT 4,L */ +OP(cb,66) { BIT(4,RM(_HL)); } /* BIT 4,(HL) */ +OP(cb,67) { BIT(4,_A); } /* BIT 4,A */ + +OP(cb,68) { BIT(5,_B); } /* BIT 5,B */ +OP(cb,69) { BIT(5,_C); } /* BIT 5,C */ +OP(cb,6a) { BIT(5,_D); } /* BIT 5,D */ +OP(cb,6b) { BIT(5,_E); } /* BIT 5,E */ +OP(cb,6c) { BIT(5,_H); } /* BIT 5,H */ +OP(cb,6d) { BIT(5,_L); } /* BIT 5,L */ +OP(cb,6e) { BIT(5,RM(_HL)); } /* BIT 5,(HL) */ +OP(cb,6f) { BIT(5,_A); } /* BIT 5,A */ + +OP(cb,70) { BIT(6,_B); } /* BIT 6,B */ +OP(cb,71) { BIT(6,_C); } /* BIT 6,C */ +OP(cb,72) { BIT(6,_D); } /* BIT 6,D */ +OP(cb,73) { BIT(6,_E); } /* BIT 6,E */ +OP(cb,74) { BIT(6,_H); } /* BIT 6,H */ +OP(cb,75) { BIT(6,_L); } /* BIT 6,L */ +OP(cb,76) { BIT(6,RM(_HL)); } /* BIT 6,(HL) */ +OP(cb,77) { BIT(6,_A); } /* BIT 6,A */ + +OP(cb,78) { BIT(7,_B); } /* BIT 7,B */ +OP(cb,79) { BIT(7,_C); } /* BIT 7,C */ +OP(cb,7a) { BIT(7,_D); } /* BIT 7,D */ +OP(cb,7b) { BIT(7,_E); } /* BIT 7,E */ +OP(cb,7c) { BIT(7,_H); } /* BIT 7,H */ +OP(cb,7d) { BIT(7,_L); } /* BIT 7,L */ +OP(cb,7e) { BIT(7,RM(_HL)); } /* BIT 7,(HL) */ +OP(cb,7f) { BIT(7,_A); } /* BIT 7,A */ + +OP(cb,80) { _B = RES(0,_B); } /* RES 0,B */ +OP(cb,81) { _C = RES(0,_C); } /* RES 0,C */ +OP(cb,82) { _D = RES(0,_D); } /* RES 0,D */ +OP(cb,83) { _E = RES(0,_E); } /* RES 0,E */ +OP(cb,84) { _H = RES(0,_H); } /* RES 0,H */ +OP(cb,85) { _L = RES(0,_L); } /* RES 0,L */ +OP(cb,86) { WM( _HL, RES(0,RM(_HL)) ); } /* RES 0,(HL) */ +OP(cb,87) { _A = RES(0,_A); } /* RES 0,A */ + +OP(cb,88) { _B = RES(1,_B); } /* RES 1,B */ +OP(cb,89) { _C = RES(1,_C); } /* RES 1,C */ +OP(cb,8a) { _D = RES(1,_D); } /* RES 1,D */ +OP(cb,8b) { _E = RES(1,_E); } /* RES 1,E */ +OP(cb,8c) { _H = RES(1,_H); } /* RES 1,H */ +OP(cb,8d) { _L = RES(1,_L); } /* RES 1,L */ +OP(cb,8e) { WM( _HL, RES(1,RM(_HL)) ); } /* RES 1,(HL) */ +OP(cb,8f) { _A = RES(1,_A); } /* RES 1,A */ + +OP(cb,90) { _B = RES(2,_B); } /* RES 2,B */ +OP(cb,91) { _C = RES(2,_C); } /* RES 2,C */ +OP(cb,92) { _D = RES(2,_D); } /* RES 2,D */ +OP(cb,93) { _E = RES(2,_E); } /* RES 2,E */ +OP(cb,94) { _H = RES(2,_H); } /* RES 2,H */ +OP(cb,95) { _L = RES(2,_L); } /* RES 2,L */ +OP(cb,96) { WM( _HL, RES(2,RM(_HL)) ); } /* RES 2,(HL) */ +OP(cb,97) { _A = RES(2,_A); } /* RES 2,A */ + +OP(cb,98) { _B = RES(3,_B); } /* RES 3,B */ +OP(cb,99) { _C = RES(3,_C); } /* RES 3,C */ +OP(cb,9a) { _D = RES(3,_D); } /* RES 3,D */ +OP(cb,9b) { _E = RES(3,_E); } /* RES 3,E */ +OP(cb,9c) { _H = RES(3,_H); } /* RES 3,H */ +OP(cb,9d) { _L = RES(3,_L); } /* RES 3,L */ +OP(cb,9e) { WM( _HL, RES(3,RM(_HL)) ); } /* RES 3,(HL) */ +OP(cb,9f) { _A = RES(3,_A); } /* RES 3,A */ + +OP(cb,a0) { _B = RES(4,_B); } /* RES 4,B */ +OP(cb,a1) { _C = RES(4,_C); } /* RES 4,C */ +OP(cb,a2) { _D = RES(4,_D); } /* RES 4,D */ +OP(cb,a3) { _E = RES(4,_E); } /* RES 4,E */ +OP(cb,a4) { _H = RES(4,_H); } /* RES 4,H */ +OP(cb,a5) { _L = RES(4,_L); } /* RES 4,L */ +OP(cb,a6) { WM( _HL, RES(4,RM(_HL)) ); } /* RES 4,(HL) */ +OP(cb,a7) { _A = RES(4,_A); } /* RES 4,A */ + +OP(cb,a8) { _B = RES(5,_B); } /* RES 5,B */ +OP(cb,a9) { _C = RES(5,_C); } /* RES 5,C */ +OP(cb,aa) { _D = RES(5,_D); } /* RES 5,D */ +OP(cb,ab) { _E = RES(5,_E); } /* RES 5,E */ +OP(cb,ac) { _H = RES(5,_H); } /* RES 5,H */ +OP(cb,ad) { _L = RES(5,_L); } /* RES 5,L */ +OP(cb,ae) { WM( _HL, RES(5,RM(_HL)) ); } /* RES 5,(HL) */ +OP(cb,af) { _A = RES(5,_A); } /* RES 5,A */ + +OP(cb,b0) { _B = RES(6,_B); } /* RES 6,B */ +OP(cb,b1) { _C = RES(6,_C); } /* RES 6,C */ +OP(cb,b2) { _D = RES(6,_D); } /* RES 6,D */ +OP(cb,b3) { _E = RES(6,_E); } /* RES 6,E */ +OP(cb,b4) { _H = RES(6,_H); } /* RES 6,H */ +OP(cb,b5) { _L = RES(6,_L); } /* RES 6,L */ +OP(cb,b6) { WM( _HL, RES(6,RM(_HL)) ); } /* RES 6,(HL) */ +OP(cb,b7) { _A = RES(6,_A); } /* RES 6,A */ + +OP(cb,b8) { _B = RES(7,_B); } /* RES 7,B */ +OP(cb,b9) { _C = RES(7,_C); } /* RES 7,C */ +OP(cb,ba) { _D = RES(7,_D); } /* RES 7,D */ +OP(cb,bb) { _E = RES(7,_E); } /* RES 7,E */ +OP(cb,bc) { _H = RES(7,_H); } /* RES 7,H */ +OP(cb,bd) { _L = RES(7,_L); } /* RES 7,L */ +OP(cb,be) { WM( _HL, RES(7,RM(_HL)) ); } /* RES 7,(HL) */ +OP(cb,bf) { _A = RES(7,_A); } /* RES 7,A */ + +OP(cb,c0) { _B = SET(0,_B); } /* SET 0,B */ +OP(cb,c1) { _C = SET(0,_C); } /* SET 0,C */ +OP(cb,c2) { _D = SET(0,_D); } /* SET 0,D */ +OP(cb,c3) { _E = SET(0,_E); } /* SET 0,E */ +OP(cb,c4) { _H = SET(0,_H); } /* SET 0,H */ +OP(cb,c5) { _L = SET(0,_L); } /* SET 0,L */ +OP(cb,c6) { WM( _HL, SET(0,RM(_HL)) ); } /* SET 0,(HL) */ +OP(cb,c7) { _A = SET(0,_A); } /* SET 0,A */ + +OP(cb,c8) { _B = SET(1,_B); } /* SET 1,B */ +OP(cb,c9) { _C = SET(1,_C); } /* SET 1,C */ +OP(cb,ca) { _D = SET(1,_D); } /* SET 1,D */ +OP(cb,cb) { _E = SET(1,_E); } /* SET 1,E */ +OP(cb,cc) { _H = SET(1,_H); } /* SET 1,H */ +OP(cb,cd) { _L = SET(1,_L); } /* SET 1,L */ +OP(cb,ce) { WM( _HL, SET(1,RM(_HL)) ); } /* SET 1,(HL) */ +OP(cb,cf) { _A = SET(1,_A); } /* SET 1,A */ + +OP(cb,d0) { _B = SET(2,_B); } /* SET 2,B */ +OP(cb,d1) { _C = SET(2,_C); } /* SET 2,C */ +OP(cb,d2) { _D = SET(2,_D); } /* SET 2,D */ +OP(cb,d3) { _E = SET(2,_E); } /* SET 2,E */ +OP(cb,d4) { _H = SET(2,_H); } /* SET 2,H */ +OP(cb,d5) { _L = SET(2,_L); } /* SET 2,L */ +OP(cb,d6) { WM( _HL, SET(2,RM(_HL)) ); }/* SET 2,(HL) */ +OP(cb,d7) { _A = SET(2,_A); } /* SET 2,A */ + +OP(cb,d8) { _B = SET(3,_B); } /* SET 3,B */ +OP(cb,d9) { _C = SET(3,_C); } /* SET 3,C */ +OP(cb,da) { _D = SET(3,_D); } /* SET 3,D */ +OP(cb,db) { _E = SET(3,_E); } /* SET 3,E */ +OP(cb,dc) { _H = SET(3,_H); } /* SET 3,H */ +OP(cb,dd) { _L = SET(3,_L); } /* SET 3,L */ +OP(cb,de) { WM( _HL, SET(3,RM(_HL)) ); } /* SET 3,(HL) */ +OP(cb,df) { _A = SET(3,_A); } /* SET 3,A */ + +OP(cb,e0) { _B = SET(4,_B); } /* SET 4,B */ +OP(cb,e1) { _C = SET(4,_C); } /* SET 4,C */ +OP(cb,e2) { _D = SET(4,_D); } /* SET 4,D */ +OP(cb,e3) { _E = SET(4,_E); } /* SET 4,E */ +OP(cb,e4) { _H = SET(4,_H); } /* SET 4,H */ +OP(cb,e5) { _L = SET(4,_L); } /* SET 4,L */ +OP(cb,e6) { WM( _HL, SET(4,RM(_HL)) ); } /* SET 4,(HL) */ +OP(cb,e7) { _A = SET(4,_A); } /* SET 4,A */ + +OP(cb,e8) { _B = SET(5,_B); } /* SET 5,B */ +OP(cb,e9) { _C = SET(5,_C); } /* SET 5,C */ +OP(cb,ea) { _D = SET(5,_D); } /* SET 5,D */ +OP(cb,eb) { _E = SET(5,_E); } /* SET 5,E */ +OP(cb,ec) { _H = SET(5,_H); } /* SET 5,H */ +OP(cb,ed) { _L = SET(5,_L); } /* SET 5,L */ +OP(cb,ee) { WM( _HL, SET(5,RM(_HL)) ); } /* SET 5,(HL) */ +OP(cb,ef) { _A = SET(5,_A); } /* SET 5,A */ + +OP(cb,f0) { _B = SET(6,_B); } /* SET 6,B */ +OP(cb,f1) { _C = SET(6,_C); } /* SET 6,C */ +OP(cb,f2) { _D = SET(6,_D); } /* SET 6,D */ +OP(cb,f3) { _E = SET(6,_E); } /* SET 6,E */ +OP(cb,f4) { _H = SET(6,_H); } /* SET 6,H */ +OP(cb,f5) { _L = SET(6,_L); } /* SET 6,L */ +OP(cb,f6) { WM( _HL, SET(6,RM(_HL)) ); } /* SET 6,(HL) */ +OP(cb,f7) { _A = SET(6,_A); } /* SET 6,A */ + +OP(cb,f8) { _B = SET(7,_B); } /* SET 7,B */ +OP(cb,f9) { _C = SET(7,_C); } /* SET 7,C */ +OP(cb,fa) { _D = SET(7,_D); } /* SET 7,D */ +OP(cb,fb) { _E = SET(7,_E); } /* SET 7,E */ +OP(cb,fc) { _H = SET(7,_H); } /* SET 7,H */ +OP(cb,fd) { _L = SET(7,_L); } /* SET 7,L */ +OP(cb,fe) { WM( _HL, SET(7,RM(_HL)) ); } /* SET 7,(HL) */ +OP(cb,ff) { _A = SET(7,_A); } /* SET 7,A */ diff --git a/src/devices/cpu/z180/z180dasm.c b/src/devices/cpu/z180/z180dasm.c new file mode 100644 index 00000000000..5c83ed212b2 --- /dev/null +++ b/src/devices/cpu/z180/z180dasm.c @@ -0,0 +1,518 @@ +// license:BSD-3-Clause +// copyright-holders:Juergen Buchmueller +/***************************************************************************** + * + * z180dasm.c + * Portable Z8x180 disassembler + * + *****************************************************************************/ + +#include "emu.h" +#include "debugger.h" +#include "z180.h" + +enum e_mnemonics { + zADC ,zADD ,zAND ,zBIT ,zCALL ,zCCF ,zCP ,zCPD , + zCPDR ,zCPI ,zCPIR ,zCPL ,zDAA ,zDB ,zDEC ,zDI , + zDJNZ ,zEI ,zEX ,zEXX ,zHLT ,zIM ,zIN ,zIN0 , + zINC ,zIND ,zINDR ,zINI ,zINIR ,zJP ,zJR ,zLD , + zLDD ,zLDDR ,zLDI ,zLDIR ,zMLT ,zNEG ,zNOP ,zOR , + zOTDM ,zOTDMR ,zOTDR ,zOTIM ,zOTIMR ,zOTIR ,zOUT ,zOUT0 , + zOUTD ,zOUTI ,zPOP ,zPUSH ,zRES ,zRET ,zRETI ,zRETN , + zRL ,zRLA ,zRLC ,zRLCA ,zRLD ,zRR ,zRRA ,zRRC , + zRRCA ,zRRD ,zRST ,zSBC ,zSCF ,zSET ,zSLA ,zSLL , + zSLP ,zSRA ,zSRL ,zSUB ,zTST ,zTSTIO ,zXOR +}; + +static const char *const s_mnemonic[] = { + "adc" ,"add" ,"and" ,"bit" ,"call" ,"ccf" ,"cp" ,"cpd" , + "cpdr" ,"cpi" ,"cpir" ,"cpl" ,"daa" ,"db" ,"dec" ,"di" , + "djnz" ,"ei" ,"ex" ,"exx" ,"halt" ,"im" ,"in" ,"in0" , + "inc" ,"ind" ,"indr" ,"ini" ,"inir" ,"jp" ,"jr" ,"ld" , + "ldd" ,"lddr" ,"ldi" ,"ldir" ,"mlt" ,"neg" ,"nop" ,"or" , + "otdm" ,"otdmr","otdr" ,"otim" ,"otimr","otir" ,"out" ,"out0" , + "outd" ,"outi" ,"pop" ,"push" ,"res" ,"ret" ,"reti" ,"retn" , + "rl" ,"rla" ,"rlc" ,"rlca" ,"rld" ,"rr" ,"rra" ,"rrc" , + "rrca" ,"rrd" ,"rst" ,"sbc" ,"scf" ,"set" ,"sla" ,"sll" , + "slp" ,"sra" ,"srl" ,"sub" ,"tst" ,"tstio","xor " +}; + +struct z80dasm { + UINT8 mnemonic; + const char *arguments; +}; + +static const z80dasm mnemonic_xx_cb[256]= { + {zRLC,"b=Y"}, {zRLC,"c=Y"}, {zRLC,"d=Y"}, {zRLC,"e=Y"}, + {zRLC,"h=Y"}, {zRLC,"l=Y"}, {zRLC,"Y"}, {zRLC,"a=Y"}, + {zRRC,"b=Y"}, {zRRC,"c=Y"}, {zRRC,"d=Y"}, {zRRC,"e=Y"}, + {zRRC,"h=Y"}, {zRRC,"l=Y"}, {zRRC,"Y"}, {zRRC,"a=Y"}, + {zRL,"b=Y"}, {zRL,"c=Y"}, {zRL,"d=Y"}, {zRL,"e=Y"}, + {zRL,"h=Y"}, {zRL,"l=Y"}, {zRL,"Y"}, {zRL,"a=Y"}, + {zRR,"b=Y"}, {zRR,"c=Y"}, {zRR,"d=Y"}, {zRR,"e=Y"}, + {zRR,"h=Y"}, {zRR,"l=Y"}, {zRR,"Y"}, {zRR,"a=Y"}, + {zSLA,"b=Y"}, {zSLA,"c=Y"}, {zSLA,"d=Y"}, {zSLA,"e=Y"}, + {zSLA,"h=Y"}, {zSLA,"l=Y"}, {zSLA,"Y"}, {zSLA,"a=Y"}, + {zSRA,"b=Y"}, {zSRA,"c=Y"}, {zSRA,"d=Y"}, {zSRA,"e=Y"}, + {zSRA,"h=Y"}, {zSRA,"l=Y"}, {zSRA,"Y"}, {zSRA,"a=Y"}, + {zSLL,"b=Y"}, {zSLL,"c=Y"}, {zSLL,"d=Y"}, {zSLL,"e=Y"}, + {zSLL,"h=Y"}, {zSLL,"l=Y"}, {zSLL,"Y"}, {zSLL,"a=Y"}, + {zSRL,"b=Y"}, {zSRL,"c=Y"}, {zSRL,"d=Y"}, {zSRL,"e=Y"}, + {zSRL,"h=Y"}, {zSRL,"l=Y"}, {zSRL,"Y"}, {zSRL,"a=Y"}, + {zBIT,"b=0,Y"}, {zBIT,"c=0,Y"}, {zBIT,"d=0,Y"}, {zBIT,"e=0,Y"}, + {zBIT,"h=0,Y"}, {zBIT,"l=0,Y"}, {zBIT,"0,Y"}, {zBIT,"a=0,Y"}, + {zBIT,"b=1,Y"}, {zBIT,"c=1,Y"}, {zBIT,"d=1,Y"}, {zBIT,"e=1,Y"}, + {zBIT,"h=1,Y"}, {zBIT,"l=1,Y"}, {zBIT,"1,Y"}, {zBIT,"a=1,Y"}, + {zBIT,"b=2,Y"}, {zBIT,"c=2,Y"}, {zBIT,"d=2,Y"}, {zBIT,"e=2,Y"}, + {zBIT,"h=2,Y"}, {zBIT,"l=2,Y"}, {zBIT,"2,Y"}, {zBIT,"a=2,Y"}, + {zBIT,"b=3,Y"}, {zBIT,"c=3,Y"}, {zBIT,"d=3,Y"}, {zBIT,"e=3,Y"}, + {zBIT,"h=3,Y"}, {zBIT,"l=3,Y"}, {zBIT,"3,Y"}, {zBIT,"a=3,Y"}, + {zBIT,"b=4,Y"}, {zBIT,"c=4,Y"}, {zBIT,"d=4,Y"}, {zBIT,"e=4,Y"}, + {zBIT,"h=4,Y"}, {zBIT,"l=4,Y"}, {zBIT,"4,Y"}, {zBIT,"a=4,Y"}, + {zBIT,"b=5,Y"}, {zBIT,"c=5,Y"}, {zBIT,"d=5,Y"}, {zBIT,"e=5,Y"}, + {zBIT,"h=5,Y"}, {zBIT,"l=5,Y"}, {zBIT,"5,Y"}, {zBIT,"a=5,Y"}, + {zBIT,"b=6,Y"}, {zBIT,"c=6,Y"}, {zBIT,"d=6,Y"}, {zBIT,"e=6,Y"}, + {zBIT,"h=6,Y"}, {zBIT,"l=6,Y"}, {zBIT,"6,Y"}, {zBIT,"a=6,Y"}, + {zBIT,"b=7,Y"}, {zBIT,"c=7,Y"}, {zBIT,"d=7,Y"}, {zBIT,"e=7,Y"}, + {zBIT,"h=7,Y"}, {zBIT,"l=7,Y"}, {zBIT,"7,Y"}, {zBIT,"a=7,Y"}, + {zRES,"b=0,Y"}, {zRES,"c=0,Y"}, {zRES,"d=0,Y"}, {zRES,"e=0,Y"}, + {zRES,"h=0,Y"}, {zRES,"l=0,Y"}, {zRES,"0,Y"}, {zRES,"a=0,Y"}, + {zRES,"b=1,Y"}, {zRES,"c=1,Y"}, {zRES,"d=1,Y"}, {zRES,"e=1,Y"}, + {zRES,"h=1,Y"}, {zRES,"l=1,Y"}, {zRES,"1,Y"}, {zRES,"a=1,Y"}, + {zRES,"b=2,Y"}, {zRES,"c=2,Y"}, {zRES,"d=2,Y"}, {zRES,"e=2,Y"}, + {zRES,"h=2,Y"}, {zRES,"l=2,Y"}, {zRES,"2,Y"}, {zRES,"a=2,Y"}, + {zRES,"b=3,Y"}, {zRES,"c=3,Y"}, {zRES,"d=3,Y"}, {zRES,"e=3,Y"}, + {zRES,"h=3,Y"}, {zRES,"l=3,Y"}, {zRES,"3,Y"}, {zRES,"a=3,Y"}, + {zRES,"b=4,Y"}, {zRES,"c=4,Y"}, {zRES,"d=4,Y"}, {zRES,"e=4,Y"}, + {zRES,"h=4,Y"}, {zRES,"l=4,Y"}, {zRES,"4,Y"}, {zRES,"a=4,Y"}, + {zRES,"b=5,Y"}, {zRES,"c=5,Y"}, {zRES,"d=5,Y"}, {zRES,"e=5,Y"}, + {zRES,"h=5,Y"}, {zRES,"l=5,Y"}, {zRES,"5,Y"}, {zRES,"a=5,Y"}, + {zRES,"b=6,Y"}, {zRES,"c=6,Y"}, {zRES,"d=6,Y"}, {zRES,"e=6,Y"}, + {zRES,"h=6,Y"}, {zRES,"l=6,Y"}, {zRES,"6,Y"}, {zRES,"a=6,Y"}, + {zRES,"b=7,Y"}, {zRES,"c=7,Y"}, {zRES,"d=7,Y"}, {zRES,"e=7,Y"}, + {zRES,"h=7,Y"}, {zRES,"l=7,Y"}, {zRES,"7,Y"}, {zRES,"a=7,Y"}, + {zSET,"b=0,Y"}, {zSET,"c=0,Y"}, {zSET,"d=0,Y"}, {zSET,"e=0,Y"}, + {zSET,"h=0,Y"}, {zSET,"l=0,Y"}, {zSET,"0,Y"}, {zSET,"a=0,Y"}, + {zSET,"b=1,Y"}, {zSET,"c=1,Y"}, {zSET,"d=1,Y"}, {zSET,"e=1,Y"}, + {zSET,"h=1,Y"}, {zSET,"l=1,Y"}, {zSET,"1,Y"}, {zSET,"a=1,Y"}, + {zSET,"b=2,Y"}, {zSET,"c=2,Y"}, {zSET,"d=2,Y"}, {zSET,"e=2,Y"}, + {zSET,"h=2,Y"}, {zSET,"l=2,Y"}, {zSET,"2,Y"}, {zSET,"a=2,Y"}, + {zSET,"b=3,Y"}, {zSET,"c=3,Y"}, {zSET,"d=3,Y"}, {zSET,"e=3,Y"}, + {zSET,"h=3,Y"}, {zSET,"l=3,Y"}, {zSET,"3,Y"}, {zSET,"a=3,Y"}, + {zSET,"b=4,Y"}, {zSET,"c=4,Y"}, {zSET,"d=4,Y"}, {zSET,"e=4,Y"}, + {zSET,"h=4,Y"}, {zSET,"l=4,Y"}, {zSET,"4,Y"}, {zSET,"a=4,Y"}, + {zSET,"b=5,Y"}, {zSET,"c=5,Y"}, {zSET,"d=5,Y"}, {zSET,"e=5,Y"}, + {zSET,"h=5,Y"}, {zSET,"l=5,Y"}, {zSET,"5,Y"}, {zSET,"a=5,Y"}, + {zSET,"b=6,Y"}, {zSET,"c=6,Y"}, {zSET,"d=6,Y"}, {zSET,"e=6,Y"}, + {zSET,"h=6,Y"}, {zSET,"l=6,Y"}, {zSET,"6,Y"}, {zSET,"a=6,Y"}, + {zSET,"b=7,Y"}, {zSET,"c=7,Y"}, {zSET,"d=7,Y"}, {zSET,"e=7,Y"}, + {zSET,"h=7,Y"}, {zSET,"l=7,Y"}, {zSET,"7,Y"}, {zSET,"a=7,Y"} +}; + +static const z80dasm mnemonic_cb[256] = { + {zRLC,"b"}, {zRLC,"c"}, {zRLC,"d"}, {zRLC,"e"}, + {zRLC,"h"}, {zRLC,"l"}, {zRLC,"(hl)"}, {zRLC,"a"}, + {zRRC,"b"}, {zRRC,"c"}, {zRRC,"d"}, {zRRC,"e"}, + {zRRC,"h"}, {zRRC,"l"}, {zRRC,"(hl)"}, {zRRC,"a"}, + {zRL,"b"}, {zRL,"c"}, {zRL,"d"}, {zRL,"e"}, + {zRL,"h"}, {zRL,"l"}, {zRL,"(hl)"}, {zRL,"a"}, + {zRR,"b"}, {zRR,"c"}, {zRR,"d"}, {zRR,"e"}, + {zRR,"h"}, {zRR,"l"}, {zRR,"(hl)"}, {zRR,"a"}, + {zSLA,"b"}, {zSLA,"c"}, {zSLA,"d"}, {zSLA,"e"}, + {zSLA,"h"}, {zSLA,"l"}, {zSLA,"(hl)"}, {zSLA,"a"}, + {zSRA,"b"}, {zSRA,"c"}, {zSRA,"d"}, {zSRA,"e"}, + {zSRA,"h"}, {zSRA,"l"}, {zSRA,"(hl)"}, {zSRA,"a"}, + {zSLL,"b"}, {zSLL,"c"}, {zSLL,"d"}, {zSLL,"e"}, + {zSLL,"h"}, {zSLL,"l"}, {zSLL,"(hl)"}, {zSLL,"a"}, + {zSRL,"b"}, {zSRL,"c"}, {zSRL,"d"}, {zSRL,"e"}, + {zSRL,"h"}, {zSRL,"l"}, {zSRL,"(hl)"}, {zSRL,"a"}, + {zBIT,"0,b"}, {zBIT,"0,c"}, {zBIT,"0,d"}, {zBIT,"0,e"}, + {zBIT,"0,h"}, {zBIT,"0,l"}, {zBIT,"0,(hl)"},{zBIT,"0,a"}, + {zBIT,"1,b"}, {zBIT,"1,c"}, {zBIT,"1,d"}, {zBIT,"1,e"}, + {zBIT,"1,h"}, {zBIT,"1,l"}, {zBIT,"1,(hl)"},{zBIT,"1,a"}, + {zBIT,"2,b"}, {zBIT,"2,c"}, {zBIT,"2,d"}, {zBIT,"2,e"}, + {zBIT,"2,h"}, {zBIT,"2,l"}, {zBIT,"2,(hl)"},{zBIT,"2,a"}, + {zBIT,"3,b"}, {zBIT,"3,c"}, {zBIT,"3,d"}, {zBIT,"3,e"}, + {zBIT,"3,h"}, {zBIT,"3,l"}, {zBIT,"3,(hl)"},{zBIT,"3,a"}, + {zBIT,"4,b"}, {zBIT,"4,c"}, {zBIT,"4,d"}, {zBIT,"4,e"}, + {zBIT,"4,h"}, {zBIT,"4,l"}, {zBIT,"4,(hl)"},{zBIT,"4,a"}, + {zBIT,"5,b"}, {zBIT,"5,c"}, {zBIT,"5,d"}, {zBIT,"5,e"}, + {zBIT,"5,h"}, {zBIT,"5,l"}, {zBIT,"5,(hl)"},{zBIT,"5,a"}, + {zBIT,"6,b"}, {zBIT,"6,c"}, {zBIT,"6,d"}, {zBIT,"6,e"}, + {zBIT,"6,h"}, {zBIT,"6,l"}, {zBIT,"6,(hl)"},{zBIT,"6,a"}, + {zBIT,"7,b"}, {zBIT,"7,c"}, {zBIT,"7,d"}, {zBIT,"7,e"}, + {zBIT,"7,h"}, {zBIT,"7,l"}, {zBIT,"7,(hl)"},{zBIT,"7,a"}, + {zRES,"0,b"}, {zRES,"0,c"}, {zRES,"0,d"}, {zRES,"0,e"}, + {zRES,"0,h"}, {zRES,"0,l"}, {zRES,"0,(hl)"},{zRES,"0,a"}, + {zRES,"1,b"}, {zRES,"1,c"}, {zRES,"1,d"}, {zRES,"1,e"}, + {zRES,"1,h"}, {zRES,"1,l"}, {zRES,"1,(hl)"},{zRES,"1,a"}, + {zRES,"2,b"}, {zRES,"2,c"}, {zRES,"2,d"}, {zRES,"2,e"}, + {zRES,"2,h"}, {zRES,"2,l"}, {zRES,"2,(hl)"},{zRES,"2,a"}, + {zRES,"3,b"}, {zRES,"3,c"}, {zRES,"3,d"}, {zRES,"3,e"}, + {zRES,"3,h"}, {zRES,"3,l"}, {zRES,"3,(hl)"},{zRES,"3,a"}, + {zRES,"4,b"}, {zRES,"4,c"}, {zRES,"4,d"}, {zRES,"4,e"}, + {zRES,"4,h"}, {zRES,"4,l"}, {zRES,"4,(hl)"},{zRES,"4,a"}, + {zRES,"5,b"}, {zRES,"5,c"}, {zRES,"5,d"}, {zRES,"5,e"}, + {zRES,"5,h"}, {zRES,"5,l"}, {zRES,"5,(hl)"},{zRES,"5,a"}, + {zRES,"6,b"}, {zRES,"6,c"}, {zRES,"6,d"}, {zRES,"6,e"}, + {zRES,"6,h"}, {zRES,"6,l"}, {zRES,"6,(hl)"},{zRES,"6,a"}, + {zRES,"7,b"}, {zRES,"7,c"}, {zRES,"7,d"}, {zRES,"7,e"}, + {zRES,"7,h"}, {zRES,"7,l"}, {zRES,"7,(hl)"},{zRES,"7,a"}, + {zSET,"0,b"}, {zSET,"0,c"}, {zSET,"0,d"}, {zSET,"0,e"}, + {zSET,"0,h"}, {zSET,"0,l"}, {zSET,"0,(hl)"},{zSET,"0,a"}, + {zSET,"1,b"}, {zSET,"1,c"}, {zSET,"1,d"}, {zSET,"1,e"}, + {zSET,"1,h"}, {zSET,"1,l"}, {zSET,"1,(hl)"},{zSET,"1,a"}, + {zSET,"2,b"}, {zSET,"2,c"}, {zSET,"2,d"}, {zSET,"2,e"}, + {zSET,"2,h"}, {zSET,"2,l"}, {zSET,"2,(hl)"},{zSET,"2,a"}, + {zSET,"3,b"}, {zSET,"3,c"}, {zSET,"3,d"}, {zSET,"3,e"}, + {zSET,"3,h"}, {zSET,"3,l"}, {zSET,"3,(hl)"},{zSET,"3,a"}, + {zSET,"4,b"}, {zSET,"4,c"}, {zSET,"4,d"}, {zSET,"4,e"}, + {zSET,"4,h"}, {zSET,"4,l"}, {zSET,"4,(hl)"},{zSET,"4,a"}, + {zSET,"5,b"}, {zSET,"5,c"}, {zSET,"5,d"}, {zSET,"5,e"}, + {zSET,"5,h"}, {zSET,"5,l"}, {zSET,"5,(hl)"},{zSET,"5,a"}, + {zSET,"6,b"}, {zSET,"6,c"}, {zSET,"6,d"}, {zSET,"6,e"}, + {zSET,"6,h"}, {zSET,"6,l"}, {zSET,"6,(hl)"},{zSET,"6,a"}, + {zSET,"7,b"}, {zSET,"7,c"}, {zSET,"7,d"}, {zSET,"7,e"}, + {zSET,"7,h"}, {zSET,"7,l"}, {zSET,"7,(hl)"},{zSET,"7,a"} +}; + +static const z80dasm mnemonic_ed[256]= { + {zIN0,"b,(B)"}, {zOUT0,"(B),b"},{zDB,"?"}, {zDB,"?"}, + {zTST,"b"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zIN0,"c,(B)"}, {zOUT0,"(B),c"},{zDB,"?"}, {zDB,"?"}, + {zTST,"c"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zIN0,"d,(B)"}, {zOUT0,"(B),d"},{zDB,"?"}, {zDB,"?"}, + {zTST,"d"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zIN0,"e,(B)"}, {zOUT0,"(B),e"},{zDB,"?"}, {zDB,"?"}, + {zTST,"e"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zIN0,"h,(B)"}, {zOUT0,"(B),h"},{zDB,"?"}, {zDB,"?"}, + {zTST,"h"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zIN0,"l,(B)"}, {zOUT0,"(B),l"},{zDB,"?"}, {zDB,"?"}, + {zTST,"l"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zIN0,"f,(B)"}, {zOUT0,"(B),0"},{zDB,"?"}, {zDB,"?"}, + {zTST,"(hl)"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zIN0,"a,(B)"}, {zOUT0,"(B),a"},{zDB,"?"}, {zDB,"?"}, + {zTST,"a"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zIN,"b,(c)"}, {zOUT,"(c),b"}, {zSBC,"hl,bc"}, {zLD,"(W),bc"}, + {zNEG,0}, {zRETN,0}, {zIM,"0"}, {zLD,"i,a"}, + {zIN,"c,(c)"}, {zOUT,"(c),c"}, {zADC,"hl,bc"}, {zLD,"bc,(W)"}, + {zMLT,"bc"}, {zRETI,0}, {zIM,"0"}, {zLD,"r,a"}, + {zIN,"d,(c)"}, {zOUT,"(c),d"}, {zSBC,"hl,de"}, {zLD,"(W),de"}, + {zNEG,"*"}, {zRETN,0}, {zIM,"1"}, {zLD,"a,i"}, + {zIN,"e,(c)"}, {zOUT,"(c),e"}, {zADC,"hl,de"}, {zLD,"de,(W)"}, + {zMLT,"de"}, {zRETI,0}, {zIM,"2"}, {zLD,"a,r"}, + {zIN,"h,(c)"}, {zOUT,"(c),h"}, {zSBC,"hl,hl"}, {zLD,"(W),hl"}, + {zTST,"B"}, {zRETN,0}, {zIM,"0"}, {zRRD,"(hl)"}, + {zIN,"l,(c)"}, {zOUT,"(c),l"}, {zADC,"hl,hl"}, {zLD,"hl,(W)"}, + {zMLT,"hl"}, {zRETI,0}, {zIM,"0"}, {zRLD,"(hl)"}, + {zIN,"0,(c)"}, {zOUT,"(c),0"}, {zSBC,"hl,sp"}, {zLD,"(W),sp"}, + {zTSTIO,"B"}, {zRETN,0}, {zSLP,0}, {zDB,"?"}, + {zIN,"a,(c)"}, {zOUT,"(c),a"}, {zADC,"hl,sp"}, {zLD,"sp,(W)"}, + {zMLT,"sp"}, {zRETI,0}, {zIM,"2"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zOTIM,0}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zOTDM,0}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zOTIMR,0}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zOTDMR,0}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zLDI,0}, {zCPI,0}, {zINI,0}, {zOUTI,0}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zLDD,0}, {zCPD,0}, {zIND,0}, {zOUTD,0}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zLDIR,0}, {zCPIR,0}, {zINIR,0}, {zOTIR,0}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zLDDR,0}, {zCPDR,0}, {zINDR,0}, {zOTDR,0}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"} +}; + +static const z80dasm mnemonic_xx[256]= { + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zDB,"?"}, {zADD,"I,bc"}, {zDB,"?"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zDB,"?"}, {zADD,"I,de"}, {zDB,"?"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zDB,"?"}, {zLD,"I,N"}, {zLD,"(W),I"}, {zINC,"I"}, + {zINC,"Ih"}, {zDEC,"Ih"}, {zLD,"Ih,B"}, {zDB,"?"}, + {zDB,"?"}, {zADD,"I,I"}, {zLD,"I,(W)"}, {zDEC,"I"}, + {zINC,"Il"}, {zDEC,"Il"}, {zLD,"Il,B"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zINC,"X"}, {zDEC,"X"}, {zLD,"X,B"}, {zDB,"?"}, + {zDB,"?"}, {zADD,"I,sp"}, {zDB,"?"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zLD,"b,Ih"}, {zLD,"b,Il"}, {zLD,"b,X"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zLD,"c,Ih"}, {zLD,"c,Il"}, {zLD,"c,X"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zLD,"d,Ih"}, {zLD,"d,Il"}, {zLD,"d,X"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zLD,"e,Ih"}, {zLD,"e,Il"}, {zLD,"e,X"}, {zDB,"?"}, + {zLD,"Ih,b"}, {zLD,"Ih,c"}, {zLD,"Ih,d"}, {zLD,"Ih,e"}, + {zLD,"Ih,Ih"}, {zLD,"Ih,Il"}, {zLD,"h,X"}, {zLD,"Ih,a"}, + {zLD,"Il,b"}, {zLD,"Il,c"}, {zLD,"Il,d"}, {zLD,"Il,e"}, + {zLD,"Il,Ih"}, {zLD,"Il,Il"}, {zLD,"l,X"}, {zLD,"Il,a"}, + {zLD,"X,b"}, {zLD,"X,c"}, {zLD,"X,d"}, {zLD,"X,e"}, + {zLD,"X,h"}, {zLD,"X,l"}, {zDB,"?"}, {zLD,"X,a"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zLD,"a,Ih"}, {zLD,"a,Il"}, {zLD,"a,X"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zADD,"a,Ih"}, {zADD,"a,Il"}, {zADD,"a,X"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zADC,"a,Ih"}, {zADC,"a,Il"}, {zADC,"a,X"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zSUB,"Ih"}, {zSUB,"Il"}, {zSUB,"X"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zSBC,"a,Ih"}, {zSBC,"a,Il"}, {zSBC,"a,X"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zAND,"Ih"}, {zAND,"Il"}, {zAND,"X"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zXOR,"Ih"}, {zXOR,"Il"}, {zXOR,"X"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zOR,"Ih"}, {zOR,"Il"}, {zOR,"X"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zCP,"Ih"}, {zCP,"Il"}, {zCP,"X"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"cb"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zDB,"?"}, {zPOP,"I"}, {zDB,"?"}, {zEX,"(sp),I"}, + {zDB,"?"}, {zPUSH,"I"}, {zDB,"?"}, {zDB,"?"}, + {zDB,"?"}, {zJP,"(I)"}, {zDB,"?"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zDB,"?"}, {zLD,"sp,I"}, {zDB,"?"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"} +}; + +static const z80dasm mnemonic_main[256]= { + {zNOP,0}, {zLD,"bc,N"}, {zLD,"(bc),a"}, {zINC,"bc"}, + {zINC,"b"}, {zDEC,"b"}, {zLD,"b,B"}, {zRLCA,0}, + {zEX,"af,af'"}, {zADD,"hl,bc"}, {zLD,"a,(bc)"}, {zDEC,"bc"}, + {zINC,"c"}, {zDEC,"c"}, {zLD,"c,B"}, {zRRCA,0}, + {zDJNZ,"O"}, {zLD,"de,N"}, {zLD,"(de),a"}, {zINC,"de"}, + {zINC,"d"}, {zDEC,"d"}, {zLD,"d,B"}, {zRLA,0}, + {zJR,"O"}, {zADD,"hl,de"}, {zLD,"a,(de)"}, {zDEC,"de"}, + {zINC,"e"}, {zDEC,"e"}, {zLD,"e,B"}, {zRRA,0}, + {zJR,"nz,O"}, {zLD,"hl,N"}, {zLD,"(W),hl"}, {zINC,"hl"}, + {zINC,"h"}, {zDEC,"h"}, {zLD,"h,B"}, {zDAA,0}, + {zJR,"z,O"}, {zADD,"hl,hl"}, {zLD,"hl,(W)"}, {zDEC,"hl"}, + {zINC,"l"}, {zDEC,"l"}, {zLD,"l,B"}, {zCPL,0}, + {zJR,"nc,O"}, {zLD,"sp,N"}, {zLD,"(W),a"}, {zINC,"sp"}, + {zINC,"(hl)"}, {zDEC,"(hl)"}, {zLD,"(hl),B"}, {zSCF,0}, + {zJR,"c,O"}, {zADD,"hl,sp"}, {zLD,"a,(W)"}, {zDEC,"sp"}, + {zINC,"a"}, {zDEC,"a"}, {zLD,"a,B"}, {zCCF,0}, + {zLD,"b,b"}, {zLD,"b,c"}, {zLD,"b,d"}, {zLD,"b,e"}, + {zLD,"b,h"}, {zLD,"b,l"}, {zLD,"b,(hl)"}, {zLD,"b,a"}, + {zLD,"c,b"}, {zLD,"c,c"}, {zLD,"c,d"}, {zLD,"c,e"}, + {zLD,"c,h"}, {zLD,"c,l"}, {zLD,"c,(hl)"}, {zLD,"c,a"}, + {zLD,"d,b"}, {zLD,"d,c"}, {zLD,"d,d"}, {zLD,"d,e"}, + {zLD,"d,h"}, {zLD,"d,l"}, {zLD,"d,(hl)"}, {zLD,"d,a"}, + {zLD,"e,b"}, {zLD,"e,c"}, {zLD,"e,d"}, {zLD,"e,e"}, + {zLD,"e,h"}, {zLD,"e,l"}, {zLD,"e,(hl)"}, {zLD,"e,a"}, + {zLD,"h,b"}, {zLD,"h,c"}, {zLD,"h,d"}, {zLD,"h,e"}, + {zLD,"h,h"}, {zLD,"h,l"}, {zLD,"h,(hl)"}, {zLD,"h,a"}, + {zLD,"l,b"}, {zLD,"l,c"}, {zLD,"l,d"}, {zLD,"l,e"}, + {zLD,"l,h"}, {zLD,"l,l"}, {zLD,"l,(hl)"}, {zLD,"l,a"}, + {zLD,"(hl),b"}, {zLD,"(hl),c"}, {zLD,"(hl),d"}, {zLD,"(hl),e"}, + {zLD,"(hl),h"}, {zLD,"(hl),l"}, {zHLT,0}, {zLD,"(hl),a"}, + {zLD,"a,b"}, {zLD,"a,c"}, {zLD,"a,d"}, {zLD,"a,e"}, + {zLD,"a,h"}, {zLD,"a,l"}, {zLD,"a,(hl)"}, {zLD,"a,a"}, + {zADD,"a,b"}, {zADD,"a,c"}, {zADD,"a,d"}, {zADD,"a,e"}, + {zADD,"a,h"}, {zADD,"a,l"}, {zADD,"a,(hl)"},{zADD,"a,a"}, + {zADC,"a,b"}, {zADC,"a,c"}, {zADC,"a,d"}, {zADC,"a,e"}, + {zADC,"a,h"}, {zADC,"a,l"}, {zADC,"a,(hl)"},{zADC,"a,a"}, + {zSUB,"b"}, {zSUB,"c"}, {zSUB,"d"}, {zSUB,"e"}, + {zSUB,"h"}, {zSUB,"l"}, {zSUB,"(hl)"}, {zSUB,"a"}, + {zSBC,"a,b"}, {zSBC,"a,c"}, {zSBC,"a,d"}, {zSBC,"a,e"}, + {zSBC,"a,h"}, {zSBC,"a,l"}, {zSBC,"a,(hl)"},{zSBC,"a,a"}, + {zAND,"b"}, {zAND,"c"}, {zAND,"d"}, {zAND,"e"}, + {zAND,"h"}, {zAND,"l"}, {zAND,"(hl)"}, {zAND,"a"}, + {zXOR,"b"}, {zXOR,"c"}, {zXOR,"d"}, {zXOR,"e"}, + {zXOR,"h"}, {zXOR,"l"}, {zXOR,"(hl)"}, {zXOR,"a"}, + {zOR,"b"}, {zOR,"c"}, {zOR,"d"}, {zOR,"e"}, + {zOR,"h"}, {zOR,"l"}, {zOR,"(hl)"}, {zOR,"a"}, + {zCP,"b"}, {zCP,"c"}, {zCP,"d"}, {zCP,"e"}, + {zCP,"h"}, {zCP,"l"}, {zCP,"(hl)"}, {zCP,"a"}, + {zRET,"nz"}, {zPOP,"bc"}, {zJP,"nz,A"}, {zJP,"A"}, + {zCALL,"nz,A"}, {zPUSH,"bc"}, {zADD,"a,B"}, {zRST,"V"}, + {zRET,"z"}, {zRET,0}, {zJP,"z,A"}, {zDB,"cb"}, + {zCALL,"z,A"}, {zCALL,"A"}, {zADC,"a,B"}, {zRST,"V"}, + {zRET,"nc"}, {zPOP,"de"}, {zJP,"nc,A"}, {zOUT,"(P),a"}, + {zCALL,"nc,A"}, {zPUSH,"de"}, {zSUB,"B"}, {zRST,"V"}, + {zRET,"c"}, {zEXX,0}, {zJP,"c,A"}, {zIN,"a,(P)"}, + {zCALL,"c,A"}, {zDB,"dd"}, {zSBC,"a,B"}, {zRST,"V"}, + {zRET,"po"}, {zPOP,"hl"}, {zJP,"po,A"}, {zEX,"(sp),hl"}, + {zCALL,"po,A"}, {zPUSH,"hl"}, {zAND,"B"}, {zRST,"V"}, + {zRET,"pe"}, {zJP,"(hl)"}, {zJP,"pe,A"}, {zEX,"de,hl"}, + {zCALL,"pe,A"}, {zDB,"ed"}, {zXOR,"B"}, {zRST,"V"}, + {zRET,"p"}, {zPOP,"af"}, {zJP,"p,A"}, {zDI,0}, + {zCALL,"p,A"}, {zPUSH,"af"}, {zOR,"B"}, {zRST,"V"}, + {zRET,"m"}, {zLD,"sp,hl"}, {zJP,"m,A"}, {zEI,0}, + {zCALL,"m,A"}, {zDB,"fd"}, {zCP,"B"}, {zRST,"V"} +}; + +static char sign(INT8 offset) +{ + return (offset < 0)? '-':'+'; +} + +static int offs(INT8 offset) +{ + if (offset < 0) return -offset; + return offset; +} + +/**************************************************************************** + * Disassemble opcode at PC and return number of bytes it takes + ****************************************************************************/ +CPU_DISASSEMBLE( z180 ) +{ + const z80dasm *d; + const char *src, *ixy; + char *dst; + unsigned PC = pc; + INT8 offset = 0; + UINT8 op, op1 = 0; + UINT16 ea = 0; + int pos = 0; + UINT32 flags = 0; + + ixy = "oops!!"; + dst = buffer; + + op = oprom[pos++]; + + switch (op) + { + case 0xcb: + op = oprom[pos++]; + d = &mnemonic_cb[op]; + break; + case 0xed: + op1 = oprom[pos++]; + d = &mnemonic_ed[op1]; + break; + case 0xdd: + ixy = "ix"; + op1 = oprom[pos++]; + if( op1 == 0xcb ) + { + offset = (INT8) opram[pos++]; + op1 = opram[pos++]; /* fourth byte from opbase.ram! */ + d = &mnemonic_xx_cb[op1]; + } + else d = &mnemonic_xx[op1]; + break; + case 0xfd: + ixy = "iy"; + op1 = oprom[pos++]; + if( op1 == 0xcb ) + { + offset = (INT8) opram[pos++]; + op1 = opram[pos++]; /* fourth byte from opbase.ram! */ + d = &mnemonic_xx_cb[op1]; + } + else d = &mnemonic_xx[op1]; + break; + default: + d = &mnemonic_main[op]; + break; + } + + if( d->arguments ) + { + dst += sprintf(dst, "%-5s ", s_mnemonic[d->mnemonic]); + src = d->arguments; + while( *src ) + { + switch( *src ) + { + case '?': /* illegal opcode */ + dst += sprintf( dst, "$%02x,$%02x", op, op1); + break; + case 'A': + ea = opram[pos] + ( opram[pos+1] << 8); + pos += 2; + dst += sprintf( dst, "$%04X", ea ); + break; + case 'B': /* Byte op arg */ + ea = opram[pos++]; + dst += sprintf( dst, "$%02X", ea ); + break; + case 'N': /* Immediate 16 bit */ + ea = opram[pos] + ( opram[pos+1] << 8 ); + pos += 2; + dst += sprintf( dst, "$%04X", ea ); + break; + case 'O': /* Offset relative to PC */ + offset = (INT8) opram[pos++]; + dst += sprintf( dst, "$%05X", PC + offset + 2 ); + break; + case 'P': /* Port number */ + ea = opram[pos++]; + dst += sprintf( dst, "$%02X", ea ); + break; + case 'V': /* Restart vector */ + ea = op & 0x38; + dst += sprintf( dst, "$%02X", ea ); + break; + case 'W': /* Memory address word */ + ea = opram[pos] + ( opram[pos+1] << 8); + pos += 2; + dst += sprintf( dst, "$%05X", ea ); + break; + case 'X': + offset = (INT8) opram[pos++]; + case 'Y': + dst += sprintf( dst,"(%s%c$%02x)", ixy, sign(offset), offs(offset) ); + break; + case 'I': + dst += sprintf( dst, "%s", ixy); + break; + default: + *dst++ = *src; + } + src++; + } + *dst = '\0'; + } + else + { + dst += sprintf(dst, "%s", s_mnemonic[d->mnemonic]); + } + + if (d->mnemonic == zCALL || d->mnemonic == zCPDR || d->mnemonic == zCPIR || d->mnemonic == zDJNZ || + d->mnemonic == zHLT || d->mnemonic == zINDR || d->mnemonic == zINIR || d->mnemonic == zLDDR || + d->mnemonic == zLDIR || d->mnemonic == zOTDR || d->mnemonic == zOTIR || d->mnemonic == zRST) + flags = DASMFLAG_STEP_OVER; + else if (d->mnemonic == zRETN || d->mnemonic == zRET || d->mnemonic == zRETI) + flags = DASMFLAG_STEP_OUT; + + return pos | flags | DASMFLAG_SUPPORTED; +} diff --git a/src/devices/cpu/z180/z180dd.inc b/src/devices/cpu/z180/z180dd.inc new file mode 100644 index 00000000000..bd2a9fc7137 --- /dev/null +++ b/src/devices/cpu/z180/z180dd.inc @@ -0,0 +1,297 @@ +// license:BSD-3-Clause +// copyright-holders:Juergen Buchmueller +OP(illegal,1) { + logerror("Z180 '%s' ill. opcode $%02x $%02x\n", + tag(), m_odirect->read_byte((_PCD-1)&0xffff), m_odirect->read_byte(_PCD)); +} + +/********************************************************** + * IX register related opcodes (DD prefix) + **********************************************************/ +OP(dd,00) { illegal_1(); op_00(); } /* DB DD */ +OP(dd,01) { illegal_1(); op_01(); } /* DB DD */ +OP(dd,02) { illegal_1(); op_02(); } /* DB DD */ +OP(dd,03) { illegal_1(); op_03(); } /* DB DD */ +OP(dd,04) { illegal_1(); op_04(); } /* DB DD */ +OP(dd,05) { illegal_1(); op_05(); } /* DB DD */ +OP(dd,06) { illegal_1(); op_06(); } /* DB DD */ +OP(dd,07) { illegal_1(); op_07(); } /* DB DD */ + +OP(dd,08) { illegal_1(); op_08(); } /* DB DD */ +OP(dd,09) { m_R++; ADD16(IX,BC); } /* ADD IX,BC */ +OP(dd,0a) { illegal_1(); op_0a(); } /* DB DD */ +OP(dd,0b) { illegal_1(); op_0b(); } /* DB DD */ +OP(dd,0c) { illegal_1(); op_0c(); } /* DB DD */ +OP(dd,0d) { illegal_1(); op_0d(); } /* DB DD */ +OP(dd,0e) { illegal_1(); op_0e(); } /* DB DD */ +OP(dd,0f) { illegal_1(); op_0f(); } /* DB DD */ + +OP(dd,10) { illegal_1(); op_10(); } /* DB DD */ +OP(dd,11) { illegal_1(); op_11(); } /* DB DD */ +OP(dd,12) { illegal_1(); op_12(); } /* DB DD */ +OP(dd,13) { illegal_1(); op_13(); } /* DB DD */ +OP(dd,14) { illegal_1(); op_14(); } /* DB DD */ +OP(dd,15) { illegal_1(); op_15(); } /* DB DD */ +OP(dd,16) { illegal_1(); op_16(); } /* DB DD */ +OP(dd,17) { illegal_1(); op_17(); } /* DB DD */ + +OP(dd,18) { illegal_1(); op_18(); } /* DB DD */ +OP(dd,19) { m_R++; ADD16(IX,DE); } /* ADD IX,DE */ +OP(dd,1a) { illegal_1(); op_1a(); } /* DB DD */ +OP(dd,1b) { illegal_1(); op_1b(); } /* DB DD */ +OP(dd,1c) { illegal_1(); op_1c(); } /* DB DD */ +OP(dd,1d) { illegal_1(); op_1d(); } /* DB DD */ +OP(dd,1e) { illegal_1(); op_1e(); } /* DB DD */ +OP(dd,1f) { illegal_1(); op_1f(); } /* DB DD */ + +OP(dd,20) { illegal_1(); op_20(); } /* DB DD */ +OP(dd,21) { m_R++; _IX = ARG16(); } /* LD IX,w */ +OP(dd,22) { m_R++; m_ea = ARG16(); WM16( m_ea, &m_IX ); } /* LD (w),IX */ +OP(dd,23) { m_R++; _IX++; } /* INC IX */ +OP(dd,24) { m_R++; _HX = INC(_HX); } /* INC HX */ +OP(dd,25) { m_R++; _HX = DEC(_HX); } /* DEC HX */ +OP(dd,26) { m_R++; _HX = ARG(); } /* LD HX,n */ +OP(dd,27) { illegal_1(); op_27(); } /* DB DD */ + +OP(dd,28) { illegal_1(); op_28(); } /* DB DD */ +OP(dd,29) { m_R++; ADD16(IX,IX); } /* ADD IX,IX */ +OP(dd,2a) { m_R++; m_ea = ARG16(); RM16( m_ea, &m_IX ); } /* LD IX,(w) */ +OP(dd,2b) { m_R++; _IX--; } /* DEC IX */ +OP(dd,2c) { m_R++; _LX = INC(_LX); } /* INC LX */ +OP(dd,2d) { m_R++; _LX = DEC(_LX); } /* DEC LX */ +OP(dd,2e) { m_R++; _LX = ARG(); } /* LD LX,n */ +OP(dd,2f) { illegal_1(); op_2f(); } /* DB DD */ + +OP(dd,30) { illegal_1(); op_30(); } /* DB DD */ +OP(dd,31) { illegal_1(); op_31(); } /* DB DD */ +OP(dd,32) { illegal_1(); op_32(); } /* DB DD */ +OP(dd,33) { illegal_1(); op_33(); } /* DB DD */ +OP(dd,34) { m_R++; EAX(); WM( m_ea, INC(RM(m_ea)) ); } /* INC (IX+o) */ +OP(dd,35) { m_R++; EAX(); WM( m_ea, DEC(RM(m_ea)) ); } /* DEC (IX+o) */ +OP(dd,36) { m_R++; EAX(); WM( m_ea, ARG() ); } /* LD (IX+o),n */ +OP(dd,37) { illegal_1(); op_37(); } /* DB DD */ + +OP(dd,38) { illegal_1(); op_38(); } /* DB DD */ +OP(dd,39) { m_R++; ADD16(IX,SP); } /* ADD IX,SP */ +OP(dd,3a) { illegal_1(); op_3a(); } /* DB DD */ +OP(dd,3b) { illegal_1(); op_3b(); } /* DB DD */ +OP(dd,3c) { illegal_1(); op_3c(); } /* DB DD */ +OP(dd,3d) { illegal_1(); op_3d(); } /* DB DD */ +OP(dd,3e) { illegal_1(); op_3e(); } /* DB DD */ +OP(dd,3f) { illegal_1(); op_3f(); } /* DB DD */ + +OP(dd,40) { illegal_1(); op_40(); } /* DB DD */ +OP(dd,41) { illegal_1(); op_41(); } /* DB DD */ +OP(dd,42) { illegal_1(); op_42(); } /* DB DD */ +OP(dd,43) { illegal_1(); op_43(); } /* DB DD */ +OP(dd,44) { m_R++; _B = _HX; } /* LD B,HX */ +OP(dd,45) { m_R++; _B = _LX; } /* LD B,LX */ +OP(dd,46) { m_R++; EAX(); _B = RM(m_ea); } /* LD B,(IX+o) */ +OP(dd,47) { illegal_1(); op_47(); } /* DB DD */ + +OP(dd,48) { illegal_1(); op_48(); } /* DB DD */ +OP(dd,49) { illegal_1(); op_49(); } /* DB DD */ +OP(dd,4a) { illegal_1(); op_4a(); } /* DB DD */ +OP(dd,4b) { illegal_1(); op_4b(); } /* DB DD */ +OP(dd,4c) { m_R++; _C = _HX; } /* LD C,HX */ +OP(dd,4d) { m_R++; _C = _LX; } /* LD C,LX */ +OP(dd,4e) { m_R++; EAX(); _C = RM(m_ea); } /* LD C,(IX+o) */ +OP(dd,4f) { illegal_1(); op_4f(); } /* DB DD */ + +OP(dd,50) { illegal_1(); op_50(); } /* DB DD */ +OP(dd,51) { illegal_1(); op_51(); } /* DB DD */ +OP(dd,52) { illegal_1(); op_52(); } /* DB DD */ +OP(dd,53) { illegal_1(); op_53(); } /* DB DD */ +OP(dd,54) { m_R++; _D = _HX; } /* LD D,HX */ +OP(dd,55) { m_R++; _D = _LX; } /* LD D,LX */ +OP(dd,56) { m_R++; EAX(); _D = RM(m_ea); } /* LD D,(IX+o) */ +OP(dd,57) { illegal_1(); op_57(); } /* DB DD */ + +OP(dd,58) { illegal_1(); op_58(); } /* DB DD */ +OP(dd,59) { illegal_1(); op_59(); } /* DB DD */ +OP(dd,5a) { illegal_1(); op_5a(); } /* DB DD */ +OP(dd,5b) { illegal_1(); op_5b(); } /* DB DD */ +OP(dd,5c) { m_R++; _E = _HX; } /* LD E,HX */ +OP(dd,5d) { m_R++; _E = _LX; } /* LD E,LX */ +OP(dd,5e) { m_R++; EAX(); _E = RM(m_ea); } /* LD E,(IX+o) */ +OP(dd,5f) { illegal_1(); op_5f(); } /* DB DD */ + +OP(dd,60) { m_R++; _HX = _B; } /* LD HX,B */ +OP(dd,61) { m_R++; _HX = _C; } /* LD HX,C */ +OP(dd,62) { m_R++; _HX = _D; } /* LD HX,D */ +OP(dd,63) { m_R++; _HX = _E; } /* LD HX,E */ +OP(dd,64) { } /* LD HX,HX */ +OP(dd,65) { m_R++; _HX = _LX; } /* LD HX,LX */ +OP(dd,66) { m_R++; EAX(); _H = RM(m_ea); } /* LD H,(IX+o) */ +OP(dd,67) { m_R++; _HX = _A; } /* LD HX,A */ + +OP(dd,68) { m_R++; _LX = _B; } /* LD LX,B */ +OP(dd,69) { m_R++; _LX = _C; } /* LD LX,C */ +OP(dd,6a) { m_R++; _LX = _D; } /* LD LX,D */ +OP(dd,6b) { m_R++; _LX = _E; } /* LD LX,E */ +OP(dd,6c) { m_R++; _LX = _HX; } /* LD LX,HX */ +OP(dd,6d) { } /* LD LX,LX */ +OP(dd,6e) { m_R++; EAX(); _L = RM(m_ea); } /* LD L,(IX+o) */ +OP(dd,6f) { m_R++; _LX = _A; } /* LD LX,A */ + +OP(dd,70) { m_R++; EAX(); WM( m_ea, _B ); } /* LD (IX+o),B */ +OP(dd,71) { m_R++; EAX(); WM( m_ea, _C ); } /* LD (IX+o),C */ +OP(dd,72) { m_R++; EAX(); WM( m_ea, _D ); } /* LD (IX+o),D */ +OP(dd,73) { m_R++; EAX(); WM( m_ea, _E ); } /* LD (IX+o),E */ +OP(dd,74) { m_R++; EAX(); WM( m_ea, _H ); } /* LD (IX+o),H */ +OP(dd,75) { m_R++; EAX(); WM( m_ea, _L ); } /* LD (IX+o),L */ +OP(dd,76) { illegal_1(); op_76(); } /* DB DD */ +OP(dd,77) { m_R++; EAX(); WM( m_ea, _A ); } /* LD (IX+o),A */ + +OP(dd,78) { illegal_1(); op_78(); } /* DB DD */ +OP(dd,79) { illegal_1(); op_79(); } /* DB DD */ +OP(dd,7a) { illegal_1(); op_7a(); } /* DB DD */ +OP(dd,7b) { illegal_1(); op_7b(); } /* DB DD */ +OP(dd,7c) { m_R++; _A = _HX; } /* LD A,HX */ +OP(dd,7d) { m_R++; _A = _LX; } /* LD A,LX */ +OP(dd,7e) { m_R++; EAX(); _A = RM(m_ea); } /* LD A,(IX+o) */ +OP(dd,7f) { illegal_1(); op_7f(); } /* DB DD */ + +OP(dd,80) { illegal_1(); op_80(); } /* DB DD */ +OP(dd,81) { illegal_1(); op_81(); } /* DB DD */ +OP(dd,82) { illegal_1(); op_82(); } /* DB DD */ +OP(dd,83) { illegal_1(); op_83(); } /* DB DD */ +OP(dd,84) { m_R++; ADD(_HX); } /* ADD A,HX */ +OP(dd,85) { m_R++; ADD(_LX); } /* ADD A,LX */ +OP(dd,86) { m_R++; EAX(); ADD(RM(m_ea)); } /* ADD A,(IX+o) */ +OP(dd,87) { illegal_1(); op_87(); } /* DB DD */ + +OP(dd,88) { illegal_1(); op_88(); } /* DB DD */ +OP(dd,89) { illegal_1(); op_89(); } /* DB DD */ +OP(dd,8a) { illegal_1(); op_8a(); } /* DB DD */ +OP(dd,8b) { illegal_1(); op_8b(); } /* DB DD */ +OP(dd,8c) { m_R++; ADC(_HX); } /* ADC A,HX */ +OP(dd,8d) { m_R++; ADC(_LX); } /* ADC A,LX */ +OP(dd,8e) { m_R++; EAX(); ADC(RM(m_ea)); } /* ADC A,(IX+o) */ +OP(dd,8f) { illegal_1(); op_8f(); } /* DB DD */ + +OP(dd,90) { illegal_1(); op_90(); } /* DB DD */ +OP(dd,91) { illegal_1(); op_91(); } /* DB DD */ +OP(dd,92) { illegal_1(); op_92(); } /* DB DD */ +OP(dd,93) { illegal_1(); op_93(); } /* DB DD */ +OP(dd,94) { m_R++; SUB(_HX); } /* SUB HX */ +OP(dd,95) { m_R++; SUB(_LX); } /* SUB LX */ +OP(dd,96) { m_R++; EAX(); SUB(RM(m_ea)); } /* SUB (IX+o) */ +OP(dd,97) { illegal_1(); op_97(); } /* DB DD */ + +OP(dd,98) { illegal_1(); op_98(); } /* DB DD */ +OP(dd,99) { illegal_1(); op_99(); } /* DB DD */ +OP(dd,9a) { illegal_1(); op_9a(); } /* DB DD */ +OP(dd,9b) { illegal_1(); op_9b(); } /* DB DD */ +OP(dd,9c) { m_R++; SBC(_HX); } /* SBC A,HX */ +OP(dd,9d) { m_R++; SBC(_LX); } /* SBC A,LX */ +OP(dd,9e) { m_R++; EAX(); SBC(RM(m_ea)); } /* SBC A,(IX+o) */ +OP(dd,9f) { illegal_1(); op_9f(); } /* DB DD */ + +OP(dd,a0) { illegal_1(); op_a0(); } /* DB DD */ +OP(dd,a1) { illegal_1(); op_a1(); } /* DB DD */ +OP(dd,a2) { illegal_1(); op_a2(); } /* DB DD */ +OP(dd,a3) { illegal_1(); op_a3(); } /* DB DD */ +OP(dd,a4) { m_R++; AND(_HX); } /* AND HX */ +OP(dd,a5) { m_R++; AND(_LX); } /* AND LX */ +OP(dd,a6) { m_R++; EAX(); AND(RM(m_ea)); } /* AND (IX+o) */ +OP(dd,a7) { illegal_1(); op_a7(); } /* DB DD */ + +OP(dd,a8) { illegal_1(); op_a8(); } /* DB DD */ +OP(dd,a9) { illegal_1(); op_a9(); } /* DB DD */ +OP(dd,aa) { illegal_1(); op_aa(); } /* DB DD */ +OP(dd,ab) { illegal_1(); op_ab(); } /* DB DD */ +OP(dd,ac) { m_R++; XOR(_HX); } /* XOR HX */ +OP(dd,ad) { m_R++; XOR(_LX); } /* XOR LX */ +OP(dd,ae) { m_R++; EAX(); XOR(RM(m_ea)); } /* XOR (IX+o) */ +OP(dd,af) { illegal_1(); op_af(); } /* DB DD */ + +OP(dd,b0) { illegal_1(); op_b0(); } /* DB DD */ +OP(dd,b1) { illegal_1(); op_b1(); } /* DB DD */ +OP(dd,b2) { illegal_1(); op_b2(); } /* DB DD */ +OP(dd,b3) { illegal_1(); op_b3(); } /* DB DD */ +OP(dd,b4) { m_R++; OR(_HX); } /* OR HX */ +OP(dd,b5) { m_R++; OR(_LX); } /* OR LX */ +OP(dd,b6) { m_R++; EAX(); OR(RM(m_ea)); } /* OR (IX+o) */ +OP(dd,b7) { illegal_1(); op_b7(); } /* DB DD */ + +OP(dd,b8) { illegal_1(); op_b8(); } /* DB DD */ +OP(dd,b9) { illegal_1(); op_b9(); } /* DB DD */ +OP(dd,ba) { illegal_1(); op_ba(); } /* DB DD */ +OP(dd,bb) { illegal_1(); op_bb(); } /* DB DD */ +OP(dd,bc) { m_R++; CP(_HX); } /* CP HX */ +OP(dd,bd) { m_R++; CP(_LX); } /* CP LX */ +OP(dd,be) { m_R++; EAX(); CP(RM(m_ea)); } /* CP (IX+o) */ +OP(dd,bf) { illegal_1(); op_bf(); } /* DB DD */ + +OP(dd,c0) { illegal_1(); op_c0(); } /* DB DD */ +OP(dd,c1) { illegal_1(); op_c1(); } /* DB DD */ +OP(dd,c2) { illegal_1(); op_c2(); } /* DB DD */ +OP(dd,c3) { illegal_1(); op_c3(); } /* DB DD */ +OP(dd,c4) { illegal_1(); op_c4(); } /* DB DD */ +OP(dd,c5) { illegal_1(); op_c5(); } /* DB DD */ +OP(dd,c6) { illegal_1(); op_c6(); } /* DB DD */ +OP(dd,c7) { illegal_1(); op_c7(); } /* DB DD */ + +OP(dd,c8) { illegal_1(); op_c8(); } /* DB DD */ +OP(dd,c9) { illegal_1(); op_c9(); } /* DB DD */ +OP(dd,ca) { illegal_1(); op_ca(); } /* DB DD */ +OP(dd,cb) { m_R++; EAX(); m_extra_cycles += exec_xycb(ARG()); } /* ** DD CB xx */ +OP(dd,cc) { illegal_1(); op_cc(); } /* DB DD */ +OP(dd,cd) { illegal_1(); op_cd(); } /* DB DD */ +OP(dd,ce) { illegal_1(); op_ce(); } /* DB DD */ +OP(dd,cf) { illegal_1(); op_cf(); } /* DB DD */ + +OP(dd,d0) { illegal_1(); op_d0(); } /* DB DD */ +OP(dd,d1) { illegal_1(); op_d1(); } /* DB DD */ +OP(dd,d2) { illegal_1(); op_d2(); } /* DB DD */ +OP(dd,d3) { illegal_1(); op_d3(); } /* DB DD */ +OP(dd,d4) { illegal_1(); op_d4(); } /* DB DD */ +OP(dd,d5) { illegal_1(); op_d5(); } /* DB DD */ +OP(dd,d6) { illegal_1(); op_d6(); } /* DB DD */ +OP(dd,d7) { illegal_1(); op_d7(); } /* DB DD */ + +OP(dd,d8) { illegal_1(); op_d8(); } /* DB DD */ +OP(dd,d9) { illegal_1(); op_d9(); } /* DB DD */ +OP(dd,da) { illegal_1(); op_da(); } /* DB DD */ +OP(dd,db) { illegal_1(); op_db(); } /* DB DD */ +OP(dd,dc) { illegal_1(); op_dc(); } /* DB DD */ +OP(dd,dd) { illegal_1(); op_dd(); } /* DB DD */ +OP(dd,de) { illegal_1(); op_de(); } /* DB DD */ +OP(dd,df) { illegal_1(); op_df(); } /* DB DD */ + +OP(dd,e0) { illegal_1(); op_e0(); } /* DB DD */ +OP(dd,e1) { m_R++; POP(IX); } /* POP IX */ +OP(dd,e2) { illegal_1(); op_e2(); } /* DB DD */ +OP(dd,e3) { m_R++; EXSP(IX); } /* EX (SP),IX */ +OP(dd,e4) { illegal_1(); op_e4(); } /* DB DD */ +OP(dd,e5) { m_R++; PUSH( IX ); } /* PUSH IX */ +OP(dd,e6) { illegal_1(); op_e6(); } /* DB DD */ +OP(dd,e7) { illegal_1(); op_e7(); } /* DB DD */ + +OP(dd,e8) { illegal_1(); op_e8(); } /* DB DD */ +OP(dd,e9) { m_R++; _PC = _IX; } /* JP (IX) */ +OP(dd,ea) { illegal_1(); op_ea(); } /* DB DD */ +OP(dd,eb) { illegal_1(); op_eb(); } /* DB DD */ +OP(dd,ec) { illegal_1(); op_ec(); } /* DB DD */ +OP(dd,ed) { illegal_1(); op_ed(); } /* DB DD */ +OP(dd,ee) { illegal_1(); op_ee(); } /* DB DD */ +OP(dd,ef) { illegal_1(); op_ef(); } /* DB DD */ + +OP(dd,f0) { illegal_1(); op_f0(); } /* DB DD */ +OP(dd,f1) { illegal_1(); op_f1(); } /* DB DD */ +OP(dd,f2) { illegal_1(); op_f2(); } /* DB DD */ +OP(dd,f3) { illegal_1(); op_f3(); } /* DB DD */ +OP(dd,f4) { illegal_1(); op_f4(); } /* DB DD */ +OP(dd,f5) { illegal_1(); op_f5(); } /* DB DD */ +OP(dd,f6) { illegal_1(); op_f6(); } /* DB DD */ +OP(dd,f7) { illegal_1(); op_f7(); } /* DB DD */ + +OP(dd,f8) { illegal_1(); op_f8(); } /* DB DD */ +OP(dd,f9) { m_R++; _SP = _IX; } /* LD SP,IX */ +OP(dd,fa) { illegal_1(); op_fa(); } /* DB DD */ +OP(dd,fb) { illegal_1(); op_fb(); } /* DB DD */ +OP(dd,fc) { illegal_1(); op_fc(); } /* DB DD */ +OP(dd,fd) { illegal_1(); op_fd(); } /* DB DD */ +OP(dd,fe) { illegal_1(); op_fe(); } /* DB DD */ +OP(dd,ff) { illegal_1(); op_ff(); } /* DB DD */ diff --git a/src/devices/cpu/z180/z180ed.inc b/src/devices/cpu/z180/z180ed.inc new file mode 100644 index 00000000000..91520228f87 --- /dev/null +++ b/src/devices/cpu/z180/z180ed.inc @@ -0,0 +1,298 @@ +// license:BSD-3-Clause +// copyright-holders:Juergen Buchmueller +OP(illegal,2) +{ + logerror("Z180 '%s' ill. opcode $ed $%02x\n", + tag(), m_odirect->read_byte((_PCD-1)&0xffff)); +} + +/********************************************************** + * special opcodes (ED prefix) + **********************************************************/ +OP(ed,00) { unsigned n = ARG(); _B = IN( n ); } /* IN0 B,(n) */ +OP(ed,01) { unsigned n = ARG(); OUT( n, _B ); } /* OUT0 (n),B */ +OP(ed,02) { illegal_2(); } /* DB ED */ +OP(ed,03) { illegal_2(); } /* DB ED */ +OP(ed,04) { TST( _B ); } /* TST B */ +OP(ed,05) { illegal_2(); } /* DB ED */ +OP(ed,06) { illegal_2(); } /* DB ED */ +OP(ed,07) { illegal_2(); } /* DB ED */ + +OP(ed,08) { unsigned n = ARG(); _C = IN( n ); } /* IN0 C,(n) */ +OP(ed,09) { unsigned n = ARG(); OUT( n, _C ); } /* OUT0 (n),C */ +OP(ed,0a) { illegal_2(); } /* DB ED */ +OP(ed,0b) { illegal_2(); } /* DB ED */ +OP(ed,0c) { TST( _C ); } /* TST C */ +OP(ed,0d) { illegal_2(); } /* DB ED */ +OP(ed,0e) { illegal_2(); } /* DB ED */ +OP(ed,0f) { illegal_2(); } /* DB ED */ + +OP(ed,10) { unsigned n = ARG(); _D = IN( n ); } /* IN0 D,(n) */ +OP(ed,11) { unsigned n = ARG(); OUT( n, _D ); } /* OUT0 (n),D */ +OP(ed,12) { illegal_2(); } /* DB ED */ +OP(ed,13) { illegal_2(); } /* DB ED */ +OP(ed,14) { TST( _D ); } /* TST D */ +OP(ed,15) { illegal_2(); } /* DB ED */ +OP(ed,16) { illegal_2(); } /* DB ED */ +OP(ed,17) { illegal_2(); } /* DB ED */ + +OP(ed,18) { unsigned n = ARG(); _E = IN( n ); } /* IN0 E,(n) */ +OP(ed,19) { unsigned n = ARG(); OUT( n, _E ); } /* OUT0 (n),E */ +OP(ed,1a) { illegal_2(); } /* DB ED */ +OP(ed,1b) { illegal_2(); } /* DB ED */ +OP(ed,1c) { TST( _E ); } /* TST E */ +OP(ed,1d) { illegal_2(); } /* DB ED */ +OP(ed,1e) { illegal_2(); } /* DB ED */ +OP(ed,1f) { illegal_2(); } /* DB ED */ + +OP(ed,20) { unsigned n = ARG(); _H = IN( n ); } /* IN0 H,(n) */ +OP(ed,21) { unsigned n = ARG(); OUT( n, _H ); } /* OUT0 (n),H */ +OP(ed,22) { illegal_2(); } /* DB ED */ +OP(ed,23) { illegal_2(); } /* DB ED */ +OP(ed,24) { TST( _H ); } /* TST H */ +OP(ed,25) { illegal_2(); } /* DB ED */ +OP(ed,26) { illegal_2(); } /* DB ED */ +OP(ed,27) { illegal_2(); } /* DB ED */ + +OP(ed,28) { unsigned n = ARG(); _L = IN( n ); } /* IN0 L,(n) */ +OP(ed,29) { unsigned n = ARG(); OUT( n, _L ); } /* OUT0 (n),L */ +OP(ed,2a) { illegal_2(); } /* DB ED */ +OP(ed,2b) { illegal_2(); } /* DB ED */ +OP(ed,2c) { TST( _L ); } /* TST L */ +OP(ed,2d) { illegal_2(); } /* DB ED */ +OP(ed,2e) { illegal_2(); } /* DB ED */ +OP(ed,2f) { illegal_2(); } /* DB ED */ + +OP(ed,30) { unsigned n = ARG(); IN( n ); } /* IN0 (n) */ +OP(ed,31) { unsigned n = ARG(); OUT( n, 0 ); } /* OUT0 (n) */ +OP(ed,32) { illegal_2(); } /* DB ED */ +OP(ed,33) { illegal_2(); } /* DB ED */ +OP(ed,34) { TST( RM(_HL) ); } /* TST (HL) */ +OP(ed,35) { illegal_2(); } /* DB ED */ +OP(ed,36) { illegal_2(); } /* DB ED */ +OP(ed,37) { illegal_2(); } /* DB ED */ + +OP(ed,38) { unsigned n = ARG(); _A = IN( n ); } /* IN0 A,(n) */ +OP(ed,39) { unsigned n = ARG(); OUT( n, _A ); } /* OUT0 (n),A */ +OP(ed,3a) { illegal_2(); } /* DB ED */ +OP(ed,3b) { illegal_2(); } /* DB ED */ +OP(ed,3c) { TST( _A ); } /* TST A */ +OP(ed,3d) { illegal_2(); } /* DB ED */ +OP(ed,3e) { illegal_2(); } /* DB ED */ +OP(ed,3f) { illegal_2(); } /* DB ED */ + +OP(ed,40) { _B = IN(_BC); _F = (_F & CF) | SZP[_B]; } /* IN B,(C) */ +OP(ed,41) { OUT(_BC,_B); } /* OUT (C),B */ +OP(ed,42) { SBC16( BC ); } /* SBC HL,BC */ +OP(ed,43) { m_ea = ARG16(); WM16( m_ea, &m_BC ); } /* LD (w),BC */ +OP(ed,44) { NEG; } /* NEG */ +OP(ed,45) { RETN; } /* RETN; */ +OP(ed,46) { m_IM = 0; } /* IM 0 */ +OP(ed,47) { LD_I_A; } /* LD I,A */ + +OP(ed,48) { _C = IN(_BC); _F = (_F & CF) | SZP[_C]; } /* IN C,(C) */ +OP(ed,49) { OUT(_BC,_C); } /* OUT (C),C */ +OP(ed,4a) { ADC16( BC ); } /* ADC HL,BC */ +OP(ed,4b) { m_ea = ARG16(); RM16( m_ea, &m_BC ); } /* LD BC,(w) */ +OP(ed,4c) { MLT( BC ); } /* MLT BC */ +OP(ed,4d) { RETI; } /* RETI */ +OP(ed,4e) { m_IM = 0; } /* IM 0 */ +OP(ed,4f) { LD_R_A; } /* LD R,A */ + +OP(ed,50) { _D = IN(_BC); _F = (_F & CF) | SZP[_D]; } /* IN D,(C) */ +OP(ed,51) { OUT(_BC,_D); } /* OUT (C),D */ +OP(ed,52) { SBC16( DE ); } /* SBC HL,DE */ +OP(ed,53) { m_ea = ARG16(); WM16( m_ea, &m_DE ); } /* LD (w),DE */ +OP(ed,54) { NEG; } /* NEG */ +OP(ed,55) { RETN; } /* RETN; */ +OP(ed,56) { m_IM = 1; } /* IM 1 */ +OP(ed,57) { LD_A_I; } /* LD A,I */ + +OP(ed,58) { _E = IN(_BC); _F = (_F & CF) | SZP[_E]; } /* IN E,(C) */ +OP(ed,59) { OUT(_BC,_E); } /* OUT (C),E */ +OP(ed,5a) { ADC16( DE ); } /* ADC HL,DE */ +OP(ed,5b) { m_ea = ARG16(); RM16( m_ea, &m_DE ); } /* LD DE,(w) */ +OP(ed,5c) { MLT( DE ); } /* MLT DE */ +OP(ed,5d) { RETI; } /* RETI */ +OP(ed,5e) { m_IM = 2; } /* IM 2 */ +OP(ed,5f) { LD_A_R; } /* LD A,R */ + +OP(ed,60) { _H = IN(_BC); _F = (_F & CF) | SZP[_H]; } /* IN H,(C) */ +OP(ed,61) { OUT(_BC,_H); } /* OUT (C),H */ +OP(ed,62) { SBC16( HL ); } /* SBC HL,HL */ +OP(ed,63) { m_ea = ARG16(); WM16( m_ea, &m_HL ); } /* LD (w),HL */ +OP(ed,64) { unsigned m = ARG(); TST( m ); } /* TST m */ +OP(ed,65) { RETN; } /* RETN; */ +OP(ed,66) { m_IM = 0; } /* IM 0 */ +OP(ed,67) { RRD; } /* RRD (HL) */ + +OP(ed,68) { _L = IN(_BC); _F = (_F & CF) | SZP[_L]; } /* IN L,(C) */ +OP(ed,69) { OUT(_BC,_L); } /* OUT (C),L */ +OP(ed,6a) { ADC16( HL ); } /* ADC HL,HL */ +OP(ed,6b) { m_ea = ARG16(); RM16( m_ea, &m_HL ); } /* LD HL,(w) */ +OP(ed,6c) { MLT( HL ); } /* MLT HL */ +OP(ed,6d) { RETI; } /* RETI */ +OP(ed,6e) { m_IM = 0; } /* IM 0 */ +OP(ed,6f) { RLD; } /* RLD (HL) */ + +OP(ed,70) { UINT8 res = IN(_BC); _F = (_F & CF) | SZP[res]; } /* IN 0,(C) */ +OP(ed,71) { OUT(_BC,0); } /* OUT (C),0 */ +OP(ed,72) { SBC16( SP ); } /* SBC HL,SP */ +OP(ed,73) { m_ea = ARG16(); WM16( m_ea, &m_SP ); } /* LD (w),SP */ +OP(ed,74) { unsigned m = ARG(); _F = (_F & CF) | SZP[IN(_C) & m]; } /* TSTIO m */ +OP(ed,75) { RETN; } /* RETN; */ +OP(ed,76) { SLP; } /* SLP */ +OP(ed,77) { illegal_2(); } /* DB ED,77 */ + +OP(ed,78) { _A = IN(_BC); _F = (_F & CF) | SZP[_A]; } /* IN E,(C) */ +OP(ed,79) { OUT(_BC,_A); } /* OUT (C),E */ +OP(ed,7a) { ADC16( SP ); } /* ADC HL,SP */ +OP(ed,7b) { m_ea = ARG16(); RM16( m_ea, &m_SP ); } /* LD SP,(w) */ +OP(ed,7c) { MLT( SP ); } /* MLT SP */ +OP(ed,7d) { RETI; } /* RETI */ +OP(ed,7e) { m_IM = 2; } /* IM 2 */ +OP(ed,7f) { illegal_2(); } /* DB ED,7F */ + +OP(ed,80) { illegal_2(); } /* DB ED */ +OP(ed,81) { illegal_2(); } /* DB ED */ +OP(ed,82) { illegal_2(); } /* DB ED */ +OP(ed,83) { OTIM; } /* OTIM */ +OP(ed,84) { illegal_2(); } /* DB ED */ +OP(ed,85) { illegal_2(); } /* DB ED */ +OP(ed,86) { illegal_2(); } /* DB ED */ +OP(ed,87) { illegal_2(); } /* DB ED */ + +OP(ed,88) { illegal_2(); } /* DB ED */ +OP(ed,89) { illegal_2(); } /* DB ED */ +OP(ed,8a) { illegal_2(); } /* DB ED */ +OP(ed,8b) { OTDM; } /* OTDM */ +OP(ed,8c) { illegal_2(); } /* DB ED */ +OP(ed,8d) { illegal_2(); } /* DB ED */ +OP(ed,8e) { illegal_2(); } /* DB ED */ +OP(ed,8f) { illegal_2(); } /* DB ED */ + +OP(ed,90) { illegal_2(); } /* DB ED */ +OP(ed,91) { illegal_2(); } /* DB ED */ +OP(ed,92) { illegal_2(); } /* DB ED */ +OP(ed,93) { OTIMR; } /* OTIMR */ +OP(ed,94) { illegal_2(); } /* DB ED */ +OP(ed,95) { illegal_2(); } /* DB ED */ +OP(ed,96) { illegal_2(); } /* DB ED */ +OP(ed,97) { illegal_2(); } /* DB ED */ + +OP(ed,98) { illegal_2(); } /* DB ED */ +OP(ed,99) { illegal_2(); } /* DB ED */ +OP(ed,9a) { illegal_2(); } /* DB ED */ +OP(ed,9b) { OTDMR; } /* OTDMR */ +OP(ed,9c) { illegal_2(); } /* DB ED */ +OP(ed,9d) { illegal_2(); } /* DB ED */ +OP(ed,9e) { illegal_2(); } /* DB ED */ +OP(ed,9f) { illegal_2(); } /* DB ED */ + +OP(ed,a0) { LDI; } /* LDI */ +OP(ed,a1) { CPI; } /* CPI */ +OP(ed,a2) { INI; } /* INI */ +OP(ed,a3) { OUTI; } /* OUTI */ +OP(ed,a4) { illegal_2(); } /* DB ED */ +OP(ed,a5) { illegal_2(); } /* DB ED */ +OP(ed,a6) { illegal_2(); } /* DB ED */ +OP(ed,a7) { illegal_2(); } /* DB ED */ + +OP(ed,a8) { LDD; } /* LDD */ +OP(ed,a9) { CPD; } /* CPD */ +OP(ed,aa) { IND; } /* IND */ +OP(ed,ab) { OUTD; } /* OUTD */ +OP(ed,ac) { illegal_2(); } /* DB ED */ +OP(ed,ad) { illegal_2(); } /* DB ED */ +OP(ed,ae) { illegal_2(); } /* DB ED */ +OP(ed,af) { illegal_2(); } /* DB ED */ + +OP(ed,b0) { LDIR; } /* LDIR */ +OP(ed,b1) { CPIR; } /* CPIR */ +OP(ed,b2) { INIR; } /* INIR */ +OP(ed,b3) { OTIR; } /* OTIR */ +OP(ed,b4) { illegal_2(); } /* DB ED */ +OP(ed,b5) { illegal_2(); } /* DB ED */ +OP(ed,b6) { illegal_2(); } /* DB ED */ +OP(ed,b7) { illegal_2(); } /* DB ED */ + +OP(ed,b8) { LDDR; } /* LDDR */ +OP(ed,b9) { CPDR; } /* CPDR */ +OP(ed,ba) { INDR; } /* INDR */ +OP(ed,bb) { OTDR; } /* OTDR */ +OP(ed,bc) { illegal_2(); } /* DB ED */ +OP(ed,bd) { illegal_2(); } /* DB ED */ +OP(ed,be) { illegal_2(); } /* DB ED */ +OP(ed,bf) { illegal_2(); } /* DB ED */ + +OP(ed,c0) { illegal_2(); } /* DB ED */ +OP(ed,c1) { illegal_2(); } /* DB ED */ +OP(ed,c2) { illegal_2(); } /* DB ED */ +OP(ed,c3) { illegal_2(); } /* DB ED */ +OP(ed,c4) { illegal_2(); } /* DB ED */ +OP(ed,c5) { illegal_2(); } /* DB ED */ +OP(ed,c6) { illegal_2(); } /* DB ED */ +OP(ed,c7) { illegal_2(); } /* DB ED */ + +OP(ed,c8) { illegal_2(); } /* DB ED */ +OP(ed,c9) { illegal_2(); } /* DB ED */ +OP(ed,ca) { illegal_2(); } /* DB ED */ +OP(ed,cb) { illegal_2(); } /* DB ED */ +OP(ed,cc) { illegal_2(); } /* DB ED */ +OP(ed,cd) { illegal_2(); } /* DB ED */ +OP(ed,ce) { illegal_2(); } /* DB ED */ +OP(ed,cf) { illegal_2(); } /* DB ED */ + +OP(ed,d0) { illegal_2(); } /* DB ED */ +OP(ed,d1) { illegal_2(); } /* DB ED */ +OP(ed,d2) { illegal_2(); } /* DB ED */ +OP(ed,d3) { illegal_2(); } /* DB ED */ +OP(ed,d4) { illegal_2(); } /* DB ED */ +OP(ed,d5) { illegal_2(); } /* DB ED */ +OP(ed,d6) { illegal_2(); } /* DB ED */ +OP(ed,d7) { illegal_2(); } /* DB ED */ + +OP(ed,d8) { illegal_2(); } /* DB ED */ +OP(ed,d9) { illegal_2(); } /* DB ED */ +OP(ed,da) { illegal_2(); } /* DB ED */ +OP(ed,db) { illegal_2(); } /* DB ED */ +OP(ed,dc) { illegal_2(); } /* DB ED */ +OP(ed,dd) { illegal_2(); } /* DB ED */ +OP(ed,de) { illegal_2(); } /* DB ED */ +OP(ed,df) { illegal_2(); } /* DB ED */ + +OP(ed,e0) { illegal_2(); } /* DB ED */ +OP(ed,e1) { illegal_2(); } /* DB ED */ +OP(ed,e2) { illegal_2(); } /* DB ED */ +OP(ed,e3) { illegal_2(); } /* DB ED */ +OP(ed,e4) { illegal_2(); } /* DB ED */ +OP(ed,e5) { illegal_2(); } /* DB ED */ +OP(ed,e6) { illegal_2(); } /* DB ED */ +OP(ed,e7) { illegal_2(); } /* DB ED */ + +OP(ed,e8) { illegal_2(); } /* DB ED */ +OP(ed,e9) { illegal_2(); } /* DB ED */ +OP(ed,ea) { illegal_2(); } /* DB ED */ +OP(ed,eb) { illegal_2(); } /* DB ED */ +OP(ed,ec) { illegal_2(); } /* DB ED */ +OP(ed,ed) { illegal_2(); } /* DB ED */ +OP(ed,ee) { illegal_2(); } /* DB ED */ +OP(ed,ef) { illegal_2(); } /* DB ED */ + +OP(ed,f0) { illegal_2(); } /* DB ED */ +OP(ed,f1) { illegal_2(); } /* DB ED */ +OP(ed,f2) { illegal_2(); } /* DB ED */ +OP(ed,f3) { illegal_2(); } /* DB ED */ +OP(ed,f4) { illegal_2(); } /* DB ED */ +OP(ed,f5) { illegal_2(); } /* DB ED */ +OP(ed,f6) { illegal_2(); } /* DB ED */ +OP(ed,f7) { illegal_2(); } /* DB ED */ + +OP(ed,f8) { illegal_2(); } /* DB ED */ +OP(ed,f9) { illegal_2(); } /* DB ED */ +OP(ed,fa) { illegal_2(); } /* DB ED */ +OP(ed,fb) { illegal_2(); } /* DB ED */ +OP(ed,fc) { illegal_2(); } /* DB ED */ +OP(ed,fd) { illegal_2(); } /* DB ED */ +OP(ed,fe) { illegal_2(); } /* DB ED */ +OP(ed,ff) { illegal_2(); } /* DB ED */ diff --git a/src/devices/cpu/z180/z180fd.inc b/src/devices/cpu/z180/z180fd.inc new file mode 100644 index 00000000000..66697a9b997 --- /dev/null +++ b/src/devices/cpu/z180/z180fd.inc @@ -0,0 +1,292 @@ +// license:BSD-3-Clause +// copyright-holders:Juergen Buchmueller +/********************************************************** + * IY register related opcodes (FD prefix) + **********************************************************/ +OP(fd,00) { illegal_1(); op_00(); } /* DB FD */ +OP(fd,01) { illegal_1(); op_01(); } /* DB FD */ +OP(fd,02) { illegal_1(); op_02(); } /* DB FD */ +OP(fd,03) { illegal_1(); op_03(); } /* DB FD */ +OP(fd,04) { illegal_1(); op_04(); } /* DB FD */ +OP(fd,05) { illegal_1(); op_05(); } /* DB FD */ +OP(fd,06) { illegal_1(); op_06(); } /* DB FD */ +OP(fd,07) { illegal_1(); op_07(); } /* DB FD */ + +OP(fd,08) { illegal_1(); op_08(); } /* DB FD */ +OP(fd,09) { m_R++; ADD16(IY,BC); } /* ADD IY,BC */ +OP(fd,0a) { illegal_1(); op_0a(); } /* DB FD */ +OP(fd,0b) { illegal_1(); op_0b(); } /* DB FD */ +OP(fd,0c) { illegal_1(); op_0c(); } /* DB FD */ +OP(fd,0d) { illegal_1(); op_0d(); } /* DB FD */ +OP(fd,0e) { illegal_1(); op_0e(); } /* DB FD */ +OP(fd,0f) { illegal_1(); op_0f(); } /* DB FD */ + +OP(fd,10) { illegal_1(); op_10(); } /* DB FD */ +OP(fd,11) { illegal_1(); op_11(); } /* DB FD */ +OP(fd,12) { illegal_1(); op_12(); } /* DB FD */ +OP(fd,13) { illegal_1(); op_13(); } /* DB FD */ +OP(fd,14) { illegal_1(); op_14(); } /* DB FD */ +OP(fd,15) { illegal_1(); op_15(); } /* DB FD */ +OP(fd,16) { illegal_1(); op_16(); } /* DB FD */ +OP(fd,17) { illegal_1(); op_17(); } /* DB FD */ + +OP(fd,18) { illegal_1(); op_18(); } /* DB FD */ +OP(fd,19) { m_R++; ADD16(IY,DE); } /* ADD IY,DE */ +OP(fd,1a) { illegal_1(); op_1a(); } /* DB FD */ +OP(fd,1b) { illegal_1(); op_1b(); } /* DB FD */ +OP(fd,1c) { illegal_1(); op_1c(); } /* DB FD */ +OP(fd,1d) { illegal_1(); op_1d(); } /* DB FD */ +OP(fd,1e) { illegal_1(); op_1e(); } /* DB FD */ +OP(fd,1f) { illegal_1(); op_1f(); } /* DB FD */ + +OP(fd,20) { illegal_1(); op_20(); } /* DB FD */ +OP(fd,21) { m_R++; _IY = ARG16(); } /* LD IY,w */ +OP(fd,22) { m_R++; m_ea = ARG16(); WM16( m_ea, &m_IY ); } /* LD (w),IY */ +OP(fd,23) { m_R++; _IY++; } /* INC IY */ +OP(fd,24) { m_R++; _HY = INC(_HY); } /* INC HY */ +OP(fd,25) { m_R++; _HY = DEC(_HY); } /* DEC HY */ +OP(fd,26) { m_R++; _HY = ARG(); } /* LD HY,n */ +OP(fd,27) { illegal_1(); op_27(); } /* DB FD */ + +OP(fd,28) { illegal_1(); op_28(); } /* DB FD */ +OP(fd,29) { m_R++; ADD16(IY,IY); } /* ADD IY,IY */ +OP(fd,2a) { m_R++; m_ea = ARG16(); RM16( m_ea, &m_IY ); } /* LD IY,(w) */ +OP(fd,2b) { m_R++; _IY--; } /* DEC IY */ +OP(fd,2c) { m_R++; _LY = INC(_LY); } /* INC LY */ +OP(fd,2d) { m_R++; _LY = DEC(_LY); } /* DEC LY */ +OP(fd,2e) { m_R++; _LY = ARG(); } /* LD LY,n */ +OP(fd,2f) { illegal_1(); op_2f(); } /* DB FD */ + +OP(fd,30) { illegal_1(); op_30(); } /* DB FD */ +OP(fd,31) { illegal_1(); op_31(); } /* DB FD */ +OP(fd,32) { illegal_1(); op_32(); } /* DB FD */ +OP(fd,33) { illegal_1(); op_33(); } /* DB FD */ +OP(fd,34) { m_R++; EAY(); WM( m_ea, INC(RM(m_ea)) ); } /* INC (IY+o) */ +OP(fd,35) { m_R++; EAY(); WM( m_ea, DEC(RM(m_ea)) ); } /* DEC (IY+o) */ +OP(fd,36) { m_R++; EAY(); WM( m_ea, ARG() ); } /* LD (IY+o),n */ +OP(fd,37) { illegal_1(); op_37(); } /* DB FD */ + +OP(fd,38) { illegal_1(); op_38(); } /* DB FD */ +OP(fd,39) { m_R++; ADD16(IY,SP); } /* ADD IY,SP */ +OP(fd,3a) { illegal_1(); op_3a(); } /* DB FD */ +OP(fd,3b) { illegal_1(); op_3b(); } /* DB FD */ +OP(fd,3c) { illegal_1(); op_3c(); } /* DB FD */ +OP(fd,3d) { illegal_1(); op_3d(); } /* DB FD */ +OP(fd,3e) { illegal_1(); op_3e(); } /* DB FD */ +OP(fd,3f) { illegal_1(); op_3f(); } /* DB FD */ + +OP(fd,40) { illegal_1(); op_40(); } /* DB FD */ +OP(fd,41) { illegal_1(); op_41(); } /* DB FD */ +OP(fd,42) { illegal_1(); op_42(); } /* DB FD */ +OP(fd,43) { illegal_1(); op_43(); } /* DB FD */ +OP(fd,44) { m_R++; _B = _HY; } /* LD B,HY */ +OP(fd,45) { m_R++; _B = _LY; } /* LD B,LY */ +OP(fd,46) { m_R++; EAY(); _B = RM(m_ea); } /* LD B,(IY+o) */ +OP(fd,47) { illegal_1(); op_47(); } /* DB FD */ + +OP(fd,48) { illegal_1(); op_48(); } /* DB FD */ +OP(fd,49) { illegal_1(); op_49(); } /* DB FD */ +OP(fd,4a) { illegal_1(); op_4a(); } /* DB FD */ +OP(fd,4b) { illegal_1(); op_4b(); } /* DB FD */ +OP(fd,4c) { m_R++; _C = _HY; } /* LD C,HY */ +OP(fd,4d) { m_R++; _C = _LY; } /* LD C,LY */ +OP(fd,4e) { m_R++; EAY(); _C = RM(m_ea); } /* LD C,(IY+o) */ +OP(fd,4f) { illegal_1(); op_4f(); } /* DB FD */ + +OP(fd,50) { illegal_1(); op_50(); } /* DB FD */ +OP(fd,51) { illegal_1(); op_51(); } /* DB FD */ +OP(fd,52) { illegal_1(); op_52(); } /* DB FD */ +OP(fd,53) { illegal_1(); op_53(); } /* DB FD */ +OP(fd,54) { m_R++; _D = _HY; } /* LD D,HY */ +OP(fd,55) { m_R++; _D = _LY; } /* LD D,LY */ +OP(fd,56) { m_R++; EAY(); _D = RM(m_ea); } /* LD D,(IY+o) */ +OP(fd,57) { illegal_1(); op_57(); } /* DB FD */ + +OP(fd,58) { illegal_1(); op_58(); } /* DB FD */ +OP(fd,59) { illegal_1(); op_59(); } /* DB FD */ +OP(fd,5a) { illegal_1(); op_5a(); } /* DB FD */ +OP(fd,5b) { illegal_1(); op_5b(); } /* DB FD */ +OP(fd,5c) { m_R++; _E = _HY; } /* LD E,HY */ +OP(fd,5d) { m_R++; _E = _LY; } /* LD E,LY */ +OP(fd,5e) { m_R++; EAY(); _E = RM(m_ea); } /* LD E,(IY+o) */ +OP(fd,5f) { illegal_1(); op_5f(); } /* DB FD */ + +OP(fd,60) { m_R++; _HY = _B; } /* LD HY,B */ +OP(fd,61) { m_R++; _HY = _C; } /* LD HY,C */ +OP(fd,62) { m_R++; _HY = _D; } /* LD HY,D */ +OP(fd,63) { m_R++; _HY = _E; } /* LD HY,E */ +OP(fd,64) { m_R++; } /* LD HY,HY */ +OP(fd,65) { m_R++; _HY = _LY; } /* LD HY,LY */ +OP(fd,66) { m_R++; EAY(); _H = RM(m_ea); } /* LD H,(IY+o) */ +OP(fd,67) { m_R++; _HY = _A; } /* LD HY,A */ + +OP(fd,68) { m_R++; _LY = _B; } /* LD LY,B */ +OP(fd,69) { m_R++; _LY = _C; } /* LD LY,C */ +OP(fd,6a) { m_R++; _LY = _D; } /* LD LY,D */ +OP(fd,6b) { m_R++; _LY = _E; } /* LD LY,E */ +OP(fd,6c) { m_R++; _LY = _HY; } /* LD LY,HY */ +OP(fd,6d) { m_R++; } /* LD LY,LY */ +OP(fd,6e) { m_R++; EAY(); _L = RM(m_ea); } /* LD L,(IY+o) */ +OP(fd,6f) { m_R++; _LY = _A; } /* LD LY,A */ + +OP(fd,70) { m_R++; EAY(); WM( m_ea, _B ); } /* LD (IY+o),B */ +OP(fd,71) { m_R++; EAY(); WM( m_ea, _C ); } /* LD (IY+o),C */ +OP(fd,72) { m_R++; EAY(); WM( m_ea, _D ); } /* LD (IY+o),D */ +OP(fd,73) { m_R++; EAY(); WM( m_ea, _E ); } /* LD (IY+o),E */ +OP(fd,74) { m_R++; EAY(); WM( m_ea, _H ); } /* LD (IY+o),H */ +OP(fd,75) { m_R++; EAY(); WM( m_ea, _L ); } /* LD (IY+o),L */ +OP(fd,76) { illegal_1(); op_76(); } /* DB FD */ +OP(fd,77) { m_R++; EAY(); WM( m_ea, _A ); } /* LD (IY+o),A */ + +OP(fd,78) { illegal_1(); op_78(); } /* DB FD */ +OP(fd,79) { illegal_1(); op_79(); } /* DB FD */ +OP(fd,7a) { illegal_1(); op_7a(); } /* DB FD */ +OP(fd,7b) { illegal_1(); op_7b(); } /* DB FD */ +OP(fd,7c) { m_R++; _A = _HY; } /* LD A,HY */ +OP(fd,7d) { m_R++; _A = _LY; } /* LD A,LY */ +OP(fd,7e) { m_R++; EAY(); _A = RM(m_ea); } /* LD A,(IY+o) */ +OP(fd,7f) { illegal_1(); op_7f(); } /* DB FD */ + +OP(fd,80) { illegal_1(); op_80(); } /* DB FD */ +OP(fd,81) { illegal_1(); op_81(); } /* DB FD */ +OP(fd,82) { illegal_1(); op_82(); } /* DB FD */ +OP(fd,83) { illegal_1(); op_83(); } /* DB FD */ +OP(fd,84) { m_R++; ADD(_HY); } /* ADD A,HY */ +OP(fd,85) { m_R++; ADD(_LY); } /* ADD A,LY */ +OP(fd,86) { m_R++; EAY(); ADD(RM(m_ea)); } /* ADD A,(IY+o) */ +OP(fd,87) { illegal_1(); op_87(); } /* DB FD */ + +OP(fd,88) { illegal_1(); op_88(); } /* DB FD */ +OP(fd,89) { illegal_1(); op_89(); } /* DB FD */ +OP(fd,8a) { illegal_1(); op_8a(); } /* DB FD */ +OP(fd,8b) { illegal_1(); op_8b(); } /* DB FD */ +OP(fd,8c) { m_R++; ADC(_HY); } /* ADC A,HY */ +OP(fd,8d) { m_R++; ADC(_LY); } /* ADC A,LY */ +OP(fd,8e) { m_R++; EAY(); ADC(RM(m_ea)); } /* ADC A,(IY+o) */ +OP(fd,8f) { illegal_1(); op_8f(); } /* DB FD */ + +OP(fd,90) { illegal_1(); op_90(); } /* DB FD */ +OP(fd,91) { illegal_1(); op_91(); } /* DB FD */ +OP(fd,92) { illegal_1(); op_92(); } /* DB FD */ +OP(fd,93) { illegal_1(); op_93(); } /* DB FD */ +OP(fd,94) { m_R++; SUB(_HY); } /* SUB HY */ +OP(fd,95) { m_R++; SUB(_LY); } /* SUB LY */ +OP(fd,96) { m_R++; EAY(); SUB(RM(m_ea)); } /* SUB (IY+o) */ +OP(fd,97) { illegal_1(); op_97(); } /* DB FD */ + +OP(fd,98) { illegal_1(); op_98(); } /* DB FD */ +OP(fd,99) { illegal_1(); op_99(); } /* DB FD */ +OP(fd,9a) { illegal_1(); op_9a(); } /* DB FD */ +OP(fd,9b) { illegal_1(); op_9b(); } /* DB FD */ +OP(fd,9c) { m_R++; SBC(_HY); } /* SBC A,HY */ +OP(fd,9d) { m_R++; SBC(_LY); } /* SBC A,LY */ +OP(fd,9e) { m_R++; EAY(); SBC(RM(m_ea)); } /* SBC A,(IY+o) */ +OP(fd,9f) { illegal_1(); op_9f(); } /* DB FD */ + +OP(fd,a0) { illegal_1(); op_a0(); } /* DB FD */ +OP(fd,a1) { illegal_1(); op_a1(); } /* DB FD */ +OP(fd,a2) { illegal_1(); op_a2(); } /* DB FD */ +OP(fd,a3) { illegal_1(); op_a3(); } /* DB FD */ +OP(fd,a4) { m_R++; AND(_HY); } /* AND HY */ +OP(fd,a5) { m_R++; AND(_LY); } /* AND LY */ +OP(fd,a6) { m_R++; EAY(); AND(RM(m_ea)); } /* AND (IY+o) */ +OP(fd,a7) { illegal_1(); op_a7(); } /* DB FD */ + +OP(fd,a8) { illegal_1(); op_a8(); } /* DB FD */ +OP(fd,a9) { illegal_1(); op_a9(); } /* DB FD */ +OP(fd,aa) { illegal_1(); op_aa(); } /* DB FD */ +OP(fd,ab) { illegal_1(); op_ab(); } /* DB FD */ +OP(fd,ac) { m_R++; XOR(_HY); } /* XOR HY */ +OP(fd,ad) { m_R++; XOR(_LY); } /* XOR LY */ +OP(fd,ae) { m_R++; EAY(); XOR(RM(m_ea)); } /* XOR (IY+o) */ +OP(fd,af) { illegal_1(); op_af(); } /* DB FD */ + +OP(fd,b0) { illegal_1(); op_b0(); } /* DB FD */ +OP(fd,b1) { illegal_1(); op_b1(); } /* DB FD */ +OP(fd,b2) { illegal_1(); op_b2(); } /* DB FD */ +OP(fd,b3) { illegal_1(); op_b3(); } /* DB FD */ +OP(fd,b4) { m_R++; OR(_HY); } /* OR HY */ +OP(fd,b5) { m_R++; OR(_LY); } /* OR LY */ +OP(fd,b6) { m_R++; EAY(); OR(RM(m_ea)); } /* OR (IY+o) */ +OP(fd,b7) { illegal_1(); op_b7(); } /* DB FD */ + +OP(fd,b8) { illegal_1(); op_b8(); } /* DB FD */ +OP(fd,b9) { illegal_1(); op_b9(); } /* DB FD */ +OP(fd,ba) { illegal_1(); op_ba(); } /* DB FD */ +OP(fd,bb) { illegal_1(); op_bb(); } /* DB FD */ +OP(fd,bc) { m_R++; CP(_HY); } /* CP HY */ +OP(fd,bd) { m_R++; CP(_LY); } /* CP LY */ +OP(fd,be) { m_R++; EAY(); CP(RM(m_ea)); } /* CP (IY+o) */ +OP(fd,bf) { illegal_1(); op_bf(); } /* DB FD */ + +OP(fd,c0) { illegal_1(); op_c0(); } /* DB FD */ +OP(fd,c1) { illegal_1(); op_c1(); } /* DB FD */ +OP(fd,c2) { illegal_1(); op_c2(); } /* DB FD */ +OP(fd,c3) { illegal_1(); op_c3(); } /* DB FD */ +OP(fd,c4) { illegal_1(); op_c4(); } /* DB FD */ +OP(fd,c5) { illegal_1(); op_c5(); } /* DB FD */ +OP(fd,c6) { illegal_1(); op_c6(); } /* DB FD */ +OP(fd,c7) { illegal_1(); op_c7(); } /* DB FD */ + +OP(fd,c8) { illegal_1(); op_c8(); } /* DB FD */ +OP(fd,c9) { illegal_1(); op_c9(); } /* DB FD */ +OP(fd,ca) { illegal_1(); op_ca(); } /* DB FD */ +OP(fd,cb) { m_R++; EAY(); m_extra_cycles += exec_xycb(ARG()); } /* ** FD CB xx */ +OP(fd,cc) { illegal_1(); op_cc(); } /* DB FD */ +OP(fd,cd) { illegal_1(); op_cd(); } /* DB FD */ +OP(fd,ce) { illegal_1(); op_ce(); } /* DB FD */ +OP(fd,cf) { illegal_1(); op_cf(); } /* DB FD */ + +OP(fd,d0) { illegal_1(); op_d0(); } /* DB FD */ +OP(fd,d1) { illegal_1(); op_d1(); } /* DB FD */ +OP(fd,d2) { illegal_1(); op_d2(); } /* DB FD */ +OP(fd,d3) { illegal_1(); op_d3(); } /* DB FD */ +OP(fd,d4) { illegal_1(); op_d4(); } /* DB FD */ +OP(fd,d5) { illegal_1(); op_d5(); } /* DB FD */ +OP(fd,d6) { illegal_1(); op_d6(); } /* DB FD */ +OP(fd,d7) { illegal_1(); op_d7(); } /* DB FD */ + +OP(fd,d8) { illegal_1(); op_d8(); } /* DB FD */ +OP(fd,d9) { illegal_1(); op_d9(); } /* DB FD */ +OP(fd,da) { illegal_1(); op_da(); } /* DB FD */ +OP(fd,db) { illegal_1(); op_db(); } /* DB FD */ +OP(fd,dc) { illegal_1(); op_dc(); } /* DB FD */ +OP(fd,dd) { illegal_1(); op_dd(); } /* DB FD */ +OP(fd,de) { illegal_1(); op_de(); } /* DB FD */ +OP(fd,df) { illegal_1(); op_df(); } /* DB FD */ + +OP(fd,e0) { illegal_1(); op_e0(); } /* DB FD */ +OP(fd,e1) { m_R++; POP(IY); } /* POP IY */ +OP(fd,e2) { illegal_1(); op_e2(); } /* DB FD */ +OP(fd,e3) { m_R++; EXSP(IY); } /* EX (SP),IY */ +OP(fd,e4) { illegal_1(); op_e4(); } /* DB FD */ +OP(fd,e5) { m_R++; PUSH( IY ); } /* PUSH IY */ +OP(fd,e6) { illegal_1(); op_e6(); } /* DB FD */ +OP(fd,e7) { illegal_1(); op_e7(); } /* DB FD */ + +OP(fd,e8) { illegal_1(); op_e8(); } /* DB FD */ +OP(fd,e9) { m_R++; _PC = _IY; } /* JP (IY) */ +OP(fd,ea) { illegal_1(); op_ea(); } /* DB FD */ +OP(fd,eb) { illegal_1(); op_eb(); } /* DB FD */ +OP(fd,ec) { illegal_1(); op_ec(); } /* DB FD */ +OP(fd,ed) { illegal_1(); op_ed(); } /* DB FD */ +OP(fd,ee) { illegal_1(); op_ee(); } /* DB FD */ +OP(fd,ef) { illegal_1(); op_ef(); } /* DB FD */ + +OP(fd,f0) { illegal_1(); op_f0(); } /* DB FD */ +OP(fd,f1) { illegal_1(); op_f1(); } /* DB FD */ +OP(fd,f2) { illegal_1(); op_f2(); } /* DB FD */ +OP(fd,f3) { illegal_1(); op_f3(); } /* DB FD */ +OP(fd,f4) { illegal_1(); op_f4(); } /* DB FD */ +OP(fd,f5) { illegal_1(); op_f5(); } /* DB FD */ +OP(fd,f6) { illegal_1(); op_f6(); } /* DB FD */ +OP(fd,f7) { illegal_1(); op_f7(); } /* DB FD */ + +OP(fd,f8) { illegal_1(); op_f8(); } /* DB FD */ +OP(fd,f9) { m_R++; _SP = _IY; } /* LD SP,IY */ +OP(fd,fa) { illegal_1(); op_fa(); } /* DB FD */ +OP(fd,fb) { illegal_1(); op_fb(); } /* DB FD */ +OP(fd,fc) { illegal_1(); op_fc(); } /* DB FD */ +OP(fd,fd) { illegal_1(); op_fd(); } /* DB FD */ +OP(fd,fe) { illegal_1(); op_fe(); } /* DB FD */ +OP(fd,ff) { illegal_1(); op_ff(); } /* DB FD */ diff --git a/src/devices/cpu/z180/z180op.inc b/src/devices/cpu/z180/z180op.inc new file mode 100644 index 00000000000..b3005629a78 --- /dev/null +++ b/src/devices/cpu/z180/z180op.inc @@ -0,0 +1,382 @@ +// license:BSD-3-Clause +// copyright-holders:Juergen Buchmueller +/********************************************************** + * main opcodes + **********************************************************/ +OP(op,00) { } /* NOP */ +OP(op,01) { _BC = ARG16(); } /* LD BC,w */ +OP(op,02) { WM( _BC, _A ); } /* LD (BC),A */ +OP(op,03) { _BC++; } /* INC BC */ +OP(op,04) { _B = INC(_B); } /* INC B */ +OP(op,05) { _B = DEC(_B); } /* DEC B */ +OP(op,06) { _B = ARG(); } /* LD B,n */ +OP(op,07) { RLCA; } /* RLCA */ + +OP(op,08) { EX_AF; } /* EX AF,AF' */ +OP(op,09) { ADD16(HL,BC); } /* ADD HL,BC */ +OP(op,0a) { _A = RM(_BC); } /* LD A,(BC) */ +OP(op,0b) { _BC--; } /* DEC BC */ +OP(op,0c) { _C = INC(_C); } /* INC C */ +OP(op,0d) { _C = DEC(_C); } /* DEC C */ +OP(op,0e) { _C = ARG(); } /* LD C,n */ +OP(op,0f) { RRCA; } /* RRCA */ + +OP(op,10) { _B--; JR_COND( _B, 0x10 ); } /* DJNZ o */ +OP(op,11) { _DE = ARG16(); } /* LD DE,w */ +OP(op,12) { WM( _DE, _A ); } /* LD (DE),A */ +OP(op,13) { _DE++; } /* INC DE */ +OP(op,14) { _D = INC(_D); } /* INC D */ +OP(op,15) { _D = DEC(_D); } /* DEC D */ +OP(op,16) { _D = ARG(); } /* LD D,n */ +OP(op,17) { RLA; } /* RLA */ + +OP(op,18) { JR(); } /* JR o */ +OP(op,19) { ADD16(HL,DE); } /* ADD HL,DE */ +OP(op,1a) { _A = RM(_DE); } /* LD A,(DE) */ +OP(op,1b) { _DE--; ; } /* DEC DE */ +OP(op,1c) { _E = INC(_E); } /* INC E */ +OP(op,1d) { _E = DEC(_E); } /* DEC E */ +OP(op,1e) { _E = ARG(); } /* LD E,n */ +OP(op,1f) { RRA; } /* RRA */ + +OP(op,20) { JR_COND( !(_F & ZF), 0x20 ); } /* JR NZ,o */ +OP(op,21) { _HL = ARG16(); } /* LD HL,w */ +OP(op,22) { m_ea = ARG16(); WM16(m_ea, &m_HL ); } /* LD (w),HL */ +OP(op,23) { _HL++; } /* INC HL */ +OP(op,24) { _H = INC(_H); } /* INC H */ +OP(op,25) { _H = DEC(_H); } /* DEC H */ +OP(op,26) { _H = ARG(); } /* LD H,n */ +OP(op,27) { DAA; } /* DAA */ + +OP(op,28) { JR_COND( _F & ZF, 0x28 ); } /* JR Z,o */ +OP(op,29) { ADD16(HL,HL); } /* ADD HL,HL */ +OP(op,2a) { m_ea = ARG16(); RM16(m_ea, &m_HL ); } /* LD HL,(w) */ +OP(op,2b) { _HL--; } /* DEC HL */ +OP(op,2c) { _L = INC(_L); } /* INC L */ +OP(op,2d) { _L = DEC(_L); } /* DEC L */ +OP(op,2e) { _L = ARG(); } /* LD L,n */ +OP(op,2f) { _A ^= 0xff; _F = (_F&(SF|ZF|PF|CF))|HF|NF|(_A&(YF|XF)); } /* CPL */ + +OP(op,30) { JR_COND( !(_F & CF), 0x30 ); } /* JR NC,o */ +OP(op,31) { _SP = ARG16(); } /* LD SP,w */ +OP(op,32) { m_ea = ARG16(); WM( m_ea, _A ); } /* LD (w),A */ +OP(op,33) { _SP++; } /* INC SP */ +OP(op,34) { WM( _HL, INC(RM(_HL)) ); } /* INC (HL) */ +OP(op,35) { WM( _HL, DEC(RM(_HL)) ); } /* DEC (HL) */ +OP(op,36) { WM( _HL, ARG() ); } /* LD (HL),n */ +OP(op,37) { _F = (_F & (SF|ZF|PF)) | CF | (_A & (YF|XF)); } /* SCF */ + +OP(op,38) { JR_COND( _F & CF, 0x38 ); } /* JR C,o */ +OP(op,39) { ADD16(HL,SP); } /* ADD HL,SP */ +OP(op,3a) { m_ea = ARG16(); _A = RM( m_ea ); } /* LD A,(w) */ +OP(op,3b) { _SP--; } /* DEC SP */ +OP(op,3c) { _A = INC(_A); } /* INC A */ +OP(op,3d) { _A = DEC(_A); } /* DEC A */ +OP(op,3e) { _A = ARG(); } /* LD A,n */ +OP(op,3f) { _F = ((_F&(SF|ZF|PF|CF))|((_F&CF)<<4)|(_A&(YF|XF)))^CF; } /* CCF */ +//OP(op,3f) { _F = ((_F & ~(HF|NF)) | ((_F & CF)<<4)) ^ CF; } /* CCF */ + +OP(op,40) { } /* LD B,B */ +OP(op,41) { _B = _C; } /* LD B,C */ +OP(op,42) { _B = _D; } /* LD B,D */ +OP(op,43) { _B = _E; } /* LD B,E */ +OP(op,44) { _B = _H; } /* LD B,H */ +OP(op,45) { _B = _L; } /* LD B,L */ +OP(op,46) { _B = RM(_HL); } /* LD B,(HL) */ +OP(op,47) { _B = _A; } /* LD B,A */ + +OP(op,48) { _C = _B; } /* LD C,B */ +OP(op,49) { } /* LD C,C */ +OP(op,4a) { _C = _D; } /* LD C,D */ +OP(op,4b) { _C = _E; } /* LD C,E */ +OP(op,4c) { _C = _H; } /* LD C,H */ +OP(op,4d) { _C = _L; } /* LD C,L */ +OP(op,4e) { _C = RM(_HL); } /* LD C,(HL) */ +OP(op,4f) { _C = _A; } /* LD C,A */ + +OP(op,50) { _D = _B; } /* LD D,B */ +OP(op,51) { _D = _C; } /* LD D,C */ +OP(op,52) { } /* LD D,D */ +OP(op,53) { _D = _E; } /* LD D,E */ +OP(op,54) { _D = _H; } /* LD D,H */ +OP(op,55) { _D = _L; } /* LD D,L */ +OP(op,56) { _D = RM(_HL); } /* LD D,(HL) */ +OP(op,57) { _D = _A; } /* LD D,A */ + +OP(op,58) { _E = _B; } /* LD E,B */ +OP(op,59) { _E = _C; } /* LD E,C */ +OP(op,5a) { _E = _D; } /* LD E,D */ +OP(op,5b) { } /* LD E,E */ +OP(op,5c) { _E = _H; } /* LD E,H */ +OP(op,5d) { _E = _L; } /* LD E,L */ +OP(op,5e) { _E = RM(_HL); } /* LD E,(HL) */ +OP(op,5f) { _E = _A; } /* LD E,A */ + +OP(op,60) { _H = _B; } /* LD H,B */ +OP(op,61) { _H = _C; } /* LD H,C */ +OP(op,62) { _H = _D; } /* LD H,D */ +OP(op,63) { _H = _E; } /* LD H,E */ +OP(op,64) { } /* LD H,H */ +OP(op,65) { _H = _L; } /* LD H,L */ +OP(op,66) { _H = RM(_HL); } /* LD H,(HL) */ +OP(op,67) { _H = _A; } /* LD H,A */ + +OP(op,68) { _L = _B; } /* LD L,B */ +OP(op,69) { _L = _C; } /* LD L,C */ +OP(op,6a) { _L = _D; } /* LD L,D */ +OP(op,6b) { _L = _E; } /* LD L,E */ +OP(op,6c) { _L = _H; } /* LD L,H */ +OP(op,6d) { } /* LD L,L */ +OP(op,6e) { _L = RM(_HL); } /* LD L,(HL) */ +OP(op,6f) { _L = _A; } /* LD L,A */ + +OP(op,70) { WM( _HL, _B ); } /* LD (HL),B */ +OP(op,71) { WM( _HL, _C ); } /* LD (HL),C */ +OP(op,72) { WM( _HL, _D ); } /* LD (HL),D */ +OP(op,73) { WM( _HL, _E ); } /* LD (HL),E */ +OP(op,74) { WM( _HL, _H ); } /* LD (HL),H */ +OP(op,75) { WM( _HL, _L ); } /* LD (HL),L */ +OP(op,76) { ENTER_HALT(); } /* HALT */ +OP(op,77) { WM( _HL, _A ); } /* LD (HL),A */ + +OP(op,78) { _A = _B; } /* LD A,B */ +OP(op,79) { _A = _C; } /* LD A,C */ +OP(op,7a) { _A = _D; } /* LD A,D */ +OP(op,7b) { _A = _E; } /* LD A,E */ +OP(op,7c) { _A = _H; } /* LD A,H */ +OP(op,7d) { _A = _L; } /* LD A,L */ +OP(op,7e) { _A = RM(_HL); } /* LD A,(HL) */ +OP(op,7f) { } /* LD A,A */ + +OP(op,80) { ADD(_B); } /* ADD A,B */ +OP(op,81) { ADD(_C); } /* ADD A,C */ +OP(op,82) { ADD(_D); } /* ADD A,D */ +OP(op,83) { ADD(_E); } /* ADD A,E */ +OP(op,84) { ADD(_H); } /* ADD A,H */ +OP(op,85) { ADD(_L); } /* ADD A,L */ +OP(op,86) { ADD(RM(_HL)); } /* ADD A,(HL) */ +OP(op,87) { ADD(_A); } /* ADD A,A */ + +OP(op,88) { ADC(_B); } /* ADC A,B */ +OP(op,89) { ADC(_C); } /* ADC A,C */ +OP(op,8a) { ADC(_D); } /* ADC A,D */ +OP(op,8b) { ADC(_E); } /* ADC A,E */ +OP(op,8c) { ADC(_H); } /* ADC A,H */ +OP(op,8d) { ADC(_L); } /* ADC A,L */ +OP(op,8e) { ADC(RM(_HL)); } /* ADC A,(HL) */ +OP(op,8f) { ADC(_A); } /* ADC A,A */ + +OP(op,90) { SUB(_B); } /* SUB B */ +OP(op,91) { SUB(_C); } /* SUB C */ +OP(op,92) { SUB(_D); } /* SUB D */ +OP(op,93) { SUB(_E); } /* SUB E */ +OP(op,94) { SUB(_H); } /* SUB H */ +OP(op,95) { SUB(_L); } /* SUB L */ +OP(op,96) { SUB(RM(_HL)); } /* SUB (HL) */ +OP(op,97) { SUB(_A); } /* SUB A */ + +OP(op,98) { SBC(_B); } /* SBC A,B */ +OP(op,99) { SBC(_C); } /* SBC A,C */ +OP(op,9a) { SBC(_D); } /* SBC A,D */ +OP(op,9b) { SBC(_E); } /* SBC A,E */ +OP(op,9c) { SBC(_H); } /* SBC A,H */ +OP(op,9d) { SBC(_L); } /* SBC A,L */ +OP(op,9e) { SBC(RM(_HL)); } /* SBC A,(HL) */ +OP(op,9f) { SBC(_A); } /* SBC A,A */ + +OP(op,a0) { AND(_B); } /* AND B */ +OP(op,a1) { AND(_C); } /* AND C */ +OP(op,a2) { AND(_D); } /* AND D */ +OP(op,a3) { AND(_E); } /* AND E */ +OP(op,a4) { AND(_H); } /* AND H */ +OP(op,a5) { AND(_L); } /* AND L */ +OP(op,a6) { AND(RM(_HL)); } /* AND (HL) */ +OP(op,a7) { AND(_A); } /* AND A */ + +OP(op,a8) { XOR(_B); } /* XOR B */ +OP(op,a9) { XOR(_C); } /* XOR C */ +OP(op,aa) { XOR(_D); } /* XOR D */ +OP(op,ab) { XOR(_E); } /* XOR E */ +OP(op,ac) { XOR(_H); } /* XOR H */ +OP(op,ad) { XOR(_L); } /* XOR L */ +OP(op,ae) { XOR(RM(_HL)); } /* XOR (HL) */ +OP(op,af) { XOR(_A); } /* XOR A */ + +OP(op,b0) { OR(_B); } /* OR B */ +OP(op,b1) { OR(_C); } /* OR C */ +OP(op,b2) { OR(_D); } /* OR D */ +OP(op,b3) { OR(_E); } /* OR E */ +OP(op,b4) { OR(_H); } /* OR H */ +OP(op,b5) { OR(_L); } /* OR L */ +OP(op,b6) { OR(RM(_HL)); } /* OR (HL) */ +OP(op,b7) { OR(_A); } /* OR A */ + +OP(op,b8) { CP(_B); } /* CP B */ +OP(op,b9) { CP(_C); } /* CP C */ +OP(op,ba) { CP(_D); } /* CP D */ +OP(op,bb) { CP(_E); } /* CP E */ +OP(op,bc) { CP(_H); } /* CP H */ +OP(op,bd) { CP(_L); } /* CP L */ +OP(op,be) { CP(RM(_HL)); } /* CP (HL) */ +OP(op,bf) { CP(_A); } /* CP A */ + +OP(op,c0) { RET_COND( !(_F & ZF), 0xc0 ); } /* RET NZ */ +OP(op,c1) { POP(BC); } /* POP BC */ +OP(op,c2) { JP_COND( !(_F & ZF) ); } /* JP NZ,a */ +OP(op,c3) { JP; } /* JP a */ +OP(op,c4) { CALL_COND( !(_F & ZF), 0xc4 ); } /* CALL NZ,a */ +OP(op,c5) { PUSH( BC ); } /* PUSH BC */ +OP(op,c6) { ADD(ARG()); } /* ADD A,n */ +OP(op,c7) { RST(0x00); } /* RST 0 */ + +OP(op,c8) { RET_COND( _F & ZF, 0xc8 ); } /* RET Z */ +OP(op,c9) { POP(PC); } /* RET */ +OP(op,ca) { JP_COND( _F & ZF ); } /* JP Z,a */ +OP(op,cb) { m_R++; m_extra_cycles += exec_cb(ROP()); } /* **** CB xx */ +OP(op,cc) { CALL_COND( _F & ZF, 0xcc ); } /* CALL Z,a */ +OP(op,cd) { CALL(); } /* CALL a */ +OP(op,ce) { ADC(ARG()); } /* ADC A,n */ +OP(op,cf) { RST(0x08); } /* RST 1 */ + +OP(op,d0) { RET_COND( !(_F & CF), 0xd0 ); } /* RET NC */ +OP(op,d1) { POP(DE); } /* POP DE */ +OP(op,d2) { JP_COND( !(_F & CF) ); } /* JP NC,a */ +OP(op,d3) { unsigned n = ARG() | (_A << 8); OUT(n, _A ); } /* OUT (n),A */ +OP(op,d4) { CALL_COND( !(_F & CF), 0xd4 ); } /* CALL NC,a */ +OP(op,d5) { PUSH( DE ); } /* PUSH DE */ +OP(op,d6) { SUB(ARG()); } /* SUB n */ +OP(op,d7) { RST(0x10); } /* RST 2 */ + +OP(op,d8) { RET_COND( _F & CF, 0xd8 ); } /* RET C */ +OP(op,d9) { EXX; } /* EXX */ +OP(op,da) { JP_COND( _F & CF ); } /* JP C,a */ +OP(op,db) { unsigned n = ARG() | (_A << 8); _A = IN(n ); } /* IN A,(n) */ +OP(op,dc) { CALL_COND( _F & CF, 0xdc ); } /* CALL C,a */ +OP(op,dd) { m_R++; m_extra_cycles += exec_dd(ROP()); } /* **** DD xx */ +OP(op,de) { SBC(ARG()); } /* SBC A,n */ +OP(op,df) { RST(0x18); } /* RST 3 */ + +OP(op,e0) { RET_COND( !(_F & PF), 0xe0 ); } /* RET PO */ +OP(op,e1) { POP(HL); } /* POP HL */ +OP(op,e2) { JP_COND( !(_F & PF) ); } /* JP PO,a */ +OP(op,e3) { EXSP(HL); } /* EX HL,(SP) */ +OP(op,e4) { CALL_COND( !(_F & PF), 0xe4 ); } /* CALL PO,a */ +OP(op,e5) { PUSH( HL ); } /* PUSH HL */ +OP(op,e6) { AND(ARG()); } /* AND n */ +OP(op,e7) { RST(0x20); } /* RST 4 */ + +OP(op,e8) { RET_COND( _F & PF, 0xe8 ); } /* RET PE */ +OP(op,e9) { _PC = _HL; } /* JP (HL) */ +OP(op,ea) { JP_COND( _F & PF ); } /* JP PE,a */ +OP(op,eb) { EX_DE_HL; } /* EX DE,HL */ +OP(op,ec) { CALL_COND( _F & PF, 0xec ); } /* CALL PE,a */ +OP(op,ed) { m_R++; m_extra_cycles += exec_ed(ROP()); } /* **** ED xx */ +OP(op,ee) { XOR(ARG()); } /* XOR n */ +OP(op,ef) { RST(0x28); } /* RST 5 */ + +OP(op,f0) { RET_COND( !(_F & SF), 0xf0 ); } /* RET P */ +OP(op,f1) { POP(AF); } /* POP AF */ +OP(op,f2) { JP_COND( !(_F & SF) ); } /* JP P,a */ +OP(op,f3) { m_IFF1 = m_IFF2 = 0; } /* DI */ +OP(op,f4) { CALL_COND( !(_F & SF), 0xf4 ); } /* CALL P,a */ +OP(op,f5) { PUSH( AF ); } /* PUSH AF */ +OP(op,f6) { OR(ARG()); } /* OR n */ +OP(op,f7) { RST(0x30); } /* RST 6 */ + +OP(op,f8) { RET_COND( _F & SF, 0xf8 ); } /* RET M */ +OP(op,f9) { _SP = _HL; } /* LD SP,HL */ +OP(op,fa) { JP_COND(_F & SF); } /* JP M,a */ +OP(op,fb) { EI; } /* EI */ +OP(op,fc) { CALL_COND( _F & SF, 0xfc ); } /* CALL M,a */ +OP(op,fd) { m_R++; m_extra_cycles += exec_fd(ROP()); } /* **** FD xx */ +OP(op,fe) { CP(ARG()); } /* CP n */ +OP(op,ff) { RST(0x38); } /* RST 7 */ + + +int z180_device::take_interrupt(int irq) +{ + int irq_vector; + int cycles = 0; + + /* there isn't a valid previous program counter */ + _PPC = -1; + + /* Check if processor was halted */ + LEAVE_HALT(); + + /* Clear both interrupt flip flops */ + m_IFF1 = m_IFF2 = 0; + + if( irq == Z180_INT_IRQ0 ) + { + /* Daisy chain mode? If so, call the requesting device */ + if (m_daisy.present()) + irq_vector = m_daisy.call_ack_device(); + + /* else call back the cpu interface to retrieve the vector */ + else + irq_vector = standard_irq_callback(0); + + LOG(("Z180 '%s' single int. irq_vector $%02x\n", tag(), irq_vector)); + + /* Interrupt mode 2. Call [m_I:databyte] */ + if( m_IM == 2 ) + { + irq_vector = (irq_vector & 0xff) + (m_I << 8); + PUSH( PC ); + RM16(irq_vector, &m_PC ); + LOG(("Z180 '%s' IM2 [$%04x] = $%04x\n",tag() , irq_vector, _PCD)); + /* CALL opcode timing */ + cycles += m_cc[Z180_TABLE_op][0xcd]; + } + else + /* Interrupt mode 1. RST 38h */ + if( m_IM == 1 ) + { + LOG(("Z180 '%s' IM1 $0038\n",tag() )); + PUSH( PC ); + _PCD = 0x0038; + /* RST $38 + 'interrupt latency' cycles */ + cycles += m_cc[Z180_TABLE_op][0xff] - m_cc[Z180_TABLE_ex][0xff]; + } + else + { + /* Interrupt mode 0. We check for CALL and JP instructions, */ + /* if neither of these were found we assume a 1 byte opcode */ + /* was placed on the databus */ + LOG(("Z180 '%s' IM0 $%04x\n",tag() , irq_vector)); + switch (irq_vector & 0xff0000) + { + case 0xcd0000: /* call */ + PUSH( PC ); + _PCD = irq_vector & 0xffff; + /* CALL $xxxx + 'interrupt latency' cycles */ + cycles += m_cc[Z180_TABLE_op][0xcd] - m_cc[Z180_TABLE_ex][0xff]; + break; + case 0xc30000: /* jump */ + _PCD = irq_vector & 0xffff; + /* JP $xxxx + 2 cycles */ + cycles += m_cc[Z180_TABLE_op][0xc3] - m_cc[Z180_TABLE_ex][0xff]; + break; + default: /* rst (or other opcodes?) */ + PUSH( PC ); + _PCD = irq_vector & 0x0038; + /* RST $xx + 2 cycles */ + cycles += m_cc[Z180_TABLE_op][_PCD] - m_cc[Z180_TABLE_ex][_PCD]; + break; + } + } + } + else + { + irq_vector = (IO(Z180_IL) & Z180_IL_IL) + (irq - Z180_INT_IRQ1) * 2; + irq_vector = (m_I << 8) + (irq_vector & 0xff); + PUSH( PC ); + RM16(irq_vector, &m_PC ); + LOG(("Z180 '%s' INT%d [$%04x] = $%04x\n", tag(), irq, irq_vector, _PCD)); + /* CALL opcode timing */ + cycles += m_cc[Z180_TABLE_op][0xcd]; + } + + return cycles; +} diff --git a/src/devices/cpu/z180/z180ops.h b/src/devices/cpu/z180/z180ops.h new file mode 100644 index 00000000000..36f06a6847f --- /dev/null +++ b/src/devices/cpu/z180/z180ops.h @@ -0,0 +1,940 @@ +// license:BSD-3-Clause +// copyright-holders:Juergen Buchmueller +/*************************************************************** + * Enter HALT state; write 1 to fake port on first execution + ***************************************************************/ +#define ENTER_HALT() { \ + _PC--; \ + m_HALT = 1; \ +} + +/*************************************************************** + * Leave HALT state; write 0 to fake port + ***************************************************************/ +#define LEAVE_HALT() { \ + if( m_HALT ) \ + { \ + m_HALT = 0; \ + _PC++; \ + } \ +} + +/*************************************************************** + * Input a byte from given I/O port + ***************************************************************/ +#define IN(port) \ + (((port ^ IO_IOCR) & 0xffc0) == 0) ? \ + z180_readcontrol(port) : m_iospace->read_byte(port) + +/*************************************************************** + * Output a byte to given I/O port + ***************************************************************/ +#define OUT(port,value) \ + if (((port ^ IO_IOCR) & 0xffc0) == 0) \ + z180_writecontrol(port,value); \ + else m_iospace->write_byte(port,value) + +/*************************************************************** + * MMU calculate the memory managemant lookup table + * bb and cb specify a 4K page + * If the 4 most significant bits of an 16 bit address are + * greater or equal to the bank base, the bank base register + * specifies the 4K offset into the 20 bit address space. + * If the 4 bits are also greater or equal to the common base, + * the common base register is used to specify the offset. + ***************************************************************/ +void z180_device::z180_mmu() +{ + offs_t addr, page, bb, cb; + bb = IO_CBAR & 15; + cb = IO_CBAR >> 4; + for( page = 0; page < 16; page++ ) + { + addr = page << 12; + if (page >= bb) + { + if (page >= cb) + addr += (IO_CBR << 12); + else + addr += (IO_BBR << 12); + } + m_mmu[page] = (addr & 0xfffff); + } +} + + +#define MMU_REMAP_ADDR(addr) (m_mmu[((addr)>>12)&15]|((addr)&4095)) + +/*************************************************************** + * Read a byte from given memory location + ***************************************************************/ +#define RM(addr) m_program->read_byte(MMU_REMAP_ADDR(addr)) + +/*************************************************************** + * Write a byte to given memory location + ***************************************************************/ +#define WM(addr,value) m_program->write_byte(MMU_REMAP_ADDR(addr),value) + +/*************************************************************** + * Read a word from given memory location + ***************************************************************/ +void z180_device::RM16( offs_t addr, PAIR *r ) +{ + r->b.l = RM(addr); + r->b.h = RM(addr+1); +} + +/*************************************************************** + * Write a word to given memory location + ***************************************************************/ +void z180_device::WM16( offs_t addr, PAIR *r ) +{ + WM(addr, r->b.l); + WM(addr+1, r->b.h); +} + +/*************************************************************** + * ROP() is identical to RM() except it is used for + * reading opcodes. In case of system with memory mapped I/O, + * this function can be used to greatly speed up emulation + ***************************************************************/ +UINT8 z180_device::ROP() +{ + offs_t addr = _PCD; + _PC++; + return m_odirect->read_byte(MMU_REMAP_ADDR(addr)); +} + +/**************************************************************** + * ARG() is identical to ROP() except it is used + * for reading opcode arguments. This difference can be used to + * support systems that use different encoding mechanisms for + * opcodes and opcode arguments + ***************************************************************/ +UINT8 z180_device::ARG() +{ + offs_t addr = _PCD; + _PC++; + return m_direct->read_byte(MMU_REMAP_ADDR(addr)); +} + +UINT32 z180_device::ARG16() +{ + offs_t addr = _PCD; + _PC += 2; + return m_direct->read_byte(MMU_REMAP_ADDR(addr)) | (m_direct->read_byte(MMU_REMAP_ADDR(addr+1)) << 8); +} + +/*************************************************************** + * Calculate the effective addess m_ea of an opcode using + * IX+offset resp. IY+offset addressing. + ***************************************************************/ +#define EAX() m_ea = (UINT32)(UINT16)(_IX + (INT8)ARG()) +#define EAY() m_ea = (UINT32)(UINT16)(_IY + (INT8)ARG()) + +/*************************************************************** + * POP + ***************************************************************/ +#define POP(DR) { RM16(_SPD, &m_##DR ); _SP += 2; } + +/*************************************************************** + * PUSH + ***************************************************************/ +#define PUSH(SR) { _SP -= 2; WM16(_SPD, &m_##SR); } + +/*************************************************************** + * JP + ***************************************************************/ +#define JP { \ + _PCD = ARG16(); \ +} + +/*************************************************************** + * JP_COND + ***************************************************************/ + +#define JP_COND(cond) \ + if( cond ) \ + { \ + _PCD = ARG16(); \ + } \ + else \ + { \ + _PC += 2; \ + } + +/*************************************************************** + * JR + ***************************************************************/ +#define JR() \ +{ \ + INT8 arg = (INT8)ARG(); /* ARG() also increments _PC */ \ + _PC += arg; /* so don't do _PC += ARG() */ \ +} + +/*************************************************************** + * JR_COND + ***************************************************************/ +#define JR_COND(cond,opcode) \ + if( cond ) \ + { \ + INT8 arg = (INT8)ARG(); /* ARG() also increments _PC */ \ + _PC += arg; /* so don't do _PC += ARG() */ \ + CC(ex,opcode); \ + } \ + else _PC++; +/*************************************************************** + * CALL + ***************************************************************/ +#define CALL() \ + m_ea = ARG16(); \ + PUSH( PC ); \ + _PCD = m_ea; + +/*************************************************************** + * CALL_COND + ***************************************************************/ +#define CALL_COND(cond,opcode) \ + if( cond ) \ + { \ + m_ea = ARG16(); \ + PUSH( PC ); \ + _PCD = m_ea; \ + CC(ex,opcode); \ + } \ + else \ + { \ + _PC+=2; \ + } + +/*************************************************************** + * RET_COND + ***************************************************************/ +#define RET_COND(cond,opcode) \ + if( cond ) \ + { \ + POP(PC); \ + CC(ex,opcode); \ + } + +/*************************************************************** + * RETN + ***************************************************************/ +#define RETN { \ + LOG(("Z180 '%s' RETN IFF1:%d IFF2:%d\n", tag(), m_IFF1, m_IFF2)); \ + POP(PC); \ + m_IFF1 = m_IFF2; \ +} + +/*************************************************************** + * RETI + ***************************************************************/ +#define RETI { \ + POP(PC); \ +/* according to http://www.msxnet.org/tech/Z80/z80undoc.txt */ \ +/* m_IFF1 = m_IFF2; */ \ + m_daisy.call_reti_device(); \ +} + +/*************************************************************** + * LD R,A + ***************************************************************/ +#define LD_R_A { \ + m_R = _A; \ + m_R2 = _A & 0x80; /* keep bit 7 of R */ \ +} + +/*************************************************************** + * LD A,R + ***************************************************************/ +#define LD_A_R { \ + _A = (m_R & 0x7f) | m_R2; \ + _F = (_F & CF) | SZ[_A] | ( m_IFF2 << 2 ); \ +} + +/*************************************************************** + * LD I,A + ***************************************************************/ +#define LD_I_A { \ + m_I = _A; \ +} + +/*************************************************************** + * LD A,I + ***************************************************************/ +#define LD_A_I { \ + _A = m_I; \ + _F = (_F & CF) | SZ[_A] | ( m_IFF2 << 2 ); \ +} + +/*************************************************************** + * RST + ***************************************************************/ +#define RST(addr) \ + PUSH( PC ); \ + _PCD = addr; + +/*************************************************************** + * INC r8 + ***************************************************************/ +UINT8 z180_device::INC(UINT8 value) +{ + UINT8 res = value + 1; + _F = (_F & CF) | SZHV_inc[res]; + return (UINT8)res; +} + +/*************************************************************** + * DEC r8 + ***************************************************************/ +UINT8 z180_device::DEC(UINT8 value) +{ + UINT8 res = value - 1; + _F = (_F & CF) | SZHV_dec[res]; + return res; +} + +/*************************************************************** + * RLCA + ***************************************************************/ +#define RLCA \ + _A = (_A << 1) | (_A >> 7); \ + _F = (_F & (SF | ZF | PF)) | (_A & (YF | XF | CF)) + +/*************************************************************** + * RRCA + ***************************************************************/ +#define RRCA \ + _F = (_F & (SF | ZF | PF)) | (_A & (YF | XF | CF)); \ + _A = (_A >> 1) | (_A << 7) + +/*************************************************************** + * RLA + ***************************************************************/ +#define RLA { \ + UINT8 res = (_A << 1) | (_F & CF); \ + UINT8 c = (_A & 0x80) ? CF : 0; \ + _F = (_F & (SF | ZF | PF)) | c | (res & (YF | XF)); \ + _A = res; \ +} + +/*************************************************************** + * RRA + ***************************************************************/ +#define RRA { \ + UINT8 res = (_A >> 1) | (_F << 7); \ + UINT8 c = (_A & 0x01) ? CF : 0; \ + _F = (_F & (SF | ZF | PF)) | c | (res & (YF | XF)); \ + _A = res; \ +} + +/*************************************************************** + * RRD + ***************************************************************/ +#define RRD { \ + UINT8 n = RM(_HL); \ + WM( _HL, (n >> 4) | (_A << 4) ); \ + _A = (_A & 0xf0) | (n & 0x0f); \ + _F = (_F & CF) | SZP[_A]; \ +} + +/*************************************************************** + * RLD + ***************************************************************/ +#define RLD { \ + UINT8 n = RM(_HL); \ + WM( _HL, (n << 4) | (_A & 0x0f) ); \ + _A = (_A & 0xf0) | (n >> 4); \ + _F = (_F & CF) | SZP[_A]; \ +} + +/*************************************************************** + * ADD A,n + ***************************************************************/ +#define ADD(value) \ +{ \ + UINT32 ah = _AFD & 0xff00; \ + UINT32 res = (UINT8)((ah >> 8) + value); \ + _F = SZHVC_add[ah | res]; \ + _A = res; \ +} + +/*************************************************************** + * ADC A,n + ***************************************************************/ +#define ADC(value) \ +{ \ + UINT32 ah = _AFD & 0xff00, c = _AFD & 1; \ + UINT32 res = (UINT8)((ah >> 8) + value + c); \ + _F = SZHVC_add[(c << 16) | ah | res]; \ + _A = res; \ +} + +/*************************************************************** + * SUB n + ***************************************************************/ +#define SUB(value) \ +{ \ + UINT32 ah = _AFD & 0xff00; \ + UINT32 res = (UINT8)((ah >> 8) - value); \ + _F = SZHVC_sub[ah | res]; \ + _A = res; \ +} + +/*************************************************************** + * SBC A,n + ***************************************************************/ +#define SBC(value) \ +{ \ + UINT32 ah = _AFD & 0xff00, c = _AFD & 1; \ + UINT32 res = (UINT8)((ah >> 8) - value - c); \ + _F = SZHVC_sub[(c<<16) | ah | res]; \ + _A = res; \ +} + +/*************************************************************** + * NEG + ***************************************************************/ +#define NEG { \ + UINT8 value = _A; \ + _A = 0; \ + SUB(value); \ +} + +/*************************************************************** + * DAA + ***************************************************************/ +#define DAA { \ + UINT8 r = _A; \ + if (_F&NF) { \ + if ((_F&HF)|((_A&0xf)>9)) r-=6; \ + if ((_F&CF)|(_A>0x99)) r-=0x60; \ + } \ + else { \ + if ((_F&HF)|((_A&0xf)>9)) r+=6; \ + if ((_F&CF)|(_A>0x99)) r+=0x60; \ + } \ + _F=(_F&3)|(_A>0x99)|((_A^r)&HF)|SZP[r]; \ + _A=r; \ +} + +/*************************************************************** + * AND n + ***************************************************************/ +#define AND(value) \ + _A &= value; \ + _F = SZP[_A] | HF + +/*************************************************************** + * OR n + ***************************************************************/ +#define OR(value) \ + _A |= value; \ + _F = SZP[_A] + +/*************************************************************** + * XOR n + ***************************************************************/ +#define XOR(value) \ + _A ^= value; \ + _F = SZP[_A] + +/*************************************************************** + * CP n + ***************************************************************/ +#define CP(value) \ +{ \ + UINT32 ah = _AFD & 0xff00; \ + UINT32 res = (UINT8)((ah >> 8) - value); \ + _F = SZHVC_sub[ah | res]; \ +} + +/*************************************************************** + * EX AF,AF' + ***************************************************************/ +#define EX_AF { \ + PAIR tmp; \ + tmp = m_AF; m_AF = m_AF2; m_AF2 = tmp; \ +} + +/*************************************************************** + * EX DE,HL + ***************************************************************/ +#define EX_DE_HL { \ + PAIR tmp; \ + tmp = m_DE; m_DE = m_HL; m_HL = tmp; \ +} + +/*************************************************************** + * EXX + ***************************************************************/ +#define EXX { \ + PAIR tmp; \ + tmp = m_BC; m_BC = m_BC2; m_BC2 = tmp; \ + tmp = m_DE; m_DE = m_DE2; m_DE2 = tmp; \ + tmp = m_HL; m_HL = m_HL2; m_HL2 = tmp; \ +} + +/*************************************************************** + * EX (SP),r16 + ***************************************************************/ +#define EXSP(DR) \ +{ \ + PAIR tmp = { { 0, 0, 0, 0 } }; \ + RM16( _SPD, &tmp ); \ + WM16( _SPD, &m_##DR ); \ + m_##DR = tmp; \ +} + + +/*************************************************************** + * ADD16 + ***************************************************************/ +#define ADD16(DR,SR) \ +{ \ + UINT32 res = m_##DR.d + m_##SR.d; \ + _F = (_F & (SF | ZF | VF)) | \ + (((m_##DR.d ^ res ^ m_##SR.d) >> 8) & HF) | \ + ((res >> 16) & CF); \ + m_##DR.w.l = (UINT16)res; \ +} + +/*************************************************************** + * ADC r16,r16 + ***************************************************************/ +#define ADC16(DR) \ +{ \ + UINT32 res = _HLD + m_##DR.d + (_F & CF); \ + _F = (((_HLD ^ res ^ m_##DR.d) >> 8) & HF) | \ + ((res >> 16) & CF) | \ + ((res >> 8) & SF) | \ + ((res & 0xffff) ? 0 : ZF) | \ + (((m_##DR.d ^ _HLD ^ 0x8000) & (m_##DR.d ^ res) & 0x8000) >> 13); \ + _HL = (UINT16)res; \ +} + +/*************************************************************** + * SBC r16,r16 + ***************************************************************/ +#define SBC16(DR) \ +{ \ + UINT32 res = _HLD - m_##DR.d - (_F & CF); \ + _F = (((_HLD ^ res ^ m_##DR.d) >> 8) & HF) | NF | \ + ((res >> 16) & CF) | \ + ((res >> 8) & SF) | \ + ((res & 0xffff) ? 0 : ZF) | \ + (((m_##DR.d ^ _HLD) & (_HLD ^ res) &0x8000) >> 13); \ + _HL = (UINT16)res; \ +} + +/*************************************************************** + * RLC r8 + ***************************************************************/ +UINT8 z180_device::RLC(UINT8 value) +{ + unsigned res = value; + unsigned c = (res & 0x80) ? CF : 0; + res = ((res << 1) | (res >> 7)) & 0xff; + _F = SZP[res] | c; + return res; +} + +/*************************************************************** + * RRC r8 + ***************************************************************/ +UINT8 z180_device::RRC(UINT8 value) +{ + unsigned res = value; + unsigned c = (res & 0x01) ? CF : 0; + res = ((res >> 1) | (res << 7)) & 0xff; + _F = SZP[res] | c; + return res; +} + +/*************************************************************** + * RL r8 + ***************************************************************/ +UINT8 z180_device::RL(UINT8 value) +{ + unsigned res = value; + unsigned c = (res & 0x80) ? CF : 0; + res = ((res << 1) | (_F & CF)) & 0xff; + _F = SZP[res] | c; + return res; +} + +/*************************************************************** + * RR r8 + ***************************************************************/ +UINT8 z180_device::RR(UINT8 value) +{ + unsigned res = value; + unsigned c = (res & 0x01) ? CF : 0; + res = ((res >> 1) | (_F << 7)) & 0xff; + _F = SZP[res] | c; + return res; +} + +/*************************************************************** + * SLA r8 + ***************************************************************/ +UINT8 z180_device::SLA(UINT8 value) +{ + unsigned res = value; + unsigned c = (res & 0x80) ? CF : 0; + res = (res << 1) & 0xff; + _F = SZP[res] | c; + return res; +} + +/*************************************************************** + * SRA r8 + ***************************************************************/ +UINT8 z180_device::SRA(UINT8 value) +{ + unsigned res = value; + unsigned c = (res & 0x01) ? CF : 0; + res = ((res >> 1) | (res & 0x80)) & 0xff; + _F = SZP[res] | c; + return res; +} + +/*************************************************************** + * SLL r8 + ***************************************************************/ +UINT8 z180_device::SLL(UINT8 value) +{ + unsigned res = value; + unsigned c = (res & 0x80) ? CF : 0; + res = ((res << 1) | 0x01) & 0xff; + _F = SZP[res] | c; + return res; +} + +/*************************************************************** + * SRL r8 + ***************************************************************/ +UINT8 z180_device::SRL(UINT8 value) +{ + unsigned res = value; + unsigned c = (res & 0x01) ? CF : 0; + res = (res >> 1) & 0xff; + _F = SZP[res] | c; + return res; +} + +/*************************************************************** + * BIT bit,r8 + ***************************************************************/ +#undef BIT +#define BIT(bit,reg) \ + _F = (_F & CF) | HF | SZ_BIT[reg & (1<>8) & (YF|XF)) + +/*************************************************************** + * RES bit,r8 + ***************************************************************/ +UINT8 z180_device::RES(UINT8 bit, UINT8 value) +{ + return value & ~(1< flag 5 */ \ + if( (_A + io) & 0x08 ) _F |= XF; /* bit 3 -> flag 3 */ \ + _HL++; _DE++; _BC--; \ + if( _BC ) _F |= VF; \ +} + +/*************************************************************** + * CPI + ***************************************************************/ +#define CPI { \ + UINT8 val = RM(_HL); \ + UINT8 res = _A - val; \ + _HL++; _BC--; \ + _F = (_F & CF) | (SZ[res] & ~(YF|XF)) | ((_A ^ val ^ res) & HF) | NF; \ + if( _F & HF ) res -= 1; \ + if( res & 0x02 ) _F |= YF; /* bit 1 -> flag 5 */ \ + if( res & 0x08 ) _F |= XF; /* bit 3 -> flag 3 */ \ + if( _BC ) _F |= VF; \ +} + +/*************************************************************** + * INI + ***************************************************************/ +#define INI { \ + UINT8 io = IN(_BC); \ + _B--; \ + WM( _HL, io ); \ + _HL++; \ + _F = SZ[_B]; \ + if( io & SF ) _F |= NF; \ + if( (_C + io + 1) & 0x100 ) _F |= HF | CF; \ + if( (irep_tmp1[_C & 3][io & 3] ^ \ + breg_tmp2[_B] ^ \ + (_C >> 2) ^ \ + (io >> 2)) & 1 ) \ + _F |= PF; \ +} + +/*************************************************************** + * OUTI + ***************************************************************/ +#define OUTI { \ + UINT8 io = RM(_HL); \ + _B--; \ + OUT( _BC, io ); \ + _HL++; \ + _F = SZ[_B]; \ + if( io & SF ) _F |= NF; \ + if( (_C + io + 1) & 0x100 ) _F |= HF | CF; \ + if( (irep_tmp1[_C & 3][io & 3] ^ \ + breg_tmp2[_B] ^ \ + (_C >> 2) ^ \ + (io >> 2)) & 1 ) \ + _F |= PF; \ +} + +/*************************************************************** + * LDD + ***************************************************************/ +#define LDD { \ + UINT8 io = RM(_HL); \ + WM( _DE, io ); \ + _F &= SF | ZF | CF; \ + if( (_A + io) & 0x02 ) _F |= YF; /* bit 1 -> flag 5 */ \ + if( (_A + io) & 0x08 ) _F |= XF; /* bit 3 -> flag 3 */ \ + _HL--; _DE--; _BC--; \ + if( _BC ) _F |= VF; \ +} + +/*************************************************************** + * CPD + ***************************************************************/ +#define CPD { \ + UINT8 val = RM(_HL); \ + UINT8 res = _A - val; \ + _HL--; _BC--; \ + _F = (_F & CF) | (SZ[res] & ~(YF|XF)) | ((_A ^ val ^ res) & HF) | NF; \ + if( _F & HF ) res -= 1; \ + if( res & 0x02 ) _F |= YF; /* bit 1 -> flag 5 */ \ + if( res & 0x08 ) _F |= XF; /* bit 3 -> flag 3 */ \ + if( _BC ) _F |= VF; \ +} + +/*************************************************************** + * IND + ***************************************************************/ +#define IND { \ + UINT8 io = IN(_BC); \ + _B--; \ + WM( _HL, io ); \ + _HL--; \ + _F = SZ[_B]; \ + if( io & SF ) _F |= NF; \ + if( (_C + io - 1) & 0x100 ) _F |= HF | CF; \ + if( (drep_tmp1[_C & 3][io & 3] ^ \ + breg_tmp2[_B] ^ \ + (_C >> 2) ^ \ + (io >> 2)) & 1 ) \ + _F |= PF; \ +} + +/*************************************************************** + * OUTD + ***************************************************************/ +#define OUTD { \ + UINT8 io = RM(_HL); \ + _B--; \ + OUT( _BC, io ); \ + _HL--; \ + _F = SZ[_B]; \ + if( io & SF ) _F |= NF; \ + if( (_C + io - 1) & 0x100 ) _F |= HF | CF; \ + if( (drep_tmp1[_C & 3][io & 3] ^ \ + breg_tmp2[_B] ^ \ + (_C >> 2) ^ \ + (io >> 2)) & 1 ) \ + _F |= PF; \ +} + +/*************************************************************** + * LDIR + ***************************************************************/ +#define LDIR \ + LDI; \ + if( _BC ) \ + { \ + _PC -= 2; \ + CC(ex,0xb0); \ + } + +/*************************************************************** + * CPIR + ***************************************************************/ +#define CPIR \ + CPI; \ + if( _BC && !(_F & ZF) ) \ + { \ + _PC -= 2; \ + CC(ex,0xb1); \ + } + +/*************************************************************** + * INIR + ***************************************************************/ +#define INIR \ + INI; \ + if( _B ) \ + { \ + _PC -= 2; \ + CC(ex,0xb2); \ + } + +/*************************************************************** + * OTIR + ***************************************************************/ +#define OTIR \ + OUTI; \ + if( _B ) \ + { \ + _PC -= 2; \ + CC(ex,0xb3); \ + } + +/*************************************************************** + * LDDR + ***************************************************************/ +#define LDDR \ + LDD; \ + if( _BC ) \ + { \ + _PC -= 2; \ + CC(ex,0xb8); \ + } + +/*************************************************************** + * CPDR + ***************************************************************/ +#define CPDR \ + CPD; \ + if( _BC && !(_F & ZF) ) \ + { \ + _PC -= 2; \ + CC(ex,0xb9); \ + } + +/*************************************************************** + * INDR + ***************************************************************/ +#define INDR \ + IND; \ + if( _B ) \ + { \ + _PC -= 2; \ + CC(ex,0xba); \ + } + +/*************************************************************** + * OTDR + ***************************************************************/ +#define OTDR \ + OUTD; \ + if( _B ) \ + { \ + _PC -= 2; \ + CC(ex,0xbb); \ + } + +/*************************************************************** + * EI + ***************************************************************/ +#define EI { \ + m_IFF1 = m_IFF2 = 1; \ + m_after_EI = 1; \ +} + +/*************************************************************** + * TST n + ***************************************************************/ +#define TST(value) \ + _F = SZP[_A & value] | HF + +/*************************************************************** + * MLT rr + ***************************************************************/ +#define MLT(DR) { \ + m_##DR.w.l = m_##DR.b.l * m_##DR.b.h; \ +} + +/*************************************************************** + * OTIM + ***************************************************************/ +#define OTIM { \ + _B--; \ + OUT( _C, RM(_HL) ); \ + _HL++; \ + _C++; \ + _F = (_B) ? NF : NF | ZF; \ +} + +/*************************************************************** + * OTDM + ***************************************************************/ +#define OTDM { \ + _B--; \ + OUT( _C, RM(_HL) ); \ + _HL--; \ + _C--; \ + _F = (_B) ? NF : NF | ZF; \ +} + +/*************************************************************** + * OTIMR + ***************************************************************/ +#define OTIMR \ + OTIM; \ + if( _B ) \ + { \ + _PC -= 2; \ + CC(ex,0xb3); \ + } + +/*************************************************************** + * OTDMR + ***************************************************************/ +#define OTDMR \ + OTDM; \ + if( _B ) \ + { \ + _PC -= 2; \ + CC(ex,0xb3); \ + } + +/*************************************************************** + * OTDMR + ***************************************************************/ +#define SLP { \ + m_icount = 0; \ + m_HALT = 2; \ +} diff --git a/src/devices/cpu/z180/z180tbl.h b/src/devices/cpu/z180/z180tbl.h new file mode 100644 index 00000000000..4884992a5e3 --- /dev/null +++ b/src/devices/cpu/z180/z180tbl.h @@ -0,0 +1,232 @@ +// license:BSD-3-Clause +// copyright-holders:Juergen Buchmueller +/* tmp1 value for ini/inir/outi/otir for [C.1-0][io.1-0] */ +static const UINT8 irep_tmp1[4][4] = { + {0,0,1,0},{0,1,0,1},{1,0,1,1},{0,1,1,0} +}; + +/* tmp1 value for ind/indr/outd/otdr for [C.1-0][io.1-0] */ +static const UINT8 drep_tmp1[4][4] = { + {0,1,0,0},{1,0,0,1},{0,0,1,0},{0,1,0,1} +}; + +/* tmp2 value for all in/out repeated opcodes for B.7-0 */ +static const UINT8 breg_tmp2[256] = { + 0,0,1,1,0,1,0,0,1,1,0,0,1,0,1,1, + 0,1,0,0,1,0,1,1,0,0,1,1,0,1,0,0, + 1,1,0,0,1,0,1,1,0,0,1,1,0,1,0,0, + 1,0,1,1,0,1,0,0,1,1,0,0,1,0,1,1, + 0,1,0,0,1,0,1,1,0,0,1,1,0,1,0,0, + 1,0,1,1,0,1,0,0,1,1,0,0,1,0,1,1, + 0,0,1,1,0,1,0,0,1,1,0,0,1,0,1,1, + 0,1,0,0,1,0,1,1,0,0,1,1,0,1,0,0, + 1,1,0,0,1,0,1,1,0,0,1,1,0,1,0,0, + 1,0,1,1,0,1,0,0,1,1,0,0,1,0,1,1, + 0,0,1,1,0,1,0,0,1,1,0,0,1,0,1,1, + 0,1,0,0,1,0,1,1,0,0,1,1,0,1,0,0, + 1,0,1,1,0,1,0,0,1,1,0,0,1,0,1,1, + 0,1,0,0,1,0,1,1,0,0,1,1,0,1,0,0, + 1,1,0,0,1,0,1,1,0,0,1,1,0,1,0,0, + 1,0,1,1,0,1,0,0,1,1,0,0,1,0,1,1 +}; + +static const UINT8 cc_op[0x100] = { +/*-0 -1 -2 -3 -4 -5 -6 -7 -8 -9 -a -b -c -d -e -f */ + 3, 9, 7, 4, 4, 4, 6, 3, 4, 7, 6, 4, 4, 4, 6, 3, + 7, 9, 7, 4, 4, 4, 6, 3, 8, 7, 6, 4, 4, 4, 6, 3, + 6, 9,16, 4, 4, 4, 6, 4, 6, 7,15, 4, 4, 4, 6, 3, + 6, 9,13, 4,10,10, 9, 3, 6, 7,12, 4, 4, 4, 6, 3, + 4, 4, 4, 4, 4, 4, 6, 4, 4, 4, 4, 4, 4, 4, 6, 4, + 4, 4, 4, 4, 4, 4, 6, 4, 4, 4, 4, 4, 4, 4, 6, 4, + 4, 4, 4, 4, 4, 4, 6, 4, 4, 4, 4, 4, 4, 4, 6, 4, + 7, 7, 7, 7, 7, 7, 3, 7, 4, 4, 4, 4, 4, 4, 6, 4, + 4, 4, 4, 4, 4, 4, 6, 4, 4, 4, 4, 4, 4, 4, 6, 4, + 4, 4, 4, 4, 4, 4, 6, 4, 4, 4, 4, 4, 4, 4, 6, 4, + 4, 4, 4, 4, 4, 4, 6, 4, 4, 4, 4, 4, 4, 4, 6, 4, + 4, 4, 4, 4, 4, 4, 6, 4, 4, 4, 4, 4, 4, 4, 6, 4, + 5, 9, 6, 9, 6,11, 6,11, 5, 9, 6, 0, 6,16, 6,11, + 5, 9, 6,10, 6,11, 6,11, 5, 3, 6, 9, 6, 0, 6,11, + 5, 9, 6,16, 6,11, 6,11, 5, 3, 6, 3, 6, 0, 6,11, + 5, 9, 6, 3, 6,11, 6,11, 5, 4, 6, 3, 6, 0, 6,11 +}; + +static const UINT8 cc_cb[0x100] = { +/*-0 -1 -2 -3 -4 -5 -6 -7 -8 -9 -a -b -c -d -e -f */ + 7, 7, 7, 7, 7, 7,13, 7, 7, 7, 7, 7, 7, 7,13, 7, + 7, 7, 7, 7, 7, 7,13, 7, 7, 7, 7, 7, 7, 7,13, 7, + 7, 7, 7, 7, 7, 7,13, 7, 7, 7, 7, 7, 7, 7,13, 7, + 7, 7, 7, 7, 7, 7,13, 7, 7, 7, 7, 7, 7, 7,13, 7, + 6, 6, 6, 6, 6, 6, 9, 6, 6, 6, 6, 6, 6, 6, 9, 6, + 6, 6, 6, 6, 6, 6, 9, 6, 6, 6, 6, 6, 6, 6, 9, 6, + 6, 6, 6, 6, 6, 6, 9, 6, 6, 6, 6, 6, 6, 6, 9, 6, + 6, 6, 6, 6, 6, 6, 9, 6, 6, 6, 6, 6, 6, 6, 9, 6, + 7, 7, 7, 7, 7, 7,13, 7, 7, 7, 7, 7, 7, 7,13, 7, + 7, 7, 7, 7, 7, 7,13, 7, 7, 7, 7, 7, 7, 7,13, 7, + 7, 7, 7, 7, 7, 7,13, 7, 7, 7, 7, 7, 7, 7,13, 7, + 7, 7, 7, 7, 7, 7,13, 7, 7, 7, 7, 7, 7, 7,13, 7, + 7, 7, 7, 7, 7, 7,13, 7, 7, 7, 7, 7, 7, 7,13, 7, + 7, 7, 7, 7, 7, 7,13, 7, 7, 7, 7, 7, 7, 7,13, 7, + 7, 7, 7, 7, 7, 7,13, 7, 7, 7, 7, 7, 7, 7,13, 7, + 7, 7, 7, 7, 7, 7,13, 7, 7, 7, 7, 7, 7, 7,13, 7 +}; + +static const UINT8 cc_ed[0x100] = { +/*-0 -1 -2 -3 -4 -5 -6 -7 -8 -9 -a -b -c -d -e -f */ + 12,13, 6, 6, 9, 6, 6, 6,12,13, 6, 6, 9, 6, 6, 6, + 12,13, 6, 6, 9, 6, 6, 6,12,13, 6, 6, 9, 6, 6, 6, + 12,13, 6, 6, 9, 6, 6, 6,12,13, 6, 6,10, 6, 6, 6, + 12,13, 6, 6, 9, 6, 6, 6,12,13, 6, 6, 9, 6, 6, 6, + 9,10,10,19, 6,12, 6, 6, 9,10,10,18,17,12, 6, 6, + 9,10,10,19, 6,12, 6, 6, 9,10,10,18,17,12, 6, 6, + 9,10,10,19, 6,12, 6,16, 9,10,10,18,17,12, 6,16, + 9,10,10,19,12,12, 8, 6, 9,10,10,18,17,12, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 12,12,12,12, 6, 6, 6, 6,12,12,12,12, 6, 6, 6, 6, + 12,12,12,12, 6, 6, 6, 6,12,12,12,12, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6 +}; + +static const UINT8 cc_xy[0x100] = { +/*-0 -1 -2 -3 -4 -5 -6 -7 -8 -9 -a -b -c -d -e -f */ + 4, 4, 4, 4, 4, 4, 4, 4, 4,10, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4,10, 4, 4, 4, 4, 4, 4, + 4,12,19, 7, 9, 9,15, 4, 4,10,18, 7, 9, 9, 9, 4, + 4, 4, 4, 4,18,18,15, 4, 4,10, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 9, 9,14, 4, 4, 4, 4, 4, 9, 9,14, 4, + 4, 4, 4, 4, 9, 9,14, 4, 4, 4, 4, 4, 9, 9,14, 4, + 9, 9, 9, 9, 9, 9,14, 9, 9, 9, 9, 9, 9, 9,14, 9, + 15,15,15,15,15,15, 4,15, 4, 4, 4, 4, 9, 9,14, 4, + 4, 4, 4, 4, 9, 9,14, 4, 4, 4, 4, 4, 9, 9,14, 4, + 4, 4, 4, 4, 9, 9,14, 4, 4, 4, 4, 4, 9, 9,14, 4, + 4, 4, 4, 4, 9, 9,14, 4, 4, 4, 4, 4, 9, 9,14, 4, + 4, 4, 4, 4, 9, 9,14, 4, 4, 4, 4, 4, 9, 9,14, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4,12, 4,19, 4,14, 4, 4, 4, 6, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4 +}; + +static const UINT8 cc_xycb[0x100] = { +/*-0 -1 -2 -3 -4 -5 -6 -7 -8 -9 -a -b -c -d -e -f */ + 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15, + 15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15, + 15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15, + 15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15, + 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19 +}; + +/* extra cycles if jr/jp/call taken and 'interrupt latency' on rst 0-7 */ +static const UINT8 cc_ex[0x100] = { +/*-0 -1 -2 -3 -4 -5 -6 -7 -8 -9 -a -b -c -d -e -f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* DJNZ */ + 2, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, /* JR NZ/JR Z */ + 2, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, /* JR NC/JR C */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,10, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,10, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,10, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,10, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 4, 4, 4, 4, 0, 0, 0, 0, 4, 4, 4, 4, 0, 0, 0, 0, /* LDIR/CPIR/INIR/OTIR LDDR/CPDR/INDR/OTDR */ + 5, 0, 3, 0,10, 0, 0, 2, 5, 0, 3, 0,10, 0, 0, 2, + 5, 0, 3, 0,10, 0, 0, 2, 5, 0, 3, 0,10, 0, 0, 2, + 5, 0, 3, 0,10, 0, 0, 2, 5, 0, 3, 0,10, 0, 0, 2, + 5, 0, 3, 0,10, 0, 0, 2, 5, 0, 3, 0,10, 0, 0, 2 +}; + +static const UINT8 *const cc_default[6] = { cc_op, cc_cb, cc_ed, cc_xy, cc_xycb, cc_ex }; + +#define Z180_TABLE_dd Z180_TABLE_xy +#define Z180_TABLE_fd Z180_TABLE_xy + + +#define TABLE(prefix) {\ + &z180_device::prefix##_00,&z180_device::prefix##_01,&z180_device::prefix##_02,&z180_device::prefix##_03,&z180_device::prefix##_04,&z180_device::prefix##_05,&z180_device::prefix##_06,&z180_device::prefix##_07, \ + &z180_device::prefix##_08,&z180_device::prefix##_09,&z180_device::prefix##_0a,&z180_device::prefix##_0b,&z180_device::prefix##_0c,&z180_device::prefix##_0d,&z180_device::prefix##_0e,&z180_device::prefix##_0f, \ + &z180_device::prefix##_10,&z180_device::prefix##_11,&z180_device::prefix##_12,&z180_device::prefix##_13,&z180_device::prefix##_14,&z180_device::prefix##_15,&z180_device::prefix##_16,&z180_device::prefix##_17, \ + &z180_device::prefix##_18,&z180_device::prefix##_19,&z180_device::prefix##_1a,&z180_device::prefix##_1b,&z180_device::prefix##_1c,&z180_device::prefix##_1d,&z180_device::prefix##_1e,&z180_device::prefix##_1f, \ + &z180_device::prefix##_20,&z180_device::prefix##_21,&z180_device::prefix##_22,&z180_device::prefix##_23,&z180_device::prefix##_24,&z180_device::prefix##_25,&z180_device::prefix##_26,&z180_device::prefix##_27, \ + &z180_device::prefix##_28,&z180_device::prefix##_29,&z180_device::prefix##_2a,&z180_device::prefix##_2b,&z180_device::prefix##_2c,&z180_device::prefix##_2d,&z180_device::prefix##_2e,&z180_device::prefix##_2f, \ + &z180_device::prefix##_30,&z180_device::prefix##_31,&z180_device::prefix##_32,&z180_device::prefix##_33,&z180_device::prefix##_34,&z180_device::prefix##_35,&z180_device::prefix##_36,&z180_device::prefix##_37, \ + &z180_device::prefix##_38,&z180_device::prefix##_39,&z180_device::prefix##_3a,&z180_device::prefix##_3b,&z180_device::prefix##_3c,&z180_device::prefix##_3d,&z180_device::prefix##_3e,&z180_device::prefix##_3f, \ + &z180_device::prefix##_40,&z180_device::prefix##_41,&z180_device::prefix##_42,&z180_device::prefix##_43,&z180_device::prefix##_44,&z180_device::prefix##_45,&z180_device::prefix##_46,&z180_device::prefix##_47, \ + &z180_device::prefix##_48,&z180_device::prefix##_49,&z180_device::prefix##_4a,&z180_device::prefix##_4b,&z180_device::prefix##_4c,&z180_device::prefix##_4d,&z180_device::prefix##_4e,&z180_device::prefix##_4f, \ + &z180_device::prefix##_50,&z180_device::prefix##_51,&z180_device::prefix##_52,&z180_device::prefix##_53,&z180_device::prefix##_54,&z180_device::prefix##_55,&z180_device::prefix##_56,&z180_device::prefix##_57, \ + &z180_device::prefix##_58,&z180_device::prefix##_59,&z180_device::prefix##_5a,&z180_device::prefix##_5b,&z180_device::prefix##_5c,&z180_device::prefix##_5d,&z180_device::prefix##_5e,&z180_device::prefix##_5f, \ + &z180_device::prefix##_60,&z180_device::prefix##_61,&z180_device::prefix##_62,&z180_device::prefix##_63,&z180_device::prefix##_64,&z180_device::prefix##_65,&z180_device::prefix##_66,&z180_device::prefix##_67, \ + &z180_device::prefix##_68,&z180_device::prefix##_69,&z180_device::prefix##_6a,&z180_device::prefix##_6b,&z180_device::prefix##_6c,&z180_device::prefix##_6d,&z180_device::prefix##_6e,&z180_device::prefix##_6f, \ + &z180_device::prefix##_70,&z180_device::prefix##_71,&z180_device::prefix##_72,&z180_device::prefix##_73,&z180_device::prefix##_74,&z180_device::prefix##_75,&z180_device::prefix##_76,&z180_device::prefix##_77, \ + &z180_device::prefix##_78,&z180_device::prefix##_79,&z180_device::prefix##_7a,&z180_device::prefix##_7b,&z180_device::prefix##_7c,&z180_device::prefix##_7d,&z180_device::prefix##_7e,&z180_device::prefix##_7f, \ + &z180_device::prefix##_80,&z180_device::prefix##_81,&z180_device::prefix##_82,&z180_device::prefix##_83,&z180_device::prefix##_84,&z180_device::prefix##_85,&z180_device::prefix##_86,&z180_device::prefix##_87, \ + &z180_device::prefix##_88,&z180_device::prefix##_89,&z180_device::prefix##_8a,&z180_device::prefix##_8b,&z180_device::prefix##_8c,&z180_device::prefix##_8d,&z180_device::prefix##_8e,&z180_device::prefix##_8f, \ + &z180_device::prefix##_90,&z180_device::prefix##_91,&z180_device::prefix##_92,&z180_device::prefix##_93,&z180_device::prefix##_94,&z180_device::prefix##_95,&z180_device::prefix##_96,&z180_device::prefix##_97, \ + &z180_device::prefix##_98,&z180_device::prefix##_99,&z180_device::prefix##_9a,&z180_device::prefix##_9b,&z180_device::prefix##_9c,&z180_device::prefix##_9d,&z180_device::prefix##_9e,&z180_device::prefix##_9f, \ + &z180_device::prefix##_a0,&z180_device::prefix##_a1,&z180_device::prefix##_a2,&z180_device::prefix##_a3,&z180_device::prefix##_a4,&z180_device::prefix##_a5,&z180_device::prefix##_a6,&z180_device::prefix##_a7, \ + &z180_device::prefix##_a8,&z180_device::prefix##_a9,&z180_device::prefix##_aa,&z180_device::prefix##_ab,&z180_device::prefix##_ac,&z180_device::prefix##_ad,&z180_device::prefix##_ae,&z180_device::prefix##_af, \ + &z180_device::prefix##_b0,&z180_device::prefix##_b1,&z180_device::prefix##_b2,&z180_device::prefix##_b3,&z180_device::prefix##_b4,&z180_device::prefix##_b5,&z180_device::prefix##_b6,&z180_device::prefix##_b7, \ + &z180_device::prefix##_b8,&z180_device::prefix##_b9,&z180_device::prefix##_ba,&z180_device::prefix##_bb,&z180_device::prefix##_bc,&z180_device::prefix##_bd,&z180_device::prefix##_be,&z180_device::prefix##_bf, \ + &z180_device::prefix##_c0,&z180_device::prefix##_c1,&z180_device::prefix##_c2,&z180_device::prefix##_c3,&z180_device::prefix##_c4,&z180_device::prefix##_c5,&z180_device::prefix##_c6,&z180_device::prefix##_c7, \ + &z180_device::prefix##_c8,&z180_device::prefix##_c9,&z180_device::prefix##_ca,&z180_device::prefix##_cb,&z180_device::prefix##_cc,&z180_device::prefix##_cd,&z180_device::prefix##_ce,&z180_device::prefix##_cf, \ + &z180_device::prefix##_d0,&z180_device::prefix##_d1,&z180_device::prefix##_d2,&z180_device::prefix##_d3,&z180_device::prefix##_d4,&z180_device::prefix##_d5,&z180_device::prefix##_d6,&z180_device::prefix##_d7, \ + &z180_device::prefix##_d8,&z180_device::prefix##_d9,&z180_device::prefix##_da,&z180_device::prefix##_db,&z180_device::prefix##_dc,&z180_device::prefix##_dd,&z180_device::prefix##_de,&z180_device::prefix##_df, \ + &z180_device::prefix##_e0,&z180_device::prefix##_e1,&z180_device::prefix##_e2,&z180_device::prefix##_e3,&z180_device::prefix##_e4,&z180_device::prefix##_e5,&z180_device::prefix##_e6,&z180_device::prefix##_e7, \ + &z180_device::prefix##_e8,&z180_device::prefix##_e9,&z180_device::prefix##_ea,&z180_device::prefix##_eb,&z180_device::prefix##_ec,&z180_device::prefix##_ed,&z180_device::prefix##_ee,&z180_device::prefix##_ef, \ + &z180_device::prefix##_f0,&z180_device::prefix##_f1,&z180_device::prefix##_f2,&z180_device::prefix##_f3,&z180_device::prefix##_f4,&z180_device::prefix##_f5,&z180_device::prefix##_f6,&z180_device::prefix##_f7, \ + &z180_device::prefix##_f8,&z180_device::prefix##_f9,&z180_device::prefix##_fa,&z180_device::prefix##_fb,&z180_device::prefix##_fc,&z180_device::prefix##_fd,&z180_device::prefix##_fe,&z180_device::prefix##_ff \ +} + + +const z180_device::opcode_func z180_device::s_z180ops[Z180_PREFIX_COUNT][0x100] = +{ + TABLE(op), + TABLE(cb), + TABLE(dd), + TABLE(ed), + TABLE(fd), + TABLE(xycb) +}; + +/*************************************************************** + * define an opcode function + ***************************************************************/ +#define OP(prefix,opcode) void z180_device::prefix##_##opcode() + +/*************************************************************** + * adjust cycle count by n T-states + ***************************************************************/ +#define CC(prefix,opcode) m_extra_cycles += m_cc[Z180_TABLE_##prefix][opcode] + +/*************************************************************** + * execute an opcode + ***************************************************************/ + +#define EXEC_PROTOTYPE(prefix) \ +int z180_device::exec##_##prefix(const UINT8 opcode) \ +{ \ + (this->*s_z180ops[Z180_PREFIX_##prefix][opcode])(); \ + return m_cc[Z180_TABLE_##prefix][opcode]; \ +} + +EXEC_PROTOTYPE(op) +EXEC_PROTOTYPE(cb) +EXEC_PROTOTYPE(dd) +EXEC_PROTOTYPE(ed) +EXEC_PROTOTYPE(fd) +EXEC_PROTOTYPE(xycb) diff --git a/src/devices/cpu/z180/z180xy.inc b/src/devices/cpu/z180/z180xy.inc new file mode 100644 index 00000000000..e8976079dfd --- /dev/null +++ b/src/devices/cpu/z180/z180xy.inc @@ -0,0 +1,293 @@ +// license:BSD-3-Clause +// copyright-holders:Juergen Buchmueller +/********************************************************** +* opcodes with DD/FD CB prefix +* rotate, shift and bit operations with (IX+o) +**********************************************************/ +OP(xycb,00) { _B = RLC(RM(m_ea) ); WM( m_ea,_B ); } /* RLC B=(XY+o) */ +OP(xycb,01) { _C = RLC(RM(m_ea) ); WM( m_ea,_C ); } /* RLC C=(XY+o) */ +OP(xycb,02) { _D = RLC(RM(m_ea) ); WM( m_ea,_D ); } /* RLC D=(XY+o) */ +OP(xycb,03) { _E = RLC(RM(m_ea) ); WM( m_ea,_E ); } /* RLC E=(XY+o) */ +OP(xycb,04) { _H = RLC(RM(m_ea) ); WM( m_ea,_H ); } /* RLC H=(XY+o) */ +OP(xycb,05) { _L = RLC(RM(m_ea) ); WM( m_ea,_L ); } /* RLC L=(XY+o) */ +OP(xycb,06) { WM( m_ea, RLC(RM(m_ea) ) ); } /* RLC (XY+o) */ +OP(xycb,07) { _A = RLC(RM(m_ea) ); WM( m_ea,_A ); } /* RLC A=(XY+o) */ + +OP(xycb,08) { _B = RRC(RM(m_ea) ); WM( m_ea,_B ); } /* RRC B=(XY+o) */ +OP(xycb,09) { _C = RRC(RM(m_ea) ); WM( m_ea,_C ); } /* RRC C=(XY+o) */ +OP(xycb,0a) { _D = RRC(RM(m_ea) ); WM( m_ea,_D ); } /* RRC D=(XY+o) */ +OP(xycb,0b) { _E = RRC(RM(m_ea) ); WM( m_ea,_E ); } /* RRC E=(XY+o) */ +OP(xycb,0c) { _H = RRC(RM(m_ea) ); WM( m_ea,_H ); } /* RRC H=(XY+o) */ +OP(xycb,0d) { _L = RRC(RM(m_ea) ); WM( m_ea,_L ); } /* RRC L=(XY+o) */ +OP(xycb,0e) { WM( m_ea,RRC(RM(m_ea) ) ); } /* RRC (XY+o) */ +OP(xycb,0f) { _A = RRC(RM(m_ea) ); WM( m_ea,_A ); } /* RRC A=(XY+o) */ + +OP(xycb,10) { _B = RL(RM(m_ea) ); WM( m_ea,_B ); } /* RL B=(XY+o) */ +OP(xycb,11) { _C = RL(RM(m_ea) ); WM( m_ea,_C ); } /* RL C=(XY+o) */ +OP(xycb,12) { _D = RL(RM(m_ea) ); WM( m_ea,_D ); } /* RL D=(XY+o) */ +OP(xycb,13) { _E = RL(RM(m_ea) ); WM( m_ea,_E ); } /* RL E=(XY+o) */ +OP(xycb,14) { _H = RL(RM(m_ea) ); WM( m_ea,_H ); } /* RL H=(XY+o) */ +OP(xycb,15) { _L = RL(RM(m_ea) ); WM( m_ea,_L ); } /* RL L=(XY+o) */ +OP(xycb,16) { WM( m_ea,RL(RM(m_ea) ) ); } /* RL (XY+o) */ +OP(xycb,17) { _A = RL(RM(m_ea) ); WM( m_ea,_A ); } /* RL A=(XY+o) */ + +OP(xycb,18) { _B = RR(RM(m_ea) ); WM( m_ea,_B ); } /* RR B=(XY+o) */ +OP(xycb,19) { _C = RR(RM(m_ea) ); WM( m_ea,_C ); } /* RR C=(XY+o) */ +OP(xycb,1a) { _D = RR(RM(m_ea) ); WM( m_ea,_D ); } /* RR D=(XY+o) */ +OP(xycb,1b) { _E = RR(RM(m_ea) ); WM( m_ea,_E ); } /* RR E=(XY+o) */ +OP(xycb,1c) { _H = RR(RM(m_ea) ); WM( m_ea,_H ); } /* RR H=(XY+o) */ +OP(xycb,1d) { _L = RR(RM(m_ea) ); WM( m_ea,_L ); } /* RR L=(XY+o) */ +OP(xycb,1e) { WM( m_ea,RR(RM(m_ea) ) ); } /* RR (XY+o) */ +OP(xycb,1f) { _A = RR(RM(m_ea) ); WM( m_ea,_A ); } /* RR A=(XY+o) */ + +OP(xycb,20) { _B = SLA(RM(m_ea) ); WM( m_ea,_B ); } /* SLA B=(XY+o) */ +OP(xycb,21) { _C = SLA(RM(m_ea) ); WM( m_ea,_C ); } /* SLA C=(XY+o) */ +OP(xycb,22) { _D = SLA(RM(m_ea) ); WM( m_ea,_D ); } /* SLA D=(XY+o) */ +OP(xycb,23) { _E = SLA(RM(m_ea) ); WM( m_ea,_E ); } /* SLA E=(XY+o) */ +OP(xycb,24) { _H = SLA(RM(m_ea) ); WM( m_ea,_H ); } /* SLA H=(XY+o) */ +OP(xycb,25) { _L = SLA(RM(m_ea) ); WM( m_ea,_L ); } /* SLA L=(XY+o) */ +OP(xycb,26) { WM( m_ea,SLA(RM(m_ea) ) ); } /* SLA (XY+o) */ +OP(xycb,27) { _A = SLA(RM(m_ea) ); WM( m_ea,_A ); } /* SLA A=(XY+o) */ + +OP(xycb,28) { _B = SRA(RM(m_ea) ); WM( m_ea,_B ); } /* SRA B=(XY+o) */ +OP(xycb,29) { _C = SRA(RM(m_ea) ); WM( m_ea,_C ); } /* SRA C=(XY+o) */ +OP(xycb,2a) { _D = SRA(RM(m_ea) ); WM( m_ea,_D ); } /* SRA D=(XY+o) */ +OP(xycb,2b) { _E = SRA(RM(m_ea) ); WM( m_ea,_E ); } /* SRA E=(XY+o) */ +OP(xycb,2c) { _H = SRA(RM(m_ea) ); WM( m_ea,_H ); } /* SRA H=(XY+o) */ +OP(xycb,2d) { _L = SRA(RM(m_ea) ); WM( m_ea,_L ); } /* SRA L=(XY+o) */ +OP(xycb,2e) { WM( m_ea,SRA(RM(m_ea) ) ); } /* SRA (XY+o) */ +OP(xycb,2f) { _A = SRA(RM(m_ea) ); WM( m_ea,_A ); } /* SRA A=(XY+o) */ + +OP(xycb,30) { _B = SLL(RM(m_ea) ); WM( m_ea,_B ); } /* SLL B=(XY+o) */ +OP(xycb,31) { _C = SLL(RM(m_ea) ); WM( m_ea,_C ); } /* SLL C=(XY+o) */ +OP(xycb,32) { _D = SLL(RM(m_ea) ); WM( m_ea,_D ); } /* SLL D=(XY+o) */ +OP(xycb,33) { _E = SLL(RM(m_ea) ); WM( m_ea,_E ); } /* SLL E=(XY+o) */ +OP(xycb,34) { _H = SLL(RM(m_ea) ); WM( m_ea,_H ); } /* SLL H=(XY+o) */ +OP(xycb,35) { _L = SLL(RM(m_ea) ); WM( m_ea,_L ); } /* SLL L=(XY+o) */ +OP(xycb,36) { WM( m_ea,SLL(RM(m_ea) ) ); } /* SLL (XY+o) */ +OP(xycb,37) { _A = SLL(RM(m_ea) ); WM( m_ea,_A ); } /* SLL A=(XY+o) */ + +OP(xycb,38) { _B = SRL(RM(m_ea) ); WM( m_ea,_B ); } /* SRL B=(XY+o) */ +OP(xycb,39) { _C = SRL(RM(m_ea) ); WM( m_ea,_C ); } /* SRL C=(XY+o) */ +OP(xycb,3a) { _D = SRL(RM(m_ea) ); WM( m_ea,_D ); } /* SRL D=(XY+o) */ +OP(xycb,3b) { _E = SRL(RM(m_ea) ); WM( m_ea,_E ); } /* SRL E=(XY+o) */ +OP(xycb,3c) { _H = SRL(RM(m_ea) ); WM( m_ea,_H ); } /* SRL H=(XY+o) */ +OP(xycb,3d) { _L = SRL(RM(m_ea) ); WM( m_ea,_L ); } /* SRL L=(XY+o) */ +OP(xycb,3e) { WM( m_ea,SRL(RM(m_ea) ) ); } /* SRL (XY+o) */ +OP(xycb,3f) { _A = SRL(RM(m_ea) ); WM( m_ea,_A ); } /* SRL A=(XY+o) */ + +OP(xycb,40) { xycb_46(); } /* BIT 0,B=(XY+o) */ +OP(xycb,41) { xycb_46(); } /* BIT 0,C=(XY+o) */ +OP(xycb,42) { xycb_46(); } /* BIT 0,D=(XY+o) */ +OP(xycb,43) { xycb_46(); } /* BIT 0,E=(XY+o) */ +OP(xycb,44) { xycb_46(); } /* BIT 0,H=(XY+o) */ +OP(xycb,45) { xycb_46(); } /* BIT 0,L=(XY+o) */ +OP(xycb,46) { BIT_XY(0,RM(m_ea)); } /* BIT 0,(XY+o) */ +OP(xycb,47) { xycb_46(); } /* BIT 0,A=(XY+o) */ + +OP(xycb,48) { xycb_4e(); } /* BIT 1,B=(XY+o) */ +OP(xycb,49) { xycb_4e(); } /* BIT 1,C=(XY+o) */ +OP(xycb,4a) { xycb_4e(); } /* BIT 1,D=(XY+o) */ +OP(xycb,4b) { xycb_4e(); } /* BIT 1,E=(XY+o) */ +OP(xycb,4c) { xycb_4e(); } /* BIT 1,H=(XY+o) */ +OP(xycb,4d) { xycb_4e(); } /* BIT 1,L=(XY+o) */ +OP(xycb,4e) { BIT_XY(1,RM(m_ea)); } /* BIT 1,(XY+o) */ +OP(xycb,4f) { xycb_4e(); } /* BIT 1,A=(XY+o) */ + +OP(xycb,50) { xycb_56(); } /* BIT 2,B=(XY+o) */ +OP(xycb,51) { xycb_56(); } /* BIT 2,C=(XY+o) */ +OP(xycb,52) { xycb_56(); } /* BIT 2,D=(XY+o) */ +OP(xycb,53) { xycb_56(); } /* BIT 2,E=(XY+o) */ +OP(xycb,54) { xycb_56(); } /* BIT 2,H=(XY+o) */ +OP(xycb,55) { xycb_56(); } /* BIT 2,L=(XY+o) */ +OP(xycb,56) { BIT_XY(2,RM(m_ea)); } /* BIT 2,(XY+o) */ +OP(xycb,57) { xycb_56(); } /* BIT 2,A=(XY+o) */ + +OP(xycb,58) { xycb_5e(); } /* BIT 3,B=(XY+o) */ +OP(xycb,59) { xycb_5e(); } /* BIT 3,C=(XY+o) */ +OP(xycb,5a) { xycb_5e(); } /* BIT 3,D=(XY+o) */ +OP(xycb,5b) { xycb_5e(); } /* BIT 3,E=(XY+o) */ +OP(xycb,5c) { xycb_5e(); } /* BIT 3,H=(XY+o) */ +OP(xycb,5d) { xycb_5e(); } /* BIT 3,L=(XY+o) */ +OP(xycb,5e) { BIT_XY(3,RM(m_ea)); } /* BIT 3,(XY+o) */ +OP(xycb,5f) { xycb_5e(); } /* BIT 3,A=(XY+o) */ + +OP(xycb,60) { xycb_66(); } /* BIT 4,B=(XY+o) */ +OP(xycb,61) { xycb_66(); } /* BIT 4,C=(XY+o) */ +OP(xycb,62) { xycb_66(); } /* BIT 4,D=(XY+o) */ +OP(xycb,63) { xycb_66(); } /* BIT 4,E=(XY+o) */ +OP(xycb,64) { xycb_66(); } /* BIT 4,H=(XY+o) */ +OP(xycb,65) { xycb_66(); } /* BIT 4,L=(XY+o) */ +OP(xycb,66) { BIT_XY(4,RM(m_ea)); } /* BIT 4,(XY+o) */ +OP(xycb,67) { xycb_66(); } /* BIT 4,A=(XY+o) */ + +OP(xycb,68) { xycb_6e(); } /* BIT 5,B=(XY+o) */ +OP(xycb,69) { xycb_6e(); } /* BIT 5,C=(XY+o) */ +OP(xycb,6a) { xycb_6e(); } /* BIT 5,D=(XY+o) */ +OP(xycb,6b) { xycb_6e(); } /* BIT 5,E=(XY+o) */ +OP(xycb,6c) { xycb_6e(); } /* BIT 5,H=(XY+o) */ +OP(xycb,6d) { xycb_6e(); } /* BIT 5,L=(XY+o) */ +OP(xycb,6e) { BIT_XY(5,RM(m_ea)); } /* BIT 5,(XY+o) */ +OP(xycb,6f) { xycb_6e(); } /* BIT 5,A=(XY+o) */ + +OP(xycb,70) { xycb_76(); } /* BIT 6,B=(XY+o) */ +OP(xycb,71) { xycb_76(); } /* BIT 6,C=(XY+o) */ +OP(xycb,72) { xycb_76(); } /* BIT 6,D=(XY+o) */ +OP(xycb,73) { xycb_76(); } /* BIT 6,E=(XY+o) */ +OP(xycb,74) { xycb_76(); } /* BIT 6,H=(XY+o) */ +OP(xycb,75) { xycb_76(); } /* BIT 6,L=(XY+o) */ +OP(xycb,76) { BIT_XY(6,RM(m_ea)); } /* BIT 6,(XY+o) */ +OP(xycb,77) { xycb_76(); } /* BIT 6,A=(XY+o) */ + +OP(xycb,78) { xycb_7e(); } /* BIT 7,B=(XY+o) */ +OP(xycb,79) { xycb_7e(); } /* BIT 7,C=(XY+o) */ +OP(xycb,7a) { xycb_7e(); } /* BIT 7,D=(XY+o) */ +OP(xycb,7b) { xycb_7e(); } /* BIT 7,E=(XY+o) */ +OP(xycb,7c) { xycb_7e(); } /* BIT 7,H=(XY+o) */ +OP(xycb,7d) { xycb_7e(); } /* BIT 7,L=(XY+o) */ +OP(xycb,7e) { BIT_XY(7,RM(m_ea)); } /* BIT 7,(XY+o) */ +OP(xycb,7f) { xycb_7e(); } /* BIT 7,A=(XY+o) */ + +OP(xycb,80) { _B = RES(0, RM(m_ea) ); WM( m_ea,_B ); } /* RES 0,B=(XY+o) */ +OP(xycb,81) { _C = RES(0, RM(m_ea) ); WM( m_ea,_C ); } /* RES 0,C=(XY+o) */ +OP(xycb,82) { _D = RES(0, RM(m_ea) ); WM( m_ea,_D ); } /* RES 0,D=(XY+o) */ +OP(xycb,83) { _E = RES(0, RM(m_ea) ); WM( m_ea,_E ); } /* RES 0,E=(XY+o) */ +OP(xycb,84) { _H = RES(0, RM(m_ea) ); WM( m_ea,_H ); } /* RES 0,H=(XY+o) */ +OP(xycb,85) { _L = RES(0, RM(m_ea) ); WM( m_ea,_L ); } /* RES 0,L=(XY+o) */ +OP(xycb,86) { WM( m_ea, RES(0,RM(m_ea)) ); } /* RES 0,(XY+o) */ +OP(xycb,87) { _A = RES(0, RM(m_ea) ); WM( m_ea,_A ); } /* RES 0,A=(XY+o) */ + +OP(xycb,88) { _B = RES(1, RM(m_ea) ); WM( m_ea,_B ); } /* RES 1,B=(XY+o) */ +OP(xycb,89) { _C = RES(1, RM(m_ea) ); WM( m_ea,_C ); } /* RES 1,C=(XY+o) */ +OP(xycb,8a) { _D = RES(1, RM(m_ea) ); WM( m_ea,_D ); } /* RES 1,D=(XY+o) */ +OP(xycb,8b) { _E = RES(1, RM(m_ea) ); WM( m_ea,_E ); } /* RES 1,E=(XY+o) */ +OP(xycb,8c) { _H = RES(1, RM(m_ea) ); WM( m_ea,_H ); } /* RES 1,H=(XY+o) */ +OP(xycb,8d) { _L = RES(1, RM(m_ea) ); WM( m_ea,_L ); } /* RES 1,L=(XY+o) */ +OP(xycb,8e) { WM( m_ea, RES(1,RM(m_ea)) ); } /* RES 1,(XY+o) */ +OP(xycb,8f) { _A = RES(1, RM(m_ea) ); WM( m_ea,_A ); } /* RES 1,A=(XY+o) */ + +OP(xycb,90) { _B = RES(2, RM(m_ea) ); WM( m_ea,_B ); } /* RES 2,B=(XY+o) */ +OP(xycb,91) { _C = RES(2, RM(m_ea) ); WM( m_ea,_C ); } /* RES 2,C=(XY+o) */ +OP(xycb,92) { _D = RES(2, RM(m_ea) ); WM( m_ea,_D ); } /* RES 2,D=(XY+o) */ +OP(xycb,93) { _E = RES(2, RM(m_ea) ); WM( m_ea,_E ); } /* RES 2,E=(XY+o) */ +OP(xycb,94) { _H = RES(2, RM(m_ea) ); WM( m_ea,_H ); } /* RES 2,H=(XY+o) */ +OP(xycb,95) { _L = RES(2, RM(m_ea) ); WM( m_ea,_L ); } /* RES 2,L=(XY+o) */ +OP(xycb,96) { WM( m_ea, RES(2,RM(m_ea)) ); } /* RES 2,(XY+o) */ +OP(xycb,97) { _A = RES(2, RM(m_ea) ); WM( m_ea,_A ); } /* RES 2,A=(XY+o) */ + +OP(xycb,98) { _B = RES(3, RM(m_ea) ); WM( m_ea,_B ); } /* RES 3,B=(XY+o) */ +OP(xycb,99) { _C = RES(3, RM(m_ea) ); WM( m_ea,_C ); } /* RES 3,C=(XY+o) */ +OP(xycb,9a) { _D = RES(3, RM(m_ea) ); WM( m_ea,_D ); } /* RES 3,D=(XY+o) */ +OP(xycb,9b) { _E = RES(3, RM(m_ea) ); WM( m_ea,_E ); } /* RES 3,E=(XY+o) */ +OP(xycb,9c) { _H = RES(3, RM(m_ea) ); WM( m_ea,_H ); } /* RES 3,H=(XY+o) */ +OP(xycb,9d) { _L = RES(3, RM(m_ea) ); WM( m_ea,_L ); } /* RES 3,L=(XY+o) */ +OP(xycb,9e) { WM( m_ea, RES(3,RM(m_ea)) ); } /* RES 3,(XY+o) */ +OP(xycb,9f) { _A = RES(3, RM(m_ea) ); WM( m_ea,_A ); } /* RES 3,A=(XY+o) */ + +OP(xycb,a0) { _B = RES(4, RM(m_ea) ); WM( m_ea,_B ); } /* RES 4,B=(XY+o) */ +OP(xycb,a1) { _C = RES(4, RM(m_ea) ); WM( m_ea,_C ); } /* RES 4,C=(XY+o) */ +OP(xycb,a2) { _D = RES(4, RM(m_ea) ); WM( m_ea,_D ); } /* RES 4,D=(XY+o) */ +OP(xycb,a3) { _E = RES(4, RM(m_ea) ); WM( m_ea,_E ); } /* RES 4,E=(XY+o) */ +OP(xycb,a4) { _H = RES(4, RM(m_ea) ); WM( m_ea,_H ); } /* RES 4,H=(XY+o) */ +OP(xycb,a5) { _L = RES(4, RM(m_ea) ); WM( m_ea,_L ); } /* RES 4,L=(XY+o) */ +OP(xycb,a6) { WM( m_ea, RES(4,RM(m_ea)) ); } /* RES 4,(XY+o) */ +OP(xycb,a7) { _A = RES(4, RM(m_ea) ); WM( m_ea,_A ); } /* RES 4,A=(XY+o) */ + +OP(xycb,a8) { _B = RES(5, RM(m_ea) ); WM( m_ea,_B ); } /* RES 5,B=(XY+o) */ +OP(xycb,a9) { _C = RES(5, RM(m_ea) ); WM( m_ea,_C ); } /* RES 5,C=(XY+o) */ +OP(xycb,aa) { _D = RES(5, RM(m_ea) ); WM( m_ea,_D ); } /* RES 5,D=(XY+o) */ +OP(xycb,ab) { _E = RES(5, RM(m_ea) ); WM( m_ea,_E ); } /* RES 5,E=(XY+o) */ +OP(xycb,ac) { _H = RES(5, RM(m_ea) ); WM( m_ea,_H ); } /* RES 5,H=(XY+o) */ +OP(xycb,ad) { _L = RES(5, RM(m_ea) ); WM( m_ea,_L ); } /* RES 5,L=(XY+o) */ +OP(xycb,ae) { WM( m_ea, RES(5,RM(m_ea)) ); } /* RES 5,(XY+o) */ +OP(xycb,af) { _A = RES(5, RM(m_ea) ); WM( m_ea,_A ); } /* RES 5,A=(XY+o) */ + +OP(xycb,b0) { _B = RES(6, RM(m_ea) ); WM( m_ea,_B ); } /* RES 6,B=(XY+o) */ +OP(xycb,b1) { _C = RES(6, RM(m_ea) ); WM( m_ea,_C ); } /* RES 6,C=(XY+o) */ +OP(xycb,b2) { _D = RES(6, RM(m_ea) ); WM( m_ea,_D ); } /* RES 6,D=(XY+o) */ +OP(xycb,b3) { _E = RES(6, RM(m_ea) ); WM( m_ea,_E ); } /* RES 6,E=(XY+o) */ +OP(xycb,b4) { _H = RES(6, RM(m_ea) ); WM( m_ea,_H ); } /* RES 6,H=(XY+o) */ +OP(xycb,b5) { _L = RES(6, RM(m_ea) ); WM( m_ea,_L ); } /* RES 6,L=(XY+o) */ +OP(xycb,b6) { WM( m_ea, RES(6,RM(m_ea)) ); } /* RES 6,(XY+o) */ +OP(xycb,b7) { _A = RES(6, RM(m_ea) ); WM( m_ea,_A ); } /* RES 6,A=(XY+o) */ + +OP(xycb,b8) { _B = RES(7, RM(m_ea) ); WM( m_ea,_B ); } /* RES 7,B=(XY+o) */ +OP(xycb,b9) { _C = RES(7, RM(m_ea) ); WM( m_ea,_C ); } /* RES 7,C=(XY+o) */ +OP(xycb,ba) { _D = RES(7, RM(m_ea) ); WM( m_ea,_D ); } /* RES 7,D=(XY+o) */ +OP(xycb,bb) { _E = RES(7, RM(m_ea) ); WM( m_ea,_E ); } /* RES 7,E=(XY+o) */ +OP(xycb,bc) { _H = RES(7, RM(m_ea) ); WM( m_ea,_H ); } /* RES 7,H=(XY+o) */ +OP(xycb,bd) { _L = RES(7, RM(m_ea) ); WM( m_ea,_L ); } /* RES 7,L=(XY+o) */ +OP(xycb,be) { WM( m_ea, RES(7,RM(m_ea)) ); } /* RES 7,(XY+o) */ +OP(xycb,bf) { _A = RES(7, RM(m_ea) ); WM( m_ea,_A ); } /* RES 7,A=(XY+o) */ + +OP(xycb,c0) { _B = SET(0, RM(m_ea) ); WM( m_ea,_B ); } /* SET 0,B=(XY+o) */ +OP(xycb,c1) { _C = SET(0, RM(m_ea) ); WM( m_ea,_C ); } /* SET 0,C=(XY+o) */ +OP(xycb,c2) { _D = SET(0, RM(m_ea) ); WM( m_ea,_D ); } /* SET 0,D=(XY+o) */ +OP(xycb,c3) { _E = SET(0, RM(m_ea) ); WM( m_ea,_E ); } /* SET 0,E=(XY+o) */ +OP(xycb,c4) { _H = SET(0, RM(m_ea) ); WM( m_ea,_H ); } /* SET 0,H=(XY+o) */ +OP(xycb,c5) { _L = SET(0, RM(m_ea) ); WM( m_ea,_L ); } /* SET 0,L=(XY+o) */ +OP(xycb,c6) { WM( m_ea, SET(0,RM(m_ea)) ); } /* SET 0,(XY+o) */ +OP(xycb,c7) { _A = SET(0, RM(m_ea) ); WM( m_ea,_A ); } /* SET 0,A=(XY+o) */ + +OP(xycb,c8) { _B = SET(1, RM(m_ea) ); WM( m_ea,_B ); } /* SET 1,B=(XY+o) */ +OP(xycb,c9) { _C = SET(1, RM(m_ea) ); WM( m_ea,_C ); } /* SET 1,C=(XY+o) */ +OP(xycb,ca) { _D = SET(1, RM(m_ea) ); WM( m_ea,_D ); } /* SET 1,D=(XY+o) */ +OP(xycb,cb) { _E = SET(1, RM(m_ea) ); WM( m_ea,_E ); } /* SET 1,E=(XY+o) */ +OP(xycb,cc) { _H = SET(1, RM(m_ea) ); WM( m_ea,_H ); } /* SET 1,H=(XY+o) */ +OP(xycb,cd) { _L = SET(1, RM(m_ea) ); WM( m_ea,_L ); } /* SET 1,L=(XY+o) */ +OP(xycb,ce) { WM( m_ea, SET(1,RM(m_ea)) ); } /* SET 1,(XY+o) */ +OP(xycb,cf) { _A = SET(1, RM(m_ea) ); WM( m_ea,_A ); } /* SET 1,A=(XY+o) */ + +OP(xycb,d0) { _B = SET(2, RM(m_ea) ); WM( m_ea,_B ); } /* SET 2,B=(XY+o) */ +OP(xycb,d1) { _C = SET(2, RM(m_ea) ); WM( m_ea,_C ); } /* SET 2,C=(XY+o) */ +OP(xycb,d2) { _D = SET(2, RM(m_ea) ); WM( m_ea,_D ); } /* SET 2,D=(XY+o) */ +OP(xycb,d3) { _E = SET(2, RM(m_ea) ); WM( m_ea,_E ); } /* SET 2,E=(XY+o) */ +OP(xycb,d4) { _H = SET(2, RM(m_ea) ); WM( m_ea,_H ); } /* SET 2,H=(XY+o) */ +OP(xycb,d5) { _L = SET(2, RM(m_ea) ); WM( m_ea,_L ); } /* SET 2,L=(XY+o) */ +OP(xycb,d6) { WM( m_ea, SET(2,RM(m_ea)) ); } /* SET 2,(XY+o) */ +OP(xycb,d7) { _A = SET(2, RM(m_ea) ); WM( m_ea,_A ); } /* SET 2,A=(XY+o) */ + +OP(xycb,d8) { _B = SET(3, RM(m_ea) ); WM( m_ea,_B ); } /* SET 3,B=(XY+o) */ +OP(xycb,d9) { _C = SET(3, RM(m_ea) ); WM( m_ea,_C ); } /* SET 3,C=(XY+o) */ +OP(xycb,da) { _D = SET(3, RM(m_ea) ); WM( m_ea,_D ); } /* SET 3,D=(XY+o) */ +OP(xycb,db) { _E = SET(3, RM(m_ea) ); WM( m_ea,_E ); } /* SET 3,E=(XY+o) */ +OP(xycb,dc) { _H = SET(3, RM(m_ea) ); WM( m_ea,_H ); } /* SET 3,H=(XY+o) */ +OP(xycb,dd) { _L = SET(3, RM(m_ea) ); WM( m_ea,_L ); } /* SET 3,L=(XY+o) */ +OP(xycb,de) { WM( m_ea, SET(3,RM(m_ea)) ); } /* SET 3,(XY+o) */ +OP(xycb,df) { _A = SET(3, RM(m_ea) ); WM( m_ea,_A ); } /* SET 3,A=(XY+o) */ + +OP(xycb,e0) { _B = SET(4, RM(m_ea) ); WM( m_ea,_B ); } /* SET 4,B=(XY+o) */ +OP(xycb,e1) { _C = SET(4, RM(m_ea) ); WM( m_ea,_C ); } /* SET 4,C=(XY+o) */ +OP(xycb,e2) { _D = SET(4, RM(m_ea) ); WM( m_ea,_D ); } /* SET 4,D=(XY+o) */ +OP(xycb,e3) { _E = SET(4, RM(m_ea) ); WM( m_ea,_E ); } /* SET 4,E=(XY+o) */ +OP(xycb,e4) { _H = SET(4, RM(m_ea) ); WM( m_ea,_H ); } /* SET 4,H=(XY+o) */ +OP(xycb,e5) { _L = SET(4, RM(m_ea) ); WM( m_ea,_L ); } /* SET 4,L=(XY+o) */ +OP(xycb,e6) { WM( m_ea, SET(4,RM(m_ea)) ); } /* SET 4,(XY+o) */ +OP(xycb,e7) { _A = SET(4, RM(m_ea) ); WM( m_ea,_A ); } /* SET 4,A=(XY+o) */ + +OP(xycb,e8) { _B = SET(5, RM(m_ea) ); WM( m_ea,_B ); } /* SET 5,B=(XY+o) */ +OP(xycb,e9) { _C = SET(5, RM(m_ea) ); WM( m_ea,_C ); } /* SET 5,C=(XY+o) */ +OP(xycb,ea) { _D = SET(5, RM(m_ea) ); WM( m_ea,_D ); } /* SET 5,D=(XY+o) */ +OP(xycb,eb) { _E = SET(5, RM(m_ea) ); WM( m_ea,_E ); } /* SET 5,E=(XY+o) */ +OP(xycb,ec) { _H = SET(5, RM(m_ea) ); WM( m_ea,_H ); } /* SET 5,H=(XY+o) */ +OP(xycb,ed) { _L = SET(5, RM(m_ea) ); WM( m_ea,_L ); } /* SET 5,L=(XY+o) */ +OP(xycb,ee) { WM( m_ea, SET(5,RM(m_ea)) ); } /* SET 5,(XY+o) */ +OP(xycb,ef) { _A = SET(5, RM(m_ea) ); WM( m_ea,_A ); } /* SET 5,A=(XY+o) */ + +OP(xycb,f0) { _B = SET(6, RM(m_ea) ); WM( m_ea,_B ); } /* SET 6,B=(XY+o) */ +OP(xycb,f1) { _C = SET(6, RM(m_ea) ); WM( m_ea,_C ); } /* SET 6,C=(XY+o) */ +OP(xycb,f2) { _D = SET(6, RM(m_ea) ); WM( m_ea,_D ); } /* SET 6,D=(XY+o) */ +OP(xycb,f3) { _E = SET(6, RM(m_ea) ); WM( m_ea,_E ); } /* SET 6,E=(XY+o) */ +OP(xycb,f4) { _H = SET(6, RM(m_ea) ); WM( m_ea,_H ); } /* SET 6,H=(XY+o) */ +OP(xycb,f5) { _L = SET(6, RM(m_ea) ); WM( m_ea,_L ); } /* SET 6,L=(XY+o) */ +OP(xycb,f6) { WM( m_ea, SET(6,RM(m_ea)) ); } /* SET 6,(XY+o) */ +OP(xycb,f7) { _A = SET(6, RM(m_ea) ); WM( m_ea,_A ); } /* SET 6,A=(XY+o) */ + +OP(xycb,f8) { _B = SET(7, RM(m_ea) ); WM( m_ea,_B ); } /* SET 7,B=(XY+o) */ +OP(xycb,f9) { _C = SET(7, RM(m_ea) ); WM( m_ea,_C ); } /* SET 7,C=(XY+o) */ +OP(xycb,fa) { _D = SET(7, RM(m_ea) ); WM( m_ea,_D ); } /* SET 7,D=(XY+o) */ +OP(xycb,fb) { _E = SET(7, RM(m_ea) ); WM( m_ea,_E ); } /* SET 7,E=(XY+o) */ +OP(xycb,fc) { _H = SET(7, RM(m_ea) ); WM( m_ea,_H ); } /* SET 7,H=(XY+o) */ +OP(xycb,fd) { _L = SET(7, RM(m_ea) ); WM( m_ea,_L ); } /* SET 7,L=(XY+o) */ +OP(xycb,fe) { WM( m_ea, SET(7,RM(m_ea)) ); } /* SET 7,(XY+o) */ +OP(xycb,ff) { _A = SET(7, RM(m_ea) ); WM( m_ea,_A ); } /* SET 7,A=(XY+o) */ diff --git a/src/devices/cpu/z8/z8.c b/src/devices/cpu/z8/z8.c new file mode 100644 index 00000000000..7db38eaf500 --- /dev/null +++ b/src/devices/cpu/z8/z8.c @@ -0,0 +1,845 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Zilog Z8 Single-Chip MCU emulation + +**********************************************************************/ + +/* + + TODO: + + - strobed I/O + - interrupts + - expose register file to disassembler + - decimal adjust instruction + - timer Tin/Tout modes + - serial + - instruction pipeline + +*/ + +#include "emu.h" +#include "debugger.h" +#include "z8.h" + +/*************************************************************************** + CONSTANTS +***************************************************************************/ + +enum +{ + Z8_REGISTER_P0 = 0, + Z8_REGISTER_P1, + Z8_REGISTER_P2, + Z8_REGISTER_P3, + Z8_REGISTER_SIO = 0xf0, + Z8_REGISTER_TMR, + Z8_REGISTER_T1, + Z8_REGISTER_PRE1, + Z8_REGISTER_T0, + Z8_REGISTER_PRE0, + Z8_REGISTER_P2M, + Z8_REGISTER_P3M, + Z8_REGISTER_P01M, + Z8_REGISTER_IPR, + Z8_REGISTER_IRQ, + Z8_REGISTER_IMR, + Z8_REGISTER_FLAGS, + Z8_REGISTER_RP, + Z8_REGISTER_SPH, + Z8_REGISTER_SPL +}; + +#define Z8_P3_DAV0 0x04 /* not supported */ +#define Z8_P3_DAV1 0x08 /* not supported */ +#define Z8_P3_DAV2 0x02 /* not supported */ +#define Z8_P3_RDY0 0x20 /* not supported */ +#define Z8_P3_RDY1 0x10 /* not supported */ +#define Z8_P3_RDY2 0x40 /* not supported */ +#define Z8_P3_IRQ0 0x04 /* not supported */ +#define Z8_P3_IRQ1 0x08 /* not supported */ +#define Z8_P3_IRQ2 0x02 /* not supported */ +#define Z8_P3_IRQ3 0x01 /* not supported */ +#define Z8_P3_DI 0x01 /* not supported */ +#define Z8_P3_DO 0x80 /* not supported */ +#define Z8_P3_TIN 0x02 /* not supported */ +#define Z8_P3_TOUT 0x40 /* not supported */ +#define Z8_P3_DM 0x10 /* not supported */ + +#define Z8_PRE0_COUNT_MODULO_N 0x01 + +#define Z8_PRE1_COUNT_MODULO_N 0x01 +#define Z8_PRE1_INTERNAL_CLOCK 0x02 + +#define Z8_TMR_LOAD_T0 0x01 +#define Z8_TMR_ENABLE_T0 0x02 +#define Z8_TMR_LOAD_T1 0x04 +#define Z8_TMR_ENABLE_T1 0x08 +#define Z8_TMR_TIN_MASK 0x30 /* not supported */ +#define Z8_TMR_TIN_EXTERNAL_CLK 0x00 /* not supported */ +#define Z8_TMR_TIN_GATE 0x10 /* not supported */ +#define Z8_TMR_TIN_TRIGGER 0x20 /* not supported */ +#define Z8_TMR_TIN_RETRIGGER 0x30 /* not supported */ +#define Z8_TMR_TOUT_MASK 0xc0 /* not supported */ +#define Z8_TMR_TOUT_OFF 0x00 /* not supported */ +#define Z8_TMR_TOUT_T0 0x40 /* not supported */ +#define Z8_TMR_TOUT_T1 0x80 /* not supported */ +#define Z8_TMR_TOUT_INTERNAL_CLK 0xc0 /* not supported */ + +#define Z8_P01M_P0L_MODE_MASK 0x03 +#define Z8_P01M_P0L_MODE_OUTPUT 0x00 +#define Z8_P01M_P0L_MODE_INPUT 0x01 +#define Z8_P01M_P0L_MODE_A8_A11 0x02 /* not supported */ +#define Z8_P01M_INTERNAL_STACK 0x04 +#define Z8_P01M_P1_MODE_MASK 0x18 +#define Z8_P01M_P1_MODE_OUTPUT 0x00 +#define Z8_P01M_P1_MODE_INPUT 0x08 +#define Z8_P01M_P1_MODE_AD0_AD7 0x10 /* not supported */ +#define Z8_P01M_P1_MODE_HI_Z 0x18 /* not supported */ +#define Z8_P01M_EXTENDED_TIMING 0x20 /* not supported */ +#define Z8_P01M_P0H_MODE_MASK 0xc0 +#define Z8_P01M_P0H_MODE_OUTPUT 0x00 +#define Z8_P01M_P0H_MODE_INPUT 0x40 +#define Z8_P01M_P0H_MODE_A12_A15 0x80 /* not supported */ + +#define Z8_P3M_P2_ACTIVE_PULLUPS 0x01 /* not supported */ +#define Z8_P3M_P0_STROBED 0x04 /* not supported */ +#define Z8_P3M_P33_P34_MASK 0x18 +#define Z8_P3M_P33_P34_INPUT_OUTPUT 0x00 +#define Z8_P3M_P33_P34_INPUT_DM 0x08 /* not supported */ +#define Z8_P3M_P33_P34_INPUT_DM_2 0x10 /* not supported */ +#define Z8_P3M_P33_P34_DAV1_RDY1 0x18 /* not supported */ +#define Z8_P3M_P2_STROBED 0x20 /* not supported */ +#define Z8_P3M_P3_SERIAL 0x40 /* not supported */ +#define Z8_P3M_PARITY 0x80 /* not supported */ + +#define Z8_IMR_ENABLE 0x80 /* not supported */ +#define Z8_IMR_RAM_PROTECT 0x40 /* not supported */ +#define Z8_IMR_ENABLE_IRQ5 0x20 /* not supported */ +#define Z8_IMR_ENABLE_IRQ4 0x10 /* not supported */ +#define Z8_IMR_ENABLE_IRQ3 0x08 /* not supported */ +#define Z8_IMR_ENABLE_IRQ2 0x04 /* not supported */ +#define Z8_IMR_ENABLE_IRQ1 0x02 /* not supported */ +#define Z8_IMR_ENABLE_IRQ0 0x01 /* not supported */ + +#define Z8_FLAGS_F1 0x01 +#define Z8_FLAGS_F2 0x02 +#define Z8_FLAGS_H 0x04 +#define Z8_FLAGS_D 0x08 +#define Z8_FLAGS_V 0x10 +#define Z8_FLAGS_S 0x20 +#define Z8_FLAGS_Z 0x40 +#define Z8_FLAGS_C 0x80 + +enum +{ + CC_F = 0, CC_LT, CC_LE, CC_ULE, CC_OV, CC_MI, CC_Z, CC_C, + CC_T, CC_GE, CC_GT, CC_UGT, CC_NOV, CC_PL, CC_NZ, CC_NC +}; + +/*************************************************************************** + MACROS +***************************************************************************/ + +#define P01M m_r[Z8_REGISTER_P01M] +#define P2M m_r[Z8_REGISTER_P2M] +#define P3M m_r[Z8_REGISTER_P3M] +#define T0 m_r[Z8_REGISTER_T0] +#define T1 m_r[Z8_REGISTER_T1] +#define PRE0 m_r[Z8_REGISTER_PRE0] +#define PRE1 m_r[Z8_REGISTER_PRE1] + + +const device_type Z8601 = &device_creator; +const device_type UB8830D = &device_creator; +const device_type Z8611 = &device_creator; + + +/*************************************************************************** + ADDRESS MAPS +***************************************************************************/ + +static ADDRESS_MAP_START( program_2kb, AS_PROGRAM, 8, z8_device ) + AM_RANGE(0x0000, 0x07ff) AM_ROM +ADDRESS_MAP_END + +static ADDRESS_MAP_START( program_4kb, AS_PROGRAM, 8, z8_device ) + AM_RANGE(0x0000, 0x0fff) AM_ROM +ADDRESS_MAP_END + + +z8_device::z8_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source, int size) + : cpu_device(mconfig, type, name, tag, owner, clock, shortname, source) + , m_program_config("program", ENDIANNESS_LITTLE, 8, 16, 0, ( size == 4 ) ? ADDRESS_MAP_NAME(program_4kb) : ADDRESS_MAP_NAME(program_2kb)) + , m_data_config("data", ENDIANNESS_LITTLE, 8, 16, 0) + , m_io_config("io", ENDIANNESS_LITTLE, 8, 2, 0) +{ +} + + +z8601_device::z8601_device(const machine_config &mconfig, const char *_tag, device_t *_owner, UINT32 _clock) + : z8_device(mconfig, Z8601, "Z8601", _tag, _owner, _clock, "z8601", __FILE__, 2) +{ +} + + +ub8830d_device::ub8830d_device(const machine_config &mconfig, const char *_tag, device_t *_owner, UINT32 _clock) + : z8_device(mconfig, UB8830D, "UB8830D", _tag, _owner, _clock, "ub8830d", __FILE__, 2) +{ +} + + +z8611_device::z8611_device(const machine_config &mconfig, const char *_tag, device_t *_owner, UINT32 _clock) + : z8_device(mconfig, Z8611, "Z8611", _tag, _owner, _clock, "z8611", __FILE__, 4) +{ +} + + +offs_t z8_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( z8 ); + return CPU_DISASSEMBLE_NAME(z8)(this, buffer, pc, oprom, opram, options); +} + + +/*************************************************************************** + INLINE FUNCTIONS +***************************************************************************/ + +UINT8 z8_device::fetch() +{ + UINT8 data = m_direct->read_byte(m_pc); + + m_pc++; + + return data; +} + + +UINT8 z8_device::register_read(UINT8 offset) +{ + UINT8 data = 0xff; + UINT8 mask = 0; + + switch (offset) + { + case Z8_REGISTER_P0: + switch (P01M & Z8_P01M_P0L_MODE_MASK) + { + case Z8_P01M_P0L_MODE_OUTPUT: data = m_output[offset] & 0x0f; break; + case Z8_P01M_P0L_MODE_INPUT: mask = 0x0f; break; + default: /* A8...A11 */ data = 0x0f; break; + } + + switch (P01M & Z8_P01M_P0H_MODE_MASK) + { + case Z8_P01M_P0H_MODE_OUTPUT: data |= m_output[offset] & 0xf0; break; + case Z8_P01M_P0H_MODE_INPUT: mask |= 0xf0; break; + default: /* A12...A15 */ data |= 0xf0; break; + } + + if (!(P3M & Z8_P3M_P0_STROBED)) + { + if (mask) m_input[offset] = m_io->read_byte(offset); + } + + data |= m_input[offset] & mask; + break; + + case Z8_REGISTER_P1: + switch (P01M & Z8_P01M_P1_MODE_MASK) + { + case Z8_P01M_P1_MODE_OUTPUT: data = m_output[offset]; break; + case Z8_P01M_P1_MODE_INPUT: mask = 0xff; break; + default: /* AD0..AD7 */ data = 0xff; break; + } + + if ((P3M & Z8_P3M_P33_P34_MASK) != Z8_P3M_P33_P34_DAV1_RDY1) + { + if (mask) m_input[offset] = m_io->read_byte(offset); + } + + data |= m_input[offset] & mask; + break; + + case Z8_REGISTER_P2: + mask = m_r[Z8_REGISTER_P2M]; + + if (!(P3M & Z8_P3M_P2_STROBED)) + { + if (mask) m_input[offset] = m_io->read_byte(offset); + } + + data = (m_input[offset] & mask) | (m_output[offset] & ~mask); + break; + + case Z8_REGISTER_P3: + // TODO: special port 3 modes + if (!(P3M & 0x7c)) + { + mask = 0x0f; + } + + if (mask) m_input[offset] = m_io->read_byte(offset); + + data = (m_input[offset] & mask) | (m_output[offset] & ~mask); + break; + + case Z8_REGISTER_T0: + data = m_t0; + break; + + case Z8_REGISTER_T1: + data = m_t1; + break; + + case Z8_REGISTER_PRE1: + case Z8_REGISTER_PRE0: + case Z8_REGISTER_P2M: + case Z8_REGISTER_P3M: + case Z8_REGISTER_P01M: + case Z8_REGISTER_IPR: + /* write only */ + break; + + default: + data = m_r[offset]; + break; + } + + return data; +} + +UINT16 z8_device::register_pair_read(UINT8 offset) +{ + return (register_read(offset) << 8) | register_read(offset + 1); +} + +void z8_device::register_write(UINT8 offset, UINT8 data) +{ + UINT8 mask = 0; + + switch (offset) + { + case Z8_REGISTER_P0: + m_output[offset] = data; + if ((P01M & Z8_P01M_P0L_MODE_MASK) == Z8_P01M_P0L_MODE_OUTPUT) mask |= 0x0f; + if ((P01M & Z8_P01M_P0H_MODE_MASK) == Z8_P01M_P0H_MODE_OUTPUT) mask |= 0xf0; + if (mask) m_io->write_byte(offset, data & mask); + break; + + case Z8_REGISTER_P1: + m_output[offset] = data; + if ((P01M & Z8_P01M_P1_MODE_MASK) == Z8_P01M_P1_MODE_OUTPUT) mask = 0xff; + if (mask) m_io->write_byte(offset, data & mask); + break; + + case Z8_REGISTER_P2: + m_output[offset] = data; + mask = m_r[Z8_REGISTER_P2M] ^ 0xff; + if (mask) m_io->write_byte(offset, data & mask); + break; + + case Z8_REGISTER_P3: + m_output[offset] = data; + + // TODO: special port 3 modes + if (!(P3M & 0x7c)) + { + mask = 0xf0; + } + + if (mask) m_io->write_byte(offset, data & mask); + break; + + case Z8_REGISTER_SIO: + break; + + case Z8_REGISTER_TMR: + if (data & Z8_TMR_LOAD_T0) + { + m_t0 = T0; + m_t0_timer->adjust(attotime::zero, 0, attotime::from_hz(m_clock / 2 / 4 / ((PRE0 >> 2) + 1))); + } + + m_t0_timer->enable(data & Z8_TMR_ENABLE_T0); + + if (data & Z8_TMR_LOAD_T1) + { + m_t1 = T1; + m_t1_timer->adjust(attotime::zero, 0, attotime::from_hz(m_clock / 2 / 4 / ((PRE1 >> 2) + 1))); + } + + m_t1_timer->enable(data & Z8_TMR_ENABLE_T1); + break; + + case Z8_REGISTER_P2M: + break; + case Z8_REGISTER_P3M: + break; + case Z8_REGISTER_P01M: + break; + case Z8_REGISTER_IPR: + break; + case Z8_REGISTER_IRQ: + break; + case Z8_REGISTER_IMR: + break; + case Z8_REGISTER_FLAGS: + break; + case Z8_REGISTER_RP: + break; + case Z8_REGISTER_SPH: + break; + case Z8_REGISTER_SPL: + break; + default: + // TODO ignore missing registers + break; + } + + m_r[offset] = data; +} + +void z8_device::register_pair_write(UINT8 offset, UINT16 data) +{ + register_write(offset, data >> 8); + register_write(offset + 1, data & 0xff); +} + +UINT8 z8_device::get_working_register(int offset) +{ + return (m_r[Z8_REGISTER_RP] & 0xf0) | (offset & 0x0f); +} + +UINT8 z8_device::get_register(UINT8 offset) +{ + if ((offset & 0xf0) == 0xe0) + return get_working_register(offset & 0x0f); + else + return offset; +} + +UINT8 z8_device::get_intermediate_register(int offset) +{ + return register_read(get_register(offset)); +} + +void z8_device::stack_push_byte(UINT8 src) +{ + if (register_read(Z8_REGISTER_P01M) & Z8_P01M_INTERNAL_STACK) + { + /* SP <- SP - 1 */ + UINT8 sp = register_read(Z8_REGISTER_SPL) - 1; + register_write(Z8_REGISTER_SPL, sp); + + /* @SP <- src */ + register_write(sp, src); + } + else + { + /* SP <- SP - 1 */ + UINT16 sp = register_pair_read(Z8_REGISTER_SPH) - 1; + register_pair_write(Z8_REGISTER_SPH, sp); + + /* @SP <- src */ + m_data->write_byte(sp, src); + } +} + +void z8_device::stack_push_word(UINT16 src) +{ + if (register_read(Z8_REGISTER_P01M) & Z8_P01M_INTERNAL_STACK) + { + /* SP <- SP - 2 */ + UINT8 sp = register_read(Z8_REGISTER_SPL) - 2; + register_write(Z8_REGISTER_SPL, sp); + + /* @SP <- src */ + register_pair_write(sp, src); + } + else + { + /* SP <- SP - 2 */ + UINT16 sp = register_pair_read(Z8_REGISTER_SPH) - 2; + register_pair_write(Z8_REGISTER_SPH, sp); + + /* @SP <- src */ + m_data->write_word(sp, src); + } +} + +UINT8 z8_device::stack_pop_byte() +{ + if (register_read(Z8_REGISTER_P01M) & Z8_P01M_INTERNAL_STACK) + { + /* SP <- SP + 1 */ + UINT8 sp = register_read(Z8_REGISTER_SPL) + 1; + register_write(Z8_REGISTER_SPL, sp); + + /* @SP <- src */ + return register_read(sp); + } + else + { + /* SP <- SP + 1 */ + UINT16 sp = register_pair_read(Z8_REGISTER_SPH) + 1; + register_pair_write(Z8_REGISTER_SPH, sp); + + /* @SP <- src */ + return m_data->read_byte(sp); + } +} + +UINT16 z8_device::stack_pop_word() +{ + if (register_read(Z8_REGISTER_P01M) & Z8_P01M_INTERNAL_STACK) + { + /* SP <- SP + 2 */ + UINT8 sp = register_read(Z8_REGISTER_SPL) + 2; + register_write(Z8_REGISTER_SPL, sp); + + /* @SP <- src */ + return register_read(sp); + } + else + { + /* SP <- SP + 2 */ + UINT16 sp = register_pair_read(Z8_REGISTER_SPH) + 2; + register_pair_write(Z8_REGISTER_SPH, sp); + + /* @SP <- src */ + return m_data->read_word(sp); + } +} + +void z8_device::set_flag(UINT8 flag, int state) +{ + if (state) + m_r[Z8_REGISTER_FLAGS] |= flag; + else + m_r[Z8_REGISTER_FLAGS] &= ~flag; +} + +#define set_flag_h(state) set_flag(Z8_FLAGS_H, state); +#define set_flag_d(state) set_flag(Z8_FLAGS_D, state); +#define set_flag_v(state) set_flag(Z8_FLAGS_V, state); +#define set_flag_s(state) set_flag(Z8_FLAGS_S, state); +#define set_flag_z(state) set_flag(Z8_FLAGS_Z, state); +#define set_flag_c(state) set_flag(Z8_FLAGS_C, state); + +/*************************************************************************** + OPCODE HANDLERS +***************************************************************************/ + +#define INSTRUCTION(mnemonic) void z8_device::mnemonic(UINT8 opcode, int *cycles) + +INSTRUCTION( illegal ) +{ + logerror("Z8: PC = %04x, Illegal opcode = %02x\n", m_pc - 1, opcode); +} + +#include "z8ops.inc" + +/*************************************************************************** + OPCODE TABLES +***************************************************************************/ + +const z8_device::z8_opcode_map z8_device::Z8601_OPCODE_MAP[256] = +{ + { &z8_device::dec_R1, 6, 5 }, { &z8_device::dec_IR1, 6, 5 }, { &z8_device::add_r1_r2, 10, 5 }, { &z8_device::add_r1_Ir2, 10, 5 }, + { &z8_device::add_R2_R1, 10, 5 }, { &z8_device::add_IR2_R1, 10, 5 }, { &z8_device::add_R1_IM, 10, 5 }, { &z8_device::add_IR1_IM, 10, 5 }, + { &z8_device::ld_r1_R2, 6, 5 }, { &z8_device::ld_r2_R1, 6, 5 }, { &z8_device::djnz_r1_RA, 10, 5 }, { &z8_device::jr_cc_RA, 10, 0 }, + { &z8_device::ld_r1_IM, 6, 5 }, { &z8_device::jp_cc_DA, 10, 0 }, { &z8_device::inc_r1, 6, 5 }, { &z8_device::illegal, 0, 0 }, + + { &z8_device::rlc_R1, 6, 5 }, { &z8_device::rlc_IR1, 6, 5 }, { &z8_device::adc_r1_r2, 6, 5 }, { &z8_device::adc_r1_Ir2, 6, 5 }, + { &z8_device::adc_R2_R1, 10, 5 }, { &z8_device::adc_IR2_R1, 10, 5 }, { &z8_device::adc_R1_IM, 10, 5 }, { &z8_device::adc_IR1_IM, 10, 5 }, + { &z8_device::ld_r1_R2, 6, 5 }, { &z8_device::ld_r2_R1, 6, 5 }, { &z8_device::djnz_r1_RA, 10, 5 }, { &z8_device::jr_cc_RA, 10, 0 }, + { &z8_device::ld_r1_IM, 6, 5 }, { &z8_device::jp_cc_DA, 10, 0 }, { &z8_device::inc_r1, 6, 5 }, { &z8_device::illegal, 0, 0 }, + + { &z8_device::inc_R1, 6, 5 }, { &z8_device::inc_IR1, 6, 5 }, { &z8_device::sub_r1_r2, 6, 5 }, { &z8_device::sub_r1_Ir2, 6, 5 }, + { &z8_device::sub_R2_R1, 10, 5 }, { &z8_device::sub_IR2_R1, 10, 5 }, { &z8_device::sub_R1_IM, 10, 5 }, { &z8_device::sub_IR1_IM, 10, 5 }, + { &z8_device::ld_r1_R2, 6, 5 }, { &z8_device::ld_r2_R1, 6, 5 }, { &z8_device::djnz_r1_RA, 10, 5 }, { &z8_device::jr_cc_RA, 10, 0 }, + { &z8_device::ld_r1_IM, 6, 5 }, { &z8_device::jp_cc_DA, 10, 0 }, { &z8_device::inc_r1, 6, 5 }, { &z8_device::illegal, 0, 0 }, + + { &z8_device::jp_IRR1, 8, 0 }, { &z8_device::srp_IM, 6, 1 }, { &z8_device::sbc_r1_r2, 6, 5 }, { &z8_device::sbc_r1_Ir2, 6, 5 }, + { &z8_device::sbc_R2_R1, 10, 5 }, { &z8_device::sbc_IR2_R1, 10, 5 }, { &z8_device::sbc_R1_IM, 10, 5 }, { &z8_device::sbc_IR1_IM, 10, 5 }, + { &z8_device::ld_r1_R2, 6, 5 }, { &z8_device::ld_r2_R1, 6, 5 }, { &z8_device::djnz_r1_RA, 10, 5 }, { &z8_device::jr_cc_RA, 10, 0 }, + { &z8_device::ld_r1_IM, 6, 5 }, { &z8_device::jp_cc_DA, 10, 0 }, { &z8_device::inc_r1, 6, 5 }, { &z8_device::illegal, 0, 0 }, + + { &z8_device::da_R1, 8, 5 }, { &z8_device::da_IR1, 8, 5 }, { &z8_device::or_r1_r2, 6, 5 }, { &z8_device::or_r1_Ir2, 6, 5 }, + { &z8_device::or_R2_R1, 10, 5 }, { &z8_device::or_IR2_R1, 10, 5 }, { &z8_device::or_R1_IM, 10, 5 }, { &z8_device::or_IR1_IM, 10, 5 }, + { &z8_device::ld_r1_R2, 6, 5 }, { &z8_device::ld_r2_R1, 6, 5 }, { &z8_device::djnz_r1_RA, 10, 5 }, { &z8_device::jr_cc_RA, 10, 0 }, + { &z8_device::ld_r1_IM, 6, 5 }, { &z8_device::jp_cc_DA, 10, 0 }, { &z8_device::inc_r1, 6, 5 }, { &z8_device::illegal, 0, 0 }, + + { &z8_device::pop_R1, 10, 5 }, { &z8_device::pop_IR1, 10, 5 }, { &z8_device::and_r1_r2, 6, 5 }, { &z8_device::and_r1_Ir2, 6, 5 }, + { &z8_device::and_R2_R1, 10, 5 }, { &z8_device::and_IR2_R1, 10, 5 }, { &z8_device::and_R1_IM, 10, 5 }, { &z8_device::and_IR1_IM, 10, 5 }, + { &z8_device::ld_r1_R2, 6, 5 }, { &z8_device::ld_r2_R1, 6, 5 }, { &z8_device::djnz_r1_RA, 10, 5 }, { &z8_device::jr_cc_RA, 10, 0 }, + { &z8_device::ld_r1_IM, 6, 5 }, { &z8_device::jp_cc_DA, 10, 0 }, { &z8_device::inc_r1, 6, 5 }, { &z8_device::illegal, 0, 0 }, + + { &z8_device::com_R1, 6, 5 }, { &z8_device::com_IR1, 6, 5 }, { &z8_device::tcm_r1_r2, 6, 5 }, { &z8_device::tcm_r1_Ir2, 6, 5 }, + { &z8_device::tcm_R2_R1, 10, 5 }, { &z8_device::tcm_IR2_R1, 10, 5 }, { &z8_device::tcm_R1_IM, 10, 5 }, { &z8_device::tcm_IR1_IM, 10, 5 }, + { &z8_device::ld_r1_R2, 6, 5 }, { &z8_device::ld_r2_R1, 6, 5 }, { &z8_device::djnz_r1_RA, 10, 5 }, { &z8_device::jr_cc_RA, 10, 0 }, + { &z8_device::ld_r1_IM, 6, 5 }, { &z8_device::jp_cc_DA, 10, 0 }, { &z8_device::inc_r1, 6, 5 }, { &z8_device::illegal, 0, 0 }, + + { &z8_device::push_R2, 10, 1 }, { &z8_device::push_IR2, 12, 1 },{ &z8_device::tm_r1_r2, 6, 5 }, { &z8_device::tm_r1_Ir2, 6, 5 }, + { &z8_device::tm_R2_R1, 10, 5 }, { &z8_device::tm_IR2_R1, 10, 5 }, { &z8_device::tm_R1_IM, 10, 5 }, { &z8_device::tm_IR1_IM, 10, 5 }, + { &z8_device::ld_r1_R2, 6, 5 }, { &z8_device::ld_r2_R1, 6, 5 }, { &z8_device::djnz_r1_RA, 10, 5 }, { &z8_device::jr_cc_RA, 10, 0 }, + { &z8_device::ld_r1_IM, 6, 5 }, { &z8_device::jp_cc_DA, 10, 0 }, { &z8_device::inc_r1, 6, 5 }, { &z8_device::illegal, 0, 0 }, + + { &z8_device::decw_RR1, 10, 5 },{ &z8_device::decw_IR1, 10, 5 },{ &z8_device::lde_r1_Irr2, 12, 0 }, { &z8_device::ldei_Ir1_Irr2, 18, 0 }, + { &z8_device::illegal, 0, 0 }, { &z8_device::illegal, 0, 0 }, { &z8_device::illegal, 0, 0 }, { &z8_device::illegal, 0, 0 }, + { &z8_device::ld_r1_R2, 6, 5 }, { &z8_device::ld_r2_R1, 6, 5 }, { &z8_device::djnz_r1_RA, 10, 5 }, { &z8_device::jr_cc_RA, 10, 0 }, + { &z8_device::ld_r1_IM, 6, 5 }, { &z8_device::jp_cc_DA, 10, 0 }, { &z8_device::inc_r1, 6, 5 }, { &z8_device::di, 6, 1 }, + + { &z8_device::rl_R1, 6, 5 }, { &z8_device::rl_IR1, 6, 5 }, { &z8_device::lde_r2_Irr1, 12, 0 }, { &z8_device::ldei_Ir2_Irr1, 18, 0 }, + { &z8_device::illegal, 0, 0 }, { &z8_device::illegal, 0, 0 }, { &z8_device::illegal, 0, 0 }, { &z8_device::illegal, 0, 0 }, + { &z8_device::ld_r1_R2, 6, 5 }, { &z8_device::ld_r2_R1, 6, 5 }, { &z8_device::djnz_r1_RA, 10, 5 }, { &z8_device::jr_cc_RA, 10, 0 }, + { &z8_device::ld_r1_IM, 6, 5 }, { &z8_device::jp_cc_DA, 10, 0 }, { &z8_device::inc_r1, 6, 5 }, { &z8_device::ei, 6, 1 }, + + { &z8_device::incw_RR1, 10, 5 },{ &z8_device::incw_IR1, 10, 5 },{ &z8_device::cp_r1_r2, 6, 5 }, { &z8_device::cp_r1_Ir2, 6, 5 }, + { &z8_device::cp_R2_R1, 10, 5 }, { &z8_device::cp_IR2_R1, 10, 5 }, { &z8_device::cp_R1_IM, 10, 5 }, { &z8_device::cp_IR1_IM, 10, 5 }, + { &z8_device::ld_r1_R2, 6, 5 }, { &z8_device::ld_r2_R1, 6, 5 }, { &z8_device::djnz_r1_RA, 10, 5 }, { &z8_device::jr_cc_RA, 10, 0 }, + { &z8_device::ld_r1_IM, 6, 5 }, { &z8_device::jp_cc_DA, 10, 0 }, { &z8_device::inc_r1, 6, 5 }, { &z8_device::ret, 14, 0 }, + + { &z8_device::clr_R1, 6, 5 }, { &z8_device::clr_IR1, 6, 5 }, { &z8_device::xor_r1_r2, 6, 5 }, { &z8_device::xor_r1_Ir2, 6, 5 }, + { &z8_device::xor_R2_R1, 10, 5 }, { &z8_device::xor_IR2_R1, 10, 5 }, { &z8_device::xor_R1_IM, 10, 5 }, { &z8_device::xor_IR1_IM, 10, 5 }, + { &z8_device::ld_r1_R2, 6, 5 }, { &z8_device::ld_r2_R1, 6, 5 }, { &z8_device::djnz_r1_RA, 10, 5 }, { &z8_device::jr_cc_RA, 10, 0 }, + { &z8_device::ld_r1_IM, 6, 5 }, { &z8_device::jp_cc_DA, 10, 0 }, { &z8_device::inc_r1, 6, 5 }, { &z8_device::iret, 16, 0 }, + + { &z8_device::rrc_R1, 6, 5 }, { &z8_device::rrc_IR1, 6, 5 }, { &z8_device::ldc_r1_Irr2, 12, 0 }, { &z8_device::ldci_Ir1_Irr2, 18, 0 }, + { &z8_device::illegal, 0, 0 }, { &z8_device::illegal, 0, 0 }, { &z8_device::illegal, 0, 0 }, { &z8_device::ld_r1_x_R2, 10, 5 }, + { &z8_device::ld_r1_R2, 6, 5 }, { &z8_device::ld_r2_R1, 6, 5 }, { &z8_device::djnz_r1_RA, 10, 5 }, { &z8_device::jr_cc_RA, 10, 0 }, + { &z8_device::ld_r1_IM, 6, 5 }, { &z8_device::jp_cc_DA, 10, 0 }, { &z8_device::inc_r1, 6, 5 }, { &z8_device::rcf, 6, 5 }, + + { &z8_device::sra_R1, 6, 5 }, { &z8_device::sra_IR1, 6, 5 }, { &z8_device::ldc_r2_Irr1, 12, 0 }, { &z8_device::ldci_Ir2_Irr1, 18, 0 }, + { &z8_device::call_IRR1, 20, 0 }, { &z8_device::illegal, 0, 0 }, { &z8_device::call_DA, 20, 0 }, { &z8_device::ld_r2_x_R1, 10, 5 }, + { &z8_device::ld_r1_R2, 6, 5 }, { &z8_device::ld_r2_R1, 6, 5 }, { &z8_device::djnz_r1_RA, 10, 5 }, { &z8_device::jr_cc_RA, 10, 0 }, + { &z8_device::ld_r1_IM, 6, 5 }, { &z8_device::jp_cc_DA, 10, 0 }, { &z8_device::inc_r1, 6, 5 }, { &z8_device::scf, 6, 5 }, + + { &z8_device::rr_R1, 6, 5 }, { &z8_device::rr_IR1, 6, 5 }, { &z8_device::illegal, 0, 0 }, { &z8_device::ld_r1_Ir2, 6, 5 }, + { &z8_device::ld_R2_R1, 10, 5 }, { &z8_device::ld_IR2_R1, 10, 5 }, { &z8_device::ld_R1_IM, 10, 5 }, { &z8_device::ld_IR1_IM, 10, 5 }, + { &z8_device::ld_r1_R2, 6, 5 }, { &z8_device::ld_r2_R1, 6, 5 }, { &z8_device::djnz_r1_RA, 10, 5 }, { &z8_device::jr_cc_RA, 10, 0 }, + { &z8_device::ld_r1_IM, 6, 5 }, { &z8_device::jp_cc_DA, 10, 0 }, { &z8_device::inc_r1, 6, 5 }, { &z8_device::ccf, 6, 5 }, + + { &z8_device::swap_R1, 8, 5 }, { &z8_device::swap_IR1, 8, 5 }, { &z8_device::illegal, 0, 0 }, { &z8_device::ld_Ir1_r2, 6, 5 }, + { &z8_device::illegal, 0, 0 }, { &z8_device::ld_R2_IR1, 10, 5 }, { &z8_device::illegal, 0, 0 }, { &z8_device::illegal, 0, 0 }, + { &z8_device::ld_r1_R2, 6, 5 }, { &z8_device::ld_r2_R1, 6, 5 }, { &z8_device::djnz_r1_RA, 10, 5 }, { &z8_device::jr_cc_RA, 10, 0 }, + { &z8_device::ld_r1_IM, 6, 5 }, { &z8_device::jp_cc_DA, 10, 0 }, { &z8_device::inc_r1, 6, 5 }, { &z8_device::nop, 6, 0 } +}; + +/*************************************************************************** + TIMER CALLBACKS +***************************************************************************/ + +TIMER_CALLBACK_MEMBER( z8_device::t0_tick ) +{ + m_t0--; + + if (m_t0 == 0) + { + m_t0 = T0; + m_t0_timer->adjust(attotime::zero, 0, attotime::from_hz(m_clock / 2 / 4 / ((PRE0 >> 2) + 1))); + m_t0_timer->enable(PRE0 & Z8_PRE0_COUNT_MODULO_N); + m_irq[4] = ASSERT_LINE; + } +} + +TIMER_CALLBACK_MEMBER( z8_device::t1_tick ) +{ + m_t1--; + + if (m_t1 == 0) + { + m_t1 = T1; + m_t1_timer->adjust(attotime::zero, 0, attotime::from_hz(m_clock / 2 / 4 / ((PRE1 >> 2) + 1))); + m_t1_timer->enable(PRE1 & Z8_PRE0_COUNT_MODULO_N); + m_irq[5] = ASSERT_LINE; + } +} + +/*************************************************************************** + INITIALIZATION +***************************************************************************/ + +void z8_device::device_start() +{ + /* set up the state table */ + { + state_add(Z8_PC, "PC", m_pc); + state_add(STATE_GENPC, "GENPC", m_pc).noshow(); + state_add(Z8_SP, "SP", m_fake_sp).callimport().callexport(); + state_add(STATE_GENSP, "GENSP", m_fake_sp).callimport().callexport().noshow(); + state_add(Z8_RP, "RP", m_r[Z8_REGISTER_RP]); + state_add(Z8_T0, "T0", m_t0); + state_add(Z8_T1, "T1", m_t1); + state_add(STATE_GENFLAGS, "GENFLAGS", m_r[Z8_REGISTER_FLAGS]).noshow().formatstr("%6s"); + + std::string tempstr; + for (int regnum = 0; regnum < 16; regnum++) + state_add(Z8_R0 + regnum, strformat(tempstr, "R%d", regnum).c_str(), m_fake_r[regnum]).callimport().callexport(); + } + + /* find address spaces */ + m_program = &space(AS_PROGRAM); + m_direct = &m_program->direct(); + m_data = &space(AS_DATA); + m_io = &space(AS_IO); + + /* allocate timers */ + m_t0_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(z8_device::t0_tick), this)); + m_t1_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(z8_device::t1_tick), this)); + + /* Clear state */ + for ( int i = 0; i < 6; i++ ) + m_irq[i] = 0; + for ( int i = 0; i < 256; i++ ) + m_r[i] = 0; + for ( int i = 0; i < 4; i++ ) + { + m_input[i] = 0; + m_output[i] = 0; + } + for ( int i = 0; i < 16; i++ ) + m_fake_r[i] = 0; + m_fake_sp = 0; + m_t0 = 0; + m_t1 = 0; + + /* register for state saving */ + save_item(NAME(m_pc)); + save_item(NAME(m_r)); + save_item(NAME(m_input)); + save_item(NAME(m_output)); + save_item(NAME(m_irq)); + + m_icountptr = &m_icount; +} + +/*************************************************************************** + EXECUTION +***************************************************************************/ + +void z8_device::execute_run() +{ + do + { + UINT8 opcode; + int cycles; + + debugger_instruction_hook(this, m_pc); + + /* TODO: sample interrupts */ + m_input[3] = m_io->read_byte(3); + + /* fetch opcode */ + opcode = fetch(); + cycles = Z8601_OPCODE_MAP[opcode].execution_cycles; + + /* execute instruction */ + (this->*(Z8601_OPCODE_MAP[opcode].function))(opcode, &cycles); + + m_icount -= cycles; + } + while (m_icount > 0); +} + +/*************************************************************************** + RESET +***************************************************************************/ + +void z8_device::device_reset() +{ + m_pc = 0x000c; + + register_write(Z8_REGISTER_TMR, 0x00); + register_write(Z8_REGISTER_PRE1, register_read(Z8_REGISTER_PRE1) & 0xfc); + register_write(Z8_REGISTER_PRE0, register_read(Z8_REGISTER_PRE0) & 0xfe); + register_write(Z8_REGISTER_P2M, 0xff); + register_write(Z8_REGISTER_P3M, 0x00); + register_write(Z8_REGISTER_P01M, 0x4d); + register_write(Z8_REGISTER_IRQ, 0x00); + register_write(Z8_REGISTER_RP, 0x00); +} + + +/************************************************************************** + * STATE IMPORT/EXPORT + **************************************************************************/ + +void z8_device::state_import(const device_state_entry &entry) +{ + switch (entry.index()) + { + case Z8_SP: + case Z8_GENSP: + m_r[Z8_REGISTER_SPH] = m_fake_sp >> 8; + m_r[Z8_REGISTER_SPL] = m_fake_sp & 0xff; + break; + + case Z8_R0: case Z8_R1: case Z8_R2: case Z8_R3: case Z8_R4: case Z8_R5: case Z8_R6: case Z8_R7: case Z8_R8: case Z8_R9: case Z8_R10: case Z8_R11: case Z8_R12: case Z8_R13: case Z8_R14: case Z8_R15: + m_r[m_r[Z8_REGISTER_RP] + (entry.index() - Z8_R0)] = m_fake_r[entry.index() - Z8_R0]; + break; + + default: + fatalerror("CPU_IMPORT_STATE(z8) called for unexpected value\n"); + } +} + +void z8_device::state_export(const device_state_entry &entry) +{ + switch (entry.index()) + { + case Z8_SP: + case Z8_GENSP: + m_fake_sp = (m_r[Z8_REGISTER_SPH] << 8) | m_r[Z8_REGISTER_SPL]; + break; + + case Z8_R0: case Z8_R1: case Z8_R2: case Z8_R3: case Z8_R4: case Z8_R5: case Z8_R6: case Z8_R7: case Z8_R8: case Z8_R9: case Z8_R10: case Z8_R11: case Z8_R12: case Z8_R13: case Z8_R14: case Z8_R15: + m_fake_r[entry.index() - Z8_R0] = m_r[m_r[Z8_REGISTER_RP] + (entry.index() - Z8_R0)]; + break; + + default: + fatalerror("CPU_EXPORT_STATE(z8) called for unexpected value\n"); + } +} + +void z8_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + switch (entry.index()) + { + case STATE_GENFLAGS: strprintf(str, "%c%c%c%c%c%c", + m_r[Z8_REGISTER_FLAGS] & Z8_FLAGS_C ? 'C' : '.', + m_r[Z8_REGISTER_FLAGS] & Z8_FLAGS_Z ? 'Z' : '.', + m_r[Z8_REGISTER_FLAGS] & Z8_FLAGS_S ? 'S' : '.', + m_r[Z8_REGISTER_FLAGS] & Z8_FLAGS_V ? 'V' : '.', + m_r[Z8_REGISTER_FLAGS] & Z8_FLAGS_D ? 'D' : '.', + m_r[Z8_REGISTER_FLAGS] & Z8_FLAGS_H ? 'H' : '.'); break; + } +} + + +void z8_device::execute_set_input(int inputnum, int state) +{ + switch ( inputnum ) + { + case INPUT_LINE_IRQ0: + m_irq[0] = state; + break; + + case INPUT_LINE_IRQ1: + m_irq[1] = state; + break; + + case INPUT_LINE_IRQ2: + m_irq[2] = state; + break; + + case INPUT_LINE_IRQ3: + m_irq[3] = state; + break; + + } +} diff --git a/src/devices/cpu/z8/z8.h b/src/devices/cpu/z8/z8.h new file mode 100644 index 00000000000..3ab30695bd6 --- /dev/null +++ b/src/devices/cpu/z8/z8.h @@ -0,0 +1,326 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Zilog Z8 Single-Chip MCU emulation + +**********************************************************************/ + +#pragma once + +#ifndef __Z8_H__ +#define __Z8_H__ + + +enum +{ + Z8_PC, Z8_SP, Z8_RP, Z8_T0, Z8_T1, + + Z8_R0, Z8_R1, Z8_R2, Z8_R3, Z8_R4, Z8_R5, Z8_R6, Z8_R7, Z8_R8, Z8_R9, Z8_R10, Z8_R11, Z8_R12, Z8_R13, Z8_R14, Z8_R15, + + Z8_GENPC = STATE_GENPC, + Z8_GENSP = STATE_GENSP +}; + + +class z8_device : public cpu_device +{ +public: + // construction/destruction + z8_device(const machine_config &mconfig, device_type type, const char *name, const char *_tag, device_t *_owner, UINT32 _clock, const char *shortname, const char *source, int size); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_execute_interface overrides + virtual UINT32 execute_min_cycles() const { return 6; } + virtual UINT32 execute_max_cycles() const { return 20; } + virtual UINT32 execute_input_lines() const { return 4; } + virtual UINT64 execute_clocks_to_cycles(UINT64 clocks) const { return (clocks + 2 - 1) / 2; } + virtual UINT64 execute_cycles_to_clocks(UINT64 cycles) const { return (cycles * 2); } + virtual void execute_run(); + virtual void execute_set_input(int inputnum, int state); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const + { + switch ( spacenum ) + { + case AS_PROGRAM: return &m_program_config; + case AS_DATA: return &m_data_config; + case AS_IO: return &m_io_config; + default: return NULL; + } + return NULL; + } + + // device_state_interface overrides + virtual void state_import(const device_state_entry &entry); + virtual void state_export(const device_state_entry &entry); + void state_string_export(const device_state_entry &entry, std::string &str); + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const { return 1; } + virtual UINT32 disasm_max_opcode_bytes() const { return 3; } + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + + +private: + address_space_config m_program_config; + address_space_config m_data_config; + address_space_config m_io_config; + + address_space *m_program; + direct_read_data *m_direct; + address_space *m_data; + address_space *m_io; + + /* registers */ + UINT16 m_pc; /* program counter */ + UINT8 m_r[256]; /* register file */ + UINT8 m_input[4]; /* port input latches */ + UINT8 m_output[4]; /* port output latches */ + UINT8 m_t0; /* timer 0 current count */ + UINT8 m_t1; /* timer 1 current count */ + + /* fake registers */ + UINT16 m_fake_sp; /* fake stack pointer */ + UINT8 m_fake_r[16]; /* fake working registers */ + + /* interrupts */ + int m_irq[6]; /* interrupts */ + + /* execution logic */ + int m_icount; /* instruction counter */ + + /* timers */ + emu_timer *m_t0_timer; + emu_timer *m_t1_timer; + + TIMER_CALLBACK_MEMBER( t0_tick ); + TIMER_CALLBACK_MEMBER( t1_tick ); + + inline UINT8 fetch(); + inline UINT8 register_read(UINT8 offset); + inline UINT16 register_pair_read(UINT8 offset); + inline void register_write(UINT8 offset, UINT8 data); + inline void register_pair_write(UINT8 offset, UINT16 data); + inline UINT8 get_working_register(int offset); + inline UINT8 get_register(UINT8 offset); + inline UINT8 get_intermediate_register(int offset); + inline void stack_push_byte(UINT8 src); + inline void stack_push_word(UINT16 src); + inline UINT8 stack_pop_byte(); + inline UINT16 stack_pop_word(); + inline void set_flag(UINT8 flag, int state); + inline void clear(UINT8 dst); + inline void load(UINT8 dst, UINT8 src); + inline void load_from_memory(address_space *space); + inline void load_to_memory(address_space *space); + inline void load_from_memory_autoinc(address_space *space); + inline void load_to_memory_autoinc(address_space *space); + inline void pop(UINT8 dst); + inline void push(UINT8 src); + inline void add_carry(UINT8 dst, INT8 src); + inline void add(UINT8 dst, INT8 src); + inline void compare(UINT8 dst, UINT8 src); + inline void decimal_adjust(UINT8 dst); + inline void decrement(UINT8 dst); + inline void decrement_word(UINT8 dst); + inline void increment(UINT8 dst); + inline void increment_word(UINT8 dst); + inline void subtract_carry(UINT8 dst, UINT8 src); + inline void subtract(UINT8 dst, UINT8 src); + inline void _and(UINT8 dst, UINT8 src); + inline void complement(UINT8 dst); + inline void _or(UINT8 dst, UINT8 src); + inline void _xor(UINT8 dst, UINT8 src); + inline void call(UINT16 dst); + inline void jump(UINT16 dst); + inline int check_condition_code(int cc); + inline void test_complement_under_mask(UINT8 dst, UINT8 src); + inline void test_under_mask(UINT8 dst, UINT8 src); + inline void rotate_left(UINT8 dst); + inline void rotate_left_carry(UINT8 dst); + inline void rotate_right(UINT8 dst); + inline void rotate_right_carry(UINT8 dst); + inline void shift_right_arithmetic(UINT8 dst); + inline void swap(UINT8 dst); + + #define INSTRUCTION(inst) void inst(UINT8 opcode, int *cycles); + INSTRUCTION( illegal ) + INSTRUCTION( clr_R1 ) + INSTRUCTION( clr_IR1 ) + INSTRUCTION( ld_r1_IM ) + INSTRUCTION( ld_r1_R2 ) + INSTRUCTION( ld_r2_R1 ) + INSTRUCTION( ld_Ir1_r2 ) + INSTRUCTION( ld_R2_IR1 ) + INSTRUCTION( ld_r1_x_R2 ) + INSTRUCTION( ld_r2_x_R1 ) + INSTRUCTION( ld_r1_r2 ) + INSTRUCTION( ld_r1_Ir2 ) + INSTRUCTION( ld_R2_R1 ) + INSTRUCTION( ld_IR2_R1 ) + INSTRUCTION( ld_R1_IM ) + INSTRUCTION( ld_IR1_IM ) + INSTRUCTION( ldc_r1_Irr2 ) + INSTRUCTION( ldc_r2_Irr1 ) + INSTRUCTION( ldci_Ir1_Irr2 ) + INSTRUCTION( ldci_Ir2_Irr1 ) + INSTRUCTION( lde_r1_Irr2 ) + INSTRUCTION( lde_r2_Irr1 ) + INSTRUCTION( ldei_Ir1_Irr2 ) + INSTRUCTION( ldei_Ir2_Irr1 ) + INSTRUCTION( pop_R1 ) + INSTRUCTION( pop_IR1 ) + INSTRUCTION( push_R2 ) + INSTRUCTION( push_IR2 ) + INSTRUCTION( adc_r1_r2 ) + INSTRUCTION( adc_r1_Ir2 ) + INSTRUCTION( adc_R2_R1 ) + INSTRUCTION( adc_IR2_R1 ) + INSTRUCTION( adc_R1_IM ) + INSTRUCTION( adc_IR1_IM ) + INSTRUCTION( add_r1_r2 ) + INSTRUCTION( add_r1_Ir2 ) + INSTRUCTION( add_R2_R1 ) + INSTRUCTION( add_IR2_R1 ) + INSTRUCTION( add_R1_IM ) + INSTRUCTION( add_IR1_IM ) + INSTRUCTION( cp_r1_r2 ) + INSTRUCTION( cp_r1_Ir2 ) + INSTRUCTION( cp_R2_R1 ) + INSTRUCTION( cp_IR2_R1 ) + INSTRUCTION( cp_R1_IM ) + INSTRUCTION( cp_IR1_IM ) + INSTRUCTION( da_R1 ) + INSTRUCTION( da_IR1 ) + INSTRUCTION( dec_R1 ) + INSTRUCTION( dec_IR1 ) + INSTRUCTION( decw_RR1 ) + INSTRUCTION( decw_IR1 ) + INSTRUCTION( inc_r1 ) + INSTRUCTION( inc_R1 ) + INSTRUCTION( inc_IR1 ) + INSTRUCTION( incw_RR1 ) + INSTRUCTION( incw_IR1 ) + INSTRUCTION( sbc_r1_r2 ) + INSTRUCTION( sbc_r1_Ir2 ) + INSTRUCTION( sbc_R2_R1 ) + INSTRUCTION( sbc_IR2_R1 ) + INSTRUCTION( sbc_R1_IM ) + INSTRUCTION( sbc_IR1_IM ) + INSTRUCTION( sub_r1_r2 ) + INSTRUCTION( sub_r1_Ir2 ) + INSTRUCTION( sub_R2_R1 ) + INSTRUCTION( sub_IR2_R1 ) + INSTRUCTION( sub_R1_IM ) + INSTRUCTION( sub_IR1_IM ) + INSTRUCTION( and_r1_r2 ) + INSTRUCTION( and_r1_Ir2 ) + INSTRUCTION( and_R2_R1 ) + INSTRUCTION( and_IR2_R1 ) + INSTRUCTION( and_R1_IM ) + INSTRUCTION( and_IR1_IM ) + INSTRUCTION( com_R1 ) + INSTRUCTION( com_IR1 ) + INSTRUCTION( or_r1_r2 ) + INSTRUCTION( or_r1_Ir2 ) + INSTRUCTION( or_R2_R1 ) + INSTRUCTION( or_IR2_R1 ) + INSTRUCTION( or_R1_IM ) + INSTRUCTION( or_IR1_IM ) + INSTRUCTION( xor_r1_r2 ) + INSTRUCTION( xor_r1_Ir2 ) + INSTRUCTION( xor_R2_R1 ) + INSTRUCTION( xor_IR2_R1 ) + INSTRUCTION( xor_R1_IM ) + INSTRUCTION( xor_IR1_IM ) + INSTRUCTION( call_IRR1 ) + INSTRUCTION( call_DA ) + INSTRUCTION( djnz_r1_RA ) + INSTRUCTION( iret ) + INSTRUCTION( ret ) + INSTRUCTION( jp_IRR1 ) + INSTRUCTION( jp_cc_DA ) + INSTRUCTION( jr_cc_RA ) + INSTRUCTION( tcm_r1_r2 ) + INSTRUCTION( tcm_r1_Ir2 ) + INSTRUCTION( tcm_R2_R1 ) + INSTRUCTION( tcm_IR2_R1 ) + INSTRUCTION( tcm_R1_IM ) + INSTRUCTION( tcm_IR1_IM ) + INSTRUCTION( tm_r1_r2 ) + INSTRUCTION( tm_r1_Ir2 ) + INSTRUCTION( tm_R2_R1 ) + INSTRUCTION( tm_IR2_R1 ) + INSTRUCTION( tm_R1_IM ) + INSTRUCTION( tm_IR1_IM ) + INSTRUCTION( rl_R1 ) + INSTRUCTION( rl_IR1 ) + INSTRUCTION( rlc_R1 ) + INSTRUCTION( rlc_IR1 ) + INSTRUCTION( rr_R1 ) + INSTRUCTION( rr_IR1 ) + INSTRUCTION( rrc_R1 ) + INSTRUCTION( rrc_IR1 ) + INSTRUCTION( sra_R1 ) + INSTRUCTION( sra_IR1 ) + INSTRUCTION( swap_R1 ) + INSTRUCTION( swap_IR1 ) + INSTRUCTION( ccf ) + INSTRUCTION( di ) + INSTRUCTION( ei ) + INSTRUCTION( nop ) + INSTRUCTION( rcf ) + INSTRUCTION( scf ) + INSTRUCTION( srp_IM ) + #undef INSTRUCTION + + typedef void (z8_device::*z8_opcode_func) (UINT8 opcode, int *cycles); + struct z8_opcode_map + { + z8_opcode_func function; + int execution_cycles; + int pipeline_cycles; + }; + static const z8_opcode_map Z8601_OPCODE_MAP[256]; + +}; + + +class z8601_device : public z8_device +{ +public: + z8601_device(const machine_config &mconfig, const char *_tag, device_t *_owner, UINT32 _clock); +}; + + +class ub8830d_device : public z8_device +{ +public: + ub8830d_device(const machine_config &mconfig, const char *_tag, device_t *_owner, UINT32 _clock); +}; + + +class z8611_device : public z8_device +{ +public: + z8611_device(const machine_config &mconfig, const char *_tag, device_t *_owner, UINT32 _clock); +}; + + +/* Zilog Z8601 */ +extern const device_type Z8601; + +/* VEB Mikroelektronik Erfurt UB8830D MME */ +extern const device_type UB8830D; + +/* Zilog Z8611 */ +extern const device_type Z8611; + + +#endif diff --git a/src/devices/cpu/z8/z8dasm.c b/src/devices/cpu/z8/z8dasm.c new file mode 100644 index 00000000000..3801ca5c34b --- /dev/null +++ b/src/devices/cpu/z8/z8dasm.c @@ -0,0 +1,380 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +#include "emu.h" +#include "debugger.h" +#include "z8.h" + +/*************************************************************************** + CONSTANTS +***************************************************************************/ + +static const char *const REGISTER_NAME[256] = +{ + "P0", "P1", "P2", "P3", "", "", "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", + "SIO", "TMR", "T1", "PRE1", "T0", "PRE0", "P2M", "P3M", "P01M", "IPR", "IRQ", "IMR", "FLAGS", "RP", "SPH", "SPL" +}; + +static const char *const CONDITION_CODE[16] = +{ + "F", "LT", "LE", "ULE", "OV", "MI", "Z", "C", + "", "GE", "GT", "UGT", "NOV", "PL", "NZ", "NC" +}; + +/*************************************************************************** + MACROS +***************************************************************************/ + +#define r "R%u" +#define Ir "@R%u" +#define R "%02Xh" +#define RR "%02Xh" +#define IR "@%02Xh" +#define Irr "@RR%u" +#define IRR "@%02Xh" +#define IM "#%02Xh" +#define X "%02Xh(R%u)" +#define DA "%04Xh" +#define RA "%04Xh" + +#define B0 oprom[0] +#define B1 oprom[1] +#define B0H (B0 >> 4) +#define B0L (B0 & 0x0f) +#define OPH (opcode >> 4) + +#define ARG(_formatting, _value) { if (argc) dst += sprintf(dst, ", "); dst += sprintf(dst, _formatting, _value); argc++; } + +#define arg_name(_value) ARG("%s", REGISTER_NAME[_value]) +#define arg_cc ARG("%s", CONDITION_CODE[OPH]) +#define arg_r(_value) ARG(r, _value) +#define arg_Ir(_value) ARG(Ir, _value) +#define arg_Irr(_value) ARG(Irr, _value & 0x0f) +#define arg_R(_value) if ((_value & 0xf0) == 0xe0) ARG(r, _value & 0x0f) else if ((_value < 4) || (_value >= 0xf0)) arg_name(_value) else ARG(R, _value) +#define arg_RR(_value) if ((_value & 0xf0) == 0xe0) ARG(r, _value & 0x0f) else ARG(R, _value) +#define arg_IR(_value) if ((_value & 0xf0) == 0xe0) ARG(Ir, _value & 0x0f) else ARG(IR, _value) +#define arg_IRR(_value) if ((_value & 0xf0) == 0xe0) ARG(Irr, _value & 0x0f) else ARG(IRR, _value) +#define arg_IM(_value) ARG(IM, _value) +#define arg_RA ARG(RA, pc + (INT8)B0 + 2) +#define arg_DA ARG(DA, B0 << 8 | B1) +#define arg_X(_value1, _value2) { if (argc) dst += sprintf(dst, ", "); dst += sprintf(dst, X, _value1, _value2); argc++; } + +#define illegal dst += sprintf(dst, "Illegal") +#define mnemonic(_mnemonic) dst += sprintf(dst, "%-5s", _mnemonic) +#define bytes(_count) oprom += (_count - 1) +#define step_over flags = DASMFLAG_STEP_OVER +#define step_out flags = DASMFLAG_STEP_OUT + +/*************************************************************************** + DISASSEMBLER +***************************************************************************/ + +CPU_DISASSEMBLE( z8 ) +{ + const UINT8 *startrom = oprom; + UINT32 flags = 0; + UINT8 opcode = *oprom++; + char *dst = buffer; + int argc = 0; + + switch (pc) + { + case 0x0000: + case 0x0002: + case 0x0004: + case 0x0006: + case 0x0008: + case 0x000a: + sprintf(buffer, "IRQ%u Vector %04Xh", pc / 2, opcode << 8 | *oprom++); break; + default: + switch (opcode) + { + case 0x00: mnemonic("DEC"); arg_R(B0); bytes(2); break; + case 0x01: mnemonic("DEC"); arg_IR(B0); bytes(2); break; + case 0x02: mnemonic("ADD"); arg_r(B0H); arg_r(B0L); bytes(2); break; + case 0x03: mnemonic("ADD"); arg_r(B0H); arg_Ir(B0L); bytes(2); break; + case 0x04: mnemonic("ADD"); arg_R(B1); arg_R(B0); bytes(3); break; + case 0x05: mnemonic("ADD"); arg_R(B1); arg_IR(B0); bytes(3); break; + case 0x06: mnemonic("ADD"); arg_R(B0); arg_IM(B1); bytes(3); break; + case 0x07: mnemonic("ADD"); arg_IR(B0); arg_IM(B1); bytes(3); break; + case 0x08: mnemonic("LD"); arg_r(OPH); arg_R(B0); bytes(2); break; + case 0x09: mnemonic("LD"); arg_R(B0); arg_r(OPH); bytes(2); break; + case 0x0a: mnemonic("DJNZ"); arg_r(OPH); arg_RA; bytes(2); break; + case 0x0b: mnemonic("JR"); arg_cc; arg_RA; bytes(2); break; + case 0x0c: mnemonic("LD"); arg_r(OPH); arg_IM(B0); bytes(2); break; + case 0x0d: mnemonic("JP"); arg_cc; arg_DA; bytes(3); break; + case 0x0e: mnemonic("INC"); arg_r(OPH); break; + case 0x0f: illegal; break; + + case 0x10: mnemonic("RLC"); arg_R(B0); bytes(2); break; + case 0x11: mnemonic("RLC"); arg_IR(B0); bytes(2); break; + case 0x12: mnemonic("ADC"); arg_r(B0H); arg_r(B0L); bytes(2); break; + case 0x13: mnemonic("ADC"); arg_r(B0H); arg_Ir(B0L); bytes(2); break; + case 0x14: mnemonic("ADC"); arg_R(B1); arg_R(B0); bytes(3); break; + case 0x15: mnemonic("ADC"); arg_R(B1); arg_IR(B0); bytes(3); break; + case 0x16: mnemonic("ADC"); arg_R(B0); arg_IM(B1); bytes(3); break; + case 0x17: mnemonic("ADC"); arg_IR(B0); arg_IM(B1); bytes(3); break; + case 0x18: mnemonic("LD"); arg_r(OPH); arg_R(B0); bytes(2); break; + case 0x19: mnemonic("LD"); arg_R(B0); arg_r(OPH); bytes(2); break; + case 0x1a: mnemonic("DJNZ"); arg_r(OPH); arg_RA; bytes(2); break; + case 0x1b: mnemonic("JR"); arg_cc; arg_RA; bytes(2); break; + case 0x1c: mnemonic("LD"); arg_r(OPH); arg_IM(B0); bytes(2); break; + case 0x1d: mnemonic("JP"); arg_cc; arg_DA; bytes(3); break; + case 0x1e: mnemonic("INC"); arg_r(OPH); break; + case 0x1f: illegal; break; + + case 0x20: mnemonic("INC"); arg_R(B0); bytes(2); break; + case 0x21: mnemonic("INC"); arg_IR(B0); bytes(2); break; + case 0x22: mnemonic("SUB"); arg_r(B0H); arg_r(B0L); bytes(2); break; + case 0x23: mnemonic("SUB"); arg_r(B0H); arg_Ir(B0L); bytes(2); break; + case 0x24: mnemonic("SUB"); arg_R(B1); arg_R(B0); bytes(3); break; + case 0x25: mnemonic("SUB"); arg_R(B1); arg_IR(B0); bytes(3); break; + case 0x26: mnemonic("SUB"); arg_R(B0); arg_IM(B1); bytes(3); break; + case 0x27: mnemonic("SUB"); arg_IR(B0); arg_IM(B1); bytes(3); break; + case 0x28: mnemonic("LD"); arg_r(OPH); arg_R(B0); bytes(2); break; + case 0x29: mnemonic("LD"); arg_R(B0); arg_r(OPH); bytes(2); break; + case 0x2a: mnemonic("DJNZ"); arg_r(OPH); arg_RA; bytes(2); break; + case 0x2b: mnemonic("JR"); arg_cc; arg_RA; bytes(2); break; + case 0x2c: mnemonic("LD"); arg_r(OPH); arg_IM(B0); bytes(2); break; + case 0x2d: mnemonic("JP"); arg_cc; arg_DA; bytes(3); break; + case 0x2e: mnemonic("INC"); arg_r(OPH); break; + case 0x2f: illegal; break; + + case 0x30: mnemonic("JP"); arg_IRR(B0); bytes(2); break; + case 0x31: mnemonic("SRP"); arg_IM(*oprom++); break; + case 0x32: mnemonic("SBC"); arg_r(B0H); arg_r(B0L); bytes(2); break; + case 0x33: mnemonic("SBC"); arg_r(B0H); arg_Ir(B0L); bytes(2); break; + case 0x34: mnemonic("SBC"); arg_R(B1); arg_R(B0); bytes(3); break; + case 0x35: mnemonic("SBC"); arg_R(B1); arg_IR(B0); bytes(3); break; + case 0x36: mnemonic("SBC"); arg_R(B0); arg_IM(B1); bytes(3); break; + case 0x37: mnemonic("SBC"); arg_IR(B0); arg_IM(B1); bytes(3); break; + case 0x38: mnemonic("LD"); arg_r(OPH); arg_R(B0); bytes(2); break; + case 0x39: mnemonic("LD"); arg_R(B0); arg_r(OPH); bytes(2); break; + case 0x3a: mnemonic("DJNZ"); arg_r(OPH); arg_RA; bytes(2); break; + case 0x3b: mnemonic("JR"); arg_cc; arg_RA; bytes(2); break; + case 0x3c: mnemonic("LD"); arg_r(OPH); arg_IM(B0); bytes(2); break; + case 0x3d: mnemonic("JP"); arg_cc; arg_DA; bytes(3); break; + case 0x3e: mnemonic("INC"); arg_r(OPH); break; + case 0x3f: illegal; break; + + case 0x40: mnemonic("DA"); arg_R(B0); bytes(2); break; + case 0x41: mnemonic("DA"); arg_IR(B0); bytes(2); break; + case 0x42: mnemonic("OR"); arg_r(B0H); arg_r(B0L); bytes(2); break; + case 0x43: mnemonic("OR"); arg_r(B0H); arg_Ir(B0L); bytes(2); break; + case 0x44: mnemonic("OR"); arg_R(B1); arg_R(B0); bytes(3); break; + case 0x45: mnemonic("OR"); arg_R(B1); arg_IR(B0); bytes(3); break; + case 0x46: mnemonic("OR"); arg_R(B0); arg_IM(B1); bytes(3); break; + case 0x47: mnemonic("OR"); arg_IR(B0); arg_IM(B1); bytes(3); break; + case 0x48: mnemonic("LD"); arg_r(OPH); arg_R(B0); bytes(2); break; + case 0x49: mnemonic("LD"); arg_R(B0); arg_r(OPH); bytes(2); break; + case 0x4a: mnemonic("DJNZ"); arg_r(OPH); arg_RA; bytes(2); break; + case 0x4b: mnemonic("JR"); arg_cc; arg_RA; bytes(2); break; + case 0x4c: mnemonic("LD"); arg_r(OPH); arg_IM(B0); bytes(2); break; + case 0x4d: mnemonic("JP"); arg_cc; arg_DA; bytes(3); break; + case 0x4e: mnemonic("INC"); arg_r(OPH); break; + case 0x4f: illegal; /* mnemonic("WDH"); */ break; + + case 0x50: mnemonic("POP"); arg_R(B0); bytes(2); break; + case 0x51: mnemonic("POP"); arg_IR(B0); bytes(2); break; + case 0x52: mnemonic("AND"); arg_r(B0H); arg_r(B0L); bytes(2); break; + case 0x53: mnemonic("AND"); arg_r(B0H); arg_Ir(B0L); bytes(2); break; + case 0x54: mnemonic("AND"); arg_R(B1); arg_R(B0); bytes(3); break; + case 0x55: mnemonic("AND"); arg_R(B1); arg_IR(B0); bytes(3); break; + case 0x56: mnemonic("AND"); arg_R(B0); arg_IM(B1); bytes(3); break; + case 0x57: mnemonic("AND"); arg_IR(B0); arg_IM(B1); bytes(3); break; + case 0x58: mnemonic("LD"); arg_r(OPH); arg_R(B0); bytes(2); break; + case 0x59: mnemonic("LD"); arg_R(B0); arg_r(OPH); bytes(2); break; + case 0x5a: mnemonic("DJNZ"); arg_r(OPH); arg_RA; bytes(2); break; + case 0x5b: mnemonic("JR"); arg_cc; arg_RA; bytes(2); break; + case 0x5c: mnemonic("LD"); arg_r(OPH); arg_IM(B0); bytes(2); break; + case 0x5d: mnemonic("JP"); arg_cc; arg_DA; bytes(3); break; + case 0x5e: mnemonic("INC"); arg_r(OPH); break; + case 0x5f: illegal; /* mnemonic("WDT"); */ break; + + case 0x60: mnemonic("COM"); arg_R(B0); bytes(2); break; + case 0x61: mnemonic("COM"); arg_IR(B0); bytes(2); break; + case 0x62: mnemonic("TCM"); arg_r(B0H); arg_r(B0L); bytes(2); break; + case 0x63: mnemonic("TCM"); arg_r(B0H); arg_Ir(B0L); bytes(2); break; + case 0x64: mnemonic("TCM"); arg_R(B1); arg_R(B0); bytes(3); break; + case 0x65: mnemonic("TCM"); arg_R(B1); arg_IR(B0); bytes(3); break; + case 0x66: mnemonic("TCM"); arg_R(B0); arg_IM(B1); bytes(3); break; + case 0x67: mnemonic("TCM"); arg_IR(B0); arg_IM(B1); bytes(3); break; + case 0x68: mnemonic("LD"); arg_r(OPH); arg_R(B0); bytes(2); break; + case 0x69: mnemonic("LD"); arg_R(B0); arg_r(OPH); bytes(2); break; + case 0x6a: mnemonic("DJNZ"); arg_r(OPH); arg_RA; bytes(2); break; + case 0x6b: mnemonic("JR"); arg_cc; arg_RA; bytes(2); break; + case 0x6c: mnemonic("LD"); arg_r(OPH); arg_IM(B0); bytes(2); break; + case 0x6d: mnemonic("JP"); arg_cc; arg_DA; bytes(3); break; + case 0x6e: mnemonic("INC"); arg_r(OPH); break; + case 0x6f: illegal; /* mnemonic("STOP"); */ break; + + case 0x70: mnemonic("PUSH"); arg_R(B0); bytes(2); break; + case 0x71: mnemonic("PUSH"); arg_IR(B0); bytes(2); break; + case 0x72: mnemonic("TM"); arg_r(B0H); arg_r(B0L); bytes(2); break; + case 0x73: mnemonic("TM"); arg_r(B0H); arg_Ir(B0L); bytes(2); break; + case 0x74: mnemonic("TM"); arg_R(B1); arg_R(B0); bytes(3); break; + case 0x75: mnemonic("TM"); arg_R(B1); arg_IR(B0); bytes(3); break; + case 0x76: mnemonic("TM"); arg_R(B0); arg_IM(B1); bytes(3); break; + case 0x77: mnemonic("TM"); arg_IR(B0); arg_IM(B1); bytes(3); break; + case 0x78: mnemonic("LD"); arg_r(OPH); arg_R(B0); bytes(2); break; + case 0x79: mnemonic("LD"); arg_R(B0); arg_r(OPH); bytes(2); break; + case 0x7a: mnemonic("DJNZ"); arg_r(OPH); arg_RA; bytes(2); break; + case 0x7b: mnemonic("JR"); arg_cc; arg_RA; bytes(2); break; + case 0x7c: mnemonic("LD"); arg_r(OPH); arg_IM(B0); bytes(2); break; + case 0x7d: mnemonic("JP"); arg_cc; arg_DA; bytes(3); break; + case 0x7e: mnemonic("INC"); arg_r(OPH); break; + case 0x7f: illegal; /* mnemonic("HALT"); */ break; + + case 0x80: mnemonic("DECW"); arg_RR(*oprom++); break; + case 0x81: mnemonic("DECW"); arg_IR(B0); bytes(2); break; + case 0x82: mnemonic("LDE"); arg_r(B0H); arg_Irr(B0L); bytes(2); break; + case 0x83: mnemonic("LDEI"); arg_Ir(B0H); arg_Irr(B0L); bytes(2); break; + case 0x84: illegal; break; + case 0x85: illegal; break; + case 0x86: illegal; break; + case 0x87: illegal; break; + case 0x88: mnemonic("LD"); arg_r(OPH); arg_R(B0); bytes(2); break; + case 0x89: mnemonic("LD"); arg_R(B0); arg_r(OPH); bytes(2); break; + case 0x8a: mnemonic("DJNZ"); arg_r(OPH); arg_RA; bytes(2); break; + case 0x8b: mnemonic("JR"); arg_RA; bytes(2); break; + case 0x8c: mnemonic("LD"); arg_r(OPH); arg_IM(B0); bytes(2); break; + case 0x8d: mnemonic("JP"); arg_DA; bytes(3); break; + case 0x8e: mnemonic("INC"); arg_r(OPH); break; + case 0x8f: mnemonic("DI"); break; + + case 0x90: mnemonic("RL"); arg_R(B0); bytes(2); break; + case 0x91: mnemonic("RL"); arg_IR(B0); bytes(2); break; + case 0x92: mnemonic("LDE"); arg_r(B0L); arg_Irr(B0H); bytes(2); break; + case 0x93: mnemonic("LDEI"); arg_Ir(B0L); arg_Irr(B0H); bytes(2); break; + case 0x94: illegal; break; + case 0x95: illegal; break; + case 0x96: illegal; break; + case 0x97: illegal; break; + case 0x98: mnemonic("LD"); arg_r(OPH); arg_R(B0); bytes(2); break; + case 0x99: mnemonic("LD"); arg_R(B0); arg_r(OPH); bytes(2); break; + case 0x9a: mnemonic("DJNZ"); arg_r(OPH); arg_RA; bytes(2); break; + case 0x9b: mnemonic("JR"); arg_cc; arg_RA; bytes(2); break; + case 0x9c: mnemonic("LD"); arg_r(OPH); arg_IM(B0); bytes(2); break; + case 0x9d: mnemonic("JP"); arg_cc; arg_DA; bytes(3); break; + case 0x9e: mnemonic("INC"); arg_r(OPH); break; + case 0x9f: mnemonic("EI"); break; + + case 0xa0: mnemonic("INCW"); arg_RR(B0); bytes(2); break; + case 0xa1: mnemonic("INCW"); arg_IR(B0); bytes(2); break; + case 0xa2: mnemonic("CP"); arg_r(B0H); arg_r(B0L); bytes(2); break; + case 0xa3: mnemonic("CP"); arg_r(B0H); arg_Ir(B0L); bytes(2); break; + case 0xa4: mnemonic("CP"); arg_R(B1); arg_R(B0); bytes(3); break; + case 0xa5: mnemonic("CP"); arg_R(B1); arg_IR(B0); bytes(3); break; + case 0xa6: mnemonic("CP"); arg_R(B0); arg_IM(B1); bytes(3); break; + case 0xa7: mnemonic("CP"); arg_IR(B0); arg_IM(B1); bytes(3); break; + case 0xa8: mnemonic("LD"); arg_r(OPH); arg_R(B0); bytes(2); break; + case 0xa9: mnemonic("LD"); arg_R(B0); arg_r(OPH); bytes(2); break; + case 0xaa: mnemonic("DJNZ"); arg_r(OPH); arg_RA; bytes(2); break; + case 0xab: mnemonic("JR"); arg_cc; arg_RA; bytes(2); break; + case 0xac: mnemonic("LD"); arg_r(OPH); arg_IM(B0); bytes(2); break; + case 0xad: mnemonic("JP"); arg_cc; arg_DA; bytes(3); break; + case 0xae: mnemonic("INC"); arg_r(OPH); break; + case 0xaf: mnemonic("RET"); step_out; break; + + case 0xb0: mnemonic("CLR"); arg_R(B0); bytes(2); break; + case 0xb1: mnemonic("CLR"); arg_IR(B0); bytes(2); break; + case 0xb2: mnemonic("XOR"); arg_r(B0H); arg_r(B0L); bytes(2); break; + case 0xb3: mnemonic("XOR"); arg_r(B0H); arg_Ir(B0L); bytes(2); break; + case 0xb4: mnemonic("XOR"); arg_R(B1); arg_R(B0); bytes(3); break; + case 0xb5: mnemonic("XOR"); arg_R(B1); arg_IR(B0); bytes(3); break; + case 0xb6: mnemonic("XOR"); arg_R(B0); arg_IM(B1); bytes(3); break; + case 0xb7: mnemonic("XOR"); arg_IR(B0); arg_IM(B1); bytes(3); break; + case 0xb8: mnemonic("LD"); arg_r(OPH); arg_R(B0); bytes(2); break; + case 0xb9: mnemonic("LD"); arg_R(B0); arg_r(OPH); bytes(2); break; + case 0xba: mnemonic("DJNZ"); arg_r(OPH); arg_RA; bytes(2); break; + case 0xbb: mnemonic("JR"); arg_cc; arg_RA; bytes(2); break; + case 0xbc: mnemonic("LD"); arg_r(OPH); arg_IM(B0); bytes(2); break; + case 0xbd: mnemonic("JP"); arg_cc; arg_DA; bytes(3); break; + case 0xbe: mnemonic("INC"); arg_r(OPH); break; + case 0xbf: mnemonic("IRET"); step_out; break; + + case 0xc0: mnemonic("RRC"); arg_R(B0); bytes(2); break; + case 0xc1: mnemonic("RRC"); arg_IR(B0); bytes(2); break; + case 0xc2: mnemonic("LDC"); arg_r(B0H); arg_Irr(B0L); bytes(2); break; + case 0xc3: mnemonic("LDCI"); arg_Ir(B0H); arg_Irr(B0L); bytes(2); break; + case 0xc4: illegal; break; + case 0xc5: illegal; break; + case 0xc6: illegal; break; + case 0xc7: mnemonic("LD"); arg_r(B0H); arg_X(B1, B0L); bytes(3); break; + case 0xc8: mnemonic("LD"); arg_r(OPH); arg_R(B0); bytes(2); break; + case 0xc9: mnemonic("LD"); arg_R(B0); arg_r(OPH); bytes(2); break; + case 0xca: mnemonic("DJNZ"); arg_r(OPH); arg_RA; bytes(2); break; + case 0xcb: mnemonic("JR"); arg_cc; arg_RA; bytes(2); break; + case 0xcc: mnemonic("LD"); arg_r(OPH); arg_IM(B0); bytes(2); break; + case 0xcd: mnemonic("JP"); arg_cc; arg_DA; bytes(3); break; + case 0xce: mnemonic("INC"); arg_r(OPH); break; + case 0xcf: mnemonic("RCF"); break; + + case 0xd0: mnemonic("SRA"); arg_R(B0); bytes(2); break; + case 0xd1: mnemonic("SRA"); arg_IR(B0); bytes(2); break; + case 0xd2: mnemonic("LDC"); arg_Irr(B0L); arg_r(B0H); bytes(2); break; + case 0xd3: mnemonic("LDCI"); arg_Irr(B0L); arg_Ir(B0H); bytes(2); break; + case 0xd4: mnemonic("CALL"); arg_IRR(B0); bytes(2); step_over; break; + case 0xd5: illegal; break; + case 0xd6: mnemonic("CALL"); arg_DA; bytes(3); step_over; break; + case 0xd7: mnemonic("LD"); arg_r(B0L); arg_X(B1, B0H); bytes(3); break; + case 0xd8: mnemonic("LD"); arg_r(OPH); arg_R(B0); bytes(2); break; + case 0xd9: mnemonic("LD"); arg_R(B0); arg_r(OPH); bytes(2); break; + case 0xda: mnemonic("DJNZ"); arg_r(OPH); arg_RA; bytes(2); break; + case 0xdb: mnemonic("JR"); arg_cc; arg_RA; bytes(2); break; + case 0xdc: mnemonic("LD"); arg_r(OPH); arg_IM(B0); bytes(2); break; + case 0xdd: mnemonic("JP"); arg_cc; arg_DA; bytes(3); break; + case 0xde: mnemonic("INC"); arg_r(OPH); break; + case 0xdf: mnemonic("SCF"); break; + + case 0xe0: mnemonic("RR"); arg_R(B0); bytes(2); break; + case 0xe1: mnemonic("RR"); arg_IR(B0); bytes(2); break; + case 0xe2: illegal; break; + case 0xe3: mnemonic("LD"); arg_r(B0H); arg_Ir(B0L); bytes(2); break; + case 0xe4: mnemonic("LD"); arg_R(B1); arg_R(B0); bytes(3); break; + case 0xe5: mnemonic("LD"); arg_R(B1); arg_IR(B0); bytes(3); break; + case 0xe6: mnemonic("LD"); arg_R(B0); arg_IM(B1); bytes(3); break; + case 0xe7: mnemonic("LD"); arg_IR(B0); arg_IM(B1); bytes(3); break; + case 0xe8: mnemonic("LD"); arg_r(OPH); arg_R(B0); bytes(2); break; + case 0xe9: mnemonic("LD"); arg_R(B0); arg_r(OPH); bytes(2); break; + case 0xea: mnemonic("DJNZ"); arg_r(OPH); arg_RA; bytes(2); break; + case 0xeb: mnemonic("JR"); arg_cc; arg_RA; bytes(2); break; + case 0xec: mnemonic("LD"); arg_r(OPH); arg_IM(B0); bytes(2); break; + case 0xed: mnemonic("JP"); arg_cc; arg_DA; bytes(3); break; + case 0xee: mnemonic("INC"); arg_r(OPH); break; + case 0xef: mnemonic("CCF"); break; + + case 0xf0: mnemonic("SWAP"); arg_R(B0); bytes(2); break; + case 0xf1: mnemonic("SWAP"); arg_IR(B0); bytes(2); break; + case 0xf2: illegal; break; + case 0xf3: mnemonic("LD"); arg_Ir(B0H); arg_r(B0L); bytes(2); break; + case 0xf4: illegal; break; + case 0xf5: mnemonic("LD"); arg_IR(B0); arg_R(B1); bytes(3); break; + case 0xf6: illegal; break; + case 0xf7: illegal; break; + case 0xf8: mnemonic("LD"); arg_r(OPH); arg_R(B0); bytes(2); break; + case 0xf9: mnemonic("LD"); arg_R(B0); arg_r(OPH); bytes(2); break; + case 0xfa: mnemonic("DJNZ"); arg_r(OPH); arg_RA; bytes(2); break; + case 0xfb: mnemonic("JR"); arg_cc; arg_RA; bytes(2); break; + case 0xfc: mnemonic("LD"); arg_r(OPH); arg_IM(B0); bytes(2); break; + case 0xfd: mnemonic("JP"); arg_cc; arg_DA; bytes(3); break; + case 0xfe: mnemonic("INC"); arg_r(OPH); break; + case 0xff: mnemonic("NOP"); break; + } + } + + return (oprom - startrom) | flags | DASMFLAG_SUPPORTED; +} diff --git a/src/devices/cpu/z8/z8ops.inc b/src/devices/cpu/z8/z8ops.inc new file mode 100644 index 00000000000..4c522791b8e --- /dev/null +++ b/src/devices/cpu/z8/z8ops.inc @@ -0,0 +1,745 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Zilog Z8 Single-Chip MCU emulation + +**********************************************************************/ + +/*************************************************************************** + MACROS +***************************************************************************/ + +#define read(_reg) register_read(_reg) +#define r(_data) get_working_register(_data) +#define Ir(_data) get_intermediate_register(get_working_register(_data)) +#define R get_register(fetch()) +#define IR get_intermediate_register(get_register(fetch())) +#define RR get_intermediate_register(get_register(fetch())) +#define IM fetch() +#define flag(_flag) ((m_r[Z8_REGISTER_FLAGS] & Z8_FLAGS##_##_flag) ? 1 : 0) + +#define mode_r1_r2(_func) \ + UINT8 dst_src = fetch();\ + UINT8 dst = r(dst_src >> 4);\ + UINT8 src = read(r(dst_src & 0x0f));\ + _func(dst, src); + +#define mode_r1_Ir2(_func) \ + UINT8 dst_src = fetch();\ + UINT8 dst = r(dst_src >> 4);\ + UINT8 src = read(Ir(dst_src & 0x0f));\ + _func(dst, src); + +#define mode_R2_R1(_func) \ + UINT8 src = read(R);\ + UINT8 dst = R;\ + _func(dst, src); + +#define mode_IR2_R1(_func) \ + UINT8 src = read(R);\ + UINT8 dst = IR;\ + _func(dst, src); + +#define mode_R1_IM(_func) \ + UINT8 dst = R;\ + UINT8 src = IM;\ + _func(dst, src); + +#define mode_IR1_IM(_func) \ + UINT8 dst = IR;\ + UINT8 src = IM;\ + _func(dst, src); + +#define mode_r1(_func) \ + UINT8 dst = r(opcode >> 4);\ + _func(dst); + +#define mode_R1(_func) \ + UINT8 dst = R;\ + _func(dst); + +#define mode_RR1(_func) \ + UINT8 dst = R;\ + _func(dst); + +#define mode_IR1(_func) \ + UINT8 dst = IR;\ + _func(dst); + +#define mode_r1_IM(_func) \ + UINT8 dst = r(opcode >> 4);\ + UINT8 src = IM;\ + _func(dst, src); + +#define mode_r1_R2(_func) \ + UINT8 dst = r(opcode >> 4);\ + UINT8 src = read(R);\ + _func(dst, src); + +#define mode_r2_R1(_func) \ + UINT8 src = read(r(opcode >> 4));\ + UINT8 dst = R;\ + _func(dst, src); + +#define mode_Ir1_r2(_func) \ + UINT8 dst_src = fetch();\ + UINT8 dst = Ir(dst_src >> 4);\ + UINT8 src = read(r(dst_src & 0x0f));\ + _func(dst, src); + +#define mode_R2_IR1(_func) \ + UINT8 src = read(R);\ + UINT8 dst = IR;\ + _func(dst, src); + +#define mode_r1_x_R2(_func) \ + UINT8 dst_src = fetch();\ + UINT8 dst = r(dst_src >> 4);\ + UINT8 src = read(read(r(dst_src & 0x0f)) + R);\ + _func(dst, src); + +#define mode_r2_x_R1(_func) \ + UINT8 dst_src = fetch();\ + UINT8 dst = R + read(r(dst_src & 0x0f));\ + UINT8 src = read(r(dst_src >> 4));\ + _func(dst, src); + +/*************************************************************************** + LOAD INSTRUCTIONS +***************************************************************************/ + +void z8_device::clear(UINT8 dst) +{ + /* dst <- 0 */ + register_write(dst, 0); +} + +INSTRUCTION( clr_R1 ) { mode_R1(clear) } +INSTRUCTION( clr_IR1 ) { mode_IR1(clear) } + +void z8_device::load(UINT8 dst, UINT8 src) +{ + /* dst <- src */ + register_write(dst, src); +} + +INSTRUCTION( ld_r1_IM ) { mode_r1_IM(load) } +INSTRUCTION( ld_r1_R2 ) { mode_r1_R2(load) } +INSTRUCTION( ld_r2_R1 ) { mode_r2_R1(load) } +INSTRUCTION( ld_Ir1_r2 ) { mode_Ir1_r2(load) } +INSTRUCTION( ld_R2_IR1 ) { mode_R2_IR1(load) } +INSTRUCTION( ld_r1_x_R2 ) { mode_r1_x_R2(load) } +INSTRUCTION( ld_r2_x_R1 ) { mode_r2_x_R1(load) } + +INSTRUCTION( ld_r1_r2 ) { mode_r1_r2(load) } +INSTRUCTION( ld_r1_Ir2 ) { mode_r1_Ir2(load) } +INSTRUCTION( ld_R2_R1 ) { mode_R2_R1(load) } +INSTRUCTION( ld_IR2_R1 ) { mode_IR2_R1(load) } +INSTRUCTION( ld_R1_IM ) { mode_R1_IM(load) } +INSTRUCTION( ld_IR1_IM ) { mode_IR1_IM(load) } + +void z8_device::load_from_memory(address_space *space) +{ + UINT8 operands = fetch(); + UINT8 dst = get_working_register(operands >> 4); + UINT8 src = get_working_register(operands & 0x0f); + + UINT16 address = register_pair_read(src); + UINT8 data = m_direct->read_byte(address); + + register_write(dst, data); +} + +void z8_device::load_to_memory(address_space *space) +{ + UINT8 operands = fetch(); + UINT8 src = get_working_register(operands >> 4); + UINT8 dst = get_working_register(operands & 0x0f); + + UINT16 address = register_pair_read(dst); + UINT8 data = register_read(src); + + m_program->write_byte(address, data); +} + +void z8_device::load_from_memory_autoinc(address_space *space) +{ + UINT8 operands = fetch(); + UINT8 dst = get_working_register(operands >> 4); + UINT8 real_dst = get_intermediate_register(dst); + UINT8 src = get_working_register(operands & 0x0f); + + UINT16 address = register_pair_read(src); + UINT8 data = m_direct->read_byte(address); + + register_write(real_dst, data); + + register_write(dst, real_dst + 1); + register_pair_write(src, address + 1); +} + +void z8_device::load_to_memory_autoinc(address_space *space) +{ + UINT8 operands = fetch(); + UINT8 src = get_working_register(operands >> 4); + UINT8 dst = get_working_register(operands & 0x0f); + UINT8 real_src = get_intermediate_register(src); + + UINT16 address = register_pair_read(dst); + UINT8 data = register_read(real_src); + + m_program->write_byte(address, data); + + register_pair_write(dst, address + 1); + register_write(src, real_src + 1); +} + +INSTRUCTION( ldc_r1_Irr2 ) { load_from_memory(m_program); } +INSTRUCTION( ldc_r2_Irr1 ) { load_to_memory(m_program); } +INSTRUCTION( ldci_Ir1_Irr2 ) { load_from_memory_autoinc(m_program); } +INSTRUCTION( ldci_Ir2_Irr1 ) { load_to_memory_autoinc(m_program); } +INSTRUCTION( lde_r1_Irr2 ) { load_from_memory(m_data); } +INSTRUCTION( lde_r2_Irr1 ) { load_to_memory(m_data); } +INSTRUCTION( ldei_Ir1_Irr2 ) { load_from_memory_autoinc(m_data); } +INSTRUCTION( ldei_Ir2_Irr1 ) { load_to_memory_autoinc(m_data); } + +void z8_device::pop(UINT8 dst) +{ + /* dst <- @SP + SP <- SP + 1 */ + register_write(dst, stack_pop_byte()); +} + +INSTRUCTION( pop_R1 ) { mode_R1(pop) } +INSTRUCTION( pop_IR1 ) { mode_IR1(pop) } + +void z8_device::push(UINT8 src) +{ + /* SP <- SP - 1 + @SP <- src */ + stack_push_byte(read(src)); +} + +INSTRUCTION( push_R2 ) { mode_R1(push) } +INSTRUCTION( push_IR2 ) { mode_IR1(push) } + +/*************************************************************************** + ARITHMETIC INSTRUCTIONS +***************************************************************************/ + +void z8_device::add_carry(UINT8 dst, INT8 src) +{ + /* dst <- dst + src + C */ + UINT8 data = register_read(dst); + UINT16 new_data = data + src + flag(C); + + set_flag_c(new_data & 0x100); + set_flag_z(new_data == 0); + set_flag_s(new_data & 0x80); + set_flag_v(((data & 0x80) == (src & 0x80)) && ((new_data & 0x80) != (src & 0x80))); + set_flag_d(0); + set_flag_h(((data & 0x1f) == 0x0f) && ((new_data & 0x1f) == 0x10)); + + register_write(dst, new_data & 0xff); +} + +INSTRUCTION( adc_r1_r2 ) { mode_r1_r2(add_carry) } +INSTRUCTION( adc_r1_Ir2 ) { mode_r1_Ir2(add_carry) } +INSTRUCTION( adc_R2_R1 ) { mode_R2_R1(add_carry) } +INSTRUCTION( adc_IR2_R1 ) { mode_IR2_R1(add_carry) } +INSTRUCTION( adc_R1_IM ) { mode_R1_IM(add_carry) } +INSTRUCTION( adc_IR1_IM ) { mode_IR1_IM(add_carry) } + +void z8_device::add(UINT8 dst, INT8 src) +{ + /* dst <- dst + src */ + UINT8 data = register_read(dst); + UINT16 new_data = data + src; + + set_flag_c(new_data & 0x100); + set_flag_z(new_data == 0); + set_flag_s(new_data & 0x80); + set_flag_v(((data & 0x80) == (src & 0x80)) && ((new_data & 0x80) != (src & 0x80))); + set_flag_d(0); + set_flag_h(((data & 0x1f) == 0x0f) && ((new_data & 0x1f) == 0x10)); + + register_write(dst, new_data & 0xff); +} + +INSTRUCTION( add_r1_r2 ) { mode_r1_r2(add) } +INSTRUCTION( add_r1_Ir2 ) { mode_r1_Ir2(add) } +INSTRUCTION( add_R2_R1 ) { mode_R2_R1(add) } +INSTRUCTION( add_IR2_R1 ) { mode_IR2_R1(add) } +INSTRUCTION( add_R1_IM ) { mode_R1_IM(add) } +INSTRUCTION( add_IR1_IM ) { mode_IR1_IM(add) } + +void z8_device::compare(UINT8 dst, UINT8 src) +{ + /* dst - src */ + UINT8 data = register_read(dst); + UINT16 new_data = data - src; + + set_flag_c(!(new_data & 0x100)); + set_flag_z(new_data == 0); + set_flag_s(new_data & 0x80); + set_flag_v(((data & 0x80) != (src & 0x80)) && ((new_data & 0x80) == (src & 0x80))); +} + +INSTRUCTION( cp_r1_r2 ) { mode_r1_r2(compare) } +INSTRUCTION( cp_r1_Ir2 ) { mode_r1_Ir2(compare) } +INSTRUCTION( cp_R2_R1 ) { mode_R2_R1(compare) } +INSTRUCTION( cp_IR2_R1 ) { mode_IR2_R1(compare) } +INSTRUCTION( cp_R1_IM ) { mode_R1_IM(compare) } +INSTRUCTION( cp_IR1_IM ) { mode_IR1_IM(compare) } + +void z8_device::decimal_adjust(UINT8 dst) +{ +} + +INSTRUCTION( da_R1 ) { mode_R1(decimal_adjust) } +INSTRUCTION( da_IR1 ) { mode_IR1(decimal_adjust) } + +void z8_device::decrement(UINT8 dst) +{ + /* dst <- dst - 1 */ + UINT8 data = register_read(dst) - 1; + + set_flag_z(data == 0); + set_flag_s(data & 0x80); + set_flag_v(data == 0x7f); + + register_write(dst, data); +} + +INSTRUCTION( dec_R1 ) { mode_R1(decrement) } +INSTRUCTION( dec_IR1 ) { mode_IR1(decrement) } + +void z8_device::decrement_word(UINT8 dst) +{ + /* dst <- dst - 1 */ + UINT16 data = register_pair_read(dst) - 1; + + set_flag_z(data == 0); + set_flag_s(data & 0x8000); + set_flag_v(data == 0x7fff); + + register_pair_write(dst, data); +} + +INSTRUCTION( decw_RR1 ) { mode_RR1(decrement_word) } +INSTRUCTION( decw_IR1 ) { mode_IR1(decrement_word) } + +void z8_device::increment(UINT8 dst) +{ + /* dst <- dst + 1 */ + UINT8 data = register_read(dst) + 1; + + set_flag_z(data == 0); + set_flag_s(data & 0x80); + set_flag_v(data == 0x80); + + register_write(dst, data); +} + +INSTRUCTION( inc_r1 ) { mode_r1(increment) } +INSTRUCTION( inc_R1 ) { mode_R1(increment) } +INSTRUCTION( inc_IR1 ) { mode_IR1(increment) } + +void z8_device::increment_word(UINT8 dst) +{ + /* dst <- dst + 1 */ + UINT16 data = register_pair_read(dst) + 1; + + set_flag_z(data == 0); + set_flag_s(data & 0x8000); + set_flag_v(data == 0x8000); + + register_pair_write(dst, data); +} + +INSTRUCTION( incw_RR1 ) { mode_RR1(increment_word) } +INSTRUCTION( incw_IR1 ) { mode_IR1(increment_word) } + +void z8_device::subtract_carry(UINT8 dst, UINT8 src) +{ + /* dst <- dst - src - C */ + UINT8 data = register_read(dst); + UINT16 new_data = data - src; + + set_flag_c(!(new_data & 0x100)); + set_flag_z(new_data == 0); + set_flag_s(new_data & 0x80); + set_flag_v(((data & 0x80) != (src & 0x80)) && ((new_data & 0x80) == (src & 0x80))); + set_flag_d(1); + set_flag_h(!(((data & 0x1f) == 0x0f) && ((new_data & 0x1f) == 0x10))); + + register_write(dst, new_data & 0xff); +} + +INSTRUCTION( sbc_r1_r2 ) { mode_r1_r2(subtract_carry) } +INSTRUCTION( sbc_r1_Ir2 ) { mode_r1_Ir2(subtract_carry) } +INSTRUCTION( sbc_R2_R1 ) { mode_R2_R1(subtract_carry) } +INSTRUCTION( sbc_IR2_R1 ) { mode_IR2_R1(subtract_carry) } +INSTRUCTION( sbc_R1_IM ) { mode_R1_IM(subtract_carry) } +INSTRUCTION( sbc_IR1_IM ) { mode_IR1_IM(subtract_carry) } + +void z8_device::subtract(UINT8 dst, UINT8 src) +{ + /* dst <- dst - src */ + UINT8 data = register_read(dst); + UINT16 new_data = data - src; + + set_flag_c(!(new_data & 0x100)); + set_flag_z(new_data == 0); + set_flag_s(new_data & 0x80); + set_flag_v(((data & 0x80) != (src & 0x80)) && ((new_data & 0x80) == (src & 0x80))); + set_flag_d(1); + set_flag_h(!(((data & 0x1f) == 0x0f) && ((new_data & 0x1f) == 0x10))); + + register_write(dst, new_data & 0xff); +} + +INSTRUCTION( sub_r1_r2 ) { mode_r1_r2(subtract) } +INSTRUCTION( sub_r1_Ir2 ) { mode_r1_Ir2(subtract) } +INSTRUCTION( sub_R2_R1 ) { mode_R2_R1(subtract) } +INSTRUCTION( sub_IR2_R1 ) { mode_IR2_R1(subtract) } +INSTRUCTION( sub_R1_IM ) { mode_R1_IM(subtract) } +INSTRUCTION( sub_IR1_IM ) { mode_IR1_IM(subtract) } + +/*************************************************************************** + LOGICAL INSTRUCTIONS +***************************************************************************/ + +void z8_device::_and(UINT8 dst, UINT8 src) +{ + /* dst <- dst AND src */ + UINT8 data = register_read(dst) & src; + register_write(dst, data); + + set_flag_z(data == 0); + set_flag_s(data & 0x80); + set_flag_v(0); +} + +INSTRUCTION( and_r1_r2 ) { mode_r1_r2(_and) } +INSTRUCTION( and_r1_Ir2 ) { mode_r1_Ir2(_and) } +INSTRUCTION( and_R2_R1 ) { mode_R2_R1(_and) } +INSTRUCTION( and_IR2_R1 ) { mode_IR2_R1(_and) } +INSTRUCTION( and_R1_IM ) { mode_R1_IM(_and) } +INSTRUCTION( and_IR1_IM ) { mode_IR1_IM(_and) } + +void z8_device::complement(UINT8 dst) +{ + /* dst <- NOT dst */ + UINT8 data = register_read(dst) ^ 0xff; + register_write(dst, data); + + set_flag_z(data == 0); + set_flag_s(data & 0x80); + set_flag_v(0); +} + +INSTRUCTION( com_R1 ) { mode_R1(complement) } +INSTRUCTION( com_IR1 ) { mode_IR1(complement) } + +void z8_device::_or(UINT8 dst, UINT8 src) +{ + /* dst <- dst OR src */ + UINT8 data = register_read(dst) | src; + register_write(dst, data); + + set_flag_z(data == 0); + set_flag_s(data & 0x80); + set_flag_v(0); +} + +INSTRUCTION( or_r1_r2 ) { mode_r1_r2(_or) } +INSTRUCTION( or_r1_Ir2 ) { mode_r1_Ir2(_or) } +INSTRUCTION( or_R2_R1 ) { mode_R2_R1(_or) } +INSTRUCTION( or_IR2_R1 ) { mode_IR2_R1(_or) } +INSTRUCTION( or_R1_IM ) { mode_R1_IM(_or) } +INSTRUCTION( or_IR1_IM ) { mode_IR1_IM(_or) } + +void z8_device::_xor(UINT8 dst, UINT8 src) +{ + /* dst <- dst XOR src */ + UINT8 data = register_read(dst) ^ src; + register_write(dst, data); + + set_flag_z(data == 0); + set_flag_s(data & 0x80); + set_flag_v(0); +} + +INSTRUCTION( xor_r1_r2 ) { mode_r1_r2(_xor) } +INSTRUCTION( xor_r1_Ir2 ) { mode_r1_Ir2(_xor) } +INSTRUCTION( xor_R2_R1 ) { mode_R2_R1(_xor) } +INSTRUCTION( xor_IR2_R1 ) { mode_IR2_R1(_xor) } +INSTRUCTION( xor_R1_IM ) { mode_R1_IM(_xor) } +INSTRUCTION( xor_IR1_IM ) { mode_IR1_IM(_xor) } + +/*************************************************************************** + PROGRAM CONTROL INSTRUCTIONS +***************************************************************************/ + +void z8_device::call(UINT16 dst) +{ + stack_push_word(m_pc); + m_pc = dst; +} + +INSTRUCTION( call_IRR1 ) { UINT16 dst = register_pair_read(get_intermediate_register(get_register(fetch()))); call(dst); } +INSTRUCTION( call_DA ) { UINT16 dst = (fetch() << 8) | fetch(); call(dst); } + +INSTRUCTION( djnz_r1_RA ) +{ + INT8 ra = (INT8)fetch(); + + /* r <- r - 1 */ + int r = get_working_register(opcode >> 4); + UINT8 data = register_read(r) - 1; + register_write(r, data); + + /* if r<>0, PC <- PC + dst */ + if (data != 0) + { + m_pc += ra; + *cycles += 2; + } +} + +INSTRUCTION( iret ) +{ + /* FLAGS <- @SP + SP <- SP + 1 */ + register_write(Z8_REGISTER_FLAGS, stack_pop_byte()); + + /* PC <- @SP + SP <- SP + 2 */ + m_pc = stack_pop_word(); + + /* IMR (7) <- 1 */ + m_r[Z8_REGISTER_IMR] |= Z8_IMR_ENABLE; +} + +INSTRUCTION( ret ) +{ + /* PC <- @SP + SP <- SP + 2 */ + m_pc = stack_pop_word(); +} + +void z8_device::jump(UINT16 dst) +{ + /* PC <- dst */ + m_pc = dst; +} + +INSTRUCTION( jp_IRR1 ) { jump(register_pair_read(IR)); } + +int z8_device::check_condition_code(int cc) +{ + int truth = 0; + + switch (cc) + { + case CC_F: truth = 0; break; + case CC_LT: truth = flag(S) ^ flag(V); break; + case CC_LE: truth = (flag(Z) | (flag(S) ^ flag(V))); break; + case CC_ULE: truth = flag(C) | flag(Z); break; + case CC_OV: truth = flag(V); break; + case CC_MI: truth = flag(S); break; + case CC_Z: truth = flag(Z); break; + case CC_C: truth = flag(C); break; + case CC_T: truth = 1; break; + case CC_GE: truth = !(flag(S) ^ flag(V)); break; + case CC_GT: truth = !(flag(Z) | (flag(S) ^ flag(V))); break; + case CC_UGT: truth = ((!flag(C)) & (!flag(Z))); break; + case CC_NOV: truth = !flag(V); break; + case CC_PL: truth = !flag(S); break; + case CC_NZ: truth = !flag(Z); break; + case CC_NC: truth = !flag(C); break; + } + + return truth; +} + +INSTRUCTION( jp_cc_DA ) +{ + UINT16 dst = (fetch() << 8) | fetch(); + + /* if cc is true, then PC <- dst */ + if (check_condition_code(opcode >> 4)) + { + jump(dst); + *cycles += 2; + } +} + +INSTRUCTION( jr_cc_RA ) +{ + INT8 ra = (INT8)fetch(); + UINT16 dst = m_pc + ra; + + /* if cc is true, then PC <- dst */ + if (check_condition_code(opcode >> 4)) + { + jump(dst); + *cycles += 2; + } +} + +/*************************************************************************** + BIT MANIPULATION INSTRUCTIONS +***************************************************************************/ + +void z8_device::test_complement_under_mask(UINT8 dst, UINT8 src) +{ + /* NOT(dst) AND src */ + UINT8 data = (register_read(dst) ^ 0xff) & src; + + set_flag_z(data == 0); + set_flag_s(data & 0x80); + set_flag_v(0); +} + +INSTRUCTION( tcm_r1_r2 ) { mode_r1_r2(test_complement_under_mask) } +INSTRUCTION( tcm_r1_Ir2 ) { mode_r1_Ir2(test_complement_under_mask) } +INSTRUCTION( tcm_R2_R1 ) { mode_R2_R1(test_complement_under_mask) } +INSTRUCTION( tcm_IR2_R1 ) { mode_IR2_R1(test_complement_under_mask) } +INSTRUCTION( tcm_R1_IM ) { mode_R1_IM(test_complement_under_mask) } +INSTRUCTION( tcm_IR1_IM ) { mode_IR1_IM(test_complement_under_mask) } + +void z8_device::test_under_mask(UINT8 dst, UINT8 src) +{ + /* dst AND src */ + UINT8 data = register_read(dst) & src; + + set_flag_z(data == 0); + set_flag_s(data & 0x80); + set_flag_v(0); +} + +INSTRUCTION( tm_r1_r2 ) { mode_r1_r2(test_under_mask) } +INSTRUCTION( tm_r1_Ir2 ) { mode_r1_Ir2(test_under_mask) } +INSTRUCTION( tm_R2_R1 ) { mode_R2_R1(test_under_mask) } +INSTRUCTION( tm_IR2_R1 ) { mode_IR2_R1(test_under_mask) } +INSTRUCTION( tm_R1_IM ) { mode_R1_IM(test_under_mask) } +INSTRUCTION( tm_IR1_IM ) { mode_IR1_IM(test_under_mask) } + +/*************************************************************************** + ROTATE AND SHIFT INSTRUCTIONS +***************************************************************************/ + +void z8_device::rotate_left(UINT8 dst) +{ + /* << */ + UINT8 data = register_read(dst); + UINT8 new_data = (data << 1) | BIT(data, 7); + + set_flag_c(data & 0x80); + set_flag_z(data == 0); + set_flag_s(new_data & 0x80); + set_flag_v((data & 0x80) != (new_data & 0x80)); + + register_write(dst, new_data); +} + +INSTRUCTION( rl_R1 ) { mode_R1(rotate_left) } +INSTRUCTION( rl_IR1 ) { mode_IR1(rotate_left) } + +void z8_device::rotate_left_carry(UINT8 dst) +{ + /* << C */ + UINT8 data = register_read(dst); + UINT8 new_data = (data << 1) | flag(C); + + set_flag_c(data & 0x80); + set_flag_z(data == 0); + set_flag_s(new_data & 0x80); + set_flag_v((data & 0x80) != (new_data & 0x80)); + + register_write(dst, new_data); +} + +INSTRUCTION( rlc_R1 ) { mode_R1(rotate_left_carry) } +INSTRUCTION( rlc_IR1 ) { mode_IR1(rotate_left_carry) } + +void z8_device::rotate_right(UINT8 dst) +{ + /* >> */ + UINT8 data = register_read(dst); + UINT8 new_data = ((data & 0x01) << 7) | (data >> 1); + + set_flag_c(data & 0x01); + set_flag_z(data == 0); + set_flag_s(new_data & 0x80); + set_flag_v((data & 0x80) != (new_data & 0x80)); + + register_write(dst, new_data); +} + +INSTRUCTION( rr_R1 ) { mode_R1(rotate_right) } +INSTRUCTION( rr_IR1 ) { mode_IR1(rotate_right) } + +void z8_device::rotate_right_carry(UINT8 dst) +{ + /* >> C */ + UINT8 data = register_read(dst); + UINT8 new_data = (flag(C) << 7) | (data >> 1); + + set_flag_c(data & 0x01); + set_flag_z(data == 0); + set_flag_s(new_data & 0x80); + set_flag_v((data & 0x80) != (new_data & 0x80)); + + register_write(dst, new_data); +} + +INSTRUCTION( rrc_R1 ) { mode_R1(rotate_right_carry) } +INSTRUCTION( rrc_IR1 ) { mode_IR1(rotate_right_carry) } + +void z8_device::shift_right_arithmetic(UINT8 dst) +{ + /* */ + UINT8 data = register_read(dst); + UINT8 new_data = (data & 0x80) | ((data >> 1) & 0x7f); + + set_flag_c(data & 0x01); + set_flag_z(data == 0); + set_flag_s(new_data & 0x80); + set_flag_v(0); + + register_write(dst, new_data); +} + +INSTRUCTION( sra_R1 ) { mode_R1(shift_right_arithmetic) } +INSTRUCTION( sra_IR1 ) { mode_IR1(shift_right_arithmetic) } + +void z8_device::swap(UINT8 dst) +{ + /* dst(7-4) <-> dst(3-0) */ + UINT8 data = register_read(dst); + data = (data << 4) | (data >> 4); + register_write(dst, data); + + set_flag_z(data == 0); + set_flag_s(data & 0x80); +// set_flag_v(0); undefined +} + +INSTRUCTION( swap_R1 ) { mode_R1(swap) } +INSTRUCTION( swap_IR1 ) { mode_IR1(swap) } + +/*************************************************************************** + CPU CONTROL INSTRUCTIONS +***************************************************************************/ + +INSTRUCTION( ccf ) { m_r[Z8_REGISTER_FLAGS] ^= Z8_FLAGS_C; } +INSTRUCTION( di ) { m_r[Z8_REGISTER_IMR] &= ~Z8_IMR_ENABLE; } +INSTRUCTION( ei ) { m_r[Z8_REGISTER_IMR] |= Z8_IMR_ENABLE; } +INSTRUCTION( nop ) { /* no operation */ } +INSTRUCTION( rcf ) { set_flag_c(0); } +INSTRUCTION( scf ) { set_flag_c(1); } +INSTRUCTION( srp_IM ) { m_r[Z8_REGISTER_RP] = fetch(); } diff --git a/src/devices/cpu/z80/kl5c80a12.c b/src/devices/cpu/z80/kl5c80a12.c new file mode 100644 index 00000000000..500b68d567b --- /dev/null +++ b/src/devices/cpu/z80/kl5c80a12.c @@ -0,0 +1,54 @@ +// license:BSD-3-Clause +// copyright-holders:David Haywood +/*************************************************************************** + + Kawasaki LSI + KL5C80A12 CPU (KL5C80A12CFP on hng64.c) + + Binary compatible with Z80, significantly faster opcode timings, operating at up to 10Mhz + Timers / Counters, Parrallel / Serial ports/ MMU, Interrupt Controller + + (is this different enough to need it's own core?) + (todo: everything, some code currently lives in machine/hng64_net.c but not much) + +***************************************************************************/ + +#include "kl5c80a12.h" + +const device_type KL5C80A12 = &device_creator; + + +kl5c80a12_device::kl5c80a12_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : z80_device(mconfig, KL5C80A12, "KL5C80A12", tag, owner, clock, "KL5C80A12", __FILE__) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void kl5c80a12_device::device_start() +{ + z80_device::device_start(); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void kl5c80a12_device::device_reset() +{ + z80_device::device_reset(); +} + + +/* CPU interface */ +static MACHINE_CONFIG_FRAGMENT( kl5c80a12 ) +MACHINE_CONFIG_END + +machine_config_constructor kl5c80a12_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( kl5c80a12 ); +} diff --git a/src/devices/cpu/z80/kl5c80a12.h b/src/devices/cpu/z80/kl5c80a12.h new file mode 100644 index 00000000000..3e5e35a460b --- /dev/null +++ b/src/devices/cpu/z80/kl5c80a12.h @@ -0,0 +1,62 @@ +// license:BSD-3-Clause +// copyright-holders:David Haywood +/*************************************************************************** + + Kawasaki LSI + KL5C80A12 CPU (KL5C80A12CFP on hng64.c) + + Binary compatible with Z80, significantly faster opcode timings, operating at up to 10Mhz + Timers / Counters, Parrallel / Serial ports/ MMU, Interrupt Controller + + (is this different enough to need it's own core?) + (todo: everything, some code currently lives in machine/hng64_net.c but not much) + +***************************************************************************/ + +#pragma once + +#ifndef __KL5C80A12__ +#define __KL5C80A12__ + +#include "emu.h" +#include "z80.h" +#include "machine/z80ctc.h" + + +/*************************************************************************** + DEVICE CONFIGURATION MACROS +***************************************************************************/ + + +/*************************************************************************** + TYPE DEFINITIONS +***************************************************************************/ + +class kl5c80a12_device : public z80_device +{ +public: + kl5c80a12_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32); + + // static configuration helpers + +protected: + // device-level overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual void device_start(); + virtual void device_reset(); + + +private: + // devices/pointers + + // internal state + + // callbacks +}; + + +// device type definition +extern const device_type KL5C80A12; + + +#endif /// __KL5C80A12__ diff --git a/src/devices/cpu/z80/tmpz84c011.c b/src/devices/cpu/z80/tmpz84c011.c new file mode 100644 index 00000000000..428dd924c71 --- /dev/null +++ b/src/devices/cpu/z80/tmpz84c011.c @@ -0,0 +1,124 @@ +// license:BSD-3-Clause +// copyright-holders:David Haywood,hap +/*************************************************************************** + + Toshiba TMPZ84C011, MPUZ80/TLCS-Z80 ASSP Family + Z80 CPU, CTC, CGC, I/O8x5 + + TODO: + - CGC (clock generator/controller) + +***************************************************************************/ + +#include "tmpz84c011.h" + +const device_type TMPZ84C011 = &device_creator; + +static ADDRESS_MAP_START( tmpz84c011_internal_io_map, AS_IO, 8, tmpz84c011_device ) + AM_RANGE(0x10, 0x13) AM_MIRROR(0xff00) AM_DEVREADWRITE("tmpz84c011_ctc", z80ctc_device, read, write) + + AM_RANGE(0x50, 0x50) AM_MIRROR(0xff00) AM_READWRITE(tmpz84c011_pa_r, tmpz84c011_pa_w) + AM_RANGE(0x51, 0x51) AM_MIRROR(0xff00) AM_READWRITE(tmpz84c011_pb_r, tmpz84c011_pb_w) + AM_RANGE(0x52, 0x52) AM_MIRROR(0xff00) AM_READWRITE(tmpz84c011_pc_r, tmpz84c011_pc_w) + AM_RANGE(0x30, 0x30) AM_MIRROR(0xff00) AM_READWRITE(tmpz84c011_pd_r, tmpz84c011_pd_w) + AM_RANGE(0x40, 0x40) AM_MIRROR(0xff00) AM_READWRITE(tmpz84c011_pe_r, tmpz84c011_pe_w) + AM_RANGE(0x54, 0x54) AM_MIRROR(0xff00) AM_READWRITE(tmpz84c011_dir_pa_r, tmpz84c011_dir_pa_w) + AM_RANGE(0x55, 0x55) AM_MIRROR(0xff00) AM_READWRITE(tmpz84c011_dir_pb_r, tmpz84c011_dir_pb_w) + AM_RANGE(0x56, 0x56) AM_MIRROR(0xff00) AM_READWRITE(tmpz84c011_dir_pc_r, tmpz84c011_dir_pc_w) + AM_RANGE(0x34, 0x34) AM_MIRROR(0xff00) AM_READWRITE(tmpz84c011_dir_pd_r, tmpz84c011_dir_pd_w) + AM_RANGE(0x44, 0x44) AM_MIRROR(0xff00) AM_READWRITE(tmpz84c011_dir_pe_r, tmpz84c011_dir_pe_w) +ADDRESS_MAP_END + + +tmpz84c011_device::tmpz84c011_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : z80_device(mconfig, TMPZ84C011, "TMPZ84C011", tag, owner, clock, "tmpz84c011", __FILE__), + m_io_space_config( "io", ENDIANNESS_LITTLE, 8, 16, 0, ADDRESS_MAP_NAME( tmpz84c011_internal_io_map ) ), + m_ctc(*this, "tmpz84c011_ctc"), + m_outportsa(*this), + m_outportsb(*this), + m_outportsc(*this), + m_outportsd(*this), + m_outportse(*this), + m_inportsa(*this), + m_inportsb(*this), + m_inportsc(*this), + m_inportsd(*this), + m_inportse(*this), + m_zc0_cb(*this), + m_zc1_cb(*this), + m_zc2_cb(*this) +{ + memset(m_pio_dir, 0, 5); + memset(m_pio_latch, 0, 5); +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void tmpz84c011_device::device_start() +{ + z80_device::device_start(); + + // resolve callbacks + m_outportsa.resolve_safe(); + m_outportsb.resolve_safe(); + m_outportsc.resolve_safe(); + m_outportsd.resolve_safe(); + m_outportse.resolve_safe(); + + m_inportsa.resolve_safe(0); + m_inportsb.resolve_safe(0); + m_inportsc.resolve_safe(0); + m_inportsd.resolve_safe(0); + m_inportse.resolve_safe(0); + + m_zc0_cb.resolve_safe(); + m_zc1_cb.resolve_safe(); + m_zc2_cb.resolve_safe(); + + // register for save states + save_item(NAME(m_pio_dir[0])); + save_item(NAME(m_pio_latch[0])); + save_item(NAME(m_pio_dir[1])); + save_item(NAME(m_pio_latch[1])); + save_item(NAME(m_pio_dir[2])); + save_item(NAME(m_pio_latch[2])); + save_item(NAME(m_pio_dir[3])); + save_item(NAME(m_pio_latch[3])); + save_item(NAME(m_pio_dir[4])); + save_item(NAME(m_pio_latch[4])); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void tmpz84c011_device::device_reset() +{ + z80_device::device_reset(); + + // initialize I/O + tmpz84c011_dir_pa_w(*m_io, 0, 0); tmpz84c011_pa_w(*m_io, 0, 0); + tmpz84c011_dir_pb_w(*m_io, 0, 0); tmpz84c011_pb_w(*m_io, 0, 0); + tmpz84c011_dir_pc_w(*m_io, 0, 0); tmpz84c011_pc_w(*m_io, 0, 0); + tmpz84c011_dir_pd_w(*m_io, 0, 0); tmpz84c011_pd_w(*m_io, 0, 0); + tmpz84c011_dir_pe_w(*m_io, 0, 0); tmpz84c011_pe_w(*m_io, 0, 0); +} + + +/* CPU interface */ +static MACHINE_CONFIG_FRAGMENT( tmpz84c011 ) + MCFG_DEVICE_ADD("tmpz84c011_ctc", Z80CTC, DERIVED_CLOCK(1,1) ) + MCFG_Z80CTC_INTR_CB(INPUTLINE(DEVICE_SELF, INPUT_LINE_IRQ0)) + MCFG_Z80CTC_ZC0_CB(WRITELINE(tmpz84c011_device, zc0_cb_trampoline_w)) + MCFG_Z80CTC_ZC1_CB(WRITELINE(tmpz84c011_device, zc1_cb_trampoline_w)) + MCFG_Z80CTC_ZC2_CB(WRITELINE(tmpz84c011_device, zc2_cb_trampoline_w)) +MACHINE_CONFIG_END + +machine_config_constructor tmpz84c011_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( tmpz84c011 ); +} diff --git a/src/devices/cpu/z80/tmpz84c011.h b/src/devices/cpu/z80/tmpz84c011.h new file mode 100644 index 00000000000..1a5bdd83a85 --- /dev/null +++ b/src/devices/cpu/z80/tmpz84c011.h @@ -0,0 +1,179 @@ +// license:BSD-3-Clause +// copyright-holders:David Haywood,hap +/*************************************************************************** + + Toshiba TMPZ84C011, MPUZ80/TLCS-Z80 ASSP Family + Z80 CPU, CTC, CGC, I/O8x5 + +***************************************************************************/ + +#pragma once + +#ifndef __TMPZ84C011__ +#define __TMPZ84C011__ + +#include "emu.h" +#include "z80.h" +#include "machine/z80ctc.h" + + +/*************************************************************************** + DEVICE CONFIGURATION MACROS +***************************************************************************/ + +// For daisy chain configuration, insert this: +#define TMPZ84C011_DAISY_INTERNAL { "tmpz84c011_ctc" } + +// CTC callbacks +#define MCFG_TMPZ84C011_ZC0_CB(_devcb) \ + devcb = &tmpz84c011_device::set_zc0_callback(*device, DEVCB_##_devcb); + +#define MCFG_TMPZ84C011_ZC1_CB(_devcb) \ + devcb = &tmpz84c011_device::set_zc1_callback(*device, DEVCB_##_devcb); + +#define MCFG_TMPZ84C011_ZC2_CB(_devcb) \ + devcb = &tmpz84c011_device::set_zc2_callback(*device, DEVCB_##_devcb); + + +// I/O callbacks +#define MCFG_TMPZ84C011_PORTA_READ_CB(_devcb) \ + devcb = &tmpz84c011_device::set_inportsa_cb(*device, DEVCB_##_devcb); + +#define MCFG_TMPZ84C011_PORTB_READ_CB(_devcb) \ + devcb = &tmpz84c011_device::set_inportsb_cb(*device, DEVCB_##_devcb); + +#define MCFG_TMPZ84C011_PORTC_READ_CB(_devcb) \ + devcb = &tmpz84c011_device::set_inportsc_cb(*device, DEVCB_##_devcb); + +#define MCFG_TMPZ84C011_PORTD_READ_CB(_devcb) \ + devcb = &tmpz84c011_device::set_inportsd_cb(*device, DEVCB_##_devcb); + +#define MCFG_TMPZ84C011_PORTE_READ_CB(_devcb) \ + devcb = &tmpz84c011_device::set_inportse_cb(*device, DEVCB_##_devcb); + + +#define MCFG_TMPZ84C011_PORTA_WRITE_CB(_devcb) \ + devcb = &tmpz84c011_device::set_outportsa_cb(*device, DEVCB_##_devcb); + +#define MCFG_TMPZ84C011_PORTB_WRITE_CB(_devcb) \ + devcb = &tmpz84c011_device::set_outportsb_cb(*device, DEVCB_##_devcb); + +#define MCFG_TMPZ84C011_PORTC_WRITE_CB(_devcb) \ + devcb = &tmpz84c011_device::set_outportsc_cb(*device, DEVCB_##_devcb); + +#define MCFG_TMPZ84C011_PORTD_WRITE_CB(_devcb) \ + devcb = &tmpz84c011_device::set_outportsd_cb(*device, DEVCB_##_devcb); + +#define MCFG_TMPZ84C011_PORTE_WRITE_CB(_devcb) \ + devcb = &tmpz84c011_device::set_outportse_cb(*device, DEVCB_##_devcb); + + +/*************************************************************************** + TYPE DEFINITIONS +***************************************************************************/ + +class tmpz84c011_device : public z80_device +{ +public: + tmpz84c011_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32); + + // static configuration helpers + template static devcb_base &set_zc0_callback(device_t &device, _Object object) { return downcast(device).m_zc0_cb.set_callback(object); } + template static devcb_base &set_zc1_callback(device_t &device, _Object object) { return downcast(device).m_zc1_cb.set_callback(object); } + template static devcb_base &set_zc2_callback(device_t &device, _Object object) { return downcast(device).m_zc2_cb.set_callback(object); } + + template static devcb_base & set_outportsa_cb(device_t &device, _Object object) { return downcast(device).m_outportsa.set_callback(object); } + template static devcb_base & set_outportsb_cb(device_t &device, _Object object) { return downcast(device).m_outportsb.set_callback(object); } + template static devcb_base & set_outportsc_cb(device_t &device, _Object object) { return downcast(device).m_outportsc.set_callback(object); } + template static devcb_base & set_outportsd_cb(device_t &device, _Object object) { return downcast(device).m_outportsd.set_callback(object); } + template static devcb_base & set_outportse_cb(device_t &device, _Object object) { return downcast(device).m_outportse.set_callback(object); } + + template static devcb_base & set_inportsa_cb(device_t &device, _Object object) { return downcast(device).m_inportsa.set_callback(object); } + template static devcb_base & set_inportsb_cb(device_t &device, _Object object) { return downcast(device).m_inportsb.set_callback(object); } + template static devcb_base & set_inportsc_cb(device_t &device, _Object object) { return downcast(device).m_inportsc.set_callback(object); } + template static devcb_base & set_inportsd_cb(device_t &device, _Object object) { return downcast(device).m_inportsd.set_callback(object); } + template static devcb_base & set_inportse_cb(device_t &device, _Object object) { return downcast(device).m_inportse.set_callback(object); } + + // CTC public interface + DECLARE_WRITE_LINE_MEMBER( trg0 ) { m_ctc->trg0(state); } + DECLARE_WRITE_LINE_MEMBER( trg1 ) { m_ctc->trg1(state); } + DECLARE_WRITE_LINE_MEMBER( trg2 ) { m_ctc->trg2(state); } + DECLARE_WRITE_LINE_MEMBER( trg3 ) { m_ctc->trg3(state); } + + ///////////////////////////////////////////////////////// + + DECLARE_READ8_MEMBER( tmpz84c011_pa_r ) { return (m_inportsa() & ~m_pio_dir[0]) | (m_pio_latch[0] & m_pio_dir[0]); } + DECLARE_READ8_MEMBER( tmpz84c011_pb_r ) { return (m_inportsb() & ~m_pio_dir[1]) | (m_pio_latch[1] & m_pio_dir[1]); } + DECLARE_READ8_MEMBER( tmpz84c011_pc_r ) { return (m_inportsc() & ~m_pio_dir[2]) | (m_pio_latch[2] & m_pio_dir[2]); } + DECLARE_READ8_MEMBER( tmpz84c011_pd_r ) { return (m_inportsd() & ~m_pio_dir[3]) | (m_pio_latch[3] & m_pio_dir[3]); } + DECLARE_READ8_MEMBER( tmpz84c011_pe_r ) { return (m_inportse() & ~m_pio_dir[4]) | (m_pio_latch[4] & m_pio_dir[4]); } + DECLARE_WRITE8_MEMBER( tmpz84c011_pa_w ) { m_pio_latch[0] = data; m_outportsa(data & m_pio_dir[0]); } + DECLARE_WRITE8_MEMBER( tmpz84c011_pb_w ) { m_pio_latch[1] = data; m_outportsb(data & m_pio_dir[1]); } + DECLARE_WRITE8_MEMBER( tmpz84c011_pc_w ) { m_pio_latch[2] = data; m_outportsc(data & m_pio_dir[2]); } + DECLARE_WRITE8_MEMBER( tmpz84c011_pd_w ) { m_pio_latch[3] = data; m_outportsd(data & m_pio_dir[3]); } + DECLARE_WRITE8_MEMBER( tmpz84c011_pe_w ) { m_pio_latch[4] = data; m_outportse(data & m_pio_dir[4]); } + + DECLARE_READ8_MEMBER( tmpz84c011_dir_pa_r ) { return m_pio_dir[0]; } + DECLARE_READ8_MEMBER( tmpz84c011_dir_pb_r ) { return m_pio_dir[1]; } + DECLARE_READ8_MEMBER( tmpz84c011_dir_pc_r ) { return m_pio_dir[2]; } + DECLARE_READ8_MEMBER( tmpz84c011_dir_pd_r ) { return m_pio_dir[3]; } + DECLARE_READ8_MEMBER( tmpz84c011_dir_pe_r ) { return m_pio_dir[4]; } + DECLARE_WRITE8_MEMBER( tmpz84c011_dir_pa_w ) { m_pio_dir[0] = data; } + DECLARE_WRITE8_MEMBER( tmpz84c011_dir_pb_w ) { m_pio_dir[1] = data; } + DECLARE_WRITE8_MEMBER( tmpz84c011_dir_pc_w ) { m_pio_dir[2] = data; } + DECLARE_WRITE8_MEMBER( tmpz84c011_dir_pd_w ) { m_pio_dir[3] = data; } + DECLARE_WRITE8_MEMBER( tmpz84c011_dir_pe_w ) { m_pio_dir[4] = data; } + + DECLARE_WRITE_LINE_MEMBER( zc0_cb_trampoline_w ) { m_zc0_cb(state); } + DECLARE_WRITE_LINE_MEMBER( zc1_cb_trampoline_w ) { m_zc1_cb(state); } + DECLARE_WRITE_LINE_MEMBER( zc2_cb_trampoline_w ) { m_zc2_cb(state); } + +protected: + // device-level overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual void device_start(); + virtual void device_reset(); + + const address_space_config m_io_space_config; + + const address_space_config *memory_space_config(address_spacenum spacenum) const + { + switch (spacenum) + { + case AS_IO: return &m_io_space_config; + default: return z80_device::memory_space_config(spacenum); + } + } + +private: + // devices/pointers + required_device m_ctc; + + // internal state + UINT8 m_pio_dir[5]; + UINT8 m_pio_latch[5]; + + // callbacks + devcb_write8 m_outportsa; + devcb_write8 m_outportsb; + devcb_write8 m_outportsc; + devcb_write8 m_outportsd; + devcb_write8 m_outportse; + + devcb_read8 m_inportsa; + devcb_read8 m_inportsb; + devcb_read8 m_inportsc; + devcb_read8 m_inportsd; + devcb_read8 m_inportse; + + devcb_write_line m_zc0_cb; + devcb_write_line m_zc1_cb; + devcb_write_line m_zc2_cb; +}; + + +// device type definition +extern const device_type TMPZ84C011; + + +#endif /// __TMPZ84C011__ diff --git a/src/devices/cpu/z80/tmpz84c015.c b/src/devices/cpu/z80/tmpz84c015.c new file mode 100644 index 00000000000..1677358e059 --- /dev/null +++ b/src/devices/cpu/z80/tmpz84c015.c @@ -0,0 +1,217 @@ +// license:BSD-3-Clause +// copyright-holders:hap +/*************************************************************************** + + Toshiba TMPZ84C015, MPUZ80/TLCS-Z80 ASSP Family + Z80 CPU, SIO, CTC, CGC, PIO, WDT + + TODO: + - SIO configuration, or should that be up to the driver? + - CGC (clock generator/controller) + - WDT (watchdog timer) + +***************************************************************************/ + +#include "tmpz84c015.h" + +const device_type TMPZ84C015 = &device_creator; + +static ADDRESS_MAP_START( tmpz84c015_internal_io_map, AS_IO, 8, tmpz84c015_device ) + AM_RANGE(0x10, 0x13) AM_MIRROR(0xff00) AM_DEVREADWRITE("tmpz84c015_ctc", z80ctc_device, read, write) + AM_RANGE(0x18, 0x1b) AM_MIRROR(0xff00) AM_DEVREADWRITE("tmpz84c015_sio", z80dart_device, ba_cd_r, ba_cd_w) + AM_RANGE(0x1c, 0x1f) AM_MIRROR(0xff00) AM_DEVREADWRITE("tmpz84c015_pio", z80pio_device, read_alt, write_alt) + AM_RANGE(0xf4, 0xf4) AM_MIRROR(0xff00) AM_WRITE(irq_priority_w) +ADDRESS_MAP_END + + +tmpz84c015_device::tmpz84c015_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : z80_device(mconfig, TMPZ84C015, "TMPZ84C015", tag, owner, clock, "tmpz84c015", __FILE__), + m_io_space_config( "io", ENDIANNESS_LITTLE, 8, 16, 0, ADDRESS_MAP_NAME( tmpz84c015_internal_io_map ) ), + m_ctc(*this, "tmpz84c015_ctc"), + m_sio(*this, "tmpz84c015_sio"), + m_pio(*this, "tmpz84c015_pio"), + m_irq_priority(-1), // ! + + m_out_txda_cb(*this), + m_out_dtra_cb(*this), + m_out_rtsa_cb(*this), + m_out_wrdya_cb(*this), + m_out_synca_cb(*this), + + m_out_txdb_cb(*this), + m_out_dtrb_cb(*this), + m_out_rtsb_cb(*this), + m_out_wrdyb_cb(*this), + m_out_syncb_cb(*this), + + m_out_rxdrqa_cb(*this), + m_out_txdrqa_cb(*this), + m_out_rxdrqb_cb(*this), + m_out_txdrqb_cb(*this), + + m_zc0_cb(*this), + m_zc1_cb(*this), + m_zc2_cb(*this), + + m_in_pa_cb(*this), + m_out_pa_cb(*this), + m_out_ardy_cb(*this), + + m_in_pb_cb(*this), + m_out_pb_cb(*this), + m_out_brdy_cb(*this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void tmpz84c015_device::device_start() +{ + z80_device::device_start(); + + // resolve callbacks + m_out_txda_cb.resolve_safe(); + m_out_dtra_cb.resolve_safe(); + m_out_rtsa_cb.resolve_safe(); + m_out_wrdya_cb.resolve_safe(); + m_out_synca_cb.resolve_safe(); + + m_out_txdb_cb.resolve_safe(); + m_out_dtrb_cb.resolve_safe(); + m_out_rtsb_cb.resolve_safe(); + m_out_wrdyb_cb.resolve_safe(); + m_out_syncb_cb.resolve_safe(); + + m_out_rxdrqa_cb.resolve_safe(); + m_out_txdrqa_cb.resolve_safe(); + m_out_rxdrqb_cb.resolve_safe(); + m_out_txdrqb_cb.resolve_safe(); + + m_zc0_cb.resolve_safe(); + m_zc1_cb.resolve_safe(); + m_zc2_cb.resolve_safe(); + + m_in_pa_cb.resolve_safe(0); + m_out_pa_cb.resolve_safe(); + m_out_ardy_cb.resolve_safe(); + + m_in_pb_cb.resolve_safe(0); + m_out_pb_cb.resolve_safe(); + m_out_brdy_cb.resolve_safe(); + + // register for save states + save_item(NAME(m_irq_priority)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void tmpz84c015_device::device_reset() +{ + irq_priority_w(*m_io, 0, 0); + z80_device::device_reset(); +} + + +//------------------------------------------------- +// device_post_load - device-specific post-load +//------------------------------------------------- + +void tmpz84c015_device::device_post_load() +{ + // reinit irq priority + UINT8 prio = m_irq_priority; + m_irq_priority = -1; + irq_priority_w(*m_io, 0, prio); +} + + +/* CPU interface */ +WRITE8_MEMBER(tmpz84c015_device::irq_priority_w) +{ + data &= 7; + + if (data > 5) + { + logerror("tmpz84c015: irq_priority_w undefined state %X\n", data); + data &= 3; // guess + } + + if (m_irq_priority != data) + { + static const char *dev[3] = { "tmpz84c015_ctc", "tmpz84c015_sio", "tmpz84c015_pio" }; + static const int prio[6][3] = + { + { 0, 1, 2 }, // 0: ctc -> sio -> pio -> ext + { 1, 0, 2 }, // 1: sio -> ctc -> pio -> ext + { 0, 2, 1 }, // 2: ctc -> pio -> sio -> ext + { 2, 1, 0 }, // 3: pio -> sio -> ctc -> ext + { 2, 0, 1 }, // 4: pio -> ctc -> sio -> ext + { 1, 2, 0 } // 5: sio -> pio -> ctc -> ext + }; + + // reconfigure first 3 entries in daisy chain + const z80_daisy_config daisy_chain[] = + { + { dev[prio[data][0]] }, + { dev[prio[data][1]] }, + { dev[prio[data][2]] }, + { NULL } + }; + m_daisy.init(this, daisy_chain); + + m_irq_priority = data; + } +} + +static MACHINE_CONFIG_FRAGMENT( tmpz84c015 ) + + /* basic machine hardware */ + MCFG_Z80SIO0_ADD("tmpz84c015_sio", DERIVED_CLOCK(1,1), 0, 0, 0, 0) + MCFG_Z80DART_OUT_INT_CB(INPUTLINE(DEVICE_SELF, INPUT_LINE_IRQ0)) + + MCFG_Z80DART_OUT_TXDA_CB(WRITELINE(tmpz84c015_device, out_txda_cb_trampoline_w)) + MCFG_Z80DART_OUT_DTRA_CB(WRITELINE(tmpz84c015_device, out_dtra_cb_trampoline_w)) + MCFG_Z80DART_OUT_RTSA_CB(WRITELINE(tmpz84c015_device, out_rtsa_cb_trampoline_w)) + MCFG_Z80DART_OUT_WRDYA_CB(WRITELINE(tmpz84c015_device, out_wrdya_cb_trampoline_w)) + MCFG_Z80DART_OUT_SYNCA_CB(WRITELINE(tmpz84c015_device, out_synca_cb_trampoline_w)) + + MCFG_Z80DART_OUT_TXDB_CB(WRITELINE(tmpz84c015_device, out_txdb_cb_trampoline_w)) + MCFG_Z80DART_OUT_DTRB_CB(WRITELINE(tmpz84c015_device, out_dtrb_cb_trampoline_w)) + MCFG_Z80DART_OUT_RTSB_CB(WRITELINE(tmpz84c015_device, out_rtsb_cb_trampoline_w)) + MCFG_Z80DART_OUT_WRDYB_CB(WRITELINE(tmpz84c015_device, out_wrdyb_cb_trampoline_w)) + MCFG_Z80DART_OUT_SYNCB_CB(WRITELINE(tmpz84c015_device, out_syncb_cb_trampoline_w)) + + MCFG_Z80DART_OUT_RXDRQA_CB(WRITELINE(tmpz84c015_device, out_rxdrqa_cb_trampoline_w)) + MCFG_Z80DART_OUT_TXDRQA_CB(WRITELINE(tmpz84c015_device, out_txdrqa_cb_trampoline_w)) + MCFG_Z80DART_OUT_RXDRQB_CB(WRITELINE(tmpz84c015_device, out_rxdrqb_cb_trampoline_w)) + MCFG_Z80DART_OUT_TXDRQB_CB(WRITELINE(tmpz84c015_device, out_txdrqb_cb_trampoline_w)) + + MCFG_DEVICE_ADD("tmpz84c015_ctc", Z80CTC, DERIVED_CLOCK(1,1) ) + MCFG_Z80CTC_INTR_CB(INPUTLINE(DEVICE_SELF, INPUT_LINE_IRQ0)) + + MCFG_Z80CTC_ZC0_CB(WRITELINE(tmpz84c015_device, zc0_cb_trampoline_w)) + MCFG_Z80CTC_ZC1_CB(WRITELINE(tmpz84c015_device, zc1_cb_trampoline_w)) + MCFG_Z80CTC_ZC2_CB(WRITELINE(tmpz84c015_device, zc2_cb_trampoline_w)) + + MCFG_DEVICE_ADD("tmpz84c015_pio", Z80PIO, DERIVED_CLOCK(1,1) ) + MCFG_Z80PIO_OUT_INT_CB(INPUTLINE(DEVICE_SELF, INPUT_LINE_IRQ0)) + + MCFG_Z80PIO_IN_PA_CB(READ8(tmpz84c015_device, in_pa_cb_trampoline_r)) + MCFG_Z80PIO_OUT_PA_CB(WRITE8(tmpz84c015_device, out_pa_cb_trampoline_w)) + MCFG_Z80PIO_OUT_ARDY_CB(WRITELINE(tmpz84c015_device, out_ardy_cb_trampoline_w)) + + MCFG_Z80PIO_IN_PB_CB(READ8(tmpz84c015_device, in_pb_cb_trampoline_r)) + MCFG_Z80PIO_OUT_PB_CB(WRITE8(tmpz84c015_device, out_pb_cb_trampoline_w)) + MCFG_Z80PIO_OUT_BRDY_CB(WRITELINE(tmpz84c015_device, out_brdy_cb_trampoline_w)) +MACHINE_CONFIG_END + +machine_config_constructor tmpz84c015_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( tmpz84c015 ); +} diff --git a/src/devices/cpu/z80/tmpz84c015.h b/src/devices/cpu/z80/tmpz84c015.h new file mode 100644 index 00000000000..225a658edc3 --- /dev/null +++ b/src/devices/cpu/z80/tmpz84c015.h @@ -0,0 +1,273 @@ +// license:BSD-3-Clause +// copyright-holders:hap +/*************************************************************************** + + Toshiba TMPZ84C015, MPUZ80/TLCS-Z80 ASSP Family + Z80 CPU, SIO, CTC, CGC, PIO, WDT + +***************************************************************************/ + +#pragma once + +#ifndef __TMPZ84C015__ +#define __TMPZ84C015__ + +#include "emu.h" +#include "z80.h" +#include "machine/z80dart.h" +#include "machine/z80ctc.h" +#include "machine/z80pio.h" + + +/*************************************************************************** + DEVICE CONFIGURATION MACROS +***************************************************************************/ + +// If an external daisy chain is used, insert this before your own device tags: +#define TMPZ84C015_DAISY_INTERNAL { "tmpz84c015_ctc" }, { "tmpz84c015_sio" }, { "tmpz84c015_pio" } + +// SIO callbacks +#define MCFG_TMPZ84C015_OUT_TXDA_CB(_devcb) \ + devcb = &tmpz84c015_device::set_out_txda_callback(*device, DEVCB_##_devcb); + +#define MCFG_TMPZ84C015_OUT_DTRA_CB(_devcb) \ + devcb = &tmpz84c015_device::set_out_dtra_callback(*device, DEVCB_##_devcb); + +#define MCFG_TMPZ84C015_OUT_RTSA_CB(_devcb) \ + devcb = &tmpz84c015_device::set_out_rtsa_callback(*device, DEVCB_##_devcb); + +#define MCFG_TMPZ84C015_OUT_WRDYA_CB(_devcb) \ + devcb = &tmpz84c015_device::set_out_wrdya_callback(*device, DEVCB_##_devcb); + +#define MCFG_TMPZ84C015_OUT_SYNCA_CB(_devcb) \ + devcb = &tmpz84c015_device::set_out_synca_callback(*device, DEVCB_##_devcb); + +#define MCFG_TMPZ84C015_OUT_TXDB_CB(_devcb) \ + devcb = &tmpz84c015_device::set_out_txdb_callback(*device, DEVCB_##_devcb); + +#define MCFG_TMPZ84C015_OUT_DTRB_CB(_devcb) \ + devcb = &tmpz84c015_device::set_out_dtrb_callback(*device, DEVCB_##_devcb); + +#define MCFG_TMPZ84C015_OUT_RTSB_CB(_devcb) \ + devcb = &tmpz84c015_device::set_out_rtsb_callback(*device, DEVCB_##_devcb); + +#define MCFG_TMPZ84C015_OUT_WRDYB_CB(_devcb) \ + devcb = &tmpz84c015_device::set_out_wrdyb_callback(*device, DEVCB_##_devcb); + +#define MCFG_TMPZ84C015_OUT_SYNCB_CB(_devcb) \ + devcb = &tmpz84c015_device::set_out_syncb_callback(*device, DEVCB_##_devcb); + +#define MCFG_TMPZ84C015_OUT_RXDRQA_CB(_devcb) \ + devcb = &tmpz84c015_device::set_out_rxdrqa_callback(*device, DEVCB_##_devcb); + +#define MCFG_TMPZ84C015_OUT_TXDRQA_CB(_devcb) \ + devcb = &tmpz84c015_device::set_out_txdrqa_callback(*device, DEVCB_##_devcb); + +#define MCFG_TMPZ84C015_OUT_RXDRQB_CB(_devcb) \ + devcb = &tmpz84c015_device::set_out_rxdrqb_callback(*device, DEVCB_##_devcb); + +#define MCFG_TMPZ84C015_OUT_TXDRQB_CB(_devcb) \ + devcb = &tmpz84c015_device::set_out_txdrqb_callback(*device, DEVCB_##_devcb); + + +// CTC callbacks +#define MCFG_TMPZ84C015_ZC0_CB(_devcb) \ + devcb = &tmpz84c015_device::set_zc0_callback(*device, DEVCB_##_devcb); + +#define MCFG_TMPZ84C015_ZC1_CB(_devcb) \ + devcb = &tmpz84c015_device::set_zc1_callback(*device, DEVCB_##_devcb); + +#define MCFG_TMPZ84C015_ZC2_CB(_devcb) \ + devcb = &tmpz84c015_device::set_zc2_callback(*device, DEVCB_##_devcb); + + +// PIO callbacks +#define MCFG_TMPZ84C015_IN_PA_CB(_devcb) \ + devcb = &tmpz84c015_device::set_in_pa_callback(*device, DEVCB_##_devcb); + +#define MCFG_TMPZ84C015_OUT_PA_CB(_devcb) \ + devcb = &tmpz84c015_device::set_out_pa_callback(*device, DEVCB_##_devcb); + +#define MCFG_TMPZ84C015_OUT_ARDY_CB(_devcb) \ + devcb = &tmpz84c015_device::set_out_ardy_callback(*device, DEVCB_##_devcb); + +#define MCFG_TMPZ84C015_IN_PB_CB(_devcb) \ + devcb = &tmpz84c015_device::set_in_pb_callback(*device, DEVCB_##_devcb); + +#define MCFG_TMPZ84C015_OUT_PB_CB(_devcb) \ + devcb = &tmpz84c015_device::set_out_pb_callback(*device, DEVCB_##_devcb); + +#define MCFG_TMPZ84C015_OUT_BRDY_CB(_devcb) \ + devcb = &tmpz84c015_device::set_out_brdy_callback(*device, DEVCB_##_devcb); + + +/*************************************************************************** + TYPE DEFINITIONS +***************************************************************************/ + +class tmpz84c015_device : public z80_device +{ +public: + tmpz84c015_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32); + + // static configuration helpers + template static devcb_base &set_out_txda_callback(device_t &device, _Object object) { return downcast(device).m_out_txda_cb.set_callback(object); } + template static devcb_base &set_out_dtra_callback(device_t &device, _Object object) { return downcast(device).m_out_dtra_cb.set_callback(object); } + template static devcb_base &set_out_rtsa_callback(device_t &device, _Object object) { return downcast(device).m_out_rtsa_cb.set_callback(object); } + template static devcb_base &set_out_wrdya_callback(device_t &device, _Object object) { return downcast(device).m_out_wrdya_cb.set_callback(object); } + template static devcb_base &set_out_synca_callback(device_t &device, _Object object) { return downcast(device).m_out_synca_cb.set_callback(object); } + + template static devcb_base &set_out_txdb_callback(device_t &device, _Object object) { return downcast(device).m_out_txdb_cb.set_callback(object); } + template static devcb_base &set_out_dtrb_callback(device_t &device, _Object object) { return downcast(device).m_out_dtrb_cb.set_callback(object); } + template static devcb_base &set_out_rtsb_callback(device_t &device, _Object object) { return downcast(device).m_out_rtsb_cb.set_callback(object); } + template static devcb_base &set_out_wrdyb_callback(device_t &device, _Object object) { return downcast(device).m_out_wrdyb_cb.set_callback(object); } + template static devcb_base &set_out_syncb_callback(device_t &device, _Object object) { return downcast(device).m_out_syncb_cb.set_callback(object); } + + template static devcb_base &set_out_rxdrqa_callback(device_t &device, _Object object) { return downcast(device).m_out_rxdrqa_cb.set_callback(object); } + template static devcb_base &set_out_txdrqa_callback(device_t &device, _Object object) { return downcast(device).m_out_txdrqa_cb.set_callback(object); } + template static devcb_base &set_out_rxdrqb_callback(device_t &device, _Object object) { return downcast(device).m_out_rxdrqb_cb.set_callback(object); } + template static devcb_base &set_out_txdrqb_callback(device_t &device, _Object object) { return downcast(device).m_out_txdrqb_cb.set_callback(object); } + + template static devcb_base &set_zc0_callback(device_t &device, _Object object) { return downcast(device).m_zc0_cb.set_callback(object); } + template static devcb_base &set_zc1_callback(device_t &device, _Object object) { return downcast(device).m_zc1_cb.set_callback(object); } + template static devcb_base &set_zc2_callback(device_t &device, _Object object) { return downcast(device).m_zc2_cb.set_callback(object); } + + template static devcb_base &set_in_pa_callback(device_t &device, _Object object) { return downcast(device).m_in_pa_cb.set_callback(object); } + template static devcb_base &set_out_pa_callback(device_t &device, _Object object) { return downcast(device).m_out_pa_cb.set_callback(object); } + template static devcb_base &set_out_ardy_callback(device_t &device, _Object object) { return downcast(device).m_out_ardy_cb.set_callback(object); } + + template static devcb_base &set_in_pb_callback(device_t &device, _Object object) { return downcast(device).m_in_pb_cb.set_callback(object); } + template static devcb_base &set_out_pb_callback(device_t &device, _Object object) { return downcast(device).m_out_pb_cb.set_callback(object); } + template static devcb_base &set_out_brdy_callback(device_t &device, _Object object) { return downcast(device).m_out_brdy_cb.set_callback(object); } + + // SIO public interface + DECLARE_WRITE_LINE_MEMBER( rxa_w ) { m_sio->rxa_w(state); } + DECLARE_WRITE_LINE_MEMBER( rxb_w ) { m_sio->rxb_w(state); } + DECLARE_WRITE_LINE_MEMBER( ctsa_w ) { m_sio->ctsa_w(state); } + DECLARE_WRITE_LINE_MEMBER( ctsb_w ) { m_sio->ctsb_w(state); } + DECLARE_WRITE_LINE_MEMBER( dcda_w ) { m_sio->dcda_w(state); } + DECLARE_WRITE_LINE_MEMBER( dcdb_w ) { m_sio->dcdb_w(state); } + DECLARE_WRITE_LINE_MEMBER( ria_w ) { m_sio->ria_w(state); } + DECLARE_WRITE_LINE_MEMBER( rib_w ) { m_sio->rib_w(state); } + DECLARE_WRITE_LINE_MEMBER( rxca_w ) { m_sio->rxca_w(state); } + DECLARE_WRITE_LINE_MEMBER( rxcb_w ) { m_sio->rxcb_w(state); } + DECLARE_WRITE_LINE_MEMBER( txca_w ) { m_sio->txca_w(state); } + DECLARE_WRITE_LINE_MEMBER( txcb_w ) { m_sio->txcb_w(state); } + DECLARE_WRITE_LINE_MEMBER( rxtxcb_w ) { m_sio->rxtxcb_w(state); } + DECLARE_WRITE_LINE_MEMBER( synca_w ) { m_sio->synca_w(state); } + DECLARE_WRITE_LINE_MEMBER( syncb_w ) { m_sio->syncb_w(state); } + + // CTC public interface + DECLARE_WRITE_LINE_MEMBER( trg0 ) { m_ctc->trg0(state); } + DECLARE_WRITE_LINE_MEMBER( trg1 ) { m_ctc->trg1(state); } + DECLARE_WRITE_LINE_MEMBER( trg2 ) { m_ctc->trg2(state); } + DECLARE_WRITE_LINE_MEMBER( trg3 ) { m_ctc->trg3(state); } + + // PIO public interface + DECLARE_READ_LINE_MEMBER( rdy_a ) { return m_pio->rdy_a(); } + DECLARE_READ_LINE_MEMBER( rdy_b ) { return m_pio->rdy_b(); } + DECLARE_WRITE_LINE_MEMBER( strobe_a ) { m_pio->strobe_a(state); } + DECLARE_WRITE_LINE_MEMBER( strobe_b ) { m_pio->strobe_b(state); } + + DECLARE_WRITE8_MEMBER( pa_w ) { m_pio->pa_w(space, offset, data, mem_mask); } + DECLARE_READ8_MEMBER( pa_r ) { return m_pio->pa_r(space, offset, mem_mask); } + DECLARE_WRITE8_MEMBER( pb_w ) { m_pio->pb_w(space, offset, data, mem_mask); } + DECLARE_READ8_MEMBER( pb_r ) { return m_pio->pb_r(space, offset, mem_mask); } + + ///////////////////////////////////////////////////////// + + DECLARE_WRITE8_MEMBER( irq_priority_w ); + + DECLARE_WRITE_LINE_MEMBER( out_txda_cb_trampoline_w ) { m_out_txda_cb(state); } + DECLARE_WRITE_LINE_MEMBER( out_dtra_cb_trampoline_w ) { m_out_dtra_cb(state); } + DECLARE_WRITE_LINE_MEMBER( out_rtsa_cb_trampoline_w ) { m_out_rtsa_cb(state); } + DECLARE_WRITE_LINE_MEMBER( out_wrdya_cb_trampoline_w ) { m_out_wrdya_cb(state); } + DECLARE_WRITE_LINE_MEMBER( out_synca_cb_trampoline_w ) { m_out_synca_cb(state); } + + DECLARE_WRITE_LINE_MEMBER( out_txdb_cb_trampoline_w ) { m_out_txdb_cb(state); } + DECLARE_WRITE_LINE_MEMBER( out_dtrb_cb_trampoline_w ) { m_out_dtrb_cb(state); } + DECLARE_WRITE_LINE_MEMBER( out_rtsb_cb_trampoline_w ) { m_out_rtsb_cb(state); } + DECLARE_WRITE_LINE_MEMBER( out_wrdyb_cb_trampoline_w ) { m_out_wrdyb_cb(state); } + DECLARE_WRITE_LINE_MEMBER( out_syncb_cb_trampoline_w ) { m_out_syncb_cb(state); } + + DECLARE_WRITE_LINE_MEMBER( out_rxdrqa_cb_trampoline_w ) { m_out_rxdrqa_cb(state); } + DECLARE_WRITE_LINE_MEMBER( out_txdrqa_cb_trampoline_w ) { m_out_txdrqa_cb(state); } + DECLARE_WRITE_LINE_MEMBER( out_rxdrqb_cb_trampoline_w ) { m_out_rxdrqb_cb(state); } + DECLARE_WRITE_LINE_MEMBER( out_txdrqb_cb_trampoline_w ) { m_out_txdrqb_cb(state); } + + DECLARE_WRITE_LINE_MEMBER( zc0_cb_trampoline_w ) { m_zc0_cb(state); } + DECLARE_WRITE_LINE_MEMBER( zc1_cb_trampoline_w ) { m_zc1_cb(state); } + DECLARE_WRITE_LINE_MEMBER( zc2_cb_trampoline_w ) { m_zc2_cb(state); } + + DECLARE_READ8_MEMBER( in_pa_cb_trampoline_r ) { return m_in_pa_cb(); } + DECLARE_WRITE8_MEMBER( out_pa_cb_trampoline_w ) { m_out_pa_cb(data); } + DECLARE_WRITE_LINE_MEMBER( out_ardy_cb_trampoline_w ) { m_out_ardy_cb(state); } + + DECLARE_READ8_MEMBER( in_pb_cb_trampoline_r ) { return m_in_pb_cb(); } + DECLARE_WRITE8_MEMBER( out_pb_cb_trampoline_w ) { m_out_pb_cb(data); } + DECLARE_WRITE_LINE_MEMBER( out_brdy_cb_trampoline_w ) { m_out_brdy_cb(state); } + +protected: + // device-level overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual void device_start(); + virtual void device_reset(); + virtual void device_post_load(); + + const address_space_config m_io_space_config; + + const address_space_config *memory_space_config(address_spacenum spacenum) const + { + switch (spacenum) + { + case AS_IO: return &m_io_space_config; + default: return z80_device::memory_space_config(spacenum); + } + } + +private: + // devices/pointers + required_device m_ctc; + required_device m_sio; + required_device m_pio; + + // internal state + UINT8 m_irq_priority; + + // callbacks + devcb_write_line m_out_txda_cb; + devcb_write_line m_out_dtra_cb; + devcb_write_line m_out_rtsa_cb; + devcb_write_line m_out_wrdya_cb; + devcb_write_line m_out_synca_cb; + + devcb_write_line m_out_txdb_cb; + devcb_write_line m_out_dtrb_cb; + devcb_write_line m_out_rtsb_cb; + devcb_write_line m_out_wrdyb_cb; + devcb_write_line m_out_syncb_cb; + + devcb_write_line m_out_rxdrqa_cb; + devcb_write_line m_out_txdrqa_cb; + devcb_write_line m_out_rxdrqb_cb; + devcb_write_line m_out_txdrqb_cb; + + devcb_write_line m_zc0_cb; + devcb_write_line m_zc1_cb; + devcb_write_line m_zc2_cb; + + devcb_read8 m_in_pa_cb; + devcb_write8 m_out_pa_cb; + devcb_write_line m_out_ardy_cb; + + devcb_read8 m_in_pb_cb; + devcb_write8 m_out_pb_cb; + devcb_write_line m_out_brdy_cb; +}; + + +// device type definition +extern const device_type TMPZ84C015; + + +#endif // __TMPZ84C015__ diff --git a/src/devices/cpu/z80/z80.c b/src/devices/cpu/z80/z80.c new file mode 100644 index 00000000000..2b5e2e877f7 --- /dev/null +++ b/src/devices/cpu/z80/z80.c @@ -0,0 +1,3745 @@ +// license:BSD-3-Clause +// copyright-holders:Juergen Buchmueller +/***************************************************************************** + * + * z80.c + * Portable Z80 emulator V3.9 + * + * TODO: + * - Interrupt mode 0 should be able to execute arbitrary opcodes + * - If LD A,I or LD A,R is interrupted, P/V flag gets reset, even if IFF2 + * was set before this instruction (implemented, but not enabled: we need + * document Z80 types first, see below) + * - Ideally, the tiny differences between Z80 types should be supported, + * currently known differences: + * - LD A,I/R P/V flag reset glitch is fixed on CMOS Z80 + * - OUT (C),0 outputs 0 on NMOS Z80, $FF on CMOS Z80 + * - SCF/CCF X/Y flags is ((flags | A) & 0x28) on SGS/SHARP/ZiLOG NMOS Z80, + * (flags & A & 0x28) on NEC NMOS Z80, other models unknown. + * However, people from the Speccy scene mention that SCF/CCF X/Y results + * are inconsistant and may be influenced by I and R registers. + * This Z80 emulator assumes a ZiLOG NMOS model. + * + * Changes in 3.9: + * - Fixed cycle counts for LD IYL/IXL/IYH/IXH,n [Marshmellow] + * - Fixed X/Y flags in CCF/SCF/BIT, ZEXALL is happy now [hap] + * - Simplified DAA, renamed MEMPTR (3.8) to WZ, added TODO [hap] + * - Fixed IM2 interrupt cycles [eke] + * Changes in 3.8 [Miodrag Milanovic]: + * - Added MEMPTR register (according to informations provided + * by Vladimir Kladov + * - BIT n,(HL) now return valid values due to use of MEMPTR + * - Fixed BIT 6,(XY+o) undocumented instructions + * Changes in 3.7 [Aaron Giles]: + * - Changed NMI handling. NMIs are now latched in set_irq_state + * but are not taken there. Instead they are taken at the start of the + * execute loop. + * - Changed IRQ handling. IRQ state is set in set_irq_state but not taken + * except during the inner execute loop. + * - Removed x86 assembly hacks and obsolete timing loop catchers. + * Changes in 3.6: + * - Got rid of the code that would inexactly emulate a Z80, i.e. removed + * all the #if Z80_EXACT #else branches. + * - Removed leading underscores from local register name shortcuts as + * this violates the C99 standard. + * - Renamed the registers inside the Z80 context to lower case to avoid + * ambiguities (shortcuts would have had the same names as the fields + * of the structure). + * Changes in 3.5: + * - Implemented OTIR, INIR, etc. without look-up table for PF flag. + * [Ramsoft, Sean Young] + * Changes in 3.4: + * - Removed Z80-MSX specific code as it's not needed any more. + * - Implemented DAA without look-up table [Ramsoft, Sean Young] + * Changes in 3.3: + * - Fixed undocumented flags XF & YF in the non-asm versions of CP, + * and all the 16 bit arithmetic instructions. [Sean Young] + * Changes in 3.2: + * - Fixed undocumented flags XF & YF of RRCA, and CF and HF of + * INI/IND/OUTI/OUTD/INIR/INDR/OTIR/OTDR [Sean Young] + * Changes in 3.1: + * - removed the REPEAT_AT_ONCE execution of LDIR/CPIR etc. opcodes + * for readabilities sake and because the implementation was buggy + * (and i was not able to find the difference) + * Changes in 3.0: + * - 'finished' switch to dynamically overrideable cycle count tables + * Changes in 2.9: + * - added methods to access and override the cycle count tables + * - fixed handling and timing of multiple DD/FD prefixed opcodes + * Changes in 2.8: + * - OUTI/OUTD/OTIR/OTDR also pre-decrement the B register now. + * This was wrong because of a bug fix on the wrong side + * (astrocade sound driver). + * Changes in 2.7: + * - removed z80_vm specific code, it's not needed (and never was). + * Changes in 2.6: + * - BUSY_LOOP_HACKS needed to call change_pc() earlier, before + * checking the opcodes at the new address, because otherwise they + * might access the old (wrong or even NULL) banked memory region. + * Thanks to Sean Young for finding this nasty bug. + * Changes in 2.5: + * - Burning cycles always adjusts the ICount by a multiple of 4. + * - In REPEAT_AT_ONCE cases the r register wasn't incremented twice + * per repetition as it should have been. Those repeated opcodes + * could also underflow the ICount. + * - Simplified TIME_LOOP_HACKS for BC and added two more for DE + HL + * timing loops. i think those hacks weren't endian safe before too. + * Changes in 2.4: + * - z80_reset zaps the entire context, sets IX and IY to 0xffff(!) and + * sets the Z flag. With these changes the Tehkan World Cup driver + * _seems_ to work again. + * Changes in 2.3: + * - External termination of the execution loop calls z80_burn() and + * z80_vm_burn() to burn an amount of cycles (r adjustment) + * - Shortcuts which burn CPU cycles (BUSY_LOOP_HACKS and TIME_LOOP_HACKS) + * now also adjust the r register depending on the skipped opcodes. + * Changes in 2.2: + * - Fixed bugs in CPL, SCF and CCF instructions flag handling. + * - Changed variable ea and arg16() function to UINT32; this + * produces slightly more efficient code. + * - The DD/FD XY CB opcodes where XY is 40-7F and Y is not 6/E + * are changed to calls to the X6/XE opcodes to reduce object size. + * They're hardly ever used so this should not yield a speed penalty. + * New in 2.0: + * - Optional more exact Z80 emulation (#define Z80_EXACT 1) according + * to a detailed description by Sean Young which can be found at: + * http://www.msxnet.org/tech/z80-documented.pdf + *****************************************************************************/ + +#include "emu.h" +#include "debugger.h" +#include "z80.h" +#include "z80daisy.h" + +#define VERBOSE 0 + +/* On an NMOS Z80, if LD A,I or LD A,R is interrupted, P/V flag gets reset, + even if IFF2 was set before this instruction. This issue was fixed on + the CMOS Z80, so until knowing (most) Z80 types on hardware, it's disabled */ +#define HAS_LDAIR_QUIRK 0 + +#define LOG(x) do { if (VERBOSE) logerror x; } while (0) + + +/****************************************************************************/ +/* The Z80 registers. halt is set to 1 when the CPU is halted, the refresh */ +/* register is calculated as follows: refresh=(r&127)|(r2&128) */ +/****************************************************************************/ + +#define CF 0x01 +#define NF 0x02 +#define PF 0x04 +#define VF PF +#define XF 0x08 +#define HF 0x10 +#define YF 0x20 +#define ZF 0x40 +#define SF 0x80 + +#define INT_IRQ 0x01 +#define NMI_IRQ 0x02 + +#define PRVPC m_prvpc.d /* previous program counter */ + +#define PCD m_pc.d +#define PC m_pc.w.l + +#define SPD m_sp.d +#define SP m_sp.w.l + +#define AFD m_af.d +#define AF m_af.w.l +#define A m_af.b.h +#define F m_af.b.l + +#define BCD m_bc.d +#define BC m_bc.w.l +#define B m_bc.b.h +#define C m_bc.b.l + +#define DED m_de.d +#define DE m_de.w.l +#define D m_de.b.h +#define E m_de.b.l + +#define HLD m_hl.d +#define HL m_hl.w.l +#define H m_hl.b.h +#define L m_hl.b.l + +#define IXD m_ix.d +#define IX m_ix.w.l +#define HX m_ix.b.h +#define LX m_ix.b.l + +#define IYD m_iy.d +#define IY m_iy.w.l +#define HY m_iy.b.h +#define LY m_iy.b.l + +#define WZ m_wz.w.l +#define WZ_H m_wz.b.h +#define WZ_L m_wz.b.l + + +static bool tables_initialised = false; +static UINT8 SZ[256]; /* zero and sign flags */ +static UINT8 SZ_BIT[256]; /* zero, sign and parity/overflow (=zero) flags for BIT opcode */ +static UINT8 SZP[256]; /* zero, sign and parity flags */ +static UINT8 SZHV_inc[256]; /* zero, sign, half carry and overflow flags INC r8 */ +static UINT8 SZHV_dec[256]; /* zero, sign, half carry and overflow flags DEC r8 */ + +static UINT8 SZHVC_add[2*256*256]; +static UINT8 SZHVC_sub[2*256*256]; + +static const UINT8 cc_op[0x100] = { + 4,10, 7, 6, 4, 4, 7, 4, 4,11, 7, 6, 4, 4, 7, 4, + 8,10, 7, 6, 4, 4, 7, 4,12,11, 7, 6, 4, 4, 7, 4, + 7,10,16, 6, 4, 4, 7, 4, 7,11,16, 6, 4, 4, 7, 4, + 7,10,13, 6,11,11,10, 4, 7,11,13, 6, 4, 4, 7, 4, + 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, + 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, + 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, + 7, 7, 7, 7, 7, 7, 4, 7, 4, 4, 4, 4, 4, 4, 7, 4, + 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, + 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, + 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, + 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, + 5,10,10,10,10,11, 7,11, 5,10,10, 0,10,17, 7,11, /* cb -> cc_cb */ + 5,10,10,11,10,11, 7,11, 5, 4,10,11,10, 0, 7,11, /* dd -> cc_xy */ + 5,10,10,19,10,11, 7,11, 5, 4,10, 4,10, 0, 7,11, /* ed -> cc_ed */ + 5,10,10, 4,10,11, 7,11, 5, 6,10, 4,10, 0, 7,11 /* fd -> cc_xy */ +}; + +static const UINT8 cc_cb[0x100] = { + 8, 8, 8, 8, 8, 8,15, 8, 8, 8, 8, 8, 8, 8,15, 8, + 8, 8, 8, 8, 8, 8,15, 8, 8, 8, 8, 8, 8, 8,15, 8, + 8, 8, 8, 8, 8, 8,15, 8, 8, 8, 8, 8, 8, 8,15, 8, + 8, 8, 8, 8, 8, 8,15, 8, 8, 8, 8, 8, 8, 8,15, 8, + 8, 8, 8, 8, 8, 8,12, 8, 8, 8, 8, 8, 8, 8,12, 8, + 8, 8, 8, 8, 8, 8,12, 8, 8, 8, 8, 8, 8, 8,12, 8, + 8, 8, 8, 8, 8, 8,12, 8, 8, 8, 8, 8, 8, 8,12, 8, + 8, 8, 8, 8, 8, 8,12, 8, 8, 8, 8, 8, 8, 8,12, 8, + 8, 8, 8, 8, 8, 8,15, 8, 8, 8, 8, 8, 8, 8,15, 8, + 8, 8, 8, 8, 8, 8,15, 8, 8, 8, 8, 8, 8, 8,15, 8, + 8, 8, 8, 8, 8, 8,15, 8, 8, 8, 8, 8, 8, 8,15, 8, + 8, 8, 8, 8, 8, 8,15, 8, 8, 8, 8, 8, 8, 8,15, 8, + 8, 8, 8, 8, 8, 8,15, 8, 8, 8, 8, 8, 8, 8,15, 8, + 8, 8, 8, 8, 8, 8,15, 8, 8, 8, 8, 8, 8, 8,15, 8, + 8, 8, 8, 8, 8, 8,15, 8, 8, 8, 8, 8, 8, 8,15, 8, + 8, 8, 8, 8, 8, 8,15, 8, 8, 8, 8, 8, 8, 8,15, 8 +}; + +static const UINT8 cc_ed[0x100] = { + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, +12,12,15,20, 8,14, 8, 9,12,12,15,20, 8,14, 8, 9, +12,12,15,20, 8,14, 8, 9,12,12,15,20, 8,14, 8, 9, +12,12,15,20, 8,14, 8,18,12,12,15,20, 8,14, 8,18, +12,12,15,20, 8,14, 8, 8,12,12,15,20, 8,14, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, +16,16,16,16, 8, 8, 8, 8,16,16,16,16, 8, 8, 8, 8, +16,16,16,16, 8, 8, 8, 8,16,16,16,16, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8 +}; + +/* ix/iy: with the exception of (i+offset) opcodes, t-states are main_opcode_table + 4 */ +static const UINT8 cc_xy[0x100] = { + 4+4,10+4, 7+4, 6+4, 4+4, 4+4, 7+4, 4+4, 4+4,11+4, 7+4, 6+4, 4+4, 4+4, 7+4, 4+4, + 8+4,10+4, 7+4, 6+4, 4+4, 4+4, 7+4, 4+4,12+4,11+4, 7+4, 6+4, 4+4, 4+4, 7+4, 4+4, + 7+4,10+4,16+4, 6+4, 4+4, 4+4, 7+4, 4+4, 7+4,11+4,16+4, 6+4, 4+4, 4+4, 7+4, 4+4, + 7+4,10+4,13+4, 6+4,23 ,23 ,19 , 4+4, 7+4,11+4,13+4, 6+4, 4+4, 4+4, 7+4, 4+4, + 4+4, 4+4, 4+4, 4+4, 4+4, 4+4,19 , 4+4, 4+4, 4+4, 4+4, 4+4, 4+4, 4+4,19 , 4+4, + 4+4, 4+4, 4+4, 4+4, 4+4, 4+4,19 , 4+4, 4+4, 4+4, 4+4, 4+4, 4+4, 4+4,19 , 4+4, + 4+4, 4+4, 4+4, 4+4, 4+4, 4+4,19 , 4+4, 4+4, 4+4, 4+4, 4+4, 4+4, 4+4,19 , 4+4, +19 ,19 ,19 ,19 ,19 ,19 , 4+4,19 , 4+4, 4+4, 4+4, 4+4, 4+4, 4+4,19 , 4+4, + 4+4, 4+4, 4+4, 4+4, 4+4, 4+4,19 , 4+4, 4+4, 4+4, 4+4, 4+4, 4+4, 4+4,19 , 4+4, + 4+4, 4+4, 4+4, 4+4, 4+4, 4+4,19 , 4+4, 4+4, 4+4, 4+4, 4+4, 4+4, 4+4,19 , 4+4, + 4+4, 4+4, 4+4, 4+4, 4+4, 4+4,19 , 4+4, 4+4, 4+4, 4+4, 4+4, 4+4, 4+4,19 , 4+4, + 4+4, 4+4, 4+4, 4+4, 4+4, 4+4,19 , 4+4, 4+4, 4+4, 4+4, 4+4, 4+4, 4+4,19 , 4+4, + 5+4,10+4,10+4,10+4,10+4,11+4, 7+4,11+4, 5+4,10+4,10+4, 0 ,10+4,17+4, 7+4,11+4, /* cb -> cc_xycb */ + 5+4,10+4,10+4,11+4,10+4,11+4, 7+4,11+4, 5+4, 4+4,10+4,11+4,10+4, 4 , 7+4,11+4, /* dd -> cc_xy again */ + 5+4,10+4,10+4,19+4,10+4,11+4, 7+4,11+4, 5+4, 4+4,10+4, 4+4,10+4, 4 , 7+4,11+4, /* ed -> cc_ed */ + 5+4,10+4,10+4, 4+4,10+4,11+4, 7+4,11+4, 5+4, 6+4,10+4, 4+4,10+4, 4 , 7+4,11+4 /* fd -> cc_xy again */ +}; + +static const UINT8 cc_xycb[0x100] = { +23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23, +23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23, +23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23, +23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23, +20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20, +20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20, +20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20, +20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20, +23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23, +23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23, +23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23, +23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23, +23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23, +23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23, +23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23, +23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23 +}; + +/* extra cycles if jr/jp/call taken and 'interrupt latency' on rst 0-7 */ +static const UINT8 cc_ex[0x100] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* DJNZ */ + 5, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, /* JR NZ/JR Z */ + 5, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, /* JR NC/JR C */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 5, 5, 5, 5, 0, 0, 0, 0, 5, 5, 5, 5, 0, 0, 0, 0, /* LDIR/CPIR/INIR/OTIR LDDR/CPDR/INDR/OTDR */ + 6, 0, 0, 0, 7, 0, 0, 2, 6, 0, 0, 0, 7, 0, 0, 2, + 6, 0, 0, 0, 7, 0, 0, 2, 6, 0, 0, 0, 7, 0, 0, 2, + 6, 0, 0, 0, 7, 0, 0, 2, 6, 0, 0, 0, 7, 0, 0, 2, + 6, 0, 0, 0, 7, 0, 0, 2, 6, 0, 0, 0, 7, 0, 0, 2 +}; + +#define m_cc_dd m_cc_xy +#define m_cc_fd m_cc_xy + +/*************************************************************** + * define an opcode function + ***************************************************************/ +#define OP(prefix,opcode) inline void z80_device::prefix##_##opcode() + +/*************************************************************** + * adjust cycle count by n T-states + ***************************************************************/ +#define CC(prefix,opcode) do { m_icount -= m_cc_##prefix[opcode]; } while (0) + +#define EXEC(prefix,opcode) do { \ + unsigned op = opcode; \ + CC(prefix,op); \ + switch(op) \ + { \ + case 0x00:prefix##_##00();break; case 0x01:prefix##_##01();break; case 0x02:prefix##_##02();break; case 0x03:prefix##_##03();break; \ + case 0x04:prefix##_##04();break; case 0x05:prefix##_##05();break; case 0x06:prefix##_##06();break; case 0x07:prefix##_##07();break; \ + case 0x08:prefix##_##08();break; case 0x09:prefix##_##09();break; case 0x0a:prefix##_##0a();break; case 0x0b:prefix##_##0b();break; \ + case 0x0c:prefix##_##0c();break; case 0x0d:prefix##_##0d();break; case 0x0e:prefix##_##0e();break; case 0x0f:prefix##_##0f();break; \ + case 0x10:prefix##_##10();break; case 0x11:prefix##_##11();break; case 0x12:prefix##_##12();break; case 0x13:prefix##_##13();break; \ + case 0x14:prefix##_##14();break; case 0x15:prefix##_##15();break; case 0x16:prefix##_##16();break; case 0x17:prefix##_##17();break; \ + case 0x18:prefix##_##18();break; case 0x19:prefix##_##19();break; case 0x1a:prefix##_##1a();break; case 0x1b:prefix##_##1b();break; \ + case 0x1c:prefix##_##1c();break; case 0x1d:prefix##_##1d();break; case 0x1e:prefix##_##1e();break; case 0x1f:prefix##_##1f();break; \ + case 0x20:prefix##_##20();break; case 0x21:prefix##_##21();break; case 0x22:prefix##_##22();break; case 0x23:prefix##_##23();break; \ + case 0x24:prefix##_##24();break; case 0x25:prefix##_##25();break; case 0x26:prefix##_##26();break; case 0x27:prefix##_##27();break; \ + case 0x28:prefix##_##28();break; case 0x29:prefix##_##29();break; case 0x2a:prefix##_##2a();break; case 0x2b:prefix##_##2b();break; \ + case 0x2c:prefix##_##2c();break; case 0x2d:prefix##_##2d();break; case 0x2e:prefix##_##2e();break; case 0x2f:prefix##_##2f();break; \ + case 0x30:prefix##_##30();break; case 0x31:prefix##_##31();break; case 0x32:prefix##_##32();break; case 0x33:prefix##_##33();break; \ + case 0x34:prefix##_##34();break; case 0x35:prefix##_##35();break; case 0x36:prefix##_##36();break; case 0x37:prefix##_##37();break; \ + case 0x38:prefix##_##38();break; case 0x39:prefix##_##39();break; case 0x3a:prefix##_##3a();break; case 0x3b:prefix##_##3b();break; \ + case 0x3c:prefix##_##3c();break; case 0x3d:prefix##_##3d();break; case 0x3e:prefix##_##3e();break; case 0x3f:prefix##_##3f();break; \ + case 0x40:prefix##_##40();break; case 0x41:prefix##_##41();break; case 0x42:prefix##_##42();break; case 0x43:prefix##_##43();break; \ + case 0x44:prefix##_##44();break; case 0x45:prefix##_##45();break; case 0x46:prefix##_##46();break; case 0x47:prefix##_##47();break; \ + case 0x48:prefix##_##48();break; case 0x49:prefix##_##49();break; case 0x4a:prefix##_##4a();break; case 0x4b:prefix##_##4b();break; \ + case 0x4c:prefix##_##4c();break; case 0x4d:prefix##_##4d();break; case 0x4e:prefix##_##4e();break; case 0x4f:prefix##_##4f();break; \ + case 0x50:prefix##_##50();break; case 0x51:prefix##_##51();break; case 0x52:prefix##_##52();break; case 0x53:prefix##_##53();break; \ + case 0x54:prefix##_##54();break; case 0x55:prefix##_##55();break; case 0x56:prefix##_##56();break; case 0x57:prefix##_##57();break; \ + case 0x58:prefix##_##58();break; case 0x59:prefix##_##59();break; case 0x5a:prefix##_##5a();break; case 0x5b:prefix##_##5b();break; \ + case 0x5c:prefix##_##5c();break; case 0x5d:prefix##_##5d();break; case 0x5e:prefix##_##5e();break; case 0x5f:prefix##_##5f();break; \ + case 0x60:prefix##_##60();break; case 0x61:prefix##_##61();break; case 0x62:prefix##_##62();break; case 0x63:prefix##_##63();break; \ + case 0x64:prefix##_##64();break; case 0x65:prefix##_##65();break; case 0x66:prefix##_##66();break; case 0x67:prefix##_##67();break; \ + case 0x68:prefix##_##68();break; case 0x69:prefix##_##69();break; case 0x6a:prefix##_##6a();break; case 0x6b:prefix##_##6b();break; \ + case 0x6c:prefix##_##6c();break; case 0x6d:prefix##_##6d();break; case 0x6e:prefix##_##6e();break; case 0x6f:prefix##_##6f();break; \ + case 0x70:prefix##_##70();break; case 0x71:prefix##_##71();break; case 0x72:prefix##_##72();break; case 0x73:prefix##_##73();break; \ + case 0x74:prefix##_##74();break; case 0x75:prefix##_##75();break; case 0x76:prefix##_##76();break; case 0x77:prefix##_##77();break; \ + case 0x78:prefix##_##78();break; case 0x79:prefix##_##79();break; case 0x7a:prefix##_##7a();break; case 0x7b:prefix##_##7b();break; \ + case 0x7c:prefix##_##7c();break; case 0x7d:prefix##_##7d();break; case 0x7e:prefix##_##7e();break; case 0x7f:prefix##_##7f();break; \ + case 0x80:prefix##_##80();break; case 0x81:prefix##_##81();break; case 0x82:prefix##_##82();break; case 0x83:prefix##_##83();break; \ + case 0x84:prefix##_##84();break; case 0x85:prefix##_##85();break; case 0x86:prefix##_##86();break; case 0x87:prefix##_##87();break; \ + case 0x88:prefix##_##88();break; case 0x89:prefix##_##89();break; case 0x8a:prefix##_##8a();break; case 0x8b:prefix##_##8b();break; \ + case 0x8c:prefix##_##8c();break; case 0x8d:prefix##_##8d();break; case 0x8e:prefix##_##8e();break; case 0x8f:prefix##_##8f();break; \ + case 0x90:prefix##_##90();break; case 0x91:prefix##_##91();break; case 0x92:prefix##_##92();break; case 0x93:prefix##_##93();break; \ + case 0x94:prefix##_##94();break; case 0x95:prefix##_##95();break; case 0x96:prefix##_##96();break; case 0x97:prefix##_##97();break; \ + case 0x98:prefix##_##98();break; case 0x99:prefix##_##99();break; case 0x9a:prefix##_##9a();break; case 0x9b:prefix##_##9b();break; \ + case 0x9c:prefix##_##9c();break; case 0x9d:prefix##_##9d();break; case 0x9e:prefix##_##9e();break; case 0x9f:prefix##_##9f();break; \ + case 0xa0:prefix##_##a0();break; case 0xa1:prefix##_##a1();break; case 0xa2:prefix##_##a2();break; case 0xa3:prefix##_##a3();break; \ + case 0xa4:prefix##_##a4();break; case 0xa5:prefix##_##a5();break; case 0xa6:prefix##_##a6();break; case 0xa7:prefix##_##a7();break; \ + case 0xa8:prefix##_##a8();break; case 0xa9:prefix##_##a9();break; case 0xaa:prefix##_##aa();break; case 0xab:prefix##_##ab();break; \ + case 0xac:prefix##_##ac();break; case 0xad:prefix##_##ad();break; case 0xae:prefix##_##ae();break; case 0xaf:prefix##_##af();break; \ + case 0xb0:prefix##_##b0();break; case 0xb1:prefix##_##b1();break; case 0xb2:prefix##_##b2();break; case 0xb3:prefix##_##b3();break; \ + case 0xb4:prefix##_##b4();break; case 0xb5:prefix##_##b5();break; case 0xb6:prefix##_##b6();break; case 0xb7:prefix##_##b7();break; \ + case 0xb8:prefix##_##b8();break; case 0xb9:prefix##_##b9();break; case 0xba:prefix##_##ba();break; case 0xbb:prefix##_##bb();break; \ + case 0xbc:prefix##_##bc();break; case 0xbd:prefix##_##bd();break; case 0xbe:prefix##_##be();break; case 0xbf:prefix##_##bf();break; \ + case 0xc0:prefix##_##c0();break; case 0xc1:prefix##_##c1();break; case 0xc2:prefix##_##c2();break; case 0xc3:prefix##_##c3();break; \ + case 0xc4:prefix##_##c4();break; case 0xc5:prefix##_##c5();break; case 0xc6:prefix##_##c6();break; case 0xc7:prefix##_##c7();break; \ + case 0xc8:prefix##_##c8();break; case 0xc9:prefix##_##c9();break; case 0xca:prefix##_##ca();break; case 0xcb:prefix##_##cb();break; \ + case 0xcc:prefix##_##cc();break; case 0xcd:prefix##_##cd();break; case 0xce:prefix##_##ce();break; case 0xcf:prefix##_##cf();break; \ + case 0xd0:prefix##_##d0();break; case 0xd1:prefix##_##d1();break; case 0xd2:prefix##_##d2();break; case 0xd3:prefix##_##d3();break; \ + case 0xd4:prefix##_##d4();break; case 0xd5:prefix##_##d5();break; case 0xd6:prefix##_##d6();break; case 0xd7:prefix##_##d7();break; \ + case 0xd8:prefix##_##d8();break; case 0xd9:prefix##_##d9();break; case 0xda:prefix##_##da();break; case 0xdb:prefix##_##db();break; \ + case 0xdc:prefix##_##dc();break; case 0xdd:prefix##_##dd();break; case 0xde:prefix##_##de();break; case 0xdf:prefix##_##df();break; \ + case 0xe0:prefix##_##e0();break; case 0xe1:prefix##_##e1();break; case 0xe2:prefix##_##e2();break; case 0xe3:prefix##_##e3();break; \ + case 0xe4:prefix##_##e4();break; case 0xe5:prefix##_##e5();break; case 0xe6:prefix##_##e6();break; case 0xe7:prefix##_##e7();break; \ + case 0xe8:prefix##_##e8();break; case 0xe9:prefix##_##e9();break; case 0xea:prefix##_##ea();break; case 0xeb:prefix##_##eb();break; \ + case 0xec:prefix##_##ec();break; case 0xed:prefix##_##ed();break; case 0xee:prefix##_##ee();break; case 0xef:prefix##_##ef();break; \ + case 0xf0:prefix##_##f0();break; case 0xf1:prefix##_##f1();break; case 0xf2:prefix##_##f2();break; case 0xf3:prefix##_##f3();break; \ + case 0xf4:prefix##_##f4();break; case 0xf5:prefix##_##f5();break; case 0xf6:prefix##_##f6();break; case 0xf7:prefix##_##f7();break; \ + case 0xf8:prefix##_##f8();break; case 0xf9:prefix##_##f9();break; case 0xfa:prefix##_##fa();break; case 0xfb:prefix##_##fb();break; \ + case 0xfc:prefix##_##fc();break; case 0xfd:prefix##_##fd();break; case 0xfe:prefix##_##fe();break; case 0xff:prefix##_##ff();break; \ + } \ +} while (0) + +/*************************************************************** + * Enter halt state; write 1 to fake port on first execution + ***************************************************************/ +inline void z80_device::halt() +{ + PC--; + m_halt = 1; +} + +/*************************************************************** + * Leave halt state; write 0 to fake port + ***************************************************************/ +inline void z80_device::leave_halt() +{ + if( m_halt ) + { + m_halt = 0; + PC++; + } +} + +/*************************************************************** + * Input a byte from given I/O port + ***************************************************************/ +inline UINT8 z80_device::in(UINT16 port) +{ + return m_io->read_byte(port); +} + +/*************************************************************** + * Output a byte to given I/O port + ***************************************************************/ +inline void z80_device::out(UINT16 port, UINT8 value) +{ + m_io->write_byte(port, value); +} + +/*************************************************************** + * Read a byte from given memory location + ***************************************************************/ +inline UINT8 z80_device::rm(UINT16 addr) +{ + return m_program->read_byte(addr); +} + +/*************************************************************** + * Read a word from given memory location + ***************************************************************/ +inline void z80_device::rm16(UINT16 addr, PAIR &r) +{ + r.b.l = rm(addr); + r.b.h = rm((addr+1)); +} + +/*************************************************************** + * Write a byte to given memory location + ***************************************************************/ +inline void z80_device::wm(UINT16 addr, UINT8 value) +{ + m_program->write_byte(addr, value); +} + +/*************************************************************** + * Write a word to given memory location + ***************************************************************/ +inline void z80_device::wm16(UINT16 addr, PAIR &r) +{ + wm(addr, r.b.l); + wm((addr+1), r.b.h); +} + +/*************************************************************** + * rop() is identical to rm() except it is used for + * reading opcodes. In case of system with memory mapped I/O, + * this function can be used to greatly speed up emulation + ***************************************************************/ +inline UINT8 z80_device::rop() +{ + unsigned pc = PCD; + PC++; + return m_decrypted_opcodes_direct->read_byte(pc); +} + +/**************************************************************** + * arg() is identical to rop() except it is used + * for reading opcode arguments. This difference can be used to + * support systems that use different encoding mechanisms for + * opcodes and opcode arguments + ***************************************************************/ +inline UINT8 z80_device::arg() +{ + unsigned pc = PCD; + PC++; + return m_direct->read_byte(pc); +} + +inline UINT16 z80_device::arg16() +{ + unsigned pc = PCD; + PC += 2; + return m_direct->read_byte(pc) | (m_direct->read_byte((pc+1)&0xffff) << 8); +} + +/*************************************************************** + * Calculate the effective address EA of an opcode using + * IX+offset resp. IY+offset addressing. + ***************************************************************/ +inline void z80_device::eax() +{ + m_ea = (UINT32)(UINT16)(IX + (INT8)arg()); + WZ = m_ea; +} + +inline void z80_device::eay() +{ + m_ea = (UINT32)(UINT16)(IY + (INT8)arg()); + WZ = m_ea; +} + +/*************************************************************** + * POP + ***************************************************************/ +inline void z80_device::pop(PAIR &r) +{ + rm16(SPD, r); + SP += 2; +} + +/*************************************************************** + * PUSH + ***************************************************************/ +inline void z80_device::push(PAIR &r) +{ + SP -= 2; + wm16(SPD, r); +} + +/*************************************************************** + * JP + ***************************************************************/ +inline void z80_device::jp(void) +{ + PCD = arg16(); + WZ = PCD; +} + +/*************************************************************** + * JP_COND + ***************************************************************/ +inline void z80_device::jp_cond(bool cond) +{ + if (cond) + { + PCD = arg16(); + WZ = PCD; + } + else + { + WZ = arg16(); /* implicit do PC += 2 */ + } +} + +/*************************************************************** + * JR + ***************************************************************/ +inline void z80_device::jr() +{ + INT8 a = (INT8)arg(); /* arg() also increments PC */ + PC += a; /* so don't do PC += arg() */ + WZ = PC; +} + +/*************************************************************** + * JR_COND + ***************************************************************/ +inline void z80_device::jr_cond(bool cond, UINT8 opcode) +{ + if (cond) + { + jr(); + CC(ex, opcode); + } + else + PC++; +} + +/*************************************************************** + * CALL + ***************************************************************/ +inline void z80_device::call() +{ + m_ea = arg16(); + WZ = m_ea; + push(m_pc); + PCD = m_ea; +} + +/*************************************************************** + * CALL_COND + ***************************************************************/ +inline void z80_device::call_cond(bool cond, UINT8 opcode) +{ + if (cond) + { + m_ea = arg16(); + WZ = m_ea; + push(m_pc); + PCD = m_ea; + CC(ex, opcode); + } + else + { + WZ = arg16(); /* implicit call PC+=2; */ + } +} + +/*************************************************************** + * RET_COND + ***************************************************************/ +inline void z80_device::ret_cond(bool cond, UINT8 opcode) +{ + if (cond) + { + pop(m_pc); + WZ = PC; + CC(ex, opcode); + } +} + +/*************************************************************** + * RETN + ***************************************************************/ +inline void z80_device::retn() +{ + LOG(("Z80 '%s' RETN m_iff1:%d m_iff2:%d\n", + tag(), m_iff1, m_iff2)); + pop(m_pc); + WZ = PC; + m_iff1 = m_iff2; +} + +/*************************************************************** + * RETI + ***************************************************************/ +inline void z80_device::reti() +{ + pop(m_pc); + WZ = PC; + m_iff1 = m_iff2; + m_daisy.call_reti_device(); +} + +/*************************************************************** + * LD R,A + ***************************************************************/ +inline void z80_device::ld_r_a() +{ + m_r = A; + m_r2 = A & 0x80; /* keep bit 7 of r */ +} + +/*************************************************************** + * LD A,R + ***************************************************************/ +inline void z80_device::ld_a_r() +{ + A = (m_r & 0x7f) | m_r2; + F = (F & CF) | SZ[A] | (m_iff2 << 2); + m_after_ldair = TRUE; +} + +/*************************************************************** + * LD I,A + ***************************************************************/ +inline void z80_device::ld_i_a() +{ + m_i = A; +} + +/*************************************************************** + * LD A,I + ***************************************************************/ +inline void z80_device::ld_a_i() +{ + A = m_i; + F = (F & CF) | SZ[A] | (m_iff2 << 2); + m_after_ldair = TRUE; +} + +/*************************************************************** + * RST + ***************************************************************/ +inline void z80_device::rst(UINT16 addr) +{ + push(m_pc); + PCD = addr; + WZ = PC; +} + +/*************************************************************** + * INC r8 + ***************************************************************/ +inline UINT8 z80_device::inc(UINT8 value) +{ + UINT8 res = value + 1; + F = (F & CF) | SZHV_inc[res]; + return (UINT8)res; +} + +/*************************************************************** + * DEC r8 + ***************************************************************/ +inline UINT8 z80_device::dec(UINT8 value) +{ + UINT8 res = value - 1; + F = (F & CF) | SZHV_dec[res]; + return res; +} + +/*************************************************************** + * RLCA + ***************************************************************/ +inline void z80_device::rlca() +{ + A = (A << 1) | (A >> 7); + F = (F & (SF | ZF | PF)) | (A & (YF | XF | CF)); +} + +/*************************************************************** + * RRCA + ***************************************************************/ +inline void z80_device::rrca() +{ + F = (F & (SF | ZF | PF)) | (A & CF); + A = (A >> 1) | (A << 7); + F |= (A & (YF | XF)); +} + +/*************************************************************** + * RLA + ***************************************************************/ +inline void z80_device::rla() +{ + UINT8 res = (A << 1) | (F & CF); + UINT8 c = (A & 0x80) ? CF : 0; + F = (F & (SF | ZF | PF)) | c | (res & (YF | XF)); + A = res; +} + +/*************************************************************** + * RRA + ***************************************************************/ +inline void z80_device::rra() +{ + UINT8 res = (A >> 1) | (F << 7); + UINT8 c = (A & 0x01) ? CF : 0; + F = (F & (SF | ZF | PF)) | c | (res & (YF | XF)); + A = res; +} + +/*************************************************************** + * RRD + ***************************************************************/ +inline void z80_device::rrd() +{ + UINT8 n = rm(HL); + WZ = HL+1; + wm(HL, (n >> 4) | (A << 4)); + A = (A & 0xf0) | (n & 0x0f); + F = (F & CF) | SZP[A]; +} + +/*************************************************************** + * RLD + ***************************************************************/ +inline void z80_device::rld() +{ + UINT8 n = rm(HL); + WZ = HL+1; + wm(HL, (n << 4) | (A & 0x0f)); + A = (A & 0xf0) | (n >> 4); + F = (F & CF) | SZP[A]; +} + +/*************************************************************** + * ADD A,n + ***************************************************************/ +inline void z80_device::add_a(UINT8 value) +{ + UINT32 ah = AFD & 0xff00; + UINT32 res = (UINT8)((ah >> 8) + value); + F = SZHVC_add[ah | res]; + A = res; +} + +/*************************************************************** + * ADC A,n + ***************************************************************/ +inline void z80_device::adc_a(UINT8 value) +{ + UINT32 ah = AFD & 0xff00, c = AFD & 1; + UINT32 res = (UINT8)((ah >> 8) + value + c); + F = SZHVC_add[(c << 16) | ah | res]; + A = res; +} + +/*************************************************************** + * SUB n + ***************************************************************/ +inline void z80_device::sub(UINT8 value) +{ + UINT32 ah = AFD & 0xff00; + UINT32 res = (UINT8)((ah >> 8) - value); + F = SZHVC_sub[ah | res]; + A = res; +} + +/*************************************************************** + * SBC A,n + ***************************************************************/ +inline void z80_device::sbc_a(UINT8 value) +{ + UINT32 ah = AFD & 0xff00, c = AFD & 1; + UINT32 res = (UINT8)((ah >> 8) - value - c); + F = SZHVC_sub[(c<<16) | ah | res]; + A = res; +} + +/*************************************************************** + * NEG + ***************************************************************/ +inline void z80_device::neg() +{ + UINT8 value = A; + A = 0; + sub(value); +} + +/*************************************************************** + * DAA + ***************************************************************/ +inline void z80_device::daa() +{ + UINT8 a = A; + if (F & NF) { + if ((F&HF) | ((A&0xf)>9)) a-=6; + if ((F&CF) | (A>0x99)) a-=0x60; + } + else { + if ((F&HF) | ((A&0xf)>9)) a+=6; + if ((F&CF) | (A>0x99)) a+=0x60; + } + + F = (F&(CF|NF)) | (A>0x99) | ((A^a)&HF) | SZP[a]; + A = a; +} + +/*************************************************************** + * AND n + ***************************************************************/ +inline void z80_device::and_a(UINT8 value) +{ + A &= value; + F = SZP[A] | HF; +} + +/*************************************************************** + * OR n + ***************************************************************/ +inline void z80_device::or_a(UINT8 value) +{ + A |= value; + F = SZP[A]; +} + +/*************************************************************** + * XOR n + ***************************************************************/ +inline void z80_device::xor_a(UINT8 value) +{ + A ^= value; + F = SZP[A]; +} + +/*************************************************************** + * CP n + ***************************************************************/ +inline void z80_device::cp(UINT8 value) +{ + unsigned val = value; + UINT32 ah = AFD & 0xff00; + UINT32 res = (UINT8)((ah >> 8) - val); + F = (SZHVC_sub[ah | res] & ~(YF | XF)) | + (val & (YF | XF)); +} + +/*************************************************************** + * EX AF,AF' + ***************************************************************/ +inline void z80_device::ex_af() +{ + PAIR tmp; + tmp = m_af; m_af = m_af2; m_af2 = tmp; +} + +/*************************************************************** + * EX DE,HL + ***************************************************************/ +inline void z80_device::ex_de_hl() +{ + PAIR tmp; + tmp = m_de; m_de = m_hl; m_hl = tmp; +} + +/*************************************************************** + * EXX + ***************************************************************/ +inline void z80_device::exx() +{ + PAIR tmp; + tmp = m_bc; m_bc = m_bc2; m_bc2 = tmp; + tmp = m_de; m_de = m_de2; m_de2 = tmp; + tmp = m_hl; m_hl = m_hl2; m_hl2 = tmp; +} + +/*************************************************************** + * EX (SP),r16 + ***************************************************************/ +inline void z80_device::ex_sp(PAIR &r) +{ + PAIR tmp = { { 0, 0, 0, 0 } }; + rm16(SPD, tmp); + wm16(SPD, r); + r = tmp; + WZ = r.d; +} + +/*************************************************************** + * ADD16 + ***************************************************************/ +inline void z80_device::add16(PAIR &dr, PAIR &sr) +{ + UINT32 res = dr.d + sr.d; + WZ = dr.d + 1; + F = (F & (SF | ZF | VF)) | + (((dr.d ^ res ^ sr.d) >> 8) & HF) | + ((res >> 16) & CF) | ((res >> 8) & (YF | XF)); + dr.w.l = (UINT16)res; +} + +/*************************************************************** + * ADC HL,r16 + ***************************************************************/ +inline void z80_device::adc_hl(PAIR &r) +{ + UINT32 res = HLD + r.d + (F & CF); + WZ = HL + 1; + F = (((HLD ^ res ^ r.d) >> 8) & HF) | + ((res >> 16) & CF) | + ((res >> 8) & (SF | YF | XF)) | + ((res & 0xffff) ? 0 : ZF) | + (((r.d ^ HLD ^ 0x8000) & (r.d ^ res) & 0x8000) >> 13); + HL = (UINT16)res; +} + +/*************************************************************** + * SBC HL,r16 + ***************************************************************/ +inline void z80_device::sbc_hl(PAIR &r) +{ + UINT32 res = HLD - r.d - (F & CF); + WZ = HL + 1; + F = (((HLD ^ res ^ r.d) >> 8) & HF) | NF | + ((res >> 16) & CF) | + ((res >> 8) & (SF | YF | XF)) | + ((res & 0xffff) ? 0 : ZF) | + (((r.d ^ HLD) & (HLD ^ res) &0x8000) >> 13); + HL = (UINT16)res; +} + +/*************************************************************** + * RLC r8 + ***************************************************************/ +inline UINT8 z80_device::rlc(UINT8 value) +{ + unsigned res = value; + unsigned c = (res & 0x80) ? CF : 0; + res = ((res << 1) | (res >> 7)) & 0xff; + F = SZP[res] | c; + return res; +} + +/*************************************************************** + * RRC r8 + ***************************************************************/ +inline UINT8 z80_device::rrc(UINT8 value) +{ + unsigned res = value; + unsigned c = (res & 0x01) ? CF : 0; + res = ((res >> 1) | (res << 7)) & 0xff; + F = SZP[res] | c; + return res; +} + +/*************************************************************** + * RL r8 + ***************************************************************/ +inline UINT8 z80_device::rl(UINT8 value) +{ + unsigned res = value; + unsigned c = (res & 0x80) ? CF : 0; + res = ((res << 1) | (F & CF)) & 0xff; + F = SZP[res] | c; + return res; +} + +/*************************************************************** + * RR r8 + ***************************************************************/ +inline UINT8 z80_device::rr(UINT8 value) +{ + unsigned res = value; + unsigned c = (res & 0x01) ? CF : 0; + res = ((res >> 1) | (F << 7)) & 0xff; + F = SZP[res] | c; + return res; +} + +/*************************************************************** + * SLA r8 + ***************************************************************/ +inline UINT8 z80_device::sla(UINT8 value) +{ + unsigned res = value; + unsigned c = (res & 0x80) ? CF : 0; + res = (res << 1) & 0xff; + F = SZP[res] | c; + return res; +} + +/*************************************************************** + * SRA r8 + ***************************************************************/ +inline UINT8 z80_device::sra(UINT8 value) +{ + unsigned res = value; + unsigned c = (res & 0x01) ? CF : 0; + res = ((res >> 1) | (res & 0x80)) & 0xff; + F = SZP[res] | c; + return res; +} + +/*************************************************************** + * SLL r8 + ***************************************************************/ +inline UINT8 z80_device::sll(UINT8 value) +{ + unsigned res = value; + unsigned c = (res & 0x80) ? CF : 0; + res = ((res << 1) | 0x01) & 0xff; + F = SZP[res] | c; + return res; +} + +/*************************************************************** + * SRL r8 + ***************************************************************/ +inline UINT8 z80_device::srl(UINT8 value) +{ + unsigned res = value; + unsigned c = (res & 0x01) ? CF : 0; + res = (res >> 1) & 0xff; + F = SZP[res] | c; + return res; +} + +/*************************************************************** + * BIT bit,r8 + ***************************************************************/ +inline void z80_device::bit(int bit, UINT8 value) +{ + F = (F & CF) | HF | (SZ_BIT[value & (1<>8) & (YF|XF)); +} + +/*************************************************************** + * RES bit,r8 + ***************************************************************/ +inline UINT8 z80_device::res(int bit, UINT8 value) +{ + return value & ~(1< flag 5 */ + if ((A + io) & 0x08) F |= XF; /* bit 3 -> flag 3 */ + HL++; DE++; BC--; + if(BC) F |= VF; +} + +/*************************************************************** + * CPI + ***************************************************************/ +inline void z80_device::cpi() +{ + UINT8 val = rm(HL); + UINT8 res = A - val; + WZ++; + HL++; BC--; + F = (F & CF) | (SZ[res]&~(YF|XF)) | ((A^val^res)&HF) | NF; + if (F & HF) res -= 1; + if (res & 0x02) F |= YF; /* bit 1 -> flag 5 */ + if (res & 0x08) F |= XF; /* bit 3 -> flag 3 */ + if (BC) F |= VF; +} + +/*************************************************************** + * INI + ***************************************************************/ +inline void z80_device::ini() +{ + unsigned t; + UINT8 io = in(BC); + WZ = BC + 1; + B--; + wm(HL, io); + HL++; + F = SZ[B]; + t = (unsigned)((C + 1) & 0xff) + (unsigned)io; + if (io & SF) F |= NF; + if (t & 0x100) F |= HF | CF; + F |= SZP[(UINT8)(t & 0x07) ^ B] & PF; +} + +/*************************************************************** + * OUTI + ***************************************************************/ +inline void z80_device::outi() +{ + unsigned t; + UINT8 io = rm(HL); + B--; + WZ = BC + 1; + out(BC, io); + HL++; + F = SZ[B]; + t = (unsigned)L + (unsigned)io; + if (io & SF) F |= NF; + if (t & 0x100) F |= HF | CF; + F |= SZP[(UINT8)(t & 0x07) ^ B] & PF; +} + +/*************************************************************** + * LDD + ***************************************************************/ +inline void z80_device::ldd() +{ + UINT8 io = rm(HL); + wm(DE, io); + F &= SF | ZF | CF; + if ((A + io) & 0x02) F |= YF; /* bit 1 -> flag 5 */ + if ((A + io) & 0x08) F |= XF; /* bit 3 -> flag 3 */ + HL--; DE--; BC--; + if (BC) F |= VF; +} + +/*************************************************************** + * CPD + ***************************************************************/ +inline void z80_device::cpd() +{ + UINT8 val = rm(HL); + UINT8 res = A - val; + WZ--; + HL--; BC--; + F = (F & CF) | (SZ[res]&~(YF|XF)) | ((A^val^res)&HF) | NF; + if (F & HF) res -= 1; + if (res & 0x02) F |= YF; /* bit 1 -> flag 5 */ + if (res & 0x08) F |= XF; /* bit 3 -> flag 3 */ + if (BC) F |= VF; +} + +/*************************************************************** + * IND + ***************************************************************/ +inline void z80_device::ind() +{ + unsigned t; + UINT8 io = in(BC); + WZ = BC - 1; + B--; + wm(HL, io); + HL--; + F = SZ[B]; + t = ((unsigned)(C - 1) & 0xff) + (unsigned)io; + if (io & SF) F |= NF; + if (t & 0x100) F |= HF | CF; + F |= SZP[(UINT8)(t & 0x07) ^ B] & PF; +} + +/*************************************************************** + * OUTD + ***************************************************************/ +inline void z80_device::outd() +{ + unsigned t; + UINT8 io = rm(HL); + B--; + WZ = BC - 1; + out(BC, io); + HL--; + F = SZ[B]; + t = (unsigned)L + (unsigned)io; + if (io & SF) F |= NF; + if (t & 0x100) F |= HF | CF; + F |= SZP[(UINT8)(t & 0x07) ^ B] & PF; +} + +/*************************************************************** + * LDIR + ***************************************************************/ +inline void z80_device::ldir() +{ + ldi(); + if (BC != 0) + { + PC -= 2; + WZ = PC + 1; + CC(ex, 0xb0); + } +} + +/*************************************************************** + * CPIR + ***************************************************************/ +inline void z80_device::cpir() +{ + cpi(); + if (BC != 0 && !(F & ZF)) + { + PC -= 2; + WZ = PC + 1; + CC(ex, 0xb1); + } +} + +/*************************************************************** + * INIR + ***************************************************************/ +inline void z80_device::inir() +{ + ini(); + if (B != 0) + { + PC -= 2; + CC(ex, 0xb2); + } +} + +/*************************************************************** + * OTIR + ***************************************************************/ +inline void z80_device::otir() +{ + outi(); + if (B != 0) + { + PC -= 2; + CC(ex, 0xb3); + } +} + +/*************************************************************** + * LDDR + ***************************************************************/ +inline void z80_device::lddr() +{ + ldd(); + if (BC != 0) + { + PC -= 2; + WZ = PC + 1; + CC(ex, 0xb8); + } +} + +/*************************************************************** + * CPDR + ***************************************************************/ +inline void z80_device::cpdr() +{ + cpd(); + if (BC != 0 && !(F & ZF)) + { + PC -= 2; + WZ = PC + 1; + CC(ex, 0xb9); + } +} + +/*************************************************************** + * INDR + ***************************************************************/ +inline void z80_device::indr() +{ + ind(); + if (B != 0) + { + PC -= 2; + CC(ex, 0xba); + } +} + +/*************************************************************** + * OTDR + ***************************************************************/ +inline void z80_device::otdr() +{ + outd(); + if (B != 0) + { + PC -= 2; + CC(ex, 0xbb); + } +} + +/*************************************************************** + * EI + ***************************************************************/ +inline void z80_device::ei() +{ + m_iff1 = m_iff2 = 1; + m_after_ei = TRUE; +} + +/********************************************************** + * opcodes with CB prefix + * rotate, shift and bit operations + **********************************************************/ +OP(cb,00) { B = rlc(B); } /* RLC B */ +OP(cb,01) { C = rlc(C); } /* RLC C */ +OP(cb,02) { D = rlc(D); } /* RLC D */ +OP(cb,03) { E = rlc(E); } /* RLC E */ +OP(cb,04) { H = rlc(H); } /* RLC H */ +OP(cb,05) { L = rlc(L); } /* RLC L */ +OP(cb,06) { wm(HL, rlc(rm(HL))); } /* RLC (HL) */ +OP(cb,07) { A = rlc(A); } /* RLC A */ + +OP(cb,08) { B = rrc(B); } /* RRC B */ +OP(cb,09) { C = rrc(C); } /* RRC C */ +OP(cb,0a) { D = rrc(D); } /* RRC D */ +OP(cb,0b) { E = rrc(E); } /* RRC E */ +OP(cb,0c) { H = rrc(H); } /* RRC H */ +OP(cb,0d) { L = rrc(L); } /* RRC L */ +OP(cb,0e) { wm(HL, rrc(rm(HL))); } /* RRC (HL) */ +OP(cb,0f) { A = rrc(A); } /* RRC A */ + +OP(cb,10) { B = rl(B); } /* RL B */ +OP(cb,11) { C = rl(C); } /* RL C */ +OP(cb,12) { D = rl(D); } /* RL D */ +OP(cb,13) { E = rl(E); } /* RL E */ +OP(cb,14) { H = rl(H); } /* RL H */ +OP(cb,15) { L = rl(L); } /* RL L */ +OP(cb,16) { wm(HL, rl(rm(HL))); } /* RL (HL) */ +OP(cb,17) { A = rl(A); } /* RL A */ + +OP(cb,18) { B = rr(B); } /* RR B */ +OP(cb,19) { C = rr(C); } /* RR C */ +OP(cb,1a) { D = rr(D); } /* RR D */ +OP(cb,1b) { E = rr(E); } /* RR E */ +OP(cb,1c) { H = rr(H); } /* RR H */ +OP(cb,1d) { L = rr(L); } /* RR L */ +OP(cb,1e) { wm(HL, rr(rm(HL))); } /* RR (HL) */ +OP(cb,1f) { A = rr(A); } /* RR A */ + +OP(cb,20) { B = sla(B); } /* SLA B */ +OP(cb,21) { C = sla(C); } /* SLA C */ +OP(cb,22) { D = sla(D); } /* SLA D */ +OP(cb,23) { E = sla(E); } /* SLA E */ +OP(cb,24) { H = sla(H); } /* SLA H */ +OP(cb,25) { L = sla(L); } /* SLA L */ +OP(cb,26) { wm(HL, sla(rm(HL))); } /* SLA (HL) */ +OP(cb,27) { A = sla(A); } /* SLA A */ + +OP(cb,28) { B = sra(B); } /* SRA B */ +OP(cb,29) { C = sra(C); } /* SRA C */ +OP(cb,2a) { D = sra(D); } /* SRA D */ +OP(cb,2b) { E = sra(E); } /* SRA E */ +OP(cb,2c) { H = sra(H); } /* SRA H */ +OP(cb,2d) { L = sra(L); } /* SRA L */ +OP(cb,2e) { wm(HL, sra(rm(HL))); } /* SRA (HL) */ +OP(cb,2f) { A = sra(A); } /* SRA A */ + +OP(cb,30) { B = sll(B); } /* SLL B */ +OP(cb,31) { C = sll(C); } /* SLL C */ +OP(cb,32) { D = sll(D); } /* SLL D */ +OP(cb,33) { E = sll(E); } /* SLL E */ +OP(cb,34) { H = sll(H); } /* SLL H */ +OP(cb,35) { L = sll(L); } /* SLL L */ +OP(cb,36) { wm(HL, sll(rm(HL))); } /* SLL (HL) */ +OP(cb,37) { A = sll(A); } /* SLL A */ + +OP(cb,38) { B = srl(B); } /* SRL B */ +OP(cb,39) { C = srl(C); } /* SRL C */ +OP(cb,3a) { D = srl(D); } /* SRL D */ +OP(cb,3b) { E = srl(E); } /* SRL E */ +OP(cb,3c) { H = srl(H); } /* SRL H */ +OP(cb,3d) { L = srl(L); } /* SRL L */ +OP(cb,3e) { wm(HL, srl(rm(HL))); } /* SRL (HL) */ +OP(cb,3f) { A = srl(A); } /* SRL A */ + +OP(cb,40) { bit(0, B); } /* BIT 0,B */ +OP(cb,41) { bit(0, C); } /* BIT 0,C */ +OP(cb,42) { bit(0, D); } /* BIT 0,D */ +OP(cb,43) { bit(0, E); } /* BIT 0,E */ +OP(cb,44) { bit(0, H); } /* BIT 0,H */ +OP(cb,45) { bit(0, L); } /* BIT 0,L */ +OP(cb,46) { bit_hl(0, rm(HL)); } /* BIT 0,(HL) */ +OP(cb,47) { bit(0, A); } /* BIT 0,A */ + +OP(cb,48) { bit(1, B); } /* BIT 1,B */ +OP(cb,49) { bit(1, C); } /* BIT 1,C */ +OP(cb,4a) { bit(1, D); } /* BIT 1,D */ +OP(cb,4b) { bit(1, E); } /* BIT 1,E */ +OP(cb,4c) { bit(1, H); } /* BIT 1,H */ +OP(cb,4d) { bit(1, L); } /* BIT 1,L */ +OP(cb,4e) { bit_hl(1, rm(HL)); } /* BIT 1,(HL) */ +OP(cb,4f) { bit(1, A); } /* BIT 1,A */ + +OP(cb,50) { bit(2, B); } /* BIT 2,B */ +OP(cb,51) { bit(2, C); } /* BIT 2,C */ +OP(cb,52) { bit(2, D); } /* BIT 2,D */ +OP(cb,53) { bit(2, E); } /* BIT 2,E */ +OP(cb,54) { bit(2, H); } /* BIT 2,H */ +OP(cb,55) { bit(2, L); } /* BIT 2,L */ +OP(cb,56) { bit_hl(2, rm(HL)); } /* BIT 2,(HL) */ +OP(cb,57) { bit(2, A); } /* BIT 2,A */ + +OP(cb,58) { bit(3, B); } /* BIT 3,B */ +OP(cb,59) { bit(3, C); } /* BIT 3,C */ +OP(cb,5a) { bit(3, D); } /* BIT 3,D */ +OP(cb,5b) { bit(3, E); } /* BIT 3,E */ +OP(cb,5c) { bit(3, H); } /* BIT 3,H */ +OP(cb,5d) { bit(3, L); } /* BIT 3,L */ +OP(cb,5e) { bit_hl(3, rm(HL)); } /* BIT 3,(HL) */ +OP(cb,5f) { bit(3, A); } /* BIT 3,A */ + +OP(cb,60) { bit(4, B); } /* BIT 4,B */ +OP(cb,61) { bit(4, C); } /* BIT 4,C */ +OP(cb,62) { bit(4, D); } /* BIT 4,D */ +OP(cb,63) { bit(4, E); } /* BIT 4,E */ +OP(cb,64) { bit(4, H); } /* BIT 4,H */ +OP(cb,65) { bit(4, L); } /* BIT 4,L */ +OP(cb,66) { bit_hl(4, rm(HL)); } /* BIT 4,(HL) */ +OP(cb,67) { bit(4, A); } /* BIT 4,A */ + +OP(cb,68) { bit(5, B); } /* BIT 5,B */ +OP(cb,69) { bit(5, C); } /* BIT 5,C */ +OP(cb,6a) { bit(5, D); } /* BIT 5,D */ +OP(cb,6b) { bit(5, E); } /* BIT 5,E */ +OP(cb,6c) { bit(5, H); } /* BIT 5,H */ +OP(cb,6d) { bit(5, L); } /* BIT 5,L */ +OP(cb,6e) { bit_hl(5, rm(HL)); } /* BIT 5,(HL) */ +OP(cb,6f) { bit(5, A); } /* BIT 5,A */ + +OP(cb,70) { bit(6, B); } /* BIT 6,B */ +OP(cb,71) { bit(6, C); } /* BIT 6,C */ +OP(cb,72) { bit(6, D); } /* BIT 6,D */ +OP(cb,73) { bit(6, E); } /* BIT 6,E */ +OP(cb,74) { bit(6, H); } /* BIT 6,H */ +OP(cb,75) { bit(6, L); } /* BIT 6,L */ +OP(cb,76) { bit_hl(6, rm(HL)); } /* BIT 6,(HL) */ +OP(cb,77) { bit(6, A); } /* BIT 6,A */ + +OP(cb,78) { bit(7, B); } /* BIT 7,B */ +OP(cb,79) { bit(7, C); } /* BIT 7,C */ +OP(cb,7a) { bit(7, D); } /* BIT 7,D */ +OP(cb,7b) { bit(7, E); } /* BIT 7,E */ +OP(cb,7c) { bit(7, H); } /* BIT 7,H */ +OP(cb,7d) { bit(7, L); } /* BIT 7,L */ +OP(cb,7e) { bit_hl(7, rm(HL)); } /* BIT 7,(HL) */ +OP(cb,7f) { bit(7, A); } /* BIT 7,A */ + +OP(cb,80) { B = res(0, B); } /* RES 0,B */ +OP(cb,81) { C = res(0, C); } /* RES 0,C */ +OP(cb,82) { D = res(0, D); } /* RES 0,D */ +OP(cb,83) { E = res(0, E); } /* RES 0,E */ +OP(cb,84) { H = res(0, H); } /* RES 0,H */ +OP(cb,85) { L = res(0, L); } /* RES 0,L */ +OP(cb,86) { wm(HL, res(0, rm(HL))); } /* RES 0,(HL) */ +OP(cb,87) { A = res(0, A); } /* RES 0,A */ + +OP(cb,88) { B = res(1, B); } /* RES 1,B */ +OP(cb,89) { C = res(1, C); } /* RES 1,C */ +OP(cb,8a) { D = res(1, D); } /* RES 1,D */ +OP(cb,8b) { E = res(1, E); } /* RES 1,E */ +OP(cb,8c) { H = res(1, H); } /* RES 1,H */ +OP(cb,8d) { L = res(1, L); } /* RES 1,L */ +OP(cb,8e) { wm(HL, res(1, rm(HL))); } /* RES 1,(HL) */ +OP(cb,8f) { A = res(1, A); } /* RES 1,A */ + +OP(cb,90) { B = res(2, B); } /* RES 2,B */ +OP(cb,91) { C = res(2, C); } /* RES 2,C */ +OP(cb,92) { D = res(2, D); } /* RES 2,D */ +OP(cb,93) { E = res(2, E); } /* RES 2,E */ +OP(cb,94) { H = res(2, H); } /* RES 2,H */ +OP(cb,95) { L = res(2, L); } /* RES 2,L */ +OP(cb,96) { wm(HL, res(2, rm(HL))); } /* RES 2,(HL) */ +OP(cb,97) { A = res(2, A); } /* RES 2,A */ + +OP(cb,98) { B = res(3, B); } /* RES 3,B */ +OP(cb,99) { C = res(3, C); } /* RES 3,C */ +OP(cb,9a) { D = res(3, D); } /* RES 3,D */ +OP(cb,9b) { E = res(3, E); } /* RES 3,E */ +OP(cb,9c) { H = res(3, H); } /* RES 3,H */ +OP(cb,9d) { L = res(3, L); } /* RES 3,L */ +OP(cb,9e) { wm(HL, res(3, rm(HL))); } /* RES 3,(HL) */ +OP(cb,9f) { A = res(3, A); } /* RES 3,A */ + +OP(cb,a0) { B = res(4, B); } /* RES 4,B */ +OP(cb,a1) { C = res(4, C); } /* RES 4,C */ +OP(cb,a2) { D = res(4, D); } /* RES 4,D */ +OP(cb,a3) { E = res(4, E); } /* RES 4,E */ +OP(cb,a4) { H = res(4, H); } /* RES 4,H */ +OP(cb,a5) { L = res(4, L); } /* RES 4,L */ +OP(cb,a6) { wm(HL, res(4, rm(HL))); } /* RES 4,(HL) */ +OP(cb,a7) { A = res(4, A); } /* RES 4,A */ + +OP(cb,a8) { B = res(5, B); } /* RES 5,B */ +OP(cb,a9) { C = res(5, C); } /* RES 5,C */ +OP(cb,aa) { D = res(5, D); } /* RES 5,D */ +OP(cb,ab) { E = res(5, E); } /* RES 5,E */ +OP(cb,ac) { H = res(5, H); } /* RES 5,H */ +OP(cb,ad) { L = res(5, L); } /* RES 5,L */ +OP(cb,ae) { wm(HL, res(5, rm(HL))); } /* RES 5,(HL) */ +OP(cb,af) { A = res(5, A); } /* RES 5,A */ + +OP(cb,b0) { B = res(6, B); } /* RES 6,B */ +OP(cb,b1) { C = res(6, C); } /* RES 6,C */ +OP(cb,b2) { D = res(6, D); } /* RES 6,D */ +OP(cb,b3) { E = res(6, E); } /* RES 6,E */ +OP(cb,b4) { H = res(6, H); } /* RES 6,H */ +OP(cb,b5) { L = res(6, L); } /* RES 6,L */ +OP(cb,b6) { wm(HL, res(6, rm(HL))); } /* RES 6,(HL) */ +OP(cb,b7) { A = res(6, A); } /* RES 6,A */ + +OP(cb,b8) { B = res(7, B); } /* RES 7,B */ +OP(cb,b9) { C = res(7, C); } /* RES 7,C */ +OP(cb,ba) { D = res(7, D); } /* RES 7,D */ +OP(cb,bb) { E = res(7, E); } /* RES 7,E */ +OP(cb,bc) { H = res(7, H); } /* RES 7,H */ +OP(cb,bd) { L = res(7, L); } /* RES 7,L */ +OP(cb,be) { wm(HL, res(7, rm(HL))); } /* RES 7,(HL) */ +OP(cb,bf) { A = res(7, A); } /* RES 7,A */ + +OP(cb,c0) { B = set(0, B); } /* SET 0,B */ +OP(cb,c1) { C = set(0, C); } /* SET 0,C */ +OP(cb,c2) { D = set(0, D); } /* SET 0,D */ +OP(cb,c3) { E = set(0, E); } /* SET 0,E */ +OP(cb,c4) { H = set(0, H); } /* SET 0,H */ +OP(cb,c5) { L = set(0, L); } /* SET 0,L */ +OP(cb,c6) { wm(HL, set(0, rm(HL))); } /* SET 0,(HL) */ +OP(cb,c7) { A = set(0, A); } /* SET 0,A */ + +OP(cb,c8) { B = set(1, B); } /* SET 1,B */ +OP(cb,c9) { C = set(1, C); } /* SET 1,C */ +OP(cb,ca) { D = set(1, D); } /* SET 1,D */ +OP(cb,cb) { E = set(1, E); } /* SET 1,E */ +OP(cb,cc) { H = set(1, H); } /* SET 1,H */ +OP(cb,cd) { L = set(1, L); } /* SET 1,L */ +OP(cb,ce) { wm(HL, set(1, rm(HL))); } /* SET 1,(HL) */ +OP(cb,cf) { A = set(1, A); } /* SET 1,A */ + +OP(cb,d0) { B = set(2, B); } /* SET 2,B */ +OP(cb,d1) { C = set(2, C); } /* SET 2,C */ +OP(cb,d2) { D = set(2, D); } /* SET 2,D */ +OP(cb,d3) { E = set(2, E); } /* SET 2,E */ +OP(cb,d4) { H = set(2, H); } /* SET 2,H */ +OP(cb,d5) { L = set(2, L); } /* SET 2,L */ +OP(cb,d6) { wm(HL, set(2, rm(HL))); } /* SET 2,(HL) */ +OP(cb,d7) { A = set(2, A); } /* SET 2,A */ + +OP(cb,d8) { B = set(3, B); } /* SET 3,B */ +OP(cb,d9) { C = set(3, C); } /* SET 3,C */ +OP(cb,da) { D = set(3, D); } /* SET 3,D */ +OP(cb,db) { E = set(3, E); } /* SET 3,E */ +OP(cb,dc) { H = set(3, H); } /* SET 3,H */ +OP(cb,dd) { L = set(3, L); } /* SET 3,L */ +OP(cb,de) { wm(HL, set(3, rm(HL))); } /* SET 3,(HL) */ +OP(cb,df) { A = set(3, A); } /* SET 3,A */ + +OP(cb,e0) { B = set(4, B); } /* SET 4,B */ +OP(cb,e1) { C = set(4, C); } /* SET 4,C */ +OP(cb,e2) { D = set(4, D); } /* SET 4,D */ +OP(cb,e3) { E = set(4, E); } /* SET 4,E */ +OP(cb,e4) { H = set(4, H); } /* SET 4,H */ +OP(cb,e5) { L = set(4, L); } /* SET 4,L */ +OP(cb,e6) { wm(HL, set(4, rm(HL))); } /* SET 4,(HL) */ +OP(cb,e7) { A = set(4, A); } /* SET 4,A */ + +OP(cb,e8) { B = set(5, B); } /* SET 5,B */ +OP(cb,e9) { C = set(5, C); } /* SET 5,C */ +OP(cb,ea) { D = set(5, D); } /* SET 5,D */ +OP(cb,eb) { E = set(5, E); } /* SET 5,E */ +OP(cb,ec) { H = set(5, H); } /* SET 5,H */ +OP(cb,ed) { L = set(5, L); } /* SET 5,L */ +OP(cb,ee) { wm(HL, set(5, rm(HL))); } /* SET 5,(HL) */ +OP(cb,ef) { A = set(5, A); } /* SET 5,A */ + +OP(cb,f0) { B = set(6, B); } /* SET 6,B */ +OP(cb,f1) { C = set(6, C); } /* SET 6,C */ +OP(cb,f2) { D = set(6, D); } /* SET 6,D */ +OP(cb,f3) { E = set(6, E); } /* SET 6,E */ +OP(cb,f4) { H = set(6, H); } /* SET 6,H */ +OP(cb,f5) { L = set(6, L); } /* SET 6,L */ +OP(cb,f6) { wm(HL, set(6, rm(HL))); } /* SET 6,(HL) */ +OP(cb,f7) { A = set(6, A); } /* SET 6,A */ + +OP(cb,f8) { B = set(7, B); } /* SET 7,B */ +OP(cb,f9) { C = set(7, C); } /* SET 7,C */ +OP(cb,fa) { D = set(7, D); } /* SET 7,D */ +OP(cb,fb) { E = set(7, E); } /* SET 7,E */ +OP(cb,fc) { H = set(7, H); } /* SET 7,H */ +OP(cb,fd) { L = set(7, L); } /* SET 7,L */ +OP(cb,fe) { wm(HL, set(7, rm(HL))); } /* SET 7,(HL) */ +OP(cb,ff) { A = set(7, A); } /* SET 7,A */ + + +/********************************************************** +* opcodes with DD/FD CB prefix +* rotate, shift and bit operations with (IX+o) +**********************************************************/ +OP(xycb,00) { B = rlc(rm(m_ea)); wm(m_ea, B); } /* RLC B=(XY+o) */ +OP(xycb,01) { C = rlc(rm(m_ea)); wm(m_ea, C); } /* RLC C=(XY+o) */ +OP(xycb,02) { D = rlc(rm(m_ea)); wm(m_ea, D); } /* RLC D=(XY+o) */ +OP(xycb,03) { E = rlc(rm(m_ea)); wm(m_ea, E); } /* RLC E=(XY+o) */ +OP(xycb,04) { H = rlc(rm(m_ea)); wm(m_ea, H); } /* RLC H=(XY+o) */ +OP(xycb,05) { L = rlc(rm(m_ea)); wm(m_ea, L); } /* RLC L=(XY+o) */ +OP(xycb,06) { wm(m_ea, rlc(rm(m_ea))); } /* RLC (XY+o) */ +OP(xycb,07) { A = rlc(rm(m_ea)); wm(m_ea, A); } /* RLC A=(XY+o) */ + +OP(xycb,08) { B = rrc(rm(m_ea)); wm(m_ea, B); } /* RRC B=(XY+o) */ +OP(xycb,09) { C = rrc(rm(m_ea)); wm(m_ea, C); } /* RRC C=(XY+o) */ +OP(xycb,0a) { D = rrc(rm(m_ea)); wm(m_ea, D); } /* RRC D=(XY+o) */ +OP(xycb,0b) { E = rrc(rm(m_ea)); wm(m_ea, E); } /* RRC E=(XY+o) */ +OP(xycb,0c) { H = rrc(rm(m_ea)); wm(m_ea, H); } /* RRC H=(XY+o) */ +OP(xycb,0d) { L = rrc(rm(m_ea)); wm(m_ea, L); } /* RRC L=(XY+o) */ +OP(xycb,0e) { wm(m_ea,rrc(rm(m_ea))); } /* RRC (XY+o) */ +OP(xycb,0f) { A = rrc(rm(m_ea)); wm(m_ea, A); } /* RRC A=(XY+o) */ + +OP(xycb,10) { B = rl(rm(m_ea)); wm(m_ea, B); } /* RL B=(XY+o) */ +OP(xycb,11) { C = rl(rm(m_ea)); wm(m_ea, C); } /* RL C=(XY+o) */ +OP(xycb,12) { D = rl(rm(m_ea)); wm(m_ea, D); } /* RL D=(XY+o) */ +OP(xycb,13) { E = rl(rm(m_ea)); wm(m_ea, E); } /* RL E=(XY+o) */ +OP(xycb,14) { H = rl(rm(m_ea)); wm(m_ea, H); } /* RL H=(XY+o) */ +OP(xycb,15) { L = rl(rm(m_ea)); wm(m_ea, L); } /* RL L=(XY+o) */ +OP(xycb,16) { wm(m_ea,rl(rm(m_ea))); } /* RL (XY+o) */ +OP(xycb,17) { A = rl(rm(m_ea)); wm(m_ea, A); } /* RL A=(XY+o) */ + +OP(xycb,18) { B = rr(rm(m_ea)); wm(m_ea, B); } /* RR B=(XY+o) */ +OP(xycb,19) { C = rr(rm(m_ea)); wm(m_ea, C); } /* RR C=(XY+o) */ +OP(xycb,1a) { D = rr(rm(m_ea)); wm(m_ea, D); } /* RR D=(XY+o) */ +OP(xycb,1b) { E = rr(rm(m_ea)); wm(m_ea, E); } /* RR E=(XY+o) */ +OP(xycb,1c) { H = rr(rm(m_ea)); wm(m_ea, H); } /* RR H=(XY+o) */ +OP(xycb,1d) { L = rr(rm(m_ea)); wm(m_ea, L); } /* RR L=(XY+o) */ +OP(xycb,1e) { wm(m_ea, rr(rm(m_ea))); } /* RR (XY+o) */ +OP(xycb,1f) { A = rr(rm(m_ea)); wm(m_ea, A); } /* RR A=(XY+o) */ + +OP(xycb,20) { B = sla(rm(m_ea)); wm(m_ea, B); } /* SLA B=(XY+o) */ +OP(xycb,21) { C = sla(rm(m_ea)); wm(m_ea, C); } /* SLA C=(XY+o) */ +OP(xycb,22) { D = sla(rm(m_ea)); wm(m_ea, D); } /* SLA D=(XY+o) */ +OP(xycb,23) { E = sla(rm(m_ea)); wm(m_ea, E); } /* SLA E=(XY+o) */ +OP(xycb,24) { H = sla(rm(m_ea)); wm(m_ea, H); } /* SLA H=(XY+o) */ +OP(xycb,25) { L = sla(rm(m_ea)); wm(m_ea, L); } /* SLA L=(XY+o) */ +OP(xycb,26) { wm(m_ea, sla(rm(m_ea))); } /* SLA (XY+o) */ +OP(xycb,27) { A = sla(rm(m_ea)); wm(m_ea, A); } /* SLA A=(XY+o) */ + +OP(xycb,28) { B = sra(rm(m_ea)); wm(m_ea, B); } /* SRA B=(XY+o) */ +OP(xycb,29) { C = sra(rm(m_ea)); wm(m_ea, C); } /* SRA C=(XY+o) */ +OP(xycb,2a) { D = sra(rm(m_ea)); wm(m_ea, D); } /* SRA D=(XY+o) */ +OP(xycb,2b) { E = sra(rm(m_ea)); wm(m_ea, E); } /* SRA E=(XY+o) */ +OP(xycb,2c) { H = sra(rm(m_ea)); wm(m_ea, H); } /* SRA H=(XY+o) */ +OP(xycb,2d) { L = sra(rm(m_ea)); wm(m_ea, L); } /* SRA L=(XY+o) */ +OP(xycb,2e) { wm(m_ea, sra(rm(m_ea))); } /* SRA (XY+o) */ +OP(xycb,2f) { A = sra(rm(m_ea)); wm(m_ea, A); } /* SRA A=(XY+o) */ + +OP(xycb,30) { B = sll(rm(m_ea)); wm(m_ea, B); } /* SLL B=(XY+o) */ +OP(xycb,31) { C = sll(rm(m_ea)); wm(m_ea, C); } /* SLL C=(XY+o) */ +OP(xycb,32) { D = sll(rm(m_ea)); wm(m_ea, D); } /* SLL D=(XY+o) */ +OP(xycb,33) { E = sll(rm(m_ea)); wm(m_ea, E); } /* SLL E=(XY+o) */ +OP(xycb,34) { H = sll(rm(m_ea)); wm(m_ea, H); } /* SLL H=(XY+o) */ +OP(xycb,35) { L = sll(rm(m_ea)); wm(m_ea, L); } /* SLL L=(XY+o) */ +OP(xycb,36) { wm(m_ea, sll(rm(m_ea))); } /* SLL (XY+o) */ +OP(xycb,37) { A = sll(rm(m_ea)); wm(m_ea, A); } /* SLL A=(XY+o) */ + +OP(xycb,38) { B = srl(rm(m_ea)); wm(m_ea, B); } /* SRL B=(XY+o) */ +OP(xycb,39) { C = srl(rm(m_ea)); wm(m_ea, C); } /* SRL C=(XY+o) */ +OP(xycb,3a) { D = srl(rm(m_ea)); wm(m_ea, D); } /* SRL D=(XY+o) */ +OP(xycb,3b) { E = srl(rm(m_ea)); wm(m_ea, E); } /* SRL E=(XY+o) */ +OP(xycb,3c) { H = srl(rm(m_ea)); wm(m_ea, H); } /* SRL H=(XY+o) */ +OP(xycb,3d) { L = srl(rm(m_ea)); wm(m_ea, L); } /* SRL L=(XY+o) */ +OP(xycb,3e) { wm(m_ea, srl(rm(m_ea))); } /* SRL (XY+o) */ +OP(xycb,3f) { A = srl(rm(m_ea)); wm(m_ea, A); } /* SRL A=(XY+o) */ + +OP(xycb,40) { xycb_46(); } /* BIT 0,(XY+o) */ +OP(xycb,41) { xycb_46(); } /* BIT 0,(XY+o) */ +OP(xycb,42) { xycb_46(); } /* BIT 0,(XY+o) */ +OP(xycb,43) { xycb_46(); } /* BIT 0,(XY+o) */ +OP(xycb,44) { xycb_46(); } /* BIT 0,(XY+o) */ +OP(xycb,45) { xycb_46(); } /* BIT 0,(XY+o) */ +OP(xycb,46) { bit_xy(0, rm(m_ea)); } /* BIT 0,(XY+o) */ +OP(xycb,47) { xycb_46(); } /* BIT 0,(XY+o) */ + +OP(xycb,48) { xycb_4e(); } /* BIT 1,(XY+o) */ +OP(xycb,49) { xycb_4e(); } /* BIT 1,(XY+o) */ +OP(xycb,4a) { xycb_4e(); } /* BIT 1,(XY+o) */ +OP(xycb,4b) { xycb_4e(); } /* BIT 1,(XY+o) */ +OP(xycb,4c) { xycb_4e(); } /* BIT 1,(XY+o) */ +OP(xycb,4d) { xycb_4e(); } /* BIT 1,(XY+o) */ +OP(xycb,4e) { bit_xy(1, rm(m_ea)); } /* BIT 1,(XY+o) */ +OP(xycb,4f) { xycb_4e(); } /* BIT 1,(XY+o) */ + +OP(xycb,50) { xycb_56(); } /* BIT 2,(XY+o) */ +OP(xycb,51) { xycb_56(); } /* BIT 2,(XY+o) */ +OP(xycb,52) { xycb_56(); } /* BIT 2,(XY+o) */ +OP(xycb,53) { xycb_56(); } /* BIT 2,(XY+o) */ +OP(xycb,54) { xycb_56(); } /* BIT 2,(XY+o) */ +OP(xycb,55) { xycb_56(); } /* BIT 2,(XY+o) */ +OP(xycb,56) { bit_xy(2, rm(m_ea)); } /* BIT 2,(XY+o) */ +OP(xycb,57) { xycb_56(); } /* BIT 2,(XY+o) */ + +OP(xycb,58) { xycb_5e(); } /* BIT 3,(XY+o) */ +OP(xycb,59) { xycb_5e(); } /* BIT 3,(XY+o) */ +OP(xycb,5a) { xycb_5e(); } /* BIT 3,(XY+o) */ +OP(xycb,5b) { xycb_5e(); } /* BIT 3,(XY+o) */ +OP(xycb,5c) { xycb_5e(); } /* BIT 3,(XY+o) */ +OP(xycb,5d) { xycb_5e(); } /* BIT 3,(XY+o) */ +OP(xycb,5e) { bit_xy(3, rm(m_ea)); } /* BIT 3,(XY+o) */ +OP(xycb,5f) { xycb_5e(); } /* BIT 3,(XY+o) */ + +OP(xycb,60) { xycb_66(); } /* BIT 4,(XY+o) */ +OP(xycb,61) { xycb_66(); } /* BIT 4,(XY+o) */ +OP(xycb,62) { xycb_66(); } /* BIT 4,(XY+o) */ +OP(xycb,63) { xycb_66(); } /* BIT 4,(XY+o) */ +OP(xycb,64) { xycb_66(); } /* BIT 4,(XY+o) */ +OP(xycb,65) { xycb_66(); } /* BIT 4,(XY+o) */ +OP(xycb,66) { bit_xy(4, rm(m_ea)); } /* BIT 4,(XY+o) */ +OP(xycb,67) { xycb_66(); } /* BIT 4,(XY+o) */ + +OP(xycb,68) { xycb_6e(); } /* BIT 5,(XY+o) */ +OP(xycb,69) { xycb_6e(); } /* BIT 5,(XY+o) */ +OP(xycb,6a) { xycb_6e(); } /* BIT 5,(XY+o) */ +OP(xycb,6b) { xycb_6e(); } /* BIT 5,(XY+o) */ +OP(xycb,6c) { xycb_6e(); } /* BIT 5,(XY+o) */ +OP(xycb,6d) { xycb_6e(); } /* BIT 5,(XY+o) */ +OP(xycb,6e) { bit_xy(5, rm(m_ea)); } /* BIT 5,(XY+o) */ +OP(xycb,6f) { xycb_6e(); } /* BIT 5,(XY+o) */ + +OP(xycb,70) { xycb_76(); } /* BIT 6,(XY+o) */ +OP(xycb,71) { xycb_76(); } /* BIT 6,(XY+o) */ +OP(xycb,72) { xycb_76(); } /* BIT 6,(XY+o) */ +OP(xycb,73) { xycb_76(); } /* BIT 6,(XY+o) */ +OP(xycb,74) { xycb_76(); } /* BIT 6,(XY+o) */ +OP(xycb,75) { xycb_76(); } /* BIT 6,(XY+o) */ +OP(xycb,76) { bit_xy(6, rm(m_ea)); } /* BIT 6,(XY+o) */ +OP(xycb,77) { xycb_76(); } /* BIT 6,(XY+o) */ + +OP(xycb,78) { xycb_7e(); } /* BIT 7,(XY+o) */ +OP(xycb,79) { xycb_7e(); } /* BIT 7,(XY+o) */ +OP(xycb,7a) { xycb_7e(); } /* BIT 7,(XY+o) */ +OP(xycb,7b) { xycb_7e(); } /* BIT 7,(XY+o) */ +OP(xycb,7c) { xycb_7e(); } /* BIT 7,(XY+o) */ +OP(xycb,7d) { xycb_7e(); } /* BIT 7,(XY+o) */ +OP(xycb,7e) { bit_xy(7, rm(m_ea)); } /* BIT 7,(XY+o) */ +OP(xycb,7f) { xycb_7e(); } /* BIT 7,(XY+o) */ + +OP(xycb,80) { B = res(0, rm(m_ea)); wm(m_ea, B); } /* RES 0,B=(XY+o) */ +OP(xycb,81) { C = res(0, rm(m_ea)); wm(m_ea, C); } /* RES 0,C=(XY+o) */ +OP(xycb,82) { D = res(0, rm(m_ea)); wm(m_ea, D); } /* RES 0,D=(XY+o) */ +OP(xycb,83) { E = res(0, rm(m_ea)); wm(m_ea, E); } /* RES 0,E=(XY+o) */ +OP(xycb,84) { H = res(0, rm(m_ea)); wm(m_ea, H); } /* RES 0,H=(XY+o) */ +OP(xycb,85) { L = res(0, rm(m_ea)); wm(m_ea, L); } /* RES 0,L=(XY+o) */ +OP(xycb,86) { wm(m_ea, res(0, rm(m_ea))); } /* RES 0,(XY+o) */ +OP(xycb,87) { A = res(0, rm(m_ea)); wm(m_ea, A); } /* RES 0,A=(XY+o) */ + +OP(xycb,88) { B = res(1, rm(m_ea)); wm(m_ea, B); } /* RES 1,B=(XY+o) */ +OP(xycb,89) { C = res(1, rm(m_ea)); wm(m_ea, C); } /* RES 1,C=(XY+o) */ +OP(xycb,8a) { D = res(1, rm(m_ea)); wm(m_ea, D); } /* RES 1,D=(XY+o) */ +OP(xycb,8b) { E = res(1, rm(m_ea)); wm(m_ea, E); } /* RES 1,E=(XY+o) */ +OP(xycb,8c) { H = res(1, rm(m_ea)); wm(m_ea, H); } /* RES 1,H=(XY+o) */ +OP(xycb,8d) { L = res(1, rm(m_ea)); wm(m_ea, L); } /* RES 1,L=(XY+o) */ +OP(xycb,8e) { wm(m_ea, res(1, rm(m_ea))); } /* RES 1,(XY+o) */ +OP(xycb,8f) { A = res(1, rm(m_ea)); wm(m_ea, A); } /* RES 1,A=(XY+o) */ + +OP(xycb,90) { B = res(2, rm(m_ea)); wm(m_ea, B); } /* RES 2,B=(XY+o) */ +OP(xycb,91) { C = res(2, rm(m_ea)); wm(m_ea, C); } /* RES 2,C=(XY+o) */ +OP(xycb,92) { D = res(2, rm(m_ea)); wm(m_ea, D); } /* RES 2,D=(XY+o) */ +OP(xycb,93) { E = res(2, rm(m_ea)); wm(m_ea, E); } /* RES 2,E=(XY+o) */ +OP(xycb,94) { H = res(2, rm(m_ea)); wm(m_ea, H); } /* RES 2,H=(XY+o) */ +OP(xycb,95) { L = res(2, rm(m_ea)); wm(m_ea, L); } /* RES 2,L=(XY+o) */ +OP(xycb,96) { wm(m_ea, res(2, rm(m_ea))); } /* RES 2,(XY+o) */ +OP(xycb,97) { A = res(2, rm(m_ea)); wm(m_ea, A); } /* RES 2,A=(XY+o) */ + +OP(xycb,98) { B = res(3, rm(m_ea)); wm(m_ea, B); } /* RES 3,B=(XY+o) */ +OP(xycb,99) { C = res(3, rm(m_ea)); wm(m_ea, C); } /* RES 3,C=(XY+o) */ +OP(xycb,9a) { D = res(3, rm(m_ea)); wm(m_ea, D); } /* RES 3,D=(XY+o) */ +OP(xycb,9b) { E = res(3, rm(m_ea)); wm(m_ea, E); } /* RES 3,E=(XY+o) */ +OP(xycb,9c) { H = res(3, rm(m_ea)); wm(m_ea, H); } /* RES 3,H=(XY+o) */ +OP(xycb,9d) { L = res(3, rm(m_ea)); wm(m_ea, L); } /* RES 3,L=(XY+o) */ +OP(xycb,9e) { wm(m_ea, res(3, rm(m_ea))); } /* RES 3,(XY+o) */ +OP(xycb,9f) { A = res(3, rm(m_ea)); wm(m_ea, A); } /* RES 3,A=(XY+o) */ + +OP(xycb,a0) { B = res(4, rm(m_ea)); wm(m_ea, B); } /* RES 4,B=(XY+o) */ +OP(xycb,a1) { C = res(4, rm(m_ea)); wm(m_ea, C); } /* RES 4,C=(XY+o) */ +OP(xycb,a2) { D = res(4, rm(m_ea)); wm(m_ea, D); } /* RES 4,D=(XY+o) */ +OP(xycb,a3) { E = res(4, rm(m_ea)); wm(m_ea, E); } /* RES 4,E=(XY+o) */ +OP(xycb,a4) { H = res(4, rm(m_ea)); wm(m_ea, H); } /* RES 4,H=(XY+o) */ +OP(xycb,a5) { L = res(4, rm(m_ea)); wm(m_ea, L); } /* RES 4,L=(XY+o) */ +OP(xycb,a6) { wm(m_ea, res(4, rm(m_ea))); } /* RES 4,(XY+o) */ +OP(xycb,a7) { A = res(4, rm(m_ea)); wm(m_ea, A); } /* RES 4,A=(XY+o) */ + +OP(xycb,a8) { B = res(5, rm(m_ea)); wm(m_ea, B); } /* RES 5,B=(XY+o) */ +OP(xycb,a9) { C = res(5, rm(m_ea)); wm(m_ea, C); } /* RES 5,C=(XY+o) */ +OP(xycb,aa) { D = res(5, rm(m_ea)); wm(m_ea, D); } /* RES 5,D=(XY+o) */ +OP(xycb,ab) { E = res(5, rm(m_ea)); wm(m_ea, E); } /* RES 5,E=(XY+o) */ +OP(xycb,ac) { H = res(5, rm(m_ea)); wm(m_ea, H); } /* RES 5,H=(XY+o) */ +OP(xycb,ad) { L = res(5, rm(m_ea)); wm(m_ea, L); } /* RES 5,L=(XY+o) */ +OP(xycb,ae) { wm(m_ea, res(5, rm(m_ea))); } /* RES 5,(XY+o) */ +OP(xycb,af) { A = res(5, rm(m_ea)); wm(m_ea, A); } /* RES 5,A=(XY+o) */ + +OP(xycb,b0) { B = res(6, rm(m_ea)); wm(m_ea, B); } /* RES 6,B=(XY+o) */ +OP(xycb,b1) { C = res(6, rm(m_ea)); wm(m_ea, C); } /* RES 6,C=(XY+o) */ +OP(xycb,b2) { D = res(6, rm(m_ea)); wm(m_ea, D); } /* RES 6,D=(XY+o) */ +OP(xycb,b3) { E = res(6, rm(m_ea)); wm(m_ea, E); } /* RES 6,E=(XY+o) */ +OP(xycb,b4) { H = res(6, rm(m_ea)); wm(m_ea, H); } /* RES 6,H=(XY+o) */ +OP(xycb,b5) { L = res(6, rm(m_ea)); wm(m_ea, L); } /* RES 6,L=(XY+o) */ +OP(xycb,b6) { wm(m_ea, res(6, rm(m_ea))); } /* RES 6,(XY+o) */ +OP(xycb,b7) { A = res(6, rm(m_ea)); wm(m_ea, A); } /* RES 6,A=(XY+o) */ + +OP(xycb,b8) { B = res(7, rm(m_ea)); wm(m_ea, B); } /* RES 7,B=(XY+o) */ +OP(xycb,b9) { C = res(7, rm(m_ea)); wm(m_ea, C); } /* RES 7,C=(XY+o) */ +OP(xycb,ba) { D = res(7, rm(m_ea)); wm(m_ea, D); } /* RES 7,D=(XY+o) */ +OP(xycb,bb) { E = res(7, rm(m_ea)); wm(m_ea, E); } /* RES 7,E=(XY+o) */ +OP(xycb,bc) { H = res(7, rm(m_ea)); wm(m_ea, H); } /* RES 7,H=(XY+o) */ +OP(xycb,bd) { L = res(7, rm(m_ea)); wm(m_ea, L); } /* RES 7,L=(XY+o) */ +OP(xycb,be) { wm(m_ea, res(7, rm(m_ea))); } /* RES 7,(XY+o) */ +OP(xycb,bf) { A = res(7, rm(m_ea)); wm(m_ea, A); } /* RES 7,A=(XY+o) */ + +OP(xycb,c0) { B = set(0, rm(m_ea)); wm(m_ea, B); } /* SET 0,B=(XY+o) */ +OP(xycb,c1) { C = set(0, rm(m_ea)); wm(m_ea, C); } /* SET 0,C=(XY+o) */ +OP(xycb,c2) { D = set(0, rm(m_ea)); wm(m_ea, D); } /* SET 0,D=(XY+o) */ +OP(xycb,c3) { E = set(0, rm(m_ea)); wm(m_ea, E); } /* SET 0,E=(XY+o) */ +OP(xycb,c4) { H = set(0, rm(m_ea)); wm(m_ea, H); } /* SET 0,H=(XY+o) */ +OP(xycb,c5) { L = set(0, rm(m_ea)); wm(m_ea, L); } /* SET 0,L=(XY+o) */ +OP(xycb,c6) { wm(m_ea, set(0, rm(m_ea))); } /* SET 0,(XY+o) */ +OP(xycb,c7) { A = set(0, rm(m_ea)); wm(m_ea, A); } /* SET 0,A=(XY+o) */ + +OP(xycb,c8) { B = set(1, rm(m_ea)); wm(m_ea, B); } /* SET 1,B=(XY+o) */ +OP(xycb,c9) { C = set(1, rm(m_ea)); wm(m_ea, C); } /* SET 1,C=(XY+o) */ +OP(xycb,ca) { D = set(1, rm(m_ea)); wm(m_ea, D); } /* SET 1,D=(XY+o) */ +OP(xycb,cb) { E = set(1, rm(m_ea)); wm(m_ea, E); } /* SET 1,E=(XY+o) */ +OP(xycb,cc) { H = set(1, rm(m_ea)); wm(m_ea, H); } /* SET 1,H=(XY+o) */ +OP(xycb,cd) { L = set(1, rm(m_ea)); wm(m_ea, L); } /* SET 1,L=(XY+o) */ +OP(xycb,ce) { wm(m_ea, set(1, rm(m_ea))); } /* SET 1,(XY+o) */ +OP(xycb,cf) { A = set(1, rm(m_ea)); wm(m_ea, A); } /* SET 1,A=(XY+o) */ + +OP(xycb,d0) { B = set(2, rm(m_ea)); wm(m_ea, B); } /* SET 2,B=(XY+o) */ +OP(xycb,d1) { C = set(2, rm(m_ea)); wm(m_ea, C); } /* SET 2,C=(XY+o) */ +OP(xycb,d2) { D = set(2, rm(m_ea)); wm(m_ea, D); } /* SET 2,D=(XY+o) */ +OP(xycb,d3) { E = set(2, rm(m_ea)); wm(m_ea, E); } /* SET 2,E=(XY+o) */ +OP(xycb,d4) { H = set(2, rm(m_ea)); wm(m_ea, H); } /* SET 2,H=(XY+o) */ +OP(xycb,d5) { L = set(2, rm(m_ea)); wm(m_ea, L); } /* SET 2,L=(XY+o) */ +OP(xycb,d6) { wm(m_ea, set(2, rm(m_ea))); } /* SET 2,(XY+o) */ +OP(xycb,d7) { A = set(2, rm(m_ea)); wm(m_ea, A); } /* SET 2,A=(XY+o) */ + +OP(xycb,d8) { B = set(3, rm(m_ea)); wm(m_ea, B); } /* SET 3,B=(XY+o) */ +OP(xycb,d9) { C = set(3, rm(m_ea)); wm(m_ea, C); } /* SET 3,C=(XY+o) */ +OP(xycb,da) { D = set(3, rm(m_ea)); wm(m_ea, D); } /* SET 3,D=(XY+o) */ +OP(xycb,db) { E = set(3, rm(m_ea)); wm(m_ea, E); } /* SET 3,E=(XY+o) */ +OP(xycb,dc) { H = set(3, rm(m_ea)); wm(m_ea, H); } /* SET 3,H=(XY+o) */ +OP(xycb,dd) { L = set(3, rm(m_ea)); wm(m_ea, L); } /* SET 3,L=(XY+o) */ +OP(xycb,de) { wm(m_ea, set(3, rm(m_ea))); } /* SET 3,(XY+o) */ +OP(xycb,df) { A = set(3, rm(m_ea)); wm(m_ea, A); } /* SET 3,A=(XY+o) */ + +OP(xycb,e0) { B = set(4, rm(m_ea)); wm(m_ea, B); } /* SET 4,B=(XY+o) */ +OP(xycb,e1) { C = set(4, rm(m_ea)); wm(m_ea, C); } /* SET 4,C=(XY+o) */ +OP(xycb,e2) { D = set(4, rm(m_ea)); wm(m_ea, D); } /* SET 4,D=(XY+o) */ +OP(xycb,e3) { E = set(4, rm(m_ea)); wm(m_ea, E); } /* SET 4,E=(XY+o) */ +OP(xycb,e4) { H = set(4, rm(m_ea)); wm(m_ea, H); } /* SET 4,H=(XY+o) */ +OP(xycb,e5) { L = set(4, rm(m_ea)); wm(m_ea, L); } /* SET 4,L=(XY+o) */ +OP(xycb,e6) { wm(m_ea, set(4, rm(m_ea))); } /* SET 4,(XY+o) */ +OP(xycb,e7) { A = set(4, rm(m_ea)); wm(m_ea, A); } /* SET 4,A=(XY+o) */ + +OP(xycb,e8) { B = set(5, rm(m_ea)); wm(m_ea, B); } /* SET 5,B=(XY+o) */ +OP(xycb,e9) { C = set(5, rm(m_ea)); wm(m_ea, C); } /* SET 5,C=(XY+o) */ +OP(xycb,ea) { D = set(5, rm(m_ea)); wm(m_ea, D); } /* SET 5,D=(XY+o) */ +OP(xycb,eb) { E = set(5, rm(m_ea)); wm(m_ea, E); } /* SET 5,E=(XY+o) */ +OP(xycb,ec) { H = set(5, rm(m_ea)); wm(m_ea, H); } /* SET 5,H=(XY+o) */ +OP(xycb,ed) { L = set(5, rm(m_ea)); wm(m_ea, L); } /* SET 5,L=(XY+o) */ +OP(xycb,ee) { wm(m_ea, set(5, rm(m_ea))); } /* SET 5,(XY+o) */ +OP(xycb,ef) { A = set(5, rm(m_ea)); wm(m_ea, A); } /* SET 5,A=(XY+o) */ + +OP(xycb,f0) { B = set(6, rm(m_ea)); wm(m_ea, B); } /* SET 6,B=(XY+o) */ +OP(xycb,f1) { C = set(6, rm(m_ea)); wm(m_ea, C); } /* SET 6,C=(XY+o) */ +OP(xycb,f2) { D = set(6, rm(m_ea)); wm(m_ea, D); } /* SET 6,D=(XY+o) */ +OP(xycb,f3) { E = set(6, rm(m_ea)); wm(m_ea, E); } /* SET 6,E=(XY+o) */ +OP(xycb,f4) { H = set(6, rm(m_ea)); wm(m_ea, H); } /* SET 6,H=(XY+o) */ +OP(xycb,f5) { L = set(6, rm(m_ea)); wm(m_ea, L); } /* SET 6,L=(XY+o) */ +OP(xycb,f6) { wm(m_ea, set(6, rm(m_ea))); } /* SET 6,(XY+o) */ +OP(xycb,f7) { A = set(6, rm(m_ea)); wm(m_ea, A); } /* SET 6,A=(XY+o) */ + +OP(xycb,f8) { B = set(7, rm(m_ea)); wm(m_ea, B); } /* SET 7,B=(XY+o) */ +OP(xycb,f9) { C = set(7, rm(m_ea)); wm(m_ea, C); } /* SET 7,C=(XY+o) */ +OP(xycb,fa) { D = set(7, rm(m_ea)); wm(m_ea, D); } /* SET 7,D=(XY+o) */ +OP(xycb,fb) { E = set(7, rm(m_ea)); wm(m_ea, E); } /* SET 7,E=(XY+o) */ +OP(xycb,fc) { H = set(7, rm(m_ea)); wm(m_ea, H); } /* SET 7,H=(XY+o) */ +OP(xycb,fd) { L = set(7, rm(m_ea)); wm(m_ea, L); } /* SET 7,L=(XY+o) */ +OP(xycb,fe) { wm(m_ea, set(7, rm(m_ea))); } /* SET 7,(XY+o) */ +OP(xycb,ff) { A = set(7, rm(m_ea)); wm(m_ea, A); } /* SET 7,A=(XY+o) */ + +OP(illegal,1) { + logerror("Z80 '%s' ill. opcode $%02x $%02x\n", + tag(), m_decrypted_opcodes_direct->read_byte((PCD-1)&0xffff), m_decrypted_opcodes_direct->read_byte(PCD)); +} + +/********************************************************** + * IX register related opcodes (DD prefix) + **********************************************************/ +OP(dd,00) { illegal_1(); op_00(); } /* DB DD */ +OP(dd,01) { illegal_1(); op_01(); } /* DB DD */ +OP(dd,02) { illegal_1(); op_02(); } /* DB DD */ +OP(dd,03) { illegal_1(); op_03(); } /* DB DD */ +OP(dd,04) { illegal_1(); op_04(); } /* DB DD */ +OP(dd,05) { illegal_1(); op_05(); } /* DB DD */ +OP(dd,06) { illegal_1(); op_06(); } /* DB DD */ +OP(dd,07) { illegal_1(); op_07(); } /* DB DD */ + +OP(dd,08) { illegal_1(); op_08(); } /* DB DD */ +OP(dd,09) { add16(m_ix, m_bc); } /* ADD IX,BC */ +OP(dd,0a) { illegal_1(); op_0a(); } /* DB DD */ +OP(dd,0b) { illegal_1(); op_0b(); } /* DB DD */ +OP(dd,0c) { illegal_1(); op_0c(); } /* DB DD */ +OP(dd,0d) { illegal_1(); op_0d(); } /* DB DD */ +OP(dd,0e) { illegal_1(); op_0e(); } /* DB DD */ +OP(dd,0f) { illegal_1(); op_0f(); } /* DB DD */ + +OP(dd,10) { illegal_1(); op_10(); } /* DB DD */ +OP(dd,11) { illegal_1(); op_11(); } /* DB DD */ +OP(dd,12) { illegal_1(); op_12(); } /* DB DD */ +OP(dd,13) { illegal_1(); op_13(); } /* DB DD */ +OP(dd,14) { illegal_1(); op_14(); } /* DB DD */ +OP(dd,15) { illegal_1(); op_15(); } /* DB DD */ +OP(dd,16) { illegal_1(); op_16(); } /* DB DD */ +OP(dd,17) { illegal_1(); op_17(); } /* DB DD */ + +OP(dd,18) { illegal_1(); op_18(); } /* DB DD */ +OP(dd,19) { add16(m_ix, m_de); } /* ADD IX,DE */ +OP(dd,1a) { illegal_1(); op_1a(); } /* DB DD */ +OP(dd,1b) { illegal_1(); op_1b(); } /* DB DD */ +OP(dd,1c) { illegal_1(); op_1c(); } /* DB DD */ +OP(dd,1d) { illegal_1(); op_1d(); } /* DB DD */ +OP(dd,1e) { illegal_1(); op_1e(); } /* DB DD */ +OP(dd,1f) { illegal_1(); op_1f(); } /* DB DD */ + +OP(dd,20) { illegal_1(); op_20(); } /* DB DD */ +OP(dd,21) { IX = arg16(); } /* LD IX,w */ +OP(dd,22) { m_ea = arg16(); wm16(m_ea, m_ix); WZ = m_ea + 1; } /* LD (w),IX */ +OP(dd,23) { IX++; } /* INC IX */ +OP(dd,24) { HX = inc(HX); } /* INC HX */ +OP(dd,25) { HX = dec(HX); } /* DEC HX */ +OP(dd,26) { HX = arg(); } /* LD HX,n */ +OP(dd,27) { illegal_1(); op_27(); } /* DB DD */ + +OP(dd,28) { illegal_1(); op_28(); } /* DB DD */ +OP(dd,29) { add16(m_ix, m_ix); } /* ADD IX,IX */ +OP(dd,2a) { m_ea = arg16(); rm16(m_ea, m_ix); WZ = m_ea + 1; } /* LD IX,(w) */ +OP(dd,2b) { IX--; } /* DEC IX */ +OP(dd,2c) { LX = inc(LX); } /* INC LX */ +OP(dd,2d) { LX = dec(LX); } /* DEC LX */ +OP(dd,2e) { LX = arg(); } /* LD LX,n */ +OP(dd,2f) { illegal_1(); op_2f(); } /* DB DD */ + +OP(dd,30) { illegal_1(); op_30(); } /* DB DD */ +OP(dd,31) { illegal_1(); op_31(); } /* DB DD */ +OP(dd,32) { illegal_1(); op_32(); } /* DB DD */ +OP(dd,33) { illegal_1(); op_33(); } /* DB DD */ +OP(dd,34) { eax(); wm(m_ea, inc(rm(m_ea))); } /* INC (IX+o) */ +OP(dd,35) { eax(); wm(m_ea, dec(rm(m_ea))); } /* DEC (IX+o) */ +OP(dd,36) { eax(); wm(m_ea, arg()); } /* LD (IX+o),n */ +OP(dd,37) { illegal_1(); op_37(); } /* DB DD */ + +OP(dd,38) { illegal_1(); op_38(); } /* DB DD */ +OP(dd,39) { add16(m_ix, m_sp); } /* ADD IX,SP */ +OP(dd,3a) { illegal_1(); op_3a(); } /* DB DD */ +OP(dd,3b) { illegal_1(); op_3b(); } /* DB DD */ +OP(dd,3c) { illegal_1(); op_3c(); } /* DB DD */ +OP(dd,3d) { illegal_1(); op_3d(); } /* DB DD */ +OP(dd,3e) { illegal_1(); op_3e(); } /* DB DD */ +OP(dd,3f) { illegal_1(); op_3f(); } /* DB DD */ + +OP(dd,40) { illegal_1(); op_40(); } /* DB DD */ +OP(dd,41) { illegal_1(); op_41(); } /* DB DD */ +OP(dd,42) { illegal_1(); op_42(); } /* DB DD */ +OP(dd,43) { illegal_1(); op_43(); } /* DB DD */ +OP(dd,44) { B = HX; } /* LD B,HX */ +OP(dd,45) { B = LX; } /* LD B,LX */ +OP(dd,46) { eax(); B = rm(m_ea); } /* LD B,(IX+o) */ +OP(dd,47) { illegal_1(); op_47(); } /* DB DD */ + +OP(dd,48) { illegal_1(); op_48(); } /* DB DD */ +OP(dd,49) { illegal_1(); op_49(); } /* DB DD */ +OP(dd,4a) { illegal_1(); op_4a(); } /* DB DD */ +OP(dd,4b) { illegal_1(); op_4b(); } /* DB DD */ +OP(dd,4c) { C = HX; } /* LD C,HX */ +OP(dd,4d) { C = LX; } /* LD C,LX */ +OP(dd,4e) { eax(); C = rm(m_ea); } /* LD C,(IX+o) */ +OP(dd,4f) { illegal_1(); op_4f(); } /* DB DD */ + +OP(dd,50) { illegal_1(); op_50(); } /* DB DD */ +OP(dd,51) { illegal_1(); op_51(); } /* DB DD */ +OP(dd,52) { illegal_1(); op_52(); } /* DB DD */ +OP(dd,53) { illegal_1(); op_53(); } /* DB DD */ +OP(dd,54) { D = HX; } /* LD D,HX */ +OP(dd,55) { D = LX; } /* LD D,LX */ +OP(dd,56) { eax(); D = rm(m_ea); } /* LD D,(IX+o) */ +OP(dd,57) { illegal_1(); op_57(); } /* DB DD */ + +OP(dd,58) { illegal_1(); op_58(); } /* DB DD */ +OP(dd,59) { illegal_1(); op_59(); } /* DB DD */ +OP(dd,5a) { illegal_1(); op_5a(); } /* DB DD */ +OP(dd,5b) { illegal_1(); op_5b(); } /* DB DD */ +OP(dd,5c) { E = HX; } /* LD E,HX */ +OP(dd,5d) { E = LX; } /* LD E,LX */ +OP(dd,5e) { eax(); E = rm(m_ea); } /* LD E,(IX+o) */ +OP(dd,5f) { illegal_1(); op_5f(); } /* DB DD */ + +OP(dd,60) { HX = B; } /* LD HX,B */ +OP(dd,61) { HX = C; } /* LD HX,C */ +OP(dd,62) { HX = D; } /* LD HX,D */ +OP(dd,63) { HX = E; } /* LD HX,E */ +OP(dd,64) { } /* LD HX,HX */ +OP(dd,65) { HX = LX; } /* LD HX,LX */ +OP(dd,66) { eax(); H = rm(m_ea); } /* LD H,(IX+o) */ +OP(dd,67) { HX = A; } /* LD HX,A */ + +OP(dd,68) { LX = B; } /* LD LX,B */ +OP(dd,69) { LX = C; } /* LD LX,C */ +OP(dd,6a) { LX = D; } /* LD LX,D */ +OP(dd,6b) { LX = E; } /* LD LX,E */ +OP(dd,6c) { LX = HX; } /* LD LX,HX */ +OP(dd,6d) { } /* LD LX,LX */ +OP(dd,6e) { eax(); L = rm(m_ea); } /* LD L,(IX+o) */ +OP(dd,6f) { LX = A; } /* LD LX,A */ + +OP(dd,70) { eax(); wm(m_ea, B); } /* LD (IX+o),B */ +OP(dd,71) { eax(); wm(m_ea, C); } /* LD (IX+o),C */ +OP(dd,72) { eax(); wm(m_ea, D); } /* LD (IX+o),D */ +OP(dd,73) { eax(); wm(m_ea, E); } /* LD (IX+o),E */ +OP(dd,74) { eax(); wm(m_ea, H); } /* LD (IX+o),H */ +OP(dd,75) { eax(); wm(m_ea, L); } /* LD (IX+o),L */ +OP(dd,76) { illegal_1(); op_76(); } /* DB DD */ +OP(dd,77) { eax(); wm(m_ea, A); } /* LD (IX+o),A */ + +OP(dd,78) { illegal_1(); op_78(); } /* DB DD */ +OP(dd,79) { illegal_1(); op_79(); } /* DB DD */ +OP(dd,7a) { illegal_1(); op_7a(); } /* DB DD */ +OP(dd,7b) { illegal_1(); op_7b(); } /* DB DD */ +OP(dd,7c) { A = HX; } /* LD A,HX */ +OP(dd,7d) { A = LX; } /* LD A,LX */ +OP(dd,7e) { eax(); A = rm(m_ea); } /* LD A,(IX+o) */ +OP(dd,7f) { illegal_1(); op_7f(); } /* DB DD */ + +OP(dd,80) { illegal_1(); op_80(); } /* DB DD */ +OP(dd,81) { illegal_1(); op_81(); } /* DB DD */ +OP(dd,82) { illegal_1(); op_82(); } /* DB DD */ +OP(dd,83) { illegal_1(); op_83(); } /* DB DD */ +OP(dd,84) { add_a(HX); } /* ADD A,HX */ +OP(dd,85) { add_a(LX); } /* ADD A,LX */ +OP(dd,86) { eax(); add_a(rm(m_ea)); } /* ADD A,(IX+o) */ +OP(dd,87) { illegal_1(); op_87(); } /* DB DD */ + +OP(dd,88) { illegal_1(); op_88(); } /* DB DD */ +OP(dd,89) { illegal_1(); op_89(); } /* DB DD */ +OP(dd,8a) { illegal_1(); op_8a(); } /* DB DD */ +OP(dd,8b) { illegal_1(); op_8b(); } /* DB DD */ +OP(dd,8c) { adc_a(HX); } /* ADC A,HX */ +OP(dd,8d) { adc_a(LX); } /* ADC A,LX */ +OP(dd,8e) { eax(); adc_a(rm(m_ea)); } /* ADC A,(IX+o) */ +OP(dd,8f) { illegal_1(); op_8f(); } /* DB DD */ + +OP(dd,90) { illegal_1(); op_90(); } /* DB DD */ +OP(dd,91) { illegal_1(); op_91(); } /* DB DD */ +OP(dd,92) { illegal_1(); op_92(); } /* DB DD */ +OP(dd,93) { illegal_1(); op_93(); } /* DB DD */ +OP(dd,94) { sub(HX); } /* SUB HX */ +OP(dd,95) { sub(LX); } /* SUB LX */ +OP(dd,96) { eax(); sub(rm(m_ea)); } /* SUB (IX+o) */ +OP(dd,97) { illegal_1(); op_97(); } /* DB DD */ + +OP(dd,98) { illegal_1(); op_98(); } /* DB DD */ +OP(dd,99) { illegal_1(); op_99(); } /* DB DD */ +OP(dd,9a) { illegal_1(); op_9a(); } /* DB DD */ +OP(dd,9b) { illegal_1(); op_9b(); } /* DB DD */ +OP(dd,9c) { sbc_a(HX); } /* SBC A,HX */ +OP(dd,9d) { sbc_a(LX); } /* SBC A,LX */ +OP(dd,9e) { eax(); sbc_a(rm(m_ea)); } /* SBC A,(IX+o) */ +OP(dd,9f) { illegal_1(); op_9f(); } /* DB DD */ + +OP(dd,a0) { illegal_1(); op_a0(); } /* DB DD */ +OP(dd,a1) { illegal_1(); op_a1(); } /* DB DD */ +OP(dd,a2) { illegal_1(); op_a2(); } /* DB DD */ +OP(dd,a3) { illegal_1(); op_a3(); } /* DB DD */ +OP(dd,a4) { and_a(HX); } /* AND HX */ +OP(dd,a5) { and_a(LX); } /* AND LX */ +OP(dd,a6) { eax(); and_a(rm(m_ea)); } /* AND (IX+o) */ +OP(dd,a7) { illegal_1(); op_a7(); } /* DB DD */ + +OP(dd,a8) { illegal_1(); op_a8(); } /* DB DD */ +OP(dd,a9) { illegal_1(); op_a9(); } /* DB DD */ +OP(dd,aa) { illegal_1(); op_aa(); } /* DB DD */ +OP(dd,ab) { illegal_1(); op_ab(); } /* DB DD */ +OP(dd,ac) { xor_a(HX); } /* XOR HX */ +OP(dd,ad) { xor_a(LX); } /* XOR LX */ +OP(dd,ae) { eax(); xor_a(rm(m_ea)); } /* XOR (IX+o) */ +OP(dd,af) { illegal_1(); op_af(); } /* DB DD */ + +OP(dd,b0) { illegal_1(); op_b0(); } /* DB DD */ +OP(dd,b1) { illegal_1(); op_b1(); } /* DB DD */ +OP(dd,b2) { illegal_1(); op_b2(); } /* DB DD */ +OP(dd,b3) { illegal_1(); op_b3(); } /* DB DD */ +OP(dd,b4) { or_a(HX); } /* OR HX */ +OP(dd,b5) { or_a(LX); } /* OR LX */ +OP(dd,b6) { eax(); or_a(rm(m_ea)); } /* OR (IX+o) */ +OP(dd,b7) { illegal_1(); op_b7(); } /* DB DD */ + +OP(dd,b8) { illegal_1(); op_b8(); } /* DB DD */ +OP(dd,b9) { illegal_1(); op_b9(); } /* DB DD */ +OP(dd,ba) { illegal_1(); op_ba(); } /* DB DD */ +OP(dd,bb) { illegal_1(); op_bb(); } /* DB DD */ +OP(dd,bc) { cp(HX); } /* CP HX */ +OP(dd,bd) { cp(LX); } /* CP LX */ +OP(dd,be) { eax(); cp(rm(m_ea)); } /* CP (IX+o) */ +OP(dd,bf) { illegal_1(); op_bf(); } /* DB DD */ + +OP(dd,c0) { illegal_1(); op_c0(); } /* DB DD */ +OP(dd,c1) { illegal_1(); op_c1(); } /* DB DD */ +OP(dd,c2) { illegal_1(); op_c2(); } /* DB DD */ +OP(dd,c3) { illegal_1(); op_c3(); } /* DB DD */ +OP(dd,c4) { illegal_1(); op_c4(); } /* DB DD */ +OP(dd,c5) { illegal_1(); op_c5(); } /* DB DD */ +OP(dd,c6) { illegal_1(); op_c6(); } /* DB DD */ +OP(dd,c7) { illegal_1(); op_c7(); } /* DB DD */ + +OP(dd,c8) { illegal_1(); op_c8(); } /* DB DD */ +OP(dd,c9) { illegal_1(); op_c9(); } /* DB DD */ +OP(dd,ca) { illegal_1(); op_ca(); } /* DB DD */ +OP(dd,cb) { eax(); EXEC(xycb,arg()); } /* ** DD CB xx */ +OP(dd,cc) { illegal_1(); op_cc(); } /* DB DD */ +OP(dd,cd) { illegal_1(); op_cd(); } /* DB DD */ +OP(dd,ce) { illegal_1(); op_ce(); } /* DB DD */ +OP(dd,cf) { illegal_1(); op_cf(); } /* DB DD */ + +OP(dd,d0) { illegal_1(); op_d0(); } /* DB DD */ +OP(dd,d1) { illegal_1(); op_d1(); } /* DB DD */ +OP(dd,d2) { illegal_1(); op_d2(); } /* DB DD */ +OP(dd,d3) { illegal_1(); op_d3(); } /* DB DD */ +OP(dd,d4) { illegal_1(); op_d4(); } /* DB DD */ +OP(dd,d5) { illegal_1(); op_d5(); } /* DB DD */ +OP(dd,d6) { illegal_1(); op_d6(); } /* DB DD */ +OP(dd,d7) { illegal_1(); op_d7(); } /* DB DD */ + +OP(dd,d8) { illegal_1(); op_d8(); } /* DB DD */ +OP(dd,d9) { illegal_1(); op_d9(); } /* DB DD */ +OP(dd,da) { illegal_1(); op_da(); } /* DB DD */ +OP(dd,db) { illegal_1(); op_db(); } /* DB DD */ +OP(dd,dc) { illegal_1(); op_dc(); } /* DB DD */ +OP(dd,dd) { illegal_1(); op_dd(); } /* DB DD */ +OP(dd,de) { illegal_1(); op_de(); } /* DB DD */ +OP(dd,df) { illegal_1(); op_df(); } /* DB DD */ + +OP(dd,e0) { illegal_1(); op_e0(); } /* DB DD */ +OP(dd,e1) { pop(m_ix); } /* POP IX */ +OP(dd,e2) { illegal_1(); op_e2(); } /* DB DD */ +OP(dd,e3) { ex_sp(m_ix); } /* EX (SP),IX */ +OP(dd,e4) { illegal_1(); op_e4(); } /* DB DD */ +OP(dd,e5) { push(m_ix); } /* PUSH IX */ +OP(dd,e6) { illegal_1(); op_e6(); } /* DB DD */ +OP(dd,e7) { illegal_1(); op_e7(); } /* DB DD */ + +OP(dd,e8) { illegal_1(); op_e8(); } /* DB DD */ +OP(dd,e9) { PC = IX; } /* JP (IX) */ +OP(dd,ea) { illegal_1(); op_ea(); } /* DB DD */ +OP(dd,eb) { illegal_1(); op_eb(); } /* DB DD */ +OP(dd,ec) { illegal_1(); op_ec(); } /* DB DD */ +OP(dd,ed) { illegal_1(); op_ed(); } /* DB DD */ +OP(dd,ee) { illegal_1(); op_ee(); } /* DB DD */ +OP(dd,ef) { illegal_1(); op_ef(); } /* DB DD */ + +OP(dd,f0) { illegal_1(); op_f0(); } /* DB DD */ +OP(dd,f1) { illegal_1(); op_f1(); } /* DB DD */ +OP(dd,f2) { illegal_1(); op_f2(); } /* DB DD */ +OP(dd,f3) { illegal_1(); op_f3(); } /* DB DD */ +OP(dd,f4) { illegal_1(); op_f4(); } /* DB DD */ +OP(dd,f5) { illegal_1(); op_f5(); } /* DB DD */ +OP(dd,f6) { illegal_1(); op_f6(); } /* DB DD */ +OP(dd,f7) { illegal_1(); op_f7(); } /* DB DD */ + +OP(dd,f8) { illegal_1(); op_f8(); } /* DB DD */ +OP(dd,f9) { SP = IX; } /* LD SP,IX */ +OP(dd,fa) { illegal_1(); op_fa(); } /* DB DD */ +OP(dd,fb) { illegal_1(); op_fb(); } /* DB DD */ +OP(dd,fc) { illegal_1(); op_fc(); } /* DB DD */ +OP(dd,fd) { illegal_1(); op_fd(); } /* DB DD */ +OP(dd,fe) { illegal_1(); op_fe(); } /* DB DD */ +OP(dd,ff) { illegal_1(); op_ff(); } /* DB DD */ + +/********************************************************** + * IY register related opcodes (FD prefix) + **********************************************************/ +OP(fd,00) { illegal_1(); op_00(); } /* DB FD */ +OP(fd,01) { illegal_1(); op_01(); } /* DB FD */ +OP(fd,02) { illegal_1(); op_02(); } /* DB FD */ +OP(fd,03) { illegal_1(); op_03(); } /* DB FD */ +OP(fd,04) { illegal_1(); op_04(); } /* DB FD */ +OP(fd,05) { illegal_1(); op_05(); } /* DB FD */ +OP(fd,06) { illegal_1(); op_06(); } /* DB FD */ +OP(fd,07) { illegal_1(); op_07(); } /* DB FD */ + +OP(fd,08) { illegal_1(); op_08(); } /* DB FD */ +OP(fd,09) { add16(m_iy, m_bc); } /* ADD IY,BC */ +OP(fd,0a) { illegal_1(); op_0a(); } /* DB FD */ +OP(fd,0b) { illegal_1(); op_0b(); } /* DB FD */ +OP(fd,0c) { illegal_1(); op_0c(); } /* DB FD */ +OP(fd,0d) { illegal_1(); op_0d(); } /* DB FD */ +OP(fd,0e) { illegal_1(); op_0e(); } /* DB FD */ +OP(fd,0f) { illegal_1(); op_0f(); } /* DB FD */ + +OP(fd,10) { illegal_1(); op_10(); } /* DB FD */ +OP(fd,11) { illegal_1(); op_11(); } /* DB FD */ +OP(fd,12) { illegal_1(); op_12(); } /* DB FD */ +OP(fd,13) { illegal_1(); op_13(); } /* DB FD */ +OP(fd,14) { illegal_1(); op_14(); } /* DB FD */ +OP(fd,15) { illegal_1(); op_15(); } /* DB FD */ +OP(fd,16) { illegal_1(); op_16(); } /* DB FD */ +OP(fd,17) { illegal_1(); op_17(); } /* DB FD */ + +OP(fd,18) { illegal_1(); op_18(); } /* DB FD */ +OP(fd,19) { add16(m_iy, m_de); } /* ADD IY,DE */ +OP(fd,1a) { illegal_1(); op_1a(); } /* DB FD */ +OP(fd,1b) { illegal_1(); op_1b(); } /* DB FD */ +OP(fd,1c) { illegal_1(); op_1c(); } /* DB FD */ +OP(fd,1d) { illegal_1(); op_1d(); } /* DB FD */ +OP(fd,1e) { illegal_1(); op_1e(); } /* DB FD */ +OP(fd,1f) { illegal_1(); op_1f(); } /* DB FD */ + +OP(fd,20) { illegal_1(); op_20(); } /* DB FD */ +OP(fd,21) { IY = arg16(); } /* LD IY,w */ +OP(fd,22) { m_ea = arg16(); wm16(m_ea, m_iy); WZ = m_ea + 1; } /* LD (w),IY */ +OP(fd,23) { IY++; } /* INC IY */ +OP(fd,24) { HY = inc(HY); } /* INC HY */ +OP(fd,25) { HY = dec(HY); } /* DEC HY */ +OP(fd,26) { HY = arg(); } /* LD HY,n */ +OP(fd,27) { illegal_1(); op_27(); } /* DB FD */ + +OP(fd,28) { illegal_1(); op_28(); } /* DB FD */ +OP(fd,29) { add16(m_iy, m_iy); } /* ADD IY,IY */ +OP(fd,2a) { m_ea = arg16(); rm16(m_ea, m_iy); WZ = m_ea + 1; } /* LD IY,(w) */ +OP(fd,2b) { IY--; } /* DEC IY */ +OP(fd,2c) { LY = inc(LY); } /* INC LY */ +OP(fd,2d) { LY = dec(LY); } /* DEC LY */ +OP(fd,2e) { LY = arg(); } /* LD LY,n */ +OP(fd,2f) { illegal_1(); op_2f(); } /* DB FD */ + +OP(fd,30) { illegal_1(); op_30(); } /* DB FD */ +OP(fd,31) { illegal_1(); op_31(); } /* DB FD */ +OP(fd,32) { illegal_1(); op_32(); } /* DB FD */ +OP(fd,33) { illegal_1(); op_33(); } /* DB FD */ +OP(fd,34) { eay(); wm(m_ea, inc(rm(m_ea))); } /* INC (IY+o) */ +OP(fd,35) { eay(); wm(m_ea, dec(rm(m_ea))); } /* DEC (IY+o) */ +OP(fd,36) { eay(); wm(m_ea, arg()); } /* LD (IY+o),n */ +OP(fd,37) { illegal_1(); op_37(); } /* DB FD */ + +OP(fd,38) { illegal_1(); op_38(); } /* DB FD */ +OP(fd,39) { add16(m_iy, m_sp); } /* ADD IY,SP */ +OP(fd,3a) { illegal_1(); op_3a(); } /* DB FD */ +OP(fd,3b) { illegal_1(); op_3b(); } /* DB FD */ +OP(fd,3c) { illegal_1(); op_3c(); } /* DB FD */ +OP(fd,3d) { illegal_1(); op_3d(); } /* DB FD */ +OP(fd,3e) { illegal_1(); op_3e(); } /* DB FD */ +OP(fd,3f) { illegal_1(); op_3f(); } /* DB FD */ + +OP(fd,40) { illegal_1(); op_40(); } /* DB FD */ +OP(fd,41) { illegal_1(); op_41(); } /* DB FD */ +OP(fd,42) { illegal_1(); op_42(); } /* DB FD */ +OP(fd,43) { illegal_1(); op_43(); } /* DB FD */ +OP(fd,44) { B = HY; } /* LD B,HY */ +OP(fd,45) { B = LY; } /* LD B,LY */ +OP(fd,46) { eay(); B = rm(m_ea); } /* LD B,(IY+o) */ +OP(fd,47) { illegal_1(); op_47(); } /* DB FD */ + +OP(fd,48) { illegal_1(); op_48(); } /* DB FD */ +OP(fd,49) { illegal_1(); op_49(); } /* DB FD */ +OP(fd,4a) { illegal_1(); op_4a(); } /* DB FD */ +OP(fd,4b) { illegal_1(); op_4b(); } /* DB FD */ +OP(fd,4c) { C = HY; } /* LD C,HY */ +OP(fd,4d) { C = LY; } /* LD C,LY */ +OP(fd,4e) { eay(); C = rm(m_ea); } /* LD C,(IY+o) */ +OP(fd,4f) { illegal_1(); op_4f(); } /* DB FD */ + +OP(fd,50) { illegal_1(); op_50(); } /* DB FD */ +OP(fd,51) { illegal_1(); op_51(); } /* DB FD */ +OP(fd,52) { illegal_1(); op_52(); } /* DB FD */ +OP(fd,53) { illegal_1(); op_53(); } /* DB FD */ +OP(fd,54) { D = HY; } /* LD D,HY */ +OP(fd,55) { D = LY; } /* LD D,LY */ +OP(fd,56) { eay(); D = rm(m_ea); } /* LD D,(IY+o) */ +OP(fd,57) { illegal_1(); op_57(); } /* DB FD */ + +OP(fd,58) { illegal_1(); op_58(); } /* DB FD */ +OP(fd,59) { illegal_1(); op_59(); } /* DB FD */ +OP(fd,5a) { illegal_1(); op_5a(); } /* DB FD */ +OP(fd,5b) { illegal_1(); op_5b(); } /* DB FD */ +OP(fd,5c) { E = HY; } /* LD E,HY */ +OP(fd,5d) { E = LY; } /* LD E,LY */ +OP(fd,5e) { eay(); E = rm(m_ea); } /* LD E,(IY+o) */ +OP(fd,5f) { illegal_1(); op_5f(); } /* DB FD */ + +OP(fd,60) { HY = B; } /* LD HY,B */ +OP(fd,61) { HY = C; } /* LD HY,C */ +OP(fd,62) { HY = D; } /* LD HY,D */ +OP(fd,63) { HY = E; } /* LD HY,E */ +OP(fd,64) { } /* LD HY,HY */ +OP(fd,65) { HY = LY; } /* LD HY,LY */ +OP(fd,66) { eay(); H = rm(m_ea); } /* LD H,(IY+o) */ +OP(fd,67) { HY = A; } /* LD HY,A */ + +OP(fd,68) { LY = B; } /* LD LY,B */ +OP(fd,69) { LY = C; } /* LD LY,C */ +OP(fd,6a) { LY = D; } /* LD LY,D */ +OP(fd,6b) { LY = E; } /* LD LY,E */ +OP(fd,6c) { LY = HY; } /* LD LY,HY */ +OP(fd,6d) { } /* LD LY,LY */ +OP(fd,6e) { eay(); L = rm(m_ea); } /* LD L,(IY+o) */ +OP(fd,6f) { LY = A; } /* LD LY,A */ + +OP(fd,70) { eay(); wm(m_ea, B); } /* LD (IY+o),B */ +OP(fd,71) { eay(); wm(m_ea, C); } /* LD (IY+o),C */ +OP(fd,72) { eay(); wm(m_ea, D); } /* LD (IY+o),D */ +OP(fd,73) { eay(); wm(m_ea, E); } /* LD (IY+o),E */ +OP(fd,74) { eay(); wm(m_ea, H); } /* LD (IY+o),H */ +OP(fd,75) { eay(); wm(m_ea, L); } /* LD (IY+o),L */ +OP(fd,76) { illegal_1(); op_76(); } /* DB FD */ +OP(fd,77) { eay(); wm(m_ea, A); } /* LD (IY+o),A */ + +OP(fd,78) { illegal_1(); op_78(); } /* DB FD */ +OP(fd,79) { illegal_1(); op_79(); } /* DB FD */ +OP(fd,7a) { illegal_1(); op_7a(); } /* DB FD */ +OP(fd,7b) { illegal_1(); op_7b(); } /* DB FD */ +OP(fd,7c) { A = HY; } /* LD A,HY */ +OP(fd,7d) { A = LY; } /* LD A,LY */ +OP(fd,7e) { eay(); A = rm(m_ea); } /* LD A,(IY+o) */ +OP(fd,7f) { illegal_1(); op_7f(); } /* DB FD */ + +OP(fd,80) { illegal_1(); op_80(); } /* DB FD */ +OP(fd,81) { illegal_1(); op_81(); } /* DB FD */ +OP(fd,82) { illegal_1(); op_82(); } /* DB FD */ +OP(fd,83) { illegal_1(); op_83(); } /* DB FD */ +OP(fd,84) { add_a(HY); } /* ADD A,HY */ +OP(fd,85) { add_a(LY); } /* ADD A,LY */ +OP(fd,86) { eay(); add_a(rm(m_ea)); } /* ADD A,(IY+o) */ +OP(fd,87) { illegal_1(); op_87(); } /* DB FD */ + +OP(fd,88) { illegal_1(); op_88(); } /* DB FD */ +OP(fd,89) { illegal_1(); op_89(); } /* DB FD */ +OP(fd,8a) { illegal_1(); op_8a(); } /* DB FD */ +OP(fd,8b) { illegal_1(); op_8b(); } /* DB FD */ +OP(fd,8c) { adc_a(HY); } /* ADC A,HY */ +OP(fd,8d) { adc_a(LY); } /* ADC A,LY */ +OP(fd,8e) { eay(); adc_a(rm(m_ea)); } /* ADC A,(IY+o) */ +OP(fd,8f) { illegal_1(); op_8f(); } /* DB FD */ + +OP(fd,90) { illegal_1(); op_90(); } /* DB FD */ +OP(fd,91) { illegal_1(); op_91(); } /* DB FD */ +OP(fd,92) { illegal_1(); op_92(); } /* DB FD */ +OP(fd,93) { illegal_1(); op_93(); } /* DB FD */ +OP(fd,94) { sub(HY); } /* SUB HY */ +OP(fd,95) { sub(LY); } /* SUB LY */ +OP(fd,96) { eay(); sub(rm(m_ea)); } /* SUB (IY+o) */ +OP(fd,97) { illegal_1(); op_97(); } /* DB FD */ + +OP(fd,98) { illegal_1(); op_98(); } /* DB FD */ +OP(fd,99) { illegal_1(); op_99(); } /* DB FD */ +OP(fd,9a) { illegal_1(); op_9a(); } /* DB FD */ +OP(fd,9b) { illegal_1(); op_9b(); } /* DB FD */ +OP(fd,9c) { sbc_a(HY); } /* SBC A,HY */ +OP(fd,9d) { sbc_a(LY); } /* SBC A,LY */ +OP(fd,9e) { eay(); sbc_a(rm(m_ea)); } /* SBC A,(IY+o) */ +OP(fd,9f) { illegal_1(); op_9f(); } /* DB FD */ + +OP(fd,a0) { illegal_1(); op_a0(); } /* DB FD */ +OP(fd,a1) { illegal_1(); op_a1(); } /* DB FD */ +OP(fd,a2) { illegal_1(); op_a2(); } /* DB FD */ +OP(fd,a3) { illegal_1(); op_a3(); } /* DB FD */ +OP(fd,a4) { and_a(HY); } /* AND HY */ +OP(fd,a5) { and_a(LY); } /* AND LY */ +OP(fd,a6) { eay(); and_a(rm(m_ea)); } /* AND (IY+o) */ +OP(fd,a7) { illegal_1(); op_a7(); } /* DB FD */ + +OP(fd,a8) { illegal_1(); op_a8(); } /* DB FD */ +OP(fd,a9) { illegal_1(); op_a9(); } /* DB FD */ +OP(fd,aa) { illegal_1(); op_aa(); } /* DB FD */ +OP(fd,ab) { illegal_1(); op_ab(); } /* DB FD */ +OP(fd,ac) { xor_a(HY); } /* XOR HY */ +OP(fd,ad) { xor_a(LY); } /* XOR LY */ +OP(fd,ae) { eay(); xor_a(rm(m_ea)); } /* XOR (IY+o) */ +OP(fd,af) { illegal_1(); op_af(); } /* DB FD */ + +OP(fd,b0) { illegal_1(); op_b0(); } /* DB FD */ +OP(fd,b1) { illegal_1(); op_b1(); } /* DB FD */ +OP(fd,b2) { illegal_1(); op_b2(); } /* DB FD */ +OP(fd,b3) { illegal_1(); op_b3(); } /* DB FD */ +OP(fd,b4) { or_a(HY); } /* OR HY */ +OP(fd,b5) { or_a(LY); } /* OR LY */ +OP(fd,b6) { eay(); or_a(rm(m_ea)); } /* OR (IY+o) */ +OP(fd,b7) { illegal_1(); op_b7(); } /* DB FD */ + +OP(fd,b8) { illegal_1(); op_b8(); } /* DB FD */ +OP(fd,b9) { illegal_1(); op_b9(); } /* DB FD */ +OP(fd,ba) { illegal_1(); op_ba(); } /* DB FD */ +OP(fd,bb) { illegal_1(); op_bb(); } /* DB FD */ +OP(fd,bc) { cp(HY); } /* CP HY */ +OP(fd,bd) { cp(LY); } /* CP LY */ +OP(fd,be) { eay(); cp(rm(m_ea)); } /* CP (IY+o) */ +OP(fd,bf) { illegal_1(); op_bf(); } /* DB FD */ + +OP(fd,c0) { illegal_1(); op_c0(); } /* DB FD */ +OP(fd,c1) { illegal_1(); op_c1(); } /* DB FD */ +OP(fd,c2) { illegal_1(); op_c2(); } /* DB FD */ +OP(fd,c3) { illegal_1(); op_c3(); } /* DB FD */ +OP(fd,c4) { illegal_1(); op_c4(); } /* DB FD */ +OP(fd,c5) { illegal_1(); op_c5(); } /* DB FD */ +OP(fd,c6) { illegal_1(); op_c6(); } /* DB FD */ +OP(fd,c7) { illegal_1(); op_c7(); } /* DB FD */ + +OP(fd,c8) { illegal_1(); op_c8(); } /* DB FD */ +OP(fd,c9) { illegal_1(); op_c9(); } /* DB FD */ +OP(fd,ca) { illegal_1(); op_ca(); } /* DB FD */ +OP(fd,cb) { eay(); EXEC(xycb,arg()); } /* ** FD CB xx */ +OP(fd,cc) { illegal_1(); op_cc(); } /* DB FD */ +OP(fd,cd) { illegal_1(); op_cd(); } /* DB FD */ +OP(fd,ce) { illegal_1(); op_ce(); } /* DB FD */ +OP(fd,cf) { illegal_1(); op_cf(); } /* DB FD */ + +OP(fd,d0) { illegal_1(); op_d0(); } /* DB FD */ +OP(fd,d1) { illegal_1(); op_d1(); } /* DB FD */ +OP(fd,d2) { illegal_1(); op_d2(); } /* DB FD */ +OP(fd,d3) { illegal_1(); op_d3(); } /* DB FD */ +OP(fd,d4) { illegal_1(); op_d4(); } /* DB FD */ +OP(fd,d5) { illegal_1(); op_d5(); } /* DB FD */ +OP(fd,d6) { illegal_1(); op_d6(); } /* DB FD */ +OP(fd,d7) { illegal_1(); op_d7(); } /* DB FD */ + +OP(fd,d8) { illegal_1(); op_d8(); } /* DB FD */ +OP(fd,d9) { illegal_1(); op_d9(); } /* DB FD */ +OP(fd,da) { illegal_1(); op_da(); } /* DB FD */ +OP(fd,db) { illegal_1(); op_db(); } /* DB FD */ +OP(fd,dc) { illegal_1(); op_dc(); } /* DB FD */ +OP(fd,dd) { illegal_1(); op_dd(); } /* DB FD */ +OP(fd,de) { illegal_1(); op_de(); } /* DB FD */ +OP(fd,df) { illegal_1(); op_df(); } /* DB FD */ + +OP(fd,e0) { illegal_1(); op_e0(); } /* DB FD */ +OP(fd,e1) { pop(m_iy); } /* POP IY */ +OP(fd,e2) { illegal_1(); op_e2(); } /* DB FD */ +OP(fd,e3) { ex_sp(m_iy); } /* EX (SP),IY */ +OP(fd,e4) { illegal_1(); op_e4(); } /* DB FD */ +OP(fd,e5) { push(m_iy); } /* PUSH IY */ +OP(fd,e6) { illegal_1(); op_e6(); } /* DB FD */ +OP(fd,e7) { illegal_1(); op_e7(); } /* DB FD */ + +OP(fd,e8) { illegal_1(); op_e8(); } /* DB FD */ +OP(fd,e9) { PC = IY; } /* JP (IY) */ +OP(fd,ea) { illegal_1(); op_ea(); } /* DB FD */ +OP(fd,eb) { illegal_1(); op_eb(); } /* DB FD */ +OP(fd,ec) { illegal_1(); op_ec(); } /* DB FD */ +OP(fd,ed) { illegal_1(); op_ed(); } /* DB FD */ +OP(fd,ee) { illegal_1(); op_ee(); } /* DB FD */ +OP(fd,ef) { illegal_1(); op_ef(); } /* DB FD */ + +OP(fd,f0) { illegal_1(); op_f0(); } /* DB FD */ +OP(fd,f1) { illegal_1(); op_f1(); } /* DB FD */ +OP(fd,f2) { illegal_1(); op_f2(); } /* DB FD */ +OP(fd,f3) { illegal_1(); op_f3(); } /* DB FD */ +OP(fd,f4) { illegal_1(); op_f4(); } /* DB FD */ +OP(fd,f5) { illegal_1(); op_f5(); } /* DB FD */ +OP(fd,f6) { illegal_1(); op_f6(); } /* DB FD */ +OP(fd,f7) { illegal_1(); op_f7(); } /* DB FD */ + +OP(fd,f8) { illegal_1(); op_f8(); } /* DB FD */ +OP(fd,f9) { SP = IY; } /* LD SP,IY */ +OP(fd,fa) { illegal_1(); op_fa(); } /* DB FD */ +OP(fd,fb) { illegal_1(); op_fb(); } /* DB FD */ +OP(fd,fc) { illegal_1(); op_fc(); } /* DB FD */ +OP(fd,fd) { illegal_1(); op_fd(); } /* DB FD */ +OP(fd,fe) { illegal_1(); op_fe(); } /* DB FD */ +OP(fd,ff) { illegal_1(); op_ff(); } /* DB FD */ + +OP(illegal,2) +{ + logerror("Z80 '%s' ill. opcode $ed $%02x\n", + tag(), m_decrypted_opcodes_direct->read_byte((PCD-1)&0xffff)); +} + +/********************************************************** + * special opcodes (ED prefix) + **********************************************************/ +OP(ed,00) { illegal_2(); } /* DB ED */ +OP(ed,01) { illegal_2(); } /* DB ED */ +OP(ed,02) { illegal_2(); } /* DB ED */ +OP(ed,03) { illegal_2(); } /* DB ED */ +OP(ed,04) { illegal_2(); } /* DB ED */ +OP(ed,05) { illegal_2(); } /* DB ED */ +OP(ed,06) { illegal_2(); } /* DB ED */ +OP(ed,07) { illegal_2(); } /* DB ED */ + +OP(ed,08) { illegal_2(); } /* DB ED */ +OP(ed,09) { illegal_2(); } /* DB ED */ +OP(ed,0a) { illegal_2(); } /* DB ED */ +OP(ed,0b) { illegal_2(); } /* DB ED */ +OP(ed,0c) { illegal_2(); } /* DB ED */ +OP(ed,0d) { illegal_2(); } /* DB ED */ +OP(ed,0e) { illegal_2(); } /* DB ED */ +OP(ed,0f) { illegal_2(); } /* DB ED */ + +OP(ed,10) { illegal_2(); } /* DB ED */ +OP(ed,11) { illegal_2(); } /* DB ED */ +OP(ed,12) { illegal_2(); } /* DB ED */ +OP(ed,13) { illegal_2(); } /* DB ED */ +OP(ed,14) { illegal_2(); } /* DB ED */ +OP(ed,15) { illegal_2(); } /* DB ED */ +OP(ed,16) { illegal_2(); } /* DB ED */ +OP(ed,17) { illegal_2(); } /* DB ED */ + +OP(ed,18) { illegal_2(); } /* DB ED */ +OP(ed,19) { illegal_2(); } /* DB ED */ +OP(ed,1a) { illegal_2(); } /* DB ED */ +OP(ed,1b) { illegal_2(); } /* DB ED */ +OP(ed,1c) { illegal_2(); } /* DB ED */ +OP(ed,1d) { illegal_2(); } /* DB ED */ +OP(ed,1e) { illegal_2(); } /* DB ED */ +OP(ed,1f) { illegal_2(); } /* DB ED */ + +OP(ed,20) { illegal_2(); } /* DB ED */ +OP(ed,21) { illegal_2(); } /* DB ED */ +OP(ed,22) { illegal_2(); } /* DB ED */ +OP(ed,23) { illegal_2(); } /* DB ED */ +OP(ed,24) { illegal_2(); } /* DB ED */ +OP(ed,25) { illegal_2(); } /* DB ED */ +OP(ed,26) { illegal_2(); } /* DB ED */ +OP(ed,27) { illegal_2(); } /* DB ED */ + +OP(ed,28) { illegal_2(); } /* DB ED */ +OP(ed,29) { illegal_2(); } /* DB ED */ +OP(ed,2a) { illegal_2(); } /* DB ED */ +OP(ed,2b) { illegal_2(); } /* DB ED */ +OP(ed,2c) { illegal_2(); } /* DB ED */ +OP(ed,2d) { illegal_2(); } /* DB ED */ +OP(ed,2e) { illegal_2(); } /* DB ED */ +OP(ed,2f) { illegal_2(); } /* DB ED */ + +OP(ed,30) { illegal_2(); } /* DB ED */ +OP(ed,31) { illegal_2(); } /* DB ED */ +OP(ed,32) { illegal_2(); } /* DB ED */ +OP(ed,33) { illegal_2(); } /* DB ED */ +OP(ed,34) { illegal_2(); } /* DB ED */ +OP(ed,35) { illegal_2(); } /* DB ED */ +OP(ed,36) { illegal_2(); } /* DB ED */ +OP(ed,37) { illegal_2(); } /* DB ED */ + +OP(ed,38) { illegal_2(); } /* DB ED */ +OP(ed,39) { illegal_2(); } /* DB ED */ +OP(ed,3a) { illegal_2(); } /* DB ED */ +OP(ed,3b) { illegal_2(); } /* DB ED */ +OP(ed,3c) { illegal_2(); } /* DB ED */ +OP(ed,3d) { illegal_2(); } /* DB ED */ +OP(ed,3e) { illegal_2(); } /* DB ED */ +OP(ed,3f) { illegal_2(); } /* DB ED */ + +OP(ed,40) { B = in(BC); F = (F & CF) | SZP[B]; } /* IN B,(C) */ +OP(ed,41) { out(BC, B); } /* OUT (C),B */ +OP(ed,42) { sbc_hl(m_bc); } /* SBC HL,BC */ +OP(ed,43) { m_ea = arg16(); wm16(m_ea, m_bc); WZ = m_ea + 1; } /* LD (w),BC */ +OP(ed,44) { neg(); } /* NEG */ +OP(ed,45) { retn(); } /* RETN */ +OP(ed,46) { m_im = 0; } /* IM 0 */ +OP(ed,47) { ld_i_a(); } /* LD i,A */ + +OP(ed,48) { C = in(BC); F = (F & CF) | SZP[C]; } /* IN C,(C) */ +OP(ed,49) { out(BC, C); } /* OUT (C),C */ +OP(ed,4a) { adc_hl(m_bc); } /* ADC HL,BC */ +OP(ed,4b) { m_ea = arg16(); rm16(m_ea, m_bc); WZ = m_ea + 1; } /* LD BC,(w) */ +OP(ed,4c) { neg(); } /* NEG */ +OP(ed,4d) { reti(); } /* RETI */ +OP(ed,4e) { m_im = 0; } /* IM 0 */ +OP(ed,4f) { ld_r_a(); } /* LD r,A */ + +OP(ed,50) { D = in(BC); F = (F & CF) | SZP[D]; } /* IN D,(C) */ +OP(ed,51) { out(BC, D); } /* OUT (C),D */ +OP(ed,52) { sbc_hl(m_de); } /* SBC HL,DE */ +OP(ed,53) { m_ea = arg16(); wm16(m_ea, m_de); WZ = m_ea + 1; } /* LD (w),DE */ +OP(ed,54) { neg(); } /* NEG */ +OP(ed,55) { retn(); } /* RETN */ +OP(ed,56) { m_im = 1; } /* IM 1 */ +OP(ed,57) { ld_a_i(); } /* LD A,i */ + +OP(ed,58) { E = in(BC); F = (F & CF) | SZP[E]; } /* IN E,(C) */ +OP(ed,59) { out(BC, E); } /* OUT (C),E */ +OP(ed,5a) { adc_hl(m_de); } /* ADC HL,DE */ +OP(ed,5b) { m_ea = arg16(); rm16(m_ea, m_de); WZ = m_ea + 1; } /* LD DE,(w) */ +OP(ed,5c) { neg(); } /* NEG */ +OP(ed,5d) { reti(); } /* RETI */ +OP(ed,5e) { m_im = 2; } /* IM 2 */ +OP(ed,5f) { ld_a_r(); } /* LD A,r */ + +OP(ed,60) { H = in(BC); F = (F & CF) | SZP[H]; } /* IN H,(C) */ +OP(ed,61) { out(BC, H); } /* OUT (C),H */ +OP(ed,62) { sbc_hl(m_hl); } /* SBC HL,HL */ +OP(ed,63) { m_ea = arg16(); wm16(m_ea, m_hl); WZ = m_ea + 1; } /* LD (w),HL */ +OP(ed,64) { neg(); } /* NEG */ +OP(ed,65) { retn(); } /* RETN */ +OP(ed,66) { m_im = 0; } /* IM 0 */ +OP(ed,67) { rrd(); } /* RRD (HL) */ + +OP(ed,68) { L = in(BC); F = (F & CF) | SZP[L]; } /* IN L,(C) */ +OP(ed,69) { out(BC, L); } /* OUT (C),L */ +OP(ed,6a) { adc_hl(m_hl); } /* ADC HL,HL */ +OP(ed,6b) { m_ea = arg16(); rm16(m_ea, m_hl); WZ = m_ea + 1; } /* LD HL,(w) */ +OP(ed,6c) { neg(); } /* NEG */ +OP(ed,6d) { reti(); } /* RETI */ +OP(ed,6e) { m_im = 0; } /* IM 0 */ +OP(ed,6f) { rld(); } /* RLD (HL) */ + +OP(ed,70) { UINT8 res = in(BC); F = (F & CF) | SZP[res]; } /* IN 0,(C) */ +OP(ed,71) { out(BC, 0); } /* OUT (C),0 */ +OP(ed,72) { sbc_hl(m_sp); } /* SBC HL,SP */ +OP(ed,73) { m_ea = arg16(); wm16(m_ea, m_sp); WZ = m_ea + 1; } /* LD (w),SP */ +OP(ed,74) { neg(); } /* NEG */ +OP(ed,75) { retn(); } /* RETN */ +OP(ed,76) { m_im = 1; } /* IM 1 */ +OP(ed,77) { illegal_2(); } /* DB ED,77 */ + +OP(ed,78) { A = in(BC); F = (F & CF) | SZP[A]; WZ = BC + 1; } /* IN A,(C) */ +OP(ed,79) { out(BC, A); WZ = BC + 1; } /* OUT (C),A */ +OP(ed,7a) { adc_hl(m_sp); } /* ADC HL,SP */ +OP(ed,7b) { m_ea = arg16(); rm16(m_ea, m_sp); WZ = m_ea + 1; } /* LD SP,(w) */ +OP(ed,7c) { neg(); } /* NEG */ +OP(ed,7d) { reti(); } /* RETI */ +OP(ed,7e) { m_im = 2; } /* IM 2 */ +OP(ed,7f) { illegal_2(); } /* DB ED,7F */ + +OP(ed,80) { illegal_2(); } /* DB ED */ +OP(ed,81) { illegal_2(); } /* DB ED */ +OP(ed,82) { illegal_2(); } /* DB ED */ +OP(ed,83) { illegal_2(); } /* DB ED */ +OP(ed,84) { illegal_2(); } /* DB ED */ +OP(ed,85) { illegal_2(); } /* DB ED */ +OP(ed,86) { illegal_2(); } /* DB ED */ +OP(ed,87) { illegal_2(); } /* DB ED */ + +OP(ed,88) { illegal_2(); } /* DB ED */ +OP(ed,89) { illegal_2(); } /* DB ED */ +OP(ed,8a) { illegal_2(); } /* DB ED */ +OP(ed,8b) { illegal_2(); } /* DB ED */ +OP(ed,8c) { illegal_2(); } /* DB ED */ +OP(ed,8d) { illegal_2(); } /* DB ED */ +OP(ed,8e) { illegal_2(); } /* DB ED */ +OP(ed,8f) { illegal_2(); } /* DB ED */ + +OP(ed,90) { illegal_2(); } /* DB ED */ +OP(ed,91) { illegal_2(); } /* DB ED */ +OP(ed,92) { illegal_2(); } /* DB ED */ +OP(ed,93) { illegal_2(); } /* DB ED */ +OP(ed,94) { illegal_2(); } /* DB ED */ +OP(ed,95) { illegal_2(); } /* DB ED */ +OP(ed,96) { illegal_2(); } /* DB ED */ +OP(ed,97) { illegal_2(); } /* DB ED */ + +OP(ed,98) { illegal_2(); } /* DB ED */ +OP(ed,99) { illegal_2(); } /* DB ED */ +OP(ed,9a) { illegal_2(); } /* DB ED */ +OP(ed,9b) { illegal_2(); } /* DB ED */ +OP(ed,9c) { illegal_2(); } /* DB ED */ +OP(ed,9d) { illegal_2(); } /* DB ED */ +OP(ed,9e) { illegal_2(); } /* DB ED */ +OP(ed,9f) { illegal_2(); } /* DB ED */ + +OP(ed,a0) { ldi(); } /* LDI */ +OP(ed,a1) { cpi(); } /* CPI */ +OP(ed,a2) { ini(); } /* INI */ +OP(ed,a3) { outi(); } /* OUTI */ +OP(ed,a4) { illegal_2(); } /* DB ED */ +OP(ed,a5) { illegal_2(); } /* DB ED */ +OP(ed,a6) { illegal_2(); } /* DB ED */ +OP(ed,a7) { illegal_2(); } /* DB ED */ + +OP(ed,a8) { ldd(); } /* LDD */ +OP(ed,a9) { cpd(); } /* CPD */ +OP(ed,aa) { ind(); } /* IND */ +OP(ed,ab) { outd(); } /* OUTD */ +OP(ed,ac) { illegal_2(); } /* DB ED */ +OP(ed,ad) { illegal_2(); } /* DB ED */ +OP(ed,ae) { illegal_2(); } /* DB ED */ +OP(ed,af) { illegal_2(); } /* DB ED */ + +OP(ed,b0) { ldir(); } /* LDIR */ +OP(ed,b1) { cpir(); } /* CPIR */ +OP(ed,b2) { inir(); } /* INIR */ +OP(ed,b3) { otir(); } /* OTIR */ +OP(ed,b4) { illegal_2(); } /* DB ED */ +OP(ed,b5) { illegal_2(); } /* DB ED */ +OP(ed,b6) { illegal_2(); } /* DB ED */ +OP(ed,b7) { illegal_2(); } /* DB ED */ + +OP(ed,b8) { lddr(); } /* LDDR */ +OP(ed,b9) { cpdr(); } /* CPDR */ +OP(ed,ba) { indr(); } /* INDR */ +OP(ed,bb) { otdr(); } /* OTDR */ +OP(ed,bc) { illegal_2(); } /* DB ED */ +OP(ed,bd) { illegal_2(); } /* DB ED */ +OP(ed,be) { illegal_2(); } /* DB ED */ +OP(ed,bf) { illegal_2(); } /* DB ED */ + +OP(ed,c0) { illegal_2(); } /* DB ED */ +OP(ed,c1) { illegal_2(); } /* DB ED */ +OP(ed,c2) { illegal_2(); } /* DB ED */ +OP(ed,c3) { illegal_2(); } /* DB ED */ +OP(ed,c4) { illegal_2(); } /* DB ED */ +OP(ed,c5) { illegal_2(); } /* DB ED */ +OP(ed,c6) { illegal_2(); } /* DB ED */ +OP(ed,c7) { illegal_2(); } /* DB ED */ + +OP(ed,c8) { illegal_2(); } /* DB ED */ +OP(ed,c9) { illegal_2(); } /* DB ED */ +OP(ed,ca) { illegal_2(); } /* DB ED */ +OP(ed,cb) { illegal_2(); } /* DB ED */ +OP(ed,cc) { illegal_2(); } /* DB ED */ +OP(ed,cd) { illegal_2(); } /* DB ED */ +OP(ed,ce) { illegal_2(); } /* DB ED */ +OP(ed,cf) { illegal_2(); } /* DB ED */ + +OP(ed,d0) { illegal_2(); } /* DB ED */ +OP(ed,d1) { illegal_2(); } /* DB ED */ +OP(ed,d2) { illegal_2(); } /* DB ED */ +OP(ed,d3) { illegal_2(); } /* DB ED */ +OP(ed,d4) { illegal_2(); } /* DB ED */ +OP(ed,d5) { illegal_2(); } /* DB ED */ +OP(ed,d6) { illegal_2(); } /* DB ED */ +OP(ed,d7) { illegal_2(); } /* DB ED */ + +OP(ed,d8) { illegal_2(); } /* DB ED */ +OP(ed,d9) { illegal_2(); } /* DB ED */ +OP(ed,da) { illegal_2(); } /* DB ED */ +OP(ed,db) { illegal_2(); } /* DB ED */ +OP(ed,dc) { illegal_2(); } /* DB ED */ +OP(ed,dd) { illegal_2(); } /* DB ED */ +OP(ed,de) { illegal_2(); } /* DB ED */ +OP(ed,df) { illegal_2(); } /* DB ED */ + +OP(ed,e0) { illegal_2(); } /* DB ED */ +OP(ed,e1) { illegal_2(); } /* DB ED */ +OP(ed,e2) { illegal_2(); } /* DB ED */ +OP(ed,e3) { illegal_2(); } /* DB ED */ +OP(ed,e4) { illegal_2(); } /* DB ED */ +OP(ed,e5) { illegal_2(); } /* DB ED */ +OP(ed,e6) { illegal_2(); } /* DB ED */ +OP(ed,e7) { illegal_2(); } /* DB ED */ + +OP(ed,e8) { illegal_2(); } /* DB ED */ +OP(ed,e9) { illegal_2(); } /* DB ED */ +OP(ed,ea) { illegal_2(); } /* DB ED */ +OP(ed,eb) { illegal_2(); } /* DB ED */ +OP(ed,ec) { illegal_2(); } /* DB ED */ +OP(ed,ed) { illegal_2(); } /* DB ED */ +OP(ed,ee) { illegal_2(); } /* DB ED */ +OP(ed,ef) { illegal_2(); } /* DB ED */ + +OP(ed,f0) { illegal_2(); } /* DB ED */ +OP(ed,f1) { illegal_2(); } /* DB ED */ +OP(ed,f2) { illegal_2(); } /* DB ED */ +OP(ed,f3) { illegal_2(); } /* DB ED */ +OP(ed,f4) { illegal_2(); } /* DB ED */ +OP(ed,f5) { illegal_2(); } /* DB ED */ +OP(ed,f6) { illegal_2(); } /* DB ED */ +OP(ed,f7) { illegal_2(); } /* DB ED */ + +OP(ed,f8) { illegal_2(); } /* DB ED */ +OP(ed,f9) { illegal_2(); } /* DB ED */ +OP(ed,fa) { illegal_2(); } /* DB ED */ +OP(ed,fb) { illegal_2(); } /* DB ED */ +OP(ed,fc) { illegal_2(); } /* DB ED */ +OP(ed,fd) { illegal_2(); } /* DB ED */ +OP(ed,fe) { illegal_2(); } /* DB ED */ +OP(ed,ff) { illegal_2(); } /* DB ED */ + + +/********************************************************** + * main opcodes + **********************************************************/ +OP(op,00) { } /* NOP */ +OP(op,01) { BC = arg16(); } /* LD BC,w */ +OP(op,02) { wm(BC,A); WZ_L = (BC + 1) & 0xFF; WZ_H = A; } /* LD (BC),A */ +OP(op,03) { BC++; } /* INC BC */ +OP(op,04) { B = inc(B); } /* INC B */ +OP(op,05) { B = dec(B); } /* DEC B */ +OP(op,06) { B = arg(); } /* LD B,n */ +OP(op,07) { rlca(); } /* RLCA */ + +OP(op,08) { ex_af(); } /* EX AF,AF' */ +OP(op,09) { add16(m_hl, m_bc); } /* ADD HL,BC */ +OP(op,0a) { A = rm(BC); WZ=BC+1; } /* LD A,(BC) */ +OP(op,0b) { BC--; } /* DEC BC */ +OP(op,0c) { C = inc(C); } /* INC C */ +OP(op,0d) { C = dec(C); } /* DEC C */ +OP(op,0e) { C = arg(); } /* LD C,n */ +OP(op,0f) { rrca(); } /* RRCA */ + +OP(op,10) { B--; jr_cond(B, 0x10); } /* DJNZ o */ +OP(op,11) { DE = arg16(); } /* LD DE,w */ +OP(op,12) { wm(DE,A); WZ_L = (DE + 1) & 0xFF; WZ_H = A; } /* LD (DE),A */ +OP(op,13) { DE++; } /* INC DE */ +OP(op,14) { D = inc(D); } /* INC D */ +OP(op,15) { D = dec(D); } /* DEC D */ +OP(op,16) { D = arg(); } /* LD D,n */ +OP(op,17) { rla(); } /* RLA */ + +OP(op,18) { jr(); } /* JR o */ +OP(op,19) { add16(m_hl, m_de); } /* ADD HL,DE */ +OP(op,1a) { A = rm(DE); WZ = DE + 1; } /* LD A,(DE) */ +OP(op,1b) { DE--; } /* DEC DE */ +OP(op,1c) { E = inc(E); } /* INC E */ +OP(op,1d) { E = dec(E); } /* DEC E */ +OP(op,1e) { E = arg(); } /* LD E,n */ +OP(op,1f) { rra(); } /* RRA */ + +OP(op,20) { jr_cond(!(F & ZF), 0x20); } /* JR NZ,o */ +OP(op,21) { HL = arg16(); } /* LD HL,w */ +OP(op,22) { m_ea = arg16(); wm16(m_ea, m_hl); WZ = m_ea + 1; } /* LD (w),HL */ +OP(op,23) { HL++; } /* INC HL */ +OP(op,24) { H = inc(H); } /* INC H */ +OP(op,25) { H = dec(H); } /* DEC H */ +OP(op,26) { H = arg(); } /* LD H,n */ +OP(op,27) { daa(); } /* DAA */ + +OP(op,28) { jr_cond(F & ZF, 0x28); } /* JR Z,o */ +OP(op,29) { add16(m_hl, m_hl); } /* ADD HL,HL */ +OP(op,2a) { m_ea = arg16(); rm16(m_ea, m_hl); WZ = m_ea+1; } /* LD HL,(w) */ +OP(op,2b) { HL--; } /* DEC HL */ +OP(op,2c) { L = inc(L); } /* INC L */ +OP(op,2d) { L = dec(L); } /* DEC L */ +OP(op,2e) { L = arg(); } /* LD L,n */ +OP(op,2f) { A ^= 0xff; F = (F & (SF | ZF | PF | CF)) | HF | NF | (A & (YF | XF)); } /* CPL */ + +OP(op,30) { jr_cond(!(F & CF), 0x30); } /* JR NC,o */ +OP(op,31) { SP = arg16(); } /* LD SP,w */ +OP(op,32) { m_ea = arg16(); wm(m_ea, A); WZ_L = (m_ea + 1) & 0xFF; WZ_H = A; } /* LD (w),A */ +OP(op,33) { SP++; } /* INC SP */ +OP(op,34) { wm(HL, inc(rm(HL))); } /* INC (HL) */ +OP(op,35) { wm(HL, dec(rm(HL))); } /* DEC (HL) */ +OP(op,36) { wm(HL, arg()); } /* LD (HL),n */ +OP(op,37) { F = (F & (SF | ZF | YF | XF | PF)) | CF | (A & (YF | XF)); } /* SCF */ + +OP(op,38) { jr_cond(F & CF, 0x38); } /* JR C,o */ +OP(op,39) { add16(m_hl, m_sp); } /* ADD HL,SP */ +OP(op,3a) { m_ea = arg16(); A = rm(m_ea); WZ = m_ea + 1; } /* LD A,(w) */ +OP(op,3b) { SP--; } /* DEC SP */ +OP(op,3c) { A = inc(A); } /* INC A */ +OP(op,3d) { A = dec(A); } /* DEC A */ +OP(op,3e) { A = arg(); } /* LD A,n */ +OP(op,3f) { F = ((F&(SF|ZF|YF|XF|PF|CF))|((F&CF)<<4)|(A&(YF|XF)))^CF; } /* CCF */ + +OP(op,40) { } /* LD B,B */ +OP(op,41) { B = C; } /* LD B,C */ +OP(op,42) { B = D; } /* LD B,D */ +OP(op,43) { B = E; } /* LD B,E */ +OP(op,44) { B = H; } /* LD B,H */ +OP(op,45) { B = L; } /* LD B,L */ +OP(op,46) { B = rm(HL); } /* LD B,(HL) */ +OP(op,47) { B = A; } /* LD B,A */ + +OP(op,48) { C = B; } /* LD C,B */ +OP(op,49) { } /* LD C,C */ +OP(op,4a) { C = D; } /* LD C,D */ +OP(op,4b) { C = E; } /* LD C,E */ +OP(op,4c) { C = H; } /* LD C,H */ +OP(op,4d) { C = L; } /* LD C,L */ +OP(op,4e) { C = rm(HL); } /* LD C,(HL) */ +OP(op,4f) { C = A; } /* LD C,A */ + +OP(op,50) { D = B; } /* LD D,B */ +OP(op,51) { D = C; } /* LD D,C */ +OP(op,52) { } /* LD D,D */ +OP(op,53) { D = E; } /* LD D,E */ +OP(op,54) { D = H; } /* LD D,H */ +OP(op,55) { D = L; } /* LD D,L */ +OP(op,56) { D = rm(HL); } /* LD D,(HL) */ +OP(op,57) { D = A; } /* LD D,A */ + +OP(op,58) { E = B; } /* LD E,B */ +OP(op,59) { E = C; } /* LD E,C */ +OP(op,5a) { E = D; } /* LD E,D */ +OP(op,5b) { } /* LD E,E */ +OP(op,5c) { E = H; } /* LD E,H */ +OP(op,5d) { E = L; } /* LD E,L */ +OP(op,5e) { E = rm(HL); } /* LD E,(HL) */ +OP(op,5f) { E = A; } /* LD E,A */ + +OP(op,60) { H = B; } /* LD H,B */ +OP(op,61) { H = C; } /* LD H,C */ +OP(op,62) { H = D; } /* LD H,D */ +OP(op,63) { H = E; } /* LD H,E */ +OP(op,64) { } /* LD H,H */ +OP(op,65) { H = L; } /* LD H,L */ +OP(op,66) { H = rm(HL); } /* LD H,(HL) */ +OP(op,67) { H = A; } /* LD H,A */ + +OP(op,68) { L = B; } /* LD L,B */ +OP(op,69) { L = C; } /* LD L,C */ +OP(op,6a) { L = D; } /* LD L,D */ +OP(op,6b) { L = E; } /* LD L,E */ +OP(op,6c) { L = H; } /* LD L,H */ +OP(op,6d) { } /* LD L,L */ +OP(op,6e) { L = rm(HL); } /* LD L,(HL) */ +OP(op,6f) { L = A; } /* LD L,A */ + +OP(op,70) { wm(HL, B); } /* LD (HL),B */ +OP(op,71) { wm(HL, C); } /* LD (HL),C */ +OP(op,72) { wm(HL, D); } /* LD (HL),D */ +OP(op,73) { wm(HL, E); } /* LD (HL),E */ +OP(op,74) { wm(HL, H); } /* LD (HL),H */ +OP(op,75) { wm(HL, L); } /* LD (HL),L */ +OP(op,76) { halt(); } /* halt */ +OP(op,77) { wm(HL, A); } /* LD (HL),A */ + +OP(op,78) { A = B; } /* LD A,B */ +OP(op,79) { A = C; } /* LD A,C */ +OP(op,7a) { A = D; } /* LD A,D */ +OP(op,7b) { A = E; } /* LD A,E */ +OP(op,7c) { A = H; } /* LD A,H */ +OP(op,7d) { A = L; } /* LD A,L */ +OP(op,7e) { A = rm(HL); } /* LD A,(HL) */ +OP(op,7f) { } /* LD A,A */ + +OP(op,80) { add_a(B); } /* ADD A,B */ +OP(op,81) { add_a(C); } /* ADD A,C */ +OP(op,82) { add_a(D); } /* ADD A,D */ +OP(op,83) { add_a(E); } /* ADD A,E */ +OP(op,84) { add_a(H); } /* ADD A,H */ +OP(op,85) { add_a(L); } /* ADD A,L */ +OP(op,86) { add_a(rm(HL)); } /* ADD A,(HL) */ +OP(op,87) { add_a(A); } /* ADD A,A */ + +OP(op,88) { adc_a(B); } /* ADC A,B */ +OP(op,89) { adc_a(C); } /* ADC A,C */ +OP(op,8a) { adc_a(D); } /* ADC A,D */ +OP(op,8b) { adc_a(E); } /* ADC A,E */ +OP(op,8c) { adc_a(H); } /* ADC A,H */ +OP(op,8d) { adc_a(L); } /* ADC A,L */ +OP(op,8e) { adc_a(rm(HL)); } /* ADC A,(HL) */ +OP(op,8f) { adc_a(A); } /* ADC A,A */ + +OP(op,90) { sub(B); } /* SUB B */ +OP(op,91) { sub(C); } /* SUB C */ +OP(op,92) { sub(D); } /* SUB D */ +OP(op,93) { sub(E); } /* SUB E */ +OP(op,94) { sub(H); } /* SUB H */ +OP(op,95) { sub(L); } /* SUB L */ +OP(op,96) { sub(rm(HL)); } /* SUB (HL) */ +OP(op,97) { sub(A); } /* SUB A */ + +OP(op,98) { sbc_a(B); } /* SBC A,B */ +OP(op,99) { sbc_a(C); } /* SBC A,C */ +OP(op,9a) { sbc_a(D); } /* SBC A,D */ +OP(op,9b) { sbc_a(E); } /* SBC A,E */ +OP(op,9c) { sbc_a(H); } /* SBC A,H */ +OP(op,9d) { sbc_a(L); } /* SBC A,L */ +OP(op,9e) { sbc_a(rm(HL)); } /* SBC A,(HL) */ +OP(op,9f) { sbc_a(A); } /* SBC A,A */ + +OP(op,a0) { and_a(B); } /* AND B */ +OP(op,a1) { and_a(C); } /* AND C */ +OP(op,a2) { and_a(D); } /* AND D */ +OP(op,a3) { and_a(E); } /* AND E */ +OP(op,a4) { and_a(H); } /* AND H */ +OP(op,a5) { and_a(L); } /* AND L */ +OP(op,a6) { and_a(rm(HL)); } /* AND (HL) */ +OP(op,a7) { and_a(A); } /* AND A */ + +OP(op,a8) { xor_a(B); } /* XOR B */ +OP(op,a9) { xor_a(C); } /* XOR C */ +OP(op,aa) { xor_a(D); } /* XOR D */ +OP(op,ab) { xor_a(E); } /* XOR E */ +OP(op,ac) { xor_a(H); } /* XOR H */ +OP(op,ad) { xor_a(L); } /* XOR L */ +OP(op,ae) { xor_a(rm(HL)); } /* XOR (HL) */ +OP(op,af) { xor_a(A); } /* XOR A */ + +OP(op,b0) { or_a(B); } /* OR B */ +OP(op,b1) { or_a(C); } /* OR C */ +OP(op,b2) { or_a(D); } /* OR D */ +OP(op,b3) { or_a(E); } /* OR E */ +OP(op,b4) { or_a(H); } /* OR H */ +OP(op,b5) { or_a(L); } /* OR L */ +OP(op,b6) { or_a(rm(HL)); } /* OR (HL) */ +OP(op,b7) { or_a(A); } /* OR A */ + +OP(op,b8) { cp(B); } /* CP B */ +OP(op,b9) { cp(C); } /* CP C */ +OP(op,ba) { cp(D); } /* CP D */ +OP(op,bb) { cp(E); } /* CP E */ +OP(op,bc) { cp(H); } /* CP H */ +OP(op,bd) { cp(L); } /* CP L */ +OP(op,be) { cp(rm(HL)); } /* CP (HL) */ +OP(op,bf) { cp(A); } /* CP A */ + +OP(op,c0) { ret_cond(!(F & ZF), 0xc0); } /* RET NZ */ +OP(op,c1) { pop(m_bc); } /* POP BC */ +OP(op,c2) { jp_cond(!(F & ZF)); } /* JP NZ,a */ +OP(op,c3) { jp(); } /* JP a */ +OP(op,c4) { call_cond(!(F & ZF), 0xc4); } /* CALL NZ,a */ +OP(op,c5) { push(m_bc); } /* PUSH BC */ +OP(op,c6) { add_a(arg()); } /* ADD A,n */ +OP(op,c7) { rst(0x00); } /* RST 0 */ + +OP(op,c8) { ret_cond(F & ZF, 0xc8); } /* RET Z */ +OP(op,c9) { pop(m_pc); WZ = PCD; } /* RET */ +OP(op,ca) { jp_cond(F & ZF); } /* JP Z,a */ +OP(op,cb) { m_r++; EXEC(cb,rop()); } /* **** CB xx */ +OP(op,cc) { call_cond(F & ZF, 0xcc); } /* CALL Z,a */ +OP(op,cd) { call(); } /* CALL a */ +OP(op,ce) { adc_a(arg()); } /* ADC A,n */ +OP(op,cf) { rst(0x08); } /* RST 1 */ + +OP(op,d0) { ret_cond(!(F & CF), 0xd0); } /* RET NC */ +OP(op,d1) { pop(m_de); } /* POP DE */ +OP(op,d2) { jp_cond(!(F & CF)); } /* JP NC,a */ +OP(op,d3) { unsigned n = arg() | (A << 8); out(n, A); WZ_L = ((n & 0xff) + 1) & 0xff; WZ_H = A; } /* OUT (n),A */ +OP(op,d4) { call_cond(!(F & CF), 0xd4); } /* CALL NC,a */ +OP(op,d5) { push(m_de); } /* PUSH DE */ +OP(op,d6) { sub(arg()); } /* SUB n */ +OP(op,d7) { rst(0x10); } /* RST 2 */ + +OP(op,d8) { ret_cond(F & CF, 0xd8); } /* RET C */ +OP(op,d9) { exx(); } /* EXX */ +OP(op,da) { jp_cond(F & CF); } /* JP C,a */ +OP(op,db) { unsigned n = arg() | (A << 8); A = in(n); WZ = n + 1; } /* IN A,(n) */ +OP(op,dc) { call_cond(F & CF, 0xdc); } /* CALL C,a */ +OP(op,dd) { m_r++; EXEC(dd,rop()); } /* **** DD xx */ +OP(op,de) { sbc_a(arg()); } /* SBC A,n */ +OP(op,df) { rst(0x18); } /* RST 3 */ + +OP(op,e0) { ret_cond(!(F & PF), 0xe0); } /* RET PO */ +OP(op,e1) { pop(m_hl); } /* POP HL */ +OP(op,e2) { jp_cond(!(F & PF)); } /* JP PO,a */ +OP(op,e3) { ex_sp(m_hl); } /* EX HL,(SP) */ +OP(op,e4) { call_cond(!(F & PF), 0xe4); } /* CALL PO,a */ +OP(op,e5) { push(m_hl); } /* PUSH HL */ +OP(op,e6) { and_a(arg()); } /* AND n */ +OP(op,e7) { rst(0x20); } /* RST 4 */ + +OP(op,e8) { ret_cond(F & PF, 0xe8); } /* RET PE */ +OP(op,e9) { PC = HL; } /* JP (HL) */ +OP(op,ea) { jp_cond(F & PF); } /* JP PE,a */ +OP(op,eb) { ex_de_hl(); } /* EX DE,HL */ +OP(op,ec) { call_cond(F & PF, 0xec); } /* CALL PE,a */ +OP(op,ed) { m_r++; EXEC(ed,rop()); } /* **** ED xx */ +OP(op,ee) { xor_a(arg()); } /* XOR n */ +OP(op,ef) { rst(0x28); } /* RST 5 */ + +OP(op,f0) { ret_cond(!(F & SF), 0xf0); } /* RET P */ +OP(op,f1) { pop(m_af); } /* POP AF */ +OP(op,f2) { jp_cond(!(F & SF)); } /* JP P,a */ +OP(op,f3) { m_iff1 = m_iff2 = 0; } /* DI */ +OP(op,f4) { call_cond(!(F & SF), 0xf4); } /* CALL P,a */ +OP(op,f5) { push(m_af); } /* PUSH AF */ +OP(op,f6) { or_a(arg()); } /* OR n */ +OP(op,f7) { rst(0x30); } /* RST 6 */ + +OP(op,f8) { ret_cond(F & SF, 0xf8); } /* RET M */ +OP(op,f9) { SP = HL; } /* LD SP,HL */ +OP(op,fa) { jp_cond(F & SF); } /* JP M,a */ +OP(op,fb) { ei(); } /* EI */ +OP(op,fc) { call_cond(F & SF, 0xfc); } /* CALL M,a */ +OP(op,fd) { m_r++; EXEC(fd,rop()); } /* **** FD xx */ +OP(op,fe) { cp(arg()); } /* CP n */ +OP(op,ff) { rst(0x38); } /* RST 7 */ + + +void z80_device::take_interrupt() +{ + int irq_vector; + + /* there isn't a valid previous program counter */ + PRVPC = -1; + + /* Check if processor was halted */ + leave_halt(); + + /* Clear both interrupt flip flops */ + m_iff1 = m_iff2 = 0; + + /* Daisy chain mode? If so, call the requesting device */ + if (m_daisy.present()) + irq_vector = m_daisy.call_ack_device(); + + /* else call back the cpu interface to retrieve the vector */ + else + irq_vector = m_irq_callback(*this, 0); + + LOG(("Z80 '%s' single int. irq_vector $%02x\n", tag(), irq_vector)); + + /* Interrupt mode 2. Call [i:databyte] */ + if( m_im == 2 ) + { + irq_vector = (irq_vector & 0xff) | (m_i << 8); + push(m_pc); + rm16(irq_vector, m_pc); + LOG(("Z80 '%s' IM2 [$%04x] = $%04x\n", tag(), irq_vector, PCD)); + /* CALL opcode timing + 'interrupt latency' cycles */ + m_icount -= m_cc_op[0xcd] + m_cc_ex[0xff]; + } + else + /* Interrupt mode 1. RST 38h */ + if( m_im == 1 ) + { + LOG(("Z80 '%s' IM1 $0038\n", tag())); + push(m_pc); + PCD = 0x0038; + /* RST $38 + 'interrupt latency' cycles */ + m_icount -= m_cc_op[0xff] + cc_ex[0xff]; + } + else + { + /* Interrupt mode 0. We check for CALL and JP instructions, */ + /* if neither of these were found we assume a 1 byte opcode */ + /* was placed on the databus */ + LOG(("Z80 '%s' IM0 $%04x\n", tag(), irq_vector)); + + /* check for nop */ + if (irq_vector != 0x00) + { + switch (irq_vector & 0xff0000) + { + case 0xcd0000: /* call */ + push(m_pc); + PCD = irq_vector & 0xffff; + /* CALL $xxxx cycles */ + m_icount -= m_cc_op[0xcd]; + break; + case 0xc30000: /* jump */ + PCD = irq_vector & 0xffff; + /* JP $xxxx cycles */ + m_icount -= m_cc_op[0xc3]; + break; + default: /* rst (or other opcodes?) */ + push(m_pc); + PCD = irq_vector & 0x0038; + /* RST $xx cycles */ + m_icount -= m_cc_op[0xff]; + break; + } + } + + /* 'interrupt latency' cycles */ + m_icount -= m_cc_ex[0xff]; + } + WZ=PCD; +} + +void nsc800_device::take_interrupt_nsc800() +{ + /* there isn't a valid previous program counter */ + PRVPC = -1; + + /* Check if processor was halted */ + leave_halt(); + + /* Clear both interrupt flip flops */ + m_iff1 = m_iff2 = 0; + + if (m_nsc800_irq_state[NSC800_RSTA]) + { + push(m_pc); + PCD = 0x003c; + } + else if (m_nsc800_irq_state[NSC800_RSTB]) + { + push(m_pc); + PCD = 0x0034; + } + else if (m_nsc800_irq_state[NSC800_RSTC]) + { + push(m_pc); + PCD = 0x002c; + } + + /* 'interrupt latency' cycles */ + m_icount -= m_cc_op[0xff] + cc_ex[0xff]; + + WZ=PCD; +} + +/**************************************************************************** + * Processor initialization + ****************************************************************************/ +void z80_device::device_start() +{ + if( !tables_initialised ) + { + UINT8 *padd = &SZHVC_add[ 0*256]; + UINT8 *padc = &SZHVC_add[256*256]; + UINT8 *psub = &SZHVC_sub[ 0*256]; + UINT8 *psbc = &SZHVC_sub[256*256]; + for (int oldval = 0; oldval < 256; oldval++) + { + for (int newval = 0; newval < 256; newval++) + { + /* add or adc w/o carry set */ + int val = newval - oldval; + *padd = (newval) ? ((newval & 0x80) ? SF : 0) : ZF; + *padd |= (newval & (YF | XF)); /* undocumented flag bits 5+3 */ + if( (newval & 0x0f) < (oldval & 0x0f) ) *padd |= HF; + if( newval < oldval ) *padd |= CF; + if( (val^oldval^0x80) & (val^newval) & 0x80 ) *padd |= VF; + padd++; + + /* adc with carry set */ + val = newval - oldval - 1; + *padc = (newval) ? ((newval & 0x80) ? SF : 0) : ZF; + *padc |= (newval & (YF | XF)); /* undocumented flag bits 5+3 */ + if( (newval & 0x0f) <= (oldval & 0x0f) ) *padc |= HF; + if( newval <= oldval ) *padc |= CF; + if( (val^oldval^0x80) & (val^newval) & 0x80 ) *padc |= VF; + padc++; + + /* cp, sub or sbc w/o carry set */ + val = oldval - newval; + *psub = NF | ((newval) ? ((newval & 0x80) ? SF : 0) : ZF); + *psub |= (newval & (YF | XF)); /* undocumented flag bits 5+3 */ + if( (newval & 0x0f) > (oldval & 0x0f) ) *psub |= HF; + if( newval > oldval ) *psub |= CF; + if( (val^oldval) & (oldval^newval) & 0x80 ) *psub |= VF; + psub++; + + /* sbc with carry set */ + val = oldval - newval - 1; + *psbc = NF | ((newval) ? ((newval & 0x80) ? SF : 0) : ZF); + *psbc |= (newval & (YF | XF)); /* undocumented flag bits 5+3 */ + if( (newval & 0x0f) >= (oldval & 0x0f) ) *psbc |= HF; + if( newval >= oldval ) *psbc |= CF; + if( (val^oldval) & (oldval^newval) & 0x80 ) *psbc |= VF; + psbc++; + } + } + + for (int i = 0; i < 256; i++) + { + int p = 0; + if( i&0x01 ) ++p; + if( i&0x02 ) ++p; + if( i&0x04 ) ++p; + if( i&0x08 ) ++p; + if( i&0x10 ) ++p; + if( i&0x20 ) ++p; + if( i&0x40 ) ++p; + if( i&0x80 ) ++p; + SZ[i] = i ? i & SF : ZF; + SZ[i] |= (i & (YF | XF)); /* undocumented flag bits 5+3 */ + SZ_BIT[i] = i ? i & SF : ZF | PF; + SZ_BIT[i] |= (i & (YF | XF)); /* undocumented flag bits 5+3 */ + SZP[i] = SZ[i] | ((p & 1) ? 0 : PF); + SZHV_inc[i] = SZ[i]; + if( i == 0x80 ) SZHV_inc[i] |= VF; + if( (i & 0x0f) == 0x00 ) SZHV_inc[i] |= HF; + SZHV_dec[i] = SZ[i] | NF; + if( i == 0x7f ) SZHV_dec[i] |= VF; + if( (i & 0x0f) == 0x0f ) SZHV_dec[i] |= HF; + } + + tables_initialised = true; + } + + save_item(NAME(m_prvpc.w.l)); + save_item(NAME(PC)); + save_item(NAME(SP)); + save_item(NAME(AF)); + save_item(NAME(BC)); + save_item(NAME(DE)); + save_item(NAME(HL)); + save_item(NAME(IX)); + save_item(NAME(IY)); + save_item(NAME(WZ)); + save_item(NAME(m_af2.w.l)); + save_item(NAME(m_bc2.w.l)); + save_item(NAME(m_de2.w.l)); + save_item(NAME(m_hl2.w.l)); + save_item(NAME(m_r)); + save_item(NAME(m_r2)); + save_item(NAME(m_iff1)); + save_item(NAME(m_iff2)); + save_item(NAME(m_halt)); + save_item(NAME(m_im)); + save_item(NAME(m_i)); + save_item(NAME(m_nmi_state)); + save_item(NAME(m_nmi_pending)); + save_item(NAME(m_irq_state)); + save_item(NAME(m_wait_state)); + save_item(NAME(m_busrq_state)); + save_item(NAME(m_after_ei)); + save_item(NAME(m_after_ldair)); + + /* Reset registers to their initial values */ + PRVPC = 0; + PCD = 0; + SPD = 0; + AFD = 0; + BCD = 0; + DED = 0; + HLD = 0; + IXD = 0; + IYD = 0; + WZ = 0; + m_af2.d = 0; + m_bc2.d = 0; + m_de2.d = 0; + m_hl2.d = 0; + m_r = 0; + m_r2 = 0; + m_iff1 = 0; + m_iff2 = 0; + m_halt = 0; + m_im = 0; + m_i = 0; + m_nmi_state = 0; + m_nmi_pending = 0; + m_irq_state = 0; + m_wait_state = 0; + m_busrq_state = 0; + m_after_ei = 0; + m_after_ldair = 0; + m_ea = 0; + + m_program = &space(AS_PROGRAM); + m_decrypted_opcodes = has_space(AS_DECRYPTED_OPCODES) ? &space(AS_DECRYPTED_OPCODES) : m_program; + m_direct = &m_program->direct(); + m_decrypted_opcodes_direct = &m_decrypted_opcodes->direct(); + m_io = &space(AS_IO); + + if (static_config() != NULL) + m_daisy.init(this, (const z80_daisy_config *)static_config()); + m_irq_callback = device_irq_acknowledge_delegate(FUNC(z80_device::standard_irq_callback_member), this); + + IX = IY = 0xffff; /* IX and IY are FFFF after a reset! */ + F = ZF; /* Zero flag is set */ + + /* set up the state table */ + state_add(Z80_PC, "PC", m_pc.w.l); + state_add(STATE_GENPC, "GENPC", m_pc.w.l).noshow(); + state_add(STATE_GENPCBASE, "GENPCBASE", m_prvpc.w.l).noshow(); + state_add(Z80_SP, "SP", SP); + state_add(STATE_GENSP, "GENSP", SP).noshow(); + state_add(STATE_GENFLAGS, "GENFLAGS", F).noshow().formatstr("%8s"); + state_add(Z80_A, "A", A).noshow(); + state_add(Z80_B, "B", B).noshow(); + state_add(Z80_C, "C", C).noshow(); + state_add(Z80_D, "D", D).noshow(); + state_add(Z80_E, "E", E).noshow(); + state_add(Z80_H, "H", H).noshow(); + state_add(Z80_L, "L", L).noshow(); + state_add(Z80_AF, "AF", AF); + state_add(Z80_BC, "BC", BC); + state_add(Z80_DE, "DE", DE); + state_add(Z80_HL, "HL", HL); + state_add(Z80_IX, "IX", IX); + state_add(Z80_IY, "IY", IY); + state_add(Z80_AF2, "AF2", m_af2.w.l); + state_add(Z80_BC2, "BC2", m_bc2.w.l); + state_add(Z80_DE2, "DE2", m_de2.w.l); + state_add(Z80_HL2, "HL2", m_hl2.w.l); + state_add(Z80_WZ, "WZ", WZ); + state_add(Z80_R, "R", m_rtemp).callimport().callexport(); + state_add(Z80_I, "I", m_i); + state_add(Z80_IM, "IM", m_im).mask(0x3); + state_add(Z80_IFF1, "IFF1", m_iff1).mask(0x1); + state_add(Z80_IFF2, "IFF2", m_iff2).mask(0x1); + state_add(Z80_HALT, "HALT", m_halt).mask(0x1); + + // set our instruction counter + m_icountptr = &m_icount; + + /* setup cycle tables */ + m_cc_op = cc_op; + m_cc_cb = cc_cb; + m_cc_ed = cc_ed; + m_cc_xy = cc_xy; + m_cc_xycb = cc_xycb; + m_cc_ex = cc_ex; +} + +void nsc800_device::device_start() +{ + z80_device::device_start(); + save_item(NAME(m_nsc800_irq_state)); +} + +/**************************************************************************** + * Do a reset + ****************************************************************************/ +void z80_device::device_reset() +{ + PC = 0x0000; + m_i = 0; + m_r = 0; + m_r2 = 0; + m_nmi_pending = FALSE; + m_after_ei = FALSE; + m_after_ldair = FALSE; + m_iff1 = 0; + m_iff2 = 0; + + m_daisy.reset(); + + WZ=PCD; +} + +void nsc800_device::device_reset() +{ + z80_device::device_reset(); + memset(m_nsc800_irq_state, 0, sizeof(m_nsc800_irq_state)); +} + +/**************************************************************************** + * Execute 'cycles' T-states. Return number of T-states really executed + ****************************************************************************/ +void z80_device::execute_run() +{ + /* check for NMIs on the way in; they can only be set externally */ + /* via timers, and can't be dynamically enabled, so it is safe */ + /* to just check here */ + if (m_nmi_pending) + { + LOG(("Z80 '%s' take NMI\n", tag())); + PRVPC = -1; /* there isn't a valid previous program counter */ + leave_halt(); /* Check if processor was halted */ + +#if HAS_LDAIR_QUIRK + /* reset parity flag after LD A,I or LD A,R */ + if (m_after_ldair) F &= ~PF; +#endif + m_after_ldair = FALSE; + + m_iff1 = 0; + push(m_pc); + PCD = 0x0066; + WZ=PCD; + m_icount -= 11; + m_nmi_pending = FALSE; + } + + do + { + /* check for IRQs before each instruction */ + if (m_irq_state != CLEAR_LINE && m_iff1 && !m_after_ei) + { +#if HAS_LDAIR_QUIRK + /* reset parity flag after LD A,I or LD A,R */ + if (m_after_ldair) F &= ~PF; +#endif + take_interrupt(); + } + m_after_ei = FALSE; + m_after_ldair = FALSE; + + PRVPC = PCD; + debugger_instruction_hook(this, PCD); + m_r++; + EXEC(op,rop()); + } while (m_icount > 0); +} + +void nsc800_device::execute_run() +{ + /* check for NMIs on the way in; they can only be set externally */ + /* via timers, and can't be dynamically enabled, so it is safe */ + /* to just check here */ + if (m_nmi_pending) + { + LOG(("Z80 '%s' take NMI\n", tag())); + PRVPC = -1; /* there isn't a valid previous program counter */ + leave_halt(); /* Check if processor was halted */ + + m_iff1 = 0; + push(m_pc); + PCD = 0x0066; + WZ=PCD; + m_icount -= 11; + m_nmi_pending = FALSE; + } + + do + { + /* check for NSC800 IRQs line RSTA, RSTB, RSTC */ + if ((m_nsc800_irq_state[NSC800_RSTA] != CLEAR_LINE || m_nsc800_irq_state[NSC800_RSTB] != CLEAR_LINE || m_nsc800_irq_state[NSC800_RSTC] != CLEAR_LINE) && m_iff1 && !m_after_ei) + take_interrupt_nsc800(); + + /* check for IRQs before each instruction */ + if (m_irq_state != CLEAR_LINE && m_iff1 && !m_after_ei) + take_interrupt(); + + m_after_ei = FALSE; + + PRVPC = PCD; + debugger_instruction_hook(this, PCD); + m_r++; + EXEC(op,rop()); + } while (m_icount > 0); +} + +void z80_device::execute_set_input(int inputnum, int state) +{ + switch (inputnum) + { + case Z80_INPUT_LINE_BUSRQ: + m_busrq_state = state; + break; + + case INPUT_LINE_NMI: + /* mark an NMI pending on the rising edge */ + if (m_nmi_state == CLEAR_LINE && state != CLEAR_LINE) + m_nmi_pending = TRUE; + m_nmi_state = state; + break; + + case INPUT_LINE_IRQ0: + /* update the IRQ state via the daisy chain */ + m_irq_state = state; + if (m_daisy.present()) + m_irq_state = ( m_daisy.update_irq_state() == ASSERT_LINE ) ? ASSERT_LINE : m_irq_state; + + /* the main execute loop will take the interrupt */ + break; + + case Z80_INPUT_LINE_WAIT: + m_wait_state = state; + break; + } +} + +void nsc800_device::execute_set_input(int inputnum, int state) +{ + switch (inputnum) + { + case Z80_INPUT_LINE_BUSRQ: + m_busrq_state = state; + break; + + case INPUT_LINE_NMI: + /* mark an NMI pending on the rising edge */ + if (m_nmi_state == CLEAR_LINE && state != CLEAR_LINE) + m_nmi_pending = TRUE; + m_nmi_state = state; + break; + + case NSC800_RSTA: + m_nsc800_irq_state[NSC800_RSTA] = state; + break; + + case NSC800_RSTB: + m_nsc800_irq_state[NSC800_RSTB] = state; + break; + + case NSC800_RSTC: + m_nsc800_irq_state[NSC800_RSTC] = state; + break; + + case INPUT_LINE_IRQ0: + /* update the IRQ state via the daisy chain */ + m_irq_state = state; + if (m_daisy.present()) + m_irq_state = m_daisy.update_irq_state(); + + /* the main execute loop will take the interrupt */ + break; + + case Z80_INPUT_LINE_WAIT: + m_wait_state = state; + break; + } +} + + + +/************************************************************************** + * STATE IMPORT/EXPORT + **************************************************************************/ + +void z80_device::state_import( const device_state_entry &entry ) +{ + switch (entry.index()) + { + case Z80_R: + m_r = m_rtemp & 0x7f; + m_r2 = m_rtemp & 0x80; + break; + + default: + fatalerror("CPU_IMPORT_STATE() called for unexpected value\n"); + } +} + + +void z80_device::state_export( const device_state_entry &entry ) +{ + switch (entry.index()) + { + case Z80_R: + m_rtemp = (m_r & 0x7f) | (m_r2 & 0x80); + break; + + default: + fatalerror("CPU_EXPORT_STATE() called for unexpected value\n"); + } +} + +void z80_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + switch (entry.index()) + { + case STATE_GENFLAGS: + strprintf(str, "%c%c%c%c%c%c%c%c", + F & 0x80 ? 'S':'.', + F & 0x40 ? 'Z':'.', + F & 0x20 ? 'Y':'.', + F & 0x10 ? 'H':'.', + F & 0x08 ? 'X':'.', + F & 0x04 ? 'P':'.', + F & 0x02 ? 'N':'.', + F & 0x01 ? 'C':'.'); + break; + } +} + +//------------------------------------------------- +// disasm_disassemble - call the disassembly +// helper function +//------------------------------------------------- + +offs_t z80_device::disasm_disassemble( char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options ) +{ + extern CPU_DISASSEMBLE( z80 ); + return CPU_DISASSEMBLE_NAME(z80)(this, buffer, pc, oprom, opram, options); +} + + +/************************************************************************** + * Generic set_info + **************************************************************************/ + +void z80_device::z80_set_cycle_tables(const UINT8 *op, const UINT8 *cb, const UINT8 *ed, const UINT8 *xy, const UINT8 *xycb, const UINT8 *ex) +{ + m_cc_op = (op != NULL) ? op : cc_op; + m_cc_cb = (cb != NULL) ? cb : cc_cb; + m_cc_ed = (ed != NULL) ? ed : cc_ed; + m_cc_xy = (xy != NULL) ? xy : cc_xy; + m_cc_xycb = (xycb != NULL) ? xycb : cc_xycb; + m_cc_ex = (ex != NULL) ? ex : cc_ex; +} + + +z80_device::z80_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + cpu_device(mconfig, Z80, "Z80", tag, owner, clock, "z80", __FILE__), + m_program_config("program", ENDIANNESS_LITTLE, 8, 16, 0), + m_decrypted_opcodes_config("decrypted_opcodes", ENDIANNESS_LITTLE, 8, 16, 0), + m_io_config("io", ENDIANNESS_LITTLE, 8, 16, 0) +{ +} + +z80_device::z80_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + cpu_device(mconfig, type, name, tag, owner, clock, shortname, source), + m_program_config("program", ENDIANNESS_LITTLE, 8, 16, 0), + m_decrypted_opcodes_config("decrypted_opcodes", ENDIANNESS_LITTLE, 8, 16, 0), + m_io_config("io", ENDIANNESS_LITTLE, 8, 16, 0) +{ +} + +const address_space_config *z80_device::memory_space_config(address_spacenum spacenum) const +{ + switch(spacenum) + { + case AS_PROGRAM: return &m_program_config; + case AS_IO: return &m_io_config; + case AS_DECRYPTED_OPCODES: return has_configured_map(AS_DECRYPTED_OPCODES) ? &m_decrypted_opcodes_config : NULL; + default: return NULL; + } +} + +const device_type Z80 = &device_creator; + +nsc800_device::nsc800_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : z80_device(mconfig, NSC800, "NSC800", tag, owner, clock, "nsc800", __FILE__) +{ +} + +const device_type NSC800 = &device_creator; + + + +WRITE_LINE_MEMBER( z80_device::irq_line ) +{ + set_input_line( INPUT_LINE_IRQ0, state ); +} diff --git a/src/devices/cpu/z80/z80.h b/src/devices/cpu/z80/z80.h new file mode 100644 index 00000000000..e424c4f9937 --- /dev/null +++ b/src/devices/cpu/z80/z80.h @@ -0,0 +1,310 @@ +// license:BSD-3-Clause +// copyright-holders:Juergen Buchmueller +#pragma once + +#ifndef __Z80_H__ +#define __Z80_H__ + +#include "z80daisy.h" + +enum +{ + NSC800_RSTA = INPUT_LINE_IRQ0 + 1, + NSC800_RSTB, + NSC800_RSTC, + Z80_INPUT_LINE_WAIT, + Z80_INPUT_LINE_BUSRQ +}; + +enum +{ + Z80_PC, Z80_SP, + Z80_A, Z80_B, Z80_C, Z80_D, Z80_E, Z80_H, Z80_L, + Z80_AF, Z80_BC, Z80_DE, Z80_HL, + Z80_IX, Z80_IY, Z80_AF2, Z80_BC2, Z80_DE2, Z80_HL2, + Z80_R, Z80_I, Z80_IM, Z80_IFF1, Z80_IFF2, Z80_HALT, + Z80_DC0, Z80_DC1, Z80_DC2, Z80_DC3, Z80_WZ, + + Z80_GENPC = STATE_GENPC, + Z80_GENSP = STATE_GENSP, + Z80_GENPCBASE = STATE_GENPCBASE +}; + +class z80_device : public cpu_device +{ +public: + z80_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + DECLARE_WRITE_LINE_MEMBER( irq_line ); + + void z80_set_cycle_tables(const UINT8 *op, const UINT8 *cb, const UINT8 *ed, const UINT8 *xy, const UINT8 *xycb, const UINT8 *ex); + +protected: + z80_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_execute_interface overrides + virtual UINT32 execute_min_cycles() const { return 2; } + virtual UINT32 execute_max_cycles() const { return 16; } + virtual UINT32 execute_input_lines() const { return 4; } + virtual UINT32 execute_default_irq_vector() const { return 0xff; } + virtual void execute_run(); + virtual void execute_set_input(int inputnum, int state); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const; + + // device_state_interface overrides + virtual void state_import(const device_state_entry &entry); + virtual void state_export(const device_state_entry &entry); + virtual void state_string_export(const device_state_entry &entry, std::string &str); + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const { return 1; } + virtual UINT32 disasm_max_opcode_bytes() const { return 4; } + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + +#undef PROTOTYPES +#define PROTOTYPES(prefix) \ + void prefix##_00(); void prefix##_01(); void prefix##_02(); void prefix##_03(); \ + void prefix##_04(); void prefix##_05(); void prefix##_06(); void prefix##_07(); \ + void prefix##_08(); void prefix##_09(); void prefix##_0a(); void prefix##_0b(); \ + void prefix##_0c(); void prefix##_0d(); void prefix##_0e(); void prefix##_0f(); \ + void prefix##_10(); void prefix##_11(); void prefix##_12(); void prefix##_13(); \ + void prefix##_14(); void prefix##_15(); void prefix##_16(); void prefix##_17(); \ + void prefix##_18(); void prefix##_19(); void prefix##_1a(); void prefix##_1b(); \ + void prefix##_1c(); void prefix##_1d(); void prefix##_1e(); void prefix##_1f(); \ + void prefix##_20(); void prefix##_21(); void prefix##_22(); void prefix##_23(); \ + void prefix##_24(); void prefix##_25(); void prefix##_26(); void prefix##_27(); \ + void prefix##_28(); void prefix##_29(); void prefix##_2a(); void prefix##_2b(); \ + void prefix##_2c(); void prefix##_2d(); void prefix##_2e(); void prefix##_2f(); \ + void prefix##_30(); void prefix##_31(); void prefix##_32(); void prefix##_33(); \ + void prefix##_34(); void prefix##_35(); void prefix##_36(); void prefix##_37(); \ + void prefix##_38(); void prefix##_39(); void prefix##_3a(); void prefix##_3b(); \ + void prefix##_3c(); void prefix##_3d(); void prefix##_3e(); void prefix##_3f(); \ + void prefix##_40(); void prefix##_41(); void prefix##_42(); void prefix##_43(); \ + void prefix##_44(); void prefix##_45(); void prefix##_46(); void prefix##_47(); \ + void prefix##_48(); void prefix##_49(); void prefix##_4a(); void prefix##_4b(); \ + void prefix##_4c(); void prefix##_4d(); void prefix##_4e(); void prefix##_4f(); \ + void prefix##_50(); void prefix##_51(); void prefix##_52(); void prefix##_53(); \ + void prefix##_54(); void prefix##_55(); void prefix##_56(); void prefix##_57(); \ + void prefix##_58(); void prefix##_59(); void prefix##_5a(); void prefix##_5b(); \ + void prefix##_5c(); void prefix##_5d(); void prefix##_5e(); void prefix##_5f(); \ + void prefix##_60(); void prefix##_61(); void prefix##_62(); void prefix##_63(); \ + void prefix##_64(); void prefix##_65(); void prefix##_66(); void prefix##_67(); \ + void prefix##_68(); void prefix##_69(); void prefix##_6a(); void prefix##_6b(); \ + void prefix##_6c(); void prefix##_6d(); void prefix##_6e(); void prefix##_6f(); \ + void prefix##_70(); void prefix##_71(); void prefix##_72(); void prefix##_73(); \ + void prefix##_74(); void prefix##_75(); void prefix##_76(); void prefix##_77(); \ + void prefix##_78(); void prefix##_79(); void prefix##_7a(); void prefix##_7b(); \ + void prefix##_7c(); void prefix##_7d(); void prefix##_7e(); void prefix##_7f(); \ + void prefix##_80(); void prefix##_81(); void prefix##_82(); void prefix##_83(); \ + void prefix##_84(); void prefix##_85(); void prefix##_86(); void prefix##_87(); \ + void prefix##_88(); void prefix##_89(); void prefix##_8a(); void prefix##_8b(); \ + void prefix##_8c(); void prefix##_8d(); void prefix##_8e(); void prefix##_8f(); \ + void prefix##_90(); void prefix##_91(); void prefix##_92(); void prefix##_93(); \ + void prefix##_94(); void prefix##_95(); void prefix##_96(); void prefix##_97(); \ + void prefix##_98(); void prefix##_99(); void prefix##_9a(); void prefix##_9b(); \ + void prefix##_9c(); void prefix##_9d(); void prefix##_9e(); void prefix##_9f(); \ + void prefix##_a0(); void prefix##_a1(); void prefix##_a2(); void prefix##_a3(); \ + void prefix##_a4(); void prefix##_a5(); void prefix##_a6(); void prefix##_a7(); \ + void prefix##_a8(); void prefix##_a9(); void prefix##_aa(); void prefix##_ab(); \ + void prefix##_ac(); void prefix##_ad(); void prefix##_ae(); void prefix##_af(); \ + void prefix##_b0(); void prefix##_b1(); void prefix##_b2(); void prefix##_b3(); \ + void prefix##_b4(); void prefix##_b5(); void prefix##_b6(); void prefix##_b7(); \ + void prefix##_b8(); void prefix##_b9(); void prefix##_ba(); void prefix##_bb(); \ + void prefix##_bc(); void prefix##_bd(); void prefix##_be(); void prefix##_bf(); \ + void prefix##_c0(); void prefix##_c1(); void prefix##_c2(); void prefix##_c3(); \ + void prefix##_c4(); void prefix##_c5(); void prefix##_c6(); void prefix##_c7(); \ + void prefix##_c8(); void prefix##_c9(); void prefix##_ca(); void prefix##_cb(); \ + void prefix##_cc(); void prefix##_cd(); void prefix##_ce(); void prefix##_cf(); \ + void prefix##_d0(); void prefix##_d1(); void prefix##_d2(); void prefix##_d3(); \ + void prefix##_d4(); void prefix##_d5(); void prefix##_d6(); void prefix##_d7(); \ + void prefix##_d8(); void prefix##_d9(); void prefix##_da(); void prefix##_db(); \ + void prefix##_dc(); void prefix##_dd(); void prefix##_de(); void prefix##_df(); \ + void prefix##_e0(); void prefix##_e1(); void prefix##_e2(); void prefix##_e3(); \ + void prefix##_e4(); void prefix##_e5(); void prefix##_e6(); void prefix##_e7(); \ + void prefix##_e8(); void prefix##_e9(); void prefix##_ea(); void prefix##_eb(); \ + void prefix##_ec(); void prefix##_ed(); void prefix##_ee(); void prefix##_ef(); \ + void prefix##_f0(); void prefix##_f1(); void prefix##_f2(); void prefix##_f3(); \ + void prefix##_f4(); void prefix##_f5(); void prefix##_f6(); void prefix##_f7(); \ + void prefix##_f8(); void prefix##_f9(); void prefix##_fa(); void prefix##_fb(); \ + void prefix##_fc(); void prefix##_fd(); void prefix##_fe(); void prefix##_ff(); + + void illegal_1(); + void illegal_2(); + + PROTOTYPES(op) + PROTOTYPES(cb) + PROTOTYPES(dd) + PROTOTYPES(ed) + PROTOTYPES(fd) + PROTOTYPES(xycb) + + void halt(); + void leave_halt(); + UINT8 in(UINT16 port); + void out(UINT16 port, UINT8 value); + UINT8 rm(UINT16 addr); + void rm16(UINT16 addr, PAIR &r); + void wm(UINT16 addr, UINT8 value); + void wm16(UINT16 addr, PAIR &r); + UINT8 rop(); + UINT8 arg(); + UINT16 arg16(); + void eax(); + void eay(); + void pop(PAIR &r); + void push(PAIR &r); + void jp(void); + void jp_cond(bool cond); + void jr(); + void jr_cond(bool cond, UINT8 opcode); + void call(); + void call_cond(bool cond, UINT8 opcode); + void ret_cond(bool cond, UINT8 opcode); + void retn(); + void reti(); + void ld_r_a(); + void ld_a_r(); + void ld_i_a(); + void ld_a_i(); + void rst(UINT16 addr); + UINT8 inc(UINT8 value); + UINT8 dec(UINT8 value); + void rlca(); + void rrca(); + void rla(); + void rra(); + void rrd(); + void rld(); + void add_a(UINT8 value); + void adc_a(UINT8 value); + void sub(UINT8 value); + void sbc_a(UINT8 value); + void neg(); + void daa(); + void and_a(UINT8 value); + void or_a(UINT8 value); + void xor_a(UINT8 value); + void cp(UINT8 value); + void ex_af(); + void ex_de_hl(); + void exx(); + void ex_sp(PAIR &r); + void add16(PAIR &dr, PAIR &sr); + void adc_hl(PAIR &r); + void sbc_hl(PAIR &r); + UINT8 rlc(UINT8 value); + UINT8 rrc(UINT8 value); + UINT8 rl(UINT8 value); + UINT8 rr(UINT8 value); + UINT8 sla(UINT8 value); + UINT8 sra(UINT8 value); + UINT8 sll(UINT8 value); + UINT8 srl(UINT8 value); + void bit(int bit, UINT8 value); + void bit_hl(int bit, UINT8 value); + void bit_xy(int bit, UINT8 value); + UINT8 res(int bit, UINT8 value); + UINT8 set(int bit, UINT8 value); + void ldi(); + void cpi(); + void ini(); + void outi(); + void ldd(); + void cpd(); + void ind(); + void outd(); + void ldir(); + void cpir(); + void inir(); + void otir(); + void lddr(); + void cpdr(); + void indr(); + void otdr(); + void ei(); + + void take_interrupt(); + + // address spaces + const address_space_config m_program_config; + const address_space_config m_decrypted_opcodes_config; + const address_space_config m_io_config; + address_space *m_program; + address_space *m_decrypted_opcodes; + address_space *m_io; + direct_read_data *m_direct; + direct_read_data *m_decrypted_opcodes_direct; + + PAIR m_prvpc; + PAIR m_pc; + PAIR m_sp; + PAIR m_af; + PAIR m_bc; + PAIR m_de; + PAIR m_hl; + PAIR m_ix; + PAIR m_iy; + PAIR m_wz; + PAIR m_af2; + PAIR m_bc2; + PAIR m_de2; + PAIR m_hl2; + UINT8 m_r; + UINT8 m_r2; + UINT8 m_iff1; + UINT8 m_iff2; + UINT8 m_halt; + UINT8 m_im; + UINT8 m_i; + UINT8 m_nmi_state; /* nmi line state */ + UINT8 m_nmi_pending; /* nmi pending */ + UINT8 m_irq_state; /* irq line state */ + int m_wait_state; // wait line state + int m_busrq_state; // bus request line state + UINT8 m_after_ei; /* are we in the EI shadow? */ + UINT8 m_after_ldair; /* same, but for LD A,I or LD A,R */ + UINT32 m_ea; + device_irq_acknowledge_delegate m_irq_callback; + + int m_icount; + z80_daisy_chain m_daisy; + UINT8 m_rtemp; + const UINT8 * m_cc_op; + const UINT8 * m_cc_cb; + const UINT8 * m_cc_ed; + const UINT8 * m_cc_xy; + const UINT8 * m_cc_xycb; + const UINT8 * m_cc_ex; +}; + +extern const device_type Z80; + +class nsc800_device : public z80_device +{ +public: + nsc800_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_execute_interface overrides + virtual UINT32 execute_input_lines() const { return 7; } + virtual void execute_run(); + virtual void execute_set_input(int inputnum, int state); + + void take_interrupt_nsc800(); + UINT8 m_nsc800_irq_state[4]; /* state of NSC800 restart interrupts A, B, C */ +}; + +extern const device_type NSC800; + + +#endif /* __Z80_H__ */ diff --git a/src/devices/cpu/z80/z80daisy.c b/src/devices/cpu/z80/z80daisy.c new file mode 100644 index 00000000000..c1b0a5454c3 --- /dev/null +++ b/src/devices/cpu/z80/z80daisy.c @@ -0,0 +1,179 @@ +// license:BSD-3-Clause +// copyright-holders:Juergen Buchmueller +/*************************************************************************** + + z80daisy.c + + Z80/180 daisy chaining support functions. + +***************************************************************************/ + +#include "emu.h" +#include "z80daisy.h" + + +//************************************************************************** +// DEVICE Z80 DAISY INTERFACE +//************************************************************************** + +//------------------------------------------------- +// device_z80daisy_interface - constructor +//------------------------------------------------- + +device_z80daisy_interface::device_z80daisy_interface(const machine_config &mconfig, device_t &device) + : device_interface(device, "z80daisy") +{ +} + + +//------------------------------------------------- +// ~device_z80daisy_interface - destructor +//------------------------------------------------- + +device_z80daisy_interface::~device_z80daisy_interface() +{ +} + + + +//************************************************************************** +// Z80 DAISY CHAIN +//************************************************************************** + +//------------------------------------------------- +// z80_daisy_chain - constructor +//------------------------------------------------- + +z80_daisy_chain::z80_daisy_chain() + : m_daisy_list(NULL) +{ +} + + +//------------------------------------------------- +// init - allocate the daisy chain based on the +// provided configuration +//------------------------------------------------- + +void z80_daisy_chain::init(device_t *cpudevice, const z80_daisy_config *daisy) +{ + // create a linked list of devices + daisy_entry **tailptr = &m_daisy_list; + for ( ; daisy->devname != NULL; daisy++) + { + // find the device + device_t *target; + if ((target = cpudevice->subdevice(daisy->devname)) == NULL) + { + if ((target = cpudevice->siblingdevice(daisy->devname)) == NULL) + fatalerror("Unable to locate device '%s'\n", daisy->devname); + } + + // make sure it has an interface + device_z80daisy_interface *intf; + if (!target->interface(intf)) + fatalerror("Device '%s' does not implement the z80daisy interface!\n", daisy->devname); + + // append to the end, or overwrite existing entry + daisy_entry *next = (*tailptr) ? (*tailptr)->m_next : NULL; + if (*tailptr != NULL) + auto_free(cpudevice->machine(), *tailptr); + *tailptr = auto_alloc(cpudevice->machine(), daisy_entry(target)); + (*tailptr)->m_next = next; + tailptr = &(*tailptr)->m_next; + } +} + + +//------------------------------------------------- +// reset - send a reset signal to all chained +// devices +//------------------------------------------------- + +void z80_daisy_chain::reset() +{ + // loop over all devices and call their reset function + for (daisy_entry *daisy = m_daisy_list; daisy != NULL; daisy = daisy->m_next) + daisy->m_device->reset(); +} + + +//------------------------------------------------- +// update_irq_state - update the IRQ state and +// return assert/clear based on the state +//------------------------------------------------- + +int z80_daisy_chain::update_irq_state() +{ + // loop over all devices; dev[0] is highest priority + for (daisy_entry *daisy = m_daisy_list; daisy != NULL; daisy = daisy->m_next) + { + // if this device is asserting the INT line, that's the one we want + int state = daisy->m_interface->z80daisy_irq_state(); + if (state & Z80_DAISY_INT) + return ASSERT_LINE; + + // if this device is asserting the IEO line, it blocks everyone else + if (state & Z80_DAISY_IEO) + return CLEAR_LINE; + } + return CLEAR_LINE; +} + + +//------------------------------------------------- +// call_ack_device - acknowledge an interrupt +// from a chained device and return the vector +//------------------------------------------------- + +int z80_daisy_chain::call_ack_device() +{ + int vector = 0; + + // loop over all devices; dev[0] is the highest priority + for (daisy_entry *daisy = m_daisy_list; daisy != NULL; daisy = daisy->m_next) + { + // if this device is asserting the INT line, that's the one we want + int state = daisy->m_interface->z80daisy_irq_state(); + vector = daisy->m_interface->z80daisy_irq_ack(); + if (state & Z80_DAISY_INT) + return vector; + } + //logerror("z80daisy_call_ack_device: failed to find an device to ack!\n"); + return vector; +} + + +//------------------------------------------------- +// call_reti_device - signal a RETI operator to +// the chain +//------------------------------------------------- + +void z80_daisy_chain::call_reti_device() +{ + // loop over all devices; dev[0] is the highest priority + for (daisy_entry *daisy = m_daisy_list; daisy != NULL; daisy = daisy->m_next) + { + // if this device is asserting the IEO line, that's the one we want + int state = daisy->m_interface->z80daisy_irq_state(); + if (state & Z80_DAISY_IEO) + { + daisy->m_interface->z80daisy_irq_reti(); + return; + } + } + //logerror("z80daisy_call_reti_device: failed to find an device to reti!\n"); +} + + +//------------------------------------------------- +// daisy_entry - constructor +//------------------------------------------------- + +z80_daisy_chain::daisy_entry::daisy_entry(device_t *device) + : m_next(NULL), + m_device(device), + m_interface(NULL) +{ + device->interface(m_interface); +} diff --git a/src/devices/cpu/z80/z80daisy.h b/src/devices/cpu/z80/z80daisy.h new file mode 100644 index 00000000000..b4651649a20 --- /dev/null +++ b/src/devices/cpu/z80/z80daisy.h @@ -0,0 +1,89 @@ +// license:BSD-3-Clause +// copyright-holders:Juergen Buchmueller +/*************************************************************************** + + z80daisy.h + + Z80/180 daisy chaining support functions. + +***************************************************************************/ + +#pragma once + +#ifndef __Z80DAISY_H__ +#define __Z80DAISY_H__ + + + +//************************************************************************** +// CONSTANTS +//************************************************************************** + +// these constants are returned from the irq_state function +const UINT8 Z80_DAISY_INT = 0x01; // interrupt request mask +const UINT8 Z80_DAISY_IEO = 0x02; // interrupt disable mask (IEO) + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + + +// ======================> z80_daisy_config + +struct z80_daisy_config +{ + const char * devname; // name of the device +}; + + + +// ======================> device_z80daisy_interface + +class device_z80daisy_interface : public device_interface +{ +public: + // construction/destruction + device_z80daisy_interface(const machine_config &mconfig, device_t &device); + virtual ~device_z80daisy_interface(); + + // required operation overrides + virtual int z80daisy_irq_state() = 0; + virtual int z80daisy_irq_ack() = 0; + virtual void z80daisy_irq_reti() = 0; +}; + + + +// ======================> z80_daisy_chain + +class z80_daisy_chain +{ +public: + z80_daisy_chain(); + void init(device_t *cpudevice, const z80_daisy_config *daisy); + + bool present() const { return (m_daisy_list != NULL); } + + void reset(); + int update_irq_state(); + int call_ack_device(); + void call_reti_device(); + +protected: + class daisy_entry + { + public: + daisy_entry(device_t *device); + + daisy_entry * m_next; // next device + device_t * m_device; // associated device + device_z80daisy_interface * m_interface; // associated device's daisy interface + }; + + daisy_entry * m_daisy_list; // head of the daisy chain +}; + + +#endif diff --git a/src/devices/cpu/z80/z80dasm.c b/src/devices/cpu/z80/z80dasm.c new file mode 100644 index 00000000000..ebb965db26e --- /dev/null +++ b/src/devices/cpu/z80/z80dasm.c @@ -0,0 +1,532 @@ +// license:BSD-3-Clause +// copyright-holders:Juergen Buchmueller +/***************************************************************************** + * + * z80dasm.c + * Portable Z80 disassembler + * + *****************************************************************************/ + +#include "emu.h" +#include "debugger.h" +#include "z80.h" + +enum e_mnemonics +{ + zADC ,zADD ,zAND ,zBIT ,zCALL ,zCCF ,zCP ,zCPD , + zCPDR ,zCPI ,zCPIR ,zCPL ,zDAA ,zDB ,zDEC ,zDI , + zDJNZ ,zEI ,zEX ,zEXX ,zHLT ,zIM ,zIN ,zINC , + zIND ,zINDR ,zINI ,zINIR ,zJP ,zJR ,zLD ,zLDD , + zLDDR ,zLDI ,zLDIR ,zNEG ,zNOP ,zOR ,zOTDR ,zOTIR , + zOUT ,zOUTD ,zOUTI ,zPOP ,zPUSH ,zRES ,zRET ,zRETI , + zRETN ,zRL ,zRLA ,zRLC ,zRLCA ,zRLD ,zRR ,zRRA , + zRRC ,zRRCA ,zRRD ,zRST ,zSBC ,zSCF ,zSET ,zSLA , + zSLL ,zSRA ,zSRL ,zSUB ,zXOR +}; + +static const char *const s_mnemonic[] = +{ + "adc" ,"add" ,"and" ,"bit" ,"call","ccf" ,"cp" ,"cpd" , + "cpdr","cpi" ,"cpir","cpl" ,"daa" ,"db" ,"dec" ,"di" , + "djnz","ei" ,"ex" ,"exx" ,"halt","im" ,"in" ,"inc" , + "ind" ,"indr","ini" ,"inir","jp" ,"jr" ,"ld" ,"ldd" , + "lddr","ldi" ,"ldir","neg" ,"nop" ,"or" ,"otdr","otir", + "out" ,"outd","outi","pop" ,"push","res" ,"ret" ,"reti", + "retn","rl" ,"rla" ,"rlc" ,"rlca","rld" ,"rr" ,"rra" , + "rrc" ,"rrca","rrd" ,"rst" ,"sbc" ,"scf" ,"set" ,"sla" , + "sll" ,"sra" ,"srl" ,"sub" ,"xor " +}; + +#define _OVER DASMFLAG_STEP_OVER +#define _OUT DASMFLAG_STEP_OUT + +static const UINT32 s_flags[] = +{ + 0 ,0 ,0 ,0 ,_OVER,0 ,0 ,0 , + _OVER,0 ,_OVER,0 ,0 ,0 ,0 ,0 , + _OVER,0 ,0 ,0 ,_OVER,0 ,0 ,0 , + 0 ,_OVER,0 ,_OVER,0 ,0 ,0 ,0 , + _OVER,0 ,_OVER,0 ,0 ,0 ,_OVER,_OVER, + 0 ,0 ,0 ,0 ,0 ,0 ,_OUT ,_OUT , + _OUT ,0 ,0 ,0 ,0 ,0 ,0 ,0 , + 0 ,0 ,0 ,_OVER,0 ,0 ,0 ,0 , + 0 ,0 ,0 ,0 ,0 +}; + +struct z80dasm +{ + UINT8 mnemonic; + const char *arguments; +}; + +static const z80dasm mnemonic_xx_cb[256] = +{ + {zRLC,"b=Y"}, {zRLC,"c=Y"}, {zRLC,"d=Y"}, {zRLC,"e=Y"}, + {zRLC,"h=Y"}, {zRLC,"l=Y"}, {zRLC,"Y"}, {zRLC,"a=Y"}, + {zRRC,"b=Y"}, {zRRC,"c=Y"}, {zRRC,"d=Y"}, {zRRC,"e=Y"}, + {zRRC,"h=Y"}, {zRRC,"l=Y"}, {zRRC,"Y"}, {zRRC,"a=Y"}, + {zRL,"b=Y"}, {zRL,"c=Y"}, {zRL,"d=Y"}, {zRL,"e=Y"}, + {zRL,"h=Y"}, {zRL,"l=Y"}, {zRL,"Y"}, {zRL,"a=Y"}, + {zRR,"b=Y"}, {zRR,"c=Y"}, {zRR,"d=Y"}, {zRR,"e=Y"}, + {zRR,"h=Y"}, {zRR,"l=Y"}, {zRR,"Y"}, {zRR,"a=Y"}, + {zSLA,"b=Y"}, {zSLA,"c=Y"}, {zSLA,"d=Y"}, {zSLA,"e=Y"}, + {zSLA,"h=Y"}, {zSLA,"l=Y"}, {zSLA,"Y"}, {zSLA,"a=Y"}, + {zSRA,"b=Y"}, {zSRA,"c=Y"}, {zSRA,"d=Y"}, {zSRA,"e=Y"}, + {zSRA,"h=Y"}, {zSRA,"l=Y"}, {zSRA,"Y"}, {zSRA,"a=Y"}, + {zSLL,"b=Y"}, {zSLL,"c=Y"}, {zSLL,"d=Y"}, {zSLL,"e=Y"}, + {zSLL,"h=Y"}, {zSLL,"l=Y"}, {zSLL,"Y"}, {zSLL,"a=Y"}, + {zSRL,"b=Y"}, {zSRL,"c=Y"}, {zSRL,"d=Y"}, {zSRL,"e=Y"}, + {zSRL,"h=Y"}, {zSRL,"l=Y"}, {zSRL,"Y"}, {zSRL,"a=Y"}, + {zBIT,"b=0,Y"}, {zBIT,"c=0,Y"}, {zBIT,"d=0,Y"}, {zBIT,"e=0,Y"}, + {zBIT,"h=0,Y"}, {zBIT,"l=0,Y"}, {zBIT,"0,Y"}, {zBIT,"a=0,Y"}, + {zBIT,"b=1,Y"}, {zBIT,"c=1,Y"}, {zBIT,"d=1,Y"}, {zBIT,"e=1,Y"}, + {zBIT,"h=1,Y"}, {zBIT,"l=1,Y"}, {zBIT,"1,Y"}, {zBIT,"a=1,Y"}, + {zBIT,"b=2,Y"}, {zBIT,"c=2,Y"}, {zBIT,"d=2,Y"}, {zBIT,"e=2,Y"}, + {zBIT,"h=2,Y"}, {zBIT,"l=2,Y"}, {zBIT,"2,Y"}, {zBIT,"a=2,Y"}, + {zBIT,"b=3,Y"}, {zBIT,"c=3,Y"}, {zBIT,"d=3,Y"}, {zBIT,"e=3,Y"}, + {zBIT,"h=3,Y"}, {zBIT,"l=3,Y"}, {zBIT,"3,Y"}, {zBIT,"a=3,Y"}, + {zBIT,"b=4,Y"}, {zBIT,"c=4,Y"}, {zBIT,"d=4,Y"}, {zBIT,"e=4,Y"}, + {zBIT,"h=4,Y"}, {zBIT,"l=4,Y"}, {zBIT,"4,Y"}, {zBIT,"a=4,Y"}, + {zBIT,"b=5,Y"}, {zBIT,"c=5,Y"}, {zBIT,"d=5,Y"}, {zBIT,"e=5,Y"}, + {zBIT,"h=5,Y"}, {zBIT,"l=5,Y"}, {zBIT,"5,Y"}, {zBIT,"a=5,Y"}, + {zBIT,"b=6,Y"}, {zBIT,"c=6,Y"}, {zBIT,"d=6,Y"}, {zBIT,"e=6,Y"}, + {zBIT,"h=6,Y"}, {zBIT,"l=6,Y"}, {zBIT,"6,Y"}, {zBIT,"a=6,Y"}, + {zBIT,"b=7,Y"}, {zBIT,"c=7,Y"}, {zBIT,"d=7,Y"}, {zBIT,"e=7,Y"}, + {zBIT,"h=7,Y"}, {zBIT,"l=7,Y"}, {zBIT,"7,Y"}, {zBIT,"a=7,Y"}, + {zRES,"b=0,Y"}, {zRES,"c=0,Y"}, {zRES,"d=0,Y"}, {zRES,"e=0,Y"}, + {zRES,"h=0,Y"}, {zRES,"l=0,Y"}, {zRES,"0,Y"}, {zRES,"a=0,Y"}, + {zRES,"b=1,Y"}, {zRES,"c=1,Y"}, {zRES,"d=1,Y"}, {zRES,"e=1,Y"}, + {zRES,"h=1,Y"}, {zRES,"l=1,Y"}, {zRES,"1,Y"}, {zRES,"a=1,Y"}, + {zRES,"b=2,Y"}, {zRES,"c=2,Y"}, {zRES,"d=2,Y"}, {zRES,"e=2,Y"}, + {zRES,"h=2,Y"}, {zRES,"l=2,Y"}, {zRES,"2,Y"}, {zRES,"a=2,Y"}, + {zRES,"b=3,Y"}, {zRES,"c=3,Y"}, {zRES,"d=3,Y"}, {zRES,"e=3,Y"}, + {zRES,"h=3,Y"}, {zRES,"l=3,Y"}, {zRES,"3,Y"}, {zRES,"a=3,Y"}, + {zRES,"b=4,Y"}, {zRES,"c=4,Y"}, {zRES,"d=4,Y"}, {zRES,"e=4,Y"}, + {zRES,"h=4,Y"}, {zRES,"l=4,Y"}, {zRES,"4,Y"}, {zRES,"a=4,Y"}, + {zRES,"b=5,Y"}, {zRES,"c=5,Y"}, {zRES,"d=5,Y"}, {zRES,"e=5,Y"}, + {zRES,"h=5,Y"}, {zRES,"l=5,Y"}, {zRES,"5,Y"}, {zRES,"a=5,Y"}, + {zRES,"b=6,Y"}, {zRES,"c=6,Y"}, {zRES,"d=6,Y"}, {zRES,"e=6,Y"}, + {zRES,"h=6,Y"}, {zRES,"l=6,Y"}, {zRES,"6,Y"}, {zRES,"a=6,Y"}, + {zRES,"b=7,Y"}, {zRES,"c=7,Y"}, {zRES,"d=7,Y"}, {zRES,"e=7,Y"}, + {zRES,"h=7,Y"}, {zRES,"l=7,Y"}, {zRES,"7,Y"}, {zRES,"a=7,Y"}, + {zSET,"b=0,Y"}, {zSET,"c=0,Y"}, {zSET,"d=0,Y"}, {zSET,"e=0,Y"}, + {zSET,"h=0,Y"}, {zSET,"l=0,Y"}, {zSET,"0,Y"}, {zSET,"a=0,Y"}, + {zSET,"b=1,Y"}, {zSET,"c=1,Y"}, {zSET,"d=1,Y"}, {zSET,"e=1,Y"}, + {zSET,"h=1,Y"}, {zSET,"l=1,Y"}, {zSET,"1,Y"}, {zSET,"a=1,Y"}, + {zSET,"b=2,Y"}, {zSET,"c=2,Y"}, {zSET,"d=2,Y"}, {zSET,"e=2,Y"}, + {zSET,"h=2,Y"}, {zSET,"l=2,Y"}, {zSET,"2,Y"}, {zSET,"a=2,Y"}, + {zSET,"b=3,Y"}, {zSET,"c=3,Y"}, {zSET,"d=3,Y"}, {zSET,"e=3,Y"}, + {zSET,"h=3,Y"}, {zSET,"l=3,Y"}, {zSET,"3,Y"}, {zSET,"a=3,Y"}, + {zSET,"b=4,Y"}, {zSET,"c=4,Y"}, {zSET,"d=4,Y"}, {zSET,"e=4,Y"}, + {zSET,"h=4,Y"}, {zSET,"l=4,Y"}, {zSET,"4,Y"}, {zSET,"a=4,Y"}, + {zSET,"b=5,Y"}, {zSET,"c=5,Y"}, {zSET,"d=5,Y"}, {zSET,"e=5,Y"}, + {zSET,"h=5,Y"}, {zSET,"l=5,Y"}, {zSET,"5,Y"}, {zSET,"a=5,Y"}, + {zSET,"b=6,Y"}, {zSET,"c=6,Y"}, {zSET,"d=6,Y"}, {zSET,"e=6,Y"}, + {zSET,"h=6,Y"}, {zSET,"l=6,Y"}, {zSET,"6,Y"}, {zSET,"a=6,Y"}, + {zSET,"b=7,Y"}, {zSET,"c=7,Y"}, {zSET,"d=7,Y"}, {zSET,"e=7,Y"}, + {zSET,"h=7,Y"}, {zSET,"l=7,Y"}, {zSET,"7,Y"}, {zSET,"a=7,Y"} +}; + +static const z80dasm mnemonic_cb[256] = +{ + {zRLC,"b"}, {zRLC,"c"}, {zRLC,"d"}, {zRLC,"e"}, + {zRLC,"h"}, {zRLC,"l"}, {zRLC,"(hl)"}, {zRLC,"a"}, + {zRRC,"b"}, {zRRC,"c"}, {zRRC,"d"}, {zRRC,"e"}, + {zRRC,"h"}, {zRRC,"l"}, {zRRC,"(hl)"}, {zRRC,"a"}, + {zRL,"b"}, {zRL,"c"}, {zRL,"d"}, {zRL,"e"}, + {zRL,"h"}, {zRL,"l"}, {zRL,"(hl)"}, {zRL,"a"}, + {zRR,"b"}, {zRR,"c"}, {zRR,"d"}, {zRR,"e"}, + {zRR,"h"}, {zRR,"l"}, {zRR,"(hl)"}, {zRR,"a"}, + {zSLA,"b"}, {zSLA,"c"}, {zSLA,"d"}, {zSLA,"e"}, + {zSLA,"h"}, {zSLA,"l"}, {zSLA,"(hl)"}, {zSLA,"a"}, + {zSRA,"b"}, {zSRA,"c"}, {zSRA,"d"}, {zSRA,"e"}, + {zSRA,"h"}, {zSRA,"l"}, {zSRA,"(hl)"}, {zSRA,"a"}, + {zSLL,"b"}, {zSLL,"c"}, {zSLL,"d"}, {zSLL,"e"}, + {zSLL,"h"}, {zSLL,"l"}, {zSLL,"(hl)"}, {zSLL,"a"}, + {zSRL,"b"}, {zSRL,"c"}, {zSRL,"d"}, {zSRL,"e"}, + {zSRL,"h"}, {zSRL,"l"}, {zSRL,"(hl)"}, {zSRL,"a"}, + {zBIT,"0,b"}, {zBIT,"0,c"}, {zBIT,"0,d"}, {zBIT,"0,e"}, + {zBIT,"0,h"}, {zBIT,"0,l"}, {zBIT,"0,(hl)"},{zBIT,"0,a"}, + {zBIT,"1,b"}, {zBIT,"1,c"}, {zBIT,"1,d"}, {zBIT,"1,e"}, + {zBIT,"1,h"}, {zBIT,"1,l"}, {zBIT,"1,(hl)"},{zBIT,"1,a"}, + {zBIT,"2,b"}, {zBIT,"2,c"}, {zBIT,"2,d"}, {zBIT,"2,e"}, + {zBIT,"2,h"}, {zBIT,"2,l"}, {zBIT,"2,(hl)"},{zBIT,"2,a"}, + {zBIT,"3,b"}, {zBIT,"3,c"}, {zBIT,"3,d"}, {zBIT,"3,e"}, + {zBIT,"3,h"}, {zBIT,"3,l"}, {zBIT,"3,(hl)"},{zBIT,"3,a"}, + {zBIT,"4,b"}, {zBIT,"4,c"}, {zBIT,"4,d"}, {zBIT,"4,e"}, + {zBIT,"4,h"}, {zBIT,"4,l"}, {zBIT,"4,(hl)"},{zBIT,"4,a"}, + {zBIT,"5,b"}, {zBIT,"5,c"}, {zBIT,"5,d"}, {zBIT,"5,e"}, + {zBIT,"5,h"}, {zBIT,"5,l"}, {zBIT,"5,(hl)"},{zBIT,"5,a"}, + {zBIT,"6,b"}, {zBIT,"6,c"}, {zBIT,"6,d"}, {zBIT,"6,e"}, + {zBIT,"6,h"}, {zBIT,"6,l"}, {zBIT,"6,(hl)"},{zBIT,"6,a"}, + {zBIT,"7,b"}, {zBIT,"7,c"}, {zBIT,"7,d"}, {zBIT,"7,e"}, + {zBIT,"7,h"}, {zBIT,"7,l"}, {zBIT,"7,(hl)"},{zBIT,"7,a"}, + {zRES,"0,b"}, {zRES,"0,c"}, {zRES,"0,d"}, {zRES,"0,e"}, + {zRES,"0,h"}, {zRES,"0,l"}, {zRES,"0,(hl)"},{zRES,"0,a"}, + {zRES,"1,b"}, {zRES,"1,c"}, {zRES,"1,d"}, {zRES,"1,e"}, + {zRES,"1,h"}, {zRES,"1,l"}, {zRES,"1,(hl)"},{zRES,"1,a"}, + {zRES,"2,b"}, {zRES,"2,c"}, {zRES,"2,d"}, {zRES,"2,e"}, + {zRES,"2,h"}, {zRES,"2,l"}, {zRES,"2,(hl)"},{zRES,"2,a"}, + {zRES,"3,b"}, {zRES,"3,c"}, {zRES,"3,d"}, {zRES,"3,e"}, + {zRES,"3,h"}, {zRES,"3,l"}, {zRES,"3,(hl)"},{zRES,"3,a"}, + {zRES,"4,b"}, {zRES,"4,c"}, {zRES,"4,d"}, {zRES,"4,e"}, + {zRES,"4,h"}, {zRES,"4,l"}, {zRES,"4,(hl)"},{zRES,"4,a"}, + {zRES,"5,b"}, {zRES,"5,c"}, {zRES,"5,d"}, {zRES,"5,e"}, + {zRES,"5,h"}, {zRES,"5,l"}, {zRES,"5,(hl)"},{zRES,"5,a"}, + {zRES,"6,b"}, {zRES,"6,c"}, {zRES,"6,d"}, {zRES,"6,e"}, + {zRES,"6,h"}, {zRES,"6,l"}, {zRES,"6,(hl)"},{zRES,"6,a"}, + {zRES,"7,b"}, {zRES,"7,c"}, {zRES,"7,d"}, {zRES,"7,e"}, + {zRES,"7,h"}, {zRES,"7,l"}, {zRES,"7,(hl)"},{zRES,"7,a"}, + {zSET,"0,b"}, {zSET,"0,c"}, {zSET,"0,d"}, {zSET,"0,e"}, + {zSET,"0,h"}, {zSET,"0,l"}, {zSET,"0,(hl)"},{zSET,"0,a"}, + {zSET,"1,b"}, {zSET,"1,c"}, {zSET,"1,d"}, {zSET,"1,e"}, + {zSET,"1,h"}, {zSET,"1,l"}, {zSET,"1,(hl)"},{zSET,"1,a"}, + {zSET,"2,b"}, {zSET,"2,c"}, {zSET,"2,d"}, {zSET,"2,e"}, + {zSET,"2,h"}, {zSET,"2,l"}, {zSET,"2,(hl)"},{zSET,"2,a"}, + {zSET,"3,b"}, {zSET,"3,c"}, {zSET,"3,d"}, {zSET,"3,e"}, + {zSET,"3,h"}, {zSET,"3,l"}, {zSET,"3,(hl)"},{zSET,"3,a"}, + {zSET,"4,b"}, {zSET,"4,c"}, {zSET,"4,d"}, {zSET,"4,e"}, + {zSET,"4,h"}, {zSET,"4,l"}, {zSET,"4,(hl)"},{zSET,"4,a"}, + {zSET,"5,b"}, {zSET,"5,c"}, {zSET,"5,d"}, {zSET,"5,e"}, + {zSET,"5,h"}, {zSET,"5,l"}, {zSET,"5,(hl)"},{zSET,"5,a"}, + {zSET,"6,b"}, {zSET,"6,c"}, {zSET,"6,d"}, {zSET,"6,e"}, + {zSET,"6,h"}, {zSET,"6,l"}, {zSET,"6,(hl)"},{zSET,"6,a"}, + {zSET,"7,b"}, {zSET,"7,c"}, {zSET,"7,d"}, {zSET,"7,e"}, + {zSET,"7,h"}, {zSET,"7,l"}, {zSET,"7,(hl)"},{zSET,"7,a"} +}; + +static const z80dasm mnemonic_ed[256] = +{ + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zIN,"b,(c)"}, {zOUT,"(c),b"}, {zSBC,"hl,bc"}, {zLD,"(W),bc"}, + {zNEG,0}, {zRETN,0}, {zIM,"0"}, {zLD,"i,a"}, + {zIN,"c,(c)"}, {zOUT,"(c),c"}, {zADC,"hl,bc"}, {zLD,"bc,(W)"}, + {zNEG,"*"}, {zRETI,0}, {zIM,"0"}, {zLD,"r,a"}, + {zIN,"d,(c)"}, {zOUT,"(c),d"}, {zSBC,"hl,de"}, {zLD,"(W),de"}, + {zNEG,"*"}, {zRETN,0}, {zIM,"1"}, {zLD,"a,i"}, + {zIN,"e,(c)"}, {zOUT,"(c),e"}, {zADC,"hl,de"}, {zLD,"de,(W)"}, + {zNEG,"*"}, {zRETI,0}, {zIM,"2"}, {zLD,"a,r"}, + {zIN,"h,(c)"}, {zOUT,"(c),h"}, {zSBC,"hl,hl"}, {zLD,"(W),hl"}, + {zNEG,"*"}, {zRETN,0}, {zIM,"0"}, {zRRD,"(hl)"}, + {zIN,"l,(c)"}, {zOUT,"(c),l"}, {zADC,"hl,hl"}, {zLD,"hl,(W)"}, + {zNEG,"*"}, {zRETI,0}, {zIM,"0"}, {zRLD,"(hl)"}, + {zIN,"0,(c)"}, {zOUT,"(c),0"}, {zSBC,"hl,sp"}, {zLD,"(W),sp"}, + {zNEG,"*"}, {zRETN,0}, {zIM,"1"}, {zDB,"?"}, + {zIN,"a,(c)"}, {zOUT,"(c),a"}, {zADC,"hl,sp"}, {zLD,"sp,(W)"}, + {zNEG,"*"}, {zRETI,0}, {zIM,"2"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zLDI,0}, {zCPI,0}, {zINI,0}, {zOUTI,0}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zLDD,0}, {zCPD,0}, {zIND,0}, {zOUTD,0}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zLDIR,0}, {zCPIR,0}, {zINIR,0}, {zOTIR,0}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zLDDR,0}, {zCPDR,0}, {zINDR,0}, {zOTDR,0}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"} +}; + +static const z80dasm mnemonic_xx[256] = +{ + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zDB,"?"}, {zADD,"I,bc"}, {zDB,"?"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zDB,"?"}, {zADD,"I,de"}, {zDB,"?"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zDB,"?"}, {zLD,"I,N"}, {zLD,"(W),I"}, {zINC,"I"}, + {zINC,"Ih"}, {zDEC,"Ih"}, {zLD,"Ih,B"}, {zDB,"?"}, + {zDB,"?"}, {zADD,"I,I"}, {zLD,"I,(W)"}, {zDEC,"I"}, + {zINC,"Il"}, {zDEC,"Il"}, {zLD,"Il,B"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zINC,"X"}, {zDEC,"X"}, {zLD,"X,B"}, {zDB,"?"}, + {zDB,"?"}, {zADD,"I,sp"}, {zDB,"?"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zLD,"b,Ih"}, {zLD,"b,Il"}, {zLD,"b,X"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zLD,"c,Ih"}, {zLD,"c,Il"}, {zLD,"c,X"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zLD,"d,Ih"}, {zLD,"d,Il"}, {zLD,"d,X"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zLD,"e,Ih"}, {zLD,"e,Il"}, {zLD,"e,X"}, {zDB,"?"}, + {zLD,"Ih,b"}, {zLD,"Ih,c"}, {zLD,"Ih,d"}, {zLD,"Ih,e"}, + {zLD,"Ih,Ih"}, {zLD,"Ih,Il"}, {zLD,"h,X"}, {zLD,"Ih,a"}, + {zLD,"Il,b"}, {zLD,"Il,c"}, {zLD,"Il,d"}, {zLD,"Il,e"}, + {zLD,"Il,Ih"}, {zLD,"Il,Il"}, {zLD,"l,X"}, {zLD,"Il,a"}, + {zLD,"X,b"}, {zLD,"X,c"}, {zLD,"X,d"}, {zLD,"X,e"}, + {zLD,"X,h"}, {zLD,"X,l"}, {zDB,"?"}, {zLD,"X,a"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zLD,"a,Ih"}, {zLD,"a,Il"}, {zLD,"a,X"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zADD,"a,Ih"}, {zADD,"a,Il"}, {zADD,"a,X"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zADC,"a,Ih"}, {zADC,"a,Il"}, {zADC,"a,X"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zSUB,"Ih"}, {zSUB,"Il"}, {zSUB,"X"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zSBC,"a,Ih"}, {zSBC,"a,Il"}, {zSBC,"a,X"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zAND,"Ih"}, {zAND,"Il"}, {zAND,"X"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zXOR,"Ih"}, {zXOR,"Il"}, {zXOR,"X"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zOR,"Ih"}, {zOR,"Il"}, {zOR,"X"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zCP,"Ih"}, {zCP,"Il"}, {zCP,"X"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"cb"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zDB,"?"}, {zPOP,"I"}, {zDB,"?"}, {zEX,"(sp),I"}, + {zDB,"?"}, {zPUSH,"I"}, {zDB,"?"}, {zDB,"?"}, + {zDB,"?"}, {zJP,"(I)"}, {zDB,"?"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, + {zDB,"?"}, {zLD,"sp,I"}, {zDB,"?"}, {zDB,"?"}, + {zDB,"?"}, {zDB,"?"}, {zDB,"?"}, {zDB,"?"} +}; + +static const z80dasm mnemonic_main[256] = +{ + {zNOP,0}, {zLD,"bc,N"}, {zLD,"(bc),a"}, {zINC,"bc"}, + {zINC,"b"}, {zDEC,"b"}, {zLD,"b,B"}, {zRLCA,0}, + {zEX,"af,af'"}, {zADD,"hl,bc"}, {zLD,"a,(bc)"}, {zDEC,"bc"}, + {zINC,"c"}, {zDEC,"c"}, {zLD,"c,B"}, {zRRCA,0}, + {zDJNZ,"O"}, {zLD,"de,N"}, {zLD,"(de),a"}, {zINC,"de"}, + {zINC,"d"}, {zDEC,"d"}, {zLD,"d,B"}, {zRLA,0}, + {zJR,"O"}, {zADD,"hl,de"}, {zLD,"a,(de)"}, {zDEC,"de"}, + {zINC,"e"}, {zDEC,"e"}, {zLD,"e,B"}, {zRRA,0}, + {zJR,"nz,O"}, {zLD,"hl,N"}, {zLD,"(W),hl"}, {zINC,"hl"}, + {zINC,"h"}, {zDEC,"h"}, {zLD,"h,B"}, {zDAA,0}, + {zJR,"z,O"}, {zADD,"hl,hl"}, {zLD,"hl,(W)"}, {zDEC,"hl"}, + {zINC,"l"}, {zDEC,"l"}, {zLD,"l,B"}, {zCPL,0}, + {zJR,"nc,O"}, {zLD,"sp,N"}, {zLD,"(W),a"}, {zINC,"sp"}, + {zINC,"(hl)"}, {zDEC,"(hl)"}, {zLD,"(hl),B"}, {zSCF,0}, + {zJR,"c,O"}, {zADD,"hl,sp"}, {zLD,"a,(W)"}, {zDEC,"sp"}, + {zINC,"a"}, {zDEC,"a"}, {zLD,"a,B"}, {zCCF,0}, + {zLD,"b,b"}, {zLD,"b,c"}, {zLD,"b,d"}, {zLD,"b,e"}, + {zLD,"b,h"}, {zLD,"b,l"}, {zLD,"b,(hl)"}, {zLD,"b,a"}, + {zLD,"c,b"}, {zLD,"c,c"}, {zLD,"c,d"}, {zLD,"c,e"}, + {zLD,"c,h"}, {zLD,"c,l"}, {zLD,"c,(hl)"}, {zLD,"c,a"}, + {zLD,"d,b"}, {zLD,"d,c"}, {zLD,"d,d"}, {zLD,"d,e"}, + {zLD,"d,h"}, {zLD,"d,l"}, {zLD,"d,(hl)"}, {zLD,"d,a"}, + {zLD,"e,b"}, {zLD,"e,c"}, {zLD,"e,d"}, {zLD,"e,e"}, + {zLD,"e,h"}, {zLD,"e,l"}, {zLD,"e,(hl)"}, {zLD,"e,a"}, + {zLD,"h,b"}, {zLD,"h,c"}, {zLD,"h,d"}, {zLD,"h,e"}, + {zLD,"h,h"}, {zLD,"h,l"}, {zLD,"h,(hl)"}, {zLD,"h,a"}, + {zLD,"l,b"}, {zLD,"l,c"}, {zLD,"l,d"}, {zLD,"l,e"}, + {zLD,"l,h"}, {zLD,"l,l"}, {zLD,"l,(hl)"}, {zLD,"l,a"}, + {zLD,"(hl),b"}, {zLD,"(hl),c"}, {zLD,"(hl),d"}, {zLD,"(hl),e"}, + {zLD,"(hl),h"}, {zLD,"(hl),l"}, {zHLT,0}, {zLD,"(hl),a"}, + {zLD,"a,b"}, {zLD,"a,c"}, {zLD,"a,d"}, {zLD,"a,e"}, + {zLD,"a,h"}, {zLD,"a,l"}, {zLD,"a,(hl)"}, {zLD,"a,a"}, + {zADD,"a,b"}, {zADD,"a,c"}, {zADD,"a,d"}, {zADD,"a,e"}, + {zADD,"a,h"}, {zADD,"a,l"}, {zADD,"a,(hl)"},{zADD,"a,a"}, + {zADC,"a,b"}, {zADC,"a,c"}, {zADC,"a,d"}, {zADC,"a,e"}, + {zADC,"a,h"}, {zADC,"a,l"}, {zADC,"a,(hl)"},{zADC,"a,a"}, + {zSUB,"b"}, {zSUB,"c"}, {zSUB,"d"}, {zSUB,"e"}, + {zSUB,"h"}, {zSUB,"l"}, {zSUB,"(hl)"}, {zSUB,"a"}, + {zSBC,"a,b"}, {zSBC,"a,c"}, {zSBC,"a,d"}, {zSBC,"a,e"}, + {zSBC,"a,h"}, {zSBC,"a,l"}, {zSBC,"a,(hl)"},{zSBC,"a,a"}, + {zAND,"b"}, {zAND,"c"}, {zAND,"d"}, {zAND,"e"}, + {zAND,"h"}, {zAND,"l"}, {zAND,"(hl)"}, {zAND,"a"}, + {zXOR,"b"}, {zXOR,"c"}, {zXOR,"d"}, {zXOR,"e"}, + {zXOR,"h"}, {zXOR,"l"}, {zXOR,"(hl)"}, {zXOR,"a"}, + {zOR,"b"}, {zOR,"c"}, {zOR,"d"}, {zOR,"e"}, + {zOR,"h"}, {zOR,"l"}, {zOR,"(hl)"}, {zOR,"a"}, + {zCP,"b"}, {zCP,"c"}, {zCP,"d"}, {zCP,"e"}, + {zCP,"h"}, {zCP,"l"}, {zCP,"(hl)"}, {zCP,"a"}, + {zRET,"nz"}, {zPOP,"bc"}, {zJP,"nz,A"}, {zJP,"A"}, + {zCALL,"nz,A"}, {zPUSH,"bc"}, {zADD,"a,B"}, {zRST,"V"}, + {zRET,"z"}, {zRET,0}, {zJP,"z,A"}, {zDB,"cb"}, + {zCALL,"z,A"}, {zCALL,"A"}, {zADC,"a,B"}, {zRST,"V"}, + {zRET,"nc"}, {zPOP,"de"}, {zJP,"nc,A"}, {zOUT,"(P),a"}, + {zCALL,"nc,A"}, {zPUSH,"de"}, {zSUB,"B"}, {zRST,"V"}, + {zRET,"c"}, {zEXX,0}, {zJP,"c,A"}, {zIN,"a,(P)"}, + {zCALL,"c,A"}, {zDB,"dd"}, {zSBC,"a,B"}, {zRST,"V"}, + {zRET,"po"}, {zPOP,"hl"}, {zJP,"po,A"}, {zEX,"(sp),hl"}, + {zCALL,"po,A"}, {zPUSH,"hl"}, {zAND,"B"}, {zRST,"V"}, + {zRET,"pe"}, {zJP,"(hl)"}, {zJP,"pe,A"}, {zEX,"de,hl"}, + {zCALL,"pe,A"}, {zDB,"ed"}, {zXOR,"B"}, {zRST,"V"}, + {zRET,"p"}, {zPOP,"af"}, {zJP,"p,A"}, {zDI,0}, + {zCALL,"p,A"}, {zPUSH,"af"}, {zOR,"B"}, {zRST,"V"}, + {zRET,"m"}, {zLD,"sp,hl"}, {zJP,"m,A"}, {zEI,0}, + {zCALL,"m,A"}, {zDB,"fd"}, {zCP,"B"}, {zRST,"V"} +}; + +static char sign(INT8 offset) +{ + return (offset < 0)? '-':'+'; +} + +static int offs(INT8 offset) +{ + if (offset < 0) return -offset; + return offset; +} + +/**************************************************************************** + * Disassemble opcode at PC and return number of bytes it takes + ****************************************************************************/ +CPU_DISASSEMBLE( z80 ) +{ + const z80dasm *d; + const char *src, *ixy; + char *dst; + INT8 offset = 0; + UINT8 op, op1 = 0; + UINT16 ea = 0; + int pos = 0; + + ixy = "oops!!"; + dst = buffer; + + op = oprom[pos++]; + + switch (op) + { + case 0xcb: + op = oprom[pos++]; + d = &mnemonic_cb[op]; + break; + case 0xed: + op1 = oprom[pos++]; + d = &mnemonic_ed[op1]; + break; + case 0xdd: + ixy = "ix"; + op1 = oprom[pos++]; + if( op1 == 0xcb ) + { + offset = (INT8) opram[pos++]; + op1 = opram[pos++]; /* fourth byte from opbase.ram! */ + d = &mnemonic_xx_cb[op1]; + } + else d = &mnemonic_xx[op1]; + break; + case 0xfd: + ixy = "iy"; + op1 = oprom[pos++]; + if( op1 == 0xcb ) + { + offset = (INT8) opram[pos++]; + op1 = opram[pos++]; /* fourth byte from opbase.ram! */ + d = &mnemonic_xx_cb[op1]; + } + else d = &mnemonic_xx[op1]; + break; + default: + d = &mnemonic_main[op]; + break; + } + + if( d->arguments ) + { + dst += sprintf(dst, "%-4s ", s_mnemonic[d->mnemonic]); + src = d->arguments; + while( *src ) + { + switch( *src ) + { + case '?': /* illegal opcode */ + dst += sprintf( dst, "$%02x,$%02x", op, op1 ); + break; + case 'A': + ea = opram[pos+0] + ( opram[pos+1] << 8 ); + pos += 2; + dst += sprintf( dst, "$%04X", ea ); + break; + case 'B': /* Byte op arg */ + ea = opram[pos++]; + dst += sprintf( dst, "$%02X", ea ); + break; + case 'N': /* Immediate 16 bit */ + ea = opram[pos+0] + ( opram[pos+1] << 8 ); + pos += 2; + dst += sprintf( dst, "$%04X", ea ); + break; + case 'O': /* Offset relative to PC */ + offset = (INT8) opram[pos++]; + dst += sprintf( dst, "$%04X", (pc + offset + 2) & 0xffff ); + break; + case 'P': /* Port number */ + ea = opram[pos++]; + dst += sprintf( dst, "$%02X", ea ); + break; + case 'V': /* Restart vector */ + ea = op & 0x38; + dst += sprintf( dst, "$%02X", ea ); + break; + case 'W': /* Memory address word */ + ea = opram[pos+0] + ( opram[pos+1] << 8 ); + pos += 2; + dst += sprintf( dst, "$%04X", ea ); + break; + case 'X': + offset = (INT8) opram[pos++]; + /* fall through */ + case 'Y': + dst += sprintf( dst,"(%s%c$%02x)", ixy, sign(offset), offs(offset) ); + break; + case 'I': + dst += sprintf( dst, "%s", ixy); + break; + default: + *dst++ = *src; + } + src++; + } + *dst = '\0'; + } + else + { + dst += sprintf(dst, "%s", s_mnemonic[d->mnemonic]); + } + + return pos | s_flags[d->mnemonic] | DASMFLAG_SUPPORTED; +} diff --git a/src/devices/cpu/z8000/8000dasm.c b/src/devices/cpu/z8000/8000dasm.c new file mode 100644 index 00000000000..91a4849da41 --- /dev/null +++ b/src/devices/cpu/z8000/8000dasm.c @@ -0,0 +1,355 @@ +// license:BSD-3-Clause +// copyright-holders:Juergen Buchmueller,Ernesto Corvi +/***************************************************************************** + * + * 8000dasm.c + * Portable Z8000(2) emulator + * Z8000 disassembler; requires the z8000_exec table to be initialized + * + *****************************************************************************/ + +#include "emu.h" +#include "z8000.h" +#include "z8000cpu.h" +#include "debugger.h" +#include "debug/debugvw.h" +#include "debug/debugcon.h" + +static int n[16]; /* opcode nibbles */ +static int b[8]; /* opcode bytes */ +static int w[4]; /* opcode words */ + +static void GET_OP(const UINT8 *oprom, int i, unsigned offset) +{ + UINT16 opcode = (oprom[offset] << 8) | oprom[offset + 1]; + w[i] = opcode; + b[i*2+0] = opcode >> 8; + b[i*2+1] = opcode & 0xff; + n[i*4+0] = (opcode >> 12) & 0x0f; + n[i*4+1] = (opcode >> 8) & 0x0f; + n[i*4+2] = (opcode >> 4) & 0x0f; + n[i*4+3] = opcode & 0x0f; +} + +static const char *const cc[16] = { + "n", "lt", "le", "ule", "pe/ov", "mi", "eq/z", "c/ult", + "a", "ge", "gt", "ugt", "po/nov", "pl", "ne/nz", "nc/uge" +}; + +static const char *const flg[16] = { + "", "p/v", "s", "p/v,s", "z", "p/v,z", "s,z", "p/v,s,z", + "c", "p/v,c","s,c", "p/v,s,c", "z,c", "p/v,z,c","s,z,c","p/v,s,z,c" +}; + +static const char *const ints[4] = { + "", "vi", "nvi", "vi,nvi" +}; + +int z8k_segm; /* Current disassembler mode: 0 - non-segmented, 1 - segmented */ +int z8k_segm_mode = Z8K_SEGM_MODE_AUTO; /* User disassembler mode setting: segmented, non-segmented, auto */ + +void z8k_disass_mode(running_machine &machine, int ref, int params, const char *param[]) +{ + size_t len; + if (params == 1) + { + len = strlen(param[0]); + if (!core_strnicmp(param[0], "segmented", len) || !core_stricmp(param[0], "z8001")) { + z8k_segm = true; + z8k_segm_mode = Z8K_SEGM_MODE_SEG; + debug_console_printf(machine, "Disassembler mode set to Z8001/segmented\n"); + } + else if (!core_strnicmp(param[0], "non-segmented", len) || !core_stricmp(param[0], "z8002")) { + z8k_segm = false; + z8k_segm_mode = Z8K_SEGM_MODE_NONSEG; + debug_console_printf(machine, "Disassembler mode set to Z8002/non-segmented\n"); + } + else if (!core_strnicmp(param[0], "automatic", len)) { + z8k_segm_mode = Z8K_SEGM_MODE_AUTO; + debug_console_printf(machine, "Disassembler mode set to automatic\n"); + } + else + goto usage; + } + else if (params > 1) { + usage: + debug_console_printf(machine, "Usage: z8k_disass_mode \n"); + debug_console_printf(machine, " set disassembler mode\n"); + debug_console_printf(machine, " mode: \"segmented\" or \"z8001\" - Z8001 mode\n"); + debug_console_printf(machine, " \"non-segmented\" or \"z8002\" - Z8002 mode\n"); + debug_console_printf(machine, " \"automatic\" - automatic mode\n"); + } + else { + debug_console_printf(machine, "Current disassembler mode: "); + if (z8k_segm_mode == Z8K_SEGM_MODE_AUTO) + debug_console_printf(machine, "automatic, currently "); + debug_console_printf(machine, "%s\n", z8k_segm ? "Z8001/segmented" : "Z8002/non-segmented"); + } +} + +CPU_DISASSEMBLE( z8000 ) +{ + int new_pc = pc, i, j, tmp; + char *dst = buffer; + const char *src; + Z8000_exec *o; + UINT32 flags = 0; + UINT32 old_w; + + /* already initialized? */ + if(z8000_exec == NULL) + z8000_init_tables(); + + GET_OP(oprom, 0, new_pc - pc); + new_pc += 2; + switch (pc) + { + case 0x0000: + dst += sprintf(dst, ".word #%%%04x ;RST", w[0]); + break; + case 0x0002: + dst += sprintf(dst, ".word #%%%04x ;RST FCW", w[0]); + break; + case 0x0004: + dst += sprintf(dst, ".word #%%%04x ;RST PC", w[0]); + break; + default: + o = &z8000_exec[w[0]]; + if (o->size > 1) { GET_OP(oprom, 1, new_pc - pc); new_pc += 2; } + if (o->size > 2) { GET_OP(oprom, 2, new_pc - pc); new_pc += 2; } + src = o->dasm; + flags = o->dasmflags; + + while (*src) + { + if (*src == '%') + { + src++; + switch (*src) { + case '0': case '1': case '2': case '3': + case '4': case '5': case '6': case '7': + /* nibble number */ + i = *src++ - '0'; + dst += sprintf(dst, "%d", n[i]); + break; + case '#': + /* immediate */ + src++; + switch (*src++) { + case 'b': /* imm8 (byte) */ + i = *src++ - '0'; + dst += sprintf(dst, "#%%%02x", b[i]); + break; + case 'w': /* imm16 (word) */ + i = *src++ - '0'; + dst += sprintf(dst, "#%%%04x", w[i]); + break; + case 'l': /* imm32 (long) */ + i = *src++ - '0'; + dst += sprintf(dst, "#%%%04x%04x", w[i], w[i+1]); + break; + } + break; + case '$': + /* absolute immediate 8bit (rl/rr) */ + src++; + i = *src++ - '0'; + dst += sprintf(dst, "#%d", ((INT8)b[i]<0) ? -(INT8)b[i] : b[i]); + break; + case '+': + /* imm4m1 (inc/dec value) */ + src++; + i = *src++ - '0'; + dst += sprintf(dst, "%i", n[i] + 1); + break; + case '*': + /* left/right (rotate/shift) */ + src++; + dst += sprintf(dst, "%c", b[2] ? 'r' : 'l'); + break; + case '?': + /* imm1or2 (shift/rotate once or twice) */ + src++; + i = *src++ - '0'; + dst += sprintf(dst, "%c", (n[i] & 2) ? '2' : '1'); + break; + case 'R': + src++; + //tmp = ((n[1] & 0x01) << 16) + (n[3] << 8) + (n[7] & 0x08); + tmp = ((n[1] & 0x01) << 8) + (n[3] << 4) + (n[7] & 0x08); + switch (tmp) + { + case 0x000: dst += sprintf(dst, "inirb "); flags = DASMFLAG_STEP_OVER; break; + case 0x008: dst += sprintf(dst, "inib "); break; + case 0x010: dst += sprintf(dst, "sinirb"); flags = DASMFLAG_STEP_OVER; break; + case 0x018: dst += sprintf(dst, "sinib "); break; + case 0x020: dst += sprintf(dst, "otirb "); flags = DASMFLAG_STEP_OVER; break; + case 0x028: dst += sprintf(dst, "outib "); break; + case 0x030: dst += sprintf(dst, "soutib"); break; + case 0x038: dst += sprintf(dst, "sotirb"); flags = DASMFLAG_STEP_OVER; break; + case 0x040: dst += sprintf(dst, "inb "); break; + case 0x048: dst += sprintf(dst, "inb "); break; + case 0x050: dst += sprintf(dst, "sinb "); break; + case 0x058: dst += sprintf(dst, "sinb "); break; + case 0x060: dst += sprintf(dst, "outb "); break; + case 0x068: dst += sprintf(dst, "outb "); break; + case 0x070: dst += sprintf(dst, "soutb "); break; + case 0x078: dst += sprintf(dst, "soutb "); break; + case 0x080: dst += sprintf(dst, "indrb "); flags = DASMFLAG_STEP_OVER; break; + case 0x088: dst += sprintf(dst, "indb "); break; + case 0x090: dst += sprintf(dst, "sindrb"); flags = DASMFLAG_STEP_OVER; break; + case 0x098: dst += sprintf(dst, "sindb "); break; + case 0x0a0: dst += sprintf(dst, "otdrb "); flags = DASMFLAG_STEP_OVER; break; + case 0x0a8: dst += sprintf(dst, "outdb "); break; + case 0x0b0: dst += sprintf(dst, "soutdb"); break; + case 0x0b8: dst += sprintf(dst, "sotdrb"); flags = DASMFLAG_STEP_OVER; break; + case 0x100: dst += sprintf(dst, "inir "); flags = DASMFLAG_STEP_OVER; break; + case 0x108: dst += sprintf(dst, "ini "); break; + case 0x110: dst += sprintf(dst, "sinir "); flags = DASMFLAG_STEP_OVER; break; + case 0x118: dst += sprintf(dst, "sini "); break; + case 0x120: dst += sprintf(dst, "otir "); flags = DASMFLAG_STEP_OVER; break; + case 0x128: dst += sprintf(dst, "outi "); break; + case 0x130: dst += sprintf(dst, "souti "); break; + case 0x138: dst += sprintf(dst, "sotir "); flags = DASMFLAG_STEP_OVER; break; + case 0x140: dst += sprintf(dst, "in "); break; + case 0x148: dst += sprintf(dst, "in "); break; + case 0x150: dst += sprintf(dst, "sin "); break; + case 0x158: dst += sprintf(dst, "sin "); break; + case 0x160: dst += sprintf(dst, "out "); break; + case 0x168: dst += sprintf(dst, "out "); break; + case 0x170: dst += sprintf(dst, "sout "); break; + case 0x178: dst += sprintf(dst, "sout "); break; + case 0x180: dst += sprintf(dst, "indr "); flags = DASMFLAG_STEP_OVER; break; + case 0x188: dst += sprintf(dst, "ind "); break; + case 0x190: dst += sprintf(dst, "sindr "); flags = DASMFLAG_STEP_OVER; break; + case 0x198: dst += sprintf(dst, "sind "); break; + case 0x1a0: dst += sprintf(dst, "otdr "); flags = DASMFLAG_STEP_OVER; break; + case 0x1a8: dst += sprintf(dst, "outd "); break; + case 0x1b0: dst += sprintf(dst, "soutd "); break; + case 0x1b8: dst += sprintf(dst, "sotdr "); flags = DASMFLAG_STEP_OVER; break; + default: + dst += sprintf(dst, "unk(0x%x)", tmp); + } + break; + case 'a': + /* address */ + src++; + i = *src++ - '0'; + if (z8k_segm) { + if (w[i] & 0x8000) { + old_w = w[i]; + for (j = i; j < o->size; j++) + w[j] = w[j + 1]; + GET_OP(oprom, o->size - 1, new_pc - pc); + new_pc += 2; + w[i] = ((old_w & 0x7f00) << 16) | (w[i] & 0xffff); + } + else { + w[i] = ((w[i] & 0x7f00) << 16) | (w[i] & 0xff); + } + dst += sprintf(dst, "<%%%02X>%%%04X", (w[i] >> 24) & 0xff, w[i] & 0xffff); + } + else dst += sprintf(dst, "%%%04x", w[i]); + break; + case 'c': + /* condition code */ + src++; + i = *src++ - '0'; + if (n[i] == 8) { /* always? */ + /* skip following comma */ + if (*src == ',') + src++; + } + else dst += sprintf(dst, "%s", cc[n[i]]); + break; + case 'd': + /* displacement */ + src++; + i = *src++ - '0'; + switch (i) { + case 0: /* disp7 */ + tmp = new_pc - 2 * (w[0] & 0x7f); + break; + case 1: /* disp8 */ + tmp = new_pc + 2 * (INT8)(w[0] & 0xff); + break; + case 2: /* disp12 */ + tmp = w[0] & 0x7ff; + if (w[0] & 0x800) + tmp = new_pc + 0x1000 -2 * tmp; + else + tmp = new_pc + -2 * tmp; + break; + default: + tmp = 0; + abort(); + } + if (z8k_segm) + dst += sprintf(dst, "<%%%02X>%%%04X", (tmp >> 16) & 0xff, tmp & 0xffff); + else + dst += sprintf(dst, "%%%04x", tmp); + break; + case 'f': + /* flag (setflg/resflg/comflg) */ + src++; + i = *src++ - '0'; + dst += sprintf(dst, "%s", flg[n[i]]); + break; + case 'i': + /* interrupts */ + src++; + i = *src++ - '0'; + dst += sprintf(dst, "%s", ints[n[i] & 3]); + break; + case 'n': + /* register count for ldm */ + src++; + dst += sprintf(dst, "%d", n[7] + 1); + break; + case 'p': + /* disp16 (pc relative) */ + src++; + i = *src++ - '0'; + dst += sprintf(dst, "%%%04x", new_pc + w[i]); + break; + case 'r': + /* register */ + src++; + switch (*src++) { + case 'b': + /* byte */ + i = *src++ - '0'; + if (n[i] & 8) + dst += sprintf(dst, "rl%d", n[i] & 7); + else + dst += sprintf(dst, "rh%d", n[i]); + break; + case 'w': + /* word */ + i = *src++ - '0'; + dst += sprintf(dst, "r%d", n[i]); + break; + case 'l': + /* long */ + i = *src++ - '0'; + dst += sprintf(dst, "rr%d", n[i]); + break; + case 'q': + /* quad word (long long) */ + i = *src++ - '0'; + dst += sprintf(dst, "rq%d", n[i]); + break; + } + break; + default: + *dst++ = '%'; + *dst++ = *src++; + break; + } + } else *dst++ = *src++; + } + *dst = '\0'; + break; + } + return (new_pc - pc) | flags | DASMFLAG_SUPPORTED; +} diff --git a/src/devices/cpu/z8000/makedab.c b/src/devices/cpu/z8000/makedab.c new file mode 100644 index 00000000000..57668f3af85 --- /dev/null +++ b/src/devices/cpu/z8000/makedab.c @@ -0,0 +1,89 @@ +// license:BSD-3-Clause +// copyright-holders:Juergen Buchmueller,Ernesto Corvi +#include + +#define CF 0x100 +#define HF 0x200 +#define DF 0x400 + +int dab[0x800]; + +int main(int ac, char **av) +{ + int i; + + for (i = 0; i < DF; i++) { + if (i & CF) { + if (i & 0x0f < 0x0a) + dab[i] = CF | ((i + 0x60) & 0xff); + else + dab[i] = CF | ((i + 0x66) & 0xff); + } else { + if (i & HF) { + if (i & 0xf0 < 0xa0) + dab[i] = ((i + 0x06) & 0xff); + else + dab[i] = CF | ((i + 0x66) & 0xff); + } else { + if ((i & 0xf0) < 0xa0 && (i & 0x0f) < 0x0a) + dab[i] = i & 0xff; + else if ((i & 0xf0) < 0x90 && (i & 0x0f) >= 0x0a) + dab[i] = ((i + 0x06) & 0xff); + else if ((i & 0xf0) >= 0xa0 && (i & 0x0f) < 0x0a) + dab[i] = CF | ((i + 0x60) & 0xff); + else if ((i & 0xf0) >= 0x90 && (i & 0x0f) >= 0x0a) + dab[i] = CF | ((i + 0x66) & 0xff); + else { + fprintf(stderr, "unhandled $%04x\n", i); + return 1; + } + + } + } + + if (i & CF) { + if (i & HF) { + dab[DF+i] = CF | ((i + 0x9a) & 0xff); + } else { + dab[DF+i] = CF | ((i + 0xa0) & 0xff); + } + } else { + if (i & HF) { + dab[DF+i] = CF | ((i + 0xfa) & 0xff); + } else { + dab[DF+i] = (i & 0xff); + } + } + } + + printf("/************************************************ \n"); + printf(" * Result table for Z8000 DAB instruction \n"); + printf(" * \n"); + printf(" * bits description \n"); + printf(" * ---------------------------------------------- \n"); + printf(" * 0..7 destination value \n"); + printf(" * 8 carry flag before \n"); + printf(" * 9 half carry flag before \n"); + printf(" * 10 D flag (0 add/adc, 1 sub/sbc) \n"); + printf(" * \n"); + printf(" * result description \n"); + printf(" * ---------------------------------------------- \n"); + printf(" * 0..7 result value \n"); + printf(" * 8 carry flag after \n"); + printf(" ************************************************/\n"); + printf("static const UINT16 Z8000_dab[0x800] = {\n"); + for (i = 0; i < 0x800; i++) { + if ((i & 0x3ff) == 0) { + if (i & 0x400) + printf("\t/* sub/sbc results */\n"); + else + printf("\t/* add/adc results */\n"); + } + if ((i & 7) == 0) printf("\t"); + printf("0x%03x,",dab[i]); + if ((i & 7) == 7) printf("\n"); + } + printf("};\n"); + + return 0; +} diff --git a/src/devices/cpu/z8000/z8000.c b/src/devices/cpu/z8000/z8000.c new file mode 100644 index 00000000000..76ff93c76b8 --- /dev/null +++ b/src/devices/cpu/z8000/z8000.c @@ -0,0 +1,808 @@ +// license:BSD-3-Clause +// copyright-holders:Juergen Buchmueller,Ernesto Corvi +/***************************************************************************** + * + * z8000.c + * Portable Z8000(2) emulator + * Z8000 MAME interface + * + * TODO: + * - make the z8001 opcodes to be dynamic (i.e. to take segmented mode flag into account and use the non-segmented mode) + * - dissassembler doesn't work at all with the z8001 + * + *****************************************************************************/ + +#include "emu.h" +#include "debugger.h" +#include "debug/debugcon.h" +#include "z8000.h" + +#define VERBOSE 0 + + +#define LOG(x) do { if (VERBOSE) logerror x; } while (0) + + +extern int z8k_segm; +extern int z8k_segm_mode; +extern void z8k_disass_mode(running_machine &machine, int ref, int params, const char *param[]); + +#include "z8000cpu.h" + +const device_type Z8001 = &device_creator; +const device_type Z8002 = &device_creator; + + +z8002_device::z8002_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : cpu_device(mconfig, Z8002, "Z8002", tag, owner, clock, "z8002", __FILE__) + , m_program_config("program", ENDIANNESS_BIG, 16, 16, 0) + , m_io_config("io", ENDIANNESS_BIG, 8, 16, 0) + , m_mo_out(*this) + , m_vector_mult(1) +{ +} + + +z8002_device::z8002_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : cpu_device(mconfig, type, name, tag, owner, clock, shortname, source) + , m_program_config("program", ENDIANNESS_BIG, 16, 20, 0) + , m_io_config("io", ENDIANNESS_BIG, 16, 16, 0) + , m_mo_out(*this) + , m_vector_mult(2) +{ +} + + +z8001_device::z8001_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : z8002_device(mconfig, Z8001, "Zilog Z8001", tag, owner, clock, "z8001", __FILE__) + , m_data_config("data", ENDIANNESS_BIG, 16, 20, 0) +{ +} + + +offs_t z8002_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + extern CPU_DISASSEMBLE( z8000 ); + return CPU_DISASSEMBLE_NAME(z8000)(this, buffer, pc, oprom, opram, options); +} + + +/* opcode execution table */ +Z8000_exec *z8000_exec = NULL; + +/* zero, sign and parity flags for logical byte operations */ +static UINT8 z8000_zsp[256]; + + +int z8002_device::segmented_mode() +{ + return 0; +} + +int z8001_device::segmented_mode() +{ + return (m_fcw & F_SEG) ? 1 : 0; +} + +UINT32 z8002_device::addr_add(UINT32 addr, UINT32 addend) +{ + return (addr & 0xffff0000) | ((addr + addend) & 0xffff); +} + +UINT32 z8002_device::addr_sub(UINT32 addr, UINT32 subtrahend) +{ + return (addr & 0xffff0000) | ((addr - subtrahend) & 0xffff); +} + +/* conversion table for Z8000 DAB opcode */ +#include "z8000dab.h" + +UINT16 z8002_device::RDOP() +{ + UINT16 res = m_program->read_word(m_pc); + m_pc += 2; + return res; +} + +UINT32 z8002_device::get_operand(int opnum) +{ + int i; + + for (i = 0; i < opnum; i++) + { + assert (m_op_valid & (1 << i)); + } + + if (! (m_op_valid & (1 << opnum))) + { + m_op[opnum] = m_program->read_word(m_pc); + m_pc += 2; + m_op_valid |= (1 << opnum); + } + return m_op[opnum]; +} + +UINT32 z8002_device::get_addr_operand(int opnum) +{ + int i; + + for (i = 0; i < opnum; i++) + { + assert (m_op_valid & (1 << i)); + } + + if (! (m_op_valid & (1 << opnum))) + { + UINT32 seg = m_program->read_word(m_pc); + m_pc += 2; + if (segmented_mode()) + { + if (seg & 0x8000) + { + m_op[opnum] = ((seg & 0x7f00) << 8) | m_program->read_word(m_pc); + m_pc += 2; + } + else + m_op[opnum] = ((seg & 0x7f00) << 8) | (seg & 0xff); + } + else + m_op[opnum] = seg; + m_op_valid |= (1 << opnum); + } + return m_op[opnum]; +} + +UINT32 z8002_device::get_raw_addr_operand(int opnum) +{ + int i; + + for (i = 0; i < opnum; i++) + { + assert (m_op_valid & (1 << i)); + } + + if (! (m_op_valid & (1 << opnum))) + { + UINT32 seg = m_program->read_word(m_pc); + m_pc += 2; + if (segmented_mode()) + { + if (seg & 0x8000) + { + m_op[opnum] = (seg << 16) | m_program->read_word(m_pc); + m_pc += 2; + } + else + m_op[opnum] = (seg << 16) | (seg & 0xff); + } + else + m_op[opnum] = seg; + m_op_valid |= (1 << opnum); + } + return m_op[opnum]; +} + +UINT32 z8002_device::adjust_addr_for_nonseg_mode(UINT32 addr) +{ + return addr; +} + +UINT32 z8001_device::adjust_addr_for_nonseg_mode(UINT32 addr) +{ + if (!(m_fcw & F_SEG)) + { + return (addr & 0xffff) | (m_pc & 0x7f0000); + } + else + { + return addr; + } +} + +UINT8 z8002_device::RDMEM_B(address_spacenum spacenum, UINT32 addr) +{ + addr = adjust_addr_for_nonseg_mode(addr); + if (spacenum == AS_PROGRAM) + return m_program->read_byte(addr); + else + return m_data->read_byte(addr); +} + +UINT16 z8002_device::RDMEM_W(address_spacenum spacenum, UINT32 addr) +{ + addr = adjust_addr_for_nonseg_mode(addr); + addr &= ~1; + /* hack for m20 driver: BIOS accesses 0x7f0000 and expects a segmentation violation */ + if (addr >= 0x7f0000) { + m_irq_req = Z8000_SEGTRAP; + return 0xffff; + } + if (spacenum == AS_PROGRAM) + return m_program->read_word(addr); + else + return m_data->read_word(addr); +} + +UINT32 z8002_device::RDMEM_L(address_spacenum spacenum, UINT32 addr) +{ + UINT32 result; + addr = adjust_addr_for_nonseg_mode(addr); + addr &= ~1; + if (spacenum == AS_PROGRAM) + { + result = m_program->read_word(addr) << 16; + return result + m_program->read_word(addr_add(addr, 2)); + } + else + { + result = m_data->read_word(addr) << 16; + return result + m_data->read_word(addr_add(addr, 2)); + } +} + +void z8002_device::WRMEM_B(address_spacenum spacenum, UINT32 addr, UINT8 value) +{ + addr = adjust_addr_for_nonseg_mode(addr); + if (spacenum == AS_PROGRAM) + m_program->write_byte(addr, value); + else + m_data->write_byte(addr, value); +} + +void z8002_device::WRMEM_W(address_spacenum spacenum, UINT32 addr, UINT16 value) +{ + addr = adjust_addr_for_nonseg_mode(addr); + addr &= ~1; + if (spacenum == AS_PROGRAM) + m_program->write_word(addr, value); + else + m_data->write_word(addr, value); +} + +void z8002_device::WRMEM_L(address_spacenum spacenum, UINT32 addr, UINT32 value) +{ + addr = adjust_addr_for_nonseg_mode(addr); + addr &= ~1; + if (spacenum == AS_PROGRAM) + { + m_program->write_word(addr, value >> 16); + m_program->write_word(addr_add(addr, 2), value & 0xffff); + } + else + { + m_data->write_word(addr, value >> 16); + m_data->write_word(addr_add(addr, 2), value & 0xffff); + } +} + +UINT8 z8002_device::RDPORT_B(int mode, UINT16 addr) +{ + if(mode == 0) + { + return m_io->read_byte(addr); + } + else + { + /* how to handle MMU reads? for now just do it */ + return m_io->read_byte(addr); + } +} + +UINT16 z8002_device::RDPORT_W(int mode, UINT16 addr) +{ + if(mode == 0) + { + return m_io->read_byte((UINT16)(addr)) + + (m_io->read_byte((UINT16)(addr+1)) << 8); + } + else + { + /* how to handle MMU reads? */ + return 0x0000; + } +} + +UINT16 z8001_device::RDPORT_W(int mode, UINT16 addr) +{ + if(mode == 0) + { + return m_io->read_word_unaligned((UINT16)addr); + } + else + { + /* how to handle MMU reads? */ + return 0x0000; + } +} + +void z8002_device::WRPORT_B(int mode, UINT16 addr, UINT8 value) +{ + if(mode == 0) + { + m_io->write_byte(addr,value); + } + else + { + /* how to handle MMU writes? for now just do it */ + m_io->write_byte(addr,value); + } +} + +void z8002_device::WRPORT_W(int mode, UINT16 addr, UINT16 value) +{ + if(mode == 0) + { + m_io->write_byte((UINT16)(addr),value & 0xff); + m_io->write_byte((UINT16)(addr+1),(value >> 8) & 0xff); + } + else + { + /* how to handle MMU writes? */ + } +} + +void z8001_device::WRPORT_W(int mode, UINT16 addr, UINT16 value) +{ + if(mode == 0) + { + m_io->write_word_unaligned((UINT16)addr, value); + } + else + { + /* how to handle MMU writes? */ + } +} + +void z8002_device::cycles(int cycles) +{ + m_icount -= cycles; +} + +#include "z8000ops.inc" +#include "z8000tbl.inc" + +void z8002_device::set_irq(int type) +{ + switch ((type >> 8) & 255) + { + case Z8000_EPU >> 8: + m_irq_req = type; + break; + case Z8000_TRAP >> 8: + m_irq_req = type; + break; + case Z8000_NMI >> 8: + m_irq_req = type; + break; + case Z8000_SEGTRAP >> 8: + m_irq_req = type; + break; + case Z8000_NVI >> 8: + m_irq_req = type; + break; + case Z8000_VI >> 8: + m_irq_req = type; + break; + case Z8000_SYSCALL >> 8: + LOG(("Z8K '%s' SYSCALL $%02x\n", tag(), type & 0xff)); + m_irq_req = type; + break; + default: + logerror("Z8000 invalid Cause_Interrupt %04x\n", type); + return; + } + /* set interrupt request flag, reset HALT flag */ + m_irq_req = type & ~Z8000_HALT; +} + +void z8002_device::PUSH_PC() +{ + PUSHW(SP, m_pc); /* save current pc */ +} + +void z8001_device::PUSH_PC() +{ + PUSHL(SP, make_segmented_addr(m_pc)); /* save current pc */ +} + + +UINT32 z8002_device::GET_PC(UINT32 VEC) +{ + return RDMEM_W(AS_PROGRAM, VEC + 2); +} + +UINT32 z8001_device::GET_PC(UINT32 VEC) +{ + return segmented_addr(RDMEM_L(AS_PROGRAM, VEC + 4)); +} + +UINT16 z8002_device::GET_FCW(UINT32 VEC) +{ + return RDMEM_W(AS_PROGRAM, VEC); +} + +UINT16 z8001_device::GET_FCW(UINT32 VEC) +{ + return RDMEM_W(AS_PROGRAM, VEC + 2); +} + +UINT32 z8002_device::F_SEG_Z8001() +{ + return 0; +} + +UINT32 z8001_device::F_SEG_Z8001() +{ + return F_SEG; +} + +UINT32 z8002_device::PSA_ADDR() +{ + return m_psapoff; +} + +UINT32 z8001_device::PSA_ADDR() +{ + return segmented_addr((m_psapseg << 16) | m_psapoff); +} + + +void z8002_device::Interrupt() +{ + UINT16 fcw = m_fcw; + + if (m_irq_req & Z8000_NVI) + { + int type = standard_irq_callback(0); + set_irq(type | Z8000_NVI); + } + + if (m_irq_req & Z8000_VI) + { + int type = standard_irq_callback(1); + set_irq(type | Z8000_VI); + } + + /* trap ? */ + if (m_irq_req & Z8000_EPU) + { + CHANGE_FCW(fcw | F_S_N | F_SEG_Z8001());/* switch to segmented (on Z8001) system mode */ + PUSH_PC(); + PUSHW(SP, fcw); /* save current m_fcw */ + PUSHW(SP, RDMEM_W(AS_PROGRAM, m_ppc)); /* for internal traps, the 1st word of the instruction is pushed */ + m_irq_req &= ~Z8000_EPU; + CHANGE_FCW(GET_FCW(EPU)); + m_pc = GET_PC(EPU); + LOG(("Z8K '%s' ext instr trap $%04x\n", tag(), m_pc)); + } + else + if (m_irq_req & Z8000_TRAP) + { + CHANGE_FCW(fcw | F_S_N | F_SEG_Z8001());/* switch to segmented (on Z8001) system mode */ + PUSH_PC(); + PUSHW(SP, fcw); /* save current m_fcw */ + PUSHW(SP, RDMEM_W(AS_PROGRAM, m_ppc)); /* for internal traps, the 1st word of the instruction is pushed */ + m_irq_req &= ~Z8000_TRAP; + CHANGE_FCW(GET_FCW(TRAP)); + m_pc = GET_PC(TRAP); + LOG(("Z8K '%s' priv instr trap $%04x\n", tag(), m_pc)); + } + else + if (m_irq_req & Z8000_SYSCALL) + { + CHANGE_FCW(fcw | F_S_N | F_SEG_Z8001());/* switch to segmented (on Z8001) system mode */ + PUSH_PC(); + PUSHW(SP, fcw); /* save current m_fcw */ + PUSHW(SP, RDMEM_W(AS_PROGRAM, m_ppc)); /* for internal traps, the 1st word of the instruction is pushed */ + m_irq_req &= ~Z8000_SYSCALL; + CHANGE_FCW(GET_FCW(SYSCALL)); + m_pc = GET_PC(SYSCALL); + LOG(("Z8K '%s' syscall $%04x\n", tag(), m_pc)); + } + else + if (m_irq_req & Z8000_SEGTRAP) + { + CHANGE_FCW(fcw | F_S_N | F_SEG_Z8001());/* switch to segmented (on Z8001) system mode */ + PUSH_PC(); + PUSHW(SP, fcw); /* save current m_fcw */ + PUSHW(SP, m_irq_req); /* save interrupt/trap type tag */ + m_irq_req &= ~Z8000_SEGTRAP; + CHANGE_FCW(GET_FCW(SEGTRAP)); + m_pc = GET_PC(SEGTRAP); + LOG(("Z8K '%s' segtrap $%04x\n", tag(), m_pc)); + } + else + if (m_irq_req & Z8000_NMI) + { + CHANGE_FCW(fcw | F_S_N | F_SEG_Z8001());/* switch to segmented (on Z8001) system mode */ + PUSH_PC(); + PUSHW(SP, fcw); /* save current m_fcw */ + PUSHW(SP, m_irq_req); /* save interrupt/trap type tag */ + m_pc = RDMEM_W(AS_PROGRAM, NMI); + m_irq_req &= ~Z8000_NMI; + CHANGE_FCW(GET_FCW(NMI)); + m_pc = GET_PC(NMI); + LOG(("Z8K '%s' NMI $%04x\n", tag(), m_pc)); + } + else + if ((m_irq_req & Z8000_NVI) && (m_fcw & F_NVIE)) + { + CHANGE_FCW(fcw | F_S_N | F_SEG_Z8001());/* switch to segmented (on Z8001) system mode */ + PUSH_PC(); + PUSHW(SP, fcw); /* save current m_fcw */ + PUSHW(SP, m_irq_req); /* save interrupt/trap type tag */ + m_pc = GET_PC(NVI); + m_irq_req &= ~Z8000_NVI; + CHANGE_FCW(GET_FCW(NVI)); + LOG(("Z8K '%s' NVI $%04x\n", tag(), m_pc)); + } + else + if ((m_irq_req & Z8000_VI) && (m_fcw & F_VIE)) + { + CHANGE_FCW(fcw | F_S_N | F_SEG_Z8001());/* switch to segmented (on Z8001) system mode */ + PUSH_PC(); + PUSHW(SP, fcw); /* save current m_fcw */ + PUSHW(SP, m_irq_req); /* save interrupt/trap type tag */ + m_pc = read_irq_vector(); + m_irq_req &= ~Z8000_VI; + CHANGE_FCW(GET_FCW(VI)); + LOG(("Z8K '%s' VI [$%04x/$%04x] fcw $%04x, pc $%04x\n", tag(), m_irq_vec, VEC00 + ( m_vector_mult * 2 ) * (m_irq_req & 0xff), m_fcw, m_pc)); + } +} + +UINT32 z8002_device::read_irq_vector() +{ + return RDMEM_W(AS_PROGRAM, VEC00 + 2 * (m_irq_req & 0xff)); +} + + +UINT32 z8001_device::read_irq_vector() +{ + return segmented_addr(RDMEM_L(AS_PROGRAM, VEC00 + 4 * (m_irq_req & 0xff))); +} + + +void z8002_device::clear_internal_state() +{ + m_op[0] = m_op[1] = m_op[2] = m_op[3] = 0; + m_ppc = 0; + m_pc = 0; + m_psapseg = 0; + m_psapoff = 0; + m_fcw = 0; + m_refresh = 0; + m_nspseg = 0; + m_nspoff = 0; + m_irq_req = 0; + m_irq_vec = 0; + m_op_valid = 0; + m_regs.Q[0] = m_regs.Q[1] = m_regs.Q[2] = m_regs.Q[3] = 0; + m_nmi_state = 0; + m_irq_state[0] = m_irq_state[1] = 0; +} + +void z8002_device::register_debug_state() +{ + state_add( Z8000_PPC, "prev PC", m_ppc ).formatstr("%08X"); + state_add( Z8000_PC, "PC", m_pc ).formatstr("%08X"); + state_add( Z8000_NSPOFF, "NSPOFF", m_nspoff ).formatstr("%04X"); + state_add( Z8000_NSPSEG, "NSPSEG", m_nspseg ).formatstr("%04X"); + state_add( Z8000_FCW, "FCW", m_fcw ).formatstr("%04X"); + state_add( Z8000_PSAPOFF, "PSAPOFF", m_psapoff ).formatstr("%04X"); + state_add( Z8000_PSAPSEG, "PSAPSEG", m_psapseg ).formatstr("%04X"); + state_add( Z8000_REFRESH, "REFR", m_refresh ).formatstr("%04X"); + state_add( Z8000_IRQ_REQ, "IRQR", m_irq_req ).formatstr("%04X"); + state_add( Z8000_IRQ_VEC, "IRQV", m_irq_vec ).formatstr("%04X"); + state_add( Z8000_R0, "R0", RW(0) ).formatstr("%04X"); + state_add( Z8000_R1, "R1", RW(1) ).formatstr("%04X"); + state_add( Z8000_R2, "R2", RW(2) ).formatstr("%04X"); + state_add( Z8000_R3, "R3", RW(3) ).formatstr("%04X"); + state_add( Z8000_R4, "R4", RW(4) ).formatstr("%04X"); + state_add( Z8000_R5, "R5", RW(5) ).formatstr("%04X"); + state_add( Z8000_R6, "R6", RW(6) ).formatstr("%04X"); + state_add( Z8000_R7, "R7", RW(7) ).formatstr("%04X"); + state_add( Z8000_R8, "R8", RW(8) ).formatstr("%04X"); + state_add( Z8000_R9, "R9", RW(9) ).formatstr("%04X"); + state_add( Z8000_R10, "R10", RW(10) ).formatstr("%04X"); + state_add( Z8000_R11, "R11", RW(11) ).formatstr("%04X"); + state_add( Z8000_R12, "R12", RW(12) ).formatstr("%04X"); + state_add( Z8000_R13, "R13", RW(13) ).formatstr("%04X"); + state_add( Z8000_R14, "R14", RW(14) ).formatstr("%04X"); + state_add( Z8000_R15, "R15", RW(15) ).formatstr("%04X"); + + state_add( STATE_GENPC, "GENPC", m_pc ).noshow(); + state_add( STATE_GENPCBASE, "GENPCBASE", m_ppc ).noshow(); + state_add( STATE_GENFLAGS, "GENFLAGS", m_fcw ).formatstr("%16s").noshow(); + state_add( STATE_GENSP, "GENSP", m_nspoff ).noshow(); +} + +void z8002_device::state_string_export(const device_state_entry &entry, std::string &str) +{ + switch (entry.index()) + { + case STATE_GENFLAGS: + strprintf(str, "%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c", + m_fcw & 0x8000 ? 'S':'s', + m_fcw & 0x4000 ? 'n':'N', + m_fcw & 0x2000 ? 'E':'e', + m_fcw & 0x1000 ? 'V':'v', + m_fcw & 0x0800 ? 'N':'n', + m_fcw & 0x0400 ? '?':'.', + m_fcw & 0x0200 ? '?':'.', + m_fcw & 0x0100 ? '?':'.', + m_fcw & 0x0080 ? 'C':'c', + m_fcw & 0x0040 ? 'Z':'z', + m_fcw & 0x0020 ? 'S':'s', + m_fcw & 0x0010 ? 'V':'v', + m_fcw & 0x0008 ? 'D':'d', + m_fcw & 0x0004 ? 'H':'h', + m_fcw & 0x0002 ? '?':'.', + m_fcw & 0x0001 ? '?':'.'); + break; + } + +} + +void z8001_device::device_start() +{ + clear_internal_state(); + + m_program = &space(AS_PROGRAM); + /* If the system decodes STn lines to distinguish between data and program memory fetches, + install the data space. If it doesn't, install the program memory into data memory space. */ + if (has_space(AS_DATA)) + m_data = &space(AS_DATA); + else + m_data = &space(AS_PROGRAM); + m_direct = &m_program->direct(); + m_io = &space(AS_IO); + + /* already initialized? */ + if(z8000_exec == NULL) + z8000_init_tables(); + + if (machine().debug_flags & DEBUG_FLAG_ENABLED) + debug_console_register_command(machine(), "z8k_disass_mode", CMDFLAG_NONE, 0, 0, 1, z8k_disass_mode); + + z8k_segm = true; + + register_debug_state(); + + m_icountptr = &m_icount; + m_mo_out.resolve_safe(); + m_mi = CLEAR_LINE; +} + +void z8002_device::device_start() +{ + clear_internal_state(); + + m_program = &space(AS_PROGRAM); + /* If the system decodes STn lines to distinguish between data and program memory fetches, + install the data space. If it doesn't, install the program memory into data memory space. */ + if (has_space(AS_DATA)) + m_data = &space(AS_DATA); + else + m_data = &space(AS_PROGRAM); + m_direct = &m_program->direct(); + m_io = &space(AS_IO); + + /* already initialized? */ + if(z8000_exec == NULL) + z8000_init_tables(); + + z8k_segm = false; + + register_debug_state(); + + m_icountptr = &m_icount; + m_mo_out.resolve_safe(); + m_mi = CLEAR_LINE; +} + +void z8001_device::device_reset() +{ + m_fcw = RDMEM_W(AS_PROGRAM, 2); /* get reset m_fcw */ + if(m_fcw & F_SEG) + { + m_pc = ((RDMEM_W(AS_PROGRAM, 4) & 0x0700) << 8) | (RDMEM_W(AS_PROGRAM, 6) & 0xffff); /* get reset m_pc */ + } + else + { + m_pc = RDMEM_W(AS_PROGRAM, 4); /* get reset m_pc */ + } + m_ppc = m_pc; +} + +void z8002_device::device_reset() +{ + m_fcw = RDMEM_W(AS_PROGRAM, 2); /* get reset m_fcw */ + m_pc = RDMEM_W(AS_PROGRAM, 4); /* get reset m_pc */ + m_ppc = m_pc; +} + +z8002_device::~z8002_device() +{ + z8000_deinit_tables(); +} + +void z8002_device::execute_run() +{ + do + { + /* any interrupt request pending? */ + if (m_irq_req) + Interrupt(); + + if (z8k_segm_mode == Z8K_SEGM_MODE_AUTO) + z8k_segm = (m_fcw & F_SEG_Z8001()) ? 1 : 0; + + debugger_instruction_hook(this, m_pc); + + if (m_irq_req & Z8000_HALT) + { + m_icount = 0; + } + else + { + Z8000_exec *exec; + + m_ppc = m_pc; + m_op[0] = RDOP(); + m_op_valid = 1; + exec = &z8000_exec[m_op[0]]; + + m_icount -= exec->cycles; + (this->*exec->opcode)(); + m_op_valid = 0; + } + } while (m_icount > 0); + +} + +void z8002_device::execute_set_input(int irqline, int state) +{ + if (irqline == INPUT_LINE_NMI) + { + if (m_nmi_state == state) + return; + + m_nmi_state = state; + + if (state != CLEAR_LINE) + { + m_irq_req = Z8000_NMI; + m_irq_vec = NMI; + } + } + else if (irqline < 2) + { + m_irq_state[irqline] = state; + if (irqline == 0) + { + if (state == CLEAR_LINE) + { + if (!(m_fcw & F_NVIE)) + m_irq_req &= ~Z8000_NVI; + } + else + { + if (m_fcw & F_NVIE) + m_irq_req |= Z8000_NVI; + } + } + else + { + if (state == CLEAR_LINE) + { + if (!(m_fcw & F_VIE)) + m_irq_req &= ~Z8000_VI; + } + else + { + if (m_fcw & F_VIE) + m_irq_req |= Z8000_VI; + } + } + } +} diff --git a/src/devices/cpu/z8000/z8000.h b/src/devices/cpu/z8000/z8000.h new file mode 100644 index 00000000000..4437e0399ab --- /dev/null +++ b/src/devices/cpu/z8000/z8000.h @@ -0,0 +1,678 @@ +// license:BSD-3-Clause +// copyright-holders:Juergen Buchmueller,Ernesto Corvi +#pragma once + +#ifndef __Z8000_H__ +#define __Z8000_H__ + + +enum +{ + Z8000_PC=1, + Z8000_PPC, Z8000_NSPSEG, Z8000_NSPOFF, Z8000_FCW, + Z8000_PSAPSEG, Z8000_PSAPOFF, Z8000_REFRESH, + Z8000_IRQ_REQ, Z8000_IRQ_SRV, Z8000_IRQ_VEC, + Z8000_R0, Z8000_R1, Z8000_R2, Z8000_R3, + Z8000_R4, Z8000_R5, Z8000_R6, Z8000_R7, + Z8000_R8, Z8000_R9, Z8000_R10, Z8000_R11, + Z8000_R12, Z8000_R13, Z8000_R14, Z8000_R15 +}; + +/* Interrupt Types that can be generated by outside sources */ +#define Z8000_EPU 0x8000 /* extended instruction trap */ +#define Z8000_TRAP 0x4000 /* privileged instruction trap */ +#define Z8000_NMI 0x2000 /* non maskable interrupt */ +#define Z8000_SEGTRAP 0x1000 /* segment trap (Z8001) */ +#define Z8000_NVI 0x0800 /* non vectored interrupt */ +#define Z8000_VI 0x0400 /* vectored interrupt (LSB is vector) */ +#define Z8000_SYSCALL 0x0200 /* system call (lsb is vector) */ +#define Z8000_HALT 0x0100 /* halted flag */ + +#define MCFG_Z8000_MO(_devcb) \ + devcb = &z8002_device::set_mo_callback(*device, DEVCB_##_devcb); + +class z8002_device : public cpu_device +{ +public: + // construction/destruction + z8002_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + z8002_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + ~z8002_device(); + + template static devcb_base &set_mo_callback(device_t &device, _Object object) { return downcast(device).m_mo_out.set_callback(object); } + DECLARE_WRITE_LINE_MEMBER(mi_w) { m_mi = state; } // XXX: this has to apply in the middle of an insn for now + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_execute_interface overrides + virtual UINT32 execute_min_cycles() const { return 2; } + virtual UINT32 execute_max_cycles() const { return 744; } + virtual UINT32 execute_input_lines() const { return 2; } + virtual UINT32 execute_default_irq_vector() const { return 0xff; } + virtual void execute_run(); + virtual void execute_set_input(int inputnum, int state); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const + { + switch (spacenum) + { + case AS_PROGRAM: return &m_program_config; + case AS_IO: return &m_io_config; + default: return NULL; + } + } + + // device_state_interface overrides + void state_string_export(const device_state_entry &entry, std::string &str); + + // device_disasm_interface overrides + virtual UINT32 disasm_min_opcode_bytes() const { return 2; } + virtual UINT32 disasm_max_opcode_bytes() const { return 6; } + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + + address_space_config m_program_config; + address_space_config m_io_config; + devcb_write_line m_mo_out; + + UINT32 m_op[4]; /* opcodes/data of current instruction */ + UINT32 m_ppc; /* previous program counter */ + UINT32 m_pc; /* program counter */ + UINT16 m_psapseg; /* program status pointer, segment (Z8001 only) */ + UINT16 m_psapoff; /* program status pointer, offset */ + UINT16 m_fcw; /* flags and control word */ + UINT16 m_refresh; /* refresh timer/counter */ + UINT16 m_nspseg; /* system stack pointer, segment (Z8001 only) */ + UINT16 m_nspoff; /* system stack pointer, offset */ + UINT16 m_irq_req; /* CPU is halted, interrupt or trap request */ + UINT16 m_irq_vec; /* interrupt vector */ + UINT32 m_op_valid; /* bit field indicating if given op[] field is already initialized */ + union + { + UINT8 B[16]; /* RL0,RH0,RL1,RH1...RL7,RH7 */ + UINT16 W[16]; /* R0,R1,R2...R15 */ + UINT32 L[8]; /* RR0,RR2,RR4..RR14 */ + UINT64 Q[4]; /* RQ0,RQ4,..RQ12 */ + } m_regs; /* registers */ + int m_nmi_state; /* NMI line state */ + int m_irq_state[2]; /* IRQ line states (NVI, VI) */ + int m_mi; + address_space *m_program; + address_space *m_data; + direct_read_data *m_direct; + address_space *m_io; + int m_icount; + int m_vector_mult; + + void clear_internal_state(); + void register_debug_state(); + virtual int segmented_mode(); + static inline UINT32 addr_add(UINT32 addr, UINT32 addend); + static inline UINT32 addr_sub(UINT32 addr, UINT32 subtrahend); + inline UINT16 RDOP(); + inline UINT32 get_operand(int opnum); + inline UINT32 get_addr_operand(int opnum); + inline UINT32 get_raw_addr_operand(int opnum); + virtual UINT32 adjust_addr_for_nonseg_mode(UINT32 addr); + inline UINT8 RDMEM_B(address_spacenum spacenum, UINT32 addr); + inline UINT16 RDMEM_W(address_spacenum spacenum, UINT32 addr); + inline UINT32 RDMEM_L(address_spacenum spacenum, UINT32 addr); + inline void WRMEM_B(address_spacenum spacenum, UINT32 addr, UINT8 value); + inline void WRMEM_W(address_spacenum spacenum, UINT32 addr, UINT16 value); + inline void WRMEM_L(address_spacenum spacenum, UINT32 addr, UINT32 value); + inline UINT8 RDPORT_B(int mode, UINT16 addr); + virtual UINT16 RDPORT_W(int mode, UINT16 addr); + inline void WRPORT_B(int mode, UINT16 addr, UINT8 value); + virtual void WRPORT_W(int mode, UINT16 addr, UINT16 value); + inline void cycles(int cycles); + inline void set_irq(int type); + virtual void PUSH_PC(); + virtual void CHANGE_FCW(UINT16 fcw); + static inline UINT32 make_segmented_addr(UINT32 addr); + static inline UINT32 segmented_addr(UINT32 addr); + inline UINT32 addr_from_reg(int regno); + inline void addr_to_reg(int regno, UINT32 addr); + inline void add_to_addr_reg(int regno, UINT16 addend); + inline void sub_from_addr_reg(int regno, UINT16 subtrahend); + inline void set_pc(UINT32 addr); + inline void PUSHW(UINT8 dst, UINT16 value); + inline UINT16 POPW(UINT8 src); + inline void PUSHL(UINT8 dst, UINT32 value); + inline UINT32 POPL(UINT8 src); + inline UINT8 ADDB(UINT8 dest, UINT8 value); + inline UINT16 ADDW(UINT16 dest, UINT16 value); + inline UINT32 ADDL(UINT32 dest, UINT32 value); + inline UINT8 ADCB(UINT8 dest, UINT8 value); + inline UINT16 ADCW(UINT16 dest, UINT16 value); + inline UINT8 SUBB(UINT8 dest, UINT8 value); + inline UINT16 SUBW(UINT16 dest, UINT16 value); + inline UINT32 SUBL(UINT32 dest, UINT32 value); + inline UINT8 SBCB(UINT8 dest, UINT8 value); + inline UINT16 SBCW(UINT16 dest, UINT16 value); + inline UINT8 ORB(UINT8 dest, UINT8 value); + inline UINT16 ORW(UINT16 dest, UINT16 value); + inline UINT8 ANDB(UINT8 dest, UINT8 value); + inline UINT16 ANDW(UINT16 dest, UINT16 value); + inline UINT8 XORB(UINT8 dest, UINT8 value); + inline UINT16 XORW(UINT16 dest, UINT16 value); + inline void CPB(UINT8 dest, UINT8 value); + inline void CPW(UINT16 dest, UINT16 value); + inline void CPL(UINT32 dest, UINT32 value); + inline UINT8 COMB(UINT8 dest); + inline UINT16 COMW(UINT16 dest); + inline UINT8 NEGB(UINT8 dest); + inline UINT16 NEGW(UINT16 dest); + inline void TESTB(UINT8 result); + inline void TESTW(UINT16 dest); + inline void TESTL(UINT32 dest); + inline UINT8 INCB(UINT8 dest, UINT8 value); + inline UINT16 INCW(UINT16 dest, UINT16 value); + inline UINT8 DECB(UINT8 dest, UINT8 value); + inline UINT16 DECW(UINT16 dest, UINT16 value); + inline UINT32 MULTW(UINT16 dest, UINT16 value); + inline UINT64 MULTL(UINT32 dest, UINT32 value); + inline UINT32 DIVW(UINT32 dest, UINT16 value); + inline UINT64 DIVL(UINT64 dest, UINT32 value); + inline UINT8 RLB(UINT8 dest, UINT8 twice); + inline UINT16 RLW(UINT16 dest, UINT8 twice); + inline UINT8 RLCB(UINT8 dest, UINT8 twice); + inline UINT16 RLCW(UINT16 dest, UINT8 twice); + inline UINT8 RRB(UINT8 dest, UINT8 twice); + inline UINT16 RRW(UINT16 dest, UINT8 twice); + inline UINT8 RRCB(UINT8 dest, UINT8 twice); + inline UINT16 RRCW(UINT16 dest, UINT8 twice); + inline UINT8 SDAB(UINT8 dest, INT8 count); + inline UINT16 SDAW(UINT16 dest, INT8 count); + inline UINT32 SDAL(UINT32 dest, INT8 count); + inline UINT8 SDLB(UINT8 dest, INT8 count); + inline UINT16 SDLW(UINT16 dest, INT8 count); + inline UINT32 SDLL(UINT32 dest, INT8 count); + inline UINT8 SLAB(UINT8 dest, UINT8 count); + inline UINT16 SLAW(UINT16 dest, UINT8 count); + inline UINT32 SLAL(UINT32 dest, UINT8 count); + inline UINT8 SLLB(UINT8 dest, UINT8 count); + inline UINT16 SLLW(UINT16 dest, UINT8 count); + inline UINT32 SLLL(UINT32 dest, UINT8 count); + inline UINT8 SRAB(UINT8 dest, UINT8 count); + inline UINT16 SRAW(UINT16 dest, UINT8 count); + inline UINT32 SRAL(UINT32 dest, UINT8 count); + inline UINT8 SRLB(UINT8 dest, UINT8 count); + inline UINT16 SRLW(UINT16 dest, UINT8 count); + inline UINT32 SRLL(UINT32 dest, UINT8 count); + inline void Interrupt(); + virtual UINT32 GET_PC(UINT32 VEC); + virtual UINT16 GET_FCW(UINT32 VEC); + virtual UINT32 F_SEG_Z8001(); + virtual UINT32 PSA_ADDR(); + virtual UINT32 read_irq_vector(); + +public: + void zinvalid(); + void Z00_0000_dddd_imm8(); + void Z00_ssN0_dddd(); + void Z01_0000_dddd_imm16(); + void Z01_ssN0_dddd(); + void Z02_0000_dddd_imm8(); + void Z02_ssN0_dddd(); + void Z03_0000_dddd_imm16(); + void Z03_ssN0_dddd(); + void Z04_0000_dddd_imm8(); + void Z04_ssN0_dddd(); + void Z05_0000_dddd_imm16(); + void Z05_ssN0_dddd(); + void Z06_0000_dddd_imm8(); + void Z06_ssN0_dddd(); + void Z07_0000_dddd_imm16(); + void Z07_ssN0_dddd(); + void Z08_0000_dddd_imm8(); + void Z08_ssN0_dddd(); + void Z09_0000_dddd_imm16(); + void Z09_ssN0_dddd(); + void Z0A_0000_dddd_imm8(); + void Z0A_ssN0_dddd(); + void Z0B_0000_dddd_imm16(); + void Z0B_ssN0_dddd(); + void Z0C_ddN0_0000(); + void Z0C_ddN0_0001_imm8(); + void Z0C_ddN0_0010(); + void Z0C_ddN0_0100(); + void Z0C_ddN0_0101_imm8(); + void Z0C_ddN0_0110(); + void Z0C_ddN0_1000(); + void Z0D_ddN0_0000(); + void Z0D_ddN0_0001_imm16(); + void Z0D_ddN0_0010(); + void Z0D_ddN0_0100(); + void Z0D_ddN0_0101_imm16(); + void Z0D_ddN0_0110(); + void Z0D_ddN0_1000(); + void Z0D_ddN0_1001_imm16(); + void Z0E_imm8(); + void Z0F_imm8(); + void Z10_0000_dddd_imm32(); + void Z10_ssN0_dddd(); + void Z11_ddN0_ssN0(); + void Z12_0000_dddd_imm32(); + void Z12_ssN0_dddd(); + void Z13_ddN0_ssN0(); + void Z14_0000_dddd_imm32(); + void Z14_ssN0_dddd(); + void Z15_ssN0_ddN0(); + void Z16_0000_dddd_imm32(); + void Z16_ssN0_dddd(); + void Z17_ssN0_ddN0(); + void Z18_00N0_dddd_imm32(); + void Z18_ssN0_dddd(); + void Z19_0000_dddd_imm16(); + void Z19_ssN0_dddd(); + void Z1A_0000_dddd_imm32(); + void Z1A_ssN0_dddd(); + void Z1B_0000_dddd_imm16(); + void Z1B_ssN0_dddd(); + void Z1C_ddN0_1000(); + void Z1C_ddN0_1001_0000_ssss_0000_nmin1(); + void Z1C_ssN0_0001_0000_dddd_0000_nmin1(); + void Z1D_ddN0_ssss(); + void Z1E_ddN0_cccc(); + void Z1F_ddN0_0000(); + void Z20_ssN0_dddd(); + void Z21_0000_dddd_imm16(); + void Z21_ssN0_dddd(); + void Z22_0000_ssss_0000_dddd_0000_0000(); + void Z22_ddN0_imm4(); + void Z23_0000_ssss_0000_dddd_0000_0000(); + void Z23_ddN0_imm4(); + void Z24_0000_ssss_0000_dddd_0000_0000(); + void Z24_ddN0_imm4(); + void Z25_0000_ssss_0000_dddd_0000_0000(); + void Z25_ddN0_imm4(); + void Z26_0000_ssss_0000_dddd_0000_0000(); + void Z26_ddN0_imm4(); + void Z27_0000_ssss_0000_dddd_0000_0000(); + void Z27_ddN0_imm4(); + void Z28_ddN0_imm4m1(); + void Z29_ddN0_imm4m1(); + void Z2A_ddN0_imm4m1(); + void Z2B_ddN0_imm4m1(); + void Z2C_ssN0_dddd(); + void Z2D_ssN0_dddd(); + void Z2E_ddN0_ssss(); + void Z2F_ddN0_ssss(); + void Z30_0000_dddd_dsp16(); + void Z30_ssN0_dddd_imm16(); + void Z31_0000_dddd_dsp16(); + void Z31_ssN0_dddd_imm16(); + void Z32_0000_ssss_dsp16(); + void Z32_ddN0_ssss_imm16(); + void Z33_0000_ssss_dsp16(); + void Z33_ddN0_ssss_imm16(); + void Z34_0000_dddd_dsp16(); + void Z34_ssN0_dddd_imm16(); + void Z35_0000_dddd_dsp16(); + void Z35_ssN0_dddd_imm16(); + void Z36_0000_0000(); + void Z36_imm8(); + void Z37_0000_ssss_dsp16(); + void Z37_ddN0_ssss_imm16(); + void Z38_imm8(); + void Z39_ssN0_0000(); + void Z3A_ssss_0000_0000_aaaa_dddd_x000(); + void Z3A_ssss_0001_0000_aaaa_dddd_x000(); + void Z3A_ssss_0010_0000_aaaa_dddd_x000(); + void Z3A_ssss_0011_0000_aaaa_dddd_x000(); + void Z3A_dddd_0100_imm16(); + void Z3A_dddd_0101_imm16(); + void Z3A_ssss_0110_imm16(); + void Z3A_ssss_0111_imm16(); + void Z3A_ssss_1000_0000_aaaa_dddd_x000(); + void Z3A_ssss_1001_0000_aaaa_dddd_x000(); + void Z3A_ssss_1010_0000_aaaa_dddd_x000(); + void Z3A_ssss_1011_0000_aaaa_dddd_x000(); + void Z3B_ssss_0000_0000_aaaa_dddd_x000(); + void Z3B_ssss_0001_0000_aaaa_dddd_x000(); + void Z3B_ssss_0010_0000_aaaa_dddd_x000(); + void Z3B_ssss_0011_0000_aaaa_dddd_x000(); + void Z3B_dddd_0100_imm16(); + void Z3B_dddd_0101_imm16(); + void Z3B_ssss_0110_imm16(); + void Z3B_ssss_0111_imm16(); + void Z3B_ssss_1000_0000_aaaa_dddd_x000(); + void Z3B_ssss_1001_0000_aaaa_dddd_x000(); + void Z3B_ssss_1010_0000_aaaa_dddd_x000(); + void Z3B_ssss_1011_0000_aaaa_dddd_x000(); + void Z3C_ssss_dddd(); + void Z3D_ssss_dddd(); + void Z3E_dddd_ssss(); + void Z3F_dddd_ssss(); + void Z40_0000_dddd_addr(); + void Z40_ssN0_dddd_addr(); + void Z41_0000_dddd_addr(); + void Z41_ssN0_dddd_addr(); + void Z42_0000_dddd_addr(); + void Z42_ssN0_dddd_addr(); + void Z43_0000_dddd_addr(); + void Z43_ssN0_dddd_addr(); + void Z44_0000_dddd_addr(); + void Z44_ssN0_dddd_addr(); + void Z45_0000_dddd_addr(); + void Z45_ssN0_dddd_addr(); + void Z46_0000_dddd_addr(); + void Z46_ssN0_dddd_addr(); + void Z47_0000_dddd_addr(); + void Z47_ssN0_dddd_addr(); + void Z48_0000_dddd_addr(); + void Z48_ssN0_dddd_addr(); + void Z49_0000_dddd_addr(); + void Z49_ssN0_dddd_addr(); + void Z4A_0000_dddd_addr(); + void Z4A_ssN0_dddd_addr(); + void Z4B_0000_dddd_addr(); + void Z4B_ssN0_dddd_addr(); + void Z4C_0000_0000_addr(); + void Z4C_0000_0001_addr_imm8(); + void Z4C_0000_0010_addr(); + void Z4C_0000_0100_addr(); + void Z4C_0000_0101_addr_imm8(); + void Z4C_0000_0110_addr(); + void Z4C_0000_1000_addr(); + void Z4C_ddN0_0000_addr(); + void Z4C_ddN0_0001_addr_imm8(); + void Z4C_ddN0_0010_addr(); + void Z4C_ddN0_0100_addr(); + void Z4C_ddN0_0101_addr_imm8(); + void Z4C_ddN0_0110_addr(); + void Z4C_ddN0_1000_addr(); + void Z4D_0000_0000_addr(); + void Z4D_0000_0001_addr_imm16(); + void Z4D_0000_0010_addr(); + void Z4D_0000_0100_addr(); + void Z4D_0000_0101_addr_imm16(); + void Z4D_0000_0110_addr(); + void Z4D_0000_1000_addr(); + void Z4D_ddN0_0000_addr(); + void Z4D_ddN0_0001_addr_imm16(); + void Z4D_ddN0_0010_addr(); + void Z4D_ddN0_0100_addr(); + void Z4D_ddN0_0101_addr_imm16(); + void Z4D_ddN0_0110_addr(); + void Z4D_ddN0_1000_addr(); + void Z4E_ddN0_ssN0_addr(); + void Z50_0000_dddd_addr(); + void Z50_ssN0_dddd_addr(); + void Z51_ddN0_0000_addr(); + void Z51_ddN0_ssN0_addr(); + void Z52_0000_dddd_addr(); + void Z52_ssN0_dddd_addr(); + void Z53_ddN0_0000_addr(); + void Z53_ddN0_ssN0_addr(); + void Z54_0000_dddd_addr(); + void Z54_ssN0_dddd_addr(); + void Z55_ssN0_0000_addr(); + void Z55_ssN0_ddN0_addr(); + void Z56_0000_dddd_addr(); + void Z56_ssN0_dddd_addr(); + void Z57_ssN0_0000_addr(); + void Z57_ssN0_ddN0_addr(); + void Z58_0000_dddd_addr(); + void Z58_ssN0_dddd_addr(); + void Z59_0000_dddd_addr(); + void Z59_ssN0_dddd_addr(); + void Z5A_0000_dddd_addr(); + void Z5A_ssN0_dddd_addr(); + void Z5B_0000_dddd_addr(); + void Z5B_ssN0_dddd_addr(); + void Z5C_0000_0001_0000_dddd_0000_nmin1_addr(); + void Z5C_0000_1000_addr(); + void Z5C_0000_1001_0000_ssss_0000_nmin1_addr(); + void Z5C_ddN0_1000_addr(); + void Z5C_ddN0_1001_0000_ssN0_0000_nmin1_addr(); + void Z5C_ssN0_0001_0000_dddd_0000_nmin1_addr(); + void Z5D_0000_ssss_addr(); + void Z5D_ddN0_ssss_addr(); + void Z5E_0000_cccc_addr(); + void Z5E_ddN0_cccc_addr(); + void Z5F_0000_0000_addr(); + void Z5F_ddN0_0000_addr(); + void Z60_0000_dddd_addr(); + void Z60_ssN0_dddd_addr(); + void Z61_0000_dddd_addr(); + void Z61_ssN0_dddd_addr(); + void Z62_0000_imm4_addr(); + void Z62_ddN0_imm4_addr(); + void Z63_0000_imm4_addr(); + void Z63_ddN0_imm4_addr(); + void Z64_0000_imm4_addr(); + void Z64_ddN0_imm4_addr(); + void Z65_0000_imm4_addr(); + void Z65_ddN0_imm4_addr(); + void Z66_0000_imm4_addr(); + void Z66_ddN0_imm4_addr(); + void Z67_0000_imm4_addr(); + void Z67_ddN0_imm4_addr(); + void Z68_0000_imm4m1_addr(); + void Z68_ddN0_imm4m1_addr(); + void Z69_0000_imm4m1_addr(); + void Z69_ddN0_imm4m1_addr(); + void Z6A_0000_imm4m1_addr(); + void Z6A_ddN0_imm4m1_addr(); + void Z6B_0000_imm4m1_addr(); + void Z6B_ddN0_imm4m1_addr(); + void Z6C_0000_dddd_addr(); + void Z6C_ssN0_dddd_addr(); + void Z6D_0000_dddd_addr(); + void Z6D_ssN0_dddd_addr(); + void Z6E_0000_ssss_addr(); + void Z6E_ddN0_ssss_addr(); + void Z6F_0000_ssss_addr(); + void Z6F_ddN0_ssss_addr(); + void Z70_ssN0_dddd_0000_xxxx_0000_0000(); + void Z71_ssN0_dddd_0000_xxxx_0000_0000(); + void Z72_ddN0_ssss_0000_xxxx_0000_0000(); + void Z73_ddN0_ssss_0000_xxxx_0000_0000(); + void Z74_ssN0_dddd_0000_xxxx_0000_0000(); + void Z75_ssN0_dddd_0000_xxxx_0000_0000(); + void Z76_0000_dddd_addr(); + void Z76_ssN0_dddd_addr(); + void Z77_ddN0_ssss_0000_xxxx_0000_0000(); + void Z78_imm8(); + void Z79_0000_0000_addr(); + void Z79_ssN0_0000_addr(); + void Z7A_0000_0000(); + void Z7B_0000_0000(); + void Z7B_0000_1000(); + void Z7B_0000_1001(); + void Z7B_0000_1010(); + void Z7B_dddd_1101(); + void Z7C_0000_00ii(); + void Z7C_0000_01ii(); + void Z7D_dddd_0ccc(); + void Z7D_ssss_1ccc(); + void Z7E_imm8(); + void Z7F_imm8(); + void Z80_ssss_dddd(); + void Z81_ssss_dddd(); + void Z82_ssss_dddd(); + void Z83_ssss_dddd(); + void Z84_ssss_dddd(); + void Z85_ssss_dddd(); + void Z86_ssss_dddd(); + void Z87_ssss_dddd(); + void Z88_ssss_dddd(); + void Z89_ssss_dddd(); + void Z8A_ssss_dddd(); + void Z8B_ssss_dddd(); + void Z8C_dddd_0000(); + void Z8C_dddd_0010(); + void Z8C_dddd_0100(); + void Z8C_dddd_0110(); + void Z8C_dddd_0001(); + void Z8C_dddd_1000(); + void Z8C_dddd_1001(); + void Z8D_0000_0111(); + void Z8D_dddd_0000(); + void Z8D_dddd_0010(); + void Z8D_dddd_0100(); + void Z8D_dddd_0110(); + void Z8D_dddd_1000(); + void Z8D_imm4_0001(); + void Z8D_imm4_0011(); + void Z8D_imm4_0101(); + void Z8E_imm8(); + void Z8F_imm8(); + void Z90_ssss_dddd(); + void Z91_ddN0_ssss(); + void Z92_ssss_dddd(); + void Z93_ddN0_ssss(); + void Z94_ssss_dddd(); + void Z95_ssN0_dddd(); + void Z96_ssss_dddd(); + void Z97_ssN0_dddd(); + void Z98_ssss_dddd(); + void Z99_ssss_dddd(); + void Z9A_ssss_dddd(); + void Z9B_ssss_dddd(); + void Z9C_dddd_1000(); + void Z9D_imm8(); + void Z9E_0000_cccc(); + void Z9F_imm8(); + void ZA0_ssss_dddd(); + void ZA1_ssss_dddd(); + void ZA2_dddd_imm4(); + void ZA3_dddd_imm4(); + void ZA4_dddd_imm4(); + void ZA5_dddd_imm4(); + void ZA6_dddd_imm4(); + void ZA7_dddd_imm4(); + void ZA8_dddd_imm4m1(); + void ZA9_dddd_imm4m1(); + void ZAA_dddd_imm4m1(); + void ZAB_dddd_imm4m1(); + void ZAC_ssss_dddd(); + void ZAD_ssss_dddd(); + void ZAE_dddd_cccc(); + void ZAF_dddd_cccc(); + void ZB0_dddd_0000(); + void ZB1_dddd_0000(); + void ZB1_dddd_0111(); + void ZB1_dddd_1010(); + void ZB2_dddd_0001_imm8(); + void ZB2_dddd_0011_0000_ssss_0000_0000(); + void ZB2_dddd_00I0(); + void ZB2_dddd_01I0(); + void ZB2_dddd_1001_imm8(); + void ZB2_dddd_1011_0000_ssss_0000_0000(); + void ZB2_dddd_10I0(); + void ZB2_dddd_11I0(); + void ZB3_dddd_0001_imm8(); + void ZB3_dddd_0011_0000_ssss_0000_0000(); + void ZB3_dddd_00I0(); + void ZB3_dddd_0101_imm8(); + void ZB3_dddd_0111_0000_ssss_0000_0000(); + void ZB3_dddd_01I0(); + void ZB3_dddd_1001_imm8(); + void ZB3_dddd_1011_0000_ssss_0000_0000(); + void ZB3_dddd_10I0(); + void ZB3_dddd_1101_imm8(); + void ZB3_dddd_1111_0000_ssss_0000_0000(); + void ZB3_dddd_11I0(); + void ZB4_ssss_dddd(); + void ZB5_ssss_dddd(); + void ZB6_ssss_dddd(); + void ZB7_ssss_dddd(); + void ZB8_ddN0_0010_0000_rrrr_ssN0_0000(); + void ZB8_ddN0_0110_0000_rrrr_ssN0_1110(); + void ZB8_ddN0_1010_0000_rrrr_ssN0_0000(); + void ZB8_ddN0_1110_0000_rrrr_ssN0_1110(); + void ZB8_ddN0_0000_0000_rrrr_ssN0_0000(); + void ZB8_ddN0_0100_0000_rrrr_ssN0_0000(); + void ZB8_ddN0_1000_0000_rrrr_ssN0_0000(); + void ZB8_ddN0_1100_0000_rrrr_ssN0_0000(); + void ZB9_imm8(); + void ZBA_ssN0_0000_0000_rrrr_dddd_cccc(); + void ZBA_ssN0_0001_0000_rrrr_ddN0_x000(); + void ZBA_ssN0_0010_0000_rrrr_ddN0_cccc(); + void ZBA_ssN0_0100_0000_rrrr_dddd_cccc(); + void ZBA_ssN0_0110_0000_rrrr_ddN0_cccc(); + void ZBA_ssN0_1000_0000_rrrr_dddd_cccc(); + void ZBA_ssN0_1001_0000_rrrr_ddN0_x000(); + void ZBA_ssN0_1010_0000_rrrr_ddN0_cccc(); + void ZBA_ssN0_1100_0000_rrrr_dddd_cccc(); + void ZBA_ssN0_1110_0000_rrrr_ddN0_cccc(); + void ZBB_ssN0_0000_0000_rrrr_dddd_cccc(); + void ZBB_ssN0_0001_0000_rrrr_ddN0_x000(); + void ZBB_ssN0_0010_0000_rrrr_ddN0_cccc(); + void ZBB_ssN0_0100_0000_rrrr_dddd_cccc(); + void ZBB_ssN0_0110_0000_rrrr_ddN0_cccc(); + void ZBB_ssN0_1000_0000_rrrr_dddd_cccc(); + void ZBB_ssN0_1001_0000_rrrr_ddN0_x000(); + void ZBB_ssN0_1010_0000_rrrr_ddN0_cccc(); + void ZBB_ssN0_1100_0000_rrrr_dddd_cccc(); + void ZBB_ssN0_1110_0000_rrrr_ddN0_cccc(); + void ZBC_aaaa_bbbb(); + void ZBD_dddd_imm4(); + void ZBE_aaaa_bbbb(); + void ZBF_imm8(); + void Z20_0000_dddd_imm8(); + void ZC_dddd_imm8(); + void ZD_dsp12(); + void ZE_cccc_dsp8(); + void ZF_dddd_0dsp7(); + void ZF_dddd_1dsp7(); +}; + + +class z8001_device : public z8002_device +{ +public: + // construction/destruction + z8001_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const + { + switch (spacenum) + { + case AS_PROGRAM: return &m_program_config; + case AS_DATA: return &m_data_config; + case AS_IO: return &m_io_config; + default: return NULL; + } + } + + // device_disasm_interface overrides + virtual UINT32 disasm_max_opcode_bytes() const { return 8; } + + address_space_config m_data_config; + + virtual int segmented_mode(); + virtual UINT32 adjust_addr_for_nonseg_mode(UINT32 addr); + virtual UINT16 RDPORT_W(int mode, UINT16 addr); + virtual void WRPORT_W(int mode, UINT16 addr, UINT16 value); + virtual void PUSH_PC(); + virtual void CHANGE_FCW(UINT16 fcw); + virtual UINT32 GET_PC(UINT32 VEC); + virtual UINT16 GET_FCW(UINT32 VEC); + virtual UINT32 F_SEG_Z8001(); + virtual UINT32 PSA_ADDR(); + virtual UINT32 read_irq_vector(); +}; + + +extern const device_type Z8001; +extern const device_type Z8002; + + +/* possible values for z8k_segm_mode */ +#define Z8K_SEGM_MODE_NONSEG 0 +#define Z8K_SEGM_MODE_SEG 1 +#define Z8K_SEGM_MODE_AUTO 2 + +#endif /* __Z8000_H__ */ diff --git a/src/devices/cpu/z8000/z8000cpu.h b/src/devices/cpu/z8000/z8000cpu.h new file mode 100644 index 00000000000..1a3f9e52b0f --- /dev/null +++ b/src/devices/cpu/z8000/z8000cpu.h @@ -0,0 +1,203 @@ +// license:BSD-3-Clause +// copyright-holders:Juergen Buchmueller,Ernesto Corvi +/***************************************************************************** + * + * z8000cpu.h + * Portable Z8000(2) emulator + * Macros and types used in z8000.c / z8000ops.inc / z8000tbl.inc + * + *****************************************************************************/ + +/************************************************************************** + * This is the register file layout: + * + * BYTE WORD LONG QUAD + * msb lsb bits bits bits + * RH0 - RL0 R 0 15- 0 RR 0 31-16 RQ 0 63-48 + * RH1 - RL1 R 1 15- 0 15- 0 47-32 + * RH2 - RL2 R 2 15- 0 RR 2 31-16 31-16 + * RH3 - RL3 R 3 15- 0 15- 0 15- 0 + * RH4 - RL4 R 4 15- 0 RR 4 31-16 RQ 4 63-48 + * RH5 - RL5 R 5 15- 0 15- 0 47-32 + * RH6 - RL6 R 6 15- 0 RR 6 31-16 31-16 + * RH7 - RL7 R 7 15- 0 15- 0 15- 0 + * R 8 15- 0 RR 8 31-16 RQ 8 63-48 + * R 9 15- 0 15- 0 47-32 + * R10 15- 0 RR10 31-16 31-16 + * R11 15- 0 15- 0 15- 0 + * R12 15- 0 RR12 31-16 RQ12 63-48 + * R13 15- 0 15- 0 47-32 + * R14 15- 0 RR14 31-16 31-16 + * R15 15- 0 15- 0 15- 0 + * + * Note that for LSB_FIRST machines we have the case that the RR registers + * use the lower numbered R registers in the higher bit positions. + * And also the RQ registers use the lower numbered RR registers in the + * higher bit positions. + * That's the reason for the ordering in the following pointer table. + **************************************************************************/ +#define RB(n) m_regs.B[BYTE8_XOR_BE((((n) & 7) << 1) | (((n) & 8) >> 3))] +#define RW(n) m_regs.W[BYTE4_XOR_BE(n)] +#define RL(n) m_regs.L[BYTE_XOR_BE((n) >> 1)] +#define RQ(n) m_regs.Q[(n) >> 2] + +/* the register used as stack pointer */ +#define SP (segmented_mode() ? 14 : 15) + +/* these vectors are based on m_psap */ +#define RST (PSA_ADDR() + 0) /* start up m_fcw and m_pc */ +#define EPU (PSA_ADDR() + m_vector_mult * 0x0004) /* extension processor unit? trap */ +#define TRAP (PSA_ADDR() + m_vector_mult * 0x0008) /* privilege violation trap */ +#define SYSCALL (PSA_ADDR() + m_vector_mult * 0x000c) /* system call SC */ +#define SEGTRAP (PSA_ADDR() + m_vector_mult * 0x0010) /* segment trap */ +#define NMI (PSA_ADDR() + m_vector_mult * 0x0014) /* non maskable interrupt */ +#define NVI (PSA_ADDR() + m_vector_mult * 0x0018) /* non vectored interrupt */ +#define VI (PSA_ADDR() + m_vector_mult * 0x001c) /* vectored interrupt */ +#define VEC00 (PSA_ADDR() + m_vector_mult * 0x001e) /* vector n m_pc value */ + +/* bits of the m_fcw */ +#define F_SEG 0x8000 /* segmented mode (Z8001 only) */ +#define F_S_N 0x4000 /* system / normal mode */ +#define F_EPU 0x2000 /* extension processor unit? */ +#define F_VIE 0x1000 /* vectored interrupt enable */ +#define F_NVIE 0x0800 /* non vectored interrupt enable */ +#define F_10 0x0400 /* unused */ +#define F_9 0x0200 /* unused */ +#define F_8 0x0100 /* unused */ +#define F_C 0x0080 /* carry flag */ +#define F_Z 0x0040 /* zero flag */ +#define F_S 0x0020 /* sign flag */ +#define F_PV 0x0010 /* parity/overflow flag */ +#define F_DA 0x0008 /* decimal adjust flag (0 add/adc, 1 sub/sbc) */ +#define F_H 0x0004 /* half carry flag (byte arithmetic only) */ +#define F_1 0x0002 /* unused */ +#define F_0 0x0001 /* unused */ + +/* opcode word numbers in m_op[] array */ +#define OP0 0 +#define OP1 1 +#define OP2 2 + +/* nibble shift factors for an opcode word */ +/* left to right: 0x1340 -> NIB0=1, NIB1=3, NIB2=4, NIB3=0 */ +#define NIB0 12 +#define NIB1 8 +#define NIB2 4 +#define NIB3 0 + +/* sign bit masks for byte, word and long */ +#define S08 0x80 +#define S16 0x8000 +#define S32 0x80000000 + +/* get a single flag bit 0/1 */ +#define GET_C ((m_fcw >> 7) & 1) +#define GET_Z ((m_fcw >> 6) & 1) +#define GET_S ((m_fcw >> 5) & 1) +#define GET_PV ((m_fcw >> 4) & 1) +#define GET_DA ((m_fcw >> 3) & 1) +#define GET_H ((m_fcw >> 2) & 1) + +/* clear a single flag bit */ +#define CLR_C m_fcw &= ~F_C +#define CLR_Z m_fcw &= ~F_Z +#define CLR_S m_fcw &= ~F_S +#define CLR_P m_fcw &= ~F_PV +#define CLR_V m_fcw &= ~F_PV +#define CLR_DA m_fcw &= ~F_DA +#define CLR_H m_fcw &= ~F_H + +/* clear a flag bit combination */ +#define CLR_CZS m_fcw &= ~(F_C|F_Z|F_S) +#define CLR_CZSP m_fcw &= ~(F_C|F_Z|F_S|F_PV) +#define CLR_CZSV m_fcw &= ~(F_C|F_Z|F_S|F_PV) +#define CLR_CZSVH m_fcw &= ~(F_C|F_Z|F_S|F_PV|F_H) +#define CLR_ZS m_fcw &= ~(F_Z|F_S) +#define CLR_ZSV m_fcw &= ~(F_Z|F_S|F_PV) +#define CLR_ZSP m_fcw &= ~(F_Z|F_S|F_PV) + +/* set a single flag bit */ +#define SET_C m_fcw |= F_C +#define SET_Z m_fcw |= F_Z +#define SET_S m_fcw |= F_S +#define SET_P m_fcw |= F_PV +#define SET_V m_fcw |= F_PV +#define SET_DA m_fcw |= F_DA +#define SET_H m_fcw |= F_H + +/* set a flag bit combination */ +#define SET_SC m_fcw |= F_C | F_S + +/* check condition codes */ +#define CC0 (0) /* always false */ +#define CC1 (GET_PV^GET_S) /* less than */ +#define CC2 (GET_Z|(GET_PV^GET_S)) /* less than or equal */ +#define CC3 (GET_Z|GET_C) /* unsigned less than or equal */ +#define CC4 GET_PV /* parity even / overflow */ +#define CC5 GET_S /* minus (signed) */ +#define CC6 GET_Z /* zero / equal */ +#define CC7 GET_C /* carry / unsigned less than */ + +#define CC8 (1) /* always true */ +#define CC9 !(GET_PV^GET_S) /* greater than or equal */ +#define CCA !(GET_Z|(GET_PV^GET_S)) /* greater than */ +#define CCB !(GET_Z|GET_C) /* unsigned greater than */ +#define CCC !GET_PV /* parity odd / no overflow */ +#define CCD !GET_S /* plus (not signed) */ +#define CCE !GET_Z /* not zero / not equal */ +#define CCF !GET_C /* not carry / unsigned greater than */ + +/* get data from the opcode words */ +/* o is the opcode word offset */ +/* s is a nibble shift factor */ +#define GET_BIT(o) UINT16 bit = 1 << (get_operand(o) & 15) +#define GET_CCC(o,s) UINT8 cc = (get_operand(o) >> (s)) & 15 + +#define GET_DST(o,s) UINT8 dst = (get_operand(o) >> (s)) & 15 +#define GET_SRC(o,s) UINT8 src = (get_operand(o) >> (s)) & 15 +#define GET_IDX(o,s) UINT8 idx = (get_operand(o) >> (s)) & 15 +#define GET_CNT(o,s) INT8 cnt = (get_operand(o) >> (s)) & 15 +#define GET_IMM4(o,s) UINT8 imm4 = (get_operand(o) >> (s)) & 15 + +#define GET_I4M1(o,s) UINT8 i4p1 = ((get_operand(o) >> (s)) & 15) + 1 +#define GET_IMM1(o,s) UINT8 imm1 = (get_operand(o) >> (s)) & 2 +#define GET_IMM2(o,s) UINT8 imm2 = (get_operand(o) >> (s)) & 3 +#define GET_IMM3(o,s) UINT8 imm3 = (get_operand(o) >> (s)) & 7 + +#define GET_IMM8(o) UINT8 imm8 = (UINT8)get_operand(o) + +#define GET_IMM16(o) UINT16 imm16 = get_operand(o) +#define GET_IDX16(o) UINT32 idx16 = get_operand(o) +#define GET_IMM32 UINT32 imm32 = (get_operand(1) << 16) + get_operand(2) +#define GET_DSP7 UINT8 dsp7 = get_operand(0) & 127 +#define GET_DSP8 INT8 dsp8 = (INT8)get_operand(0) +#define GET_DSP16 UINT32 dsp16 = addr_add(m_pc, (INT16)get_operand(1)) +#define GET_ADDR(o) UINT32 addr = (UINT32)get_addr_operand(o) +#define GET_ADDR_RAW(o) UINT32 addr = (UINT32)get_raw_addr_operand(o) + + +/* structure for the opcode definition table */ +typedef void (z8002_device::*opcode_func)(); + +struct Z8000_init { + int beg, end, step; + int size, cycles; + opcode_func opcode; + const char *dasm; + UINT32 dasmflags; +}; + +/* structure for the opcode execution table / disassembler */ +struct Z8000_exec { + opcode_func opcode; + int cycles; + int size; + const char *dasm; + UINT32 dasmflags; +}; + +/* opcode execution table */ +extern Z8000_exec *z8000_exec; + +extern void z8000_init_tables(void); +extern void z8000_deinit_tables(void); diff --git a/src/devices/cpu/z8000/z8000dab.h b/src/devices/cpu/z8000/z8000dab.h new file mode 100644 index 00000000000..44280993803 --- /dev/null +++ b/src/devices/cpu/z8000/z8000dab.h @@ -0,0 +1,277 @@ +// license:BSD-3-Clause +// copyright-holders:Juergen Buchmueller,Ernesto Corvi +/************************************************ + * Result table for Z8000 DAB instruction + * + * bits description + * ---------------------------------------------- + * 0..7 destination value + * 8 carry flag before + * 9 half carry flag before + * 10 D flag (0 add/adc, 1 sub/sbc) + * + * result description + * ---------------------------------------------- + * 0..7 result value + * 8 carry flag after + ************************************************/ +static const UINT16 Z8000_dab[0x800] = { + /* add/adc results */ + 0x000,0x001,0x002,0x003,0x004,0x005,0x006,0x007, + 0x008,0x009,0x010,0x011,0x012,0x013,0x014,0x015, + 0x010,0x011,0x012,0x013,0x014,0x015,0x016,0x017, + 0x018,0x019,0x020,0x021,0x022,0x023,0x024,0x025, + 0x020,0x021,0x022,0x023,0x024,0x025,0x026,0x027, + 0x028,0x029,0x030,0x031,0x032,0x033,0x034,0x035, + 0x030,0x031,0x032,0x033,0x034,0x035,0x036,0x037, + 0x038,0x039,0x040,0x041,0x042,0x043,0x044,0x045, + 0x040,0x041,0x042,0x043,0x044,0x045,0x046,0x047, + 0x048,0x049,0x050,0x051,0x052,0x053,0x054,0x055, + 0x050,0x051,0x052,0x053,0x054,0x055,0x056,0x057, + 0x058,0x059,0x060,0x061,0x062,0x063,0x064,0x065, + 0x060,0x061,0x062,0x063,0x064,0x065,0x066,0x067, + 0x068,0x069,0x070,0x071,0x072,0x073,0x074,0x075, + 0x070,0x071,0x072,0x073,0x074,0x075,0x076,0x077, + 0x078,0x079,0x080,0x081,0x082,0x083,0x084,0x085, + 0x080,0x081,0x082,0x083,0x084,0x085,0x086,0x087, + 0x088,0x089,0x090,0x091,0x092,0x093,0x094,0x095, + 0x090,0x091,0x092,0x093,0x094,0x095,0x096,0x097, + 0x098,0x099,0x100,0x101,0x102,0x103,0x104,0x105, + 0x100,0x101,0x102,0x103,0x104,0x105,0x106,0x107, + 0x108,0x109,0x110,0x111,0x112,0x113,0x114,0x115, + 0x110,0x111,0x112,0x113,0x114,0x115,0x116,0x117, + 0x118,0x119,0x120,0x121,0x122,0x123,0x124,0x125, + 0x120,0x121,0x122,0x123,0x124,0x125,0x126,0x127, + 0x128,0x129,0x130,0x131,0x132,0x133,0x134,0x135, + 0x130,0x131,0x132,0x133,0x134,0x135,0x136,0x137, + 0x138,0x139,0x140,0x141,0x142,0x143,0x144,0x145, + 0x140,0x141,0x142,0x143,0x144,0x145,0x146,0x147, + 0x148,0x149,0x150,0x151,0x152,0x153,0x154,0x155, + 0x150,0x151,0x152,0x153,0x154,0x155,0x156,0x157, + 0x158,0x159,0x160,0x161,0x162,0x163,0x164,0x165, + 0x166,0x167,0x168,0x169,0x16a,0x16b,0x16c,0x16d, + 0x16e,0x16f,0x170,0x171,0x172,0x173,0x174,0x175, + 0x176,0x177,0x178,0x179,0x17a,0x17b,0x17c,0x17d, + 0x17e,0x17f,0x180,0x181,0x182,0x183,0x184,0x185, + 0x186,0x187,0x188,0x189,0x18a,0x18b,0x18c,0x18d, + 0x18e,0x18f,0x190,0x191,0x192,0x193,0x194,0x195, + 0x196,0x197,0x198,0x199,0x19a,0x19b,0x19c,0x19d, + 0x19e,0x19f,0x1a0,0x1a1,0x1a2,0x1a3,0x1a4,0x1a5, + 0x1a6,0x1a7,0x1a8,0x1a9,0x1aa,0x1ab,0x1ac,0x1ad, + 0x1ae,0x1af,0x1b0,0x1b1,0x1b2,0x1b3,0x1b4,0x1b5, + 0x1b6,0x1b7,0x1b8,0x1b9,0x1ba,0x1bb,0x1bc,0x1bd, + 0x1be,0x1bf,0x1c0,0x1c1,0x1c2,0x1c3,0x1c4,0x1c5, + 0x1c6,0x1c7,0x1c8,0x1c9,0x1ca,0x1cb,0x1cc,0x1cd, + 0x1ce,0x1cf,0x1d0,0x1d1,0x1d2,0x1d3,0x1d4,0x1d5, + 0x1d6,0x1d7,0x1d8,0x1d9,0x1da,0x1db,0x1dc,0x1dd, + 0x1de,0x1df,0x1e0,0x1e1,0x1e2,0x1e3,0x1e4,0x1e5, + 0x1e6,0x1e7,0x1e8,0x1e9,0x1ea,0x1eb,0x1ec,0x1ed, + 0x1ee,0x1ef,0x1f0,0x1f1,0x1f2,0x1f3,0x1f4,0x1f5, + 0x1f6,0x1f7,0x1f8,0x1f9,0x1fa,0x1fb,0x1fc,0x1fd, + 0x1fe,0x1ff,0x100,0x101,0x102,0x103,0x104,0x105, + 0x106,0x107,0x108,0x109,0x10a,0x10b,0x10c,0x10d, + 0x10e,0x10f,0x110,0x111,0x112,0x113,0x114,0x115, + 0x116,0x117,0x118,0x119,0x11a,0x11b,0x11c,0x11d, + 0x11e,0x11f,0x120,0x121,0x122,0x123,0x124,0x125, + 0x126,0x127,0x128,0x129,0x12a,0x12b,0x12c,0x12d, + 0x12e,0x12f,0x130,0x131,0x132,0x133,0x134,0x135, + 0x136,0x137,0x138,0x139,0x13a,0x13b,0x13c,0x13d, + 0x13e,0x13f,0x140,0x141,0x142,0x143,0x144,0x145, + 0x146,0x147,0x148,0x149,0x14a,0x14b,0x14c,0x14d, + 0x14e,0x14f,0x150,0x151,0x152,0x153,0x154,0x155, + 0x156,0x157,0x158,0x159,0x15a,0x15b,0x15c,0x15d, + 0x15e,0x15f,0x160,0x161,0x162,0x163,0x164,0x165, + 0x166,0x167,0x168,0x169,0x16a,0x16b,0x16c,0x16d, + 0x16e,0x16f,0x170,0x171,0x172,0x173,0x174,0x175, + 0x176,0x177,0x178,0x179,0x17a,0x17b,0x17c,0x17d, + 0x17e,0x17f,0x180,0x181,0x182,0x183,0x184,0x185, + 0x186,0x187,0x188,0x189,0x18a,0x18b,0x18c,0x18d, + 0x18e,0x18f,0x190,0x191,0x192,0x193,0x194,0x195, + 0x196,0x197,0x198,0x199,0x19a,0x19b,0x19c,0x19d, + 0x19e,0x19f,0x1a0,0x1a1,0x1a2,0x1a3,0x1a4,0x1a5, + 0x1a6,0x1a7,0x1a8,0x1a9,0x1aa,0x1ab,0x1ac,0x1ad, + 0x1ae,0x1af,0x1b0,0x1b1,0x1b2,0x1b3,0x1b4,0x1b5, + 0x1b6,0x1b7,0x1b8,0x1b9,0x1ba,0x1bb,0x1bc,0x1bd, + 0x1be,0x1bf,0x1c0,0x1c1,0x1c2,0x1c3,0x1c4,0x1c5, + 0x1c6,0x1c7,0x1c8,0x1c9,0x1ca,0x1cb,0x1cc,0x1cd, + 0x1ce,0x1cf,0x1d0,0x1d1,0x1d2,0x1d3,0x1d4,0x1d5, + 0x1d6,0x1d7,0x1d8,0x1d9,0x1da,0x1db,0x1dc,0x1dd, + 0x1de,0x1df,0x1e0,0x1e1,0x1e2,0x1e3,0x1e4,0x1e5, + 0x1e6,0x1e7,0x1e8,0x1e9,0x1ea,0x1eb,0x1ec,0x1ed, + 0x1ee,0x1ef,0x1f0,0x1f1,0x1f2,0x1f3,0x1f4,0x1f5, + 0x1f6,0x1f7,0x1f8,0x1f9,0x1fa,0x1fb,0x1fc,0x1fd, + 0x1fe,0x1ff,0x100,0x101,0x102,0x103,0x104,0x105, + 0x106,0x107,0x108,0x109,0x10a,0x10b,0x10c,0x10d, + 0x10e,0x10f,0x110,0x111,0x112,0x113,0x114,0x115, + 0x116,0x117,0x118,0x119,0x11a,0x11b,0x11c,0x11d, + 0x11e,0x11f,0x120,0x121,0x122,0x123,0x124,0x125, + 0x126,0x127,0x128,0x129,0x12a,0x12b,0x12c,0x12d, + 0x12e,0x12f,0x130,0x131,0x132,0x133,0x134,0x135, + 0x136,0x137,0x138,0x139,0x13a,0x13b,0x13c,0x13d, + 0x13e,0x13f,0x140,0x141,0x142,0x143,0x144,0x145, + 0x146,0x147,0x148,0x149,0x14a,0x14b,0x14c,0x14d, + 0x14e,0x14f,0x150,0x151,0x152,0x153,0x154,0x155, + 0x156,0x157,0x158,0x159,0x15a,0x15b,0x15c,0x15d, + 0x15e,0x15f,0x160,0x161,0x162,0x163,0x164,0x165, + 0x166,0x167,0x168,0x169,0x16a,0x16b,0x16c,0x16d, + 0x16e,0x16f,0x170,0x171,0x172,0x173,0x174,0x175, + 0x176,0x177,0x178,0x179,0x17a,0x17b,0x17c,0x17d, + 0x17e,0x17f,0x180,0x181,0x182,0x183,0x184,0x185, + 0x186,0x187,0x188,0x189,0x18a,0x18b,0x18c,0x18d, + 0x18e,0x18f,0x190,0x191,0x192,0x193,0x194,0x195, + 0x196,0x197,0x198,0x199,0x19a,0x19b,0x19c,0x19d, + 0x19e,0x19f,0x1a0,0x1a1,0x1a2,0x1a3,0x1a4,0x1a5, + 0x1a6,0x1a7,0x1a8,0x1a9,0x1aa,0x1ab,0x1ac,0x1ad, + 0x1ae,0x1af,0x1b0,0x1b1,0x1b2,0x1b3,0x1b4,0x1b5, + 0x1b6,0x1b7,0x1b8,0x1b9,0x1ba,0x1bb,0x1bc,0x1bd, + 0x1be,0x1bf,0x1c0,0x1c1,0x1c2,0x1c3,0x1c4,0x1c5, + 0x1c6,0x1c7,0x1c8,0x1c9,0x1ca,0x1cb,0x1cc,0x1cd, + 0x1ce,0x1cf,0x1d0,0x1d1,0x1d2,0x1d3,0x1d4,0x1d5, + 0x1d6,0x1d7,0x1d8,0x1d9,0x1da,0x1db,0x1dc,0x1dd, + 0x1de,0x1df,0x1e0,0x1e1,0x1e2,0x1e3,0x1e4,0x1e5, + 0x1e6,0x1e7,0x1e8,0x1e9,0x1ea,0x1eb,0x1ec,0x1ed, + 0x1ee,0x1ef,0x1f0,0x1f1,0x1f2,0x1f3,0x1f4,0x1f5, + 0x1f6,0x1f7,0x1f8,0x1f9,0x1fa,0x1fb,0x1fc,0x1fd, + 0x1fe,0x1ff,0x100,0x101,0x102,0x103,0x104,0x105, + 0x106,0x107,0x108,0x109,0x10a,0x10b,0x10c,0x10d, + 0x10e,0x10f,0x110,0x111,0x112,0x113,0x114,0x115, + 0x116,0x117,0x118,0x119,0x11a,0x11b,0x11c,0x11d, + 0x11e,0x11f,0x120,0x121,0x122,0x123,0x124,0x125, + 0x126,0x127,0x128,0x129,0x12a,0x12b,0x12c,0x12d, + 0x12e,0x12f,0x130,0x131,0x132,0x133,0x134,0x135, + 0x136,0x137,0x138,0x139,0x13a,0x13b,0x13c,0x13d, + 0x13e,0x13f,0x140,0x141,0x142,0x143,0x144,0x145, + 0x146,0x147,0x148,0x149,0x14a,0x14b,0x14c,0x14d, + 0x14e,0x14f,0x150,0x151,0x152,0x153,0x154,0x155, + 0x156,0x157,0x158,0x159,0x15a,0x15b,0x15c,0x15d, + 0x15e,0x15f,0x160,0x161,0x162,0x163,0x164,0x165, + /* sub/sbc results */ + 0x000,0x001,0x002,0x003,0x004,0x005,0x006,0x007, + 0x008,0x009,0x00a,0x00b,0x00c,0x00d,0x00e,0x00f, + 0x010,0x011,0x012,0x013,0x014,0x015,0x016,0x017, + 0x018,0x019,0x01a,0x01b,0x01c,0x01d,0x01e,0x01f, + 0x020,0x021,0x022,0x023,0x024,0x025,0x026,0x027, + 0x028,0x029,0x02a,0x02b,0x02c,0x02d,0x02e,0x02f, + 0x030,0x031,0x032,0x033,0x034,0x035,0x036,0x037, + 0x038,0x039,0x03a,0x03b,0x03c,0x03d,0x03e,0x03f, + 0x040,0x041,0x042,0x043,0x044,0x045,0x046,0x047, + 0x048,0x049,0x04a,0x04b,0x04c,0x04d,0x04e,0x04f, + 0x050,0x051,0x052,0x053,0x054,0x055,0x056,0x057, + 0x058,0x059,0x05a,0x05b,0x05c,0x05d,0x05e,0x05f, + 0x060,0x061,0x062,0x063,0x064,0x065,0x066,0x067, + 0x068,0x069,0x06a,0x06b,0x06c,0x06d,0x06e,0x06f, + 0x070,0x071,0x072,0x073,0x074,0x075,0x076,0x077, + 0x078,0x079,0x07a,0x07b,0x07c,0x07d,0x07e,0x07f, + 0x080,0x081,0x082,0x083,0x084,0x085,0x086,0x087, + 0x088,0x089,0x08a,0x08b,0x08c,0x08d,0x08e,0x08f, + 0x090,0x091,0x092,0x093,0x094,0x095,0x096,0x097, + 0x098,0x099,0x09a,0x09b,0x09c,0x09d,0x09e,0x09f, + 0x0a0,0x0a1,0x0a2,0x0a3,0x0a4,0x0a5,0x0a6,0x0a7, + 0x0a8,0x0a9,0x0aa,0x0ab,0x0ac,0x0ad,0x0ae,0x0af, + 0x0b0,0x0b1,0x0b2,0x0b3,0x0b4,0x0b5,0x0b6,0x0b7, + 0x0b8,0x0b9,0x0ba,0x0bb,0x0bc,0x0bd,0x0be,0x0bf, + 0x0c0,0x0c1,0x0c2,0x0c3,0x0c4,0x0c5,0x0c6,0x0c7, + 0x0c8,0x0c9,0x0ca,0x0cb,0x0cc,0x0cd,0x0ce,0x0cf, + 0x0d0,0x0d1,0x0d2,0x0d3,0x0d4,0x0d5,0x0d6,0x0d7, + 0x0d8,0x0d9,0x0da,0x0db,0x0dc,0x0dd,0x0de,0x0df, + 0x0e0,0x0e1,0x0e2,0x0e3,0x0e4,0x0e5,0x0e6,0x0e7, + 0x0e8,0x0e9,0x0ea,0x0eb,0x0ec,0x0ed,0x0ee,0x0ef, + 0x0f0,0x0f1,0x0f2,0x0f3,0x0f4,0x0f5,0x0f6,0x0f7, + 0x0f8,0x0f9,0x0fa,0x0fb,0x0fc,0x0fd,0x0fe,0x0ff, + 0x1a0,0x1a1,0x1a2,0x1a3,0x1a4,0x1a5,0x1a6,0x1a7, + 0x1a8,0x1a9,0x1aa,0x1ab,0x1ac,0x1ad,0x1ae,0x1af, + 0x1b0,0x1b1,0x1b2,0x1b3,0x1b4,0x1b5,0x1b6,0x1b7, + 0x1b8,0x1b9,0x1ba,0x1bb,0x1bc,0x1bd,0x1be,0x1bf, + 0x1c0,0x1c1,0x1c2,0x1c3,0x1c4,0x1c5,0x1c6,0x1c7, + 0x1c8,0x1c9,0x1ca,0x1cb,0x1cc,0x1cd,0x1ce,0x1cf, + 0x1d0,0x1d1,0x1d2,0x1d3,0x1d4,0x1d5,0x1d6,0x1d7, + 0x1d8,0x1d9,0x1da,0x1db,0x1dc,0x1dd,0x1de,0x1df, + 0x1e0,0x1e1,0x1e2,0x1e3,0x1e4,0x1e5,0x1e6,0x1e7, + 0x1e8,0x1e9,0x1ea,0x1eb,0x1ec,0x1ed,0x1ee,0x1ef, + 0x1f0,0x1f1,0x1f2,0x1f3,0x1f4,0x1f5,0x1f6,0x1f7, + 0x1f8,0x1f9,0x1fa,0x1fb,0x1fc,0x1fd,0x1fe,0x1ff, + 0x100,0x101,0x102,0x103,0x104,0x105,0x106,0x107, + 0x108,0x109,0x10a,0x10b,0x10c,0x10d,0x10e,0x10f, + 0x110,0x111,0x112,0x113,0x114,0x115,0x116,0x117, + 0x118,0x119,0x11a,0x11b,0x11c,0x11d,0x11e,0x11f, + 0x120,0x121,0x122,0x123,0x124,0x125,0x126,0x127, + 0x128,0x129,0x12a,0x12b,0x12c,0x12d,0x12e,0x12f, + 0x130,0x131,0x132,0x133,0x134,0x135,0x136,0x137, + 0x138,0x139,0x13a,0x13b,0x13c,0x13d,0x13e,0x13f, + 0x140,0x141,0x142,0x143,0x144,0x145,0x146,0x147, + 0x148,0x149,0x14a,0x14b,0x14c,0x14d,0x14e,0x14f, + 0x150,0x151,0x152,0x153,0x154,0x155,0x156,0x157, + 0x158,0x159,0x15a,0x15b,0x15c,0x15d,0x15e,0x15f, + 0x160,0x161,0x162,0x163,0x164,0x165,0x166,0x167, + 0x168,0x169,0x16a,0x16b,0x16c,0x16d,0x16e,0x16f, + 0x170,0x171,0x172,0x173,0x174,0x175,0x176,0x177, + 0x178,0x179,0x17a,0x17b,0x17c,0x17d,0x17e,0x17f, + 0x180,0x181,0x182,0x183,0x184,0x185,0x186,0x187, + 0x188,0x189,0x18a,0x18b,0x18c,0x18d,0x18e,0x18f, + 0x190,0x191,0x192,0x193,0x194,0x195,0x196,0x197, + 0x198,0x199,0x19a,0x19b,0x19c,0x19d,0x19e,0x19f, + 0x1fa,0x1fb,0x1fc,0x1fd,0x1fe,0x1ff,0x100,0x101, + 0x102,0x103,0x104,0x105,0x106,0x107,0x108,0x109, + 0x10a,0x10b,0x10c,0x10d,0x10e,0x10f,0x110,0x111, + 0x112,0x113,0x114,0x115,0x116,0x117,0x118,0x119, + 0x11a,0x11b,0x11c,0x11d,0x11e,0x11f,0x120,0x121, + 0x122,0x123,0x124,0x125,0x126,0x127,0x128,0x129, + 0x12a,0x12b,0x12c,0x12d,0x12e,0x12f,0x130,0x131, + 0x132,0x133,0x134,0x135,0x136,0x137,0x138,0x139, + 0x13a,0x13b,0x13c,0x13d,0x13e,0x13f,0x140,0x141, + 0x142,0x143,0x144,0x145,0x146,0x147,0x148,0x149, + 0x14a,0x14b,0x14c,0x14d,0x14e,0x14f,0x150,0x151, + 0x152,0x153,0x154,0x155,0x156,0x157,0x158,0x159, + 0x15a,0x15b,0x15c,0x15d,0x15e,0x15f,0x160,0x161, + 0x162,0x163,0x164,0x165,0x166,0x167,0x168,0x169, + 0x16a,0x16b,0x16c,0x16d,0x16e,0x16f,0x170,0x171, + 0x172,0x173,0x174,0x175,0x176,0x177,0x178,0x179, + 0x17a,0x17b,0x17c,0x17d,0x17e,0x17f,0x180,0x181, + 0x182,0x183,0x184,0x185,0x186,0x187,0x188,0x189, + 0x18a,0x18b,0x18c,0x18d,0x18e,0x18f,0x190,0x191, + 0x192,0x193,0x194,0x195,0x196,0x197,0x198,0x199, + 0x19a,0x19b,0x19c,0x19d,0x19e,0x19f,0x1a0,0x1a1, + 0x1a2,0x1a3,0x1a4,0x1a5,0x1a6,0x1a7,0x1a8,0x1a9, + 0x1aa,0x1ab,0x1ac,0x1ad,0x1ae,0x1af,0x1b0,0x1b1, + 0x1b2,0x1b3,0x1b4,0x1b5,0x1b6,0x1b7,0x1b8,0x1b9, + 0x1ba,0x1bb,0x1bc,0x1bd,0x1be,0x1bf,0x1c0,0x1c1, + 0x1c2,0x1c3,0x1c4,0x1c5,0x1c6,0x1c7,0x1c8,0x1c9, + 0x1ca,0x1cb,0x1cc,0x1cd,0x1ce,0x1cf,0x1d0,0x1d1, + 0x1d2,0x1d3,0x1d4,0x1d5,0x1d6,0x1d7,0x1d8,0x1d9, + 0x1da,0x1db,0x1dc,0x1dd,0x1de,0x1df,0x1e0,0x1e1, + 0x1e2,0x1e3,0x1e4,0x1e5,0x1e6,0x1e7,0x1e8,0x1e9, + 0x1ea,0x1eb,0x1ec,0x1ed,0x1ee,0x1ef,0x1f0,0x1f1, + 0x1f2,0x1f3,0x1f4,0x1f5,0x1f6,0x1f7,0x1f8,0x1f9, + 0x19a,0x19b,0x19c,0x19d,0x19e,0x19f,0x1a0,0x1a1, + 0x1a2,0x1a3,0x1a4,0x1a5,0x1a6,0x1a7,0x1a8,0x1a9, + 0x1aa,0x1ab,0x1ac,0x1ad,0x1ae,0x1af,0x1b0,0x1b1, + 0x1b2,0x1b3,0x1b4,0x1b5,0x1b6,0x1b7,0x1b8,0x1b9, + 0x1ba,0x1bb,0x1bc,0x1bd,0x1be,0x1bf,0x1c0,0x1c1, + 0x1c2,0x1c3,0x1c4,0x1c5,0x1c6,0x1c7,0x1c8,0x1c9, + 0x1ca,0x1cb,0x1cc,0x1cd,0x1ce,0x1cf,0x1d0,0x1d1, + 0x1d2,0x1d3,0x1d4,0x1d5,0x1d6,0x1d7,0x1d8,0x1d9, + 0x1da,0x1db,0x1dc,0x1dd,0x1de,0x1df,0x1e0,0x1e1, + 0x1e2,0x1e3,0x1e4,0x1e5,0x1e6,0x1e7,0x1e8,0x1e9, + 0x1ea,0x1eb,0x1ec,0x1ed,0x1ee,0x1ef,0x1f0,0x1f1, + 0x1f2,0x1f3,0x1f4,0x1f5,0x1f6,0x1f7,0x1f8,0x1f9, + 0x1fa,0x1fb,0x1fc,0x1fd,0x1fe,0x1ff,0x100,0x101, + 0x102,0x103,0x104,0x105,0x106,0x107,0x108,0x109, + 0x10a,0x10b,0x10c,0x10d,0x10e,0x10f,0x110,0x111, + 0x112,0x113,0x114,0x115,0x116,0x117,0x118,0x119, + 0x11a,0x11b,0x11c,0x11d,0x11e,0x11f,0x120,0x121, + 0x122,0x123,0x124,0x125,0x126,0x127,0x128,0x129, + 0x12a,0x12b,0x12c,0x12d,0x12e,0x12f,0x130,0x131, + 0x132,0x133,0x134,0x135,0x136,0x137,0x138,0x139, + 0x13a,0x13b,0x13c,0x13d,0x13e,0x13f,0x140,0x141, + 0x142,0x143,0x144,0x145,0x146,0x147,0x148,0x149, + 0x14a,0x14b,0x14c,0x14d,0x14e,0x14f,0x150,0x151, + 0x152,0x153,0x154,0x155,0x156,0x157,0x158,0x159, + 0x15a,0x15b,0x15c,0x15d,0x15e,0x15f,0x160,0x161, + 0x162,0x163,0x164,0x165,0x166,0x167,0x168,0x169, + 0x16a,0x16b,0x16c,0x16d,0x16e,0x16f,0x170,0x171, + 0x172,0x173,0x174,0x175,0x176,0x177,0x178,0x179, + 0x17a,0x17b,0x17c,0x17d,0x17e,0x17f,0x180,0x181, + 0x182,0x183,0x184,0x185,0x186,0x187,0x188,0x189, + 0x18a,0x18b,0x18c,0x18d,0x18e,0x18f,0x190,0x191, + 0x192,0x193,0x194,0x195,0x196,0x197,0x198,0x199, +}; diff --git a/src/devices/cpu/z8000/z8000ops.inc b/src/devices/cpu/z8000/z8000ops.inc new file mode 100644 index 00000000000..c9d0b365783 --- /dev/null +++ b/src/devices/cpu/z8000/z8000ops.inc @@ -0,0 +1,6811 @@ +// license:BSD-3-Clause +// copyright-holders:Juergen Buchmueller,Ernesto Corvi +/***************************************************************************** + * + * z8000ops.inc + * Portable Z8000(2) emulator + * Opcode functions + * + *****************************************************************************/ + +/****************************************** + helper functions + ******************************************/ + +/****************************************** + check new fcw for switch to system mode + and swap stack pointer if needed + ******************************************/ +void z8002_device::CHANGE_FCW(UINT16 fcw) +{ + UINT16 tmp; + if ((fcw ^ m_fcw) & F_S_N) /* system/user mode change? */ + { + tmp = RW(15); + RW(15) = m_nspoff; + m_nspoff = tmp; + } + + fcw &= ~F_SEG; /* never set segmented mode bit on Z8002 */ + + if (!(m_fcw & F_NVIE) && (fcw & F_NVIE) && (m_irq_state[0] != CLEAR_LINE)) + { + m_irq_req |= Z8000_NVI; + } + if (!(m_fcw & F_VIE) && (fcw & F_VIE) && (m_irq_state[1] != CLEAR_LINE)) + { + m_irq_req |= Z8000_VI; + } + m_fcw = fcw; /* set new m_fcw */ +} + +void z8001_device::CHANGE_FCW(UINT16 fcw) +{ + UINT16 tmp; + if ((fcw ^ m_fcw) & F_S_N) /* system/user mode change? */ + { + tmp = RW(15); + RW(15) = m_nspoff; + m_nspoff = tmp; + } + /* User mode R14 is used in user mode and non-segmented system mode. + System mode R14 is only used in segmented system mode. + There is no transition from user mode to non-segmented system mode, + so this doesn't need to be handled here. */ + if (fcw & F_S_N) /* new mode is system mode */ + { + if (!(m_fcw & F_S_N) /* old mode was user mode */ + || ((fcw ^ m_fcw) & F_SEG)) /* or switch between segmented and non-segmented */ + { + tmp = RW(14); + RW(14) = m_nspseg; + m_nspseg = tmp; + } + } + else /* new mode is user mode */ + { + if (m_fcw & F_S_N /* old mode was system mode */ + && m_fcw & F_SEG) /* and was segmented */ + { + tmp = RW(14); + RW(14) = m_nspseg; + m_nspseg = tmp; + } + } + + if (!(m_fcw & F_NVIE) && (fcw & F_NVIE) && (m_irq_state[0] != CLEAR_LINE)) + { + m_irq_req |= Z8000_NVI; + } + if (!(m_fcw & F_VIE) && (fcw & F_VIE) && (m_irq_state[1] != CLEAR_LINE)) + { + m_irq_req |= Z8000_VI; + } + m_fcw = fcw; /* set new m_fcw */ +} + +UINT32 z8002_device::make_segmented_addr(UINT32 addr) +{ + return ((addr & 0x007f0000) << 8) | 0x80000000 | (addr & 0xffff); +} + +UINT32 z8002_device::segmented_addr(UINT32 addr) +{ + return ((addr & 0x7f000000) >> 8) | (addr & 0xffff); +} + +UINT32 z8002_device::addr_from_reg(int regno) +{ + if (segmented_mode()) + return segmented_addr(RL(regno)); + else + return RW(regno); +} + +void z8002_device::addr_to_reg(int regno, UINT32 addr) +{ + if (segmented_mode()) { + UINT32 segaddr = make_segmented_addr(addr); + RW(regno) = (RW(regno) & 0x80ff) | ((segaddr >> 16) & 0x7f00); + RW(regno | 1) = segaddr & 0xffff; + } + else + RW(regno) = addr; +} + +void z8002_device::add_to_addr_reg(int regno, UINT16 addend) +{ + if (segmented_mode()) + regno |= 1; + RW(regno) += addend; +} + +void z8002_device::sub_from_addr_reg(int regno, UINT16 subtrahend) +{ + if (segmented_mode()) + regno |= 1; + RW(regno) -= subtrahend; +} + +void z8002_device::set_pc(UINT32 addr) +{ + if (segmented_mode()) + m_pc = addr; + else + m_pc = (m_pc & 0xffff0000) | (addr & 0xffff); +} + +void z8002_device::PUSHW(UINT8 dst, UINT16 value) +{ + if (segmented_mode()) + RW(dst | 1) -= 2; + else + RW(dst) -= 2; + WRMEM_W(AS_DATA, addr_from_reg(dst), value); +} + +UINT16 z8002_device::POPW(UINT8 src) +{ + UINT16 result = RDMEM_W(AS_DATA, addr_from_reg(src)); + if (segmented_mode()) + RW(src | 1) += 2; + else + RW(src) += 2; + return result; +} + +void z8002_device::PUSHL(UINT8 dst, UINT32 value) +{ + if (segmented_mode()) + RW(dst | 1) -= 4; + else + RW(dst) -= 4; + WRMEM_L(AS_DATA, addr_from_reg(dst), value); +} + +UINT32 z8002_device::POPL(UINT8 src) +{ + UINT32 result = RDMEM_L(AS_DATA, addr_from_reg(src)); + if (segmented_mode()) + RW(src | 1) += 4; + else + RW(src) += 4; + return result; +} + +/* check zero and sign flag for byte, word and long results */ +#define CHK_XXXB_ZS if (!result) SET_Z; else if ((INT8) result < 0) SET_S +#define CHK_XXXW_ZS if (!result) SET_Z; else if ((INT16)result < 0) SET_S +#define CHK_XXXL_ZS if (!result) SET_Z; else if ((INT32)result < 0) SET_S +#define CHK_XXXQ_ZS if (!result) SET_Z; else if ((INT64)result < 0) SET_S + +#define CHK_XXXB_ZSP m_fcw |= z8000_zsp[result] + +/* check carry for addition and subtraction */ +#define CHK_ADDX_C if (result < dest) SET_C +#define CHK_ADCX_C if (result < dest || (result == dest && value)) SET_C + +#define CHK_SUBX_C if (result > dest) SET_C +#define CHK_SBCX_C if (result > dest || (result == dest && value)) SET_C + +/* check half carry for A addition and S subtraction */ +#define CHK_ADDB_H if ((result & 15) < (dest & 15)) SET_H +#define CHK_ADCB_H if ((result & 15) < (dest & 15) || ((result & 15) == (dest & 15) && (value & 15))) SET_H + +#define CHK_SUBB_H if ((result & 15) > (dest & 15)) SET_H +#define CHK_SBCB_H if ((result & 15) > (dest & 15) || ((result & 15) == (dest & 15) && (value & 15))) SET_H + +/* check overflow for addition for byte, word and long */ +#define CHK_ADDB_V if (((value & dest & ~result) | (~value & ~dest & result)) & S08) SET_V +#define CHK_ADDW_V if (((value & dest & ~result) | (~value & ~dest & result)) & S16) SET_V +#define CHK_ADDL_V if (((value & dest & ~result) | (~value & ~dest & result)) & S32) SET_V + +/* check overflow for subtraction for byte, word and long */ +#define CHK_SUBB_V if (((~value & dest & ~result) | (value & ~dest & result)) & S08) SET_V +#define CHK_SUBW_V if (((~value & dest & ~result) | (value & ~dest & result)) & S16) SET_V +#define CHK_SUBL_V if (((~value & dest & ~result) | (value & ~dest & result)) & S32) SET_V + +/* check for privileged instruction and trap if executed */ +#define CHECK_PRIVILEGED_INSTR() if (!(m_fcw & F_S_N)) { m_irq_req = Z8000_TRAP; return; } + +/* if no EPU is present (it isn't), raise an extended intstuction trap */ +#define CHECK_EXT_INSTR() if (!(m_fcw & F_EPU)) { m_irq_req = Z8000_EPU; return; } + + +/****************************************** + add byte + flags: CZSVDH + ******************************************/ +UINT8 z8002_device::ADDB(UINT8 dest, UINT8 value) +{ + UINT8 result = dest + value; + CLR_CZSVH; /* first clear C, Z, S, P/V and H flags */ + CLR_DA; /* clear DA (decimal adjust) flag for addb */ + CHK_XXXB_ZS; /* set Z and S flags for result byte */ + CHK_ADDX_C; /* set C if result overflowed */ + CHK_ADDB_V; /* set V if result has incorrect sign */ + CHK_ADDB_H; /* set H if lower nibble overflowed */ + return result; +} + +/****************************************** + add word + flags: CZSV-- + ******************************************/ +UINT16 z8002_device::ADDW(UINT16 dest, UINT16 value) +{ + UINT16 result = dest + value; + CLR_CZSV; /* first clear C, Z, S, P/V flags */ + CHK_XXXW_ZS; /* set Z and S flags for result word */ + CHK_ADDX_C; /* set C if result overflowed */ + CHK_ADDW_V; /* set V if result has incorrect sign */ + return result; +} + +/****************************************** + add long + flags: CZSV-- + ******************************************/ +UINT32 z8002_device::ADDL(UINT32 dest, UINT32 value) +{ + UINT32 result = dest + value; + CLR_CZSV; /* first clear C, Z, S, P/V flags */ + CHK_XXXL_ZS; /* set Z and S flags for result long */ + CHK_ADDX_C; /* set C if result overflowed */ + CHK_ADDL_V; /* set V if result has incorrect sign */ + return result; +} + +/****************************************** + add with carry byte + flags: CZSVDH + ******************************************/ +UINT8 z8002_device::ADCB(UINT8 dest, UINT8 value) +{ + UINT8 result = dest + value + GET_C; + CLR_CZSVH; /* first clear C, Z, S, P/V and H flags */ + CLR_DA; /* clear DA (decimal adjust) flag for adcb */ + CHK_XXXB_ZS; /* set Z and S flags for result byte */ + CHK_ADCX_C; /* set C if result overflowed */ + CHK_ADDB_V; /* set V if result has incorrect sign */ + CHK_ADCB_H; /* set H if lower nibble overflowed */ + return result; +} + +/****************************************** + add with carry word + flags: CZSV-- + ******************************************/ +UINT16 z8002_device::ADCW(UINT16 dest, UINT16 value) +{ + UINT16 result = dest + value + GET_C; + CLR_CZSV; /* first clear C, Z, S, P/V flags */ + CHK_XXXW_ZS; /* set Z and S flags for result word */ + CHK_ADCX_C; /* set C if result overflowed */ + CHK_ADDW_V; /* set V if result has incorrect sign */ + return result; +} + +/****************************************** + subtract byte + flags: CZSVDH + ******************************************/ +UINT8 z8002_device::SUBB(UINT8 dest, UINT8 value) +{ + UINT8 result = dest - value; + CLR_CZSVH; /* first clear C, Z, S, P/V and H flags */ + SET_DA; /* set DA (decimal adjust) flag for subb */ + CHK_XXXB_ZS; /* set Z and S flags for result byte */ + CHK_SUBX_C; /* set C if result underflowed */ + CHK_SUBB_V; /* set V if result has incorrect sign */ + CHK_SUBB_H; /* set H if lower nibble underflowed */ + return result; +} + +/****************************************** + subtract word + flags: CZSV-- + ******************************************/ +UINT16 z8002_device::SUBW(UINT16 dest, UINT16 value) +{ + UINT16 result = dest - value; + CLR_CZSV; /* first clear C, Z, S, P/V flags */ + CHK_XXXW_ZS; /* set Z and S flags for result word */ + CHK_SUBX_C; /* set C if result underflowed */ + CHK_SUBW_V; /* set V if result has incorrect sign */ + return result; +} + +/****************************************** + subtract long + flags: CZSV-- + ******************************************/ +UINT32 z8002_device::SUBL(UINT32 dest, UINT32 value) +{ + UINT32 result = dest - value; + CLR_CZSV; /* first clear C, Z, S, P/V flags */ + CHK_XXXL_ZS; /* set Z and S flags for result long */ + CHK_SUBX_C; /* set C if result underflowed */ + CHK_SUBL_V; /* set V if result has incorrect sign */ + return result; +} + +/****************************************** + subtract with carry byte + flags: CZSVDH + ******************************************/ +UINT8 z8002_device::SBCB(UINT8 dest, UINT8 value) +{ + UINT8 result = dest - value - GET_C; + CLR_CZSVH; /* first clear C, Z, S, P/V and H flags */ + SET_DA; /* set DA (decimal adjust) flag for sbcb */ + CHK_XXXB_ZS; /* set Z and S flags for result byte */ + CHK_SBCX_C; /* set C if result underflowed */ + CHK_SUBB_V; /* set V if result has incorrect sign */ + CHK_SBCB_H; /* set H if lower nibble underflowed */ + return result; +} + +/****************************************** + subtract with carry word + flags: CZSV-- + ******************************************/ +UINT16 z8002_device::SBCW(UINT16 dest, UINT16 value) +{ + UINT16 result = dest - value - GET_C; + CLR_CZSV; /* first clear C, Z, S, P/V flags */ + CHK_XXXW_ZS; /* set Z and S flags for result word */ + CHK_SBCX_C; /* set C if result underflowed */ + CHK_SUBW_V; /* set V if result has incorrect sign */ + return result; +} + +/****************************************** + logical or byte + flags: -ZSP-- + ******************************************/ +UINT8 z8002_device::ORB(UINT8 dest, UINT8 value) +{ + UINT8 result = dest | value; + CLR_ZSP; /* first clear Z, S, P/V flags */ + CHK_XXXB_ZSP; /* set Z, S and P flags for result byte */ + return result; +} + +/****************************************** + logical or word + flags: -ZS--- + ******************************************/ +UINT16 z8002_device::ORW(UINT16 dest, UINT16 value) +{ + UINT16 result = dest | value; + CLR_ZS; /* first clear Z, and S flags */ + CHK_XXXW_ZS; /* set Z and S flags for result word */ + return result; +} + +/****************************************** + logical and byte + flags: -ZSP-- + ******************************************/ +UINT8 z8002_device::ANDB(UINT8 dest, UINT8 value) +{ + UINT8 result = dest & value; + CLR_ZSP; /* first clear Z,S and P/V flags */ + CHK_XXXB_ZSP; /* set Z, S and P flags for result byte */ + return result; +} + +/****************************************** + logical and word + flags: -ZS--- + ******************************************/ +UINT16 z8002_device::ANDW(UINT16 dest, UINT16 value) +{ + UINT16 result = dest & value; + CLR_ZS; /* first clear Z and S flags */ + CHK_XXXW_ZS; /* set Z and S flags for result word */ + return result; +} + +/****************************************** + logical exclusive or byte + flags: -ZSP-- + ******************************************/ +UINT8 z8002_device::XORB(UINT8 dest, UINT8 value) +{ + UINT8 result = dest ^ value; + CLR_ZSP; /* first clear Z, S and P/V flags */ + CHK_XXXB_ZSP; /* set Z, S and P flags for result byte */ + return result; +} + +/****************************************** + logical exclusive or word + flags: -ZS--- + ******************************************/ +UINT16 z8002_device::XORW(UINT16 dest, UINT16 value) +{ + UINT16 result = dest ^ value; + CLR_ZS; /* first clear Z and S flags */ + CHK_XXXW_ZS; /* set Z and S flags for result word */ + return result; +} + + +/****************************************** + compare byte + flags: CZSV-- + ******************************************/ +void z8002_device::CPB(UINT8 dest, UINT8 value) +{ + UINT8 result = dest - value; + CLR_CZSV; /* first clear C, Z, S and P/V flags */ + CHK_XXXB_ZS; /* set Z and S flags for result byte */ + CHK_SUBX_C; /* set C if result underflowed */ + CHK_SUBB_V; +} + +/****************************************** + compare word + flags: CZSV-- + ******************************************/ +void z8002_device::CPW(UINT16 dest, UINT16 value) +{ + UINT16 result = dest - value; + CLR_CZSV; + CHK_XXXW_ZS; /* set Z and S flags for result word */ + CHK_SUBX_C; /* set C if result underflowed */ + CHK_SUBW_V; +} + +/****************************************** + compare long + flags: CZSV-- + ******************************************/ +void z8002_device::CPL(UINT32 dest, UINT32 value) +{ + UINT32 result = dest - value; + CLR_CZSV; + CHK_XXXL_ZS; /* set Z and S flags for result long */ + CHK_SUBX_C; /* set C if result underflowed */ + CHK_SUBL_V; +} + +/****************************************** + complement byte + flags: -ZSP-- + ******************************************/ +UINT8 z8002_device::COMB(UINT8 dest) +{ + UINT8 result = ~dest; + CLR_ZSP; + CHK_XXXB_ZSP; /* set Z, S and P flags for result byte */ + return result; +} + +/****************************************** + complement word + flags: -ZS--- + ******************************************/ +UINT16 z8002_device::COMW(UINT16 dest) +{ + UINT16 result = ~dest; + CLR_ZS; + CHK_XXXW_ZS; /* set Z and S flags for result word */ + return result; +} + +/****************************************** + negate byte + flags: CZSV-- + ******************************************/ +UINT8 z8002_device::NEGB(UINT8 dest) +{ + UINT8 result = (UINT8) -dest; + CLR_CZSV; + CHK_XXXB_ZS; /* set Z and S flags for result byte */ + if (result > 0) SET_C; + if (result == S08) SET_V; + return result; +} + +/****************************************** + negate word + flags: CZSV-- + ******************************************/ +UINT16 z8002_device::NEGW(UINT16 dest) +{ + UINT16 result = (UINT16) -dest; + CLR_CZSV; + CHK_XXXW_ZS; /* set Z and S flags for result word */ + if (result > 0) SET_C; + if (result == S16) SET_V; + return result; +} + +/****************************************** + test byte + flags: -ZSP-- + ******************************************/ +void z8002_device::TESTB(UINT8 result) +{ + CLR_ZSP; + CHK_XXXB_ZSP; /* set Z and S flags for result byte */ +} + +/****************************************** + test word + flags: -ZS--- + ******************************************/ +void z8002_device::TESTW(UINT16 dest) +{ + CLR_ZS; + if (!dest) SET_Z; else if (dest & S16) SET_S; +} + +/****************************************** + test long + flags: -ZS--- + ******************************************/ +void z8002_device::TESTL(UINT32 dest) +{ + CLR_ZS; + if (!dest) SET_Z; else if (dest & S32) SET_S; +} + +/****************************************** + increment byte + flags: -ZSV-- + ******************************************/ +UINT8 z8002_device::INCB(UINT8 dest, UINT8 value) +{ + UINT8 result = dest + value; + CLR_ZSV; + CHK_XXXB_ZS; /* set Z and S flags for result byte */ + CHK_ADDB_V; /* set V if result overflowed */ + return result; +} + +/****************************************** + increment word + flags: -ZSV-- + ******************************************/ +UINT16 z8002_device::INCW(UINT16 dest, UINT16 value) +{ + UINT16 result = dest + value; + CLR_ZSV; + CHK_XXXW_ZS; /* set Z and S flags for result byte */ + CHK_ADDW_V; /* set V if result overflowed */ + return result; +} + +/****************************************** + decrement byte + flags: -ZSV-- + ******************************************/ +UINT8 z8002_device::DECB(UINT8 dest, UINT8 value) +{ + UINT8 result = dest - value; + CLR_ZSV; + CHK_XXXB_ZS; /* set Z and S flags for result byte */ + CHK_SUBB_V; /* set V if result overflowed */ + return result; +} + +/****************************************** + decrement word + flags: -ZSV-- + ******************************************/ +UINT16 z8002_device::DECW(UINT16 dest, UINT16 value) +{ + UINT16 result = dest - value; + CLR_ZSV; + CHK_XXXW_ZS; /* set Z and S flags for result word */ + CHK_SUBW_V; /* set V if result overflowed */ + return result; +} + +/****************************************** + multiply words + flags: CZSV-- + ******************************************/ +UINT32 z8002_device::MULTW(UINT16 dest, UINT16 value) +{ + UINT32 result = (INT32)(INT16)dest * (INT16)value; + CLR_CZSV; + CHK_XXXL_ZS; + if(!value) + { + /* multiplication with zero is faster */ + m_icount += (70-18); + } + if((INT32)result < -0x7fff || (INT32)result >= 0x7fff) SET_C; + return result; +} + +/****************************************** + multiply longs + flags: CZSV-- + ******************************************/ +UINT64 z8002_device::MULTL(UINT32 dest, UINT32 value) +{ + UINT64 result = (INT64)(INT32)dest * (INT32)value; + if(!value) + { + /* multiplication with zero is faster */ + m_icount += (282 - 30); + } + else + { + int n; + for(n = 0; n < 32; n++) + if(dest & (1L << n)) m_icount -= 7; + } + CLR_CZSV; + CHK_XXXQ_ZS; + if((INT64)result < -0x7fffffffL || (INT64)result >= 0x7fffffffL) SET_C; + return result; +} + +/****************************************** + divide long by word + flags: CZSV-- + ******************************************/ +UINT32 z8002_device::DIVW(UINT32 dest, UINT16 value) +{ + UINT32 result = dest; + UINT16 remainder = 0; + CLR_CZSV; + if (value) + { + UINT16 qsign = ((dest >> 16) ^ value) & S16; + UINT16 rsign = (dest >> 16) & S16; + if ((INT32)dest < 0) dest = -dest; + if ((INT16)value < 0) value = -value; + result = dest / value; + remainder = dest % value; + if (qsign) result = -result; + if (rsign) remainder = -remainder; + if ((INT32)result < -0x8000 || (INT32)result > 0x7fff) + { + INT32 temp = (INT32)result >> 1; + SET_V; + if (temp >= -0x8000 && temp <= 0x7fff) + { + result = (temp < 0) ? -1 : 0; + CHK_XXXW_ZS; + SET_C; + } + } + else + { + CHK_XXXW_ZS; + } + result = ((UINT32)remainder << 16) | (result & 0xffff); + } + else + { + SET_Z; + SET_V; + } + return result; +} + +/****************************************** + divide quad word by long + flags: CZSV-- + ******************************************/ +UINT64 z8002_device::DIVL(UINT64 dest, UINT32 value) +{ + UINT64 result = dest; + UINT32 remainder = 0; + CLR_CZSV; + if (value) + { + UINT32 qsign = ((dest >> 32) ^ value) & S32; + UINT32 rsign = (dest >> 32) & S32; + if ((INT64)dest < 0) dest = -dest; + if ((INT32)value < 0) value = -value; + result = dest / value; + remainder = dest % value; + if (qsign) result = -result; + if (rsign) remainder = -remainder; + if ((INT64)result < -0x80000000 || (INT64)result > 0x7fffffff) + { + INT64 temp = (INT64)result >> 1; + SET_V; + if (temp >= -0x80000000 && temp <= 0x7fffffff) + { + result = (temp < 0) ? -1 : 0; + CHK_XXXL_ZS; + SET_C; + } + } + else + { + CHK_XXXL_ZS; + } + result = ((UINT64)remainder << 32) | (result & 0xffffffff); + } + else + { + SET_Z; + SET_V; + } + return result; +} + +/****************************************** + rotate left byte + flags: CZSV-- + ******************************************/ +UINT8 z8002_device::RLB(UINT8 dest, UINT8 twice) +{ + UINT8 result = (dest << 1) | (dest >> 7); + CLR_CZSV; + if (twice) result = (result << 1) | (result >> 7); + CHK_XXXB_ZS; /* set Z and S flags for result byte */ + if (result & 0x01) SET_C; + if ((result ^ dest) & S08) SET_V; + return result; +} + +/****************************************** + rotate left word + flags: CZSV-- + ******************************************/ +UINT16 z8002_device::RLW(UINT16 dest, UINT8 twice) +{ + UINT16 result = (dest << 1) | (dest >> 15); + CLR_CZSV; + if (twice) result = (result << 1) | (result >> 15); + CHK_XXXW_ZS; /* set Z and S flags for result word */ + if (result & 0x0001) SET_C; + if ((result ^ dest) & S16) SET_V; + return result; +} + +/****************************************** + rotate left through carry byte + flags: CZSV-- + ******************************************/ +UINT8 z8002_device::RLCB(UINT8 dest, UINT8 twice) +{ + UINT8 c = dest & S08; + UINT8 result = (dest << 1) | GET_C; + CLR_CZSV; + if (twice) { + UINT8 c1 = c >> 7; + c = result & S08; + result = (result << 1) | c1; + } + CHK_XXXB_ZS; /* set Z and S flags for result byte */ + if (c) SET_C; + if ((result ^ dest) & S08) SET_V; + return result; +} + +/****************************************** + rotate left through carry word + flags: CZSV-- + ******************************************/ +UINT16 z8002_device::RLCW(UINT16 dest, UINT8 twice) +{ + UINT16 c = dest & S16; + UINT16 result = (dest << 1) | GET_C; + CLR_CZSV; + if (twice) { + UINT16 c1 = c >> 15; + c = result & S16; + result = (result << 1) | c1; + } + CHK_XXXW_ZS; /* set Z and S flags for result word */ + if (c) SET_C; + if ((result ^ dest) & S16) SET_V; + return result; +} + +/****************************************** + rotate right byte + flags: CZSV-- + ******************************************/ +UINT8 z8002_device::RRB(UINT8 dest, UINT8 twice) +{ + UINT8 result = (dest >> 1) | (dest << 7); + CLR_CZSV; + if (twice) result = (result >> 1) | (result << 7); + if (!result) SET_Z; else if (result & S08) SET_SC; + if ((result ^ dest) & S08) SET_V; + return result; +} + +/****************************************** + rotate right word + flags: CZSV-- + ******************************************/ +UINT16 z8002_device::RRW(UINT16 dest, UINT8 twice) +{ + UINT16 result = (dest >> 1) | (dest << 15); + CLR_CZSV; + if (twice) result = (result >> 1) | (result << 15); + if (!result) SET_Z; else if (result & S16) SET_SC; + if ((result ^ dest) & S16) SET_V; + return result; +} + +/****************************************** + rotate right through carry byte + flags: CZSV-- + ******************************************/ +UINT8 z8002_device::RRCB(UINT8 dest, UINT8 twice) +{ + UINT8 c = dest & 1; + UINT8 result = (dest >> 1) | (GET_C << 7); + CLR_CZSV; + if (twice) { + UINT8 c1 = c << 7; + c = result & 1; + result = (result >> 1) | c1; + } + CHK_XXXB_ZS; /* set Z and S flags for result byte */ + if (c) SET_C; + if ((result ^ dest) & S08) SET_V; + return result; +} + +/****************************************** + rotate right through carry word + flags: CZSV-- + ******************************************/ +UINT16 z8002_device::RRCW(UINT16 dest, UINT8 twice) +{ + UINT16 c = dest & 1; + UINT16 result = (dest >> 1) | (GET_C << 15); + CLR_CZSV; + if (twice) { + UINT16 c1 = c << 15; + c = result & 1; + result = (result >> 1) | c1; + } + CHK_XXXW_ZS; /* set Z and S flags for result word */ + if (c) SET_C; + if ((result ^ dest) & S16) SET_V; + return result; +} + +/****************************************** + shift dynamic arithmetic byte + flags: CZSV-- + ******************************************/ +UINT8 z8002_device::SDAB(UINT8 dest, INT8 count) +{ + INT8 result = (INT8) dest; + UINT8 c = 0; + CLR_CZSV; + while (count > 0) { + c = result & S08; + result <<= 1; + count--; + } + while (count < 0) { + c = result & 0x01; + result >>= 1; + count++; + } + CHK_XXXB_ZS; /* set Z and S flags for result byte */ + if (c) SET_C; + if ((result ^ dest) & S08) SET_V; + return (UINT8)result; +} + +/****************************************** + shift dynamic arithmetic word + flags: CZSV-- + ******************************************/ +UINT16 z8002_device::SDAW(UINT16 dest, INT8 count) +{ + INT16 result = (INT16) dest; + UINT16 c = 0; + CLR_CZSV; + while (count > 0) { + c = result & S16; + result <<= 1; + count--; + } + while (count < 0) { + c = result & 0x0001; + result >>= 1; + count++; + } + CHK_XXXW_ZS; /* set Z and S flags for result word */ + if (c) SET_C; + if ((result ^ dest) & S16) SET_V; + return (UINT16)result; +} + +/****************************************** + shift dynamic arithmetic long + flags: CZSV-- + ******************************************/ +UINT32 z8002_device::SDAL(UINT32 dest, INT8 count) +{ + INT32 result = (INT32) dest; + UINT32 c = 0; + CLR_CZSV; + while (count > 0) { + c = result & S32; + result <<= 1; + count--; + } + while (count < 0) { + c = result & 0x00000001; + result >>= 1; + count++; + } + CHK_XXXL_ZS; /* set Z and S flags for result long */ + if (c) SET_C; + if ((result ^ dest) & S32) SET_V; + return (UINT32) result; +} + +/****************************************** + shift dynamic logic byte + flags: CZSV-- + ******************************************/ +UINT8 z8002_device::SDLB(UINT8 dest, INT8 count) +{ + UINT8 result = dest; + UINT8 c = 0; + CLR_CZSV; + while (count > 0) { + c = result & S08; + result <<= 1; + count--; + } + while (count < 0) { + c = result & 0x01; + result >>= 1; + count++; + } + CHK_XXXB_ZS; /* set Z and S flags for result byte */ + if (c) SET_C; + if ((result ^ dest) & S08) SET_V; + return result; +} + +/****************************************** + shift dynamic logic word + flags: CZSV-- + ******************************************/ +UINT16 z8002_device::SDLW(UINT16 dest, INT8 count) +{ + UINT16 result = dest; + UINT16 c = 0; + CLR_CZSV; + while (count > 0) { + c = result & S16; + result <<= 1; + count--; + } + while (count < 0) { + c = result & 0x0001; + result >>= 1; + count++; + } + CHK_XXXW_ZS; /* set Z and S flags for result word */ + if (c) SET_C; + if ((result ^ dest) & S16) SET_V; + return result; +} + +/****************************************** + shift dynamic logic long + flags: CZSV-- + ******************************************/ +UINT32 z8002_device::SDLL(UINT32 dest, INT8 count) +{ + UINT32 result = dest; + UINT32 c = 0; + CLR_CZSV; + while (count > 0) { + c = result & S32; + result <<= 1; + count--; + } + while (count < 0) { + c = result & 0x00000001; + result >>= 1; + count++; + } + CHK_XXXL_ZS; /* set Z and S flags for result long */ + if (c) SET_C; + if ((result ^ dest) & S32) SET_V; + return result; +} + +/****************************************** + shift left arithmetic byte + flags: CZSV-- + ******************************************/ +UINT8 z8002_device::SLAB(UINT8 dest, UINT8 count) +{ + UINT8 c = (count) ? (dest << (count - 1)) & S08 : 0; + UINT8 result = (UINT8)((INT8)dest << count); + CLR_CZSV; + CHK_XXXB_ZS; /* set Z and S flags for result byte */ + if (c) SET_C; + if ((result ^ dest) & S08) SET_V; + return result; +} + +/****************************************** + shift left arithmetic word + flags: CZSV-- + ******************************************/ +UINT16 z8002_device::SLAW(UINT16 dest, UINT8 count) +{ + UINT16 c = (count) ? (dest << (count - 1)) & S16 : 0; + UINT16 result = (UINT16)((INT16)dest << count); + CLR_CZSV; + CHK_XXXW_ZS; /* set Z and S flags for result word */ + if (c) SET_C; + if ((result ^ dest) & S16) SET_V; + return result; +} + +/****************************************** + shift left arithmetic long + flags: CZSV-- + ******************************************/ +UINT32 z8002_device::SLAL(UINT32 dest, UINT8 count) +{ + UINT32 c = (count) ? (dest << (count - 1)) & S32 : 0; + UINT32 result = (UINT32)((INT32)dest << count); + CLR_CZSV; + CHK_XXXL_ZS; /* set Z and S flags for result long */ + if (c) SET_C; + if ((result ^ dest) & S32) SET_V; + return result; +} + +/****************************************** + shift left logic byte + flags: CZS--- + ******************************************/ +UINT8 z8002_device::SLLB(UINT8 dest, UINT8 count) +{ + UINT8 c = (count) ? (dest << (count - 1)) & S08 : 0; + UINT8 result = dest << count; + CLR_CZS; + CHK_XXXB_ZS; /* set Z and S flags for result byte */ + if (c) SET_C; + return result; +} + +/****************************************** + shift left logic word + flags: CZS--- + ******************************************/ +UINT16 z8002_device::SLLW(UINT16 dest, UINT8 count) +{ + UINT16 c = (count) ? (dest << (count - 1)) & S16 : 0; + UINT16 result = dest << count; + CLR_CZS; + CHK_XXXW_ZS; /* set Z and S flags for result word */ + if (c) SET_C; + return result; +} + +/****************************************** + shift left logic long + flags: CZS--- + ******************************************/ +UINT32 z8002_device::SLLL(UINT32 dest, UINT8 count) +{ + UINT32 c = (count) ? (dest << (count - 1)) & S32 : 0; + UINT32 result = dest << count; + CLR_CZS; + CHK_XXXL_ZS; /* set Z and S flags for result long */ + if (c) SET_C; + return result; +} + +/****************************************** + shift right arithmetic byte + flags: CZSV-- + ******************************************/ +UINT8 z8002_device::SRAB(UINT8 dest, UINT8 count) +{ + UINT8 c = (count) ? ((INT8)dest >> (count - 1)) & 1 : 0; + UINT8 result = (UINT8)((INT8)dest >> count); + CLR_CZSV; + CHK_XXXB_ZS; /* set Z and S flags for result byte */ + if (c) SET_C; + return result; +} + +/****************************************** + shift right arithmetic word + flags: CZSV-- + ******************************************/ +UINT16 z8002_device::SRAW(UINT16 dest, UINT8 count) +{ + UINT8 c = (count) ? ((INT16)dest >> (count - 1)) & 1 : 0; + UINT16 result = (UINT16)((INT16)dest >> count); + CLR_CZSV; + CHK_XXXW_ZS; /* set Z and S flags for result word */ + if (c) SET_C; + return result; +} + +/****************************************** + shift right arithmetic long + flags: CZSV-- + ******************************************/ +UINT32 z8002_device::SRAL(UINT32 dest, UINT8 count) +{ + UINT8 c = (count) ? ((INT32)dest >> (count - 1)) & 1 : 0; + UINT32 result = (UINT32)((INT32)dest >> count); + CLR_CZSV; + CHK_XXXL_ZS; /* set Z and S flags for result long */ + if (c) SET_C; + return result; +} + +/****************************************** + shift right logic byte + flags: CZSV-- + ******************************************/ +UINT8 z8002_device::SRLB(UINT8 dest, UINT8 count) +{ + UINT8 c = (count) ? (dest >> (count - 1)) & 1 : 0; + UINT8 result = dest >> count; + CLR_CZS; + CHK_XXXB_ZS; /* set Z and S flags for result byte */ + if (c) SET_C; + return result; +} + +/****************************************** + shift right logic word + flags: CZSV-- + ******************************************/ +UINT16 z8002_device::SRLW(UINT16 dest, UINT8 count) +{ + UINT8 c = (count) ? (dest >> (count - 1)) & 1 : 0; + UINT16 result = dest >> count; + CLR_CZS; + CHK_XXXW_ZS; /* set Z and S flags for result word */ + if (c) SET_C; + return result; +} + +/****************************************** + shift right logic long + flags: CZSV-- + ******************************************/ +UINT32 z8002_device::SRLL(UINT32 dest, UINT8 count) +{ + UINT8 c = (count) ? (dest >> (count - 1)) & 1 : 0; + UINT32 result = dest >> count; + CLR_CZS; + CHK_XXXL_ZS; /* set Z and S flags for result long */ + if (c) SET_C; + return result; +} + +/****************************************** + invalid + flags: ------ + ******************************************/ +void z8002_device::zinvalid() +{ + logerror("Z8000 invalid opcode %04x: %04x\n", m_pc, m_op[0]); +} + +/****************************************** + addb rbd,imm8 + flags: CZSVDH + ******************************************/ +void z8002_device::Z00_0000_dddd_imm8() +{ + GET_DST(OP0,NIB3); + GET_IMM8(OP1); + RB(dst) = ADDB(RB(dst), imm8); +} + +/****************************************** + addb rbd,@rs + flags: CZSVDH + ******************************************/ +void z8002_device::Z00_ssN0_dddd() +{ + GET_DST(OP0,NIB3); + GET_SRC(OP0,NIB2); + RB(dst) = ADDB(RB(dst), RDMEM_B(AS_DATA, addr_from_reg(src))); +} + +/****************************************** + add rd,imm16 + flags: CZSV-- + ******************************************/ +void z8002_device::Z01_0000_dddd_imm16() +{ + GET_DST(OP0,NIB3); + GET_IMM16(OP1); + RW(dst) = ADDW(RW(dst), imm16); +} + +/****************************************** + add rd,@rs + flags: CZSV-- + ******************************************/ +void z8002_device::Z01_ssN0_dddd() +{ + GET_DST(OP0,NIB3); + GET_SRC(OP0,NIB2); + RW(dst) = ADDW(RW(dst), RDMEM_W(AS_DATA, addr_from_reg(src))); +} + +/****************************************** + subb rbd,imm8 + flags: CZSVDH + ******************************************/ +void z8002_device::Z02_0000_dddd_imm8() +{ + GET_DST(OP0,NIB3); + GET_IMM8(OP1); + RB(dst) = SUBB(RB(dst), imm8); +} + +/****************************************** + subb rbd,@rs + flags: CZSVDH + ******************************************/ +void z8002_device::Z02_ssN0_dddd() +{ + GET_DST(OP0,NIB3); + GET_SRC(OP0,NIB2); + RB(dst) = SUBB(RB(dst), RDMEM_B(AS_DATA, addr_from_reg(src))); /* EHC */ +} + +/****************************************** + sub rd,imm16 + flags: CZSV-- + ******************************************/ +void z8002_device::Z03_0000_dddd_imm16() +{ + GET_DST(OP0,NIB3); + GET_IMM16(OP1); + RW(dst) = SUBW(RW(dst), imm16); +} + +/****************************************** + sub rd,@rs + flags: CZSV-- + ******************************************/ +void z8002_device::Z03_ssN0_dddd() +{ + GET_DST(OP0,NIB3); + GET_SRC(OP0,NIB2); + RW(dst) = SUBW(RW(dst), RDMEM_W(AS_DATA, addr_from_reg(src))); +} + +/****************************************** + orb rbd,imm8 + flags: CZSP-- + ******************************************/ +void z8002_device::Z04_0000_dddd_imm8() +{ + GET_DST(OP0,NIB3); + GET_IMM8(OP1); + RB(dst) = ORB(RB(dst), imm8); +} + +/****************************************** + orb rbd,@rs + flags: CZSP-- + ******************************************/ +void z8002_device::Z04_ssN0_dddd() +{ + GET_DST(OP0,NIB3); + GET_SRC(OP0,NIB2); + RB(dst) = ORB(RB(dst), RDMEM_B(AS_DATA, addr_from_reg(src))); +} + +/****************************************** + or rd,imm16 + flags: CZS--- + ******************************************/ +void z8002_device::Z05_0000_dddd_imm16() +{ + GET_DST(OP0,NIB3); + GET_IMM16(OP1); + RW(dst) = ORW(RW(dst), imm16); +} + +/****************************************** + or rd,@rs + flags: CZS--- + ******************************************/ +void z8002_device::Z05_ssN0_dddd() +{ + GET_DST(OP0,NIB3); + GET_SRC(OP0,NIB2); + RW(dst) = ORW(RW(dst), RDMEM_W(AS_DATA, addr_from_reg(src))); +} + +/****************************************** + andb rbd,imm8 + flags: -ZSP-- + ******************************************/ +void z8002_device::Z06_0000_dddd_imm8() +{ + GET_DST(OP0,NIB3); + GET_IMM8(OP1); + RB(dst) = ANDB(RB(dst), imm8); +} + +/****************************************** + andb rbd,@rs + flags: -ZSP-- + ******************************************/ +void z8002_device::Z06_ssN0_dddd() +{ + GET_DST(OP0,NIB3); + GET_SRC(OP0,NIB2); + RB(dst) = ANDB(RB(dst), RDMEM_B(AS_DATA, addr_from_reg(src))); +} + +/****************************************** + and rd,imm16 + flags: -ZS--- + ******************************************/ +void z8002_device::Z07_0000_dddd_imm16() +{ + GET_DST(OP0,NIB3); + GET_IMM16(OP1); + RW(dst) = ANDW(RW(dst), imm16); +} + +/****************************************** + and rd,@rs + flags: -ZS--- + ******************************************/ +void z8002_device::Z07_ssN0_dddd() +{ + GET_DST(OP0,NIB3); + GET_SRC(OP0,NIB2); + RW(dst) = ANDW(RW(dst), RDMEM_W(AS_DATA, addr_from_reg(src))); +} + +/****************************************** + xorb rbd,imm8 + flags: -ZSP-- + ******************************************/ +void z8002_device::Z08_0000_dddd_imm8() +{ + GET_DST(OP0,NIB3); + GET_IMM8(OP1); + RB(dst) = XORB(RB(dst), imm8); +} + +/****************************************** + xorb rbd,@rs + flags: -ZSP-- + ******************************************/ +void z8002_device::Z08_ssN0_dddd() +{ + GET_DST(OP0,NIB3); + GET_SRC(OP0,NIB2); + RB(dst) = XORB(RB(dst), RDMEM_B(AS_DATA, addr_from_reg(src))); +} + +/****************************************** + xor rd,imm16 + flags: -ZS--- + ******************************************/ +void z8002_device::Z09_0000_dddd_imm16() +{ + GET_DST(OP0,NIB3); + GET_IMM16(OP1); + RW(dst) = XORW(RW(dst), imm16); +} + +/****************************************** + xor rd,@rs + flags: -ZS--- + ******************************************/ +void z8002_device::Z09_ssN0_dddd() +{ + GET_DST(OP0,NIB3); + GET_SRC(OP0,NIB2); + RW(dst) = XORW(RW(dst), RDMEM_W(AS_DATA, addr_from_reg(src))); +} + +/****************************************** + cpb rbd,imm8 + flags: CZSV-- + ******************************************/ +void z8002_device::Z0A_0000_dddd_imm8() +{ + GET_DST(OP0,NIB3); + GET_IMM8(OP1); + CPB(RB(dst), imm8); +} + +/****************************************** + cpb rbd,@rs + flags: CZSV-- + ******************************************/ +void z8002_device::Z0A_ssN0_dddd() +{ + GET_DST(OP0,NIB3); + GET_SRC(OP0,NIB2); + CPB(RB(dst), RDMEM_B(AS_DATA, addr_from_reg(src))); +} + +/****************************************** + cp rd,imm16 + flags: CZSV-- + ******************************************/ +void z8002_device::Z0B_0000_dddd_imm16() +{ + GET_DST(OP0,NIB3); + GET_IMM16(OP1); + CPW(RW(dst), imm16); +} + +/****************************************** + cp rd,@rs + flags: CZSV-- + ******************************************/ +void z8002_device::Z0B_ssN0_dddd() +{ + GET_DST(OP0,NIB3); + GET_SRC(OP0,NIB2); + CPW(RW(dst), RDMEM_W(AS_DATA, addr_from_reg(src))); +} + +/****************************************** + comb @rd + flags: -ZSP-- + ******************************************/ +void z8002_device::Z0C_ddN0_0000() +{ + GET_DST(OP0,NIB3); + UINT32 addr = addr_from_reg(dst); + WRMEM_B(AS_DATA, addr, COMB(RDMEM_B(AS_DATA, addr))); +} + +/****************************************** + cpb @rd,imm8 + flags: CZSV-- + ******************************************/ +void z8002_device::Z0C_ddN0_0001_imm8() +{ + GET_DST(OP0,NIB2); + GET_IMM8(OP1); + CPB(RDMEM_B(AS_DATA, addr_from_reg(dst)), imm8); // @@@done +} + +/****************************************** + negb @rd + flags: CZSV-- + ******************************************/ +void z8002_device::Z0C_ddN0_0010() +{ + GET_DST(OP0,NIB2); + UINT32 addr = addr_from_reg(dst); + WRMEM_B(AS_DATA, addr, NEGB(RDMEM_B(AS_DATA, addr))); +} + +/****************************************** + testb @rd + flags: -ZSP-- + ******************************************/ +void z8002_device::Z0C_ddN0_0100() +{ + GET_DST(OP0,NIB2); + TESTB(RDMEM_B(AS_DATA, addr_from_reg(dst))); +} + +/****************************************** + ldb @rd,imm8 + flags: ------ + ******************************************/ +void z8002_device::Z0C_ddN0_0101_imm8() +{ + GET_DST(OP0,NIB2); + GET_IMM8(OP1); + WRMEM_B(AS_DATA, addr_from_reg(dst), imm8); +} + +/****************************************** + tsetb @rd + flags: --S--- + ******************************************/ +void z8002_device::Z0C_ddN0_0110() +{ + GET_DST(OP0,NIB2); + UINT32 addr = addr_from_reg(dst); + if (RDMEM_B(AS_DATA, addr) & S08) SET_S; else CLR_S; + WRMEM_B(AS_DATA, addr, 0xff); +} + +/****************************************** + clrb @rd + flags: ------ + ******************************************/ +void z8002_device::Z0C_ddN0_1000() +{ + GET_DST(OP0,NIB2); + WRMEM_B(AS_DATA, addr_from_reg(dst), 0); +} + +/****************************************** + com @rd + flags: -ZS--- + ******************************************/ +void z8002_device::Z0D_ddN0_0000() +{ + GET_DST(OP0,NIB2); + UINT32 addr = addr_from_reg(dst); + WRMEM_W(AS_DATA, addr, COMW(RDMEM_W(AS_DATA, addr))); +} + +/****************************************** + cp @rd,imm16 + flags: CZSV-- + ******************************************/ +void z8002_device::Z0D_ddN0_0001_imm16() +{ + GET_DST(OP0,NIB2); + GET_IMM16(OP1); + CPW(RDMEM_W(AS_DATA, addr_from_reg(dst)), imm16); +} + +/****************************************** + neg @rd + flags: CZSV-- + ******************************************/ +void z8002_device::Z0D_ddN0_0010() +{ + GET_DST(OP0,NIB2); + UINT32 addr = addr_from_reg(dst); + WRMEM_W(AS_DATA, addr, NEGW(RDMEM_W(AS_DATA, addr))); +} + +/****************************************** + test @rd + flags: -ZS--- + ******************************************/ +void z8002_device::Z0D_ddN0_0100() +{ + GET_DST(OP0,NIB2); + TESTW(RDMEM_W(AS_DATA, addr_from_reg(dst))); +} + +/****************************************** + ld @rd,imm16 + flags: ------ + ******************************************/ +void z8002_device::Z0D_ddN0_0101_imm16() +{ + GET_DST(OP0,NIB2); + GET_IMM16(OP1); + WRMEM_W(AS_DATA, addr_from_reg(dst), imm16); +} + +/****************************************** + tset @rd + flags: --S--- + ******************************************/ +void z8002_device::Z0D_ddN0_0110() +{ + GET_DST(OP0,NIB2); + UINT32 addr = addr_from_reg(dst); + if (RDMEM_W(AS_DATA, addr) & S16) SET_S; else CLR_S; + WRMEM_W(AS_DATA, addr, 0xffff); +} + +/****************************************** + clr @rd + flags: ------ + ******************************************/ +void z8002_device::Z0D_ddN0_1000() +{ + GET_DST(OP0,NIB2); + WRMEM_W(AS_DATA, addr_from_reg(dst), 0); +} + +/****************************************** + push @rd,imm16 + flags: ------ + ******************************************/ +void z8002_device::Z0D_ddN0_1001_imm16() +{ + GET_DST(OP0,NIB2); + GET_IMM16(OP1); + PUSHW(dst, imm16); +} + +/****************************************** + ext0e imm8 + flags: ------ + ******************************************/ +void z8002_device::Z0E_imm8() +{ + CHECK_EXT_INSTR(); + GET_IMM8(0); + LOG(("Z8K '%s' %04x: ext0e $%02x\n", tag(), m_pc, imm8)); + if (m_fcw & F_EPU) { + /* Z8001 EPU code goes here */ + (void)imm8; + } +} + +/****************************************** + ext0f imm8 + flags: ------ + ******************************************/ +void z8002_device::Z0F_imm8() +{ + CHECK_EXT_INSTR(); + GET_IMM8(0); + LOG(("Z8K '%s' %04x: ext0f $%02x\n", tag(), m_pc, imm8)); + if (m_fcw & F_EPU) { + /* Z8001 EPU code goes here */ + (void)imm8; + } +} + +/****************************************** + cpl rrd,imm32 + flags: CZSV-- + ******************************************/ +void z8002_device::Z10_0000_dddd_imm32() +{ + GET_DST(OP0,NIB3); + GET_IMM32; + CPL(RL(dst), imm32); +} + +/****************************************** + cpl rrd,@rs + flags: CZSV-- + ******************************************/ +void z8002_device::Z10_ssN0_dddd() +{ + GET_DST(OP0,NIB3); + GET_SRC(OP0,NIB2); + CPL(RL(dst), RDMEM_L(AS_DATA, addr_from_reg(src))); +} + +/****************************************** + pushl @rd,@rs + flags: ------ + ******************************************/ +void z8002_device::Z11_ddN0_ssN0() +{ + GET_SRC(OP0,NIB3); + GET_DST(OP0,NIB2); + PUSHL(dst, RDMEM_L(AS_DATA, addr_from_reg(src))); +} + +/****************************************** + subl rrd,imm32 + flags: CZSV-- + ******************************************/ +void z8002_device::Z12_0000_dddd_imm32() +{ + GET_DST(OP0,NIB3); + GET_IMM32; + RL(dst) = SUBL(RL(dst), imm32); +} + +/****************************************** + subl rrd,@rs + flags: CZSV-- + ******************************************/ +void z8002_device::Z12_ssN0_dddd() +{ + GET_DST(OP0,NIB3); + GET_SRC(OP0,NIB2); + RL(dst) = SUBL(RL(dst), RDMEM_L(AS_DATA, addr_from_reg(src))); +} + +/****************************************** + push @rd,@rs + flags: ------ + ******************************************/ +void z8002_device::Z13_ddN0_ssN0() +{ + GET_SRC(OP0,NIB3); + GET_DST(OP0,NIB2); + PUSHW(dst, RDMEM_W(AS_DATA, addr_from_reg(src))); +} + +/****************************************** + ldl rrd,imm32 + flags: ------ + ******************************************/ +void z8002_device::Z14_0000_dddd_imm32() +{ + GET_DST(OP0,NIB3); + GET_IMM32; + RL(dst) = imm32; +} + +/****************************************** + ldl rrd,@rs + flags: ------ + ******************************************/ +void z8002_device::Z14_ssN0_dddd() +{ + GET_DST(OP0,NIB3); + GET_SRC(OP0,NIB2); + RL(dst) = RDMEM_L( AS_DATA, addr_from_reg(src)); +} + +/****************************************** + popl rd,@rs + flags: ------ + ******************************************/ +void z8002_device::Z15_ssN0_ddN0() +{ + GET_DST(OP0,NIB3); + GET_SRC(OP0,NIB2); + RL(dst) = POPL(src); +} + +/****************************************** + addl rrd,imm32 + flags: CZSV-- + ******************************************/ +void z8002_device::Z16_0000_dddd_imm32() +{ + GET_DST(OP0,NIB3); + GET_IMM32; + RL(dst) = ADDL(RL(dst), imm32); +} + +/****************************************** + addl rrd,@rs + flags: CZSV-- + ******************************************/ +void z8002_device::Z16_ssN0_dddd() +{ + GET_DST(OP0,NIB3); + GET_SRC(OP0,NIB2); + RL(dst) = ADDL(RL(dst), RDMEM_L(AS_DATA, addr_from_reg(src))); +} + +/****************************************** + pop @rd,@rs + flags: ------ + ******************************************/ +void z8002_device::Z17_ssN0_ddN0() +{ + GET_DST(OP0,NIB3); + GET_SRC(OP0,NIB2); + WRMEM_W(AS_DATA, addr_from_reg(dst), POPW(src)); +} + +/****************************************** + multl rqd,imm32 + flags: CZSV-- + ******************************************/ +void z8002_device::Z18_00N0_dddd_imm32() +{ + GET_DST(OP0,NIB3); + GET_IMM32; + RQ(dst) = MULTL(RQ(dst), imm32); +} + +/****************************************** + multl rqd,@rs + flags: CZSV-- + ******************************************/ +void z8002_device::Z18_ssN0_dddd() +{ + GET_DST(OP0,NIB3); + GET_SRC(OP0,NIB2); + RQ(dst) = MULTL(RQ(dst), RL(src)); //@@@ +} + +/****************************************** + mult rrd,imm16 + flags: CZSV-- + ******************************************/ +void z8002_device::Z19_0000_dddd_imm16() +{ + GET_DST(OP0,NIB3); + GET_IMM16(OP1); + RL(dst) = MULTW(RL(dst), imm16); +} + +/****************************************** + mult rrd,@rs + flags: CZSV-- + ******************************************/ +void z8002_device::Z19_ssN0_dddd() +{ + GET_DST(OP0,NIB3); + GET_SRC(OP0,NIB2); + RL(dst) = MULTW(RL(dst), RDMEM_W(AS_DATA, addr_from_reg(src))); +} + +/****************************************** + divl rqd,imm32 + flags: CZSV-- + ******************************************/ +void z8002_device::Z1A_0000_dddd_imm32() +{ + GET_DST(OP0,NIB3); + GET_IMM32; + RQ(dst) = DIVL(RQ(dst), imm32); +} + +/****************************************** + divl rqd,@rs + flags: CZSV-- + ******************************************/ +void z8002_device::Z1A_ssN0_dddd() +{ + GET_DST(OP0,NIB3); + GET_SRC(OP0,NIB2); + RQ(dst) = DIVL(RQ(dst), RDMEM_L(AS_DATA, addr_from_reg(src))); +} + +/****************************************** + div rrd,imm16 + flags: CZSV-- + ******************************************/ +void z8002_device::Z1B_0000_dddd_imm16() +{ + GET_DST(OP0,NIB3); + GET_IMM16(OP1); + RL(dst) = DIVW(RL(dst), imm16); +} + +/****************************************** + div rrd,@rs + flags: CZSV-- + ******************************************/ +void z8002_device::Z1B_ssN0_dddd() +{ + GET_DST(OP0,NIB3); + GET_SRC(OP0,NIB2); + RL(dst) = DIVW(RL(dst), RDMEM_W(AS_DATA, addr_from_reg(src))); +} + +/****************************************** + testl @rd + flags: -ZS--- + ******************************************/ +void z8002_device::Z1C_ddN0_1000() +{ + GET_DST(OP0,NIB2); + TESTL(RDMEM_L(AS_DATA, addr_from_reg(dst))); +} + +/****************************************** + ldm @rd,rs,n + flags: ------ + ******************************************/ +void z8002_device::Z1C_ddN0_1001_0000_ssss_0000_nmin1() +{ + GET_DST(OP0,NIB2); + GET_CNT(OP1,NIB3); + GET_SRC(OP1,NIB1); + UINT32 addr = addr_from_reg(dst); + while (cnt-- >= 0) { + WRMEM_W(AS_DATA, addr, RW(src)); + addr = addr_add(addr, 2); + src = (src+1) & 15; + } +} + +/****************************************** + ldm rd,@rs,n + flags: ------ + ******************************************/ +void z8002_device::Z1C_ssN0_0001_0000_dddd_0000_nmin1() +{ + GET_SRC(OP0,NIB2); + GET_CNT(OP1,NIB3); + GET_DST(OP1,NIB1); + UINT32 addr = addr_from_reg(src); + while (cnt-- >= 0) { + RW(dst) = RDMEM_W(AS_DATA, addr); + addr = addr_add(addr, 2); + dst = (dst+1) & 15; + } +} + +/****************************************** + ldl @rd,rrs + flags: ------ + ******************************************/ +void z8002_device::Z1D_ddN0_ssss() +{ + GET_SRC(OP0,NIB3); + GET_DST(OP0,NIB2); + WRMEM_L(AS_DATA, addr_from_reg(dst), RL(src)); +} + +/****************************************** + jp cc,rd + flags: ------ + ******************************************/ +void z8002_device::Z1E_ddN0_cccc() +{ + GET_CCC(OP0,NIB3); + GET_DST(OP0,NIB2); + switch (cc) { + case 0: if (CC0) set_pc(addr_from_reg(dst)); break; + case 1: if (CC1) set_pc(addr_from_reg(dst)); break; + case 2: if (CC2) set_pc(addr_from_reg(dst)); break; + case 3: if (CC3) set_pc(addr_from_reg(dst)); break; + case 4: if (CC4) set_pc(addr_from_reg(dst)); break; + case 5: if (CC5) set_pc(addr_from_reg(dst)); break; + case 6: if (CC6) set_pc(addr_from_reg(dst)); break; + case 7: if (CC7) set_pc(addr_from_reg(dst)); break; + case 8: if (CC8) set_pc(addr_from_reg(dst)); break; + case 9: if (CC9) set_pc(addr_from_reg(dst)); break; + case 10: if (CCA) set_pc(addr_from_reg(dst)); break; + case 11: if (CCB) set_pc(addr_from_reg(dst)); break; + case 12: if (CCC) set_pc(addr_from_reg(dst)); break; + case 13: if (CCD) set_pc(addr_from_reg(dst)); break; + case 14: if (CCE) set_pc(addr_from_reg(dst)); break; + case 15: if (CCF) set_pc(addr_from_reg(dst)); break; + } +} + +/****************************************** + call @rd + flags: ------ + ******************************************/ +void z8002_device::Z1F_ddN0_0000() +{ + GET_DST(OP0,NIB2); + if (segmented_mode()) + PUSHL(SP, make_segmented_addr(m_pc)); + else + PUSHW(SP, m_pc); + set_pc(addr_from_reg(dst)); +} + +/****************************************** + ldb rbd,@rs + flags: ------ + ******************************************/ +void z8002_device::Z20_ssN0_dddd() +{ + GET_DST(OP0,NIB3); + GET_SRC(OP0,NIB2); + RB(dst) = RDMEM_B(AS_DATA, addr_from_reg(src)); +} + +/****************************************** + ld rd,imm16 + flags: ------ + ******************************************/ +void z8002_device::Z21_0000_dddd_imm16() +{ + GET_DST(OP0,NIB3); + GET_IMM16(OP1); + RW(dst) = imm16; +} + +/****************************************** + ld rd,@rs + flags: ------ + ******************************************/ +void z8002_device::Z21_ssN0_dddd() +{ + GET_DST(OP0,NIB3); + GET_SRC(OP0,NIB2); + RW(dst) = RDMEM_W(AS_DATA, addr_from_reg(src)); +} + +/****************************************** + resb rbd,rs + flags: ------ + ******************************************/ +void z8002_device::Z22_0000_ssss_0000_dddd_0000_0000() +{ + GET_SRC(OP0,NIB3); + GET_DST(OP1,NIB1); + RB(dst) = RB(dst) & ~(1 << (RW(src) & 7)); +} + +/****************************************** + resb @rd,imm4 + flags: ------ + ******************************************/ +void z8002_device::Z22_ddN0_imm4() +{ + GET_BIT(OP0); + GET_DST(OP0,NIB2); + UINT32 addr = addr_from_reg(dst); + WRMEM_B(AS_DATA, addr, RDMEM_B(AS_DATA, addr) & ~bit); +} + +/****************************************** + res rd,rs + flags: ------ + ******************************************/ +void z8002_device::Z23_0000_ssss_0000_dddd_0000_0000() +{ + GET_SRC(OP0,NIB3); + GET_DST(OP1,NIB1); + RW(dst) = RW(dst) & ~(1 << (RW(src) & 15)); +} + +/****************************************** + res @rd,imm4 + flags: ------ + ******************************************/ +void z8002_device::Z23_ddN0_imm4() +{ + GET_BIT(OP0); + GET_DST(OP0,NIB2); + UINT32 addr = addr_from_reg(dst); + WRMEM_W(AS_DATA, addr, RDMEM_W(AS_DATA, addr) & ~bit); +} + +/****************************************** + setb rbd,rs + flags: ------ + ******************************************/ +void z8002_device::Z24_0000_ssss_0000_dddd_0000_0000() +{ + GET_SRC(OP0,NIB3); + GET_DST(OP1,NIB1); + RB(dst) = RB(dst) | (1 << (RW(src) & 7)); +} + +/****************************************** + setb @rd,imm4 + flags: ------ + ******************************************/ +void z8002_device::Z24_ddN0_imm4() +{ + GET_BIT(OP0); + GET_DST(OP0,NIB2); + UINT32 addr = addr_from_reg(dst); + WRMEM_B(AS_DATA, addr, RDMEM_B(AS_DATA, addr) | bit); +} + +/****************************************** + set rd,rs + flags: ------ + ******************************************/ +void z8002_device::Z25_0000_ssss_0000_dddd_0000_0000() +{ + GET_SRC(OP0,NIB3); + GET_DST(OP1,NIB1); + RW(dst) = RW(dst) | (1 << (RW(src) & 15)); +} + +/****************************************** + set @rd,imm4 + flags: ------ + ******************************************/ +void z8002_device::Z25_ddN0_imm4() +{ + GET_BIT(OP0); + GET_DST(OP0,NIB2); + UINT32 addr = addr_from_reg(dst); + WRMEM_W(AS_DATA, addr, RDMEM_W(AS_DATA, addr) | bit); +} + +/****************************************** + bitb rbd,rs + flags: -Z---- + ******************************************/ +void z8002_device::Z26_0000_ssss_0000_dddd_0000_0000() +{ + GET_SRC(OP0,NIB3); + GET_DST(OP1,NIB1); + if (RB(dst) & (1 << (RW(src) & 7))) CLR_Z; else SET_Z; +} + +/****************************************** + bitb @rd,imm4 + flags: -Z---- + ******************************************/ +void z8002_device::Z26_ddN0_imm4() +{ + GET_BIT(OP0); + GET_DST(OP0,NIB2); + if (RDMEM_B(AS_DATA, addr_from_reg(dst)) & bit) CLR_Z; else SET_Z; +} + +/****************************************** + bit rd,rs + flags: -Z---- + ******************************************/ +void z8002_device::Z27_0000_ssss_0000_dddd_0000_0000() +{ + GET_SRC(OP0,NIB3); + GET_DST(OP1,NIB1); + if (RW(dst) & (1 << (RW(src) & 15))) CLR_Z; else SET_Z; +} + +/****************************************** + bit @rd,imm4 + flags: -Z---- + ******************************************/ +void z8002_device::Z27_ddN0_imm4() +{ + GET_BIT(OP0); + GET_DST(OP0,NIB2); + if (RDMEM_W(AS_DATA, addr_from_reg(dst)) & bit) CLR_Z; else SET_Z; +} + +/****************************************** + incb @rd,imm4m1 + flags: -ZSV-- + ******************************************/ +void z8002_device::Z28_ddN0_imm4m1() +{ + GET_I4M1(OP0,NIB3); + GET_DST(OP0,NIB2); + UINT32 addr = addr_from_reg(dst); + WRMEM_B(AS_DATA, addr, INCB(RDMEM_B(AS_DATA, addr), i4p1)); +} + +/****************************************** + inc @rd,imm4m1 + flags: -ZSV-- + ******************************************/ +void z8002_device::Z29_ddN0_imm4m1() +{ + GET_I4M1(OP0,NIB3); + GET_DST(OP0,NIB2); + UINT32 addr = addr_from_reg(dst); + WRMEM_W(AS_DATA, addr, INCW(RDMEM_W(AS_DATA, addr), i4p1)); +} + +/****************************************** + decb @rd,imm4m1 + flags: -ZSV-- + ******************************************/ +void z8002_device::Z2A_ddN0_imm4m1() +{ + GET_I4M1(OP0,NIB3); + GET_DST(OP0,NIB2); + UINT32 addr = addr_from_reg(dst); + WRMEM_B(AS_DATA, addr, DECB(RDMEM_B(AS_DATA, addr), i4p1)); +} + +/****************************************** + dec @rd,imm4m1 + flags: -ZSV-- + ******************************************/ +void z8002_device::Z2B_ddN0_imm4m1() +{ + GET_I4M1(OP0,NIB3); + GET_DST(OP0,NIB2); + UINT32 addr = addr_from_reg(dst); + WRMEM_W(AS_DATA, addr, DECW(RDMEM_W(AS_DATA, addr), i4p1)); +} + +/****************************************** + exb rbd,@rs + flags: ------ + ******************************************/ +void z8002_device::Z2C_ssN0_dddd() +{ + GET_DST(OP0,NIB3); + GET_SRC(OP0,NIB2); + UINT32 addr = addr_from_reg(src); + UINT8 tmp = RDMEM_B( AS_DATA, addr); + WRMEM_B(AS_DATA, addr, RB(dst)); + RB(dst) = tmp; +} + +/****************************************** + ex rd,@rs + flags: ------ + ******************************************/ +void z8002_device::Z2D_ssN0_dddd() +{ + GET_DST(OP0,NIB3); + GET_SRC(OP0,NIB2); + UINT32 addr = addr_from_reg(src); + UINT16 tmp = RDMEM_W(AS_DATA, addr); + WRMEM_W(AS_DATA, addr, RW(dst)); + RW(dst) = tmp; +} + +/****************************************** + ldb @rd,rbs + flags: ------ + ******************************************/ +void z8002_device::Z2E_ddN0_ssss() +{ + GET_SRC(OP0,NIB3); + GET_DST(OP0,NIB2); + WRMEM_B(AS_DATA, addr_from_reg(dst), RB(src)); +} + +/****************************************** + ld @rd,rs + flags: ------ + ******************************************/ +void z8002_device::Z2F_ddN0_ssss() +{ + GET_SRC(OP0,NIB3); + GET_DST(OP0,NIB2); + WRMEM_W(AS_DATA, addr_from_reg(dst), RW(src)); +} + +/****************************************** + ldrb rbd,dsp16 + flags: ------ + ******************************************/ +void z8002_device::Z30_0000_dddd_dsp16() +{ + GET_DST(OP0,NIB3); + GET_DSP16; + RB(dst) = RDMEM_B(AS_PROGRAM, dsp16); +} + +/****************************************** + ldb rbd,rs(idx16) + flags: ------ + ******************************************/ +void z8002_device::Z30_ssN0_dddd_imm16() +{ + GET_DST(OP0,NIB3); + GET_SRC(OP0,NIB2); + GET_IDX16(OP1); + idx16 = addr_add(addr_from_reg(src), idx16); + RB(dst) = RDMEM_B(AS_DATA, idx16); +} + +/****************************************** + ldr rd,dsp16 + flags: ------ + ******************************************/ +void z8002_device::Z31_0000_dddd_dsp16() +{ + GET_DST(OP0,NIB3); + GET_DSP16; + RW(dst) = RDMEM_W(AS_PROGRAM, dsp16); +} + +/****************************************** + ld rd,rs(idx16) + flags: ------ + ******************************************/ +void z8002_device::Z31_ssN0_dddd_imm16() +{ + GET_DST(OP0,NIB3); + GET_SRC(OP0,NIB2); + GET_IDX16(OP1); + idx16 = addr_add(addr_from_reg(src), idx16); + RW(dst) = RDMEM_W(AS_DATA, idx16); +} + +/****************************************** + ldrb dsp16,rbs + flags: ------ + ******************************************/ +void z8002_device::Z32_0000_ssss_dsp16() +{ + GET_SRC(OP0,NIB3); + GET_DSP16; + WRMEM_B(AS_PROGRAM, dsp16, RB(src)); +} + +/****************************************** + ldb rd(idx16),rbs + flags: ------ + ******************************************/ +void z8002_device::Z32_ddN0_ssss_imm16() +{ + GET_SRC(OP0,NIB3); + GET_DST(OP0,NIB2); + GET_IDX16(OP1); + idx16 = addr_add(addr_from_reg(dst), idx16); + WRMEM_B(AS_DATA, idx16, RB(src)); +} + +/****************************************** + ldr dsp16,rs + flags: ------ + ******************************************/ +void z8002_device::Z33_0000_ssss_dsp16() +{ + GET_SRC(OP0,NIB3); + GET_DSP16; + WRMEM_W(AS_PROGRAM, dsp16, RW(src)); +} + +/****************************************** + ld rd(idx16),rs + flags: ------ + ******************************************/ +void z8002_device::Z33_ddN0_ssss_imm16() +{ + GET_SRC(OP0,NIB3); + GET_DST(OP0,NIB2); + GET_IDX16(OP1); + idx16 = addr_add(addr_from_reg(dst), idx16); + WRMEM_W(AS_DATA, idx16, RW(src)); +} + +/****************************************** + ldar prd,dsp16 + flags: ------ + ******************************************/ +void z8002_device::Z34_0000_dddd_dsp16() +{ + GET_DST(OP0,NIB3); + GET_DSP16; + addr_to_reg(dst, dsp16); +} + +/****************************************** + lda prd,rs(idx16) + flags: ------ + ******************************************/ +void z8002_device::Z34_ssN0_dddd_imm16() +{ + GET_DST(OP0,NIB3); + GET_SRC(OP0,NIB2); + GET_IDX16(OP1); + if (segmented_mode()) { + RL(dst) = RL(src); + } + else { + RW(dst) = RW(src); + } + add_to_addr_reg(dst, idx16); +} + +/****************************************** + ldrl rrd,dsp16 + flags: ------ + ******************************************/ +void z8002_device::Z35_0000_dddd_dsp16() +{ + GET_DST(OP0,NIB3); + GET_DSP16; + RL(dst) = RDMEM_L(AS_PROGRAM, dsp16); +} + +/****************************************** + ldl rrd,rs(idx16) + flags: ------ + ******************************************/ +void z8002_device::Z35_ssN0_dddd_imm16() +{ + GET_DST(OP0,NIB3); + GET_SRC(OP0,NIB2); + GET_IDX16(OP1); + idx16 = addr_add(addr_from_reg(src), idx16); + RL(dst) = RDMEM_L(AS_DATA, idx16); +} + +/****************************************** + bpt + flags: ------ + ******************************************/ +void z8002_device::Z36_0000_0000() +{ + /* execute break point trap m_irq_req */ + m_irq_req = Z8000_TRAP; +} + +/****************************************** + rsvd36 + flags: ------ + ******************************************/ +void z8002_device::Z36_imm8() +{ + GET_IMM8(0); + LOG(("Z8K '%s' %04x: rsvd36 $%02x\n", tag(), m_pc, imm8)); + if (m_fcw & F_EPU) { + /* Z8001 EPU code goes here */ + (void)imm8; + } +} + +/****************************************** + ldrl dsp16,rrs + flags: ------ + ******************************************/ +void z8002_device::Z37_0000_ssss_dsp16() +{ + GET_SRC(OP0,NIB3); + GET_DSP16; + WRMEM_L(AS_PROGRAM, dsp16, RL(src)); +} + +/****************************************** + ldl rd(idx16),rrs + flags: ------ + ******************************************/ +void z8002_device::Z37_ddN0_ssss_imm16() +{ + GET_SRC(OP0,NIB3); + GET_DST(OP0,NIB2); + GET_IDX16(OP1); + idx16 = addr_add(addr_from_reg(dst), idx16); + WRMEM_L(AS_DATA, idx16, RL(src)); +} + +/****************************************** + rsvd38 + flags: ------ + ******************************************/ +void z8002_device::Z38_imm8() +{ + GET_IMM8(0); + LOG(("Z8K '%s' %04x: rsvd38 $%02x\n", tag(), m_pc, imm8)); + if (m_fcw & F_EPU) { + /* Z8001 EPU code goes here */ + (void)imm8; + } +} + +/****************************************** + ldps @rs + flags: CZSVDH + ******************************************/ +void z8002_device::Z39_ssN0_0000() +{ + CHECK_PRIVILEGED_INSTR(); + GET_SRC(OP0,NIB2); + UINT16 fcw; + if (segmented_mode()) { + UINT32 addr = addr_from_reg(src); + fcw = RDMEM_W(AS_DATA, addr + 2); + set_pc(segmented_addr(RDMEM_L(AS_DATA, addr + 4))); + } + else { + fcw = RDMEM_W(AS_DATA, RW(src)); + set_pc(RDMEM_W(AS_DATA, (UINT16)(RW(src) + 2))); + } + if ((fcw ^ m_fcw) & F_SEG) printf("ldps 1 (0x%05x): changing from %ssegmented mode to %ssegmented mode\n", m_pc, (m_fcw & F_SEG) ? "non-" : "", (fcw & F_SEG) ? "" : "non-"); + CHANGE_FCW(fcw); /* check for user/system mode change */ +} + +/****************************************** + inib(r) @rd,@rs,ra + flags: ---V-- + ******************************************/ +void z8002_device::Z3A_ssss_0000_0000_aaaa_dddd_x000() +{ + CHECK_PRIVILEGED_INSTR(); + GET_SRC(OP0,NIB2); + GET_CNT(OP1,NIB1); + GET_DST(OP1,NIB2); + GET_CCC(OP1,NIB3); + WRMEM_B(AS_DATA, addr_from_reg(dst), RDPORT_B( 0, RW(src))); + add_to_addr_reg(dst, 1); + if (--RW(cnt)) { CLR_V; if (cc == 0) m_pc -= 4; } else SET_V; +} + +/****************************************** + sinib @rd,@rs,ra + sinibr @rd,@rs,ra + flags: ------ + ******************************************/ +void z8002_device::Z3A_ssss_0001_0000_aaaa_dddd_x000() +{//@@@@ + CHECK_PRIVILEGED_INSTR(); + GET_SRC(OP0,NIB2); + GET_CNT(OP1,NIB1); + GET_DST(OP1,NIB2); + GET_CCC(OP1,NIB3); + WRMEM_B(AS_DATA, RW(dst), RDPORT_B( 1, RW(src))); + RW(dst)++; + RW(src)++; + if (--RW(cnt)) { CLR_V; if (cc == 0) m_pc -= 4; } else SET_V; +} + +/****************************************** + outib @rd,@rs,ra + outibr @rd,@rs,ra + flags: ---V-- + ******************************************/ +void z8002_device::Z3A_ssss_0010_0000_aaaa_dddd_x000() +{ + CHECK_PRIVILEGED_INSTR(); + GET_SRC(OP0,NIB2); + GET_CNT(OP1,NIB1); + GET_DST(OP1,NIB2); + GET_CCC(OP1,NIB3); + WRPORT_B( 0, RW(dst), RDMEM_B(AS_DATA, addr_from_reg(src))); + add_to_addr_reg(src, 1); + if (--RW(cnt)) { CLR_V; if (cc == 0) m_pc -= 4; } else SET_V; +} + +/****************************************** + soutib @rd,@rs,ra + soutibr @rd,@rs,ra + flags: ------ + ******************************************/ +void z8002_device::Z3A_ssss_0011_0000_aaaa_dddd_x000() +{//@@@@ + CHECK_PRIVILEGED_INSTR(); + GET_SRC(OP0,NIB2); + GET_CNT(OP1,NIB1); + GET_DST(OP1,NIB2); + GET_CCC(OP1,NIB3); + WRPORT_B( 1, RW(dst), RDMEM_B(AS_DATA, RW(src))); + RW(dst)++; + RW(src)++; + if (--RW(cnt)) { CLR_V; if (cc == 0) m_pc -= 4; } else SET_V; +} + +/****************************************** + inb rbd,imm16 + flags: ------ + ******************************************/ +void z8002_device::Z3A_dddd_0100_imm16() +{ + CHECK_PRIVILEGED_INSTR(); + GET_DST(OP0,NIB2); + GET_IMM16(OP1); + RB(dst) = RDPORT_B( 0, imm16); +} + +/****************************************** + sinb rbd,imm16 + flags: ------ + ******************************************/ +void z8002_device::Z3A_dddd_0101_imm16() +{ + CHECK_PRIVILEGED_INSTR(); + GET_DST(OP0,NIB2); + GET_IMM16(OP1); + RB(dst) = RDPORT_B( 1, imm16); +} + +/****************************************** + outb imm16,rbs + flags: ---V-- + ******************************************/ +void z8002_device::Z3A_ssss_0110_imm16() +{ + CHECK_PRIVILEGED_INSTR(); + GET_SRC(OP0,NIB2); + GET_IMM16(OP1); + WRPORT_B( 0, imm16, RB(src)); +} + +/****************************************** + soutb imm16,rbs + flags: ------ + ******************************************/ +void z8002_device::Z3A_ssss_0111_imm16() +{ + CHECK_PRIVILEGED_INSTR(); + GET_SRC(OP0,NIB2); + GET_IMM16(OP1); + WRPORT_B( 1, imm16, RB(src)); +} + +/****************************************** + indb @rd,@rs,rba + indbr @rd,@rs,rba + flags: ---V-- + ******************************************/ +void z8002_device::Z3A_ssss_1000_0000_aaaa_dddd_x000() +{//@@@ + CHECK_PRIVILEGED_INSTR(); + GET_SRC(OP0,NIB2); + GET_CNT(OP1,NIB1); + GET_DST(OP1,NIB2); + GET_CCC(OP1,NIB3); + WRMEM_B(AS_DATA, RW(dst), RDPORT_B( 0, RW(src))); + RW(dst)--; + RW(src)--; + if (--RW(cnt)) { CLR_V; if (cc == 0) m_pc -= 4; } else SET_V; +} + +/****************************************** + sindb @rd,@rs,rba + sindbr @rd,@rs,rba + flags: ------ + ******************************************/ +void z8002_device::Z3A_ssss_1001_0000_aaaa_dddd_x000() +{//@@@ + CHECK_PRIVILEGED_INSTR(); + GET_SRC(OP0,NIB2); + GET_CNT(OP1,NIB1); + GET_DST(OP1,NIB2); + GET_CCC(OP1,NIB3); + WRMEM_B(AS_DATA, RW(dst), RDPORT_B( 1, RW(src))); + RW(dst)--; + RW(src)--; + if (--RW(cnt)) { CLR_V; if (cc == 0) m_pc -= 4; } else SET_V; +} + +/****************************************** + outdb @rd,@rs,rba + outdbr @rd,@rs,rba + flags: ---V-- + ******************************************/ +void z8002_device::Z3A_ssss_1010_0000_aaaa_dddd_x000() +{//@@@ + CHECK_PRIVILEGED_INSTR(); + GET_SRC(OP0,NIB2); + GET_CNT(OP1,NIB1); + GET_DST(OP1,NIB2); + GET_CCC(OP1,NIB3); + WRPORT_B( 0, RW(dst), RDMEM_B(AS_DATA, RW(src))); + RW(dst)--; + RW(src)--; + if (--RW(cnt)) { CLR_V; if (cc == 0) m_pc -= 4; } else SET_V; +} + +/****************************************** + soutdb @rd,@rs,rba + soutdbr @rd,@rs,rba + flags: ------ + ******************************************/ +void z8002_device::Z3A_ssss_1011_0000_aaaa_dddd_x000() +{//@@@ + CHECK_PRIVILEGED_INSTR(); + GET_SRC(OP0,NIB2); + GET_CNT(OP1,NIB1); + GET_DST(OP1,NIB2); + GET_CCC(OP1,NIB3); + WRPORT_B( 1, RW(dst), RDMEM_B(AS_DATA, RW(src))); + RW(dst)--; + RW(src)--; + if (--RW(cnt)) { CLR_V; if (cc == 0) m_pc -= 4; } else SET_V; +} + +/****************************************** + ini @rd,@rs,ra + inir @rd,@rs,ra + flags: ---V-- + ******************************************/ +void z8002_device::Z3B_ssss_0000_0000_aaaa_dddd_x000() +{//@@@ + CHECK_PRIVILEGED_INSTR(); + GET_SRC(OP0,NIB2); + GET_CNT(OP1,NIB1); + GET_DST(OP1,NIB2); + GET_CCC(OP1,NIB3); + WRMEM_W(AS_DATA, RW(dst), RDPORT_W( 0, RW(src))); + RW(dst) += 2; + RW(src) += 2; + if (--RW(cnt)) { CLR_V; if (cc == 0) m_pc -= 4; } else SET_V; +} + +/****************************************** + sini @rd,@rs,ra + sinir @rd,@rs,ra + flags: ------ + ******************************************/ +void z8002_device::Z3B_ssss_0001_0000_aaaa_dddd_x000() +{//@@@ + CHECK_PRIVILEGED_INSTR(); + GET_SRC(OP0,NIB2); + GET_CNT(OP1,NIB1); + GET_DST(OP1,NIB2); + GET_CCC(OP1,NIB3); + WRMEM_W(AS_DATA, RW(dst), RDPORT_W( 1, RW(src))); + RW(dst) += 2; + RW(src) += 2; + if (--RW(cnt)) { CLR_V; if (cc == 0) m_pc -= 4; } else SET_V; +} + +/****************************************** + outi @rd,@rs,ra + outir @rd,@rs,ra + flags: ---V-- + ******************************************/ +void z8002_device::Z3B_ssss_0010_0000_aaaa_dddd_x000() +{//@@@ + CHECK_PRIVILEGED_INSTR(); + GET_SRC(OP0,NIB2); + GET_CNT(OP1,NIB1); + GET_DST(OP1,NIB2); + GET_CCC(OP1,NIB3); + WRPORT_W( 0, RW(dst), RDMEM_W(AS_DATA, RW(src))); + RW(dst) += 2; + RW(src) += 2; + if (--RW(cnt)) { CLR_V; if (cc == 0) m_pc -= 4; } else SET_V; +} + +/****************************************** + souti @rd,@rs,ra + soutir @rd,@rs,ra + flags: ------ + ******************************************/ +void z8002_device::Z3B_ssss_0011_0000_aaaa_dddd_x000() +{//@@@ + CHECK_PRIVILEGED_INSTR(); + GET_SRC(OP0,NIB2); + GET_CNT(OP1,NIB1); + GET_DST(OP1,NIB2); + GET_CCC(OP1,NIB3); + WRPORT_W( 1, RW(dst), RDMEM_W(AS_DATA, RW(src))); + RW(dst) += 2; + RW(src) += 2; + if (--RW(cnt)) { CLR_V; if (cc == 0) m_pc -= 4; } else SET_V; +} + +/****************************************** + in rd,imm16 + flags: ------ + ******************************************/ +void z8002_device::Z3B_dddd_0100_imm16() +{ + CHECK_PRIVILEGED_INSTR(); + GET_DST(OP0,NIB2); + GET_IMM16(OP1); + RW(dst) = RDPORT_W( 0, imm16); +} + +/****************************************** + sin rd,imm16 + flags: ------ + ******************************************/ +void z8002_device::Z3B_dddd_0101_imm16() +{ + CHECK_PRIVILEGED_INSTR(); + GET_DST(OP0,NIB2); + GET_IMM16(OP1); + RW(dst) = RDPORT_W( 1, imm16); +} + +/****************************************** + out imm16,rs + flags: ---V-- + ******************************************/ +void z8002_device::Z3B_ssss_0110_imm16() +{ + CHECK_PRIVILEGED_INSTR(); + GET_SRC(OP0,NIB2); + GET_IMM16(OP1); + WRPORT_W( 0, imm16, RW(src)); +} + +/****************************************** + sout imm16,rbs + flags: ------ + ******************************************/ +void z8002_device::Z3B_ssss_0111_imm16() +{ + CHECK_PRIVILEGED_INSTR(); + GET_SRC(OP0,NIB2); + GET_IMM16(OP1); + WRPORT_W( 1, imm16, RW(src)); +} + +/****************************************** + ind @rd,@rs,ra + indr @rd,@rs,ra + flags: ---V-- + ******************************************/ +void z8002_device::Z3B_ssss_1000_0000_aaaa_dddd_x000() +{//@@@ + CHECK_PRIVILEGED_INSTR(); + GET_SRC(OP0,NIB2); + GET_CNT(OP1,NIB1); + GET_DST(OP1,NIB2); + GET_CCC(OP1,NIB3); + WRMEM_W(AS_DATA, RW(dst), RDPORT_W( 0, RW(src))); + RW(dst) -= 2; + RW(src) -= 2; + if (--RW(cnt)) { CLR_V; if (cc == 0) m_pc -= 4; } else SET_V; +} + +/****************************************** + sind @rd,@rs,ra + sindr @rd,@rs,ra + flags: ------ + ******************************************/ +void z8002_device::Z3B_ssss_1001_0000_aaaa_dddd_x000() +{//@@@ + CHECK_PRIVILEGED_INSTR(); + GET_SRC(OP0,NIB2); + GET_CNT(OP1,NIB1); + GET_DST(OP1,NIB2); + GET_CCC(OP1,NIB3); + WRMEM_W(AS_DATA, RW(dst), RDPORT_W( 1, RW(src))); + RW(dst) -= 2; + RW(src) -= 2; + if (--RW(cnt)) { CLR_V; if (cc == 0) m_pc -= 4; } else SET_V; +} + +/****************************************** + outd @rd,@rs,ra + outdr @rd,@rs,ra + flags: ---V-- + ******************************************/ +void z8002_device::Z3B_ssss_1010_0000_aaaa_dddd_x000() +{//@@@ + CHECK_PRIVILEGED_INSTR(); + GET_SRC(OP0,NIB2); + GET_CNT(OP1,NIB1); + GET_DST(OP1,NIB2); + GET_CCC(OP1,NIB3); + WRPORT_W( 0, RW(dst), RDMEM_W(AS_DATA, RW(src))); + RW(dst) -= 2; + RW(src) -= 2; + if (--RW(cnt)) { CLR_V; if (cc == 0) m_pc -= 4; } else SET_V; +} + +/****************************************** + soutd @rd,@rs,ra + soutdr @rd,@rs,ra + flags: ------ + ******************************************/ +void z8002_device::Z3B_ssss_1011_0000_aaaa_dddd_x000() +{//@@@ + CHECK_PRIVILEGED_INSTR(); + GET_SRC(OP0,NIB2); + GET_CNT(OP1,NIB1); + GET_DST(OP1,NIB2); + GET_CCC(OP1,NIB3); + WRPORT_W( 1, RW(dst), RDMEM_W(AS_DATA, RW(src))); + RW(dst) -= 2; + RW(src) -= 2; + if (--RW(cnt)) { CLR_V; if (cc == 0) m_pc -= 4; } else SET_V; +} + +/****************************************** + inb rbd,@rs + flags: ------ + ******************************************/ +void z8002_device::Z3C_ssss_dddd() +{ + CHECK_PRIVILEGED_INSTR(); + GET_SRC(OP0,NIB2); + GET_DST(OP0,NIB3); + RB(dst) = RDPORT_B( 0, RW(src)); +} + +/****************************************** + in rd,@rs + flags: ------ + ******************************************/ +void z8002_device::Z3D_ssss_dddd() +{ + CHECK_PRIVILEGED_INSTR(); + GET_SRC(OP0,NIB2); + GET_DST(OP0,NIB3); + RW(dst) = RDPORT_W( 0, RW(src)); +} + +/****************************************** + outb @rd,rbs + flags: ---V-- + ******************************************/ +void z8002_device::Z3E_dddd_ssss() +{ + CHECK_PRIVILEGED_INSTR(); + GET_DST(OP0,NIB2); + GET_SRC(OP0,NIB3); + WRPORT_B( 0, RW(dst), RB(src)); +} + +/****************************************** + out @rd,rs + flags: ---V-- + ******************************************/ +void z8002_device::Z3F_dddd_ssss() +{ + CHECK_PRIVILEGED_INSTR(); + GET_DST(OP0,NIB2); + GET_SRC(OP0,NIB3); + WRPORT_W( 0, RW(dst), RW(src)); +} + +/****************************************** + addb rbd,addr + flags: CZSVDH + ******************************************/ +void z8002_device::Z40_0000_dddd_addr() +{ + GET_DST(OP0,NIB3); + GET_ADDR(OP1); + RB(dst) = ADDB(RB(dst), RDMEM_B(AS_DATA, addr)); +} + +/****************************************** + addb rbd,addr(rs) + flags: CZSVDH + ******************************************/ +void z8002_device::Z40_ssN0_dddd_addr() +{ + GET_DST(OP0,NIB3); + GET_SRC(OP0,NIB2); + GET_ADDR(OP1); + addr = addr_add(addr, RW(src)); + RB(dst) = ADDB(RB(dst), RDMEM_B(AS_DATA, addr)); +} + +/****************************************** + add rd,addr + flags: CZSV-- + ******************************************/ +void z8002_device::Z41_0000_dddd_addr() +{ + GET_DST(OP0,NIB3); + GET_ADDR(OP1); + RW(dst) = ADDW(RW(dst), RDMEM_W(AS_DATA, addr)); /* EHC */ +} + +/****************************************** + add rd,addr(rs) + flags: CZSV-- + ******************************************/ +void z8002_device::Z41_ssN0_dddd_addr() +{ + GET_DST(OP0,NIB3); + GET_SRC(OP0,NIB2); + GET_ADDR(OP1); + addr = addr_add(addr, RW(src)); + RW(dst) = ADDW(RW(dst), RDMEM_W(AS_DATA, addr)); /* ASG */ +} + +/****************************************** + subb rbd,addr + flags: CZSVDH + ******************************************/ +void z8002_device::Z42_0000_dddd_addr() +{ + GET_DST(OP0,NIB3); + GET_ADDR(OP1); + RB(dst) = SUBB(RB(dst), RDMEM_B(AS_DATA, addr)); /* EHC */ +} + +/****************************************** + subb rbd,addr(rs) + flags: CZSVDH + ******************************************/ +void z8002_device::Z42_ssN0_dddd_addr() +{ + GET_DST(OP0,NIB3); + GET_SRC(OP0,NIB2); + GET_ADDR(OP1); + addr = addr_add(addr, RW(src)); + RB(dst) = SUBB(RB(dst), RDMEM_B(AS_DATA, addr)); +} + +/****************************************** + sub rd,addr + flags: CZSV-- + ******************************************/ +void z8002_device::Z43_0000_dddd_addr() +{ + GET_DST(OP0,NIB3); + GET_ADDR(OP1); + RW(dst) = SUBW(RW(dst), RDMEM_W(AS_DATA, addr)); +} + +/****************************************** + sub rd,addr(rs) + flags: CZSV-- + ******************************************/ +void z8002_device::Z43_ssN0_dddd_addr() +{ + GET_DST(OP0,NIB3); + GET_SRC(OP0,NIB2); + GET_ADDR(OP1); + addr = addr_add(addr, RW(src)); + RW(dst) = SUBW(RW(dst), RDMEM_W(AS_DATA, addr)); +} + +/****************************************** + orb rbd,addr + flags: CZSP-- + ******************************************/ +void z8002_device::Z44_0000_dddd_addr() +{ + GET_DST(OP0,NIB3); + GET_ADDR(OP1); + RB(dst) = ORB(RB(dst), RDMEM_B(AS_DATA, addr)); +} + +/****************************************** + orb rbd,addr(rs) + flags: CZSP-- + ******************************************/ +void z8002_device::Z44_ssN0_dddd_addr() +{ + GET_DST(OP0,NIB3); + GET_SRC(OP0,NIB2); + GET_ADDR(OP1); + addr = addr_add(addr, RW(src)); + RB(dst) = ORB(RB(dst), RDMEM_B(AS_DATA, addr)); +} + +/****************************************** + or rd,addr + flags: CZS--- + ******************************************/ +void z8002_device::Z45_0000_dddd_addr() +{ + GET_DST(OP0,NIB3); + GET_ADDR(OP1); + RW(dst) = ORW(RW(dst), RDMEM_W(AS_DATA, addr)); +} + +/****************************************** + or rd,addr(rs) + flags: CZS--- + ******************************************/ +void z8002_device::Z45_ssN0_dddd_addr() +{ + GET_DST(OP0,NIB3); + GET_SRC(OP0,NIB2); + GET_ADDR(OP1); + addr = addr_add(addr, RW(src)); + RW(dst) = ORW(RW(dst), RDMEM_W(AS_DATA, addr)); +} + +/****************************************** + andb rbd,addr + flags: -ZSP-- + ******************************************/ +void z8002_device::Z46_0000_dddd_addr() +{ + GET_DST(OP0,NIB3); + GET_ADDR(OP1); + RB(dst) = ANDB(RB(dst), RDMEM_B(AS_DATA, addr)); +} + +/****************************************** + andb rbd,addr(rs) + flags: -ZSP-- + ******************************************/ +void z8002_device::Z46_ssN0_dddd_addr() +{ + GET_DST(OP0,NIB3); + GET_SRC(OP0,NIB2); + GET_ADDR(OP1); + addr = addr_add(addr, RW(src)); + RB(dst) = ANDB(RB(dst), RDMEM_B(AS_DATA, addr)); +} + +/****************************************** + and rd,addr + flags: -ZS--- + ******************************************/ +void z8002_device::Z47_0000_dddd_addr() +{ + GET_DST(OP0,NIB3); + GET_ADDR(OP1); + RW(dst) = ANDW(RW(dst), RDMEM_W(AS_DATA, addr)); +} + +/****************************************** + and rd,addr(rs) + flags: -ZS--- + ******************************************/ +void z8002_device::Z47_ssN0_dddd_addr() +{ + GET_DST(OP0,NIB3); + GET_SRC(OP0,NIB2); + GET_ADDR(OP1); + addr = addr_add(addr, RW(src)); + RW(dst) = ANDW(RW(dst), RDMEM_W(AS_DATA, addr)); +} + +/****************************************** + xorb rbd,addr + flags: -ZSP-- + ******************************************/ +void z8002_device::Z48_0000_dddd_addr() +{ + GET_DST(OP0,NIB3); + GET_ADDR(OP1); + RB(dst) = XORB(RB(dst), RDMEM_B(AS_DATA, addr)); +} + +/****************************************** + xorb rbd,addr(rs) + flags: -ZSP-- + ******************************************/ +void z8002_device::Z48_ssN0_dddd_addr() +{ + GET_DST(OP0,NIB3); + GET_SRC(OP0,NIB2); + GET_ADDR(OP1); + addr = addr_add(addr, RW(src)); + RB(dst) = XORB(RB(dst), RDMEM_B(AS_DATA, addr)); +} + +/****************************************** + xor rd,addr + flags: -ZS--- + ******************************************/ +void z8002_device::Z49_0000_dddd_addr() +{ + GET_DST(OP0,NIB3); + GET_ADDR(OP1); + RW(dst) = XORW(RW(dst), RDMEM_W(AS_DATA, addr)); +} + +/****************************************** + xor rd,addr(rs) + flags: -ZS--- + ******************************************/ +void z8002_device::Z49_ssN0_dddd_addr() +{ + GET_DST(OP0,NIB3); + GET_SRC(OP0,NIB2); + GET_ADDR(OP1); + addr = addr_add(addr, RW(src)); + RW(dst) = XORW(RW(dst), RDMEM_W(AS_DATA, addr)); +} + +/****************************************** + cpb rbd,addr + flags: CZSV-- + ******************************************/ +void z8002_device::Z4A_0000_dddd_addr() +{ + GET_DST(OP0,NIB3); + GET_ADDR(OP1); + CPB(RB(dst), RDMEM_B(AS_DATA, addr)); +} + +/****************************************** + cpb rbd,addr(rs) + flags: CZSV-- + ******************************************/ +void z8002_device::Z4A_ssN0_dddd_addr() +{ + GET_DST(OP0,NIB3); + GET_SRC(OP0,NIB2); + GET_ADDR(OP1); + addr = addr_add(addr, RW(src)); + CPB(RB(dst), RDMEM_B(AS_DATA, addr)); +} + +/****************************************** + cp rd,addr + flags: CZSV-- + ******************************************/ +void z8002_device::Z4B_0000_dddd_addr() +{ + GET_DST(OP0,NIB3); + GET_ADDR(OP1); + CPW(RW(dst), RDMEM_W(AS_DATA, addr)); +} + +/****************************************** + cp rd,addr(rs) + flags: CZSV-- + ******************************************/ +void z8002_device::Z4B_ssN0_dddd_addr() +{ + GET_DST(OP0,NIB3); + GET_SRC(OP0,NIB2); + GET_ADDR(OP1); + addr = addr_add(addr, RW(src)); + CPW(RW(dst), RDMEM_W(AS_DATA, addr)); +} + +/****************************************** + comb addr + flags: -ZSP-- + ******************************************/ +void z8002_device::Z4C_0000_0000_addr() +{ + GET_ADDR(OP1); + WRMEM_B(AS_DATA, addr, COMB(RDMEM_W(AS_DATA, addr))); +} + +/****************************************** + cpb addr,imm8 + flags: CZSV-- + ******************************************/ +void z8002_device::Z4C_0000_0001_addr_imm8() +{ + GET_ADDR(OP1); + GET_IMM8(OP2); + CPB(RDMEM_B(AS_DATA, addr), imm8); +} + +/****************************************** + negb addr + flags: CZSV-- + ******************************************/ +void z8002_device::Z4C_0000_0010_addr() +{ + GET_ADDR(OP1); + WRMEM_B(AS_DATA, addr, NEGB(RDMEM_B(AS_DATA, addr))); +} + +/****************************************** + testb addr + flags: -ZSP-- + ******************************************/ +void z8002_device::Z4C_0000_0100_addr() +{ + GET_ADDR(OP1); + TESTB(RDMEM_B(AS_DATA, addr)); +} + +/****************************************** + ldb addr,imm8 + flags: ------ + ******************************************/ +void z8002_device::Z4C_0000_0101_addr_imm8() +{ + GET_ADDR(OP1); + GET_IMM8(OP2); + WRMEM_B(AS_DATA, addr, imm8); +} + +/****************************************** + tsetb addr + flags: --S--- + ******************************************/ +void z8002_device::Z4C_0000_0110_addr() +{ + GET_ADDR(OP1); + if (RDMEM_B(AS_DATA, addr) & S08) SET_S; else CLR_S; + WRMEM_B(AS_DATA, addr, 0xff); +} + +/****************************************** + clrb addr + flags: ------ + ******************************************/ +void z8002_device::Z4C_0000_1000_addr() +{ + GET_ADDR(OP1); + WRMEM_B(AS_DATA, addr, 0); +} + +/****************************************** + comb addr(rd) + flags: -ZSP-- + ******************************************/ +void z8002_device::Z4C_ddN0_0000_addr() +{ + GET_DST(OP0,NIB2); + GET_ADDR(OP1); + addr = addr_add(addr, RW(dst)); + WRMEM_B(AS_DATA, addr, COMB(RDMEM_B(AS_DATA, addr))); +} + +/****************************************** + cpb addr(rd),imm8 + flags: CZSV-- + ******************************************/ +void z8002_device::Z4C_ddN0_0001_addr_imm8() +{ + GET_DST(OP0,NIB2); + GET_ADDR(OP1); + GET_IMM8(OP2); + addr = addr_add(addr, RW(dst)); + CPB(RDMEM_B(AS_DATA, addr), imm8); +} + +/****************************************** + negb addr(rd) + flags: CZSV-- + ******************************************/ +void z8002_device::Z4C_ddN0_0010_addr() +{ + GET_DST(OP0,NIB2); + GET_ADDR(OP1); + addr = addr_add(addr, RW(dst)); + WRMEM_B(AS_DATA, addr, NEGB(RDMEM_B(AS_DATA, addr))); +} + +/****************************************** + testb addr(rd) + flags: -ZSP-- + ******************************************/ +void z8002_device::Z4C_ddN0_0100_addr() +{ + GET_DST(OP0,NIB2); + GET_ADDR(OP1); + addr = addr_add(addr, RW(dst)); + TESTB(RDMEM_B(AS_DATA, addr)); +} + +/****************************************** + ldb addr(rd),imm8 + flags: ------ + ******************************************/ +void z8002_device::Z4C_ddN0_0101_addr_imm8() +{ + GET_DST(OP0,NIB2); + GET_ADDR(OP1); + GET_IMM8(OP2); + addr = addr_add(addr, RW(dst)); + WRMEM_B(AS_DATA, addr, imm8); +} + +/****************************************** + tsetb addr(rd) + flags: --S--- + ******************************************/ +void z8002_device::Z4C_ddN0_0110_addr() +{ + GET_DST(OP0,NIB2); + GET_ADDR(OP1); + addr = addr_add(addr, RW(dst)); + if (RDMEM_B(AS_DATA, addr) & S08) SET_S; else CLR_S; + WRMEM_B(AS_DATA, addr, 0xff); +} + +/****************************************** + clrb addr(rd) + flags: ------ + ******************************************/ +void z8002_device::Z4C_ddN0_1000_addr() +{ + GET_DST(OP0,NIB2); + GET_ADDR(OP1); + addr = addr_add(addr, RW(dst)); + WRMEM_B(AS_DATA, addr, 0); +} + +/****************************************** + com addr + flags: -ZS--- + ******************************************/ +void z8002_device::Z4D_0000_0000_addr() +{ + GET_ADDR(OP1); + WRMEM_W(AS_DATA, addr, COMW(RDMEM_W(AS_DATA, addr))); +} + +/****************************************** + cp addr,imm16 + flags: CZSV-- + ******************************************/ +void z8002_device::Z4D_0000_0001_addr_imm16() +{ + GET_ADDR(OP1); + GET_IMM16(OP2); + CPW(RDMEM_W(AS_DATA, addr), imm16); +} + +/****************************************** + neg addr + flags: CZSV-- + ******************************************/ +void z8002_device::Z4D_0000_0010_addr() +{ + GET_ADDR(OP1); + WRMEM_W(AS_DATA, addr, NEGW(RDMEM_W(AS_DATA, addr))); +} + +/****************************************** + test addr + flags: ------ + ******************************************/ +void z8002_device::Z4D_0000_0100_addr() +{ + GET_ADDR(OP1); + TESTW(RDMEM_W(AS_DATA, addr)); +} + +/****************************************** + ld addr,imm16 + flags: ------ + ******************************************/ +void z8002_device::Z4D_0000_0101_addr_imm16() +{ + GET_ADDR(OP1); + GET_IMM16(OP2); + WRMEM_W(AS_DATA, addr, imm16); +} + +/****************************************** + tset addr + flags: --S--- + ******************************************/ +void z8002_device::Z4D_0000_0110_addr() +{ + GET_ADDR(OP1); + if (RDMEM_W(AS_DATA, addr) & S16) SET_S; else CLR_S; + WRMEM_W(AS_DATA, addr, 0xffff); +} + +/****************************************** + clr addr + flags: ------ + ******************************************/ +void z8002_device::Z4D_0000_1000_addr() +{ + GET_ADDR(OP1); + WRMEM_W(AS_DATA, addr, 0); +} + +/****************************************** + com addr(rd) + flags: -ZS--- + ******************************************/ +void z8002_device::Z4D_ddN0_0000_addr() +{ + GET_DST(OP0,NIB2); + GET_ADDR(OP1); + addr = addr_add(addr, RW(dst)); + WRMEM_W(AS_DATA, addr, COMW(RDMEM_W(AS_DATA, addr))); +} + +/****************************************** + cp addr(rd),imm16 + flags: CZSV-- + ******************************************/ +void z8002_device::Z4D_ddN0_0001_addr_imm16() +{ + GET_DST(OP0,NIB2); + GET_ADDR(OP1); + GET_IMM16(OP2); + addr = addr_add(addr, RW(dst)); + CPW(RDMEM_W(AS_DATA, addr), imm16); +} + +/****************************************** + neg addr(rd) + flags: CZSV-- + ******************************************/ +void z8002_device::Z4D_ddN0_0010_addr() +{ + GET_DST(OP0,NIB2); + GET_ADDR(OP1); + addr = addr_add(addr, RW(dst)); + WRMEM_W(AS_DATA, addr, NEGW(RDMEM_W(AS_DATA, addr))); +} + +/****************************************** + test addr(rd) + flags: ------ + ******************************************/ +void z8002_device::Z4D_ddN0_0100_addr() +{ + GET_DST(OP0,NIB2); + GET_ADDR(OP1); + addr = addr_add(addr, RW(dst)); + TESTW(RDMEM_W(AS_DATA, addr)); +} + +/****************************************** + ld addr(rd),imm16 + flags: ------ + ******************************************/ +void z8002_device::Z4D_ddN0_0101_addr_imm16() +{ + GET_DST(OP0,NIB2); + GET_ADDR(OP1); + GET_IMM16(OP2); + addr = addr_add(addr, RW(dst)); + WRMEM_W(AS_DATA, addr, imm16); +} + +/****************************************** + tset addr(rd) + flags: --S--- + ******************************************/ +void z8002_device::Z4D_ddN0_0110_addr() +{ + GET_DST(OP0,NIB2); + GET_ADDR(OP1); + addr = addr_add(addr, RW(dst)); + if (RDMEM_W(AS_DATA, addr) & S16) SET_S; else CLR_S; + WRMEM_W(AS_DATA, addr, 0xffff); +} + +/****************************************** + clr addr(rd) + flags: ------ + ******************************************/ +void z8002_device::Z4D_ddN0_1000_addr() +{ + GET_DST(OP0,NIB2); + GET_ADDR(OP1); + addr = addr_add(addr, RW(dst)); + WRMEM_W(AS_DATA, addr, 0); +} + +/****************************************** + ldb addr(rd),rbs + flags: ------ + ******************************************/ +void z8002_device::Z4E_ddN0_ssN0_addr() +{ + GET_DST(OP0,NIB2); + GET_SRC(OP0,NIB3); + GET_ADDR(OP1); + addr = addr_add(addr, RW(dst)); + WRMEM_B(AS_DATA, addr, RB(src)); +} + +/****************************************** + cpl rrd,addr + flags: CZSV-- + ******************************************/ +void z8002_device::Z50_0000_dddd_addr() +{ + GET_DST(OP0,NIB3); + GET_ADDR(OP1); + CPL(RL(dst), RDMEM_L(AS_DATA, addr)); +} + +/****************************************** + cpl rrd,addr(rs) + flags: CZSV-- + ******************************************/ +void z8002_device::Z50_ssN0_dddd_addr() +{ + GET_DST(OP0,NIB3); + GET_SRC(OP0,NIB2); + GET_ADDR(OP1); + addr = addr_add(addr, RW(src)); + CPL(RL(dst), RDMEM_L(AS_DATA, addr)); +} + +/****************************************** + pushl @rd,addr + flags: ------ + ******************************************/ +void z8002_device::Z51_ddN0_0000_addr() +{ + GET_DST(OP0,NIB2); + GET_ADDR(OP1); + PUSHL(dst, RDMEM_L(AS_DATA, addr)); +} + +/****************************************** + pushl @rd,addr(rs) + flags: ------ + ******************************************/ +void z8002_device::Z51_ddN0_ssN0_addr() +{ + GET_SRC(OP0,NIB3); + GET_DST(OP0,NIB2); + GET_ADDR(OP1); + addr = addr_add(addr, RW(src)); + PUSHL(dst, RDMEM_L(AS_DATA, addr)); +} + +/****************************************** + subl rrd,addr + flags: CZSV-- + ******************************************/ +void z8002_device::Z52_0000_dddd_addr() +{ + GET_DST(OP0,NIB3); + GET_ADDR(OP1); + RL(dst) = SUBL(RL(dst), RDMEM_L(AS_DATA, addr)); +} + +/****************************************** + subl rrd,addr(rs) + flags: CZSV-- + ******************************************/ +void z8002_device::Z52_ssN0_dddd_addr() +{ + GET_DST(OP0,NIB3); + GET_SRC(OP0,NIB2); + GET_ADDR(OP1); + addr = addr_add(addr, RW(src)); + RL(dst) = SUBL(RL(dst), RDMEM_L(AS_DATA, addr)); +} + +/****************************************** + push @rd,addr + flags: ------ + ******************************************/ +void z8002_device::Z53_ddN0_0000_addr() +{ + GET_DST(OP0,NIB2); + GET_ADDR(OP1); + PUSHW(dst, RDMEM_W(AS_DATA, addr)); +} + +/****************************************** + push @rd,addr(rs) + flags: ------ + ******************************************/ +void z8002_device::Z53_ddN0_ssN0_addr() +{ + GET_DST(OP0,NIB2); + GET_SRC(OP0,NIB3); + GET_ADDR(OP1); + addr = addr_add(addr, RW(src)); + PUSHW(dst, RDMEM_W(AS_DATA, addr)); +} + +/****************************************** + ldl rrd,addr + flags: ------ + ******************************************/ +void z8002_device::Z54_0000_dddd_addr() +{ + GET_DST(OP0,NIB3); + GET_ADDR(OP1); + RL(dst) = RDMEM_L(AS_DATA, addr); +} + +/****************************************** + ldl rrd,addr(rs) + flags: ------ + ******************************************/ +void z8002_device::Z54_ssN0_dddd_addr() +{ + GET_DST(OP0,NIB3); + GET_SRC(OP0,NIB2); + GET_ADDR(OP1); + addr = addr_add(addr, RW(src)); + RL(dst) = RDMEM_L(AS_DATA, addr); +} + +/****************************************** + popl addr,@rs + flags: ------ + ******************************************/ +void z8002_device::Z55_ssN0_0000_addr() +{ + GET_SRC(OP0,NIB2); + GET_ADDR(OP1); + WRMEM_L(AS_DATA, addr, POPL(src)); +} + +/****************************************** + popl addr(rd),@rs + flags: ------ + ******************************************/ +void z8002_device::Z55_ssN0_ddN0_addr() +{ + GET_DST(OP0,NIB3); + GET_SRC(OP0,NIB2); + GET_ADDR(OP1); + addr = addr_add(addr, RW(dst)); + WRMEM_L(AS_DATA, addr, POPL(src)); +} + +/****************************************** + addl rrd,addr + flags: CZSV-- + ******************************************/ +void z8002_device::Z56_0000_dddd_addr() +{ + GET_DST(OP0,NIB3); + GET_ADDR(OP1); + RL(dst) = ADDL(RL(dst), RDMEM_L(AS_DATA, addr)); +} + +/****************************************** + addl rrd,addr(rs) + flags: CZSV-- + ******************************************/ +void z8002_device::Z56_ssN0_dddd_addr() +{ + GET_DST(OP0,NIB3); + GET_SRC(OP0,NIB2); + GET_ADDR(OP1); + addr = addr_add(addr, RW(src)); + RL(dst) = ADDL(RL(dst), RDMEM_L(AS_DATA, addr)); +} + +/****************************************** + pop addr,@rs + flags: ------ + ******************************************/ +void z8002_device::Z57_ssN0_0000_addr() +{ + GET_SRC(OP0,NIB2); + GET_ADDR(OP1); + WRMEM_W(AS_DATA, addr, POPW(src)); +} + +/****************************************** + pop addr(rd),@rs + flags: ------ + ******************************************/ +void z8002_device::Z57_ssN0_ddN0_addr() +{ + GET_DST(OP0,NIB3); + GET_SRC(OP0,NIB2); + GET_ADDR(OP1); + addr = addr_add(addr, RW(dst)); + WRMEM_W(AS_DATA, addr, POPW(src)); +} + +/****************************************** + multl rqd,addr + flags: CZSV-- + ******************************************/ +void z8002_device::Z58_0000_dddd_addr() +{ + GET_DST(OP0,NIB3); + GET_ADDR(OP1); + RQ(dst) = MULTL(RQ(dst), RDMEM_L(AS_DATA, addr)); +} + +/****************************************** + multl rqd,addr(rs) + flags: CZSV-- + ******************************************/ +void z8002_device::Z58_ssN0_dddd_addr() +{ + GET_DST(OP0,NIB3); + GET_SRC(OP0,NIB2); + GET_ADDR(OP1); + addr = addr_add(addr, RW(src)); + RQ(dst) = MULTL(RQ(dst), RDMEM_L(AS_DATA, addr)); +} + +/****************************************** + mult rrd,addr + flags: CZSV-- + ******************************************/ +void z8002_device::Z59_0000_dddd_addr() +{ + GET_DST(OP0,NIB3); + GET_ADDR(OP1); + RL(dst) = MULTW(RL(dst), RDMEM_W(AS_DATA, addr)); +} + +/****************************************** + mult rrd,addr(rs) + flags: CZSV-- + ******************************************/ +void z8002_device::Z59_ssN0_dddd_addr() +{ + GET_DST(OP0,NIB3); + GET_SRC(OP0,NIB2); + GET_ADDR(OP1); + addr = addr_add(addr, RW(src)); + RL(dst) = MULTW(RL(dst), RDMEM_W(AS_DATA, addr)); +} + +/****************************************** + divl rqd,addr + flags: CZSV-- + ******************************************/ +void z8002_device::Z5A_0000_dddd_addr() +{ + GET_DST(OP0,NIB3); + GET_ADDR(OP1); + RQ(dst) = DIVL(RQ(dst), RDMEM_L(AS_DATA, addr)); +} + +/****************************************** + divl rqd,addr(rs) + flags: CZSV-- + ******************************************/ +void z8002_device::Z5A_ssN0_dddd_addr() +{ + GET_DST(OP0,NIB3); + GET_SRC(OP0,NIB2); + GET_ADDR(OP1); + addr = addr_add(addr, RW(src)); + RQ(dst) = DIVL(RQ(dst), RDMEM_L(AS_DATA, addr)); +} + +/****************************************** + div rrd,addr + flags: CZSV-- + ******************************************/ +void z8002_device::Z5B_0000_dddd_addr() +{ + GET_DST(OP0,NIB3); + GET_ADDR(OP1); + RL(dst) = DIVW(RL(dst), RDMEM_W(AS_DATA, addr)); +} + +/****************************************** + div rrd,addr(rs) + flags: CZSV-- + ******************************************/ +void z8002_device::Z5B_ssN0_dddd_addr() +{ + GET_DST(OP0,NIB3); + GET_SRC(OP0,NIB2); + GET_ADDR(OP1); + addr = addr_add(addr, RW(src)); + RL(dst) = DIVW(RL(dst), RDMEM_W(AS_DATA, addr)); +} + +/****************************************** + ldm rd,addr,n + flags: ------ + ******************************************/ +void z8002_device::Z5C_0000_0001_0000_dddd_0000_nmin1_addr() +{ + GET_DST(OP1,NIB1); + GET_CNT(OP1,NIB3); + GET_ADDR(OP2); + while (cnt-- >= 0) { + RW(dst) = RDMEM_W(AS_DATA, addr); + dst = (dst+1) & 15; + addr = addr_add (addr, 2); + } +} + +/****************************************** + testl addr + flags: -ZS--- + ******************************************/ +void z8002_device::Z5C_0000_1000_addr() +{ + GET_ADDR(OP1); + TESTL(RDMEM_L(AS_DATA, addr)); +} + +/****************************************** + ldm addr,rs,n + flags: ------ + ******************************************/ +void z8002_device::Z5C_0000_1001_0000_ssss_0000_nmin1_addr() +{ + GET_SRC(OP1,NIB1); + GET_CNT(OP1,NIB3); + GET_ADDR(OP2); + while (cnt-- >= 0) { + WRMEM_W(AS_DATA, addr, RW(src)); + src = (src+1) & 15; + addr = addr_add (addr, 2); + } +} + +/****************************************** + testl addr(rd) + flags: -ZS--- + ******************************************/ +void z8002_device::Z5C_ddN0_1000_addr() +{ + GET_DST(OP0,NIB2); + GET_ADDR(OP1); + addr = addr_add(addr, RW(dst)); + TESTL(RDMEM_L(AS_DATA, addr)); +} + +/****************************************** + ldm addr(rd),rs,n + flags: ------ + ******************************************/ +void z8002_device::Z5C_ddN0_1001_0000_ssN0_0000_nmin1_addr() +{ + GET_DST(OP0,NIB2); + GET_SRC(OP1,NIB1); + GET_CNT(OP1,NIB3); + GET_ADDR(OP2); + addr = addr_add(addr, RW(dst)); + while (cnt-- >= 0) { + WRMEM_W(AS_DATA, addr, RW(src)); + src = (src+1) & 15; + addr = addr_add(addr, 2); + } +} + +/****************************************** + ldm rd,addr(rs),n + flags: ------ + ******************************************/ +void z8002_device::Z5C_ssN0_0001_0000_dddd_0000_nmin1_addr() +{ + GET_SRC(OP0,NIB2); + GET_DST(OP1,NIB1); + GET_CNT(OP1,NIB3); + GET_ADDR(OP2); + addr = addr_add(addr, RW(src)); + while (cnt-- >= 0) { + RW(dst) = RDMEM_W(AS_DATA, addr); + dst = (dst+1) & 15; + addr = addr_add(addr, 2); + } +} + +/****************************************** + ldl addr,rrs + flags: ------ + ******************************************/ +void z8002_device::Z5D_0000_ssss_addr() +{ + GET_SRC(OP0,NIB3); + GET_ADDR(OP1); + WRMEM_L(AS_DATA, addr, RL(src)); +} + +/****************************************** + ldl addr(rd),rrs + flags: ------ + ******************************************/ +void z8002_device::Z5D_ddN0_ssss_addr() +{ + GET_SRC(OP0,NIB3); + GET_DST(OP0,NIB2); + GET_ADDR(OP1); + addr = addr_add(addr, RW(dst)); + WRMEM_L(AS_DATA, addr, RL(src)); +} + +/****************************************** + jp cc,addr + flags: ------ + ******************************************/ +void z8002_device::Z5E_0000_cccc_addr() +{ + GET_CCC(OP0,NIB3); + GET_ADDR(OP1); + switch (cc) { + case 0: if (CC0) set_pc(addr); break; + case 1: if (CC1) set_pc(addr); break; + case 2: if (CC2) set_pc(addr); break; + case 3: if (CC3) set_pc(addr); break; + case 4: if (CC4) set_pc(addr); break; + case 5: if (CC5) set_pc(addr); break; + case 6: if (CC6) set_pc(addr); break; + case 7: if (CC7) set_pc(addr); break; + case 8: if (CC8) set_pc(addr); break; + case 9: if (CC9) set_pc(addr); break; + case 10: if (CCA) set_pc(addr); break; + case 11: if (CCB) set_pc(addr); break; + case 12: if (CCC) set_pc(addr); break; + case 13: if (CCD) set_pc(addr); break; + case 14: if (CCE) set_pc(addr); break; + case 15: if (CCF) set_pc(addr); break; + } +} + +/****************************************** + jp cc,addr(rd) + flags: ------ + ******************************************/ +void z8002_device::Z5E_ddN0_cccc_addr() +{ + GET_CCC(OP0,NIB3); + GET_DST(OP0,NIB2); + GET_ADDR(OP1); + addr = addr_add(addr, RW(dst)); + switch (cc) { + case 0: if (CC0) set_pc(addr); break; + case 1: if (CC1) set_pc(addr); break; + case 2: if (CC2) set_pc(addr); break; + case 3: if (CC3) set_pc(addr); break; + case 4: if (CC4) set_pc(addr); break; + case 5: if (CC5) set_pc(addr); break; + case 6: if (CC6) set_pc(addr); break; + case 7: if (CC7) set_pc(addr); break; + case 8: if (CC8) set_pc(addr); break; + case 9: if (CC9) set_pc(addr); break; + case 10: if (CCA) set_pc(addr); break; + case 11: if (CCB) set_pc(addr); break; + case 12: if (CCC) set_pc(addr); break; + case 13: if (CCD) set_pc(addr); break; + case 14: if (CCE) set_pc(addr); break; + case 15: if (CCF) set_pc(addr); break; + } +} + +/****************************************** + call addr + flags: ------ + ******************************************/ +void z8002_device::Z5F_0000_0000_addr() +{ + GET_ADDR(OP1); + if (segmented_mode()) + PUSHL(SP, make_segmented_addr(m_pc)); + else + PUSHW(SP, m_pc); + set_pc(addr); +} + +/****************************************** + call addr(rd) + flags: ------ + ******************************************/ +void z8002_device::Z5F_ddN0_0000_addr() +{ + GET_DST(OP0,NIB2); + GET_ADDR(OP1); + if (segmented_mode()) + PUSHL(SP, make_segmented_addr(m_pc)); + else + PUSHW(SP, m_pc); + addr = addr_add(addr, RW(dst)); + set_pc(addr); +} + +/****************************************** + ldb rbd,addr + flags: ------ + ******************************************/ +void z8002_device::Z60_0000_dddd_addr() +{ + GET_DST(OP0,NIB3); + GET_ADDR(OP1); + RB(dst) = RDMEM_B(AS_DATA, addr); +} + +/****************************************** + ldb rbd,addr(rs) + flags: ------ + ******************************************/ +void z8002_device::Z60_ssN0_dddd_addr() +{ + GET_DST(OP0,NIB3); + GET_SRC(OP0,NIB2); + GET_ADDR(OP1); + addr = addr_add(addr, RW(src)); + RB(dst) = RDMEM_B(AS_DATA, addr); +} + +/****************************************** + ld rd,addr + flags: ------ + ******************************************/ +void z8002_device::Z61_0000_dddd_addr() +{ + GET_DST(OP0,NIB3); + GET_ADDR(OP1); + RW(dst) = RDMEM_W(AS_DATA, addr); +} + +/****************************************** + ld rd,addr(rs) + flags: ------ + ******************************************/ +void z8002_device::Z61_ssN0_dddd_addr() +{ + GET_DST(OP0,NIB3); + GET_SRC(OP0,NIB2); + GET_ADDR(OP1); + addr = addr_add(addr, RW(src)); + RW(dst) = RDMEM_W(AS_DATA, addr); +} + +/****************************************** + resb addr,imm4 + flags: ------ + ******************************************/ +void z8002_device::Z62_0000_imm4_addr() +{ + GET_BIT(OP0); + GET_ADDR(OP1); + WRMEM_B(AS_DATA, addr, RDMEM_B(AS_DATA, addr) & ~bit); +} + +/****************************************** + resb addr(rd),imm4 + flags: ------ + ******************************************/ +void z8002_device::Z62_ddN0_imm4_addr() +{ + GET_BIT(OP0); + GET_DST(OP0,NIB2); + GET_ADDR(OP1); + addr = addr_add(addr, RW(dst)); + WRMEM_B(AS_DATA, addr, RDMEM_B(AS_DATA, addr) & ~bit); +} + +/****************************************** + res addr,imm4 + flags: ------ + ******************************************/ +void z8002_device::Z63_0000_imm4_addr() +{ + GET_BIT(OP0); + GET_ADDR(OP1); + WRMEM_W(AS_DATA, addr, RDMEM_W(AS_DATA, addr) & ~bit); +} + +/****************************************** + res addr(rd),imm4 + flags: ------ + ******************************************/ +void z8002_device::Z63_ddN0_imm4_addr() +{ + GET_BIT(OP0); + GET_DST(OP0,NIB2); + GET_ADDR(OP1); + addr = addr_add(addr, RW(dst)); + WRMEM_W(AS_DATA, addr, RDMEM_W(AS_DATA, addr) & ~bit); +} + +/****************************************** + setb addr,imm4 + flags: ------ + ******************************************/ +void z8002_device::Z64_0000_imm4_addr() +{ + GET_BIT(OP0); + GET_ADDR(OP1); + WRMEM_B(AS_DATA, addr, RDMEM_B(AS_DATA, addr) | bit); +} + +/****************************************** + setb addr(rd),imm4 + flags: ------ + ******************************************/ +void z8002_device::Z64_ddN0_imm4_addr() +{ + GET_BIT(OP0); + GET_DST(OP0,NIB2); + GET_ADDR(OP1); + addr = addr_add(addr, RW(dst)); + WRMEM_B(AS_DATA, addr, RDMEM_B(AS_DATA, addr) | bit); +} + +/****************************************** + set addr,imm4 + flags: ------ + ******************************************/ +void z8002_device::Z65_0000_imm4_addr() +{ + GET_BIT(OP0); + GET_ADDR(OP1); + WRMEM_W(AS_DATA, addr, RDMEM_W(AS_DATA, addr) | bit); +} + +/****************************************** + set addr(rd),imm4 + flags: ------ + ******************************************/ +void z8002_device::Z65_ddN0_imm4_addr() +{ + GET_BIT(OP0); + GET_DST(OP0,NIB2); + GET_ADDR(OP1); + addr = addr_add(addr, RW(dst)); + WRMEM_W(AS_DATA, addr, RDMEM_W(AS_DATA, addr) | bit); +} + +/****************************************** + bitb addr,imm4 + flags: -Z---- + ******************************************/ +void z8002_device::Z66_0000_imm4_addr() +{ + GET_BIT(OP0); + GET_ADDR(OP1); + if (RDMEM_B(AS_DATA, addr) & bit) CLR_Z; else SET_Z; +} + +/****************************************** + bitb addr(rd),imm4 + flags: -Z---- + ******************************************/ +void z8002_device::Z66_ddN0_imm4_addr() +{ + GET_BIT(OP0); + GET_DST(OP0,NIB2); + GET_ADDR(OP1); + addr = addr_add(addr, RW(dst)); + if (RDMEM_B(AS_DATA, addr) & bit) CLR_Z; else SET_Z; +} + +/****************************************** + bit addr,imm4 + flags: -Z---- + ******************************************/ +void z8002_device::Z67_0000_imm4_addr() +{ + GET_BIT(OP0); + GET_ADDR(OP1); + if (RDMEM_W(AS_DATA, addr) & bit) CLR_Z; else SET_Z; +} + +/****************************************** + bit addr(rd),imm4 + flags: -Z---- + ******************************************/ +void z8002_device::Z67_ddN0_imm4_addr() +{ + GET_BIT(OP0); + GET_DST(OP0,NIB2); + GET_ADDR(OP1); + addr = addr_add(addr, RW(dst)); + if (RDMEM_W(AS_DATA, addr) & bit) CLR_Z; else SET_Z; +} + +/****************************************** + incb addr,imm4m1 + flags: -ZSV-- + ******************************************/ +void z8002_device::Z68_0000_imm4m1_addr() +{ + GET_I4M1(OP0,NIB3); + GET_ADDR(OP1); + WRMEM_B(AS_DATA, addr, INCB(RDMEM_B(AS_DATA, addr), i4p1)); +} + +/****************************************** + incb addr(rd),imm4m1 + flags: -ZSV-- + ******************************************/ +void z8002_device::Z68_ddN0_imm4m1_addr() +{ + GET_I4M1(OP0,NIB3); + GET_DST(OP0,NIB2); + GET_ADDR(OP1); + addr = addr_add(addr, RW(dst)); + WRMEM_B(AS_DATA, addr, INCB(RDMEM_B(AS_DATA, addr), i4p1)); +} + +/****************************************** + inc addr,imm4m1 + flags: -ZSV-- + ******************************************/ +void z8002_device::Z69_0000_imm4m1_addr() +{ + GET_I4M1(OP0,NIB3); + GET_ADDR(OP1); + WRMEM_W(AS_DATA, addr, INCW(RDMEM_W(AS_DATA, addr), i4p1)); +} + +/****************************************** + inc addr(rd),imm4m1 + flags: -ZSV-- + ******************************************/ +void z8002_device::Z69_ddN0_imm4m1_addr() +{ + GET_I4M1(OP0,NIB3); + GET_DST(OP0,NIB2); + GET_ADDR(OP1); + addr = addr_add(addr, RW(dst)); + WRMEM_W(AS_DATA, addr, INCW(RDMEM_W(AS_DATA, addr), i4p1)); +} + +/****************************************** + decb addr,imm4m1 + flags: -ZSV-- + ******************************************/ +void z8002_device::Z6A_0000_imm4m1_addr() +{ + GET_I4M1(OP0,NIB3); + GET_ADDR(OP1); + WRMEM_B(AS_DATA, addr, DECB(RDMEM_B(AS_DATA, addr), i4p1)); +} + +/****************************************** + decb addr(rd),imm4m1 + flags: -ZSV-- + ******************************************/ +void z8002_device::Z6A_ddN0_imm4m1_addr() +{ + GET_I4M1(OP0,NIB3); + GET_DST(OP0,NIB2); + GET_ADDR(OP1); + addr = addr_add(addr, RW(dst)); + WRMEM_B(AS_DATA, addr, DECB(RDMEM_B(AS_DATA, addr), i4p1)); +} + +/****************************************** + dec addr,imm4m1 + flags: -ZSV-- + ******************************************/ +void z8002_device::Z6B_0000_imm4m1_addr() +{ + GET_I4M1(OP0,NIB3); + GET_ADDR(OP1); + WRMEM_W(AS_DATA, addr, DECW(RDMEM_W(AS_DATA, addr), i4p1)); +} + +/****************************************** + dec addr(rd),imm4m1 + flags: -ZSV-- + ******************************************/ +void z8002_device::Z6B_ddN0_imm4m1_addr() +{ + GET_I4M1(OP0,NIB3); + GET_DST(OP0,NIB2); + GET_ADDR(OP1); + addr = addr_add(addr, RW(dst)); + WRMEM_W(AS_DATA, addr, DECW(RDMEM_W(AS_DATA, addr), i4p1)); +} + +/****************************************** + exb rbd,addr + flags: ------ + ******************************************/ +void z8002_device::Z6C_0000_dddd_addr() +{ + GET_DST(OP0,NIB3); + GET_ADDR(OP1); + UINT8 tmp = RDMEM_B(AS_DATA, addr); + WRMEM_B(AS_DATA, addr, RB(dst)); + RB(dst) = tmp; +} + +/****************************************** + exb rbd,addr(rs) + flags: ------ + ******************************************/ +void z8002_device::Z6C_ssN0_dddd_addr() +{ + GET_DST(OP0,NIB3); + GET_SRC(OP0,NIB2); + GET_ADDR(OP1); + UINT8 tmp; + addr = addr_add(addr, RW(src)); + tmp = RDMEM_B(AS_DATA, addr); + WRMEM_B(AS_DATA, addr, RB(dst)); + RB(dst) = tmp; +} + +/****************************************** + ex rd,addr + flags: ------ + ******************************************/ +void z8002_device::Z6D_0000_dddd_addr() +{ + GET_DST(OP0,NIB3); + GET_ADDR(OP1); + UINT16 tmp = RDMEM_W(AS_DATA, addr); + WRMEM_W(AS_DATA, addr, RW(dst)); + RW(dst) = tmp; +} + +/****************************************** + ex rd,addr(rs) + flags: ------ + ******************************************/ +void z8002_device::Z6D_ssN0_dddd_addr() +{ + GET_DST(OP0,NIB3); + GET_SRC(OP0,NIB2); + GET_ADDR(OP1); + UINT16 tmp; + addr = addr_add(addr, RW(src)); + tmp = RDMEM_W(AS_DATA, addr); + WRMEM_W(AS_DATA, addr, RW(dst)); + RW(dst) = tmp; +} + +/****************************************** + ldb addr,rbs + flags: ------ + ******************************************/ +void z8002_device::Z6E_0000_ssss_addr() +{ + GET_SRC(OP0,NIB3); + GET_ADDR(OP1); + WRMEM_B(AS_DATA, addr, RB(src)); +} + +/****************************************** + ldb addr(rd),rbs + flags: ------ + ******************************************/ +void z8002_device::Z6E_ddN0_ssss_addr() +{ + GET_SRC(OP0,NIB3); + GET_DST(OP0,NIB2); + GET_ADDR(OP1); + addr = addr_add(addr, RW(dst)); + WRMEM_B(AS_DATA, addr, RB(src)); +} + +/****************************************** + ld addr,rs + flags: ------ + ******************************************/ +void z8002_device::Z6F_0000_ssss_addr() +{ + GET_SRC(OP0,NIB3); + GET_ADDR(OP1); + WRMEM_W(AS_DATA, addr, RW(src)); +} + +/****************************************** + ld addr(rd),rs + flags: ------ + ******************************************/ +void z8002_device::Z6F_ddN0_ssss_addr() +{ + GET_SRC(OP0,NIB3); + GET_DST(OP0,NIB2); + GET_ADDR(OP1); + addr = addr_add(addr, RW(dst)); + WRMEM_W(AS_DATA, addr, RW(src)); +} + +/****************************************** + ldb rbd,rs(rx) + flags: ------ + ******************************************/ +void z8002_device::Z70_ssN0_dddd_0000_xxxx_0000_0000() +{ + GET_DST(OP0,NIB3); + GET_SRC(OP0,NIB2); + GET_IDX(OP1,NIB1); + RB(dst) = RDMEM_B(AS_DATA, addr_add(addr_from_reg(src), RW(idx))); +} + +/****************************************** + ld rd,rs(rx) + flags: ------ + ******************************************/ +void z8002_device::Z71_ssN0_dddd_0000_xxxx_0000_0000() +{ + GET_DST(OP0,NIB3); + GET_SRC(OP0,NIB2); + GET_IDX(OP1,NIB1); + RW(dst) = RDMEM_W(AS_DATA, addr_add(addr_from_reg(src), RW(idx))); +} + +/****************************************** + ldb rd(rx),rbs + flags: ------ + ******************************************/ +void z8002_device::Z72_ddN0_ssss_0000_xxxx_0000_0000() +{ + GET_SRC(OP0,NIB3); + GET_DST(OP0,NIB2); + GET_IDX(OP1,NIB1); + WRMEM_B(AS_DATA, addr_add(addr_from_reg(dst), RW(idx)), RB(src)); +} + +/****************************************** + ld rd(rx),rs + flags: ------ + ******************************************/ +void z8002_device::Z73_ddN0_ssss_0000_xxxx_0000_0000() +{ + GET_SRC(OP0,NIB3); + GET_DST(OP0,NIB2); + GET_IDX(OP1,NIB1); + WRMEM_W(AS_DATA, addr_add(addr_from_reg(dst), RW(idx)), RW(src)); +} + +/****************************************** + lda prd,rs(rx) + flags: ------ + ******************************************/ +void z8002_device::Z74_ssN0_dddd_0000_xxxx_0000_0000() +{ + GET_DST(OP0,NIB3); + GET_SRC(OP0,NIB2); + GET_IDX(OP1,NIB1); + if (segmented_mode()) { + RL(dst) = RL(src); + } + else { + RW(dst) = RW(src); + } + add_to_addr_reg(dst, RW(idx)); +} + +/****************************************** + ldl rrd,rs(rx) + flags: ------ + ******************************************/ +void z8002_device::Z75_ssN0_dddd_0000_xxxx_0000_0000() +{ + GET_DST(OP0,NIB3); + GET_SRC(OP0,NIB2); + GET_IDX(OP1,NIB1); + RL(dst) = RDMEM_L(AS_DATA, addr_add(addr_from_reg(src), RW(idx))); +} + +/****************************************** + lda prd,addr + flags: ------ + ******************************************/ +void z8002_device::Z76_0000_dddd_addr() +{ + GET_DST(OP0,NIB3); + GET_ADDR_RAW(OP1); + if (segmented_mode()) { + RL(dst) = addr; + } + else { + RW(dst) = addr; + } +} + +/****************************************** + lda prd,addr(rs) + flags: ------ + ******************************************/ +void z8002_device::Z76_ssN0_dddd_addr() +{//@@@ + GET_DST(OP0,NIB3); + GET_SRC(OP0,NIB2); + GET_ADDR_RAW(OP1); + UINT16 temp = RW(src); // store src in case dst == src + if (segmented_mode()) { + RL(dst) = addr; + } + else { + RW(dst) = addr; + } + add_to_addr_reg(dst, temp); +} + +/****************************************** + ldl rd(rx),rrs + flags: ------ + ******************************************/ +void z8002_device::Z77_ddN0_ssss_0000_xxxx_0000_0000() +{ + GET_SRC(OP0,NIB3); + GET_DST(OP0,NIB2); + GET_IDX(OP1,NIB1); + WRMEM_L(AS_DATA, addr_add(addr_from_reg(dst), RW(idx)), RL(src)); +} + +/****************************************** + rsvd78 + flags: ------ + ******************************************/ +void z8002_device::Z78_imm8() +{ + GET_IMM8(0); + LOG(("Z8K '%s' %04x: rsvd78 $%02x\n", tag(), m_pc, imm8)); + if (m_fcw & F_EPU) { + /* Z8001 EPU code goes here */ + (void)imm8; + } +} + +/****************************************** + ldps addr + flags: CZSVDH + ******************************************/ +void z8002_device::Z79_0000_0000_addr() +{ + CHECK_PRIVILEGED_INSTR(); + GET_ADDR(OP1); + UINT16 fcw; + if (segmented_mode()) { + fcw = RDMEM_W(AS_DATA, addr + 2); + set_pc(segmented_addr(RDMEM_L(AS_DATA, addr + 4))); + } + else { + fcw = RDMEM_W(AS_DATA, addr); + set_pc(RDMEM_W(AS_DATA, (UINT16)(addr + 2))); + } + CHANGE_FCW(fcw); /* check for user/system mode change */ +} + +/****************************************** + ldps addr(rs) + flags: CZSVDH + ******************************************/ +void z8002_device::Z79_ssN0_0000_addr() +{ + CHECK_PRIVILEGED_INSTR(); + GET_SRC(OP0,NIB2); + GET_ADDR(OP1); + UINT16 fcw; + addr = addr_add(addr, RW(src)); + if (segmented_mode()) { + fcw = RDMEM_W(AS_DATA, addr + 2); + set_pc(segmented_addr(RDMEM_L(AS_DATA, addr + 4))); + } + else { + fcw = RDMEM_W(AS_DATA, addr); + m_pc = RDMEM_W(AS_DATA, (UINT16)(addr + 2)); + } + if ((fcw ^ m_fcw) & F_SEG) printf("ldps 3 (0x%05x): changing from %ssegmented mode to %ssegmented mode\n", m_pc, (fcw & F_SEG) ? "non-" : "", (fcw & F_SEG) ? "" : "non-"); + CHANGE_FCW(fcw); /* check for user/system mode change */ +} + +/****************************************** + halt + flags: ------ + ******************************************/ +void z8002_device::Z7A_0000_0000() +{ + CHECK_PRIVILEGED_INSTR(); + m_irq_req |= Z8000_HALT; + if (m_icount > 0) m_icount = 0; +} + +/****************************************** + iret + flags: CZSVDH + ******************************************/ +void z8002_device::Z7B_0000_0000() +{ + UINT16 tag, fcw; + CHECK_PRIVILEGED_INSTR(); + tag = POPW(SP); /* get type tag */ + fcw = POPW(SP); /* get m_fcw */ + if (segmented_mode()) + set_pc(segmented_addr(POPL(SP))); + else + m_pc = POPW(SP); /* get m_pc */ + CHANGE_FCW(fcw); /* check for user/system mode change */ + LOG(("Z8K '%s' IRET tag $%04x, fcw $%04x, pc $%04x\n", this->tag(), tag, fcw, m_pc)); +} + +/****************************************** + mset + flags: ------ + ******************************************/ +void z8002_device::Z7B_0000_1000() +{ + CHECK_PRIVILEGED_INSTR(); + /* set mu-0 line */ +} + +/****************************************** + mres + flags: ------ + ******************************************/ +void z8002_device::Z7B_0000_1001() +{ + CHECK_PRIVILEGED_INSTR(); + /* reset mu-0 line */ +} + +/****************************************** + mbit + flags: CZS--- + ******************************************/ +void z8002_device::Z7B_0000_1010() +{ + CHECK_PRIVILEGED_INSTR(); + /* test mu-I line */ +} + +/****************************************** + mreq rd + flags: -ZS--- + ******************************************/ +void z8002_device::Z7B_dddd_1101() +{ + CHECK_PRIVILEGED_INSTR(); + /* test mu-I line, invert cascade to mu-0 */ + if (m_mi) + { + CLR_Z; + CLR_S; + m_mo_out(CLEAR_LINE); + return; + } + SET_Z; + m_mo_out(ASSERT_LINE); + if (m_mi) + { + SET_S; + } + else + { + CLR_S; + m_mo_out(CLEAR_LINE); + } +} + +/****************************************** + di i2 + flags: ------ + ******************************************/ +void z8002_device::Z7C_0000_00ii() +{ + CHECK_PRIVILEGED_INSTR(); + GET_IMM2(OP0,NIB3); + UINT16 fcw = m_fcw; + fcw &= (imm2 << 11) | 0xe7ff; + CHANGE_FCW(fcw); +} + +/****************************************** + ei i2 + flags: ------ + ******************************************/ +void z8002_device::Z7C_0000_01ii() +{ + CHECK_PRIVILEGED_INSTR(); + GET_IMM2(OP0,NIB3); + UINT16 fcw = m_fcw; + fcw |= ((~imm2) << 11) & 0x1800; + CHANGE_FCW(fcw); +} + +/****************************************** + ldctl rd,ctrl + flags: ------ + ******************************************/ +void z8002_device::Z7D_dddd_0ccc() +{//@@@ + CHECK_PRIVILEGED_INSTR(); + GET_IMM3(OP0,NIB3); + GET_DST(OP0,NIB2); + switch (imm3) { + case 2: + RW(dst) = m_fcw; + break; + case 3: + RW(dst) = m_refresh; + break; + case 4: + RW(dst) = m_psapseg; + break; + case 5: + RW(dst) = m_psapoff; + break; + case 6: + RW(dst) = m_nspseg; + break; + case 7: + RW(dst) = m_nspoff; + break; + default: + LOG(("Z8K '%s' LDCTL R%d,%d\n", tag(), dst, imm3)); + } +} + +/****************************************** + ldctl ctrl,rs + flags: ------ + ******************************************/ +void z8002_device::Z7D_ssss_1ccc() +{//@@@ + CHECK_PRIVILEGED_INSTR(); + GET_IMM3(OP0,NIB3); + GET_SRC(OP0,NIB2); + switch (imm3) { + case 2: + { + UINT16 fcw; + fcw = RW(src); + CHANGE_FCW(fcw); /* check for user/system mode change */ + } + break; + case 3: + m_refresh = RW(src); + break; + case 4: + m_psapseg = RW(src); + break; + case 5: + m_psapoff = RW(src); + break; + case 6: + m_nspseg = RW(src); + break; + case 7: + m_nspoff = RW(src); + break; + default: + LOG(("Z8K '%s' LDCTL %d,R%d\n", tag(), imm3, src)); + } +} + +/****************************************** + rsvd7e + flags: ------ + ******************************************/ +void z8002_device::Z7E_imm8() +{ + GET_IMM8(0); + LOG(("Z8K '%s' %04x: rsvd7e $%02x\n", tag(), m_pc, imm8)); + if (m_fcw & F_EPU) { + /* Z8001 EPU code goes here */ + (void)imm8; + } +} + +/****************************************** + sc imm8 + flags: CZSVDH + ******************************************/ +void z8002_device::Z7F_imm8() +{ + GET_IMM8(0); + /* execute system call via IRQ */ + m_irq_req = Z8000_SYSCALL | imm8; + +} + +/****************************************** + addb rbd,rbs + flags: CZSVDH + ******************************************/ +void z8002_device::Z80_ssss_dddd() +{ + GET_DST(OP0,NIB3); + GET_SRC(OP0,NIB2); + RB(dst) = ADDB(RB(dst), RB(src)); +} + +/****************************************** + add rd,rs + flags: CZSV-- + ******************************************/ +void z8002_device::Z81_ssss_dddd() +{ + GET_DST(OP0,NIB3); + GET_SRC(OP0,NIB2); + RW(dst) = ADDW(RW(dst), RW(src)); +} + +/****************************************** + subb rbd,rbs + flags: CZSVDH + ******************************************/ +void z8002_device::Z82_ssss_dddd() +{ + GET_DST(OP0,NIB3); + GET_SRC(OP0,NIB2); + RB(dst) = SUBB(RB(dst), RB(src)); +} + +/****************************************** + sub rd,rs + flags: CZSV-- + ******************************************/ +void z8002_device::Z83_ssss_dddd() +{ + GET_DST(OP0,NIB3); + GET_SRC(OP0,NIB2); + RW(dst) = SUBW(RW(dst), RW(src)); +} + +/****************************************** + orb rbd,rbs + flags: CZSP-- + ******************************************/ +void z8002_device::Z84_ssss_dddd() +{ + GET_DST(OP0,NIB3); + GET_SRC(OP0,NIB2); + RB(dst) = ORB(RB(dst), RB(src)); +} + +/****************************************** + or rd,rs + flags: CZS--- + ******************************************/ +void z8002_device::Z85_ssss_dddd() +{ + GET_DST(OP0,NIB3); + GET_SRC(OP0,NIB2); + RW(dst) = ORW(RW(dst), RW(src)); +} + +/****************************************** + andb rbd,rbs + flags: -ZSP-- + ******************************************/ +void z8002_device::Z86_ssss_dddd() +{ + GET_DST(OP0,NIB3); + GET_SRC(OP0,NIB2); + RB(dst) = ANDB(RB(dst), RB(src)); +} + +/****************************************** + and rd,rs + flags: -ZS--- + ******************************************/ +void z8002_device::Z87_ssss_dddd() +{ + GET_DST(OP0,NIB3); + GET_SRC(OP0,NIB2); + RW(dst) = ANDW(RW(dst), RW(src)); +} + +/****************************************** + xorb rbd,rbs + flags: -ZSP-- + ******************************************/ +void z8002_device::Z88_ssss_dddd() +{ + GET_DST(OP0,NIB3); + GET_SRC(OP0,NIB2); + RB(dst) = XORB(RB(dst), RB(src)); +} + +/****************************************** + xor rd,rs + flags: -ZS--- + ******************************************/ +void z8002_device::Z89_ssss_dddd() +{ + GET_DST(OP0,NIB3); + GET_SRC(OP0,NIB2); + RW(dst) = XORW(RW(dst), RW(src)); +} + +/****************************************** + cpb rbd,rbs + flags: CZSV-- + ******************************************/ +void z8002_device::Z8A_ssss_dddd() +{ + GET_DST(OP0,NIB3); + GET_SRC(OP0,NIB2); + CPB(RB(dst), RB(src)); +} + +/****************************************** + cp rd,rs + flags: CZSV-- + ******************************************/ +void z8002_device::Z8B_ssss_dddd() +{ + GET_DST(OP0,NIB3); + GET_SRC(OP0,NIB2); + CPW(RW(dst), RW(src)); +} + +/****************************************** + comb rbd + flags: -ZSP-- + ******************************************/ +void z8002_device::Z8C_dddd_0000() +{ + GET_DST(OP0,NIB2); + RB(dst) = COMB(RB(dst)); +} + +/****************************************** + negb rbd + flags: CZSV-- + ******************************************/ +void z8002_device::Z8C_dddd_0010() +{ + GET_DST(OP0,NIB2); + RB(dst) = NEGB(RB(dst)); +} + +/****************************************** + testb rbd + flags: -ZSP-- + ******************************************/ +void z8002_device::Z8C_dddd_0100() +{ + GET_DST(OP0,NIB2); + TESTB(RB(dst)); +} + +/****************************************** + tsetb rbd + flags: --S--- + ******************************************/ +void z8002_device::Z8C_dddd_0110() +{ + GET_DST(OP0,NIB2); + if (RB(dst) & S08) SET_S; else CLR_S; + RB(dst) = 0xff; +} + +/****************************************** + ldctlb rbd,flags + flags: CZSVDH + ******************************************/ +void z8002_device::Z8C_dddd_0001() +{ + GET_DST(OP0,NIB2); + RB(dst) = m_fcw & 0xfc; +} + +/****************************************** + clrb rbd + flags: ------ + ******************************************/ +void z8002_device::Z8C_dddd_1000() +{ + GET_DST(OP0,NIB2); + RB(dst) = 0; +} + +/****************************************** + ldctlb flags,rbd + flags: ------ + ******************************************/ +void z8002_device::Z8C_dddd_1001() +{ + GET_DST(OP0,NIB2); + m_fcw &= ~0x00fc; + m_fcw |= (RB(dst) & 0xfc); +} + +/****************************************** + nop + flags: ------ + ******************************************/ +void z8002_device::Z8D_0000_0111() +{ + /* nothing */ +} + +/****************************************** + com rd + flags: -ZS--- + ******************************************/ +void z8002_device::Z8D_dddd_0000() +{ + GET_DST(OP0,NIB2); + RW(dst) = COMW(RW(dst)); +} + +/****************************************** + neg rd + flags: CZSV-- + ******************************************/ +void z8002_device::Z8D_dddd_0010() +{ + GET_DST(OP0,NIB2); + RW(dst) = NEGW(RW(dst)); +} + +/****************************************** + test rd + flags: ------ + ******************************************/ +void z8002_device::Z8D_dddd_0100() +{ + GET_DST(OP0,NIB2); + TESTW(RW(dst)); +} + +/****************************************** + tset rd + flags: --S--- + ******************************************/ +void z8002_device::Z8D_dddd_0110() +{ + GET_DST(OP0,NIB2); + if (RW(dst) & S16) SET_S; else CLR_S; + RW(dst) = 0xffff; +} + +/****************************************** + clr rd + flags: ------ + ******************************************/ +void z8002_device::Z8D_dddd_1000() +{ + GET_DST(OP0,NIB2); + RW(dst) = 0; +} + +/****************************************** + setflg imm4 + flags: CZSV-- + ******************************************/ +void z8002_device::Z8D_imm4_0001() +{ + m_fcw |= m_op[0] & 0x00f0; +} + +/****************************************** + resflg imm4 + flags: CZSV-- + ******************************************/ +void z8002_device::Z8D_imm4_0011() +{ + m_fcw &= ~(m_op[0] & 0x00f0); +} + +/****************************************** + comflg flags + flags: CZSP-- + ******************************************/ +void z8002_device::Z8D_imm4_0101() +{ + m_fcw ^= (m_op[0] & 0x00f0); +} + +/****************************************** + ext8e imm8 + flags: ------ + ******************************************/ +void z8002_device::Z8E_imm8() +{ + CHECK_EXT_INSTR(); + GET_IMM8(0); + LOG(("Z8K '%s' %04x: ext8e $%02x\n", tag(), m_pc, imm8)); + if (m_fcw & F_EPU) { + /* Z8001 EPU code goes here */ + (void)imm8; + } +} + +/****************************************** + ext8f imm8 + flags: ------ + ******************************************/ +void z8002_device::Z8F_imm8() +{ + CHECK_EXT_INSTR(); + GET_IMM8(0); + LOG(("Z8K '%s' %04x: ext8f $%02x\n", tag(), m_pc, imm8)); + if (m_fcw & F_EPU) { + /* Z8001 EPU code goes here */ + (void)imm8; + } +} + +/****************************************** + cpl rrd,rrs + flags: CZSV-- + ******************************************/ +void z8002_device::Z90_ssss_dddd() +{ + GET_DST(OP0,NIB3); + GET_SRC(OP0,NIB2); + CPL(RL(dst), RL(src)); +} + +/****************************************** + pushl @rd,rrs + flags: ------ + ******************************************/ +void z8002_device::Z91_ddN0_ssss() +{ + GET_SRC(OP0,NIB3); + GET_DST(OP0,NIB2); + PUSHL(dst, RL(src)); +} + +/****************************************** + subl rrd,rrs + flags: CZSV-- + ******************************************/ +void z8002_device::Z92_ssss_dddd() +{ + GET_DST(OP0,NIB3); + GET_SRC(OP0,NIB2); + RL(dst) = SUBL(RL(dst), RL(src)); +} + +/****************************************** + push @rd,rs + flags: ------ + ******************************************/ +void z8002_device::Z93_ddN0_ssss() +{ + GET_SRC(OP0,NIB3); + GET_DST(OP0,NIB2); + PUSHW(dst, RW(src)); +} + +/****************************************** + ldl rrd,rrs + flags: ------ + ******************************************/ +void z8002_device::Z94_ssss_dddd() +{ + GET_DST(OP0,NIB3); + GET_SRC(OP0,NIB2); + RL(dst) = RL(src); +} + +/****************************************** + popl rrd,@rs + flags: ------ + ******************************************/ +void z8002_device::Z95_ssN0_dddd() +{ + GET_DST(OP0,NIB3); + GET_SRC(OP0,NIB2); + RL(dst) = POPL(src); +} + +/****************************************** + addl rrd,rrs + flags: CZSV-- + ******************************************/ +void z8002_device::Z96_ssss_dddd() +{ + GET_DST(OP0,NIB3); + GET_SRC(OP0,NIB2); + RL(dst) = ADDL(RL(dst), RL(src)); +} + +/****************************************** + pop rd,@rs + flags: ------ + ******************************************/ +void z8002_device::Z97_ssN0_dddd() +{ + GET_DST(OP0,NIB3); + GET_SRC(OP0,NIB2); + RW(dst) = POPW(src); +} + +/****************************************** + multl rqd,rrs + flags: CZSV-- + ******************************************/ +void z8002_device::Z98_ssss_dddd() +{ + GET_DST(OP0,NIB3); + GET_SRC(OP0,NIB2); + RQ(dst) = MULTL(RQ(dst), RL(src)); +} + +/****************************************** + mult rrd,rs + flags: CZSV-- + ******************************************/ +void z8002_device::Z99_ssss_dddd() +{ + GET_DST(OP0,NIB3); + GET_SRC(OP0,NIB2); + RL(dst) = MULTW(RL(dst), RW(src)); +} + +/****************************************** + divl rqd,rrs + flags: CZSV-- + ******************************************/ +void z8002_device::Z9A_ssss_dddd() +{ + GET_DST(OP0,NIB3); + GET_SRC(OP0,NIB2); + RQ(dst) = DIVL(RQ(dst), RL(src)); +} + +/****************************************** + div rrd,rs + flags: CZSV-- + ******************************************/ +void z8002_device::Z9B_ssss_dddd() +{ + GET_DST(OP0,NIB3); + GET_SRC(OP0,NIB2); + RL(dst) = DIVW(RL(dst), RW(src)); +} + +/****************************************** + testl rrd + flags: -ZS--- + ******************************************/ +void z8002_device::Z9C_dddd_1000() +{ + GET_DST(OP0,NIB2); + CLR_ZS; + if (!RL(dst)) SET_Z; + else if (RL(dst) & S32) SET_S; +} + +/****************************************** + rsvd9d + flags: ------ + ******************************************/ +void z8002_device::Z9D_imm8() +{ + GET_IMM8(0); + LOG(("Z8K '%s' %04x: rsvd9d $%02x\n", tag(), m_pc, imm8)); + if (m_fcw & F_EPU) { + /* Z8001 EPU code goes here */ + (void)imm8; + } +} + +/****************************************** + ret cc + flags: ------ + ******************************************/ +void z8002_device::Z9E_0000_cccc() +{ + GET_CCC(OP0,NIB3); + if (segmented_mode()) + switch (cc) { + case 0: if (CC0) set_pc(segmented_addr(POPL(SP))); break; + case 1: if (CC1) set_pc(segmented_addr(POPL(SP))); break; + case 2: if (CC2) set_pc(segmented_addr(POPL(SP))); break; + case 3: if (CC3) set_pc(segmented_addr(POPL(SP))); break; + case 4: if (CC4) set_pc(segmented_addr(POPL(SP))); break; + case 5: if (CC5) set_pc(segmented_addr(POPL(SP))); break; + case 6: if (CC6) set_pc(segmented_addr(POPL(SP))); break; + case 7: if (CC7) set_pc(segmented_addr(POPL(SP))); break; + case 8: if (CC8) set_pc(segmented_addr(POPL(SP))); break; + case 9: if (CC9) set_pc(segmented_addr(POPL(SP))); break; + case 10: if (CCA) set_pc(segmented_addr(POPL(SP))); break; + case 11: if (CCB) set_pc(segmented_addr(POPL(SP))); break; + case 12: if (CCC) set_pc(segmented_addr(POPL(SP))); break; + case 13: if (CCD) set_pc(segmented_addr(POPL(SP))); break; + case 14: if (CCE) set_pc(segmented_addr(POPL(SP))); break; + case 15: if (CCF) set_pc(segmented_addr(POPL(SP))); break; + } + else + switch (cc) { + case 0: if (CC0) set_pc(POPW(SP)); break; + case 1: if (CC1) set_pc(POPW(SP)); break; + case 2: if (CC2) set_pc(POPW(SP)); break; + case 3: if (CC3) set_pc(POPW(SP)); break; + case 4: if (CC4) set_pc(POPW(SP)); break; + case 5: if (CC5) set_pc(POPW(SP)); break; + case 6: if (CC6) set_pc(POPW(SP)); break; + case 7: if (CC7) set_pc(POPW(SP)); break; + case 8: if (CC8) set_pc(POPW(SP)); break; + case 9: if (CC9) set_pc(POPW(SP)); break; + case 10: if (CCA) set_pc(POPW(SP)); break; + case 11: if (CCB) set_pc(POPW(SP)); break; + case 12: if (CCC) set_pc(POPW(SP)); break; + case 13: if (CCD) set_pc(POPW(SP)); break; + case 14: if (CCE) set_pc(POPW(SP)); break; + case 15: if (CCF) set_pc(POPW(SP)); break; + } +} + +/****************************************** + rsvd9f + flags: ------ + ******************************************/ +void z8002_device::Z9F_imm8() +{ + GET_IMM8(0); + LOG(("Z8K '%s' %04x: rsvd9f $%02x\n", tag(), m_pc, imm8)); + if (m_fcw & F_EPU) { + /* Z8001 EPU code goes here */ + (void)imm8; + } +} + +/****************************************** + ldb rbd,rbs + flags: ------ + ******************************************/ +void z8002_device::ZA0_ssss_dddd() +{ + GET_DST(OP0,NIB3); + GET_SRC(OP0,NIB2); + RB(dst) = RB(src); +} + +/****************************************** + ld rd,rs + flags: ------ + ******************************************/ +void z8002_device::ZA1_ssss_dddd() +{ + GET_DST(OP0,NIB3); + GET_SRC(OP0,NIB2); + RW(dst) = RW(src); +} + +/****************************************** + resb rbd,imm4 + flags: ------ + ******************************************/ +void z8002_device::ZA2_dddd_imm4() +{ + GET_BIT(OP0); + GET_DST(OP0,NIB2); + RB(dst) &= ~bit; +} + +/****************************************** + res rd,imm4 + flags: ------ + ******************************************/ +void z8002_device::ZA3_dddd_imm4() +{ + GET_BIT(OP0); + GET_DST(OP0,NIB2); + RW(dst) &= ~bit; +} + +/****************************************** + setb rbd,imm4 + flags: ------ + ******************************************/ +void z8002_device::ZA4_dddd_imm4() +{ + GET_BIT(OP0); + GET_DST(OP0,NIB2); + RB(dst) |= bit; +} + +/****************************************** + set rd,imm4 + flags: ------ + ******************************************/ +void z8002_device::ZA5_dddd_imm4() +{ + GET_BIT(OP0); + GET_DST(OP0,NIB2); + RW(dst) |= bit; +} + +/****************************************** + bitb rbd,imm4 + flags: -Z---- + ******************************************/ +void z8002_device::ZA6_dddd_imm4() +{ + GET_BIT(OP0); + GET_DST(OP0,NIB2); + if (RB(dst) & bit) CLR_Z; else SET_Z; +} + +/****************************************** + bit rd,imm4 + flags: -Z---- + ******************************************/ +void z8002_device::ZA7_dddd_imm4() +{ + GET_BIT(OP0); + GET_DST(OP0,NIB2); + if (RW(dst) & bit) CLR_Z; else SET_Z; +} + +/****************************************** + incb rbd,imm4m1 + flags: -ZSV-- + ******************************************/ +void z8002_device::ZA8_dddd_imm4m1() +{ + GET_I4M1(OP0,NIB3); + GET_DST(OP0,NIB2); + RB(dst) = INCB(RB(dst), i4p1); +} + +/****************************************** + inc rd,imm4m1 + flags: -ZSV-- + ******************************************/ +void z8002_device::ZA9_dddd_imm4m1() +{ + GET_I4M1(OP0,NIB3); + GET_DST(OP0,NIB2); + RW(dst) = INCW(RW(dst), i4p1); +} + +/****************************************** + decb rbd,imm4m1 + flags: -ZSV-- + ******************************************/ +void z8002_device::ZAA_dddd_imm4m1() +{ + GET_I4M1(OP0,NIB3); + GET_DST(OP0,NIB2); + RB(dst) = DECB(RB(dst), i4p1); +} + +/****************************************** + dec rd,imm4m1 + flags: -ZSV-- + ******************************************/ +void z8002_device::ZAB_dddd_imm4m1() +{ + GET_I4M1(OP0,NIB3); + GET_DST(OP0,NIB2); + RW(dst) = DECW(RW(dst), i4p1); +} + +/****************************************** + exb rbd,rbs + flags: ------ + ******************************************/ +void z8002_device::ZAC_ssss_dddd() +{ + GET_DST(OP0,NIB3); + GET_SRC(OP0,NIB2); + UINT8 tmp = RB(src); + RB(src) = RB(dst); + RB(dst) = tmp; +} + +/****************************************** + ex rd,rs + flags: ------ + ******************************************/ +void z8002_device::ZAD_ssss_dddd() +{ + GET_DST(OP0,NIB3); + GET_SRC(OP0,NIB2); + UINT16 tmp = RW(src); + RW(src) = RW(dst); + RW(dst) = tmp; +} + +/****************************************** + tccb cc,rbd + flags: ------ + ******************************************/ +void z8002_device::ZAE_dddd_cccc() +{ + GET_CCC(OP0,NIB3); + GET_DST(OP0,NIB2); + UINT8 tmp = RB(dst) & ~1; + switch (cc) { + case 0: if (CC0) tmp |= 1; break; + case 1: if (CC1) tmp |= 1; break; + case 2: if (CC2) tmp |= 1; break; + case 3: if (CC3) tmp |= 1; break; + case 4: if (CC4) tmp |= 1; break; + case 5: if (CC5) tmp |= 1; break; + case 6: if (CC6) tmp |= 1; break; + case 7: if (CC7) tmp |= 1; break; + case 8: if (CC8) tmp |= 1; break; + case 9: if (CC9) tmp |= 1; break; + case 10: if (CCA) tmp |= 1; break; + case 11: if (CCB) tmp |= 1; break; + case 12: if (CCC) tmp |= 1; break; + case 13: if (CCD) tmp |= 1; break; + case 14: if (CCE) tmp |= 1; break; + case 15: if (CCF) tmp |= 1; break; + } + RB(dst) = tmp; +} + +/****************************************** + tcc cc,rd + flags: ------ + ******************************************/ +void z8002_device::ZAF_dddd_cccc() +{ + GET_CCC(OP0,NIB3); + GET_DST(OP0,NIB2); + UINT16 tmp = RW(dst) & ~1; + switch (cc) { + case 0: if (CC0) tmp |= 1; break; + case 1: if (CC1) tmp |= 1; break; + case 2: if (CC2) tmp |= 1; break; + case 3: if (CC3) tmp |= 1; break; + case 4: if (CC4) tmp |= 1; break; + case 5: if (CC5) tmp |= 1; break; + case 6: if (CC6) tmp |= 1; break; + case 7: if (CC7) tmp |= 1; break; + case 8: if (CC8) tmp |= 1; break; + case 9: if (CC9) tmp |= 1; break; + case 10: if (CCA) tmp |= 1; break; + case 11: if (CCB) tmp |= 1; break; + case 12: if (CCC) tmp |= 1; break; + case 13: if (CCD) tmp |= 1; break; + case 14: if (CCE) tmp |= 1; break; + case 15: if (CCF) tmp |= 1; break; + } + RW(dst) = tmp; +} + +/****************************************** + dab rbd + flags: CZS--- + ******************************************/ +void z8002_device::ZB0_dddd_0000() +{ + GET_DST(OP0,NIB2); + UINT8 result; + UINT16 idx = RB(dst); + if (m_fcw & F_C) idx |= 0x100; + if (m_fcw & F_H) idx |= 0x200; + if (m_fcw & F_DA) idx |= 0x400; + result = Z8000_dab[idx]; + CLR_CZS; + CHK_XXXB_ZS; + if (Z8000_dab[idx] & 0x100) SET_C; + RB(dst) = result; +} + +/****************************************** + extsb rd + flags: ------ + ******************************************/ +void z8002_device::ZB1_dddd_0000() +{ + GET_DST(OP0,NIB2); + RW(dst) = (RW(dst) & 0xff) | ((RW(dst) & S08) ? 0xff00 : 0x0000); +} + +/****************************************** + extsl rqd + flags: ------ + ******************************************/ +void z8002_device::ZB1_dddd_0111() +{ + GET_DST(OP0,NIB2); + RQ(dst) = CONCAT_64((RQ(dst) & S32) ? + 0xfffffffful : 0, EXTRACT_64LO(RQ(dst))); +} + +/****************************************** + exts rrd + flags: ------ + ******************************************/ +void z8002_device::ZB1_dddd_1010() +{ + GET_DST(OP0,NIB2); + RL(dst) = (RL(dst) & 0xffff) | ((RL(dst) & S16) ? + 0xffff0000ul : 0x00000000ul); +} + +/****************************************** + sllb rbd,imm8 + flags: CZS--- + srlb rbd,imm8 + flags: CZSV-- + ******************************************/ +void z8002_device::ZB2_dddd_0001_imm8() +{ + GET_DST(OP0,NIB2); + GET_IMM8(OP1); + if (imm8 & S08) + RB(dst) = SRLB(RB(dst), -(INT8)imm8); + else + RB(dst) = SLLB(RB(dst), imm8); +} + +/****************************************** + sdlb rbd,rs + flags: CZS--- + ******************************************/ +void z8002_device::ZB2_dddd_0011_0000_ssss_0000_0000() +{ + GET_DST(OP0,NIB2); + GET_SRC(OP1,NIB1); + RB(dst) = SRLB(RB(dst), (INT8)RW(src)); +} + +/****************************************** + rlb rbd,imm1or2 + flags: CZSV-- + ******************************************/ +void z8002_device::ZB2_dddd_00I0() +{ + GET_DST(OP0,NIB2); + GET_IMM1(OP0,NIB3); + RB(dst) = RLB(RB(dst), imm1); +} + +/****************************************** + rrb rbd,imm1or2 + flags: CZSV-- + ******************************************/ +void z8002_device::ZB2_dddd_01I0() +{ + GET_DST(OP0,NIB2); + GET_IMM1(OP0,NIB3); + RB(dst) = RRB(RB(dst), imm1); +} + +/****************************************** + slab rbd,imm8 + flags: CZSV-- + srab rbd,imm8 + flags: CZSV-- + ******************************************/ +void z8002_device::ZB2_dddd_1001_imm8() +{ + GET_DST(OP0,NIB2); + GET_IMM8(OP1); + if (imm8 & S08) + RB(dst) = SRAB(RB(dst), -(INT8)imm8); + else + RB(dst) = SLAB(RB(dst), imm8); +} + +/****************************************** + sdab rbd,rs + flags: CZSV-- + ******************************************/ +void z8002_device::ZB2_dddd_1011_0000_ssss_0000_0000() +{ + GET_DST(OP0,NIB2); + GET_SRC(OP1,NIB1); + RB(dst) = SDAB(RB(dst), (INT8) RW(src)); +} + +/****************************************** + rlcb rbd,imm1or2 + flags: -Z---- + ******************************************/ +void z8002_device::ZB2_dddd_10I0() +{ + GET_DST(OP0,NIB2); + GET_IMM1(OP0,NIB3); + RB(dst) = RLCB(RB(dst), imm1); +} + +/****************************************** + rrcb rbd,imm1or2 + flags: -Z---- + ******************************************/ +void z8002_device::ZB2_dddd_11I0() +{ + GET_DST(OP0,NIB2); + GET_IMM1(OP0,NIB3); + RB(dst) = RRCB(RB(dst), imm1); +} + +/****************************************** + sll rd,imm8 + flags: CZS--- + srl rd,imm8 + flags: CZSV-- + ******************************************/ +void z8002_device::ZB3_dddd_0001_imm8() +{ + GET_DST(OP0,NIB2); + GET_IMM16(OP1); + if (imm16 & S16) + RW(dst) = SRLW(RW(dst), -(INT16)imm16); + else + RW(dst) = SLLW(RW(dst), imm16); +} + +/****************************************** + sdl rd,rs + flags: CZS--- + ******************************************/ +void z8002_device::ZB3_dddd_0011_0000_ssss_0000_0000() +{ + GET_DST(OP0,NIB2); + GET_SRC(OP1,NIB1); + RW(dst) = SDLW(RW(dst), (INT8)RW(src)); +} + +/****************************************** + rl rd,imm1or2 + flags: CZSV-- + ******************************************/ +void z8002_device::ZB3_dddd_00I0() +{ + GET_DST(OP0,NIB2); + GET_IMM1(OP0,NIB3); + RW(dst) = RLW(RW(dst), imm1); +} + +/****************************************** + slll rrd,imm8 + flags: CZS--- + srll rrd,imm8 + flags: CZSV-- + ******************************************/ +void z8002_device::ZB3_dddd_0101_imm8() +{ + GET_DST(OP0,NIB2); + GET_IMM16(OP1); + if (imm16 & S16) + RL(dst) = SRLL(RL(dst), -(INT16)imm16); + else + RL(dst) = SLLL(RL(dst), imm16); +} + +/****************************************** + sdll rrd,rs + flags: CZS--- + ******************************************/ +void z8002_device::ZB3_dddd_0111_0000_ssss_0000_0000() +{ + GET_DST(OP0,NIB2); + GET_SRC(OP1,NIB1); + RL(dst) = SDLL(RL(dst), RW(src) & 0xff); +} + +/****************************************** + rr rd,imm1or2 + flags: CZSV-- + ******************************************/ +void z8002_device::ZB3_dddd_01I0() +{ + GET_DST(OP0,NIB2); + GET_IMM1(OP0,NIB3); + RW(dst) = RRW(RW(dst), imm1); +} + +/****************************************** + sla rd,imm8 + flags: CZSV-- + sra rd,imm8 + flags: CZSV-- + ******************************************/ +void z8002_device::ZB3_dddd_1001_imm8() +{ + GET_DST(OP0,NIB2); + GET_IMM16(OP1); + if (imm16 & S16) + RW(dst) = SRAW(RW(dst), -(INT16)imm16); + else + RW(dst) = SLAW(RW(dst), imm16); +} + +/****************************************** + sda rd,rs + flags: CZSV-- + ******************************************/ +void z8002_device::ZB3_dddd_1011_0000_ssss_0000_0000() +{ + GET_DST(OP0,NIB2); + GET_SRC(OP1,NIB1); + RW(dst) = SDAW(RW(dst), (INT8)RW(src)); +} + +/****************************************** + rlc rd,imm1or2 + flags: CZSV-- + ******************************************/ +void z8002_device::ZB3_dddd_10I0() +{ + GET_DST(OP0,NIB2); + GET_IMM1(OP0,NIB3); + RW(dst) = RLCW(RW(dst), imm1); +} + +/****************************************** + slal rrd,imm8 + flags: CZSV-- + sral rrd,imm8 + flags: CZSV-- + ******************************************/ +void z8002_device::ZB3_dddd_1101_imm8() +{ + GET_DST(OP0,NIB2); + GET_IMM16(OP1); + if (imm16 & S16) + RL(dst) = SRAL(RL(dst), -(INT16)imm16); + else + RL(dst) = SLAL(RL(dst), imm16); +} + +/****************************************** + sdal rrd,rs + flags: CZSV-- + ******************************************/ +void z8002_device::ZB3_dddd_1111_0000_ssss_0000_0000() +{ + GET_DST(OP0,NIB2); + GET_SRC(OP1,NIB1); + RL(dst) = SDAL(RL(dst), RW(src) & 0xff); +} + +/****************************************** + rrc rd,imm1or2 + flags: CZSV-- + ******************************************/ +void z8002_device::ZB3_dddd_11I0() +{ + GET_DST(OP0,NIB2); + GET_IMM1(OP0,NIB3); + RW(dst) = RRCW(RW(dst), imm1); +} + +/****************************************** + adcb rbd,rbs + flags: CZSVDH + ******************************************/ +void z8002_device::ZB4_ssss_dddd() +{ + GET_DST(OP0,NIB3); + GET_SRC(OP0,NIB2); + RB(dst) = ADCB(RB(dst), RB(src)); +} + +/****************************************** + adc rd,rs + flags: CZSV-- + ******************************************/ +void z8002_device::ZB5_ssss_dddd() +{ + GET_DST(OP0,NIB3); + GET_SRC(OP0,NIB2); + RW(dst) = ADCW(RW(dst), RW(src)); +} + +/****************************************** + sbcb rbd,rbs + flags: CZSVDH + ******************************************/ +void z8002_device::ZB6_ssss_dddd() +{ + GET_DST(OP0,NIB3); + GET_SRC(OP0,NIB2); + RB(dst) = SBCB(RB(dst), RB(src)); +} + +/****************************************** + sbc rd,rs + flags: CZSV-- + ******************************************/ +void z8002_device::ZB7_ssss_dddd() +{ + GET_DST(OP0,NIB3); + GET_SRC(OP0,NIB2); + RW(dst) = SBCW(RW(dst), RW(src)); +} + +/****************************************** + trtib @rd,@rs,rr + flags: -ZSV-- + ******************************************/ +void z8002_device::ZB8_ddN0_0010_0000_rrrr_ssN0_0000() +{ + GET_DST(OP0,NIB2); + GET_SRC(OP1,NIB2); + GET_CNT(OP1,NIB1); + UINT8 xlt = RDMEM_B(AS_DATA, addr_from_reg(src) + RDMEM_B(AS_DATA, addr_from_reg(dst))); + RB(1) = xlt; /* load RH1 */ + if (xlt) CLR_Z; else SET_Z; + add_to_addr_reg(dst, 1); + if (--RW(cnt)) CLR_V; else SET_V; +} + +/****************************************** + trtirb @rd,@rs,rbr + flags: -ZSV-- + ******************************************/ +void z8002_device::ZB8_ddN0_0110_0000_rrrr_ssN0_1110() +{ + GET_DST(OP0,NIB2); + GET_SRC(OP1,NIB2); + GET_CNT(OP1,NIB1); + UINT8 xlt = RDMEM_B(AS_DATA, addr_from_reg(src) + RDMEM_B(AS_DATA, addr_from_reg(dst))); + RB(1) = xlt; /* load RH1 */ + if (xlt) CLR_Z; else SET_Z; + add_to_addr_reg(dst, 1); + if (--RW(cnt)) { + CLR_V; + if (!xlt) + m_pc -= 4; + } + else SET_V; +} + +/****************************************** + trtdb @rd,@rs,rbr + flags: -ZSV-- + ******************************************/ +void z8002_device::ZB8_ddN0_1010_0000_rrrr_ssN0_0000() +{ + GET_DST(OP0,NIB2); + GET_SRC(OP1,NIB2); + GET_CNT(OP1,NIB1); + UINT8 xlt = RDMEM_B(AS_DATA, addr_from_reg(src) + RDMEM_B(AS_DATA, addr_from_reg(dst))); + RB(1) = xlt; /* load RH1 */ + if (xlt) CLR_Z; else SET_Z; + sub_from_addr_reg(dst, 1); + if (--RW(cnt)) CLR_V; else SET_V; +} + +/****************************************** + trtdrb @rd,@rs,rbr + flags: -ZSV-- + ******************************************/ +void z8002_device::ZB8_ddN0_1110_0000_rrrr_ssN0_1110() +{ + GET_DST(OP0,NIB2); + GET_SRC(OP1,NIB2); + GET_CNT(OP1,NIB1); + UINT8 xlt = RDMEM_B(AS_DATA, addr_from_reg(src) + RDMEM_B(AS_DATA, addr_from_reg(dst))); + RB(1) = xlt; /* load RH1 */ + if (xlt) CLR_Z; else SET_Z; + sub_from_addr_reg(dst, 1); + if (--RW(cnt)) { + CLR_V; + if (!xlt) + m_pc -= 4; + } + else SET_V; +} + +/****************************************** + trib @rd,@rs,rbr + flags: -ZSV-- + ******************************************/ +void z8002_device::ZB8_ddN0_0000_0000_rrrr_ssN0_0000() +{ + GET_DST(OP0,NIB2); + GET_SRC(OP1,NIB2); + GET_CNT(OP1,NIB1); + UINT8 xlt = RDMEM_B(AS_DATA, addr_from_reg(src) + RDMEM_B(AS_DATA, addr_from_reg(dst))); + WRMEM_B(AS_DATA, addr_from_reg(dst), xlt); + RB(1) = xlt; /* destroy RH1 */ + add_to_addr_reg(dst, 1); + if (--RW(cnt)) CLR_V; else SET_V; +} + +/****************************************** + trirb @rd,@rs,rbr + flags: -ZSV-- + ******************************************/ +void z8002_device::ZB8_ddN0_0100_0000_rrrr_ssN0_0000() +{ + GET_DST(OP0,NIB2); + GET_SRC(OP1,NIB2); + GET_CNT(OP1,NIB1); + UINT8 xlt = RDMEM_B(AS_DATA, addr_from_reg(src) + RDMEM_B(AS_DATA, addr_from_reg(dst))); + WRMEM_B(AS_DATA, addr_from_reg(dst), xlt); + RB(1) = xlt; /* destroy RH1 */ + add_to_addr_reg(dst, 1); + if (--RW(cnt)) { CLR_V; m_pc -= 4; } else SET_V; +} + +/****************************************** + trdb @rd,@rs,rbr + flags: -ZSV-- + ******************************************/ +void z8002_device::ZB8_ddN0_1000_0000_rrrr_ssN0_0000() +{ + GET_DST(OP0,NIB2); + GET_SRC(OP1,NIB2); + GET_CNT(OP1,NIB1); + UINT8 xlt = RDMEM_B(AS_DATA, addr_from_reg(src) + RDMEM_B(AS_DATA, addr_from_reg(dst))); + WRMEM_B(AS_DATA, addr_from_reg(dst), xlt); + RB(1) = xlt; /* destroy RH1 */ + sub_from_addr_reg(dst, 1); + if (--RW(cnt)) CLR_V; else SET_V; +} + +/****************************************** + trdrb @rd,@rs,rbr + flags: -ZSV-- + ******************************************/ +void z8002_device::ZB8_ddN0_1100_0000_rrrr_ssN0_0000() +{ + GET_DST(OP0,NIB2); + GET_SRC(OP1,NIB2); + GET_CNT(OP1,NIB1); + UINT8 xlt = RDMEM_B(AS_DATA, addr_from_reg(src) + RDMEM_B(AS_DATA, addr_from_reg(dst))); + WRMEM_B(AS_DATA, addr_from_reg(dst), xlt); + RB(1) = xlt; /* destroy RH1 */ + sub_from_addr_reg(dst, 1); + if (--RW(cnt)) { CLR_V; m_pc -= 4; } else SET_V; +} + +/****************************************** + rsvdb9 + flags: ------ + ******************************************/ +void z8002_device::ZB9_imm8() +{ + GET_IMM8(0); + LOG(("Z8K '%s' %04x: rsvdb9 $%02x\n", tag(), m_pc, imm8)); + if (m_fcw & F_EPU) { + /* Z8001 EPU code goes here */ + (void)imm8; + } + (void)imm8; +} + +/****************************************** + cpib rbd,@rs,rr,cc + flags: CZSV-- + ******************************************/ +void z8002_device::ZBA_ssN0_0000_0000_rrrr_dddd_cccc() +{ + GET_SRC(OP0,NIB2); + GET_CCC(OP1,NIB3); + GET_DST(OP1,NIB2); + GET_CNT(OP1,NIB1); + CPB(RB(dst), RDMEM_B(AS_DATA, addr_from_reg(src))); + switch (cc) { + case 0: if (CC0) SET_Z; else CLR_Z; break; + case 1: if (CC1) SET_Z; else CLR_Z; break; + case 2: if (CC2) SET_Z; else CLR_Z; break; + case 3: if (CC3) SET_Z; else CLR_Z; break; + case 4: if (CC4) SET_Z; else CLR_Z; break; + case 5: if (CC5) SET_Z; else CLR_Z; break; + case 6: if (CC6) SET_Z; else CLR_Z; break; + case 7: if (CC7) SET_Z; else CLR_Z; break; + case 8: if (CC8) SET_Z; else CLR_Z; break; + case 9: if (CC9) SET_Z; else CLR_Z; break; + case 10: if (CCA) SET_Z; else CLR_Z; break; + case 11: if (CCB) SET_Z; else CLR_Z; break; + case 12: if (CCC) SET_Z; else CLR_Z; break; + case 13: if (CCD) SET_Z; else CLR_Z; break; + case 14: if (CCE) SET_Z; else CLR_Z; break; + case 15: if (CCF) SET_Z; else CLR_Z; break; + } + add_to_addr_reg(src, 1); + if (--RW(cnt)) CLR_V; else SET_V; +} + +/****************************************** + ldib @rd,@rs,rr + ldibr @rd,@rs,rr + flags: ---V-- + ******************************************/ +void z8002_device::ZBA_ssN0_0001_0000_rrrr_ddN0_x000() +{ + GET_SRC(OP0,NIB2); + GET_CNT(OP1,NIB1); + GET_DST(OP1,NIB2); + GET_CCC(OP1,NIB3); /* repeat? */ + WRMEM_B(AS_DATA, addr_from_reg(dst), RDMEM_B(AS_DATA, addr_from_reg(src))); + add_to_addr_reg(src, 1); + add_to_addr_reg(dst, 1); + if (--RW(cnt)) { CLR_V; if (cc == 0) m_pc -= 4; } else SET_V; +} + +/****************************************** + cpsib @rd,@rs,rr,cc + flags: CZSV-- + ******************************************/ +void z8002_device::ZBA_ssN0_0010_0000_rrrr_ddN0_cccc() +{ + GET_SRC(OP0,NIB2); + GET_CCC(OP1,NIB3); + GET_DST(OP1,NIB2); + GET_CNT(OP1,NIB1); + CPB(RDMEM_B(AS_DATA, addr_from_reg(dst)), RDMEM_B(AS_DATA, addr_from_reg(src))); + switch (cc) { + case 0: if (CC0) SET_Z; else CLR_Z; break; + case 1: if (CC1) SET_Z; else CLR_Z; break; + case 2: if (CC2) SET_Z; else CLR_Z; break; + case 3: if (CC3) SET_Z; else CLR_Z; break; + case 4: if (CC4) SET_Z; else CLR_Z; break; + case 5: if (CC5) SET_Z; else CLR_Z; break; + case 6: if (CC6) SET_Z; else CLR_Z; break; + case 7: if (CC7) SET_Z; else CLR_Z; break; + case 8: if (CC8) SET_Z; else CLR_Z; break; + case 9: if (CC9) SET_Z; else CLR_Z; break; + case 10: if (CCA) SET_Z; else CLR_Z; break; + case 11: if (CCB) SET_Z; else CLR_Z; break; + case 12: if (CCC) SET_Z; else CLR_Z; break; + case 13: if (CCD) SET_Z; else CLR_Z; break; + case 14: if (CCE) SET_Z; else CLR_Z; break; + case 15: if (CCF) SET_Z; else CLR_Z; break; + } + add_to_addr_reg(src, 1); + add_to_addr_reg(dst, 1); + if (--RW(cnt)) { CLR_V; if (!(m_fcw & F_Z)) m_pc -= 4; } else SET_V; +} + +/****************************************** + cpirb rbd,@rs,rr,cc + flags: CZSV-- + ******************************************/ +void z8002_device::ZBA_ssN0_0100_0000_rrrr_dddd_cccc() +{ + GET_SRC(OP0,NIB2); + GET_CCC(OP1,NIB3); + GET_DST(OP1,NIB2); + GET_CNT(OP1,NIB1); + CPB(RB(dst), RDMEM_B(AS_DATA, addr_from_reg(src))); + switch (cc) { + case 0: if (CC0) SET_Z; else CLR_Z; break; + case 1: if (CC1) SET_Z; else CLR_Z; break; + case 2: if (CC2) SET_Z; else CLR_Z; break; + case 3: if (CC3) SET_Z; else CLR_Z; break; + case 4: if (CC4) SET_Z; else CLR_Z; break; + case 5: if (CC5) SET_Z; else CLR_Z; break; + case 6: if (CC6) SET_Z; else CLR_Z; break; + case 7: if (CC7) SET_Z; else CLR_Z; break; + case 8: if (CC8) SET_Z; else CLR_Z; break; + case 9: if (CC9) SET_Z; else CLR_Z; break; + case 10: if (CCA) SET_Z; else CLR_Z; break; + case 11: if (CCB) SET_Z; else CLR_Z; break; + case 12: if (CCC) SET_Z; else CLR_Z; break; + case 13: if (CCD) SET_Z; else CLR_Z; break; + case 14: if (CCE) SET_Z; else CLR_Z; break; + case 15: if (CCF) SET_Z; else CLR_Z; break; + } + add_to_addr_reg(src, 1); + if (--RW(cnt)) { CLR_V; if (!(m_fcw & F_Z)) m_pc -= 4; } else SET_V; +} + +/****************************************** + cpsirb @rd,@rs,rr,cc + flags: CZSV-- + ******************************************/ +void z8002_device::ZBA_ssN0_0110_0000_rrrr_ddN0_cccc() +{ + GET_SRC(OP0,NIB2); + GET_CCC(OP1,NIB3); + GET_DST(OP1,NIB2); + GET_CNT(OP1,NIB1); + CPB(RDMEM_B(AS_DATA, addr_from_reg(dst)), RDMEM_B(AS_DATA, addr_from_reg(src))); + switch (cc) { + case 0: if (CC0) SET_Z; else CLR_Z; break; + case 1: if (CC1) SET_Z; else CLR_Z; break; + case 2: if (CC2) SET_Z; else CLR_Z; break; + case 3: if (CC3) SET_Z; else CLR_Z; break; + case 4: if (CC4) SET_Z; else CLR_Z; break; + case 5: if (CC5) SET_Z; else CLR_Z; break; + case 6: if (CC6) SET_Z; else CLR_Z; break; + case 7: if (CC7) SET_Z; else CLR_Z; break; + case 8: if (CC8) SET_Z; else CLR_Z; break; + case 9: if (CC9) SET_Z; else CLR_Z; break; + case 10: if (CCA) SET_Z; else CLR_Z; break; + case 11: if (CCB) SET_Z; else CLR_Z; break; + case 12: if (CCC) SET_Z; else CLR_Z; break; + case 13: if (CCD) SET_Z; else CLR_Z; break; + case 14: if (CCE) SET_Z; else CLR_Z; break; + case 15: if (CCF) SET_Z; else CLR_Z; break; + } + add_to_addr_reg(src, 1); + add_to_addr_reg(dst, 1); + if (--RW(cnt)) { CLR_V; if (!(m_fcw & F_Z)) m_pc -= 4; } else SET_V; +} + +/****************************************** + cpdb rbd,@rs,rr,cc + flags: CZSV-- + ******************************************/ +void z8002_device::ZBA_ssN0_1000_0000_rrrr_dddd_cccc() +{ + GET_SRC(OP0,NIB2); + GET_CCC(OP1,NIB3); + GET_DST(OP1,NIB2); + GET_CNT(OP1,NIB1); + CPB(RB(dst), RDMEM_B(AS_DATA, addr_from_reg(src))); + switch (cc) { + case 0: if (CC0) SET_Z; else CLR_Z; break; + case 1: if (CC1) SET_Z; else CLR_Z; break; + case 2: if (CC2) SET_Z; else CLR_Z; break; + case 3: if (CC3) SET_Z; else CLR_Z; break; + case 4: if (CC4) SET_Z; else CLR_Z; break; + case 5: if (CC5) SET_Z; else CLR_Z; break; + case 6: if (CC6) SET_Z; else CLR_Z; break; + case 7: if (CC7) SET_Z; else CLR_Z; break; + case 8: if (CC8) SET_Z; else CLR_Z; break; + case 9: if (CC9) SET_Z; else CLR_Z; break; + case 10: if (CCA) SET_Z; else CLR_Z; break; + case 11: if (CCB) SET_Z; else CLR_Z; break; + case 12: if (CCC) SET_Z; else CLR_Z; break; + case 13: if (CCD) SET_Z; else CLR_Z; break; + case 14: if (CCE) SET_Z; else CLR_Z; break; + case 15: if (CCF) SET_Z; else CLR_Z; break; + } + sub_from_addr_reg(src, 1); + if (--RW(cnt)) CLR_V; else SET_V; +} + +/****************************************** + lddb @rs,@rd,rr + lddbr @rs,@rd,rr + flags: ---V-- + ******************************************/ +void z8002_device::ZBA_ssN0_1001_0000_rrrr_ddN0_x000() +{ + GET_SRC(OP0,NIB2); + GET_CNT(OP1,NIB1); + GET_DST(OP1,NIB2); + GET_CCC(OP1,NIB3); + WRMEM_B(AS_DATA, addr_from_reg(dst), RDMEM_B(AS_DATA, addr_from_reg(src))); + sub_from_addr_reg(src, 1); + sub_from_addr_reg(dst, 1); + if (--RW(cnt)) { CLR_V; if (cc == 0) m_pc -= 4; } else SET_V; +} + +/****************************************** + cpsdb @rd,@rs,rr,cc + flags: CZSV-- + ******************************************/ +void z8002_device::ZBA_ssN0_1010_0000_rrrr_ddN0_cccc() +{ + GET_SRC(OP0,NIB2); + GET_CCC(OP1,NIB3); + GET_DST(OP1,NIB2); + GET_CNT(OP1,NIB1); + CPB(RDMEM_B(AS_DATA, addr_from_reg(dst)), RDMEM_B(AS_DATA, addr_from_reg(src))); + switch (cc) { + case 0: if (CC0) SET_Z; else CLR_Z; break; + case 1: if (CC1) SET_Z; else CLR_Z; break; + case 2: if (CC2) SET_Z; else CLR_Z; break; + case 3: if (CC3) SET_Z; else CLR_Z; break; + case 4: if (CC4) SET_Z; else CLR_Z; break; + case 5: if (CC5) SET_Z; else CLR_Z; break; + case 6: if (CC6) SET_Z; else CLR_Z; break; + case 7: if (CC7) SET_Z; else CLR_Z; break; + case 8: if (CC8) SET_Z; else CLR_Z; break; + case 9: if (CC9) SET_Z; else CLR_Z; break; + case 10: if (CCA) SET_Z; else CLR_Z; break; + case 11: if (CCB) SET_Z; else CLR_Z; break; + case 12: if (CCC) SET_Z; else CLR_Z; break; + case 13: if (CCD) SET_Z; else CLR_Z; break; + case 14: if (CCE) SET_Z; else CLR_Z; break; + case 15: if (CCF) SET_Z; else CLR_Z; break; + } + sub_from_addr_reg(src, 1); + sub_from_addr_reg(dst, 1); + if (--RW(cnt)) CLR_V; else SET_V; +} + +/****************************************** + cpdrb rbd,@rs,rr,cc + flags: CZSV-- + ******************************************/ +void z8002_device::ZBA_ssN0_1100_0000_rrrr_dddd_cccc() +{ + GET_SRC(OP0,NIB2); + GET_CCC(OP1,NIB3); + GET_DST(OP1,NIB2); + GET_CNT(OP1,NIB1); + CPB(RB(dst), RDMEM_B(AS_DATA, addr_from_reg(src))); + switch (cc) { + case 0: if (CC0) SET_Z; else CLR_Z; break; + case 1: if (CC1) SET_Z; else CLR_Z; break; + case 2: if (CC2) SET_Z; else CLR_Z; break; + case 3: if (CC3) SET_Z; else CLR_Z; break; + case 4: if (CC4) SET_Z; else CLR_Z; break; + case 5: if (CC5) SET_Z; else CLR_Z; break; + case 6: if (CC6) SET_Z; else CLR_Z; break; + case 7: if (CC7) SET_Z; else CLR_Z; break; + case 8: if (CC8) SET_Z; else CLR_Z; break; + case 9: if (CC9) SET_Z; else CLR_Z; break; + case 10: if (CCA) SET_Z; else CLR_Z; break; + case 11: if (CCB) SET_Z; else CLR_Z; break; + case 12: if (CCC) SET_Z; else CLR_Z; break; + case 13: if (CCD) SET_Z; else CLR_Z; break; + case 14: if (CCE) SET_Z; else CLR_Z; break; + case 15: if (CCF) SET_Z; else CLR_Z; break; + } + sub_from_addr_reg(src, 1); + if (--RW(cnt)) { CLR_V; if (!(m_fcw & F_Z)) m_pc -= 4; } else SET_V; +} + +/****************************************** + cpsdrb @rd,@rs,rr,cc + flags: CZSV-- + ******************************************/ +void z8002_device::ZBA_ssN0_1110_0000_rrrr_ddN0_cccc() +{ + GET_SRC(OP0,NIB2); + GET_CCC(OP1,NIB3); + GET_DST(OP1,NIB2); + GET_CNT(OP1,NIB1); + CPB(RDMEM_B(AS_DATA, addr_from_reg(dst)), RDMEM_B(AS_DATA, addr_from_reg(src))); + switch (cc) { + case 0: if (CC0) SET_Z; else CLR_Z; break; + case 1: if (CC1) SET_Z; else CLR_Z; break; + case 2: if (CC2) SET_Z; else CLR_Z; break; + case 3: if (CC3) SET_Z; else CLR_Z; break; + case 4: if (CC4) SET_Z; else CLR_Z; break; + case 5: if (CC5) SET_Z; else CLR_Z; break; + case 6: if (CC6) SET_Z; else CLR_Z; break; + case 7: if (CC7) SET_Z; else CLR_Z; break; + case 8: if (CC8) SET_Z; else CLR_Z; break; + case 9: if (CC9) SET_Z; else CLR_Z; break; + case 10: if (CCA) SET_Z; else CLR_Z; break; + case 11: if (CCB) SET_Z; else CLR_Z; break; + case 12: if (CCC) SET_Z; else CLR_Z; break; + case 13: if (CCD) SET_Z; else CLR_Z; break; + case 14: if (CCE) SET_Z; else CLR_Z; break; + case 15: if (CCF) SET_Z; else CLR_Z; break; + } + sub_from_addr_reg(src, 1); + sub_from_addr_reg(dst, 1); + if (--RW(cnt)) { CLR_V; if (!(m_fcw & F_Z)) m_pc -= 4; } else SET_V; +} + +/****************************************** + cpi rd,@rs,rr,cc + flags: CZSV-- + ******************************************/ +void z8002_device::ZBB_ssN0_0000_0000_rrrr_dddd_cccc() +{ + GET_SRC(OP0,NIB2); + GET_CCC(OP1,NIB3); + GET_DST(OP1,NIB2); + GET_CNT(OP1,NIB1); + CPW(RW(dst), RDMEM_W(AS_DATA, addr_from_reg(src))); + switch (cc) { + case 0: if (CC0) SET_Z; else CLR_Z; break; + case 1: if (CC1) SET_Z; else CLR_Z; break; + case 2: if (CC2) SET_Z; else CLR_Z; break; + case 3: if (CC3) SET_Z; else CLR_Z; break; + case 4: if (CC4) SET_Z; else CLR_Z; break; + case 5: if (CC5) SET_Z; else CLR_Z; break; + case 6: if (CC6) SET_Z; else CLR_Z; break; + case 7: if (CC7) SET_Z; else CLR_Z; break; + case 8: if (CC8) SET_Z; else CLR_Z; break; + case 9: if (CC9) SET_Z; else CLR_Z; break; + case 10: if (CCA) SET_Z; else CLR_Z; break; + case 11: if (CCB) SET_Z; else CLR_Z; break; + case 12: if (CCC) SET_Z; else CLR_Z; break; + case 13: if (CCD) SET_Z; else CLR_Z; break; + case 14: if (CCE) SET_Z; else CLR_Z; break; + case 15: if (CCF) SET_Z; else CLR_Z; break; + } + add_to_addr_reg(src, 2); + if (--RW(cnt)) CLR_V; else SET_V; +} + +/****************************************** + ldi @rd,@rs,rr + ldir @rd,@rs,rr + flags: ---V-- + ******************************************/ +void z8002_device::ZBB_ssN0_0001_0000_rrrr_ddN0_x000() +{ + GET_SRC(OP0,NIB2); + GET_CNT(OP1,NIB1); + GET_DST(OP1,NIB2); + GET_CCC(OP1,NIB3); + WRMEM_W(AS_DATA, addr_from_reg(dst), RDMEM_W(AS_DATA, addr_from_reg(src))); + add_to_addr_reg(src, 2); + add_to_addr_reg(dst, 2); + if (--RW(cnt)) { CLR_V; if (cc == 0) m_pc -= 4; } else SET_V; +} + +/****************************************** + cpsi @rd,@rs,rr,cc + flags: CZSV-- + ******************************************/ +void z8002_device::ZBB_ssN0_0010_0000_rrrr_ddN0_cccc() +{ + GET_SRC(OP0,NIB2); + GET_CCC(OP1,NIB3); + GET_DST(OP1,NIB2); + GET_CNT(OP1,NIB1); + CPW(RDMEM_W(AS_DATA, addr_from_reg(dst)), RDMEM_W(AS_DATA, addr_from_reg(src))); + switch (cc) { + case 0: if (CC0) SET_Z; else CLR_Z; break; + case 1: if (CC1) SET_Z; else CLR_Z; break; + case 2: if (CC2) SET_Z; else CLR_Z; break; + case 3: if (CC3) SET_Z; else CLR_Z; break; + case 4: if (CC4) SET_Z; else CLR_Z; break; + case 5: if (CC5) SET_Z; else CLR_Z; break; + case 6: if (CC6) SET_Z; else CLR_Z; break; + case 7: if (CC7) SET_Z; else CLR_Z; break; + case 8: if (CC8) SET_Z; else CLR_Z; break; + case 9: if (CC9) SET_Z; else CLR_Z; break; + case 10: if (CCA) SET_Z; else CLR_Z; break; + case 11: if (CCB) SET_Z; else CLR_Z; break; + case 12: if (CCC) SET_Z; else CLR_Z; break; + case 13: if (CCD) SET_Z; else CLR_Z; break; + case 14: if (CCE) SET_Z; else CLR_Z; break; + case 15: if (CCF) SET_Z; else CLR_Z; break; + } + add_to_addr_reg(src, 2); + add_to_addr_reg(dst, 2); + if (--RW(cnt)) CLR_V; else SET_V; +} + +/****************************************** + cpir rd,@rs,rr,cc + flags: CZSV-- + ******************************************/ +void z8002_device::ZBB_ssN0_0100_0000_rrrr_dddd_cccc() +{ + GET_SRC(OP0,NIB2); + GET_CCC(OP1,NIB3); + GET_DST(OP1,NIB2); + GET_CNT(OP1,NIB1); + CPW(RW(dst), RDMEM_W(AS_DATA, addr_from_reg(src))); + switch (cc) { + case 0: if (CC0) SET_Z; else CLR_Z; break; + case 1: if (CC1) SET_Z; else CLR_Z; break; + case 2: if (CC2) SET_Z; else CLR_Z; break; + case 3: if (CC3) SET_Z; else CLR_Z; break; + case 4: if (CC4) SET_Z; else CLR_Z; break; + case 5: if (CC5) SET_Z; else CLR_Z; break; + case 6: if (CC6) SET_Z; else CLR_Z; break; + case 7: if (CC7) SET_Z; else CLR_Z; break; + case 8: if (CC8) SET_Z; else CLR_Z; break; + case 9: if (CC9) SET_Z; else CLR_Z; break; + case 10: if (CCA) SET_Z; else CLR_Z; break; + case 11: if (CCB) SET_Z; else CLR_Z; break; + case 12: if (CCC) SET_Z; else CLR_Z; break; + case 13: if (CCD) SET_Z; else CLR_Z; break; + case 14: if (CCE) SET_Z; else CLR_Z; break; + case 15: if (CCF) SET_Z; else CLR_Z; break; + } + add_to_addr_reg(src, 2); + if (--RW(cnt)) { CLR_V; if (!(m_fcw & F_Z)) m_pc -= 4; } else SET_V; +} + +/****************************************** + cpsir @rd,@rs,rr,cc + flags: CZSV-- + ******************************************/ +void z8002_device::ZBB_ssN0_0110_0000_rrrr_ddN0_cccc() +{ + GET_SRC(OP0,NIB2); + GET_CCC(OP1,NIB3); + GET_DST(OP1,NIB2); + GET_CNT(OP1,NIB1); + CPW(RDMEM_W(AS_DATA, addr_from_reg(dst)), RDMEM_W(AS_DATA, addr_from_reg(src))); + switch (cc) { + case 0: if (CC0) SET_Z; else CLR_Z; break; + case 1: if (CC1) SET_Z; else CLR_Z; break; + case 2: if (CC2) SET_Z; else CLR_Z; break; + case 3: if (CC3) SET_Z; else CLR_Z; break; + case 4: if (CC4) SET_Z; else CLR_Z; break; + case 5: if (CC5) SET_Z; else CLR_Z; break; + case 6: if (CC6) SET_Z; else CLR_Z; break; + case 7: if (CC7) SET_Z; else CLR_Z; break; + case 8: if (CC8) SET_Z; else CLR_Z; break; + case 9: if (CC9) SET_Z; else CLR_Z; break; + case 10: if (CCA) SET_Z; else CLR_Z; break; + case 11: if (CCB) SET_Z; else CLR_Z; break; + case 12: if (CCC) SET_Z; else CLR_Z; break; + case 13: if (CCD) SET_Z; else CLR_Z; break; + case 14: if (CCE) SET_Z; else CLR_Z; break; + case 15: if (CCF) SET_Z; else CLR_Z; break; + } + add_to_addr_reg(src, 2); + add_to_addr_reg(dst, 2); + if (--RW(cnt)) { CLR_V; if (!(m_fcw & F_Z)) m_pc -= 4; } else SET_V; +} + +/****************************************** + cpd rd,@rs,rr,cc + flags: CZSV-- + ******************************************/ +void z8002_device::ZBB_ssN0_1000_0000_rrrr_dddd_cccc() +{ + GET_SRC(OP0,NIB2); + GET_CCC(OP1,NIB3); + GET_DST(OP1,NIB2); + GET_CNT(OP1,NIB1); + CPW(RW(dst), RDMEM_W(AS_DATA, addr_from_reg(src))); + switch (cc) { + case 0: if (CC0) SET_Z; else CLR_Z; break; + case 1: if (CC1) SET_Z; else CLR_Z; break; + case 2: if (CC2) SET_Z; else CLR_Z; break; + case 3: if (CC3) SET_Z; else CLR_Z; break; + case 4: if (CC4) SET_Z; else CLR_Z; break; + case 5: if (CC5) SET_Z; else CLR_Z; break; + case 6: if (CC6) SET_Z; else CLR_Z; break; + case 7: if (CC7) SET_Z; else CLR_Z; break; + case 8: if (CC8) SET_Z; else CLR_Z; break; + case 9: if (CC9) SET_Z; else CLR_Z; break; + case 10: if (CCA) SET_Z; else CLR_Z; break; + case 11: if (CCB) SET_Z; else CLR_Z; break; + case 12: if (CCC) SET_Z; else CLR_Z; break; + case 13: if (CCD) SET_Z; else CLR_Z; break; + case 14: if (CCE) SET_Z; else CLR_Z; break; + case 15: if (CCF) SET_Z; else CLR_Z; break; + } + sub_from_addr_reg(src, 2); + if (--RW(cnt)) CLR_V; else SET_V; +} + +/****************************************** + ldd @rs,@rd,rr + lddr @rs,@rd,rr + flags: ---V-- + ******************************************/ +void z8002_device::ZBB_ssN0_1001_0000_rrrr_ddN0_x000() +{ + GET_SRC(OP0,NIB2); + GET_CNT(OP1,NIB1); + GET_DST(OP1,NIB2); + GET_CCC(OP1,NIB3); + WRMEM_W(AS_DATA, addr_from_reg(dst), RDMEM_W(AS_DATA, addr_from_reg(src))); + sub_from_addr_reg(src, 2); + sub_from_addr_reg(dst, 2); + if (--RW(cnt)) { CLR_V; if (cc == 0) m_pc -= 4; } else SET_V; +} + +/****************************************** + cpsd @rd,@rs,rr,cc + flags: CZSV-- + ******************************************/ +void z8002_device::ZBB_ssN0_1010_0000_rrrr_ddN0_cccc() +{ + GET_SRC(OP0,NIB2); + GET_CCC(OP1,NIB3); + GET_DST(OP1,NIB2); + GET_CNT(OP1,NIB1); + CPW(RDMEM_W(AS_DATA, addr_from_reg(dst)), RDMEM_W(AS_DATA, addr_from_reg(src))); + switch (cc) { + case 0: if (CC0) SET_Z; else CLR_Z; break; + case 1: if (CC1) SET_Z; else CLR_Z; break; + case 2: if (CC2) SET_Z; else CLR_Z; break; + case 3: if (CC3) SET_Z; else CLR_Z; break; + case 4: if (CC4) SET_Z; else CLR_Z; break; + case 5: if (CC5) SET_Z; else CLR_Z; break; + case 6: if (CC6) SET_Z; else CLR_Z; break; + case 7: if (CC7) SET_Z; else CLR_Z; break; + case 8: if (CC8) SET_Z; else CLR_Z; break; + case 9: if (CC9) SET_Z; else CLR_Z; break; + case 10: if (CCA) SET_Z; else CLR_Z; break; + case 11: if (CCB) SET_Z; else CLR_Z; break; + case 12: if (CCC) SET_Z; else CLR_Z; break; + case 13: if (CCD) SET_Z; else CLR_Z; break; + case 14: if (CCE) SET_Z; else CLR_Z; break; + case 15: if (CCF) SET_Z; else CLR_Z; break; + } + sub_from_addr_reg(src, 2); + sub_from_addr_reg(dst, 2); + if (--RW(cnt)) CLR_V; else SET_V; +} + +/****************************************** + cpdr rd,@rs,rr,cc + flags: CZSV-- + ******************************************/ +void z8002_device::ZBB_ssN0_1100_0000_rrrr_dddd_cccc() +{ + GET_SRC(OP0,NIB2); + GET_CCC(OP1,NIB3); + GET_DST(OP1,NIB2); + GET_CNT(OP1,NIB1); + CPW(RW(dst), RDMEM_W(AS_DATA, addr_from_reg(src))); + switch (cc) { + case 0: if (CC0) SET_Z; else CLR_Z; break; + case 1: if (CC1) SET_Z; else CLR_Z; break; + case 2: if (CC2) SET_Z; else CLR_Z; break; + case 3: if (CC3) SET_Z; else CLR_Z; break; + case 4: if (CC4) SET_Z; else CLR_Z; break; + case 5: if (CC5) SET_Z; else CLR_Z; break; + case 6: if (CC6) SET_Z; else CLR_Z; break; + case 7: if (CC7) SET_Z; else CLR_Z; break; + case 8: if (CC8) SET_Z; else CLR_Z; break; + case 9: if (CC9) SET_Z; else CLR_Z; break; + case 10: if (CCA) SET_Z; else CLR_Z; break; + case 11: if (CCB) SET_Z; else CLR_Z; break; + case 12: if (CCC) SET_Z; else CLR_Z; break; + case 13: if (CCD) SET_Z; else CLR_Z; break; + case 14: if (CCE) SET_Z; else CLR_Z; break; + case 15: if (CCF) SET_Z; else CLR_Z; break; + } + sub_from_addr_reg(src, 2); + if (--RW(cnt)) { CLR_V; if (!(m_fcw & F_Z)) m_pc -= 4; } else SET_V; +} + +/****************************************** + cpsdr @rd,@rs,rr,cc + flags: CZSV-- + ******************************************/ +void z8002_device::ZBB_ssN0_1110_0000_rrrr_ddN0_cccc() +{ + GET_SRC(OP0,NIB2); + GET_CCC(OP1,NIB3); + GET_DST(OP1,NIB2); + GET_CNT(OP1,NIB1); + CPW(RDMEM_W(AS_DATA, addr_from_reg(dst)), RDMEM_W(AS_DATA, addr_from_reg(src))); + switch (cc) { + case 0: if (CC0) SET_Z; else CLR_Z; break; + case 1: if (CC1) SET_Z; else CLR_Z; break; + case 2: if (CC2) SET_Z; else CLR_Z; break; + case 3: if (CC3) SET_Z; else CLR_Z; break; + case 4: if (CC4) SET_Z; else CLR_Z; break; + case 5: if (CC5) SET_Z; else CLR_Z; break; + case 6: if (CC6) SET_Z; else CLR_Z; break; + case 7: if (CC7) SET_Z; else CLR_Z; break; + case 8: if (CC8) SET_Z; else CLR_Z; break; + case 9: if (CC9) SET_Z; else CLR_Z; break; + case 10: if (CCA) SET_Z; else CLR_Z; break; + case 11: if (CCB) SET_Z; else CLR_Z; break; + case 12: if (CCC) SET_Z; else CLR_Z; break; + case 13: if (CCD) SET_Z; else CLR_Z; break; + case 14: if (CCE) SET_Z; else CLR_Z; break; + case 15: if (CCF) SET_Z; else CLR_Z; break; + } + sub_from_addr_reg(src, 2); + sub_from_addr_reg(dst, 2); + if (--RW(cnt)) { CLR_V; if (!(m_fcw & F_Z)) m_pc -= 4; } else SET_V; +} + +/****************************************** + rrdb rbb,rba + flags: -Z---- + ******************************************/ +void z8002_device::ZBC_aaaa_bbbb() +{ + UINT8 b = m_op[0] & 15; + UINT8 a = (m_op[0] >> 4) & 15; + UINT8 tmp = RB(b); + RB(a) = (RB(a) >> 4) | (RB(b) << 4); + RB(b) = (RB(b) & 0xf0) | (tmp & 0x0f); + if (RB(b)) CLR_Z; else SET_Z; +} + +/****************************************** + ldk rd,imm4 + flags: ------ + ******************************************/ +void z8002_device::ZBD_dddd_imm4() +{ + GET_DST(OP0,NIB2); + GET_IMM4(OP0,NIB3); + RW(dst) = imm4; +} + +/****************************************** + rldb rbb,rba + flags: -Z---- + ******************************************/ +void z8002_device::ZBE_aaaa_bbbb() +{ + UINT8 b = m_op[0] & 15; + UINT8 a = (m_op[0] >> 4) & 15; + UINT8 tmp = RB(a); + RB(a) = (RB(a) << 4) | (RB(b) & 0x0f); + RB(b) = (RB(b) & 0xf0) | (tmp >> 4); + if (RB(b)) CLR_Z; else SET_Z; +} + +/****************************************** + rsvdbf + flags: ------ + ******************************************/ +void z8002_device::ZBF_imm8() +{ + GET_IMM8(0); + LOG(("Z8K '%s' %04x: rsvdbf $%02x\n", tag(), m_pc, imm8)); + if (m_fcw & F_EPU) { + /* Z8001 EPU code goes here */ + (void)imm8; + } + (void)imm8; +} + +/****************************************** + ldb rbd,imm8 (long version) + flags: ------ + ******************************************/ +void z8002_device::Z20_0000_dddd_imm8() +{ + GET_DST(OP0,NIB3); + GET_IMM8(OP1); + RB(dst) = imm8; +} + +/****************************************** + ldb rbd,imm8 + flags: ------ + ******************************************/ +void z8002_device::ZC_dddd_imm8() +{ + GET_DST(OP0,NIB1); + GET_IMM8(0); + RB(dst) = imm8; +} + +/****************************************** + calr dsp12 + flags: ------ + ******************************************/ +void z8002_device::ZD_dsp12() +{ + INT16 dsp12 = m_op[0] & 0xfff; + if (segmented_mode()) + PUSHL(SP, make_segmented_addr(m_pc)); + else + PUSHW(SP, m_pc); + dsp12 = (dsp12 & 2048) ? 4096 - 2 * (dsp12 & 2047) : -2 * (dsp12 & 2047); + set_pc(addr_add(m_pc, dsp12)); +} + +/****************************************** + jr cc,dsp8 + flags: ------ + ******************************************/ +void z8002_device::ZE_cccc_dsp8() +{ + GET_DSP8; + GET_CCC(OP0,NIB1); + switch (cc) { + case 0: if (CC0) set_pc(addr_add(m_pc, dsp8 * 2)); break; + case 1: if (CC1) set_pc(addr_add(m_pc, dsp8 * 2)); break; + case 2: if (CC2) set_pc(addr_add(m_pc, dsp8 * 2)); break; + case 3: if (CC3) set_pc(addr_add(m_pc, dsp8 * 2)); break; + case 4: if (CC4) set_pc(addr_add(m_pc, dsp8 * 2)); break; + case 5: if (CC5) set_pc(addr_add(m_pc, dsp8 * 2)); break; + case 6: if (CC6) set_pc(addr_add(m_pc, dsp8 * 2)); break; + case 7: if (CC7) set_pc(addr_add(m_pc, dsp8 * 2)); break; + case 8: if (CC8) set_pc(addr_add(m_pc, dsp8 * 2)); break; + case 9: if (CC9) set_pc(addr_add(m_pc, dsp8 * 2)); break; + case 10: if (CCA) set_pc(addr_add(m_pc, dsp8 * 2)); break; + case 11: if (CCB) set_pc(addr_add(m_pc, dsp8 * 2)); break; + case 12: if (CCC) set_pc(addr_add(m_pc, dsp8 * 2)); break; + case 13: if (CCD) set_pc(addr_add(m_pc, dsp8 * 2)); break; + case 14: if (CCE) set_pc(addr_add(m_pc, dsp8 * 2)); break; + case 15: if (CCF) set_pc(addr_add(m_pc, dsp8 * 2)); break; + } +} + +/****************************************** + dbjnz rbd,dsp7 + flags: ------ + ******************************************/ +void z8002_device::ZF_dddd_0dsp7() +{ + GET_DST(OP0,NIB1); + GET_DSP7; + RB(dst) -= 1; + if (RB(dst)) { + set_pc(addr_sub(m_pc, 2 * dsp7)); + } +} + +/****************************************** + djnz rd,dsp7 + flags: ------ + ******************************************/ +void z8002_device::ZF_dddd_1dsp7() +{ + GET_DST(OP0,NIB1); + GET_DSP7; + RW(dst) -= 1; + if (RW(dst)) { + set_pc(addr_sub(m_pc, 2 * dsp7)); + } +} diff --git a/src/devices/cpu/z8000/z8000tbl.inc b/src/devices/cpu/z8000/z8000tbl.inc new file mode 100644 index 00000000000..e4959706858 --- /dev/null +++ b/src/devices/cpu/z8000/z8000tbl.inc @@ -0,0 +1,579 @@ +// license:BSD-3-Clause +// copyright-holders:Juergen Buchmueller,Ernesto Corvi +/***************************************************************************** + * + * z8000tbl.inc + * Portable Z8000(2) emulator + * Opcode table (including mnemonics) and initialization + * + *****************************************************************************/ + +static const Z8000_init table[] = { +{0x0000,0x000f, 1,2, 7,&z8002_device::Z00_0000_dddd_imm8, "addb %rb3,%#b3", 0}, +{0x0010,0x00ff, 1,1, 7,&z8002_device::Z00_ssN0_dddd, "addb %rb3,@%rw2", 0}, +{0x0100,0x010f, 1,2, 7,&z8002_device::Z01_0000_dddd_imm16, "add %rw3,%#w1", 0}, +{0x0110,0x01ff, 1,1, 7,&z8002_device::Z01_ssN0_dddd, "add %rw3,@%rw2", 0}, +{0x0200,0x020f, 1,2, 7,&z8002_device::Z02_0000_dddd_imm8, "subb %rb3,%#b3", 0}, +{0x0210,0x02ff, 1,1, 7,&z8002_device::Z02_ssN0_dddd, "subb %rb3,@%rw2", 0}, +{0x0300,0x030f, 1,2, 7,&z8002_device::Z03_0000_dddd_imm16, "sub %rw3,%#w1", 0}, +{0x0310,0x03ff, 1,1, 7,&z8002_device::Z03_ssN0_dddd, "sub %rw3,@%rw2", 0}, +{0x0400,0x040f, 1,2, 7,&z8002_device::Z04_0000_dddd_imm8, "orb %rb3,%#b3", 0}, +{0x0410,0x04ff, 1,1, 7,&z8002_device::Z04_ssN0_dddd, "orb %rb3,@%rw2", 0}, +{0x0500,0x050f, 1,2, 7,&z8002_device::Z05_0000_dddd_imm16, "or %rw3,%#w1", 0}, +{0x0510,0x05ff, 1,1, 7,&z8002_device::Z05_ssN0_dddd, "or %rw3,@%rw2", 0}, +{0x0600,0x060f, 1,2, 7,&z8002_device::Z06_0000_dddd_imm8, "andb %rb3,%#b3", 0}, +{0x0610,0x06ff, 1,1, 7,&z8002_device::Z06_ssN0_dddd, "andb %rb3,@%rw2", 0}, +{0x0700,0x070f, 1,2, 7,&z8002_device::Z07_0000_dddd_imm16, "and %rw3,%#w1", 0}, +{0x0710,0x07ff, 1,1, 7,&z8002_device::Z07_ssN0_dddd, "and %rw3,@%rw2", 0}, +{0x0800,0x080f, 1,2, 7,&z8002_device::Z08_0000_dddd_imm8, "xorb %rb3,%#b3", 0}, +{0x0810,0x08ff, 1,1, 7,&z8002_device::Z08_ssN0_dddd, "xorb %rb3,@%rw2", 0}, +{0x0900,0x090f, 1,2, 7,&z8002_device::Z09_0000_dddd_imm16, "xor %rw3,%#w1", 0}, +{0x0910,0x09ff, 1,1, 7,&z8002_device::Z09_ssN0_dddd, "xor %rw3,@%rw2", 0}, +{0x0a00,0x0a0f, 1,2, 7,&z8002_device::Z0A_0000_dddd_imm8, "cpb %rb3,%#b3", 0}, +{0x0a10,0x0aff, 1,1, 7,&z8002_device::Z0A_ssN0_dddd, "cpb %rb3,@%rw2", 0}, +{0x0b00,0x0b0f, 1,2, 7,&z8002_device::Z0B_0000_dddd_imm16, "cp %rw3,%#w1", 0}, +{0x0b10,0x0bff, 1,1, 7,&z8002_device::Z0B_ssN0_dddd, "cp %rw3,@%rw2", 0}, +{0x0c10,0x0cf0,16,1, 12,&z8002_device::Z0C_ddN0_0000, "comb @%rw2", 0}, +{0x0c11,0x0cf1,16,2, 11,&z8002_device::Z0C_ddN0_0001_imm8, "cpb @%rw2,%#b3", 0}, +{0x0c12,0x0cf2,16,1, 12,&z8002_device::Z0C_ddN0_0010, "negb @%rw2", 0}, +{0x0c14,0x0cf4,16,1, 8,&z8002_device::Z0C_ddN0_0100, "testb @%rw2", 0}, +{0x0c15,0x0cf5,16,2, 7,&z8002_device::Z0C_ddN0_0101_imm8, "ldb @%rw2,%#b3", 0}, +{0x0c16,0x0cf6,16,1, 11,&z8002_device::Z0C_ddN0_0110, "tsetb @%rw2", 0}, +{0x0c18,0x0cf8,16,1, 8,&z8002_device::Z0C_ddN0_1000, "clrb @%rw2", 0}, +{0x0d10,0x0df0,16,1, 12,&z8002_device::Z0D_ddN0_0000, "com @%rw2", 0}, +{0x0d11,0x0df1,16,2, 11,&z8002_device::Z0D_ddN0_0001_imm16, "cp @%rw2,%#w1", 0}, +{0x0d12,0x0df2,16,1, 12,&z8002_device::Z0D_ddN0_0010, "neg @%rw2", 0}, +{0x0d14,0x0df4,16,1, 8,&z8002_device::Z0D_ddN0_0100, "test @%rw2", 0}, +{0x0d15,0x0df5,16,2, 11,&z8002_device::Z0D_ddN0_0101_imm16, "ld @%rw2,%#w1", 0}, /* fix cycles ld IR,IM */ +{0x0d16,0x0df6,16,1, 11,&z8002_device::Z0D_ddN0_0110, "tset @%rw2", 0}, +{0x0d18,0x0df8,16,1, 8,&z8002_device::Z0D_ddN0_1000, "clr @%rw2", 0}, +{0x0d19,0x0df9,16,2, 12,&z8002_device::Z0D_ddN0_1001_imm16, "push @%rw2,%#w1", 0}, +{0x0e00,0x0eff, 1,1, 10,&z8002_device::Z0E_imm8, "ext0e %#b1", 0}, +{0x0f00,0x0fff, 1,1, 10,&z8002_device::Z0F_imm8, "ext0f %#b1", 0}, +{0x1000,0x100f, 1,3, 14,&z8002_device::Z10_0000_dddd_imm32, "cpl %rl3,%#l1", 0}, +{0x1010,0x10ff, 1,1, 14,&z8002_device::Z10_ssN0_dddd, "cpl %rl3,@%rw2", 0}, +{0x1111,0x11ff, 1,1, 20,&z8002_device::Z11_ddN0_ssN0, "pushl @%rw2,@%rw3", 0}, +{0x1200,0x120f, 1,3, 14,&z8002_device::Z12_0000_dddd_imm32, "subl %rl3,%#l1", 0}, +{0x1210,0x12ff, 1,1, 14,&z8002_device::Z12_ssN0_dddd, "subl %rl3,@%rw2", 0}, +{0x1311,0x13ff, 1,1, 13,&z8002_device::Z13_ddN0_ssN0, "push @%rw2,@%rw3", 0}, +{0x1400,0x140f, 1,3, 11,&z8002_device::Z14_0000_dddd_imm32, "ldl %rl3,%#l1", 0}, +{0x1410,0x14ff, 1,1, 11,&z8002_device::Z14_ssN0_dddd, "ldl %rl3,@%rw2", 0}, +{0x1511,0x15ff, 1,1, 19,&z8002_device::Z15_ssN0_ddN0, "popl @%rw3,@%rw2", 0}, +{0x1600,0x160f, 1,3, 14,&z8002_device::Z16_0000_dddd_imm32, "addl %rl3,%#l1", 0}, +{0x1610,0x16ff, 1,1, 14,&z8002_device::Z16_ssN0_dddd, "addl %rl3,@%rw2", 0}, +{0x1711,0x17ff, 1,1, 12,&z8002_device::Z17_ssN0_ddN0, "pop @%rw3,@%rw2", 0}, +{0x1800,0x180f, 1,1,282,&z8002_device::Z18_00N0_dddd_imm32, "multl %rq3,@%l#1", 0}, +{0x1810,0x18ff, 1,1,282,&z8002_device::Z18_ssN0_dddd, "multl %rq3,@%rw2", 0}, +{0x1900,0x190f, 1,2, 70,&z8002_device::Z19_0000_dddd_imm16, "mult %rl3,%#w1", 0}, +{0x1910,0x19ff, 1,1, 70,&z8002_device::Z19_ssN0_dddd, "mult %rl3,@%rw2", 0}, +{0x1a00,0x1a0f, 1,3,744,&z8002_device::Z1A_0000_dddd_imm32, "divl %rq3,%#l1", 0}, +{0x1a10,0x1aff, 1,1,744,&z8002_device::Z1A_ssN0_dddd, "divl %rq3,@%rw2", 0}, +{0x1b00,0x1b0f, 1,2,107,&z8002_device::Z1B_0000_dddd_imm16, "div %rl3,%#w1", 0}, +{0x1b10,0x1bff, 1,1,107,&z8002_device::Z1B_ssN0_dddd, "div %rl3,@%rw2", 0}, +{0x1c11,0x1cf1,16,2, 11,&z8002_device::Z1C_ssN0_0001_0000_dddd_0000_nmin1, "ldm %rw5,@%rw2,#%n", 0}, +{0x1c18,0x1cf8,16,1, 13,&z8002_device::Z1C_ddN0_1000, "testl @%rw2", 0}, +{0x1c19,0x1cf9,16,2, 11,&z8002_device::Z1C_ddN0_1001_0000_ssss_0000_nmin1, "ldm @%rw2,%rw5,#%n", 0}, +{0x1d10,0x1dff, 1,1, 11,&z8002_device::Z1D_ddN0_ssss, "ldl @%rw2,%rl3", 0}, +{0x1e10,0x1eff, 1,1, 10,&z8002_device::Z1E_ddN0_cccc, "jp %c3,@%rl2", 0}, +{0x1f10,0x1ff0,16,1, 10,&z8002_device::Z1F_ddN0_0000, "call %rw2", DASMFLAG_STEP_OVER}, +{0x2000,0x200f, 1,2, 7,&z8002_device::Z20_0000_dddd_imm8, "ldb %rb3,%#b3", 0}, +{0x2010,0x20ff, 1,1, 7,&z8002_device::Z20_ssN0_dddd, "ldb %rb3,@%rw2", 0}, +{0x2100,0x210f, 1,2, 7,&z8002_device::Z21_0000_dddd_imm16, "ld %rw3,%#w1", 0}, +{0x2110,0x21ff, 1,1, 7,&z8002_device::Z21_ssN0_dddd, "ld %rw3,@%rw2", 0}, +{0x2200,0x220f, 1,2, 10,&z8002_device::Z22_0000_ssss_0000_dddd_0000_0000, "resb %rb5,%rw3", 0}, +{0x2210,0x22ff, 1,1, 11,&z8002_device::Z22_ddN0_imm4, "resb @%rw3,%3", 0}, +{0x2300,0x230f, 1,2, 10,&z8002_device::Z23_0000_ssss_0000_dddd_0000_0000, "res %rw5,%rw3", 0}, +{0x2310,0x23ff, 1,1, 11,&z8002_device::Z23_ddN0_imm4, "res @%rw3,%3", 0}, +{0x2400,0x240f, 1,2, 10,&z8002_device::Z24_0000_ssss_0000_dddd_0000_0000, "setb %rb5,%rw3", 0}, +{0x2410,0x24ff, 1,1, 11,&z8002_device::Z24_ddN0_imm4, "setb @%rw3,%3", 0}, +{0x2500,0x250f, 1,2, 10,&z8002_device::Z25_0000_ssss_0000_dddd_0000_0000, "set %rw5,%rw3", 0}, +{0x2510,0x25ff, 1,1, 11,&z8002_device::Z25_ddN0_imm4, "set @%rw3,%3", 0}, +{0x2600,0x260f, 1,2, 10,&z8002_device::Z26_0000_ssss_0000_dddd_0000_0000, "bitb %rb5,%rw3", 0}, +{0x2610,0x26ff, 1,1, 8,&z8002_device::Z26_ddN0_imm4, "bitb @%rw3,%3", 0}, +{0x2700,0x270f, 1,2, 10,&z8002_device::Z27_0000_ssss_0000_dddd_0000_0000, "bit %rw5,%rw3", 0}, +{0x2710,0x27ff, 1,1, 8,&z8002_device::Z27_ddN0_imm4, "bit @%rw2,%3", 0}, +{0x2810,0x28ff, 1,1, 11,&z8002_device::Z28_ddN0_imm4m1, "incb @%rw2,%+3", 0}, +{0x2910,0x29ff, 1,1, 11,&z8002_device::Z29_ddN0_imm4m1, "inc @%rw2,%+3", 0}, +{0x2a10,0x2aff, 1,1, 11,&z8002_device::Z2A_ddN0_imm4m1, "decb @%rw2,%+3", 0}, +{0x2b10,0x2bff, 1,1, 11,&z8002_device::Z2B_ddN0_imm4m1, "dec @%rw2,%+3", 0}, +{0x2c10,0x2cff, 1,1, 12,&z8002_device::Z2C_ssN0_dddd, "exb %rb3,@%rw2", 0}, +{0x2d10,0x2dff, 1,1, 12,&z8002_device::Z2D_ssN0_dddd, "ex %rw3,@%rw2", 0}, +{0x2e10,0x2eff, 1,1, 8,&z8002_device::Z2E_ddN0_ssss, "ldb @%rw2,%rb3", 0}, +{0x2f10,0x2fff, 1,1, 8,&z8002_device::Z2F_ddN0_ssss, "ld @%rw2,%rw3", 0}, +{0x3000,0x300f, 1,2, 14,&z8002_device::Z30_0000_dddd_dsp16, "ldrb %rb3,%p1", 0}, +{0x3010,0x30ff, 1,2, 14,&z8002_device::Z30_ssN0_dddd_imm16, "ldb %rb3,%rw2(%#w1)", 0}, +{0x3100,0x310f, 1,2, 14,&z8002_device::Z31_0000_dddd_dsp16, "ldr %rw3,%p1", 0}, +{0x3110,0x31ff, 1,2, 14,&z8002_device::Z31_ssN0_dddd_imm16, "ld %rw3,%rw2(%#w1)", 0}, +{0x3200,0x320f, 1,2, 14,&z8002_device::Z32_0000_ssss_dsp16, "ldrb %p1,%rb3", 0}, +{0x3210,0x32ff, 1,2, 14,&z8002_device::Z32_ddN0_ssss_imm16, "ldb %rw2(%#w1),%rb3", 0}, +{0x3300,0x330f, 1,2, 14,&z8002_device::Z33_0000_ssss_dsp16, "ldr %p1,%rw3", 0}, +{0x3310,0x33ff, 1,2, 14,&z8002_device::Z33_ddN0_ssss_imm16, "ld %rw2(%#w1),%rw3", 0}, +{0x3400,0x340f, 1,2, 15,&z8002_device::Z34_0000_dddd_dsp16, "ldar p%rw3,%p1", 0}, +{0x3410,0x34ff, 1,2, 15,&z8002_device::Z34_ssN0_dddd_imm16, "lda p%rw3,%rw2(%#w1)", 0}, +{0x3500,0x350f, 1,2, 17,&z8002_device::Z35_0000_dddd_dsp16, "ldrl %rl3,%p1", 0}, +{0x3510,0x35ff, 1,2, 17,&z8002_device::Z35_ssN0_dddd_imm16, "ldl %rl3,%rw2(%#w1)", 0}, +{0x3600,0x3600, 1,1, 2,&z8002_device::Z36_0000_0000, "bpt", 0}, +{0x3601,0x36ff, 1,1, 10,&z8002_device::Z36_imm8, "rsvd36", 0}, +{0x3700,0x370f, 1,2, 17,&z8002_device::Z37_0000_ssss_dsp16, "ldrl %p1,%rl3", 0}, +{0x3710,0x37ff, 1,2, 17,&z8002_device::Z37_ddN0_ssss_imm16, "ldl %rw2(%#w1),%rl3", 0}, +{0x3800,0x38ff, 1,1, 10,&z8002_device::Z38_imm8, "rsvd38", 0}, +{0x3910,0x39f0,16,1, 12,&z8002_device::Z39_ssN0_0000, "ldps @%rw2", 0}, +{0x3a00,0x3af0,16,2, 21,&z8002_device::Z3A_ssss_0000_0000_aaaa_dddd_x000, "%R @%rw6,@%rw2,%rw5", 0}, +{0x3a01,0x3af1,16,2, 21,&z8002_device::Z3A_ssss_0001_0000_aaaa_dddd_x000, "%R @%rw6,@%rw2,%rw5", 0}, +{0x3a02,0x3af2,16,2, 21,&z8002_device::Z3A_ssss_0010_0000_aaaa_dddd_x000, "%R @%rw6,@%rw2,%rw5", 0}, +{0x3a03,0x3af3,16,2, 21,&z8002_device::Z3A_ssss_0011_0000_aaaa_dddd_x000, "%R @%rw6,@%rw2,%rw5", 0}, +{0x3a04,0x3af4,16,2, 10,&z8002_device::Z3A_dddd_0100_imm16, "%R %rb2,%#w1", 0}, +{0x3a05,0x3af5,16,2, 10,&z8002_device::Z3A_dddd_0101_imm16, "%R %rb2,%#w1", 0}, +{0x3a06,0x3af6,16,2, 12,&z8002_device::Z3A_ssss_0110_imm16, "%R %#w1,%rb2", 0}, +{0x3a07,0x3af7,16,2, 12,&z8002_device::Z3A_ssss_0111_imm16, "%R %#w1,%rb2", 0}, +{0x3a08,0x3af8,16,2, 21,&z8002_device::Z3A_ssss_1000_0000_aaaa_dddd_x000, "%R @%rw6,@%rw2,%rw5", 0}, +{0x3a09,0x3af9,16,2, 21,&z8002_device::Z3A_ssss_1001_0000_aaaa_dddd_x000, "%R @%rw6,@%rw2,%rw5", 0}, +{0x3a0a,0x3afa,16,2, 21,&z8002_device::Z3A_ssss_1010_0000_aaaa_dddd_x000, "%R @%rw6,@%rw2,%rw5", 0}, +{0x3a0b,0x3afb,16,2, 21,&z8002_device::Z3A_ssss_1011_0000_aaaa_dddd_x000, "%R @%rw6,@%rw2,%rw5", 0}, +{0x3b00,0x3bf0,16,2, 21,&z8002_device::Z3B_ssss_0000_0000_aaaa_dddd_x000, "%R @%rw6,@%rw2,%rw5", 0}, +{0x3b01,0x3bf1,16,2, 21,&z8002_device::Z3B_ssss_0001_0000_aaaa_dddd_x000, "%R @%rw6,@%rw2,%rw5", 0}, +{0x3b02,0x3bf2,16,2, 21,&z8002_device::Z3B_ssss_0010_0000_aaaa_dddd_x000, "%R @%rw6,@%rw2,%rw5", 0}, +{0x3b03,0x3bf3,16,2, 21,&z8002_device::Z3B_ssss_0011_0000_aaaa_dddd_x000, "%R @%rw6,@%rw2,%rw5", 0}, +{0x3b04,0x3bf4,16,2, 12,&z8002_device::Z3B_dddd_0100_imm16, "%R %rw2,%#w1", 0}, +{0x3b05,0x3bf5,16,2, 12,&z8002_device::Z3B_dddd_0101_imm16, "%R %rw2,%#w1", 0}, +{0x3b06,0x3bf6,16,2, 12,&z8002_device::Z3B_ssss_0110_imm16, "%R %#w1,%rw2", 0}, +{0x3b07,0x3bf7,16,2, 12,&z8002_device::Z3B_ssss_0111_imm16, "%R %#w1,%rw2", 0}, +{0x3b08,0x3bf8,16,2, 21,&z8002_device::Z3B_ssss_1000_0000_aaaa_dddd_x000, "%R @%rw6,@%rw2,%rw5", 0}, +{0x3b09,0x3bf9,16,2, 21,&z8002_device::Z3B_ssss_1001_0000_aaaa_dddd_x000, "%R @%rw6,@%rw2,%rw5", 0}, +{0x3b0a,0x3bfa,16,2, 21,&z8002_device::Z3B_ssss_1010_0000_aaaa_dddd_x000, "%R @%rw6,@%rw2,%rb5", 0}, +{0x3b0b,0x3bfb,16,2, 21,&z8002_device::Z3B_ssss_1011_0000_aaaa_dddd_x000, "%R @%rw6,@%rw2,%rb5", 0}, +{0x3c00,0x3cff, 1,1, 10,&z8002_device::Z3C_ssss_dddd, "inb %rb3,@%rw2", 0}, +{0x3d00,0x3dff, 1,1, 10,&z8002_device::Z3D_ssss_dddd, "in %rw3,@%rw2", 0}, +{0x3e00,0x3eff, 1,1, 12,&z8002_device::Z3E_dddd_ssss, "outb @%rw2,%rb3", 0}, +{0x3f00,0x3fff, 1,1, 12,&z8002_device::Z3F_dddd_ssss, "out @%rw2,%rw3", 0}, +{0x4000,0x400f, 1,2, 9,&z8002_device::Z40_0000_dddd_addr, "addb %rb3,%a1", 0}, +{0x4010,0x40ff, 1,2, 10,&z8002_device::Z40_ssN0_dddd_addr, "addb %rb3,%a1(%rw2)", 0}, +{0x4100,0x410f, 1,2, 9,&z8002_device::Z41_0000_dddd_addr, "add %rw3,%a1", 0}, +{0x4110,0x41ff, 1,2, 10,&z8002_device::Z41_ssN0_dddd_addr, "add %rw3,%a1(%rw2)", 0}, +{0x4200,0x420f, 1,2, 9,&z8002_device::Z42_0000_dddd_addr, "subb %rb3,%a1", 0}, +{0x4210,0x42ff, 1,2, 10,&z8002_device::Z42_ssN0_dddd_addr, "subb %rb3,%a1(%rw2)", 0}, +{0x4300,0x430f, 1,2, 9,&z8002_device::Z43_0000_dddd_addr, "sub %rw3,%a1", 0}, +{0x4310,0x43ff, 1,2, 10,&z8002_device::Z43_ssN0_dddd_addr, "sub %rw3,%a1(%rw2)", 0}, +{0x4400,0x440f, 1,2, 9,&z8002_device::Z44_0000_dddd_addr, "orb %rb3,%a1", 0}, +{0x4410,0x44ff, 1,2, 10,&z8002_device::Z44_ssN0_dddd_addr, "orb %rb3,%a1(%rw2)", 0}, +{0x4500,0x450f, 1,2, 9,&z8002_device::Z45_0000_dddd_addr, "or %rw3,%a1", 0}, +{0x4510,0x45ff, 1,2, 10,&z8002_device::Z45_ssN0_dddd_addr, "or %rw3,%a1(%rw2)", 0}, +{0x4600,0x460f, 1,2, 9,&z8002_device::Z46_0000_dddd_addr, "andb %rb3,%a1", 0}, +{0x4610,0x46ff, 1,2, 10,&z8002_device::Z46_ssN0_dddd_addr, "andb %rb3,%a1(%rw2)", 0}, +{0x4700,0x470f, 1,2, 9,&z8002_device::Z47_0000_dddd_addr, "and %rw3,%a1", 0}, +{0x4710,0x47ff, 1,2, 10,&z8002_device::Z47_ssN0_dddd_addr, "and %rw3,%a1(%rw2)", 0}, +{0x4800,0x480f, 1,2, 9,&z8002_device::Z48_0000_dddd_addr, "xorb %rb3,%a1", 0}, +{0x4810,0x48ff, 1,2, 10,&z8002_device::Z48_ssN0_dddd_addr, "xorb %rb3,%a1(%rw2)", 0}, +{0x4900,0x490f, 1,2, 9,&z8002_device::Z49_0000_dddd_addr, "xor %rw3,%a1", 0}, +{0x4910,0x49ff, 1,2, 10,&z8002_device::Z49_ssN0_dddd_addr, "xor %rw3,%a1(%rw2)", 0}, +{0x4a00,0x4a0f, 1,2, 9,&z8002_device::Z4A_0000_dddd_addr, "cpb %rb3,%a1", 0}, +{0x4a10,0x4aff, 1,2, 10,&z8002_device::Z4A_ssN0_dddd_addr, "cpb %rb3,%a1(%rw2)", 0}, +{0x4b00,0x4b0f, 1,2, 9,&z8002_device::Z4B_0000_dddd_addr, "cp %rw3,%a1", 0}, +{0x4b10,0x4bff, 1,2, 10,&z8002_device::Z4B_ssN0_dddd_addr, "cp %rw3,%a1(%rw2)", 0}, +{0x4c00,0x4c00, 1,2, 15,&z8002_device::Z4C_0000_0000_addr, "comb %a1", 0}, +{0x4c01,0x4c01, 1,3, 14,&z8002_device::Z4C_0000_0001_addr_imm8, "cpb %a1,%#b3", 0}, +{0x4c02,0x4c02, 1,2, 15,&z8002_device::Z4C_0000_0010_addr, "negb %a1", 0}, +{0x4c04,0x4c04, 1,2, 11,&z8002_device::Z4C_0000_0100_addr, "testb %a1", 0}, +{0x4c05,0x4c05, 1,3, 14,&z8002_device::Z4C_0000_0101_addr_imm8, "ldb %a1,%#b3", 0}, +{0x4c06,0x4c06, 1,2, 14,&z8002_device::Z4C_0000_0110_addr, "tsetb %a1", 0}, +{0x4c08,0x4c08, 1,2, 11,&z8002_device::Z4C_0000_1000_addr, "clrb %a1", 0}, +{0x4c10,0x4cf0,16,2, 16,&z8002_device::Z4C_ddN0_0000_addr, "comb %a1(%rw2)", 0}, +{0x4c11,0x4cf1,16,3, 15,&z8002_device::Z4C_ddN0_0001_addr_imm8, "cpb %a1(%rw2),%#b3", 0}, +{0x4c12,0x4cf2,16,2, 16,&z8002_device::Z4C_ddN0_0010_addr, "negb %a1(%rw2)", 0}, +{0x4c14,0x4cf4,16,2, 12,&z8002_device::Z4C_ddN0_0100_addr, "testb %a1(%rw2)", 0}, +{0x4c15,0x4cf5,16,3, 15,&z8002_device::Z4C_ddN0_0101_addr_imm8, "ldb %a1(%rw2),%#b3", 0}, +{0x4c16,0x4cf6,16,2, 15,&z8002_device::Z4C_ddN0_0110_addr, "tsetb %a1(%rw2)", 0}, +{0x4c18,0x4cf8,16,2, 12,&z8002_device::Z4C_ddN0_1000_addr, "clrb %a1(%rw2)", 0}, +{0x4d00,0x4d00, 1,2, 15,&z8002_device::Z4D_0000_0000_addr, "com %a1", 0}, +{0x4d01,0x4d01, 1,3, 14,&z8002_device::Z4D_0000_0001_addr_imm16, "cp %a1,%#w2", 0}, +{0x4d02,0x4d02, 1,2, 15,&z8002_device::Z4D_0000_0010_addr, "neg %a1", 0}, +{0x4d04,0x4d04, 1,2, 11,&z8002_device::Z4D_0000_0100_addr, "test %a1", 0}, +{0x4d05,0x4d05, 1,3, 14,&z8002_device::Z4D_0000_0101_addr_imm16, "ld %a1,%#w2", 0}, +{0x4d06,0x4d06, 1,2, 14,&z8002_device::Z4D_0000_0110_addr, "tset %a1", 0}, +{0x4d08,0x4d08, 1,2, 11,&z8002_device::Z4D_0000_1000_addr, "clr %a1", 0}, +{0x4d10,0x4df0,16,2, 16,&z8002_device::Z4D_ddN0_0000_addr, "com %a1(%rw2)", 0}, +{0x4d11,0x4df1,16,3, 15,&z8002_device::Z4D_ddN0_0001_addr_imm16, "cp %a1(%rw2),%#w2", 0}, +{0x4d12,0x4df2,16,2, 16,&z8002_device::Z4D_ddN0_0010_addr, "neg %a1(%rw2)", 0}, +{0x4d14,0x4df4,16,2, 12,&z8002_device::Z4D_ddN0_0100_addr, "test %a1(%rw2)", 0}, +{0x4d15,0x4df5,16,3, 15,&z8002_device::Z4D_ddN0_0101_addr_imm16, "ld %a1(%rw2),%#w2", 0}, +{0x4d16,0x4df6,16,2, 15,&z8002_device::Z4D_ddN0_0110_addr, "tset %a1(%rw2)", 0}, +{0x4d18,0x4df8,16,2, 12,&z8002_device::Z4D_ddN0_1000_addr, "clr %a1(%rw2)", 0}, +{0x4e11,0x4ef0,16,2, 12,&z8002_device::Z4E_ddN0_ssN0_addr, "ldb %a1(%rw2),%rb3", 0}, +{0x5000,0x500f, 1,2, 15,&z8002_device::Z50_0000_dddd_addr, "cpl %rl3,%a1", 0}, +{0x5010,0x50ff, 1,2, 16,&z8002_device::Z50_ssN0_dddd_addr, "cpl %rl3,%a1(%rw2)", 0}, +{0x5110,0x51f0,16,2, 21,&z8002_device::Z51_ddN0_0000_addr, "pushl @%rw2,%a1", 0}, +{0x5111,0x51f1,16,2, 21,&z8002_device::Z51_ddN0_ssN0_addr, "pushl @%rw2,%a1(%rw3)", 0}, +{0x5112,0x51f2,16,2, 21,&z8002_device::Z51_ddN0_ssN0_addr, "pushl @%rw2,%a1(%rw3)", 0}, +{0x5113,0x51f3,16,2, 21,&z8002_device::Z51_ddN0_ssN0_addr, "pushl @%rw2,%a1(%rw3)", 0}, +{0x5114,0x51f4,16,2, 21,&z8002_device::Z51_ddN0_ssN0_addr, "pushl @%rw2,%a1(%rw3)", 0}, +{0x5115,0x51f5,16,2, 21,&z8002_device::Z51_ddN0_ssN0_addr, "pushl @%rw2,%a1(%rw3)", 0}, +{0x5116,0x51f6,16,2, 21,&z8002_device::Z51_ddN0_ssN0_addr, "pushl @%rw2,%a1(%rw3)", 0}, +{0x5117,0x51f7,16,2, 21,&z8002_device::Z51_ddN0_ssN0_addr, "pushl @%rw2,%a1(%rw3)", 0}, +{0x5118,0x51f8,16,2, 21,&z8002_device::Z51_ddN0_ssN0_addr, "pushl @%rw2,%a1(%rw3)", 0}, +{0x5119,0x51f9,16,2, 21,&z8002_device::Z51_ddN0_ssN0_addr, "pushl @%rw2,%a1(%rw3)", 0}, +{0x511a,0x51fa,16,2, 21,&z8002_device::Z51_ddN0_ssN0_addr, "pushl @%rw2,%a1(%rw3)", 0}, +{0x511b,0x51fb,16,2, 21,&z8002_device::Z51_ddN0_ssN0_addr, "pushl @%rw2,%a1(%rw3)", 0}, +{0x511c,0x51fc,16,2, 21,&z8002_device::Z51_ddN0_ssN0_addr, "pushl @%rw2,%a1(%rw3)", 0}, +{0x511d,0x51fd,16,2, 21,&z8002_device::Z51_ddN0_ssN0_addr, "pushl @%rw2,%a1(%rw3)", 0}, +{0x511e,0x51fe,16,2, 21,&z8002_device::Z51_ddN0_ssN0_addr, "pushl @%rw2,%a1(%rw3)", 0}, +{0x511f,0x51ff,16,2, 21,&z8002_device::Z51_ddN0_ssN0_addr, "pushl @%rw2,%a1(%rw3)", 0}, +{0x5200,0x520f, 1,2, 15,&z8002_device::Z52_0000_dddd_addr, "subl %rl3,%a1", 0}, +{0x5210,0x52ff, 1,2, 16,&z8002_device::Z52_ssN0_dddd_addr, "subl %rl3,%a1(%rw2)", 0}, +{0x5310,0x53f0,16,2, 14,&z8002_device::Z53_ddN0_0000_addr, "push @%rw2,%a1", 0}, +{0x5311,0x53f1,16,2, 14,&z8002_device::Z53_ddN0_ssN0_addr, "push @%rw2,%a1(%rw3)", 0}, +{0x5312,0x53f2,16,2, 14,&z8002_device::Z53_ddN0_ssN0_addr, "push @%rw2,%a1(%rw3)", 0}, +{0x5313,0x53f3,16,2, 14,&z8002_device::Z53_ddN0_ssN0_addr, "push @%rw2,%a1(%rw3)", 0}, +{0x5314,0x53f4,16,2, 14,&z8002_device::Z53_ddN0_ssN0_addr, "push @%rw2,%a1(%rw3)", 0}, +{0x5315,0x53f5,16,2, 14,&z8002_device::Z53_ddN0_ssN0_addr, "push @%rw2,%a1(%rw3)", 0}, +{0x5316,0x53f6,16,2, 14,&z8002_device::Z53_ddN0_ssN0_addr, "push @%rw2,%a1(%rw3)", 0}, +{0x5317,0x53f7,16,2, 14,&z8002_device::Z53_ddN0_ssN0_addr, "push @%rw2,%a1(%rw3)", 0}, +{0x5318,0x53f8,16,2, 14,&z8002_device::Z53_ddN0_ssN0_addr, "push @%rw2,%a1(%rw3)", 0}, +{0x5319,0x53f9,16,2, 14,&z8002_device::Z53_ddN0_ssN0_addr, "push @%rw2,%a1(%rw3)", 0}, +{0x531a,0x53fa,16,2, 14,&z8002_device::Z53_ddN0_ssN0_addr, "push @%rw2,%a1(%rw3)", 0}, +{0x531b,0x53fb,16,2, 14,&z8002_device::Z53_ddN0_ssN0_addr, "push @%rw2,%a1(%rw3)", 0}, +{0x531c,0x53fc,16,2, 14,&z8002_device::Z53_ddN0_ssN0_addr, "push @%rw2,%a1(%rw3)", 0}, +{0x531d,0x53fd,16,2, 14,&z8002_device::Z53_ddN0_ssN0_addr, "push @%rw2,%a1(%rw3)", 0}, +{0x531e,0x53fe,16,2, 14,&z8002_device::Z53_ddN0_ssN0_addr, "push @%rw2,%a1(%rw3)", 0}, +{0x531f,0x53ff,16,2, 14,&z8002_device::Z53_ddN0_ssN0_addr, "push @%rw2,%a1(%rw3)", 0}, +{0x5400,0x540f, 1,2, 12,&z8002_device::Z54_0000_dddd_addr, "ldl %rl3,%a1", 0}, +{0x5410,0x54ff, 1,2, 13,&z8002_device::Z54_ssN0_dddd_addr, "ldl %rl3,%a1(%rw2)", 0}, +{0x5510,0x55f0,16,2, 23,&z8002_device::Z55_ssN0_0000_addr, "popl %a1,@%rw2", 0}, +{0x5511,0x55f1,16,2, 23,&z8002_device::Z55_ssN0_ddN0_addr, "popl %a1(%rw3),@%rw2", 0}, +{0x5512,0x55f2,16,2, 23,&z8002_device::Z55_ssN0_ddN0_addr, "popl %a1(%rw3),@%rw2", 0}, +{0x5513,0x55f3,16,2, 23,&z8002_device::Z55_ssN0_ddN0_addr, "popl %a1(%rw3),@%rw2", 0}, +{0x5514,0x55f4,16,2, 23,&z8002_device::Z55_ssN0_ddN0_addr, "popl %a1(%rw3),@%rw2", 0}, +{0x5515,0x55f5,16,2, 23,&z8002_device::Z55_ssN0_ddN0_addr, "popl %a1(%rw3),@%rw2", 0}, +{0x5516,0x55f6,16,2, 23,&z8002_device::Z55_ssN0_ddN0_addr, "popl %a1(%rw3),@%rw2", 0}, +{0x5517,0x55f7,16,2, 23,&z8002_device::Z55_ssN0_ddN0_addr, "popl %a1(%rw3),@%rw2", 0}, +{0x5518,0x55f8,16,2, 23,&z8002_device::Z55_ssN0_ddN0_addr, "popl %a1(%rw3),@%rw2", 0}, +{0x5519,0x55f9,16,2, 23,&z8002_device::Z55_ssN0_ddN0_addr, "popl %a1(%rw3),@%rw2", 0}, +{0x551a,0x55fa,16,2, 23,&z8002_device::Z55_ssN0_ddN0_addr, "popl %a1(%rw3),@%rw2", 0}, +{0x551b,0x55fb,16,2, 23,&z8002_device::Z55_ssN0_ddN0_addr, "popl %a1(%rw3),@%rw2", 0}, +{0x551c,0x55fc,16,2, 23,&z8002_device::Z55_ssN0_ddN0_addr, "popl %a1(%rw3),@%rw2", 0}, +{0x551d,0x55fd,16,2, 23,&z8002_device::Z55_ssN0_ddN0_addr, "popl %a1(%rw3),@%rw2", 0}, +{0x551e,0x55fe,16,2, 23,&z8002_device::Z55_ssN0_ddN0_addr, "popl %a1(%rw3),@%rw2", 0}, +{0x551f,0x55ff,16,2, 23,&z8002_device::Z55_ssN0_ddN0_addr, "popl %a1(%rw3),@%rw2", 0}, +{0x5600,0x560f, 1,2, 15,&z8002_device::Z56_0000_dddd_addr, "addl %rl3,%a1", 0}, +{0x5610,0x56ff, 1,2, 16,&z8002_device::Z56_ssN0_dddd_addr, "addl %rl3,%a1(%rw2)", 0}, +{0x5710,0x57f0,16,2, 16,&z8002_device::Z57_ssN0_0000_addr, "pop %a1,@%rw2", 0}, +{0x5711,0x57f1,16,2, 16,&z8002_device::Z57_ssN0_ddN0_addr, "pop %a1(%rw3),@%rw2", 0}, +{0x5712,0x57f2,16,2, 16,&z8002_device::Z57_ssN0_ddN0_addr, "pop %a1(%rw3),@%rw2", 0}, +{0x5713,0x57f3,16,2, 16,&z8002_device::Z57_ssN0_ddN0_addr, "pop %a1(%rw3),@%rw2", 0}, +{0x5714,0x57f4,16,2, 16,&z8002_device::Z57_ssN0_ddN0_addr, "pop %a1(%rw3),@%rw2", 0}, +{0x5715,0x57f5,16,2, 16,&z8002_device::Z57_ssN0_ddN0_addr, "pop %a1(%rw3),@%rw2", 0}, +{0x5716,0x57f6,16,2, 16,&z8002_device::Z57_ssN0_ddN0_addr, "pop %a1(%rw3),@%rw2", 0}, +{0x5717,0x57f7,16,2, 16,&z8002_device::Z57_ssN0_ddN0_addr, "pop %a1(%rw3),@%rw2", 0}, +{0x5718,0x57f8,16,2, 16,&z8002_device::Z57_ssN0_ddN0_addr, "pop %a1(%rw3),@%rw2", 0}, +{0x5719,0x57f9,16,2, 16,&z8002_device::Z57_ssN0_ddN0_addr, "pop %a1(%rw3),@%rw2", 0}, +{0x571a,0x57fa,16,2, 16,&z8002_device::Z57_ssN0_ddN0_addr, "pop %a1(%rw3),@%rw2", 0}, +{0x571b,0x57fb,16,2, 16,&z8002_device::Z57_ssN0_ddN0_addr, "pop %a1(%rw3),@%rw2", 0}, +{0x571c,0x57fc,16,2, 16,&z8002_device::Z57_ssN0_ddN0_addr, "pop %a1(%rw3),@%rw2", 0}, +{0x571d,0x57fd,16,2, 16,&z8002_device::Z57_ssN0_ddN0_addr, "pop %a1(%rw3),@%rw2", 0}, +{0x571e,0x57fe,16,2, 16,&z8002_device::Z57_ssN0_ddN0_addr, "pop %a1(%rw3),@%rw2", 0}, +{0x571f,0x57ff,16,2, 16,&z8002_device::Z57_ssN0_ddN0_addr, "pop %a1(%rw3),@%rw2", 0}, +{0x5800,0x580f, 1,2,283,&z8002_device::Z58_0000_dddd_addr, "multl %rq3,%a1", 0}, +{0x5810,0x58ff, 1,2,284,&z8002_device::Z58_ssN0_dddd_addr, "multl %rq3,%a1(%rw2)", 0}, +{0x5900,0x590f, 1,2, 71,&z8002_device::Z59_0000_dddd_addr, "mult %rl3,%a1", 0}, +{0x5910,0x59ff, 1,2, 72,&z8002_device::Z59_ssN0_dddd_addr, "mult %rl3,%a1(%rw2)", 0}, +{0x5a00,0x5a0f, 1,2,745,&z8002_device::Z5A_0000_dddd_addr, "divl %rq3,%a1", 0}, +{0x5a10,0x5aff, 1,2,746,&z8002_device::Z5A_ssN0_dddd_addr, "divl %rq3,%a1(%rw2)", 0}, +{0x5b00,0x5b0f, 1,2,108,&z8002_device::Z5B_0000_dddd_addr, "div %rl3,%a1", 0}, +{0x5b10,0x5bff, 1,2,109,&z8002_device::Z5B_ssN0_dddd_addr, "div %rl3,%a1(%rw2)", 0}, +{0x5c01,0x5c01, 1,3, 14,&z8002_device::Z5C_0000_0001_0000_dddd_0000_nmin1_addr, "ldm %rw5,%a2,#%n", 0}, +{0x5c08,0x5c08, 1,2, 16,&z8002_device::Z5C_0000_1000_addr, "testl %a1", 0}, +{0x5c09,0x5c09, 1,3, 14,&z8002_device::Z5C_0000_1001_0000_ssss_0000_nmin1_addr, "ldm %a2,%rw5,#%n", 0}, +{0x5c11,0x5cf1,16,3, 15,&z8002_device::Z5C_ssN0_0001_0000_dddd_0000_nmin1_addr, "ldm %rw5,%a2(%rw2),#%n", 0}, +{0x5c18,0x5cf8,16,2, 17,&z8002_device::Z5C_ddN0_1000_addr, "testl %a1(%rw2)", 0}, +{0x5c19,0x5cf9,16,3, 15,&z8002_device::Z5C_ddN0_1001_0000_ssN0_0000_nmin1_addr, "ldm %a2(%rw2),%rw5,#%n", 0}, +{0x5d00,0x5d0f, 1,2, 15,&z8002_device::Z5D_0000_ssss_addr, "ldl %a1,%rl3", 0}, +{0x5d10,0x5dff, 1,2, 14,&z8002_device::Z5D_ddN0_ssss_addr, "ldl %a1(%rw2),%rl3", 0}, +{0x5e00,0x5e0f, 1,2, 7,&z8002_device::Z5E_0000_cccc_addr, "jp %c3,%a1", 0}, +{0x5e10,0x5eff, 1,2, 8,&z8002_device::Z5E_ddN0_cccc_addr, "jp %c3,%a1(%rw2)", 0}, +{0x5f00,0x5f00, 1,2, 12,&z8002_device::Z5F_0000_0000_addr, "call %a1", DASMFLAG_STEP_OVER}, +{0x5f10,0x5ff0,16,2, 13,&z8002_device::Z5F_ddN0_0000_addr, "call %a1(%rw2)", DASMFLAG_STEP_OVER}, +{0x6000,0x600f, 1,2, 9,&z8002_device::Z60_0000_dddd_addr, "ldb %rb3,%a1", 0}, +{0x6010,0x60ff, 1,2, 10,&z8002_device::Z60_ssN0_dddd_addr, "ldb %rb3,%a1(%rw2)", 0}, +{0x6100,0x610f, 1,2, 9,&z8002_device::Z61_0000_dddd_addr, "ld %rw3,%a1", 0}, +{0x6110,0x61ff, 1,2, 10,&z8002_device::Z61_ssN0_dddd_addr, "ld %rw3,%a1(%rw2)", 0}, +{0x6200,0x620f, 1,2, 13,&z8002_device::Z62_0000_imm4_addr, "resb %a1,%3", 0}, +{0x6210,0x62ff, 1,2, 14,&z8002_device::Z62_ddN0_imm4_addr, "resb %a1(%rw2),%3", 0}, +{0x6300,0x630f, 1,2, 13,&z8002_device::Z63_0000_imm4_addr, "res %a1,%3", 0}, +{0x6310,0x63ff, 1,2, 14,&z8002_device::Z63_ddN0_imm4_addr, "res %a1(%rw2),%3", 0}, +{0x6400,0x640f, 1,2, 13,&z8002_device::Z64_0000_imm4_addr, "setb %a1,%3", 0}, +{0x6410,0x64ff, 1,2, 14,&z8002_device::Z64_ddN0_imm4_addr, "setb %a1(%rw2),%3", 0}, +{0x6500,0x650f, 1,2, 13,&z8002_device::Z65_0000_imm4_addr, "set %a1,%3", 0}, +{0x6510,0x65ff, 1,2, 14,&z8002_device::Z65_ddN0_imm4_addr, "set %a1(%rw2),%3", 0}, +{0x6600,0x660f, 1,2, 10,&z8002_device::Z66_0000_imm4_addr, "bitb %a1,%3", 0}, +{0x6610,0x66ff, 1,2, 11,&z8002_device::Z66_ddN0_imm4_addr, "bitb %a1(%rw2),%3", 0}, +{0x6700,0x670f, 1,2, 10,&z8002_device::Z67_0000_imm4_addr, "bit %a1,%3", 0}, +{0x6710,0x67ff, 1,2, 11,&z8002_device::Z67_ddN0_imm4_addr, "bit %a1(%rw2),%3", 0}, +{0x6800,0x680f, 1,2, 13,&z8002_device::Z68_0000_imm4m1_addr, "incb %a1,%+3", 0}, +{0x6810,0x68ff, 1,2, 14,&z8002_device::Z68_ddN0_imm4m1_addr, "incb %a1(%rw2),%+3", 0}, +{0x6900,0x690f, 1,2, 13,&z8002_device::Z69_0000_imm4m1_addr, "inc %a1,%+3", 0}, +{0x6910,0x69ff, 1,2, 14,&z8002_device::Z69_ddN0_imm4m1_addr, "inc %a1(%rw2),%+3", 0}, +{0x6a00,0x6a0f, 1,2, 13,&z8002_device::Z6A_0000_imm4m1_addr, "decb %a1,%+3", 0}, +{0x6a10,0x6aff, 1,2, 14,&z8002_device::Z6A_ddN0_imm4m1_addr, "decb %a1(%rw2),%+3", 0}, +{0x6b00,0x6b0f, 1,2, 13,&z8002_device::Z6B_0000_imm4m1_addr, "dec %a1,%+3", 0}, +{0x6b10,0x6bff, 1,2, 14,&z8002_device::Z6B_ddN0_imm4m1_addr, "dec %a1(%rw2),%+3", 0}, +{0x6c00,0x6c0f, 1,2, 15,&z8002_device::Z6C_0000_dddd_addr, "exb %rb3,%a1", 0}, +{0x6c10,0x6cff, 1,2, 16,&z8002_device::Z6C_ssN0_dddd_addr, "exb %rb3,%a1(%rw2)", 0}, +{0x6d00,0x6d0f, 1,2, 15,&z8002_device::Z6D_0000_dddd_addr, "ex %rw3,%a1", 0}, +{0x6d10,0x6dff, 1,2, 16,&z8002_device::Z6D_ssN0_dddd_addr, "ex %rw3,%a1(%rw2)", 0}, +{0x6e00,0x6e0f, 1,2, 11,&z8002_device::Z6E_0000_ssss_addr, "ldb %a1,%rb3", 0}, +{0x6e10,0x6eff, 1,2, 11,&z8002_device::Z6E_ddN0_ssss_addr, "ldb %a1(%rw2),%rb3", 0}, +{0x6f00,0x6f0f, 1,2, 11,&z8002_device::Z6F_0000_ssss_addr, "ld %a1,%rw3", 0}, +{0x6f10,0x6fff, 1,2, 12,&z8002_device::Z6F_ddN0_ssss_addr, "ld %a1(%rw2),%rw3", 0}, +{0x7010,0x70ff, 1,2, 14,&z8002_device::Z70_ssN0_dddd_0000_xxxx_0000_0000, "ldb %rb3,%rw2(%rw5)", 0}, +{0x7110,0x71ff, 1,2, 14,&z8002_device::Z71_ssN0_dddd_0000_xxxx_0000_0000, "ld %rw3,%rw2(%rw5)", 0}, +{0x7210,0x72ff, 1,2, 14,&z8002_device::Z72_ddN0_ssss_0000_xxxx_0000_0000, "ldb %rw2(%rw5),%rb3", 0}, +{0x7310,0x73ff, 1,2, 14,&z8002_device::Z73_ddN0_ssss_0000_xxxx_0000_0000, "ld %rw2(%rw5),%rw3", 0}, +{0x7410,0x74ff, 1,2, 15,&z8002_device::Z74_ssN0_dddd_0000_xxxx_0000_0000, "lda p%rw3,%rw2(%rw5)", 0}, +{0x7510,0x75ff, 1,2, 17,&z8002_device::Z75_ssN0_dddd_0000_xxxx_0000_0000, "ldl %rl3,%rw2(%rw5)", 0}, +{0x7600,0x760f, 1,2, 12,&z8002_device::Z76_0000_dddd_addr, "lda p%rw3,%a1", 0}, +{0x7610,0x76ff, 1,2, 13,&z8002_device::Z76_ssN0_dddd_addr, "lda p%rw3,%a1(%rw2)", 0}, +{0x7710,0x77ff, 1,2, 17,&z8002_device::Z77_ddN0_ssss_0000_xxxx_0000_0000, "ldl %rw2(%rw5),%rl3", 0}, +{0x7800,0x78ff, 1,1, 10,&z8002_device::Z78_imm8, "rsvd78", 0}, +{0x7900,0x7900, 1,2, 16,&z8002_device::Z79_0000_0000_addr, "ldps %a1", 0}, +{0x7910,0x79f0,16,2, 17,&z8002_device::Z79_ssN0_0000_addr, "ldps %a1(%rw2)", 0}, +{0x7a00,0x7a00, 1,1, 8,&z8002_device::Z7A_0000_0000, "halt", DASMFLAG_STEP_OVER}, +{0x7b00,0x7b00, 1,1, 13,&z8002_device::Z7B_0000_0000, "iret", DASMFLAG_STEP_OUT}, +{0x7b08,0x7b08, 1,1, 5,&z8002_device::Z7B_0000_1000, "mset", 0}, +{0x7b09,0x7b09, 1,1, 5,&z8002_device::Z7B_0000_1001, "mres", 0}, +{0x7b0a,0x7b0a, 1,1, 7,&z8002_device::Z7B_0000_1010, "mbit", 0}, +{0x7b0d,0x7bfd,16,1, 12,&z8002_device::Z7B_dddd_1101, "mreq %rw2", 0}, +{0x7c00,0x7c03, 1,1, 7,&z8002_device::Z7C_0000_00ii, "di %i3", 0}, +{0x7c04,0x7c07, 1,1, 7,&z8002_device::Z7C_0000_01ii, "ei %i3", 0}, +{0x7d00,0x7df0,16,1, 7,&z8002_device::Z7D_dddd_0ccc, "ldctl %rw2,ctrl0", 0}, +{0x7d01,0x7df1,16,1, 7,&z8002_device::Z7D_dddd_0ccc, "ldctl %rw2,ctrl1", 0}, +{0x7d02,0x7df2,16,1, 7,&z8002_device::Z7D_dddd_0ccc, "ldctl %rw2,fcw", 0}, +{0x7d03,0x7df3,16,1, 7,&z8002_device::Z7D_dddd_0ccc, "ldctl %rw2,refresh", 0}, +{0x7d04,0x7df4,16,1, 7,&z8002_device::Z7D_dddd_0ccc, "ldctl %rw2,psapseg", 0}, +{0x7d05,0x7df5,16,1, 7,&z8002_device::Z7D_dddd_0ccc, "ldctl %rw2,psapoff", 0}, +{0x7d06,0x7df6,16,1, 7,&z8002_device::Z7D_dddd_0ccc, "ldctl %rw2,nspseg", 0}, +{0x7d07,0x7df7,16,1, 7,&z8002_device::Z7D_dddd_0ccc, "ldctl %rw2,nspoff", 0}, +{0x7d08,0x7df8,16,1, 7,&z8002_device::Z7D_ssss_1ccc, "ldctl ctrl0,%rw2", 0}, +{0x7d09,0x7df9,16,1, 7,&z8002_device::Z7D_ssss_1ccc, "ldctl ctrl1,%rw2", 0}, +{0x7d0a,0x7dfa,16,1, 7,&z8002_device::Z7D_ssss_1ccc, "ldctl fcw,%rw2", 0}, +{0x7d0b,0x7dfb,16,1, 7,&z8002_device::Z7D_ssss_1ccc, "ldctl refresh,%rw2", 0}, +{0x7d0c,0x7dfc,16,1, 7,&z8002_device::Z7D_ssss_1ccc, "ldctl psapseg,%rw2", 0}, +{0x7d0d,0x7dfd,16,1, 7,&z8002_device::Z7D_ssss_1ccc, "ldctl psapoff,%rw2", 0}, +{0x7d0e,0x7dfe,16,1, 7,&z8002_device::Z7D_ssss_1ccc, "ldctl nspseg,%rw2", 0}, +{0x7d0f,0x7dff,16,1, 7,&z8002_device::Z7D_ssss_1ccc, "ldctl nspoff,%rw2", 0}, +{0x7e00,0x7eff, 1,1, 10,&z8002_device::Z7E_imm8, "rsvd7e %#b1", 0}, +{0x7f00,0x7fff, 1,1, 33,&z8002_device::Z7F_imm8, "sc %#b1", DASMFLAG_STEP_OVER}, +{0x8000,0x80ff, 1,1, 4,&z8002_device::Z80_ssss_dddd, "addb %rb3,%rb2", 0}, +{0x8100,0x81ff, 1,1, 4,&z8002_device::Z81_ssss_dddd, "add %rw3,%rw2", 0}, +{0x8200,0x82ff, 1,1, 4,&z8002_device::Z82_ssss_dddd, "subb %rb3,%rb2", 0}, +{0x8300,0x83ff, 1,1, 4,&z8002_device::Z83_ssss_dddd, "sub %rw3,%rw2", 0}, +{0x8400,0x84ff, 1,1, 4,&z8002_device::Z84_ssss_dddd, "orb %rb3,%rb2", 0}, +{0x8500,0x85ff, 1,1, 4,&z8002_device::Z85_ssss_dddd, "or %rw3,%rw2", 0}, +{0x8600,0x86ff, 1,1, 4,&z8002_device::Z86_ssss_dddd, "andb %rb3,%rb2", 0}, +{0x8700,0x87ff, 1,1, 4,&z8002_device::Z87_ssss_dddd, "and %rw3,%rw2", 0}, +{0x8800,0x88ff, 1,1, 4,&z8002_device::Z88_ssss_dddd, "xorb %rb3,%rb2", 0}, +{0x8900,0x89ff, 1,1, 4,&z8002_device::Z89_ssss_dddd, "xor %rw3,%rw2", 0}, +{0x8a00,0x8aff, 1,1, 4,&z8002_device::Z8A_ssss_dddd, "cpb %rb3,%rb2", 0}, +{0x8b00,0x8bff, 1,1, 4,&z8002_device::Z8B_ssss_dddd, "cp %rw3,%rw2", 0}, +{0x8c00,0x8cf0,16,1, 7,&z8002_device::Z8C_dddd_0000, "comb %rb2", 0}, +{0x8c02,0x8cf2,16,1, 7,&z8002_device::Z8C_dddd_0010, "negb %rb2", 0}, +{0x8c04,0x8cf4,16,1, 7,&z8002_device::Z8C_dddd_0100, "testb %rb2", 0}, +{0x8c06,0x8cf6,16,1, 7,&z8002_device::Z8C_dddd_0110, "tsetb %rb2", 0}, +{0x8c01,0x8cf1,16,1, 7,&z8002_device::Z8C_dddd_0001, "ldctlb %rb2,flags", 0}, +{0x8c08,0x8cf8,16,1, 7,&z8002_device::Z8C_dddd_1000, "clrb %rb2", 0}, +{0x8c09,0x8cf9,16,1, 7,&z8002_device::Z8C_dddd_1001, "ldctlb flags,%rb2", 0}, +{0x8d00,0x8df0,16,1, 7,&z8002_device::Z8D_dddd_0000, "com %rw2", 0}, +{0x8d01,0x8df1,16,1, 7,&z8002_device::Z8D_imm4_0001, "setflg %f2", 0}, +{0x8d02,0x8df2,16,1, 7,&z8002_device::Z8D_dddd_0010, "neg %rw2", 0}, +{0x8d03,0x8df3,16,1, 7,&z8002_device::Z8D_imm4_0011, "resflg %f2", 0}, +{0x8d04,0x8df4,16,1, 7,&z8002_device::Z8D_dddd_0100, "test %rw2", 0}, +{0x8d05,0x8df5,16,1, 7,&z8002_device::Z8D_imm4_0101, "comflg %f2", 0}, +{0x8d06,0x8df6,16,1, 7,&z8002_device::Z8D_dddd_0110, "tset %rw2", 0}, +{0x8d07,0x8d07, 1,1, 7,&z8002_device::Z8D_0000_0111, "nop", 0}, +{0x8d08,0x8df8,16,1, 7,&z8002_device::Z8D_dddd_1000, "clr %rw2", 0}, +{0x8e00,0x8eff, 1,1, 10,&z8002_device::Z8E_imm8, "ext8e %#b1", 0}, +{0x8f00,0x8fff, 1,1, 10,&z8002_device::Z8F_imm8, "ext8f %#b1", 0}, +{0x9000,0x90ff, 1,1, 8,&z8002_device::Z90_ssss_dddd, "cpl %rl3,%rl2", 0}, +{0x9110,0x91ff, 1,1, 12,&z8002_device::Z91_ddN0_ssss, "pushl @%rw2,%rl3", 0}, +{0x9200,0x92ff, 1,1, 8,&z8002_device::Z92_ssss_dddd, "subl %rl3,%rl2", 0}, +{0x9310,0x93ff, 1,1, 9,&z8002_device::Z93_ddN0_ssss, "push @%rw2,%rw3", 0}, +{0x9400,0x94ff, 1,1, 5,&z8002_device::Z94_ssss_dddd, "ldl %rl3,%rl2", 0}, +{0x9510,0x95ff, 1,1, 12,&z8002_device::Z95_ssN0_dddd, "popl %rl3,@%rw2", 0}, +{0x9600,0x96ff, 1,1, 8,&z8002_device::Z96_ssss_dddd, "addl %rl3,%rl2", 0}, +{0x9710,0x97ff, 1,1, 8,&z8002_device::Z97_ssN0_dddd, "pop %rw3,@%rw2", 0}, +{0x9800,0x98ff, 1,1,282,&z8002_device::Z98_ssss_dddd, "multl %rq3,%rl2", 0}, +{0x9900,0x99ff, 1,1, 70,&z8002_device::Z99_ssss_dddd, "mult %rl3,%rw2", 0}, +{0x9a00,0x9aff, 1,1,744,&z8002_device::Z9A_ssss_dddd, "divl %rq3,%rl2", 0}, +{0x9b00,0x9bff, 1,1,107,&z8002_device::Z9B_ssss_dddd, "div %rl3,%rw2", 0}, +{0x9c00,0x9cf8, 8,1, 13,&z8002_device::Z9C_dddd_1000, "testl %rl2", 0}, +{0x9d00,0x9dff, 1,1, 10,&z8002_device::Z9D_imm8, "rsvd9d", 0}, +{0x9e00,0x9e0f, 1,1, 10,&z8002_device::Z9E_0000_cccc, "ret %c3", DASMFLAG_STEP_OUT}, +{0x9f00,0x9fff, 1,1, 10,&z8002_device::Z9F_imm8, "rsvd9f", 0}, +{0xa000,0xa0ff, 1,1, 3,&z8002_device::ZA0_ssss_dddd, "ldb %rb3,%rb2", 0}, +{0xa100,0xa1ff, 1,1, 3,&z8002_device::ZA1_ssss_dddd, "ld %rw3,%rw2", 0}, +{0xa200,0xa2ff, 1,1, 4,&z8002_device::ZA2_dddd_imm4, "resb %rb2,%3", 0}, +{0xa300,0xa3ff, 1,1, 4,&z8002_device::ZA3_dddd_imm4, "res %rw2,%3", 0}, +{0xa400,0xa4ff, 1,1, 4,&z8002_device::ZA4_dddd_imm4, "setb %rb2,%3", 0}, +{0xa500,0xa5ff, 1,1, 4,&z8002_device::ZA5_dddd_imm4, "set %rw2,%3", 0}, +{0xa600,0xa6ff, 1,1, 4,&z8002_device::ZA6_dddd_imm4, "bitb %rb2,%3", 0}, +{0xa700,0xa7ff, 1,1, 4,&z8002_device::ZA7_dddd_imm4, "bit %rw2,%3", 0}, +{0xa800,0xa8ff, 1,1, 4,&z8002_device::ZA8_dddd_imm4m1, "incb %rb2,%+3", 0}, +{0xa900,0xa9ff, 1,1, 4,&z8002_device::ZA9_dddd_imm4m1, "inc %rw2,%+3", 0}, +{0xaa00,0xaaff, 1,1, 4,&z8002_device::ZAA_dddd_imm4m1, "decb %rb2,%+3", 0}, +{0xab00,0xabff, 1,1, 4,&z8002_device::ZAB_dddd_imm4m1, "dec %rw2,%+3", 0}, +{0xac00,0xacff, 1,1, 6,&z8002_device::ZAC_ssss_dddd, "exb %rb3,%rb2", 0}, +{0xad00,0xadff, 1,1, 6,&z8002_device::ZAD_ssss_dddd, "ex %rw3,%rw2", 0}, +{0xae00,0xaeff, 1,1, 5,&z8002_device::ZAE_dddd_cccc, "tccb %c3,%rb2", 0}, +{0xaf00,0xafff, 1,1, 5,&z8002_device::ZAF_dddd_cccc, "tcc %c3,%rw2", 0}, +{0xb000,0xb0f0,16,1, 5,&z8002_device::ZB0_dddd_0000, "dab %rb2", 0}, +{0xb100,0xb1f0,16,1, 11,&z8002_device::ZB1_dddd_0000, "extsb %rw2", 0}, +{0xb107,0xb1f7,16,1, 11,&z8002_device::ZB1_dddd_0111, "extsl %rq2", 0}, +{0xb10a,0xb1fa,16,1, 11,&z8002_device::ZB1_dddd_1010, "exts %rl2", 0}, +{0xb200,0xb2f0,16,1, 6,&z8002_device::ZB2_dddd_00I0, "rlb %rb2,%?3", 0}, +{0xb201,0xb2f1,16,2, 13,&z8002_device::ZB2_dddd_0001_imm8, "s%*lb %rb2,%$3", 0}, +{0xb202,0xb2f2,16,1, 6,&z8002_device::ZB2_dddd_00I0, "rlb %rb2,%?3", 0}, +{0xb203,0xb2f3,16,2, 15,&z8002_device::ZB2_dddd_0011_0000_ssss_0000_0000, "sdlb %rb2,%rw5", 0}, +{0xb204,0xb2f4,16,1, 6,&z8002_device::ZB2_dddd_01I0, "rrb %rb2,%?3", 0}, +{0xb206,0xb2f6,16,1, 6,&z8002_device::ZB2_dddd_01I0, "rrb %rb2,%?3", 0}, +{0xb208,0xb2f8,16,1, 9,&z8002_device::ZB2_dddd_10I0, "rlcb %rb2,%?3", 0}, +{0xb209,0xb2f9,16,2, 13,&z8002_device::ZB2_dddd_1001_imm8, "s%*ab %rb2,%$3", 0}, +{0xb20a,0xb2fa,16,1, 9,&z8002_device::ZB2_dddd_10I0, "rlcb %rb2,%?3", 0}, +{0xb20b,0xb2fb,16,2, 15,&z8002_device::ZB2_dddd_1011_0000_ssss_0000_0000, "sdab %rb2,%rw5", 0}, +{0xb20c,0xb2fc,16,1, 9,&z8002_device::ZB2_dddd_11I0, "rrcb %rb2,%?3", 0}, +{0xb20e,0xb2fe,16,1, 9,&z8002_device::ZB2_dddd_11I0, "rrcb %rb2,%?3", 0}, +{0xb300,0xb3f0,16,1, 6,&z8002_device::ZB3_dddd_00I0, "rl %rw2,%?3", 0}, +{0xb301,0xb3f1,16,2, 13,&z8002_device::ZB3_dddd_0001_imm8, "s%*l %rw2,%$3", 0}, +{0xb302,0xb3f2,16,1, 6,&z8002_device::ZB3_dddd_00I0, "rl %rw2,%?3", 0}, +{0xb303,0xb3f3,16,2, 15,&z8002_device::ZB3_dddd_0011_0000_ssss_0000_0000, "sdl %rw2,%rw5", 0}, +{0xb304,0xb3f4,16,1, 6,&z8002_device::ZB3_dddd_01I0, "rr %rw2,%?3", 0}, +{0xb305,0xb3f5,16,2, 13,&z8002_device::ZB3_dddd_0101_imm8, "s%*ll %rl2,%$3", 0}, +{0xb306,0xb3f6,16,1, 6,&z8002_device::ZB3_dddd_01I0, "rr %rw2,%?3", 0}, +{0xb307,0xb3f7,16,2, 15,&z8002_device::ZB3_dddd_0111_0000_ssss_0000_0000, "sdll %rl2,%rw5", 0}, +{0xb308,0xb3f8,16,1, 6,&z8002_device::ZB3_dddd_10I0, "rlc %rw2,%?3", 0}, +{0xb309,0xb3f9,16,2, 13,&z8002_device::ZB3_dddd_1001_imm8, "s%*a %rw2,%$3", 0}, +{0xb30a,0xb3fa,16,1, 6,&z8002_device::ZB3_dddd_10I0, "rlc %rw2,%?3", 0}, +{0xb30b,0xb3fb,16,2, 15,&z8002_device::ZB3_dddd_1011_0000_ssss_0000_0000, "sda %rw2,%rw5", 0}, +{0xb30c,0xb3fc,16,1, 6,&z8002_device::ZB3_dddd_11I0, "rrc %rw2,%?3", 0}, +{0xb30d,0xb3fd,16,2, 13,&z8002_device::ZB3_dddd_1101_imm8, "s%*al %rl2,%$3", 0}, +{0xb30e,0xb3fe,16,1, 6,&z8002_device::ZB3_dddd_11I0, "rrc %rw2,%?3", 0}, +{0xb30f,0xb3ff,16,2, 15,&z8002_device::ZB3_dddd_1111_0000_ssss_0000_0000, "sdal %rl2,%rw5", 0}, +{0xb400,0xb4ff, 1,1, 5,&z8002_device::ZB4_ssss_dddd, "adcb %rb3,%rb2", 0}, +{0xb500,0xb5ff, 1,1, 5,&z8002_device::ZB5_ssss_dddd, "adc %rw3,%rw2", 0}, +{0xb600,0xb6ff, 1,1, 5,&z8002_device::ZB6_ssss_dddd, "sbcb %rb3,%rb2", 0}, +{0xb700,0xb7ff, 1,1, 5,&z8002_device::ZB7_ssss_dddd, "sbc %rw3,%rw2", 0}, +{0xb810,0xb8f0,16,2, 25,&z8002_device::ZB8_ddN0_0000_0000_rrrr_ssN0_0000, "trib @%rw2,@%rw6,%rb5", 0}, +{0xb812,0xb8f2,16,2, 25,&z8002_device::ZB8_ddN0_0010_0000_rrrr_ssN0_0000, "trtib @%rw2,@%rw6,%rb5", 0}, +{0xb814,0xb8f4,16,2, 25,&z8002_device::ZB8_ddN0_0100_0000_rrrr_ssN0_0000, "trirb @%rw2,@%rw6,%rb5", 0}, +{0xb816,0xb8f6,16,2, 25,&z8002_device::ZB8_ddN0_0110_0000_rrrr_ssN0_1110, "trtirb @%rw2,@%rw6,%rb5", 0}, +{0xb818,0xb8f8,16,2, 25,&z8002_device::ZB8_ddN0_1000_0000_rrrr_ssN0_0000, "trdb @%rw2,@%rw6,%rb5", 0}, +{0xb81a,0xb8fa,16,2, 25,&z8002_device::ZB8_ddN0_1010_0000_rrrr_ssN0_0000, "trtrb @%rw2,@%rw6,%rb5", 0}, +{0xb81c,0xb8fc,16,2, 25,&z8002_device::ZB8_ddN0_1100_0000_rrrr_ssN0_0000, "trdrb @%rw2,@%rw6,%rb5", 0}, +{0xb81e,0xb8fe,16,2, 25,&z8002_device::ZB8_ddN0_1110_0000_rrrr_ssN0_1110, "trtdrb @%rw2,@%rw6,%rb5", 0}, +{0xb900,0xb9ff,16,1, 10,&z8002_device::ZB9_imm8, "rsvdb9", 0}, +{0xba10,0xbaf0,16,2, 11,&z8002_device::ZBA_ssN0_0000_0000_rrrr_dddd_cccc, "cpib %rb6,@%rw2,%rw5,%c7", 0}, +{0xba11,0xbaf1,16,2, 11,&z8002_device::ZBA_ssN0_0001_0000_rrrr_ddN0_x000, "ldirb @%rw6,@%rw2,%rw5", DASMFLAG_STEP_OVER}, +{0xba12,0xbaf2,16,2, 11,&z8002_device::ZBA_ssN0_0010_0000_rrrr_ddN0_cccc, "cpsib @%rw6,@%rw2,%rw5,%c7", 0}, +{0xba14,0xbaf4,16,2, 11,&z8002_device::ZBA_ssN0_0100_0000_rrrr_dddd_cccc, "cpirb %rb6,@%rw2,%rw5,%c7", DASMFLAG_STEP_OVER}, +{0xba16,0xbaf6,16,2, 11,&z8002_device::ZBA_ssN0_0110_0000_rrrr_ddN0_cccc, "cpsirb @%rw6,@%rw2,%rw5,%c7", DASMFLAG_STEP_OVER}, +{0xba18,0xbaf8,16,2, 11,&z8002_device::ZBA_ssN0_1000_0000_rrrr_dddd_cccc, "cpdb %rb6,@%rw2,%rw5,%c7", 0}, +{0xba19,0xbaf9,16,2, 11,&z8002_device::ZBA_ssN0_1001_0000_rrrr_ddN0_x000, "lddrb @%rw2,@%rw6,%rw5", DASMFLAG_STEP_OVER}, +{0xba1a,0xbafa,16,2, 11,&z8002_device::ZBA_ssN0_1010_0000_rrrr_ddN0_cccc, "cpsdb @%rw6,@%rw2,%rw5,%c7", 0}, +{0xba1c,0xbafc,16,2, 11,&z8002_device::ZBA_ssN0_1100_0000_rrrr_dddd_cccc, "cpdrb %rb6,@%rw2,%rw5,%c7", DASMFLAG_STEP_OVER}, +{0xba1e,0xbafe,16,2, 11,&z8002_device::ZBA_ssN0_1110_0000_rrrr_ddN0_cccc, "cpsdrb @%rw6,@%rw2,%rw5,%c7", DASMFLAG_STEP_OVER}, +{0xbb10,0xbbf0,16,2, 11,&z8002_device::ZBB_ssN0_0000_0000_rrrr_dddd_cccc, "cpi %rw6,@%rw2,%rw5,%c7", 0}, +{0xbb11,0xbbf1,16,2, 11,&z8002_device::ZBB_ssN0_0001_0000_rrrr_ddN0_x000, "ldir @%rw6,@%rw2,%rw5", DASMFLAG_STEP_OVER}, +{0xbb12,0xbbf2,16,2, 11,&z8002_device::ZBB_ssN0_0010_0000_rrrr_ddN0_cccc, "cpsi @%rw6,@%rw2,%rw5,%c7", 0}, +{0xbb14,0xbbf4,16,2, 11,&z8002_device::ZBB_ssN0_0100_0000_rrrr_dddd_cccc, "cpir %rw6,@%rw2,%rw5,%c7", DASMFLAG_STEP_OVER}, +{0xbb16,0xbbf6,16,2, 11,&z8002_device::ZBB_ssN0_0110_0000_rrrr_ddN0_cccc, "cpsir @%rw6,@%rw2,%rw5,%c7", DASMFLAG_STEP_OVER}, +{0xbb18,0xbbf8,16,2, 11,&z8002_device::ZBB_ssN0_1000_0000_rrrr_dddd_cccc, "cpd %rw6,@%rw2,%rw5,%c7", 0}, +{0xbb19,0xbbf9,16,2, 11,&z8002_device::ZBB_ssN0_1001_0000_rrrr_ddN0_x000, "lddr @%rw2,@%rw6,%rw5", DASMFLAG_STEP_OVER}, +{0xbb1a,0xbbfa,16,2, 11,&z8002_device::ZBB_ssN0_1010_0000_rrrr_ddN0_cccc, "cpsd @%rw6,@%rw2,%rw5,%c7", 0}, +{0xbb1c,0xbbfc,16,2, 11,&z8002_device::ZBB_ssN0_1100_0000_rrrr_dddd_cccc, "cpdr %rw6,@%rw2,%rw5,%c7", DASMFLAG_STEP_OVER}, +{0xbb1e,0xbbfe,16,2, 11,&z8002_device::ZBB_ssN0_1110_0000_rrrr_ddN0_cccc, "cpsdr @%rw6,@%rw2,%rw5,%c7", DASMFLAG_STEP_OVER}, +{0xbc00,0xbcff, 1,1, 9,&z8002_device::ZBC_aaaa_bbbb, "rrdb %rb3,%rb2", 0}, +{0xbd00,0xbdff, 1,1, 5,&z8002_device::ZBD_dddd_imm4, "ldk %rw2,%3", 0}, +{0xbe00,0xbeff, 1,1, 9,&z8002_device::ZBE_aaaa_bbbb, "rldb %rb3,%rb2", 0}, +{0xbf00,0xbfff, 1,1, 10,&z8002_device::ZBF_imm8, "rsvdbf", 0}, +{0xc000,0xcfff, 1,1, 5,&z8002_device::ZC_dddd_imm8, "ldb %rb1,%#b1", 0}, +{0xd000,0xdfff, 1,1, 10,&z8002_device::ZD_dsp12, "calr %d2", DASMFLAG_STEP_OVER}, +{0xe000,0xefff, 1,1, 6,&z8002_device::ZE_cccc_dsp8, "jr %c1,%d1", 0}, +{0xf000,0xf07f, 1,1, 11,&z8002_device::ZF_dddd_0dsp7, "dbjnz %rb1,%d0", DASMFLAG_STEP_OVER}, +{0xf100,0xf17f, 1,1, 11,&z8002_device::ZF_dddd_0dsp7, "dbjnz %rb1,%d0", DASMFLAG_STEP_OVER}, +{0xf200,0xf27f, 1,1, 11,&z8002_device::ZF_dddd_0dsp7, "dbjnz %rb1,%d0", DASMFLAG_STEP_OVER}, +{0xf300,0xf37f, 1,1, 11,&z8002_device::ZF_dddd_0dsp7, "dbjnz %rb1,%d0", DASMFLAG_STEP_OVER}, +{0xf400,0xf47f, 1,1, 11,&z8002_device::ZF_dddd_0dsp7, "dbjnz %rb1,%d0", DASMFLAG_STEP_OVER}, +{0xf500,0xf57f, 1,1, 11,&z8002_device::ZF_dddd_0dsp7, "dbjnz %rb1,%d0", DASMFLAG_STEP_OVER}, +{0xf600,0xf67f, 1,1, 11,&z8002_device::ZF_dddd_0dsp7, "dbjnz %rb1,%d0", DASMFLAG_STEP_OVER}, +{0xf700,0xf77f, 1,1, 11,&z8002_device::ZF_dddd_0dsp7, "dbjnz %rb1,%d0", DASMFLAG_STEP_OVER}, +{0xf800,0xf87f, 1,1, 11,&z8002_device::ZF_dddd_0dsp7, "dbjnz %rb1,%d0", DASMFLAG_STEP_OVER}, +{0xf900,0xf97f, 1,1, 11,&z8002_device::ZF_dddd_0dsp7, "dbjnz %rb1,%d0", DASMFLAG_STEP_OVER}, +{0xfa00,0xfa7f, 1,1, 11,&z8002_device::ZF_dddd_0dsp7, "dbjnz %rb1,%d0", DASMFLAG_STEP_OVER}, +{0xfb00,0xfb7f, 1,1, 11,&z8002_device::ZF_dddd_0dsp7, "dbjnz %rb1,%d0", DASMFLAG_STEP_OVER}, +{0xfc00,0xfc7f, 1,1, 11,&z8002_device::ZF_dddd_0dsp7, "dbjnz %rb1,%d0", DASMFLAG_STEP_OVER}, +{0xfd00,0xfd7f, 1,1, 11,&z8002_device::ZF_dddd_0dsp7, "dbjnz %rb1,%d0", DASMFLAG_STEP_OVER}, +{0xfe00,0xfe7f, 1,1, 11,&z8002_device::ZF_dddd_0dsp7, "dbjnz %rb1,%d0", DASMFLAG_STEP_OVER}, +{0xff00,0xff7f, 1,1, 11,&z8002_device::ZF_dddd_0dsp7, "dbjnz %rb1,%d0", DASMFLAG_STEP_OVER}, +{0xf080,0xf0ff, 1,1, 11,&z8002_device::ZF_dddd_1dsp7, "djnz %rw1,%d0", DASMFLAG_STEP_OVER}, +{0xf180,0xf1ff, 1,1, 11,&z8002_device::ZF_dddd_1dsp7, "djnz %rw1,%d0", DASMFLAG_STEP_OVER}, +{0xf280,0xf2ff, 1,1, 11,&z8002_device::ZF_dddd_1dsp7, "djnz %rw1,%d0", DASMFLAG_STEP_OVER}, +{0xf380,0xf3ff, 1,1, 11,&z8002_device::ZF_dddd_1dsp7, "djnz %rw1,%d0", DASMFLAG_STEP_OVER}, +{0xf480,0xf4ff, 1,1, 11,&z8002_device::ZF_dddd_1dsp7, "djnz %rw1,%d0", DASMFLAG_STEP_OVER}, +{0xf580,0xf5ff, 1,1, 11,&z8002_device::ZF_dddd_1dsp7, "djnz %rw1,%d0", DASMFLAG_STEP_OVER}, +{0xf680,0xf6ff, 1,1, 11,&z8002_device::ZF_dddd_1dsp7, "djnz %rw1,%d0", DASMFLAG_STEP_OVER}, +{0xf780,0xf7ff, 1,1, 11,&z8002_device::ZF_dddd_1dsp7, "djnz %rw1,%d0", DASMFLAG_STEP_OVER}, +{0xf880,0xf8ff, 1,1, 11,&z8002_device::ZF_dddd_1dsp7, "djnz %rw1,%d0", DASMFLAG_STEP_OVER}, +{0xf980,0xf9ff, 1,1, 11,&z8002_device::ZF_dddd_1dsp7, "djnz %rw1,%d0", DASMFLAG_STEP_OVER}, +{0xfa80,0xfaff, 1,1, 11,&z8002_device::ZF_dddd_1dsp7, "djnz %rw1,%d0", DASMFLAG_STEP_OVER}, +{0xfb80,0xfbff, 1,1, 11,&z8002_device::ZF_dddd_1dsp7, "djnz %rw1,%d0", DASMFLAG_STEP_OVER}, +{0xfc80,0xfcff, 1,1, 11,&z8002_device::ZF_dddd_1dsp7, "djnz %rw1,%d0", DASMFLAG_STEP_OVER}, +{0xfd80,0xfdff, 1,1, 11,&z8002_device::ZF_dddd_1dsp7, "djnz %rw1,%d0", DASMFLAG_STEP_OVER}, +{0xfe80,0xfeff, 1,1, 11,&z8002_device::ZF_dddd_1dsp7, "djnz %rw1,%d0", DASMFLAG_STEP_OVER}, +{0xff80,0xffff, 1,1, 11,&z8002_device::ZF_dddd_1dsp7, "djnz %rw1,%d0", DASMFLAG_STEP_OVER}, +{0, 0, 0,0, 0,NULL, NULL, 0} +}; + + +void z8000_init_tables(void) +{ + const Z8000_init *init; + int i; + + /* allocate the opcode execution and disassembler array */ + z8000_exec = global_alloc_array(Z8000_exec, 0x10000); + + /* set up the zero, sign, parity lookup table */ + for (i = 0; i < 256; i++) + z8000_zsp[i] = ((i == 0) ? F_Z : 0) | + ((i & 128) ? F_S : 0) | + ((((i>>7)^(i>>6)^(i>>5)^(i>>4)^(i>>3)^(i>>2)^(i>>1)^i) & 1) ? 0 : F_PV); + + /* first set all 64K opcodes to invalid */ + for (i = 0; i < 0x10000; i++) + { + z8000_exec[i].opcode = &z8002_device::zinvalid; + z8000_exec[i].cycles = 4; + z8000_exec[i].size = 1; + z8000_exec[i].dasm = ".word %#w0"; + z8000_exec[i].dasmflags = 0; + } + + /* now decompose the initialization table */ + for (init = table; init->size; init++) + { + for (i = init->beg; i <= init->end; i += init->step) + { + if (z8000_exec[i].opcode != &z8002_device::zinvalid) + logerror("Z8000 opcode %04x clash '%s'\n", i, z8000_exec[i].dasm); + + z8000_exec[i].opcode = init->opcode; + z8000_exec[i].cycles = init->cycles; + z8000_exec[i].size = init->size; + z8000_exec[i].dasm = init->dasm; + z8000_exec[i].dasmflags = init->dasmflags; + } + } +} + +void z8000_deinit_tables(void) +{ + global_free_array( z8000_exec ); + z8000_exec = NULL; +} diff --git a/src/devices/imagedev/bitbngr.c b/src/devices/imagedev/bitbngr.c new file mode 100644 index 00000000000..9577d9e1efd --- /dev/null +++ b/src/devices/imagedev/bitbngr.c @@ -0,0 +1,103 @@ +// license:BSD-3-Clause +// copyright-holders:Nathan Woods, Miodrag Milanovic +/********************************************************************* + + bitbngr.c + +*********************************************************************/ + +#include "emu.h" +#include "bitbngr.h" + + + +/*************************************************************************** + IMPLEMENTATION +***************************************************************************/ + +const device_type BITBANGER = &device_creator; + +/*------------------------------------------------- + ctor +-------------------------------------------------*/ + +bitbanger_device::bitbanger_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, BITBANGER, "Bitbanger", tag, owner, clock, "bitbanger", __FILE__), + device_image_interface(mconfig, *this) +{ +} + + + +/*------------------------------------------------- + native_output - outputs data to a file +-------------------------------------------------*/ + +void bitbanger_device::output(UINT8 data) +{ + if (exists()) + { + fwrite(&data, 1); + } +} + + +/*------------------------------------------------- + native_input - inputs data from a file +-------------------------------------------------*/ + +UINT32 bitbanger_device::input(void *buffer, UINT32 length) +{ + if (exists()) + { + return fread(buffer, length); + } + return 0; +} + + + +/*------------------------------------------------- + device_start +-------------------------------------------------*/ + +void bitbanger_device::device_start(void) +{ +} + + + +/*------------------------------------------------- + device_config_complete +-------------------------------------------------*/ + +void bitbanger_device::device_config_complete(void) +{ + update_names(BITBANGER, "bitbngr", "bitb"); +} + + + +/*------------------------------------------------- + call_load +-------------------------------------------------*/ + +bool bitbanger_device::call_load(void) +{ + /* we don't need to do anything special */ + return IMAGE_INIT_PASS; +} + +bool bitbanger_device::call_create(int format_type, option_resolution *format_options) +{ + /* we don't need to do anything special */ + return IMAGE_INIT_PASS; +} + +/*------------------------------------------------- + call_unload +-------------------------------------------------*/ + +void bitbanger_device::call_unload(void) +{ +} diff --git a/src/devices/imagedev/bitbngr.h b/src/devices/imagedev/bitbngr.h new file mode 100644 index 00000000000..4c3b3e5b9d1 --- /dev/null +++ b/src/devices/imagedev/bitbngr.h @@ -0,0 +1,46 @@ +// license:BSD-3-Clause +// copyright-holders:Nathan Woods, Miodrag Milanovic +/********************************************************************* + + bitbngr.h + +*********************************************************************/ + +#ifndef __BITBNGR_H__ +#define __BITBNGR_H__ + +class bitbanger_device : public device_t, + public device_image_interface +{ +public: + // construction/destruction + bitbanger_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // image-level overrides + virtual bool call_load(); + virtual bool call_create(int format_type, option_resolution *format_options); + virtual void call_unload(); + + // image device + virtual iodevice_t image_type() const { return IO_SERIAL; } + virtual bool is_readable() const { return 1; } + virtual bool is_writeable() const { return 1; } + virtual bool is_creatable() const { return 1; } + virtual bool must_be_loaded() const { return 0; } + virtual bool is_reset_on_load() const { return 0; } + virtual const char *file_extensions() const { return ""; } + virtual const option_guide *create_option_guide() const { return NULL; } + + void output(UINT8 data); + UINT32 input(void *buffer, UINT32 length); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_config_complete(); +}; + +// device type definition +extern const device_type BITBANGER; + +#endif /* __BITBNGR_H__ */ diff --git a/src/devices/imagedev/cassette.c b/src/devices/imagedev/cassette.c new file mode 100644 index 00000000000..4721a486b62 --- /dev/null +++ b/src/devices/imagedev/cassette.c @@ -0,0 +1,429 @@ +// license:BSD-3-Clause +// copyright-holders:Nathan Woods, Miodrag Milanovic +/********************************************************************* + + cassette.c + + Interface to the cassette image abstraction code + +*********************************************************************/ + +#include "emu.h" +#include "formats/imageutl.h" +#include "cassette.h" +#include "ui/ui.h" + + +#define ANIMATION_FPS 1 +#define ANIMATION_FRAMES 4 + +#define VERBOSE 0 +#define LOG(x) do { if (VERBOSE) logerror x; } while (0) + +// device type definition +const device_type CASSETTE = &device_creator; + +//------------------------------------------------- +// cassette_image_device - constructor +//------------------------------------------------- + +cassette_image_device::cassette_image_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, CASSETTE, "Cassette", tag, owner, clock, "cassette_image", __FILE__), + device_image_interface(mconfig, *this), + m_state(CASSETTE_STOPPED), + m_formats(cassette_default_formats), + m_create_opts(NULL), + m_default_state(CASSETTE_PLAY), + m_interface(NULL) +{ +} + +//------------------------------------------------- +// cassette_image_device - destructor +//------------------------------------------------- + +cassette_image_device::~cassette_image_device() +{ +} + +//------------------------------------------------- +// device_config_complete - perform any +// operations now that the configuration is +// complete +//------------------------------------------------- + +void cassette_image_device::device_config_complete() +{ + m_extension_list[0] = '\0'; + for (int i = 0; m_formats[i]; i++ ) + image_specify_extension( m_extension_list, 256, m_formats[i]->extensions ); + + // set brief and instance name + update_names(); +} + + +/********************************************************************* + cassette IO +*********************************************************************/ + +bool cassette_image_device::is_motor_on() +{ + if ((m_state & CASSETTE_MASK_UISTATE) == CASSETTE_STOPPED) + return FALSE; + if ((m_state & CASSETTE_MASK_MOTOR) != CASSETTE_MOTOR_ENABLED) + return FALSE; + return TRUE; +} + + + +void cassette_image_device::update() +{ + double cur_time = device().machine().time().as_double(); + + if (is_motor_on()) + { + double new_position = m_position + (cur_time - m_position_time)*m_speed*m_direction; + + switch(m_state & CASSETTE_MASK_UISTATE) { + case CASSETTE_RECORD: + cassette_put_sample(m_cassette, m_channel, m_position, new_position - m_position, m_value); + break; + + case CASSETTE_PLAY: + if ( m_cassette ) + { + cassette_get_sample(m_cassette, m_channel, new_position, 0.0, &m_value); + /* See if reached end of tape */ + double length = get_length(); + if (new_position > length) + { + m_state = (cassette_state)(( m_state & ~CASSETTE_MASK_UISTATE ) | CASSETTE_STOPPED); + new_position = length; + } + else if (new_position < 0) + { + m_state = (cassette_state)(( m_state & ~CASSETTE_MASK_UISTATE ) | CASSETTE_STOPPED); + new_position = 0; + } + } + break; + } + m_position = new_position; + } + m_position_time = cur_time; +} + +void cassette_image_device::change_state(cassette_state state, cassette_state mask) +{ + cassette_state new_state; + + new_state = m_state; + new_state = (cassette_state)(new_state & ~mask); + new_state = (cassette_state)(new_state | (state & mask)); + + if (new_state != m_state) + { + update(); + m_state = new_state; + } +} + + + +double cassette_image_device::input() +{ + INT32 sample; + double double_value; + + update(); + sample = m_value; + double_value = sample / ((double) 0x7FFFFFFF); + + LOG(("cassette_input(): time_index=%g value=%g\n", m_position, double_value)); + + return double_value; +} + + + +void cassette_image_device::output(double value) +{ + if (((m_state & CASSETTE_MASK_UISTATE) == CASSETTE_RECORD) && (m_value != value)) + { + update(); + + value = MIN(value, 1.0); + value = MAX(value, -1.0); + + m_value = (INT32) (value * 0x7FFFFFFF); + } +} + + +double cassette_image_device::get_position() +{ + double position = m_position; + + if (is_motor_on()) + position += (device().machine().time().as_double() - m_position_time)*m_speed*m_direction; + return position; +} + + + +double cassette_image_device::get_length() +{ + struct CassetteInfo info; + + cassette_get_info(m_cassette, &info); + return ((double) info.sample_count) / info.sample_frequency; +} + +void cassette_image_device::set_channel(int channel) +{ + m_channel = channel; +} + +void cassette_image_device::set_speed(double speed) +{ + m_speed = speed; +} + +void cassette_image_device::go_forward() +{ + m_direction = 1; +} + +void cassette_image_device::go_reverse() +{ + m_direction = -1; +} + + +void cassette_image_device::seek(double time, int origin) +{ + double length; + + update(); + + length = get_length(); + + switch(origin) { + case SEEK_SET: + break; + + case SEEK_END: + time += length; + break; + + case SEEK_CUR: + time += get_position(); + break; + } + + /* clip position into legal bounds */ + if (time < 0) + time = 0; + else + if (time > length) + time = length; + + m_position = time; +} + + + +/********************************************************************* + cassette device init/load/unload/specify +*********************************************************************/ + +void cassette_image_device::device_start() +{ + /* set to default state */ + m_cassette = NULL; + m_state = m_default_state; + m_value = 0; +} + +bool cassette_image_device::call_create(int format_type, option_resolution *format_options) +{ + return call_load(); +} + +bool cassette_image_device::call_load() +{ + casserr_t err; + int cassette_flags; + const char *extension; + int is_writable; + device_image_interface *image = NULL; + interface(image); + + if ((has_been_created()) || (length() == 0)) + { + /* creating an image */ + err = cassette_create((void *)image, &image_ioprocs, &wavfile_format, m_create_opts, CASSETTE_FLAG_READWRITE|CASSETTE_FLAG_SAVEONEXIT, &m_cassette); + if (err) + goto error; + } + else + { + /* opening an image */ + do + { + is_writable = !is_readonly(); + cassette_flags = is_writable ? (CASSETTE_FLAG_READWRITE|CASSETTE_FLAG_SAVEONEXIT) : CASSETTE_FLAG_READONLY; + std::string fname; + if (software_entry()==NULL) { + extension = filetype(); + } else { + fname = m_mame_file->filename(); + int loc = fname.find_last_of('.'); + if (loc!=-1) { + extension = fname.substr(loc + 1,fname.length()-loc).c_str(); + } else { + extension = ""; + } + } + err = cassette_open_choices((void *)image, &image_ioprocs, extension, m_formats, cassette_flags, &m_cassette); + + /* this is kind of a hack */ + if (err && is_writable) + make_readonly(); + } + while(err && is_writable); + + if (err) + goto error; + } + + /* set to default state, but only change the UI state */ + change_state(m_default_state, CASSETTE_MASK_UISTATE); + + /* reset the position */ + m_position = 0.0; + m_position_time = device().machine().time().as_double(); + + /* default channel to 0, speed multiplier to 1 */ + m_channel = 0; + m_speed = 1; + m_direction = 1; + + return IMAGE_INIT_PASS; + +error: + image_error_t imgerr = IMAGE_ERROR_UNSPECIFIED; + switch(err) + { + case CASSETTE_ERROR_INTERNAL: + imgerr = IMAGE_ERROR_INTERNAL; + break; + case CASSETTE_ERROR_UNSUPPORTED: + imgerr = IMAGE_ERROR_UNSUPPORTED; + break; + case CASSETTE_ERROR_OUTOFMEMORY: + imgerr = IMAGE_ERROR_OUTOFMEMORY; + break; + case CASSETTE_ERROR_INVALIDIMAGE: + imgerr = IMAGE_ERROR_INVALIDIMAGE; + break; + default: + imgerr = IMAGE_ERROR_UNSPECIFIED; + break; + } + image->seterror(imgerr, "" ); + return IMAGE_INIT_FAIL; +} + + + +void cassette_image_device::call_unload() +{ + /* if we are recording, write the value to the image */ + if ((m_state & CASSETTE_MASK_UISTATE) == CASSETTE_RECORD) + update(); + + /* close out the cassette */ + cassette_close(m_cassette); + m_cassette = NULL; + + /* set to default state, but only change the UI state */ + change_state(CASSETTE_STOPPED, CASSETTE_MASK_UISTATE); +} + + + +/* + display a small tape icon, with the current position in the tape image +*/ +void cassette_image_device::call_display() +{ + char buf[65]; + float x, y; + int n; + double position, length; + cassette_state uistate; + cassette_image_device *dev; + static const UINT8 shapes[8] = { 0x2d, 0x5c, 0x7c, 0x2f, 0x2d, 0x20, 0x20, 0x20 }; + + /* abort if we should not be showing the image */ + if (!exists()) + return; + if (!is_motor_on()) + return; + + /* figure out where we are in the cassette */ + position = get_position(); + length = get_length(); + uistate = (cassette_state)(get_state() & CASSETTE_MASK_UISTATE); + + /* choose a location on the screen */ + x = 0.2f; + y = 0.5f; + + cassette_device_iterator iter(device().machine().root_device()); + for (dev = iter.first(); dev != NULL && strcmp( dev->tag(), device().tag() ); dev = iter.next()) + y += 1; + + y *= device().machine().ui().get_line_height() + 2.0f * UI_BOX_TB_BORDER; + /* choose which frame of the animation we are at */ + n = ((int) position / ANIMATION_FPS) % ANIMATION_FRAMES; + /* Since you can have anything in a BDF file, we will use crude ascii characters instead */ + snprintf(buf, ARRAY_LENGTH(buf), "%c%c %c %02d:%02d (%04d) [%02d:%02d (%04d)]", +#if 0 + /* THE ANIMATION HASN'T WORKED SINCE 0.114 - LEFT HERE FOR REFERENCE */ + /* NEVER SEEN THE PLAY / RECORD ICONS */ + /* character pairs 2-3, 4-5, 6-7, 8-9 form little tape cassette images */ + n * 2 + 2, /* cassette icon left */ + n * 2 + 3, /* cassette icon right */ + (uistate == CASSETTE_PLAY) ? 16 : 14, /* play or record icon */ +#else + shapes[n], /* cassette icon left */ + shapes[n|4], /* cassette icon right */ + (uistate == CASSETTE_PLAY) ? 0x50 : 0x52, /* play (P) or record (R) */ +#endif + ((int) position / 60), + ((int) position % 60), + (int) position, + ((int) length / 60), + ((int) length % 60), + (int) length); + + // draw the cassette + device().machine().ui().draw_text_box(&device().machine().render().ui_container(), buf, JUSTIFY_LEFT, x, y, UI_BACKGROUND_COLOR); + + // make sure tape stops at end when playing + if ((m_state & CASSETTE_MASK_UISTATE) == CASSETTE_PLAY) + { + if ( m_cassette ) + { + if (position > length) + { + m_state = (cassette_state)(( m_state & ~CASSETTE_MASK_UISTATE ) | CASSETTE_STOPPED); + position = length; + } + } + } +} diff --git a/src/devices/imagedev/cassette.h b/src/devices/imagedev/cassette.h new file mode 100644 index 00000000000..188670922cc --- /dev/null +++ b/src/devices/imagedev/cassette.h @@ -0,0 +1,142 @@ +// license:BSD-3-Clause +// copyright-holders:Nathan Woods, Miodrag Milanovic +/********************************************************************* + + cassette.h + + Interface to the cassette image abstraction code + +*********************************************************************/ + +#ifndef CASSETTE_H +#define CASSETTE_H + +#include "formats/cassimg.h" + + +enum cassette_state +{ + /* this part of the state is controlled by the UI */ + CASSETTE_STOPPED = 0, + CASSETTE_PLAY = 1, + CASSETTE_RECORD = 2, + + /* this part of the state is controlled by drivers */ + CASSETTE_MOTOR_ENABLED = 0, + CASSETTE_MOTOR_DISABLED = 4, + CASSETTE_SPEAKER_ENABLED = 0, + CASSETTE_SPEAKER_MUTED = 8, + + /* masks */ + CASSETTE_MASK_UISTATE = 3, + CASSETTE_MASK_MOTOR = 4, + CASSETTE_MASK_SPEAKER = 8, + CASSETTE_MASK_DRVSTATE = 12 +}; + + +/*************************************************************************** + TYPE DEFINITIONS +***************************************************************************/ + +// ======================> cassette_image_device + +class cassette_image_device : public device_t, + public device_image_interface +{ +public: + // construction/destruction + cassette_image_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual ~cassette_image_device(); + + static void static_set_formats(device_t &device, const struct CassetteFormat* const *formats) { downcast(device).m_formats = formats; } + static void static_set_create_opts(device_t &device, const struct CassetteOptions *create_opts) { downcast(device).m_create_opts = create_opts; } + static void static_set_default_state(device_t &device, cassette_state default_state) { downcast(device).m_default_state = default_state; } + static void static_set_interface(device_t &device, const char *_interface) { downcast(device).m_interface = _interface; } + + // image-level overrides + virtual bool call_load(); + virtual bool call_create(int format_type, option_resolution *format_options); + virtual void call_unload(); + virtual void call_display(); + virtual bool call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry) { return load_software(swlist, swname, start_entry); } + + virtual iodevice_t image_type() const { return IO_CASSETTE; } + + virtual bool is_readable() const { return 1; } + virtual bool is_writeable() const { return 1; } + virtual bool is_creatable() const { return 1; } + virtual bool must_be_loaded() const { return 0; } + virtual bool is_reset_on_load() const { return 0; } + virtual const char *image_interface() const { return m_interface; } + virtual const char *file_extensions() const { return m_extension_list; } + virtual const option_guide *create_option_guide() const { return NULL; } + + // specific implementation + cassette_state get_state() { return m_state; } + void set_state(cassette_state state) { change_state(m_state, (cassette_state)(~0)); } + void change_state(cassette_state state, cassette_state mask); + + double input(); + void output(double value); + + cassette_image *get_image() { return m_cassette; } + double get_position(); + double get_length(); + void set_speed(double speed); + void set_channel(int channel); + void go_forward(); + void go_reverse(); + void seek(double time, int origin); + +protected: + bool is_motor_on(); + void update(); + + // device-level overrides + virtual void device_config_complete(); + virtual void device_start(); +private: + cassette_image *m_cassette; + cassette_state m_state; + double m_position; + double m_position_time; + INT32 m_value; + int m_channel; + double m_speed; // speed multiplier for tape speeds other than standard 1.875ips (used in adam driver) + int m_direction; // direction select + char m_extension_list[256]; + const struct CassetteFormat* const *m_formats; + const struct CassetteOptions *m_create_opts; + cassette_state m_default_state; + const char * m_interface; +}; + +// device type definition +extern const device_type CASSETTE; + +// device iterator +typedef device_type_iterator<&device_creator, cassette_image_device> cassette_device_iterator; + +/*************************************************************************** + DEVICE CONFIGURATION MACROS +***************************************************************************/ +#define MCFG_CASSETTE_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, CASSETTE, 0) + +#define MCFG_CASSETTE_MODIFY(_tag) \ + MCFG_DEVICE_MODIFY(_tag) + +#define MCFG_CASSETTE_FORMATS(_formats) \ + cassette_image_device::static_set_formats(*device, _formats); + +#define MCFG_CASSETTE_CREATE_OPTS(_create_opts) \ + cassette_image_device::static_set_create_opts(*device, _create_opts); + +#define MCFG_CASSETTE_DEFAULT_STATE(_state) \ + cassette_image_device::static_set_default_state(*device, (cassette_state) (_state)); + +#define MCFG_CASSETTE_INTERFACE(_interface) \ + cassette_image_device::static_set_interface(*device, _interface); + +#endif /* CASSETTE_H */ diff --git a/src/devices/imagedev/chd_cd.c b/src/devices/imagedev/chd_cd.c new file mode 100644 index 00000000000..b506ebfa784 --- /dev/null +++ b/src/devices/imagedev/chd_cd.c @@ -0,0 +1,143 @@ +// license:BSD-3-Clause +// copyright-holders:Nathan Woods, R. Belmont, Miodrag Milanovic +/********************************************************************* + + Code to interface the image code with CHD-CD core. + + Based on harddriv.c by Raphael Nabet 2003 + +*********************************************************************/ + +#include "emu.h" +#include "cdrom.h" +#include "chd_cd.h" + + +static OPTION_GUIDE_START(cd_option_guide) + OPTION_INT('K', "hunksize", "Hunk Bytes") +OPTION_GUIDE_END + +static const char cd_option_spec[] = "K512/1024/2048/[4096]"; + +// device type definition +const device_type CDROM = &device_creator; + +//------------------------------------------------- +// cdrom_image_device - constructor +//------------------------------------------------- + +cdrom_image_device::cdrom_image_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, CDROM, "CD-ROM Image", tag, owner, clock, "cdrom_image", __FILE__), + device_image_interface(mconfig, *this), + m_interface(NULL) +{ +} + +cdrom_image_device::cdrom_image_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_image_interface(mconfig, *this), + m_interface(NULL) +{ +} +//------------------------------------------------- +// cdrom_image_device - destructor +//------------------------------------------------- + +cdrom_image_device::~cdrom_image_device() +{ +} + +//------------------------------------------------- +// device_config_complete - perform any +// operations now that the configuration is +// complete +//------------------------------------------------- + +void cdrom_image_device::device_config_complete() +{ + m_extension_list = "chd,cue,toc,nrg,gdi,iso,cdr"; + + m_formatlist.append(*global_alloc(image_device_format("chdcd", "CD-ROM drive", m_extension_list, cd_option_spec))); + + // set brief and instance name + update_names(); +} + +const option_guide *cdrom_image_device::create_option_guide() const +{ + return cd_option_guide; +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void cdrom_image_device::device_start() +{ + // try to locate the CHD from a DISK_REGION + chd_file *chd = get_disk_handle( machine(), owner()->tag() ); + if( chd != NULL ) + { + m_cdrom_handle = cdrom_open( chd ); + } + else + { + m_cdrom_handle = NULL; + } +} + +void cdrom_image_device::device_stop() +{ + if (m_cdrom_handle) + cdrom_close(m_cdrom_handle); + if( m_self_chd.opened() ) + m_self_chd.close(); +} + +bool cdrom_image_device::call_load() +{ + chd_error err = (chd_error)0; + chd_file *chd = NULL; + + if (m_cdrom_handle) + cdrom_close(m_cdrom_handle); + + if (software_entry() == NULL) + { + if (strstr(m_image_name.c_str(), ".chd") && is_loaded()) { + err = m_self_chd.open( *image_core_file() ); /* CDs are never writeable */ + if ( err ) + goto error; + chd = &m_self_chd; + } + } else { + chd = get_disk_handle(device().machine(), device().subtag("cdrom").c_str()); + } + + /* open the CHD file */ + if (chd) { + m_cdrom_handle = cdrom_open( chd ); + } else { + m_cdrom_handle = cdrom_open(m_image_name.c_str()); + } + if ( ! m_cdrom_handle ) + goto error; + + return IMAGE_INIT_PASS; + +error: + if ( chd && chd == &m_self_chd ) + m_self_chd.close( ); + if ( err ) + seterror( IMAGE_ERROR_UNSPECIFIED, chd_file::error_string( err ) ); + return IMAGE_INIT_FAIL; +} + +void cdrom_image_device::call_unload() +{ + assert(m_cdrom_handle); + cdrom_close(m_cdrom_handle); + m_cdrom_handle = NULL; + if( m_self_chd.opened() ) + m_self_chd.close(); +} diff --git a/src/devices/imagedev/chd_cd.h b/src/devices/imagedev/chd_cd.h new file mode 100644 index 00000000000..5bdd7e4122a --- /dev/null +++ b/src/devices/imagedev/chd_cd.h @@ -0,0 +1,77 @@ +// license:BSD-3-Clause +// copyright-holders:Nathan Woods, R. Belmont, Miodrag Milanovic +/********************************************************************* + + chd_cd.h + + Interface to the CHD CDROM code + +*********************************************************************/ + +#ifndef CHD_CD_H +#define CHD_CD_H + +#include "cdrom.h" + +/*************************************************************************** + TYPE DEFINITIONS +***************************************************************************/ + +// ======================> cdrom_image_device + +class cdrom_image_device : public device_t, + public device_image_interface +{ +public: + // construction/destruction + cdrom_image_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + cdrom_image_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + virtual ~cdrom_image_device(); + + static void static_set_interface(device_t &device, const char *_interface) { downcast(device).m_interface = _interface; } + + // image-level overrides + virtual bool call_load(); + virtual void call_unload(); + virtual bool call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry) { load_software_part_region(*this, swlist, swname, start_entry ); return TRUE; } + + virtual iodevice_t image_type() const { return IO_CDROM; } + + virtual bool is_readable() const { return 1; } + virtual bool is_writeable() const { return 0; } + virtual bool is_creatable() const { return 0; } + virtual bool must_be_loaded() const { return 0; } + virtual bool is_reset_on_load() const { return 0; } + virtual const char *image_interface() const { return m_interface; } + virtual const char *file_extensions() const { return m_extension_list; } + virtual const option_guide *create_option_guide() const; + + // specific implementation + cdrom_file *get_cdrom_file() { return m_cdrom_handle; } +protected: + // device-level overrides + virtual void device_config_complete(); + virtual void device_start(); + virtual void device_stop(); + + chd_file m_self_chd; + cdrom_file *m_cdrom_handle; + const char *m_extension_list; + const char *m_interface; +}; + +// device type definition +extern const device_type CDROM; + +/*************************************************************************** + DEVICE CONFIGURATION MACROS +***************************************************************************/ + + +#define MCFG_CDROM_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, CDROM, 0) + +#define MCFG_CDROM_INTERFACE(_interface) \ + cdrom_image_device::static_set_interface(*device, _interface); + +#endif /* CHD_CD_H */ diff --git a/src/devices/imagedev/diablo.c b/src/devices/imagedev/diablo.c new file mode 100644 index 00000000000..d7d499ec523 --- /dev/null +++ b/src/devices/imagedev/diablo.c @@ -0,0 +1,274 @@ +// license:BSD-3-Clause +// copyright-holders:Juergen Buchmueller +/********************************************************** + * DIABLO drive image to hard disk interface + **********************************************************/ + +#include "emu.h" +#include "emuopts.h" +#include "harddisk.h" +#include "diablo.h" + + +static OPTION_GUIDE_START(dsk_option_guide) + OPTION_INT('C', "cylinders", "Cylinders") + OPTION_INT('H', "heads", "Heads") + OPTION_INT('S', "sectors", "Sectors") + OPTION_INT('L', "sectorlength", "Sector Words") + OPTION_INT('K', "hunksize", "Hunk Bytes") +OPTION_GUIDE_END + +static const char *dsk_option_spec = + "C1-[203]-1024;H1/[2]/4/8;S1-[12]-64;L267;K6408"; + + +// device type definition +const device_type DIABLO = &device_creator; + +//------------------------------------------------- +// diablo_image_device - constructor +//------------------------------------------------- + +diablo_image_device::diablo_image_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, DIABLO, "Diablo", tag, owner, clock, "diablo_image", __FILE__), + device_image_interface(mconfig, *this), + m_chd(NULL), + m_hard_disk_handle(NULL), + m_device_image_load(device_image_load_delegate()), + m_device_image_unload(device_image_func_delegate()), + m_interface(NULL) +{ +} + +//------------------------------------------------- +// diablo_image_device - destructor +//------------------------------------------------- + +diablo_image_device::~diablo_image_device() +{ +} + +//------------------------------------------------- +// device_config_complete - perform any +// operations now that the configuration is +// complete +//------------------------------------------------- + +void diablo_image_device::device_config_complete() +{ + m_formatlist.append(*global_alloc(image_device_format("chd", "CHD Hard drive", "chd,dsk", dsk_option_spec))); + + // set brief and instance name + update_names(); +} + +const option_guide *diablo_image_device::create_option_guide() const +{ + return dsk_option_guide; +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void diablo_image_device::device_start() +{ + m_chd = NULL; + + // try to locate the CHD from a DISK_REGION + chd_file *handle = get_disk_handle(machine(), tag()); + if (handle != NULL) + { + m_hard_disk_handle = hard_disk_open(handle); + } + else + { + m_hard_disk_handle = NULL; + } +} + +void diablo_image_device::device_stop() +{ + if (m_hard_disk_handle) + hard_disk_close(m_hard_disk_handle); +} + +bool diablo_image_device::call_load() +{ + int our_result; + + our_result = internal_load_dsk(); + /* Check if there is an image_load callback defined */ + if (!m_device_image_load.isnull()) + { + /* Let the override do some additional work/checks */ + our_result = m_device_image_load(*this); + } + return our_result; + +} + +bool diablo_image_device::call_create(int create_format, option_resolution *create_args) +{ + int err; + UINT32 sectorsize, hunksize; + UINT32 cylinders, heads, sectors, totalsectors; + std::string metadata; + + cylinders = option_resolution_lookup_int(create_args, 'C'); + heads = option_resolution_lookup_int(create_args, 'H'); + sectors = option_resolution_lookup_int(create_args, 'S'); + sectorsize = option_resolution_lookup_int(create_args, 'L') * sizeof(UINT16); + hunksize = option_resolution_lookup_int(create_args, 'K'); + + totalsectors = cylinders * heads * sectors; + + /* create the CHD file */ + chd_codec_type compression[4] = { CHD_CODEC_NONE }; + err = m_origchd.create(*image_core_file(), (UINT64)totalsectors * (UINT64)sectorsize, hunksize, sectorsize, compression); + if (err != CHDERR_NONE) + goto error; + + /* if we created the image and hence, have metadata to set, set the metadata */ + strprintf(metadata,HARD_DISK_METADATA_FORMAT, cylinders, heads, sectors, sectorsize); + err = m_origchd.write_metadata(HARD_DISK_METADATA_TAG, 0, metadata); + m_origchd.close(); + + if (err != CHDERR_NONE) + goto error; + + return internal_load_dsk(); + +error: + return IMAGE_INIT_FAIL; +} + +void diablo_image_device::call_unload() +{ + /* Check if there is an image_unload callback defined */ + if ( !m_device_image_unload.isnull() ) + { + m_device_image_unload(*this); + } + + if (m_hard_disk_handle != NULL) + { + hard_disk_close(m_hard_disk_handle); + m_hard_disk_handle = NULL; + } + + m_origchd.close(); + m_diffchd.close(); + m_chd = NULL; +} + +/*------------------------------------------------- + open_disk_diff - open a DISK diff file +-------------------------------------------------*/ + +static chd_error open_disk_diff(emu_options &options, const char *name, chd_file &source, chd_file &diff_chd) +{ + std::string fname = std::string(name).append(".dif"); + + /* try to open the diff */ + //printf("Opening differencing image file: %s\n", fname.c_str()); + emu_file diff_file(options.diff_directory(), OPEN_FLAG_READ | OPEN_FLAG_WRITE); + file_error filerr = diff_file.open(fname.c_str()); + if (filerr == FILERR_NONE) + { + std::string fullpath(diff_file.fullpath()); + diff_file.close(); + + //printf("Opening differencing image file: %s\n", fullpath.c_str()); + return diff_chd.open(fullpath.c_str(), true, &source); + } + + /* didn't work; try creating it instead */ + //printf("Creating differencing image: %s\n", fname.c_str()); + diff_file.set_openflags(OPEN_FLAG_READ | OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS); + filerr = diff_file.open(fname.c_str()); + if (filerr == FILERR_NONE) + { + std::string fullpath(diff_file.fullpath()); + diff_file.close(); + + /* create the CHD */ + //printf("Creating differencing image file: %s\n", fullpath.c_str()); + chd_codec_type compression[4] = { CHD_CODEC_NONE }; + chd_error err = diff_chd.create(fullpath.c_str(), source.logical_bytes(), source.hunk_bytes(), compression, source); + if (err != CHDERR_NONE) + return err; + + return diff_chd.clone_all_metadata(source); + } + + return CHDERR_FILE_NOT_FOUND; +} + +int diablo_image_device::internal_load_dsk() +{ + chd_error err = CHDERR_NONE; + + m_chd = NULL; + + if (m_hard_disk_handle) + hard_disk_close(m_hard_disk_handle); + + /* open the CHD file */ + if (software_entry() != NULL) + { + m_chd = get_disk_handle(device().machine(), device().subtag("harddriv").c_str()); + } + else + { + err = m_origchd.open(*image_core_file(), true); + if (err == CHDERR_NONE) + { + m_chd = &m_origchd; + } + else if (err == CHDERR_FILE_NOT_WRITEABLE) + { + err = m_origchd.open(*image_core_file(), false); + if (err == CHDERR_NONE) + { + err = open_disk_diff(device().machine().options(), basename_noext(), m_origchd, m_diffchd); + if (err == CHDERR_NONE) + { + m_chd = &m_diffchd; + } + } + } + } + + if (m_chd != NULL) + { + /* open the hard disk file */ + m_hard_disk_handle = hard_disk_open(m_chd); + if (m_hard_disk_handle != NULL) + return IMAGE_INIT_PASS; + } + + /* if we had an error, close out the CHD */ + m_origchd.close(); + m_diffchd.close(); + m_chd = NULL; + seterror(IMAGE_ERROR_UNSPECIFIED, chd_file::error_string(err)); + + return IMAGE_INIT_FAIL; +} + +/************************************* + * + * Get the CHD file (from the src/chd.c core) + * after an image has been opened with the hd core + * + *************************************/ + +chd_file *diablo_image_device::get_chd_file() +{ + chd_file *result = NULL; + hard_disk_file *hd_file = get_hard_disk_file(); + if (hd_file) + result = hard_disk_get_chd(hd_file); + return result; +} diff --git a/src/devices/imagedev/diablo.h b/src/devices/imagedev/diablo.h new file mode 100644 index 00000000000..11e0ffe091c --- /dev/null +++ b/src/devices/imagedev/diablo.h @@ -0,0 +1,90 @@ +// license:BSD-3-Clause +// copyright-holders:Juergen Buchmueller +/********************************************************** + * DIABLO drive image to hard disk interface + **********************************************************/ + +#ifndef _IMAGEDEV_DIABLO_H_ +#define _IMAGEDEV_DIABLO_H_ + +#include "harddisk.h" + +#define DIABLO_TAG(_id) "diablo"#_id + +/*************************************************************************** + TYPE DEFINITIONS +***************************************************************************/ + +// ======================> diablo_image_device + +class diablo_image_device : public device_t, + public device_image_interface +{ +public: + // construction/destruction + diablo_image_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual ~diablo_image_device(); + + static void static_set_device_load(device_t &device, device_image_load_delegate callback) { downcast(device).m_device_image_load = callback; } + static void static_set_device_unload(device_t &device, device_image_func_delegate callback) { downcast(device).m_device_image_unload = callback; } + static void static_set_interface(device_t &device, const char *_interface) { downcast(device).m_interface = _interface; } + + // image-level overrides + virtual bool call_load(); + virtual bool call_create(int create_format, option_resolution *create_args); + virtual void call_unload(); + virtual bool call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry) { load_software_part_region(*this, swlist, swname, start_entry ); return TRUE; } + + virtual iodevice_t image_type() const { return IO_HARDDISK; } + + virtual bool is_readable() const { return 1; } + virtual bool is_writeable() const { return 1; } + virtual bool is_creatable() const { return 0; } + virtual bool must_be_loaded() const { return 0; } + virtual bool is_reset_on_load() const { return 0; } + virtual const char *image_interface() const { return m_interface; } + virtual const char *file_extensions() const { return "chd,dsk"; } + virtual const option_guide *create_option_guide() const; + + // specific implementation + hard_disk_file *get_hard_disk_file() { return m_hard_disk_handle; } + chd_file *get_chd_file(); + +protected: + // device-level overrides + virtual void device_config_complete(); + virtual void device_start(); + virtual void device_stop(); + + int internal_load_dsk(); + + chd_file *m_chd; + chd_file m_origchd; /* handle to the original CHD */ + chd_file m_diffchd; /* handle to the diff CHD */ + hard_disk_file *m_hard_disk_handle; + + device_image_load_delegate m_device_image_load; + device_image_func_delegate m_device_image_unload; + const char * m_interface; +}; + +// device type definition +extern const device_type DIABLO; + +/*************************************************************************** + DEVICE CONFIGURATION MACROS +***************************************************************************/ + +#define MCFG_DIABLO_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, DIABLO, 0) + +#define MCFG_DIABLO_LOAD(_class,_method) \ + diablo_image_device::static_set_device_load(*device, device_image_load_delegate(&DEVICE_IMAGE_LOAD_NAME(_class,_method), #_class "::device_image_load_" #_method, downcast<_class *>(owner))); + +#define MCFG_DIABLO_UNLOAD(_class,_method) \ + diablo_image_device::static_set_device_unload(*device, device_image_func_delegate(&DEVICE_IMAGE_UNLOAD_NAME(_class,_method), #_class "::device_image_unload_" #_method, downcast<_class *>(owner))); + +#define MCFG_DIABLO_INTERFACE(_interface) \ + diablo_image_device::static_set_interface(*device, _interface); + +#endif /* _IMAGEDEV_DIABLO_H_ */ diff --git a/src/devices/imagedev/flopdrv.c b/src/devices/imagedev/flopdrv.c new file mode 100644 index 00000000000..8fafd466dae --- /dev/null +++ b/src/devices/imagedev/flopdrv.c @@ -0,0 +1,898 @@ +// license:BSD-3-Clause +// copyright-holders:Nathan Woods, Miodrag Milanovic +/* + This code handles the floppy drives. + All FDD actions should be performed using these functions. + + The functions are emulated and a disk image is used. + + Real disk operation: + - set unit id + + TODO: + - Override write protect if disk image has been opened in read mode +*/ + +#include "emu.h" +#include "formats/imageutl.h" +#include "flopdrv.h" + +#define VERBOSE 0 +#define LOG(x) do { if (VERBOSE) logerror x; } while (0) + +/*************************************************************************** + CONSTANTS +***************************************************************************/ + +#define FLOPDRVTAG "flopdrv" +#define LOG_FLOPPY 0 + +/*************************************************************************** + TYPE DEFINITIONS +***************************************************************************/ + +struct floppy_error_map +{ + floperr_t ferr; + image_error_t ierr; + const char *message; +}; + + + +/*************************************************************************** + GLOBAL VARIABLES +***************************************************************************/ + +static const floppy_error_map errmap[] = +{ + { FLOPPY_ERROR_SUCCESS, IMAGE_ERROR_SUCCESS }, + { FLOPPY_ERROR_INTERNAL, IMAGE_ERROR_INTERNAL }, + { FLOPPY_ERROR_UNSUPPORTED, IMAGE_ERROR_UNSUPPORTED }, + { FLOPPY_ERROR_OUTOFMEMORY, IMAGE_ERROR_OUTOFMEMORY }, + { FLOPPY_ERROR_INVALIDIMAGE, IMAGE_ERROR_INVALIDIMAGE } +}; + +/*************************************************************************** + IMPLEMENTATION +***************************************************************************/ + + +floppy_image_legacy *legacy_floppy_image_device::flopimg_get_image() +{ + return m_floppy; +} + +int legacy_floppy_image_device::flopimg_get_sectors_per_track(int side) +{ + floperr_t err; + int sector_count; + + if (!m_floppy) + return 0; + + err = floppy_get_sector_count(m_floppy, side, m_track, §or_count); + if (err) + return 0; + return sector_count; +} + +void legacy_floppy_image_device::flopimg_get_id_callback(chrn_id *id, int id_index, int side) +{ + int cylinder, sector, N; + unsigned long flags; + UINT32 sector_length; + + if (!m_floppy) + return; + + floppy_get_indexed_sector_info(m_floppy, side, m_track, id_index, &cylinder, &side, §or, §or_length, &flags); + + N = compute_log2(sector_length); + + id->C = cylinder; + id->H = side; + id->R = sector; + id->data_id = id_index; + id->flags = flags; + id->N = ((N >= 7) && (N <= 10)) ? N - 7 : 0; +} + +void legacy_floppy_image_device::log_readwrite(const char *name, int head, int track, int sector, const char *buf, int length) +{ + char membuf[1024]; + int i; + for (i = 0; i < length; i++) + sprintf(membuf + i*2, "%02x", (int) (UINT8) buf[i]); + logerror("%s: head=%i track=%i sector=%i buffer='%s'\n", name, head, track, sector, membuf); +} + +void legacy_floppy_image_device::floppy_drive_set_geometry_absolute(int tracks, int sides) +{ + m_max_track = tracks; + m_num_sides = sides; +} + +void legacy_floppy_image_device::floppy_drive_set_geometry(floppy_type_t type) +{ + floppy_drive_set_geometry_absolute(type.max_track_number, type.head_number); +} + +/* this is called on device init */ +void legacy_floppy_image_device::floppy_drive_init() +{ + /* initialise flags */ + m_flags = 0; + m_index_pulse_callback = NULL; + m_index_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(legacy_floppy_image_device::floppy_drive_index_callback),this)); + m_idx = 0; + + floppy_drive_set_geometry(((floppy_interface*)static_config())->floppy_type); + + /* initialise id index - not so important */ + m_id_index = 0; + /* initialise track */ + m_current_track = 0; + + /* default RPM */ + m_rpm = 300; + + m_controller = NULL; + + m_floppy_drive_type = FLOPPY_TYPE_REGULAR; +} + +/* index pulses at rpm/60 Hz, and stays high 1/20th of time */ +void legacy_floppy_image_device::floppy_drive_index_func() +{ + double ms = 1000.0 / ((double) m_rpm / 60.0); + + if (m_idx) + { + m_idx = 0; + m_index_timer->adjust(attotime::from_double(ms*19/20/1000.0)); + } + else + { + m_idx = 1; + m_index_timer->adjust(attotime::from_double(ms/20/1000.0)); + } + + m_out_idx_func(m_idx); + + if (m_index_pulse_callback) + m_index_pulse_callback(m_controller, this, m_idx); +} + +TIMER_CALLBACK_MEMBER(legacy_floppy_image_device::floppy_drive_index_callback) +{ + floppy_drive_index_func(); +} + +/*************************************************************************/ +/* IO_FLOPPY device functions */ + +/* set flag state */ +void legacy_floppy_image_device::floppy_drive_set_flag_state(int flag, int state) +{ + int prev_state; + int new_state; + + /* get old state */ + prev_state = m_flags & flag; + + /* set new state */ + m_flags &= ~flag; + if (state) + m_flags |= flag; + + /* get new state */ + new_state = m_flags & flag; + + /* changed state? */ + if (prev_state ^ new_state) + { + if (flag & FLOPPY_DRIVE_READY) + { + /* trigger state change callback */ + //m_out_rdy_func(new_state ? ASSERT_LINE : CLEAR_LINE); + } + } +} + +/* for pc, drive is always ready, for amstrad,pcw,spectrum it is only ready under +a fixed set of circumstances */ +/* use this to set ready state of drive */ +void legacy_floppy_image_device::floppy_drive_set_ready_state(int state, int flag) +{ + if (flag) + { + /* set ready only if drive is present, disk is in the drive, + and disk motor is on - for Amstrad, Spectrum and PCW*/ + + /* drive present? */ + /* disk inserted? */ + if (exists()) + { + if (m_mon == CLEAR_LINE) + { + /* set state */ + floppy_drive_set_flag_state(FLOPPY_DRIVE_READY, state); + return; + } + } + floppy_drive_set_flag_state(FLOPPY_DRIVE_READY, 0); + } + else + { + /* force ready state - for PC driver */ + floppy_drive_set_flag_state(FLOPPY_DRIVE_READY, state); + } +} + +/* get flag state */ +int legacy_floppy_image_device::floppy_drive_get_flag_state(int flag) +{ + int drive_flags; + int flags; + + flags = 0; + + drive_flags = m_flags; + + /* these flags are independent of a real drive/disk image */ + flags |= drive_flags & (FLOPPY_DRIVE_READY | FLOPPY_DRIVE_INDEX); + + flags &= flag; + + return flags; +} + + +void legacy_floppy_image_device::floppy_drive_seek(signed int signed_tracks) +{ + LOG(("seek from: %d delta: %d\n",m_current_track, signed_tracks)); + + /* update position */ + m_current_track+=signed_tracks; + + if (m_current_track<0) + { + m_current_track = 0; + } + else + if (m_current_track>=m_max_track) + { + m_current_track = m_max_track-1; + } + + /* set track 0 flag */ + m_tk00 = (m_current_track == 0) ? CLEAR_LINE : ASSERT_LINE; + //m_out_tk00_func(m_tk00); + + /* clear disk changed flag */ + m_dskchg = ASSERT_LINE; + //m_out_dskchg_func(m_dskchg); + + /* inform disk image of step operation so it can cache information */ + if (exists()) + m_track = m_current_track; + + m_id_index = 0; +} + + +/* this is not accurate. But it will do for now */ +int legacy_floppy_image_device::floppy_drive_get_next_id(int side, chrn_id *id) +{ + int spt; + + /* get sectors per track */ + spt = flopimg_get_sectors_per_track(side); + + /* set index */ + if ((m_id_index==(spt-1)) || (spt==0)) + { + floppy_drive_set_flag_state(FLOPPY_DRIVE_INDEX, 1); + } + else + { + floppy_drive_set_flag_state(FLOPPY_DRIVE_INDEX, 0); + } + + /* get id */ + if (spt!=0) + { + flopimg_get_id_callback(id, m_id_index, side); + } + + m_id_index++; + if (spt!=0) + m_id_index %= spt; + else + m_id_index = 0; + + return (spt == 0) ? 0 : 1; +} + +void legacy_floppy_image_device::floppy_drive_read_track_data_info_buffer(int side, void *ptr, int *length ) +{ + if (exists()) + { + if (!m_floppy) + return; + + floppy_read_track_data(m_floppy, side, m_track, ptr, *length); + } +} + +void legacy_floppy_image_device::floppy_drive_write_track_data_info_buffer(int side, const void *ptr, int *length ) +{ + if (exists()) + { + if (!m_floppy) + return; + + floppy_write_track_data(m_floppy, side, m_track, ptr, *length); + } +} + +void legacy_floppy_image_device::floppy_drive_format_sector(int side, int sector_index,int c,int h, int r, int n, int filler) +{ + if (exists()) + { +/* if (m_interface_.format_sector) + m_interface_.format_sector(img, side, sector_index,c, h, r, n, filler);*/ + } +} + +void legacy_floppy_image_device::floppy_drive_read_sector_data(int side, int index1, void *ptr, int length) +{ + if (exists()) + { + if (!m_floppy) + return; + + floppy_read_indexed_sector(m_floppy, side, m_track, index1, 0, ptr, length); + + if (LOG_FLOPPY) + log_readwrite("sector_read", side, m_track, index1, (const char *)ptr, length); + + } +} + +void legacy_floppy_image_device::floppy_drive_write_sector_data(int side, int index1, const void *ptr,int length, int ddam) +{ + if (exists()) + { + if (!m_floppy) + return; + + if (LOG_FLOPPY) + log_readwrite("sector_write", side, m_track, index1, (const char *)ptr, length); + + floppy_write_indexed_sector(m_floppy, side, m_track, index1, 0, ptr, length, ddam); + } +} + +void legacy_floppy_image_device::floppy_install_load_proc(void (*proc)(device_image_interface &image)) +{ + m_load_proc = proc; +} + +void legacy_floppy_image_device::floppy_install_unload_proc(void (*proc)(device_image_interface &image)) +{ + m_unload_proc = proc; +} + +/* set the callback for the index pulse */ +void legacy_floppy_image_device::floppy_drive_set_index_pulse_callback(void (*callback)(device_t *controller, device_t *img, int state)) +{ + m_index_pulse_callback = callback; +} + +int legacy_floppy_image_device::floppy_drive_get_current_track() +{ + return m_current_track; +} + +UINT64 legacy_floppy_image_device::floppy_drive_get_current_track_size(int head) +{ + int size = 0; + if (exists()) + { + size = floppy_get_track_size(m_floppy, head, m_current_track); + } + + return size; +} + +void legacy_floppy_image_device::floppy_drive_set_rpm(float rpm) +{ + m_rpm = rpm; +} + +void legacy_floppy_image_device::floppy_drive_set_controller(device_t *controller) +{ + m_controller = controller; +} + +int legacy_floppy_image_device::internal_floppy_device_load(int create_format, option_resolution *create_args) +{ + floperr_t err; + const struct FloppyFormat *floppy_options; + int floppy_flags, i; + const char *extension; + + device_image_interface *image = NULL; + interface(image); /* figure out the floppy options */ + floppy_options = ((floppy_interface*)static_config())->formats; + + if (has_been_created()) + { + /* creating an image */ + assert(create_format >= 0); + err = floppy_create((void *) image, &image_ioprocs, &floppy_options[create_format], create_args, &m_floppy); + if (err) + goto error; + } + else + { + /* opening an image */ + floppy_flags = !is_readonly() ? FLOPPY_FLAGS_READWRITE : FLOPPY_FLAGS_READONLY; + extension = filetype(); + err = floppy_open_choices((void *) image, &image_ioprocs, extension, floppy_options, floppy_flags, &m_floppy); + if (err) + goto error; + } + if (floppy_callbacks(m_floppy)->get_heads_per_disk && floppy_callbacks(m_floppy)->get_tracks_per_disk) + { + floppy_drive_set_geometry_absolute(floppy_get_tracks_per_disk(m_floppy),floppy_get_heads_per_disk(m_floppy)); + } + /* disk changed */ + m_dskchg = CLEAR_LINE; + + return IMAGE_INIT_PASS; + +error: + for (i = 0; i < ARRAY_LENGTH(errmap); i++) + { + if (err == errmap[i].ferr) + seterror(errmap[i].ierr, errmap[i].message); + } + return IMAGE_INIT_FAIL; +} + +TIMER_CALLBACK_MEMBER( legacy_floppy_image_device::set_wpt ) +{ + m_wpt = param; + //m_out_wpt_func(param); +} + +legacy_floppy_image_device *floppy_get_device(running_machine &machine,int drive) +{ + switch(drive) { + case 0 : return machine.device(FLOPPY_0); + case 1 : return machine.device(FLOPPY_1); + case 2 : return machine.device(FLOPPY_2); + case 3 : return machine.device(FLOPPY_3); + } + return NULL; +} + +int legacy_floppy_image_device::floppy_get_drive_type() +{ + return m_floppy_drive_type; +} + +void legacy_floppy_image_device::floppy_set_type(int ftype) +{ + m_floppy_drive_type = ftype; +} + +legacy_floppy_image_device *floppy_get_device_by_type(running_machine &machine,int ftype,int drive) +{ + int i; + int cnt = 0; + for (i=0;i<4;i++) { + legacy_floppy_image_device *disk = floppy_get_device(machine,i); + if (disk->floppy_get_drive_type()==ftype) { + if (cnt==drive) { + return disk; + } + cnt++; + } + } + return NULL; +} + +int floppy_get_drive(device_t *image) +{ + int drive =0; + if (strcmp(image->tag(), ":" FLOPPY_0) == 0) drive = 0; + if (strcmp(image->tag(), ":" FLOPPY_1) == 0) drive = 1; + if (strcmp(image->tag(), ":" FLOPPY_2) == 0) drive = 2; + if (strcmp(image->tag(), ":" FLOPPY_3) == 0) drive = 3; + return drive; +} + +int floppy_get_drive_by_type(legacy_floppy_image_device *image,int ftype) +{ + int i,drive =0; + for (i=0;i<4;i++) { + legacy_floppy_image_device *disk = floppy_get_device(image->machine(),i); + if (disk->floppy_get_drive_type()==ftype) { + if (image==disk) { + return drive; + } + drive++; + } + } + return drive; +} + +int floppy_get_count(running_machine &machine) +{ + int cnt = 0; + if (machine.device(FLOPPY_0)) cnt++; + if (machine.device(FLOPPY_1)) cnt++; + if (machine.device(FLOPPY_2)) cnt++; + if (machine.device(FLOPPY_3)) cnt++; + return cnt; +} + + +/* drive select 0 */ +WRITE_LINE_MEMBER( legacy_floppy_image_device::floppy_ds0_w ) +{ + if (state == CLEAR_LINE) + m_active = (m_drive_id == 0); +} + +/* drive select 1 */ +WRITE_LINE_MEMBER( legacy_floppy_image_device::floppy_ds1_w ) +{ + if (state == CLEAR_LINE) + m_active = (m_drive_id == 1); +} + +/* drive select 2 */ +WRITE_LINE_MEMBER( legacy_floppy_image_device::floppy_ds2_w ) +{ + if (state == CLEAR_LINE) + m_active = (m_drive_id == 2); +} + +/* drive select 3 */ +WRITE_LINE_MEMBER( legacy_floppy_image_device::floppy_ds3_w ) +{ + if (state == CLEAR_LINE) + m_active = (m_drive_id == 3); +} + +/* shortcut to write all four ds lines */ +WRITE8_MEMBER( legacy_floppy_image_device::floppy_ds_w ) +{ + floppy_ds0_w(BIT(data, 0)); + floppy_ds1_w(BIT(data, 1)); + floppy_ds2_w(BIT(data, 2)); + floppy_ds3_w(BIT(data, 3)); +} + +/* motor on, active low */ +WRITE_LINE_MEMBER( legacy_floppy_image_device::floppy_mon_w ) +{ + /* force off if there is no attached image */ + if (!exists()) + state = ASSERT_LINE; + + /* off -> on */ + if (m_mon && state == CLEAR_LINE) + { + m_idx = 0; + floppy_drive_index_func(); + } + + /* on -> off */ + else if (m_mon == CLEAR_LINE && state) + m_index_timer->adjust(attotime::zero); + + m_mon = state; +} + +/* direction */ +WRITE_LINE_MEMBER( legacy_floppy_image_device::floppy_drtn_w ) +{ + m_drtn = state; +} + +/* write data */ +WRITE_LINE_MEMBER( legacy_floppy_image_device::floppy_wtd_w ) +{ +} + +/* step */ +WRITE_LINE_MEMBER( legacy_floppy_image_device::floppy_stp_w ) +{ + /* move head one track when going from high to low and write gate is high */ + if (m_active && m_stp && state == CLEAR_LINE && m_wtg) + { + /* move head according to the direction line */ + if (m_drtn) + { + /* move head outward */ + if (m_current_track > 0) + m_current_track--; + + /* are we at track 0 now? */ + m_tk00 = (m_current_track == 0) ? CLEAR_LINE : ASSERT_LINE; + } + else + { + /* move head inward */ + if (m_current_track < m_max_track) + m_current_track++; + + /* we can't be at track 0 here, so reset the line */ + m_tk00 = ASSERT_LINE; + } + + /* update track 0 line with new status */ + //m_out_tk00_func(m_tk00); + } + + m_stp = state; +} + +/* write gate */ +WRITE_LINE_MEMBER( legacy_floppy_image_device::floppy_wtg_w ) +{ + m_wtg = state; +} + +/* write protect signal, active low */ +READ_LINE_MEMBER( legacy_floppy_image_device::floppy_wpt_r ) +{ + return m_wpt; +} + +/* track 0 detect */ +READ_LINE_MEMBER( legacy_floppy_image_device::floppy_tk00_r ) +{ + return m_tk00; +} + +/* disk changed */ +READ_LINE_MEMBER( legacy_floppy_image_device::floppy_dskchg_r ) +{ + return m_dskchg; +} + +/* 2-sided disk */ +READ_LINE_MEMBER( legacy_floppy_image_device::floppy_twosid_r ) +{ + if (m_floppy == NULL) + return ASSERT_LINE; + else + return !floppy_get_heads_per_disk(m_floppy); +} + +READ_LINE_MEMBER( legacy_floppy_image_device::floppy_index_r ) +{ + return m_idx; +} + +READ_LINE_MEMBER( legacy_floppy_image_device::floppy_ready_r ) +{ + return !(floppy_drive_get_flag_state(FLOPPY_DRIVE_READY) == FLOPPY_DRIVE_READY); +} + +// device type definition +const device_type LEGACY_FLOPPY = &device_creator; + +//------------------------------------------------- +// legacy_floppy_image_device - constructor +//------------------------------------------------- + +legacy_floppy_image_device::legacy_floppy_image_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, LEGACY_FLOPPY, "Floppy Disk", tag, owner, clock, "legacy_floppy_image", __FILE__), + device_image_interface(mconfig, *this), + m_out_idx_func(*this), + m_drtn(0), + m_stp(0), + m_wtg(0), + m_mon(0), + m_idx(0), + m_tk00(0), + m_wpt(0), + m_rdy(0), + m_dskchg(0), + m_drive_id(0), + m_active(0), + m_flags(0), + m_max_track(0), + m_num_sides(0), + m_current_track(0), + m_index_pulse_callback(NULL), + m_rpm(0.0f), + m_id_index(0), + m_controller(NULL), + m_floppy(NULL), + m_track(0), + m_load_proc(NULL), + m_unload_proc(NULL), + m_floppy_drive_type(0) +{ + memset(&m_extension_list,0,sizeof(m_extension_list)); +} + +legacy_floppy_image_device::legacy_floppy_image_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_image_interface(mconfig, *this), + m_out_idx_func(*this), + m_drtn(0), + m_stp(0), + m_wtg(0), + m_mon(0), + m_idx(0), + m_tk00(0), + m_wpt(0), + m_rdy(0), + m_dskchg(0), + m_drive_id(0), + m_active(0), + m_flags(0), + m_max_track(0), + m_num_sides(0), + m_current_track(0), + m_index_pulse_callback(NULL), + m_rpm(0.0f), + m_id_index(0), + m_controller(NULL), + m_floppy(NULL), + m_track(0), + m_load_proc(NULL), + m_unload_proc(NULL), + m_floppy_drive_type(0) +{ + memset(&m_extension_list,0,sizeof(m_extension_list)); +} + +//------------------------------------------------- +// legacy_floppy_image_device - destructor +//------------------------------------------------- + +legacy_floppy_image_device::~legacy_floppy_image_device() +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void legacy_floppy_image_device::device_start() +{ + m_config = (const floppy_interface*)static_config(); + floppy_drive_init(); + + m_drive_id = floppy_get_drive(this); + m_active = FALSE; + + /* resolve callbacks */ + m_out_idx_func.resolve_safe(); + //m_in_mon_func.resolve(m_config->in_mon_func, *this); + //m_out_tk00_func.resolve(m_config->out_tk00_func, *this); + //m_out_wpt_func.resolve(m_config->out_wpt_func, *this); + //m_out_rdy_func.resolve(m_config->out_rdy_func, *this); +// m_out_dskchg_func.resolve(m_config->out_dskchg_func, *this); + + /* by default we are not write-protected */ + m_wpt = ASSERT_LINE; + //m_out_wpt_func(m_wpt); + + /* not at track 0 */ + m_tk00 = ASSERT_LINE; + //m_out_tk00_func(m_tk00); + + /* motor off */ + m_mon = ASSERT_LINE; + + /* disk changed */ + m_dskchg = CLEAR_LINE; +// m_out_dskchg_func(m_dskchg); +} + + +//------------------------------------------------- +// device_config_complete - perform any +// operations now that the configuration is +// complete +//------------------------------------------------- + +void legacy_floppy_image_device::device_config_complete() +{ + m_extension_list[0] = '\0'; + const struct FloppyFormat *floppy_options = ((floppy_interface*)static_config())->formats; + for (int i = 0; floppy_options[i].construct; i++) + { + // only add if creatable + if (floppy_options[i].param_guidelines) { + // allocate a new format and append it to the list + m_formatlist.append(*global_alloc(image_device_format(floppy_options[i].name, floppy_options[i].description, floppy_options[i].extensions, floppy_options[i].param_guidelines))); + } + image_specify_extension( m_extension_list, 256, floppy_options[i].extensions ); + } + + // set brief and instance name + update_names(); +} + +bool legacy_floppy_image_device::call_create(int format_type, option_resolution *format_options) +{ + return internal_floppy_device_load(format_type, format_options); +} + +bool legacy_floppy_image_device::call_load() +{ + int retVal = internal_floppy_device_load(-1, NULL); + if (retVal==IMAGE_INIT_PASS) { + /* if we have one of our hacky unload procs, call it */ + if (m_load_proc) + m_load_proc(*this); + } + + /* push disk halfway into drive */ + m_wpt = CLEAR_LINE; + //m_out_wpt_func(m_wpt); + + /* set timer for disk load */ + int next_wpt; + + if (!is_readonly()) + next_wpt = ASSERT_LINE; + else + next_wpt = CLEAR_LINE; + + machine().scheduler().timer_set(attotime::from_msec(250), timer_expired_delegate(FUNC(legacy_floppy_image_device::set_wpt),this), next_wpt); + + return retVal; +} + +void legacy_floppy_image_device::call_unload() +{ + if (m_unload_proc) + m_unload_proc(*this); + + floppy_close(m_floppy); + m_floppy = NULL; + + /* disk changed */ + m_dskchg = CLEAR_LINE; + //m_out_dskchg_func(m_dskchg); + + /* pull disk halfway out of drive */ + m_wpt = CLEAR_LINE; + //m_out_wpt_func(m_wpt); + + /* set timer for disk eject */ + machine().scheduler().timer_set(attotime::from_msec(250), timer_expired_delegate(FUNC(legacy_floppy_image_device::set_wpt),this), ASSERT_LINE); +} + +bool legacy_floppy_image_device::is_creatable() const +{ + int cnt = 0; + if (static_config() ) + { + const struct FloppyFormat *floppy_options = ((floppy_interface*)static_config())->formats; + int i; + for ( i = 0; floppy_options[i].construct; i++ ) { + if(floppy_options[i].param_guidelines) cnt++; + } + } + return (cnt>0) ? 1 : 0; +} + +const char *legacy_floppy_image_device::image_interface() const +{ + return ((floppy_interface *)static_config())->interface; +} diff --git a/src/devices/imagedev/flopdrv.h b/src/devices/imagedev/flopdrv.h new file mode 100644 index 00000000000..e2511ca9a50 --- /dev/null +++ b/src/devices/imagedev/flopdrv.h @@ -0,0 +1,266 @@ +// license:BSD-3-Clause +// copyright-holders:Nathan Woods, Miodrag Milanovic +/* flopdrv provides simple emulation of a disc drive */ +/* the 8271, upd765 and wd179x use this */ + +#ifndef __FLOPDRV_H__ +#define __FLOPDRV_H__ + +#include "formats/flopimg.h" + +#define FLOPPY_TYPE_REGULAR 0 +#define FLOPPY_TYPE_APPLE 1 +#define FLOPPY_TYPE_SONY 2 + +#define FLOPPY_DRIVE_2_8_INCH 1 +#define FLOPPY_DRIVE_3_INCH 2 +#define FLOPPY_DRIVE_3_5_INCH 3 +#define FLOPPY_DRIVE_5_25_INCH 4 +#define FLOPPY_DRIVE_8_INCH 5 + +// Maximum supported density +#define FLOPPY_DRIVE_SD 1 +#define FLOPPY_DRIVE_DD 2 +#define FLOPPY_DRIVE_QD 3 +#define FLOPPY_DRIVE_HD 4 +#define FLOPPY_DRIVE_ED 5 + +#define FLOPPY_STANDARD_3_SSDD { FLOPPY_DRIVE_3_INCH, 1, 42, FLOPPY_DRIVE_DD } +#define FLOPPY_STANDARD_3_DSDD { FLOPPY_DRIVE_3_INCH, 2, 42, FLOPPY_DRIVE_DD } +#define FLOPPY_STANDARD_3_5_SSDD { FLOPPY_DRIVE_3_5_INCH, 1, 83, FLOPPY_DRIVE_DD } +#define FLOPPY_STANDARD_3_5_DSDD { FLOPPY_DRIVE_3_5_INCH, 2, 83, FLOPPY_DRIVE_DD } +#define FLOPPY_STANDARD_3_5_DSHD { FLOPPY_DRIVE_3_5_INCH, 2, 83, FLOPPY_DRIVE_HD } +#define FLOPPY_STANDARD_3_5_DSED { FLOPPY_DRIVE_3_5_INCH, 2, 83, FLOPPY_DRIVE_ED } +#define FLOPPY_STANDARD_5_25_SSSD_35 { FLOPPY_DRIVE_5_25_INCH, 1, 37, FLOPPY_DRIVE_SD } +#define FLOPPY_STANDARD_5_25_DSSD_35 { FLOPPY_DRIVE_5_25_INCH, 2, 37, FLOPPY_DRIVE_SD } +#define FLOPPY_STANDARD_5_25_SSSD { FLOPPY_DRIVE_5_25_INCH, 1, 42, FLOPPY_DRIVE_SD } +#define FLOPPY_STANDARD_5_25_DSSD { FLOPPY_DRIVE_5_25_INCH, 2, 42, FLOPPY_DRIVE_SD } +#define FLOPPY_STANDARD_5_25_SSDD_40 { FLOPPY_DRIVE_5_25_INCH, 1, 42, FLOPPY_DRIVE_DD } +#define FLOPPY_STANDARD_5_25_SSDD_80 { FLOPPY_DRIVE_5_25_INCH, 1, 83, FLOPPY_DRIVE_DD } +#define FLOPPY_STANDARD_5_25_DSDD_40 { FLOPPY_DRIVE_5_25_INCH, 2, 42, FLOPPY_DRIVE_DD } +#define FLOPPY_STANDARD_5_25_SSDD { FLOPPY_DRIVE_5_25_INCH, 1, 83, FLOPPY_DRIVE_DD } +#define FLOPPY_STANDARD_5_25_DSDD { FLOPPY_DRIVE_5_25_INCH, 2, 83, FLOPPY_DRIVE_DD } +#define FLOPPY_STANDARD_5_25_DSQD { FLOPPY_DRIVE_5_25_INCH, 2, 83, FLOPPY_DRIVE_QD } +#define FLOPPY_STANDARD_5_25_DSHD { FLOPPY_DRIVE_5_25_INCH, 2, 83, FLOPPY_DRIVE_HD } +#define FLOPPY_STANDARD_8_SSSD { FLOPPY_DRIVE_8_INCH, 1, 77, FLOPPY_DRIVE_SD } +#define FLOPPY_STANDARD_8_DSSD { FLOPPY_DRIVE_8_INCH, 2, 77, FLOPPY_DRIVE_SD } +#define FLOPPY_STANDARD_8_DSDD { FLOPPY_DRIVE_8_INCH, 2, 77, FLOPPY_DRIVE_DD } + +/*************************************************************************** + TYPE DEFINITIONS +***************************************************************************/ + +// ======================> floppy_type_t + +struct floppy_type_t +{ + UINT8 media_size; + UINT8 head_number; + UINT8 max_track_number; + UINT8 max_density; +}; + +// ======================> floppy_interface + +struct floppy_interface +{ + floppy_type_t floppy_type; + const struct FloppyFormat *formats; + const char *interface; +}; + +struct chrn_id +{ + unsigned char C; + unsigned char H; + unsigned char R; + unsigned char N; + int data_id; // id for read/write data command + unsigned long flags; +}; + +/* set if drive is ready */ +#define FLOPPY_DRIVE_READY 0x0010 +/* set if index has just occurred */ +#define FLOPPY_DRIVE_INDEX 0x0020 + +#define MCFG_LEGACY_FLOPPY_IDX_CB(_devcb) \ + devcb = &legacy_floppy_image_device::set_out_idx_func(*device, DEVCB_##_devcb); + +class legacy_floppy_image_device : public device_t, + public device_image_interface +{ +public: + // construction/destruction + legacy_floppy_image_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + legacy_floppy_image_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + ~legacy_floppy_image_device(); + + template static devcb_base &set_out_idx_func(device_t &device, _Object object) { return downcast(device).m_out_idx_func.set_callback(object); } + + virtual bool call_load(); + virtual bool call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry) { return load_software(swlist, swname, start_entry); } + virtual bool call_create(int format_type, option_resolution *format_options); + virtual void call_unload(); + + virtual iodevice_t image_type() const { return IO_FLOPPY; } + + virtual bool is_readable() const { return 1; } + virtual bool is_writeable() const { return 1; } + virtual bool is_creatable() const; + virtual bool must_be_loaded() const { return 0; } + virtual bool is_reset_on_load() const { return 0; } + virtual const char *image_interface() const; + virtual const char *file_extensions() const { return m_extension_list; } + virtual const option_guide *create_option_guide() const { return floppy_option_guide; } + + floppy_image_legacy *flopimg_get_image(); + void floppy_drive_set_geometry(floppy_type_t type); + void floppy_drive_set_flag_state(int flag, int state); + void floppy_drive_set_ready_state(int state, int flag); + int floppy_drive_get_flag_state(int flag); + void floppy_drive_seek(signed int signed_tracks); + int floppy_drive_get_next_id(int side, chrn_id *id); + void floppy_drive_read_track_data_info_buffer(int side, void *ptr, int *length ); + void floppy_drive_write_track_data_info_buffer(int side, const void *ptr, int *length ); + void floppy_drive_format_sector(int side, int sector_index,int c,int h, int r, int n, int filler); + void floppy_drive_read_sector_data(int side, int index1, void *ptr, int length); + void floppy_drive_write_sector_data(int side, int index1, const void *ptr,int length, int ddam); + void floppy_install_load_proc(void (*proc)(device_image_interface &image)); + void floppy_install_unload_proc(void (*proc)(device_image_interface &image)); + void floppy_drive_set_index_pulse_callback(void (*callback)(device_t *controller,device_t *image, int state)); + int floppy_drive_get_current_track(); + UINT64 floppy_drive_get_current_track_size(int head); + void floppy_drive_set_rpm(float rpm); + void floppy_drive_set_controller(device_t *controller); + int floppy_get_drive_type(); + void floppy_set_type(int ftype); + WRITE_LINE_MEMBER( floppy_ds0_w ); + WRITE_LINE_MEMBER( floppy_ds1_w ); + WRITE_LINE_MEMBER( floppy_ds2_w ); + WRITE_LINE_MEMBER( floppy_ds3_w ); + WRITE8_MEMBER( floppy_ds_w ); + WRITE_LINE_MEMBER( floppy_mon_w ); + WRITE_LINE_MEMBER( floppy_drtn_w ); + WRITE_LINE_MEMBER( floppy_wtd_w ); + WRITE_LINE_MEMBER( floppy_stp_w ); + WRITE_LINE_MEMBER( floppy_wtg_w ); + READ_LINE_MEMBER( floppy_wpt_r ); + READ_LINE_MEMBER( floppy_tk00_r ); + READ_LINE_MEMBER( floppy_dskchg_r ); + READ_LINE_MEMBER( floppy_twosid_r ); + READ_LINE_MEMBER( floppy_index_r ); + READ_LINE_MEMBER( floppy_ready_r ); + + +private: + int flopimg_get_sectors_per_track(int side); + void flopimg_get_id_callback(chrn_id *id, int id_index, int side); + void log_readwrite(const char *name, int head, int track, int sector, const char *buf, int length); + void floppy_drive_set_geometry_absolute(int tracks, int sides); + TIMER_CALLBACK_MEMBER(floppy_drive_index_callback); + void floppy_drive_init(); + void floppy_drive_index_func(); + TIMER_CALLBACK(floppy_drive_index_callback); + int internal_floppy_device_load(int create_format, option_resolution *create_args); + TIMER_CALLBACK_MEMBER( set_wpt ); + +protected: + // device overrides + virtual void device_config_complete(); + virtual void device_start(); + + /* callbacks */ + devcb_write_line m_out_idx_func; + + /* state of input lines */ + int m_drtn; /* direction */ + int m_stp; /* step */ + int m_wtg; /* write gate */ + int m_mon; /* motor on */ + + /* state of output lines */ + int m_idx; /* index pulse */ + int m_tk00; /* track 00 */ + int m_wpt; /* write protect */ + int m_rdy; /* ready */ + int m_dskchg; /* disk changed */ + + /* drive select logic */ + int m_drive_id; + int m_active; + + const floppy_interface *m_config; + + /* flags */ + int m_flags; + /* maximum track allowed */ + int m_max_track; + /* num sides */ + int m_num_sides; + /* current track - this may or may not relate to the present cylinder number + stored by the fdc */ + int m_current_track; + + /* index pulse timer */ + emu_timer *m_index_timer; + /* index pulse callback */ + void (*m_index_pulse_callback)(device_t *controller,device_t *image, int state); + /* rotation per minute => gives index pulse frequency */ + float m_rpm; + + int m_id_index; + + device_t *m_controller; + + floppy_image_legacy *m_floppy; + int m_track; + void (*m_load_proc)(device_image_interface &image); + void (*m_unload_proc)(device_image_interface &image); + int m_floppy_drive_type; + + char m_extension_list[256]; +}; + +// device type definition +extern const device_type LEGACY_FLOPPY; + + + +legacy_floppy_image_device *floppy_get_device(running_machine &machine,int drive); +legacy_floppy_image_device *floppy_get_device_by_type(running_machine &machine,int ftype,int drive); +int floppy_get_drive(device_t *image); +int floppy_get_drive_by_type(legacy_floppy_image_device *image,int ftype); +int floppy_get_count(running_machine &machine); + + +/*************************************************************************** + DEVICE CONFIGURATION MACROS +***************************************************************************/ +#define FLOPPY_0 "floppy0" +#define FLOPPY_1 "floppy1" +#define FLOPPY_2 "floppy2" +#define FLOPPY_3 "floppy3" + + +#define MCFG_LEGACY_FLOPPY_DRIVE_ADD(_tag, _config) \ + MCFG_DEVICE_ADD(_tag, LEGACY_FLOPPY, 0) \ + MCFG_DEVICE_CONFIG(_config) + +#define MCFG_LEGACY_FLOPPY_4_DRIVES_ADD(_config) \ + MCFG_DEVICE_ADD(FLOPPY_0, LEGACY_FLOPPY, 0) \ + MCFG_DEVICE_CONFIG(_config) \ + MCFG_DEVICE_ADD(FLOPPY_1, LEGACY_FLOPPY, 0) \ + MCFG_DEVICE_CONFIG(_config) \ + MCFG_DEVICE_ADD(FLOPPY_2, LEGACY_FLOPPY, 0) \ + MCFG_DEVICE_CONFIG(_config) \ + MCFG_DEVICE_ADD(FLOPPY_3, LEGACY_FLOPPY, 0) \ + MCFG_DEVICE_CONFIG(_config) + +#define MCFG_LEGACY_FLOPPY_2_DRIVES_ADD(_config) \ + MCFG_DEVICE_ADD(FLOPPY_0, LEGACY_FLOPPY, 0) \ + MCFG_DEVICE_CONFIG(_config) \ + MCFG_DEVICE_ADD(FLOPPY_1, LEGACY_FLOPPY, 0) \ + MCFG_DEVICE_CONFIG(_config) + +#endif /* __FLOPDRV_H__ */ diff --git a/src/devices/imagedev/floppy.c b/src/devices/imagedev/floppy.c new file mode 100644 index 00000000000..b85f60d7ef7 --- /dev/null +++ b/src/devices/imagedev/floppy.c @@ -0,0 +1,2132 @@ +// license:BSD-3-Clause +// copyright-holders:Nathan Woods, Olivier Galibert, Miodrag Milanovic +/********************************************************************* + + + +*********************************************************************/ + +#include "emu.h" +#include "emuopts.h" +#include "zippath.h" +#include "floppy.h" +#include "formats/imageutl.h" +#include "ui/filesel.h" + +/* + Debugging flags. Set to 0 or 1. +*/ + +// Show step operation +#define TRACE_STEP 1 + +#define FLOPSND_TAG "floppysound" + +// device type definition +const device_type FLOPPY_CONNECTOR = &device_creator; + +// generic 3" drives +const device_type FLOPPY_3_SSDD = &device_creator; +const device_type FLOPPY_3_DSDD = &device_creator; + +// generic 3.5" drives +const device_type FLOPPY_35_SSDD = &device_creator; +const device_type FLOPPY_35_DD = &device_creator; +const device_type FLOPPY_35_HD = &device_creator; +const device_type FLOPPY_35_ED = &device_creator; + +// generic 5.25" drives +const device_type FLOPPY_525_SSSD_35T = &device_creator; +const device_type FLOPPY_525_SD_35T = &device_creator; +const device_type FLOPPY_525_SSSD = &device_creator; +const device_type FLOPPY_525_SD = &device_creator; +const device_type FLOPPY_525_SSDD = &device_creator; +const device_type FLOPPY_525_DD = &device_creator; +const device_type FLOPPY_525_SSQD = &device_creator; +const device_type FLOPPY_525_QD = &device_creator; +const device_type FLOPPY_525_HD = &device_creator; + +// generic 8" drives +const device_type FLOPPY_8_SSSD = &device_creator; +const device_type FLOPPY_8_DSSD = &device_creator; +const device_type FLOPPY_8_SSDD = &device_creator; +const device_type FLOPPY_8_DSDD = &device_creator; + +// Epson 3.5" drives +#if 0 +const device_type EPSON_SMD_110 = &device_creator; +const device_type EPSON_SMD_120 = &device_creator; +const device_type EPSON_SMD_125 = &device_creator; +const device_type EPSON_SMD_130 = &device_creator; +const device_type EPSON_SMD_140 = &device_creator; +const device_type EPSON_SMD_150 = &device_creator; +const device_type EPSON_SMD_160 = &device_creator; +#endif +const device_type EPSON_SMD_165 = &device_creator; +#if 0 +const device_type EPSON_SMD_170 = &device_creator; +const device_type EPSON_SMD_180 = &device_creator; +const device_type EPSON_SMD_240L = &device_creator; +const device_type EPSON_SMD_280HL = &device_creator; +const device_type EPSON_SMD_440L = &device_creator; +const device_type EPSON_SMD_449L = &device_creator; +const device_type EPSON_SMD_480LM = &device_creator; +const device_type EPSON_SMD_489M = &device_creator; +#endif + +// Epson 5.25" drives +#if 0 +const device_type EPSON_SD_311 = &device_creator; +#endif +const device_type EPSON_SD_320 = &device_creator; +const device_type EPSON_SD_321 = &device_creator; +#if 0 +const device_type EPSON_SD_521L = &device_creator; +const device_type EPSON_SD_525 = &device_creator; +const device_type EPSON_SD_543 = &device_creator; +const device_type EPSON_SD_545 = &device_creator; +const device_type EPSON_SD_560 = &device_creator; +const device_type EPSON_SD_580L = &device_creator; +const device_type EPSON_SD_581L = &device_creator; +const device_type EPSON_SD_621L = &device_creator; +const device_type EPSON_SD_680L = &device_creator; +#endif + +// Sony 3.5" drives +const device_type SONY_OA_D31V = &device_creator; +const device_type SONY_OA_D32W = &device_creator; +const device_type SONY_OA_D32V = &device_creator; + +// TEAC 5.25" drives +#if 0 +const device_type TEAC_FD_55A = &device_creator; +const device_type TEAC_FD_55B = &device_creator; +#endif +const device_type TEAC_FD_55E = &device_creator; +const device_type TEAC_FD_55F = &device_creator; +const device_type TEAC_FD_55G = &device_creator; + +// ALPS 5.25" drives +const device_type ALPS_3255190x = &device_creator; + + +const floppy_format_type floppy_image_device::default_floppy_formats[] = { + FLOPPY_D88_FORMAT, + FLOPPY_DFI_FORMAT, + FLOPPY_IMD_FORMAT, + FLOPPY_IPF_FORMAT, + FLOPPY_MFI_FORMAT, + FLOPPY_MFM_FORMAT, + FLOPPY_TD0_FORMAT, + FLOPPY_CQM_FORMAT, + FLOPPY_DSK_FORMAT, + NULL +}; + +floppy_connector::floppy_connector(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, FLOPPY_CONNECTOR, "Floppy drive connector abstraction", tag, owner, clock, "floppy_connector", __FILE__), + device_slot_interface(mconfig, *this), + m_enable_sound(false) +{ +} + +floppy_connector::~floppy_connector() +{ +} + +void floppy_connector::set_formats(const floppy_format_type *_formats) +{ + formats = _formats; +} + +void floppy_connector::device_start() +{ +} + +void floppy_connector::device_config_complete() +{ + floppy_image_device *dev = dynamic_cast(get_card_device()); + if(dev) + { + dev->set_formats(formats); + dev->enable_sound(m_enable_sound); + } +} + +floppy_image_device *floppy_connector::get_device() +{ + return dynamic_cast(get_card_device()); +} + +//------------------------------------------------- +// floppy_image_device - constructor +//------------------------------------------------- + +floppy_image_device::floppy_image_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_image_interface(mconfig, *this), + device_slot_card_interface(mconfig, *this), + image(NULL), + fif_list(NULL), + m_make_sound(false) +{ + extension_list[0] = '\0'; + m_err = IMAGE_ERROR_INVALIDIMAGE; +} + +//------------------------------------------------- +// floppy_image_device - destructor +//------------------------------------------------- + +floppy_image_device::~floppy_image_device() +{ + for(floppy_image_format_t *format = fif_list; format; ) { + floppy_image_format_t* tmp_format = format; + format = format->next; + delete tmp_format; + } + fif_list = NULL; +} + +void floppy_image_device::setup_load_cb(load_cb cb) +{ + cur_load_cb = cb; +} + +void floppy_image_device::setup_unload_cb(unload_cb cb) +{ + cur_unload_cb = cb; +} + +void floppy_image_device::setup_index_pulse_cb(index_pulse_cb cb) +{ + cur_index_pulse_cb = cb; +} + +void floppy_image_device::setup_ready_cb(ready_cb cb) +{ + cur_ready_cb = cb; +} + +void floppy_image_device::setup_wpt_cb(wpt_cb cb) +{ + cur_wpt_cb = cb; +} + +void floppy_image_device::set_formats(const floppy_format_type *formats) +{ + extension_list[0] = '\0'; + fif_list = NULL; + for(int cnt=0; formats[cnt]; cnt++) + { + // allocate a new format + floppy_image_format_t *fif = formats[cnt](); + if(!fif_list) + fif_list = fif; + else + fif_list->append(fif); + + m_formatlist.append(*global_alloc(image_device_format(fif->name(), fif->description(), fif->extensions(), ""))); + + image_specify_extension( extension_list, 256, fif->extensions() ); + } + + // set brief and instance name + update_names(); +} + +floppy_image_format_t *floppy_image_device::get_formats() const +{ + return fif_list; +} + +floppy_image_format_t *floppy_image_device::get_load_format() const +{ + return input_format; +} + +void floppy_image_device::device_config_complete() +{ + update_names(); +} + +void floppy_image_device::set_rpm(float _rpm) +{ + if(rpm == _rpm) + return; + + rpm = _rpm; + rev_time = attotime::from_double(60/rpm); + floppy_ratio_1 = int(1000.0f*rpm/300.0f+0.5f); +} + +void floppy_image_device::setup_write(floppy_image_format_t *_output_format) +{ + output_format = _output_format; + commit_image(); +} + +void floppy_image_device::commit_image() +{ + image_dirty = false; + if(!output_format || !output_format->supports_save()) + return; + io_generic io; + // Do _not_ remove this cast otherwise the pointer will be incorrect when used by the ioprocs. + io.file = (device_image_interface *)this; + io.procs = &image_ioprocs; + io.filler = 0xff; + + file_error err = core_truncate(image_core_file(), 0); + if (err != 0) + popmessage("Error, unable to truncate image: %d", err); + + output_format->save(&io, image); +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void floppy_image_device::device_start() +{ + rpm = 0; + motor_always_on = false; + + idx = 0; + + /* motor off */ + mon = 1; + + cyl = 0; + subcyl = 0; + ss = 0; + stp = 1; + wpt = 0; + dskchg = exists() ? 1 : 0; + index_timer = timer_alloc(0); + image_dirty = false; + ready = true; + ready_counter = 0; + + setup_characteristics(); + + if (m_make_sound) m_sound_out = subdevice(FLOPSND_TAG); + + save_item(NAME(cyl)); + save_item(NAME(subcyl)); +} + +void floppy_image_device::device_reset() +{ + if (m_make_sound) + { + // Have we loaded all samples? Otherwise mute the floppy. + m_make_sound = m_sound_out->samples_loaded(); + } + + revolution_start_time = attotime::never; + revolution_count = 0; + mon = 1; + if(!ready) { + ready = true; + if(!cur_ready_cb.isnull()) + cur_ready_cb(this, ready); + } + if(motor_always_on) + mon_w(0); +} + +void floppy_image_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + index_resync(); +} + +floppy_image_format_t *floppy_image_device::identify(std::string filename) +{ + core_file *fd; + std::string revised_path; + + file_error err = zippath_fopen(filename.c_str(), OPEN_FLAG_READ, fd, revised_path); + if(err) { + seterror(IMAGE_ERROR_INVALIDIMAGE, "Unable to open the image file"); + return 0; + } + + io_generic io; + io.file = fd; + io.procs = &corefile_ioprocs_noclose; + io.filler = 0xff; + int best = 0; + floppy_image_format_t *best_format = 0; + for(floppy_image_format_t *format = fif_list; format; format = format->next) { + int score = format->identify(&io, form_factor); + if(score > best) { + best = score; + best_format = format; + } + } + core_fclose(fd); + return best_format; +} + +bool floppy_image_device::call_load() +{ + io_generic io; + + // Do _not_ remove this cast otherwise the pointer will be incorrect when used by the ioprocs. + io.file = (device_image_interface *)this; + io.procs = &image_ioprocs; + io.filler = 0xff; + int best = 0; + floppy_image_format_t *best_format = 0; + for(floppy_image_format_t *format = fif_list; format; format = format->next) { + int score = format->identify(&io, form_factor); + if(score > best) { + best = score; + best_format = format; + } + } + + if(!best_format) + { + seterror(IMAGE_ERROR_INVALIDIMAGE, "Unable to identify the image format"); + return IMAGE_INIT_FAIL; + } + + image = global_alloc(floppy_image(tracks, sides, form_factor)); + best_format->load(&io, form_factor, image); + output_format = is_readonly() ? 0 : best_format; + + revolution_start_time = mon ? attotime::never : machine().time(); + revolution_count = 0; + + index_resync(); + image_dirty = false; + + wpt = 1; // disk sleeve is covering the sensor + if (!cur_wpt_cb.isnull()) + cur_wpt_cb(this, wpt); + + wpt = is_readonly() || (output_format == 0); + if (!cur_wpt_cb.isnull()) + cur_wpt_cb(this, wpt); + + if (!cur_load_cb.isnull()) + return cur_load_cb(this); + + if(!mon) + ready_counter = 2; + + return IMAGE_INIT_PASS; +} + +void floppy_image_device::call_unload() +{ + dskchg = 0; + + if (image) { + if(image_dirty) + commit_image(); + global_free(image); + image = 0; + } + + wpt = 1; // disk sleeve is covering the sensor + if (!cur_wpt_cb.isnull()) + cur_wpt_cb(this, wpt); + + wpt = 0; // sensor is uncovered + if (!cur_wpt_cb.isnull()) + cur_wpt_cb(this, wpt); + + if (!cur_unload_cb.isnull()) + cur_unload_cb(this); + if(!ready) { + ready = true; + if(!cur_ready_cb.isnull()) + cur_ready_cb(this, ready); + } +} + +bool floppy_image_device::call_create(int format_type, option_resolution *format_options) +{ + image = global_alloc(floppy_image(tracks, sides, form_factor)); + output_format = 0; + + // search for a suitable format based on the extension + for(floppy_image_format_t *i = fif_list; i; i = i->next) + { + // only consider formats that actually support saving + if(!i->supports_save()) + continue; + + if (i->extension_matches(basename())) + { + output_format = i; + break; + } + } + + // did we find a suitable format? + if (output_format == 0) + { + seterror(IMAGE_ERROR_INVALIDIMAGE, "Unable to identify the image format"); + return IMAGE_INIT_FAIL; + } + + return IMAGE_INIT_PASS; +} + +/* motor on, active low */ +void floppy_image_device::mon_w(int state) +{ + if(mon == state) + return; + + mon = state; + + /* off -> on */ + if (!mon && image) + { + revolution_start_time = machine().time(); + ready_counter = 2; + index_resync(); + } + + /* on -> off */ + else { + if(image_dirty) + commit_image(); + revolution_start_time = attotime::never; + index_timer->adjust(attotime::zero); + if(!ready) { + ready = true; + if(!cur_ready_cb.isnull()) + cur_ready_cb(this, ready); + } + } + + if (m_make_sound) m_sound_out->motor(state==0); +} + +attotime floppy_image_device::time_next_index() +{ + if(revolution_start_time.is_never()) + return attotime::never; + return revolution_start_time + rev_time; +} + +/* index pulses at rpm/60 Hz, and stays high for ~2ms at 300rpm */ +void floppy_image_device::index_resync() +{ + if(revolution_start_time.is_never()) { + if(idx) { + idx = 0; + if (!cur_index_pulse_cb.isnull()) + cur_index_pulse_cb(this, idx); + } + return; + } + + attotime delta = machine().time() - revolution_start_time; + while(delta >= rev_time) { + delta -= rev_time; + revolution_start_time += rev_time; + revolution_count++; + } + int position = (delta*floppy_ratio_1).as_ticks(1000000000/1000); + + int new_idx = position < 20000; + + if(new_idx) { + attotime index_up_time = attotime::from_nsec((2000000*1000)/floppy_ratio_1); + index_timer->adjust(index_up_time - delta); + } else + index_timer->adjust(rev_time - delta); + + if(new_idx != idx) { + idx = new_idx; + if(idx && ready) { + ready_counter--; + if(!ready_counter) { + ready = false; + if(!cur_ready_cb.isnull()) + cur_ready_cb(this, ready); + } + } + if (!cur_index_pulse_cb.isnull()) + cur_index_pulse_cb(this, idx); + } +} + +bool floppy_image_device::ready_r() +{ + return ready; +} + +double floppy_image_device::get_pos() +{ + return index_timer->elapsed().as_double(); +} + +bool floppy_image_device::twosid_r() +{ + int tracks = 0, heads = 0; + + if (image) image->get_actual_geometry(tracks, heads); + + return heads == 1; +} + +void floppy_image_device::stp_w(int state) +{ + if ( stp != state ) { + stp = state; + if ( stp == 0 ) { + int ocyl = cyl; + if ( dir ) { + if ( cyl ) cyl--; + } else { + if ( cyl < tracks-1 ) cyl++; + } + if(ocyl != cyl) + { + if (TRACE_STEP) logerror("%s: track %d\n", tag(), cyl); + // Do we want a stepper sound? + if (m_make_sound) m_sound_out->step(); + } + /* Update disk detection if applicable */ + if (exists()) + { + if (dskchg==0) dskchg = 1; + } + } + subcyl = 0; + } +} + +void floppy_image_device::seek_phase_w(int phases) +{ + int cur_pos = (cyl << 2) | subcyl; + int req_pos; + switch(phases) { + case 0x1: req_pos = 0; break; + case 0x3: req_pos = 1; break; + case 0x2: req_pos = 2; break; + case 0x6: req_pos = 3; break; + case 0x4: req_pos = 4; break; + case 0xc: req_pos = 5; break; + case 0x8: req_pos = 6; break; + case 0x9: req_pos = 7; break; + default: return; + } + + // Opposite phase, don't move + if(((cur_pos ^ req_pos) & 7) == 4) + return; + + int next_pos = (cur_pos & ~7) | req_pos; + if(next_pos < cur_pos-4) + next_pos += 8; + else if(next_pos > cur_pos+4) + next_pos -= 8; + if(next_pos < 0) + next_pos = 0; + else if(next_pos > (tracks-1)*4) + next_pos = (tracks-1)*4; + cyl = next_pos >> 2; + subcyl = next_pos & 3; + + if(TRACE_STEP && (next_pos != cur_pos)) + logerror("%s: track %d.%d\n", tag(), cyl, subcyl); + + /* Update disk detection if applicable */ + if (exists()) + if (dskchg==0) + dskchg = 1; +} + +int floppy_image_device::find_index(UINT32 position, const std::vector &buf) +{ + int spos = (buf.size() >> 1)-1; + int step; + for(step=1; step>= 1; + + for(;;) { + if(spos >= int(buf.size()) || (spos > 0 && (buf[spos] & floppy_image::TIME_MASK) > position)) { + spos -= step; + step >>= 1; + } else if(spos < 0 || (spos < int(buf.size())-1 && (buf[spos+1] & floppy_image::TIME_MASK) <= position)) { + spos += step; + step >>= 1; + } else + return spos; + } +} + +UINT32 floppy_image_device::find_position(attotime &base, const attotime &when) +{ + base = revolution_start_time; + attotime delta = when - base; + + while(delta >= rev_time) { + delta -= rev_time; + base += rev_time; + } + while(delta < attotime::zero) { + delta += rev_time; + base -= rev_time; + } + + return (delta*floppy_ratio_1).as_ticks(1000000000/1000); +} + +attotime floppy_image_device::get_next_index_time(std::vector &buf, int index, int delta, attotime base) +{ + UINT32 next_position; + int cells = buf.size(); + if(index+delta < cells) + next_position = buf[index+delta] & floppy_image::TIME_MASK; + else { + if((buf[cells-1]^buf[0]) & floppy_image::MG_MASK) + delta--; + index = index + delta - cells + 1; + next_position = 200000000 + (buf[index] & floppy_image::TIME_MASK); + } + + return base + attotime::from_nsec((UINT64(next_position)*2000/floppy_ratio_1+1)/2); +} + +attotime floppy_image_device::get_next_transition(const attotime &from_when) +{ + if(!image || mon) + return attotime::never; + + std::vector &buf = image->get_buffer(cyl, ss, subcyl); + UINT32 cells = buf.size(); + if(cells <= 1) + return attotime::never; + + attotime base; + UINT32 position = find_position(base, from_when); + + int index = find_index(position, buf); + + if(index == -1) + return attotime::never; + + attotime result = get_next_index_time(buf, index, 1, base); + if(result > from_when) + return result; + return get_next_index_time(buf, index, 2, base); +} + +void floppy_image_device::write_flux(const attotime &start, const attotime &end, int transition_count, const attotime *transitions) +{ + if(!image || mon) + return; + image_dirty = true; + + attotime base; + int start_pos = find_position(base, start); + int end_pos = find_position(base, end); + + std::vector trans_pos(transition_count); + for(int i=0; i != transition_count; i++) + trans_pos[i] = find_position(base, transitions[i]); + + std::vector &buf = image->get_buffer(cyl, ss, subcyl); + + int index; + if(!buf.empty()) + index = find_index(start_pos, buf); + else { + index = 0; + buf.push_back(floppy_image::MG_N); + } + + if(index && (buf[index] & floppy_image::TIME_MASK) == start_pos) + index--; + + UINT32 cur_mg = buf[index] & floppy_image::MG_MASK; + if(cur_mg == floppy_image::MG_N || cur_mg == floppy_image::MG_D) + cur_mg = floppy_image::MG_A; + + UINT32 pos = start_pos; + int ti = 0; + int cells = buf.size(); + while(pos != end_pos) { + if(buf.size() < cells+10) + buf.resize(cells+200); + UINT32 next_pos; + if(ti != transition_count) + next_pos = trans_pos[ti++]; + else + next_pos = end_pos; + if(next_pos > pos) + write_zone(&buf[0], cells, index, pos, next_pos, cur_mg); + else { + write_zone(&buf[0], cells, index, pos, 200000000, cur_mg); + index = 0; + write_zone(&buf[0], cells, index, 0, next_pos, cur_mg); + } + pos = next_pos; + cur_mg = cur_mg == floppy_image::MG_A ? floppy_image::MG_B : floppy_image::MG_A; + } + + buf.resize(cells); +} + +void floppy_image_device::write_zone(UINT32 *buf, int &cells, int &index, UINT32 spos, UINT32 epos, UINT32 mg) +{ + while(spos < epos) { + while(index != cells-1 && (buf[index+1] & floppy_image::TIME_MASK) <= spos) + index++; + + UINT32 ref_start = buf[index] & floppy_image::TIME_MASK; + UINT32 ref_end = index == cells-1 ? 200000000 : buf[index+1] & floppy_image::TIME_MASK; + UINT32 ref_mg = buf[index] & floppy_image::MG_MASK; + + // Can't overwrite a damaged zone + if(ref_mg == floppy_image::MG_D) { + spos = ref_end; + continue; + } + + // If the zone is of the type we want, we don't need to touch it + if(ref_mg == mg) { + spos = ref_end; + continue; + } + + // Check the overlaps, act accordingly + if(spos == ref_start) { + if(epos >= ref_end) { + // Full overlap, that cell is dead, we need to see which ones we can extend + UINT32 prev_mg = index != 0 ? buf[index-1] & floppy_image::MG_MASK : ~0; + UINT32 next_mg = index != cells-1 ? buf[index+1] & floppy_image::MG_MASK : ~0; + if(prev_mg == mg) { + if(next_mg == mg) { + // Both match, merge all three in one + memmove(buf+index, buf+index+2, (cells-index-2)*sizeof(UINT32)); + cells -= 2; + index--; + + } else { + // Previous matches, drop the current cell + memmove(buf+index, buf+index+1, (cells-index-1)*sizeof(UINT32)); + cells --; + } + + } else { + if(next_mg == mg) { + // Following matches, extend it + memmove(buf+index, buf+index+1, (cells-index-1)*sizeof(UINT32)); + cells --; + buf[index] = mg | spos; + } else { + // None match, convert the current cell + buf[index] = mg | spos; + index++; + } + } + spos = ref_end; + + } else { + // Overlap at the start only + // Check if we can just extend the previous cell + if(index != 0 && (buf[index-1] & floppy_image::MG_MASK) == mg) + buf[index] = ref_mg | epos; + else { + // Otherwise we need to insert a new cell + if(index != cells-1) + memmove(buf+index+1, buf+index, (cells-index)*sizeof(UINT32)); + cells++; + buf[index] = mg | spos; + buf[index+1] = ref_mg | epos; + } + spos = epos; + } + + } else { + if(epos >= ref_end) { + // Overlap at the end only + // If we can't just extend the following cell, we need to insert a new one + if(index == cells-1 || (buf[index+1] & floppy_image::MG_MASK) != mg) { + if(index != cells-1) + memmove(buf+index+2, buf+index+1, (cells-index-1)*sizeof(UINT32)); + cells++; + } + buf[index+1] = mg | spos; + index++; + spos = ref_end; + + } else { + // Full inclusion + // We need to split the zone in 3 + if(index != cells-1) + memmove(buf+index+3, buf+index+1, (cells-index-1)*sizeof(UINT32)); + cells += 2; + buf[index+1] = mg | spos; + buf[index+2] = ref_mg | epos; + spos = epos; + } + } + + } +} + +void floppy_image_device::set_write_splice(const attotime &when) +{ + if(image) { + image_dirty = true; + attotime base; + int splice_pos = find_position(base, when); + image->set_write_splice_position(cyl, ss, splice_pos, subcyl); + } +} + +UINT32 floppy_image_device::get_form_factor() const +{ + return form_factor; +} + +UINT32 floppy_image_device::get_variant() const +{ + return image ? image->get_variant() : 0; +} + +ui_menu *floppy_image_device::get_selection_menu(running_machine &machine, render_container *container) +{ + return auto_alloc_clear(machine, ui_menu_control_floppy_image(machine, container, this)); +} + +ui_menu_control_floppy_image::ui_menu_control_floppy_image(running_machine &machine, render_container *container, device_image_interface *_image) : ui_menu_control_device_image(machine, container, _image) +{ + floppy_image_device *fd = static_cast(image); + const floppy_image_format_t *fif_list = fd->get_formats(); + int fcnt = 0; + for(const floppy_image_format_t *i = fif_list; i; i = i->next) + fcnt++; + + format_array = global_alloc_array(floppy_image_format_t *, fcnt); + input_format = output_format = 0; + input_filename = output_filename = ""; +} + +ui_menu_control_floppy_image::~ui_menu_control_floppy_image() +{ + global_free_array(format_array); +} + +void ui_menu_control_floppy_image::do_load_create() +{ + floppy_image_device *fd = static_cast(image); + if(input_filename.compare("")==0) { + int err = fd->create(output_filename.c_str(), 0, NULL); + if (err != 0) { + popmessage("Error: %s", fd->error()); + return; + } + fd->setup_write(output_format); + } else { + int err = fd->load(input_filename.c_str()); + if (!err && output_filename.compare("") != 0) + err = fd->reopen_for_write(output_filename.c_str()); + if(err != 0) { + popmessage("Error: %s", fd->error()); + return; + } + if(output_format) + fd->setup_write(output_format); + } +} + +void ui_menu_control_floppy_image::hook_load(std::string filename, bool softlist) +{ + if (softlist) + { + popmessage("When loaded from software list, the disk is Read-only.\n"); + image->load(filename.c_str()); + ui_menu::stack_pop(machine()); + return; + } + + input_filename = filename; + input_format = static_cast(image)->identify(filename); + + if (!input_format) + { + popmessage("Error: %s\n", image->error()); + ui_menu::stack_pop(machine()); + return; + } + + bool can_in_place = input_format->supports_save(); + if(can_in_place) { + file_error filerr = FILERR_NOT_FOUND; + std::string tmp_path; + core_file *tmp_file; + /* attempt to open the file for writing but *without* create */ + filerr = zippath_fopen(filename.c_str(), OPEN_FLAG_READ | OPEN_FLAG_WRITE, tmp_file, tmp_path); + if(!filerr) + core_fclose(tmp_file); + else + can_in_place = false; + } + submenu_result = -1; + ui_menu::stack_push(auto_alloc_clear(machine(), ui_menu_select_rw(machine(), container, can_in_place, &submenu_result))); + state = SELECT_RW; +} + +void ui_menu_control_floppy_image::handle() +{ + floppy_image_device *fd = static_cast(image); + switch (state) { + case DO_CREATE: { + floppy_image_format_t *fif_list = fd->get_formats(); + int ext_match = 0, total_usable = 0; + for(floppy_image_format_t *i = fif_list; i; i = i->next) { + if(!i->supports_save()) + continue; + if (i->extension_matches(current_file.c_str())) + format_array[total_usable++] = i; + } + ext_match = total_usable; + for(floppy_image_format_t *i = fif_list; i; i = i->next) { + if(!i->supports_save()) + continue; + if (!i->extension_matches(current_file.c_str())) + format_array[total_usable++] = i; + } + submenu_result = -1; + ui_menu::stack_push(auto_alloc_clear(machine(), ui_menu_select_format(machine(), container, format_array, ext_match, total_usable, &submenu_result))); + + state = SELECT_FORMAT; + break; + } + + case SELECT_FORMAT: + if(submenu_result == -1) { + state = START_FILE; + handle(); + } else { + zippath_combine(output_filename, current_directory.c_str(), current_file.c_str()); + output_format = format_array[submenu_result]; + do_load_create(); + ui_menu::stack_pop(machine()); + } + break; + + case SELECT_RW: + switch(submenu_result) { + case ui_menu_select_rw::READONLY: + do_load_create(); + ui_menu::stack_pop(machine()); + break; + + case ui_menu_select_rw::READWRITE: + output_format = input_format; + do_load_create(); + ui_menu::stack_pop(machine()); + break; + + case ui_menu_select_rw::WRITE_DIFF: + popmessage("Sorry, diffs are not supported yet\n"); + ui_menu::stack_pop(machine()); + break; + + case ui_menu_select_rw::WRITE_OTHER: + ui_menu::stack_push(auto_alloc_clear(machine(), ui_menu_file_create(machine(), container, image, current_directory, current_file, &create_ok))); + state = CHECK_CREATE; + break; + + case -1: + state = START_FILE; + break; + } + break; + + default: + ui_menu_control_device_image::handle(); + } +} + +//=================================================================== +// Floppy sound +// +// In order to enable floppy sound you must add the line +// MCFG_FLOPPY_DRIVE_SOUND(true) +// after MCFG_FLOPPY_DRIVE_ADD +// and you must put audio samples (44100Hz, mono) with names as +// shown in floppy_sample_names into the directory samples/floppy +// Sound will be disabled when these samples are missing. +// +// MZ, Aug 2015 +//=================================================================== + +floppy_sound_device::floppy_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : samples_device(mconfig, FLOPPYSOUND, "Floppy sound", tag, owner, clock, "flopsnd", __FILE__) +{ + m_motor = false; + m_loaded = false; +} + +void floppy_sound_device::register_for_save_states() +{ + save_item(NAME(m_sampleend_motor)); + save_item(NAME(m_samplepos_motor)); + save_item(NAME(m_motor_mintime)); + save_item(NAME(m_motor_time)); + save_item(NAME(m_motor)); + save_item(NAME(m_sampleend_step)); + save_item(NAME(m_samplestart_step)); + save_item(NAME(m_samplepos_step)); + save_item(NAME(m_step_mintime)); + save_item(NAME(m_step_time)); +} + +void floppy_sound_device::device_start() +{ + // Read audio samples. The samples are stored in the list m_samples. + m_loaded = load_samples(); + + // The per-floppy stream. If we don't have all samples, don't allocate a stream. + if (m_loaded) m_sound = machine().sound().stream_alloc(*this, 0, 1, clock()); + + // Of course, we can read the length from the sample_t, but we want to + // be able to fine-tune it, for instance, choose different start and end points + m_samplestart_motor = 0; + m_sampleend_motor = 8820; // 200ms + m_samplestart_step = 0; + m_sampleend_step = 2205; // 50ms + + // Mintime says how long the sound persists after the initiating signal + // is cleared (important for short step pulses) + m_motor_mintime = 8820; + m_step_mintime = 1500; + + // Number of updates until the sample stops + m_motor_time = 0; + m_step_time = 0; + + // Initialize position + m_samplepos_step = m_samplestart_step; + m_samplepos_motor = m_samplestart_motor; + register_for_save_states(); +} + +void floppy_sound_device::motor(bool state) +{ + m_sound->update(); + // We do not reset the motor sample on state==true because we don't want + // the sound to "jump" + if (state==true) m_motor_time = m_motor_mintime; + m_motor = state; +} + +/* + Activate the step sound. +*/ +void floppy_sound_device::step() +{ + m_sound->update(); // required + m_step_time = m_step_mintime; + m_samplepos_step = m_samplestart_step; +} + +//------------------------------------------------- +// sound_stream_update - update the sound stream +//------------------------------------------------- + +void floppy_sound_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + // We are using only one stream, unlike the parent class + // Also, there is no need for interpolation, as we only expect + // one sample rate of 44100 for all samples + + INT16 out = 0; + + stream_sample_t *samplebuffer = outputs[0]; + sample_t& motor_sample = m_sample[0]; + sample_t& step_sample = m_sample[1]; + + while (samples-- > 0) + { + out = 0; + // Motor sound + if (m_motor_time > 0) + { + if (m_samplepos_motor < m_sampleend_motor) + // Stream value + out = motor_sample.data[m_samplepos_motor++]; + else + m_samplepos_motor = m_samplestart_motor; + + // When the motor is turned off, count down the samples + if (!m_motor) m_motor_time--; + } + + // Stepper sound + if (m_step_time > 0) + { + if (m_samplepos_step < m_sampleend_step) + // Mix it into the stream value + out = out + step_sample.data[m_samplepos_step++]; + else + m_samplepos_step = m_samplestart_step; + + // Count down the samples + m_step_time--; + } + // Write to the stream buffer + *(samplebuffer++) = out; + } +} + +static const char *const floppy_sample_names[] = +{ + "*floppy", + "floppy_35_motor", + "floppy_35_step", + 0 +}; + +#define FLOPSPK "flopsndout" + +MACHINE_CONFIG_FRAGMENT( floppy_img ) + MCFG_SPEAKER_STANDARD_MONO(FLOPSPK) + MCFG_SOUND_ADD(FLOPSND_TAG, FLOPPYSOUND, 44100) + MCFG_SAMPLES_NAMES(floppy_sample_names) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, FLOPSPK, 0.75) +MACHINE_CONFIG_END + +machine_config_constructor floppy_image_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( floppy_img ); +} + +const device_type FLOPPYSOUND = &device_creator; + + +//************************************************************************** +// GENERIC FLOPPY DRIVE DEFINITIONS +//************************************************************************** + +//------------------------------------------------- +// 3" single-sided double density +//------------------------------------------------- + +floppy_3_ssdd::floppy_3_ssdd(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + floppy_image_device(mconfig, FLOPPY_3_SSDD, "3\" single sided floppy drive", tag, owner, clock, "floppy_3_ssdd", __FILE__) +{ +} + +floppy_3_ssdd::~floppy_3_ssdd() +{ +} + +void floppy_3_ssdd::setup_characteristics() +{ + form_factor = floppy_image::FF_3; + tracks = 42; + sides = 1; + set_rpm(300); +} + +void floppy_3_ssdd::handled_variants(UINT32 *variants, int &var_count) const +{ + var_count = 0; + variants[var_count++] = floppy_image::SSDD; +} + +//------------------------------------------------- +// 3" double-sided double density +//------------------------------------------------- + +floppy_3_dsdd::floppy_3_dsdd(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + floppy_image_device(mconfig, FLOPPY_3_DSDD, "3\" double sided floppy drive", tag, owner, clock, "floppy_3_dsdd", __FILE__) +{ +} + +floppy_3_dsdd::~floppy_3_dsdd() +{ +} + +void floppy_3_dsdd::setup_characteristics() +{ + form_factor = floppy_image::FF_3; + tracks = 42; + sides = 2; + set_rpm(300); +} + +void floppy_3_dsdd::handled_variants(UINT32 *variants, int &var_count) const +{ + var_count = 0; + variants[var_count++] = floppy_image::SSDD; + variants[var_count++] = floppy_image::DSDD; +} + +//------------------------------------------------- +// 3.5" single-sided double density +//------------------------------------------------- + +floppy_35_ssdd::floppy_35_ssdd(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + floppy_image_device(mconfig, FLOPPY_35_SSDD, "3.5\" single-sided double density floppy drive", tag, owner, clock, "floppy_35_ssdd", __FILE__) +{ +} + +floppy_35_ssdd::~floppy_35_ssdd() +{ +} + +void floppy_35_ssdd::setup_characteristics() +{ + form_factor = floppy_image::FF_35; + tracks = 84; + sides = 1; + set_rpm(300); +} + +void floppy_35_ssdd::handled_variants(UINT32 *variants, int &var_count) const +{ + var_count = 0; + variants[var_count++] = floppy_image::SSSD; + variants[var_count++] = floppy_image::SSDD; +} + +//------------------------------------------------- +// 3.5" double-sided double density +//------------------------------------------------- + +floppy_35_dd::floppy_35_dd(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + floppy_image_device(mconfig, FLOPPY_35_DD, "3.5\" double density floppy drive", tag, owner, clock, "floppy_35_dd", __FILE__) +{ +} + +floppy_35_dd::~floppy_35_dd() +{ +} + +void floppy_35_dd::setup_characteristics() +{ + form_factor = floppy_image::FF_35; + tracks = 84; + sides = 2; + set_rpm(300); +} + +void floppy_35_dd::handled_variants(UINT32 *variants, int &var_count) const +{ + var_count = 0; + variants[var_count++] = floppy_image::SSSD; + variants[var_count++] = floppy_image::SSDD; + variants[var_count++] = floppy_image::DSDD; +} + +//------------------------------------------------- +// 3.5" high density +//------------------------------------------------- + +floppy_35_hd::floppy_35_hd(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + floppy_image_device(mconfig, FLOPPY_35_HD, "3.5\" high density floppy drive", tag, owner, clock, "floppy_35_hd", __FILE__) +{ +} + +floppy_35_hd::~floppy_35_hd() +{ +} + +void floppy_35_hd::setup_characteristics() +{ + form_factor = floppy_image::FF_35; + tracks = 84; + sides = 2; + set_rpm(300); +} + +void floppy_35_hd::handled_variants(UINT32 *variants, int &var_count) const +{ + var_count = 0; + variants[var_count++] = floppy_image::SSSD; + variants[var_count++] = floppy_image::SSDD; + variants[var_count++] = floppy_image::DSDD; + variants[var_count++] = floppy_image::DSHD; +} + +//------------------------------------------------- +// 3.5" extended density +//------------------------------------------------- + +floppy_35_ed::floppy_35_ed(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + floppy_image_device(mconfig, FLOPPY_35_ED, "3.5\" extended density floppy drive", tag, owner, clock, "floppy_35_ed", __FILE__) +{ +} + +floppy_35_ed::~floppy_35_ed() +{ +} + +void floppy_35_ed::setup_characteristics() +{ + form_factor = floppy_image::FF_35; + tracks = 84; + sides = 2; + set_rpm(300); +} + +void floppy_35_ed::handled_variants(UINT32 *variants, int &var_count) const +{ + var_count = 0; + variants[var_count++] = floppy_image::SSSD; + variants[var_count++] = floppy_image::SSDD; + variants[var_count++] = floppy_image::DSDD; + variants[var_count++] = floppy_image::DSHD; + variants[var_count++] = floppy_image::DSED; +} + +//------------------------------------------------- +// 5.25" single-sided single density 35 tracks +//------------------------------------------------- + +floppy_525_sssd_35t::floppy_525_sssd_35t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + floppy_image_device(mconfig, FLOPPY_525_SSSD_35T, "5.25\" single-sided single density 35-track floppy drive", tag, owner, clock, "floppy_525_sssd_35t", __FILE__) +{ +} + +floppy_525_sssd_35t::~floppy_525_sssd_35t() +{ +} + +void floppy_525_sssd_35t::setup_characteristics() +{ + form_factor = floppy_image::FF_525; + tracks = 35; + sides = 1; + set_rpm(300); +} + +void floppy_525_sssd_35t::handled_variants(UINT32 *variants, int &var_count) const +{ + var_count = 0; + variants[var_count++] = floppy_image::SSSD; +} + +//------------------------------------------------- +// 5.25" double-sided single density 35 tracks +//------------------------------------------------- + +floppy_525_sd_35t::floppy_525_sd_35t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + floppy_image_device(mconfig, FLOPPY_525_SD_35T, "5.25\" single density 35-track floppy drive", tag, owner, clock, "floppy_525_sd_35t", __FILE__) +{ +} + +floppy_525_sd_35t::~floppy_525_sd_35t() +{ +} + +void floppy_525_sd_35t::setup_characteristics() +{ + form_factor = floppy_image::FF_525; + tracks = 35; + sides = 2; + set_rpm(300); +} + +void floppy_525_sd_35t::handled_variants(UINT32 *variants, int &var_count) const +{ + var_count = 0; + variants[var_count++] = floppy_image::SSSD; +} + +//------------------------------------------------- +// 5.25" single-sided single density +//------------------------------------------------- + +floppy_525_sssd::floppy_525_sssd(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + floppy_image_device(mconfig, FLOPPY_525_SSSD, "5.25\" single-sided single density floppy drive", tag, owner, clock, "floppy_525_sssd", __FILE__) +{ +} + +floppy_525_sssd::~floppy_525_sssd() +{ +} + +void floppy_525_sssd::setup_characteristics() +{ + form_factor = floppy_image::FF_525; + tracks = 42; + sides = 1; + set_rpm(300); +} + +void floppy_525_sssd::handled_variants(UINT32 *variants, int &var_count) const +{ + var_count = 0; + variants[var_count++] = floppy_image::SSSD; +} + +//------------------------------------------------- +// 5.25" double-sided single density +//------------------------------------------------- + +floppy_525_sd::floppy_525_sd(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + floppy_image_device(mconfig, FLOPPY_525_SD, "5.25\" single density floppy drive", tag, owner, clock, "floppy_525_sd", __FILE__) +{ +} + +floppy_525_sd::~floppy_525_sd() +{ +} + +void floppy_525_sd::setup_characteristics() +{ + form_factor = floppy_image::FF_525; + tracks = 42; + sides = 2; + set_rpm(300); +} + +void floppy_525_sd::handled_variants(UINT32 *variants, int &var_count) const +{ + var_count = 0; + variants[var_count++] = floppy_image::SSSD; +} + +//------------------------------------------------- +// 5.25" single-sided double density +//------------------------------------------------- + +floppy_525_ssdd::floppy_525_ssdd(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + floppy_image_device(mconfig, FLOPPY_525_SSDD, "5.25\" single-sided double density floppy drive", tag, owner, clock, "floppy_525_ssdd", __FILE__) +{ +} + +floppy_525_ssdd::~floppy_525_ssdd() +{ +} + +void floppy_525_ssdd::setup_characteristics() +{ + form_factor = floppy_image::FF_525; + tracks = 42; + sides = 1; + set_rpm(300); +} + +void floppy_525_ssdd::handled_variants(UINT32 *variants, int &var_count) const +{ + var_count = 0; + variants[var_count++] = floppy_image::SSSD; + variants[var_count++] = floppy_image::SSDD; +} + +//------------------------------------------------- +// 5.25" double-sided double density +//------------------------------------------------- + +floppy_525_dd::floppy_525_dd(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + floppy_image_device(mconfig, FLOPPY_525_DD, "5.25\" double density floppy drive", tag, owner, clock, "floppy_525_dd", __FILE__) +{ +} + +floppy_525_dd::~floppy_525_dd() +{ +} + +void floppy_525_dd::setup_characteristics() +{ + form_factor = floppy_image::FF_525; + tracks = 42; + sides = 2; + set_rpm(300); +} + +void floppy_525_dd::handled_variants(UINT32 *variants, int &var_count) const +{ + var_count = 0; + variants[var_count++] = floppy_image::SSSD; + variants[var_count++] = floppy_image::SSDD; + variants[var_count++] = floppy_image::DSDD; +} + +//------------------------------------------------- +// 5.25" single-sided quad density +//------------------------------------------------- + +floppy_525_ssqd::floppy_525_ssqd(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + floppy_image_device(mconfig, FLOPPY_525_QD, "5.25\" single-sided quad density floppy drive", tag, owner, clock, "floppy_525_ssqd", __FILE__) +{ +} + +floppy_525_ssqd::~floppy_525_ssqd() +{ +} + +void floppy_525_ssqd::setup_characteristics() +{ + form_factor = floppy_image::FF_525; + tracks = 84; + sides = 1; + set_rpm(300); +} + +void floppy_525_ssqd::handled_variants(UINT32 *variants, int &var_count) const +{ + var_count = 0; + variants[var_count++] = floppy_image::SSSD; + variants[var_count++] = floppy_image::SSDD; + variants[var_count++] = floppy_image::SSQD; +} + +//------------------------------------------------- +// 5.25" double-sided quad density +//------------------------------------------------- + +floppy_525_qd::floppy_525_qd(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + floppy_image_device(mconfig, FLOPPY_525_QD, "5.25\" quad density floppy drive", tag, owner, clock, "floppy_525_qd", __FILE__) +{ +} + +floppy_525_qd::~floppy_525_qd() +{ +} + +void floppy_525_qd::setup_characteristics() +{ + form_factor = floppy_image::FF_525; + tracks = 84; + sides = 2; + set_rpm(300); +} + +void floppy_525_qd::handled_variants(UINT32 *variants, int &var_count) const +{ + var_count = 0; + variants[var_count++] = floppy_image::SSSD; + variants[var_count++] = floppy_image::SSDD; + variants[var_count++] = floppy_image::SSQD; + variants[var_count++] = floppy_image::DSSD; + variants[var_count++] = floppy_image::DSDD; + variants[var_count++] = floppy_image::DSQD; +} + +//------------------------------------------------- +// 5.25" high density +//------------------------------------------------- + +floppy_525_hd::floppy_525_hd(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + floppy_image_device(mconfig, FLOPPY_525_HD, "5.25\" high density floppy drive", tag, owner, clock, "floppy_525_hd", __FILE__) +{ +} + +floppy_525_hd::~floppy_525_hd() +{ +} + +void floppy_525_hd::setup_characteristics() +{ + form_factor = floppy_image::FF_525; + tracks = 84; + sides = 2; + set_rpm(360); +} + +void floppy_525_hd::handled_variants(UINT32 *variants, int &var_count) const +{ + var_count = 0; + variants[var_count++] = floppy_image::SSSD; + variants[var_count++] = floppy_image::SSDD; + variants[var_count++] = floppy_image::SSQD; + variants[var_count++] = floppy_image::DSDD; + variants[var_count++] = floppy_image::DSQD; + variants[var_count++] = floppy_image::DSHD; +} + +//------------------------------------------------- +// 8" single-sided single density +//------------------------------------------------- + +floppy_8_sssd::floppy_8_sssd(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + floppy_image_device(mconfig, FLOPPY_8_SSSD, "8\" single density single sided floppy drive", tag, owner, clock, "floppy_8_sssd", __FILE__) +{ +} + +floppy_8_sssd::~floppy_8_sssd() +{ +} + +void floppy_8_sssd::setup_characteristics() +{ + form_factor = floppy_image::FF_8; + tracks = 77; + sides = 1; + motor_always_on = true; + set_rpm(360); +} + +void floppy_8_sssd::handled_variants(UINT32 *variants, int &var_count) const +{ + var_count = 0; + variants[var_count++] = floppy_image::SSSD; +} + +//------------------------------------------------- +// 8" double-sided single density +//------------------------------------------------- + +floppy_8_dssd::floppy_8_dssd(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + floppy_image_device(mconfig, FLOPPY_8_DSSD, "8\" single density double sided floppy drive", tag, owner, clock, "floppy_8_dssd", __FILE__) +{ +} + +floppy_8_dssd::~floppy_8_dssd() +{ +} + +void floppy_8_dssd::setup_characteristics() +{ + form_factor = floppy_image::FF_8; + tracks = 77; + sides = 2; + motor_always_on = true; + set_rpm(360); +} + +void floppy_8_dssd::handled_variants(UINT32 *variants, int &var_count) const +{ + var_count = 0; + variants[var_count++] = floppy_image::SSSD; + variants[var_count++] = floppy_image::DSSD; +} + +//------------------------------------------------- +// 8" single-sided double density +//------------------------------------------------- + +floppy_8_ssdd::floppy_8_ssdd(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + floppy_image_device(mconfig, FLOPPY_8_DSDD, "8\" double density single sided floppy drive", tag, owner, clock, "floppy_8_ssdd", __FILE__) +{ +} + +floppy_8_ssdd::~floppy_8_ssdd() +{ +} + +void floppy_8_ssdd::setup_characteristics() +{ + form_factor = floppy_image::FF_8; + tracks = 77; + sides = 1; + motor_always_on = true; + set_rpm(360); +} + +void floppy_8_ssdd::handled_variants(UINT32 *variants, int &var_count) const +{ + var_count = 0; + variants[var_count++] = floppy_image::SSSD; + variants[var_count++] = floppy_image::SSDD; +} + +//------------------------------------------------- +// 8" double-sided double density +//------------------------------------------------- + +floppy_8_dsdd::floppy_8_dsdd(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + floppy_image_device(mconfig, FLOPPY_8_DSDD, "8\" double density double sided floppy drive", tag, owner, clock, "floppy_8_dsdd", __FILE__) +{ +} + +floppy_8_dsdd::~floppy_8_dsdd() +{ +} + +void floppy_8_dsdd::setup_characteristics() +{ + form_factor = floppy_image::FF_8; + tracks = 77; + sides = 2; + motor_always_on = true; + set_rpm(360); +} + +void floppy_8_dsdd::handled_variants(UINT32 *variants, int &var_count) const +{ + var_count = 0; + variants[var_count++] = floppy_image::SSSD; + variants[var_count++] = floppy_image::SSDD; + variants[var_count++] = floppy_image::DSDD; +} + + +//************************************************************************** +// SPECIFIC FLOPPY DRIVE DEFINITIONS +//************************************************************************** + +//------------------------------------------------- +// epson smd-165 +// +// track to track: 6 ms +// average: 97 ms +// setting time: 15 ms +// motor start time: 1 s +// +//------------------------------------------------- + +epson_smd_165::epson_smd_165(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + floppy_image_device(mconfig, EPSON_SD_321, "EPSON SMD-165 Floppy Disk Drive", tag, owner, clock, "epson_smd_165", __FILE__) +{ +} + +epson_smd_165::~epson_smd_165() +{ +} + +void epson_smd_165::setup_characteristics() +{ + form_factor = floppy_image::FF_35; + tracks = 40; + sides = 2; + set_rpm(300); +} + +void epson_smd_165::handled_variants(UINT32 *variants, int &var_count) const +{ + var_count = 0; + variants[var_count++] = floppy_image::SSSD; + variants[var_count++] = floppy_image::DSSD; +} + +//------------------------------------------------- +// epson sd-320 +// +// track to track: 15 ms +// average: 220 ms +// setting time: 15 ms +// head load time: 35 ms +// motor start time: 0.5 s +// +// dip switch ss1 +// 1 = drive select 0 +// 2 = drive select 1 +// 3 = drive select 2 +// 4 = drive select 3 +// 5 = head load from pin 4 +// 6 = head load from drive select +// +// dic switch ss2 +// hs = load controlled by head-load +// ms = load controlled by motor enable +// +// dic switch ss3 +// ds = in-use led by drive select +// hl = in-use led by head load +// +//------------------------------------------------- + +epson_sd_320::epson_sd_320(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + floppy_image_device(mconfig, EPSON_SD_320, "EPSON SD-320 Mini-Floppy Disk Drive", tag, owner, clock, "epson_sd_320", __FILE__) +{ +} + +epson_sd_320::~epson_sd_320() +{ +} + +void epson_sd_320::setup_characteristics() +{ + form_factor = floppy_image::FF_525; + tracks = 40; + sides = 2; + set_rpm(300); +} + +void epson_sd_320::handled_variants(UINT32 *variants, int &var_count) const +{ + var_count = 0; + variants[var_count++] = floppy_image::SSSD; + variants[var_count++] = floppy_image::SSDD; + variants[var_count++] = floppy_image::DSDD; +} + +//------------------------------------------------- +// epson sd-321 +// +// same as sd-320, but no head-load selenoid +// +//------------------------------------------------- + +epson_sd_321::epson_sd_321(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + floppy_image_device(mconfig, EPSON_SD_321, "EPSON SD-321 Mini-Floppy Disk Drive", tag, owner, clock, "epson_sd_321", __FILE__) +{ +} + +epson_sd_321::~epson_sd_321() +{ +} + +void epson_sd_321::setup_characteristics() +{ + form_factor = floppy_image::FF_525; + tracks = 40; + sides = 2; + set_rpm(300); +} + +void epson_sd_321::handled_variants(UINT32 *variants, int &var_count) const +{ + var_count = 0; + variants[var_count++] = floppy_image::SSSD; + variants[var_count++] = floppy_image::SSDD; + variants[var_count++] = floppy_image::DSDD; +} + +//------------------------------------------------- +// Sony OA-D31V +// +// track to track: 15 ms +// average: 365 ms +// setting time: 15 ms +// head load time: 60 ms +// +//------------------------------------------------- + +sony_oa_d31v::sony_oa_d31v(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + floppy_image_device(mconfig, SONY_OA_D31V, "Sony OA-D31V Micro Floppydisk Drive", tag, owner, clock, "sony_oa_d31v", __FILE__) +{ +} + +sony_oa_d31v::~sony_oa_d31v() +{ +} + +void sony_oa_d31v::setup_characteristics() +{ + form_factor = floppy_image::FF_35; + tracks = 70; + sides = 1; + set_rpm(600); +} + +void sony_oa_d31v::handled_variants(UINT32 *variants, int &var_count) const +{ + var_count = 0; + variants[var_count++] = floppy_image::SSSD; + variants[var_count++] = floppy_image::SSDD; +} + +//------------------------------------------------- +// Sony OA-D32W +// +// track to track: 12 ms +// average: 350 ms +// setting time: 30 ms +// head load time: 60 ms +// average latency: 50 ms +// +//------------------------------------------------- + +sony_oa_d32w::sony_oa_d32w(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + floppy_image_device(mconfig, SONY_OA_D32W, "Sony OA-D32W Micro Floppydisk Drive", tag, owner, clock, "sony_oa_d32w", __FILE__) +{ +} + +sony_oa_d32w::~sony_oa_d32w() +{ +} + +void sony_oa_d32w::setup_characteristics() +{ + form_factor = floppy_image::FF_35; + tracks = 80; + sides = 2; + set_rpm(600); +} + +void sony_oa_d32w::handled_variants(UINT32 *variants, int &var_count) const +{ + var_count = 0; + variants[var_count++] = floppy_image::SSSD; + variants[var_count++] = floppy_image::SSDD; + variants[var_count++] = floppy_image::DSDD; +} + +//------------------------------------------------- +// Sony OA-D32V +// +// track to track: 12 ms +// average: 350 ms +// setting time: 30 ms +// head load time: 60 ms +// average latency: 50 ms +// +//------------------------------------------------- + +sony_oa_d32v::sony_oa_d32v(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + floppy_image_device(mconfig, SONY_OA_D32V, "Sony OA-D32V Micro Floppydisk Drive", tag, owner, clock, "sony_oa_d32v", __FILE__) +{ +} + +sony_oa_d32v::~sony_oa_d32v() +{ +} + +void sony_oa_d32v::setup_characteristics() +{ + form_factor = floppy_image::FF_35; + tracks = 80; + sides = 1; + set_rpm(600); +} + +void sony_oa_d32v::handled_variants(UINT32 *variants, int &var_count) const +{ + var_count = 0; + variants[var_count++] = floppy_image::SSSD; + variants[var_count++] = floppy_image::SSDD; +} + +//------------------------------------------------- +// TEAC FD-55E +// +// track to track: 3 ms +// average: 94 ms +// setting time: 15 ms +// motor start time: 400 ms +// +//------------------------------------------------- + +teac_fd_55e::teac_fd_55e(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + floppy_image_device(mconfig, TEAC_FD_55F, "TEAC FD-55E FDD", tag, owner, clock, "teac_fd_55e", __FILE__) +{ +} + +teac_fd_55e::~teac_fd_55e() +{ +} + +void teac_fd_55e::setup_characteristics() +{ + form_factor = floppy_image::FF_525; + tracks = 80; + sides = 1; + set_rpm(300); +} + +void teac_fd_55e::handled_variants(UINT32 *variants, int &var_count) const +{ + var_count = 0; + variants[var_count++] = floppy_image::SSSD; + variants[var_count++] = floppy_image::SSDD; + variants[var_count++] = floppy_image::SSQD; +} + +//------------------------------------------------- +// TEAC FD-55F +// +// track to track: 3 ms +// average: 94 ms +// setting time: 15 ms +// motor start time: 400 ms +// +//------------------------------------------------- + +teac_fd_55f::teac_fd_55f(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + floppy_image_device(mconfig, TEAC_FD_55F, "TEAC FD-55F FDD", tag, owner, clock, "teac_fd_55f", __FILE__) +{ +} + +teac_fd_55f::~teac_fd_55f() +{ +} + +void teac_fd_55f::setup_characteristics() +{ + form_factor = floppy_image::FF_525; + tracks = 80; + sides = 2; + set_rpm(300); +} + +void teac_fd_55f::handled_variants(UINT32 *variants, int &var_count) const +{ + var_count = 0; + variants[var_count++] = floppy_image::SSSD; + variants[var_count++] = floppy_image::SSDD; + variants[var_count++] = floppy_image::SSQD; + variants[var_count++] = floppy_image::DSSD; + variants[var_count++] = floppy_image::DSDD; + variants[var_count++] = floppy_image::DSQD; +} + +//------------------------------------------------- +// TEAC FD-55G +// +// track to track: 3 ms +// average: 91 ms +// setting time: 15 ms +// motor start time: 400 ms +// +//------------------------------------------------- + +teac_fd_55g::teac_fd_55g(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + floppy_image_device(mconfig, TEAC_FD_55G, "TEAC FD-55G FDD", tag, owner, clock, "teac_fd_55g", __FILE__) +{ +} + +teac_fd_55g::~teac_fd_55g() +{ +} + +void teac_fd_55g::setup_characteristics() +{ + form_factor = floppy_image::FF_525; + tracks = 77; + sides = 2; + set_rpm(360); +} + +void teac_fd_55g::handled_variants(UINT32 *variants, int &var_count) const +{ + var_count = 0; + variants[var_count++] = floppy_image::SSSD; + variants[var_count++] = floppy_image::SSDD; + variants[var_count++] = floppy_image::SSQD; + variants[var_count++] = floppy_image::DSDD; + variants[var_count++] = floppy_image::DSQD; + variants[var_count++] = floppy_image::DSHD; +} + +//------------------------------------------------- +// ALPS 32551901 (black) / 32551902 (brown) +// +// used in the Commodoere 1541 disk drive +//------------------------------------------------- + +alps_3255190x::alps_3255190x(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + floppy_image_device(mconfig, ALPS_3255190x, "ALPS 32551901/32551902 Floppy Drive", tag, owner, clock, "alps_3255190x", __FILE__) +{ +} + +alps_3255190x::~alps_3255190x() +{ +} + +void alps_3255190x::setup_characteristics() +{ + form_factor = floppy_image::FF_525; + tracks = 84; + sides = 1; + set_rpm(300); + cyl = 34; +} + +void alps_3255190x::handled_variants(UINT32 *variants, int &var_count) const +{ + var_count = 0; + variants[var_count++] = floppy_image::SSSD; +} diff --git a/src/devices/imagedev/floppy.h b/src/devices/imagedev/floppy.h new file mode 100644 index 00000000000..95f2442d308 --- /dev/null +++ b/src/devices/imagedev/floppy.h @@ -0,0 +1,357 @@ +// license:BSD-3-Clause +// copyright-holders:Nathan Woods, Olivier Galibert, Miodrag Milanovic +/********************************************************************* + + floppy.h + +*********************************************************************/ + +#ifndef FLOPPY_H +#define FLOPPY_H + +#include "formats/flopimg.h" +#include "formats/d88_dsk.h" +#include "formats/dfi_dsk.h" +#include "formats/hxcmfm_dsk.h" +#include "formats/imd_dsk.h" +#include "formats/ipf_dsk.h" +#include "formats/mfi_dsk.h" +#include "formats/td0_dsk.h" +#include "formats/cqm_dsk.h" +#include "formats/dsk_dsk.h" +#include "ui/imgcntrl.h" +#include "sound/samples.h" + +#define MCFG_FLOPPY_DRIVE_ADD(_tag, _slot_intf, _def_slot, _formats) \ + MCFG_DEVICE_ADD(_tag, FLOPPY_CONNECTOR, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) \ + static_cast(device)->set_formats(_formats); + +#define MCFG_FLOPPY_DRIVE_SOUND(_doit) \ + static_cast(device)->enable_sound(_doit); + +#define DECLARE_FLOPPY_FORMATS(_name) \ + static const floppy_format_type _name [] + +#define FLOPPY_FORMATS_MEMBER(_member) \ + const floppy_format_type _member [] = { +#define FLOPPY_FORMATS_END \ + , \ + FLOPPY_D88_FORMAT, \ + FLOPPY_DFI_FORMAT, \ + FLOPPY_IMD_FORMAT, \ + FLOPPY_IPF_FORMAT, \ + FLOPPY_MFI_FORMAT, \ + FLOPPY_MFM_FORMAT, \ + FLOPPY_TD0_FORMAT, \ + FLOPPY_CQM_FORMAT, \ + FLOPPY_DSK_FORMAT, \ + NULL }; + +class floppy_sound_device; + +/*************************************************************************** + TYPE DEFINITIONS +***************************************************************************/ + +class floppy_image_device : public device_t, + public device_image_interface, + public device_slot_card_interface +{ +public: + typedef delegate load_cb; + typedef delegate unload_cb; + typedef delegate index_pulse_cb; + typedef delegate ready_cb; + typedef delegate wpt_cb; + + // construction/destruction + floppy_image_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + virtual ~floppy_image_device(); + + virtual void handled_variants(UINT32 *variants, int &var_count) const = 0; + + void set_formats(const floppy_format_type *formats); + floppy_image_format_t *get_formats() const; + floppy_image_format_t *get_load_format() const; + floppy_image_format_t *identify(std::string filename); + void set_rpm(float rpm); + + // image-level overrides + virtual bool call_load(); + virtual void call_unload(); + virtual bool call_create(int format_type, option_resolution *format_options); + virtual bool call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry) { return load_software(swlist, swname, start_entry); } + virtual const char *image_interface() const = 0; + virtual iodevice_t image_type() const { return IO_FLOPPY; } + + virtual bool is_readable() const { return true; } + virtual bool is_writeable() const { return true; } + virtual bool is_creatable() const { return true; } + virtual bool must_be_loaded() const { return false; } + virtual bool is_reset_on_load() const { return false; } + virtual const char *file_extensions() const { return extension_list; } + virtual const option_guide *create_option_guide() const { return NULL; } + void setup_write(floppy_image_format_t *output_format); + + void setup_load_cb(load_cb cb); + void setup_unload_cb(unload_cb cb); + void setup_index_pulse_cb(index_pulse_cb cb); + void setup_ready_cb(ready_cb cb); + void setup_wpt_cb(wpt_cb cb); + + std::vector &get_buffer() { return image->get_buffer(cyl, ss, subcyl); } + int get_cyl() { return cyl; } + + void mon_w(int state); + bool ready_r(); + double get_pos(); + + bool wpt_r() { return wpt; } + int dskchg_r() { return dskchg; } + bool trk00_r() { return cyl != 0; } + int idx_r() { return idx; } + int mon_r() { return mon; } + bool ss_r() { return ss; } + bool twosid_r(); + + void seek_phase_w(int phases); + void stp_w(int state); + void dir_w(int state) { dir = state; } + void ss_w(int state) { ss = state; } + void inuse_w(int state) { } + + void index_resync(); + attotime time_next_index(); + attotime get_next_transition(const attotime &from_when); + void write_flux(const attotime &start, const attotime &end, int transition_count, const attotime *transitions); + void set_write_splice(const attotime &when); + int get_sides() { return sides; } + UINT32 get_form_factor() const; + UINT32 get_variant() const; + + virtual ui_menu *get_selection_menu(running_machine &machine, class render_container *container); + + static const floppy_format_type default_floppy_formats[]; + + // Enable sound + void enable_sound(bool doit) { m_make_sound = doit; } + +protected: + // device-level overrides + virtual void device_config_complete(); + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + virtual machine_config_constructor device_mconfig_additions() const; + + virtual void setup_characteristics() = 0; + + floppy_image_format_t *input_format; + floppy_image_format_t *output_format; + floppy_image *image; + char extension_list[256]; + floppy_image_format_t *fif_list; + emu_timer *index_timer; + + /* Physical characteristics, filled by setup_characteristics */ + int tracks; /* addressable tracks */ + int sides; /* number of heads */ + UINT32 form_factor; /* 3"5, 5"25, etc */ + bool motor_always_on; + + /* state of input lines */ + int dir; /* direction */ + int stp; /* step */ + int wtg; /* write gate */ + int mon; /* motor on */ + int ss; /* side select */ + + /* state of output lines */ + int idx; /* index pulse */ + int wpt; /* write protect */ + int rdy; /* ready */ + int dskchg; /* disk changed */ + bool ready; + + /* rotation per minute => gives index pulse frequency */ + float rpm; + int floppy_ratio_1; // rpm/300*1000 + + attotime revolution_start_time, rev_time; + UINT32 revolution_count; + int cyl, subcyl; + + bool image_dirty; + int ready_counter; + + load_cb cur_load_cb; + unload_cb cur_unload_cb; + index_pulse_cb cur_index_pulse_cb; + ready_cb cur_ready_cb; + wpt_cb cur_wpt_cb; + + UINT32 find_position(attotime &base, const attotime &when); + int find_index(UINT32 position, const std::vector &buf); + void write_zone(UINT32 *buf, int &cells, int &index, UINT32 spos, UINT32 epos, UINT32 mg); + void commit_image(); + attotime get_next_index_time(std::vector &buf, int index, int delta, attotime base); + + // Sound + bool m_make_sound; + floppy_sound_device* m_sound_out; +}; + +class ui_menu_control_floppy_image : public ui_menu_control_device_image { +public: + ui_menu_control_floppy_image(running_machine &machine, render_container *container, device_image_interface *image); + virtual ~ui_menu_control_floppy_image(); + + virtual void handle(); + +protected: + enum { SELECT_FORMAT = LAST_ID, SELECT_MEDIA, SELECT_RW }; + + floppy_image_format_t **format_array; + floppy_image_format_t *input_format, *output_format; + std::string input_filename, output_filename; + + void do_load_create(); + virtual void hook_load(std::string filename, bool softlist); +}; + + +#define DECLARE_FLOPPY_IMAGE_DEVICE(_name, _interface) \ + class _name : public floppy_image_device { \ + public: \ + _name(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); \ + virtual ~_name(); \ + virtual void handled_variants(UINT32 *variants, int &var_count) const; \ + virtual const char *image_interface() const { return _interface; } \ + protected: \ + virtual void setup_characteristics(); \ + }; + +DECLARE_FLOPPY_IMAGE_DEVICE(floppy_3_ssdd, "floppy_3") +DECLARE_FLOPPY_IMAGE_DEVICE(floppy_3_dsdd, "floppy_3") +DECLARE_FLOPPY_IMAGE_DEVICE(floppy_35_ssdd, "floppy_3_5") +DECLARE_FLOPPY_IMAGE_DEVICE(floppy_35_dd, "floppy_3_5") +DECLARE_FLOPPY_IMAGE_DEVICE(floppy_35_hd, "floppy_3_5") +DECLARE_FLOPPY_IMAGE_DEVICE(floppy_35_ed, "floppy_3_5") +DECLARE_FLOPPY_IMAGE_DEVICE(floppy_525_sssd_35t, "floppy_5_25") +DECLARE_FLOPPY_IMAGE_DEVICE(floppy_525_sd_35t, "floppy_5_25") +DECLARE_FLOPPY_IMAGE_DEVICE(floppy_525_sssd, "floppy_5_25") +DECLARE_FLOPPY_IMAGE_DEVICE(floppy_525_sd, "floppy_5_25") +DECLARE_FLOPPY_IMAGE_DEVICE(floppy_525_ssdd, "floppy_5_25") +DECLARE_FLOPPY_IMAGE_DEVICE(floppy_525_dd, "floppy_5_25") +DECLARE_FLOPPY_IMAGE_DEVICE(floppy_525_ssqd, "floppy_5_25") +DECLARE_FLOPPY_IMAGE_DEVICE(floppy_525_qd, "floppy_5_25") +DECLARE_FLOPPY_IMAGE_DEVICE(floppy_525_hd, "floppy_5_25") +DECLARE_FLOPPY_IMAGE_DEVICE(floppy_8_sssd, "floppy_8") +DECLARE_FLOPPY_IMAGE_DEVICE(floppy_8_dssd, "floppy_8") +DECLARE_FLOPPY_IMAGE_DEVICE(floppy_8_ssdd, "floppy_8") +DECLARE_FLOPPY_IMAGE_DEVICE(floppy_8_dsdd, "floppy_8") +DECLARE_FLOPPY_IMAGE_DEVICE(epson_smd_165, "floppy_3_5") +DECLARE_FLOPPY_IMAGE_DEVICE(epson_sd_320, "floppy_5_25") +DECLARE_FLOPPY_IMAGE_DEVICE(epson_sd_321, "floppy_5_25") +DECLARE_FLOPPY_IMAGE_DEVICE(sony_oa_d31v, "floppy_3_5") +DECLARE_FLOPPY_IMAGE_DEVICE(sony_oa_d32w, "floppy_3_5") +DECLARE_FLOPPY_IMAGE_DEVICE(sony_oa_d32v, "floppy_3_5") +DECLARE_FLOPPY_IMAGE_DEVICE(teac_fd_55e, "floppy_5_25") +DECLARE_FLOPPY_IMAGE_DEVICE(teac_fd_55f, "floppy_5_25") +DECLARE_FLOPPY_IMAGE_DEVICE(teac_fd_55g, "floppy_5_25") +DECLARE_FLOPPY_IMAGE_DEVICE(alps_3255190x, "floppy_5_25") + +extern const device_type FLOPPYSOUND; + +/* + Floppy drive sound +*/ +class floppy_sound_device : public samples_device +{ +public: + floppy_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + void motor(bool on); + void step(); + bool samples_loaded() { return m_loaded; } + void register_for_save_states(); + +protected: + void device_start(); + +private: + // device_sound_interface overrides + void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + + sound_stream* m_sound; + bool m_loaded; + + int m_sampleend_motor; + int m_samplepos_motor; + int m_samplestart_motor; + int m_motor_mintime; // min time for the samples; sound persists for that time + int m_motor_time; + bool m_motor; + + int m_sampleend_step; + int m_samplestart_step; + int m_samplepos_step; + int m_step_mintime; + int m_step_time; +}; + +class floppy_connector: public device_t, + public device_slot_interface +{ +public: + floppy_connector(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual ~floppy_connector(); + + void set_formats(const floppy_format_type *formats); + floppy_image_device *get_device(); + void enable_sound(bool doit) { m_enable_sound = doit; } + +protected: + virtual void device_start(); + virtual void device_config_complete(); + +private: + const floppy_format_type *formats; + bool m_enable_sound; +}; + + +// device type definition +extern const device_type FLOPPY_CONNECTOR; +extern const device_type FLOPPY_3_SSDD; +extern const device_type FLOPPY_3_DSDD; +extern const device_type FLOPPY_35_SSDD; +extern const device_type FLOPPY_35_DD; +extern const device_type FLOPPY_35_HD; +extern const device_type FLOPPY_35_ED; +extern const device_type FLOPPY_525_SSSD_35T; +extern const device_type FLOPPY_525_SD_35T; +extern const device_type FLOPPY_525_SSSD; +extern const device_type FLOPPY_525_SD; +extern const device_type FLOPPY_525_SSDD; +extern const device_type FLOPPY_525_DD; +extern const device_type FLOPPY_525_SSQD; +extern const device_type FLOPPY_525_QD; +extern const device_type FLOPPY_525_HD; +extern const device_type FLOPPY_8_SSSD; +extern const device_type FLOPPY_8_DSSD; +extern const device_type FLOPPY_8_SSDD; +extern const device_type FLOPPY_8_DSDD; +extern const device_type EPSON_SMD_165; +extern const device_type EPSON_SD_320; +extern const device_type EPSON_SD_321; +extern const device_type SONY_OA_D31V; +extern const device_type SONY_OA_D32W; +extern const device_type SONY_OA_D32V; +extern const device_type TEAC_FD_55E; +extern const device_type TEAC_FD_55F; +extern const device_type TEAC_FD_55G; +extern const device_type ALPS_3255190x; + +#endif /* FLOPPY_H */ diff --git a/src/devices/imagedev/harddriv.c b/src/devices/imagedev/harddriv.c new file mode 100644 index 00000000000..bc39d53e4b3 --- /dev/null +++ b/src/devices/imagedev/harddriv.c @@ -0,0 +1,298 @@ +// license:BSD-3-Clause +// copyright-holders:Nathan Woods, Raphael Nabet, Miodrag Milanovic +/********************************************************************* + + Code to interface the image code with harddisk core. + + Raphael Nabet 2003 + + Update: 23-Feb-2004 - Unlike floppy disks, for which we support + myriad formats on many systems, it is my intention for MESS to + standardize on the CHD file format for hard drives so I made a few + changes to support this + +*********************************************************************/ + +#include "emu.h" +#include "emuopts.h" +#include "harddisk.h" +#include "harddriv.h" + + +static OPTION_GUIDE_START(hd_option_guide) + OPTION_INT('C', "cylinders", "Cylinders") + OPTION_INT('H', "heads", "Heads") + OPTION_INT('S', "sectors", "Sectors") + OPTION_INT('L', "sectorlength", "Sector Bytes") + OPTION_INT('K', "hunksize", "Hunk Bytes") +OPTION_GUIDE_END + +static const char *hd_option_spec = + "C1-[512]-1024;H1/2/[4]/8;S1-[16]-64;L128/256/[512]/1024;K512/1024/2048/[4096]"; + + +// device type definition +const device_type HARDDISK = &device_creator; + +//------------------------------------------------- +// harddisk_image_device - constructor +//------------------------------------------------- + +harddisk_image_device::harddisk_image_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, HARDDISK, "Harddisk", tag, owner, clock, "harddisk_image", __FILE__), + device_image_interface(mconfig, *this), + m_chd(NULL), + m_hard_disk_handle(NULL), + m_device_image_load(device_image_load_delegate()), + m_device_image_unload(device_image_func_delegate()), + m_interface(NULL) +{ +} + +//------------------------------------------------- +// harddisk_image_device - constructor for subclasses +//------------------------------------------------- +harddisk_image_device::harddisk_image_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_image_interface(mconfig, *this), + m_chd(NULL), + m_hard_disk_handle(NULL), + m_device_image_load(device_image_load_delegate()), + m_device_image_unload(device_image_func_delegate()), + m_interface(NULL) +{ +} + +//------------------------------------------------- +// harddisk_image_device - destructor +//------------------------------------------------- + +harddisk_image_device::~harddisk_image_device() +{ +} + +//------------------------------------------------- +// device_config_complete - perform any +// operations now that the configuration is +// complete +//------------------------------------------------- + +void harddisk_image_device::device_config_complete() +{ + m_formatlist.append(*global_alloc(image_device_format("chd", "CHD Hard drive", "chd,hd", hd_option_spec))); + + // set brief and instance name + update_names(); +} + +const option_guide *harddisk_image_device::create_option_guide() const +{ + return hd_option_guide; +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void harddisk_image_device::device_start() +{ + m_chd = NULL; + + // try to locate the CHD from a DISK_REGION + chd_file *handle = get_disk_handle(machine(), tag()); + if (handle != NULL) + { + m_hard_disk_handle = hard_disk_open(handle); + } + else + { + m_hard_disk_handle = NULL; + } +} + +void harddisk_image_device::device_stop() +{ + if (m_hard_disk_handle) + hard_disk_close(m_hard_disk_handle); +} + +bool harddisk_image_device::call_load() +{ + int our_result; + + our_result = internal_load_hd(); + + /* Check if there is an image_load callback defined */ + if (!m_device_image_load.isnull()) + { + /* Let the override do some additional work/checks */ + our_result = m_device_image_load(*this); + } + return our_result; + +} + +bool harddisk_image_device::call_create(int create_format, option_resolution *create_args) +{ + int err; + UINT32 sectorsize, hunksize; + UINT32 cylinders, heads, sectors, totalsectors; + std::string metadata; + + cylinders = option_resolution_lookup_int(create_args, 'C'); + heads = option_resolution_lookup_int(create_args, 'H'); + sectors = option_resolution_lookup_int(create_args, 'S'); + sectorsize = option_resolution_lookup_int(create_args, 'L'); + hunksize = option_resolution_lookup_int(create_args, 'K'); + + totalsectors = cylinders * heads * sectors; + + /* create the CHD file */ + chd_codec_type compression[4] = { CHD_CODEC_NONE }; + err = m_origchd.create(*image_core_file(), (UINT64)totalsectors * (UINT64)sectorsize, hunksize, sectorsize, compression); + if (err != CHDERR_NONE) + goto error; + + /* if we created the image and hence, have metadata to set, set the metadata */ + strprintf(metadata, HARD_DISK_METADATA_FORMAT, cylinders, heads, sectors, sectorsize); + err = m_origchd.write_metadata(HARD_DISK_METADATA_TAG, 0, metadata); + m_origchd.close(); + + if (err != CHDERR_NONE) + goto error; + + return internal_load_hd(); + +error: + return IMAGE_INIT_FAIL; +} + +void harddisk_image_device::call_unload() +{ + /* Check if there is an image_unload callback defined */ + if ( !m_device_image_unload.isnull() ) + { + m_device_image_unload(*this); + } + + if (m_hard_disk_handle != NULL) + { + hard_disk_close(m_hard_disk_handle); + m_hard_disk_handle = NULL; + } + + m_origchd.close(); + m_diffchd.close(); + m_chd = NULL; +} + +/*------------------------------------------------- + open_disk_diff - open a DISK diff file +-------------------------------------------------*/ + +static chd_error open_disk_diff(emu_options &options, const char *name, chd_file &source, chd_file &diff_chd) +{ + std::string fname = std::string(name).append(".dif"); + + /* try to open the diff */ + //printf("Opening differencing image file: %s\n", fname.c_str()); + emu_file diff_file(options.diff_directory(), OPEN_FLAG_READ | OPEN_FLAG_WRITE); + file_error filerr = diff_file.open(fname.c_str()); + if (filerr == FILERR_NONE) + { + std::string fullpath(diff_file.fullpath()); + diff_file.close(); + + //printf("Opening differencing image file: %s\n", fullpath.c_str()); + return diff_chd.open(fullpath.c_str(), true, &source); + } + + /* didn't work; try creating it instead */ + //printf("Creating differencing image: %s\n", fname.c_str()); + diff_file.set_openflags(OPEN_FLAG_READ | OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS); + filerr = diff_file.open(fname.c_str()); + if (filerr == FILERR_NONE) + { + std::string fullpath(diff_file.fullpath()); + diff_file.close(); + + /* create the CHD */ + //printf("Creating differencing image file: %s\n", fupointllpath.c_str()); + chd_codec_type compression[4] = { CHD_CODEC_NONE }; + chd_error err = diff_chd.create(fullpath.c_str(), source.logical_bytes(), source.hunk_bytes(), compression, source); + if (err != CHDERR_NONE) + return err; + + return diff_chd.clone_all_metadata(source); + } + + return CHDERR_FILE_NOT_FOUND; +} + +int harddisk_image_device::internal_load_hd() +{ + chd_error err = CHDERR_NONE; + + m_chd = NULL; + + if (m_hard_disk_handle) + hard_disk_close(m_hard_disk_handle); + + /* open the CHD file */ + if (software_entry() != NULL) + { + m_chd = get_disk_handle(device().machine(), device().subtag("harddriv").c_str()); + } + else + { + err = m_origchd.open(*image_core_file(), true); + if (err == CHDERR_NONE) + { + m_chd = &m_origchd; + } + else if (err == CHDERR_FILE_NOT_WRITEABLE) + { + err = m_origchd.open(*image_core_file(), false); + if (err == CHDERR_NONE) + { + err = open_disk_diff(device().machine().options(), basename_noext(), m_origchd, m_diffchd); + if (err == CHDERR_NONE) + { + m_chd = &m_diffchd; + } + } + } + } + + if (m_chd != NULL) + { + /* open the hard disk file */ + m_hard_disk_handle = hard_disk_open(m_chd); + if (m_hard_disk_handle != NULL) + return IMAGE_INIT_PASS; + } + + /* if we had an error, close out the CHD */ + m_origchd.close(); + m_diffchd.close(); + m_chd = NULL; + seterror(IMAGE_ERROR_UNSPECIFIED, chd_file::error_string(err)); + + return IMAGE_INIT_FAIL; +} + +/************************************* + * + * Get the CHD file (from the src/chd.c core) + * after an image has been opened with the hd core + * + *************************************/ + +chd_file *harddisk_image_device::get_chd_file() +{ + chd_file *result = NULL; + hard_disk_file *hd_file = get_hard_disk_file(); + if (hd_file) + result = hard_disk_get_chd(hd_file); + return result; +} diff --git a/src/devices/imagedev/harddriv.h b/src/devices/imagedev/harddriv.h new file mode 100644 index 00000000000..f72dc0553f1 --- /dev/null +++ b/src/devices/imagedev/harddriv.h @@ -0,0 +1,94 @@ +// license:BSD-3-Clause +// copyright-holders:Nathan Woods, Raphael Nabet, Miodrag Milanovic +/********************************************************************* + + harddriv.h + + Interface to the CHD code + +*********************************************************************/ + +#ifndef HARDDRIV_H +#define HARDDRIV_H + +#include "harddisk.h" + +/*************************************************************************** + TYPE DEFINITIONS +***************************************************************************/ + +// ======================> harddisk_image_device + +class harddisk_image_device : public device_t, + public device_image_interface +{ +public: + // construction/destruction + harddisk_image_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual ~harddisk_image_device(); + + static void static_set_device_load(device_t &device, device_image_load_delegate callback) { downcast(device).m_device_image_load = callback; } + static void static_set_device_unload(device_t &device, device_image_func_delegate callback) { downcast(device).m_device_image_unload = callback; } + static void static_set_interface(device_t &device, const char *_interface) { downcast(device).m_interface = _interface; } + + // image-level overrides + virtual bool call_load(); + virtual bool call_create(int create_format, option_resolution *create_args); + virtual void call_unload(); + virtual bool call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry) { load_software_part_region(*this, swlist, swname, start_entry ); return TRUE; } + + virtual iodevice_t image_type() const { return IO_HARDDISK; } + + virtual bool is_readable() const { return 1; } + virtual bool is_writeable() const { return 1; } + virtual bool is_creatable() const { return 0; } + virtual bool must_be_loaded() const { return 0; } + virtual bool is_reset_on_load() const { return 0; } + virtual const char *image_interface() const { return m_interface; } + virtual const char *file_extensions() const { return "chd,hd"; } + virtual const option_guide *create_option_guide() const; + + // specific implementation + hard_disk_file *get_hard_disk_file() { return m_hard_disk_handle; } + chd_file *get_chd_file(); + +protected: + harddisk_image_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + // device-level overrides + virtual void device_config_complete(); + virtual void device_start(); + virtual void device_stop(); + + int internal_load_hd(); + + chd_file *m_chd; + chd_file m_origchd; /* handle to the original CHD */ + chd_file m_diffchd; /* handle to the diff CHD */ + hard_disk_file *m_hard_disk_handle; + + device_image_load_delegate m_device_image_load; + device_image_func_delegate m_device_image_unload; + const char * m_interface; +}; + +// device type definition +extern const device_type HARDDISK; + +/*************************************************************************** + DEVICE CONFIGURATION MACROS +***************************************************************************/ + +#define MCFG_HARDDISK_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, HARDDISK, 0) + +#define MCFG_HARDDISK_LOAD(_class,_method) \ + harddisk_image_device::static_set_device_load(*device, device_image_load_delegate(&DEVICE_IMAGE_LOAD_NAME(_class,_method), #_class "::device_image_load_" #_method, downcast<_class *>(owner))); + +#define MCFG_HARDDISK_UNLOAD(_class,_method) \ + harddisk_image_device::static_set_device_unload(*device, device_image_func_delegate(&DEVICE_IMAGE_UNLOAD_NAME(_class,_method), #_class "::device_image_unload_" #_method, downcast<_class *>(owner))); + +#define MCFG_HARDDISK_INTERFACE(_interface) \ + harddisk_image_device::static_set_interface(*device, _interface); + +#endif /* HARDDRIV_H */ diff --git a/src/devices/imagedev/mfmhd.c b/src/devices/imagedev/mfmhd.c new file mode 100644 index 00000000000..cfcdbed0353 --- /dev/null +++ b/src/devices/imagedev/mfmhd.c @@ -0,0 +1,1176 @@ +// license:LGPL-2.1+ +// copyright-holders:Michael Zapf +/************************************************************************* + + MFM Hard disk emulation + ----------------------- + + This is a low-level emulation of a hard disk drive. Unlike high-level + emulations which just deliver the data bytes, this implementation + considers all bytes on a track, including gaps, CRC, interleave, and more. + + The actual data are stored on a CHD file, however, only as a sequence + of sector contents. The other metadata (like gap information, interleave) + are stored as metadata information in the CHD. + + To provide the desired low-level emulation grade, the tracks must be + reconstructed from the sector contents in the CHD. This is done in + the call_load method. + + Usually, more than one sector of a track is read, so when a track is + reconstructed, the track image is retained for later accesses. + + This implementation also features a LRU cache for the track images, + implemented by the class mfmhd_trackimage_cache, also contained in this + source file. The LRU cache stores the most recently accessed track images. + When lines must be evicted, they are stored back into the CHD file. This + is done in the call_unload method. Beside the sector contents, call_unload + also saves track layout metadata which have been detected during usage. + + The architecture can be imagined like this: + + [host system] ---- [controller] --- [harddisk] --- [track cache] + | + [format] ---- [CHD] + + Encodings + --------- + The goal of this implementation is to provide an emulation that is very + close to the original, similar to the grade achieved for the floppy + emulation. This means that the track image does not contain a byte + sequence but a sequence of MFM cell values. Unlike the floppy emulation, + we do not define the cells by time intervals but simply by a sequence of + bits which represent the MFM cell contents; this is also due to the fact + that the cell rate is more than 10 times higher than with floppy media. + + There are four options for encodings which differ by overhead and + emulation precision. + + - MFM_BITS: MFM cells are transferred bit by bit for reading and writing + - MFM_BYTE: MFM cells are transferred in clusters of 16 cells, thus + encoding a full data byte (with 8 clock bits interleaved) + - SEPARATED: 16 bits are transferred in one go, with the 8 clock bits in the + first byte, and the 8 data bits in the second byte + - SEPARATED_SIMPLE: Similar to SEPARATED, but instead of the clock bits, + 0x00 is used for normal data, and 0xff is used for marks. + + Following the specification of MFM, the data byte 0x67 is encoded as follows: + + MFM_BITS / MFM_BYTE: 1001010010010101 = 0x9495 + SEPARATED: 10001000 01100111 = 0x8867 + SEPARATED_SIMPLE: 00000000 01100111 = 0x0067 + + The ID Address Mark (0xA1) is encoded this way: + + MFM_BITS / MFM_BYTE: 0100010010001001 = 0x4489 + SEPARATED: 00001010 10100001 = 0x0AA1 + SEPARATED_SIMPLE: 11111111 10100001 = 0xFFA1 + + If the CPU load by the emulation is already very high, the + SEPARATED(_SIMPLE) options are recommended. The MFM_BITS option is closest + to the real processing, but causes a high load. MFM_BYTE is a good + compromise between speed and precision. + + + Drive definition + ---------------- + Hard disk drives are defined by subclassing mfm_harddisk_device, as can + be seen for the offered Seagate drive implementations. + + The following parameters must be set in the constructor of the subclass: + + - Number of physical cylinders. These can be more than the number of + cylinders that are used for data. Some drives have cylinders near the + spindle that are used as park positions. + + - Number of cylinders used for data. This is the number of the highest + cylinder plus 1 (counting from 0). + + - Landing zone: Cylinder number where the head is parked. Should be higher + than the number of usable cylinders. + + - Heads: Number of heads. + + - Time for one cylinder seek step in milliseconds: This is the time the + drive heads need to step one cylinder inwards or outwards. This time + includes the settling time. + + - Maximum seek time in milliseconds: This is the time the drive needs to + seek from cylinder 0 to the maximum cylinder. This time includes the + settling time and is typically far less than the one cylinder time + multiplied by the number of cylinders, because the settling time only + occurs once. These delay values are calculated in call_load. + + If the number of physical cylinders is set to 0, the cylinder and head + count in taken from the metadata of the mounted CHD file. This allows for + using all kinds of CHD images that can be handled by the controller, + without having to define a proper drive for them. + + The predefined drives are + + ST-213: Seagate hard disk drive, 10 MB capacity + ST-225: Seagate hard disk drive, 20 MB capacity + ST-251: Seagate hard disk drive, 40 MB capacity + + generic: Hard disk with 0 physical cylinders, which can be used for + all CHDs that can be handled by the controller. + + The ST-xxx drives require to mount a CHD that exactly matches their + geometry. + + + Track image cache + ----------------- + Since the reconstruction of the track takes some time, and we don't want + to create unnecessary effort, track images (sector contents plus all + preambles and gaps encoded as selected) are kept in a cache. Whenever a + track shall be read, the cache is consulted first to retrieve a copy. + If no recent copy is available, the track is loaded from the CHD, set up + by the format implementation (see lib/formats/mfm_hd.c). The least + recently used track is evicted from the cache and written back to the CHD + (also by means of the format implementation). + + When the emulation is stopped, all cache lines are evicted and written back. + If the emulation is killed before, cache contents may possibly not be + written back, so changes may be lost. To alleviate this issue, the cache + writes back one line every 5 seconds so that changes are automatically + committed after some time. + + This cache is not related to caches on real hard drives. It is a pure + emulation artifact, intended to keep conversion efforts as low as possible. + + + Interface + --------- + There are three outgoing lines, used as callbacks to the controller: + - READY: asserted when the drive has completed its spinup. + - INDEX: asserted when the index hole passes by. Unlike the floppy + implementation, this hard disk implementation produces a + zero-length pulse (assert/clear). This must be considered for + the controller emulation. + - SEEK COMPLETE: asserted when the read/write heads have settled over the + target cylinder. This line is important for controller that want + to employ buffered steps. + + There are two data transfer methods: + + - read(attotime &from_when, const attotime &limit, UINT16 &data) + + Delivers the MFM cells at the given point in time. The cells are returned + in the data parameter. The behavior depends on the chosen encoding: + + MFM_BITS: data contains 0x0000 or 0x0001 + MFM_BYTE: data contains a set of 16 consecutive cells at the given time + SEPARATED: data contains the clock bits in the MSB, the data bits in the LSB + SEPARATED_SIMPLE: data contains 0x00 or 0xFF in the MSB (normal or mark) + and the data bits in the LSB. + + When the limit is exceeded, the method returns true, otherwise false. + + - write(attotime &from_when, const attotime &limit, UINT16 cdata, bool wpcom=false, bool reduced_wc=false) + + Writes the MFM cells at the given point in time. cdata contains the + cells according to the encoding (see above). The controller also has + to set wpcom to true to indicate write precompensation, and reduced_wc + to true to indicate a reduced write current; otherwise, these settings + are assumed to be false. The wpcom and rwc settings do not affect the + recording of the data bytes in this emulation, but the drive will store + the cylinder with the lowest number where wpcom (or rwc) occured and + store this in the CHD. + + These methods are used to move and select the heads: + + - step_w(line_state line) + - direction_in_w(line_state line) + - headsel_w(int head) + + Some status lines: + + - ready_r + - seek_complete_r + - trk00_r + + These reflect the values that are also passed by the callback routines + listed above and can be used for a polling scheme. Track00 is not available + as a callback. It indicates whether track 0 has been reached. + + + Configuration + ------------- + For a working example please refer to emu/bus/ti99_peb/hfdc.c. + + According to the MAME/MESS concept of slot devices, the settings are + passed over the slot to the slot device, in this case, the hard disk drive. + + This means that when we add a slot (the connector), we also have to + pass the desired parameters for the drive. + + MCFG_MFM_HARDDISK_CONN_ADD(_tag, _slot_intf, _def_slot, _enc, _spinupms, _cache, _format) + + Specific parameters: + + _enc: Select an encoding from the values as listed above. + _spinupms: Number of milliseconds until the drive announces READY. Many + drives like the included Seagate drives require a pretty long + powerup time (10-20 seconds). In some computer systems, the + user is therefore asked to turn on the drive first so that + on first access by the system, the drive may have completed + its powerup. In MAME/MESS we cannot turn on components earlier, + thus we do not define the spinup time inside the drive + implementation but at this point. + _cache: Number of tracks to be stored in the LRU track cache + _format: Format to be used for the drive. Must be a subclass of + mfmhd_image_format_t, for example, mfmhd_generic_format. The format + is specified by its format creator identifier (e.g. MFMHD_GEN_FORMAT). + + Metadata + -------- + We have three sets of metadata information. The first one is the + declaration of cylinders, heads, sectors, and sector size. It is stored + by the tag GDDD in the CHD. + The second is the declaration of interleave, skew, write precompensation, + and reduced write current. + + Write precompensation is a modification of the timing used for the inner + cylinders. Although write precompensation (wpcom for short) can be applied + at every write operation, it is usually only used starting from some + cylinder, going towards the spindle, applied to the whole tracks. + The value defined here is the first cylinder where wpcom is applied. + Reduced write current (rwc) is a modification of the electrical current + used for writing data. The value defined here is the first cylinder where + rwc is applied. + + Both wpcom and rwc have an effect on the physical device, but this is not + emulated. For that reason we store the information as additional metadata + inside the CHD. It is not relevant for the functionality of the emulated + hard disk. The write operations + + When wpcom or rwc are not used, their value is defined to be -1. + + Interleave affects the order how sectors are arranged on the track; skew + is the number of sectors that the sector sequence is shifted on the + next cylinder (cylinder skew) or head (head skew). These values are used + to compensate for the delay that occurs when the read/write heads are moved + from one cylinder to the next, or switched from one head to the next. + + These parameters are stored by the tag GDDI on the CHD. + + The third set refers to the specification of gaps and sync fields on the + track. These values may change only on first use (when undefined) or when + the hard disk is reformatted with a different controller or driver. These + parameters are also stored by the GDDI tag as a second record. + + + Michael Zapf + August 2015 + + References: + [1] ST225 OEM Manual, Seagate + +**************************************************************************/ + +#include "emu.h" +#include "formats/imageutl.h" +#include "harddisk.h" +#include "mfmhd.h" + +#define TRACE_STEPS 0 +#define TRACE_SIGNALS 0 +#define TRACE_READ 0 +#define TRACE_WRITE 0 +#define TRACE_CACHE 0 +#define TRACE_BITS 0 +#define TRACE_DETAIL 0 +#define TRACE_TIMING 0 +#define TRACE_STATE 1 +#define TRACE_CONFIG 1 + +enum +{ + INDEX_TM = 0, + SPINUP_TM, + SEEK_TM, + CACHE_TM +}; + +enum +{ + STEP_COLLECT = 0, + STEP_MOVING, + STEP_SETTLE +}; + +std::string mfm_harddisk_device::tts(const attotime &t) +{ + char buf[256]; + int nsec = t.attoseconds() / ATTOSECONDS_PER_NANOSECOND; + sprintf(buf, "%4d.%03d,%03d,%03d", int(t.seconds()), nsec/1000000, (nsec/1000)%1000, nsec % 1000); + return buf; +} + +mfm_harddisk_device::mfm_harddisk_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : harddisk_image_device(mconfig, type, name, tag, owner, clock, shortname, source), + device_slot_card_interface(mconfig, *this) +{ + m_spinupms = 10000; + m_cachelines = 5; + m_max_cylinders = 0; + m_phys_cylinders = 0; // We will get this value for generic drives from the image + m_max_heads = 0; + m_cell_size = 100; + m_rpm = 3600; // MFM drives have a revolution rate of 3600 rpm (i.e. 60/sec) + m_trackimage_size = (int)((60000000000ULL / (m_rpm * m_cell_size)) / 16 + 1); + m_cache = NULL; + // We will calculate default values from the time specs later. + m_seeknext_time = 0; + m_maxseek_time = 0; + m_actual_cylinders = 0; + m_landing_zone = 0; + m_interleave = 0; +} + +mfm_harddisk_device::~mfm_harddisk_device() +{ +} + +void mfm_harddisk_device::device_start() +{ + m_index_timer = timer_alloc(INDEX_TM); + m_spinup_timer = timer_alloc(SPINUP_TM); + m_seek_timer = timer_alloc(SEEK_TM); + m_cache_timer = timer_alloc(CACHE_TM); + + m_rev_time = attotime::from_hz(m_rpm/60); + m_index_timer->adjust(attotime::from_hz(m_rpm/60), 0, attotime::from_hz(m_rpm/60)); + + m_current_cylinder = m_landing_zone; // Park position + m_spinup_timer->adjust(attotime::from_msec(m_spinupms)); + + m_cache = global_alloc(mfmhd_trackimage_cache); + + // In 5 second periods, check whether the cache has dirty lines + m_cache_timer->adjust(attotime::from_msec(5000), 0, attotime::from_msec(5000)); +} + +void mfm_harddisk_device::device_reset() +{ + m_autotruncation = false; + m_ready = false; + m_seek_complete = true; + m_seek_inward = false; + m_track_delta = 0; + m_step_line = CLEAR_LINE; + m_recalibrated = false; +} + +void mfm_harddisk_device::device_stop() +{ + if (m_cache!=NULL) global_free(m_cache); +} + +/* + Load the image from the CHD. We also calculate the head timing here + because we need the number of cylinders, and for generic drives we get + them from the CHD. +*/ +bool mfm_harddisk_device::call_load() +{ + bool loaded = harddisk_image_device::call_load(); + + std::string devtag(tag()); + devtag += ":format"; + + m_format->set_tag(devtag); + + if (loaded==IMAGE_INIT_PASS) + { + std::string metadata; + chd_file* chdfile = get_chd_file(); + + if (chdfile==NULL) + { + logerror("%s: chdfile is null\n", tag()); + return IMAGE_INIT_FAIL; + } + + // Read the hard disk metadata + chd_error state = chdfile->read_metadata(HARD_DISK_METADATA_TAG, 0, metadata); + if (state != CHDERR_NONE) + { + logerror("%s: Failed to read CHD metadata\n", tag()); + return IMAGE_INIT_FAIL; + } + + if (TRACE_CONFIG) logerror("%s: CHD metadata: %s\n", tag(), metadata.c_str()); + + // Parse the metadata + mfmhd_layout_params param; + param.encoding = m_encoding; + if (TRACE_CONFIG) logerror("%s: Set encoding to %d\n", tag(), m_encoding); + + if (sscanf(metadata.c_str(), HARD_DISK_METADATA_FORMAT, ¶m.cylinders, ¶m.heads, ¶m.sectors_per_track, ¶m.sector_size) != 4) + { + logerror("%s: Invalid CHD metadata\n", tag()); + return IMAGE_INIT_FAIL; + } + + if (TRACE_CONFIG) logerror("%s: CHD image has geometry cyl=%d, head=%d, sect=%d, size=%d\n", tag(), param.cylinders, param.heads, param.sectors_per_track, param.sector_size); + + if (m_max_cylinders != 0 && (param.cylinders != m_max_cylinders || param.heads != m_max_heads)) + { + throw emu_fatalerror("Image geometry does not fit this kind of hard drive: drive=(%d,%d), image=(%d,%d)", m_max_cylinders, m_max_heads, param.cylinders, param.heads); + } + + // MDM format specs + param.interleave = 0; + param.cylskew = 0; + param.headskew = 0; + param.write_precomp_cylinder = -1; + param.reduced_wcurr_cylinder = -1; + + state = chdfile->read_metadata(MFM_HARD_DISK_METADATA_TAG, 0, metadata); + if (state != CHDERR_NONE) + { + logerror("%s: Failed to read CHD sector arrangement/recording specs, applying defaults\n", tag()); + } + else + { + sscanf(metadata.c_str(), MFMHD_REC_METADATA_FORMAT, ¶m.interleave, ¶m.cylskew, ¶m.headskew, ¶m.write_precomp_cylinder, ¶m.reduced_wcurr_cylinder); + } + + if (!param.sane_rec()) + { + if (TRACE_CONFIG) logerror("%s: Sector arrangement/recording specs have invalid values, applying defaults\n", tag()); + param.reset_rec(); + } + else + if (TRACE_CONFIG) logerror("%s: MFM HD rec specs: interleave=%d, cylskew=%d, headskew=%d, wpcom=%d, rwc=%d\n", + tag(), param.interleave, param.cylskew, param.headskew, param.write_precomp_cylinder, param.reduced_wcurr_cylinder); + + state = chdfile->read_metadata(MFM_HARD_DISK_METADATA_TAG, 1, metadata); + if (state != CHDERR_NONE) + { + logerror("%s: Failed to read CHD track gap specs, applying defaults\n", tag()); + } + else + { + sscanf(metadata.c_str(), MFMHD_GAP_METADATA_FORMAT, ¶m.gap1, ¶m.gap2, ¶m.gap3, ¶m.sync, ¶m.headerlen, ¶m.ecctype); + } + + if (!param.sane_gap()) + { + if (TRACE_CONFIG) logerror("%s: MFM HD gap specs have invalid values, applying defaults\n", tag()); + param.reset_gap(); + } + else + if (TRACE_CONFIG) logerror("%s: MFM HD gap specs: gap1=%d, gap2=%d, gap3=%d, sync=%d, headerlen=%d, ecctype=%d\n", + tag(), param.gap1, param.gap2, param.gap3, param.sync, param.headerlen, param.ecctype); + + m_format->set_layout_params(param); + + m_cache->init(this, m_trackimage_size, m_cachelines); + + // Head timing + // We assume that the real times are 80% of the max times + // The single-step time includes the settle time, so does the max time + // From that we calculate the actual cylinder-by-cylinder time and the settle time + + m_actual_cylinders = param.cylinders; + + if (m_phys_cylinders == 0) m_phys_cylinders = m_actual_cylinders+1; + if (m_landing_zone == 0) m_landing_zone = m_phys_cylinders-1; + + float realnext = (m_seeknext_time==0)? 10 : (m_seeknext_time * 0.8); + float realmax = (m_maxseek_time==0)? (m_actual_cylinders * 0.2) : (m_maxseek_time * 0.8); + float settle_us = ((m_actual_cylinders-1.0) * realnext - realmax) / (m_actual_cylinders-2.0) * 1000; + float step_us = realnext * 1000 - settle_us; + if (TRACE_CONFIG) logerror("%s: Calculated settle time: %0.2f ms, step: %d us\n", tag(), settle_us/1000, (int)step_us); + + m_settle_time = attotime::from_usec((int)settle_us); + m_step_time = attotime::from_usec((int)step_us); + + m_current_cylinder = m_landing_zone; + } + else + { + logerror("%s: Could not load CHD\n", tag()); + } + return loaded; +} + +const char *MFMHD_REC_METADATA_FORMAT = "IL:%d,CSKEW:%d,HSKEW:%d,WPCOM:%d,RWC:%d"; +const char *MFMHD_GAP_METADATA_FORMAT = "GAP1:%d,GAP2:%d,GAP3:%d,SYNC:%d,HLEN:%d,ECC:%d"; + +void mfm_harddisk_device::call_unload() +{ + mfmhd_layout_params* params = m_format->get_current_params(); + mfmhd_layout_params* oldparams = m_format->get_initial_params(); + + if (m_cache!=NULL) + { + m_cache->cleanup(); + + if (m_format->save_param(MFMHD_IL) && !params->equals_rec(oldparams)) + { + logerror("%s: MFM HD sector arrangement and recording specs have changed; updating CHD metadata\n", tag()); + chd_file* chdfile = get_chd_file(); + std::string metadata; + + strprintf(metadata, MFMHD_REC_METADATA_FORMAT, params->interleave, params->cylskew, params->headskew, params->write_precomp_cylinder, params->reduced_wcurr_cylinder); + + chd_error err = chdfile->write_metadata(MFM_HARD_DISK_METADATA_TAG, 0, metadata, 0); + if (err != CHDERR_NONE) + { + logerror("%s: Failed to save MFM HD sector arrangement/recording specs to CHD\n", tag()); + } + } + + if (m_format->save_param(MFMHD_GAP1) && !params->equals_gap(oldparams)) + { + logerror("%s: MFM HD track gap specs have changed; updating CHD metadata\n", tag()); + chd_file* chdfile = get_chd_file(); + std::string metadata; + + strprintf(metadata, MFMHD_GAP_METADATA_FORMAT, params->gap1, params->gap2, params->gap3, params->sync, params->headerlen, params->ecctype); + + chd_error err = chdfile->write_metadata(MFM_HARD_DISK_METADATA_TAG, 1, metadata, 0); + if (err != CHDERR_NONE) + { + logerror("%s: Failed to save MFM HD track gap specs to CHD\n", tag()); + } + } + } + harddisk_image_device::call_unload(); +} + +void mfm_harddisk_device::setup_index_pulse_cb(index_pulse_cb cb) +{ + m_index_pulse_cb = cb; +} + +void mfm_harddisk_device::setup_ready_cb(ready_cb cb) +{ + m_ready_cb = cb; +} + +void mfm_harddisk_device::setup_seek_complete_cb(seek_complete_cb cb) +{ + m_seek_complete_cb = cb; +} + +attotime mfm_harddisk_device::track_end_time() +{ + // We back up two microseconds before the track end to avoid the + // index pulse to appear earlier (because of rounding effects) + attotime nexttime = m_rev_time - attotime::from_nsec(2000); + attotime endtime = attotime::never; + + if (!m_ready) + { + // estimate the next index time; during power-up we assume half the rotational speed + // Should never be relevant, though, because READY is false. + nexttime = nexttime * 2; + } + + if (!m_revolution_start_time.is_never()) + { + endtime = m_revolution_start_time + nexttime; + if (TRACE_TIMING) logerror("%s: Track start time = %s, end time = %s\n", tag(), tts(m_revolution_start_time).c_str(), tts(endtime).c_str()); + } + return endtime; +} + +void mfm_harddisk_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch (id) + { + case INDEX_TM: + // Simple index hole handling. We assume that there is only a short pulse. + m_revolution_start_time = machine().time(); + if (!m_index_pulse_cb.isnull()) + { + m_index_pulse_cb(this, ASSERT_LINE); + m_index_pulse_cb(this, CLEAR_LINE); + } + break; + + case SPINUP_TM: + recalibrate(); + break; + + case CACHE_TM: + m_cache->write_back_one(); + break; + + case SEEK_TM: + switch (m_step_phase) + { + case STEP_COLLECT: + // Collect timer has expired; start moving head + head_move(); + break; + case STEP_MOVING: + // Head has reached final position + // Check whether we have a new delta + if (m_track_delta == 0) + { + // Start the settle timer + m_step_phase = STEP_SETTLE; + m_seek_timer->adjust(m_settle_time); + if (TRACE_STEPS && TRACE_DETAIL) logerror("%s: Arrived at target cylinder %d, settling ...\n", tag(), m_current_cylinder); + } + else + { + // need to move the head again + head_move(); + } + break; + case STEP_SETTLE: + // Do we have new step pulses? + if (m_track_delta != 0) head_move(); + else + { + // Seek completed + if (!m_recalibrated) + { + m_ready = true; + m_recalibrated = true; + if (TRACE_STATE) logerror("%s: Spinup complete, drive recalibrated and positioned at cylinder %d; drive is READY\n", tag(), m_current_cylinder); + if (!m_ready_cb.isnull()) m_ready_cb(this, ASSERT_LINE); + } + else + { + if (TRACE_SIGNALS) logerror("%s: Settling done at cylinder %d, seek complete\n", tag(), m_current_cylinder); + } + m_seek_complete = true; + if (!m_seek_complete_cb.isnull()) m_seek_complete_cb(this, ASSERT_LINE); + m_step_phase = STEP_COLLECT; + } + break; + } + } +} + +void mfm_harddisk_device::recalibrate() +{ + if (TRACE_STEPS) logerror("%s: Recalibrate to track 0\n", tag()); + direction_in_w(CLEAR_LINE); + while (-m_track_delta < m_phys_cylinders) + { + step_w(ASSERT_LINE); + step_w(CLEAR_LINE); + } +} + +void mfm_harddisk_device::head_move() +{ + int steps = m_track_delta; + if (steps < 0) steps = -steps; + if (TRACE_STEPS) logerror("%s: Moving head by %d step(s) %s\n", tag(), steps, (m_track_delta<0)? "outward" : "inward"); + + // We simulate the head movement by pausing for n*step_time with n being the cylinder delta + m_step_phase = STEP_MOVING; + m_seek_timer->adjust(m_step_time * steps); + + if (TRACE_TIMING) logerror("%s: Head movement takes %s time\n", tag(), tts(m_step_time * steps).c_str()); + // We pretend that we already arrived + // TODO: Check auto truncation? + m_current_cylinder += m_track_delta; + if (m_current_cylinder < 0) m_current_cylinder = 0; + if (m_current_cylinder >= m_actual_cylinders) m_current_cylinder = m_actual_cylinders-1; + m_track_delta = 0; +} + +void mfm_harddisk_device::direction_in_w(line_state line) +{ + m_seek_inward = (line == ASSERT_LINE); + if (TRACE_STEPS && TRACE_DETAIL) logerror("%s: Setting seek direction %s\n", tag(), m_seek_inward? "inward" : "outward"); +} + +/* + According to the specs [1]: + + "4.3.1 BUFFERED SEEK: To minimize access time, pulses may be issued at an + accelerated rate and buffered in a counter. Initiation of a seek starts + immediately after the first pulse is received. Head motion occurs during + pulse accumulation, and the seek is completed following receipt of all pulses." + + "8.1.3 SEEKING: Upon receiving a Step pulse, the MPU (microprocessor unit) + pauses for 250 usec to allow for additional pulses before executing the seek + operation. Every incoming pulse resets the 250 usec timer. The seek will + not begin until the last pulse is received." + + WTF? Oh come on, Seagate, be consistent at least in a single document. + + ================================ + + Step behaviour: + During all waiting times, further step_w invocations increase the counter + + - Leading edge increments the counter c and sets the timer to 250us (mode=collect) + - When the timer expires (mode=collect): + (1)- Calculate the stepping time: time = c*200us; save the counter + - Start the timer (mode=move) + - When the timer expires (mode=move) + - Add the track delta to the current track position + - Subtract the delta from the current counter + - When the counter is not zero (pulses arrived in the meantime), go to (1) + - When the counter is zero, set the timer to 16.8 ms (mode=settle) + - When the timer expires (mode=settle) + - When the counter is not zero, go to (1) + - When the counter is zero, signal seek_complete; done +*/ + +void mfm_harddisk_device::step_w(line_state line) +{ + // Leading edge + if (line == ASSERT_LINE && m_step_line == CLEAR_LINE) + { + if (m_seek_complete) + { + m_step_phase = STEP_COLLECT; + m_seek_complete = false; + if (!m_seek_complete_cb.isnull()) m_seek_complete_cb(this, CLEAR_LINE); + } + + // Counter will be adjusted according to the direction (+-1) + m_track_delta += (m_seek_inward)? +1 : -1; + if (TRACE_STEPS && TRACE_DETAIL) logerror("%s: Got seek pulse; track delta %d\n", tag(), m_track_delta); + if (m_track_delta < -m_phys_cylinders || m_track_delta > m_phys_cylinders) + { + if (TRACE_STEPS) logerror("%s: Excessive step pulses - doing auto-truncation\n", tag()); + m_autotruncation = true; + } + m_seek_timer->adjust(attotime::from_usec(250)); // Start step collect timer + } + m_step_line = line; +} + +/* + Find the position of the cell. + Returns true when the current time exceeds the limit. + Returns the position as an index into the track array and the bit number. +*/ +bool mfm_harddisk_device::find_position(attotime &from_when, const attotime &limit, int &bytepos, int &bit) +{ + // Frequency + UINT32 freq = 1000000000/m_cell_size; + + // As we stop some few cells early each track, we adjust our position + // to the track start + if (from_when < m_revolution_start_time) from_when = m_revolution_start_time; + + // Calculate the position in the track, given the from_when time and the revolution_start_time. + int cell = (from_when - m_revolution_start_time).as_ticks(freq); + + from_when += attotime::from_nsec((m_encoding==MFM_BITS)? m_cell_size : (16*m_cell_size)); + if (from_when > limit) return true; + + bytepos = cell / 16; + + // Reached the end + if (bytepos >= m_trackimage_size) + { + if (TRACE_TIMING) logerror("%s: Reached end: rev_start = %s, live = %s\n", tag(), tts(m_revolution_start_time).c_str(), tts(from_when).c_str()); + m_revolution_start_time += m_rev_time; + cell = (from_when - m_revolution_start_time).as_ticks(freq); + bytepos = cell / 16; + } + + if (bytepos < 0) + { + if (TRACE_TIMING) logerror("%s: Negative cell number: rev_start = %s, live = %s\n", tag(), tts(m_revolution_start_time).c_str(), tts(from_when).c_str()); + bytepos = 0; + } + bit = cell % 16; + + return false; +} + +/* + Reading bytes from the hard disk. + + Returns true if the time limit will be exceeded before reading the bit or complete byte. + Otherwise returns the bit at the given position, or the complete data byte with the clock byte. +*/ +bool mfm_harddisk_device::read(attotime &from_when, const attotime &limit, UINT16 &cdata) +{ + UINT16* track = m_cache->get_trackimage(m_current_cylinder, m_current_head); + + if (track==NULL) + { + // What shall we do in this case? + throw emu_fatalerror("Cannot read CHD image"); + } + + // Get a copy for later debug output + attotime fw = from_when; + + int bytepos = 0; + int bitpos = 0; + + bool offlimit = find_position(from_when, limit, bytepos, bitpos); + if (offlimit) return true; + + if (m_encoding == MFM_BITS) + { + // We will deliver a single bit + cdata = ((track[bytepos] << bitpos) & 0x8000) >> 15; + if (TRACE_BITS) logerror("%s: Reading (c=%d,h=%d,bit=%d) at cell %d [%s] = %d\n", tag(), m_current_cylinder, m_current_head, bitpos, ((bytepos<<4) + bitpos), tts(fw).c_str(), cdata); + } + else + { + // We will deliver a whole byte + if (TRACE_READ) logerror("%s: Reading (c=%d,h=%d) at position %d\n", tag(), m_current_cylinder, m_current_head, bytepos); + cdata = track[bytepos]; + } + return false; +} + +/* + Writing bytes to the hard disk. + + Returns true if the time limit will be exceeded before writing the bit or complete byte. +*/ +bool mfm_harddisk_device::write(attotime &from_when, const attotime &limit, UINT16 cdata, bool wpcom, bool reduced_wc) +{ + UINT16* track = m_cache->get_trackimage(m_current_cylinder, m_current_head); + + if (track==NULL) + { + // What shall we do in this case? + throw emu_fatalerror("Cannot read CHD image"); + } + + int bytepos = 0; + int bitpos = 0; + + bool offlimit = find_position(from_when, limit, bytepos, bitpos); + if (offlimit) return true; + + m_cache->mark_current_as_dirty(); + + if (m_encoding == MFM_BITS) + { + // We will write a single bit + if (cdata != 0) track[bytepos] |= (0x8000 >> bitpos); + else track[bytepos] &= ~(0x8000 >> bitpos); + bitpos++; + } + else + { + // We will write a whole byte + track[bytepos] = cdata; + } + + // Update our cylinders for reduced write current and write precompensation. + // We assume that write precompensation and reduced write current occur + // at some cylinder and continue up to the innermost cylinder. + mfmhd_layout_params* params = m_format->get_current_params(); + + if (reduced_wc && (params->reduced_wcurr_cylinder == -1 || m_current_cylinder < params->reduced_wcurr_cylinder)) + params->reduced_wcurr_cylinder = m_current_cylinder; + + if (wpcom && (params->write_precomp_cylinder == -1 || m_current_cylinder < params->write_precomp_cylinder)) + params->write_precomp_cylinder = m_current_cylinder; + + if (TRACE_WRITE) if ((bitpos&0x0f)==0) logerror("%s: Wrote data=%04x (c=%d,h=%d) at position %04x, wpcom=%d, rwc=%d\n", tag(), track[bytepos], m_current_cylinder, m_current_head, bytepos, wpcom, reduced_wc); + return false; +} + +chd_error mfm_harddisk_device::load_track(UINT16* data, int cylinder, int head) +{ + chd_error state = m_format->load(m_chd, data, m_trackimage_size, cylinder, head); + return state; +} + +void mfm_harddisk_device::write_track(UINT16* data, int cylinder, int head) +{ + m_format->save(m_chd, data, m_trackimage_size, cylinder, head); +} + +int mfm_harddisk_device::get_actual_heads() +{ + return m_format->get_current_params()->heads; +} + +/* + The generic HD takes any kind of CHD HD image and magically creates enough heads and cylinders. +*/ +mfm_hd_generic_device::mfm_hd_generic_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) +: mfm_harddisk_device(mconfig, MFMHD_GENERIC, "Generic MFM hard disk", tag, owner, clock, "mfm_harddisk", __FILE__) +{ +} + +const device_type MFMHD_GENERIC = &device_creator; + +/* + Various models. +*/ +mfm_hd_st213_device::mfm_hd_st213_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) +: mfm_harddisk_device(mconfig, MFMHD_ST213, "Seagate ST-213 MFM hard disk", tag, owner, clock, "mfm_hd_st213", __FILE__) +{ + m_phys_cylinders = 670; + m_max_cylinders = 615; // 0..614 + m_landing_zone = 620; + m_max_heads = 2; + m_seeknext_time = 20; // time for one step including settle time + m_maxseek_time = 150; +} + +const device_type MFMHD_ST213 = &device_creator; + +mfm_hd_st225_device::mfm_hd_st225_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) +: mfm_harddisk_device(mconfig, MFMHD_ST225, "Seagate ST-225 MFM hard disk", tag, owner, clock, "mfm_hd_st225", __FILE__) +{ + m_phys_cylinders = 670; + m_max_cylinders = 615; + m_landing_zone = 620; + m_max_heads = 4; + m_seeknext_time = 20; + m_maxseek_time = 150; +} + +const device_type MFMHD_ST225 = &device_creator; + +mfm_hd_st251_device::mfm_hd_st251_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) +: mfm_harddisk_device(mconfig, MFMHD_ST251, "Seagate ST-251 MFM hard disk", tag, owner, clock, "mfm_hd_st251", __FILE__) +{ + m_phys_cylinders = 821; + m_max_cylinders = 820; + m_landing_zone = 820; + m_max_heads = 6; + m_seeknext_time = 8; + m_maxseek_time = 70; +} + +const device_type MFMHD_ST251 = &device_creator; + +// =========================================================== +// Track cache +// The cache holds track images to be read by the controller. +// This is a write-back LRU cache. +// =========================================================== + +mfmhd_trackimage_cache::mfmhd_trackimage_cache(): + m_tracks(NULL) +{ +} + +mfmhd_trackimage_cache::~mfmhd_trackimage_cache() +{ + mfmhd_trackimage* current = m_tracks; + if (TRACE_CACHE) logerror("%s: MFM HD cache destroy\n", m_mfmhd->tag()); + + while (current != NULL) + { + global_free_array(current->encdata); + mfmhd_trackimage* currenttmp = current->next; + global_free(current); + current = currenttmp; + } +} + +void mfmhd_trackimage_cache::write_back_one() +{ + mfmhd_trackimage* current = m_tracks; + + while (current != NULL) + { + if (current->dirty) + { + m_mfmhd->write_track(current->encdata, current->cylinder, current->head); + current->dirty = false; + break; + } + mfmhd_trackimage* currenttmp = current->next; + current = currenttmp; + } +} + +void mfmhd_trackimage_cache::cleanup() +{ + mfmhd_trackimage* current = m_tracks; + if (TRACE_CACHE) logerror("%s: MFM HD cache cleanup\n", m_mfmhd->tag()); + + // Still dirty? + while (current != NULL) + { + if (TRACE_CACHE) logerror("%s: MFM HD cache: evict line cylinder=%d head=%d\n", m_mfmhd->tag(), current->cylinder, current->head); + if (current->dirty) + { + m_mfmhd->write_track(current->encdata, current->cylinder, current->head); + current->dirty = false; + } + mfmhd_trackimage* currenttmp = current->next; + current = currenttmp; + } +} + +/* + Marks the recently loaded track as dirty. As every writing operations + is preceded by a lookup, writing will always be done on the first track in the list. +*/ +void mfmhd_trackimage_cache::mark_current_as_dirty() +{ + m_tracks->dirty = true; +} + +const char *encnames[] = { "MFM_BITS","MFM_BYTE","SEPARATE","SSIMPLE " }; + +/* + Initialize the cache by loading the first tracks. +*/ +void mfmhd_trackimage_cache::init(mfm_harddisk_device* mfmhd, int tracksize, int trackslots) +{ + if (TRACE_CACHE) logerror("%s: MFM HD cache init; cache size is %d tracks\n", mfmhd->tag(), trackslots); + + chd_error state = CHDERR_NONE; + + mfmhd_trackimage* previous = NULL; + mfmhd_trackimage* current = NULL; + + m_mfmhd = mfmhd; + + // Load some tracks into the cache + int track = 0; + int head = 0; + int cylinder = 0; + + while (track < trackslots) + { + if (TRACE_CACHE && TRACE_DETAIL) logerror("%s: MFM HD allocate cache slot\n", mfmhd->tag()); + previous = current; + current = global_alloc(mfmhd_trackimage); + current->encdata = global_alloc_array(UINT16, tracksize); + + // Load the first tracks into the slots + state = m_mfmhd->load_track(current->encdata, cylinder, head); + if (state != CHDERR_NONE) throw emu_fatalerror("Cannot load (c=%d,h=%d) from hard disk", cylinder, head); + + current->dirty = false; + current->cylinder = cylinder; + current->head = head; + + // We will read all heads per cylinder first, then go to the next cylinder. + if (++head >= mfmhd->get_actual_heads()) + { + head = 0; + cylinder++; + } + current->next = NULL; + + if (previous != NULL) + previous->next = current; + else + // Head + m_tracks = current; + + // Count the number of loaded tracks + track++; + } +} + +/* + Delivers the track image. + First look up the track image in the cache. If not present, load it from + the CHD, convert it, and evict the least recently used line. + The searched track will be the first in m_tracks. +*/ +UINT16* mfmhd_trackimage_cache::get_trackimage(int cylinder, int head) +{ + // Search the cached track images + mfmhd_trackimage* current = m_tracks; + mfmhd_trackimage* previous = NULL; + + chd_error state = CHDERR_NONE; + + // Repeat the search. This loop should run at most twice; once for a direct hit, + // and twice on miss, then the second iteration will be a hit. + while (state == CHDERR_NONE) + { + // A simple linear search + while (current != NULL) + { + if (current->cylinder == cylinder && current->head == head) + { + // found it + // move it to the front of the chain for LRU + if (previous != NULL) + { + previous->next = current->next; // pull out here + current->next = m_tracks; // put the previous head into the next field + m_tracks = current; // set this line as new head + } + return current->encdata; + } + else + { + // Don't lose the pointer to the next tail + if (current->next != NULL) previous = current; + current = current->next; + } + } + // If we are here, we have a cache miss. + // Evict the last line + // Load the new line into that line + // Then look it up again, which will move it to the front + + // previous points to the second to last element + current = previous->next; + if (TRACE_CACHE) logerror("%s: MFM HD cache: evict line (c=%d,h=%d)\n", m_mfmhd->tag(), current->cylinder, current->head); + + if (current->dirty) + { + m_mfmhd->write_track(current->encdata, current->cylinder, current->head); + current->dirty = false; + } + + state = m_mfmhd->load_track(current->encdata, cylinder, head); + + current->dirty = false; + current->cylinder = cylinder; + current->head = head; + } + // If we are here we have a CHD error. + return NULL; +} + +// ================================================================ + +mfm_harddisk_connector::mfm_harddisk_connector(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock): + device_t(mconfig, MFM_HD_CONNECTOR, "MFM hard disk connector", tag, owner, clock, "mfm_hd_connector", __FILE__), + device_slot_interface(mconfig, *this) +{ +} + +mfm_harddisk_connector::~mfm_harddisk_connector() +{ +} + +mfm_harddisk_device* mfm_harddisk_connector::get_device() +{ + return dynamic_cast(get_card_device()); +} + +void mfm_harddisk_connector::configure(mfmhd_enc_t encoding, int spinupms, int cache, const mfmhd_format_type format) +{ + m_encoding = encoding; + m_spinupms = spinupms; + m_cachesize = cache; + m_format = format(); +} + +void mfm_harddisk_connector::device_config_complete() +{ + mfm_harddisk_device *dev = get_device(); + if (dev != NULL) + { + dev->set_encoding(m_encoding); + dev->set_spinup_time(m_spinupms); + dev->set_cache_size(m_cachesize); + dev->set_format(m_format); + } +} + +const device_type MFM_HD_CONNECTOR = &device_creator; diff --git a/src/devices/imagedev/mfmhd.h b/src/devices/imagedev/mfmhd.h new file mode 100644 index 00000000000..c15b892423d --- /dev/null +++ b/src/devices/imagedev/mfmhd.h @@ -0,0 +1,250 @@ +// license:LGPL-2.1+ +// copyright-holders:Michael Zapf +/**************************************************************************** + + MFM hard disk emulation + + See mfmhd.c for documentation + + Michael Zapf + August 2015 + +*****************************************************************************/ + +#ifndef __MFMHD__ +#define __MFMHD__ + +#include "emu.h" +#include "imagedev/harddriv.h" +#include "formats/mfm_hd.h" + +class mfm_harddisk_device; + +class mfmhd_trackimage +{ +public: + bool dirty; + int cylinder; + int head; + UINT16* encdata; // MFM encoding per byte + mfmhd_trackimage* next; +}; + +class mfmhd_trackimage_cache +{ +public: + mfmhd_trackimage_cache(); + ~mfmhd_trackimage_cache(); + void init(mfm_harddisk_device* mfmhd, int tracksize, int trackslots); + UINT16* get_trackimage(int cylinder, int head); + void mark_current_as_dirty(); + void cleanup(); + void write_back_one(); + +private: + mfm_harddisk_device* m_mfmhd; + mfmhd_trackimage* m_tracks; +}; + +class mfm_harddisk_device : public harddisk_image_device, + public device_slot_card_interface +{ +public: + mfm_harddisk_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + ~mfm_harddisk_device(); + + typedef delegate index_pulse_cb; + typedef delegate ready_cb; + typedef delegate seek_complete_cb; + + void setup_index_pulse_cb(index_pulse_cb cb); + void setup_ready_cb(ready_cb cb); + void setup_seek_complete_cb(seek_complete_cb cb); + + // Configuration + void set_encoding(mfmhd_enc_t encoding) { m_encoding = encoding; } + void set_spinup_time(int spinupms) { m_spinupms = spinupms; } + void set_cache_size(int tracks) { m_cachelines = tracks; } + void set_format(mfmhd_image_format_t* format) { m_format = format; } + + mfmhd_enc_t get_encoding() { return m_encoding; } + + // Active low lines. We're using ASSERT=0 / CLEAR=1 + line_state ready_r() { return m_ready? ASSERT_LINE : CLEAR_LINE; } + line_state seek_complete_r() { return m_seek_complete? ASSERT_LINE : CLEAR_LINE; } ; + line_state trk00_r() { return m_current_cylinder==0? ASSERT_LINE : CLEAR_LINE; } + + // Data output towards controller + bool read(attotime &from_when, const attotime &limit, UINT16 &data); + + // Data input from controller + bool write(attotime &from_when, const attotime &limit, UINT16 cdata, bool wpcom=false, bool reduced_wc=false); + + // Step + void step_w(line_state line); + void direction_in_w(line_state line); + + // Head select + void headsel_w(int head) { m_current_head = head & 0x0f; } + + bool call_load(); + void call_unload(); + + // Tells us the time when the track ends (next index pulse). Needed by the controller. + attotime track_end_time(); + + // Access the tracks on the image. Used as a callback from the cache. + chd_error load_track(UINT16* data, int cylinder, int head); + void write_track(UINT16* data, int cylinder, int head); + + // Delivers the number of heads according to the loaded image + int get_actual_heads(); + +protected: + void device_start(); + void device_stop(); + void device_reset(); + void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + std::string tts(const attotime &t); + + emu_timer *m_index_timer, *m_spinup_timer, *m_seek_timer, *m_cache_timer; + index_pulse_cb m_index_pulse_cb; + ready_cb m_ready_cb; + seek_complete_cb m_seek_complete_cb; + + int m_max_cylinders; + int m_phys_cylinders; + int m_actual_cylinders; // after reading the CHD + int m_max_heads; + int m_landing_zone; + int m_precomp_cyl; + int m_redwc_cyl; + + int m_maxseek_time; + int m_seeknext_time; + +private: + mfmhd_enc_t m_encoding; + int m_cell_size; // nanoseconds + int m_trackimage_size; // number of 16-bit cell blocks (data bytes) + int m_spinupms; + int m_rpm; + int m_interleave; + int m_cachelines; + bool m_ready; + int m_current_cylinder; + int m_current_head; + int m_track_delta; + int m_step_phase; + bool m_seek_complete; + bool m_seek_inward; + bool m_autotruncation; + bool m_recalibrated; + line_state m_step_line; // keep the last state + + attotime m_spinup_time; + attotime m_revolution_start_time; + attotime m_rev_time; + + attotime m_settle_time; + attotime m_step_time; + + mfmhd_trackimage_cache* m_cache; + mfmhd_image_format_t* m_format; + + void prepare_track(int cylinder, int head); + void head_move(); + void recalibrate(); + + // Common routine for read/write + bool find_position(attotime &from_when, const attotime &limit, int &bytepos, int &bitpos); +}; + +/* + The Generic drive is a MFM drive that has just enough heads and cylinders + to handle the CHD image. + + Specific Seagate models: + + ST-213: 10 MB + ST-225: 20 MB + ST-251: 40 MB +*/ +class mfm_hd_generic_device : public mfm_harddisk_device +{ +public: + mfm_hd_generic_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +extern const device_type MFMHD_GENERIC; + +class mfm_hd_st213_device : public mfm_harddisk_device +{ +public: + mfm_hd_st213_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +extern const device_type MFMHD_ST213; + +class mfm_hd_st225_device : public mfm_harddisk_device +{ +public: + mfm_hd_st225_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +extern const device_type MFMHD_ST225; + +class mfm_hd_st251_device : public mfm_harddisk_device +{ +public: + mfm_hd_st251_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +extern const device_type MFMHD_ST251; + + +/* Connector for a MFM hard disk. See also floppy.c */ +class mfm_harddisk_connector : public device_t, + public device_slot_interface +{ +public: + mfm_harddisk_connector(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + ~mfm_harddisk_connector(); + + mfm_harddisk_device *get_device(); + + void configure(mfmhd_enc_t encoding, int spinupms, int cache, mfmhd_format_type format); + +protected: + void device_start() { }; + void device_config_complete(); + +private: + mfmhd_enc_t m_encoding; + int m_spinupms; + int m_cachesize; + mfmhd_image_format_t* m_format; +}; + +extern const device_type MFM_HD_CONNECTOR; + +/* + Add a harddisk connector. + Parameters: + _tag = Tag of the connector + _slot_intf = Selection of hard drives + _def_slot = Default hard drive + _enc = Encoding (see comments in mfm_hd.c) + _spinupms = Spinup time in milliseconds (some configurations assume that the + user has turned on the hard disk before turning on the system. We cannot + emulate this, so we allow for shorter times) + _cache = number of cached MFM tracks +*/ +#define MCFG_MFM_HARDDISK_CONN_ADD(_tag, _slot_intf, _def_slot, _enc, _spinupms, _cache, _format) \ + MCFG_DEVICE_ADD(_tag, MFM_HD_CONNECTOR, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) \ + static_cast(device)->configure(_enc, _spinupms, _cache, _format); + + +#endif diff --git a/src/devices/imagedev/midiin.c b/src/devices/imagedev/midiin.c new file mode 100644 index 00000000000..e412409aa38 --- /dev/null +++ b/src/devices/imagedev/midiin.c @@ -0,0 +1,176 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/********************************************************************* + + midiin.c + + MIDI In image device and serial transmitter + +*********************************************************************/ + +#include "emu.h" +#include "midiin.h" +#include "osdepend.h" + +/*************************************************************************** + IMPLEMENTATION +***************************************************************************/ + +const device_type MIDIIN = &device_creator; + +/*------------------------------------------------- + ctor +-------------------------------------------------*/ + +midiin_device::midiin_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, MIDIIN, "MIDI In image device", tag, owner, clock, "midiin", __FILE__), + device_image_interface(mconfig, *this), + device_serial_interface(mconfig, *this), + m_input_cb(*this) +{ +} + +/*------------------------------------------------- + device_start +-------------------------------------------------*/ + +void midiin_device::device_start() +{ + m_input_cb.resolve_safe(); + m_timer = timer_alloc(0); + m_midi = NULL; + m_timer->enable(false); +} + +void midiin_device::device_reset() +{ + m_tx_busy = false; + m_xmit_read = m_xmit_write = 0; + + // we don't Rx, we Tx at 31250 8-N-1 + set_data_frame(1, 8, PARITY_NONE, STOP_BITS_1); + set_rcv_rate(0); + set_tra_rate(31250); +} + +/*------------------------------------------------- + device_config_complete +-------------------------------------------------*/ + +void midiin_device::device_config_complete(void) +{ + update_names(); +} + +/*------------------------------------------------- + device_timer +-------------------------------------------------*/ + +void midiin_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + if (id) { + device_serial_interface::device_timer(timer, id, param, ptr); + return; + } + + UINT8 buf[8192*4]; + int bytesRead; + + if (m_midi == NULL) { + return; + } + + while (m_midi->poll()) + { + bytesRead = m_midi->read(buf); + + if (bytesRead > 0) + { + for (int i = 0; i < bytesRead; i++) + { + xmit_char(buf[i]); + } + } + } +} + +/*------------------------------------------------- + call_load +-------------------------------------------------*/ + +bool midiin_device::call_load(void) +{ + m_midi = machine().osd().create_midi_device(); + + if (!m_midi->open_input(filename())) + { + global_free(m_midi); + m_midi = NULL; + return IMAGE_INIT_FAIL; + } + + m_timer->adjust(attotime::from_hz(1500), 0, attotime::from_hz(1500)); + m_timer->enable(true); + return IMAGE_INIT_PASS; +} + +/*------------------------------------------------- + call_unload +-------------------------------------------------*/ + +void midiin_device::call_unload(void) +{ + if (m_midi) + { + m_midi->close(); + global_free(m_midi); + } + m_timer->enable(false); + m_midi = NULL; +} + +void midiin_device::tra_complete() +{ + // is there more waiting to send? + if (m_xmit_read != m_xmit_write) + { +// printf("tx1 %02x\n", m_xmitring[m_xmit_read]); + transmit_register_setup(m_xmitring[m_xmit_read++]); + if (m_xmit_read >= XMIT_RING_SIZE) + { + m_xmit_read = 0; + } + } + else + { + m_tx_busy = false; + } +} + +void midiin_device::tra_callback() +{ + int bit = transmit_register_get_data_bit(); + m_input_cb(bit); +} + +void midiin_device::xmit_char(UINT8 data) +{ +// printf("MIDI in: xmit %02x\n", data); + + // if tx is busy it'll pick this up automatically when it completes + if (!m_tx_busy) + { + m_tx_busy = true; +// printf("tx0 %02x\n", data); + transmit_register_setup(data); + } + else + { + // tx is busy, it'll pick this up next time + m_xmitring[m_xmit_write++] = data; + if (m_xmit_write >= XMIT_RING_SIZE) + { + m_xmit_write = 0; + } + } +} diff --git a/src/devices/imagedev/midiin.h b/src/devices/imagedev/midiin.h new file mode 100644 index 00000000000..d8cc99eb0aa --- /dev/null +++ b/src/devices/imagedev/midiin.h @@ -0,0 +1,79 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/********************************************************************* + + midiin.h + + MIDI In image device + +*********************************************************************/ + +#ifndef __MIDIIN_H__ +#define __MIDIIN_H__ + + +#define MCFG_MIDIIN_INPUT_CB(_devcb) \ + devcb = &midiin_device::set_input_callback(*device, DEVCB_##_devcb); + + +/*************************************************************************** + TYPE DEFINITIONS +***************************************************************************/ + +class midiin_device : public device_t, + public device_image_interface, + public device_serial_interface +{ +public: + // construction/destruction + midiin_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + template static devcb_base &set_input_callback(device_t &device, _Object object) { return downcast(device).m_input_cb.set_callback(object); } + + // image-level overrides + virtual bool call_load(); + virtual void call_unload(); + + // image device + virtual iodevice_t image_type() const { return IO_MIDIIN; } + virtual bool is_readable() const { return 1; } + virtual bool is_writeable() const { return 0; } + virtual bool is_creatable() const { return 0; } + virtual bool must_be_loaded() const { return 0; } + virtual bool is_reset_on_load() const { return 0; } + virtual const char *file_extensions() const { return "mid"; } + virtual bool core_opens_image_file() const { return FALSE; } + virtual const option_guide *create_option_guide() const { return NULL; } + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + virtual void device_config_complete(); + + // serial overrides + virtual void tra_complete(); // Tx completed sending byte + virtual void tra_callback(); // Tx send bit + +private: + static const int XMIT_RING_SIZE = (8192*4*4); + + void xmit_char(UINT8 data); + + osd_midi_device *m_midi; + emu_timer *m_timer; + devcb_write_line m_input_cb; + UINT8 m_xmitring[XMIT_RING_SIZE]; + int m_xmit_read, m_xmit_write; + bool m_tx_busy; +}; + +// device type definition +extern const device_type MIDIIN; + +// device iterator +typedef device_type_iterator<&device_creator, midiin_device> midiin_device_iterator; + +#endif /* __MIDIIN_H__ */ diff --git a/src/devices/imagedev/midiout.c b/src/devices/imagedev/midiout.c new file mode 100644 index 00000000000..97ecb36ab89 --- /dev/null +++ b/src/devices/imagedev/midiout.c @@ -0,0 +1,104 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/********************************************************************* + + midiout.c + + MIDI Out image device and serial receiver + +*********************************************************************/ + +#include "emu.h" +#include "osdepend.h" +#include "midiout.h" + +/*************************************************************************** + IMPLEMENTATION +***************************************************************************/ + +const device_type MIDIOUT = &device_creator; + +/*------------------------------------------------- + ctor +-------------------------------------------------*/ + +midiout_device::midiout_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, MIDIOUT, "MIDI Out image device", tag, owner, clock, "midiout", __FILE__), + device_image_interface(mconfig, *this), + device_serial_interface(mconfig, *this) +{ +} + +/*------------------------------------------------- + device_start +-------------------------------------------------*/ + +void midiout_device::device_start() +{ + m_midi = NULL; +} + +void midiout_device::device_reset() +{ + // we don't Tx, we Rx at 31250 8-N-1 + set_data_frame(1, 8, PARITY_NONE, STOP_BITS_1); + set_rcv_rate(31250); + set_tra_rate(0); +} + +void midiout_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + device_serial_interface::device_timer(timer, id, param, ptr); +} + +/*------------------------------------------------- + device_config_complete +-------------------------------------------------*/ + +void midiout_device::device_config_complete(void) +{ + update_names(); +} + +/*------------------------------------------------- + call_load +-------------------------------------------------*/ + +bool midiout_device::call_load(void) +{ + m_midi = machine().osd().create_midi_device(); + + if (!m_midi->open_output(filename())) + { + global_free(m_midi); + m_midi = NULL; + return IMAGE_INIT_FAIL; + } + + return IMAGE_INIT_PASS; +} + +/*------------------------------------------------- + call_unload +-------------------------------------------------*/ + +void midiout_device::call_unload(void) +{ + if (m_midi) + { + m_midi->close(); + global_free(m_midi); + m_midi = NULL; + } +} + +void midiout_device::rcv_complete() // Rx completed receiving byte +{ + receive_register_extract(); + UINT8 data = get_received_char(); + + if (m_midi) + { + m_midi->write(data); + } +} diff --git a/src/devices/imagedev/midiout.h b/src/devices/imagedev/midiout.h new file mode 100644 index 00000000000..5ac4d7c3ed4 --- /dev/null +++ b/src/devices/imagedev/midiout.h @@ -0,0 +1,74 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/********************************************************************* + + midiout.h + + MIDI Out image device + +*********************************************************************/ + +#ifndef __MIDIOUT_H__ +#define __MIDIOUT_H__ + + +/*************************************************************************** + CONSTANTS +***************************************************************************/ + + +#define MCFG_MIDIOUT_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, MIDIOUT, 0) + + +/*************************************************************************** + TYPE DEFINITIONS +***************************************************************************/ + +class midiout_device : public device_t, + public device_image_interface, + public device_serial_interface +{ +public: + // construction/destruction + midiout_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // image-level overrides + virtual bool call_load(); + virtual void call_unload(); + + // image device + virtual iodevice_t image_type() const { return IO_MIDIOUT; } + virtual bool is_readable() const { return 0; } + virtual bool is_writeable() const { return 1; } + virtual bool is_creatable() const { return 0; } + virtual bool must_be_loaded() const { return 0; } + virtual bool is_reset_on_load() const { return 0; } + virtual const char *file_extensions() const { return "mid"; } + virtual bool core_opens_image_file() const { return FALSE; } + virtual const option_guide *create_option_guide() const { return NULL; } + + virtual void tx(UINT8 state) { rx_w(state); } + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + virtual void device_config_complete(); + + // serial overrides + virtual void rcv_complete(); // Rx completed receiving byte + +private: + osd_midi_device *m_midi; +}; + +// device type definition +extern const device_type MIDIOUT; + +// device iterator +typedef device_type_iterator<&device_creator, midiout_device> midiout_device_iterator; + +#endif /* __MIDIOUT_H__ */ diff --git a/src/devices/imagedev/printer.c b/src/devices/imagedev/printer.c new file mode 100644 index 00000000000..aedfecbeddd --- /dev/null +++ b/src/devices/imagedev/printer.c @@ -0,0 +1,110 @@ +// license:BSD-3-Clause +// copyright-holders:Nathan Woods, Miodrag Milanovic +/**************************************************************************** + + printer.c + + Code for handling printer devices + +****************************************************************************/ + +#include "emu.h" +#include "printer.h" + + +// device type definition +const device_type PRINTER = &device_creator; + +//------------------------------------------------- +// printer_image_device - constructor +//------------------------------------------------- + +printer_image_device::printer_image_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, PRINTER, "Printer", tag, owner, clock, "printer_image", __FILE__), + device_image_interface(mconfig, *this), + m_online_cb(*this) +{ +} + +//------------------------------------------------- +// device_config_complete - perform any +// operations now that the configuration is +// complete +//------------------------------------------------- + +void printer_image_device::device_config_complete() +{ + // set brief and instance name + update_names(); +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void printer_image_device::device_start() +{ + m_online_cb.resolve(); +} + +/*************************************************************************** + IMPLEMENTATION +***************************************************************************/ + +/*------------------------------------------------- + printer_is_ready - checks to see if a printer + is ready +-------------------------------------------------*/ + +int printer_image_device::is_ready() +{ + return exists() != 0; +} + + + +/*------------------------------------------------- + printer_output - outputs data to a printer +-------------------------------------------------*/ + +void printer_image_device::output(UINT8 data) +{ + if (exists()) + { + fwrite(&data, 1); + } +} + +/*------------------------------------------------- + DEVICE_IMAGE_CREATE( printer ) +-------------------------------------------------*/ + +bool printer_image_device::call_create(int format_type, option_resolution *format_options) +{ + return call_load(); +} + +/*------------------------------------------------- + DEVICE_IMAGE_LOAD( printer ) +-------------------------------------------------*/ +bool printer_image_device::call_load() +{ + /* send notify that the printer is now online */ + if (!m_online_cb.isnull()) + m_online_cb(TRUE); + + /* we don't need to do anything special */ + return IMAGE_INIT_PASS; +} + + +/*------------------------------------------------- + DEVICE_IMAGE_UNLOAD( printer ) +-------------------------------------------------*/ +void printer_image_device::call_unload() +{ + /* send notify that the printer is now offline */ + if (!m_online_cb.isnull()) + m_online_cb(FALSE); +} diff --git a/src/devices/imagedev/printer.h b/src/devices/imagedev/printer.h new file mode 100644 index 00000000000..8e6ca051fdc --- /dev/null +++ b/src/devices/imagedev/printer.h @@ -0,0 +1,65 @@ +// license:BSD-3-Clause +// copyright-holders:Nathan Woods, Miodrag Milanovic +/**************************************************************************** + + printer.h + + Code for handling printer devices + +****************************************************************************/ + +#ifndef __PRINTER_H__ +#define __PRINTER_H__ + +#define MCFG_PRINTER_ONLINE_CB(_devcb) \ + devcb = &printer_image_device::set_online_callback(*device, DEVCB_##_devcb); + +/*************************************************************************** + TYPE DEFINITIONS +***************************************************************************/ + +// ======================> printer_image_device + +class printer_image_device : public device_t, + public device_image_interface +{ +public: + // construction/destruction + printer_image_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + template static devcb_base &set_online_callback(device_t &device, _Object object) { return downcast(device).m_online_cb.set_callback(object); } + + // image-level overrides + virtual bool call_load(); + virtual bool call_create(int format_type, option_resolution *format_options); + virtual void call_unload(); + + // image device + virtual iodevice_t image_type() const { return IO_PRINTER; } + virtual bool is_readable() const { return 0; } + virtual bool is_writeable() const { return 1; } + virtual bool is_creatable() const { return 1; } + virtual bool must_be_loaded() const { return 0; } + virtual bool is_reset_on_load() const { return 0; } + virtual const char *file_extensions() const { return "prn"; } + virtual const option_guide *create_option_guide() const { return NULL; } + + // specific implementation + + /* checks to see if a printer is ready */ + int is_ready(); + /* outputs data to a printer */ + void output(UINT8 data); +protected: + // device-level overrides + virtual void device_start(); + virtual void device_config_complete(); + + devcb_write_line m_online_cb; +}; + + +// device type definition +extern const device_type PRINTER; + +#endif /* __PRINTER_H__ */ diff --git a/src/devices/imagedev/snapquik.c b/src/devices/imagedev/snapquik.c new file mode 100644 index 00000000000..02fc2fa241e --- /dev/null +++ b/src/devices/imagedev/snapquik.c @@ -0,0 +1,96 @@ +// license:BSD-3-Clause +// copyright-holders:Nathan Woods, Miodrag Milanovic +/********************************************************************* + + snapquik.h + + Snapshots and quickloads + +*********************************************************************/ + +#include "emu.h" +#include "snapquik.h" + +// device type definition +const device_type SNAPSHOT = &device_creator; + +//------------------------------------------------- +// snapshot_image_device - constructor +//------------------------------------------------- + +snapshot_image_device::snapshot_image_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, SNAPSHOT, "Snapshot", tag, owner, clock, "snapshot_image", __FILE__), + device_image_interface(mconfig, *this), + m_interface(NULL), + m_delay_attoseconds(0) +{ +} + +snapshot_image_device::snapshot_image_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_image_interface(mconfig, *this), + m_interface(NULL), + m_delay_attoseconds(0) +{ +} +//------------------------------------------------- +// snapshot_image_device - destructor +//------------------------------------------------- + +snapshot_image_device::~snapshot_image_device() +{ +} + +//------------------------------------------------- +// device_config_complete - perform any +// operations now that the configuration is +// complete +//------------------------------------------------- + +void snapshot_image_device::device_config_complete() +{ + // set brief and instance name + update_names(); +} + +/*------------------------------------------------- + TIMER_CALLBACK_MEMBER(process_snapshot_or_quickload) +-------------------------------------------------*/ + +TIMER_CALLBACK_MEMBER(snapshot_image_device::process_snapshot_or_quickload) +{ + /* invoke the load */ + m_load(*this, filetype(), length()); +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void snapshot_image_device::device_start() +{ + /* allocate a timer */ + m_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(snapshot_image_device::process_snapshot_or_quickload),this)); +} + +/*------------------------------------------------- + call_load +-------------------------------------------------*/ +bool snapshot_image_device::call_load() +{ + /* adjust the timer */ + m_timer->adjust(attotime(m_delay_seconds, m_delay_attoseconds),0); + return IMAGE_INIT_PASS; +} + +// device type definition +const device_type QUICKLOAD = &device_creator; + +//------------------------------------------------- +// quickload_image_device - constructor +//------------------------------------------------- + +quickload_image_device::quickload_image_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : snapshot_image_device(mconfig, QUICKLOAD, "Quickload", tag, owner, clock, "quickload", __FILE__) +{ +} diff --git a/src/devices/imagedev/snapquik.h b/src/devices/imagedev/snapquik.h new file mode 100644 index 00000000000..a9e186ba2bd --- /dev/null +++ b/src/devices/imagedev/snapquik.h @@ -0,0 +1,103 @@ +// license:BSD-3-Clause +// copyright-holders:Nathan Woods, Miodrag Milanovic +/********************************************************************* + + snapquik.h + + Snapshots and quickloads + +*********************************************************************/ + +#ifndef __SNAPQUIK_H__ +#define __SNAPQUIK_H__ + +typedef delegate snapquick_load_delegate; + +// ======================> snapshot_image_device +class snapshot_image_device : public device_t, + public device_image_interface +{ +public: + // construction/destruction + snapshot_image_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + snapshot_image_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + virtual ~snapshot_image_device(); + + static void static_set_interface(device_t &device, const char *_interface) { downcast(device).m_interface = _interface; } + + // image-level overrides + virtual bool call_load(); + virtual bool call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry) { return load_software(swlist, swname, start_entry); } + virtual iodevice_t image_type() const { return IO_SNAPSHOT; } + + virtual bool is_readable() const { return 1; } + virtual bool is_writeable() const { return 0; } + virtual bool is_creatable() const { return 0; } + virtual bool must_be_loaded() const { return 0; } + virtual bool is_reset_on_load() const { return 0; } + virtual const char *image_interface() const { return m_interface; } + virtual const char *file_extensions() const { return m_file_extensions; } + virtual const option_guide *create_option_guide() const { return NULL; } + + TIMER_CALLBACK_MEMBER(process_snapshot_or_quickload); + void set_handler(snapquick_load_delegate load, const char *ext, seconds_t sec) { m_load = load; m_file_extensions = ext; m_delay_seconds = sec; }; +protected: + // device-level overrides + virtual void device_config_complete(); + virtual void device_start(); + + snapquick_load_delegate m_load; /* loading function */ + const char * m_file_extensions; /* file extensions */ + const char * m_interface; + seconds_t m_delay_seconds; /* loading delay (seconds) */ + attoseconds_t m_delay_attoseconds; /* loading delay (attoseconds) */ + emu_timer *m_timer; +}; + +// device type definition +extern const device_type SNAPSHOT; + +// ======================> quickload_image_device + +class quickload_image_device : public snapshot_image_device +{ +public: + // construction/destruction + quickload_image_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual iodevice_t image_type() const { return IO_QUICKLOAD; } +}; + +// device type definition +extern const device_type QUICKLOAD; + +/*************************************************************************** + DEVICE CONFIGURATION MACROS +***************************************************************************/ +#define SNAPSHOT_LOAD_MEMBER_NAME(_name) snapshot_load_##_name +#define SNAPSHOT_LOAD_NAME(_class,_name) _class::SNAPSHOT_LOAD_MEMBER_NAME(_name) +#define DECLARE_SNAPSHOT_LOAD_MEMBER(_name) int SNAPSHOT_LOAD_MEMBER_NAME(_name)(device_image_interface &image, const char *file_type, int snapshot_size) +#define SNAPSHOT_LOAD_MEMBER(_class,_name) int SNAPSHOT_LOAD_NAME(_class,_name)(device_image_interface &image, const char *file_type, int snapshot_size) +#define SNAPSHOT_LOAD_DELEGATE(_class,_name) snapquick_load_delegate(&SNAPSHOT_LOAD_NAME(_class,_name),#_class "::snapshot_load_" #_name, downcast<_class *>(device->owner())) + +#define QUICKLOAD_LOAD_MEMBER_NAME(_name) quickload_load##_name +#define QUICKLOAD_LOAD_NAME(_class,_name) _class::QUICKLOAD_LOAD_MEMBER_NAME(_name) +#define DECLARE_QUICKLOAD_LOAD_MEMBER(_name) int QUICKLOAD_LOAD_MEMBER_NAME(_name)(device_image_interface &image, const char *file_type, int quickload_size) +#define QUICKLOAD_LOAD_MEMBER(_class,_name) int QUICKLOAD_LOAD_NAME(_class,_name)(device_image_interface &image, const char *file_type, int quickload_size) +#define QUICKLOAD_LOAD_DELEGATE(_class,_name) snapquick_load_delegate(&QUICKLOAD_LOAD_NAME(_class,_name),#_class "::quickload_load_" #_name, downcast<_class *>(device->owner())) + +#define MCFG_SNAPSHOT_ADD(_tag, _class, _load, _file_extensions, _delay) \ + MCFG_DEVICE_ADD(_tag, SNAPSHOT, 0) \ + static_cast(device)->set_handler(SNAPSHOT_LOAD_DELEGATE(_class,_load), _file_extensions, _delay); + +#define MCFG_SNAPSHOT_INTERFACE(_interface) \ + snapshot_image_device::static_set_interface(*device, _interface); + +#define MCFG_QUICKLOAD_ADD(_tag, _class, _load, _file_extensions, _delay) \ + MCFG_DEVICE_ADD(_tag, QUICKLOAD, 0) \ + static_cast(device)->set_handler(QUICKLOAD_LOAD_DELEGATE(_class,_load), _file_extensions, _delay); + +#define MCFG_QUICKLOAD_INTERFACE(_interface) \ + quickload_image_device::static_set_interface(*device, _interface); + +#endif /* __SNAPQUIK_H__ */ diff --git a/src/devices/machine/40105.c b/src/devices/machine/40105.c new file mode 100644 index 00000000000..e2f059dfed0 --- /dev/null +++ b/src/devices/machine/40105.c @@ -0,0 +1,172 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + CMOS 40105 FIFO Register emulation + +**********************************************************************/ + +#include "40105.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define LOG 0 + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type CMOS_40105 = &device_creator; + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// cmos_40105_device - constructor +//------------------------------------------------- + +cmos_40105_device::cmos_40105_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, CMOS_40105, "40105", tag, owner, clock, "40105", __FILE__), + m_write_dir(*this), + m_write_dor(*this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void cmos_40105_device::device_start() +{ + // resolve callbacks + m_write_dir.resolve_safe(); + m_write_dor.resolve_safe(); + + // state saving + save_item(NAME(m_d)); + save_item(NAME(m_q)); + save_item(NAME(m_dir)); + save_item(NAME(m_dor)); + save_item(NAME(m_si)); + save_item(NAME(m_so)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void cmos_40105_device::device_reset() +{ + m_fifo = std::queue(); + + m_dir = 1; + m_dor = 0; + m_si = 0; + + m_write_dir(m_dir); + m_write_dor(m_dor); +} + + +//------------------------------------------------- +// read - read Q +//------------------------------------------------- + +UINT8 cmos_40105_device::read() +{ + return m_q; +} + + +//------------------------------------------------- +// write - write D +//------------------------------------------------- + +void cmos_40105_device::write(UINT8 data) +{ + m_d = data & 0x0f; +} + + +//------------------------------------------------- +// si_w - shift in write +//------------------------------------------------- + +WRITE_LINE_MEMBER( cmos_40105_device::si_w ) +{ + if (m_dir && !m_si && state) + { + m_fifo.push(m_d); + + if (m_fifo.size() == 16) + { + m_dir = 0; + m_write_dir(m_dir); + } + + if (!m_dor) + { + m_dor = 1; + m_write_dor(m_dor); + } + + } + + m_si = state; +} + + +//------------------------------------------------- +// so_w - shift out write +//------------------------------------------------- + +WRITE_LINE_MEMBER( cmos_40105_device::so_w ) +{ + if (m_dor && m_so && !m_so) + { + m_dor = 0; + m_write_dor(m_dor); + + m_q = m_fifo.front(); + m_fifo.pop(); + + if (m_fifo.size() > 0) + { + m_dor = 1; + m_write_dor(m_dor); + } + } + + m_so = state; +} + + +//------------------------------------------------- +// dir_r - data in ready read +//------------------------------------------------- + +READ_LINE_MEMBER( cmos_40105_device::dir_r ) +{ + return m_dir; +} + + +//------------------------------------------------- +// dor_r - data out ready read +//------------------------------------------------- + +READ_LINE_MEMBER( cmos_40105_device::dor_r ) +{ + return m_dor; +} diff --git a/src/devices/machine/40105.h b/src/devices/machine/40105.h new file mode 100644 index 00000000000..bc632c8cdca --- /dev/null +++ b/src/devices/machine/40105.h @@ -0,0 +1,80 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + CMOS 40105 FIFO Register emulation + +**********************************************************************/ + +#pragma once + +#ifndef __CMOS_40105__ +#define __CMOS_40105__ + +#include "emu.h" +#include + + + +///************************************************************************* +// INTERFACE CONFIGURATION MACROS +///************************************************************************* + +#define MCFG_40105_ADD(_tag, _dir, _dor) \ + MCFG_DEVICE_ADD(_tag, CMOS_40105, 0) \ + downcast(device)->set_dir_callback(DEVCB_##_dir); \ + downcast(device)->set_dor_callback(DEVCB_##_dor); + + + +///************************************************************************* +// TYPE DEFINITIONS +///************************************************************************* + +// ======================> cmos_40105_device + +class cmos_40105_device : public device_t +{ +public: + // construction/destruction + cmos_40105_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + template void set_dir_callback(_dir dir) { m_write_dir.set_callback(dir); } + template void set_dor_callback(_dor dor) { m_write_dor.set_callback(dor); } + + UINT8 read(); + void write(UINT8 data); + + DECLARE_WRITE_LINE_MEMBER( si_w ); + DECLARE_WRITE_LINE_MEMBER( so_w ); + + DECLARE_READ_LINE_MEMBER( dir_r ); + DECLARE_READ_LINE_MEMBER( dor_r ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + +private: + devcb_write_line m_write_dir; + devcb_write_line m_write_dor; + + std::queue m_fifo; + + UINT8 m_d; + UINT8 m_q; + + int m_dir; + int m_dor; + int m_si; + int m_so; +}; + + +// device type definition +extern const device_type CMOS_40105; + + + +#endif diff --git a/src/devices/machine/53c7xx.c b/src/devices/machine/53c7xx.c new file mode 100644 index 00000000000..f2aad1ad75b --- /dev/null +++ b/src/devices/machine/53c7xx.c @@ -0,0 +1,1776 @@ +// license:BSD-3-Clause +// copyright-holders:Philip Bennett +/********************************************************************* + + 53c7xx.c + + NCR 53C700 SCSI I/O Processor + + + TODO: + * Low-level register accesses + * Remove arbitrary delays + * Add unimplemented SCRIPTS opcodes + +*********************************************************************/ + +#include "emu.h" +#include "53c7xx.h" + + + +//************************************************************************** +// DEBUGGERY +//************************************************************************** + +#define DEBUG_LOG 1 +#define DEBUG_LEVEL 0 + +#if DEBUG_LOG + #define VERBOSE_LOG(machine, level, ...) verbose_log(machine, level, __VA_ARGS__) +#else + #define VERBOSE_LOG(machine, level, ...) +#endif + +static void ATTR_PRINTF(3,4) verbose_log(running_machine &machine, int level, const char* format, ...) +{ + if (level <= DEBUG_LEVEL) + { + char buffer[32768]; + va_list v; + + va_start(v, format); + vsprintf(buffer, format, v); + va_end(v); + + printf("53C7XX (%s): %s", machine.describe_context(), buffer); + } +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +const device_type NCR53C7XX = &device_creator; + +//------------------------------------------------- +// ncr53c7xx_device - constructor/destructor +//------------------------------------------------- + +ncr53c7xx_device::ncr53c7xx_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nscsi_device(mconfig, NCR53C7XX, "53C7xx SCSI", tag, owner, clock, "ncr537xx", __FILE__), + device_execute_interface(mconfig, *this), + m_icount(0), + m_irq_handler(*this), + m_host_write(*this), + m_host_read(*this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void ncr53c7xx_device::device_start() +{ + // set our instruction counter + m_icountptr = &m_icount; + + // resolve line callbacks + m_irq_handler.resolve_safe(); + m_host_read.resolve_safe(0); + m_host_write.resolve_safe(); + + m_tm = timer_alloc(0); + + // The SCRIPTS processor runs at ~2 MIPS so approximate this + set_unscaled_clock(2000000); + + // savestate support + save_item(NAME(m_scntl)); + save_item(NAME(m_sdid)); + save_item(NAME(m_sien)); + save_item(NAME(m_scid)); + save_item(NAME(m_sxfer)); + save_item(NAME(m_sodl)); + save_item(NAME(m_socl)); + save_item(NAME(m_sfbr)); + save_item(NAME(m_sidl)); + save_item(NAME(m_sbdl)); + save_item(NAME(m_sbcl)); + save_item(NAME(m_dstat)); + save_item(NAME(m_sstat)); + save_item(NAME(m_ctest)); + save_item(NAME(m_temp)); + save_item(NAME(m_dfifo)); + save_item(NAME(m_istat)); + save_item(NAME(m_dbc)); + save_item(NAME(m_dcmd)); + save_item(NAME(m_dnad)); + save_item(NAME(m_dsp)); + save_item(NAME(m_dsps)); + save_item(NAME(m_dmode)); + save_item(NAME(m_dien)); + save_item(NAME(m_dwt)); + save_item(NAME(m_dcntl)); + + // other state + save_item(NAME(m_scsi_state)); + save_item(NAME(m_connected)); + save_item(NAME(m_finished)); + save_item(NAME(m_last_data)); + save_item(NAME(m_xfr_phase)); + + save_item(NAME(m_scripts_state)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void ncr53c7xx_device::device_reset() +{ + // Reset registers to defaults + m_scntl[0] = 3 << SCNTL0_ARB_SHIFT; + m_scntl[1] = 0; + m_sdid = 0; + m_sien = 0; + m_scid = 0; + m_sxfer = 0; + m_sodl = 0; + m_socl = 0; + m_sfbr = 0; + m_sidl = 0; + m_sbdl = 0; + m_sbcl = 0; + m_dstat = DSTAT_DFE; + m_sstat[0] = 0; + m_sstat[1] = 0; + m_sstat[2] = 0; + m_ctest[0] = 0; + m_ctest[1] = 0xf0; + m_ctest[2] = 0x21; + m_ctest[3] = 0; + m_ctest[4] = 0; + m_ctest[5] = 0; + m_ctest[6] = 0; + m_ctest[7] = 0; + m_dfifo = 0; + m_istat = 0;//ISTAT_PRE; + m_dmode = 0; + m_dien = 0; + m_dcntl = 0; + + m_finished = false; + m_connected = false; + + scsi_bus->ctrl_wait(scsi_refid, S_SEL | S_BSY | S_RST, S_ALL); + set_scripts_state(SCRIPTS_IDLE); + set_scsi_state(IDLE); + + m_irq_handler(CLEAR_LINE); +} + + +//************************************************************************** +// MEMORY HANDLERS +//************************************************************************** + +//------------------------------------------------- +// read - Host read handler +//------------------------------------------------- + +READ32_MEMBER( ncr53c7xx_device::read ) +{ + VERBOSE_LOG(machine(), 1, "REG R: [%x] (%08X)\n", offset, mem_mask); + + UINT32 ret = 0; + + switch (offset) + { + case 0x0: + { + if (ACCESSING_BITS_0_7) + { + ret = m_scntl[0]; + } + if (ACCESSING_BITS_8_15) + { + ret |= m_scntl[1] << 8; + } + if (ACCESSING_BITS_16_23) + { + ret |= m_sdid << 16; + } + if (ACCESSING_BITS_24_31) + { + ret |= m_sien << 24; + } + + break; + } + + case 0x1: + { + if (ACCESSING_BITS_0_7) + { + ret = m_scid; + } + if (ACCESSING_BITS_8_15) + { + ret |= m_sxfer << 8; + } + if (ACCESSING_BITS_16_23) + { + ret |= m_sodl << 16; + } + if (ACCESSING_BITS_24_31) + { + ret |= m_socl << 24; + } + + break; + } + + case 0x2: + { + if (ACCESSING_BITS_0_7) + { + ret = m_sfbr; + } + if (ACCESSING_BITS_8_15) + { + ret |= m_sidl << 8; + } + if (ACCESSING_BITS_16_23) + { + ret |= m_sbdl << 16; + } + if (ACCESSING_BITS_24_31) + { + ret |= m_sbcl << 24; + } + + break; + } + + case 0x3: + { + if (ACCESSING_BITS_0_7) + { + ret = m_dstat; + m_dstat = 0; + update_irqs(); + } + if (ACCESSING_BITS_8_15) + { + ret |= m_sstat[0] << 8; + m_sstat[0] = 0; + update_irqs(); + } + if (ACCESSING_BITS_16_23) + { + ret |= m_sstat[1] << 16; + } + if (ACCESSING_BITS_24_31) + { + ret |= m_sstat[2] << 24; + } + + break; + } + + case 0x5: + { + if (ACCESSING_BITS_0_7) + { + ret = m_ctest[0]; + } + if (ACCESSING_BITS_8_15) + { + ret |= m_ctest[1] << 8; + } + if (ACCESSING_BITS_16_23) + { + ret |= m_ctest[2] << 16; + } + if (ACCESSING_BITS_24_31) + { + ret |= m_ctest[3] << 24; + } + + break; + } + + case 0x6: + { + if (ACCESSING_BITS_0_7) + { + ret = m_ctest[4]; + } + if (ACCESSING_BITS_8_15) + { + ret |= m_ctest[5] << 8; + } + if (ACCESSING_BITS_16_23) + { + ret |= m_ctest[6] << 16; + } + if (ACCESSING_BITS_24_31) + { + ret |= m_ctest[7] << 24; + } + + break; + } + + case 0x7: + { + ret = m_temp; + + break; + } + + case 0x8: + { + if (ACCESSING_BITS_0_7) + { + ret = m_dfifo; + } + if (ACCESSING_BITS_8_15) + { + ret |= m_istat << 8; + } + + break; + } + + case 0x9: + { + if (ACCESSING_BITS_0_7 || ACCESSING_BITS_8_15 || ACCESSING_BITS_16_23) + { + ret = m_dbc; + } + if (ACCESSING_BITS_24_31) + { + ret |= m_dcmd << 24; + } + + break; + } + + case 0xa: + { + ret = m_dnad; + + break; + } + + case 0xb: + { + ret = m_dsp; + + break; + } + + case 0xc: + { + ret = m_dsps; + + break; + } + + case 0xd: + { + if (ACCESSING_BITS_0_7) + { + ret = m_dmode; + } + + break; + } + + case 0xe: + { + if (ACCESSING_BITS_8_15) + { + ret = m_dien << 8; + } + if (ACCESSING_BITS_16_23) + { + ret |= m_dwt << 16; + + } + if (ACCESSING_BITS_24_31) + { + ret |= m_dcntl << 24; + } + + break; + } + + default: + { + VERBOSE_LOG(machine(), 0, "Unhandled register access"); + } + } + + return ret; +} + + +//------------------------------------------------- +// write - Host write handler +//------------------------------------------------- + +WRITE32_MEMBER( ncr53c7xx_device::write ) +{ + VERBOSE_LOG(machine(), 1, "REG W: [%x] (%08X) %x\n", offset, mem_mask, data); + + switch (offset) + { + case 0x0: + { + if (ACCESSING_BITS_0_7) + { + m_scntl[0] = data; + + if (data & SCNTL0_TRG) + fatalerror("53c7xx: Target mode unsupported!"); + + if (data & SCNTL0_START) + { + // Start arbitration + set_scsi_state(ARBITRATE_WAIT_FREE); + step(true); + } + } + if (ACCESSING_BITS_8_15) + { + m_scntl[1] = data >> 8; + } + if (ACCESSING_BITS_16_23) + { + m_sdid = data >> 16; + } + if (ACCESSING_BITS_24_31) + { + m_sien = data >> 24; + } + + break; + } + + case 0x1: + { + if (ACCESSING_BITS_0_7) + { + m_scid = data; + } + if (ACCESSING_BITS_8_15) + { + m_sxfer = data >> 8; + } + if (ACCESSING_BITS_16_23) + { + m_sodl = data >> 16; + } + if (ACCESSING_BITS_24_31) + { + m_socl = data >> 24; + } + + break; + } + + case 0x6: + { + if (ACCESSING_BITS_0_7) + { + m_ctest[4] = data; + } + if (ACCESSING_BITS_8_15) + { + m_ctest[5] = data >> 8; + } + if (ACCESSING_BITS_16_23) + { + m_ctest[6] = data >> 16; + } + if (ACCESSING_BITS_24_31) + { + m_ctest[7] = data >> 24; + } + + break; + } + + case 0x7: + { + m_temp = data; + + break; + } + + case 0x8: + { + if (ACCESSING_BITS_0_7) + { + m_dfifo = data; + } + if (ACCESSING_BITS_8_15) + { + m_istat = data >> 8; + } + + break; + } + + case 0x9: + { + if (ACCESSING_BITS_0_7 || ACCESSING_BITS_8_15 || ACCESSING_BITS_16_23) + { + m_dbc = data & 0xffffff; + } + if (ACCESSING_BITS_24_31) + { + m_dcmd = data >> 24; + } + + break; + } + + case 0xa: + { + m_dnad = data; + + break; + } + + case 0xb: + { + // Write to the upper byte starts the fetch + m_dsp = data; + + if (m_dmode & 1) + { + set_scripts_state(SCRIPTS_WAIT_MANUAL_START); + } + else + { + set_scripts_state(SCRIPTS_FETCH); + } + + break; + } + + case 0xc: + { + m_dsps = data; + + break; + } + + case 0xd: + { + if (ACCESSING_BITS_0_7) + { + m_dmode = data; + } + + break; + } + + case 0xe: + { + if (ACCESSING_BITS_8_15) + { + m_dien = data >> 8; + } + if (ACCESSING_BITS_16_23) + { + m_dwt = data >> 16; + + if (m_dwt) + fatalerror("53c7xx: DMA Watchdog Timer enabled!"); + } + if (ACCESSING_BITS_24_31) + { + m_dcntl = data >> 24; + + // Note: not self-clearing + if (m_dcntl & 1) // RST + { + device_reset(); + } + else if (m_dcntl & 2) // STD + { + // Only applies to these modes: + // * Manual Start + // * Single Step + // * Pipeline + fatalerror("53c7xx: Start DMA"); + } + else if (m_dcntl & 4) + { + fatalerror("53c7xx: SCSI Low-Level Mode not supported!"); + } + + // TODO: Update clocking + } + + break; + } + + default: + { + VERBOSE_LOG(machine(), 0, "Unhandled register access"); + } + } +} + + + +//************************************************************************** +// SCSI STATE MACHINE +//************************************************************************** + +//------------------------------------------------- +// update_irqs - +//------------------------------------------------- +void ncr53c7xx_device::update_irqs() +{ + if (m_sstat[0] & m_sien) + m_istat |= ISTAT_SIP; + else + m_istat &= ~ISTAT_SIP; + + if (m_dstat & m_dien) + m_istat |= ISTAT_DIP; + else + m_istat &= ~ISTAT_DIP; + + m_irq_handler(m_istat ? ASSERT_LINE : CLEAR_LINE); +} + +//------------------------------------------------- +// set_scsi_state - change SCSI state +//------------------------------------------------- + +void ncr53c7xx_device::set_scsi_state(int state) +{ + VERBOSE_LOG(machine(), 2, "SCSI state change: %x to %x\n", m_scsi_state, state); + + m_scsi_state = state; +} + + +//------------------------------------------------- +// delay - step the SCSI state machine following +// a time delay +//------------------------------------------------- + +void ncr53c7xx_device::delay(const attotime &delay) +{ + m_tm->adjust(delay); +} + + +//------------------------------------------------- +// scsi_ctrl_changed - callback from nscsi_device +//------------------------------------------------- + +void ncr53c7xx_device::scsi_ctrl_changed() +{ + step(false); +} + + +//------------------------------------------------- +// send_byte - send data to a SCSI device +//------------------------------------------------- + +void ncr53c7xx_device::send_byte() +{ + if (m_dbc == 0) + fatalerror("53C7XX: send_byte() - DBC should not be 0\n"); + + set_scsi_state( (m_scsi_state & STATE_MASK) | (SEND_WAIT_SETTLE << SUB_SHIFT) ); + + UINT32 data = m_host_read(m_dnad & ~3, 0xffffffff); + data = data >> ((m_dnad & 3) * 8) & 0xff; + + ++m_dnad; + --m_dbc; + + scsi_bus->data_w(scsi_refid, data); + scsi_bus->ctrl_w(scsi_refid, S_ACK, S_ACK); + scsi_bus->ctrl_wait(scsi_refid, S_REQ, S_REQ); + delay(attotime::from_nsec(5)); +} + + +//------------------------------------------------- +// recv_byte - receive data from a SCSI device +//------------------------------------------------- + +void ncr53c7xx_device::recv_byte() +{ + scsi_bus->ctrl_wait(scsi_refid, S_REQ, S_REQ); + set_scsi_state( (m_scsi_state & STATE_MASK) | (RECV_WAIT_REQ_1 << SUB_SHIFT) ); + step(false); +} + + +//------------------------------------------------- +// device_timer - callback to step the SCSI +// state machine +//------------------------------------------------- + +void ncr53c7xx_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + step(true); +} + + +//------------------------------------------------- +// step - advance the SCSI state machine +//------------------------------------------------- + +void ncr53c7xx_device::step(bool timeout) +{ + UINT32 ctrl = scsi_bus->ctrl_r(); + UINT32 data = scsi_bus->data_r(); + + VERBOSE_LOG(machine(), 2, "Step: CTRL:%x DATA:%x (%d.%d) Timeout:%d\n", ctrl, data, m_scsi_state & STATE_MASK, m_scsi_state >> SUB_SHIFT, timeout); + + // Check for disconnect from target + if (!(m_scntl[0] & SCNTL0_TRG) && m_connected && !(ctrl & S_BSY)) + { + set_scsi_state(FINISHED); + m_connected = false; +// istatus |= I_DISCONNECT; +// reset_disconnect(); +// check_irq(); + } + + switch (m_scsi_state & SUB_MASK ? m_scsi_state & SUB_MASK : m_scsi_state & STATE_MASK) + { + case IDLE: + { + break; + } + + case FINISHED: + { + m_finished = true; + set_scsi_state(IDLE); + step(true); + + break; + } + + case ARBITRATE_WAIT_FREE: + { + if (!timeout) + break; + + // Is the bus free? + if (ctrl & (S_BSY | S_SEL)) + { + // Keep trying until it is + delay(attotime::from_nsec(800)); + } + else + { + // Bus is free; next phase + delay(attotime::from_nsec(800)); + set_scsi_state(ARBITRATE_CHECK_FREE); + } + + break; + } + + case ARBITRATE_CHECK_FREE: + { + if ((ctrl & (S_BSY | S_SEL)) == 0) + { + // Bus is free - assert the controller SCSI ID and BUSY + scsi_bus->ctrl_w(scsi_refid, S_BSY, S_BSY); + + if (((m_scntl[0] >> SCNTL0_ARB_SHIFT) & SCNTL0_ARB_MASK) == 3) + { + // Full arbitration + scsi_bus->data_w(scsi_refid, m_scid); + } + else + { + // Simple arbitration + scsi_bus->data_w(scsi_refid, m_sodl); + } + + set_scsi_state(ARBITRATE_EXAMINE_BUS); + delay(attotime::from_nsec(2400)); + } + + break; + } + + case ARBITRATE_EXAMINE_BUS: + { + if (!timeout) + break; + + if (ctrl & S_SEL) + { + scsi_bus->ctrl_w(scsi_refid, 0, S_BSY); + scsi_bus->data_w(scsi_refid, 0); + + if (((m_scntl[0] >> SCNTL0_ARB_SHIFT) & SCNTL0_ARB_MASK) == 3) + { + // Try again + set_scsi_state(ARBITRATE_WAIT_FREE); + delay(attotime::from_nsec(2400)); + } + else + { + // TODO: Is this right? + m_sstat[1] |= SSTAT1_LOA; + m_scntl[0] &= ~SCNTL0_START; + m_sstat[0] |= SSTAT0_CMP; + update_irqs(); + + set_scsi_state(FINISHED); + step(true); + } + + break; + } + + // Full arbitration? + if (((m_scntl[0] >> SCNTL0_ARB_SHIFT) & SCNTL0_ARB_MASK) == 3) + { + int win; + for (win = 7; win >=0 && !(data & (1 << win)); win--); + + if ((1 << win) != m_scid) + { + scsi_bus->data_w(scsi_refid, 0); + scsi_bus->ctrl_w(scsi_refid, 0, S_ALL); + + delay(attotime::from_nsec(2400)); + break; + } + + // Begin the select phase; assert SEL + m_sstat[1] |= SSTAT1_WOA; + scsi_bus->ctrl_w(scsi_refid, S_SEL, S_SEL); + set_scsi_state(ARBITRATE_ASSERT_SEL); + delay(attotime::from_nsec(1200)); + } + else + { + // TODO: Worth adding another state here? + m_sstat[0] |= SSTAT0_CMP; + m_scntl[0] &= ~SCNTL0_START; + update_irqs(); + set_scsi_state(FINISHED); + step(true); + } + + break; + } + + case ARBITRATE_ASSERT_SEL: + { + if (!timeout) + break; + + // Activate data line of the thing + scsi_bus->data_w(scsi_refid, m_sdid); + + set_scsi_state(ARBITRATE_SELECT_DEST); + delay(attotime::from_nsec(2)); + + break; + } + + case ARBITRATE_SELECT_DEST: + { + if (!timeout) + break; + + scsi_bus->ctrl_w(scsi_refid, m_scntl[0] & SCNTL0_WATN ? S_ATN : 0, S_ATN | S_BSY); + + set_scsi_state(ARBITRATE_RELEASE_BSY); + delay(attotime::from_nsec(20)); + + break; + } + + case ARBITRATE_RELEASE_BSY: + { + if (!timeout) + break; + + set_scsi_state(ARBITRATE_DESKEW_WAIT); + delay(attotime::from_nsec(500)); + + break; + } + + case ARBITRATE_DESKEW_WAIT: + { + if (!timeout) + break; + + // Clear everything + scsi_bus->data_w(scsi_refid, 0); + scsi_bus->ctrl_w(scsi_refid, 0, S_SEL); + + // Done? + m_sstat[0] |= SSTAT0_CMP; + m_scntl[0] &= ~SCNTL0_START; + //update_irqs(); + set_scsi_state(FINISHED); + m_connected = true; + + step(true); + break; + } + + + // Note this is actually block transfers + case INIT_XFER: + { + if (ctrl & S_INP) + { + set_scsi_state(m_dbc ? INIT_XFER_RECV_BYTE_ACK : INIT_XFER_RECV_BYTE_NACK); + recv_byte(); + } + else + { + if (m_dbc == 1) + scsi_bus->ctrl_w(scsi_refid, 0, S_ATN); + + set_scsi_state(INIT_XFER_SEND_BYTE); + send_byte(); + } + + break; + } + + case INIT_XFER_SEND_BYTE: + { + if (m_dbc == 0) + { + set_scsi_state(FINISHED); + step(true); + } + else + { + set_scsi_state(INIT_XFER_WAIT_REQ); + } + + break; + } + + case INIT_XFER_RECV_BYTE_ACK: + { + set_scsi_state(INIT_XFER_WAIT_REQ); + scsi_bus->ctrl_w(scsi_refid, 0, S_ACK); + + break; + } + + case INIT_XFER_RECV_BYTE_NACK: + { + set_scsi_state(FINISHED); + step(true); + + break; + } + + case INIT_XFER_WAIT_REQ: + { + if (!(ctrl & S_REQ)) + break; + + if ((ctrl & S_PHASE_MASK) != m_xfr_phase) + { + set_scsi_state(FINISHED); + step(true); + } + else + { + set_scsi_state(INIT_XFER); + step(false); + } + + break; + } + + case SEND_WAIT_SETTLE << SUB_SHIFT: + { + if (!timeout) + break; + + set_scsi_state( (m_scsi_state & STATE_MASK) | (SEND_WAIT_REQ_0 << SUB_SHIFT) ); + step(false); + + break; + } + + case SEND_WAIT_REQ_0 << SUB_SHIFT: + { + if (ctrl & S_REQ) + break; + + set_scsi_state(m_scsi_state & STATE_MASK); + scsi_bus->data_w(scsi_refid, 0); + scsi_bus->ctrl_w(scsi_refid, 0, S_ACK); + + step(false); + + break; + } + + case RECV_WAIT_REQ_1 << SUB_SHIFT: + { + if (!(ctrl & S_REQ)) + break; + + set_scsi_state( (m_scsi_state & STATE_MASK) | (RECV_WAIT_SETTLE << SUB_SHIFT) ); + delay(attotime::from_nsec(5)); + + break; + } + + case RECV_WAIT_SETTLE << SUB_SHIFT: + { + if (!timeout) + break; + + if ((m_scsi_state & STATE_MASK) != INIT_XFER_RECV_PAD) + { + m_last_data = scsi_bus->data_r(); + + UINT32 shift = (8 * (m_dnad & 3)); + UINT32 mem_mask = 0xff << shift; + m_host_write(m_dnad & ~3, data << shift, mem_mask); + + ++m_dnad; + --m_dbc; + } + + scsi_bus->ctrl_w(scsi_refid, S_ACK, S_ACK); + set_scsi_state( (m_scsi_state & STATE_MASK) | (RECV_WAIT_REQ_0 << SUB_SHIFT) ); + step(false); + + break; + } + + case RECV_WAIT_REQ_0 << SUB_SHIFT: + { + if (ctrl & S_REQ) + break; + + set_scsi_state(m_scsi_state & STATE_MASK); + step(false); + + break; + } + + default: + fatalerror("Unknown state! (%x)\n", m_scsi_state); + + } +} + + +//************************************************************************** +// SCSI SCRIPTS +//************************************************************************** + +#define UNIMPLEMENTED fatalerror("%s is unimplemented\n", __FUNCTION__) + +//------------------------------------------------- +// set_scripts_state - +//------------------------------------------------- + +void ncr53c7xx_device::set_scripts_state(scripts_state state) +{ + m_scripts_state = state; +} + + +//------------------------------------------------- +// scripts_yield - suspend execution +//------------------------------------------------- +void ncr53c7xx_device::scripts_yield() +{ + m_icount = 0; +} + + +//------------------------------------------------- +// execute_run - SCRIPTS execution loop +//------------------------------------------------- + +void ncr53c7xx_device::execute_run() +{ + // Not processing anything so bail + if (m_scripts_state < SCRIPTS_FETCH) + { + m_icount = 0; + return; + } + + do + { + switch (m_scripts_state) + { + case SCRIPTS_FETCH: + { + m_finished = false; + + // Fetch the instruction + UINT32 inst = m_host_read(m_dsp, 0xffffffff); + + m_dcmd = inst >> 24; + m_dbc = inst & 0xffffff; + + // Unless we encounter an illegal instruction... + set_scripts_state(SCRIPTS_EXECUTE); + + // Decode the relevant group + switch ((m_dcmd >> 6) & 3) + { + case 0: + scripts_decode_bm(); + break; + + case 1: + scripts_decode_io(); + break; + + case 2: + scripts_decode_tc(); + break; + + case 3: + illegal(); + } + + VERBOSE_LOG(machine(), 3, "%s", disassemble_scripts()); + break; + } + + case SCRIPTS_EXECUTE: + { + (*this.*m_scripts_op)(); + break; + } + } + + m_icount--; + } while (m_icount > 0); +} + + +//------------------------------------------------- +// scripts_decode_bm - decode block move +//------------------------------------------------- + +void ncr53c7xx_device::scripts_decode_bm(void) +{ + // Decode our instruction + if (m_scntl[0] & SCNTL0_TRG) + { + // Target mode + switch ((m_dcmd >> 3) & 3) + { + case 0: + m_scripts_op = &ncr53c7xx_device::bm_t_move; + break; + + default: + illegal(); + return; + } + } + else + { + // Initiator mode + switch ((m_dcmd >> 3) & 3) + { + case 0: + m_scripts_op = &ncr53c7xx_device::bm_i_move; + break; + + case 1: + m_scripts_op = &ncr53c7xx_device::bm_i_wmov; + break; + + default: + illegal(); + return; + } + } + + m_dnad = m_host_read(m_dsp + 4, 0xffffffff); + m_dsp += 8; +} + + +//------------------------------------------------- +// scripts_decode_io - decode IO +//------------------------------------------------- + +void ncr53c7xx_device::scripts_decode_io(void) +{ + // Set Target Mode? + if (m_dbc & (1 << 9)) + m_scntl[0] |= SCNTL0_TRG; + + // Decode our instruction + if (m_scntl[0] & SCNTL0_TRG) + { + // Initiator mode + switch ((m_dcmd >> 3) & 7) + { + case 0: + m_scripts_op = &ncr53c7xx_device::io_t_reselect; + break; + + case 1: + m_scripts_op = &ncr53c7xx_device::io_t_disconnect; + break; + + case 2: + m_scripts_op = &ncr53c7xx_device::io_t_waitselect; + break; + + case 3: + m_scripts_op = &ncr53c7xx_device::io_t_set; + break; + + case 4: + m_scripts_op = &ncr53c7xx_device::io_t_clear; + break; + + default: + illegal(); + return; + } + } + else + { + // Initiator mode + switch ((m_dcmd >> 3) & 7) + { + case 0: + m_scripts_op = &ncr53c7xx_device::io_i_select; + break; + + case 1: + m_scripts_op = &ncr53c7xx_device::io_i_waitdisconnect; + break; + + case 2: + m_scripts_op = &ncr53c7xx_device::io_i_waitreselect; + break; + + case 3: + m_scripts_op = &ncr53c7xx_device::io_i_set; + break; + + case 4: + m_scripts_op = &ncr53c7xx_device::io_i_clear; + break; + + default: + illegal(); + return; + } + } + + // Set some additional registers + m_dnad = m_dsps = m_host_read(m_dsp + 4, 0xffffffff); + m_dsp += 8; +} + + +//------------------------------------------------- +// scripts_decode_tc - decode transfer control +//------------------------------------------------- + +void ncr53c7xx_device::scripts_decode_tc(void) +{ + // Decode our instruction + switch ((m_dcmd >> 3) & 7) + { + case 0: + m_scripts_op = &ncr53c7xx_device::tc_jump; + break; + + case 1: + m_scripts_op = &ncr53c7xx_device::tc_call; + break; + + case 2: + m_scripts_op = &ncr53c7xx_device::tc_return; + break; + + case 3: + m_scripts_op = &ncr53c7xx_device::tc_int; + break; + + default: + illegal(); + break; + } + + m_dnad = m_dsps = m_host_read(m_dsp + 4, 0xffffffff); + m_dsp += 8; +} + +//************************************************************************** +// SCSI SCRIPTS INSTRUCTIONS +//************************************************************************** + +//------------------------------------------------- +// illegal - illegal instruction +//------------------------------------------------- + +void ncr53c7xx_device::illegal() +{ + m_dstat |= DSTAT_OPC; + update_irqs(); + set_scripts_state(SCRIPTS_IDLE); + +} + + +//------------------------------------------------- +// bm_t_move - block move (target) +//------------------------------------------------- + +void ncr53c7xx_device::bm_t_move() +{ + UNIMPLEMENTED; +} + + +//------------------------------------------------- +// bm_i_move - block move (initiator) +//------------------------------------------------- + +void ncr53c7xx_device::bm_i_move() +{ + UNIMPLEMENTED; +} + + +//------------------------------------------------- +// bm_i_wmov - wait block move (initiator) +//------------------------------------------------- + +void ncr53c7xx_device::bm_i_wmov() +{ + if (!m_finished) + { + if (m_scsi_state == IDLE) + { + if (m_dbc == 0) + { + VERBOSE_LOG(machine(), 0, "DBC should not be 0\n"); + illegal(); + } + + // Indirect addressing + if (m_dcmd & (1 << 5)) + m_dnad = m_host_read(m_dnad, 0xffffffff); + + // Compare the phase bits + if ((scsi_bus->ctrl_r() & 7) == (m_dcmd & 7)) + { + // Transfer bytes + set_scsi_state(INIT_XFER); + m_xfr_phase = m_dcmd & 7; + step(false); + } + else + { + fatalerror("Phase mismatch\n"); + } + } + else + { + scripts_yield(); + } + } + else + { + // TODO: We should see what happened here; different behaviour + // depending on whether or not we won arbitration + set_scripts_state(SCRIPTS_FETCH); + } +} + + +//------------------------------------------------- +// io_t_reselect - +//------------------------------------------------- + +void ncr53c7xx_device::io_t_reselect() +{ + UNIMPLEMENTED; +} + + +//------------------------------------------------- +// io_t_disconnect - +//------------------------------------------------- + +void ncr53c7xx_device::io_t_disconnect() +{ + UNIMPLEMENTED; +} + + +//------------------------------------------------- +// io_t_waitselect - +//------------------------------------------------- + +void ncr53c7xx_device::io_t_waitselect() +{ + UNIMPLEMENTED; +} + + +//------------------------------------------------- +// io_t_set - +//------------------------------------------------- + +void ncr53c7xx_device::io_t_set() +{ + UNIMPLEMENTED; +} + + +//------------------------------------------------- +// io_t_clear - +//------------------------------------------------- + +void ncr53c7xx_device::io_t_clear() +{ + UNIMPLEMENTED; +} + + +//------------------------------------------------- +// io_i_select - +//------------------------------------------------- + +void ncr53c7xx_device::io_i_select() +{ + if (!m_finished) + { + if (m_scsi_state == IDLE) + { + m_sdid = m_dbc >> 16; + m_scntl[0] |= (3 << SCNTL0_ARB_SHIFT) | SCNTL0_START; + + // Set select with ATN bit + if (m_dcmd & 1) + m_scntl[0] |= SCNTL0_WATN; + + // Start the arbitration + set_scsi_state(ARBITRATE_WAIT_FREE); + step(true); + } + + scripts_yield(); + } + else + { + // TODO: We should see what happened here; different behaviour + // depending on whether or not we won arbitration + set_scripts_state(SCRIPTS_FETCH); + } +} + + +//------------------------------------------------- +// io_i_waitdisconnect - +//------------------------------------------------- + +void ncr53c7xx_device::io_i_waitdisconnect() +{ + if (scsi_bus->ctrl_r() & (S_BSY | S_SEL)) + scripts_yield(); + else + set_scripts_state(SCRIPTS_FETCH); +} + + +//------------------------------------------------- +// io_i_waitreselect - +//------------------------------------------------- + +void ncr53c7xx_device::io_i_waitreselect() +{ + UNIMPLEMENTED; +} + + +//------------------------------------------------- +// io_i_set - +//------------------------------------------------- + +void ncr53c7xx_device::io_i_set() +{ + UINT32 mask = 0; + + if (m_dbc & (1 << 3)) + mask |= S_ATN; + + if (m_dbc & (1 << 6)) + mask |= S_ACK; + + scsi_bus->ctrl_w(scsi_refid, mask, mask); + + set_scripts_state(SCRIPTS_FETCH); +} + + +//------------------------------------------------- +// io_i_clear - +//------------------------------------------------- + +void ncr53c7xx_device::io_i_clear() +{ + UINT32 mask = 0; + + if (m_dbc & (1 << 3)) + mask |= S_ATN; + + if (m_dbc & (1 << 6)) + mask |= S_ACK; + + scsi_bus->ctrl_w(scsi_refid, 0, mask); + + set_scripts_state(SCRIPTS_FETCH); +} + + +//------------------------------------------------- +// tc_jump - +//------------------------------------------------- + +void ncr53c7xx_device::tc_jump() +{ +// if (m_dbc & (1 << 16)) +// printf("Must wait for valid phase?\n"); + + bool jump = true; + + if (m_dbc & (1 << 17)) + { + // Phase + jump &= (m_dcmd & 7) == (scsi_bus->ctrl_r() & 7); + } + if (m_dbc & (1 << 18)) + { + // Data + jump &= (m_dbc & 0xff) == m_last_data; + } + + if (!(m_dbc & (1 << 19))) + jump = !jump; + + if (jump) + { + m_dsp = m_dsps; + } + set_scripts_state(SCRIPTS_FETCH); +} + + +//------------------------------------------------- +// tc_call - +//------------------------------------------------- + +void ncr53c7xx_device::tc_call() +{ + bool jump = true; + + if (m_dbc & (1 << 17)) + { + // Phase + jump &= (m_dcmd & 7) == (scsi_bus->ctrl_r() & 7); + } + if (m_dbc & (1 << 18)) + { + // Data + jump &= (m_dbc & 0xff) == m_last_data; + } + + if (!(m_dbc & (1 << 19))) + jump = !jump; + + if (jump) + { + m_temp = m_dsp; + m_dsp = m_dsps; + } + set_scripts_state(SCRIPTS_FETCH); +} + + +//------------------------------------------------- +// tc_return - +//------------------------------------------------- + +void ncr53c7xx_device::tc_return() +{ + bool jump = true; + + if (m_dbc & (1 << 17)) + { + // Phase + jump &= (m_dcmd & 7) == (scsi_bus->ctrl_r() & 7); + } + if (m_dbc & (1 << 18)) + { + // Data + jump &= (m_dbc & 0xff) == m_last_data; + } + + if (!(m_dbc & (1 << 19))) + jump = !jump; + + if (jump) + { + m_dsp = m_temp; + } + set_scripts_state(SCRIPTS_FETCH); +} + + +//------------------------------------------------- +// tc_int - +//------------------------------------------------- + +void ncr53c7xx_device::tc_int() +{ + bool jump = true; + + if (m_dbc & (1 << 17)) + { + // Phase + jump &= (m_dcmd & 7) == (scsi_bus->ctrl_r() & 7); + } + if (m_dbc & (1 << 18)) + { + // Data + jump &= (m_dbc & 0xff) == m_last_data; + } + + if (!(m_dbc & (1 << 19))) + jump = !jump; + + if (jump) + { + m_dstat |= DSTAT_SIR; + update_irqs(); + set_scripts_state(SCRIPTS_IDLE); + } + else + { + set_scripts_state(SCRIPTS_FETCH); + } +} + + +//************************************************************************** +// SCSI SCRIPTS DISASSEMBLY +//************************************************************************** + +//------------------------------------------------- +// disassemble_scripts - +//------------------------------------------------- + +const char* ncr53c7xx_device::disassemble_scripts() +{ + static const char* phases[] = + { + "Data Out", + "Data In", + "Command", + "Status", + "Reserved", + "Reserved", + "Message Out", + "Message In" + }; + + static char buffer[64]; + char opstring[64]; + + switch ((m_dcmd >> 6) & 3) + { + case 0: + { + sprintf(opstring, "BMOV: %s [%x] %d bytes\n", phases[m_dcmd & 7], m_dnad, m_dbc); + break; + } + case 1: + { + static const char* ops[] = + { + "SELECT", + "DISCONNECT", + "RESELECT", + "SET", + "CLEAR", + "ILLEGAL", + "ILLEGAL", + "ILLEGAL", + }; + + sprintf(opstring, "IO: %s (%x)\n", ops[(m_dcmd >> 3) & 7], m_dnad); + break; + } + case 2: + { + static const char* ops[] = + { + "JUMP", + "CALL", + "RETURN", + "INT", + "ILLEGAL", + "ILLEGAL", + "ILLEGAL", + "ILLEGAL", + }; + + sprintf(opstring, "TC: %s %c (%s) (%x)\n", ops[(m_dcmd >> 3) & 7], m_dbc & (1 << 19) ? 'T' : 'F', phases[m_dcmd & 7], m_dnad); + break; + } + case 3: + { + sprintf(opstring, "ILLEGAL"); + break; + } + } + + sprintf(buffer, "SCRIPTS [%08x]: %s", m_dsp - 8, opstring); + + return buffer; +} diff --git a/src/devices/machine/53c7xx.h b/src/devices/machine/53c7xx.h new file mode 100644 index 00000000000..937bd9d16a0 --- /dev/null +++ b/src/devices/machine/53c7xx.h @@ -0,0 +1,229 @@ +// license:BSD-3-Clause +// copyright-holders:Philip Bennett +/********************************************************************* + + 53c7xx.h + + NCR 53C700 SCSI I/O Processor + +*********************************************************************/ + +#ifndef _NCR53C7XX_H_ +#define _NCR53C7XX_H_ + +#include "machine/nscsi_bus.h" + + +//************************************************************************** +// REGISTER DEFINES (INCOMPLETE) +//************************************************************************** + +#define SCNTL0_TRG 0x01 +#define SCNTL0_AAP 0x02 +#define SCNTL0_EPG 0x04 +#define SCNTL0_EPC 0x08 +#define SCNTL0_WATN 0x10 +#define SCNTL0_START 0x20 +#define SCNTL0_ARB_MASK 3 +#define SCNTL0_ARB_SHIFT 6 + +#define SSTAT0_PAR 0x01 +#define SSTAT0_RST 0x02 +#define SSTAT0_UDC 0x04 +#define SSTAT0_SGE 0x08 +#define SSTAT0_SEL 0x10 +#define SSTAT0_STO 0x20 +#define SSTAT0_CMP 0x40 +#define SSTAT0_MA 0x80 + +#define SSTAT1_SDP 0x01 +#define SSTAT1_RST 0x02 +#define SSTAT1_WOA 0x04 +#define SSTAT1_LOA 0x08 +#define SSTAT1_AIP 0x10 +#define SSTAT1_ORF 0x20 +#define SSTAT1_OLF 0x40 +#define SSTAT1_ILF 0x80 + +#define ISTAT_DIP 0x01 +#define ISTAT_SIP 0x02 +#define ISTAT_PRE 0x04 +#define ISTAT_CON 0x08 +#define ISTAT_ABRT 0x80 + +#define DSTAT_OPC 0x01 +#define DSTAT_WTD 0x02 +#define DSTAT_SIR 0x04 +#define DSTAT_SSI 0x08 +#define DSTAT_ABRT 0x10 +#define DSTAT_DFE 0x80 + +#define MCFG_NCR53C7XX_IRQ_HANDLER(_devcb) \ + devcb = &ncr53c7xx_device::set_irq_handler(*device, DEVCB_##_devcb); + +#define MCFG_NCR53C7XX_HOST_WRITE(_devcb) \ + devcb = &ncr53c7xx_device::set_host_write(*device, DEVCB_##_devcb); + +#define MCFG_NCR53C7XX_HOST_READ(_devcb) \ + devcb = &ncr53c7xx_device::set_host_read(*device, DEVCB_##_devcb); + +class ncr53c7xx_device : public nscsi_device, + public device_execute_interface +{ +public: + // construction/destruction + ncr53c7xx_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // static configuration helpers + template static devcb_base &set_irq_handler(device_t &device, _Object object) { return downcast(device).m_irq_handler.set_callback(object); } + template static devcb_base &set_host_write(device_t &device, _Object object) { return downcast(device).m_host_write.set_callback(object); } + template static devcb_base &set_host_read(device_t &device, _Object object) { return downcast(device).m_host_read.set_callback(object); } + + // our API + DECLARE_READ32_MEMBER(read); + DECLARE_WRITE32_MEMBER(write); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + virtual void execute_run(); + + int m_icount; + +private: + + enum + { + STATE_MASK = 0x00ff, + SUB_SHIFT = 8, + SUB_MASK = 0xff00 + }; + + enum + { + MODE_I, + MODE_T, + MODE_D + }; + + enum scsi_state + { + IDLE, + FINISHED, + ARBITRATE_WAIT_FREE, + ARBITRATE_CHECK_FREE, + ARBITRATE_EXAMINE_BUS, + ARBITRATE_SELECT_DEST, + ARBITRATE_ASSERT_SEL, + ARBITRATE_RELEASE_BSY, + ARBITRATE_DESKEW_WAIT, + SELECT, + SELECT_COMPLETE, + INIT_XFER, + INIT_XFER_WAIT_REQ, + INIT_XFER_SEND_BYTE, + INIT_XFER_RECV_PAD, + INIT_XFER_RECV_BYTE_ACK, + INIT_XFER_RECV_BYTE_NACK, + SEND_WAIT_REQ_0, + SEND_WAIT_SETTLE, + RECV_WAIT_SETTLE, + RECV_WAIT_REQ_0, + RECV_WAIT_REQ_1 + }; + + void update_irqs(); + void set_scsi_state(int state); + void delay(const attotime &delay); + void scsi_ctrl_changed(); + void send_byte(); + void recv_byte(); + void step(bool timeout); + + + enum scripts_state + { + SCRIPTS_IDLE, + SCRIPTS_WAIT_MANUAL_START, + SCRIPTS_FETCH, + SCRIPTS_EXECUTE + }; + + void set_scripts_state(scripts_state state); + void scripts_yield(); + void scripts_decode_bm(void); + void scripts_decode_io(void); + void scripts_decode_tc(void); + void bm_t_move(); + void bm_i_move(); + void bm_i_wmov(); + void io_t_reselect(); + void io_t_disconnect(); + void io_t_waitselect(); + void io_t_set(); + void io_t_clear(); + void io_i_select(); + void io_i_waitdisconnect(); + void io_i_waitreselect(); + void io_i_set(); + void io_i_clear(); + void tc_jump(); + void tc_call(); + void tc_return(); + void tc_int(); + void illegal(); + const char* disassemble_scripts(); + + + // SCSI registers + UINT8 m_scntl[2]; + UINT8 m_sdid; + UINT8 m_sien; + UINT8 m_scid; + UINT8 m_sxfer; + UINT8 m_sodl; + UINT8 m_socl; + UINT8 m_sfbr; + UINT8 m_sidl; + UINT8 m_sbdl; + UINT8 m_sbcl; + UINT8 m_dstat; + UINT8 m_sstat[3]; + UINT8 m_ctest[8]; + UINT32 m_temp; + UINT8 m_dfifo; + UINT8 m_istat; + UINT32 m_dbc; + UINT8 m_dcmd; + UINT32 m_dnad; + UINT32 m_dsp; + UINT32 m_dsps; + UINT8 m_dmode; + UINT8 m_dien; + UINT8 m_dwt; + UINT8 m_dcntl; + + + // other state + int m_scsi_state; + bool m_connected; + bool m_finished; + UINT8 m_last_data; + UINT32 m_xfr_phase; + emu_timer *m_tm; + + int m_scripts_state; + //int m_scripts_substate; + void (ncr53c7xx_device::*m_scripts_op)(); + + // callbacks + devcb_write_line m_irq_handler; + devcb_write32 m_host_write; + devcb_read32 m_host_read; +}; + +// device type definition +extern const device_type NCR53C7XX; +#endif diff --git a/src/devices/machine/53c810.c b/src/devices/machine/53c810.c new file mode 100644 index 00000000000..a2a22f0fac0 --- /dev/null +++ b/src/devices/machine/53c810.c @@ -0,0 +1,816 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/* LSI Logic LSI53C810A PCI to SCSI I/O Processor */ + +#include "emu.h" +#include "53c810.h" +#include "bus/scsi/scsihle.h" + +#define DMA_MAX_ICOUNT 512 /* Maximum number of DMA Scripts opcodes to run */ +#define DASM_OPCODES 0 + +UINT32 lsi53c810_device::FETCH() +{ + UINT32 r = m_fetch_cb(dsp); + dsp += 4; + return r; +} + +void lsi53c810_device::dmaop_invalid() +{ + fatalerror("LSI53C810: Invalid SCRIPTS DMA opcode %08X at %08X\n", dcmd, dsp); +} + +void lsi53c810_device::dmaop_move_memory() +{ + UINT32 src = FETCH(); + UINT32 dst = FETCH(); + int count; + + count = dcmd & 0xffffff; + if (!m_dma_cb.isnull()) + m_dma_cb(src, dst, count, 1); +} + +void lsi53c810_device::dmaop_interrupt() +{ + if(dcmd & 0x100000) { + fatalerror("LSI53C810: INTFLY opcode not implemented\n"); + } + dsps = FETCH(); + + istat |= 0x1; /* DMA interrupt pending */ + dstat |= 0x4; /* SIR (SCRIPTS Interrupt Instruction Received) */ + + if (!m_irq_cb.isnull()) + m_irq_cb(1); + + dma_icount = 0; + halted = 1; +} + +void lsi53c810_device::dmaop_block_move() +{ + UINT32 address; + UINT32 count; + INT32 dsps; + + address = FETCH(); + count = dcmd & 0x00ffffff; + + // normal indirect + if (dcmd & 0x20000000) + address = m_fetch_cb(address); + + // table indirect + if (dcmd & 0x10000000) + { + dsps = (INT32)address&0xffffff; + // sign extend + if (dsps & 0x00800000) + { + dsps |= 0xff000000; + } + logerror("table offset: %x, DSA = %x\n", dsps, dsa); + dsps += dsa; + + logerror("Loading from table at %x\n", dsps); + count = m_fetch_cb(dsps); + address = m_fetch_cb(dsps + 4); + } + + logerror("block move: address %x count %x phase %x\n", address, count, (dcmd>>24)&7); + + if (scntl0 & 0x01) + { + /* target mode */ + fatalerror("LSI53C810: dmaop_block_move not implemented in target mode\n"); + } + else + { + /* initiator mode */ + logerror("53c810: block_move not actually implemented\n"); + } +} + +void lsi53c810_device::dmaop_select() +{ +// UINT32 operand; + +// operand = FETCH(); + + if (scntl0 & 0x01) + { + /* target mode */ + logerror("LSI53C810: reselect ID #%d\n", (dcmd >> 16) & 0x07); + } + else + { + select((dcmd>>16)&7); + + /* initiator mode */ + logerror("53c810: SELECT: our ID %d, target ID %d\n", scid&7, (dcmd>>16)&7); + + sstat1 &= ~0x07; // clear current bus phase + if (dcmd & 0x01000000) // select with ATN + { + osd_printf_debug("53c810: want select with ATN, setting message phase\n"); + sstat1 |= 0x7; // ATN means we want message in phase + } + } +} + +void lsi53c810_device::dmaop_wait_disconnect() +{ +// UINT32 operand; + +// operand = FETCH(); + + if (scntl0 & 0x01) + { + /* target mode */ + fatalerror("LSI53C810: dmaop_wait_disconnect not implemented in target mode\n"); + } + else + { + /* initiator mode */ + fatalerror("LSI53C810: dmaop_wait_disconnect not implemented\n"); + } +} + +void lsi53c810_device::dmaop_wait_reselect() +{ + // UINT32 operand; + +// operand = FETCH(); + + if (scntl0 & 0x01) + { + /* target mode */ + fatalerror("LSI53C810: dmaop_wait_reselect not implemented in target mode\n"); + } + else + { + /* initiator mode */ + fatalerror("LSI53C810: dmaop_wait_reselect not implemented\n"); + } +} + +void lsi53c810_device::dmaop_set() +{ +// UINT32 operand; + +// operand = FETCH(); + + /* initiator mode */ + if (dcmd & 0x8) + { + // set ATN in SOCL + socl |= 0x08; + } + if (dcmd & 0x40) + { + // set ACK in SOCL + socl |= 0x40; + } + if (dcmd & 0x200) + { + // set target mode + scntl0 |= 0x01; + } + if (dcmd & 0x400) + { + // set carry in ALU + carry = 1; + } +} + +void lsi53c810_device::dmaop_clear() +{ +// UINT32 operand; + +// operand = FETCH(); + + /* initiator mode */ + if (dcmd & 0x8) + { + // clear ATN in SOCL + socl &= ~0x08; + } + if (dcmd & 0x40) + { + // clear ACK in SOCL + socl &= ~0x40; + } + if (dcmd & 0x200) + { + // clear target mode + scntl0 &= ~0x01; + } + if (dcmd & 0x400) + { + // clear carry in ALU + carry = 0; + } +} + +void lsi53c810_device::dmaop_move_from_sfbr() +{ + fatalerror("LSI53C810: dmaop_move_from_sfbr not implemented in target mode\n"); +} + +void lsi53c810_device::dmaop_move_to_sfbr() +{ + fatalerror("LSI53C810: dmaop_move_to_sfbr not implemented\n"); +} + +void lsi53c810_device::dmaop_read_modify_write() +{ + fatalerror("LSI53C810: dmaop_read_modify_write not implemented\n"); +} + +int lsi53c810_device::scripts_compute_branch() +{ + int dtest, ptest, wanted, passed; + +// |jump if true +// 878b0000 ||compare data +// 1000 0111 1000 1011 0000 0000 0000 0000 +// | |rel ||wait valid phase +// | |compare phase +// |desired phase: message in + + if (dcmd & 0x00200000) + { + fatalerror("LSI53C810: jump with carry test not implemented\n"); + } + + if (dcmd & 0x00100000) + { + fatalerror("LSI53C810: jump with interrupt on the fly not implemented\n"); + } + + // set desired result to take jump + wanted = (dcmd & 0x00080000) ? 1 : 0; + // default to passing the tests in case they're disabled + dtest = ptest = wanted; + + // phase test? + if (dcmd & 0x00020000) + { + logerror("53c810: phase test. current: %x. target: %x\n", sstat1 & 7, (dcmd>>24)&7); + + // do the phases match? + if (((dcmd>>24)&7) == (sstat1 & 7)) + { + ptest = 1; + } + else + { + ptest = 0; + } + } + + // data test? + if (dcmd & 0x00040000) + { + logerror("53c810: data test. target: %x [not yet implemented]\n", dcmd&0xff); + } + + // if all conditions go, take the jump + passed = 0; + if ((ptest == dtest) && (dtest == wanted)) + { + passed = 1; + } + + logerror("53c810: phase test %d data test %d wanted %d => pass %d\n", ptest, dtest, wanted, passed); + + return passed; +} + +UINT32 lsi53c810_device::scripts_get_jump_dest() +{ + INT32 dsps; + UINT32 dest; + + dsps = FETCH(); + + /* relative or absolute addressing? */ + if (dcmd & 0x00800000) + { + // sign-extend the 24-bit value + if (dsps & 0x00800000) + { + dsps |= 0xff000000; + } + + logerror("dsps = %x, dsp = %x\n", dsps, dsp); + dsps += dsp; + } + + dest = (UINT32)dsps; + + logerror("cur DSP %x, dest %x\n", dsp, dest); + + return dest; +} + +void lsi53c810_device::dmaop_jump() +{ + if (scripts_compute_branch()) + { + dsp = scripts_get_jump_dest(); + } + else + { + FETCH(); // skip operand to continue on + } +} + +void lsi53c810_device::dmaop_call() +{ + if (scripts_compute_branch()) + { + // save return address + temp = dsp; + + // and go + dsp = scripts_get_jump_dest(); + } + else + { + FETCH(); // skip operand to continue on + } +} + +void lsi53c810_device::dmaop_return() +{ + // is this correct? return only happens if the condition is true? + if (scripts_compute_branch()) + { + // restore return address + dsp = temp; + } + else + { + FETCH(); // skip operand to continue on + } +} + +void lsi53c810_device::dmaop_store() +{ + fatalerror("LSI53C810: dmaop_store not implemented\n"); +} + +void lsi53c810_device::dmaop_load() +{ + fatalerror("LSI53C810: dmaop_load not implemented\n"); +} + + + +void lsi53c810_device::dma_exec() +{ + dma_icount = DMA_MAX_ICOUNT; + + while(dma_icount > 0) + { + int op; + + if (DASM_OPCODES) + { + char buf[256]; + lsi53c810_dasm(buf, dsp); + logerror("0x%08X: %s\n", dsp, buf); + } + + dcmd = FETCH(); + + op = (dcmd >> 24) & 0xff; + dma_opcode[op](); + + dma_icount--; + } +} + +UINT8 lsi53c810_device::lsi53c810_reg_r( int offset ) +{ +// logerror("53c810: read reg %d:0x%x (PC=%x)\n", offset, offset, space.device().safe_pc()); + switch(offset) + { + case 0x00: /* SCNTL0 */ + return scntl0; + case 0x01: /* SCNTL1 */ + return scntl1; + case 0x02: /* SCNTL2 */ + return scntl2; + case 0x03: /* SCNTL3 */ + return scntl3; + case 0x04: /* SCID */ + return scid; + case 0x05: /* SXFER */ + return sxfer; + case 0x09: /* SOCL */ + return socl; + case 0x0c: /* DSTAT */ + istat &= ~1; + return dstat; + case 0x0d: /* SSTAT0 */ + return sstat0; + case 0x0e: /* SSTAT1 */ + return sstat1; + case 0x0f: /* SSTAT2 */ + return sstat2; + case 0x10: /* DSA [7-0] */ + return dsa & 0xff; + case 0x11: /* DSA [15-8] */ + return (dsa >> 8) & 0xff; + case 0x12: /* DSA [23-16] */ + return (dsa >> 16) & 0xff; + case 0x13: /* DSA [31-24] */ + return (dsa >> 24) & 0xff; + case 0x14: /* ISTAT */ + // clear the interrupt on service + if (!m_irq_cb.isnull()) + m_irq_cb(0); + + return istat; + case 0x2c: /* DSP [7-0] */ + return dsp & 0xff; + case 0x2d: /* DSP [15-8] */ + return (dsp >> 8) & 0xff; + case 0x2e: /* DSP [23-16] */ + return (dsp >> 16) & 0xff; + case 0x2f: /* DSP [31-24] */ + return (dsp >> 24) & 0xff; + case 0x34: /* SCRATCH A */ + case 0x35: + case 0x36: + case 0x37: + return scratch_a[offset % 4]; + case 0x39: /* DIEN */ + return dien; + case 0x3b: /* DCNTL */ + return dcntl; + case 0x40: /* SIEN0 */ + return sien0; + case 0x41: /* SIEN1 */ + return sien1; + case 0x48: /* STIME0 */ + return stime0; + case 0x4a: /* RESPID */ + return respid; + case 0x4d: /* STEST1 */ + return stest1; + case 0x5c: /* SCRATCH B */ + case 0x5d: + case 0x5e: + case 0x5f: + return scratch_b[offset % 4]; + + default: + fatalerror("LSI53C810: reg_r: Unknown reg %02X\n", offset); + } + + // never executed + //return 0; +} + +void lsi53c810_device::lsi53c810_reg_w(int offset, UINT8 data) +{ +// logerror("53c810: %02x to reg %d:0x%x (PC=%x)\n", data, offset, offset, space.device().safe_pc()); + switch(offset) + { + case 0x00: /* SCNTL0 */ + scntl0 = data; + break; + case 0x01: /* SCNTL1 */ + scntl1 = data; + break; + case 0x02: /* SCNTL2 */ + scntl2 = data; + break; + case 0x03: /* SCNTL3 */ + scntl3 = data; + break; + case 0x04: /* SCID */ + scid = data; + break; + case 0x05: /* SXFER */ + sxfer = data; + break; + case 0x09: /* SOCL */ + socl = data; + break; + case 0x0d: /* SSTAT0 */ + sstat0 = data; + break; + case 0x0e: /* SSTAT1 */ + sstat1 = data; + break; + case 0x0f: /* SSTAT2 */ + sstat2 = data; + break; + case 0x10: /* DSA [7-0] */ + dsa &= 0xffffff00; + dsa |= data; + break; + case 0x11: /* DSA [15-8] */ + dsa &= 0xffff00ff; + dsa |= data << 8; + break; + case 0x12: /* DSA [23-16] */ + dsa &= 0xff00ffff; + dsa |= data << 16; + break; + case 0x13: /* DSA [31-24] */ + dsa &= 0x00ffffff; + dsa |= data << 24; + break; + case 0x14: /* ISTAT */ + istat = data; + break; + case 0x2c: /* DSP [7-0] */ + dsp &= 0xffffff00; + dsp |= data; + break; + case 0x2d: /* DSP [15-8] */ + dsp &= 0xffff00ff; + dsp |= data << 8; + break; + case 0x2e: /* DSP [23-16] */ + dsp &= 0xff00ffff; + dsp |= data << 16; + break; + case 0x2f: /* DSP [31-24] */ + dsp &= 0x00ffffff; + dsp |= data << 24; + halted = 0; + if((dmode & 0x1) == 0 && !halted) { + dma_exec(); + } + break; + case 0x34: /* SCRATCH A */ + case 0x35: + case 0x36: + case 0x37: + scratch_a[offset % 4] = data; + break; + case 0x38: /* DMODE */ + dmode = data; + break; + case 0x39: /* DIEN */ + dien = data; + break; + case 0x3b: /* DCNTL */ + dcntl = data; + + if(dcntl & 0x14 && !halted) /* single-step & start DMA */ + { + int op; + dcmd = FETCH(); + op = (dcmd >> 24) & 0xff; + dma_opcode[op](); + + istat |= 0x3; /* DMA interrupt pending */ + dstat |= 0x8; /* SSI (Single Step Interrupt) */ + if (!m_irq_cb.isnull()) + m_irq_cb(1); + } + else if(dcntl & 0x04 && !halted) /* manual start DMA */ + { + dma_exec(); + } + break; + case 0x40: /* SIEN0 */ + sien0 = data; + break; + case 0x41: /* SIEN1 */ + sien1 = data; + break; + case 0x48: /* STIME0 */ + stime0 = data; + break; + case 0x4a: /* RESPID */ + respid = data; + break; + case 0x4d: /* STEST1 */ + stest1 = data; + break; + case 0x5c: /* SCRATCH B */ + case 0x5d: + case 0x5e: + case 0x5f: + scratch_b[offset % 4] = data; + break; + + default: + fatalerror("LSI53C810: reg_w: Unknown reg %02X, %02X\n", offset, data); + } +} + +void lsi53c810_device::add_opcode(UINT8 op, UINT8 mask, opcode_handler_delegate handler) +{ + for (int i = 0; i < 256; i++) + { + if ((i & mask) == op) + { + dma_opcode[i] = handler; + } + } +} + +lsi53c810_device::lsi53c810_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : legacy_scsi_host_adapter(mconfig, LSI53C810, "53C810 SCSI", tag, owner, clock, "lsi53c810", __FILE__) +{ +} + +void lsi53c810_device::device_start() +{ + legacy_scsi_host_adapter::device_start(); + + m_irq_cb.bind_relative_to(*owner()); + m_dma_cb.bind_relative_to(*owner()); + m_fetch_cb.bind_relative_to(*owner()); + + for (int i = 0; i < 256; i++) + { + dma_opcode[i] = opcode_handler_delegate(FUNC(lsi53c810_device::dmaop_invalid), this); + } + + add_opcode(0x00, 0xc0, opcode_handler_delegate(FUNC( lsi53c810_device::dmaop_block_move ), this)); + add_opcode(0x40, 0xf8, opcode_handler_delegate(FUNC( lsi53c810_device::dmaop_select ), this)); + add_opcode(0x48, 0xf8, opcode_handler_delegate(FUNC( lsi53c810_device::dmaop_wait_disconnect ), this)); + add_opcode(0x50, 0xf8, opcode_handler_delegate(FUNC( lsi53c810_device::dmaop_wait_reselect ), this)); + add_opcode(0x58, 0xf8, opcode_handler_delegate(FUNC( lsi53c810_device::dmaop_set ), this)); + add_opcode(0x60, 0xf8, opcode_handler_delegate(FUNC( lsi53c810_device::dmaop_clear ), this)); + add_opcode(0x68, 0xf8, opcode_handler_delegate(FUNC( lsi53c810_device::dmaop_move_from_sfbr ), this)); + add_opcode(0x70, 0xf8, opcode_handler_delegate(FUNC( lsi53c810_device::dmaop_move_to_sfbr ), this)); + add_opcode(0x78, 0xf8, opcode_handler_delegate(FUNC( lsi53c810_device::dmaop_read_modify_write ), this)); + add_opcode(0x80, 0xf8, opcode_handler_delegate(FUNC( lsi53c810_device::dmaop_jump ), this)); + add_opcode(0x88, 0xf8, opcode_handler_delegate(FUNC( lsi53c810_device::dmaop_call ), this)); + add_opcode(0x90, 0xf8, opcode_handler_delegate(FUNC( lsi53c810_device::dmaop_return ), this)); + add_opcode(0x98, 0xf8, opcode_handler_delegate(FUNC( lsi53c810_device::dmaop_interrupt ), this)); + add_opcode(0xc0, 0xfe, opcode_handler_delegate(FUNC( lsi53c810_device::dmaop_move_memory ), this)); + add_opcode(0xe0, 0xed, opcode_handler_delegate(FUNC( lsi53c810_device::dmaop_store ), this)); + add_opcode(0xe1, 0xed, opcode_handler_delegate(FUNC( lsi53c810_device::dmaop_load ), this)); +} + +/************************************* + * + * Disassembler + * + *************************************/ + +UINT32 lsi53c810_device::lsi53c810_dasm_fetch(UINT32 pc) +{ + return m_fetch_cb(pc); +} + +unsigned lsi53c810_device::lsi53c810_dasm(char *buf, UINT32 pc) +{ + unsigned result = 0; + const char *op_mnemonic = NULL; + UINT32 op = lsi53c810_dasm_fetch(pc); + UINT32 dest; + int i; + + static const char *const phases[] = + { + "DATA_OUT", "DATA_IN", "CMD", "STATUS", + "RESERVED_OUT??", "RESERVED_IN??", "MSG_OUT", "MSG_IN" + }; + + if ((op & 0xF8000000) == 0x40000000) + { + /* SELECT */ + dest = lsi53c810_dasm_fetch(pc + 4); + + buf += sprintf(buf, "SELECT%s %d, 0x%08X", + (op & 0x01000000) ? " ATN" : "", + (op >> 16) & 0x07, + dest); + + result = 8; + } + else if (((op & 0xF8000000) == 0x58000000) + | ((op & 0xF8000000) == 0x60000000)) + { + static const struct + { + UINT32 flag; + const char *text; + } flags[] = + { + { 0x00000008, "ATN" }, + { 0x00000040, "ACK" }, + { 0x00000200, "TARGET" }, + { 0x00000400, "CARRY" } + }; + int need_cojunction = FALSE; + + /* SET/CLEAR */ + switch(op & 0xF8000000) + { + case 0x58000000: op_mnemonic = "SET"; break; + case 0x60000000: op_mnemonic = "CLEAR"; break; + } + + buf += sprintf(buf, "%s ", op_mnemonic); + need_cojunction = FALSE; + + for (i = 0; i < ARRAY_LENGTH(flags); i++) + { + if (op & flags[i].flag) + { + if (need_cojunction) + buf += sprintf(buf, " AND "); + else + need_cojunction = TRUE; + buf += sprintf(buf, "%s", flags[i].text); + } + } + } + else if (((op & 0xF8000000) == 0x80000000) + | ((op & 0xF8000000) == 0x88000000) + | ((op & 0xF8000000) == 0x98000000)) + { + /* JUMP/CALL/INT */ + switch(op & 0xF8000000) + { + case 0x80000000: op_mnemonic = "JUMP"; break; + case 0x88000000: op_mnemonic = "CALL"; break; + case 0x98000000: op_mnemonic = "INT"; break; + } + + dest = lsi53c810_dasm_fetch(pc + 4); + + if (op & 0x00800000) + { + /* relative */ + if (dest & 0x00800000) + dest |= 0xFF000000; + else + dest &= 0x00FFFFFF; + dest = (pc + 8) + dest; + buf += sprintf(buf, "%s REL(0x%08X)", op_mnemonic, dest); + } + else + { + /* absolute */ + buf += sprintf(buf, "%s 0x%08X", op_mnemonic, dest); + } + + switch(op & 0x000B0000) + { + case 0x00000000: + buf += sprintf(buf, ", NOT??"); + break; + + case 0x00080000: + break; + + case 0x00020000: + case 0x00030000: + case 0x000A0000: + case 0x000B0000: + buf += sprintf(buf, ", %s%s %s", + (op & 0x00010000) ? "WHEN" : "IF", + (op & 0x00080000) ? "" : " NOT", + phases[(op >> 24) & 0x07]); + break; + + default: + fatalerror("unknown op 0x%08X\n", op); + } + result = 8; + } + else if ((op & 0xE0000000) == 0x00000000) + { + /* MOVE FROM */ + dest = lsi53c810_dasm_fetch(pc + 4); + + buf += sprintf(buf, "MOVE FROM 0x%08X, WHEN %s", + dest, phases[(op >> 24) & 0x07]); + + result = 8; + } + else if ((op & 0xE0000000) == 0x20000000) + { + /* MOVE PTR */ + dest = lsi53c810_dasm_fetch(pc + 4); + + buf += sprintf(buf, "MOVE 0x%08X, PTR 0x%08X, WHEN %s", + (op & 0x00FFFFFF), dest, phases[(op >> 24) & 0x07]); + + result = 8; + } + else + { + fatalerror("unknown op 0x%08X\n", op); + } + return result; +} + +const device_type LSI53C810 = &device_creator; diff --git a/src/devices/machine/53c810.h b/src/devices/machine/53c810.h new file mode 100644 index 00000000000..f55c3cdbfb1 --- /dev/null +++ b/src/devices/machine/53c810.h @@ -0,0 +1,119 @@ +// license:BSD-3-Clause +// copyright-holders:smf +#ifndef LSI53C810_H +#define LSI53C810_H + +#include "legscsi.h" + +typedef device_delegate lsi53c810_irq_delegate; +#define LSI53C810_IRQ_CB(name) void name(int state) + +typedef device_delegate lsi53c810_dma_delegate; +#define LSI53C810_DMA_CB(name) void name(UINT32 src, UINT32 dst, int length, int byteswap) + +typedef device_delegate lsi53c810_fetch_delegate; +#define LSI53C810_FETCH_CB(name) UINT32 name(UINT32 dsp) + + +class lsi53c810_device : public legacy_scsi_host_adapter +{ +public: + // construction/destruction + lsi53c810_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + static void set_irq_callback(device_t &device, lsi53c810_irq_delegate callback) { downcast(device).m_irq_cb = callback; } + static void set_dma_callback(device_t &device, lsi53c810_dma_delegate callback) { downcast(device).m_dma_cb = callback; } + static void set_fetch_callback(device_t &device, lsi53c810_fetch_delegate callback) { downcast(device).m_fetch_cb = callback; } + + void lsi53c810_read_data(int bytes, UINT8 *pData); + void lsi53c810_write_data(int bytes, UINT8 *pData); + + UINT8 lsi53c810_reg_r( int offset ); + void lsi53c810_reg_w(int offset, UINT8 data); + +protected: + // device-level overrides + virtual void device_start(); + +private: + typedef delegate opcode_handler_delegate; + opcode_handler_delegate dma_opcode[256]; + + lsi53c810_irq_delegate m_irq_cb; + lsi53c810_dma_delegate m_dma_cb; + lsi53c810_fetch_delegate m_fetch_cb; + + UINT32 FETCH(); + void dmaop_invalid(); + void dmaop_move_memory(); + void dmaop_interrupt(); + void dmaop_block_move(); + void dmaop_select(); + void dmaop_wait_disconnect(); + void dmaop_wait_reselect(); + void dmaop_set(); + void dmaop_clear(); + void dmaop_move_from_sfbr(); + void dmaop_move_to_sfbr(); + void dmaop_read_modify_write(); + int scripts_compute_branch(); + UINT32 scripts_get_jump_dest(); + void dmaop_jump(); + void dmaop_call(); + void dmaop_return(); + void dmaop_store(); + void dmaop_load(); + void dma_exec(); + void add_opcode(UINT8 op, UINT8 mask, opcode_handler_delegate handler); + void lsi53c810_init(); + UINT32 lsi53c810_dasm_fetch(UINT32 pc); + unsigned lsi53c810_dasm(char *buf, UINT32 pc); + + UINT8 last_id; + + UINT8 scntl0; + UINT8 scntl1; + UINT8 scntl2; + UINT8 scntl3; + UINT8 scid; + UINT8 sxfer; + UINT8 socl; + UINT8 istat; + UINT8 dstat; + UINT8 sstat0; + UINT8 sstat1; + UINT8 sstat2; + UINT8 dien; + UINT8 dcntl; + UINT8 dmode; + UINT32 temp; + UINT32 dsa; + UINT32 dsp; + UINT32 dsps; + UINT32 dcmd; + UINT8 sien0; + UINT8 sien1; + UINT8 stime0; + UINT8 respid; + UINT8 stest1; + UINT8 scratch_a[4]; + UINT8 scratch_b[4]; + int dma_icount; + int halted; + int carry; +}; + +// device type definition +extern const device_type LSI53C810; + + +#define MCFG_LSI53C810_IRQ_CB(_class, _method) \ + lsi53c810_device::set_irq_callback(*device, lsi53c810_irq_delegate(&_class::_method, #_class "::" #_method, downcast<_class *>(owner))); + +#define MCFG_LSI53C810_DMA_CB(_class, _method) \ + lsi53c810_device::set_dma_callback(*device, lsi53c810_dma_delegate(&_class::_method, #_class "::" #_method, downcast<_class *>(owner))); + +#define MCFG_LSI53C810_FETCH_CB(_class, _method) \ + lsi53c810_device::set_fetch_callback(*device, lsi53c810_fetch_delegate(&_class::_method, #_class "::" #_method, downcast<_class *>(owner))); + +#endif diff --git a/src/devices/machine/64h156.c b/src/devices/machine/64h156.c new file mode 100644 index 00000000000..508034169dd --- /dev/null +++ b/src/devices/machine/64h156.c @@ -0,0 +1,652 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Commodore 64H156 Gate Array emulation + +**********************************************************************/ + +/* + + TODO: + + http://personalpages.tds.net/~rcarlsen/cbm/1541/1541%20EARLY/1540-2.GIF + + - write protect + - separate read/write methods + - cycle exact VIA + - get these running and we're golden + - Bounty Bob Strikes Back (aligned halftracks) + - Quiwi (speed change within track) + - Defender of the Crown (V-MAX! v2, density checks) + - Test Drive / Cabal (HLS, sub-cycle jitter) + - Galaxian (?, needs 100% accurate VIA) + +*/ + +#include "64h156.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define LOG 0 + +#define CYCLES_UNTIL_ANALOG_DESYNC 288 // 18 us + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type C64H156 = &device_creator; + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// c64h156_device - constructor +//------------------------------------------------- + +c64h156_device::c64h156_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, C64H156, "64H156", tag, owner, clock, "c64h156", __FILE__), + m_write_atn(*this), + m_write_sync(*this), + m_write_byte(*this), + m_floppy(NULL), + m_mtr(1), + m_accl(0), + m_stp(0), + m_ds(0), + m_soe(0), + m_oe(1), + m_ted(0), + m_yb(0), + m_atni(0), + m_atna(0), + m_period(attotime::from_hz(clock)) +{ + memset(&cur_live, 0x00, sizeof(cur_live)); + cur_live.tm = attotime::never; + cur_live.state = IDLE; + cur_live.next_state = -1; + cur_live.write_start_time = attotime::never; +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void c64h156_device::device_start() +{ + // resolve callbacks + m_write_atn.resolve_safe(); + m_write_sync.resolve_safe(); + m_write_byte.resolve_safe(); + + // allocate timer + t_gen = timer_alloc(0); + + // register for state saving + save_item(NAME(m_mtr)); + save_item(NAME(m_accl)); + save_item(NAME(m_stp)); + save_item(NAME(m_ds)); + save_item(NAME(m_soe)); + save_item(NAME(m_oe)); + save_item(NAME(m_ted)); + save_item(NAME(m_yb)); + save_item(NAME(m_atni)); + save_item(NAME(m_atna)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void c64h156_device::device_reset() +{ + live_abort(); +} + + +//------------------------------------------------- +// device_timer - handler timer events +//------------------------------------------------- + +void c64h156_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + live_sync(); + live_run(); +} + +void c64h156_device::live_start() +{ + cur_live.tm = machine().time(); + cur_live.state = RUNNING; + cur_live.next_state = -1; + + cur_live.shift_reg = 0; + cur_live.shift_reg_write = 0; + cur_live.cycle_counter = 0; + cur_live.cell_counter = 0; + cur_live.bit_counter = 0; + cur_live.ds = m_ds; + cur_live.oe = m_oe; + cur_live.soe = m_soe; + cur_live.accl = m_accl; + cur_live.zero_counter = 0; + cur_live.cycles_until_random_flux = (rand() % 31) + 289; + + checkpoint_live = cur_live; + + live_run(); +} + +void c64h156_device::checkpoint() +{ + get_next_edge(machine().time()); + checkpoint_live = cur_live; +} + +void c64h156_device::rollback() +{ + cur_live = checkpoint_live; + get_next_edge(cur_live.tm); +} + +void c64h156_device::start_writing(const attotime &tm) +{ + cur_live.write_start_time = tm; + cur_live.write_position = 0; +} + +void c64h156_device::stop_writing(const attotime &tm) +{ + commit(tm); + cur_live.write_start_time = attotime::never; +} + +bool c64h156_device::write_next_bit(bool bit, const attotime &limit) +{ + if(cur_live.write_start_time.is_never()) { + cur_live.write_start_time = cur_live.tm; + cur_live.write_position = 0; + } + + attotime etime = cur_live.tm + m_period; + if(etime > limit) + return true; + + if(bit && cur_live.write_position < ARRAY_LENGTH(cur_live.write_buffer)) + cur_live.write_buffer[cur_live.write_position++] = cur_live.tm - m_period; + + if (LOG) logerror("%s write bit %u (%u)\n", cur_live.tm.as_string(), cur_live.bit_counter, bit); + + return false; +} + +void c64h156_device::commit(const attotime &tm) +{ + if(cur_live.write_start_time.is_never() || tm == cur_live.write_start_time || !cur_live.write_position) + return; + + if (LOG) logerror("%s committing %u transitions since %s\n", tm.as_string(), cur_live.write_position, cur_live.write_start_time.as_string()); + + m_floppy->write_flux(cur_live.write_start_time, tm, cur_live.write_position, cur_live.write_buffer); + + cur_live.write_start_time = tm; + cur_live.write_position = 0; +} + +void c64h156_device::live_delay(int state) +{ + cur_live.next_state = state; + if(cur_live.tm != machine().time()) + t_gen->adjust(cur_live.tm - machine().time()); + else + live_sync(); +} + +void c64h156_device::live_sync() +{ + if(!cur_live.tm.is_never()) { + if(cur_live.tm > machine().time()) { + rollback(); + live_run(machine().time()); + commit(cur_live.tm); + } else { + commit(cur_live.tm); + if(cur_live.next_state != -1) { + cur_live.state = cur_live.next_state; + cur_live.next_state = -1; + } + if(cur_live.state == IDLE) { + stop_writing(cur_live.tm); + cur_live.tm = attotime::never; + } + } + cur_live.next_state = -1; + checkpoint(); + } +} + +void c64h156_device::live_abort() +{ + if(!cur_live.tm.is_never() && cur_live.tm > machine().time()) { + rollback(); + live_run(machine().time()); + } + + stop_writing(cur_live.tm); + + cur_live.tm = attotime::never; + cur_live.state = IDLE; + cur_live.next_state = -1; + cur_live.write_position = 0; + cur_live.write_start_time = attotime::never; + + cur_live.sync = 1; + cur_live.byte = 1; +} + +void c64h156_device::live_run(const attotime &limit) +{ + if(cur_live.state == IDLE || cur_live.next_state != -1) + return; + + for(;;) { + switch(cur_live.state) { + case RUNNING: { + bool syncpoint = false; + + if (cur_live.tm > limit) + return; + + int bit = get_next_bit(cur_live.tm, limit); + if(bit < 0) + return; + + int cell_counter = cur_live.cell_counter; + + if (bit) { + cur_live.cycle_counter = cur_live.ds; + cur_live.cell_counter = 0; + } else { + cur_live.cycle_counter++; + } + + if (cur_live.cycle_counter == 16) { + cur_live.cycle_counter = cur_live.ds; + + cur_live.cell_counter++; + cur_live.cell_counter &= 0xf; + } + + if (!BIT(cell_counter, 1) && BIT(cur_live.cell_counter, 1)) { + // read bit + cur_live.shift_reg <<= 1; + cur_live.shift_reg |= !(BIT(cur_live.cell_counter, 3) || BIT(cur_live.cell_counter, 2)); + cur_live.shift_reg &= 0x3ff; + + if (LOG) logerror("%s read bit %u (%u) >> %03x, oe=%u soe=%u sync=%u byte=%u\n", cur_live.tm.as_string(), cur_live.bit_counter, + !(BIT(cur_live.cell_counter, 3) || BIT(cur_live.cell_counter, 2)), cur_live.shift_reg, cur_live.oe, cur_live.soe, cur_live.sync, cur_live.byte); + + syncpoint = true; + } + + if (BIT(cell_counter, 1) && !BIT(cur_live.cell_counter, 1) && !cur_live.oe) { // TODO WPS + write_next_bit(BIT(cur_live.shift_reg_write, 7), limit); + } + + int sync = !((cur_live.shift_reg == 0x3ff) && cur_live.oe); + + if (!sync) { + cur_live.bit_counter = 8; + } else if (!BIT(cell_counter, 1) && BIT(cur_live.cell_counter, 1) && cur_live.sync) { + cur_live.bit_counter++; + cur_live.bit_counter &= 0xf; + } + + int byte = !(((cur_live.bit_counter & 7) == 7) && cur_live.soe && !(cur_live.cell_counter & 2)); + int load = !(((cur_live.bit_counter & 7) == 7) && ((cur_live.cell_counter & 3) == 3)); + + if (!load) { + if (cur_live.oe) { + cur_live.shift_reg_write = cur_live.shift_reg; + if (LOG) logerror("%s load write shift register from read shift register %02x\n",cur_live.tm.as_string(),cur_live.shift_reg_write); + } else { + cur_live.shift_reg_write = cur_live.yb; + if (LOG) logerror("%s load write shift register from YB %02x\n",cur_live.tm.as_string(),cur_live.shift_reg_write); + } + } else if (!BIT(cell_counter, 1) && BIT(cur_live.cell_counter, 1)) { + cur_live.shift_reg_write <<= 1; + cur_live.shift_reg_write &= 0xff; + if (LOG) logerror("%s shift write register << %02x\n", cur_live.tm.as_string(), cur_live.shift_reg_write); + } + + // update signals + if (byte != cur_live.byte) { + if (!byte || !cur_live.accl) { + if (LOG) logerror("%s BYTE %02x\n", cur_live.tm.as_string(), cur_live.shift_reg & 0xff); + cur_live.byte = byte; + syncpoint = true; + } + if (!byte) { + cur_live.accl_yb = cur_live.shift_reg & 0xff; + } + } + + if (sync != cur_live.sync) { + if (LOG) logerror("%s SYNC %u\n", cur_live.tm.as_string(),sync); + cur_live.sync = sync; + syncpoint = true; + } + + if (syncpoint) { + commit(cur_live.tm); + + cur_live.tm += m_period; + live_delay(RUNNING_SYNCPOINT); + return; + } + + cur_live.tm += m_period; + break; + } + + case RUNNING_SYNCPOINT: { + m_write_sync(cur_live.sync); + m_write_byte(cur_live.byte); + + cur_live.state = RUNNING; + checkpoint(); + break; + } + } + } +} + +void c64h156_device::get_next_edge(const attotime &when) +{ + cur_live.edge = m_floppy->get_next_transition(when); +} + +int c64h156_device::get_next_bit(attotime &tm, const attotime &limit) +{ + int bit = 0; + if (!cur_live.edge.is_never()) + { + attotime next = tm + m_period; + if (cur_live.edge < next) + { + bit = 1; + + cur_live.zero_counter = 0; + cur_live.cycles_until_random_flux = (rand() % 31) + 289; + + get_next_edge(next); + } + } + + if (cur_live.zero_counter >= cur_live.cycles_until_random_flux) { + cur_live.zero_counter = 0; + cur_live.cycles_until_random_flux = (rand() % 367) + 33; + + bit = 1; + } + + return bit && cur_live.oe; +} + + +//------------------------------------------------- +// yb_r - +//------------------------------------------------- + +READ8_MEMBER( c64h156_device::yb_r ) +{ + if (checkpoint_live.accl) { + return checkpoint_live.accl_yb; + } else { + return checkpoint_live.shift_reg; + } +} + + +//------------------------------------------------- +// yb_w - +//------------------------------------------------- + +WRITE8_MEMBER( c64h156_device::yb_w ) +{ + if (m_yb != data) + { + live_sync(); + m_yb = cur_live.yb = data; + checkpoint(); + if (LOG) logerror("%s YB %02x\n", machine().time().as_string(), data); + live_run(); + } + +} + + +//------------------------------------------------- +// test_w - test write +//------------------------------------------------- + +WRITE_LINE_MEMBER( c64h156_device::test_w ) +{ +} + + +//------------------------------------------------- +// accl_w - +//------------------------------------------------- + +WRITE_LINE_MEMBER( c64h156_device::accl_w ) +{ + if (m_accl != state) + { + live_sync(); + m_accl = cur_live.accl = state; + checkpoint(); + if (LOG) logerror("%s ACCL %u\n", machine().time().as_string(), state); + live_run(); + } +} + + +//------------------------------------------------- +// ted_w - +//------------------------------------------------- + +WRITE_LINE_MEMBER( c64h156_device::ted_w ) +{ + if (m_ted != state) + { + live_sync(); + if (m_ted && !state && cur_live.accl && !cur_live.byte) { + cur_live.byte = 1; + m_write_byte(cur_live.byte); + } + m_ted = state; + checkpoint(); + if (LOG) logerror("%s TED %u\n", machine().time().as_string(), state); + live_run(); + } +} + + +//------------------------------------------------- +// mtr_w - motor write +//------------------------------------------------- + +WRITE_LINE_MEMBER( c64h156_device::mtr_w ) +{ + if (m_mtr != state) + { + live_sync(); + m_mtr = state; + if (LOG) logerror("%s MTR %u\n", machine().time().as_string(), state); + m_floppy->mon_w(!state); + checkpoint(); + + if (m_mtr) { + if(cur_live.state == IDLE) { + live_start(); + } + } else { + live_abort(); + } + + live_run(); + } +} + + +//------------------------------------------------- +// oe_w - output enable write +//------------------------------------------------- + +WRITE_LINE_MEMBER( c64h156_device::oe_w ) +{ + if (m_oe != state) + { + live_sync(); + m_oe = cur_live.oe = state; + if (m_oe) { + stop_writing(machine().time()); + } else { + start_writing(machine().time()); + } + checkpoint(); + if (LOG) logerror("%s OE %u\n", machine().time().as_string(), state); + live_run(); + } +} + + +//------------------------------------------------- +// soe_w - SO enable write +//------------------------------------------------- + +WRITE_LINE_MEMBER( c64h156_device::soe_w ) +{ + if (m_soe != state) + { + live_sync(); + m_soe = cur_live.soe = state; + checkpoint(); + if (LOG) logerror("%s SOE %u\n", machine().time().as_string(), state); + live_run(); + } +} + + +//------------------------------------------------- +// atni_w - serial attention input write +//------------------------------------------------- + +WRITE_LINE_MEMBER( c64h156_device::atni_w ) +{ + if (LOG) logerror("ATNI %u\n", state); + + m_atni = state; + + m_write_atn(m_atni ^ m_atna); +} + + +//------------------------------------------------- +// atna_w - serial attention acknowledge write +//------------------------------------------------- + +WRITE_LINE_MEMBER( c64h156_device::atna_w ) +{ + if (LOG) logerror("ATNA %u\n", state); + + m_atna = state; + + m_write_atn(m_atni ^ m_atna); +} + + +//------------------------------------------------- +// set_floppy - +//------------------------------------------------- + +void c64h156_device::set_floppy(floppy_image_device *floppy) +{ + m_floppy = floppy; +} + + +//------------------------------------------------- +// stp_w - +//------------------------------------------------- + +void c64h156_device::stp_w(int stp) +{ + if (m_stp != stp) + { + live_sync(); + + if (m_mtr) + { + int tracks = 0; + + switch (m_stp) + { + case 0: if (stp == 1) tracks++; else if (stp == 3) tracks--; break; + case 1: if (stp == 2) tracks++; else if (stp == 0) tracks--; break; + case 2: if (stp == 3) tracks++; else if (stp == 1) tracks--; break; + case 3: if (stp == 0) tracks++; else if (stp == 2) tracks--; break; + } + + if (tracks == -1) + { + m_floppy->dir_w(1); + m_floppy->stp_w(1); + m_floppy->stp_w(0); + } + else if (tracks == 1) + { + m_floppy->dir_w(0); + m_floppy->stp_w(1); + m_floppy->stp_w(0); + } + + m_stp = stp; + } + + checkpoint(); + live_run(); + } +} + + +//------------------------------------------------- +// ds_w - density select +//------------------------------------------------- + +void c64h156_device::ds_w(int ds) +{ + if (m_ds != ds) + { + live_sync(); + m_ds = cur_live.ds = ds; + checkpoint(); + if (LOG) logerror("%s DS %u\n", machine().time().as_string(), ds); + live_run(); + } +} diff --git a/src/devices/machine/64h156.h b/src/devices/machine/64h156.h new file mode 100644 index 00000000000..d21ce389dd0 --- /dev/null +++ b/src/devices/machine/64h156.h @@ -0,0 +1,205 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Commodore 64H156 Gate Array emulation + + Used in 1541B/1541C/1541-II/1551/1571 + +********************************************************************** + _____ _____ + TEST 1 |* \_/ | 40 _BYTE + YB0 2 | | 39 SOE + YB1 3 | | 38 B + YB2 4 | | 37 CK + YB3 5 | | 36 _QX + YB4 6 | | 35 Q + YB5 7 | | 34 R/_W + YB6 8 | | 33 LOCK + YB7 9 | | 32 PLL + Vss 10 | 64H156-01 | 31 CLR + STP1 11 | 251828-01 | 30 Vcc + STP0 12 | | 29 _XRW + MTR 13 | | 28 Y3 + _A 14 | | 27 Y2 + DS0 15 | | 26 Y1 + DS1 16 | | 25 Y0 + _SYNC 17 | | 24 ATN + TED 18 | | 23 ATNI + OE 19 | | 22 ATNA + _ACCL 20 |_____________| 21 OSC + + _____ _____ + TEST 1 |* \_/ | 42 _BYTE + YB0 2 | | 41 SOE + YB1 3 | | 40 B + YB2 4 | | 39 CK + YB3 5 | | 38 _QX + YB4 6 | | 37 Q + YB5 7 | | 36 R/_W + YB6 8 | | 35 LOCK + YB7 9 | | 34 PLL + Vss 10 | 64H156-02 | 33 CLR + STP1 11 | 251828-02 | 32 Vcc + STP0 12 | | 31 _XRW + MTR 13 | | 30 Y3 + _A 14 | | 29 Y2 + DS0 15 | | 28 Y1 + DS1 16 | | 27 Y0 + _SYNC 17 | | 26 ATN + TED 18 | | 25 ATNI + OE 19 | | 24 ATNA + _ACCL 20 | | 23 OSC + Vcc 21 |_____________| 22 Vss + +**********************************************************************/ + +#pragma once + +#ifndef __C64H156__ +#define __C64H156__ + +#include "emu.h" +#include "imagedev/floppy.h" +#include "formats/d64_dsk.h" +#include "formats/g64_dsk.h" +#include "formats/d71_dsk.h" + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_64H156_ATN_CALLBACK(_write) \ + devcb = &c64h156_device::set_atn_wr_callback(*device, DEVCB_##_write); + +#define MCFG_64H156_SYNC_CALLBACK(_write) \ + devcb = &c64h156_device::set_sync_wr_callback(*device, DEVCB_##_write); + +#define MCFG_64H156_BYTE_CALLBACK(_write) \ + devcb = &c64h156_device::set_byte_wr_callback(*device, DEVCB_##_write); + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> c64h156_device + +class c64h156_device : public device_t +{ +public: + // construction/destruction + c64h156_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + template static devcb_base &set_atn_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_atn.set_callback(object); } + template static devcb_base &set_sync_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_sync.set_callback(object); } + template static devcb_base &set_byte_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_byte.set_callback(object); } + + DECLARE_READ8_MEMBER( yb_r ); + DECLARE_WRITE8_MEMBER( yb_w ); + + DECLARE_WRITE_LINE_MEMBER( test_w ); + DECLARE_WRITE_LINE_MEMBER( accl_w ); + DECLARE_WRITE_LINE_MEMBER( ted_w ); + DECLARE_WRITE_LINE_MEMBER( mtr_w ); + DECLARE_WRITE_LINE_MEMBER( oe_w ); + DECLARE_WRITE_LINE_MEMBER( soe_w ); + DECLARE_WRITE_LINE_MEMBER( atni_w ); + DECLARE_WRITE_LINE_MEMBER( atna_w ); + + DECLARE_READ_LINE_MEMBER( sync_r ) { return checkpoint_live.sync; } + DECLARE_READ_LINE_MEMBER( byte_r ) { return checkpoint_live.byte; } + DECLARE_READ_LINE_MEMBER( atn_r ) { return m_atni ^ m_atna; } + + void stp_w(int stp); + void ds_w(int ds); + + void set_floppy(floppy_image_device *floppy); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + +private: + enum { + IDLE, + RUNNING, + RUNNING_SYNCPOINT + }; + + struct live_info { + attotime tm; + int state, next_state; + int sync; + int byte; + int ds; + int oe; + int soe; + int accl; + UINT8 accl_yb; + + attotime edge; + UINT16 shift_reg; + int cycle_counter; + int cell_counter; + int bit_counter; + int zero_counter; + int cycles_until_random_flux; + + UINT8 yb; + UINT8 shift_reg_write; + attotime write_start_time; + attotime write_buffer[32]; + int write_position; + }; + + devcb_write_line m_write_atn; + devcb_write_line m_write_sync; + devcb_write_line m_write_byte; + + floppy_image_device *m_floppy; + + int m_mtr; + int m_accl; + int m_stp; + int m_ds; + int m_soe; + int m_oe; + int m_ted; + UINT8 m_yb; + int m_atni; + int m_atna; + + attotime m_period; + + live_info cur_live, checkpoint_live; + emu_timer *t_gen; + + void live_start(); + void checkpoint(); + void rollback(); + bool write_next_bit(bool bit, const attotime &limit); + void start_writing(const attotime &tm); + void commit(const attotime &tm); + void stop_writing(const attotime &tm); + void live_delay(int state); + void live_sync(); + void live_abort(); + void live_run(const attotime &limit = attotime::never); + void get_next_edge(const attotime &when); + int get_next_bit(attotime &tm, const attotime &limit); +}; + + + +// device type definition +extern const device_type C64H156; + + + +#endif diff --git a/src/devices/machine/6522via.c b/src/devices/machine/6522via.c new file mode 100644 index 00000000000..56a35e19040 --- /dev/null +++ b/src/devices/machine/6522via.c @@ -0,0 +1,985 @@ +// license:BSD-3-Clause +// copyright-holders:Peter Trauner, Mathis Rosenhauer +/********************************************************************** + + Rockwell 6522 VIA interface and emulation + + This function emulates the functionality of up to 8 6522 + versatile interface adapters. + + This is based on the M6821 emulation in MAME. + + To do: + + T2 pulse counting mode + Pulse mode handshake output + More shift register + +**********************************************************************/ + +/* + 1999-Dec-22 PeT + vc20 random number generation only partly working + (reads (uninitialized) timer 1 and timer 2 counter) + timer init, reset, read changed + */ + +#include "emu.h" +#include "6522via.h" + +/*************************************************************************** + PARAMETERS +***************************************************************************/ + +#define TRACE_VIA 0 + + +/*************************************************************************** + MACROS +***************************************************************************/ + +/* Macros for PCR */ +#define CA1_LOW_TO_HIGH(c) (c & 0x01) +#define CA1_HIGH_TO_LOW(c) (!(c & 0x01)) + +#define CB1_LOW_TO_HIGH(c) (c & 0x10) +#define CB1_HIGH_TO_LOW(c) (!(c & 0x10)) + +#define CA2_INPUT(c) (!(c & 0x08)) +#define CA2_LOW_TO_HIGH(c) ((c & 0x0c) == 0x04) +#define CA2_HIGH_TO_LOW(c) ((c & 0x0c) == 0x00) +#define CA2_IND_IRQ(c) ((c & 0x0a) == 0x02) + +#define CA2_OUTPUT(c) (c & 0x08) +#define CA2_AUTO_HS(c) ((c & 0x0c) == 0x08) +#define CA2_HS_OUTPUT(c) ((c & 0x0e) == 0x08) +#define CA2_PULSE_OUTPUT(c) ((c & 0x0e) == 0x0a) +#define CA2_FIX_OUTPUT(c) ((c & 0x0c) == 0x0c) +#define CA2_OUTPUT_LEVEL(c) ((c & 0x02) >> 1) + +#define CB2_INPUT(c) (!(c & 0x80)) +#define CB2_LOW_TO_HIGH(c) ((c & 0xc0) == 0x40) +#define CB2_HIGH_TO_LOW(c) ((c & 0xc0) == 0x00) +#define CB2_IND_IRQ(c) ((c & 0xa0) == 0x20) + +#define CB2_OUTPUT(c) (c & 0x80) +#define CB2_AUTO_HS(c) ((c & 0xc0) == 0x80) +#define CB2_HS_OUTPUT(c) ((c & 0xe0) == 0x80) +#define CB2_PULSE_OUTPUT(c) ((c & 0xe0) == 0xa0) +#define CB2_FIX_OUTPUT(c) ((c & 0xc0) == 0xc0) +#define CB2_OUTPUT_LEVEL(c) ((c & 0x20) >> 5) + +/* Macros for ACR */ +#define PA_LATCH_ENABLE(c) (c & 0x01) +#define PB_LATCH_ENABLE(c) (c & 0x02) + +#define SR_DISABLED(c) (!(c & 0x1c)) +#define SI_T2_CONTROL(c) ((c & 0x1c) == 0x04) +#define SI_O2_CONTROL(c) ((c & 0x1c) == 0x08) +#define SI_EXT_CONTROL(c) ((c & 0x1c) == 0x0c) +#define SO_T2_RATE(c) ((c & 0x1c) == 0x10) +#define SO_T2_CONTROL(c) ((c & 0x1c) == 0x14) +#define SO_O2_CONTROL(c) ((c & 0x1c) == 0x18) +#define SO_EXT_CONTROL(c) ((c & 0x1c) == 0x1c) + +#define T1_SET_PB7(c) (c & 0x80) +#define T1_CONTINUOUS(c) (c & 0x40) +#define T2_COUNT_PB6(c) (c & 0x20) + +/* Interrupt flags */ +#define INT_CA2 0x01 +#define INT_CA1 0x02 +#define INT_SR 0x04 +#define INT_CB2 0x08 +#define INT_CB1 0x10 +#define INT_T2 0x20 +#define INT_T1 0x40 +#define INT_ANY 0x80 + +#define CLR_PA_INT() clear_int(INT_CA1 | ((!CA2_IND_IRQ(m_pcr)) ? INT_CA2: 0)) +#define CLR_PB_INT() clear_int(INT_CB1 | ((!CB2_IND_IRQ(m_pcr)) ? INT_CB2: 0)) + +#define IFR_DELAY 3 + +#define TIMER1_VALUE (m_t1ll+(m_t1lh<<8)) +#define TIMER2_VALUE (m_t2ll+(m_t2lh<<8)) + + + +/*************************************************************************** + INLINE FUNCTIONS +***************************************************************************/ + +UINT16 via6522_device::get_counter1_value() +{ + UINT16 val; + + if(m_t1_active) + { + val = attotime_to_clocks(m_t1->remaining()) - IFR_DELAY; + } + else + { + val = 0xffff - attotime_to_clocks(machine().time() - m_time1); + } + + return val; +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +// device type definition +const device_type VIA6522 = &device_creator; + +DEVICE_ADDRESS_MAP_START( map, 8, via6522_device ) + AM_RANGE(0x00, 0x0f) AM_READWRITE(read, write) +ADDRESS_MAP_END + +//------------------------------------------------- +// via6522_device - constructor +//------------------------------------------------- + +via6522_device::via6522_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, VIA6522, "6522 VIA", tag, owner, clock, "via6522", __FILE__), + m_in_a_handler(*this), + m_in_b_handler(*this), + m_out_a_handler(*this), + m_out_b_handler(*this), + m_ca2_handler(*this), + m_cb1_handler(*this), + m_cb2_handler(*this), + m_irq_handler(*this), + m_in_a(0xff), + m_in_ca1(0), + m_in_ca2(0), + m_out_ca2(0), + m_in_b(0), + m_in_cb1(0), + m_in_cb2(0), + m_pcr(0), + m_acr(0), + m_ier(0), + m_ifr(0) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void via6522_device::device_start() +{ + m_in_a_handler.resolve(); + m_in_b_handler.resolve(); + m_out_a_handler.resolve_safe(); + m_out_b_handler.resolve_safe(); + m_cb1_handler.resolve_safe(); + m_ca2_handler.resolve_safe(); + m_cb2_handler.resolve_safe(); + m_irq_handler.resolve_safe(); + + m_t1ll = 0xf3; /* via at 0x9110 in vic20 show these values */ + m_t1lh = 0xb5; /* ports are not written by kernel! */ + m_t2ll = 0xff; /* taken from vice */ + m_t2lh = 0xff; + m_sr = 0; + + m_time2 = m_time1 = machine().time(); + m_t1 = timer_alloc(TIMER_T1); + m_t2 = timer_alloc(TIMER_T2); + m_ca2_timer = timer_alloc(TIMER_CA2); + m_shift_timer = timer_alloc(TIMER_SHIFT); + + /* Default clock is from CPU1 */ + if (clock() == 0) + { + set_unscaled_clock(machine().firstcpu->clock()); + } + + /* save state register */ + save_item(NAME(m_in_a)); + save_item(NAME(m_in_ca1)); + save_item(NAME(m_in_ca2)); + save_item(NAME(m_out_a)); + save_item(NAME(m_out_ca2)); + save_item(NAME(m_ddr_a)); + save_item(NAME(m_latch_a)); + save_item(NAME(m_in_b)); + save_item(NAME(m_in_cb1)); + save_item(NAME(m_in_cb2)); + save_item(NAME(m_out_b)); + save_item(NAME(m_out_cb1)); + save_item(NAME(m_out_cb2)); + save_item(NAME(m_ddr_b)); + save_item(NAME(m_latch_b)); + save_item(NAME(m_t1cl)); + save_item(NAME(m_t1ch)); + save_item(NAME(m_t1ll)); + save_item(NAME(m_t1lh)); + save_item(NAME(m_t2cl)); + save_item(NAME(m_t2ch)); + save_item(NAME(m_t2ll)); + save_item(NAME(m_t2lh)); + save_item(NAME(m_sr)); + save_item(NAME(m_pcr)); + save_item(NAME(m_acr)); + save_item(NAME(m_ier)); + save_item(NAME(m_ifr)); + save_item(NAME(m_time1)); + save_item(NAME(m_t1_active)); + save_item(NAME(m_t1_pb7)); + save_item(NAME(m_time2)); + save_item(NAME(m_t2_active)); + save_item(NAME(m_shift_counter)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void via6522_device::device_reset() +{ + m_out_a = 0; + m_out_ca2 = 1; + m_ddr_a = 0; + m_latch_a = 0; + + m_out_b = 0; + m_out_cb1 = 1; + m_out_cb2 = 1; + m_ddr_b = 0; + m_latch_b = 0; + + m_t1cl = 0; + m_t1ch = 0; + m_t2cl = 0; + m_t2ch = 0; + + m_pcr = 0; + m_acr = 0; + m_ier = 0; + m_ifr = 0; + m_t1_active = 0; + m_t1_pb7 = 1; + m_t2_active = 0; + m_shift_counter = 0; + + output_pa(); + output_pb(); + m_ca2_handler(m_out_ca2); + m_cb1_handler(m_out_cb1); + m_cb2_handler(m_out_cb2); +} + + +void via6522_device::output_irq() +{ + if (m_ier & m_ifr & 0x7f) + { + if ((m_ifr & INT_ANY) == 0) + { + m_ifr |= INT_ANY; + m_irq_handler(ASSERT_LINE); + } + } + else + { + if (m_ifr & INT_ANY) + { + m_ifr &= ~INT_ANY; + m_irq_handler(CLEAR_LINE); + } + } +} + + +/*------------------------------------------------- + via_set_int - external interrupt check +-------------------------------------------------*/ + +void via6522_device::set_int(int data) +{ + if (!(m_ifr & data)) + { + m_ifr |= data; + + output_irq(); + + if (TRACE_VIA) + { + logerror("%s:6522VIA chip %s: IFR = %02X\n", machine().describe_context(), tag(), m_ifr); + } + } +} + + +/*------------------------------------------------- + via_clear_int - external interrupt check +-------------------------------------------------*/ + +void via6522_device::clear_int(int data) +{ + if (m_ifr & data) + { + m_ifr &= ~data; + + output_irq(); + + if (TRACE_VIA) + { + logerror("%s:6522VIA chip %s: IFR = %02X\n", machine().describe_context(), tag(), m_ifr); + } + } +} + + +/*------------------------------------------------- + via_shift +-------------------------------------------------*/ + +void via6522_device::shift_out() +{ + m_out_cb2 = (m_sr >> 7) & 1; + m_sr = (m_sr << 1) | m_out_cb2; + + m_cb2_handler(m_out_cb2); + + if (!SO_T2_RATE(m_acr)) + { + m_shift_counter = (m_shift_counter + 1) % 8; + + if (m_shift_counter == 0) + { + set_int(INT_SR); + } + } +} + +void via6522_device::shift_in() +{ + m_sr = (m_sr << 1) | (m_in_cb2 & 1); + + m_shift_counter = (m_shift_counter + 1) % 8; + + if (m_shift_counter == 0) + { + set_int(INT_SR); + } +} + + +void via6522_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch (id) + { + case TIMER_SHIFT: + m_out_cb1 = 0; + m_cb1_handler(m_out_cb1); + + if (SO_T2_RATE(m_acr) || SO_T2_CONTROL(m_acr) || SO_O2_CONTROL(m_acr)) + { + shift_out(); + } + + m_out_cb1 = 1; + m_cb1_handler(m_out_cb1); + + if (SI_T2_CONTROL(m_acr) || SI_O2_CONTROL(m_acr)) + { + shift_in(); + } + + if (SO_T2_RATE(m_acr) || m_shift_counter) + { + if (SI_O2_CONTROL(m_acr) || SO_O2_CONTROL(m_acr)) + { + m_shift_timer->adjust(clocks_to_attotime(2)); + } + else + { + m_shift_timer->adjust(clocks_to_attotime((m_t2ll + 2)*2)); + } + } + break; + + case TIMER_T1: + if (T1_CONTINUOUS (m_acr)) + { + m_t1_pb7 = !m_t1_pb7; + m_t1->adjust(clocks_to_attotime(TIMER1_VALUE + IFR_DELAY)); + } + else + { + m_t1_pb7 = 1; + m_t1_active = 0; + m_time1 = machine().time(); + } + + if (T1_SET_PB7(m_acr)) + { + output_pb(); + } + + set_int(INT_T1); + break; + + case TIMER_T2: + m_t2_active = 0; + m_time2 = machine().time(); + + set_int(INT_T2); + break; + + case TIMER_CA2: + m_out_ca2 = 1; + m_ca2_handler(m_out_ca2); + break; + } +} + +UINT8 via6522_device::input_pa() +{ + /// TODO: REMOVE THIS + if (!m_in_a_handler.isnull()) + { + if (m_ddr_a != 0xff) + m_in_a = m_in_a_handler(0); + + return (m_out_a & m_ddr_a) + (m_in_a & ~m_ddr_a); + } + + return m_in_a & (m_out_a | ~m_ddr_a); +} + +void via6522_device::output_pa() +{ + UINT8 pa = (m_out_a & m_ddr_a) | ~m_ddr_a; + m_out_a_handler(pa); +} + +UINT8 via6522_device::input_pb() +{ + /// TODO: REMOVE THIS + if (m_ddr_b != 0xff && !m_in_b_handler.isnull()) + { + m_in_b = m_in_b_handler(0); + } + + UINT8 pb = (m_out_b & m_ddr_b) + (m_in_b & ~m_ddr_b); + + if (T1_SET_PB7(m_acr)) + pb = (pb & 0x7f) | (m_t1_pb7 << 7); + + return pb; +} + +void via6522_device::output_pb() +{ + UINT8 pb = (m_out_b & m_ddr_b) | ~m_ddr_b; + + if (T1_SET_PB7(m_acr)) + pb = (pb & 0x7f) | (m_t1_pb7 << 7); + + m_out_b_handler(pb); +} + +/*------------------------------------------------- + via_r - CPU interface for VIA read +-------------------------------------------------*/ + +READ8_MEMBER( via6522_device::read ) +{ + int val = 0; + if (space.debugger_access()) + return 0; + + offset &= 0xf; + + switch (offset) + { + case VIA_PB: + /* update the input */ + if (PB_LATCH_ENABLE(m_acr) == 0) + { + val = input_pb(); + } + else + { + val = m_latch_b; + } + + CLR_PB_INT(); + break; + + case VIA_PA: + /* update the input */ + if (PA_LATCH_ENABLE(m_acr) == 0) + { + val = input_pa(); + } + else + { + val = m_latch_a; + } + + CLR_PA_INT(); + + if (m_out_ca2 && (CA2_PULSE_OUTPUT(m_pcr) || CA2_AUTO_HS(m_pcr))) + { + m_out_ca2 = 0; + m_ca2_handler(m_out_ca2); + } + + if (CA2_PULSE_OUTPUT(m_pcr)) + m_ca2_timer->adjust(clocks_to_attotime(1)); + + break; + + case VIA_PANH: + /* update the input */ + if (PA_LATCH_ENABLE(m_acr) == 0) + { + val = input_pa(); + } + else + { + val = m_latch_a; + } + break; + + case VIA_DDRB: + val = m_ddr_b; + break; + + case VIA_DDRA: + val = m_ddr_a; + break; + + case VIA_T1CL: + clear_int(INT_T1); + val = get_counter1_value() & 0xFF; + break; + + case VIA_T1CH: + val = get_counter1_value() >> 8; + break; + + case VIA_T1LL: + val = m_t1ll; + break; + + case VIA_T1LH: + val = m_t1lh; + break; + + case VIA_T2CL: + clear_int(INT_T2); + if (m_t2_active) + { + val = attotime_to_clocks(m_t2->remaining()) & 0xff; + } + else + { + if (T2_COUNT_PB6(m_acr)) + { + val = m_t2cl; + } + else + { + val = (0x10000 - (attotime_to_clocks(machine().time() - m_time2) & 0xffff) - 1) & 0xff; + } + } + break; + + case VIA_T2CH: + if (m_t2_active) + { + val = attotime_to_clocks(m_t2->remaining()) >> 8; + } + else + { + if (T2_COUNT_PB6(m_acr)) + { + val = m_t2ch; + } + else + { + val = (0x10000 - (attotime_to_clocks(machine().time() - m_time2) & 0xffff) - 1) >> 8; + } + } + break; + + case VIA_SR: + val = m_sr; + m_shift_counter=0; + clear_int(INT_SR); + if (SI_O2_CONTROL(m_acr)) + { + m_shift_timer->adjust(clocks_to_attotime(2)); + } + if (SI_T2_CONTROL(m_acr)) + { + m_shift_timer->adjust(clocks_to_attotime((m_t2ll + 2)*2)); + } + break; + + case VIA_PCR: + val = m_pcr; + break; + + case VIA_ACR: + val = m_acr; + break; + + case VIA_IER: + val = m_ier | 0x80; + break; + + case VIA_IFR: + val = m_ifr; + break; + } + return val; +} + + +/*------------------------------------------------- + via_w - CPU interface for VIA write +-------------------------------------------------*/ + +WRITE8_MEMBER( via6522_device::write ) +{ + offset &=0x0f; + + switch (offset) + { + case VIA_PB: + m_out_b = data; + + if (m_ddr_b != 0) + { + output_pb(); + } + + CLR_PB_INT(); + + if (m_out_cb2 && CB2_AUTO_HS(m_pcr)) + { + m_out_cb2 = 0; + m_cb2_handler(m_out_cb2); + } + break; + + case VIA_PA: + m_out_a = data; + + if (m_ddr_a != 0) + { + output_pa(); + } + + CLR_PA_INT(); + + if (m_out_ca2 && (CA2_PULSE_OUTPUT(m_pcr) || CA2_AUTO_HS(m_pcr))) + { + m_out_ca2 = 0; + m_ca2_handler(m_out_ca2); + } + + if (CA2_PULSE_OUTPUT(m_pcr)) + m_ca2_timer->adjust(clocks_to_attotime(1)); + + break; + + case VIA_PANH: + m_out_a = data; + + if (m_ddr_a != 0) + { + output_pa(); + } + + break; + + case VIA_DDRB: + if ( data != m_ddr_b ) + { + m_ddr_b = data; + + output_pb(); + } + break; + + case VIA_DDRA: + if (m_ddr_a != data) + { + m_ddr_a = data; + + output_pa(); + } + break; + + case VIA_T1CL: + case VIA_T1LL: + m_t1ll = data; + break; + + case VIA_T1LH: + m_t1lh = data; + clear_int(INT_T1); + break; + + case VIA_T1CH: + m_t1ch = m_t1lh = data; + m_t1cl = m_t1ll; + + clear_int(INT_T1); + + m_t1_pb7 = 0; + + if (T1_SET_PB7(m_acr)) + { + output_pb(); + } + + m_t1->adjust(clocks_to_attotime(TIMER1_VALUE + IFR_DELAY)); + m_t1_active = 1; + break; + + case VIA_T2CL: + m_t2ll = data; + break; + + case VIA_T2CH: + m_t2ch = m_t2lh = data; + m_t2cl = m_t2ll; + + clear_int(INT_T2); + + if (!T2_COUNT_PB6(m_acr)) + { + m_t2->adjust(clocks_to_attotime(TIMER2_VALUE + IFR_DELAY)); + m_t2_active = 1; + } + else + { + m_t2->adjust(clocks_to_attotime(TIMER2_VALUE)); + m_t2_active = 1; + m_time2 = machine().time(); + } + break; + + case VIA_SR: + m_sr = data; + m_shift_counter=0; + clear_int(INT_SR); + if (SO_O2_CONTROL(m_acr)) + { + m_shift_timer->adjust(clocks_to_attotime(2)); + } + if (SO_T2_RATE(m_acr) || SO_T2_CONTROL(m_acr)) + { + m_shift_timer->adjust(clocks_to_attotime((m_t2ll + 2)*2)); + } + break; + + case VIA_PCR: + m_pcr = data; + + if (TRACE_VIA) + { + logerror("%s:6522VIA chip %s: PCR = %02X\n", machine().describe_context(), tag(), data); + } + + if (CA2_FIX_OUTPUT(data) && m_out_ca2 != CA2_OUTPUT_LEVEL(data)) + { + m_out_ca2 = CA2_OUTPUT_LEVEL(data); + m_ca2_handler(m_out_ca2); + } + + if (CB2_FIX_OUTPUT(data) && m_out_cb2 != CB2_OUTPUT_LEVEL(data)) + { + m_out_cb2 = CB2_OUTPUT_LEVEL(data); + m_cb2_handler(m_out_cb2); + } + break; + + case VIA_ACR: + { + UINT16 counter1 = get_counter1_value(); + m_acr = data; + + output_pb(); + + if (T1_CONTINUOUS(data)) + { + m_t1->adjust(clocks_to_attotime(counter1 + IFR_DELAY)); + m_t1_active = 1; + } + } + break; + + case VIA_IER: + if (data & 0x80) + { + m_ier |= data & 0x7f; + } + else + { + m_ier &= ~(data & 0x7f); + } + + output_irq(); + break; + + case VIA_IFR: + if (data & INT_ANY) + { + data = 0x7f; + } + clear_int(data); + break; + } +} + +void via6522_device::write_pa(int line, int state) +{ + if (state) + m_in_a |= (1 << line); + else + m_in_a &= ~(1 << line); +} + +WRITE8_MEMBER( via6522_device::write_pa ) +{ + m_in_a = data; +} + +/*------------------------------------------------- + ca1_w - interface setting VIA port CA1 input +-------------------------------------------------*/ + +WRITE_LINE_MEMBER( via6522_device::write_ca1 ) +{ + if (m_in_ca1 != state) + { + m_in_ca1 = state; + + if (TRACE_VIA) + logerror("%s:6522VIA chip %s: CA1 = %02X\n", machine().describe_context(), tag(), m_in_ca1); + + if ((m_in_ca1 && CA1_LOW_TO_HIGH(m_pcr)) || (!m_in_ca1 && CA1_HIGH_TO_LOW(m_pcr))) + { + if (PA_LATCH_ENABLE(m_acr)) + { + m_latch_a = input_pa(); + } + + set_int(INT_CA1); + + if (!m_out_ca2 && CA2_AUTO_HS(m_pcr)) + { + m_out_ca2 = 1; + m_ca2_handler(m_out_ca2); + } + } + } +} + + +/*------------------------------------------------- + ca2_w - interface setting VIA port CA2 input +-------------------------------------------------*/ + +WRITE_LINE_MEMBER( via6522_device::write_ca2 ) +{ + if (m_in_ca2 != state) + { + m_in_ca2 = state; + + if (CA2_INPUT(m_pcr)) + { + if ((m_in_ca2 && CA2_LOW_TO_HIGH(m_pcr)) || (!m_in_ca2 && CA2_HIGH_TO_LOW(m_pcr))) + { + set_int(INT_CA2); + } + } + } +} + +void via6522_device::write_pb(int line, int state) +{ + if (state) + m_in_b |= (1 << line); + else + m_in_b &= ~(1 << line); +} + +WRITE8_MEMBER( via6522_device::write_pb ) +{ + m_in_b = data; +} + +/*------------------------------------------------- + cb1_w - interface setting VIA port CB1 input +-------------------------------------------------*/ + +WRITE_LINE_MEMBER( via6522_device::write_cb1 ) +{ + if (m_in_cb1 != state) + { + m_in_cb1 = state; + + if ((m_in_cb1 && CB1_LOW_TO_HIGH(m_pcr)) || (!m_in_cb1 && CB1_HIGH_TO_LOW(m_pcr))) + { + if (PB_LATCH_ENABLE(m_acr)) + { + m_latch_b = input_pb(); + } + + if (SO_EXT_CONTROL(m_acr)) + { + shift_out(); + } + + if (SI_EXT_CONTROL(m_acr)) + { + shift_in(); + } + + set_int(INT_CB1); + + if (!m_out_cb2 && CB2_AUTO_HS(m_pcr)) + { + m_out_cb2 = 1; + m_cb2_handler(1); + } + } + } +} + + +/*------------------------------------------------- + cb2_w - interface setting VIA port CB2 input +-------------------------------------------------*/ + +WRITE_LINE_MEMBER( via6522_device::write_cb2 ) +{ + if (m_in_cb2 != state) + { + m_in_cb2 = state; + + if (CB2_INPUT(m_pcr)) + { + if ((m_in_cb2 && CB2_LOW_TO_HIGH(m_pcr)) || (!m_in_cb2 && CB2_HIGH_TO_LOW(m_pcr))) + { + set_int(INT_CB2); + } + } + } +} diff --git a/src/devices/machine/6522via.h b/src/devices/machine/6522via.h new file mode 100644 index 00000000000..0b882ee7195 --- /dev/null +++ b/src/devices/machine/6522via.h @@ -0,0 +1,221 @@ +// license:BSD-3-Clause +// copyright-holders:Peter Trauner, Mathis Rosenhauer +/********************************************************************** + + Rockwell 6522 VIA interface and emulation + + This function emulates all the functionality of 6522 + versatile interface adapters. + + This is based on the pre-existing 6821 emulation. + + Written by Mathis Rosenhauer + +**********************************************************************/ + +#pragma once + +#ifndef __6522VIA_H__ +#define __6522VIA_H__ + +#include "emu.h" + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +// TODO: REMOVE THESE +#define MCFG_VIA6522_READPA_HANDLER(_devcb) \ + devcb = &via6522_device::set_readpa_handler(*device, DEVCB_##_devcb); + +#define MCFG_VIA6522_READPB_HANDLER(_devcb) \ + devcb = &via6522_device::set_readpb_handler(*device, DEVCB_##_devcb); + +// TODO: CONVERT THESE TO WRITE LINE +#define MCFG_VIA6522_WRITEPA_HANDLER(_devcb) \ + devcb = &via6522_device::set_writepa_handler(*device, DEVCB_##_devcb); + +#define MCFG_VIA6522_WRITEPB_HANDLER(_devcb) \ + devcb = &via6522_device::set_writepb_handler(*device, DEVCB_##_devcb); + +#define MCFG_VIA6522_CA2_HANDLER(_devcb) \ + devcb = &via6522_device::set_ca2_handler(*device, DEVCB_##_devcb); + +#define MCFG_VIA6522_CB1_HANDLER(_devcb) \ + devcb = &via6522_device::set_cb1_handler(*device, DEVCB_##_devcb); + +#define MCFG_VIA6522_CB2_HANDLER(_devcb) \ + devcb = &via6522_device::set_cb2_handler(*device, DEVCB_##_devcb); + +#define MCFG_VIA6522_IRQ_HANDLER(_devcb) \ + devcb = &via6522_device::set_irq_handler(*device, DEVCB_##_devcb); + + +/*************************************************************************** + TYPE DEFINITIONS +***************************************************************************/ + + +// ======================> via6522_device + +class via6522_device : public device_t +{ +public: + // construction/destruction + via6522_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // TODO: REMOVE THESE + template static devcb_base &set_readpa_handler(device_t &device, _Object object) { return downcast(device).m_in_a_handler.set_callback(object); } + template static devcb_base &set_readpb_handler(device_t &device, _Object object) { return downcast(device).m_in_b_handler.set_callback(object); } + + // TODO: CONVERT THESE TO WRITE LINE + template static devcb_base &set_writepa_handler(device_t &device, _Object object) { return downcast(device).m_out_a_handler.set_callback(object); } + template static devcb_base &set_writepb_handler(device_t &device, _Object object) { return downcast(device).m_out_b_handler.set_callback(object); } + + template static devcb_base &set_ca2_handler(device_t &device, _Object object) { return downcast(device).m_ca2_handler.set_callback(object); } + template static devcb_base &set_cb1_handler(device_t &device, _Object object) { return downcast(device).m_cb1_handler.set_callback(object); } + template static devcb_base &set_cb2_handler(device_t &device, _Object object) { return downcast(device).m_cb2_handler.set_callback(object); } + template static devcb_base &set_irq_handler(device_t &device, _Object object) { return downcast(device).m_irq_handler.set_callback(object); } + + virtual DECLARE_ADDRESS_MAP(map, 8); + + DECLARE_READ8_MEMBER( read ); + DECLARE_WRITE8_MEMBER( write ); + + DECLARE_WRITE_LINE_MEMBER( write_pa0 ) { write_pa(0, state); } + DECLARE_WRITE_LINE_MEMBER( write_pa1 ) { write_pa(1, state); } + DECLARE_WRITE_LINE_MEMBER( write_pa2 ) { write_pa(2, state); } + DECLARE_WRITE_LINE_MEMBER( write_pa3 ) { write_pa(3, state); } + DECLARE_WRITE_LINE_MEMBER( write_pa4 ) { write_pa(4, state); } + DECLARE_WRITE_LINE_MEMBER( write_pa5 ) { write_pa(5, state); } + DECLARE_WRITE_LINE_MEMBER( write_pa6 ) { write_pa(6, state); } + DECLARE_WRITE_LINE_MEMBER( write_pa7 ) { write_pa(7, state); } + DECLARE_WRITE8_MEMBER( write_pa ); + DECLARE_WRITE_LINE_MEMBER( write_ca1 ); + DECLARE_WRITE_LINE_MEMBER( write_ca2 ); + + DECLARE_WRITE_LINE_MEMBER( write_pb0 ) { write_pb(0, state); } + DECLARE_WRITE_LINE_MEMBER( write_pb1 ) { write_pb(1, state); } + DECLARE_WRITE_LINE_MEMBER( write_pb2 ) { write_pb(2, state); } + DECLARE_WRITE_LINE_MEMBER( write_pb3 ) { write_pb(3, state); } + DECLARE_WRITE_LINE_MEMBER( write_pb4 ) { write_pb(4, state); } + DECLARE_WRITE_LINE_MEMBER( write_pb5 ) { write_pb(5, state); } + DECLARE_WRITE_LINE_MEMBER( write_pb6 ) { write_pb(6, state); } + DECLARE_WRITE_LINE_MEMBER( write_pb7 ) { write_pb(7, state); } + DECLARE_WRITE8_MEMBER( write_pb ); + DECLARE_WRITE_LINE_MEMBER( write_cb1 ); + DECLARE_WRITE_LINE_MEMBER( write_cb2 ); + + enum + { + VIA_PB = 0, + VIA_PA = 1, + VIA_DDRB = 2, + VIA_DDRA = 3, + VIA_T1CL = 4, + VIA_T1CH = 5, + VIA_T1LL = 6, + VIA_T1LH = 7, + VIA_T2CL = 8, + VIA_T2CH = 9, + VIA_SR = 10, + VIA_ACR = 11, + VIA_PCR = 12, + VIA_IFR = 13, + VIA_IER = 14, + VIA_PANH = 15 + }; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + +private: + static const device_timer_id TIMER_SHIFT = 0; + static const device_timer_id TIMER_T1 = 1; + static const device_timer_id TIMER_T2 = 2; + static const device_timer_id TIMER_CA2 = 3; + + UINT16 get_counter1_value(); + + void set_int(int data); + void clear_int(int data); + void shift_out(); + void shift_in(); + void write_pa(int line, int state); + void write_pb(int line, int state); + + UINT8 input_pa(); + void output_pa(); + UINT8 input_pb(); + void output_pb(); + void output_irq(); + + // TODO: REMOVE THESE + devcb_read8 m_in_a_handler; + devcb_read8 m_in_b_handler; + + // TODO: CONVERT THESE TO WRITE LINE + devcb_write8 m_out_a_handler; + devcb_write8 m_out_b_handler; + + devcb_write_line m_ca2_handler; + devcb_write_line m_cb1_handler; + devcb_write_line m_cb2_handler; + devcb_write_line m_irq_handler; + + UINT8 m_in_a; + int m_in_ca1; + int m_in_ca2; + UINT8 m_out_a; + int m_out_ca2; + UINT8 m_ddr_a; + UINT8 m_latch_a; + + UINT8 m_in_b; + int m_in_cb1; + int m_in_cb2; + UINT8 m_out_b; + int m_out_cb1; + int m_out_cb2; + UINT8 m_ddr_b; + UINT8 m_latch_b; + + UINT8 m_t1cl; + UINT8 m_t1ch; + UINT8 m_t1ll; + UINT8 m_t1lh; + UINT8 m_t2cl; + UINT8 m_t2ch; + UINT8 m_t2ll; + UINT8 m_t2lh; + + UINT8 m_sr; + UINT8 m_pcr; + UINT8 m_acr; + UINT8 m_ier; + UINT8 m_ifr; + + emu_timer *m_t1; + attotime m_time1; + UINT8 m_t1_active; + int m_t1_pb7; + emu_timer *m_t2; + attotime m_time2; + UINT8 m_t2_active; + emu_timer *m_ca2_timer; + + emu_timer *m_shift_timer; + UINT8 m_shift_counter; +}; + + +// device type definition +extern const device_type VIA6522; + + +#endif /* __6522VIA_H__ */ diff --git a/src/devices/machine/6525tpi.c b/src/devices/machine/6525tpi.c new file mode 100644 index 00000000000..038440e29d3 --- /dev/null +++ b/src/devices/machine/6525tpi.c @@ -0,0 +1,561 @@ +// license:BSD-3-Clause +// copyright-holders:Peter Trauner +/*************************************************************************** + mos tri port interface 6525 + mos triple interface adapter 6523 + + peter.trauner@jk.uni-linz.ac.at + + used in commodore b series + used in commodore c1551 floppy disk drive +***************************************************************************/ + +/* + mos tpi 6525 + 40 pin package + 3 8 bit ports (pa, pb, pc) + 8 registers to pc + 0 port a 0 in low + 1 port a data direction register 1 output + 2 port b + 3 port b ddr + 4 port c + handshaking, interrupt mode + 0 interrupt 0 input, 1 interrupt enabled + interrupt set on falling edge + 1 interrupt 1 input + 2 interrupt 2 input + 3 interrupt 3 input + 4 interrupt 4 input + 5 irq output + 6 ca handshake line (read handshake answer on I3 preferred) + 7 cb handshake line (write handshake clear on I4 preferred) + 5 port c ddr + + 6 cr configuration register + 0 mc + 0 port c normal input output mode like port a and b + 1 port c used for handshaking and interrupt input + 1 1 interrupt prioritized + 2 i3 configure edge + 1 interrupt set on positive edge + 3 i4 configure edge + 5,4 ca handshake + 00 on read + rising edge of i3 sets ca high + read a data from computers sets ca low + 01 pulse output + 1 microsecond low after read a operation + 10 manual output low + 11 manual output high + 7,6 cb handshake + 00 handshake on write + write b data from computer sets cb 0 + rising edge of i4 sets cb high + 01 pulse output + 1 microsecond low after write b operation + 10 manual output low + 11 manual output high + 7 air active interrupt register + 0 I0 occurred + 1 I1 occurred + 2 I2 occurred + 3 I3 occurred + 4 I4 occurred + read clears interrupt + + non prioritized interrupts + interrupt is set when occurred + read clears all interrupts + + prioritized interrupts + I4>I3>I2>I1>I0 + highest interrupt can be found in air register + read clears highest interrupt +*/ + +#include "emu.h" +#include "6525tpi.h" + + +/*************************************************************************** + CONSTANTS +***************************************************************************/ + +#define VERBOSE_LEVEL 0 +#define DBG_LOG( MACHINE, N, M, A ) \ + do { \ + if(VERBOSE_LEVEL >= N) \ + { \ + if( M ) \ + logerror("%11.6f: %-24s", MACHINE.time().as_double(), (char*) M ); \ + logerror A; \ + } \ + } while (0) + + +#define INTERRUPT_MODE (m_cr & 1) +#define PRIORIZED_INTERRUPTS (m_cr & 2) +#define INTERRUPT3_RISING_EDGE (m_cr & 4) +#define INTERRUPT4_RISING_EDGE (m_cr & 8) +#define CA_MANUAL_OUT (m_cr & 0x20) +#define CA_MANUAL_LEVEL ((m_cr & 0x10) ? 1 : 0) +#define CB_MANUAL_OUT (m_cr & 0x80) +#define CB_MANUAL_LEVEL ((m_cr & 0x40) ? 1 : 0) + + +const device_type TPI6525 = &device_creator; + +tpi6525_device::tpi6525_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, TPI6525, "6525 TPI", tag, owner, clock, "tpi6525", __FILE__), + m_out_irq_cb(*this), + m_in_pa_cb(*this), + m_out_pa_cb(*this), + m_in_pb_cb(*this), + m_out_pb_cb(*this), + m_in_pc_cb(*this), + m_out_pc_cb(*this), + m_out_ca_cb(*this), + m_out_cb_cb(*this), + m_port_a(0), + m_ddr_a(0), + m_in_a(0), + m_port_b(0), + m_ddr_b(0), + m_in_b(0), + m_port_c(0), + m_ddr_c(0), + m_in_c(0), + m_ca_level(0), + m_cb_level(0), + m_interrupt_level(0), + m_cr(0), + m_air(0) +{ + for (int i = 0; i < 5; i++) + { + m_irq_level[i] = 0; + } +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void tpi6525_device::device_start() +{ + // resolve callbacks + m_out_irq_cb.resolve_safe(); + m_in_pa_cb.resolve(); + m_out_pa_cb.resolve_safe(); + m_in_pb_cb.resolve(); + m_out_pb_cb.resolve_safe(); + m_in_pc_cb.resolve(); + m_out_pc_cb.resolve_safe(); + m_out_ca_cb.resolve_safe(); + m_out_cb_cb.resolve_safe(); + + /* register for state saving */ + save_item(NAME(m_port_a)); + save_item(NAME(m_ddr_a)); + save_item(NAME(m_in_a)); + save_item(NAME(m_port_b)); + save_item(NAME(m_ddr_b)); + save_item(NAME(m_in_b)); + save_item(NAME(m_port_c)); + save_item(NAME(m_ddr_c)); + save_item(NAME(m_in_c)); + save_item(NAME(m_ca_level)); + save_item(NAME(m_cb_level)); + save_item(NAME(m_interrupt_level)); + save_item(NAME(m_cr)); + save_item(NAME(m_air)); + save_item(NAME(m_irq_level)); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void tpi6525_device::device_reset() +{ + /* setup some initial values */ + m_in_a = 0xff; + m_in_b = 0xff; + m_in_c = 0xff; +} + + +/*************************************************************************** + IMPLEMENTATION +***************************************************************************/ + +void tpi6525_device::set_interrupt() +{ + if (!m_interrupt_level && (m_air != 0)) + { + m_interrupt_level = 1; + + DBG_LOG(machine(), 3, "tpi6525", ("%s set interrupt\n", tag())); + + m_out_irq_cb(m_interrupt_level); + } +} + + +void tpi6525_device::clear_interrupt() +{ + if (m_interrupt_level && (m_air == 0)) + { + m_interrupt_level = 0; + + DBG_LOG(machine(), 3, "tpi6525", ("%s clear interrupt\n", tag())); + + m_out_irq_cb(m_interrupt_level); + } +} + + +WRITE_LINE_MEMBER( tpi6525_device::i0_w ) +{ + if (INTERRUPT_MODE && (state != m_irq_level[0])) + { + m_irq_level[0] = state; + + if ((state == 0) && !(m_air & 1) && (m_ddr_c & 1)) + { + m_air |= 1; + set_interrupt(); + } + } +} + + +WRITE_LINE_MEMBER( tpi6525_device::i1_w ) +{ + if (INTERRUPT_MODE && (state != m_irq_level[1])) + { + m_irq_level[1] = state; + + if ((state == 0) && !(m_air & 2) && (m_ddr_c & 2)) + { + m_air |= 2; + set_interrupt(); + } + } +} + + +WRITE_LINE_MEMBER( tpi6525_device::i2_w ) +{ + if (INTERRUPT_MODE && (state != m_irq_level[2])) + { + m_irq_level[2] = state; + + if ((state == 0) && !(m_air & 4) && (m_ddr_c & 4)) + { + m_air |= 4; + set_interrupt(); + } + } +} + + +WRITE_LINE_MEMBER( tpi6525_device::i3_w ) +{ + if (INTERRUPT_MODE && (state != m_irq_level[3])) + { + m_irq_level[3] = state; + + if (((INTERRUPT3_RISING_EDGE && (state == 1)) + || (!INTERRUPT3_RISING_EDGE && (state == 0))) + && !(m_air & 8) && (m_ddr_c & 8)) + { + m_air |= 8; + set_interrupt(); + } + } +} + + +WRITE_LINE_MEMBER( tpi6525_device::i4_w ) +{ + if (INTERRUPT_MODE && (state != m_irq_level[4]) ) + { + m_irq_level[4] = state; + + if (((INTERRUPT4_RISING_EDGE && (state == 1)) + ||(!INTERRUPT4_RISING_EDGE&&(state == 0))) + && !(m_air & 0x10) && (m_ddr_c & 0x10)) + { + m_air |= 0x10; + set_interrupt(); + } + } +} + +READ8_MEMBER( tpi6525_device::pa_r ) +{ + UINT8 data = m_in_a; + + if (!m_in_pa_cb.isnull()) + data = m_in_pa_cb(offset); + + data = (data & ~m_ddr_a) | (m_ddr_a & m_port_a); + + return data; +} + + +WRITE8_MEMBER( tpi6525_device::pa_w ) +{ + m_in_a = data; +} + + +READ8_MEMBER( tpi6525_device::pb_r ) +{ + UINT8 data = m_in_b; + + if (!m_in_pb_cb.isnull()) + data = m_in_pb_cb(offset); + + data = (data & ~m_ddr_b) | (m_ddr_b & m_port_b); + + return data; +} + + +WRITE8_MEMBER( tpi6525_device::pb_w ) +{ + m_in_b = data; +} + + +READ8_MEMBER( tpi6525_device::pc_r ) +{ + UINT8 data = m_in_c; + + if (!m_in_pc_cb.isnull()) + data &= m_in_pc_cb(offset); + + data = (data & ~m_ddr_c) | (m_ddr_c & m_port_c); + + return data; +} + + +WRITE8_MEMBER( tpi6525_device::pc_w ) +{ + m_in_c = data; +} + + +READ8_MEMBER( tpi6525_device::read ) +{ + UINT8 data = 0xff; + + switch (offset & 7) + { + case 0: + data = m_in_a; + + if (!m_in_pa_cb.isnull()) + data &= m_in_pa_cb(0); + + data = (data & ~m_ddr_a) | (m_ddr_a & m_port_a); + + break; + + case 1: + data = m_in_b; + + if (!m_in_pb_cb.isnull()) + data &= m_in_pb_cb(0); + + data = (data & ~m_ddr_b) | (m_ddr_b & m_port_b); + + break; + + case 2: + if (INTERRUPT_MODE) + { + data = 0; + + if (m_irq_level[0]) data |= 0x01; + if (m_irq_level[1]) data |= 0x02; + if (m_irq_level[2]) data |= 0x04; + if (m_irq_level[3]) data |= 0x08; + if (m_irq_level[4]) data |= 0x10; + if (!m_interrupt_level) data |= 0x20; + if (m_ca_level) data |= 0x40; + if (m_cb_level) data |= 0x80; + } + else + { + data = m_in_c; + + if (!m_in_pc_cb.isnull()) + data &= m_in_pc_cb(0); + + data = (data & ~m_ddr_c) | (m_ddr_c & m_port_c); + } + + DBG_LOG(machine(), 2, "tpi6525", ("%s read %.2x %.2x\n", tag(), offset, data)); + break; + + case 3: + data = m_ddr_a; + break; + + case 4: + data = m_ddr_b; + break; + + case 5: + data = m_ddr_c; + break; + + case 6: + data = m_cr; + break; + + case 7: /* air */ + if (PRIORIZED_INTERRUPTS) + { + if (m_air & 0x10) + { + data = 0x10; + m_air &= ~0x10; + } + else if (m_air & 8) + { + data = 8; + m_air &= ~8; + } + else if (m_air & 4) + { + data = 4; + m_air &= ~4; + } + else if (m_air & 2) + { + data = 2; + m_air &= ~2; + } + else if (m_air & 1) + { + data = 1; + m_air &= ~1; + } + } + else + { + data = m_air; + m_air = 0; + } + + clear_interrupt(); + break; + + } + + DBG_LOG(machine(), 3, "tpi6525", ("%s read %.2x %.2x\n", tag(), offset, data)); + + return data; +} + + +WRITE8_MEMBER( tpi6525_device::write ) +{ + DBG_LOG(machine(), 2, "tpi6525", ("%s write %.2x %.2x\n", tag(), offset, data)); + + switch (offset & 7) + { + case 0: + m_port_a = data; + m_out_pa_cb((offs_t)0, (m_port_a & m_ddr_a) | (m_ddr_a ^ 0xff)); + break; + + case 1: + m_port_b = data; + m_out_pb_cb((offs_t)0, (m_port_b & m_ddr_b) | (m_ddr_b ^ 0xff)); + break; + + case 2: + m_port_c = data; + + if (!INTERRUPT_MODE) + m_out_pc_cb((offs_t)0, (m_port_c & m_ddr_c) | (m_ddr_c ^ 0xff)); + break; + + case 3: + m_ddr_a = data; + m_out_pa_cb((offs_t)0, (m_port_a & m_ddr_a) | (m_ddr_a ^ 0xff)); + break; + + case 4: + m_ddr_b = data; + m_out_pb_cb((offs_t)0, (m_port_b & m_ddr_b) | (m_ddr_b ^ 0xff)); + break; + + case 5: + m_ddr_c = data; + + if (!INTERRUPT_MODE) + m_out_pc_cb((offs_t)0, (m_port_c & m_ddr_c) | (m_ddr_c ^ 0xff)); + break; + + case 6: + m_cr = data; + + if (INTERRUPT_MODE) + { + if (CA_MANUAL_OUT) + { + if (m_ca_level != CA_MANUAL_LEVEL) + { + m_ca_level = CA_MANUAL_LEVEL; + m_out_ca_cb(m_ca_level); + } + } + if (CB_MANUAL_OUT) + { + if (m_cb_level != CB_MANUAL_LEVEL) + { + m_cb_level = CB_MANUAL_LEVEL; + m_out_cb_cb(m_cb_level); + } + } + } + + break; + + case 7: + /* m_air = data; */ + break; + } +} + +void tpi6525_device::port_line_w(UINT8 &port, int line, int state) +{ + port &= ~(1 << line); + port |= state << line; +} + +/* this should probably be done better, needed for amigacd.c */ + +UINT8 tpi6525_device::get_ddr_a() +{ + return m_ddr_a; +} + +UINT8 tpi6525_device::get_ddr_b() +{ + return m_ddr_b; +} + +UINT8 tpi6525_device::get_ddr_c() +{ + return m_ddr_c; +} diff --git a/src/devices/machine/6525tpi.h b/src/devices/machine/6525tpi.h new file mode 100644 index 00000000000..5a2e07d12dd --- /dev/null +++ b/src/devices/machine/6525tpi.h @@ -0,0 +1,154 @@ +// license:BSD-3-Clause +// copyright-holders:Peter Trauner +/***************************************************************************** + * + * machine/tpi6525.h + * + * mos tri port interface 6525 + * mos triple interface adapter 6523 + * + * peter.trauner@jk.uni-linz.ac.at + * + * used in commodore b series + * used in commodore c1551 floppy disk drive + * + * tia6523 is a tpi6525 without control register!? + * + * tia6523 + * only some lines of port b and c are in the pinout! + * + * connector to floppy c1551 (delivered with c1551 as c16 expansion) + * port a for data read/write + * port b + * 0 status 0 + * 1 status 1 + * port c + * 6 dav output edge data on port a available + * 7 ack input edge ready for next datum + * + ****************************************************************************/ + +#ifndef __TPI6525_H__ +#define __TPI6525_H__ + + +/*************************************************************************** + DEVICE CONFIGURATION MACROS +***************************************************************************/ + +class tpi6525_device : public device_t +{ +public: + tpi6525_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + ~tpi6525_device() {} + + template static devcb_base &set_out_irq_callback(device_t &device, _Object object) { return downcast(device).m_out_irq_cb.set_callback(object); } + template static devcb_base &set_in_pa_callback(device_t &device, _Object object) { return downcast(device).m_in_pa_cb.set_callback(object); } + template static devcb_base &set_out_pa_callback(device_t &device, _Object object) { return downcast(device).m_out_pa_cb.set_callback(object); } + template static devcb_base &set_in_pb_callback(device_t &device, _Object object) { return downcast(device).m_in_pb_cb.set_callback(object); } + template static devcb_base &set_out_pb_callback(device_t &device, _Object object) { return downcast(device).m_out_pb_cb.set_callback(object); } + template static devcb_base &set_in_pc_callback(device_t &device, _Object object) { return downcast(device).m_in_pc_cb.set_callback(object); } + template static devcb_base &set_out_pc_callback(device_t &device, _Object object) { return downcast(device).m_out_pc_cb.set_callback(object); } + template static devcb_base &set_out_ca_callback(device_t &device, _Object object) { return downcast(device).m_out_ca_cb.set_callback(object); } + template static devcb_base &set_out_cb_callback(device_t &device, _Object object) { return downcast(device).m_out_cb_cb.set_callback(object); } + + DECLARE_READ8_MEMBER( read ); + DECLARE_WRITE8_MEMBER( write ); + + DECLARE_WRITE_LINE_MEMBER( i0_w ); + DECLARE_WRITE_LINE_MEMBER( i1_w ); + DECLARE_WRITE_LINE_MEMBER( i2_w ); + DECLARE_WRITE_LINE_MEMBER( i3_w ); + DECLARE_WRITE_LINE_MEMBER( i4_w ); + + DECLARE_READ8_MEMBER( pa_r ); + DECLARE_READ8_MEMBER( pb_r ); + DECLARE_READ8_MEMBER( pc_r ); + DECLARE_WRITE8_MEMBER( pa_w ); + DECLARE_WRITE8_MEMBER( pb_w ); + DECLARE_WRITE8_MEMBER( pc_w ); + + WRITE_LINE_MEMBER( pb0_w ) { port_line_w(m_in_b, 0, state); } + WRITE_LINE_MEMBER( pb1_w ) { port_line_w(m_in_b, 1, state); } + WRITE_LINE_MEMBER( pb2_w ) { port_line_w(m_in_b, 2, state); } + WRITE_LINE_MEMBER( pb3_w ) { port_line_w(m_in_b, 3, state); } + WRITE_LINE_MEMBER( pb4_w ) { port_line_w(m_in_b, 4, state); } + WRITE_LINE_MEMBER( pb5_w ) { port_line_w(m_in_b, 5, state); } + WRITE_LINE_MEMBER( pb6_w ) { port_line_w(m_in_b, 6, state); } + WRITE_LINE_MEMBER( pb7_w ) { port_line_w(m_in_b, 7, state); } + + UINT8 get_ddr_a(); + UINT8 get_ddr_b(); + UINT8 get_ddr_c(); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + +private: + // internal state + devcb_write_line m_out_irq_cb; + + devcb_read8 m_in_pa_cb; + devcb_write8 m_out_pa_cb; + + devcb_read8 m_in_pb_cb; + devcb_write8 m_out_pb_cb; + + devcb_read8 m_in_pc_cb; + devcb_write8 m_out_pc_cb; + + devcb_write_line m_out_ca_cb; + devcb_write_line m_out_cb_cb; + + UINT8 m_port_a, m_ddr_a, m_in_a; + UINT8 m_port_b, m_ddr_b, m_in_b; + UINT8 m_port_c, m_ddr_c, m_in_c; + + UINT8 m_ca_level, m_cb_level, m_interrupt_level; + + UINT8 m_cr; + UINT8 m_air; + + UINT8 m_irq_level[5]; + + void set_interrupt(); + void clear_interrupt(); + + // helper function to write a single line + static void port_line_w(UINT8 &port, int line, int state); +}; + +extern const device_type TPI6525; + + +#define MCFG_TPI6525_OUT_IRQ_CB(_devcb) \ + devcb = &tpi6525_device::set_out_irq_callback(*device, DEVCB_##_devcb); + +#define MCFG_TPI6525_IN_PA_CB(_devcb) \ + devcb = &tpi6525_device::set_in_pa_callback(*device, DEVCB_##_devcb); + +#define MCFG_TPI6525_OUT_PA_CB(_devcb) \ + devcb = &tpi6525_device::set_out_pa_callback(*device, DEVCB_##_devcb); + +#define MCFG_TPI6525_IN_PB_CB(_devcb) \ + devcb = &tpi6525_device::set_in_pb_callback(*device, DEVCB_##_devcb); + +#define MCFG_TPI6525_OUT_PB_CB(_devcb) \ + devcb = &tpi6525_device::set_out_pb_callback(*device, DEVCB_##_devcb); + +#define MCFG_TPI6525_IN_PC_CB(_devcb) \ + devcb = &tpi6525_device::set_in_pc_callback(*device, DEVCB_##_devcb); + +#define MCFG_TPI6525_OUT_PC_CB(_devcb) \ + devcb = &tpi6525_device::set_out_pc_callback(*device, DEVCB_##_devcb); + +#define MCFG_TPI6525_OUT_CA_CB(_devcb) \ + devcb = &tpi6525_device::set_out_ca_callback(*device, DEVCB_##_devcb); + +#define MCFG_TPI6525_OUT_CB_CB(_devcb) \ + devcb = &tpi6525_device::set_out_cb_callback(*device, DEVCB_##_devcb); + + +#endif /* __TPI6525_H__ */ diff --git a/src/devices/machine/6532riot.c b/src/devices/machine/6532riot.c new file mode 100644 index 00000000000..98bb8c2dacc --- /dev/null +++ b/src/devices/machine/6532riot.c @@ -0,0 +1,483 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + RIOT 6532 emulation + +The timer seems to follow these rules: +- When the timer flag changes from 0 to 1 the timer continues to count + down at a 1 cycle rate. +- When the timer is being read or written the timer flag is reset. +- When the timer flag is set and the timer contents are 0, the counting + stops. + +***************************************************************************/ + +#include "emu.h" +#include "6532riot.h" + + +//************************************************************************** +// CONSTANTS +//************************************************************************** + +// device type definition +const device_type RIOT6532 = &device_creator; + +enum +{ + TIMER_IDLE, + TIMER_COUNTING, + TIMER_FINISHING +}; + +#define TIMER_FLAG 0x80 +#define PA7_FLAG 0x40 + + + +/*************************************************************************** + INTERNAL FUNCTIONS +***************************************************************************/ + +/*------------------------------------------------- + update_irqstate - update the IRQ state + based on interrupt enables +-------------------------------------------------*/ + +void riot6532_device::update_irqstate() +{ + int irq = (m_irqstate & m_irqenable) ? ASSERT_LINE : CLEAR_LINE; + + if (m_irq != irq) + { + m_irq_cb(irq); + m_irq = irq; + } +} + + +/*------------------------------------------------- + apply_ddr - combine inputs and outputs + according to the DDR +-------------------------------------------------*/ + +UINT8 riot6532_device::apply_ddr(const riot6532_port *port) +{ + return (port->m_out & port->m_ddr) | (port->m_in & ~port->m_ddr); +} + + +/*------------------------------------------------- + update_pa7_state - see if PA7 has changed + and signal appropriately +-------------------------------------------------*/ + +void riot6532_device::update_pa7_state() +{ + UINT8 data = apply_ddr(&m_port[0]) & 0x80; + + /* if the state changed in the correct direction, set the PA7 flag and update IRQs */ + if ((m_pa7prev ^ data) && (m_pa7dir ^ data) == 0) + { + m_irqstate |= PA7_FLAG; + update_irqstate(); + } + m_pa7prev = data; +} + + +/*------------------------------------------------- + get_timer - return the current timer value +-------------------------------------------------*/ + +UINT8 riot6532_device::get_timer() +{ + /* if idle, return 0 */ + if (m_timerstate == TIMER_IDLE) + { + return 0; + } + + /* if counting, return the number of ticks remaining */ + else if (m_timerstate == TIMER_COUNTING) + { + return m_timer->remaining().as_ticks(clock()) >> m_timershift; + } + + /* if finishing, return the number of ticks without the shift */ + else + { + return m_timer->remaining().as_ticks(clock()); + } +} + + + +void riot6532_device::timer_end() +{ + assert(m_timerstate != TIMER_IDLE); + + /* if we finished counting, switch to the finishing state */ + if(m_timerstate == TIMER_COUNTING) + { + m_timerstate = TIMER_FINISHING; + m_timer->adjust(attotime::from_ticks(256, clock())); + + /* signal timer IRQ as well */ + m_irqstate |= TIMER_FLAG; + update_irqstate(); + } + + /* if we finished finishing, keep spinning */ + else if (m_timerstate == TIMER_FINISHING) + { + m_timer->adjust(attotime::from_ticks(256, clock())); + } +} + + + +/*************************************************************************** + I/O ACCESS +***************************************************************************/ + +/*------------------------------------------------- + riot6532_w - master I/O write access +-------------------------------------------------*/ + +WRITE8_MEMBER( riot6532_device::write ) +{ + reg_w(offset, data); +} + +void riot6532_device::reg_w(UINT8 offset, UINT8 data) +{ + /* if A4 == 1 and A2 == 1, we are writing to the timer */ + if ((offset & 0x14) == 0x14) + { + static const UINT8 timershift[4] = { 0, 3, 6, 10 }; + attotime curtime = machine().time(); + INT64 target; + + /* A0-A1 contain the timer divisor */ + m_timershift = timershift[offset & 3]; + + /* A3 contains the timer IRQ enable */ + if (offset & 8) + m_irqenable |= TIMER_FLAG; + else + m_irqenable &= ~TIMER_FLAG; + + /* writes here clear the timer flag */ + if (m_timerstate != TIMER_FINISHING || get_timer() != 0xff) + { + m_irqstate &= ~TIMER_FLAG; + } + update_irqstate(); + + /* update the timer */ + m_timerstate = TIMER_COUNTING; + target = curtime.as_ticks(clock()) + 1 + (data << m_timershift); + m_timer->adjust(attotime::from_ticks(target, clock()) - curtime); + } + + /* if A4 == 0 and A2 == 1, we are writing to the edge detect control */ + else if ((offset & 0x14) == 0x04) + { + /* A1 contains the A7 IRQ enable */ + if (offset & 2) + { + m_irqenable |= PA7_FLAG; + } + else + { + m_irqenable &= ~PA7_FLAG; + } + + /* A0 specifies the edge detect direction: 0=negative, 1=positive */ + m_pa7dir = (offset & 1) << 7; + } + + /* if A4 == anything and A2 == 0, we are writing to the I/O section */ + else + { + /* A1 selects the port */ + riot6532_port *port = &m_port[BIT(offset, 1)]; + + /* if A0 == 1, we are writing to the port's DDR */ + if (offset & 1) + { + port->m_ddr = data; + } + + /* if A0 == 0, we are writing to the port's output */ + else + { + port->m_out = data; + (*port->m_out_cb)((offs_t)0, data); + } + + /* writes to port A need to update the PA7 state */ + if (port == &m_port[0]) + { + update_pa7_state(); + } + } +} + + +/*------------------------------------------------- + riot6532_r - master I/O read access +-------------------------------------------------*/ + +READ8_MEMBER( riot6532_device::read ) +{ + return reg_r(offset, space.debugger_access()); +} + +UINT8 riot6532_device::reg_r(UINT8 offset, bool debugger_access) +{ + UINT8 val = 0; + + /* if A2 == 1 and A0 == 1, we are reading interrupt flags */ + if ((offset & 0x05) == 0x05) + { + val = m_irqstate; + + if ( ! debugger_access ) + { + /* implicitly clears the PA7 flag */ + m_irqstate &= ~PA7_FLAG; + update_irqstate(); + } + } + + /* if A2 == 1 and A0 == 0, we are reading the timer */ + else if ((offset & 0x05) == 0x04) + { + val = get_timer(); + + if ( ! debugger_access ) + { + /* A3 contains the timer IRQ enable */ + if (offset & 8) + { + m_irqenable |= TIMER_FLAG; + } + else + { + m_irqenable &= ~TIMER_FLAG; + } + + /* implicitly clears the timer flag */ + if (m_timerstate != TIMER_FINISHING || val != 0xff) + { + m_irqstate &= ~TIMER_FLAG; + } + update_irqstate(); + } + } + + /* if A2 == 0 and A0 == anything, we are reading from ports */ + else + { + /* A1 selects the port */ + riot6532_port *port = &m_port[BIT(offset, 1)]; + + /* if A0 == 1, we are reading the port's DDR */ + if (offset & 1) + { + val = port->m_ddr; + } + + /* if A0 == 0, we are reading the port as an input */ + else + { + /* call the input callback if it exists */ + if (!(*port->m_in_cb).isnull()) + { + port->m_in = (*port->m_in_cb)(0); + + /* changes to port A need to update the PA7 state */ + if (port == &m_port[0]) + { + if (!debugger_access) + { + update_pa7_state(); + } + } + } + + /* apply the DDR to the result */ + val = apply_ddr(port); + } + } + return val; +} + + +/*------------------------------------------------- + porta_in_set - set port A input value +-------------------------------------------------*/ + +void riot6532_device::porta_in_set(UINT8 data, UINT8 mask) +{ + m_port[0].m_in = (m_port[0].m_in & ~mask) | (data & mask); + update_pa7_state(); +} + + +/*------------------------------------------------- + portb_in_set - set port B input value +-------------------------------------------------*/ + +void riot6532_device::portb_in_set(UINT8 data, UINT8 mask) +{ + m_port[1].m_in = (m_port[1].m_in & ~mask) | (data & mask); +} + + +/*------------------------------------------------- + porta_in_get - return port A input value +-------------------------------------------------*/ + +UINT8 riot6532_device::porta_in_get() +{ + return m_port[0].m_in; +} + + +/*------------------------------------------------- + portb_in_get - return port B input value +-------------------------------------------------*/ + +UINT8 riot6532_device::portb_in_get() +{ + return m_port[1].m_in; +} + + +/*------------------------------------------------- + porta_in_get - return port A output value +-------------------------------------------------*/ + +UINT8 riot6532_device::porta_out_get() +{ + return m_port[0].m_out; +} + + +/*------------------------------------------------- + portb_in_get - return port B output value +-------------------------------------------------*/ + +UINT8 riot6532_device::portb_out_get() +{ + return m_port[1].m_out; +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// riot6532_device - constructor +//------------------------------------------------- + +riot6532_device::riot6532_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, RIOT6532, "6532 RIOT", tag, owner, clock, "riot6532", __FILE__), + m_in_pa_cb(*this), + m_out_pa_cb(*this), + m_in_pb_cb(*this), + m_out_pb_cb(*this), + m_irq_cb(*this), + m_irq(CLEAR_LINE), + m_pa7dir(0), + m_pa7prev(0) +{ + memset(m_port, 0x00, sizeof(m_port)); +} + +/*------------------------------------------------- + device_start - device-specific startup +-------------------------------------------------*/ + +void riot6532_device::device_start() +{ + /* resolve callbacks */ + m_in_pa_cb.resolve(); + m_port[0].m_in_cb = &m_in_pa_cb; + m_out_pa_cb.resolve_safe(); + m_port[0].m_out_cb = &m_out_pa_cb; + m_in_pb_cb.resolve(); + m_port[1].m_in_cb = &m_in_pb_cb; + m_out_pb_cb.resolve_safe(); + m_port[1].m_out_cb = &m_out_pb_cb; + m_irq_cb.resolve_safe(); + + /* allocate timers */ + m_timer = timer_alloc(TIMER_END_CB); + + /* register for save states */ + save_item(NAME(m_port[0].m_in)); + save_item(NAME(m_port[0].m_out)); + save_item(NAME(m_port[0].m_ddr)); + save_item(NAME(m_port[1].m_in)); + save_item(NAME(m_port[1].m_out)); + save_item(NAME(m_port[1].m_ddr)); + + save_item(NAME(m_irqstate)); + save_item(NAME(m_irqenable)); + save_item(NAME(m_irq)); + + save_item(NAME(m_pa7dir)); + save_item(NAME(m_pa7prev)); + + save_item(NAME(m_timershift)); + save_item(NAME(m_timerstate)); +} + + + +/*------------------------------------------------- + device_reset - device-specific reset +-------------------------------------------------*/ + +void riot6532_device::device_reset() +{ + /* reset I/O states */ + m_port[0].m_in = 0; + m_port[0].m_out = 0; + m_port[0].m_ddr = 0; + m_port[1].m_in = 0; + m_port[1].m_out = 0; + m_port[1].m_ddr = 0; + + /* reset IRQ states */ + m_irqenable = 0; + m_irqstate = 0; + update_irqstate(); + + /* reset PA7 states */ + m_pa7dir = 0; + m_pa7prev = 0; + + /* reset timer states */ + m_timershift = 10; + m_timerstate = TIMER_COUNTING; + m_timer->adjust(attotime::from_ticks(256 << m_timershift, clock())); +} + +void riot6532_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch (id) + { + case TIMER_END_CB: + timer_end(); + break; + default: + assert_always(FALSE, "Unknown id in riot6532_device::device_timer"); + } +} diff --git a/src/devices/machine/6532riot.h b/src/devices/machine/6532riot.h new file mode 100644 index 00000000000..2825f31dc9d --- /dev/null +++ b/src/devices/machine/6532riot.h @@ -0,0 +1,127 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + RIOT 6532 emulation + +***************************************************************************/ + +#pragma once + +#ifndef __RIOT6532_H__ +#define __RIOT6532_H__ + +#include "emu.h" + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_RIOT6532_IN_PA_CB(_devcb) \ + devcb = &riot6532_device::set_in_pa_callback(*device, DEVCB_##_devcb); + +#define MCFG_RIOT6532_OUT_PA_CB(_devcb) \ + devcb = &riot6532_device::set_out_pa_callback(*device, DEVCB_##_devcb); + +#define MCFG_RIOT6532_IN_PB_CB(_devcb) \ + devcb = &riot6532_device::set_in_pb_callback(*device, DEVCB_##_devcb); + +#define MCFG_RIOT6532_OUT_PB_CB(_devcb) \ + devcb = &riot6532_device::set_out_pb_callback(*device, DEVCB_##_devcb); + +#define MCFG_RIOT6532_IRQ_CB(_devcb) \ + devcb = &riot6532_device::set_irq_callback(*device, DEVCB_##_devcb); + + +/*************************************************************************** + TYPE DEFINITIONS +***************************************************************************/ + + +// ======================> riot6532_device + +class riot6532_device : public device_t +{ +public: + // construction/destruction + riot6532_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + template static devcb_base &set_in_pa_callback(device_t &device, _Object object) { return downcast(device).m_in_pa_cb.set_callback(object); } + template static devcb_base &set_out_pa_callback(device_t &device, _Object object) { return downcast(device).m_out_pa_cb.set_callback(object); } + template static devcb_base &set_in_pb_callback(device_t &device, _Object object) { return downcast(device).m_in_pb_cb.set_callback(object); } + template static devcb_base &set_out_pb_callback(device_t &device, _Object object) { return downcast(device).m_out_pb_cb.set_callback(object); } + template static devcb_base &set_irq_callback(device_t &device, _Object object) { return downcast(device).m_irq_cb.set_callback(object); } + + DECLARE_READ8_MEMBER( read ); + DECLARE_WRITE8_MEMBER( write ); + + UINT8 reg_r(UINT8 offset, bool debugger_access = false); + void reg_w(UINT8 offset, UINT8 data); + + void porta_in_set(UINT8 data, UINT8 mask); + void portb_in_set(UINT8 data, UINT8 mask); + + UINT8 porta_in_get(); + UINT8 portb_in_get(); + + UINT8 porta_out_get(); + UINT8 portb_out_get(); + + void timer_end(); + +protected: + class riot6532_port + { + public: + UINT8 m_in; + UINT8 m_out; + UINT8 m_ddr; + devcb_read8 *m_in_cb; + devcb_write8 *m_out_cb; + }; + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + virtual void device_post_load() { } + virtual void device_clock_changed() { } + + +private: + void update_irqstate(); + UINT8 apply_ddr(const riot6532_port *port); + void update_pa7_state(); + UINT8 get_timer(); + + riot6532_port m_port[2]; + + devcb_read8 m_in_pa_cb; + devcb_write8 m_out_pa_cb; + devcb_read8 m_in_pb_cb; + devcb_write8 m_out_pb_cb; + devcb_write_line m_irq_cb; + + UINT8 m_irqstate; + UINT8 m_irqenable; + int m_irq; + + UINT8 m_pa7dir; /* 0x80 = high-to-low, 0x00 = low-to-high */ + UINT8 m_pa7prev; + + UINT8 m_timershift; + UINT8 m_timerstate; + emu_timer * m_timer; + + enum + { + TIMER_END_CB + }; +}; + + +// device type definition +extern const device_type RIOT6532; + +#endif diff --git a/src/devices/machine/6821pia.c b/src/devices/machine/6821pia.c new file mode 100644 index 00000000000..3fbf6477fa9 --- /dev/null +++ b/src/devices/machine/6821pia.c @@ -0,0 +1,1121 @@ +// license:BSD-3-Clause +// copyright-holders:Nathan Woods +/********************************************************************** + + Motorola 6821 PIA interface and emulation + +**********************************************************************/ + +#include "emu.h" +#include "6821pia.h" + + +//************************************************************************** +// MACROS +//************************************************************************** + +#define VERBOSE 1 + +#define LOG(x) do { if (VERBOSE) logerror x; } while (0) + +#define PIA_IRQ1 (0x80) +#define PIA_IRQ2 (0x40) + +#define IRQ1_ENABLED(c) ( (((c) >> 0) & 0x01)) +#define C1_LOW_TO_HIGH(c) ( (((c) >> 1) & 0x01)) +#define C1_HIGH_TO_LOW(c) (!(((c) >> 1) & 0x01)) +#define OUTPUT_SELECTED(c) ( (((c) >> 2) & 0x01)) +#define IRQ2_ENABLED(c) ( (((c) >> 3) & 0x01)) +#define STROBE_E_RESET(c) ( (((c) >> 3) & 0x01)) +#define STROBE_C1_RESET(c) (!(((c) >> 3) & 0x01)) +#define C2_SET(c) ( (((c) >> 3) & 0x01)) +#define C2_LOW_TO_HIGH(c) ( (((c) >> 4) & 0x01)) +#define C2_HIGH_TO_LOW(c) (!(((c) >> 4) & 0x01)) +#define C2_SET_MODE(c) ( (((c) >> 4) & 0x01)) +#define C2_STROBE_MODE(c) (!(((c) >> 4) & 0x01)) +#define C2_OUTPUT(c) ( (((c) >> 5) & 0x01)) +#define C2_INPUT(c) (!(((c) >> 5) & 0x01)) + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +// device type definition +const device_type PIA6821 = &device_creator; + + +//------------------------------------------------- +// pia6821_device - constructor +//------------------------------------------------- + +pia6821_device::pia6821_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, PIA6821, "6821 PIA", tag, owner, clock, "pia6821", __FILE__), + m_in_a_handler(*this), + m_in_b_handler(*this), + m_in_ca1_handler(*this), + m_in_cb1_handler(*this), + m_in_ca2_handler(*this), + m_out_a_handler(*this), + m_out_b_handler(*this), + m_ca2_handler(*this), + m_cb2_handler(*this), + m_irqa_handler(*this), + m_irqb_handler(*this), + m_in_ca1(0), + m_ctl_a(0), + m_irq_a_state(0), + m_in_cb1(0), + m_ctl_b(0), + m_irq_b_state(0) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void pia6821_device::device_start() +{ + // resolve callbacks + m_in_a_handler.resolve(); + m_in_b_handler.resolve(); + m_in_ca1_handler.resolve(); + m_in_cb1_handler.resolve(); + m_in_ca2_handler.resolve(); + m_out_a_handler.resolve(); + m_out_b_handler.resolve(); + m_ca2_handler.resolve(); + m_cb2_handler.resolve(); + m_irqa_handler.resolve_safe(); + m_irqb_handler.resolve_safe(); + + save_item(NAME(m_in_a)); + save_item(NAME(m_in_ca1)); + save_item(NAME(m_in_ca2)); + save_item(NAME(m_out_a)); + save_item(NAME(m_out_ca2)); + save_item(NAME(m_port_a_z_mask)); + save_item(NAME(m_ddr_a)); + save_item(NAME(m_ctl_a)); + save_item(NAME(m_irq_a1)); + save_item(NAME(m_irq_a2)); + save_item(NAME(m_irq_a_state)); + save_item(NAME(m_in_b)); + save_item(NAME(m_in_cb1)); + save_item(NAME(m_in_cb2)); + save_item(NAME(m_out_b)); + save_item(NAME(m_out_cb2)); + save_item(NAME(m_last_out_cb2_z)); + save_item(NAME(m_ddr_b)); + save_item(NAME(m_ctl_b)); + save_item(NAME(m_irq_b1)); + save_item(NAME(m_irq_b2)); + save_item(NAME(m_irq_b_state)); + save_item(NAME(m_in_a_pushed)); + save_item(NAME(m_out_a_needs_pulled)); + save_item(NAME(m_in_ca1_pushed)); + save_item(NAME(m_in_ca2_pushed)); + save_item(NAME(m_out_ca2_needs_pulled)); + save_item(NAME(m_in_b_pushed)); + save_item(NAME(m_out_b_needs_pulled)); + save_item(NAME(m_in_cb1_pushed)); + save_item(NAME(m_in_cb2_pushed)); + save_item(NAME(m_out_cb2_needs_pulled)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void pia6821_device::device_reset() +{ + // + // set default read values. + // + // ports A,CA1,CA2 default to 1 + // ports B,CB1,CB2 are three-state and undefined (set to 0) + // + m_in_a = 0xff; + m_in_ca1 = TRUE; + m_in_ca2 = TRUE; + m_out_a = 0; + m_out_ca2 = 0; + m_port_a_z_mask = 0; + m_ddr_a = 0; + m_ctl_a = 0; + m_irq_a1 = 0; + m_irq_a2 = 0; + m_irq_a_state = 0; + m_in_b = 0; + m_in_cb1 = 0; + m_in_cb2 = 0; + m_out_b = 0; + m_out_cb2 = 0; + m_last_out_cb2_z = 0; + m_ddr_b = 0; + m_ctl_b = 0; + m_irq_b1 = 0; + m_irq_b2 = 0; + m_irq_b_state = 0; + m_in_a_pushed = false; + m_out_a_needs_pulled = false; + m_in_ca1_pushed = false; + m_in_ca2_pushed = false; + m_out_ca2_needs_pulled = false; + m_in_b_pushed = false; + m_out_b_needs_pulled = false; + m_in_cb1_pushed = false; + m_in_cb2_pushed = false; + m_out_cb2_needs_pulled = false; + m_logged_port_a_not_connected = false; + m_logged_port_b_not_connected = false; + m_logged_ca1_not_connected = false; + m_logged_ca2_not_connected = false; + m_logged_cb1_not_connected = false; + m_logged_cb2_not_connected = false; + + + // clear the IRQs + m_irqa_handler(FALSE); + m_irqb_handler(FALSE); +} + + +//------------------------------------------------- +// update_interrupts +//------------------------------------------------- + +void pia6821_device::update_interrupts() +{ + // start with IRQ A + int new_state = (m_irq_a1 && IRQ1_ENABLED(m_ctl_a)) || (m_irq_a2 && IRQ2_ENABLED(m_ctl_a)); + + if (new_state != m_irq_a_state) + { + m_irq_a_state = new_state; + m_irqa_handler(m_irq_a_state); + } + + // then do IRQ B + new_state = (m_irq_b1 && IRQ1_ENABLED(m_ctl_b)) || (m_irq_b2 && IRQ2_ENABLED(m_ctl_b)); + + if (new_state != m_irq_b_state) + { + m_irq_b_state = new_state; + m_irqb_handler(m_irq_b_state); + } +} + + +//------------------------------------------------- +// get_in_a_value +//------------------------------------------------- + +UINT8 pia6821_device::get_in_a_value() +{ + UINT8 port_a_data = 0; + UINT8 ret; + + // update the input + if (!m_in_a_handler.isnull()) + { + port_a_data = m_in_a_handler(0); + } + else + { + if (m_in_a_pushed) + { + port_a_data = m_in_a; + } + else + { + // mark all pins disconnected + m_port_a_z_mask = 0xff; + + if (!m_logged_port_a_not_connected && (m_ddr_a != 0xff)) + { + logerror("PIA #%s: Warning! No port A read handler. Assuming pins 0x%02X not connected\n", tag(), m_ddr_a ^ 0xff); + m_logged_port_a_not_connected = true; + } + } + } + + // - connected pins are always read + // - disconnected pins read the output buffer in output mode + // - disconnected pins are HI in input mode + ret = (~m_port_a_z_mask & port_a_data) | + ( m_port_a_z_mask & m_ddr_a & m_out_a) | + ( m_port_a_z_mask & ~m_ddr_a); + + return ret; +} + + +//------------------------------------------------- +// get_in_b_value +//------------------------------------------------- + +UINT8 pia6821_device::get_in_b_value() +{ + UINT8 ret; + + if (m_ddr_b == 0xff) + { + // all output, just return buffer + ret = m_out_b; + } + else + { + UINT8 port_b_data; + + // update the input + if (!m_in_b_handler.isnull()) + { + port_b_data = m_in_b_handler(0); + } + else + { + if (m_in_b_pushed) + { + port_b_data = m_in_b; + } + else + { + if (!m_logged_port_b_not_connected && (m_ddr_b != 0xff)) + { + logerror("PIA #%s: Error! No port B read handler. Three-state pins 0x%02X are undefined\n", tag(), m_ddr_b ^ 0xff); + m_logged_port_b_not_connected = true; + } + + // undefined -- need to return something + port_b_data = 0x00; + } + } + + // the DDR determines if the pin or the output buffer is read + ret = (m_out_b & m_ddr_b) | (port_b_data & ~m_ddr_b); + } + + return ret; +} + + +//------------------------------------------------- +// get_out_a_value +//------------------------------------------------- + +UINT8 pia6821_device::get_out_a_value() +{ + UINT8 ret; + + if (m_ddr_a == 0xff) + { + // all output + ret = m_out_a; + } + else + { + // input pins don't change + ret = (m_out_a & m_ddr_a) | (get_in_a_value() & ~m_ddr_a); + } + + return ret; +} + + +//------------------------------------------------- +// get_out_b_value +//------------------------------------------------- + +UINT8 pia6821_device::get_out_b_value() +{ + // input pins are high-impedance - we just send them as zeros for backwards compatibility + return m_out_b & m_ddr_b; +} + + +//------------------------------------------------- +// set_out_ca2 +//------------------------------------------------- + +void pia6821_device::set_out_ca2(int data) +{ + if (data != m_out_ca2) + { + m_out_ca2 = data; + + // send to output function + if (!m_ca2_handler.isnull()) + { + m_ca2_handler(m_out_ca2); + } + else + { + if (m_out_ca2_needs_pulled) + { + logerror("PIA #%s: Warning! No port CA2 write handler. Previous value has been lost!\n", tag()); + } + + m_out_ca2_needs_pulled = true; + } + } +} + + +//------------------------------------------------- +// set_out_cb2 +//------------------------------------------------- + +void pia6821_device::set_out_cb2(int data) +{ + int z = cb2_output_z(); + + if ((data != m_out_cb2) || (z != m_last_out_cb2_z)) + { + m_out_cb2 = data; + m_last_out_cb2_z = z; + + // send to output function + if (!m_cb2_handler.isnull()) + { + m_cb2_handler(m_out_cb2); + } + else + { + if (m_out_cb2_needs_pulled) + { + logerror("PIA #%s: Warning! No port CB2 write handler. Previous value has been lost!\n", tag()); + } + + m_out_cb2_needs_pulled = true; + } + } +} + + +//------------------------------------------------- +// port_a_r +//------------------------------------------------- + +UINT8 pia6821_device::port_a_r() +{ + UINT8 ret = get_in_a_value(); + + // IRQ flags implicitly cleared by a read + m_irq_a1 = FALSE; + m_irq_a2 = FALSE; + update_interrupts(); + + // CA2 is configured as output and in read strobe mode + if(C2_OUTPUT(m_ctl_a) && C2_STROBE_MODE(m_ctl_a)) + { + // this will cause a transition low + set_out_ca2(FALSE); + + // if the CA2 strobe is cleared by the E, reset it right away + if(STROBE_E_RESET(m_ctl_a)) + { + set_out_ca2(TRUE); + } + } + + LOG(("PIA #%s: port A read = %02X\n", tag(), ret)); + + return ret; +} + + +//------------------------------------------------- +// ddr_a_r +//------------------------------------------------- + +UINT8 pia6821_device::ddr_a_r() +{ + UINT8 ret = m_ddr_a; + + LOG(("PIA #%s: DDR A read = %02X\n", tag(), ret)); + + return ret; +} + + +//------------------------------------------------- +// port_b_r +//------------------------------------------------- + +UINT8 pia6821_device::port_b_r() +{ + UINT8 ret = get_in_b_value(); + + // This read will implicitly clear the IRQ B1 flag. If CB2 is in write-strobe + // mode with CB1 restore, and a CB1 active transition set the flag, + // clearing it will cause CB2 to go high again. Note that this is different + // from what happens with port A. + if(m_irq_b1 && C2_STROBE_MODE(m_ctl_b) && STROBE_C1_RESET(m_ctl_b)) + { + set_out_cb2(TRUE); + } + + // IRQ flags implicitly cleared by a read + m_irq_b1 = FALSE; + m_irq_b2 = FALSE; + update_interrupts(); + + LOG(("PIA #%s: port B read = %02X\n", tag(), ret)); + + return ret; +} + + +//------------------------------------------------- +// ddr_b_r +//------------------------------------------------- + +UINT8 pia6821_device::ddr_b_r() +{ + UINT8 ret = m_ddr_b; + + LOG(("PIA #%s: DDR B read = %02X\n", tag(), ret)); + + return ret; +} + + +//------------------------------------------------- +// control_a_r +//------------------------------------------------- + +UINT8 pia6821_device::control_a_r() +{ + UINT8 ret; + + // update CA1 & CA2 if callback exists, these in turn may update IRQ's + if (!m_in_ca1_handler.isnull()) + { + ca1_w(m_in_ca1_handler()); + } + else if(!m_logged_ca1_not_connected && (!m_in_ca1_pushed)) + { + logerror("PIA #%s: Warning! No CA1 read handler. Assuming pin not connected\n", tag()); + m_logged_ca1_not_connected = true; + } + + if (!m_in_ca2_handler.isnull()) + { + ca2_w(m_in_ca2_handler()); + } + else if ( !m_logged_ca2_not_connected && C2_INPUT(m_ctl_a) && !m_in_ca2_pushed) + { + logerror("PIA #%s: Warning! No CA2 read handler. Assuming pin not connected\n", tag()); + m_logged_ca2_not_connected = true; + } + + // read control register + ret = m_ctl_a; + + // set the IRQ flags if we have pending IRQs + if(m_irq_a1) + { + ret |= PIA_IRQ1; + } + + if(m_irq_a2 && C2_INPUT(m_ctl_a)) + { + ret |= PIA_IRQ2; + } + + LOG(("PIA #%s: control A read = %02X\n", tag(), ret)); + + return ret; +} + + +//------------------------------------------------- +// control_b_r +//------------------------------------------------- + +UINT8 pia6821_device::control_b_r() +{ + UINT8 ret; + + // update CB1 & CB2 if callback exists, these in turn may update IRQ's + if(!m_in_cb1_handler.isnull()) + { + cb1_w(m_in_cb1_handler()); + } + else if(!m_logged_cb1_not_connected && !m_in_cb1_pushed) + { + logerror("PIA #%s: Error! no CB1 read handler. Three-state pin is undefined\n", tag()); + m_logged_cb1_not_connected = true; + } + + if(!m_logged_cb2_not_connected && C2_INPUT(m_ctl_b) && !m_in_cb2_pushed) + { + logerror("PIA #%s: Error! Three-state pin is undefined\n", tag()); + m_logged_cb2_not_connected = true; + } + + // read control register + ret = m_ctl_b; + + // set the IRQ flags if we have pending IRQs + if(m_irq_b1) + { + ret |= PIA_IRQ1; + } + + if(m_irq_b2 && C2_INPUT(m_ctl_b)) + { + ret |= PIA_IRQ2; + } + + LOG(("PIA #%s: control B read = %02X\n", tag(), ret)); + + return ret; +} + + +//------------------------------------------------- +// read +//------------------------------------------------- + +UINT8 pia6821_device::reg_r(UINT8 offset) +{ + UINT8 ret; + + switch (offset & 0x03) + { + default: // impossible + case 0x00: + if (OUTPUT_SELECTED(m_ctl_a)) + { + ret = port_a_r(); + } + else + { + ret = ddr_a_r(); + } + break; + + case 0x01: + ret = control_a_r(); + break; + + case 0x02: + if (OUTPUT_SELECTED(m_ctl_b)) + { + ret = port_b_r(); + } + else + { + ret = ddr_b_r(); + } + break; + + case 0x03: + ret = control_b_r(); + break; + } + + return ret; +} + + + +//------------------------------------------------- +// send_to_out_a_func +//------------------------------------------------- + +void pia6821_device::send_to_out_a_func(const char* message) +{ + // input pins are pulled high + UINT8 data = get_out_a_value(); + + LOG(("PIA #%s: %s = %02X\n", tag(), message, data)); + + if(!m_out_a_handler.isnull()) + { + m_out_a_handler((offs_t) 0, data); + } + else + { + if(m_out_a_needs_pulled) + { + logerror("PIA #%s: Warning! No port A write handler. Previous value has been lost!\n", tag()); + } + + m_out_a_needs_pulled = true; + } +} + + +//------------------------------------------------- +// send_to_out_b_func +//------------------------------------------------- + +void pia6821_device::send_to_out_b_func(const char* message) +{ + // input pins are high-impedance - we just send them as zeros for backwards compatibility + UINT8 data = get_out_b_value(); + + LOG(("PIA #%s: %s = %02X\n", tag(), message, data)); + + if(!m_out_b_handler.isnull()) + { + m_out_b_handler((offs_t)0, data); + } + else + { + if(m_out_b_needs_pulled) + { + logerror("PIA #%s: Warning! No port B write handler. Previous value has been lost!\n", tag()); + } + + m_out_b_needs_pulled = true; + } +} + + +//------------------------------------------------- +// port_a_w +//------------------------------------------------- + +void pia6821_device::port_a_w(UINT8 data) +{ + // buffer the output value + m_out_a = data; + + send_to_out_a_func("port A write"); +} + + +//------------------------------------------------- +// ddr_a_w +//------------------------------------------------- + +void pia6821_device::ddr_a_w(UINT8 data) +{ + if(data == 0x00) + { + LOG(("PIA #%s: DDR A write = %02X (input mode)\n", tag(), data)); + } + else if(data == 0xff) + { + LOG(("PIA #%s: DDR A write = %02X (output mode)\n", tag(), data)); + } + else + { + LOG(("PIA #%s: DDR A write = %02X (mixed mode)\n", tag(), data)); + } + + if(m_ddr_a != data) + { + // DDR changed, call the callback again + m_ddr_a = data; + m_logged_port_a_not_connected = false; + send_to_out_a_func("port A write due to DDR change"); + } +} + + +//------------------------------------------------- +// port_b_w +//------------------------------------------------- + +void pia6821_device::port_b_w(UINT8 data) +{ + // buffer the output value + m_out_b = data; + + send_to_out_b_func("port B write"); + + // CB2 in write strobe mode + if(C2_STROBE_MODE(m_ctl_b)) + { + // this will cause a transition low + set_out_cb2(FALSE); + + // if the CB2 strobe is cleared by the E, reset it right away + if(STROBE_E_RESET(m_ctl_b)) + { + set_out_cb2(TRUE); + } + } +} + + +//------------------------------------------------- +// ddr_b_w +//------------------------------------------------- + +void pia6821_device::ddr_b_w(UINT8 data) +{ + if (data == 0x00) + { + LOG(("PIA #%s: DDR B write = %02X (input mode)\n", tag(), data)); + } + else if (data == 0xff) + { + LOG(("PIA #%s: DDR B write = %02X (output mode)\n", tag(), data)); + } + else + { + LOG(("PIA #%s: DDR B write = %02X (mixed mode)\n", tag(), data)); + } + + if(m_ddr_b != data) + { + // DDR changed, call the callback again + m_ddr_b = data; + m_logged_port_b_not_connected = false; + send_to_out_b_func("port B write due to DDR change"); + } +} + + +//------------------------------------------------- +// control_a_w +//------------------------------------------------- + +void pia6821_device::control_a_w(UINT8 data) +{ + // bit 7 and 6 are read only + data &= 0x3f; + + LOG(("PIA #%s: control A write = %02X\n", tag(), data)); + + // update the control register + m_ctl_a = data; + + // CA2 is configured as output + if(C2_OUTPUT(m_ctl_a)) + { + int temp; + + if(C2_SET_MODE(m_ctl_a)) + { + // set/reset mode - bit value determines the new output + temp = C2_SET(m_ctl_a); + } + else + { + // strobe mode - output is always high unless strobed + temp = TRUE; + } + + set_out_ca2(temp); + } + + // update externals + update_interrupts(); +} + + +//------------------------------------------------- +// control_b_w +//------------------------------------------------- + +void pia6821_device::control_b_w(UINT8 data) +{ + int temp; + + // bit 7 and 6 are read only + data &= 0x3f; + + LOG(("PIA #%s: control B write = %02X\n", tag(), data)); + + // update the control register + m_ctl_b = data; + + if (C2_SET_MODE(m_ctl_b)) + { + // set/reset mode - bit value determines the new output + temp = C2_SET(m_ctl_b); + } + else + { + // strobe mode - output is always high unless strobed + temp = TRUE; + } + + set_out_cb2(temp); + + // update externals + update_interrupts(); +} + + +//------------------------------------------------- +// write +//------------------------------------------------- + +void pia6821_device::reg_w(UINT8 offset, UINT8 data) +{ + switch (offset & 0x03) + { + default: // impossible + case 0x00: + if (OUTPUT_SELECTED(m_ctl_a)) + { + port_a_w(data); + } + else + { + ddr_a_w(data); + } + break; + + case 0x01: + control_a_w( data); + break; + + case 0x02: + if(OUTPUT_SELECTED(m_ctl_b)) + { + port_b_w(data); + } + else + { + ddr_b_w(data); + } + break; + + case 0x03: + control_b_w(data); + break; + } +} + + +//------------------------------------------------- +// set_a_input +//------------------------------------------------- + +void pia6821_device::set_a_input(UINT8 data, UINT8 z_mask) +{ + assert_always(m_in_a_handler.isnull(), "pia6821_porta_w() called when in_a_func implemented"); + + LOG(("PIA #%s: set input port A = %02X\n", tag(), data)); + + m_in_a = data; + m_port_a_z_mask = z_mask; + m_in_a_pushed = true; +} + + +//------------------------------------------------- +// pia6821_porta_w +//------------------------------------------------- + +void pia6821_device::porta_w(UINT8 data) +{ + set_a_input(data, 0); +} + + +//------------------------------------------------- +// a_output +//------------------------------------------------- + +UINT8 pia6821_device::a_output() +{ + m_out_a_needs_pulled = false; + + return get_out_a_value(); +} + + +//------------------------------------------------- +// ca1_w +//------------------------------------------------- + +WRITE_LINE_MEMBER( pia6821_device::ca1_w ) +{ + LOG(("PIA #%s: set input CA1 = %d\n", tag(), state)); + + // the new state has caused a transition + if((m_in_ca1 != state) && ((state && C1_LOW_TO_HIGH(m_ctl_a)) || (!state && C1_HIGH_TO_LOW(m_ctl_a)))) + { + LOG(("PIA #%s: CA1 triggering\n", tag())); + + // mark the IRQ + m_irq_a1 = TRUE; + + // update externals + update_interrupts(); + + // CA2 is configured as output and in read strobe mode and cleared by a CA1 transition + if(C2_OUTPUT(m_ctl_a) && C2_STROBE_MODE(m_ctl_a) && STROBE_C1_RESET(m_ctl_a)) + { + set_out_ca2(TRUE); + } + } + + // set the new value for CA1 + m_in_ca1 = state; + m_in_ca1_pushed = true; +} + + +//------------------------------------------------- +// ca2_w +//------------------------------------------------- + +WRITE_LINE_MEMBER( pia6821_device::ca2_w ) +{ + LOG(("PIA #%s: set input CA2 = %d\n", tag(), state)); + + // if input mode and the new state has caused a transition + if(C2_INPUT(m_ctl_a) && (m_in_ca2 != state) && ((state && C2_LOW_TO_HIGH(m_ctl_a)) || (!state && C2_HIGH_TO_LOW(m_ctl_a)))) + { + LOG(("PIA #%s: CA2 triggering\n", tag())); + + // mark the IRQ + m_irq_a2 = TRUE; + + // update externals + update_interrupts(); + } + + // set the new value for CA2 + m_in_ca2 = state; + m_in_ca2_pushed = true; +} + + +//------------------------------------------------- +// ca2_output +//------------------------------------------------- + +int pia6821_device::ca2_output() +{ + m_out_ca2_needs_pulled = false; + + return m_out_ca2; +} + + +//------------------------------------------------- +// ca2_output_z - version of ca2_output which +// takes account of internal pullup resistor +//------------------------------------------------- + +int pia6821_device::ca2_output_z() +{ + m_out_ca2_needs_pulled = false; + + // If it's an output, output the bit, if it's an input, it's + // pulled up + return m_out_ca2 | C2_INPUT(m_ctl_a); +} + + +//------------------------------------------------- +// portb_w +//------------------------------------------------- + +void pia6821_device::portb_w(UINT8 data) +{ + assert_always(m_in_b_handler.isnull(), "pia_set_input_b() called when in_b_func implemented"); + + LOG(("PIA #%s: set input port B = %02X\n", tag(), data)); + + m_in_b = data; + m_in_b_pushed = true; +} + + +//------------------------------------------------- +// b_output +//------------------------------------------------- + +UINT8 pia6821_device::b_output() +{ + m_out_b_needs_pulled = false; + + return get_out_b_value(); +} + + +//------------------------------------------------- +// cb1_w +//------------------------------------------------- + +WRITE_LINE_MEMBER( pia6821_device::cb1_w ) +{ + LOG(("PIA #%s: set input CB1 = %d\n", tag(), state)); + + // the new state has caused a transition + if((m_in_cb1 != state) && ((state && C1_LOW_TO_HIGH(m_ctl_b)) || (!state && C1_HIGH_TO_LOW(m_ctl_b)))) + { + LOG(("PIA #%s: CB1 triggering\n", tag())); + + // mark the IRQ + m_irq_b1 = 1; + + // update externals + update_interrupts(); + + // If CB2 is configured as a write-strobe output which is reset by a CB1 + // transition, this reset will only happen when a read from port B implicitly + // clears the IRQ B1 flag. So we handle the CB2 reset there. Note that this + // is different from what happens with port A. + } + + // set the new value for CB1 + m_in_cb1 = state; + m_in_cb1_pushed = true; +} + + +//------------------------------------------------- +// cb2_w +//------------------------------------------------- + +WRITE_LINE_MEMBER( pia6821_device::cb2_w ) +{ + LOG(("PIA #%s: set input CB2 = %d\n", tag(), state)); + + // if input mode and the new state has caused a transition + if (C2_INPUT(m_ctl_b) && + (m_in_cb2 != state) && + ((state && C2_LOW_TO_HIGH(m_ctl_b)) || (!state && C2_HIGH_TO_LOW(m_ctl_b)))) + { + LOG(("PIA #%s: CB2 triggering\n", tag())); + + // mark the IRQ + m_irq_b2 = 1; + + // update externals + update_interrupts(); + } + + // set the new value for CA2 + m_in_cb2 = state; + m_in_cb2_pushed = true; +} + + +//------------------------------------------------- +// output_cb2 +//------------------------------------------------- + +int pia6821_device::cb2_output() +{ + m_out_cb2_needs_pulled = false; + + return m_out_cb2; +} + + +//------------------------------------------------- +// cb2_output_z +//------------------------------------------------- + +int pia6821_device::cb2_output_z() +{ + return !C2_OUTPUT(m_ctl_b); +} diff --git a/src/devices/machine/6821pia.h b/src/devices/machine/6821pia.h new file mode 100644 index 00000000000..cc686114feb --- /dev/null +++ b/src/devices/machine/6821pia.h @@ -0,0 +1,233 @@ +// license:BSD-3-Clause +// copyright-holders:Nathan Woods +/********************************************************************** + + Motorola 6821 PIA interface and emulation + + Notes: + * get_port_b_z_mask() gives the caller the bitmask that shows + which bits are high-impendance when reading port B, and thus + neither 0 or 1. get_output_cb2_z() returns the same info + for the CB2 pin. + * set_port_a_z_mask allows the input callback to indicate + which port A bits are disconnected. For these bits, the + read operation will return the output buffer's contents. + * The 'alt' interface functions are used when the A0 and A1 + address bits are swapped. + * All 'int' data or return values are bool, and should be + converted to bool at some point. + +**********************************************************************/ + +#pragma once + +#ifndef __6821PIA_H__ +#define __6821PIA_H__ + +#include "emu.h" + + + +/*************************************************************************** + DEVICE CONFIGURATION MACROS +***************************************************************************/ + +// TODO: REMOVE THESE +#define MCFG_PIA_READPA_HANDLER(_devcb) \ + devcb = &pia6821_device::set_readpa_handler(*device, DEVCB_##_devcb); + +#define MCFG_PIA_READPB_HANDLER(_devcb) \ + devcb = &pia6821_device::set_readpb_handler(*device, DEVCB_##_devcb); + +#define MCFG_PIA_READCA1_HANDLER(_devcb) \ + devcb = &pia6821_device::set_readca1_handler(*device, DEVCB_##_devcb); + +#define MCFG_PIA_READCA2_HANDLER(_devcb) \ + devcb = &pia6821_device::set_readca2_handler(*device, DEVCB_##_devcb); + +#define MCFG_PIA_READCB1_HANDLER(_devcb) \ + devcb = &pia6821_device::set_readcb1_handler(*device, DEVCB_##_devcb); + +// TODO: CONVERT THESE TO WRITE LINE +#define MCFG_PIA_WRITEPA_HANDLER(_devcb) \ + devcb = &pia6821_device::set_writepa_handler(*device, DEVCB_##_devcb); + +#define MCFG_PIA_WRITEPB_HANDLER(_devcb) \ + devcb = &pia6821_device::set_writepb_handler(*device, DEVCB_##_devcb); + +#define MCFG_PIA_CA2_HANDLER(_devcb) \ + devcb = &pia6821_device::set_ca2_handler(*device, DEVCB_##_devcb); + +#define MCFG_PIA_CB2_HANDLER(_devcb) \ + devcb = &pia6821_device::set_cb2_handler(*device, DEVCB_##_devcb); + +#define MCFG_PIA_IRQA_HANDLER(_devcb) \ + devcb = &pia6821_device::set_irqa_handler(*device, DEVCB_##_devcb); + +#define MCFG_PIA_IRQB_HANDLER(_devcb) \ + devcb = &pia6821_device::set_irqb_handler(*device, DEVCB_##_devcb); + + +/*************************************************************************** + TYPE DEFINITIONS +***************************************************************************/ + +// ======================> pia6821_device + +class pia6821_device : public device_t +{ +public: + // construction/destruction + pia6821_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // static configuration helpers + // TODO: REMOVE THESE + template static devcb_base &set_readpa_handler(device_t &device, _Object object) { return downcast(device).m_in_a_handler.set_callback(object); } + template static devcb_base &set_readpb_handler(device_t &device, _Object object) { return downcast(device).m_in_b_handler.set_callback(object); } + template static devcb_base &set_readca1_handler(device_t &device, _Object object) { return downcast(device).m_in_ca1_handler.set_callback(object); } + template static devcb_base &set_readca2_handler(device_t &device, _Object object) { return downcast(device).m_in_ca2_handler.set_callback(object); } + template static devcb_base &set_readcb1_handler(device_t &device, _Object object) { return downcast(device).m_in_cb1_handler.set_callback(object); } + + // TODO: CONVERT THESE TO WRITE LINE + template static devcb_base &set_writepa_handler(device_t &device, _Object object) { return downcast(device).m_out_a_handler.set_callback(object); } + template static devcb_base &set_writepb_handler(device_t &device, _Object object) { return downcast(device).m_out_b_handler.set_callback(object); } + + template static devcb_base &set_ca2_handler(device_t &device, _Object object) { return downcast(device).m_ca2_handler.set_callback(object); } + template static devcb_base &set_cb2_handler(device_t &device, _Object object) { return downcast(device).m_cb2_handler.set_callback(object); } + template static devcb_base &set_irqa_handler(device_t &device, _Object object) { return downcast(device).m_irqa_handler.set_callback(object); } + template static devcb_base &set_irqb_handler(device_t &device, _Object object) { return downcast(device).m_irqb_handler.set_callback(object); } + + DECLARE_READ8_MEMBER( read ) { return reg_r(offset); } + DECLARE_WRITE8_MEMBER( write ) { reg_w(offset, data); } + DECLARE_READ8_MEMBER( read_alt ) { return reg_r(((offset << 1) & 0x02) | ((offset >> 1) & 0x01)); } + DECLARE_WRITE8_MEMBER( write_alt ) { reg_w(((offset << 1) & 0x02) | ((offset >> 1) & 0x01), data); } + + UINT8 port_b_z_mask() const { return ~m_ddr_b; } // see first note in .c + void set_port_a_z_mask(UINT8 data) { m_port_a_z_mask = data; }// see second note in .c + + DECLARE_WRITE8_MEMBER( porta_w ) { porta_w(data); } + void porta_w(UINT8 data); + void set_a_input(UINT8 data, UINT8 z_mask); + UINT8 a_output(); + + DECLARE_WRITE_LINE_MEMBER( ca1_w ); + + DECLARE_WRITE_LINE_MEMBER( ca2_w ); + int ca2_output(); + int ca2_output_z(); + + DECLARE_WRITE8_MEMBER( portb_w ) { portb_w(data); } + void portb_w(UINT8 data); + UINT8 b_output(); + + DECLARE_WRITE_LINE_MEMBER( cb1_w ); + + DECLARE_WRITE_LINE_MEMBER( cb2_w ); + int cb2_output(); + int cb2_output_z(); + + int irq_a_state() const { return m_irq_a_state; } + int irq_b_state() const { return m_irq_b_state; } + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + +private: + UINT8 reg_r(UINT8 offset); + void reg_w(UINT8 offset, UINT8 data); + + void update_interrupts(); + + UINT8 get_in_a_value(); + UINT8 get_in_b_value(); + + UINT8 get_out_a_value(); + UINT8 get_out_b_value(); + + void set_out_ca2(int data); + void set_out_cb2(int data); + + UINT8 port_a_r(); + UINT8 ddr_a_r(); + UINT8 control_a_r(); + + UINT8 port_b_r(); + UINT8 ddr_b_r(); + UINT8 control_b_r(); + + void send_to_out_a_func(const char* message); + void send_to_out_b_func(const char* message); + + void port_a_w(UINT8 data); + void ddr_a_w(UINT8 data); + + void port_b_w(UINT8 data); + void ddr_b_w(UINT8 data); + + void control_a_w(UINT8 data); + void control_b_w(UINT8 data); + + devcb_read8 m_in_a_handler; + devcb_read8 m_in_b_handler; + devcb_read_line m_in_ca1_handler; + devcb_read_line m_in_cb1_handler; + devcb_read_line m_in_ca2_handler; + devcb_write8 m_out_a_handler; + devcb_write8 m_out_b_handler; + devcb_write_line m_ca2_handler; + devcb_write_line m_cb2_handler; + devcb_write_line m_irqa_handler; + devcb_write_line m_irqb_handler; + + UINT8 m_in_a; + UINT8 m_in_ca1; + UINT8 m_in_ca2; + UINT8 m_out_a; + UINT8 m_out_ca2; + UINT8 m_port_a_z_mask; + UINT8 m_ddr_a; + UINT8 m_ctl_a; + UINT8 m_irq_a1; + UINT8 m_irq_a2; + UINT8 m_irq_a_state; + + UINT8 m_in_b; + UINT8 m_in_cb1; + UINT8 m_in_cb2; + UINT8 m_out_b; + UINT8 m_out_cb2; + UINT8 m_last_out_cb2_z; + UINT8 m_ddr_b; + UINT8 m_ctl_b; + UINT8 m_irq_b1; + UINT8 m_irq_b2; + UINT8 m_irq_b_state; + + // variables that indicate if access a line externally - + // used to for logging purposes ONLY + bool m_in_a_pushed; + bool m_out_a_needs_pulled; + bool m_in_ca1_pushed; + bool m_in_ca2_pushed; + bool m_out_ca2_needs_pulled; + bool m_in_b_pushed; + bool m_out_b_needs_pulled; + bool m_in_cb1_pushed; + bool m_in_cb2_pushed; + bool m_out_cb2_needs_pulled; + bool m_logged_port_a_not_connected; + bool m_logged_port_b_not_connected; + bool m_logged_ca1_not_connected; + bool m_logged_ca2_not_connected; + bool m_logged_cb1_not_connected; + bool m_logged_cb2_not_connected; +}; + + +// device type definition +extern const device_type PIA6821; + + +#endif /* __6821PIA_H__ */ diff --git a/src/devices/machine/68230pit.c b/src/devices/machine/68230pit.c new file mode 100644 index 00000000000..46c8733f085 --- /dev/null +++ b/src/devices/machine/68230pit.c @@ -0,0 +1,265 @@ +// license:BSD-3-Clause +// copyright-holders:Joakim Larsson Edstr??m +/********************************************************************** +* +* Motorola MC68230 PI/T Parallell Interface and Timer +* +* Revisions +* 2015-07-15 JLE initial +* +* Todo +* - Add clock and timers +* - Add all missing registers +* - Add configuration +**********************************************************************/ + +#include "68230pit.h" + +#define LOG(x) /* x */ + +//************************************************************************** +// DEVICE TYPE DEFINITIONS +//************************************************************************** + +const device_type PIT68230 = &device_creator; + +//------------------------------------------------- +// pit68230_device - constructors +//------------------------------------------------- +pit68230_device::pit68230_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, UINT32 variant, const char *shortname, const char *source) + : device_t (mconfig, type, name, tag, owner, clock, shortname, source), + device_execute_interface (mconfig, *this) + , m_icount (0) + , m_write_pa (*this) + , m_write_h2 (*this) +{ +} + + +pit68230_device::pit68230_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t (mconfig, PIT68230, "PIT68230", tag, owner, clock, "pit68230", __FILE__), + device_execute_interface (mconfig, *this) + , m_icount (0) + , m_write_pa (*this) + , m_write_h2 (*this) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- +void pit68230_device::device_start () +{ + LOG (logerror ("PIT68230 device started\n")); + m_icountptr = &m_icount; + + // resolve callbacks + m_write_pa.resolve_safe (); + m_write_h2.resolve_safe (); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- +void pit68230_device::device_reset () +{ + LOG (logerror ("PIT68230 device reseted\n")); + m_pgcr = 0; + m_psrr = 0; + m_paddr = 0; + m_pbddr = 0; + m_pcddr = 0; + m_pacr = 0; m_write_h2 (m_pacr); + m_pbcr = 0; + m_padr = 0; m_write_pa ((offs_t)0, m_padr); // TODO: check PADDR + m_pbdr = 0; + m_psr = 0; +} + +//------------------------------------------------- +// device_timer - handler timer events +//------------------------------------------------- +void pit68230_device::device_timer (emu_timer &timer, device_timer_id id, INT32 param, void *ptr) +{ +} + +void pit68230_device::h1_set (UINT8 state) +{ + LOG (logerror ("h1_set %d @ m_psr %2x => ", state, m_psr)); + if (state) m_psr |= 1; else m_psr &= ~1; + LOG (logerror ("%02x %lld\n", m_psr, machine ().firstcpu->total_cycles ())); +} + +void pit68230_device::portb_setbit (UINT8 bit, UINT8 state) +{ + LOG (logerror ("portb_setbit %d/%d @ m_pbdr %2x => ", bit, state, m_pbdr)); + if (state) m_pbdr |= (1 << bit); else m_pbdr &= ~(1 << bit); + LOG (logerror ("%02x %lld\n", m_pbdr, machine ().firstcpu->total_cycles ())); +} + +//------------------------------------------------- +// execute_run - +//------------------------------------------------- +void pit68230_device::execute_run () +{ + do { + synchronize (); + + m_icount--; + } while (m_icount > 0); +} + +LOG (static INT32 ow_cnt = 0); +LOG (static INT32 ow_data = 0); +LOG (static INT32 ow_ofs = 0); + +WRITE8_MEMBER (pit68230_device::write){ + switch (offset) { + case PIT_68230_PGCR: + m_pgcr = data; + break; + + case PIT_68230_PSRR: + m_psrr = data; + break; + + case PIT_68230_PADDR: + m_paddr = data; + break; + + case PIT_68230_PBDDR: + m_pbddr = data; + break; + + case PIT_68230_PCDDR: + m_pcddr = data; + break; + + case PIT_68230_PACR: + m_pacr = data; + // callbacks + /*PACR in Mode 0 + * 5 43 H2 Control in Submode 00 && 01 + * ------------------------------------ + * 0 XX Input pin - edge-sensitive status input, H2S is set on an asserted edge. + * 1 00 Output pin - negated, H2S is always clear. + * 1 01 Output pin - asserted, H2S is always clear. + * 1 10 Output pin - interlocked input handshake protocol, H2S is always clear. + * 1 11 Output pin - pulsed input handshake protocol, H2S is always clear. + * + * 5 43 H2 Control in Submode 1x + * ------------------------------------ + * 0 XX Input pin - edge-sensitive status input, H2S is set on an asserted edge. + * 1 X0 Output pin - negated, H2S is always cleared. + * 1 X1 Output pin - asserted, H2S is always cleared. + */ + m_write_h2 (m_pacr & 0x08 ? 1 : 0); // TODO: Check mode and submodes + break; + + case PIT_68230_PBCR: + m_pbcr = data; + break; + + case PIT_68230_PADR: + m_padr = data; + // callbacks + m_write_pa ((offs_t)0, m_padr); // TODO: check PADDR + break; + + case PIT_68230_PSR: + m_psr = data; + break; + + default: + LOG (logerror ("unhandled register %02x", offset)); + } + + LOG (if (offset != ow_ofs || data != ow_data || ow_cnt >= 1000) { + logerror ("\npit68230_device::write: previous identical operation performed %02x times\n", ow_cnt); + ow_cnt = 0; + ow_data = data; + ow_ofs = offset; + logerror ("pit68230_device::write: offset=%02x data=%02x %lld\n", ow_ofs, ow_data, machine ().firstcpu->total_cycles ()); + } + else + ow_cnt++; ) +} + +LOG (static INT32 or_cnt = 0); +LOG (static INT32 or_data = 0); +LOG (static INT32 or_ofs = 0); + +READ8_MEMBER (pit68230_device::read){ + UINT8 data = 0; + + switch (offset) { + case PIT_68230_PGCR: + data = m_pgcr; + break; + + case PIT_68230_PSRR: + data = m_psrr; + break; + + case PIT_68230_PADDR: + data = m_paddr; + break; + + case PIT_68230_PBDDR: + data = m_pbddr; + break; + + case PIT_68230_PCDDR: + data = m_pcddr; + break; + + case PIT_68230_PACR: + data = m_pacr; + break; + + case PIT_68230_PBCR: + data = m_pbcr; + break; + + case PIT_68230_PADR: + data = m_padr; + break; + + case PIT_68230_PBDR: + /* 4.6.2. PORT B DATA REGISTER (PBDR). The port B data register is a holding + * register for moving data to and from port B pins. The port B data direction + * register determines whether each pin is an input (zero) or an output (one). + * This register is readable and writable at all times. Depending on the chosen + * mode/submode, reading or writing may affect the double-buffered handshake + * mechanism. The port B data register is not affected by the assertion of the + * RESET pin. PB0-PB7 sits on pins 17-24 on a 48 pin DIP package */ + data = m_pbdr; + break; + + case PIT_68230_PSR: + /* 4.8. PORT STATUS REGISTER (PSR) The port status register contains information about + * handshake pin activity. Bits 7-4 show the instantaneous level of the respective handshake + * pin, and are independent of the handshake pin sense bits in the port general control + * register. Bits 3-0 are the respective status bits referred to throughout this document. + * Their interpretation depends on the programmed mode/submode of the PI/T. For bits + * 3-0 a one is the active or asserted state. */ + data = m_psr; + break; + + default: + LOG (logerror ("unhandled register %02x", offset)); + data = 0; + } + + LOG (if (offset != or_ofs || data != or_data || or_cnt >= 1000) { + logerror ("\npit68230_device::read: previous identical operation performed %02x times\n", or_cnt); + or_cnt = 0; + or_data = data; + or_ofs = offset; + logerror ("pit68230_device::read: offset=%02x data=%02x %lld\n", or_ofs, or_data, machine ().firstcpu->total_cycles ()); + } + else + or_cnt++; ) + + return data; +} diff --git a/src/devices/machine/68230pit.h b/src/devices/machine/68230pit.h new file mode 100644 index 00000000000..b32cb25e928 --- /dev/null +++ b/src/devices/machine/68230pit.h @@ -0,0 +1,131 @@ +// license:BSD-3-Clause +// copyright-holders:Joakim Larsson Edstr??m +/********************************************************************** +* +* Motorola MC68230 PI/T Parallell Interface and Timer +* +* _____ _____ +* D5 1 |* \_/ | 48 D4 +* D6 2 | | 47 D3 +* D7 3 | | 46 D2 +* PA0 4 | | 45 D1 +* PA1 5 | | 44 D0 +* PA2 6 | | 43 R/W* +* PA3 7 | | 42 DTACK* +* PA4 8 | | 41 CS* +* PA5 9 | | 40 CLK +* PA6 10 | | 39 RESET* +* PA7 11 | | 38 VSS +* Vcc 12 | TS68230 | 37 PC7/TIACK* +* H1 13 | SC87845 | 36 PC6/PIACK* +* H2 14 | | 35 PC5/PIRQ* +* H3 15 | | 34 PC4/DMAREQ* +* H4 16 | | 33 PC3/TOUT +* PB0 17 | | 32 PC2/TIN +* PB1 18 | | 31 PC1 +* PB2 19 | | 30 PC0 +* PB3 20 | | 29 RS1 +* PB4 21 | | 28 RS2 +* PB5 22 | | 27 RS3 +* PB6 23 | | 26 RS4 +* PB7 24 |_____________| 25 RS5 +* +**********************************************************************/ + +#pragma once + +#ifndef __68230PIT_H__ +#define __68230PIT_H__ + +#include "emu.h" + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_PIT68230_PA_OUTPUT_CALLBACK(_write) \ + devcb = &pit68230_device::set_pa_wr_callback (*device, DEVCB_ ## _write); + +#define MCFG_PIT68230_PB_OUTPUT_CALLBACK(_write) \ + devcb = &pit68230_device::set_pb_wr_callback (*device, DEVCB_ ## _write); + +#define MCFG_PIT68230_H2_CALLBACK(_write) \ + devcb = &pit68230_device::set_h2_wr_callback (*device, DEVCB_ ## _write); + +/*----------------------------------------------------------------------- + * Registers RS1-RS5 R/W Description + * -------------------------------------------------------------------------*/ +#define PIT_68230_PGCR 0x00 /* RW Port General Control register */ +#define PIT_68230_PSRR 0x01 /* RW Port Service Request register */ +#define PIT_68230_PADDR 0x02 /* RW Port A Data Direction register */ +#define PIT_68230_PBDDR 0x03 /* RW Port B Data Direction register */ +#define PIT_68230_PCDDR 0x04 /* RW Port C Data Direction register */ +#define PIT_68230_PIVR 0x05 /* RW Port Interrupt vector register */ +#define PIT_68230_PACR 0x06 /* RW Port A Control register */ +#define PIT_68230_PBCR 0x07 /* RW Port B Control register */ +#define PIT_68230_PADR 0x08 /* RW Port A Data register */ +#define PIT_68230_PBDR 0x09 /* RW Port B Data register */ +#define PIT_68230_PAAR 0x0a /* RO Port A Alternate register */ +#define PIT_68230_PBAR 0x0b /* RO Port B Alternate register */ +#define PIT_68230_PCDR 0x0c /* RW Port C Data register */ +#define PIT_68230_PSR 0x0d /* RW Port Status register */ +#define PIT_68230_TCR 0x10 /* RW Timer Control Register */ +#define PIT_68230_TIVR 0x11 /* RW Timer Interrupt Vector Register */ +#define PIT_68230_CPRH 0x13 /* RW Counter Preload Register High */ +#define PIT_68230_CPRM 0x14 /* RW Counter Preload Register Middle */ +#define PIT_68230_CPRL 0x15 /* RW Counter Preload Register Low */ +#define PIT_68230_CNTRH 0x17 /* RO Counter Register High */ +#define PIT_68230_CNTRM 0x18 /* RO Counter Register Middle */ +#define PIT_68230_CNTRL 0x19 /* RO Counter Register Low */ +#define PIT_68230_TSR 0x1A /* RW Timer Status Register */ + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** +class pit68230_device : public device_t, public device_execute_interface +{ +public: +// construction/destruction +pit68230_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, UINT32 variant, const char *shortname, const char *source); +pit68230_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +template static devcb_base &set_pa_wr_callback (device_t &device, _Object object) +{ + return downcast(device).m_write_pa.set_callback (object); +} +template static devcb_base &set_h2_wr_callback (device_t &device, _Object object) +{ + return downcast(device).m_write_h2.set_callback (object); +} + +DECLARE_WRITE8_MEMBER (write); +DECLARE_READ8_MEMBER (read); + +void h1_set (UINT8 state); +void portb_setbit (UINT8 bit, UINT8 state); + +protected: +// device-level overrides +virtual void device_start (); +virtual void device_reset (); +virtual void device_timer (emu_timer &timer, device_timer_id id, int param, void *ptr); +virtual void execute_run (); +int m_icount; +devcb_write8 m_write_pa; +devcb_write_line m_write_h2; + +// peripheral ports +UINT8 m_pgcr; // Port General Control register +UINT8 m_psrr; // Port Service Request register +UINT8 m_paddr; // Port A Data Direction register +UINT8 m_pbddr; // Port B Data Direction register +UINT8 m_pcddr; // Port C Data Direction register +UINT8 m_pacr; // Port A Control register +UINT8 m_pbcr; // Port B Control register +UINT8 m_padr; // Port A Data register +UINT8 m_pbdr; // Port B Data register +UINT8 m_psr; // Port Status Register +}; + +// device type definition +extern const device_type PIT68230; +#endif /* __68230PIT_H__ */ diff --git a/src/devices/machine/68307.c b/src/devices/machine/68307.c new file mode 100644 index 00000000000..320c701acc7 --- /dev/null +++ b/src/devices/machine/68307.c @@ -0,0 +1,352 @@ +// license:BSD-3-Clause +// copyright-holders:David Haywood +/* 68307 */ + +#include "68307.h" + +/* 68307 SERIAL Module */ +/* all ports on this are 8-bit? */ + +/* this is a 68681 'compatible' chip but with only a single channel implemented + (writes to the other channel have no effects) + + for now at least we piggyback on the existing 68307 emulation rather than having + a custom verson here, that may change later if subtle differences exist. + +*/ +READ8_MEMBER( m68307cpu_device::m68307_internal_serial_r ) +{ + m68307cpu_device *m68k = this; + + if (offset&1) return m_duart->read(*m68k->program, offset>>1); + return 0x0000; +} + +WRITE8_MEMBER(m68307cpu_device::m68307_internal_serial_w) +{ + m68307cpu_device *m68k = this; + + if (offset & 1) m_duart->write(*m68k->program, offset >> 1, data); +} + + + +static ADDRESS_MAP_START( m68307_internal_map, AS_PROGRAM, 16, m68307cpu_device ) + AM_RANGE(0x000000f0, 0x000000ff) AM_READWRITE(m68307_internal_base_r, m68307_internal_base_w) +ADDRESS_MAP_END + + + +static MACHINE_CONFIG_FRAGMENT( 68307fragment ) + MCFG_MC68681_ADD("internal68681", 16000000/4) // ?? Mhz - should be specified in inline config + MCFG_MC68681_IRQ_CALLBACK(WRITELINE(m68307cpu_device, m68307_duart_irq_handler)) + MCFG_MC68681_A_TX_CALLBACK(WRITELINE(m68307cpu_device, m68307_duart_txa)) + MCFG_MC68681_B_TX_CALLBACK(WRITELINE(m68307cpu_device, m68307_duart_txb)) + MCFG_MC68681_INPORT_CALLBACK(READ8(m68307cpu_device, m68307_duart_input_r)) + MCFG_MC68681_OUTPORT_CALLBACK(WRITE8(m68307cpu_device, m68307_duart_output_w)) +MACHINE_CONFIG_END + +machine_config_constructor m68307cpu_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( 68307fragment ); +} + + +m68307cpu_device::m68307cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : m68000_device(mconfig, "MC68307", tag, owner, clock, M68307, 16,24, ADDRESS_MAP_NAME(m68307_internal_map), "mc68307", __FILE__), + write_irq(*this), + write_a_tx(*this), + write_b_tx(*this), + read_inport(*this), + write_outport(*this), + m_duart(*this, "internal68681") +{ + m68307SIM = 0; + m68307MBUS = 0; + m68307TIMER = 0; + m68307_base = 0; + m68307_scrhigh = 0; + m68307_scrlow = 0; + m68307_currentcs = 0; +} + + + + + + +void m68307cpu_device::device_reset() +{ + m68000_device::device_reset(); + + if (m68307SIM) m68307SIM->reset(); + if (m68307MBUS) m68307MBUS->reset(); + if (m68307TIMER) m68307TIMER->reset(); + + m68307_base = 0xbfff; + m68307_scrhigh = 0x0007; + m68307_scrlow = 0xf010; + +} + + +/* todo: is it possible to calculate the address map based on CS when they change + and install handlers? Going through this logic for every memory access is + very slow */ + +int m68307_calc_cs(m68307cpu_device *m68k, offs_t address) +{ + m68307_sim* sim = m68k->m68307SIM; + + for (int i=0;i<4;i++) + { + int br,amask,bra; + br = sim->m_br[i] & 1; + amask = ((sim->m_or[i]&0x1ffc)<<11); + bra = ((sim->m_br[i] & 0x1ffc)<<11); + if ((br) && ((address & amask) == bra)) return i+1; + } + return 0; +} + + + +UINT16 m68307cpu_device::simple_read_immediate_16_m68307(offs_t address) +{ +// m68307_currentcs = m68307_calc_cs(this, address); + return m_direct->read_word(address); +} + +UINT8 m68307cpu_device::read_byte_m68307(offs_t address) +{ +// m68307_currentcs = m68307_calc_cs(this, address); + return m_space->read_byte(address); +} + +UINT16 m68307cpu_device::read_word_m68307(offs_t address) +{ +// m68307_currentcs = m68307_calc_cs(this, address); + return m_space->read_word(address); +} + +UINT32 m68307cpu_device::read_dword_m68307(offs_t address) +{ +// m68307_currentcs = m68307_calc_cs(this, address); + return m_space->read_dword(address); +} + +void m68307cpu_device::write_byte_m68307(offs_t address, UINT8 data) +{ +// m68307_currentcs = m68307_calc_cs(this, address); + m_space->write_byte(address, data); +} + +void m68307cpu_device::write_word_m68307(offs_t address, UINT16 data) +{ +// m68307_currentcs = m68307_calc_cs(this, address); + m_space->write_word(address, data); +} + +void m68307cpu_device::write_dword_m68307(offs_t address, UINT32 data) +{ +// m68307_currentcs = m68307_calc_cs(this, address); + m_space->write_dword(address, data); +} + + + + +void m68307cpu_device::init16_m68307(address_space &space) +{ + m_space = &space; + m_direct = &space.direct(); + opcode_xor = 0; + + readimm16 = m68k_readimm16_delegate(FUNC(m68307cpu_device::simple_read_immediate_16_m68307), this); + read8 = m68k_read8_delegate(FUNC(m68307cpu_device::read_byte_m68307), this); + read16 = m68k_read16_delegate(FUNC(m68307cpu_device::read_word_m68307), this); + read32 = m68k_read32_delegate(FUNC(m68307cpu_device::read_dword_m68307), this); + write8 = m68k_write8_delegate(FUNC(m68307cpu_device::write_byte_m68307), this); + write16 = m68k_write16_delegate(FUNC(m68307cpu_device::write_word_m68307), this); + write32 = m68k_write32_delegate(FUNC(m68307cpu_device::write_dword_m68307), this); +} + + + +void m68307cpu_device::set_port_callbacks(m68307_porta_read_delegate porta_r, m68307_porta_write_delegate porta_w, m68307_portb_read_delegate portb_r, m68307_portb_write_delegate portb_w) +{ + m_m68307_porta_r = porta_r; + m_m68307_porta_w = porta_w; + m_m68307_portb_r = portb_r; + m_m68307_portb_w = portb_w; +} + + + + + +UINT16 m68307cpu_device::get_cs(offs_t address) +{ + m68307_currentcs = m68307_calc_cs(this, address); + + return m68307_currentcs; +} + + +/* 68307 specifics - MOVE */ + +void m68307cpu_device::set_interrupt(int level, int vector) +{ + set_input_line_and_vector(level, HOLD_LINE, vector); +} + +void m68307cpu_device::timer0_interrupt() +{ + int prioritylevel = (m68307SIM->m_picr & 0x7000)>>12; + int vector = (m68307SIM->m_pivr & 0x00f0) | 0xa; + set_interrupt(prioritylevel, vector); +} + +void m68307cpu_device::timer1_interrupt() +{ + int prioritylevel = (m68307SIM->m_picr & 0x0700)>>8; + int vector = (m68307SIM->m_pivr & 0x00f0) | 0xb; + set_interrupt(prioritylevel, vector); +} + + +void m68307cpu_device::serial_interrupt(int vector) +{ + int prioritylevel = (m68307SIM->m_picr & 0x0070)>>4; + set_interrupt(prioritylevel, vector); +} + +WRITE_LINE_MEMBER(m68307cpu_device::m68307_duart_irq_handler) +{ + if (state == ASSERT_LINE) + { + serial_interrupt(m_duart->get_irq_vector()); + } +} + +void m68307cpu_device::mbus_interrupt() +{ + int prioritylevel = (m68307SIM->m_picr & 0x0007)>>0; + int vector = (m68307SIM->m_pivr & 0x00f0) | 0xd; + set_interrupt(prioritylevel, vector); +} + +void m68307cpu_device::licr2_interrupt() +{ + int prioritylevel = (m68307SIM->m_licr2 & 0x0007)>>0; + int vector = (m68307SIM->m_pivr & 0x00f0) | 0x9; + m68307SIM->m_licr2 |= 0x8; + + + set_interrupt(prioritylevel, vector); +} + +void m68307cpu_device::device_start() +{ + init_cpu_m68000(); + + /* basic CS logic, timers, mbus, serial logic + set via remappable register + */ + + init16_m68307(*program); + + m68307SIM = new m68307_sim(); + m68307MBUS = new m68307_mbus(); + m68307TIMER = new m68307_timer(); + + m68307TIMER->init(this); + + m68307SIM->reset(); + m68307MBUS->reset(); + m68307TIMER->reset(); + + internal = &this->space(AS_PROGRAM); + m68307_base = 0xbfff; + m68307_scrhigh = 0x0007; + m68307_scrlow = 0xf010; + + write_irq.resolve_safe(); + write_a_tx.resolve_safe(); + write_b_tx.resolve_safe(); + read_inport.resolve(); + write_outport.resolve_safe(); + + set_port_callbacks(m68307_porta_read_delegate(),m68307_porta_write_delegate(),m68307_portb_read_delegate(),m68307_portb_write_delegate()); +} + + + +READ16_MEMBER( m68307cpu_device::m68307_internal_base_r ) +{ + m68307cpu_device *m68k = this; + + int pc = space.device().safe_pc(); + logerror("%08x m68307_internal_base_r %08x, (%04x)\n", pc, offset*2,mem_mask); + + switch (offset<<1) + { + case 0x2: return m68k->m68307_base; + case 0x4: return m68k->m68307_scrhigh; + case 0x6: return m68k->m68307_scrlow; + } + + logerror("(read was illegal?)\n"); + + return 0x0000; +} + +WRITE16_MEMBER( m68307cpu_device::m68307_internal_base_w ) +{ + m68307cpu_device *m68k = this; + + int pc = space.device().safe_pc(); + logerror("%08x m68307_internal_base_w %08x, %04x (%04x)\n", pc, offset*2,data,mem_mask); + int base = 0; + //int mask = 0; + + switch (offset<<1) + { + case 0x2: + /* remove old internal handler */ + base = (m68k->m68307_base & 0x0fff) << 12; + //mask = (m68k->m68307_base & 0xe000) >> 13; + //if ( m68k->m68307_base & 0x1000 ) mask |= 7; + m68k->internal->unmap_readwrite(base+0x000, base+0x04f); + m68k->internal->unmap_readwrite(base+0x100, base+0x11f); + m68k->internal->unmap_readwrite(base+0x120, base+0x13f); + m68k->internal->unmap_readwrite(base+0x140, base+0x149); + + /* store new base address */ + COMBINE_DATA(&m68k->m68307_base); + + /* install new internal handler */ + base = (m68k->m68307_base & 0x0fff) << 12; + //mask = (m68k->m68307_base & 0xe000) >> 13; + //if ( m68k->m68307_base & 0x1000 ) mask |= 7; + m68k->internal->install_readwrite_handler(base + 0x000, base + 0x04f, read16_delegate(FUNC(m68307cpu_device::m68307_internal_sim_r),this), write16_delegate(FUNC(m68307cpu_device::m68307_internal_sim_w),this)); + m68k->internal->install_readwrite_handler(base + 0x100, base + 0x11f, read8_delegate(FUNC(m68307cpu_device::m68307_internal_serial_r),this), write8_delegate(FUNC(m68307cpu_device::m68307_internal_serial_w),this), 0xffff); + m68k->internal->install_readwrite_handler(base + 0x120, base + 0x13f, read16_delegate(FUNC(m68307cpu_device::m68307_internal_timer_r),this), write16_delegate(FUNC(m68307cpu_device::m68307_internal_timer_w),this)); + m68k->internal->install_readwrite_handler(base + 0x140, base + 0x149, read8_delegate(FUNC(m68307cpu_device::m68307_internal_mbus_r),this), write8_delegate(FUNC(m68307cpu_device::m68307_internal_mbus_w),this), 0xffff); + + + break; + + case 0x4: + COMBINE_DATA(&m68k->m68307_scrhigh); + break; + + case 0x6: + COMBINE_DATA(&m68k->m68307_scrlow); + break; + + default: + logerror("(write was illegal?)\n"); + break; + } +} diff --git a/src/devices/machine/68307.h b/src/devices/machine/68307.h new file mode 100644 index 00000000000..57b09b639ca --- /dev/null +++ b/src/devices/machine/68307.h @@ -0,0 +1,132 @@ +// license:BSD-3-Clause +// copyright-holders:David Haywood +/* 68307 */ + + +#pragma once +#ifndef __M68307_H__ +#define __M68307_H__ + +#include "emu.h" +#include "cpu/m68000/m68000.h" + +#include "68307sim.h" +#include "68307bus.h" +#include "68307tmu.h" +#include "machine/mc68681.h" + + +typedef device_delegate m68307_porta_read_delegate; +typedef device_delegate m68307_porta_write_delegate; +typedef device_delegate m68307_portb_read_delegate; +typedef device_delegate m68307_portb_write_delegate; + + +/* trampolines so we can specify the 68681 serial configuration when adding the CPU */ +#define MCFG_MC68307_SERIAL_A_TX_CALLBACK(_cb) \ + devcb = &m68307cpu_device::set_a_tx_cb(*device, DEVCB_##_cb); + +#define MCFG_MC68307_SERIAL_B_TX_CALLBACK(_cb) \ + devcb = &m68307cpu_device::set_b_tx_cb(*device, DEVCB_##_cb); + +// deprecated: use ipX_w() instead +#define MCFG_MC68307_SERIAL_INPORT_CALLBACK(_cb) \ + devcb = &m68307cpu_device::set_inport_cb(*device, DEVCB_##_cb); + +#define MCFG_MC68307_SERIAL_OUTPORT_CALLBACK(_cb) \ + devcb = &m68307cpu_device::set_outport_cb(*device, DEVCB_##_cb); + + +class m68307cpu_device : public m68000_device { +public: + m68307cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + /* trampolines so we can specify the 68681 serial configuration when adding the CPU */ + template static devcb_base &set_irq_cb(device_t &device, _Object object) { return downcast(device).write_irq.set_callback(object); } + template static devcb_base &set_a_tx_cb(device_t &device, _Object object) { return downcast(device).write_a_tx.set_callback(object); } + template static devcb_base &set_b_tx_cb(device_t &device, _Object object) { return downcast(device).write_b_tx.set_callback(object); } + template static devcb_base &set_inport_cb(device_t &device, _Object object) { return downcast(device).read_inport.set_callback(object); } + template static devcb_base &set_outport_cb(device_t &device, _Object object) { return downcast(device).write_outport.set_callback(object); } + + DECLARE_WRITE_LINE_MEMBER(m68307_duart_irq_handler); + DECLARE_WRITE_LINE_MEMBER(m68307_duart_txa){ write_a_tx(state); } + DECLARE_WRITE_LINE_MEMBER(m68307_duart_txb){ write_b_tx(state); } + DECLARE_READ8_MEMBER(m68307_duart_input_r){ return read_inport(); } + DECLARE_WRITE8_MEMBER(m68307_duart_output_w){ write_outport(data); } + devcb_write_line write_irq, write_a_tx, write_b_tx; + devcb_read8 read_inport; + devcb_write8 write_outport; + + UINT16 simple_read_immediate_16_m68307(offs_t address); + + + UINT8 read_byte_m68307(offs_t address); + UINT16 read_word_m68307(offs_t address); + UINT32 read_dword_m68307(offs_t address); + void write_byte_m68307(offs_t address, UINT8 data); + void write_word_m68307(offs_t address, UINT16 data); + void write_dword_m68307(offs_t address, UINT32 data); + + + /* 68307 peripheral modules */ + m68307_sim* m68307SIM; + m68307_mbus* m68307MBUS; +// m68307_serial* m68307SERIAL; + m68307_timer* m68307TIMER; + + UINT16 m68307_base; + UINT16 m68307_scrhigh; + UINT16 m68307_scrlow; + + int m68307_currentcs; + + + DECLARE_READ16_MEMBER( m68307_internal_base_r ); + DECLARE_WRITE16_MEMBER( m68307_internal_base_w ); + DECLARE_READ16_MEMBER( m68307_internal_timer_r ); + DECLARE_WRITE16_MEMBER( m68307_internal_timer_w ); + DECLARE_READ16_MEMBER( m68307_internal_sim_r ); + DECLARE_WRITE16_MEMBER( m68307_internal_sim_w ); + DECLARE_READ8_MEMBER( m68307_internal_serial_r ); + DECLARE_WRITE8_MEMBER( m68307_internal_serial_w ); + DECLARE_READ8_MEMBER( m68307_internal_mbus_r ); + DECLARE_WRITE8_MEMBER( m68307_internal_mbus_w ); + + + /* callbacks for internal ports */ + void set_port_callbacks(m68307_porta_read_delegate porta_r, m68307_porta_write_delegate porta_w, m68307_portb_read_delegate portb_r, m68307_portb_write_delegate portb_w); + void set_interrupt(int level, int vector); + UINT16 get_cs(offs_t address); + void timer0_interrupt(); + void timer1_interrupt(); + void serial_interrupt(int vector); + void mbus_interrupt(); + void licr2_interrupt(); + + m68307_porta_read_delegate m_m68307_porta_r; + m68307_porta_write_delegate m_m68307_porta_w; + m68307_portb_read_delegate m_m68307_portb_r; + m68307_portb_write_delegate m_m68307_portb_w; + + void init16_m68307(address_space &space); + void init_cpu_m68307(void); + + virtual UINT32 disasm_min_opcode_bytes() const { return 2; }; + virtual UINT32 disasm_max_opcode_bytes() const { return 10; }; + + virtual UINT32 execute_min_cycles() const { return 4; }; + virtual UINT32 execute_max_cycles() const { return 158; }; + + required_device m_duart; +protected: + virtual machine_config_constructor device_mconfig_additions() const; + virtual void device_start(); + virtual void device_reset(); + +private: +}; + +static const device_type M68307 = &device_creator; + + +#endif diff --git a/src/devices/machine/68307bus.c b/src/devices/machine/68307bus.c new file mode 100644 index 00000000000..c9af37df775 --- /dev/null +++ b/src/devices/machine/68307bus.c @@ -0,0 +1,112 @@ +// license:BSD-3-Clause +// copyright-holders:David Haywood +/* 68307 MBUS module */ +/* all ports on this are 8-bit? */ + +#include "emu.h" +#include "68307.h" + + +READ8_MEMBER( m68307cpu_device::m68307_internal_mbus_r ) +{ + m68307cpu_device *m68k = this; + m68307_mbus* mbus = m68k->m68307MBUS; + assert(mbus != NULL); + UINT8 retval; + + if (mbus) + { + int pc = space.device().safe_pc(); + + + switch (offset) + { + case m68307BUS_MADR: + logerror("%08x m68307_internal_mbus_r %08x (MADR - M-Bus Address Register)\n", pc, offset); + return space.machine().rand(); + + case m68307BUS_MFDR: + logerror("%08x m68307_internal_mbus_r %08x (MFDR - M-Bus Frequency Divider Register)\n", pc, offset); + return space.machine().rand(); + + case m68307BUS_MBCR: + logerror("%08x m68307_internal_mbus_r %08x (MFCR - M-Bus Control Register)\n", pc, offset); + return mbus->m_MFCR;//space.machine().rand(); + + case m68307BUS_MBSR: + logerror("%08x m68307_internal_mbus_r %08x (MBSR - M-Bus Status Register)\n", pc, offset); + retval = 0; + if (mbus->m_busy) retval |= 0x20; + if (mbus->m_intpend) retval |= 0x02; + + return retval; + + case m68307BUS_MBDR: + logerror("%08x m68307_internal_mbus_r %08x (MBDR - M-Bus Data I/O Register)\n", pc, offset); + mbus->m_intpend = true; + return 0xff;//space.machine().rand(); + + default: + logerror("%08x m68307_internal_mbus_r %08x (UNKNOWN / ILLEGAL)\n", pc, offset); + return 0x00; + } + } + + return 0xff; +} + +WRITE8_MEMBER( m68307cpu_device::m68307_internal_mbus_w ) +{ + m68307cpu_device *m68k = this; + m68307_mbus* mbus = m68k->m68307MBUS; + assert(mbus != NULL); + + if (mbus) + { + int pc = space.device().safe_pc(); + + switch (offset) + { + case m68307BUS_MADR: + logerror("%08x m68307_internal_mbus_w %08x, %02x (MADR - M-Bus Address Register)\n", pc, offset,data); + break; + + case m68307BUS_MFDR: + logerror("%08x m68307_internal_mbus_w %08x, %02x (MFDR - M-Bus Frequency Divider Register)\n", pc, offset,data); + break; + + case m68307BUS_MBCR: + logerror("%08x m68307_internal_mbus_w %08x, %02x (MFCR - M-Bus Control Register)\n", pc, offset,data); + + mbus->m_MFCR = data; + if (data & 0x80) + { + mbus->m_busy = false; + mbus->m_intpend = false; + } + if (data & 0x20) mbus->m_busy = true; + + break; + + case m68307BUS_MBSR: + logerror("%08x m68307_internal_mbus_w %08x, %02x (MBSR - M-Bus Status Register)\n", pc, offset,data); + break; + + case m68307BUS_MBDR: + logerror("%08x m68307_internal_mbus_w %08x, %02x (MBDR - M-Bus Data I/O Register)\n", pc, offset,data); + + mbus->m_intpend = true; + + break; + + default: + logerror("%08x m68307_internal_mbus_w %08x, %02x (UNKNOWN / ILLEGAL)\n", pc, offset,data); + break; + } + } +} + +void m68307_mbus::reset(void) +{ + m_busy = false; +} diff --git a/src/devices/machine/68307bus.h b/src/devices/machine/68307bus.h new file mode 100644 index 00000000000..5131ad4c9c5 --- /dev/null +++ b/src/devices/machine/68307bus.h @@ -0,0 +1,22 @@ +// license:BSD-3-Clause +// copyright-holders:David Haywood +#include "cpu/m68000/m68000.h" + +#define m68307BUS_MADR (0x01) +#define m68307BUS_MFDR (0x03) +#define m68307BUS_MBCR (0x05) +#define m68307BUS_MBSR (0x07) +#define m68307BUS_MBDR (0x09) + + +class m68307_mbus +{ + public: + + UINT16 m_MFCR; + + bool m_busy; + bool m_intpend; + + void reset(void); +}; diff --git a/src/devices/machine/68307sim.c b/src/devices/machine/68307sim.c new file mode 100644 index 00000000000..3709c346fbf --- /dev/null +++ b/src/devices/machine/68307sim.c @@ -0,0 +1,314 @@ +// license:BSD-3-Clause +// copyright-holders:David Haywood +/* 68307 SIM module */ + +#include "emu.h" +#include "68307.h" + + +READ16_MEMBER( m68307cpu_device::m68307_internal_sim_r ) +{ + m68307cpu_device *m68k = this; + m68307_sim* sim = m68k->m68307SIM; + assert(sim != NULL); + + int pc = space.device().safe_pc(); + + if (sim) + { + switch (offset<<1) + { + case m68307SIM_PADAT: return sim->read_padat(this, space, mem_mask); + case m68307SIM_PBDAT: return sim->read_pbdat(this, space, mem_mask); + + case m68307SIM_LICR2: return (sim->m_licr2); + + case m68307SIM_BR0: return (sim->m_br[0]); + case m68307SIM_OR0: return (sim->m_or[0]); + case m68307SIM_BR1: return (sim->m_br[1]); + case m68307SIM_OR1: return (sim->m_or[1]); + case m68307SIM_BR2: return (sim->m_br[2]); + case m68307SIM_OR2: return (sim->m_or[2]); + case m68307SIM_BR3: return (sim->m_br[3]); + case m68307SIM_OR3: return (sim->m_or[3]); + + default: + logerror("%08x m68307_internal_sim_r %08x, (%04x)\n", pc, offset*2,mem_mask); + return 0xff; + + } + } + + return 0x0000; +} + + +WRITE16_MEMBER( m68307cpu_device::m68307_internal_sim_w ) +{ + m68307cpu_device *m68k = this; + m68307_sim* sim = m68k->m68307SIM; + assert(sim != NULL); + + int pc = space.device().safe_pc(); + + if (sim) + { + switch (offset<<1) + { + case m68307SIM_PACNT: + logerror("%08x m68307_internal_sim_w %08x, %04x (%04x) (Port A (8-bit) Control Register - PACNT)\n", pc, offset*2,data,mem_mask); + sim->write_pacnt(data,mem_mask); + break; + + case m68307SIM_PADDR: + logerror("%08x m68307_internal_sim_w %08x, %04x (%04x) (Port A (8-bit) Direction Register - PADDR)\n", pc, offset*2,data,mem_mask); + sim->write_paddr(data,mem_mask); + break; + + case m68307SIM_PADAT: + sim->write_padat(this, space, data,mem_mask); + break; + + case m68307SIM_PBCNT: + logerror("%08x m68307_internal_sim_w %08x, %04x (%04x) (Port B (16-bit) Control Register - PBCNT)\n", pc, offset*2,data,mem_mask); + sim->write_pbcnt(data,mem_mask); + break; + + case m68307SIM_PBDDR: + logerror("%08x m68307_internal_sim_w %08x, %04x (%04x) (Port B (16-bit) Direction Register - PBDDR)\n", pc, offset*2,data,mem_mask); + sim->write_pbddr(data,mem_mask); + break; + + case m68307SIM_PBDAT: + sim->write_pbdat(this, space, data, mem_mask); + break; + + + case m68307SIM_LICR1: + logerror("%08x m68307_internal_sim_w %08x, %04x (%04x) (Latched Interrupt Control Register 1 - LICR1)\n", pc, offset*2,data,mem_mask); + sim->write_licr1(data,mem_mask); + break; + + case m68307SIM_LICR2: + logerror("%08x m68307_internal_sim_w %08x, %04x (%04x) (Latched Interrupt Control Register 2 - LICR2)\n", pc, offset*2,data,mem_mask); + sim->write_licr2(data,mem_mask); + break; + + case m68307SIM_PICR: + logerror("%08x m68307_internal_sim_w %08x, %04x (%04x) (Peripheral Interrupt Control Register - PICR)\n", pc, offset*2,data,mem_mask); + sim->write_picr(data,mem_mask); + break; + + case m68307SIM_PIVR: + logerror("%08x m68307_internal_sim_w %08x, %04x (%04x) (Peripheral Interrupt Vector Register - PIVR)\n", pc, offset*2,data,mem_mask); + sim->write_pivr(data,mem_mask); + break; + + case m68307SIM_BR0: + COMBINE_DATA(&sim->m_br[0]); + break; + case m68307SIM_OR0: + COMBINE_DATA(&sim->m_or[0]); + break; + case m68307SIM_BR1: + COMBINE_DATA(&sim->m_br[1]); + break; + case m68307SIM_OR1: + COMBINE_DATA(&sim->m_or[1]); + break; + case m68307SIM_BR2: + COMBINE_DATA(&sim->m_br[2]); + break; + case m68307SIM_OR2: + COMBINE_DATA(&sim->m_or[2]); + break; + case m68307SIM_BR3: + COMBINE_DATA(&sim->m_br[3]); + break; + case m68307SIM_OR3: + COMBINE_DATA(&sim->m_or[3]); + break; + + + + default : + logerror("%08x m68307_internal_sim_w %08x, %04x (%04x)\n", pc, offset*2,data,mem_mask); + break; + + } + } +} + + +void m68307_sim::write_pacnt(UINT16 data, UINT16 mem_mask) +{ + COMBINE_DATA(&m_pacnt); +} + +void m68307_sim::write_paddr(UINT16 data, UINT16 mem_mask) +{ + COMBINE_DATA(&m_paddr); +} + + +UINT16 m68307_sim::read_padat(m68307cpu_device* m68k, address_space &space, UINT16 mem_mask) +{ + int pc = space.device().safe_pc(); + + if (!m68k->m_m68307_porta_r.isnull()) + { + // for general purpose bits, if configured as 'output' then anything output gets latched + // and anything configured as input is read from the port + UINT8 outputbits = m_paddr; + UINT8 inputbits = ~m_paddr; + UINT8 general_purpose_bits = ~m_pacnt; + UINT8 indat = m68k->m_m68307_porta_r(space, false, (inputbits & general_purpose_bits)&mem_mask) & ((inputbits & general_purpose_bits) & mem_mask); // read general purpose input lines + indat |= m68k->m_m68307_porta_r(space, true, (inputbits & ~general_purpose_bits)&mem_mask) & ((inputbits & ~general_purpose_bits)& mem_mask); // read dedicated input lines + UINT8 outdat = (m_padat & outputbits) & general_purpose_bits; // read general purpose output lines (reads latched data) + + return (indat | outdat); + + } + else + { + logerror("%08x m68307_internal_sim_r (%04x) (Port A (8-bit) Data Register - PADAT)\n", pc, mem_mask); + } + return 0xffff; +} + + +void m68307_sim::write_padat(m68307cpu_device* m68k, address_space &space, UINT16 data, UINT16 mem_mask) +{ + int pc = space.device().safe_pc(); + COMBINE_DATA(&m_padat); + + if (!m68k->m_m68307_porta_w.isnull()) + { + m68k->m_m68307_porta_w(space, false, data, 0xff); + } + else + { + logerror("%08x m68307_internal_sim_w %04x (%04x) (Port A (8-bit) Data Register - PADAT)\n", pc, data,mem_mask); + } +} + +void m68307_sim::write_pbcnt(UINT16 data, UINT16 mem_mask) +{ + COMBINE_DATA(&m_pbcnt); +} + +void m68307_sim::write_pbddr(UINT16 data, UINT16 mem_mask) +{ + COMBINE_DATA(&m_pbddr); +} + +UINT16 m68307_sim::read_pbdat(m68307cpu_device* m68k, address_space &space, UINT16 mem_mask) +{ + int pc = space.device().safe_pc(); + + if (!m68k->m_m68307_portb_r.isnull()) + { + // for general purpose bits, if configured as 'output' then anything output gets latched + // and anything configured as input is read from the port + UINT16 outputbits = m_pbddr; + UINT16 inputbits = ~m_pbddr; + UINT16 general_purpose_bits = ~m_pbcnt; + + UINT16 indat = m68k->m_m68307_portb_r(space, false, (inputbits & general_purpose_bits)&mem_mask) & ((inputbits & general_purpose_bits) & mem_mask); // read general purpose input lines + indat |= m68k->m_m68307_portb_r(space, true, (inputbits & ~general_purpose_bits)&mem_mask) & ((inputbits & ~general_purpose_bits)& mem_mask); // read dedicated input lines + UINT16 outdat = (m_pbdat & outputbits) & general_purpose_bits; // read general purpose output lines (reads latched data) + + return (indat | outdat); + } + else + { + logerror("%08x m68307_internal_sim_r (%04x) (Port B (16-bit) Data Register - PBDAT)\n", pc, mem_mask); + } + return 0xffff; +} + + +void m68307_sim::write_pbdat(m68307cpu_device* m68k, address_space &space, UINT16 data, UINT16 mem_mask) +{ + int pc = space.device().safe_pc(); + COMBINE_DATA(&m_pbdat); + + if (!m68k->m_m68307_portb_w.isnull()) + { + m68k->m_m68307_portb_w(space, false, data, mem_mask); + } + else + { + logerror("%08x m68307_internal_sim_w %04x (%04x) (Port B (16-bit) Data Register - PBDAT)\n", pc, data,mem_mask); + } +} + +void m68307_sim::write_licr1(UINT16 data, UINT16 mem_mask) +{ + COMBINE_DATA(&m_licr1); + data = m_licr1; + logerror("m_licr1 value %04x : Details :\n", data); + logerror("int4ipl %01x\n", (data>>0)&7); + logerror("pir4 %01x\n", (data>>3)&1); + logerror("int3ipl %01x\n", (data>>4)&7); + logerror("pir3 %01x\n", (data>>7)&1); + logerror("int2ipl %01x\n", (data>>8)&7); + logerror("pir2 %01x\n", (data>>11)&1); + logerror("int1ipl %01x\n", (data>>12)&7); + logerror("pir1 %01x\n", (data>>15)&1); + logerror("\n"); +} + +void m68307_sim::write_licr2(UINT16 data, UINT16 mem_mask) +{ + COMBINE_DATA(&m_licr2); + UINT16 newdata = m_licr2; + logerror("m_licr2 value %04x : Details :\n", newdata); + logerror("int8ipl %01x\n", (newdata>>0)&7); + logerror("pir8 %01x\n", (newdata>>3)&1); + logerror("int7ipl %01x\n", (newdata>>4)&7); + logerror("pir7 %01x\n", (newdata>>7)&1); + logerror("int6ipl %01x\n", (newdata>>8)&7); + logerror("pir6 %01x\n", (newdata>>11)&1); + logerror("int5ipl %01x\n", (newdata>>12)&7); + logerror("pir5 %01x\n", (newdata>>15)&1); + logerror("\n"); + + if (data & 0x0008) m_licr2 = m_licr2 & ~0x0008; + if (data & 0x0080) m_licr2 = m_licr2 & ~0x0080; + if (data & 0x0800) m_licr2 = m_licr2 & ~0x0800; + if (data & 0x8000) m_licr2 = m_licr2 & ~0x8000; + + +} + + +void m68307_sim::write_picr(UINT16 data, UINT16 mem_mask) +{ + COMBINE_DATA(&m_picr); + data = m_picr; + logerror("picr value %04x : Details :\n", data); + logerror("mbipl %01x\n", (data>>0)&7); + logerror("uaipl %01x\n", (data>>4)&7); + logerror("t2ipl %01x\n", (data>>8)&7); + logerror("t1ipl %01x\n", (data>>12)&7); + logerror("\n"); +} + +void m68307_sim::write_pivr(UINT16 data, UINT16 mem_mask) +{ + COMBINE_DATA(&m_pivr); + data = m_pivr; + logerror("pivr value %04x : Details :\n", data); + logerror("unused %01x\n", (data>>0)&0xf); + logerror("high vector %01x\n", (data>>4)&0xf); +} + +void m68307_sim::reset(void) +{ + for (int i=0;i<4;i++) + { + m_br[i] = 0xc001; + m_or[i] = 0xdffd; + } +} diff --git a/src/devices/machine/68307sim.h b/src/devices/machine/68307sim.h new file mode 100644 index 00000000000..59b33bee1e7 --- /dev/null +++ b/src/devices/machine/68307sim.h @@ -0,0 +1,74 @@ +// license:BSD-3-Clause +// copyright-holders:David Haywood +/* 68307 SIM module */ + +#include "cpu/m68000/m68000.h" + +class m68307cpu_device; + + +/* ports */ +#define m68307SIM_PACNT (0x10) +#define m68307SIM_PADDR (0x12) +#define m68307SIM_PADAT (0x14) +#define m68307SIM_PBCNT (0x16) +#define m68307SIM_PBDDR (0x18) +#define m68307SIM_PBDAT (0x1a) + + +/* interrupt logic */ +#define m68307SIM_LICR1 (0x20) +#define m68307SIM_LICR2 (0x22) +#define m68307SIM_PICR (0x24) +#define m68307SIM_PIVR (0x26) + +/* used for the CS logic */ +#define m68307SIM_BR0 (0x40) +#define m68307SIM_OR0 (0x42) +#define m68307SIM_BR1 (0x44) +#define m68307SIM_OR1 (0x46) +#define m68307SIM_BR2 (0x48) +#define m68307SIM_OR2 (0x4a) +#define m68307SIM_BR3 (0x4c) +#define m68307SIM_OR3 (0x4e) + +class m68307_sim +{ + public: + + UINT16 m_pacnt; // 8-bit + UINT16 m_paddr; // 8-bit + UINT16 m_padat; // 8-bit + + UINT16 m_pbcnt; + UINT16 m_pbddr; + UINT16 m_pbdat; + + UINT16 m_pivr; // 8-bit + + UINT16 m_br[4]; + UINT16 m_or[4]; + UINT16 m_picr; + UINT16 m_licr1; + UINT16 m_licr2; + + + void write_pacnt(UINT16 data, UINT16 mem_mask); + void write_paddr(UINT16 data, UINT16 mem_mask); + UINT16 read_padat(m68307cpu_device* m68k, address_space &space, UINT16 mem_mask); + void write_padat(m68307cpu_device* m68k, address_space &space, UINT16 data, UINT16 mem_mask); + + void write_pbcnt(UINT16 data, UINT16 mem_mask); + void write_pbddr(UINT16 data, UINT16 mem_mask); + UINT16 read_pbdat(m68307cpu_device* m68k, address_space &space, UINT16 mem_mask); + void write_pbdat(m68307cpu_device* m68k, address_space &space, UINT16 data, UINT16 mem_mask); + + + + void write_licr1(UINT16 data, UINT16 mem_mask); + void write_licr2(UINT16 data, UINT16 mem_mask); + void write_picr(UINT16 data, UINT16 mem_mask); + void write_pivr(UINT16 data, UINT16 mem_mask); + + void reset(void); +}; diff --git a/src/devices/machine/68307tmu.c b/src/devices/machine/68307tmu.c new file mode 100644 index 00000000000..23a67ada9ad --- /dev/null +++ b/src/devices/machine/68307tmu.c @@ -0,0 +1,245 @@ +// license:BSD-3-Clause +// copyright-holders:David Haywood +/* 68307 TIMER module */ +// 2x timers + +#include "emu.h" +#include "68307.h" + +READ16_MEMBER( m68307cpu_device::m68307_internal_timer_r ) +{ + m68307cpu_device *m68k = this; + m68307_timer* timer = m68k->m68307TIMER; + assert(timer != NULL); + + if (timer) + { + int pc = space.device().safe_pc(); + int which = offset & 0x8; + + switch (offset&0x7) + { + case m68307TIMER_TCN: /* 0x3 (0x126 / 0x136) */ + //if (pc!=0x2182e) logerror("%08x m68307_internal_timer_r %08x (%04x) (TCN - Timer Counter for timer %d)\n", pc, offset*2,mem_mask, which); + return timer->read_tcn(mem_mask, which); + + default: + logerror("%08x m68307_internal_timer_r %08x, (%04x)\n", pc, offset*2,mem_mask); + break; + } + } + + return 0x0000; +} + +WRITE16_MEMBER( m68307cpu_device::m68307_internal_timer_w ) +{ + m68307cpu_device *m68k = this; + m68307_timer* timer = m68k->m68307TIMER; + assert(timer != NULL); + + if (timer) + { + int pc = space.device().safe_pc(); + int which = offset & 0x8; + + switch (offset&0x7) + { + case m68307TIMER_TMR: /* 0x0 (0x120 / 0x130) */ + logerror("%08x m68307_internal_timer_w %08x, %04x (%04x) (TMR - Timer Mode Register for timer %d)\n", pc, offset*2,data,mem_mask, which); + timer->write_tmr(data, mem_mask, which); + break; + + case m68307TIMER_TRR: /* 0x1 (0x122 / 0x132) */ + logerror("%08x m68307_internal_timer_w %08x, %04x (%04x) (TRR - Timer Reference Register for timer %d)\n", pc, offset*2,data,mem_mask, which); + timer->write_trr(data, mem_mask, which); + break; + + case m68307TIMER_TCR: /* 0x2 (0x124 / 0x134) */ + logerror("%08x m68307_internal_timer_w %08x, %04x (%04x) (TCR - Timer Capture Register for timer %d) (illegal, read-only)\n", pc, offset*2,data,mem_mask, which); + break; + + case m68307TIMER_TCN: /* 0x3 (0x126 / 0x136) */ + logerror("%08x m68307_internal_timer_w %08x, %04x (%04x) (TCN - Timer Counter for timer %d)\n", pc, offset*2,data,mem_mask, which); + break; + + case m68307TIMER_TER: /* 0x4 (0x128 / 0x138) */ + /* 8-bit only!! */ + //logerror("%08x m68307_internal_timer_w %08x, %04x (%04x) (TER - Timer Event Register for timer %d)\n", pc, offset*2,data,mem_mask, which); + timer->write_ter(data, mem_mask, which); + break; + + case m68307TIMER_WRR: /* 0x5 (0x12a / 0x13a) */ + if (which==0) + { + logerror("%08x m68307_internal_timer_w %08x, %04x (%04x) (WRR - Watchdog Reference Register)\n", pc, offset*2,data,mem_mask); + } + else + { + logerror("%08x m68307_internal_timer_w %08x, %04x (%04x) (illegal)\n", pc, offset*2,data,mem_mask); + } + break; + + case m68307TIMER_WCR: /* 0x6 (0x12c / 0x13c) */ + if (which==0) + { + logerror("%08x m68307_internal_timer_w %08x, %04x (%04x) (WRR - Watchdog Counter Register)\n", pc, offset*2,data,mem_mask); + } + else + { + logerror("%08x m68307_internal_timer_w %08x, %04x (%04x) (illegal)\n", pc, offset*2,data,mem_mask); + } + break; + + case m68307TIMER_XXX: /* 0x7 (0x12e / 0x13e) */ + logerror("%08x m68307_internal_timer_w %08x, %04x (%04x) (illegal)\n", pc, offset*2,data,mem_mask); + break; + + } + } +} + +static TIMER_CALLBACK( m68307_timer0_callback ) +{ + m68307cpu_device* m68k = (m68307cpu_device *)ptr; + m68307_single_timer* tptr = &m68k->m68307TIMER->singletimer[0]; + tptr->regs[m68307TIMER_TMR] |= 0x2; + + m68k->timer0_interrupt(); + + tptr->mametimer->adjust(m68k->cycles_to_attotime(20000)); +} + +static TIMER_CALLBACK( m68307_timer1_callback ) +{ + m68307cpu_device* m68k = (m68307cpu_device *)ptr; + m68307_single_timer* tptr = &m68k->m68307TIMER->singletimer[1]; + tptr->regs[m68307TIMER_TMR] |= 0x2; + + m68k->timer1_interrupt(); + + tptr->mametimer->adjust(m68k->cycles_to_attotime(20000)); + +} + +static TIMER_CALLBACK( m68307_wd_timer_callback ) +{ + printf("wd timer\n"); +} + +void m68307_timer::init(m68307cpu_device *device) +{ + parent = device; + + m68307_single_timer* tptr; + + tptr = &singletimer[0]; + tptr->mametimer = device->machine().scheduler().timer_alloc(FUNC(m68307_timer0_callback), parent); + + tptr = &singletimer[1]; + tptr->mametimer = device->machine().scheduler().timer_alloc(FUNC(m68307_timer1_callback), parent); + + + wd_mametimer = device->machine().scheduler().timer_alloc(FUNC(m68307_wd_timer_callback), parent); + + +} + +UINT16 m68307_timer::read_tcn(UINT16 mem_mask, int which) +{ + // we should return the current timer value by + // calculating what it should be based on the time + // since it was last set + return 0x3a98; +} + +void m68307_timer::write_ter(UINT16 data, UINT16 mem_mask, int which) +{ + assert(which >= 0 && which < ARRAY_LENGTH(singletimer)); + m68307_single_timer* tptr = &singletimer[which]; + if (data & 0x2) tptr->regs[m68307TIMER_TMR] &= ~0x2; +} + +void m68307_timer::write_tmr(UINT16 data, UINT16 mem_mask, int which) +{ + m68307cpu_device* m68k = parent; + assert(which >= 0 && which < ARRAY_LENGTH(singletimer)); + m68307_single_timer* tptr = &singletimer[which]; + + COMBINE_DATA(&tptr->regs[m68307TIMER_TMR]); + + data = tptr->regs[m68307TIMER_TMR]; + + int ps = data & (0xff00)>>8; + int ce = data & (0x00c0)>>6; + int om = data & (0x0020)>>5; + int ori = data & (0x0010)>>4; + int frr = data & (0x0008)>>3; + int iclk = data & (0x0006)>>1; + int rst = data & (0x0001)>>0; + + + logerror("tmr value %04x : Details :\n", data); + logerror("prescale %d\n", ps); + logerror("(clock divided by %d)\n", ps+1); + logerror("capture edge / enable interrupt %d\n", ce); + if (ce==0x0) logerror("(disable interrupt on capture event)\n"); + if (ce==0x1) logerror("(capture on rising edge only + enable capture interrupt)\n"); + if (ce==0x2) logerror("(capture on falling edge only + enable capture interrupt)\n"); + if (ce==0x3) logerror("(capture on any edge + enable capture interrupt)\n"); + logerror("output mode %d\n", om); + if (om==0x0) logerror("(active-low pulse for one cycle))\n"); + if (om==0x1) logerror("(toggle output)\n"); + logerror("output reference interrupt %d\n", ori); + if (ori==0x0) logerror("(disable reference interrupt)\n"); + if (ori==0x1) logerror("(enable interrupt on reaching reference value))\n"); + logerror("free running %d\n", frr); + if (frr==0x0) logerror("(free running mode, counter continues after value reached)\n"); + if (frr==0x1) logerror("(restart mode, counter resets after value reached)\n"); + logerror("interrupt clock source %d\n", iclk); + if (iclk==0x0) logerror("(stop count)\n"); + if (iclk==0x1) logerror("(master system clock)\n"); + if (iclk==0x2) logerror("(master system clock divided by 16)\n"); + if (iclk==0x3) logerror("(TIN Pin)\n"); + logerror("reset %d\n", rst); + if (rst==0x0) logerror("(timer is reset)\n"); + if (rst==0x1) logerror("(timer is running)\n"); + + tptr->mametimer->adjust(m68k->cycles_to_attotime(100000)); + + logerror("\n"); + +} + +void m68307_timer::write_trr(UINT16 data, UINT16 mem_mask, int which) +{ + assert(which >= 0 && which < ARRAY_LENGTH(singletimer)); + m68307_single_timer* tptr = &singletimer[which]; + + COMBINE_DATA(&tptr->regs[m68307TIMER_TRR]); +} + + + +void m68307_timer::reset(void) +{ + for (int i=0;i<2;i++) + { + m68307_single_timer* tptr = &singletimer[i]; + + tptr->regs[m68307TIMER_TMR] = 0x0000; + tptr->regs[m68307TIMER_TRR] = 0xffff; + tptr->regs[m68307TIMER_TCR] = 0x0000; + tptr->regs[m68307TIMER_TCN] = 0x0000; + tptr->regs[m68307TIMER_TER] = 0x0000; + tptr->regs[m68307TIMER_WRR] = 0xffff; + tptr->regs[m68307TIMER_WCR] = 0xffff; + tptr->regs[m68307TIMER_XXX] = 0; + tptr->enabled = false; + tptr->mametimer->adjust(attotime::never); + } + + wd_mametimer->adjust(attotime::never); + + +} diff --git a/src/devices/machine/68307tmu.h b/src/devices/machine/68307tmu.h new file mode 100644 index 00000000000..2c62858b66d --- /dev/null +++ b/src/devices/machine/68307tmu.h @@ -0,0 +1,41 @@ +// license:BSD-3-Clause +// copyright-holders:David Haywood + +#include "cpu/m68000/m68000.h" + +class m68307cpu_device; + + +#define m68307TIMER_TMR (0x0) +#define m68307TIMER_TRR (0x1) +#define m68307TIMER_TCR (0x2) +#define m68307TIMER_TCN (0x3) +#define m68307TIMER_TER (0x4) +#define m68307TIMER_WRR (0x5) +#define m68307TIMER_WCR (0x6) +#define m68307TIMER_XXX (0x7) + +struct m68307_single_timer +{ + UINT16 regs[0x8]; + bool enabled; + emu_timer *mametimer; +}; + + +class m68307_timer +{ + public: + m68307_single_timer singletimer[2]; + + emu_timer *wd_mametimer; + m68307cpu_device *parent; + + void write_tmr(UINT16 data, UINT16 mem_mask, int which); + void write_trr(UINT16 data, UINT16 mem_mask, int which); + void write_ter(UINT16 data, UINT16 mem_mask, int which); + UINT16 read_tcn(UINT16 mem_mask, int which); + + void init(m68307cpu_device *device); + void reset(void); +}; diff --git a/src/devices/machine/68340.c b/src/devices/machine/68340.c new file mode 100644 index 00000000000..752a7be4592 --- /dev/null +++ b/src/devices/machine/68340.c @@ -0,0 +1,152 @@ +// license:BSD-3-Clause +// copyright-holders:David Haywood +/* 68340 */ + +#include "68340.h" + + + + +int m68340_calc_cs(m68340cpu_device *m68k, offs_t address) +{ + m68340_sim* sim = m68k->m68340SIM; + + if ( !(sim->m_ba[0] & 1) ) return 1; + + for (int i=0;i<4;i++) + { + if (sim->m_ba[i] & 1) + { + int mask = ((sim->m_am[i]&0xffffff00) | 0xff); + int base = sim->m_ba[i] & 0xffffff00; + int fcmask = (sim->m_am[i] & 0xf0); + int fcbase = (sim->m_ba[i] & 0xf0) & ~(sim->m_am[i] & 0xf0); + int fc = m68k->mmu_tmp_fc; + + if ((address & ~mask) == base && ((fc << 4) & ~fcmask ) == fcbase ) return i+1; + } + } + + return 0; +} + + + +UINT16 m68340_get_cs(m68340cpu_device *device, offs_t address) +{ + device->m68340_currentcs = m68340_calc_cs(device, address); + + return device->m68340_currentcs; +} + + + +/* 68340 specifics - MOVE */ + +READ32_MEMBER( m68340cpu_device::m68340_internal_base_r ) +{ + m68340cpu_device *m68k = this; + int pc = space.device().safe_pc(); + logerror("%08x m68340_internal_base_r %08x, (%08x)\n", pc, offset*4,mem_mask); + return m68k->m68340_base; +} + +WRITE32_MEMBER( m68340cpu_device::m68340_internal_base_w ) +{ + m68340cpu_device *m68k = this; + + int pc = space.device().safe_pc(); + logerror("%08x m68340_internal_base_w %08x, %08x (%08x)\n", pc, offset*4,data,mem_mask); + + // other conditions? + if (m68k->dfc==0x7) + { + // unmap old modules + if (m68k->m68340_base&1) + { + int base = m68k->m68340_base & 0xfffff000; + + m68k->internal->unmap_readwrite(base + 0x000, base + 0x05f); + m68k->internal->unmap_readwrite(base + 0x600, base + 0x67f); + m68k->internal->unmap_readwrite(base + 0x700, base + 0x723); + m68k->internal->unmap_readwrite(base + 0x780, base + 0x7bf); + + } + + COMBINE_DATA(&m68k->m68340_base); + logerror("%08x m68340_internal_base_w %08x, %08x (%08x) (m68340_base write)\n", pc, offset*4,data,mem_mask); + + // map new modules + if (m68k->m68340_base&1) + { + int base = m68k->m68340_base & 0xfffff000; + + m68k->internal->install_readwrite_handler(base + 0x000, base + 0x03f, read16_delegate(FUNC(m68340cpu_device::m68340_internal_sim_r),this), write16_delegate(FUNC(m68340cpu_device::m68340_internal_sim_w),this),0xffffffff); + m68k->internal->install_readwrite_handler(base + 0x010, base + 0x01f, read8_delegate(FUNC(m68340cpu_device::m68340_internal_sim_ports_r),this),write8_delegate(FUNC(m68340cpu_device::m68340_internal_sim_ports_w),this),0xffffffff); + m68k->internal->install_readwrite_handler(base + 0x040, base + 0x05f, read32_delegate(FUNC(m68340cpu_device::m68340_internal_sim_cs_r),this), write32_delegate(FUNC(m68340cpu_device::m68340_internal_sim_cs_w),this)); + m68k->internal->install_readwrite_handler(base + 0x600, base + 0x67f, read32_delegate(FUNC(m68340cpu_device::m68340_internal_timer_r),this), write32_delegate(FUNC(m68340cpu_device::m68340_internal_timer_w),this)); + m68k->internal->install_readwrite_handler(base + 0x700, base + 0x723, read32_delegate(FUNC(m68340cpu_device::m68340_internal_serial_r),this), write32_delegate(FUNC(m68340cpu_device::m68340_internal_serial_w),this)); + m68k->internal->install_readwrite_handler(base + 0x780, base + 0x7bf, read32_delegate(FUNC(m68340cpu_device::m68340_internal_dma_r),this), write32_delegate(FUNC(m68340cpu_device::m68340_internal_dma_w),this)); + + } + + } + else + { + logerror("%08x m68340_internal_base_w %08x, %04x (%04x) (should fall through?)\n", pc, offset*4,data,mem_mask); + } + + + +} + + +static ADDRESS_MAP_START( m68340_internal_map, AS_PROGRAM, 32, m68340cpu_device ) + AM_RANGE(0x0003ff00, 0x0003ff03) AM_READWRITE( m68340_internal_base_r, m68340_internal_base_w) +ADDRESS_MAP_END + + + + + +m68340cpu_device::m68340cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : fscpu32_device(mconfig, "MC68340", tag, owner, clock, M68340, 32,32, ADDRESS_MAP_NAME(m68340_internal_map), "mc68340", __FILE__) +{ + m68340SIM = 0; + m68340DMA = 0; + m68340SERIAL = 0; + m68340TIMER = 0; + m68340_base = 0; +} + + + + + + +void m68340cpu_device::device_reset() +{ + fscpu32_device::device_reset(); +} + + +void m68340cpu_device::device_start() +{ + fscpu32_device::device_start(); + + m68340SIM = new m68340_sim(); + m68340DMA = new m68340_dma(); + m68340SERIAL = new m68340_serial(); + m68340TIMER = new m68340_timer(); + + m68340SIM->reset(); + m68340DMA->reset(); + m68340SERIAL->reset(); + m68340TIMER->reset(); + + start_68340_sim(); + + m68340_base = 0x00000000; + + internal = &this->space(AS_PROGRAM); +} diff --git a/src/devices/machine/68340.h b/src/devices/machine/68340.h new file mode 100644 index 00000000000..6f1260ae1cb --- /dev/null +++ b/src/devices/machine/68340.h @@ -0,0 +1,75 @@ +// license:BSD-3-Clause +// copyright-holders:David Haywood +/* 68340 */ + + +#pragma once +#ifndef __M68340_H__ +#define __M68340_H__ + +#include "emu.h" +#include "cpu/m68000/m68000.h" + +#include "68340sim.h" +#include "68340dma.h" +#include "68340ser.h" +#include "68340tmu.h" + + + + + +class m68340cpu_device : public fscpu32_device { +public: + m68340cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + + int m68340_currentcs; + + /* 68340 peripheral modules */ + m68340_sim* m68340SIM; + m68340_dma* m68340DMA; + m68340_serial* m68340SERIAL; + m68340_timer* m68340TIMER; + + UINT32 m68340_base; + + UINT16 m_avr; + UINT16 m_picr; + UINT16 m_pitr; + + READ32_MEMBER( m68340_internal_base_r ); + WRITE32_MEMBER( m68340_internal_base_w ); + READ32_MEMBER( m68340_internal_dma_r ); + WRITE32_MEMBER( m68340_internal_dma_w ); + READ32_MEMBER( m68340_internal_serial_r ); + WRITE32_MEMBER( m68340_internal_serial_w ); + READ16_MEMBER( m68340_internal_sim_r ); + READ8_MEMBER( m68340_internal_sim_ports_r ); + READ32_MEMBER( m68340_internal_sim_cs_r ); + WRITE16_MEMBER( m68340_internal_sim_w ); + WRITE8_MEMBER( m68340_internal_sim_ports_w ); + WRITE32_MEMBER( m68340_internal_sim_cs_w ); + READ32_MEMBER( m68340_internal_timer_r ); + WRITE32_MEMBER( m68340_internal_timer_w ); + + emu_timer *m_irq_timer; + TIMER_CALLBACK_MEMBER(periodic_interrupt_timer_callback); + void start_68340_sim(void); + void do_timer_irq(void); +protected: + + virtual void device_start(); + virtual void device_reset(); + +}; + +static const device_type M68340 = &device_creator; + +extern UINT16 m68340_get_cs(m68340cpu_device *device, offs_t address); + + + + + +#endif diff --git a/src/devices/machine/68340dma.c b/src/devices/machine/68340dma.c new file mode 100644 index 00000000000..9ee0ae5114e --- /dev/null +++ b/src/devices/machine/68340dma.c @@ -0,0 +1,39 @@ +// license:BSD-3-Clause +// copyright-holders:David Haywood +/* 68340 DMA module */ + +#include "emu.h" +#include "68340.h" + + +READ32_MEMBER( m68340cpu_device::m68340_internal_dma_r ) +{ + m68340cpu_device *m68k = this; + m68340_dma* dma = m68k->m68340DMA; + assert(dma != NULL); + + if (dma) + { + int pc = space.device().safe_pc(); + logerror("%08x m68340_internal_dma_r %08x, (%08x)\n", pc, offset*4,mem_mask); + } + + return 0x00000000; +} + +WRITE32_MEMBER( m68340cpu_device::m68340_internal_dma_w ) +{ + m68340cpu_device *m68k = this; + m68340_dma* dma = m68k->m68340DMA; + assert(dma != NULL); + + if (dma) + { + int pc = space.device().safe_pc(); + logerror("%08x m68340_internal_dma_w %08x, %08x (%08x)\n", pc, offset*4,data,mem_mask); + } +} + +void m68340_dma::reset(void) +{ +} diff --git a/src/devices/machine/68340dma.h b/src/devices/machine/68340dma.h new file mode 100644 index 00000000000..56d8228fa2d --- /dev/null +++ b/src/devices/machine/68340dma.h @@ -0,0 +1,10 @@ +// license:BSD-3-Clause +// copyright-holders:David Haywood + +#include "cpu/m68000/m68000.h" + +class m68340_dma +{ + public: + void reset(void); +}; diff --git a/src/devices/machine/68340ser.c b/src/devices/machine/68340ser.c new file mode 100644 index 00000000000..9e4118ec92e --- /dev/null +++ b/src/devices/machine/68340ser.c @@ -0,0 +1,40 @@ +// license:BSD-3-Clause +// copyright-holders:David Haywood +/* 68340 SERIAL module */ + +#include "emu.h" +#include "68340.h" + + +READ32_MEMBER( m68340cpu_device::m68340_internal_serial_r ) +{ + m68340cpu_device *m68k = this; + m68340_serial* serial = m68k->m68340SERIAL; + assert(serial != NULL); + + if (serial) + { + int pc = space.device().safe_pc(); + logerror("%08x m68340_internal_serial_r %08x, (%08x)\n", pc, offset*4,mem_mask); + } + + return 0x00000000; +} + +WRITE32_MEMBER( m68340cpu_device::m68340_internal_serial_w ) +{ + m68340cpu_device *m68k = this; + m68340_serial* serial = m68k->m68340SERIAL; + assert(serial != NULL); + + if (serial) + { + int pc = space.device().safe_pc(); + logerror("%08x m68340_internal_serial_w %08x, %08x (%08x)\n", pc, offset*4,data,mem_mask); + } + +} + +void m68340_serial::reset(void) +{ +} diff --git a/src/devices/machine/68340ser.h b/src/devices/machine/68340ser.h new file mode 100644 index 00000000000..0fda812ff0a --- /dev/null +++ b/src/devices/machine/68340ser.h @@ -0,0 +1,10 @@ +// license:BSD-3-Clause +// copyright-holders:David Haywood + +#include "cpu/m68000/m68000.h" + +class m68340_serial +{ + public: + void reset(void); +}; diff --git a/src/devices/machine/68340sim.c b/src/devices/machine/68340sim.c new file mode 100644 index 00000000000..88e56d78763 --- /dev/null +++ b/src/devices/machine/68340sim.c @@ -0,0 +1,349 @@ +// license:BSD-3-Clause +// copyright-holders:David Haywood +/* 68340 SIM module */ + +#include "emu.h" +#include "68340.h" + + + +READ16_MEMBER( m68340cpu_device::m68340_internal_sim_r ) +{ + m68340cpu_device *m68k = this; + m68340_sim* sim = m68k->m68340SIM; + assert(sim != NULL); + + if (sim) + { + int pc = space.device().safe_pc(); + + switch (offset<<1) + { + case m68340SIM_MCR: + logerror("%08x m68340_internal_sim_r %04x, (%04x) (MCR - Module Configuration Register)\n", pc, offset*2,mem_mask); + return space.machine().rand(); + + case m68340SIM_SYNCR: + logerror("%08x m68340_internal_sim_r %04x, (%04x) (SYNCR - Clock Synthesizer Register)\n", pc, offset*2,mem_mask); + return space.machine().rand(); + + case m68340SIM_AVR_RSR: + logerror("%08x m68340_internal_sim_r %04x, (%04x) (AVR, RSR - Auto Vector Register, Reset Status Register)\n", pc, offset*2,mem_mask); + return space.machine().rand(); + + case m68340SIM_SWIV_SYPCR: + logerror("%08x m68340_internal_sim_r %04x, (%04x) (SWIV_SYPCR - Software Interrupt Vector, System Protection Control Register)\n", pc, offset*2,mem_mask); + return space.machine().rand(); + + case m68340SIM_PICR: + logerror("%08x m68340_internal_sim_r %04x, (%04x) (PICR - Periodic Interrupt Control Register)\n", pc, offset*2,mem_mask); + return space.machine().rand(); + + case m68340SIM_PITR: + logerror("%08x m68340_internal_sim_r %04x, (%04x) (PITR - Periodic Interrupt Timer Register)\n", pc, offset*2,mem_mask); + return space.machine().rand(); + + case m68340SIM_SWSR: + logerror("%08x m68340_internal_sim_r %04x, (%04x) (SWSR - Software Service)\n", pc, offset*2,mem_mask); + return space.machine().rand(); + + default: + logerror("%08x m68340_internal_sim_r %04x, (%04x)\n", pc, offset*2,mem_mask); + + + } + } + + return 0x0000; +} + +READ8_MEMBER( m68340cpu_device::m68340_internal_sim_ports_r ) +{ + offset += 0x10; + m68340cpu_device *m68k = this; + m68340_sim* sim = m68k->m68340SIM; + assert(sim != NULL); + + if (sim) + { + int pc = space.device().safe_pc(); + + switch (offset) + { + case m68340SIM_PORTA: + logerror("%08x m68340_internal_sim_r %04x (PORTA - Port A Data)\n", pc, offset); + return space.machine().rand(); + + case m68340SIM_DDRA: + logerror("%08x m68340_internal_sim_r %04x (DDRA - Port A Data Direction)\n", pc, offset); + return space.machine().rand(); + + case m68340SIM_PPRA1: + logerror("%08x m68340_internal_sim_r %04x (PPRA1 - Port A Pin Assignment 1)\n", pc, offset); + return space.machine().rand(); + + case m68340SIM_PPRA2: + logerror("%08x m68340_internal_sim_r %04x (PPRA2 - Port A Pin Assignment 2)\n", pc, offset); + return space.machine().rand(); + + case m68340SIM_PORTB: + logerror("%08x m68340_internal_sim_r %04x (PORTB - Port B Data 0)\n", pc, offset); + return space.machine().rand(); + + case m68340SIM_PORTB1: + logerror("%08x m68340_internal_sim_r %04x (PORTB1 - Port B Data 1)\n", pc, offset); + return space.machine().rand(); + + case m68340SIM_DDRB: + logerror("%08x m68340_internal_sim_r %04x (DDR - Port B Data Direction)\n", pc, offset); + return space.machine().rand(); + + case m68340SIM_PPARB: + logerror("%08x m68340_internal_sim_r %04x (PPARB - Port B Pin Assignment)\n", pc, offset); + return space.machine().rand(); + + default: + logerror("%08x m68340_internal_sim_r %04x (ILLEGAL?)\n", pc, offset); + return space.machine().rand(); + + } + } + + return 0x00; +} + +READ32_MEMBER( m68340cpu_device::m68340_internal_sim_cs_r ) +{ + offset += m68340SIM_AM_CS0>>2; + + m68340cpu_device *m68k = this; + m68340_sim* sim = m68k->m68340SIM; + assert(sim != NULL); + + if (sim) + { + int pc = space.device().safe_pc(); + + switch (offset<<2) + { + case m68340SIM_AM_CS0: return sim->m_am[0]; + case m68340SIM_BA_CS0: return sim->m_ba[0]; + case m68340SIM_AM_CS1: return sim->m_am[1]; + case m68340SIM_BA_CS1: return sim->m_ba[1]; + case m68340SIM_AM_CS2: return sim->m_am[2]; + case m68340SIM_BA_CS2: return sim->m_ba[2]; + case m68340SIM_AM_CS3: return sim->m_am[3]; + case m68340SIM_BA_CS3: return sim->m_ba[3]; + + default: + logerror("%08x m68340_internal_sim_r %08x, (%08x)\n", pc, offset*4,mem_mask); + + } + } + + return 0x00000000; +} + +WRITE16_MEMBER( m68340cpu_device::m68340_internal_sim_w ) +{ + m68340cpu_device *m68k = this; + m68340_sim* sim = m68k->m68340SIM; + assert(sim != NULL); + + if (sim) + { + int pc = space.device().safe_pc(); + + switch (offset<<1) + { + case m68340SIM_MCR: + logerror("%08x m68340_internal_sim_w %04x, %04x (%04x) (MCR - Module Configuration Register)\n", pc, offset*2,data,mem_mask); + break; + + case m68340SIM_SYNCR: + logerror("%08x m68340_internal_sim_w %04x, %04x (%04x) (SYNCR - Clock Synthesizer Register)\n", pc, offset*2,data,mem_mask); + break; + + + case m68340SIM_AVR_RSR: + logerror("%08x m68340_internal_sim_w %04x, %04x (%04x) (AVR, RSR - Auto Vector Register, Reset Status Register)\n", pc, offset*2,data,mem_mask); + COMBINE_DATA(&m_avr); + break; + + case m68340SIM_SWIV_SYPCR: + logerror("%08x m68340_internal_sim_w %04x, %04x (%04x) (SWIV_SYPCR - Software Interrupt Vector, System Protection Control Register)\n", pc, offset*2,data,mem_mask); + break; + + case m68340SIM_PICR: + logerror("%08x m68340_internal_sim_w %04x, %04x (%04x) (PICR - Periodic Interrupt Control Register)\n", pc, offset*2,data,mem_mask); + COMBINE_DATA(&m_picr); + break; + + case m68340SIM_PITR: + logerror("%08x m68340_internal_sim_w %04x, %04x (%04x) (PITR - Periodic Interrupt Timer Register)\n", pc, offset*2,data,mem_mask); + COMBINE_DATA(&m_pitr); + if (m_pitr !=0 ) // hack + { + //logerror("timer set\n"); + m_irq_timer->adjust(cycles_to_attotime(20000)); // hack + } + + break; + + case m68340SIM_SWSR: + // basically watchdog, you must write an alternating pattern of 0x55 / 0xaa to keep the watchdog from resetting the system + //logerror("%08x m68340_internal_sim_w %04x, %04x (%04x) (SWSR - Software Service)\n", pc, offset*2,data,mem_mask); + break; + + default: + logerror("%08x m68340_internal_sim_w %04x, %04x (%04x)\n", pc, offset*2,data,mem_mask); + + } + } +} + +WRITE8_MEMBER( m68340cpu_device::m68340_internal_sim_ports_w ) +{ + offset += 0x10; + m68340cpu_device *m68k = this; + m68340_sim* sim = m68k->m68340SIM; + assert(sim != NULL); + + if (sim) + { + int pc = space.device().safe_pc(); + + switch (offset) + { + case m68340SIM_PORTA: + logerror("%08x m68340_internal_sim_w %04x, %02x (PORTA - Port A Data)\n", pc, offset,data); + break; + + case m68340SIM_DDRA: + logerror("%08x m68340_internal_sim_w %04x, %02x (DDRA - Port A Data Direction)\n", pc, offset,data); + break; + + case m68340SIM_PPRA1: + logerror("%08x m68340_internal_sim_w %04x, %02x (PPRA1 - Port A Pin Assignment 1)\n", pc, offset,data); + break; + + case m68340SIM_PPRA2: + logerror("%08x m68340_internal_sim_w %04x, %02x (PPRA2 - Port A Pin Assignment 2)\n", pc, offset,data); + break; + + case m68340SIM_PORTB: + logerror("%08x m68340_internal_sim_w %04x, %02x (PORTB - Port B Data)\n", pc, offset,data); + break; + + case m68340SIM_PORTB1: + logerror("%08x m68340_internal_sim_w %04x, %02x (PORTB1 - Port B Data - mirror)\n", pc, offset,data); + break; + + case m68340SIM_DDRB: + logerror("%08x m68340_internal_sim_w %04x, %02x (DDR - Port B Data Direction)\n", pc, offset,data); + break; + + case m68340SIM_PPARB: + logerror("%08x m68340_internal_sim_w %04x, %02x (PPARB - Port B Pin Assignment)\n", pc, offset,data); + break; + + default: + logerror("%08x m68340_internal_sim_w %04x, %02x (ILLEGAL?)\n", pc, offset,data); + break; + + } + } +} + +WRITE32_MEMBER( m68340cpu_device::m68340_internal_sim_cs_w ) +{ + offset += m68340SIM_AM_CS0>>2; + m68340cpu_device *m68k = this; + m68340_sim* sim = m68k->m68340SIM; + assert(sim != NULL); + + if (sim) + { + int pc = space.device().safe_pc(); + + switch (offset<<2) + { + case m68340SIM_AM_CS0: + COMBINE_DATA(&sim->m_am[0]); + break; + + case m68340SIM_BA_CS0: + COMBINE_DATA(&sim->m_ba[0]); + break; + + case m68340SIM_AM_CS1: + COMBINE_DATA(&sim->m_am[1]); + break; + + case m68340SIM_BA_CS1: + COMBINE_DATA(&sim->m_ba[1]); + break; + + case m68340SIM_AM_CS2: + COMBINE_DATA(&sim->m_am[2]); + break; + + case m68340SIM_BA_CS2: + COMBINE_DATA(&sim->m_ba[2]); + break; + + case m68340SIM_AM_CS3: + COMBINE_DATA(&sim->m_am[3]); + break; + + case m68340SIM_BA_CS3: + COMBINE_DATA(&sim->m_ba[3]); + break; + + default: + logerror("%08x m68340_internal_sim_w %08x, %08x (%08x)\n", pc, offset*4,data,mem_mask); + break; + + } + } + +} + +void m68340cpu_device::do_timer_irq(void) +{ + //logerror("do_timer_irq\n"); + int timer_irq_level = (m_picr & 0x0700)>>8; + int timer_irq_vector = (m_picr & 0x00ff)>>0; + + if (timer_irq_level) // 0 is irq disabled + { + int use_autovector = (m_avr >> timer_irq_level)&1; + + if (use_autovector) + { + //logerror("irq with autovector\n"); + set_input_line(timer_irq_level, HOLD_LINE); + } + else + { + //logerror("irq without autovector\n"); + set_input_line_and_vector(timer_irq_level, HOLD_LINE, timer_irq_vector); + } + + } +} + +TIMER_CALLBACK_MEMBER(m68340cpu_device::periodic_interrupt_timer_callback) +{ + do_timer_irq(); + m_irq_timer->adjust(cycles_to_attotime(20000)); // hack +} + +void m68340cpu_device::start_68340_sim(void) +{ + m_irq_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(m68340cpu_device::periodic_interrupt_timer_callback),this)); +} + +void m68340_sim::reset(void) +{ +} diff --git a/src/devices/machine/68340sim.h b/src/devices/machine/68340sim.h new file mode 100644 index 00000000000..493fa9805ce --- /dev/null +++ b/src/devices/machine/68340sim.h @@ -0,0 +1,60 @@ +// license:BSD-3-Clause +// copyright-holders:David Haywood + +#include "cpu/m68000/m68000.h" + +#define m68340SIM_MCR (0x00) +// (0x02) +#define m68340SIM_SYNCR (0x04) +#define m68340SIM_AVR_RSR (0x06) +// (0x08) +// (0x0a) +// (0x0c) +// (0x0e) +#define m68340SIM_PORTA (0x11) +#define m68340SIM_DDRA (0x13) +#define m68340SIM_PPRA1 (0x15) +#define m68340SIM_PPRA2 (0x17) +#define m68340SIM_PORTB (0x19) +#define m68340SIM_PORTB1 (0x1b) +#define m68340SIM_DDRB (0x1d) +#define m68340SIM_PPARB (0x1f) +#define m68340SIM_SWIV_SYPCR (0x20) +#define m68340SIM_PICR (0x22) +#define m68340SIM_PITR (0x24) +#define m68340SIM_SWSR (0x26) +// (0x28) +// (0x2a) +// (0x2c) +// (0x2e) +// (0x30) +// (0x32) +// (0x34) +// (0x36) +// (0x38) +// (0x3a) +// (0x3c) +// (0x3e) +#define m68340SIM_AM_CS0 (0x40) +#define m68340SIM_BA_CS0 (0x44) +#define m68340SIM_AM_CS1 (0x48) +#define m68340SIM_BA_CS1 (0x4c) +#define m68340SIM_AM_CS2 (0x50) +#define m68340SIM_BA_CS2 (0x54) +#define m68340SIM_AM_CS3 (0x58) +#define m68340SIM_BA_CS3 (0x5c) + + + + + + +class m68340_sim +{ + public: + + UINT32 m_am[4]; + UINT32 m_ba[4]; + + void reset(void); +}; diff --git a/src/devices/machine/68340tmu.c b/src/devices/machine/68340tmu.c new file mode 100644 index 00000000000..f8109214ba0 --- /dev/null +++ b/src/devices/machine/68340tmu.c @@ -0,0 +1,39 @@ +// license:BSD-3-Clause +// copyright-holders:David Haywood +/* 68340 TIMER module */ + +#include "emu.h" +#include "68340.h" + + +READ32_MEMBER( m68340cpu_device::m68340_internal_timer_r ) +{ + m68340cpu_device *m68k = this; + m68340_timer* timer = m68k->m68340TIMER; + assert(timer != NULL); + + if (timer) + { + int pc = space.device().safe_pc(); + logerror("%08x m68340_internal_timer_r %08x, (%08x)\n", pc, offset*4,mem_mask); + } + + return 0x00000000; +} + +WRITE32_MEMBER( m68340cpu_device::m68340_internal_timer_w ) +{ + m68340cpu_device *m68k = this; + m68340_timer* timer = m68k->m68340TIMER; + assert(timer != NULL); + + if (timer) + { + int pc = space.device().safe_pc(); + logerror("%08x m68340_internal_timer_w %08x, %08x (%08x)\n", pc, offset*4,data,mem_mask); + } +} + +void m68340_timer::reset(void) +{ +} diff --git a/src/devices/machine/68340tmu.h b/src/devices/machine/68340tmu.h new file mode 100644 index 00000000000..a892e2792d8 --- /dev/null +++ b/src/devices/machine/68340tmu.h @@ -0,0 +1,10 @@ +// license:BSD-3-Clause +// copyright-holders:David Haywood +#include "cpu/m68000/m68000.h" + + +class m68340_timer +{ + public: + void reset(void); +}; diff --git a/src/devices/machine/6840ptm.c b/src/devices/machine/6840ptm.c new file mode 100644 index 00000000000..239498f681c --- /dev/null +++ b/src/devices/machine/6840ptm.c @@ -0,0 +1,755 @@ +// license:BSD-3-Clause +// copyright-holders:James Wallace +/*************************************************************************** + + Motorola 6840 (PTM) + + Programmable Timer Module + + Written By J.Wallace based on previous work by Aaron Giles, + 'Re-Animator' and Mathis Rosenhauer. + + Todo: + Confirm handling for 'Single Shot' operation. + (Datasheet suggests that output starts high, going low + on timeout, opposite of continuous case) + Establish whether ptm6840_set_c? routines can replace + hard coding of external clock frequencies. + + + Operation: + The interface is arranged as follows: + + Internal Clock frequency, + Clock 1 frequency, Clock 2 frequency, Clock 3 frequency, + Clock 1 output, Clock 2 output, Clock 3 output, + IRQ function + + If the external clock frequencies are not fixed, they should be + entered as '0', and the ptm6840_set_c?(which, state) functions + should be used instead if necessary (This should allow the VBLANK + clock on the MCR units to operate). + + + 2009-06 Converted to be a device + +***************************************************************************/ + +#include "emu.h" +#include "6840ptm.h" + + +#define PTMVERBOSE 0 +#define PLOG(x) do { if (PTMVERBOSE) logerror x; } while (0) + +/*************************************************************************** + LOCAL VARIABLES +***************************************************************************/ + +const char *const ptm6840_device::opmode[] = +{ + "000 continuous mode", + "001 freq comparison mode", + "010 continuous mode", + "011 pulse width comparison mode", + "100 single shot mode", + "101 freq comparison mode", + "110 single shot mode", + "111 pulse width comparison mode" +}; + +/*************************************************************************** + IMPLEMENTATION +***************************************************************************/ + +// device type definition +const device_type PTM6840 = &device_creator; + +//------------------------------------------------- +// ptm6840_device - constructor +//------------------------------------------------- + +ptm6840_device::ptm6840_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, PTM6840, "6840 PTM", tag, owner, clock, "ptm6840", __FILE__), + m_internal_clock(0.0), + m_out0_cb(*this), + m_out1_cb(*this), + m_out2_cb(*this), + m_irq_cb(*this) +{ + m_external_clock[0] = m_external_clock[1] = m_external_clock[2] = 0.0; +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void ptm6840_device::device_start() +{ + // resolve callbacks + m_out0_cb.resolve_safe(); + m_out1_cb.resolve_safe(); + m_out2_cb.resolve_safe(); + m_irq_cb.resolve_safe(); + + for (int i = 0; i < 3; i++) + { + if ( m_external_clock[i] == 0 ) + m_external_clock[i] = 1; + } + + m_timer[0] = timer_alloc(0); + m_timer[1] = timer_alloc(1); + m_timer[2] = timer_alloc(2); + + for (int i = 0; i < 3; i++) + { + m_timer[i]->enable(false); + } + + // register for state saving + save_item(NAME(m_lsb_buffer)); + save_item(NAME(m_msb_buffer)); + save_item(NAME(m_status_read_since_int)); + save_item(NAME(m_status_reg)); + save_item(NAME(m_t3_divisor)); + save_item(NAME(m_t3_scaler)); + save_item(NAME(m_internal_clock)); + save_item(NAME(m_IRQ)); + + save_item(NAME(m_control_reg)); + save_item(NAME(m_output)); + save_item(NAME(m_gate)); + save_item(NAME(m_clk)); + save_item(NAME(m_mode)); + save_item(NAME(m_fired)); + save_item(NAME(m_enabled)); + save_item(NAME(m_external_clock)); + save_item(NAME(m_counter)); + save_item(NAME(m_latch)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void ptm6840_device::device_reset() +{ + m_control_reg[2] = 0; + m_control_reg[1] = 0; + m_control_reg[0] = 1; + m_status_reg = 0; + m_t3_divisor = 1; + m_status_read_since_int = 0; + m_IRQ = 0; + m_t3_scaler = 0; + for (int i = 0; i < 3; i++) + { + m_counter[i] = 0xffff; + m_latch[i] = 0xffff; + m_output[i] = 0; + m_fired[i] = 0; + m_enabled[i] = 0; + m_mode[i] = 0; + } +} + + +//------------------------------------------------- +// device_timer - handle timer callbacks +//------------------------------------------------- + +void ptm6840_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + timeout(id); +} + + +//------------------------------------------------- +// subtract_from_counter - Subtract from Counter +//------------------------------------------------- + +void ptm6840_device::subtract_from_counter(int counter, int count) +{ + double clock; + + // Determine the clock frequency for this timer + if (m_control_reg[counter] & 0x02) + { + clock = m_internal_clock; + } + else + { + clock = m_external_clock[counter]; + } + + // Dual-byte mode + if (m_control_reg[counter] & 0x04) + { + int lsb = m_counter[counter] & 0xff; + int msb = m_counter[counter] >> 8; + + // Count the clocks + lsb -= count; + + // Loop while we're less than zero + while (lsb < 0) + { + // Borrow from the MSB + lsb += (m_latch[counter] & 0xff) + 1; + msb--; + + // If MSB goes less than zero, we've expired + if (msb < 0) + { + timeout(counter); + msb = (m_latch[counter] >> 8) + 1; + } + } + + // Store the result + m_counter[counter] = (msb << 8) | lsb; + } + + // Word mode + else + { + int word = m_counter[counter]; + + // Count the clocks + word -= count; + + // loop while we're less than zero + while (word < 0) + { + // Borrow from the MSB + word += m_latch[counter] + 1; + + // We've expired + timeout(counter); + } + + // Store the result + m_counter[counter] = word; + } + + if (m_enabled[counter]) + { + attotime duration = attotime::from_hz(clock) * m_counter[counter]; + + if (counter == 2) + { + duration *= m_t3_divisor; + } + + m_timer[counter]->adjust(duration); + } +} + + + +//------------------------------------------------- +// tick +//------------------------------------------------- + +void ptm6840_device::tick(int counter, int count) +{ + if (counter == 2) + { + m_t3_scaler += count; + + if ( m_t3_scaler > m_t3_divisor - 1) + { + subtract_from_counter(counter, 1); + m_t3_scaler = 0; + } + } + else + { + subtract_from_counter(counter, count); + } +} + + + +//------------------------------------------------- +// update_interrupts - Update Internal Interrupts +//------------------------------------------------- + +void ptm6840_device::update_interrupts() +{ + int new_state = ((m_status_reg & 0x01) && (m_control_reg[0] & 0x40)) || + ((m_status_reg & 0x02) && (m_control_reg[1] & 0x40)) || + ((m_status_reg & 0x04) && (m_control_reg[2] & 0x40)); + + if (new_state != m_IRQ) + { + m_IRQ = new_state; + + if (m_IRQ) + { + m_status_reg |= 0x80; + } + else + { + m_status_reg &= ~0x80; + } + + m_irq_cb(m_IRQ); + } +} + + + +//------------------------------------------------- +// compute_counter - Compute Counter +//------------------------------------------------- + +UINT16 ptm6840_device::compute_counter( int counter ) const +{ + double clock; + + // If there's no timer, return the count + if (!m_enabled[counter]) + { + PLOG(("MC6840 #%s: read counter(%d): %d\n", tag(), counter, m_counter[counter])); + return m_counter[counter]; + } + + // determine the clock frequency for this timer + if (m_control_reg[counter] & 0x02) + { + clock = m_internal_clock; + PLOG(("MC6840 #%s: %d internal clock freq %f \n", tag(), counter, clock)); + } + else + { + clock = m_external_clock[counter]; + PLOG(("MC6840 #%s: %d external clock freq %f \n", tag(), counter, clock)); + } + // See how many are left + int remaining = (m_timer[counter]->remaining() * clock).as_double(); + + // Adjust the count for dual byte mode + if (m_control_reg[counter] & 0x04) + { + int divisor = (m_counter[counter] & 0xff) + 1; + int msb = remaining / divisor; + int lsb = remaining % divisor; + remaining = (msb << 8) | lsb; + } + PLOG(("MC6840 #%s: read counter(%d): %d\n", tag(), counter, remaining)); + return remaining; +} + + + +//------------------------------------------------- +// reload_count - Reload Counter +//------------------------------------------------- + +void ptm6840_device::reload_count(int idx) +{ + double clock; + + // Copy the latched value in + m_counter[idx] = m_latch[idx]; + + // Determine the clock frequency for this timer + if (m_control_reg[idx] & 0x02) + { + clock = m_internal_clock; + PLOG(("MC6840 #%s: %d internal clock freq %f \n", tag(), idx, clock)); + } + else + { + clock = m_external_clock[idx]; + PLOG(("MC6840 #%s: %d external clock freq %f \n", tag(), idx, clock)); + } + + // Determine the number of clock periods before we expire + int count = m_counter[idx]; + if (m_control_reg[idx] & 0x04) + { + count = ((count >> 8) + 1) * ((count & 0xff) + 1); + } + else + { + count = count + 1; + } + + m_fired[idx] = 0; + + if ((m_mode[idx] == 4) || (m_mode[idx] == 6)) + { + m_output[idx] = 1; + switch (idx) + { + case 0: + m_out0_cb((offs_t)0, m_output[0]); + break; + case 1: + m_out1_cb((offs_t)0, m_output[1]); + break; + case 2: + m_out2_cb((offs_t)0, m_output[2]); + break; + } + } + + // Set the timer + PLOG(("MC6840 #%s: reload_count(%d): clock = %f count = %d\n", tag(), idx, clock, count)); + + attotime duration = attotime::from_hz(clock) * count; + if (idx == 2) + { + duration *= m_t3_divisor; + } + + PLOG(("MC6840 #%s: reload_count(%d): output = %f\n", tag(), idx, duration.as_double())); + +#if 0 + if (!(m_control_reg[idx] & 0x02)) + { + if (!m_external_clock[idx]) + { + m_enabled[idx] = 0; + m_timer[idx]->enable(false); + } + } + else +#endif + { + m_enabled[idx] = 1; + m_timer[idx]->adjust(duration); + m_timer[idx]->enable(true); + } +} + + + +//------------------------------------------------- +// read - Read Timer +//------------------------------------------------- + +READ8_MEMBER( ptm6840_device::read ) +{ + int val; + + switch ( offset ) + { + case PTM_6840_CTRL1: + { + val = 0; + break; + } + + case PTM_6840_STATUS: + { + PLOG(("%s: MC6840 #%s: Status read = %04X\n", machine().describe_context(), tag(), m_status_reg)); + m_status_read_since_int |= m_status_reg & 0x07; + val = m_status_reg; + break; + } + + case PTM_6840_MSBBUF1: + case PTM_6840_MSBBUF2: + case PTM_6840_MSBBUF3: + { + int idx = (offset - 2) / 2; + int result = compute_counter(idx); + + // Clear the interrupt if the status has been read + if (m_status_read_since_int & (1 << idx)) + { + m_status_reg &= ~(1 << idx); + update_interrupts(); + } + + m_lsb_buffer = result & 0xff; + + PLOG(("%s: MC6840 #%s: Counter %d read = %04X\n", machine().describe_context(), tag(), idx, result >> 8)); + val = result >> 8; + break; + } + + case PTM_6840_LSB1: + case PTM_6840_LSB2: + case PTM_6840_LSB3: + { + val = m_lsb_buffer; + break; + } + + default: + { + val = 0; + break; + } + + } + return val; +} + + +//------------------------------------------------- +// write - Write Timer +//------------------------------------------------- + +WRITE8_MEMBER( ptm6840_device::write ) +{ + switch ( offset ) + { + case PTM_6840_CTRL1: + case PTM_6840_CTRL2: + { + int idx = (offset == 1) ? 1 : (m_control_reg[1] & 0x01) ? 0 : 2; + UINT8 diffs = data ^ m_control_reg[idx]; + m_t3_divisor = (m_control_reg[2] & 0x01) ? 8 : 1; + m_mode[idx] = (data >> 3) & 0x07; + m_control_reg[idx] = data; + + PLOG(("MC6840 #%s : Control register %d selected\n", tag(), idx)); + PLOG(("operation mode = %s\n", opmode[ m_mode[idx] ])); + PLOG(("value = %04X\n", m_control_reg[idx])); + PLOG(("t3divisor = %d\n", m_t3_divisor)); + + if (!(m_control_reg[idx] & 0x80 )) + { + // Output cleared + switch (idx) + { + case 0: + m_out0_cb((offs_t)0, 0); + break; + case 1: + m_out1_cb((offs_t)0, 0); + break; + case 2: + m_out2_cb((offs_t)0, 0); + break; + } + } + // Reset? + if (idx == 0 && (diffs & 0x01)) + { + // Holding reset down + if (data & 0x01) + { + PLOG(("MC6840 #%s : Timer reset\n", tag())); + for (int i = 0; i < 3; i++) + { + m_timer[i]->enable(false); + m_enabled[i] = 0; + } + } + // Releasing reset + else + { + for (int i = 0; i < 3; i++) + { + reload_count(i); + } + } + + m_status_reg = 0; + update_interrupts(); + + // Changing the clock source? (e.g. Zwackery) + if (diffs & 0x02) + { + reload_count(idx); + } + } + break; + } + + case PTM_6840_MSBBUF1: + case PTM_6840_MSBBUF2: + case PTM_6840_MSBBUF3: + { + PLOG(("MC6840 #%s msbbuf%d = %02X\n", tag(), offset / 2, data)); + m_msb_buffer = data; + break; + } + + case PTM_6840_LSB1: + case PTM_6840_LSB2: + case PTM_6840_LSB3: + { + int idx = (offset - 3) / 2; + m_latch[idx] = (m_msb_buffer << 8) | (data & 0xff); + + // Clear the interrupt + m_status_reg &= ~(1 << idx); + update_interrupts(); + + // Reload the count if in an appropriate mode + if (!(m_control_reg[idx] & 0x10)) + { + reload_count(idx); + } + + PLOG(("%s:MC6840 #%s: Counter %d latch = %04X\n", machine().describe_context(), tag(), idx, m_latch[idx])); + break; + } + } +} + + +//------------------------------------------------- +// timeout - Called if timer is mature +//------------------------------------------------- + +void ptm6840_device::timeout(int idx) +{ + PLOG(("**ptm6840 %s t%d timeout**\n", tag(), idx)); + + // Set the interrupt flag + m_status_reg |= (1 << idx); + m_status_read_since_int &= ~(1 << idx); + update_interrupts(); + + if ( m_control_reg[idx] & 0x80 ) + { + if ((m_mode[idx] == 0)||(m_mode[idx] == 2)) + { + m_output[idx] = m_output[idx] ? 0 : 1; + PLOG(("**ptm6840 %s t%d output %d **\n", tag(), idx, m_output[idx])); + + switch (idx) + { + case 0: + m_out0_cb((offs_t)0, m_output[0]); + break; + case 1: + m_out1_cb((offs_t)0, m_output[1]); + break; + case 2: + m_out2_cb((offs_t)0, m_output[2]); + break; + } + } + if ((m_mode[idx] == 4)||(m_mode[idx] == 6)) + { + if (!m_fired[idx]) + { + m_output[idx] = 1; + PLOG(("**ptm6840 %s t%d output %d **\n", tag(), idx, m_output[idx])); + + switch (idx) + { + case 0: + m_out0_cb((offs_t)0, m_output[0]); + break; + case 1: + m_out1_cb((offs_t)0, m_output[1]); + break; + case 2: + m_out2_cb((offs_t)0, m_output[2]); + break; + } + + // No changes in output until reinit + m_fired[idx] = 1; + + m_status_reg |= (1 << idx); + m_status_read_since_int &= ~(1 << idx); + update_interrupts(); + } + } + } + m_enabled[idx]= 0; + reload_count(idx); +} + + +//------------------------------------------------- +// set_gate - set gate status (0 or 1) +//------------------------------------------------- + +void ptm6840_device::set_gate(int idx, int state) +{ + if ((m_mode[idx] & 1) == 0) + { + if (state == 0 && m_gate[idx]) + { + reload_count(idx); + } + } + m_gate[idx] = state; +} + +WRITE_LINE_MEMBER( ptm6840_device::set_g1 ) { set_gate(0, state); } +WRITE_LINE_MEMBER( ptm6840_device::set_g2 ) { set_gate(1, state); } +WRITE_LINE_MEMBER( ptm6840_device::set_g3 ) { set_gate(2, state); } + + +//------------------------------------------------- +// set_clock - set clock status (0 or 1) +//------------------------------------------------- + +void ptm6840_device::set_clock(int idx, int state) +{ + m_clk[idx] = state; + + if (!(m_control_reg[idx] & 0x02)) + { + if (state) + { + tick(idx, 1); + } + } +} + +WRITE_LINE_MEMBER( ptm6840_device::set_c1 ) { set_clock(0, state); } +WRITE_LINE_MEMBER( ptm6840_device::set_c2 ) { set_clock(1, state); } +WRITE_LINE_MEMBER( ptm6840_device::set_c3 ) { set_clock(2, state); } + + +//------------------------------------------------- +// set_ext_clock - set external clock frequency +//------------------------------------------------- + +void ptm6840_device::set_ext_clock(int counter, double clock) +{ + m_external_clock[counter] = clock; + + if (!(m_control_reg[counter] & 0x02)) + { + if (!m_external_clock[counter]) + { + m_enabled[counter] = 0; + m_timer[counter]->enable(false); + } + } + else + { + int count; + attotime duration; + + // Determine the number of clock periods before we expire + count = m_counter[counter]; + + if (m_control_reg[counter] & 0x04) + { + count = ((count >> 8) + 1) * ((count & 0xff) + 1); + } + else + { + count = count + 1; + } + + duration = attotime::from_hz(clock) * count; + + if (counter == 2) + { + duration *= m_t3_divisor; + } + + m_enabled[counter] = 1; + m_timer[counter]->adjust(duration); + m_timer[counter]->enable(true); + } +} diff --git a/src/devices/machine/6840ptm.h b/src/devices/machine/6840ptm.h new file mode 100644 index 00000000000..d00577d62d0 --- /dev/null +++ b/src/devices/machine/6840ptm.h @@ -0,0 +1,148 @@ +// license:BSD-3-Clause +// copyright-holders:James Wallace +/*************************************************************************** + + Motorola 6840 (PTM) + + Programmable Timer Module + +***************************************************************************/ + +#pragma once + +#ifndef __6840PTM_H__ +#define __6840PTM_H__ + +#include "emu.h" + + + +//************************************************************************** +// DEVICE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_PTM6840_INTERNAL_CLOCK(_clk) \ + ptm6840_device::set_internal_clock(*device, _clk); + +#define MCFG_PTM6840_EXTERNAL_CLOCKS(_clk0, _clk1, _clk2) \ + ptm6840_device::set_external_clocks(*device, _clk0, _clk1, _clk2); + +#define MCFG_PTM6840_OUT0_CB(_devcb) \ + devcb = &ptm6840_device::set_out0_callback(*device, DEVCB_##_devcb); + +#define MCFG_PTM6840_OUT1_CB(_devcb) \ + devcb = &ptm6840_device::set_out1_callback(*device, DEVCB_##_devcb); + +#define MCFG_PTM6840_OUT2_CB(_devcb) \ + devcb = &ptm6840_device::set_out2_callback(*device, DEVCB_##_devcb); + +#define MCFG_PTM6840_IRQ_CB(_devcb) \ + devcb = &ptm6840_device::set_irq_callback(*device, DEVCB_##_devcb); + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> ptm6840_device + +class ptm6840_device : public device_t +{ +public: + // construction/destruction + ptm6840_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + static void set_internal_clock(device_t &device, double clock) { downcast(device).m_internal_clock = clock; } + static void set_external_clocks(device_t &device, double clock0, double clock1, double clock2) { downcast(device).m_external_clock[0] = clock0; downcast(device).m_external_clock[1] = clock1; downcast(device).m_external_clock[2] = clock2; } + template static devcb_base &set_out0_callback(device_t &device, _Object object) { return downcast(device).m_out0_cb.set_callback(object); } + template static devcb_base &set_out1_callback(device_t &device, _Object object) { return downcast(device).m_out1_cb.set_callback(object); } + template static devcb_base &set_out2_callback(device_t &device, _Object object) { return downcast(device).m_out2_cb.set_callback(object); } + template static devcb_base &set_irq_callback(device_t &device, _Object object) { return downcast(device).m_irq_cb.set_callback(object); } + + int status(int clock) const { return m_enabled[clock]; } // get whether timer is enabled + int irq_state() const { return m_IRQ; } // get IRQ state + UINT16 count(int counter) const { return compute_counter(counter); } // get counter value + void set_ext_clock(int counter, double clock); // set clock frequency + int ext_clock(int counter) const { return m_external_clock[counter]; } // get clock frequency + + DECLARE_WRITE8_MEMBER( write ); + void write(offs_t offset, UINT8 data) { write(machine().driver_data()->generic_space(), offset, data); } + DECLARE_READ8_MEMBER( read ); + UINT8 read(offs_t offset) { return read(machine().driver_data()->generic_space(), offset); } + + void set_gate(int idx, int state); + DECLARE_WRITE_LINE_MEMBER( set_g1 ); + DECLARE_WRITE_LINE_MEMBER( set_g2 ); + DECLARE_WRITE_LINE_MEMBER( set_g3 ); + + void set_clock(int idx, int state); + DECLARE_WRITE_LINE_MEMBER( set_c1 ); + DECLARE_WRITE_LINE_MEMBER( set_c2 ); + DECLARE_WRITE_LINE_MEMBER( set_c3 ); + + void update_interrupts(); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + +private: + void subtract_from_counter(int counter, int count); + void tick(int counter, int count); + void timeout(int idx); + + UINT16 compute_counter(int counter) const; + void reload_count(int idx); + + enum + { + PTM_6840_CTRL1 = 0, + PTM_6840_CTRL2 = 1, + PTM_6840_STATUS = 1, + PTM_6840_MSBBUF1 = 2, + PTM_6840_LSB1 = 3, + PTM_6840_MSBBUF2 = 4, + PTM_6840_LSB2 = 5, + PTM_6840_MSBBUF3 = 6, + PTM_6840_LSB3 = 7 + }; + + double m_internal_clock; + double m_external_clock[3]; + + devcb_write8 m_out0_cb; + devcb_write8 m_out1_cb; + devcb_write8 m_out2_cb; + devcb_write_line m_irq_cb; // function called if IRQ line changes + + UINT8 m_control_reg[3]; + UINT8 m_output[3]; // Output states + UINT8 m_gate[3]; // Input gate states + UINT8 m_clk[3]; // Clock states + UINT8 m_enabled[3]; + UINT8 m_mode[3]; + UINT8 m_fired[3]; + UINT8 m_t3_divisor; + UINT8 m_t3_scaler; + UINT8 m_IRQ; + UINT8 m_status_reg; + UINT8 m_status_read_since_int; + UINT8 m_lsb_buffer; + UINT8 m_msb_buffer; + + // Each PTM has 3 timers + emu_timer *m_timer[3]; + + UINT16 m_latch[3]; + UINT16 m_counter[3]; + + static const char *const opmode[]; +}; + + +// device type definition +extern const device_type PTM6840; + + +#endif /* __6840PTM_H__ */ diff --git a/src/devices/machine/6850acia.c b/src/devices/machine/6850acia.c new file mode 100644 index 00000000000..7c1fcc85178 --- /dev/null +++ b/src/devices/machine/6850acia.c @@ -0,0 +1,597 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/********************************************************************* + + 6850acia.c + + 6850 ACIA code + +*********************************************************************/ + +#include "emu.h" +#include "6850acia.h" + + +/*************************************************************************** + MACROS +***************************************************************************/ + +#define LOG 0 + +/*************************************************************************** + LOCAL VARIABLES +***************************************************************************/ + +const int acia6850_device::counter_divide_select[4] = +{ + 1, + 16, + 64, + 0 +}; + +const int acia6850_device::word_select[8][3] = +{ + // word length, parity, stop bits + { 7, PARITY_EVEN, 2 }, + { 7, PARITY_ODD, 2 }, + { 7, PARITY_EVEN, 1 }, + { 7, PARITY_ODD, 1 }, + { 8, PARITY_NONE, 2 }, + { 8, PARITY_NONE, 1 }, + { 8, PARITY_EVEN, 1 }, + { 8, PARITY_ODD, 1 } +}; + +const int acia6850_device::transmitter_control[4][3] = +{ + // rts, brk, tx irq + { 0, 0, 0 }, + { 0, 0, 1 }, + { 1, 0, 0 }, + { 0, 1, 0 } +}; + + +/*************************************************************************** + LIVE DEVICE +***************************************************************************/ + +// device type definition +const device_type ACIA6850 = &device_creator; + +//------------------------------------------------- +// acia6850_device - constructor +//------------------------------------------------- + +acia6850_device::acia6850_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, ACIA6850, "6850 ACIA", tag, owner, clock, "acia6850", __FILE__), + m_txd_handler(*this), + m_rts_handler(*this), + m_irq_handler(*this), + m_status(SR_TDRE), + m_tdr(0), + m_first_master_reset(true), + m_dcd_irq_pending(false), + m_overrun_pending(false), + m_divide(0), + m_rts(0), + m_dcd(0), + m_irq(0), + m_txc(0), + m_txd(0), + m_tx_counter(0), + m_tx_irq_enable(false), + m_rxc(0), + m_rxd(1), + m_rx_irq_enable(false) +{ +} + +acia6850_device::acia6850_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + m_txd_handler(*this), + m_rts_handler(*this), + m_irq_handler(*this), + m_status(SR_TDRE), + m_tdr(0), + m_first_master_reset(true), + m_dcd_irq_pending(false), + m_overrun_pending(false), + m_divide(0), + m_rts(0), + m_dcd(0), + m_irq(0), + m_txc(0), + m_txd(0), + m_tx_counter(0), + m_tx_irq_enable(false), + m_rxc(0), + m_rxd(1), + m_rx_irq_enable(false) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void acia6850_device::device_start() +{ + // resolve callbacks + m_txd_handler.resolve_safe(); + m_rts_handler.resolve_safe(); + m_irq_handler.resolve_safe(); + + save_item(NAME(m_status)); + save_item(NAME(m_tdr)); + save_item(NAME(m_rdr)); + + save_item(NAME(m_first_master_reset)); + save_item(NAME(m_dcd_irq_pending)); + save_item(NAME(m_overrun_pending)); + + save_item(NAME(m_divide)); + save_item(NAME(m_bits)); + save_item(NAME(m_stopbits)); + save_item(NAME(m_parity)); + save_item(NAME(m_brk)); + + save_item(NAME(m_rts)); + save_item(NAME(m_dcd)); + save_item(NAME(m_irq)); + + save_item(NAME(m_txc)); + save_item(NAME(m_txd)); + save_item(NAME(m_tx_state)); + save_item(NAME(m_tx_bits)); + save_item(NAME(m_tx_shift)); + save_item(NAME(m_tx_parity)); + save_item(NAME(m_tx_counter)); + save_item(NAME(m_tx_irq_enable)); + + save_item(NAME(m_rxc)); + save_item(NAME(m_rxd)); + save_item(NAME(m_rx_state)); + save_item(NAME(m_rx_bits)); + save_item(NAME(m_rx_shift)); + save_item(NAME(m_rx_parity)); + save_item(NAME(m_rx_counter)); + save_item(NAME(m_rx_irq_enable)); + + output_txd(1); + output_rts(1); + output_irq(1); +} + +READ8_MEMBER( acia6850_device::status_r ) +{ + UINT8 status = m_status; + + if (status & SR_CTS) + { + status &= ~SR_TDRE; + } + + if (m_dcd_irq_pending == DCD_IRQ_READ_STATUS) + { + m_dcd_irq_pending = DCD_IRQ_READ_DATA; + } + + return status; +} + +WRITE8_MEMBER( acia6850_device::control_w ) +{ + if (LOG) logerror("MC6850 '%s' Control: %02x\n", tag(), data); + + // CR0 & CR1 + int counter_divide_select_bits = (data >> 0) & 3; + m_divide = counter_divide_select[counter_divide_select_bits]; + + // CR2, CR3 & CR4 + int word_select_bits = (data >> 2) & 7; + m_bits = word_select[word_select_bits][0]; + m_parity = word_select[word_select_bits][1]; + m_stopbits = word_select[word_select_bits][2]; + + // CR5 & CR6 + int transmitter_control_bits = (data >> 5) & 3; + int rts = transmitter_control[transmitter_control_bits][0]; + m_brk = transmitter_control[transmitter_control_bits][1]; + m_tx_irq_enable = transmitter_control[transmitter_control_bits][2]; + + // CR7 + m_rx_irq_enable = (data >> 7) & 1; + + if (m_divide == 0) + { + if (m_first_master_reset) + { + /// TODO: find out whether you need to leave master reset before it stops counting as the first + rts = 1; + m_first_master_reset = false; + } + + m_dcd_irq_pending = DCD_IRQ_NONE; + m_overrun_pending = false; + + m_rx_state = STATE_START; + m_rx_counter = 0; + + m_tx_state = STATE_START; + output_txd(1); + + m_status &= SR_CTS; + + if (m_dcd) + { + m_status |= SR_DCD; + } + } + + output_rts(rts); + + update_irq(); +} + + +int acia6850_device::calculate_txirq() +{ + return !(m_tx_irq_enable && ((m_status & SR_TDRE) && !(m_status & SR_CTS))); +} + +int acia6850_device::calculate_rxirq() +{ + return !(m_rx_irq_enable && ((m_status & SR_RDRF) || m_dcd_irq_pending != DCD_IRQ_NONE)); +} + +void acia6850_device::update_irq() +{ + output_irq(calculate_txirq() && calculate_rxirq()); +} + +WRITE8_MEMBER( acia6850_device::data_w ) +{ + if (LOG) logerror("MC6850 '%s' Data: %02x\n", tag(), data); + + /// TODO: find out if data stored during master reset is sent after divider is set + if (m_divide == 0) + { + logerror("%s:ACIA %p: Data write while in reset!\n", machine().describe_context(), (void *)this); + } + + /// TODO: find out what happens if TDRE is already clear when you write + m_tdr = data; + m_status &= ~SR_TDRE; + + update_irq(); +} + +READ8_MEMBER( acia6850_device::data_r ) +{ + if (m_overrun_pending) + { + m_status |= SR_OVRN; + m_overrun_pending = false; + } + else + { + m_status &= ~SR_OVRN; + m_status &= ~SR_RDRF; + } + + if (m_dcd_irq_pending == DCD_IRQ_READ_DATA) + { + m_dcd_irq_pending = DCD_IRQ_NONE; + } + + update_irq(); + + return m_rdr; +} + +DECLARE_WRITE_LINE_MEMBER( acia6850_device::write_cts ) +{ + if (state) + { + m_status |= SR_CTS; + } + else + { + m_status &= ~SR_CTS; + } +} + +DECLARE_WRITE_LINE_MEMBER( acia6850_device::write_dcd ) +{ + m_dcd = state; +} + +WRITE_LINE_MEMBER( acia6850_device::write_rxc ) +{ + if (m_rxc != state) + { + m_rxc = state; + + if (state && m_divide > 0) + { + if (m_dcd) + { + if (!(m_status & SR_DCD)) + { + m_status |= SR_DCD; + m_dcd_irq_pending = DCD_IRQ_READ_STATUS; + } + + m_rx_state = STATE_START; + m_rx_counter = 0; + } + else + { + if (m_dcd_irq_pending == DCD_IRQ_NONE) + { + m_status &= ~SR_DCD; + } + + m_rx_counter++; + + switch (m_rx_state) + { + case STATE_START: + if (m_rxd == 0) + { + if (m_rx_counter == 1) + { + if (LOG) logerror("MC6850 '%s': RX START BIT\n", tag()); + } + + if (m_rx_counter >= m_divide / 2) + { + m_rx_state = STATE_DATA; + m_rx_counter = 0; + m_rx_shift = 0; + m_rx_parity = 0; + m_rx_bits = 0; + } + } + else + { + if (m_rx_counter != 1) + { + if (LOG) logerror("MC6850 '%s': RX FALSE START BIT\n", tag()); + } + + m_rx_counter = 0; + } + break; + + case STATE_DATA: + if (m_rx_counter == m_divide) + { + m_rx_counter = 0; + + if (m_rx_bits < m_bits) + { + if (LOG) logerror("MC6850 '%s': RX DATA BIT %d %d\n", tag(), m_rx_bits, m_rxd); + } + else + { + if (LOG) logerror("MC6850 '%s': RX PARITY BIT %x\n", tag(), m_rxd); + } + + if (m_rxd) + { + m_rx_shift |= 1 << m_rx_bits; + } + + m_rx_bits++; + + m_rx_parity ^= m_rxd; + + if ((m_rx_bits == m_bits && m_parity == PARITY_NONE) || + (m_rx_bits == (m_bits + 1) && m_parity != PARITY_NONE)) + { + if (m_status & SR_RDRF) + { + m_overrun_pending = true; + } + else + { + /// TODO: find out if this is the correct place to calculate parity + if (m_parity == PARITY_ODD) + { + m_rx_parity = !m_rx_parity; + } + + if (m_parity != PARITY_NONE && m_rx_parity) + { + m_status |= SR_PE; + } + else + { + m_status &= ~SR_PE; + } + + m_rdr = m_rx_shift; + + if (m_bits == 7 && m_parity != PARITY_NONE) + { + m_rdr &= 0x7f; + } + + m_status |= SR_RDRF; + } + + m_rx_state = STATE_STOP; + } + } + break; + + case STATE_STOP: + if (m_rx_counter == m_divide) + { + m_rx_counter = 0; + + if (LOG) logerror("MC6850 '%s': RX STOP BIT\n", tag()); + + if (!m_rxd) + { + m_status |= SR_FE; + } + else + { + m_status &= ~SR_FE; + } + + /// TODO: find out if 6850 only waits for 1 STOP bit when receiving + m_rx_state = STATE_START; + } + break; + } + } + + update_irq(); + } + } +} + +DECLARE_WRITE_LINE_MEMBER( acia6850_device::write_rxd ) +{ + m_rxd = state; +} + +WRITE_LINE_MEMBER( acia6850_device::write_txc ) +{ + if (m_txc != state) + { + m_txc = state; + + if (!state && m_divide > 0) + { + m_tx_counter++; + + /// TODO: check txd is correctly generated, check atarist mcu is reading data, start checking receive data. + switch (m_tx_state) + { + case STATE_START: + m_tx_counter = 0; + + if (!(m_status & SR_TDRE) && !(m_status & SR_CTS)) + { + if (LOG) logerror("MC6850 '%s': TX DATA %x\n", tag(), m_tdr); + + m_tx_state = STATE_DATA; + m_tx_shift = m_tdr; + m_tx_bits = 0; + m_tx_parity = 0; + m_status |= SR_TDRE; + + if (LOG) logerror("MC6850 '%s': TX START BIT\n", tag()); + + output_txd(0); + } + else + { + /// TODO: find out if break stops transmitter + output_txd(!m_brk); + } + break; + + case STATE_DATA: + if (m_tx_counter == m_divide) + { + m_tx_counter = 0; + + if (m_tx_bits < m_bits) + { + output_txd((m_tx_shift >> m_tx_bits) & 1); + + m_tx_bits++; + m_tx_parity ^= m_txd; + + if (LOG) logerror("MC6850 '%s': TX DATA BIT %d %d\n", tag(), m_tx_bits, m_txd); + } + else if (m_tx_bits == m_bits && m_parity != PARITY_NONE) + { + m_tx_bits++; + + /// TODO: find out if this is the correct place to calculate parity + if (m_parity == PARITY_ODD) + { + m_tx_parity = !m_tx_parity; + } + + output_txd(m_tx_parity); + + if (LOG) logerror("MC6850 '%s': TX PARITY BIT %d\n", tag(), m_txd); + } + else + { + m_tx_state = STATE_STOP; + m_tx_bits = 0; + + output_txd(1); + } + } + break; + + case STATE_STOP: + if (m_tx_counter == m_divide) + { + m_tx_counter = 0; + + m_tx_bits++; + + if (LOG) logerror("MC6850 '%s': TX STOP BIT %d\n", tag(), m_tx_bits); + + if (m_tx_bits == m_stopbits) + { + m_tx_state = STATE_START; + } + } + break; + } + } + + update_irq(); + } +} + +void acia6850_device::output_txd(int txd) +{ + if (m_txd != txd) + { + m_txd = txd; + + m_txd_handler(m_txd); + } +} + +void acia6850_device::output_rts(int rts) +{ + if (m_rts != rts) + { + m_rts = rts; + m_rts_handler(m_rts); + } +} + +void acia6850_device::output_irq(int irq) +{ + if (m_irq != irq) + { + m_irq = irq; + + if (irq) + { + m_status &= ~SR_IRQ; + } + else + { + m_status |= SR_IRQ; + } + + m_irq_handler(!m_irq); + } +} diff --git a/src/devices/machine/6850acia.h b/src/devices/machine/6850acia.h new file mode 100644 index 00000000000..8bb1a3891bd --- /dev/null +++ b/src/devices/machine/6850acia.h @@ -0,0 +1,145 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/********************************************************************* + + 6850acia.h + + 6850 ACIA code + +*********************************************************************/ + +#pragma once + +#ifndef __ACIA6850_H__ +#define __ACIA6850_H__ + +#include "emu.h" + +#define MCFG_ACIA6850_TXD_HANDLER(_devcb) \ + devcb = &acia6850_device::set_txd_handler(*device, DEVCB_##_devcb); + +#define MCFG_ACIA6850_RTS_HANDLER(_devcb) \ + devcb = &acia6850_device::set_rts_handler(*device, DEVCB_##_devcb); + +#define MCFG_ACIA6850_IRQ_HANDLER(_devcb) \ + devcb = &acia6850_device::set_irq_handler(*device, DEVCB_##_devcb); + +class acia6850_device : public device_t +{ +public: + // construction/destruction + acia6850_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // static configuration helpers + template static devcb_base &set_txd_handler(device_t &device, _Object object) { return downcast(device).m_txd_handler.set_callback(object); } + template static devcb_base &set_rts_handler(device_t &device, _Object object) { return downcast(device).m_rts_handler.set_callback(object); } + template static devcb_base &set_irq_handler(device_t &device, _Object object) { return downcast(device).m_irq_handler.set_callback(object); } + + DECLARE_WRITE8_MEMBER( control_w ); + DECLARE_READ8_MEMBER( status_r ); + DECLARE_WRITE8_MEMBER( data_w ); + DECLARE_READ8_MEMBER( data_r ); + + DECLARE_WRITE_LINE_MEMBER( write_cts ); + DECLARE_WRITE_LINE_MEMBER( write_dcd ); + DECLARE_WRITE_LINE_MEMBER( write_rxd ); + DECLARE_WRITE_LINE_MEMBER( write_rxc ); + DECLARE_WRITE_LINE_MEMBER( write_txc ); + +protected: + acia6850_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + // device-level overrides + virtual void device_start(); + + virtual void update_irq(); + int calculate_txirq(); + int calculate_rxirq(); + +private: + void output_txd(int txd); + void output_rts(int txd); + void output_irq(int irq); + + enum + { + SR_RDRF = 0x01, + SR_TDRE = 0x02, + SR_DCD = 0x04, + SR_CTS = 0x08, + SR_FE = 0x10, + SR_OVRN = 0x20, + SR_PE = 0x40, + SR_IRQ = 0x80 + }; + + enum serial_state + { + STATE_START, + STATE_DATA, + STATE_STOP + }; + + enum parity_type + { + PARITY_NONE, + PARITY_ODD, + PARITY_EVEN + }; + + enum dcd_irq_state + { + DCD_IRQ_NONE = 0, + DCD_IRQ_READ_DATA, + DCD_IRQ_READ_STATUS + }; + + devcb_write_line m_txd_handler; + devcb_write_line m_rts_handler; + devcb_write_line m_irq_handler; + + UINT8 m_status; + UINT8 m_tdr; + UINT8 m_rdr; + + bool m_first_master_reset; + int m_dcd_irq_pending; + bool m_overrun_pending; + + int m_divide; + int m_bits; + int m_stopbits; + int m_parity; + int m_brk; + + int m_rts; + int m_dcd; + int m_irq; + + int m_txc; + int m_txd; + int m_tx_state; + int m_tx_bits; + int m_tx_shift; + int m_tx_parity; + int m_tx_counter; + int m_tx_irq_enable; + + int m_rxc; + int m_rxd; + int m_rx_state; + int m_rx_bits; + int m_rx_shift; + int m_rx_parity; + int m_rx_counter; + int m_rx_irq_enable; + + static const int counter_divide_select[4]; + static const int word_select[8][3]; + static const int transmitter_control[4][3]; +}; + +// device type definition +extern const device_type ACIA6850; + +#endif /* __ACIA6850_H__ */ diff --git a/src/devices/machine/68561mpcc.c b/src/devices/machine/68561mpcc.c new file mode 100644 index 00000000000..1b8a8895fed --- /dev/null +++ b/src/devices/machine/68561mpcc.c @@ -0,0 +1,481 @@ +// license:BSD-3-Clause +// copyright-holders:Sergey Svishchev +/********************************************************************* + + 68561mpcc.c + + Rockwell 68561 MPCC (Multi Protocol Communications Controller) + + skeleton driver, just enough for besta.c console to work + +*********************************************************************/ + + +#include "emu.h" +#include "68561mpcc.h" + +const device_type MPCC68561 = &device_creator; + + +/*************************************************************************** + PARAMETERS +***************************************************************************/ + +#define LOG_MPCC (1) + +/*************************************************************************** + IMPLEMENTATION +***************************************************************************/ + +mpcc68561_t::mpcc68561_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, MPCC68561, "Rockwell 68561 MPCC", tag, owner, clock, "mpcc68561", __FILE__), + intrq_cb(*this) +{ +} + +/*------------------------------------------------- + mpcc_updateirqs +-------------------------------------------------*/ + +void mpcc68561_t::updateirqs() +{ + int irqstat; + + irqstat = 0; + if (MasterIRQEnable) + { + if ((channel[0].txIRQEnable) && (channel[0].txIRQPending)) + { + IRQType = IRQ_B_TX; + irqstat = 1; + } + else if ((channel[1].txIRQEnable) && (channel[1].txIRQPending)) + { + IRQType = IRQ_A_TX; + irqstat = 1; + } + else if ((channel[0].extIRQEnable) && (channel[0].extIRQPending)) + { + IRQType = IRQ_B_EXT; + irqstat = 1; + } + else if ((channel[1].extIRQEnable) && (channel[1].extIRQPending)) + { + IRQType = IRQ_A_EXT; + irqstat = 1; + } + } + else + { + IRQType = IRQ_NONE; + } + +// printf("mpcc: irqstat %d, last %d\n", irqstat, lastIRQStat); +// printf("ch0: en %d pd %d ch1: en %d pd %d\n", channel[0].txIRQEnable, channel[0].txIRQPending, channel[1].txIRQEnable, channel[1].txIRQPending); + + // don't spam the driver with unnecessary transitions + if (irqstat != lastIRQStat) + { + lastIRQStat = irqstat; + + // tell the driver the new IRQ line status if possible +#if LOG_MPCC + printf("mpcc68561 IRQ status => %d\n", irqstat); +#endif + if(!intrq_cb.isnull()) + intrq_cb(irqstat); + } +} + +/*------------------------------------------------- + mpcc_initchannel +-------------------------------------------------*/ +void mpcc68561_t::initchannel(int ch) +{ + channel[ch].syncHunt = 1; +} + +/*------------------------------------------------- + mpcc_resetchannel +-------------------------------------------------*/ +void mpcc68561_t::resetchannel(int ch) +{ + emu_timer *timersave = channel[ch].baudtimer; + + memset(&channel[ch], 0, sizeof(Chan)); + + channel[ch].txUnderrun = 1; + channel[ch].baudtimer = timersave; + + channel[ch].baudtimer->adjust(attotime::never, ch); +} + +/*------------------------------------------------- + mpcc68561_baud_expire - baud rate timer expiry +-------------------------------------------------*/ + +void mpcc68561_t::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + Chan *pChan = &channel[id]; + int brconst = pChan->reg_val[13]<<8 | pChan->reg_val[14]; + int rate; + + if (brconst) + { + rate = clock() / brconst; + } + else + { + rate = 0; + } + + // is baud counter IRQ enabled on this channel? + // always flag pending in case it's enabled after this + pChan->baudIRQPending = 1; + if (pChan->baudIRQEnable) + { + if (pChan->extIRQEnable) + { + pChan->extIRQPending = 1; + pChan->baudIRQPending = 0; + updateirqs(); + } + } + + // reset timer according to current register values + if (rate) + { + timer.adjust(attotime::from_hz(rate), 0, attotime::from_hz(rate)); + } + else + { + timer.adjust(attotime::never, 0, attotime::never); + } +} + +/*------------------------------------------------- + device_start - device-specific startup +-------------------------------------------------*/ + +void mpcc68561_t::device_start() +{ + intrq_cb.resolve_safe(); + + memset(channel, 0, sizeof(channel)); + + mode = 0; + reg = 0; + status = 0; + IRQV = 0; + MasterIRQEnable = 0; + lastIRQStat = 0; + IRQType = IRQ_NONE; + + channel[0].baudtimer = timer_alloc(0); +} + + +/*------------------------------------------------- + device_reset - device-specific reset +-------------------------------------------------*/ +void mpcc68561_t::device_reset() +{ + IRQType = IRQ_NONE; + MasterIRQEnable = 0; + IRQV = 0; + + initchannel(0); + resetchannel(0); +} + +/*------------------------------------------------- + mpcc_set_status +-------------------------------------------------*/ + +void mpcc68561_t::set_status(int _status) +{ + status = _status; +} + +/*------------------------------------------------- + mpcc_acknowledge +-------------------------------------------------*/ + +void mpcc68561_t::acknowledge() +{ + if(!intrq_cb.isnull()) + intrq_cb(0); +} + +/*------------------------------------------------- + mpcc_getreg +-------------------------------------------------*/ + +UINT8 mpcc68561_t::getreg() +{ + /* Not yet implemented */ + #if LOG_MPCC + printf("mpcc: port A reg %d read 0x%02x\n", reg, channel[0].reg_val[reg]); + #endif + + if (reg == 0) + { + UINT8 rv = 0; + + Chan *ourCh = &channel[0]; + + rv |= (ourCh->txUnderrun) ? 0x40 : 0; + rv |= (ourCh->syncHunt) ? 0x10 : 0; + rv |= channel[0].reg_val[0] & 0x05; // pick up TXBE and RXBF bits + + return rv; + } + else if (reg == 10) + { + return 0; + } + return channel[0].reg_val[reg]; +} + +/*------------------------------------------------- + mpcc_putreg +-------------------------------------------------*/ + +void mpcc68561_t::putreg(int ch, UINT8 data) +{ + Chan *pChan = &channel[ch]; + + channel[ch].reg_val[reg] = data; + #if LOG_MPCC + printf("mpcc: port %c reg %d write 0x%02x\n", 'A'+ch, reg, data); + #endif + + switch (reg) + { + case 0: // command register + switch ((data >> 3) & 7) + { + case 1: // select high registers (handled elsewhere) + break; + + case 2: // reset external and status IRQs + pChan->syncHunt = 0; + break; + + case 5: // ack Tx IRQ + pChan->txIRQPending = 0; + updateirqs(); + break; + + case 0: // nothing + case 3: // send SDLC abort + case 4: // enable IRQ on next Rx byte + case 6: // reset errors + case 7: // reset highest IUS + // we don't handle these yet + break; + + } + break; + + case 1: // Tx/Rx IRQ and data transfer mode defintion + pChan->extIRQEnable = (data & 1); + pChan->txIRQEnable = (data & 2) ? 1 : 0; + pChan->rxIRQEnable = (data >> 3) & 3; + updateirqs(); + break; + + case 2: // IRQ vector + IRQV = data; + break; + + case 3: // Rx parameters and controls + pChan->rxEnable = (data & 1); + pChan->syncHunt = (data & 0x10) ? 1 : 0; + break; + + case 5: // Tx parameters and controls +// printf("ch %d TxEnable = %d [%02x]\n", ch, data & 8, data); + pChan->txEnable = data & 8; + + if (pChan->txEnable) + { + pChan->reg_val[0] |= 0x04; // Tx empty + } + break; + + case 4: // Tx/Rx misc parameters and modes + case 6: // sync chars/SDLC address field + case 7: // sync char/SDLC flag + break; + + case 9: // master IRQ control + MasterIRQEnable = (data & 8) ? 1 : 0; + updateirqs(); + + // channel reset command + switch ((data>>6) & 3) + { + case 0: // do nothing + break; + + case 1: // reset channel B + resetchannel(0); + break; + + case 3: // force h/w reset (entire chip) + IRQType = IRQ_NONE; + MasterIRQEnable = 0; + IRQV = 0; + + initchannel(0); + resetchannel(0); + + // make sure we stop yanking the IRQ line if we were + updateirqs(); + break; + + } + break; + + case 10: // misc transmitter/receiver control bits + case 11: // clock mode control + case 12: // lower byte of baud rate gen + case 13: // upper byte of baud rate gen + break; + + case 14: // misc control bits + if (data & 0x01) // baud rate generator enable? + { + int brconst = pChan->reg_val[13]<<8 | pChan->reg_val[14]; + int rate = clock() / brconst; + + pChan->baudtimer->adjust(attotime::from_hz(rate), 0, attotime::from_hz(rate)); + } + break; + + case 15: // external/status interrupt control + pChan->baudIRQEnable = (data & 2) ? 1 : 0; + pChan->DCDEnable = (data & 8) ? 1 : 0; + pChan->CTSEnable = (data & 0x20) ? 1 : 0; + pChan->txUnderrunEnable = (data & 0x40) ? 1 : 0; + break; + } +} + +/*------------------------------------------------- + mpcc68561_get_reg_a +-------------------------------------------------*/ + +UINT8 mpcc68561_t::get_reg_a(int reg) +{ + return channel[0].reg_val[reg]; +} + + + +/*------------------------------------------------- + mpcc68561_set_reg_a +-------------------------------------------------*/ + +void mpcc68561_t::set_reg_a(int reg, UINT8 data) +{ + channel[0].reg_val[reg] = data; +} + + + +/*------------------------------------------------- + mpcc68561_r +-------------------------------------------------*/ + +READ8_MEMBER( mpcc68561_t::reg_r) +{ + UINT8 result = 0; + + offset %= 4; + + switch(offset) + { + case 1: + /* Channel A (Modem Port) Control */ + if (mode == 1) + mode = 0; + else + reg = 0; + + result = getreg(); + break; + + case 3: + /* Channel A (Modem Port) Data */ + return channel[0].rxData; + break; + } + return result; +} + + + +/*------------------------------------------------- + mpcc68561_w +-------------------------------------------------*/ + +WRITE8_MEMBER( mpcc68561_t::reg_w ) +{ + Chan *pChan; + + offset &= 3; + +// printf(" mode %d data %x offset %d \n", mode, data, offset); + + switch(offset) + { + case 1: + /* Channel A (Modem Port) Control */ + if (mode == 0) + { + if((data & 0xf0) == 0) // not a reset command + { + mode = 1; + reg = data & 0x0f; +// putareg(data & 0xf0); + } + else if (data == 0x10) + { + pChan = &channel[0]; + // clear ext. interrupts + pChan->extIRQPending = 0; + pChan->baudIRQPending = 0; + updateirqs(); + } + } + else + { + mode = 0; + putreg(0, data); + } + break; + + case 3: + /* Channel A (Modem Port) Data */ + pChan = &channel[0]; + + if (pChan->txEnable) + { + pChan->txData = data; + // local loopback? + if (pChan->reg_val[14] & 0x10) + { + pChan->rxData = data; + pChan->reg_val[0] |= 0x01; // Rx character available + } + pChan->reg_val[1] |= 0x01; // All sent + pChan->reg_val[0] |= 0x04; // Tx empty + pChan->txUnderrun = 1; + pChan->txIRQPending = 1; + updateirqs(); + } + break; + } +} diff --git a/src/devices/machine/68561mpcc.h b/src/devices/machine/68561mpcc.h new file mode 100644 index 00000000000..df036282f1c --- /dev/null +++ b/src/devices/machine/68561mpcc.h @@ -0,0 +1,102 @@ +// license:BSD-3-Clause +// copyright-holders:Sergey Svishchev +/********************************************************************* + + 68561mpcc.h + + Rockwell 68561 MPCC (Multi Protocol Communications Controller) + + skeleton driver + +*********************************************************************/ + +#ifndef __68561MPCC_H__ +#define __68561MPCC_H__ + +#define MCFG_MPCC68561_INTRQ_CALLBACK(_write) \ + devcb = &mpcc68561_t::set_intrq_wr_callback(*device, DEVCB_##_write); + +class mpcc68561_t : public device_t +{ +public: + enum IRQType_t { + IRQ_NONE, + IRQ_A_RX, + IRQ_A_RX_SPECIAL, + IRQ_B_RX, + IRQ_B_RX_SPECIAL, + IRQ_A_TX, + IRQ_B_TX, + IRQ_A_EXT, + IRQ_B_EXT + }; + + mpcc68561_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + template static devcb_base &set_intrq_wr_callback(device_t &device, _Object object) { return downcast(device).intrq_cb.set_callback(object); } + + UINT8 get_reg_a(int reg); + void set_reg_a(int reg, UINT8 data); + + void set_status(int status); + + DECLARE_READ8_MEMBER(reg_r); + DECLARE_WRITE8_MEMBER(reg_w); + +protected: + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + +private: + struct Chan { + bool txIRQEnable; + bool rxIRQEnable; + bool extIRQEnable; + bool baudIRQEnable; + bool txIRQPending; + bool rxIRQPending; + bool extIRQPending; + bool baudIRQPending; + bool txEnable; + bool rxEnable; + bool txUnderrun; + bool txUnderrunEnable; + bool syncHunt; + bool DCDEnable; + bool CTSEnable; + UINT8 rxData; + UINT8 txData; + + emu_timer *baudtimer; + + UINT8 reg_val[22]; + }; + + int mode; + int reg; + int status; + int IRQV; + int MasterIRQEnable; + int lastIRQStat; + IRQType_t IRQType; + + Chan channel[2]; + + devcb_write_line intrq_cb; + + void updateirqs(); + void initchannel(int ch); + void resetchannel(int ch); + void acknowledge(); + UINT8 getreg(); + void putreg(int ch, UINT8 data); +}; + +/*************************************************************************** + MACROS +***************************************************************************/ + +extern const device_type MPCC68561; + +#endif /* __68561MPCC_H__ */ diff --git a/src/devices/machine/7200fifo.c b/src/devices/machine/7200fifo.c new file mode 100644 index 00000000000..ee44eada962 --- /dev/null +++ b/src/devices/machine/7200fifo.c @@ -0,0 +1,138 @@ +// license:BSD-3-Clause +// copyright-holders:hap +/********************************************************************** + + IDT7200 series 9-bit Asynchronous FIFO Emulation + + TODO: + - retransmit (RT pin) + - cascaded width expansion mode (when needed) + +**********************************************************************/ + +#include "machine/7200fifo.h" + + +const device_type FIFO7200 = &device_creator; + +//------------------------------------------------- +// fifo7200_device - constructor +//------------------------------------------------- + +fifo7200_device::fifo7200_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, FIFO7200, "IDT7200 FIFO", tag, owner, clock, "fifo7200", __FILE__), + m_ram_size(0), + m_ef_handler(*this), + m_ff_handler(*this), + m_hf_handler(*this) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void fifo7200_device::device_start() +{ + assert(m_ram_size > 1 && ~m_ram_size & 1); + m_buffer.resize(m_ram_size); + + // resolve callbacks + m_ef_handler.resolve_safe(); + m_ff_handler.resolve_safe(); + m_hf_handler.resolve_safe(); + + // state save + save_item(NAME(m_buffer)); + save_item(NAME(m_read_ptr)); + save_item(NAME(m_write_ptr)); + save_item(NAME(m_ef)); + save_item(NAME(m_ff)); + save_item(NAME(m_hf)); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void fifo7200_device::device_reset() +{ + // master reset + m_buffer.clear(); + m_read_ptr = 0; + m_write_ptr = 0; + + m_ef = 1; + m_ff = 0; + m_hf = 0; + + m_ef_handler(!m_ef); + m_ff_handler(!m_ff); + m_hf_handler(!m_hf); +} + + + +void fifo7200_device::fifo_write(UINT16 data) +{ + if (m_ff) + { + logerror("IDT7200 %s fifo_write overflow!\n", tag()); + return; + } + + m_buffer[m_write_ptr] = data & 0x1ff; + m_write_ptr = (m_write_ptr + 1) % m_ram_size; + + // update flags + if (m_ef) + { + m_ef = 0; + m_ef_handler(!m_ef); + } + + else if (m_read_ptr == m_write_ptr) + { + m_ff = 1; + m_ff_handler(!m_ff); + } + + else if (((m_read_ptr + 1 + m_ram_size / 2) % m_ram_size) == m_write_ptr) + { + m_hf = 1; + m_hf_handler(!m_hf); + } +} + +UINT16 fifo7200_device::fifo_read() +{ + if (m_ef) + { + logerror("IDT7200 %s fifo_read underflow!\n", tag()); + return 0x1ff; + } + + UINT16 ret = m_buffer[m_read_ptr]; + m_read_ptr = (m_read_ptr + 1) % m_ram_size; + + // update flags + if (m_ff) + { + m_ff = 0; + m_ff_handler(!m_ff); + } + + else if (m_read_ptr == m_write_ptr) + { + m_ef = 1; + m_ef_handler(!m_ef); + } + + else if (((m_read_ptr + m_ram_size / 2) % m_ram_size) == m_write_ptr) + { + m_hf = 0; + m_hf_handler(!m_hf); + } + + return ret; +} diff --git a/src/devices/machine/7200fifo.h b/src/devices/machine/7200fifo.h new file mode 100644 index 00000000000..0f5c28e7048 --- /dev/null +++ b/src/devices/machine/7200fifo.h @@ -0,0 +1,132 @@ +// license:BSD-3-Clause +// copyright-holders:hap +/********************************************************************** + + IDT7200 series 9-bit Asynchronous FIFO Emulation + +********************************************************************** + _____ _____ + _W 1 |* \_/ | 28 Vcc + D8 2 | | 27 D4 + D3 3 | | 26 D5 + D2 4 | | 25 D6 + D1 5 | | 24 D7 + D0 6 | | 23 _FL/_RT + _XI 7 | 7200 | 22 _MR + _FF 8 | | 21 _EF + Q0 9 | | 20 _XO/_HF + Q1 10 | | 19 Q7 + Q2 11 | | 18 Q6 + Q3 12 | | 17 Q5 + Q8 13 | | 16 Q4 + GND 14 |_____________| 15 _R + + +Known chips and buffer sizes are listed below. Note that in width or depth +expansion mode (using more than one chip and XO/XI), it may be increased more. + + 256x9 512x9 1Kx9 2Kx9 4Kx9 8Kx9 16Kx9 32Kx9 64Kx9 + ------------------------------------------------------------------------------------------- + IDT7200 IDT7201 IDT7202 IDT7203 IDT7204 IDT7205 IDT7206 IDT7207 IDT7208 + +The following chips are functionally equivalent and pin-compatible. + + AM7200 AM7201 AM7202 AM7203 AM7204 + MS7200 MS7201 MS7202 MS7203 MS7204 + + LH5495 LH5496 LH5497 LH5498 LH5499 + LH540201 LH540202 LH540203 LH540204 LH540205 LH540206 + + CY7C419 CY7C420 CY7C424 CY7C428 CY7C432 + CY7C421 CY7C425 CY7C429 CY7C433 + +32-pin PLCC/LCC or TQFP configurations are also available. + + +**********************************************************************/ + +#pragma once + +#ifndef _7200FIFO_H +#define _7200FIFO_H + +#include "emu.h" + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_FIFO7200_ADD(_tag, _ramsize) \ + MCFG_DEVICE_ADD(_tag, FIFO7200, 0) \ + fifo7200_device::set_ram_size(*device, _ramsize); + +#define MCFG_FIFO7200_EF_HANDLER(_devcb) \ + devcb = &fifo7200_device::set_ef_handler(*device, DEVCB_##_devcb); + +#define MCFG_FIFO7200_FF_HANDLER(_devcb) \ + devcb = &fifo7200_device::set_ff_handler(*device, DEVCB_##_devcb); + +#define MCFG_FIFO7200_HF_HANDLER(_devcb) \ + devcb = &fifo7200_device::set_hf_handler(*device, DEVCB_##_devcb); + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> fifo7200_device + +class fifo7200_device : public device_t +{ +public: + fifo7200_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // static configuration helpers + template static devcb_base &set_ef_handler(device_t &device, _Object object) { return downcast(device).m_ef_handler.set_callback(object); } + template static devcb_base &set_ff_handler(device_t &device, _Object object) { return downcast(device).m_ff_handler.set_callback(object); } + template static devcb_base &set_hf_handler(device_t &device, _Object object) { return downcast(device).m_hf_handler.set_callback(object); } + static void set_ram_size(device_t &device, int size) { downcast(device).m_ram_size = size; } + + DECLARE_READ_LINE_MEMBER( ef_r ) { return !m_ef; } // _EF + DECLARE_READ_LINE_MEMBER( ff_r ) { return !m_ff; } // _FF + DECLARE_READ_LINE_MEMBER( hf_r ) { return !m_hf; } // _HF + + // normal configuration + DECLARE_WRITE16_MEMBER( data_word_w ) { fifo_write(data); } + DECLARE_READ16_MEMBER( data_word_r ) { return (UINT16)fifo_read(); } + + // use these for simple configurations that don't have d8/q8 connected + DECLARE_WRITE8_MEMBER( data_byte_w ) { fifo_write(data); } + DECLARE_READ8_MEMBER( data_byte_r ) { return (UINT8)fifo_read(); } + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + +private: + void fifo_write(UINT16 data); + UINT16 fifo_read(); + + std::vector m_buffer; + int m_ram_size; + + int m_read_ptr; + int m_write_ptr; + + int m_ef; // empty flag + int m_ff; // full flag + int m_hf; // half-full flag + + devcb_write_line m_ef_handler; + devcb_write_line m_ff_handler; + devcb_write_line m_hf_handler; +}; + +// device type definition +extern const device_type FIFO7200; + + +#endif /* _7200FIFO_H */ diff --git a/src/devices/machine/74123.c b/src/devices/machine/74123.c new file mode 100644 index 00000000000..f88b71dfab8 --- /dev/null +++ b/src/devices/machine/74123.c @@ -0,0 +1,249 @@ +// license:BSD-3-Clause +// copyright-holders:Couriersud +/***************************************************************************** + + 74123 monoflop emulator - see 74123.h for pin out and truth table + + Formulas came from the TI datasheet revised on March 1998 + + *****************************************************************************/ + +#include "emu.h" +#include "machine/74123.h" +#include "machine/rescap.h" + + +#define LOG (0) + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +// device type definition +const device_type TTL74123 = &device_creator; + +//------------------------------------------------- +// ttl74123_device - constructor +//------------------------------------------------- + +ttl74123_device::ttl74123_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, TTL74123, "74123 TTL", tag, owner, clock, "ttl74123", __FILE__), + m_connection_type(TTL74123_NOT_GROUNDED_NO_DIODE), + m_res(1.0), + m_cap(1.0), + m_a(0), + m_b(0), + m_clear(0), + m_output_changed_cb(*this) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void ttl74123_device::device_start() +{ + m_output_changed_cb.resolve_safe(); + + m_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(ttl74123_device::clear_callback),this)); + + /* register for state saving */ + save_item(NAME(m_a)); + save_item(NAME(m_b)); + save_item(NAME(m_clear)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void ttl74123_device::device_reset() +{ + set_output(); +} + + + +//------------------------------------------------- +// compute_duration - compute timer duration +//------------------------------------------------- + +attotime ttl74123_device::compute_duration() +{ + double duration; + + switch (m_connection_type) + { + case TTL74123_NOT_GROUNDED_NO_DIODE: + duration = 0.28 * m_res * m_cap * (1.0 + (700.0 / m_res)); + break; + + case TTL74123_NOT_GROUNDED_DIODE: + duration = 0.25 * m_res * m_cap * (1.0 + (700.0 / m_res)); + break; + + case TTL74123_GROUNDED: + default: + if (m_cap < CAP_U(0.1)) + { + /* this is really a curve - a very flat one in the 0.1uF-.01uF range */ + duration = 0.32 * m_res * m_cap; + } + else + { + duration = 0.33 * m_res * m_cap; + } + break; + } + + return attotime::from_double(duration); +} + + +//------------------------------------------------- +// timer_running - is the timer running? +//------------------------------------------------- + +int ttl74123_device::timer_running() +{ + return (m_timer->remaining() > attotime::zero) && + (m_timer->remaining() != attotime::never); +} + + +/*------------------------------------------------- + TIMER_CALLBACK( output_callback ) +-------------------------------------------------*/ + +TIMER_CALLBACK_MEMBER( ttl74123_device::output_callback ) +{ + m_output_changed_cb((offs_t)0, param); +} + + +//------------------------------------------------- +// set_output - set the output line state +//------------------------------------------------- + +void ttl74123_device::set_output() +{ + int output = timer_running(); + + machine().scheduler().timer_set( attotime::zero, timer_expired_delegate(FUNC(ttl74123_device::output_callback ),this), output); + + if (LOG) logerror("74123 %s: Output: %d\n", tag(), output); +} + + +/*------------------------------------------------- + TIMER_CALLBACK( clear_callback ) +-------------------------------------------------*/ + +TIMER_CALLBACK_MEMBER( ttl74123_device::clear_callback ) +{ + int output = timer_running(); + + m_output_changed_cb((offs_t)0, output); +} + +//------------------------------------------------- +// start_pulse - begin timing +//------------------------------------------------- + +void ttl74123_device::start_pulse() +{ + attotime duration = compute_duration(); + + if(timer_running()) + { + /* retriggering, but not if we are called to quickly */ + attotime delay_time = attotime(0, ATTOSECONDS_PER_SECOND * m_cap * 220); + + if(m_timer->elapsed() >= delay_time) + { + m_timer->adjust(duration); + + if (LOG) logerror("74123 %s: Retriggering pulse. Duration: %f\n", tag(), duration.as_double()); + } + else + { + if (LOG) logerror("74123 %s: Retriggering failed.\n", tag()); + } + } + else + { + /* starting */ + m_timer->adjust(duration); + + set_output(); + + if (LOG) logerror("74123 %s: Starting pulse. Duration: %f\n", tag(), duration.as_double()); + } +} + + +//------------------------------------------------- +// a_w - write register a data +//------------------------------------------------- + +WRITE8_MEMBER( ttl74123_device::a_w ) +{ + /* start/regtrigger pulse if B=HI and falling edge on A (while clear is HI) */ + if (!data && m_a && m_b && m_clear) + { + start_pulse(); + } + + m_a = data; +} + + +//------------------------------------------------- +// b_w - write register b data +//------------------------------------------------- + +WRITE8_MEMBER( ttl74123_device::b_w) +{ + /* start/regtrigger pulse if A=LO and rising edge on B (while clear is HI) */ + if (data && !m_b && !m_a && m_clear) + { + start_pulse(); + } + + m_b = data; +} + + +//------------------------------------------------- +// clear_w - write register clear data +//------------------------------------------------- + +WRITE8_MEMBER( ttl74123_device::clear_w) +{ + /* start/regtrigger pulse if B=HI and A=LO and rising edge on clear */ + if (data && !m_a && m_b && !m_clear) + { + start_pulse(); + } + else if (!data) /* clear the output */ + { + m_timer->adjust(attotime::zero); + + if (LOG) logerror("74123 #%s: Cleared\n", tag() ); + } + m_clear = data; +} + + +//------------------------------------------------- +// reset_w - reset device +//------------------------------------------------- + +WRITE8_MEMBER( ttl74123_device::reset_w) +{ + set_output(); +} diff --git a/src/devices/machine/74123.h b/src/devices/machine/74123.h new file mode 100644 index 00000000000..93325bdbeb1 --- /dev/null +++ b/src/devices/machine/74123.h @@ -0,0 +1,147 @@ +// license:BSD-3-Clause +// copyright-holders:Couriersud +/***************************************************************************** + + 74123 monoflop emulator + + There are 2 monoflops per chips. + + Pin out: + + +--------+ + B1 |1 | | 16| Vcc + A1 o|2 - 15| RCext1 + Clear1 o|3 14| Cext1 + *Output1 o|4 13| Output1 + Output2 |5 12|o *Output2 + Cext2 |6 11|o Clear2 + RCext2 |7 10| B2 + GND |8 9|o A2 + +--------+ + + All resistor values in Ohms. + All capacitor values in Farads. + + + Truth table: + + C A B | Q /Q + ----------|------- + L X X | L H + X H X | L H + X X L | L H + H L _- |_-_ -_- + H -_ H |_-_ -_- + _- L H |_-_ -_- + ------------------ + C = clear + L = LO (0) + H = HI (1) + X = any state + _- = raising edge + -_ = falling edge + _-_ = positive pulse + -_- = negative pulse + +*****************************************************************************/ + +#pragma once + +#ifndef __TTL74123_H__ +#define __TTL74123_H__ + +#include "emu.h" + + + +/*************************************************************************** + DEVICE CONFIGURATION MACROS +***************************************************************************/ + +#define MCFG_TTL74123_CONNECTION_TYPE(_ctype) \ + ttl74123_device::set_connection_type(*device, _ctype); + +#define MCFG_TTL74123_RESISTOR_VALUE(_value) \ + ttl74123_device::set_resistor_value(*device, _value); + +#define MCFG_TTL74123_CAPACITOR_VALUE(_value) \ + ttl74123_device::set_capacitor_value(*device, _value); + +#define MCFG_TTL74123_A_PIN_VALUE(_value) \ + ttl74123_device::set_a_pin_value(*device, _value); + +#define MCFG_TTL74123_B_PIN_VALUE(_value) \ + ttl74123_device::set_b_pin_value(*device, _value); + +#define MCFG_TTL74123_CLEAR_PIN_VALUE(_value) \ + ttl74123_device::set_clear_pin_value(*device, _value); + +#define MCFG_TTL74123_OUTPUT_CHANGED_CB(_devcb) \ + devcb = &ttl74123_device::set_output_changed_callback(*device, DEVCB_##_devcb); + +/* constants for the different ways the cap/res can be connected. + This determines the formula for calculating the pulse width */ +#define TTL74123_NOT_GROUNDED_NO_DIODE (1) +#define TTL74123_NOT_GROUNDED_DIODE (2) +#define TTL74123_GROUNDED (3) + + +/*************************************************************************** + TYPE DEFINITIONS +***************************************************************************/ + +// ======================> ttl74123_device + +class ttl74123_device : public device_t +{ +public: + // construction/destruction + ttl74123_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + static void set_connection_type(device_t &device, int type) { downcast(device).m_connection_type = type; } + static void set_resistor_value(device_t &device, double value) { downcast(device).m_res = value; } + static void set_capacitor_value(device_t &device, double value) { downcast(device).m_cap = value; } + static void set_a_pin_value(device_t &device, int value) { downcast(device).m_a = value; } + static void set_b_pin_value(device_t &device, int value) { downcast(device).m_b = value; } + static void set_clear_pin_value(device_t &device, int value) { downcast(device).m_clear = value; } + template static devcb_base &set_output_changed_callback(device_t &device, _Object object) { return downcast(device).m_output_changed_cb.set_callback(object); } + + DECLARE_WRITE8_MEMBER(a_w); + DECLARE_WRITE8_MEMBER(b_w); + DECLARE_WRITE8_MEMBER(clear_w); + DECLARE_WRITE8_MEMBER(reset_w); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_post_load() { } + virtual void device_clock_changed() { } + + TIMER_CALLBACK_MEMBER( output_callback ); + TIMER_CALLBACK_MEMBER( clear_callback ); + +private: + + int timer_running(); + void start_pulse(); + void output(INT32 param); + void set_output(); + attotime compute_duration(); + void clear(); + + emu_timer *m_timer; + int m_connection_type; /* the hook up type - one of the constants above */ + double m_res; /* resistor connected to RCext */ + double m_cap; /* capacitor connected to Cext and RCext */ + int m_a; /* initial/constant value of the A pin */ + int m_b; /* initial/constant value of the B pin */ + int m_clear; /* initial/constant value of the Clear pin */ + devcb_write8 m_output_changed_cb; +}; + + +// device type definition +extern const device_type TTL74123; + +#endif diff --git a/src/devices/machine/74145.c b/src/devices/machine/74145.c new file mode 100644 index 00000000000..f85439398de --- /dev/null +++ b/src/devices/machine/74145.c @@ -0,0 +1,142 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best +/***************************************************************************** + * + * TTL74145 + * + * + * BCD-to-Decimal decoder + * + * __ __ + * 0-| v |-VCC + * 1-| |-A + * 2-| |-B + * 3-| |-C + * 4-| |-D + * 5-| |-9 + * 6-| |-8 + * GND-|_____|-7 + * + * + * Truth table + * _______________________________ + * | Inputs | Outputs | + * | D C B A | 0 1 2 3 4 5 6 7 8 9 | + * |-------------------------------| + * | L L L L | L H H H H H H H H H | + * | L L L H | H L H H H H H H H H | + * | L L H L | H H L H H H H H H H | + * | L L H H | H H H L H H H H H H | + * | L H L L | H H H H L H H H H H | + * |-------------------------------| + * | L H L H | H H H H H L H H H H | + * | L H H L | H H H H H H L H H H | + * | L H H H | H H H H H H H L H H | + * | H L L L | H H H H H H H H L H | + * | H L L H | H H H H H H H H H L | + * |-------------------------------| + * | H L H L | H H H H H H H H H H | + * | H L H H | H H H H H H H H H H | + * | H H L L | H H H H H H H H H H | + * | H H L H | H H H H H H H H H H | + * | H H H L | H H H H H H H H H H | + * | H H H H | H H H H H H H H H H | + * ------------------------------- + * + ****************************************************************************/ + +#include "emu.h" +#include "74145.h" +#include "coreutil.h" + + +const device_type TTL74145 = &device_creator; + +/*************************************************************************** + DEVICE INTERFACE +***************************************************************************/ +//------------------------------------------------- +// ttl74145_device - constructor +//------------------------------------------------- + +ttl74145_device::ttl74145_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, TTL74145, "TTL74145", tag, owner, clock, "ttl74145", __FILE__) + , m_output_line_0_cb(*this) + , m_output_line_1_cb(*this) + , m_output_line_2_cb(*this) + , m_output_line_3_cb(*this) + , m_output_line_4_cb(*this) + , m_output_line_5_cb(*this) + , m_output_line_6_cb(*this) + , m_output_line_7_cb(*this) + , m_output_line_8_cb(*this) + , m_output_line_9_cb(*this) + , m_number(0) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void ttl74145_device::device_start() +{ + /* resolve callbacks */ + m_output_line_0_cb.resolve_safe(); + m_output_line_1_cb.resolve_safe(); + m_output_line_2_cb.resolve_safe(); + m_output_line_3_cb.resolve_safe(); + m_output_line_4_cb.resolve_safe(); + m_output_line_5_cb.resolve_safe(); + m_output_line_6_cb.resolve_safe(); + m_output_line_7_cb.resolve_safe(); + m_output_line_8_cb.resolve_safe(); + m_output_line_9_cb.resolve_safe(); + + // register for state saving + save_item(NAME(m_number)); +} + +//------------------------------------------------- +// device_start - device-specific reset +//------------------------------------------------- + +void ttl74145_device::device_reset() +{ + m_number = 0; +} + +/*************************************************************************** + IMPLEMENTATION +***************************************************************************/ + +void ttl74145_device::write(UINT8 data) +{ + /* decode number */ + UINT16 new_number = bcd_2_dec(data & 0x0f); + + /* call output callbacks if the number changed */ + if (new_number != m_number) + { + m_output_line_0_cb(new_number == 0); + m_output_line_1_cb(new_number == 1); + m_output_line_2_cb(new_number == 2); + m_output_line_3_cb(new_number == 3); + m_output_line_4_cb(new_number == 4); + m_output_line_5_cb(new_number == 5); + m_output_line_6_cb(new_number == 6); + m_output_line_7_cb(new_number == 7); + m_output_line_8_cb(new_number == 8); + m_output_line_9_cb(new_number == 9); + } + + /* update state */ + m_number = new_number; +} + + +UINT16 ttl74145_device::read() +{ + return (1 << m_number) & 0x3ff; +} diff --git a/src/devices/machine/74145.h b/src/devices/machine/74145.h new file mode 100644 index 00000000000..9b047207f1b --- /dev/null +++ b/src/devices/machine/74145.h @@ -0,0 +1,96 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best +/*************************************************************************** + + TTL74145 + + BCD-to-Decimal decoder + +***************************************************************************/ + +#ifndef __TTL74145_H__ +#define __TTL74145_H__ + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** +#define MCFG_TTL74145_OUTPUT_LINE_0_CB(_devcb) \ + devcb = &ttl74145_device::set_output_line_0_callback(*device, DEVCB_##_devcb); + +#define MCFG_TTL74145_OUTPUT_LINE_1_CB(_devcb) \ + devcb = &ttl74145_device::set_output_line_1_callback(*device, DEVCB_##_devcb); + +#define MCFG_TTL74145_OUTPUT_LINE_2_CB(_devcb) \ + devcb = &ttl74145_device::set_output_line_2_callback(*device, DEVCB_##_devcb); + +#define MCFG_TTL74145_OUTPUT_LINE_3_CB(_devcb) \ + devcb = &ttl74145_device::set_output_line_3_callback(*device, DEVCB_##_devcb); + +#define MCFG_TTL74145_OUTPUT_LINE_4_CB(_devcb) \ + devcb = &ttl74145_device::set_output_line_4_callback(*device, DEVCB_##_devcb); + +#define MCFG_TTL74145_OUTPUT_LINE_5_CB(_devcb) \ + devcb = &ttl74145_device::set_output_line_5_callback(*device, DEVCB_##_devcb); + +#define MCFG_TTL74145_OUTPUT_LINE_6_CB(_devcb) \ + devcb = &ttl74145_device::set_output_line_6_callback(*device, DEVCB_##_devcb); + +#define MCFG_TTL74145_OUTPUT_LINE_7_CB(_devcb) \ + devcb = &ttl74145_device::set_output_line_7_callback(*device, DEVCB_##_devcb); + +#define MCFG_TTL74145_OUTPUT_LINE_8_CB(_devcb) \ + devcb = &ttl74145_device::set_output_line_8_callback(*device, DEVCB_##_devcb); + +#define MCFG_TTL74145_OUTPUT_LINE_9_CB(_devcb) \ + devcb = &ttl74145_device::set_output_line_9_callback(*device, DEVCB_##_devcb); + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> ttl74145_device + +class ttl74145_device : public device_t +{ +public: + // construction/destruction + ttl74145_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + template static devcb_base &set_output_line_0_callback(device_t &device, _Object object) { return downcast(device).m_output_line_0_cb.set_callback(object); } + template static devcb_base &set_output_line_1_callback(device_t &device, _Object object) { return downcast(device).m_output_line_1_cb.set_callback(object); } + template static devcb_base &set_output_line_2_callback(device_t &device, _Object object) { return downcast(device).m_output_line_2_cb.set_callback(object); } + template static devcb_base &set_output_line_3_callback(device_t &device, _Object object) { return downcast(device).m_output_line_3_cb.set_callback(object); } + template static devcb_base &set_output_line_4_callback(device_t &device, _Object object) { return downcast(device).m_output_line_4_cb.set_callback(object); } + template static devcb_base &set_output_line_5_callback(device_t &device, _Object object) { return downcast(device).m_output_line_5_cb.set_callback(object); } + template static devcb_base &set_output_line_6_callback(device_t &device, _Object object) { return downcast(device).m_output_line_6_cb.set_callback(object); } + template static devcb_base &set_output_line_7_callback(device_t &device, _Object object) { return downcast(device).m_output_line_7_cb.set_callback(object); } + template static devcb_base &set_output_line_8_callback(device_t &device, _Object object) { return downcast(device).m_output_line_8_cb.set_callback(object); } + template static devcb_base &set_output_line_9_callback(device_t &device, _Object object) { return downcast(device).m_output_line_9_cb.set_callback(object); } + + UINT16 read(); + void write(UINT8 data); +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + +private: + devcb_write_line m_output_line_0_cb; + devcb_write_line m_output_line_1_cb; + devcb_write_line m_output_line_2_cb; + devcb_write_line m_output_line_3_cb; + devcb_write_line m_output_line_4_cb; + devcb_write_line m_output_line_5_cb; + devcb_write_line m_output_line_6_cb; + devcb_write_line m_output_line_7_cb; + devcb_write_line m_output_line_8_cb; + devcb_write_line m_output_line_9_cb; + + /* decoded number */ + UINT16 m_number; +}; + +// device type definition +extern const device_type TTL74145; + +#endif /* TTL74145 */ diff --git a/src/devices/machine/74148.c b/src/devices/machine/74148.c new file mode 100644 index 00000000000..02d1be3927a --- /dev/null +++ b/src/devices/machine/74148.c @@ -0,0 +1,198 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/***************************************************************************** + + 74148 8-line-to-3-line priority encoder + + + Pin layout and functions to access pins: + + input_line_w(4) [1] /IN4 VCC [16] + input_line_w(5) [2] /IN5 /EO [15] enable_output_r + input_line_w(6) [3] /IN6 /GS [14] output_valid_r + input_line_w(7) [4] /IN7 /IN3 [13] input_line_w(3) + enable_input_w [5] /EI /IN2 [12] input_line_w(2) + output_r [6] /A2 /IN1 [11] input_line_w(1) + output_r [7] /A1 /IN0 [10] input_line_w(0) + [8] GND /A0 [9] output_r + + + Truth table (all logic levels indicate the actual voltage on the line): + + INPUTS | OUTPUTS + | + EI I0 I1 I2 I3 I4 I5 I6 I7 | A2 A1 A0 | GS EO + ----------------------------+----------+------ + 1 H X X X X X X X X | H H H | H H + 2 L H H H H H H H H | H H H | H L + 3 L X X X X X X X L | L L L | L H + 4 L X X X X X X L H | L L H | L H + 5 L X X X X X L H H | L H L | L H + 6 L X X X X L H H H | L H H | L H + 7 L X X X L H H H H | H L L | L H + 8 L X X L H H H H H | H L H | L H + 9 L X L H H H H H H | H H L | L H + 10 L L H H H H H H H | H H H | L H + ----------------------------+----------+------ + L = lo (0) + H = hi (1) + X = any state + +*****************************************************************************/ + +#include "emu.h" +#include "machine/74148.h" + + +const device_type TTL74148 = &device_creator; + +ttl74148_device::ttl74148_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, TTL74148, "74148 TTL", tag, owner, clock, "74148", __FILE__), + m_enable_input(0), + m_output(0), + m_output_valid(0), + m_enable_output(0), + m_last_output(0), + m_last_output_valid(0), + m_last_enable_output(0) +{ + for (int i = 0; i < 8; i++) + m_input_lines[i] = 0; +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void ttl74148_device::device_start() +{ + m_output_cb.bind_relative_to(*owner()); + + save_item(NAME(m_input_lines)); + save_item(NAME(m_enable_input)); + save_item(NAME(m_output)); + save_item(NAME(m_output_valid)); + save_item(NAME(m_enable_output)); + save_item(NAME(m_last_output)); + save_item(NAME(m_last_output_valid)); + save_item(NAME(m_last_enable_output)); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void ttl74148_device::device_reset() +{ + m_enable_input = 1; + m_input_lines[0] = 1; + m_input_lines[1] = 1; + m_input_lines[2] = 1; + m_input_lines[3] = 1; + m_input_lines[4] = 1; + m_input_lines[5] = 1; + m_input_lines[6] = 1; + m_input_lines[7] = 1; + + m_last_output = -1; + m_last_output_valid = -1; + m_last_enable_output = -1; +} + + +void ttl74148_device::update() +{ + if (m_enable_input) + { + // row 1 in truth table + m_output = 0x07; + m_output_valid = 1; + m_enable_output = 1; + } + else + { + int bit0, bit1, bit2; + + /* this comes straight off the data sheet schematics */ + bit0 = !(((!m_input_lines[1]) & + m_input_lines[2] & + m_input_lines[4] & + m_input_lines[6]) | + ((!m_input_lines[3]) & + m_input_lines[4] & + m_input_lines[6]) | + ((!m_input_lines[5]) & + m_input_lines[6]) | + (!m_input_lines[7])); + + bit1 = !(((!m_input_lines[2]) & + m_input_lines[4] & + m_input_lines[5]) | + ((!m_input_lines[3]) & + m_input_lines[4] & + m_input_lines[5]) | + (!m_input_lines[6]) | + (!m_input_lines[7])); + + bit2 = !((!m_input_lines[4]) | + (!m_input_lines[5]) | + (!m_input_lines[6]) | + (!m_input_lines[7])); + + m_output = (bit2 << 2) | (bit1 << 1) | bit0; + + m_output_valid = (m_input_lines[0] & + m_input_lines[1] & + m_input_lines[2] & + m_input_lines[3] & + m_input_lines[4] & + m_input_lines[5] & + m_input_lines[6] & + m_input_lines[7]); + + m_enable_output = !m_output_valid; + } + + + /* call callback if any of the outputs changed */ + if (!m_output_cb.isnull() && + ((m_output != m_last_output) || + (m_output_valid != m_last_output_valid) || (m_enable_output != m_last_enable_output))) + { + m_last_output = m_output; + m_last_output_valid = m_output_valid; + m_last_enable_output = m_enable_output; + + m_output_cb(); + } +} + + +void ttl74148_device::input_line_w(int input_line, int data) +{ + m_input_lines[input_line] = data ? 1 : 0; +} + + +void ttl74148_device::enable_input_w(int data) +{ + m_enable_input = data ? 1 : 0; +} + + +int ttl74148_device::output_r() +{ + return m_output; +} + + +int ttl74148_device::output_valid_r() +{ + return m_output_valid; +} + + +int ttl74148_device::enable_output_r() +{ + return m_enable_output; +} diff --git a/src/devices/machine/74148.h b/src/devices/machine/74148.h new file mode 100644 index 00000000000..294869de12f --- /dev/null +++ b/src/devices/machine/74148.h @@ -0,0 +1,99 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/***************************************************************************** + + 74148 8-line-to-3-line priority encoder + + + Pin layout and functions to access pins: + + input_line_w(4) [1] /IN4 VCC [16] + input_line_w(5) [2] /IN5 /EO [15] enable_output_r + input_line_w(6) [3] /IN6 /GS [14] output_valid_r + input_line_w(7) [4] /IN7 /IN3 [13] input_line_w(3) + enable_input_w [5] /EI /IN2 [12] input_line_w(2) + output_r [6] /A2 /IN1 [11] input_line_w(1) + output_r [7] /A1 /IN0 [10] input_line_w(0) + [8] GND /A0 [9] output_r + + + Truth table (all logic levels indicate the actual voltage on the line): + + INPUTS | OUTPUTS + | + EI I0 I1 I2 I3 I4 I5 I6 I7 | A2 A1 A0 | GS EO + ----------------------------+----------+------ + H X X X X X X X X | H H H | H H + L H H H H H H H H | H H H | H L + L X X X X X X X L | L L L | L H + L X X X X X X L H | L L H | L H + L X X X X X L H H | L H L | L H + L X X X X L H H H | L H H | L H + L X X X L H H H H | H L L | L H + L X X L H H H H H | H L H | L H + L X L H H H H H H | H H L | L H + L L H H H H H H H | H H H | L H + ----------------------------+----------+------ + L = lo (0) + H = hi (1) + X = any state + +*****************************************************************************/ + +#ifndef TTL74148_H +#define TTL74148_H + + +typedef device_delegate ttl74148_output_delegate; + +#define TTL74148_OUTPUT_CB(_name) void _name(void) + + +class ttl74148_device : public device_t +{ +public: + ttl74148_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + ~ttl74148_device() {} + + static void set_output_callback(device_t &device, ttl74148_output_delegate callback) { downcast(device).m_output_cb = callback; } + + /* must call update() after setting the inputs */ + void update(); + + void input_line_w(int input_line, int data); + void enable_input_w(int data); + int output_r(); + int output_valid_r(); + int enable_output_r(); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); +private: + // internal state + ttl74148_output_delegate m_output_cb; + + /* inputs */ + int m_input_lines[8]; /* pins 1-4,10-13 */ + int m_enable_input; /* pin 5 */ + + /* outputs */ + int m_output; /* pins 6,7,9 */ + int m_output_valid; /* pin 14 */ + int m_enable_output; /* pin 15 */ + + /* internals */ + int m_last_output; + int m_last_output_valid; + int m_last_enable_output; +}; + +extern const device_type TTL74148; + + +#define MCFG_74148_OUTPUT_CB(_class, _method) \ + ttl74148_device::set_output_callback(*device, ttl74148_output_delegate(&_class::_method, #_class "::" #_method, downcast<_class *>(owner))); + + +#endif diff --git a/src/devices/machine/74153.c b/src/devices/machine/74153.c new file mode 100644 index 00000000000..e38194f5d6e --- /dev/null +++ b/src/devices/machine/74153.c @@ -0,0 +1,172 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/***************************************************************************** + + 74153 Dual 4-line to 1-line data selectors/multiplexers + + + Pin layout and functions to access pins: + + enable_w(0) [1] /1G VCC [16] + b_w [2] B /2G [15] enable_w(1) + input_line_w(0,3) [3] 1C3 A [14] a_w + input_line_w(0,2) [4] 1C2 2C3 [13] input_line_w(1,3) + input_line_w(0,1) [5] 1C1 2C2 [12] input_line_w(1,2) + input_line_w(0,0) [6] 1C0 2C1 [11] input_line_w(1,1) + output_r(0) [7] 1Y 2C0 [10] input_line_w(1,0) + [8] GND 2Y [9] output_r(1) + + + Truth table (all logic levels indicate the actual voltage on the line): + + INPUTS | OUTPUT + | + G | B A | C0 C1 C2 C3 | Y + --+------+-------------+--- +1 H | X X | X X X X | L +2 L | L L | X X X X | C0 +3 L | L H | X X X X | C1 +4 L | H L | X X X X | C2 +5 L | H H | X X X X | C3 + --+------+-------------+--- + L = lo (0) + H = hi (1) + X = any state + +*****************************************************************************/ + +#include "emu.h" +#include "machine/74153.h" + + +const device_type TTL74153 = &device_creator; + +ttl74153_device::ttl74153_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, TTL74153, "74153 TTL", tag, owner, clock, "74153", __FILE__), + m_a(0), + m_b(0) +{ + m_input_lines[0][0] = 0; + m_input_lines[0][1] = 0; + m_input_lines[0][2] = 0; + m_input_lines[0][3] = 0; + m_input_lines[1][0] = 0; + m_input_lines[1][1] = 0; + m_input_lines[1][2] = 0; + m_input_lines[1][3] = 0; + + for (int i = 0; i < 2; i++) + m_enable[i] = 0; + + for (int i = 0; i < 2; i++) + m_output[i] = 0; + + for (int i = 0; i < 2; i++) + m_last_output[i] = 0; +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void ttl74153_device::device_start() +{ + m_output_cb.bind_relative_to(*owner()); + + save_item(NAME(m_enable)); + save_item(NAME(m_last_output)); + save_item(NAME(m_input_lines[0][0])); + save_item(NAME(m_input_lines[0][1])); + save_item(NAME(m_input_lines[0][2])); + save_item(NAME(m_input_lines[0][3])); + save_item(NAME(m_input_lines[1][0])); + save_item(NAME(m_input_lines[1][1])); + save_item(NAME(m_input_lines[1][2])); + save_item(NAME(m_input_lines[1][3])); + save_item(NAME(m_a)); + save_item(NAME(m_b)); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void ttl74153_device::device_reset() +{ + m_a = 1; + m_b = 1; + m_enable[0] = 1; + m_enable[1] = 1; + m_input_lines[0][0] = 1; + m_input_lines[0][1] = 1; + m_input_lines[0][2] = 1; + m_input_lines[0][3] = 1; + m_input_lines[1][0] = 1; + m_input_lines[1][1] = 1; + m_input_lines[1][2] = 1; + m_input_lines[1][3] = 1; + + m_last_output[0] = -1; + m_last_output[1] = -1; +} + + +void ttl74153_device::update() +{ + int sel; + int section; + + + sel = (m_b << 1) | m_a; + + + /* process both sections */ + for (section = 0; section < 2; section++) + { + if (m_enable[section]) + m_output[section] = 0; // row 1 in truth table + else + m_output[section] = m_input_lines[section][sel]; + } + + + /* call callback if either of the outputs changed */ + if (!m_output_cb.isnull() && + ((m_output[0] != m_last_output[0]) || (m_output[1] != m_last_output[1]))) + { + m_last_output[0] = m_output[0]; + m_last_output[1] = m_output[1]; + + m_output_cb(); + } +} + + +void ttl74153_device::a_w(int data) +{ + m_a = data ? 1 : 0; +} + + +void ttl74153_device::b_w(int data) +{ + m_b = data ? 1 : 0; +} + + +void ttl74153_device::input_line_w(int section, int input_line, int data) +{ + m_input_lines[section][input_line] = data ? 1 : 0; +} + + +void ttl74153_device::enable_w(int section, int data) +{ + m_enable[section] = data ? 1 : 0; +} + + +int ttl74153_device::output_r(int section) +{ + return m_output[section]; +} diff --git a/src/devices/machine/74153.h b/src/devices/machine/74153.h new file mode 100644 index 00000000000..bfd9967e0e4 --- /dev/null +++ b/src/devices/machine/74153.h @@ -0,0 +1,92 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/***************************************************************************** + + 74153 Dual 4-line to 1-line data selectors/multiplexers + + + Pin layout and functions to access pins: + + enable_w(0) [1] /1G VCC [16] + b_w [2] B /2G [15] enable_w(1) + input_line_w(0,3) [3] 1C3 A [14] a_w + input_line_w(0,2) [4] 1C2 2C3 [13] input_line_w(1,3) + input_line_w(0,1) [5] 1C1 2C2 [12] input_line_w(1,2) + input_line_w(0,0) [6] 1C0 2C1 [11] input_line_w(1,1) + output_r(0) [7] 1Y 2C0 [10] input_line_w(1,0) + [8] GND 2Y [9] output_r(1) + + + Truth table (all logic levels indicate the actual voltage on the line): + + INPUTS | OUTPUT + | + G | B A | C0 C1 C2 C3 | Y + --+------+-------------+--- + H | X X | X X X X | L + L | L L | X X X X | C0 + L | L H | X X X X | C1 + L | H L | X X X X | C2 + L | H H | X X X X | C3 + --+------+-------------+--- + L = lo (0) + H = hi (1) + X = any state + +*****************************************************************************/ + +#ifndef TTL74153_H +#define TTL74153_H + + +typedef device_delegate ttl74153_output_delegate; + +#define TTL74153_OUTPUT_CB(_name) void _name(void) + + +class ttl74153_device : public device_t +{ +public: + ttl74153_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + ~ttl74153_device() {} + + static void set_output_callback(device_t &device, ttl74153_output_delegate callback) { downcast(device).m_output_cb = callback; } + + /* must call update() after setting the inputs */ + void update(); + + void a_w(int data); + void b_w(int data); + void input_line_w(int section, int input_line, int data); + void enable_w(int section, int data); + int output_r(int section); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + +private: + // internal state + ttl74153_output_delegate m_output_cb; + + /* inputs */ + int m_a; /* pin 14 */ + int m_b; /* pin 2 */ + int m_input_lines[2][4]; /* pins 3-6,10-13 */ + int m_enable[2]; /* pins 1,15 */ + + /* output */ + int m_output[2]; /* pins 7,9 */ + + /* internals */ + int m_last_output[2]; +}; + +extern const device_type TTL74153; + + +#define MCFG_74153_OUTPUT_CB(_class, _method) \ + ttl74153_device::set_output_callback(*device, ttl74153_output_delegate(&_class::_method, #_class "::" #_method, downcast<_class *>(owner))); + +#endif diff --git a/src/devices/machine/74181.c b/src/devices/machine/74181.c new file mode 100644 index 00000000000..dee894446ea --- /dev/null +++ b/src/devices/machine/74181.c @@ -0,0 +1,150 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + 74181 + + 4-Bit Arithmetic Logic Unit + +***************************************************************************/ + +#include "74181.h" + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type TTL74181 = &device_creator; + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// ttl74181_device - constructor +//------------------------------------------------- + +ttl74181_device::ttl74181_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, TTL74181, "74181 TTL", tag, owner, clock, "ttl74181", __FILE__), + m_a(0), + m_b(0), + m_s(0), + m_m(0), + m_c(0) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void ttl74181_device::device_start() +{ + // register for state saving + save_item(NAME(m_a)); + save_item(NAME(m_b)); + save_item(NAME(m_s)); + save_item(NAME(m_m)); + save_item(NAME(m_c)); + + update(); +} + +//------------------------------------------------- +// device_post_load - called after loading a saved state +//------------------------------------------------- + +void ttl74181_device::device_post_load() +{ + // after loading a state re-initialize our output lines + update(); +} + + +//************************************************************************** +// ARITHMETHIC UNIT +//************************************************************************** + +void ttl74181_device::update() +{ + // inputs + int a0 = BIT(m_a, 0), a1 = BIT(m_a, 1), a2 = BIT(m_a, 2), a3 = BIT(m_a, 3); + int b0 = BIT(m_b, 0), b1 = BIT(m_b, 1), b2 = BIT(m_b, 2), b3 = BIT(m_b, 3); + int s0 = BIT(m_s, 0), s1 = BIT(m_s, 1), s2 = BIT(m_s, 2), s3 = BIT(m_s, 3); + int mp = !m_m; + + // intermediate calculations + int ap0 = !(a0 | (b0 & s0) | (s1 & !b0)); + int bp0 = !(((!b0) & s2 & a0) | (a0 & b0 & s3)); + int ap1 = !(a1 | (b1 & s0) | (s1 & !b1)); + int bp1 = !(((!b1) & s2 & a1) | (a1 & b1 & s3)); + int ap2 = !(a2 | (b2 & s0) | (s1 & !b2)); + int bp2 = !(((!b2) & s2 & a2) | (a2 & b2 & s3)); + int ap3 = !(a3 | (b3 & s0) | (s1 & !b3)); + int bp3 = !(((!b3) & s2 & a3) | (a3 & b3 & s3)); + + int fp0 = !(m_c & mp) ^ ((!ap0) & bp0); + int fp1 = (!((mp & ap0) | (mp & bp0 & m_c))) ^ ((!ap1) & bp1); + int fp2 = (!((mp & ap1) | (mp & ap0 & bp1) | (mp & m_c & bp0 & bp1))) ^ ((!ap2) & bp2); + int fp3 = (!((mp & ap2) | (mp & ap1 & bp2) | (mp & ap0 & bp1 & bp2) | (mp & m_c & bp0 & bp1 & bp2))) ^ ((!ap3) & bp3); + + // outputs + m_f = fp0 | fp1 << 1 | fp2 << 2 | fp3 << 3; + m_equals = fp0 & fp1 & fp2 & fp3; + m_p = !(bp0 & bp1 & bp2 & bp3); + m_g = !((ap0 & bp1 & bp2 & bp3) | (ap1 & bp2 & bp3) | (ap2 & bp3) | ap3); + m_cn = (!(m_c & bp0 & bp1 & bp2 & bp3)) | m_g; +} + +void ttl74181_device::input_a_w(UINT8 data) +{ + data &= 0x0f; + + if (m_a != data) + { + m_a = data; + update(); + } +} + +void ttl74181_device::input_b_w(UINT8 data) +{ + data &= 0x0f; + + if (m_b != data) + { + m_b = data; + update(); + } +} + +void ttl74181_device::select_w(UINT8 data) +{ + data &= 0x0f; + + if (m_s != data) + { + m_s = data; + update(); + } +} + +WRITE_LINE_MEMBER( ttl74181_device::mode_w ) +{ + if (m_m != state) + { + m_m = state; + update(); + } +} + +WRITE_LINE_MEMBER( ttl74181_device::carry_w ) +{ + if (m_c != state) + { + m_c = state; + update(); + } +} diff --git a/src/devices/machine/74181.h b/src/devices/machine/74181.h new file mode 100644 index 00000000000..5aeb64768f7 --- /dev/null +++ b/src/devices/machine/74181.h @@ -0,0 +1,80 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + 74181 + + 4-Bit Arithmetic Logic Unit + +***************************************************************************/ + +#pragma once + +#ifndef __74181_H__ +#define __74181_H__ + +#include "emu.h" + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_TTL74181_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, TTL74181, 0) + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> ttl74181_device + +class ttl74181_device : public device_t +{ +public: + // construction/destruction + ttl74181_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // inputs + void input_a_w(UINT8 data); + void input_b_w(UINT8 data); + void select_w(UINT8 data); + DECLARE_WRITE_LINE_MEMBER( mode_w ); + DECLARE_WRITE_LINE_MEMBER( carry_w ); + + // outputs + UINT8 function_r() { return m_f; } + DECLARE_READ_LINE_MEMBER( carry_r ) { return m_cn; } + DECLARE_READ_LINE_MEMBER( generate_r ) { return m_g; } + DECLARE_READ_LINE_MEMBER( propagate_r ) { return m_p; } + DECLARE_READ_LINE_MEMBER( equals_r ) { return m_equals; } + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_post_load(); + +private: + void update(); + + // inputs + UINT8 m_a; + UINT8 m_b; + UINT8 m_s; + int m_m; + int m_c; + + // outputs + UINT8 m_f; + int m_cn; + int m_g; + int m_p; + int m_equals; +}; + + +// device type definition +extern const device_type TTL74181; + + +#endif /* __74181_H__ */ diff --git a/src/devices/machine/7474.c b/src/devices/machine/7474.c new file mode 100644 index 00000000000..1b6ce95033d --- /dev/null +++ b/src/devices/machine/7474.c @@ -0,0 +1,216 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/***************************************************************************** + + 7474 positive-edge-triggered D-type flip-flop with preset, clear and + complementary outputs. There are 2 flip-flops per chips + + + Pin layout and functions to access pins: + + clear_w [1] /1CLR VCC [14] + d_w [2] 1D /2CLR [13] clear_w + clock_w [3] 1CLK 2D [12] d_w + preset_w [4] /1PR 2CLK [11] clock_w + output_r [5] 1Q /2PR [10] preset_w + output_comp_r [6] /1Q 2Q [9] output_r + [7] GND /2Q [8] output_comp_r + + + Truth table (all logic levels indicate the actual voltage on the line): + + INPUTS | OUTPUTS + | + PR CLR CLK D | Q /Q + --------------+------- + 1 L H X X | H L + 2 H L X X | L H + 3 L L X X | H H (Note 1) + 4 H H _- X | D /D + 5 H H L X | Q0 /Q0 + --------------+------- + L = lo (0) + H = hi (1) + X = any state + _- = raising edge + Q0 = previous state + + Note 1: Non-stable configuration + +*****************************************************************************/ + +#include "emu.h" +#include "7474.h" + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +// device type definition +const device_type TTL7474 = &device_creator; + +//------------------------------------------------- +// ttl7474_device - constructor +//------------------------------------------------- + +ttl7474_device::ttl7474_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, TTL7474, "7474 TTL", tag, owner, clock, "7474", __FILE__), + m_output_func(*this), + m_comp_output_func(*this) +{ + init(); +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void ttl7474_device::device_start() +{ + save_item(NAME(m_clear)); + save_item(NAME(m_preset)); + save_item(NAME(m_clk)); + save_item(NAME(m_d)); + save_item(NAME(m_output)); + save_item(NAME(m_output_comp)); + save_item(NAME(m_last_clock)); + save_item(NAME(m_last_output)); + save_item(NAME(m_last_output_comp)); + + m_output_func.resolve_safe(); + m_comp_output_func.resolve_safe(); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void ttl7474_device::device_reset() +{ + init(); +} + + +//------------------------------------------------- +// update - update internal state +//------------------------------------------------- + +void ttl7474_device::update() +{ + if (!m_preset && m_clear) // line 1 in truth table + { + m_output = 1; + m_output_comp = 0; + } + else if (m_preset && !m_clear) // line 2 in truth table + { + m_output = 0; + m_output_comp = 1; + } + else if (!m_preset && !m_clear) // line 3 in truth table + { + m_output = 1; + m_output_comp = 1; + } + else if (!m_last_clock && m_clk) // line 4 in truth table + { + m_output = m_d; + m_output_comp = !m_d; + } + + m_last_clock = m_clk; + + + // call callback if any of the outputs changed + if (m_output != m_last_output) + { + m_last_output = m_output; + m_output_func(m_output); + } + // call callback if any of the outputs changed + if (m_output_comp != m_last_output_comp) + { + m_last_output_comp = m_output_comp; + m_comp_output_func(m_output_comp); + } +} + + +//------------------------------------------------- +// clear_w - set the clear line state +//------------------------------------------------- + +WRITE_LINE_MEMBER( ttl7474_device::clear_w ) +{ + m_clear = state & 1; + update(); +} + + +//------------------------------------------------- +// clear_w - set the clear line state +//------------------------------------------------- + +WRITE_LINE_MEMBER( ttl7474_device::preset_w ) +{ + m_preset = state & 1; + update(); +} + + +//------------------------------------------------- +// clock_w - set the clock line state +//------------------------------------------------- + +WRITE_LINE_MEMBER( ttl7474_device::clock_w ) +{ + m_clk = state & 1; + update(); +} + + +//------------------------------------------------- +// d_w - set the d line state +//------------------------------------------------- + +WRITE_LINE_MEMBER( ttl7474_device::d_w ) +{ + m_d = state & 1; + update(); +} + + +//------------------------------------------------- +// output_r - get the output line state +//------------------------------------------------- + +READ_LINE_MEMBER( ttl7474_device::output_r ) +{ + return m_output; +} + + +//----------------------------------------------------- +// output_comp_r - get the output-compare line state +//----------------------------------------------------- + +READ_LINE_MEMBER( ttl7474_device::output_comp_r ) +{ + return m_output_comp; +} + +void ttl7474_device::init() +{ + m_clear = 1; + m_preset = 1; + m_clk = 1; + m_d = 1; + + m_output = -1; + m_last_clock = 1; + m_last_output = -1; + m_last_output_comp = -1; +} diff --git a/src/devices/machine/7474.h b/src/devices/machine/7474.h new file mode 100644 index 00000000000..9373e41d7d3 --- /dev/null +++ b/src/devices/machine/7474.h @@ -0,0 +1,121 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/***************************************************************************** + + 7474 positive-edge-triggered D-type flip-flop with preset, clear and + complementary outputs. There are 2 flip-flops per chips + + + Pin layout and functions to access pins: + + clear_w [1] /1CLR VCC [14] + d_w [2] 1D /2CLR [13] clear_w + clock_w [3] 1CLK 2D [12] d_w + preset_w [4] /1PR 2CLK [11] clock_w + output_r [5] 1Q /2PR [10] preset_w + output_comp_r [6] /1Q 2Q [9] output_r + [7] GND /2Q [8] output_comp_r + + + Truth table (all logic levels indicate the actual voltage on the line): + + INPUTS | OUTPUTS + | + PR CLR CLK D | Q /Q + --------------+------- + L H X X | H L + H L X X | L H + L L X X | H H (Note 1) + H H _- X | D /D + H H L X | Q0 /Q01 + --------------+------- + L = lo (0) + H = hi (1) + X = any state + _- = raising edge + Q0 = previous state + + Note 1: Non-stable configuration + +*****************************************************************************/ + +#pragma once + +#ifndef __TTL7474_H__ +#define __TTL7474_H__ + +#include "emu.h" + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_7474_OUTPUT_CB(_devcb) \ + devcb = &ttl7474_device::set_output_cb(*device, DEVCB_##_devcb); + +#define MCFG_7474_COMP_OUTPUT_CB(_devcb) \ + devcb = &ttl7474_device::set_comp_output_cb(*device, DEVCB_##_devcb); + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> ttl7474_device + +class ttl7474_device : public device_t +{ +public: + // construction/destruction + ttl7474_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // static configuration helpers + template static devcb_base &set_output_cb(device_t &device, _Object object) { return downcast(device).m_output_func.set_callback(object); } + template static devcb_base &set_comp_output_cb(device_t &device, _Object object) { return downcast(device).m_comp_output_func.set_callback(object); } + + // public interfaces + DECLARE_WRITE_LINE_MEMBER( clear_w ); + DECLARE_WRITE_LINE_MEMBER( preset_w ); + DECLARE_WRITE_LINE_MEMBER( clock_w ); + DECLARE_WRITE_LINE_MEMBER( d_w ); + DECLARE_READ_LINE_MEMBER( output_r ); + DECLARE_READ_LINE_MEMBER( output_comp_r ); // NOT strictly the same as !output_r() + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_post_load() { } + virtual void device_clock_changed() { } +private: + // callbacks + devcb_write_line m_output_func; + devcb_write_line m_comp_output_func; + + // inputs + UINT8 m_clear; // pin 1/13 + UINT8 m_preset; // pin 4/10 + UINT8 m_clk; // pin 3/11 + UINT8 m_d; // pin 2/12 + + // outputs + UINT8 m_output; // pin 5/9 + UINT8 m_output_comp; // pin 6/8 + + // internal + UINT8 m_last_clock; + UINT8 m_last_output; + UINT8 m_last_output_comp; + + void update(); + void init(); +}; + + +// device type definition +extern const device_type TTL7474; + + +#endif /* __TTL7474_H__ */ diff --git a/src/devices/machine/8042kbdc.c b/src/devices/machine/8042kbdc.c new file mode 100644 index 00000000000..a1d36a41b43 --- /dev/null +++ b/src/devices/machine/8042kbdc.c @@ -0,0 +1,618 @@ +// license:BSD-3-Clause +// copyright-holders:Peter Trauner +/********************************************************************* + + 8042kbdc.c + + Code specific to fun IBM AT stuff + + + PeT's notes about various Power On Self Tests (POSTs) + + at post + ------- + f81d2 01 + f82e6 05 + f8356 07 + f83e5 0a + f847e 0e + f8e7c 10 + f8f3a 13 + f9058 1a + f913a 1e + fa8ba 30 + fa96c 36 + fa9d3 3c + fa9f4 3e + ff122 50 + ff226 5b + ff29f 5f + f9228 70 + f92b2 74 ide? + + ibm at bios + ----------- + f0101 after switch to real mode jump back!!!!!!!!!! + jumping table + f0123 + f098e memory tests + f10b4 ??? + not reached + f1050 + f1617 + f0119 + f10d8 + f10b7 system board error + + f019f + f025b + f02e6 + f0323 + f03b3 0e + f03d7 0f + f058d + at8042 signal timing test + sets errorcode! + + f0655 + f06a3 postcode 15 + f06ba 16 + f0747 18 + f0763 enter pm! (0x81, 0x85) + f0766 1a + f07b3 first 640kb memory test + f084c 1c + f086e extended memory test + f0928 1f + f097d 20 + ??? + f0ff4 34 + ??? + f1675 f0 + f16cb f2 + illegal access trap test!!!! + f16fe f3 + task descriptor test!!!! + f174a f4 + f17af f5 + f1800 f6 writing to non write segment + f1852 f7 arpl + f1880 f8 lar, lsl + f18ca fa + f10d8 + f10ec 35 + f1106 36 + f1137 !!!!!!!keyboard test fails + + f11aa 3a + f1240 3c harddisk controller test!!! + f13f3 3b + f1a6d xthdd bios init + f1429 + f1462 + f1493 40 + f1532 + keyboard lock + f1 to unlock + f155c + jumps to f0050 (reset) without enabling of the a20 gate --> hangs + 0412 bit 5 must be set to reach f1579 + f1579 + f15c3 41 + f1621 43 + + routines + f1945 read cmos ram + f195f write to cmos al value ah + f1a3a poll 0x61 bit 4 + f1a49 sets something in cmos ram + f1d30 switch to protected mode + + neat + ---- + f80b9 + + at386 + ----- + fd28c fd + fd2c3 fc + f40dc + fd949 + fd8e3 + fd982 + f4219 01 + f4296 03 + f42f3 04 + f4377 05 + f43ec 06 + f4430 08 + f6017 switches to PM + f4456 09 + f55a2 + f44ec 0d + f4557 20 + f462d 27 my special friend, the keyboard controller once more + ed0a1 + f4679 28 + fa16a + f46d6 + f4768 2c + f47f0 2e + f5081 + fa16a + f9a83 + Message: "Checksum Error on Extended CMOS" + f4840 34 + f488c 35 + reset + f48ee + f493e 3a + f49cd + f4fc7 + fe842 + f4a5a + f4b01 38 + (Memory Test) + f4b41 3b + f4c0f + Message: "Invalid configuration information - please run SETUP program" + f4c5c + f86fc + f8838 + f4c80 + f4ca2 + f4d4c + f4e15 (int 19h) + + [f9a83 output text at return address!, return after text] + + + at486 + ----- + f81a5 03 + f1096 0f 09 wbinvd i486 instruction + +*********************************************************************/ + + +#include "machine/8042kbdc.h" + + +/*************************************************************************** + + Constants & macros + +***************************************************************************/ + +#define PS2_MOUSE_ON 1 +#define KEYBOARD_ON 1 + +#define LOG_KEYBOARD 0 +#define LOG_ACCESSES 0 + +const device_type KBDC8042 = &device_creator; + +//------------------------------------------------- +// kbdc8042_device - constructor +//------------------------------------------------- + +kbdc8042_device::kbdc8042_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, KBDC8042, "8042 Keyboard Controller", tag, owner, clock, "kbdc8042", __FILE__) + , m_keyboard_dev(*this, "at_keyboard") + , m_system_reset_cb(*this) + , m_gate_a20_cb(*this) + , m_input_buffer_full_cb(*this) + , m_output_buffer_empty_cb(*this) + , m_speaker_cb(*this) +{ +} + +static MACHINE_CONFIG_FRAGMENT( keyboard ) + MCFG_AT_KEYB_ADD("at_keyboard", 1, WRITELINE(kbdc8042_device, keyboard_w)) +MACHINE_CONFIG_END + +machine_config_constructor kbdc8042_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( keyboard ); +} + +/*------------------------------------------------- + device_start - device-specific startup +-------------------------------------------------*/ + +void kbdc8042_device::device_start() +{ + // resolve callbacks + m_system_reset_cb.resolve_safe(); + m_gate_a20_cb.resolve(); + m_input_buffer_full_cb.resolve(); + m_output_buffer_empty_cb.resolve_safe(); + m_speaker_cb.resolve(); + m_operation_write_state = 0; /* first write to 0x60 might occur before anything can set this */ + memset(&m_keyboard, 0x00, sizeof(m_keyboard)); + memset(&m_mouse, 0x00, sizeof(m_mouse)); + m_sending = 0; + m_last_write_to_control = 0; + m_status_read_mode = 0; +} + +/*------------------------------------------------- + device_reset - device-specific reset +-------------------------------------------------*/ + +void kbdc8042_device::device_reset() +{ + m_poll_delay = 10; + + /* ibmat bios wants 0x20 set! (keyboard locked when not set) 0x80 */ + m_inport = 0xa0; + at_8042_set_outport(0xfe, 1); +} + +void kbdc8042_device::at_8042_set_outport(UINT8 data, int initial) +{ + UINT8 change; + change = initial ? 0xFF : (m_outport ^ data); + m_outport = data; + if (change & 0x02) + { + if (!m_gate_a20_cb.isnull()) + m_gate_a20_cb(data & 0x02 ? 1 : 0); + } +} + +WRITE_LINE_MEMBER( kbdc8042_device::keyboard_w ) +{ + if(state) + at_8042_check_keyboard(); +} + +TIMER_CALLBACK_MEMBER( kbdc8042_device::kbdc8042_clr_int ) +{ + /* Lets 8952's timers do their job before clear the interrupt line, */ + /* else Keyboard interrupt never happens. */ + m_input_buffer_full_cb(0); +} + +void kbdc8042_device::at_8042_receive(UINT8 data) +{ + if (LOG_KEYBOARD) + logerror("at_8042_receive Received 0x%02x\n", data); + + m_data = data; + m_keyboard.received = 1; + + if (!m_input_buffer_full_cb.isnull()) + { + m_input_buffer_full_cb(1); + /* Lets 8952's timers do their job before clear the interrupt line, */ + /* else Keyboard interrupt never happens. */ + machine().scheduler().timer_set(attotime::from_usec(2), timer_expired_delegate(FUNC(kbdc8042_device::kbdc8042_clr_int),this)); + } +} + +void kbdc8042_device::at_8042_check_keyboard() +{ + int data; + + if (!m_keyboard.received && !m_mouse.received) + { + if((data = m_keyboard_dev->read(machine().driver_data()->generic_space(), 0))) + at_8042_receive(data); + } +} + + +void kbdc8042_device::at_8042_clear_keyboard_received() +{ + if (m_keyboard.received) + { + if (LOG_KEYBOARD) + logerror("kbdc8042_8_r(): Clearing m_keyboard.received\n"); + } + + m_keyboard.received = 0; + m_mouse.received = 0; +} + + + +/* ************************************************************************** + * Port 0x60 Input and Output Buffer (keyboard and mouse data) + * Port 0x64 Read Status Register + * Write operation for controller + * + * Output port controller: + * 7: Keyboard data + * 6: Keyboard clock + * 5: Mouse buffer full + * 4: Keyboard buffer full + * 3: Mouse clock + * 2: Mouse data + * 1: 0 A20 cleared + * 0: 0 system reset + * + * Input port controller + * 7: 0=Keyboard Locked + * 6: 1 = Monochrome 0 = Color (true for real IBM, clones are undefined and use CMOS RAM data) + * 5..2: reserved + * 1: Mouse data in + * 0: Keyboard data in + */ + +READ8_MEMBER(kbdc8042_device::data_r) +{ + UINT8 data = 0; + + switch (offset) { + case 0: + data = m_data; + if ((m_status_read_mode != 3) || (data != 0xfa)) + { + if (m_keybtype != KBDC8042_AT386 || (data != 0x55)) + { + /* at386 self test doesn't like this */ + at_8042_clear_keyboard_received(); + } + at_8042_check_keyboard(); + } + else + { + m_status_read_mode = 4; + } + break; + + case 1: + data = m_speaker; + data &= ~0xc0; /* AT BIOS don't likes this being set */ + + /* needed for AMI BIOS, maybe only some keyboard controller revisions! */ + at_8042_clear_keyboard_received(); + + /* polled for changes in ibmat bios */ + if (--m_poll_delay < 0) + { + if (m_keybtype != KBDC8042_PS2) + m_poll_delay = 4; /* ibmat */ + else + m_poll_delay = 8; /* ibm ps2m30 */ + m_offset1 ^= 0x10; + } + data = (data & ~0x10) | m_offset1; + + if (m_speaker & 1) + data |= 0x20; + else + data &= ~0x20; /* ps2m30 wants this */ + break; + + case 2: + if (m_out2) + data |= 0x20; + else + data &= ~0x20; + break; + + case 4: + at_8042_check_keyboard(); + + if (m_keyboard.received || m_mouse.received) + data |= 1; + if (m_sending) + data |= 2; + + m_sending = 0; /* quicker than normal */ + data |= 4; /* selftest ok */ + + if (m_last_write_to_control) + data |= 8; + + switch (m_status_read_mode) { + case 0: + if (!m_keyboard.on) data|=0x10; + if (m_mouse.received) data|=0x20; + break; + case 1: + data |= m_inport&0xf; + break; + case 2: + data |= m_inport<<4; + break; + case 4: + at_8042_receive(0xaa); + m_status_read_mode = 0; + break; + } + break; + } + + if (LOG_ACCESSES) + logerror("kbdc8042_8_r(): offset=%d data=0x%02x\n", offset, (unsigned) data); + return data; +} + + + +WRITE8_MEMBER(kbdc8042_device::data_w) +{ + switch (offset) { + case 0: + m_last_write_to_control = 0; + m_status_read_mode = 0; + switch (m_operation_write_state) { + case 0: + if ((data == 0xf4) || (data == 0xff)) /* keyboard enable or keyboard reset */ + { + at_8042_receive(0xfa); /* ACK, delivered a bit differently */ + + if (data == 0xff) + { + m_status_read_mode = 3; /* keyboard buffer to be written again after next read */ + } + + break; + } + + /* normal case */ + m_data = data; + m_sending=1; + m_keyboard_dev->write(space, 0, data); + break; + + case 1: + /* preceded by writing 0xD1 to port 60h + * |7|6|5|4|3|2|1|0| 8042 Output Port + * | | | | | | | `---- system reset line + * | | | | | | `----- gate A20 + * | | | | `-------- undefined + * | | | `--------- output buffer full + * | | `---------- input buffer empty + * | `----------- keyboard clock (output) + * `------------ keyboard data (output) + */ + at_8042_set_outport(data, 0); + break; + + case 2: + /* preceded by writing 0xD2 to port 60h */ + m_data = data; + m_sending=1; + m_keyboard_dev->write(space, 0, data); + break; + + case 3: + /* preceded by writing 0xD3 to port 60h */ + m_data = data; + break; + + case 4: + /* preceded by writing 0xD4 to port 60h */ + m_data = data; + break; + + case 5: + /* preceded by writing 0x60 to port 60h */ + m_command = data; + break; + } + m_operation_write_state = 0; + break; + + case 1: + m_speaker = data; + if (!m_speaker_cb.isnull()) + m_speaker_cb((offs_t)0, m_speaker); + + break; + + case 4: + m_last_write_to_control=0; + + /* switch based on the command */ + switch(data) { + case 0x20: /* current 8042 command byte is placed on port 60h */ + m_data = m_command; + break; + case 0x60: /* next data byte is placed in 8042 command byte */ + m_operation_write_state = 5; + m_send_to_mouse = 0; + break; + case 0xa7: /* disable auxilary interface */ + m_mouse.on = 0; + break; + case 0xa8: /* enable auxilary interface */ + m_mouse.on = 1; + break; + case 0xa9: /* test mouse */ + at_8042_receive(PS2_MOUSE_ON ? 0x00 : 0xff); + break; + case 0xaa: /* selftest */ + at_8042_receive(0x55); + break; + case 0xab: /* test keyboard */ + at_8042_receive(KEYBOARD_ON ? 0x00 : 0xff); + break; + case 0xad: /* disable keyboard interface */ + m_keyboard.on = 0; + break; + case 0xae: /* enable keyboard interface */ + m_keyboard.on = 1; + break; + case 0xc0: /* read input port */ + /* |7|6|5|4|3 2 1 0| 8042 Input Port + * | | | | | + * | | | | `------- undefined + * | | | | + * | | | `--------- 1=enable 2nd 256k of Motherboard RAM + * | | `---------- 1=manufacturing jumper installed + * | `----------- 1=primary display is MDA, 0=CGA + * `------------ 1=keyboard not inhibited; 0=inhibited + */ + at_8042_receive(m_inport); + break; + case 0xc1: /* read input port 3..0 until write to 0x60 */ + m_status_read_mode = 1; + break; + case 0xc2: /* read input port 7..4 until write to 0x60 */ + m_status_read_mode = 2; + break; + case 0xd0: /* read output port */ + at_8042_receive(m_outport); + break; + case 0xd1: + /* write output port; next byte written to port 60h is placed on + * 8042 output port */ + m_operation_write_state = 1; + return; /* instant delivery */ + case 0xd2: + /* write keyboard output register; on PS/2 systems next port 60h + * write is written to port 60h output register as if initiated + * by a device; invokes interrupt if enabled */ + m_operation_write_state = 2; + m_send_to_mouse = 0; + break; + case 0xd3: + /* write auxillary output register; on PS/2 systems next port 60h + * write is written to port 60h input register as if initiated + * by a device; invokes interrupt if enabled */ + m_operation_write_state = 3; + m_send_to_mouse = 1; + break; + case 0xd4: + /* write auxillary device; on PS/2 systems the next data byte + * written to input register a port at 60h is sent to the + * auxiliary device */ + m_operation_write_state = 4; + break; + case 0xe0: + /* read test inputs; read T1/T0 test inputs into bit 1/0 */ + at_8042_receive(0x00); + break; + + case 0xf0: + case 0xf2: + case 0xf4: + case 0xf6: + case 0xf8: + case 0xfa: + case 0xfc: + case 0xfe: + /* Commands 0xF0...0xFF causes certain output lines to be pulsed + * low for six milliseconds. The bits pulsed low correspond to + * the bits low set in the command byte. The only pulse that has + * an effect currently is bit 0, which pulses the CPU's reset line + */ + m_system_reset_cb(ASSERT_LINE); + m_system_reset_cb(CLEAR_LINE); + at_8042_set_outport(m_outport | 0x02, 0); + break; + } + m_sending = 1; + break; + } +} + +WRITE_LINE_MEMBER(kbdc8042_device::write_out2) +{ + m_out2 = state; +} diff --git a/src/devices/machine/8042kbdc.h b/src/devices/machine/8042kbdc.h new file mode 100644 index 00000000000..b8d9c4e22fd --- /dev/null +++ b/src/devices/machine/8042kbdc.h @@ -0,0 +1,127 @@ +// license:BSD-3-Clause +// copyright-holders:Peter Trauner +/********************************************************************** + + 8042 Keyboard Controller Emulation + + This is the keyboard controller used in the IBM AT and further + models. It is a popular controller for PC style keyboards + +**********************************************************************/ + +#ifndef KBDC8042_H +#define KBDC8042_H + +#include "emu.h" +#include "machine/pckeybrd.h" + +enum kbdc8042_type_t +{ + KBDC8042_STANDARD, + KBDC8042_PS2, /* another timing of integrated controller */ + KBDC8042_AT386 /* hack for at386 driver */ +}; + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_KBDC8042_KEYBOARD_TYPE(_kbdt) \ + kbdc8042_device::set_keyboard_type(*device, _kbdt); + +#define MCFG_KBDC8042_SYSTEM_RESET_CB(_devcb) \ + devcb = &kbdc8042_device::set_system_reset_callback(*device, DEVCB_##_devcb); + +#define MCFG_KBDC8042_GATE_A20_CB(_devcb) \ + devcb = &kbdc8042_device::set_gate_a20_callback(*device, DEVCB_##_devcb); + +#define MCFG_KBDC8042_INPUT_BUFFER_FULL_CB(_devcb) \ + devcb = &kbdc8042_device::set_input_buffer_full_callback(*device, DEVCB_##_devcb); + +#define MCFG_KBDC8042_OUTPUT_BUFFER_EMPTY_CB(_devcb) \ + devcb = &kbdc8042_device::set_output_buffer_empty_callback(*device, DEVCB_##_devcb); + +#define MCFG_KBDC8042_SPEAKER_CB(_devcb) \ + devcb = &kbdc8042_device::set_speaker_callback(*device, DEVCB_##_devcb); + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> kbdc8042_device + +class kbdc8042_device : public device_t +{ +public: + // construction/destruction + kbdc8042_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual machine_config_constructor device_mconfig_additions() const; + + static void set_keyboard_type(device_t &device, kbdc8042_type_t keybtype) { downcast(device).m_keybtype = keybtype; } + template static devcb_base &set_system_reset_callback(device_t &device, _Object object) { return downcast(device).m_system_reset_cb.set_callback(object); } + template static devcb_base &set_gate_a20_callback(device_t &device, _Object object) { return downcast(device).m_gate_a20_cb.set_callback(object); } + template static devcb_base &set_input_buffer_full_callback(device_t &device, _Object object) { return downcast(device).m_input_buffer_full_cb.set_callback(object); } + template static devcb_base &set_output_buffer_empty_callback(device_t &device, _Object object) { return downcast(device).m_output_buffer_empty_cb.set_callback(object); } + template static devcb_base &set_speaker_callback(device_t &device, _Object object) { return downcast(device).m_speaker_cb.set_callback(object); } + + DECLARE_READ8_MEMBER( data_r ); + DECLARE_WRITE8_MEMBER( data_w ); + + DECLARE_WRITE_LINE_MEMBER( write_out2 ); + DECLARE_WRITE_LINE_MEMBER( keyboard_w ); + + void at_8042_set_outport(UINT8 data, int initial); + TIMER_CALLBACK_MEMBER( kbdc8042_clr_int ); + void at_8042_receive(UINT8 data); + void at_8042_check_keyboard(); + void at_8042_clear_keyboard_received(); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + UINT8 m_inport, m_outport, m_data, m_command; + + struct { + int received; + int on; + } m_keyboard; + struct { + int received; + int on; + } m_mouse; + + int m_last_write_to_control; + int m_sending; + int m_send_to_mouse; + + int m_operation_write_state; + int m_status_read_mode; + + int m_speaker; + int m_out2; + + /* temporary hack */ + int m_offset1; + + int m_poll_delay; + + required_device m_keyboard_dev; + + kbdc8042_type_t m_keybtype; + + devcb_write_line m_system_reset_cb; + devcb_write_line m_gate_a20_cb; + devcb_write_line m_input_buffer_full_cb; + devcb_write_line m_output_buffer_empty_cb; + + devcb_write8 m_speaker_cb; +}; + +// device type definition +extern const device_type KBDC8042; + + +#endif /* KBDC8042_H */ diff --git a/src/devices/machine/8530scc.c b/src/devices/machine/8530scc.c new file mode 100644 index 00000000000..8180d01f869 --- /dev/null +++ b/src/devices/machine/8530scc.c @@ -0,0 +1,678 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/********************************************************************* + + 8530scc.c + + Zilog 8530 SCC (Serial Control Chip) code + +*********************************************************************/ + + +#include "emu.h" +#include "8530scc.h" + +const device_type SCC8530 = &device_creator; + + +/*************************************************************************** + PARAMETERS +***************************************************************************/ + +#define LOG_SCC (0) + +/*************************************************************************** + IMPLEMENTATION +***************************************************************************/ + +scc8530_t::scc8530_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, SCC8530, "Zilog 8530 SCC", tag, owner, clock, "scc8530", __FILE__), + intrq_cb(*this) +{ +} + + +/*------------------------------------------------- + scc_updateirqs +-------------------------------------------------*/ + +void scc8530_t::updateirqs() +{ + int irqstat; + + irqstat = 0; + if (MasterIRQEnable) + { + if ((channel[0].txIRQEnable) && (channel[0].txIRQPending)) + { + IRQType = IRQ_B_TX; + irqstat = 1; + } + else if ((channel[1].txIRQEnable) && (channel[1].txIRQPending)) + { + IRQType = IRQ_A_TX; + irqstat = 1; + } + else if ((channel[0].extIRQEnable) && (channel[0].extIRQPending)) + { + IRQType = IRQ_B_EXT; + irqstat = 1; + } + else if ((channel[1].extIRQEnable) && (channel[1].extIRQPending)) + { + IRQType = IRQ_A_EXT; + irqstat = 1; + } + } + else + { + IRQType = IRQ_NONE; + } + +// printf("SCC: irqstat %d, last %d\n", irqstat, lastIRQStat); +// printf("ch0: en %d pd %d ch1: en %d pd %d\n", channel[0].txIRQEnable, channel[0].txIRQPending, channel[1].txIRQEnable, channel[1].txIRQPending); + + // don't spam the driver with unnecessary transitions + if (irqstat != lastIRQStat) + { + lastIRQStat = irqstat; + + // tell the driver the new IRQ line status if possible +#if LOG_SCC + printf("SCC8530 IRQ status => %d\n", irqstat); +#endif + if(!intrq_cb.isnull()) + intrq_cb(irqstat); + } +} + +/*------------------------------------------------- + scc_initchannel +-------------------------------------------------*/ +void scc8530_t::initchannel(int ch) +{ + channel[ch].syncHunt = 1; +} + +/*------------------------------------------------- + scc_resetchannel +-------------------------------------------------*/ +void scc8530_t::resetchannel(int ch) +{ + emu_timer *timersave = channel[ch].baudtimer; + + memset(&channel[ch], 0, sizeof(Chan)); + + channel[ch].txUnderrun = 1; + channel[ch].baudtimer = timersave; + + channel[ch].baudtimer->adjust(attotime::never, ch); +} + +/*------------------------------------------------- + scc8530_baud_expire - baud rate timer expiry +-------------------------------------------------*/ + +void scc8530_t::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + Chan *pChan = &channel[id]; + int brconst = pChan->reg_val[13]<<8 | pChan->reg_val[14]; + int rate; + + if (brconst) + { + rate = clock() / brconst; + } + else + { + rate = 0; + } + + // is baud counter IRQ enabled on this channel? + // always flag pending in case it's enabled after this + pChan->baudIRQPending = 1; + if (pChan->baudIRQEnable) + { + if (pChan->extIRQEnable) + { + pChan->extIRQPending = 1; + pChan->baudIRQPending = 0; + updateirqs(); + } + } + + // reset timer according to current register values + if (rate) + { + attotime attorate = attotime::from_hz(rate); + timer.adjust(attorate, 0, attorate); + } + else + { + timer.adjust(attotime::never, 0, attotime::never); + } +} + +/*------------------------------------------------- + device_start - device-specific startup +-------------------------------------------------*/ + +void scc8530_t::device_start() +{ + intrq_cb.resolve(); + + memset(channel, 0, sizeof(channel)); + + mode = 0; + reg = 0; + status = 0; + IRQV = 0; + MasterIRQEnable = 0; + lastIRQStat = 0; + IRQType = IRQ_NONE; + + channel[0].baudtimer = timer_alloc(0); + channel[1].baudtimer = timer_alloc(1); +} + + +/*------------------------------------------------- + device_reset - device-specific reset +-------------------------------------------------*/ +void scc8530_t::device_reset() +{ + IRQType = IRQ_NONE; + MasterIRQEnable = 0; + IRQV = 0; + + initchannel(0); + initchannel(1); + resetchannel(0); + resetchannel(1); +} + +/*------------------------------------------------- + scc_set_status +-------------------------------------------------*/ + +void scc8530_t::set_status(int _status) +{ + status = _status; +} + +/*------------------------------------------------- + scc_acknowledge +-------------------------------------------------*/ + +void scc8530_t::acknowledge() +{ + if(!intrq_cb.isnull()) + intrq_cb(0); +} + +/*------------------------------------------------- + scc_getareg +-------------------------------------------------*/ + +UINT8 scc8530_t::getareg() +{ + /* Not yet implemented */ + #if LOG_SCC + printf("SCC: port A reg %d read 0x%02x\n", reg, channel[0].reg_val[reg]); + #endif + + if (reg == 0) + { + UINT8 rv = 0; + + Chan *ourCh = &channel[0]; + + rv |= (ourCh->txUnderrun) ? 0x40 : 0; + rv |= (ourCh->syncHunt) ? 0x10 : 0; + rv |= channel[0].reg_val[0] & 0x0D; // pick up TXBE, RXBF, DCD bits + + return rv; + } + else if (reg == 10) + { + return 0; + } + return channel[0].reg_val[reg]; +} + + + +/*------------------------------------------------- + scc_getareg +-------------------------------------------------*/ + +UINT8 scc8530_t::getbreg() +{ + #if LOG_SCC + printf("SCC: port B reg %i read 0x%02x\n", reg, channel[1].reg_val[reg]); + #endif + + if (reg == 0) + { + UINT8 rv = 0; + + Chan *ourCh = &channel[1]; + + rv |= (ourCh->txUnderrun) ? 0x40 : 0; + rv |= (ourCh->syncHunt) ? 0x10 : 0; + rv |= channel[1].reg_val[0] & 0x0D; // pick up TXBE, RXBF, DCD bits + + return rv; + } + else if (reg == 2) + { + /* HACK! but lets the Mac Plus mouse move again. Needs further investigation. */ + acknowledge(); + + return status; + } + else if (reg == 10) + { + return 0; + } + + return channel[1].reg_val[reg]; +} + + + +/*------------------------------------------------- + scc_putreg +-------------------------------------------------*/ + +void scc8530_t::putreg(int ch, UINT8 data) +{ + Chan *pChan = &channel[ch]; + + channel[ch].reg_val[reg] = data; + #if LOG_SCC + printf("SCC: port %c reg %d write 0x%02x\n", 'A'+ch, reg, data); + #endif + + switch (reg) + { + case 0: // command register + switch ((data >> 3) & 7) + { + case 1: // select high registers (handled elsewhere) + break; + + case 2: // reset external and status IRQs + pChan->syncHunt = 0; + break; + + case 5: // ack Tx IRQ + pChan->txIRQPending = 0; + updateirqs(); + break; + + case 0: // nothing + case 3: // send SDLC abort + case 4: // enable IRQ on next Rx byte + case 6: // reset errors + case 7: // reset highest IUS + // we don't handle these yet + break; + + } + break; + + case 1: // Tx/Rx IRQ and data transfer mode defintion + pChan->extIRQEnable = (data & 1); + pChan->txIRQEnable = (data & 2) ? 1 : 0; + pChan->rxIRQEnable = (data >> 3) & 3; + updateirqs(); + break; + + case 2: // IRQ vector + IRQV = data; + break; + + case 3: // Rx parameters and controls + pChan->rxEnable = (data & 1); + pChan->syncHunt = (data & 0x10) ? 1 : 0; + break; + + case 5: // Tx parameters and controls +// printf("ch %d TxEnable = %d [%02x]\n", ch, data & 8, data); + pChan->txEnable = data & 8; + + if (pChan->txEnable) + { + pChan->reg_val[0] |= 0x04; // Tx empty + } + break; + + case 4: // Tx/Rx misc parameters and modes + case 6: // sync chars/SDLC address field + case 7: // sync char/SDLC flag + break; + + case 9: // master IRQ control + MasterIRQEnable = (data & 8) ? 1 : 0; + updateirqs(); + + // channel reset command + switch ((data>>6) & 3) + { + case 0: // do nothing + break; + + case 1: // reset channel B + resetchannel(0); + break; + + case 2: // reset channel A + resetchannel(1); + break; + + case 3: // force h/w reset (entire chip) + IRQType = IRQ_NONE; + MasterIRQEnable = 0; + IRQV = 0; + + initchannel(0); + initchannel(1); + resetchannel(0); + resetchannel(1); + + // make sure we stop yanking the IRQ line if we were + updateirqs(); + break; + + } + break; + + case 10: // misc transmitter/receiver control bits + case 11: // clock mode control + case 12: // lower byte of baud rate gen + case 13: // upper byte of baud rate gen + break; + + case 14: // misc control bits + if (data & 0x01) // baud rate generator enable? + { + int brconst = pChan->reg_val[13]<<8 | pChan->reg_val[14]; + int rate = clock() / brconst; + + pChan->baudtimer->adjust(attotime::from_hz(rate), 0, attotime::from_hz(rate)); + } + break; + + case 15: // external/status interrupt control + pChan->baudIRQEnable = (data & 2) ? 1 : 0; + pChan->DCDEnable = (data & 8) ? 1 : 0; + pChan->CTSEnable = (data & 0x20) ? 1 : 0; + pChan->txUnderrunEnable = (data & 0x40) ? 1 : 0; + break; + } +} + +/*------------------------------------------------- + scc8530_get_reg_a +-------------------------------------------------*/ + +UINT8 scc8530_t::get_reg_a(int reg) +{ + return channel[0].reg_val[reg]; +} + + + +/*------------------------------------------------- + scc8530_get_reg_b +-------------------------------------------------*/ + +UINT8 scc8530_t::get_reg_b(int reg) +{ + return channel[1].reg_val[reg]; +} + + + +/*------------------------------------------------- + scc8530_set_reg_a +-------------------------------------------------*/ + +void scc8530_t::set_reg_a(int reg, UINT8 data) +{ + channel[0].reg_val[reg] = data; +} + + + +/*------------------------------------------------- + scc8530_set_reg_a +-------------------------------------------------*/ + +void scc8530_t::set_reg_b(int reg, UINT8 data) +{ + channel[1].reg_val[reg] = data; +} + + + +/*------------------------------------------------- + scc8530_r +-------------------------------------------------*/ + +READ8_MEMBER( scc8530_t::reg_r) +{ + UINT8 result = 0; + + offset %= 4; + + switch(offset) + { + case 0: + /* Channel B (Printer Port) Control */ + if (mode == 1) + mode = 0; + else + reg = 0; + + result = getbreg(); + break; + + case 1: + /* Channel A (Modem Port) Control */ + if (mode == 1) + mode = 0; + else + reg = 0; + + result = getareg(); + break; + + case 2: + /* Channel B (Printer Port) Data */ + result = channel[1].rxData; + break; + + case 3: + /* Channel A (Modem Port) Data */ + result = channel[0].rxData; + break; + } + return result; +} + + + +/*------------------------------------------------- + scc8530_w +-------------------------------------------------*/ + +WRITE8_MEMBER( scc8530_t::reg_w ) +{ + Chan *pChan; + + offset &= 3; + +// printf(" mode %d data %x offset %d \n", mode, data, offset); + + switch(offset) + { + case 0: + /* Channel B (Printer Port) Control */ + if (mode == 0) + { + if((data & 0xf0) == 0) // not a reset command + { + mode = 1; + reg = data & 0x0f; +// putbreg(data & 0xf0); + } + else if (data == 0x10) + { + pChan = &channel[1]; + // clear ext. interrupts + pChan->extIRQPending = 0; + pChan->baudIRQPending = 0; + updateirqs(); + } + } + else + { + mode = 0; + putreg(1, data); + } + break; + + case 1: + /* Channel A (Modem Port) Control */ + if (mode == 0) + { + if((data & 0xf0) == 0) // not a reset command + { + mode = 1; + reg = data & 0x0f; +// putareg(data & 0xf0); + } + else if (data == 0x10) + { + pChan = &channel[0]; + // clear ext. interrupts + pChan->extIRQPending = 0; + pChan->baudIRQPending = 0; + updateirqs(); + } + } + else + { + mode = 0; + putreg(0, data); + } + break; + + case 2: + /* Channel B (Printer Port) Data */ + pChan = &channel[1]; + + if (pChan->txEnable) + { + pChan->txData = data; + // local loopback? + if (pChan->reg_val[14] & 0x10) + { + pChan->rxData = data; + pChan->reg_val[0] |= 0x01; // Rx character available + } + pChan->reg_val[1] |= 0x01; // All sent + pChan->reg_val[0] |= 0x04; // Tx empty + pChan->txUnderrun = 1; + pChan->txIRQPending = 1; + updateirqs(); + } + break; + + case 3: + /* Channel A (Modem Port) Data */ + pChan = &channel[0]; + + if (pChan->txEnable) + { + pChan->txData = data; + // local loopback? + if (pChan->reg_val[14] & 0x10) + { + pChan->rxData = data; + pChan->reg_val[0] |= 0x01; // Rx character available + } + pChan->reg_val[1] |= 0x01; // All sent + pChan->reg_val[0] |= 0x04; // Tx empty + pChan->txUnderrun = 1; + pChan->txIRQPending = 1; + updateirqs(); + } + break; + } +} + +/* + +AppleTalk check: + +SCC: port B reg 9 write 0x40 Channel Reset B +SCC: port B reg 4 write 0x20 SDLC mode +SCC: port B reg 10 write 0xe0 CRC preset + FM0 +SCC: port B reg 6 write 0x00 SDLC address +SCC: port B reg 7 write 0x7e SDLC flag +SCC: port B reg 12 write 0x06 baud rate low +SCC: port B reg 13 write 0x00 baud rate high +SCC: port B reg 14 write 0xc0 Set FM mode +SCC: port B reg 3 write 0xdd Rx 8 bits, enter hunt mode, CRC enable, address search mode, Rx enable +SCC: port B reg 2 write 0x00 interrupt vector 0 +SCC: port B reg 15 write 0x08 DCD interrupt enable +SCC: port B reg 1 write 0x09 Rx IRQ on first char or special, ext int enable +SCC: port B reg 9 write 0x0a Master IRQ enable, no-vector mode +SCC: port B reg 11 write 0x70 Rx clock = DPLL output, Tx clock = BR generator +SCC: port B reg 14 write 0x21 Enter search mode, BR generator enable +SCC: port B reg 5 write 0x60 Tx 8 bits/char +SCC: port B reg 6 write 0x2a SDLC address +SCC: port B reg 0 read 0x00 +SCC: port B reg 15 write 0x88 DCD interrupt enable, break/abort interrupt enable + +(repeats) +SCC: port B reg 1 read 0x09 +SCC: port B reg 3 write 0xd0 +SCC: port B reg 3 write 0xdd Rx 8 bits, enter hunt mode, CRC enable, address search mode, Rx enable +SCC: port B reg 15 write 0x08 DCD interrupt enable +SCC: port B reg 0 read 0x00 +SCC: port B reg 15 write 0x88 + +System 7: + +SCC: port B reg 9 write 0x40 Channel Reset B +SCC: port B reg 4 write 0x20 SDLC mode +SCC: port B reg 10 write 0xe0 CRC preset + FM0 +SCC: port B reg 6 write 0x00 SDLC address +SCC: port B reg 7 write 0x7e SDLC flag +SCC: port B reg 12 write 0x06 baud rate low +SCC: port B reg 13 write 0x00 baud rate high +SCC: port B reg 14 write 0xc0 Set FM mode +SCC: port B reg 3 write 0xdd Rx 8 bits, enter hunt mode, CRC enable, address search mode, Rx enable +SCC: port B reg 2 write 0x00 interrupt vector 0 +SCC: port B reg 15 write 0x08 DCD interrupt enable +SCC: port B reg 1 write 0x09 Rx IRQ on first char or special, ext int enable +SCC: port B reg 9 write 0x0a Master IRQ enable, no-vector mode +SCC: port B reg 11 write 0x70 Rx clock = DPLL output, Tx clock = BR generator +SCC: port B reg 14 write 0x21 Enter search mode, BR generator enable +SCC: port B reg 5 write 0x60 Tx 8 bits/char +SCC: port B reg 6 write 0x01 SDLC address +SCC: port B reg 3 write 0xdd Rx 8 bits, enter hunt mode, CRC enable, address search mode, Rx enable + +(repeats) + +SCC: port B reg 0 read 0x00 +SCC: port B reg 15 write 0x88 DCD interrupt enable, break/abort interrupt enable +SCC: port B reg 15 write 0x08 DCD interrupt enable +SCC: port B reg 1 read 0x09 Rx IRQ on first char or special, ext int enable +SCC: port B reg 3 write 0xdd Rx 8 bits, enter hunt mode, CRC enable, address search mode, Rx enable + +*/ diff --git a/src/devices/machine/8530scc.h b/src/devices/machine/8530scc.h new file mode 100644 index 00000000000..af4cef88e1e --- /dev/null +++ b/src/devices/machine/8530scc.h @@ -0,0 +1,103 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/********************************************************************* + + 8530scc.h + + Zilog 8530 SCC (Serial Control Chip) code + +*********************************************************************/ + +#ifndef __8530SCC_H__ +#define __8530SCC_H__ + +#define MCFG_Z8530_INTRQ_CALLBACK(_write) \ + devcb = &scc8530_t::set_intrq_wr_callback(*device, DEVCB_##_write); + +class scc8530_t : public device_t +{ +public: + enum IRQType_t { + IRQ_NONE, + IRQ_A_RX, + IRQ_A_RX_SPECIAL, + IRQ_B_RX, + IRQ_B_RX_SPECIAL, + IRQ_A_TX, + IRQ_B_TX, + IRQ_A_EXT, + IRQ_B_EXT + }; + + scc8530_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + template static devcb_base &set_intrq_wr_callback(device_t &device, _Object object) { return downcast(device).intrq_cb.set_callback(object); } + + UINT8 get_reg_a(int reg); + UINT8 get_reg_b(int reg); + void set_reg_a(int reg, UINT8 data); + void set_reg_b(int reg, UINT8 data); + + void set_status(int status); + + DECLARE_READ8_MEMBER(reg_r); + DECLARE_WRITE8_MEMBER(reg_w); + +protected: + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + +private: + struct Chan { + bool txIRQEnable; + bool rxIRQEnable; + bool extIRQEnable; + bool baudIRQEnable; + bool txIRQPending; + bool rxIRQPending; + bool extIRQPending; + bool baudIRQPending; + bool txEnable; + bool rxEnable; + bool txUnderrun; + bool txUnderrunEnable; + bool syncHunt; + bool DCDEnable; + bool CTSEnable; + UINT8 rxData; + UINT8 txData; + + emu_timer *baudtimer; + + UINT8 reg_val[16]; + }; + + int mode; + int reg; + int status; + int IRQV; + int MasterIRQEnable; + int lastIRQStat; + IRQType_t IRQType; + + Chan channel[2]; + + devcb_write_line intrq_cb; + + void updateirqs(); + void initchannel(int ch); + void resetchannel(int ch); + void acknowledge(); + UINT8 getareg(); + UINT8 getbreg(); + void putreg(int ch, UINT8 data); +}; + +/*************************************************************************** + MACROS +***************************************************************************/ + +extern const device_type SCC8530; + +#endif /* __8530SCC_H__ */ diff --git a/src/devices/machine/aakart.c b/src/devices/machine/aakart.c new file mode 100644 index 00000000000..762a1a2f8b9 --- /dev/null +++ b/src/devices/machine/aakart.c @@ -0,0 +1,195 @@ +// license:LGPL-2.1+ +// copyright-holders:Angelo Salese +/*************************************************************************** + +Acorn Archimedes KART interface + +TODO: +- FIFO + +***************************************************************************/ + +#include "emu.h" +#include "machine/aakart.h" + + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +// device type definition +const device_type AAKART = &device_creator; + +#define HRST 0xff +#define RAK1 0xfe +#define RAK2 0xfd +#define BACK 0x3f +#define SMAK 0x33 /* keyboard + mouse ack */ +#define MACK 0x32 /* mouse ack */ +#define SACK 0x31 /* keyboard ack */ +#define NACK 0x30 /* no data ack */ +#define RQID 0x20 + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// aakart_device - constructor +//------------------------------------------------- + +aakart_device::aakart_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, AAKART, "AAKART", tag, owner, clock, "aakart", __FILE__), + m_out_tx_cb(*this), + m_out_rx_cb(*this) +{ +} + + +//------------------------------------------------- +// device_validity_check - perform validity checks +// on this device +//------------------------------------------------- + +void aakart_device::device_validity_check(validity_checker &valid) const +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void aakart_device::device_start() +{ + m_out_tx_cb.resolve_safe(); + m_out_rx_cb.resolve_safe(); + m_rxtimer = timer_alloc(RX_TIMER); + m_rxtimer->adjust(attotime::from_hz(clock()), 0, attotime::from_hz(clock())); + m_txtimer = timer_alloc(TX_TIMER); + m_txtimer->adjust(attotime::from_hz(clock()), 0, attotime::from_hz(clock())); + m_mousetimer = timer_alloc(MOUSE_TIMER); + m_mousetimer->adjust(attotime::from_hz(clock()), 0, attotime::from_hz(clock())); + m_keybtimer = timer_alloc(KEYB_TIMER); + m_keybtimer->adjust(attotime::from_hz(clock()), 0, attotime::from_hz(clock())); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void aakart_device::device_reset() +{ + m_status = STATUS_HRST; + m_new_command = 0; + m_rx = -1; + m_mouse_enable = 0; +} + +//------------------------------------------------- +// device_timer - handler timer events +//------------------------------------------------- + +void aakart_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + if(id == TX_TIMER && m_new_command & 1) + { + switch(m_tx_latch) + { + case 0x00: + case 0x02: + case 0x03: + case 0x07: + // ---- -x-- scroll lock + // ---- --x- num lock + // ---- ---x caps lock + break; + case 0x20: + m_rx = 0x81; + m_out_tx_cb(ASSERT_LINE); + break; + case 0x30: + case 0x31: + case 0x32: + case 0x33: + m_keyb_enable = m_tx_latch & 1; + m_mouse_enable = (m_tx_latch & 2) >> 1; + if(m_keyb_enable & 1 && m_keyb_state & 1) + { + //printf("Got row\n"); + m_rx = m_keyb_row; + m_out_tx_cb(ASSERT_LINE); + } + + break; + case 0x3f: + if(m_keyb_enable & 1 && m_keyb_state & 1) + { + //printf("Got col\n"); + m_rx = m_keyb_col; + m_out_tx_cb(ASSERT_LINE); + m_keyb_state = 0; + } + + break; + case 0xfd: + m_rx = 0xfd; + m_out_tx_cb(ASSERT_LINE); + break; + case 0xfe: + m_rx = 0xfe; + m_out_tx_cb(ASSERT_LINE); + break; + case 0xff: + m_rx = 0xff; + m_out_tx_cb(ASSERT_LINE); + break; + default: + //printf("%02x %02x %02x\n",m_tx_latch,m_rx_latch,m_keyb_enable); + break; + } + + //m_new_command &= ~1; + m_out_rx_cb(ASSERT_LINE); + } + +} + +//************************************************************************** +// READ/WRITE HANDLERS +//************************************************************************** + +#include "debugger.h" + +READ8_MEMBER( aakart_device::read ) +{ + m_out_tx_cb(CLEAR_LINE); + //debugger_break(machine()); + return m_rx; +} + +WRITE8_MEMBER( aakart_device::write ) +{ + // if(m_new_command) printf("skip cmd %02x\n",data); + + m_tx_latch = data; + m_out_rx_cb(CLEAR_LINE); + m_new_command |= 1; +} + +void aakart_device::send_keycode_down(UINT8 row, UINT8 col) +{ + //printf("keycode down\n"); + m_keyb_row = row | 0xc0; + m_keyb_col = col | 0xc0; + m_keyb_state = 1; +} + +void aakart_device::send_keycode_up(UINT8 row, UINT8 col) +{ + //printf("keycode up\n"); + m_keyb_row = row | 0xd0; + m_keyb_col = col | 0xd0; + m_keyb_state = 1; +} diff --git a/src/devices/machine/aakart.h b/src/devices/machine/aakart.h new file mode 100644 index 00000000000..bd59a54838a --- /dev/null +++ b/src/devices/machine/aakart.h @@ -0,0 +1,100 @@ +// license:LGPL-2.1+ +// copyright-holders:Angelo Salese +/*************************************************************************** + +Acorn Archimedes KART interface + +***************************************************************************/ + +#pragma once + +#ifndef __AAKARTDEV_H__ +#define __AAKARTDEV_H__ + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_AAKART_OUT_TX_CB(_devcb) \ + devcb = &aakart_device::set_out_tx_callback(*device, DEVCB_##_devcb); + +#define MCFG_AAKART_OUT_RX_CB(_devcb) \ + devcb = &aakart_device::set_out_rx_callback(*device, DEVCB_##_devcb); + + +enum{ + STATUS_NORMAL = 0, + STATUS_KEYUP, + STATUS_KEYDOWN, + STATUS_MOUSE, + STATUS_HRST, + STATUS_UNDEFINED +}; + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> aakart_device + +class aakart_device : public device_t +{ +public: + // construction/destruction + aakart_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + template static devcb_base &set_out_tx_callback(device_t &device, _Object object) { return downcast(device).m_out_tx_cb.set_callback(object); } + template static devcb_base &set_out_rx_callback(device_t &device, _Object object) { return downcast(device).m_out_rx_cb.set_callback(object); } + + // I/O operations + DECLARE_WRITE8_MEMBER( write ); + DECLARE_READ8_MEMBER( read ); + void send_keycode_down(UINT8 row, UINT8 col); + void send_keycode_up(UINT8 row, UINT8 col); +protected: + // device-level overrides + virtual void device_validity_check(validity_checker &valid) const; + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + +private: + static const device_timer_id RX_TIMER = 1; + static const device_timer_id TX_TIMER = 2; + static const device_timer_id MOUSE_TIMER = 3; + static const device_timer_id KEYB_TIMER = 4; + emu_timer * m_rxtimer; + emu_timer * m_txtimer; + emu_timer * m_mousetimer; + emu_timer * m_keybtimer; + + devcb_write_line m_out_tx_cb; + devcb_write_line m_out_rx_cb; + UINT8 m_tx_latch; + //UINT8 m_rx_latch; + UINT8 m_rx; + UINT8 m_new_command; + UINT8 m_status; + UINT8 m_mouse_enable; + UINT8 m_keyb_enable; + UINT8 m_keyb_row; + UINT8 m_keyb_col; + UINT8 m_keyb_state; + +}; + + +// device type definition +extern const device_type AAKART; + + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + + + +#endif diff --git a/src/devices/machine/adc0808.c b/src/devices/machine/adc0808.c new file mode 100644 index 00000000000..dc173cc178e --- /dev/null +++ b/src/devices/machine/adc0808.c @@ -0,0 +1,187 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + National Semiconductor ADC0808/ADC0809 8-Bit A/D Converter emulation + +**********************************************************************/ + +#include "emu.h" +#include "adc0808.h" + + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +// device type definition +const device_type ADC0808 = &device_creator; + +//------------------------------------------------- +// adc0808_device - constructor +//------------------------------------------------- + +adc0808_device::adc0808_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, ADC0808, "ADC0808", tag, owner, clock, "adc0808", __FILE__), + m_out_eoc_cb(*this), + m_address(0), + m_start(0), + m_eoc(0), + m_next_eoc(0), + m_cycle(0), + m_bit(0) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void adc0808_device::device_start() +{ + // resolve callbacks + m_out_eoc_cb.resolve_safe(); + m_in_vref_pos_cb.bind_relative_to(*owner()); + m_in_vref_neg_cb.bind_relative_to(*owner()); + m_in_in_0_cb.bind_relative_to(*owner()); + m_in_in_1_cb.bind_relative_to(*owner()); + m_in_in_2_cb.bind_relative_to(*owner()); + m_in_in_3_cb.bind_relative_to(*owner()); + m_in_in_4_cb.bind_relative_to(*owner()); + m_in_in_5_cb.bind_relative_to(*owner()); + m_in_in_6_cb.bind_relative_to(*owner()); + m_in_in_7_cb.bind_relative_to(*owner()); + + // allocate timers + m_cycle_timer = timer_alloc(); + m_cycle_timer->adjust(attotime::zero, 0, attotime::from_hz(clock())); + + // register for state saving + save_item(NAME(m_address)); + save_item(NAME(m_start)); + save_item(NAME(m_eoc)); + save_item(NAME(m_next_eoc)); + save_item(NAME(m_sar)); + save_item(NAME(m_cycle)); + save_item(NAME(m_bit)); +} + + +//------------------------------------------------- +// device_timer - handler timer events +//------------------------------------------------- + +void adc0808_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + if (!m_start) + { + if (m_cycle == 7) + { + m_bit++; + + if (m_bit == 8) + { + /* sample input */ + double vref_pos = m_in_vref_pos_cb(); + double vref_neg = m_in_vref_neg_cb(); + + double input = 0; + + switch (m_address) + { + case 0: + input = m_in_in_0_cb(); + break; + case 1: + input = m_in_in_1_cb(); + break; + case 2: + input = m_in_in_2_cb(); + break; + case 3: + input = m_in_in_3_cb(); + break; + case 4: + input = m_in_in_4_cb(); + break; + case 5: + input = m_in_in_5_cb(); + break; + case 6: + input = m_in_in_6_cb(); + break; + case 7: + input = m_in_in_7_cb(); + break; + } + m_sar = (255 * (input - vref_neg)) / (vref_pos - vref_neg); + + /* trigger end of conversion */ + m_next_eoc = 1; + } + } + } + + if (m_cycle == 0) + { + /* set end of conversion pin */ + if (m_next_eoc != m_eoc) + { + m_out_eoc_cb(m_next_eoc); + m_eoc = m_next_eoc; + } + } + + m_cycle++; + + if (m_cycle == 8) + { + m_cycle = 0; + } +} + + +//------------------------------------------------- +// data_r - data read +//------------------------------------------------- + +READ8_MEMBER( adc0808_device::data_r ) +{ + return m_sar; +} + + +//------------------------------------------------- +// ale_w - address write +//------------------------------------------------- + +WRITE8_MEMBER( adc0808_device::ale_w ) +{ + m_address = data; +} + + +//------------------------------------------------- +// start_w - start conversion +//------------------------------------------------- + +WRITE_LINE_MEMBER( adc0808_device::start_w ) +{ + if (!m_start && state) // rising edge + { + // reset registers + + m_sar = 0; + m_bit = 0; + } + else if (m_start && !state) // falling edge + { + // start conversion + + m_next_eoc = 0; + } + + m_start = state; +} diff --git a/src/devices/machine/adc0808.h b/src/devices/machine/adc0808.h new file mode 100644 index 00000000000..a7d1c3eb6c5 --- /dev/null +++ b/src/devices/machine/adc0808.h @@ -0,0 +1,140 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + National Semiconductor ADC0808/ADC0809 8-Bit A/D Converter emulation + +********************************************************************** + _____ _____ + IN3 1 |* \_/ | 28 IN2 + IN4 2 | | 27 IN1 + IN5 3 | | 26 IN0 + IN6 4 | | 25 ADD A + IN7 5 | | 24 ADD B + START 6 | | 23 ADD C + EOC 7 | ADC0808 | 22 ALE + 2-5 8 | ADC0809 | 21 2-1 MSB + OUTPUT ENABLE 9 | | 20 2-2 + CLOCK 10 | | 19 2-3 + Vcc 11 | | 18 2-4 + Vref+ 12 | | 17 2-8 LSB + GND 13 | | 16 Vref- + 2-7 14 |_____________| 15 2-6 + +**********************************************************************/ + +#pragma once + +#ifndef __ADC0808__ +#define __ADC0808__ + +#include "emu.h" + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> adc0808_analog_read + +typedef device_delegate adc0808_analog_read_delegate; +#define ADC0808_ANALOG_READ_CB(name) double name() + + +#define MCFG_ADC0808_OUT_EOC_CB(_devcb) \ + devcb = &adc0808_device::set_out_eoc_callback(*device, DEVCB_##_devcb); + +#define MCFG_ADC0808_IN_VREF_POS_CB(_class, _method) \ + adc0808_device::set_in_vref_pos_callback(*device, adc0808_analog_read_delegate(&_class::_method, #_class "::" #_method, downcast<_class *>(owner))); + +#define MCFG_ADC0808_IN_VREF_NEG_CB(_class, _method) \ + adc0808_device::set_in_vref_neg_callback(*device, adc0808_analog_read_delegate(&_class::_method, #_class "::" #_method, downcast<_class *>(owner))); + +#define MCFG_ADC0808_IN_IN_0_CB(_class, _method) \ + adc0808_device::set_in_in_0_callback(*device, adc0808_analog_read_delegate(&_class::_method, #_class "::" #_method, downcast<_class *>(owner))); + +#define MCFG_ADC0808_IN_IN_1_CB(_class, _method) \ + adc0808_device::set_in_in_1_callback(*device, adc0808_analog_read_delegate(&_class::_method, #_class "::" #_method, downcast<_class *>(owner))); + +#define MCFG_ADC0808_IN_IN_2_CB(_class, _method) \ + adc0808_device::set_in_in_2_callback(*device, adc0808_analog_read_delegate(&_class::_method, #_class "::" #_method, downcast<_class *>(owner))); + +#define MCFG_ADC0808_IN_IN_3_CB(_class, _method) \ + adc0808_device::set_in_in_3_callback(*device, adc0808_analog_read_delegate(&_class::_method, #_class "::" #_method, downcast<_class *>(owner))); + +#define MCFG_ADC0808_IN_IN_4_CB(_class, _method) \ + adc0808_device::set_in_in_4_callback(*device, adc0808_analog_read_delegate(&_class::_method, #_class "::" #_method, downcast<_class *>(owner))); + +#define MCFG_ADC0808_IN_IN_5_CB(_class, _method) \ + adc0808_device::set_in_in_5_callback(*device, adc0808_analog_read_delegate(&_class::_method, #_class "::" #_method, downcast<_class *>(owner))); + +#define MCFG_ADC0808_IN_IN_6_CB(_class, _method) \ + adc0808_device::set_in_in_6_callback(*device, adc0808_analog_read_delegate(&_class::_method, #_class "::" #_method, downcast<_class *>(owner))); + +#define MCFG_ADC0808_IN_IN_7_CB(_class, _method) \ + adc0808_device::set_in_in_7_callback(*device, adc0808_analog_read_delegate(&_class::_method, #_class "::" #_method, downcast<_class *>(owner))); + +// ======================> adc0808_device + +class adc0808_device : public device_t +{ +public: + // construction/destruction + adc0808_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + template static devcb_base &set_out_eoc_callback(device_t &device, _Object object) { return downcast(device).m_out_eoc_cb.set_callback(object); } + static void set_in_vref_pos_callback(device_t &device, adc0808_analog_read_delegate callback) { downcast(device).m_in_vref_pos_cb = callback; } + static void set_in_vref_neg_callback(device_t &device, adc0808_analog_read_delegate callback) { downcast(device).m_in_vref_neg_cb = callback; } + static void set_in_in_0_callback(device_t &device, adc0808_analog_read_delegate callback) { downcast(device).m_in_in_0_cb = callback; } + static void set_in_in_1_callback(device_t &device, adc0808_analog_read_delegate callback) { downcast(device).m_in_in_1_cb = callback; } + static void set_in_in_2_callback(device_t &device, adc0808_analog_read_delegate callback) { downcast(device).m_in_in_2_cb = callback; } + static void set_in_in_3_callback(device_t &device, adc0808_analog_read_delegate callback) { downcast(device).m_in_in_3_cb = callback; } + static void set_in_in_4_callback(device_t &device, adc0808_analog_read_delegate callback) { downcast(device).m_in_in_4_cb = callback; } + static void set_in_in_5_callback(device_t &device, adc0808_analog_read_delegate callback) { downcast(device).m_in_in_5_cb = callback; } + static void set_in_in_6_callback(device_t &device, adc0808_analog_read_delegate callback) { downcast(device).m_in_in_6_cb = callback; } + static void set_in_in_7_callback(device_t &device, adc0808_analog_read_delegate callback) { downcast(device).m_in_in_7_cb = callback; } + + DECLARE_READ8_MEMBER( data_r ); + DECLARE_WRITE8_MEMBER( ale_w ); + + DECLARE_WRITE_LINE_MEMBER( start_w ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + +private: + devcb_write_line m_out_eoc_cb; + adc0808_analog_read_delegate m_in_vref_pos_cb; + adc0808_analog_read_delegate m_in_vref_neg_cb; + adc0808_analog_read_delegate m_in_in_0_cb; + adc0808_analog_read_delegate m_in_in_1_cb; + adc0808_analog_read_delegate m_in_in_2_cb; + adc0808_analog_read_delegate m_in_in_3_cb; + adc0808_analog_read_delegate m_in_in_4_cb; + adc0808_analog_read_delegate m_in_in_5_cb; + adc0808_analog_read_delegate m_in_in_6_cb; + adc0808_analog_read_delegate m_in_in_7_cb; + + int m_address; // analog channel address + int m_start; // start conversion pin + int m_eoc; // end of conversion pin + int m_next_eoc; // next value end of conversion pin + + UINT8 m_sar; // successive approximation register + + int m_cycle; // clock cycle counter + int m_bit; // bit counter + + // timers + emu_timer *m_cycle_timer; +}; + + +// device type definition +extern const device_type ADC0808; + + + +#endif diff --git a/src/devices/machine/adc083x.c b/src/devices/machine/adc083x.c new file mode 100644 index 00000000000..4f1b11cebf0 --- /dev/null +++ b/src/devices/machine/adc083x.c @@ -0,0 +1,448 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/*************************************************************************** + + National Semiconductor ADC0831 / ADC0832 / ADC0834 / ADC0838 + + 8-Bit serial I/O A/D Converters with Muliplexer Options + +***************************************************************************/ + +#include "emu.h" +#include "adc083x.h" + +#define VERBOSE_LEVEL ( 0 ) + +INLINE void ATTR_PRINTF( 3, 4 ) verboselog( int n_level, running_machine &machine, const char *s_fmt, ... ) +{ + if( VERBOSE_LEVEL >= n_level ) + { + va_list v; + char buf[ 32768 ]; + va_start( v, s_fmt ); + vsprintf( buf, s_fmt, v ); + va_end( v ); + logerror( "%s: %s", machine.describe_context( ), buf ); + } +} + +/*************************************************************************** + PARAMETERS +***************************************************************************/ + +enum +{ + STATE_IDLE, + STATE_WAIT_FOR_START, + STATE_SHIFT_MUX, + STATE_MUX_SETTLE, + STATE_OUTPUT_MSB_FIRST, + STATE_WAIT_FOR_SE, + STATE_OUTPUT_LSB_FIRST, + STATE_FINISHED +}; + +/*************************************************************************** + TYPE DEFINITIONS +***************************************************************************/ + +const device_type ADC0831 = &device_creator; +const device_type ADC0832 = &device_creator; +const device_type ADC0834 = &device_creator; +const device_type ADC0838 = &device_creator; + +adc083x_device::adc083x_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + m_cs(0), + m_clk(0), + m_di(0), + m_se(0), + m_do(1), + m_sgl(0), + m_odd(0), + m_sel1(0), + m_sel0(0), + m_state(STATE_IDLE), + m_bit(0), + m_output(0) +{ +} + +adc0831_device::adc0831_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : adc083x_device(mconfig, ADC0831, "ADC0831", tag, owner, clock, "adc0831", __FILE__) +{ + m_mux_bits = 0; +} + +adc0832_device::adc0832_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : adc083x_device(mconfig, ADC0832, "ADC0832", tag, owner, clock, "adc0832", __FILE__) +{ + m_mux_bits = 2; +} + +adc0834_device::adc0834_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : adc083x_device(mconfig, ADC0834, "ADC0834", tag, owner, clock, "adc0834", __FILE__) +{ + m_mux_bits = 3; +} + +adc0838_device::adc0838_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : adc083x_device(mconfig, ADC0838, "ADC0838", tag, owner, clock, "adc0838", __FILE__) +{ + m_mux_bits = 4; +} + +/*------------------------------------------------- + adc083x_device::device_start +-------------------------------------------------*/ + +void adc083x_device::device_start() +{ + clear_sars(); + + /* resolve callbacks */ + m_input_callback.bind_relative_to(*owner()); + + /* register for state saving */ + save_item( NAME(m_cs) ); + save_item( NAME(m_clk) ); + save_item( NAME(m_di) ); + save_item( NAME(m_se) ); + save_item( NAME(m_sars) ); + save_item( NAME(m_do) ); + save_item( NAME(m_sgl) ); + save_item( NAME(m_odd) ); + save_item( NAME(m_sel1) ); + save_item( NAME(m_sel0) ); + save_item( NAME(m_state) ); + save_item( NAME(m_bit) ); + save_item( NAME(m_output) ); + save_item( NAME(m_mux_bits) ); +} + +/*------------------------------------------------- + adc083x_device::clear_sars +-------------------------------------------------*/ + +void adc083x_device::clear_sars() +{ + if( type() == ADC0834 || type() == ADC0838 ) + { + m_sars = 1; + } + else + { + m_sars = 0; + } +} + +/*------------------------------------------------- + adc083x_device::cs_write +-------------------------------------------------*/ + +WRITE_LINE_MEMBER( adc083x_device::cs_write ) +{ + if( m_cs != state ) + { + verboselog( 2, machine(), "adc083x_cs_write( %s, %d )\n", tag(), state ); + } + + if( m_cs == 0 && state != 0 ) + { + m_state = STATE_IDLE; + clear_sars(); + m_do = 1; + } + + if( m_cs != 0 && state == 0 ) + { + if( type() == ADC0831 ) + { + m_state = STATE_MUX_SETTLE; + } + else + { + m_state = STATE_WAIT_FOR_START; + } + + clear_sars(); + m_do = 1; + } + + m_cs = state; +} + +/*------------------------------------------------- + adc083x_device::conversion +-------------------------------------------------*/ + +UINT8 adc083x_device::conversion() +{ + int result; + int positive_channel = ADC083X_AGND; + int negative_channel = ADC083X_AGND; + double positive = 0; + double negative = 0; + double gnd = m_input_callback(ADC083X_AGND); + double vref = m_input_callback(ADC083X_VREF); + + if( type() == ADC0831 ) + { + positive_channel = ADC083X_CH0; + negative_channel = ADC083X_CH1; + } + else if( type() == ADC0832 ) + { + positive_channel = ADC083X_CH0 + m_odd; + if( m_sgl == 0 ) + { + negative_channel = positive_channel ^ 1; + } + else + { + negative_channel = ADC083X_AGND; + } + } + else if( type() == ADC0834 ) + { + positive_channel = ADC083X_CH0 + m_odd + ( m_sel1 * 2 ); + if( m_sgl == 0 ) + { + negative_channel = positive_channel ^ 1; + } + else + { + negative_channel = ADC083X_AGND; + } + } + else if( type() == ADC0838 ) + { + positive_channel = ADC083X_CH0 + m_odd + ( m_sel0 * 2 ) + ( m_sel1 * 4 ); + if( m_sgl == 0 ) + { + negative_channel = positive_channel ^ 1; + } + else + { + negative_channel = ADC083X_COM; + } + } + + if( positive_channel != ADC083X_AGND ) + { + positive = m_input_callback(positive_channel) - gnd; + } + + if( negative_channel != ADC083X_AGND ) + { + negative = m_input_callback(negative_channel) - gnd; + } + + result = (int) ( ( ( positive - negative ) * 255 ) / vref ); + if( result < 0 ) + { + result = 0; + } + else if( result > 255 ) + { + result = 255; + } + + return result; +} + +/*------------------------------------------------- + adc083x_device::clk_write +-------------------------------------------------*/ + +WRITE_LINE_MEMBER( adc083x_device::clk_write ) +{ + if( m_clk != state ) + { + verboselog( 2, machine(), "adc083x_clk_write( %s, %d )\n", tag(), state ); + } + + if( m_cs == 0 ) + { + if( m_clk == 0 && state != 0 ) + { + switch( m_state ) + { + case STATE_WAIT_FOR_START: + if( m_di != 0 ) + { + verboselog( 1, machine(), "adc083x %s got start bit\n", tag() ); + m_state = STATE_SHIFT_MUX; + m_sars = 0; + m_sgl = 0; + m_odd = 0; + m_sel1 = 0; + m_sel0 = 0; + m_bit = 0; + } + else + { + verboselog( 1, machine(), "adc083x %s not start bit\n", tag() ); + } + break; + + case STATE_SHIFT_MUX: + switch( m_bit ) + { + case 0: + if( m_di != 0 ) + { + m_sgl = 1; + } + verboselog( 1, machine(), "adc083x %s sgl <- %d\n", tag(), m_sgl ); + break; + + case 1: + if( m_di != 0 ) + { + m_odd = 1; + } + verboselog( 1, machine(), "adc083x %s odd <- %d\n", tag(), m_odd ); + break; + + case 2: + if( m_di != 0 ) + { + m_sel1 = 1; + } + verboselog( 1, machine(), "adc083x %s sel1 <- %d\n", tag(), m_sel1 ); + break; + + case 3: + if( m_di != 0 ) + { + m_sel0 = 1; + } + verboselog( 1, machine(), "adc083x %s sel0 <- %d\n", tag(), m_sel0 ); + break; + } + + m_bit++; + if( m_bit == m_mux_bits ) + { + m_state = STATE_MUX_SETTLE; + } + + break; + + case STATE_WAIT_FOR_SE: + m_sars = 0; + if( type() == ADC0838 && m_se != 0 ) + { + verboselog( 1, machine(), "adc083x %s not se\n", tag() ); + } + else + { + verboselog( 1, machine(), "adc083x %s got se\n", tag() ); + m_state = STATE_OUTPUT_LSB_FIRST; + m_bit = 1; + } + break; + } + } + + if( m_clk != 0 && state == 0 ) + { + switch( m_state ) + { + case STATE_MUX_SETTLE: + verboselog( 1, machine(), "adc083x %s mux settle\n", tag() ); + m_output = conversion(); + m_state = STATE_OUTPUT_MSB_FIRST; + m_bit = 7; + clear_sars(); + m_do = 0; + break; + + case STATE_OUTPUT_MSB_FIRST: + m_do = ( m_output >> m_bit ) & 1; + verboselog( 1, machine(), "adc083x %s msb %d -> %d\n", tag(), m_bit, m_do ); + + m_bit--; + if( m_bit < 0 ) + { + if( type() == ADC0831 ) + { + m_state = STATE_FINISHED; + } + else + { + m_state = STATE_WAIT_FOR_SE; + } + } + break; + + case STATE_OUTPUT_LSB_FIRST: + m_do = ( m_output >> m_bit ) & 1; + verboselog( 1, machine(), "adc083x %s lsb %d -> %d\n", tag(), m_bit, m_do ); + + m_bit++; + if( m_bit == 8 ) + { + m_state = STATE_FINISHED; + } + break; + + case STATE_FINISHED: + m_state = STATE_IDLE; + m_do = 0; + break; + } + } + } + + m_clk = state; +} + +/*------------------------------------------------- + adc083x_device::di_write +-------------------------------------------------*/ + +WRITE_LINE_MEMBER( adc083x_device::di_write ) +{ + if( m_di != state ) + { + verboselog( 2, machine(), "adc083x_di_write( %s, %d )\n", tag(), state ); + } + + m_di = state; +} + +/*------------------------------------------------- + adc083x_device::se_write +-------------------------------------------------*/ + +WRITE_LINE_MEMBER( adc083x_device::se_write ) +{ + if( m_se != state ) + { + verboselog( 2, machine(), "adc083x_se_write( %s, %d )\n", tag(), state ); + } + + m_se = state; +} + +/*------------------------------------------------- + adc083x_device::sars_read +-------------------------------------------------*/ + +READ_LINE_MEMBER( adc083x_device::sars_read ) +{ + verboselog( 1, machine(), "adc083x_sars_read( %s ) %d\n", tag(), m_sars ); + return m_sars; +} + +/*------------------------------------------------- + adc083x_device::do_read +-------------------------------------------------*/ + +READ_LINE_MEMBER( adc083x_device::do_read ) +{ + verboselog( 1, machine(), "adc083x_do_read( %s ) %d\n", tag(), m_do ); + return m_do; +} diff --git a/src/devices/machine/adc083x.h b/src/devices/machine/adc083x.h new file mode 100644 index 00000000000..60050506f81 --- /dev/null +++ b/src/devices/machine/adc083x.h @@ -0,0 +1,126 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/*************************************************************************** + + National Semiconductor ADC0831 / ADC0832 / ADC0834 / ADC0838 + + 8-Bit serial I/O A/D Converters with Muliplexer Options + +***************************************************************************/ + +#ifndef __ADC083X_H__ +#define __ADC083X_H__ + +#include "emu.h" + +/*************************************************************************** + TYPE DEFINITIONS +***************************************************************************/ + +typedef device_delegate adc083x_input_delegate; +#define ADC083X_INPUT_CB(name) double name(UINT8 input) + +#define MCFG_ADC083X_INPUT_CB(_class, _method) \ + adc083x_device::set_input_callback(*device, adc083x_input_delegate(&_class::_method, #_class "::" #_method, downcast<_class *>(owner))); + +/*************************************************************************** + CONSTANTS +***************************************************************************/ + +#define ADC083X_CH0 0 +#define ADC083X_CH1 1 +#define ADC083X_CH2 2 +#define ADC083X_CH3 3 +#define ADC083X_CH4 4 +#define ADC083X_CH5 5 +#define ADC083X_CH6 6 +#define ADC083X_CH7 7 +#define ADC083X_COM 8 +#define ADC083X_AGND 9 +#define ADC083X_VREF 10 + +/*************************************************************************** + MACROS / CONSTANTS +***************************************************************************/ + +class adc083x_device : public device_t +{ +public: + adc083x_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + // static configuration helpers + static void set_input_callback(device_t &device, adc083x_input_delegate input_callback) { downcast(device).m_input_callback = input_callback; } + + DECLARE_WRITE_LINE_MEMBER( cs_write ); + DECLARE_WRITE_LINE_MEMBER( clk_write ); + DECLARE_WRITE_LINE_MEMBER( di_write ); + DECLARE_WRITE_LINE_MEMBER( se_write ); + DECLARE_READ_LINE_MEMBER( sars_read ); + DECLARE_READ_LINE_MEMBER( do_read ); + +protected: + // device-level overrides + virtual void device_start(); + + INT32 m_mux_bits; + +private: + UINT8 conversion(); + + void clear_sars(); + + // internal state + INT32 m_cs; + INT32 m_clk; + INT32 m_di; + INT32 m_se; + INT32 m_sars; + INT32 m_do; + INT32 m_sgl; + INT32 m_odd; + INT32 m_sel1; + INT32 m_sel0; + INT32 m_state; + INT32 m_bit; + INT32 m_output; + + adc083x_input_delegate m_input_callback; +}; + +class adc0831_device : public adc083x_device +{ +public: + adc0831_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +extern const device_type ADC0831; + + +class adc0832_device : public adc083x_device +{ +public: + adc0832_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +extern const device_type ADC0832; + + +class adc0834_device : public adc083x_device +{ +public: + adc0834_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +extern const device_type ADC0834; + + +class adc0838_device : public adc083x_device +{ +public: + adc0838_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +extern const device_type ADC0838; + + +#endif /* __ADC083X_H__ */ diff --git a/src/devices/machine/adc1038.c b/src/devices/machine/adc1038.c new file mode 100644 index 00000000000..46b2d7c8e76 --- /dev/null +++ b/src/devices/machine/adc1038.c @@ -0,0 +1,121 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*************************************************************************** + + National Semiconductor ADC1038 + + 10-Bit Serial I/O A/D Converters with Analog Multiplexer and + Track/hold Function + +***************************************************************************/ + +#include "emu.h" +#include "adc1038.h" + + +const device_type ADC1038 = &device_creator; + +adc1038_device::adc1038_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, ADC1038, "ADC1038", tag, owner, clock, "adc1038", __FILE__), + m_gticlub_hack(0) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void adc1038_device::device_start() +{ + m_input_cb.bind_relative_to(*owner()); + + save_item(NAME(m_cycle)); + save_item(NAME(m_clk)); + save_item(NAME(m_adr)); + save_item(NAME(m_data_in)); + save_item(NAME(m_data_out)); + save_item(NAME(m_adc_data)); + save_item(NAME(m_sars)); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void adc1038_device::device_reset() +{ + m_cycle = 0; + m_clk = 0; + m_adr = 0; + m_data_in = 0; + m_data_out = 0; + m_adc_data = 0; + m_sars = 1; +} + +/***************************************************************************** + DEVICE HANDLERS +*****************************************************************************/ + +READ_LINE_MEMBER( adc1038_device::do_read ) +{ + m_data_out = (m_adc_data & 0x200) ? 1 : 0; + m_adc_data <<= 1; + + //printf("ADC DO\n"); + return m_data_out; +} + +WRITE_LINE_MEMBER( adc1038_device::di_write ) +{ + m_data_in = state; +} + +WRITE_LINE_MEMBER( adc1038_device::clk_write ) +{ + // GTI Club doesn't sync on SARS + if (m_gticlub_hack) + { + if (m_clk == 0 && state == 0) + { + m_cycle = 0; + + /* notice that m_adr is always < 7! */ + m_adc_data = m_input_cb(m_adr); + } + } + + if (state == 1) + { + //printf("ADC CLK, DI = %d, cycle = %d\n", m_data_in, m_cycle); + + if (m_cycle == 0) // A2 + { + m_adr = 0; + m_adr |= (m_data_in << 2); + } + else if (m_cycle == 1) // A1 + { + m_adr |= (m_data_in << 1); + } + else if (m_cycle == 2) // A0 + { + m_adr |= (m_data_in << 0); + } + + m_cycle++; + } + + m_clk = state; +} + +READ_LINE_MEMBER( adc1038_device::sars_read ) +{ + m_cycle = 0; + + /* notice that m_adr is always < 7! */ + m_adc_data = m_input_cb(m_adr); + + m_sars ^= 1; + return m_sars; +} diff --git a/src/devices/machine/adc1038.h b/src/devices/machine/adc1038.h new file mode 100644 index 00000000000..1d6b0f890bc --- /dev/null +++ b/src/devices/machine/adc1038.h @@ -0,0 +1,69 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*************************************************************************** + + National Semiconductor ADC1038 + + 10-Bit Serial I/O A/D Converters with Analog Multiplexer and + Track/hold Function + +***************************************************************************/ + +#ifndef __ADC1038_H__ +#define __ADC1038_H__ + +/*************************************************************************** + TYPE DEFINITIONS +***************************************************************************/ + +typedef device_delegate adc1038_input_delegate; +#define ADC1038_INPUT_CB(name) int name(int input) + +/*************************************************************************** + MACROS / CONSTANTS +***************************************************************************/ + +class adc1038_device : public device_t +{ +public: + adc1038_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + ~adc1038_device() {} + + static void set_input_callback(device_t &device, adc1038_input_delegate callback) { downcast(device).m_input_cb = callback; } + static void set_gti_club_hack(device_t &device, int hack) { downcast(device).m_gticlub_hack = hack; } + + DECLARE_READ_LINE_MEMBER( do_read ); + DECLARE_READ_LINE_MEMBER( sars_read ); + DECLARE_WRITE_LINE_MEMBER( di_write ); + DECLARE_WRITE_LINE_MEMBER( clk_write ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + +private: + // internal state + int m_cycle; + int m_clk; + int m_adr; + int m_data_in; + int m_data_out; + int m_adc_data; + int m_sars; + + int m_gticlub_hack; + adc1038_input_delegate m_input_cb; +}; + +extern const device_type ADC1038; + + +#define MCFG_ADC1038_INPUT_CB(_class, _method) \ + adc1038_device::set_input_callback(*device, adc1038_input_delegate(&_class::_method, #_class "::" #_method, downcast<_class *>(owner))); + +#define MCFG_ADC1038_GTIHACK(_hack) \ + adc1038_device::set_gti_club_hack(*device, _hack); + + +#endif /* __ADC1038_H__ */ diff --git a/src/devices/machine/adc1213x.c b/src/devices/machine/adc1213x.c new file mode 100644 index 00000000000..f6104f273e3 --- /dev/null +++ b/src/devices/machine/adc1213x.c @@ -0,0 +1,338 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/*************************************************************************** + + National Semiconductor ADC12130 / ADC12132 / ADC12138 + + Self-calibrating 12-bit Plus Sign Serial I/O A/D Converters with MUX + and Sample/Hold + + TODO: + - Only ADC12138 currently supported + + 2009-06 Converted to be a device + +***************************************************************************/ + +#include "emu.h" +#include "adc1213x.h" + + +/*************************************************************************** + TYPE DEFINITIONS +***************************************************************************/ + +#define ADC1213X_CONV_MODE_12_MSB_FIRST 0 +#define ADC1213X_CONV_MODE_16_MSB_FIRST 1 +#define ADC1213X_CONV_MODE_12_LSB_FIRST 2 +#define ADC1213X_CONV_MODE_16_LSB_FIRST 3 + +#define ADC1213X_ACQUISITION_TIME_6_CCLK 0 +#define ADC1213X_ACQUISITION_TIME_10_CCLK 1 +#define ADC1213X_ACQUISITION_TIME_18_CCLK 2 +#define ADC1213X_ACQUISITION_TIME_34_CCLK 3 + + + +const device_type ADC12130 = &device_creator; + +adc12130_device::adc12130_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : adc12138_device(mconfig, ADC12130, "ADC12130", tag, owner, clock, "adc12130", __FILE__) +{ +} + + +const device_type ADC12132 = &device_creator; + +adc12132_device::adc12132_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : adc12138_device(mconfig, ADC12132, "ADC12132", tag, owner, clock, "adc12132", __FILE__) +{ +} + + +const device_type ADC12138 = &device_creator; + +adc12138_device::adc12138_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, ADC12138, "ADC12138", tag, owner, clock, "adc12138", __FILE__) +{ +} +adc12138_device::adc12138_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void adc12138_device::device_start() +{ + m_cycle = 0; + m_data_out = 0; + m_data_in = 0; + m_auto_cal = 0; + m_auto_zero = 0; + m_input_shift_reg = 0; + m_output_shift_reg = 0; + m_end_conv = 0; + + /* resolve callbacks */ + m_ipt_read_cb.bind_relative_to(*owner()); + + /* register for state saving */ + save_item(NAME(m_cycle)); + save_item(NAME(m_data_out)); + save_item(NAME(m_data_in)); + save_item(NAME(m_conv_mode)); + save_item(NAME(m_auto_cal)); + save_item(NAME(m_auto_zero)); + save_item(NAME(m_acq_time)); + save_item(NAME(m_data_out_sign)); + save_item(NAME(m_input_shift_reg)); + save_item(NAME(m_output_shift_reg)); + save_item(NAME(m_end_conv)); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void adc12138_device::device_reset() +{ + m_conv_mode = ADC1213X_CONV_MODE_12_MSB_FIRST; + m_data_out_sign = 1; + m_auto_cal = 0; + m_auto_zero = 0; + m_acq_time = ADC1213X_ACQUISITION_TIME_10_CCLK; +} + +/*************************************************************************** + IMPLEMENTATION +***************************************************************************/ + +/*------------------------------------------------- + di_w +-------------------------------------------------*/ + +WRITE8_MEMBER( adc12138_device::di_w ) +{ + m_data_in = data & 1; +} + +/*------------------------------------------------- + convert +-------------------------------------------------*/ + +void adc12138_device::convert(int channel, int bits16, int lsbfirst) +{ + int bits; + int input_value; + double input = 0; + + if (bits16) + fatalerror("ADC1213X: 16-bit mode not supported\n"); + + if (lsbfirst) + fatalerror("ADC1213X: LSB first not supported\n"); + + switch (channel) + { + case 0x8: // H L L L - CH0 (single-ended) + { + input = m_ipt_read_cb(0); + break; + } + case 0xc: // H H L L - CH1 (single-ended) + { + input = m_ipt_read_cb(1); + break; + } + case 0x9: // H L L H - CH2 (single-ended) + { + input = m_ipt_read_cb(2); + break; + } + case 0xd: // H H L H - CH3 (single-ended) + { + input = m_ipt_read_cb(3); + break; + } + case 0xa: // H L H L - CH4 (single-ended) + { + input = m_ipt_read_cb(4); + break; + } + case 0xe: // H H H L - CH5 (single-ended) + { + input = m_ipt_read_cb(5); + break; + } + case 0xb: // H L H H - CH6 (single-ended) + { + input = m_ipt_read_cb(6); + break; + } + case 0xf: // H H H H - CH7 (single-ended) + { + input = m_ipt_read_cb(7); + break; + } + default: + { + fatalerror("ADC1213X: unsupported channel %02X\n", channel); + } + } + + input_value = (int)(input * 2047.0); + + bits = 12; + + // sign-extend if needed + if (m_data_out_sign) + { + input_value = input_value | ((input_value & 0x800) << 1); + bits++; + } + + m_output_shift_reg = 0; + + for (int i = 0; i < bits; i++) + { + if (input_value & (1 << ((bits - 1) - i))) + { + m_output_shift_reg |= (1 << i); + } + } + + m_data_out = m_output_shift_reg & 1; + m_output_shift_reg >>= 1; +} + +/*------------------------------------------------- + cs_w +-------------------------------------------------*/ + +WRITE8_MEMBER( adc12138_device::cs_w ) +{ + if (data) + { + //printf("ADC: CS\n"); + + if (m_cycle >= 7) + { + int mode = m_input_shift_reg >> (m_cycle - 8); + + switch (mode & 0xf) + { + case 0x0: // X X X X L L L L - 12 or 13 Bit MSB First conversion + { + convert((mode >> 4) & 0xf, 0, 0); + break; + } + case 0x1: // X X X X L L L H - 16 or 17 Bit MSB First conversion + { + convert((mode >> 4) & 0xf, 1, 0); + break; + } + case 0x4: // X X X X L H L L - 12 or 13 Bit LSB First conversion + { + convert((mode >> 4) & 0xf, 0, 1); + break; + } + case 0x5: // X X X X L H L H - 16 or 17 Bit LSB First conversion + { + convert((mode >> 4) & 0xf, 1, 1); + break; + } + + default: + { + switch (mode) + { + case 0x08: // L L L L H L L L - Auto cal + { + m_auto_cal = 1; + break; + } + + case 0x0e: // L L L L H H H L - Acquisition time 6 CCLK cycles + { + m_acq_time = ADC1213X_ACQUISITION_TIME_6_CCLK; + break; + } + + case 0x8d: // H L L L H H L H - Data out with sign + { + m_data_out_sign = 1; + break; + } + + case 0x0f: // L L L L H H H H - User mode + { + break; + } + + default: + { + fatalerror("ADC1213X: unknown config mode %02X\n", mode); + } + } + break; + } + } + } + + m_cycle = 0; + m_input_shift_reg = 0; + + m_end_conv = 0; + } +} + +/*------------------------------------------------- + sclk_w +-------------------------------------------------*/ + +WRITE8_MEMBER( adc12138_device::sclk_w ) +{ + if (data) + { + //printf("ADC: cycle %d, DI = %d\n", adc1213x->cycle, adc1213x->data_in); + + m_input_shift_reg <<= 1; + m_input_shift_reg |= m_data_in; + + m_data_out = m_output_shift_reg & 1; + m_output_shift_reg >>= 1; + + m_cycle++; + } +} + +/*------------------------------------------------- + conv_w +-------------------------------------------------*/ + +WRITE8_MEMBER( adc12138_device::conv_w ) +{ + m_end_conv = 1; +} + +/*------------------------------------------------- + do_r +-------------------------------------------------*/ + +READ8_MEMBER( adc12138_device::do_r ) +{ + //printf("ADC: DO\n"); + return m_data_out; +} + +/*------------------------------------------------- + eoc_r +-------------------------------------------------*/ + +READ8_MEMBER( adc12138_device::eoc_r ) +{ + return m_end_conv; +} diff --git a/src/devices/machine/adc1213x.h b/src/devices/machine/adc1213x.h new file mode 100644 index 00000000000..3f2f0dbc63c --- /dev/null +++ b/src/devices/machine/adc1213x.h @@ -0,0 +1,89 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/*************************************************************************** + + National Semiconductor ADC12130 / ADC12132 / ADC12138 + + Self-calibrating 12-bit Plus Sign Serial I/O A/D Converters with MUX + and Sample/Hold + +***************************************************************************/ + +#ifndef __ADC1213X_H__ +#define __ADC1213X_H__ + + +/*************************************************************************** + TYPE DEFINITIONS +***************************************************************************/ + +typedef device_delegate adc1213x_ipt_convert_delegate; +#define ADC12138_IPT_CONVERT_CB(name) double name(UINT8 input) + +/*************************************************************************** + MACROS / CONSTANTS +***************************************************************************/ + +class adc12138_device : public device_t +{ +public: + adc12138_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + adc12138_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + ~adc12138_device() {} + + static void set_ipt_convert_callback(device_t &device, adc1213x_ipt_convert_delegate callback) { downcast(device).m_ipt_read_cb = callback; } + + DECLARE_WRITE8_MEMBER( di_w ); + DECLARE_WRITE8_MEMBER( cs_w ); + DECLARE_WRITE8_MEMBER( sclk_w ); + DECLARE_WRITE8_MEMBER( conv_w ); + DECLARE_READ8_MEMBER( do_r ); + DECLARE_READ8_MEMBER( eoc_r ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + void convert(int channel, int bits16, int lsbfirst); + + adc1213x_ipt_convert_delegate m_ipt_read_cb; + +private: + // internal state + int m_cycle; + int m_data_out; + int m_data_in; + int m_conv_mode; + int m_auto_cal; + int m_auto_zero; + int m_acq_time; + int m_data_out_sign; + int m_input_shift_reg; + int m_output_shift_reg; + int m_end_conv; +}; + +extern const device_type ADC12138; + +class adc12130_device : public adc12138_device +{ +public: + adc12130_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +extern const device_type ADC12130; + +class adc12132_device : public adc12138_device +{ +public: + adc12132_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +extern const device_type ADC12132; + + +#define MCFG_ADC1213X_IPT_CONVERT_CB(_class, _method) \ + adc12138_device::set_ipt_convert_callback(*device, adc1213x_ipt_convert_delegate(&_class::_method, #_class "::" #_method, downcast<_class *>(owner))); + +#endif /* __ADC1213X_H__ */ diff --git a/src/devices/machine/aicartc.c b/src/devices/machine/aicartc.c new file mode 100644 index 00000000000..dc6dba7c2e6 --- /dev/null +++ b/src/devices/machine/aicartc.c @@ -0,0 +1,169 @@ +// license:BSD-3-Clause +// copyright-holders:Angelo Salese +/*************************************************************************** + + AICA-RTC sub-device + + TODO: + - move this inside AICA sound core once that'll get modernized + +***************************************************************************/ + +#include "emu.h" +#include "machine/aicartc.h" + + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +// device type definition +const device_type AICARTC = &device_creator; + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// aicartc_device - constructor +//------------------------------------------------- + +aicartc_device::aicartc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, AICARTC, "AICA RTC", tag, owner, clock, "aicartc", __FILE__), + device_rtc_interface(mconfig, *this) +{ +} + + +//------------------------------------------------- +// device_validity_check - perform validity checks +// on this device +//------------------------------------------------- + +void aicartc_device::device_validity_check(validity_checker &valid) const +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void aicartc_device::device_start() +{ + m_clock_timer = timer_alloc(); + m_clock_timer->adjust(attotime::from_hz(clock()), 0, attotime::from_hz(clock())); + + { + UINT32 current_time; + int year_count,cur_year,i; + const int month_to_day_conversion[12] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }; + system_time systime; + machine().base_datetime(systime); + + /* put the seconds */ + current_time = systime.local_time.second; + /* put the minutes */ + current_time+= systime.local_time.minute*60; + /* put the hours */ + current_time+= systime.local_time.hour*60*60; + /* put the days (note -1) */ + current_time+= (systime.local_time.mday-1)*60*60*24; + /* take the current year here for calculating leaps */ + cur_year = (systime.local_time.year); + + /* take the months - despite popular beliefs, leap years aren't just evenly divisible by 4 */ + if(((((cur_year % 4) == 0) && ((cur_year % 100) != 0)) || ((cur_year % 400) == 0)) && systime.local_time.month > 2) + current_time+= (month_to_day_conversion[systime.local_time.month]+1)*60*60*24; + else + current_time+= (month_to_day_conversion[systime.local_time.month])*60*60*24; + + /* put the years */ + year_count = (cur_year-1949); + + for(i=0;i> 16; + } +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void aicartc_device::device_reset() +{ + m_rtc_tick = 0; +} + + +//------------------------------------------------- +// device_timer - handler timer events +//------------------------------------------------- + + +void aicartc_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + m_rtc_tick++; + if(m_rtc_tick & 0x8000) + { + m_rtc_tick = 0; + m_rtc_reg_lo++; + if(m_rtc_reg_lo == 0) + m_rtc_reg_hi++; + } +} + + +//************************************************************************** +// READ/WRITE HANDLERS +//************************************************************************** + +READ16_MEMBER( aicartc_device::read ) +{ + UINT16 res; + + res = 0; + switch(offset) + { + case 0: + res = m_rtc_reg_hi; break; + case 1: + res = m_rtc_reg_lo; break; + } + + return res; +} + +WRITE16_MEMBER( aicartc_device::write ) +{ + switch(offset) + { + case 0: + if(m_we) + { + COMBINE_DATA(&m_rtc_reg_hi); + // clear write enable here? + } + + break; + + case 1: + if(m_we) + { + COMBINE_DATA(&m_rtc_reg_lo); + m_rtc_tick = 0; // low register also clears tick count + } + + break; + + case 2: + m_we = data & 1; + break; + } + +} diff --git a/src/devices/machine/aicartc.h b/src/devices/machine/aicartc.h new file mode 100644 index 00000000000..1b877a604ff --- /dev/null +++ b/src/devices/machine/aicartc.h @@ -0,0 +1,67 @@ +// license:BSD-3-Clause +// copyright-holders:Angelo Salese +/*************************************************************************** + +Template for skeleton device + +***************************************************************************/ + +#pragma once + +#ifndef __AICARTCDEV_H__ +#define __AICARTCDEV_H__ + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_AICARTC_ADD(_tag,_freq) \ + MCFG_DEVICE_ADD(_tag, AICARTC, _freq) + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> aicartc_device + +class aicartc_device : public device_t, + public device_rtc_interface +{ +public: + // construction/destruction + aicartc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // I/O operations + DECLARE_WRITE16_MEMBER( write ); + DECLARE_READ16_MEMBER( read ); + + UINT16 m_rtc_reg_lo,m_rtc_reg_hi; + UINT16 m_rtc_tick; + UINT8 m_we; + +protected: + // device-level overrides + virtual void device_validity_check(validity_checker &valid) const; + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + +private: + emu_timer *m_clock_timer; +}; + + +// device type definition +extern const device_type AICARTC; + + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + + + +#endif diff --git a/src/devices/machine/akiko.c b/src/devices/machine/akiko.c new file mode 100644 index 00000000000..99acef43cab --- /dev/null +++ b/src/devices/machine/akiko.c @@ -0,0 +1,927 @@ +// license:BSD-3-Clause +// copyright-holders:Mariusz Wojcieszek +/*************************************************************************** + + Akiko + + ASIC used in the Amiga CD32. Commodore Part number 391563-01. + + - CD-ROM controller + - Builtin 1KB NVRAM + - Chunky to planar converter + - 2x CIA chips + +***************************************************************************/ + +#include "akiko.h" +#include "includes/amiga.h" +#include "imagedev/chd_cd.h" +#include "coreutil.h" + + +//************************************************************************** +// CONSTANTS / MACROS +//************************************************************************** + +#define LOG_AKIKO 0 +#define LOG_AKIKO_CD 0 + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type AKIKO = &device_creator; + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( akiko ) +MACHINE_CONFIG_END + +machine_config_constructor akiko_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( akiko ); +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// akiko_device - constructor +//------------------------------------------------- + +akiko_device::akiko_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, AKIKO, "CBM AKIKO", tag, owner, clock, "akiko", __FILE__), + m_c2p_input_index(0), + m_c2p_output_index(0), + m_i2c_scl_out(0), + m_i2c_scl_dir(0), + m_i2c_sda_out(0), + m_i2c_sda_dir(0), + m_cdrom_track_index(0), + m_cdrom_lba_start(0), + m_cdrom_lba_end(0), + m_cdrom_lba_cur(0), + m_cdrom_readmask(0), + m_cdrom_readreqmask(0), + m_cdrom_dmacontrol(0), + m_cdrom_numtracks(0), + m_cdrom_speed(0), + m_cdrom_cmd_start(0), + m_cdrom_cmd_end(0), + m_cdrom_cmd_resp(0), + m_cdda(NULL), + m_cdrom(NULL), + m_cdrom_toc(NULL), + m_dma_timer(NULL), + m_frame_timer(NULL), + m_cdrom_is_device(0), + m_scl_w(*this), + m_sda_r(*this), + m_sda_w(*this) +{ + for (int i = 0; i < 8; i++) + { + m_c2p_input_buffer[i] = 0; + m_c2p_output_buffer[i] = 0; + } + + for (int i = 0; i < 2; i++) + { + m_cdrom_status[i] = 0; + m_cdrom_address[i] = 0; + } +} + + +//------------------------------------------------- +// set_cputag - set cpu tag for cpu we working on +//------------------------------------------------- + +void akiko_device::set_cputag(device_t &device, const char *tag) +{ + akiko_device &akiko = downcast(device); + akiko.m_cputag = tag; +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void akiko_device::device_start() +{ + // resolve callbacks + m_scl_w.resolve_safe(); + m_sda_r.resolve_safe(1); + m_sda_w.resolve_safe(); + + m_c2p_input_index = 0; + m_c2p_output_index = 0; + + m_i2c_scl_out = 0; + m_i2c_scl_dir = 0; + m_i2c_sda_out = 0; + m_i2c_sda_dir = 0; + + m_cdrom_status[0] = m_cdrom_status[1] = 0; + m_cdrom_address[0] = m_cdrom_address[1] = 0; + m_cdrom_track_index = 0; + m_cdrom_lba_start = 0; + m_cdrom_lba_end = 0; + m_cdrom_lba_cur = 0; + m_cdrom_readmask = 0; + m_cdrom_readreqmask = 0; + m_cdrom_dmacontrol = 0; + m_cdrom_numtracks = 0; + m_cdrom_speed = 0; + m_cdrom_cmd_start = 0; + m_cdrom_cmd_end = 0; + m_cdrom_cmd_resp = 0; + + device_t *cpu = machine().device(m_cputag); + m_space = &cpu->memory().space(AS_PROGRAM); + + m_cdrom_toc = NULL; + m_dma_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(akiko_device::dma_proc), this)); + m_frame_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(akiko_device::frame_proc), this)); + m_cdda = machine().device("cdda"); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void akiko_device::device_reset() +{ + cdrom_image_device *cddevice = machine().device("cdrom"); + + if (cddevice != NULL) + { + // MESS case + m_cdrom = cddevice->get_cdrom_file(); + m_cdrom_is_device = 1; + } + else + { + // MAME case + m_cdrom = cdrom_open(get_disk_handle(machine(), ":cdrom")); + m_cdrom_is_device = 0; + } + + /* create the TOC table */ + if ( m_cdrom != NULL && cdrom_get_last_track(m_cdrom) ) + { + UINT8 *p; + int i, addrctrl = cdrom_get_adr_control( m_cdrom, 0 ); + UINT32 discend; + + discend = cdrom_get_track_start(m_cdrom,cdrom_get_last_track(m_cdrom)-1); + discend += cdrom_get_toc(m_cdrom)->tracks[cdrom_get_last_track(m_cdrom)-1].frames; + discend = lba_to_msf(discend); + + m_cdrom_numtracks = cdrom_get_last_track(m_cdrom)+3; + + m_cdrom_toc = auto_alloc_array(machine(), UINT8, 13*m_cdrom_numtracks); + memset( m_cdrom_toc, 0, 13*m_cdrom_numtracks); + + p = m_cdrom_toc; + p[1] = ((addrctrl & 0x0f) << 4) | ((addrctrl & 0xf0) >> 4); + p[3] = 0xa0; /* first track */ + p[8] = 1; + p += 13; + p[1] = 0x01; + p[3] = 0xa1; /* last track */ + p[8] = cdrom_get_last_track(m_cdrom); + p += 13; + p[1] = 0x01; + p[3] = 0xa2; /* disc end */ + p[8] = (discend >> 16 ) & 0xff; + p[9] = (discend >> 8 ) & 0xff; + p[10] = discend & 0xff; + p += 13; + + for( i = 0; i < cdrom_get_last_track(m_cdrom); i++ ) + { + UINT32 trackpos = cdrom_get_track_start(m_cdrom,i); + + trackpos = lba_to_msf(trackpos); + addrctrl = cdrom_get_adr_control( m_cdrom, i ); + + p[1] = ((addrctrl & 0x0f) << 4) | ((addrctrl & 0xf0) >> 4); + p[3] = dec_2_bcd( i+1 ); + p[8] = (trackpos >> 16 ) & 0xff; + p[9] = (trackpos >> 8 ) & 0xff; + p[10] = trackpos & 0xff; + + p += 13; + } + } + +} + +//------------------------------------------------- +// device_stop - device-specific stop +//------------------------------------------------- + +void akiko_device::device_stop() +{ + if (!m_cdrom_is_device) + { + if( m_cdrom ) + { + cdrom_close(m_cdrom); + m_cdrom = (cdrom_file *)NULL; + } + } +} + +void akiko_device::nvram_write(UINT32 data) +{ + m_i2c_scl_out = BIT(data, 31); + m_i2c_sda_out = BIT(data, 30); + m_i2c_scl_dir = BIT(data, 15); + m_i2c_sda_dir = BIT(data, 14); + + m_scl_w(m_i2c_scl_out); + m_sda_w(m_i2c_sda_out); +} + +UINT32 akiko_device::nvram_read() +{ + UINT32 v = 0; + + if (m_i2c_scl_dir) + v |= m_i2c_scl_out << 31; + + if (m_i2c_sda_dir) + v |= m_i2c_sda_out << 30; + else + v |= m_sda_r() << 30; + + v |= m_i2c_scl_dir << 15; + v |= m_i2c_sda_dir << 14; + + return v; +} + +/************************************* + * + * Akiko Chunky to Planar converter + * + ************************************/ + +void akiko_device::c2p_write(UINT32 data) +{ + m_c2p_input_buffer[m_c2p_input_index] = data; + m_c2p_input_index++; + m_c2p_input_index &= 7; + m_c2p_output_index = 0; +} + +UINT32 akiko_device::c2p_read() +{ + UINT32 val; + + if ( m_c2p_output_index == 0 ) + { + int i; + + for ( i = 0; i < 8; i++ ) + m_c2p_output_buffer[i] = 0; + + for (i = 0; i < 8 * 32; i++) + { + if (m_c2p_input_buffer[7 - (i >> 5)] & (1 << (i & 31))) + m_c2p_output_buffer[i & 7] |= 1 << (i >> 3); + } + } + m_c2p_input_index = 0; + val = m_c2p_output_buffer[m_c2p_output_index]; + m_c2p_output_index++; + m_c2p_output_index &= 7; + return val; +} + +static const char *const akiko_reg_names[] = +{ + /*0*/ "ID", + /*1*/ "CDROM STATUS 1", + /*2*/ "CDROM_STATUS 2", + /*3*/ "???", + /*4*/ "CDROM ADDRESS 1", + /*5*/ "CDROM ADDRESS 2", + /*6*/ "CDROM COMMAND 1", + /*7*/ "CDROM COMMAND 2", + /*8*/ "CDROM READMASK", + /*9*/ "CDROM DMACONTROL", + /*A*/ "???", + /*B*/ "???", + /*C*/ "NVRAM", + /*D*/ "???", + /*E*/ "C2P" +}; + +static const char* get_akiko_reg_name(int reg) +{ + if (reg < 0xf ) + { + return akiko_reg_names[reg]; + } + else + { + return "???"; + } +} + +/************************************* + * + * Akiko CDROM Controller + * + ************************************/ + +void akiko_device::cdda_stop() +{ + if (m_cdda != NULL) + { + m_cdda->stop_audio(); + m_frame_timer->reset( ); + } +} + +void akiko_device::cdda_play(UINT32 lba, UINT32 num_blocks) +{ + if (m_cdda != NULL) + { + m_cdda->start_audio(lba, num_blocks); + m_frame_timer->adjust( attotime::from_hz( 75 ) ); + } +} + +void akiko_device::cdda_pause(int pause) +{ + if (m_cdda != NULL) + { + if (m_cdda->audio_active() && m_cdda->audio_paused() != pause ) + { + m_cdda->pause_audio(pause); + + if ( pause ) + { + m_frame_timer->reset( ); + } + else + { + m_frame_timer->adjust( attotime::from_hz( 75 ) ); + } + } + } +} + +UINT8 akiko_device::cdda_getstatus(UINT32 *lba) +{ + if ( lba ) *lba = 0; + + if (m_cdda != NULL) + { + if (m_cdda->audio_active()) + { + if ( lba ) *lba = m_cdda->get_audio_lba(); + + if (m_cdda->audio_paused()) + { + return 0x12; /* audio paused */ + } + else + { + return 0x11; /* audio in progress */ + } + } + else if (m_cdda->audio_ended()) + { + return 0x13; /* audio ended */ + } + } + + return 0x15; /* no audio status */ +} + +void akiko_device::set_cd_status(UINT32 status) +{ + amiga_state *amiga = machine().driver_data(); + + m_cdrom_status[0] |= status; + + if ( m_cdrom_status[0] & m_cdrom_status[1] ) + { + if (LOG_AKIKO_CD) + logerror("Akiko CD IRQ\n"); + + amiga->custom_chip_w(REG_INTREQ, INTENA_SETCLR | INTENA_PORTS); + } +} + +TIMER_CALLBACK_MEMBER(akiko_device::frame_proc) +{ + (void)param; + + if (m_cdda != NULL) + { + UINT8 s = cdda_getstatus(NULL); + + if ( s == 0x11 ) + { + set_cd_status(0x80000000); /* subcode ready */ + } + + m_frame_timer->adjust( attotime::from_hz( 75 ) ); + } +} + +static UINT32 lba_from_triplet( UINT8 *triplet ) +{ + UINT32 r; + + r = bcd_2_dec(triplet[0]) * (60*75); + r += bcd_2_dec(triplet[1]) * 75; + r += bcd_2_dec(triplet[2]); + + return r; +} + +TIMER_CALLBACK_MEMBER(akiko_device::dma_proc) +{ + UINT8 buf[2352]; + int index; + + if ( (m_cdrom_dmacontrol & 0x04000000) == 0 ) + return; + + if ( m_cdrom_readreqmask == 0 ) + return; + + index = (m_cdrom_lba_cur - m_cdrom_lba_start) & 0x0f; + + if ( m_cdrom_readreqmask & ( 1 << index ) ) + { + amiga_state *amiga = machine().driver_data(); + UINT32 track = cdrom_get_track( m_cdrom, m_cdrom_lba_cur ); + UINT32 datasize = cdrom_get_toc( m_cdrom )->tracks[track].datasize; + UINT32 subsize = cdrom_get_toc( m_cdrom )->tracks[track].subsize; + int i; + + UINT32 curmsf = lba_to_msf( m_cdrom_lba_cur ); + memset( buf, 0, 16 ); + + buf[3] = m_cdrom_lba_cur - m_cdrom_lba_start; + memset( &buf[4], 0xff, 8 ); + + buf[12] = (curmsf >> 16) & 0xff; + buf[13] = (curmsf >> 8) & 0xff; + buf[14] = curmsf & 0xff; + buf[15] = 0x01; /* mode1 */ + + datasize = 2048; + if ( !cdrom_read_data( m_cdrom, m_cdrom_lba_cur, &buf[16], CD_TRACK_MODE1 ) ) + { + logerror( "AKIKO: Read error trying to read sector %08x!\n", m_cdrom_lba_cur ); + return; + } + + if ( subsize ) + { + if ( !cdrom_read_subcode( m_cdrom, m_cdrom_lba_cur, &buf[16+datasize] ) ) + { + logerror( "AKIKO: Read error trying to read subcode for sector %08x!\n", m_cdrom_lba_cur ); + return; + } + } + + if (LOG_AKIKO_CD) logerror( "DMA: sector %d - address %08x\n", m_cdrom_lba_cur, m_cdrom_address[0] + (index*4096) ); + + for( i = 0; i < 2352; i += 2 ) + { + UINT16 data; + + data = buf[i]; + data <<= 8; + data |= buf[i+1]; + + amiga->chip_ram_w(m_cdrom_address[0] + (index*4096) + i, data ); + } + + m_cdrom_readmask |= ( 1 << index ); + m_cdrom_readreqmask &= ~( 1 << index ); + m_cdrom_lba_cur++; + } + + if ( m_cdrom_readreqmask == 0 ) + set_cd_status(0x04000000); + else + m_dma_timer->adjust( attotime::from_usec( CD_SECTOR_TIME / m_cdrom_speed ) ); +} + +void akiko_device::start_dma() +{ + if ( m_cdrom_readreqmask == 0 ) + return; + + if ( m_cdrom_lba_start > m_cdrom_lba_end ) + return; + + if ( m_cdrom_speed == 0 ) + return; + + m_cdrom_lba_cur = m_cdrom_lba_start; + + m_dma_timer->adjust( attotime::from_usec( CD_SECTOR_TIME / m_cdrom_speed ) ); +} + +void akiko_device::setup_response( int len, UINT8 *r1 ) +{ + int resp_addr = m_cdrom_address[1]; + UINT8 resp_csum = 0xff; + UINT8 resp_buffer[32]; + int i; + + memset( resp_buffer, 0, sizeof( resp_buffer ) ); + + for( i = 0; i < len; i++ ) + { + resp_buffer[i] = r1[i]; + resp_csum -= resp_buffer[i]; + } + + resp_buffer[len++] = resp_csum; + + for( i = 0; i < len; i++ ) + { + m_space->write_byte( resp_addr + ((m_cdrom_cmd_resp + i) & 0xff), resp_buffer[i] ); + } + + m_cdrom_cmd_resp = (m_cdrom_cmd_resp+len) & 0xff; + + set_cd_status(0x10000000); /* new data available */ +} + +TIMER_CALLBACK_MEMBER( akiko_device::cd_delayed_cmd ) +{ + UINT8 resp[32]; + UINT8 cddastatus; + + if ( m_cdrom_status[0] & 0x10000000 ) + return; + + cddastatus = cdda_getstatus(NULL); + + if ( cddastatus == 0x11 || cddastatus == 0x12 ) + return; + + memset( resp, 0, sizeof( resp ) ); + resp[0] = param; + + param &= 0x0f; + + if ( param == 0x05 ) + { + if (LOG_AKIKO_CD) logerror( "AKIKO: Completing Command %d\n", param ); + + resp[0] = 0x06; + + if ( m_cdrom == NULL || m_cdrom_numtracks == 0 ) + { + resp[1] = 0x80; + setup_response( 15, resp ); + } + else + { + resp[1] = 0x00; + memcpy( &resp[2], &m_cdrom_toc[13*m_cdrom_track_index], 13 ); + + m_cdrom_track_index = ( m_cdrom_track_index + 1 ) % m_cdrom_numtracks; + + setup_response( 15, resp ); + } + } +} + +void akiko_device::update_cdrom() +{ + UINT8 resp[32], cmdbuf[32]; + + if ( m_cdrom_status[0] & 0x10000000 ) + return; + + while ( m_cdrom_cmd_start != m_cdrom_cmd_end ) + { + UINT32 cmd_addr = m_cdrom_address[1] + 0x200 + m_cdrom_cmd_start; + int cmd = m_space->read_byte( cmd_addr ); + + memset( resp, 0, sizeof( resp ) ); + resp[0] = cmd; + + cmd &= 0x0f; + + if (LOG_AKIKO_CD) logerror( "CDROM command: %02X\n", cmd ); + + if ( cmd == 0x02 ) /* pause audio */ + { + resp[1] = 0x00; + + if ( cdda_getstatus(NULL) == 0x11 ) + resp[1] = 0x08; + + cdda_pause(1); + + m_cdrom_cmd_start = (m_cdrom_cmd_start+2) & 0xff; + + setup_response( 2, resp ); + } + else if ( cmd == 0x03 ) /* unpause audio (and check audiocd playing status) */ + { + resp[1] = 0x00; + + if ( cdda_getstatus(NULL) == 0x11 ) + resp[1] = 0x08; + + cdda_pause(0); + + m_cdrom_cmd_start = (m_cdrom_cmd_start+2) & 0xff; + + setup_response( 2, resp ); + } + else if ( cmd == 0x04 ) /* seek/read/play cd multi command */ + { + int i; + UINT32 startpos, endpos; + + for( i = 0; i < 13; i++ ) + { + cmdbuf[i] = m_space->read_byte( cmd_addr ); + cmd_addr &= 0xffffff00; + cmd_addr += ( m_cdrom_cmd_start + i + 1 ) & 0xff; + } + + m_cdrom_cmd_start = (m_cdrom_cmd_start+13) & 0xff; + + if ( m_cdrom == NULL || m_cdrom_numtracks == 0 ) + { + resp[1] = 0x80; + setup_response( 2, resp ); + } + else + { + startpos = lba_from_triplet( &cmdbuf[1] ); + endpos = lba_from_triplet( &cmdbuf[4] ); + + cdda_stop(); + + resp[1] = 0x00; + + if ( cmdbuf[7] == 0x80 ) + { + if (LOG_AKIKO_CD) logerror( "%s:AKIKO CD: Data read - start lba: %08x - end lba: %08x\n", machine().describe_context(), startpos, endpos ); + m_cdrom_speed = (cmdbuf[8] & 0x40) ? 2 : 1; + m_cdrom_lba_start = startpos; + m_cdrom_lba_end = endpos; + + resp[1] = 0x02; + } + else if ( cmdbuf[10] & 0x04 ) + { + logerror( "AKIKO CD: Audio Play - start lba: %08x - end lba: %08x\n", startpos, endpos ); + cdda_play(startpos, endpos - startpos); + resp[1] = 0x08; + } + else + { + if (LOG_AKIKO_CD) logerror( "AKIKO CD: Seek - start lba: %08x - end lba: %08x\n", startpos, endpos ); + m_cdrom_track_index = 0; + + for( i = 0; i < cdrom_get_last_track(m_cdrom); i++ ) + { + if ( startpos <= cdrom_get_track_start( m_cdrom, i ) ) + { + /* reset to 0 */ + m_cdrom_track_index = i + 2; + m_cdrom_track_index %= m_cdrom_numtracks; + break; + } + } + } + + setup_response( 2, resp ); + } + } + else if ( cmd == 0x05 ) /* read toc */ + { + m_cdrom_cmd_start = (m_cdrom_cmd_start+3) & 0xff; + + machine().scheduler().timer_set( attotime::from_msec(1), timer_expired_delegate(FUNC(akiko_device::cd_delayed_cmd ), this), resp[0]); + + break; + } + else if ( cmd == 0x06 ) /* read subq */ + { + UINT32 lba; + + resp[1] = 0x00; + + (void)cdda_getstatus(&lba); + + if ( lba > 0 ) + { + UINT32 disk_pos; + UINT32 track_pos; + UINT32 track; + int addrctrl; + + track = cdrom_get_track(m_cdrom, lba); + addrctrl = cdrom_get_adr_control(m_cdrom, track); + + resp[2] = 0x00; + resp[3] = ((addrctrl & 0x0f) << 4) | ((addrctrl & 0xf0) >> 4); + resp[4] = dec_2_bcd(track+1); + resp[5] = 0; /* index */ + + disk_pos = lba_to_msf(lba); + track_pos = lba_to_msf(lba - cdrom_get_track_start(m_cdrom, track)); + + /* track position */ + resp[6] = (track_pos >> 16) & 0xff; + resp[7] = (track_pos >> 8) & 0xff; + resp[8] = track_pos & 0xff; + + /* disk position */ + resp[9] = (disk_pos >> 24) & 0xff; + resp[10] = (disk_pos >> 16) & 0xff; + resp[11] = (disk_pos >> 8) & 0xff; + resp[12] = disk_pos & 0xff; + } + else + { + resp[1] = 0x80; + } + + setup_response( 15, resp ); + } + else if ( cmd == 0x07 ) /* check door status */ + { + resp[1] = 0x01; + + m_cdrom_cmd_start = (m_cdrom_cmd_start+2) & 0xff; + + if ( m_cdrom == NULL || m_cdrom_numtracks == 0 ) + resp[1] = 0x80; + + setup_response( 20, resp ); + break; + } + else + { + break; + } + } +} + +READ32_MEMBER( akiko_device::read ) +{ + UINT32 retval; + + if ( LOG_AKIKO && offset < (0x30/4) ) + { + logerror( "Reading AKIKO reg %0x [%s] at PC=%06x\n", offset, get_akiko_reg_name(offset), m_space->device().safe_pc() ); + } + + switch( offset ) + { + case 0x00/4: /* ID */ + if ( m_cdrom != NULL ) m_cdda->set_cdrom(m_cdrom); + return 0x0000cafe; + + case 0x04/4: /* CDROM STATUS 1 */ + return m_cdrom_status[0]; + + case 0x08/4: /* CDROM STATUS 2 */ + return m_cdrom_status[1]; + + case 0x10/4: /* CDROM ADDRESS 1 */ + return m_cdrom_address[0]; + + case 0x14/4: /* CDROM ADDRESS 2 */ + return m_cdrom_address[1]; + + case 0x18/4: /* CDROM COMMAND 1 */ + update_cdrom(); + retval = m_cdrom_cmd_start; + retval <<= 8; + retval |= m_cdrom_cmd_resp; + retval <<= 8; + return retval; + + case 0x1C/4: /* CDROM COMMAND 2 */ + update_cdrom(); + retval = m_cdrom_cmd_end; + retval <<= 16; + return retval; + + case 0x20/4: /* CDROM DMA SECTOR READ MASK */ + retval = m_cdrom_readmask << 16; + return retval; + + case 0x24/4: /* CDROM DMA ENABLE? */ + retval = m_cdrom_dmacontrol; + return retval; + + case 0x30/4: /* NVRAM */ + return nvram_read(); + + case 0x38/4: /* C2P */ + return c2p_read(); + + default: + break; + } + + return 0; +} + +WRITE32_MEMBER( akiko_device::write ) +{ + if ( LOG_AKIKO && offset < (0x30/4) ) + { + logerror( "Writing AKIKO reg %0x [%s] with %08x at PC=%06x\n", offset, get_akiko_reg_name(offset), data, m_space->device().safe_pc() ); + } + + switch( offset ) + { + case 0x04/4: /* CDROM STATUS 1 */ + m_cdrom_status[0] = data; + break; + + case 0x08/4: /* CDROM STATUS 2 */ + m_cdrom_status[1] = data; + m_cdrom_status[0] &= data; + break; + + case 0x10/4: /* CDROM ADDRESS 1 */ + m_cdrom_address[0] = data; + break; + + case 0x14/4: /* CDROM ADDRESS 2 */ + m_cdrom_address[1] = data; + break; + + case 0x18/4: /* CDROM COMMAND 1 */ + if ( ACCESSING_BITS_16_23 ) + m_cdrom_cmd_start = ( data >> 16 ) & 0xff; + + if ( ACCESSING_BITS_8_15 ) + m_cdrom_cmd_resp = ( data >> 8 ) & 0xff; + + update_cdrom(); + break; + + case 0x1C/4: /* CDROM COMMAND 2 */ + if ( ACCESSING_BITS_16_23 ) + m_cdrom_cmd_end = ( data >> 16 ) & 0xff; + + update_cdrom(); + break; + + case 0x20/4: /* CDROM DMA SECTOR READ REQUEST WRITE */ + if (LOG_AKIKO_CD) logerror( "Read Req mask W: data %08x - mem mask %08x\n", data, mem_mask ); + if ( ACCESSING_BITS_16_31 ) + { + m_cdrom_readreqmask = (data >> 16); + m_cdrom_readmask = 0; + } + break; + + case 0x24/4: /* CDROM DMA ENABLE? */ + if (LOG_AKIKO_CD) logerror( "DMA enable W: data %08x - mem mask %08x\n", data, mem_mask ); + if ( ( m_cdrom_dmacontrol ^ data ) & 0x04000000 ) + { + if ( data & 0x04000000 ) + start_dma(); + } + m_cdrom_dmacontrol = data; + break; + + case 0x30/4: + nvram_write(data); + break; + + case 0x38/4: + c2p_write(data); + break; + + default: + break; + } +} diff --git a/src/devices/machine/akiko.h b/src/devices/machine/akiko.h new file mode 100644 index 00000000000..9be2ac08185 --- /dev/null +++ b/src/devices/machine/akiko.h @@ -0,0 +1,155 @@ +// license:BSD-3-Clause +// copyright-holders:Mariusz Wojcieszek +/*************************************************************************** + + Akiko + + Used in the Amiga CD32 + + - CD-ROM controller + - Builtin 1KB NVRAM + - Chunky to planar converter + +***************************************************************************/ + +#pragma once + +#ifndef __AKIKO_H__ +#define __AKIKO_H__ + +#include "emu.h" +#include "cdrom.h" +#include "sound/cdda.h" + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_AKIKO_ADD(_tag, _cputag) \ + MCFG_DEVICE_ADD(_tag, AKIKO, 0) \ + akiko_device::set_cputag(*device, _cputag); + +#define MCFG_AKIKO_SCL_HANDLER(_devcb) \ + devcb = &akiko_device::set_scl_handler(*device, DEVCB_##_devcb); + +#define MCFG_AKIKO_SDA_READ_HANDLER(_devcb) \ + devcb = &akiko_device::set_sda_read_handler(*device, DEVCB_##_devcb); + +#define MCFG_AKIKO_SDA_WRITE_HANDLER(_devcb) \ + devcb = &akiko_device::set_sda_write_handler(*device, DEVCB_##_devcb); + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> akiko_device + +class akiko_device : public device_t +{ +public: + akiko_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + ~akiko_device() {} + + // callbacks + template static devcb_base &set_scl_handler(device_t &device, _Object object) + { return downcast(device).m_scl_w.set_callback(object); } + + template static devcb_base &set_sda_read_handler(device_t &device, _Object object) + { return downcast(device).m_sda_r.set_callback(object); } + + template static devcb_base &set_sda_write_handler(device_t &device, _Object object) + { return downcast(device).m_sda_w.set_callback(object); } + + DECLARE_READ32_MEMBER( read ); + DECLARE_WRITE32_MEMBER( write ); + + // inline configuration + static void set_cputag(device_t &device, const char *tag); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_stop(); + virtual void device_reset(); + virtual machine_config_constructor device_mconfig_additions() const; + +private: + // 1X CDROM sector time in msec (300KBps) + static const int CD_SECTOR_TIME = (1000/((150*1024)/2048)); + + // internal state + address_space *m_space; + + // chunky to planar converter + UINT32 m_c2p_input_buffer[8]; + UINT32 m_c2p_output_buffer[8]; + UINT32 m_c2p_input_index; + UINT32 m_c2p_output_index; + + // i2c bus + int m_i2c_scl_out; + int m_i2c_scl_dir; + int m_i2c_sda_out; + int m_i2c_sda_dir; + + // cdrom + UINT32 m_cdrom_status[2]; + UINT32 m_cdrom_address[2]; + UINT32 m_cdrom_track_index; + UINT32 m_cdrom_lba_start; + UINT32 m_cdrom_lba_end; + UINT32 m_cdrom_lba_cur; + UINT16 m_cdrom_readmask; + UINT16 m_cdrom_readreqmask; + UINT32 m_cdrom_dmacontrol; + UINT32 m_cdrom_numtracks; + UINT8 m_cdrom_speed; + UINT8 m_cdrom_cmd_start; + UINT8 m_cdrom_cmd_end; + UINT8 m_cdrom_cmd_resp; + + cdda_device *m_cdda; + cdrom_file *m_cdrom; + + UINT8 *m_cdrom_toc; + + emu_timer *m_dma_timer; + emu_timer *m_frame_timer; + + int m_cdrom_is_device; + + void nvram_write(UINT32 data); + UINT32 nvram_read(); + + void c2p_write(UINT32 data); + UINT32 c2p_read(); + + void cdda_stop(); + void cdda_play(UINT32 lba, UINT32 num_blocks); + void cdda_pause(int pause); + UINT8 cdda_getstatus(UINT32 *lba); + void set_cd_status(UINT32 status); + + TIMER_CALLBACK_MEMBER( frame_proc ); + TIMER_CALLBACK_MEMBER( dma_proc ); + + void start_dma(); + void setup_response( int len, UINT8 *r1 ); + + TIMER_CALLBACK_MEMBER( cd_delayed_cmd ); + void update_cdrom(); + + // i2c interface + devcb_write_line m_scl_w; + devcb_read_line m_sda_r; + devcb_write_line m_sda_w; + + const char *m_cputag; +}; + +// device type definition +extern const device_type AKIKO; + +#endif diff --git a/src/devices/machine/am53cf96.c b/src/devices/machine/am53cf96.c new file mode 100644 index 00000000000..595a38f985b --- /dev/null +++ b/src/devices/machine/am53cf96.c @@ -0,0 +1,194 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/* + * am53cf96.c + * + * AMD/NCR/Symbios 53CF96 SCSI-2 controller. + * Qlogic FAS-236 and Emulex ESP-236 are equivalents + * + * References: + * AMD Am53CF96 manual + * + */ + +#include "emu.h" +#include "am53cf96.h" +#include "bus/scsi/scsihle.h" + +READ8_MEMBER( am53cf96_device::read ) +{ + int rv; + static const int states[] = { 0, 0, 1, 1, 2, 3, 4, 5, 6, 7, 0 }; + + if (offset == REG_STATUS) + { + scsi_regs[REG_STATUS] &= ~0x7; + scsi_regs[REG_STATUS] |= states[xfer_state]; + if (xfer_state < 10) + { + xfer_state++; + } + } + + rv = scsi_regs[offset]; + + if (offset == REG_FIFO) + { +// osd_printf_debug("53cf96: read FIFO PC=%x\n", space.device().safe_pc()); + return 0; + } + +// logerror("53cf96: read reg %d = %x (PC=%x)\n", reg, rv>>shift, space.device().safe_pc()); + + if (offset == REG_IRQSTATE) + { + scsi_regs[REG_STATUS] &= ~0x80; // clear IRQ flag + } + + return rv; +} + +void am53cf96_device::device_timer(emu_timer &timer, device_timer_id tid, int param, void *ptr) +{ + scsi_regs[REG_IRQSTATE] = 8; // indicate success + scsi_regs[REG_STATUS] |= 0x80; // indicate IRQ + m_irq_handler(1); +} + +WRITE8_MEMBER( am53cf96_device::write ) +{ +// logerror("53cf96: w %x to reg %d (PC=%x)\n", data, offset, space.device().safe_pc()); + + // if writing to the target ID, cache it off for later + if (offset == REG_STATUS) + { + last_id = data; + } + + if (offset == REG_XFERCNTLOW || offset == REG_XFERCNTMID || offset == REG_XFERCNTHI) + { + scsi_regs[REG_STATUS] &= ~0x10; // clear CTZ bit + } + + // FIFO + if (offset == REG_FIFO) + { +// osd_printf_debug("%02x to FIFO @ %02d\n", data, fptr); + fifo[fptr++] = data; + if (fptr > 15) + { + fptr = 15; + } + } + + // command + if (offset == REG_COMMAND) + { + //dma = (data & 0x80) ? 1 : 0; + fptr = 0; + switch (data & 0x7f) + { + case 0: // NOP + scsi_regs[REG_IRQSTATE] = 8; // indicate success + xfer_state = 0; + break; + case 2: // reset am53cf96 + scsi_regs[REG_IRQSTATE] = 8; // indicate success + + logerror("53cf96: reset target ID = %d (PC = %x)\n", last_id, space.device().safe_pc()); + + xfer_state = 0; + break; + case 3: // reset SCSI bus + scsi_regs[REG_INTSTATE] = 4; // command sent OK + + reset_bus(); + + xfer_state = 0; + m_transfer_timer->adjust( attotime::from_hz( 16384 ) ); + break; + case 0x42: // select with ATN steps + m_transfer_timer->adjust( attotime::from_hz( 16384 ) ); + if ((fifo[1] == 0) || (fifo[1] == 0x48) || (fifo[1] == 0x4b)) + { + scsi_regs[REG_INTSTATE] = 6; + } + else + { + scsi_regs[REG_INTSTATE] = 4; + } + + logerror("53cf96: command %x exec. target ID = %d (PC = %x)\n", fifo[1], last_id, space.device().safe_pc()); + + select(last_id); + send_command(&fifo[1], 12); + xfer_state = 0; + break; + case 0x44: // enable selection/reselection + xfer_state = 0; + break; + case 0x10: // information transfer (must not change xfer_state) + case 0x11: // second phase of information transfer + case 0x12: // message accepted + m_transfer_timer->adjust( attotime::from_hz( 16384 ) ); + scsi_regs[REG_INTSTATE] = 6; // command sent OK + break; + default: + printf( "unsupported command %02x\n", data ); + break; + } + } + + // only update the register mirror if it's not a write-only reg + if (offset != REG_STATUS && offset != REG_INTSTATE && offset != REG_IRQSTATE && offset != REG_FIFOSTATE) + { + scsi_regs[offset] = data; + } +} + +am53cf96_device::am53cf96_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + legacy_scsi_host_adapter(mconfig, AM53CF96, "53CF96 SCSI", tag, owner, clock, "am53cf96", __FILE__), + m_irq_handler(*this) +{ +} + +void am53cf96_device::device_start() +{ + legacy_scsi_host_adapter::device_start(); + + m_irq_handler.resolve_safe(); + + memset(scsi_regs, 0, sizeof(scsi_regs)); + + fptr = 0; + xfer_state = 0; + last_id = -1; + + save_item( NAME( scsi_regs ) ); + save_item( NAME( fifo ) ); + save_item( NAME( fptr ) ); + save_item( NAME( xfer_state ) ); + save_item( NAME( last_id ) ); + + m_transfer_timer = timer_alloc( TIMER_TRANSFER ); +} + +// retrieve data from the SCSI controller +void am53cf96_device::dma_read_data(int bytes, UINT8 *pData) +{ + scsi_regs[REG_STATUS] |= 0x10; // indicate DMA finished + + read_data(pData, bytes); +} + +// write data to the SCSI controller +void am53cf96_device::dma_write_data(int bytes, UINT8 *pData) +{ +// int i; + + scsi_regs[REG_STATUS] |= 0x10; // indicate DMA finished + + write_data(pData, bytes); +} + +const device_type AM53CF96 = &device_creator; diff --git a/src/devices/machine/am53cf96.h b/src/devices/machine/am53cf96.h new file mode 100644 index 00000000000..8fda3ee0e5b --- /dev/null +++ b/src/devices/machine/am53cf96.h @@ -0,0 +1,76 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/* + * am53cf96.h + * + */ + +#ifndef _AM53CF96_H_ +#define _AM53CF96_H_ + +#pragma once + +#include "legscsi.h" + +#define MCFG_AM53CF96_IRQ_HANDLER(_devcb) \ + devcb = &am53cf96_device::set_irq_handler(*device, DEVCB_##_devcb); + +// 53CF96 register set +enum +{ + REG_XFERCNTLOW = 0, // read = current xfer count lo byte, write = set xfer count lo byte + REG_XFERCNTMID, // read = current xfer count mid byte, write = set xfer count mid byte + REG_FIFO, // read/write = FIFO + REG_COMMAND, // read/write = command + + REG_STATUS, // read = status, write = destination SCSI ID (4) + REG_IRQSTATE, // read = IRQ status, write = timeout (5) + REG_INTSTATE, // read = internal state, write = sync xfer period (6) + REG_FIFOSTATE, // read = FIFO status, write = sync offset + REG_CTRL1, // read/write = control 1 + REG_CLOCKFCTR, // clock factor (write only) + REG_TESTMODE, // test mode (write only) + REG_CTRL2, // read/write = control 2 + REG_CTRL3, // read/write = control 3 + REG_CTRL4, // read/write = control 4 + REG_XFERCNTHI, // read = current xfer count hi byte, write = set xfer count hi byte + REG_DATAALIGN // data alignment (write only) +}; + +class am53cf96_device : public legacy_scsi_host_adapter +{ +public: + // construction/destruction + am53cf96_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // static configuration helpers + template static devcb_base &set_irq_handler(device_t &device, _Object object) { return downcast(device).m_irq_handler.set_callback(object); } + + DECLARE_READ8_MEMBER(read); + DECLARE_WRITE8_MEMBER(write); + + void dma_read_data(int bytes, UINT8 *pData); + void dma_write_data(int bytes, UINT8 *pData); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + +private: + static const device_timer_id TIMER_TRANSFER = 0; + + UINT8 scsi_regs[32]; + UINT8 fifo[16]; + UINT8 fptr; + UINT8 xfer_state; + UINT8 last_id; + + emu_timer* m_transfer_timer; + devcb_write_line m_irq_handler; +}; + +// device type definition +extern const device_type AM53CF96; + +#endif diff --git a/src/devices/machine/am9517a.c b/src/devices/machine/am9517a.c new file mode 100644 index 00000000000..469da3d167f --- /dev/null +++ b/src/devices/machine/am9517a.c @@ -0,0 +1,1279 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/*************************************************************************** + + AMD AM9517A + Intel 8237A + NEC uPD71037 + + NEC uPD71071 (extended version of above) + + a variant is used in the V53 CPU which offers subsets of both the + uPD71071 and uPD71037 functionality depending on a mode bit. + + Multimode DMA Controller emulation + +***************************************************************************/ + +/* + + TODO: + + - external EOP + +*/ + +/* + + When the V53 operates in uPD71071 compatible mode there are the following + differences from a real uPD71071 + + V53 Real uPD71071 + Software Reqs No Yes + Memory-to-Memory DMA No Yes + DMARQ active level High programmable + DMAAK active level Low programmable + Bus Cycle 4 4 or 3 + + we don't currently handle the differences + +*/ + +#include "am9517a.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type AM9517A = &device_creator; +const device_type V53_DMAU = &device_creator; + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define LOG 0 + + +enum +{ + REGISTER_ADDRESS = 0, + REGISTER_WORD_COUNT, + REGISTER_STATUS = 8, + REGISTER_COMMAND = REGISTER_STATUS, + REGISTER_REQUEST, + REGISTER_SINGLE_MASK, + REGISTER_MODE, + REGISTER_BYTE_POINTER, + REGISTER_TEMPORARY, + REGISTER_MASTER_CLEAR = REGISTER_TEMPORARY, + REGISTER_CLEAR_MASK, + REGISTER_MASK +}; + + +#define COMMAND_MEM_TO_MEM BIT(m_command, 0) +#define COMMAND_CH0_ADDRESS_HOLD BIT(m_command, 1) +#define COMMAND_DISABLE BIT(m_command, 2) +#define COMMAND_COMPRESSED_TIMING BIT(m_command, 3) +#define COMMAND_ROTATING_PRIORITY BIT(m_command, 4) +#define COMMAND_EXTENDED_WRITE BIT(m_command, 5) +#define COMMAND_DREQ_ACTIVE_LOW BIT(m_command, 6) +#define COMMAND_DACK_ACTIVE_HIGH BIT(m_command, 7) + + +#define MODE_TRANSFER_MASK (m_channel[m_current_channel].m_mode & 0x0c) +#define MODE_TRANSFER_VERIFY 0x00 +#define MODE_TRANSFER_WRITE 0x04 +#define MODE_TRANSFER_READ 0x08 +#define MODE_TRANSFER_ILLEGAL 0x0c +#define MODE_AUTOINITIALIZE BIT(m_channel[m_current_channel].m_mode, 4) +#define MODE_ADDRESS_DECREMENT BIT(m_channel[m_current_channel].m_mode, 5) +#define MODE_MASK (m_channel[m_current_channel].m_mode & 0xc0) +#define MODE_DEMAND 0x00 +#define MODE_SINGLE 0x40 +#define MODE_BLOCK 0x80 +#define MODE_CASCADE 0xc0 + + +enum +{ + STATE_SI, + STATE_S0, + STATE_SC, + STATE_S1, + STATE_S2, + STATE_S3, + STATE_SW, + STATE_S4, + STATE_S11, + STATE_S12, + STATE_S13, + STATE_S14, + STATE_S21, + STATE_S22, + STATE_S23, + STATE_S24 +}; + + + +//************************************************************************** +// INLINE HELPERS +//************************************************************************** + +//------------------------------------------------- +// dma_request - +//------------------------------------------------- + +inline void am9517a_device::dma_request(int channel, int state) +{ + if (LOG) logerror("AM9517A '%s' Channel %u DMA Request: %u\n", tag(), channel, state); + + if (state ^ COMMAND_DREQ_ACTIVE_LOW) + { + m_status |= (1 << (channel + 4)); + } + else + { + m_status &= ~(1 << (channel + 4)); + } + trigger(1); +} + + +//------------------------------------------------- +// is_request_active - +//------------------------------------------------- + +inline bool am9517a_device::is_request_active(int channel) +{ + return (BIT(m_status, channel + 4) & !BIT(m_mask, channel)) ? true : false; +} + + +//------------------------------------------------- +// is_software_request_active - +//------------------------------------------------- + +inline bool am9517a_device::is_software_request_active(int channel) +{ + return BIT(m_request, channel) && ((m_channel[channel].m_mode & 0xc0) == MODE_BLOCK); +} + + +//------------------------------------------------- +// set_hreq +//------------------------------------------------- + +inline void am9517a_device::set_hreq(int state) +{ + if (m_hreq != state) + { + m_out_hreq_cb(state); + + m_hreq = state; + } +} + + +//------------------------------------------------- +// set_dack - +//------------------------------------------------- + +inline void am9517a_device::set_dack() +{ + for (int channel = 0; channel < 4; channel++) + { + if (channel == 0) + { + if ((channel == m_current_channel) && !COMMAND_MEM_TO_MEM) + { + m_out_dack_0_cb(COMMAND_DACK_ACTIVE_HIGH); + } + else + { + m_out_dack_0_cb(!COMMAND_DACK_ACTIVE_HIGH); + } + } + else if (channel == 1) + { + if ((channel == m_current_channel) && !COMMAND_MEM_TO_MEM) + { + m_out_dack_1_cb(COMMAND_DACK_ACTIVE_HIGH); + } + else + { + m_out_dack_1_cb(!COMMAND_DACK_ACTIVE_HIGH); + } + } + else if (channel == 2) + { + if ((channel == m_current_channel) && !COMMAND_MEM_TO_MEM) + { + m_out_dack_2_cb(COMMAND_DACK_ACTIVE_HIGH); + } + else + { + m_out_dack_2_cb(!COMMAND_DACK_ACTIVE_HIGH); + } + } + else if (channel == 3) + { + if ((channel == m_current_channel) && !COMMAND_MEM_TO_MEM) + { + m_out_dack_3_cb(COMMAND_DACK_ACTIVE_HIGH); + } + else + { + m_out_dack_3_cb(!COMMAND_DACK_ACTIVE_HIGH); + } + } + } +} + + +//------------------------------------------------- +// set_eop - +//------------------------------------------------- + +inline void am9517a_device::set_eop(int state) +{ + if (m_eop != state) + { + m_out_eop_cb(state); + + m_eop = state; + } +} + + +//------------------------------------------------- +// dma_read - +//------------------------------------------------- + +inline int am9517a_device::get_state1(bool msb_changed) +{ + if (COMMAND_MEM_TO_MEM) + { + return msb_changed ? STATE_S11 : STATE_S12; + } + else + { + return msb_changed ? STATE_S1 : STATE_S2; + } +} + + +//------------------------------------------------- +// dma_read - +//------------------------------------------------- + +inline void am9517a_device::dma_read() +{ + offs_t offset = m_channel[m_current_channel].m_address; + + switch (MODE_TRANSFER_MASK) + { + case MODE_TRANSFER_VERIFY: + case MODE_TRANSFER_WRITE: + switch(m_current_channel) + { + case 0: + m_temp = m_in_ior_0_cb(offset); + break; + case 1: + m_temp = m_in_ior_1_cb(offset); + break; + case 2: + m_temp = m_in_ior_2_cb(offset); + break; + case 3: + m_temp = m_in_ior_3_cb(offset); + break; + } + break; + + case MODE_TRANSFER_READ: + m_temp = m_in_memr_cb(offset); + break; + } +} + + +//------------------------------------------------- +// dma_write - +//------------------------------------------------- + +inline void am9517a_device::dma_write() +{ + offs_t offset = m_channel[m_current_channel].m_address; + + switch (MODE_TRANSFER_MASK) + { + case MODE_TRANSFER_VERIFY: { + UINT8 v1 = m_in_memr_cb(offset); + if(0 && m_temp != v1) + logerror("%s: verify error %02x vs. %02x\n", tag(), m_temp, v1); + break; + } + + case MODE_TRANSFER_WRITE: + m_out_memw_cb(offset, m_temp); + break; + + case MODE_TRANSFER_READ: + switch(m_current_channel) + { + case 0: + m_out_iow_0_cb(offset, m_temp); + break; + case 1: + m_out_iow_1_cb(offset, m_temp); + break; + case 2: + m_out_iow_2_cb(offset, m_temp); + break; + case 3: + m_out_iow_3_cb(offset, m_temp); + break; + } + break; + } +} + + +//------------------------------------------------- +// dma_advance - +//------------------------------------------------- + +inline void am9517a_device::dma_advance() +{ + bool msb_changed = false; + + m_channel[m_current_channel].m_count--; + + if (m_current_channel || !COMMAND_MEM_TO_MEM || !COMMAND_CH0_ADDRESS_HOLD) + { + if (MODE_ADDRESS_DECREMENT) + { + m_channel[m_current_channel].m_address--; + m_channel[m_current_channel].m_address &= m_address_mask; + + if ((m_channel[m_current_channel].m_address & 0xff) == 0xff) + { + msb_changed = true; + } + } + else + { + m_channel[m_current_channel].m_address++; + m_channel[m_current_channel].m_address &= m_address_mask; + + if ((m_channel[m_current_channel].m_address & 0xff) == 0x00) + { + msb_changed = true; + } + } + } + + if (m_channel[m_current_channel].m_count == 0xffff) + { + end_of_process(); + } + else + { + switch (MODE_MASK) + { + case MODE_DEMAND: + if (!is_request_active(m_current_channel)) + { + set_hreq(0); + set_dack(); + m_state = STATE_SI; + } + else + { + m_state = get_state1(msb_changed); + } + break; + + case MODE_SINGLE: + set_hreq(0); + set_dack(); + m_state = STATE_SI; + break; + + case MODE_BLOCK: + m_state = get_state1(msb_changed); + break; + + case MODE_CASCADE: + break; + } + } +} + + +//------------------------------------------------- +// end_of_process - +//------------------------------------------------- + +inline void am9517a_device::end_of_process() +{ + // terminal count + if (COMMAND_MEM_TO_MEM) + { + m_status |= 1 << 0; + m_status |= 1 << 1; + m_request &= ~(1 << 0); + m_request &= ~(1 << 1); + } + else + { + m_status |= 1 << m_current_channel; + m_request &= ~(1 << m_current_channel); + } + + if (MODE_AUTOINITIALIZE) + { + // autoinitialize + m_channel[m_current_channel].m_address = m_channel[m_current_channel].m_base_address; + m_channel[m_current_channel].m_count = m_channel[m_current_channel].m_base_count; + } + else + { + // mask out channel + m_mask |= 1 << m_current_channel; + } + + // signal end of process + set_eop(ASSERT_LINE); + set_hreq(0); + + m_current_channel = -1; + set_dack(); + + m_state = STATE_SI; +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// am9517a_device - constructor +//------------------------------------------------- + + +am9517a_device::am9517a_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname) + : device_t(mconfig, type, name, tag, owner, clock, shortname, __FILE__), + device_execute_interface(mconfig, *this), + m_icount(0), + m_hack(0), + m_ready(1), + m_command(0), + m_out_hreq_cb(*this), + m_out_eop_cb(*this), + m_in_memr_cb(*this), + m_out_memw_cb(*this), + m_in_ior_0_cb(*this), + m_in_ior_1_cb(*this), + m_in_ior_2_cb(*this), + m_in_ior_3_cb(*this), + m_out_iow_0_cb(*this), + m_out_iow_1_cb(*this), + m_out_iow_2_cb(*this), + m_out_iow_3_cb(*this), + m_out_dack_0_cb(*this), + m_out_dack_1_cb(*this), + m_out_dack_2_cb(*this), + m_out_dack_3_cb(*this) +{ +} + + +am9517a_device::am9517a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, AM9517A, "AM9517A", tag, owner, clock, "am9517a", __FILE__), + device_execute_interface(mconfig, *this), + m_icount(0), + m_hack(0), + m_ready(1), + m_command(0), + m_out_hreq_cb(*this), + m_out_eop_cb(*this), + m_in_memr_cb(*this), + m_out_memw_cb(*this), + m_in_ior_0_cb(*this), + m_in_ior_1_cb(*this), + m_in_ior_2_cb(*this), + m_in_ior_3_cb(*this), + m_out_iow_0_cb(*this), + m_out_iow_1_cb(*this), + m_out_iow_2_cb(*this), + m_out_iow_3_cb(*this), + m_out_dack_0_cb(*this), + m_out_dack_1_cb(*this), + m_out_dack_2_cb(*this), + m_out_dack_3_cb(*this) + +{ +} + +upd71071_v53_device::upd71071_v53_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : am9517a_device(mconfig, V53_DMAU, "V53 DMAU", tag, owner, clock, "v53_dmau") +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void am9517a_device::device_start() +{ + // set our instruction counter + m_icountptr = &m_icount; + + // resolve callbacks + m_out_hreq_cb.resolve_safe(); + m_out_eop_cb.resolve_safe(); + m_in_memr_cb.resolve_safe(0); + m_out_memw_cb.resolve_safe(); + m_in_ior_0_cb.resolve_safe(0); + m_in_ior_1_cb.resolve_safe(0); + m_in_ior_2_cb.resolve_safe(0); + m_in_ior_3_cb.resolve_safe(0); + m_out_iow_0_cb.resolve_safe(); + m_out_iow_1_cb.resolve_safe(); + m_out_iow_2_cb.resolve_safe(); + m_out_iow_3_cb.resolve_safe(); + m_out_dack_0_cb.resolve_safe(); + m_out_dack_1_cb.resolve_safe(); + m_out_dack_2_cb.resolve_safe(); + m_out_dack_3_cb.resolve_safe(); + + for (int i = 0; i < 4; i++) + { + m_channel[i].m_address = 0; + m_channel[i].m_count = 0; + m_channel[i].m_base_address = 0; + m_channel[i].m_base_count = 0; + m_channel[i].m_mode = 0; + } + + // state saving + save_item(NAME(m_msb)); + save_item(NAME(m_hreq)); + save_item(NAME(m_hack)); + save_item(NAME(m_ready)); + save_item(NAME(m_eop)); + save_item(NAME(m_state)); + save_item(NAME(m_current_channel)); + save_item(NAME(m_last_channel)); + save_item(NAME(m_command)); + save_item(NAME(m_mask)); + save_item(NAME(m_status)); + save_item(NAME(m_temp)); + save_item(NAME(m_request)); + + for (int i = 0; i < 4; i++) + { + save_item(NAME(m_channel[i].m_address), i); + save_item(NAME(m_channel[i].m_count), i); + save_item(NAME(m_channel[i].m_base_address), i); + save_item(NAME(m_channel[i].m_base_count), i); + save_item(NAME(m_channel[i].m_mode), i); + } + + m_address_mask = 0xffff; + +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void am9517a_device::device_reset() +{ + m_state = STATE_SI; + m_command = 0; + m_status = 0; + m_request = 0; + m_mask = 0x0f; + m_temp = 0; + m_msb = 0; + m_current_channel = -1; + m_last_channel = 3; + m_hreq = -1; + m_eop = 0; + + set_hreq(0); + set_eop(ASSERT_LINE); + + set_dack(); +} + + +//------------------------------------------------- +// execute_run - +//------------------------------------------------- + +void am9517a_device::execute_run() +{ + do + { + switch (m_state) + { + case STATE_SI: + set_eop(CLEAR_LINE); + + if (!COMMAND_DISABLE) + { + int priority[] = { 0, 1, 2, 3 }; + + if (COMMAND_ROTATING_PRIORITY) + { + int last_channel = m_last_channel; + + for (int channel = 3; channel >= 0; channel--) + { + priority[channel] = last_channel; + last_channel--; + if (last_channel < 0) last_channel = 3; + } + } + + for (int channel = 0; channel < 4; channel++) + { + if (is_request_active(priority[channel]) || is_software_request_active(priority[channel])) + { + m_current_channel = m_last_channel = priority[channel]; + m_state = STATE_S0; + break; + } + else if (COMMAND_MEM_TO_MEM && BIT(m_request, channel) && ((m_channel[channel].m_mode & 0xc0) == MODE_SINGLE)) + { + m_current_channel = m_last_channel = priority[channel]; + m_state = STATE_S0; + break; + } + } + } + if(m_state == STATE_SI) + { + suspend_until_trigger(1, true); + m_icount = 0; + } + break; + + case STATE_S0: + set_hreq(1); + + if (m_hack) + { + m_state = (MODE_MASK == MODE_CASCADE) ? STATE_SC : get_state1(true); + } + else + { + suspend_until_trigger(1, true); + m_icount = 0; + } + break; + + case STATE_SC: + if (!is_request_active(m_current_channel)) + { + set_hreq(0); + m_current_channel = -1; + m_state = STATE_SI; + } + else + { + suspend_until_trigger(1, true); + m_icount = 0; + } + + set_dack(); + break; + + case STATE_S1: + m_state = STATE_S2; + break; + + case STATE_S2: + set_dack(); + m_state = COMMAND_COMPRESSED_TIMING ? STATE_S4 : STATE_S3; + break; + + case STATE_S3: + dma_read(); + + if (COMMAND_EXTENDED_WRITE) + { + dma_write(); + } + + m_state = m_ready ? STATE_S4 : STATE_SW; + break; + + case STATE_SW: + m_state = m_ready ? STATE_S4 : STATE_SW; + break; + + case STATE_S4: + if (COMMAND_COMPRESSED_TIMING) + { + dma_read(); + dma_write(); + } + else if (!COMMAND_EXTENDED_WRITE) + { + dma_write(); + } + + dma_advance(); + break; + + case STATE_S11: + m_current_channel = 0; + + m_state = STATE_S12; + break; + + case STATE_S12: + m_state = STATE_S13; + break; + + case STATE_S13: + m_state = STATE_S14; + break; + + case STATE_S14: + dma_read(); + + m_state = STATE_S21; + break; + + case STATE_S21: + m_current_channel = 1; + + m_state = STATE_S22; + break; + + case STATE_S22: + m_state = STATE_S23; + break; + + case STATE_S23: + m_state = STATE_S24; + break; + + case STATE_S24: + dma_write(); + dma_advance(); + + m_current_channel = 0; + m_channel[m_current_channel].m_count--; + if (MODE_ADDRESS_DECREMENT) + { + m_channel[m_current_channel].m_address--; + m_channel[m_current_channel].m_address &= m_address_mask; + } + else + { + m_channel[m_current_channel].m_address++; + m_channel[m_current_channel].m_address &= m_address_mask; + } + + break; + } + + m_icount--; + } while (m_icount > 0); +} + + +//------------------------------------------------- +// read - +//------------------------------------------------- + +READ8_MEMBER( am9517a_device::read ) +{ + UINT8 data = 0; + + if (!BIT(offset, 3)) + { + int channel = (offset >> 1) & 0x03; + + switch (offset & 0x01) + { + case REGISTER_ADDRESS: + if (m_msb) + { + data = m_channel[channel].m_address >> 8; + } + else + { + data = m_channel[channel].m_address & 0xff; + } + break; + + case REGISTER_WORD_COUNT: + if (m_msb) + { + data = m_channel[channel].m_count >> 8; + } + else + { + data = m_channel[channel].m_count & 0xff; + } + break; + } + + m_msb = !m_msb; + } + else + { + switch (offset & 0x0f) + { + case REGISTER_STATUS: + data = m_status; + + // clear TC bits + m_status &= 0xf0; + break; + + case REGISTER_TEMPORARY: + data = m_temp; + break; + + case REGISTER_MASK: + data = m_mask; + break; + } + } + + return data; +} + + +//------------------------------------------------- +// write - +//------------------------------------------------- + +WRITE8_MEMBER( am9517a_device::write ) +{ + if (!BIT(offset, 3)) + { + int channel = (offset >> 1) & 0x03; + + switch (offset & 0x01) + { + case REGISTER_ADDRESS: + if (m_msb) + { + m_channel[channel].m_base_address = (data << 8) | (m_channel[channel].m_base_address & 0xff); + m_channel[channel].m_address = (data << 8) | (m_channel[channel].m_address & 0xff); + } + else + { + m_channel[channel].m_base_address = (m_channel[channel].m_base_address & 0xff00) | data; + m_channel[channel].m_address = (m_channel[channel].m_address & 0xff00) | data; + } + + if (LOG) logerror("AM9517A '%s' Channel %u Base Address: %04x\n", tag(), channel, m_channel[channel].m_base_address); + break; + + case REGISTER_WORD_COUNT: + if (m_msb) + { + m_channel[channel].m_base_count = (data << 8) | (m_channel[channel].m_base_count & 0xff); + m_channel[channel].m_count = (data << 8) | (m_channel[channel].m_count & 0xff); + } + else + { + m_channel[channel].m_base_count = (m_channel[channel].m_base_count & 0xff00) | data; + m_channel[channel].m_count = (m_channel[channel].m_count & 0xff00) | data; + } + + if (LOG) logerror("AM9517A '%s' Channel %u Base Word Count: %04x\n", tag(), channel, m_channel[channel].m_base_count); + break; + } + + m_msb = !m_msb; + } + else + { + switch (offset & 0x0f) + { + case REGISTER_COMMAND: + m_command = data; + + if (LOG) logerror("AM9517A '%s' Command Register: %02x\n", tag(), m_command); + break; + + case REGISTER_REQUEST: + { + int channel = data & 0x03; + + if (BIT(data, 2)) + { + m_request |= (1 << (channel + 4)); + if (COMMAND_MEM_TO_MEM) + { + m_request |= (1 << channel); + } + } + else + { + m_request &= ~(1 << (channel + 4)); + } + + if (LOG) logerror("AM9517A '%s' Request Register: %01x\n", tag(), m_request); + } + break; + + case REGISTER_SINGLE_MASK: + { + int channel = data & 0x03; + + if (BIT(data, 2)) + { + m_mask |= (1 << channel); + } + else + { + m_mask &= ~(1 << channel); + } + + if (LOG) logerror("AM9517A '%s' Mask Register: %01x\n", tag(), m_mask); + } + break; + + case REGISTER_MODE: + { + int channel = data & 0x03; + + m_channel[channel].m_mode = data & 0xfc; + + // clear terminal count + m_status &= ~(1 << channel); + + if (LOG) logerror("AM9517A '%s' Channel %u Mode: %02x\n", tag(), channel, data & 0xfc); + } + break; + + case REGISTER_BYTE_POINTER: + if (LOG) logerror("AM9517A '%s' Clear Byte Pointer Flip-Flop\n", tag()); + + m_msb = 0; + break; + + case REGISTER_MASTER_CLEAR: + if (LOG) logerror("AM9517A '%s' Master Clear\n", tag()); + + device_reset(); + break; + + case REGISTER_CLEAR_MASK: + if (LOG) logerror("AM9517A '%s' Clear Mask Register\n", tag()); + + m_mask = 0; + break; + + case REGISTER_MASK: + m_mask = data & 0x0f; + + if (LOG) logerror("AM9517A '%s' Mask Register: %01x\n", tag(), m_mask); + break; + } + } + trigger(1); +} + + +//------------------------------------------------- +// hack_w - hold acknowledge +//------------------------------------------------- + +WRITE_LINE_MEMBER( am9517a_device::hack_w ) +{ + if (LOG) logerror("AM9517A '%s' Hold Acknowledge: %u\n", tag(), state); + + m_hack = state; + trigger(1); +} + + +//------------------------------------------------- +// ready_w - ready +//------------------------------------------------- + +WRITE_LINE_MEMBER( am9517a_device::ready_w ) +{ + if (LOG) logerror("AM9517A '%s' Ready: %u\n", tag(), state); + + m_ready = state; +} + + +//------------------------------------------------- +// eop_w - end of process +//------------------------------------------------- + +WRITE_LINE_MEMBER( am9517a_device::eop_w ) +{ + if (LOG) logerror("AM9517A '%s' End of Process: %u\n", tag(), state); +} + + +//------------------------------------------------- +// dreq0_w - DMA request for channel 0 +//------------------------------------------------- + +WRITE_LINE_MEMBER( am9517a_device::dreq0_w ) +{ + dma_request(0, state); +} + + +//------------------------------------------------- +// dreq0_w - DMA request for channel 1 +//------------------------------------------------- + +WRITE_LINE_MEMBER( am9517a_device::dreq1_w ) +{ + dma_request(1, state); +} + + +//------------------------------------------------- +// dreq1_w - DMA request for channel 2 +//------------------------------------------------- + +WRITE_LINE_MEMBER( am9517a_device::dreq2_w ) +{ + dma_request(2, state); +} + + +//------------------------------------------------- +// dreq3_w - DMA request for channel 3 +//------------------------------------------------- + +WRITE_LINE_MEMBER( am9517a_device::dreq3_w ) +{ + dma_request(3, state); +} + +//------------------------------------------------- +// upd71071 register layouts +//------------------------------------------------- + +void upd71071_v53_device::device_start() +{ + am9517a_device::device_start(); + m_address_mask = 0x00ffffff; + + m_selected_channel = 0; + m_base = 0; + + save_item(NAME(m_selected_channel)); + save_item(NAME(m_base)); +} + +void upd71071_v53_device::device_reset() +{ + am9517a_device::device_reset(); + + m_selected_channel = 0; + m_base = 0; +} + + +READ8_MEMBER(upd71071_v53_device::read) +{ + UINT8 ret = 0; + int channel = m_selected_channel; + + if (LOG) logerror("DMA: read from register %02x\n",offset); + + switch (offset) + { + case 0x01: // Channel + ret = (1 << m_selected_channel); + if (m_base != 0) + ret |= 0x10; + break; + case 0x02: // Count (low) + if (m_base != 0) + ret = m_channel[channel].m_base_count & 0xff; + else + ret = m_channel[channel].m_count & 0xff; + break; + case 0x03: // Count (high) + if (m_base != 0) + ret = (m_channel[channel].m_base_count >> 8) & 0xff; + else + ret = (m_channel[channel].m_count >> 8) & 0xff; + break; + case 0x04: // Address (low) + if (m_base != 0) + ret = m_channel[channel].m_base_address & 0xff; + else + ret = m_channel[channel].m_address & 0xff; + break; + case 0x05: // Address (mid) + if (m_base != 0) + ret = (m_channel[channel].m_base_address >> 8) & 0xff; + else + ret = (m_channel[channel].m_address >> 8) & 0xff; + break; + case 0x06: // Address (high) + if (m_base != 0) + ret = (m_channel[channel].m_base_address >> 16) & 0xff; + else + ret = (m_channel[channel].m_address >> 16) & 0xff; + break; + case 0x07: // Address (highest) + if (m_base != 0) + ret = (m_channel[channel].m_base_address >> 24) & 0xff; + else + ret = (m_channel[channel].m_address >> 24) & 0xff; + break; + case 0x0a: // Mode control + ret = (m_channel[channel].m_mode); + break; + + case 0x08: // Device control (low) + ret = m_command & 0xff; + break; + case 0x09: // Device control (high) // UPD71071 only? + ret = m_command_high & 0xff; + break; + case 0x0b: // Status + ret = m_status; + // clear TC bits + m_status &= 0xf0; + break; + case 0x0c: // Temporary (low) + ret = m_temp & 0xff; + break; + case 0x0d: // Temporary (high) // UPD71071 only? (other doesn't do 16-bit?) + ret = (m_temp >> 8 ) & 0xff; + break; + case 0x0e: // Request + //ret = m_reg.request; + ret = 0; // invalid? + break; + case 0x0f: // Mask + ret = m_mask; + break; + + } + + return ret; +} + +WRITE8_MEMBER(upd71071_v53_device::write) +{ + int channel = m_selected_channel; + + switch (offset) + { + case 0x00: // Initialise + // TODO: reset (bit 0) + //m_buswidth = data & 0x02; + //if (data & 0x01) + // soft_reset(); + logerror("DMA: Initialise [%02x]\n", data); + break; + case 0x01: // Channel + m_selected_channel = data & 0x03; + m_base = data & 0x04; + logerror("DMA: Channel selected [%02x]\n", data); + break; + case 0x02: // Count (low) + m_channel[channel].m_base_count = + (m_channel[channel].m_base_count & 0xff00) | data; + if (m_base == 0) + m_channel[channel].m_count = + (m_channel[channel].m_count & 0xff00) | data; + logerror("DMA: Channel %i Counter set [%04x]\n", m_selected_channel, m_channel[channel].m_base_count); + break; + case 0x03: // Count (high) + m_channel[channel].m_base_count = + (m_channel[channel].m_base_count & 0x00ff) | (data << 8); + if (m_base == 0) + m_channel[channel].m_count = + (m_channel[channel].m_count & 0x00ff) | (data << 8); + logerror("DMA: Channel %i Counter set [%04x]\n", m_selected_channel, m_channel[channel].m_base_count); + break; + case 0x04: // Address (low) + m_channel[channel].m_base_address = + (m_channel[channel].m_base_address & 0xffffff00) | data; + if (m_base == 0) + m_channel[channel].m_address = + (m_channel[channel].m_address & 0xffffff00) | data; + logerror("DMA: Channel %i Address set [%08x]\n", m_selected_channel, m_channel[channel].m_base_address); + break; + case 0x05: // Address (mid) + m_channel[channel].m_base_address = + (m_channel[channel].m_base_address & 0xffff00ff) | (data << 8); + if (m_base == 0) + m_channel[channel].m_address = + (m_channel[channel].m_address & 0xffff00ff) | (data << 8); + logerror("DMA: Channel %i Address set [%08x]\n", m_selected_channel, m_channel[channel].m_base_address); + break; + case 0x06: // Address (high) + m_channel[channel].m_base_address = + (m_channel[channel].m_base_address & 0xff00ffff) | (data << 16); + if (m_base == 0) + m_channel[channel].m_address = + (m_channel[channel].m_address & 0xff00ffff) | (data << 16); + logerror("DMA: Channel %i Address set [%08x]\n", m_selected_channel, m_channel[channel].m_base_address); + break; + case 0x07: // Address (highest) + m_channel[channel].m_base_address = + (m_channel[channel].m_base_address & 0x00ffffff) | (data << 24); + if (m_base == 0) + m_channel[channel].m_address = + (m_channel[channel].m_address & 0x00ffffff) | (data << 24); + logerror("DMA: Channel %i Address set [%08x]\n", m_selected_channel, m_channel[channel].m_base_address); + break; + case 0x0a: // Mode control + m_channel[channel].m_mode = data; + // clear terminal count + m_status &= ~(1 << channel); + + logerror("DMA: Channel %i Mode control set [%02x]\n",m_selected_channel,m_channel[channel].m_mode); + break; + + case 0x08: // Device control (low) + m_command = data; + logerror("DMA: Device control low set [%02x]\n",data); + break; + case 0x09: // Device control (high) + m_command_high = data; + logerror("DMA: Device control high set [%02x]\n",data); + break; + case 0x0e: // Request + //m_reg.request = data; + logerror("(invalid) DMA: Request set [%02x]\n",data); // no software requests on the v53 integrated version + break; + case 0x0f: // Mask + m_mask = data & 0x0f; + logerror("DMA: Mask set [%02x]\n",data); + break; + + + } + trigger(1); + +} diff --git a/src/devices/machine/am9517a.h b/src/devices/machine/am9517a.h new file mode 100644 index 00000000000..817cf5ce9df --- /dev/null +++ b/src/devices/machine/am9517a.h @@ -0,0 +1,255 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/*************************************************************************** + + AMD AM9517A/8237A Multimode DMA Controller emulation + +**************************************************************************** + _____ _____ + _IOR 1 |* \_/ | 40 A7 + _IOW 2 | | 39 A6 + _MEMR 3 | | 38 A5 + _MEMW 4 | | 37 A4 + * 5 | | 36 _EOP + READY 6 | | 35 A3 + HACK 7 | | 34 A2 + ADSTB 8 | | 33 A1 + AEN 9 | | 32 A0 + HREQ 10 | AM9517A | 31 Vcc + _CS 11 | 8237A | 30 DB0 + CLK 12 | | 29 DB1 + RESET 13 | | 28 DB2 + DACK2 14 | | 27 DB3 + DACK3 15 | | 26 DB4 + DREQ3 16 | | 25 DACK0 + DREQ2 17 | | 24 DACK1 + DREQ1 18 | | 23 DB5 + DREQ0 19 | | 22 DB6 + Vss 20 |_____________| 21 DB7 + +***************************************************************************/ + +#pragma once + +#ifndef __AM9517A__ +#define __AM9517A__ + +#include "emu.h" + + +/*************************************************************************** + TYPE DEFINITIONS +***************************************************************************/ + +// ======================> am9517a_device + +class am9517a_device : public device_t, + public device_execute_interface +{ +public: + // construction/destruction + am9517a_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname); + am9517a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + template static devcb_base &set_out_hreq_callback(device_t &device, _Object object) { return downcast(device).m_out_hreq_cb.set_callback(object); } + template static devcb_base &set_out_eop_callback(device_t &device, _Object object) { return downcast(device).m_out_eop_cb.set_callback(object); } + + template static devcb_base &set_in_memr_callback(device_t &device, _Object object) { return downcast(device).m_in_memr_cb.set_callback(object); } + template static devcb_base &set_out_memw_callback(device_t &device, _Object object) { return downcast(device).m_out_memw_cb.set_callback(object); } + + template static devcb_base &set_in_ior_0_callback(device_t &device, _Object object) { return downcast(device).m_in_ior_0_cb.set_callback(object); } + template static devcb_base &set_in_ior_1_callback(device_t &device, _Object object) { return downcast(device).m_in_ior_1_cb.set_callback(object); } + template static devcb_base &set_in_ior_2_callback(device_t &device, _Object object) { return downcast(device).m_in_ior_2_cb.set_callback(object); } + template static devcb_base &set_in_ior_3_callback(device_t &device, _Object object) { return downcast(device).m_in_ior_3_cb.set_callback(object); } + + template static devcb_base &set_out_iow_0_callback(device_t &device, _Object object) { return downcast(device).m_out_iow_0_cb.set_callback(object); } + template static devcb_base &set_out_iow_1_callback(device_t &device, _Object object) { return downcast(device).m_out_iow_1_cb.set_callback(object); } + template static devcb_base &set_out_iow_2_callback(device_t &device, _Object object) { return downcast(device).m_out_iow_2_cb.set_callback(object); } + template static devcb_base &set_out_iow_3_callback(device_t &device, _Object object) { return downcast(device).m_out_iow_3_cb.set_callback(object); } + + template static devcb_base &set_out_dack_0_callback(device_t &device, _Object object) { return downcast(device).m_out_dack_0_cb.set_callback(object); } + template static devcb_base &set_out_dack_1_callback(device_t &device, _Object object) { return downcast(device).m_out_dack_1_cb.set_callback(object); } + template static devcb_base &set_out_dack_2_callback(device_t &device, _Object object) { return downcast(device).m_out_dack_2_cb.set_callback(object); } + template static devcb_base &set_out_dack_3_callback(device_t &device, _Object object) { return downcast(device).m_out_dack_3_cb.set_callback(object); } + + virtual DECLARE_READ8_MEMBER( read ); + virtual DECLARE_WRITE8_MEMBER( write ); + + DECLARE_WRITE_LINE_MEMBER( hack_w ); + DECLARE_WRITE_LINE_MEMBER( ready_w ); + DECLARE_WRITE_LINE_MEMBER( eop_w ); + + DECLARE_WRITE_LINE_MEMBER( dreq0_w ); + DECLARE_WRITE_LINE_MEMBER( dreq1_w ); + DECLARE_WRITE_LINE_MEMBER( dreq2_w ); + DECLARE_WRITE_LINE_MEMBER( dreq3_w ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void execute_run(); + + int m_icount; + UINT32 m_address_mask; + + struct + { + UINT32 m_address; + UINT16 m_count; + UINT32 m_base_address; + UINT16 m_base_count; + UINT8 m_mode; + } m_channel[4]; + + int m_msb; + int m_hreq; + int m_hack; + int m_ready; + int m_eop; + int m_state; + int m_current_channel; + int m_last_channel; + UINT8 m_command; + UINT8 m_mask; + UINT8 m_status; + UINT16 m_temp; + UINT8 m_request; + +private: + inline void dma_request(int channel, int state); + inline bool is_request_active(int channel); + inline bool is_software_request_active(int channel); + inline void set_hreq(int state); + inline void set_dack(); + inline void set_eop(int state); + inline int get_state1(bool msb_changed); + inline void dma_read(); + inline void dma_write(); + inline void dma_advance(); + inline void end_of_process(); + + devcb_write_line m_out_hreq_cb; + devcb_write_line m_out_eop_cb; + + devcb_read8 m_in_memr_cb; + devcb_write8 m_out_memw_cb; + + devcb_read8 m_in_ior_0_cb; + devcb_read8 m_in_ior_1_cb; + devcb_read8 m_in_ior_2_cb; + devcb_read8 m_in_ior_3_cb; + devcb_write8 m_out_iow_0_cb; + devcb_write8 m_out_iow_1_cb; + devcb_write8 m_out_iow_2_cb; + devcb_write8 m_out_iow_3_cb; + devcb_write_line m_out_dack_0_cb; + devcb_write_line m_out_dack_1_cb; + devcb_write_line m_out_dack_2_cb; + devcb_write_line m_out_dack_3_cb; + + + + + +}; + + +class upd71071_v53_device : public am9517a_device +{ +public: + // construction/destruction + upd71071_v53_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual DECLARE_READ8_MEMBER( read ); + virtual DECLARE_WRITE8_MEMBER( write ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + int m_selected_channel; + int m_base; + UINT8 m_command_high; + +}; + + + + +// device type definition +extern const device_type AM9517A; +extern const device_type V53_DMAU; + + +/*************************************************************************** + DEVICE CONFIGURATION MACROS +***************************************************************************/ + +#define MCFG_AM9517A_OUT_HREQ_CB(_devcb) \ + devcb = &am9517a_device::set_out_hreq_callback(*device, DEVCB_##_devcb); + +#define MCFG_AM9517A_OUT_EOP_CB(_devcb) \ + devcb = &am9517a_device::set_out_eop_callback(*device, DEVCB_##_devcb); + +#define MCFG_AM9517A_IN_MEMR_CB(_devcb) \ + devcb = &am9517a_device::set_in_memr_callback(*device, DEVCB_##_devcb); + +#define MCFG_AM9517A_OUT_MEMW_CB(_devcb) \ + devcb = &am9517a_device::set_out_memw_callback(*device, DEVCB_##_devcb); + +#define MCFG_AM9517A_IN_IOR_0_CB(_devcb) \ + devcb = &am9517a_device::set_in_ior_0_callback(*device, DEVCB_##_devcb); + +#define MCFG_AM9517A_IN_IOR_1_CB(_devcb) \ + devcb = &am9517a_device::set_in_ior_1_callback(*device, DEVCB_##_devcb); + +#define MCFG_AM9517A_IN_IOR_2_CB(_devcb) \ + devcb = &am9517a_device::set_in_ior_2_callback(*device, DEVCB_##_devcb); + +#define MCFG_AM9517A_IN_IOR_3_CB(_devcb) \ + devcb = &am9517a_device::set_in_ior_3_callback(*device, DEVCB_##_devcb); + +#define MCFG_AM9517A_OUT_IOW_0_CB(_devcb) \ + devcb = &am9517a_device::set_out_iow_0_callback(*device, DEVCB_##_devcb); + +#define MCFG_AM9517A_OUT_IOW_1_CB(_devcb) \ + devcb = &am9517a_device::set_out_iow_1_callback(*device, DEVCB_##_devcb); + +#define MCFG_AM9517A_OUT_IOW_2_CB(_devcb) \ + devcb = &am9517a_device::set_out_iow_2_callback(*device, DEVCB_##_devcb); + +#define MCFG_AM9517A_OUT_IOW_3_CB(_devcb) \ + devcb = &am9517a_device::set_out_iow_3_callback(*device, DEVCB_##_devcb); + +#define MCFG_AM9517A_OUT_DACK_0_CB(_devcb) \ + devcb = &am9517a_device::set_out_dack_0_callback(*device, DEVCB_##_devcb); + +#define MCFG_AM9517A_OUT_DACK_1_CB(_devcb) \ + devcb = &am9517a_device::set_out_dack_1_callback(*device, DEVCB_##_devcb); + +#define MCFG_AM9517A_OUT_DACK_2_CB(_devcb) \ + devcb = &am9517a_device::set_out_dack_2_callback(*device, DEVCB_##_devcb); + +#define MCFG_AM9517A_OUT_DACK_3_CB(_devcb) \ + devcb = &am9517a_device::set_out_dack_3_callback(*device, DEVCB_##_devcb); + +#define MCFG_I8237_OUT_HREQ_CB MCFG_AM9517A_OUT_HREQ_CB +#define MCFG_I8237_OUT_EOP_CB MCFG_AM9517A_OUT_EOP_CB +#define MCFG_I8237_IN_MEMR_CB MCFG_AM9517A_IN_MEMR_CB +#define MCFG_I8237_OUT_MEMW_CB MCFG_AM9517A_OUT_MEMW_CB +#define MCFG_I8237_IN_IOR_0_CB MCFG_AM9517A_IN_IOR_0_CB +#define MCFG_I8237_IN_IOR_1_CB MCFG_AM9517A_IN_IOR_1_CB +#define MCFG_I8237_IN_IOR_2_CB MCFG_AM9517A_IN_IOR_2_CB +#define MCFG_I8237_IN_IOR_3_CB MCFG_AM9517A_IN_IOR_3_CB +#define MCFG_I8237_OUT_IOW_0_CB MCFG_AM9517A_OUT_IOW_0_CB +#define MCFG_I8237_OUT_IOW_1_CB MCFG_AM9517A_OUT_IOW_1_CB +#define MCFG_I8237_OUT_IOW_2_CB MCFG_AM9517A_OUT_IOW_2_CB +#define MCFG_I8237_OUT_IOW_3_CB MCFG_AM9517A_OUT_IOW_3_CB +#define MCFG_I8237_OUT_DACK_0_CB MCFG_AM9517A_OUT_DACK_0_CB +#define MCFG_I8237_OUT_DACK_1_CB MCFG_AM9517A_OUT_DACK_1_CB +#define MCFG_I8237_OUT_DACK_2_CB MCFG_AM9517A_OUT_DACK_2_CB +#define MCFG_I8237_OUT_DACK_3_CB MCFG_AM9517A_OUT_DACK_3_CB + +#endif diff --git a/src/devices/machine/amigafdc.c b/src/devices/machine/amigafdc.c new file mode 100644 index 00000000000..0be33c07ec9 --- /dev/null +++ b/src/devices/machine/amigafdc.c @@ -0,0 +1,656 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +/*************************************************************************** + + Amiga floppy disk controller emulation + +***************************************************************************/ + + +#include "emu.h" +#include "includes/amiga.h" +#include "formats/ami_dsk.h" +#include "amigafdc.h" + +const device_type AMIGA_FDC = &device_creator; + +FLOPPY_FORMATS_MEMBER( amiga_fdc::floppy_formats ) + FLOPPY_ADF_FORMAT +FLOPPY_FORMATS_END + +amiga_fdc::amiga_fdc(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, AMIGA_FDC, "Amiga FDC", tag, owner, clock, "amiga_fdc", __FILE__), + m_write_index(*this) +{ +} + +void amiga_fdc::device_start() +{ + m_write_index.resolve_safe(); + + static const char *names[] = { "0", "1", "2", "3" }; + for(int i=0; i != 4; i++) { + floppy_connector *con = subdevice(names[i]); + if(con) + floppy_devices[i] = con->get_device(); + else + floppy_devices[i] = 0; + } + + floppy = 0; + + t_gen = timer_alloc(0); +} + + +void amiga_fdc::device_reset() +{ + floppy = 0; + dsklen = 0x4000; + dsksync = 0x4489; + adkcon = 0; + dmacon = 0; + dskpt = 0; + dskbyt = 0; + pre_dsklen = 0x4000; + dma_value = 0; + dma_state = DMA_IDLE; + + live_abort(); +} + +void amiga_fdc::dma_done() +{ + amiga_state *state = machine().driver_data(); + if(dskbyt & 0x2000) { + dskbyt &= ~0x2000; + cur_live.pll.stop_writing(floppy, cur_live.tm); + } + + dma_state = DMA_IDLE; + state->custom_chip_w(REG_INTREQ, INTENA_SETCLR | INTENA_DSKBLK); +} + +void amiga_fdc::dma_write(UINT16 value) +{ + amiga_state *state = machine().driver_data(); + state->chip_ram_w(dskpt, value); + + dskpt += 2; + dsklen--; + + if(dsklen & 0x3fff) + dma_state = DMA_RUNNING_BYTE_0; + else + dma_done(); +} + +UINT16 amiga_fdc::dma_read() +{ + amiga_state *state = machine().driver_data(); + UINT16 res = state->chip_ram_r(dskpt); + + dskpt += 2; + dsklen--; + + // This loses the last word. So does the real hardware. + if(dsklen & 0x3fff) + dma_state = DMA_RUNNING_BYTE_0; + else + dma_done(); + + return res; +} + +void amiga_fdc::live_start() +{ + cur_live.tm = machine().time(); + cur_live.state = RUNNING; + cur_live.next_state = -1; + cur_live.shift_reg = 0; + cur_live.bit_counter = 0; + cur_live.pll.reset(cur_live.tm); + cur_live.pll.set_clock(clocks_to_attotime(1)); + checkpoint_live = cur_live; + + live_run(); +} + +void amiga_fdc::checkpoint() +{ + cur_live.pll.commit(floppy, cur_live.tm); + checkpoint_live = cur_live; +} + +void amiga_fdc::rollback() +{ + cur_live = checkpoint_live; +} + +void amiga_fdc::live_delay(int state) +{ + cur_live.next_state = state; + if(cur_live.tm != machine().time()) + t_gen->adjust(cur_live.tm - machine().time()); +} + +void amiga_fdc::live_sync() +{ + if(!cur_live.tm.is_never()) { + if(cur_live.tm > machine().time()) { + rollback(); + live_run(machine().time()); + cur_live.pll.commit(floppy, cur_live.tm); + + } else { + cur_live.pll.commit(floppy, cur_live.tm); + + if(cur_live.next_state != -1) { + cur_live.state = cur_live.next_state; + cur_live.next_state = -1; + } + if(cur_live.state == IDLE) { + cur_live.pll.stop_writing(floppy, cur_live.tm); + cur_live.tm = attotime::never; + } + } + cur_live.next_state = -1; + checkpoint(); + } +} + +void amiga_fdc::live_abort() +{ + if(!cur_live.tm.is_never() && cur_live.tm > machine().time()) { + rollback(); + live_run(machine().time()); + } + + cur_live.pll.stop_writing(floppy, cur_live.tm); + cur_live.tm = attotime::never; + cur_live.state = IDLE; + cur_live.next_state = -1; +} + +void amiga_fdc::live_run(const attotime &limit) +{ + amiga_state *state = machine().driver_data(); + + if(cur_live.state == IDLE || cur_live.next_state != -1) + return; + + for(;;) { + switch(cur_live.state) { + case RUNNING: { + if(!(dskbyt & 0x2000)) { + int bit = cur_live.pll.get_next_bit(cur_live.tm, floppy, limit); + if(bit < 0) + return; + + cur_live.shift_reg = (cur_live.shift_reg << 1) | bit; + cur_live.bit_counter++; + + if((adkcon & 0x0200) && !(cur_live.shift_reg & 0x80)) { + cur_live.bit_counter--; + + // Avoid any risk of livelock + live_delay(RUNNING_SYNCPOINT); + return; + } + + if(cur_live.bit_counter > 8) + fatalerror("amiga_fdc::live_run - cur_live.bit_counter > 8\n"); + + if(cur_live.bit_counter == 8) { + live_delay(RUNNING_SYNCPOINT); + return; + } + if(dskbyt & 0x1000) { + if(cur_live.shift_reg != dsksync) { + live_delay(RUNNING_SYNCPOINT); + return; + } + } else { + if(cur_live.shift_reg == dsksync) { + live_delay(RUNNING_SYNCPOINT); + return; + } + } + } else { + int bit = (dma_state == DMA_RUNNING_BYTE_0 ? 15 : 7) - cur_live.bit_counter; + if(cur_live.pll.write_next_bit((dma_value >> bit) & 1, cur_live.tm, floppy, limit)) + return; + cur_live.bit_counter++; + if(cur_live.bit_counter > 8) + fatalerror("amiga_fdc::live_run - cur_live.bit_counter > 8\n"); + + if(cur_live.bit_counter == 8) { + live_delay(RUNNING_SYNCPOINT); + return; + } + } + break; + } + + case RUNNING_SYNCPOINT: { + if(!(dskbyt & 0x2000)) { + if(cur_live.shift_reg == dsksync) { + if(adkcon & 0x0400) { + if(dma_state == DMA_WAIT_START) { + cur_live.bit_counter = 0; + + if(!(dsklen & 0x3fff)) + dma_done(); + else if(dsklen & 0x4000) { + dskbyt |= 0x2000; + cur_live.bit_counter = 0; + dma_value = dma_read(); + + } else + dma_write(dsksync); + + } else if(dma_state != DMA_IDLE) { + dma_write(dsksync); + cur_live.bit_counter = 0; + + } else if(cur_live.bit_counter != 8) + cur_live.bit_counter = 0; + } + dskbyt |= 0x1000; + state->custom_chip_w(REG_INTREQ, INTENA_SETCLR | INTENA_DSKSYN); + } else + dskbyt &= ~0x1000; + + if(cur_live.bit_counter == 8) { + dskbyt = (dskbyt & 0xff00) | 0x8000 | (cur_live.shift_reg & 0xff); + cur_live.bit_counter = 0; + + switch(dma_state) { + case DMA_IDLE: + case DMA_WAIT_START: + break; + + case DMA_RUNNING_BYTE_0: + dma_value = (cur_live.shift_reg & 0xff) << 8; + dma_state = DMA_RUNNING_BYTE_1; + break; + + case DMA_RUNNING_BYTE_1: { + dma_value |= cur_live.shift_reg & 0xff; + dma_write(dma_value); + break; + } + } + } + } else { + if(cur_live.bit_counter != 8) + fatalerror("amiga_fdc::live_run - cur_live.bit_counter != 8\n"); + cur_live.bit_counter = 0; + + switch(dma_state) { + case DMA_IDLE: + case DMA_WAIT_START: + break; + + case DMA_RUNNING_BYTE_0: + dma_state = DMA_RUNNING_BYTE_1; + break; + + case DMA_RUNNING_BYTE_1: { + dma_value = dma_read(); + break; + } + } + } + + cur_live.state = RUNNING; + checkpoint(); + break; + } + } + } +} + +bool amiga_fdc::dma_enabled() +{ + return (dsklen & 0x8000) && ((dmacon & 0x0210) == 0x0210); +} + +void amiga_fdc::dma_check() +{ + bool was_writing = dskbyt & 0x2000; + dskbyt &= 0x9fff; + if(dma_enabled()) { + if(dma_state == IDLE) { + dma_state = adkcon & 0x0400 ? DMA_WAIT_START : DMA_RUNNING_BYTE_0; + if(dma_state == DMA_RUNNING_BYTE_0) { + if(!(dsklen & 0x3fff)) + dma_done(); + else if(dsklen & 0x4000) { + dskbyt |= 0x2000; + cur_live.bit_counter = 0; + dma_value = dma_read(); + } + } + } else { + dskbyt |= 0x4000; + if(dsklen & 0x4000) + dskbyt |= 0x2000; + } + } else + dma_state = IDLE; + + if(was_writing && !(dskbyt & 0x2000)) + cur_live.pll.stop_writing(floppy, cur_live.tm); + if(!was_writing && (dskbyt & 0x2000)) + cur_live.pll.start_writing(cur_live.tm); + +} + +void amiga_fdc::adkcon_set(UINT16 data) +{ + live_sync(); + adkcon = data; + live_run(); +} + +UINT16 amiga_fdc::adkcon_r(void) +{ + return adkcon; +} + +void amiga_fdc::dsklen_w(UINT16 data) +{ + live_sync(); + if(!(data & 0x8000) || (data == pre_dsklen)) { + dsklen = pre_dsklen = data; + dma_check(); + + } else + pre_dsklen = data; + live_run(); +} + +void amiga_fdc::dskpth_w(UINT16 data) +{ + live_sync(); + dskpt = (dskpt & 0xffff) | (data << 16); + live_run(); +} + +void amiga_fdc::dskptl_w(UINT16 data) +{ + live_sync(); + dskpt = (dskpt & 0xffff0000) | data; + live_run(); +} + +UINT16 amiga_fdc::dskpth_r() +{ + return dskpt >> 16; +} + +UINT16 amiga_fdc::dskptl_r() +{ + return dskpt; +} + +void amiga_fdc::dsksync_w(UINT16 data) +{ + live_sync(); + dsksync = data; + live_run(); +} + +void amiga_fdc::dmacon_set(UINT16 data) +{ + live_sync(); + dmacon = data; + dma_check(); + live_run(); +} + +UINT16 amiga_fdc::dskbytr_r() +{ + UINT16 res = dskbyt; + dskbyt &= 0x7fff; + return res; +} + +void amiga_fdc::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + live_sync(); + live_run(); +} + +void amiga_fdc::setup_leds() +{ + if(floppy) { + int drive = + floppy == floppy_devices[0] ? 0 : + floppy == floppy_devices[1] ? 1 : + floppy == floppy_devices[2] ? 2 : + 3; + + output_set_value("drive_0_led", drive == 0); + output_set_value("drive_1_led", drive == 1); + output_set_value("drive_2_led", drive == 2); + output_set_value("drive_3_led", drive == 3); + + set_led_status(machine(), 1, drive == 0); /* update internal drive led */ + set_led_status(machine(), 2, drive == 1); /* update external drive led */ + } +} + +WRITE8_MEMBER( amiga_fdc::ciaaprb_w ) +{ + floppy_image_device *old_floppy = floppy; + + live_sync(); + + if(!(data & 0x08)) + floppy = floppy_devices[0]; + else if(!(data & 0x10)) + floppy = floppy_devices[1]; + else if(!(data & 0x20)) + floppy = floppy_devices[2]; + else if(!(data & 0x40)) + floppy = floppy_devices[3]; + else + floppy = 0; + + if(old_floppy != floppy) { + if(old_floppy) + old_floppy->setup_index_pulse_cb(floppy_image_device::index_pulse_cb()); + if(floppy) + floppy->setup_index_pulse_cb(floppy_image_device::index_pulse_cb(FUNC(amiga_fdc::index_callback), this)); + } + + if(floppy) { + floppy->ss_w(!((data >> 2) & 1)); + floppy->dir_w((data >> 1) & 1); + floppy->stp_w(data & 1); + floppy->mon_w((data >> 7) & 1); + output_set_value("fdc_led", data & 0x80); // LED directly connected to FDC motor + } + + if(floppy) { + if(cur_live.state == IDLE) + live_start(); + } else + live_abort(); + + setup_leds(); + live_run(); +} + +UINT8 amiga_fdc::ciaapra_r() +{ + UINT8 ret = 0x3c; + if(floppy) { + //if(!floppy->ready_r()) fixit: seems to not work well with multiple disk drives + ret &= ~0x20; + if(!floppy->trk00_r()) + ret &= ~0x10; + if(floppy->wpt_r()) + ret &= ~0x08; + if(!floppy->dskchg_r()) + ret &= ~0x04; + } + + return ret; +} + +void amiga_fdc::index_callback(floppy_image_device *floppy, int state) +{ + /* Issue a index pulse when a disk revolution completes */ + m_write_index(!state); +} + +void amiga_fdc::pll_t::set_clock(const attotime &period) +{ + for(int i=0; i<38; i++) + delays[i] = period*(i+1); +} + +void amiga_fdc::pll_t::reset(const attotime &when) +{ + counter = 0; + increment = 146; + transition_time = 0xffff; + history = 0x80; + slot = 0; + ctime = when; + phase_add = 0x00; + phase_sub = 0x00; + freq_add = 0x00; + freq_sub = 0x00; +} + +int amiga_fdc::pll_t::get_next_bit(attotime &tm, floppy_image_device *floppy, const attotime &limit) +{ + attotime when = floppy ? floppy->get_next_transition(ctime) : attotime::never; + + for(;;) { + attotime etime = ctime+delays[slot]; + if(etime > limit) + return -1; + if(transition_time == 0xffff && !when.is_never() && etime >= when) + transition_time = counter; + if(slot < 8) { + UINT8 mask = 1 << slot; + if(phase_add & mask) + counter += 258; + else if(phase_sub & mask) + counter += 34; + else + counter += increment; + + if((freq_add & mask) && increment < 159) + increment++; + else if((freq_sub & mask) && increment > 134) + increment--; + } else + counter += increment; + + slot++; + tm = etime; + if(counter & 0x800) + break; + } + + int bit = transition_time != 0xffff; + + if(transition_time != 0xffff) { + static const UINT8 pha[8] = { 0xf, 0x7, 0x3, 0x1, 0, 0, 0, 0 }; + static const UINT8 phs[8] = { 0, 0, 0, 0, 0x1, 0x3, 0x7, 0xf }; + static const UINT8 freqa[4][8] = { + { 0xf, 0x7, 0x3, 0x1, 0, 0, 0, 0 }, + { 0x7, 0x3, 0x1, 0, 0, 0, 0, 0 }, + { 0x7, 0x3, 0x1, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0 } + }; + static const UINT8 freqs[4][8] = { + { 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0x1, 0x3, 0x7 }, + { 0, 0, 0, 0, 0, 0x1, 0x3, 0x7 }, + { 0, 0, 0, 0, 0x1, 0x3, 0x7, 0xf }, + }; + + int cslot = transition_time >> 8; + phase_add = pha[cslot]; + phase_sub = phs[cslot]; + int way = transition_time & 0x400 ? 1 : 0; + if(history & 0x80) + history = way ? 0x80 : 0x83; + else if(history & 0x40) + history = way ? history & 2 : (history & 2) | 1; + freq_add = freqa[history & 3][cslot]; + freq_sub = freqs[history & 3][cslot]; + history = way ? (history >> 1) | 2 : history >> 1; + + } else + phase_add = phase_sub = freq_add = freq_sub = 0; + + counter &= 0x7ff; + + ctime = tm; + transition_time = 0xffff; + slot = 0; + + return bit; +} + +void amiga_fdc::pll_t::start_writing(const attotime & tm) +{ + write_start_time = tm; + write_position = 0; +} + +void amiga_fdc::pll_t::stop_writing(floppy_image_device *floppy, const attotime &tm) +{ + commit(floppy, tm); + write_start_time = attotime::never; +} + +bool amiga_fdc::pll_t::write_next_bit(bool bit, attotime &tm, floppy_image_device *floppy, const attotime &limit) +{ + if(write_start_time.is_never()) { + write_start_time = ctime; + write_position = 0; + } + + for(;;) { + attotime etime = ctime+delays[slot]; + if(etime > limit) + return true; + UINT16 pre_counter = counter; + counter += increment; + if(bit && !(pre_counter & 0x400) && (counter & 0x400)) + if(write_position < ARRAY_LENGTH(write_buffer)) + write_buffer[write_position++] = etime; + slot++; + tm = etime; + if(counter & 0x800) + break; + } + + counter &= 0x7ff; + + ctime = tm; + slot = 0; + + return false; +} + + +void amiga_fdc::pll_t::commit(floppy_image_device *floppy, const attotime &tm) +{ + if(write_start_time.is_never() || tm == write_start_time) + return; + + if(floppy) + floppy->write_flux(write_start_time, tm, write_position, write_buffer); + write_start_time = tm; + write_position = 0; +} diff --git a/src/devices/machine/amigafdc.h b/src/devices/machine/amigafdc.h new file mode 100644 index 00000000000..77727d51a88 --- /dev/null +++ b/src/devices/machine/amigafdc.h @@ -0,0 +1,121 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +#ifndef AMIGAFDC_H +#define AMIGAFDC_H + +#include "emu.h" +#include "imagedev/floppy.h" + +#define MCFG_AMIGA_FDC_INDEX_CALLBACK(_write) \ + devcb = &amiga_fdc::set_index_wr_callback(*device, DEVCB_##_write); + +class amiga_fdc : public device_t { +public: + amiga_fdc(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + template static devcb_base &set_index_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_index.set_callback(object); } + + DECLARE_WRITE8_MEMBER(ciaaprb_w); + + UINT8 ciaapra_r(); + UINT16 dskbytr_r(); + UINT16 dskpth_r(); + UINT16 dskptl_r(); + + void dsksync_w(UINT16 data); + void dskpth_w(UINT16 data); + void dskptl_w(UINT16 data); + void dsklen_w(UINT16 data); + void adkcon_set(UINT16 data); + void dmacon_set(UINT16 data); + UINT16 adkcon_r(void); + + DECLARE_FLOPPY_FORMATS( floppy_formats ); + +protected: + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + +private: + // Running states + enum { + IDLE, + RUNNING, + RUNNING_SYNCPOINT + }; + + // DMA states + enum { + DMA_IDLE, + DMA_WAIT_START, + DMA_RUNNING_BYTE_0, + DMA_RUNNING_BYTE_1 + }; + + struct pll_t { + UINT16 counter; + UINT16 increment; + UINT16 transition_time; + UINT8 history; + UINT8 slot; + UINT8 phase_add, phase_sub, freq_add, freq_sub; + attotime ctime; + + attotime delays[38]; + + attotime write_start_time; + attotime write_buffer[32]; + int write_position; + + void set_clock(const attotime &period); + void reset(const attotime &when); + int get_next_bit(attotime &tm, floppy_image_device *floppy, const attotime &limit); + bool write_next_bit(bool bit, attotime &tm, floppy_image_device *floppy, const attotime &limit); + void start_writing(const attotime &tm); + void commit(floppy_image_device *floppy, const attotime &tm); + void stop_writing(floppy_image_device *floppy, const attotime &tm); + }; + + struct live_info { + attotime tm; + int state, next_state; + UINT16 shift_reg; + int bit_counter; + pll_t pll; + }; + + devcb_write_line m_write_index; + + floppy_image_device *floppy; + floppy_image_device *floppy_devices[4]; + + live_info cur_live, checkpoint_live; + + emu_timer *t_gen; + UINT16 dsklen, pre_dsklen, dsksync, dskbyt, adkcon, dmacon; + UINT32 dskpt; + UINT16 dma_value; + + int dma_state; + + void setup_leds(); + void index_callback(floppy_image_device *floppy, int state); + bool dma_enabled(); + void dma_check(); + void dma_done(); + void dma_write(UINT16 value); + UINT16 dma_read(); + + void live_start(); + void checkpoint(); + void rollback(); + void live_delay(int state); + void live_sync(); + void live_abort(); + void live_run(const attotime &limit = attotime::never); +}; + +extern const device_type AMIGA_FDC; + +#endif /* AMIGAFDC_H */ diff --git a/src/devices/machine/at28c16.c b/src/devices/machine/at28c16.c new file mode 100644 index 00000000000..e50049d9cbc --- /dev/null +++ b/src/devices/machine/at28c16.c @@ -0,0 +1,273 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/*************************************************************************** + ATMEL AT28C16 + + 16K ( 2K x 8 ) Parallel EEPROM + +***************************************************************************/ + +#include "emu.h" +#include "machine/at28c16.h" + +#define AT28C16_DATA_BYTES ( 0x800 ) +#define AT28C16_ID_BYTES ( 0x20 ) +#define AT28C16_TOTAL_BYTES ( AT28C16_DATA_BYTES + AT28C16_ID_BYTES ) + +#define AT28C16_ID_OFFSET ( AT28C16_DATA_BYTES - AT28C16_ID_BYTES ) + + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +static ADDRESS_MAP_START( at28c16_map8, AS_PROGRAM, 8, at28c16_device ) + AM_RANGE(0x0000, 0x081f) AM_RAM +ADDRESS_MAP_END + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +// device type definition +const device_type AT28C16 = &device_creator; + +//------------------------------------------------- +// at28c16_device - constructor +//------------------------------------------------- + +at28c16_device::at28c16_device( const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock ) + : device_t(mconfig, AT28C16, "AT28C16", tag, owner, clock, "at28c16", __FILE__), + device_memory_interface(mconfig, *this), + device_nvram_interface(mconfig, *this), + m_a9_12v( 0 ), + m_oe_12v( 0 ), + m_last_write( -1 ) +{ +} + + +//------------------------------------------------- +// device_config_complete - perform any +// operations now that the configuration is +// complete +//------------------------------------------------- + +void at28c16_device::device_config_complete() +{ + m_space_config = address_space_config( "at28c16", ENDIANNESS_BIG, 8, 12, 0, *ADDRESS_MAP_NAME( at28c16_map8 ) ); +} + + +//------------------------------------------------- +// device_validity_check - perform validity checks +// on this device +//------------------------------------------------- + +void at28c16_device::device_validity_check(validity_checker &valid) const +{ +} + + +//------------------------------------------------- +// memory_space_config - return a description of +// any address spaces owned by this device +//------------------------------------------------- + +const address_space_config *at28c16_device::memory_space_config( address_spacenum spacenum ) const +{ + return ( spacenum == 0 ) ? &m_space_config : NULL; +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void at28c16_device::device_start() +{ + m_write_timer = timer_alloc(0); + + save_item( NAME(m_a9_12v) ); + save_item( NAME(m_oe_12v) ); + save_item( NAME(m_last_write) ); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void at28c16_device::device_reset() +{ +} + + +//------------------------------------------------- +// nvram_default - called to initialize NVRAM to +// its default state +//------------------------------------------------- + +void at28c16_device::nvram_default() +{ + UINT16 default_value = 0xff; + for( offs_t offs = 0; offs < AT28C16_TOTAL_BYTES; offs++ ) + { + m_addrspace[ 0 ]->write_byte( offs, default_value ); + } + + /* populate from a memory region if present */ + if( m_region != NULL ) + { + if( m_region->bytes() != AT28C16_DATA_BYTES ) + { + fatalerror( "at28c16 region '%s' wrong size (expected size = 0x%X)\n", tag(), AT28C16_DATA_BYTES ); + } + + if( m_region->bytewidth() != 1 ) + { + fatalerror( "at28c16 region '%s' needs to be an 8-bit region\n", tag() ); + } + + UINT8 *default_data = m_region->base(); + + for( offs_t offs = 0; offs < AT28C16_DATA_BYTES; offs++ ) + m_addrspace[ 0 ]->write_byte( offs, default_data[offs] ); + } +} + + +//------------------------------------------------- +// nvram_read - called to read NVRAM from the +// .nv file +//------------------------------------------------- + +void at28c16_device::nvram_read( emu_file &file ) +{ + dynamic_buffer buffer( AT28C16_TOTAL_BYTES ); + + file.read( &buffer[0], AT28C16_TOTAL_BYTES ); + + for( offs_t offs = 0; offs < AT28C16_TOTAL_BYTES; offs++ ) + { + m_addrspace[ 0 ]->write_byte( offs, buffer[ offs ] ); + } +} + +//------------------------------------------------- +// nvram_write - called to write NVRAM to the +// .nv file +//------------------------------------------------- + +void at28c16_device::nvram_write( emu_file &file ) +{ + dynamic_buffer buffer ( AT28C16_TOTAL_BYTES ); + + for( offs_t offs = 0; offs < AT28C16_TOTAL_BYTES; offs++ ) + { + buffer[ offs ] = m_addrspace[ 0 ]->read_byte( offs ); + } + + file.write( &buffer[0], AT28C16_TOTAL_BYTES ); +} + + + +//************************************************************************** +// READ/WRITE HANDLERS +//************************************************************************** + +WRITE8_MEMBER( at28c16_device::write ) +{ + if( m_last_write >= 0 ) + { +// logerror( "%s: AT28C16: write( %04x, %02x ) busy\n", machine.describe_context(), offset, data ); + } + else if( m_oe_12v ) + { +// logerror( "%s: AT28C16: write( %04x, %02x ) erase\n", machine.describe_context(), offset, data ); + if( m_last_write < 0 ) + { + for( offs_t offs = 0; offs < AT28C16_TOTAL_BYTES; offs++ ) + { + m_addrspace[ 0 ]->write_byte( offs, 0xff ); + } + + m_last_write = 0xff; + m_write_timer->adjust( attotime::from_usec( 200 ) ); + } + } + else + { + if( m_a9_12v && offset >= AT28C16_ID_OFFSET ) + { + offset += AT28C16_ID_BYTES; + } + +// logerror( "%s: AT28C16: write( %04x, %02x )\n", machine.describe_context(), offset, data ); + if( m_last_write < 0 && m_addrspace[ 0 ]->read_byte( offset ) != data ) + { + m_addrspace[ 0 ]->write_byte( offset, data ); + m_last_write = data; + m_write_timer->adjust( attotime::from_usec( 200 ) ); + } + } +} + + +READ8_MEMBER( at28c16_device::read ) +{ + if( m_last_write >= 0 ) + { + UINT8 data = m_last_write ^ 0x80; +// logerror( "%s: AT28C16: read( %04x ) write status %02x\n", machine.describe_context(), offset, data ); + return data; + } + else + { + if( m_a9_12v && offset >= AT28C16_ID_OFFSET ) + { + offset += AT28C16_ID_BYTES; + } + + UINT8 data = m_addrspace[ 0 ]->read_byte( offset ); +// logerror( "%s: AT28C16: read( %04x ) data %02x\n", machine.describe_context(), offset, data ); + return data; + } +} + + +WRITE_LINE_MEMBER( at28c16_device::set_a9_12v ) +{ + state &= 1; + if( m_a9_12v != state ) + { +// logerror( "%s: AT28C16: set_a9_12v( %d )\n", machine.describe_context(), state ); + m_a9_12v = state; + } +} + + +WRITE_LINE_MEMBER( at28c16_device::set_oe_12v ) +{ + state &= 1; + if( m_oe_12v != state ) + { +// logerror( "%s: AT28C16: set_oe_12v( %d )\n", machine.describe_context(), state ); + m_oe_12v = state; + } +} + + +void at28c16_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch( id ) + { + case 0: + m_last_write = -1; + break; + } +} diff --git a/src/devices/machine/at28c16.h b/src/devices/machine/at28c16.h new file mode 100644 index 00000000000..f8f71011347 --- /dev/null +++ b/src/devices/machine/at28c16.h @@ -0,0 +1,74 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/*************************************************************************** + + ATMEL AT28C16 + + 16K ( 2K x 8 ) Parallel EEPROM + +***************************************************************************/ + +#pragma once + +#ifndef __AT28C16_H__ +#define __AT28C16_H__ + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_AT28C16_ADD( _tag, _interface ) \ + MCFG_DEVICE_ADD( _tag, AT28C16, 0 ) + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> at28c16_device + +class at28c16_device : + public device_t, + public device_memory_interface, + public device_nvram_interface +{ +public: + // construction/destruction + at28c16_device( const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock ); + + // I/O operations + DECLARE_WRITE8_MEMBER( write ); + DECLARE_READ8_MEMBER( read ); + DECLARE_WRITE_LINE_MEMBER( set_a9_12v ); + DECLARE_WRITE_LINE_MEMBER( set_oe_12v ); + +protected: + // device-level overrides + virtual void device_config_complete(); + virtual void device_validity_check(validity_checker &valid) const; + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config( address_spacenum spacenum = AS_0 ) const; + + // device_nvram_interface overrides + virtual void nvram_default(); + virtual void nvram_read( emu_file &file ); + virtual void nvram_write( emu_file &file ); + + // internal state + address_space_config m_space_config; + emu_timer *m_write_timer; + int m_a9_12v; + int m_oe_12v; + int m_last_write; +}; + + +// device type definition +extern const device_type AT28C16; + +#endif diff --git a/src/devices/machine/at29x.c b/src/devices/machine/at29x.c new file mode 100644 index 00000000000..440645b4c00 --- /dev/null +++ b/src/devices/machine/at29x.c @@ -0,0 +1,525 @@ +// license:BSD-3-Clause +// copyright-holders:Michael Zapf +/* + ATMEL AT29 family of Flash EEPROM + + References: + [1] ATMEL: 4-megabit (512K x 8) 5-volt Only 256-byte sector Flash Memory + [2] ATMEL: Programming Atmel's AT29 Flash Family + + + AT29 family + + Device Memory ID Sectors Sector Size Write Cycle Time Comments + ------------------------------------------------------------------------------------------ + AT29C256 32K x 8 DC 512 64 bytes 10 ms + AT29LV256 32K x 8 BC 512 64 bytes 20 ms + AT29C257 32K x 8 DC 512 64 bytes 10 ms + AT29C512 64K x 8 5D 512 128 bytes 10 ms + AT29LV512 64K x 8 3D 512 128 bytes 20 ms + AT29C010A 128K x 8 D5 1024 128 bytes 10 ms + AT29LV010A 128K x 8 35 1024 128 bytes 20 ms + AT29BV010A 128K x 8 35 1024 128 bytes 20 ms + AT29C1024 64K x 16 25 512 128 words 10 ms + AT29LV1024 64K x 16 26 512 128 words 20 ms + AT29C020 256K x 8 DA 1024 256 bytes 10 ms + AT29LV020 256K x 8 BA 1024 256 bytes 20 ms + AT29BV020 256K x 8 BA 1024 256 bytes 20 ms + AT29C040 512K x 8 5B 1024 512 bytes 10 ms Use AT29C040A for new designs + AT29LV040 512K x 8 3B 1024 512 bytes 20 ms Use AT29LV040A for new designs + AT29BV040 512K x 8 3B 1024 512 bytes 20 ms Use AT29BV040A for new designs + AT29C040A 512K x 8 A4 2048 256 bytes 10 ms + AT29LV040A 512K x 8 C4 2048 256 bytes 20 ms + AT29BV040A 512K x 8 C4 2048 256 bytes 20 ms + + TODO: Implement remaining variants + + MZ, Aug 2015 +*/ + +#include "at29x.h" + +#define TRACE_PRG 0 +#define TRACE_READ 0 +#define TRACE_WRITE 0 +#define TRACE_CONFIG 0 +#define TRACE_STATE 0 + +enum +{ + PRGTIMER = 1 +}; + +/* + Constructor for all variants +*/ + +at29x_device::at29x_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_nvram_interface(mconfig, *this), + m_memory_size(0), // bytes + m_word_width(8), + m_device_id(0), + m_sector_size(0), + m_cycle_time(10), // ms + m_boot_block_size(16*1024), + m_version(0) +{ +} + +/* + Constructor for AT29C020 +*/ +at29c020_device::at29c020_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : at29x_device(mconfig, AT29C020, "ATMEL 29C020 256K x 8 FEEPROM", tag, owner, clock, "at29c020", __FILE__) +{ + m_memory_size = 256*1024; + m_device_id = 0xda; + m_sector_size = 256; +} + +/* + Constructor for AT29C040 +*/ +at29c040_device::at29c040_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : at29x_device(mconfig, AT29C040, "ATMEL 29C040 512K x 8 FEEPROM", tag, owner, clock, "at29c040", __FILE__) +{ + m_memory_size = 512*1024; + m_device_id = 0x5b; + m_sector_size = 512; +} + +/* + Constructor for AT29C040A +*/ +at29c040a_device::at29c040a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : at29x_device(mconfig, AT29C040A, "ATMEL 29C040A 512K x 8 FEEPROM", tag, owner, clock, "at29c040a", __FILE__) +{ + m_memory_size = 512*1024; + m_device_id = 0xa4; + m_sector_size = 256; +} + + +//------------------------------------------------- +// nvram_default - called to initialize NVRAM to +// its default state +//------------------------------------------------- + +void at29x_device::nvram_default() +{ + memset(m_eememory, 0, m_memory_size+2); +} + +//------------------------------------------------- +// nvram_read - called to read NVRAM from the +// .nv file +//------------------------------------------------- + +void at29x_device::nvram_read(emu_file &file) +{ + file.read(m_eememory, m_memory_size+2); +} + +//------------------------------------------------- +// nvram_write - called to write NVRAM to the +// .nv file +//------------------------------------------------- + +void at29x_device::nvram_write(emu_file &file) +{ + // If we don't write (because there were no changes), the file will be wiped + if (TRACE_PRG) logerror("%s: Write to NVRAM file\n", tag()); + m_eememory[0] = m_version; + file.write(m_eememory, m_memory_size+2); +} + +/* + Programming timer callback +*/ +void at29x_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch (m_pgm) + { + case PGM_1: + // Programming cycle timeout + logerror("%s: Programming cycle timeout\n", tag()); + m_pgm = PGM_0; + break; + + case PGM_2: + // Programming cycle start + if (TRACE_PRG) logerror("%s: Sector write start\n", tag()); + m_pgm = PGM_3; + // We assume a typical delay of 70% of the max value + m_programming_timer->adjust(attotime::from_msec(m_cycle_time*7/10)); + break; + + case PGM_3: + // Programming cycle end; now burn the buffer into the flash EEPROM + memcpy(m_eememory + 2 + get_sector_number(m_programming_last_offset) * m_sector_size, m_programming_buffer, m_sector_size); + + if (TRACE_PRG) logerror("%s: Sector write completed at location %04x\n", tag(), m_programming_last_offset); + + // Data protect state will be activated at the end of the program cycle [1] + if (m_enabling_sdb) m_sdp = true; + + // Data protect state will be deactivated at the end of the program period [1] + if (m_disabling_sdb) m_sdp = false; + + if (TRACE_PRG) logerror("%s: Software data protection = %d\n", tag(), m_sdp); + + m_pgm = PGM_0; + m_enabling_sdb = false; + m_disabling_sdb = false; + sync_flags(); + break; + + default: + logerror("%s: Invalid state %d during programming\n", tag(), m_pgm); + m_pgm = PGM_0; + break; + } +} + +void at29x_device::sync_flags() +{ + if (m_lower_bbl) m_eememory[1] |= 0x04; + else m_eememory[1] &= ~0x04; + + if (m_higher_bbl) m_eememory[1] |= 0x02; + else m_eememory[1] &= ~0x02; + + if (m_sdp) m_eememory[1] |= 0x01; + else m_eememory[1] &= ~0x01; +} + +/* + read a byte from FEEPROM +*/ +READ8_MEMBER( at29x_device::read ) +{ + int reply; + + offset &= m_address_mask; + + // Reading in the midst of any command sequence cancels it (not verified) + m_cmd = CMD_0; + m_long_sequence = false; + + sync_flags(); + + // Reading before the start of a programming cycle cancels it (not verified) + if (m_pgm == PGM_1) + { + // Attempt to access a locked out boot block: cancel programming command if necessary + m_pgm = PGM_0; + m_enabling_sdb = false; + m_disabling_sdb = false; + m_programming_timer->adjust(attotime::never); + } + + if (m_id_mode) + { + // Experiments showed that the manufacturer code and device code + // are returned for every address 0 and 1 modulo sector_size. + // + if ((offset % m_sector_size)==0) reply = 0x1f; // Manufacturer code + else + { + if ((offset % m_sector_size)==1) reply = m_device_id; // Device code + else + { + // Boot block lockout detection [1] + if (offset == 0x00002) reply = m_lower_bbl? 0xff : 0xfe; + else + { + if (offset == 0x7fff2) reply = m_higher_bbl? 0xff : 0xfe; + else reply = 0; + } + } + } + } + else if ((m_pgm == PGM_2) || (m_pgm == PGM_3)) + { + if (m_pgm == PGM_2) + { + // DATA* polling starts the programming cycle (not verified) + m_pgm = PGM_3; + + // We assume a typical delay of 70% of the max value + m_programming_timer->adjust(attotime::from_msec(m_cycle_time*7/10)); + } + + if (TRACE_READ) logerror("%s: DATA poll; toggle bit 1\n", tag()); + reply = m_toggle_bit? 0x02 : 0x00; + m_toggle_bit = !m_toggle_bit; + + // When we read the byte on the last position, we get the inverse of the last bit [1] + if (offset == m_programming_last_offset) + { + reply |= ((~m_programming_buffer[m_programming_last_offset & m_sector_mask]) & 0x01); + } + } + else + // Simple case: just read the memory contents + reply = m_eememory[offset+2]; + + if (TRACE_READ) logerror("%s: %05x -> %02x (PGM=%d)\n", tag(), offset, reply, m_pgm); + + return reply; +} + +/* + Write a byte to FEEPROM +*/ +WRITE8_MEMBER( at29x_device::write ) +{ + offset &= m_address_mask; + if (TRACE_WRITE) logerror("%s: %05x <- %02x\n", tag(), offset, data); + + // The special CFI commands assume a smaller address space according + // to the specification ("address format A14-A0") + offs_t cfi_offset = offset & 0x7fff; + + if (m_enabling_bbl) + { + // Determine whether we lock the upper or lower boot block + if (TRACE_STATE) logerror("%s: Enabling boot block lockout\n", tag()); + m_enabling_bbl = false; + + if ((offset == 0x00000) && (data == 0x00)) + { + if (TRACE_STATE) logerror("%s: Enabling lower boot block lockout\n", tag()); + m_lower_bbl = true; + sync_flags(); + return; + } + else + { + if ((offset == 0x7ffff) && (data == 0xff)) + { + if (TRACE_STATE) logerror("%s: Enabling higher boot block lockout\n", tag()); + m_higher_bbl = true; + sync_flags(); + return; + } + else + { + logerror("%s: Invalid boot block specification: %05x/%02x\n", tag(), offset, data); + } + } + } + + switch (m_cmd) + { + case CMD_0: + // CMD_0: start state + if ((cfi_offset == 0x5555) && (data == 0xaa)) + { + if (TRACE_STATE) logerror("%s: Command sequence started (aa)\n", tag()); + m_cmd = CMD_1; + return; + } + else + { + m_cmd = CMD_0; + m_long_sequence = false; + } + break; + + case CMD_1: + // CMD_1: state after writing aa to 5555 + if ((cfi_offset == 0x2aaa) && (data == 0x55)) + { + if (TRACE_STATE) logerror("%s: Command sequence continued (55)\n", tag()); + m_cmd = CMD_2; + return; + } + else + { + m_cmd = CMD_0; + m_long_sequence = false; + if (TRACE_STATE) logerror("%s: Command sequence aborted\n", tag()); + } + break; + + case CMD_2: + // CMD_2: state after writing 55 to 2aaa + if (cfi_offset == 0x5555) + { + m_pgm = PGM_0; + m_enabling_sdb = false; + m_disabling_sdb = false; + m_programming_timer->adjust(attotime::never); + + // Process command + if (TRACE_STATE) logerror("%s: Command sequence continued (%2x)\n", tag(), data); + switch (data) + { + case 0x10: + // Software chip erase (optional feature, see [1]) + if (m_long_sequence) + { + if (m_lower_bbl || m_higher_bbl) + logerror("%s: Boot block lockout active; chip cannot be erased.\n", tag()); + else + { + if (TRACE_STATE) logerror("%s: Erase chip\n", tag()); + memset(m_eememory+2, 0xff, m_memory_size); + } + } + break; + + case 0x20: + // Software data protection disable + // The complete sequence is aa-55-80-aa-55-20 + // so we need a 80 before, else the sequence is invalid + if (m_long_sequence) + { + if (TRACE_STATE) logerror("%s: Software data protection disable\n", tag()); + m_pgm = PGM_1; + m_disabling_sdb = true; + // It is not clear from the specification whether the byte cycle timer + // is already started here or when the first data byte is written + } + break; + + case 0x40: + // Boot block lockout enable + // Complete sequence is aa-55-80-aa-55-40 + if (TRACE_STATE) logerror("%s: Boot block lockout enable\n", tag()); + if (m_long_sequence) m_enabling_bbl = true; + // We'll know which boot block is affected on the next write + break; + + case 0x80: + // Long sequences are those that contain aa55 twice + m_long_sequence = true; + break; + + case 0x90: + // Software product identification entry + if (TRACE_STATE) logerror("%s: Entering Identification mode\n", tag()); + m_id_mode = true; + break; + + case 0xa0: + // Software data protection enable + if (TRACE_STATE) logerror("%s: Software data protection enable\n", tag()); + m_pgm = PGM_1; + m_enabling_sdb = true; + // It is not clear from the specification whether the byte cycle timer + // is already started here or when the first data byte is written + break; + + case 0xf0: + // Software product identification exit + if (TRACE_STATE) logerror("%s: Exiting Identification mode\n", tag()); + m_id_mode = false; + break; + } + m_cmd = CMD_0; + if (data != 0x80) m_long_sequence = false; + + // Return, because we don't want to write the EEPROM with the command byte + return; + } + else + { + m_cmd = CMD_0; + m_long_sequence = false; + } + } + + if ((m_pgm == PGM_2) && (get_sector_number(offset) != get_sector_number(m_programming_last_offset))) + { + // cancel current programming cycle + if (TRACE_WRITE) logerror("%s: Invalid sector change (from sector 0x%04x to 0x%04x); cancel programming cycle\n", tag(), get_sector_number(m_programming_last_offset), get_sector_number(offset)); + m_pgm = PGM_0; + m_enabling_sdb = false; + m_disabling_sdb = false; + m_programming_timer->adjust(attotime::never); + } + + if (((m_pgm == PGM_0) && !m_sdp) // write directly + || (m_pgm == PGM_1)) // write after unlocking + { + if (((offset < m_boot_block_size) && m_lower_bbl) + || ((offset >= m_memory_size-m_boot_block_size) && m_higher_bbl)) + { + // attempt to access a locked out boot block: cancel programming + // command if necessary + if (TRACE_WRITE) logerror("%s: Attempt to access a locked out boot block: offset = %05x, lowblock=%d, highblock=%d\n", tag(), offset, m_lower_bbl, m_higher_bbl); + + m_pgm = PGM_0; + m_enabling_sdb = false; + m_disabling_sdb = false; + } + else + { // enter programming mode + if (TRACE_STATE) logerror("%s: Enter programming mode (m_pgm=%d, m_sdp=%d)\n", tag(), m_pgm, m_sdp); + // Clear the programming buffer + memset(m_programming_buffer, 0xff, m_sector_size); + m_pgm = PGM_2; + } + } + // TODO: If data protection is active and bytes are written, the device + // enters a dummy write mode + + if (m_pgm == PGM_2) + { + // write data to programming buffer + if (TRACE_PRG) logerror("%s: Write data to programming buffer: buf[%x] = %02x\n", tag(), offset & m_sector_mask, data); + m_programming_buffer[offset & m_sector_mask] = data; + m_programming_last_offset = offset; + m_programming_timer->adjust(attotime::from_usec(150)); // next byte must be written before the timer expires + } +} + +void at29x_device::device_start(void) +{ + m_programming_buffer = global_alloc_array(UINT8, m_sector_size); + m_eememory = global_alloc_array(UINT8, m_memory_size+2); + m_programming_timer = timer_alloc(PRGTIMER); + + // TODO: Complete 16-bit handling + m_address_mask = m_memory_size/(m_word_width/8) - 1; + m_sector_mask = m_sector_size - 1; +} + +void at29x_device::device_stop(void) +{ + global_free_array(m_programming_buffer); + global_free_array(m_eememory); +} + +void at29x_device::device_reset(void) +{ + if (m_eememory[0] != m_version) + { + logerror("%s: Warning: Version mismatch; expected %d but found %d in file. Resetting.\n", tag(), m_version, m_eememory[0]); + m_eememory[0] = 0; + m_eememory[1] = 0; + } + + m_lower_bbl = ((m_eememory[1] & 0x04)!=0); + m_higher_bbl = ((m_eememory[1] & 0x02)!=0); + m_sdp = ((m_eememory[1] & 0x01)!=0); + + if (TRACE_CONFIG) logerror("%s: LowerBBL = %d, HigherBBL = %d, SoftDataProt = %d\n", tag(), m_lower_bbl, m_higher_bbl, m_sdp); + + m_id_mode = false; + m_cmd = CMD_0; + m_enabling_bbl = false; + m_long_sequence = false; + m_pgm = PGM_0; + m_enabling_sdb = false; + m_disabling_sdb = false; + m_toggle_bit = false; + m_programming_last_offset = 0; +} + +const device_type AT29C020 = &device_creator; +const device_type AT29C040 = &device_creator; +const device_type AT29C040A = &device_creator; diff --git a/src/devices/machine/at29x.h b/src/devices/machine/at29x.h new file mode 100644 index 00000000000..91c81c585cf --- /dev/null +++ b/src/devices/machine/at29x.h @@ -0,0 +1,116 @@ +// license:BSD-3-Clause +// copyright-holders:Raphael Nabet, Michael Zapf +/* + ATMEL AT29 family + + Michael Zapf + August 2015 +*/ + +#ifndef __AT29X__ +#define __AT29X__ + +#include "emu.h" + +extern const device_type AT29C020; +extern const device_type AT29C040; +extern const device_type AT29C040A; + +enum s_cmd_t +{ + CMD_0 = 0, + CMD_1, + CMD_2 +}; + +enum s_pgm_t +{ + PGM_0 = 0, + PGM_1, + PGM_2, + PGM_3 +}; + +class at29x_device : public device_t, public device_nvram_interface +{ +public: + at29x_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + DECLARE_READ8_MEMBER( read ); + DECLARE_WRITE8_MEMBER( write ); + +protected: + virtual void device_start(void); + virtual void device_reset(void); + virtual void device_stop(void); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + void nvram_default(); + void nvram_read(emu_file &file); + void nvram_write(emu_file &file); + + int get_sector_number(offs_t address) { return address / m_sector_size; } + + int m_memory_size; // bytes + int m_word_width; + int m_device_id; + int m_sector_size; + int m_cycle_time; // ms + int m_boot_block_size; + int m_version; + int m_address_mask; + int m_sector_mask; + +private: + void sync_flags(void); + + UINT8* m_eememory; + + bool m_lower_bbl; // set when lower boot block lockout is enabled + bool m_higher_bbl; // set when upper boot block lockout is enabled + bool m_sdp; // set when in software data protect mode + + bool m_id_mode; // set when in chip id mode + s_cmd_t m_cmd; // command state + bool m_enabling_bbl; // set when a boot block lockout command is expecting its parameter + bool m_long_sequence; // set if 0x80 command has just been executed (some command require this prefix) + s_pgm_t m_pgm; // programming state + bool m_enabling_sdb; // set when a sdp enable command is in progress + bool m_disabling_sdb; // set when a sdp disable command is in progress + bool m_toggle_bit; // indicates flashing in progress (toggles for each query) + + UINT8* m_programming_buffer; + int m_programming_last_offset; + emu_timer* m_programming_timer; +}; + +/* + Variants +*/ +class at29c020_device : public at29x_device +{ +public: + at29c020_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class at29c040_device : public at29x_device +{ +public: + at29c040_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class at29c040a_device : public at29x_device +{ +public: + at29c040a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +#define MCFG_AT29C020_ADD(_tag ) \ + MCFG_DEVICE_ADD(_tag, AT29C020, 0) + +#define MCFG_AT29C040_ADD(_tag ) \ + MCFG_DEVICE_ADD(_tag, AT29C040, 0) + +#define MCFG_AT29C040A_ADD(_tag ) \ + MCFG_DEVICE_ADD(_tag, AT29C040A, 0) + +#endif diff --git a/src/devices/machine/at45dbxx.c b/src/devices/machine/at45dbxx.c new file mode 100644 index 00000000000..2890f8784d4 --- /dev/null +++ b/src/devices/machine/at45dbxx.c @@ -0,0 +1,388 @@ +// license:BSD-3-Clause +// copyright-holders:Tim Schuerewegen +/* + + Atmel Serial DataFlash + + (c) 2001-2007 Tim Schuerewegen + + AT45DB041 - 528 KByte + AT45DB081 - 1056 KByte + AT45DB161 - 2112 KByte + +*/ + +#include "at45dbxx.h" + +#define LOG_LEVEL 1 +#define _logerror(level,x) do { if (LOG_LEVEL > level) logerror x; } while (0) + +#define FLASH_CMD_52 0x52 +#define FLASH_CMD_57 0x57 +#define FLASH_CMD_60 0x60 +#define FLASH_CMD_82 0x82 + +#define FLASH_MODE_XX 0 // unknown +#define FLASH_MODE_SI 1 // input +#define FLASH_MODE_SO 2 // output + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +// device type definition +const device_type AT45DB041 = &device_creator; +const device_type AT45DB081 = &device_creator; +const device_type AT45DB161 = &device_creator; + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// at45db041_device - constructor +//------------------------------------------------- + +at45db041_device::at45db041_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, AT45DB041, "AT45DB041", tag, owner, clock, "at45db041", __FILE__), + device_nvram_interface(mconfig, *this), + write_so(*this) +{ +} + + +at45db041_device::at45db041_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_nvram_interface(mconfig, *this), + write_so(*this) +{ +} + + +at45db081_device::at45db081_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : at45db041_device(mconfig, AT45DB081, "AT45DB081", tag, owner, clock, "at45db081", __FILE__) +{ +} + + +at45db161_device::at45db161_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : at45db041_device(mconfig, AT45DB161, "AT45DB161", tag, owner, clock, "at45db161", __FILE__) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void at45db041_device::device_start() +{ + m_size = num_pages() * page_size(); + m_data.resize(m_size); + m_buffer1.resize(page_size()); + //m_buffer2.resize(page_size()); + + // pins + m_pin.cs = 0; + m_pin.sck = 0; + m_pin.si = 0; + m_pin.wp = 0; + m_pin.reset = 0; + m_pin.busy = 0; + + // data + save_item(NAME(m_data)); + // pins + save_item(NAME(m_pin.cs)); + save_item(NAME(m_pin.sck)); + save_item(NAME(m_pin.si)); + save_item(NAME(m_pin.so)); + save_item(NAME(m_pin.wp)); + save_item(NAME(m_pin.reset)); + save_item(NAME(m_pin.busy)); + + write_so.resolve_safe(); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void at45db041_device::device_reset() +{ + _logerror( 1, ("at45dbxx_reset\n")); + // mode + m_mode = FLASH_MODE_SI; + m_status = 0; + // command + memset(&m_cmd.data[0], 0, sizeof(m_cmd.data)); + m_cmd.size = 0; + // input/output + m_io.data = NULL; + m_io.size = 0; + m_io.pos = 0; + // pins + m_pin.so = 0; + // output + m_so_byte = 0; + m_so_bits = 0; + // input + m_si_byte = 0; + m_si_bits = 0; +} + + +//------------------------------------------------- +// nvram_default - called to initialize NVRAM to +// its default state +//------------------------------------------------- + +void at45db041_device::nvram_default() +{ + memset(&m_data[0], 0xff, m_data.size()); + + if (region() != NULL) + { + UINT32 bytes = region()->bytes(); + if (bytes > m_size) + bytes = m_size; + + memcpy(&m_data[0], region()->base(), bytes); + } +} + +//------------------------------------------------- +// nvram_read - called to read NVRAM from the +// .nv file +//------------------------------------------------- + +void at45db041_device::nvram_read(emu_file &file) +{ + file.read(&m_data[0], m_size); +} + +//------------------------------------------------- +// nvram_write - called to write NVRAM to the +// .nv file +//------------------------------------------------- + +void at45db041_device::nvram_write(emu_file &file) +{ + file.write(&m_data[0], m_size); +} + +UINT8 at45db041_device::read_byte() +{ + UINT8 data; + // check mode + if ((m_mode != FLASH_MODE_SO) || (!m_io.data)) return 0; + // read byte + data = m_io.data[m_io.pos++]; + _logerror( 2, ("at45dbxx_read_byte (%02X) (%03d/%03d)\n", data, m_io.pos, m_io.size)); + if (m_io.pos == m_io.size) m_io.pos = 0; + return data; +} + +void at45db041_device::flash_set_io(UINT8* data, UINT32 size, UINT32 pos) +{ + m_io.data = data; + m_io.size = size; + m_io.pos = pos; +} + +UINT32 at45db041_device::flash_get_page_addr() +{ + return ((m_cmd.data[1] & 0x0F) << 7) | ((m_cmd.data[2] & 0xFE) >> 1); +} + +UINT32 at45db041_device::flash_get_byte_addr() +{ + return ((m_cmd.data[2] & 0x01) << 8) | ((m_cmd.data[3] & 0xFF) >> 0); +} + +UINT32 at45db081_device::flash_get_page_addr() +{ + return ((m_cmd.data[1] & 0x1F) << 7) | ((m_cmd.data[2] & 0xFE) >> 1); +} + +UINT32 at45db161_device::flash_get_page_addr() +{ + return ((m_cmd.data[1] & 0x3F) << 6) | ((m_cmd.data[2] & 0xFC) >> 2); +} + +UINT32 at45db161_device::flash_get_byte_addr() +{ + return ((m_cmd.data[2] & 0x03) << 8) | ((m_cmd.data[3] & 0xFF) >> 0); +} + +void at45db041_device::write_byte(UINT8 data) +{ + // check mode + if (m_mode != FLASH_MODE_SI) return; + // process byte + if (m_cmd.size < 8) + { + UINT8 opcode; + _logerror( 2, ("at45dbxx_write_byte (%02X)\n", data)); + // add to command buffer + m_cmd.data[m_cmd.size++] = data; + // check opcode + opcode = m_cmd.data[0]; + switch (opcode) + { + // status register read + case FLASH_CMD_57 : + { + // 8 bits command + if (m_cmd.size == 1) + { + _logerror( 1, ("at45dbxx opcode %02X - status register read\n", opcode)); + m_status = (m_status & 0xC7) | device_id(); // 80 = busy / 40 = compare fail + flash_set_io(&m_status, 1, 0); + m_mode = FLASH_MODE_SO; + m_cmd.size = 8; + } + } + break; + // main memory page to buffer 1 compare + case FLASH_CMD_60 : + { + // 8 bits command + 4 bits reserved + 11 bits page address + 9 bits don't care + if (m_cmd.size == 4) + { + UINT32 page; + UINT8 comp; + page = flash_get_page_addr(); + _logerror( 1, ("at45dbxx opcode %02X - main memory page to buffer 1 compare [%04X]\n", opcode, page)); + comp = memcmp( &m_data[page * page_size()], &m_buffer1[0], page_size()) == 0 ? 0 : 1; + if (comp) m_status |= 0x40; else m_status &= ~0x40; + _logerror( 1, ("at45dbxx page compare %s\n", comp ? "failure" : "success")); + m_mode = FLASH_MODE_SI; + m_cmd.size = 8; + } + } + break; + // main memory page read + case FLASH_CMD_52 : + { + // 8 bits command + 4 bits reserved + 11 bits page address + 9 bits buffer address + 32 bits don't care + if (m_cmd.size == 8) + { + UINT32 page, byte; + page = flash_get_page_addr(); + byte = flash_get_byte_addr(); + _logerror( 1, ("at45dbxx opcode %02X - main memory page read [%04X/%04X]\n", opcode, page, byte)); + flash_set_io(&m_data[page * page_size()], page_size(), byte); + m_mode = FLASH_MODE_SO; + m_cmd.size = 8; + } + } + break; + // main memory page program through buffer 1 + case FLASH_CMD_82 : + { + // 8 bits command + 4 bits reserved + 11 bits page address + 9 bits buffer address + if (m_cmd.size == 4) + { + UINT32 page, byte; + page = flash_get_page_addr(); + byte = flash_get_byte_addr(); + _logerror( 1, ("at45dbxx opcode %02X - main memory page program through buffer 1 [%04X/%04X]\n",opcode, page, byte)); + flash_set_io(&m_buffer1[0], page_size(), byte); + memset(&m_buffer1[0], 0xff, m_buffer1.size()); + m_mode = FLASH_MODE_SI; + m_cmd.size = 8; + } + } + break; + // other + default : + { + _logerror( 1, ("at45dbxx opcode %02X - unknown\n", opcode)); + m_cmd.data[0] = 0; + m_cmd.size = 0; + } + break; + } + } + else + { + _logerror( 2, ("at45dbxx_write_byte (%02X) (%03d/%03d)\n", data, m_io.pos + 1, m_io.size)); + // store byte + m_io.data[m_io.pos] = data; + m_io.pos++; + if (m_io.pos == m_io.size) m_io.pos = 0; + } +} + +READ_LINE_MEMBER(at45db041_device::so_r) +{ + if (m_pin.cs == 0) return 0; + return m_pin.so; +} + +WRITE_LINE_MEMBER(at45db041_device::si_w) +{ + if (m_pin.cs == 0) return; + m_pin.si = state; +} + +WRITE_LINE_MEMBER(at45db041_device::cs_w) +{ + // check if changed + if (m_pin.cs == state) return; + // cs low-to-high + if (state != 0) + { + // complete program command + if ((m_cmd.size >= 4) && (m_cmd.data[0] == FLASH_CMD_82)) + { + UINT32 page, byte; + page = flash_get_page_addr(); + byte = flash_get_byte_addr(); + _logerror( 1, ("at45dbxx - program data stored in buffer 1 into selected page in main memory [%04X/%04X]\n", page, byte)); + memcpy( &m_data[page * page_size()], &m_buffer1[0], page_size()); + } + // reset + at45db041_device::device_reset(); + } + // save cs + m_pin.cs = state; +} + +WRITE_LINE_MEMBER(at45db041_device::sck_w) +{ + // check if changed + if (m_pin.sck == state) return; + // sck high-to-low + if (state == 0) + { + // output (part 1) + if (m_so_bits == 8) + { + m_so_bits = 0; + m_so_byte = read_byte(); + } + // output (part 2) + m_pin.so = (m_so_byte >> m_so_bits) & 1; + write_so(m_pin.so); + m_so_bits++; + } + else + { + // input + if (m_pin.si) m_si_byte = m_si_byte | (1 << m_si_bits); + m_si_bits++; + if (m_si_bits == 8) + { + m_si_bits = 0; + write_byte(m_si_byte); + m_si_byte = 0; + } + } + // save sck + m_pin.sck = state; +} diff --git a/src/devices/machine/at45dbxx.h b/src/devices/machine/at45dbxx.h new file mode 100644 index 00000000000..a1e41e88657 --- /dev/null +++ b/src/devices/machine/at45dbxx.h @@ -0,0 +1,152 @@ +// license:BSD-3-Clause +// copyright-holders:Tim Schuerewegen +/* + + Atmel Serial DataFlash + + (c) 2001-2007 Tim Schuerewegen + + AT45DB041 - 528 KByte + AT45DB081 - 1056 KByte + AT45DB161 - 2112 KByte + +*/ + +#ifndef _AT45DBXX_H_ +#define _AT45DBXX_H_ + +#include "emu.h" + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_AT45DB041_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, AT45DB041, 0) + +#define MCFG_AT45DB081_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, AT45DB081, 0) + +#define MCFG_AT45DB161_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, AT45DB161, 0) + +#define MCFG_AT45DBXXX_SO_CALLBACK(_cb) \ + devcb = &at45db041_device::set_so_cb(*device, DEVCB_##_cb); + + +// ======================> at45db041_device + +class at45db041_device : public device_t, + public device_nvram_interface +{ +public: + at45db041_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + at45db041_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + DECLARE_WRITE_LINE_MEMBER(cs_w); + DECLARE_WRITE_LINE_MEMBER(sck_w); + DECLARE_WRITE_LINE_MEMBER(si_w); + DECLARE_READ_LINE_MEMBER(so_r); + + UINT8 *get_ptr() { return &m_data[0]; } + + template static devcb_base &set_so_cb(device_t &device, _Object object) { return downcast(device).write_so.set_callback(object); } + devcb_write_line write_so; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_nvram_interface overrides + virtual void nvram_default(); + virtual void nvram_read(emu_file &file); + virtual void nvram_write(emu_file &file); + +protected: + virtual int num_pages() const { return 2048; } + virtual int page_size() const { return 264; } + virtual UINT8 device_id() const { return 0x18; } + + UINT8 read_byte(); + void flash_set_io(UINT8* data, UINT32 size, UINT32 pos); + virtual UINT32 flash_get_page_addr(); + virtual UINT32 flash_get_byte_addr(); + void write_byte(UINT8 data); + + // internal state + dynamic_buffer m_data; + UINT32 m_size; + UINT8 m_mode; + UINT8 m_status; + dynamic_buffer m_buffer1; + //dynamic_buffer m_buffer2; + UINT8 m_si_byte; + UINT8 m_si_bits; + UINT8 m_so_byte; + UINT8 m_so_bits; + + struct AT45DBXX_PINS + { + int cs; // chip select + int sck; // serial clock + int si; // serial input + int so; // serial output + int wp; // write protect + int reset; // reset + int busy; // busy + } m_pin; + + struct AT45DBXX_IO + { + UINT8 *data; + UINT32 size; + UINT32 pos; + } m_io; + + struct AT45DBXX_CMD + { + UINT8 data[8]; + UINT8 size; + } m_cmd; +}; + +// ======================> at45db081_device + +class at45db081_device : public at45db041_device +{ +public: + at45db081_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual int num_pages() const { return 4096; } + virtual int page_size() const { return 264; } + virtual UINT8 device_id() const { return 0x20; } + + virtual UINT32 flash_get_page_addr(); +}; + +// ======================> at45db161_device + +class at45db161_device : public at45db041_device +{ +public: + at45db161_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual int num_pages() const { return 4096; } + virtual int page_size() const { return 528; } + virtual UINT8 device_id() const { return 0x28; } + + virtual UINT32 flash_get_page_addr(); + virtual UINT32 flash_get_byte_addr(); +}; + + +// device type definition +extern const device_type AT45DB041; +extern const device_type AT45DB081; +extern const device_type AT45DB161; + +#endif diff --git a/src/devices/machine/at_keybc.c b/src/devices/machine/at_keybc.c new file mode 100644 index 00000000000..a2930d627f9 --- /dev/null +++ b/src/devices/machine/at_keybc.c @@ -0,0 +1,226 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +/*************************************************************************** + + IBM PC AT compatibles 8042 keyboard controller + +***************************************************************************/ + +#include "emu.h" +#include "at_keybc.h" +#include "cpu/mcs48/mcs48.h" + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type AT_KEYBOARD_CONTROLLER = &device_creator; + +// i/o map for the 8042 +static ADDRESS_MAP_START( at_keybc_io, AS_IO, 8, at_keyboard_controller_device) + AM_RANGE(MCS48_PORT_T0, MCS48_PORT_T0) AM_READ(t0_r) + AM_RANGE(MCS48_PORT_T1, MCS48_PORT_T1) AM_READ(t1_r) + AM_RANGE(MCS48_PORT_P1, MCS48_PORT_P1) AM_READ( p1_r) + AM_RANGE(MCS48_PORT_P2, MCS48_PORT_P2) AM_READWRITE(p2_r, p2_w) +ADDRESS_MAP_END + +static INPUT_PORTS_START( at_keybc ) + PORT_START("DSW") + PORT_BIT( 0xbf, 0xbf, IPT_UNUSED ) + PORT_DIPNAME( 0x40, 0x00, "Display switch") + PORT_DIPSETTING( 0x40, "Monochrome adapter" ) + PORT_DIPSETTING( 0x00, "Color/Graphics adapter" ) +INPUT_PORTS_END + +// machine fragment +static MACHINE_CONFIG_FRAGMENT( at_keybc ) + MCFG_CPU_ADD("at_keybc", I8042, DERIVED_CLOCK(1,1)) + MCFG_CPU_IO_MAP(at_keybc_io) +MACHINE_CONFIG_END + +// rom definition for the 8042 internal rom +ROM_START( at_keybc ) + ROM_REGION(0x800, "at_keybc", 0) + + // unknown controller bios, (c) 1985, 1986 PTL + ROM_LOAD("yan25d05.bin", 0x000, 0x800, CRC(70c798f1) SHA1(ae9a79c7184a17331b70a50035ff63c757df094c)) + + // 1983 ibm controller bios + ROM_LOAD("1503033.bin", 0x000, 0x800, CRC(5a81c0d2) SHA1(0100f8789fb4de74706ae7f9473a12ec2b9bd729)) +ROM_END + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// at_keyboard_controller_device - constructor +//------------------------------------------------- + +at_keyboard_controller_device::at_keyboard_controller_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, AT_KEYBOARD_CONTROLLER, "AT Keyboard Controller", tag, owner, clock, "at_keybc", __FILE__), + m_cpu(NULL), + m_system_reset_cb(*this), + m_gate_a20_cb(*this), + m_input_buffer_full_cb(*this), + m_output_buffer_empty_cb(*this), + m_keyboard_clock_cb(*this), + m_keyboard_data_cb(*this) +{ +} + +//------------------------------------------------- +// rom_region - return a pointer to the device's +// internal ROM region +//------------------------------------------------- + +const rom_entry *at_keyboard_controller_device::device_rom_region() const +{ + return ROM_NAME(at_keybc); +} + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor at_keyboard_controller_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( at_keybc ); +} + +//------------------------------------------------- +// machine_config_additions - return a pointer to +// the device's machine fragment +//------------------------------------------------- + +machine_config_constructor at_keyboard_controller_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME(at_keybc); +} + +/*------------------------------------------------- + device_start - device-specific startup +-------------------------------------------------*/ + +void at_keyboard_controller_device::device_start() +{ + // find our cpu + m_cpu = downcast(subdevice("at_keybc")); + + // resolve callbacks + m_system_reset_cb.resolve_safe(); + m_gate_a20_cb.resolve_safe(); + m_input_buffer_full_cb.resolve_safe(); + m_output_buffer_empty_cb.resolve_safe(); + m_keyboard_clock_cb.resolve_safe(); + m_keyboard_data_cb.resolve_safe(); + + // register for save states + save_item(NAME(m_clock_signal)); + save_item(NAME(m_data_signal)); +} + +/*------------------------------------------------- + device_reset - device-specific reset +-------------------------------------------------*/ + +void at_keyboard_controller_device::device_reset() +{ +} + + +//************************************************************************** +// INTERNAL 8042 READ/WRITE HANDLERS +//************************************************************************** + +READ8_MEMBER( at_keyboard_controller_device::t0_r ) +{ + return m_clock_signal; +} + +READ8_MEMBER( at_keyboard_controller_device::t1_r ) +{ + return m_data_signal; +} + +/* + Port 1 (Input port) + 0 - P10 - Undefined + 1 - P11 - Undefined + 2 - P12 - Undefined + 3 - P13 - Undefined + 4 - P14 - External RAM (1 = Enable external RAM, 0 = Disable external RAM) + 5 - P15 - Manufacturing setting (1 = Setting enabled, 0 = Setting disabled) + 6 - P16 - Display type switch (1 = Monochrome display, 0 = Color display) + 7 - P17 - Keyboard inhibit switch (1 = Keyboard enabled, 0 = Keyboard inhibited) +*/ +READ8_MEMBER( at_keyboard_controller_device::p1_r ) +{ + return ioport("DSW")->read(); +} + +READ8_MEMBER( at_keyboard_controller_device::p2_r ) +{ + return 0xff; +} + +/* + Port 2 (Output port) + 0 - P20 - System Reset (1 = Normal, 0 = Reset computer) + 1 - P21 - Gate A20 + 2 - P22 - Undefined + 3 - P23 - Undefined + 4 - P24 - Input Buffer Full + 5 - P25 - Output Buffer Empty + 6 - P26 - Keyboard Clock (1 = Pull Clock low, 0 = High-Z) + 7 - P27 - Keyboard Data (1 = Pull Data low, 0 = High-Z) +*/ +WRITE8_MEMBER( at_keyboard_controller_device::p2_w ) +{ + m_system_reset_cb(BIT(data, 0) ? CLEAR_LINE : ASSERT_LINE); + m_gate_a20_cb(BIT(data, 1) ? ASSERT_LINE : CLEAR_LINE); + m_input_buffer_full_cb(BIT(data, 4) ? ASSERT_LINE : CLEAR_LINE); + m_output_buffer_empty_cb(BIT(data, 5) ? ASSERT_LINE : CLEAR_LINE); + + m_clock_signal = !BIT(data, 6); + m_data_signal = BIT(data, 7); + + m_keyboard_data_cb(m_data_signal); + m_keyboard_clock_cb(m_clock_signal); +} + + +//************************************************************************** +// READ/WRITE HANDLERS +//************************************************************************** + +READ8_MEMBER( at_keyboard_controller_device::data_r ) +{ + return m_cpu->upi41_master_r(space, 0); +} + +WRITE8_MEMBER( at_keyboard_controller_device::data_w ) +{ + m_cpu->upi41_master_w(space, 0, data); +} + +READ8_MEMBER( at_keyboard_controller_device::status_r ) +{ + return m_cpu->upi41_master_r(space, 1); +} + +WRITE8_MEMBER( at_keyboard_controller_device::command_w ) +{ + m_cpu->upi41_master_w(space, 1, data); +} + +WRITE_LINE_MEMBER( at_keyboard_controller_device::keyboard_clock_w ) +{ + m_clock_signal = state; +} + +WRITE_LINE_MEMBER( at_keyboard_controller_device::keyboard_data_w ) +{ + m_data_signal = state; +} diff --git a/src/devices/machine/at_keybc.h b/src/devices/machine/at_keybc.h new file mode 100644 index 00000000000..2051071da5f --- /dev/null +++ b/src/devices/machine/at_keybc.h @@ -0,0 +1,108 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +/*************************************************************************** + + IBM PC AT compatibles 8042 keyboard controller + +***************************************************************************/ + +#pragma once + +#ifndef __AT_KEYBC_H__ +#define __AT_KEYBC_H__ + +#include "emu.h" +#include "cpu/mcs48/mcs48.h" + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_AT_KEYBOARD_CONTROLLER_SYSTEM_RESET_CB(_devcb) \ + devcb = &at_keyboard_controller_device::set_system_reset_callback(*device, DEVCB_##_devcb); + +#define MCFG_AT_KEYBOARD_CONTROLLER_GATE_A20_CB(_devcb) \ + devcb = &at_keyboard_controller_device::set_gate_a20_callback(*device, DEVCB_##_devcb); + +#define MCFG_AT_KEYBOARD_CONTROLLER_INPUT_BUFFER_FULL_CB(_devcb) \ + devcb = &at_keyboard_controller_device::set_input_buffer_full_callback(*device, DEVCB_##_devcb); + +#define MCFG_AT_KEYBOARD_CONTROLLER_OUTPUT_BUFFER_EMPTY_CB(_devcb) \ + devcb = &at_keyboard_controller_device::set_output_buffer_empty_callback(*device, DEVCB_##_devcb); + +#define MCFG_AT_KEYBOARD_CONTROLLER_KEYBOARD_CLOCK_CB(_devcb) \ + devcb = &at_keyboard_controller_device::set_keyboard_clock_callback(*device, DEVCB_##_devcb); + +#define MCFG_AT_KEYBOARD_CONTROLLER_KEYBOARD_DATA_CB(_devcb) \ + devcb = &at_keyboard_controller_device::set_keyboard_data_callback(*device, DEVCB_##_devcb); + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> at_keyboard_controller_device + +class at_keyboard_controller_device : public device_t +{ +public: + // construction/destruction + at_keyboard_controller_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + template static devcb_base &set_system_reset_callback(device_t &device, _Object object) { return downcast(device).m_system_reset_cb.set_callback(object); } + template static devcb_base &set_gate_a20_callback(device_t &device, _Object object) { return downcast(device).m_gate_a20_cb.set_callback(object); } + template static devcb_base &set_input_buffer_full_callback(device_t &device, _Object object) { return downcast(device).m_input_buffer_full_cb.set_callback(object); } + template static devcb_base &set_output_buffer_empty_callback(device_t &device, _Object object) { return downcast(device).m_output_buffer_empty_cb.set_callback(object); } + template static devcb_base &set_keyboard_clock_callback(device_t &device, _Object object) { return downcast(device).m_keyboard_clock_cb.set_callback(object); } + template static devcb_base &set_keyboard_data_callback(device_t &device, _Object object) { return downcast(device).m_keyboard_data_cb.set_callback(object); } + + // internal 8042 interface + DECLARE_READ8_MEMBER( t0_r ); + DECLARE_READ8_MEMBER( t1_r ); + DECLARE_READ8_MEMBER( p1_r ); + DECLARE_READ8_MEMBER( p2_r ); + DECLARE_WRITE8_MEMBER( p2_w ); + + // interface to the host pc + DECLARE_READ8_MEMBER( data_r ); + DECLARE_WRITE8_MEMBER( data_w ); + DECLARE_READ8_MEMBER( status_r ); + DECLARE_WRITE8_MEMBER( command_w ); + + // interface to the keyboard + DECLARE_WRITE_LINE_MEMBER( keyboard_clock_w ); + DECLARE_WRITE_LINE_MEMBER( keyboard_data_w ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + virtual const rom_entry *device_rom_region() const; + virtual ioport_constructor device_input_ports() const; + virtual machine_config_constructor device_mconfig_additions() const; + +private: + // internal state + upi41_cpu_device *m_cpu; + + // interface to the host pc + devcb_write_line m_system_reset_cb; + devcb_write_line m_gate_a20_cb; + devcb_write_line m_input_buffer_full_cb; + devcb_write_line m_output_buffer_empty_cb; + + // interface to the keyboard + devcb_write_line m_keyboard_clock_cb; + devcb_write_line m_keyboard_data_cb; + + UINT8 m_clock_signal; + UINT8 m_data_signal; +}; + + +// device type definition +extern const device_type AT_KEYBOARD_CONTROLLER; + + +#endif /* __AT_KEYBC__ */ diff --git a/src/devices/machine/atadev.c b/src/devices/machine/atadev.c new file mode 100644 index 00000000000..691ffe7562f --- /dev/null +++ b/src/devices/machine/atadev.c @@ -0,0 +1,21 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/*************************************************************************** + + ATA Device implementation. + +***************************************************************************/ + +#include "atadev.h" + +//------------------------------------------------- +// ata_device_interface - constructor +//------------------------------------------------- + +ata_device_interface::ata_device_interface(const machine_config &mconfig, device_t &device) : + m_irq_handler(device), + m_dmarq_handler(device), + m_dasp_handler(device), + m_pdiag_handler(device) +{ +} diff --git a/src/devices/machine/atadev.h b/src/devices/machine/atadev.h new file mode 100644 index 00000000000..3b96a6b580c --- /dev/null +++ b/src/devices/machine/atadev.h @@ -0,0 +1,44 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/*************************************************************************** + + atadev.h + + ATA Device implementation. + +***************************************************************************/ + +#pragma once + +#ifndef __ATADEV_H__ +#define __ATADEV_H__ + +#include "emu.h" + +// ======================> ata_device_interface + +class ata_device_interface +{ +public: + ata_device_interface(const machine_config &mconfig, device_t &device); + virtual ~ata_device_interface() {} + + virtual UINT16 read_dma() = 0; + virtual DECLARE_READ16_MEMBER(read_cs0) = 0; + virtual DECLARE_READ16_MEMBER(read_cs1) = 0; + + virtual void write_dma(UINT16 data) = 0; + virtual DECLARE_WRITE16_MEMBER(write_cs0) = 0; + virtual DECLARE_WRITE16_MEMBER(write_cs1) = 0; + virtual DECLARE_WRITE_LINE_MEMBER(write_dmack) = 0; + virtual DECLARE_WRITE_LINE_MEMBER(write_csel) = 0; + virtual DECLARE_WRITE_LINE_MEMBER(write_dasp) = 0; + virtual DECLARE_WRITE_LINE_MEMBER(write_pdiag) = 0; + + devcb_write_line m_irq_handler; + devcb_write_line m_dmarq_handler; + devcb_write_line m_dasp_handler; + devcb_write_line m_pdiag_handler; +}; + +#endif diff --git a/src/devices/machine/ataflash.c b/src/devices/machine/ataflash.c new file mode 100644 index 00000000000..914ba2bcc65 --- /dev/null +++ b/src/devices/machine/ataflash.c @@ -0,0 +1,209 @@ +// license:BSD-3-Clause +// copyright-holders:smf +#include "ataflash.h" + +#define IDE_COMMAND_TAITO_GNET_UNLOCK_1 0xfe +#define IDE_COMMAND_TAITO_GNET_UNLOCK_2 0xfc +#define IDE_COMMAND_TAITO_GNET_UNLOCK_3 0x0f + +const device_type ATA_FLASH_PCCARD = &device_creator; + +ata_flash_pccard_device::ata_flash_pccard_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + ide_hdd_device(mconfig, ATA_FLASH_PCCARD, "ATA Flash PCCARD", tag, owner, clock, "ataflash", __FILE__) +{ +} + +void ata_flash_pccard_device::device_start() +{ + ide_hdd_device::device_start(); + + save_item(NAME(m_locked)); + save_item(NAME(m_gnetreadlock)); +} + +void ata_flash_pccard_device::device_reset() +{ + ide_hdd_device::device_reset(); + + UINT32 metalength; + memset(m_key, 0, sizeof(m_key)); + memset(m_cis, 0xff, 512); + + if (m_handle != NULL) + { + m_handle->read_metadata(PCMCIA_CIS_METADATA_TAG, 0, m_cis, 512, metalength); + + if (m_handle->read_metadata(HARD_DISK_KEY_METADATA_TAG, 0, m_key, 5, metalength) == CHDERR_NONE) + { + m_locked = 0x1ff; + m_gnetreadlock = 1; + } + } +} + +READ16_MEMBER( ata_flash_pccard_device::read_memory ) +{ + if(offset <= 7) + { + m_8bit_data_transfers = !ACCESSING_BITS_8_15; // HACK + return read_cs0(space, offset, mem_mask); + } + else if(offset <= 15) + { + return read_cs1(space, offset & 7, mem_mask); + } + else + { + return 0xffff; + } +} + +WRITE16_MEMBER( ata_flash_pccard_device::write_memory ) +{ + if(offset <= 7) + { + m_8bit_data_transfers = !ACCESSING_BITS_8_15; // HACK + write_cs0(space, offset, data, mem_mask); + } + else if( offset <= 15) + { + write_cs1(space, offset & 7, data, mem_mask); + } +} + +READ16_MEMBER( ata_flash_pccard_device::read_reg ) +{ + if(offset < 0x100) + return m_cis[offset]; + + switch(offset) + { + case 0x100: + return 0x0041; + + case 0x101: + return 0x0080; + + case 0x102: + return 0x002e; + + case 0x201: + return m_gnetreadlock; + + default: + return 0; + } +} + +WRITE16_MEMBER( ata_flash_pccard_device::write_reg ) +{ + if(offset >= 0x280 && offset <= 0x288 && m_handle != NULL) + { + UINT8 v = data; + int pos = offset - 0x280; + UINT8 k = pos < sizeof(m_key) ? m_key[pos] : 0; + + if(v == k) + { + m_locked &= ~(1 << pos); + } + else + { + m_locked |= 1 << pos; + } + + if (!m_locked) + { + m_gnetreadlock = 0; + } + } +} + +bool ata_flash_pccard_device::is_ready() +{ + return !m_gnetreadlock; +} + +void ata_flash_pccard_device::process_command() +{ + m_buffer_size = IDE_DISK_SECTOR_SIZE; + + switch (m_command) + { + case IDE_COMMAND_TAITO_GNET_UNLOCK_1: + //LOGPRINT(("IDE GNET Unlock 1\n")); + + m_sector_count = 1; + m_status |= IDE_STATUS_DRDY; + + set_irq(ASSERT_LINE); + break; + + case IDE_COMMAND_TAITO_GNET_UNLOCK_2: + //LOGPRINT(("IDE GNET Unlock 2\n")); + + /* mark the buffer ready */ + m_status |= IDE_STATUS_DRQ; + + set_irq(ASSERT_LINE); + break; + + case IDE_COMMAND_TAITO_GNET_UNLOCK_3: + //LOGPRINT(("IDE GNET Unlock 3\n")); + + /* key check */ + if (m_feature == m_key[0] && m_sector_count == m_key[1] && m_sector_number == m_key[2] && m_cylinder_low == m_key[3] && m_cylinder_high == m_key[4]) + { + m_gnetreadlock = 0; + } + else + { + m_status &= ~IDE_STATUS_DRDY; + } + + set_irq(ASSERT_LINE); + break; + + default: + if (m_gnetreadlock) + { + m_status |= IDE_STATUS_ERR; + m_error = IDE_ERROR_NONE; + m_status &= ~IDE_STATUS_DRDY; + break; + } + + ide_hdd_device::process_command(); + break; + } +} + +void ata_flash_pccard_device::process_buffer() +{ + if (m_command == IDE_COMMAND_TAITO_GNET_UNLOCK_2) + { + int i, bad = 0; + + for (i=0; !bad && i<512; i++) + bad = ((i < 2 || i >= 7) && m_buffer[i]) || ((i >= 2 && i < 7) && m_buffer[i] != m_key[i-2]); + + if (bad) + { + m_status |= IDE_STATUS_ERR; + m_error = IDE_ERROR_NONE; + } + else + { + m_gnetreadlock= 0; + } + } + else + { + ide_hdd_device::process_buffer(); + } +} + +attotime ata_flash_pccard_device::seek_time() +{ + return attotime::zero; +} diff --git a/src/devices/machine/ataflash.h b/src/devices/machine/ataflash.h new file mode 100644 index 00000000000..3bfd198f1af --- /dev/null +++ b/src/devices/machine/ataflash.h @@ -0,0 +1,41 @@ +// license:BSD-3-Clause +// copyright-holders:smf +#pragma once + +#ifndef __ATAFLASH_H__ +#define __ATAFLASH_H__ + +#include "pccard.h" +#include "machine/idehd.h" + +extern const device_type ATA_FLASH_PCCARD; + +class ata_flash_pccard_device : public ide_hdd_device, + public pccard_interface +{ +public: + ata_flash_pccard_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual DECLARE_READ16_MEMBER(read_memory); + virtual DECLARE_WRITE16_MEMBER(write_memory); + virtual DECLARE_READ16_MEMBER(read_reg); + virtual DECLARE_WRITE16_MEMBER(write_reg); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + virtual attotime seek_time(); + virtual void process_command(); + virtual void process_buffer(); + virtual bool is_ready(); + +private: + UINT8 m_cis[512]; + UINT8 m_key[5]; + UINT8 m_gnetreadlock; + int m_locked; +}; + +#endif diff --git a/src/devices/machine/atahle.c b/src/devices/machine/atahle.c new file mode 100644 index 00000000000..3a1599a3eed --- /dev/null +++ b/src/devices/machine/atahle.c @@ -0,0 +1,950 @@ +// license:BSD-3-Clause +// copyright-holders:smf +#include "atahle.h" + +#define VERBOSE 0 +#define PRINTF_IDE_COMMANDS 0 + +#define LOG(x) do { if (VERBOSE) logerror x; } while (0) +#define LOGPRINT(x) do { if (VERBOSE) logerror x; if (PRINTF_IDE_COMMANDS) osd_printf_debug x; } while (0) + +enum +{ + IDE_CS0_DATA_RW = 0, + IDE_CS0_ERROR_R = 1, + IDE_CS0_FEATURE_W = 1, + IDE_CS0_SECTOR_COUNT_RW = 2, + IDE_CS0_SECTOR_NUMBER_RW = 3, + IDE_CS0_CYLINDER_LOW_RW = 4, + IDE_CS0_CYLINDER_HIGH_RW = 5, + IDE_CS0_DEVICE_HEAD_RW = 6, + IDE_CS0_STATUS_R = 7, + IDE_CS0_COMMAND_W = 7 +}; + +enum +{ + IDE_CS1_ALTERNATE_STATUS_R = 6, + IDE_CS1_DEVICE_CONTROL_W = 6, + IDE_CS1_ACTIVE_STATUS = 7 +}; + +enum +{ + IDE_DEVICE_CONTROL_NIEN = 0x02, + IDE_DEVICE_CONTROL_SRST = 0x04 +}; + +#define DETECT_DEVICE1_TIME (attotime::from_msec(2)) +#define DEVICE1_PDIAG_TIME (attotime::from_msec(2)) +#define DIAGNOSTIC_TIME (attotime::from_msec(2)) + +ata_hle_device::ata_hle_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock,const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + ata_device_interface(mconfig, *this), + device_slot_card_interface(mconfig, *this), + m_buffer_offset(0), + m_buffer_size(0), + m_error(0), + m_feature(0), + m_sector_count(0), + m_sector_number(0), + m_cylinder_low(0), + m_cylinder_high(0), + m_device_head(0), + m_status(0), + m_command(0), + m_device_control(0), + m_revert_to_defaults(true), + m_8bit_data_transfers(false), + m_csel(0), + m_daspin(0), + m_daspout(0), + m_dmack(0), + m_dmarq(0), + m_irq(0), + m_pdiagin(0), + m_pdiagout(0), + m_single_device(0), + m_resetting(0) +{ +} + +void ata_hle_device::device_start() +{ + MINIMUM_COMMAND_TIME = attotime::from_usec(10); + + m_irq_handler.resolve_safe(); + m_dmarq_handler.resolve_safe(); + m_dasp_handler.resolve_safe(); + m_pdiag_handler.resolve_safe(); + + m_buffer.resize(sector_length()); + save_item(NAME(m_buffer)); + save_item(NAME(m_buffer_offset)); + save_item(NAME(m_buffer_size)); + save_item(NAME(m_error)); + save_item(NAME(m_feature)); + save_item(NAME(m_sector_count)); + save_item(NAME(m_sector_number)); + save_item(NAME(m_cylinder_low)); + save_item(NAME(m_cylinder_high)); + save_item(NAME(m_device_head)); + save_item(NAME(m_status)); + save_item(NAME(m_command)); + save_item(NAME(m_device_control)); + save_item(NAME(m_revert_to_defaults)); + + save_item(NAME(m_single_device)); + save_item(NAME(m_resetting)); + + save_item(NAME(m_csel)); + save_item(NAME(m_daspin)); + save_item(NAME(m_daspout)); + save_item(NAME(m_dmack)); + save_item(NAME(m_dmarq)); + save_item(NAME(m_irq)); + save_item(NAME(m_pdiagin)); + save_item(NAME(m_pdiagout)); + + save_item(NAME(m_identify_buffer)); + + m_busy_timer = timer_alloc(TID_BUSY); +} + +void ata_hle_device::device_reset() +{ + /* reset the drive state */ + set_dasp(CLEAR_LINE); + set_dmarq(CLEAR_LINE); + set_irq(CLEAR_LINE); + set_pdiag(CLEAR_LINE); + + m_status = 0; + m_device_control = 0; + m_resetting = true; + + if (m_csel == 0) + { + start_busy(DETECT_DEVICE1_TIME, PARAM_DETECT_DEVICE1); + } + else + { + set_dasp(ASSERT_LINE); + soft_reset(); + } +} + +void ata_hle_device::soft_reset() +{ + m_buffer_offset = 0; + m_buffer_size = 0; + m_status = 0; + + if (is_ready()) + { + m_status |= IDE_STATUS_DRDY; + } + + start_busy(DIAGNOSTIC_TIME, PARAM_DIAGNOSTIC); +} + +void ata_hle_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch(id) + { + case TID_BUSY: + m_status &= ~IDE_STATUS_BSY; + + finished_busy(param); + break; + } +} + +void ata_hle_device::finished_busy(int param) +{ + switch (param) + { + case PARAM_DETECT_DEVICE1: + m_single_device = (m_daspin == CLEAR_LINE); + soft_reset(); + break; + + case PARAM_DIAGNOSTIC: + start_diagnostic(); + break; + + case PARAM_WAIT_FOR_PDIAG: + m_error |= IDE_ERROR_DIAGNOSTIC_DEVICE1_FAILED; + finished_diagnostic(); + break; + + case PARAM_COMMAND: + finished_command(); + break; + } +} + +void ata_hle_device::process_command() +{ + switch (m_command) + { + case IDE_COMMAND_DIAGNOSTIC: + start_busy(DIAGNOSTIC_TIME, PARAM_COMMAND); + break; + + case IDE_COMMAND_SET_FEATURES: + start_busy(MINIMUM_COMMAND_TIME, PARAM_COMMAND); + break; + + case IDE_COMMAND_CACHE_FLUSH: + start_busy(MINIMUM_COMMAND_TIME, PARAM_COMMAND); + break; + + default: + LOGPRINT(("IDE unknown command (%02X)\n", m_command)); + m_status |= IDE_STATUS_ERR; + m_error = IDE_ERROR_ABRT; + set_irq(ASSERT_LINE); + //debugger_break(device->machine()); + break; + } +} + +void ata_hle_device::finished_command() +{ + switch (m_command) + { + case IDE_COMMAND_DIAGNOSTIC: + start_diagnostic(); + + if (m_csel == 0) + set_irq(ASSERT_LINE); + break; + + case IDE_COMMAND_SET_FEATURES: + if (!set_features()) + { + LOGPRINT(("IDE Set features failed (%02X %02X %02X %02X %02X)\n", m_feature, m_sector_count & 0xff, m_sector_number, m_cylinder_low, m_cylinder_high)); + + m_status |= IDE_STATUS_ERR; + m_error = IDE_ERROR_ABRT; + } + set_irq(ASSERT_LINE); + break; + + case IDE_COMMAND_CACHE_FLUSH: + m_status |= IDE_STATUS_DRDY; + break; + + default: + logerror( "finished_command() unhandled command %02x\n", m_command ); + break; + } +} + +bool ata_hle_device::set_dma_mode(int word) +{ + if ((m_identify_buffer[word] >> (m_sector_count & 7)) & 1) + { + m_identify_buffer[62] &= 0xff; + m_identify_buffer[63] &= 0xff; + m_identify_buffer[88] &= 0xff; + + m_identify_buffer[word] |= 0x100 << (m_sector_count & 7); + return true; + } + + return false; +} + +bool ata_hle_device::set_features() +{ + switch (m_feature) + { + case IDE_SET_FEATURES_ENABLE_8BIT_DATA_TRANSFERS: + m_8bit_data_transfers = true; + return true; + + case IDE_SET_FEATURES_TRANSFER_MODE: + switch (m_sector_count & IDE_TRANSFER_TYPE_MASK) + { + case IDE_TRANSFER_TYPE_PIO_DEFAULT: + switch (m_sector_count & 7) + { + case 0: + case 1: + return true; + } + break; + + case IDE_TRANSFER_TYPE_PIO_FLOW_CONTROL: + switch (m_sector_count & 7) + { + case 0: + case 1: + case 2: + return true; + + default: + if ((m_identify_buffer[64] >> ((m_sector_count & 7) - 3)) & 1) + { + return true; + } + } + break; + + case IDE_TRANSFER_TYPE_SINGLE_WORD_DMA: + return set_dma_mode(62); + + case IDE_TRANSFER_TYPE_MULTI_WORD_DMA: + return set_dma_mode(63); + + case IDE_TRANSFER_TYPE_ULTRA_DMA: + return set_dma_mode(88); + } + break; + + case IDE_SET_FEATURES_DISABLE_REVERTING_TO_POWER_ON_DEFAULTS: + m_revert_to_defaults = false; + return true; + + case IDE_SET_FEATURES_DISABLE_8BIT_DATA_TRANSFERS: + m_8bit_data_transfers = false; + return true; + + case IDE_SET_FEATURES_ENABLE_REVERTING_TO_POWER_ON_DEFAULTS: + m_revert_to_defaults = true; + return true; + } + + return false; +} + +int ata_hle_device::bit_to_mode(UINT16 word) +{ + switch (word>>8) + { + case 0x01: + return 0; + case 0x02: + return 1; + case 0x04: + return 2; + case 0x08: + return 3; + case 0x10: + return 4; + case 0x20: + return 5; + case 0x40: + return 6; + case 0x080: + return 7; + } + + return -1; +} + +int ata_hle_device::single_word_dma_mode() +{ + return bit_to_mode(m_identify_buffer[62]); +} + +int ata_hle_device::multi_word_dma_mode() +{ + return bit_to_mode(m_identify_buffer[63]); +} + +int ata_hle_device::ultra_dma_mode() +{ + return bit_to_mode(m_identify_buffer[88]); +} + +UINT16 ata_hle_device::read_data() +{ + /* fetch the correct amount of data */ + UINT16 result = m_buffer[m_buffer_offset++]; + if (!m_8bit_data_transfers) + result |= m_buffer[m_buffer_offset++] << 8; + + /* if we're at the end of the buffer, handle it */ + if (m_buffer_offset >= m_buffer_size) + { + LOG(("%s:IDE completed PIO read\n", machine().describe_context())); + read_buffer_empty(); + } + + return result; +} + +void ata_hle_device::write_data(UINT16 data) +{ + /* store the correct amount of data */ + m_buffer[m_buffer_offset++] = data; + if (!m_8bit_data_transfers) + m_buffer[m_buffer_offset++] = data >> 8; + + /* if we're at the end of the buffer, handle it */ + if (m_buffer_offset >= m_buffer_size) + { + LOG(("%s:IDE completed PIO write\n", machine().describe_context())); + write_buffer_full(); + } +} + +void ata_hle_device::update_irq() +{ + if (device_selected() && (m_device_control & IDE_DEVICE_CONTROL_NIEN) == 0) + m_irq_handler(m_irq); + else + m_irq_handler(CLEAR_LINE); +} + +void ata_hle_device::set_irq(int state) +{ + if (m_irq != state) + { + m_irq = state; + + update_irq(); + } +} + +void ata_hle_device::set_dmarq(int state) +{ + if (m_dmarq != state) + { + m_dmarq = state; + + m_dmarq_handler(state); + } +} + +void ata_hle_device::set_dasp(int state) +{ + if (m_daspout != state) + { + m_daspout = state; + + m_dasp_handler(state); + } +} + +void ata_hle_device::set_pdiag(int state) +{ + if (m_pdiagout != state) + { + m_pdiagout = state; + + m_pdiag_handler(state); + } +} + +void ata_hle_device::start_busy(const attotime &time, int param) +{ + m_status |= IDE_STATUS_BSY; + m_busy_timer->adjust(time, param); +} + +void ata_hle_device::stop_busy() +{ + m_status &= ~IDE_STATUS_BSY; + m_busy_timer->adjust(attotime::never); +} + +void ata_hle_device::read_buffer_empty() +{ + m_buffer_offset = 0; + + m_status &= ~IDE_STATUS_DRQ; + + if (multi_word_dma_mode() >= 0) + set_dmarq(CLEAR_LINE); + + fill_buffer(); +} + +void ata_hle_device::write_buffer_full() +{ + m_buffer_offset = 0; + + m_status &= ~IDE_STATUS_DRQ; + + if (multi_word_dma_mode() >= 0) + set_dmarq(CLEAR_LINE); + + process_buffer(); +} + +void ata_hle_device::start_diagnostic() +{ + m_error = IDE_ERROR_DIAGNOSTIC_FAILED; + + perform_diagnostic(); + + if (m_csel == 1 && m_error == IDE_ERROR_DIAGNOSTIC_PASSED) + set_pdiag(ASSERT_LINE); + + if (m_csel == 0 && !m_single_device && m_pdiagin == CLEAR_LINE) + start_busy(DEVICE1_PDIAG_TIME, PARAM_WAIT_FOR_PDIAG); + else + finished_diagnostic(); +} + +void ata_hle_device::finished_diagnostic() +{ + m_resetting = false; + + signature(); +} + + +WRITE_LINE_MEMBER( ata_hle_device::write_csel ) +{ + m_csel = state; +} + +WRITE_LINE_MEMBER( ata_hle_device::write_dasp ) +{ + m_daspin = state; +} + +WRITE_LINE_MEMBER( ata_hle_device::write_dmack ) +{ + if (state && !m_dmack && single_word_dma_mode() >= 0) + set_dmarq(CLEAR_LINE); + + m_dmack = state; +} + +WRITE_LINE_MEMBER( ata_hle_device::write_pdiag ) +{ + m_pdiagin = state; + + if (m_pdiagin == ASSERT_LINE && m_busy_timer->param() == PARAM_WAIT_FOR_PDIAG) + { + stop_busy(); + finished_diagnostic(); + } +} + +UINT16 ata_hle_device::read_dma() +{ + UINT16 result = 0xffff; + + if (device_selected()) + { + if (!m_dmack) + { + logerror( "%s: %s dev %d read_dma ignored (!DMACK)\n", machine().describe_context(), tag(), dev() ); + } + else if (m_dmarq && single_word_dma_mode() >= 0) + { + logerror( "%s: %s dev %d read_dma ignored (DMARQ)\n", machine().describe_context(), tag(), dev() ); + } + else if (!m_dmarq && multi_word_dma_mode() >= 0) + { + logerror( "%s: %s dev %d read_dma ignored (!DMARQ)\n", machine().describe_context(), tag(), dev() ); + } + else if (m_status & IDE_STATUS_BSY) + { + logerror( "%s: %s dev %d read_dma ignored (BSY)\n", machine().describe_context(), tag(), dev() ); + } + else if (!(m_status & IDE_STATUS_DRQ)) + { + logerror( "%s: %s dev %d read_dma ignored (!DRQ)\n", machine().describe_context(), tag(), dev() ); + } + else + { + result = read_data(); + + if ((m_status & IDE_STATUS_DRQ) && single_word_dma_mode() >= 0) + set_dmarq(ASSERT_LINE); + } + } + + return result; +} + +READ16_MEMBER( ata_hle_device::read_cs0 ) +{ + /* logit */ +// if (offset != IDE_CS0_DATA_RW && offset != IDE_CS0_STATUS_R) + LOG(("%s:IDE cs0 read at %X, mem_mask=%d\n", machine().describe_context(), offset, mem_mask)); + + UINT16 result = 0xffff; + + if (device_selected() || m_single_device) + { + if (m_dmack) + { + logerror( "%s: %s dev %d read_cs0 %04x %04x ignored (DMACK)\n", machine().describe_context(), tag(), dev(), offset, mem_mask ); + } + else if ((m_status & IDE_STATUS_BSY) && offset != IDE_CS0_STATUS_R) + { + // ATA5 spec says status reads should also go through here, but this breaks Primal Rage 2. + // Real hardware might work due to read ahead in the vt83c461. + if (device_selected()) + { + switch (offset) + { + case IDE_CS0_DATA_RW: + logerror( "%s: %s dev %d read_cs0 %04x %04x ignored (BSY)\n", machine().describe_context(), tag(), dev(), offset, mem_mask ); + break; + + default: + result = calculate_status(); + break; + } + } + else + { + result = 0; + } + } + else + { + switch (offset) + { + /* read data if there's data to be read */ + case IDE_CS0_DATA_RW: + if (device_selected()) + { + if (!(m_status & IDE_STATUS_DRQ)) + { + logerror( "%s: %s dev %d read_cs0 ignored (!DRQ)\n", machine().describe_context(), tag(), dev() ); + } + else + { + result = read_data(); + } + } + else + { + result = 0; + } + break; + + /* return the current error */ + case IDE_CS0_ERROR_R: + result = m_error; + break; + + /* return the current sector count */ + case IDE_CS0_SECTOR_COUNT_RW: + result = m_sector_count; + break; + + /* return the current sector */ + case IDE_CS0_SECTOR_NUMBER_RW: + result = m_sector_number; + break; + + /* return the current cylinder LSB */ + case IDE_CS0_CYLINDER_LOW_RW: + result = m_cylinder_low; + break; + + /* return the current cylinder MSB */ + case IDE_CS0_CYLINDER_HIGH_RW: + result = m_cylinder_high; + break; + + /* return the current head */ + case IDE_CS0_DEVICE_HEAD_RW: + result = m_device_head; + break; + + /* return the current status and clear any pending interrupts */ + case IDE_CS0_STATUS_R: + if (device_selected()) + { + result = calculate_status(); + + if (!(m_status & IDE_STATUS_DRDY) && is_ready()) + m_status |= IDE_STATUS_DRDY; + + set_irq(CLEAR_LINE); + } + else + { + result = 0; + } + break; + + /* log anything else */ + default: + logerror("%s:unknown IDE cs0 read at %03X, mem_mask=%d\n", machine().describe_context(), offset, mem_mask); + break; + } + } + } + + /* return the result */ + return result; +} + +READ16_MEMBER( ata_hle_device::read_cs1 ) +{ + /* logit */ +// if (offset != IDE_CS1_ALTERNATE_STATUS_R) + LOG(("%s:IDE cs1 read at %X, mem_mask=%d\n", machine().describe_context(), offset, mem_mask)); + + UINT16 result = 0xffff; + + if (device_selected() || m_single_device) + { + if (m_dmack) + { + logerror( "%s: %s dev %d read_cs1 %04x %04x ignored (DMACK)\n", machine().describe_context(), tag(), dev(), offset, mem_mask ); + } + else + { + switch (offset) + { + case IDE_CS1_ALTERNATE_STATUS_R: + if (device_selected()) + { + result = calculate_status(); + } + else + { + result = 0; + } + break; + + case IDE_CS1_ACTIVE_STATUS: + /* + + bit description + + 0 master active + 1 slave active + 2 complement of active disk head bit 0 + 3 complement of active disk head bit 1 + 4 complement of active disk head bit 2 + 5 complement of active disk head bit 3 + 6 write in progress + 7 floppy present (unused) + + */ + if (device_selected()) + { + result = 0x01; + } + else + { + result = 0; + } + break; + + /* log anything else */ + default: + logerror("%s:unknown IDE cs1 read at %03X, mem_mask=%d\n", machine().describe_context(), offset, mem_mask); + break; + } + } + } + + /* return the result */ + return result; +} + +void ata_hle_device::write_dma( UINT16 data ) +{ + if (device_selected()) + { + if (!m_dmack) + { + logerror( "%s: %s dev %d write_dma %04x ignored (!DMACK)\n", machine().describe_context(), tag(), dev(), data ); + } + else if (m_dmarq && single_word_dma_mode() >= 0) + { + logerror( "%s: %s dev %d write_dma %04x ignored (DMARQ)\n", machine().describe_context(), tag(), dev(), data ); + } + else if (!m_dmarq && multi_word_dma_mode() >= 0) + { + logerror( "%s: %s dev %d write_dma %04x ignored (!DMARQ)\n", machine().describe_context(), tag(), dev(), data ); + } + else if (m_status & IDE_STATUS_BSY) + { + logerror( "%s: %s dev %d write_dma %04x ignored (BSY)\n", machine().describe_context(), tag(), dev(), data ); + } + else if (!(m_status & IDE_STATUS_DRQ)) + { + logerror( "%s: %s dev %d write_dma %04x ignored (!DRQ)\n", machine().describe_context(), tag(), dev(), data ); + } + else + { + write_data(data); + + if ((m_status & IDE_STATUS_DRQ) && single_word_dma_mode() >= 0) + set_dmarq(ASSERT_LINE); + } + } +} + +WRITE16_MEMBER( ata_hle_device::write_cs0 ) +{ + /* logit */ + if (offset != IDE_CS0_DATA_RW) + LOG(("%s:IDE cs0 write to %X = %08X, mem_mask=%d\n", machine().describe_context(), offset, data, mem_mask)); + // fprintf(stderr, "ide write %03x %02x mem_mask=%d\n", offset, data, size); + + if (m_dmack) + { + logerror( "%s: %s dev %d write_cs0 %04x %04x %04x ignored (DMACK)\n", machine().describe_context(), tag(), dev(), offset, data, mem_mask ); + } + else if ((m_status & IDE_STATUS_BSY) && offset != IDE_CS0_COMMAND_W) + { + logerror( "%s: %s dev %d write_cs0 %04x %04x %04x ignored (BSY) command %02x\n", machine().describe_context(), tag(), dev(), offset, data, mem_mask, m_command ); + } + else if ((m_status & IDE_STATUS_DRQ) && offset != IDE_CS0_DATA_RW && offset != IDE_CS0_COMMAND_W) + { + logerror( "%s: %s dev %d write_cs0 %04x %04x %04x ignored (DRQ) command %02x\n", machine().describe_context(), tag(), dev(), offset, data, mem_mask, m_command ); + } + else + { + UINT8 old; + + switch (offset) + { + /* write data */ + case IDE_CS0_DATA_RW: + if (device_selected()) + { + if (!(m_status & IDE_STATUS_DRQ)) + { + logerror( "%s: %s dev %d write_cs0 %04x %04x %04x ignored (!DRQ)\n", machine().describe_context(), tag(), dev(), offset, data, mem_mask ); + } + else + { + write_data(data); + } + } + break; + + case IDE_CS0_FEATURE_W: + m_feature = data; + break; + + /* sector count */ + case IDE_CS0_SECTOR_COUNT_RW: + m_sector_count = data ? data : 256; + break; + + /* current sector */ + case IDE_CS0_SECTOR_NUMBER_RW: + m_sector_number = data; + break; + + /* current cylinder LSB */ + case IDE_CS0_CYLINDER_LOW_RW: + m_cylinder_low = data; + break; + + /* current cylinder MSB */ + case IDE_CS0_CYLINDER_HIGH_RW: + m_cylinder_high = data; + break; + + /* current head */ + case IDE_CS0_DEVICE_HEAD_RW: + old = m_device_head; + m_device_head = data; + + if ((m_device_head ^ old) & IDE_DEVICE_HEAD_DRV) + update_irq(); + break; + + /* command */ + case IDE_CS0_COMMAND_W: + // Packet devices can accept DEVICE RESET when BSY or DRQ is set. + if (m_status & IDE_STATUS_BSY) + { + logerror( "%s: %s dev %d write_cs0 %04x %04x %04x ignored (BSY) command %02x\n", machine().describe_context(), tag(), dev(), offset, data, mem_mask, m_command ); + } + else if (m_status & IDE_STATUS_DRQ) + { + logerror( "%s: %s dev %d write_cs0 %04x %04x %04x ignored (DRQ) command %02x\n", machine().describe_context(), tag(), dev(), offset, data, mem_mask, m_command ); + } + else if (device_selected() || m_command == IDE_COMMAND_DIAGNOSTIC) + { + m_command = data; + + /* implicitly clear interrupts & dmarq here */ + set_irq(CLEAR_LINE); + set_dmarq(CLEAR_LINE); + + m_buffer_offset = 0; + + set_dasp(CLEAR_LINE); + m_status &= ~IDE_STATUS_DRQ; + m_status &= ~IDE_STATUS_ERR; + + process_command(); + } + break; + + default: + logerror("%s:unknown IDE cs0 write at %03X = %04x, mem_mask=%d\n", machine().describe_context(), offset, data, mem_mask); + break; + } + } +} + +WRITE16_MEMBER( ata_hle_device::write_cs1 ) +{ + /* logit */ + LOG(("%s:IDE cs1 write to %X = %08X, mem_mask=%d\n", machine().describe_context(), offset, data, mem_mask)); + + if (m_dmack) + { + logerror( "%s: %s dev %d write_cs1 %04x %04x %04x ignored (DMACK)\n", machine().describe_context(), tag(), dev(), offset, data, mem_mask ); + } + else + { + UINT8 old; + + switch (offset) + { + /* adapter control */ + case IDE_CS1_DEVICE_CONTROL_W: + old = m_device_control; + m_device_control = data; + + if ((m_device_control ^ old) & IDE_DEVICE_CONTROL_NIEN) + update_irq(); + + if ((m_device_control ^ old) & IDE_DEVICE_CONTROL_SRST) + { + if (m_device_control & IDE_DEVICE_CONTROL_SRST) + { + if (m_resetting) + { + logerror( "%s: %s dev %d write_cs1 %04x %04x %04x ignored (RESET)\n", machine().describe_context(), tag(), dev(), offset, data, mem_mask ); + } + else + { + set_dasp(CLEAR_LINE); + set_dmarq(CLEAR_LINE); + set_irq(CLEAR_LINE); + set_pdiag(CLEAR_LINE); + + start_busy(attotime::never, PARAM_RESET); + } + } + else if (m_busy_timer->param() == PARAM_RESET) + { + soft_reset(); + } + } + break; + + default: + logerror("%s:unknown IDE cs1 write at %03X = %04x, mem_mask=%d\n", machine().describe_context(), offset, data, mem_mask); + break; + } + } +} diff --git a/src/devices/machine/atahle.h b/src/devices/machine/atahle.h new file mode 100644 index 00000000000..30236e62d49 --- /dev/null +++ b/src/devices/machine/atahle.h @@ -0,0 +1,218 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/*************************************************************************** + + atahle.h + + ATA Device HLE + +***************************************************************************/ + +#pragma once + +#ifndef __ATAHLE_H__ +#define __ATAHLE_H__ + +#include "atadev.h" + +class ata_hle_device : public device_t, + public ata_device_interface, + public device_slot_card_interface +{ +public: + ata_hle_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock,const char *shortname, const char *source); + + virtual UINT16 read_dma(); + virtual DECLARE_READ16_MEMBER(read_cs0); + virtual DECLARE_READ16_MEMBER(read_cs1); + + virtual void write_dma(UINT16 data); + virtual DECLARE_WRITE16_MEMBER(write_cs0); + virtual DECLARE_WRITE16_MEMBER(write_cs1); + virtual DECLARE_WRITE_LINE_MEMBER(write_csel); + virtual DECLARE_WRITE_LINE_MEMBER(write_dasp); + virtual DECLARE_WRITE_LINE_MEMBER(write_dmack); + virtual DECLARE_WRITE_LINE_MEMBER(write_pdiag); + +protected: + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + void set_irq(int state); + void set_dmarq(int state); + void set_dasp(int state); + void set_pdiag(int state); + + void start_busy(const attotime &time, int param); + void stop_busy(); + + int dev() { return (m_device_head & IDE_DEVICE_HEAD_DRV) >> 4; } + bool device_selected() { return m_csel == dev(); } + + virtual UINT8 calculate_status() { return m_status; } + virtual void soft_reset(); + virtual void process_command(); + virtual void finished_command(); + virtual bool set_features(); + virtual int sector_length() = 0; + virtual void process_buffer() = 0; + virtual void fill_buffer() = 0; + virtual bool is_ready() = 0; + virtual void perform_diagnostic() = 0; + virtual void signature() = 0; + virtual UINT16 read_data(); + virtual void write_data(UINT16 data); + + int bit_to_mode(UINT16 word); + int single_word_dma_mode(); + int multi_word_dma_mode(); + int ultra_dma_mode(); + + /// TODO: not sure this should be protected. + void read_buffer_empty(); + + enum + { + IDE_STATUS_ERR = 0x01, // Error + IDE_STATUS_IDX = 0x02, // Index + IDE_STATUS_CORR = 0x04, // Corrected Data + IDE_STATUS_DRQ = 0x08, // Data Request + IDE_STATUS_DSC = 0x10, // ATA Drive Seek Complete + IDE_STATUS_SERV = 0x10, // ATAPI Service + IDE_STATUS_DWF = 0x20, // ATA Drive Write Fault + IDE_STATUS_DMRD = 0x20, // ATAPI DMA Ready + IDE_STATUS_DRDY = 0x40, // Drive Ready + IDE_STATUS_BSY = 0x80 // Busy + }; + + enum + { + IDE_ERROR_NONE = 0x00, + IDE_ERROR_DIAGNOSTIC_OK = 0x01, + IDE_ERROR_TRACK0_NOT_FOUND = 0x02, + IDE_ERROR_ABRT = 0x04, + IDE_ERROR_BAD_LOCATION = 0x10, + IDE_ERROR_BAD_SECTOR = 0x80, + IDE_ERROR_DIAGNOSTIC_FAILED = 0x00, + IDE_ERROR_DIAGNOSTIC_PASSED = 0x01, + IDE_ERROR_DIAGNOSTIC_DEVICE1_FAILED = 0x80 + }; + + enum + { + IDE_COMMAND_NOP = 0x00, + IDE_COMMAND_DEVICE_RESET = 0x08, + IDE_COMMAND_RECALIBRATE = 0x10, + IDE_COMMAND_READ_SECTORS = 0x20, + IDE_COMMAND_READ_SECTORS_NORETRY = 0x21, + IDE_COMMAND_WRITE_SECTORS = 0x30, + IDE_COMMAND_WRITE_SECTORS_NORETRY = 0x31, + IDE_COMMAND_VERIFY_SECTORS = 0x40, + IDE_COMMAND_VERIFY_SECTORS_NORETRY = 0x41, + IDE_COMMAND_SEEK = 0x70, + IDE_COMMAND_DIAGNOSTIC = 0x90, + IDE_COMMAND_SET_CONFIG = 0x91, + IDE_COMMAND_PACKET = 0xa0, + IDE_COMMAND_IDENTIFY_PACKET_DEVICE = 0xa1, + IDE_COMMAND_READ_MULTIPLE = 0xc4, + IDE_COMMAND_WRITE_MULTIPLE = 0xc5, + IDE_COMMAND_SET_BLOCK_COUNT = 0xc6, + IDE_COMMAND_READ_DMA = 0xc8, + IDE_COMMAND_WRITE_DMA = 0xca, + IDE_COMMAND_IDLE_IMMEDIATE = 0xe1, + IDE_COMMAND_IDLE = 0xe3, + IDE_COMMAND_CHECK_POWER_MODE = 0xe5, + IDE_COMMAND_CACHE_FLUSH = 0xe7, + IDE_COMMAND_IDENTIFY_DEVICE = 0xec, + IDE_COMMAND_SET_FEATURES = 0xef, + IDE_COMMAND_SECURITY_UNLOCK = 0xf2, + IDE_COMMAND_READ_NATIVE_MAX_ADDRESS = 0xf8, + IDE_COMMAND_SET_MAX = 0xf9 + }; + + enum + { + IDE_SET_FEATURES_ENABLE_8BIT_DATA_TRANSFERS = 0x01, + IDE_SET_FEATURES_TRANSFER_MODE = 0x03, + IDE_SET_FEATURES_DISABLE_REVERTING_TO_POWER_ON_DEFAULTS = 0x66, + IDE_SET_FEATURES_DISABLE_8BIT_DATA_TRANSFERS = 0x81, + IDE_SET_FEATURES_ENABLE_REVERTING_TO_POWER_ON_DEFAULTS = 0xcc + }; + + enum ide_transfer_type_t + { + IDE_TRANSFER_TYPE_PIO_DEFAULT = 0x00, + IDE_TRANSFER_TYPE_PIO_FLOW_CONTROL = 0x08, + IDE_TRANSFER_TYPE_SINGLE_WORD_DMA = 0x10, + IDE_TRANSFER_TYPE_MULTI_WORD_DMA = 0x20, + IDE_TRANSFER_TYPE_ULTRA_DMA = 0x40, + IDE_TRANSFER_TYPE_MASK = 0xf8 + }; + + enum + { + IDE_DEVICE_HEAD_HS = 0x0f, + IDE_DEVICE_HEAD_DRV = 0x10, + IDE_DEVICE_HEAD_L = 0x40, + IDE_DEVICE_HEAD_OBSOLETE = 0x80 | 0x20 + }; + + enum + { + TID_BUSY + }; + + enum + { + PARAM_RESET, + PARAM_DETECT_DEVICE1, + PARAM_DIAGNOSTIC, + PARAM_WAIT_FOR_PDIAG, + PARAM_COMMAND + }; + + attotime MINIMUM_COMMAND_TIME; + + dynamic_buffer m_buffer; + UINT16 m_buffer_offset; + UINT16 m_buffer_size; + UINT8 m_error; + UINT8 m_feature; + UINT16 m_sector_count; + UINT8 m_sector_number; + UINT8 m_cylinder_low; + UINT8 m_cylinder_high; + UINT8 m_device_head; + UINT8 m_status; + UINT8 m_command; + UINT8 m_device_control; + + UINT16 m_identify_buffer[256]; + bool m_revert_to_defaults; + bool m_8bit_data_transfers; + +private: + void update_irq(); + void write_buffer_full(); + void start_diagnostic(); + void finished_diagnostic(); + void finished_busy(int param); + bool set_dma_mode(int word); + + int m_csel; + int m_daspin; + int m_daspout; + int m_dmack; + int m_dmarq; + int m_irq; + int m_pdiagin; + int m_pdiagout; + + bool m_single_device; + bool m_resetting; + + emu_timer *m_busy_timer; +}; + +#endif diff --git a/src/devices/machine/ataintf.c b/src/devices/machine/ataintf.c new file mode 100644 index 00000000000..56c2031bd56 --- /dev/null +++ b/src/devices/machine/ataintf.c @@ -0,0 +1,323 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/*************************************************************************** + + ataintf.c + + ATA Interface implementation. + +***************************************************************************/ + +#include "emu.h" +#include "ataintf.h" +#include "debugger.h" +#include "idehd.h" +#include "atapicdr.h" + +void ata_interface_device::set_irq(int state) +{ +// printf( "%s: irq %d\n", machine().describe_context(), state ); + + m_irq_handler(state); +} + +void ata_interface_device::set_dmarq(int state) +{ +// printf( "%s: dmarq %d\n", machine().describe_context(), state ); + + m_dmarq_handler(state); +} + +void ata_interface_device::set_dasp(int state) +{ +// printf( "%s: dasp %d\n", machine().describe_context(), state ); + + m_dasp_handler(state); +} + +WRITE_LINE_MEMBER( ata_interface_device::irq0_write_line ) +{ + if (m_irq[0] != state) + { + m_irq[0] = state; + + set_irq(m_irq[0] == ASSERT_LINE || m_irq[1] == ASSERT_LINE); + } +} + +WRITE_LINE_MEMBER( ata_interface_device::irq1_write_line ) +{ + if (m_irq[1] != state) + { + m_irq[1] = state; + + set_irq(m_irq[0] == ASSERT_LINE || m_irq[1] == ASSERT_LINE); + } +} + +WRITE_LINE_MEMBER( ata_interface_device::dasp0_write_line ) +{ + if (m_dasp[0] != state) + { + m_dasp[0] = state; + + set_dasp(m_dasp[0] == ASSERT_LINE || m_dasp[1] == ASSERT_LINE); + } +} + +WRITE_LINE_MEMBER( ata_interface_device::dasp1_write_line ) +{ + if (m_dasp[1] != state) + { + m_dasp[1] = state; + + ata_device_interface *dev = m_slot[0]->dev(); + if (dev != NULL) + dev->write_dasp(state); + + set_dasp(m_dasp[0] == ASSERT_LINE || m_dasp[1] == ASSERT_LINE); + } +} + +WRITE_LINE_MEMBER( ata_interface_device::dmarq0_write_line ) +{ + if (m_dmarq[0] != state) + { + m_dmarq[0] = state; + + set_dmarq(m_dmarq[0] == ASSERT_LINE || m_dmarq[1] == ASSERT_LINE); + } +} + +WRITE_LINE_MEMBER( ata_interface_device::dmarq1_write_line ) +{ + if (m_dmarq[1] != state) + { + m_dmarq[1] = state; + + set_dmarq(m_dmarq[0] == ASSERT_LINE || m_dmarq[1] == ASSERT_LINE); + } +} + +WRITE_LINE_MEMBER( ata_interface_device::pdiag0_write_line ) +{ + m_pdiag[0] = state; +} + +WRITE_LINE_MEMBER( ata_interface_device::pdiag1_write_line ) +{ + if (m_pdiag[1] != state) + { + m_pdiag[1] = state; + + ata_device_interface *dev = m_slot[0]->dev(); + if (dev != NULL) + dev->write_pdiag(state); + } +} + +/************************************* + * + * ATA interface read + * + *************************************/ + +UINT16 ata_interface_device::read_dma() +{ + UINT16 result = 0xffff; + for (int i = 0; i < 2; i++) + if (m_slot[i]->dev() != NULL) + result &= m_slot[i]->dev()->read_dma(); + +// printf( "%s: read_dma %04x\n", machine().describe_context(), result ); + return result; +} + +READ16_MEMBER( ata_interface_device::read_cs0 ) +{ + UINT16 result = mem_mask; + for (int i = 0; i < 2; i++) + if (m_slot[i]->dev() != NULL) + result &= m_slot[i]->dev()->read_cs0(space, offset, mem_mask); + +// { static int last_status = -1; if (offset == 7 ) { if( result == last_status ) return last_status; last_status = result; } else last_status = -1; } + +// printf( "%s: read cs0 %04x %04x %04x\n", machine().describe_context(), offset, result, mem_mask ); + + return result; +} + +READ16_MEMBER( ata_interface_device::read_cs1 ) +{ + UINT16 result = mem_mask; + for (int i = 0; i < 2; i++) + if (m_slot[i]->dev() != NULL) + result &= m_slot[i]->dev()->read_cs1(space, offset, mem_mask); + +// printf( "%s: read cs1 %04x %04x %04x\n", machine().describe_context(), offset, result, mem_mask ); + + return result; +} + + +/************************************* + * + * ATA interface write + * + *************************************/ + +void ata_interface_device::write_dma( UINT16 data ) +{ +// printf( "%s: write_dma %04x\n", machine().describe_context(), data ); + + for (int i = 0; i < 2; i++) + if (m_slot[i]->dev() != NULL) + m_slot[i]->dev()->write_dma(data); +} + +WRITE16_MEMBER( ata_interface_device::write_cs0 ) +{ +// printf( "%s: write cs0 %04x %04x %04x\n", machine().describe_context(), offset, data, mem_mask ); + + for (int i = 0; i < 2; i++) + if (m_slot[i]->dev() != NULL) + m_slot[i]->dev()->write_cs0(space, offset, data, mem_mask); +} + +WRITE16_MEMBER( ata_interface_device::write_cs1 ) +{ +// printf( "%s: write cs1 %04x %04x %04x\n", machine().describe_context(), offset, data, mem_mask ); + + for (int i = 0; i < 2; i++) + if (m_slot[i]->dev() != NULL) + m_slot[i]->dev()->write_cs1(space, offset, data, mem_mask); +} + +WRITE_LINE_MEMBER( ata_interface_device::write_dmack ) +{ +// printf( "%s: write_dmack %04x\n", machine().describe_context(), state ); + + for (int i = 0; i < 2; i++) + if (m_slot[i]->dev() != NULL) + m_slot[i]->dev()->write_dmack(state); +} + +SLOT_INTERFACE_START(ata_devices) + SLOT_INTERFACE("hdd", IDE_HARDDISK) + SLOT_INTERFACE("cdrom", ATAPI_CDROM) +SLOT_INTERFACE_END + +ata_interface_device::ata_interface_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + m_irq_handler(*this), + m_dmarq_handler(*this), + m_dasp_handler(*this){ +} + + +const device_type ATA_INTERFACE = &device_creator; + +ata_interface_device::ata_interface_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, ATA_INTERFACE, "ATA Interface", tag, owner, clock, "ata_interface", __FILE__), + m_irq_handler(*this), + m_dmarq_handler(*this), + m_dasp_handler(*this) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void ata_interface_device::device_start() +{ + m_irq_handler.resolve_safe(); + m_dmarq_handler.resolve_safe(); + m_dasp_handler.resolve_safe(); + + /* set MAME harddisk handle */ + m_slot[0] = subdevice("0"); + m_slot[1] = subdevice("1"); + + for (int i = 0; i < 2; i++) + { + m_irq[i] = 0; + m_dmarq[i] = 0; + m_dasp[i] = 0; + m_pdiag[i] = 0; + + ata_device_interface *dev = m_slot[i]->dev(); + if (dev != NULL) + { + if (i == 0) + { + dev->m_irq_handler.set_callback(DEVCB_DEVWRITELINE("^", ata_interface_device, irq0_write_line)); + dev->m_dmarq_handler.set_callback(DEVCB_DEVWRITELINE("^", ata_interface_device, dmarq0_write_line)); + dev->m_dasp_handler.set_callback(DEVCB_DEVWRITELINE("^", ata_interface_device, dasp0_write_line)); + dev->m_pdiag_handler.set_callback(DEVCB_DEVWRITELINE("^", ata_interface_device, pdiag0_write_line)); + } + else + { + dev->m_irq_handler.set_callback(DEVCB_DEVWRITELINE("^", ata_interface_device, irq1_write_line)); + dev->m_dmarq_handler.set_callback(DEVCB_DEVWRITELINE("^", ata_interface_device, dmarq1_write_line)); + dev->m_dasp_handler.set_callback(DEVCB_DEVWRITELINE("^", ata_interface_device, dasp1_write_line)); + dev->m_pdiag_handler.set_callback(DEVCB_DEVWRITELINE("^", ata_interface_device, pdiag1_write_line)); + } + + dev->write_csel(i); + } + } +} + +static MACHINE_CONFIG_FRAGMENT( ata_interface ) + MCFG_DEVICE_ADD( "0", ATA_SLOT, 0 ) + MCFG_DEVICE_ADD( "1", ATA_SLOT, 0 ) +MACHINE_CONFIG_END + +//------------------------------------------------- +// machine_config_additions - return a pointer to +// the device's machine fragment +//------------------------------------------------- + +machine_config_constructor ata_interface_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( ata_interface ); +} + + +//************************************************************************** +// ATA SLOT DEVICE +//************************************************************************** + +// device type definition +const device_type ATA_SLOT = &device_creator; + +//------------------------------------------------- +// ata_slot_device - constructor +//------------------------------------------------- + +ata_slot_device::ata_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, ATA_SLOT, "ATA Connector", tag, owner, clock, "ata_slot", __FILE__), + device_slot_interface(mconfig, *this), + m_dev(NULL) +{ +} + +//------------------------------------------------- +// device_config_complete - perform any +// operations now that the configuration is +// complete +//------------------------------------------------- + +void ata_slot_device::device_config_complete() +{ + m_dev = dynamic_cast(get_card_device()); +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void ata_slot_device::device_start() +{ +} diff --git a/src/devices/machine/ataintf.h b/src/devices/machine/ataintf.h new file mode 100644 index 00000000000..01ee67e159f --- /dev/null +++ b/src/devices/machine/ataintf.h @@ -0,0 +1,129 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/*************************************************************************** + + ataintf.h + + ATA Interface implementation. + +***************************************************************************/ + +#pragma once + +#ifndef __ATAINTF_H__ +#define __ATAINTF_H__ + +#include "atadev.h" + +/*************************************************************************** + TYPE DEFINITIONS +***************************************************************************/ + +// ======================> ata_slot_device + +class ata_slot_device : public device_t, + public device_slot_interface +{ +public: + // construction/destruction + ata_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + ata_device_interface *dev() { return m_dev; } +protected: + // device-level overrides + virtual void device_start(); + virtual void device_config_complete(); + +private: + ata_device_interface *m_dev; +}; + +// device type definition +extern const device_type ATA_SLOT; + +/*************************************************************************** + TYPE DEFINITIONS +***************************************************************************/ + +#define MCFG_ATA_INTERFACE_IRQ_HANDLER(_devcb) \ + devcb = &ata_interface_device::set_irq_handler(*device, DEVCB_##_devcb); + +#define MCFG_ATA_INTERFACE_DMARQ_HANDLER(_devcb) \ + devcb = &ata_interface_device::set_dmarq_handler(*device, DEVCB_##_devcb); + +#define MCFG_ATA_INTERFACE_DASP_HANDLER(_devcb) \ + devcb = &ata_interface_device::set_dasp_handler(*device, DEVCB_##_devcb); + +SLOT_INTERFACE_EXTERN(ata_devices); + +/*************************************************************************** + DEVICE CONFIGURATION MACROS +***************************************************************************/ + +#define MCFG_ATA_INTERFACE_ADD(_tag, _slot_intf, _master, _slave, _fixed) \ + MCFG_DEVICE_ADD(_tag, ATA_INTERFACE, 0) \ + MCFG_DEVICE_MODIFY(_tag ":0") \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _master, _fixed) \ + MCFG_DEVICE_MODIFY(_tag ":1") \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _slave, _fixed) \ + MCFG_DEVICE_MODIFY(_tag) + +/*************************************************************************** + TYPE DEFINITIONS +***************************************************************************/ + +/* ----- device interface ----- */ + +class ata_interface_device : public device_t +{ +public: + ata_interface_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + ata_interface_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + // static configuration helpers + template static devcb_base &set_irq_handler(device_t &device, _Object object) { return downcast(device).m_irq_handler.set_callback(object); } + template static devcb_base &set_dmarq_handler(device_t &device, _Object object) { return downcast(device).m_dmarq_handler.set_callback(object); } + template static devcb_base &set_dasp_handler(device_t &device, _Object object) { return downcast(device).m_dasp_handler.set_callback(object); } + UINT16 read_dma(); + virtual DECLARE_READ16_MEMBER(read_cs0); + virtual DECLARE_READ16_MEMBER(read_cs1); + + void write_dma(UINT16 data); + virtual DECLARE_WRITE16_MEMBER(write_cs0); + virtual DECLARE_WRITE16_MEMBER(write_cs1); + DECLARE_WRITE_LINE_MEMBER(write_dmack); + +protected: + // device-level overrides + virtual void device_start(); + virtual machine_config_constructor device_mconfig_additions() const; + + virtual void set_irq(int state); + virtual void set_dmarq(int state); + virtual void set_dasp(int state); + +private: + DECLARE_WRITE_LINE_MEMBER(irq0_write_line); + DECLARE_WRITE_LINE_MEMBER(dmarq0_write_line); + DECLARE_WRITE_LINE_MEMBER(dasp0_write_line); + DECLARE_WRITE_LINE_MEMBER(pdiag0_write_line); + + DECLARE_WRITE_LINE_MEMBER(irq1_write_line); + DECLARE_WRITE_LINE_MEMBER(dmarq1_write_line); + DECLARE_WRITE_LINE_MEMBER(dasp1_write_line); + DECLARE_WRITE_LINE_MEMBER(pdiag1_write_line); + + ata_slot_device *m_slot[2]; + int m_irq[2]; + int m_dmarq[2]; + int m_dasp[2]; + int m_pdiag[2]; + + devcb_write_line m_irq_handler; + devcb_write_line m_dmarq_handler; + devcb_write_line m_dasp_handler; +}; + +extern const device_type ATA_INTERFACE; + +#endif /* __ATAINTF_H__ */ diff --git a/src/devices/machine/atapicdr.c b/src/devices/machine/atapicdr.c new file mode 100644 index 00000000000..1588f6d17cd --- /dev/null +++ b/src/devices/machine/atapicdr.c @@ -0,0 +1,81 @@ +// license:BSD-3-Clause +// copyright-holders:smf +#include "atapicdr.h" + +// device type definition +const device_type ATAPI_CDROM = &device_creator; + +atapi_cdrom_device::atapi_cdrom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + atapi_hle_device(mconfig, ATAPI_CDROM, "ATAPI CDROM", tag, owner, clock, "cdrom", __FILE__) +{ +} + +atapi_cdrom_device::atapi_cdrom_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + atapi_hle_device(mconfig, type, name, tag, owner, clock, shortname, source) +{ +} + +static MACHINE_CONFIG_FRAGMENT( atapicdr ) + MCFG_CDROM_ADD("image") + MCFG_CDROM_INTERFACE("cdrom") + MCFG_SOUND_ADD("cdda", CDDA, 0) +MACHINE_CONFIG_END + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor atapi_cdrom_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( atapicdr ); +} + +void atapi_cdrom_device::device_start() +{ + m_image = subdevice("image"); + m_cdda = subdevice("cdda"); + + memset(m_identify_buffer, 0, sizeof(m_identify_buffer)); + + m_identify_buffer[ 0 ] = 0x8500; // ATAPI device, cmd set 5 compliant, DRQ within 3 ms of PACKET command + + m_identify_buffer[ 23 ] = ('1' << 8) | '.'; + m_identify_buffer[ 24 ] = ('0' << 8) | ' '; + m_identify_buffer[ 25 ] = (' ' << 8) | ' '; + m_identify_buffer[ 26 ] = (' ' << 8) | ' '; + + m_identify_buffer[ 27 ] = ('M' << 8) | 'A'; + m_identify_buffer[ 28 ] = ('M' << 8) | 'E'; + m_identify_buffer[ 29 ] = (' ' << 8) | ' '; + m_identify_buffer[ 30 ] = (' ' << 8) | ' '; + m_identify_buffer[ 31 ] = ('V' << 8) | 'i'; + m_identify_buffer[ 32 ] = ('r' << 8) | 't'; + m_identify_buffer[ 33 ] = ('u' << 8) | 'a'; + m_identify_buffer[ 34 ] = ('l' << 8) | ' '; + m_identify_buffer[ 35 ] = ('C' << 8) | 'D'; + m_identify_buffer[ 36 ] = ('R' << 8) | 'O'; + m_identify_buffer[ 37 ] = ('M' << 8) | ' '; + m_identify_buffer[ 38 ] = (' ' << 8) | ' '; + m_identify_buffer[ 39 ] = (' ' << 8) | ' '; + m_identify_buffer[ 40 ] = (' ' << 8) | ' '; + m_identify_buffer[ 41 ] = (' ' << 8) | ' '; + m_identify_buffer[ 42 ] = (' ' << 8) | ' '; + m_identify_buffer[ 43 ] = (' ' << 8) | ' '; + m_identify_buffer[ 44 ] = (' ' << 8) | ' '; + m_identify_buffer[ 45 ] = (' ' << 8) | ' '; + m_identify_buffer[ 46 ] = (' ' << 8) | ' '; + + m_identify_buffer[ 49 ] = 0x0600; // Word 49=Capabilities, IORDY may be disabled (bit_10), LBA Supported mandatory (bit_9) + + atapi_hle_device::device_start(); +} + +void atapi_cdrom_device::perform_diagnostic() +{ + m_error = IDE_ERROR_DIAGNOSTIC_PASSED; +} + +void atapi_cdrom_device::identify_packet_device() +{ +} diff --git a/src/devices/machine/atapicdr.h b/src/devices/machine/atapicdr.h new file mode 100644 index 00000000000..535a5b801b1 --- /dev/null +++ b/src/devices/machine/atapicdr.h @@ -0,0 +1,38 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/*************************************************************************** + + atapicdr.h + + ATAPI CDROM + +***************************************************************************/ + +#pragma once + +#ifndef __ATAPICDR_H__ +#define __ATAPICDR_H__ + +#include "atapihle.h" +#include "t10mmc.h" + +class atapi_cdrom_device : public atapi_hle_device, + public t10mmc +{ +public: + atapi_cdrom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + atapi_cdrom_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock,const char *shortname, const char *source); + +protected: + // device-level overrides + virtual void device_start(); + virtual machine_config_constructor device_mconfig_additions() const; + + virtual void perform_diagnostic(); + virtual void identify_packet_device(); +}; + +// device type definition +extern const device_type ATAPI_CDROM; + +#endif diff --git a/src/devices/machine/atapihle.c b/src/devices/machine/atapihle.c new file mode 100644 index 00000000000..dcbc00fb26c --- /dev/null +++ b/src/devices/machine/atapihle.c @@ -0,0 +1,277 @@ +// license:BSD-3-Clause +// copyright-holders:smf +#include "atapihle.h" + +atapi_hle_device::atapi_hle_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock,const char *shortname, const char *source) + : ata_hle_device(mconfig, type, name, tag, owner, clock, shortname, source), + m_packet(0), + m_data_size(0) +{ +} + +void atapi_hle_device::device_start() +{ + t10_start(*this); + ata_hle_device::device_start(); +} + +void atapi_hle_device::device_reset() +{ + t10_reset(); + ata_hle_device::device_reset(); +} + +void atapi_hle_device::process_buffer() +{ + if (m_packet) + { + //printf( "atapi command %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", + // m_buffer[0],m_buffer[1],m_buffer[2],m_buffer[3], + // m_buffer[4],m_buffer[5],m_buffer[6],m_buffer[7], + // m_buffer[8],m_buffer[9],m_buffer[10],m_buffer[11]); + + m_error = 0; // HACK: This might not be the right place, but firebeat needs this cleared at some point + + SetCommand(&m_buffer[0], m_buffer_size); + ExecCommand(); + GetLength(&m_data_size); + + if (m_status_code == SCSI_STATUS_CODE_CHECK_CONDITION) + m_status |= IDE_STATUS_ERR; + + m_buffer_size = (m_cylinder_high << 8) | m_cylinder_low; + if (m_buffer_size == 0xffff) + m_buffer_size = 0xfffe; + + //printf("atapi result %08x %08x\n", m_data_size, m_buffer_size); + + if (m_buffer_size > ATAPI_BUFFER_LENGTH || m_buffer_size == 0) + m_buffer_size = ATAPI_BUFFER_LENGTH; + + if (m_feature & ATAPI_FEATURES_FLAG_OVL) + { + printf( "ATAPI_FEATURES_FLAG_OVL not supported\n" ); + } + + switch (m_phase) + { + case SCSI_PHASE_DATAOUT: + wait_buffer(); + break; + + case SCSI_PHASE_DATAIN: + /// TODO: delay data + fill_buffer(); + break; + + default: + m_cylinder_low = 0; + m_cylinder_high = 0; + m_sector_count = ATAPI_INTERRUPT_REASON_IO | ATAPI_INTERRUPT_REASON_CD; + set_irq(ASSERT_LINE); + break; + } + + m_packet = 0; + } + else + { + switch (m_command) + { + case IDE_COMMAND_PACKET: + WriteData( &m_buffer[0], m_buffer_size ); + m_data_size -= m_buffer_size; + + wait_buffer(); + break; + } + } +} + +void atapi_hle_device::fill_buffer() +{ + switch (m_command) + { + case IDE_COMMAND_PACKET: + if (m_buffer_size >= m_data_size) + { + m_buffer_size = m_data_size; + } + else if (m_buffer_size & 1) + { + m_buffer_size--; + } + + m_cylinder_low = m_buffer_size & 0xff; + m_cylinder_high = m_buffer_size >> 8; + + if (m_buffer_size > 0) + { + ReadData( &m_buffer[0], m_buffer_size ); + m_data_size -= m_buffer_size; + + m_status |= IDE_STATUS_DRQ; + m_sector_count = ATAPI_INTERRUPT_REASON_IO; + + if (m_feature & ATAPI_FEATURES_FLAG_DMA) + { + set_dmarq(ASSERT_LINE); + } + else + { + set_irq(ASSERT_LINE); + } + } + else + { + m_sector_count = ATAPI_INTERRUPT_REASON_IO | ATAPI_INTERRUPT_REASON_CD; + set_irq(ASSERT_LINE); + } + break; + + case IDE_COMMAND_IDENTIFY_PACKET_DEVICE: + m_cylinder_low = 0; + m_cylinder_high = 0; + + m_sector_count = ATAPI_INTERRUPT_REASON_IO | ATAPI_INTERRUPT_REASON_CD; + set_irq(ASSERT_LINE); + break; + } +} + +void atapi_hle_device::wait_buffer() +{ + if (m_buffer_size >= m_data_size) + { + m_buffer_size = m_data_size; + } + else if (m_buffer_size & 1) + { + m_buffer_size--; + } + + m_cylinder_low = m_buffer_size & 0xff; + m_cylinder_high = m_buffer_size >> 8; + + if (m_buffer_size > 0) + { + m_status |= IDE_STATUS_DRQ; + m_sector_count = 0; + + if (m_feature & ATAPI_FEATURES_FLAG_DMA) + { + set_dmarq(ASSERT_LINE); + } + else + { + set_irq(ASSERT_LINE); + } + } + else + { + m_sector_count = ATAPI_INTERRUPT_REASON_IO | ATAPI_INTERRUPT_REASON_CD; + set_irq(ASSERT_LINE); + } +} + +void atapi_hle_device::signature() +{ + // TODO: IDENTIFY DEVICE & READ SECTORS writes signature too. + m_sector_count = 1; + m_sector_number = 1; + m_cylinder_low = 0x14; + m_cylinder_high = 0xeb; + + m_device_head &= IDE_DEVICE_HEAD_DRV; +} + +void atapi_hle_device::process_command() +{ + m_packet = 0; + + switch (m_command) + { + case IDE_COMMAND_DEVICE_RESET: + soft_reset(); + break; + + case IDE_COMMAND_PACKET: + m_packet = 1; + + if (packet_command_length() == PACKET_COMMAND_LENGTH_16) + { + m_buffer_size = 16; + } + else + { + m_buffer_size = 12; + } + + m_status |= IDE_STATUS_DRQ; + m_sector_count = ATAPI_INTERRUPT_REASON_CD; + + if (packet_command_response() == PACKET_COMMAND_RESPONSE_INTRQ) + { + set_irq(ASSERT_LINE); + } + break; + + case IDE_COMMAND_IDENTIFY_PACKET_DEVICE: + identify_packet_device(); + + for( int w = 0; w < 256; w++ ) + { + m_buffer[w * 2] = m_identify_buffer[ w ] & 0xff; + m_buffer[(w * 2) + 1] = m_identify_buffer[ w ] >> 8; + } + + m_buffer_size = 512; + + m_error = 0; + m_cylinder_low = m_buffer_size & 0xff; + m_cylinder_high = m_buffer_size >> 8; + + m_status |= IDE_STATUS_DRQ; + m_sector_count = ATAPI_INTERRUPT_REASON_IO; + set_irq(ASSERT_LINE); + break; + + case IDE_COMMAND_IDENTIFY_DEVICE: + /// TODO: busy + signature(); + m_status |= IDE_STATUS_ERR; + m_error = IDE_ERROR_ABRT; + set_irq(ASSERT_LINE); + break; + + case IDE_COMMAND_CHECK_POWER_MODE: + m_status = IDE_STATUS_DRDY; + m_sector_count = 0xff; // Power mode: 0x00 = Standby, 0x80 = Idle mode, 0xff = Active mode or Idle mode + set_irq(ASSERT_LINE); + break; + + default: + ata_hle_device::process_command(); + break; + } +} + +void atapi_hle_device::finished_command() +{ + switch (m_command) + { + default: + ata_hle_device::finished_command(); + break; + } +} + +atapi_hle_device::packet_command_length_t atapi_hle_device::packet_command_length() +{ + return (packet_command_length_t) (m_identify_buffer[0] & 3); +} + +atapi_hle_device::packet_command_response_t atapi_hle_device::packet_command_response() +{ + return (packet_command_response_t) ((m_identify_buffer[0] >> 5 ) & 3); +} diff --git a/src/devices/machine/atapihle.h b/src/devices/machine/atapihle.h new file mode 100644 index 00000000000..4d33e60a378 --- /dev/null +++ b/src/devices/machine/atapihle.h @@ -0,0 +1,78 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/*************************************************************************** + + atapihle.h + + ATAPI High Level Emulation + +***************************************************************************/ + +#pragma once + +#ifndef __ATAPIHLE_H__ +#define __ATAPIHLE_H__ + +#include "atahle.h" +#include "t10spc.h" + +class atapi_hle_device : public ata_hle_device, + public virtual t10spc +{ +public: + atapi_hle_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock,const char *shortname, const char *source); + + enum atapi_features_flag_t + { + ATAPI_FEATURES_FLAG_DMA = 0x01, + ATAPI_FEATURES_FLAG_OVL = 0x02 + }; + + enum atapi_interrupt_reason_t + { + ATAPI_INTERRUPT_REASON_CD = 0x01, // 1 = command, 0 = data + ATAPI_INTERRUPT_REASON_IO = 0x02, // 1 = to host, 0 = to device + ATAPI_INTERRUPT_REASON_REL = 0x04, // 1 = bus release + ATAPI_INTERRUPT_REASON_TAG = 0xf8 // command tag + }; + + enum packet_command_length_t + { + PACKET_COMMAND_LENGTH_12, + PACKET_COMMAND_LENGTH_16 + }; + + enum packet_command_response_t + { + PACKET_COMMAND_RESPONSE_DRQ_3MS, + PACKET_COMMAND_RESPONSE_INTRQ, + PACKET_COMMAND_RESPONSE_DRQ_50US + }; + +protected: + virtual void device_start(); + virtual void device_reset(); + + virtual int sector_length() { return ATAPI_BUFFER_LENGTH; } + virtual void process_buffer(); + virtual void fill_buffer(); + virtual bool is_ready() { return false; } + virtual void signature(); + virtual void process_command(); + virtual void finished_command(); + + virtual void identify_packet_device() = 0; + + packet_command_length_t packet_command_length(); + packet_command_response_t packet_command_response(); + +private: + void wait_buffer(); + + int m_packet; + int m_data_size; + + static const int ATAPI_BUFFER_LENGTH = 0xf800; +}; + +#endif diff --git a/src/devices/machine/autoconfig.c b/src/devices/machine/autoconfig.c new file mode 100644 index 00000000000..84b51cd8c24 --- /dev/null +++ b/src/devices/machine/autoconfig.c @@ -0,0 +1,169 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best +/*************************************************************************** + + Amiga Autoconfig + +***************************************************************************/ + +#include "autoconfig.h" + + +//************************************************************************** +// CONSTANTS & MACROS +//************************************************************************** + +#define VERBOSE 1 + + +//************************************************************************** +// CONSTRUCTOR +//************************************************************************** + +amiga_autoconfig::amiga_autoconfig() +{ + memset(m_cfg, 0xff, sizeof(m_cfg)); + + // interrupt status register, not inverted + m_cfg[0x20] = 0; + m_cfg[0x21] = 0; +} + +amiga_autoconfig::~amiga_autoconfig() +{ +} + + +//************************************************************************** +// AUTOCONFIG INFO SETTERS +//************************************************************************** + +void amiga_autoconfig::autoconfig_board_type(board_type type) +{ + m_cfg[0x00] &= 0x3000; + m_cfg[0x00] |= (type << 2) << 12; +} + +void amiga_autoconfig::autoconfig_board_size(board_size size) +{ + m_cfg[0x01] &= 0x8000; + m_cfg[0x01] |= (size << 0) << 12; +} + +void amiga_autoconfig::autoconfig_rom_vector_valid(bool state) +{ + m_cfg[0x00] &= 0xe000; + m_cfg[0x00] |= (state ? 0x01 : 0x00) << 12; +} + +void amiga_autoconfig::autoconfig_link_into_memory(bool state) +{ + m_cfg[0x00] &= 0xd000; + m_cfg[0x00] |= (state ? 0x02 : 0x00) << 12; +} + +void amiga_autoconfig::autoconfig_multi_device(bool state) +{ + m_cfg[0x01] &= 0x7000; + m_cfg[0x01] |= (state ? 0x08 : 0x00) << 12; +} + +void amiga_autoconfig::autoconfig_8meg_preferred(bool state) +{ + m_cfg[0x04] &= 0x7000; + m_cfg[0x04] |= (state ? 0x08 : 0x00) << 12; +} + +void amiga_autoconfig::autoconfig_can_shutup(bool state) +{ + m_cfg[0x04] &= 0xb000; + m_cfg[0x04] |= (state ? 0x04 : 0x00) << 12; +} + +void amiga_autoconfig::autoconfig_product(UINT8 data) +{ + m_cfg[0x02] = ~((data & 0xf0) >> 4) << 12; + m_cfg[0x03] = ~((data & 0x0f) >> 0) << 12; +} + +void amiga_autoconfig::autoconfig_manufacturer(UINT16 data) +{ + m_cfg[0x08] = ~((data & 0xf000) >> 12) << 12; + m_cfg[0x09] = ~((data & 0x0f00) >> 8) << 12; + m_cfg[0x0a] = ~((data & 0x00f0) >> 4) << 12; + m_cfg[0x0b] = ~((data & 0x000f) >> 0) << 12; +} + +void amiga_autoconfig::autoconfig_serial(UINT32 data) +{ + m_cfg[0x0c] = ~((data & 0xf0000000) >> 28) << 12; + m_cfg[0x0d] = ~((data & 0x0f000000) >> 24) << 12; + m_cfg[0x0e] = ~((data & 0x00f00000) >> 20) << 12; + m_cfg[0x0f] = ~((data & 0x000f0000) >> 16) << 12; + m_cfg[0x10] = ~((data & 0x0000f000) >> 12) << 12; + m_cfg[0x11] = ~((data & 0x00000f00) >> 8) << 12; + m_cfg[0x12] = ~((data & 0x000000f0) >> 4) << 12; + m_cfg[0x13] = ~((data & 0x0000000f) >> 0) << 12; +} + +void amiga_autoconfig::autoconfig_rom_vector(UINT16 data) +{ + m_cfg[0x14] = ~((data & 0xf000) >> 12) << 12; + m_cfg[0x15] = ~((data & 0x0f00) >> 8) << 12; + m_cfg[0x16] = ~((data & 0x00f0) >> 4) << 12; + m_cfg[0x17] = ~((data & 0x000f) >> 0) << 12; +} + + +//************************************************************************** +// MEMORY INTERFACE +//************************************************************************** + +READ16_MEMBER( amiga_autoconfig::autoconfig_read ) +{ + UINT16 data = m_cfg[offset] | 0x0fff; + + if (VERBOSE && !space.debugger_access()) + logerror("autoconfig_read %04x @ %02x [mask = %04x]\n", data, offset, mem_mask); + + return data; +} + +WRITE16_MEMBER( amiga_autoconfig::autoconfig_write ) +{ + if (VERBOSE && !space.debugger_access()) + logerror("autoconfig_write %04x @ %02x [mask = %04x]\n", data, offset, mem_mask); + + switch (offset) + { + case 0x20: + // user-definable + break; + + case 0x21: + // bit 0 = interrupt enable + // bit 1 = user-definable + // bit 2 = local reset + // bit 3 = user-definable + break; + + case 0x24: + // base address register + m_cfg[0x24] = data & 0xf000; + autoconfig_base_address((m_cfg[0x24] << 8) | (m_cfg[0x25] << 4)); + break; + + case 0x25: + // latch low-nibble + m_cfg[0x25] = data & 0xf000; + break; + + case 0x26: + // shut-up register + autoconfig_base_address(0); + break; + + case 0x27: + break; + } +} diff --git a/src/devices/machine/autoconfig.h b/src/devices/machine/autoconfig.h new file mode 100644 index 00000000000..042d3886189 --- /dev/null +++ b/src/devices/machine/autoconfig.h @@ -0,0 +1,74 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best +/*************************************************************************** + + Amiga Autoconfig + +***************************************************************************/ + +#pragma once + +#ifndef __AUTOCONFIG_H__ +#define __AUTOCONFIG_H__ + +#include "emu.h" + +class amiga_autoconfig +{ +public: + amiga_autoconfig(); + virtual ~amiga_autoconfig(); + + // read from autoconfig space + DECLARE_READ16_MEMBER( autoconfig_read ); + + // write to autoconfig space + DECLARE_WRITE16_MEMBER( autoconfig_write ); + +protected: + enum board_type + { + BOARD_TYPE_ZORRO3 = 2, + BOARD_TYPE_ZORRO2 = 3 + }; + + enum board_size + { + BOARD_SIZE_8M = 0, + BOARD_SIZE_64K = 1, + BOARD_SIZE_128K = 2, + BOARD_SIZE_256K = 3, + BOARD_SIZE_512K = 4, + BOARD_SIZE_1M = 5, + BOARD_SIZE_2M = 6, + BOARD_SIZE_4M = 7 + }; + + // board type & size + void autoconfig_board_type(board_type type); + void autoconfig_board_size(board_size size); + + // various flags + void autoconfig_rom_vector_valid(bool state); + void autoconfig_link_into_memory(bool state); + void autoconfig_multi_device(bool state); + void autoconfig_8meg_preferred(bool state); + void autoconfig_can_shutup(bool state); + + // product number, manufacturer number, serial number + void autoconfig_product(UINT8 data); + void autoconfig_manufacturer(UINT16 data); + void autoconfig_serial(UINT32 data); + + // rom vector + void autoconfig_rom_vector(UINT16 data); + + // called once we have received a valid base address from the host system + virtual void autoconfig_base_address(offs_t address) = 0; + +private: + // configuration information about our autoconfig board, 256 nibbles + UINT16 m_cfg[0x40]; +}; + +#endif // __AUTOCONFIG_H__ diff --git a/src/devices/machine/ay31015.c b/src/devices/machine/ay31015.c new file mode 100644 index 00000000000..2ecd3f311f7 --- /dev/null +++ b/src/devices/machine/ay31015.c @@ -0,0 +1,753 @@ +// license:BSD-3-Clause +// copyright-holders:Robbbert +/**************************************************************************** + + ay31015.c by Robbbert, May 2008. Bugs fixed by Judge. + + Code for the AY-3-1014A, AY-3-1015(D), AY-5-1013(A), and AY-6-1013 UARTs + The HD6402 UART is compatible with the AY-3-1015 UART. + + This is cycle-accurate according to the specifications. + + It supports independent receive and transmit clocks, + and transmission and reception can occur simultaneously if desired. + +***************************************************************************** + +Differences between the chip types: +- All units have pull-up resistors on the inputs, except for the AY-3-1014A which is CMOS-compatible. +- AY-3-1014A and AY-3-1015 - 1.5 stop bits mode available. +- Max baud rate of 30k, except AY-5-1013 which has 20k. +- AY-5-1013 has extended temperature ratings. +- AY-5-1013 and AY-6-1013 require a -12 volt supply on pin 2. Pin is not used otherwise. +- AY-5-1013 and AY-6-1013 do not reset the received data register when XR pin is used. + +****************************************************************************** + +It is not clear in the documentation as to which settings will reset the device. + To be safe, we will always reset whenever the control register changes. + + Also, it not clear exactly what happens under various error conditions. + +******************************************************************************** + +Device Data: + +* Common Controls: +-- Pin 1 - Vcc - 5 volts +-- Pin 2 - not used (on AY-5-1013 and AY-6-1013 this is Voo = -12 volts) +-- Pin 3 - Gnd - 0 volts +-- Pin 21 - XR - External Reset - resets all registers to initial state except for the control register +-- Pin 35 - NP - No Parity - "1" will kill any parity processing +-- Pin 36 - TSB - Number of Stop Bits - "0" = 1 stop bit; "1" = 2 stop bits. If "1", and 5 bits per character, then we have 1.5 stop bits +-- pin 37 - NB1 +-- pin 38 - NB2 - Number of bits per character = NB1 + (NB2 * 2) + 5 +-- pin 39 - EPS - Odd or Even Parity Select - "0" = Odd parity; "1" = Even parity. Has no effect if NP is high. +-- Pin 34 - CS - Control Strobe - Read NP, TSB, EPS, NB1, NB2 into the control register. + +Format of data stream: +Start bit (low), Bit 0, Bit 1... highest bit, Parity bit (if enabled), 1-2 stop bits (high) + + +* Receiver Controls: +-- Pin 17 - RCP - Clock which is 16x the desired baud rate +-- Pin 20 - SI - Serial input stream - "1" = Mark (waiting for input), "0" = Space (Start bit) initiates the transfer of a byte +-- Pin 4 - RDE - "0" causes the received data to appear on RD1 to RD8. +-- Pins 5 to 12 - RD8 to RD1 - These are the data lines (bits 7 to 0). Data is right-justified. +-- Pin 16 - SWE - Status word enable - causes the status bits (PE, FE, OR, DAV, TBMT) to appear at the pins. +-- Pin 19 - DAV - "1" indicates that a byte has been received by the UART, and should now be accepted by the computer +-- Pin 18 - RDAV - "0" will force DAV low. +-- Pin 13 - PE - Parity error - "1" indicates that a parity error occurred +-- Pin 14 - FE - Framing error - "1" Indicates that the stop bit was missing +-- Pin 15 - OR - overrun - "1" indicates that a new character has become available before the computer had accepted the previous character + +* Transmitter controls: +-- Pin 40 - TCP - Clock which is 16x the desired baud rate +-- Pin 25 - SO - Serial output stream - it will stay at "1" while no data is being transmitted +-- Pins 26 to 33 - DB1 to DB8 - These are the data lines containing the byte to be sent +-- Pin 23 - DS - Data Strobe - "0" will copy DB1 to DB8 into the transmit buffer +-- Pin 22 - TBMT - Transmit buffer Empty - "1" indicates to the computer that another byte may be sent to the UART +-- Pin 24 - EOC - End of Character - "0" means that a character is being sent. + +******************************************* COMMON CONTROLS ********************************************************/ + +#include "emu.h" +#include "ay31015.h" + + + +/* control reg */ +#define CONTROL_NB1 0x01 +#define CONTROL_NB2 0x02 +#define CONTROL_TSB 0x04 +#define CONTROL_EPS 0x08 +#define CONTROL_NP 0x10 + + +/* status reg */ +#define STATUS_TBMT 0x01 +#define STATUS_DAV 0x02 +#define STATUS_OR 0x04 +#define STATUS_FE 0x08 +#define STATUS_PE 0x10 +#define STATUS_EOC 0x20 + + + +const device_type AY31015 = &device_creator; +const device_type AY51013 = &device_creator; + +ay31015_device::ay31015_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + m_control_reg(0), + m_status_reg(0), + m_second_stop_bit(0), + m_total_pulses(0), + m_internal_sample(0), + m_rx_data(0), + m_rx_buffer(0), + m_rx_bit_count(0), + m_rx_parity(0), + m_rx_pulses(0), + m_rx_clock(0), + m_rx_timer(NULL), + m_tx_data(0), + m_tx_buffer(0), + m_tx_parity(0), + m_tx_pulses(0), + m_tx_clock(0), + m_tx_timer(NULL), + m_read_si_cb(*this), + m_write_so_cb(*this), + m_status_changed_cb(*this) +{ + for (int i = 0; i < 41; i++) + m_pins[i] = 0; +} + +ay31015_device::ay31015_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, AY31015, "AY-3-1015", tag, owner, clock, "ay31015", __FILE__), + m_control_reg(0), + m_status_reg(0), + m_second_stop_bit(0), + m_total_pulses(0), + m_internal_sample(0), + m_rx_data(0), + m_rx_buffer(0), + m_rx_bit_count(0), + m_rx_parity(0), + m_rx_pulses(0), + m_rx_clock(0), + m_rx_timer(NULL), + m_tx_data(0), + m_tx_buffer(0), + m_tx_parity(0), + m_tx_pulses(0), + m_tx_clock(0), + m_tx_timer(NULL), + m_read_si_cb(*this), + m_write_so_cb(*this), + m_status_changed_cb(*this) +{ + for (int i = 0; i < 41; i++) + m_pins[i] = 0; +} + +ay51013_device::ay51013_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : ay31015_device(mconfig, AY31015, "AY-5-1013", tag, owner, clock, "ay51013", __FILE__) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void ay31015_device::device_start() +{ + m_read_si_cb.resolve(); + m_write_so_cb.resolve(); + m_status_changed_cb.resolve(); + + m_rx_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(ay31015_device::rx_process),this)); + m_tx_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(ay31015_device::tx_process),this)); + + update_rx_timer(); + update_tx_timer(); + + save_item(NAME(m_pins)); + save_item(NAME(m_control_reg)); + save_item(NAME(m_status_reg)); + save_item(NAME(m_second_stop_bit)); + save_item(NAME(m_total_pulses)); + save_item(NAME(m_internal_sample)); + + save_item(NAME(m_rx_state)); + save_item(NAME(m_rx_data)); + save_item(NAME(m_rx_buffer)); + save_item(NAME(m_rx_bit_count)); + save_item(NAME(m_rx_parity)); + save_item(NAME(m_rx_pulses)); + save_item(NAME(m_rx_clock)); + + save_item(NAME(m_tx_state)); + save_item(NAME(m_tx_data)); + save_item(NAME(m_tx_buffer)); + save_item(NAME(m_tx_parity)); + save_item(NAME(m_tx_pulses)); + save_item(NAME(m_tx_clock)); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void ay31015_device::device_reset() +{ + m_control_reg = 0; + m_rx_data = 0; + + internal_reset(); +} + + +inline UINT8 ay31015_device::get_si() +{ + if (!m_read_si_cb.isnull()) + m_pins[AY31015_SI] = m_read_si_cb(0) ? 1 : 0; + + return m_pins[AY31015_SI]; +} + + +inline void ay31015_device::set_so( int data ) +{ + m_pins[AY31015_SO] = data ? 1 : 0; + + if (!m_write_so_cb.isnull()) + m_write_so_cb((offs_t)0, m_pins[AY31015_SO]); +} + + +inline int ay31015_device::update_status_pin( UINT8 reg_bit, ay31015_output_pin_t pin ) +{ + int new_value = (m_status_reg & reg_bit) ? 1 : 0; + + if (new_value == m_pins[pin]) + return 0; + + m_pins[pin] = new_value; + return 1; +} + + +/*------------------------------------------------- + ay31015_update_status_pins - Update the status pins +-------------------------------------------------*/ + +void ay31015_device::update_status_pins() +{ + int status_pins_changed = 0; + + /* Should status pins be updated? */ + if (!m_pins[AY31015_SWE]) + { + status_pins_changed += update_status_pin(STATUS_PE, AY31015_PE); + status_pins_changed += update_status_pin(STATUS_FE, AY31015_FE); + status_pins_changed += update_status_pin(STATUS_OR, AY31015_OR); + status_pins_changed += update_status_pin(STATUS_DAV, AY31015_DAV); + status_pins_changed += update_status_pin(STATUS_TBMT, AY31015_TBMT); + } + status_pins_changed += update_status_pin(STATUS_EOC, AY31015_EOC); + + if (status_pins_changed && !m_status_changed_cb.isnull()) + { + m_status_changed_cb((offs_t)0, status_pins_changed); + } +} + + +/*************************************************** RECEIVE CONTROLS *************************************************/ + + +/*------------------------------------------------- + ay31015_rx_process - convert serial to parallel +-------------------------------------------------*/ + +TIMER_CALLBACK_MEMBER( ay31015_device::rx_process ) +{ + switch (m_rx_state) + { + case PREP_TIME: // assist sync by ensuring high bit occurs + m_rx_pulses--; + if (get_si()) + m_rx_state = IDLE; + return; + + case IDLE: + m_rx_pulses--; + if (!get_si()) + { + m_rx_state = START_BIT; + m_rx_pulses = 16; + } + return; + + case START_BIT: + m_rx_pulses--; + if (m_rx_pulses == 8) // start bit must be low at sample time + { + if (get_si()) + m_rx_state = IDLE; + } + else + if (!m_rx_pulses) // end of start bit + { + m_rx_state = PROCESSING; + m_rx_pulses = m_total_pulses; + m_rx_bit_count = 0; + m_rx_parity = 0; + m_rx_data = 0; + } + return; + + case PROCESSING: + m_rx_pulses--; + if (!m_rx_pulses) // end of a byte + { + m_rx_pulses = 16; + if (m_control_reg & CONTROL_NP) // see if we need to get a parity bit + m_rx_state = FIRST_STOP_BIT; + else + m_rx_state = PARITY_BIT; + } + else + if (!(m_rx_pulses & 15)) // end of a bit + m_rx_bit_count++; + else + if ((m_rx_pulses & 15) == 8) // sample input stream + { + m_internal_sample = get_si(); + m_rx_parity ^= m_internal_sample; // calculate cumulative parity + m_rx_data |= m_internal_sample << m_rx_bit_count; + } + return; + + case PARITY_BIT: + m_rx_pulses--; + + if (m_rx_pulses == 8) // sample input stream + { + m_rx_parity ^= get_si(); // calculate cumulative parity + } + else + if (!m_rx_pulses) // end of a byte + { + m_rx_pulses = 16; + m_rx_state = FIRST_STOP_BIT; + + if ((!(m_control_reg & CONTROL_EPS)) && (m_rx_parity)) + m_rx_parity = 0; // odd parity, ok + else + if ((m_control_reg & CONTROL_EPS) && (!m_rx_parity)) + m_rx_parity = 0; // even parity, ok + else + m_rx_parity = 1; // parity error + } + return; + + case FIRST_STOP_BIT: + m_rx_pulses--; + if (m_rx_pulses == 8) // sample input stream + m_internal_sample = get_si(); + else + if (m_rx_pulses == 7) // set error flags + { + if (!m_internal_sample) + { + m_status_reg |= STATUS_FE; // framing error - the stop bit not high + m_rx_state = PREP_TIME; // lost sync - start over + // return; + } + else + m_status_reg &= ~STATUS_FE; + + if ((m_rx_parity) && (!(m_control_reg & CONTROL_NP))) + m_status_reg |= STATUS_PE; // parity error + else + m_status_reg &= ~STATUS_PE; + + if (m_status_reg & STATUS_DAV) + m_status_reg |= STATUS_OR; // overrun error - previous byte still in buffer + else + m_status_reg &= ~STATUS_OR; + + m_rx_buffer = m_rx_data; // bring received byte out for computer to read + + update_status_pins(); + } + else + if (m_rx_pulses == 6) + { + m_status_reg |= STATUS_DAV; // tell computer that new byte is ready + update_status_pins(); + } + else + if (m_rx_pulses == 4) + { + if (m_second_stop_bit) + { + /* We should wait for the full first stop bit and + the beginning of the second stop bit */ + m_rx_state = SECOND_STOP_BIT; + m_rx_pulses += m_second_stop_bit - 7; + } + else + { + /* We have seen a STOP bit, go back to PREP_TIME */ + m_rx_state = PREP_TIME; + } + } + return; + + case SECOND_STOP_BIT: + m_rx_pulses--; + if (!m_rx_pulses) + m_rx_state = PREP_TIME; + return; + + } +} + + +/*************************************************** TRANSMIT CONTROLS *************************************************/ + + +/*------------------------------------------------- + ay31015_tx_process - convert parallel to serial +-------------------------------------------------*/ + +TIMER_CALLBACK_MEMBER( ay31015_device::tx_process ) +{ + UINT8 t1; + switch (m_tx_state) + { + case IDLE: + if (!(m_status_reg & STATUS_TBMT)) + { + m_tx_state = PREP_TIME; // When idle, see if a byte has been sent to us + m_tx_pulses = 1; + } + return; + + case PREP_TIME: // This phase lets the transmitter regain sync after an idle period + m_tx_pulses--; + if (!m_tx_pulses) + { + m_tx_state = START_BIT; + m_tx_pulses = 16; + } + return; + + case START_BIT: + if (m_tx_pulses == 16) // beginning of start bit + { + m_tx_data = m_tx_buffer; // load the shift register + m_status_reg |= STATUS_TBMT; // tell computer that another byte can be sent to uart + set_so(0); /* start bit begins now (we are "spacing") */ + m_status_reg &= ~STATUS_EOC; // we are no longer idle + m_tx_parity = 0; + update_status_pins(); + } + + m_tx_pulses--; + if (!m_tx_pulses) // end of start bit + { + m_tx_state = PROCESSING; + m_tx_pulses = m_total_pulses; + } + return; + + case PROCESSING: + if (!(m_tx_pulses & 15)) // beginning of a data bit + { + if (m_tx_data & 1) + { + set_so(1); + m_tx_parity++; // calculate cumulative parity + } + else + set_so(0); + + m_tx_data >>= 1; // adjust the shift register + } + + m_tx_pulses--; + if (!m_tx_pulses) // all data bits sent + { + m_tx_pulses = 16; + if (m_control_reg & CONTROL_NP) // see if we need to make a parity bit + m_tx_state = FIRST_STOP_BIT; + else + m_tx_state = PARITY_BIT; + } + + return; + + case PARITY_BIT: + if (m_tx_pulses == 16) + { + t1 = (m_control_reg & CONTROL_EPS) ? 0 : 1; + t1 ^= (m_tx_parity & 1); + if (t1) + set_so(1); /* extra bit to set the correct parity */ + else + set_so(0); /* it was already correct */ + } + + m_tx_pulses--; + if (!m_tx_pulses) + { + m_tx_state = FIRST_STOP_BIT; + m_tx_pulses = 16; + } + return; + + case FIRST_STOP_BIT: + if (m_tx_pulses == 16) + set_so(1); /* create a stop bit (marking and soon idle) */ + m_tx_pulses--; + if (!m_tx_pulses) + { + m_status_reg |= STATUS_EOC; // character is completely sent + if (m_second_stop_bit) + { + m_tx_state = SECOND_STOP_BIT; + m_tx_pulses = m_second_stop_bit; + } + else + if (m_status_reg & STATUS_TBMT) + m_tx_state = IDLE; // if nothing to send, go idle + else + { + m_tx_pulses = 16; + m_tx_state = START_BIT; // otherwise immediately start next byte + } + update_status_pins(); + } + return; + + case SECOND_STOP_BIT: + m_tx_pulses--; + if (!m_tx_pulses) + { + if (m_status_reg & STATUS_TBMT) + m_tx_state = IDLE; // if nothing to send, go idle + else + { + m_tx_pulses = 16; + m_tx_state = START_BIT; // otherwise immediately start next byte + } + } + return; + + } +} + + +/*------------------------------------------------- + ay31015_reset - reset internal state +-------------------------------------------------*/ + +void ay31015_device::internal_reset() +{ + /* total pulses = 16 * data-bits */ + UINT8 t1; + + if (m_control_reg & CONTROL_NB2) + t1 = (m_control_reg & CONTROL_NB1) ? 8 : 7; + else + t1 = (m_control_reg & CONTROL_NB1) ? 6 : 5; + + m_total_pulses = t1 << 4; /* total clock pulses to load a byte */ + m_second_stop_bit = ((m_control_reg & CONTROL_TSB) ? 16 : 0); /* 2nd stop bit */ + if ((t1 == 5) && (m_second_stop_bit == 16)) + m_second_stop_bit = 8; /* 5 data bits and 2 stop bits = 1.5 stop bits */ + m_status_reg = STATUS_EOC | STATUS_TBMT; + m_tx_data = 0; + m_rx_state = PREP_TIME; + m_tx_state = IDLE; + m_pins[AY31015_SI] = 1; + set_so(1); + + m_rx_data = 0; +} + + +void ay51013_device::internal_reset() +{ + /* total pulses = 16 * data-bits */ + UINT8 t1; + + if (m_control_reg & CONTROL_NB2) + t1 = (m_control_reg & CONTROL_NB1) ? 8 : 7; + else + t1 = (m_control_reg & CONTROL_NB1) ? 6 : 5; + + m_total_pulses = t1 << 4; /* total clock pulses to load a byte */ + m_second_stop_bit = ((m_control_reg & CONTROL_TSB) ? 16 : 0); /* 2nd stop bit */ + if ((t1 == 5) && (m_second_stop_bit == 16)) + m_second_stop_bit = 8; /* 5 data bits and 2 stop bits = 1.5 stop bits */ + m_status_reg = STATUS_EOC | STATUS_TBMT; + m_tx_data = 0; + m_rx_state = PREP_TIME; + m_tx_state = IDLE; + m_pins[AY31015_SI] = 1; + set_so(1); + // no m_rx_data = 0 in this case +} + +/*------------------------------------------------- + ay31015_transfer_control_pins - transfers contents of controls pins to the control register +-------------------------------------------------*/ + +void ay31015_device::transfer_control_pins() +{ + UINT8 control = 0; + + control |= m_pins[AY31015_NP ] ? CONTROL_NP : 0; + control |= m_pins[AY31015_TSB] ? CONTROL_TSB : 0; + control |= m_pins[AY31015_NB1] ? CONTROL_NB1 : 0; + control |= m_pins[AY31015_NB2] ? CONTROL_NB2 : 0; + control |= m_pins[AY31015_EPS] ? CONTROL_EPS : 0; + + if (m_control_reg != control) + { + m_control_reg = control; + internal_reset(); + } +} + + +/*------------------------------------------------- + ay31015_set_input_pin - set an input pin +-------------------------------------------------*/ +void ay31015_device::set_input_pin( ay31015_input_pin_t pin, int data ) +{ + data = data ? 1 : 0; + + switch (pin) + { + case AY31015_SWE: + m_pins[pin] = data; + update_status_pins(); + break; + case AY31015_RDAV: + m_pins[pin] = data; + if (!data) + { + m_status_reg &= ~STATUS_DAV; + m_pins[AY31015_DAV] = 0; + } + break; + case AY31015_SI: + m_pins[pin] = data; + break; + case AY31015_XR: + m_pins[pin] = data; + if (data) + internal_reset(); + break; + case AY31015_CS: + case AY31015_NP: + case AY31015_TSB: + case AY31015_NB1: + case AY31015_NB2: + case AY31015_EPS: + m_pins[pin] = data; + if (m_pins[AY31015_CS]) + transfer_control_pins(); + break; + } +} + + +/*------------------------------------------------- + ay31015_get_output_pin - get the status of an output pin +-------------------------------------------------*/ + +int ay31015_device::get_output_pin( ay31015_output_pin_t pin ) +{ + return m_pins[pin]; +} + + +inline void ay31015_device::update_rx_timer() +{ + if (m_rx_clock > 0.0) + { + m_rx_timer->adjust(attotime::from_hz(m_rx_clock), 0, attotime::from_hz(m_rx_clock)); + } + else + { + m_rx_timer->enable(0); + } +} + + +inline void ay31015_device::update_tx_timer() +{ + if (m_tx_clock > 0.0) + { + m_tx_timer->adjust(attotime::from_hz(m_tx_clock), 0, attotime::from_hz(m_tx_clock)); + } + else + { + m_tx_timer->enable(0); + } +} + + +/*------------------------------------------------- + ay31015_set_receiver_clock - set receive clock +-------------------------------------------------*/ + +void ay31015_device::set_receiver_clock( double new_clock ) +{ + m_rx_clock = new_clock; + update_rx_timer(); +} + + +/*------------------------------------------------- + ay31015_set_transmitter_clock - set transmit clock +-------------------------------------------------*/ + +void ay31015_device::set_transmitter_clock( double new_clock ) +{ + m_tx_clock = new_clock; + update_tx_timer(); +} + + +/*------------------------------------------------- + ay31015_get_received_data - return a byte to the computer +-------------------------------------------------*/ + +UINT8 ay31015_device::get_received_data() +{ + return m_rx_buffer; +} + + +/*------------------------------------------------- + ay31015_set_transmit_data - accept a byte to transmit, if able +-------------------------------------------------*/ +void ay31015_device::set_transmit_data( UINT8 data ) +{ + if (m_status_reg & STATUS_TBMT) + { + m_tx_buffer = data; + m_status_reg &= ~STATUS_TBMT; + update_status_pins(); + } +} diff --git a/src/devices/machine/ay31015.h b/src/devices/machine/ay31015.h new file mode 100644 index 00000000000..2f2ae33eca8 --- /dev/null +++ b/src/devices/machine/ay31015.h @@ -0,0 +1,198 @@ +// license:BSD-3-Clause +// copyright-holders:Robbbert +/* ay31015.h + + Written for MESS by Robbbert on May 29th, 2008. + +*/ + +#ifndef __AY31015_H_ +#define __AY31015_H_ + +/*************************************************************************** + TYPE DEFINITIONS +***************************************************************************/ + + +enum ay31015_input_pin_t +{ + AY31015_SWE = 16, /* -SWE - Pin 16 - Status word enable */ + AY31015_RDAV = 18, /* -RDAV - Pin 18 - Reset data available */ + AY31015_SI = 20, /* SI - Pin 20 - Serial input */ + AY31015_XR = 21, /* XR - Pin 21 - External reset */ + AY31015_CS = 34, /* CS - Pin 34 - Control strobe */ + AY31015_NP = 35, /* NP - Pin 35 - No parity */ + AY31015_TSB = 36, /* TSB - Pin 36 - Number of stop bits */ + AY31015_NB1 = 37, /* NB1 - Pin 37 - Number of bits #1 */ + AY31015_NB2 = 38, /* NB2 - Pin 38 - Number of bits #2 */ + AY31015_EPS = 39 /* EPS - Pin 39 - Odd/Even parity select */ +}; + + +enum ay31015_output_pin_t +{ + AY31015_PE = 13, /* PE - Pin 13 - Parity error */ + AY31015_FE = 14, /* FE - Pin 14 - Framing error */ + AY31015_OR = 15, /* OR - Pin 15 - Over-run */ + AY31015_DAV = 19, /* DAV - Pin 19 - Data available */ + AY31015_TBMT = 22, /* TBMT - Pin 22 - Transmit buffer empty */ + AY31015_EOC = 24, /* EOC - Pin 24 - End of character */ + AY31015_SO = 25 /* SO - Pin 25 - Serial output */ +}; + + +/*************************************************************************** + DEVICE INTERFACE +***************************************************************************/ + +enum state_t +{ + IDLE, + START_BIT, + PROCESSING, + PARITY_BIT, + FIRST_STOP_BIT, + SECOND_STOP_BIT, + PREP_TIME +}; + +ALLOW_SAVE_TYPE(state_t); + +class ay31015_device : public device_t +{ +public: + ay31015_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + ay31015_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + ~ay31015_device() {} + + static void set_tx_clock(device_t &device, double tx_clock) { downcast(device).m_tx_clock = tx_clock; } + static void set_rx_clock(device_t &device, double rx_clock) { downcast(device).m_rx_clock = rx_clock; } + template static devcb_base &set_read_si_callback(device_t &device, _Object object) { return downcast(device).m_read_si_cb.set_callback(object); } + template static devcb_base &set_write_so_callback(device_t &device, _Object object) { return downcast(device).m_write_so_cb.set_callback(object); } + template static devcb_base &set_status_changed_callback(device_t &device, _Object object) { return downcast(device).m_status_changed_cb.set_callback(object); } + + /* Set an input pin */ + void set_input_pin( ay31015_input_pin_t pin, int data ); + + + /* Get an output pin */ + int get_output_pin( ay31015_output_pin_t pin ); + + + /* Set a new transmitter clock (new_clock is in Hz) */ + void set_transmitter_clock( double new_clock ); + + + /* Set a new receiver clock (new_clock is in Hz) */ + void set_receiver_clock( double new_clock ); + + + /* Reead the received data */ + /* The received data is available on RD8-RD1 (pins 5-12) */ + UINT8 get_received_data(); + + + /* Set the transmitter buffer */ + /* The data to transmit is set on DB1-DB8 (pins 26-33) */ + void set_transmit_data( UINT8 data ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + virtual void internal_reset(); + + // internal state + inline UINT8 get_si(); + inline void set_so(int data); + inline int update_status_pin(UINT8 reg_bit, ay31015_output_pin_t pin); + void update_status_pins(); + void transfer_control_pins(); + inline void update_rx_timer(); + inline void update_tx_timer(); + TIMER_CALLBACK_MEMBER(rx_process); + TIMER_CALLBACK_MEMBER(tx_process); + + int m_pins[41]; + + UINT8 m_control_reg; + UINT8 m_status_reg; + UINT16 m_second_stop_bit; // 0, 8, 16 + UINT16 m_total_pulses; // bits * 16 + UINT8 m_internal_sample; + + state_t m_rx_state; + UINT8 m_rx_data; // byte being received + UINT8 m_rx_buffer; // received byte waiting to be accepted by computer + UINT8 m_rx_bit_count; + UINT8 m_rx_parity; + UINT16 m_rx_pulses; // total pulses left + double m_rx_clock; /* RCP - pin 17 */ + emu_timer *m_rx_timer; + + state_t m_tx_state; + UINT8 m_tx_data; // byte being sent + UINT8 m_tx_buffer; // next byte to send + UINT8 m_tx_parity; + UINT16 m_tx_pulses; // total pulses left + double m_tx_clock; /* TCP - pin 40 */ + emu_timer *m_tx_timer; + + devcb_read8 m_read_si_cb; /* SI - pin 20 - This will be called whenever the SI pin is sampled. Optional */ + devcb_write8 m_write_so_cb; /* SO - pin 25 - This will be called whenever data is put on the SO pin. Optional */ + devcb_write8 m_status_changed_cb; /* This will be called whenever one of the status pins may have changed. Optional */ +}; + +class ay51013_device : public ay31015_device +{ +public: + ay51013_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual void internal_reset(); + +}; + +extern const device_type AY31015; // For AY-3-1014A, AY-3-1015(D) and HD6402 variants +extern const device_type AY51013; // For AY-3-1014, AY-5-1013 and AY-6-1013 variants + + + +/*************************************************************************** + DEVICE CONFIGURATION MACROS + ***************************************************************************/ + + +#define MCFG_AY31015_TX_CLOCK(_txclk) \ + ay31015_device::set_tx_clock(*device, _txclk); + +#define MCFG_AY31015_RX_CLOCK(_rxclk) \ + ay31015_device::set_rx_clock(*device, _rxclk); + +#define MCFG_AY31015_READ_SI_CB(_devcb) \ + devcb = &ay31015_device::set_read_si_callback(*device, DEVCB_##_devcb); + +#define MCFG_AY31015_WRITE_SO_CB(_devcb) \ + devcb = &ay31015_device::set_write_so_callback(*device, DEVCB_##_devcb); + +#define MCFG_AY31015_STATUS_CHANGED_CB(_devcb) \ + devcb = &ay31015_device::set_status_changed_callback(*device, DEVCB_##_devcb); + + +#define MCFG_AY51013_TX_CLOCK(_txclk) \ + ay51013_device::set_tx_clock(*device, _txclk); + +#define MCFG_AY51013_RX_CLOCK(_rxclk) \ + ay51013_device::set_rx_clock(*device, _rxclk); + +#define MCFG_AY51013_READ_SI_CB(_devcb) \ + devcb = &ay51013_device::set_read_si_callback(*device, DEVCB_##_devcb); + +#define MCFG_AY51013_WRITE_SO_CB(_devcb) \ + devcb = &ay51013_device::set_write_so_callback(*device, DEVCB_##_devcb); + +#define MCFG_AY51013_STATUS_CHANGED_CB(_devcb) \ + devcb = &ay51013_device::set_status_changed_callback(*device, DEVCB_##_devcb); + +#endif diff --git a/src/devices/machine/bankdev.c b/src/devices/machine/bankdev.c new file mode 100644 index 00000000000..1a600527511 --- /dev/null +++ b/src/devices/machine/bankdev.c @@ -0,0 +1,90 @@ +// license:BSD-3-Clause +// copyright-holders:smf +#include "bankdev.h" + +// device type definition +const device_type ADDRESS_MAP_BANK = &device_creator; + +address_map_bank_device::address_map_bank_device( const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock ) + : device_t(mconfig, ADDRESS_MAP_BANK, "Address Map Bank", tag, owner, clock, "address_map_bank", __FILE__), + device_memory_interface(mconfig, *this), + m_endianness(ENDIANNESS_NATIVE), + m_databus_width(0), + m_addrbus_width(32), + m_stride(1), + m_offset(0) +{ +} + +DEVICE_ADDRESS_MAP_START(amap8, 8, address_map_bank_device) + AM_RANGE(0x00000000, 0xffffffff) AM_READWRITE(read8, write8) +ADDRESS_MAP_END + +DEVICE_ADDRESS_MAP_START(amap16, 16, address_map_bank_device) + AM_RANGE(0x00000000, 0xffffffff) AM_READWRITE(read16, write16) +ADDRESS_MAP_END + +DEVICE_ADDRESS_MAP_START(amap32, 32, address_map_bank_device) + AM_RANGE(0x00000000, 0xffffffff) AM_READWRITE(read32, write32) +ADDRESS_MAP_END + +DEVICE_ADDRESS_MAP_START(amap64, 64, address_map_bank_device) + AM_RANGE(0x00000000, 0xffffffff) AM_READWRITE(read64, write64) +ADDRESS_MAP_END + +WRITE8_MEMBER(address_map_bank_device::write8) +{ + m_program->write_byte(m_offset + offset, data); +} + +WRITE16_MEMBER(address_map_bank_device::write16) +{ + m_program->write_word(m_offset + (offset * 2), data, mem_mask); +} + +WRITE32_MEMBER(address_map_bank_device::write32) +{ + m_program->write_dword(m_offset + (offset * 4), data, mem_mask); +} + +WRITE64_MEMBER(address_map_bank_device::write64) +{ + m_program->write_qword(m_offset + (offset * 8), data, mem_mask); +} + +READ8_MEMBER(address_map_bank_device::read8) +{ + return m_program->read_byte(m_offset + offset); +} + +READ16_MEMBER(address_map_bank_device::read16) +{ + return m_program->read_word(m_offset + (offset * 2), mem_mask); +} + +READ32_MEMBER(address_map_bank_device::read32) +{ + return m_program->read_dword(m_offset + (offset * 4), mem_mask); +} + +READ64_MEMBER(address_map_bank_device::read64) +{ + return m_program->read_qword(m_offset + (offset * 8), mem_mask); +} + +void address_map_bank_device::device_config_complete() +{ + m_program_config = address_space_config( "program", m_endianness, m_databus_width, m_addrbus_width ); +} + +void address_map_bank_device::device_start() +{ + m_program = &space(AS_PROGRAM); + + save_item(NAME(m_offset)); +} + +void address_map_bank_device::set_bank(offs_t bank) +{ + m_offset = bank * m_stride; +} diff --git a/src/devices/machine/bankdev.h b/src/devices/machine/bankdev.h new file mode 100644 index 00000000000..54359fc6282 --- /dev/null +++ b/src/devices/machine/bankdev.h @@ -0,0 +1,75 @@ +// license:BSD-3-Clause +// copyright-holders:smf +#pragma once + +#ifndef __BANKDEV_H__ +#define __BANKDEV_H__ + +#include "emu.h" + +#define MCFG_ADDRESS_MAP_BANK_ENDIANNESS(_endianness) \ + address_map_bank_device::set_endianness(*device, _endianness); + +#define MCFG_ADDRESS_MAP_BANK_DATABUS_WIDTH(_databus_width) \ + address_map_bank_device::set_databus_width(*device, _databus_width); + +#define MCFG_ADDRESS_MAP_BANK_ADDRBUS_WIDTH(_addrbus_width) \ + address_map_bank_device::set_addrbus_width(*device, _addrbus_width); + +#define MCFG_ADDRESS_MAP_BANK_STRIDE(_stride) \ + address_map_bank_device::set_stride(*device, _stride); + +class address_map_bank_device : + public device_t, + public device_memory_interface +{ +public: + // construction/destruction + address_map_bank_device( const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock ); + + // static configuration helpers + static void set_endianness(device_t &device, endianness_t endianness) { downcast(device).m_endianness = endianness; } + static void set_databus_width(device_t &device, UINT8 databus_width) { downcast(device).m_databus_width = databus_width; } + static void set_addrbus_width(device_t &device, UINT8 addrbus_width) { downcast(device).m_addrbus_width = addrbus_width; } + static void set_stride(device_t &device, UINT32 stride) { downcast(device).m_stride = stride; } + + DECLARE_ADDRESS_MAP(amap8, 8); + DECLARE_ADDRESS_MAP(amap16, 16); + DECLARE_ADDRESS_MAP(amap32, 32); + DECLARE_ADDRESS_MAP(amap64, 64); + + DECLARE_WRITE8_MEMBER(write8); + DECLARE_WRITE16_MEMBER(write16); + DECLARE_WRITE32_MEMBER(write32); + DECLARE_WRITE64_MEMBER(write64); + + DECLARE_READ8_MEMBER(read8); + DECLARE_READ16_MEMBER(read16); + DECLARE_READ32_MEMBER(read32); + DECLARE_READ64_MEMBER(read64); + + void set_bank(offs_t offset); + +protected: + virtual void device_start(); + virtual void device_config_complete(); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const { return (spacenum == AS_PROGRAM) ? &m_program_config : NULL; } + +private: + // internal state + endianness_t m_endianness; + UINT8 m_databus_width; + UINT8 m_addrbus_width; + UINT32 m_stride; + address_space_config m_program_config; + address_space *m_program; + offs_t m_offset; +}; + + +// device type definition +extern const device_type ADDRESS_MAP_BANK; + +#endif diff --git a/src/devices/machine/bcreader.c b/src/devices/machine/bcreader.c new file mode 100644 index 00000000000..5a5df7fb452 --- /dev/null +++ b/src/devices/machine/bcreader.c @@ -0,0 +1,330 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*************************************************************************** + + bcreader.c + + Generic barcode reader emulation. + + This device only provides the storage of the actual barcode, entered + by the user via Internal UI, both as a raw strip of pixels (up to 95, + for an EAN-13 barcode) and as an array of 0-9 digits. + + It is up to the driver to handle the serial transfer of the data to + the emulated machine, depending on the used protocol + + E.g. Bandai Datach games directly read the raw pixel sequence of + black/white bars; + OTOH Barcode Battle (used by Barcode World for NES and a few SNES + titles) sends the digits as sequences of 20 bytes (13 for the code, + suitably padded for shorted codes, followed by a signature) and the + actual serial transmission to the console is up to the slot device + connected to the NES/SNES controller port (yet to be emulated, in this + case) + + Note: we currently support the following barcode formats + * UPC-A: 12 digits + * EAN-13: 13 digits (extension of the former) + * EAN-8: 8 digits (same encoding as UPC-A, but 4-digits blocks instead + of 6-digits blocks) + Notice that since EAN-13 is an extension of UPC-A, we just treat UPC-A + as an EAN-13 code with leading '0'. If any barcode reader shall be found + which supports the older format only, this shall be changed + + + TODO: add support for UPC-E barcodes? these are 8 digits barcodes with 17 + black stripes (they are compressed UPC-A codes). Datach reader does not + support these, so it is low priority + + + TODO 2: verify barcode checksum in is_valid() and not only length, so + that we can then use the actual last digit in the decode function below, + rather than replacing it with the checksum value + + + TODO 3: possibly the white spaces before the actual barcode (see the + 61 white pixels sent by read_pixel() before and after the code), shall + be moved to the specific implementations to emulate different "sensitivity" + of the readers? Bandai Datach seems to need at least 32 pixels... + +***************************************************************************/ + +#include "emu.h" +#include "bcreader.h" + +// device type definition +const device_type BARCODE_READER = &device_creator; + +//------------------------------------------------- +// barcode_reader_device - constructor +//------------------------------------------------- + +barcode_reader_device::barcode_reader_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, BARCODE_READER, "Barcode Reader", tag, owner, clock, "bcreader", __FILE__) + , m_byte_length(0) + , m_pixel_length(0) + , m_byte_count(0) + , m_pixel_count(0) + , m_new_code(0) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void barcode_reader_device::device_start() +{ + save_item(m_byte_data, "DATACH/m_byte_data"); + save_item(m_pixel_data, "DATACH/m_pixel_data"); + save_item(m_byte_length, "DATACH/m_byte_length"); + save_item(m_pixel_length, "DATACH/m_pixel_length"); + save_item(m_byte_count, "DATACH/m_byte_count"); + save_item(m_pixel_count, "DATACH/m_pixel_count"); + save_item(m_new_code, "DATACH/m_new_code"); +} + + +//------------------------------------------------- +// Barcode Decoding - convert the entered sequence +// of digits into a sequence of B/W pixels (the +// actual bars) - each digit corresponds to 7 pixels +// 0 is black, 1 is white +//------------------------------------------------- + +// Left Odd +static const UINT8 bcread_data_LO[10][7] = +{ + {1, 1, 1, 0, 0, 1, 0}, {1, 1, 0, 0, 1, 1, 0}, + {1, 1, 0, 1, 1, 0, 0}, {1, 0, 0, 0, 0, 1, 0}, + {1, 0, 1, 1, 1, 0, 0}, {1, 0, 0, 1, 1, 1, 0}, + {1, 0, 1, 0, 0, 0, 0}, {1, 0, 0, 0, 1, 0, 0}, + {1, 0, 0, 1, 0, 0, 0}, {1, 1, 1, 0, 1, 0, 0} +}; + +// Left Even +static const UINT8 bcread_data_LE[10][7] = +{ + {1, 0, 1, 1, 0, 0, 0}, {1, 0, 0, 1, 1, 0, 0}, + {1, 1, 0, 0, 1, 0, 0}, {1, 0, 1, 1, 1, 1, 0}, + {1, 1, 0, 0, 0, 1, 0}, {1, 0, 0, 0, 1, 1, 0}, + {1, 1, 1, 1, 0, 1, 0}, {1, 1, 0, 1, 1, 1, 0}, + {1, 1, 1, 0, 1, 1, 0}, {1, 1, 0, 1, 0, 0, 0} +}; + +// Right Even +static const UINT8 bcread_data_RE[10][7] = +{ + {0, 0, 0, 1, 1, 0, 1}, {0, 0, 1, 1, 0, 0, 1}, + {0, 0, 1, 0, 0, 1, 1}, {0, 1, 1, 1, 1, 0, 1}, + {0, 1, 0, 0, 0, 1, 1}, {0, 1, 1, 0, 0, 0, 1}, + {0, 1, 0, 1, 1, 1, 1}, {0, 1, 1, 1, 0, 1, 1}, + {0, 1, 1, 0, 1, 1, 1}, {0, 0, 0, 1, 0, 1, 1} +}; + +// EAN-13 added an extra digit to determine +// the parity type of the first digits block +static const UINT8 bcread_parity_type[10][6] = +{ + {1, 1, 1, 1, 1, 1}, {1, 1, 0, 1, 0, 0}, + {1, 1, 0, 0, 1, 0}, {1, 1, 0, 0, 0, 1}, + {1, 0, 1, 1, 0, 0}, {1, 0, 0, 1, 1, 0}, + {1, 0, 0, 0, 1, 1}, {1, 0, 1, 0, 1, 0}, + {1, 0, 1, 0, 0, 1}, {1, 0, 0, 1, 0, 1} +}; + + +void barcode_reader_device::decode(int len) +{ + int output = 0; + int sum = 0; + + if (len == 13) + { + // UPC-A and EAN-13 + + m_pixel_data[output++] = 0; + m_pixel_data[output++] = 1; + m_pixel_data[output++] = 0; + + for (int i = 1; i < 7; i++) + { + if (bcread_parity_type[m_byte_data[0]][i - 1]) + { + for (int j = 0; j < 7; j++) + m_pixel_data[output++] = bcread_data_LO[m_byte_data[i]][j]; + } + else + { + for (int j = 0; j < 7; j++) + m_pixel_data[output++] = bcread_data_LE[m_byte_data[i]][j]; + } + } + + m_pixel_data[output++] = 1; + m_pixel_data[output++] = 0; + m_pixel_data[output++] = 1; + m_pixel_data[output++] = 0; + m_pixel_data[output++] = 1; + + for (int i = 7; i < 12; i++) + { + for (int j = 0; j < 7; j++) + m_pixel_data[output++] = bcread_data_RE[m_byte_data[i]][j]; + } + + // ignore the last digit and compute it as checksum of the first 12 + for (int i = 0; i < 12; i++) + sum += (i & 1) ? (m_byte_data[i] * 3) : (m_byte_data[i] * 1); + } + else if (len == 8) + { + // EAN-8 (same encoding as UPC-A, but only 4+4 digits, instead of 6+6) + + m_pixel_data[output++] = 0; + m_pixel_data[output++] = 1; + m_pixel_data[output++] = 0; + + for (int i = 0; i < 4; i++) + { + for (int j = 0; j < 7; j++) + m_pixel_data[output++] = bcread_data_LO[m_byte_data[i]][j]; + } + + m_pixel_data[output++] = 1; + m_pixel_data[output++] = 0; + m_pixel_data[output++] = 1; + m_pixel_data[output++] = 0; + m_pixel_data[output++] = 1; + + for (int i = 4; i < 7; i++) + { + for (int j = 0; j < 7; j++) + m_pixel_data[output++] = bcread_data_RE[m_byte_data[i]][j]; + } + + // ignore the last digit and compute it as checksum of the first 12 + for (int i = 0; i < 7; i++) + sum += (i & 1) ? (m_byte_data[i] * 1) : (m_byte_data[i] * 3); + } + + if (m_pixel_data) + { + sum = (10 - (sum % 10)) % 10; + if (sum != m_byte_data[len - 1]) + logerror("WARNING: wrong checksum detected in the barcode! chksum %d last digit %d\n", + sum, m_byte_data[len - 1]); + + for (int i = 0; i < 7; i++) + m_pixel_data[output++] = bcread_data_RE[sum][i]; + + m_pixel_data[output++] = 0; + m_pixel_data[output++] = 1; + m_pixel_data[output++] = 0; + } + + m_byte_length = len; + m_pixel_length = output; + +// printf("byte len %d - pixel len\n", m_byte_length, m_pixel_length); +} + + +//------------------------------------------------- +// write_code - invoked by UI, stores the barcode +// both as an array of digits and as a sequence +// of B/W pixels (the actual bars) +//------------------------------------------------- + +void barcode_reader_device::write_code(const char *barcode, int len) +{ + int shift = 0; + int deconde_len = len; + + // len has already been checked to be one of the following: 8, 12 or 13 + + if (deconde_len == 12) + { + // convert UPC-A to EAN-13 + shift = 1; + deconde_len = 13; + m_byte_data[0] = 0; + } + + for (int i = 0; i < len; i++) + m_byte_data[i+shift] = barcode[i] - '0'; + + decode(deconde_len); + + m_new_code = 1; +} + + +//------------------------------------------------- +// read_code - accessor for drivers which read +// the codes by bytes +//------------------------------------------------- + +UINT8 barcode_reader_device::read_code() +{ + if (m_new_code) + { + if (m_byte_count < m_byte_length) + { + UINT8 val = m_byte_data[m_byte_count]; + m_byte_count++; + return val; + } + else + { + m_byte_count = 0; + m_new_code = 0; + return 0; + } + } + + // no pending transfer + return 0; +} + +//------------------------------------------------- +// read_pixel - accessor for drivers which read +// the codes by pixels +//------------------------------------------------- + +int barcode_reader_device::read_pixel() +{ + if (m_new_code) + { + // start of card: 61 white pixels + if (m_pixel_count < 61) + { + m_pixel_count++; + return 1; + } + // barcode: approx 95 pixels for B/W bars + else if (m_pixel_count < 61 + m_pixel_length) + { + // actual barcode starts here + int val = m_pixel_data[m_pixel_count - 61]; + m_pixel_count++; + return val; + } + // end of card: 61 white pixels + else if (m_pixel_count < 61 + m_pixel_length + 61) + { + m_pixel_count++; + return 1; + } + // finished scan, erase code + else + { + m_pixel_count = 0; + m_new_code = 0; + return 0; + } + } + + // no pending transfer = black pixel = 0 + return 0; +} diff --git a/src/devices/machine/bcreader.h b/src/devices/machine/bcreader.h new file mode 100644 index 00000000000..23b80ddab70 --- /dev/null +++ b/src/devices/machine/bcreader.h @@ -0,0 +1,60 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/********************************************************************* + + bcreader.h + + Generic barcode reader emulation. + +*********************************************************************/ + +#ifndef __BCREADER_H_ +#define __BCREADER_H_ + +#define MCFG_BARCODE_READER_ADD( _tag ) \ + MCFG_DEVICE_ADD( _tag, BARCODE_READER, 0 ) + +#define MCFG_BARCODE_READER_REMOVE( _tag ) \ + MCFG_DEVICE_REMOVE( _tag ) + + +// ======================> barcode_reader_device + +class barcode_reader_device : public device_t +{ +public: + // construction/destruction + barcode_reader_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + void write_code(const char *barcode, int len); + int get_pending_code() { return m_new_code; } + int get_byte_length() { return m_byte_length; } + UINT8 read_code(); + int read_pixel(); + + // TODO: add checksum validation! + bool is_valid(int len) { return (len != 12 && len != 13 && len != 8) ? FALSE : TRUE; } + void decode(int len); + +protected: + // device-level overrides + virtual void device_start(); + + UINT8 m_byte_data[13]; + UINT8 m_pixel_data[100]; + int m_byte_length; + int m_pixel_length; + int m_byte_count; + int m_pixel_count; + int m_new_code; +}; + + +// device type definition +extern const device_type BARCODE_READER; + +// device type iterator +typedef device_type_iterator<&device_creator, barcode_reader_device> barcode_reader_device_iterator; + + +#endif diff --git a/src/devices/machine/buffer.c b/src/devices/machine/buffer.c new file mode 100644 index 00000000000..6b2058c6937 --- /dev/null +++ b/src/devices/machine/buffer.c @@ -0,0 +1,17 @@ +// license:BSD-3-Clause +// copyright-holders:smf +#include "emu.h" +#include "buffer.h" + +const device_type INPUT_BUFFER = &device_creator; + +input_buffer_device::input_buffer_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, INPUT_BUFFER, "Input Buffer", tag, owner, clock, "input_buffer", __FILE__), + m_input_data(0xff) +{ +} + +void input_buffer_device::device_start() +{ + save_item(NAME(m_input_data)); +} diff --git a/src/devices/machine/buffer.h b/src/devices/machine/buffer.h new file mode 100644 index 00000000000..cab1b9914f4 --- /dev/null +++ b/src/devices/machine/buffer.h @@ -0,0 +1,31 @@ +// license:BSD-3-Clause +// copyright-holders:smf +#ifndef __BUFFER_H__ +#define __BUFFER_H__ + +class input_buffer_device : public device_t +{ +public: + input_buffer_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + UINT8 read() { return m_input_data; } + DECLARE_READ8_MEMBER(read) { return read(); } + + DECLARE_WRITE_LINE_MEMBER(write_bit0) { if (state) m_input_data |= 0x01; else m_input_data &= ~0x01; } + DECLARE_WRITE_LINE_MEMBER(write_bit1) { if (state) m_input_data |= 0x02; else m_input_data &= ~0x02; } + DECLARE_WRITE_LINE_MEMBER(write_bit2) { if (state) m_input_data |= 0x04; else m_input_data &= ~0x04; } + DECLARE_WRITE_LINE_MEMBER(write_bit3) { if (state) m_input_data |= 0x08; else m_input_data &= ~0x08; } + DECLARE_WRITE_LINE_MEMBER(write_bit4) { if (state) m_input_data |= 0x10; else m_input_data &= ~0x10; } + DECLARE_WRITE_LINE_MEMBER(write_bit5) { if (state) m_input_data |= 0x20; else m_input_data &= ~0x20; } + DECLARE_WRITE_LINE_MEMBER(write_bit6) { if (state) m_input_data |= 0x40; else m_input_data &= ~0x40; } + DECLARE_WRITE_LINE_MEMBER(write_bit7) { if (state) m_input_data |= 0x80; else m_input_data &= ~0x80; } + +protected: + virtual void device_start(); + + UINT8 m_input_data; +}; + +extern const device_type INPUT_BUFFER; + +#endif diff --git a/src/devices/machine/cdp1852.c b/src/devices/machine/cdp1852.c new file mode 100644 index 00000000000..7a91e4060c3 --- /dev/null +++ b/src/devices/machine/cdp1852.c @@ -0,0 +1,187 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + RCA CDP1852 Byte-Wide Input/Output Port emulation + +**********************************************************************/ + +#include "cdp1852.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type CDP1852 = &device_creator; + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +enum +{ + MODE_INPUT = 0, + MODE_OUTPUT +}; + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// cdp1852_device - constructor +//------------------------------------------------- + +cdp1852_device::cdp1852_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, CDP1852, "CDP1852 I/O", tag, owner, clock, "cdp1852", __FILE__), + m_read_mode(*this), + m_write_sr(*this), + m_read_data(*this), + m_write_data(*this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void cdp1852_device::device_start() +{ + // resolve callbacks + m_read_mode.resolve_safe(0); + m_write_sr.resolve_safe(); + m_read_data.resolve_safe(0); + m_write_data.resolve_safe(); + + // allocate timers + if (clock() > 0) + { + m_scan_timer = timer_alloc(); + m_scan_timer->adjust(attotime::zero, 0, attotime::from_hz(clock())); + } + + // register for state saving + save_item(NAME(m_new_data)); + save_item(NAME(m_data)); + save_item(NAME(m_next_data)); + save_item(NAME(m_sr)); + save_item(NAME(m_next_sr)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void cdp1852_device::device_reset() +{ + // reset data register + m_data = 0; + + if (!m_read_mode()) + { + // reset service request flip-flop + set_sr_line(1); + } + else + { + // output data + m_write_data((offs_t)0, m_data); + + // reset service request flip-flop + set_sr_line(0); + } +} + + +//------------------------------------------------- +// device_timer - handler timer events +//------------------------------------------------- + +void cdp1852_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + if (!m_read_mode()) + { + // input data into register + m_data = m_read_data(0); + + // signal processor + set_sr_line(0); + } + else + { + if (m_new_data) + { + m_new_data = 0; + + // latch data into register + m_data = m_next_data; + + // output data + m_write_data((offs_t)0, m_data); + + // signal peripheral device + set_sr_line(1); + + m_next_sr = 0; + } + else + { + set_sr_line(m_next_sr); + } + } +} + + +//------------------------------------------------- +// set_sr_line - +//------------------------------------------------- + +void cdp1852_device::set_sr_line(int state) +{ + if (m_sr != state) + { + m_sr = state; + + m_write_sr(m_sr); + } +} + + +//------------------------------------------------- +// read - data read +//------------------------------------------------- + +READ8_MEMBER( cdp1852_device::read ) +{ + if (!m_read_mode() && !clock()) + { + // input data into register + m_data = m_read_data(0); + } + + set_sr_line(1); + + return m_data; +} + + +//------------------------------------------------- +// write - data write +//------------------------------------------------- + +WRITE8_MEMBER( cdp1852_device::write ) +{ + if (m_read_mode()) + { + m_next_data = data; + m_new_data = 1; + } +} diff --git a/src/devices/machine/cdp1852.h b/src/devices/machine/cdp1852.h new file mode 100644 index 00000000000..232e148e474 --- /dev/null +++ b/src/devices/machine/cdp1852.h @@ -0,0 +1,102 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + RCA CDP1852 Byte-Wide Input/Output Port emulation + +********************************************************************** + _____ _____ + CSI/_CSI 1 |* \_/ | 24 Vdd + MODE 2 | | 23 _SR/SR + DI0 3 | | 22 DI7 + DO0 4 | | 21 DO7 + DI1 5 | | 20 DI6 + DO1 6 | CDP1852 | 19 DO6 + DI2 7 | | 18 DI5 + DO2 8 | | 17 DO5 + DI3 9 | | 16 DI4 + DO3 10 | | 15 DO4 + CLOCK 11 | | 14 _CLEAR + Vss 12 |_____________| 13 CS2 + +**********************************************************************/ + +#pragma once + +#ifndef __CDP1852__ +#define __CDP1852__ + +#include "emu.h" + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_CDP1852_MODE_CALLBACK(_read) \ + devcb = &cdp1852_device::set_mode_rd_callback(*device, DEVCB_##_read); + +#define MCFG_CDP1852_SR_CALLBACK(_write) \ + devcb = &cdp1852_device::set_sr_wr_callback(*device, DEVCB_##_write); + +#define MCFG_CDP1852_DI_CALLBACK(_read) \ + devcb = &cdp1852_device::set_data_rd_callback(*device, DEVCB_##_read); + +#define MCFG_CDP1852_DO_CALLBACK(_write) \ + devcb = &cdp1852_device::set_data_wr_callback(*device, DEVCB_##_write); + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> cdp1852_device + +class cdp1852_device : public device_t +{ +public: + // construction/destruction + cdp1852_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + template static devcb_base &set_mode_rd_callback(device_t &device, _Object object) { return downcast(device).m_read_mode.set_callback(object); } + template static devcb_base &set_sr_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_sr.set_callback(object); } + template static devcb_base &set_data_rd_callback(device_t &device, _Object object) { return downcast(device).m_read_data.set_callback(object); } + template static devcb_base &set_data_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_data.set_callback(object); } + + DECLARE_READ8_MEMBER( read ); + DECLARE_WRITE8_MEMBER( write ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + +private: + void set_sr_line(int state); + + devcb_read_line m_read_mode; + devcb_write_line m_write_sr; + devcb_read8 m_read_data; + devcb_write8 m_write_data; + + int m_new_data; // new data written + UINT8 m_data; // data latch + UINT8 m_next_data; // next data + + int m_sr; // service request flag + int m_next_sr; // next value of service request flag + + // timers + emu_timer *m_scan_timer; +}; + + +// device type definition +extern const device_type CDP1852; + + + +#endif diff --git a/src/devices/machine/cdp1871.c b/src/devices/machine/cdp1871.c new file mode 100644 index 00000000000..e685f8c43ad --- /dev/null +++ b/src/devices/machine/cdp1871.c @@ -0,0 +1,290 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + RCA CDP1871 Keyboard Encoder emulation + +**********************************************************************/ + +#include "cdp1871.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type CDP1871 = &device_creator; + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +const UINT8 cdp1871_device::key_codes[4][11][8] = +{ + // normal + { + { 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37 }, + { 0x38, 0x39, 0x3a, 0x3b, 0x2c, 0x2d, 0x2e, 0x2f }, + { 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67 }, + { 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f }, + { 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77 }, + { 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f }, + { 0x20, 0xff, 0x0a, 0x1b, 0xff, 0x0d, 0xff, 0x7f }, + { 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87 }, + { 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f }, + { 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97 }, + { 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f } + }, + + // alpha + { + { 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37 }, + { 0x38, 0x39, 0x3a, 0x3b, 0x2c, 0x2d, 0x2e, 0x2f }, + { 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47 }, + { 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f }, + { 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57 }, + { 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f }, + { 0x20, 0xff, 0x0a, 0x1b, 0xff, 0x0d, 0xff, 0x7f }, + { 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87 }, + { 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f }, + { 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97 }, + { 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f } + }, + + // shift + { + { 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27 }, + { 0x28, 0x29, 0x2a, 0x2b, 0x3c, 0x3d, 0x3e, 0x3f }, + { 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47 }, + { 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f }, + { 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57 }, + { 0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f }, + { 0x20, 0xff, 0x0a, 0x1b, 0xff, 0x0d, 0xff, 0x7f }, + { 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87 }, + { 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f }, + { 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97 }, + { 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f } + }, + + // control + { + { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, + { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 }, + { 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }, + { 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17 }, + { 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f }, + { 0x20, 0xff, 0x0a, 0x1b, 0xff, 0x0d, 0xff, 0x7f }, + { 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87 }, + { 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f }, + { 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97 }, + { 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f } + } +}; + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// cdp1871_device - constructor +//------------------------------------------------- + +cdp1871_device::cdp1871_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, CDP1871, "RCA CDP1871", tag, owner, clock, "cdp1871", __FILE__), + m_read_d1(*this), + m_read_d2(*this), + m_read_d3(*this), + m_read_d4(*this), + m_read_d5(*this), + m_read_d6(*this), + m_read_d7(*this), + m_read_d8(*this), + m_read_d9(*this), + m_read_d10(*this), + m_read_d11(*this), + m_write_da(*this), + m_write_rpt(*this), + m_inhibit(false), + m_sense(0), + m_drive(0), + m_shift(0), + m_shift_latch(0), + m_control(0), + m_control_latch(0), + m_alpha(0), + m_da(0), + m_next_da(CLEAR_LINE), + m_rpt(0), + m_next_rpt(CLEAR_LINE) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void cdp1871_device::device_start() +{ + // resolve callbacks + m_read_d1.resolve_safe(0xff); + m_read_d2.resolve_safe(0xff); + m_read_d3.resolve_safe(0xff); + m_read_d4.resolve_safe(0xff); + m_read_d5.resolve_safe(0xff); + m_read_d6.resolve_safe(0xff); + m_read_d7.resolve_safe(0xff); + m_read_d8.resolve_safe(0xff); + m_read_d9.resolve_safe(0xff); + m_read_d10.resolve_safe(0xff); + m_read_d11.resolve_safe(0xff); + m_write_da.resolve_safe(); + m_write_rpt.resolve_safe(); + + // set initial values + change_output_lines(); + + // allocate timers + m_scan_timer = timer_alloc(); + m_scan_timer->adjust(attotime::zero, 0, attotime::from_hz(clock())); + + // register for state saving + save_item(NAME(m_inhibit)); + save_item(NAME(m_sense)); + save_item(NAME(m_drive)); + save_item(NAME(m_shift)); + save_item(NAME(m_shift_latch)); + save_item(NAME(m_control)); + save_item(NAME(m_control_latch)); + save_item(NAME(m_alpha)); + save_item(NAME(m_da)); + save_item(NAME(m_next_da)); + save_item(NAME(m_rpt)); + save_item(NAME(m_next_rpt)); +} + + +//------------------------------------------------- +// device_timer - handler timer events +//------------------------------------------------- + +void cdp1871_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + change_output_lines(); + clock_scan_counters(); + detect_keypress(); +} + + +//------------------------------------------------- +// change_output_lines - change output lines +//------------------------------------------------- + +void cdp1871_device::change_output_lines() +{ + if (m_next_da != m_da) + { + m_da = m_next_da; + + m_write_da(m_da); + } + + if (m_next_rpt != m_rpt) + { + m_rpt = m_next_rpt; + + m_write_rpt(m_rpt); + } +} + + +//------------------------------------------------- +// clock_scan_counters - clock the keyboard +// scan counters +//------------------------------------------------- + +void cdp1871_device::clock_scan_counters() +{ + if (!m_inhibit) + { + m_sense++; + + if (m_sense == 8) + { + m_sense = 0; + m_drive++; + + if (m_drive == 11) + { + m_drive = 0; + } + } + } +} + + +//------------------------------------------------- +// detect_keypress - detect key press +//------------------------------------------------- + +void cdp1871_device::detect_keypress() +{ + UINT8 data = 0; + + switch (m_drive) { + case 0: data = m_read_d1(0); break; + case 1: data = m_read_d2(0); break; + case 2: data = m_read_d3(0); break; + case 3: data = m_read_d4(0); break; + case 4: data = m_read_d5(0); break; + case 5: data = m_read_d6(0); break; + case 6: data = m_read_d7(0); break; + case 7: data = m_read_d8(0); break; + case 8: data = m_read_d9(0); break; + case 9: data = m_read_d10(0); break; + case 10: data = m_read_d11(0); break; + } + + if (data == (1 << m_sense)) + { + if (!m_inhibit) + { + m_shift_latch = m_shift; + m_control_latch = m_control; + m_inhibit = true; + m_next_da = ASSERT_LINE; + } + else + { + m_next_rpt = ASSERT_LINE; + } + } + else + { + m_inhibit = false; + m_next_rpt = CLEAR_LINE; + } +} + + +//------------------------------------------------- +// read - keyboard data read +//------------------------------------------------- + +READ8_MEMBER( cdp1871_device::read ) +{ + int table = 0; + + if (m_control_latch) table = 3; else if (m_shift_latch) table = 2; else if (m_alpha) table = 1; + + // reset DA on next TPB + m_next_da = CLEAR_LINE; + + return key_codes[table][m_drive][m_sense]; +} diff --git a/src/devices/machine/cdp1871.h b/src/devices/machine/cdp1871.h new file mode 100644 index 00000000000..651f9c4343d --- /dev/null +++ b/src/devices/machine/cdp1871.h @@ -0,0 +1,172 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + RCA CDP1871 Keyboard Encoder emulation + +********************************************************************** + _____ _____ + D1 1 |* \_/ | 40 Vdd + D2 2 | | 39 SHIFT + D3 3 | | 38 CONTROL + D4 4 | | 37 ALPHA + D5 5 | | 36 DEBOUNCE + D6 6 | | 35 _RPT + D7 7 | | 34 TPB + D8 8 | | 33 _DA + D9 9 | | 32 BUS 7 + D10 10 | CDP1871 | 31 BUS 6 + D11 11 | | 30 BUS 5 + S1 12 | | 29 BUS 4 + S2 13 | | 28 BUS 3 + S3 14 | | 27 BUS 2 + S4 15 | | 26 BUS 1 + S5 16 | | 25 BUS 0 + S6 17 | | 24 CS4 + S7 18 | | 23 CS3 + S8 19 | | 22 CS2 + Vss 20 |_____________| 21 _CS1 + +**********************************************************************/ + +#pragma once + +#ifndef __CDP1871__ +#define __CDP1871__ + +#include "emu.h" + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_CDP1871_D1_CALLBACK(_read) \ + devcb = &cdp1871_device::set_d1_rd_callback(*device, DEVCB_##_read); + +#define MCFG_CDP1871_D2_CALLBACK(_read) \ + devcb = &cdp1871_device::set_d2_rd_callback(*device, DEVCB_##_read); + +#define MCFG_CDP1871_D3_CALLBACK(_read) \ + devcb = &cdp1871_device::set_d3_rd_callback(*device, DEVCB_##_read); + +#define MCFG_CDP1871_D4_CALLBACK(_read) \ + devcb = &cdp1871_device::set_d4_rd_callback(*device, DEVCB_##_read); + +#define MCFG_CDP1871_D5_CALLBACK(_read) \ + devcb = &cdp1871_device::set_d5_rd_callback(*device, DEVCB_##_read); + +#define MCFG_CDP1871_D6_CALLBACK(_read) \ + devcb = &cdp1871_device::set_d6_rd_callback(*device, DEVCB_##_read); + +#define MCFG_CDP1871_D7_CALLBACK(_read) \ + devcb = &cdp1871_device::set_d7_rd_callback(*device, DEVCB_##_read); + +#define MCFG_CDP1871_D8_CALLBACK(_read) \ + devcb = &cdp1871_device::set_d8_rd_callback(*device, DEVCB_##_read); + +#define MCFG_CDP1871_D9_CALLBACK(_read) \ + devcb = &cdp1871_device::set_d9_rd_callback(*device, DEVCB_##_read); + +#define MCFG_CDP1871_D10_CALLBACK(_read) \ + devcb = &cdp1871_device::set_d10_rd_callback(*device, DEVCB_##_read); + +#define MCFG_CDP1871_D11_CALLBACK(_read) \ + devcb = &cdp1871_device::set_d11_rd_callback(*device, DEVCB_##_read); + +#define MCFG_CDP1871_DA_CALLBACK(_write) \ + devcb = &cdp1871_device::set_da_wr_callback(*device, DEVCB_##_write); + +#define MCFG_CDP1871_RPT_CALLBACK(_write) \ + devcb = &cdp1871_device::set_rpt_wr_callback(*device, DEVCB_##_write); + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> cdp1871_device + +class cdp1871_device : public device_t +{ +public: + // construction/destruction + cdp1871_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + template static devcb_base &set_d1_rd_callback(device_t &device, _Object object) { return downcast(device).m_read_d1.set_callback(object); } + template static devcb_base &set_d2_rd_callback(device_t &device, _Object object) { return downcast(device).m_read_d2.set_callback(object); } + template static devcb_base &set_d3_rd_callback(device_t &device, _Object object) { return downcast(device).m_read_d3.set_callback(object); } + template static devcb_base &set_d4_rd_callback(device_t &device, _Object object) { return downcast(device).m_read_d4.set_callback(object); } + template static devcb_base &set_d5_rd_callback(device_t &device, _Object object) { return downcast(device).m_read_d5.set_callback(object); } + template static devcb_base &set_d6_rd_callback(device_t &device, _Object object) { return downcast(device).m_read_d6.set_callback(object); } + template static devcb_base &set_d7_rd_callback(device_t &device, _Object object) { return downcast(device).m_read_d7.set_callback(object); } + template static devcb_base &set_d8_rd_callback(device_t &device, _Object object) { return downcast(device).m_read_d8.set_callback(object); } + template static devcb_base &set_d9_rd_callback(device_t &device, _Object object) { return downcast(device).m_read_d9.set_callback(object); } + template static devcb_base &set_d10_rd_callback(device_t &device, _Object object) { return downcast(device).m_read_d10.set_callback(object); } + template static devcb_base &set_d11_rd_callback(device_t &device, _Object object) { return downcast(device).m_read_d11.set_callback(object); } + template static devcb_base &set_da_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_da.set_callback(object); } + template static devcb_base &set_rpt_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_rpt.set_callback(object); } + + DECLARE_READ8_MEMBER( read ); + + DECLARE_READ_LINE_MEMBER( da_r ) { return m_da; } + DECLARE_READ_LINE_MEMBER( rpt_r ) { return m_rpt; } + + DECLARE_WRITE_LINE_MEMBER( shift_w ) { m_shift = state; } + DECLARE_WRITE_LINE_MEMBER( control_w ) { m_control = state; } + DECLARE_WRITE_LINE_MEMBER( alpha_w ) { m_alpha = state; } + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + void change_output_lines(); + void clock_scan_counters(); + void detect_keypress(); + +private: + devcb_read8 m_read_d1; + devcb_read8 m_read_d2; + devcb_read8 m_read_d3; + devcb_read8 m_read_d4; + devcb_read8 m_read_d5; + devcb_read8 m_read_d6; + devcb_read8 m_read_d7; + devcb_read8 m_read_d8; + devcb_read8 m_read_d9; + devcb_read8 m_read_d10; + devcb_read8 m_read_d11; + devcb_write_line m_write_da; + devcb_write_line m_write_rpt; + + bool m_inhibit; // scan counter clock inhibit + int m_sense; // sense input scan counter + int m_drive; // modifier inputs + + int m_shift; + int m_shift_latch; // latched shift modifier + int m_control; + int m_control_latch; // latched control modifier + int m_alpha; + + int m_da; // data available flag + int m_next_da; // next value of data available flag + int m_rpt; // repeat flag + int m_next_rpt; // next value of repeat flag + + // timers + emu_timer *m_scan_timer; // keyboard scan timer + + static const UINT8 key_codes[4][11][8]; +}; + + +// device type definition +extern const device_type CDP1871; + + + +#endif diff --git a/src/devices/machine/clock.c b/src/devices/machine/clock.c new file mode 100644 index 00000000000..9896bebabcc --- /dev/null +++ b/src/devices/machine/clock.c @@ -0,0 +1,68 @@ +// license:BSD-3-Clause +// copyright-holders:smf +#include "clock.h" + +const device_type CLOCK = &device_creator; + +clock_device::clock_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, CLOCK, "Clock", tag, owner, clock, "clock", __FILE__), + m_signal(0), + m_timer(NULL), + m_signal_handler(*this) +{ +} + +void clock_device::device_start() +{ + m_signal_handler.resolve(); + + save_item(NAME(m_signal)); +} + +void clock_device::device_clock_changed() +{ + update_timer(); +} + +attotime clock_device::period() +{ + if (m_clock > 0) + return attotime::from_hz(m_clock * 2); + + return attotime::never; +} + +void clock_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + m_signal = !m_signal; + m_signal_handler(m_signal); + + m_timer->adjust(period()); +} + +void clock_device::update_timer() +{ + if (!m_signal_handler.isnull() && m_clock > 0) + { + if (m_timer == NULL) + { + m_timer = timer_alloc(0); + m_timer->adjust(period()); + } + else + { + attotime next = period() - m_timer->elapsed(); + + if (next < attotime::zero) + { + next = attotime::zero; + } + + m_timer->adjust(next); + } + } + else if (m_timer != NULL) + { + m_timer->adjust(attotime::never); + } +} diff --git a/src/devices/machine/clock.h b/src/devices/machine/clock.h new file mode 100644 index 00000000000..9f3712327aa --- /dev/null +++ b/src/devices/machine/clock.h @@ -0,0 +1,37 @@ +// license:BSD-3-Clause +// copyright-holders:smf +#ifndef __CLOCK_H__ +#define __CLOCK_H__ + +#pragma once + +#include "emu.h" + +#define MCFG_CLOCK_SIGNAL_HANDLER(_devcb) \ + devcb = &clock_device::set_signal_handler(*device, DEVCB_##_devcb); + +class clock_device : public device_t +{ +public: + clock_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + template static devcb_base &set_signal_handler(device_t &device, _Object object) { return downcast(device).m_signal_handler.set_callback(object); } + +protected: + virtual void device_start(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + virtual void device_clock_changed(); + +private: + void update_timer(); + attotime period(); + + int m_signal; + emu_timer *m_timer; + + devcb_write_line m_signal_handler; +}; + +extern const device_type CLOCK; + +#endif diff --git a/src/devices/machine/com8116.c b/src/devices/machine/com8116.c new file mode 100644 index 00000000000..46a0ce83986 --- /dev/null +++ b/src/devices/machine/com8116.c @@ -0,0 +1,159 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + COM8116 Dual Baud Rate Generator (Programmable Divider) emulation + +**********************************************************************/ + +#include "com8116.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define LOG 0 + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +// device type definition +const device_type COM8116 = &device_creator; + + +const int com8116_device::divisors_16X_5_0688MHz[] = + { 6336, 4224, 2880, 2355, 2112, 1056, 528, 264, 176, 158, 132, 88, 66, 44, 33, 16 }; + +const int com8116_device::divisors_16X_4_9152MHz[] = + { 6144, 4096, 2793, 2284, 2048, 1024, 512, 256, 171, 154, 128, 85, 64, 43, 32, 16 }; + +const int com8116_device::divisors_32X_5_0688MHz[] = + { 3168, 2112, 1440, 1177, 1056, 792, 528, 264, 132, 88, 66, 44, 33, 22, 16, 8 }; + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// com8116_device - constructor +//------------------------------------------------- + +com8116_device::com8116_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, COM8116, "COM8116", tag, owner, clock, "com8116", __FILE__), + m_fx4_handler(*this), + m_fr_handler(*this), + m_ft_handler(*this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void com8116_device::device_start() +{ + // resolve callbacks + m_fx4_handler.resolve_safe(); + m_fr_handler.resolve_safe(); + m_ft_handler.resolve_safe(); + + // allocate timers + m_fx4_timer = timer_alloc(TIMER_FX4); + m_fx4_timer->adjust(attotime::from_hz((clock() / 4) * 2), 0, attotime::from_hz((clock() / 4)) * 2); + m_fr_timer = timer_alloc(TIMER_FR); + m_ft_timer = timer_alloc(TIMER_FT); + + m_fr_divisors = divisors_16X_5_0688MHz; + m_ft_divisors = divisors_16X_5_0688MHz; + + // register for state saving + save_item(NAME(m_fx4)); + save_item(NAME(m_fr)); + save_item(NAME(m_ft)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void com8116_device::device_reset() +{ + m_fx4 = 0; + m_fr = 0; + m_ft = 0; +} + + +//------------------------------------------------- +// device_timer - handler timer events +//------------------------------------------------- + +void com8116_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch (id) + { + case TIMER_FX4: + m_fx4 = !m_fx4; + m_fx4_handler(m_fx4); + break; + + case TIMER_FR: + m_fr = !m_fr; + m_fr_handler(m_fr); + break; + + case TIMER_FT: + m_ft = !m_ft; + m_ft_handler(m_ft); + break; + } +} + + +//------------------------------------------------- +// str_w - +//------------------------------------------------- + +void com8116_device::str_w(UINT8 data) +{ + int fr_divider = data & 0x0f; + int fr_clock = clock() / m_fr_divisors[fr_divider]; + + if (LOG) logerror("COM8116 '%s' Receiver Divisor Select %01x: %u (%u Hz)\n", tag(), data & 0x0f, m_fr_divisors[fr_divider], fr_clock); + + m_fr_timer->adjust(attotime::from_nsec(3500), 0, attotime::from_hz(fr_clock * 2)); +} + +WRITE8_MEMBER( com8116_device::str_w ) +{ + str_w(data); +} + + +//------------------------------------------------- +// stt_w - +//------------------------------------------------- + +void com8116_device::stt_w(UINT8 data) +{ + int ft_divider = data & 0x0f; + int ft_clock = clock() / m_ft_divisors[ft_divider]; + + if (LOG) logerror("COM8116 '%s' Transmitter Divisor Select %01x: %u (%u Hz)\n", tag(), data & 0x0f, m_ft_divisors[ft_divider], ft_clock); + + m_ft_timer->adjust(attotime::from_nsec(3500), 0, attotime::from_hz(ft_clock * 2)); +} + +WRITE8_MEMBER( com8116_device::stt_w ) +{ + stt_w(data); +} diff --git a/src/devices/machine/com8116.h b/src/devices/machine/com8116.h new file mode 100644 index 00000000000..a423f3782d7 --- /dev/null +++ b/src/devices/machine/com8116.h @@ -0,0 +1,104 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + COM8116 Dual Baud Rate Generator (Programmable Divider) emulation + +********************************************************************** + _____ _____ + XTAL/EXT1 1 |* \_/ | 18 XTAL/EXT2 + +5V 2 | | 17 fT + fR 3 | | 16 Ta + Ra 4 | COM8116 | 15 Tb + Rb 5 | COM8116T | 14 Tc + Rc 6 | COM8136 | 13 Td + Rd 7 | COM8136T | 12 STT + STR 8 | | 11 GND + NC 9 |_____________| 10 fX/4 + +**********************************************************************/ + +#pragma once + +#ifndef __COM8116__ +#define __COM8116__ + +#include "emu.h" + + + +///************************************************************************* +// INTERFACE CONFIGURATION MACROS +///************************************************************************* + +#define MCFG_COM8116_FX4_HANDLER(_devcb) \ + devcb = &com8116_device::set_fx4_handler(*device, DEVCB_##_devcb); + +#define MCFG_COM8116_FR_HANDLER(_devcb) \ + devcb = &com8116_device::set_fr_handler(*device, DEVCB_##_devcb); + +#define MCFG_COM8116_FT_HANDLER(_devcb) \ + devcb = &com8116_device::set_ft_handler(*device, DEVCB_##_devcb); + + +///************************************************************************* +// TYPE DEFINITIONS +///************************************************************************* + +// ======================> com8116_device + +class com8116_device : public device_t +{ +public: + // construction/destruction + com8116_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + template static devcb_base &set_fx4_handler(device_t &device, _Object object) { return downcast(device).m_fx4_handler.set_callback(object); } + template static devcb_base &set_fr_handler(device_t &device, _Object object) { return downcast(device).m_fr_handler.set_callback(object); } + template static devcb_base &set_ft_handler(device_t &device, _Object object) { return downcast(device).m_ft_handler.set_callback(object); } + + void str_w(UINT8 data); + DECLARE_WRITE8_MEMBER( str_w ); + void stt_w(UINT8 data); + DECLARE_WRITE8_MEMBER( stt_w ); + + static const int divisors_16X_5_0688MHz[]; + static const int divisors_16X_4_9152MHz[]; + static const int divisors_32X_5_0688MHz[]; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int m_param, void *ptr); + +private: + enum + { + TIMER_FX4, + TIMER_FR, + TIMER_FT + }; + + devcb_write_line m_fx4_handler; + devcb_write_line m_fr_handler; + devcb_write_line m_ft_handler; + + int m_fx4; + int m_fr; + int m_ft; + + const int *m_fr_divisors; + const int *m_ft_divisors; + + // timers + emu_timer *m_fx4_timer; + emu_timer *m_fr_timer; + emu_timer *m_ft_timer; +}; + + +// device type definition +extern const device_type COM8116; + +#endif diff --git a/src/devices/machine/corvushd.c b/src/devices/machine/corvushd.c new file mode 100644 index 00000000000..0444d3cb530 --- /dev/null +++ b/src/devices/machine/corvushd.c @@ -0,0 +1,1475 @@ +// license:BSD-3-Clause +// copyright-holders:Brett Wyer, Raphael Nabet +// +// corvus_hd +// +// Implementation of a Corvus Hard Drive / Host Bus Adapter pair. The drive +// being emulated is a Rev B drive, functionally speaking, rather than an Omnidrive. +// +// The Corvus Flat Cable HBA is a very simplistic device due to the fact that most +// of the smarts are in the Hard Drive itself. What's in the hard drive includes a +// Z80 processor, 4K of EPROM and 5KB of RAM. Ultimately, a true emulation would include +// the on-boad controller; however, that is outside the current scope of this code. Maybe +// if I could get a Rev. B/H drive, it could be reverse-engineered to do this. +// +// The Flat Cable controller has two registers: +// +// Data - Single byte bidirectional data transfer +// Status Register - Bit 7 - Controller Ready -- off = ready, on = not ready +// Bit 6 - Bus Direction -- off = host-to-controller, on = controller-to-host +// +// Layout of a Corvus Hard Disk is as follows: +// +// Blk Len Description +// --- --- ----------- +// 0 1 Boot Block +// 1 1 Disk Parameter Block +// 2 1 Diagnostic Block (prep code) +// 3 1 Constellation Parameter Block +// 4 2 Dispatcher Code +// 6 2 Pipes and Semaphores code (Semaphore table contained in block 7, bytes 1-256) +// 8 10 Mirror Controller Code +// 18 2 LSI-11 Controller Code +// 20 2 Pipes Controller Code +// 22 3 Reserved for Future Use +// 25 8 Boot Blocks 0-7. Apple II uses 0-3, Concept uses 4-7 +// 33 4 Active User Table +// 37 3 Reserved +// +// All of the above blocks are initialized by the DDIAG program. This can be found on the +// Concept FSYSGEN floppy. +// - Boot blocks and code blocks are initialized using the "Update Firmware on Disk" function. +// - Disk Parameter Block is initialized using the "Display/Modify Drive Parameters" function +// +// An on-disk structure is written with the SYSGEN utility on the same disk. Password is "HAI" +// +// +// Corvus Hard Disk performance characteristics (from a 6MB Rev B-E drive) +// +// Average Latency: 6.25ms +// Average Access Time: 125ms (and you thought YOUR drive was slow...) +// Maximum Access Time: 240ms +// Maximum Access Time (single track): 3ms +// Data Transfer Rate: 960Kb/sec +// Rotational Speed: 4800RPM +// +// Brett Wyer +// +// +// TODO: +// Implement READY line glitch after last byte of command (Disk System Tech Ref pp. 3) +// Implement Read-after-Write (always happens on Rev B/H drives per Mass Storage GTI pp. 12) +// Implement Drive Illegal Addresses (seek past last sector) +// Implement Switches on front of drive (LSI-11, MUX, Format, Reset) +// Implement an inter-sector delay during the FORMAT command (format happens too quickly now) +// + +#include "emu.h" +#include "imagedev/harddriv.h" +#include "machine/corvushd.h" +#include + + +const device_type CORVUS_HDC = &device_creator; + +corvus_hdc_t::corvus_hdc_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, CORVUS_HDC, "Corvus Flat Cable HDC", tag, owner, clock, "corvus_hdc", __FILE__), + m_status(0), + m_prep_mode(false), + m_prep_drv(0), + m_sectors_per_track(0), + m_tracks_per_cylinder(0), + m_cylinders_per_drive(0), + m_offset(0), + m_awaiting_modifier(false), + m_recv_bytes(0), + m_xmit_bytes(0), + m_last_cylinder(0), + m_delay(0), + m_invalid_command_flag(false) +{ +} + +#define VERBOSE 0 +#define VERBOSE_RESPONSES 0 +#define ROM_VERSION 1 // Controller ROM version +#define MAX_COMMAND_SIZE 4096 // The maximum size of a command packet (the controller only has 5K of RAM...) +#define SPARE_TRACKS 7 // This is a Rev B drive, so 7 it is +#define CALLBACK_CTH_MODE 1 // Set to Controller-to-Host mode when callback fires +#define CALLBACK_HTC_MODE 2 // Set to Host-to-Controller mode when callback fires +#define CALLBACK_SAME_MODE 3 // Leave mode the same when callback fires +#define CALLBACK_TIMEOUT 4 // Four seconds have elapsed. We're timing out +#define TRACK_SEEK_TIME 1667 // Track-to-track seek time in microseconds (Maximum Access Time / Total Cylinders) +#define INTERBYTE_DELAY 5 // Inter-byte delay in microseconds communicating between controller and host +#define INTERSECTOR_DELAY 25000 // 25ms delay between sectors (4800 RPM = 80 Rev/Second. Maximum 2 sectors transferred / Rev) + +#define LOG(x) do { if (VERBOSE) logerror x; } while (0) +#define LOG_BUFFER(p,s) do { if (VERBOSE) dump_buffer(p,s); } while (0) + + + +// +// Dump_Buffer +// +// Dump a buffer to the error log in a nice format. +// +// Pass: +// buffer: Data to be dumped +// length: Number of bytes to be dumped +// +// Returns: +// nada +// +void corvus_hdc_t::dump_buffer(UINT8 *buffer, UINT16 length) { + UINT16 offset; + char ascii_dump[16]; + + logerror("dump_buffer: Dump of %d bytes:\n", length); + logerror("Base 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f ASCII\n"); + logerror("---- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- ----------------"); + + for(offset=0; offset < length; offset++) { + if(offset % 16 == 0) { // WHY IS 0 % 16 == 0??? + if(offset > 0 && offset % 16 == 0) + logerror("%16.16s", ascii_dump); + logerror("\n%4.4x: %2.2x ", offset, *(buffer + offset)); + } else { + logerror("%2.2x ", *(buffer + offset)); + } + ascii_dump[offset % 16] = isprint(*(buffer + offset)) ? *(buffer + offset) : '.'; + } + if(offset % 16) + logerror("%.*s", (16 - (offset % 16)) * 3, " "); + logerror("%.*s\n", (offset % 16) ? (offset % 16) : 16, ascii_dump); +} + + + +// +// Parse_HDC_Command +// +// Process the first byte received from the host. Do some initial evaluation and +// return either true or false as to whether the command was invalid or not. +// +// Note that recv_bytes and xmit_bytes in the corvus_hdc structure are updated as +// a side-effect of this command, as is awaiting_modifier. +// +// Pass: +// data: Initial byte received from the host in Host to Controller mode +// +// Returns: +// Whether the command was invalid or not (true = invalid command) +// +bool corvus_hdc_t::parse_hdc_command(UINT8 data) { + m_awaiting_modifier = false; // This is the case by definition + + LOG(("parse_hdc_command: Called with data: 0x%2.2x, Prep mode is: %d\n", data, m_prep_mode)); + + if(!m_prep_mode) { + switch(data) { + // + // Single-byte commands - Non-Prep mode + // + case READ_SECTOR_256: + case WRITE_SECTOR_256: + case READ_CHUNK_128: + case READ_CHUNK_256: + case READ_CHUNK_512: + case WRITE_CHUNK_128: + case WRITE_CHUNK_256: + case WRITE_CHUNK_512: + case READTEMPBLOCK: + case WRITETEMPBLOCK: + case BOOT: + case READ_BOOT_BLOCK: + case GET_DRIVE_PARAMETERS: + // case PARK_HEADS_REVH: + case PARK_HEADS_OMNI: + case ECHO: + case PREP_MODE_SELECT: + m_recv_bytes = corvus_cmd[data][0].recv_bytes; + m_xmit_bytes = corvus_cmd[data][0].xmit_bytes; + LOG(("parse_hdc_command: Single byte command recognized: 0x%2.2x, to recv: %d, to xmit: %d\n", data, + m_recv_bytes, m_xmit_bytes)); + break; + // + // Double-byte commands + // + case SEMAPHORE_LOCK_CODE: + // case SEMAPHORE_UNLOCK_CODE: + case SEMAPHORE_INIT_CODE: + // case PIPE_READ_CODE: + // case PIPE_WRITE_CODE: + // case PIPE_CLOSE_CODE: + // case PIPE_STATUS_CODE: + // case SEMAPHORE_STATUS_CODE: + case PIPE_OPEN_WRITE_CODE: + // case PIPE_AREA_INIT_CODE: + // case PIPE_OPEN_READ_CODE: + case ADDACTIVE_CODE: + // case DELACTIVEUSR_REVBH_CODE: + // case DELACTIVEUSR_OMNI_CODE: + // case DELACTIVENUM_OMNI_CODE: + // case FINDACTIVE_CODE: + m_awaiting_modifier = true; + LOG(("parse_hdc_command: Double byte command recognized: 0x%2.2x\n", data)); + break; + + default: // This is an INVALID command + m_recv_bytes = 1; + m_xmit_bytes = 1; + LOG(("parse_hdc_command: Invalid command detected: 0x%2.2x\n", data)); + return true; + } + } else { + switch(data) { + // + // Prep Commands + // + case PREP_MODE_SELECT: + case PREP_RESET_DRIVE: + case PREP_FORMAT_DRIVE: + case PREP_FILL_DRIVE_OMNI: + case PREP_VERIFY: + case PREP_READ_FIRMWARE: + case PREP_WRITE_FIRMWARE: + m_recv_bytes = corvus_prep_cmd[data].recv_bytes; + m_xmit_bytes = corvus_prep_cmd[data].xmit_bytes; + LOG(("parse_hdc_command: Prep command recognized: 0x%2.2x, to recv: %d, to xmit: %d\n", data, + m_recv_bytes, m_xmit_bytes)); + break; + + default: // This is an INVALID prep command + m_recv_bytes = 1; + m_xmit_bytes = 1; + LOG(("parse_hdc_command: Invalid Prep command detected: 0x%2.2x\n", data)); + return true; + } + } // if(!prep_mode) + + return false; +} + + + +// +// Corvus_Write_Sector +// +// Write a variably-sized chunk of data to the CHD file +// +// Pass: +// drv: Corvus drive id (1..15) +// sector: Physical sector number to write to +// buffer: Buffer to write +// len: Length of the buffer (amount of data to write) +// +// Returns: +// status: Command status +// +UINT8 corvus_hdc_t::corvus_write_sector(UINT8 drv, UINT32 sector, UINT8 *buffer, int len) { + hard_disk_file + *disk; // Structures for interface to CHD routines + UINT8 tbuffer[512]; // Buffer to hold an entire sector + UINT16 cylinder; // Cylinder this sector resides on + + LOG(("corvus_write_sector: Write Drive: %d, physical sector: 0x%5.5x\n", drv, sector)); + + disk = corvus_hdc_file(drv); + if(!disk) { + logerror("corvus_write_sector: Failure returned by corvus_hdc_file(%d)\n", drv); + return STAT_FATAL_ERR | STAT_DRIVE_NOT_ONLINE; + } + + // + // Calculate what cylinder the sector resides on for timing purposes + // + cylinder = (double) sector / (double) m_sectors_per_track / (double) m_tracks_per_cylinder; + m_delay = abs(m_last_cylinder - cylinder) * TRACK_SEEK_TIME + INTERSECTOR_DELAY; + + // + // Corvus supports write sizes of 128, 256 and 512 bytes. In the case of a write smaller than + // the sector size of 512 bytes, the sector is read, the provided data is overlayed and then the + // sector is written back out. See pp. 5 of the Mass Storage Systems GTI for the details of this + // wonderful functionality. + // + if(len == 512) { + hard_disk_write(disk, sector, buffer); + } else { + hard_disk_read(disk, sector, tbuffer); // Read the existing data into our temporary buffer + memcpy(tbuffer, buffer, len); // Overlay the data with the buffer passed + m_delay += INTERSECTOR_DELAY; // Add another delay because of the Read / Write + hard_disk_write(disk, sector, tbuffer); // Re-write the data + } + + m_last_cylinder = cylinder; + + LOG(("corvus_write_sector: Full sector dump on a write of %d bytes follows:\n", len)); + LOG_BUFFER(len == 512 ? buffer : tbuffer, 512); + + return STAT_SUCCESS; +} + + + +// +// Corvus_Write_Logical_Sector +// +// Write a variably-sized chunk of data to the user area of the virtual Corvus drive +// +// Pass: +// dadr: Corvus-encoded Disk Address -- Logical Sector +// buffer: Buffer holding the data to be written to the disk +// len: Length of the buffer +// +// Returns: +// status: Corvus status +// +UINT8 corvus_hdc_t::corvus_write_logical_sector(dadr_t *dadr, UINT8 *buffer, int len) { + UINT8 status; // Status returned from Physical Sector read + UINT8 drv; // Corvus drive id (1..15) + UINT32 sector; // Sector number on drive + + // + // Unencode the first byte of the DADR + // + // High-order nibble of first byte is the most-significant nibble of the sector address + // Low-order nibble of first byte is the drive id + // + // For example: 0x23 would decode to Drive ID #3, high-order nibble: 0x02. + // + drv = (dadr->address_msn_and_drive & 0x0f); + sector = (dadr->address_msn_and_drive & 0xf0 << 12) | (dadr->address_mid << 8) | dadr->address_lsb; + + LOG(("corvus_write_logical_sector: Writing based on DADR: 0x%6.6x, logical sector: 0x%5.5x, drive: %d\n", + dadr->address_msn_and_drive << 16 | dadr->address_lsb << 8 | dadr->address_mid, sector, drv)); + + // Set m_tracks_per_cylinder and m_sectors_per_track + corvus_hdc_file(drv); + + // + // Shift the logical sector address forward by the number of firmware cylinders (2) + the number of spare tracks (7) + // + sector += (m_tracks_per_cylinder * m_sectors_per_track * 2) + (SPARE_TRACKS * m_sectors_per_track); + + status = corvus_write_sector(drv, sector, buffer, len); + + if(status != STAT_SUCCESS) + m_xmit_bytes = 1; + + return status; +} + + +// +// Corvus_Read_Sector +// +// Read a variably-sized chunk of data from the CHD file +// +// Pass: +// drv: Corvus drive id (1..15) +// sector: Physical sector number to read from +// buffer: Buffer to hold the data read from the disk +// len: Length of the buffer +// +// Returns: +// status: Corvus status +// +UINT8 corvus_hdc_t::corvus_read_sector(UINT8 drv, UINT32 sector, UINT8 *buffer, int len) { + hard_disk_file + *disk; // Structures for interface to CHD routines + UINT8 tbuffer[512]; // Buffer to store full sector results in + UINT16 cylinder; + + LOG(("corvus_read_sector: Read Drive: %d, physical sector: 0x%5.5x\n", drv, sector)); + + disk = corvus_hdc_file(drv); + if(!disk) { + logerror("corvus_read_sector: Failure returned by corvus_hdc_file(%d)\n", drv); + return STAT_FATAL_ERR | STAT_DRIVE_NOT_ONLINE; + } + + // + // Calculate what cylinder the sector resides on for timing purposes + // + cylinder = (double) sector / (double) m_sectors_per_track / (double) m_tracks_per_cylinder; + m_delay = abs(m_last_cylinder - cylinder) * TRACK_SEEK_TIME + INTERSECTOR_DELAY; + + hard_disk_read(disk, sector, tbuffer); + + memcpy(buffer, tbuffer, len); + + m_last_cylinder = cylinder; + + LOG(("corvus_read_sector: Data read follows:\n")); + LOG_BUFFER(tbuffer, len); + + return STAT_SUCCESS; +} + + + +// +// Corvus_Read_Logical_Sector +// +// Read a variably-sized chunk of data from the user area of the virtual Corvus drive +// +// Pass: +// dadr: Corvus-encoded Disk Address -- Logical Sector +// buffer: Buffer to hold the data read from the disk +// len: Length of the buffer +// +// Returns: +// status: Corvus status +// +UINT8 corvus_hdc_t::corvus_read_logical_sector(dadr_t *dadr, UINT8 *buffer, int len) { + UINT8 status; // Status returned from Physical Sector read + UINT8 drv; // Corvus drive id (1..15) + UINT32 sector; // Sector number on drive + + // + // Unencode the first byte of the DADR + // + // High-order nibble of first byte is the most-significant nibble of the sector address + // Low-order nibble of first byte is the drive id + // + // For example: 0x23 would decode to Drive ID #3, high-order nibble: 0x02. + // + drv = (dadr->address_msn_and_drive & 0x0f); + sector = (dadr->address_msn_and_drive & 0xf0 << 12) | (dadr->address_mid << 8) | dadr->address_lsb; + + LOG(("corvus_read_logical_sector: Reading based on DADR: 0x%6.6x, logical sector: 0x%5.5x, drive: %d\n", + dadr->address_msn_and_drive << 16 | dadr->address_lsb << 8 | dadr->address_mid, sector, drv)); + + // Set up m_tracks_per_cylinder and m_sectors_per_track + corvus_hdc_file(drv); + + // + // Shift the logical sector address forward by the number of firmware cylinders (2) + the number of spare tracks (7) + // + sector += (m_tracks_per_cylinder * m_sectors_per_track * 2) + (SPARE_TRACKS * m_sectors_per_track); + + status = corvus_read_sector(drv, sector, buffer, len); + + if(status != STAT_SUCCESS) + m_xmit_bytes = 1; + + return status; +} + + + +// +// Corvus_Lock_Semaphore +// +// Lock a semaphore in the semaphore table +// +// Pass: +// name: Name of the semaphore to lock +// +// Returns: +// status: Disk status +// +// Side-effects: +// Fills in the semaphore result code +// +UINT8 corvus_hdc_t::corvus_lock_semaphore(UINT8 *name) { + semaphore_table_block_t + semaphore_table; + UINT8 offset = 0; + bool found = false; + UINT8 blank_offset = 32; // Initialize to invalid offset + UINT8 status; // Status returned from Physical Sector read + + // + // Read the semaphore table from the drive + // + status = corvus_read_sector(1, 7, semaphore_table.semaphore_block.semaphore_table, 256); + if(status != STAT_SUCCESS) { + logerror("corvus_lock_semaphore: Error reading semaphore table, status: 0x%2.2x\n", status); + m_buffer.semaphore_locking_response.result = SEM_DISK_ERROR; + return status; + } + + // + // Search the semaphore table to see if the semaphore already exists--if so it's locked + // Also look for the first blank entry to stick the new one into + // + do { + if(blank_offset == 32 && strncmp((char *) &semaphore_table.semaphore_block.semaphore_entry[offset], " ", 8) == 0) + blank_offset = offset; + if(strncmp((char *) &semaphore_table.semaphore_block.semaphore_entry[offset], (char *) name, 8) == 0) { + found = true; + break; + } + } while( ++offset < 32 ); + + // + // Deal with the found status + // + // - Stick it into the table if we didn't find it and there's room + // - Respond with a "set" status if we did find it + // + // Once that's done, write the updated table to the disk + // + if(!found) { + if(blank_offset == 32) { + m_buffer.semaphore_locking_response.result = SEM_TABLE_FULL; // No space for the semaphore! + } else { + m_buffer.semaphore_locking_response.result = SEM_PRIOR_STATE_NOT_SET; // It wasn't there already + memcpy(&semaphore_table.semaphore_block.semaphore_entry[blank_offset], name, 8);// Stick it into the table + status = corvus_write_sector(1, 7, semaphore_table.semaphore_block.semaphore_table, 256); + if(status != STAT_SUCCESS) { + logerror("corvus_lock_semaphore: Error updating semaphore table, status: 0x%2.2x\n", status); + m_buffer.semaphore_locking_response.result = SEM_DISK_ERROR; + return status; + } + } + } else { + m_buffer.semaphore_locking_response.result = SEM_PRIOR_STATE_SET; // It's already locked -- sorry + } + + return STAT_SUCCESS; +} + + + +// +// Corvus_Unlock_Semaphore +// +// Unock a semaphore in the semaphore table +// +// Pass: +// name: Name of the semaphore to unlock +// +// Returns: +// status: Disk status +// +// Side-effects: +// Fills in the semaphore result code +// +UINT8 corvus_hdc_t::corvus_unlock_semaphore(UINT8 *name) { + semaphore_table_block_t + semaphore_table; + UINT8 offset = 0; + bool found = false; + UINT8 status; // Status returned from Physical Sector read + + // + // Read the semaphore table from the drive + // + status = corvus_read_sector(1, 7, semaphore_table.semaphore_block.semaphore_table, 256); + if(status != STAT_SUCCESS) { + logerror("corvus_unlock_semaphore: Error reading semaphore table, status: 0x%2.2x\n", status); + m_buffer.semaphore_locking_response.result = SEM_DISK_ERROR; + return status; + } + + // + // Search the semaphore table to see if the semaphore already exists--if so it's locked + // + do { + if(strncmp((char *) &semaphore_table.semaphore_block.semaphore_entry[offset], (char *) name, 8) == 0) { + found = true; + break; + } + } while( ++offset < 32 ); + + // + // Deal with the found status + // + // - If we didn't find it, just respond that it wasn't there + // - If we did find it, respond with a "set" status and clear it + // + // Once that's done, write the updated table to the disk + // + if(!found) { + m_buffer.semaphore_locking_response.result = SEM_PRIOR_STATE_NOT_SET; // It wasn't there already + } else { + m_buffer.semaphore_locking_response.result = SEM_PRIOR_STATE_SET; // It was there + memcpy(&semaphore_table.semaphore_block.semaphore_entry[offset], " ", 8); // Clear it + status = corvus_write_sector(1, 7, semaphore_table.semaphore_block.semaphore_table, 256); + if(status != STAT_SUCCESS) { + logerror("corvus_unlock_semaphore: Error updating semaphore table, status: 0x%2.2x\n", status); + m_buffer.semaphore_locking_response.result = SEM_DISK_ERROR; + return status; + } + } + + return STAT_SUCCESS; +} + + + +// +// Corvus_Init_Semaphore_Table +// +// Zap all of the semaphores from the table (set them to blanks) +// +// Pass: +// Nothing +// +// Returns: +// Disk status +// +// +UINT8 corvus_hdc_t::corvus_init_semaphore_table() { + semaphore_table_block_t + semaphore_table; + UINT8 status; + + memset(semaphore_table.semaphore_block.semaphore_table, 0x20, 256); + + status = corvus_write_sector(1, 7, semaphore_table.semaphore_block.semaphore_table, 256); + if(status != STAT_SUCCESS) { + logerror("corvus_init_semaphore_table: Error updating semaphore table, status: 0x%2.2x\n", status); + return status; + } + + return STAT_SUCCESS; +} + + + +// +// Corvus_Get_Drive_Parameters +// +// Fills in the Drive Parameter packet based on the opened CHD file +// +// Pass: +// drv: Corvus drive id (1..15) +// +// Returns: +// Status of command +// +UINT8 corvus_hdc_t::corvus_get_drive_parameters(UINT8 drv) { + UINT16 capacity; // Number of usable 512-byte blocks + UINT16 raw_capacity; // Number of actual 512-byte blocks + union { + UINT8 + buffer[512]; + disk_parameter_block_t + dpb; + } raw_disk_parameter_block; // Buffer for the Disk Parameter Block + union { + UINT8 + buffer[512]; + constellation_parameter_block_t + cpb; + } raw_constellation_parameter_block; // Buffer for the Constellation Parameter Block + UINT8 status; // Status to return + + // + // Make sure a valid drive is being accessed + // + if ( ! corvus_hdc_file( drv ) ) + { + logerror("corvus_get_drive_parameters: Attempt to retrieve parameters from non-existant drive: %d\n", drv); + m_xmit_bytes = 1; + return STAT_FATAL_ERR | STAT_DRIVE_NOT_ONLINE; + } + + // + // Read the Disk Parameter Block (Sector 1) from the drive + // + status = corvus_read_sector(drv, 1, raw_disk_parameter_block.buffer, 512); + if(status != STAT_SUCCESS) { + logerror("corvus_get_drive_parameters: Error status returned reading Disk Parameter Block -- status: 0x%2.2x\n", status); + m_xmit_bytes = 1; + return status; + } + + // + // Read the Constellation Parameter Block (Sector 3) from the drive + // + status = corvus_read_sector(drv, 3, raw_constellation_parameter_block.buffer, 512); + if(status != STAT_SUCCESS) { + logerror("corvus_get_drive_parameters: Error status returned reading Constellation Parameter Block -- status: 0x%2.2x\n", status); + m_xmit_bytes = 1; + return status; + } + + // + // Build up the parameter packet + // + + // This firmware string and revision were taken from the Corvus firmware + // file CORVB184.CLR found on the SSE SoftBox distribution disk. + strncpy((char *) m_buffer.drive_param_response.firmware_desc, "V18.4 -- CONST II - 11/82 ", sizeof(m_buffer.drive_param_response.firmware_desc)); + m_buffer.drive_param_response.firmware_rev = 37; + + // Controller ROM version + m_buffer.drive_param_response.rom_version = ROM_VERSION; + + // + // Track information + // + m_buffer.drive_param_response.track_info.sectors_per_track = m_sectors_per_track; + m_buffer.drive_param_response.track_info.tracks_per_cylinder = m_tracks_per_cylinder; + m_buffer.drive_param_response.track_info.cylinders_per_drive.msb = (m_cylinders_per_drive & 0xff00) >> 8; + m_buffer.drive_param_response.track_info.cylinders_per_drive.lsb = (m_cylinders_per_drive & 0x00ff); + + // + // Calculate the user capacity of the drive based on total capacity less spare tracks and firmware tracks + // + raw_capacity = m_tracks_per_cylinder * m_cylinders_per_drive * m_sectors_per_track; // Total capacity + capacity = raw_capacity - ((m_tracks_per_cylinder * m_sectors_per_track * 2) + (SPARE_TRACKS * m_sectors_per_track)); + m_buffer.drive_param_response.capacity.msb = (capacity & 0xff0000) >> 16; + m_buffer.drive_param_response.capacity.midb = (capacity & 0x00ff00) >> 8; + m_buffer.drive_param_response.capacity.lsb = (capacity & 0x0000ff); + + // + // Fill in the information from the Disk Parameter Block and Constellation Parameter Block + // + m_buffer.drive_param_response.interleave = raw_disk_parameter_block.dpb.interleave; + memcpy(m_buffer.drive_param_response.table_info.mux_parameters, raw_constellation_parameter_block.cpb.mux_parameters, 12); + memcpy(m_buffer.drive_param_response.table_info.pipe_name_table_ptr, + raw_constellation_parameter_block.cpb.pipe_name_table_ptr, 2); + memcpy(m_buffer.drive_param_response.table_info.pipe_ptr_table_ptr, + raw_constellation_parameter_block.cpb.pipe_ptr_table_ptr, 2); + memcpy(m_buffer.drive_param_response.table_info.pipe_area_size, raw_constellation_parameter_block.cpb.pipe_area_size, 2); + memcpy(m_buffer.drive_param_response.table_info.vdo_table, raw_disk_parameter_block.dpb.vdo_table, 14); + memcpy(m_buffer.drive_param_response.table_info.lsi11_vdo_table, raw_disk_parameter_block.dpb.lsi11_vdo_table, 8); + memcpy(m_buffer.drive_param_response.table_info.lsi11_spare_table, raw_disk_parameter_block.dpb.lsi11_spare_table, 8); + + m_buffer.drive_param_response.drive_number = drv; + m_buffer.drive_param_response.physical_capacity.msb = (raw_capacity & 0xff0000) >> 16; + m_buffer.drive_param_response.physical_capacity.midb = (raw_capacity & 0x00ff00) >> 8; + m_buffer.drive_param_response.physical_capacity.lsb = (raw_capacity & 0x0000ff); + + LOG(("corvus_get_drive_parameters: Drive Parameter packet follows:\n")); + LOG_BUFFER(m_buffer.raw_data, 110); + + return STAT_SUCCESS; +} + + + +// +// Corvus_Read_Boot_Block +// +// Old-style Boot (0x14) command boot block reader +// +// Pass: +// block: Boot block number to read (0-7) +// +// Returns: +// status: Status of read operation +// +UINT8 corvus_hdc_t::corvus_read_boot_block(UINT8 block) { + LOG(("corvus_read_boot_block: Reading boot block: %d\n", block)); + + return corvus_read_sector(1, 25 + block, m_buffer.read_512_response.data, 512); +} + + + +// +// corvus_enter_prep_mode +// +// Enter prep mode. In prep mode, only prep mode commands may be executed. +// +// A "prep block" is 512 bytes of machine code that the host sends to the +// controller. The controller will jump to this code after receiving it, +// and it is what actually implements prep mode commands. This HLE ignores +// the prep block from the host. +// +// On the Rev B/H drives (which we emulate), a prep block is Z80 machine +// code and only one prep block can be sent. Sending the "put drive into +// prep mode" command (0x11) when already in prep mode is an error. The +// prep block sent by the Corvus program DIAG.COM on the SSE SoftBox +// distribution disk returns error 0x8f (unrecognized command) for this case. +// +// On the OmniDrive and Bank, a prep block is 6801 machine code. These +// controllers allow multiple prep blocks to be sent. The first time the +// "put drive into prep mode" command is sent puts the drive into prep mode. +// The command can then be sent again up to 3 times with more prep blocks. +// (Mass Storage GTI, pages 50-51) +// +// Pass: +// drv: Corvus drive id (1..15) to be prepped +// prep_block: 512 bytes of machine code, contents ignored +// +// Returns: +// Status of command +// +UINT8 corvus_hdc_t::corvus_enter_prep_mode(UINT8 drv, UINT8 *prep_block) { + // on rev b/h drives, sending the "put drive into prep mode" + // command when already in prep mode is an error. + if (m_prep_mode) { + logerror("corvus_enter_prep_mode: Attempt to enter prep mode while in prep mode\n"); + return STAT_FATAL_ERR | STAT_ILL_CMD_OP_CODE; + } + + // check if drive is valid + if (!corvus_hdc_file(drv)) { + logerror("corvus_enter_prep_mode: Failure returned by corvus_hdc_file(%d)\n", drv); + return STAT_FATAL_ERR | STAT_DRIVE_NOT_ONLINE; + } + + LOG(("corvus_enter_prep_mode: Prep mode entered for drive %d, prep block follows:\n", drv)); + LOG_BUFFER(prep_block, 512); + + m_prep_mode = true; + m_prep_drv = drv; + return STAT_SUCCESS; +} + + + +// +// corvus_exit_prep_mode (Prep Mode Only) +// +// Exit from prep mode and return to normal command mode. +// +// Returns: +// Status of command (always success) +// +UINT8 corvus_hdc_t::corvus_exit_prep_mode() { + LOG(("corvus_exit_prep_mode: Prep mode exited\n")); + m_prep_mode = false; + m_prep_drv = 0; + return STAT_SUCCESS; +} + + + +// +// Corvus_Read_Firmware_Block (Prep Mode Only) +// +// Reads firmware information from the first cylinder of the drive +// +// Pass: +// head: Head number +// sector: Sector number +// +// Returns: +// Status of command +// +UINT8 corvus_hdc_t::corvus_read_firmware_block(UINT8 head, UINT8 sector) { + UINT16 relative_sector; // Relative sector on drive for Physical Read + UINT8 status; + + relative_sector = head * m_sectors_per_track + sector; + + LOG(("corvus_read_firmware_block: Reading firmware head: 0x%2.2x, sector: 0x%2.2x, relative_sector: 0x%2.2x\n", + head, sector, relative_sector)); + + status = corvus_read_sector(m_prep_drv, relative_sector, m_buffer.read_512_response.data, 512); + return status; +} + + + +// +// Corvus_Write_Firmware_Block (Prep Mode Only) +// +// Writes firmware information to the first cylinder of the drive +// +// Pass: +// head: Head number +// sector: Sector number +// buffer: Data to be written +// +// Returns: +// Status of command +// +UINT8 corvus_hdc_t::corvus_write_firmware_block(UINT8 head, UINT8 sector, UINT8 *buffer) { + UINT16 relative_sector; // Relative sector on drive for Physical Read + UINT8 status; + + relative_sector = head * m_sectors_per_track + sector; + + LOG(("corvus_write_firmware_block: Writing firmware head: 0x%2.2x, sector: 0x%2.2x, relative_sector: 0x%2.2x\n", + head, sector, relative_sector)); + + status = corvus_write_sector(m_prep_drv, relative_sector, buffer, 512); + return status; +} + + + +// +// Corvus_Format_Drive (Prep Mode Only) +// +// Write the pattern provided across the entire disk +// +// Pass: +// pattern: 512-byte buffer containing the pattern to write to the whole drive +// +// Returns: +// Status of command +// +UINT8 corvus_hdc_t::corvus_format_drive(UINT8 *pattern, UINT16 len) { + UINT32 sector; + UINT32 max_sector; + UINT8 status = 0; + UINT8 tbuffer[512]; + + // Set up m_tracks_per_cylinder and m_sectors_per_track + corvus_hdc_file(m_prep_drv); + + max_sector = m_sectors_per_track * m_tracks_per_cylinder * m_cylinders_per_drive; + + // + // If we were passed less than 512 bytes, fill the buffer up with the first byte passed (for Omnidrive Format command) + // + if(len < 512) { + memset(tbuffer, *pattern, 512); + pattern = tbuffer; + } + + LOG(("corvus_format_drive: Formatting drive with 0x%5.5x sectors, pattern buffer (passed length: %d) follows\n", max_sector, 512)); + LOG_BUFFER(pattern, 512); + + for(sector = 0; sector <= max_sector; sector++) { + status = corvus_write_sector(m_prep_drv, sector, pattern, 512); + if(status != STAT_SUCCESS) { + logerror("corvus_format_drive: Error while formatting drive in corvus_write_sector--sector: 0x%5.5x, status: 0x%x2.2x\n", + sector, status); + break; + } + } + + return status; +} + + + +// +// Corvus_HDC_File +// +// Returns a hard_disk_file object for a given virtual hard drive device in the concept +// +// Pass: +// drv: Corvus drive id (1..15) +// +// Returns: +// hard_disk_file object +// +hard_disk_file *corvus_hdc_t::corvus_hdc_file(int drv) { + static const char *const tags[] = { + "harddisk1", "harddisk2", "harddisk3", "harddisk4" + }; + + // we only support 4 drives, as per the tags[] table, so prevent a crash + // Corvus drive id numbers are 1-based so we check 1..4 instead of 0..3 + if (drv < 1 || drv > 4) + { + return NULL; + } + + harddisk_image_device *img = siblingdevice(tags[drv - 1]); + + if ( !img ) + return NULL; + + if (!img->exists()) + return NULL; + + // Pick up the Head/Cylinder/Sector info + hard_disk_file *file = img->get_hard_disk_file(); + hard_disk_info *info = hard_disk_get_info(file); + m_sectors_per_track = info->sectors; + m_tracks_per_cylinder = info->heads; + m_cylinders_per_drive = info->cylinders; + + LOG(("corvus_hdc_file: Attached to drive %u image: H:%d, C:%d, S:%d\n", drv, info->heads, info->cylinders, info->sectors)); + + return file; +} + + + +// +// Corvus_Process_Command_Packet +// +// Having received a complete packet from the host, process it +// +// Pass: +// Invalid_Command_Flag: Invalid command flag responses are handled in this routine +// +// Returns: +// Nothing +// +void corvus_hdc_t::corvus_process_command_packet(bool invalid_command_flag) { + if (VERBOSE_RESPONSES) + { + LOG(("corvus_hdc_data_w: Complete packet received. Dump follows:\n")); + LOG_BUFFER(m_buffer.raw_data, m_offset); + } + + if(!invalid_command_flag) { + if(!m_prep_mode) { + switch(m_buffer.command.code) { + // + // Read / Write Chunk commands + // + case READ_CHUNK_128: + m_buffer.read_128_response.status = + corvus_read_logical_sector(&m_buffer.read_sector_command.dadr, m_buffer.read_128_response.data, 128); + break; + case READ_SECTOR_256: + case READ_CHUNK_256: + m_buffer.read_256_response.status = + corvus_read_logical_sector(&m_buffer.read_sector_command.dadr, m_buffer.read_256_response.data, 256); + break; + case READ_CHUNK_512: + m_buffer.read_512_response.status = + corvus_read_logical_sector(&m_buffer.read_sector_command.dadr, m_buffer.read_512_response.data, 512); + break; + case WRITE_CHUNK_128: + m_buffer.single_byte_response.status = + corvus_write_logical_sector(&m_buffer.write_128_command.dadr, m_buffer.write_128_command.data, 128); + break; + case WRITE_SECTOR_256: + case WRITE_CHUNK_256: + m_buffer.single_byte_response.status = + corvus_write_logical_sector(&m_buffer.write_256_command.dadr, m_buffer.write_256_command.data, 256); + break; + case WRITE_CHUNK_512: + m_buffer.single_byte_response.status = + corvus_write_logical_sector(&m_buffer.write_512_command.dadr, m_buffer.write_512_command.data, 512); + break; + // + // Semaphore commands + // + case SEMAPHORE_LOCK_CODE: + // case SEMAPHORE_UNLOCK_CODE: + case SEMAPHORE_INIT_CODE: + // case SEMAPHORE_STATUS_CODE: + switch(m_buffer.command.modifier) { + case SEMAPHORE_LOCK_MOD: + m_buffer.semaphore_locking_response.status = corvus_lock_semaphore(m_buffer.lock_semaphore_command.name); + break; + case SEMAPHORE_UNLOCK_MOD: + m_buffer.semaphore_locking_response.status = + corvus_unlock_semaphore(m_buffer.unlock_semaphore_command.name); + break; + case SEMAPHORE_INIT_MOD: + m_buffer.single_byte_response.status = corvus_init_semaphore_table(); + break; + case SEMAPHORE_STATUS_MOD: + m_buffer.semaphore_status_response.status = + corvus_read_sector(1, 7, m_buffer.semaphore_status_response.table, 256); + break; + default: + invalid_command_flag = true; + } + break; + // + // Miscellaneous commands + // + case BOOT: + m_buffer.read_512_response.status = + corvus_read_boot_block(m_buffer.old_boot_command.boot_block); + break; + case GET_DRIVE_PARAMETERS: + m_buffer.drive_param_response.status = + corvus_get_drive_parameters(m_buffer.get_drive_parameters_command.drive); + break; + case PREP_MODE_SELECT: + m_buffer.single_byte_response.status = + corvus_enter_prep_mode(m_buffer.prep_mode_command.drive, + m_buffer.prep_mode_command.prep_block); + break; + default: + m_xmit_bytes = 1; // Return a fatal status + m_buffer.single_byte_response.status = STAT_FAULT | STAT_FATAL_ERR; + logerror("corvus_hdc_data_w: Unimplemented command, returning FATAL FAULT status!\n"); + break; + } + } else { // In Prep mode + switch(m_buffer.command.code) { + case PREP_MODE_SELECT: + // when already in prep mode, some drives allow this command to + // be sent again. see corvus_enter_prep_mode() for details. + m_buffer.single_byte_response.status = + corvus_enter_prep_mode(m_buffer.prep_mode_command.drive, + m_buffer.prep_mode_command.prep_block); + break; + case PREP_RESET_DRIVE: + m_buffer.single_byte_response.status = + corvus_exit_prep_mode(); + break; + case PREP_READ_FIRMWARE: + m_buffer.drive_param_response.status = + corvus_read_firmware_block((m_buffer.read_firmware_command.encoded_h_s & 0xe0) >> 5, + m_buffer.read_firmware_command.encoded_h_s & 0x1f); + break; + case PREP_WRITE_FIRMWARE: + m_buffer.drive_param_response.status = + corvus_write_firmware_block((m_buffer.write_firmware_command.encoded_h_s & 0xe0) >> 5, + m_buffer.write_firmware_command.encoded_h_s & 0x1f, m_buffer.write_firmware_command.data); + break; + case PREP_FORMAT_DRIVE: + m_buffer.drive_param_response.status = + corvus_format_drive(m_buffer.format_drive_revbh_command.pattern, m_offset - 512); + break; + case PREP_VERIFY: + m_buffer.verify_drive_response.status = STAT_SUCCESS; + m_buffer.verify_drive_response.bad_sectors = 0; + break; + default: + m_xmit_bytes = 1; + m_buffer.single_byte_response.status = STAT_FAULT | STAT_FATAL_ERR; + logerror("corvus_hdc_data_w: Unimplemented Prep command %02x, returning FATAL FAULT status!\n", m_buffer.command.code); + } + } + if (VERBOSE_RESPONSES) + { + LOG(("corvus_hdc_data_w: Command execution complete, status: 0x%2.2x. Response dump follows:\n", + m_buffer.single_byte_response.status)); + LOG_BUFFER(m_buffer.raw_data, m_xmit_bytes); + } + + } // if(!invalid_command_flag) + + // + // Use a separate "if" in case the Invalid Command Flag was set as a result of a two-byte command + // + if(invalid_command_flag) { + // + // An Illegal command was detected (Truly invalid, not just unimplemented) + // + m_buffer.single_byte_response.status = + STAT_FATAL_ERR | STAT_ILL_CMD_OP_CODE; // Respond with an Illegal Op Code + + logerror("corvus_hdc_data_w: Illegal command 0x%2.2x, status: 0x%2.2x\n", m_buffer.command.code, m_buffer.single_byte_response.status); + } + // + // Command execution complete, free up the controller + // + m_offset = 0; // Point to beginning of buffer for response + + LOG(("corvus_hdc_data_w: Setting one-time mame timer of %d microseconds to simulate disk function\n", m_delay)); + + // + // Set up timers for command completion and timeout from host + // + //machine.scheduler().timer_set(attotime::from_usec(m_delay), FUNC(corvus_hdc_callback), CALLBACK_CTH_MODE); + m_cmd_timer->adjust(attotime::from_usec(m_delay), CALLBACK_CTH_MODE); + m_timeout_timer->enable(0); // We've received enough data, disable the timeout timer + + m_delay = 0; // Reset delay for next function +} + + + +// +// Corvus_HDC_Callback +// +// Callback routine for completion of controller functions +// +// Pass: +// Callback Function +// +// Returns: +// Nothing +// +void corvus_hdc_t::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + int function = param; + + switch(function) { + case CALLBACK_CTH_MODE: + m_status |= CONTROLLER_DIRECTION; // Set to Controller-to-Host, Ready mode + m_status &= ~(CONTROLLER_BUSY); + + LOG(("corvus_hdc_callback: Callback executed with function CALLBACK_CTH_MODE\n")); + + break; + case CALLBACK_HTC_MODE: + m_status &= ~(CONTROLLER_DIRECTION | + CONTROLLER_BUSY); // Set to Host-to-Controller, Ready mode + + LOG(("corvus_hdc_callback: Callback executed with function CALLBACK_HTC_MODE\n")); + + break; + case CALLBACK_SAME_MODE: + m_status &= ~(CONTROLLER_BUSY); // Set the controller to Ready mode + + break; + case CALLBACK_TIMEOUT: // We reached a four-second timeout threshold + if(m_offset < m_recv_bytes || (m_offset > m_recv_bytes && m_recv_bytes != 0)) { + m_buffer.single_byte_response.status = STAT_TIMEOUT; + m_status |= CONTROLLER_DIRECTION; + m_status &= ~(CONTROLLER_BUSY); + m_recv_bytes = 0; + m_xmit_bytes = 1; + logerror("corvus_hdc_callback: Exceeded four-second timeout for data from host, resetting communications\n"); + } else { // if(m_recv_bytes == 0) This was a variable-size command + LOG(("corvus_hdc_callback: Executing variable-length command via four-second timeout\n")); + corvus_process_command_packet(0); // Process the command + } + break; + default: + logerror("corvus_hdc_callback: FATAL ERROR -- Unknown callback function: %d\n", function); + assert(0); + } + if(function != CALLBACK_SAME_MODE) { + m_timeout_timer->enable(0); // Disable the four-second timer now that we're done + } +} + + + +// +// Corvus_HDC_Init +// +// Global routine to initialize the Hard Disk Controller structures and arrays +// +// Pass: +// Nothing +// +// Returns: +// NULL if there's no file to attach to +// +void corvus_hdc_t::device_start() { + m_status &= ~(CONTROLLER_DIRECTION | CONTROLLER_BUSY); // Host-to-controller mode, Idle (awaiting command from Host mode) + m_prep_mode = false; // We're not in Prep Mode + m_offset = 0; // Buffer is empty + m_awaiting_modifier = false; // We're not in the middle of a two-byte command + m_xmit_bytes = 0; // We don't have anything to say to the host + m_recv_bytes = 0; // We aren't waiting on additional data from the host + + m_timeout_timer = timer_alloc(TIMER_TIMEOUT); // Set up a timer to handle the four-second host-to-controller timeout + m_timeout_timer->adjust(attotime::from_seconds(4), CALLBACK_TIMEOUT); + m_timeout_timer->enable(0); // Start this timer out disabled + + m_cmd_timer = timer_alloc(TIMER_COMMAND); + + // + // Define all of the packet sizes for the commands + // + + // Read / Write commands + corvus_cmd[READ_SECTOR_256][0].recv_bytes = 4; + corvus_cmd[READ_SECTOR_256][0].xmit_bytes = 257; + corvus_cmd[WRITE_SECTOR_256][0].recv_bytes = 260; + corvus_cmd[WRITE_SECTOR_256][0].xmit_bytes = 1; + corvus_cmd[READ_CHUNK_128][0].recv_bytes = 4; + corvus_cmd[READ_CHUNK_128][0].xmit_bytes = 129; + corvus_cmd[READ_CHUNK_256][0].recv_bytes = 4; + corvus_cmd[READ_CHUNK_256][0].xmit_bytes = 257; + corvus_cmd[READ_CHUNK_512][0].recv_bytes = 4; + corvus_cmd[READ_CHUNK_512][0].xmit_bytes = 513; + corvus_cmd[WRITE_CHUNK_128][0].recv_bytes = 132; + corvus_cmd[WRITE_CHUNK_128][0].xmit_bytes = 1; + corvus_cmd[WRITE_CHUNK_256][0].recv_bytes = 260; + corvus_cmd[WRITE_CHUNK_256][0].xmit_bytes = 1; + corvus_cmd[WRITE_CHUNK_512][0].recv_bytes = 516; + corvus_cmd[WRITE_CHUNK_512][0].xmit_bytes = 1; + + // Semaphore commands + corvus_cmd[SEMAPHORE_LOCK_CODE][SEMAPHORE_LOCK_MOD].recv_bytes = 10; + corvus_cmd[SEMAPHORE_LOCK_CODE][SEMAPHORE_LOCK_MOD].xmit_bytes = 12; + corvus_cmd[SEMAPHORE_UNLOCK_CODE][SEMAPHORE_UNLOCK_MOD].recv_bytes = 10; + corvus_cmd[SEMAPHORE_UNLOCK_CODE][SEMAPHORE_UNLOCK_MOD].xmit_bytes = 12; + corvus_cmd[SEMAPHORE_INIT_CODE][SEMAPHORE_INIT_MOD].recv_bytes = 5; + corvus_cmd[SEMAPHORE_INIT_CODE][SEMAPHORE_INIT_MOD].xmit_bytes = 1; + corvus_cmd[SEMAPHORE_STATUS_CODE][SEMAPHORE_STATUS_MOD].recv_bytes = 5; + corvus_cmd[SEMAPHORE_STATUS_CODE][SEMAPHORE_STATUS_MOD].xmit_bytes = 257; + + // Pipe commands + corvus_cmd[PIPE_READ_CODE][PIPE_READ_MOD].recv_bytes = 5; + corvus_cmd[PIPE_READ_CODE][PIPE_READ_MOD].xmit_bytes = 516; + corvus_cmd[PIPE_WRITE_CODE][PIPE_WRITE_MOD].recv_bytes = 517; + corvus_cmd[PIPE_WRITE_CODE][PIPE_WRITE_MOD].xmit_bytes = 12; + corvus_cmd[PIPE_CLOSE_CODE][PIPE_CLOSE_MOD].recv_bytes = 5; + corvus_cmd[PIPE_CLOSE_CODE][PIPE_CLOSE_MOD].xmit_bytes = 12; + corvus_cmd[PIPE_STATUS_CODE][PIPE_STATUS_MOD].recv_bytes = 5; + corvus_cmd[PIPE_STATUS_CODE][PIPE_STATUS_MOD].xmit_bytes = 513; // There are actually two possibilities here + corvus_cmd[PIPE_OPEN_WRITE_CODE][PIPE_OPEN_WRITE_MOD].recv_bytes = 10; + corvus_cmd[PIPE_OPEN_WRITE_CODE][PIPE_OPEN_WRITE_MOD].xmit_bytes = 12; + corvus_cmd[PIPE_AREA_INIT_CODE][PIPE_AREA_INIT_MOD].recv_bytes = 10; + corvus_cmd[PIPE_AREA_INIT_CODE][PIPE_AREA_INIT_MOD].xmit_bytes = 12; + corvus_cmd[PIPE_OPEN_READ_CODE][PIPE_OPEN_READ_MOD].recv_bytes = 10; + corvus_cmd[PIPE_OPEN_READ_CODE][PIPE_OPEN_READ_MOD].xmit_bytes = 12; + + // Active User Table Commands + corvus_cmd[ADDACTIVE_CODE][ADDACTIVE_MOD].recv_bytes = 18; + corvus_cmd[ADDACTIVE_CODE][ADDACTIVE_MOD].xmit_bytes = 2; + corvus_cmd[DELACTIVEUSR_REVBH_CODE][DELACTIVEUSR_REVBH_MOD].recv_bytes = 18; + corvus_cmd[DELACTIVEUSR_REVBH_CODE][DELACTIVEUSR_REVBH_MOD].xmit_bytes = 2; + corvus_cmd[DELACTIVENUM_OMNI_CODE][DELACTIVENUM_OMNI_MOD].recv_bytes = 18; + corvus_cmd[DELACTIVENUM_OMNI_CODE][DELACTIVENUM_OMNI_MOD].xmit_bytes = 2; + corvus_cmd[DELACTIVEUSR_OMNI_CODE][DELACTIVEUSR_OMNI_MOD].recv_bytes = 18; + corvus_cmd[DELACTIVEUSR_OMNI_CODE][DELACTIVEUSR_OMNI_MOD].xmit_bytes = 2; + corvus_cmd[FINDACTIVE_CODE][FINDACTIVE_MOD].recv_bytes = 18; + corvus_cmd[FINDACTIVE_CODE][FINDACTIVE_MOD].xmit_bytes = 17; + corvus_cmd[READTEMPBLOCK][0].recv_bytes = 2; + corvus_cmd[READTEMPBLOCK][0].xmit_bytes = 513; + corvus_cmd[WRITETEMPBLOCK][0].recv_bytes = 514; + corvus_cmd[WRITETEMPBLOCK][0].xmit_bytes = 1; + + // Miscellaneous Commands + corvus_cmd[BOOT][0].recv_bytes = 2; + corvus_cmd[BOOT][0].xmit_bytes = 513; + corvus_cmd[READ_BOOT_BLOCK][0].recv_bytes = 3; + corvus_cmd[READ_BOOT_BLOCK][0].xmit_bytes = 513; + corvus_cmd[GET_DRIVE_PARAMETERS][0].recv_bytes = 2; + corvus_cmd[GET_DRIVE_PARAMETERS][0].xmit_bytes = 129; + corvus_cmd[PARK_HEADS_REVH][0].recv_bytes = 514; + corvus_cmd[PARK_HEADS_REVH][0].xmit_bytes = 1; + corvus_cmd[PARK_HEADS_OMNI][0].recv_bytes = 1; + corvus_cmd[PARK_HEADS_OMNI][0].xmit_bytes = 1; + corvus_cmd[ECHO][0].recv_bytes = 513; + corvus_cmd[ECHO][0].xmit_bytes = 513; + + // Put Drive in Prep Mode + corvus_cmd[PREP_MODE_SELECT][0].recv_bytes = 514; + corvus_cmd[PREP_MODE_SELECT][0].xmit_bytes = 1; + + // Prep Mode Commands + corvus_prep_cmd[PREP_MODE_SELECT].recv_bytes = 514; + corvus_prep_cmd[PREP_MODE_SELECT].xmit_bytes = 1; + corvus_prep_cmd[PREP_RESET_DRIVE].recv_bytes = 1; + corvus_prep_cmd[PREP_RESET_DRIVE].xmit_bytes = 1; + corvus_prep_cmd[PREP_FORMAT_DRIVE].recv_bytes = 0; + corvus_prep_cmd[PREP_FORMAT_DRIVE].xmit_bytes = 1; + corvus_prep_cmd[PREP_FILL_DRIVE_OMNI].recv_bytes = 3; + corvus_prep_cmd[PREP_FILL_DRIVE_OMNI].xmit_bytes = 1; + corvus_prep_cmd[PREP_VERIFY].recv_bytes = 1; + corvus_prep_cmd[PREP_VERIFY].xmit_bytes = 2; + corvus_prep_cmd[PREP_READ_FIRMWARE].recv_bytes = 2; + corvus_prep_cmd[PREP_READ_FIRMWARE].xmit_bytes = 513; + corvus_prep_cmd[PREP_WRITE_FIRMWARE].recv_bytes = 514; + corvus_prep_cmd[PREP_WRITE_FIRMWARE].xmit_bytes = 1; + + LOG(("corvus_hdc_init: Drive structures initialized\n")); +} + + +// +// Corvus_HDC_Status_R +// +// Global routine to read the Status Register from the Controller (Controller to Host) +// +// Pass: +// Nothing +// +// Returns: +// Value in the controller status register +// +READ8_MEMBER ( corvus_hdc_t::status_r ) { + return m_status; +} + + + +// +// Corvus_HDC_Data_R +// +// Read the Data Register from the Controller (Controller to Host). If transmission is complete, +// as defined as offset == bytes to transmit, reset the status to Host-to-Controller mode and Idle +// when complete. +// +// Pass: +// Nothing +// +// Returns: +// Value in the controller data register +// +READ8_MEMBER ( corvus_hdc_t::read ) { + UINT8 result; + + if((m_status & CONTROLLER_DIRECTION) == 0) { // Check to see if we're in Controller-to-Host mode + logerror("corvus_hdc_data_r: Data register read when in Host-to-Controller mode (status: 0x%2.2x)\n", m_status); + return 0; + } + + if((m_status & CONTROLLER_BUSY) != 0) { // Check to see if we're Busy + logerror("corvus_hdc_data_r: Data register read when Busy (status: 0x%2.2x)\n", m_status); + return 0; + } + + result = m_buffer.raw_data[m_offset++]; + + if(m_offset == m_xmit_bytes) { + LOG(("corvus_hdc_data_r: Finished transmitting %d bytes of data. Returning to idle mode.\n", m_xmit_bytes)); + + m_offset = 0; // We've reached the end of valid data + m_xmit_bytes = 0; // We don't have anything more to say + m_recv_bytes = 0; // No active commands + + m_cmd_timer->adjust(attotime::from_usec(INTERBYTE_DELAY), CALLBACK_HTC_MODE); + +// m_status &= ~(CONTROLLER_DIRECTION | CONTROLLER_BUSY); // Put us in Idle, Host-to-Controller mode + } else { + // + // Not finished with this packet. Insert an interbyte delay and then let the host continue + // + m_cmd_timer->adjust(attotime::from_usec(INTERBYTE_DELAY), CALLBACK_SAME_MODE); + } + + return result; +} + + + +// +// Corvus_HDC_Data_W +// +// Write to the Data Register on the Controller (Host to Controller) +// +// Pass: +// Value to write to controller data register +// +// Returns: +// Nothing +// +WRITE8_MEMBER ( corvus_hdc_t::write ) { + // + // Received a byte -- check to see if we should really respond + // + if((m_status & CONTROLLER_DIRECTION) != 0) { // System wrote to controller when controller wasn't listening + logerror("corvus_hdc_data_w: Data register written when in Controller-to-Host mode (status: 0x%2.2x, data: 0x%2.2x)\n", + m_status, data); + return; + } + + if((m_status & CONTROLLER_BUSY) != 0) { // System wrote to controller when controller was busy + logerror("corvus_hdc_data_w: Data register written when controller not Ready (status: 0x%2.2x, data: 0x%2.2x)\n", + m_status, data); + return; + } + + // + // We're supposed to be paying attention. Make a decision about the data received + // + if(m_offset == 0) { // First byte of a packet + LOG(("corvus_hdc_data_w: Received a byte with m_offset == 0. Processing as command: 0x%2.2x\n", data)); + m_invalid_command_flag = parse_hdc_command(data); + m_timeout_timer->reset((attotime::from_seconds(4))); + m_timeout_timer->enable(1); // Start our four-second timer + } else if(m_offset == 1 && m_awaiting_modifier) { // Second byte of a packet + LOG(("corvus_hdc_data_w: Received a byte while awaiting modifier with m_offset == 0. Processing as modifier: 0x%2.2x\n", data)); + m_awaiting_modifier = false; + m_recv_bytes = corvus_cmd[m_buffer.command.code][data].recv_bytes; + m_xmit_bytes = corvus_cmd[m_buffer.command.code][data].xmit_bytes; + } + + m_buffer.raw_data[m_offset++] = data; + + assert(m_offset <= MAX_COMMAND_SIZE); // Something is wrong, or I undersized the buffer + + // + // We now have enough information to make a decision whether to execute the command, respond with a fatal response + // or just wait for more data. If we can do something, execute the command. Otherwise, just fall through and return + // to the user with us Ready for more data and in Host-to-Controller mode. + // + if(m_offset == m_recv_bytes) { // We've received enough data to process + corvus_process_command_packet(m_invalid_command_flag); + } else { + // + // Reset the four-second timer since we received some data + // + m_timeout_timer->reset((attotime::from_seconds(4))); + + // + // Make the controller busy for a few microseconds while the command is processed + // + m_status |= CONTROLLER_BUSY; + m_cmd_timer->adjust(attotime::from_usec(INTERBYTE_DELAY), CALLBACK_SAME_MODE); + } +} diff --git a/src/devices/machine/corvushd.h b/src/devices/machine/corvushd.h new file mode 100644 index 00000000000..bc83fa2585d --- /dev/null +++ b/src/devices/machine/corvushd.h @@ -0,0 +1,530 @@ +// license:BSD-3-Clause +// copyright-holders:Brett Wyer, Raphael Nabet +/***************************************************************************** + * + * includes/corvushd.h + * + * Implementation of the Corvus Systems Flat Cable Hard Disk controller + * + * Corvus Model 6 (5 MB): IMI 5006H hard disk (-chs 144,4,20 -ss 512) + * Corvus Model 11 (10 MB): IMI 5012H hard disk (-chs 358,3,20 -ss 512) + * Corvus Model 20 (20 MB): IMI 5018H hard disk (-chs 388,5,20 -ss 512) + * + ****************************************************************************/ + +#ifndef CORVUSHD_H_ +#define CORVUSHD_H_ + +#include "emu.h" +#include "imagedev/harddriv.h" +#include + +// +// Controller Commands +// + +// Read/Write Commands + +#define READ_SECTOR_256 0x02 +#define WRITE_SECTOR_256 0x03 +#define READ_CHUNK_128 0x12 +#define READ_CHUNK_256 0x22 +#define READ_CHUNK_512 0x32 +#define WRITE_CHUNK_128 0x13 +#define WRITE_CHUNK_256 0x23 +#define WRITE_CHUNK_512 0x33 + +// Semaphore Commands + +#define SEMAPHORE_LOCK_CODE 0x0b +#define SEMAPHORE_LOCK_MOD 0x01 +#define SEMAPHORE_UNLOCK_CODE 0x0b +#define SEMAPHORE_UNLOCK_MOD 0x11 +#define SEMAPHORE_INIT_CODE 0x1a +#define SEMAPHORE_INIT_MOD 0x10 +#define SEMAPHORE_STATUS_CODE 0x1a +#define SEMAPHORE_STATUS_MOD 0x41 + +// Pipe Commands + +#define PIPE_READ_CODE 0x1a +#define PIPE_READ_MOD 0x20 +#define PIPE_WRITE_CODE 0x1a +#define PIPE_WRITE_MOD 0x21 +#define PIPE_CLOSE_CODE 0x1a +#define PIPE_CLOSE_MOD 0x40 +#define PIPE_STATUS_CODE 0x1a +#define PIPE_STATUS_MOD 0x41 +#define PIPE_OPEN_WRITE_CODE 0x1b +#define PIPE_OPEN_WRITE_MOD 0x80 +#define PIPE_AREA_INIT_CODE 0x1b +#define PIPE_AREA_INIT_MOD 0xa0 +#define PIPE_OPEN_READ_CODE 0x1b +#define PIPE_OPEN_READ_MOD 0xc0 + +// Active User Table Commands + +#define ADDACTIVE_CODE 0x34 +#define ADDACTIVE_MOD 0x03 +#define DELACTIVEUSR_REVBH_CODE 0x34 +#define DELACTIVEUSR_REVBH_MOD 0x00 +#define DELACTIVENUM_OMNI_CODE 0x34 +#define DELACTIVENUM_OMNI_MOD 0x00 +#define DELACTIVEUSR_OMNI_CODE 0x34 +#define DELACTIVEUSR_OMNI_MOD 0x31 +#define FINDACTIVE_CODE 0x34 +#define FINDACTIVE_MOD 0x05 +#define READTEMPBLOCK 0xc4 +#define WRITETEMPBLOCK 0xb4 + +// Miscellaneous Commands + +#define BOOT 0x14 +#define READ_BOOT_BLOCK 0x44 +#define GET_DRIVE_PARAMETERS 0x10 +#define PARK_HEADS_REVH 0x11 +#define PARK_HEADS_OMNI 0x80 +#define ECHO 0xf4 + +// Put drive in Prep Mode + +#define PREP_MODE_SELECT 0x11 + +// Prep Mode Commands + +#define PREP_RESET_DRIVE 0x00 +#define PREP_FORMAT_DRIVE 0x01 +#define PREP_FILL_DRIVE_OMNI 0x81 +#define PREP_VERIFY 0x07 +#define PREP_READ_FIRMWARE 0x32 +#define PREP_WRITE_FIRMWARE 0x33 + +// +// Controller Status Codes +// + +// Disk status codes + +#define STAT_SUCCESS 0x00 + +#define STAT_HEADER_FAULT 0x00 +#define STAT_SEEK_TIMEOUT 0x01 +#define STAT_SEEK_FAULT 0x02 +#define STAT_SEEK_ERROR 0x03 +#define STAT_HEADER_CRC_ERROR 0x04 +#define STAT_REZERO_FAULT 0x05 +#define STAT_REZERO_TIMEOUT 0x06 +#define STAT_DRIVE_NOT_ONLINE 0x07 +#define STAT_WRITE_FAULT 0x08 +#define STAT_NOT_USED 0x09 +#define STAT_READ_DATA_FAULT 0x0a +#define STAT_DATA_CRC_ERROR 0x0b +#define STAT_SECTOR_LOCATE_ERR 0x0c +#define STAT_WRITE_PROTECTED 0x0d +#define STAT_ILL_SECTOR_ADDRESS 0x0e +#define STAT_ILL_CMD_OP_CODE 0x0f +#define STAT_DRIVE_NOT_ACK 0x10 +#define STAT_ACK_STUCK_ACTIVE 0x11 +#define STAT_TIMEOUT 0x12 +#define STAT_FAULT 0x13 +#define STAT_CRC 0x14 +#define STAT_SEEK 0x15 +#define STAT_VERIFICATION 0x16 +#define STAT_SPEED_ERROR 0x17 +#define STAT_ILL_ADDRESS 0x18 +#define STAT_RW_FAULT_ERROR 0x19 +#define STAT_SERVO_ERROR 0x1a +#define STAT_GUARD_BAND 0x1b +#define STAT_PLO_ERROR 0x1c +#define STAT_RW_UNSAFE 0x1d + +// Disk status modifiers (added to status code) + +#define STAT_RECOVERABLE_ERR 0x20 +#define STAT_VERIFY_ERR 0x40 +#define STAT_FATAL_ERR 0x80 + +// Semaphore status codes + +#define SEM_PRIOR_STATE_NOT_SET 0x00 +#define SEM_PRIOR_STATE_SET 0x80 +#define SEM_TABLE_FULL 0xfd +#define SEM_DISK_ERROR 0xfe + +// Pipe Status codes + +#define PIPE_REQ_SUCCESSFUL 0x00 +#define PIPE_EMPTY_PIPE_READ 0x08 +#define PIPE_NOT_OPEN 0x09 +#define PIPE_WRITE_TO_FULL_PIPE 0x0a +#define PIPE_OPEN_OPEN_PIPE 0x0b +#define PIPE_PIPE_NOT_EXIST 0x0c +#define PIPE_NO_ROOM_FOR_NEW 0x0d +#define PIPE_ILLEGAL_COMMAND 0x0e +#define PIPE_AREA_NOT_INIT 0x0f + +// Pipe State codes + +#define PIPE_OPEN_WRITE_EMPTY 0x01 +#define PIPE_OPEN_READ_EMPTY 0x02 +#define PIPE_NOT_OPEN_FULL 0x80 +#define PIPE_OPEN_WRITE_FULL 0x81 +#define PIPE_OPEN_READ_FULL 0x82 + +// Status Register Bits + +#define CONTROLLER_BUSY 0x80 // Set = Busy, Clear = Ready +#define CONTROLLER_DIRECTION 0x40 // Set = Controller->Host, Clear = Host->Controller + +#define MAX_COMMAND_SIZE 4096 // The maximum size of a command packet (the controller only has 5K of RAM...) + +class corvus_hdc_t : public device_t +{ +public: + // construction/destruction + corvus_hdc_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + DECLARE_READ8_MEMBER( read ); + DECLARE_WRITE8_MEMBER( write ); + DECLARE_READ8_MEMBER( status_r ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + +private: + enum + { + TIMER_TIMEOUT, + TIMER_COMMAND + }; + + // Sector addressing scheme for Rev B/H drives used in various commands (Called a DADR in the docs) + struct dadr_t { + UINT8 address_msn_and_drive;// Most significant nibble: Most signficant nibble of sector address, Least significant nibble: Drive # + UINT8 address_lsb; // Least significant byte of sector address + UINT8 address_mid; // Middle byte of sector address + }; + + UINT8 m_status; // Controller status byte (DIRECTION + BUSY/READY) + // Prep mode + bool m_prep_mode; // Whether the controller is in Prep Mode or not + UINT8 m_prep_drv; // If in prep mode, Corvus drive id (1..15) being prepped + // Physical drive info + UINT8 m_sectors_per_track; // Number of sectors per track for this drive + UINT8 m_tracks_per_cylinder;// Number of tracks per cylinder (heads) + UINT16 m_cylinders_per_drive;// Number of cylinders per drive + // Command Processing + UINT16 m_offset; // Current offset into raw_data buffer + bool m_awaiting_modifier; // We've received a two-byte command and we're waiting for the mod + UINT16 m_recv_bytes; // Number of bytes expected to be received from Host + UINT16 m_xmit_bytes; // Number of bytes expected to be transmitted to host + // Timing-related values + UINT16 m_last_cylinder; // Last cylinder accessed - for calculating seek times + UINT32 m_delay; // Delay in microseconds for callback + emu_timer *m_timeout_timer; // Four-second timer for timeouts + emu_timer *m_cmd_timer; + bool m_invalid_command_flag; // I hate this, but it saves a lot more tests + + // + // Union below represents both an input and output buffer and interpretations of it + // + union { + // + // Raw Buffer + // + UINT8 raw_data[MAX_COMMAND_SIZE]; + // + // Basic interpretation of code and modifier + // + struct { + UINT8 code; // First byte of data is the code (command) + UINT8 modifier; // Second byte of data is the modifier + } command; + // + // Basic response code + // + struct { + UINT8 status; // Status code returned by the command executed + } single_byte_response; + // + // Read sector command + // + struct { + UINT8 code; // Command code + dadr_t dadr; // Encoded drive and sector to read + } read_sector_command; + // + // 128-byte Read Sector response + // + struct { + UINT8 status; // Status code returned by command executed + UINT8 data[128]; // Data returned from read + } read_128_response; + // + // 256-byte Read Sector response + // + struct { + UINT8 status; // Status code returned by command executed + UINT8 data[256]; // Data returned from read + } read_256_response; + // + // 512-byte Read Sector response + // + struct { + UINT8 status; // Status code returned by command executed + UINT8 data[512]; // Data returned by read + } read_512_response; + // + // Write 128-byte sector command + // + struct { + UINT8 code; // Command code + dadr_t dadr; // Encoded drive and sector to write + UINT8 data[128]; // Data to be written + } write_128_command; + // + // Write 256-byte sector command + // + struct { + UINT8 code; // Command code + dadr_t dadr; // Encoded drive and sector to write + UINT8 data[256]; // Data to be written + } write_256_command; + // + // Write 512-byte sector command + // + struct { + UINT8 code; // Command Code + dadr_t dadr; // Encoded drive and sector to write + UINT8 data[512]; // Data to be written + } write_512_command; + // + // Semaphore Lock command + // + struct { + UINT8 code; // Command code + UINT8 modifier; // Command code modifier + UINT8 name[8]; // Semaphore name + } lock_semaphore_command; + // + // Semaphore Unlock command + // + struct { + UINT8 code; // Command code + UINT8 modifier; // Command code modifier + UINT8 name[8]; // Semaphore name + } unlock_semaphore_command; + // + // Semaphore Lock/Unlock response + // + struct { + UINT8 status; // Disk access status + UINT8 result; // Semaphore action status + UINT8 unused[10]; // Unused + } semaphore_locking_response; + // + // Initialize Semaphore table command + // + struct { + UINT8 code; // Command code + UINT8 modifier; // Command code modifier + UINT8 unused[3]; // Unused + } init_semaphore_command; + // + // Semaphore Status command + // + struct { + UINT8 code; // Command code + UINT8 modifier; // Command code modifier + UINT8 zero_three; // Don't ask me... + UINT8 unused[2]; // Unused + } semaphore_status_command; + // + // Semaphore Status response + // + struct { + UINT8 status; // Disk access status + UINT8 table[256]; // Contents of the semaphore table + } semaphore_status_response; + // + // Get Drive Parameters command (0x10) + // + struct { + UINT8 code; // Command code + UINT8 drive; // Drive number (starts at 1) + } get_drive_parameters_command; + // + // Get Drive Parameters command response + // + struct { + UINT8 status; // Status code returned by command executed + UINT8 firmware_desc[31]; // Firmware string description + UINT8 firmware_rev; // Firmware revision number + UINT8 rom_version; // ROM Version + struct { + UINT8 sectors_per_track; // Sectors/Track + UINT8 tracks_per_cylinder; // Tracks/Cylinder (heads) + struct { + UINT8 lsb; + UINT8 msb; + } cylinders_per_drive; // Byte-flipped Cylinders/Drive + } track_info; + struct { + UINT8 lsb; // Least significant byte + UINT8 midb; // Middle byte + UINT8 msb; // Most significant byte + } capacity; // 24-bit value, byte-flipped (lsb..msb) + UINT8 unused[16]; + UINT8 interleave; // Interleave factor + struct { + UINT8 mux_parameters[12]; + UINT8 pipe_name_table_ptr[2]; // Pointer to table of 64 entries, 8 bytes each (table of names) + UINT8 pipe_ptr_table_ptr[2]; // Pointer to table of 64 entries, 8 bytes each. See pp. 29 - Mass Storage GTI + UINT8 pipe_area_size[2]; // Size of pipe area (lsb, msb) + struct { + UINT8 track_offset[2]; + } vdo_table[7]; // Virtual drive table + UINT8 lsi11_vdo_table[8]; + UINT8 lsi11_spare_table[8]; + } table_info; + UINT8 drive_number; // Physical drive number + struct { + UINT8 lsb; // Least + UINT8 midb; // Middle + UINT8 msb; // Most + } physical_capacity; // Physical capacity of drive + } drive_param_response; + // + // 2-byte Boot command (0x14) + // + struct { + UINT8 code; // Command code + UINT8 boot_block; // Which boot block to read (0-7) + } old_boot_command; + // + // Put drive into prep mode command (0x11) + // + struct { + UINT8 code; // Command code + UINT8 drive; // Drive number (starts at 1) + UINT8 prep_block[512]; // Machine code payload + } prep_mode_command; + // + // Read Firmware command (Prep Mode 0x32) + // + struct { + UINT8 code; // Command Code + UINT8 encoded_h_s;// Encoded Head (bits 7-5) / Sector (bits 4-0) + } read_firmware_command; + // + // Write Firmware command (Prep Mode 0x33) + // + struct { + UINT8 code; // Command Code + UINT8 encoded_h_s; // Encoded Head (bits 7-5) / Sector (bits 4-0) + UINT8 data[512]; // Data to be written + } write_firmware_command; + // + // Format Drive command (Prep Mode 0x01) + // + // Note that the following is a BLATANT ASSUMPTION. Technically, the Format Drive command + // uses a variable-length buffer for the pattern. Unfortunately, the docs don't explain how to determine the + // length of the buffer passed. I assume it's a timeout; however, the docs happen to say that + // all Corvus diagnostic programs send 513 bytes total, including the command, so I'm going with that. + // + struct { + UINT8 code; // Command Code + UINT8 pattern[512]; // Pattern to be written + } format_drive_revbh_command; + // + // Verify Drive command (Prep Mode 0x07) + // + // On the real Corvus controller, this is a variable length response. If the + // number of bad sectors is greater than zero, an additional four bytes will + // follow for each bad sector. We don't emulate bad sectors, so we always + // return a count of 0. That makes this a fixed length response of 2 bytes. + // + struct { + UINT8 status; // Disk access status + UINT8 bad_sectors; // Number of bad sectors (always zero) + } verify_drive_response; + } m_buffer; + + // Structure of Block #1, the Disk Parameter Block + struct disk_parameter_block_t { + struct { + UINT8 lsb; + UINT8 msb; + } spared_track[8]; // Spared track table (0xffff indicates end) + UINT8 interleave; // Interleave factor + UINT8 reserved; + struct { + UINT8 track_offset[2]; // Virtual drive offsets (lsb, msb) 0xffff indicates unused + } vdo_table[7]; + UINT8 lsi11_vdo_table[8]; + UINT8 lsi11_spare_table[8]; + UINT8 reserved2[432]; + struct { + UINT8 lsb; + UINT8 msb; + } revh_spare_table[16]; + }; + + // Structure of Block #3, the Constellation Parameter Block + struct constellation_parameter_block_t { + UINT8 mux_parameters[12]; + UINT8 pipe_name_table_ptr[2]; + UINT8 pipe_ptr_table_ptr[2]; + UINT8 pipe_area_size[2]; + UINT8 reserved[470]; + UINT8 software_protection[12]; + UINT8 serial_number[12]; + }; + + // Structure of Block #7, the Semaphore Table Block + struct semaphore_table_block_t { + union { + UINT8 semaphore_table[256]; // Table consists of 256 bytes + struct { + UINT8 semaphore_name[8]; // Each semaphore name is 8 bytes + } semaphore_entry[32]; // 32 Entries + } semaphore_block; + UINT8 unused[256]; // Remaining half of block is unused + }; + + // Command size structure (number of bytes to xmit and recv for each command) + struct corvus_cmd_t { + UINT16 recv_bytes; // Number of bytes from host for this command + UINT16 xmit_bytes; // Number of bytes to return to host + }; + + void dump_buffer(UINT8 *buffer, UINT16 length); + bool parse_hdc_command(UINT8 data); + UINT8 corvus_write_sector(UINT8 drv, UINT32 sector, UINT8 *buffer, int len); + UINT8 corvus_write_logical_sector(dadr_t *dadr, UINT8 *buffer, int len); + UINT8 corvus_read_sector(UINT8 drv, UINT32 sector, UINT8 *buffer, int len); + UINT8 corvus_read_logical_sector(dadr_t *dadr, UINT8 *buffer, int len); + UINT8 corvus_lock_semaphore(UINT8 *name); + UINT8 corvus_unlock_semaphore(UINT8 *name); + UINT8 corvus_init_semaphore_table(); + UINT8 corvus_get_drive_parameters(UINT8 drv); + UINT8 corvus_read_boot_block(UINT8 block); + UINT8 corvus_enter_prep_mode(UINT8 drv, UINT8 *prep_block); + UINT8 corvus_exit_prep_mode(); + UINT8 corvus_read_firmware_block(UINT8 head, UINT8 sector); + UINT8 corvus_write_firmware_block(UINT8 head, UINT8 sector, UINT8 *buffer); + UINT8 corvus_format_drive(UINT8 *pattern, UINT16 len); + hard_disk_file *corvus_hdc_file(int id); + void corvus_process_command_packet(bool local_invalid_command_flag); + + corvus_cmd_t corvus_cmd[0xf5][0xc1]; // Command sizes and their return sizes + corvus_cmd_t corvus_prep_cmd[0x82]; // Prep Command sizes and their return sizes +}; + + +// device type definition +extern const device_type CORVUS_HDC; + +#endif /* CORVUSHD_H_ */ diff --git a/src/devices/machine/cr511b.c b/src/devices/machine/cr511b.c new file mode 100644 index 00000000000..9ce22895dba --- /dev/null +++ b/src/devices/machine/cr511b.c @@ -0,0 +1,121 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best +/*************************************************************************** + + CR-511-B CD-ROM drive + + CD-ROM drive with a custom MKE/Panasonic interface as used in the + Commodore CDTV and early SoundBlaster cards. + +***************************************************************************/ + +#include "cr511b.h" + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type CR511B = &device_creator; + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( cr511b ) + MCFG_CDROM_ADD("cdrom") + MCFG_CDROM_INTERFACE("cdrom") + MCFG_SOUND_ADD("cdda", CDDA, 0) + MCFG_SOUND_ROUTE(0, ":lspeaker", 1.0) + MCFG_SOUND_ROUTE(1, ":rspeaker", 1.0) +MACHINE_CONFIG_END + +machine_config_constructor cr511b_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( cr511b ); +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// cr511b_device - constructor +//------------------------------------------------- + +cr511b_device::cr511b_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, CR511B, "CR-511-B CD-ROM drive", tag, owner, clock, "cr511b", __FILE__), + m_cdrom(*this, "cdrom"), + m_cdda(*this, "cdda"), + m_stch_handler(*this), + m_sten_handler(*this), + m_drq_handler(*this), + m_dten_handler(*this), + m_scor_handler(*this), + m_xaen_handler(*this), + m_frame_timer(NULL), + //m_motor(false), + m_enabled(-1), + m_cmd(-1) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void cr511b_device::device_start() +{ + // resolve callbacks + m_stch_handler.resolve_safe(); + m_sten_handler.resolve_safe(); + m_drq_handler.resolve_safe(); + m_dten_handler.resolve_safe(); + m_scor_handler.resolve_safe(); + m_xaen_handler.resolve_safe(); + + m_frame_timer = timer_alloc(0, NULL); + m_frame_timer->adjust(attotime::never); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void cr511b_device::device_reset() +{ +} + +//------------------------------------------------- +// device_timer - device-specific timer events +//------------------------------------------------- + +void cr511b_device::device_timer(emu_timer &timer, device_timer_id tid, int param, void *ptr) +{ +} + + +//************************************************************************** +// IMPLEMENTATION +//************************************************************************** + +READ8_MEMBER( cr511b_device::read ) +{ + return 0xff; +} + +WRITE8_MEMBER ( cr511b_device::write ) +{ +} + +WRITE_LINE_MEMBER( cr511b_device::enable_w ) +{ + m_enabled = state; +} + +WRITE_LINE_MEMBER( cr511b_device::cmd_w ) +{ + m_cmd = state; +} diff --git a/src/devices/machine/cr511b.h b/src/devices/machine/cr511b.h new file mode 100644 index 00000000000..59a8fc13fca --- /dev/null +++ b/src/devices/machine/cr511b.h @@ -0,0 +1,150 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best +/*************************************************************************** + + CR-511-B CD-ROM drive + + CD-ROM drive with a custom MKE/Panasonic interface as used in the + Commodore CDTV and early SoundBlaster cards. + + 1 _RESET 2 GND + 3 EFFK 4 SCCK + 5 SBCP 6 SCOR + 7 GND 8 GND + 9 C16M 10 GND + 11 _XAEN 12 GND + 13 EMPASIS 14 D0 + 15 LRCK 16 DSCK + 17 _MUTE 18 GND + 19 _BUSY 20 _STCH + 21 _ENABLE 22 DRQ + 23 _HWR 24 GND + 25 _DTEN 26 _HRD + 27 _STEN 28 _CMD + 29 _EOP 30 GND + 31 DB7 32 GND + 33 DB6 34 DB5 + 35 DB4 36 GND + 37 DB3 38 DB2 + 39 DB1 40 DB0 + +***************************************************************************/ + +#pragma once + +#ifndef __CR511B_H__ +#define __CR511B_H__ + +#include "emu.h" +#include "imagedev/chd_cd.h" +#include "sound/cdda.h" + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_CR511B_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, CR511B, 0) +#define MCFG_CR511B_STCH_HANDLER(_devcb) \ + devcb = &cr511b_device::set_stch_handler(*device, DEVCB_##_devcb); + +#define MCFG_CR511B_STEN_HANDLER(_devcb) \ + devcb = &cr511b_device::set_sten_handler(*device, DEVCB_##_devcb); + +#define MCFG_CR511B_DRQ_HANDLER(_devcb) \ + devcb = &cr511b_device::set_drq_handler(*device, DEVCB_##_devcb); + +#define MCFG_CR511B_DTEN_HANDLER(_devcb) \ + devcb = &cr511b_device::set_dten_handler(*device, DEVCB_##_devcb); + +#define MCFG_CR511B_SCOR_HANDLER(_devcb) \ + devcb = &cr511b_device::set_scor_handler(*device, DEVCB_##_devcb); + +#define MCFG_CR511B_XAEN_HANDLER(_devcb) \ + devcb = &cr511b_device::set_xaen_handler(*device, DEVCB_##_devcb); + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> cr511b_device + +class cr511b_device : public device_t +{ +public: + // construction/destruction + cr511b_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // callbacks + template static devcb_base &set_stch_handler(device_t &device, _Object object) + { return downcast(device).m_stch_handler.set_callback(object); } + + template static devcb_base &set_sten_handler(device_t &device, _Object object) + { return downcast(device).m_sten_handler.set_callback(object); } + + template static devcb_base &set_drq_handler(device_t &device, _Object object) + { return downcast(device).m_drq_handler.set_callback(object); } + + template static devcb_base &set_dten_handler(device_t &device, _Object object) + { return downcast(device).m_dten_handler.set_callback(object); } + + template static devcb_base &set_scor_handler(device_t &device, _Object object) + { return downcast(device).m_scor_handler.set_callback(object); } + + template static devcb_base &set_xaen_handler(device_t &device, _Object object) + { return downcast(device).m_xaen_handler.set_callback(object); } + + DECLARE_READ8_MEMBER( read ); + DECLARE_WRITE8_MEMBER ( write ); + + DECLARE_WRITE_LINE_MEMBER( enable_w ); + DECLARE_WRITE_LINE_MEMBER( cmd_w ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual machine_config_constructor device_mconfig_additions() const; + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + +private: + enum + { + STATUS_DOOR_CLOSED = 0x80, + STATUS_MEDIA = 0x40, + STATUS_MOTOR = 0x20, + STATUS_ERROR = 0x10, + STATUS_SUCCESS = 0x08, + STATUS_PLAYING = 0x04, + STATUS_DOOR_LOCKED = 0x02, + STATUS_READY = 0x01 + }; + + required_device m_cdrom; + required_device m_cdda; + + devcb_write_line m_stch_handler; + devcb_write_line m_sten_handler; + devcb_write_line m_drq_handler; + devcb_write_line m_dten_handler; + devcb_write_line m_scor_handler; + devcb_write_line m_xaen_handler; + + emu_timer *m_frame_timer; + + //bool m_motor; + + // state of lines + int m_enabled; + int m_cmd; + + // data transfer + //UINT8 m_sector_buffer[CD_MAX_SECTOR_DATA]; +}; + +// device type definition +extern const device_type CR511B; + +#endif diff --git a/src/devices/machine/cr589.c b/src/devices/machine/cr589.c new file mode 100644 index 00000000000..8c0ae34f6c9 --- /dev/null +++ b/src/devices/machine/cr589.c @@ -0,0 +1,196 @@ +// license:BSD-3-Clause +// copyright-holders:smf +#include "cr589.h" + + +static const int identity_offset = 0x3ab; +static const char download_identity[] = "MATSHITA CD98Q4 DOWNLOADGS0N"; + +//------------------------------------------------- +// nvram_default - called to initialize NVRAM to +// its default state +//------------------------------------------------- + +void matsushita_cr589_device::nvram_default() +{ + memset( buffer, 0, sizeof(buffer)); + memcpy( &buffer[ identity_offset ], "MATSHITACD-ROM CR-589 GS0N", 28 ); +} + + + +//------------------------------------------------- +// nvram_read - called to read NVRAM from the +// .nv file +//------------------------------------------------- + +void matsushita_cr589_device::nvram_read(emu_file &file) +{ + file.read(buffer, sizeof(buffer)); +} + + + +//------------------------------------------------- +// nvram_write - called to write NVRAM to the +// .nv file +//------------------------------------------------- + +void matsushita_cr589_device::nvram_write(emu_file &file) +{ + file.write(buffer, sizeof(buffer)); +} + + + +void matsushita_cr589_device::ExecCommand() +{ + switch( command[ 0 ] ) + { + case T10SPC_CMD_INQUIRY: + logerror("T10MMC: INQUIRY\n"); + m_phase = SCSI_PHASE_DATAIN; + m_status_code = SCSI_STATUS_CODE_GOOD; + m_transfer_length = SCSILengthFromUINT8( &command[ 4 ] ); + break; + + case 0x3b: // WRITE BUFFER + bufferOffset = ( command[ 3 ] << 16 ) | ( command[ 4 ] << 8 ) | command[ 5 ]; + m_phase = SCSI_PHASE_DATAOUT; + m_status_code = SCSI_STATUS_CODE_GOOD; + m_transfer_length = ( command[ 6 ] << 16 ) | ( command[ 7 ] << 8 ) | command[ 8 ]; + break; + + case 0x3c: // READ BUFFER + bufferOffset = ( command[ 3 ] << 16 ) | ( command[ 4 ] << 8 ) | command[ 5 ]; + m_phase = SCSI_PHASE_DATAIN; + m_status_code = SCSI_STATUS_CODE_GOOD; + m_transfer_length = ( command[ 6 ] << 16 ) | ( command[ 7 ] << 8 ) | command[ 8 ]; + break; + + case 0xcc: // FIRMWARE DOWNLOAD ENABLE + m_phase = SCSI_PHASE_DATAOUT; + m_status_code = SCSI_STATUS_CODE_GOOD; + m_transfer_length = SCSILengthFromUINT16( &command[7] ); + break; + + default: + t10mmc::ExecCommand(); + break; + } +} + +void matsushita_cr589_device::ReadData( UINT8 *data, int dataLength ) +{ + switch( command[ 0 ] ) + { + case T10SPC_CMD_INQUIRY: + memset(data, 0, dataLength); + + t10mmc::ReadData( data, dataLength ); + + if( download ) + { + memcpy( &data[ 8 ], download_identity, 28 ); + } + else + { + memcpy( &data[ 8 ], &buffer[ identity_offset ], 28 ); + } + break; + + case 0x3c: // READ BUFFER + memcpy( data, &buffer[ bufferOffset ], dataLength ); + bufferOffset += dataLength; + break; + + default: + t10mmc::ReadData( data, dataLength ); + break; + } +} + +void matsushita_cr589_device::WriteData( UINT8 *data, int dataLength ) +{ + switch( command[ 0 ] ) + { + case 0x3b: // WRITE BUFFER + memcpy( &buffer[ bufferOffset ], data + 32, dataLength - 32 ); + bufferOffset += dataLength; + break; + + case 0xcc: // FIRMWARE DOWNLOAD ENABLE + if( memcmp( data, &buffer[ identity_offset ], 28 ) == 0 ) + { + download = 1; + } + else if( memcmp( data, download_identity, 28 ) == 0 ) + { + download = 0; + } + break; + + default: + t10mmc::WriteData( data, dataLength ); + break; + } +} + +// device type definition +const device_type CR589 = &device_creator; + +matsushita_cr589_device::matsushita_cr589_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + atapi_cdrom_device(mconfig, CR589, "Matsushita CR589 CD-ROM Drive", tag, owner, clock, "cr589", __FILE__), + device_nvram_interface(mconfig, *this) +{ +} + +void matsushita_cr589_device::device_start() +{ + save_item(NAME(download)); + save_item(NAME(buffer)); + save_item(NAME(bufferOffset)); + + atapi_cdrom_device::device_start(); + + /// TODO: split identify buffer into another method as device_start() should be called after it's filled in, but the atapi_cdrom_device has it's own. + memset(m_identify_buffer, 0, sizeof(m_identify_buffer)); + + m_identify_buffer[ 0 ] = 0x8500; // ATAPI device, cmd set 5 compliant, DRQ within 3 ms of PACKET command + + m_identify_buffer[ 23 ] = ('1' << 8) | '.'; + m_identify_buffer[ 24 ] = ('0' << 8) | ' '; + m_identify_buffer[ 25 ] = (' ' << 8) | ' '; + m_identify_buffer[ 26 ] = (' ' << 8) | ' '; + + m_identify_buffer[ 27 ] = ('M' << 8) | 'A'; + m_identify_buffer[ 28 ] = ('T' << 8) | 'S'; + m_identify_buffer[ 29 ] = ('H' << 8) | 'I'; + m_identify_buffer[ 30 ] = ('T' << 8) | 'A'; + m_identify_buffer[ 31 ] = (' ' << 8) | 'C'; + m_identify_buffer[ 32 ] = ('R' << 8) | '-'; + m_identify_buffer[ 33 ] = ('5' << 8) | '8'; + m_identify_buffer[ 34 ] = ('9' << 8) | ' '; + m_identify_buffer[ 35 ] = (' ' << 8) | ' '; + m_identify_buffer[ 36 ] = (' ' << 8) | ' '; + m_identify_buffer[ 37 ] = (' ' << 8) | ' '; + m_identify_buffer[ 38 ] = (' ' << 8) | ' '; + m_identify_buffer[ 39 ] = (' ' << 8) | ' '; + m_identify_buffer[ 40 ] = (' ' << 8) | ' '; + m_identify_buffer[ 41 ] = (' ' << 8) | ' '; + m_identify_buffer[ 42 ] = (' ' << 8) | ' '; + m_identify_buffer[ 43 ] = (' ' << 8) | ' '; + m_identify_buffer[ 44 ] = (' ' << 8) | ' '; + m_identify_buffer[ 45 ] = (' ' << 8) | ' '; + m_identify_buffer[ 46 ] = (' ' << 8) | ' '; + + m_identify_buffer[ 49 ] = 0x0400; // IORDY may be disabled +} + +void matsushita_cr589_device::device_reset() +{ + atapi_cdrom_device::device_reset(); + + download = 0; + bufferOffset = 0; +} diff --git a/src/devices/machine/cr589.h b/src/devices/machine/cr589.h new file mode 100644 index 00000000000..87fe1c16641 --- /dev/null +++ b/src/devices/machine/cr589.h @@ -0,0 +1,48 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/*************************************************************************** + + cr589.h + + Matsushita CR589 + +***************************************************************************/ + +#pragma once + +#ifndef __CR589_H__ +#define __CR589_H__ + +#include "atapicdr.h" +#include "t10mmc.h" + +class matsushita_cr589_device : public atapi_cdrom_device, + public device_nvram_interface +{ +public: + matsushita_cr589_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual void ExecCommand(); + virtual void WriteData( UINT8 *data, int dataLength ); + virtual void ReadData( UINT8 *data, int dataLength ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_nvram_interface overrides + virtual void nvram_default(); + virtual void nvram_read(emu_file &file); + virtual void nvram_write(emu_file &file); + +private: + int download; + UINT8 buffer[ 65536 ]; + int bufferOffset; +}; + +// device type definition +extern const device_type CR589; + +#endif diff --git a/src/devices/machine/cs4031.c b/src/devices/machine/cs4031.c new file mode 100644 index 00000000000..b6d8de1acd8 --- /dev/null +++ b/src/devices/machine/cs4031.c @@ -0,0 +1,969 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best +/*************************************************************************** + + Chips & Technologies CS4031 chipset + + Chipset for 486 based PC/AT compatible systems. Consists of two + individual chips: + + * F84031 + - DRAM controller + - ISA-bus controller + - VESA VL-BUS controller + + * F84035 (82C206 IPC core) + - 2x 8257 DMA controller + - 2x 8259 interrupt controller + - 8254 timer + - MC14818 RTC + + TODO: + - No emulation of memory parity checks + - Move IPC core to its own file so it can be shared with + other chipsets + +***************************************************************************/ + +#include "emu.h" +#include "machine/ram.h" +#include "machine/cs4031.h" + + +//************************************************************************** +// MACROS/CONSTANTS +//************************************************************************** + +#define LOG_REGISTER 1 +#define LOG_MEMORY 1 +#define LOG_IO 1 +#define LOG_KEYBOARD 0 + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type CS4031 = &device_creator; + +const char* cs4031_device::m_register_names[] = +{ + /* 00 */ "RESERVED", + /* 01 */ "DMA WAIT STATE CONTROL", + /* 02 */ "RESERVED", + /* 03 */ "RESERVED", + /* 04 */ "RESERVED", + /* 05 */ "ISA BUS COMMAND DELAY", + /* 06 */ "ISA BUS WAIT STATES AND ADDRESS HOLD", + /* 07 */ "ISA BUS CLOCK SELECTION", + /* 08 */ "PERFORMANCE CONTROL", + /* 09 */ "84035 MISC CONTROL", + /* 0a */ "DMA CLOCK SELECTION", + /* 0b */ "RESERVED", + /* 0c */ "RESERVED", + /* 0d */ "RESERVED", + /* 0e */ "RESERVED", + /* 0f */ "RESERVED", + /* 10 */ "DRAM TIMING", + /* 11 */ "DRAM SETUP", + /* 12 */ "DRAM CONFIGURATION 0 AND 1", + /* 13 */ "DRAM CONFIGURATION 2 AND 3", + /* 14 */ "DRAM BLOCK 0 STARTING ADDRESS", + /* 15 */ "DRAM BLOCK 1 STARTING ADDRESS", + /* 16 */ "DRAM BLOCK 2 STARTING ADDRESS", + /* 17 */ "DRAM BLOCK 3 STARTING ADDRESS", + /* 18 */ "VIDEO AREA SHADOW AND LOCAL BUS CONTROL", + /* 19 */ "DRAM SHADOW READ ENABLE", + /* 1a */ "DRAM SHADOW WRITE ENABLE", + /* 1b */ "ROMCS ENABLE", + /* 1c */ "SOFT RESET AND GATEA20", + /* 1d */ "RESERVED", + /* 1e */ "RESERVED", + /* 1f */ "RESERVED" +}; + +const float cs4031_device::m_dma_clock_divider[] = +{ + 10, 8, 6, 0, 0, 0, 0, 0, 5, 4, 3, 2.5, 2, 1.5, 0, 0 +}; + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( cs4031 ) + MCFG_DEVICE_ADD("dma1", AM9517A, 0) + MCFG_I8237_OUT_HREQ_CB(DEVWRITELINE("dma2", am9517a_device, dreq0_w)) + MCFG_I8237_OUT_EOP_CB(WRITELINE(cs4031_device, dma1_eop_w)) + MCFG_I8237_IN_MEMR_CB(READ8(cs4031_device, dma_read_byte)) + MCFG_I8237_OUT_MEMW_CB(WRITE8(cs4031_device, dma_write_byte)) + MCFG_I8237_IN_IOR_0_CB(READ8(cs4031_device, dma1_ior0_r)) + MCFG_I8237_IN_IOR_1_CB(READ8(cs4031_device, dma1_ior1_r)) + MCFG_I8237_IN_IOR_2_CB(READ8(cs4031_device, dma1_ior2_r)) + MCFG_I8237_IN_IOR_3_CB(READ8(cs4031_device, dma1_ior3_r)) + MCFG_I8237_OUT_IOW_0_CB(WRITE8(cs4031_device, dma1_iow0_w)) + MCFG_I8237_OUT_IOW_1_CB(WRITE8(cs4031_device, dma1_iow1_w)) + MCFG_I8237_OUT_IOW_2_CB(WRITE8(cs4031_device, dma1_iow2_w)) + MCFG_I8237_OUT_IOW_3_CB(WRITE8(cs4031_device, dma1_iow3_w)) + MCFG_I8237_OUT_DACK_0_CB(WRITELINE(cs4031_device, dma1_dack0_w)) + MCFG_I8237_OUT_DACK_1_CB(WRITELINE(cs4031_device, dma1_dack1_w)) + MCFG_I8237_OUT_DACK_2_CB(WRITELINE(cs4031_device, dma1_dack2_w)) + MCFG_I8237_OUT_DACK_3_CB(WRITELINE(cs4031_device, dma1_dack3_w)) + MCFG_DEVICE_ADD("dma2", AM9517A, 0) + MCFG_I8237_OUT_HREQ_CB(WRITELINE(cs4031_device, dma2_hreq_w)) + MCFG_I8237_IN_MEMR_CB(READ8(cs4031_device, dma_read_word)) + MCFG_I8237_OUT_MEMW_CB(WRITE8(cs4031_device, dma_write_word)) + MCFG_I8237_IN_IOR_1_CB(READ8(cs4031_device, dma2_ior1_r)) + MCFG_I8237_IN_IOR_2_CB(READ8(cs4031_device, dma2_ior2_r)) + MCFG_I8237_IN_IOR_3_CB(READ8(cs4031_device, dma2_ior3_r)) + MCFG_I8237_OUT_IOW_1_CB(WRITE8(cs4031_device, dma2_iow1_w)) + MCFG_I8237_OUT_IOW_2_CB(WRITE8(cs4031_device, dma2_iow2_w)) + MCFG_I8237_OUT_IOW_3_CB(WRITE8(cs4031_device, dma2_iow3_w)) + MCFG_I8237_OUT_DACK_0_CB(WRITELINE(cs4031_device, dma2_dack0_w)) + MCFG_I8237_OUT_DACK_1_CB(WRITELINE(cs4031_device, dma2_dack1_w)) + MCFG_I8237_OUT_DACK_2_CB(WRITELINE(cs4031_device, dma2_dack2_w)) + MCFG_I8237_OUT_DACK_3_CB(WRITELINE(cs4031_device, dma2_dack3_w)) + MCFG_PIC8259_ADD("intc1", WRITELINE(cs4031_device, intc1_int_w), VCC, READ8(cs4031_device, intc1_slave_ack_r)) + MCFG_PIC8259_ADD("intc2", DEVWRITELINE("intc1", pic8259_device, ir2_w), GND, NULL) + + MCFG_DEVICE_ADD("ctc", PIT8254, 0) + MCFG_PIT8253_CLK0(XTAL_14_31818MHz / 12) + MCFG_PIT8253_OUT0_HANDLER(DEVWRITELINE("intc1", pic8259_device, ir0_w)) + MCFG_PIT8253_CLK1(XTAL_14_31818MHz / 12) + MCFG_PIT8253_OUT1_HANDLER(WRITELINE(cs4031_device, ctc_out1_w)) + MCFG_PIT8253_CLK2(XTAL_14_31818MHz / 12) + MCFG_PIT8253_OUT2_HANDLER(WRITELINE(cs4031_device, ctc_out2_w)) + + MCFG_DS12885_ADD("rtc") + MCFG_MC146818_IRQ_HANDLER(WRITELINE(cs4031_device, rtc_irq_w)) + MCFG_MC146818_CENTURY_INDEX(0x32) +MACHINE_CONFIG_END + +machine_config_constructor cs4031_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( cs4031 ); +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// cs4031_device - constructor +//------------------------------------------------- + +cs4031_device::cs4031_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, CS4031, "CS4031", tag, owner, clock, "cs4031", __FILE__), + m_read_ior(*this), + m_write_iow(*this), + m_write_tc(*this), + m_write_hold(*this), + m_write_nmi(*this), + m_write_intr(*this), + m_write_cpureset(*this), + m_write_a20m(*this), + m_write_spkr(*this), + m_dma1(*this, "dma1"), + m_dma2(*this, "dma2"), + m_intc1(*this, "intc1"), + m_intc2(*this, "intc2"), + m_ctc(*this, "ctc"), + m_rtc(*this, "rtc"), + m_dma_eop(0), + m_dma_high_byte(0xff), + m_dma_channel(-1), + m_portb(0x0f), + m_refresh_toggle(0), + m_iochck(1), + m_nmi_mask(1), + m_cpureset(0), + m_kbrst(1), + m_ext_gatea20(0), + m_fast_gatea20(0), + m_emu_gatea20(0), + m_keybc_d1_written(false), + m_keybc_data_blocked(false), + m_address(0), + m_address_valid(false) +{ +} + +void cs4031_device::static_set_cputag(device_t &device, const char *tag) +{ + cs4031_device &cs4031 = downcast(device); + cs4031.m_cputag = tag; +} + +void cs4031_device::static_set_isatag(device_t &device, const char *tag) +{ + cs4031_device &cs4031 = downcast(device); + cs4031.m_isatag = tag; +} + +void cs4031_device::static_set_biostag(device_t &device, const char *tag) +{ + cs4031_device &cs4031 = downcast(device); + cs4031.m_biostag = tag; +} + +void cs4031_device::static_set_keybctag(device_t &device, const char *tag) +{ + cs4031_device &cs4031 = downcast(device); + cs4031.m_keybctag = tag; +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void cs4031_device::device_start() +{ + ram_device *ram_dev = machine().device(RAM_TAG); + + // make sure the ram device is already running + if (!ram_dev->started()) + throw device_missing_dependencies(); + + // resolve callbacks + m_read_ior.resolve_safe(0); + m_write_iow.resolve_safe(); + m_write_tc.resolve_safe(); + m_write_hold.resolve_safe(); + m_write_nmi.resolve_safe(); + m_write_intr.resolve_safe(); + m_write_cpureset.resolve_safe(); + m_write_a20m.resolve_safe(); + m_write_spkr.resolve_safe(); + + // register for state saving + save_item(NAME(m_dma_eop)); + save_item(NAME(m_dma_page)); + save_item(NAME(m_dma_high_byte)); + save_item(NAME(m_dma_channel)); + save_item(NAME(m_portb)); + save_item(NAME(m_refresh_toggle)); + save_item(NAME(m_iochck)); + save_item(NAME(m_nmi_mask)); + save_item(NAME(m_cpureset)); + save_item(NAME(m_kbrst)); + save_item(NAME(m_ext_gatea20)); + save_item(NAME(m_fast_gatea20)); + save_item(NAME(m_address)); + save_item(NAME(m_address_valid)); + save_item(NAME(m_registers)); + + device_t *cpu = machine().device(m_cputag); + m_space = &cpu->memory().space(AS_PROGRAM); + m_space_io = &cpu->memory().space(AS_IO); + + m_isa = machine().root_device().memregion(m_isatag)->base(); + m_bios = machine().root_device().memregion(m_biostag)->base(); + m_keybc = downcast(machine().device(m_keybctag)); + + m_ram = ram_dev->pointer(); + UINT32 ram_size = ram_dev->size(); + + // install base memory + m_space->install_ram(0x000000, 0x09ffff, m_ram); + + // install extended memory + if (ram_size > 0x100000) + m_space->install_ram(0x100000, ram_size - 1, m_ram + 0x100000); + + // install bios rom at cpu inital pc + m_space->install_rom(0xffff0000, 0xffffffff, m_bios + 0xf0000); + + // install i/o accesses + m_space_io->install_readwrite_handler(0x0000, 0x000f, read8_delegate(FUNC(am9517a_device::read), &(*m_dma1)), write8_delegate(FUNC(am9517a_device::write), &(*m_dma1)), 0xffffffff); + m_space_io->install_readwrite_handler(0x0020, 0x0023, read8_delegate(FUNC(pic8259_device::read), &(*m_intc1)), write8_delegate(FUNC(pic8259_device::write), &(*m_intc1)), 0x0000ffff); + m_space_io->install_write_handler(0x0020, 0x0023, write8_delegate(FUNC(cs4031_device::config_address_w), this), 0x00ff0000); + m_space_io->install_readwrite_handler(0x0020, 0x0023, read8_delegate(FUNC(cs4031_device::config_data_r), this), write8_delegate(FUNC(cs4031_device::config_data_w), this), 0xff000000); + m_space_io->install_readwrite_handler(0x0040, 0x0043, read8_delegate(FUNC(pit8254_device::read), &(*m_ctc)), write8_delegate(FUNC(pit8254_device::write), &(*m_ctc)), 0xffffffff); + m_space_io->install_readwrite_handler(0x0060, 0x0063, read8_delegate(FUNC(cs4031_device::keyb_data_r), this), write8_delegate(FUNC(cs4031_device::keyb_data_w), this), 0x000000ff); + m_space_io->install_readwrite_handler(0x0060, 0x0063, read8_delegate(FUNC(cs4031_device::portb_r), this), write8_delegate(FUNC(cs4031_device::portb_w), this), 0x0000ff00); + m_space_io->install_readwrite_handler(0x0064, 0x0067, read8_delegate(FUNC(cs4031_device::keyb_status_r), this), write8_delegate(FUNC(cs4031_device::keyb_command_w), this), 0x000000ff); + m_space_io->install_readwrite_handler(0x0070, 0x0073, read8_delegate(FUNC(mc146818_device::read), &(*m_rtc)), write8_delegate(FUNC(cs4031_device::rtc_w), this), 0x0000ffff); + m_space_io->install_readwrite_handler(0x0080, 0x008f, read8_delegate(FUNC(cs4031_device::dma_page_r), this), write8_delegate(FUNC(cs4031_device::dma_page_w), this), 0xffffffff); + m_space_io->install_readwrite_handler(0x0090, 0x0093, read8_delegate(FUNC(cs4031_device::sysctrl_r), this), write8_delegate(FUNC(cs4031_device::sysctrl_w), this), 0x00ff0000); + m_space_io->install_readwrite_handler(0x00a0, 0x00a3, read8_delegate(FUNC(pic8259_device::read), &(*m_intc2)), write8_delegate(FUNC(pic8259_device::write), &(*m_intc2)), 0x0000ffff); + m_space_io->install_readwrite_handler(0x00c0, 0x00df, read8_delegate(FUNC(cs4031_device::dma2_r),this), write8_delegate(FUNC(cs4031_device::dma2_w),this), 0xffffffff); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void cs4031_device::device_reset() +{ + // setup default values + memset(&m_registers, 0x00, sizeof(m_registers)); + m_registers[ROMCS] = 0x60; + + // update rom/ram regions below 1mb + update_read_regions(); + update_write_regions(); + + // initialize dma controller clocks + update_dma_clock(); +} + +//------------------------------------------------- +// device_reset_after_children +//------------------------------------------------- + +void cs4031_device::device_reset_after_children() +{ + // timer 2 default state + m_ctc->write_gate2(1); +} + + +//************************************************************************** +// DMA CONTROLLER +//************************************************************************** + +offs_t cs4031_device::page_offset() +{ + switch (m_dma_channel) + { + case 0: return (offs_t) m_dma_page[0x07] << 16; + case 1: return (offs_t) m_dma_page[0x03] << 16; + case 2: return (offs_t) m_dma_page[0x01] << 16; + case 3: return (offs_t) m_dma_page[0x02] << 16; + case 5: return (offs_t) m_dma_page[0x0b] << 16; + case 6: return (offs_t) m_dma_page[0x09] << 16; + case 7: return (offs_t) m_dma_page[0x0a] << 16; + } + + // should never get here + return 0xff0000; +} + +READ8_MEMBER( cs4031_device::dma_read_byte ) +{ + if (m_dma_channel == -1) + return 0xff; + + return m_space->read_byte(page_offset() + offset); +} + +WRITE8_MEMBER( cs4031_device::dma_write_byte ) +{ + if (m_dma_channel == -1) + return; + + m_space->write_byte(page_offset() + offset, data); +} + +READ8_MEMBER( cs4031_device::dma_read_word ) +{ + if (m_dma_channel == -1) + return 0xff; + + UINT16 result = m_space->read_word(page_offset() + (offset << 1)); + m_dma_high_byte = result >> 8; + + return result; +} + +WRITE8_MEMBER( cs4031_device::dma_write_word ) +{ + if (m_dma_channel == -1) + return; + + m_space->write_word(page_offset() + (offset << 1), (m_dma_high_byte << 8) | data); +} + +WRITE_LINE_MEMBER( cs4031_device::dma2_dack0_w ) +{ + m_dma1->hack_w(state ? 0 : 1); // inverted? +} + +WRITE_LINE_MEMBER( cs4031_device::dma1_eop_w ) +{ + m_dma_eop = state; + if (m_dma_channel != -1) + m_write_tc(m_dma_channel, state, 0xff); +} + +void cs4031_device::set_dma_channel(int channel, bool state) +{ + if (!state) + { + m_dma_channel = channel; + if (m_dma_eop) + m_write_tc(channel, 1, 0xff); + } + else + { + if (m_dma_channel == channel) + { + m_dma_channel = -1; + if (m_dma_eop) + m_write_tc(channel, 0, 0xff); + } + } +} + +void cs4031_device::update_dma_clock() +{ + if (m_dma_clock_divider[m_registers[DMA_CLOCK] & 0x0f] != 0) + { + UINT32 dma_clock = clock() / m_dma_clock_divider[m_registers[DMA_CLOCK] & 0x0f]; + + if (!BIT(m_registers[DMA_WAIT_STATE], 0)) + dma_clock /= 2; + + logerror("cs4031_device::update_dma_clock: dma clock is now %u\n", dma_clock); + + m_dma1->set_unscaled_clock(dma_clock); + m_dma2->set_unscaled_clock(dma_clock); + } +} + + +//************************************************************************** +// INTERRUPTS +//************************************************************************** + +/* + Check NMI sources and generate NMI if needed + + Not emulated here: Parity check NMI + */ +void cs4031_device::nmi() +{ + if (m_nmi_mask & BIT(m_portb, 6)) + { + m_write_nmi(1); + m_write_nmi(0); + } +} + +READ8_MEMBER( cs4031_device::intc1_slave_ack_r ) +{ + if (offset == 2) // IRQ 2 + return m_intc2->acknowledge(); + + return 0x00; +} + +WRITE_LINE_MEMBER( cs4031_device::rtc_irq_w ) +{ + m_intc2->ir0_w(state ? 0 : 1); // inverted? +} + +WRITE_LINE_MEMBER( cs4031_device::iochck_w ) +{ + if (LOG_IO) + logerror("cs4031_device::iochck_w: %u\n", state); + + if (BIT(m_portb, 3) == 0) + { + if (m_iochck && state == 0) + { + // set channel check latch + m_portb |= 1 << 6; + nmi(); + } + + m_iochck = state; + } +} + + +//************************************************************************** +// TIMER +//************************************************************************** + +WRITE_LINE_MEMBER( cs4031_device::ctc_out1_w ) +{ + m_refresh_toggle ^= state; + m_portb = (m_portb & 0xef) | (m_refresh_toggle << 4); +} + +WRITE_LINE_MEMBER( cs4031_device::ctc_out2_w ) +{ + m_write_spkr(!(state & BIT(m_portb, 1))); + m_portb = (m_portb & 0xdf) | (state << 5); +} + + +//************************************************************************** +// CHIPSET CONFIGURATION +//************************************************************************** + +WRITE8_MEMBER( cs4031_device::config_address_w ) +{ + m_address = data; + m_address_valid = (m_address < 0x20) ? true : false; +} + +READ8_MEMBER( cs4031_device::config_data_r ) +{ + UINT8 result = 0xff; + + if (m_address_valid) + { + if (LOG_REGISTER) + logerror("cs4031_device: read %s = %02x\n", m_register_names[m_address], m_registers[m_address]); + + result = m_registers[m_address]; + } + + // after a read the selected address needs to be reset + m_address_valid = false; + + return result; +} + +WRITE8_MEMBER( cs4031_device::config_data_w ) +{ + if (m_address_valid) + { + if (LOG_REGISTER) + logerror("cs4031_device: write %s = %02x\n", m_register_names[m_address], data); + + // update register with new data + m_registers[m_address] = data; + + // execute command + switch (m_address) + { + case DMA_WAIT_STATE: + update_dma_clock(); + break; + + case 0x05: break; + case 0x06: break; + case 0x07: break; + case 0x08: break; + case 0x09: break; + + case DMA_CLOCK: + update_dma_clock(); + break; + + case 0x10: break; + case 0x11: break; + case 0x12: break; + case 0x13: break; + case 0x14: break; + case 0x15: break; + case 0x16: break; + case 0x17: break; + case 0x18: break; + + case SHADOW_READ: + update_read_regions(); + break; + + case SHADOW_WRITE: + update_write_regions(); + break; + + case ROMCS: + update_read_regions(); + update_write_regions(); + break; + + case SOFT_RESET_AND_GATEA20: + a20m(); + break; + } + } + + // after a write the selected address needs to be reset + m_address_valid = false; +} + + +//************************************************************************** +// MEMORY MAPPER +//************************************************************************** + +void cs4031_device::update_read_region(int index, const char *region, offs_t start, offs_t end) +{ + if (!BIT(m_registers[SHADOW_READ], index) && BIT(m_registers[ROMCS], index)) + { + if (LOG_MEMORY) + logerror("ROM read from %x to %x\n", start, end); + + m_space->install_read_bank(start, end, region); + machine().root_device().membank(region)->set_base(m_bios + start); + } + else if (!BIT(m_registers[SHADOW_READ], index) && !BIT(m_registers[ROMCS], index)) + { + if (LOG_MEMORY) + logerror("ISA read from %x to %x\n", start, end); + + m_space->install_read_bank(start, end, region); + machine().root_device().membank(region)->set_base(m_isa + start - 0xc0000); + } + else if (BIT(m_registers[SHADOW_READ], index)) + { + if (LOG_MEMORY) + logerror("RAM read from %x to %x\n", start, end); + + m_space->install_read_bank(start, end, region); + machine().root_device().membank(region)->set_base(m_ram + start); + } + else + { + if (LOG_MEMORY) + logerror("NOP read from %x to %x\n", start, end); + + m_space->nop_read(start, end); + } +} + +void cs4031_device::update_write_region(int index, const char *region, offs_t start, offs_t end) +{ + if (!BIT(m_registers[SHADOW_WRITE], index) && BIT(m_registers[ROMCS], index) && BIT(m_registers[ROMCS], 7)) + { + if (LOG_MEMORY) + logerror("ROM write from %x to %x\n", start, end); + + m_space->install_write_bank(start, end, region); + machine().root_device().membank(region)->set_base(m_bios + start); + } + else if (!BIT(m_registers[SHADOW_WRITE], index) && !BIT(m_registers[ROMCS], index)) + { + if (LOG_MEMORY) + logerror("ISA write from %x to %x\n", start, end); + + m_space->install_write_bank(start, end, region); + machine().root_device().membank(region)->set_base(m_isa + start - 0xc0000); + } + else if (BIT(m_registers[SHADOW_WRITE], index)) + { + if (LOG_MEMORY) + logerror("RAM write from %x to %x\n", start, end); + + m_space->install_write_bank(start, end, region); + machine().root_device().membank(region)->set_base(m_ram + start); + } + else + { + if (LOG_MEMORY) + logerror("NOP write from %x to %x\n", start, end); + + m_space->nop_write(start, end); + } +} + +void cs4031_device::update_read_regions() +{ + update_read_region(0, "read_c0000", 0xc0000, 0xc3fff); + update_read_region(1, "read_c4000", 0xc4000, 0xc7fff); + update_read_region(2, "read_c8000", 0xc8000, 0xcbfff); + update_read_region(3, "read_cc000", 0xcc000, 0xcffff); + update_read_region(4, "read_d0000", 0xd0000, 0xdffff); + update_read_region(5, "read_e0000", 0xe0000, 0xeffff); + update_read_region(6, "read_f0000", 0xf0000, 0xfffff); +} + +void cs4031_device::update_write_regions() +{ + update_write_region(0, "write_c0000", 0xc0000, 0xc3fff); + update_write_region(1, "write_c4000", 0xc4000, 0xc7fff); + update_write_region(2, "write_c8000", 0xc8000, 0xcbfff); + update_write_region(3, "write_cc000", 0xcc000, 0xcffff); + update_write_region(4, "write_d0000", 0xd0000, 0xdffff); + update_write_region(5, "write_e0000", 0xe0000, 0xeffff); + update_write_region(6, "write_f0000", 0xf0000, 0xfffff); +} + + +//************************************************************************** +// KEYBOARD / 8042 +//************************************************************************** + +void cs4031_device::a20m() +{ + // external signal is ignored when emulation is on + if (BIT(m_registers[SOFT_RESET_AND_GATEA20], 5)) + m_write_a20m(m_fast_gatea20 | m_emu_gatea20); + else + m_write_a20m(m_fast_gatea20 | m_ext_gatea20); +} + +void cs4031_device::emulated_kbreset(int state) +{ + if (BIT(m_registers[SOFT_RESET_AND_GATEA20], 4)) + { + // kbreset (input) is active low + // cpureset (output) is active high + m_write_cpureset(!state); + } +} + +void cs4031_device::emulated_gatea20(int state) +{ + if (BIT(m_registers[SOFT_RESET_AND_GATEA20], 5)) + { + m_emu_gatea20 = state; + a20m(); + } +} + +void cs4031_device::fast_gatea20(int state) +{ + m_fast_gatea20 = state; + a20m(); +} + +void cs4031_device::keyboard_gatea20(int state) +{ + m_ext_gatea20 = state; + a20m(); +} + +READ8_MEMBER( cs4031_device::keyb_status_r ) +{ + if (LOG_KEYBOARD) + logerror("cs4031_device::keyb_status_r\n"); + + return m_keybc->status_r(space, 0); +} + +WRITE8_MEMBER( cs4031_device::keyb_command_blocked_w ) +{ + // command is optionally blocked + if (!BIT(m_registers[SOFT_RESET_AND_GATEA20], 7)) + m_keybc->command_w(space, 0, data); +} + +WRITE8_MEMBER( cs4031_device::keyb_command_w ) +{ + if (LOG_KEYBOARD) + logerror("cs4031_device::keyb_command_w: %02x\n", data); + + m_keybc_d1_written = false; + + switch (data) + { + // self-test + case 0xaa: + emulated_kbreset(1); + emulated_gatea20(1); + + // self-test is never blocked + m_keybc->command_w(space, 0, data); + break; + + case 0xd1: + m_keybc_d1_written = true; + keyb_command_blocked_w(space, 0, data); + break; + + case 0xf0: + case 0xf1: + case 0xf2: + case 0xf4: + case 0xf5: + case 0xf6: + case 0xf8: + case 0xf9: + case 0xfa: + case 0xfc: + case 0xfd: + case 0xfe: + // toggle keyboard reset? + if (!BIT(data, 0)) + { + emulated_kbreset(0); + emulated_kbreset(1); + } + + // toggle gatea20? + if (!BIT(data, 1)) + { + emulated_gatea20(0); + emulated_gatea20(1); + } + + keyb_command_blocked_w(space, 0, data); + + break; + + case 0xff: + // last data write was blocked? + if (m_keybc_data_blocked) + { + m_keybc_data_blocked = false; + keyb_command_blocked_w(space, 0, data); + } + else + m_keybc->command_w(space, 0, data); + + break; + + // everything else goes directly to the keyboard controller + default: + m_keybc->command_w(space, 0, data); + break; + } +} + +READ8_MEMBER( cs4031_device::keyb_data_r ) +{ + if (LOG_KEYBOARD) + logerror("cs4031_device::keyb_data_r\n"); + + return m_keybc->data_r(space, 0); +} + +WRITE8_MEMBER( cs4031_device::keyb_data_w ) +{ + if (LOG_KEYBOARD) + logerror("cs4031_device::keyb_data_w: %02x\n", data); + + // data is blocked only for d1 command + if (BIT(m_registers[SOFT_RESET_AND_GATEA20], 7) && m_keybc_d1_written) + { + m_keybc_data_blocked = true; + emulated_kbreset(BIT(data, 0)); + emulated_gatea20(BIT(data, 1)); + } + else + { + m_keybc_data_blocked = false; + m_keybc->data_w(space, 0, data); + } +} + +WRITE_LINE_MEMBER( cs4031_device::gatea20_w ) +{ + if (LOG_KEYBOARD) + logerror("cs4031_device::gatea20_w: %u\n", state); + + keyboard_gatea20(state); +} + +WRITE_LINE_MEMBER( cs4031_device::kbrst_w ) +{ + if (LOG_KEYBOARD) + logerror("cs4031_device::kbrst_w: %u\n", state); + + // convert to active low signal (gets inverted in at_keybc.c) + state = (state == ASSERT_LINE ? 0 : 1); + + // external kbreset is ignored when emulation enabled + if (!BIT(m_registers[SOFT_RESET_AND_GATEA20], 4)) + { + // detect transition + if (m_kbrst == 1 && state == 0) + { + m_write_cpureset(1); + m_write_cpureset(0); + } + } + + m_kbrst = state; +} + +/* + Fast CPU reset and Gate A20 + + 0 - Fast CPU reset + 1 - Fast Gate A20 + + */ +WRITE8_MEMBER( cs4031_device::sysctrl_w ) +{ + if (LOG_IO) + logerror("cs4031_device::sysctrl_w: %u\n", data); + + fast_gatea20(BIT(data, 1)); + + if (m_cpureset == 0 && BIT(data, 0)) + { + // pulse reset line + m_write_cpureset(1); + m_write_cpureset(0); + } + + m_cpureset = BIT(data, 0); +} + +READ8_MEMBER( cs4031_device::sysctrl_r ) +{ + UINT8 result = 0; // reserved bits read as 0? + + result |= m_cpureset << 0; + result |= m_fast_gatea20 << 1; + + if (LOG_IO) + logerror("cs4031_device::sysctrl_r: %u\n", result); + + return result; +} + + +//************************************************************************** +// MISCELLANEOUS +//************************************************************************** + +/* + "Port B" - AT-compatible port with miscellaneous information + + 0 - Timer 2 gate (rw) + 1 - Speaker data (rw) + 2 - Enable parity check (rw) [not emulated] + 3 - Enable IOCHECK (rw) + 4 - Refresh detect (r) + 5 - Timer 2 output (r) + 6 - Channel check latch (r) + 7 - Parity check latch (r) [not emulated] +*/ + +READ8_MEMBER( cs4031_device::portb_r ) +{ + if (0) + logerror("cs4031_device::portb_r: %02x\n", m_portb); + + return m_portb; +} + +WRITE8_MEMBER( cs4031_device::portb_w ) +{ + if (0) + logerror("cs4031_device::portb_w: %02x\n", data); + + m_portb = (m_portb & 0xf0) | (data & 0x0f); + + // bit 5 forced to 1 if timer disabled + if (!BIT(m_portb, 0)) + m_portb |= 1 << 5; + + m_ctc->write_gate2(BIT(m_portb, 0)); + + m_write_spkr(!BIT(m_portb, 1)); + + // clear channel check latch? + if (BIT(m_portb, 3)) + m_portb &= 0xbf; +} + +/* + NMI mask and RTC address + + 7 - NMI mask + 6:0 - RTC address + */ +WRITE8_MEMBER( cs4031_device::rtc_w ) +{ + if (0) + logerror("cs4031_device::rtc_w: %02x\n", data); + + if (offset == 0) + { + m_nmi_mask = !BIT(data, 7); + data &= 0x7f; + } + + m_rtc->write(space, offset, data); +} diff --git a/src/devices/machine/cs4031.h b/src/devices/machine/cs4031.h new file mode 100644 index 00000000000..e27886f7b41 --- /dev/null +++ b/src/devices/machine/cs4031.h @@ -0,0 +1,290 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best +/*************************************************************************** + + Chips & Technologies CS4031 chipset + + Chipset for 486 based PC/AT compatible systems. Consists of two + individual chips: + + * F84031 + - DRAM controller + - ISA-bus controller + - VESA VL-BUS controller + + * F84035 (82C206 IPC core) + - 2x 8257 DMA controller + - 2x 8259 interrupt controller + - 8254 timer + - MC14818 RTC + +***************************************************************************/ + +#pragma once + +#ifndef __CS4031_H__ +#define __CS4031_H__ + +#include "emu.h" +#include "machine/am9517a.h" +#include "machine/pic8259.h" +#include "machine/pit8253.h" +#include "machine/ds128x.h" +#include "machine/at_keybc.h" + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_CS4031_ADD(_tag, _clock, _cputag, _isatag, _biostag, _keybctag) \ + MCFG_DEVICE_ADD(_tag, CS4031, _clock) \ + cs4031_device::static_set_cputag(*device, _cputag); \ + cs4031_device::static_set_isatag(*device, _isatag); \ + cs4031_device::static_set_biostag(*device, _biostag); \ + cs4031_device::static_set_keybctag(*device, _keybctag); + +#define MCFG_CS4031_IOR(_ior) \ + downcast(device)->set_ior_callback(DEVCB_##_ior); + +#define MCFG_CS4031_IOW(_iow) \ + downcast(device)->set_iow_callback(DEVCB_##_iow); + +#define MCFG_CS4031_TC(_tc) \ + downcast(device)->set_tc_callback(DEVCB_##_tc); + +#define MCFG_CS4031_HOLD(_hold) \ + downcast(device)->set_hold_callback(DEVCB_##_hold); + +#define MCFG_CS4031_NMI(_nmi) \ + downcast(device)->set_nmi_callback(DEVCB_##_nmi); + +#define MCFG_CS4031_INTR(_intr) \ + downcast(device)->set_intr_callback(DEVCB_##_intr); + +#define MCFG_CS4031_CPURESET(_cpureset) \ + downcast(device)->set_cpureset_callback(DEVCB_##_cpureset); + +#define MCFG_CS4031_A20M(_a20m) \ + downcast(device)->set_a20m_callback(DEVCB_##_a20m); + +#define MCFG_CS4031_SPKR(_spkr) \ + downcast(device)->set_spkr_callback(DEVCB_##_spkr); + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> cs4031_device + +class cs4031_device : public device_t +{ +public: + // construction/destruction + cs4031_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + + // callbacks + template void set_ior_callback(_ior ior) { m_read_ior.set_callback(ior); } + template void set_iow_callback(_iow iow) { m_write_iow.set_callback(iow); } + template void set_tc_callback(_tc tc) { m_write_tc.set_callback(tc); } + template void set_hold_callback(_hold hold) { m_write_hold.set_callback(hold); } + template void set_cpureset_callback(_cpureset cpureset) { m_write_cpureset.set_callback(cpureset); } + template void set_nmi_callback(_nmi nmi) { m_write_nmi.set_callback(nmi); } + template void set_intr_callback(_intr intr) { m_write_intr.set_callback(intr); } + template void set_a20m_callback(_a20m a20m) { m_write_a20m.set_callback(a20m); } + template void set_spkr_callback(_spkr spkr) { m_write_spkr.set_callback(spkr); } + + // not really public + DECLARE_READ8_MEMBER( dma_read_byte ); + DECLARE_WRITE8_MEMBER( dma_write_byte ); + DECLARE_READ8_MEMBER( dma_read_word ); + DECLARE_WRITE8_MEMBER( dma_write_word ); + DECLARE_WRITE_LINE_MEMBER( dma1_eop_w ); + DECLARE_READ8_MEMBER( dma1_ior0_r ) { return m_read_ior(0); } + DECLARE_READ8_MEMBER( dma1_ior1_r ) { return m_read_ior(1); } + DECLARE_READ8_MEMBER( dma1_ior2_r ) { return m_read_ior(2); } + DECLARE_READ8_MEMBER( dma1_ior3_r ) { return m_read_ior(3); } + DECLARE_READ8_MEMBER( dma2_ior1_r ) { UINT16 result = m_read_ior(5); m_dma_high_byte = result >> 8; return result; } + DECLARE_READ8_MEMBER( dma2_ior2_r ) { UINT16 result = m_read_ior(6); m_dma_high_byte = result >> 8; return result; } + DECLARE_READ8_MEMBER( dma2_ior3_r ) { UINT16 result = m_read_ior(7); m_dma_high_byte = result >> 8; return result; } + DECLARE_WRITE8_MEMBER( dma1_iow0_w ) { m_write_iow(0, data, 0xffff); } + DECLARE_WRITE8_MEMBER( dma1_iow1_w ) { m_write_iow(1, data, 0xffff); } + DECLARE_WRITE8_MEMBER( dma1_iow2_w ) { m_write_iow(2, data, 0xffff); } + DECLARE_WRITE8_MEMBER( dma1_iow3_w ) { m_write_iow(3, data, 0xffff); } + DECLARE_WRITE8_MEMBER( dma2_iow1_w ) { m_write_iow(5, (m_dma_high_byte << 8) | data, 0xffff); } + DECLARE_WRITE8_MEMBER( dma2_iow2_w ) { m_write_iow(6, (m_dma_high_byte << 8) | data, 0xffff); } + DECLARE_WRITE8_MEMBER( dma2_iow3_w ) { m_write_iow(7, (m_dma_high_byte << 8) | data, 0xffff); } + DECLARE_WRITE_LINE_MEMBER( dma1_dack0_w ) { set_dma_channel(0, state); } + DECLARE_WRITE_LINE_MEMBER( dma1_dack1_w ) { set_dma_channel(1, state); } + DECLARE_WRITE_LINE_MEMBER( dma1_dack2_w ) { set_dma_channel(2, state); } + DECLARE_WRITE_LINE_MEMBER( dma1_dack3_w ) { set_dma_channel(3, state); } + DECLARE_WRITE_LINE_MEMBER( dma2_dack0_w ); + DECLARE_WRITE_LINE_MEMBER( dma2_dack1_w ) { set_dma_channel(5, state); } + DECLARE_WRITE_LINE_MEMBER( dma2_dack2_w ) { set_dma_channel(6, state); } + DECLARE_WRITE_LINE_MEMBER( dma2_dack3_w ) { set_dma_channel(7, state); } + DECLARE_WRITE_LINE_MEMBER( dma2_hreq_w ) { m_write_hold(state); } + DECLARE_WRITE_LINE_MEMBER( intc1_int_w ) { m_write_intr(state); } + DECLARE_READ8_MEMBER( intc1_slave_ack_r ); + DECLARE_WRITE_LINE_MEMBER( ctc_out1_w ); + DECLARE_WRITE_LINE_MEMBER( ctc_out2_w ); + DECLARE_WRITE_LINE_MEMBER( rtc_irq_w ); + + // internal io + DECLARE_WRITE8_MEMBER( config_address_w ); + DECLARE_READ8_MEMBER( config_data_r ); + DECLARE_WRITE8_MEMBER( config_data_w ); + DECLARE_READ8_MEMBER( portb_r ); + DECLARE_WRITE8_MEMBER( portb_w ); + DECLARE_WRITE8_MEMBER( rtc_w ); + DECLARE_WRITE8_MEMBER( sysctrl_w ); + DECLARE_READ8_MEMBER( sysctrl_r ); + DECLARE_READ8_MEMBER( dma_page_r ) { return m_dma_page[offset]; } + DECLARE_WRITE8_MEMBER( dma_page_w ) { m_dma_page[offset] = data; } + DECLARE_READ8_MEMBER( dma2_r ) { return m_dma2->read(space, offset / 2); } + DECLARE_WRITE8_MEMBER( dma2_w ) { m_dma2->write(space, offset / 2, data); } + DECLARE_READ8_MEMBER( keyb_data_r ); + DECLARE_WRITE8_MEMBER( keyb_data_w ); + DECLARE_READ8_MEMBER( keyb_status_r ); + DECLARE_WRITE8_MEMBER( keyb_command_w ); + DECLARE_WRITE8_MEMBER( keyb_command_blocked_w ); + + // input lines + DECLARE_WRITE_LINE_MEMBER( irq01_w ) { m_intc1->ir1_w(state); } + DECLARE_WRITE_LINE_MEMBER( irq03_w ) { m_intc1->ir3_w(state); } + DECLARE_WRITE_LINE_MEMBER( irq04_w ) { m_intc1->ir4_w(state); } + DECLARE_WRITE_LINE_MEMBER( irq05_w ) { m_intc1->ir5_w(state); } + DECLARE_WRITE_LINE_MEMBER( irq06_w ) { m_intc1->ir6_w(state); } + DECLARE_WRITE_LINE_MEMBER( irq07_w ) { m_intc1->ir7_w(state); } + DECLARE_WRITE_LINE_MEMBER( irq09_w ) { m_intc2->ir1_w(state); } + DECLARE_WRITE_LINE_MEMBER( irq10_w ) { m_intc2->ir2_w(state); } + DECLARE_WRITE_LINE_MEMBER( irq11_w ) { m_intc2->ir3_w(state); } + DECLARE_WRITE_LINE_MEMBER( irq12_w ) { m_intc2->ir4_w(state); } + DECLARE_WRITE_LINE_MEMBER( irq13_w ) { m_intc2->ir5_w(state); } // also FERR# + DECLARE_WRITE_LINE_MEMBER( irq14_w ) { m_intc2->ir6_w(state); } + DECLARE_WRITE_LINE_MEMBER( irq15_w ) { m_intc2->ir7_w(state); } + DECLARE_WRITE_LINE_MEMBER( dreq0_w ) { m_dma1->dreq0_w(state); } + DECLARE_WRITE_LINE_MEMBER( dreq1_w ) { m_dma1->dreq1_w(state); } + DECLARE_WRITE_LINE_MEMBER( dreq2_w ) { m_dma1->dreq2_w(state); } + DECLARE_WRITE_LINE_MEMBER( dreq3_w ) { m_dma1->dreq3_w(state); } + DECLARE_WRITE_LINE_MEMBER( dreq5_w ) { m_dma2->dreq1_w(state); } + DECLARE_WRITE_LINE_MEMBER( dreq6_w ) { m_dma2->dreq2_w(state); } + DECLARE_WRITE_LINE_MEMBER( dreq7_w ) { m_dma2->dreq3_w(state); } + DECLARE_WRITE_LINE_MEMBER( hlda_w ) { m_dma2->hack_w(state); } + DECLARE_WRITE_LINE_MEMBER( iochck_w ); + DECLARE_WRITE_LINE_MEMBER( gatea20_w ); + DECLARE_WRITE_LINE_MEMBER( kbrst_w ); + + IRQ_CALLBACK_MEMBER(int_ack_r) { return m_intc1->acknowledge(); } + + // inline configuration + static void static_set_cputag(device_t &device, const char *tag); + static void static_set_isatag(device_t &device, const char *tag); + static void static_set_biostag(device_t &device, const char *tag); + static void static_set_keybctag(device_t &device, const char *tag); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_reset_after_children(); + +private: + devcb_read16 m_read_ior; + devcb_write16 m_write_iow; + devcb_write8 m_write_tc; + devcb_write_line m_write_hold; + devcb_write_line m_write_nmi; + devcb_write_line m_write_intr; + devcb_write_line m_write_cpureset; + devcb_write_line m_write_a20m; + devcb_write_line m_write_spkr; + + offs_t page_offset(); + void set_dma_channel(int channel, bool state); + void update_dma_clock(); + + void nmi(); + void a20m(); + + void emulated_kbreset(int state); + void emulated_gatea20(int state); + void fast_gatea20(int state); + void keyboard_gatea20(int state); + + void update_read_region(int index, const char *region, offs_t start, offs_t end); + void update_write_region(int index, const char *region, offs_t start, offs_t end); + void update_read_regions(); + void update_write_regions(); + + // internal state + const char *m_cputag; + const char *m_isatag; + const char *m_biostag; + const char *m_keybctag; + + address_space *m_space; + address_space *m_space_io; + UINT8 *m_isa; + UINT8 *m_bios; + UINT8 *m_ram; + + // ipc core devices + required_device m_dma1; + required_device m_dma2; + required_device m_intc1; + required_device m_intc2; + required_device m_ctc; + required_device m_rtc; + + int m_dma_eop; + UINT8 m_dma_page[0x10]; + UINT8 m_dma_high_byte; + int m_dma_channel; + + UINT8 m_portb; + int m_refresh_toggle; + int m_iochck; + int m_nmi_mask; + + // keyboard + at_keyboard_controller_device *m_keybc; + int m_cpureset; + int m_kbrst; + int m_ext_gatea20; + int m_fast_gatea20; + int m_emu_gatea20; + bool m_keybc_d1_written; + bool m_keybc_data_blocked; + + // chipset configuration + static const char* m_register_names[]; + static const float m_dma_clock_divider[]; + + enum + { + DMA_WAIT_STATE = 0x01, + PERFORMANCE = 0x08, + F84035_MISC = 0x09, + DMA_CLOCK = 0x0a, + SHADOW_READ = 0x19, + SHADOW_WRITE = 0x1a, + ROMCS = 0x1b, + SOFT_RESET_AND_GATEA20 = 0x1c + }; + + UINT8 m_address; + bool m_address_valid; + + UINT8 m_registers[0x20]; +}; + + +// device type definition +extern const device_type CS4031; + + +#endif /* __CS4031_H__ */ diff --git a/src/devices/machine/cs8221.c b/src/devices/machine/cs8221.c new file mode 100644 index 00000000000..95a890d7bba --- /dev/null +++ b/src/devices/machine/cs8221.c @@ -0,0 +1,167 @@ +// license:BSD-3-Clause +// copyright-holders:Miodrag Milanovic +/*************************************************************************** + + Chips & Technologies CS8221 chipset + + a.k.a. NEW ENHANCED AT (NEAT) + + Consists of four individual chips: + + * 82C211 - CPU/Bus controller + * 82C212 - Page/Interleave and EMS Memory controller + * 82C215 - Data/Address buffer + * 82C206 - Integrated Peripherals Controller(IPC) + +***************************************************************************/ + +#include "emu.h" +#include "machine/ram.h" +#include "machine/cs8221.h" + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +#define LOG_REGISTER 1 +#define LOG_MEMORY 1 + +const device_type CS8221 = &device_creator; + + +static const char *const register_names[] = +{ + /* 00 */ "PROCCLK", + /* 01 */ "COMMAND DELAY", + /* 02 */ "WAIT STATES", + /* 03 */ "RESERVED", + /* 04 */ "VERSION", + /* 05 */ "ROM CONFIGURATION", + /* 06 */ "MEMORY ENABLE-1", + /* 07 */ "MEMORY ENABLE-2", + /* 08 */ "MEMORY ENABLE-3", + /* 09 */ "MEMORY ENABLE-4", + /* 0a */ "BANK 0/1 ENABLE", + /* 0b */ "DRAM CONFIGURATION", + /* 0c */ "BANK 2/3 ENABLE", + /* 0d */ "EMS BASE ADDRESS", + /* 0e */ "EMS ADDRESS EXTENSION", + /* 0f */ "MISCELLANEOUS" +}; + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// cs8221_device - constructor +//------------------------------------------------- + +cs8221_device::cs8221_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, CS8221, "CS8221", tag, owner, clock, "cs8221", __FILE__), + m_address(0), + m_address_valid(false) +{ +} + +void cs8221_device::static_set_cputag(device_t &device, const char *tag) +{ + cs8221_device &cs8221 = downcast(device); + cs8221.m_cputag = tag; +} + +void cs8221_device::static_set_isatag(device_t &device, const char *tag) +{ + cs8221_device &cs8221 = downcast(device); + cs8221.m_isatag = tag; +} + +void cs8221_device::static_set_biostag(device_t &device, const char *tag) +{ + cs8221_device &cs8221 = downcast(device); + cs8221.m_biostag = tag; +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void cs8221_device::device_start() +{ +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void cs8221_device::device_reset() +{ + // setup default values + memset(&m_registers, 0x00, sizeof(m_registers)); +} + + +//************************************************************************** +// READ/WRITE HANDLERS +//************************************************************************** + +WRITE8_MEMBER( cs8221_device::address_w ) +{ + m_address = data; + m_address_valid = ((m_address & 0x60)== 0x60) ? true : false; +} + +READ8_MEMBER( cs8221_device::data_r ) +{ + UINT8 result = 0xff; + + if (m_address_valid) + { + if (LOG_REGISTER) + logerror("cs8221_device: read %s = %02x\n", register_names[m_address & 0x0f], m_registers[m_address & 0x0f]); + + result = m_registers[m_address & 0x0f]; + } + + // after a read the selected address needs to be reset + m_address_valid = false; + + return result; +} + +WRITE8_MEMBER( cs8221_device::data_w ) +{ + if (m_address_valid) + { + if (LOG_REGISTER) + logerror("cs8221_device: write %s = %02x\n", register_names[m_address & 0x0f], data); + + // update register with new data + m_registers[m_address & 0x0f] = data; + + // execute command + switch (m_address) + { + case 0x60: break; + case 0x61: break; + case 0x62: break; + case 0x63: break; + case 0x64: break; + case 0x65: break; + case 0x66: break; + case 0x67: break; + case 0x68: break; + case 0x69: break; + case 0x6a: break; + case 0x6b: break; + case 0x6c: break; + case 0x6d: break; + case 0x6e: break; + case 0x6f: break; + } + } + + // after a write the selected address needs to be reset + m_address_valid = false; +} diff --git a/src/devices/machine/cs8221.h b/src/devices/machine/cs8221.h new file mode 100644 index 00000000000..b2d04dfe89e --- /dev/null +++ b/src/devices/machine/cs8221.h @@ -0,0 +1,88 @@ +// license:BSD-3-Clause +// copyright-holders:Miodrag Milanovic +/*************************************************************************** + + Chips & Technologies CS8221 chipset + + a.k.a. NEW ENHANCED AT (NEAT) + + Consists of four individual chips: + + * 82C211 - CPU/Bus controller + * 82C212 - Page/Interleave and EMS Memory controller + * 82C215 - Data/Address buffer + * 82C206 - Integrated Peripherals Controller(IPC) + +***************************************************************************/ + +#pragma once + +#ifndef __CS8221_H__ +#define __CS8221_H__ + +#include "emu.h" + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_CS8221_ADD(_tag, _cputag, _isatag, _biostag) \ + MCFG_DEVICE_ADD(_tag, CS8221, 0) \ + cs8221_device::static_set_cputag(*device, _cputag); \ + cs8221_device::static_set_isatag(*device, _isatag); \ + cs8221_device::static_set_biostag(*device, _biostag); + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> cs8221_device + +class cs8221_device : public device_t +{ +public: + // construction/destruction + cs8221_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + DECLARE_WRITE8_MEMBER( address_w ); + DECLARE_READ8_MEMBER( data_r ); + DECLARE_WRITE8_MEMBER( data_w ); + + // inline configuration + static void static_set_cputag(device_t &device, const char *tag); + static void static_set_isatag(device_t &device, const char *tag); + static void static_set_biostag(device_t &device, const char *tag); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + +private: + + // internal state + //address_space *m_space; + //UINT8 *m_isa; + //UINT8 *m_bios; + //UINT8 *m_ram; + + // address selection + UINT8 m_address; + bool m_address_valid; + + const char *m_cputag; + const char *m_isatag; + const char *m_biostag; + + + UINT8 m_registers[0x10]; +}; + + +// device type definition +extern const device_type CS8221; + + +#endif /* __CS8221_H__ */ diff --git a/src/devices/machine/diablo_hd.c b/src/devices/machine/diablo_hd.c new file mode 100644 index 00000000000..9ee566350ff --- /dev/null +++ b/src/devices/machine/diablo_hd.c @@ -0,0 +1,1464 @@ +// license:BSD-3-Clause +// copyright-holders:Juergen Buchmueller +/********************************************************** + * DIABLO31 and DIABLO44 hard drive support + **********************************************************/ +#include "diablo_hd.h" + +/** + * + * Just for completeness' sake: + * The mapping of disk controller connector P2 pins to the + * Winchester disk drive signals (see drive.h) + *
+ * Alto Controller     Winchester
+ * P2 signal           disk bus
+ * -----------------------------------------------
+ *  1 GND              D_GROUND
+ *  2 RDCLK'           A_READ_CLOCK
+ *  3 WRDATA'          B_WRITE_DATA_AND_CLOCK
+ *  4 SRWRDY'          F_S_R_W
+ *  5 DISK             L_SELECT_LINE_UNIT_1
+ *  6 CYL(7)'          N_CYL_7
+ *  7 DISK'            R_SELECT_LINE_UNIT_2
+ *  8 CYL(2)'          T_CYL_2
+ *  9 ???              V_SELECT_LINE_UNIT_3
+ * 10 CYL(4)'          X_CYL_4
+ * 11 CYL(0)'          Z_CYL_0
+ * 12 CYL(1)'          BB_CYL_1
+ * 13 CYL(3)'          FF_CYL_3
+ * 14 ???              KK_BIT_2
+ * 15 CYL(8)'          LL_CYL_8
+ * 16 ADRACK'          NN_ADDX_ACKNOWLEDGE
+ * 17 SKINC'           TT_SEEK_INCOMPLETE
+ * 18 LAI'             XX_LOG_ADDX_INTERLOCK
+ * 19 CYL(6)'          RR_CYL_6
+ * 20 RESTOR'          VV_RESTORE
+ * 21 ???              UU_BIT_16
+ * 22 STROBE'          SS_STROBE
+ * 23 ???              MM_BIT_8
+ * 24 ???              KK_BIT_4
+ * 25 ???              HH_WRITE_CHK
+ * 26 WRTGATE'         EE_WRITE_GATE
+ * 27 ???              CC_BIT_SECTOR_ADDX
+ * 28 HEAD'            AA_HEAD_SELECT
+ * 29 ???              Y_INDEX_MARK
+ * 30 SECT(4)'         W_SECTOR_MARK
+ * 31 READY'           U_FILE_READY
+ * 32 ???              S_PSEUDO_SECTOR_MARK
+ * 33 ???              P_WRITE_PROTECT_IND
+ * 34 ???              H_WRITE_PROTECT_INPUT_ATTENTION
+ * 35 ERGATE'          K_ERASE_GATE
+ * 36 ???              M_HIGH_DENSITY
+ * 37 CYL(5)'          J_CYL_5
+ * 38 RDDATA'          C_READ_DATA
+ * 39 RDGATE'          E_READ_GATE
+ * 40 GND              ??
+ * 
+ */ + +diablo_hd_device::diablo_hd_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, DIABLO_HD, "Diablo Disk", tag, owner, clock, "diablo_hd", __FILE__), +#if DIABLO_DEBUG + m_log_level(8), +#endif + m_diablo31(true), + m_unit(0), + m_packs(1), + m_rotation_time(), + m_sector_time(), + m_sector_mark_0_time(), + m_sector_mark_1_time(), + m_bit_time(), + m_s_r_w_0(1), + m_ready_0(1), + m_sector_mark_0(1), + m_addx_acknowledge_0(1), + m_log_addx_interlock_0(1), + m_seek_incomplete_0(1), + m_egate_0(1), + m_wrgate_0(1), + m_rdgate_0(1), + m_cylinders(DIABLO_CYLINDERS), + m_pages(DIABLO_PAGES), + m_seekto(0), + m_restore(0), + m_cylinder(-1), + m_head(-1), + m_sector(-1), + m_page(-1), + m_cache(0), + m_bits(0), + m_rdfirst(-1), + m_rdlast(-1), + m_wrfirst(-1), + m_wrlast(-1), + m_sector_callback_cookie(0), + m_sector_callback(0), + m_timer(0), + m_image(0), + m_handle(0), + m_disk(0) +{ + memset(m_description, 0x00, sizeof(m_description)); +} + +/** + * @brief diablo_hd_device destructor + * Free all m_cache and m_bits pages and the arrays + */ +diablo_hd_device::~diablo_hd_device() +{ +} + +#if DIABLO_DEBUG +void diablo_hd_device::logprintf(int level, const char* format, ...) +{ + if (level > m_log_level) + return; + va_list ap; + va_start(ap, format); + vlogerror(format, ap); + va_end(ap); +} +#endif + +void diablo_hd_device::set_sector_callback(void *cookie, void (*callback)(void *, int)) +{ + if (m_sector_callback_cookie == cookie && m_sector_callback == callback) + return; + LOG_DRIVE((0,"[DHD%u] cookie=%p callback=%p\n", m_unit, cookie, callback)); + m_sector_callback_cookie = cookie; + m_sector_callback = callback; +} + +#define DIABLO31_ROTATION_TIME attotime::from_usec(39900) //!< DIABLO 31 rotation time is approx. 40ms +#define DIABLO31_SECTOR_TIME attotime::from_usec(39900/12) //!< DIABLO 31 sector time +/** + * @brief DIABLO 31 bit clock is 3330kHz ~= 300ns per bit + * ~= 133333 bits/track (?) + * ~= 11111 bits/sector + * ~= 347 words/sector + */ +#define DIABLO31_BIT_TIME(bits) attotime::from_nsec(300*(bits)) +#define DIABLO31_SECTOR_BITS 10432 +#define DIABLO31_SECTOR_WORDS 347 //!< DIABLO 31 possible sector words +#define DIABLO31_SECTOR_MARK_PULSE_PRE DIABLO31_BIT_TIME(16) //!< pulse width of sector mark before the next sector begins +#define DIABLO31_SECTOR_MARK_PULSE_POST DIABLO31_BIT_TIME(16) //!< pulse width of sector mark after the next sector began + +#define DIABLO44_ROTATION_TIME attotime::from_usec(25000) //!< DIABLO 44 rotation time is approx. 25ms +#define DIABLO44_SECTOR_TIME attotime::from_usec(25000/12) //!< DIABLO 44 sector time +/** + * @brief DIABLO 44 bit clock is 5000kHz ~= 200ns per bit + * ~= 125184 bits/track (?) + * ~= 10432 bits/sector + * ~= 325 words/sector + */ +#define DIABLO44_BIT_TIME(bits) attotime::from_nsec(200*(bits)) +#define DIABLO44_SECTOR_BITS 10432 +#define DIABLO44_SECTOR_WORDS 325 //!< DIABLO 44 possible sector words +#define DIABLO44_SECTOR_MARK_PULSE_PRE DIABLO44_BIT_TIME(16) //!< pulse width of sector mark before the next sector begins +#define DIABLO44_SECTOR_MARK_PULSE_POST DIABLO44_BIT_TIME(16) //!< pulse width of sector mark after the next sector began + +#define MFROBL 34 //!< from the microcode: disk header preamble is 34 words +#define MFRRDL 21 //!< from the microcode: disk header read delay is 21 words +#define MIRRDL 4 //!< from the microcode: interrecord read delay is 4 words +#define MIROBL 3 //!< from the microcode: disk interrecord preamble is 3 words +#define MRPAL 3 //!< from the microcode: disk read postamble length is 3 words +#define MWPAL 5 //!< from the microcode: disk write postamble length is 5 words + +#define GUARD_ZONE_BITS (16*32) //!< end of the guard zone at the beginning of a sector (wild guess!) + +/** + * @brief description of the sector layout (reverse engineered) + *
+ *
+ *                                   xx.x msec sector mark pulses
+ * -+   +-------------------------------------------------------------------------------+   +--
+ *  |   |                                                                               |   |
+ *  +---+                                                                               +---+
+ *
+ *    |                                                                                   |
+ *
+ *    +------+----+------+-----+------+----+-------+-----+------+----+-------+-----+------+
+ *    | PRE- |SYNC|HEADER|CKSUM| PRE- |SYNC| LABEL |CKSUM| PRE- |SYNC| DATA  |CKSUM| POST |
+ *    |AMBLE1|  1 |      |  1  |AMBLE2|  2 |       |  2  |AMBLE3|  3 |       |  3  |AMBLE |
+ *    +------+----+------+-----+------+----+-------+-----+------+----+-------+-----+------+
+ *
+ *    |                                                                                   |
+ *
+ *    +-----------------------------------------------------------------------------------+
+ *    |                                                                                   |
+ * ---+                                                                                   +----
+ *      FORMAT WRITE GATE FOR INITIALIZING
+ *    |                                                                                   |
+ *
+ *    |                                                    +------------------------------+
+ *                                                         |                              |
+ * ---|----------------------------------------------------+                              +----
+ *      WRITE GATE FOR DATA XFER (*)
+ *    |                                                                                   |
+ *
+ *    |                          +-----------------------+-+------------------------------+
+ *                               |                       | | may be continuous (?)        |
+ * ------------------------------+                       +-+                              +----
+ * ???  WRITE GATE FOR LABEL AND DATA XFER (*)
+ *    |                                                                                   |
+ *
+ *    |   +--------------------+   +---------------------+   +----------------------------+
+ *        |                    |   |                     |   |                            |
+ * -------+                    +---+                     +---+                            +----
+ *      READ GATE FOR INITIALIZING OR DATA XFER (**)
+ *
+ *
+ *  (*) Enable should be delayed 1 byte/word time from last bit of checks sum.
+ *  (**) Read Gate should be enabled half way through the preamble area. This
+ *       ensures reading a zero field for data separator synchronization.
+ *
+ * 
+ */ + +#define DIABLO_PAGENO_WORDS 1 //!< number of words in a page number (this doesn't really belong here) +#define DIABLO_HEADER_WORDS 2 //!< number of words in a header (this doesn't really belong here) +#define DIABLO_LABEL_WORDS 8 //!< number of words in a label (this doesn't really belong here) +#define DIABLO_DATA_WORDS 256 //!< number of data words (this doesn't really belong here) +#define DIABLO_CKSUM_WORDS 1 //!< number of words for a checksum (this doesn't really belong here) + +/** + * @brief format of the cooked disk image sectors, i.e. pure data + * + * The available images are a multiple of 267 words (534 bytes) per sector, + * 1 word page number + * 2 words header + * 8 words label + * 256 words data + */ +typedef struct { + UINT8 pageno[2*DIABLO_PAGENO_WORDS]; //!< sector page number + UINT8 header[2*DIABLO_HEADER_WORDS]; //!< sector header words + UINT8 label[2*DIABLO_LABEL_WORDS]; //!< sector label words + UINT8 data[2*DIABLO_DATA_WORDS]; //!< sector data words +} diablo_sector_t; + +/** + * @brief write a bit into an array of UINT32 + * @param bits pointer to array of bits + * @param dst destination index + * @param bit bit value + * @return next destination index + */ +static inline size_t WRBIT(UINT32* bits, size_t dst, int bit) +{ + if (bit) { + bits[(dst)/32] |= 1 << ((dst) % 32); + } else { + bits[(dst)/32] &= ~(1 << ((dst) % 32)); + } + return ++dst; +} + +/** + * @brief read a bit from an array of UINT32 + * @param bits pointer to array of bits + * @param src source index + * @param bit reference to the bit to set + * @return next source index + */ +static inline size_t RDBIT(UINT32* bits, size_t src, int& bit) +{ + bit = (bits[src/32] >> (src % 32)) & 1; + return ++src; +} + +/** + * @brief calculate the sector from the logical block address and read it + * + * Modifies drive's page by calculating the logical + * block address from cylinder, head, and sector. + */ +void diablo_hd_device::read_sector() +{ + /* If there's no drive, just reset the page number */ + if (!m_image) { + LOG_DRIVE((0,"[DHD%u] CHS:%03d/%d/%02d => no image\n", m_unit, m_cylinder, m_head, m_sector)); + m_page = -1; + return; + } + if (m_cylinder < 0 || m_cylinder >= m_cylinders) { + LOG_DRIVE((0,"[DHD%u] CHS:%03d/%d/%02d => invalid cylinder\n", m_unit, m_cylinder, m_head, m_sector)); + m_page = -1; + return; + } + if (m_head < 0 || m_head >= DIABLO_HEADS) { + LOG_DRIVE((0,"[DHD%u] CHS:%03d/%d/%02d => invalid head\n", m_unit, m_cylinder, m_head, m_sector)); + m_page = -1; + return; + } + if (m_sector < 0 || m_sector >= DIABLO_SPT) { + LOG_DRIVE((0,"[DHD%u] CHS:%03d/%d/%02d => invalid sector\n", m_unit, m_cylinder, m_head, m_sector)); + m_page = -1; + return; + } + /* calculate the new disk relative sector offset */ + m_page = DIABLO_PAGE(m_cylinder, m_head, m_sector); + + // already have the sector image? + if (m_cache[m_page]) { + LOG_DRIVE((9,"[DHD%u] CHS:%03d/%d/%02d => page:%d is cached\n", m_unit, m_cylinder, m_head, m_sector, m_page)); + return; + } + + if (m_disk) { + // allocate a buffer for this page + m_cache[m_page] = auto_alloc_array(machine(), UINT8, sizeof(diablo_sector_t)); + // and read the page from the hard_disk image + if (hard_disk_read(m_disk, m_page, m_cache[m_page])) { + LOG_DRIVE((2,"[DHD%u] CHS:%03d/%d/%02d => page:%d loaded\n", m_unit, m_cylinder, m_head, m_sector, m_page)); + } else { + LOG_DRIVE((0,"[DHD%u] CHS:%03d/%d/%02d => page:%d read failed\n", m_unit, m_cylinder, m_head, m_sector, m_page)); + auto_free(machine(), m_cache[m_page]); + m_cache[m_page] = 0; + } + } else { + LOG_DRIVE((2,"[DHD%u] no disk\n", m_unit)); + } +} + +/** + * @brief compute the checksum of a record + * + * @param src pointer to a record (header, label, data) + * @param size size of the record in bytes + * @param start start value for the checksum + * @return returns the checksum of the record + */ +int diablo_hd_device::cksum(UINT8 *src, size_t size, int start) +{ + int sum = start; + /* compute XOR of all words */ + for (size_t offs = 0; offs < size; offs += 2) { + int word = src[size - 2 - offs] + 256 * src[size - 2 - offs + 1]; + sum ^= word; + } + return sum; +} + +/** + * @brief expand a series of clock bits and 0 data bits + * + * @param bits pointer to the sector bits + * @param dst destination offset into bits (bit number) + * @param size number of words to write + * @return offset to next destination bit + */ +size_t diablo_hd_device::expand_zeroes(UINT32 *bits, size_t dst, size_t size) +{ + for (size_t offs = 0; offs < 32 * size; offs += 2) { + dst = WRBIT(bits, dst, 1); // write the clock bit + dst = WRBIT(bits, dst, 0); // write the 0 data bit + } + return dst; +} + +/** + * @brief expand a series of 0 words and write a final sync bit + * + * @param bits pointer to the sector bits + * @param dst destination offset into bits (bit number) + * @param size number of words to write + * @return offset to next destination bit + */ +size_t diablo_hd_device::expand_sync(UINT32 *bits, size_t dst, size_t size) +{ + for (size_t offs = 0; offs < 32 * size - 2; offs += 2) { + dst = WRBIT(bits, dst, 1); // write the clock bit + dst = WRBIT(bits, dst, 0); // write the 0 data bit + } + dst = WRBIT(bits, dst, 1); // write the final clock bit + dst = WRBIT(bits, dst, 1); // write the 1 data bit + return dst; +} + +/** + * @brief expand a record of words into a array of bits at dst + * + * @param bits pointer to the sector bits + * @param dst destination offset into bits (bit number) + * @param field pointer to the record data (bytes) + * @param size size of the record in bytes + * @return offset to next destination bit + */ +size_t diablo_hd_device::expand_record(UINT32 *bits, size_t dst, UINT8 *field, size_t size) +{ + for (size_t offs = 0; offs < size; offs += 2) { + int word = field[size - 2 - offs] + 256 * field[size - 2 - offs + 1]; + for (size_t bit = 0; bit < 16; bit++) { + dst = WRBIT(bits, dst, 1); // write the clock bit + dst = WRBIT(bits, dst, (word >> 15) & 1); // write the data bit + word <<= 1; + } + } + return dst; +} + +/** + * @brief expand a record's checksum word to 32 bits + * + * @param bits pointer to the sector bits + * @param dst destination offset into bits (bit number) + * @param field pointer to the record data (bytes) + * @param size size of the record in bytes + * @return offset to next destination bit + */ +size_t diablo_hd_device::expand_cksum(UINT32 *bits, size_t dst, UINT8 *field, size_t size) +{ + int word = cksum(field, size, 0521); + for (size_t bit = 0; bit < 32; bit += 2) { + dst = WRBIT(bits, dst, 1); // write the clock bit + dst = WRBIT(bits, dst, (word >> 15) & 1); // write the data bit + word <<= 1; + } + return dst; +} + +/** + * @brief expand a sector into an array of clock and data bits + * + * @param page page number (0 to DRIVE_PAGES-1) + * @return pointer to the newly allocated array of bits + */ +UINT32* diablo_hd_device::expand_sector() +{ + size_t dst; + + if (!m_bits) + return NULL; + /* already expanded this sector? */ + if (m_bits[m_page]) + return m_bits[m_page]; + + /* allocate a sector buffer */ + if (!m_cache[m_page]) { + LOG_DRIVE((0,"[DHD%u] no image for page #%d\n", m_unit, m_page)); + return NULL; + } + diablo_sector_t *s = reinterpret_cast(m_cache[m_page]); + + /* allocate a bits image */ + UINT32 *bits = auto_alloc_array_clear(machine(), UINT32, 400); + + if (m_diablo31) { + /* write sync bit after (MFROBL-MRPAL) words - 1 bit */ + dst = expand_sync(bits, 0, (MFROBL - MRPAL)); + dst = expand_record(bits, dst, s->header, sizeof(s->header)); + dst = expand_cksum(bits, dst, s->header, sizeof(s->header)); + + /* write sync bit after 2 * MWPAL + 1 words - 1 bit */ + dst = expand_sync(bits, dst, 2 * MWPAL); + dst = expand_record(bits, dst, s->label, sizeof(s->label)); + dst = expand_cksum(bits, dst, s->label, sizeof(s->label)); + + /* write sync bit after 2 * MWPAL + 1 words - 1 bit */ + dst = expand_sync(bits, dst, 2 * MWPAL); + dst = expand_record(bits, dst, s->data, sizeof(s->data)); + dst = expand_cksum(bits, dst, s->data, sizeof(s->data)); + + /* fill MWPAL words of clock and 0 data bits */ + dst = expand_zeroes(bits, dst, MWPAL); + } else { + /* write sync bit after (MFROBL - MRPAL) words - 1 bit */ + dst = expand_sync(bits, 0, (MFROBL - MRPAL)); + dst = expand_record(bits, dst, s->header, sizeof(s->header)); + dst = expand_cksum(bits, dst, s->header, sizeof(s->header)); + + /* write sync bit after 2 * MWPAL words - 1 bit */ + dst = expand_sync(bits, dst, 2 * MWPAL); + dst = expand_record(bits, dst, s->label, sizeof(s->label)); + dst = expand_cksum(bits, dst, s->label, sizeof(s->label)); + + /* write sync bit after 2 * MWPAL words - 1 bit */ + dst = expand_sync(bits, dst, 2 * MWPAL); + dst = expand_record(bits, dst, s->data, sizeof(s->data)); + dst = expand_cksum(bits, dst, s->data, sizeof(s->data)); + + /* fill MWPAL words of clock and 0 data bits */ + dst = expand_zeroes(bits, dst, MWPAL); + } + m_bits[m_page] = bits; + + LOG_DRIVE((0,"[DHD%u] CHS:%03d/%d/%02d #%5d bits\n", m_unit, m_cylinder, m_head, m_sector, dst)); +#if DIABLO_DEBUG + dump_record(s->pageno, 0, sizeof(s->pageno), "pageno", 0); + dump_record(s->header, 0, sizeof(s->header), "header", 0); + dump_record(s->label, 0, sizeof(s->label), "label", 0); + dump_record(s->data, 0, sizeof(s->data), "data", 1); +#endif + return bits; +} + +#if DIABLO_DEBUG +void diablo_hd_device::dump_ascii(UINT8 *src, size_t size) +{ + size_t offs; + LOG_DRIVE((0," [")); + for (offs = 0; offs < size; offs++) { + char ch = (char)src[offs ^ 1]; + LOG_DRIVE((0, "%c", ch < 32 || ch > 126 ? '.' : ch)); + } + LOG_DRIVE((0,"]\n")); +} + + +/** + * @brief dump a record's contents + * + * @param src pointer to a record (header, label, data) + * @param size size of the record in bytes + * @param name name to print before the dump + */ +size_t diablo_hd_device::dump_record(UINT8 *src, size_t addr, size_t size, const char *name, int cr) +{ + size_t offs; + LOG_DRIVE((0,"%s:", name)); + for (offs = 0; offs < size; offs += 2) { + int word = src[offs] + 256 * src[offs + 1]; + if (offs % 16) { + LOG_DRIVE((0," %06o", word)); + } else { + if (offs > 0) + dump_ascii(&src[offs-16], 16); + LOG_DRIVE((0,"\t%05o: %06o", (addr + offs) / 2, word)); + } + } + if (offs % 16) { + dump_ascii(&src[offs - (offs % 16)], offs % 16); + } else { + dump_ascii(&src[offs-16], 16); + } + if (cr) { + LOG_DRIVE((0,"\n")); + } + return size; +} +#endif + +/** + * @brief find a sync bit in an array of clock and data bits + * + * @param bits pointer to the sector's bits + * @param src source index into bits (bit number) + * @param size number of words to scan for a sync word + * @return next source index for reading + */ +size_t diablo_hd_device::squeeze_sync(UINT32 *bits, size_t src, size_t size) +{ + UINT32 accu = 0; + /* hunt for the first 0x0001 word */ + for (size_t bitcount = 0, offs = 0; offs < size; /* */) { + /* + * accumulate clock and data bits until we are + * on the clock bit boundary + */ + int bit; + src = RDBIT(bits,src,bit); + accu = (accu << 1) | bit; + /* + * look for 15 alternating clocks and 0-bits + * and the 16th clock with a 1-bit + */ + if (accu == 0xaaaaaaab) + return src; + if (++bitcount == 32) { + bitcount = 0; + offs++; + } + } + /* return if no sync found within size*32 clock and data bits */ + LOG_DRIVE((0,"[DHD%u] no sync within %d words\n", m_unit, size)); + return src; +} + +/** + * @brief find a 16 x 0 bits sequence in an array of clock and data bits + * + * @param bits pointer to the sector's bits + * @param src source index into bits (bit number) + * @param size number of words to scan for a sync word + * @return next source index for reading + */ +size_t diablo_hd_device::squeeze_unsync(UINT32 *bits, size_t src, size_t size) +{ + UINT32 accu = 0; + /* hunt for the first 0 word (16 x 0 bits) */ + for (size_t bitcount = 0, offs = 0; offs < size; /* */) { + /* + * accumulate clock and data bits until we are + * on the clock bit boundary + */ + int bit; + src = RDBIT(bits,src,bit); + accu = (accu << 1) | bit; + /* + * look for 16 alternating clocks and 0 data bits + */ + if (accu == 0xaaaaaaaa) + return src; + if (++bitcount == 32) { + bitcount = 0; + offs++; + } + } + /* return if no sync found within size*32 clock and data bits */ + LOG_DRIVE((0,"[DHD%u] no unsync within %d words\n", m_unit, size)); + return src; +} + +/** + * @brief squeeze an array of clock and data bits into a sector's record + * + * @param bits pointer to the sector's bits + * @param src source index into bits (bit number) + * @param field pointer to the record data (bytes) + * @param size size of the record in bytes + * @return next source index for reading + */ +size_t diablo_hd_device::squeeze_record(UINT32 *bits, size_t src, UINT8 *field, size_t size) +{ + UINT32 accu = 0; + for (size_t bitcount = 0, offs = 0; offs < size; /* */) { + int bit; + src = RDBIT(bits,src,bit); // skip clock + assert(bit == 1); + src = RDBIT(bits,src,bit); // get data bit + accu = (accu << 1) | bit; + bitcount += 2; + if (bitcount == 32) { + /* collected a word */ + field[size - 2 - offs + 0] = accu % 256; + field[size - 2 - offs + 1] = accu / 256; + offs += 2; + bitcount = 0; + } + } + return src; +} + +/** + * @brief squeeze an array of 32 clock and data bits into a checksum word + * + * @param bits pointer to the sector's bits + * @param src source index into bits (bit number) + * @param cksum pointer to an int to receive the checksum word + * @return next source index for reading + */ +size_t diablo_hd_device::squeeze_cksum(UINT32 *bits, size_t src, int *cksum) +{ + UINT32 accu = 0; + + for (size_t bitcount = 0; bitcount < 32; bitcount += 2) { + int bit; + src = RDBIT(bits,src,bit); // skip clock + assert(bit == 1); + src = RDBIT(bits,src,bit); // get data bit + accu = (accu << 1) | bit; + } + + /* set the cksum to the extracted word */ + *cksum = accu; + return src; +} + +/** + * @brief squeeze a array of clock and data bits into a sector's data + * + * Find and squeeze header, label and data fields and verify for + * zero checksums, starting with a value of 0521. + * Write the page back to the media and free the bitmap + */ +void diablo_hd_device::squeeze_sector() +{ + diablo_sector_t *s; + size_t src; + int cksum_header, cksum_label, cksum_data; + + if (m_rdfirst >= 0) { + LOG_DRIVE((0, "[DHD%u] READ CHS:%03d/%d/%02d bit#%d ... bit#%d\n", + m_unit, m_cylinder, m_head, m_sector, m_rdfirst, m_rdlast)); + } + m_rdfirst = -1; + m_rdlast = -1; + + /* not written to, just drop it now */ + if (m_wrfirst < 0) { + m_wrfirst = -1; + m_wrlast = -1; + return; + } + + /* did write into the next sector (?) */ + if (m_wrlast > m_wrfirst && m_wrlast < 256) { + m_wrfirst = -1; + m_wrlast = -1; + return; + } + + if (m_wrfirst >= 0) { + LOG_DRIVE((0, "[DHD%u] WRITE CHS:%03d/%d/%02d bit#%d ... bit#%d\n", + m_unit, m_cylinder, m_head, m_sector, m_wrfirst, m_wrlast)); + } + m_wrfirst = -1; + m_wrlast = -1; + + if (m_page < 0 || m_page >= m_pages) { + LOG_DRIVE((0,"[DHD%u] page not set\n", m_unit)); + return; + } + + if (!m_cache[m_page]) { + LOG_DRIVE((0,"[DHD%u] no image\n", m_unit)); + return; + } + + /* no bits to write? */ + if (!m_bits[m_page]) { + LOG_DRIVE((0,"[DHD%u] no bits\n", m_unit)); + return; + } + UINT32 *bits = m_bits[m_page]; + + // pointer to sector buffer + s = reinterpret_cast(m_cache[m_page]); + + // zap the sector first + memset(s, 0, sizeof(*s)); + + src = MFRRDL * 32; + src = squeeze_unsync(bits, src, 40); // skip first words and garbage until 0 bits are coming in + src = squeeze_sync(bits, src, 40); // sync on header preamble + LOG_DRIVE((0,"[DHD%u] header sync bit #%5d\n", m_unit, src)); + src = squeeze_record(bits, src, s->header, sizeof(s->header)); + LOG_DRIVE((0,"[DHD%u] header CRC bit #%5d\n", m_unit, src)); + src = squeeze_cksum(bits, src, &cksum_header); +#if DIABLO_DEBUG + dump_record(s->header, 0, sizeof(s->header), "header", 0); +#endif + + src = squeeze_unsync(bits, src, 40); // skip garbage until 0 bits are coming in + src = squeeze_sync(bits, src, 40); // sync on label preamble + LOG_DRIVE((0,"[DHD%u] label sync bit #%5d\n", m_unit, src)); + src = squeeze_record(bits, src, s->label, sizeof(s->label)); + LOG_DRIVE((0,"[DHD%u] label CRC bit #%5d\n", m_unit, src)); + src = squeeze_cksum(bits, src, &cksum_label); +#if DIABLO_DEBUG + dump_record(s->label, 0, sizeof(s->label), "label", 0); +#endif + + src = squeeze_unsync(bits, src, 40); // skip garbage until 0 bits are coming in + src = squeeze_sync(bits, src, 40); // sync on data preamble + LOG_DRIVE((0,"[DHD%u] data sync bit #%5d\n", m_unit, src)); + src = squeeze_record(bits, src, s->data, sizeof(s->data)); + LOG_DRIVE((0,"[DHD%u] data CRC bit #%5d\n", m_unit, src)); + src = squeeze_cksum(bits, src, &cksum_data); +#if DIABLO_DEBUG + dump_record(s->data, 0, sizeof(s->data), "data", 1); +#endif + LOG_DRIVE((0,"[DHD%u] postamble bit #%5d\n", m_unit, src)); + + /* The checksum start value always seems to be 0521 */ + cksum_header ^= cksum(s->header, sizeof(s->header), 0521); + cksum_label ^= cksum(s->label, sizeof(s->label), 0521); + cksum_data ^= cksum(s->data, sizeof(s->data), 0521); + + if (cksum_header || cksum_label || cksum_data) { +#if DIABLO_DEBUG + LOG_DRIVE((0,"[DHD%u] cksum check - header:%06o label:%06o data:%06o\n", m_unit, cksum_header, cksum_label, cksum_data)); +#endif + } + auto_free(machine(), m_bits[m_page]); + m_bits[m_page] = 0; + + if (m_disk) { + if (!hard_disk_write(m_disk, m_page, m_cache[m_page])) { + LOG_DRIVE((0,"[DHD%u] write failed for page #%d\n", m_unit, m_page)); + } + } else { + LOG_DRIVE((2,"[DHD%u] no disk\n", m_unit)); + } +} + +/** + * @brief return number of bit clocks for a sector (clock and data) + * @return number of bitclks for a sector + */ +int diablo_hd_device::bits_per_sector() const +{ + return m_diablo31 ? DIABLO31_SECTOR_BITS : DIABLO44_SECTOR_BITS; +} + +/** + * @brief return a pointer to a drive's description + * @return a pointer to the string description + */ +const char* diablo_hd_device::description() const +{ + return m_description; +} + +/** + * @brief return the number of a drive unit + * @return the unit number of this instance + */ +int diablo_hd_device::unit() const +{ + return m_unit; +} + +/** + * @brief return the time for a full rotation + * @return the time for a full track rotation in atto seconds + */ +attotime diablo_hd_device::rotation_time() const +{ + return m_rotation_time; +} + +/** + * @brief return the time for a sector + * @return the time for a sector in atto seconds + */ +attotime diablo_hd_device::sector_time() const +{ + return m_sector_time; +} + +/** + * @brief return the time for a data bit + * @return the time in atto seconds per bit clock + */ +attotime diablo_hd_device::bit_time() const +{ + return m_bit_time; +} + +/** + * @brief return the seek/read/write status of a drive + * @return the seek/read/write status for the drive unit (0:active 1:inactive) + */ +int diablo_hd_device::get_seek_read_write_0() const +{ + return m_s_r_w_0; +} + +/** + * @brief return the ready status of a drive + * @return the ready status for the drive unit (0:ready 1:not ready) + */ +int diablo_hd_device::get_ready_0() const +{ + return m_ready_0; +} + +/** + * @brief return the current sector mark status of a drive + * + * The sector mark is derived from the offset into the current sector. + * It is deasserted except for a short time (a few micro seconds) + * around each new sector. + * + * @return the current sector mark for the drive (0:active 1:inactive) + */ +int diablo_hd_device::get_sector_mark_0() const +{ + /* no sector marks while seeking (?) */ + if (m_s_r_w_0) + return 1; + + /* return the sector mark */ + return m_sector_mark_0; +} + +/** + * @brief return the address acknowledge state + * @return address acknowledge state (0:active 1:inactive) + */ +int diablo_hd_device::get_addx_acknowledge_0() const +{ + return m_addx_acknowledge_0; +} + +/** + * @brief return the log address interlock state + * @return log address interlock state (0:active 1:inactive) + */ +int diablo_hd_device::get_log_addx_interlock_0() const +{ + return m_log_addx_interlock_0; +} + +/** + * @brief return the seek incomplete state + * @return address acknowledge state (0:active 1:inactive) + */ +int diablo_hd_device::get_seek_incomplete_0() const +{ + return m_seek_incomplete_0; +} + +/** + * @brief return the current cylinder of a drive unit + * + * This is a convenience function. + * There is no such signal on the BUS. + * + * Note: The bus lines are active low + * The value on the BUS needs an XOR with DIABLO_CYLINDER_MASK + * to resemble the physical line levels. + * + * @return current cylinder number for the drive + */ +int diablo_hd_device::get_cylinder() const +{ + return m_cylinder; +} + +/** + * @brief return the current head of a drive unit + * + * This is a convenience function. + * There is no such signal on the BUS. + * + * Note: The bus lines are active low + * The value on the BUS needs an XOR with DIABLO_HEAD_MASK + * to resemble the physical line levels. + * + * @return currently selected head for the drive + */ +int diablo_hd_device::get_head() const +{ + return m_head; +} + +/** + * @brief return the current sector of a drive unit + * + * The current sector number is derived from the time since the + * most recent track rotation started. + * It counts modulo DIABLO_SPT (12). + * + * Note: The bus lines are active low + * The value on the BUS needs an XOR with DIABLO_SECTOR_MASK + * to resemble the physical line levels. + * + * @return current sector for the drive + */ +int diablo_hd_device::get_sector() const +{ + return m_sector; +} + +/** + * @brief return the current page of a drive unit + * + * This is a convenience function. + * There is no such signal on the BUS. + * + * The current page number is derived from the cylinder, + * head, and sector numbers. + * + * @return the current page for the drive + */ +int diablo_hd_device::get_page() const +{ + return m_page; +} + +/** + * @brief select a drive unit + * + * Selecting a drive unit updates the ready status + * + * @param unit unit number + */ +void diablo_hd_device::select(int unit) +{ + assert(unit == m_unit); // this drive is selected + + if (m_disk) { + m_ready_0 = 0; // it is ready + m_s_r_w_0 = 0; // and can take seek/read/write commands + m_addx_acknowledge_0 = 0; // assert address acknowledge (?) + m_log_addx_interlock_0 = 1; // deassert log address interlock (?) + LOG_DRIVE((1,"[DHD%u] select unit:%d ready\n", m_unit, unit)); + read_sector(); + } else { + m_ready_0 = 1; // it is not ready (?) + m_s_r_w_0 = 1; // can't take seek/read/write commands (?) + m_addx_acknowledge_0 = 0; // assert address acknowledge (?) + m_log_addx_interlock_0 = 1; // deassert log address interlock (?) + LOG_DRIVE((1,"[DHD%u] select unit:%d not ready (no image)\n", m_unit, unit)); + } +} + +/** + * @brief set the selected head + * @param head head number + */ +void diablo_hd_device::set_head(int head) +{ + if ((head & DIABLO_HEAD_MASK) != m_head) { + m_head = head & DIABLO_HEAD_MASK; + LOG_DRIVE((0,"[DHD%u] select head:%d\n", m_unit, m_head)); + } +} + +/** + * @brief set the cylinder number to seek to + * + * This defines the cylinder to seek when the + * STROBE line is pulsed. + * + * @param cylinder cylinder number (bus lines CYL[0-9]) + */ +void diablo_hd_device::set_cylinder(int cylinder) +{ + if ((cylinder & DIABLO_CYLINDER_MASK) != m_seekto) { + m_seekto = cylinder & DIABLO_CYLINDER_MASK; + LOG_DRIVE((0,"[DHD%u] seek to cylinder:%d\n", m_unit, m_seekto)); + } +} + +/** + * @brief set the restore line + * + * If the restore line is asserted when the + * STROBE line is pulsed, the drive seeks + * towards cylinder 0. + * + * @param restore state of the restore line + */ +void diablo_hd_device::set_restore(int restore) +{ + if ((restore & 1) != m_restore) { + m_restore = restore & 1; + LOG_DRIVE((0,"[DHD%u] restore:%d\n", m_unit, m_restore)); + } +} + +/** + * @brief strobe a seek operation + * + * Seek to the specified cylinder m_seekto, + * or restore to cylinder 0, if m_restore is set. + * + * @param strobe current level of the strobe signal (for edge detection) + */ +void diablo_hd_device::set_strobe(int strobe) +{ + int seekto = m_restore ? 0 : m_seekto; + if (strobe) { + LOG_DRIVE((1,"[DHD%u] STROBE end of interlock\n", m_unit)); + // deassert the log address interlock + m_log_addx_interlock_0 = 1; + return; + } + + // assert the log address interlock + m_log_addx_interlock_0 = 0; + + if (seekto == m_cylinder) { + LOG_DRIVE((1,"[DHD%u] STROBE to cylinder %d acknowledge\n", m_unit, seekto)); + m_addx_acknowledge_0 = 0; // address acknowledge, if cylinder is reached + m_seek_incomplete_0 = 1; // reset seek incomplete + return; + } + // assert the seek-read-write signal + m_s_r_w_0 = 0; + + bool complete = true; + if (seekto < m_cylinder) { + m_cylinder--; // previous cylinder + if (m_cylinder < 0) { + m_cylinder = 0; + complete = false; + } + } + if (seekto > m_cylinder) { + /* increment cylinder */ + m_cylinder++; + if (m_cylinder >= m_cylinders) { + m_cylinder = m_cylinders - 1; + complete = false; + } + } + if (complete) { + LOG_DRIVE((1,"[DHD%u] STROBE to cylinder %d (now %d) - interlock\n", m_unit, seekto, m_cylinder)); + m_addx_acknowledge_0 = 1; // deassert address acknowledge signal + m_seek_incomplete_0 = 1; // deassert seek incomplete signal + read_sector(); + } else { + m_log_addx_interlock_0 = 0; // deassert the log address interlock signal + m_seek_incomplete_0 = 1; // deassert seek incomplete signal + m_addx_acknowledge_0 = 0; // assert address acknowledge signal + LOG_DRIVE((1,"[DHD%u] STROBE to cylinder %d incomplete\n", m_unit, seekto)); + } +} + +/** + * @brief set the drive erase gate + * @param gate value of erase gate + */ +void diablo_hd_device::set_egate(int gate) +{ + m_egate_0 = gate & 1; +} + +/** + * @brief set the drive write gate + * @param gate value of write gate + */ +void diablo_hd_device::set_wrgate(int gate) +{ + m_wrgate_0 = gate & 1; +} + +/** + * @brief set the drive read gate + * @param gate value of read gate + */ +void diablo_hd_device::set_rdgate(int gate) +{ + m_rdgate_0 = gate & 1; +} + +/** + * @brief write the sector relative bit at index + * + * The disk controller writes a combined clock and data pulse to one output + *
+ * Encoding of binary 01011
+ *
+ *   clk   data  clk   data  clk   data  clk   data  clk   data
+ *   0     1     2     3     4     5     6     7     8     9
+ *   +--+        +--+  +--+  +--+        +--+  +--+  +--+  +--+  +--
+ *   |  |        |  |  |  |  |  |        |  |  |  |  |  |  |  |  |
+ * --+  +--------+  +--+  +--+  +--------+  +--+  +--+  +--+  +--+
+ * 
+ * + * @param index relative index of bit/clock into sector + * @param wrdata write data clock or bit + */ +void diablo_hd_device::wr_data(int index, int wrdata) +{ + if (m_wrgate_0) { + LOG_DRIVE((0,"[DHD%u] index=%d wrgate not asserted\n", m_unit, index)); + return; // write gate is not asserted (active 0) + } + + if (index < 0 || index >= bits_per_sector()) { + LOG_DRIVE((0,"[DHD%u] index=%d out of range\n", m_unit, index)); + return; // don't write before or beyond the sector + } + + if (-1 == m_page) { + LOG_DRIVE((0,"[DHD%u] invalid page\n", m_unit)); + return; // invalid page + } + + UINT32 *bits = expand_sector(); + if (!bits) { + LOG_DRIVE((0,"[DHD%u] no bits\n", m_unit)); + return; // invalid unit + } + + if (-1 == m_wrfirst) + m_wrfirst = index; + + LOG_DRIVE((9,"[DHD%u] CHS:%03d/%d/%02d index #%d bit:%d\n", m_unit, m_cylinder, m_head, m_sector, index, wrdata)); + + if (index < GUARD_ZONE_BITS) { + /* don't write in the guard zone (?) */ + } else { + WRBIT(bits,index,wrdata); + } + m_wrlast = index; +} + +/** + * @brief read the sector relative bit at index + * + * Note: this is a gross hack to allow the controller pulling bits + * at its will, rather than clocking them with the drive's RDCLK- + * + * @param index is the sector relative bit index + * @return returns the sector's bit by index + */ +int diablo_hd_device::rd_data(int index) +{ + int bit = 0; + + if (m_rdgate_0) { + LOG_DRIVE((1,"[DHD%u] index=%d rdgate not asserted\n", m_unit, index)); + return 0; // read gate is not asserted (active 0) + } + + if (index < 0 || index >= bits_per_sector()) { + LOG_DRIVE((0,"[DHD%u] index=%d out of range\n", m_unit, index)); + return 1; // don't read before or beyond the sector + } + + if (0 == m_sector_mark_0) { + LOG_DRIVE((0,"[DHD%u] read while sector mark is asserted\n", m_unit)); + return 1; // no data while sector mark is asserted + } + + if (-1 == m_page) { + LOG_DRIVE((0,"[DHD%u] invalid page\n", m_unit)); + return 1; // invalid unit + } + + UINT32 *bits = expand_sector(); + if (!bits) { + LOG_DRIVE((0,"[DHD%u] no bits\n", m_unit)); + return 1; // invalid page + } + + if (-1 == m_rdfirst) + m_rdfirst = index; + + RDBIT(bits,index,bit); + LOG_DRIVE((9,"[DHD%u] CHS:%03d/%d/%02d index #%d bit:%d\n", m_unit, m_cylinder, m_head, m_sector, index, bit)); + m_rdlast = index; + return bit; +} + +/** + * @brief get the sector relative clock at index + * + * Note: this is a gross hack to allow the controller pulling bits + * at its will, rather than clocking them with the drive's RDCLK- + * + * @param index is the sector relative bit index + * @return returns the sector's clock bit by index + */ +int diablo_hd_device::rd_clock(int index) +{ + int clk = 0; + + if (index < 0 || index >= bits_per_sector()) { + LOG_DRIVE((0,"[DHD%u] index out of range (%d)\n", m_unit, index)); + return 1; // don't read before or beyond the sector + } + + if (0 == m_sector_mark_0) { + LOG_DRIVE((0,"[DHD%u] read while sector mark is asserted\n", m_unit)); + return 1; // no clock while sector mark is low (?) + } + + if (-1 == m_page) { + LOG_DRIVE((0,"[DHD%u] invalid page\n", m_unit)); + return 1; // invalid page + } + + UINT32 *bits = expand_sector(); + if (!bits) { + LOG_DRIVE((0,"[DHD%u] no bits\n", m_unit)); + return 1; // invalid unit + } + + if (-1 == m_rdfirst) + m_rdfirst = index; + + if (index & 1) { + // clock bits are on even bit positions only + clk = 0; + } else if (bits) { + RDBIT(bits,index,clk); + } else { + clk = 0; + } + LOG_DRIVE((9,"[DHD%u] CHS:%03d/%d/%02d index #%d clk:%d\n", m_unit, m_cylinder, m_head, m_sector, index, clk)); + m_rdlast = index; + return clk ^ 1; +} + +/** + * @brief deassert the sector mark + * + */ +void diablo_hd_device::sector_mark_1() +{ + LOG_DRIVE((9,"[DHD%u] CHS:%03d/%d/%02d sector_mark_0=1\n", m_unit, m_cylinder, m_head, m_sector)); + m_sector_mark_0 = 1; // deassert sector mark (set to 1) +} + +/** + * @brief assert the sector mark and read the next sector + * + * Assert the sector mark and reset the read and write + * first and last bit indices. + * Increment the sector number, wrap and read the + * next sector from the media. + */ +void diablo_hd_device::sector_mark_0() +{ + LOG_DRIVE((9,"[DHD%u] CHS:%03d/%d/%02d sector_mark_0=0\n", m_unit, m_cylinder, m_head, m_sector)); + + // HACK: deassert wrgate + // m_wrgate_0 = 1; + + squeeze_sector(); // squeeze previous sector bits, if it was written to + m_sector_mark_0 = 0; // assert sector mark (set to 0) + // reset read and write bit locations + m_rdfirst = -1; + m_rdlast = -1; + m_wrfirst = -1; + m_wrlast = -1; + + // count up the sector number + m_sector = (m_sector + 1) % DIABLO_SPT; + read_sector(); +} + +void diablo_hd_device::device_start() +{ + m_image = static_cast(subdevice("drive")); + + m_packs = 1; // FIXME: get from configuration? + m_unit = strstr(m_image->tag(), "diablo0") ? 0 : 1; + m_timer = timer_alloc(1, 0); +} + +void diablo_hd_device::device_reset() +{ + // free previous page cache + if (m_cache) { + for (int page = 0; page < m_pages; page++) + if (m_cache[page]) + auto_free(machine(), m_cache[page]); + auto_free(machine(), m_cache); + m_cache = 0; + } + // free previous bits cache + if (m_bits) { + for (int page = 0; page < m_pages; page++) + if (m_bits[page]) + auto_free(machine(), m_bits[page]); + auto_free(machine(), m_bits); + m_bits = 0; + } + m_handle = m_image->get_chd_file(); + m_diablo31 = true; // FIXME: get from m_handle meta data? + m_disk = m_image->get_hard_disk_file(); + if (m_diablo31) { + snprintf(m_description, sizeof(m_description), "DIABLO31"); + m_rotation_time = DIABLO31_ROTATION_TIME; + m_sector_time = DIABLO31_ROTATION_TIME / DIABLO_SPT; + m_sector_mark_0_time = DIABLO31_SECTOR_MARK_PULSE_PRE; + m_sector_mark_1_time = DIABLO31_SECTOR_MARK_PULSE_PRE; + m_bit_time = DIABLO31_BIT_TIME(1); + m_cylinders = DIABLO_CYLINDERS; + m_pages = DIABLO_PAGES; + } else { + snprintf(m_description, sizeof(m_description), "DIABLO44"); + m_rotation_time = DIABLO44_ROTATION_TIME; + m_sector_time = DIABLO44_ROTATION_TIME / DIABLO_SPT; + m_sector_mark_0_time = DIABLO44_SECTOR_MARK_PULSE_PRE; + m_sector_mark_1_time = DIABLO44_SECTOR_MARK_PULSE_PRE; + m_bit_time = DIABLO44_BIT_TIME(1); + m_cylinders = 2 * DIABLO_CYLINDERS; + m_pages = 2 * DIABLO_PAGES; + } + LOG_DRIVE((0,"[DHD%u] m_handle : %p\n", m_unit, m_handle)); + LOG_DRIVE((0,"[DHD%u] m_disk : %p\n", m_unit, m_disk)); + LOG_DRIVE((0,"[DHD%u] rotation time : %.0fns\n", m_unit, m_rotation_time.as_double() * ATTOSECONDS_PER_NANOSECOND)); + LOG_DRIVE((0,"[DHD%u] sector time : %.0fns\n", m_unit, m_sector_time.as_double() * ATTOSECONDS_PER_NANOSECOND)); + LOG_DRIVE((0,"[DHD%u] sector mark 0 time : %.0fns\n", m_unit, m_sector_mark_0_time.as_double() * ATTOSECONDS_PER_NANOSECOND)); + LOG_DRIVE((0,"[DHD%u] sector mark 1 time : %.0fns\n", m_unit, m_sector_mark_1_time.as_double() * ATTOSECONDS_PER_NANOSECOND)); + LOG_DRIVE((0,"[DHD%u] bit time : %.0fns\n", m_unit, m_bit_time.as_double() * ATTOSECONDS_PER_NANOSECOND)); + + m_s_r_w_0 = 1; // deassert seek/read/write ready + m_ready_0 = 1; // deassert drive ready + m_sector_mark_0 = 1; // deassert sector mark + m_addx_acknowledge_0 = 1; // deassert drive address acknowledge + m_log_addx_interlock_0 = 1; // deassert drive log address interlock + m_seek_incomplete_0 = 1; // deassert drive seek incomplete + + // reset the disk drive's strobe info + m_seekto = 0; + m_restore = 0; + // reset the disk drive's address + m_cylinder = 0; + m_head = 0; + m_sector = 0; + m_page = 0; + + // disable the erase, write and read gates + m_egate_0 = 1; + m_wrgate_0 = 1; + m_rdgate_0 = 1; + + // reset read and write first and last indices + m_wrfirst = -1; + m_wrlast = -1; + m_rdfirst = -1; + m_rdlast = -1; + + if (!m_handle) + return; + // for units with a CHD assigned to them start the timer + m_cache = auto_alloc_array_clear(machine(), UINT8*, m_pages); + m_bits = auto_alloc_array_clear(machine(), UINT32*, m_pages); + timer_set(m_sector_time - m_sector_mark_0_time, 1, 0); + read_sector(); +} + +/** + * @brief timer callback that is called thrice per sector in the rotation + * + * The timer is called three times at the events: + * 0: sector mark goes active + * 1: sector mark goes inactive + * 2: in the middle of the active phase + * + * @param id timer id + * @param arg argument supplied to timer_insert (unused) + */ +void diablo_hd_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + LOG_DRIVE((9,"[DHD%u] TIMER id=%d param=%d ptr=%p @%.0fns\n", m_unit, id, param, ptr, timer.elapsed().as_double() * ATTOSECONDS_PER_NANOSECOND)); + if (!m_disk) + return; + + switch (param) { + case 0: + // assert sector mark + sector_mark_0(); + // next sector timer event is in the middle between sector_mark going 0 and back to 1 + timer.adjust(m_sector_mark_0_time, 1); + break; + case 1: + /* call the sector_callback, if any */ + if (m_sector_callback) + (void)(*m_sector_callback)(m_sector_callback_cookie, m_unit); + // next sector timer event is deassert of sector_mark_0 (set to 1) + timer.adjust(m_sector_mark_1_time, 2); + break; + case 2: + // deassert sector mark + sector_mark_1(); + // next sector timer event is sector_mark_0 for next sector + timer.adjust(m_sector_time - m_sector_mark_0_time, 0); + break; + } +} + +MACHINE_CONFIG_FRAGMENT( diablo_drive ) + MCFG_DIABLO_ADD("drive") +MACHINE_CONFIG_END + +machine_config_constructor diablo_hd_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( diablo_drive ); +} + +const device_type DIABLO_HD = &device_creator; diff --git a/src/devices/machine/diablo_hd.h b/src/devices/machine/diablo_hd.h new file mode 100644 index 00000000000..835cc2c281d --- /dev/null +++ b/src/devices/machine/diablo_hd.h @@ -0,0 +1,178 @@ +// license:BSD-3-Clause +// copyright-holders:Juergen Buchmueller +/********************************************************** + * DIABLO31 and DIABLO44 hard drive support + **********************************************************/ + +#if !defined(_DIABLO_HD_DEVICE_) +#define _DIABLO_HD_DEVICE_ + +#include "emu.h" +#include "imagedev/diablo.h" + +#ifndef DIABLO_DEBUG +#define DIABLO_DEBUG 1 //!< set to 1 to enable debug log output +#endif + +#define DIABLO_HD_0 "diablo0" +#define DIABLO_HD_1 "diablo1" + +extern const device_type DIABLO_HD; + +class diablo_hd_device : public device_t +{ +public: + diablo_hd_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + ~diablo_hd_device(); + + static const int DIABLO_UNIT_MAX = 2; //!< max number of drive units + static const int DIABLO_CYLINDERS = 203; //!< number of cylinders per drive + static const int DIABLO_CYLINDER_MASK = 0777; //!< bit maks for cylinder number (9 bits) + static const int DIABLO_SPT = 12; //!< number of sectors per track + static const int DIABLO_SECTOR_MASK = 017; //!< bit maks for sector number (4 bits) + static const int DIABLO_HEADS = 2; //!< number of heads per drive + static const int DIABLO_HEAD_MASK = 1; //!< bit maks for head number (1 bit) + static const int DIABLO_PAGES = 203*2*12; //!< number of pages per drive + //! convert a cylinder/head/sector to a logical block address (page) + static inline int DIABLO_PAGE(int c, int h, int s) { return (c * DIABLO_HEADS + h) * DIABLO_SPT + s; } + + void set_sector_callback(void* cookie, void(*callback)(void*, int)); + + int bits_per_sector() const; + const char* description() const; + int unit() const; + attotime rotation_time() const; + attotime sector_time() const; + attotime bit_time() const; + + int get_seek_read_write_0() const; + int get_ready_0() const; + int get_sector_mark_0() const; + int get_addx_acknowledge_0() const; + int get_log_addx_interlock_0() const; + int get_seek_incomplete_0() const; + int get_cylinder() const; + int get_head() const; + int get_sector() const; + int get_page() const; + void select(int unit); + void set_head(int head); + void set_cylinder(int cylinder); + void set_restore(int restore); + void set_strobe(int strobe); + void set_egate(int gate); + void set_wrgate(int gate); + void set_rdgate(int gate); + void wr_data(int index, int wrdata); + int rd_data(int index); + int rd_clock(int index); + +protected: + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + virtual machine_config_constructor device_mconfig_additions() const; + +private: +#if DIABLO_DEBUG + int m_log_level; + void logprintf(int level, const char* format, ...); +# define LOG_DRIVE(x) logprintf x + +#else +# define LOG_DRIVE(x) +#endif + bool m_diablo31; //!< true, if this is a DIABLO31 drive + int m_unit; //!< drive unit number (0 or 1) + char m_description[32]; //!< description of the drive(s) + int m_packs; //!< number of packs in drive (1 or 2) + attotime m_rotation_time; //!< rotation time in atto seconds + attotime m_sector_time; //!< sector time in atto seconds + attotime m_sector_mark_0_time; //!< sector mark going 0 before sector pulse time + attotime m_sector_mark_1_time; //!< sector mark going 1 after sector pulse time + attotime m_bit_time; //!< bit time in atto seconds + int m_s_r_w_0; //!< drive seek/read/write signal (active 0) + int m_ready_0; //!< drive ready signal (active 0) + int m_sector_mark_0; //!< sector mark (0 if new sector) + int m_addx_acknowledge_0; //!< address acknowledge, i.e. seek successful (active 0) + int m_log_addx_interlock_0; //!< log address interlock, i.e. seek in progress (active 0) + int m_seek_incomplete_0; //!< seek incomplete, i.e. seek in progress (active 0) + int m_egate_0; //!< erase gate + int m_wrgate_0; //!< write gate + int m_rdgate_0; //!< read gate + int m_cylinders; //!< total number of cylinders + int m_pages; //!< total number of pages + int m_seekto; //!< seek to cylinder number + int m_restore; //!< restore to cylinder 0 flag + int m_cylinder; //!< current cylinder number + int m_head; //!< current head (track) number on cylinder + int m_sector; //!< current sector number in track + int m_page; //!< current page (derived from cylinder, head and sector) + UINT8** m_cache; //!< pages raw bytes + UINT32** m_bits; //!< pages expanded to bits + int m_rdfirst; //!< set to first bit of a sector that is read from + int m_rdlast; //!< set to last bit of a sector that was read from + int m_wrfirst; //!< set to non-zero if a sector is written to + int m_wrlast; //!< set to last bit of a sector that was written to + void *m_sector_callback_cookie; //!< cookie to pass to callback + void (*m_sector_callback)(void*,int); //!< callback to call at the start of each sector + emu_timer* m_timer; //!< sector timer + diablo_image_device* m_image; //!< diablo_image_device interfacing the CHD + chd_file* m_handle; //!< underlying CHD handle + hard_disk_file* m_disk; //!< underlying hard disk file + + //! translate C/H/S to a page and read the sector + void read_sector(); + + //! compute the checksum of a record + int cksum(UINT8 *src, size_t size, int start); + + //! expand a series of clock bits and 0 data bits + size_t expand_zeroes(UINT32 *bits, size_t dst, size_t size); + + //! expand a series of 0 words and write a final sync bit + size_t expand_sync(UINT32 *bits, size_t dst, size_t size); + + //! expand a record of words into a array of bits at dst + size_t expand_record(UINT32 *bits, size_t dst, UINT8 *field, size_t size); + + //! expand a record's checksum word to 32 bits + size_t expand_cksum(UINT32 *bits, size_t dst, UINT8 *field, size_t size); + + //! expand a sector into an array of clock and data bits + UINT32* expand_sector(); + +#if DIABLO_DEBUG + //! dump a number of words as ASCII characters + void dump_ascii(UINT8 *src, size_t size); + + //! dump a record's contents + size_t dump_record(UINT8 *src, size_t addr, size_t size, const char *name, int cr); +#endif + + //! find a sync bit in an array of clock and data bits + size_t squeeze_sync(UINT32 *bits, size_t src, size_t size); + + //! find a 16 x 0 bits sequence in an array of clock and data bits + size_t squeeze_unsync(UINT32 *bits, size_t src, size_t size); + + //! squeeze an array of clock and data bits into a sector's record + size_t squeeze_record(UINT32 *bits, size_t src, UINT8 *field, size_t size); + + //! squeeze an array of 32 clock and data bits into a checksum word + size_t squeeze_cksum(UINT32 *bits, size_t src, int *cksum); + + //! squeeze a array of clock and data bits into a sector's data + void squeeze_sector(); + + //! deassert the sector mark + void sector_mark_1(); + + //! assert the sector mark and read the next sector + void sector_mark_0(); +}; + +#define MCFG_DIABLO_DRIVES_ADD() \ + MCFG_DEVICE_ADD(DIABLO_HD_0, DIABLO_HD, 3333333) \ + MCFG_DEVICE_ADD(DIABLO_HD_1, DIABLO_HD, 3333333) +#endif // !defined(_DIABLO_HD_DEVICE_) diff --git a/src/devices/machine/dmac.c b/src/devices/machine/dmac.c new file mode 100644 index 00000000000..d739d64f308 --- /dev/null +++ b/src/devices/machine/dmac.c @@ -0,0 +1,465 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best +/*************************************************************************** + + DMAC + + DMA controller used in Amiga systems + +BOARDS: + CBM A590/A2091 HD controller: Prod=514/3($202/$3) (@$e90000 64K) + CBM A2052/58. RAM I 590/2091.RAM Prod=514/10($202/$a) (@$200000 2meg mem) + +***************************************************************************/ + +#include "dmac.h" + + +//************************************************************************** +// CONSTANTS / MACROS +//************************************************************************** + +#define VERBOSE 1 + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type DMAC = &device_creator; + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// dmac_device - constructor +//------------------------------------------------- + +dmac_device::dmac_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, DMAC, "DMAC DMA Controller", tag, owner, clock, "dmac", __FILE__), + amiga_autoconfig(), + m_cfgout_handler(*this), + m_int_handler(*this), + m_xdack_handler(*this), + m_scsi_read_handler(*this), + m_scsi_write_handler(*this), + m_io_read_handler(*this), + m_io_write_handler(*this), + m_space(NULL), + m_rom(NULL), + m_ram(NULL), + m_ram_size(-1), + m_configured(false), + m_rst(-1), + m_cntr(0), + m_istr(0), + m_wtc(0), + m_acr(0), + m_dma_active(false) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void dmac_device::device_start() +{ + // resolve callbacks + m_cfgout_handler.resolve_safe(); + m_int_handler.resolve_safe(); + m_xdack_handler.resolve_safe(); + m_scsi_read_handler.resolve_safe(0); + m_scsi_write_handler.resolve_safe(); + m_io_read_handler.resolve_safe(0); + m_io_write_handler.resolve_safe(); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void dmac_device::device_reset() +{ + // fifo empty + m_istr |= ISTR_FE_FLG; +} + +void dmac_device::autoconfig_base_address(offs_t address) +{ + if (VERBOSE) + logerror("%s('%s'): autoconfig_base_address received: 0x%06x\n", shortname(), basetag(), address); + + if (!m_configured && m_ram_size > 0) + { + if (VERBOSE) + logerror("-> installing ram (%d bytes)\n", m_ram_size); + + // install access to the ram space + if (address) + m_space->install_ram(address, address + (m_ram_size - 1), m_ram); + + // prepare autoconfig for main device + autoconfig_board_size(BOARD_SIZE_64K); + autoconfig_product(0x03); // or 0x02 for rev 1 + autoconfig_rom_vector(0x2000); + autoconfig_rom_vector_valid(true); + autoconfig_link_into_memory(false); + autoconfig_multi_device(false); + + // first device configured + m_configured = true; + } + else + { + if (VERBOSE) + logerror("-> installing dmac\n"); + + // internal dmac registers + m_space->install_readwrite_handler(address, address + 0xff, + read16_delegate(FUNC(dmac_device::register_read), this), + write16_delegate(FUNC(dmac_device::register_write), this), 0xffff); + + // install access to the rom space + if (m_rom) + { + m_space->install_rom(address + 0x2000, address + 0x7fff, m_rom + 0x2000); + m_space->install_rom(address + 0x8000, address + 0xffff, m_rom); + } + + // stop responding to autoconfig + m_space->unmap_readwrite(0xe80000, 0xe8007f); + + // we're done + m_cfgout_handler(0); + } +} + +void dmac_device::check_interrupts() +{ + // interrupts enabled? + if (m_cntr & CNTR_INTEN) + { + // any interrupts pending? + if (m_istr & ISTR_INT_MASK) + m_istr |= ISTR_INT_P; + } + else + m_istr &= ~ISTR_INT_P; + + // finally update interrupt line + m_int_handler((m_istr & ISTR_INT_P) ? 1 : 0); +} + +void dmac_device::stop_dma() +{ + m_dma_active = false; + m_istr &= ~ISTR_E_INT; + check_interrupts(); +} + +void dmac_device::start_dma() +{ + m_dma_active = true; +} + + +//************************************************************************** +// IMPLEMENTATION +//************************************************************************** + +READ16_MEMBER( dmac_device::register_read ) +{ + UINT16 data = 0xffff; + + // autoconfig handles this + if (offset < 0x20) + return autoconfig_read(space, offset, mem_mask); + + switch (offset) + { + case 0x20: + data = m_istr; + + // reading clears fifo status (?) + m_istr &= ~0x0f; + check_interrupts(); + + if (VERBOSE) + logerror("%s('%s'): read istr %04x [mask = %04x]\n", shortname(), basetag(), data, mem_mask); + + break; + + case 0x21: + data = m_cntr; + + if (VERBOSE) + logerror("%s('%s'): read cntr %04x [mask = %04x]\n", shortname(), basetag(), data, mem_mask); + + break; + + case 0x48: + case 0x49: + case 0x50: + case 0x58: + case 0x59: + case 0x5a: + case 0x5b: + case 0x5c: + case 0x5e: + case 0x5f: + data = m_scsi_read_handler(offset); + + if (VERBOSE) + logerror("%s('%s'): read scsi data @ %02x %04x [mask = %04x]\n", shortname(), basetag(), offset, data, mem_mask); + + break; + + case 0x70: + if (VERBOSE) + logerror("%s('%s'): read dma start strobe %04x [mask = %04x]\n", shortname(), basetag(), data, mem_mask); + + start_dma(); + break; + + case 0x71: + if (VERBOSE) + logerror("%s('%s'): read dma stop strobe %04x [mask = %04x]\n", shortname(), basetag(), data, mem_mask); + + stop_dma(); + break; + + case 0x72: + if (VERBOSE) + logerror("%s('%s'): read clear irq strobe %04x [mask = %04x]\n", shortname(), basetag(), data, mem_mask); + + // clear all interrupts + m_istr &= ~ISTR_INT_MASK; + check_interrupts(); + break; + + case 0x74: + if (VERBOSE) + logerror("%s('%s'): read flush fifo strobe %04x [mask = %04x]\n", shortname(), basetag(), data, mem_mask); + + m_istr |= ISTR_FE_FLG; + break; + + default: + if (VERBOSE) + logerror("%s('%s'): register_read %04x @ %02x [mask = %04x]\n", shortname(), basetag(), data, offset, mem_mask); + } + + return data; +} + +WRITE16_MEMBER( dmac_device::register_write ) +{ + switch (offset) + { + case 0x21: + if (VERBOSE) + logerror("%s('%s'): write cntr %04x [mask = %04x]\n", shortname(), basetag(), data, mem_mask); + + m_cntr = data; + check_interrupts(); + break; + + case 0x40: + if (VERBOSE) + logerror("%s('%s'): write wtc hi %04x [mask = %04x]\n", shortname(), basetag(), data, mem_mask); + + m_wtc &= 0x0000ffff; + m_wtc |= ((UINT32) data) << 16; + break; + + case 0x41: + if (VERBOSE) + logerror("%s('%s'): write wtc lo %04x [mask = %04x]\n", shortname(), basetag(), data, mem_mask); + + m_wtc &= 0xffff0000; + m_wtc |= data; + break; + + case 0x42: + if (VERBOSE) + logerror("%s('%s'): write acr hi %04x [mask = %04x]\n", shortname(), basetag(), data, mem_mask); + + m_acr &= 0x0000ffff; + m_acr |= ((UINT32) data) << 16; + break; + + case 0x43: + if (VERBOSE) + logerror("%s('%s'): write acr lo %04x [mask = %04x]\n", shortname(), basetag(), data, mem_mask); + + m_acr &= 0xffff0000; + m_acr |= data; + break; + + case 0x47: + if (VERBOSE) + logerror("%s('%s'): write dawr %04x [mask = %04x]\n", shortname(), basetag(), data, mem_mask); + break; + + case 0x48: + case 0x49: + case 0x50: + case 0x58: + case 0x59: + case 0x5a: + case 0x5b: + case 0x5c: + case 0x5e: + case 0x5f: + if (VERBOSE) + logerror("%s('%s'): write scsi data @ %02x %04x [mask = %04x]\n", shortname(), basetag(), offset, data, mem_mask); + + m_scsi_write_handler(offset, data, 0xff); + break; + + case 0x70: + if (VERBOSE) + logerror("%s('%s'): write dma start strobe %04x [mask = %04x]\n", shortname(), basetag(), data, mem_mask); + + start_dma(); + break; + + case 0x71: + if (VERBOSE) + logerror("%s('%s'): write dma stop strobe %04x [mask = %04x]\n", shortname(), basetag(), data, mem_mask); + + stop_dma(); + break; + + case 0x72: + if (VERBOSE) + logerror("%s('%s'): write clear irq strobe %04x [mask = %04x]\n", shortname(), basetag(), data, mem_mask); + + // clear all interrupts + m_istr &= ~ISTR_INT_MASK; + check_interrupts(); + break; + + case 0x74: + if (VERBOSE) + logerror("%s('%s'): write flush fifo strobe %04x [mask = %04x]\n", shortname(), basetag(), data, mem_mask); + + m_istr |= ISTR_FE_FLG; + break; + + default: + if (VERBOSE) + logerror("%s('%s'): write %04x @ %02x [mask = %04x]\n", shortname(), basetag(), data, offset, mem_mask); + } +} + +// this signal tells us to expose our autoconfig values +WRITE_LINE_MEMBER( dmac_device::configin_w ) +{ + if (VERBOSE) + logerror("%s('%s'): configin_w (%d)\n", shortname(), basetag(), state); + + if (state == 0 && !m_configured) + { + // common autoconfig values + autoconfig_board_type(BOARD_TYPE_ZORRO2); + autoconfig_manufacturer(0x0202); + autoconfig_serial(0x00000000); + autoconfig_8meg_preferred(false); + autoconfig_can_shutup(true); + + // if we have ram, configure it first + if (m_ram_size > 0) + { + // product id 10 + autoconfig_product(0x0a); + + // board size + switch (m_ram_size) + { + case 0x080000: autoconfig_board_size(BOARD_SIZE_512K); break; + case 0x100000: autoconfig_board_size(BOARD_SIZE_1M); break; + case 0x200000: autoconfig_board_size(BOARD_SIZE_2M); break; + } + + // no rom and link into free memory + autoconfig_rom_vector_valid(false); + autoconfig_link_into_memory(true); + + // the main device follows + autoconfig_multi_device(true); + } + else + { + // just setup autoconfig for the main device + autoconfig_board_size(BOARD_SIZE_64K); + autoconfig_product(0x03); // or 0x02 for rev 1 + autoconfig_rom_vector(0x2000); + autoconfig_rom_vector_valid(true); + autoconfig_link_into_memory(false); + + // no more devices after this + autoconfig_multi_device(false); + } + + // install autoconfig handler + m_space->install_readwrite_handler(0xe80000, 0xe8007f, + read16_delegate(FUNC(amiga_autoconfig::autoconfig_read), static_cast(this)), + write16_delegate(FUNC(amiga_autoconfig::autoconfig_write), static_cast(this)), 0xffff); + } +} + +// this sets the ram size depending on the line voltage +WRITE_LINE_MEMBER( dmac_device::ramsz_w ) +{ + if (VERBOSE) + logerror("%s('%s'): ramsz_w (%d)\n", shortname(), basetag(), state); + + switch (state) + { + case 0: m_ram_size = 0x000000; break; + case 1: m_ram_size = 0x080000; break; + case 2: m_ram_size = 0x100000; break; + case 3: m_ram_size = 0x200000; break; + } +} + +// reset the device +WRITE_LINE_MEMBER( dmac_device::rst_w ) +{ + if (VERBOSE) + logerror("%s('%s'): rst_w (%d)\n", shortname(), basetag(), state); + + if (m_rst == 1 && state == 0) + device_reset(); + + m_rst = state; +} + +// external interrupt +WRITE_LINE_MEMBER( dmac_device::intx_w ) +{ + if (VERBOSE) + logerror("%s('%s'): intx_w (%d)\n", shortname(), basetag(), state); + + if (state) + m_istr |= ISTR_INTS; + else + m_istr &= ~ISTR_INTS; + + check_interrupts(); +} + +// data request +WRITE_LINE_MEMBER( dmac_device::xdreq_w ) +{ + if (VERBOSE) + logerror("%s('%s'): xdreq_w (%d)\n", shortname(), basetag(), state); + + if (m_dma_active) + { + } +} diff --git a/src/devices/machine/dmac.h b/src/devices/machine/dmac.h new file mode 100644 index 00000000000..52c5d64ff5d --- /dev/null +++ b/src/devices/machine/dmac.h @@ -0,0 +1,171 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best +/*************************************************************************** + + DMAC + + DMA controller used in Amiga systems + +***************************************************************************/ + +#pragma once + +#ifndef __DMAC_H__ +#define __DMAC_H__ + +#include "emu.h" +#include "autoconfig.h" + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_DMAC_ADD(_tag, _clock) \ + MCFG_DEVICE_ADD(_tag, DMAC, _clock) +#define MCFG_DMAC_CFGOUT_HANDLER(_devcb) \ + devcb = &dmac_device::set_cfgout_handler(*device, DEVCB_##_devcb); + +#define MCFG_DMAC_INT_HANDLER(_devcb) \ + devcb = &dmac_device::set_int_handler(*device, DEVCB_##_devcb); + +#define MCFG_DMAC_XDACK_HANDLER(_devcb) \ + devcb = &dmac_device::set_xdack_handler(*device, DEVCB_##_devcb); + +#define MCFG_DMAC_SCSI_READ_HANDLER(_devcb) \ + devcb = &dmac_device::set_scsi_read_handler(*device, DEVCB_##_devcb); + +#define MCFG_DMAC_SCSI_WRITE_HANDLER(_devcb) \ + devcb = &dmac_device::set_scsi_write_handler(*device, DEVCB_##_devcb); + +#define MCFG_DMAC_IO_READ_HANDLER(_devcb) \ + devcb = &dmac_device::set_io_read_handler(*device, DEVCB_##_devcb); + +#define MCFG_DMAC_IO_WRITE_HANDLER(_devcb) \ + devcb = &dmac_device::set_io_write_handler(*device, DEVCB_##_devcb); + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> dmac_device + +class dmac_device : public device_t, public amiga_autoconfig +{ +public: + // construction/destruction + dmac_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // callbacks + template static devcb_base &set_cfgout_handler(device_t &device, _Object object) + { return downcast(device).m_cfgout_handler.set_callback(object); } + + template static devcb_base &set_int_handler(device_t &device, _Object object) + { return downcast(device).m_int_handler.set_callback(object); } + + template static devcb_base &set_xdack_handler(device_t &device, _Object object) + { return downcast(device).m_xdack_handler.set_callback(object); } + + template static devcb_base &set_scsi_read_handler(device_t &device, _Object object) + { return downcast(device).m_scsi_read_handler.set_callback(object); } + + template static devcb_base &set_scsi_write_handler(device_t &device, _Object object) + { return downcast(device).m_scsi_write_handler.set_callback(object); } + + template static devcb_base &set_io_read_handler(device_t &device, _Object object) + { return downcast(device).m_io_read_handler.set_callback(object); } + + template static devcb_base &set_io_write_handler(device_t &device, _Object object) + { return downcast(device).m_io_write_handler.set_callback(object); } + + void set_address_space(address_space *space) { m_space = space; }; + void set_rom(UINT8 *rom) { m_rom = rom; }; + void set_ram(UINT8 *ram) { m_ram = ram; }; + + // input lines + DECLARE_WRITE_LINE_MEMBER( configin_w ); + DECLARE_WRITE_LINE_MEMBER( ramsz_w ); + DECLARE_WRITE_LINE_MEMBER( rst_w ); + DECLARE_WRITE_LINE_MEMBER( intx_w ); + DECLARE_WRITE_LINE_MEMBER( xdreq_w ); + + // dmac register access + DECLARE_READ16_MEMBER( register_read ); + DECLARE_WRITE16_MEMBER( register_write ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // amiga_autoconfig overrides + virtual void autoconfig_base_address(offs_t address); + +private: + + // control register flags + enum + { + CNTR_TCEN = 0x80, // terminal count enable + CNTR_PREST = 0x40, // peripheral reset + CNTR_PDMD = 0x20, // peripheral device mode select (1=scsi, 0=xt) + CNTR_INTEN = 0x10, // interrupt enable + CNTR_DDIR = 0x08 // device direction (1=rd host, wr to peripheral) + }; + + // interrupt status register + enum + { + ISTR_INTX = 0x100, // xt interrupt pending + ISTR_INT_F = 0x080, // interrupt follow + ISTR_INTS = 0x040, // scsi peripheral interrupt + ISTR_E_INT = 0x020, // end-of-process interrupt + ISTR_INT_P = 0x010, // interrupt pending + ISTR_UE_INT = 0x008, // under-run fifo error interrupt + ISTR_OE_INT = 0x004, // over-run fifo error interrupt + ISTR_FF_FLG = 0x002, // fifo-full flag + ISTR_FE_FLG = 0x001 // fifo-empty flag + }; + + static const int ISTR_INT_MASK = 0x1fc; + + // callbacks + devcb_write_line m_cfgout_handler; + devcb_write_line m_int_handler; + devcb_write_line m_xdack_handler; + devcb_read8 m_scsi_read_handler; + devcb_write8 m_scsi_write_handler; + devcb_read8 m_io_read_handler; + devcb_write8 m_io_write_handler; + + address_space *m_space; + UINT8 *m_rom; + UINT8 *m_ram; + int m_ram_size; + + // autoconfig state + bool m_configured; + + // state of lines + int m_rst; + + // register + UINT16 m_cntr; // control register + UINT16 m_istr; // interrupt status register + UINT32 m_wtc; // word transfer count + UINT32 m_acr; // address control register + + bool m_dma_active; + + void check_interrupts(); + void start_dma(); + void stop_dma(); +}; + + +// device type definition +extern const device_type DMAC; + + +#endif /* __DMAC_H__ */ diff --git a/src/devices/machine/dp8390.c b/src/devices/machine/dp8390.c new file mode 100644 index 00000000000..e67499538ac --- /dev/null +++ b/src/devices/machine/dp8390.c @@ -0,0 +1,479 @@ +// license:BSD-3-Clause +// copyright-holders:Carl +#include "emu.h" +#include "dp8390.h" + +#define DP8390_BYTE_ORDER(w) ((m_regs.dcr & 3) == 3 ? ((data << 8) | (data >> 8)) : data) +#define LOOPBACK (!(m_regs.dcr & 8) && (m_regs.tcr & 6)) + +const device_type DP8390D = &device_creator; +const device_type RTL8019A = &device_creator; + +dp8390d_device::dp8390d_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : dp8390_device(mconfig, DP8390D, "DP8390D", tag, owner, clock, 10.0f, "dp8390d", __FILE__) { + m_type = TYPE_DP8390D; +} + +rtl8019a_device::rtl8019a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : dp8390_device(mconfig, RTL8019A, "RTL8019A", tag, owner, clock, 10.0f, "rtl8019a", __FILE__) { + m_type = TYPE_RTL8019A; +} + +dp8390_device::dp8390_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, float bandwidth, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_network_interface(mconfig, *this, bandwidth), + m_irq_cb(*this), + m_breq_cb(*this), + m_mem_read_cb(*this), + m_mem_write_cb(*this) + { +} + +void dp8390_device::device_start() { + m_irq_cb.resolve_safe(); + m_breq_cb.resolve_safe(); + m_mem_read_cb.resolve_safe(0); + m_mem_write_cb.resolve_safe(); +} + +void dp8390_device::stop() { + m_regs.isr = 0x80; // is this right? + m_regs.cr |= 1; + m_irq_cb(CLEAR_LINE); + m_reset = 1; +} + +void dp8390_device::device_reset() { + memset(&m_regs, 0, sizeof(m_regs)); + m_regs.cr = 0x21; + m_regs.isr = 0x80; + m_regs.dcr = 0x04; + memset(&m_8019regs, 0, sizeof(m_8019regs)); + m_8019regs.config1 = 0x80; + m_8019regs.config3 = 0x01; + m_irq_cb(CLEAR_LINE); + + m_reset = 1; +} + +void dp8390_device::check_dma_complete() { + if(m_regs.rbcr) return; + m_regs.isr |= 0x40; + check_irq(); + m_rdma_active = 0; +} + +void dp8390_device::do_tx() { + dynamic_buffer buf; + int i; + UINT32 high16 = (m_regs.dcr & 4)?m_regs.rsar<<16:0; + if(m_reset) return; + if(LOOPBACK) return; // TODO: loopback + m_regs.tsr = 0; + if(m_regs.tbcr > 1518) logerror("dp8390: trying to send overlong frame\n"); + if(!m_regs.tbcr) { // ? Bochs says solaris actually does this + m_regs.tsr = 1; + m_regs.cr &= ~4; + return; + } + + buf.resize(m_regs.tbcr); + for(i = 0; i < m_regs.tbcr; i++) buf[i] = m_mem_read_cb(high16 + (m_regs.tpsr << 8) + i); + + if(send(&buf[0], m_regs.tbcr)) { + m_regs.tsr = 1; + m_regs.isr |= 2; + } else { + m_regs.tsr = 8; // not quite right but there isn't a generic "tx failed" + m_regs.isr |= 8; + } + m_regs.cr &= ~4; + check_irq(); +} + +void dp8390_device::set_cr(UINT8 newcr) { + int ostate = ((m_regs.cr & 3) == 2); + m_regs.cr = newcr; + if((newcr & 1) && (ostate == 1)) return stop(); + if((newcr & 3) == 2) { + m_reset = 0; + m_regs.isr &= ~0x80; + } + if(newcr & 0x20) m_rdma_active = 0; + if(m_reset) return; + if(newcr & 4) do_tx(); + if((newcr & 0x38) == 8) { + m_rdma_active = 1; + check_dma_complete(); + } + if((newcr & 0x38) == 0x10) m_rdma_active = 2; +} + +void dp8390_device::recv_overflow() { + m_regs.rsr = 0x10; + m_regs.isr |= 0x10; + check_irq(); + m_regs.cntr2++; + return; +} + +void dp8390_device::recv(UINT8 *buf, int len) { + int i; + UINT16 start = (m_regs.curr << 8), offset; + UINT32 high16; + if(m_reset) return; + if(m_regs.curr == m_regs.pstop) start = m_regs.pstart << 8; + offset = start + 4; + high16 = (m_regs.dcr & 4)?m_regs.rsar<<16:0; + if(buf[0] & 1) { + if(!memcmp((const char *)buf, "\xff\xff\xff\xff\xff\xff", 6)) { + if(!(m_regs.rcr & 4)) return; + } else return; // multicast + m_regs.rsr = 0x20; + } else m_regs.rsr = 0; + len &= 0xffff; + + for(i = 0; i < len; i++) { + m_mem_write_cb(high16 + offset, buf[i]); + offset++; + if(!(offset & 0xff)) { + if((offset >> 8) == m_regs.pstop) offset = m_regs.pstart << 8; + if((offset >> 8) == m_regs.bnry) return recv_overflow(); + } + } + if(len < 60) { + // this can't pass to the next page + for(; i < 60; i++) { + m_mem_write_cb(high16 + offset, 0); + offset++; + } + len = 60; + } + + m_regs.rsr |= 1; + m_regs.isr |= 1; + m_regs.curr = (offset >> 8) + ((offset & 0xff)?1:0); + if(m_regs.curr == m_regs.pstop) m_regs.curr = m_regs.pstart; + len += 4; + m_mem_write_cb((offs_t)start, m_regs.rsr); + m_mem_write_cb((offs_t)start+1, m_regs.curr); + m_mem_write_cb((offs_t)start+2, len & 0xff); + m_mem_write_cb((offs_t)start+3, len >> 8); + check_irq(); +} + +void dp8390_device::recv_cb(UINT8 *buf, int len) { + if(!LOOPBACK) recv(buf, len); +} + +WRITE_LINE_MEMBER(dp8390_device::dp8390_cs) { + m_cs = state; +} + +WRITE_LINE_MEMBER(dp8390_device::dp8390_reset) { + if(!state) device_reset(); +} + +READ16_MEMBER(dp8390_device::dp8390_r) { + UINT16 data; + if(m_cs) { + UINT32 high16 = (m_regs.dcr & 4)?m_regs.rsar<<16:0; + if(m_regs.dcr & 1) { + m_regs.crda &= ~1; + data = m_mem_read_cb(high16 + m_regs.crda++); + data |= m_mem_read_cb(high16 + m_regs.crda++) << 8; + m_regs.rbcr -= (m_regs.rbcr < 2)?m_regs.rbcr:2; + check_dma_complete(); + return DP8390_BYTE_ORDER(data); + } else { + m_regs.rbcr -= (m_regs.rbcr)?1:0; + data = m_mem_read_cb(high16 + m_regs.crda++); + check_dma_complete(); + return data; + } + } + + switch((offset & 0x0f)|(m_regs.cr & 0xc0)) { + case 0x00: + case 0x40: + case 0x80: + data = m_regs.cr; + break; + case 0x01: + data = m_regs.clda & 0xff; + break; + case 0x02: + data = m_regs.clda >> 8; + break; + case 0x03: + data = m_regs.bnry; + break; + case 0x04: + data = m_regs.tsr; + break; + case 0x05: + data = m_regs.ncr; + break; + case 0x06: + data = m_regs.fifo; + break; + case 0x07: + data = m_regs.isr; + break; + case 0x08: + data = m_regs.crda & 0xff; + break; + case 0x09: + data = m_regs.crda >> 8; + break; + case 0x0c: + data = m_regs.rsr; + break; + case 0x0d: + data = m_regs.cntr0; + break; + case 0x0e: + data = m_regs.cntr1; + break; + case 0x0f: + data = m_regs.cntr2; + break; + case 0x41: + case 0x42: + case 0x43: + case 0x44: + case 0x45: + case 0x46: + data = m_regs.par[(offset & 0x7)-1]; + break; + case 0x47: + data = m_regs.curr; + break; + case 0x48: + case 0x49: + case 0x4a: + case 0x4b: + case 0x4c: + case 0x4d: + case 0x4e: + case 0x4f: + data = m_regs.mar[offset & 0x7]; + break; + case 0x81: + data = m_regs.pstart; + break; + case 0x82: + data = m_regs.pstop; + break; + case 0x83: + data = m_regs.rnpp; + break; + case 0x84: + data = m_regs.tpsr; + break; + case 0x85: + data = m_regs.lnpp; + break; + case 0x86: + data = m_regs.ac >> 8; + break; + case 0x87: + data = m_regs.ac & 0xff; + break; + case 0x8c: + data = m_regs.rcr; + break; + case 0x8d: + data = m_regs.tcr; + break; + case 0x8e: + data = m_regs.dcr; + break; + case 0x8f: + data = m_regs.imr; + break; + case 0xc0: + data = m_regs.cr; + break; + default: + if(m_type == TYPE_RTL8019A) { + switch((offset & 0x0f)|(m_regs.cr & 0xc0)) { + case 0x0a: + data = 'P'; + break; + case 0x0b: + data = 'p'; + break; + + case 0xc1: + data = m_8019regs.cr9346; + break; + case 0xc2: + data = m_8019regs.bpage; + break; + case 0xc3: + data = m_8019regs.config0; + break; + case 0xc4: + data = m_8019regs.config1; + break; + case 0xc5: + data = m_8019regs.config2; + break; + case 0xc6: + data = m_8019regs.config3; + break; + case 0xcd: + data = m_8019regs.config4; + break; + case 0xc8: + data = m_8019regs.csnsav; + break; + case 0xcb: + data = m_8019regs.intr; + break; + default: + logerror("rtl8019: invalid read page %01X reg %02X\n", (m_regs.cr & 0xc0) >> 6, offset & 0x0f); + return 0; + } + } else { + logerror("dp8390: invalid read page %01X reg %02X\n", (m_regs.cr & 0xc0) >> 6, offset & 0x0f); + return 0; + } + } + return data; +} + +WRITE16_MEMBER(dp8390_device::dp8390_w) { + if(m_cs) { + UINT32 high16 = (m_regs.dcr & 4)?m_regs.rsar<<16:0; + if(m_regs.dcr & 1) { + data = DP8390_BYTE_ORDER(data); + m_regs.crda &= ~1; + m_mem_write_cb(high16 + m_regs.crda++, data & 0xff); + m_mem_write_cb(high16 + m_regs.crda++, data >> 8); + m_regs.rbcr -= (m_regs.rbcr < 2)?m_regs.rbcr:2; + check_dma_complete(); + } else { + data &= 0xff; + m_mem_write_cb(high16 + m_regs.crda++, data); + m_regs.rbcr -= (m_regs.rbcr)?1:0; + check_dma_complete(); + } + return; + } + + data &= 0xff; + switch((offset & 0x0f)|(m_regs.cr & 0xc0)) { + case 0x00: + case 0x40: + case 0x80: + set_cr(data); + break; + case 0x01: + m_regs.pstart = data; + break; + case 0x02: + m_regs.pstop = data; + break; + case 0x03: + m_regs.bnry = data; + break; + case 0x04: + m_regs.tpsr = data; + break; + case 0x05: + m_regs.tbcr = (m_regs.tbcr & 0xff00) | data; + break; + case 0x06: + m_regs.tbcr = (m_regs.tbcr & 0xff) | (data << 8); + break; + case 0x07: + m_regs.isr &= ~data; + check_irq(); + break; + case 0x08: + m_regs.rsar = (m_regs.rsar & 0xff00) | data; + m_regs.crda = m_regs.rsar; + break; + case 0x09: + m_regs.rsar = (m_regs.rsar & 0xff) | (data << 8); + m_regs.crda = m_regs.rsar; + break; + case 0x0a: + m_regs.rbcr = (m_regs.rbcr & 0xff00) | data; + break; + case 0x0b: + m_regs.rbcr = (m_regs.rbcr & 0xff) | (data << 8); + break; + case 0x0c: + m_regs.rcr = data; + set_promisc((data & 0x10)?true:false); + break; + case 0x0d: + m_regs.tcr = data; + break; + case 0x0e: + m_regs.dcr = data; + break; + case 0x0f: + m_regs.imr = data; + check_irq(); + break; + case 0x41: + case 0x42: + case 0x43: + case 0x44: + case 0x45: + case 0x46: + m_regs.par[(offset & 0x7)-1] = data; + set_mac((const char *)m_regs.par); + break; + case 0x47: + m_regs.curr = data; + break; + case 0x48: + case 0x49: + case 0x4a: + case 0x4b: + case 0x4c: + case 0x4d: + case 0x4e: + case 0x4f: + m_regs.mar[offset & 0x7] = data; + break; + case 0x81: + m_regs.clda = (m_regs.clda & 0xff00) | data; + break; + case 0x82: + m_regs.clda = (m_regs.clda & 0xff) | (data << 8); + break; + case 0x83: + m_regs.rnpp = data; + break; + case 0x85: + m_regs.lnpp = data; + break; + case 0x86: + m_regs.ac = (m_regs.ac & 0xff) | (data << 8); + break; + case 0x87: + m_regs.ac = (m_regs.ac & 0xff00) | data; + break; + case 0xc0: + set_cr(data); + break; + default: + if(m_type == TYPE_RTL8019A) { + switch((offset & 0x0f)|(m_regs.cr & 0xc0)) { + // XXX: rest of the regs + default: + logerror("rtl8019: invalid write page %01X reg %02X data %04X\n", (m_regs.cr & 0xc0) >> 6, offset & 0x0f, data); + return; + } + } else { + logerror("dp8390: invalid write page %01X reg %02X data %04X\n", (m_regs.cr & 0xc0) >> 6, offset & 0x0f, data); + return; + } + } +} diff --git a/src/devices/machine/dp8390.h b/src/devices/machine/dp8390.h new file mode 100644 index 00000000000..46889b3b025 --- /dev/null +++ b/src/devices/machine/dp8390.h @@ -0,0 +1,147 @@ +// license:BSD-3-Clause +// copyright-holders:Carl +#ifndef _DP8390_H_ +#define _DP8390_H_ + +#include "emu.h" + + +// device stuff + +#define MCFG_DP8390D_IRQ_CB(_devcb) \ + devcb = &dp8390d_device::set_irq_callback(*device, DEVCB_##_devcb); + +#define MCFG_DP8390D_BREQ_CB(_devcb) \ + devcb = &dp8390d_device::set_breq_callback(*device, DEVCB_##_devcb); + +#define MCFG_DP8390D_MEM_READ_CB(_devcb) \ + devcb = &dp8390d_device::set_mem_read_callback(*device, DEVCB_##_devcb); + +#define MCFG_DP8390D_MEM_WRITE_CB(_devcb) \ + devcb = &dp8390d_device::set_mem_write_callback(*device, DEVCB_##_devcb); + +#define MCFG_RTL8019A_IRQ_CB(_devcb) \ + devcb = &rtl8019a_device::set_irq_callback(*device, DEVCB_##_devcb); + +#define MCFG_RTL8019A_BREQ_CB(_devcb) \ + devcb = &rtl8019a_device::set_breq_callback(*device, DEVCB_##_devcb); + +#define MCFG_RTL8019A_MEM_READ_CB(_devcb) \ + devcb = &rtl8019a_device::set_mem_read_callback(*device, DEVCB_##_devcb); + +#define MCFG_RTL8019A_MEM_WRITE_CB(_devcb) \ + devcb = &rtl8019a_device::set_mem_write_callback(*device, DEVCB_##_devcb); + + +class dp8390_device : public device_t, + public device_network_interface +{ +public: + // construction/destruction + dp8390_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, float bandwidth, const char *shortname, const char *source); + + template static devcb_base &set_irq_callback(device_t &device, _Object object) { return downcast(device).m_irq_cb.set_callback(object); } + template static devcb_base &set_breq_callback(device_t &device, _Object object) { return downcast(device).m_breq_cb.set_callback(object); } + template static devcb_base &set_mem_read_callback(device_t &device, _Object object) { return downcast(device).m_mem_read_cb.set_callback(object); } + template static devcb_base &set_mem_write_callback(device_t &device, _Object object) { return downcast(device).m_mem_write_cb.set_callback(object); } + + DECLARE_WRITE16_MEMBER( dp8390_w ); + DECLARE_READ16_MEMBER( dp8390_r ); + DECLARE_WRITE_LINE_MEMBER( dp8390_cs ); + DECLARE_WRITE_LINE_MEMBER( dp8390_reset ); + void recv_cb(UINT8 *buf, int len); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + int m_type; + + enum { + TYPE_DP8390D = 0, + TYPE_RTL8019A + }; + +private: + devcb_write_line m_irq_cb; + devcb_write_line m_breq_cb; + devcb_read8 m_mem_read_cb; + devcb_write8 m_mem_write_cb; + + void set_cr(UINT8 newcr); + void check_dma_complete(); + void do_tx(); + bool mcast_ck(const UINT8 *buf, int len); + void check_irq() { m_irq_cb((m_regs.imr & m_regs.isr & 0x7f)?ASSERT_LINE:CLEAR_LINE); } + void recv_overflow(); + void stop(); + void recv(UINT8 *buf, int len); + + int m_reset; + bool m_cs; + int m_rdma_active; + + struct { + UINT8 cr; + UINT16 clda; + UINT8 pstart; + UINT8 pstop; + UINT8 bnry; + UINT8 tsr; + UINT8 tpsr; + UINT8 ncr; + UINT8 fifo; + UINT16 tbcr; + UINT8 isr; + UINT16 crda; + UINT16 rsar; + UINT16 rbcr; + UINT8 rsr; + UINT8 rcr; + UINT8 cntr0; + UINT8 tcr; + UINT8 cntr1; + UINT8 dcr; + UINT8 cntr2; + UINT8 imr; + + UINT8 par[6]; + UINT8 curr; + UINT8 mar[8]; + + UINT8 rnpp; + UINT8 lnpp; + UINT16 ac; + } m_regs; + + struct { + UINT8 cr9346; + UINT8 bpage; + UINT8 config0; + UINT8 config1; + UINT8 config2; + UINT8 config3; + UINT8 config4; + UINT8 csnsav; + UINT8 intr; + } m_8019regs; +}; + +class rtl8019a_device : public dp8390_device +{ +public: + rtl8019a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class dp8390d_device : public dp8390_device +{ +public: + dp8390d_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +// device type definition +extern const device_type DP8390D; +extern const device_type RTL8019A; + +#endif diff --git a/src/devices/machine/ds1204.c b/src/devices/machine/ds1204.c new file mode 100644 index 00000000000..a35624a3c6a --- /dev/null +++ b/src/devices/machine/ds1204.c @@ -0,0 +1,375 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/* + * ds1204.c + * + * Electronic Key + * + */ + +#include +#include "emu.h" +#include "ds1204.h" + +#define VERBOSE_LEVEL ( 0 ) + +inline void ATTR_PRINTF( 3, 4 ) ds1204_device::verboselog( int n_level, const char *s_fmt, ... ) +{ + if( VERBOSE_LEVEL >= n_level ) + { + va_list v; + char buf[ 32768 ]; + va_start( v, s_fmt ); + vsprintf( buf, s_fmt, v ); + va_end( v ); + logerror( "%s: ds1204(%s) %s", machine().describe_context(), tag(), buf ); + } +} + +// device type definition +const device_type DS1204 = &device_creator; + +ds1204_device::ds1204_device( const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock ) + : device_t( mconfig, DS1204, "DS1204", tag, owner, clock, "ds1204", __FILE__ ), + device_nvram_interface(mconfig, *this), + m_rst( 0 ), + m_clk( 0 ), + m_dqw( 0 ) +{ +} + +void ds1204_device::device_start() +{ + new_state( STATE_STOP ); + m_dqr = DQ_HIGH_IMPEDANCE; + + memset( m_command, 0, sizeof( m_command ) ); + memset( m_compare_register, 0, sizeof( m_compare_register ) ); + + save_item( NAME( m_rst ) ); + save_item( NAME( m_clk ) ); + save_item( NAME( m_dqw ) ); + save_item( NAME( m_dqr ) ); + save_item( NAME( m_state ) ); + save_item( NAME( m_bit ) ); + save_item( NAME( m_command ) ); + save_item( NAME( m_compare_register ) ); + save_item( NAME( m_unique_pattern ) ); + save_item( NAME( m_identification ) ); + save_item( NAME( m_security_match ) ); + save_item( NAME( m_secure_memory ) ); +} + +void ds1204_device::nvram_default() +{ + memset( m_unique_pattern, 0, sizeof( m_unique_pattern ) ); + memset( m_identification, 0, sizeof( m_identification ) ); + memset( m_security_match, 0, sizeof( m_security_match ) ); + memset( m_secure_memory, 0, sizeof( m_secure_memory ) ); + + int expected_bytes = sizeof( m_unique_pattern ) + sizeof( m_identification ) + sizeof( m_security_match ) + sizeof( m_secure_memory ); + + if( !m_region ) + { + logerror( "ds1204(%s) region not found\n", tag() ); + } + else if( m_region->bytes() != expected_bytes ) + { + logerror( "ds1204(%s) region length 0x%x expected 0x%x\n", tag(), m_region->bytes(), expected_bytes ); + } + else + { + UINT8 *region = m_region->base(); + + memcpy( m_unique_pattern, region, sizeof( m_unique_pattern ) ); region += sizeof( m_unique_pattern ); + memcpy( m_identification, region, sizeof( m_identification ) ); region += sizeof( m_identification ); + memcpy( m_security_match, region, sizeof( m_security_match ) ); region += sizeof( m_security_match ); + memcpy( m_secure_memory, region, sizeof( m_secure_memory ) ); region += sizeof( m_secure_memory ); + } +} + +void ds1204_device::nvram_read( emu_file &file ) +{ + file.read( m_unique_pattern, sizeof( m_unique_pattern ) ); + file.read( m_identification, sizeof( m_identification ) ); + file.read( m_security_match, sizeof( m_security_match ) ); + file.read( m_secure_memory, sizeof( m_secure_memory ) ); +} + +void ds1204_device::nvram_write( emu_file &file ) +{ + file.write( m_unique_pattern, sizeof( m_unique_pattern ) ); + file.write( m_identification, sizeof( m_identification ) ); + file.write( m_security_match, sizeof( m_security_match ) ); + file.write( m_secure_memory, sizeof( m_secure_memory ) ); +} + +void ds1204_device::new_state( int state ) +{ + m_state = state; + m_bit = 0; +} + +void ds1204_device::writebit( UINT8 *buffer ) +{ + if( m_clk ) + { + int index = m_bit / 8; + int mask = 1 << ( m_bit % 8 ); + + if( m_dqw ) + { + buffer[ index ] |= mask; + } + else + { + buffer[ index ] &= ~mask; + } + + m_bit++; + } +} + +void ds1204_device::readbit( UINT8 *buffer ) +{ + if( !m_clk ) + { + int index = m_bit / 8; + int mask = 1 << ( m_bit % 8 ); + + if( buffer[ index ] & mask ) + { + m_dqr = 1; + } + else + { + m_dqr = 0; + } + } + else + { + m_bit++; + } +} + +WRITE_LINE_MEMBER( ds1204_device::write_rst ) +{ + if( m_rst != state ) + { + m_rst = state; + verboselog( 2, "rst=%d\n", m_rst ); + + if( m_rst ) + { + new_state( STATE_PROTOCOL ); + } + else + { + switch( m_state ) + { + case STATE_WRITE_IDENTIFICATION: + verboselog( 0, "reset during write identification (bit=%d)\n", m_bit ); + break; + case STATE_WRITE_SECURITY_MATCH: + verboselog( 0, "reset during write security match (bit=%d)\n", m_bit ); + break; + case STATE_WRITE_SECURE_MEMORY: + verboselog( 0, "reset during write secure memory (bit=%d)\n", m_bit ); + break; + } + + new_state( STATE_STOP ); + m_dqr = DQ_HIGH_IMPEDANCE; + } + } +} + +WRITE_LINE_MEMBER( ds1204_device::write_clk ) +{ + if( m_clk != state ) + { + m_clk = state; + verboselog( 2, "clk=%d (bit=%d)\n", m_clk, m_bit ); + + if( m_clk ) + { + m_dqr = DQ_HIGH_IMPEDANCE; + } + + switch( m_state ) + { + case STATE_PROTOCOL: + writebit( m_command ); + + if( m_bit == 24 ) + { + verboselog( 1, "-> command %02x %02x %02x (%02x %02x)\n", + m_command[ 0 ], m_command[ 1 ], m_command[ 2 ], m_unique_pattern[ 0 ], m_unique_pattern[ 1 ] ); + + if( m_command[ 0 ] == COMMAND_READ && m_command[ 1 ] == ( m_unique_pattern[ 0 ] | CYCLE_NORMAL ) && m_command[ 2 ] == m_unique_pattern[ 1 ] ) + { + new_state( STATE_READ_IDENTIFICATION ); + } + else if( m_command[ 0 ] == COMMAND_WRITE && m_command[ 1 ] == ( m_unique_pattern[ 0 ] | CYCLE_NORMAL ) && m_command[ 2 ] == m_unique_pattern[ 1 ] ) + { + new_state( STATE_READ_IDENTIFICATION ); + } + else if( m_command[ 0 ] == COMMAND_WRITE && m_command[ 1 ] == ( m_unique_pattern[ 0 ] | CYCLE_PROGRAM ) && m_command[ 2 ] == m_unique_pattern[ 1 ] ) + { + new_state( STATE_WRITE_IDENTIFICATION ); + } + else + { + new_state( STATE_STOP ); + } + } + break; + + case STATE_READ_IDENTIFICATION: + readbit( m_identification ); + + if( m_bit == 64 ) + { + verboselog( 1, "<- identification %02x %02x %02x %02x %02x %02x %02x %02x\n", + m_identification[ 0 ], m_identification[ 1 ], m_identification[ 2 ], m_identification[ 3 ], + m_identification[ 4 ], m_identification[ 5 ], m_identification[ 6 ], m_identification[ 7 ] ); + + new_state( STATE_WRITE_COMPARE_REGISTER ); + } + break; + + case STATE_WRITE_COMPARE_REGISTER: + writebit( m_compare_register ); + + if( m_bit == 64 ) + { + verboselog( 1, "-> compare register %02x %02x %02x %02x %02x %02x %02x %02x (%02x %02x %02x %02x %02x %02x %02x %02x)\n", + m_compare_register[ 0 ], m_compare_register[ 1 ], m_compare_register[ 2 ], m_compare_register[ 3 ], + m_compare_register[ 4 ], m_compare_register[ 5 ], m_compare_register[ 6 ], m_compare_register[ 7 ], + m_security_match[ 0 ], m_security_match[ 1 ], m_security_match[ 2 ], m_security_match[ 3 ], + m_security_match[ 4 ], m_security_match[ 5 ], m_security_match[ 6 ], m_security_match[ 7 ] ); + + if( memcmp( m_compare_register, m_security_match, sizeof( m_compare_register ) ) == 0 ) + { + if( m_command[ 0 ] == COMMAND_READ ) + { + new_state( STATE_READ_SECURE_MEMORY ); + } + else + { + new_state( STATE_WRITE_SECURE_MEMORY ); + } + } + else + { + new_state( STATE_OUTPUT_GARBLED_DATA ); + } + } + break; + + case STATE_READ_SECURE_MEMORY: + readbit( m_secure_memory ); + + if( m_bit == 128 ) + { + verboselog( 1, "<- secure memory %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", + m_secure_memory[ 0 ], m_secure_memory[ 1 ], m_secure_memory[ 2 ], m_secure_memory[ 3 ], + m_secure_memory[ 4 ], m_secure_memory[ 5 ], m_secure_memory[ 6 ], m_secure_memory[ 7 ], + m_secure_memory[ 8 ], m_secure_memory[ 9 ], m_secure_memory[ 10 ], m_secure_memory[ 11 ], + m_secure_memory[ 12 ], m_secure_memory[ 13 ], m_secure_memory[ 14 ], m_secure_memory[ 15 ] ); + + new_state( STATE_STOP ); + } + break; + + case STATE_WRITE_SECURE_MEMORY: + writebit( m_secure_memory ); + + if( m_bit == 128 ) + { + verboselog( 1, "-> secure memory %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", + m_secure_memory[ 0 ], m_secure_memory[ 1 ], m_secure_memory[ 2 ], m_secure_memory[ 3 ], + m_secure_memory[ 4 ], m_secure_memory[ 5 ], m_secure_memory[ 6 ], m_secure_memory[ 7 ], + m_secure_memory[ 8 ], m_secure_memory[ 9 ], m_secure_memory[ 10 ], m_secure_memory[ 11 ], + m_secure_memory[ 12 ], m_secure_memory[ 13 ], m_secure_memory[ 14 ], m_secure_memory[ 15 ] ); + + new_state( STATE_STOP ); + } + break; + + case STATE_WRITE_IDENTIFICATION: + writebit( m_identification ); + + if( m_bit == 64 ) + { + verboselog( 1, "-> identification %02x %02x %02x %02x %02x %02x %02x %02x\n", + m_identification[ 0 ], m_identification[ 1 ], m_identification[ 2 ], m_identification[ 3 ], + m_identification[ 4 ], m_identification[ 5 ], m_identification[ 6 ], m_identification[ 7 ] ); + + new_state( STATE_WRITE_SECURITY_MATCH ); + } + break; + + case STATE_WRITE_SECURITY_MATCH: + writebit( m_security_match ); + + if( m_bit == 64 ) + { + verboselog( 1, ">- security match %02x %02x %02x %02x %02x %02x %02x %02x\n", + m_security_match[ 0 ], m_security_match[ 1 ], m_security_match[ 2 ], m_security_match[ 3 ], + m_security_match[ 4 ], m_security_match[ 5 ], m_security_match[ 6 ], m_security_match[ 7 ] ); + + new_state( STATE_STOP ); + } + break; + + case STATE_OUTPUT_GARBLED_DATA: + if( !m_clk && m_command[ 0 ] == COMMAND_READ ) + { + m_dqr = machine().rand() & 1; + m_bit++; + } + else if( m_clk && m_command[ 0 ] == COMMAND_WRITE ) + { + m_bit++; + } + + if( m_bit == 64 ) + { + if( m_command[ 0 ] == COMMAND_READ ) + { + verboselog( 1, "<- random\n" ); + } + else + { + verboselog( 1, "-> ignore\n" ); + } + + new_state( STATE_STOP ); + } + break; + } + } +} + +WRITE_LINE_MEMBER( ds1204_device::write_dq ) +{ + if( m_dqw != state ) + { + m_dqw = state; + + verboselog( 2, "dqw=%d\n", m_dqw ); + } +} + +READ_LINE_MEMBER( ds1204_device::read_dq ) +{ + if( m_dqr == DQ_HIGH_IMPEDANCE ) + { + verboselog( 2, "dqr=high impedance\n" ); + return 0; + } + + verboselog( 2, "dqr=%d (bit=%d)\n", m_dqr, m_bit ); + return m_dqr; +} diff --git a/src/devices/machine/ds1204.h b/src/devices/machine/ds1204.h new file mode 100644 index 00000000000..7c8f1727c37 --- /dev/null +++ b/src/devices/machine/ds1204.h @@ -0,0 +1,93 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/* + * ds1204.h + * + * Electronic Key + * + */ + +#pragma once + +#ifndef __DS1204_H__ +#define __DS1204_H__ + +#include "emu.h" + +#define MCFG_DS1204_ADD( _tag ) \ + MCFG_DEVICE_ADD( _tag, DS1204, 0 ) + +class ds1204_device : public device_t, + public device_nvram_interface +{ +public: + // construction/destruction + ds1204_device( const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock ); + + DECLARE_WRITE_LINE_MEMBER( write_rst ); + DECLARE_WRITE_LINE_MEMBER( write_clk ); + DECLARE_WRITE_LINE_MEMBER( write_dq ); + DECLARE_READ_LINE_MEMBER( read_dq ); + +protected: + // device-level overrides + virtual void device_start(); + + // device_nvram_interface overrides + virtual void nvram_default(); + virtual void nvram_read( emu_file &file ); + virtual void nvram_write( emu_file &file ); + +private: + inline void ATTR_PRINTF( 3, 4 ) verboselog( int n_level, const char *s_fmt, ... ); + void new_state(int state); + void writebit(UINT8 *buffer); + void readbit(UINT8 *buffer); + + enum state_t + { + STATE_STOP, + STATE_PROTOCOL, + STATE_READ_IDENTIFICATION, + STATE_WRITE_IDENTIFICATION, + STATE_WRITE_COMPARE_REGISTER, + STATE_WRITE_SECURITY_MATCH, + STATE_READ_SECURE_MEMORY, + STATE_WRITE_SECURE_MEMORY, + STATE_OUTPUT_GARBLED_DATA + }; + + enum command_t + { + COMMAND_READ = 0x62, + COMMAND_WRITE = 0x9d + }; + + enum cycle_t + { + CYCLE_NORMAL = 1, + CYCLE_PROGRAM = 2, + CYCLE_MASK = 3 + }; + + static const int DQ_HIGH_IMPEDANCE = -1; + + int m_rst; + int m_clk; + int m_dqw; + int m_dqr; + int m_state; + int m_bit; + UINT8 m_command[3]; + UINT8 m_compare_register[8]; + UINT8 m_unique_pattern[2]; + UINT8 m_identification[8]; + UINT8 m_security_match[8]; + UINT8 m_secure_memory[16]; +}; + + +// device type definition +extern const device_type DS1204; + +#endif diff --git a/src/devices/machine/ds128x.c b/src/devices/machine/ds128x.c new file mode 100644 index 00000000000..5b7fa8e0663 --- /dev/null +++ b/src/devices/machine/ds128x.c @@ -0,0 +1,16 @@ +// license:BSD-3-Clause +// copyright-holders:smf +#include "ds128x.h" + +/// TODO: Only DV2/DV1/DV0 == 0/1/0 is supported as the chip only has a 15 stage divider and not 22. + +const device_type DS12885 = &device_creator; + +//------------------------------------------------- +// ds12885_device - constructor +//------------------------------------------------- + +ds12885_device::ds12885_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : mc146818_device(mconfig, DS12885, "DS12885", tag, owner, clock, "ds12885", __FILE__) +{ +} diff --git a/src/devices/machine/ds128x.h b/src/devices/machine/ds128x.h new file mode 100644 index 00000000000..d07e785340f --- /dev/null +++ b/src/devices/machine/ds128x.h @@ -0,0 +1,26 @@ +// license:BSD-3-Clause +// copyright-holders:smf +#ifndef __DS128X_H__ +#define __DS128X_H__ + +#include "mc146818.h" + +#define MCFG_DS12885_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, DS12885, XTAL_32_768kHz) + +// ======================> mc146818_device + +class ds12885_device : public mc146818_device +{ +public: + // construction/destruction + ds12885_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual int data_size() { return 128; } +}; + +// device type definition +extern const device_type DS12885; + +#endif diff --git a/src/devices/machine/ds1302.c b/src/devices/machine/ds1302.c new file mode 100644 index 00000000000..c254690cae0 --- /dev/null +++ b/src/devices/machine/ds1302.c @@ -0,0 +1,413 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Dallas DS1302 Trickle-Charge Timekeeping Chip emulation + +**********************************************************************/ + +/* + + TODO: + + - 12 hour format + - synchronize user buffers on falling edge of CE after write + +*/ + +#include "ds1302.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define LOG 0 + + +#define RAM_SIZE 0x1f // 31 bytes + + +enum +{ + STATE_COMMAND, + STATE_INPUT, + STATE_OUTPUT +}; + +enum +{ + REGISTER_SECONDS = 0, + REGISTER_MINUTES, + REGISTER_HOUR, + REGISTER_DATE, + REGISTER_MONTH, + REGISTER_DAY, + REGISTER_YEAR, + REGISTER_CONTROL, + REGISTER_TRICKLE +}; + + +#define COMMAND_READ (m_cmd & 0x01) +#define COMMAND_RAM (m_cmd & 0x40) +#define COMMAND_VALID (m_cmd & 0x80) +#define COMMAND_BURST (((m_cmd >> 1) & 0x1f) == 0x1f) +#define CLOCK_HALT (m_reg[REGISTER_SECONDS] & 0x80) +#define WRITE_PROTECT (m_reg[REGISTER_CONTROL] & 0x80) +#define BURST_END (COMMAND_RAM ? 0x1f : 0x09) + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +// device type definition +const device_type DS1302 = &device_creator; + + +//------------------------------------------------- +// ds1302_device - constructor +//------------------------------------------------- + +ds1302_device::ds1302_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, DS1302, "DS1302", tag, owner, clock, "ds1302", __FILE__), + device_rtc_interface(mconfig, *this), + device_nvram_interface(mconfig, *this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void ds1302_device::device_start() +{ + // allocate timers + m_clock_timer = timer_alloc(); + m_clock_timer->adjust(attotime::from_hz(clock() / 32768), 0, attotime::from_hz(clock() / 32768)); + + for (int i = 0; i < 9; i++) + m_reg[i] = 0; + + // state saving + save_item(NAME(m_ce)); + save_item(NAME(m_clk)); + save_item(NAME(m_io)); + save_item(NAME(m_state)); + save_item(NAME(m_bits)); + save_item(NAME(m_cmd)); + save_item(NAME(m_data)); + save_item(NAME(m_addr)); + save_item(NAME(m_reg)); + save_item(NAME(m_user)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void ds1302_device::device_reset() +{ + set_current_time(machine()); + + m_clk = 0; + m_ce = 0; + m_state = STATE_COMMAND; + m_bits = 0; + m_cmd = 0; +} + + +//------------------------------------------------- +// device_timer - handler timer events +//------------------------------------------------- + +void ds1302_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + if (!CLOCK_HALT) + { + advance_seconds(); + } +} + + +//------------------------------------------------- +// nvram_default - called to initialize NVRAM to +// its default state +//------------------------------------------------- + +void ds1302_device::nvram_default() +{ + memset(m_ram, 0, RAM_SIZE); +} + + +//------------------------------------------------- +// nvram_read - called to read NVRAM from the +// .nv file +//------------------------------------------------- + +void ds1302_device::nvram_read(emu_file &file) +{ + file.read(m_ram, RAM_SIZE); +} + + +//------------------------------------------------- +// nvram_write - called to write NVRAM to the +// .nv file +//------------------------------------------------- + +void ds1302_device::nvram_write(emu_file &file) +{ + file.write(m_ram, RAM_SIZE); +} + + +//------------------------------------------------- +// rtc_clock_updated - +//------------------------------------------------- + +void ds1302_device::rtc_clock_updated(int year, int month, int day, int day_of_week, int hour, int minute, int second) +{ + m_reg[REGISTER_YEAR] = convert_to_bcd(year); + m_reg[REGISTER_DAY] = day_of_week; + m_reg[REGISTER_MONTH] = convert_to_bcd(month); + m_reg[REGISTER_DATE] = convert_to_bcd(day); + m_reg[REGISTER_HOUR] = convert_to_bcd(hour); + m_reg[REGISTER_MINUTES] = convert_to_bcd(minute); + m_reg[REGISTER_SECONDS] = (m_reg[REGISTER_SECONDS] & 0x80) | convert_to_bcd(second); +} + + +//------------------------------------------------- +// ce_w - chip enable write +//------------------------------------------------- + +WRITE_LINE_MEMBER( ds1302_device::ce_w ) +{ + if (LOG) logerror("DS1302 '%s' CE: %u\n", tag(), state); + + if (!state && m_ce) + { + // synchronize user buffers + for (int i = 0; i < 9; i++) + { + m_user[i] = m_reg[i]; + } + } + else if (state && !m_ce) + { + // terminate data transfer + m_state = STATE_COMMAND; + m_bits = 0; + } + + m_ce = state; +} + + +//------------------------------------------------- +// load_shift_register - +//------------------------------------------------- + +void ds1302_device::load_shift_register() +{ + if (COMMAND_READ) + { + if (COMMAND_RAM) + { + m_data = m_ram[m_addr]; + + if (LOG) logerror("DS1302 '%s' Read RAM %u:%02x\n", tag(), m_addr, m_data); + } + else + { + m_data = m_user[m_addr]; + + if (LOG) logerror("DS1302 '%s' Read Clock %u:%02x\n", tag(), m_addr, m_data); + } + } + else + { + if (COMMAND_RAM) + { + if (LOG) logerror("DS1302 '%s' Write RAM %u:%02x\n", tag(), m_addr, m_data); + + m_ram[m_addr] = m_data; + } + else if (m_addr < 9) + { + if (LOG) logerror("DS1302 '%s' Write Clock %u:%02x\n", tag(), m_addr, m_data); + + m_reg[m_addr] = m_data; + } + } +} + + +//------------------------------------------------- +// input_bit - +//------------------------------------------------- + +void ds1302_device::input_bit() +{ + switch (m_state) + { + case STATE_COMMAND: + m_cmd >>= 1; + m_cmd |= (m_io << 7); + m_bits++; + + if (m_bits == 8) + { + if (LOG) logerror("DS1302 '%s' Command: %02x\n", tag(), m_cmd); + + m_bits = 0; + m_addr = (m_cmd >> 1) & 0x1f; + + if (COMMAND_VALID) + { + if (COMMAND_BURST) + { + m_addr = 0; + } + + if (COMMAND_READ) + { + load_shift_register(); + + m_state = STATE_OUTPUT; + } + else + { + m_state = STATE_INPUT; + } + } + else + { + m_state = STATE_COMMAND; + } + } + break; + + case STATE_INPUT: + m_data >>= 1; + m_data |= (m_io << 7); + m_bits++; + + if (m_bits == 8) + { + if (LOG) logerror("DS1302 '%s' Data: %02x\n", tag(), m_data); + + m_bits = 0; + + if (!WRITE_PROTECT) + { + load_shift_register(); + } + + if (COMMAND_BURST) + { + m_addr++; + + if (m_addr == BURST_END) + { + m_state = STATE_COMMAND; + } + } + else + { + m_state = STATE_COMMAND; + } + } + break; + } +} + + +//------------------------------------------------- +// output_bit - +//------------------------------------------------- + +void ds1302_device::output_bit() +{ + if (m_state != STATE_OUTPUT) return; + + m_io = BIT(m_data, 0); + m_data >>= 1; + m_bits++; + + if (m_bits == 8) + { + m_bits = 0; + + if (COMMAND_BURST) + { + m_addr++; + + if (m_addr == BURST_END) + { + m_state = STATE_COMMAND; + } + else + { + load_shift_register(); + } + } + else + { + m_state = STATE_COMMAND; + } + } +} + + +//------------------------------------------------- +// sclk_w - serial clock write +//------------------------------------------------- + +WRITE_LINE_MEMBER( ds1302_device::sclk_w ) +{ + if (LOG) logerror("DS1302 '%s' CLK: %u\n", tag(), state); + + if (!m_ce) return; + + if (!m_clk && state) // rising edge + { + input_bit(); + } + else if (m_clk && !state) // falling edge + { + output_bit(); + } + + m_clk = state; +} + + +//------------------------------------------------- +// io_w - I/O write +//------------------------------------------------- + +WRITE_LINE_MEMBER( ds1302_device::io_w ) +{ + if (LOG) logerror("DS1302 '%s' I/O: %u\n", tag(), state); + + m_io = state; +} + + +//------------------------------------------------- +// io_r - I/O read +//------------------------------------------------- + +READ_LINE_MEMBER( ds1302_device::io_r ) +{ + return m_io; +} diff --git a/src/devices/machine/ds1302.h b/src/devices/machine/ds1302.h new file mode 100644 index 00000000000..15a6fad80c8 --- /dev/null +++ b/src/devices/machine/ds1302.h @@ -0,0 +1,96 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Dallas DS1302 Trickle-Charge Timekeeping Chip emulation + +********************************************************************** + _____ _____ + Vcc2 1 |* \_/ | 8 Vcc1 + X1 2 | | 7 SCLK + X2 3 | | 6 I/O + GND 4 |_____________| 5 CE + +**********************************************************************/ + +#pragma once + +#ifndef __DS1302_H__ +#define __DS1302_H__ + +#include "emu.h" + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_DS1302_ADD(_tag, _clock) \ + MCFG_DEVICE_ADD(_tag, DS1302, _clock) + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> ds1302_device + +class ds1302_device : public device_t, + public device_rtc_interface, + public device_nvram_interface +{ +public: + // construction/destruction + ds1302_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + DECLARE_WRITE_LINE_MEMBER( ce_w ); + DECLARE_WRITE_LINE_MEMBER( sclk_w ); + DECLARE_WRITE_LINE_MEMBER( io_w ); + DECLARE_READ_LINE_MEMBER( io_r ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + // device_nvram_interface overrides + virtual void nvram_default(); + virtual void nvram_read(emu_file &file); + virtual void nvram_write(emu_file &file); + + // device_rtc_interface overrides + virtual void rtc_clock_updated(int year, int month, int day, int day_of_week, int hour, int minute, int second); + virtual bool rtc_feature_leap_year() { return true; } + +private: + void load_shift_register(); + void input_bit(); + void output_bit(); + + int m_ce; + int m_clk; + int m_io; + int m_state; + int m_bits; + UINT8 m_cmd; + UINT8 m_data; + int m_addr; + + UINT8 m_reg[9]; + UINT8 m_user[9]; + UINT8 m_ram[0x20]; + + // timers + emu_timer *m_clock_timer; +}; + + +// device type definition +extern const device_type DS1302; + + + +#endif diff --git a/src/devices/machine/ds1315.c b/src/devices/machine/ds1315.c new file mode 100644 index 00000000000..8470aaaaf9c --- /dev/null +++ b/src/devices/machine/ds1315.c @@ -0,0 +1,277 @@ +// license:BSD-3-Clause +// copyright-holders:Tim Lindner +/***************************************************************************************** + + ds1315.c + + Dallas Semiconductor's Phantom Time Chip DS1315. + NOTE: writes are decoded, but the host's time will always be returned when asked. + + April 2015: chip enable / chip reset / phantom writes by Karl-Ludwig Deisenhofer + + November 2001: implementation by Tim Lindner + + HOW DOES IT WORK? + + READS: pattern recognition (64 bits in correct order). When RTC finally enables + 64 bits of data can be read. Chance of accidential pattern recognition is minimal. + + WRITES: two different locations (bits 0 and 1) are used to transfer data to the + DS1315. 64 bit with time/date info are transmitted directly after recognition + of the magic 64 bit pattern (see read above). + **************************************************************************************/ + +#include "ds1315.h" +#include "coreutil.h" + + +const device_type DS1315 = &device_creator; + +ds1315_device::ds1315_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, DS1315, "Dallas Semiconductor DS1315", tag, owner, clock, "ds1315", __FILE__) +{ +} + +//------------------------------------------------- +// device_config_complete - perform any +// operations now that the configuration is +// complete +//------------------------------------------------- + +void ds1315_device::device_config_complete() +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void ds1315_device::device_start() +{ + save_item(NAME(m_count)); + save_item(NAME(m_mode)); + save_item(NAME(m_raw_data)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void ds1315_device::device_reset() +{ + chip_reset(); +} + + + +/*************************************************************************** + LOCAL VARIABLES +***************************************************************************/ + +static const UINT8 ds1315_pattern[] = +{ + 1, 0, 1, 0, 0, 0, 1, 1, + 0, 1, 0, 1, 1, 1, 0, 0, + 1, 1, 0, 0, 0, 1, 0, 1, + 0, 0, 1, 1, 1, 0, 1, 0, + 1, 0, 1, 0, 0, 0, 1, 1, + 0, 1, 0, 1, 1, 1, 0, 0, + 1, 1, 0, 0, 0, 1, 0, 1, + 0, 0, 1, 1, 1, 0, 1, 0 +}; + + +/*************************************************************************** + IMPLEMENTATION +***************************************************************************/ + +/*------------------------------------------------- + read_0 (actual data) + -------------------------------------------------*/ + +READ8_MEMBER( ds1315_device::read_0 ) +{ + if (ds1315_pattern[m_count++] == 0) + { + if (m_count == 64) + { + /* entire pattern matched */ + m_count = 0; + m_mode = DS_CALENDAR_IO; + fill_raw_data(); + } + + return 0; + } + + m_count = 0; + m_mode = DS_SEEK_MATCHING; + return 0; +} + + +/*------------------------------------------------- + read_1 (actual data) +-------------------------------------------------*/ + +READ8_MEMBER( ds1315_device::read_1 ) +{ + if (ds1315_pattern[m_count++] == 1) + { + m_count %= 64; + return 0; + } + + m_count = 0; + m_mode = DS_SEEK_MATCHING; + return 0; +} + + +/*------------------------------------------------- + read_data +-------------------------------------------------*/ + +READ8_MEMBER( ds1315_device::read_data ) +{ + UINT8 result; + + if (m_mode == DS_CALENDAR_IO) + { + result = m_raw_data[m_count++]; + + if (m_count == 64) + { + m_mode = DS_SEEK_MATCHING; + m_count = 0; + } + + return result; + } + + m_count = 0; + return 0; +} + + +/*------------------------------------------------- + fill_raw_data +-------------------------------------------------*/ + +void ds1315_device::fill_raw_data() +{ + /* This routine calls a standard 'C' library routine to get the current + date and time and then fill in the raw data struct. + */ + + system_time systime; + int raw[8], i, j; + + /* get the current date/time from the core */ + machine().current_datetime(systime); + + raw[0] = 0; /* tenths and hundreths of seconds are always zero */ + raw[1] = dec_2_bcd(systime.local_time.second); + raw[2] = dec_2_bcd(systime.local_time.minute); + raw[3] = dec_2_bcd(systime.local_time.hour); + + raw[4] = dec_2_bcd((systime.local_time.weekday != 0) ? systime.local_time.weekday : 7); + raw[5] = dec_2_bcd(systime.local_time.mday); + raw[6] = dec_2_bcd(systime.local_time.month + 1); + raw[7] = dec_2_bcd(systime.local_time.year - 1900); /* Epoch is 1900 */ + + /* Ok now we have the raw bcd bytes. Now we need to push them into our bit array */ + + for (i = 0; i < 64; i++) + { + j = i / 8; + m_raw_data[i] = (raw[j] & 0x0001); + raw[j] = raw[j] >> 1; + } +} + + + + +/*------------------------------------------------- +write_data +-------------------------------------------------*/ + +READ8_MEMBER(ds1315_device::write_data) +{ + static int write_count; + if (write_count >= 64) + write_count = 0; + + if (m_mode == DS_CALENDAR_IO) + { + m_raw_data[write_count++] = offset & 0x01; + + if (write_count == 64) + { + write_count = 0; + + m_mode = DS_SEEK_MATCHING; + m_count = 0; + input_raw_data(); + } + } + return 0; // ignore +} + +/*------------------------------------------------- + ds1315_input_raw_data + + Routine is called when new date and time has + been written to the clock chip. Currently we + ignore setting the date and time in the clock + chip. +-------------------------------------------------*/ + +void ds1315_device::input_raw_data() +{ + int raw[8], i, j=0; + raw[0] = raw[1] = raw[2] = raw[3] = raw[4] = raw[5] = raw[6] = raw[7] = 0; + UINT8 flag = 1; + + for (i = 0; i < 64; i++) + { + j = i / 8; + if ((i % 8) == 0) + flag = 1; + + if (m_raw_data[i] & 1) + raw[j] |= flag; + flag <<= 1; + } + raw[0] = bcd_2_dec(raw[0]); // hundreds of seconds + raw[1] = bcd_2_dec(raw[1]); // seconds (often set to zero) + raw[2] = bcd_2_dec(raw[2]); // minute + raw[3] = bcd_2_dec(raw[3]); // hour + + raw[4] = bcd_2_dec(raw[4]); // weekday (10 for Friday ?!) + raw[5] = bcd_2_dec(raw[5]); // mday + raw[6] = bcd_2_dec(raw[6]); // month + raw[7] = bcd_2_dec(raw[7]); // year (two digits) + + printf("\nDS1315 RTC INPUT (WILL BE IGNORED) mm/dd/yy hh:mm:ss - %02d/%02d/%02d %02d/%02d/%02d", + raw[6], raw[5], raw[7], raw[3], raw[2], raw[1] + ); +} + +/*------------------------------------------------- + query and reset chip status + -------------------------------------------------*/ +bool ds1315_device::chip_enable() +{ + return (m_mode == DS_CALENDAR_IO); +} + +// Set a defined state (important for pattern detection) +void ds1315_device::chip_reset() +{ + memset(m_raw_data, 0, sizeof(m_raw_data)); + m_count = 0; + m_mode = DS_SEEK_MATCHING; +} diff --git a/src/devices/machine/ds1315.h b/src/devices/machine/ds1315.h new file mode 100644 index 00000000000..0d5a7abc802 --- /dev/null +++ b/src/devices/machine/ds1315.h @@ -0,0 +1,72 @@ +// license:BSD-3-Clause +// copyright-holders:Tim Lindner +/********************************************************************* + + ds1315.h + + Dallas Semiconductor's Phantom Time Chip DS1315. + + by tim lindner, November 2001. + +*********************************************************************/ + +#ifndef __DS1315_H__ +#define __DS1315_H__ + +#include "emu.h" + + +/*************************************************************************** + MACROS +***************************************************************************/ + +enum ds1315_mode_t +{ + DS_SEEK_MATCHING, + DS_CALENDAR_IO +}; + +ALLOW_SAVE_TYPE(ds1315_mode_t); + +class ds1315_device : public device_t +{ +public: + ds1315_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + ~ds1315_device() {} + + DECLARE_READ8_MEMBER(read_0); + DECLARE_READ8_MEMBER(read_1); + DECLARE_READ8_MEMBER(read_data); + DECLARE_READ8_MEMBER(write_data); + + bool chip_enable(); + void chip_reset(); + +protected: + // device-level overrides + virtual void device_config_complete(); + virtual void device_start(); + virtual void device_reset(); + +private: + // internal state + ds1315_mode_t m_mode; + + void fill_raw_data(); + void input_raw_data(); + + int m_count; + UINT8 m_raw_data[8*8]; +}; + +extern const device_type DS1315; + +/*************************************************************************** + DEVICE CONFIGURATION MACROS +***************************************************************************/ + +#define MCFG_DS1315_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, DS1315, 0) + + +#endif /* __DS1315_H__ */ diff --git a/src/devices/machine/ds2401.c b/src/devices/machine/ds2401.c new file mode 100644 index 00000000000..48182b2d2c3 --- /dev/null +++ b/src/devices/machine/ds2401.c @@ -0,0 +1,270 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/* + * DS2401 + * + * Dallas Semiconductor + * Silicon Serial Number + * + */ + +#include "emu.h" +#include "machine/ds2401.h" + +#define VERBOSE_LEVEL 0 + +inline void ds2401_device::verboselog(int n_level, const char *s_fmt, ...) +{ + if(VERBOSE_LEVEL >= n_level) + { + va_list v; + char buf[32768]; + va_start(v, s_fmt); + vsprintf(buf, s_fmt, v); + va_end(v); + logerror("ds2401 %s %s: %s", tag(), machine().describe_context(), buf); + } +} + +// device type definition +const device_type DS2401 = &device_creator; + +ds2401_device::ds2401_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, DS2401, "DS2401", tag, owner, clock, "ds2401", __FILE__) +{ +} + +void ds2401_device::device_start() +{ + t_samp = attotime::from_usec( 30); + t_rdv = attotime::from_usec( 30); + t_rstl = attotime::from_usec(480); + t_pdh = attotime::from_usec( 30); + t_pdl = attotime::from_usec(120); + + m_rx = true; + m_tx = true; + + save_item(NAME(m_state)); + save_item(NAME(m_bit)); + save_item(NAME(m_byte)); + save_item(NAME(m_shift)); + save_item(NAME(m_rx)); + save_item(NAME(m_tx)); + + m_timer_main = timer_alloc(TIMER_MAIN); + m_timer_reset = timer_alloc(TIMER_RESET); +} + +void ds2401_device::device_reset() +{ + m_state = STATE_IDLE; + m_bit = 0; + m_byte = 0; + m_shift = 0; + m_rx = true; + m_tx = true; + + if(m_region) + { + if(m_region->bytes() == SIZE_DATA) + { + memcpy(m_data, m_region->base(), SIZE_DATA); + return; + } + + logerror("ds2401 %s: Wrong region length for id data, expected 0x%x, got 0x%x\n", tag(), SIZE_DATA, m_region->bytes()); + } + else + { + logerror("ds2401 %s: Warning, no id provided, answer will be all zeroes.\n", tag()); + } + + memset(m_data, 0, SIZE_DATA); +} + +void ds2401_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch(id) + { + case TIMER_RESET: + verboselog(1, "timer_reset\n"); + m_state = STATE_RESET; + m_timer_reset->adjust(attotime::never); + break; + + case TIMER_MAIN: + switch(m_state) + { + case STATE_RESET1: + verboselog(2, "timer_main state_reset1 %d\n", m_rx); + m_tx = false; + m_state = STATE_RESET2; + m_timer_main->adjust(t_pdl); + break; + + case STATE_RESET2: + verboselog(2, "timer_main state_reset2 %d\n", m_rx); + m_tx = true; + m_bit = 0; + m_shift = 0; + m_state = STATE_COMMAND; + break; + + case STATE_COMMAND: + verboselog(2, "timer_main state_command %d\n", m_rx); + + m_shift >>= 1; + if(m_rx) + { + m_shift |= 0x80; + } + + m_bit++; + if(m_bit == 8) + { + switch(m_shift) + { + case COMMAND_READROM: + verboselog(1, "timer_main readrom\n"); + m_bit = 0; + m_byte = 0; + m_state = STATE_READROM; + break; + + default: + verboselog(0, "timer_main command not handled %02x\n", m_shift); + m_state = STATE_IDLE; + break; + } + } + break; + + case STATE_READROM: + m_tx = true; + + if( m_byte == SIZE_DATA ) + { + verboselog(1, "timer_main readrom finished\n"); + m_state = STATE_IDLE; + } + else + { + verboselog(2, "timer_main readrom window closed\n"); + } + break; + default: + verboselog(0, "timer_main state not handled: %d\n", m_state); + break; + } + } +} + +WRITE_LINE_MEMBER( ds2401_device::write ) +{ + verboselog(1, "write(%d)\n", state); + + if(!state && m_rx) + { + switch(m_state) + { + case STATE_IDLE: + break; + + case STATE_COMMAND: + verboselog(2, "state_command\n"); + m_timer_main->adjust(t_samp); + break; + + case STATE_READROM: + if(!m_bit) + { + m_shift = m_data[7 - m_byte]; + verboselog(1, "<- data %02x\n", m_shift); + } + + m_tx = m_shift & 1; + m_shift >>= 1; + + m_bit++; + if(m_bit == 8) + { + m_bit = 0; + m_byte++; + } + + verboselog(2, "state_readrom %d\n", m_tx); + m_timer_main->adjust(t_rdv); + break; + + default: + verboselog(0, "state not handled: %d\n", m_state ); + break; + } + + m_timer_reset->adjust(t_rstl); + } + else if(state && !m_rx) + { + switch(m_state) + { + case STATE_RESET: + m_state = STATE_RESET1; + m_timer_main->adjust(t_pdh); + break; + } + + m_timer_reset->adjust(attotime::never); + } + + m_rx = state; +} + +READ_LINE_MEMBER( ds2401_device::read ) +{ + verboselog(2, "read %d\n", m_tx && m_rx); + return m_tx && m_rx; +} + +UINT8 ds2401_device::direct_read(int index) +{ + return m_data[index]; +} + +/* + +app74.pdf + +Under normal circumstances an ibutton will sample the line 30us after the falling edge of the start condition. +The internal time base of ibutton may deviate from its nominal value. The allowed tollerance band ranges from 15us to 60us. +This means that the actual slave sampling may occur anywhere from 15 and 60us after the start condition, which is a ratio of 1 to 4. +During this time frame the voltage on the data line must stay below Vilmax or above Vihmin. + +In the 1-Wire system, the logical values 1 and 0 are represented by certain voltages in special waveforms. +The waveforms needed to write commands or data to ibuttons are called write-1 and write-0 time slots. +The duration of a low pulse to write a 1 must be shorter than 15us. +To write a 0, the duration of the low pulse must be at least 60us to cope with worst-case conditions. + +The duration of the active part of a time slot can be extended beyond 60us. +The maximum extension is limited by the fact that a low pulse of a duration of at least eight active time slots ( 480us ) is defined as a Reset Pulse. +Allowing the same worst-case tolerance ratio, a low pulse of 120us might be sufficient for a reset. +This limits the extension of the active part of a time slot to a maximum of 120us to prevent misinterpretation with reset. + +Commands and data are sent to ibuttons by combining write-0 and write-1 time slots. +To read data, the master has to generate read-data time slots to define the start condition of each bit. +The read-data time slots looks essentially the same as a write-1 time slot from the masters point of view. +Starting at the high-to-low transition, the ibuttons sends 1 bit of its addressed contents. +If the data bit is a 1, the ibutton leaves the pulse unchanged. +If the data bit is a 0, the ibutton will pull the data line low for 15us. +In this time frame data is valid for reading by the master. +The duration of the low pulse sent by the master should be a minimum of 1us with a maximum value as short as possible to maximize the master sampling window. + +The Reset Pulse provides a clear starting condition that supersedes any time slot synchronisation. +It is defined as single low pulse of minimum duration of eight time slots or 480us followed by a Reset-high time tRSTH of another 480us. +After a Reset Pulse has been sent, the ibutton will wait for the time tPDH and then generate a Pulse-Presence Pulse of duration tPDL. +No other communication on the 1-Wire bus is allowed during tRSTH. + +There are 1,000 microseconds in a millisecond, and 1,000 milliseconds in a second. +Thus, there are 1,000,000 microseconds in a second. Why is it "usec"? +The "u" is supposed to look like the Greek letter Mu that we use for "micro". . +*/ diff --git a/src/devices/machine/ds2401.h b/src/devices/machine/ds2401.h new file mode 100644 index 00000000000..b8b1148dc37 --- /dev/null +++ b/src/devices/machine/ds2401.h @@ -0,0 +1,71 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/* + * DS2401 + * + * Dallas Semiconductor + * Silicon Serial Number + * + */ + +#ifndef __DS2401_H__ +#define __DS2401_H__ + +#define MCFG_DS2401_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, DS2401, 0) + +#include "emu.h" + +class ds2401_device : public device_t +{ +public: + // construction/destruction + ds2401_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + DECLARE_WRITE_LINE_MEMBER( write ); + DECLARE_READ_LINE_MEMBER( read ); + UINT8 direct_read(int index); + +protected: + enum { + SIZE_DATA = 8, + + COMMAND_READROM = 0x33 + }; + + enum { + STATE_IDLE, + STATE_RESET, + STATE_RESET1, + STATE_RESET2, + STATE_COMMAND, + STATE_READROM + }; + + enum { + TIMER_MAIN, + TIMER_RESET + }; + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + // internal state + int m_state, m_bit, m_shift; + UINT8 m_byte; + bool m_rx, m_tx; + UINT8 m_data[SIZE_DATA]; + emu_timer *m_timer_main, *m_timer_reset; + attotime t_samp, t_rdv, t_rstl, t_pdh, t_pdl; + +private: + inline void verboselog(int n_level, const char *s_fmt, ...) ATTR_PRINTF(3,4); +}; + + +// device type definition +extern const device_type DS2401; + +#endif diff --git a/src/devices/machine/ds2404.c b/src/devices/machine/ds2404.c new file mode 100644 index 00000000000..57f8fa62d8f --- /dev/null +++ b/src/devices/machine/ds2404.c @@ -0,0 +1,405 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/********************************************************************** + + DALLAS DS2404 + + RTC + BACKUP RAM + +**********************************************************************/ + +#include "emu.h" +#include "ds2404.h" +#include + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +// device type definition +const device_type DS2404 = &device_creator; + +//------------------------------------------------- +// ds2404_device - constructor +//------------------------------------------------- + +ds2404_device::ds2404_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, DS2404, "DS2404", tag, owner, clock, "ds2404", __FILE__), + device_nvram_interface(mconfig, *this), + m_address(0), + m_offset(0), + m_end_offset(0), + m_a1(0), + m_a2(0), + m_state_ptr(0) +{ + memset(m_ram, 0, sizeof(m_ram)); +} + + +//------------------------------------------------- +// static_set_ref_year - configuration helper +// to set the reference year +//------------------------------------------------- + +void ds2404_device::static_set_ref_year(device_t &device, UINT32 year) +{ + ds2404_device &ds2404 = downcast(device); + ds2404.m_ref_year = year; +} + + +//------------------------------------------------- +// static_set_ref_month - configuration helper +// to set the reference month +//------------------------------------------------- + +void ds2404_device::static_set_ref_month(device_t &device, UINT8 month) +{ + ds2404_device &ds2404 = downcast(device); + ds2404.m_ref_month = month; +} + + +//------------------------------------------------- +// static_set_ref_day - configuration helper +// to set the reference day +//------------------------------------------------- + +void ds2404_device::static_set_ref_day(device_t &device, UINT8 day) +{ + ds2404_device &ds2404 = downcast(device); + ds2404.m_ref_day = day; +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void ds2404_device::device_start() +{ + struct tm ref_tm; + + memset(&ref_tm, 0, sizeof(ref_tm)); + ref_tm.tm_year = m_ref_year - 1900; + ref_tm.tm_mon = m_ref_month - 1; + ref_tm.tm_mday = m_ref_day; + + time_t ref_time = mktime(&ref_tm); + + time_t current_time; + time(¤t_time); + current_time -= ref_time; + + m_rtc[0] = 0x0; + m_rtc[1] = (current_time >> 0) & 0xff; + m_rtc[2] = (current_time >> 8) & 0xff; + m_rtc[3] = (current_time >> 16) & 0xff; + m_rtc[4] = (current_time >> 24) & 0xff; + + for (int i = 0; i < 8; i++) + m_state[i] = DS2404_STATE_IDLE; + + m_tick_timer = timer_alloc(0); + m_tick_timer->adjust(attotime::from_hz(256), 0, attotime::from_hz(256)); +} + + +void ds2404_device::ds2404_rom_cmd(UINT8 cmd) +{ + switch(cmd) + { + case 0xcc: /* Skip ROM */ + m_state[0] = DS2404_STATE_COMMAND; + m_state_ptr = 0; + break; + + default: + fatalerror("DS2404: Unknown ROM command %02X\n", cmd); + } +} + +void ds2404_device::ds2404_cmd(UINT8 cmd) +{ + switch(cmd) + { + case 0x0f: /* Write scratchpad */ + m_state[0] = DS2404_STATE_ADDRESS1; + m_state[1] = DS2404_STATE_ADDRESS2; + m_state[2] = DS2404_STATE_INIT_COMMAND; + m_state[3] = DS2404_STATE_WRITE_SCRATCHPAD; + m_state_ptr = 0; + break; + + case 0x55: /* Copy scratchpad */ + m_state[0] = DS2404_STATE_ADDRESS1; + m_state[1] = DS2404_STATE_ADDRESS2; + m_state[2] = DS2404_STATE_OFFSET; + m_state[3] = DS2404_STATE_INIT_COMMAND; + m_state[4] = DS2404_STATE_COPY_SCRATCHPAD; + m_state_ptr = 0; + break; + + case 0xf0: /* Read memory */ + m_state[0] = DS2404_STATE_ADDRESS1; + m_state[1] = DS2404_STATE_ADDRESS2; + m_state[2] = DS2404_STATE_INIT_COMMAND; + m_state[3] = DS2404_STATE_READ_MEMORY; + m_state_ptr = 0; + break; + + default: + fatalerror("DS2404: Unknown command %02X\n", cmd); + } +} + +UINT8 ds2404_device::ds2404_readmem() +{ + if( m_address < 0x200 ) + { + return m_sram[ m_address ]; + } + else if( m_address >= 0x202 && m_address <= 0x206 ) + { + return m_rtc[ m_address - 0x202 ]; + } + return 0; +} + +void ds2404_device::ds2404_writemem(UINT8 value) +{ + if( m_address < 0x200 ) + { + m_sram[ m_address ] = value; + } + else if( m_address >= 0x202 && m_address <= 0x206 ) + { + m_rtc[ m_address - 0x202 ] = value; + } +} + +WRITE8_MEMBER( ds2404_device::ds2404_1w_reset_w ) +{ + m_state[0] = DS2404_STATE_IDLE; + m_state_ptr = 0; +} + +WRITE8_MEMBER( ds2404_device::ds2404_3w_reset_w ) +{ + m_state[0] = DS2404_STATE_COMMAND; + m_state_ptr = 0; +} + +READ8_MEMBER( ds2404_device::ds2404_data_r ) +{ + UINT8 value = 0; + switch(m_state[m_state_ptr]) + { + case DS2404_STATE_IDLE: + case DS2404_STATE_COMMAND: + case DS2404_STATE_ADDRESS1: + case DS2404_STATE_ADDRESS2: + case DS2404_STATE_OFFSET: + case DS2404_STATE_INIT_COMMAND: + break; + + case DS2404_STATE_READ_MEMORY: + value = ds2404_readmem(); + break; + + case DS2404_STATE_READ_SCRATCHPAD: + if(m_offset < 0x20) + { + value = m_ram[m_offset]; + m_offset++; + } + break; + + case DS2404_STATE_WRITE_SCRATCHPAD: + break; + + case DS2404_STATE_COPY_SCRATCHPAD: + break; + } + return value; +} + +WRITE8_MEMBER( ds2404_device::ds2404_data_w ) +{ + switch( m_state[m_state_ptr] ) + { + case DS2404_STATE_IDLE: + ds2404_rom_cmd(data & 0xff); + break; + + case DS2404_STATE_COMMAND: + ds2404_cmd(data & 0xff); + break; + + case DS2404_STATE_ADDRESS1: + m_a1 = data & 0xff; + m_state_ptr++; + break; + + case DS2404_STATE_ADDRESS2: + m_a2 = data & 0xff; + m_state_ptr++; + break; + + case DS2404_STATE_OFFSET: + m_end_offset = data & 0xff; + m_state_ptr++; + break; + + case DS2404_STATE_INIT_COMMAND: + break; + + case DS2404_STATE_READ_MEMORY: + break; + + case DS2404_STATE_READ_SCRATCHPAD: + break; + + case DS2404_STATE_WRITE_SCRATCHPAD: + if( m_offset < 0x20 ) + { + m_ram[m_offset] = data & 0xff; + m_offset++; + } + else + { + /* Set OF flag */ + } + break; + + case DS2404_STATE_COPY_SCRATCHPAD: + break; + } + + if( m_state[m_state_ptr] == DS2404_STATE_INIT_COMMAND ) + { + switch( m_state[m_state_ptr + 1] ) + { + case DS2404_STATE_IDLE: + case DS2404_STATE_COMMAND: + case DS2404_STATE_ADDRESS1: + case DS2404_STATE_ADDRESS2: + case DS2404_STATE_OFFSET: + case DS2404_STATE_INIT_COMMAND: + break; + + case DS2404_STATE_READ_MEMORY: + m_address = (m_a2 << 8) | m_a1; + m_address -= 1; + break; + + case DS2404_STATE_WRITE_SCRATCHPAD: + m_address = (m_a2 << 8) | m_a1; + m_offset = m_address & 0x1f; + break; + + case DS2404_STATE_READ_SCRATCHPAD: + m_address = (m_a2 << 8) | m_a1; + m_offset = m_address & 0x1f; + break; + + case DS2404_STATE_COPY_SCRATCHPAD: + m_address = (m_a2 << 8) | m_a1; + + for(int i = 0; i <= m_end_offset; i++) + { + ds2404_writemem(m_ram[i]); + m_address++; + } + break; + } + m_state_ptr++; + } +} + +WRITE8_MEMBER( ds2404_device::ds2404_clk_w ) +{ + switch( m_state[m_state_ptr] ) + { + case DS2404_STATE_IDLE: + case DS2404_STATE_COMMAND: + case DS2404_STATE_ADDRESS1: + case DS2404_STATE_ADDRESS2: + case DS2404_STATE_OFFSET: + case DS2404_STATE_INIT_COMMAND: + break; + + case DS2404_STATE_READ_MEMORY: + m_address++; + break; + + case DS2404_STATE_READ_SCRATCHPAD: + break; + + case DS2404_STATE_WRITE_SCRATCHPAD: + break; + + case DS2404_STATE_COPY_SCRATCHPAD: + break; + } +} + +void ds2404_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch(id) + { + case 0: + { + // tick + for(int i = 0; i < 5; i++) + { + m_rtc[ i ]++; + if(m_rtc[ i ] != 0) + { + break; + } + } + + break; + } + + default: + assert_always(FALSE, "Unknown id in ds2404_device::device_timer"); + break; + } +} + + +//------------------------------------------------- +// nvram_default - called to initialize NVRAM to +// its default state +//------------------------------------------------- + +void ds2404_device::nvram_default() +{ + memset(m_sram, 0, sizeof(m_sram)); +} + + +//------------------------------------------------- +// nvram_read - called to read NVRAM from the +// .nv file +//------------------------------------------------- + +void ds2404_device::nvram_read(emu_file &file) +{ + file.read(m_sram, sizeof(m_sram)); +} + + +//------------------------------------------------- +// nvram_write - called to write NVRAM to the +// .nv file +//------------------------------------------------- + +void ds2404_device::nvram_write(emu_file &file) +{ + file.write(m_sram, sizeof(m_sram)); +} diff --git a/src/devices/machine/ds2404.h b/src/devices/machine/ds2404.h new file mode 100644 index 00000000000..31ff35a99a6 --- /dev/null +++ b/src/devices/machine/ds2404.h @@ -0,0 +1,129 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/********************************************************************** + + DALLAS DS2404 + + RTC + BACKUP RAM + +**********************************************************************/ + +#pragma once + +#ifndef __DS2404_H__ +#define __DS2404_H__ + +#include "emu.h" + + + +/*************************************************************************** + DEVICE CONFIGURATION MACROS +***************************************************************************/ + +#define MCFG_DS2404_ADD(_tag, _ref_year, _ref_month, _ref_day) \ + MCFG_DEVICE_ADD(_tag, DS2404, 0) \ + MCFG_DS2404_REF_YEAR(_ref_year) \ + MCFG_DS2404_REF_MONTH(_ref_month) \ + MCFG_DS2404_REF_DAY(_ref_day) + +#define MCFG_DS2404_REF_YEAR(_ref_year) \ + ds2404_device::static_set_ref_year(*device, _ref_year); + +#define MCFG_DS2404_REF_MONTH(_ref_month) \ + ds2404_device::static_set_ref_month(*device, _ref_month); + +#define MCFG_DS2404_REF_DAY(_ref_day) \ + ds2404_device::static_set_ref_day(*device, _ref_day); + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + + +// ======================> ds2404_device + +class ds2404_device : public device_t, + public device_nvram_interface +{ +public: + // construction/destruction + ds2404_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // inline configuration helpers + static void static_set_ref_year(device_t &device, UINT32 m_ref_year); + static void static_set_ref_month(device_t &device, UINT8 m_ref_month); + static void static_set_ref_day(device_t &device, UINT8 m_ref_day); + + /* 1-wire interface reset */ + DECLARE_WRITE8_MEMBER(ds2404_1w_reset_w); + + /* 3-wire interface reset */ + DECLARE_WRITE8_MEMBER(ds2404_3w_reset_w); + + DECLARE_READ8_MEMBER(ds2404_data_r); + DECLARE_WRITE8_MEMBER(ds2404_data_w); + DECLARE_WRITE8_MEMBER(ds2404_clk_w); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset() { } + virtual void device_post_load() { } + virtual void device_clock_changed() { } + + // device_nvram_interface overrides + virtual void nvram_default(); + virtual void nvram_read(emu_file &file); + virtual void nvram_write(emu_file &file); + + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + +private: + + void ds2404_rom_cmd(UINT8 cmd); + void ds2404_cmd(UINT8 cmd); + + UINT8 ds2404_readmem(); + void ds2404_writemem(UINT8 value); + + enum DS2404_STATE + { + DS2404_STATE_IDLE = 1, /* waiting for ROM command, in 1-wire mode */ + DS2404_STATE_COMMAND, /* waiting for memory command */ + DS2404_STATE_ADDRESS1, /* waiting for address bits 0-7 */ + DS2404_STATE_ADDRESS2, /* waiting for address bits 8-15 */ + DS2404_STATE_OFFSET, /* waiting for ending offset */ + DS2404_STATE_INIT_COMMAND, + DS2404_STATE_READ_MEMORY, /* Read Memory command active */ + DS2404_STATE_WRITE_SCRATCHPAD, /* Write Scratchpad command active */ + DS2404_STATE_READ_SCRATCHPAD, /* Read Scratchpad command active */ + DS2404_STATE_COPY_SCRATCHPAD /* Copy Scratchpad command active */ + }; + + emu_timer *m_tick_timer; + + // configuration state + UINT32 m_ref_year; + UINT8 m_ref_month; + UINT8 m_ref_day; + + UINT16 m_address; + UINT16 m_offset; + UINT16 m_end_offset; + UINT8 m_a1; + UINT8 m_a2; + UINT8 m_sram[512]; /* 4096 bits */ + UINT8 m_ram[32]; /* scratchpad ram, 256 bits */ + UINT8 m_rtc[5]; /* 40-bit RTC counter */ + DS2404_STATE m_state[8]; + int m_state_ptr; +}; + + +// device type definition +extern const device_type DS2404; + + +#endif /* __DS2404_H__ */ diff --git a/src/devices/machine/ds75160a.c b/src/devices/machine/ds75160a.c new file mode 100644 index 00000000000..1560fa4f0b2 --- /dev/null +++ b/src/devices/machine/ds75160a.c @@ -0,0 +1,111 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + National Semiconductor DS75160A IEEE-488 GPIB Transceiver emulation + +**********************************************************************/ + +#include "ds75160a.h" + + + +//************************************************************************** +// DEVICE TYPE DEFINITIONS +//************************************************************************** + +const device_type DS75160A = &device_creator; + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// ds75160a_device - constructor +//------------------------------------------------- + +ds75160a_device::ds75160a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, DS75160A, "DS75160A", tag, owner, clock, "ds75160a", __FILE__), + m_read(*this), + m_write(*this), + m_data(0xff), + m_te(0), + m_pe(0) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void ds75160a_device::device_start() +{ + // resolve callbacks + m_read.resolve_safe(0); + m_write.resolve_safe(); + + // register for state saving + save_item(NAME(m_data)); + save_item(NAME(m_te)); + save_item(NAME(m_pe)); +} + + +//------------------------------------------------- +// read - read data bus +//------------------------------------------------- + +READ8_MEMBER( ds75160a_device::read ) +{ + UINT8 data = 0; + + if (!m_te) + { + data = m_read(0); + } + + return data; +} + + +//------------------------------------------------- +// write - write data bus +//------------------------------------------------- + +WRITE8_MEMBER( ds75160a_device::write ) +{ + m_data = data; + + if (m_te) + { + m_write((offs_t)0, m_data); + } +} + + +//------------------------------------------------- +// te_w - transmit enable +//------------------------------------------------- + +WRITE_LINE_MEMBER( ds75160a_device::te_w ) +{ + if (m_te != state) + { + m_write((offs_t)0, m_te ? m_data : 0xff); + } + + m_te = state; +} + + +//------------------------------------------------- +// pe_w - parallel enable +//------------------------------------------------- + +WRITE_LINE_MEMBER( ds75160a_device::pe_w ) +{ + m_pe = state; +} diff --git a/src/devices/machine/ds75160a.h b/src/devices/machine/ds75160a.h new file mode 100644 index 00000000000..d3ca0b38de6 --- /dev/null +++ b/src/devices/machine/ds75160a.h @@ -0,0 +1,84 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + National Semiconductor DS75160A IEEE-488 GPIB Transceiver emulation + +********************************************************************** + _____ _____ + TE 1 |* \_/ | 20 Vcc + D1 2 | | 19 D1 + D2 3 | | 18 D2 + D3 4 | | 17 D3 + D4 5 | DS75160A | 16 D4 + D5 6 | | 15 D5 + D6 7 | | 14 D6 + D7 8 | | 13 D7 + D8 8 | | 12 D8 + GND 10 |_____________| 11 PE + +**********************************************************************/ + +#pragma once + +#ifndef __DS75160A__ +#define __DS75160A__ + +#include "emu.h" + + + +///************************************************************************* +// INTERFACE CONFIGURATION MACROS +///************************************************************************* + +#define MCFG_DS75160A_ADD(_tag, _read, _write) \ + MCFG_DEVICE_ADD(_tag, DS75160A, 0) \ + downcast(device)->set_callbacks(DEVCB_##_read, DEVCB_##_write); + + + +///************************************************************************* +// TYPE DEFINITIONS +///************************************************************************* + +// ======================> ds75160a_device + +class ds75160a_device : public device_t +{ +public: + // construction/destruction + ds75160a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + template void set_callbacks(_read rd, _write wr) { + m_read.set_callback(rd); + m_write.set_callback(wr); + } + + DECLARE_READ8_MEMBER( read ); + DECLARE_WRITE8_MEMBER( write ); + + DECLARE_WRITE_LINE_MEMBER( te_w ); + DECLARE_WRITE_LINE_MEMBER( pe_w ); + +protected: + // device-level overrides + virtual void device_start(); + +private: + devcb_read8 m_read; + devcb_write8 m_write; + + UINT8 m_data; + + int m_te; + int m_pe; +}; + + +// device type definition +extern const device_type DS75160A; + + + +#endif diff --git a/src/devices/machine/ds75161a.c b/src/devices/machine/ds75161a.c new file mode 100644 index 00000000000..5ec21a0e003 --- /dev/null +++ b/src/devices/machine/ds75161a.c @@ -0,0 +1,353 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + National Semiconductor DS75161A IEEE-488 GPIB Transceiver emulation + +**********************************************************************/ + +#include "ds75161a.h" + + + +//************************************************************************** +// DEVICE TYPE DEFINITIONS +//************************************************************************** + +const device_type DS75161A = &device_creator; + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// ds75161a_device - constructor +//------------------------------------------------- + +ds75161a_device::ds75161a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, DS75161A, "DS75161A", tag, owner, clock, "ds75161a", __FILE__), + m_in_ren_cb(*this), + m_in_ifc_cb(*this), + m_in_ndac_cb(*this), + m_in_nrfd_cb(*this), + m_in_dav_cb(*this), + m_in_eoi_cb(*this), + m_in_atn_cb(*this), + m_in_srq_cb(*this), + m_out_ren_cb(*this), + m_out_ifc_cb(*this), + m_out_ndac_cb(*this), + m_out_nrfd_cb(*this), + m_out_dav_cb(*this), + m_out_eoi_cb(*this), + m_out_atn_cb(*this), + m_out_srq_cb(*this), + m_ren(1), + m_ifc(1), + m_ndac(1), + m_nrfd(1), + m_dav(1), + m_eoi(1), + m_atn(1), + m_srq(1), + m_te(0), + m_dc(0) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void ds75161a_device::device_start() +{ + // resolve callbacks + m_in_ren_cb.resolve_safe(0); + m_in_ifc_cb.resolve_safe(0); + m_in_ndac_cb.resolve_safe(0); + m_in_nrfd_cb.resolve_safe(0); + m_in_dav_cb.resolve_safe(0); + m_in_eoi_cb.resolve_safe(0); + m_in_atn_cb.resolve_safe(0); + m_in_srq_cb.resolve_safe(0); + + m_out_ren_cb.resolve_safe(); + m_out_ifc_cb.resolve_safe(); + m_out_ndac_cb.resolve_safe(); + m_out_nrfd_cb.resolve_safe(); + m_out_dav_cb.resolve_safe(); + m_out_eoi_cb.resolve_safe(); + m_out_atn_cb.resolve_safe(); + m_out_srq_cb.resolve_safe(); + + // register for state saving + save_item(NAME(m_ren)); + save_item(NAME(m_ifc)); + save_item(NAME(m_ndac)); + save_item(NAME(m_nrfd)); + save_item(NAME(m_dav)); + save_item(NAME(m_eoi)); + save_item(NAME(m_atn)); + save_item(NAME(m_srq)); + save_item(NAME(m_te)); + save_item(NAME(m_dc)); +} + + +//------------------------------------------------- +// update_signals - +//------------------------------------------------- + +void ds75161a_device::update_signals() +{ + m_out_ren_cb(m_dc ? 1 : m_ren); + m_out_ifc_cb(m_dc ? 1 : m_ifc); + m_out_ndac_cb(m_te ? 1 : m_ndac); + m_out_nrfd_cb(m_te ? 1 : m_nrfd); + m_out_dav_cb(m_te ? m_dav : 1); + m_out_atn_cb(m_dc ? 1 : m_atn); + m_out_srq_cb(m_dc ? m_srq : 1 ); + + int atn = m_in_atn_cb(); + + if (m_te && atn) m_out_eoi_cb(m_eoi); + else if (!m_dc && !atn) m_out_eoi_cb(m_eoi); + else m_out_eoi_cb(1); +} + + +//------------------------------------------------- +// te_w - transmit enable +//------------------------------------------------- + +WRITE_LINE_MEMBER( ds75161a_device::te_w ) +{ + if (m_te != state) + { + m_te = state; + + update_signals(); + } +} + + +//------------------------------------------------- +// dc_w - direction control +//------------------------------------------------- + +WRITE_LINE_MEMBER( ds75161a_device::dc_w ) +{ + if (m_dc != state) + { + m_dc = state; + + update_signals(); + } +} + + +//------------------------------------------------- +// ren_r - remote enable read +//------------------------------------------------- + +READ_LINE_MEMBER( ds75161a_device::ren_r ) +{ + return m_dc ? m_in_ren_cb() : 0; +} + + +//------------------------------------------------- +// ifc_r - interface clear read +//------------------------------------------------- + +READ_LINE_MEMBER( ds75161a_device::ifc_r ) +{ + return m_dc ? m_in_ifc_cb() : 0; +} + + +//------------------------------------------------- +// ndac_r - not data acknowledge read +//------------------------------------------------- + +READ_LINE_MEMBER( ds75161a_device::ndac_r ) +{ + return m_te ? m_in_ndac_cb() : 0; +} + + +//------------------------------------------------- +// nrfd_r - not ready for data read +//------------------------------------------------- + +READ_LINE_MEMBER( ds75161a_device::nrfd_r ) +{ + return m_te ? m_in_nrfd_cb() : 0; +} + + +//------------------------------------------------- +// dav_r - data valid read +//------------------------------------------------- + +READ_LINE_MEMBER( ds75161a_device::dav_r ) +{ + return m_te ? 0 : m_in_dav_cb(); +} + + +//------------------------------------------------- +// eoi_r - end or identify read +//------------------------------------------------- + +READ_LINE_MEMBER( ds75161a_device::eoi_r ) +{ + int atn = m_in_atn_cb(); + int eoi = m_in_eoi_cb(); + + if (!m_te && atn) return eoi; + else if (m_dc && !atn) return eoi; + else return 0; +} + + +//------------------------------------------------- +// atn_r - attention read +//------------------------------------------------- + +READ_LINE_MEMBER( ds75161a_device::atn_r ) +{ + return m_dc ? m_in_atn_cb() : 0; +} + + +//------------------------------------------------- +// srq_r - service request read +//------------------------------------------------- + +READ_LINE_MEMBER( ds75161a_device::srq_r ) +{ + return m_dc ? 0 : m_in_srq_cb(); +} + + +//------------------------------------------------- +// ren_w - remote enable write +//------------------------------------------------- + +WRITE_LINE_MEMBER( ds75161a_device::ren_w ) +{ + if (m_ren != state) + { + m_ren = state; + + update_signals(); + } +} + + +//------------------------------------------------- +// ifc_w - interface clear write +//------------------------------------------------- + +WRITE_LINE_MEMBER( ds75161a_device::ifc_w ) +{ + if (m_ifc != state) + { + m_ifc = state; + + update_signals(); + } +} + + +//------------------------------------------------- +// ndac_w - not data acknowledge write +//------------------------------------------------- + +WRITE_LINE_MEMBER( ds75161a_device::ndac_w ) +{ + if (m_ndac != state) + { + m_ndac = state; + + update_signals(); + } +} + + +//------------------------------------------------- +// nrfd_w - not ready for data write +//------------------------------------------------- + +WRITE_LINE_MEMBER( ds75161a_device::nrfd_w ) +{ + if (m_nrfd != state) + { + m_nrfd = state; + + update_signals(); + } +} + + +//------------------------------------------------- +// dav_w - data valid write +//------------------------------------------------- + +WRITE_LINE_MEMBER( ds75161a_device::dav_w ) +{ + if (m_dav != state) + { + m_dav = state; + + update_signals(); + } +} + + +//------------------------------------------------- +// eoi_w - end or identify write +//------------------------------------------------- + +WRITE_LINE_MEMBER( ds75161a_device::eoi_w ) +{ + if (m_eoi != state) + { + m_eoi = state; + + update_signals(); + } +} + + +//------------------------------------------------- +// atn_w - attention write +//------------------------------------------------- + +WRITE_LINE_MEMBER( ds75161a_device::atn_w ) +{ + if (m_atn != state) + { + m_atn = state; + + update_signals(); + } +} + + +//------------------------------------------------- +// srq_w - service request write +//------------------------------------------------- + +WRITE_LINE_MEMBER( ds75161a_device::srq_w ) +{ + if (m_srq != state) + { + m_srq = state; + + update_signals(); + } +} diff --git a/src/devices/machine/ds75161a.h b/src/devices/machine/ds75161a.h new file mode 100644 index 00000000000..83f129857e6 --- /dev/null +++ b/src/devices/machine/ds75161a.h @@ -0,0 +1,177 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + National Semiconductor DS75161A IEEE-488 GPIB Transceiver emulation + +********************************************************************** + _____ _____ + TE 1 |* \_/ | 20 Vcc + REN 2 | | 19 REN + IFC 3 | | 18 IFC + NDAC 4 | | 17 NDAC + NRFD 5 | DS75161A | 16 NRFD + DAV 6 | | 15 DAV + EOI 7 | | 14 EOI + ATN 8 | | 13 ATN + SRQ 8 | | 12 SRQ + GND 10 |_____________| 11 DC + +**********************************************************************/ + +#pragma once + +#ifndef __DS75161A__ +#define __DS75161A__ + +#include "emu.h" + + + +///************************************************************************* +// INTERFACE CONFIGURATION MACROS +///************************************************************************* + +#define MCFG_DS75161A_IN_REN_CB(_devcb) \ + devcb = &ds75161a_device::set_in_ren_callback(*device, DEVCB_##_devcb); + +#define MCFG_DS75161A_IN_IFC_CB(_devcb) \ + devcb = &ds75161a_device::set_in_ifc_callback(*device, DEVCB_##_devcb); + +#define MCFG_DS75161A_IN_NDAC_CB(_devcb) \ + devcb = &ds75161a_device::set_in_ndac_callback(*device, DEVCB_##_devcb); + +#define MCFG_DS75161A_IN_NRFD_CB(_devcb) \ + devcb = &ds75161a_device::set_in_nrfd_callback(*device, DEVCB_##_devcb); + +#define MCFG_DS75161A_IN_DAV_CB(_devcb) \ + devcb = &ds75161a_device::set_in_dav_callback(*device, DEVCB_##_devcb); + +#define MCFG_DS75161A_IN_EOI_CB(_devcb) \ + devcb = &ds75161a_device::set_in_eoi_callback(*device, DEVCB_##_devcb); + +#define MCFG_DS75161A_IN_ATN_CB(_devcb) \ + devcb = &ds75161a_device::set_in_atn_callback(*device, DEVCB_##_devcb); + +#define MCFG_DS75161A_IN_SRQ_CB(_devcb) \ + devcb = &ds75161a_device::set_in_srq_callback(*device, DEVCB_##_devcb); + +#define MCFG_DS75161A_OUT_REN_CB(_devcb) \ + devcb = &ds75161a_device::set_out_ren_callback(*device, DEVCB_##_devcb); + +#define MCFG_DS75161A_OUT_IFC_CB(_devcb) \ + devcb = &ds75161a_device::set_out_ifc_callback(*device, DEVCB_##_devcb); + +#define MCFG_DS75161A_OUT_NDAC_CB(_devcb) \ + devcb = &ds75161a_device::set_out_ndac_callback(*device, DEVCB_##_devcb); + +#define MCFG_DS75161A_OUT_NRFD_CB(_devcb) \ + devcb = &ds75161a_device::set_out_nrfd_callback(*device, DEVCB_##_devcb); + +#define MCFG_DS75161A_OUT_DAV_CB(_devcb) \ + devcb = &ds75161a_device::set_out_dav_callback(*device, DEVCB_##_devcb); + +#define MCFG_DS75161A_OUT_EOI_CB(_devcb) \ + devcb = &ds75161a_device::set_out_eoi_callback(*device, DEVCB_##_devcb); + +#define MCFG_DS75161A_OUT_ATN_CB(_devcb) \ + devcb = &ds75161a_device::set_out_atn_callback(*device, DEVCB_##_devcb); + +#define MCFG_DS75161A_OUT_SRQ_CB(_devcb) \ + devcb = &ds75161a_device::set_out_srq_callback(*device, DEVCB_##_devcb); + +///************************************************************************* +// TYPE DEFINITIONS +///************************************************************************* + +// ======================> ds75161a_device + +class ds75161a_device : public device_t +{ +public: + // construction/destruction + ds75161a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + template static devcb_base &set_in_ren_callback(device_t &device, _Object object) { return downcast(device).m_in_ren_cb.set_callback(object); } + template static devcb_base &set_in_ifc_callback(device_t &device, _Object object) { return downcast(device).m_in_ifc_cb.set_callback(object); } + template static devcb_base &set_in_ndac_callback(device_t &device, _Object object) { return downcast(device).m_in_ndac_cb.set_callback(object); } + template static devcb_base &set_in_nrfd_callback(device_t &device, _Object object) { return downcast(device).m_in_nrfd_cb.set_callback(object); } + template static devcb_base &set_in_dav_callback(device_t &device, _Object object) { return downcast(device).m_in_dav_cb.set_callback(object); } + template static devcb_base &set_in_eoi_callback(device_t &device, _Object object) { return downcast(device).m_in_eoi_cb.set_callback(object); } + template static devcb_base &set_in_atn_callback(device_t &device, _Object object) { return downcast(device).m_in_atn_cb.set_callback(object); } + template static devcb_base &set_in_srq_callback(device_t &device, _Object object) { return downcast(device).m_in_srq_cb.set_callback(object); } + template static devcb_base &set_out_ren_callback(device_t &device, _Object object) { return downcast(device).m_out_ren_cb.set_callback(object); } + template static devcb_base &set_out_ifc_callback(device_t &device, _Object object) { return downcast(device).m_out_ifc_cb.set_callback(object); } + template static devcb_base &set_out_ndac_callback(device_t &device, _Object object) { return downcast(device).m_out_ndac_cb.set_callback(object); } + template static devcb_base &set_out_nrfd_callback(device_t &device, _Object object) { return downcast(device).m_out_nrfd_cb.set_callback(object); } + template static devcb_base &set_out_dav_callback(device_t &device, _Object object) { return downcast(device).m_out_dav_cb.set_callback(object); } + template static devcb_base &set_out_eoi_callback(device_t &device, _Object object) { return downcast(device).m_out_eoi_cb.set_callback(object); } + template static devcb_base &set_out_atn_callback(device_t &device, _Object object) { return downcast(device).m_out_atn_cb.set_callback(object); } + template static devcb_base &set_out_srq_callback(device_t &device, _Object object) { return downcast(device).m_out_srq_cb.set_callback(object); } + + DECLARE_WRITE_LINE_MEMBER( te_w ); + DECLARE_WRITE_LINE_MEMBER( dc_w ); + + DECLARE_READ_LINE_MEMBER( ren_r ); + DECLARE_READ_LINE_MEMBER( ifc_r ); + DECLARE_READ_LINE_MEMBER( ndac_r ); + DECLARE_READ_LINE_MEMBER( nrfd_r ); + DECLARE_READ_LINE_MEMBER( dav_r ); + DECLARE_READ_LINE_MEMBER( eoi_r ); + DECLARE_READ_LINE_MEMBER( atn_r ); + DECLARE_READ_LINE_MEMBER( srq_r ); + + DECLARE_WRITE_LINE_MEMBER( ren_w ); + DECLARE_WRITE_LINE_MEMBER( ifc_w ); + DECLARE_WRITE_LINE_MEMBER( ndac_w ); + DECLARE_WRITE_LINE_MEMBER( nrfd_w ); + DECLARE_WRITE_LINE_MEMBER( dav_w ); + DECLARE_WRITE_LINE_MEMBER( eoi_w ); + DECLARE_WRITE_LINE_MEMBER( atn_w ); + DECLARE_WRITE_LINE_MEMBER( srq_w ); + +protected: + // device-level overrides + virtual void device_start(); + +private: + void update_signals(); + + devcb_read_line m_in_ren_cb; + devcb_read_line m_in_ifc_cb; + devcb_read_line m_in_ndac_cb; + devcb_read_line m_in_nrfd_cb; + devcb_read_line m_in_dav_cb; + devcb_read_line m_in_eoi_cb; + devcb_read_line m_in_atn_cb; + devcb_read_line m_in_srq_cb; + + devcb_write_line m_out_ren_cb; + devcb_write_line m_out_ifc_cb; + devcb_write_line m_out_ndac_cb; + devcb_write_line m_out_nrfd_cb; + devcb_write_line m_out_dav_cb; + devcb_write_line m_out_eoi_cb; + devcb_write_line m_out_atn_cb; + devcb_write_line m_out_srq_cb; + + int m_ren; + int m_ifc; + int m_ndac; + int m_nrfd; + int m_dav; + int m_eoi; + int m_atn; + int m_srq; + + int m_te; + int m_dc; +}; + + +// device type definition +extern const device_type DS75161A; + + + +#endif diff --git a/src/devices/machine/e0516.c b/src/devices/machine/e0516.c new file mode 100644 index 00000000000..0fc743ba95c --- /dev/null +++ b/src/devices/machine/e0516.c @@ -0,0 +1,198 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Microelectronic-Marin E050-16 Real Time Clock emulation + +**********************************************************************/ + +#include "emu.h" +#include "e0516.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define LOG 0 + + +// states +enum +{ + STATE_ADDRESS = 0, + STATE_DATA +}; + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +// device type definition +const device_type E0516 = &device_creator; + +//------------------------------------------------- +// e0516_device - constructor +//------------------------------------------------- + +e0516_device::e0516_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, E0516, "E05-16", tag, owner, clock, "e0516", __FILE__), + device_rtc_interface(mconfig, *this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void e0516_device::device_start() +{ + // allocate timers + m_timer = timer_alloc(); + m_timer->adjust(attotime::from_hz(clock() / 32768), 0, attotime::from_hz(clock() / 32768)); + + // state saving + save_item(NAME(m_cs)); + save_item(NAME(m_clk)); + save_item(NAME(m_data_latch)); + save_item(NAME(m_reg_latch)); + save_item(NAME(m_read_write)); + save_item(NAME(m_state)); + save_item(NAME(m_bits)); + save_item(NAME(m_dio)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void e0516_device::device_reset() +{ + set_current_time(machine()); +} + + +//------------------------------------------------- +// device_timer - handler timer events +//------------------------------------------------- + +void e0516_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + advance_seconds(); +} + + +//------------------------------------------------- +// cs_w - chip select input +//------------------------------------------------- + +WRITE_LINE_MEMBER( e0516_device::cs_w ) +{ + if (LOG) logerror("E05-16 '%s' CS %u\n", tag(), state); + + m_cs = state; + + if (m_cs) + { + m_data_latch = 0; + m_reg_latch = 0; + m_bits = 0; + m_state = STATE_ADDRESS; + } +} + + +//------------------------------------------------- +// clk_w - serial clock input +//------------------------------------------------- + +WRITE_LINE_MEMBER( e0516_device::clk_w ) +{ + if (LOG) logerror("E05-16 '%s' CLK %u\n", tag(), state); + + m_clk = state; + + if (m_cs || m_clk) return; + + m_bits++; + + if (m_state == STATE_ADDRESS) + { + if (LOG) logerror("E05-16 '%s' Command Bit %u\n", tag(), m_dio); + + // command + m_reg_latch |= m_dio << 3; + m_reg_latch >>= 1; + + if (m_bits == 4) + { + m_state = STATE_DATA; + m_bits = 0; + + if (BIT(m_reg_latch, 0)) + { + // load register value to data latch + m_data_latch = convert_to_bcd(get_clock_register(m_reg_latch >> 1)); + } + } + } + else + { + // data + if (BIT(m_reg_latch, 0)) + { + // read + if (LOG) logerror("E05-16 '%s' Data Bit OUT %u\n", tag(), m_dio); + + m_dio = BIT(m_data_latch, 0); + m_data_latch >>= 1; + } + else + { + // write + if (LOG) logerror("E05-16 '%s' Data Bit IN %u\n", tag(), m_dio); + + m_data_latch |= m_dio << 7; + m_data_latch >>= 1; + } + + if (m_bits == 8) + { + m_state = STATE_ADDRESS; + m_bits = 0; + + if (!BIT(m_reg_latch, 0)) + { + // write latched data to register + set_clock_register(m_reg_latch >> 1, bcd_to_integer(m_data_latch)); + } + } + } +} + + +//------------------------------------------------- +// dio_w - serial data input +//------------------------------------------------- + +WRITE_LINE_MEMBER( e0516_device::dio_w ) +{ + if (LOG) logerror("E05-16 '%s' DIO %u\n", tag(), state); + + m_dio = state; +} + + +//------------------------------------------------- +// do_r - serial data output +//------------------------------------------------- + +READ_LINE_MEMBER( e0516_device::dio_r ) +{ + return m_dio; +} diff --git a/src/devices/machine/e0516.h b/src/devices/machine/e0516.h new file mode 100644 index 00000000000..8adcdc75948 --- /dev/null +++ b/src/devices/machine/e0516.h @@ -0,0 +1,82 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Microelectronic-Marin E050-16 Real Time Clock emulation + +********************************************************************** + _____ _____ + Vdd1 1 |* \_/ | 16 Vdd2 + OSC IN 2 | | 15 Clk + OSC OUT 3 | | 14 XOUT + _STOP 4 | E05-16 | 13 DI/O + _RESET 5 | E050-16 | 12 _SEC + _OUTSEL 6 | | 11 _MIN + _DAY 7 | | 10 _HRS + Vss 8 |_____________| 9 _CS + +**********************************************************************/ + +#pragma once + +#ifndef __E0516__ +#define __E0516__ + +#include "emu.h" + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_E0516_ADD(_tag, _clock) \ + MCFG_DEVICE_ADD(_tag, E0516, _clock) + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> e0516_device + +class e0516_device : public device_t, + public device_rtc_interface +{ +public: + // construction/destruction + e0516_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + DECLARE_WRITE_LINE_MEMBER( cs_w ); + DECLARE_WRITE_LINE_MEMBER( clk_w ); + DECLARE_WRITE_LINE_MEMBER( dio_w ); + DECLARE_READ_LINE_MEMBER( dio_r ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + +private: + int m_cs; // chip select + int m_clk; // clock + int m_data_latch; // data latch + int m_reg_latch; // register latch + int m_read_write; // read/write data + int m_state; // state + int m_bits; // number of bits transferred + int m_dio; // data pin + + // timers + emu_timer *m_timer; +}; + + +// device type definition +extern const device_type E0516; + + + +#endif diff --git a/src/devices/machine/e05a03.c b/src/devices/machine/e05a03.c new file mode 100644 index 00000000000..258c3d1ca0b --- /dev/null +++ b/src/devices/machine/e05a03.c @@ -0,0 +1,188 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best +/*************************************************************************** + + E05A03 Gate Array (used in the Epson LX-800) + +***************************************************************************/ + +#include "emu.h" +#include "e05a03.h" + + +/***************************************************************************** + DEVICE INTERFACE +*****************************************************************************/ + +const device_type E05A03 = &device_creator; + +e05a03_device::e05a03_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, E05A03, "E05A03", tag, owner, clock, "e05a03", __FILE__), + m_write_nlq_lp(*this), + m_write_pe_lp(*this), + m_write_reso(*this), + m_write_pe(*this), + m_read_data(*this), + m_shift(0), + m_busy_leading(0), + m_busy_software(0), + m_nlqlp(0), + m_cndlp(0), + #if 0 + m_pe(0), + m_pelp(0), + #endif + m_printhead(0), + m_pf_motor(0), + m_cr_motor(0) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void e05a03_device::device_start() +{ + /* resolve callbacks */ + m_write_nlq_lp.resolve_safe(); + m_write_pe_lp.resolve_safe(); + m_write_reso.resolve_safe(); + m_write_pe.resolve_safe(); + m_read_data.resolve_safe(0); + + /* register for state saving */ + save_item(NAME(m_shift)); + save_item(NAME(m_busy_leading)); + save_item(NAME(m_busy_software)); + save_item(NAME(m_nlqlp)); + save_item(NAME(m_cndlp)); + #if 0 + save_item(NAME(m_pe)); + save_item(NAME(m_pelp)); + #endif + save_item(NAME(m_printhead)); + save_item(NAME(m_pf_motor)); + save_item(NAME(m_cr_motor)); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void e05a03_device::device_reset() +{ + m_printhead = 0x00; + m_pf_motor = 0x00; + m_cr_motor = 0x0f; + + m_write_pe(0); + m_write_pe_lp(1); + + m_busy_software = 1; + m_nlqlp = 1; + m_cndlp = 1; +} + + + +/*************************************************************************** + IMPLEMENTATION +***************************************************************************/ + +WRITE8_MEMBER( e05a03_device::write ) +{ + logerror("%s: e05a03_w(%02x): %02x\n", space.machine().describe_context(), offset, data); + + switch (offset) + { + /* shift register */ + case 0x00: m_shift = (m_shift & 0x00ffff) | (data << 16); break; + case 0x01: m_shift = (m_shift & 0xff00ff) | (data << 8); break; + case 0x02: m_shift = (m_shift & 0xffff00) | (data << 0); break; + + case 0x03: + m_busy_leading = BIT(data, 7); + m_busy_software = BIT(data, 6); + m_nlqlp = BIT(data, 4); + m_cndlp = BIT(data, 3); + + m_write_pe(BIT(data, 2)); + m_write_pe_lp(!BIT(data, 2)); + +#if 0 + m_pe = BIT(data, 2); + m_pelp = !BIT(data, 2); +#endif + + break; + + /* printhead */ + case 0x04: m_printhead = (m_printhead & 0x100) | !data; break; + case 0x05: m_printhead = (m_printhead & 0x0ff) | (!(BIT(data, 7) << 8)); break; + + /* paper feed and carriage motor phase data*/ + case 0x06: m_pf_motor = (data & 0xf0) >> 4; break; + case 0x07: m_cr_motor = (data & 0x0f) >> 0; break; + } +} + +READ8_MEMBER( e05a03_device::read ) +{ + UINT8 result = 0; + + logerror("%s: e05a03_r(%02x)\n", space.machine().describe_context(), offset); + + switch (offset) + { + case 0x00: + break; + + case 0x01: + break; + + case 0x02: + result = m_read_data(0); + break; + + case 0x03: + result |= BIT(m_shift, 23) << 7; + m_shift <<= 1; + break; + } + + return result; +} + +/* home position signal */ +WRITE_LINE_MEMBER( e05a03_device::home_w ) +{ +} + +/* printhead solenoids trigger */ +WRITE_LINE_MEMBER( e05a03_device::fire_w ) +{ +} + +WRITE_LINE_MEMBER( e05a03_device::strobe_w ) +{ +} + +READ_LINE_MEMBER( e05a03_device::busy_r ) +{ + return 1; +} + +WRITE_LINE_MEMBER( e05a03_device::resi_w ) +{ + if (!state) + { + device_reset(); + m_write_reso(1); + } +} + +WRITE_LINE_MEMBER( e05a03_device::init_w ) +{ + resi_w(state); +} diff --git a/src/devices/machine/e05a03.h b/src/devices/machine/e05a03.h new file mode 100644 index 00000000000..03fa2aca98a --- /dev/null +++ b/src/devices/machine/e05a03.h @@ -0,0 +1,99 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best +/*************************************************************************** + + E05A03 Gate Array (used in the Epson LX-800) + +***************************************************************************/ + +#ifndef __E05A03_H__ +#define __E05A03_H__ + +/*************************************************************************** + DEVICE CONFIGURATION MACROS +***************************************************************************/ + +#define MCFG_E05A03_NLQ_LP_CALLBACK(_write) \ + devcb = &e05a03_device::set_nlq_lp_wr_callback(*device, DEVCB_##_write); + +#define MCFG_E05A03_PE_LP_CALLBACK(_write) \ + devcb = &e05a03_device::set_pe_lp_wr_callback(*device, DEVCB_##_write); + +#define MCFG_E05A03_RESO_CALLBACK(_write) \ + devcb = &e05a03_device::set_reso_wr_callback(*device, DEVCB_##_write); + +#define MCFG_E05A03_PE_CALLBACK(_write) \ + devcb = &e05a03_device::set_pe_wr_callback(*device, DEVCB_##_write); + +#define MCFG_E05A03_DATA_CALLBACK(_read) \ + devcb = &e05a03_device::set_data_rd_callback(*device, DEVCB_##_read); + + +/*************************************************************************** + TYPE DEFINITIONS +***************************************************************************/ + +class e05a03_device : public device_t +{ +public: + e05a03_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + ~e05a03_device() {} + + template static devcb_base &set_nlq_lp_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_nlq_lp.set_callback(object); } + template static devcb_base &set_pe_lp_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_pe_lp.set_callback(object); } + template static devcb_base &set_reso_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_reso.set_callback(object); } + template static devcb_base &set_pe_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_pe.set_callback(object); } + template static devcb_base &set_data_rd_callback(device_t &device, _Object object) { return downcast(device).m_read_data.set_callback(object); } + + DECLARE_WRITE8_MEMBER( write ); + DECLARE_READ8_MEMBER( read ); + + WRITE_LINE_MEMBER( home_w ); /* home position signal */ + WRITE_LINE_MEMBER( fire_w ); /* printhead solenoids trigger */ + WRITE_LINE_MEMBER( strobe_w ); + READ_LINE_MEMBER( busy_r ); + WRITE_LINE_MEMBER( resi_w ); /* reset input */ + WRITE_LINE_MEMBER( init_w ); /* centronics init */ + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + +private: + // internal state + /* callbacks */ + devcb_write_line m_write_nlq_lp; /* pin 2, nlq lamp output */ + devcb_write_line m_write_pe_lp; /* pin 3, paper empty lamp output */ + devcb_write_line m_write_reso; /* pin 25, reset output */ + devcb_write_line m_write_pe; /* pin 35, centronics pe output */ + devcb_read8 m_read_data; /* pin 47-54, centronics data input */ + + /* 24-bit shift register, port 0x00, 0x01 and 0x02 */ + UINT32 m_shift; + + /* port 0x03 */ + int m_busy_leading; + int m_busy_software; + int m_nlqlp; + int m_cndlp; + +#if 0 + int m_pe; + int m_pelp; +#endif + + /* port 0x04 and 0x05 (9-bit) */ + UINT16 m_printhead; + + /* port 0x06 (4-bit) */ + UINT8 m_pf_motor; + + /* port 0x07 (4-bit) */ + UINT8 m_cr_motor; +}; + +extern const device_type E05A03; + + +#endif /* __E05A03_H__ */ diff --git a/src/devices/machine/e05a30.c b/src/devices/machine/e05a30.c new file mode 100644 index 00000000000..682a8fb96ec --- /dev/null +++ b/src/devices/machine/e05a30.c @@ -0,0 +1,224 @@ +// license:BSD-3-Clause +// copyright-holders:Ramiro Polla +/* + * E05A30 Gate Array (used in the Epson ActionPrinter 2000) + * + */ + +#include "emu.h" +#include "e05a30.h" + +//#define E05A30DEBUG +#ifdef E05A30DEBUG +#define LOG(...) fprintf(stderr, __VA_ARGS__) +#else +#define LOG(...) +#endif + + +/***************************************************************************** + DEVICE INTERFACE +*****************************************************************************/ + +const device_type E05A30 = &device_creator; + +e05a30_device::e05a30_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, E05A30, "E05A30", tag, owner, clock, "e05a30", __FILE__), + m_write_printhead(*this), + m_write_pf_stepper(*this), + m_write_cr_stepper(*this), + m_write_ready(*this), + m_write_centronics_ack(*this), + m_write_centronics_busy(*this), + m_write_centronics_perror(*this), + m_write_centronics_fault(*this), + m_write_centronics_select(*this), + m_printhead(0), + m_pf_stepper(0), + m_cr_stepper(0) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void e05a30_device::device_start() +{ + /* resolve callbacks */ + m_write_printhead.resolve_safe(); + m_write_pf_stepper.resolve_safe(); + m_write_cr_stepper.resolve_safe(); + m_write_ready.resolve_safe(); + m_write_centronics_ack.resolve_safe(); + m_write_centronics_busy.resolve_safe(); + m_write_centronics_perror.resolve_safe(); + m_write_centronics_fault.resolve_safe(); + m_write_centronics_select.resolve_safe(); + + /* register for state saving */ + save_item(NAME(m_printhead)); + save_item(NAME(m_pf_stepper)); + save_item(NAME(m_cr_stepper)); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void e05a30_device::device_reset() +{ + m_printhead = 0x00; + m_pf_stepper = 0x00; + m_cr_stepper = 0x00; + + /* centronics init */ + m_centronics_nack = FALSE; + m_centronics_busy = FALSE; + m_write_centronics_ack (!m_centronics_nack); + m_write_centronics_busy ( m_centronics_busy); + m_write_centronics_perror(FALSE); + m_write_centronics_fault (TRUE); + m_write_centronics_select(TRUE); + + m_write_ready(1); +} + + +/*************************************************************************** + PRINT HEAD +***************************************************************************/ + +/* The e05a30 controls the printhead through MMIOs 0xC005 and 0xC006. + * MMIO 0xC006 keeps the first 8 pins. + * MMIO 0xC005 keeps the 9th pin in the MSB. + */ + +void e05a30_device::update_printhead(int pos, UINT8 data) +{ + if (pos == 0) { + m_printhead &= 0x00ff; + m_printhead |= (UINT16) !!data << 8; + } else { + m_printhead &= 0xff00; + m_printhead |= data; + } + m_write_printhead(m_printhead); +} + +/*************************************************************************** + STEPPER MOTORS +***************************************************************************/ + +/* The e05a30 controls two stepper motors: + * - The Paper Feed stepper motor is controlled through MMIO 0xC007 + * - The Carriage Return stepper motor is controlled through MMIO 0xC008 + * The Carriage Return stepper motor is used throug the SLA7020M driver. It + * is therefore necessary to translate the input data from the SLA7020M + * format to a format describing the 4 phases of a stepper motor. + * For the PF motor, the output data is fed directly to the stepper motor. + */ + +void e05a30_device::update_pf_stepper(UINT8 data) +{ + m_pf_stepper = data & 0x0f; + m_write_pf_stepper(m_pf_stepper); +} + +static UINT8 cr_sla7020m(UINT8 data) +{ + bool ina = BIT(data, 0); + bool inb = BIT(data, 1); + bool tda = BIT(data, 2); + bool tdb = BIT(data, 3); + bool outa0 = ina && tda; + bool outa1 = !ina && tda; + bool outb0 = inb && tdb; + bool outb1 = !inb && tdb; + return (outb1<<3)|(outb0<<2)|(outa1<<1)|(outa0<<0); +} +void e05a30_device::update_cr_stepper(UINT8 data) +{ + m_cr_stepper = data & 0x0f; + m_write_cr_stepper(cr_sla7020m(m_cr_stepper)); +} + + +/*************************************************************************** + Centronics +***************************************************************************/ + +WRITE_LINE_MEMBER( e05a30_device::centronics_input_strobe ) +{ + if (m_centronics_strobe == TRUE && state == FALSE && !m_centronics_busy) { + m_centronics_data_latch = m_centronics_data; + + m_centronics_data_latched = TRUE; + m_centronics_busy = TRUE; + m_write_centronics_busy(m_centronics_busy); + } + + m_centronics_strobe = state; +} + + +/*************************************************************************** + IMPLEMENTATION +***************************************************************************/ + +WRITE8_MEMBER( e05a30_device::write ) +{ + LOG("%s: e05a30_w([0xC0%02x]): %02x\n", space.machine().describe_context(), offset, data); + + switch (offset) { + case 0x04: + m_centronics_nack = BIT(data,5); + m_centronics_busy = BIT(data,0); + /* The ActionPrinter 2000 firmware might overwrite the busy signal at + * address 20AB if the host depends only on the busy signal and + * doesn't wait for the ack pulse. To avoid skipping input data, we + * assume the busy signal cannot be reset while the data hasn't been + * read. */ + if (m_centronics_data_latched) + m_centronics_busy = TRUE; + m_write_centronics_ack (!m_centronics_nack); + m_write_centronics_busy( m_centronics_busy); + break; + /* printhead */ + case 0x05: update_printhead(0, data); break; + case 0x06: update_printhead(1, data); break; + /* paper feed stepper motor */ + case 0x07: update_pf_stepper(data); break; + /* carriage return stepper motor */ + case 0x08: update_cr_stepper(data); break; + } +} + +READ8_MEMBER( e05a30_device::read ) +{ + UINT8 result = 0; + + LOG("%s: e05a30_r([0xC0%02x]): ", space.machine().describe_context(), offset); + + switch (offset) { + case 0x02: + result = m_centronics_data_latched << 7; + break; + case 0x03: + result = m_centronics_data_latch; + m_centronics_data_latched = FALSE; + break; + case 0x04: + result |= m_centronics_busy << 0; + result |= m_centronics_nack << 5; + break; + /* paper feed stepper motor */ + case 0x07: result = m_pf_stepper; break; + /* carriage return stepper motor */ + case 0x08: result = m_cr_stepper; break; + } + + LOG("0x%02x\n", result); + + return result; +} diff --git a/src/devices/machine/e05a30.h b/src/devices/machine/e05a30.h new file mode 100644 index 00000000000..95e4fadb37c --- /dev/null +++ b/src/devices/machine/e05a30.h @@ -0,0 +1,115 @@ +// license:BSD-3-Clause +// copyright-holders:Ramiro Polla +/* + * E05A30 Gate Array (used in the Epson ActionPrinter 2000) + * + */ + +#ifndef __E05A30_H__ +#define __E05A30_H__ + +/*************************************************************************** + DEVICE CONFIGURATION MACROS +***************************************************************************/ + +#define MCFG_E05A30_PRINTHEAD_CALLBACK(_write) \ + devcb = &e05a30_device::set_printhead_wr_callback(*device, DEVCB_##_write); + +#define MCFG_E05A30_PF_STEPPER_CALLBACK(_write) \ + devcb = &e05a30_device::set_pf_stepper_wr_callback(*device, DEVCB_##_write); + +#define MCFG_E05A30_CR_STEPPER_CALLBACK(_write) \ + devcb = &e05a30_device::set_cr_stepper_wr_callback(*device, DEVCB_##_write); + +#define MCFG_E05A30_READY_CALLBACK(_write) \ + devcb = &e05a30_device::set_ready_wr_callback(*device, DEVCB_##_write); + +#define MCFG_E05A30_CENTRONICS_ACK_CALLBACK(_write) \ + devcb = &e05a30_device::set_centronics_ack_wr_callback(*device, DEVCB_##_write); + +#define MCFG_E05A30_CENTRONICS_BUSY_CALLBACK(_write) \ + devcb = &e05a30_device::set_centronics_busy_wr_callback(*device, DEVCB_##_write); + +#define MCFG_E05A30_CENTRONICS_PERROR_CALLBACK(_write) \ + devcb = &e05a30_device::set_centronics_perror_wr_callback(*device, DEVCB_##_write); + +#define MCFG_E05A30_CENTRONICS_FAULT_CALLBACK(_write) \ + devcb = &e05a30_device::set_centronics_fault_wr_callback(*device, DEVCB_##_write); + +#define MCFG_E05A30_CENTRONICS_SELECT_CALLBACK(_write) \ + devcb = &e05a30_device::set_centronics_select_wr_callback(*device, DEVCB_##_write); + +/*************************************************************************** + TYPE DEFINITIONS +***************************************************************************/ + +class e05a30_device : public device_t +{ +public: + e05a30_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + ~e05a30_device() {} + + template static devcb_base &set_printhead_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_printhead.set_callback(object); } + template static devcb_base &set_pf_stepper_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_pf_stepper.set_callback(object); } + template static devcb_base &set_cr_stepper_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_cr_stepper.set_callback(object); } + template static devcb_base &set_ready_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_ready.set_callback(object); } + template static devcb_base &set_centronics_ack_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_centronics_ack.set_callback(object); } + template static devcb_base &set_centronics_busy_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_centronics_busy.set_callback(object); } + template static devcb_base &set_centronics_perror_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_centronics_perror.set_callback(object); } + template static devcb_base &set_centronics_fault_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_centronics_fault.set_callback(object); } + template static devcb_base &set_centronics_select_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_centronics_select.set_callback(object); } + + DECLARE_WRITE8_MEMBER( write ); + DECLARE_READ8_MEMBER( read ); + + /* Centronics stuff */ + DECLARE_WRITE_LINE_MEMBER( centronics_input_strobe ); + DECLARE_WRITE_LINE_MEMBER( centronics_input_data0 ) { if (state) m_centronics_data |= 0x01; else m_centronics_data &= ~0x01; } + DECLARE_WRITE_LINE_MEMBER( centronics_input_data1 ) { if (state) m_centronics_data |= 0x02; else m_centronics_data &= ~0x02; } + DECLARE_WRITE_LINE_MEMBER( centronics_input_data2 ) { if (state) m_centronics_data |= 0x04; else m_centronics_data &= ~0x04; } + DECLARE_WRITE_LINE_MEMBER( centronics_input_data3 ) { if (state) m_centronics_data |= 0x08; else m_centronics_data &= ~0x08; } + DECLARE_WRITE_LINE_MEMBER( centronics_input_data4 ) { if (state) m_centronics_data |= 0x10; else m_centronics_data &= ~0x10; } + DECLARE_WRITE_LINE_MEMBER( centronics_input_data5 ) { if (state) m_centronics_data |= 0x20; else m_centronics_data &= ~0x20; } + DECLARE_WRITE_LINE_MEMBER( centronics_input_data6 ) { if (state) m_centronics_data |= 0x40; else m_centronics_data &= ~0x40; } + DECLARE_WRITE_LINE_MEMBER( centronics_input_data7 ) { if (state) m_centronics_data |= 0x80; else m_centronics_data &= ~0x80; } + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + +private: + /* callbacks */ + devcb_write16 m_write_printhead; + devcb_write8 m_write_pf_stepper; + devcb_write8 m_write_cr_stepper; + devcb_write_line m_write_ready; + devcb_write_line m_write_centronics_ack; + devcb_write_line m_write_centronics_busy; + devcb_write_line m_write_centronics_perror; + devcb_write_line m_write_centronics_fault; + devcb_write_line m_write_centronics_select; + + void update_printhead(int pos, UINT8 data); + void update_pf_stepper(UINT8 data); + void update_cr_stepper(UINT8 data); + + /* port 0x05 and 0x06 (9-bit) */ + UINT16 m_printhead; + /* port 0x07 (4-bit) */ + UINT8 m_pf_stepper; + /* port 0x08 (4-bit) */ + UINT8 m_cr_stepper; + + /* Centronics stuff */ + UINT8 m_centronics_data; + int m_centronics_busy; + int m_centronics_nack; + UINT8 m_centronics_strobe; + UINT8 m_centronics_data_latch; + UINT8 m_centronics_data_latched; +}; + +extern const device_type E05A30; + +#endif /* __E05A30_H__ */ diff --git a/src/devices/machine/eeprom.c b/src/devices/machine/eeprom.c new file mode 100644 index 00000000000..a0e8886e7f4 --- /dev/null +++ b/src/devices/machine/eeprom.c @@ -0,0 +1,376 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + eeprom.c + + Base class for EEPROM devices. + +***************************************************************************/ + +#include "emu.h" +#include "machine/eeprom.h" + + + +//************************************************************************** +// DEBUGGING +//************************************************************************** + +#define VERBOSE 0 +#define LOG(x) do { if (VERBOSE) logerror x; } while (0) + + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +static ADDRESS_MAP_START( eeprom_map8, AS_PROGRAM, 8, eeprom_base_device ) + AM_RANGE(0x00000, 0xfffff) AM_RAM +ADDRESS_MAP_END + +static ADDRESS_MAP_START( eeprom_map16, AS_PROGRAM, 16, eeprom_base_device ) + AM_RANGE(0x00000, 0x7ffff) AM_RAM +ADDRESS_MAP_END + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// eeprom_base_device - constructor +//------------------------------------------------- + +eeprom_base_device::eeprom_base_device(const machine_config &mconfig, device_type devtype, const char *name, const char *tag, device_t *owner, const char *shortname, const char *file) + : device_t(mconfig, devtype, name, tag, owner, 0, shortname, file), + device_memory_interface(mconfig, *this), + device_nvram_interface(mconfig, *this), + m_cells(0), + m_address_bits(0), + m_data_bits(0), + m_default_data(0), + m_default_data_size(0), + m_default_value(0), + m_default_value_set(false), + m_completion_time(attotime::zero) +{ + // a 2ms write time is too long for rfjetsa + m_operation_time[WRITE_TIME] = attotime::from_usec(1750); + m_operation_time[WRITE_ALL_TIME] = attotime::from_usec(8000); + m_operation_time[ERASE_TIME] = attotime::from_usec(1000); + m_operation_time[ERASE_ALL_TIME] = attotime::from_usec(8000); +} + + +//------------------------------------------------- +// static_set_default_data - configuration helpers +// to set the default data +//------------------------------------------------- + +void eeprom_base_device::static_set_size(device_t &device, int cells, int cellbits) +{ + eeprom_base_device &eeprom = downcast(device); + eeprom.m_cells = cells; + eeprom.m_data_bits = cellbits; + + // compute address bits (validation checks verify cells was an even power of 2) + cells--; + eeprom.m_address_bits = 0; + while (cells != 0) + { + cells >>= 1; + eeprom.m_address_bits++; + } + + // describe our address space + if (eeprom.m_data_bits == 8) + eeprom.m_space_config = address_space_config("eeprom", ENDIANNESS_BIG, 8, eeprom.m_address_bits, 0, *ADDRESS_MAP_NAME(eeprom_map8)); + else + eeprom.m_space_config = address_space_config("eeprom", ENDIANNESS_BIG, 16, eeprom.m_address_bits * 2, 0, *ADDRESS_MAP_NAME(eeprom_map16)); +} + + +//------------------------------------------------- +// static_set_default_data - configuration helpers +// to set the default data +//------------------------------------------------- + +void eeprom_base_device::static_set_default_data(device_t &device, const UINT8 *data, UINT32 size) +{ + eeprom_base_device &eeprom = downcast(device); + assert(eeprom.m_data_bits == 8); + eeprom.m_default_data.u8 = const_cast(data); + eeprom.m_default_data_size = size; +} + +void eeprom_base_device::static_set_default_data(device_t &device, const UINT16 *data, UINT32 size) +{ + eeprom_base_device &eeprom = downcast(device); + assert(eeprom.m_data_bits == 16); + eeprom.m_default_data.u16 = const_cast(data); + eeprom.m_default_data_size = size / 2; +} + + +//------------------------------------------------- +// static_set_default_value - configuration helper +// to set the default value +//------------------------------------------------- + +void eeprom_base_device::static_set_default_value(device_t &device, UINT32 value) +{ + eeprom_base_device &eeprom = downcast(device); + eeprom.m_default_value = value; + eeprom.m_default_value_set = true; +} + + +//------------------------------------------------- +// static_set_timing - configuration helper +// to set timing constants for various operations +//------------------------------------------------- + +void eeprom_base_device::static_set_timing(device_t &device, timing_type type, const attotime &duration) +{ + downcast(device).m_operation_time[type] = duration; +} + + +//------------------------------------------------- +// read - read data at the given address +//------------------------------------------------- + +UINT32 eeprom_base_device::read(offs_t address) +{ + if (!ready()) + logerror("EEPROM: Read performed before previous operation completed!"); + return internal_read(address); +} + + +//------------------------------------------------- +// write - write data at the given address +//------------------------------------------------- + +void eeprom_base_device::write(offs_t address, UINT32 data) +{ + if (!ready()) + logerror("EEPROM: Write performed before previous operation completed!"); + internal_write(address, data); + m_completion_time = machine().time() + m_operation_time[WRITE_TIME]; +} + + +//------------------------------------------------- +// write_all - write data at all addresses +// (assumes an erase has previously been +// performed) +//------------------------------------------------- + +void eeprom_base_device::write_all(UINT32 data) +{ + if (!ready()) + logerror("EEPROM: Write all performed before previous operation completed!"); + for (offs_t address = 0; address < (1 << m_address_bits); address++) + internal_write(address, internal_read(address) & data); + m_completion_time = machine().time() + m_operation_time[WRITE_ALL_TIME]; +} + + +//------------------------------------------------- +// erase - erase data at the given address +//------------------------------------------------- + +void eeprom_base_device::erase(offs_t address) +{ + if (!ready()) + logerror("EEPROM: Erase performed before previous operation completed!"); + internal_write(address, ~0); + m_completion_time = machine().time() + m_operation_time[ERASE_TIME]; +} + + +//------------------------------------------------- +// erase_all - erase data at all addresses +//------------------------------------------------- + +void eeprom_base_device::erase_all() +{ + if (!ready()) + logerror("EEPROM: Erase all performed before previous operation completed!"); + for (offs_t address = 0; address < (1 << m_address_bits); address++) + internal_write(address, ~0); + m_completion_time = machine().time() + m_operation_time[ERASE_ALL_TIME]; +} + + +//------------------------------------------------- +// device_validity_check - perform validity checks +// on this device +//------------------------------------------------- + +void eeprom_base_device::device_validity_check(validity_checker &valid) const +{ + // ensure the number of cells is an even power of 2 + if (m_cells != (1 << m_address_bits)) + osd_printf_error("Invalid EEPROM size %d specified\n", m_cells); + + // ensure only the sizes we support are requested + if (m_data_bits != 8 && m_data_bits != 16) + osd_printf_error("Invalid EEPROM data width %d specified\n", m_data_bits); +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void eeprom_base_device::device_start() +{ + // save states + save_item(NAME(m_completion_time)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void eeprom_base_device::device_reset() +{ + // reset any pending operations + m_completion_time = attotime::zero; +} + + +//------------------------------------------------- +// memory_space_config - return a description of +// any address spaces owned by this device +//------------------------------------------------- + +const address_space_config *eeprom_base_device::memory_space_config(address_spacenum spacenum) const +{ + return (spacenum == 0) ? &m_space_config : NULL; +} + + +//------------------------------------------------- +// nvram_default - called to initialize NVRAM to +// its default state +//------------------------------------------------- + +void eeprom_base_device::nvram_default() +{ + UINT32 eeprom_length = 1 << m_address_bits; + UINT32 eeprom_bytes = eeprom_length * m_data_bits / 8; + + // initialize to the default value + UINT32 default_value = m_default_value_set ? m_default_value : ~0; + for (offs_t offs = 0; offs < eeprom_length; offs++) + if (m_data_bits == 8) + m_addrspace[0]->write_byte(offs, default_value); + else + m_addrspace[0]->write_word(offs * 2, default_value); + + // handle hard-coded data from the driver + if (m_default_data.u8 != NULL) + { + osd_printf_verbose("Warning: Driver-specific EEPROM defaults are going away soon.\n"); + for (offs_t offs = 0; offs < m_default_data_size; offs++) + { + if (m_data_bits == 8) + m_addrspace[0]->write_byte(offs, m_default_data.u8[offs]); + else + m_addrspace[0]->write_word(offs * 2, m_default_data.u16[offs]); + } + } + + // populate from a memory region if present + if (m_region != NULL) + { + if (m_region->bytes() != eeprom_bytes) + fatalerror("eeprom region '%s' wrong size (expected size = 0x%X)\n", tag(), eeprom_bytes); + if (m_data_bits == 8 && m_region->bytewidth() != 1) + fatalerror("eeprom region '%s' needs to be an 8-bit region\n", tag()); + if (m_data_bits == 16 && (m_region->bytewidth() != 2 || m_region->endianness() != ENDIANNESS_BIG)) + fatalerror("eeprom region '%s' needs to be a 16-bit big-endian region\n", tag()); + osd_printf_verbose("Loading data from EEPROM region '%s'\n", tag()); + + if (m_data_bits == 8) + { + UINT8 *default_data = m_region->base(); + for (offs_t offs = 0; offs < eeprom_length; offs++) + m_addrspace[0]->write_byte(offs, default_data[offs]); + } + else + { + UINT16 *default_data = (UINT16 *)(m_region->base()); + for (offs_t offs = 0; offs < eeprom_length; offs++) + m_addrspace[0]->write_word(offs * 2, default_data[offs]); + } + } +} + + +//------------------------------------------------- +// nvram_read - called to read NVRAM from the +// .nv file +//------------------------------------------------- + +void eeprom_base_device::nvram_read(emu_file &file) +{ + UINT32 eeprom_length = 1 << m_address_bits; + UINT32 eeprom_bytes = eeprom_length * m_data_bits / 8; + + dynamic_buffer buffer(eeprom_bytes); + file.read(&buffer[0], eeprom_bytes); + for (offs_t offs = 0; offs < eeprom_bytes; offs++) + m_addrspace[0]->write_byte(offs, buffer[offs]); +} + + +//------------------------------------------------- +// nvram_write - called to write NVRAM to the +// .nv file +//------------------------------------------------- + +void eeprom_base_device::nvram_write(emu_file &file) +{ + UINT32 eeprom_length = 1 << m_address_bits; + UINT32 eeprom_bytes = eeprom_length * m_data_bits / 8; + + dynamic_buffer buffer(eeprom_bytes); + for (offs_t offs = 0; offs < eeprom_bytes; offs++) + buffer[offs] = m_addrspace[0]->read_byte(offs); + file.write(&buffer[0], eeprom_bytes); +} + + +//------------------------------------------------- +// internal_read - read data at the given address +//------------------------------------------------- + +UINT32 eeprom_base_device::internal_read(offs_t address) +{ + if (m_data_bits == 16) + return m_addrspace[0]->read_word(address * 2); + else + return m_addrspace[0]->read_byte(address); +} + + +//------------------------------------------------- +// internal_write - write data at the given +// address +//------------------------------------------------- + +void eeprom_base_device::internal_write(offs_t address, UINT32 data) +{ + if (m_data_bits == 16) + m_addrspace[0]->write_word(address * 2, data); + else + m_addrspace[0]->write_byte(address, data); +} diff --git a/src/devices/machine/eeprom.h b/src/devices/machine/eeprom.h new file mode 100644 index 00000000000..d6db74f5a21 --- /dev/null +++ b/src/devices/machine/eeprom.h @@ -0,0 +1,116 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + eeprom.h + + Base class for EEPROM devices. + +***************************************************************************/ + +#pragma once + +#ifndef __EEPROM_H__ +#define __EEPROM_H__ + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_EEPROM_SIZE(_cells, _cellbits) \ + eeprom_base_device::static_set_size(*device, _cells, _cellbits); +#define MCFG_EEPROM_DATA(_data, _size) \ + eeprom_base_device::static_set_default_data(*device, _data, _size); +#define MCFG_EEPROM_DEFAULT_VALUE(_value) \ + eeprom_base_device::static_set_default_value(*device, _value); + +#define MCFG_EEPROM_WRITE_TIME(_value) \ + eeprom_base_device::static_set_timing(*device, eeprom_base_device::WRITE_TIME, _value); +#define MCFG_EEPROM_WRITE_ALL_TIME(_value) \ + eeprom_base_device::static_set_timing(*device, eeprom_base_device::WRITE_ALL_TIME, _value); +#define MCFG_EEPROM_ERASE_TIME(_value) \ + eeprom_base_device::static_set_timing(*device, eeprom_base_device::ERASE_TIME, _value); +#define MCFG_EEPROM_ERASE_ALL_TIME(_value) \ + eeprom_base_device::static_set_timing(*device, eeprom_base_device::ERASE_ALL_TIME, _value); + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> eeprom_base_device + +class eeprom_base_device : public device_t, + public device_memory_interface, + public device_nvram_interface +{ +protected: + // construction/destruction + eeprom_base_device(const machine_config &mconfig, device_type devtype, const char *name, const char *tag, device_t *owner, const char *shortname, const char *file); + +public: + // timing constants + enum timing_type + { + WRITE_TIME, // default = 2ms + WRITE_ALL_TIME, // default = 8ms + ERASE_TIME, // default = 1ms + ERASE_ALL_TIME, // default = 8ms + TIMING_COUNT + }; + + // inline configuration helpers + static void static_set_size(device_t &device, int cells, int cellbits); + static void static_set_default_data(device_t &device, const UINT8 *data, UINT32 size); + static void static_set_default_data(device_t &device, const UINT16 *data, UINT32 size); + static void static_set_default_value(device_t &device, UINT32 value); + static void static_set_timing(device_t &device, timing_type type, const attotime &duration); + + // read/write/erase data + UINT32 read(offs_t address); + void write(offs_t address, UINT32 data); + void write_all(UINT32 data); + void erase(offs_t address); + void erase_all(); + + // status + bool ready() const { return machine().time() >= m_completion_time; } + +protected: + // device-level overrides + virtual void device_validity_check(validity_checker &valid) const; + virtual void device_start(); + virtual void device_reset(); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const; + + // device_nvram_interface overrides + virtual void nvram_default(); + virtual void nvram_read(emu_file &file); + virtual void nvram_write(emu_file &file); + + // internal read/write without side-effects + UINT32 internal_read(offs_t address); + void internal_write(offs_t address, UINT32 data); + + // configuration state + UINT32 m_cells; + UINT8 m_address_bits; + UINT8 m_data_bits; + address_space_config m_space_config; + generic_ptr m_default_data; + UINT32 m_default_data_size; + UINT32 m_default_value; + bool m_default_value_set; + attotime m_operation_time[TIMING_COUNT]; + + // live state + attotime m_completion_time; +}; + + +#endif diff --git a/src/devices/machine/eeprompar.c b/src/devices/machine/eeprompar.c new file mode 100644 index 00000000000..af575ec1419 --- /dev/null +++ b/src/devices/machine/eeprompar.c @@ -0,0 +1,133 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + eeprompar.c + + Parallel EEPROM devices. + +**************************************************************************** + + Parallel EEPROMs are generally simpler than serial EEPROMs, though + they require more pins to provide the full set of address and data + lines necessary. They also require more pins the larger the EEPROM + is, whereas serial EEPROMs all share the same pinout regardless of + size. + + At a basic level, there are 5 sets of signals involved: + + * /CE = chip enable + * /OE = output enable + * /WE = write enable + * D0-Dn = data lines + * A0-An = address lines + + To access the chip, the various enable states must be asserted or + cleared. Note that these are generally active-low, so asserted means + pulled to GND, and cleared means pulled to Vcc: + + /CE /OE /WE Action + ASSERT ASSERT CLEAR Read (D0-Dn contain output data) + ASSERT CLEAR ASSERT Write/Erase (D0-Dn are input data) + + Erase is performed by doing a write with D0-Dn all set to 1. + + In general, it is slow to write or erase (9ms is quoted in the 2816A + datasheet, for example), and the /WE must be held low for the entire + write/erase duration in order to guarantee the data is written. + +***************************************************************************/ + +#include "emu.h" +#include "machine/eeprompar.h" + + + +//************************************************************************** +// BASE DEVICE IMPLEMENTATION +//************************************************************************** + +//------------------------------------------------- +// eeprom_parallel_base_device - constructor +//------------------------------------------------- + +eeprom_parallel_base_device::eeprom_parallel_base_device(const machine_config &mconfig, device_type devtype, const char *name, const char *tag, device_t *owner, const char *shortname, const char *file) + : eeprom_base_device(mconfig, devtype, name, tag, owner, shortname, file) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void eeprom_parallel_base_device::device_start() +{ + // start the base class + eeprom_base_device::device_start(); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void eeprom_parallel_base_device::device_reset() +{ + // reset the base class + eeprom_base_device::device_reset(); +} + + + +//************************************************************************** +// 28XX INTERFACE IMPLEMENTATION +//************************************************************************** + +//------------------------------------------------- +// eeprom_parallel_28xx_device - constructor +//------------------------------------------------- + +eeprom_parallel_28xx_device::eeprom_parallel_28xx_device(const machine_config &mconfig, device_type devtype, const char *name, const char *tag, device_t *owner, const char *shortname, const char *file) + : eeprom_parallel_base_device(mconfig, devtype, name, tag, owner, shortname, file) +{ +} + + +//------------------------------------------------- +// read/write - read/write handlers +//------------------------------------------------- + +WRITE8_MEMBER(eeprom_parallel_28xx_device::write) +{ + eeprom_base_device::write(offset, data); +} + +READ8_MEMBER(eeprom_parallel_28xx_device::read) +{ + return eeprom_base_device::read(offset); +} + + + +//************************************************************************** +// DERIVED TYPES +//************************************************************************** + +// macro for defining a new device class +#define DEFINE_PARALLEL_EEPROM_DEVICE(_baseclass, _lowercase, _uppercase, _bits, _cells) \ +eeprom_parallel_##_lowercase##_device::eeprom_parallel_##_lowercase##_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) \ + : eeprom_parallel_##_baseclass##_device(mconfig, EEPROM_PARALLEL_##_uppercase, "Parallel EEPROM " #_uppercase " (" #_cells "x" #_bits ")", tag, owner, #_lowercase, __FILE__) \ +{ \ + static_set_size(*this, _cells, _bits); \ +} \ +const device_type EEPROM_PARALLEL_##_uppercase = &device_creator; +// standard 28XX class of 8-bit EEPROMs +DEFINE_PARALLEL_EEPROM_DEVICE(28xx, 2804, 2804, 8, 512) +DEFINE_PARALLEL_EEPROM_DEVICE(28xx, 2816, 2816, 8, 2048) +DEFINE_PARALLEL_EEPROM_DEVICE(28xx, 2864, 2864, 8, 8192) +DEFINE_PARALLEL_EEPROM_DEVICE(28xx, 28256, 28256, 8, 32768) +DEFINE_PARALLEL_EEPROM_DEVICE(28xx, 28512, 28512, 8, 65536) +DEFINE_PARALLEL_EEPROM_DEVICE(28xx, 28010, 28010, 8, 131072) +DEFINE_PARALLEL_EEPROM_DEVICE(28xx, 28020, 28020, 8, 262144) +DEFINE_PARALLEL_EEPROM_DEVICE(28xx, 28040, 28040, 8, 524288) diff --git a/src/devices/machine/eeprompar.h b/src/devices/machine/eeprompar.h new file mode 100644 index 00000000000..84c4090f14e --- /dev/null +++ b/src/devices/machine/eeprompar.h @@ -0,0 +1,105 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + eeprompar.h + + Parallel EEPROM devices. + +***************************************************************************/ + +#pragma once + +#ifndef __EEPROMPAR_H__ +#define __EEPROMPAR_H__ + +#include "eeprom.h" + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +// standard 28XX class of 8-bit parallel EEPROMs +#define MCFG_EEPROM_2804_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, EEPROM_PARALLEL_2804, 0) +#define MCFG_EEPROM_2816_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, EEPROM_PARALLEL_2816, 0) +#define MCFG_EEPROM_2864_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, EEPROM_PARALLEL_2864, 0) +#define MCFG_EEPROM_28256_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, EEPROM_PARALLEL_28256, 0) +#define MCFG_EEPROM_28512_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, EEPROM_PARALLEL_28512, 0) +#define MCFG_EEPROM_28010_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, EEPROM_PARALLEL_28010, 0) +#define MCFG_EEPROM_28020_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, EEPROM_PARALLEL_28020, 0) +#define MCFG_EEPROM_28040_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, EEPROM_PARALLEL_28040, 0) + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + + +// ======================> eeprom_parallel_base_device + +class eeprom_parallel_base_device : public eeprom_base_device +{ +protected: + // construction/destruction + eeprom_parallel_base_device(const machine_config &mconfig, device_type devtype, const char *name, const char *tag, device_t *owner, const char *shortname, const char *file); + +public: + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); +}; + + + +// ======================> eeprom_parallel_28xx_device + +class eeprom_parallel_28xx_device : public eeprom_parallel_base_device +{ +protected: + // construction/destruction + eeprom_parallel_28xx_device(const machine_config &mconfig, device_type devtype, const char *name, const char *tag, device_t *owner, const char *shortname, const char *file); + +public: + // read/write data lines - for now we cheat and ignore the control lines, assuming + // they are handled reasonably + DECLARE_WRITE8_MEMBER(write); + DECLARE_READ8_MEMBER(read); +}; + + + +//************************************************************************** +// DERIVED TYPES +//************************************************************************** + +// macro for declaring a new device class +#define DECLARE_PARALLEL_EEPROM_DEVICE(_baseclass, _lowercase, _uppercase) \ +class eeprom_parallel_##_lowercase##_device : public eeprom_parallel_##_baseclass##_device \ +{ \ +public: \ + eeprom_parallel_##_lowercase##_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); \ +}; \ +extern const device_type EEPROM_PARALLEL_##_uppercase; +// standard 28XX class of 8-bit EEPROMs +DECLARE_PARALLEL_EEPROM_DEVICE(28xx, 2804, 2804) +DECLARE_PARALLEL_EEPROM_DEVICE(28xx, 2816, 2816) +DECLARE_PARALLEL_EEPROM_DEVICE(28xx, 2864, 2864) +DECLARE_PARALLEL_EEPROM_DEVICE(28xx, 28256, 28256) +DECLARE_PARALLEL_EEPROM_DEVICE(28xx, 28512, 28512) +DECLARE_PARALLEL_EEPROM_DEVICE(28xx, 28010, 28010) +DECLARE_PARALLEL_EEPROM_DEVICE(28xx, 28020, 28020) +DECLARE_PARALLEL_EEPROM_DEVICE(28xx, 28040, 28040) + +#endif diff --git a/src/devices/machine/eepromser.c b/src/devices/machine/eepromser.c new file mode 100644 index 00000000000..347accae06f --- /dev/null +++ b/src/devices/machine/eepromser.c @@ -0,0 +1,1161 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + eepromser.c + + Serial EEPROM devices. + +**************************************************************************** + + Serial EEPROMs generally work the same across manufacturers and models, + varying largely by the size of the EEPROM and the packaging details. + + At a basic level, there are 5 signals involved: + + * CS = chip select + * CLK = serial data clock + * DI = serial data in + * DO = serial data out + * RDY/BUSY = ready (1) or busy (0) status + + Data is read or written via serial commands. A command is begun on a + low-to-high transition of the CS line, following by clocking a start + bit (1) on the DI line. After the start bit, subsequent clocks + assemble one of the following commands: + + Start Opcode Address Data + 1 01 aaaaaaaaa ddddddd WRITE data + 1 10 aaaaaaaaa READ data + 1 11 aaaaaaaaa ERASE data + 1 00 00xxxxxxx WREN = WRite ENable + 1 00 01xxxxxxx ddddddd WRAL = WRite ALl cells + 1 00 10xxxxxxx ERAL = ERase ALl cells + 1 00 11xxxxxxx WRDS = WRite DiSable + + The number of address bits (a) clocked varies based on the size of the + chip, though it does not always map 1:1 with the size of the chip. + For example, the 93C06 has 16 cells, which only needs 4 address bits; + but commands to the 93C06 require 6 address bits (the top two must + be 0). + + The number of data bits (d) clocked varies based on the chip and at + times on the state of a pin on the chip which selects between multiple + sizes (e.g., 8-bit versus 16-bit). + +**************************************************************************** + + Most EEPROMs are based on the 93Cxx design (and have similar part + designations): + + +--v--+ + CS |1 8| Vcc + CLK |2 7| NC + DI |3 6| NC + DO |4 5| GND + +-----+ + + Note the lack of a READY/BUSY pin. On the 93Cxx series, the DO pin + serves double-duty, returning READY/BUSY during a write/erase cycle, + and outputting data during a read cycle. + + Some manufacturers have released "enhanced" versions with additional + features: + + * Several manufacturers (ST) map pin 6 to "ORG", specifying the + logical organization of the data. Connecting ORG to ground + makes the EEPROM work as an 8-bit device, while connecting it + to Vcc makes it work as a 16-bit device with one less + address bit. + + * Other manufacturers (ST) have enhanced the read operations to + allow serially streaming more than one cell. Essentially, after + reading the first cell, keep CS high and keep clocking, and + data from following cells will be read as well. + + The ER5911 is only slightly different: + + +--v--+ + CS |1 8| Vcc + CLK |2 7| RDY/BUSY + DI |3 6| ORG + DO |4 5| GND + +-----+ + + Here we have an explicit RDY/BUSY signal, and the ORG flag as described + above. + + From a command perspective, the ER5911 is also slightly different: + + 93Cxx has ERASE command; this maps to WRITE on ER5911 + 93Cxx has WRITEALL command; no equivalent on ER5911 + +**************************************************************************** + + Issues with: + + kickgoal.c - code seems wrong, clock logic writes 0-0-0 instead of 0-1-0 as expected + overdriv.c - drops CS, raises CS, keeps DI=1, triggering extraneous start bit + +***************************************************************************/ + +#include "emu.h" +#include "machine/eepromser.h" + + + +//************************************************************************** +// DEBUGGING +//************************************************************************** + +// logging levels: +// 0 = errors and warnings only +// 1 = commands +// 2 = state machine +// 3 = DI/DO/READY reads & writes +// 4 = all reads & writes + +#define VERBOSE_PRINTF 0 +#define VERBOSE_LOGERROR 0 + +#define LOG0(x) do { if (VERBOSE_PRINTF >= 1) printf x; logerror x; } while (0) +#define LOG1(x) do { if (VERBOSE_PRINTF >= 1) printf x; if (VERBOSE_LOGERROR >= 1) logerror x; } while (0) +#define LOG2(x) do { if (VERBOSE_PRINTF >= 2) printf x; if (VERBOSE_LOGERROR >= 2) logerror x; } while (0) +#define LOG3(x) do { if (VERBOSE_PRINTF >= 3) printf x; if (VERBOSE_LOGERROR >= 3) logerror x; } while (0) +#define LOG4(x) do { if (VERBOSE_PRINTF >= 4) printf x; if (VERBOSE_LOGERROR >= 4) logerror x; } while (0) + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +ALLOW_SAVE_TYPE(eeprom_serial_base_device::eeprom_command); +ALLOW_SAVE_TYPE(eeprom_serial_base_device::eeprom_state); + + + +//************************************************************************** +// BASE DEVICE IMPLEMENTATION +//************************************************************************** + +//------------------------------------------------- +// eeprom_serial_base_device - constructor +//------------------------------------------------- + +eeprom_serial_base_device::eeprom_serial_base_device(const machine_config &mconfig, device_type devtype, const char *name, const char *tag, device_t *owner, const char *shortname, const char *file) + : eeprom_base_device(mconfig, devtype, name, tag, owner, shortname, file), + m_command_address_bits(0), + m_streaming_enabled(false), + m_state(STATE_IN_RESET), + m_cs_state(CLEAR_LINE), + m_last_cs_rising_edge_time(attotime::zero), + m_oe_state(CLEAR_LINE), + m_clk_state(CLEAR_LINE), + m_di_state(CLEAR_LINE), + m_locked(true), + m_bits_accum(0), + m_command_address_accum(0), + m_command(COMMAND_INVALID), + m_address(0), + m_shift_register(0) +{ +} + + +//------------------------------------------------- +// static_set_address_bits - configuration helper +// to set the number of address bits in the +// serial commands +//------------------------------------------------- + +void eeprom_serial_base_device::static_set_address_bits(device_t &device, int addrbits) +{ + downcast(device).m_command_address_bits = addrbits; +} + + +//------------------------------------------------- +// static_enable_streaming - configuration helper +// to enable streaming data +//------------------------------------------------- + +void eeprom_serial_base_device::static_enable_streaming(device_t &device) +{ + downcast(device).m_streaming_enabled = true; +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void eeprom_serial_base_device::device_start() +{ + // if no command address bits set, just inherit from the address bits + if (m_command_address_bits == 0) + m_command_address_bits = m_address_bits; + + // start the base class + eeprom_base_device::device_start(); + + // save the current state + save_item(NAME(m_state)); + save_item(NAME(m_cs_state)); + save_item(NAME(m_oe_state)); + save_item(NAME(m_clk_state)); + save_item(NAME(m_di_state)); + save_item(NAME(m_locked)); + save_item(NAME(m_bits_accum)); + save_item(NAME(m_command_address_accum)); + save_item(NAME(m_command)); + save_item(NAME(m_address)); + save_item(NAME(m_shift_register)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void eeprom_serial_base_device::device_reset() +{ + // reset the base class + eeprom_base_device::device_reset(); + + // reset the state + set_state(STATE_IN_RESET); + m_locked = true; + m_bits_accum = 0; + m_command_address_accum = 0; + m_command = COMMAND_INVALID; + m_address = 0; + m_shift_register = 0; +} + + + +//************************************************************************** +// READ/WRITE HANDLERS +//************************************************************************** + +//------------------------------------------------- +// base_cs_write - set the state of the chip +// select (CS) line +//------------------------------------------------- + +void eeprom_serial_base_device::base_cs_write(int state) +{ + // ignore if the state is not changing + state &= 1; + if (state == m_cs_state) + return; + + // set the new state + LOG4((" cs_write(%d)\n", state)); + m_cs_state = state; + + // remember the rising edge time so we don't process CLK signals at the same time + if (state == ASSERT_LINE) + m_last_cs_rising_edge_time = machine().time(); + handle_event((m_cs_state == ASSERT_LINE) ? EVENT_CS_RISING_EDGE : EVENT_CS_FALLING_EDGE); +} + + +//------------------------------------------------- +// base_clk_write - set the state of the clock +// (CLK) line +//------------------------------------------------- + +void eeprom_serial_base_device::base_clk_write(int state) +{ + // ignore if the state is not changing + state &= 1; + if (state == m_clk_state) + return; + + // set the new state + LOG4((" clk_write(%d)\n", state)); + m_clk_state = state; + handle_event((m_clk_state == ASSERT_LINE) ? EVENT_CLK_RISING_EDGE : EVENT_CLK_FALLING_EDGE); +} + + +//------------------------------------------------- +// base_di_write - set the state of the data input +// (DI) line +//------------------------------------------------- + +void eeprom_serial_base_device::base_di_write(int state) +{ + if (state != 0 && state != 1) + LOG0(("EEPROM: Unexpected data at input 0x%X treated as %d\n", state, state & 1)); + LOG3((" di_write(%d)\n", state)); + m_di_state = state & 1; +} + + +//------------------------------------------------- +// base_do_read - read the state of the data +// output (DO) line +//------------------------------------------------- + +int eeprom_serial_base_device::base_do_read() +{ + // in most states, the output is tristated, and generally connected to a pull up + // to send back a 1 value; the only exception is if reading data and the current output + // bit is a 0 + int result = (m_state == STATE_READING_DATA && ((m_shift_register & 0x80000000) == 0)) ? CLEAR_LINE : ASSERT_LINE; + LOG3((" do_read(%d)\n", result)); + return result; +} + + +//------------------------------------------------- +// base_ready_read - read the state of the +// READY/BUSY line +//------------------------------------------------- + +int eeprom_serial_base_device::base_ready_read() +{ + // ready by default, except during long operations + int result = ready() ? ASSERT_LINE : CLEAR_LINE; + LOG3((" ready_read(%d)\n", result)); + return result; +} + + + +//************************************************************************** +// INTERNAL HELPERS +//************************************************************************** + +//------------------------------------------------- +// set_state - update the state to a new one +//------------------------------------------------- + +void eeprom_serial_base_device::set_state(eeprom_state newstate) +{ +#if (VERBOSE_PRINTF > 0 || VERBOSE_LOGERROR > 0) + // for debugging purposes + static const struct { eeprom_state state; const char *string; } s_state_names[] = + { + { STATE_IN_RESET, "IN_RESET" }, + { STATE_WAIT_FOR_START_BIT, "WAIT_FOR_START_BIT" }, + { STATE_WAIT_FOR_COMMAND, "WAIT_FOR_COMMAND" }, + { STATE_READING_DATA, "READING_DATA" }, + { STATE_WAIT_FOR_DATA, "WAIT_FOR_DATA" }, + { STATE_WAIT_FOR_COMPLETION, "WAIT_FOR_COMPLETION" }, + }; + const char *newstate_string = "UNKNOWN"; + for (int index = 0; index < ARRAY_LENGTH(s_state_names); index++) + if (s_state_names[index].state == newstate) + newstate_string = s_state_names[index].string; + LOG2(("New state: %s\n", newstate_string)); +#endif + + // switch to the new state + m_state = newstate; +} + + +//------------------------------------------------- +// handle_event - handle an event via the state +// machine +//------------------------------------------------- + +void eeprom_serial_base_device::handle_event(eeprom_event event) +{ +#if (VERBOSE_PRINTF > 0 || VERBOSE_LOGERROR > 0) + // for debugging purposes + if ((event & EVENT_CS_RISING_EDGE) != 0) LOG2(("Event: CS rising\n")); + if ((event & EVENT_CS_FALLING_EDGE) != 0) LOG2(("Event: CS falling\n")); + if ((event & EVENT_CLK_RISING_EDGE) != 0) + { + if (m_state == STATE_WAIT_FOR_COMMAND || m_state == STATE_WAIT_FOR_DATA) + LOG2(("Event: CLK rising (%d, DI=%d)\n", m_bits_accum + 1, m_di_state)); + else if (m_state == STATE_READING_DATA) + LOG2(("Event: CLK rising (%d, DO=%d)\n", m_bits_accum + 1, (m_shift_register >> 30) & 1)); + else if (m_state == STATE_WAIT_FOR_START_BIT) + LOG2(("Event: CLK rising (%d)\n", m_di_state)); + else + LOG2(("Event: CLK rising\n")); + } + if ((event & EVENT_CLK_FALLING_EDGE) != 0) LOG4(("Event: CLK falling\n")); +#endif + + // switch off the current state + switch (m_state) + { + // CS is not asserted; wait for a rising CS to move us forward, ignoring all clocks + case STATE_IN_RESET: + if (event == EVENT_CS_RISING_EDGE) + set_state(STATE_WAIT_FOR_START_BIT); + break; + + // CS is asserted; wait for rising clock with a 1 start bit; falling CS will reset us + // note that because each bit is written independently, it is possible for us to receive + // a false rising CLK edge at the exact same time as a rising CS edge; it appears we + // should ignore these edges (makes sense really) + case STATE_WAIT_FOR_START_BIT: + if (event == EVENT_CLK_RISING_EDGE && m_di_state == ASSERT_LINE && ready() && machine().time() > m_last_cs_rising_edge_time) + { + m_command_address_accum = m_bits_accum = 0; + set_state(STATE_WAIT_FOR_COMMAND); + } + else if (event == EVENT_CS_FALLING_EDGE) + set_state(STATE_IN_RESET); + break; + + // CS is asserted; wait for a command to come through; falling CS will reset us + case STATE_WAIT_FOR_COMMAND: + if (event == EVENT_CLK_RISING_EDGE) + { + // if we have enough bits for a command + address, check it out + m_command_address_accum = (m_command_address_accum << 1) | m_di_state; + if (++m_bits_accum == 2 + m_command_address_bits) + execute_command(); + } + else if (event == EVENT_CS_FALLING_EDGE) + set_state(STATE_IN_RESET); + break; + + // CS is asserted; reading data, clock the shift register; falling CS will reset us + case STATE_READING_DATA: + if (event == EVENT_CLK_RISING_EDGE) + { + int bit_index = m_bits_accum++; + + // wrapping the address on multi-read is required by pacslot(cave.c) + if (bit_index % m_data_bits == 0 && (bit_index == 0 || m_streaming_enabled)) + m_shift_register = read((m_address + m_bits_accum / m_data_bits) & ((1 << m_address_bits) - 1)) << (32 - m_data_bits); + else + m_shift_register = (m_shift_register << 1) | 1; + } + else if (event == EVENT_CS_FALLING_EDGE) + { + set_state(STATE_IN_RESET); + if (m_streaming_enabled) + LOG1((" (%d cells read)\n", m_bits_accum / m_data_bits)); + if (!m_streaming_enabled && m_bits_accum > m_data_bits + 1) + LOG0(("EEPROM: Overclocked read by %d bits\n", m_bits_accum - m_data_bits)); + else if (m_streaming_enabled && m_bits_accum > m_data_bits + 1 && m_bits_accum % m_data_bits > 2) + LOG0(("EEPROM: Overclocked read by %d bits\n", m_bits_accum % m_data_bits)); + else if (m_bits_accum < m_data_bits) + LOG0(("EEPROM: CS deasserted in READING_DATA after %d bits\n", m_bits_accum)); + } + break; + + // CS is asserted; waiting for data; clock data through until we accumulate enough; falling CS will reset us + case STATE_WAIT_FOR_DATA: + if (event == EVENT_CLK_RISING_EDGE) + { + m_shift_register = (m_shift_register << 1) | m_di_state; + if (++m_bits_accum == m_data_bits) + execute_write_command(); + } + else if (event == EVENT_CS_FALLING_EDGE) + { + set_state(STATE_IN_RESET); + LOG0(("EEPROM: CS deasserted in STATE_WAIT_FOR_DATA after %d bits\n", m_bits_accum)); + } + break; + + // CS is asserted; waiting for completion; watch for CS falling + case STATE_WAIT_FOR_COMPLETION: + if (event == EVENT_CS_FALLING_EDGE) + set_state(STATE_IN_RESET); + break; + } +} + + +//------------------------------------------------- +// execute_command - execute a command once we +// have enough bits for one +//------------------------------------------------- + +void eeprom_serial_base_device::execute_command() +{ + // parse into a generic command and reset the accumulator count + parse_command_and_address(); + m_bits_accum = 0; + +#if (VERBOSE_PRINTF > 0 || VERBOSE_LOGERROR > 0) + // for debugging purposes + static const struct { eeprom_command command; const char *string; } s_command_names[] = + { + { COMMAND_INVALID, "Execute command: INVALID\n" }, + { COMMAND_READ, "Execute command:READ 0x%X\n" }, + { COMMAND_WRITE, "Execute command:WRITE 0x%X\n" }, + { COMMAND_ERASE, "Execute command:ERASE 0x%X\n" }, + { COMMAND_LOCK, "Execute command:LOCK\n" }, + { COMMAND_UNLOCK, "Execute command:UNLOCK\n" }, + { COMMAND_WRITEALL, "Execute command:WRITEALL\n" }, + { COMMAND_ERASEALL, "Execute command:ERASEALL\n" }, + }; + const char *command_string = s_command_names[0].string; + for (int index = 0; index < ARRAY_LENGTH(s_command_names); index++) + if (s_command_names[index].command == m_command) + command_string = s_command_names[index].string; + LOG1((command_string, m_address)); +#endif + + // each command advances differently + switch (m_command) + { + // advance to the READING_DATA state; data is fetched after first CLK + // reset the shift register to 0 to simulate the dummy 0 bit that happens prior + // to the first clock + case COMMAND_READ: + m_shift_register = 0; + set_state(STATE_READING_DATA); + break; + + // reset the shift register and wait for enough data to be clocked through + case COMMAND_WRITE: + case COMMAND_WRITEALL: + m_shift_register = 0; + set_state(STATE_WAIT_FOR_DATA); + break; + + // erase the parsed address (unless locked) and wait for it to complete + case COMMAND_ERASE: + if (m_locked) + { + LOG0(("EEPROM: Attempt to erase while locked\n")); + set_state(STATE_IN_RESET); + break; + } + erase(m_address); + set_state(STATE_WAIT_FOR_COMPLETION); + break; + + // lock the chip; return to IN_RESET state + case COMMAND_LOCK: + m_locked = true; + set_state(STATE_IN_RESET); + break; + + // unlock the chip; return to IN_RESET state + case COMMAND_UNLOCK: + m_locked = false; + set_state(STATE_IN_RESET); + break; + + // erase the entire chip (unless locked) and wait for it to complete + case COMMAND_ERASEALL: + if (m_locked) + { + LOG0(("EEPROM: Attempt to erase all while locked\n")); + set_state(STATE_IN_RESET); + break; + } + erase_all(); + set_state(STATE_WAIT_FOR_COMPLETION); + break; + + default: + throw emu_fatalerror("execute_command called with invalid command %d\n", m_command); + } +} + + +//------------------------------------------------- +// execute_write_command - execute a write +// command after receiving the data bits +//------------------------------------------------- + +void eeprom_serial_base_device::execute_write_command() +{ +#if (VERBOSE_PRINTF > 0 || VERBOSE_LOGERROR > 0) + // for debugging purposes + static const struct { eeprom_command command; const char *string; } s_command_names[] = + { + { COMMAND_WRITE, "Execute write command: WRITE 0x%X = 0x%X\n" }, + { COMMAND_WRITEALL, "Execute write command: WRITEALL (%X) = 0x%X\n" }, + }; + const char *command_string = "UNKNOWN"; + for (int index = 0; index < ARRAY_LENGTH(s_command_names); index++) + if (s_command_names[index].command == m_command) + command_string = s_command_names[index].string; + LOG1((command_string, m_address, m_shift_register)); +#endif + + // each command advances differently + switch (m_command) + { + // reset the shift register and wait for enough data to be clocked through + case COMMAND_WRITE: + if (m_locked) + { + LOG0(("EEPROM: Attempt to write to address 0x%X while locked\n", m_address)); + set_state(STATE_IN_RESET); + break; + } + write(m_address, m_shift_register); + set_state(STATE_WAIT_FOR_COMPLETION); + break; + + // write the entire EEPROM with the same data; ERASEALL is required before so we + // AND against the already-present data + case COMMAND_WRITEALL: + if (m_locked) + { + LOG0(("EEPROM: Attempt to write all while locked\n")); + set_state(STATE_IN_RESET); + break; + } + write_all(m_shift_register); + set_state(STATE_WAIT_FOR_COMPLETION); + break; + + default: + throw emu_fatalerror("execute_write_command called with invalid command %d\n", m_command); + } +} + + + +//************************************************************************** +// STANDARD INTERFACE IMPLEMENTATION +//************************************************************************** + +//------------------------------------------------- +// eeprom_serial_93cxx_device - constructor +//------------------------------------------------- + +eeprom_serial_93cxx_device::eeprom_serial_93cxx_device(const machine_config &mconfig, device_type devtype, const char *name, const char *tag, device_t *owner, const char *shortname, const char *file) + : eeprom_serial_base_device(mconfig, devtype, name, tag, owner, shortname, file) +{ +} + + +//------------------------------------------------- +// parse_command_and_address - extract the +// command and address from a bitstream +//------------------------------------------------- + +void eeprom_serial_93cxx_device::parse_command_and_address() +{ + // set the defaults + m_command = COMMAND_INVALID; + m_address = m_command_address_accum & ((1 << m_command_address_bits) - 1); + + // extract the command portion and handle it + switch (m_command_address_accum >> m_command_address_bits) + { + // opcode 0 needs two more bits to decode the operation + case 0: + switch (m_address >> (m_command_address_bits - 2)) + { + case 0: m_command = COMMAND_LOCK; break; + case 1: m_command = COMMAND_WRITEALL; break; + case 2: m_command = COMMAND_ERASEALL; break; + case 3: m_command = COMMAND_UNLOCK; break; + } + m_address = 0; + break; + case 1: m_command = COMMAND_WRITE; break; + case 2: m_command = COMMAND_READ; break; + case 3: m_command = COMMAND_ERASE; break; + } + + // warn about out-of-range addresses + if (m_address >= (1 << m_address_bits)) + LOG0(("EEPROM: out-of-range address 0x%X provided (maximum should be 0x%X)\n", m_address, (1 << m_address_bits) - 1)); +} + + +//------------------------------------------------- +// do_read - read handlers +//------------------------------------------------- + +READ_LINE_MEMBER(eeprom_serial_93cxx_device::do_read) { return base_do_read() & ((m_state == STATE_WAIT_FOR_START_BIT) ? base_ready_read() : 1); } + + +//------------------------------------------------- +// cs_write/clk_write/di_write - write handlers +//------------------------------------------------- + +WRITE_LINE_MEMBER(eeprom_serial_93cxx_device::cs_write) { base_cs_write(state); } +WRITE_LINE_MEMBER(eeprom_serial_93cxx_device::clk_write) { base_clk_write(state); } +WRITE_LINE_MEMBER(eeprom_serial_93cxx_device::di_write) { base_di_write(state); } + + + +//************************************************************************** +// ER5911 DEVICE IMPLEMENTATION +//************************************************************************** + +//------------------------------------------------- +// eeprom_serial_er5911_device - constructor +//------------------------------------------------- + +eeprom_serial_er5911_device::eeprom_serial_er5911_device(const machine_config &mconfig, device_type devtype, const char *name, const char *tag, device_t *owner, const char *shortname, const char *file) + : eeprom_serial_base_device(mconfig, devtype, name, tag, owner, shortname, file) +{ +} + + +//------------------------------------------------- +// parse_command_and_address - extract the +// command and address from a bitstream +//------------------------------------------------- + +void eeprom_serial_er5911_device::parse_command_and_address() +{ + // set the defaults + m_command = COMMAND_INVALID; + m_address = m_command_address_accum & ((1 << m_command_address_bits) - 1); + + // extract the command portion and handle it + switch (m_command_address_accum >> m_command_address_bits) + { + // opcode 0 needs two more bits to decode the operation + case 0: + switch (m_address >> (m_command_address_bits - 2)) + { + case 0: m_command = COMMAND_LOCK; break; + case 1: m_command = COMMAND_INVALID; break; // not on ER5911 + case 2: m_command = COMMAND_ERASEALL; break; + case 3: m_command = COMMAND_UNLOCK; break; + } + m_address = 0; + break; + case 1: m_command = COMMAND_WRITE; break; + case 2: m_command = COMMAND_READ; break; + case 3: m_command = COMMAND_WRITE; break; // WRITE instead of ERASE on ER5911 + } + + // warn about out-of-range addresses + if (m_address >= (1 << m_address_bits)) + LOG0(("EEPROM: out-of-range address 0x%X provided (maximum should be 0x%X)\n", m_address, (1 << m_address_bits) - 1)); +} + + +//------------------------------------------------- +// do_read/ready_read - read handlers +//------------------------------------------------- + +READ_LINE_MEMBER(eeprom_serial_er5911_device::do_read) { return base_do_read(); } +READ_LINE_MEMBER(eeprom_serial_er5911_device::ready_read) { return base_ready_read(); } + + +//------------------------------------------------- +// cs_write/clk_write/di_write - write handlers +//------------------------------------------------- + +WRITE_LINE_MEMBER(eeprom_serial_er5911_device::cs_write) { base_cs_write(state); } +WRITE_LINE_MEMBER(eeprom_serial_er5911_device::clk_write) { base_clk_write(state); } +WRITE_LINE_MEMBER(eeprom_serial_er5911_device::di_write) { base_di_write(state); } + + + +//************************************************************************** +// X24c44 DEVICE IMPLEMENTATION +//************************************************************************** + +//------------------------------------------------- +// eeprom_serial_x24c44_device - constructor +//------------------------------------------------- + +eeprom_serial_x24c44_device::eeprom_serial_x24c44_device(const machine_config &mconfig, device_type devtype, const char *name, const char *tag, device_t *owner, const char *shortname, const char *file) + : eeprom_serial_base_device(mconfig, devtype, name, tag, owner, shortname, file) +{ +} + + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void eeprom_serial_x24c44_device::device_start() +{ + // if no command address bits set, just inherit from the address bits + if (m_command_address_bits == 0) + m_command_address_bits = m_address_bits; + + // start the base class + eeprom_base_device::device_start(); + + INT16 i=0; + m_ram_length=0xf; + + for (i=0;i<16;i++){ + m_ram_data[i]=read(i); //autoreload at power up + } + m_reading=0; + m_store_latch=0; + // save the current state + save_item(NAME(m_state)); + save_item(NAME(m_cs_state)); + save_item(NAME(m_oe_state)); + save_item(NAME(m_clk_state)); + save_item(NAME(m_di_state)); + save_item(NAME(m_locked)); + save_item(NAME(m_bits_accum)); + save_item(NAME(m_command_address_accum)); + save_item(NAME(m_command)); + save_item(NAME(m_address)); + save_item(NAME(m_shift_register)); + save_item(NAME(m_ram_data)); + save_item(NAME(m_reading)); + save_item(NAME(m_store_latch)); +} + +void eeprom_serial_x24c44_device::copy_eeprom_to_ram(){ + UINT16 i=0; + LOG1(("EEPROM TO RAM COPY!!!\n")); + for (i=0;i<16;i++){ + m_ram_data[i]=read(i); + } + m_store_latch=1; +} + + + +void eeprom_serial_x24c44_device::copy_ram_to_eeprom(){ + UINT16 i=0; + if (m_store_latch){ + LOG1(("RAM TO EEPROM COPY\n")); + for (i=0;i<16;i++){ + write(i, m_ram_data[i]); + } + m_store_latch=0; + }else{ + LOG0(("Store command with store latch not set!\n")); + } + +} + +//------------------------------------------------- +// execute_command - execute a command once we +// have enough bits for one +//------------------------------------------------- + +void eeprom_serial_x24c44_device::execute_command() +{ + // parse into a generic command and reset the accumulator count + parse_command_and_address(); + m_bits_accum = 0; + +#if (VERBOSE_PRINTF > 0 || VERBOSE_LOGERROR > 0) + // for debugging purposes + static const struct { eeprom_command command; const char *string; } s_command_names[] = + { + { COMMAND_INVALID, "Execute command: INVALID\n" }, + { COMMAND_READ, "Execute command:READ 0x%X\n" }, + { COMMAND_WRITE, "Execute command:WRITE 0x%X\n" }, + { COMMAND_ERASE, "Execute command:ERASE 0x%X\n" }, + { COMMAND_LOCK, "Execute command:LOCK\n" }, + { COMMAND_UNLOCK, "Execute command:UNLOCK\n" }, + { COMMAND_WRITEALL, "Execute command:WRITEALL\n" }, + { COMMAND_ERASEALL, "Execute command:ERASEALL\n" }, + { COMMAND_COPY_EEPROM_TO_RAM, "Execute command:COPY_EEPROM_TO_RAM\n" }, + { COMMAND_COPY_RAM_TO_EEPROM, "Execute command:COPY_RAM_TO_EEPROM\n" }, + }; + const char *command_string = s_command_names[0].string; + for (int index = 0; index < ARRAY_LENGTH(s_command_names); index++) + if (s_command_names[index].command == m_command) + command_string = s_command_names[index].string; + LOG1((command_string, m_address)); +#endif + + // each command advances differently + switch (m_command) + { + // advance to the READING_DATA state; data is fetched after first CLK + // reset the shift register to 0 to simulate the dummy 0 bit that happens prior + // to the first clock + + // reset the shift register and wait for enough data to be clocked through + case COMMAND_WRITE: + m_shift_register = 0; + set_state(STATE_WAIT_FOR_DATA); + break; + + // lock the chip; return to IN_RESET state + case COMMAND_LOCK: + m_locked = true; + m_store_latch=0; + set_state(STATE_IN_RESET); + break; + + // unlock the chip; return to IN_RESET state + case COMMAND_UNLOCK: + m_locked = false; + m_store_latch=1; + set_state(STATE_IN_RESET); + break; + + // copy eeprom to ram + case COMMAND_COPY_EEPROM_TO_RAM: + copy_eeprom_to_ram(); + set_state(STATE_IN_RESET); + break; + + // copy ram into eeprom + case COMMAND_COPY_RAM_TO_EEPROM: + copy_ram_to_eeprom(); + set_state(STATE_IN_RESET); + break; + + default: + throw emu_fatalerror("execute_command called with invalid command %d\n", m_command); + } +} + + +void eeprom_serial_x24c44_device::handle_event(eeprom_event event) +{ +//UINT32 tmp=0; +#if (VERBOSE_PRINTF > 0 || VERBOSE_LOGERROR > 0) + // for debugging purposes + if ((event & EVENT_CS_RISING_EDGE) != 0) LOG2(("Event: CS rising\n")); + if ((event & EVENT_CS_FALLING_EDGE) != 0) LOG2(("Event: CS falling\n")); + if ((event & EVENT_CLK_RISING_EDGE) != 0) + { + if (m_state == STATE_WAIT_FOR_COMMAND || m_state == STATE_WAIT_FOR_DATA) + LOG2(("Event: CLK rising (%d, DI=%d)\n", m_bits_accum + 1, m_di_state)); + else if (m_state == STATE_READING_DATA) + LOG2(("Event: CLK rising (%d, DO=%d)\n", m_bits_accum + 1, (m_shift_register >> 30) & 1)); + else if (m_state == STATE_WAIT_FOR_START_BIT) + LOG2(("Event: CLK rising (%d)\n", m_di_state)); + else + LOG2(("Event: CLK rising\n")); + } + if ((event & EVENT_CLK_FALLING_EDGE) != 0) LOG4(("Event: CLK falling\n")); +#endif + + // switch off the current state + switch (m_state) + { + // CS is not asserted; wait for a rising CS to move us forward, ignoring all clocks + case STATE_IN_RESET: + if (event == EVENT_CS_RISING_EDGE) + set_state(STATE_WAIT_FOR_START_BIT); + break; + + // CS is asserted; wait for rising clock with a 1 start bit; falling CS will reset us + // note that because each bit is written independently, it is possible for us to receive + // a false rising CLK edge at the exact same time as a rising CS edge; it appears we + // should ignore these edges (makes sense really) + case STATE_WAIT_FOR_START_BIT: + if (event == EVENT_CLK_RISING_EDGE && m_di_state == ASSERT_LINE && ready() && machine().time() > m_last_cs_rising_edge_time) + { + m_command_address_accum = m_bits_accum = 0; + set_state(STATE_WAIT_FOR_COMMAND); + } + else if (event == EVENT_CS_FALLING_EDGE) + set_state(STATE_IN_RESET); + break; + + // CS is asserted; wait for a command to come through; falling CS will reset us + case STATE_WAIT_FOR_COMMAND: + if (event == EVENT_CLK_RISING_EDGE) + { + // if we have enough bits for a command + address, check it out + m_command_address_accum = (m_command_address_accum << 1) | m_di_state; + + m_bits_accum=m_bits_accum+1; + + if (m_bits_accum == 2 + m_command_address_bits){ + //read command is only 2 bits all other are 3 bits!!! + + parse_command_and_address_2_bit(); + + } + + if (!m_reading){ + if (m_bits_accum == 3 + m_command_address_bits){ + execute_command(); + } + } + } + else if (event == EVENT_CS_FALLING_EDGE) + set_state(STATE_IN_RESET); + break; + + // CS is asserted; reading data, clock the shift register; falling CS will reset us + case STATE_READING_DATA: + if (event == EVENT_CLK_RISING_EDGE) + { + int bit_index = m_bits_accum++; + + if (bit_index % m_data_bits == 0 && (bit_index == 0 || m_streaming_enabled)){ + m_shift_register=m_ram_data[m_address]; + + //m_shift_register=BITSWAP16(m_shift_register,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15); + //m_shift_register=BITSWAP16(m_shift_register,7,6,5,4,3,2,1,0,15,14,13,12,11,10,9,8); + m_shift_register= BITSWAP16(m_shift_register,8,9,10,11,12,13,14,15,0,1,2,3,4,5,6,7); + + m_shift_register=m_shift_register<<16; + + LOG1(("read from RAM addr %02X data(from ram) %04X ,m_shift_register vale %04X \n",m_address,m_ram_data[m_address],m_shift_register)); + } + else{ + m_shift_register = (m_shift_register << 1) | 1; + + } + } + else if (event == EVENT_CS_FALLING_EDGE) + { + set_state(STATE_IN_RESET); + m_reading=0; + if (m_streaming_enabled) + LOG1((" (%d cells read)\n", m_bits_accum / m_data_bits)); + if (!m_streaming_enabled && m_bits_accum > m_data_bits + 1) + LOG1(("EEPROM: Overclocked read by %d bits\n", m_bits_accum - m_data_bits)); + else if (m_streaming_enabled && m_bits_accum > m_data_bits + 1 && m_bits_accum % m_data_bits > 2) + LOG1(("EEPROM: Overclocked read by %d bits\n", m_bits_accum % m_data_bits)); + else if (m_bits_accum < m_data_bits) + LOG1(("EEPROM: CS deasserted in READING_DATA after %d bits\n", m_bits_accum)); + } + break; + + // CS is asserted; waiting for data; clock data through until we accumulate enough; falling CS will reset us + case STATE_WAIT_FOR_DATA: + if (event == EVENT_CLK_RISING_EDGE) + { + m_shift_register = (m_shift_register << 1) | m_di_state; + if (++m_bits_accum == m_data_bits){ + //m_shift_register=BITSWAP16(m_shift_register, 0, 1, 2, 3, 4, 5,6,7, 8, 9,10,11,12,13,14,15); + //m_shift_register=BITSWAP16(m_shift_register, 7, 6, 5, 4, 3, 2,1,0,15,14,13,12,11,10, 9, 8); + m_shift_register=BITSWAP16(m_shift_register,8,9,10,11,12,13,14,15,0,1,2,3,4,5,6,7); + m_ram_data[m_address]=m_shift_register; + + LOG1(("write to RAM addr=%02X data=%04X\n",m_address,m_shift_register)); + } + } + else if (event == EVENT_CS_FALLING_EDGE) + { + set_state(STATE_IN_RESET); + LOG1(("EEPROM: CS deasserted in STATE_WAIT_FOR_DATA after %d bits\n", m_bits_accum)); + } + break; + + + // CS is asserted; waiting for completion; watch for CS falling + case STATE_WAIT_FOR_COMPLETION: + if (event == EVENT_CS_FALLING_EDGE) + set_state(STATE_IN_RESET); + break; + } +} + + +//------------------------------------------------- +// parse_command_and_address - extract the +// command and address from a bitstream +//------------------------------------------------- + +void eeprom_serial_x24c44_device::parse_command_and_address() +{ + //command is start_bit - 4bit_address - 3bit_command + + // set the defaults + m_command = COMMAND_INVALID; + + m_address = (m_command_address_accum >> 3) & 0x0f; + + LOG1(("EEPROM: command= %04X, address %02X\n", m_command_address_accum& 0x07, m_address)); + + switch (m_command_address_accum & 0x07) + { + case 0: //reset write enable latch + LOG0(("Lock eeprom\n")); + m_command = COMMAND_LOCK; break; + case 3: //write data into ram + LOG0(("Write to ram\n")); + m_command = COMMAND_WRITE; break; + case 4: //set write enable latch + LOG0(("Unlock eeprom\n")); + m_command = COMMAND_UNLOCK; break; + case 1: //store ram data in eeprom + LOG0(("copy ram to eeprom\n")); + m_command = COMMAND_COPY_RAM_TO_EEPROM; break; + case 5: //reload eeprom data into ram + LOG0(("copy eeprom to ram\n")); + m_command = COMMAND_COPY_EEPROM_TO_RAM; break; + case 2: //reserved (Sleep on x2444) + m_command = COMMAND_INVALID; + break; + + } + +} + +void eeprom_serial_x24c44_device::parse_command_and_address_2_bit() +{ + if ((m_command_address_accum & 0x03) == 0x03){ + m_command = COMMAND_READ; + m_address = ((m_command_address_accum >> 2) & 0x0f); + m_shift_register = 0; + set_state(STATE_READING_DATA); + LOG1(("parse command_and_address_2_bit found a read command\n")); + m_reading=1; + m_bits_accum=0; + } + + // warn about out-of-range addresses + if (m_address >= (1 << m_address_bits)) + LOG1(("EEPROM: out-of-range address 0x%X provided (maximum should be 0x%X)\n", m_address, (1 << m_address_bits) - 1)); +} + + +//------------------------------------------------- +// do_read/ready_read - read handlers +//------------------------------------------------- + +READ_LINE_MEMBER(eeprom_serial_x24c44_device::do_read) { return base_do_read(); } + + +//------------------------------------------------- +// cs_write/clk_write/di_write - write handlers +//------------------------------------------------- + +WRITE_LINE_MEMBER(eeprom_serial_x24c44_device::cs_write) { base_cs_write(state); } +WRITE_LINE_MEMBER(eeprom_serial_x24c44_device::clk_write) { base_clk_write(state); } +WRITE_LINE_MEMBER(eeprom_serial_x24c44_device::di_write) { base_di_write(state); } + + +//************************************************************************** +// DERIVED TYPES +//************************************************************************** + +// macro for defining a new device class +#define DEFINE_SERIAL_EEPROM_DEVICE(_baseclass, _lowercase, _uppercase, _bits, _cells, _addrbits) \ +eeprom_serial_##_lowercase##_##_bits##bit_device::eeprom_serial_##_lowercase##_##_bits##bit_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) \ + : eeprom_serial_##_baseclass##_device(mconfig, EEPROM_SERIAL_##_uppercase##_##_bits##BIT, "Serial EEPROM " #_uppercase " (" #_cells "x" #_bits ")", tag, owner, #_lowercase "_" #_bits, __FILE__) \ +{ \ + static_set_size(*this, _cells, _bits); \ + static_set_address_bits(*this, _addrbits); \ +} \ +const device_type EEPROM_SERIAL_##_uppercase##_##_bits##BIT = &device_creator; +// standard 93CX6 class of 16-bit EEPROMs +DEFINE_SERIAL_EEPROM_DEVICE(93cxx, 93c06, 93C06, 16, 16, 6) +DEFINE_SERIAL_EEPROM_DEVICE(93cxx, 93c46, 93C46, 16, 64, 6) +DEFINE_SERIAL_EEPROM_DEVICE(93cxx, 93c56, 93C56, 16, 128, 8) +DEFINE_SERIAL_EEPROM_DEVICE(93cxx, 93c57, 93C57, 16, 128, 7) +DEFINE_SERIAL_EEPROM_DEVICE(93cxx, 93c66, 93C66, 16, 256, 8) +DEFINE_SERIAL_EEPROM_DEVICE(93cxx, 93c76, 93C76, 16, 512, 10) +DEFINE_SERIAL_EEPROM_DEVICE(93cxx, 93c86, 93C86, 16, 1024, 10) + +// some manufacturers use pin 6 as an "ORG" pin which, when pulled low, configures memory for 8-bit accesses +DEFINE_SERIAL_EEPROM_DEVICE(93cxx, 93c46, 93C46, 8, 128, 7) +DEFINE_SERIAL_EEPROM_DEVICE(93cxx, 93c56, 93C56, 8, 256, 9) +DEFINE_SERIAL_EEPROM_DEVICE(93cxx, 93c57, 93C57, 8, 256, 8) +DEFINE_SERIAL_EEPROM_DEVICE(93cxx, 93c66, 93C66, 8, 512, 9) +DEFINE_SERIAL_EEPROM_DEVICE(93cxx, 93c76, 93C76, 8, 1024, 11) +DEFINE_SERIAL_EEPROM_DEVICE(93cxx, 93c86, 93C86, 8, 2048, 11) + +// ER5911 has a separate ready pin, a reduced command set, and supports 8/16 bit out of the box +DEFINE_SERIAL_EEPROM_DEVICE(er5911, er5911, ER5911, 8, 128, 9) +DEFINE_SERIAL_EEPROM_DEVICE(er5911, er5911, ER5911, 16, 64, 8) +DEFINE_SERIAL_EEPROM_DEVICE(er5911, msm16911, MSM16911, 8, 128, 9) +DEFINE_SERIAL_EEPROM_DEVICE(er5911, msm16911, MSM16911, 16, 64, 8) + +// X24c44 8 bit 32byte ram/eeprom combo +DEFINE_SERIAL_EEPROM_DEVICE(x24c44, x24c44, X24C44, 16, 16, 4) diff --git a/src/devices/machine/eepromser.h b/src/devices/machine/eepromser.h new file mode 100644 index 00000000000..49161ba883f --- /dev/null +++ b/src/devices/machine/eepromser.h @@ -0,0 +1,295 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + eepromser.h + + Serial EEPROM devices. + +***************************************************************************/ + +#pragma once + +#ifndef __EEPROMSER_H__ +#define __EEPROMSER_H__ + +#include "eeprom.h" + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +// standard 93CX6 class of 16-bit EEPROMs +#define MCFG_EEPROM_SERIAL_93C06_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, EEPROM_SERIAL_93C06_16BIT, 0) +#define MCFG_EEPROM_SERIAL_93C46_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, EEPROM_SERIAL_93C46_16BIT, 0) +#define MCFG_EEPROM_SERIAL_93C56_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, EEPROM_SERIAL_93C56_16BIT, 0) +#define MCFG_EEPROM_SERIAL_93C57_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, EEPROM_SERIAL_93C57_16BIT, 0) +#define MCFG_EEPROM_SERIAL_93C66_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, EEPROM_SERIAL_93C66_16BIT, 0) +#define MCFG_EEPROM_SERIAL_93C76_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, EEPROM_SERIAL_93C76_16BIT, 0) +#define MCFG_EEPROM_SERIAL_93C86_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, EEPROM_SERIAL_93C86_16BIT, 0) + +// some manufacturers use pin 6 as an "ORG" pin which, when pulled low, configures memory for 8-bit accesses +#define MCFG_EEPROM_SERIAL_93C46_8BIT_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, EEPROM_SERIAL_93C46_8BIT, 0) +#define MCFG_EEPROM_SERIAL_93C56_8BIT_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, EEPROM_SERIAL_93C56_8BIT, 0) +#define MCFG_EEPROM_SERIAL_93C57_8BIT_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, EEPROM_SERIAL_93C57_8BIT, 0) +#define MCFG_EEPROM_SERIAL_93C66_8BIT_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, EEPROM_SERIAL_93C66_8BIT, 0) +#define MCFG_EEPROM_SERIAL_93C76_8BIT_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, EEPROM_SERIAL_93C76_8BIT, 0) +#define MCFG_EEPROM_SERIAL_93C86_8BIT_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, EEPROM_SERIAL_93C86_8BIT, 0) + +// ER5911 has a separate ready pin, a reduced command set, and supports 8/16 bit out of the box +#define MCFG_EEPROM_SERIAL_ER5911_8BIT_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, EEPROM_SERIAL_ER5911_8BIT, 0) +#define MCFG_EEPROM_SERIAL_ER5911_16BIT_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, EEPROM_SERIAL_ER5911_16BIT, 0) + +#define MCFG_EEPROM_SERIAL_MSM16911_8BIT_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, EEPROM_SERIAL_MSM16911_8BIT, 0) +#define MCFG_EEPROM_SERIAL_MSM16911_16BIT_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, EEPROM_SERIAL_MSM16911_16BIT, 0) + +// X24c44 16 bit ram/eeprom combo +#define MCFG_EEPROM_SERIAL_X24C44_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, EEPROM_SERIAL_X24C44_16BIT, 0) + +// optional enable for streaming reads +#define MCFG_EEPROM_SERIAL_ENABLE_STREAMING() \ + eeprom_serial_base_device::static_enable_streaming(*device); +// pass-throughs to the base class for setting default data +#define MCFG_EEPROM_SERIAL_DATA MCFG_EEPROM_DATA +#define MCFG_EEPROM_SERIAL_DEFAULT_VALUE MCFG_EEPROM_DEFAULT_VALUE + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + + +// ======================> eeprom_serial_base_device + +class eeprom_serial_base_device : public eeprom_base_device +{ +protected: + // construction/destruction + eeprom_serial_base_device(const machine_config &mconfig, device_type devtype, const char *name, const char *tag, device_t *owner, const char *shortname, const char *file); + +public: + // inline configuration helpers + static void static_set_address_bits(device_t &device, int addrbits); + static void static_enable_streaming(device_t &device); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // read interfaces differ between implementations + + // commands + enum eeprom_command + { + COMMAND_INVALID, + COMMAND_READ, + COMMAND_WRITE, + COMMAND_ERASE, + COMMAND_LOCK, + COMMAND_UNLOCK, + COMMAND_WRITEALL, + COMMAND_ERASEALL, + COMMAND_COPY_EEPROM_TO_RAM, + COMMAND_COPY_RAM_TO_EEPROM + }; + + // states + enum eeprom_state + { + STATE_IN_RESET, + STATE_WAIT_FOR_START_BIT, + STATE_WAIT_FOR_COMMAND, + STATE_READING_DATA, + STATE_WAIT_FOR_DATA, + STATE_WAIT_FOR_COMPLETION + }; + + // events + enum eeprom_event + { + EVENT_CS_RISING_EDGE = 1 << 0, + EVENT_CS_FALLING_EDGE = 1 << 1, + EVENT_CLK_RISING_EDGE = 1 << 2, + EVENT_CLK_FALLING_EDGE = 1 << 3 + }; + + // internal helpers + void set_state(eeprom_state newstate); + void execute_write_command(); + + // subclass helpers + void base_cs_write(int state); + void base_clk_write(int state); + void base_di_write(int state); + int base_do_read(); + int base_ready_read(); + + // subclass overrides + virtual void handle_event(eeprom_event event); + virtual void parse_command_and_address() = 0; + virtual void execute_command(); + + + // configuration state + UINT8 m_command_address_bits; // number of address bits in a command + bool m_streaming_enabled; // true if streaming is enabled + + // runtime state + eeprom_state m_state; // current internal state + UINT8 m_cs_state; // state of the CS line + attotime m_last_cs_rising_edge_time; // time of the last CS rising edge + UINT8 m_oe_state; // state of the OE line + UINT8 m_clk_state; // state of the CLK line + UINT8 m_di_state; // state of the DI line + bool m_locked; // are we locked against writes? + UINT32 m_bits_accum; // number of bits accumulated + UINT32 m_command_address_accum; // accumulator of command+address bits + eeprom_command m_command; // current command + UINT32 m_address; // current address extracted from command + UINT32 m_shift_register; // holds data coming in/going out +}; + + + +// ======================> eeprom_serial_93cxx_device + +class eeprom_serial_93cxx_device : public eeprom_serial_base_device +{ +protected: + // construction/destruction + eeprom_serial_93cxx_device(const machine_config &mconfig, device_type devtype, const char *name, const char *tag, device_t *owner, const char *shortname, const char *file); + +public: + // read handlers + DECLARE_READ_LINE_MEMBER(do_read); // combined DO+READY/BUSY + + // write handlers + DECLARE_WRITE_LINE_MEMBER(cs_write); // CS signal (active high) + DECLARE_WRITE_LINE_MEMBER(clk_write); // CLK signal (active high) + DECLARE_WRITE_LINE_MEMBER(di_write); // DI + +protected: + // subclass overrides + virtual void parse_command_and_address(); +}; + + +// ======================> eeprom_serial_er5911_device + +class eeprom_serial_er5911_device : public eeprom_serial_base_device +{ +protected: + // construction/destruction + eeprom_serial_er5911_device(const machine_config &mconfig, device_type devtype, const char *name, const char *tag, device_t *owner, const char *shortname, const char *file); + +public: + // read handlers + DECLARE_READ_LINE_MEMBER(do_read); // DO + DECLARE_READ_LINE_MEMBER(ready_read); // READY/BUSY only + + // write handlers + DECLARE_WRITE_LINE_MEMBER(cs_write); // CS signal (active high) + DECLARE_WRITE_LINE_MEMBER(clk_write); // CLK signal (active high) + DECLARE_WRITE_LINE_MEMBER(di_write); // DI + +protected: + // subclass overrides + virtual void parse_command_and_address(); +}; + + +// ======================> eeprom_serial_x24c44_device + +class eeprom_serial_x24c44_device : public eeprom_serial_base_device +{ + //async recall not implemented + //async store not implemented +protected: + // construction/destruction + eeprom_serial_x24c44_device(const machine_config &mconfig, device_type devtype, const char *name, const char *tag, device_t *owner, const char *shortname, const char *file); + +public: + // read handlers + DECLARE_READ_LINE_MEMBER(do_read); // DO + + // write handlers + DECLARE_WRITE_LINE_MEMBER(cs_write); // CS signal (active high) + DECLARE_WRITE_LINE_MEMBER(clk_write); // CLK signal (active high) + DECLARE_WRITE_LINE_MEMBER(di_write); // DI + +protected: + // subclass overrides + virtual void parse_command_and_address(); + void handle_event(eeprom_event event); + virtual void parse_command_and_address_2_bit(); + void execute_command(); + void copy_ram_to_eeprom(); + void copy_eeprom_to_ram(); + void device_start(); + UINT8 m_ram_length; + UINT16 m_ram_data[16]; + UINT16 m_reading; + UINT8 m_store_latch; +}; + + + +//************************************************************************** +// DERIVED TYPES +//************************************************************************** + +// macro for declaring a new device class +#define DECLARE_SERIAL_EEPROM_DEVICE(_baseclass, _lowercase, _uppercase, _bits) \ +class eeprom_serial_##_lowercase##_##_bits##bit_device : public eeprom_serial_##_baseclass##_device \ +{ \ +public: \ + eeprom_serial_##_lowercase##_##_bits##bit_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); \ +}; \ +extern const device_type EEPROM_SERIAL_##_uppercase##_##_bits##BIT; +// standard 93CX6 class of 16-bit EEPROMs +DECLARE_SERIAL_EEPROM_DEVICE(93cxx, 93c06, 93C06, 16) +DECLARE_SERIAL_EEPROM_DEVICE(93cxx, 93c46, 93C46, 16) +DECLARE_SERIAL_EEPROM_DEVICE(93cxx, 93c56, 93C56, 16) +DECLARE_SERIAL_EEPROM_DEVICE(93cxx, 93c57, 93C57, 16) +DECLARE_SERIAL_EEPROM_DEVICE(93cxx, 93c66, 93C66, 16) +DECLARE_SERIAL_EEPROM_DEVICE(93cxx, 93c76, 93C76, 16) +DECLARE_SERIAL_EEPROM_DEVICE(93cxx, 93c86, 93C86, 16) + +// some manufacturers use pin 6 as an "ORG" pin which, when pulled low, configures memory for 8-bit accesses +DECLARE_SERIAL_EEPROM_DEVICE(93cxx, 93c46, 93C46, 8) +DECLARE_SERIAL_EEPROM_DEVICE(93cxx, 93c56, 93C56, 8) +DECLARE_SERIAL_EEPROM_DEVICE(93cxx, 93c57, 93C57, 8) +DECLARE_SERIAL_EEPROM_DEVICE(93cxx, 93c66, 93C66, 8) +DECLARE_SERIAL_EEPROM_DEVICE(93cxx, 93c76, 93C76, 8) +DECLARE_SERIAL_EEPROM_DEVICE(93cxx, 93c86, 93C86, 8) + +// ER5911 has a separate ready pin, a reduced command set, and supports 8/16 bit out of the box +DECLARE_SERIAL_EEPROM_DEVICE(er5911, er5911, ER5911, 8) +DECLARE_SERIAL_EEPROM_DEVICE(er5911, er5911, ER5911, 16) +DECLARE_SERIAL_EEPROM_DEVICE(er5911, msm16911, MSM16911, 8) +DECLARE_SERIAL_EEPROM_DEVICE(er5911, msm16911, MSM16911, 16) + +// X24c44 8 bit 32byte ram/eeprom combo +DECLARE_SERIAL_EEPROM_DEVICE(x24c44, x24c44, X24C44, 16) +#endif diff --git a/src/devices/machine/er2055.c b/src/devices/machine/er2055.c new file mode 100644 index 00000000000..24ab1766744 --- /dev/null +++ b/src/devices/machine/er2055.c @@ -0,0 +1,177 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + er2055.c + + GI 512 bit electrically alterable read-only memory. + +***************************************************************************/ + +#include "emu.h" +#include "machine/er2055.h" + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +// device type definition +const device_type ER2055 = &device_creator; + +static ADDRESS_MAP_START( er2055_map, AS_PROGRAM, 8, er2055_device ) + AM_RANGE(0x0000, 0x003f) AM_RAM +ADDRESS_MAP_END + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// er2055_device - constructor +//------------------------------------------------- + +er2055_device::er2055_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, ER2055, "ER2055 EAROM", tag, owner, clock, "er2055", __FILE__), + device_memory_interface(mconfig, *this), + device_nvram_interface(mconfig, *this), + m_space_config("EAROM", ENDIANNESS_BIG, 8, 6, 0, *ADDRESS_MAP_NAME(er2055_map)), + m_control_state(0), + m_address(0), + m_data(0) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void er2055_device::device_start() +{ + save_item(NAME(m_control_state)); + save_item(NAME(m_address)); + save_item(NAME(m_data)); + + m_control_state = 0; +} + + +//------------------------------------------------- +// memory_space_config - return a description of +// any address spaces owned by this device +//------------------------------------------------- + +const address_space_config *er2055_device::memory_space_config(address_spacenum spacenum) const +{ + return (spacenum == 0) ? &m_space_config : NULL; +} + + +//------------------------------------------------- +// nvram_default - called to initialize NVRAM to +// its default state +//------------------------------------------------- + +void er2055_device::nvram_default() +{ + // default to all-0xff + for (int byte = 0; byte < SIZE_DATA; byte++) + m_addrspace[0]->write_byte(byte, 0xff); + + // populate from a memory region if present + if (m_region != NULL) + { + if (m_region->bytes() != SIZE_DATA) + fatalerror("er2055 region '%s' wrong size (expected size = 0x40)\n", tag()); + if (m_region->bytewidth() != 1) + fatalerror("er2055 region '%s' needs to be an 8-bit region\n", tag()); + + UINT8 *default_data = m_region->base(); + for (int byte = 0; byte < SIZE_DATA; byte++) + m_addrspace[0]->write_byte(byte, default_data[byte]); + } +} + + +//------------------------------------------------- +// nvram_read - called to read NVRAM from the +// .nv file +//------------------------------------------------- + +void er2055_device::nvram_read(emu_file &file) +{ + UINT8 buffer[SIZE_DATA]; + file.read(buffer, sizeof(buffer)); + for (int byte = 0; byte < SIZE_DATA; byte++) + m_addrspace[0]->write_byte(byte, buffer[byte]); +} + + +//------------------------------------------------- +// nvram_write - called to write NVRAM to the +// .nv file +//------------------------------------------------- + +void er2055_device::nvram_write(emu_file &file) +{ + UINT8 buffer[SIZE_DATA]; + for (int byte = 0; byte < SIZE_DATA; byte++) + buffer[byte] = m_addrspace[0]->read_byte(byte); + file.write(buffer, sizeof(buffer)); +} + + + +//************************************************************************** +// I/O OPERATIONS +//************************************************************************** + +//------------------------------------------------- +// set_control - set the control lines; these +// must be done simultaneously because the chip +// reacts to various combinations +//------------------------------------------------- + +void er2055_device::set_control(UINT8 cs1, UINT8 cs2, UINT8 c1, UINT8 c2, UINT8 ck) +{ + // create a new composite control state + UINT8 oldstate = m_control_state; + m_control_state = (ck != 0) ? CK : 0; + m_control_state |= (c1 != 0) ? C1 : 0; + m_control_state |= (c2 != 0) ? C2 : 0; + m_control_state |= (cs1 != 0) ? CS1 : 0; + m_control_state |= (cs2 != 0) ? CS2 : 0; + + // if not selected, or if change from previous, we're done + if ((m_control_state & (CS1 | CS2)) != (CS1 | CS2) || m_control_state == oldstate) + return; + + // something changed, see what it is based on what mode we're in + switch (m_control_state & (C1 | C2)) + { + // write mode; erasing is required, so we perform an AND against previous + // data to simulate incorrect behavior if erasing was not done + case 0: + m_addrspace[0]->write_byte(m_address, m_addrspace[0]->read_byte(m_address) & m_data); +//printf("Write %02X = %02X\n", m_address, m_data); + break; + + // erase mode + case C2: + m_addrspace[0]->write_byte(m_address, 0xff); +//printf("Erase %02X\n", m_address); + break; + + // read mode + case C1: + if ((oldstate & CK) != 0 && (m_control_state & CK) == 0) + { + m_data = m_addrspace[0]->read_byte(m_address); +//printf("Read %02X = %02X\n", m_address, m_data); + } + break; + } +} diff --git a/src/devices/machine/er2055.h b/src/devices/machine/er2055.h new file mode 100644 index 00000000000..58919f30e4c --- /dev/null +++ b/src/devices/machine/er2055.h @@ -0,0 +1,83 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + er2055.h + + GI 512 bit electrically alterable read-only memory. + +***************************************************************************/ + +#pragma once + +#ifndef __ER2055_H__ +#define __ER2055_H__ + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_ER2055_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, ER2055, 0) + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + + +// ======================> er2055_device + +class er2055_device : public device_t, + public device_memory_interface, + public device_nvram_interface +{ +public: + // construction/destruction + er2055_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // I/O operations + UINT8 data() const { return m_data; } + void set_address(UINT8 address) { m_address = address & 0x3f; } + void set_data(UINT8 data) { m_data = data; } + + // control lines -- all lines are specified as active-high (even CS2) + void set_control(UINT8 cs1, UINT8 cs2, UINT8 c1, UINT8 c2, UINT8 ck); + +protected: + // device-level overrides + virtual void device_start(); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const; + + // device_nvram_interface overrides + virtual void nvram_default(); + virtual void nvram_read(emu_file &file); + virtual void nvram_write(emu_file &file); + + static const int SIZE_DATA = 0x40; + + static const UINT8 CK = 0x01; + static const UINT8 C1 = 0x02; + static const UINT8 C2 = 0x04; + static const UINT8 CS1 = 0x08; + static const UINT8 CS2 = 0x10; + + // configuration state + address_space_config m_space_config; + + // internal state + UINT8 m_control_state; + UINT8 m_address; + UINT8 m_data; +}; + + +// device type definition +extern const device_type ER2055; + + +#endif diff --git a/src/devices/machine/f3853.c b/src/devices/machine/f3853.c new file mode 100644 index 00000000000..a37e1b7e59b --- /dev/null +++ b/src/devices/machine/f3853.c @@ -0,0 +1,211 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +/********************************************************************** + + Fairchild F3853 SRAM interface with integrated interrupt + controller and timer (SMI) + + This chip is a timer shift register, basically the same as in the + F3851. + + Based on a datasheet obtained from www.freetradezone.com + + The SMI does not have DC0 and DC1, only DC0; as a result, it does + not respond to the main CPU's DC0/DC1 swap instruction. This may + lead to two devices responding to the same DC0 address and + attempting to place their bytes on the data bus simultaneously! + + 8-bit shift register: + Feedback in0 = !((out3 ^ out4) ^ (out5 ^ out7)) + Interrupts are at 0xfe + 0xff stops the register (0xfe is never reached) + +**********************************************************************/ + +#include "emu.h" +#include "f3853.h" + +/*************************************************************************** + MACROS +***************************************************************************/ + +#define INTERRUPT_VECTOR(external) ( external ? m_low | ( m_high << 8 ) | 0x80 \ +: ( m_low | ( m_high << 8 ) ) & ~0x80 ) + + + +/*************************************************************************** + IMPLEMENTATION +***************************************************************************/ + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +// device type definition +const device_type F3853 = &device_creator; + +//------------------------------------------------- +// f3853_device - constructor +//------------------------------------------------- + +f3853_device::f3853_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, F3853, "F3853", tag, owner, clock, "f3853", __FILE__) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void f3853_device::device_start() +{ + UINT8 reg = 0xfe; + for(INT32 i=254 /* Known to get 0xfe after 255 cycles */; i >= 0; i--) + { + INT32 o7 = (reg & 0x80) ? TRUE : FALSE; + INT32 o5 = (reg & 0x20) ? TRUE : FALSE; + INT32 o4 = (reg & 0x10) ? TRUE : FALSE; + INT32 o3 = (reg & 0x08) ? TRUE : FALSE; + m_value_to_cycle[reg] = i; + reg <<= 1; + if (!((o7 != o5) != (o4 != o3))) + { + reg |= 1; + } + } + + m_interrupt_req_cb.bind_relative_to(*owner()); + + m_timer = machine().scheduler().timer_alloc(FUNC(f3853_timer_callback), (void *)this ); + + save_item(NAME(m_high) ); + save_item(NAME(m_low) ); + save_item(NAME(m_external_enable) ); + save_item(NAME(m_timer_enable) ); + save_item(NAME(m_request_flipflop) ); + save_item(NAME(m_priority_line) ); + save_item(NAME(m_external_interrupt_line) ); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void f3853_device::device_reset() +{ + m_high = 0; + m_low = 0; + m_external_enable = 0; + m_timer_enable = 0; + m_request_flipflop = 0; + m_priority_line = FALSE; + m_external_interrupt_line = TRUE; + + m_timer->enable(false); +} + + +void f3853_device::set_interrupt_request_line() +{ + if (m_interrupt_req_cb.isnull()) + return; + + if (m_external_enable && !m_priority_line) + m_interrupt_req_cb(INTERRUPT_VECTOR(TRUE), TRUE); + else if (m_timer_enable && !m_priority_line && m_request_flipflop) + m_interrupt_req_cb(INTERRUPT_VECTOR(FALSE), TRUE); + else + m_interrupt_req_cb(0, FALSE); +} + + +void f3853_device::timer_start(UINT8 value) +{ + attotime period = (value != 0xff) ? attotime::from_hz(clock()) * (m_value_to_cycle[value]*31) : attotime::never; + + m_timer->adjust(period); +} + + +TIMER_CALLBACK( f3853_device::f3853_timer_callback ) +{ + reinterpret_cast(ptr)->timer(); +} + +void f3853_device::timer() +{ + if(m_timer_enable) + { + m_request_flipflop = TRUE; + set_interrupt_request_line(); + } + timer_start(0xfe); +} + +void f3853_device::set_external_interrupt_in_line(int level) +{ + if(m_external_interrupt_line && !level && m_external_enable) + { + m_request_flipflop = TRUE; + } + m_external_interrupt_line = level; + set_interrupt_request_line(); +} + +void f3853_device::set_priority_in_line(int level) +{ + m_priority_line = level; + set_interrupt_request_line(); +} + + +READ8_MEMBER(f3853_device::read) +{ + UINT8 data = 0; + + switch (offset) + { + case 0: + data = m_high; + break; + + case 1: + data = m_low; + break; + + case 2: // Interrupt control; not readable + case 3: // Timer; not readable + break; + } + + return data; +} + + +WRITE8_MEMBER(f3853_device::write) +{ + switch(offset) + { + case 0: + m_high = data; + break; + + case 1: + m_low = data; + break; + + case 2: //interrupt control + m_external_enable = ((data & 3) == 1); + m_timer_enable = ((data & 3) == 3); + set_interrupt_request_line(); + break; + + case 3: //timer + m_request_flipflop = FALSE; + set_interrupt_request_line(); + timer_start(data); + break; + } +} diff --git a/src/devices/machine/f3853.h b/src/devices/machine/f3853.h new file mode 100644 index 00000000000..f2afc03b588 --- /dev/null +++ b/src/devices/machine/f3853.h @@ -0,0 +1,110 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +/*************************************************************************** + + Fairchild F3853 SRAM interface with integrated interrupt + controller and timer + + This chip is a timer shift register, basically the same as in the + F3851. + +**************************************************************************** + _____ _____ + Vgg 1 |* \_/ | 40 Vdd + PHI 2 | | 39 ROMC4 + WRITE 3 | | 38 ROMC3 + _INT REQ 4 | | 37 ROMC2 + _PRI IN 5 | | 36 ROMC1 + _RAM WRITE 6 | | 35 ROMC0 + _EXT INT 7 | | 34 CPU READ + ADDR7 8 | | 33 REG DR + ADDR6 9 | | 32 ADDR15 + ADDR5 10 | F3853 | 31 ADDR14 + ADDR4 11 | | 30 ADDR13 + ADDR3 12 | | 29 ADDR12 + ADDR2 13 | | 28 ADDR11 + ADDR1 14 | | 27 ADDR10 + ADDR0 15 | | 26 ADDR9 + DB0 16 | | 25 ADDR8 + DB1 17 | | 24 DB7 + DB2 18 | | 23 DB6 + DB3 19 | | 22 DB5 + Vss 20 |_____________| 21 DB4 + +***************************************************************************/ + +#pragma once + +#ifndef __F3853_H__ +#define __F3853_H__ + +#include "emu.h" + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_F3853_EXT_INPUT_CB(_class, _method) \ + f3853_device::set_interrupt_req_callback(*device, f3853_interrupt_req_delegate(&_class::_method, #_class "::" #_method, downcast<_class *>(owner))); + +/*************************************************************************** + TYPE DEFINITIONS +***************************************************************************/ + +typedef device_delegate f3853_interrupt_req_delegate; + +#define F3853_INTERRUPT_REQ_CB(_name) void _name(UINT16 addr, int level) + + +// ======================> f3853_device + +class f3853_device : public device_t +{ +public: + // construction/destruction + f3853_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + static void set_interrupt_req_callback(device_t &device, f3853_interrupt_req_delegate callback) { downcast(device).m_interrupt_req_cb = callback; } + + DECLARE_READ8_MEMBER(read); + DECLARE_WRITE8_MEMBER(write); + + void set_external_interrupt_in_line(int level); + void set_priority_in_line(int level); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_post_load() { } + virtual void device_clock_changed() { } + + static TIMER_CALLBACK( f3853_timer_callback ); + +private: + + void set_interrupt_request_line(); + void timer_start(UINT8 value); + void timer(); + + f3853_interrupt_req_delegate m_interrupt_req_cb; + UINT8 m_high; + UINT8 m_low; // Bit 7 is set to 0 for timer interrupts, 1 for external interrupts + INT32 m_external_enable; + INT32 m_timer_enable; + + INT32 m_request_flipflop; + + INT32 m_priority_line; /* inverted level*/ + INT32 m_external_interrupt_line; /* inverted level */ + + emu_timer *m_timer; + + UINT8 m_value_to_cycle[0x100]; +}; + + +// device type definition +extern const device_type F3853; + +#endif /* __F3853_H__ */ diff --git a/src/devices/machine/fdc37c665gt.c b/src/devices/machine/fdc37c665gt.c new file mode 100644 index 00000000000..671d0314560 --- /dev/null +++ b/src/devices/machine/fdc37c665gt.c @@ -0,0 +1,61 @@ +// license:BSD-3-Clause +// copyright-holders:smf +#include "fdc37c665gt.h" + +fdc37c665gt_device::fdc37c665gt_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, FDC37C665GT, "FDC37C665GT", tag, owner, clock, "fdc37c665gt", __FILE__), + m_uart1(*this, "uart1"), + m_uart2(*this, "uart2") +{ +} + +READ8_MEMBER(fdc37c665gt_device::read) +{ + UINT8 data = 0; + + if ((offset & 0x3f8) == 0x3f8) + { + data = m_uart1->ins8250_r(space, offset & 7, mem_mask); + } + else if ((offset & 0x3f8) == 0x2f8) + { + data = m_uart2->ins8250_r(space, offset & 7, mem_mask); + } + else + { + printf("fdc37c665gt_device::read %04x %02x\n", offset, data); + } + return data; +} + +WRITE8_MEMBER(fdc37c665gt_device::write) +{ + if ((offset & 0x3f8) == 0x3f8) + { + m_uart1->ins8250_w(space, offset & 7, data, mem_mask); + } + else if ((offset & 0x3f8) == 0x2f8) + { + m_uart2->ins8250_w(space, offset & 7, data, mem_mask); + } + else + { + printf("fdc37c665gt_device::write %04x %02x\n", offset, data); + } +} + +void fdc37c665gt_device::device_start() +{ +} + +static MACHINE_CONFIG_FRAGMENT(fdc37c665gt) + MCFG_DEVICE_ADD("uart1", NS16550, XTAL_24MHz/13) + MCFG_DEVICE_ADD("uart2", NS16550, XTAL_24MHz/13) +MACHINE_CONFIG_END + +machine_config_constructor fdc37c665gt_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME(fdc37c665gt); +} + +const device_type FDC37C665GT = &device_creator; diff --git a/src/devices/machine/fdc37c665gt.h b/src/devices/machine/fdc37c665gt.h new file mode 100644 index 00000000000..f9401ab56ce --- /dev/null +++ b/src/devices/machine/fdc37c665gt.h @@ -0,0 +1,37 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/* +* fdc37c665gt.h +* +*/ + +#ifndef _FDC37C665GT_H_ +#define _FDC37C665GT_H_ + +#pragma once + +#include "ins8250.h" + +class fdc37c665gt_device : public device_t +{ +public: + // construction/destruction + fdc37c665gt_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + DECLARE_READ8_MEMBER(read); + DECLARE_WRITE8_MEMBER(write); + +protected: + // device-level overrides + virtual void device_start(); + virtual machine_config_constructor device_mconfig_additions() const; + +private: + required_device m_uart1; + required_device m_uart2; +}; + +// device type definition +extern const device_type FDC37C665GT; + +#endif diff --git a/src/devices/machine/fdc_pll.c b/src/devices/machine/fdc_pll.c new file mode 100644 index 00000000000..cf616468a12 --- /dev/null +++ b/src/devices/machine/fdc_pll.c @@ -0,0 +1,134 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +#include "fdc_pll.h" + +std::string fdc_pll_t::tts(attotime t) +{ + char buf[256]; + bool neg = t.seconds() < 0; + if(neg) + t = attotime::zero - t; + int nsec = t.attoseconds() / ATTOSECONDS_PER_NANOSECOND; + sprintf(buf, "%c%3d.%03d,%03d,%03d", neg ? '-' : ' ', int(t.seconds()), nsec/1000000, (nsec/1000)%1000, nsec % 1000); + return buf; +} + +void fdc_pll_t::set_clock(const attotime &_period) +{ + period = _period; + period_adjust_base = period * 0.05; + min_period = period * 0.75; + max_period = period * 1.25; +} + +void fdc_pll_t::reset(const attotime &when) +{ + ctime = when; + phase_adjust = attotime::zero; + freq_hist = 0; + write_position = 0; + write_start_time = attotime::never; +} + +void fdc_pll_t::start_writing(const attotime &tm) +{ + write_start_time = tm; + write_position = 0; +} + +void fdc_pll_t::stop_writing(floppy_image_device *floppy, const attotime &tm) +{ + commit(floppy, tm); + write_start_time = attotime::never; +} + +void fdc_pll_t::commit(floppy_image_device *floppy, const attotime &tm) +{ + if(write_start_time.is_never() || tm == write_start_time) + return; + + if(floppy) + floppy->write_flux(write_start_time, tm, write_position, write_buffer); + write_start_time = tm; + write_position = 0; +} + +int fdc_pll_t::get_next_bit(attotime &tm, floppy_image_device *floppy, const attotime &limit) +{ + attotime edge = floppy ? floppy->get_next_transition(ctime) : attotime::never; + + attotime next = ctime + period + phase_adjust; + +#if 0 + if(!edge.is_never()) + fprintf(stderr, "ctime=%s, transition_time=%s, next=%s, pha=%s\n", tts(ctime).c_str(), tts(edge).c_str(), tts(next).c_str(), tts(phase_adjust).c_str()); +#endif + + if(next > limit) + return -1; + + ctime = next; + tm = next; + + if(edge.is_never() || edge >= next) { + // No transition in the window means 0 and pll in free run mode + phase_adjust = attotime::zero; + return 0; + } + + // Transition in the window means 1, and the pll is adjusted + + attotime delta = edge - (next - period/2); + + if(delta.seconds() < 0) + phase_adjust = attotime::zero - ((attotime::zero - delta)*65)/100; + else + phase_adjust = (delta*65)/100; + + if(delta < attotime::zero) { + if(freq_hist < 0) + freq_hist--; + else + freq_hist = -1; + } else if(delta > attotime::zero) { + if(freq_hist > 0) + freq_hist++; + else + freq_hist = 1; + } else + freq_hist = 0; + + if(freq_hist) { + int afh = freq_hist < 0 ? -freq_hist : freq_hist; + if(afh > 1) { + attotime aper = attotime::from_double(period_adjust_base.as_double()*delta.as_double()/period.as_double()); + period += aper; + + if(period < min_period) + period = min_period; + else if(period > max_period) + period = max_period; + } + } + + return 1; +} + +bool fdc_pll_t::write_next_bit(bool bit, attotime &tm, floppy_image_device *floppy, const attotime &limit) +{ + if(write_start_time.is_never()) { + write_start_time = ctime; + write_position = 0; + } + + attotime etime = ctime + period; + if(etime > limit) + return true; + + if(bit && write_position < ARRAY_LENGTH(write_buffer)) + write_buffer[write_position++] = ctime + period/2; + + tm = etime; + ctime = etime; + return false; +} diff --git a/src/devices/machine/fdc_pll.h b/src/devices/machine/fdc_pll.h new file mode 100644 index 00000000000..31eaae07d1b --- /dev/null +++ b/src/devices/machine/fdc_pll.h @@ -0,0 +1,33 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +#ifndef __FDC_PLL_H__ +#define __FDC_PLL_H__ + +/* + * Generic pll class for floppy controllers with analog plls + */ + +#include "emu.h" +#include "imagedev/floppy.h" + +class fdc_pll_t { +public: + attotime ctime, period, min_period, max_period, period_adjust_base, phase_adjust; + + attotime write_start_time; + attotime write_buffer[32]; + int write_position; + int freq_hist; + + void set_clock(const attotime &period); + void reset(const attotime &when); + int get_next_bit(attotime &tm, floppy_image_device *floppy, const attotime &limit); + bool write_next_bit(bool bit, attotime &tm, floppy_image_device *floppy, const attotime &limit); + void start_writing(const attotime &tm); + void commit(floppy_image_device *floppy, const attotime &tm); + void stop_writing(floppy_image_device *floppy, const attotime &tm); + + std::string tts(attotime tm); +}; + +#endif diff --git a/src/devices/machine/gayle.c b/src/devices/machine/gayle.c new file mode 100644 index 00000000000..bf56f2aaf9e --- /dev/null +++ b/src/devices/machine/gayle.c @@ -0,0 +1,210 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best +/*************************************************************************** + + GAYLE + + Gate array used in the Amiga 600 and Amiga 1200 computers. + +***************************************************************************/ + +#include "gayle.h" + + +//************************************************************************** +// CONSTANTS +//************************************************************************** + +#define VERBOSE 0 + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type GAYLE = &device_creator; + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// gayle_device - constructor +//------------------------------------------------- + +gayle_device::gayle_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, GAYLE, "GAYLE", tag, owner, clock, "gayle", __FILE__), + m_int2_w(*this), + m_cs0_read(*this), + m_cs0_write(*this), + m_cs1_read(*this), + m_cs1_write(*this), + m_gayle_id(0xff), + m_gayle_id_count(0) +{ +} + +//------------------------------------------------- +// set_id - set gayle id +//------------------------------------------------- + +void gayle_device::set_id(device_t &device, UINT8 id) +{ + gayle_device &gayle = downcast(device); + gayle.m_gayle_id = id; +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void gayle_device::device_start() +{ + // resolve callbacks + m_int2_w.resolve_safe(); + m_cs0_read.resolve_safe(0xffff); + m_cs0_write.resolve_safe(); + m_cs1_read.resolve_safe(0xffff); + m_cs1_write.resolve_safe(); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void gayle_device::device_reset() +{ + m_gayle_reg[0] = 0; + m_gayle_reg[1] = 0; + m_gayle_reg[2] = 0; + m_gayle_reg[3] = 0; +} + + +//************************************************************************** +// IMPLEMENTATION +//************************************************************************** + +READ16_MEMBER( gayle_device::gayle_r ) +{ + UINT16 data = 0xffff; + offset <<= 1; + + // swap + mem_mask = (mem_mask << 8) | (mem_mask >> 8); + + if (BIT(offset, 15)) + { + switch (offset & 0x7fff) + { + case 0x0000: data = m_gayle_reg[0]; break; + case 0x1000: data = m_gayle_reg[1]; break; + case 0x2000: data = m_gayle_reg[2]; break; + case 0x3000: data = m_gayle_reg[3]; break; + } + } + else + { + if (!BIT(offset, 14)) + { + if (BIT(offset, 13)) + data = m_cs0_read(space, (offset >> 2) & 0x07, mem_mask); + else + data = m_cs1_read(space, (offset >> 2) & 0x07, mem_mask); + } + } + + if (VERBOSE) + logerror("gayle_r(%06x): %04x & %04x\n", offset, data, mem_mask); + + // swap data + data = (data << 8) | (data >> 8); + + return data; +} + +WRITE16_MEMBER( gayle_device::gayle_w ) +{ + offset <<= 1; + + // swap + mem_mask = (mem_mask << 8) | (mem_mask >> 8); + data = ((data << 8) | (data >> 8)) & mem_mask; + + if (VERBOSE) + logerror("gayle_w(%06x): %04x & %04x\n", offset, data, mem_mask); + + if (BIT(offset, 15)) + { + switch (offset & 0x7fff) + { + case 0x0000: + m_gayle_reg[0] = data; + break; + case 0x1000: + m_gayle_reg[1] &= data; + m_gayle_reg[1] |= data & 0x03; + break; + case 0x2000: + m_gayle_reg[2] = data; + break; + case 0x3000: + m_gayle_reg[3] = data; + break; + } + } + else + { + if (!BIT(offset, 14)) + { + if (BIT(offset, 13)) + m_cs0_write(space, (offset >> 2) & 0x07, data, mem_mask); + else + m_cs1_write(space, (offset >> 2) & 0x07, data, mem_mask); + } + } +} + +WRITE_LINE_MEMBER( gayle_device::ide_interrupt_w ) +{ + if (VERBOSE) + logerror("ide_interrupt_w: %d\n", state); + + // did we change state? + if (BIT(m_gayle_reg[GAYLE_CS], 7) != state) + m_gayle_reg[GAYLE_IRQ] |= 1 << 7; + + // set line state + if (state) + m_gayle_reg[GAYLE_CS] |= 1 << 7; + else + m_gayle_reg[GAYLE_CS] &= ~(1 << 7); + + // update interrupts + if (BIT(m_gayle_reg[GAYLE_INTEN], 7)) + m_int2_w(BIT(m_gayle_reg[GAYLE_CS], 7)); +} + +READ16_MEMBER( gayle_device::gayle_id_r ) +{ + UINT16 data = 0xffff; + + if (ACCESSING_BITS_8_15) + data = ((m_gayle_id << m_gayle_id_count++) & 0x80) << 8; + else + data = 0xffff; + + if (VERBOSE) + logerror("gayle_id_r(%06x): %04x & %04x (id=%02x)\n", offset, data, mem_mask, m_gayle_id); + + return data; +} + +WRITE16_MEMBER( gayle_device::gayle_id_w ) +{ + if (VERBOSE) + logerror("gayle_id_w(%06x): %04x & %04x (id=%02x)\n", offset, data, mem_mask, m_gayle_id); + + m_gayle_id_count = 0; +} diff --git a/src/devices/machine/gayle.h b/src/devices/machine/gayle.h new file mode 100644 index 00000000000..19e9cc5df73 --- /dev/null +++ b/src/devices/machine/gayle.h @@ -0,0 +1,110 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best +/*************************************************************************** + + GAYLE + + Gate array used in the Amiga 600 and Amiga 1200 computers. + +***************************************************************************/ + +#pragma once + +#ifndef __GAYLE_H__ +#define __GAYLE_H__ + +#include "emu.h" + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_GAYLE_ADD(_tag, _clock, _id) \ + MCFG_DEVICE_ADD(_tag, GAYLE, _clock) \ + gayle_device::set_id(*device, _id); + +#define MCFG_GAYLE_INT2_HANDLER(_devcb) \ + devcb = &gayle_device::set_int2_handler(*device, DEVCB_##_devcb); + +#define MCFG_GAYLE_CS0_READ_HANDLER(_devcb) \ + devcb = &gayle_device::set_cs0_read_handler(*device, DEVCB_##_devcb); + +#define MCFG_GAYLE_CS0_WRITE_HANDLER(_devcb) \ + devcb = &gayle_device::set_cs0_write_handler(*device, DEVCB_##_devcb); + +#define MCFG_GAYLE_CS1_READ_HANDLER(_devcb) \ + devcb = &gayle_device::set_cs1_read_handler(*device, DEVCB_##_devcb); + +#define MCFG_GAYLE_CS1_WRITE_HANDLER(_devcb) \ + devcb = &gayle_device::set_cs1_write_handler(*device, DEVCB_##_devcb); + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> gayle_device + +class gayle_device : public device_t +{ +public: + // construction/destruction + gayle_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // callbacks + template static devcb_base &set_int2_handler(device_t &device, _Object object) + { return downcast(device).m_int2_w.set_callback(object); } + + template static devcb_base &set_cs0_read_handler(device_t &device, _Object object) + { return downcast(device).m_cs0_read.set_callback(object); } + + template static devcb_base &set_cs0_write_handler(device_t &device, _Object object) + { return downcast(device).m_cs0_write.set_callback(object); } + + template static devcb_base &set_cs1_read_handler(device_t &device, _Object object) + { return downcast(device).m_cs1_read.set_callback(object); } + + template static devcb_base &set_cs1_write_handler(device_t &device, _Object object) + { return downcast(device).m_cs1_write.set_callback(object); } + + // interface + DECLARE_WRITE_LINE_MEMBER( ide_interrupt_w ); + + DECLARE_READ16_MEMBER( gayle_r ); + DECLARE_WRITE16_MEMBER( gayle_w ); + DECLARE_READ16_MEMBER( gayle_id_r ); + DECLARE_WRITE16_MEMBER( gayle_id_w ); + + // inline configuration + static void set_id(device_t &device, UINT8 id); + +protected: + virtual void device_start(); + virtual void device_reset(); + +private: + enum + { + GAYLE_CS = 0, // interrupt status + GAYLE_IRQ, // interrupt change + GAYLE_INTEN, // interrupt enable register + GAYLE_CFG // config register + }; + + devcb_write_line m_int2_w; + + devcb_read16 m_cs0_read; + devcb_write16 m_cs0_write; + devcb_read16 m_cs1_read; + devcb_write16 m_cs1_write; + + UINT8 m_gayle_id; + int m_gayle_id_count; + UINT8 m_gayle_reg[4]; +}; + +// device type definition +extern const device_type GAYLE; + +#endif diff --git a/src/devices/machine/generic.c b/src/devices/machine/generic.c new file mode 100644 index 00000000000..79a3ea3f5cf --- /dev/null +++ b/src/devices/machine/generic.c @@ -0,0 +1,290 @@ +// license:BSD-3-Clause +// copyright-holders:Nicola Salmoria +/********************************************************************* + + generic.c + + Generic simple machine functions. + +*********************************************************************/ + +#include "emu.h" +#include "emuopts.h" +#include "config.h" + + + +/*************************************************************************** + FUNCTION PROTOTYPES +***************************************************************************/ + +static void counters_load(running_machine &machine, int config_type, xml_data_node *parentnode); +static void counters_save(running_machine &machine, int config_type, xml_data_node *parentnode); + + + +/*************************************************************************** + TYPE DEFINITIONS +***************************************************************************/ + +struct generic_machine_private +{ + /* tickets and coin counters */ + UINT32 dispensed_tickets; + UINT32 coin_count[COIN_COUNTERS]; + UINT32 coinlockedout[COIN_COUNTERS]; + UINT32 lastcoin[COIN_COUNTERS]; +}; + + + +/*************************************************************************** + INITIALIZATION +***************************************************************************/ + +/*------------------------------------------------- + generic_machine_init - initialize globals and + register for save states +-------------------------------------------------*/ + +void generic_machine_init(running_machine &machine) +{ + generic_machine_private *state; + int counternum; + + /* allocate our state */ + machine.generic_machine_data = auto_alloc_clear(machine, generic_machine_private); + state = machine.generic_machine_data; + + /* reset coin counters */ + for (counternum = 0; counternum < COIN_COUNTERS; counternum++) + { + state->lastcoin[counternum] = 0; + state->coinlockedout[counternum] = 0; + } + + /* register coin save state */ + machine.save().save_item(NAME(state->coin_count)); + machine.save().save_item(NAME(state->coinlockedout)); + machine.save().save_item(NAME(state->lastcoin)); + + /* register for configuration */ + config_register(machine, "counters", config_saveload_delegate(FUNC(counters_load), &machine), config_saveload_delegate(FUNC(counters_save), &machine)); +} + + + +/*************************************************************************** + TICKETS +***************************************************************************/ + +/*------------------------------------------------- + get_dispensed_tickets - return the number of + tickets dispensed +-------------------------------------------------*/ + +int get_dispensed_tickets(running_machine &machine) +{ + generic_machine_private *state = machine.generic_machine_data; + return state->dispensed_tickets; +} + + +/*------------------------------------------------- + increment_dispensed_tickets - increment the + number of dispensed tickets +-------------------------------------------------*/ + +void increment_dispensed_tickets(running_machine &machine, int delta) +{ + generic_machine_private *state = machine.generic_machine_data; + state->dispensed_tickets += delta; +} + + + +/*************************************************************************** + COIN COUNTERS +***************************************************************************/ + +/*------------------------------------------------- + counters_load - load the state of the counters + and tickets +-------------------------------------------------*/ + +static void counters_load(running_machine &machine, int config_type, xml_data_node *parentnode) +{ + generic_machine_private *state = machine.generic_machine_data; + xml_data_node *coinnode, *ticketnode; + + /* on init, reset the counters */ + if (config_type == CONFIG_TYPE_INIT) + { + memset(state->coin_count, 0, sizeof(state->coin_count)); + state->dispensed_tickets = 0; + } + + /* only care about game-specific data */ + if (config_type != CONFIG_TYPE_GAME) + return; + + /* might not have any data */ + if (parentnode == NULL) + return; + + /* iterate over coins nodes */ + for (coinnode = xml_get_sibling(parentnode->child, "coins"); coinnode; coinnode = xml_get_sibling(coinnode->next, "coins")) + { + int index = xml_get_attribute_int(coinnode, "index", -1); + if (index >= 0 && index < COIN_COUNTERS) + state->coin_count[index] = xml_get_attribute_int(coinnode, "number", 0); + } + + /* get the single tickets node */ + ticketnode = xml_get_sibling(parentnode->child, "tickets"); + if (ticketnode != NULL) + state->dispensed_tickets = xml_get_attribute_int(ticketnode, "number", 0); +} + + +/*------------------------------------------------- + counters_save - save the state of the counters + and tickets +-------------------------------------------------*/ + +static void counters_save(running_machine &machine, int config_type, xml_data_node *parentnode) +{ + generic_machine_private *state = machine.generic_machine_data; + int i; + + /* only care about game-specific data */ + if (config_type != CONFIG_TYPE_GAME) + return; + + /* iterate over coin counters */ + for (i = 0; i < COIN_COUNTERS; i++) + if (state->coin_count[i] != 0) + { + xml_data_node *coinnode = xml_add_child(parentnode, "coins", NULL); + if (coinnode != NULL) + { + xml_set_attribute_int(coinnode, "index", i); + xml_set_attribute_int(coinnode, "number", state->coin_count[i]); + } + } + + /* output tickets */ + if (state->dispensed_tickets != 0) + { + xml_data_node *tickets = xml_add_child(parentnode, "tickets", NULL); + if (tickets != NULL) + xml_set_attribute_int(tickets, "number", state->dispensed_tickets); + } +} + + +/*------------------------------------------------- + coin_counter_w - sets input for coin counter +-------------------------------------------------*/ + +void coin_counter_w(running_machine &machine, int num, int on) +{ + generic_machine_private *state = machine.generic_machine_data; + if (num >= ARRAY_LENGTH(state->coin_count)) + return; + + /* Count it only if the data has changed from 0 to non-zero */ + if (on && (state->lastcoin[num] == 0)) + state->coin_count[num]++; + state->lastcoin[num] = on; +} + + +/*------------------------------------------------- + coin_counter_get_count - return the coin count + for a given coin +-------------------------------------------------*/ + +int coin_counter_get_count(running_machine &machine, int num) +{ + generic_machine_private *state = machine.generic_machine_data; + if (num >= ARRAY_LENGTH(state->coin_count)) + return 0; + return state->coin_count[num]; +} + + +/*------------------------------------------------- + coin_lockout_w - locks out one coin input +-------------------------------------------------*/ + +void coin_lockout_w(running_machine &machine, int num,int on) +{ + generic_machine_private *state = machine.generic_machine_data; + if (num >= ARRAY_LENGTH(state->coinlockedout)) + return; + state->coinlockedout[num] = on; +} + + +/*------------------------------------------------- + coin_lockout_get_state - return current lockout + state for a particular coin +-------------------------------------------------*/ + +int coin_lockout_get_state(running_machine &machine, int num) +{ + generic_machine_private *state = machine.generic_machine_data; + if (num >= ARRAY_LENGTH(state->coinlockedout)) + return FALSE; + return state->coinlockedout[num]; +} + + +/*------------------------------------------------- + coin_lockout_global_w - locks out all the coin + inputs +-------------------------------------------------*/ + +void coin_lockout_global_w(running_machine &machine, int on) +{ + generic_machine_private *state = machine.generic_machine_data; + int i; + + for (i = 0; i < ARRAY_LENGTH(state->coinlockedout); i++) + coin_lockout_w(machine, i, on); +} + + +/*************************************************************************** + LED CODE +***************************************************************************/ + +/*------------------------------------------------- + set_led_status - set the state of a given LED +-------------------------------------------------*/ + +void set_led_status(running_machine &machine, int num, int on) +{ + output_set_led_value(num, on); +} + + + + +/*************************************************************************** + PORT READING HELPERS +***************************************************************************/ + +/*------------------------------------------------- + custom_port_read - act like input_port_read + but it is a custom port, it is useful for + e.g. input ports which expect the same port + repeated both in the upper and lower half +-------------------------------------------------*/ + +CUSTOM_INPUT_MEMBER( driver_device::custom_port_read ) +{ + const char *tag = (const char *)param; + return ioport(tag)->read(); +} diff --git a/src/devices/machine/generic.h b/src/devices/machine/generic.h new file mode 100644 index 00000000000..b724a598a9d --- /dev/null +++ b/src/devices/machine/generic.h @@ -0,0 +1,69 @@ +// license:BSD-3-Clause +// copyright-holders:Nicola Salmoria +/********************************************************************* + + generic.h + + Generic simple machine functions. + +*********************************************************************/ + +#pragma once + +#ifndef __MACHINE_GENERIC_H__ +#define __MACHINE_GENERIC_H__ + + + +/*************************************************************************** + CONSTANTS +***************************************************************************/ + +/* total # of coin counters */ +#define COIN_COUNTERS 8 + +/*************************************************************************** + FUNCTION PROTOTYPES +***************************************************************************/ + + +/* ----- initialization ----- */ + +/* set up all the common systems */ +void generic_machine_init(running_machine &machine); + + + +/* ----- tickets ----- */ + +/* return the number of tickets dispensed */ +int get_dispensed_tickets(running_machine &machine); + +/* increment the number of dispensed tickets */ +void increment_dispensed_tickets(running_machine &machine, int delta); + + + +/* ----- coin counters ----- */ + +/* write to a particular coin counter (clocks on active high edge) */ +void coin_counter_w(running_machine &machine, int num, int on); + +/* return the coin count for a given coin */ +int coin_counter_get_count(running_machine &machine, int num); + +/* enable/disable coin lockout for a particular coin */ +void coin_lockout_w(running_machine &machine, int num, int on); + +/* return current lockout state for a particular coin */ +int coin_lockout_get_state(running_machine &machine, int num); + +/* enable/disable global coin lockout */ +void coin_lockout_global_w(running_machine &machine, int on); + +/* ----- miscellaneous bits & pieces ----- */ + +/* set the status of an LED */ +void set_led_status(running_machine &machine, int num, int value); + +#endif /* __MACHINE_GENERIC_H__ */ diff --git a/src/devices/machine/hd63450.c b/src/devices/machine/hd63450.c new file mode 100644 index 00000000000..9528026b95e --- /dev/null +++ b/src/devices/machine/hd63450.c @@ -0,0 +1,555 @@ +// license:BSD-3-Clause +// copyright-holders:Barry Rodewald +/* + Hitachi HD63450 DMA Controller + + Largely based on documentation of the Sharp X68000 +*/ + +#include "hd63450.h" + +const device_type HD63450 = &device_creator; + +hd63450_device::hd63450_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, HD63450, "Hitachi HD63450", tag, owner, clock, "hd63450", __FILE__), + m_dma_end(*this), + m_dma_error(*this), + m_dma_read_0(*this), + m_dma_read_1(*this), + m_dma_read_2(*this), + m_dma_read_3(*this), + m_dma_write_0(*this), + m_dma_write_1(*this), + m_dma_write_2(*this), + m_dma_write_3(*this), + m_cpu_tag(NULL), + m_cpu(NULL) +{ + for (int i = 0; i < 4; i++) + { + memset(&m_reg[i], 0, sizeof(m_reg[i])); + m_timer[i] = NULL; + m_in_progress[i] = 0; + m_transfer_size[i] = 0; + m_halted[i] = 0; + m_our_clock[i] = attotime::zero; + m_burst_clock[i] = attotime::zero; + } +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void hd63450_device::device_start() +{ + // get the CPU device + m_cpu = machine().device(m_cpu_tag); + assert(m_cpu != NULL); + + // resolve callbacks + m_dma_end.resolve(); + m_dma_error.resolve_safe(); + m_dma_read_0.resolve(); + m_dma_read_1.resolve(); + m_dma_read_2.resolve(); + m_dma_read_3.resolve(); + m_dma_write_0.resolve(); + m_dma_write_1.resolve(); + m_dma_write_2.resolve(); + m_dma_write_3.resolve(); + + // Initialise timers and registers + for (int x = 0; x < 4 ; x++) + { + m_timer[x] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(hd63450_device::dma_transfer_timer), this)); + m_reg[x].niv = 0x0f; // defaults? + m_reg[x].eiv = 0x0f; + } +} + +void hd63450_device::device_reset() +{ + m_drq_state[0] = m_drq_state[1] = m_drq_state[2] = m_drq_state[3] = 0; +} + +READ16_MEMBER(hd63450_device::read) +{ + int channel,reg; + + channel = (offset & 0x60) >> 5; + reg = offset & 0x1f; + + switch(reg) + { + case 0x00: // CSR / CER + return (m_reg[channel].csr << 8) | m_reg[channel].cer; + case 0x02: // DCR / OCR + return (m_reg[channel].dcr << 8) | m_reg[channel].ocr; + case 0x03: // SCR / CCR + return (m_reg[channel].scr << 8) | m_reg[channel].ccr; + case 0x05: // MTC + return m_reg[channel].mtc; + case 0x06: // MAR (high) + return (m_reg[channel].mar & 0xffff0000) >> 16; + case 0x07: // MAR (low) + return (m_reg[channel].mar & 0x0000ffff); + case 0x0a: // DAR (high) + return (m_reg[channel].dar & 0xffff0000) >> 16; + case 0x0b: // DAR (low) + return (m_reg[channel].dar & 0x0000ffff); + case 0x0d: // BTC + return m_reg[channel].btc; + case 0x0e: // BAR (high) + return (m_reg[channel].bar & 0xffff0000) >> 16; + case 0x0f: // BAR (low) + return (m_reg[channel].bar & 0x0000ffff); + case 0x12: // NIV + return m_reg[channel].niv; + case 0x13: // EIV + return m_reg[channel].eiv; + case 0x14: // MFC + return m_reg[channel].mfc; + case 0x16: // CPR + return m_reg[channel].cpr; + case 0x18: // DFC + return m_reg[channel].dfc; + case 0x1c: // BFC + return m_reg[channel].bfc; + case 0x1f: // GCR + return m_reg[channel].gcr; + } + return 0xff; +} + +WRITE16_MEMBER(hd63450_device::write) +{ + int channel,reg; + + channel = (offset & 0x60) >> 5; + reg = offset & 0x1f; + switch(reg) + { + case 0x00: // CSR / CER + if(ACCESSING_BITS_8_15) + { + m_reg[channel].csr &= ~((data & 0xff00) >> 8); +// logerror("DMA#%i: Channel status write : %02x\n",channel,dmac.reg[channel].csr); + } + // CER is read-only, so no action needed there. + break; + case 0x02: // DCR / OCR + if(ACCESSING_BITS_8_15) + { + m_reg[channel].dcr = (data & 0xff00) >> 8; + logerror("DMA#%i: Device Control write : %02x\n",channel,m_reg[channel].dcr); + } + if(ACCESSING_BITS_0_7) + { + m_reg[channel].ocr = data & 0x00ff; + logerror("DMA#%i: Operation Control write : %02x\n",channel,m_reg[channel].ocr); + } + break; + case 0x03: // SCR / CCR + if(ACCESSING_BITS_8_15) + { + m_reg[channel].scr = (data & 0xff00) >> 8; + logerror("DMA#%i: Sequence Control write : %02x\n",channel,m_reg[channel].scr); + } + if(ACCESSING_BITS_0_7) + { + m_reg[channel].ccr = data & 0x00ff; + if((data & 0x0080))// && !m_dma_read[channel] && !m_dma_write[channel]) + dma_transfer_start(channel); + if(data & 0x0010) // software abort + dma_transfer_abort(channel); + if(data & 0x0020) // halt operation + dma_transfer_halt(channel); + if(data & 0x0040) // continure operation + dma_transfer_continue(channel); + logerror("DMA#%i: Channel Control write : %02x\n",channel,m_reg[channel].ccr); + } + break; + case 0x05: // MTC + m_reg[channel].mtc = data; + logerror("DMA#%i: Memory Transfer Counter write : %04x\n",channel,m_reg[channel].mtc); + break; + case 0x06: // MAR (high) + m_reg[channel].mar = (m_reg[channel].mar & 0x0000ffff) | (data << 16); + logerror("DMA#%i: Memory Address write : %08lx\n",channel,m_reg[channel].mar); + break; + case 0x07: // MAR (low) + m_reg[channel].mar = (m_reg[channel].mar & 0xffff0000) | (data & 0x0000ffff); + logerror("DMA#%i: Memory Address write : %08lx\n",channel,m_reg[channel].mar); + break; + case 0x0a: // DAR (high) + m_reg[channel].dar = (m_reg[channel].dar & 0x0000ffff) | (data << 16); + logerror("DMA#%i: Device Address write : %08lx\n",channel,m_reg[channel].dar); + break; + case 0x0b: // DAR (low) + m_reg[channel].dar = (m_reg[channel].dar & 0xffff0000) | (data & 0x0000ffff); + logerror("DMA#%i: Device Address write : %08lx\n",channel,m_reg[channel].dar); + break; + case 0x0d: // BTC + m_reg[channel].btc = data; + logerror("DMA#%i: Base Transfer Counter write : %04x\n",channel,m_reg[channel].btc); + break; + case 0x0e: // BAR (high) + m_reg[channel].bar = (m_reg[channel].bar & 0x0000ffff) | (data << 16); + logerror("DMA#%i: Base Address write : %08lx\n",channel,m_reg[channel].bar); + break; + case 0x0f: // BAR (low) + m_reg[channel].bar = (m_reg[channel].bar & 0xffff0000) | (data & 0x0000ffff); + logerror("DMA#%i: Base Address write : %08lx\n",channel,m_reg[channel].bar); + break; + case 0x12: // NIV + m_reg[channel].niv = data & 0xff; + logerror("DMA#%i: Normal IRQ Vector write : %02x\n",channel,m_reg[channel].niv); + break; + case 0x13: // EIV + m_reg[channel].eiv = data & 0xff; + logerror("DMA#%i: Error IRQ Vector write : %02x\n",channel,m_reg[channel].eiv); + break; + case 0x14: // MFC + m_reg[channel].mfc = data & 0xff; + logerror("DMA#%i: Memory Function Code write : %02x\n",channel,m_reg[channel].mfc); + break; + case 0x16: // CPR + m_reg[channel].cpr = data & 0xff; + logerror("DMA#%i: Channel Priority write : %02x\n",channel,m_reg[channel].cpr); + break; + case 0x18: // DFC + m_reg[channel].dfc = data & 0xff; + logerror("DMA#%i: Device Function Code write : %02x\n",channel,m_reg[channel].dfc); + break; + case 0x1c: // BFC + m_reg[channel].bfc = data & 0xff; + logerror("DMA#%i: Base Function Code write : %02x\n",channel,m_reg[channel].bfc); + break; + case 0x1f: + m_reg[channel].gcr = data & 0xff; + logerror("DMA#%i: General Control write : %02x\n",channel,m_reg[channel].gcr); + break; + } +} + +void hd63450_device::dma_transfer_start(int channel) +{ + address_space &space = m_cpu->space(AS_PROGRAM); + m_in_progress[channel] = 1; + m_reg[channel].csr &= ~0xe0; + m_reg[channel].csr |= 0x08; // Channel active + m_reg[channel].csr &= ~0x30; // Reset Error and Normal termination bits + if((m_reg[channel].ocr & 0x0c) != 0x00) // Array chain or Link array chain + { + m_reg[channel].mar = space.read_word(m_reg[channel].bar) << 16; + m_reg[channel].mar |= space.read_word(m_reg[channel].bar+2); + m_reg[channel].mtc = space.read_word(m_reg[channel].bar+4); + if(m_reg[channel].btc > 0) + m_reg[channel].btc--; + } + + // Burst transfers will halt the CPU until the transfer is complete + if((m_reg[channel].dcr & 0xc0) == 0x00) // Burst transfer + { + m_cpu->set_input_line(INPUT_LINE_HALT, ASSERT_LINE); + m_timer[channel]->adjust(attotime::zero, channel, m_burst_clock[channel]); + } + else if(!(m_reg[channel].ocr & 2)) + m_timer[channel]->adjust(attotime::from_usec(500), channel, m_our_clock[channel]); + else if((m_reg[channel].ocr & 3) == 3) + m_timer[channel]->adjust(attotime::from_usec(500), channel, attotime::never); + else if((m_reg[channel].ocr & 3) == 2) + m_timer[channel]->adjust(attotime::never, channel, attotime::never); + + m_transfer_size[channel] = m_reg[channel].mtc; + + logerror("DMA: Transfer begins: size=0x%08x\n",m_transfer_size[channel]); +} + +void hd63450_device::set_timer(int channel, const attotime &tm) +{ + m_our_clock[channel] = tm; + if(m_in_progress[channel] != 0) + m_timer[channel]->adjust(attotime::zero, channel, m_our_clock[channel]); +} + +TIMER_CALLBACK_MEMBER(hd63450_device::dma_transfer_timer) +{ + if(((m_reg[param].ocr & 3) == 2) && !m_drq_state[param]) + return; + single_transfer(param); +} + +void hd63450_device::dma_transfer_abort(int channel) +{ + if(!m_in_progress[channel]) + return; + + logerror("DMA#%i: Transfer aborted\n",channel); + m_timer[channel]->adjust(attotime::never); + m_in_progress[channel] = 0; + m_reg[channel].csr |= 0x90; // channel error + m_reg[channel].csr &= ~0x08; // channel no longer active + m_reg[channel].cer = 0x11; + m_reg[channel].ccr &= ~0xc0; + m_dma_error((offs_t)3, m_reg[channel].ccr & 0x08); +} + +void hd63450_device::dma_transfer_halt(int channel) +{ + m_halted[channel] = 1; + m_timer[channel]->adjust(attotime::never); +} + +void hd63450_device::dma_transfer_continue(int channel) +{ + if(m_halted[channel] != 0) + { + m_halted[channel] = 0; + m_timer[channel]->adjust(attotime::zero, channel, m_our_clock[channel]); + } +} + +void hd63450_device::single_transfer(int x) +{ + address_space &space = m_cpu->space(AS_PROGRAM); + int data; + int datasize = 1; + + if(m_in_progress[x] != 0) // DMA in progress in channel x + { + if(m_reg[x].ocr & 0x80) // direction: 1 = device -> memory + { + if((x == 0) && !m_dma_read_0.isnull()) + { + data = m_dma_read_0(m_reg[x].mar); + if(data == -1) + return; // not ready to receive data + space.write_byte(m_reg[x].mar,data); + datasize = 1; + } + else if((x == 1) && !m_dma_read_1.isnull()) + { + data = m_dma_read_1(m_reg[x].mar); + if(data == -1) + return; // not ready to receive data + space.write_byte(m_reg[x].mar,data); + datasize = 1; + } + else if((x == 2) && !m_dma_read_2.isnull()) + { + data = m_dma_read_2(m_reg[x].mar); + if(data == -1) + return; // not ready to receive data + space.write_byte(m_reg[x].mar,data); + datasize = 1; + } + else if((x == 3) && !m_dma_read_3.isnull()) + { + data = m_dma_read_3(m_reg[x].mar); + if(data == -1) + return; // not ready to receive data + space.write_byte(m_reg[x].mar,data); + datasize = 1; + } + else + { + switch(m_reg[x].ocr & 0x30) // operation size + { + case 0x00: // 8 bit + data = space.read_byte(m_reg[x].dar); // read from device address + space.write_byte(m_reg[x].mar, data); // write to memory address + datasize = 1; + break; + case 0x10: // 16 bit + data = space.read_word(m_reg[x].dar); // read from device address + space.write_word(m_reg[x].mar, data); // write to memory address + datasize = 2; + break; + case 0x20: // 32 bit + data = space.read_word(m_reg[x].dar) << 16; // read from device address + data |= space.read_word(m_reg[x].dar+2); + space.write_word(m_reg[x].mar, (data & 0xffff0000) >> 16); // write to memory address + space.write_word(m_reg[x].mar+2, data & 0x0000ffff); + datasize = 4; + break; + case 0x30: // 8 bit packed (?) + data = space.read_byte(m_reg[x].dar); // read from device address + space.write_byte(m_reg[x].mar, data); // write to memory address + datasize = 1; + break; + } + } +// logerror("DMA#%i: byte transfer %08lx -> %08lx (byte = %02x)\n",x,dmac.reg[x].dar,dmac.reg[x].mar,data); + } + else // memory -> device + { + if((x == 0) && !m_dma_write_0.isnull()) + { + data = space.read_byte(m_reg[x].mar); + m_dma_write_0((offs_t)m_reg[x].mar,data); + datasize = 1; + } + else if((x == 1) && !m_dma_write_1.isnull()) + { + data = space.read_byte(m_reg[x].mar); + m_dma_write_1((offs_t)m_reg[x].mar,data); + datasize = 1; + } + else if((x == 2) && !m_dma_write_2.isnull()) + { + data = space.read_byte(m_reg[x].mar); + m_dma_write_2((offs_t)m_reg[x].mar,data); + datasize = 1; + } + else if((x == 3) && !m_dma_write_3.isnull()) + { + data = space.read_byte(m_reg[x].mar); + m_dma_write_3((offs_t)m_reg[x].mar,data); + datasize = 1; + } + else + { + switch(m_reg[x].ocr & 0x30) // operation size + { + case 0x00: // 8 bit + data = space.read_byte(m_reg[x].mar); // read from memory address + space.write_byte(m_reg[x].dar, data); // write to device address + datasize = 1; + break; + case 0x10: // 16 bit + data = space.read_word(m_reg[x].mar); // read from memory address + space.write_word(m_reg[x].dar, data); // write to device address + datasize = 2; + break; + case 0x20: // 32 bit + data = space.read_word(m_reg[x].mar) << 16; // read from memory address + data |= space.read_word(m_reg[x].mar+2); // read from memory address + space.write_word(m_reg[x].dar, (data & 0xffff0000) >> 16); // write to device address + space.write_word(m_reg[x].dar+2, data & 0x0000ffff); // write to device address + datasize = 4; + break; + case 0x30: // 8 bit packed (?) + data = space.read_byte(m_reg[x].mar); // read from memory address + space.write_byte(m_reg[x].dar, data); // write to device address + datasize = 1; + break; + } + } +// logerror("DMA#%i: byte transfer %08lx -> %08lx\n",x,m_reg[x].mar,m_reg[x].dar); + } + + + // decrease memory transfer counter + if(m_reg[x].mtc > 0) + m_reg[x].mtc--; + + // handle change of memory and device addresses + if((m_reg[x].scr & 0x03) == 0x01) + m_reg[x].dar+=datasize; + else if((m_reg[x].scr & 0x03) == 0x02) + m_reg[x].dar-=datasize; + + if((m_reg[x].scr & 0x0c) == 0x04) + m_reg[x].mar+=datasize; + else if((m_reg[x].scr & 0x0c) == 0x08) + m_reg[x].mar-=datasize; + + if(m_reg[x].mtc <= 0) + { + // End of transfer + logerror("DMA#%i: End of transfer\n",x); + if((m_reg[x].ocr & 0x0c) != 0 && m_reg[x].btc > 0) + { + m_reg[x].btc--; + m_reg[x].bar+=6; + m_reg[x].mar = space.read_word(m_reg[x].bar) << 16; + m_reg[x].mar |= space.read_word(m_reg[x].bar+2); + m_reg[x].mtc = space.read_word(m_reg[x].bar+4); + return; + } + m_timer[x]->adjust(attotime::never); + m_in_progress[x] = 0; + m_reg[x].csr |= 0xe0; // channel operation complete, block transfer complete + m_reg[x].csr &= ~0x08; // channel no longer active + m_reg[x].ccr &= ~0xc0; + + // Burst transfer + if((m_reg[x].dcr & 0xc0) == 0x00) + { + m_cpu->set_input_line(INPUT_LINE_HALT, CLEAR_LINE); + } + + if(!m_dma_end.isnull()) + m_dma_end((offs_t)x, m_reg[x].ccr & 0x08); + } + } +} + +WRITE_LINE_MEMBER(hd63450_device::drq0_w) +{ + bool ostate = m_drq_state[0]; + m_drq_state[0] = state; + + if((m_reg[0].ocr & 2) && (state && !ostate)) + { + // in cycle steal mode drq is supposed to be edge triggered + single_transfer(0); + m_timer[0]->adjust(m_our_clock[0], 0, m_our_clock[0]); + } + else if(!state) + m_timer[0]->adjust(attotime::never); +} + +WRITE_LINE_MEMBER(hd63450_device::drq1_w) +{ + bool ostate = m_drq_state[1]; + m_drq_state[1] = state; + + if((m_reg[1].ocr & 2) && (state && !ostate)) + { + single_transfer(1); + m_timer[1]->adjust(m_our_clock[1], 1, m_our_clock[1]); + } + else if(!state) + m_timer[1]->adjust(attotime::never); +} + +WRITE_LINE_MEMBER(hd63450_device::drq2_w) +{ + bool ostate = m_drq_state[2]; + m_drq_state[2] = state; + + if((m_reg[2].ocr & 2) && (state && !ostate)) + { + single_transfer(2); + m_timer[2]->adjust(m_our_clock[2], 2, m_our_clock[2]); + } + else if(!state) + m_timer[2]->adjust(attotime::never); +} + +WRITE_LINE_MEMBER(hd63450_device::drq3_w) +{ + bool ostate = m_drq_state[3]; + m_drq_state[3] = state; + + if((m_reg[3].ocr & 2) && (state && !ostate)) + { + single_transfer(3); + m_timer[3]->adjust(m_our_clock[3], 3, m_our_clock[3]); + } + else if(!state) + m_timer[3]->adjust(attotime::never); +} + +int hd63450_device::get_vector(int channel) +{ + return m_reg[channel].niv; +} + +int hd63450_device::get_error_vector(int channel) +{ + return m_reg[channel].eiv; +} diff --git a/src/devices/machine/hd63450.h b/src/devices/machine/hd63450.h new file mode 100644 index 00000000000..baf6d0337f1 --- /dev/null +++ b/src/devices/machine/hd63450.h @@ -0,0 +1,155 @@ +// license:BSD-3-Clause +// copyright-holders:Barry Rodewald +/* + Hitachi HD63450 DMA Controller +*/ + +#include "emu.h" + + +#define MCFG_HD63450_DMA_END_CB(_devcb) \ + devcb = &hd63450_device::set_dma_end_callback(*device, DEVCB_##_devcb); + +#define MCFG_HD63450_DMA_ERROR_CB(_devcb) \ + devcb = &hd63450_device::set_dma_error_callback(*device, DEVCB_##_devcb); + +#define MCFG_HD63450_DMA_READ_0_CB(_devcb) \ + devcb = &hd63450_device::set_dma_read_0_callback(*device, DEVCB_##_devcb); + +#define MCFG_HD63450_DMA_READ_1_CB(_devcb) \ + devcb = &hd63450_device::set_dma_read_1_callback(*device, DEVCB_##_devcb); + +#define MCFG_HD63450_DMA_READ_2_CB(_devcb) \ + devcb = &hd63450_device::set_dma_read_2_callback(*device, DEVCB_##_devcb); + +#define MCFG_HD63450_DMA_READ_3_CB(_devcb) \ + devcb = &hd63450_device::set_dma_read_3_callback(*device, DEVCB_##_devcb); + +#define MCFG_HD63450_DMA_WRITE_0_CB(_devcb) \ + devcb = &hd63450_device::set_dma_write_0_callback(*device, DEVCB_##_devcb); + +#define MCFG_HD63450_DMA_WRITE_1_CB(_devcb) \ + devcb = &hd63450_device::set_dma_write_1_callback(*device, DEVCB_##_devcb); + +#define MCFG_HD63450_DMA_WRITE_2_CB(_devcb) \ + devcb = &hd63450_device::set_dma_write_2_callback(*device, DEVCB_##_devcb); + +#define MCFG_HD63450_DMA_WRITE_3_CB(_devcb) \ + devcb = &hd63450_device::set_dma_write_3_callback(*device, DEVCB_##_devcb); + +#define MCFG_HD63450_CPU(_tag) \ + hd63450_device::set_cpu_tag(*device, _tag); + +#define MCFG_HD63450_CLOCKS(_clk1, _clk2, _clk3, _clk4) \ + hd63450_device::set_our_clocks(*device, _clk1, _clk2, _clk3, _clk4); + +#define MCFG_HD63450_BURST_CLOCKS(_clk1, _clk2, _clk3, _clk4) \ + hd63450_device::set_burst_clocks(*device, _clk1, _clk2, _clk3, _clk4); + +struct hd63450_regs +{ // offsets in bytes + unsigned char csr; // [00] Channel status register (R/W) + unsigned char cer; // [01] Channel error register (R) + unsigned char dcr; // [04] Device control register (R/W) + unsigned char ocr; // [05] Operation control register (R/W) + unsigned char scr; // [06] Sequence control register (R/W) + unsigned char ccr; // [07] Channel control register (R/W) + unsigned short mtc; // [0a,0b] Memory Transfer Counter (R/W) + unsigned long mar; // [0c-0f] Memory Address Register (R/W) + unsigned long dar; // [14-17] Device Address Register (R/W) + unsigned short btc; // [1a,1b] Base Transfer Counter (R/W) + unsigned long bar; // [1c-1f] Base Address Register (R/W) + unsigned char niv; // [25] Normal Interrupt Vector (R/W) + unsigned char eiv; // [27] Error Interrupt Vector (R/W) + unsigned char mfc; // [29] Memory Function Code (R/W) + unsigned char cpr; // [2d] Channel Priority Register (R/W) + unsigned char dfc; // [31] Device Function Code (R/W) + unsigned char bfc; // [39] Base Function Code (R/W) + unsigned char gcr; // [3f] General Control Register (R/W) +}; + +class hd63450_device : public device_t +{ +public: + hd63450_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + ~hd63450_device() {} + + template static devcb_base &set_dma_end_callback(device_t &device, _Object object) { return downcast(device).m_dma_end.set_callback(object); } + template static devcb_base &set_dma_error_callback(device_t &device, _Object object) { return downcast(device).m_dma_error.set_callback(object); } + template static devcb_base &set_dma_read_0_callback(device_t &device, _Object object) { return downcast(device).m_dma_read_0.set_callback(object); } + template static devcb_base &set_dma_read_1_callback(device_t &device, _Object object) { return downcast(device).m_dma_read_1.set_callback(object); } + template static devcb_base &set_dma_read_2_callback(device_t &device, _Object object) { return downcast(device).m_dma_read_2.set_callback(object); } + template static devcb_base &set_dma_read_3_callback(device_t &device, _Object object) { return downcast(device).m_dma_read_3.set_callback(object); } + template static devcb_base &set_dma_write_0_callback(device_t &device, _Object object) { return downcast(device).m_dma_write_0.set_callback(object); } + template static devcb_base &set_dma_write_1_callback(device_t &device, _Object object) { return downcast(device).m_dma_write_1.set_callback(object); } + template static devcb_base &set_dma_write_2_callback(device_t &device, _Object object) { return downcast(device).m_dma_write_2.set_callback(object); } + template static devcb_base &set_dma_write_3_callback(device_t &device, _Object object) { return downcast(device).m_dma_write_3.set_callback(object); } + + static void set_cpu_tag(device_t &device, const char *tag) { downcast(device).m_cpu_tag = tag; } + static void set_our_clocks(device_t &device, const attotime &clk1, const attotime &clk2, const attotime &clk3, const attotime &clk4) + { + hd63450_device &dev = downcast(device); + dev.m_our_clock[0] = clk1; + dev.m_our_clock[1] = clk2; + dev.m_our_clock[2] = clk3; + dev.m_our_clock[3] = clk4; + } + static void set_burst_clocks(device_t &device, const attotime &clk1, const attotime &clk2, const attotime &clk3, const attotime &clk4) + { + hd63450_device &dev = downcast(device); + dev.m_burst_clock[0] = clk1; + dev.m_burst_clock[1] = clk2; + dev.m_burst_clock[2] = clk3; + dev.m_burst_clock[3] = clk4; + } + + DECLARE_READ16_MEMBER( read ); + DECLARE_WRITE16_MEMBER( write ); + DECLARE_WRITE_LINE_MEMBER(drq0_w); + DECLARE_WRITE_LINE_MEMBER(drq1_w); + DECLARE_WRITE_LINE_MEMBER(drq2_w); + DECLARE_WRITE_LINE_MEMBER(drq3_w); + + void single_transfer(int x); + void set_timer(int channel, const attotime &tm); + int get_vector(int channel); + int get_error_vector(int channel); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + +private: + devcb_write8 m_dma_end; + devcb_write8 m_dma_error; + devcb_read8 m_dma_read_0; + devcb_read8 m_dma_read_1; + devcb_read8 m_dma_read_2; + devcb_read8 m_dma_read_3; + devcb_write8 m_dma_write_0; + devcb_write8 m_dma_write_1; + devcb_write8 m_dma_write_2; + devcb_write8 m_dma_write_3; + + const char *m_cpu_tag; + attotime m_our_clock[4]; + attotime m_burst_clock[4]; + + // internal state + hd63450_regs m_reg[4]; + emu_timer* m_timer[4]; // for timing data reading/writing each channel + int m_in_progress[4]; // if a channel is in use + int m_transfer_size[4]; + int m_halted[4]; // non-zero if a channel has been halted, and can be continued later. + cpu_device *m_cpu; + bool m_drq_state[4]; + + TIMER_CALLBACK_MEMBER(dma_transfer_timer); + void dma_transfer_abort(int channel); + void dma_transfer_halt(int channel); + void dma_transfer_continue(int channel); + void dma_transfer_start(int channel); +}; + +extern const device_type HD63450; diff --git a/src/devices/machine/hd64610.c b/src/devices/machine/hd64610.c new file mode 100644 index 00000000000..d4639892e17 --- /dev/null +++ b/src/devices/machine/hd64610.c @@ -0,0 +1,366 @@ +// license:BSD-3-Clause +// copyright-holders:Sandro Ronco +/********************************************************************** + + Hitachi HD64610 Real Time Clock + +*********************************************************************/ + +/* + + TODO: + - leap year + - test mode + +*/ + +#include "hd64610.h" +#include "coreutil.h" + + +// device type definition +const device_type HD64610 = &device_creator; + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define LOG 1 + +// internal registers +enum +{ + REG_64HZ = 0, + REG_SECOND, + REG_MINUTE, + REG_HOUR, + REG_DAY_OF_THE_WEEK, + REG_DAY, + REG_MONTH, + REG_YEAR, + REG_64HZ_ALARM, + REG_SECOND_ALARM, + REG_MINUTE_ALARM, + REG_HOUR_ALARM, + REG_DAY_OF_THE_WEEK_ALARM, + REG_DAY_ALARM, + REG_CRA, + REG_CRB +}; + + +// Control Register A +#define CRA_CF 0x80 +#define CRA_CIE 0x10 +#define CRA_AIE 0x08 +#define CRA_AF 0x01 + +// Control Register B +#define CRB_TEST 0x08 +#define CRB_ADJ 0x04 +#define CRB_RESET 0x02 +#define CRB_S 0x01 + +// alarm +#define ALARM_ENB 0x80 + +// register write mask +static const int REG_WRITE_MASK[0x10] = +{ + 0x00, 0x7f, 0x7f, 0x3f, 0x07, 0x3f, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xbf, 0x83, 0xbf, 0x18, 0xff +}; + +//************************************************************************** +// INLINE HELPERS +//************************************************************************** + +//------------------------------------------------- +// set_irq_line - +//------------------------------------------------- + +inline void hd64610_device::set_irq_line() +{ + int irq_out = (((m_regs[REG_CRA] & CRA_CF) && (m_regs[REG_CRA] & CRA_CIE)) || + ((m_regs[REG_CRA] & CRA_AF) && (m_regs[REG_CRA] & CRA_AIE))) ? 0 : 1; + + if (m_irq_out != irq_out) + { + if (LOG) logerror("HD64610 '%s' IRQ %u\n", tag(), irq_out); + + m_out_irq_cb(irq_out); + m_irq_out = irq_out; + } +} + + +//------------------------------------------------- +// read_counter - +//------------------------------------------------- + +inline UINT8 hd64610_device::read_counter(int counter) +{ + return bcd_2_dec(m_regs[counter]); +} + + +//------------------------------------------------- +// write_counter - +//------------------------------------------------- + +inline void hd64610_device::write_counter(int counter, UINT8 value) +{ + m_regs[counter] = dec_2_bcd(value); +} + + +//------------------------------------------------- +// check_alarm - +//------------------------------------------------- + +inline void hd64610_device::check_alarm() +{ + bool alarm_flag = true; + + // clear alarm flag + m_regs[REG_CRA] &= ~CRA_AF; + + if (m_regs[REG_64HZ_ALARM] & ALARM_ENB || m_regs[REG_SECOND_ALARM] & ALARM_ENB || m_regs[REG_MINUTE_ALARM] & ALARM_ENB || + m_regs[REG_HOUR_ALARM] & ALARM_ENB || m_regs[REG_DAY_OF_THE_WEEK_ALARM] & ALARM_ENB || m_regs[REG_DAY_ALARM] & ALARM_ENB) + { + // at least one ENB is active + + for (int i = REG_64HZ; i <= REG_DAY; i++) + { + if ((m_regs[i] & REG_WRITE_MASK[i]) != (m_regs[i+8] & REG_WRITE_MASK[i]) && m_regs[i+8] & ALARM_ENB) + alarm_flag = false; + } + + m_regs[REG_CRA] |= (alarm_flag ? CRA_AF : 0); + } +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// hd64610_device - constructor +//------------------------------------------------- + +hd64610_device::hd64610_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, HD64610, "HD64610", tag, owner, clock, "hd64610", __FILE__), + device_rtc_interface(mconfig, *this), + device_nvram_interface(mconfig, *this), + m_out_irq_cb(*this), + m_out_1hz_cb(*this), + m_hline_state(1), + m_irq_out(1) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void hd64610_device::device_start() +{ + // resolve callbacks + m_out_irq_cb.resolve_safe(); + m_out_1hz_cb.resolve_safe(); + + // allocate timers + m_counter_timer = timer_alloc(TIMER_UPDATE_COUNTER); + m_counter_timer->adjust(attotime::from_hz(clock() / 256), 0, attotime::from_hz(clock() / 256)); + + // state saving + save_item(NAME(m_regs)); + save_item(NAME(m_irq_out)); + save_item(NAME(m_hline_state)); +} + + +//------------------------------------------------- +// device_start - device-specific reset +//------------------------------------------------- + +void hd64610_device::device_reset() +{ + set_current_time(machine()); +} + + +//------------------------------------------------- +// device_timer - handler timer events +//------------------------------------------------- + +void hd64610_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch (id) + { + case TIMER_UPDATE_COUNTER: + if(m_hline_state || (m_regs[REG_CRB] & CRB_S)) + { + m_regs[REG_64HZ]++; + + if (m_regs[REG_64HZ] & 0x80) + { + // update seconds + advance_seconds(); + + // set carry flag + m_regs[REG_CRA] |= CRA_CF; + + m_regs[REG_64HZ] &= 0x7f; + } + + // update 1Hz out + m_out_1hz_cb(BIT(m_regs[REG_64HZ], 6)); + + // update IRQ + check_alarm(); + set_irq_line(); + } + break; + } +} + + +//------------------------------------------------- +// rtc_clock_updated - +//------------------------------------------------- + +void hd64610_device::rtc_clock_updated(int year, int month, int day, int day_of_week, int hour, int minute, int second) +{ + write_counter(REG_SECOND, second); + write_counter(REG_MINUTE, minute); + write_counter(REG_HOUR, hour); + write_counter(REG_DAY, day); + write_counter(REG_MONTH, month); + write_counter(REG_YEAR, year); + m_regs[REG_DAY_OF_THE_WEEK] = day_of_week; + + check_alarm(); + set_irq_line(); +} + + +//------------------------------------------------- +// nvram_default - called to initialize NVRAM to +// its default state +//------------------------------------------------- + +void hd64610_device::nvram_default() +{ + memset(m_regs, 0, 0x10); +} + + +//------------------------------------------------- +// nvram_read - called to read NVRAM from the +// .nv file +//------------------------------------------------- + +void hd64610_device::nvram_read(emu_file &file) +{ + file.read(m_regs, 0x10); +} + + +//------------------------------------------------- +// nvram_write - called to write NVRAM to the +// .nv file +//------------------------------------------------- + +void hd64610_device::nvram_write(emu_file &file) +{ + file.write(m_regs, 0x10); +} + + +//------------------------------------------------- +// hardware start/stop +//------------------------------------------------- + +WRITE_LINE_MEMBER( hd64610_device::h_w ) +{ + m_hline_state = state; +} + + +//------------------------------------------------- +// read - +//------------------------------------------------- + +READ8_MEMBER( hd64610_device::read ) +{ + UINT8 data = m_regs[offset & 0x0f]; + + if (LOG) logerror("HD64610 '%s' Register %u Read %02x\n", tag(), offset, data); + + return data; +} + + +//------------------------------------------------- +// write - +//------------------------------------------------- + +WRITE8_MEMBER( hd64610_device::write ) +{ + switch (offset & 0x0f) + { + case REG_64HZ: + // read only + logerror("HD64610 '%s' Writing to read-only register 64Hz Counter\n", tag()); + break; + + case REG_CRA: + m_regs[REG_CRA] = data & REG_WRITE_MASK[REG_CRA]; + + if ((data & CRA_CF) == 0) + { + if (LOG) logerror("HD64610 '%s' clear carry flag\n", tag()); + m_regs[REG_CRA] &= 0x7f; + } + if ((data & CRA_AF) == 0) + { + if (LOG) logerror("HD64610 '%s' clear alarm flag\n", tag()); + m_regs[REG_CRA] &= 0xfe; + } + + if (LOG) logerror("HD64610 '%s' set alarm IRQ %d\n", tag(), BIT(data, 3)); + if (LOG) logerror("HD64610 '%s' set carry IRQ %d\n", tag(), BIT(data, 4)); + break; + + case REG_CRB: + m_regs[REG_CRB] = data & REG_WRITE_MASK[REG_CRB]; + + if (data & CRB_ADJ) + { + if (LOG) logerror("HD64610 '%s' 30-sec adjustament\n", tag()); + adjust_seconds(); + m_regs[REG_64HZ] = 0; + + m_regs[REG_CRB] &= ~CRB_ADJ; + } + + if (data & CRB_RESET) + { + if (LOG) logerror("HD64610 '%s' CRB reset\n", tag()); + m_regs[REG_64HZ] = 0; + + m_regs[REG_CRB] &= ~CRB_RESET; + } + + if (LOG) logerror("HD64610 '%s' set timer %d\n", tag(), BIT(data, 0)); + break; + + default: + m_regs[offset & 0x0f] = data & REG_WRITE_MASK[offset & 0x0f]; + if (LOG) logerror("HD64610 '%s' Register %u Write %02x\n", tag(), offset & 0x0f, data); + break; + } +} diff --git a/src/devices/machine/hd64610.h b/src/devices/machine/hd64610.h new file mode 100644 index 00000000000..cb1d79d8388 --- /dev/null +++ b/src/devices/machine/hd64610.h @@ -0,0 +1,105 @@ +// license:BSD-3-Clause +// copyright-holders:Sandro Ronco +/********************************************************************** + + Hitachi HD64610 Real Time Clock + +********************************************************************** + _____ _____ + GND 1 |* \_/ | 24 Vcc + H-Start/Stop 2 | | 23 OSC2 + _IRQ 3 | | 22 OSC1 + 1Hz 4 | HD64610 | 21 GND + A3 5 | | 20 _WE + A2 6 | | 19 _OE + A1 7 | | 18 _CS + A0 8 | | 17 I/O8 + I/O1 9 | | 16 I/O7 + I/O2 10 | | 15 I/O6 + I/O3 11 | | 14 I/O5 + GND 12 |_____________| 13 I/O4 + +**********************************************************************/ + +#pragma once + +#ifndef __HD64610__ +#define __HD64610__ + +#include "emu.h" + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_HD64610_OUT_IRQ_CB(_devcb) \ + devcb = &hd64610_device::set_out_irq_callback(*device, DEVCB_##_devcb); + +#define MCFG_HD64610_OUT_1HZ_CB(_devcb) \ + devcb = &hd64610_device::set_out_1hz_callback(*device, DEVCB_##_devcb); + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> hd64610_device + +class hd64610_device : public device_t, + public device_rtc_interface, + public device_nvram_interface +{ +public: + // construction/destruction + hd64610_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + template static devcb_base &set_out_irq_callback(device_t &device, _Object object) { return downcast(device).m_out_irq_cb.set_callback(object); } + template static devcb_base &set_out_1hz_callback(device_t &device, _Object object) { return downcast(device).m_out_1hz_cb.set_callback(object); } + + DECLARE_READ8_MEMBER( read ); + DECLARE_WRITE8_MEMBER( write ); + + // hardware start/stop line + DECLARE_WRITE_LINE_MEMBER( h_w ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + // device_rtc_interface overrides + virtual void rtc_clock_updated(int year, int month, int day, int day_of_week, int hour, int minute, int second); + + // device_nvram_interface overrides + virtual void nvram_default(); + virtual void nvram_read(emu_file &file); + virtual void nvram_write(emu_file &file); + +private: + inline void set_irq_line(); + inline UINT8 read_counter(int counter); + inline void write_counter(int counter, UINT8 value); + inline void check_alarm(); + + static const device_timer_id TIMER_UPDATE_COUNTER = 0; + + devcb_write_line m_out_irq_cb; + devcb_write_line m_out_1hz_cb; + + UINT8 m_regs[0x10]; // Internal registers + int m_hline_state; // H-Start/Stop line + int m_irq_out; // alarm output + + // timers + emu_timer *m_counter_timer; +}; + + +// device type definition +extern const device_type HD64610; + + +#endif diff --git a/src/devices/machine/hdc92x4.c b/src/devices/machine/hdc92x4.c new file mode 100644 index 00000000000..f887c9a7bbb --- /dev/null +++ b/src/devices/machine/hdc92x4.c @@ -0,0 +1,4456 @@ +// license:BSD-3-Clause +// copyright-holders:Michael Zapf +/************************************************************************** + + HDC 9224 and HDC 9234 Hard and Floppy Disk Controller + Standard Microsystems Corporation (SMC) + + This controller handles MFM and FM encoded floppy disks and hard disks. + + References: + [1] SMC HDC9234 preliminary data book (1988) + [2] SMC HDC9224 data book + + The HDC 9224 / 9234 controller is also referred to as the "Universal Disk Controller" (UDC) + by the data book + + Michael Zapf, August 2015 + +***************************************************************************/ + +#include "emu.h" +#include "hdc92x4.h" +#include "formats/imageutl.h" + +// Per-command debugging +#define TRACE_COMMAND 0 +#define TRACE_SELECT 0 +#define TRACE_STEP 0 +#define TRACE_RESTORE 0 +#define TRACE_SUBSTATES 0 +#define TRACE_READ 0 +#define TRACE_WRITE 0 +#define TRACE_READREG 0 +#define TRACE_SETREG 0 +#define TRACE_SETPTR 0 +#define TRACE_FORMAT 0 +#define TRACE_READTRACK 0 + +// Common states +#define TRACE_READID 0 +#define TRACE_VERIFY 0 +#define TRACE_TRANSFER 0 + +// Live states debugging +#define TRACE_LIVE 0 +#define TRACE_SHIFT 0 +#define TRACE_SYNC 0 + +// Misc debugging +#define TRACE_DELAY 0 +#define TRACE_INT 0 +#define TRACE_LINES 0 +#define TRACE_INDEX 0 +#define TRACE_DMA 0 +#define TRACE_DONE 0 +#define TRACE_FAIL 1 +#define TRACE_AUXBUS 0 +#define TRACE_HEADER 0 +#define TRACE_GAPS 0 + +#define TRACE_DETAIL 0 + +#define UNRELIABLE_MEDIA 0 + +/* + === Not implemented === + ECC + Write long (see MODE register; only useful with ECC) + Tape operations + AT mode (HD) + FM-encoded HD + + === Implemented but untested === + Restore + Poll drives + Seek/Read ID + Read track + + === TODO === + Create a common state machine for HD and floppy +*/ + +/* + Some registers of the HDC. + + +------+------+------+------+------+------+------+------+ + DHEAD: | 0 | Sector size | 0 | Desired head (OUTPUT2) | AT mode + +------+------+------+------+------+------+------+------+ + | 0 | Desired cylinder | Desired head (OUTPUT2) | SMC mode + +------+------+------+------+------+------+------+------+ + +------+------+------+------+------+------+------+------+ + RETRY: | Retry count (ones comp!) | Progr. output (OUTPUT1) | + +------+------+------+------+------+------+------+------+ + +------+------+------+------+------+------+------+------+ + MODE: | HD | use CRC/ECC | FM | 0 | step rate | + +------+------+------+------+------+------+------+------+ + +------+------+------+------+------+------+------+------+ + INTCOMM:| 1 | 0 | Done | DelD | User | WrPrt| Ready|Wfault| + +------+------+------+------+------+------+------+------+ + +------+------+------+------+------+------+------+------+ + DDELAY: | 0 | 0 | Sector size | 0 | 0 | Zone | AT mode + +------+------+------+------+------+------+------+------+ + | Data to be written on disk | writing + +------+------+------+------+------+------+------+------+ + | Head load timer count | drselect + +------+------+------+------+------+------+------+------+ + + Read registers + +------+------+------+------+------+------+------+------+ + CHIP_ST:| Retry| ECC | CRC | DelD | Sync | Comp | Current Drv | + +------+------+------+------+------+------+------+------+ + +------+------+------+------+------+------+------+------+ + INT_ST: | Pend | DMARQ| Done | Termcode | RdyCh| Ovrun| BdSec| + +------+------+------+------+------+------+------+------+ + +------+------+------+------+------+------+------+------+ + DRV_ST: | ECC | Index| SeekC| Trk00| User | WrPrt| Ready|Wfault| + +------+------+------+------+------+------+------+------+ + +*/ +enum +{ + // Write registers | Read registers + //-------------------------------------- + DMA7_0=0, + DMA15_8=1, + DMA23_16=2, + DESIRED_SECTOR=3, CURRENT_SECTOR=3, + DESIRED_HEAD=4, CURRENT_HEAD=4, + DESIRED_CYLINDER=5, CURRENT_CYLINDER=5, + SECTOR_COUNT=6, CURRENT_IDENT=6, + RETRY_COUNT=7, TEMP_STORAGE2=7, + MODE=8, CHIP_STATUS=8, + INT_COMM_TERM=9, DRIVE_STATUS=9, + DATA_DELAY=10, DATA=10, + COMMAND=11, INT_STATUS=11, + + //====================== + // Internal registers + CURRENT_SIZE=12, + CURRENT_CRC1=13, + CURRENT_CRC2=14 +}; + +/* + Definition of bits in the status register [1] p.7 +*/ +enum +{ + ST_INTPEND = 0x80, // interrupt pending + ST_DMAREQ = 0x40, // DMA request + ST_DONE = 0x20, // command done + ST_TERMCOD = 0x18, // termination code (see below) + TC_SUCCESS = 0x00, // Successful completion + TC_RDIDERR = 0x08, // Error in READ-ID sequence + TC_VRFYERR = 0x10, // Error in VERIFY sequence + TC_DATAERR = 0x18, // Error in DATA-TRANSFER seq. + ST_RDYCHNG = 0x04, // ready change + ST_OVRUN = 0x02, // overrun/underrun + ST_BADSECT = 0x01 // bad sector +}; + +/* + Definition of bits in the Termination-Conditions register +*/ +enum +{ + TC_CRCPRE = 0x80, // CRC register preset, must be 1 + TC_UNUSED = 0x40, // bit 6 is not used and must be 0 + TC_INTDONE = 0x20, // interrupt on command completion + TC_TDELDAT = 0x10, // terminate on deleted data mark detection + TC_TDUSER = 0x08, // user-defined condition + TC_TWPROT = 0x04, // terminate on write protection + TC_INTRDCH = 0x02, // interrupt on ready change + TC_TWRFLT = 0x01 // interrupt on write fault +}; + +/* + Definition of bits in the chip status register. +*/ +enum +{ + CS_RETREQ = 0x80, // retry required + CS_ECCATT = 0x40, // ECC correction attempted + CS_CRCERR = 0x20, // ECC/CRC error + CS_DELDATA = 0x10, // deleted data mark + CS_SYNCERR = 0x08, // synchronization error + CS_COMPERR = 0x04, // compare error + CS_PRESDRV = 0x03 // present drive selected +}; + +/* + Bits in the internal output registers. The registers are output via the + auxiliary bus (AB) + + OUTPUT1 + AB7 drive select 3 + AB6 drive select 2 + AB5 drive select 1 + AB4 drive select 0 + AB3 programmable outputs + AB2 programmable outputs + AB1 programmable outputs + AB0 programmable outputs + + OUTPUT2 + AB7 drive select 3* (active low, used for tape operations) + AB6 reduce write current + AB5 step direction (0=towards TRK00) + AB4 step pulse (1=active) + AB3 desired head 3 + AB2 desired head 2 + AB1 desired head 1 + AB0 desired head 0 +*/ +enum +{ + OUT1_DRVSEL3 = 0x80, + OUT1_DRVSEL2 = 0x40, + OUT1_DRVSEL1 = 0x20, + OUT1_DRVSEL0 = 0x10, + OUT2_DRVSEL3I = 0x80, + OUT2_REDWRT = 0x40, + OUT2_STEPDIR = 0x20, + OUT2_STEPPULSE = 0x10, + OUT2_HEADSEL = 0x0f +}; + +#define NODRIVE -1 + +enum +{ + TYPE_AT = 0x00, + TYPE_HD = 0x01, + TYPE_FLOPPY8 = 0x02, + TYPE_FLOPPY5 = 0x03 +}; + +/* + Timers +*/ +enum +{ + GEN_TIMER = 1, + COM_TIMER /*, + LIVE_TIMER */ +}; + +/* + Definition of bits in the Mode register +*/ +enum { + MO_TYPE = 0x80, // Hard disk (1) or floppy (0) + MO_CRCECC = 0x60, // Values for CRC/ECC handling + MO_DENSITY = 0x10, // FM = 1; MFM = 0 + MO_UNUSED = 0x08, // Unused, 0 + MO_STEPRATE = 0x07 // Step rates +}; + +/* + Step rates in microseconds for MFM. This is set in the mode register, + bits 0-2. FM mode doubles all values. +*/ +static const int step_hd[] = { 22, 50, 100, 200, 400, 800, 1600, 3200 }; +static const int step_flop8[] = { 218, 500, 1000, 2000, 4000, 8000, 16000, 32000 }; +static const int step_flop5[] = { 436, 1000, 2000, 4000, 8000, 16000, 32000, 64000 }; + +/* + Head load timer increments in usec. Delay value is calculated from this value + multiplied by the factor in the DATA/DELAY register. For FM mode all + values are doubled. The values depend on the drive type. +*/ +static const int head_load_timer_increment[] = { 200, 200, 2000, 4000 }; + +/* + ID fields association to registers +*/ +static const int id_field[] = { CURRENT_CYLINDER, CURRENT_HEAD, CURRENT_SECTOR, CURRENT_SIZE, CURRENT_CRC1, CURRENT_CRC2 }; + +/* + Pulse widths for stepping in usec +*/ +enum +{ + pulse_hd = 11, + pulse_flop8 = 112, + pulse_flop5 = 224 +}; + +/* + Times for UDC's acceptance of command and register write accesses (ns). +*/ +enum +{ + REGISTER_COMMIT = 1000, + COMMAND_COMMIT = 1000 +}; + +enum +{ + UNDEF = 0x00, + IDLE, + DONE, + COMMAND_INIT, + REGISTER_ACCESS, + + STEP_ON, + STEP_OFF, + RESTORE_CHECK, + WAIT_SEEK_COMPLETE, // 0x08 + SEEK_COMPLETE, + HEAD_DELAY, + WAITINDEX0, + WAITINDEX1, + TRACKSTART, + TRACKDONE, + POLL1, + POLL2, // 0x10 + POLL3, + + READ_ID = 0x40, + READ_ID1, + READ_ID_STEPON, + READ_ID_STEPOFF, + READ_ID_SEEK_COMPLETE, + + VERIFY = 0x50, + VERIFY1, + VERIFY2, + VERIFY3, + + DATA_TRANSFER = 0x60, + DATA_TRANSFER_READ, + DATA_TRANSFER_WRITE, + + // Live states + LIVE_STATES = 0x80, + SEARCH_IDAM, + SEARCH_IDAM_FAILED, + VERIFY_FAILED, + READ_TWO_MORE_A1_IDAM, + READ_IDENT, + READ_ID_FIELDS_INTO_REGS, + SEARCH_DAM, + READ_TWO_MORE_A1_DAM, // 0x88 + READ_DATADEL_FLAG, + SEARCH_DAM_FAILED, + READ_SECTOR_DATA, + READ_SECTOR_DATA_CONT, + WRITE_DAM_AND_SECTOR, + WRITE_SEC_SKIP_GAP2, + WRITE_SEC_SKIP_GAP2_LOOP, + WRITE_SEC_BYTE, // 0x90 + WRITE_SEC_NEXT_BYTE, + + WRITE_TRACK_BYTE, + WRITE_TRACK_NEXT_BYTE, + + READ_TRACK_BYTE, + READ_TRACK_NEXT_BYTE, + + FORMAT_TRACK, + WRITE_GAP0, + WRITE_GAP1, // 0x98 + WRITE_GAP2, + WRITE_GAP3, + WRITE_GAP4, + WRITE_IXAM_SYNC, + WRITE_IXAM, + WRITE_FC, + WRITE_IDAM_SYNC, + WRITE_IDAM, // 0xa0 + WRITE_HEADER, + WRITE_IDENT, + + WRITE_DAM_SYNC, + WRITE_A1, + WRITE_DATAMARK, + WRITE_SECDATA, + WRITE_DATA_CRC, + WRITE_DONE, // 0xa8 + WRITE_HEADER_CRC, + + READ_TRACK, + READ_TRACK_ID, + READ_TRACK_ID_DONE, + + NO_DMA_ACK +}; + +/* + Event lines +*/ +enum +{ + INDEX_LINE = 1, + READY_LINE, + SEEKCOMP_LINE +}; + +/* + State machine metastates. +*/ +enum +{ + CONTINUE = 0, + WAIT, + NEXT, + ERROR, + SUCCESS +}; + +const hdc92x4_device::cmddef hdc92x4_device::s_command[] = +{ + { 0x00, 0xff, &hdc92x4_device::reset_controller }, + { 0x01, 0xff, &hdc92x4_device::drive_deselect }, + { 0x02, 0xfe, &hdc92x4_device::restore_drive }, + { 0x04, 0xfc, &hdc92x4_device::step_drive }, + { 0x08, 0xf8, &hdc92x4_device::tape_backup }, + { 0x10, 0xf0, &hdc92x4_device::poll_drives }, + { 0x20, 0xe0, &hdc92x4_device::drive_select }, + { 0x40, 0xf0, &hdc92x4_device::set_register_pointer }, + { 0x50, 0xf8, &hdc92x4_device::seek_read_id }, + { 0x58, 0xfe, &hdc92x4_device::read_sectors }, + { 0x5a, 0xfe, &hdc92x4_device::read_track }, + { 0x5c, 0xfc, &hdc92x4_device::read_sectors }, + { 0x60, 0xe0, &hdc92x4_device::format_track }, + { 0x80, 0x80, &hdc92x4_device::write_sectors }, + { 0, 0, 0 } +}; + +/* + Standard constructor for the base class and the two variants +*/ +hdc92x4_device::hdc92x4_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + m_out_intrq(*this), + m_out_dmarq(*this), + m_out_dip(*this), + m_out_auxbus(*this), + m_in_dma(*this), + m_out_dma(*this), + m_initialized(false) +{ +} + +hdc9224_device::hdc9224_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : hdc92x4_device(mconfig, HDC9224, "SMC HDC9224 Universal Disk Controller", tag, owner, clock, "hdc9224", __FILE__) +{ + m_is_hdc9234 = false; +} + +hdc9234_device::hdc9234_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : hdc92x4_device(mconfig, HDC9234, "SMC HDC9234 Universal Disk Controller", tag, owner, clock, "hdc9234", __FILE__) +{ + m_is_hdc9234 = true; +} + + +/* + Set or reset some bits. +*/ +void hdc92x4_device::set_bits(UINT8& byte, int mask, bool set) +{ + if (set) byte |= mask; + else byte &= ~mask; +} + +/* + Tell whether the controller is in FM mode. +*/ +bool hdc92x4_device::fm_mode() +{ + return ((m_register_w[MODE]&MO_DENSITY)!=0); +} + +/* + Are we back on track 0? +*/ +bool hdc92x4_device::on_track00() +{ + return (m_register_r[DRIVE_STATUS] & HDC_DS_TRK00)!=0; +} + +/* + Seek completed? +*/ +bool hdc92x4_device::seek_complete() +{ + return (m_register_r[DRIVE_STATUS] & HDC_DS_SKCOM)!=0; +} + +/* + Index hole? +*/ +bool hdc92x4_device::index_hole() +{ + return (m_register_r[DRIVE_STATUS] & HDC_DS_INDEX)!=0; +} + +/* + Drive ready? +*/ +bool hdc92x4_device::drive_ready() +{ + return (m_register_r[DRIVE_STATUS] & HDC_DS_READY)!=0; +} + +/* + Doing a track read? +*/ +bool hdc92x4_device::reading_track() +{ + return (current_command() & 0xfe) == 0x5a; +} + +/* + Accessor functions for specific parameters. +*/ + +/* + In SMC mode, the cylinder number is stored in bit positions 4,5,6 of the + head register and in the 8 bits of the cylinder register. + This is true for the desired cyl/head, current cyl/head, and the header + fields on the track. +*/ +int hdc92x4_device::desired_head() +{ + return m_register_w[DESIRED_HEAD] & 0x0f; +} + +int hdc92x4_device::desired_cylinder() +{ + return (m_register_w[DESIRED_CYLINDER] & 0xff) | ((m_register_w[DESIRED_HEAD] & 0x70) << 4); +} + +int hdc92x4_device::desired_sector() +{ + return m_register_w[DESIRED_SECTOR] & 0xff; +} + +int hdc92x4_device::current_head() +{ + return m_register_r[CURRENT_HEAD] & 0x0f; +} + +int hdc92x4_device::current_cylinder() +{ + return (m_register_r[CURRENT_CYLINDER] & 0xff) | ((m_register_r[CURRENT_HEAD] & 0x70) << 4); +} + +int hdc92x4_device::current_sector() +{ + return m_register_r[CURRENT_SECTOR] & 0xff; +} + +UINT8 hdc92x4_device::current_command() +{ + return m_register_w[COMMAND]; +} + +bool hdc92x4_device::using_floppy() +{ + return (m_selected_drive_type == TYPE_FLOPPY5 || m_selected_drive_type == TYPE_FLOPPY8); +} + +/* + Delivers the step time (in microseconds) minus the pulse width +*/ +int hdc92x4_device::step_time() +{ + int time = 0; + int index = m_register_w[MODE] & MO_STEPRATE; + // Get seek time. + if (m_selected_drive_type == TYPE_FLOPPY8) + time = step_flop8[index] - pulse_flop8; + + else if (m_selected_drive_type == TYPE_FLOPPY5) + time = step_flop5[index] - pulse_flop5; + else + time = step_hd[index] - pulse_hd; + + if (fm_mode()) time = time * 2; + return time; +} + +/* + Delivers the pulse width time (in microseconds) +*/ +int hdc92x4_device::pulse_width() +{ + int time = 0; + // Get seek time. + if (m_selected_drive_type == TYPE_FLOPPY8) + time = pulse_flop8; + + else if (m_selected_drive_type == TYPE_FLOPPY5) + time = pulse_flop5; + else + time = pulse_hd; + + if (fm_mode()) time = time * 2; + return time; +} + +/* + Delivers the sector size +*/ +int hdc92x4_device::calc_sector_size() +{ + return 128 << (m_register_r[CURRENT_SIZE] & 3); +} + +// =========================================================================== +// Wait handling +// We can wait for a given time period or for a line to be set or cleared +// =========================================================================== + +void hdc92x4_device::wait_time(emu_timer *tm, int microsec, int next_substate) +{ + wait_time(tm, attotime::from_usec(microsec), next_substate); +} + +void hdc92x4_device::wait_time(emu_timer *tm, const attotime &delay, int param) +{ + if (TRACE_DELAY) logerror("%s: [%s] Delaying by %4.2f microsecs\n", tag(), ttsn().c_str(), delay.as_double()*1000000); + tm->adjust(delay); + m_substate = param; + m_state_after_line = UNDEF; + m_timed_wait = true; +} + +/* + Set the hook for line level handling +*/ +void hdc92x4_device::wait_line(int line, line_state level, int substate, bool stopwrite) +{ + bool line_at_level = true; + m_timed_wait = false; + + if (line == SEEKCOMP_LINE && (seek_complete() == (level==ASSERT_LINE))) + { + if (TRACE_LINES) logerror("%s: SEEK_COMPLETE line is already %d\n", tag(), level); + } + else + { + if (line == INDEX_LINE && (index_hole() == (level==ASSERT_LINE))) + { + if (TRACE_LINES) logerror("%s: INDEX line is already %d\n", tag(), level); + } + else + { + if (line == READY_LINE && (drive_ready() == (level==ASSERT_LINE))) + { + if (TRACE_LINES) logerror("%s: READY line is already %d\n", tag(), level); + } + else + { + // The line is not yet at the desired level; hence, arm the trigger. + m_event_line = line; + m_line_level = level; + m_state_after_line = substate; + m_stopwrite = stopwrite; + line_at_level = false; + } + } + } + + if (line_at_level) + { + m_substate = substate; + m_event_line = UNDEF; + m_state_after_line = UNDEF; + reenter_command_processing(); + } +} + +// ================================================================== +// Common subroutines READ ID, VERIFY, DATA TRANSFER +// called by all sector access commands +// ================================================================== +/* + READ ID FIELD ([1] p. 9) + The controller + - scans for the next IDAM + - reads the ID field values into the CURRENT_HEAD/CYLINDER/SECTOR registers + - checks the CRC + - calculates the number of steps and the direction towards DESIRED_CYLINDER + (must have saved that value before!) + - steps to that location during OUTPUT2 times +*/ +void hdc92x4_device::read_id(int& cont, bool implied_seek, bool wait_seek_complete) +{ + cont = CONTINUE; + + while (cont==CONTINUE) + { + switch (m_substate) + { + case READ_ID: + // Implied seek: Enter the READ_ID subprogram. + if (TRACE_READID && TRACE_SUBSTATES) logerror("%s: substate READ_ID\n", tag()); + + // First step: Search the next IDAM, and if found, read the + // ID values into the registers + + // Depending on the implied seek flag, continue with read_id, + // else switch to verify. + m_substate = implied_seek? READ_ID1 : VERIFY; + + m_live_state.bit_count_total = 0; + live_start(SEARCH_IDAM); + cont = WAIT; + break; + + case READ_ID1: + // If an error occurred (no IDAM found), terminate the command + if ((m_register_r[CHIP_STATUS] & CS_SYNCERR) != 0) + { + if (TRACE_FAIL) logerror("%s: READ_ID failed to find any IDAM\n", tag()); + cont = ERROR; + break; + } + + if (TRACE_READID) + { + if (TRACE_SUBSTATES) logerror("%s: substate READ_ID1\n", tag()); + logerror("%s: DESIRED_CYL = %d; CURRENT_CYL = %d\n", tag(), desired_cylinder(), current_cylinder()); + } + + // The CRC has been updated automatically with each read_one_bit during the live_run. + // We just need to check whether it ended in 0000 + if (m_live_state.crc != 0) + { + if (TRACE_FAIL) logerror("%s: CRC error in sector header\n", tag()); + set_bits(m_register_r[CHIP_STATUS], CS_CRCERR, true); + cont = ERROR; + break; + } + + // Calculate the direction and number of step pulses + // positive -> towards inner cylinders + // negative -> towards outer cylinders + // zero -> we're already there + m_track_delta = desired_cylinder() - current_cylinder(); + m_substate = READ_ID_STEPON; + break; + + case READ_ID_STEPON: + // Any more steps left? + if (m_track_delta == 0) + { + if (wait_seek_complete) + { + // We have to wait for SEEK COMPLETE + if (TRACE_READID && TRACE_SUBSTATES) logerror("%s: Waiting for SEEK COMPLETE\n", tag()); + wait_line(SEEKCOMP_LINE, ASSERT_LINE, READ_ID_SEEK_COMPLETE, false); + cont = WAIT; + } + else + { + // We do not wait for SEEK COMPLETE + m_substate = VERIFY; + cont = NEXT; + } + break; + } + + if (TRACE_READID && TRACE_SUBSTATES) logerror("%s: substate STEP_ON\n", tag()); + // STEPDIR = 0 -> towards TRK00 + set_bits(m_output2, OUT2_STEPDIR, (m_track_delta>0)); + set_bits(m_output2, OUT2_STEPPULSE, true); + wait_time(m_timer, pulse_width(), READ_ID_STEPOFF); + cont = WAIT; + break; + + case READ_ID_STEPOFF: + if (TRACE_READID && TRACE_SUBSTATES) logerror("%s: substate STEP_OFF\n", tag()); + set_bits(m_output2, OUT2_STEPPULSE, false); + m_track_delta += (m_track_delta<0)? 1 : -1; + // Return to STEP_ON, check whether there are more steps + wait_time(m_timer, step_time(), READ_ID_STEPON); + cont = WAIT; + break; + + case READ_ID_SEEK_COMPLETE: + m_substate = VERIFY; + cont = NEXT; + break; + + default: + logerror("%s: BUG: Unknown substate %02x in read_id, aborting command\n", tag(), m_substate); + cont = ERROR; + } + } + + // When an error occurs, the COMMAND_TERMINATION bits are set to 01 + if (cont == ERROR) + { + live_abort(); + set_command_done(TC_RDIDERR); + } +} + +/* + VERIFY ([1] p. 10) + The controller + - continues to read the next ID field until the current values match the + contents of the DESIRED_HEAD/CYLINDER/SECTOR registers + - checks the CRC +*/ +void hdc92x4_device::verify(int& cont) +{ + cont = CONTINUE; + + while (cont==CONTINUE) + { + switch (m_substate) + { + case VERIFY: + // After seeking (or immediately when implied seek has been disabled), + // find the desired sector. + + if (TRACE_VERIFY && TRACE_SUBSTATES) logerror("%s: substate VERIFY\n", tag()); + if (TRACE_VERIFY) logerror("%s: VERIFY: Find sector CHS=(%d,%d,%d)\n", tag(), + desired_cylinder(), + desired_head(), + desired_sector()); + + // If an error occurred (no IDAM found), terminate the command + // (This test is only relevant when we did not have a seek phase before) + if ((m_register_r[CHIP_STATUS] & CS_SYNCERR) != 0) + { + if (TRACE_FAIL) logerror("%s: VERIFY failed to find any IDAM\n", tag()); + cont = ERROR; + break; + } + + // Count from 0 again + m_live_state.bit_count_total = 0; + m_substate = VERIFY1; + break; + + case VERIFY1: + // Check whether we are already there + if (desired_cylinder() == current_cylinder() + && desired_head() == current_head() + && desired_sector() == current_sector()) + { + if (TRACE_VERIFY) logerror("%s: Found the desired sector CHS=(%d,%d,%d)\n", tag(), + desired_cylinder(), + desired_head(), + desired_sector()); + m_substate = DATA_TRANSFER; + cont = NEXT; + m_first_sector_found = true; + } + else + { + if (TRACE_VERIFY && TRACE_DETAIL) logerror("%s: Current CHS=(%d,%d,%d), desired CHS=(%d,%d,%d).\n", tag(), + current_cylinder(), + current_head(), + current_sector(), + desired_cylinder(), + desired_head(), + desired_sector()); + m_substate = VERIFY2; + } + break; + + case VERIFY2: + // Search the next ID + m_substate = VERIFY3; + live_start(SEARCH_IDAM); + cont = WAIT; + break; + + case VERIFY3: + if (TRACE_VERIFY) logerror("%s: Next IDAM found; total bytes read: %d\n", tag(), m_live_state.bit_count_total / 16); + if ((m_register_r[CHIP_STATUS] & CS_COMPERR) != 0) + { + if (TRACE_FAIL) logerror("%s: VERIFY failed to find sector CHS=(%d,%d,%d)\n", tag(), desired_cylinder(), desired_head(), desired_sector()); + cont = ERROR; + break; + } + + // Continue with the loop + if (m_logical || !m_first_sector_found) + { + // this is for the logical sector reading/writing + m_substate = VERIFY1; + } + else + { + // this is for the physical sector reading/writing + // do not verify the next ID field + m_substate = DATA_TRANSFER; + m_wait_for_index = true; + cont = NEXT; + } + break; + + default: + logerror("%s: BUG: Unknown substate %02x in verify, aborting command\n", tag(), m_substate); + cont = ERROR; + } + } + + // When an error occurs, the COMMAND_TERMINATION bits are set to 10 + if (cont == ERROR) + { + live_abort(); + set_command_done(TC_VRFYERR); + } +} + +/* + DATA TRANSFER ([1], p. 10) + only during READ/WRITE PHYSICAL/LOGICAL + The controller + - scans for the next DAM + - initiates a DMA request and waits for ACK from the system processor + - transfers the contents of the current sector into memory via DMA (read) or + via DMA to the sector (write) +*/ +void hdc92x4_device::data_transfer(int& cont) +{ + cont = CONTINUE; + + while (cont==CONTINUE) + { + switch (m_substate) + { + case DATA_TRANSFER: + if (TRACE_TRANSFER && TRACE_SUBSTATES) logerror("%s: substate DATA_TRANSFER (%s)\n", tag(), m_write? "write" : "read"); + + // Count from 0 again + m_live_state.bit_count_total = 0; + + if (m_transfer_enabled) dma_address_out(m_register_w[DMA23_16], m_register_w[DMA15_8], m_register_w[DMA7_0]); + + if (TRACE_TRANSFER && TRACE_DETAIL) + { + if (m_logical) + logerror("%s: %s sector CHS=(%d,%d,%d)\n", tag(), m_write? "Write" : "Read", + desired_cylinder(), + desired_head(), + desired_sector()); + else + logerror("%s: %s next sector on track\n", tag(), m_write? "Write" : "Read"); + } + + if (m_write) + { + m_substate = DATA_TRANSFER_WRITE; + live_start(WRITE_DAM_AND_SECTOR); + } + else + { + m_substate = DATA_TRANSFER_READ; + live_start(SEARCH_DAM); + } + + cont = WAIT; + break; + + case DATA_TRANSFER_READ: + // OK, sector has been read. + // Check CRC + if (m_live_state.crc != 0) + { + // Set Retry Required flag + set_bits(m_register_r[CHIP_STATUS], CS_RETREQ, true); + + // Decrement the retry register (one's complemented value; 0000 = 15) + int retry = 15-((m_register_w[RETRY_COUNT] >> 4)&0x0f); + + if (TRACE_FAIL) logerror("%s: DATA TRANSFER got CRC error in sector data, retries = %d\n", tag(), retry); + m_register_w[RETRY_COUNT] = (m_register_w[RETRY_COUNT] & 0x0f) | ((15-(retry-1))<<4); + + if (retry == 0) + { + if (TRACE_FAIL) logerror("%s: CRC error; no retries left\n", tag()); + set_bits(m_register_r[CHIP_STATUS], CS_CRCERR, true); + cont = ERROR; + } + else + { + // Go back to VERIFY and try again + // Note that the specs recommend to set the retry to 0 (1111) + // for physical reading; failing to do so will result in + // unpredictable behavior. + // We'll rely on the properly written software as well. + m_live_state.bit_count_total = 0; + m_substate = VERIFY2; + cont = NEXT; + } + } + else + { + if (TRACE_TRANSFER) logerror("%s: Sector successfully read (count=%d)\n", tag(), m_register_w[SECTOR_COUNT]-1); + + // Update the DMA registers for multi-sector operations + if (m_multi_sector) + { + int dma_address = (m_register_w[DMA23_16] & 0xff) << 16 | + (m_register_w[DMA15_8] & 0xff) << 8 | + (m_register_w[DMA7_0] & 0xff); + + dma_address = (dma_address + calc_sector_size()) & 0xffffff; + + m_register_w[DMA23_16] = m_register_r[DMA23_16] = (dma_address & 0xff0000) >> 16; + m_register_w[DMA15_8] = m_register_r[DMA15_8] = (dma_address & 0x00ff00) >> 8; + m_register_w[DMA7_0] = m_register_r[DMA7_0] = (dma_address & 0x0000ff); + if (TRACE_TRANSFER) logerror("%s: New DMA address = %06x\n", tag(), dma_address); + } + + // Decrement the count + m_register_w[SECTOR_COUNT] = (m_register_w[SECTOR_COUNT]-1) & 0xff; + + // Do we have more sectors to read? + // Surprisingly, the manual does not say what happens when + // the sector count is zero for the first access. + // It explicitly states that the check is done after the access. + // If we take it (and especially the state charts) seriously, zero means 256. + // m_stop_after_index is important for physical reading + if (m_register_w[SECTOR_COUNT] != 0 && !m_stop_after_index) + { + // Increment the sector number + // What happens when we exceed the highest sector number + // in the track? We have to assume that this is possible + // and that in this case the VERIFY routine fails. + if (m_logical) m_register_w[DESIRED_SECTOR] = (desired_sector() + 1) & 0xff; + m_substate = VERIFY2; + cont = NEXT; + m_live_state.bit_count_total = 0; + } + else + cont = SUCCESS; + } + break; + + case DATA_TRANSFER_WRITE: + if (TRACE_TRANSFER) logerror("%s: Sector successfully written (count=%d)\n", tag(), m_register_w[SECTOR_COUNT]-1); + + // Update the DMA registers for multi-sector operations + if (m_multi_sector) + { + int dma_address = (m_register_w[DMA23_16] & 0xff) << 16 | + (m_register_w[DMA15_8] & 0xff) << 8 | + (m_register_w[DMA7_0] & 0xff); + + dma_address = (dma_address + calc_sector_size()) & 0xffffff; + + m_register_w[DMA23_16] = m_register_r[DMA23_16] = (dma_address & 0xff0000) >> 16; + m_register_w[DMA15_8] = m_register_r[DMA15_8] = (dma_address & 0x00ff00) >> 8; + m_register_w[DMA7_0] = m_register_r[DMA7_0] = (dma_address & 0x0000ff); + if (TRACE_TRANSFER) logerror("%s: New DMA address = %06x\n", tag(), dma_address); + } + + // Decrement the count + m_register_w[SECTOR_COUNT] = (m_register_w[SECTOR_COUNT]-1) & 0xff; + if (m_register_w[SECTOR_COUNT] != 0 && !m_stop_after_index) + { + if (m_logical) m_register_w[DESIRED_SECTOR] = (desired_sector() + 1) & 0xff; + m_substate = VERIFY2; + cont = NEXT; + m_live_state.bit_count_total = 0; + } + else + cont = SUCCESS; + + break; + + default: + logerror("%s: BUG: Unknown substate %02x in data_transfer, aborting command\n", tag(), m_substate); + cont = ERROR; + } + } + + if (cont==SUCCESS) set_command_done(TC_SUCCESS); + + // When an error occurs, the COMMAND_TERMINATION bits are set to 11 + if (cont==ERROR) + { + live_abort(); + set_command_done(TC_DATAERR); + } +} + +// =========================================================================== +// Commands +// =========================================================================== + +/* + RESET + Reset the controller. This has the same effect as asserting the RST* input line. + + Command word + + 7 6 5 4 3 2 1 0 + +-----+-----+-----+-----+-----+-----+-----+-----+ + | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | + +-----+-----+-----+-----+-----+-----+-----+-----+ + +*/ +void hdc92x4_device::reset_controller() +{ + logerror("%s: RESET command\n", tag()); + device_reset(); +} + +/* + DESELECT DRIVE + Deselect all drives. + + Command word + + 7 6 5 4 3 2 1 0 + +-----+-----+-----+-----+-----+-----+-----+-----+ + | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | + +-----+-----+-----+-----+-----+-----+-----+-----+ +*/ +void hdc92x4_device::drive_deselect() +{ + if (TRACE_SELECT) logerror("%s: DESELECT command\n", tag()); + m_selected_drive_number = NODRIVE; + m_output1 = 0x00; + set_command_done(TC_SUCCESS); +} + +/* + RESTORE DRIVE + Moves the heads to cylinder 0. If skcom is set, the command terminates + after the SEEK COMPLETE line is set. + + Command word + + 7 6 5 4 3 2 1 0 + +-----+-----+-----+-----+-----+-----+-----+-----+ + | 0 | 0 | 0 | 0 | 0 | 0 | 1 |skcom| + +-----+-----+-----+-----+-----+-----+-----+-----+ +*/ +void hdc92x4_device::restore_drive() +{ + int cont = CONTINUE; + bool buffered_step = current_command() & 1; + + // The substate is set to UNDEF when the command is started; + // when we reenter the command processing after a pause, the substate is set to some other value + // In wd_fdc this is solved using two methods _start and _continue + + if (m_substate == UNDEF) + { + if (TRACE_RESTORE) logerror("%s: RESTORE command %02x\n", tag(), current_command()); + m_seek_count = 0; + m_substate = RESTORE_CHECK; + } + + while (cont==CONTINUE) + { + switch (m_substate) + { + case RESTORE_CHECK: + // Track 0 has not been reached yet + if (!drive_ready()) + { + if (TRACE_RESTORE) logerror("%s: restore command: Drive not ready\n", tag()); + // Does not look like a success, but this takes into account + // that if a drive is not connected we do not want an error message + cont = SUCCESS; + break; + } + + // Are we done? + if (m_seek_count>=4096 || on_track00()) + { + if (buffered_step) + { + // When we have buffered steps, the seek limit will be reached + // before TRK00 is asserted. In that case we have to wait for + // SEEK_COMPLETE. We also wait as soon as TRK00 is asserted. + if (TRACE_RESTORE) logerror("%s: restore using buffered steps\n", tag()); + wait_line(SEEKCOMP_LINE, ASSERT_LINE, SEEK_COMPLETE, false); + cont = WAIT; + } + else + { + // No buffered seek. If the seek limit has been reached + // and TRK00 is not true, we failed. This will be decided below. + m_substate = SEEK_COMPLETE; + } + } + else m_substate = STEP_ON; + break; + + case STEP_ON: + if (TRACE_RESTORE && TRACE_SUBSTATES) logerror("%s: [%s] substate STEP_ON\n", tag(), ttsn().c_str()); + + // Increase step count + m_seek_count++; + + // STEPDIR = 0 -> towards TRK00 + set_bits(m_output2, OUT2_STEPDIR, false); + + // Raising edge (note that all signals must be inverted before leading them to the drive) + set_bits(m_output2, OUT2_STEPPULSE, true); + wait_time(m_timer, pulse_width(), STEP_OFF); + cont = WAIT; + break; + + case STEP_OFF: + if (TRACE_RESTORE && TRACE_SUBSTATES) logerror("%s: [%s] substate STEP_OFF\n", tag(), ttsn().c_str()); + set_bits(m_output2, OUT2_STEPPULSE, false); + wait_time(m_timer, step_time(), RESTORE_CHECK); + cont = WAIT; + break; + + case SEEK_COMPLETE: + // If TRK00 is not set, the drive failed to reach it. + if (!on_track00()) + { + if (TRACE_FAIL) logerror("%s: restore command: failed to reach track 00\n", tag()); + set_command_done(TC_VRFYERR); + cont = ERROR; + } + else + cont = SUCCESS; + break; + } + } + if (cont==SUCCESS) set_command_done(TC_SUCCESS); +} + +/* + STEP IN / OUT 1 CYLINDER + Move the heads 1 step towards the center (in) or towards the outermost + track (out). + + Command word + + 7 6 5 4 3 2 1 0 + +-----+-----+-----+-----+-----+-----+-----+-----+ + | 0 | 0 | 0 | 0 | 0 | 1 | out |skcom| + +-----+-----+-----+-----+-----+-----+-----+-----+ + +*/ +void hdc92x4_device::step_drive() +{ + int cont = CONTINUE; + + if (m_substate == UNDEF) + { + if (TRACE_STEP) logerror("%s: STEP IN/OUT command %02x\n", tag(), current_command()); + m_substate = STEP_ON; + } + + while (cont==CONTINUE) + { + switch (m_substate) + { + case STEP_ON: + if (TRACE_STEP && TRACE_SUBSTATES) logerror("%s: substate STEP_ON\n", tag()); + + // STEPDIR = 0 -> towards TRK00 + set_bits(m_output2, OUT2_STEPDIR, (current_command() & 0x02)==0); + + // Raising edge (note that all signals must be inverted before leading them to the drive) + set_bits(m_output2, OUT2_STEPPULSE, true); + wait_time(m_timer, pulse_width(), STEP_OFF); + cont = WAIT; + break; + + case STEP_OFF: + if (TRACE_STEP && TRACE_SUBSTATES) logerror("%s: substate STEP_OFF\n", tag()); + set_bits(m_output2, OUT2_STEPPULSE, false); + wait_time(m_timer, step_time(), ((current_command() & 0x01)!=0)? WAIT_SEEK_COMPLETE : DONE); + cont = WAIT; + break; + + case WAIT_SEEK_COMPLETE: + wait_line(SEEKCOMP_LINE, ASSERT_LINE, DONE, false); + cont = WAIT; + break; + + case DONE: + cont = SUCCESS; + break; + } + } + if (cont==SUCCESS) set_command_done(TC_SUCCESS); +} + +/* + TAPE BACKUP + Not implemented +*/ +void hdc92x4_device::tape_backup() +{ + logerror("%s: TAPE BACKUP command %02x not implemented\n", tag(), current_command()); + set_command_done(TC_SUCCESS); +} + +/* + POLL DRIVES + Repeat + - i = i+1 % 4 + - select drive if its bit is set in the command word + until seek_complete is true. + + Command word + + 7 6 5 4 3 2 1 0 + +-----+-----+-----+-----+-----+-----+-----+-----+ + | 0 | 0 | 0 | 1 | Drv3| Drv2| Drv1| Drv0| + +-----+-----+-----+-----+-----+-----+-----+-----+ + + This command only sets the select lines but does not process parameters + like head load times or drive types. +*/ +void hdc92x4_device::poll_drives() +{ + UINT8 drivebit = 0; + if (m_substate == UNDEF) + { + logerror("%s: POLL DRIVES command %02x\n", tag(), current_command()); + m_substate = POLL1; + m_selected_drive_number = 0; + // If there is no selection, do not enter the loop + if ((current_command() & 0x0f)==0) m_substate = DONE; + } + + int cont = CONTINUE; + + while (cont==CONTINUE) + { + switch (m_substate) + { + case POLL1: + drivebit = (1 << m_selected_drive_number) & 0x0f; + + if ((current_command() & drivebit) != 0) + { + // Test this drive + m_register_r[CHIP_STATUS] = (m_register_r[CHIP_STATUS] & 0xfc) | m_selected_drive_number; + + m_output1 = (drivebit << 4) | (m_register_w[RETRY_COUNT]&0x0f); + if (TRACE_AUXBUS) logerror("%s: Setting OUTPUT1 to %02x\n", tag(), m_output1); + wait_time(m_timer, 1, POLL2); // Wait for 1 usec + cont = WAIT; + } + else + m_substate = POLL3; + + break; + + case POLL2: + if (seek_complete()) + { + // Seek complete has been set + m_substate = DONE; + // Selected drive is still found in the chip status register + } + else m_substate = POLL3; + break; + + case POLL3: + m_selected_drive_number = (m_selected_drive_number + 1) & 0x03; + m_substate = POLL1; + break; + + case DONE: + cont = SUCCESS; + break; + } + } + + if (cont==SUCCESS) set_command_done(TC_SUCCESS); +} + +/* + DRIVE SELECT + Selects a drive. With this command, parameters for the drive are also + defined, like the type of drive (Floppy 8" or 5", AT Hard disk, or generic + Hard disk), the drive number, and the head load delay. + + On the next OUTPUT1 time, the number of the drive (one of four lines) + is set on the higher four bits of the auxiliary bus. Also, the lower + 4 bits of the RETRY COUNT register are put on the lower 4 bits of the bus + (user-programmable output, [1] p. 5). + + The HFDC controller board uses the user-programmable output to + select one of four floppy disk drives with Drive set to 00. + Drive codes 01, 10, and 11 remain for three hard disk drives. + + Command word + + 7 6 5 4 3 2 1 0 + +-----+-----+-----+-----+-----+-----+-----+-----+ + | 0 | 0 | 1 |Delay| Type | Drive | + +-----+-----+-----+-----+-----+-----+-----+-----+ +*/ + +void hdc92x4_device::drive_select() +{ + int cont = CONTINUE; + int head_load_delay = 0; + + if (m_substate == UNDEF) + { + int driveparm = current_command() & 0x1f; + bool head_load_delay_enable = (driveparm & 0x10)!=0; + + // The drive type is used to configure DMA burst mode ([1], p.12) + // and to select the timing parameters + m_selected_drive_type = (driveparm>>2) & 0x03; + m_selected_drive_number = driveparm & 0x03; + + // Calculate the head load delays + head_load_delay = head_load_delay_enable? m_register_w[DATA] * head_load_timer_increment[m_selected_drive_type] : 0; + if (fm_mode()) head_load_delay <<= 1; + + if (TRACE_SELECT) logerror("%s: DRIVE SELECT command (%02x): head load delay=%d, type=%d, drive=%d, pout=%02x, step_rate=%d\n", tag(), current_command(), head_load_delay, m_selected_drive_type, driveparm&3, m_register_w[RETRY_COUNT]&0x0f, pulse_width() + step_time()); + + // Copy the DMA registers to registers CURRENT_HEAD, CURRENT_CYLINDER, + // and CURRENT_IDENT. This is required during formatting ([1], p. 14) + // as the format command reuses the registers for formatting parameters. + m_register_r[CURRENT_HEAD] = m_register_r[DMA7_0]; + m_register_r[CURRENT_CYLINDER] = m_register_r[DMA15_8]; + m_register_r[CURRENT_IDENT] = m_register_r[DMA23_16]; + + // Copy the selected drive number to the chip status register + m_register_r[CHIP_STATUS] = (m_register_r[CHIP_STATUS] & 0xfc) | m_selected_drive_number; + + m_output1 = (m_selected_drive_number != NODRIVE)? (0x10 << m_selected_drive_number) : 0; + m_output1 |= (m_register_w[RETRY_COUNT]&0x0f); + if (TRACE_AUXBUS) logerror("%s: Setting OUTPUT1 to %02x\n", tag(), m_output1); + m_substate = (head_load_delay>0)? HEAD_DELAY : DONE; + } + + // As for the head delay, the specs are not clear when it is applied. + // There is no input line indicating whether the head is already loaded + // (see WD17xx: HLT). Let's assume for now that the head is loaded with + // this drive select operation, and that we have the delay here. + switch (m_substate) + { + case HEAD_DELAY: + wait_time(m_timer, head_load_delay, DONE); + cont = WAIT; + break; + case DONE: + cont = SUCCESS; + break; + } + + if (cont==SUCCESS) set_command_done(TC_SUCCESS); +} + +/* + SET REGISTER POINTER + + Sets the pointer to the read and write registers. On read or write accesses, + the pointer is increased until it reaches the DATA register. +*/ +void hdc92x4_device::set_register_pointer() +{ + m_register_pointer = current_command() & 0xf; + if (TRACE_SETPTR) logerror("%s: SET REGISTER POINTER command; start reg=%d\n", tag(), m_register_pointer); + // The specification does not say anything about the effect of setting an + // invalid value (only "care should be taken") + if (m_register_pointer > 10) + { + logerror("%s: set register pointer: Invalid register number: %d. Setting to 10.\n", tag(), m_register_pointer); + m_register_pointer = 10; + } + set_command_done(TC_SUCCESS); +} + +/* + SEEK / READ ID + This command is used to move the head to the desired cylinder. + Depending on the Verify setting, the target sector is sought on the + track, else the command terminates after the step pulses have been issued. + + Command word + + 7 6 5 4 3 2 1 0 + +-----+-----+-----+-----+-----+-----+-----+-----+ + | 0 | 1 | 0 | 1 | 0 | Step| Seek| Verf| + +-----+-----+-----+-----+-----+-----+-----+-----+ + + All combinations of flags are legal ([1], p.12). +*/ +void hdc92x4_device::seek_read_id() +{ + if (m_substate == UNDEF) + { + // Command init + if (TRACE_READ) logerror("%s: SEEK / READ ID command %02x, CHS=(%d,%d,%d)\n", tag(), current_command(), desired_cylinder(), desired_head(), desired_sector()); + m_substate = READ_ID; + } + + int cont = NEXT; + bool step_enable = (current_command() & 0x04)==1; + bool wait_seek_comp = (current_command() & 0x02)==1; + bool do_verify = (current_command() & 0x01)==1; + m_logical = true; + + while (cont == NEXT) + { + switch (m_substate & 0xf0) + { + case READ_ID: + read_id(cont, step_enable, wait_seek_comp); + break; + case VERIFY: + if (!do_verify) + cont = SUCCESS; + else + verify(cont); + break; + case DATA_TRANSFER: + // No data transfer here. Just exit. + cont = SUCCESS; + break; + default: + logerror("%s: BUG: Unknown substate %02x in seek_read_id, aborting command\n", tag(), m_substate); + set_command_done(TC_DATAERR); + cont = ERROR; + } + } + + if (cont==SUCCESS) set_command_done(TC_SUCCESS); +} + +/* + READ SECTORS PHYSICAL / LOGICAL + Read the desired sectors, maximum count being specified in SECTOR_COUNT + + Physical: + For multiple sectors, read the sectors in the order as they appear on the track. + The command terminates with the next index pulse or when all sectors have been read before. + Implied seek (locate the correct track) is always true (opcodes 5a and 5b + are used for READ TRACK). + + Logical: + For multiple sectors, read the sectors in ascending order of their sector field (sector n, n+1, n+2 ...). + + Command word + + 7 6 5 4 3 2 1 0 + +-----+-----+-----+-----+-----+--------+------+------+ + | 0 | 1 | 0 | 1 | 1 | Logical|NoSeek| Trans| + +-----+-----+-----+-----+-----+--------+------+------+ + +*/ +void hdc92x4_device::read_sectors() +{ + m_logical = (current_command() & 0x04)!=0; + + if (m_substate == UNDEF) + { + // Command init + if (TRACE_READ) logerror("%s: READ SECTORS %s command %02x, CHS=(%d,%d,%d)\n", tag(), m_logical? "LOGICAL": "PHYSICAL", current_command(), desired_cylinder(), desired_head(), desired_sector()); + m_retry_save = m_register_w[RETRY_COUNT]; + m_multi_sector = (m_register_w[SECTOR_COUNT] != 1); + m_write = false; + m_substate = READ_ID; + m_first_sector_found = false; + } + + int cont = NEXT; + bool implied_seek = (current_command() & 0x02)==0; + m_transfer_enabled = (current_command() & 0x01)!=0; + + while (cont == NEXT) + { + switch (m_substate & 0xf0) + { + case READ_ID: + read_id(cont, implied_seek, true); // Always check SEEK COMPLETE + break; + case VERIFY: + verify(cont); // for physical, only verify the first sector + break; + case DATA_TRANSFER: + data_transfer(cont); + break; + default: + logerror("%s: BUG: Unknown substate %02x in read_sectors, aborting command\n", tag(), m_substate); + set_command_done(TC_DATAERR); + cont = ERROR; + } + } +} + +/* + READ TRACK + Read all ID and data fields as they appear on the track. Command 5A only + transmits the ID fields via DMA, which 5B transmits all ID and data fields. + Note that the specifications do not mention any gaps to be transmitted as + well. + + Command word + + 7 6 5 4 3 2 1 0 + +-----+-----+-----+-----+-----+-----+-----+------+ + | 0 | 1 | 0 | 1 | 1 | 0 | 1 | All | + +-----+-----+-----+-----+-----+-----+-----+------+ + +*/ +void hdc92x4_device::read_track() +{ + if (m_substate == UNDEF) + { + if (TRACE_READTRACK) logerror("%s: READ TRACK command %02x, head = %d\n", tag(), current_command(), desired_head()); + dma_address_out(m_register_w[DMA23_16], m_register_w[DMA15_8], m_register_w[DMA7_0]); + m_transfer_enabled = (current_command() & 1)!=0; + } + + int cont = NEXT; + while (cont == NEXT) + { + switch (m_substate) + { + case WAITINDEX0: + if (TRACE_READTRACK && TRACE_DETAIL) logerror("%s: Read track - waiting for index hole\n", tag()); + if (!index_hole()) + { + m_substate = WAITINDEX1; + cont = NEXT; + } + else + { + // We're above the index hole; wait for the index line going down + if (TRACE_READTRACK && TRACE_DETAIL) logerror("%s: Index hole just passing by ... waiting for next\n", tag()); + wait_line(INDEX_LINE, ASSERT_LINE, WAITINDEX1, false); + cont = WAIT; + } + break; + case WAITINDEX1: + // Waiting for the next rising edge + wait_line(INDEX_LINE, ASSERT_LINE, TRACKSTART, false); + cont = WAIT; + break; + case TRACKSTART: + if (TRACE_READTRACK && TRACE_DETAIL) logerror("%s: Read track - index hole arrived\n", tag()); + live_start(READ_TRACK); + cont = WAIT; + break; + case TRACKDONE: + if (TRACE_READTRACK && TRACE_SUBSTATES) logerror("%s: Track reading done\n", tag()); + cont = SUCCESS; + m_out_dmarq(CLEAR_LINE); + m_out_dip(CLEAR_LINE); + break; + } + } + + if (cont==SUCCESS) set_command_done(TC_SUCCESS); +} + +/* + FORMAT TRACK + Writes a track on the selected drive at the current cylinder. The write + process starts with the falling edge of the index hole and stops with + the rising edge of the next index hole. + + The formatting is done exclusively by the controller; user programs may + set parameters for gaps and interleaving. + + 1. Before starting the command, the user program must have set up a + sector sequence table in the controller RAM (located on the PCB): + (ident, cylinder, head, sector1, size) (5 bytes) + (ident, cylinder, head, sector2, size) + (ident, cylinder, head, sector3, size) + ... + ident is not required for floppy FM operation. size is not required + for IBM AT-compatible hard disks. + + 2. The DMA registers must point to the beginning of the table + + 3. DRIVE_SELECT must be executed (which moves DMA regs to CUR_HEAD ...) + + 4. DESIRED_HEAD register must be loaded + + 5. The following setup must be done: + + GAP 0 size DMA7_0 (2s comp) + GAP 1 size DMA15_8 (2s comp) + GAP 2 size DMA23_16 (2s comp) + GAP 3 size DESIRED_SECTOR (2s comp) + Sync size DESIRED_CYLINDER (1s comp) + Sector count SECTOR_COUNT (1s comp) + Sector size multiple RETRY_COUNT (1s comp) + + GAP4 is variable and fills the rest of the track until the next + index hole. + + 6. The step rate and density must be loaded into the MODE register + + 7. The drive must be stepped to the desired track. + + 8. Now this command may be started. + + All data bytes of a sector are filled with 0xe5. The gaps will be filled + with 0x4e (MFM) or 0xff (FM). + + To format another track, the sector id table must be updated, and steps + 7 and 8 must be repeated. If the DESIRED_HEAD register must be updated, + the complete setup process must be done. + + Command word + + 7 6 5 4 3 2 1 0 + +-----+-----+-----+------+-----+-----+-----+------+ + | 0 | 1 | 1 |DelMrk|RedWC| Precompensation | + +-----+-----+-----+------+-----+-----+-----+------+ +*/ +void hdc92x4_device::format_track() +{ + if (m_substate == UNDEF) + { + if (TRACE_FORMAT) logerror("%s: FORMAT TRACK command %02x, head = %d\n", tag(), current_command(), desired_head()); + m_substate = WAITINDEX0; + m_deleted = (current_command() & 0x10)!=0; + m_reduced_write_current = (current_command() & 0x08)!=0; + m_precompensation = (current_command() & 0x07); + m_write = true; + + m_gap0_size = -m_register_w[DMA7_0] & 0xff; + m_gap1_size = -m_register_w[DMA15_8] & 0xff; + m_gap2_size = -m_register_w[DMA23_16] & 0xff; + m_gap3_size = -m_register_w[DESIRED_SECTOR] & 0xff; + m_sync_size = ~m_register_w[DESIRED_CYLINDER] & 0xff; + m_sector_count = ~m_register_w[SECTOR_COUNT] & 0xff; + m_sector_size = (~m_register_w[RETRY_COUNT] & 0xff) * 128; + + if (TRACE_FORMAT && TRACE_DETAIL) + { + logerror("%s: GAP0 length = %d\n", tag(), m_gap0_size); + logerror("%s: GAP1 length = %d\n", tag(), m_gap1_size); + logerror("%s: GAP2 length = %d\n", tag(), m_gap2_size); + logerror("%s: GAP3 length = %d\n", tag(), m_gap3_size); + logerror("%s: Sync size = %d\n", tag(), m_sync_size); + logerror("%s: Sector count = %d\n", tag(), m_sector_count); + logerror("%s: Sector size = %d\n", tag(), m_sector_size); + } + + dma_address_out(m_register_r[CURRENT_IDENT], m_register_r[CURRENT_CYLINDER], m_register_r[CURRENT_HEAD]); + } + + int cont = NEXT; + while (cont == NEXT) + { + switch (m_substate) + { + case WAITINDEX0: + if (TRACE_FORMAT && TRACE_DETAIL) logerror("%s: Format track; looking for track start\n", tag()); + if (!index_hole()) + { + m_substate = WAITINDEX1; + cont = NEXT; + } + else + { + // We're above the index hole right now, so wait for the line going down + if (TRACE_FORMAT && TRACE_DETAIL) logerror("%s: Index hole just passing by ... \n", tag()); + wait_line(INDEX_LINE, CLEAR_LINE, WAITINDEX1, false); + cont = WAIT; + } + break; + case WAITINDEX1: + // Waiting for the next rising edge + if (TRACE_FORMAT && TRACE_DETAIL) logerror("%s: Waiting for next index hole\n", tag()); + wait_line(INDEX_LINE, ASSERT_LINE, TRACKSTART, false); + cont = WAIT; + break; + case TRACKSTART: + if (TRACE_FORMAT && TRACE_DETAIL) logerror("%s: Format track - index hole arrived\n", tag()); + live_start(FORMAT_TRACK); + cont = WAIT; + break; + case TRACKDONE: + if (FORMAT_TRACK && TRACE_SUBSTATES) logerror("%s: Track writing done\n", tag()); + cont = SUCCESS; + break; + } + } + + if (cont==SUCCESS) set_command_done(TC_SUCCESS); +} + +/* + WRITE SECTORS PHYSICAL / LOGICAL + + Write the desired sectors, maximum count being specified in SECTOR_COUNT + + Physical: + For multiple sectors, write sector contents into the data fields of + the sectors as they are arranged on the track. + The command terminates with the next index pulse or when all sectors have been written before. + + Logical: + For multiple sectors, write the sectors in ascending order of their + sector field (sector n, n+1, n+2 ...). + + Command word + + 7 6 5 4 3 2 1 0 + +-----+------+-------+------+-----+-----+-----+------+ + | 1 |NoSeek|Logical|DelMrk|RedWC| Precompensation | + +-----+------+-------+------+-----+-----+-----+------+ +*/ +void hdc92x4_device::write_sectors() +{ + m_logical = (current_command() & 0x20)!=0; + + if (m_substate == UNDEF) + { + if (TRACE_WRITE) logerror("%s: WRITE SECTORS %s command %02x, CHS=(%d,%d,%d)\n", tag(), m_logical? "LOGICAL" : "PHYSICAL", current_command(), desired_cylinder(), desired_head(), desired_sector()); + m_multi_sector = (m_register_w[SECTOR_COUNT] != 1); + m_substate = READ_ID; + + m_deleted = (current_command() & 0x10)!=0; + m_reduced_write_current = (current_command() & 0x08)!=0; + m_precompensation = (current_command() & 0x07); + // Important for DATA TRANSFER + m_transfer_enabled = true; + + // Something interesting here: + // + // The values for sync and gap2 are passed to the formatting routing + // but how do we know their values right now, when we are writing sectors? + // Since this is not clearly stated in the specification, we have to + // use the default values here + // Actually, why can we choose that value for formatting in the first place? + + if (using_floppy()) + { + m_sync_size = fm_mode()? 6 : 12; + m_gap2_size = fm_mode()? 11 : 22; + } + else + { + // Values for HD + m_sync_size = 13; + m_gap2_size = 3; + } + m_write = false; // until we're writing + m_first_sector_found = false; + } + + int cont = NEXT; + bool implied_seek = (current_command() & 0x40)==0; + + while (cont == NEXT) + { + // We're dispatching by substate value range + switch (m_substate & 0xf0) + { + case READ_ID: + read_id(cont, implied_seek, true); // Always check SEEK COMPLETE + break; + case VERIFY: + verify(cont); + break; + case DATA_TRANSFER: + m_write = true; + data_transfer(cont); + break; + default: + logerror("%s: BUG: Unknown substate %02x in write_sectors, aborting command\n", tag(), m_substate); + set_command_done(TC_DATAERR); + cont = ERROR; + } + } +} + +/* +=========================================================================== + + Live state machine + + We follow a very similar approach to track access like in wd_fdc. The live + state machine attempts to find marks on the track, starting from the current + position. When found, it waits for the machine to catch up. When an event + happens in the meantime, the state machine is rolled back, and the actions + are replayed until the position where the event occurred. + + Lots of code is taken from wd_fdc, with some minor restructuring and renaming. + Same ideas, though. More comments. + +=========================================================================== +*/ + +std::string hdc92x4_device::tts(const attotime &t) +{ + char buf[256]; + int nsec = t.attoseconds() / ATTOSECONDS_PER_NANOSECOND; + sprintf(buf, "%4d.%03d,%03d,%03d", int(t.seconds()), nsec/1000000, (nsec/1000)%1000, nsec % 1000); + return buf; +} + +std::string hdc92x4_device::ttsn() +{ + return tts(machine().time()); +} + +bool hdc92x4_device::found_mark(int state) +{ + bool ismark = false; + if (using_floppy()) + { + if (state==SEARCH_IDAM) ismark = (m_live_state.shift_reg == fm_mode()? 0xf57e : 0x4489); + else + { + // f56a 1x1x + ismark = fm_mode()? ((m_live_state.shift_reg & 0xfffa) == 0xf56a) : (m_live_state.shift_reg == 0x4489); + } + } + else + { + switch (m_hd_encoding) + { + case MFM_BITS: + case MFM_BYTE: + ismark = (m_live_state.shift_reg == 0x4489); + break; + case SEPARATED: + // 0 0 0 0 1 0 1 0 + // 1 0 1 0 0 0 0 1 + ismark = (m_live_state.data_reg == 0xa1 && m_live_state.clock_reg == 0x0a); + break; + case SEPARATED_SIMPLE: + ismark = (m_live_state.data_reg == 0xa1 && m_live_state.clock_reg == 0xff); + break; + } + } + return ismark; +} + +/* + The controller starts to read bits from the disk. This method takes an + argument for the state machine called at the end. +*/ +void hdc92x4_device::live_start(int state) +{ + if (TRACE_LIVE) logerror("%s: [%s] Live start substate=%02x\n", tag(), ttsn().c_str(), state); + m_live_state.time = machine().time(); + m_live_state.state = state; + m_live_state.next_state = -1; + + m_live_state.shift_reg = 0; + m_live_state.crc = 0xffff; + m_live_state.bit_counter = 0; + m_live_state.byte_counter = 0; + m_live_state.data_separator_phase = false; + m_live_state.data_reg = 0; + m_live_state.last_data_bit = false; + + if (using_floppy()) pll_reset(m_live_state.time, m_write); + m_checkpoint_state = m_live_state; + + // Save checkpoint + m_checkpoint_pll = m_pll; + + live_run(); + m_last_live_state = UNDEF; + if (TRACE_LIVE) logerror("%s: [%s] Live start end\n", tag(), ttsn().c_str()); // delete +} + +void hdc92x4_device::live_run() +{ + if (using_floppy()) live_run_until(attotime::never); + else live_run_hd_until(attotime::never); +} + +/* + The main method of the live state machine. We stay in this method until + the requested data are read. + limit: if unlimited (attotime::never), run up to the end of the track and wait there + otherwise, used to replay the read/write operation up to the point where the event happened + + THIS IS THE FLOPPY-ONLY LIVE_RUN +*/ +void hdc92x4_device::live_run_until(attotime limit) +{ + int slot = 0; + + if (m_live_state.state == IDLE || m_live_state.next_state != -1) + return; + + if (TRACE_LIVE) + { + if (limit == attotime::never) + logerror("%s: [%s live] live_run, live_state=%02x, mode=%s\n", tag(), tts(m_live_state.time).c_str(), m_live_state.state, fm_mode()? "FM":"MFM"); + else + logerror("%s: [%s live] live_run until %s, live_state=%02x, mode=%s\n", tag(), tts(m_live_state.time).c_str(), tts(limit).c_str(), m_live_state.state, fm_mode()? "FM":"MFM"); + } + + if (limit == attotime::never) + { + // We did not specify an upper time bound, so we take the next index pulse + if (m_floppy != NULL) limit = m_floppy->time_next_index(); + + if (limit == attotime::never) + { + // We don't have an index pulse? (no disk?) + // See wd_fdc: Force a sync from time to time in that case + // so that the main cpu timeout isn't too painful. Avoids + // looping into infinity looking for data too. + limit = machine().time() + attotime::from_msec(1); + m_timer->adjust(attotime::from_msec(1)); + } + } + + while (true) + { + switch (m_live_state.state) + { + case SEARCH_IDAM: + + // We're doing this complicated logerror check to avoid + // repeated logging in the same state. This can be found for the + // other live states as well. m_last_live_state is only used to + // control this logging. + + if (TRACE_LIVE && m_last_live_state != SEARCH_IDAM) + { + logerror("%s: [%s live] SEARCH_IDAM [limit %s]\n", tag(),tts(m_live_state.time).c_str(), tts(limit).c_str()); + m_last_live_state = m_live_state.state; + } + + // This bit will be set when the IDAM cannot be found + set_bits(m_register_r[CHIP_STATUS], CS_SYNCERR, false); + + if (read_one_bit(limit)) + { + if (TRACE_LIVE) logerror("%s: [%s live] SEARCH_IDAM limit reached\n", tag(), tts(m_live_state.time).c_str()); + return; + } + // logerror("%s: SEARCH_IDAM\n", tts(m_live_state.time).c_str()); + if (TRACE_SHIFT) logerror("%s: [%s live] shift = %04x data=%02x c=%d\n", tag(), tts(m_live_state.time).c_str(), m_live_state.shift_reg, + get_data_from_encoding(m_live_state.shift_reg), m_live_state.bit_counter); + + // [1] p. 9: The ID field sync mark must be found within 33,792 byte times + if (m_live_state.bit_count_total > 33792*16) + { + // Desired sector not found within time + if (m_substate == VERIFY3) + wait_for_realtime(VERIFY_FAILED); + else + wait_for_realtime(SEARCH_IDAM_FAILED); + return; + } + + if (!fm_mode()) + { + // MFM case + if (m_live_state.shift_reg == 0x4489) + { + if (TRACE_LIVE) logerror("%s: [%s live] Found an A1 mark\n", tag(),tts(m_live_state.time).c_str()); + m_live_state.crc = 0x443b; + m_live_state.data_separator_phase = false; + m_live_state.bit_counter = 0; + // Next task: find the next two A1 marks + m_live_state.state = READ_TWO_MORE_A1_IDAM; + } + } + else + { + // FM case + if (m_live_state.shift_reg == 0xf57e) + { + if (TRACE_LIVE) logerror("%s: SEARCH_IDAM: IDAM found\n", tag()); + m_live_state.crc = 0xef21; + m_live_state.data_separator_phase = false; + m_live_state.bit_counter = 0; + m_live_state.state = READ_ID_FIELDS_INTO_REGS; + } + } + break; + + case SEARCH_IDAM_FAILED: + set_bits(m_register_r[CHIP_STATUS], CS_SYNCERR, true); + m_live_state.state = IDLE; + return; + + case VERIFY_FAILED: + set_bits(m_register_r[CHIP_STATUS], CS_COMPERR, true); + m_live_state.state = IDLE; + return; + + case READ_TWO_MORE_A1_IDAM: // This state only applies for MFM mode. + + if (TRACE_LIVE && m_last_live_state != READ_TWO_MORE_A1_IDAM) + { + logerror("%s: [%s live] READ_TWO_MORE_A1\n", tag(),tts(m_live_state.time).c_str()); + m_last_live_state = m_live_state.state; + } + + // Beyond time limit? + if (read_one_bit(limit)) return; + + if (TRACE_SHIFT) logerror("%s: [%s live] shift = %04x data=%02x c=%d\n", tag(), tts(m_live_state.time).c_str(), m_live_state.shift_reg, + get_data_from_encoding(m_live_state.shift_reg), m_live_state.bit_counter); + + if (m_live_state.bit_count_total > 33792*16) + { + wait_for_realtime(SEARCH_IDAM_FAILED); + return; + } + + // Repeat until we have collected 16 bits + if (m_live_state.bit_counter & 15) break; + + // So we now got 16 bits. Fill this value into the next slot. We expect two more A1 values. + slot = m_live_state.bit_counter >> 4; + if (slot < 3) + { + if (m_live_state.shift_reg != 0x4489) + { + // This ain't A1. Step back into the previous state (look for the next IDAM). + m_live_state.state = SEARCH_IDAM; + } + else + if (TRACE_LIVE) logerror("%s: [%s live] Found an A1 mark\n", tag(),tts(m_live_state.time).c_str()); + // Continue + break; + } + + if (TRACE_LIVE) logerror("%s: [%s live] Found data value %02X\n", tag(),tts(m_live_state.time).c_str(), m_live_state.data_reg); + + // Check for ident field (fe, ff, fd, fc) + if ((m_live_state.data_reg & 0xfc) != 0xfc) + { + // This may happen when we accidentally locked onto the DAM. Look for the next IDAM. + if (TRACE_LIVE) + { + if (m_live_state.data_reg == 0xf8 || m_live_state.data_reg == 0xfb) + logerror("%s: [%s live] Looks like a DAM; continue to next mark\n", tag(), tts(m_live_state.time).c_str()); + else + logerror("%s: [%s live] Missing ident data after A1A1A1, and it was not DAM; format corrupt?\n", tag(), tts(m_live_state.time).c_str()); + } + m_live_state.state = SEARCH_IDAM; + break; + } + + m_register_r[CURRENT_IDENT] = m_live_state.data_reg; + + // We're here after we got the three A1 and FE + m_live_state.bit_counter = 0; + m_live_state.state = READ_ID_FIELDS_INTO_REGS; + break; + + case READ_ID_FIELDS_INTO_REGS: + if (TRACE_LIVE && m_last_live_state != READ_ID_FIELDS_INTO_REGS) + { + logerror("%s: [%s live] READ_ID_FIELDS_INTO_REGS\n", tag(),tts(m_live_state.time).c_str()); + m_last_live_state = m_live_state.state; + } + + if (read_one_bit(limit)) + { + return; + } + // Already got 16 bits? + if (m_live_state.bit_counter & 15) break; + + slot = (m_live_state.bit_counter >> 4)-1; + + if (TRACE_LIVE) logerror("%s: slot %d = %02x, crc=%04x\n", tag(), slot, m_live_state.data_reg, m_live_state.crc); + + // The id_field is an array of indexes into the chip registers. + // Thus we get the values properly assigned to the registers. + m_register_r[id_field[slot]] = m_live_state.data_reg; + + if(slot > 4) + { + // We successfully read the ID fields; let's wait for the machine time to catch up. + if (reading_track()) + // Continue if we're reading a complete track + wait_for_realtime(READ_TRACK_ID_DONE); + else + // Live run is done here; it is the main state machine's turn again. + wait_for_realtime(IDLE); + return; + } + break; + + // ================================================== + // Live states for sector read operations + // ================================================== + + case SEARCH_DAM: + if (TRACE_LIVE && m_last_live_state != SEARCH_DAM) + { + logerror("%s: [%s live] SEARCH_DAM\n", tag(),tts(m_live_state.time).c_str()); + m_last_live_state = m_live_state.state; + } + + set_bits(m_register_r[CHIP_STATUS], CS_DELDATA, false); + + if(read_one_bit(limit)) + return; + + if (TRACE_SHIFT) logerror("%s: [%s live] shift = %04x data=%02x c=%d\n", tag(), tts(m_live_state.time).c_str(), m_live_state.shift_reg, + get_data_from_encoding(m_live_state.shift_reg), m_live_state.bit_counter); + + if (!fm_mode()) + { // MFM + if(m_live_state.bit_counter > 43*16) + { + if (TRACE_FAIL) logerror("%s: SEARCH_DAM failed\n", tag()); + wait_for_realtime(SEARCH_DAM_FAILED); + return; + } + + if (m_live_state.bit_counter >= 28*16 && m_live_state.shift_reg == 0x4489) + { + if (TRACE_LIVE) logerror("%s: [%s live] Found an A1 mark\n", tag(),tts(m_live_state.time).c_str()); + m_live_state.crc = 0x443b; + m_live_state.data_separator_phase = false; + m_live_state.bit_counter = 0; + m_live_state.state = READ_TWO_MORE_A1_DAM; + } + } + else + { // FM + if (m_live_state.bit_counter > 23*16) + { + if (TRACE_FAIL) logerror("%s: SEARCH_DAM failed\n", tag()); + wait_for_realtime(SEARCH_DAM_FAILED); + return; + } + + if (m_live_state.bit_counter >= 11*16 && (m_live_state.shift_reg == 0xf56a || m_live_state.shift_reg == 0xf56b || + m_live_state.shift_reg == 0xf56e || m_live_state.shift_reg == 0xf56f)) { + if (TRACE_LIVE) logerror("%s: SEARCH_DAM: found DAM = %04x\n", tag(), m_live_state.shift_reg); + m_live_state.crc = + m_live_state.shift_reg == 0xf56a ? 0x8fe7 : + m_live_state.shift_reg == 0xf56b ? 0x9fc6 : + m_live_state.shift_reg == 0xf56e ? 0xafa5 : + 0xbf84; + m_live_state.data_separator_phase = false; + m_live_state.bit_counter = 0; + m_live_state.state = READ_SECTOR_DATA; + } + } + break; + + case READ_TWO_MORE_A1_DAM: { + if (TRACE_LIVE && m_last_live_state != READ_TWO_MORE_A1_DAM) + { + logerror("%s: [%s live] READ_TWO_MORE_A1_DAM\n", tag(),tts(m_live_state.time).c_str()); + m_last_live_state = m_live_state.state; + } + + if(read_one_bit(limit)) + return; + + if (TRACE_SHIFT) logerror("%s: [%s live] shift = %04x data=%02x c=%d\n", tag(), tts(m_live_state.time).c_str(), m_live_state.shift_reg, + get_data_from_encoding(m_live_state.shift_reg), m_live_state.bit_counter); + + // Repeat until we have collected 16 bits + if (m_live_state.bit_counter & 15) break; + + // Fill this value into the next slot. We expect three A1 values. + int slot = m_live_state.bit_counter >> 4; + + if (slot < 3) + { + if (m_live_state.shift_reg != 0x4489) + { + wait_for_realtime(SEARCH_DAM_FAILED); + return; + } + else + if (TRACE_LIVE) logerror("%s: [%s live] Found an A1 mark\n", tag(),tts(m_live_state.time).c_str()); + // Continue + break; + } + + if (TRACE_LIVE) logerror("%s: [%s live] Found data value %02X\n", tag(),tts(m_live_state.time).c_str(), m_live_state.data_reg); + + if ((m_live_state.data_reg & 0xff) == 0xf8) + { + if (TRACE_LIVE) logerror("%s: Found deleted data mark F8 after DAM sync\n", tag()); + set_bits(m_register_r[CHIP_STATUS], CS_DELDATA, true); + } + else + { + if ((m_live_state.data_reg & 0xff) != 0xfb) + { + if (TRACE_FAIL) logerror("%s: Missing FB/F8 data mark after DAM sync\n", tag()); + wait_for_realtime(SEARCH_DAM_FAILED); + return; + } + } + + m_live_state.bit_counter = 0; + m_live_state.state = READ_SECTOR_DATA; + break; + } + case SEARCH_DAM_FAILED: + if (TRACE_FAIL) logerror("%s: SEARCH_DAM failed\n", tag()); + m_live_state.state = IDLE; + return; + + case READ_SECTOR_DATA: + { + if (TRACE_LIVE && m_last_live_state != READ_SECTOR_DATA) + { + logerror("%s: [%s live] READ_SECTOR_DATA\n", tag(),tts(m_live_state.time).c_str()); + m_last_live_state = m_live_state.state; + } + + if(read_one_bit(limit)) + return; + + // Request bus release at the first bit of each byte (floppy; [1], fig 5 and 6) + if (m_transfer_enabled) + { + if ((m_live_state.bit_counter & 15)== 1) + { + // For floppies, request DMA for each byte. For hard disk, get it + // only for the first byte and then keep the bus until the last byte. + if (using_floppy() || m_live_state.bit_counter < 16) + { + set_bits(m_register_r[INT_STATUS], ST_OVRUN, true); + m_out_dmarq(ASSERT_LINE); + } + } + } + + // Repeat until we have collected 16 bits + if (m_live_state.bit_counter & 15) break; + + if (TRACE_LIVE) logerror("%s: [%s live] Found data value %02X, CRC=%04x\n", tag(),tts(m_live_state.time).c_str(), m_live_state.data_reg, m_live_state.crc); + int slot = (m_live_state.bit_counter >> 4)-1; + + if (slot < calc_sector_size()) + { + // Sector data + wait_for_realtime(READ_SECTOR_DATA_CONT); + return; + } + else if (slot < calc_sector_size()+2) + { + // CRC + if (slot == calc_sector_size()+1) + { + if (reading_track()) + { + // Reading a track? Continue with next ID. + wait_for_realtime(READ_TRACK_ID); + } + else + { + if (TRACE_LIVE) logerror("%s: [%s live] Sector read completed\n", tag(),tts(m_live_state.time).c_str()); + wait_for_realtime(IDLE); + } + return; + } + } + break; + } + + case READ_SECTOR_DATA_CONT: + if (TRACE_LIVE && m_last_live_state != READ_SECTOR_DATA_CONT) + { + logerror("%s: [%s live] READ_SECTOR_DATA_CONT\n", tag(),tts(m_live_state.time).c_str()); + m_last_live_state = m_live_state.state; + } + + // Did the system CPU send the DMA ACK in the meantime? + if ((m_register_r[INT_STATUS] & ST_OVRUN)!=0) + { + if (TRACE_FAIL) logerror("%s: No DMA ACK - buffer overrun\n", tag()); + set_bits(m_register_r[INT_STATUS], TC_DATAERR, true); + m_live_state.state = IDLE; + return; + } + + if (m_transfer_enabled) + { + m_register_r[DATA] = m_register_w[DATA] = m_live_state.data_reg; + // See above: For floppy, do it for each byte; for hard disk, only for the first byte, + if (using_floppy() || m_live_state.bit_counter == 16) + m_out_dip(ASSERT_LINE); + + m_out_dma(0, m_register_r[DATA], 0xff); + + // And again, for floppies, clear line after writing each byte, for hard disk, only after the last byte + if (using_floppy() || (m_live_state.bit_counter >> 4)==calc_sector_size()-1) + { + m_out_dip(CLEAR_LINE); + m_out_dmarq(CLEAR_LINE); + } + } + + m_live_state.state = READ_SECTOR_DATA; + checkpoint(); + break; + + // ================================================== + // Live states for sector write operations + // ================================================== + + case WRITE_DAM_AND_SECTOR: + // 1. Wait for 22*16 cells (MFM) or 11*16 cells (FM) [704 usec, Gap 2] + // 2. Write 12 (MFM) or 6 (FM) zeros + // 3. Write 3*A1 sync plus the ident byte (MFM) or FB (FM) or F8 (deleted) + // 4. Write the sector content and calculate the CRC on the fly + // 5. Write the CRC bytes + + if (TRACE_LIVE) + logerror("%s: [%s live] WRITE_DAM_AND_SECTOR\n", tag(), tts(m_live_state.time).c_str()); + + skip_on_track(m_gap2_size, WRITE_DAM_SYNC); + break; + + case WRITE_DAM_SYNC: + if (TRACE_WRITE && TRACE_DETAIL) logerror("%s: Write sync zeros\n", tag()); + + // Clear the overrun/underrun flag + set_bits(m_register_r[INT_STATUS], ST_OVRUN, false); + write_on_track(encode(0x00), m_sync_size, fm_mode()? WRITE_DATAMARK : WRITE_A1); + break; + + case WRITE_A1: + if (TRACE_WRITE && TRACE_DETAIL) logerror("%s: Write three A1\n", tag()); + write_on_track(0x4489, 3, WRITE_DATAMARK); + break; + + case WRITE_DATAMARK: + if (TRACE_WRITE && TRACE_DETAIL) logerror("%s: Write data mark and sector contents\n", tag()); + if (fm_mode()) + { + // Init the CRC for the DAM and sector + m_live_state.crc = 0xffff; + + // 1111 0101 0110 1010 = F8 deleted + // 1111 0101 0110 1111 = FB normal + write_on_track(m_deleted? 0xf56a : 0xf56f, 1, WRITE_SECDATA); + } + else + { + // Init the CRC for the ident byte and sector + m_live_state.crc = 0xcdb4; // value for 3*A1 + write_on_track(encode(m_deleted? 0xf8 : 0xfb), 1, WRITE_SECDATA); + } + m_live_state.byte_counter = calc_sector_size(); + + // Set the over/underrun flag and hope that it will be cleared before we start writing + // (only for sector writing) + if (m_substate == DATA_TRANSFER_WRITE) + { + set_bits(m_register_r[INT_STATUS], ST_OVRUN, true); + m_out_dmarq(ASSERT_LINE); + } + break; + + case WRITE_SECDATA: + if (m_substate == DATA_TRANSFER_WRITE) + { + // Check whether DMA has been acknowledged + if ((m_register_r[INT_STATUS] & ST_OVRUN)!=0) + { + // No, then stop here + m_live_state.state= NO_DMA_ACK; + } + else + { + // For floppies, set this for each byte; for hard disk, set it only at the beginning + if (using_floppy() || m_live_state.byte_counter == calc_sector_size()) + m_out_dip(ASSERT_LINE); + + m_register_r[DATA] = m_register_w[DATA] = m_in_dma(0, 0xff); + + if (using_floppy() || m_live_state.byte_counter == 0) + { + m_out_dip(CLEAR_LINE); + m_out_dmarq(CLEAR_LINE); + } + + if (m_live_state.byte_counter > 0) + { + m_live_state.byte_counter--; + write_on_track(encode(m_register_r[DATA]), 1, WRITE_SECDATA); + if (using_floppy()) m_out_dmarq(ASSERT_LINE); + } + else + { + m_live_state.state = WRITE_DATA_CRC; + m_live_state.byte_counter = 2; + } + } + } + else + { + // We are here in the context of track formatting. Write a + // blank sector + write_on_track(encode(0xe5), m_sector_size, WRITE_DATA_CRC); + m_live_state.byte_counter = 2; + } + break; + + case WRITE_DATA_CRC: + // N.B.: when we write the first CRC byte, the value of the CRC will + // change to the previous second byte, so we can write the first + // byte in two iterations to get both + if (m_live_state.byte_counter > 0) + { + if (TRACE_WRITE && TRACE_DETAIL) logerror("%s: Write CRC\n", tag()); + m_live_state.byte_counter--; + write_on_track(encode((m_live_state.crc >> 8) & 0xff), 1, WRITE_DATA_CRC); + } + else + // Write a filler byte so that the last CRC bit is saved correctly + // Without, the last bit of the CRC value may be flipped + write_on_track(encode(0xff), 1, WRITE_DONE); + + break; + + case WRITE_DONE: + if (m_substate == DATA_TRANSFER_WRITE) + { + if (TRACE_WRITE && TRACE_DETAIL) logerror("%s: Write sector complete\n", tag()); + m_pll.stop_writing(m_floppy, m_live_state.time); + m_live_state.state = IDLE; + return; + } + else + { + // Continue for track writing: Write GAP3 + m_live_state.state = WRITE_GAP3; + } + break; + +// -------------------------------------------------------- + + // ================================================== + // Live states for track formatting + // Write GAP 0 + // Write Sync+IXAM + // Write GAP 1 + // Per sector + // Write Sync+IDAM + // Write Sector header+CRC + // Write GAP2 + // Write Sync+DAM + // Write Sector data + // Write CRC bytes + // Write GAP3 + // Write GAP4 until the next pulse + // ================================================== + + case FORMAT_TRACK: + if (TRACE_LIVE) logerror("%s: FORMAT_TRACK\n", tag()); + m_live_state.state = WRITE_GAP0; + m_pll.start_writing(m_live_state.time); + break; + + case WRITE_GAP0: + // GAP0 length is in DMA7_0 (negated, 2s comp) + if (TRACE_WRITE && TRACE_DETAIL) logerror("%s: Writing GAP0\n", tag()); + write_on_track(encode(fm_mode()? 0xff : 0x4e), m_gap0_size, WRITE_IXAM_SYNC); + break; + + case WRITE_IXAM_SYNC: + if (TRACE_WRITE && TRACE_DETAIL) logerror("%s: Writing IXAM sync\n", tag()); + write_on_track(encode(0x00), m_sync_size, WRITE_IXAM); + break; + + case WRITE_IXAM: + // FM: FC with clock D7 = 1111 -111 -111 1010 + // MFM: C2 = 11000010 + // 0101 0010 -010 0100 + if (TRACE_WRITE && TRACE_DETAIL) logerror("%s: Writing IXAM\n", tag()); + if (fm_mode()) + write_on_track(0xf77a, 1, WRITE_GAP1); + else + write_on_track(0x5224, 3, WRITE_FC); + + break; + + case WRITE_FC: + // Only for MFM + write_on_track(encode(0xfc), 1, WRITE_GAP1); + break; + + case WRITE_GAP1: + // GAP1 length is in DMA15_8 + if (TRACE_WRITE && TRACE_DETAIL) logerror("%s: Writing GAP1\n", tag()); + write_on_track(encode(fm_mode()? 0xff : 0x4e), m_gap1_size, WRITE_IDAM_SYNC); + break; + + // When does the HDC actually fetch the per-sector data? All data + // at the beginning? Only the bytes for the next sector? + // We assume it reads the bytes and writes them directly on the disk + + case WRITE_IDAM_SYNC: + if (TRACE_WRITE && TRACE_DETAIL) logerror("%s: Writing IDAM sync\n", tag()); + write_on_track(encode(0x00), m_sync_size, WRITE_IDAM); + break; + + case WRITE_IDAM: + // Set the over/underrun flag and hope that it will be cleared before we enter the next state (after writing) + set_bits(m_register_r[INT_STATUS], ST_OVRUN, true); + m_out_dmarq(ASSERT_LINE); + + if (TRACE_WRITE && TRACE_DETAIL) logerror("%s: Writing IDAM and header\n", tag()); + if (fm_mode()) + { + write_on_track(0xf57e, 1, WRITE_HEADER); + m_live_state.byte_counter = 4; + } + else + { + write_on_track(0x4489, 3, WRITE_HEADER); + m_live_state.byte_counter = 5; + } + m_live_state.crc = 0xffff; + break; + + case WRITE_HEADER: + if ((m_register_r[INT_STATUS] & ST_OVRUN)!=0) + // No DMA (we do not get access to the ID table); exit + m_live_state.state= NO_DMA_ACK; + else + { + m_out_dip(ASSERT_LINE); + m_live_state.byte_counter--; + UINT8 headbyte = m_in_dma(0, 0xff); + + write_on_track(encode(headbyte), 1, (m_live_state.byte_counter>0)? WRITE_HEADER : WRITE_HEADER_CRC); + + if (using_floppy() || m_live_state.byte_counter==0) + { + m_out_dip(CLEAR_LINE); + m_out_dmarq(CLEAR_LINE); + } + // Writing will occur after the break; set the DMARQ again + if (m_live_state.byte_counter>0) + m_out_dmarq(ASSERT_LINE); + else + // we will go to WRITE_HEADER_CRC state; set the byte counter for CRC + m_live_state.byte_counter = 2; + } + break; + + case WRITE_HEADER_CRC: + if (m_live_state.byte_counter > 0) + { + UINT8 crct = (m_live_state.crc >> 8) & 0xff; + if (TRACE_WRITE && TRACE_DETAIL) logerror("%s: Write CRC byte %02x\n", tag(), crct); + m_live_state.byte_counter--; + write_on_track(encode(crct), 1, WRITE_HEADER_CRC); + } + else + m_live_state.state = WRITE_GAP2; + + break; + + case WRITE_GAP2: + if (TRACE_WRITE && TRACE_DETAIL) logerror("%s: Writing GAP2\n", tag()); + write_on_track(encode(fm_mode()? 0xff : 0x4e), m_gap2_size, WRITE_DAM_SYNC); + break; + + case WRITE_GAP3: + m_sector_count--; + if (TRACE_WRITE && TRACE_DETAIL) logerror("%s: Writing GAP3\n", tag()); + write_on_track(encode(fm_mode()? 0xff : 0x4e), m_gap3_size, (m_sector_count>0)? WRITE_IDAM_SYNC : WRITE_GAP4); + break; + + case WRITE_GAP4: + // Write bytes up to the end of the track + wait_line(INDEX_LINE, ASSERT_LINE, TRACKDONE, true); + if (TRACE_WRITE && TRACE_DETAIL && m_last_live_state != WRITE_GAP4) + { + logerror("%s: Writing GAP4\n", tag()); + m_last_live_state = WRITE_GAP4; + } + // Write a single byte; when the index hole shows up, the live run will be aborted + write_on_track(encode(fm_mode()? 0xff : 0x4e), 1, WRITE_GAP4); + break; +// -------------------------------------------------------- + + // ================================================== + // Live states for track reading + // ================================================== + + // Quite simple. Read the next ID fields, then the sector contents. + // Continue until the next index hole shows up (live_abort). + case READ_TRACK: + if (TRACE_LIVE) logerror("%s: READ_TRACK\n", tag()); + m_live_state.state = READ_TRACK_ID; + break; + + case READ_TRACK_ID: + m_live_state.state = SEARCH_IDAM; + // Ask for access to bus + set_bits(m_register_r[INT_STATUS], ST_OVRUN, true); + m_out_dmarq(ASSERT_LINE); + break; + + case READ_TRACK_ID_DONE: + if ((m_register_r[INT_STATUS] & ST_OVRUN)!=0) + { + if (TRACE_FAIL) logerror("%s: No DMA ACK - buffer overrun\n", tag()); + set_bits(m_register_r[INT_STATUS], TC_DATAERR, true); + m_live_state.state = IDLE; + return; + } + if (TRACE_LIVE) logerror("%s: READ_TRACK1\n", tag()); + + m_out_dip(ASSERT_LINE); + + // Write the header via DMA + for (int slot = 0; slot < 6; slot++) + m_out_dma(0, m_register_r[id_field[slot]], 0xff); + + m_out_dip(CLEAR_LINE); + m_out_dmarq(CLEAR_LINE); + + // Continue with reading the sector data + m_live_state.state = SEARCH_DAM; + break; + +// ================================================================= + + case READ_TRACK_BYTE: + // The pause is implemented by doing dummy reads on the floppy + if (read_one_bit(limit)) + { + if (TRACE_LIVE) logerror("%s: [%s live] return; limit=%s\n", tag(), tts(m_live_state.time).c_str(), tts(limit).c_str()); + return; + } + + // Repeat until we have collected 16 bits + if ((m_live_state.bit_counter & 15)==0) + { + if (TRACE_READ && TRACE_DETAIL) logerror("%s: [%s live] Read byte %02x, repeat = %d\n", tag(), tts(m_live_state.time).c_str(), m_live_state.data_reg, m_live_state.repeat); + wait_for_realtime(READ_TRACK_NEXT_BYTE); + return; + } + break; + + case READ_TRACK_NEXT_BYTE: + m_live_state.state = READ_TRACK_BYTE; + m_live_state.repeat--; + if (m_live_state.repeat == 0) + { + // All bytes read + m_live_state.state = m_live_state.return_state; + checkpoint(); + } + break; + + case WRITE_TRACK_BYTE: + if (write_one_bit(limit)) + return; + + if (m_live_state.bit_counter == 0) + { + // All bits written; get the next byte into the shift register + wait_for_realtime(WRITE_TRACK_NEXT_BYTE); + return; + } + break; + + case WRITE_TRACK_NEXT_BYTE: + m_live_state.state = WRITE_TRACK_BYTE; + m_live_state.repeat--; + + // Write all bytes + if (m_live_state.repeat == 0) + { + // All bytes written + m_live_state.state = m_live_state.return_state; + checkpoint(); + } + else + encode_again(); + + break; + + case NO_DMA_ACK: + if (TRACE_FAIL) logerror("%s: No DMA ACK - buffer underrun\n", tag()); + set_bits(m_register_r[INT_STATUS], TC_DATAERR, true); + m_pll.stop_writing(m_floppy, m_live_state.time); + m_live_state.state = IDLE; + return; + + default: + logerror("%s: Unknown live state: %02x\n", tag(), m_live_state.state); + m_last_live_state = m_live_state.state; + return; + } + } + m_last_live_state = UNDEF; +} + +/* + The main method of the live state machine. We stay in this method until + the requested data are read. + limit: if unlimited (attotime::never), run up to the end of the track and wait there + otherwise, used to replay the read/write operation up to the point where the event happened + + THIS IS THE HARDDISK-ONLY LIVE_RUN + + NB: Although unlikely, hard disks may be recorded in FM format with this controller + [1], section "Drive select", table + This is currently unsupported; hard disks are forced to MFM +*/ +void hdc92x4_device::live_run_hd_until(attotime limit) +{ + int slot = 0; + if (TRACE_LIVE) logerror("%s: live_run_hd\n", tag()); + + if (m_live_state.state == IDLE || m_live_state.next_state != -1) + return; + + if (TRACE_LIVE) + { + if (limit == attotime::never) + logerror("%s: [%s live] live_run_hd, live_state=%02x, mode=%s\n", tag(), tts(m_live_state.time).c_str(), m_live_state.state, fm_mode()? "FM":"MFM"); + else + logerror("%s: [%s live] live_run_hd until %s, live_state=%02x, mode=%s\n", tag(), tts(m_live_state.time).c_str(), tts(limit).c_str(), m_live_state.state, fm_mode()? "FM":"MFM"); + } + + // We did not specify an upper time bound, so we take the next index pulse + if (limit == attotime::never && m_harddisk != NULL) + { + limit = m_harddisk->track_end_time(); + if (TRACE_LIVE) logerror("%s: [%s live] live_run_hd new limit %s\n", tag(), tts(m_live_state.time).c_str(), tts(limit).c_str()); + } + + while (true) + { + switch (m_live_state.state) + { + case SEARCH_IDAM: + if (TRACE_LIVE && m_last_live_state != SEARCH_IDAM) + { + logerror("%s: [%s live] SEARCH_IDAM [limit %s]\n", tag(),tts(m_live_state.time).c_str(), tts(limit).c_str()); + m_last_live_state = m_live_state.state; + } + + // This bit will be set when the IDAM cannot be found + set_bits(m_register_r[CHIP_STATUS], CS_SYNCERR, false); + + if (read_from_mfmhd(limit)) + { + if (TRACE_LIVE) logerror("%s: [%s live] SEARCH_IDAM limit reached\n", tag(), tts(m_live_state.time).c_str()); + return; + } + + if (TRACE_LIVE) + if ((m_live_state.bit_counter & 0x000f)==0) logerror("%s: [%s live] Read %04x\n", tag(), tts(m_live_state.time).c_str(), m_live_state.shift_reg); + + // [1] p. 9: The ID field sync mark must be found within 33,792 byte times + if (m_live_state.bit_count_total > 33792*16) + { + // Desired sector not found within time + if (m_substate == VERIFY3) + wait_for_realtime(VERIFY_FAILED); + else + wait_for_realtime(SEARCH_IDAM_FAILED); + return; + } + + if (found_mark(SEARCH_IDAM)) + { + if (TRACE_LIVE) logerror("%s: [%s live] Found an A1 mark\n", tag(), tts(m_live_state.time).c_str()); + m_live_state.crc = 0x443b; + m_live_state.data_separator_phase = false; + m_live_state.bit_counter = 0; + + m_live_state.state = READ_IDENT; + } + break; + + case SEARCH_IDAM_FAILED: + set_bits(m_register_r[CHIP_STATUS], CS_SYNCERR, true); + m_live_state.state = IDLE; + return; + + case VERIFY_FAILED: + set_bits(m_register_r[CHIP_STATUS], CS_COMPERR, true); + m_live_state.state = IDLE; + return; + + case READ_IDENT: + if (read_from_mfmhd(limit)) return; + + // Repeat until we have collected 16 bits (MFM_BITS; in the other modes this is always false) + if (m_live_state.bit_counter & 15) break; + + // Ident bytes are 111111xx + if ((m_live_state.data_reg & 0xfc) != 0xfc) + { + if (TRACE_LIVE) + { + if (m_live_state.data_reg == 0xf8 || m_live_state.data_reg == 0xfb) + logerror("%s: [%s live] Looks like a DAM; continue to next mark\n", tag(), tts(m_live_state.time).c_str()); + else + logerror("%s: [%s live] Missing ident data after A1, and it was not DAM; format corrupt?\n", tag(), tts(m_live_state.time).c_str()); + } + m_live_state.state = SEARCH_IDAM; + } + else + { + m_register_r[CURRENT_IDENT] = m_live_state.data_reg; + m_live_state.state = READ_ID_FIELDS_INTO_REGS; + slot = 0; + } + break; + + case READ_ID_FIELDS_INTO_REGS: + if (TRACE_LIVE && m_last_live_state != READ_ID_FIELDS_INTO_REGS) + { + logerror("%s: [%s live] READ_ID_FIELDS_INTO_REGS\n", tag(),tts(m_live_state.time).c_str()); + m_last_live_state = m_live_state.state; + } + + if (read_from_mfmhd(limit)) return; + + // Repeat until we have collected 16 bits + if (m_live_state.bit_counter & 15) break; + + if (TRACE_LIVE) logerror("%s: slot %d = %02x, crc=%04x\n", tag(), slot, m_live_state.data_reg, m_live_state.crc); + m_register_r[id_field[slot++]] = m_live_state.data_reg; + + if(slot > 5) + { + // We successfully read the ID fields; let's wait for the machine time to catch up. + if (reading_track()) + // Continue if we're reading a complete track + wait_for_realtime(READ_TRACK_ID_DONE); + else + // Live run is done here; it is the main state machine's turn again. + wait_for_realtime(IDLE); + return; + } + break; + + case SEARCH_DAM: + if (TRACE_LIVE && m_last_live_state != SEARCH_DAM) + { + logerror("%s: [%s live] SEARCH_DAM\n", tag(),tts(m_live_state.time).c_str()); + m_last_live_state = m_live_state.state; + } + set_bits(m_register_r[CHIP_STATUS], CS_DELDATA, false); + + if (read_from_mfmhd(limit)) return; + + if (TRACE_LIVE) + if ((m_live_state.bit_counter & 15)==0) logerror("%s: [%s live] Read %04x\n", tag(), tts(m_live_state.time).c_str(), m_live_state.shift_reg); + + if (m_live_state.bit_counter > 30*16) + { + if (TRACE_FAIL) logerror("%s: SEARCH_DAM failed\n", tag()); + wait_for_realtime(SEARCH_DAM_FAILED); + return; + } + + if (found_mark(SEARCH_DAM)) + { + if (TRACE_LIVE) logerror("%s: [%s live] Found an A1 mark\n", tag(),tts(m_live_state.time).c_str()); + m_live_state.crc = 0x443b; + m_live_state.data_separator_phase = false; + m_live_state.bit_counter = 0; + m_live_state.state = READ_DATADEL_FLAG; + } + break; + + case READ_DATADEL_FLAG: + if (read_from_mfmhd(limit)) return; + + if (m_live_state.bit_counter & 15) break; + + if ((m_live_state.data_reg & 0xff) == 0xf8) + { + if (TRACE_LIVE) logerror("%s: [%s live] Found deleted data mark F8 after DAM sync\n", tag(), tts(m_live_state.time).c_str()); + set_bits(m_register_r[CHIP_STATUS], CS_DELDATA, true); + } + else + { + if ((m_live_state.data_reg & 0xff) != 0xfb) + { + if (TRACE_FAIL) logerror("%s: [%s live] Missing FB/F8 data mark after DAM sync; found %04x\n", tag(), tts(m_live_state.time).c_str(), m_live_state.shift_reg); + wait_for_realtime(SEARCH_DAM_FAILED); + return; + } + } + m_live_state.bit_counter = 0; + m_live_state.state = READ_SECTOR_DATA; + break; + + case SEARCH_DAM_FAILED: + if (TRACE_FAIL) logerror("%s: SEARCH_DAM failed\n", tag()); + m_live_state.state = IDLE; + return; + + case READ_SECTOR_DATA: + if (TRACE_LIVE && m_last_live_state != READ_SECTOR_DATA) + { + logerror("%s: [%s live] READ_SECTOR_DATA\n", tag(),tts(m_live_state.time).c_str()); + m_last_live_state = m_live_state.state; + } + + if (read_from_mfmhd(limit)) return; + + // Request bus release + // For hard disk, get it only for the first byte and then keep the bus until the last byte. + // HD: bit_counter increases by 16 for MFM_BYTE, SEPARATED(_SIMPLE) and by 1 for MFM_BIT + // If we are reading a track, the DMA must have already been granted + if (!reading_track() && m_transfer_enabled && (m_live_state.bit_counter == 1 || m_live_state.bit_counter == 16)) + { + set_bits(m_register_r[INT_STATUS], ST_OVRUN, true); + m_out_dmarq(ASSERT_LINE); + } + + // Repeat until we have collected 16 bits + if (m_live_state.bit_counter & 15) break; + + slot = (m_live_state.bit_counter >> 4)-1; + if (TRACE_LIVE) logerror("%s: [%s live] Found data value [%d/%d] = %02X, CRC=%04x\n", tag(),tts(m_live_state.time).c_str(), slot, calc_sector_size(), m_live_state.data_reg, m_live_state.crc); + + if (slot < calc_sector_size()) + { + // For the first byte, allow for the DMA acknowledge to be set. + if (slot == 0) + { + wait_for_realtime(READ_SECTOR_DATA_CONT); + return; + } + else m_live_state.state = READ_SECTOR_DATA_CONT; + } + else if (slot < calc_sector_size()+2) + { + // CRC + if (slot == calc_sector_size()+1) + { + m_out_dip(CLEAR_LINE); + m_out_dmarq(CLEAR_LINE); + checkpoint(); + + if (reading_track()) + { + // Reading a track? Continue with next ID. + wait_for_realtime(READ_TRACK_ID); + } + else + { + if (TRACE_LIVE) logerror("%s: [%s live] Sector read completed\n", tag(),tts(m_live_state.time).c_str()); + wait_for_realtime(IDLE); + } + return; + } + } + break; + + case READ_SECTOR_DATA_CONT: + + // Did the system CPU send the DMA ACK in the meantime? + if ((m_register_r[INT_STATUS] & ST_OVRUN)!=0) + { + if (TRACE_FAIL) logerror("%s: No DMA ACK - buffer overrun\n", tag()); + set_bits(m_register_r[INT_STATUS], TC_DATAERR, true); + m_live_state.state = IDLE; + return; + } + + if (m_transfer_enabled) + { + m_register_r[DATA] = m_register_w[DATA] = m_live_state.data_reg; + // See above: For hard disk do it only for the first byte / bit + if (m_live_state.bit_counter == 1 || m_live_state.bit_counter == 16) + m_out_dip(ASSERT_LINE); + + m_out_dma(0, m_register_r[DATA], 0xff); + if (TRACE_LIVE) logerror("%s: [%s live] Byte %02x sent via DMA\n", tag(),tts(m_live_state.time).c_str(), m_register_r[DATA] & 0xff); + } + m_live_state.state = READ_SECTOR_DATA; + break; + + // ==== Track R/W operations (HD), also used for sector writing =============== + + case READ_TRACK_BYTE: + // The pause is implemented by doing dummy reads on the hard disk + if (read_from_mfmhd(limit)) + { + if (TRACE_LIVE) logerror("%s: [%s live] return; limit=%s\n", tag(), tts(m_live_state.time).c_str(), tts(limit).c_str()); + return; + } + + // Repeat until we have collected 16 bits + if ((m_live_state.bit_counter & 15)==0) + { + if (TRACE_READ && TRACE_DETAIL) logerror("%s: [%s live] Read byte %02x, repeat = %d\n", tag(), tts(m_live_state.time).c_str(), m_live_state.data_reg, m_live_state.repeat); + wait_for_realtime(READ_TRACK_NEXT_BYTE); + return; + } + break; + + case READ_TRACK_NEXT_BYTE: + m_live_state.state = READ_TRACK_BYTE; + m_live_state.repeat--; + if (m_live_state.repeat == 0) + { + // All bytes read + m_live_state.state = m_live_state.return_state; + checkpoint(); + } + break; + + case WRITE_TRACK_BYTE: + if (write_to_mfmhd(limit)) + { + if (TRACE_LIVE) logerror("%s: [%s live] write limit reached\n", tag(), tts(m_live_state.time).c_str()); + return; + } + + if (m_live_state.bit_counter == 0) + { + // All bits written; get the next byte into the shift register + wait_for_realtime(WRITE_TRACK_NEXT_BYTE); + return; + } + break; + + case WRITE_TRACK_NEXT_BYTE: + m_live_state.state = WRITE_TRACK_BYTE; + m_live_state.repeat--; + + // Write all bytes + if (m_live_state.repeat == 0) + { + // All bytes written + m_live_state.state = m_live_state.return_state; + checkpoint(); + } + else + encode_again(); + + break; + + // ======= HD sector write ===================================== + + case WRITE_DAM_AND_SECTOR: + if (TRACE_LIVE) logerror("%s: [%s live] Skipping GAP2\n", tag(), tts(m_live_state.time).c_str()); + skip_on_track(m_gap2_size, WRITE_DAM_SYNC); + + break; + + case WRITE_DAM_SYNC: + if (TRACE_WRITE && TRACE_DETAIL) logerror("%s: Write sync zeros\n", tag()); + + // Clear the overrun/underrun flag + set_bits(m_register_r[INT_STATUS], ST_OVRUN, false); + write_on_track(encode_hd(0x00), m_sync_size, WRITE_A1); + break; + + case WRITE_A1: + if (TRACE_WRITE && TRACE_DETAIL) logerror("%s: Write one A1\n", tag()); + write_on_track(encode_a1_hd(), 1, WRITE_DATAMARK); + break; + + case WRITE_DATAMARK: + if (TRACE_WRITE && TRACE_DETAIL) logerror("%s: Write data mark\n", tag()); + + // Init the CRC for the ident byte and sector + m_live_state.crc = 0x443b; // value for 1*A1 + + write_on_track(encode_hd(m_deleted? 0xf8 : 0xfb), 1, WRITE_SECDATA); + + m_live_state.byte_counter = calc_sector_size(); + + // Set the over/underrun flag and hope that it will be cleared before we start writing + // (only for sector writing) + if (m_substate == DATA_TRANSFER_WRITE) + { + set_bits(m_register_r[INT_STATUS], ST_OVRUN, true); + m_out_dmarq(ASSERT_LINE); + } + break; + + case WRITE_SECDATA: + if (m_substate == DATA_TRANSFER_WRITE) + { + // Check whether DMA has been acknowledged + if ((m_register_r[INT_STATUS] & ST_OVRUN)!=0) + { + // No, then stop here + m_live_state.state= NO_DMA_ACK; + } + else + { + if (TRACE_WRITE && TRACE_DETAIL) logerror("%s: Write sector byte, %d to go\n", tag(), m_live_state.byte_counter); + + // For floppies, set this for each byte; for hard disk, set it only at the beginning + if (m_live_state.byte_counter == calc_sector_size()) + m_out_dip(ASSERT_LINE); + + m_register_r[DATA] = m_register_w[DATA] = m_in_dma(0, 0xff); + + if (m_live_state.byte_counter == 0) + { + m_out_dip(CLEAR_LINE); + m_out_dmarq(CLEAR_LINE); + } + + if (m_live_state.byte_counter > 0) + { + m_live_state.byte_counter--; + write_on_track(encode_hd(m_register_r[DATA]), 1, WRITE_SECDATA); + } + else + { + m_live_state.state = WRITE_DATA_CRC; + // TODO: Prepare for ECC; this is "only" CRC + m_live_state.byte_counter = 2; + } + } + } + else + { + // We are here in the context of track formatting. Write a + // blank sector + write_on_track(encode_hd(0xe5), m_sector_size, WRITE_DATA_CRC); + m_live_state.byte_counter = 2; + } + break; + + case WRITE_DATA_CRC: + if (m_live_state.byte_counter > 0) + { + if (TRACE_WRITE && TRACE_DETAIL) logerror("%s: Write CRC\n", tag()); + m_live_state.byte_counter--; + write_on_track(encode_hd((m_live_state.crc >> 8) & 0xff), 1, WRITE_DATA_CRC); + } + else + // Write a filler byte so that the last CRC bit is saved correctly + write_on_track(encode_hd(0xff), 1, WRITE_DONE); + + break; + + case WRITE_DONE: + if (m_substate == DATA_TRANSFER_WRITE) + { + if (TRACE_WRITE && TRACE_DETAIL) logerror("%s: Write sector complete\n", tag()); + m_live_state.state = IDLE; + return; + } + else + { + // Continue for track writing: Write GAP3 + m_live_state.state = WRITE_GAP3; + } + break; + + // ================================================== + // Track reading (HD) + // ================================================== + // + // Read the next ID fields, then the sector contents. + // Continue until the next index hole shows up (live_abort). + case READ_TRACK: + if (TRACE_LIVE) logerror("%s: READ_TRACK\n", tag()); + m_live_state.state = READ_TRACK_ID; + break; + + case READ_TRACK_ID: + m_live_state.state = SEARCH_IDAM; + // Ask for access to bus + set_bits(m_register_r[INT_STATUS], ST_OVRUN, true); + m_out_dmarq(ASSERT_LINE); + break; + + case READ_TRACK_ID_DONE: + if ((m_register_r[INT_STATUS] & ST_OVRUN)!=0) + { + // We need an ACK right now, or the header bytes will be lost + if (TRACE_FAIL) logerror("%s: No DMA ACK - buffer overrun\n", tag()); + set_bits(m_register_r[INT_STATUS], TC_DATAERR, true); + m_live_state.state = IDLE; + return; + } + if (TRACE_LIVE) logerror("%s: READ_TRACK_ID_DONE\n", tag()); + m_out_dip(ASSERT_LINE); + + // Write the header via DMA + for (int slot = 0; slot < 6; slot++) + m_out_dma(0, m_register_r[id_field[slot]], 0xff); + + // Continue with reading the sector data + m_live_state.state = SEARCH_DAM; + wait_line(INDEX_LINE, ASSERT_LINE, TRACKDONE, true); + break; + + + // =========== HD formatting ============= + // Live states for track formatting + // Write GAP 1 + // Per sector + // Write Sync+IDAM + // Write Sector header+CRC + // Write GAP2 + // Write Sync+DAM + // Write Sector data + // Write CRC bytes + // Write GAP3 + // Write GAP4 until the next pulse + // ================================================== + case FORMAT_TRACK: + if (TRACE_LIVE) logerror("%s: FORMAT_TRACK\n", tag()); + m_live_state.state = WRITE_GAP1; + break; + + case WRITE_GAP1: + // GAP1 length is in DMA15_8 + if (TRACE_GAPS) logerror("%s: Writing GAP1; size=%d\n", tag(), m_gap1_size); + write_on_track(encode_hd(0x4e), m_gap1_size, WRITE_IDAM_SYNC); + break; + + case WRITE_IDAM_SYNC: + if (TRACE_GAPS) logerror("%s: Writing IDAM sync, size=%d\n", tag(), m_sync_size); + write_on_track(encode_hd(0x00), m_sync_size, WRITE_IDAM); + break; + + case WRITE_IDAM: + // Set the over/underrun flag and hope that it will be cleared before we enter the next state (after writing) + set_bits(m_register_r[INT_STATUS], ST_OVRUN, true); + m_out_dmarq(ASSERT_LINE); + if (TRACE_HEADER) logerror("%s: Writing IDAM and header: ", tag()); + write_on_track(encode_a1_hd(), 1, WRITE_HEADER); + m_live_state.byte_counter = 5; // TODO: Check this for AT mode + m_live_state.crc = 0xffff; + break; + + case WRITE_HEADER: + if ((m_register_r[INT_STATUS] & ST_OVRUN)!=0) + // No DMA (we do not get access to the ID table); exit + m_live_state.state= NO_DMA_ACK; + else + { + m_out_dip(ASSERT_LINE); + m_live_state.byte_counter--; + UINT8 headbyte = m_in_dma(0, 0xff); + if (TRACE_HEADER) logerror("%02x ", headbyte); + write_on_track(encode_hd(headbyte), 1, (m_live_state.byte_counter>0)? WRITE_HEADER : WRITE_HEADER_CRC); + + if (m_live_state.byte_counter==0) + { + m_out_dip(CLEAR_LINE); + m_out_dmarq(CLEAR_LINE); + // we will go to WRITE_HEADER_CRC state; set the byte counter for CRC + m_live_state.byte_counter = 2; + } + } + break; + + case WRITE_HEADER_CRC: + if (m_live_state.byte_counter > 0) + { + UINT8 crct = (m_live_state.crc >> 8) & 0xff; + if (TRACE_HEADER) logerror("%02x ", crct); + m_live_state.byte_counter--; + write_on_track(encode_hd(crct), 1, WRITE_HEADER_CRC); + } + else + { + if (TRACE_HEADER) logerror("\n"); + m_live_state.state = WRITE_GAP2; + } + break; + + case WRITE_GAP2: + if (TRACE_GAPS) logerror("%s: Writing GAP2, size=%d\n", tag(), m_gap2_size); + write_on_track(encode_hd(0x4e), m_gap2_size, WRITE_DAM_SYNC); + break; + + case WRITE_GAP3: + m_sector_count--; + if (TRACE_GAPS) logerror("%s: Writing GAP3, size=%d\n", tag(), m_gap3_size); + write_on_track(encode_hd(0x4e), m_gap3_size, (m_sector_count>0)? WRITE_IDAM_SYNC : WRITE_GAP4); + break; + + case WRITE_GAP4: + // Write bytes up to the end of the track + wait_line(INDEX_LINE, ASSERT_LINE, TRACKDONE, true); + if (TRACE_GAPS && m_last_live_state != WRITE_GAP4) + { + logerror("%s: Writing GAP4\n", tag()); + m_last_live_state = WRITE_GAP4; + } + // Write a single byte; when the index hole shows up, the live run will be aborted + write_on_track(encode_hd(0x4e), 1, WRITE_GAP4); + break; +// -------------------------------------------------------- + + default: + if (TRACE_LIVE) logerror("%s: Unknown state: %02x\n", tag(), m_live_state.state); + break; + } + } + m_last_live_state = UNDEF; +} + +/* + Synchronize the live position on the track with the real time. + Results in a new checkpoint and a live position at machine time or behind. + As a side effect, portions of the track may be re-read +*/ +void hdc92x4_device::live_sync() +{ + // Do we have some time set? + if (!m_live_state.time.is_never()) + { + // Are we ahead of the machine time? + if(m_live_state.time > machine().time()) + { + // If so, we must roll back to the last checkpoint + if (TRACE_SYNC) logerror("%s: [%s] Rolling back and replaying [%s live]\n", tag(), ttsn().c_str(), tts(m_live_state.time).c_str()); + rollback(); + + // and replay until we reach the machine time + if (using_floppy()) + { + live_run_until(machine().time()); + // Caught up, commit bits from pll buffer to disk until live time (if there is something to write) + m_pll.commit(m_floppy, m_live_state.time); + } + else + { + // HD case + live_run_hd_until(machine().time()); + } + } + else + { + // We are behind machine time, so we will never get back to that + // time, thus we can commit that position + if (TRACE_SYNC) logerror("%s: [%s] Committing [%s live]\n", tag(), ttsn().c_str(), tts(m_live_state.time).c_str()); + + // Commit bits from pll buffer to disk until live time (if there is something to write) + if (using_floppy()) + m_pll.commit(m_floppy, m_live_state.time); + + if (m_live_state.next_state != -1) + m_live_state.state = m_live_state.next_state; + + if (m_live_state.state == IDLE) + { + // Commit until live time and stop + if (using_floppy()) + m_pll.stop_writing(m_floppy, m_live_state.time); + m_live_state.time = attotime::never; + } + } + + m_live_state.next_state = -1; + checkpoint(); + } +} + +void hdc92x4_device::live_abort() +{ + if (!m_live_state.time.is_never() && m_live_state.time > machine().time()) + { + if (TRACE_LIVE) logerror("%s: [%s] Abort; rolling back and replaying [%s live]\n", tag(), ttsn().c_str(), tts(m_live_state.time).c_str()); + rollback(); + live_run_until(machine().time()); + } + + if (using_floppy()) m_pll.stop_writing(m_floppy, m_live_state.time); + + m_live_state.time = attotime::never; + m_live_state.state = IDLE; + m_live_state.next_state = -1; +} + +/* + Brings the live state machine into the WRITE substate part + comprised by WRITE_TRACK_(NEXT_)BYTE + Arguments: byte to be written, number, state on return +*/ +void hdc92x4_device::write_on_track(UINT16 encoded, int repeat, int next_state) +{ + m_live_state.repeat = repeat; + m_live_state.state = WRITE_TRACK_BYTE; + m_live_state.return_state = next_state; + encode_raw(encoded); +} + +/* + Brings the live state machine into the READ substate part. This is + only intended for skipping bytes. + Arguments: number, state on return +*/ +void hdc92x4_device::skip_on_track(int repeat, int next_state) +{ + m_live_state.bit_counter = 0; + m_live_state.repeat = repeat; + m_live_state.state = READ_TRACK_BYTE; + m_live_state.return_state = next_state; +} + +UINT8 hdc92x4_device::get_data_from_encoding(UINT16 raw) +{ + unsigned int value = 0; + + if (!using_floppy() && (m_hd_encoding == SEPARATED || m_hd_encoding == SEPARATED_SIMPLE)) return raw & 0xff; + + for (int i=0; i < 8; i++) + { + value <<= 1; + value |= (raw & 0x4000); + raw <<= 2; + } + return (value >> 14) & 0xff; +} + +void hdc92x4_device::rollback() +{ + m_live_state = m_checkpoint_state; + m_pll = m_checkpoint_pll; +} + +/* + Wait for real time to catch up. This way we pretend that the last + operation actually needed the real time. +*/ +void hdc92x4_device::wait_for_realtime(int state) +{ + m_live_state.next_state = state; + m_timer->adjust(m_live_state.time - machine().time()); + if (TRACE_LIVE) logerror("%s: [%s live] Waiting for real time [%s] to catch up; next state = %02x\n", tag(), tts(m_live_state.time).c_str(), ttsn().c_str(), state); +} + +/* + Read the next bit from the disk. + Return true: the time limit has been reached + Return false: The next bit is read into the shift register as the + rightmost bit; the shift register is a member of m_live_state. Also, + the CRC is updated. +*/ +bool hdc92x4_device::read_one_bit(const attotime &limit) +{ + // Get the next bit from the phase-locked loop. + int bit = m_pll.get_next_bit(m_live_state.time, m_floppy, limit); + + // We have reached the time limit + if (bit < 0) return true; + + // For test purposes: Drop a bit at some occasions + // value > 1000: rare occasions + // value = 500: can cope with + // value < 100: big trouble for controller, will fail + if (UNRELIABLE_MEDIA) + { + if ((machine().time().attoseconds() % 1009)==0) bit = 0; + } + + // Push into shift register + m_live_state.shift_reg = (m_live_state.shift_reg << 1) | bit; + m_live_state.bit_counter++; + + // Used for timeout handling + m_live_state.bit_count_total++; + + // Clock bit (false) or data bit (true)? + if (m_live_state.data_separator_phase==true) + { + m_live_state.data_reg = (m_live_state.data_reg << 1) | bit; + // Update CRC + if ((m_live_state.crc ^ (bit ? 0x8000 : 0x0000)) & 0x8000) + m_live_state.crc = (m_live_state.crc << 1) ^ 0x1021; + else + m_live_state.crc = m_live_state.crc << 1; + } + + m_live_state.data_separator_phase = !m_live_state.data_separator_phase; + return false; +} + +bool hdc92x4_device::write_one_bit(const attotime &limit) +{ + bool bit = (m_live_state.shift_reg & 0x8000)!=0; + + bool over_limit = m_pll.write_next_bit(bit, m_live_state.time, m_floppy, limit); + if (over_limit) return true; + + // Calculate the CRC from the data bits on the odd positions + if (m_live_state.bit_counter & 1) + { + if ((m_live_state.crc ^ (bit ? 0x8000 : 0x0000)) & 0x8000) + m_live_state.crc = (m_live_state.crc << 1) ^ 0x1021; + else + m_live_state.crc = m_live_state.crc << 1; + } + m_live_state.shift_reg = m_live_state.shift_reg << 1; + m_live_state.bit_counter--; + return false; +} + +UINT16 hdc92x4_device::encode(UINT8 byte) +{ + UINT16 raw; + UINT8 check_pos; + bool last_bit_set; + check_pos = 0x80; + + m_live_state.data_reg = byte; + raw = 0; + + if (fm_mode()) + { + raw = 0; + // FM: data bit = 1 -> encode as 11 + // data bit = 0 -> encode as 10 + for (int i=0; i<8; i++) + { + raw = (raw << 2) | (((byte & check_pos)!=0)? 0x03 : 0x02); + check_pos >>= 1; + } + last_bit_set = ((byte & 1)!=0); + } + else + { + last_bit_set = m_live_state.last_data_bit; + + for (int i=0; i<8; i++) + { + bool bit_set = ((byte & check_pos)!=0); + + // MFM: data bit = 1 -> encode as 01 + // data bit = 0 -> encode as x0 (x = !last_bit) + + raw <<= 2; + if (bit_set) raw |= 1; + else + { + if (!last_bit_set) raw |= 2; + } + last_bit_set = bit_set; + check_pos >>= 1; + } + } + return raw; +} + +void hdc92x4_device::encode_again() +{ + encode_raw(m_live_state.shift_reg_save); +} + +void hdc92x4_device::encode_raw(UINT16 raw) +{ + m_live_state.bit_counter = 16; + m_live_state.shift_reg = m_live_state.shift_reg_save = raw; + m_live_state.last_data_bit = raw & 1; + if (TRACE_WRITE && TRACE_DETAIL) logerror("%s: [%s live] Write %02x (%04x)\n", tag(), tts(m_live_state.time).c_str(), get_data_from_encoding(raw), raw); + checkpoint(); +} + +/* + Reset the PLL. For reading, data must pass through a dedicated data + separator. The clock rate is delivered from + m_clock_divider with values 1-3, where 1 is FM (4000), 2 is MFM (2000), + and 3 is MFM (1000). + When writing, the controller generates the proper output bitstream, so we + have to set it from its own state (fm/mfm and device type). +*/ +void hdc92x4_device::pll_reset(const attotime &when, bool output) +{ + m_pll.reset(when); + + if (output) + { + if (fm_mode()) + m_pll.set_clock(attotime::from_nsec(4000)); + else + m_pll.set_clock(attotime::from_nsec((m_selected_drive_type==TYPE_FLOPPY5)? 2000 : 1000)); + } + else + m_pll.set_clock(attotime::from_nsec(8000 >> (~m_clock_divider & 0x03))); +} + +void hdc92x4_device::checkpoint() +{ + // Commit bits from pll buffer to disk until live time (if there is something to write) + // For HD we do not use a PLL in this implementation + if (using_floppy()) + { + m_pll.commit(m_floppy, m_live_state.time); + m_checkpoint_pll = m_pll; + } + m_checkpoint_state = m_live_state; +} + +// =========================================================================== + +// HD support +/* + Read the bit or complete byte from the hard disk at the point of time + specified by the time in the live_state. + Return true: the time limit has been reached + Return false: valid return + + Updates the CRC and the shift register. Also, the time is updated. +*/ +bool hdc92x4_device::read_from_mfmhd(const attotime &limit) +{ + UINT16 data = 0; + bool offlimit = m_harddisk->read(m_live_state.time, limit, data); + + // We have reached the time limit + if (offlimit) return true; + + if (m_hd_encoding == MFM_BITS) + { + // Push bit into shift register + m_live_state.shift_reg = (m_live_state.shift_reg << 1) | data; + m_live_state.bit_counter++; + // Used for timeout handling + m_live_state.bit_count_total++; + + // Clock bit (false) or data bit (true)? + if (m_live_state.data_separator_phase==true) + { + m_live_state.data_reg = (m_live_state.data_reg << 1) | data; + // Update CRC + if ((m_live_state.crc ^ (data ? 0x8000 : 0x0000)) & 0x8000) + m_live_state.crc = (m_live_state.crc << 1) ^ 0x1021; + else + m_live_state.crc = m_live_state.crc << 1; + } + + m_live_state.data_separator_phase = !m_live_state.data_separator_phase; + } + else + { + UINT16 separated = data; + m_live_state.shift_reg = data; + + if (m_hd_encoding == MFM_BYTE) + { + for (int i=0; i < 8; i++) + { + separated <<= 1; + if (data & 0x8000) separated |= 0x0100; + data <<= 1; + if (data & 0x8000) separated |= 0x0001; + data <<= 1; + } + } + + // Push byte into data / clock register + m_live_state.clock_reg = (separated >> 8) & 0xff; + m_live_state.data_reg = separated & 0xff; + m_live_state.bit_counter += 16; + // Used for timeout handling + m_live_state.bit_count_total += 16; + + // Update CRC + m_live_state.crc = ccitt_crc16_one(m_live_state.crc, m_live_state.data_reg); + m_live_state.data_separator_phase = false; + } + + return false; +} + +/* + Write one bit or complete byte from the shift register to the hard disk + at the point of time specified by the time in the live_state. + Return true: the time limit has been reached + Return false: valid return + Updates the CRC and the shift register. Also, the time is updated. +*/ +bool hdc92x4_device::write_to_mfmhd(const attotime &limit) +{ + UINT16 data = 0; + int count; + bool offlimit; + + if (m_hd_encoding == MFM_BITS) + { + data = ((m_live_state.shift_reg & 0x8000)==0)? 0:1; + count = 1; + } + else + { + // We'll write the complete shift register in one go + data = m_live_state.shift_reg; + count = 16; + } + offlimit = m_harddisk->write(m_live_state.time, limit, data, m_precompensation != 0, m_reduced_write_current); + if (offlimit) return true; + + m_live_state.bit_counter -= count; + + // Calculate the CRC + if ((m_live_state.bit_counter & 1)==0) + { + if (m_hd_encoding == MFM_BITS) + { + if ((m_live_state.crc ^ ((data==0)? 0x8000 : 0x0000)) & 0x8000) + m_live_state.crc = (m_live_state.crc << 1) ^ 0x1021; + else + m_live_state.crc = m_live_state.crc << 1; + } + else + { + // Take the data byte from the stored copy in the data_reg + m_live_state.crc = ccitt_crc16_one(m_live_state.crc, m_live_state.data_reg); + } + } + + m_live_state.shift_reg = (m_live_state.shift_reg << count) & 0xffff; + return false; +} + +UINT16 hdc92x4_device::encode_hd(UINT8 byte) +{ + UINT16 cells; + UINT8 check_pos; + bool last_bit_set; + check_pos = 0x80; + + last_bit_set = m_live_state.last_data_bit; + cells = 0; + + int databit = (m_hd_encoding==SEPARATED)? 0x0080 : 0x4000; + int shift = (m_hd_encoding==SEPARATED)? 1 : 2; + int clockbit = 0x8000; + + if (m_hd_encoding != SEPARATED_SIMPLE) + { + for (int i=0; i<8; i++) + { + bool bit_set = ((byte & check_pos)!=0); + + // MFM: data bit = 1 -> encode as 01 + // data bit = 0 -> encode as x0 (x = !last_bit) + + if (bit_set) + cells |= databit; + else + cells |= (last_bit_set? 0x0000 : clockbit); + + databit >>= shift; + clockbit >>= shift; + + last_bit_set = bit_set; + check_pos >>= 1; + } + } + else + { + cells = byte & 0x00ff; + } + + m_live_state.data_reg = byte; + return cells; +} + +UINT16 hdc92x4_device::encode_a1_hd() +{ + UINT16 cells = 0; + + switch (m_hd_encoding) + { + case MFM_BITS: + case MFM_BYTE: + cells = 0x4489; + break; + case SEPARATED: + cells = 0x0aa1; + break; + case SEPARATED_SIMPLE: + cells = 0xffa1; + break; + } + + m_live_state.last_data_bit = true; + m_live_state.data_reg = 0xa1; + m_live_state.bit_counter = 16; + return cells; +} + + +// =========================================================================== + +/* + Read a byte of data from the controller + The address (offset) encodes the C/D* line (command and /data) +*/ +READ8_MEMBER( hdc92x4_device::read ) +{ + UINT8 reply = 0; + if ((offset & 1) == 0) + { + // Data register + reply = m_register_r[m_register_pointer]; + if (TRACE_READREG) logerror("%s: Read register[%d] -> %02x\n", tag(), m_register_pointer, reply); + + // Autoincrement until DATA is reached. + if (m_register_pointer < DATA) m_register_pointer++; + } + else + { + // Status register + reply = m_register_r[INT_STATUS]; + + // "The interrupt pin is reset to its inactive state + // when the UDC interrupt status register is read." [1] (p.3) + if (TRACE_READREG) logerror("%s: Read interrupt status register -> %02x\n", tag(), reply); + set_interrupt(CLEAR_LINE); + + // Clear the bits due to interrupt status register read. + m_register_r[INT_STATUS] &= ~(ST_INTPEND | ST_RDYCHNG); + } + return reply; +} + +/* + Write a byte to the controller + The address (offset) encodes the C/D* line (command and /data), so there + are only two addresses: 0 (register) and 1 (command). + The operation terminates immediately, and the controller picks up the + values stored in this phase at a later time. +*/ +WRITE8_MEMBER( hdc92x4_device::write ) +{ + if ((offset & 1) == 0) + { + if (TRACE_COMMAND) logerror("%s: New register write access %02x\n", tag(), data & 0xff); + if (m_executing) logerror("%s: Error - previous command %02x not completed; register access ignored\n", tag(), current_command()); + else + { + m_regvalue = data & 0xff; + wait_time(m_cmd_timer, attotime::from_nsec(REGISTER_COMMIT), REGISTER_ACCESS); + } + } + else + { + if (TRACE_COMMAND) logerror("%s: New incoming command %02x\n", tag(), data); + if (m_executing) logerror("%s: Error - previous command %02x not completed; new command %02x ignored\n", tag(), current_command(), data); + else + { + m_register_w[COMMAND] = data; + wait_time(m_cmd_timer, attotime::from_nsec(COMMAND_COMMIT), COMMAND_INIT); + } + } +} + +/* + When the commit period has passed, process the command or register access +*/ +void hdc92x4_device::process_command() +{ + if (m_substate == REGISTER_ACCESS) + { + // Writing data to registers + // Data register + if (TRACE_SETREG) + { + if (m_register_pointer == INT_COMM_TERM) + logerror("%s: Setting interrupt trigger DONE=%d READY=%d\n", tag(), (m_regvalue & TC_INTDONE)? 1:0, (m_regvalue & TC_INTRDCH)? 1:0); + else + logerror("%s: register[%d] <- %02x\n", tag(), m_register_pointer, m_regvalue); + } + m_register_w[m_register_pointer] = m_regvalue; + + // The DMA registers and the sector register for read and + // write are identical, so in that case we copy the contents + if (m_register_pointer < DESIRED_HEAD) m_register_r[m_register_pointer] = m_regvalue; + + // Autoincrement until DATA is reached. + if (m_register_pointer < DATA) m_register_pointer++; + } + else + { + // Reset DONE and BAD_SECTOR [1], p.7 + set_bits(m_register_r[INT_STATUS], ST_DONE | ST_BADSECT, false); + + // Reset interrupt line (not explicitly mentioned in spec, but seems reasonable + set_interrupt(CLEAR_LINE); + + // Clear Interrupt Pending and Ready Change + set_bits(m_register_r[INT_STATUS], ST_INTPEND | ST_RDYCHNG, false); + + int index = 0; + bool found = false; + + while (s_command[index].mask!=0 && !found) + { + if ((m_register_w[COMMAND] & s_command[index].mask) == s_command[index].baseval) + { + found = true; + + m_stop_after_index = false; + m_wait_for_index = false; + m_substate = UNDEF; + m_executing = true; + m_command = s_command[index].command; + // Invoke command + (this->*m_command)(); + } + else index++; + } + if (!found) + { + logerror("%s: Command %02x not defined\n", tag(), m_register_w[COMMAND]); + } + } + auxbus_out(); +} + +void hdc92x4_device::reenter_command_processing() +{ + if (TRACE_DELAY) logerror("%s: Re-enter command processing; live state = %02x\n", tag(), m_live_state.state); + // Do we have a live run on the track? + if (m_live_state.state != IDLE) + { + // Continue with it + live_run(); + if (m_live_state.state != IDLE) return; + } + + // We're here when there is no live_run anymore + // Where were we last time? + // Take care not to restart commands because of the index callback + if (TRACE_DELAY) logerror("%s: Continue with substate %02x\n", tag(), m_substate); + if (m_executing && m_substate != UNDEF) (this->*m_command)(); + auxbus_out(); +} + +/* + Assert Command Done status bit, triggering interrupts as needed +*/ +void hdc92x4_device::set_command_done(int flags) +{ + // Do another output, then set the flag + auxbus_out(); + + set_bits(m_register_r[INT_STATUS], ST_DONE, true); + + if (flags != -1) + { + set_bits(m_register_r[INT_STATUS], ST_TERMCOD, false); // clear the previously set flags + m_register_r[INT_STATUS] |= flags; + if (TRACE_DONE) logerror("%s: command %02x done, flags=%02x\n", tag(), current_command(), flags); + } + else + { + if (TRACE_DONE) logerror("%s: command %02x done\n", tag(), current_command()); + } + + // [1], p. 6 + if (TRACE_INT) logerror("%s: Raise interrupt DONE\n", tag()); + set_interrupt(ASSERT_LINE); + + m_substate = UNDEF; + m_executing = false; +} + +/* + Preserve previously set termination code +*/ +void hdc92x4_device::set_command_done() +{ + set_command_done(-1); +} + +/* + Auxiliary bus operation. + + The auxbus of the HDC92x4 is used to poll the drive status of the cur- + rently selected drive, to transmit DMA address bytes, to output the + OUTPUT1 register, and to output the OUTPUT2 register. + + The specification is not really precise on the times when this bus is + used, but at least we can rely on this information: + + - Whenever there is no output of data, the bus is sampled. ([1], p.8, + Drive status register). Data is sampled at the rising edge of STB*. + As the minimum STB* pulse is 800ns with min 100ns S0/S1 settling time + and min 100ns hold time we can say that the bus is polled at a maximum + rate of 1 MHz. + + - Data for the DMA address is output only when the address is initially + set; also when the address must be set again on error ([1], p.5, + DMA registers). The external memory system has to take care of the + addressing for subsequent bytes. The address will be increased by the + length of a sector during multiple sector read/write operations. + + We may assume that the OUTPUT1 and OUTPUT2 operations only occur on + changes to the registers in the controller. The values showing up on the + auxiliary bus must be latched anyway. + + For the sampling of drive status values, the emulation would have to + invoke a callback to the hosting board at a rate of about 1 MHz. Since + the devices like floppy or hard disks are pushing their status changes, + it makes much more sense to allow for an incoming call to the controller + instead of a polling. This also allows to raise interrupts as soon + as the drive status changes. The difference to the real controller + would be less than 3 microseconds (in the worst case when the auxbus is + currently outputting data as the drive status change occurs). + + Drive status read + S0 = 0, S1 = 0 + +------+------+------+------+------+------+------+------+ + | ECC |Index | SeekC| Tr00 | User | WrPrt| Ready|Fault | + +------+------+------+------+------+------+------+------+ +*/ + +/* + Read the drive status over the auxbus + (as said, let the controller board push the values into the controller) +*/ +void hdc92x4_device::auxbus_in(UINT8 data) +{ + // Kill unwanted input via auxbus until we are initialized. + if (!m_initialized) + return; + + if (TRACE_AUXBUS) logerror("%s: Got value %02x via auxbus: ecc=%d index=%d seek_comp=%d tr00=%d user=%d writeprot=%d ready=%d fault=%d\n", + tag(), data, + (data&HDC_DS_ECCERR)? 1:0, (data&HDC_DS_INDEX)? 1:0, + (data&HDC_DS_SKCOM)? 1:0, (data&HDC_DS_TRK00)? 1:0, + (data&HDC_DS_UDEF)? 1:0, (data&HDC_DS_WRPROT)? 1:0, + (data&HDC_DS_READY)? 1:0, (data&HDC_DS_WRFAULT)? 1:0); + + bool previndex = index_hole(); + bool prevready = drive_ready(); + bool prevskcom = seek_complete(); + + m_register_r[DRIVE_STATUS] = data; + + // Call a handler if the respective flag changed + if (previndex != index_hole()) index_handler(); + if (prevready != drive_ready()) ready_handler(); + if (prevskcom != seek_complete()) seek_complete_handler(); +} + +bool hdc92x4_device::waiting_for_line(int line, int level) +{ + return (m_event_line == line && m_state_after_line != UNDEF && m_line_level == level); +} + +bool hdc92x4_device::waiting_for_other_line(int line) +{ + return (m_state_after_line != UNDEF && m_event_line != line); +} + +/* + Handlers for incoming signal lines. +*/ +void hdc92x4_device::index_handler() +{ + int level = index_hole()? ASSERT_LINE : CLEAR_LINE; + if (TRACE_LINES) logerror("%s: [%s] Index handler; level=%d\n", tag(), ttsn().c_str(), level); + + // Synchronize our position on the track + live_sync(); + + if (level==ASSERT_LINE) + { + if (TRACE_INDEX) logerror("%s: Index pulse\n", tag()); + if (m_wait_for_index) m_stop_after_index = true; + } + + if (waiting_for_line(INDEX_LINE, level)) + { + if (TRACE_LINES) logerror("%s: [%s] Index pulse level=%d triggers event\n", tag(), ttsn().c_str(), level); + m_substate = m_state_after_line; + m_state_after_line = UNDEF; + if (m_stopwrite) + { + if (using_floppy()) m_pll.stop_writing(m_floppy, m_live_state.time); + m_live_state.state = IDLE; + } + reenter_command_processing(); + } + else + { + // Live processing waits for INDEX + // For harddisk we will continue processing on the falling edge + if (!m_timed_wait && !waiting_for_other_line(INDEX_LINE) && (using_floppy() || level == CLEAR_LINE)) + reenter_command_processing(); + } +} + +void hdc92x4_device::ready_handler() +{ + int level = drive_ready()? ASSERT_LINE : CLEAR_LINE; + if (TRACE_LINES) logerror("%s: [%s] Ready handler; level=%d\n", tag(), ttsn().c_str(), level); + + // Set the interrupt status flag + set_bits(m_register_r[INT_STATUS], ST_RDYCHNG, true); + + // Synchronize our position on the track + live_sync(); + + // Raise an interrupt if desired + if (m_register_w[INT_COMM_TERM] & TC_INTRDCH) + { + if (TRACE_INT) logerror("%s: Raise interrupt READY change\n", tag()); + set_interrupt(ASSERT_LINE); + } + + // This is actually not needed, since we never wait for READY + if (waiting_for_line(READY_LINE, level)) + { + m_substate = m_state_after_line; + m_state_after_line = UNDEF; + reenter_command_processing(); + } +} + +void hdc92x4_device::seek_complete_handler() +{ + int level = seek_complete()? ASSERT_LINE : CLEAR_LINE; + if (TRACE_LINES) logerror("%s: [%s] Seek complete handler; level=%d\n", tag(), ttsn().c_str(), level); + + // Synchronize our position on the track + live_sync(); + + if (waiting_for_line(SEEKCOMP_LINE, level)) + { + m_substate = m_state_after_line; + m_state_after_line = UNDEF; + reenter_command_processing(); + } +} + +/* + Push the output registers over the auxiliary bus. It is expected that + the PCB contains latches to store the values. + + OUTPUT1 register contents + S0 = 0, S1 = 1 + +------+------+------+------+------+------+------+------+ + | Drv3 | Drv2 | Drv1 | Drv0 | PO3 | PO2 | PO1 | PO0 | + +------+------+------+------+------+------+------+------+ + + DrvX = select Drive X (only one bit allowed) + POX = Programmable output X (contents from low 4 bits of register RETRY_COUNT) + + + OUTPUT2 register contents + S0 = 1, S1 = 1 + +------+------+------+------+------+------+------+------+ + | Drv3*| WCur | Dir | Step | Head | + +------+------+------+------+------+------+------+------+ + + Drv3* = inverted Drv3 signal of OUTPUT1 + WCur = Reduced write current + Dir = Step direction (0 = towards track 0) + Step = Step pulse + Head = desired head +*/ +void hdc92x4_device::auxbus_out() +{ + // prepare output2 + set_bits(m_output2, OUT2_DRVSEL3I, (m_output1 & OUT1_DRVSEL3)==0); + + m_output2 = (m_output2 & 0xb0) | desired_head(); + if (m_reduced_write_current) m_output2 |= OUT2_REDWRT; + + if (TRACE_AUXBUS) logerror("%s: [%s] Setting OUTPUT1=%02x, OUTPUT2=%02x\n", tag(), ttsn().c_str(), m_output1, m_output2); + + if (m_output1 != m_output1_old || m_output2 != m_output2_old) + { + // Only propagate changes + m_out_auxbus((offs_t)HDC_OUTPUT_1, m_output1); + m_out_auxbus((offs_t)HDC_OUTPUT_2, m_output2); + m_output1_old = m_output1; + m_output2_old = m_output2; + } +} + +void hdc92x4_device::dma_address_out(UINT8 addrub, UINT8 addrhb, UINT8 addrlb) +{ + if (TRACE_DMA) logerror("%s: Setting DMA address %06x\n", tag(), (addrub<<16 | addrhb<<8 | addrlb)&0xffffff); + m_out_auxbus((offs_t)HDC_OUTPUT_DMA_ADDR, addrub); + m_out_auxbus((offs_t)HDC_OUTPUT_DMA_ADDR, addrhb); + m_out_auxbus((offs_t)HDC_OUTPUT_DMA_ADDR, addrlb); +} + +/* + Set/clear INT + + Interupts are generated in the following occasions: + - when the DONE bit is set to 1 in the ISR and ST_DONE is set to 1 + - when the READY_CHANGE bit is set to 1 in the ISR and ST_RDYCHNG is set to 1 + (ready change: 1->0 or 0->1) +*/ +void hdc92x4_device::set_interrupt(line_state intr) +{ + if (intr == ASSERT_LINE) + { + // Only if there is not already a pending interrupt + if ((m_register_r[INT_STATUS] & ST_INTPEND) == 0) + { + m_register_r[INT_STATUS] |= ST_INTPEND; + m_out_intrq(intr); + } + } + else + { + // if there is a pending interrupt + if ((m_register_r[INT_STATUS] & ST_INTPEND) != 0) + m_out_intrq(intr); + } +} + +/* + DMA acknowledge line. +*/ +WRITE_LINE_MEMBER( hdc92x4_device::dmaack ) +{ + if (state==ASSERT_LINE) + { + if (TRACE_DMA) logerror("%s: [%s] DMA acknowledged\n", tag(), ttsn().c_str()); + set_bits(m_register_r[INT_STATUS], ST_OVRUN, false); + } +} + +/* + This is pretty simple here, compared to wd17xx, because index and ready + callbacks have to be tied to the controller board outside the chip. +*/ +void hdc92x4_device::connect_floppy_drive(floppy_image_device* floppy) +{ + m_floppy = floppy; +} + +/* + Connect the current hard drive. +*/ +void hdc92x4_device::connect_hard_drive(mfm_harddisk_device* harddisk) +{ + m_harddisk = harddisk; + m_hd_encoding = m_harddisk->get_encoding(); + if (TRACE_SELECT && TRACE_DETAIL) logerror("%s: HD encoding = %d\n", tag(), m_hd_encoding); +} + +/* + Clock divider. This input line actually belongs to the data separator which + is a separate circuit. Maybe we will take it out of this implementation + at some time and make it a device of its own. + line: CD0 (0) and CD1(1), value 0 or 1 +*/ +void hdc92x4_device::set_clock_divider(int line, int value) +{ + set_bits(m_clock_divider, (line==0)? 1 : 2, value&1); +} + +/* + This is reached when a timer has expired +*/ +void hdc92x4_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + live_sync(); + m_timed_wait = false; + + switch (id) + { + case GEN_TIMER: + reenter_command_processing(); + break; + case COM_TIMER: + process_command(); + break; + } +} + +/* + Reset the controller. Negative logic, but we use ASSERT_LINE. +*/ +WRITE_LINE_MEMBER( hdc92x4_device::reset ) +{ + if (state == ASSERT_LINE) + { + if (TRACE_LINES) logerror("%s: Reset via RST line\n", tag()); + device_reset(); + } +} + +void hdc92x4_device::device_start() +{ + m_out_intrq.resolve_safe(); + m_out_dip.resolve_safe(); + m_out_auxbus.resolve_safe(); + m_out_dmarq.resolve_safe(); + m_out_dma.resolve_safe(); + m_in_dma.resolve_safe(0); + + // allocate timers + m_timer = timer_alloc(GEN_TIMER); + m_cmd_timer = timer_alloc(COM_TIMER); + // m_live_timer = timer_alloc(LIVE_TIMER); + + m_live_state.state = IDLE; +} + +void hdc92x4_device::device_reset() +{ + m_clock_divider = 0; + m_deleted = false; + m_executing = false; + m_event_line = UNDEF; + m_first_sector_found = false; + m_initialized = true; + m_line_level = CLEAR_LINE; + m_live_state.state = IDLE; + m_live_state.time = attotime::never; + m_logical = true; + m_multi_sector = false; + m_output1 = 0; + m_output2 = 0x80; + m_output1_old = 1; // force an initial output + m_output2_old = 0x81; + m_precompensation = 0; + m_reduced_write_current = false; + m_regvalue = 0; + m_register_pointer = 0; + m_retry_save = 0; + m_seek_count = 0; + m_selected_drive_number = NODRIVE; + m_selected_drive_type = 0; + m_state_after_line = UNDEF; + m_stop_after_index = false; + m_substate = UNDEF; + m_timed_wait = false; + m_track_delta = 0; + m_transfer_enabled = true; + m_wait_for_index = false; + m_write = false; + + for (int i=0; i<=11; i++) + m_register_r[i] = m_register_w[i] = 0; + + set_interrupt(CLEAR_LINE); + m_out_dip(CLEAR_LINE); + m_out_dmarq(CLEAR_LINE); +} + +const device_type HDC9224 = &device_creator; +const device_type HDC9234 = &device_creator; diff --git a/src/devices/machine/hdc92x4.h b/src/devices/machine/hdc92x4.h new file mode 100644 index 00000000000..da3c5b6d954 --- /dev/null +++ b/src/devices/machine/hdc92x4.h @@ -0,0 +1,487 @@ +// license:BSD-3-Clause +// copyright-holders:Michael Zapf +/* + HDC9224 / HDC9234 Hard and Floppy Disk Controller + For details see hdc92x4.c +*/ +#ifndef __HDC92X4_H__ +#define __HDC92X4_H__ + +#include "emu.h" +#include "imagedev/floppy.h" +#include "imagedev/mfmhd.h" +#include "fdc_pll.h" + +extern const device_type HDC9224; +extern const device_type HDC9234; + +/* + Enumeration of the latches outside of the controller +*/ +enum +{ + HDC_INPUT_STATUS = 0x00, + HDC_OUTPUT_DMA_ADDR = 0x01, + HDC_OUTPUT_1 = 0x02, + HDC_OUTPUT_2 = 0x03 +}; + + +/* + Definition of bits in the Disk-Status register +*/ +enum +{ + HDC_DS_ECCERR = 0x80, // ECC error + HDC_DS_INDEX = 0x40, // index hole + HDC_DS_SKCOM = 0x20, // seek complete + HDC_DS_TRK00 = 0x10, // track 0 + HDC_DS_UDEF = 0x08, // user-defined + HDC_DS_WRPROT = 0x04, // write-protected + HDC_DS_READY = 0x02, // drive ready bit + HDC_DS_WRFAULT = 0x01 // write fault +}; + +//=================================================================== + +/* Interrupt line. To be connected with the controller PCB. */ +#define MCFG_HDC92X4_INTRQ_CALLBACK(_write) \ + devcb = &hdc92x4_device::set_intrq_wr_callback(*device, DEVCB_##_write); + +/* DMA request line. To be connected with the controller PCB. */ +#define MCFG_HDC92X4_DMARQ_CALLBACK(_write) \ + devcb = &hdc92x4_device::set_dmarq_wr_callback(*device, DEVCB_##_write); + +/* DMA in progress line. To be connected with the controller PCB. */ +#define MCFG_HDC92X4_DIP_CALLBACK(_write) \ + devcb = &hdc92x4_device::set_dip_wr_callback(*device, DEVCB_##_write); + +/* Auxiliary Bus. These 8 lines need to be connected to external latches + and to a counter circuitry which works together with the external RAM. + We use the S0/S1 lines as address lines. */ +#define MCFG_HDC92X4_AUXBUS_OUT_CALLBACK(_write) \ + devcb = &hdc92x4_device::set_auxbus_wr_callback(*device, DEVCB_##_write); + +/* Callback to read the contents of the external RAM via the data bus. + Note that the address must be set and automatically increased + by external circuitry. */ +#define MCFG_HDC92X4_DMA_IN_CALLBACK(_read) \ + devcb = &hdc92x4_device::set_dma_rd_callback(*device, DEVCB_##_read); + +/* Callback to write the contents of the external RAM via the data bus. + Note that the address must be set and automatically increased + by external circuitry. */ +#define MCFG_HDC92X4_DMA_OUT_CALLBACK(_write) \ + devcb = &hdc92x4_device::set_dma_wr_callback(*device, DEVCB_##_write); + +//=================================================================== + +class hdc92x4_device : public device_t +{ +public: + hdc92x4_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + // Accesors from the CPU side + DECLARE_READ8_MEMBER( read ); + DECLARE_WRITE8_MEMBER( write ); + DECLARE_WRITE_LINE_MEMBER( reset ); + DECLARE_WRITE_LINE_MEMBER( dmaack ); + + // Callbacks + template static devcb_base &set_intrq_wr_callback(device_t &device, _Object object) { return downcast(device).m_out_intrq.set_callback(object); } + template static devcb_base &set_dmarq_wr_callback(device_t &device, _Object object) { return downcast(device).m_out_dmarq.set_callback(object); } + template static devcb_base &set_dip_wr_callback(device_t &device, _Object object) { return downcast(device).m_out_dip.set_callback(object); } + template static devcb_base &set_auxbus_wr_callback(device_t &device, _Object object) { return downcast(device).m_out_auxbus.set_callback(object); } + template static devcb_base &set_dma_rd_callback(device_t &device, _Object object) { return downcast(device).m_in_dma.set_callback(object); } + template static devcb_base &set_dma_wr_callback(device_t &device, _Object object) { return downcast(device).m_out_dma.set_callback(object); } + + // auxbus_in is intended to read events from the drives + // In the real chip the status is polled; to avoid unnecessary load + // we implement it as a push call + void auxbus_in( UINT8 data ); + + // We pretend that the data separator is part of this controller. It is + // in fact a separate circuit. The clock divider must be properly set + // for MFM (CD0=1, CD1=0) or FM (CD0=0, CD1=1). + // This is not set by the controller itself! + void set_clock_divider(int pin, int value); + + // Used to reconfigure the drive connections. Floppy drive selection is done + // using the user-programmable outputs. Hence, the connection + // is changed outside of the controller, and by this way we let it know. + void connect_floppy_drive(floppy_image_device *floppy); + + // Used to reconfigure the drive connections. See connect_floppy_drive. + void connect_hard_drive(mfm_harddisk_device *harddisk); + +protected: + void device_start(); + void device_reset(); + + bool m_is_hdc9234; + + devcb_write_line m_out_intrq; // INT line + devcb_write_line m_out_dmarq; // DMA request line + devcb_write_line m_out_dip; // DMA in progress line + devcb_write8 m_out_auxbus; // AB0-7 lines (using S0,S1 as address) + devcb_read8 m_in_dma; // DMA read access to the cache buffer + devcb_write8 m_out_dma; // DMA write access to the cache buffer + + // Internal register pointer used for sequential register loading + int m_register_pointer; + + // Read and write registers + UINT8 m_register_w[12]; + UINT8 m_register_r[15]; + + // Interrupt management (outgoing INT pin) + void set_interrupt(line_state intr); + + // Currently connected floppy + floppy_image_device* m_floppy; + + // Currently connected harddisk + mfm_harddisk_device* m_harddisk; + + // internal register OUTPUT1 + UINT8 m_output1, m_output1_old; + + // internal register OUTPUT2 + UINT8 m_output2, m_output2_old; + + // Write the output registers to the latches + void auxbus_out(); + + // Write the DMA address to the external latches + void dma_address_out(UINT8 addrub, UINT8 addrhb, UINT8 addrlb); + + // Intermediate storage for register + UINT8 m_regvalue; + + // Drive type that has been selected in drive_select + int m_selected_drive_type; + + // Drive numbere that has been selected in drive_select + int m_selected_drive_number; + + // Indicates whether the device has completed initialization + bool m_initialized; + + // Timers to delay execution/completion of commands */ + emu_timer *m_timer; + emu_timer *m_cmd_timer; + // emu_timer *m_live_timer; + + // Timer callback + void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + // Handlers for incoming signals + void ready_handler(); + void index_handler(); + void seek_complete_handler(); + + // Wait for this line? + bool waiting_for_line(int line, int level); + + // Wait for some other line? + bool waiting_for_other_line(int line); + + // Wait for some time to pass or for a line to change level + void wait_time(emu_timer *tm, int microsec, int next_substate); + void wait_time(emu_timer *tm, const attotime &delay, int param); + void wait_line(int line, line_state level, int substate, bool stopwrite); + + // Converts attotime to a string + std::string tts(const attotime &t); + + // Current time + std::string ttsn(); + + // Utility routine to set or reset bits + void set_bits(UINT8& byte, int mask, bool set); + + // Event handling + line_state m_line_level; + int m_event_line; + int m_state_after_line; + bool m_timed_wait; + + // ============================================== + // Live state machine + // ============================================== + + struct live_info + { + attotime time; + UINT16 shift_reg; + UINT16 shift_reg_save; + UINT16 crc; + int bit_counter; + int bit_count_total; // used for timeout handling + int byte_counter; + bool data_separator_phase; + bool last_data_bit; + UINT8 clock_reg; + UINT8 data_reg; + int state; + int next_state; + int repeat; // for formatting + int return_state; // for formatting + }; + + live_info m_live_state, m_checkpoint_state; + int m_last_live_state; + + // Starts the live run + void live_start(int state); + + // Analyses the track until the given time + void live_run_until(attotime limit); + + // Same for hard disks + void live_run_hd_until(attotime limit); + + // Live run until next index pulse + void live_run(); + + // Control functions for syncing the track analyser with the machine time + void wait_for_realtime(int state); + void live_sync(); + void live_abort(); + void rollback(); + void checkpoint(); + + // Found a mark + bool found_mark(int state); + + // Delivers the data bits from the given encoding + UINT8 get_data_from_encoding(UINT16 raw); + + // ============================================== + // PLL functions and interface to floppy and harddisk + // ============================================== + + // Phase-locked loops + fdc_pll_t m_pll, m_checkpoint_pll; + + // Clock divider value + UINT8 m_clock_divider; + + // MFM HD encoding type + mfmhd_enc_t m_hd_encoding; + + // Resets the PLL to the given time + void pll_reset(const attotime &when, bool write); + + // Puts the word into the shift register directly. Changes the m_live_state members + // shift_reg, and last_data_bit + void encode_raw(UINT16 word); + + // Encodes a byte in FM or MFM. Called by encode_byte. + UINT16 encode(UINT8 byte); + + // Encodes a byte in FM or MFM. Called by encode_byte. + UINT16 encode_hd(UINT8 byte); + UINT16 encode_a1_hd(); + + // Encode the latest byte again + void encode_again(); + + // Reads from the current position on the track + bool read_one_bit(const attotime &limit); + + // Writes to the current position on the track + bool write_one_bit(const attotime &limit); + + // Writes to the current position on the track + void write_on_track(UINT16 raw, int count, int next_state); + + // Skips bytes on the track + void skip_on_track(int count, int next_state); + + // Read from the MFM HD + bool read_from_mfmhd(const attotime &limit); + + // Write to the MFM HD + bool write_to_mfmhd(const attotime &limit); + + // ============================================== + // Command state machine + // ============================================== + + int m_substate; + + typedef void (hdc92x4_device::*cmdfunc)(void); + + typedef struct + { + UINT8 baseval; + UINT8 mask; + cmdfunc command; + } cmddef; + + static const cmddef s_command[]; + + // Indicates whether a command is currently being executed + bool m_executing; + + // Keeps the pointer to the function for later continuation + cmdfunc m_command; + + // Invoked after the commit period for command initiation or register write access + void process_command(); + + // Re-enters the state machine after a delay + void reenter_command_processing(); + + // Command is done + void set_command_done(int flags); + void set_command_done(); + + // Difference between current cylinder and desired cylinder + int m_track_delta; + + // Used to restore the retry count for multi-sector operations + int m_retry_save; + + // ============================================== + // Operation properties + // ============================================== + + // Precompensation value + int m_precompensation; + + // Do we have a multi-sector operation? + bool m_multi_sector; + + // Shall we wait for the index hole? + bool m_wait_for_index; + + // Shall we stop after the next index hole? + bool m_stop_after_index; + + // Is data transfer enabled for read operations? + bool m_transfer_enabled; + + // Is it a read or a write operation? + bool m_write; + + // Have we found a deleted sector? + bool m_deleted; + + // Do we apply a reduced write current? + bool m_reduced_write_current; + + // Used in RESTORE to find out when to give up + int m_seek_count; + + // Read/write logical or physical? + bool m_logical; + + // Signals to abort writing + bool m_stopwrite; + + // Flag to remember whether we found the first sector during a physical access + bool m_first_sector_found; + + // Used for formatting + int m_sector_count; + int m_sector_size; + int m_gap0_size; + int m_gap1_size; + int m_gap2_size; + int m_gap3_size; + int m_sync_size; + + // Are we in FM mode? + bool fm_mode(); + + // Seek completed? + bool seek_complete(); + + // Are we on track 0? + bool on_track00(); + + // Are we at the index hole? + bool index_hole(); + + // Is the attached drive ready? + bool drive_ready(); + + // Are we reading a track? + bool reading_track(); + + // Delivers the desired head + int desired_head(); + + // Delivers the desired sector + int desired_sector(); + + // Delivers the desired cylinder. The value is spread over two registers. + int desired_cylinder(); + + // Delivers the current head as read from the track + int current_head(); + + // Delivers the current sector as read from the track + int current_sector(); + + // Delivers the current cylinder as read from the track + int current_cylinder(); + + // Delivers the current command + UINT8 current_command(); + + // Step time (minus pulse width) + int step_time(); + + // Step pulse width + int pulse_width(); + + // Sector size as read from the track + int calc_sector_size(); + + // Is the currently selected drive a floppy drive? + bool using_floppy(); + + // Common subprograms READ ID, VERIFY, and DATA TRANSFER + void read_id(int& cont, bool implied_seek, bool wait_seek_complete); + void verify(int& cont); + void data_transfer(int& cont); + + // =================================================== + // Commands + // =================================================== + + void reset_controller(); + void drive_deselect(); + void restore_drive(); + void step_drive(); + void tape_backup(); + void poll_drives(); + void drive_select(); + void set_register_pointer(); + void seek_read_id(); + void read_sectors(); + void read_track(); + void format_track(); + void write_sectors(); +}; + +// ===================================================== +// Subclasses: the two variants +// ===================================================== + +class hdc9224_device : public hdc92x4_device +{ +public: + hdc9224_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class hdc9234_device : public hdc92x4_device +{ +public: + hdc9234_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +#endif diff --git a/src/devices/machine/i2cmem.c b/src/devices/machine/i2cmem.c new file mode 100644 index 00000000000..5e714c0b129 --- /dev/null +++ b/src/devices/machine/i2cmem.c @@ -0,0 +1,510 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/*************************************************************************** + +I2C Memory + +Generic ram/rom/eeprom/flash on an i2c bus. Supports specifying the slave address, +the data size & the page size for writing. + +inputs: + e0,e1,e2 lower 3 bits of the slave address + sda serial data + scl serial clock + wc write protect + +outputs: + sda serial data + +The memory address is only 8 bits, devices larger than this have multiple slave addresses. +The top five address bits are set at manufacture time, two values are standard. +Up to 4096 bytes can be addressed. + +***************************************************************************/ + +#include "emu.h" +#include "machine/i2cmem.h" + +#define STATE_IDLE ( 0 ) +#define STATE_DEVSEL ( 1 ) +#define STATE_BYTEADDR ( 2 ) +#define STATE_DATAIN ( 3 ) +#define STATE_DATAOUT ( 4 ) + +#define DEVSEL_RW ( 1 ) +#define DEVSEL_ADDRESS ( 0xfe ) + +//************************************************************************** +// DEBUGGING +//************************************************************************** + +#define VERBOSE_LEVEL ( 0 ) + +INLINE void ATTR_PRINTF( 3, 4 ) verboselog( device_t *device, int n_level, const char *s_fmt, ... ) +{ + if( VERBOSE_LEVEL >= n_level ) + { + va_list v; + char buf[ 32768 ]; + va_start( v, s_fmt ); + vsprintf( buf, s_fmt, v ); + va_end( v ); + logerror( "%s: I2CMEM(%s) %s", device->machine().describe_context( ), device->tag(), buf ); + } +} + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +// device type definition +const device_type I2CMEM = &device_creator; + +static ADDRESS_MAP_START( i2cmem_map8, AS_PROGRAM, 8, i2cmem_device ) + AM_RANGE(0x0000, 0x0fff) AM_RAM +ADDRESS_MAP_END + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// i2cmem_device - constructor +//------------------------------------------------- + +i2cmem_device::i2cmem_device( const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock ) + : device_t(mconfig, I2CMEM, "I2C Memory", tag, owner, clock, "i2cmem", __FILE__), + device_memory_interface(mconfig, *this), + device_nvram_interface(mconfig, *this), + m_slave_address( I2CMEM_SLAVE_ADDRESS ), + m_page_size( 0 ), + m_data_size( 0 ), + m_scl( 0 ), + m_sdaw( 0 ), + m_e0( 0 ), + m_e1( 0 ), + m_e2( 0 ), + m_wc( 0 ), + m_sdar( 1 ), + m_state( STATE_IDLE ), + m_shift( 0 ), + m_byteaddr( 0 ) +{ +} + + +//------------------------------------------------- +// device_config_complete - perform any +// operations now that the configuration is +// complete +//------------------------------------------------- + +void i2cmem_device::device_config_complete() +{ + int address_bits = 0; + + int i = m_data_size - 1; + while( i > 0 ) + { + address_bits++; + i >>= 1; + } + + m_space_config = address_space_config( "i2cmem", ENDIANNESS_BIG, 8, address_bits, 0, *ADDRESS_MAP_NAME( i2cmem_map8 ) ); +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void i2cmem_device::device_start() +{ + m_page.resize( m_page_size ); + + save_item( NAME(m_scl) ); + save_item( NAME(m_sdaw) ); + save_item( NAME(m_e0) ); + save_item( NAME(m_e1) ); + save_item( NAME(m_e2) ); + save_item( NAME(m_wc) ); + save_item( NAME(m_sdar) ); + save_item( NAME(m_state) ); + save_item( NAME(m_bits) ); + save_item( NAME(m_shift) ); + save_item( NAME(m_devsel) ); + save_item( NAME(m_byteaddr) ); + if ( m_page_size > 0 ) + { + save_item( NAME(m_page) ); + } +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void i2cmem_device::device_reset() +{ +} + + +//------------------------------------------------- +// memory_space_config - return a description of +// any address spaces owned by this device +//------------------------------------------------- + +const address_space_config *i2cmem_device::memory_space_config( address_spacenum spacenum ) const +{ + return ( spacenum == 0 ) ? &m_space_config : NULL; +} + + +//------------------------------------------------- +// nvram_default - called to initialize NVRAM to +// its default state +//------------------------------------------------- + +void i2cmem_device::nvram_default() +{ + int i2cmem_bytes = m_data_size; + + UINT16 default_value = 0xff; + for( offs_t offs = 0; offs < i2cmem_bytes; offs++ ) + { + m_addrspace[ 0 ]->write_byte( offs, default_value ); + } + + /* populate from a memory region if present */ + if( m_region != NULL ) + { + if( m_region->bytes() != i2cmem_bytes ) + { + fatalerror( "i2cmem region '%s' wrong size (expected size = 0x%X)\n", tag(), i2cmem_bytes ); + } + + if( m_region->bytewidth() != 1 ) + { + fatalerror( "i2cmem region '%s' needs to be an 8-bit region\n", tag() ); + } + + UINT8 *default_data = m_region->base(); + for( offs_t offs = 0; offs < i2cmem_bytes; offs++ ) + m_addrspace[ 0 ]->write_byte( offs, default_data[offs] ); + } +} + + +//------------------------------------------------- +// nvram_read - called to read NVRAM from the +// .nv file +//------------------------------------------------- + +void i2cmem_device::nvram_read( emu_file &file ) +{ + int i2cmem_bytes = m_data_size; + dynamic_buffer buffer ( i2cmem_bytes ); + + file.read( &buffer[0], i2cmem_bytes ); + + for( offs_t offs = 0; offs < i2cmem_bytes; offs++ ) + { + m_addrspace[ 0 ]->write_byte( offs, buffer[ offs ] ); + } +} + +//------------------------------------------------- +// nvram_write - called to write NVRAM to the +// .nv file +//------------------------------------------------- + +void i2cmem_device::nvram_write( emu_file &file ) +{ + int i2cmem_bytes = m_data_size; + dynamic_buffer buffer ( i2cmem_bytes ); + + for( offs_t offs = 0; offs < i2cmem_bytes; offs++ ) + { + buffer[ offs ] = m_addrspace[ 0 ]->read_byte( offs ); + } + + file.write( &buffer[0], i2cmem_bytes ); +} + + + +//************************************************************************** +// READ/WRITE HANDLERS +//************************************************************************** + +WRITE_LINE_MEMBER( i2cmem_device::write_e0 ) +{ + state &= 1; + if( m_e0 != state ) + { + verboselog( this, 2, "set e0 %d\n", state ); + m_e0 = state; + } +} + + +WRITE_LINE_MEMBER( i2cmem_device::write_e1 ) +{ + state &= 1; + if( m_e1 != state ) + { + verboselog( this, 2, "set e1 %d\n", state ); + m_e1 = state; + } +} + + +WRITE_LINE_MEMBER( i2cmem_device::write_e2 ) +{ + state &= 1; + if( m_e2 != state ) + { + verboselog( this, 2, "set e2 %d\n", state ); + m_e2 = state; + } +} + + +WRITE_LINE_MEMBER( i2cmem_device::write_sda ) +{ + state &= 1; + if( m_sdaw != state ) + { + verboselog( this, 2, "set sda %d\n", state ); + m_sdaw = state; + + if( m_scl ) + { + if( m_sdaw ) + { + verboselog( this, 1, "stop\n" ); + m_state = STATE_IDLE; + } + else + { + verboselog( this, 2, "start\n" ); + m_state = STATE_DEVSEL; + m_bits = 0; + } + + m_sdar = 1; + } + } +} + +WRITE_LINE_MEMBER( i2cmem_device::write_scl ) +{ + if( m_scl != state ) + { + m_scl = state; + verboselog( this, 2, "set_scl_line %d\n", m_scl ); + + switch( m_state ) + { + case STATE_DEVSEL: + case STATE_BYTEADDR: + case STATE_DATAIN: + if( m_bits < 8 ) + { + if( m_scl ) + { + m_shift = ( ( m_shift << 1 ) | m_sdaw ) & 0xff; + m_bits++; + } + } + else + { + if( m_scl ) + { + switch( m_state ) + { + case STATE_DEVSEL: + m_devsel = m_shift; + + if( !select_device() ) + { + verboselog( this, 1, "devsel %02x: not this device\n", m_devsel ); + m_state = STATE_IDLE; + } + else if( ( m_devsel & DEVSEL_RW ) == 0 ) + { + verboselog( this, 1, "devsel %02x: write\n", m_devsel ); + m_state = STATE_BYTEADDR; + } + else + { + verboselog( this, 1, "devsel %02x: read\n", m_devsel ); + m_state = STATE_DATAOUT; + } + break; + + case STATE_BYTEADDR: + m_byteaddr = m_shift; + m_page_offset = 0; + + verboselog( this, 1, "byteaddr %02x\n", m_byteaddr ); + + m_state = STATE_DATAIN; + break; + + case STATE_DATAIN: + if( m_wc ) + { + verboselog( this, 0, "write not enabled\n" ); + m_state = STATE_IDLE; + } + else if( m_page_size > 0 ) + { + m_page[ m_page_offset ] = m_shift; + verboselog( this, 1, "page[ %04x ] <- %02x\n", m_page_offset, m_page[ m_page_offset ] ); + + m_page_offset++; + if( m_page_offset == m_page_size ) + { + int offset = data_offset() & ~( m_page_size - 1 ); + + verboselog( this, 1, "data[ %04x to %04x ] = page\n", offset, offset + m_page_size - 1 ); + + for( int i = 0; i < m_page_size; i++ ) + { + m_addrspace[ 0 ]->write_byte( offset + i, m_page[ i ] ); + } + + m_page_offset = 0; + } + } + else + { + int offset = data_offset(); + + verboselog( this, 1, "data[ %04x ] <- %02x\n", offset, m_shift ); + m_addrspace[ 0 ]->write_byte( offset, m_shift ); + + m_byteaddr++; + } + break; + } + + m_bits++; + } + else + { + if( m_bits == 8 ) + { + m_sdar = 0; + } + else + { + m_bits = 0; + m_sdar = 1; + } + } + } + break; + + case STATE_DATAOUT: + if( m_bits < 8 ) + { + if( m_scl ) + { + if( m_bits == 0 ) + { + int offset = data_offset(); + + m_shift = m_addrspace[ 0 ]->read_byte( offset ); + verboselog( this, 1, "data[ %04x ] -> %02x\n", offset, m_shift ); + m_byteaddr++; + } + + m_sdar = ( m_shift >> 7 ) & 1; + + m_shift = ( m_shift << 1 ) & 0xff; + m_bits++; + } + } + else + { + if( m_scl ) + { + if( m_sdaw ) + { + verboselog( this, 1, "sleep\n" ); + m_state = STATE_IDLE; + m_sdar = 0; + } + + m_bits++; + } + else + { + if( m_bits == 8 ) + { + m_sdar = 1; + } + else + { + m_bits = 0; + } + } + } + break; + } + } +} + + +WRITE_LINE_MEMBER( i2cmem_device::write_wc ) +{ + state &= 1; + if( m_wc != state ) + { + verboselog( this, 2, "set wc %d\n", state ); + m_wc = state; + } +} + + +READ_LINE_MEMBER( i2cmem_device::read_sda ) +{ + int res = m_sdar & 1; + + verboselog( this, 2, "read sda %d\n", res ); + + return res; +} + + +//************************************************************************** +// INTERNAL HELPERS +//************************************************************************** + +int i2cmem_device::address_mask() +{ + return (m_data_size - 1); +} + +int i2cmem_device::select_device() +{ + int device = ( m_slave_address & 0xf0 ) | ( m_e2 << 3 ) | ( m_e1 << 2 ) | ( m_e0 << 1 ); + int mask = DEVSEL_ADDRESS & ~( address_mask() >> 7 ); + + if( ( m_devsel & mask ) == ( device & mask ) ) + { + return 1; + } + + return 0; +} + +int i2cmem_device::data_offset() +{ + return ( ( ( m_devsel << 7 ) & 0xff00 ) | ( m_byteaddr & 0xff ) ) & address_mask(); +} diff --git a/src/devices/machine/i2cmem.h b/src/devices/machine/i2cmem.h new file mode 100644 index 00000000000..ce1bbdb3141 --- /dev/null +++ b/src/devices/machine/i2cmem.h @@ -0,0 +1,158 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/*************************************************************************** + + i2cmem.h + + I2C Memory + +***************************************************************************/ + +#pragma once + +#ifndef __I2CMEM_H__ +#define __I2CMEM_H__ + + +/*************************************************************************** + CONSTANTS +***************************************************************************/ + +#define I2CMEM_SLAVE_ADDRESS ( 0xa0 ) +#define I2CMEM_SLAVE_ADDRESS_ALT ( 0xb0 ) + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_I2CMEM_ADD( _tag ) \ + MCFG_DEVICE_ADD( _tag, I2CMEM, 0 ) + +#define MCFG_I2CMEM_ADDRESS( address ) \ + i2cmem_device::set_address(*device, address); +#define MCFG_I2CMEM_PAGE_SIZE( page_size ) \ + i2cmem_device::set_page_size(*device, page_size); +#define MCFG_I2CMEM_DATA_SIZE(data_size) \ + i2cmem_device::set_data_size(*device, data_size); +#define MCFG_I2CMEM_E0(e0) \ + i2cmem_device::set_e0(*device, e0); +#define MCFG_I2CMEM_E1(e1) \ + i2cmem_device::set_e1(*device, e1); +#define MCFG_I2CMEM_E2(e2) \ + i2cmem_device::set_e2(*device, e2); +#define MCFG_I2CMEM_WC(wc) \ + i2cmem_device::set_wc(*device, wc); + +#define MCFG_X2404P_ADD( _tag ) \ + MCFG_I2CMEM_ADD( _tag ) \ + MCFG_I2CMEM_PAGE_SIZE(8) \ + MCFG_I2CMEM_DATA_SIZE(0x200) + +#define MCFG_24C01_ADD( _tag ) \ + MCFG_I2CMEM_ADD( _tag ) \ + MCFG_I2CMEM_PAGE_SIZE(4) \ + MCFG_I2CMEM_DATA_SIZE(0x80) + +#define MCFG_24C02_ADD( _tag ) \ + MCFG_I2CMEM_ADD( _tag ) \ + MCFG_I2CMEM_PAGE_SIZE(4) \ + MCFG_I2CMEM_DATA_SIZE(0x100) + +#define MCFG_24C08_ADD( _tag ) \ + MCFG_I2CMEM_ADD( _tag ) \ + MCFG_I2CMEM_DATA_SIZE(0x400) + +#define MCFG_24C16_ADD( _tag ) \ + MCFG_I2CMEM_ADD( _tag ) \ + MCFG_I2CMEM_PAGE_SIZE(8) \ + MCFG_I2CMEM_DATA_SIZE(0x800) + +#define MCFG_24C16A_ADD( _tag ) \ + MCFG_I2CMEM_ADD( _tag ) \ + MCFG_I2CMEM_DATA_SIZE(0x800) + +#define MCFG_24C64_ADD( _tag ) \ + MCFG_I2CMEM_ADD( _tag ) \ + MCFG_I2CMEM_PAGE_SIZE(8) \ + MCFG_I2CMEM_DATA_SIZE(0x2000) + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> i2cmem_device + +class i2cmem_device : + public device_t, + public device_memory_interface, + public device_nvram_interface +{ +public: + // construction/destruction + i2cmem_device( const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock ); + + static void set_address(device_t &device, int address) { downcast(device).m_slave_address = address; } + static void set_page_size(device_t &device, int page_size) { downcast(device).m_page_size = page_size; } + static void set_data_size(device_t &device, int data_size) { downcast(device).m_data_size = data_size; } + static void set_e0(device_t &device, int e0) { downcast(device).m_e0 = e0; } + static void set_e1(device_t &device, int e1) { downcast(device).m_e1 = e1; } + static void set_e2(device_t &device, int e2) { downcast(device).m_e2 = e2; } + static void set_wc(device_t &device, int wc) { downcast(device).m_wc = wc; } + + // I/O operations + DECLARE_WRITE_LINE_MEMBER( write_e0 ); + DECLARE_WRITE_LINE_MEMBER( write_e1 ); + DECLARE_WRITE_LINE_MEMBER( write_e2 ); + DECLARE_WRITE_LINE_MEMBER( write_sda ); + DECLARE_WRITE_LINE_MEMBER( write_scl ); + DECLARE_WRITE_LINE_MEMBER( write_wc ); + DECLARE_READ_LINE_MEMBER( read_sda ); + +protected: + // device-level overrides + virtual void device_config_complete(); + virtual void device_start(); + virtual void device_reset(); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config( address_spacenum spacenum = AS_0 ) const; + + // device_nvram_interface overrides + virtual void nvram_default(); + virtual void nvram_read( emu_file &file ); + virtual void nvram_write( emu_file &file ); + + // internal helpers + int address_mask(); + int select_device(); + int data_offset(); + + // device-specific configuration + address_space_config m_space_config; + + // internal state + int m_slave_address; + int m_page_size; + int m_data_size; + int m_scl; + int m_sdaw; + int m_e0; + int m_e1; + int m_e2; + int m_wc; + int m_sdar; + int m_state; + int m_bits; + int m_shift; + int m_devsel; + int m_byteaddr; + dynamic_buffer m_page; + int m_page_offset; +}; + + +// device type definition +extern const device_type I2CMEM; + +#endif /* __I2CMEM_H__ */ diff --git a/src/devices/machine/i6300esb.c b/src/devices/machine/i6300esb.c new file mode 100644 index 00000000000..ec7ca934d31 --- /dev/null +++ b/src/devices/machine/i6300esb.c @@ -0,0 +1,757 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +#include "i6300esb.h" + +const device_type I6300ESB_WATCHDOG = &device_creator; +const device_type I6300ESB_LPC = &device_creator; + +DEVICE_ADDRESS_MAP_START(map, 32, i6300esb_watchdog_device) +ADDRESS_MAP_END + +i6300esb_watchdog_device::i6300esb_watchdog_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : pci_device(mconfig, I6300ESB_WATCHDOG, "i6300ESB southbridge watchdog", tag, owner, clock, "i6300esb_watchdog", __FILE__) +{ +} + +void i6300esb_watchdog_device::device_start() +{ + pci_device::device_start(); + add_map(16, M_MEM, FUNC(i6300esb_watchdog_device::map)); +} + +void i6300esb_watchdog_device::device_reset() +{ + pci_device::device_reset(); + command = 0x000f; + command_mask = 0x0140; + status = 0x0280; +} + + +DEVICE_ADDRESS_MAP_START(config_map, 32, i6300esb_lpc_device) + AM_RANGE(0x40, 0x43) AM_READWRITE (pmbase_r, pmbase_w) + AM_RANGE(0x44, 0x47) AM_READWRITE8 (acpi_cntl_r, acpi_cntl_w, 0x000000ff) + AM_RANGE(0x4c, 0x4f) AM_READWRITE16(bios_cntl_r, bios_cntl_w, 0xffff0000) + AM_RANGE(0x54, 0x57) AM_READWRITE8 (tco_cntl_r, tco_cntl_w, 0x000000ff) + AM_RANGE(0x58, 0x5b) AM_READWRITE (gpio_base_r, gpio_base_w) + AM_RANGE(0x5c, 0x5f) AM_READWRITE8 (gpio_cntl_r, gpio_cntl_w, 0x000000ff) + AM_RANGE(0x60, 0x63) AM_READWRITE8 (pirq_rout_r, pirq_rout_w, 0xffffffff) + AM_RANGE(0x64, 0x67) AM_READWRITE8 (serirq_cntl_r, serirq_cntl_w, 0x000000ff) + AM_RANGE(0x68, 0x6b) AM_READWRITE8 (pirq2_rout_r, pirq2_rout_w, 0xffffffff) + AM_RANGE(0x88, 0x8b) AM_READWRITE8 (d31_err_cfg_r, d31_err_cfg_w, 0x000000ff) + AM_RANGE(0x88, 0x8b) AM_READWRITE8 (d31_err_sts_r, d31_err_sts_w, 0x00ff0000) + AM_RANGE(0x90, 0x93) AM_READWRITE16(pci_dma_cfg_r, pci_dma_cfg_w, 0x0000ffff) + AM_RANGE(0xa0, 0xa3) AM_READWRITE16(gen_pmcon_1_r, gen_pmcon_1_w, 0x0000ffff) + AM_RANGE(0xa0, 0xa3) AM_READWRITE8 (gen_pmcon_2_r, gen_pmcon_2_w, 0x00ff0000) + AM_RANGE(0xa4, 0xa7) AM_READWRITE8 (gen_pmcon_3_r, gen_pmcon_3_w, 0x000000ff) + AM_RANGE(0xac, 0xaf) AM_READWRITE (rst_cnt2_r, rst_cnt2_w) + AM_RANGE(0xb0, 0xb3) AM_READWRITE8 (apm_cnt_r, apm_cnt_w, 0x00ff0000) + AM_RANGE(0xb0, 0xb3) AM_READWRITE8 (apm_sts_r, apm_sts_w, 0xff000000) + AM_RANGE(0xb8, 0xbb) AM_READWRITE (gpi_rout_r, gpi_rout_w) + AM_RANGE(0xc0, 0xc3) AM_READWRITE8 (mon_fwd_en_r, mon_fwd_en_w, 0x000000ff) + AM_RANGE(0xc4, 0xcb) AM_READWRITE16(mon_trp_rng_r, mon_trp_rng_w, 0xffffffff) + AM_RANGE(0xcc, 0xcf) AM_READWRITE16(mon_trp_msk_r, mon_trp_msk_w, 0x0000ffff) + AM_RANGE(0xd0, 0xd3) AM_READWRITE (gen_cntl_r, gen_cntl_w) + AM_RANGE(0xd4, 0xd7) AM_READWRITE8 (gen_sta_r, gen_sta_w, 0x000000ff) + AM_RANGE(0xd4, 0xd7) AM_READWRITE8 (back_cntl_r, back_cntl_w, 0x0000ff00) + AM_RANGE(0xd8, 0xdb) AM_READWRITE8 (rtc_conf_r, rtc_conf_w, 0x000000ff) + AM_RANGE(0xe0, 0xe3) AM_READWRITE8 (lpc_if_com_range_r, lpc_if_com_range_w, 0x000000ff) + AM_RANGE(0xe0, 0xe3) AM_READWRITE8 (lpc_if_fdd_lpt_range_r, lpc_if_fdd_lpt_range_w, 0x0000ff00) + AM_RANGE(0xe0, 0xe3) AM_READWRITE8 (lpc_if_sound_range_r, lpc_if_sound_range_w, 0x00ff0000) + AM_RANGE(0xe0, 0xe3) AM_READWRITE8 (fwh_dec_en1_r, fwh_dec_en1_w, 0xff000000) + AM_RANGE(0xe4, 0xe7) AM_READWRITE16(gen1_dec_r, gen1_dec_w, 0x0000ffff) + AM_RANGE(0xe4, 0xe7) AM_READWRITE16(lpc_en_r, lpc_en_w, 0xffff0000) + AM_RANGE(0xe8, 0xeb) AM_READWRITE (fwh_sel1_r, fwh_sel1_w) + AM_RANGE(0xec, 0xef) AM_READWRITE16(gen2_dec_r, gen2_dec_w, 0x0000ffff) + AM_RANGE(0xec, 0xef) AM_READWRITE16(fwh_sel2_r, fwh_sel2_w, 0xffff0000) + AM_RANGE(0xf0, 0xf3) AM_READWRITE8 (fwh_dec_en2_r, fwh_dec_en2_w, 0x000000ff) + AM_RANGE(0xf0, 0xf3) AM_READWRITE16(func_dis_r, func_dis_w, 0xffff0000) + AM_RANGE(0xf4, 0xf7) AM_READWRITE (etr1_r, etr1_w) + AM_RANGE(0xf8, 0xfb) AM_READ (mfid_r) + AM_RANGE(0xfc, 0xff) AM_READWRITE (unk_fc_r, unk_fc_w) + + AM_INHERIT_FROM(pci_device::config_map) +ADDRESS_MAP_END + +DEVICE_ADDRESS_MAP_START(internal_io_map, 32, i6300esb_lpc_device) + if(lpc_en & 0x2000) { + AM_RANGE(0x004c, 0x004f) AM_READWRITE8(siu_config_port_r, siu_config_port_w, 0x00ff0000) + AM_RANGE(0x004c, 0x004f) AM_READWRITE8(siu_data_port_r, siu_data_port_w, 0xff000000) + } + + AM_RANGE(0x0060, 0x0063) AM_READWRITE8( nmi_sc_r, nmi_sc_w, 0x0000ff00) + + AM_RANGE(0x0080, 0x0083) AM_WRITE8( nop_w, 0x000000ff) // POST/non-existing, used for delays by the bios/os + AM_RANGE(0x00ec, 0x00ef) AM_WRITE8( nop_w, 0x0000ff00) // Non-existing, used for delays by the bios/os +ADDRESS_MAP_END + + +i6300esb_lpc_device::i6300esb_lpc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : pci_device(mconfig, I6300ESB_LPC, "i6300ESB southbridge ISA/LPC bridge", tag, owner, clock, "i6300esb_lpc", __FILE__), + acpi(*this, "acpi"), + rtc (*this, "rtc"), + pit (*this, "pit") +{ +} + +void i6300esb_lpc_device::device_start() +{ + pci_device::device_start(); +} + +void i6300esb_lpc_device::device_reset() +{ + pci_device::device_reset(); + tco_cntl = 0x00; + serirq_cntl = 0x10; + memset(pirq_rout, 0x80, sizeof(pirq_rout)); + d31_err_cfg = 0x00; + d31_err_sts = 0x00; + pci_dma_cfg = 0x0000; + func_dis = 0x0080; + etr1 = 0x00000000; + siu_config_port = 0; + siu_config_state = 0; + gen_pmcon_1 = 0; + gen_pmcon_2 = 0; + gen_pmcon_3 = 0; + rst_cnt2 = 0; + apm_cnt = 0; + apm_sts = 0; + gpi_rout = 0; + mon_fwd_en = 0; + memset(mon_trp_rng, 0, sizeof(mon_trp_rng)); + mon_trp_msk = 0; + nmi_sc = 0; + gen_sta = 0x00; +} + +void i6300esb_lpc_device::reset_all_mappings() +{ + pci_device::reset_all_mappings(); + + pmbase = 0; + acpi_cntl = 0; + gpio_base = 0; + gpio_cntl = 0x00; + back_cntl = 0x0f; + lpc_if_com_range = 0x00; + lpc_if_fdd_lpt_range = 0x00; + lpc_if_sound_range = 0x00; + fwh_dec_en1 = 0xff; + fwh_dec_en2 = 0x0f; + gen1_dec = 0x0000; + lpc_en = 0x0000; + fwh_sel1 = 0x00112233; + gen_cntl = 0x00000080; + rtc_conf = 0x00; +} + +READ32_MEMBER (i6300esb_lpc_device::pmbase_r) +{ + return pmbase | 1; +} + +WRITE32_MEMBER(i6300esb_lpc_device::pmbase_w) +{ + COMBINE_DATA(&pmbase); + pmbase &= 0x0000ff80; + logerror("%s: pmbase = %08x\n", tag(), pmbase); + remap_cb(); +} + +READ8_MEMBER (i6300esb_lpc_device::acpi_cntl_r) +{ + return acpi_cntl; +} + +WRITE8_MEMBER(i6300esb_lpc_device::acpi_cntl_w) +{ + acpi_cntl = data; + logerror("%s: acpi_cntl = %08x\n", tag(), acpi_cntl); + remap_cb(); +} + +READ16_MEMBER (i6300esb_lpc_device::bios_cntl_r) +{ + return pmbase | 1; +} + +WRITE16_MEMBER(i6300esb_lpc_device::bios_cntl_w) +{ + COMBINE_DATA(&bios_cntl); + logerror("%s: bios_cntl = %08x\n", tag(), bios_cntl); + remap_cb(); +} + +READ8_MEMBER (i6300esb_lpc_device::tco_cntl_r) +{ + return tco_cntl; +} + +WRITE8_MEMBER (i6300esb_lpc_device::tco_cntl_w) +{ + tco_cntl = data; + logerror("%s: tco_cntl = %02x\n", tag(), tco_cntl); +} + +READ32_MEMBER (i6300esb_lpc_device::gpio_base_r) +{ + return gpio_base | 1; +} + +WRITE32_MEMBER(i6300esb_lpc_device::gpio_base_w) +{ + COMBINE_DATA(&gpio_base); + gpio_base &= 0x0000ffc0; + logerror("%s: gpio_base = %08x\n", tag(), gpio_base); + remap_cb(); +} + +READ8_MEMBER (i6300esb_lpc_device::gpio_cntl_r) +{ + return gpio_cntl; +} + +WRITE8_MEMBER (i6300esb_lpc_device::gpio_cntl_w) +{ + gpio_cntl = data; + logerror("%s: gpio_cntl = %02x\n", tag(), gpio_cntl); + remap_cb(); +} + +READ8_MEMBER (i6300esb_lpc_device::pirq_rout_r) +{ + return pirq_rout[offset]; +} + +WRITE8_MEMBER (i6300esb_lpc_device::pirq_rout_w) +{ + pirq_rout[offset] = data; + logerror("%s: pirq_rout[%d] = %02x\n", tag(), offset, pirq_rout[offset]); +} + +READ8_MEMBER (i6300esb_lpc_device::serirq_cntl_r) +{ + return serirq_cntl; +} + +WRITE8_MEMBER (i6300esb_lpc_device::serirq_cntl_w) +{ + serirq_cntl = data; + logerror("%s: serirq_cntl = %02x\n", tag(), serirq_cntl); +} + +READ8_MEMBER (i6300esb_lpc_device::pirq2_rout_r) +{ + return pirq_rout_r(space, offset+4); +} + +WRITE8_MEMBER (i6300esb_lpc_device::pirq2_rout_w) +{ + pirq_rout_w(space, offset+4, data); +} + +READ8_MEMBER (i6300esb_lpc_device::d31_err_cfg_r) +{ + return d31_err_cfg; +} + +WRITE8_MEMBER (i6300esb_lpc_device::d31_err_cfg_w) +{ + d31_err_cfg = data; + logerror("%s: d31_err_cfg = %02x\n", tag(), d31_err_cfg); +} + +READ8_MEMBER (i6300esb_lpc_device::d31_err_sts_r) +{ + return d31_err_sts; +} + +WRITE8_MEMBER (i6300esb_lpc_device::d31_err_sts_w) +{ + d31_err_sts &= ~data; + logerror("%s: d31_err_sts = %02x\n", tag(), d31_err_sts); +} + +READ16_MEMBER (i6300esb_lpc_device::pci_dma_cfg_r) +{ + return pci_dma_cfg; +} + +WRITE16_MEMBER(i6300esb_lpc_device::pci_dma_cfg_w) +{ + COMBINE_DATA(&pci_dma_cfg); + logerror("%s: pci_dma_cfg = %04x\n", tag(), pci_dma_cfg); +} + +READ16_MEMBER (i6300esb_lpc_device::gen_pmcon_1_r) +{ + return gen_pmcon_1; +} + +WRITE16_MEMBER(i6300esb_lpc_device::gen_pmcon_1_w) +{ + COMBINE_DATA(&gen_pmcon_1); + logerror("%s: gen_pmcon_1 = %04x\n", tag(), gen_pmcon_1); +} + +READ8_MEMBER (i6300esb_lpc_device::gen_pmcon_2_r) +{ + return gen_pmcon_2; +} + +WRITE8_MEMBER (i6300esb_lpc_device::gen_pmcon_2_w) +{ + gen_pmcon_2 = data; + logerror("%s: gen_pmcon_2 = %02x\n", tag(), gen_pmcon_2); +} + +READ8_MEMBER (i6300esb_lpc_device::gen_pmcon_3_r) +{ + return gen_pmcon_3; +} + +WRITE8_MEMBER (i6300esb_lpc_device::gen_pmcon_3_w) +{ + gen_pmcon_3 = data; + logerror("%s: gen_pmcon_3 = %02x\n", tag(), gen_pmcon_3); +} + +READ32_MEMBER (i6300esb_lpc_device::rst_cnt2_r) +{ + return rst_cnt2; +} + +WRITE32_MEMBER(i6300esb_lpc_device::rst_cnt2_w) +{ + COMBINE_DATA(&rst_cnt2); + logerror("%s: rst_cnt2 = %08x\n", tag(), rst_cnt2); +} + +READ8_MEMBER (i6300esb_lpc_device::apm_cnt_r) +{ + return apm_cnt; +} + +WRITE8_MEMBER (i6300esb_lpc_device::apm_cnt_w) +{ + apm_cnt = data; + logerror("%s: apm_cnt = %02x\n", tag(), apm_cnt); +} + +READ8_MEMBER (i6300esb_lpc_device::apm_sts_r) +{ + return apm_sts; +} + +WRITE8_MEMBER (i6300esb_lpc_device::apm_sts_w) +{ + apm_sts = data; + logerror("%s: apm_sts = %02x\n", tag(), apm_sts); +} + +READ32_MEMBER (i6300esb_lpc_device::gpi_rout_r) +{ + return gpi_rout; +} + +WRITE32_MEMBER(i6300esb_lpc_device::gpi_rout_w) +{ + COMBINE_DATA(&gpi_rout); + logerror("%s: gpi_rout = %08x\n", tag(), gpi_rout); +} + +READ8_MEMBER (i6300esb_lpc_device::mon_fwd_en_r) +{ + return mon_fwd_en; +} + +WRITE8_MEMBER (i6300esb_lpc_device::mon_fwd_en_w) +{ + mon_fwd_en = data; + logerror("%s: mon_fwd_en = %02x\n", tag(), mon_fwd_en); +} + +READ16_MEMBER (i6300esb_lpc_device::mon_trp_rng_r) +{ + return mon_trp_rng[offset]; +} + +WRITE16_MEMBER(i6300esb_lpc_device::mon_trp_rng_w) +{ + COMBINE_DATA(&mon_trp_rng[offset]); + logerror("%s: mon_trp_rng[%d] = %04x\n", tag(), 4+offset, mon_trp_rng[offset]); +} + +READ16_MEMBER (i6300esb_lpc_device::mon_trp_msk_r) +{ + return mon_trp_msk; +} + +WRITE16_MEMBER(i6300esb_lpc_device::mon_trp_msk_w) +{ + COMBINE_DATA(&mon_trp_msk); + logerror("%s: mon_trp_msk = %04x\n", tag(), mon_trp_msk); +} + +READ32_MEMBER (i6300esb_lpc_device::gen_cntl_r) +{ + return gen_cntl; +} + +WRITE32_MEMBER(i6300esb_lpc_device::gen_cntl_w) +{ + COMBINE_DATA(&gen_cntl); + logerror("%s: gen_cntl = %08x\n", tag(), gen_cntl); +} + +READ8_MEMBER (i6300esb_lpc_device::gen_sta_r) +{ + return gen_sta; +} + +WRITE8_MEMBER (i6300esb_lpc_device::gen_sta_w) +{ + gen_sta = data; + logerror("%s: gen_sta = %02x\n", tag(), gen_sta); +} + +READ8_MEMBER (i6300esb_lpc_device::back_cntl_r) +{ + return back_cntl; +} + +WRITE8_MEMBER (i6300esb_lpc_device::back_cntl_w) +{ + back_cntl = data; + logerror("%s: back_cntl = %02x\n", tag(), back_cntl); + remap_cb(); +} + +READ8_MEMBER (i6300esb_lpc_device::rtc_conf_r) +{ + return rtc_conf; +} + +WRITE8_MEMBER (i6300esb_lpc_device::rtc_conf_w) +{ + rtc_conf = data; + logerror("%s: rtc_conf = %02x\n", tag(), rtc_conf); + remap_cb(); +} + +READ8_MEMBER (i6300esb_lpc_device::lpc_if_com_range_r) +{ + return lpc_if_com_range; +} + +WRITE8_MEMBER (i6300esb_lpc_device::lpc_if_com_range_w) +{ + lpc_if_com_range = data; + logerror("%s: lpc_if_com_range = %02x\n", tag(), lpc_if_com_range); + remap_cb(); +} + +READ8_MEMBER (i6300esb_lpc_device::lpc_if_fdd_lpt_range_r) +{ + return lpc_if_fdd_lpt_range; +} + +WRITE8_MEMBER (i6300esb_lpc_device::lpc_if_fdd_lpt_range_w) +{ + COMBINE_DATA(&lpc_if_fdd_lpt_range); + logerror("%s: lpc_if_fdd_lpt_range = %02x\n", tag(), lpc_if_fdd_lpt_range); + remap_cb(); +} + +READ8_MEMBER (i6300esb_lpc_device::lpc_if_sound_range_r) +{ + return lpc_if_sound_range; +} + +WRITE8_MEMBER (i6300esb_lpc_device::lpc_if_sound_range_w) +{ + COMBINE_DATA(&lpc_if_sound_range); + logerror("%s: lpc_if_sound_range = %02x\n", tag(), lpc_if_sound_range); + remap_cb(); +} + +READ8_MEMBER (i6300esb_lpc_device::fwh_dec_en1_r) +{ + return fwh_dec_en1; +} + +WRITE8_MEMBER (i6300esb_lpc_device::fwh_dec_en1_w) +{ + fwh_dec_en1 = data | 0x80; + logerror("%s: fwh_dec_en1 = %02x\n", tag(), fwh_dec_en1); + remap_cb(); +} + +READ16_MEMBER (i6300esb_lpc_device::gen1_dec_r) +{ + return gen1_dec; +} + +WRITE16_MEMBER(i6300esb_lpc_device::gen1_dec_w) +{ + COMBINE_DATA(&gen1_dec); + logerror("%s: gen1_dec = %04x\n", tag(), gen1_dec); + remap_cb(); +} + +READ16_MEMBER (i6300esb_lpc_device::lpc_en_r) +{ + return lpc_en; +} + +WRITE16_MEMBER(i6300esb_lpc_device::lpc_en_w) +{ + COMBINE_DATA(&lpc_en); + logerror("%s: lpc_en = %04x\n", tag(), lpc_en); + remap_cb(); +} + +READ32_MEMBER (i6300esb_lpc_device::fwh_sel1_r) +{ + return fwh_sel1; +} + +WRITE32_MEMBER(i6300esb_lpc_device::fwh_sel1_w) +{ + COMBINE_DATA(&fwh_sel1); + logerror("%s: fwh_sel1 = %08x\n", tag(), fwh_sel1); + remap_cb(); +} + +READ16_MEMBER (i6300esb_lpc_device::gen2_dec_r) +{ + return gen2_dec; +} + +WRITE16_MEMBER(i6300esb_lpc_device::gen2_dec_w) +{ + COMBINE_DATA(&gen2_dec); + logerror("%s: gen2_dec = %04x\n", tag(), gen2_dec); + remap_cb(); +} + +READ16_MEMBER (i6300esb_lpc_device::fwh_sel2_r) +{ + return fwh_sel2; +} + +WRITE16_MEMBER(i6300esb_lpc_device::fwh_sel2_w) +{ + COMBINE_DATA(&fwh_sel2); + logerror("%s: fwh_sel2 = %04x\n", tag(), fwh_sel2); + remap_cb(); +} + +READ8_MEMBER (i6300esb_lpc_device::fwh_dec_en2_r) +{ + return fwh_dec_en2; +} + +WRITE8_MEMBER (i6300esb_lpc_device::fwh_dec_en2_w) +{ + fwh_dec_en2 = data; + logerror("%s: fwh_dec_en2 = %02x\n", tag(), fwh_dec_en2); + remap_cb(); +} + +READ16_MEMBER (i6300esb_lpc_device::func_dis_r) +{ + return func_dis; +} + +WRITE16_MEMBER(i6300esb_lpc_device::func_dis_w) +{ + COMBINE_DATA(&func_dis); + logerror("%s: func_dis = %04x\n", tag(), func_dis); +} + +READ32_MEMBER (i6300esb_lpc_device::etr1_r) +{ + return etr1; +} + +WRITE32_MEMBER(i6300esb_lpc_device::etr1_w) +{ + COMBINE_DATA(&etr1); + logerror("%s: etr1 = %08x\n", tag(), etr1); +} + +READ32_MEMBER (i6300esb_lpc_device::mfid_r) +{ + return 0xf66; +} + +READ32_MEMBER (i6300esb_lpc_device::unk_fc_r) +{ + logerror("%s: read undocumented config reg fc\n", tag()); + return 0; +} + +WRITE32_MEMBER(i6300esb_lpc_device::unk_fc_w) +{ + logerror("%s: write undocumented config reg fc (%08x)\n", tag(), data); +} + + + +READ8_MEMBER (i6300esb_lpc_device::siu_config_port_r) +{ + return siu_config_port; +} + +WRITE8_MEMBER (i6300esb_lpc_device::siu_config_port_w) +{ + siu_config_port = data; + switch(siu_config_state) { + case 0: + siu_config_state = data == 0x80 ? 1 : 0; + break; + case 1: + siu_config_state = data == 0x86 ? 2 : data == 0x80 ? 1 : 0; + if(siu_config_state == 2) + logerror("%s: siu configuration active\n", tag()); + break; + case 2: + siu_config_state = data == 0x68 ? 3 : 2; + break; + case 3: + siu_config_state = data == 0x08 ? 0 : data == 0x68 ? 3 : 2; + if(!siu_config_state) + logerror("%s: siu configuration disabled\n", tag()); + break; + } +} + +READ8_MEMBER (i6300esb_lpc_device::siu_data_port_r) +{ + logerror("%s: siu config read port %02x\n", tag(), siu_config_port); + return 0xff; +} + +WRITE8_MEMBER (i6300esb_lpc_device::siu_data_port_w) +{ + if(siu_config_state < 2) { + logerror("%s: siu config write port with config disabled (port=%02x, data=%02x)\n", tag(), siu_config_port, data); + return; + } + logerror("%s: siu config write port %02x, %02x\n", tag(), siu_config_port, data); +} + +READ8_MEMBER (i6300esb_lpc_device::nmi_sc_r) +{ + nmi_sc ^= 0x10; + return nmi_sc; +} + +WRITE8_MEMBER (i6300esb_lpc_device::nmi_sc_w) +{ + nmi_sc = data; + logerror("%s: nmi_sc = %02x\n", tag(), nmi_sc); +} + + +WRITE8_MEMBER (i6300esb_lpc_device::nop_w) +{ +} + +void i6300esb_lpc_device::map_bios(address_space *memory_space, UINT32 start, UINT32 end, int idsel) +{ + // Ignore idsel, a16 inversion for now + UINT32 mask = m_region->bytes() - 1; + memory_space->install_rom(start, end, m_region->base() + (start & mask)); +} + +void i6300esb_lpc_device::map_extra(UINT64 memory_window_start, UINT64 memory_window_end, UINT64 memory_offset, address_space *memory_space, + UINT64 io_window_start, UINT64 io_window_end, UINT64 io_offset, address_space *io_space) +{ + if(fwh_dec_en1 & 0x80) { + map_bios(memory_space, 0xfff80000, 0xffffffff, 7); + map_bios(memory_space, 0xffb80000, 0xffbfffff, 7); + map_bios(memory_space, 0x000e0000, 0x000fffff, 7); + } + if(fwh_dec_en1 & 0x40) { + map_bios(memory_space, 0xfff00000, 0xfff7ffff, 6); + map_bios(memory_space, 0xffb00000, 0xffb7ffff, 6); + } + if(fwh_dec_en1 & 0x20) { + map_bios(memory_space, 0xffe80000, 0xffefffff, 5); + map_bios(memory_space, 0xffa80000, 0xffafffff, 5); + } + if(fwh_dec_en1 & 0x10) { + map_bios(memory_space, 0xffe00000, 0xffe7ffff, 4); + map_bios(memory_space, 0xffa00000, 0xffa7ffff, 4); + } + if(fwh_dec_en1 & 0x08) { + map_bios(memory_space, 0xffd80000, 0xffdfffff, 3); + map_bios(memory_space, 0xff980000, 0xff9fffff, 3); + } + if(fwh_dec_en1 & 0x04) { + map_bios(memory_space, 0xffd00000, 0xffd7ffff, 2); + map_bios(memory_space, 0xff900000, 0xff97ffff, 2); + } + if(fwh_dec_en1 & 0x02) { + map_bios(memory_space, 0xffc80000, 0xffcfffff, 1); + map_bios(memory_space, 0xff880000, 0xff8fffff, 1); + } + if(fwh_dec_en1 & 0x01) { + map_bios(memory_space, 0xffc00000, 0xffc7ffff, 0); + map_bios(memory_space, 0xff800000, 0xff87ffff, 0); + } + + io_space->install_device(0, 0xffff, *this, &i6300esb_lpc_device::internal_io_map); + + if(acpi_cntl & 0x10) + acpi->map_device(memory_window_start, memory_window_end, 0, memory_space, io_window_start, io_window_end, pmbase, io_space); + if(gpio_cntl & 0x10) + logerror("%s: Warning: gpio range enabled at %04x-%04x\n", tag(), gpio_base, gpio_base+63); + + UINT32 hpet = 0xfed00000 + ((gen_cntl & 0x00018000) >> 3); + logerror("%s: Warning: hpet at %08x-%08x\n", tag(), hpet, hpet+0x3ff); + + if(lpc_en & 0x1000) + logerror("%s: Warning: superio at 2e-2f\n", tag()); + if(lpc_en & 0x0800) + logerror("%s: Warning: mcu at 62/66\n", tag()); + if(lpc_en & 0x0400) + logerror("%s: Warning: mcu at 60/64\n", tag()); + if(lpc_en & 0x0200) + logerror("%s: Warning: gameport at 208-20f\n", tag()); + if(lpc_en & 0x0100) + logerror("%s: Warning: gameport at 200-207\n", tag()); + + if(lpc_en & 0x0008) { + UINT16 fdc = lpc_if_fdd_lpt_range & 0x10 ? 0x370 : 0x3f0; + logerror("%s: Warning: floppy at %04x-%04x\n", tag(), fdc, fdc+7); + } + + if(lpc_en & 0x0004) { + static const UINT16 lpt_pos[4] = { 0x378, 0x278, 0x3bc, 0x000 }; + UINT16 lpt = lpt_pos[lpc_if_fdd_lpt_range & 3]; + if(lpt) + logerror("%s: Warning: lpt at %04x-%04x %04x-%04x\n", tag(), lpt, lpt+7, lpt+0x400, lpt+0x407); + } + + static const UINT16 com_pos[8] = { 0x3f8, 0x2f8, 0x220, 0x228, 0x238, 0x2e8, 0x338, 0x3e8 }; + + if(lpc_en & 0x0002) { + UINT16 comb = com_pos[(lpc_if_com_range >> 4) & 7]; + logerror("%s: Warning: comb at %04x-%04x\n", tag(), comb, comb+7); + } + + if(lpc_en & 0x0001) { + UINT16 coma = com_pos[lpc_if_com_range & 7]; + logerror("%s: Warning: coma at %04x-%04x\n", tag(), coma, coma+7); + } + + rtc->map_device(memory_window_start, memory_window_end, 0, memory_space, io_window_start, io_window_end, 0, io_space); + if(rtc_conf & 4) + rtc->map_extdevice(memory_window_start, memory_window_end, 0, memory_space, io_window_start, io_window_end, 0, io_space); + pit->map_device(memory_window_start, memory_window_end, 0, memory_space, io_window_start, io_window_end, 0, io_space); +} diff --git a/src/devices/machine/i6300esb.h b/src/devices/machine/i6300esb.h new file mode 100644 index 00000000000..2349db91b73 --- /dev/null +++ b/src/devices/machine/i6300esb.h @@ -0,0 +1,160 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +// Intel i6300ESB southbridge + +#ifndef I6300ESB_H +#define I6300ESB_H + +#include "pci.h" +#include "lpc-acpi.h" +#include "lpc-rtc.h" +#include "lpc-pit.h" + +#define MCFG_I6300ESB_LPC_ADD(_tag) \ + MCFG_PCI_DEVICE_ADD(_tag, I6300ESB_LPC, 0x808625a1, 0x02, 0x060100, 0x00000000) + +#define MCFG_I6300ESB_WATCHDOG_ADD(_tag, _subdevice_id) \ + MCFG_PCI_DEVICE_ADD(_tag, I6300ESB_WATCHDOG, 0x808625ab, 0x02, 0x088000, _subdevice_id) + +class i6300esb_lpc_device : public pci_device { +public: + i6300esb_lpc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual void reset_all_mappings(); + virtual void map_extra(UINT64 memory_window_start, UINT64 memory_window_end, UINT64 memory_offset, address_space *memory_space, + UINT64 io_window_start, UINT64 io_window_end, UINT64 io_offset, address_space *io_space); + + virtual DECLARE_ADDRESS_MAP(config_map, 32); + + +protected: + virtual void device_start(); + virtual void device_reset(); + +private: + required_device acpi; + required_device rtc; + required_device pit; + + DECLARE_ADDRESS_MAP(internal_io_map, 32); + + UINT32 pmbase, gpio_base, fwh_sel1, gen_cntl, etr1, rst_cnt2, gpi_rout; + UINT16 bios_cntl, pci_dma_cfg, gen1_dec, lpc_en, gen2_dec, fwh_sel2, func_dis, gen_pmcon_1; + UINT16 mon_trp_rng[4], mon_trp_msk; + UINT8 pirq_rout[8]; + UINT8 acpi_cntl, tco_cntl, gpio_cntl, serirq_cntl, d31_err_cfg, d31_err_sts, gen_sta, back_cntl, rtc_conf; + UINT8 lpc_if_com_range, lpc_if_fdd_lpt_range, lpc_if_sound_range, fwh_dec_en1, fwh_dec_en2, siu_config_port; + UINT8 gen_pmcon_2, gen_pmcon_3, apm_cnt, apm_sts, mon_fwd_en, nmi_sc; + int siu_config_state; + + DECLARE_WRITE8_MEMBER (nop_w); + + // configuration space registers + DECLARE_READ32_MEMBER (pmbase_r); // 40 + DECLARE_WRITE32_MEMBER(pmbase_w); + DECLARE_READ8_MEMBER (acpi_cntl_r); // 44 + DECLARE_WRITE8_MEMBER (acpi_cntl_w); + DECLARE_READ16_MEMBER (bios_cntl_r); // 4e + DECLARE_WRITE16_MEMBER(bios_cntl_w); + DECLARE_READ8_MEMBER (tco_cntl_r); // 54 + DECLARE_WRITE8_MEMBER (tco_cntl_w); + DECLARE_READ32_MEMBER (gpio_base_r); // 58 + DECLARE_WRITE32_MEMBER(gpio_base_w); + DECLARE_READ8_MEMBER (gpio_cntl_r); // 5c + DECLARE_WRITE8_MEMBER (gpio_cntl_w); + DECLARE_READ8_MEMBER (pirq_rout_r); // 60-63 + DECLARE_WRITE8_MEMBER (pirq_rout_w); + DECLARE_READ8_MEMBER (serirq_cntl_r); // 64 + DECLARE_WRITE8_MEMBER (serirq_cntl_w); + DECLARE_READ8_MEMBER (pirq2_rout_r); // 68-6b + DECLARE_WRITE8_MEMBER (pirq2_rout_w); + DECLARE_READ8_MEMBER (d31_err_cfg_r); // 88 + DECLARE_WRITE8_MEMBER (d31_err_cfg_w); + DECLARE_READ8_MEMBER (d31_err_sts_r); // 8a + DECLARE_WRITE8_MEMBER (d31_err_sts_w); + DECLARE_READ16_MEMBER (pci_dma_cfg_r); // 90 + DECLARE_WRITE16_MEMBER(pci_dma_cfg_w); + DECLARE_READ16_MEMBER (gen_pmcon_1_r); // a0 + DECLARE_WRITE16_MEMBER(gen_pmcon_1_w); + DECLARE_READ8_MEMBER (gen_pmcon_2_r); // a2 + DECLARE_WRITE8_MEMBER(gen_pmcon_2_w); + DECLARE_READ8_MEMBER (gen_pmcon_3_r); // a4 + DECLARE_WRITE8_MEMBER (gen_pmcon_3_w); + DECLARE_READ32_MEMBER (rst_cnt2_r); // ac + DECLARE_WRITE32_MEMBER(rst_cnt2_w); + DECLARE_READ8_MEMBER (apm_cnt_r); // b2 + DECLARE_WRITE8_MEMBER (apm_cnt_w); + DECLARE_READ8_MEMBER (apm_sts_r); // b3 + DECLARE_WRITE8_MEMBER (apm_sts_w); + DECLARE_READ32_MEMBER (gpi_rout_r); // b8 + DECLARE_WRITE32_MEMBER(gpi_rout_w); + DECLARE_READ8_MEMBER (mon_fwd_en_r); // c0 + DECLARE_WRITE8_MEMBER (mon_fwd_en_w); + DECLARE_READ16_MEMBER (mon_trp_rng_r); // c4-ca + DECLARE_WRITE16_MEMBER(mon_trp_rng_w); + DECLARE_READ16_MEMBER (mon_trp_msk_r); // cc + DECLARE_WRITE16_MEMBER(mon_trp_msk_w); + DECLARE_READ32_MEMBER (gen_cntl_r); // d0 + DECLARE_WRITE32_MEMBER(gen_cntl_w); + DECLARE_READ8_MEMBER (gen_sta_r); // d4 + DECLARE_WRITE8_MEMBER (gen_sta_w); + DECLARE_READ8_MEMBER (back_cntl_r); // d5 + DECLARE_WRITE8_MEMBER (back_cntl_w); + DECLARE_READ8_MEMBER (rtc_conf_r); // d8 + DECLARE_WRITE8_MEMBER (rtc_conf_w); + DECLARE_READ8_MEMBER (lpc_if_com_range_r); // e0 + DECLARE_WRITE8_MEMBER (lpc_if_com_range_w); + DECLARE_READ8_MEMBER (lpc_if_fdd_lpt_range_r); // e1 + DECLARE_WRITE8_MEMBER (lpc_if_fdd_lpt_range_w); + DECLARE_READ8_MEMBER (lpc_if_sound_range_r); // e2 + DECLARE_WRITE8_MEMBER (lpc_if_sound_range_w); + DECLARE_READ8_MEMBER (fwh_dec_en1_r); // e3 + DECLARE_WRITE8_MEMBER (fwh_dec_en1_w); + DECLARE_READ16_MEMBER (gen1_dec_r); // e4 + DECLARE_WRITE16_MEMBER(gen1_dec_w); + DECLARE_READ16_MEMBER (lpc_en_r); // e6 + DECLARE_WRITE16_MEMBER(lpc_en_w); + DECLARE_READ32_MEMBER (fwh_sel1_r); // e8 + DECLARE_WRITE32_MEMBER(fwh_sel1_w); + DECLARE_READ16_MEMBER (gen2_dec_r); // ec + DECLARE_WRITE16_MEMBER(gen2_dec_w); + DECLARE_READ16_MEMBER (fwh_sel2_r); // ee + DECLARE_WRITE16_MEMBER(fwh_sel2_w); + DECLARE_READ8_MEMBER (fwh_dec_en2_r); // f0 + DECLARE_WRITE8_MEMBER (fwh_dec_en2_w); + DECLARE_READ16_MEMBER (func_dis_r); // f2 + DECLARE_WRITE16_MEMBER(func_dis_w); + DECLARE_READ32_MEMBER (etr1_r); // f4 + DECLARE_WRITE32_MEMBER(etr1_w); + DECLARE_READ32_MEMBER (mfid_r); // f8 + DECLARE_READ32_MEMBER (unk_fc_r); // fc + DECLARE_WRITE32_MEMBER(unk_fc_w); + + + // i/o space registers + DECLARE_READ8_MEMBER (siu_config_port_r); // 4e + DECLARE_WRITE8_MEMBER (siu_config_port_w); + DECLARE_READ8_MEMBER (siu_data_port_r); // 4f + DECLARE_WRITE8_MEMBER (siu_data_port_w); + DECLARE_READ8_MEMBER (nmi_sc_r); // 61 + DECLARE_WRITE8_MEMBER (nmi_sc_w); + + void map_bios(address_space *memory_space, UINT32 start, UINT32 end, int idsel); +}; + +class i6300esb_watchdog_device : public pci_device { +public: + i6300esb_watchdog_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual void device_start(); + virtual void device_reset(); + +private: + DECLARE_ADDRESS_MAP(map, 32); +}; + +extern const device_type I6300ESB_LPC; +extern const device_type I6300ESB_WATCHDOG; + +#endif diff --git a/src/devices/machine/i80130.c b/src/devices/machine/i80130.c new file mode 100644 index 00000000000..fb419a06090 --- /dev/null +++ b/src/devices/machine/i80130.c @@ -0,0 +1,173 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Intel 80130 iRMX Operating System Processor emulation + +**********************************************************************/ + +#include "i80130.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +// device type definition +const device_type I80130 = &device_creator; + + +DEVICE_ADDRESS_MAP_START( rom_map, 16, i80130_device ) + //AM_RANGE(0x0000, 0x3fff) AM_ROM AM_REGION("rom", 0) +ADDRESS_MAP_END + +DEVICE_ADDRESS_MAP_START( io_map, 16, i80130_device ) + AM_RANGE(0x00, 0x0f) AM_READWRITE(io_r, io_w) + //AM_RANGE(0x00, 0x01) AM_MIRROR(0x2) AM_DEVREADWRITE8("pic", pic8259_device, read, write, 0x00ff) + //AM_RANGE(0x08, 0x0f) AM_DEVREADWRITE8("pit", pit8254_device, read, write, 0x00ff) +ADDRESS_MAP_END + +READ16_MEMBER( i80130_device::io_r ) +{ + UINT16 data = 0; + + switch (offset) + { + case 0: case 1: + if (ACCESSING_BITS_0_7) + { + data = m_pic->read(space, offset & 0x01); + } + break; + + case 4: case 5: case 6: case 7: + if (ACCESSING_BITS_0_7) + { + data = m_pit->read(space, offset & 0x03); + } + break; + } + + return data; +} + +WRITE16_MEMBER( i80130_device::io_w ) +{ + switch (offset) + { + case 0: case 1: + if (ACCESSING_BITS_0_7) + { + m_pic->write(space, offset & 0x01, data & 0xff); + } + break; + + case 4: case 5: case 6: case 7: + if (ACCESSING_BITS_0_7) + { + m_pit->write(space, offset & 0x03, data & 0xff); + } + break; + } +} + + +//------------------------------------------------- +// ROM( i80130 ) +//------------------------------------------------- + +ROM_START( i80130 ) + ROM_REGION16_LE( 0x4000, "rom", 0 ) + ROM_LOAD( "80130", 0x0000, 0x4000, NO_DUMP ) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *i80130_device::device_rom_region() const +{ + return ROM_NAME( i80130 ); +} + + +//------------------------------------------------- +// MACHINE_CONFIG_FRAGMENT( i80130 ) +//------------------------------------------------- + +static MACHINE_CONFIG_FRAGMENT( i80130 ) + MCFG_PIC8259_ADD("pic", DEVWRITELINE(DEVICE_SELF, i80130_device, irq_w), VCC, NULL) + + MCFG_DEVICE_ADD("pit", PIT8254, 0) + MCFG_PIT8253_CLK0(0) + MCFG_PIT8253_OUT0_HANDLER(WRITELINE(i80130_device, systick_w)) + MCFG_PIT8253_CLK1(0) + MCFG_PIT8253_OUT1_HANDLER(WRITELINE(i80130_device, delay_w)) + MCFG_PIT8253_CLK2(0) + MCFG_PIT8253_OUT2_HANDLER(WRITELINE(i80130_device, baud_w)) +MACHINE_CONFIG_END + + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor i80130_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( i80130 ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// i80130_device - constructor +//------------------------------------------------- + +i80130_device::i80130_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, I80130, "I80130", tag, owner, clock, "i80130", __FILE__), + m_pic(*this, "pic"), + m_pit(*this, "pit"), + m_write_irq(*this), + m_write_ack(*this), + m_write_lir(*this), + m_write_systick(*this), + m_write_delay(*this), + m_write_baud(*this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void i80130_device::device_start() +{ + // resolve callbacks + m_write_irq.resolve_safe(); + m_write_ack.resolve_safe(); + m_write_lir.resolve_safe(); + m_write_systick.resolve_safe(); + m_write_delay.resolve_safe(); + m_write_baud.resolve_safe(); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void i80130_device::device_reset() +{ + // set PIT clocks + m_pit->set_clockin(0, clock()); + m_pit->set_clockin(1, clock()); + m_pit->set_clockin(2, clock()); +} diff --git a/src/devices/machine/i80130.h b/src/devices/machine/i80130.h new file mode 100644 index 00000000000..b7aaece8fe7 --- /dev/null +++ b/src/devices/machine/i80130.h @@ -0,0 +1,111 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Intel 80130 iRMX Operating System Processor emulation + +**********************************************************************/ + +#pragma once + +#ifndef __I80130__ +#define __I80130__ + +#include "emu.h" +#include "machine/pic8259.h" +#include "machine/pit8253.h" + + + +///************************************************************************* +// INTERFACE CONFIGURATION MACROS +///************************************************************************* + +#define MCFG_I80130_IRQ_CALLBACK(_write) \ + devcb = &i80130_device::set_irq_wr_callback(*device, DEVCB_##_write); + +#define MCFG_I80130_ACK_CALLBACK(_write) \ + devcb = &i80130_device::set_ack_wr_callback(*device, DEVCB_##_write); + +#define MCFG_I80130_LIR_CALLBACK(_write) \ + devcb = &i80130_device::set_lir_wr_callback(*device, DEVCB_##_write); + +#define MCFG_I80130_SYSTICK_CALLBACK(_write) \ + devcb = &i80130_device::set_systick_wr_callback(*device, DEVCB_##_write); + +#define MCFG_I80130_DELAY_CALLBACK(_write) \ + devcb = &i80130_device::set_delay_wr_callback(*device, DEVCB_##_write); + +#define MCFG_I80130_BAUD_CALLBACK(_write) \ + devcb = &i80130_device::set_baud_wr_callback(*device, DEVCB_##_write); + + + +///************************************************************************* +// TYPE DEFINITIONS +///************************************************************************* + +// ======================> i80130_device + +class i80130_device : public device_t +{ +public: + // construction/destruction + i80130_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + template static devcb_base &set_irq_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_irq.set_callback(object); } + template static devcb_base &set_ack_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_ack.set_callback(object); } + template static devcb_base &set_lir_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_lir.set_callback(object); } + template static devcb_base &set_systick_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_systick.set_callback(object); } + template static devcb_base &set_delay_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_delay.set_callback(object); } + template static devcb_base &set_baud_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_baud.set_callback(object); } + + virtual DECLARE_ADDRESS_MAP(rom_map, 16); + virtual DECLARE_ADDRESS_MAP(io_map, 16); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + + UINT8 inta_r() { return m_pic->acknowledge(); } + + DECLARE_WRITE_LINE_MEMBER( ir0_w ) { m_pic->ir0_w(state); } + DECLARE_WRITE_LINE_MEMBER( ir1_w ) { m_pic->ir1_w(state); } + DECLARE_WRITE_LINE_MEMBER( ir2_w ) { m_pic->ir2_w(state); } + DECLARE_WRITE_LINE_MEMBER( ir3_w ) { m_pic->ir3_w(state); } + DECLARE_WRITE_LINE_MEMBER( ir4_w ) { m_pic->ir4_w(state); } + DECLARE_WRITE_LINE_MEMBER( ir5_w ) { m_pic->ir5_w(state); } + DECLARE_WRITE_LINE_MEMBER( ir6_w ) { m_pic->ir6_w(state); } + DECLARE_WRITE_LINE_MEMBER( ir7_w ) { m_pic->ir7_w(state); } + + DECLARE_WRITE_LINE_MEMBER( irq_w ) { m_write_irq(state); } + DECLARE_WRITE_LINE_MEMBER( systick_w ) { m_write_systick(state); } + DECLARE_WRITE_LINE_MEMBER( delay_w ) { m_write_delay(state); } + DECLARE_WRITE_LINE_MEMBER( baud_w ) { m_write_baud(state); } + + DECLARE_READ16_MEMBER( io_r ); + DECLARE_WRITE16_MEMBER( io_w ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + required_device m_pic; + required_device m_pit; + + devcb_write_line m_write_irq; + devcb_write_line m_write_ack; + devcb_write_line m_write_lir; + devcb_write_line m_write_systick; + devcb_write_line m_write_delay; + devcb_write_line m_write_baud; +}; + + +// device type definition +extern const device_type I80130; + + + +#endif diff --git a/src/devices/machine/i8155.c b/src/devices/machine/i8155.c new file mode 100644 index 00000000000..a2914b9081f --- /dev/null +++ b/src/devices/machine/i8155.c @@ -0,0 +1,593 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Intel 8155/8156 - 2048-Bit Static MOS RAM with I/O Ports and Timer emulation + +**********************************************************************/ + +/* + + TODO: + + - strobed mode + +*/ + +#include "emu.h" +#include "i8155.h" + + +// device type definitions +const device_type I8155 = &device_creator; +const device_type I8156 = &device_creator; + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define LOG 0 + +enum +{ + REGISTER_COMMAND = 0, + REGISTER_STATUS = 0, + REGISTER_PORT_A, + REGISTER_PORT_B, + REGISTER_PORT_C, + REGISTER_TIMER_LOW, + REGISTER_TIMER_HIGH +}; + +enum +{ + PORT_A = 0, + PORT_B, + PORT_C, + PORT_COUNT +}; + +enum +{ + PORT_MODE_INPUT = 0, + PORT_MODE_OUTPUT, + PORT_MODE_STROBED_PORT_A, // not supported + PORT_MODE_STROBED // not supported +}; + +enum +{ + MEMORY = 0, + IO +}; + +#define COMMAND_PA 0x01 +#define COMMAND_PB 0x02 +#define COMMAND_PC_MASK 0x0c +#define COMMAND_PC_ALT_1 0x00 +#define COMMAND_PC_ALT_2 0x0c +#define COMMAND_PC_ALT_3 0x04 // not supported +#define COMMAND_PC_ALT_4 0x08 // not supported +#define COMMAND_IEA 0x10 // not supported +#define COMMAND_IEB 0x20 // not supported +#define COMMAND_TM_MASK 0xc0 +#define COMMAND_TM_NOP 0x00 +#define COMMAND_TM_STOP 0x40 +#define COMMAND_TM_STOP_AFTER_TC 0x80 +#define COMMAND_TM_START 0xc0 + +#define STATUS_INTR_A 0x01 // not supported +#define STATUS_A_BF 0x02 // not supported +#define STATUS_INTE_A 0x04 // not supported +#define STATUS_INTR_B 0x08 // not supported +#define STATUS_B_BF 0x10 // not supported +#define STATUS_INTE_B 0x20 // not supported +#define STATUS_TIMER 0x40 + +#define TIMER_MODE_MASK 0xc0 +#define TIMER_MODE_LOW 0x00 +#define TIMER_MODE_SQUARE_WAVE 0x40 +#define TIMER_MODE_SINGLE_PULSE 0x80 +#define TIMER_MODE_AUTOMATIC_RELOAD 0xc0 + + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +// default address map +static ADDRESS_MAP_START( i8155, AS_0, 8, i8155_device ) + AM_RANGE(0x00, 0xff) AM_RAM +ADDRESS_MAP_END + + + +//************************************************************************** +// INLINE HELPERS +//************************************************************************** + +inline UINT8 i8155_device::get_timer_mode() +{ + return (m_count_length >> 8) & TIMER_MODE_MASK; +} + +inline void i8155_device::timer_output() +{ + m_out_to_cb(m_to); + + if (LOG) logerror("8155 '%s' Timer Output: %u\n", tag(), m_to); +} + +inline void i8155_device::pulse_timer_output() +{ + m_to = 0; timer_output(); + m_to = 1; timer_output(); +} + +inline int i8155_device::get_port_mode(int port) +{ + int mode = -1; + + switch (port) + { + case PORT_A: + mode = (m_command & COMMAND_PA) ? PORT_MODE_OUTPUT : PORT_MODE_INPUT; + break; + + case PORT_B: + mode = (m_command & COMMAND_PB) ? PORT_MODE_OUTPUT : PORT_MODE_INPUT; + break; + + case PORT_C: + switch (m_command & COMMAND_PC_MASK) + { + case COMMAND_PC_ALT_1: mode = PORT_MODE_INPUT; break; + case COMMAND_PC_ALT_2: mode = PORT_MODE_OUTPUT; break; + case COMMAND_PC_ALT_3: mode = PORT_MODE_STROBED_PORT_A; break; + case COMMAND_PC_ALT_4: mode = PORT_MODE_STROBED; break; + } + break; + } + + return mode; +} + +inline UINT8 i8155_device::read_port(int port) +{ + UINT8 data = 0; + + switch (get_port_mode(port)) + { + case PORT_MODE_INPUT: + data = (port == PORT_A) ? m_in_pa_cb(0) : ((port == PORT_B) ? m_in_pb_cb(0) : m_in_pc_cb(0)); + break; + + case PORT_MODE_OUTPUT: + data = m_output[port]; + break; + + default: + // strobed mode not implemented yet + logerror("8155 '%s' Unsupported Port C mode!\n", tag()); + break; + } + + return data; +} + +inline void i8155_device::write_port(int port, UINT8 data) +{ + switch (get_port_mode(port)) + { + case PORT_MODE_OUTPUT: + m_output[port] = data; + if (port == PORT_A) + m_out_pa_cb((offs_t)0, m_output[port]); + else if (port == PORT_B) + m_out_pb_cb((offs_t)0, m_output[port]); + else + m_out_pc_cb((offs_t)0, m_output[port]); + break; + } +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// i8155_device - constructor +//------------------------------------------------- + +i8155_device::i8155_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, I8155, "8155 RIOT", tag, owner, clock, "i8155", __FILE__), + device_memory_interface(mconfig, *this), + m_in_pa_cb(*this), + m_in_pb_cb(*this), + m_in_pc_cb(*this), + m_out_pa_cb(*this), + m_out_pb_cb(*this), + m_out_pc_cb(*this), + m_out_to_cb(*this), + m_command(0), + m_status(0), + m_space_config("ram", ENDIANNESS_LITTLE, 8, 8, 0, NULL, *ADDRESS_MAP_NAME(i8155)) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void i8155_device::device_start() +{ + // resolve callbacks + m_in_pa_cb.resolve_safe(0); + m_in_pb_cb.resolve_safe(0); + m_in_pc_cb.resolve_safe(0); + m_out_pa_cb.resolve_safe(); + m_out_pb_cb.resolve_safe(); + m_out_pc_cb.resolve_safe(); + m_out_to_cb.resolve_safe(); + + // allocate timers + m_timer = timer_alloc(); + + // register for state saving + save_item(NAME(m_io_m)); + save_item(NAME(m_ad)); + save_item(NAME(m_command)); + save_item(NAME(m_status)); + save_item(NAME(m_output)); + save_item(NAME(m_count_length)); + save_item(NAME(m_counter)); + save_item(NAME(m_to)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void i8155_device::device_reset() +{ + // clear output registers + m_output[PORT_A] = 0; + m_output[PORT_B] = 0; + m_output[PORT_C] = 0; + + // set ports to input mode + register_w(REGISTER_COMMAND, m_command & ~(COMMAND_PA | COMMAND_PB | COMMAND_PC_MASK)); + + // clear timer flag + m_status &= ~STATUS_TIMER; + + // stop counting + m_timer->enable(0); + + // clear timer output + m_to = 1; + timer_output(); +} + + +//------------------------------------------------- +// device_timer - handler timer events +//------------------------------------------------- + +void i8155_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + // count down + m_counter--; + + if (get_timer_mode() == TIMER_MODE_LOW) + { + // pulse on every count + pulse_timer_output(); + } + + if (m_counter == 0) + { + if (LOG) logerror("8155 '%s' Timer Count Reached\n", tag()); + + switch (m_command & COMMAND_TM_MASK) + { + case COMMAND_TM_STOP_AFTER_TC: + // stop timer + m_timer->enable(0); + + if (LOG) logerror("8155 '%s' Timer Stopped\n", tag()); + break; + } + + switch (get_timer_mode()) + { + case TIMER_MODE_SQUARE_WAVE: + // toggle timer output + m_to = !m_to; + timer_output(); + break; + + case TIMER_MODE_SINGLE_PULSE: + // single pulse upon TC being reached + pulse_timer_output(); + + // clear timer mode setting + m_command &= ~COMMAND_TM_MASK; + break; + + case TIMER_MODE_AUTOMATIC_RELOAD: + // automatic reload, i.e. single pulse every time TC is reached + pulse_timer_output(); + break; + } + + // set timer flag + m_status |= STATUS_TIMER; + + // reload timer counter + m_counter = m_count_length & 0x3fff; + } +} + + +//------------------------------------------------- +// memory_space_config - return a description of +// any address spaces owned by this device +//------------------------------------------------- + +const address_space_config *i8155_device::memory_space_config(address_spacenum spacenum) const +{ + return (spacenum == AS_0) ? &m_space_config : NULL; +} + + +//------------------------------------------------- +// io_r - register read +//------------------------------------------------- + +READ8_MEMBER( i8155_device::io_r ) +{ + UINT8 data = 0; + + switch (offset & 0x07) + { + case REGISTER_STATUS: + data = m_status; + + // clear timer flag + m_status &= ~STATUS_TIMER; + break; + + case REGISTER_PORT_A: + data = read_port(PORT_A); + break; + + case REGISTER_PORT_B: + data = read_port(PORT_B); + break; + + case REGISTER_PORT_C: + data = read_port(PORT_C) | 0xc0; + break; + + case REGISTER_TIMER_LOW: + data = m_counter & 0xff; + break; + + case REGISTER_TIMER_HIGH: + data = (m_counter >> 8 & 0x3f) | get_timer_mode(); + break; + } + + return data; +} + + +//------------------------------------------------- +// register_w - register write +//------------------------------------------------- + +void i8155_device::register_w(int offset, UINT8 data) +{ + switch (offset & 0x07) + { + case REGISTER_COMMAND: + m_command = data; + + if (LOG) logerror("8155 '%s' Port A Mode: %s\n", tag(), (data & COMMAND_PA) ? "output" : "input"); + if (LOG) logerror("8155 '%s' Port B Mode: %s\n", tag(), (data & COMMAND_PB) ? "output" : "input"); + + if (LOG) logerror("8155 '%s' Port A Interrupt: %s\n", tag(), (data & COMMAND_IEA) ? "enabled" : "disabled"); + if (LOG) logerror("8155 '%s' Port B Interrupt: %s\n", tag(), (data & COMMAND_IEB) ? "enabled" : "disabled"); + + switch (data & COMMAND_PC_MASK) + { + case COMMAND_PC_ALT_1: + if (LOG) logerror("8155 '%s' Port C Mode: Alt 1\n", tag()); + break; + + case COMMAND_PC_ALT_2: + if (LOG) logerror("8155 '%s' Port C Mode: Alt 2\n", tag()); + break; + + case COMMAND_PC_ALT_3: + if (LOG) logerror("8155 '%s' Port C Mode: Alt 3\n", tag()); + break; + + case COMMAND_PC_ALT_4: + if (LOG) logerror("8155 '%s' Port C Mode: Alt 4\n", tag()); + break; + } + + switch (data & COMMAND_TM_MASK) + { + case COMMAND_TM_NOP: + // do not affect counter operation + break; + + case COMMAND_TM_STOP: + // NOP if timer has not started, stop counting if the timer is running + if (LOG) logerror("8155 '%s' Timer Command: Stop\n", tag()); + m_to = 1; + timer_output(); + m_timer->enable(0); + break; + + case COMMAND_TM_STOP_AFTER_TC: + // stop immediately after present TC is reached (NOP if timer has not started) + if (LOG) logerror("8155 '%s' Timer Command: Stop after TC\n", tag()); + break; + + case COMMAND_TM_START: + if (LOG) logerror("8155 '%s' Timer Command: Start\n", tag()); + + if (m_timer->enabled()) + { + // if timer is running, start the new mode and CNT length immediately after present TC is reached + } + else + { + // load mode and CNT length and start immediately after loading (if timer is not running) + m_counter = m_count_length & 0x3fff; + m_timer->adjust(attotime::zero, 0, attotime::from_hz(clock())); + } + break; + } + break; + + case REGISTER_PORT_A: + write_port(PORT_A, data); + break; + + case REGISTER_PORT_B: + write_port(PORT_B, data); + break; + + case REGISTER_PORT_C: + write_port(PORT_C, data & 0x3f); + break; + + case REGISTER_TIMER_LOW: + m_count_length = (m_count_length & 0xff00) | data; + if (LOG) logerror("8155 '%s' Count Length Low: %04x\n", tag(), m_count_length); + break; + + case REGISTER_TIMER_HIGH: + m_count_length = (data << 8) | (m_count_length & 0xff); + if (LOG) logerror("8155 '%s' Count Length High: %04x\n", tag(), m_count_length); + + switch (data & TIMER_MODE_MASK) + { + case TIMER_MODE_LOW: + // puts out LOW during second half of count + if (LOG) logerror("8155 '%s' Timer Mode: LOW\n", tag()); + break; + + case TIMER_MODE_SQUARE_WAVE: + // square wave, i.e. the period of the square wave equals the count length programmed with automatic reload at terminal count + if (LOG) logerror("8155 '%s' Timer Mode: Square wave\n", tag()); + break; + + case TIMER_MODE_SINGLE_PULSE: + // single pulse upon TC being reached + if (LOG) logerror("8155 '%s' Timer Mode: Single pulse\n", tag()); + break; + + case TIMER_MODE_AUTOMATIC_RELOAD: + // automatic reload, i.e. single pulse every time TC is reached + if (LOG) logerror("8155 '%s' Timer Mode: Automatic reload\n", tag()); + break; + } + break; + } +} + +//------------------------------------------------- +// io_w - register write +//------------------------------------------------- + +WRITE8_MEMBER( i8155_device::io_w ) +{ + register_w(offset, data); +} + + +//------------------------------------------------- +// memory_r - internal RAM read +//------------------------------------------------- + +READ8_MEMBER( i8155_device::memory_r ) +{ + return this->space().read_byte(offset); +} + + +//------------------------------------------------- +// memory_w - internal RAM write +//------------------------------------------------- + +WRITE8_MEMBER( i8155_device::memory_w ) +{ + this->space().write_byte(offset, data); +} + + +//------------------------------------------------- +// ale_w - address latch write +//------------------------------------------------- + +WRITE8_MEMBER( i8155_device::ale_w ) +{ + // I/O / memory select + m_io_m = BIT(offset, 0); + + // address + m_ad = data; +} + + +//------------------------------------------------- +// read - memory or I/O read +//------------------------------------------------- + +READ8_MEMBER( i8155_device::read ) +{ + UINT8 data = 0; + + switch (m_io_m) + { + case MEMORY: + data = memory_r(space, m_ad); + break; + + case IO: + data = io_r(space, m_ad); + break; + } + + return data; +} + + +//------------------------------------------------- +// write - memory or I/O write +//------------------------------------------------- + +WRITE8_MEMBER( i8155_device::write ) +{ + switch (m_io_m) + { + case MEMORY: + memory_w(space, m_ad, data); + break; + + case IO: + io_w(space, m_ad, data); + break; + } +} diff --git a/src/devices/machine/i8155.h b/src/devices/machine/i8155.h new file mode 100644 index 00000000000..c85c0a62846 --- /dev/null +++ b/src/devices/machine/i8155.h @@ -0,0 +1,153 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Intel 8155/8156 - 2048-Bit Static MOS RAM with I/O Ports and Timer emulation + 8156 is the same as 8155, except that chip enable is active high instead of low + +********************************************************************** + _____ _____ + PC3 1 |* \_/ | 40 Vcc + PC4 2 | | 39 PC2 + TIMER IN 3 | | 38 PC1 + RESET 4 | | 37 PC0 + PC5 5 | | 36 PB7 + _TIMER OUT 6 | | 35 PB6 + IO/_M 7 | | 34 PB5 + CE or _CE 8 | | 33 PB4 + _RD 9 | | 32 PB3 + _WR 10 | 8155 | 31 PB2 + ALE 11 | 8156 | 30 PB1 + AD0 12 | | 29 PB0 + AD1 13 | | 28 PA7 + AD2 14 | | 27 PA6 + AD3 15 | | 26 PA5 + AD4 16 | | 25 PA4 + AD5 17 | | 24 PA3 + AD6 18 | | 23 PA2 + AD7 19 | | 22 PA1 + Vss 20 |_____________| 21 PA0 + +**********************************************************************/ + +#pragma once + +#ifndef __I8155__ +#define __I8155__ + +#include "emu.h" + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_I8155_IN_PORTA_CB(_devcb) \ + devcb = &i8155_device::set_in_pa_callback(*device, DEVCB_##_devcb); + +#define MCFG_I8155_IN_PORTB_CB(_devcb) \ + devcb = &i8155_device::set_in_pb_callback(*device, DEVCB_##_devcb); + +#define MCFG_I8155_IN_PORTC_CB(_devcb) \ + devcb = &i8155_device::set_in_pc_callback(*device, DEVCB_##_devcb); + +#define MCFG_I8155_OUT_PORTA_CB(_devcb) \ + devcb = &i8155_device::set_out_pa_callback(*device, DEVCB_##_devcb); + +#define MCFG_I8155_OUT_PORTB_CB(_devcb) \ + devcb = &i8155_device::set_out_pb_callback(*device, DEVCB_##_devcb); + +#define MCFG_I8155_OUT_PORTC_CB(_devcb) \ + devcb = &i8155_device::set_out_pc_callback(*device, DEVCB_##_devcb); + +#define MCFG_I8155_OUT_TIMEROUT_CB(_devcb) \ + devcb = &i8155_device::set_out_to_callback(*device, DEVCB_##_devcb); + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> i8155_device + +class i8155_device : public device_t, + public device_memory_interface +{ +public: + // construction/destruction + i8155_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + template static devcb_base &set_in_pa_callback(device_t &device, _Object object) { return downcast(device).m_in_pa_cb.set_callback(object); } + template static devcb_base &set_in_pb_callback(device_t &device, _Object object) { return downcast(device).m_in_pb_cb.set_callback(object); } + template static devcb_base &set_in_pc_callback(device_t &device, _Object object) { return downcast(device).m_in_pc_cb.set_callback(object); } + template static devcb_base &set_out_pa_callback(device_t &device, _Object object) { return downcast(device).m_out_pa_cb.set_callback(object); } + template static devcb_base &set_out_pb_callback(device_t &device, _Object object) { return downcast(device).m_out_pb_cb.set_callback(object); } + template static devcb_base &set_out_pc_callback(device_t &device, _Object object) { return downcast(device).m_out_pc_cb.set_callback(object); } + template static devcb_base &set_out_to_callback(device_t &device, _Object object) { return downcast(device).m_out_to_cb.set_callback(object); } + + DECLARE_READ8_MEMBER( io_r ); + DECLARE_WRITE8_MEMBER( io_w ); + + DECLARE_READ8_MEMBER( memory_r ); + DECLARE_WRITE8_MEMBER( memory_w ); + + DECLARE_WRITE8_MEMBER( ale_w ); + DECLARE_READ8_MEMBER( read ); + DECLARE_WRITE8_MEMBER( write ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const; + + inline UINT8 get_timer_mode(); + inline void timer_output(); + inline void pulse_timer_output(); + inline int get_port_mode(int port); + inline UINT8 read_port(int port); + inline void write_port(int port, UINT8 data); + + void register_w(int offset, UINT8 data); + +private: + devcb_read8 m_in_pa_cb; + devcb_read8 m_in_pb_cb; + devcb_read8 m_in_pc_cb; + + devcb_write8 m_out_pa_cb; + devcb_write8 m_out_pb_cb; + devcb_write8 m_out_pc_cb; + + // this gets called for each change of the TIMER OUT pin (pin 6) + devcb_write_line m_out_to_cb; + + // CPU interface + int m_io_m; // I/O or memory select + UINT8 m_ad; // address + + // registers + UINT8 m_command; // command register + UINT8 m_status; // status register + UINT8 m_output[3]; // output latches + + // counter + UINT16 m_count_length; // count length register + UINT16 m_counter; // counter register + int m_to; // timer output + + // timers + emu_timer *m_timer; // counter timer + + const address_space_config m_space_config; +}; + + +// device type definition +extern const device_type I8155; +extern const device_type I8156; + + +#endif diff --git a/src/devices/machine/i8212.c b/src/devices/machine/i8212.c new file mode 100644 index 00000000000..14b06841278 --- /dev/null +++ b/src/devices/machine/i8212.c @@ -0,0 +1,142 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Intel 8212 8-Bit Input/Output Port emulation + +**********************************************************************/ + +#include "emu.h" +#include "i8212.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define LOG 0 + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +// device type definition +const device_type I8212 = &device_creator; + +//------------------------------------------------- +// i8212_device - constructor +//------------------------------------------------- + +i8212_device::i8212_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, I8212, "I8212", tag, owner, clock, "i8212", __FILE__), + m_write_irq(*this), + m_read_di(*this), + m_write_do(*this), + m_md(I8212_MODE_INPUT), + m_stb(0) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void i8212_device::device_start() +{ + // resolve callbacks + m_write_irq.resolve_safe(); + m_read_di.resolve_safe(0); + m_write_do.resolve_safe(); + + // register for state saving + save_item(NAME(m_md)); + save_item(NAME(m_stb)); + save_item(NAME(m_data)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void i8212_device::device_reset() +{ + m_data = 0; + + if (m_md == I8212_MODE_OUTPUT) + { + // output data + m_write_do((offs_t)0, m_data); + } +} + + +//------------------------------------------------- +// read - data latch read +//------------------------------------------------- + +READ8_MEMBER( i8212_device::read ) +{ + // clear interrupt line + m_write_irq(CLEAR_LINE); + + if (LOG) logerror("I8212 '%s' INT: %u\n", tag(), CLEAR_LINE); + + return m_data; +} + + +//------------------------------------------------- +// write - data latch write +//------------------------------------------------- + +WRITE8_MEMBER( i8212_device::write ) +{ + // latch data + m_data = data; + + // output data + m_write_do((offs_t)0, m_data); +} + + +//------------------------------------------------- +// md_w - mode write +//------------------------------------------------- + +WRITE_LINE_MEMBER( i8212_device::md_w ) +{ + if (LOG) logerror("I8212 '%s' Mode: %s\n", tag(), state ? "output" : "input"); + + m_md = state; +} + + +//------------------------------------------------- +// stb_w - data strobe write +//------------------------------------------------- + +WRITE_LINE_MEMBER( i8212_device::stb_w ) +{ + if (LOG) logerror("I8212 '%s' STB: %u\n", tag(), state); + + if (m_md == I8212_MODE_INPUT) + { + if (m_stb && !state) + { + // input data + m_data = m_read_di(0); + + // assert interrupt line + m_write_irq(ASSERT_LINE); + + if (LOG) logerror("I8212 '%s' INT: %u\n", tag(), ASSERT_LINE); + } + } + + m_stb = state; +} diff --git a/src/devices/machine/i8212.h b/src/devices/machine/i8212.h new file mode 100644 index 00000000000..78e87470acd --- /dev/null +++ b/src/devices/machine/i8212.h @@ -0,0 +1,103 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Intel 8212 8-Bit Input/Output Port emulation + +********************************************************************** + _____ _____ + _DS1 1 |* \_/ | 24 Vcc + MD 2 | | 23 _INT + DI1 3 | | 22 DI8 + DO1 4 | | 21 DO8 + DI2 5 | | 20 DI7 + DO2 6 | 8212 | 19 DO7 + DI3 7 | | 18 DI6 + DO3 8 | | 17 DO6 + DI4 9 | | 16 DI5 + DO4 10 | | 15 DO5 + STB 11 | | 14 _CLR + GND 12 |_____________| 13 DS2 + +**********************************************************************/ + +#pragma once + +#ifndef __I8212__ +#define __I8212__ + +#include "emu.h" + + + +///************************************************************************* +// MACROS / CONSTANTS +///************************************************************************* + +enum +{ + I8212_MODE_INPUT = 0, + I8212_MODE_OUTPUT +}; + + + +///************************************************************************* +// INTERFACE CONFIGURATION MACROS +///************************************************************************* + +#define MCFG_I8212_IRQ_CALLBACK(_write) \ + devcb = &i8212_device::set_irq_wr_callback(*device, DEVCB_##_write); + +#define MCFG_I8212_DI_CALLBACK(_read) \ + devcb = &i8212_device::set_di_rd_callback(*device, DEVCB_##_read); + +#define MCFG_I8212_DO_CALLBACK(_write) \ + devcb = &i8212_device::set_do_wr_callback(*device, DEVCB_##_write); + + + +///************************************************************************* +// TYPE DEFINITIONS +///************************************************************************* + +// ======================> i8212_device + +class i8212_device : public device_t +{ +public: + // construction/destruction + i8212_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + template static devcb_base &set_irq_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_irq.set_callback(object); } + template static devcb_base &set_di_rd_callback(device_t &device, _Object object) { return downcast(device).m_read_di.set_callback(object); } + template static devcb_base &set_do_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_do.set_callback(object); } + + DECLARE_READ8_MEMBER( read ); + DECLARE_WRITE8_MEMBER( write ); + + DECLARE_WRITE_LINE_MEMBER( md_w ); + DECLARE_WRITE_LINE_MEMBER( stb_w ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + +private: + devcb_write_line m_write_irq; + devcb_read8 m_read_di; + devcb_write8 m_write_do; + + int m_md; // mode + int m_stb; // strobe + UINT8 m_data; // data latch +}; + + +// device type definition +extern const device_type I8212; + + + +#endif diff --git a/src/devices/machine/i8214.c b/src/devices/machine/i8214.c new file mode 100644 index 00000000000..9a7cf9ecd1c --- /dev/null +++ b/src/devices/machine/i8214.c @@ -0,0 +1,205 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Intel 8214 Priority Interrupt Controller emulation + +**********************************************************************/ + +#include "emu.h" +#include "i8214.h" + + + +// device type definition +const device_type I8214 = &device_creator; + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define LOG 0 + + + +//************************************************************************** +// INLINE HELPERS +//************************************************************************** + +//------------------------------------------------- +// trigger_interrupt - +//------------------------------------------------- + +inline void i8214_device::trigger_interrupt(int level) +{ + if (LOG) logerror("I8214 '%s' Interrupt Level %u\n", tag(), level); + + m_a = level; + + // disable interrupts + m_int_dis = 1; + + // disable next level group + m_write_enlg(0); + + // toggle interrupt line + m_write_irq(ASSERT_LINE); + m_write_irq(CLEAR_LINE); +} + + +//------------------------------------------------- +// check_interrupt - +//------------------------------------------------- + +inline void i8214_device::check_interrupt() +{ + int level; + + if (m_int_dis || !m_etlg) return; + + for (level = 7; level >= 0; level--) + { + if (!BIT(m_r, 7 - level)) + { + if (m_sgs) + { + if (level > m_b) + { + trigger_interrupt(level); + } + } + else + { + trigger_interrupt(level); + } + } + } +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// i8214_device - constructor +//------------------------------------------------- + +i8214_device::i8214_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, I8214, "I8214", tag, owner, clock, "i8214", __FILE__), + m_write_irq(*this), + m_write_enlg(*this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void i8214_device::device_start() +{ + // resolve callbacks + m_write_irq.resolve_safe(); + m_write_enlg.resolve_safe(); + + m_int_dis = 0; + + // register for state saving + save_item(NAME(m_inte)); + save_item(NAME(m_int_dis)); + save_item(NAME(m_a)); + save_item(NAME(m_b)); + save_item(NAME(m_r)); + save_item(NAME(m_sgs)); + save_item(NAME(m_etlg)); +} + + +//------------------------------------------------- +// a_r - +//------------------------------------------------- + +UINT8 i8214_device::a_r() +{ + UINT8 a = m_a & 0x07; + + if (LOG) logerror("I8214 '%s' A: %01x\n", tag(), a); + + return a; +} + + +//------------------------------------------------- +// b_w - +//------------------------------------------------- + +void i8214_device::b_w(UINT8 data) +{ + m_b = data & 0x07; + + if (LOG) logerror("I8214 '%s' B: %01x\n", tag(), m_b); + + // enable interrupts + m_int_dis = 0; + + // enable next level group + m_write_enlg(1); + + check_interrupt(); +} + + +//------------------------------------------------- +// r_w - +//------------------------------------------------- + +void i8214_device::r_w(UINT8 data) +{ + if (LOG) logerror("I8214 '%s' R: %02x\n", tag(), data); + + m_r = data; + + check_interrupt(); +} + + +//------------------------------------------------- +// sgs_w - +//------------------------------------------------- + +WRITE_LINE_MEMBER( i8214_device::sgs_w ) +{ + if (LOG) logerror("I8214 '%s' SGS: %u\n", tag(), state); + + m_sgs = state; + + check_interrupt(); +} + + +//------------------------------------------------- +// etlg_w - +//------------------------------------------------- + +WRITE_LINE_MEMBER( i8214_device::etlg_w ) +{ + if (LOG) logerror("I8214 '%s' ETLG: %u\n", tag(), state); + + m_etlg = state; +} + + +//------------------------------------------------- +// inte_w - +//------------------------------------------------- + +WRITE_LINE_MEMBER( i8214_device::inte_w ) +{ + if (LOG) logerror("I8214 '%s' INTE: %u\n", tag(), state); + + m_inte = state; +} diff --git a/src/devices/machine/i8214.h b/src/devices/machine/i8214.h new file mode 100644 index 00000000000..62e7f98fd51 --- /dev/null +++ b/src/devices/machine/i8214.h @@ -0,0 +1,94 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Intel 8214 Priority Interrupt Controller emulation + +********************************************************************** + _____ _____ + _B0 1 |* \_/ | 24 Vcc + _B1 2 | | 23 _ECS + _B2 3 | | 22 _R7 + _SGS 4 | | 21 _R6 + _INT 5 | | 20 _R5 + _CLK 6 | 8214 | 19 _R4 + INTE 7 | | 18 _R3 + _A0 8 | | 17 _R2 + _A1 9 | | 16 _R1 + _A2 10 | | 15 _R0 + _ELR 11 | | 14 ENLG + GND 12 |_____________| 13 ETLG + +**********************************************************************/ + +#pragma once + +#ifndef __I8214__ +#define __I8214__ + +#include "emu.h" + + + +///************************************************************************* +// INTERFACE CONFIGURATION MACROS +///************************************************************************* + +#define MCFG_I8214_IRQ_CALLBACK(_write) \ + devcb = &i8214_device::set_irq_wr_callback(*device, DEVCB_##_write); + +#define MCFG_I8214_ENLG_CALLBACK(_write) \ + devcb = &i8214_device::set_enlg_wr_callback(*device, DEVCB_##_write); + + + +///************************************************************************* +// TYPE DEFINITIONS +///************************************************************************* + +// ======================> i8214_device + +class i8214_device : public device_t +{ +public: + // construction/destruction + i8214_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + template static devcb_base &set_irq_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_irq.set_callback(object); } + template static devcb_base &set_enlg_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_enlg.set_callback(object); } + + DECLARE_WRITE_LINE_MEMBER( sgs_w ); + DECLARE_WRITE_LINE_MEMBER( etlg_w ); + DECLARE_WRITE_LINE_MEMBER( inte_w ); + + UINT8 a_r(); + void b_w(UINT8 data); + void r_w(UINT8 data); + +protected: + // device-level overrides + virtual void device_start(); + +private: + inline void trigger_interrupt(int level); + inline void check_interrupt(); + + devcb_write_line m_write_irq; + devcb_write_line m_write_enlg; + + int m_inte; // interrupt enable + int m_int_dis; // interrupt disable flip-flop + int m_a; // request level + int m_b; // current status register + UINT8 m_r; // interrupt request latch + int m_sgs; // status group select + int m_etlg; // enable this level group +}; + + +// device type definition +extern const device_type I8214; + + + +#endif diff --git a/src/devices/machine/i8243.c b/src/devices/machine/i8243.c new file mode 100644 index 00000000000..d3393cea4fd --- /dev/null +++ b/src/devices/machine/i8243.c @@ -0,0 +1,125 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + i8243.c + + Intel 8243 Port Expander + +***************************************************************************/ + +#include "emu.h" +#include "i8243.h" + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +// device type definition +const device_type I8243 = &device_creator; + +//------------------------------------------------- +// i8243_device - constructor +//------------------------------------------------- + +i8243_device::i8243_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, I8243, "8243 I/O Expander", tag, owner, clock, "i8243", __FILE__), + m_readhandler(*this), + m_writehandler(*this) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void i8243_device::device_start() +{ + m_readhandler.resolve_safe(0); + m_writehandler.resolve_safe(); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void i8243_device::device_reset() +{ + m_p2 = 0x0f; + m_p2out = 0x0f; + m_prog = 1; +} + + +/*------------------------------------------------- + i8243_p2_r - handle a read from port 2 +-------------------------------------------------*/ + +READ8_MEMBER(i8243_device::i8243_p2_r) +{ + return m_p2out; +} + + +/*------------------------------------------------- + i8243_p2_r - handle a write to port 2 +-------------------------------------------------*/ + +WRITE8_MEMBER(i8243_device::i8243_p2_w) +{ + m_p2 = data & 0x0f; +} + + +/*------------------------------------------------- + i8243_prog_w - handle a change in the PROG + line state +-------------------------------------------------*/ + +WRITE8_MEMBER(i8243_device::i8243_prog_w) +{ + /* only care about low bit */ + data &= 1; + + /* on high->low transition state, latch opcode/port */ + if(m_prog && !data) + { + m_opcode = m_p2; + + /* if this is a read opcode, copy result to p2out */ + if((m_opcode >> 2) == MCS48_EXPANDER_OP_READ) + { + if (m_readhandler.isnull()) + { + m_p[m_opcode & 3] = m_readhandler(m_opcode & 3); + } + m_p2out = m_p[m_opcode & 3] & 0x0f; + } + } + + /* on low->high transition state, act on opcode */ + else if(!m_prog && data) + { + switch(m_opcode >> 2) + { + case MCS48_EXPANDER_OP_WRITE: + m_p[m_opcode & 3] = m_p2 & 0x0f; + m_writehandler((offs_t)(m_opcode & 3), m_p[m_opcode & 3]); + break; + + case MCS48_EXPANDER_OP_OR: + m_p[m_opcode & 3] |= m_p2 & 0x0f; + m_writehandler((offs_t)(m_opcode & 3), m_p[m_opcode & 3]); + break; + + case MCS48_EXPANDER_OP_AND: + m_p[m_opcode & 3] &= m_p2 & 0x0f; + m_writehandler((offs_t)(m_opcode & 3), m_p[m_opcode & 3]); + break; + } + } + + /* remember the state */ + m_prog = data; +} diff --git a/src/devices/machine/i8243.h b/src/devices/machine/i8243.h new file mode 100644 index 00000000000..7ac782f3496 --- /dev/null +++ b/src/devices/machine/i8243.h @@ -0,0 +1,78 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + i8243.h + + Intel 8243 Port Expander + +***************************************************************************/ + +#pragma once + +#ifndef __I8243_H__ +#define __I8243_H__ + +#include "emu.h" +#include "cpu/mcs48/mcs48.h" + + + +/*************************************************************************** + DEVICE CONFIGURATION MACROS +***************************************************************************/ + +#define MCFG_I8243_ADD(_tag, _read, _write) \ + MCFG_DEVICE_ADD(_tag, I8243, 0) \ + MCFG_I8243_READHANDLER(_read) \ + MCFG_I8243_WRITEHANDLER(_write) +#define MCFG_I8243_READHANDLER(_devcb) \ + devcb = &i8243_device::set_read_handler(*device, DEVCB_##_devcb); +#define MCFG_I8243_WRITEHANDLER(_devcb) \ + devcb = &i8243_device::set_write_handler(*device, DEVCB_##_devcb); +/*************************************************************************** + TYPE DEFINITIONS +***************************************************************************/ + + +// ======================> i8243_device + +class i8243_device : public device_t +{ +public: + // construction/destruction + i8243_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // static configuration helpers + template static devcb_base &set_read_handler(device_t &device, _Object object) { return downcast(device).m_readhandler.set_callback(object); } + template static devcb_base &set_write_handler(device_t &device, _Object object) { return downcast(device).m_writehandler.set_callback(object); } + + DECLARE_READ8_MEMBER(i8243_p2_r); + DECLARE_WRITE8_MEMBER(i8243_p2_w); + + DECLARE_WRITE8_MEMBER(i8243_prog_w); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_post_load() { } + virtual void device_clock_changed() { } + +private: + + UINT8 m_p[4]; /* 4 ports' worth of data */ + UINT8 m_p2out; /* port 2 bits that will be returned */ + UINT8 m_p2; /* most recent port 2 value */ + UINT8 m_opcode; /* latched opcode */ + UINT8 m_prog; /* previous PROG state */ + + devcb_read8 m_readhandler; + devcb_write8 m_writehandler; +}; + + +// device type definition +extern const device_type I8243; + +#endif /* __I8243_H__ */ diff --git a/src/devices/machine/i8251.c b/src/devices/machine/i8251.c new file mode 100644 index 00000000000..7008fe394a3 --- /dev/null +++ b/src/devices/machine/i8251.c @@ -0,0 +1,788 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/********************************************************************* + + i8251.c + + Intel 8251 Universal Synchronous/Asynchronous Receiver Transmitter code + NEC uPD71051 is a clone + + The V53/V53A use a customized version with only the Asynchronous mode + and a split command / mode register + + + +*********************************************************************/ + +#include "emu.h" +#include "i8251.h" + + +/*************************************************************************** + MACROS +***************************************************************************/ + +#define VERBOSE 0 + +#define LOG(x) do { if (VERBOSE) logerror x; } while (0) + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type I8251 = &device_creator; +const device_type V53_SCU = &device_creator; + +//------------------------------------------------- +// i8251_device - constructor +//------------------------------------------------- + +i8251_device::i8251_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname) + : device_t(mconfig, type, name, tag, owner, clock, shortname, __FILE__), + device_serial_interface(mconfig, *this), + m_txd_handler(*this), + m_dtr_handler(*this), + m_rts_handler(*this), + m_rxrdy_handler(*this), + m_txrdy_handler(*this), + m_txempty_handler(*this), + m_syndet_handler(*this), + m_cts(1), + m_dsr(1), + m_rxd(0), + m_rxc(0), + m_txc(0) +{ +} + +i8251_device::i8251_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, I8251, "8251 USART", tag, owner, clock, "i8251", __FILE__), + device_serial_interface(mconfig, *this), + m_txd_handler(*this), + m_dtr_handler(*this), + m_rts_handler(*this), + m_rxrdy_handler(*this), + m_txrdy_handler(*this), + m_txempty_handler(*this), + m_syndet_handler(*this), + m_cts(1), + m_dsr(1), + m_rxd(0), + m_rxc(0), + m_txc(0) +{ +} + +v53_scu_device::v53_scu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : i8251_device(mconfig, V53_SCU, "V53 SCU", tag, owner, clock, "v53_scu") +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void i8251_device::device_start() +{ + // resolve callbacks + m_txd_handler.resolve_safe(); + m_rts_handler.resolve_safe(); + m_dtr_handler.resolve_safe(); + m_rxrdy_handler.resolve_safe(); + m_txrdy_handler.resolve_safe(); + m_txempty_handler.resolve_safe(); + save_item(NAME(m_flags)); + save_item(NAME(m_sync_byte_offset)); + save_item(NAME(m_sync_byte_count)); + save_item(NAME(m_sync_bytes)); + save_item(NAME(m_status)); + save_item(NAME(m_command)); + save_item(NAME(m_mode_byte)); + save_item(NAME(m_cts)); + save_item(NAME(m_dsr)); + save_item(NAME(m_rxd)); + save_item(NAME(m_rxc)); + save_item(NAME(m_txc)); + save_item(NAME(m_rxc_count)); + save_item(NAME(m_txc_count)); + save_item(NAME(m_br_factor)); + save_item(NAME(m_rx_data)); + save_item(NAME(m_tx_data)); + save_item(NAME(m_tx_busy)); + save_item(NAME(m_disable_tx_pending)); + device_serial_interface::register_save_state(machine().save(), this); +} + + + + +/*------------------------------------------------- + update_rx_ready +-------------------------------------------------*/ + +void i8251_device::update_rx_ready() +{ + int state; + + state = m_status & I8251_STATUS_RX_READY; + + /* masked? */ + if ((m_command & (1<<2))==0) + { + state = 0; + } + + m_rxrdy_handler(state != 0); +} + + + +/*------------------------------------------------- + receive_clock +-------------------------------------------------*/ + +void i8251_device::receive_clock() +{ + m_rxc_count++; + + if (m_rxc_count == m_br_factor) + m_rxc_count = 0; + else + return; + + /* receive enable? */ + if (m_command & (1<<2)) + { + //logerror("I8251\n"); + /* get bit received from other side and update receive register */ + receive_register_update_bit(m_rxd); + + if (is_receive_register_full()) + { + receive_register_extract(); + receive_character(get_received_char()); + } + } +} + + + +/*------------------------------------------------- + transmit_clock +-------------------------------------------------*/ + +void i8251_device::transmit_clock() +{ + m_txc_count++; + + if (m_txc_count == m_br_factor) + m_txc_count = 0; + else + return; + + /* transmit enabled? */ + if (m_command & (1<<0)) + { + /* do we have a character to send? */ + if ((m_status & I8251_STATUS_TX_READY)==0) + { + /* is diserial ready for it? */ + if (is_transmit_register_empty()) + { + /* set it up */ + transmit_register_setup(m_tx_data); + /* i8251 transmit reg now empty */ + m_status |=I8251_STATUS_TX_EMPTY; + /* ready for next transmit */ + m_status |=I8251_STATUS_TX_READY; + + update_tx_empty(); + update_tx_ready(); + } + } + + /* if diserial has bits to send, make them so */ + if (!is_transmit_register_empty()) + { + UINT8 data = transmit_register_get_data_bit(); + m_tx_busy = true; + m_txd_handler(data); + } + + // is transmitter totally done? + if ((m_status & I8251_STATUS_TX_READY) && is_transmit_register_empty()) + { + m_tx_busy = false; + + if (m_disable_tx_pending) + { + LOG(("Applying pending disable\n")); + m_disable_tx_pending = false; + m_command &= ~(1<<0); + m_txd_handler(1); + update_tx_ready(); + } + } + } + +#if 0 + /* hunt mode? */ + /* after each bit has been shifted in, it is compared against the current sync byte */ + if (m_command & (1<<7)) + { + /* data matches sync byte? */ + if (m_data == m_sync_bytes[m_sync_byte_offset]) + { + /* sync byte matches */ + /* update for next sync byte? */ + m_sync_byte_offset++; + + /* do all sync bytes match? */ + if (m_sync_byte_offset == m_sync_byte_count) + { + /* ent hunt mode */ + m_command &=~(1<<7); + } + } + else + { + /* if there is no match, reset */ + m_sync_byte_offset = 0; + } + } +#endif +} + + + +/*------------------------------------------------- + update_tx_ready +-------------------------------------------------*/ + +void i8251_device::update_tx_ready() +{ + /* clear tx ready state */ + int tx_ready; + + /* tx ready output is set if: + DB Buffer Empty & + CTS is set & + Transmit enable is 1 + */ + + tx_ready = 0; + + /* transmit enable? */ + if ((m_command & (1<<0))!=0) + { + /* other side has rts set (comes in as CTS at this side) */ + if (!m_cts) + { + if (m_status & I8251_STATUS_TX_EMPTY) + { + /* enable transfer */ + tx_ready = 1; + } + } + } + + m_txrdy_handler(tx_ready); +} + + + +/*------------------------------------------------- + update_tx_empty +-------------------------------------------------*/ + +void i8251_device::update_tx_empty() +{ + if (m_status & I8251_STATUS_TX_EMPTY) + { + /* tx is in marking state (high) when tx empty! */ + m_txd_handler(1); + } + + m_txempty_handler((m_status & I8251_STATUS_TX_EMPTY) != 0); +} + + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void i8251_device::device_reset() +{ + LOG(("I8251: Reset\n")); + + /* what is the default setup when the 8251 has been reset??? */ + + /* i8251 datasheet explains the state of tx pin at reset */ + /* tx is set to 1 */ + m_txd_handler(1); + + /* assumption */ + m_rts_handler(1); + m_dtr_handler(1); + + transmit_register_reset(); + receive_register_reset(); + m_flags = 0; + /* expecting mode byte */ + m_flags |= I8251_EXPECTING_MODE; + /* not expecting a sync byte */ + m_flags &= ~I8251_EXPECTING_SYNC_BYTE; + + /* no character to read by cpu */ + /* transmitter is ready and is empty */ + m_status = I8251_STATUS_TX_EMPTY | I8251_STATUS_TX_READY; + m_mode_byte = 0; + m_command = 0; + m_rx_data = 0; + m_tx_data = 0; + m_rxc_count = m_txc_count = 0; + m_br_factor = 1; + m_tx_busy = m_disable_tx_pending = false; + + /* update tx empty pin output */ + update_tx_empty(); + /* update rx ready pin output */ + update_rx_ready(); + /* update tx ready pin output */ + update_tx_ready(); +} + + + +/*------------------------------------------------- + control_w +-------------------------------------------------*/ + +WRITE8_MEMBER(i8251_device::command_w) +{ + /* command */ + LOG(("I8251: Command byte\n")); + + m_command = data; + + LOG(("Command byte: %02x\n", data)); + + if (data & (1<<7)) + { + LOG(("hunt mode\n")); + } + + if (data & (1<<5)) + { + LOG(("/rts set to 0\n")); + } + else + { + LOG(("/rts set to 1\n")); + } + + if (data & (1<<2)) + { + LOG(("receive enable\n")); + } + else + { + LOG(("receive disable\n")); + } + + if (data & (1<<1)) + { + LOG(("/dtr set to 0\n")); + } + else + { + LOG(("/dtr set to 1\n")); + } + + if (data & (1<<0)) + { + LOG(("transmit enable\n")); + + /* if we get a tx enable with a disable pending, cancel the disable */ + m_disable_tx_pending = false; + } + else + { + if (m_tx_busy) + { + if (!m_disable_tx_pending) + { + LOG(("Tx busy, set pending disable\n")); + } + m_disable_tx_pending = true; + m_command |= (1<<0); + } + else + { + LOG(("transmit disable\n")); + if ((data & (1<<0))==0) + { + /* held in high state when transmit disable */ + m_txd_handler(1); + } + } + } + + + /* bit 7: + 0 = normal operation + 1 = hunt mode + bit 6: + 0 = normal operation + 1 = internal reset + bit 5: + 0 = /RTS set to 1 + 1 = /RTS set to 0 + bit 4: + 0 = normal operation + 1 = reset error flag + bit 3: + 0 = normal operation + 1 = send break character + bit 2: + 0 = receive disable + 1 = receive enable + bit 1: + 0 = /DTR set to 1 + 1 = /DTR set to 0 + bit 0: + 0 = transmit disable + 1 = transmit enable + */ + + m_rts_handler(!BIT(data, 5)); + m_dtr_handler(!BIT(data, 1)); + + if (data & (1<<4)) + { + m_status &= ~(I8251_STATUS_PARITY_ERROR | I8251_STATUS_OVERRUN_ERROR | I8251_STATUS_FRAMING_ERROR); + } + + if (data & (1<<6)) + { + // datasheet says "returns to mode format", not + // completely resets the chip. behavior of DEC Rainbow + // backs this up. + m_flags |= I8251_EXPECTING_MODE; + } + + update_rx_ready(); + update_tx_ready(); +} + +WRITE8_MEMBER(i8251_device::mode_w) +{ + LOG(("I8251: Mode byte\n")); + + m_mode_byte = data; + + /* Synchronous or Asynchronous? */ + if ((data & 0x03) != 0) + { + /* Asynchronous + + bit 7,6: stop bit length + 0 = inhibit + 1 = 1 bit + 2 = 1.5 bits + 3 = 2 bits + bit 5: parity type + 0 = parity odd + 1 = parity even + bit 4: parity test enable + 0 = disable + 1 = enable + bit 3,2: character length + 0 = 5 bits + 1 = 6 bits + 2 = 7 bits + 3 = 8 bits + bit 1,0: baud rate factor + 0 = defines command byte for synchronous or asynchronous + 1 = x1 + 2 = x16 + 3 = x64 + */ + + LOG(("I8251: Asynchronous operation\n")); + + LOG(("Character length: %d\n", (((data >> 2) & 0x03) + 5))); + + parity_t parity; + + if (data & (1 << 4)) + { + LOG(("enable parity checking\n")); + + if (data & (1 << 5)) + { + LOG(("even parity\n")); + parity = PARITY_EVEN; + } + else + { + LOG(("odd parity\n")); + parity = PARITY_ODD; + } + } + else + { + LOG(("parity check disabled\n")); + parity = PARITY_NONE; + } + + stop_bits_t stop_bits; + + switch ((data >> 6) & 0x03) + { + case 0: + default: + stop_bits = STOP_BITS_0; + LOG(("stop bit: inhibit\n")); + break; + + case 1: + stop_bits = STOP_BITS_1; + LOG(("stop bit: 1 bit\n")); + break; + + case 2: + stop_bits = STOP_BITS_1_5; + LOG(("stop bit: 1.5 bits\n")); + break; + + case 3: + stop_bits = STOP_BITS_2; + LOG(("stop bit: 2 bits\n")); + break; + } + + int data_bits_count = ((data >> 2) & 0x03) + 5; + + set_data_frame(1, data_bits_count, parity, stop_bits); + receive_register_reset(); + + switch (data & 0x03) + { + case 1: m_br_factor = 1; break; + case 2: m_br_factor = 16; break; + case 3: m_br_factor = 64; break; + } + + m_rxc_count = m_txc_count = 0; + +#if 0 + /* data bits */ + m_receive_char_length = (((data >> 2) & 0x03) + 5); + + if (data & (1 << 4)) + { + /* parity */ + m_receive_char_length++; + } + + /* stop bits */ + m_receive_char_length++; + + m_receive_flags &= ~I8251_TRANSFER_RECEIVE_SYNCHRONISED; + m_receive_flags |= I8251_TRANSFER_RECEIVE_WAITING_FOR_START_BIT; +#endif + /* not expecting mode byte now */ + m_flags &= ~I8251_EXPECTING_MODE; + // m_status = I8251_STATUS_TX_EMPTY | I8251_STATUS_TX_READY; + } + else + { + /* bit 7: Number of sync characters + 0 = 1 character + 1 = 2 character + bit 6: Synchronous mode + 0 = Internal synchronisation + 1 = External synchronisation + bit 5: parity type + 0 = parity odd + 1 = parity even + bit 4: parity test enable + 0 = disable + 1 = enable + bit 3,2: character length + 0 = 5 bits + 1 = 6 bits + 2 = 7 bits + 3 = 8 bits + bit 1,0 = 0 + */ + LOG(("I8251: Synchronous operation\n")); + + /* setup for sync byte(s) */ + m_flags |= I8251_EXPECTING_SYNC_BYTE; + m_sync_byte_offset = 0; + if (data & 0x07) + { + m_sync_byte_count = 1; + } + else + { + m_sync_byte_count = 2; + } + + } +} + +WRITE8_MEMBER(i8251_device::control_w) +{ + if (m_flags & I8251_EXPECTING_MODE) + { + if (m_flags & I8251_EXPECTING_SYNC_BYTE) + { + LOG(("I8251: Sync byte\n")); + + LOG(("Sync byte: %02x\n", data)); + /* store sync byte written */ + m_sync_bytes[m_sync_byte_offset] = data; + m_sync_byte_offset++; + + if (m_sync_byte_offset == m_sync_byte_count) + { + /* finished transfering sync bytes, now expecting command */ + m_flags &= ~(I8251_EXPECTING_MODE | I8251_EXPECTING_SYNC_BYTE); + m_sync_byte_offset = 0; + // m_status = I8251_STATUS_TX_EMPTY | I8251_STATUS_TX_READY; + } + } + else + { + mode_w(space, offset, data); + } + } + else + { + command_w(space, offset, data); + } +} + + + +/*------------------------------------------------- + status_r +-------------------------------------------------*/ + +READ8_MEMBER(i8251_device::status_r) +{ + UINT8 status = (m_dsr << 7) | m_status; + + LOG(("status: %02x\n", status)); + return status; +} + + + +/*------------------------------------------------- + data_w +-------------------------------------------------*/ + +WRITE8_MEMBER(i8251_device::data_w) +{ + m_tx_data = data; + + LOG(("data_w %02x\n" , data)); +// printf("i8251 transmit char: %02x\n",data); + + /* writing clears */ + m_status &=~I8251_STATUS_TX_READY; + m_status &=~I8251_STATUS_TX_EMPTY; + + /* if transmitter is active, then tx empty will be signalled */ + + update_tx_ready(); + update_tx_empty(); +} + + + +/*------------------------------------------------- + receive_character - called when last + bit of data has been received +-------------------------------------------------*/ + +void i8251_device::receive_character(UINT8 ch) +{ + m_rx_data = ch; + + /* char has not been read and another has arrived! */ + if (m_status & I8251_STATUS_RX_READY) + { + m_status |= I8251_STATUS_OVERRUN_ERROR; + } + m_status |= I8251_STATUS_RX_READY; + + update_rx_ready(); +} + + + +/*------------------------------------------------- + data_r - read data +-------------------------------------------------*/ + +READ8_MEMBER(i8251_device::data_r) +{ + LOG(("read data: %02x, STATUS=%02x\n",m_rx_data,m_status)); + /* reading clears */ + m_status &= ~I8251_STATUS_RX_READY; + + update_rx_ready(); + return m_rx_data; +} + + +void i8251_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + device_serial_interface::device_timer(timer, id, param, ptr); +} + + +WRITE_LINE_MEMBER(i8251_device::write_rxd) +{ + m_rxd = state; +// device_serial_interface::rx_w(state); +} + +WRITE_LINE_MEMBER(i8251_device::write_cts) +{ + m_cts = state; +} + +WRITE_LINE_MEMBER(i8251_device::write_dsr) +{ + m_dsr = !state; +} + +WRITE_LINE_MEMBER(i8251_device::write_rxc) +{ + if (m_rxc != state) + { + m_rxc = state; + + if (m_rxc) + receive_clock(); + } +} + +WRITE_LINE_MEMBER(i8251_device::write_txc) +{ + if (m_txc != state) + { + m_txc = state; + + if (!m_txc) + transmit_clock(); + } +} diff --git a/src/devices/machine/i8251.h b/src/devices/machine/i8251.h new file mode 100644 index 00000000000..2825faf1ed1 --- /dev/null +++ b/src/devices/machine/i8251.h @@ -0,0 +1,155 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/********************************************************************* + + i8251.h + + Intel 8251 Universal Synchronous/Asynchronous Receiver Transmitter code + +*********************************************************************/ + +#ifndef __I8251_H__ +#define __I8251_H__ + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_I8251_TXD_HANDLER(_devcb) \ + devcb = &i8251_device::set_txd_handler(*device, DEVCB_##_devcb); + +#define MCFG_I8251_DTR_HANDLER(_devcb) \ + devcb = &i8251_device::set_dtr_handler(*device, DEVCB_##_devcb); + +#define MCFG_I8251_RTS_HANDLER(_devcb) \ + devcb = &i8251_device::set_rts_handler(*device, DEVCB_##_devcb); + +#define MCFG_I8251_RXRDY_HANDLER(_devcb) \ + devcb = &i8251_device::set_rxrdy_handler(*device, DEVCB_##_devcb); + +#define MCFG_I8251_TXRDY_HANDLER(_devcb) \ + devcb = &i8251_device::set_txrdy_handler(*device, DEVCB_##_devcb); + +#define MCFG_I8251_TXEMPTY_HANDLER(_devcb) \ + devcb = &i8251_device::set_txempty_handler(*device, DEVCB_##_devcb); + +#define MCFG_I8251_SYNDET_HANDLER(_devcb) \ + devcb = &i8251_device::set_syndet_handler(*device, DEVCB_##_devcb); + +class i8251_device : public device_t, + public device_serial_interface +{ +public: + // construction/destruction + i8251_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname); + i8251_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // static configuration helpers + template static devcb_base &set_txd_handler(device_t &device, _Object object) { return downcast(device).m_txd_handler.set_callback(object); } + template static devcb_base &set_dtr_handler(device_t &device, _Object object) { return downcast(device).m_dtr_handler.set_callback(object); } + template static devcb_base &set_rts_handler(device_t &device, _Object object) { return downcast(device).m_rts_handler.set_callback(object); } + template static devcb_base &set_rxrdy_handler(device_t &device, _Object object) { return downcast(device).m_rxrdy_handler.set_callback(object); } + template static devcb_base &set_txrdy_handler(device_t &device, _Object object) { return downcast(device).m_txrdy_handler.set_callback(object); } + template static devcb_base &set_txempty_handler(device_t &device, _Object object) { return downcast(device).m_txempty_handler.set_callback(object); } + template static devcb_base &set_syndet_handler(device_t &device, _Object object) { return downcast(device).m_syndet_handler.set_callback(object); } + + DECLARE_READ8_MEMBER(data_r); + DECLARE_WRITE8_MEMBER(data_w); + DECLARE_READ8_MEMBER(status_r); + DECLARE_WRITE8_MEMBER(control_w); + DECLARE_WRITE8_MEMBER(command_w); + DECLARE_WRITE8_MEMBER(mode_w); + + DECLARE_WRITE_LINE_MEMBER( write_rxd ); + DECLARE_WRITE_LINE_MEMBER( write_cts ); + DECLARE_WRITE_LINE_MEMBER( write_dsr ); + DECLARE_WRITE_LINE_MEMBER( write_txc ); + DECLARE_WRITE_LINE_MEMBER( write_rxc ); + + /// TODO: REMOVE THIS + void receive_character(UINT8 ch); + + /// TODO: this shouldn't be public + enum + { + I8251_STATUS_FRAMING_ERROR = 0x20, + I8251_STATUS_OVERRUN_ERROR = 0x10, + I8251_STATUS_PARITY_ERROR = 0x08, + I8251_STATUS_TX_EMPTY = 0x04, + I8251_STATUS_RX_READY = 0x02, + I8251_STATUS_TX_READY = 0x01 + }; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + void update_rx_ready(); + void update_tx_ready(); + void update_tx_empty(); + void transmit_clock(); + void receive_clock(); + + enum + { + I8251_EXPECTING_MODE = 0x01, + I8251_EXPECTING_SYNC_BYTE = 0x02 + }; + +private: + devcb_write_line m_txd_handler; + devcb_write_line m_dtr_handler; + devcb_write_line m_rts_handler; + devcb_write_line m_rxrdy_handler; + devcb_write_line m_txrdy_handler; + devcb_write_line m_txempty_handler; + devcb_write_line m_syndet_handler; + + /* flags controlling how i8251_control_w operates */ + UINT8 m_flags; + /* offset into sync_bytes used during sync byte transfer */ + UINT8 m_sync_byte_offset; + /* number of sync bytes written so far */ + UINT8 m_sync_byte_count; + /* the sync bytes written */ + UINT8 m_sync_bytes[2]; + /* status of i8251 */ + UINT8 m_status; + UINT8 m_command; + /* mode byte - bit definitions depend on mode - e.g. synchronous, asynchronous */ + UINT8 m_mode_byte; + + int m_cts; + int m_dsr; + int m_rxd; + int m_rxc; + int m_txc; + int m_rxc_count; + int m_txc_count; + int m_br_factor; + + /* data being received */ + UINT8 m_rx_data; + UINT8 m_tx_data; + bool m_tx_busy; + bool m_disable_tx_pending; +}; + +class v53_scu_device : public i8251_device +{ +public: + // construction/destruction + v53_scu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + + +// device type definition +extern const device_type I8251; +extern const device_type V53_SCU; + + +#endif /* __I8251_H__ */ diff --git a/src/devices/machine/i82541.c b/src/devices/machine/i82541.c new file mode 100644 index 00000000000..8e5a1467183 --- /dev/null +++ b/src/devices/machine/i82541.c @@ -0,0 +1,32 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +#include "i82541.h" + +const device_type I82541 = &device_creator; + +DEVICE_ADDRESS_MAP_START(registers_map, 32, i82541_device) +ADDRESS_MAP_END + +DEVICE_ADDRESS_MAP_START(flash_map, 32, i82541_device) +ADDRESS_MAP_END + +DEVICE_ADDRESS_MAP_START(registers_io_map, 32, i82541_device) +ADDRESS_MAP_END + +i82541_device::i82541_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : pci_device(mconfig, I82541, "I82541 ethernet controller", tag, owner, clock, "i82541", __FILE__) +{ +} + +void i82541_device::device_start() +{ + pci_device::device_start(); + add_map(128*1024, M_MEM, FUNC(i82541_device::registers_map)); + add_map(128*1024, M_MEM, FUNC(i82541_device::flash_map)); + add_map(32, M_IO, FUNC(i82541_device::registers_io_map)); +} + +void i82541_device::device_reset() +{ + pci_device::device_reset(); +} diff --git a/src/devices/machine/i82541.h b/src/devices/machine/i82541.h new file mode 100644 index 00000000000..810c4dc7b4a --- /dev/null +++ b/src/devices/machine/i82541.h @@ -0,0 +1,29 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +// Intel I82541 ethernet controller + +#ifndef I82541_H +#define I82541_H + +#include "pci.h" + +#define MCFG_I82541PI_ADD(_tag, _subdevice_id) \ + MCFG_PCI_DEVICE_ADD(_tag, I82541, 0x8086107c, 0x05, 0x020000, _subdevice_id) + +class i82541_device : public pci_device { +public: + i82541_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual void device_start(); + virtual void device_reset(); + +private: + DECLARE_ADDRESS_MAP(registers_map, 32); + DECLARE_ADDRESS_MAP(flash_map, 32); + DECLARE_ADDRESS_MAP(registers_io_map, 32); +}; + +extern const device_type I82541; + +#endif diff --git a/src/devices/machine/i8255.c b/src/devices/machine/i8255.c new file mode 100644 index 00000000000..7725565cde2 --- /dev/null +++ b/src/devices/machine/i8255.c @@ -0,0 +1,995 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Intel 8255(A) Programmable Peripheral Interface emulation + +**********************************************************************/ + +#include "i8255.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define LOG 0 + + +enum +{ + PORT_A = 0, + PORT_B, + PORT_C, + CONTROL +}; + + +enum +{ + GROUP_A = 0, + GROUP_B +}; + + +enum +{ + MODE_0 = 0, + MODE_1, + MODE_2 +}; + + +enum +{ + MODE_OUTPUT = 0, + MODE_INPUT +}; + + +#define CONTROL_PORT_C_LOWER_INPUT 0x01 +#define CONTROL_PORT_B_INPUT 0x02 +#define CONTROL_GROUP_B_MODE_1 0x04 +#define CONTROL_PORT_C_UPPER_INPUT 0x08 +#define CONTROL_PORT_A_INPUT 0x10 +#define CONTROL_GROUP_A_MODE_MASK 0x60 +#define CONTROL_MODE_SET 0x80 + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type I8255 = &device_creator; +const device_type I8255A = &device_creator; + + +//************************************************************************** +// INLINE HELPERS +//************************************************************************** + +//------------------------------------------------- +// check_interrupt - +//------------------------------------------------- + +inline void i8255_device::check_interrupt(int port) +{ + switch (group_mode(port)) + { + case MODE_1: + switch (port_mode(port)) + { + case MODE_INPUT: + set_intr(port, (m_inte[port] && m_ibf[port])); + break; + + case MODE_OUTPUT: + set_intr(port, (m_inte[port] && m_obf[port])); + break; + } + break; + + case MODE_2: + set_intr(port, ((m_inte1 && m_obf[port]) || (m_inte2 && m_ibf[port]))); + break; + } +} + + +//------------------------------------------------- +// set_ibf - +//------------------------------------------------- + +inline void i8255_device::set_ibf(int port, int state) +{ + if (LOG) logerror("I8255 '%s' Port %c IBF: %u\n", tag(), 'A' + port, state); + + m_ibf[port] = state; + + check_interrupt(port); +} + + +//------------------------------------------------- +// set_obf - +//------------------------------------------------- + +inline void i8255_device::set_obf(int port, int state) +{ + if (LOG) logerror("I8255 '%s' Port %c OBF: %u\n", tag(), 'A' + port, state); + + m_obf[port] = state; + + check_interrupt(port); +} + + +//------------------------------------------------- +// set_inte - +//------------------------------------------------- + +inline void i8255_device::set_inte(int port, int state) +{ + if (LOG) logerror("I8255 '%s' Port %c INTE: %u\n", tag(), 'A' + port, state); + + m_inte[port] = state; + + check_interrupt(port); +} + + +//------------------------------------------------- +// set_inte1 - +//------------------------------------------------- + +inline void i8255_device::set_inte1(int state) +{ + if (LOG) logerror("I8255 '%s' Port A INTE1: %u\n", tag(), state); + + m_inte1 = state; + + check_interrupt(PORT_A); +} + + +//------------------------------------------------- +// set_inte2 - +//------------------------------------------------- + +inline void i8255_device::set_inte2(int state) +{ + if (LOG) logerror("I8255 '%s' Port A INTE2: %u\n", tag(), state); + + m_inte2 = state; + + check_interrupt(PORT_A); +} + + +//------------------------------------------------- +// set_intr - +//------------------------------------------------- + +inline void i8255_device::set_intr(int port, int state) +{ + if (LOG) logerror("I8255 '%s' Port %c INTR: %u\n", tag(), 'A' + port, state); + + m_intr[port] = state; + + output_pc(); +} + + +//------------------------------------------------- +// group_mode - +//------------------------------------------------- + +inline int i8255_device::group_mode(int group) +{ + int mode = 0; + + switch (group) + { + case GROUP_A: + switch ((m_control & CONTROL_GROUP_A_MODE_MASK) >> 5) + { + case 0: mode = MODE_0; break; + case 1: mode = MODE_1; break; + case 2: case 3: mode = MODE_2; break; + } + break; + + case GROUP_B: + mode = m_control & CONTROL_GROUP_B_MODE_1 ? MODE_1 : MODE_0; + break; + } + + return mode; +} + + +//------------------------------------------------- +// port_mode - +//------------------------------------------------- + +inline int i8255_device::port_mode(int port) +{ + int mode = 0; + + switch (port) + { + case PORT_A: mode = m_control & CONTROL_PORT_A_INPUT ? MODE_INPUT : MODE_OUTPUT; break; + case PORT_B: mode = m_control & CONTROL_PORT_B_INPUT ? MODE_INPUT : MODE_OUTPUT; break; + } + + return mode; +} + + +//------------------------------------------------- +// port_c_lower_mode - +//------------------------------------------------- + +inline int i8255_device::port_c_lower_mode() +{ + return m_control & CONTROL_PORT_C_LOWER_INPUT ? MODE_INPUT : MODE_OUTPUT; +} + + +//------------------------------------------------- +// port_c_upper_mode - +//------------------------------------------------- + +inline int i8255_device::port_c_upper_mode() +{ + return m_control & CONTROL_PORT_C_UPPER_INPUT ? MODE_INPUT : MODE_OUTPUT; +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// i8255_device - constructor +//------------------------------------------------- + +i8255_device::i8255_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, I8255, "8255 PPI", tag, owner, clock, "i8255", __FILE__), + m_in_pa_cb(*this), + m_in_pb_cb(*this), + m_in_pc_cb(*this), + m_out_pa_cb(*this), + m_out_pb_cb(*this), + m_out_pc_cb(*this) +{ + m_intr[PORT_A] = m_intr[PORT_B] = 0; + m_control = 0; +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void i8255_device::device_start() +{ + // resolve callbacks + m_in_pa_cb.resolve_safe(0); + m_in_pb_cb.resolve_safe(0); + m_in_pc_cb.resolve_safe(0); + m_out_pa_cb.resolve_safe(); + m_out_pb_cb.resolve_safe(); + m_out_pc_cb.resolve_safe(); + + // register for state saving + save_item(NAME(m_control)); + save_item(NAME(m_output)); + save_item(NAME(m_input)); + save_item(NAME(m_ibf)); + save_item(NAME(m_obf)); + save_item(NAME(m_inte)); + save_item(NAME(m_inte1)); + save_item(NAME(m_inte2)); + save_item(NAME(m_intr)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void i8255_device::device_reset() +{ + set_mode(0x9b); +} + + +//------------------------------------------------- +// read_mode0 - +//------------------------------------------------- + +UINT8 i8255_device::read_mode0(int port) +{ + UINT8 data = 0; + + if (port_mode(port) == MODE_OUTPUT) + { + // read data from output latch + data = m_output[port]; + } + else + { + // read data from port + data = (port == PORT_A) ? m_in_pa_cb(0) : ((port == PORT_B) ? m_in_pb_cb(0) : m_in_pc_cb(0)); + } + + return data; +} + + +//------------------------------------------------- +// read_mode1 - +//------------------------------------------------- + +UINT8 i8255_device::read_mode1(int port) +{ + UINT8 data = 0; + + if (port_mode(port) == MODE_OUTPUT) + { + // read data from output latch + data = m_output[port]; + } + else + { + // read data from input latch + data = m_input[port]; + + // clear input buffer full flag + set_ibf(port, 0); + + // clear interrupt + set_intr(port, 0); + + // clear input latch + m_input[port] = 0; + } + + return data; +} + + +//------------------------------------------------- +// read_mode2 - +//------------------------------------------------- + +UINT8 i8255_device::read_mode2() +{ + UINT8 data = 0; + + // read data from input latch + data = m_input[PORT_A]; + + // clear input buffer full flag + set_ibf(PORT_A, 0); + + // clear interrupt + set_intr(PORT_A, 0); + + // clear input latch + m_input[PORT_A] = 0; + + return data; +} + + +//------------------------------------------------- +// read_pc - +//------------------------------------------------- + +UINT8 i8255_device::read_pc() +{ + UINT8 data = 0; + UINT8 mask = 0; + UINT8 b_mask = 0x0f; + + // PC upper + switch (group_mode(GROUP_A)) + { + case MODE_0: + if (port_c_upper_mode() == MODE_OUTPUT) + { + // read data from output latch + data |= m_output[PORT_C] & 0xf0; + } + else + { + // read data from port + mask |= 0xf0; + } + break; + + case MODE_1: + data |= m_intr[PORT_A] ? 0x08 : 0x00; + + if (port_mode(PORT_A) == MODE_OUTPUT) + { + data |= m_obf[PORT_A] ? 0x80 : 0x00; + data |= m_inte[PORT_A] ? 0x40 : 0x00; + mask |= 0x30; + } + else + { + data |= m_ibf[PORT_A] ? 0x20 : 0x00; + data |= m_inte[PORT_A] ? 0x10 : 0x00; + mask |= 0xc0; + } + break; + + case MODE_2: + b_mask = 0x07; + data |= m_intr[PORT_A] ? 0x08 : 0x00; + data |= m_inte2 ? 0x10 : 0x00; + data |= m_ibf[PORT_A] ? 0x20 : 0x00; + data |= m_inte1 ? 0x40 : 0x00; + data |= m_obf[PORT_A] ? 0x80 : 0x00; + break; + } + + // PC lower + switch (group_mode(GROUP_B)) + { + case MODE_0: + if (port_c_lower_mode() == MODE_OUTPUT) + { + // read data from output latch + data |= m_output[PORT_C] & b_mask; + } + else + { + // read data from port + mask |= b_mask; + } + break; + + case MODE_1: + data |= m_inte[PORT_B] ? 0x04 : 0x00; + data |= m_intr[PORT_B] ? 0x01 : 0x00; + + if (port_mode(PORT_B) == MODE_OUTPUT) + { + data |= m_obf[PORT_B] ? 0x02 : 0x00; + } + else + { + data |= m_ibf[PORT_B] ? 0x02 : 0x00; + } + } + + if (mask) + { + // read data from port + data |= m_in_pc_cb(0) & mask; + } + + return data; +} + + +//------------------------------------------------- +// write_mode0 - +//------------------------------------------------- + +void i8255_device::write_mode0(int port, UINT8 data) +{ + if (port_mode(port) == MODE_OUTPUT) + { + // latch output data + m_output[port] = data; + + // write data to port + if (port == PORT_A) + m_out_pa_cb((offs_t)0, m_output[port]); + else if (port == PORT_B) + m_out_pb_cb((offs_t)0, m_output[port]); + else + m_out_pc_cb((offs_t)0, m_output[port]); + } +} + + +//------------------------------------------------- +// write_mode1 - +//------------------------------------------------- + +void i8255_device::write_mode1(int port, UINT8 data) +{ + if (port_mode(port) == MODE_OUTPUT) + { + // latch output data + m_output[port] = data; + + // write data to port + if (port == PORT_A) + m_out_pa_cb((offs_t)0, m_output[port]); + else if (port == PORT_B) + m_out_pb_cb((offs_t)0, m_output[port]); + else + m_out_pc_cb((offs_t)0, m_output[port]); + + // set output buffer full flag + set_obf(port, 0); + + // clear interrupt + set_intr(port, 0); + } +} + + +//------------------------------------------------- +// write_mode2 - +//------------------------------------------------- + +void i8255_device::write_mode2(UINT8 data) +{ + // latch output data + m_output[PORT_A] = data; + + // write data to port + m_out_pa_cb((offs_t)0, data); + + // set output buffer full flag + set_obf(PORT_A, 0); + + // clear interrupt + set_intr(PORT_A, 0); +} + + +//------------------------------------------------- +// output_pc - +//------------------------------------------------- + +void i8255_device::output_pc() +{ + UINT8 data = 0; + UINT8 mask = 0; + UINT8 b_mask = 0x0f; + + // PC upper + switch (group_mode(GROUP_A)) + { + case MODE_0: + if (port_c_upper_mode() == MODE_OUTPUT) + { + mask |= 0xf0; + } + else + { + // TTL inputs float high + data |= 0xf0; + } + break; + + case MODE_1: + data |= m_intr[PORT_A] ? 0x08 : 0x00; + + if (port_mode(PORT_A) == MODE_OUTPUT) + { + data |= m_obf[PORT_A] ? 0x80 : 0x00; + mask |= 0x30; + } + else + { + data |= m_ibf[PORT_A] ? 0x20 : 0x00; + mask |= 0xc0; + } + break; + + case MODE_2: + b_mask = 0x07; + data |= m_intr[PORT_A] ? 0x08 : 0x00; + data |= m_ibf[PORT_A] ? 0x20 : 0x00; + data |= m_obf[PORT_A] ? 0x80 : 0x00; + break; + } + + // PC lower + switch (group_mode(GROUP_B)) + { + case MODE_0: + if (port_c_lower_mode() == MODE_OUTPUT) + { + mask |= b_mask; + } + else + { + // TTL inputs float high + data |= b_mask; + } + break; + + case MODE_1: + data |= m_intr[PORT_B] ? 0x01 : 0x00; + + if (port_mode(PORT_B) == MODE_OUTPUT) + { + data |= m_obf[PORT_B] ? 0x02 : 0x00; + } + else + { + data |= m_ibf[PORT_B] ? 0x02 : 0x00; + } + } + + data |= m_output[PORT_C] & mask; + + m_out_pc_cb((offs_t)0, data); +} + + +//------------------------------------------------- +// set_mode - +//------------------------------------------------- + +void i8255_device::set_mode(UINT8 data) +{ + m_control = data; + + // group A + m_output[PORT_A] = 0; + m_input[PORT_A] = 0; + m_ibf[PORT_A] = 0; + m_obf[PORT_A] = 1; + m_inte[PORT_A] = 0; + m_inte1 = 0; + m_inte2 = 0; + + if (port_mode(PORT_A) == MODE_OUTPUT) + { + m_out_pa_cb((offs_t)0, m_output[PORT_A]); + } + else + { + // TTL inputs float high + m_out_pa_cb((offs_t)0, 0xff); + } + + if (LOG) + { + logerror("I8255 '%s' Group A Mode: %u\n", tag(), group_mode(GROUP_A)); + logerror("I8255 '%s' Port A Mode: %s\n", tag(), (port_mode(PORT_A) == MODE_OUTPUT) ? "output" : "input"); + logerror("I8255 '%s' Port C Upper Mode: %s\n", tag(), (port_c_upper_mode() == MODE_OUTPUT) ? "output" : "input"); + logerror("I8255 '%s' Group B Mode: %u\n", tag(), group_mode(GROUP_B)); + logerror("I8255 '%s' Port B Mode: %s\n", tag(), (port_mode(PORT_B) == MODE_OUTPUT) ? "output" : "input"); + logerror("I8255 '%s' Port C Lower Mode: %s\n", tag(), (port_c_lower_mode() == MODE_OUTPUT) ? "output" : "input"); + } + + // group B + m_output[PORT_B] = 0; + m_input[PORT_B] = 0; + m_ibf[PORT_B] = 0; + m_obf[PORT_B] = 1; + m_inte[PORT_B] = 0; + + if (port_mode(PORT_B) == MODE_OUTPUT) + { + m_out_pb_cb((offs_t)0, m_output[PORT_B]); + } + else + { + // TTL inputs float high + m_out_pb_cb((offs_t)0, 0xff); + } + + m_output[PORT_C] = 0; + m_input[PORT_C] = 0; + + output_pc(); +} + + +//------------------------------------------------- +// set_pc_bit - +//------------------------------------------------- + +void i8255_device::set_pc_bit(int bit, int state) +{ + // set output latch bit + m_output[PORT_C] &= ~(1 << bit); + m_output[PORT_C] |= state << bit; + + switch (group_mode(GROUP_A)) + { + case MODE_1: + if (port_mode(PORT_A) == MODE_OUTPUT) + { + switch (bit) + { + case 3: set_intr(PORT_A, state); break; + case 6: set_inte(PORT_A, state); break; + case 7: set_obf(PORT_A, state); break; + default: break; + } + } + else + { + switch (bit) + { + case 3: set_intr(PORT_A, state); break; + case 4: set_inte(PORT_A, state); break; + case 5: set_ibf(PORT_A, state); break; + default: break; + } + } + break; + + case MODE_2: + switch (bit) + { + case 3: set_intr(PORT_A, state); break; + case 4: set_inte2(state); break; + case 5: set_ibf(PORT_A, state); break; + case 6: set_inte1(state); break; + case 7: set_obf(PORT_A, state); break; + default: break; + } + break; + } + + if (group_mode(GROUP_B) == MODE_1) + { + switch (bit) + { + case 0: set_intr(PORT_B, state); break; + case 1: + if (port_mode(PORT_B) == MODE_OUTPUT) + set_obf(PORT_B, state); + else + set_ibf(PORT_B, state); + break; + case 2: set_inte(PORT_B, state); break; + default: break; + } + } + + output_pc(); +} + + +//------------------------------------------------- +// read - +//------------------------------------------------- + +READ8_MEMBER( i8255_device::read ) +{ + UINT8 data = 0; + + switch (offset & 0x03) + { + case PORT_A: + switch (group_mode(GROUP_A)) + { + case MODE_0: data = read_mode0(PORT_A); break; + case MODE_1: data = read_mode1(PORT_A); break; + case MODE_2: data = read_mode2(); break; + } + if (LOG) logerror("I8255 '%s' Port A Read: %02x\n", tag(), data); + break; + + case PORT_B: + switch (group_mode(GROUP_B)) + { + case MODE_0: data = read_mode0(PORT_B); break; + case MODE_1: data = read_mode1(PORT_B); break; + } + if (LOG) logerror("I8255 '%s' Port B Read: %02x\n", tag(), data); + break; + + case PORT_C: + data = read_pc(); + if (LOG) logerror("I8255 '%s' Port C Read: %02x\n", tag(), data); + break; + + case CONTROL: + data = m_control; + if (LOG) logerror("I8255 '%s' Mode Control Word Read: %02x\n", tag(), data); + break; + } + + return data; +} + + +//------------------------------------------------- +// write - +//------------------------------------------------- + +WRITE8_MEMBER( i8255_device::write ) +{ + switch (offset & 0x03) + { + case PORT_A: + if (LOG) logerror("I8255 '%s' Port A Write: %02x\n", tag(), data); + + switch (group_mode(GROUP_A)) + { + case MODE_0: write_mode0(PORT_A, data); break; + case MODE_1: write_mode1(PORT_A, data); break; + case MODE_2: write_mode2(data); break; + } + break; + + case PORT_B: + if (LOG) logerror("I8255 '%s' Port B Write: %02x\n", tag(), data); + + switch (group_mode(GROUP_B)) + { + case MODE_0: write_mode0(PORT_B, data); break; + case MODE_1: write_mode1(PORT_B, data); break; + } + break; + + case PORT_C: + if (LOG) logerror("I8255 '%s' Port C Write: %02x\n", tag(), data); + + m_output[PORT_C] = data; + output_pc(); + break; + + case CONTROL: + if (data & CONTROL_MODE_SET) + { + if (LOG) logerror("I8255 '%s' Mode Control Word: %02x\n", tag(), data); + + set_mode(data); + } + else + { + int bit = (data >> 1) & 0x07; + int state = BIT(data, 0); + + if (LOG) logerror("I8255 '%s' %s Port C Bit %u\n", tag(), state ? "Set" : "Reset", bit); + + set_pc_bit(bit, state); + } + break; + } +} + + +//------------------------------------------------- +// pa_r - +//------------------------------------------------- + +READ8_MEMBER( i8255_device::pa_r ) +{ + return pa_r(); +} + + +//------------------------------------------------- +// pb_r - port A read +//------------------------------------------------- + +UINT8 i8255_device::pa_r() +{ + UINT8 data = 0xff; + + if (port_mode(PORT_A) == MODE_OUTPUT) + { + data = m_output[PORT_A]; + } + + return data; +} + + +//------------------------------------------------- +// pb_r - +//------------------------------------------------- + +READ8_MEMBER( i8255_device::pb_r ) +{ + return pb_r(); +} + + +//------------------------------------------------- +// pb_r - port B read +//------------------------------------------------- + +UINT8 i8255_device::pb_r() +{ + UINT8 data = 0xff; + + if (port_mode(PORT_B) == MODE_OUTPUT) + { + data = m_output[PORT_B]; + } + + return data; +} + + +//------------------------------------------------- +// pc2_w - +//------------------------------------------------- + +WRITE_LINE_MEMBER( i8255_device::pc2_w ) +{ + if (group_mode(GROUP_B) == 1) + { + if (port_mode(PORT_B) == MODE_OUTPUT) + { + // port B acknowledge + if (!m_obf[PORT_B] && !state) + { + if (LOG) logerror("I8255 '%s' Port B Acknowledge\n", tag()); + + // clear output buffer flag + set_obf(PORT_B, 1); + } + } + else + { + // port B strobe + if (!m_ibf[PORT_B] && !state) + { + if (LOG) logerror("I8255 '%s' Port B Strobe\n", tag()); + + // read port into latch + m_input[PORT_B] = m_in_pb_cb(0); + + // set input buffer flag + set_ibf(PORT_B, 1); + } + } + } +} + + +//------------------------------------------------- +// pc4_w - +//------------------------------------------------- + +WRITE_LINE_MEMBER( i8255_device::pc4_w ) +{ + if ((group_mode(GROUP_A) == 2) || ((group_mode(GROUP_A) == 1) && (port_mode(PORT_A) == MODE_INPUT))) + { + // port A strobe + if (!m_ibf[PORT_A] && !state) + { + if (LOG) logerror("I8255 '%s' Port A Strobe\n", tag()); + + // read port into latch + m_input[PORT_A] = m_in_pa_cb(0); + + // set input buffer flag + set_ibf(PORT_A, 1); + } + } +} + + +//------------------------------------------------- +// pc6_w - +//------------------------------------------------- + +WRITE_LINE_MEMBER( i8255_device::pc6_w ) +{ + if ((group_mode(GROUP_A) == 2) || ((group_mode(GROUP_A) == 1) && (port_mode(PORT_A) == MODE_OUTPUT))) + { + // port A acknowledge + if (!m_obf[PORT_A] && !state) + { + if (LOG) logerror("I8255 '%s' Port A Acknowledge\n", tag()); + + // clear output buffer flag + set_obf(PORT_A, 1); + } + } +} diff --git a/src/devices/machine/i8255.h b/src/devices/machine/i8255.h new file mode 100644 index 00000000000..c232b2105e0 --- /dev/null +++ b/src/devices/machine/i8255.h @@ -0,0 +1,148 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Intel 8255(A) Programmable Peripheral Interface emulation + +********************************************************************** + _____ _____ + PA3 1 |* \_/ | 40 PA4 + PA2 2 | | 39 PA5 + PA1 3 | | 38 PA6 + PA0 4 | | 37 PA7 + _RD 5 | | 36 WR + _CS 6 | | 35 RESET + GND 7 | | 34 D0 + A1 8 | | 33 D1 + A0 9 | | 32 D2 + PC7 10 | 8255 | 31 D3 + PC6 11 | 8255A | 30 D4 + PC5 12 | | 29 D5 + PC4 13 | | 28 D6 + PC0 14 | | 27 D7 + PC1 15 | | 26 Vcc + PC2 16 | | 25 PB7 + PC3 17 | | 24 PB6 + PB0 18 | | 23 PB5 + PB1 19 | | 22 PB4 + PB2 20 |_____________| 21 PB3 + +**********************************************************************/ + +#pragma once + +#ifndef __I8255__ +#define __I8255__ + +#include "emu.h" + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_I8255_IN_PORTA_CB(_devcb) \ + devcb = &i8255_device::set_in_pa_callback(*device, DEVCB_##_devcb); + +#define MCFG_I8255_IN_PORTB_CB(_devcb) \ + devcb = &i8255_device::set_in_pb_callback(*device, DEVCB_##_devcb); + +#define MCFG_I8255_IN_PORTC_CB(_devcb) \ + devcb = &i8255_device::set_in_pc_callback(*device, DEVCB_##_devcb); + +#define MCFG_I8255_OUT_PORTA_CB(_devcb) \ + devcb = &i8255_device::set_out_pa_callback(*device, DEVCB_##_devcb); + +#define MCFG_I8255_OUT_PORTB_CB(_devcb) \ + devcb = &i8255_device::set_out_pb_callback(*device, DEVCB_##_devcb); + +#define MCFG_I8255_OUT_PORTC_CB(_devcb) \ + devcb = &i8255_device::set_out_pc_callback(*device, DEVCB_##_devcb); + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> i8255_device + +class i8255_device : public device_t +{ +public: + // construction/destruction + i8255_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + template static devcb_base &set_in_pa_callback(device_t &device, _Object object) { return downcast(device).m_in_pa_cb.set_callback(object); } + template static devcb_base &set_in_pb_callback(device_t &device, _Object object) { return downcast(device).m_in_pb_cb.set_callback(object); } + template static devcb_base &set_in_pc_callback(device_t &device, _Object object) { return downcast(device).m_in_pc_cb.set_callback(object); } + template static devcb_base &set_out_pa_callback(device_t &device, _Object object) { return downcast(device).m_out_pa_cb.set_callback(object); } + template static devcb_base &set_out_pb_callback(device_t &device, _Object object) { return downcast(device).m_out_pb_cb.set_callback(object); } + template static devcb_base &set_out_pc_callback(device_t &device, _Object object) { return downcast(device).m_out_pc_cb.set_callback(object); } + + DECLARE_READ8_MEMBER( read ); + DECLARE_WRITE8_MEMBER( write ); + + DECLARE_READ8_MEMBER( pa_r ); + UINT8 pa_r(); + + DECLARE_READ8_MEMBER( pb_r ); + UINT8 pb_r(); + + DECLARE_WRITE_LINE_MEMBER( pc2_w ); + DECLARE_WRITE_LINE_MEMBER( pc4_w ); + DECLARE_WRITE_LINE_MEMBER( pc6_w ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + +private: + inline void check_interrupt(int port); + inline void set_ibf(int port, int state); + inline void set_obf(int port, int state); + inline void set_inte(int port, int state); + inline void set_inte1(int state); + inline void set_inte2(int state); + inline void set_intr(int port, int state); + inline int group_mode(int group); + inline int port_mode(int port); + inline int port_c_lower_mode(); + inline int port_c_upper_mode(); + + UINT8 read_mode0(int port); + UINT8 read_mode1(int port); + UINT8 read_mode2(); + UINT8 read_pc(); + void write_mode0(int port, UINT8 data); + void write_mode1(int port, UINT8 data); + void write_mode2(UINT8 data); + void output_pc(); + void set_mode(UINT8 data); + void set_pc_bit(int bit, int state); + + devcb_read8 m_in_pa_cb; + devcb_read8 m_in_pb_cb; + devcb_read8 m_in_pc_cb; + + devcb_write8 m_out_pa_cb; + devcb_write8 m_out_pb_cb; + devcb_write8 m_out_pc_cb; + + UINT8 m_control; // mode control word + UINT8 m_output[3]; // output latch + UINT8 m_input[3]; // input latch + + int m_ibf[2]; // input buffer full flag + int m_obf[2]; // output buffer full flag, negative logic + int m_inte[2]; // interrupt enable + int m_inte1; // interrupt enable + int m_inte2; // interrupt enable + int m_intr[2]; // interrupt +}; + + +// device type definition +extern const device_type I8255; +extern const device_type I8255A; + + +#endif diff --git a/src/devices/machine/i8257.c b/src/devices/machine/i8257.c new file mode 100644 index 00000000000..23abcc3915c --- /dev/null +++ b/src/devices/machine/i8257.c @@ -0,0 +1,668 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder,Carl +/*************************************************************************** + + Intel 8257 DMA Controller emulation + +***************************************************************************/ + +#include "i8257.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type I8257 = &device_creator; + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define LOG 0 + + +enum +{ + REGISTER_ADDRESS = 0, + REGISTER_WORD_COUNT, + REGISTER_STATUS = 8, + REGISTER_MODE = REGISTER_STATUS +}; + + +#define MODE_CHAN_ENABLE(x) BIT(m_transfer_mode, x) +#define MODE_ROTATING_PRIORITY BIT(m_transfer_mode, 4) +#define MODE_EXTENDED_WRITE BIT(m_transfer_mode, 5) +#define MODE_TC_STOP BIT(m_transfer_mode, 6) +#define MODE_AUTOLOAD BIT(m_transfer_mode, 7) +#define MODE_TRANSFER_MASK (m_channel[m_current_channel].m_mode) +#define MODE_TRANSFER_VERIFY 0 +#define MODE_TRANSFER_WRITE 1 +#define MODE_TRANSFER_READ 2 + + +enum +{ + STATE_SI, + STATE_S0, + STATE_S1, + STATE_S2, + STATE_S3, + STATE_SW, + STATE_S4 +}; + + + +//************************************************************************** +// INLINE HELPERS +//************************************************************************** + +//------------------------------------------------- +// dma_request - +//------------------------------------------------- + +inline void i8257_device::dma_request(int channel, int state) +{ + if (LOG) logerror("I8257 '%s' Channel %u DMA Request: %u\n", tag(), channel, state); + + if (state) + { + m_request |= 1 << channel; + } + else + { + m_request &= ~(1 << channel); + } + trigger(1); +} + + +//------------------------------------------------- +// is_request_active - +//------------------------------------------------- + +inline bool i8257_device::is_request_active(int channel) +{ + return (BIT(m_request, channel) && MODE_CHAN_ENABLE(channel)) ? true : false; +} + +//------------------------------------------------- +// set_hreq +//------------------------------------------------- + +inline void i8257_device::set_hreq(int state) +{ + if (m_hreq != state) + { + m_out_hrq_cb(state); + m_hreq = state; + } +} + + +//------------------------------------------------- +// set_tc - +//------------------------------------------------- + +inline void i8257_device::set_tc(int state) +{ + if (m_tc != state) + { + m_out_tc_cb(state); + + m_tc = state; + } +} + + +//------------------------------------------------- +// set_dack - dack is active low +//------------------------------------------------- + +inline void i8257_device::set_dack() +{ + m_out_dack_0_cb(m_current_channel != 0); + m_out_dack_1_cb(m_current_channel != 1); + m_out_dack_2_cb(m_current_channel != 2); + m_out_dack_3_cb(m_current_channel != 3); +} + + +//------------------------------------------------- +// dma_read - +//------------------------------------------------- + +inline void i8257_device::dma_read() +{ + offs_t offset = m_channel[m_current_channel].m_address; + + switch (MODE_TRANSFER_MASK) + { + case MODE_TRANSFER_VERIFY: + case MODE_TRANSFER_WRITE: + switch(m_current_channel) + { + case 0: + m_temp = m_in_ior_0_cb(offset); + break; + case 1: + m_temp = m_in_ior_1_cb(offset); + break; + case 2: + m_temp = m_in_ior_2_cb(offset); + break; + case 3: + m_temp = m_in_ior_3_cb(offset); + break; + } + break; + + case MODE_TRANSFER_READ: + m_temp = m_in_memr_cb(offset); + break; + } + +} + + +//------------------------------------------------- +// dma_write - +//------------------------------------------------- + +inline void i8257_device::dma_write() +{ + offs_t offset = m_channel[m_current_channel].m_address; + + switch (MODE_TRANSFER_MASK) + { + case MODE_TRANSFER_VERIFY: { + UINT8 v1 = m_in_memr_cb(offset); + if(0 && m_temp != v1) + logerror("%s: verify error %02x vs. %02x\n", tag(), m_temp, v1); + break; + } + + case MODE_TRANSFER_WRITE: + m_out_memw_cb(offset, m_temp); + break; + + case MODE_TRANSFER_READ: + switch(m_current_channel) + { + case 0: + m_out_iow_0_cb(offset, m_temp); + break; + case 1: + m_out_iow_1_cb(offset, m_temp); + break; + case 2: + m_out_iow_2_cb(offset, m_temp); + break; + case 3: + m_out_iow_3_cb(offset, m_temp); + break; + } + break; + } +} + + +//------------------------------------------------- +// end_of_process - +//------------------------------------------------- + +inline void i8257_device::advance() +{ + bool tc = (m_channel[m_current_channel].m_count == 0); + bool al = (MODE_AUTOLOAD && (m_current_channel == 2)); + + if(tc) + { + m_status |= 1 << m_current_channel; + m_request &= ~(1 << m_current_channel); // docs imply this isn't right but pc-8001 works better with it + set_tc(1); + + if(al) + { + // autoinitialize + m_channel[2].m_address = m_channel[3].m_address; + m_channel[2].m_count = m_channel[3].m_count; + m_channel[2].m_mode = m_channel[3].m_mode; + } + else if(MODE_TC_STOP) + // disable channel + m_transfer_mode &= ~(1 << m_current_channel); + } + + if(!(al && tc)) + { + m_channel[m_current_channel].m_count--; + m_channel[m_current_channel].m_count &= 0x3fff; + m_channel[m_current_channel].m_address++; + } +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// i8257_device - constructor +//------------------------------------------------- + +i8257_device::i8257_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, I8257, "Intel 8257", tag, owner, clock, "i8257", __FILE__), + device_execute_interface(mconfig, *this), + m_icount(0), + m_reverse_rw(0), + m_tc(false), + m_msb(0), + m_hreq(CLEAR_LINE), + m_hack(0), + m_ready(1), + m_state(0), + m_current_channel(0), + m_last_channel(0), + m_transfer_mode(0), + m_status(0), + m_request(0), + m_temp(0), + m_out_hrq_cb(*this), + m_out_tc_cb(*this), + m_in_memr_cb(*this), + m_out_memw_cb(*this), + m_in_ior_0_cb(*this), + m_in_ior_1_cb(*this), + m_in_ior_2_cb(*this), + m_in_ior_3_cb(*this), + m_out_iow_0_cb(*this), + m_out_iow_1_cb(*this), + m_out_iow_2_cb(*this), + m_out_iow_3_cb(*this), + m_out_dack_0_cb(*this), + m_out_dack_1_cb(*this), + m_out_dack_2_cb(*this), + m_out_dack_3_cb(*this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void i8257_device::device_start() +{ + // set our instruction counter + m_icountptr = &m_icount; + + // resolve callbacks + m_out_hrq_cb.resolve_safe(); + m_out_tc_cb.resolve_safe(); + m_in_memr_cb.resolve_safe(0); + m_out_memw_cb.resolve_safe(); + m_in_ior_0_cb.resolve_safe(0); + m_in_ior_1_cb.resolve_safe(0); + m_in_ior_2_cb.resolve_safe(0); + m_in_ior_3_cb.resolve_safe(0); + m_out_iow_0_cb.resolve_safe(); + m_out_iow_1_cb.resolve_safe(); + m_out_iow_2_cb.resolve_safe(); + m_out_iow_3_cb.resolve_safe(); + m_out_dack_0_cb.resolve_safe(); + m_out_dack_1_cb.resolve_safe(); + m_out_dack_2_cb.resolve_safe(); + m_out_dack_3_cb.resolve_safe(); + + // state saving + save_item(NAME(m_msb)); + save_item(NAME(m_hreq)); + save_item(NAME(m_hack)); + save_item(NAME(m_ready)); + save_item(NAME(m_state)); + save_item(NAME(m_current_channel)); + save_item(NAME(m_last_channel)); + save_item(NAME(m_transfer_mode)); + save_item(NAME(m_status)); + save_item(NAME(m_request)); + + save_item(NAME(m_channel[0].m_address)); + save_item(NAME(m_channel[0].m_count)); + save_item(NAME(m_channel[0].m_mode)); + save_item(NAME(m_channel[1].m_address)); + save_item(NAME(m_channel[1].m_count)); + save_item(NAME(m_channel[1].m_mode)); + save_item(NAME(m_channel[2].m_address)); + save_item(NAME(m_channel[2].m_count)); + save_item(NAME(m_channel[2].m_mode)); + save_item(NAME(m_channel[3].m_address)); + save_item(NAME(m_channel[3].m_count)); + save_item(NAME(m_channel[3].m_mode)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void i8257_device::device_reset() +{ + m_state = STATE_SI; + m_transfer_mode = 0; + m_status = 0; + m_request = 0; + m_msb = 0; + m_current_channel = -1; + m_last_channel = 3; + m_hreq = -1; + m_tc = 0; + + for (int i = 0; i < 4; i++) + { + m_channel[i].m_address = 0; + m_channel[i].m_count = 0; + m_channel[i].m_mode = 0; + } + set_hreq(0); + set_dack(); +} + +bool i8257_device::next_channel() +{ + int priority[] = { 0, 1, 2, 3 }; + + if (MODE_ROTATING_PRIORITY) + { + int last_channel = m_last_channel; + + for (int channel = 3; channel >= 0; channel--) + { + priority[channel] = last_channel; + last_channel--; + if (last_channel < 0) last_channel = 3; + } + } + + for (int channel = 0; channel < 4; channel++) + { + if (is_request_active(priority[channel])) + { + m_current_channel = m_last_channel = priority[channel]; + return true; + } + } + return false; +} + + +//------------------------------------------------- +// execute_run - +//------------------------------------------------- + +void i8257_device::execute_run() +{ + do + { + switch (m_state) + { + case STATE_SI: + set_tc(0); + if(next_channel()) + m_state = STATE_S0; + else + { + suspend_until_trigger(1, true); + m_icount = 0; + } + break; + + case STATE_S0: + set_hreq(1); + + if (m_hack) + { + m_state = STATE_S1; + } + else + { + suspend_until_trigger(1, true); + m_icount = 0; + } + break; + + case STATE_S1: + set_tc(0); + m_state = STATE_S2; + break; + + case STATE_S2: + set_dack(); + m_state = STATE_S3; + break; + + case STATE_S3: + dma_read(); + + if (MODE_EXTENDED_WRITE) + { + dma_write(); + } + + m_state = m_ready ? STATE_S4 : STATE_SW; + break; + + case STATE_SW: + m_state = m_ready ? STATE_S4 : STATE_SW; + break; + + case STATE_S4: + if (!MODE_EXTENDED_WRITE) + { + dma_write(); + } + advance(); + + if(next_channel()) + m_state = STATE_S1; + else + { + set_hreq(0); + m_current_channel = -1; + m_state = STATE_SI; + set_dack(); + } + break; + } + m_icount--; + } while (m_icount > 0); +} + + +//------------------------------------------------- +// read - +//------------------------------------------------- + +READ8_MEMBER( i8257_device::read ) +{ + UINT8 data = 0; + + if (!BIT(offset, 3)) + { + int channel = (offset >> 1) & 0x03; + + switch (offset & 0x01) + { + case REGISTER_ADDRESS: + if (m_msb) + { + data = m_channel[channel].m_address >> 8; + } + else + { + data = m_channel[channel].m_address & 0xff; + } + break; + + case REGISTER_WORD_COUNT: + if (m_msb) + { + data = (m_channel[channel].m_count >> 8); + if(m_reverse_rw && m_channel[channel].m_mode) + data |= (m_channel[channel].m_mode == 1) ? 0x80 : 0x40; + else + data |= (m_channel[channel].m_mode << 6); + } + else + { + data = m_channel[channel].m_count & 0xff; + } + break; + } + + m_msb = !m_msb; + } + else if(offset == REGISTER_STATUS) + { + data = m_status; + + // clear TC bits + m_status &= 0xf0; + } + + return data; +} + + +//------------------------------------------------- +// write - +//------------------------------------------------- + +WRITE8_MEMBER( i8257_device::write ) +{ + if (!BIT(offset, 3)) + { + int channel = (offset >> 1) & 0x03; + + switch (offset & 0x01) + { + case REGISTER_ADDRESS: + if (m_msb) + { + m_channel[channel].m_address = (data << 8) | (m_channel[channel].m_address & 0xff); + if(MODE_AUTOLOAD && (channel == 2)) + m_channel[3].m_address = (data << 8) | (m_channel[3].m_address & 0xff); + } + else + { + m_channel[channel].m_address = (m_channel[channel].m_address & 0xff00) | data; + if(MODE_AUTOLOAD && (channel == 2)) + m_channel[3].m_address = (m_channel[3].m_address & 0xff00) | data; + } + break; + + case REGISTER_WORD_COUNT: + if (m_msb) + { + m_channel[channel].m_count = ((data & 0x3f) << 8) | (m_channel[channel].m_count & 0xff); + m_channel[channel].m_mode = (data >> 6); + + if(m_reverse_rw && m_channel[channel].m_mode) + m_channel[channel].m_mode = (m_channel[channel].m_mode == 1) ? 2 : 1; + + if(MODE_AUTOLOAD && (channel == 2)) + { + m_channel[3].m_count = ((data & 0x3f) << 8) | (m_channel[3].m_count & 0xff); + m_channel[3].m_mode = m_channel[2].m_mode; + } + } + else + { + m_channel[channel].m_count = (m_channel[channel].m_count & 0xff00) | data; + if(MODE_AUTOLOAD && (channel == 2)) + m_channel[3].m_count = (m_channel[3].m_count & 0xff00) | data; + } + break; + } + + m_msb = !m_msb; + } + else if(offset == REGISTER_MODE) + { + m_transfer_mode = data; + + if (LOG) logerror("I8257 '%s' Command Register: %02x\n", tag(), m_transfer_mode); + } + trigger(1); +} + + +//------------------------------------------------- +// hlda_w - hold acknowledge +//------------------------------------------------- + +WRITE_LINE_MEMBER( i8257_device::hlda_w ) +{ + if (LOG) logerror("I8257 '%s' Hold Acknowledge: %u\n", tag(), state); + + m_hack = state; + trigger(1); +} + + +//------------------------------------------------- +// ready_w - ready +//------------------------------------------------- + +WRITE_LINE_MEMBER( i8257_device::ready_w ) +{ + if (LOG) logerror("I8257 '%s' Ready: %u\n", tag(), state); + + m_ready = state; +} + + +//------------------------------------------------- +// dreq0_w - DMA request for channel 0 +//------------------------------------------------- + +WRITE_LINE_MEMBER( i8257_device::dreq0_w ) +{ + dma_request(0, state); +} + + +//------------------------------------------------- +// dreq0_w - DMA request for channel 1 +//------------------------------------------------- + +WRITE_LINE_MEMBER( i8257_device::dreq1_w ) +{ + dma_request(1, state); +} + + +//------------------------------------------------- +// dreq1_w - DMA request for channel 2 +//------------------------------------------------- + +WRITE_LINE_MEMBER( i8257_device::dreq2_w ) +{ + dma_request(2, state); +} + + +//------------------------------------------------- +// dreq3_w - DMA request for channel 3 +//------------------------------------------------- + +WRITE_LINE_MEMBER( i8257_device::dreq3_w ) +{ + dma_request(3, state); +} diff --git a/src/devices/machine/i8257.h b/src/devices/machine/i8257.h new file mode 100644 index 00000000000..9ab509d38e7 --- /dev/null +++ b/src/devices/machine/i8257.h @@ -0,0 +1,207 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/*************************************************************************** + + Intel 8257 DMA Controller emulation + +**************************************************************************** + _____ _____ + _I/OR 1 |* \_/ | 40 A7 + _I/OW 2 | | 39 A6 + _MEMR 3 | | 38 A5 + _MEMW 4 | | 37 A4 + MARK 5 | | 36 TC + READY 6 | | 35 A3 + HLDA 7 | | 34 A2 + ADSTB 8 | | 33 A1 + AEN 9 | | 32 A0 + HRQ 10 | 8257 | 31 Vcc + _CS 11 | | 30 D0 + CLK 12 | | 29 D1 + RESET 13 | | 28 D2 + _DACK2 14 | | 27 D3 + _DACK3 15 | | 26 D4 + DRQ3 16 | | 25 _DACK0 + DRQ2 17 | | 24 _DACK1 + DRQ1 18 | | 23 D5 + DRQ0 19 | | 22 D6 + GND 20 |_____________| 21 D7 + +***************************************************************************/ + +#pragma once + +#ifndef __I8257__ +#define __I8257__ + +#include "emu.h" + + + +/*************************************************************************** + DEVICE CONFIGURATION MACROS +***************************************************************************/ + +#define MCFG_I8257_OUT_HRQ_CB(_devcb) \ + devcb = &i8257_device::set_out_hrq_callback(*device, DEVCB_##_devcb); + +#define MCFG_I8257_OUT_TC_CB(_devcb) \ + devcb = &i8257_device::set_out_tc_callback(*device, DEVCB_##_devcb); + +#define MCFG_I8257_IN_MEMR_CB(_devcb) \ + devcb = &i8257_device::set_in_memr_callback(*device, DEVCB_##_devcb); + +#define MCFG_I8257_OUT_MEMW_CB(_devcb) \ + devcb = &i8257_device::set_out_memw_callback(*device, DEVCB_##_devcb); + +#define MCFG_I8257_IN_IOR_0_CB(_devcb) \ + devcb = &i8257_device::set_in_ior_0_callback(*device, DEVCB_##_devcb); + +#define MCFG_I8257_IN_IOR_1_CB(_devcb) \ + devcb = &i8257_device::set_in_ior_1_callback(*device, DEVCB_##_devcb); + +#define MCFG_I8257_IN_IOR_2_CB(_devcb) \ + devcb = &i8257_device::set_in_ior_2_callback(*device, DEVCB_##_devcb); + +#define MCFG_I8257_IN_IOR_3_CB(_devcb) \ + devcb = &i8257_device::set_in_ior_3_callback(*device, DEVCB_##_devcb); + +#define MCFG_I8257_OUT_IOW_0_CB(_devcb) \ + devcb = &i8257_device::set_out_iow_0_callback(*device, DEVCB_##_devcb); + +#define MCFG_I8257_OUT_IOW_1_CB(_devcb) \ + devcb = &i8257_device::set_out_iow_1_callback(*device, DEVCB_##_devcb); + +#define MCFG_I8257_OUT_IOW_2_CB(_devcb) \ + devcb = &i8257_device::set_out_iow_2_callback(*device, DEVCB_##_devcb); + +#define MCFG_I8257_OUT_IOW_3_CB(_devcb) \ + devcb = &i8257_device::set_out_iow_3_callback(*device, DEVCB_##_devcb); + +#define MCFG_I8257_OUT_DACK_0_CB(_devcb) \ + devcb = &i8257_device::set_out_dack_0_callback(*device, DEVCB_##_devcb); + +#define MCFG_I8257_OUT_DACK_1_CB(_devcb) \ + devcb = &i8257_device::set_out_dack_1_callback(*device, DEVCB_##_devcb); + +#define MCFG_I8257_OUT_DACK_2_CB(_devcb) \ + devcb = &i8257_device::set_out_dack_2_callback(*device, DEVCB_##_devcb); + +#define MCFG_I8257_OUT_DACK_3_CB(_devcb) \ + devcb = &i8257_device::set_out_dack_3_callback(*device, DEVCB_##_devcb); + +// HACK: the radio86 and alikes require this, is it a bug in the soviet clone or is there something else happening? +#define MCFG_I8257_REVERSE_RW_MODE(_flag) \ + i8257_device::static_set_reverse_rw_mode(*device, _flag); + +// ======================> i8257_device + +class i8257_device : public device_t, + public device_execute_interface +{ +public: + // construction/destruction + i8257_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + DECLARE_READ8_MEMBER( read ); + DECLARE_WRITE8_MEMBER( write ); + + DECLARE_WRITE_LINE_MEMBER( hlda_w ); + DECLARE_WRITE_LINE_MEMBER( ready_w ); + + DECLARE_WRITE_LINE_MEMBER( dreq0_w ); + DECLARE_WRITE_LINE_MEMBER( dreq1_w ); + DECLARE_WRITE_LINE_MEMBER( dreq2_w ); + DECLARE_WRITE_LINE_MEMBER( dreq3_w ); + + template static devcb_base &set_out_hrq_callback(device_t &device, _Object object) { return downcast(device).m_out_hrq_cb.set_callback(object); } + template static devcb_base &set_out_tc_callback(device_t &device, _Object object) { return downcast(device).m_out_tc_cb.set_callback(object); } + + template static devcb_base &set_in_memr_callback(device_t &device, _Object object) { return downcast(device).m_in_memr_cb.set_callback(object); } + template static devcb_base &set_out_memw_callback(device_t &device, _Object object) { return downcast(device).m_out_memw_cb.set_callback(object); } + + template static devcb_base &set_in_ior_0_callback(device_t &device, _Object object) { return downcast(device).m_in_ior_0_cb.set_callback(object); } + template static devcb_base &set_in_ior_1_callback(device_t &device, _Object object) { return downcast(device).m_in_ior_1_cb.set_callback(object); } + template static devcb_base &set_in_ior_2_callback(device_t &device, _Object object) { return downcast(device).m_in_ior_2_cb.set_callback(object); } + template static devcb_base &set_in_ior_3_callback(device_t &device, _Object object) { return downcast(device).m_in_ior_3_cb.set_callback(object); } + + template static devcb_base &set_out_iow_0_callback(device_t &device, _Object object) { return downcast(device).m_out_iow_0_cb.set_callback(object); } + template static devcb_base &set_out_iow_1_callback(device_t &device, _Object object) { return downcast(device).m_out_iow_1_cb.set_callback(object); } + template static devcb_base &set_out_iow_2_callback(device_t &device, _Object object) { return downcast(device).m_out_iow_2_cb.set_callback(object); } + template static devcb_base &set_out_iow_3_callback(device_t &device, _Object object) { return downcast(device).m_out_iow_3_cb.set_callback(object); } + + template static devcb_base &set_out_dack_0_callback(device_t &device, _Object object) { return downcast(device).m_out_dack_0_cb.set_callback(object); } + template static devcb_base &set_out_dack_1_callback(device_t &device, _Object object) { return downcast(device).m_out_dack_1_cb.set_callback(object); } + template static devcb_base &set_out_dack_2_callback(device_t &device, _Object object) { return downcast(device).m_out_dack_2_cb.set_callback(object); } + template static devcb_base &set_out_dack_3_callback(device_t &device, _Object object) { return downcast(device).m_out_dack_3_cb.set_callback(object); } + + static void static_set_reverse_rw_mode(device_t &device, bool flag) { downcast(device).m_reverse_rw = flag; } +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void execute_run(); + + int m_icount; + +private: + inline void dma_request(int channel, int state); + inline bool is_request_active(int channel); + inline void set_hreq(int state); + inline void set_dack(); + inline void dma_read(); + inline void dma_write(); + inline void advance(); + inline void set_tc(int state); + bool next_channel(); + + bool m_reverse_rw; + bool m_tc; + int m_msb; + int m_hreq; + int m_hack; + int m_ready; + int m_state; + int m_current_channel; + int m_last_channel; + UINT8 m_transfer_mode; + UINT8 m_status; + UINT8 m_request; + UINT8 m_temp; + + devcb_write_line m_out_hrq_cb; + devcb_write_line m_out_tc_cb; + + /* accessors to main memory */ + devcb_read8 m_in_memr_cb; + devcb_write8 m_out_memw_cb; + + /* channel accessors */ + devcb_read8 m_in_ior_0_cb; + devcb_read8 m_in_ior_1_cb; + devcb_read8 m_in_ior_2_cb; + devcb_read8 m_in_ior_3_cb; + devcb_write8 m_out_iow_0_cb; + devcb_write8 m_out_iow_1_cb; + devcb_write8 m_out_iow_2_cb; + devcb_write8 m_out_iow_3_cb; + devcb_write_line m_out_dack_0_cb; + devcb_write_line m_out_dack_1_cb; + devcb_write_line m_out_dack_2_cb; + devcb_write_line m_out_dack_3_cb; + + struct + { + UINT16 m_address; + UINT16 m_count; + UINT8 m_mode; + } m_channel[4]; +}; + + +// device type definition +extern const device_type I8257; + + + +#endif diff --git a/src/devices/machine/i8271.c b/src/devices/machine/i8271.c new file mode 100644 index 00000000000..08e5944f4fc --- /dev/null +++ b/src/devices/machine/i8271.c @@ -0,0 +1,1510 @@ +// license:BSD-3-Clause +// copyright-holders:Kevin Thacker +/* Intel 8271 Floppy Disc Controller */ +/* used in BBC Micro B,Acorn Atom */ +/* Jun 2000. Kev Thacker */ + +/* TODO: + + - Scan commands + - Check the commands work properly using a BBC disc copier program + - check if 0 is specified as number of sectors, how many sectors + is actually transfered + - deleted data functions (error if data finds deleted data?) +*/ + + +#include "emu.h" +#include "i8271.h" + +/* data request */ +#define I8271_FLAGS_DATA_REQUEST 0x01 +/* data direction. If 0x02, then it is from fdc to cpu, else +it is from cpu to fdc */ +#define I8271_FLAGS_DATA_DIRECTION 0x02 + +enum I8271_STATE_t +{ + I8271_STATE_EXECUTION_READ = 0, + I8271_STATE_EXECUTION_WRITE +}; + +/* commands accepted */ +#define I8271_COMMAND_SPECIFY 0x035 +#define I8271_COMMAND_SEEK 0x029 +#define I8271_COMMAND_READ_DRIVE_STATUS 0x02c +#define I8271_COMMAND_READ_SPECIAL_REGISTER 0x03d +#define I8271_COMMAND_WRITE_SPECIAL_REGISTER 0x03a +#define I8271_COMMAND_FORMAT 0x023 +#define I8271_COMMAND_READ_ID 0x01b +#define I8271_COMMAND_READ_DATA_SINGLE_RECORD 0x012 +#define I8271_COMMAND_READ_DATA_AND_DELETED_DATA_SINGLE_RECORD 0x016 +#define I8271_COMMAND_WRITE_DATA_SINGLE_RECORD 0x00a +#define I8271_COMMAND_WRITE_DELETED_DATA_SINGLE_RECORD 0x00e +#define I8271_COMMAND_VERIFY_DATA_AND_DELETED_DATA_SINGLE_RECORD 0x01e +#define I8271_COMMAND_READ_DATA_MULTI_RECORD 0x013 +#define I8271_COMMAND_READ_DATA_AND_DELETED_DATA_MULTI_RECORD 0x017 +#define I8271_COMMAND_WRITE_DATA_MULTI_RECORD 0x00b +#define I8271_COMMAND_WRITE_DELETED_DATA_MULTI_RECORD 0x00f +#define I8271_COMMAND_VERIFY_DATA_AND_DELETED_DATA_MULTI_RECORD 0x01f +#define I8271_COMMAND_SCAN_DATA 0x000 +#define I8271_COMMAND_SCAN_DATA_AND_DELETED_DATA 0x004 + +/* +#define I8271_COMMAND_READ_OPERATION (1<<4) +#define I8271_COMMAND_DELETED_DATA (1<<2) +#define I8271_COMMAND_MULTI_RECORD (1<<0) +*/ + + + +/* first parameter for specify command */ +#define I8271_SPECIFY_INITIALIZATION 0x0d +#define I8271_SPECIFY_LOAD_BAD_TRACKS_SURFACE_0 0x010 +#define I8271_SPECIFY_LOAD_BAD_TRACKS_SURFACE_1 0x018 + +/* first parameter for read/write special register */ +#define I8271_SPECIAL_REGISTER_SCAN_SECTOR_NUMBER 0x06 +#define I8271_SPECIAL_REGISTER_SCAN_MSB_OF_COUNT 0x014 +#define I8271_SPECIAL_REGISTER_SCAN_LSB_OF_COUNT 0x013 +#define I8271_SPECIAL_REGISTER_SURFACE_0_CURRENT_TRACK 0x012 +#define I8271_SPECIAL_REGISTER_SURFACE_1_CURRENT_TRACK 0x01a +#define I8271_SPECIAL_REGISTER_MODE_REGISTER 0x017 +#define I8271_SPECIAL_REGISTER_DRIVE_CONTROL_OUTPUT_PORT 0x023 +#define I8271_SPECIAL_REGISTER_DRIVE_CONTROL_INPUT_PORT 0x022 +#define I8271_SPECIAL_REGISTER_SURFACE_0_BAD_TRACK_1 0x010 +#define I8271_SPECIAL_REGISTER_SURFACE_0_BAD_TRACK_2 0x011 +#define I8271_SPECIAL_REGISTER_SURFACE_1_BAD_TRACK_1 0x018 +#define I8271_SPECIAL_REGISTER_SURFACE_1_BAD_TRACK_2 0x019 + + +/* status register bits */ +#define I8271_STATUS_COMMAND_BUSY 0x080 +#define I8271_STATUS_COMMAND_FULL 0x040 +#define I8271_STATUS_PARAMETER_FULL 0x020 +#define I8271_STATUS_RESULT_FULL 0x010 +#define I8271_STATUS_INT_REQUEST 0x008 +#define I8271_STATUS_NON_DMA_REQUEST 0x004 + +#define VERBOSE 0 + +#define LOG(x) do { if (VERBOSE) logerror x; } while (0) +#define FDC_LOG(x) do { if (VERBOSE) logerror("I8271: %s\n",x); } while (0) +#define FDC_LOG_COMMAND(x) do { if (VERBOSE) logerror("I8271: COMMAND %s\n",x); } while (0) + + +/* Device Interface */ + +const device_type I8271 = &device_creator; + +i8271_device::i8271_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, I8271, "Intel 8271", tag, owner, clock, "i8271", __FILE__), + m_write_irq(*this), + m_write_drq(*this), + m_floppy_tag1(NULL), + m_floppy_tag2(NULL), + m_flags(0), + m_state(0), + m_Command(0), + m_StatusRegister(0), + m_CommandRegister(0), + m_ResultRegister(0), + m_ParameterRegister(0), + m_ResetRegister(0), + m_data(0), + m_ParameterCount(0), + m_ParameterCountWritten(0), + m_Mode(0), + m_drive(0), + m_side(0), + m_drive_control_output(0), + m_drive_control_input(0), + m_StepRate(0), + m_HeadSettlingTime(0), + m_IndexCountBeforeHeadUnload(0), + m_HeadLoadTime(0), + //m_ID_C(0), + //m_ID_H(0), + m_ID_R(0), + m_ID_N(0), + m_data_id(0), + m_ExecutionPhaseTransferCount(0), + m_ExecutionPhaseCount(0), + m_Counter(0) + //m_data_direction(0) +{ + for (int i = 0; i < 8; i++ ) + { + m_CommandParameters[i] = 0; + } + + for (int i = 0; i < 2; i++ ) + { + m_CurrentTrack[i] = 0; + } + + for (int i = 0; i < 4; i++ ) + { + m_BadTracks[i] = 0; + } +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void i8271_device::device_start() +{ + m_write_irq.resolve_safe(); + m_write_drq.resolve_safe(); + + m_data_timer = timer_alloc(TIMER_DATA_CALLBACK); + m_command_complete_timer = timer_alloc(TIMER_TIMED_COMMAND_COMPLETE); + m_drive = 0; + m_pExecutionPhaseData = auto_alloc_array(machine(), char, 0x4000); + + m_floppy[0] = machine().device(m_floppy_tag1); + m_floppy[1] = machine().device(m_floppy_tag2); + + // register for state saving + /*save_item(NAME(m_flags)); + save_item(NAME(m_state)); + save_item(NAME(m_Command)); + save_item(NAME(m_StatusRegister)); + save_item(NAME(m_CommandRegister)); + save_item(NAME(m_ResultRegister)); + save_item(NAME(m_ParameterRegister)); + save_item(NAME(m_ResetRegister)); + save_item(NAME(m_data)); + //save_item(NAME(m_ParameterCount)); + //save_item(NAME(m_ParameterCountWritten)); + save_item(NAME(m_CommandParameters)); + //save_item(NAME(m_CurrentTrack)); + //save_item(NAME(m_BadTracks)); + //save_item(NAME(m_Mode)); + save_item(NAME(m_drive)); + save_item(NAME(m_side)); + save_item(NAME(m_drive_control_output)); + save_item(NAME(m_drive_control_input)); + //save_item(NAME(m_StepRate)); + //save_item(NAME(m_HeadSettlingTime)); + //save_item(NAME(m_IndexCountBeforeHeadUnload)); + //save_item(NAME(m_HeadLoadTime)); + save_item(NAME(m_ID_C)); + save_item(NAME(m_ID_H)); + save_item(NAME(m_ID_R)); + save_item(NAME(m_ID_N)); + save_item(NAME(m_data_id)); + save_item(NAME(m_ExecutionPhaseTransferCount)); + save_item(NAME(m_ExecutionPhaseCount)); + save_item(NAME(m_Counter)); + save_item(NAME(m_data_direction)); + save_pointer(NAME(m_pExecutionPhaseData), 0x4000);*/ +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void i8271_device::device_reset() +{ + m_StatusRegister = 0; //I8271_STATUS_INT_REQUEST | I8271_STATUS_NON_DMA_REQUEST; + m_Mode = 0x0c0; /* bits 0, 1 are initialized to zero */ + m_ParameterCountWritten = 0; + m_ParameterCount = 0; + + /* if timer is active remove */ + m_command_complete_timer->reset(); + m_data_timer->reset(); + + /* clear irq */ + set_irq_state(0); + /* clear dma */ + set_dma_drq(); +} + +void i8271_device::seek_to_track(int track) +{ + if (track==0) + { + /* seek to track 0 */ + unsigned char StepCount = 0x0ff; + + /*logerror("step\n"); */ + + /* track 0 not set, not seeked more than 255 tracks */ + while (m_floppy[m_drive]->floppy_tk00_r() && (StepCount != 0)) + { +/* logerror("step\n"); */ + StepCount--; + m_floppy[m_drive]->floppy_drive_seek(-1); + } + + m_CurrentTrack[m_drive] = 0; + + /* failed to find track 0? */ + if (StepCount==0) + { + /* Completion Type: operator intervation probably required for recovery */ + /* Completion code: track 0 not found */ + m_ResultRegister |= (2<<3) | 2<<1; + } + + /* step out - towards track 0 */ + m_drive_control_output &=~(1<<2); + } + else + { + signed int SignedTracks; + + /* calculate number of tracks to seek */ + SignedTracks = track - m_CurrentTrack[m_drive]; + + /* step towards 0 */ + m_drive_control_output &= ~(1<<2); + + if (SignedTracks>0) + { + /* step away from 0 */ + m_drive_control_output |= (1<<2); + } + + + /* seek to track 0 */ + m_floppy[m_drive]->floppy_drive_seek(SignedTracks); + + m_CurrentTrack[m_drive] = track; + } +} + +void i8271_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch (id) + { + case TIMER_DATA_CALLBACK: + /* ok, trigger data request now */ + data_request(); + + /* stop it */ + m_data_timer->reset(); + break; + + case TIMER_TIMED_COMMAND_COMPLETE: + command_complete(1,1); + + /* stop it, but don't allow it to be free'd */ + m_command_complete_timer->reset(); + break; + + default: + break; + } +} + +/* setup a timed data request - data request will be triggered in a few usecs time */ +void i8271_device::timed_data_request() +{ + int usecs; + /* 64 for single density */ + usecs = 64; + + /* set timers */ + m_command_complete_timer->reset(); + m_data_timer->adjust(attotime::from_usec(usecs)); +} + + +/* setup a irq to occur 128us later - in reality this would be much later, because the int would +come after reading the two CRC bytes at least! This function is used when a irq is required at +command completion. Required for read data and write data, where last byte could be missed! */ +void i8271_device::timed_command_complete() +{ + int usecs; + + /* 64 for single density - 2 crc bytes later*/ + usecs = 64*2; + + /* set timers */ + m_data_timer->reset(); + m_command_complete_timer->adjust(attotime::from_usec(usecs)); +} + +void i8271_device::set_irq_state(int state) +{ + m_StatusRegister &= ~I8271_STATUS_INT_REQUEST; + if (state) + { + m_StatusRegister |= I8271_STATUS_INT_REQUEST; + } + + m_write_irq((m_StatusRegister & I8271_STATUS_INT_REQUEST) ? ASSERT_LINE : CLEAR_LINE); +} + +void i8271_device::set_dma_drq() +{ + m_write_drq((m_flags & I8271_FLAGS_DATA_REQUEST) ? 1 : 0); +} + +void i8271_device::load_bad_tracks(int surface) +{ + m_BadTracks[(surface<<1) + 0] = m_CommandParameters[1]; + m_BadTracks[(surface<<1) + 1] = m_CommandParameters[2]; + m_CurrentTrack[surface] = m_CommandParameters[3]; +} + +void i8271_device::write_bad_track(int surface, int track, int data) +{ + m_BadTracks[(surface<<1) + (track-1)] = data; +} + +void i8271_device::write_current_track(int surface, int track) +{ + m_CurrentTrack[surface] = track; +} + +int i8271_device::read_current_track(int surface) +{ + return m_CurrentTrack[surface]; +} + +int i8271_device::read_bad_track(int surface, int track) +{ + return m_BadTracks[(surface<<1) + (track-1)]; +} + +void i8271_device::get_drive() +{ + /* &40 = drive 0 side 0 */ + /* &80 = drive 1 side 0 */ + + + + if (m_CommandRegister & (1<<6)) + { + m_drive = 0; + } + + if (m_CommandRegister & (1<<7)) + { + m_drive = 1; + } + +} + +void i8271_device::check_all_parameters_written() +{ + if (m_ParameterCount == m_ParameterCountWritten) + { + m_StatusRegister &= ~I8271_STATUS_COMMAND_FULL; + + command_execute(); + } +} + + +void i8271_device::update_state() +{ + switch (m_state) + { + /* fdc reading data and passing it to cpu which must read it */ + case I8271_STATE_EXECUTION_READ: + { + // /* if data request has been cleared, i.e. caused by a read of the register */ + // if ((m_flags & I8271_FLAGS_DATA_REQUEST)==0) + { + /* setup data with byte */ + m_data = m_pExecutionPhaseData[m_ExecutionPhaseCount]; + +/* logerror("read data %02x\n", m_data); */ + + /* update counters */ + m_ExecutionPhaseCount++; + m_ExecutionPhaseTransferCount--; + + // logerror("Count: %04x\n", m_ExecutionPhaseCount); + // logerror("Remaining: %04x\n", m_ExecutionPhaseTransferCount); + + /* completed? */ + if (m_ExecutionPhaseTransferCount==0) + { + /* yes */ + + // logerror("sector read complete!\n"); + /* continue command */ + command_continue(); + } + else + { + /* no */ + + /* issue data request */ + timed_data_request(); + } + } + } + break; + + /* fdc reading data and passing it to cpu which must read it */ + case I8271_STATE_EXECUTION_WRITE: + { + /* setup data with byte */ + m_pExecutionPhaseData[m_ExecutionPhaseCount] = m_data; + /* update counters */ + m_ExecutionPhaseCount++; + m_ExecutionPhaseTransferCount--; + + /* completed? */ + if (m_ExecutionPhaseTransferCount==0) + { + /* yes */ + + /* continue command */ + command_continue(); + } + else + { + /* no */ + + /* issue data request */ + timed_data_request(); + } + } + break; + + default: + break; + } +} + +void i8271_device::initialise_execution_phase_read(int transfer_size) +{ + /* read */ + m_flags |= I8271_FLAGS_DATA_DIRECTION; + m_ExecutionPhaseCount = 0; + m_ExecutionPhaseTransferCount = transfer_size; + m_state = I8271_STATE_EXECUTION_READ; +} + + +void i8271_device::initialise_execution_phase_write(int transfer_size) +{ + /* write */ + m_flags &= ~I8271_FLAGS_DATA_DIRECTION; + m_ExecutionPhaseCount = 0; + m_ExecutionPhaseTransferCount = transfer_size; + m_state = I8271_STATE_EXECUTION_WRITE; +} + +/* for data transfers */ +void i8271_device::data_request() +{ + m_flags |= I8271_FLAGS_DATA_REQUEST; + + if ((m_Mode & 0x01)!=0) + { + /* non-dma */ + m_StatusRegister |= I8271_STATUS_NON_DMA_REQUEST; + /* set int */ + set_irq_state(1); + } + else + { + /* dma */ + m_StatusRegister &= ~I8271_STATUS_NON_DMA_REQUEST; + + set_dma_drq(); + } +} + +void i8271_device::command_complete(int result, int int_rq) +{ + /* not busy, and not a execution phase data request in non-dma mode */ + m_StatusRegister &= ~(I8271_STATUS_COMMAND_BUSY | I8271_STATUS_NON_DMA_REQUEST); + + if (result) + { + m_StatusRegister |= I8271_STATUS_RESULT_FULL; + } + + if (int_rq) + { + /* trigger an int */ + set_irq_state(1); + } + + /* correct?? */ + m_drive_control_output &=~1; +} + + +/* for data transfers */ +void i8271_device::clear_data_request() +{ + m_flags &= ~I8271_FLAGS_DATA_REQUEST; + + if ((m_Mode & 0x01)!=0) + { + /* non-dma */ + m_StatusRegister &= ~I8271_STATUS_NON_DMA_REQUEST; + /* set int */ + set_irq_state(0); + } + else + { + /* dma */ + set_dma_drq(); + } +} + + +void i8271_device::command_continue() +{ + switch (m_Command) + { + case I8271_COMMAND_READ_DATA_MULTI_RECORD: + case I8271_COMMAND_READ_DATA_SINGLE_RECORD: + { + /* completed all sectors? */ + m_Counter--; + /* increment sector id */ + m_ID_R++; + + /* end command? */ + if (m_Counter==0) + { + timed_command_complete(); + return; + } + + do_read(); + } + break; + + case I8271_COMMAND_WRITE_DATA_MULTI_RECORD: + case I8271_COMMAND_WRITE_DATA_SINGLE_RECORD: + { + /* put the buffer to the sector */ + m_floppy[m_drive]->floppy_drive_write_sector_data(m_side, m_data_id, m_pExecutionPhaseData, 1<<(m_ID_N+7),0); + + /* completed all sectors? */ + m_Counter--; + /* increment sector id */ + m_ID_R++; + + /* end command? */ + if (m_Counter==0) + { + timed_command_complete(); + return; + } + + do_write(); + } + break; + + case I8271_COMMAND_READ_ID: + { + m_Counter--; + + if (m_Counter==0) + { + timed_command_complete(); + return; + } + + do_read_id(); + } + break; + + default: + break; + } +} + +void i8271_device::do_read() +{ + /* find the sector */ + if (find_sector()) + { + /* get the sector into the buffer */ + m_floppy[m_drive]->floppy_drive_read_sector_data(m_side, m_data_id, m_pExecutionPhaseData, 1<<(m_ID_N+7)); + + /* initialise for reading */ + initialise_execution_phase_read(1<<(m_ID_N+7)); + + /* update state - gets first byte and triggers a data request */ + timed_data_request(); + return; + } + LOG(("error getting sector data\n")); + + timed_command_complete(); +} + +void i8271_device::do_read_id() +{ + chrn_id id; + + /* get next id from disc */ + m_floppy[m_drive]->floppy_drive_get_next_id(m_side,&id); + + m_pExecutionPhaseData[0] = id.C; + m_pExecutionPhaseData[1] = id.H; + m_pExecutionPhaseData[2] = id.R; + m_pExecutionPhaseData[3] = id.N; + + initialise_execution_phase_read(4); +} + + +void i8271_device::do_write() +{ + /* find the sector */ + if (find_sector()) + { + /* initialise for reading */ + initialise_execution_phase_write(1<<(m_ID_N+7)); + + /* update state - gets first byte and triggers a data request */ + timed_data_request(); + return; + } + LOG(("error getting sector data\n")); + + timed_command_complete(); +} + + + +int i8271_device::find_sector() +{ +// int track_count_attempt; + +// track_count_attempt + /* find sector within one revolution of the disc - 2 index pulses */ + + /* number of times we have seen index hole */ + int index_count = 0; + + /* get sector id's */ + do + { + chrn_id id; + + /* get next id from disc */ + if (m_floppy[m_drive]->floppy_drive_get_next_id(m_side,&id)) + { + /* tested on Amstrad CPC - All bytes must match, otherwise + a NO DATA error is reported */ + if (id.R == m_ID_R) + { + /* TODO: Is this correct? What about bad tracks? */ + if (id.C == m_CurrentTrack[m_drive]) + { + m_data_id = id.data_id; + return 1; + } + else + { + /* TODO: if track doesn't match, the real 8271 does a step */ + + + return 0; + } + } + } + + /* index set? */ + if (m_floppy[m_drive]->floppy_drive_get_flag_state(FLOPPY_DRIVE_INDEX)) + { + index_count++; + } + + } + while (index_count!=2); + + /* completion type: command/drive error */ + /* completion code: sector not found */ + m_ResultRegister |= (3<<3); + + return 0; +} + +void i8271_device::command_execute() +{ + /* clear it = good completion status */ + /* this will be changed if anything bad happens! */ + m_ResultRegister = 0; + + switch (m_Command) + { + case I8271_COMMAND_SPECIFY: + { + switch (m_CommandParameters[0]) + { + case 0x0d: + { + LOG(("Initialization\n")); + m_StepRate = m_CommandParameters[1]; + m_HeadSettlingTime = m_CommandParameters[2]; + m_IndexCountBeforeHeadUnload = (m_CommandParameters[3]>>4) & 0x0f; + m_HeadLoadTime = (m_CommandParameters[3] & 0x0f); + } + break; + + case 0x010: + { + LOG(("Load bad Tracks Surface 0\n")); + load_bad_tracks(0); + + } + break; + + case 0x018: + { + LOG(("Load bad Tracks Surface 1\n")); + load_bad_tracks(1); + + } + break; + } + + /* no result */ + command_complete(0,0); + } + break; + + case I8271_COMMAND_READ_SPECIAL_REGISTER: + { + /* unknown - what is read when a special register that isn't allowed is specified? */ + int data = 0x0ff; + + switch (m_CommandParameters[0]) + { + case I8271_SPECIAL_REGISTER_MODE_REGISTER: + { + data = m_Mode; + } + break; + + case I8271_SPECIAL_REGISTER_SURFACE_0_CURRENT_TRACK: + { + data = read_current_track(0); + + } + break; + + case I8271_SPECIAL_REGISTER_SURFACE_1_CURRENT_TRACK: + { + data = read_current_track(1); + } + break; + + case I8271_SPECIAL_REGISTER_SURFACE_0_BAD_TRACK_1: + { + data = read_bad_track(0,1); + } + break; + + case I8271_SPECIAL_REGISTER_SURFACE_0_BAD_TRACK_2: + { + data = read_bad_track(0,2); + } + break; + + case I8271_SPECIAL_REGISTER_SURFACE_1_BAD_TRACK_1: + { + data = read_bad_track(1,1); + } + break; + + case I8271_SPECIAL_REGISTER_SURFACE_1_BAD_TRACK_2: + { + data = read_bad_track(1,2); + } + break; + + case I8271_SPECIAL_REGISTER_DRIVE_CONTROL_OUTPUT_PORT: + { + FDC_LOG_COMMAND("Read Drive Control Output port\n"); + + get_drive(); + + /* assumption: select bits reflect the select bits from the previous + command. i.e. read drive status */ + data = (m_drive_control_output & ~0x0c0) | (m_CommandRegister & 0x0c0); + } + break; + + case I8271_SPECIAL_REGISTER_DRIVE_CONTROL_INPUT_PORT: + { + /* bit 7: not used */ + /* bit 6: ready 1 */ + /* bit 5: write fault */ + /* bit 4: index */ + /* bit 3: wr prot */ + /* bit 2: rdy 0 */ + /* bit 1: track 0 */ + /* bit 0: cnt/opi */ + + FDC_LOG_COMMAND("Read Drive Control Input port\n"); + + + m_drive_control_input = (1<<6) | (1<<2); + + /* bit 3 = 0 if write protected */ + m_drive_control_input |= m_floppy[m_drive]->floppy_wpt_r() << 3; + + /* bit 1 = 0 if head at track 0 */ + m_drive_control_input |= m_floppy[m_drive]->floppy_tk00_r() << 1; + + /* need to setup this register based on drive selected */ + data = m_drive_control_input; + } + break; + + } + + m_ResultRegister = data; + + command_complete(1,0); + } + break; + + + case I8271_COMMAND_WRITE_SPECIAL_REGISTER: + { + switch (m_CommandParameters[0]) + { + case I8271_SPECIAL_REGISTER_MODE_REGISTER: + { + /* TODO: Check bits 6-7 and 5-2 are valid */ + m_Mode = m_CommandParameters[1]; + + if (m_Mode & 0x01) + { + LOG(("Mode: Non-DMA\n")); + } + else + { + LOG(("Mode: DMA\n")); + } + + if (m_Mode & 0x02) + { + LOG(("Single actuator\n")); + } + else + { + LOG(("Double actuator\n")); + } + } + break; + + case I8271_SPECIAL_REGISTER_SURFACE_0_CURRENT_TRACK: + { + LOG(("Surface 0 Current Track\n")); + write_current_track(0, m_CommandParameters[1]); + } + break; + + case I8271_SPECIAL_REGISTER_SURFACE_1_CURRENT_TRACK: + { + LOG(("Surface 1 Current Track\n")); + write_current_track(1, m_CommandParameters[1]); + } + break; + + case I8271_SPECIAL_REGISTER_SURFACE_0_BAD_TRACK_1: + { + LOG(("Surface 0 Bad Track 1\n")); + write_bad_track(0, 1, m_CommandParameters[1]); + } + break; + + case I8271_SPECIAL_REGISTER_SURFACE_0_BAD_TRACK_2: + { + LOG(("Surface 0 Bad Track 2\n")); + write_bad_track(0, 2,m_CommandParameters[1]); + } + break; + + case I8271_SPECIAL_REGISTER_SURFACE_1_BAD_TRACK_1: + { + LOG(("Surface 1 Bad Track 1\n")); + + + write_bad_track(1, 1, m_CommandParameters[1]); + } + break; + + case I8271_SPECIAL_REGISTER_SURFACE_1_BAD_TRACK_2: + { + LOG(("Surface 1 Bad Track 2\n")); + + write_bad_track(1, 2, m_CommandParameters[1]); + } + break; + + case I8271_SPECIAL_REGISTER_DRIVE_CONTROL_OUTPUT_PORT: + { +// /* get drive selected */ +// m_drive = (m_CommandParameters[1]>>6) & 0x03; + + FDC_LOG_COMMAND("Write Drive Control Output port\n"); + + + if (m_CommandParameters[1] & 0x01) + { + LOG(("Write Enable\n")); + } + if (m_CommandParameters[1] & 0x02) + { + LOG(("Seek/Step\n")); + } + if (m_CommandParameters[1] & 0x04) + { + LOG(("Direction\n")); + } + if (m_CommandParameters[1] & 0x08) + { + LOG(("Load Head\n")); + } + if (m_CommandParameters[1] & 0x010) + { + LOG(("Low head current\n")); + } + if (m_CommandParameters[1] & 0x020) + { + LOG(("Write Fault Reset\n")); + } + + LOG(("Select %02x\n", (m_CommandParameters[1] & 0x0c0)>>6)); + + /* get drive */ + get_drive(); + + /* on bbc dfs 09 this is the side select output */ + m_side = (m_CommandParameters[1]>>5) & 0x01; + + /* load head - on mini-sized drives this turns on the disc motor, + on standard-sized drives this loads the head and turns the motor on */ + m_floppy[m_drive]->floppy_mon_w(!BIT(m_CommandParameters[1], 3)); + m_floppy[m_drive]->floppy_drive_set_ready_state(1, 1); + + /* step pin changed? if so perform a step in the direction indicated */ + if (((m_drive_control_output^m_CommandParameters[1]) & (1<<1))!=0) + { + /* step pin changed state? */ + + if (BIT(m_CommandParameters[1], 1)) + { + signed int signed_tracks; + + if (BIT(m_CommandParameters[1], 2)) + { + signed_tracks = 1; + } + else + { + signed_tracks = -1; + } + + m_floppy[m_drive]->floppy_drive_seek(signed_tracks); + } + } + + m_drive_control_output = m_CommandParameters[1]; + + + } + break; + + case I8271_SPECIAL_REGISTER_DRIVE_CONTROL_INPUT_PORT: + { + FDC_LOG_COMMAND("Write Drive Control Input port\n"); + + // m_drive_control_input = m_CommandParameters[1]; + } + break; + + } + + /* write doesn't supply a result */ + command_complete(0,0); + } + break; + + case I8271_COMMAND_READ_DRIVE_STATUS: + { + unsigned char status; + + get_drive(); + + /* no write fault */ + status = 0; + + status |= (1<<2) | (1<<6); + + /* these two do not appear to be set at all! ?? */ + + if (m_floppy[0]) + { + if (m_floppy[0]->floppy_drive_get_flag_state(FLOPPY_DRIVE_READY)) + { + status |= (1 << 2); + } + } + + if (m_floppy[1]) + { + if (m_floppy[1]->floppy_drive_get_flag_state(FLOPPY_DRIVE_READY)) + { + status |= (1 << 6); + } + } + + /* bit 3 = 1 if write protected */ + status |= !m_floppy[m_drive]->floppy_wpt_r() << 3; + + /* bit 1 = 1 if head at track 0 */ + status |= !m_floppy[m_drive]->floppy_tk00_r() << 1; + + m_ResultRegister = status; + command_complete(1,0); + + } + break; + + case I8271_COMMAND_SEEK: + { + get_drive(); + + seek_to_track(m_CommandParameters[0]); + + /* check for bad seek */ + timed_command_complete(); + + } + break; + + case I8271_COMMAND_READ_DATA_MULTI_RECORD: + { + /* N value as stored in ID field */ + m_ID_N = (m_CommandParameters[2]>>5) & 0x07; + + /* starting sector id */ + m_ID_R = m_CommandParameters[1]; + + /* number of sectors to transfer */ + m_Counter = m_CommandParameters[2] & 0x01f; + + + FDC_LOG_COMMAND("READ DATA MULTI RECORD"); + + LOG(("Sector Count: %02x\n", m_Counter)); + LOG(("Track: %02x\n",m_CommandParameters[0])); + LOG(("Sector: %02x\n", m_CommandParameters[1])); + LOG(("Sector Length: %02x bytes\n", 1<<(m_ID_N+7))); + + get_drive(); + + if (!m_floppy[m_drive]->floppy_drive_get_flag_state(FLOPPY_DRIVE_READY)) + { + /* Completion type: operation intervention probably required for recovery */ + /* Completion code: Drive not ready */ + m_ResultRegister = (2<<3); + timed_command_complete(); + } + else + { + seek_to_track(m_CommandParameters[0]); + + + do_read(); + } + + } + break; + + case I8271_COMMAND_READ_DATA_SINGLE_RECORD: + { + FDC_LOG_COMMAND("READ DATA SINGLE RECORD"); + + m_ID_N = 0; + m_Counter = 1; + m_ID_R = m_CommandParameters[1]; + + LOG(("Sector Count: %02x\n", m_Counter)); + LOG(("Track: %02x\n",m_CommandParameters[0])); + LOG(("Sector: %02x\n", m_CommandParameters[1])); + LOG(("Sector Length: %02x bytes\n", 1<<(m_ID_N+7))); + + get_drive(); + + if (!m_floppy[m_drive]->floppy_drive_get_flag_state(FLOPPY_DRIVE_READY)) + { + /* Completion type: operation intervention probably required for recovery */ + /* Completion code: Drive not ready */ + m_ResultRegister = (2<<3); + timed_command_complete(); + } + else + { + seek_to_track(m_CommandParameters[0]); + + do_read(); + } + + } + break; + + case I8271_COMMAND_WRITE_DATA_MULTI_RECORD: + { + /* N value as stored in ID field */ + m_ID_N = (m_CommandParameters[2]>>5) & 0x07; + + /* starting sector id */ + m_ID_R = m_CommandParameters[1]; + + /* number of sectors to transfer */ + m_Counter = m_CommandParameters[2] & 0x01f; + + FDC_LOG_COMMAND("READ DATA MULTI RECORD"); + + LOG(("Sector Count: %02x\n", m_Counter)); + LOG(("Track: %02x\n",m_CommandParameters[0])); + LOG(("Sector: %02x\n", m_CommandParameters[1])); + LOG(("Sector Length: %02x bytes\n", 1<<(m_ID_N+7))); + + get_drive(); + + m_drive_control_output &=~1; + + if (!m_floppy[m_drive]->floppy_drive_get_flag_state(FLOPPY_DRIVE_READY)) + { + /* Completion type: operation intervention probably required for recovery */ + /* Completion code: Drive not ready */ + m_ResultRegister = (2<<3); + timed_command_complete(); + } + else + { + if (m_floppy[m_drive]->floppy_wpt_r() == CLEAR_LINE) + { + /* Completion type: operation intervention probably required for recovery */ + /* Completion code: Drive write protected */ + m_ResultRegister = (2<<3) | (1<<1); + timed_command_complete(); + } + else + { + m_drive_control_output |=1; + + seek_to_track(m_CommandParameters[0]); + + do_write(); + } + } + } + break; + + case I8271_COMMAND_WRITE_DATA_SINGLE_RECORD: + { + FDC_LOG_COMMAND("WRITE DATA SINGLE RECORD"); + + m_ID_N = 0; + m_Counter = 1; + m_ID_R = m_CommandParameters[1]; + + + LOG(("Sector Count: %02x\n", m_Counter)); + LOG(("Track: %02x\n",m_CommandParameters[0])); + LOG(("Sector: %02x\n", m_CommandParameters[1])); + LOG(("Sector Length: %02x bytes\n", 1<<(m_ID_N+7))); + get_drive(); + + m_drive_control_output &=~1; + + if (!m_floppy[m_drive]->floppy_drive_get_flag_state(FLOPPY_DRIVE_READY)) + { + /* Completion type: operation intervention probably required for recovery */ + /* Completion code: Drive not ready */ + m_ResultRegister = (2<<3); + timed_command_complete(); + } + else + { + if (m_floppy[m_drive]->floppy_wpt_r() == CLEAR_LINE) + { + /* Completion type: operation intervention probably required for recovery */ + /* Completion code: Drive write protected */ + m_ResultRegister = (2<<3) | (1<<1); + timed_command_complete(); + } + else + { + m_drive_control_output |=1; + + seek_to_track(m_CommandParameters[0]); + + do_write(); + } + } + + } + break; + + + case I8271_COMMAND_READ_ID: + { + FDC_LOG_COMMAND("READ ID"); + + LOG(("Track: %02x\n",m_CommandParameters[0])); + LOG(("ID Field Count: %02x\n", m_CommandParameters[2])); + + get_drive(); + + if (!m_floppy[m_drive]->floppy_drive_get_flag_state(FLOPPY_DRIVE_READY)) + { + /* Completion type: operation intervention probably required for recovery */ + /* Completion code: Drive not ready */ + m_ResultRegister = (2<<3); + timed_command_complete(); + } + else + { + m_Counter = m_CommandParameters[2]; + + seek_to_track(m_CommandParameters[0]); + + do_read_id(); + } + } + break; + + default: + LOG(("ERROR Unrecognised Command\n")); + break; + } +} + + + +WRITE8_MEMBER(i8271_device::write) +{ + switch (offset & 3) + { + case 0: + { + LOG(("I8271 W Command Register: %02x\n", data)); + + m_CommandRegister = data; + m_Command = m_CommandRegister & 0x03f; + + m_StatusRegister |= I8271_STATUS_COMMAND_BUSY | I8271_STATUS_COMMAND_FULL; + m_StatusRegister &= ~I8271_STATUS_PARAMETER_FULL | I8271_STATUS_RESULT_FULL; + m_ParameterCountWritten = 0; + + switch (m_Command) + { + case I8271_COMMAND_SPECIFY: + { + FDC_LOG_COMMAND("SPECIFY"); + + m_ParameterCount = 4; + } + break; + + case I8271_COMMAND_SEEK: + { + FDC_LOG_COMMAND("SEEK"); + + m_ParameterCount = 1; + } + break; + + case I8271_COMMAND_READ_DRIVE_STATUS: + { + FDC_LOG_COMMAND("READ DRIVE STATUS"); + + m_ParameterCount = 0; + } + break; + + case I8271_COMMAND_READ_SPECIAL_REGISTER: + { + FDC_LOG_COMMAND("READ SPECIAL REGISTER"); + + m_ParameterCount = 1; + } + break; + + case I8271_COMMAND_WRITE_SPECIAL_REGISTER: + { + FDC_LOG_COMMAND("WRITE SPECIAL REGISTER"); + + m_ParameterCount = 2; + } + break; + + case I8271_COMMAND_FORMAT: + { + m_ParameterCount = 5; + } + break; + + case I8271_COMMAND_READ_ID: + { + m_ParameterCount = 3; + + } + break; + + + case I8271_COMMAND_READ_DATA_SINGLE_RECORD: + case I8271_COMMAND_READ_DATA_AND_DELETED_DATA_SINGLE_RECORD: + case I8271_COMMAND_WRITE_DATA_SINGLE_RECORD: + case I8271_COMMAND_WRITE_DELETED_DATA_SINGLE_RECORD: + case I8271_COMMAND_VERIFY_DATA_AND_DELETED_DATA_SINGLE_RECORD: + { + m_ParameterCount = 2; + } + break; + + case I8271_COMMAND_READ_DATA_MULTI_RECORD: + case I8271_COMMAND_READ_DATA_AND_DELETED_DATA_MULTI_RECORD: + case I8271_COMMAND_WRITE_DATA_MULTI_RECORD: + case I8271_COMMAND_WRITE_DELETED_DATA_MULTI_RECORD: + case I8271_COMMAND_VERIFY_DATA_AND_DELETED_DATA_MULTI_RECORD: + { + m_ParameterCount = 3; + } + break; + + case I8271_COMMAND_SCAN_DATA: + case I8271_COMMAND_SCAN_DATA_AND_DELETED_DATA: + { + m_ParameterCount = 5; + } + break; + + + + + + + } + + check_all_parameters_written(); + } + break; + + case 1: + { + LOG(("I8271 W Parameter Register: %02x\n",data)); + m_ParameterRegister = data; + + if (m_ParameterCount!=0) + { + m_CommandParameters[m_ParameterCountWritten] = data; + m_ParameterCountWritten++; + } + + check_all_parameters_written(); + } + break; + + case 2: + { + LOG(("I8271 W Reset Register: %02x\n", data)); + if (((data ^ m_ResetRegister) & 0x01)!=0) + { + if ((data & 0x01)==0) + { + reset(); + } + } + + m_ResetRegister = data; + + + } + break; + + default: + break; + } +} + +READ8_MEMBER(i8271_device::read) +{ + switch (offset & 3) + { + case 0: + { + /* bit 1,0 are zero other bits contain status data */ + m_StatusRegister &= ~0x03; + LOG(("I8271 R Status Register: %02x\n",m_StatusRegister)); + return m_StatusRegister; + } + + case 1: + { + if ((m_StatusRegister & I8271_STATUS_COMMAND_BUSY)==0) + { + /* clear IRQ */ + set_irq_state(0); + + m_StatusRegister &= ~I8271_STATUS_RESULT_FULL; + LOG(("I8271 R Result Register %02x\n",m_ResultRegister)); + return m_ResultRegister; + } + + /* not useful information when command busy */ + return 0x0ff; + } + + + default: + break; + } + + return 0x0ff; +} + + +/* to be completed! */ +READ8_MEMBER(i8271_device::dack_r) +{ + return data_r(space, offset); +} + +/* to be completed! */ +WRITE8_MEMBER(i8271_device::dack_w) +{ + data_w(space, offset, data); +} + +READ8_MEMBER(i8271_device::data_r) +{ + clear_data_request(); + + update_state(); + + // logerror("I8271 R data: %02x\n",m_data); + + + return m_data; +} + +WRITE8_MEMBER(i8271_device::data_w) +{ + m_data = data; + +// logerror("I8271 W data: %02x\n",m_data); + + clear_data_request(); + + update_state(); +} diff --git a/src/devices/machine/i8271.h b/src/devices/machine/i8271.h new file mode 100644 index 00000000000..c73fb4b680c --- /dev/null +++ b/src/devices/machine/i8271.h @@ -0,0 +1,165 @@ +// license:BSD-3-Clause +// copyright-holders:Kevin Thacker +/***************************************************************************** + * + * machine/i8271.h + * + ****************************************************************************/ + +#ifndef I8271_H_ +#define I8271_H_ + +#include "imagedev/flopdrv.h" + +#define MCFG_I8271_IRQ_CALLBACK(_write) \ + devcb = &i8271_device::set_irq_wr_callback(*device, DEVCB_##_write); + +#define MCFG_I8271_DRQ_CALLBACK(_write) \ + devcb = &i8271_device::set_drq_wr_callback(*device, DEVCB_##_write); + +#define MCFG_I8271_FLOPPIES(_tag1, _tag2) \ + i8271_device::set_floppy_tags(*device, _tag1, _tag2); + +/*************************************************************************** + MACROS +***************************************************************************/ + +class i8271_device : public device_t +{ +public: + i8271_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + ~i8271_device() {} + + template static devcb_base &set_irq_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_irq.set_callback(object); } + template static devcb_base &set_drq_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_drq.set_callback(object); } + + static void set_floppy_tags(device_t &device, const char *tag1, const char *tag2) + { + i8271_device &dev = downcast(device); + dev.m_floppy_tag1 = tag1; + dev.m_floppy_tag2 = tag2; + } + + DECLARE_READ8_MEMBER(read); + DECLARE_WRITE8_MEMBER(write); + + DECLARE_READ8_MEMBER(dack_r); + DECLARE_WRITE8_MEMBER(dack_w); + + DECLARE_READ8_MEMBER(data_r); + DECLARE_WRITE8_MEMBER(data_w); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + +private: + // internal state + enum + { + TIMER_DATA_CALLBACK, + TIMER_TIMED_COMMAND_COMPLETE + }; + + devcb_write_line m_write_irq; + devcb_write_line m_write_drq; + + const char *m_floppy_tag1, *m_floppy_tag2; + legacy_floppy_image_device *m_floppy[2]; + + int m_flags; + int m_state; + unsigned char m_Command; + unsigned char m_StatusRegister; + unsigned char m_CommandRegister; + unsigned char m_ResultRegister; + unsigned char m_ParameterRegister; + unsigned char m_ResetRegister; + unsigned char m_data; + + /* number of parameters required after command is specified */ + unsigned long m_ParameterCount; + /* number of parameters written so far */ + unsigned long m_ParameterCountWritten; + + unsigned char m_CommandParameters[8]; + + /* current track for each drive */ + unsigned long m_CurrentTrack[2]; + + /* 2 bad tracks for drive 0, followed by 2 bad tracks for drive 1 */ + unsigned long m_BadTracks[4]; + + /* mode special register */ + unsigned long m_Mode; + + + /* drive outputs */ + int m_drive; + int m_side; + + /* drive control output special register */ + int m_drive_control_output; + /* drive control input special register */ + int m_drive_control_input; + + unsigned long m_StepRate; + unsigned long m_HeadSettlingTime; + unsigned long m_IndexCountBeforeHeadUnload; + unsigned long m_HeadLoadTime; + + /* id on disc to find */ + //int m_ID_C; + //int m_ID_H; + int m_ID_R; + int m_ID_N; + + /* id of data for read/write */ + int m_data_id; + + int m_ExecutionPhaseTransferCount; + char *m_pExecutionPhaseData; + int m_ExecutionPhaseCount; + + /* sector counter and id counter */ + int m_Counter; + + /* ==0, to cpu, !=0 =from cpu */ + //int m_data_direction; + + emu_timer *m_data_timer; + emu_timer *m_command_complete_timer; + + void seek_to_track(int track); + void load_bad_tracks(int surface); + void write_bad_track(int surface, int track, int data); + void write_current_track(int surface, int track); + int read_current_track(int surface); + int read_bad_track(int surface, int track); + void get_drive(); + void check_all_parameters_written(); + void update_state(); + void initialise_execution_phase_read(int transfer_size); + void initialise_execution_phase_write(int transfer_size); + void command_execute(); + void command_continue(); + void command_complete(int result, int int_rq); + void timed_command_complete(); + void data_request(); + void clear_data_request(); + void timed_data_request(); + /* locate sector for read/write operation */ + int find_sector(); + /* do a read operation */ + void do_read(); + void do_write(); + void do_read_id(); + void set_irq_state(int); + void set_dma_drq(); +}; + +extern const device_type I8271; + +#endif /* I8271_H_ */ diff --git a/src/devices/machine/i8279.c b/src/devices/machine/i8279.c new file mode 100644 index 00000000000..abd4fb3beb1 --- /dev/null +++ b/src/devices/machine/i8279.c @@ -0,0 +1,489 @@ +// license:BSD-3-Clause +// copyright-holders:Robbbert +/********************************************************************** + + i8279 + +2012-JAN-08 First draft [Robbbert] +2012-JAN-12 Implemented + +Notes: +- All keys MUST be ACTIVE_LOW + + +ToDo: +- Command 5 (Nibble masking and blanking) +- Command 7 (Error Mode) +- Interrupts +- BD pin +- Sensor ram stuff +- save state + + +What has been done: +CMD 0: +- Display Mode +-- Left & Right with no increment are the same thing +-- Right with increment is not emulated yet *** +- Keyboard Mode +-- No particular code has been added for 2-key/N-key rollover, no need +-- Sensor mode is not complete yet *** +-- Encoded and Decoded are done +-- Strobe is done +-- Sensor and FIFO may share the same internal RAM, not sure +CMD 1: +- Clock Divider +-- Value is stored, but internally a fixed value is always used +CMD 2: +- Read FIFO/Sensor RAM +-- FIFO works +-- Sensor RAM works +CMD 3: +- Read Display RAM +-- This works +CMD 4: +- Write Display RAM +-- Right with increment does nothing, the rest is working *** +CMD 5: +- Blank Nibble +-- Not done *** +- Mask Nibble +-- Implemented +CMD 6: +-- All implemented +CMD 7: +- Interrupt +-- Not done +- Error Mode +-- No need to do. + +Interface: +-- All done except BD pin *** + +Status word: +- FIFO bits +-- All done +- Error bit +-- Not done (no need) +- Display unavailable +-- Not done (no need) + + +Items marked (***) can be added if a system appears +that uses this feature. + +**********************************************************************/ + +#include "i8279.h" + +#define LOG 0 + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +// device type definition +const device_type I8279 = &device_creator; + +//------------------------------------------------- +// i8279_device - constructor +//------------------------------------------------- + +i8279_device::i8279_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, I8279, "8279 KDC", tag, owner, clock, "i8279", __FILE__), + m_out_irq_cb(*this), + m_out_sl_cb(*this), + m_out_disp_cb(*this), + m_out_bd_cb(*this), + m_in_rl_cb(*this), + m_in_shift_cb(*this), + m_in_ctrl_cb(*this) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void i8279_device::device_start() +{ + /* resolve callbacks */ + m_out_irq_cb.resolve(); + m_out_sl_cb.resolve(); + m_out_disp_cb.resolve(); + m_out_bd_cb.resolve(); + m_in_rl_cb.resolve(); + m_in_shift_cb.resolve(); + m_in_ctrl_cb.resolve(); + m_clock = clock(); + m_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(i8279_device::timerproc_callback), this)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void i8279_device::device_reset() +{ + UINT8 i; + + // startup values are unknown: setting to 0 + for (i = 2; i < 8; i++) m_cmd[i] = 0; + for (i = 0; i < 8; i++) m_fifo[i] = 0; + for (i = 0; i < 8; i++) m_s_ram[i] = 0; + for (i = 0; i < 16; i++) m_d_ram[i] = 0; + m_status = 0; + m_autoinc = 1; + m_d_ram_ptr = 0; + m_s_ram_ptr = 0; + m_read_flag = 0; + m_scanner = 0; + m_ctrl_key = 1; + m_key_down = 0xffff; + + // from here is confirmed + m_cmd[0] = 8; + m_cmd[1] = 31; + logerror("Initial clock = 3100kHz\n"); + timer_adjust(); +} + + +void i8279_device::timer_adjust() +{ +// Real device runs at about 100kHz internally, clock divider is chosen so that +// this is the case. We do not need such speed, 2000Hz is enough. +// If this is too long, the sensor mode doesn't work correctly. + +#if 0 + UINT8 divider = (m_cmd[1]) ? m_cmd[1] : 1; + UINT32 new_clock = clock() / divider; +#else + UINT32 new_clock = 2000; +#endif + + if (m_clock != new_clock) + { + m_timer->adjust(attotime::from_hz(new_clock), 0, attotime::from_hz(new_clock)); + + m_clock = new_clock; + } +} + + +void i8279_device::clear_display() +{ + // clear all digits + UINT8 i,patterns[4] = { 0, 0, 0x20, 0xff }; + UINT8 data = patterns[(m_cmd[6] & 12) >> 2]; + + // The CD high bit (also done by CA) + if (m_cmd[6] & 0x11) + for (i = 0; i < 16; i++) + m_d_ram[i] = data; + + m_status &= 0x7f; // bit 7 not emulated, but do it anyway + m_d_ram_ptr = 0; // not in the datasheet, but needed + + // The CF bit (also done by CA) + if (m_cmd[6] & 3) + { + m_status &= 0xc0; // blow away fifo + m_s_ram_ptr = 0; // reset sensor pointer + set_irq(0); // reset irq + } +} + + +void i8279_device::set_irq(bool state) +{ + if ( !m_out_irq_cb.isnull() ) + m_out_irq_cb( state ); +} + + +void i8279_device::new_key(UINT8 data, bool skey, bool ckey) +{ + UINT8 i, rl, sl; + for (i = 0; BIT(data, i); i++); + rl = i; + if (BIT(m_cmd[0], 0)) + { + for (i = 0; !BIT(data, i); i++); + sl = i; + } + else + sl = m_scanner; + + new_fifo( (ckey << 7) | (skey << 6) | (sl << 3) | rl); +} + + +void i8279_device::new_fifo(UINT8 data) +{ + // see if already overrun + if (BIT(m_status, 5)) + return; + + // set overrun flag if full + if (BIT(m_status, 3)) + { + m_status |= 0x20; + return; + } + + m_fifo[m_status & 7] = data; + + // bump fifo size & turn off underrun + UINT8 fifo_size = m_status & 7; + if ((fifo_size)==7) + m_status |= 8; // full + else + m_status = (m_status & 0xe8) + fifo_size + 1; + + if (!fifo_size) + set_irq(1); // something just went into fifo, so int +} + + +TIMER_CALLBACK_MEMBER( i8279_device::timerproc_callback ) +{ + timer_mainloop(); +} + + +void i8279_device::timer_mainloop() +{ + // control byte 0 + // bit 0 - encoded or decoded keyboard scan + // bits 1,2 - keyboard type + // bit 3 - number of digits to display + // bit 4 - left or right entry + + UINT8 scanner_mask = BIT(m_cmd[0], 0) ? 15 : BIT(m_cmd[0], 3) ? 15 : 7; + bool decoded = BIT(m_cmd[0], 0); + UINT8 kbd_type = (m_cmd[0] & 6) >> 1; + bool shift_key = 1; + bool ctrl_key = 1; + bool strobe_pulse = 0; + + // keyboard + // type 0 = kbd, 2-key lockout + // type 1 = kdb, n-key + // type 2 = sensor + // type 3 = strobed + + // Get shift keys + if ( !m_in_shift_cb.isnull() ) + shift_key = m_in_shift_cb(); + + if ( !m_in_ctrl_cb.isnull() ) + ctrl_key = m_in_ctrl_cb(); + + if (ctrl_key && !m_ctrl_key) + strobe_pulse = 1; // low-to-high is a strobe + + m_ctrl_key = ctrl_key; + + // Read a row of keys + + if ( !m_in_rl_cb.isnull() ) + { + UINT8 rl = m_in_rl_cb(0); + + // see if key still down from last time + UINT16 key_down = (m_scanner << 8) | rl; + if (key_down == m_key_down) + rl = 0xff; + else + if ((rl == 0xff) && (m_scanner == m_key_down >> 8)) + m_key_down = 0xffff; + + // now process new key + if (rl < 0xff || kbd_type == 2) + { + m_key_down = key_down; + switch (kbd_type) + { + case 0: + case 1: + new_key(rl, shift_key, ctrl_key); + break; + case 2: + { + UINT8 addr = m_scanner &7; + + if (decoded) + for (addr=0; !BIT(m_scanner, addr); addr++); + + rl ^= 0xff; // inverted + assert(addr < ARRAY_LENGTH(m_s_ram)); + if (m_s_ram[addr] != rl) + { + m_s_ram[addr] = rl; + + // IRQ line goes high if a row change value + set_irq(1); + } + } + break; + case 3: + if (strobe_pulse) new_fifo(rl); + break; + } + } + } + + // Increment scanline + + if (decoded) + { + m_scanner<<= 1; + if ((m_scanner & 15)==0) + m_scanner = 1; + } + else + m_scanner++; + + m_scanner &= scanner_mask; // 4-bit port + + if ( !m_out_sl_cb.isnull() ) + m_out_sl_cb((offs_t)0, m_scanner); + + // output a digit + + if ( !m_out_disp_cb.isnull() ) + m_out_disp_cb((offs_t)0, m_d_ram[m_scanner] ); +} + + +READ8_MEMBER( i8279_device::status_r ) +{ + return m_status; +} + + +READ8_MEMBER( i8279_device::data_r ) +{ + UINT8 i; + bool sensor_mode = ((m_cmd[0] & 6)==4); + UINT8 data; + if (m_read_flag) + { + // read the display ram + data = m_d_ram[m_d_ram_ptr]; + if (m_autoinc) + m_d_ram_ptr++; + } + else + if (sensor_mode) + { + // read sensor ram + assert(m_s_ram_ptr < ARRAY_LENGTH(m_s_ram)); + data = m_s_ram[m_s_ram_ptr]; + if (m_autoinc) + m_s_ram_ptr++; + else + set_irq(0); + } + else + { + // read a key from fifo + data = m_fifo[0]; + UINT8 fifo_size = m_status & 7; + switch (m_status & 0x38) + { + case 0x00: // no errors + if (!fifo_size) + m_status |= 0x10; // underrun + else + { + for (i = 1; i < 8; i++) + m_fifo[i-1] = m_fifo[i]; + fifo_size--; + if (!fifo_size) + set_irq(0); + } + break; + case 0x28: // overrun + case 0x08: // fifo full + for (i = 1; i < 8; i++) + m_fifo[i-1] = m_fifo[i]; + break; + case 0x10: // underrun + if (!fifo_size) + break; + default: + printf("Invalid status: %X\n", m_status); + } + m_status = (m_status & 0xd0) | fifo_size; // turn off overrun & full + } + + m_d_ram_ptr &= 15; + m_s_ram_ptr &= 7; + return data; +} + + +WRITE8_MEMBER( i8279_device::cmd_w ) +{//printf("Command: %X=%X ",data>>5,data&31); + UINT8 cmd = data >> 5; + data &= 0x1f; + m_cmd[cmd] = data; + switch (cmd) + { + case 0: + if (LOG) logerror("I8279 '%s' kb mode %x, display mode %x\n", tag(), data & 7, (data>>3) & 3); + break; + case 1: + if (data > 1) + { + logerror("Clock set to %dkHz\n",data*100); + timer_adjust(); + } + break; + case 2: + m_read_flag = 0; + if ((m_cmd[0] & 6)==4) // sensor mode only + { + m_autoinc = BIT(data, 4); + m_s_ram_ptr = data & 7; + if (LOG) logerror("I8279 '%s' selct sensor row %x, AI %d\n", tag(), m_s_ram_ptr, m_autoinc); + } + break; + case 3: + m_read_flag = 1; + m_d_ram_ptr = data & 15; + m_autoinc = BIT(data, 4); + break; + case 4: + m_d_ram_ptr = data & 15; + m_autoinc = BIT(data, 4); + break; + case 6: + if (LOG) logerror("I8279 '%s' clear cmd %x\n", tag(), data); + clear_display(); + break; + } +} + + +WRITE8_MEMBER( i8279_device::data_w ) +{//printf("Data: %X ",data); + if (BIT(m_cmd[0], 4) & m_autoinc) + { + // right-entry autoincrement not implemented yet + } + else + { + if (!(m_cmd[5] & 0x04)) + m_d_ram[m_d_ram_ptr] = (m_d_ram[m_d_ram_ptr] & 0xf0) | (data & 0x0f); + if (!(m_cmd[5] & 0x08)) + m_d_ram[m_d_ram_ptr] = (m_d_ram[m_d_ram_ptr] & 0x0f) | (data & 0xf0); + + if (m_autoinc) + m_d_ram_ptr++; + } + m_d_ram_ptr &= 15; +} diff --git a/src/devices/machine/i8279.h b/src/devices/machine/i8279.h new file mode 100644 index 00000000000..42a77d7634f --- /dev/null +++ b/src/devices/machine/i8279.h @@ -0,0 +1,145 @@ +// license:BSD-3-Clause +// copyright-holders:Robbbert +/*************************************************************************** + + Intel 8279 Programmable Keyboard/Display Interface emulation + +**************************************************************************** + _____ _____ + RL2 1 |* \_/ | 40 Vcc + RL3 2 | | 39 RL1 + CLK 3 | | 38 RL0 + IRQ 4 | | 37 CNTL/STB + RL4 5 | | 36 SHIFT + RL5 6 | | 35 SL3 + RL6 7 | | 34 SL2 + RL7 8 | | 33 SL1 + RESET 9 | | 32 SL0 + /RD 10 | 8279 | 31 B0 + /WR 11 | | 30 B1 + DB0 12 | | 29 B2 + DB1 13 | | 28 B3 + DB2 14 | | 27 A0 + DB3 15 | | 26 A1 + DB4 16 | | 25 A2 + DB5 17 | | 24 A3 + DB6 18 | | 23 /BD + DB7 19 | | 22 /CS + Vss 20 |_____________| 21 CTRL/DATA + + +***************************************************************************/ + +#pragma once + +#ifndef __I8279__ +#define __I8279__ + +#include "emu.h" + + + +/*************************************************************************** + DEVICE CONFIGURATION MACROS +***************************************************************************/ + +#define MCFG_I8279_OUT_IRQ_CB(_devcb) \ + devcb = &i8279_device::set_out_irq_callback(*device, DEVCB_##_devcb); + +#define MCFG_I8279_OUT_SL_CB(_devcb) \ + devcb = &i8279_device::set_out_sl_callback(*device, DEVCB_##_devcb); + +#define MCFG_I8279_OUT_DISP_CB(_devcb) \ + devcb = &i8279_device::set_out_disp_callback(*device, DEVCB_##_devcb); + +#define MCFG_I8279_OUT_BD_CB(_devcb) \ + devcb = &i8279_device::set_out_bd_callback(*device, DEVCB_##_devcb); + +#define MCFG_I8279_IN_RL_CB(_devcb) \ + devcb = &i8279_device::set_in_rl_callback(*device, DEVCB_##_devcb); + +#define MCFG_I8279_IN_SHIFT_CB(_devcb) \ + devcb = &i8279_device::set_in_shift_callback(*device, DEVCB_##_devcb); + +#define MCFG_I8279_IN_CTRL_CB(_devcb) \ + devcb = &i8279_device::set_in_ctrl_callback(*device, DEVCB_##_devcb); + +/*************************************************************************** + TYPE DEFINITIONS +***************************************************************************/ + +// ======================> i8279_device + +class i8279_device : public device_t +{ +public: + // construction/destruction + i8279_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + template static devcb_base &set_out_irq_callback(device_t &device, _Object object) { return downcast(device).m_out_irq_cb.set_callback(object); } + template static devcb_base &set_out_sl_callback(device_t &device, _Object object) { return downcast(device).m_out_sl_cb.set_callback(object); } + template static devcb_base &set_out_disp_callback(device_t &device, _Object object) { return downcast(device).m_out_disp_cb.set_callback(object); } + template static devcb_base &set_out_bd_callback(device_t &device, _Object object) { return downcast(device).m_out_bd_cb.set_callback(object); } + template static devcb_base &set_in_rl_callback(device_t &device, _Object object) { return downcast(device).m_in_rl_cb.set_callback(object); } + template static devcb_base &set_in_shift_callback(device_t &device, _Object object) { return downcast(device).m_in_shift_cb.set_callback(object); } + template static devcb_base &set_in_ctrl_callback(device_t &device, _Object object) { return downcast(device).m_in_ctrl_cb.set_callback(object); } + + // read & write handlers + DECLARE_READ8_MEMBER(status_r); + DECLARE_READ8_MEMBER(data_r); + DECLARE_WRITE8_MEMBER(cmd_w); + DECLARE_WRITE8_MEMBER(data_w); + void timer_mainloop(); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_post_load() { } + virtual void device_clock_changed() { } + + TIMER_CALLBACK_MEMBER( timerproc_callback ); + +private: + + void timer_adjust(); + void clear_display(); + void new_key(UINT8 data, bool skey, bool ckey); + void new_fifo(UINT8 data); + UINT8 get_segments(); + void set_irq(bool state); + void set_display_mode(UINT8 data); + + devcb_write_line m_out_irq_cb; // IRQ + devcb_write8 m_out_sl_cb; // Scanlines SL0-3 + devcb_write8 m_out_disp_cb; // B0-3,A0-3 + devcb_write_line m_out_bd_cb; // BD + devcb_read8 m_in_rl_cb; // kbd readlines RL0-7 + devcb_read_line m_in_shift_cb; // Shift key + devcb_read_line m_in_ctrl_cb; // Ctrl-Strobe line + + emu_timer *m_timer; + + UINT8 m_d_ram[16]; // display ram + UINT8 m_d_ram_ptr; + UINT8 m_s_ram[8]; // might be same as fifo ram + UINT8 m_s_ram_ptr; + UINT8 m_fifo[8]; // queued keystrokes + UINT8 m_cmd[8]; // Device settings + UINT8 m_status; // Returned via status_r + UINT32 m_clock; // Internal scan clock + UINT8 m_scanner; // next output on SL lines + + bool m_autoinc; // auto-increment flag + bool m_read_flag; // read from where + bool m_ctrl_key; // previous state of strobe input + UINT16 m_key_down; +}; + + +// device type definition +extern const device_type I8279; + + + +#endif diff --git a/src/devices/machine/i82875p.c b/src/devices/machine/i82875p.c new file mode 100644 index 00000000000..58f8b3264c9 --- /dev/null +++ b/src/devices/machine/i82875p.c @@ -0,0 +1,515 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +#include "i82875p.h" + +const device_type I82875P_HOST = &device_creator; +const device_type I82875P_AGP = &device_creator; +const device_type I82875P_OVERFLOW = &device_creator; + +DEVICE_ADDRESS_MAP_START(agp_translation_map, 32, i82875p_host_device) +ADDRESS_MAP_END + +DEVICE_ADDRESS_MAP_START(config_map, 32, i82875p_host_device) + AM_RANGE(0x50, 0x53) AM_READWRITE8 (agpm_r, agpm_w, 0x0000ff00) + AM_RANGE(0x50, 0x53) AM_READ8 (gc_r, 0x00ff0000) + AM_RANGE(0x50, 0x53) AM_READ8 (csabcont_r, 0xff000000) + AM_RANGE(0x58, 0x5b) AM_READ (eap_r) + AM_RANGE(0x5c, 0x5f) AM_READ8 (derrsyn_r, 0x000000ff) + AM_RANGE(0x5c, 0x5f) AM_READ8 (des_r, 0x0000ff00) + AM_RANGE(0x60, 0x63) AM_READWRITE8 (fpllcont_r, fpllcont_w, 0x000000ff) + AM_RANGE(0x90, 0x97) AM_READWRITE8 (pam_r, pam_w, 0xffffffff) + AM_RANGE(0x9c, 0x9f) AM_READWRITE8 (smram_r, smram_w, 0x0000ff00) + AM_RANGE(0x9c, 0x9f) AM_READWRITE8 (esmramc_r, esmramc_w, 0x00ff0000) + AM_RANGE(0xa0, 0xa3) AM_READ (acapid_r) + AM_RANGE(0xa4, 0xa7) AM_READ (agpstat_r) + AM_RANGE(0xa8, 0xab) AM_READ (agpcmd_r) + AM_RANGE(0xb0, 0xb3) AM_READWRITE (agpctrl_r, agpctrl_w) + AM_RANGE(0xb4, 0xb7) AM_READWRITE8 (apsize_r, apsize_w, 0x000000ff) + AM_RANGE(0xb8, 0xbb) AM_READWRITE (attbase_r, attbase_w) + AM_RANGE(0xbc, 0xbf) AM_READWRITE8 (amtt_r, amtt_w, 0x000000ff) + AM_RANGE(0xbc, 0xbf) AM_READWRITE8 (lptt_r, lptt_w, 0x0000ff00) + AM_RANGE(0xc4, 0xc7) AM_READWRITE16(toud_r, toud_w, 0x0000ffff) + AM_RANGE(0xc4, 0xc7) AM_READWRITE16(mchcfg_r, mchcfg_w, 0xffff0000) + AM_RANGE(0xc8, 0xcb) AM_READ16 (errsts_r, 0x0000ffff) + AM_RANGE(0xc8, 0xcb) AM_READWRITE16(errcmd_r, errcmd_w, 0xffff0000) + AM_RANGE(0xcc, 0xcf) AM_READWRITE16(smicmd_r, smicmd_w, 0x0000ffff) + AM_RANGE(0xcc, 0xcf) AM_READWRITE16(scicmd_r, scicmd_w, 0xffff0000) + AM_RANGE(0xdc, 0xdf) AM_READWRITE16(skpd_r, skpd_w, 0xffff0000) + AM_RANGE(0xe4, 0xe7) AM_READ (capreg1_r) + AM_RANGE(0xe8, 0xeb) AM_READ8 (capreg2_r, 0x000000ff) + + AM_INHERIT_FROM(pci_host_device::config_map) +ADDRESS_MAP_END + +i82875p_host_device::i82875p_host_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : pci_host_device(mconfig, I82875P_HOST, "I82875P Northbridge", tag, owner, clock, "i82875p_host", __FILE__) +{ +} + +void i82875p_host_device::set_cpu_tag(const char *_cpu_tag) +{ + cpu_tag = _cpu_tag; +} + +void i82875p_host_device::set_ram_size(int _ram_size) +{ + ram_size = _ram_size; +} + +READ8_MEMBER(i82875p_host_device::capptr_r) +{ + return 0xe4; +} + +void i82875p_host_device::device_start() +{ + pci_host_device::device_start(); + cpu = machine().device(cpu_tag); + memory_space = &cpu->space(AS_PROGRAM); + io_space = &cpu->space(AS_IO); + + memory_window_start = 0; + memory_window_end = 0xffffffff; + memory_offset = 0; + io_window_start = 0; + io_window_end = 0xffff; + io_offset = 0; + status = 0x0010; + + ram.resize(ram_size/4); + + // Resizeable with the apsize register + add_map(256*1024*1024, M_MEM, FUNC(i82875p_host_device::agp_translation_map)); +} + +READ8_MEMBER( i82875p_host_device::agpm_r) +{ + return agpm; +} + +WRITE8_MEMBER( i82875p_host_device::agpm_w) +{ + agpm = data; + logerror("%s: agpm = %02x\n", tag(), agpm); +} + +READ8_MEMBER( i82875p_host_device::gc_r) +{ + return 0x08; +} + +READ8_MEMBER( i82875p_host_device::csabcont_r) +{ + return 0x00; +} + +READ32_MEMBER( i82875p_host_device::eap_r) +{ + return 0x00000000; +} + +READ8_MEMBER( i82875p_host_device::derrsyn_r) +{ + return 0x00; +} + +READ8_MEMBER( i82875p_host_device::des_r) +{ + return 0x00; +} + +READ8_MEMBER( i82875p_host_device::fpllcont_r) +{ + return fpllcont; +} + +WRITE8_MEMBER( i82875p_host_device::fpllcont_w) +{ + fpllcont = data; + logerror("%s: fpllcont = %02x\n", tag(), data); +} + +READ8_MEMBER( i82875p_host_device::pam_r) +{ + return pam[offset]; +} + +WRITE8_MEMBER( i82875p_host_device::pam_w) +{ + pam[offset] = data; + logerror("%s: pam[%d] = %02x\n", tag(), offset, data); + remap_cb(); +} + +READ8_MEMBER( i82875p_host_device::smram_r) +{ + return smram; +} + +WRITE8_MEMBER( i82875p_host_device::smram_w) +{ + if(!(smram & 0x10)) + smram = (data & 0xfe) | 0x02; + logerror("%s: smram = %02x\n", tag(), smram); + remap_cb(); +} + +READ8_MEMBER( i82875p_host_device::esmramc_r) +{ + return esmramc; +} + +WRITE8_MEMBER( i82875p_host_device::esmramc_w) +{ + if(!(smram & 0x10)) + esmramc = (data & 0x87) | 0x38; + logerror("%s: esmramc = %02x\n", tag(), smram); + remap_cb(); +} + +READ32_MEMBER( i82875p_host_device::acapid_r) +{ + return 0x00300002; +} + +READ32_MEMBER( i82875p_host_device::agpstat_r) +{ + return 0x1f004a13; +} + +READ32_MEMBER( i82875p_host_device::agpcmd_r) +{ + return 0x00000a00; +} + +READ32_MEMBER( i82875p_host_device::agpctrl_r) +{ + return agpctrl; +} + +WRITE32_MEMBER(i82875p_host_device::agpctrl_w) +{ + COMBINE_DATA(&agpctrl); + logerror("%s: agpctrl = %08x\n", tag(), agpctrl); +} + +READ8_MEMBER( i82875p_host_device::apsize_r) +{ + return apsize; +} + +WRITE8_MEMBER( i82875p_host_device::apsize_w) +{ + apsize = data; + logerror("%s: apsize = %02x\n", tag(), apsize); +} + +READ32_MEMBER( i82875p_host_device::attbase_r) +{ + return attbase; +} + +WRITE32_MEMBER(i82875p_host_device::attbase_w) +{ + COMBINE_DATA(&attbase); + logerror("%s: attbase = %08x\n", tag(), attbase); +} + +READ8_MEMBER( i82875p_host_device::amtt_r) +{ + return amtt; +} + +WRITE8_MEMBER( i82875p_host_device::amtt_w) +{ + amtt = data; +} + +READ8_MEMBER( i82875p_host_device::lptt_r) +{ + return lptt; +} + +WRITE8_MEMBER( i82875p_host_device::lptt_w) +{ + lptt = data; +} + +READ16_MEMBER( i82875p_host_device::toud_r) +{ + return toud; +} + +WRITE16_MEMBER(i82875p_host_device::toud_w) +{ + COMBINE_DATA(&toud); + toud &= ~7; + logerror("%s: toud = %08x\n", tag(), toud << 16); + remap_cb(); +} + +READ16_MEMBER( i82875p_host_device::mchcfg_r) +{ + return mchcfg; +} + +WRITE16_MEMBER(i82875p_host_device::mchcfg_w) +{ + COMBINE_DATA(&mchcfg); +} + +READ16_MEMBER( i82875p_host_device::errsts_r) +{ + return 0x0000; +} + +READ16_MEMBER( i82875p_host_device::errcmd_r) +{ + return errcmd; +} + +WRITE16_MEMBER(i82875p_host_device::errcmd_w) +{ + COMBINE_DATA(&errcmd); +} + +READ16_MEMBER( i82875p_host_device::smicmd_r) +{ + return smicmd; +} + +WRITE16_MEMBER(i82875p_host_device::smicmd_w) +{ + COMBINE_DATA(&smicmd); +} + +READ16_MEMBER( i82875p_host_device::scicmd_r) +{ + return scicmd; +} + +WRITE16_MEMBER(i82875p_host_device::scicmd_w) +{ + COMBINE_DATA(&scicmd); +} + +READ16_MEMBER( i82875p_host_device::skpd_r) +{ + return skpd; +} + +WRITE16_MEMBER(i82875p_host_device::skpd_w) +{ + COMBINE_DATA(&skpd); +} + +READ32_MEMBER( i82875p_host_device::capreg1_r) +{ + return 0x0106a009; +} + +READ8_MEMBER( i82875p_host_device::capreg2_r) +{ + return 0x00; +} + +void i82875p_host_device::reset_all_mappings() +{ + pci_host_device::reset_all_mappings(); + + toud = 0x0400; + smram = 0x02; + esmramc = 0x38; + memset(pam, 0, sizeof(pam)); +} + +void i82875p_host_device::device_reset() +{ + pci_host_device::device_reset(); + + agpm = 0x00; + fpllcont = 0x00; + agpctrl = 0x00000000; + apsize = 0x00; + attbase = 0x00000000; + amtt = 0x10; + lptt = 0x10; + mchcfg = 0x0000; + errcmd = 0x0000; + smicmd = 0x0000; + scicmd = 0x0000; + skpd = 0x0000; +} + +void i82875p_host_device::map_extra(UINT64 memory_window_start, UINT64 memory_window_end, UINT64 memory_offset, address_space *memory_space, + UINT64 io_window_start, UINT64 io_window_end, UINT64 io_offset, address_space *io_space) +{ + io_space->install_device(0, 0xffff, *static_cast(this), &pci_host_device::io_configuration_access_map); + + UINT32 top = toud << 16; + if(esmramc & 1) { + switch((esmramc >> 1) & 3) { + case 2: top += 512*1024; break; + case 3: top += 1024*1024; break; + } + } + + if(top > ram_size) + top = ram_size; + + memory_space->install_ram (0x00000000, 0x0009ffff, &ram[0x00000000/4]); + + if(smram & 0x40) + memory_space->install_ram (0x000a0000, 0x000bffff, &ram[0x000a0000/4]); + + if(pam[1] & 0x01) + memory_space->install_rom (0x000c0000, 0x000c3fff, &ram[0x000c0000/4]); + if(pam[1] & 0x02) + memory_space->install_writeonly(0x000c0000, 0x000c3fff, &ram[0x000c0000/4]); + if(pam[1] & 0x10) + memory_space->install_rom (0x000c4000, 0x000c7fff, &ram[0x000c4000/4]); + if(pam[1] & 0x20) + memory_space->install_writeonly(0x000c4000, 0x000c7fff, &ram[0x000c4000/4]); + if(pam[2] & 0x01) + memory_space->install_rom (0x000c8000, 0x000cbfff, &ram[0x000c8000/4]); + if(pam[2] & 0x02) + memory_space->install_writeonly(0x000c8000, 0x000cbfff, &ram[0x000c8000/4]); + if(pam[2] & 0x10) + memory_space->install_rom (0x000cc000, 0x000cffff, &ram[0x000cc000/4]); + if(pam[2] & 0x20) + memory_space->install_writeonly(0x000cc000, 0x000cffff, &ram[0x000cc000/4]); + if(pam[3] & 0x01) + memory_space->install_rom (0x000d0000, 0x000d3fff, &ram[0x000d0000/4]); + if(pam[3] & 0x02) + memory_space->install_writeonly(0x000d0000, 0x000d3fff, &ram[0x000d0000/4]); + if(pam[3] & 0x10) + memory_space->install_rom (0x000d4000, 0x000d7fff, &ram[0x000d4000/4]); + if(pam[3] & 0x20) + memory_space->install_writeonly(0x000d4000, 0x000d7fff, &ram[0x000d4000/4]); + if(pam[4] & 0x01) + memory_space->install_rom (0x000d8000, 0x000dbfff, &ram[0x000d8000/4]); + if(pam[4] & 0x02) + memory_space->install_writeonly(0x000d8000, 0x000dbfff, &ram[0x000d8000/4]); + if(pam[4] & 0x10) + memory_space->install_rom (0x000dc000, 0x000dffff, &ram[0x000dc000/4]); + if(pam[4] & 0x20) + memory_space->install_writeonly(0x000dc000, 0x000dffff, &ram[0x000dc000/4]); + if(pam[5] & 0x01) + memory_space->install_rom (0x000e0000, 0x000e3fff, &ram[0x000e0000/4]); + if(pam[5] & 0x02) + memory_space->install_writeonly(0x000e0000, 0x000e3fff, &ram[0x000e0000/4]); + if(pam[5] & 0x10) + memory_space->install_rom (0x000e4000, 0x000e7fff, &ram[0x000e4000/4]); + if(pam[5] & 0x20) + memory_space->install_writeonly(0x000e4000, 0x000e7fff, &ram[0x000e4000/4]); + if(pam[6] & 0x01) + memory_space->install_rom (0x000e8000, 0x000ebfff, &ram[0x000e8000/4]); + if(pam[6] & 0x02) + memory_space->install_writeonly(0x000e8000, 0x000ebfff, &ram[0x000e8000/4]); + if(pam[6] & 0x10) + memory_space->install_rom (0x000ec000, 0x000effff, &ram[0x000ec000/4]); + if(pam[6] & 0x20) + memory_space->install_writeonly(0x000ec000, 0x000effff, &ram[0x000ec000/4]); + if(pam[0] & 0x10) + memory_space->install_rom (0x000f0000, 0x000fffff, &ram[0x000f0000/4]); + if(pam[0] & 0x20) + memory_space->install_writeonly(0x000f0000, 0x000fffff, &ram[0x000f0000/4]); + + memory_space->install_ram (0x00100000, 0x00efffff, &ram[0x00100000/4]); + if(!(pam[7] & 0x80)) + memory_space->install_ram (0x00f00000, 0x00ffffff, &ram[0x00f00000/4]); + if(top > 0x01000000) + memory_space->install_ram (0x01000000, top-1, &ram[0x01000000/4]); + + if((esmramc & 0x40) && (smram & 0x08)) + memory_space->install_ram (0xfeda0000, 0xfedbffff, &ram[0x000a0000/4]); +} + + +i82875p_agp_device::i82875p_agp_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : agp_bridge_device(mconfig, I82875P_AGP, "I82875P AGP Bridge", tag, owner, clock, "i82875p_agp", __FILE__) +{ +} + +void i82875p_agp_device::device_start() +{ + agp_bridge_device::device_start(); +} + +void i82875p_agp_device::device_reset() +{ + agp_bridge_device::device_reset(); +} + +DEVICE_ADDRESS_MAP_START(overflow_map, 32, i82875p_overflow_device) + AM_RANGE(0x000, 0x007) AM_READWRITE8(dram_row_boundary_r, dram_row_boundary_w, 0xffffffff) + AM_RANGE(0x010, 0x013) AM_READWRITE8(dram_row_attribute_r, dram_row_attribute_w, 0xffffffff) + AM_RANGE(0x060, 0x064) AM_READWRITE (dram_timing_r, dram_timing_w) + AM_RANGE(0x068, 0x06b) AM_READWRITE (dram_controller_mode_r, dram_controller_mode_w) +ADDRESS_MAP_END + + +i82875p_overflow_device::i82875p_overflow_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : pci_device(mconfig, I82875P_OVERFLOW, "I82875P Configuration Overflow", tag, owner, clock, "i82875p_overflow", __FILE__) +{ +} + +void i82875p_overflow_device::device_start() +{ + pci_device::device_start(); + + add_map(4*1024, M_MEM, FUNC(i82875p_overflow_device::overflow_map)); +} + +void i82875p_overflow_device::device_reset() +{ + pci_device::device_reset(); + memset(dram_row_boundary, 1, sizeof(dram_row_boundary)); + memset(dram_row_attribute, 0, sizeof(dram_row_attribute)); + dram_timing = 0; + dram_controller_mode = 0x00010001; +} + +READ8_MEMBER (i82875p_overflow_device::dram_row_boundary_r) +{ + return dram_row_boundary[offset]; +} + +WRITE8_MEMBER (i82875p_overflow_device::dram_row_boundary_w) +{ + dram_row_boundary[offset] = data; + logerror("%s: dram_row_boundary_w %d, %02x\n", tag(), offset, data); +} + +READ8_MEMBER (i82875p_overflow_device::dram_row_attribute_r) +{ + return dram_row_attribute[offset]; +} + +WRITE8_MEMBER (i82875p_overflow_device::dram_row_attribute_w) +{ + dram_row_attribute[offset] = data; + logerror("%s: dram_row_attribute_w %d, %02x\n", tag(), offset, data); +} + +READ32_MEMBER (i82875p_overflow_device::dram_timing_r) +{ + return dram_timing; +} + +WRITE32_MEMBER(i82875p_overflow_device::dram_timing_w) +{ + COMBINE_DATA(&dram_timing); + logerror("%s: dram_timing_w %08x\n", tag(), dram_timing); +} + +READ32_MEMBER (i82875p_overflow_device::dram_controller_mode_r) +{ + return dram_controller_mode; +} + +WRITE32_MEMBER(i82875p_overflow_device::dram_controller_mode_w) +{ + COMBINE_DATA(&dram_controller_mode); + logerror("%s: dram_controller_mode_w %08x\n", tag(), dram_controller_mode); +} diff --git a/src/devices/machine/i82875p.h b/src/devices/machine/i82875p.h new file mode 100644 index 00000000000..8ab4a597eb2 --- /dev/null +++ b/src/devices/machine/i82875p.h @@ -0,0 +1,139 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +// Intel i82875p northbridge + +#ifndef I82875P_H +#define I82875P_H + +#include "pci.h" + +#define MCFG_I82875P_HOST_ADD(_tag, _subdevice_id, _cpu_tag, _ram_size) \ + MCFG_PCI_HOST_ADD(_tag, I82875P_HOST, 0x80862578, 0x02, _subdevice_id) \ + downcast(device)->set_cpu_tag(_cpu_tag); \ + downcast(device)->set_ram_size(_ram_size); + +#define MCFG_I82875P_AGP_ADD(_tag) \ + MCFG_AGP_BRIDGE_ADD(_tag, I82875P_AGP, 0x80862579, 0x02) + +#define MCFG_I82875P_OVERFLOW_ADD(_tag, _subdevice_id) \ + MCFG_PCI_DEVICE_ADD(_tag, I82875P_OVERFLOW, 0x8086257e, 0x02, 0x088000, _subdevice_id) + +class i82875p_host_device : public pci_host_device { +public: + i82875p_host_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + void set_cpu_tag(const char *tag); + void set_ram_size(int ram_size); + + virtual void reset_all_mappings(); + + virtual void map_extra(UINT64 memory_window_start, UINT64 memory_window_end, UINT64 memory_offset, address_space *memory_space, + UINT64 io_window_start, UINT64 io_window_end, UINT64 io_offset, address_space *io_space); + + virtual DECLARE_ADDRESS_MAP(config_map, 32); + + virtual DECLARE_READ8_MEMBER(capptr_r); + + DECLARE_READ8_MEMBER( agpm_r); + DECLARE_WRITE8_MEMBER( agpm_w); + DECLARE_READ8_MEMBER( gc_r); + DECLARE_READ8_MEMBER( csabcont_r); + DECLARE_READ32_MEMBER( eap_r); + DECLARE_READ8_MEMBER( derrsyn_r); + DECLARE_READ8_MEMBER( des_r); + DECLARE_READ8_MEMBER( fpllcont_r); + DECLARE_WRITE8_MEMBER( fpllcont_w); + DECLARE_READ8_MEMBER( pam_r); + DECLARE_WRITE8_MEMBER( pam_w); + DECLARE_READ8_MEMBER( smram_r); + DECLARE_WRITE8_MEMBER( smram_w); + DECLARE_READ8_MEMBER( esmramc_r); + DECLARE_WRITE8_MEMBER( esmramc_w); + DECLARE_READ32_MEMBER( acapid_r); + DECLARE_READ32_MEMBER( agpstat_r); + DECLARE_READ32_MEMBER( agpcmd_r); + DECLARE_READ32_MEMBER( agpctrl_r); + DECLARE_WRITE32_MEMBER(agpctrl_w); + DECLARE_READ8_MEMBER( apsize_r); + DECLARE_WRITE8_MEMBER( apsize_w); + DECLARE_READ32_MEMBER( attbase_r); + DECLARE_WRITE32_MEMBER(attbase_w); + DECLARE_READ8_MEMBER( amtt_r); + DECLARE_WRITE8_MEMBER( amtt_w); + DECLARE_READ8_MEMBER( lptt_r); + DECLARE_WRITE8_MEMBER( lptt_w); + DECLARE_READ16_MEMBER( toud_r); + DECLARE_WRITE16_MEMBER(toud_w); + DECLARE_READ16_MEMBER( mchcfg_r); + DECLARE_WRITE16_MEMBER(mchcfg_w); + DECLARE_READ16_MEMBER( errsts_r); + DECLARE_READ16_MEMBER( errcmd_r); + DECLARE_WRITE16_MEMBER(errcmd_w); + DECLARE_READ16_MEMBER( smicmd_r); + DECLARE_WRITE16_MEMBER(smicmd_w); + DECLARE_READ16_MEMBER( scicmd_r); + DECLARE_WRITE16_MEMBER(scicmd_w); + DECLARE_READ16_MEMBER( skpd_r); + DECLARE_WRITE16_MEMBER(skpd_w); + DECLARE_READ32_MEMBER( capreg1_r); + DECLARE_READ8_MEMBER( capreg2_r); + +protected: + virtual void device_start(); + virtual void device_reset(); + +private: + DECLARE_ADDRESS_MAP(agp_translation_map, 32); + + const char *cpu_tag; + int ram_size; + cpu_device *cpu; + std::vector ram; + + UINT8 agpm, fpllcont, pam[8], smram, esmramc; + UINT8 apsize, amtt, lptt; + UINT16 toud, mchcfg, errcmd, smicmd, scicmd, skpd; + UINT32 agpctrl, attbase; +}; + +class i82875p_agp_device : public agp_bridge_device { +public: + i82875p_agp_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual void device_start(); + virtual void device_reset(); +}; + +class i82875p_overflow_device : public pci_device { +public: + i82875p_overflow_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + + DECLARE_READ8_MEMBER (dram_row_boundary_r); + DECLARE_WRITE8_MEMBER (dram_row_boundary_w); + DECLARE_READ8_MEMBER (dram_row_attribute_r); + DECLARE_WRITE8_MEMBER (dram_row_attribute_w); + DECLARE_READ32_MEMBER (dram_timing_r); + DECLARE_WRITE32_MEMBER(dram_timing_w); + DECLARE_READ32_MEMBER (dram_controller_mode_r); + DECLARE_WRITE32_MEMBER(dram_controller_mode_w); + +protected: + + virtual void device_start(); + virtual void device_reset(); + +private: + DECLARE_ADDRESS_MAP(overflow_map, 32); + + UINT8 dram_row_boundary[8], dram_row_attribute[4]; + UINT32 dram_timing, dram_controller_mode; +}; + +extern const device_type I82875P_HOST; +extern const device_type I82875P_AGP; +extern const device_type I82875P_OVERFLOW; + + +#endif diff --git a/src/devices/machine/i8355.c b/src/devices/machine/i8355.c new file mode 100644 index 00000000000..d417bd1e3c3 --- /dev/null +++ b/src/devices/machine/i8355.c @@ -0,0 +1,210 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Intel 8355 - 16,384-Bit ROM with I/O emulation + +**********************************************************************/ + +#include "emu.h" +#include "i8355.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define LOG 0 + +enum +{ + REGISTER_PORT_A = 0, + REGISTER_PORT_B, + REGISTER_PORT_A_DDR, + REGISTER_PORT_B_DDR +}; + +enum +{ + PORT_A = 0, + PORT_B, + PORT_COUNT +}; + + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +// device type definition +const device_type I8355 = &device_creator; + +// default address map +static ADDRESS_MAP_START( i8355, AS_0, 8, i8355_device ) + AM_RANGE(0x000, 0x7ff) AM_ROM +ADDRESS_MAP_END + + + +//************************************************************************** +// INLINE HELPERS +//************************************************************************** + +//------------------------------------------------- +// read_port - read from input port +//------------------------------------------------- + +inline UINT8 i8355_device::read_port(int port) +{ + UINT8 data = m_output[port] & m_ddr[port]; + + if (m_ddr[port] != 0xff) + { + if (port == 0) {data |= m_in_pa_cb(0) & ~m_ddr[port];} + else { data |= m_in_pb_cb(0) & ~m_ddr[port];} + } + + return data; +} + + +//------------------------------------------------- +// write_port - write to output port +//------------------------------------------------- + +inline void i8355_device::write_port(int port, UINT8 data) +{ + m_output[port] = data; + + if (port == 0) {m_out_pa_cb((offs_t)0, m_output[port] & m_ddr[port]);} + else {m_out_pb_cb((offs_t)0, m_output[port] & m_ddr[port]);} +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// i8355_device - constructor +//------------------------------------------------- + +i8355_device::i8355_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, I8355, "Intel 8355", tag, owner, clock, "i8355", __FILE__), + device_memory_interface(mconfig, *this), + m_in_pa_cb(*this), + m_out_pa_cb(*this), + m_in_pb_cb(*this), + m_out_pb_cb(*this), + m_space_config("ram", ENDIANNESS_LITTLE, 8, 11, 0, NULL, *ADDRESS_MAP_NAME(i8355)) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void i8355_device::device_start() +{ + // resolve callbacks + m_in_pa_cb.resolve_safe(0); + m_in_pb_cb.resolve_safe(0); + m_out_pa_cb.resolve_safe(); + m_out_pb_cb.resolve_safe(); + + // register for state saving + save_item(NAME(m_output)); + save_item(NAME(m_ddr)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void i8355_device::device_reset() +{ + // set ports to input mode + m_ddr[PORT_A] = 0; + m_ddr[PORT_B] = 0; +} + + +//------------------------------------------------- +// memory_space_config - return a description of +// any address spaces owned by this device +//------------------------------------------------- + +const address_space_config *i8355_device::memory_space_config(address_spacenum spacenum) const +{ + return (spacenum == AS_0) ? &m_space_config : NULL; +} + + + +//------------------------------------------------- +// io_r - register read +//------------------------------------------------- + +READ8_MEMBER( i8355_device::io_r ) +{ + int port = offset & 0x01; + + UINT8 data = 0; + + switch (offset & 0x03) + { + case REGISTER_PORT_A: + case REGISTER_PORT_B: + data = read_port(port); + break; + + case REGISTER_PORT_A_DDR: + case REGISTER_PORT_B_DDR: + // write only + break; + } + + return data; +} + + +//------------------------------------------------- +// io_w - register write +//------------------------------------------------- + +WRITE8_MEMBER( i8355_device::io_w ) +{ + int port = offset & 0x01; + + switch (offset & 0x03) + { + case REGISTER_PORT_A: + case REGISTER_PORT_B: + if (LOG) logerror("I8355 '%s' Port %c Write %02x\n", tag(), 'A' + port, data); + + write_port(port, data); + break; + + case REGISTER_PORT_A_DDR: + case REGISTER_PORT_B_DDR: + if (LOG) logerror("I8355 '%s' Port %c DDR: %02x\n", tag(), 'A' + port, data); + + m_ddr[port] = data; + write_port(port, data); + break; + } +} + + +//------------------------------------------------- +// memory_r - internal ROM read +//------------------------------------------------- + +READ8_MEMBER( i8355_device::memory_r ) +{ + return this->space().read_byte(offset); +} diff --git a/src/devices/machine/i8355.h b/src/devices/machine/i8355.h new file mode 100644 index 00000000000..33d68d0fa57 --- /dev/null +++ b/src/devices/machine/i8355.h @@ -0,0 +1,120 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Intel 8355 - 16,384-Bit ROM with I/O emulation + +********************************************************************** + _____ _____ + _CE1 1 |* \_/ | 40 Vcc + CE2 2 | | 39 PB7 + CLK 3 | | 38 PB6 + RESET 4 | | 37 PB5 + N.C. 5 | | 36 PB4 + READY 6 | | 35 PB3 + IO/_M 7 | | 34 PB2 + _IOR 8 | | 33 PB1 + _RD 9 | | 32 PB0 + _IOW 10 | 8355 | 31 PA7 + ALE 11 | 8355-2 | 30 PA6 + AD0 12 | | 29 PA5 + AD1 13 | | 28 PA4 + AD2 14 | | 27 PA3 + AD3 15 | | 26 PA2 + AD4 16 | | 25 PA1 + AD5 17 | | 24 PA0 + AD6 18 | | 23 A10 + AD7 19 | | 22 A9 + Vss 20 |_____________| 21 A8 + +**********************************************************************/ + +#pragma once + +#ifndef __I8355__ +#define __I8355__ + +#include "emu.h" + + + +///************************************************************************* +// MACROS / CONSTANTS +///************************************************************************* + + + + +///************************************************************************* +// INTERFACE CONFIGURATION MACROS +///************************************************************************* + +#define MCFG_I8355_IN_PA_CB(_devcb) \ + devcb = &i8355_device::set_in_pa_callback(*device, DEVCB_##_devcb); + +#define MCFG_I8355_OUT_PA_CB(_devcb) \ + devcb = &i8355_device::set_out_pa_callback(*device, DEVCB_##_devcb); + +#define MCFG_I8355_IN_PB_CB(_devcb) \ + devcb = &i8355_device::set_in_pb_callback(*device, DEVCB_##_devcb); + +#define MCFG_I8355_OUT_PB_CB(_devcb) \ + devcb = &i8355_device::set_out_pb_callback(*device, DEVCB_##_devcb); + + +///************************************************************************* +// TYPE DEFINITIONS +///************************************************************************* + +// ======================> i8355_device + +class i8355_device : public device_t, + public device_memory_interface +{ +public: + // construction/destruction + i8355_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + template static devcb_base &set_in_pa_callback(device_t &device, _Object object) { return downcast(device).m_in_pa_cb.set_callback(object); } + template static devcb_base &set_out_pa_callback(device_t &device, _Object object) { return downcast(device).m_out_pa_cb.set_callback(object); } + template static devcb_base &set_in_pb_callback(device_t &device, _Object object) { return downcast(device).m_in_pb_cb.set_callback(object); } + template static devcb_base &set_out_pb_callback(device_t &device, _Object object) { return downcast(device).m_out_pb_cb.set_callback(object); } + + DECLARE_READ8_MEMBER( io_r ); + DECLARE_WRITE8_MEMBER( io_w ); + + DECLARE_READ8_MEMBER( memory_r ); + DECLARE_WRITE8_MEMBER( memory_w ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const; + + inline UINT8 read_port(int port); + inline void write_port(int port, UINT8 data); + +private: + devcb_read8 m_in_pa_cb; + devcb_write8 m_out_pa_cb; + + devcb_read8 m_in_pb_cb; + devcb_write8 m_out_pb_cb; + + // registers + UINT8 m_output[2]; // output latches + UINT8 m_ddr[2]; // DDR latches + + const address_space_config m_space_config; +}; + + +// device type definition +extern const device_type I8355; + + + +#endif diff --git a/src/devices/machine/idectrl.c b/src/devices/machine/idectrl.c new file mode 100644 index 00000000000..403364d57c1 --- /dev/null +++ b/src/devices/machine/idectrl.c @@ -0,0 +1,393 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/*************************************************************************** + + idectrl.c + + Generic (PC-style) IDE controller implementation. + +***************************************************************************/ + +#include "idectrl.h" + + +/*************************************************************************** + DEBUGGING +***************************************************************************/ + +#define VERBOSE 0 + +#define LOG(x) do { if (VERBOSE) logerror x; } while (0) + + +/*************************************************************************** + CONSTANTS +***************************************************************************/ + +const device_type IDE_CONTROLLER = &device_creator; + +ide_controller_device::ide_controller_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + ata_interface_device(mconfig, IDE_CONTROLLER, "IDE Controller", tag, owner, clock, "ide_controller", __FILE__) +{ +} + +ide_controller_device::ide_controller_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + ata_interface_device(mconfig, type, name, tag, owner, clock, shortname, source) +{ +} + +READ16_MEMBER( ide_controller_device::read_cs0 ) +{ + if (mem_mask == 0xffff && offset == 1 ){ offset = 0; popmessage( "requires ide_controller_32_device" ); } + if (mem_mask == 0xff00) + { + return ata_interface_device::read_cs0(space, (offset * 2) + 1, 0xff) << 8; + } + else + { + return ata_interface_device::read_cs0(space, offset * 2, mem_mask); + } +} + +READ16_MEMBER( ide_controller_device::read_cs1 ) +{ + if (mem_mask == 0xff00) + { + return ata_interface_device::read_cs1(space, (offset * 2) + 1, 0xff) << 8; + } + else + { + return ata_interface_device::read_cs1(space, offset * 2, mem_mask); + } +} + +WRITE16_MEMBER( ide_controller_device::write_cs0 ) +{ + if (mem_mask == 0xffff && offset == 1 ){ offset = 0; popmessage( "requires ide_controller_32_device" ); } + if (mem_mask == 0xff00) + { + return ata_interface_device::write_cs0(space, (offset * 2) + 1, data >> 8, 0xff); + } + else + { + return ata_interface_device::write_cs0(space, offset * 2, data, mem_mask); + } +} + +WRITE16_MEMBER( ide_controller_device::write_cs1 ) +{ + if (mem_mask == 0xff00) + { + return ata_interface_device::write_cs1(space, (offset * 2) + 1, data >> 8, 0xff); + } + else + { + return ata_interface_device::write_cs1(space, offset * 2, data, mem_mask); + } +} + + +const device_type IDE_CONTROLLER_32 = &device_creator; + +ide_controller_32_device::ide_controller_32_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + ide_controller_device(mconfig, IDE_CONTROLLER, "IDE Controller (32 bit)", tag, owner, clock, "ide_controller", __FILE__) +{ +} + +ide_controller_32_device::ide_controller_32_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + ide_controller_device(mconfig, type, name, tag, owner, clock, shortname, source) +{ +} + +READ32_MEMBER(ide_controller_32_device::read_cs0) +{ + UINT32 data = 0; + + if (ACCESSING_BITS_0_15) + { + data = ide_controller_device::read_cs0(space, (offset * 2), mem_mask); + + if (offset == 0 && ACCESSING_BITS_16_31) + data |= ide_controller_device::read_cs0(space, (offset * 2), mem_mask >> 16) << 16; + } + else if (ACCESSING_BITS_16_31) + { + data = ide_controller_device::read_cs0(space, (offset * 2) + 1, mem_mask >> 16) << 16; + } + + return data; +} + +READ32_MEMBER(ide_controller_32_device::read_cs1) +{ + UINT32 data = 0; + + if (ACCESSING_BITS_0_15) + { + data = ide_controller_device::read_cs1(space, (offset * 2), mem_mask); + } + else if (ACCESSING_BITS_16_23) + { + data = ide_controller_device::read_cs1(space, (offset * 2) + 1, mem_mask >> 16) << 16; + } + + return data; +} + +WRITE32_MEMBER(ide_controller_32_device::write_cs0) +{ + if (ACCESSING_BITS_0_15) + { + ide_controller_device::write_cs0(space, (offset * 2), data, mem_mask); + + if (offset == 0 && ACCESSING_BITS_16_31) + ata_interface_device::write_cs0(space, (offset * 2), data >> 16, mem_mask >> 16); + } + else if (ACCESSING_BITS_16_31) + { + ide_controller_device::write_cs0(space, (offset * 2) + 1, data >> 16, mem_mask >> 16); + } +} + +WRITE32_MEMBER(ide_controller_32_device::write_cs1) +{ + if (ACCESSING_BITS_0_15) + { + ide_controller_device::write_cs1(space, (offset * 2), data, mem_mask); + } + else if (ACCESSING_BITS_16_31) + { + ide_controller_device::write_cs1(space, (offset * 2) + 1, data >> 16, mem_mask >> 16); + } +} + + +#define IDE_BUSMASTER_STATUS_ACTIVE 0x01 +#define IDE_BUSMASTER_STATUS_ERROR 0x02 +#define IDE_BUSMASTER_STATUS_IRQ 0x04 + +const device_type BUS_MASTER_IDE_CONTROLLER = &device_creator; + +bus_master_ide_controller_device::bus_master_ide_controller_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + ide_controller_32_device(mconfig, BUS_MASTER_IDE_CONTROLLER, "Bus Master IDE Controller", tag, owner, clock, "bus_master_ide_controller", __FILE__), + m_dma_address(0), + m_dma_bytes_left(0), + m_dma_descriptor(0), + m_dma_last_buffer(0), + m_bus_master_command(0), + m_bus_master_status(0), + m_bus_master_descriptor(0), + m_irq(0), + m_dmarq(0) +{ +} + +void bus_master_ide_controller_device::device_start() +{ + ide_controller_32_device::device_start(); + + /* find the bus master space */ + if (m_bmcpu != NULL) + { + device_t *bmtarget = machine().device(m_bmcpu); + if (bmtarget == NULL) + throw emu_fatalerror("IDE controller '%s' bus master target '%s' doesn't exist!", tag(), m_bmcpu); + device_memory_interface *memory; + if (!bmtarget->interface(memory)) + throw emu_fatalerror("IDE controller '%s' bus master target '%s' has no memory!", tag(), m_bmcpu); + m_dma_space = &memory->space(m_bmspace); + m_dma_address_xor = (m_dma_space->endianness() == ENDIANNESS_LITTLE) ? 0 : 3; + } + + save_item(NAME(m_dma_address)); + save_item(NAME(m_dma_bytes_left)); + save_item(NAME(m_dma_descriptor)); + save_item(NAME(m_dma_last_buffer)); + save_item(NAME(m_bus_master_command)); + save_item(NAME(m_bus_master_status)); + save_item(NAME(m_bus_master_descriptor)); +} + +void bus_master_ide_controller_device::set_irq(int state) +{ + ata_interface_device::set_irq(state); + + if (m_irq != state) + { + m_irq = state; + + if( m_irq ) + m_bus_master_status |= IDE_BUSMASTER_STATUS_IRQ; + } +} + +void bus_master_ide_controller_device::set_dmarq(int state) +{ + ata_interface_device::set_dmarq(state); + + if (m_dmarq != state) + { + m_dmarq = state; + + execute_dma(); + } +} + +/************************************* + * + * Bus master read + * + *************************************/ + +READ32_MEMBER( bus_master_ide_controller_device::bmdma_r ) +{ + LOG(("%s:ide_bus_master32_r(%d, %08x)\n", machine().describe_context(), offset, mem_mask)); + + switch( offset ) + { + case 0: + /* command register/status register */ + return m_bus_master_command | (m_bus_master_status << 16); + + case 1: + /* descriptor table register */ + return m_bus_master_descriptor; + } + + return 0xffffffff; +} + + + +/************************************* + * + * Bus master write + * + *************************************/ + +WRITE32_MEMBER( bus_master_ide_controller_device::bmdma_w ) +{ + LOG(("%s:ide_bus_master32_w(%d, %08x, %08X)\n", machine().describe_context(), offset, mem_mask, data)); + + switch( offset ) + { + case 0: + if( ACCESSING_BITS_0_7 ) + { + /* command register */ + UINT8 old = m_bus_master_command; + UINT8 val = data & 0xff; + + /* save the read/write bit and the start/stop bit */ + m_bus_master_command = (old & 0xf6) | (val & 0x09); + + if ((old ^ m_bus_master_command) & 1) + { + if (m_bus_master_command & 1) + { + /* handle starting a transfer */ + m_bus_master_status |= IDE_BUSMASTER_STATUS_ACTIVE; + + /* reset all the DMA data */ + m_dma_bytes_left = 0; + m_dma_descriptor = m_bus_master_descriptor; + + /* if we're going live, start the pending read/write */ + execute_dma(); + } + else if (m_bus_master_status & IDE_BUSMASTER_STATUS_ACTIVE) + { + m_bus_master_status &= ~IDE_BUSMASTER_STATUS_ACTIVE; + + LOG(("DMA Aborted!\n")); + } + } + } + + if( ACCESSING_BITS_16_23 ) + { + /* status register */ + UINT8 old = m_bus_master_status; + UINT8 val = data >> 16; + + /* save the DMA capable bits */ + m_bus_master_status = (old & 0x9f) | (val & 0x60); + + /* clear interrupt and error bits */ + if (val & IDE_BUSMASTER_STATUS_IRQ) + m_bus_master_status &= ~IDE_BUSMASTER_STATUS_IRQ; + if (val & IDE_BUSMASTER_STATUS_ERROR) + m_bus_master_status &= ~IDE_BUSMASTER_STATUS_ERROR; + } + break; + + case 1: + /* descriptor table register */ + m_bus_master_descriptor = data & 0xfffffffc; + break; + } +} + +void bus_master_ide_controller_device::execute_dma() +{ + write_dmack(ASSERT_LINE); + + while (m_dmarq && (m_bus_master_status & IDE_BUSMASTER_STATUS_ACTIVE)) + { + /* if we're out of space, grab the next descriptor */ + if (m_dma_bytes_left == 0) + { + /* fetch the address */ + m_dma_address = m_dma_space->read_byte(m_dma_descriptor++ ^ m_dma_address_xor); + m_dma_address |= m_dma_space->read_byte(m_dma_descriptor++ ^ m_dma_address_xor) << 8; + m_dma_address |= m_dma_space->read_byte(m_dma_descriptor++ ^ m_dma_address_xor) << 16; + m_dma_address |= m_dma_space->read_byte(m_dma_descriptor++ ^ m_dma_address_xor) << 24; + m_dma_address &= 0xfffffffe; + + /* fetch the length */ + m_dma_bytes_left = m_dma_space->read_byte(m_dma_descriptor++ ^ m_dma_address_xor); + m_dma_bytes_left |= m_dma_space->read_byte(m_dma_descriptor++ ^ m_dma_address_xor) << 8; + m_dma_bytes_left |= m_dma_space->read_byte(m_dma_descriptor++ ^ m_dma_address_xor) << 16; + m_dma_bytes_left |= m_dma_space->read_byte(m_dma_descriptor++ ^ m_dma_address_xor) << 24; + m_dma_last_buffer = (m_dma_bytes_left >> 31) & 1; + m_dma_bytes_left &= 0xfffe; + if (m_dma_bytes_left == 0) + m_dma_bytes_left = 0x10000; + +// LOG(("New DMA descriptor: address = %08X bytes = %04X last = %d\n", m_dma_address, m_dma_bytes_left, m_dma_last_buffer)); + } + + if (m_bus_master_command & 8) + { + // read from ata bus + UINT16 data = read_dma(); + + // write to memory + m_dma_space->write_byte(m_dma_address++, data & 0xff); + m_dma_space->write_byte(m_dma_address++, data >> 8); + } + else + { + // read from memory; + UINT16 data = m_dma_space->read_byte(m_dma_address++); + data |= m_dma_space->read_byte(m_dma_address++) << 8; + + // write to ata bus + write_dma(data); + } + + m_dma_bytes_left -= 2; + + if (m_dma_bytes_left == 0 && m_dma_last_buffer) + { + m_bus_master_status &= ~IDE_BUSMASTER_STATUS_ACTIVE; + + if (m_dmarq) + { + LOG(("DMA Out of buffer space!\n")); + } + } + } + + write_dmack(CLEAR_LINE); +} diff --git a/src/devices/machine/idectrl.h b/src/devices/machine/idectrl.h new file mode 100644 index 00000000000..d31490e2385 --- /dev/null +++ b/src/devices/machine/idectrl.h @@ -0,0 +1,121 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/*************************************************************************** + + idectrl.h + + Generic (PC-style) IDE controller implementation. + +***************************************************************************/ + +#pragma once + +#ifndef __IDECTRL_H__ +#define __IDECTRL_H__ + +#include "ataintf.h" + +/*************************************************************************** + DEVICE CONFIGURATION MACROS +***************************************************************************/ + +#define MCFG_IDE_CONTROLLER_ADD(_tag, _slot_intf, _master, _slave, _fixed) \ + MCFG_DEVICE_ADD(_tag, IDE_CONTROLLER, 0) \ + MCFG_DEVICE_MODIFY(_tag ":0") \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _master, _fixed) \ + MCFG_DEVICE_MODIFY(_tag ":1") \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _slave, _fixed) \ + MCFG_DEVICE_MODIFY(_tag) + +class ide_controller_device : public ata_interface_device +{ +public: + ide_controller_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + ide_controller_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + virtual DECLARE_READ16_MEMBER(read_cs0); + virtual DECLARE_READ16_MEMBER(read_cs1); + virtual DECLARE_WRITE16_MEMBER(write_cs0); + virtual DECLARE_WRITE16_MEMBER(write_cs1); +}; + +extern const device_type IDE_CONTROLLER; + + +#define MCFG_IDE_CONTROLLER_32_ADD(_tag, _slot_intf, _master, _slave, _fixed) \ + MCFG_DEVICE_ADD(_tag, IDE_CONTROLLER_32, 0) \ + MCFG_DEVICE_MODIFY(_tag ":0") \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _master, _fixed) \ + MCFG_DEVICE_MODIFY(_tag ":1") \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _slave, _fixed) \ + MCFG_DEVICE_MODIFY(_tag) + +class ide_controller_32_device : public ide_controller_device +{ +public: + ide_controller_32_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + ide_controller_32_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + virtual DECLARE_READ32_MEMBER(read_cs0); + virtual DECLARE_READ32_MEMBER(read_cs1); + virtual DECLARE_WRITE32_MEMBER(write_cs0); + virtual DECLARE_WRITE32_MEMBER(write_cs1); + +private: + using ide_controller_device::read_cs0; + using ide_controller_device::read_cs1; + using ide_controller_device::write_cs0; + using ide_controller_device::write_cs1; +}; + +extern const device_type IDE_CONTROLLER_32; + + +#define MCFG_BUS_MASTER_IDE_CONTROLLER_ADD(_tag, _slot_intf, _master, _slave, _fixed) \ + MCFG_DEVICE_ADD(_tag, BUS_MASTER_IDE_CONTROLLER, 0) \ + MCFG_DEVICE_MODIFY(_tag ":0") \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _master, _fixed) \ + MCFG_DEVICE_MODIFY(_tag ":1") \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _slave, _fixed) \ + MCFG_DEVICE_MODIFY(_tag) + +#define MCFG_BUS_MASTER_IDE_CONTROLLER_SPACE(bmcpu, bmspace) \ + bus_master_ide_controller_device::set_bus_master_space(*device, bmcpu, bmspace); + +class bus_master_ide_controller_device : public ide_controller_32_device +{ +public: + bus_master_ide_controller_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + static void set_bus_master_space(device_t &device, const char *bmcpu, UINT32 bmspace) {bus_master_ide_controller_device &ide = downcast(device); ide.m_bmcpu = bmcpu; ide.m_bmspace = bmspace; } + + DECLARE_READ32_MEMBER( bmdma_r ); + DECLARE_WRITE32_MEMBER( bmdma_w ); + +protected: + virtual void device_start(); + + virtual void set_irq(int state); + virtual void set_dmarq(int state); + +private: + void execute_dma(); + + const char *m_bmcpu; + UINT32 m_bmspace; + address_space * m_dma_space; + UINT8 m_dma_address_xor; + + offs_t m_dma_address; + UINT32 m_dma_bytes_left; + offs_t m_dma_descriptor; + UINT8 m_dma_last_buffer; + UINT8 m_bus_master_command; + UINT8 m_bus_master_status; + UINT32 m_bus_master_descriptor; + int m_irq; + int m_dmarq; +}; + +extern const device_type BUS_MASTER_IDE_CONTROLLER; + +#endif /* __IDECTRL_H__ */ diff --git a/src/devices/machine/idehd.c b/src/devices/machine/idehd.c new file mode 100644 index 00000000000..aa5517a1a3e --- /dev/null +++ b/src/devices/machine/idehd.c @@ -0,0 +1,836 @@ +// license:BSD-3-Clause +// copyright-holders:smf +#include "idehd.h" + +/*************************************************************************** + DEBUGGING +***************************************************************************/ + +#define VERBOSE 0 +#define PRINTF_IDE_COMMANDS 0 +#define PRINTF_IDE_PASSWORD 0 + +#define LOGPRINT(x) do { if (VERBOSE) logerror x; if (PRINTF_IDE_COMMANDS) osd_printf_debug x; } while (0) + +#define TIME_PER_SECTOR_WRITE (attotime::from_usec(100)) +/* read time <2 breaks primrag2, ==100 breaks bm1stmix */ +#define TIME_PER_SECTOR_READ (attotime::from_usec(2)) +#define TIME_PER_ROTATION (attotime::from_hz(5400/60)) +#define TIME_BETWEEN_SECTORS (attotime::from_nsec(400)) + +#define TIME_FULL_STROKE_SEEK (attotime::from_usec(13000)) +#define TIME_AVERAGE_ROTATIONAL_LATENCY (attotime::from_usec(1300)) + +ata_mass_storage_device::ata_mass_storage_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock,const char *shortname, const char *source) + : ata_hle_device(mconfig, type, name, tag, owner, clock, shortname, source), + m_can_identify_device(0), + m_num_cylinders(0), + m_num_sectors(0), + m_num_heads(0), + m_master_password(NULL), + m_user_password(NULL) +{ +} + +/************************************* + * + * Compute the LBA address + * + *************************************/ + +UINT32 ata_mass_storage_device::lba_address() +{ + /* LBA direct? */ + if (m_device_head & IDE_DEVICE_HEAD_L) + return ((m_device_head & IDE_DEVICE_HEAD_HS) << 24) | (m_cylinder_high << 16) | (m_cylinder_low << 8) | m_sector_number; + + /* standard CHS */ + else + return (((((m_cylinder_high << 8) | m_cylinder_low) * m_num_heads) + (m_device_head & IDE_DEVICE_HEAD_HS)) * m_num_sectors) + m_sector_number - 1; +} + + +/************************************* + * + * Build a features page + * + *************************************/ + +static void swap_strncpy(UINT16 *dst, const char *src, int field_size_in_words) +{ + for (int i = 0; i < field_size_in_words; i++) + { + UINT16 d = 0; + + if (*src) + { + d = *(src++) << 8; + } + else + { + d = ' ' << 8; + } + + if (*src) + { + d |= *(src++); + } + else + { + d |= ' '; + } + + dst[i] = d; + } + + assert(*(src) == 0); +} + + +void ata_mass_storage_device::ide_build_identify_device() +{ + memset(m_identify_buffer, 0, sizeof(m_identify_buffer)); + int total_sectors = m_num_cylinders * m_num_heads * m_num_sectors; + + /* basic geometry */ + m_identify_buffer[0] = 0x045a; /* 0: configuration bits */ + m_identify_buffer[1] = m_num_cylinders; /* 1: logical cylinders */ + m_identify_buffer[2] = 0; /* 2: reserved */ + m_identify_buffer[3] = m_num_heads; /* 3: logical heads */ + m_identify_buffer[4] = 0; /* 4: vendor specific (obsolete) */ + m_identify_buffer[5] = 0; /* 5: vendor specific (obsolete) */ + m_identify_buffer[6] = m_num_sectors; /* 6: logical sectors per logical track */ + m_identify_buffer[7] = 0; /* 7: vendor-specific */ + m_identify_buffer[8] = 0; /* 8: vendor-specific */ + m_identify_buffer[9] = 0; /* 9: vendor-specific */ + swap_strncpy(&m_identify_buffer[10], /* 10-19: serial number */ + "00000000000000000000", 10); + m_identify_buffer[20] = 0; /* 20: vendor-specific */ + m_identify_buffer[21] = 0; /* 21: vendor-specific */ + m_identify_buffer[22] = 4; /* 22: # of vendor-specific bytes on read/write long commands */ + swap_strncpy(&m_identify_buffer[23], /* 23-26: firmware revision */ + "1.0", 4); + swap_strncpy(&m_identify_buffer[27], /* 27-46: model number */ + "MAME Compressed Hard Disk", 20); + m_identify_buffer[47] = 0x8001; /* 47: read/write multiple support */ + m_identify_buffer[48] = 0; /* 48: reserved */ + m_identify_buffer[49] = 0x0f03; /* 49: capabilities */ + m_identify_buffer[50] = 0; /* 50: reserved */ + m_identify_buffer[51] = 2; /* 51: PIO data transfer cycle timing mode */ + m_identify_buffer[52] = 2; /* 52: single word DMA transfer cycle timing mode */ + m_identify_buffer[53] = 3; /* 53: field validity */ + m_identify_buffer[54] = m_num_cylinders; /* 54: number of current logical cylinders */ + m_identify_buffer[55] = m_num_heads; /* 55: number of current logical heads */ + m_identify_buffer[56] = m_num_sectors; /* 56: number of current logical sectors per track */ + m_identify_buffer[57] = total_sectors & 0xffff; /* 57-58: current capacity in sectors (ATA-1 through ATA-5; obsoleted in ATA-6) */ + m_identify_buffer[58] = total_sectors >> 16; + m_identify_buffer[59] = 0; /* 59: multiple sector timing */ + m_identify_buffer[60] = total_sectors & 0xffff; /* 60-61: total user addressable sectors for LBA mode (ATA-1 through ATA-7) */ + m_identify_buffer[61] = total_sectors >> 16; + m_identify_buffer[62] = 0x0007; /* 62: single word dma transfer */ + m_identify_buffer[63] = 0x0407; /* 63: multiword DMA transfer */ + m_identify_buffer[64] = 0x0003; /* 64: flow control PIO transfer modes supported */ + m_identify_buffer[65] = 0x78; /* 65: minimum multiword DMA transfer cycle time per word */ + m_identify_buffer[66] = 0x78; /* 66: mfr's recommended multiword DMA transfer cycle time */ + m_identify_buffer[67] = 0x014d; /* 67: minimum PIO transfer cycle time without flow control */ + m_identify_buffer[68] = 0x78; /* 68: minimum PIO transfer cycle time with IORDY */ + m_identify_buffer[69] = 0x00; /* 69-70: reserved */ + m_identify_buffer[71] = 0x00; /* 71: reserved for IDENTIFY PACKET command */ + m_identify_buffer[72] = 0x00; /* 72: reserved for IDENTIFY PACKET command */ + m_identify_buffer[73] = 0x00; /* 73: reserved for IDENTIFY PACKET command */ + m_identify_buffer[74] = 0x00; /* 74: reserved for IDENTIFY PACKET command */ + m_identify_buffer[75] = 0x00; /* 75: queue depth */ + m_identify_buffer[76] = 0x00; /* 76-79: reserved */ + m_identify_buffer[80] = 0x00; /* 80: major version number */ + m_identify_buffer[81] = 0x00; /* 81: minor version number */ + m_identify_buffer[82] = 0x00; /* 82: command set supported */ + m_identify_buffer[83] = 0x00; /* 83: command sets supported */ + m_identify_buffer[84] = 0x00; /* 84: command set/feature supported extension */ + m_identify_buffer[85] = 0x00; /* 85: command set/feature enabled */ + m_identify_buffer[86] = 0x00; /* 86: command set/feature enabled */ + m_identify_buffer[87] = 0x00; /* 87: command set/feature default */ + m_identify_buffer[88] = 0x00; /* 88: additional DMA modes */ + m_identify_buffer[89] = 0x00; /* 89: time required for security erase unit completion */ + m_identify_buffer[90] = 0x00; /* 90: time required for enhanced security erase unit completion */ + m_identify_buffer[91] = 0x00; /* 91: current advanced power management value */ + m_identify_buffer[92] = 0x00; /* 92: master password revision code */ + m_identify_buffer[93] = 0x00; /* 93: hardware reset result */ + m_identify_buffer[94] = 0x00; /* 94: acoustic management values */ + m_identify_buffer[95] = 0x00; /* 95-99: reserved */ + m_identify_buffer[100] = total_sectors & 0xffff; /* 100-103: maximum 48-bit LBA */ + m_identify_buffer[101] = total_sectors >> 16; + m_identify_buffer[102] = 0x00; + m_identify_buffer[103] = 0x00; + m_identify_buffer[104] = 0x00; /* 104-126: reserved */ + m_identify_buffer[127] = 0x00; /* 127: removable media status notification */ + m_identify_buffer[128] = 0x00; /* 128: security status */ + m_identify_buffer[129] = 0x00; /* 129-159: vendor specific */ + m_identify_buffer[160] = 0x00; /* 160: CFA power mode 1 */ + m_identify_buffer[161] = 0x00; /* 161-175: reserved for CompactFlash */ + m_identify_buffer[176] = 0x00; /* 176-205: current media serial number */ + m_identify_buffer[206] = 0x00; /* 206-254: reserved */ + m_identify_buffer[255] = 0x00; /* 255: integrity word */ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void ata_mass_storage_device::device_start() +{ + ata_hle_device::device_start(); + + save_item(NAME(m_can_identify_device)); + save_item(NAME(m_num_cylinders)); + save_item(NAME(m_num_sectors)); + save_item(NAME(m_num_heads)); + + save_item(NAME(m_cur_lba)); + save_item(NAME(m_sectors_until_int)); + save_item(NAME(m_master_password_enable)); + save_item(NAME(m_user_password_enable)); + save_item(NAME(m_block_count)); +} + +void ata_mass_storage_device::soft_reset() +{ + ata_hle_device::soft_reset(); + + m_cur_lba = 0; + m_status |= IDE_STATUS_DSC; + + m_master_password_enable = (m_master_password != NULL); + m_user_password_enable = (m_user_password != NULL); +} + +void ata_mass_storage_device::perform_diagnostic() +{ + if (m_can_identify_device) + m_error = IDE_ERROR_DIAGNOSTIC_PASSED; +} + +void ata_mass_storage_device::signature() +{ + m_sector_count = 1; + m_sector_number = 1; + m_cylinder_low = 0; + m_cylinder_high = 0; + m_device_head = 0; +} + +void ata_mass_storage_device::finished_command() +{ + int total_sectors = m_num_cylinders * m_num_heads * m_num_sectors; + + switch (m_command) + { + case IDE_COMMAND_IDENTIFY_DEVICE: + if (m_can_identify_device) + { + for( int w = 0; w < 256; w++ ) + { + m_buffer[w * 2] = m_identify_buffer[ w ] & 0xff; + m_buffer[(w * 2) + 1] = m_identify_buffer[ w ] >> 8; + } + + m_status |= IDE_STATUS_DRQ; + } + else + { + m_status |= IDE_STATUS_ERR; + m_error = IDE_ERROR_NONE; + } + + set_irq(ASSERT_LINE); + break; + + case IDE_COMMAND_SET_CONFIG: + set_geometry(m_sector_count,(m_device_head & IDE_DEVICE_HEAD_HS) + 1); + set_irq(ASSERT_LINE); + break; + + case IDE_COMMAND_READ_SECTORS: + case IDE_COMMAND_READ_SECTORS_NORETRY: + case IDE_COMMAND_READ_MULTIPLE: + case IDE_COMMAND_VERIFY_SECTORS: + case IDE_COMMAND_VERIFY_SECTORS_NORETRY: + case IDE_COMMAND_READ_DMA: + finished_read(); + break; + + case IDE_COMMAND_WRITE_SECTORS: + case IDE_COMMAND_WRITE_SECTORS_NORETRY: + case IDE_COMMAND_WRITE_MULTIPLE: + case IDE_COMMAND_WRITE_DMA: + finished_write(); + break; + + case IDE_COMMAND_RECALIBRATE: + set_irq(ASSERT_LINE); + break; + + case IDE_COMMAND_READ_NATIVE_MAX_ADDRESS: + m_buffer[0] = (total_sectors & 0xff000000) >> 24; + m_buffer[1] = (total_sectors & 0x00ff0000) >> 16; + m_buffer[2] = (total_sectors & 0x0000ff00) >> 8; + m_buffer[3] = (total_sectors & 0x000000ff); + set_irq(ASSERT_LINE); + break; + + default: + ata_hle_device::finished_command(); + break; + } +} + +/************************************* + * + * Advance to the next sector + * + *************************************/ + +void ata_mass_storage_device::next_sector() +{ + UINT8 cur_head = m_device_head & IDE_DEVICE_HEAD_HS; + + /* LBA direct? */ + if (m_device_head & IDE_DEVICE_HEAD_L) + { + m_sector_number++; + if (m_sector_number == 0) + { + m_cylinder_low++; + if (m_cylinder_low == 0) + { + m_cylinder_high++; + if (m_cylinder_high == 0) + cur_head++; + } + } + } + + /* standard CHS */ + else + { + /* sectors are 1-based */ + m_sector_number++; + if (m_sector_number > m_num_sectors) + { + /* heads are 0 based */ + m_sector_number = 1; + cur_head++; + if (cur_head >= m_num_heads) + { + cur_head = 0; + m_cylinder_low++; + if (m_cylinder_low == 0) + m_cylinder_high++; + } + } + } + + m_device_head = (m_device_head & ~IDE_DEVICE_HEAD_HS) | cur_head; + + m_cur_lba = lba_address(); +} + + + +/************************************* + * + * security error handling + * + *************************************/ + +void ata_mass_storage_device::security_error() +{ + /* set error state */ + m_status |= IDE_STATUS_ERR; + m_error = IDE_ERROR_NONE; + m_status &= ~IDE_STATUS_DRDY; +} + + + +/************************************* + * + * Sector reading + * + *************************************/ + +attotime ata_mass_storage_device::seek_time() +{ + int sectors_per_cylinder = m_num_heads * m_num_sectors; + + if (sectors_per_cylinder == 0 || m_num_cylinders == 0) + return attotime::zero; + + int new_lba = lba_address(); + int old_cylinder = m_cur_lba / sectors_per_cylinder; + int new_cylinder = new_lba / sectors_per_cylinder; + int diff = abs(old_cylinder - new_cylinder); + + m_cur_lba = new_lba; + + if (diff == 0) + return TIME_BETWEEN_SECTORS; + + attotime seek_time = (TIME_FULL_STROKE_SEEK * diff) / m_num_cylinders; + + return seek_time + TIME_AVERAGE_ROTATIONAL_LATENCY; +} + +void ata_mass_storage_device::fill_buffer() +{ + switch (m_command) + { + case IDE_COMMAND_IDENTIFY_DEVICE: + break; + + default: + /* if there is more data to read, keep going */ + if (m_sector_count > 0) + m_sector_count--; + + if (m_sector_count > 0) + { + set_dasp(ASSERT_LINE); + start_busy(TIME_PER_SECTOR_READ, PARAM_COMMAND); + } + break; + } +} + + +void ata_mass_storage_device::finished_read() +{ + int lba = lba_address(), count = 0; + + set_dasp(CLEAR_LINE); + + /* now do the read */ + count = read_sector(lba, &m_buffer[0]); + + /* if we succeeded, advance to the next sector and set the nice bits */ + if (count == 1) + { + /* advance the pointers, unless this is the last sector */ + /* Gauntlet: Dark Legacy checks to make sure we stop on the last sector */ + if (m_sector_count != 1) + next_sector(); + + /* signal an interrupt */ + if (--m_sectors_until_int == 0 || m_sector_count == 1) + { + m_sectors_until_int = ((m_command == IDE_COMMAND_READ_MULTIPLE) ? m_block_count : 1); + set_irq(ASSERT_LINE); + } + + /* if we're just verifying we can read the next sector */ + if (m_command == IDE_COMMAND_VERIFY_SECTORS || + m_command == IDE_COMMAND_VERIFY_SECTORS_NORETRY ) + { + read_buffer_empty(); + } + else + { + m_status |= IDE_STATUS_DRQ; + + if (m_command == IDE_COMMAND_READ_DMA) + set_dmarq(ASSERT_LINE); + } + } + + /* if we got an error, we need to report it */ + else + { + /* set the error flag and the error */ + m_status |= IDE_STATUS_ERR; + m_error = IDE_ERROR_BAD_SECTOR; + + /* signal an interrupt */ + set_irq(ASSERT_LINE); + } +} + + +void ata_mass_storage_device::read_first_sector() +{ + if (m_master_password_enable || m_user_password_enable) + { + security_error(); + } + else + { + set_dasp(ASSERT_LINE); + + start_busy(seek_time(), PARAM_COMMAND); + } +} + +/************************************* + * + * Sector writing + * + *************************************/ + +void ata_mass_storage_device::process_buffer() +{ + if (m_command == IDE_COMMAND_SECURITY_UNLOCK) + { + if (m_user_password_enable && memcmp(&m_buffer[0], m_user_password, 2 + 32) == 0) + { + LOGPRINT(("IDE Unlocked user password\n")); + m_user_password_enable = 0; + } + if (m_master_password_enable && memcmp(&m_buffer[0], m_master_password, 2 + 32) == 0) + { + LOGPRINT(("IDE Unlocked master password\n")); + m_master_password_enable = 0; + } + if (PRINTF_IDE_PASSWORD) + { + int i; + + for (i = 0; i < 34; i += 2) + { + if (i % 8 == 2) + osd_printf_debug("\n"); + + osd_printf_debug("0x%02x, 0x%02x, ", m_buffer[i], m_buffer[i + 1]); + //osd_printf_debug("0x%02x%02x, ", m_buffer[i], m_buffer[i + 1]); + } + osd_printf_debug("\n"); + } + + if (m_master_password_enable || m_user_password_enable) + security_error(); + } + else + { + set_dasp(ASSERT_LINE); + + if (m_command == IDE_COMMAND_WRITE_MULTIPLE) + { + if (m_sectors_until_int != 1) + { + /* ready to write now */ + finished_write(); + } + else + { + /* set a timer to do the write */ + start_busy(TIME_PER_SECTOR_WRITE, PARAM_COMMAND); + } + } + else + { + /* set a timer to do the write */ + start_busy(TIME_PER_SECTOR_WRITE, PARAM_COMMAND); + } + } +} + + +void ata_mass_storage_device::finished_write() +{ + int lba = lba_address(), count = 0; + + set_dasp(CLEAR_LINE); + + /* now do the write */ + count = write_sector(lba, &m_buffer[0]); + + /* if we succeeded, advance to the next sector and set the nice bits */ + if (count == 1) + { + /* advance the pointers, unless this is the last sector */ + /* Gauntlet: Dark Legacy checks to make sure we stop on the last sector */ + if (m_sector_count != 1) + next_sector(); + + /* signal an interrupt */ + if (--m_sectors_until_int == 0 || m_sector_count == 1) + { + m_sectors_until_int = ((m_command == IDE_COMMAND_WRITE_MULTIPLE) ? m_block_count : 1); + set_irq(ASSERT_LINE); + } + + /* signal an interrupt if there's more data needed */ + if (m_sector_count > 0) + m_sector_count--; + + if (m_sector_count > 0) + { + m_status |= IDE_STATUS_DRQ; + + if (m_command == IDE_COMMAND_WRITE_DMA) + set_dmarq(ASSERT_LINE); + } + } + + /* if we got an error, we need to report it */ + else + { + /* set the error flag and the error */ + m_status |= IDE_STATUS_ERR; + m_error = IDE_ERROR_BAD_SECTOR; + + /* signal an interrupt */ + set_irq(ASSERT_LINE); + } +} + + +/************************************* + * + * Handle IDE commands + * + *************************************/ + +void ata_mass_storage_device::process_command() +{ + m_sectors_until_int = 0; + m_buffer_size = IDE_DISK_SECTOR_SIZE; + + switch (m_command) + { + case IDE_COMMAND_READ_SECTORS: + case IDE_COMMAND_READ_SECTORS_NORETRY: + LOGPRINT(("IDE Read multiple: C=%d H=%d S=%d LBA=%d count=%d\n", + (m_cylinder_high << 8) | m_cylinder_low, m_device_head & IDE_DEVICE_HEAD_HS, m_sector_number, lba_address(), m_sector_count)); + + m_sectors_until_int = 1; + + /* start the read going */ + read_first_sector(); + break; + + case IDE_COMMAND_READ_MULTIPLE: + LOGPRINT(("IDE Read multiple block: C=%d H=%d S=%d LBA=%d count=%d\n", + (m_cylinder_high << 8) | m_cylinder_low, m_device_head & IDE_DEVICE_HEAD_HS, m_sector_number, lba_address(), m_sector_count)); + + m_sectors_until_int = 1; + + /* start the read going */ + read_first_sector(); + break; + + case IDE_COMMAND_VERIFY_SECTORS: + case IDE_COMMAND_VERIFY_SECTORS_NORETRY: + LOGPRINT(("IDE Read verify multiple with/without retries: C=%d H=%d S=%d LBA=%d count=%d\n", + (m_cylinder_high << 8) | m_cylinder_low, m_device_head & IDE_DEVICE_HEAD_HS, m_sector_number, lba_address(), m_sector_count)); + + /* reset the buffer */ + m_sectors_until_int = m_sector_count; + + /* start the read going */ + read_first_sector(); + break; + + case IDE_COMMAND_READ_DMA: + LOGPRINT(("IDE Read multiple DMA: C=%d H=%d S=%d LBA=%d count=%d\n", + (m_cylinder_high << 8) | m_cylinder_low, m_device_head & IDE_DEVICE_HEAD_HS, m_sector_number, lba_address(), m_sector_count)); + + /* reset the buffer */ + m_sectors_until_int = m_sector_count; + + /* start the read going */ + read_first_sector(); + break; + + case IDE_COMMAND_WRITE_SECTORS: + case IDE_COMMAND_WRITE_SECTORS_NORETRY: + LOGPRINT(("IDE Write multiple: C=%d H=%d S=%d LBA=%d count=%d\n", + (m_cylinder_high << 8) | m_cylinder_low, m_device_head & IDE_DEVICE_HEAD_HS, m_sector_number, lba_address(), m_sector_count)); + + /* reset the buffer */ + m_sectors_until_int = 1; + + /* mark the buffer ready */ + m_status |= IDE_STATUS_DRQ; + break; + + case IDE_COMMAND_WRITE_MULTIPLE: + LOGPRINT(("IDE Write multiple block: C=%d H=%d S=%d LBA=%d count=%d\n", + (m_cylinder_high << 8) | m_cylinder_low, m_device_head & IDE_DEVICE_HEAD_HS, m_sector_number, lba_address(), m_sector_count)); + + /* reset the buffer */ + m_sectors_until_int = 1; + + /* mark the buffer ready */ + m_status |= IDE_STATUS_DRQ; + break; + + case IDE_COMMAND_WRITE_DMA: + LOGPRINT(("IDE Write multiple DMA: C=%d H=%d S=%d LBA=%d count=%d\n", + (m_cylinder_high << 8) | m_cylinder_low, m_device_head & IDE_DEVICE_HEAD_HS, m_sector_number, lba_address(), m_sector_count)); + + /* reset the buffer */ + m_sectors_until_int = m_sector_count; + + /* mark the buffer ready */ + m_status |= IDE_STATUS_DRQ; + + /* start the read going */ + set_dmarq(ASSERT_LINE); + break; + + case IDE_COMMAND_SECURITY_UNLOCK: + LOGPRINT(("IDE Security Unlock\n")); + + /* mark the buffer ready */ + m_status |= IDE_STATUS_DRQ; + + set_irq(ASSERT_LINE); + break; + + case IDE_COMMAND_IDENTIFY_DEVICE: + LOGPRINT(("IDE Identify device\n")); + + start_busy(MINIMUM_COMMAND_TIME, PARAM_COMMAND); + break; + + case IDE_COMMAND_RECALIBRATE: + start_busy(MINIMUM_COMMAND_TIME, PARAM_COMMAND); + break; + + case IDE_COMMAND_IDLE: + /* signal an interrupt */ + set_irq(ASSERT_LINE); + break; + + case IDE_COMMAND_SET_CONFIG: + LOGPRINT(("IDE Set configuration (%d heads, %d sectors)\n", (m_device_head & IDE_DEVICE_HEAD_HS) + 1, m_sector_count)); + + start_busy(MINIMUM_COMMAND_TIME, PARAM_COMMAND); + break; + + case IDE_COMMAND_SET_MAX: + LOGPRINT(("IDE Set max (%02X %02X %02X %02X %02X)\n", m_feature, m_sector_count & 0xff, m_sector_number, m_cylinder_low, m_cylinder_high)); + + /* signal an interrupt */ + set_irq(ASSERT_LINE); + break; + + case IDE_COMMAND_SET_BLOCK_COUNT: + LOGPRINT(("IDE Set block count (%02X)\n", m_sector_count)); + + m_block_count = m_sector_count; + + /* signal an interrupt */ + set_irq(ASSERT_LINE); + break; + + case IDE_COMMAND_SEEK: + /* signal an interrupt */ + set_irq(ASSERT_LINE); + break; + + case IDE_COMMAND_READ_NATIVE_MAX_ADDRESS: + start_busy(MINIMUM_COMMAND_TIME, PARAM_COMMAND); + break; + + default: + ata_hle_device::process_command(); + break; + } +} + +//************************************************************************** +// IDE HARD DISK DEVICE +//************************************************************************** + +// device type definition +const device_type IDE_HARDDISK = &device_creator; + +//------------------------------------------------- +// ide_hdd_device - constructor +//------------------------------------------------- + +ide_hdd_device::ide_hdd_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : ata_mass_storage_device(mconfig, IDE_HARDDISK, "IDE Hard Disk", tag, owner, clock, "hdd", __FILE__), + m_image(*this, "image") +{ +} + +ide_hdd_device::ide_hdd_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : ata_mass_storage_device(mconfig, type, name, tag, owner, clock, shortname, source), + m_image(*this, "image") +{ +} + +void ide_hdd_device::device_start() +{ + ata_mass_storage_device::device_start(); + + /* create a timer for timing status */ + m_last_status_timer = timer_alloc(TID_NULL); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void ide_hdd_device::device_reset() +{ + m_handle = m_image->get_chd_file(); + m_disk = m_image->get_hard_disk_file(); + + if (m_disk != NULL && !m_can_identify_device) + { + const hard_disk_info *hdinfo = hard_disk_get_info(m_disk); + if (hdinfo->sectorbytes == IDE_DISK_SECTOR_SIZE) + { + m_num_cylinders = hdinfo->cylinders; + m_num_sectors = hdinfo->sectors; + m_num_heads = hdinfo->heads; + if (PRINTF_IDE_COMMANDS) osd_printf_debug("CHS: %d %d %d\n", m_num_cylinders, m_num_heads, m_num_sectors); + osd_printf_debug("CHS: %d %d %d\n", m_num_cylinders, m_num_heads, m_num_sectors); + } + + // build the features page + UINT32 metalength; + if (m_handle->read_metadata (HARD_DISK_IDENT_METADATA_TAG, 0, &m_buffer[0], 512, metalength) == CHDERR_NONE) + { + for( int w = 0; w < 256; w++ ) + { + m_identify_buffer[w] = (m_buffer[(w * 2) + 1] << 8) | m_buffer[w * 2]; + } + } + else + { + ide_build_identify_device(); + } + + m_can_identify_device = 1; + } + + ata_mass_storage_device::device_reset(); +} + +UINT8 ide_hdd_device::calculate_status() +{ + UINT8 result = ata_hle_device::calculate_status(); + + if (m_last_status_timer->elapsed() > TIME_PER_ROTATION) + { + result |= IDE_STATUS_IDX; + m_last_status_timer->adjust(attotime::never); + } + + return result; +} + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- +static MACHINE_CONFIG_FRAGMENT( hdd_image ) + MCFG_HARDDISK_ADD( "image" ) +MACHINE_CONFIG_END + +machine_config_constructor ide_hdd_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( hdd_image ); +} diff --git a/src/devices/machine/idehd.h b/src/devices/machine/idehd.h new file mode 100644 index 00000000000..beacb0a25c4 --- /dev/null +++ b/src/devices/machine/idehd.h @@ -0,0 +1,122 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/*************************************************************************** + + idehd.h + + IDE Harddisk + +***************************************************************************/ + +#pragma once + +#ifndef __IDEHD_H__ +#define __IDEHD_H__ + +#include "atahle.h" +#include "harddisk.h" +#include "imagedev/harddriv.h" + +class ata_mass_storage_device : public ata_hle_device +{ +public: + ata_mass_storage_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock,const char *shortname, const char *source); + + UINT16 *identify_device_buffer() { return m_identify_buffer; } + + void set_master_password(const UINT8 *password) + { + m_master_password = password; + m_master_password_enable = (password != NULL); + } + + void set_user_password(const UINT8 *password) + { + m_user_password = password; + m_user_password_enable = (password != NULL); + } + +protected: + virtual void device_start(); + + virtual int read_sector(UINT32 lba, void *buffer) = 0; + virtual int write_sector(UINT32 lba, const void *buffer) = 0; + virtual attotime seek_time(); + + void ide_build_identify_device(); + + static const int IDE_DISK_SECTOR_SIZE = 512; + virtual int sector_length() { return IDE_DISK_SECTOR_SIZE; } + virtual void process_buffer(); + virtual void fill_buffer(); + virtual bool is_ready() { return true; } + virtual void process_command(); + virtual void finished_command(); + virtual void perform_diagnostic(); + virtual void signature(); + + int m_can_identify_device; + UINT16 m_num_cylinders; + UINT8 m_num_sectors; + UINT8 m_num_heads; + + virtual UINT32 lba_address(); + +private: + void set_geometry(UINT8 sectors, UINT8 heads) { m_num_sectors = sectors; m_num_heads = heads; } + void finished_read(); + void finished_write(); + void next_sector(); + void security_error(); + void read_first_sector(); + void soft_reset(); + + UINT32 m_cur_lba; + UINT16 m_block_count; + UINT16 m_sectors_until_int; + + UINT8 m_master_password_enable; + UINT8 m_user_password_enable; + const UINT8 * m_master_password; + const UINT8 * m_user_password; +}; + +// ======================> ide_hdd_device + +class ide_hdd_device : public ata_mass_storage_device +{ +public: + // construction/destruction + ide_hdd_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + ide_hdd_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + + virtual int read_sector(UINT32 lba, void *buffer) { if (m_disk == NULL) return 0; return hard_disk_read(m_disk, lba, buffer); } + virtual int write_sector(UINT32 lba, const void *buffer) { if (m_disk == NULL) return 0; return hard_disk_write(m_disk, lba, buffer); } + virtual UINT8 calculate_status(); + + chd_file *m_handle; + hard_disk_file *m_disk; + + enum + { + TID_NULL = TID_BUSY + 1 + }; + +private: + required_device m_image; + + emu_timer * m_last_status_timer; +}; + +// device type definition +extern const device_type IDE_HARDDISK; + +#endif diff --git a/src/devices/machine/im6402.c b/src/devices/machine/im6402.c new file mode 100644 index 00000000000..f713a048517 --- /dev/null +++ b/src/devices/machine/im6402.c @@ -0,0 +1,412 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/*************************************************************************** + + Intersil IM6402 Universal Asynchronous Receiver/Transmitter emulation + +***************************************************************************/ + +#include "im6402.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type IM6402 = &device_creator; + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define LOG 0 + + + +//************************************************************************** +// INLINE HELPERS +//************************************************************************** + +//------------------------------------------------- +// set_dr - +//------------------------------------------------- + +inline void im6402_device::set_dr(int state) +{ + m_dr = state; + + m_write_dr(state); +} + + +//------------------------------------------------- +// set_tbre - +//------------------------------------------------- + +inline void im6402_device::set_tbre(int state) +{ + m_tbre = state; + + m_write_tbre(state); +} + + +//------------------------------------------------- +// set_tre - +//------------------------------------------------- + +inline void im6402_device::set_tre(int state) +{ + m_tre = state; + + m_write_tre(state); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// im6402_device - constructor +//------------------------------------------------- + +im6402_device::im6402_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, IM6402, "Intersil IM6402", tag, owner, clock, "im6402", __FILE__), + device_serial_interface(mconfig, *this), + m_write_tro(*this), + m_write_dr(*this), + m_write_tbre(*this), + m_write_tre(*this), + m_rrc_count(0), + m_trc_count(0) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void im6402_device::device_start() +{ + // resolve callbacks + m_write_tro.resolve_safe(); + m_write_dr.resolve_safe(); + m_write_tbre.resolve_safe(); + m_write_tre.resolve_safe(); + + // create the timers + if (m_rrc > 0) + { + set_rcv_rate(m_rrc/16); + } + + if (m_trc > 0) + { + set_tra_rate(m_trc/16); + } + + // state saving + save_item(NAME(m_dr)); + save_item(NAME(m_tbre)); + save_item(NAME(m_tre)); + save_item(NAME(m_pe)); + save_item(NAME(m_fe)); + save_item(NAME(m_oe)); + save_item(NAME(m_cls1)); + save_item(NAME(m_cls2)); + save_item(NAME(m_sbs)); + save_item(NAME(m_sfd)); + save_item(NAME(m_epe)); + save_item(NAME(m_pi)); + save_item(NAME(m_rbr)); + save_item(NAME(m_rrc_count)); + save_item(NAME(m_tbr)); + save_item(NAME(m_trc_count)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void im6402_device::device_reset() +{ + receive_register_reset(); + transmit_register_reset(); + + m_write_tro(1); + + m_rrc_count = 0; + m_trc_count = 0; + + m_rbr = 0; + m_pe = 0; + m_fe = 0; + m_oe = 0; + + set_dr(CLEAR_LINE); + set_tbre(ASSERT_LINE); + set_tre(ASSERT_LINE); +} + + +//------------------------------------------------- +// device_timer - handler timer events +//------------------------------------------------- + +void im6402_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + device_serial_interface::device_timer(timer, id, param, ptr); +} + + +//------------------------------------------------- +// tra_callback - +//------------------------------------------------- + +void im6402_device::tra_callback() +{ + m_write_tro(transmit_register_get_data_bit()); +} + + +//------------------------------------------------- +// tra_complete - +//------------------------------------------------- + +void im6402_device::tra_complete() +{ + if (!m_tbre) + { + if (LOG) logerror("IM6402 '%s' Transmit Data %02x\n", tag(), m_tbr); + + transmit_register_setup(m_tbr); + + set_tbre(ASSERT_LINE); + set_tre(CLEAR_LINE); + } +} + + +//------------------------------------------------- +// rcv_callback - +//------------------------------------------------- + +void im6402_device::rcv_callback() +{ +} + + +//------------------------------------------------- +// rcv_complete - +//------------------------------------------------- + +void im6402_device::rcv_complete() +{ + receive_register_extract(); + m_rbr = get_received_char(); + + if (LOG) logerror("IM6402 '%s' Receive Data %02x\n", tag(), m_rbr); + + if (m_dr) + { + m_oe = 1; + } + + set_dr(ASSERT_LINE); +} + + +//------------------------------------------------- +// write - transmitter buffer register write +//------------------------------------------------- + +WRITE8_MEMBER( im6402_device::write ) +{ + if (LOG) logerror("IM6402 '%s' Transmit Buffer Register %02x\n", tag(), data); + + m_tbr = data; + + if (is_transmit_register_empty()) + { + if (LOG) logerror("IM6402 '%s' Transmit Data %02x\n", tag(), m_tbr); + + transmit_register_setup(m_tbr); + + set_tbre(ASSERT_LINE); + set_tre(CLEAR_LINE); + } + else + { + set_tbre(CLEAR_LINE); + } +} + + +//------------------------------------------------- +// rrc_w - receiver register clock +//------------------------------------------------- + +WRITE_LINE_MEMBER( im6402_device::rrc_w ) +{ + if (state) + { + rx_clock_w(m_rrc_count < 8); + m_rrc_count = (m_rrc_count + 1) & 15; + } +} + + +//------------------------------------------------- +// trc_w - transmitter register clock +//------------------------------------------------- + +WRITE_LINE_MEMBER( im6402_device::trc_w ) +{ + if (state) + { + tx_clock_w(m_trc_count < 8); + m_trc_count = (m_trc_count + 1) & 15; + } +} + + +//------------------------------------------------- +// rrd_w - receiver register disable +//------------------------------------------------- + +WRITE_LINE_MEMBER( im6402_device::rrd_w ) +{ +} + + +//------------------------------------------------- +// sfd_w - status flags disable +//------------------------------------------------- + +WRITE_LINE_MEMBER( im6402_device::sfd_w ) +{ +} + + +//------------------------------------------------- +// drr_w - data received reset +//------------------------------------------------- + +WRITE_LINE_MEMBER( im6402_device::drr_w ) +{ + if (state) + { + set_dr(CLEAR_LINE); + } +} + + +//------------------------------------------------- +// mr_w - master reset +//------------------------------------------------- + +WRITE_LINE_MEMBER( im6402_device::mr_w ) +{ + if (state) + { + device_reset(); + } +} + + +//------------------------------------------------- +// crl_w - control register load +//------------------------------------------------- + +WRITE_LINE_MEMBER( im6402_device::crl_w ) +{ + if (state) + { + if (LOG) logerror("IM6402 '%s' Control Register Load\n", tag()); + + int data_bit_count = 5 + ((m_cls2 << 1) | m_cls1); + stop_bits_t stop_bits = (m_sbs ? ((data_bit_count == 5) ? STOP_BITS_1_5 : STOP_BITS_2) : STOP_BITS_1); + parity_t parity; + + if (m_pi) parity = PARITY_NONE; + else if (m_epe) parity = PARITY_EVEN; + else parity = PARITY_ODD; + + set_data_frame(1, data_bit_count, parity, stop_bits); + } +} + + +//------------------------------------------------- +// pi_w - parity inhibit +//------------------------------------------------- + +WRITE_LINE_MEMBER( im6402_device::pi_w ) +{ + if (LOG) logerror("IM6402 '%s' Parity Inhibit %u\n", tag(), state); + + m_pi = state; +} + + +//------------------------------------------------- +// sbs_w - stop bit select +//------------------------------------------------- + +WRITE_LINE_MEMBER( im6402_device::sbs_w ) +{ + if (LOG) logerror("IM6402 '%s' Stop Bit Select %u\n", tag(), state); + + m_sbs = state; +} + + +//------------------------------------------------- +// cls1_w - character length select 1 +//------------------------------------------------- + +WRITE_LINE_MEMBER( im6402_device::cls1_w ) +{ + if (LOG) logerror("IM6402 '%s' Character Length Select 1 %u\n", tag(), state); + + m_cls1 = state; +} + + +//------------------------------------------------- +// cls2_w - character length select 2 +//------------------------------------------------- + +WRITE_LINE_MEMBER( im6402_device::cls2_w ) +{ + if (LOG) logerror("IM6402 '%s' Character Length Select 2 %u\n", tag(), state); + + m_cls2 = state; +} + + +//------------------------------------------------- +// epe_w - even parity enable +//------------------------------------------------- + +WRITE_LINE_MEMBER( im6402_device::epe_w ) +{ + if (LOG) logerror("IM6402 '%s' Even Parity Enable %u\n", tag(), state); + + m_epe = state; +} + +WRITE_LINE_MEMBER(im6402_device::write_rri) +{ + // HACK derive clock from data line as wangpckb sends bytes instantly to make up for mcs51 serial implementation + receive_register_update_bit(state); + rx_clock_w(1); + rx_clock_w(0); +} diff --git a/src/devices/machine/im6402.h b/src/devices/machine/im6402.h new file mode 100644 index 00000000000..46ac592b7ac --- /dev/null +++ b/src/devices/machine/im6402.h @@ -0,0 +1,170 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/*************************************************************************** + + Intersil IM6402 Universal Asynchronous Receiver/Transmitter emulation + +**************************************************************************** + _____ _____ + Vcc 1 |* \_/ | 40 NOTE + NOTE 2 | | 39 EPE + GND 3 | | 38 CLS1 + RRD 4 | | 37 CLS2 + RBR8 5 | | 36 SBS + RBR7 6 | | 35 PI + RBR6 7 | | 34 CRL + RBR5 8 | | 33 TBR8 + RBR4 9 | | 32 TBR7 + RBR3 10 | IM6402 | 31 TBR6 + RBR2 11 | IM6403 | 30 TBR5 + RBR1 12 | | 29 TBR4 + PE 13 | | 28 TBR3 + FE 14 | | 27 TBR2 + OE 15 | | 26 TBR1 + SFD 16 | | 25 TRO + NOTE 17 | | 24 TRE + DRR 18 | | 23 TRBL + DR 19 | | 22 TBRE + RRI 20 |_____________| 21 MR + + + NOTE: PIN IM6402 IM6403 + --------------------------- + 2 N/C CONTROL + 17 RRC OSC IN + 40 TRC OSC OUT + +***************************************************************************/ + +#pragma once + +#ifndef __IM6402__ +#define __IM6402__ + +#include "emu.h" + + + +/*************************************************************************** + INTERFACE CONFIGURATION MACROS +***************************************************************************/ + +#define MCFG_IM6402_ADD(_tag, _rrc, _trc) \ + MCFG_DEVICE_ADD(_tag, IM6402, 0) \ + im6402_device::set_rrc(*device, _rrc); \ + im6402_device::set_trc(*device, _trc); + +#define MCFG_IM6402_TRO_CALLBACK(_write) \ + devcb = &im6402_device::set_tro_wr_callback(*device, DEVCB_##_write); + +#define MCFG_IM6402_DR_CALLBACK(_write) \ + devcb = &im6402_device::set_dr_wr_callback(*device, DEVCB_##_write); + +#define MCFG_IM6402_TBRE_CALLBACK(_write) \ + devcb = &im6402_device::set_tbre_wr_callback(*device, DEVCB_##_write); + +#define MCFG_IM6402_TRE_CALLBACK(_write) \ + devcb = &im6402_device::set_tre_wr_callback(*device, DEVCB_##_write); + + + +/*************************************************************************** + TYPE DEFINITIONS +***************************************************************************/ + +// ======================> im6402_device + +class im6402_device : public device_t, + public device_serial_interface +{ +public: + // construction/destruction + im6402_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + static void set_rrc(device_t &device, int rrc) { downcast(device).m_rrc = rrc; } + static void set_trc(device_t &device, int trc) { downcast(device).m_trc = trc; } + template static devcb_base &set_tro_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_tro.set_callback(object); } + template static devcb_base &set_dr_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_dr.set_callback(object); } + template static devcb_base &set_tbre_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_tbre.set_callback(object); } + template static devcb_base &set_tre_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_tre.set_callback(object); } + + DECLARE_READ8_MEMBER( read ) { return m_rbr; } + DECLARE_WRITE8_MEMBER( write ); + + DECLARE_READ_LINE_MEMBER( dr_r ) { return m_dr; } + DECLARE_READ_LINE_MEMBER( tbre_r ) { return m_tbre; } + DECLARE_READ_LINE_MEMBER( tre_r ) { return m_tre; } + DECLARE_READ_LINE_MEMBER( pe_r ) { return m_pe; } + DECLARE_READ_LINE_MEMBER( fe_r ) { return m_fe; } + DECLARE_READ_LINE_MEMBER( oe_r ) { return m_oe; } + + DECLARE_WRITE_LINE_MEMBER( write_rri ); // receiver register input + DECLARE_WRITE_LINE_MEMBER( rrc_w ); + DECLARE_WRITE_LINE_MEMBER( trc_w ); + DECLARE_WRITE_LINE_MEMBER( rrd_w ); + DECLARE_WRITE_LINE_MEMBER( sfd_w ); + DECLARE_WRITE_LINE_MEMBER( drr_w ); + DECLARE_WRITE_LINE_MEMBER( mr_w ); + DECLARE_WRITE_LINE_MEMBER( crl_w ); + DECLARE_WRITE_LINE_MEMBER( pi_w ); + DECLARE_WRITE_LINE_MEMBER( sbs_w ); + DECLARE_WRITE_LINE_MEMBER( cls1_w ); + DECLARE_WRITE_LINE_MEMBER( cls2_w ); + DECLARE_WRITE_LINE_MEMBER( epe_w ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + // device_serial_interface overrides + virtual void tra_callback(); + virtual void tra_complete(); + virtual void rcv_callback(); + virtual void rcv_complete(); + +private: + inline void set_dr(int state); + inline void set_tbre(int state); + inline void set_tre(int state); + + devcb_write_line m_write_tro; + devcb_write_line m_write_dr; + devcb_write_line m_write_tbre; + devcb_write_line m_write_tre; + + // status + int m_dr; + int m_tbre; + int m_tre; + int m_pe; + int m_fe; + int m_oe; + + // control + int m_cls1; + int m_cls2; + int m_sbs; + int m_sfd; + int m_epe; + int m_pi; + + // receiver + UINT8 m_rbr; + int m_rrc; + int m_rrc_count; + + // transmitter + UINT8 m_tbr; + int m_trc; + int m_trc_count; +}; + + +// device type definition +extern const device_type IM6402; + + + +#endif diff --git a/src/devices/machine/ins8154.c b/src/devices/machine/ins8154.c new file mode 100644 index 00000000000..1c36af845be --- /dev/null +++ b/src/devices/machine/ins8154.c @@ -0,0 +1,247 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best +/*************************************************************************** + + National Semiconductor INS8154 + + N-Channel 128-by-8 Bit RAM Input/Output (RAM I/O) + + TODO: Strobed modes + +***************************************************************************/ + +#include "emu.h" +#include "ins8154.h" + + +/*************************************************************************** + CONSTANTS +***************************************************************************/ + +#define VERBOSE 1 + +/* Mode Definition Register */ +enum +{ + MDR_BASIC = 0x00, + MDR_STROBED_INPUT = 0x20, + MDR_STROBED_OUTPUT = 0x60, + MDR_STROBED_OUTPUT_3STATE = 0xe0 +}; + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +// device type definition +const device_type INS8154 = &device_creator; + +//------------------------------------------------- +// ins8154_device - constructor +//------------------------------------------------- + +ins8154_device::ins8154_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, INS8154, "INS8154 RAM I/O", tag, owner, clock, "ins8154", __FILE__), + m_in_a_cb(*this), + m_out_a_cb(*this), + m_in_b_cb(*this), + m_out_b_cb(*this), + m_out_irq_cb(*this) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void ins8154_device::device_start() +{ + /* resolve callbacks */ + m_in_a_cb.resolve(); + m_out_a_cb.resolve_safe(); + m_in_b_cb.resolve(); + m_out_b_cb.resolve_safe(); + m_out_irq_cb.resolve_safe(); + + /* register for state saving */ + save_item(NAME(m_in_a)); + save_item(NAME(m_in_b)); + save_item(NAME(m_out_a)); + save_item(NAME(m_out_b)); + save_item(NAME(m_mdr)); + save_item(NAME(m_odra)); + save_item(NAME(m_odrb)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void ins8154_device::device_reset() +{ + m_in_a = 0; + m_in_b = 0; + m_out_a = 0; + m_out_b = 0; + m_mdr = 0; + m_odra = 0; + m_odrb = 0; +} + + +READ8_MEMBER(ins8154_device::ins8154_r) +{ + UINT8 val = 0xff; + + if (offset > 0x24) + { + if (VERBOSE) + { + logerror("%s: INS8154 '%s' Read from invalid offset %02x!\n", machine().describe_context(), tag(), offset); + } + return 0xff; + } + + switch (offset) + { + case 0x20: + if(!m_in_a_cb.isnull()) + { + val = m_in_a_cb(0); + } + m_in_a = val; + break; + + case 0x21: + if(!m_in_b_cb.isnull()) + { + val = m_in_b_cb(0); + } + m_in_b = val; + break; + + default: + if (offset < 0x08) + { + if(!m_in_a_cb.isnull()) + { + val = (m_in_a_cb(0) << (8 - offset)) & 0x80; + } + m_in_a = val; + } + else + { + if(!m_in_b_cb.isnull()) + { + val = (m_in_b_cb(0) << (8 - (offset >> 4))) & 0x80; + } + m_in_b = val; + } + break; + } + + return val; +} + +WRITE8_MEMBER(ins8154_device::ins8154_porta_w) +{ + m_out_a = data; + + /* Test if any pins are set as outputs */ + if (m_odra) + { + m_out_a_cb((offs_t)0, (data & m_odra) | (m_odra ^ 0xff)); + } +} + +WRITE8_MEMBER(ins8154_device::ins8154_portb_w) +{ + m_out_b = data; + + /* Test if any pins are set as outputs */ + if (m_odrb) + { + m_out_b_cb((offs_t)0, (data & m_odrb) | (m_odrb ^ 0xff)); + } +} + +WRITE8_MEMBER(ins8154_device::ins8154_w) +{ + if (offset > 0x24) + { + if (VERBOSE) + { + logerror("%s: INS8154 '%s' Write %02x to invalid offset %02x!\n", machine().describe_context(), tag(), data, offset); + } + return; + } + + switch (offset) + { + case 0x20: + ins8154_porta_w(space, 0, data); + break; + + case 0x21: + ins8154_portb_w(space, 0, data); + break; + + case 0x22: + if (VERBOSE) + { + logerror("%s: INS8154 '%s' ODRA set to %02x\n", machine().describe_context(), tag(), data); + } + + m_odra = data; + break; + + case 0x23: + if (VERBOSE) + { + logerror("%s: INS8154 '%s' ODRB set to %02x\n", machine().describe_context(), tag(), data); + } + + m_odrb = data; + break; + + case 0x24: + if (VERBOSE) + { + logerror("%s: INS8154 '%s' MDR set to %02x\n", machine().describe_context(), tag(), data); + } + + m_mdr = data; + break; + + default: + if (offset & 0x10) + { + /* Set bit */ + if (offset < 0x08) + { + ins8154_porta_w(space, 0, m_out_a |= offset & 0x07); + } + else + { + ins8154_portb_w(space, 0, m_out_b |= (offset >> 4) & 0x07); + } + } + else + { + /* Clear bit */ + if (offset < 0x08) + { + ins8154_porta_w(space, 0, m_out_a & ~(offset & 0x07)); + } + else + { + ins8154_portb_w(space, 0, m_out_b & ~((offset >> 4) & 0x07)); + } + } + + break; + } +} diff --git a/src/devices/machine/ins8154.h b/src/devices/machine/ins8154.h new file mode 100644 index 00000000000..300b9763a9b --- /dev/null +++ b/src/devices/machine/ins8154.h @@ -0,0 +1,115 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best +/*************************************************************************** + + National Semiconductor INS8154 + + N-Channel 128-by-8 Bit RAM Input/Output (RAM I/O) + + _____ _____ + PB6 1 |* \_/ | 40 VCC + PB5 2 | | 39 PB7 + PB4 3 | | 38 NWDS + PB3 4 | | 37 NRDS + PB2 5 | | 36 NRST + PB1 6 | | 35 _CS0 + PB0 7 | | 34 CS1 + DB7 8 | | 33 M/_IO + DB6 9 | | 32 AD6 + DB5 10 | INS8154 | 31 AD5 + DB4 11 | | 30 AD4 + DB3 12 | | 29 AD3 + DB2 13 | | 28 AD2 + DB1 14 | | 27 AD1 + DB0 15 | | 26 AD0 + PA7 16 | | 25 INTR + PA6 17 | | 24 PA0 + PA5 18 | | 23 PA1 + PA4 19 | | 22 PA2 + GND 20 |_____________| 21 PA3 + +***************************************************************************/ + +#pragma once + +#ifndef __INS8154_H__ +#define __INS8154_H__ + +#include "emu.h" + + + +/*************************************************************************** + DEVICE CONFIGURATION MACROS +***************************************************************************/ + +#define MCFG_INS8154_IN_A_CB(_devcb) \ + devcb = &ins8154_device::set_in_a_callback(*device, DEVCB_##_devcb); + +#define MCFG_INS8154_OUT_A_CB(_devcb) \ + devcb = &ins8154_device::set_out_a_callback(*device, DEVCB_##_devcb); + +#define MCFG_INS8154_IN_B_CB(_devcb) \ + devcb = &ins8154_device::set_in_b_callback(*device, DEVCB_##_devcb); + +#define MCFG_INS8154_OUT_B_CB(_devcb) \ + devcb = &ins8154_device::set_out_b_callback(*device, DEVCB_##_devcb); + +#define MCFG_INS8154_OUT_IRQ_CB(_devcb) \ + devcb = &ins8154_device::set_out_irq_callback(*device, DEVCB_##_devcb); //currently unused + +/*************************************************************************** + TYPE DEFINITIONS +***************************************************************************/ + +// ======================> ins8154_device + +class ins8154_device : public device_t +{ +public: + // construction/destruction + ins8154_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + template static devcb_base &set_in_a_callback(device_t &device, _Object object) { return downcast(device).m_in_a_cb.set_callback(object); } + template static devcb_base &set_out_a_callback(device_t &device, _Object object) { return downcast(device).m_out_a_cb.set_callback(object); } + template static devcb_base &set_in_b_callback(device_t &device, _Object object) { return downcast(device).m_in_b_cb.set_callback(object); } + template static devcb_base &set_out_b_callback(device_t &device, _Object object) { return downcast(device).m_out_b_cb.set_callback(object); } + template static devcb_base &set_out_irq_callback(device_t &device, _Object object) { return downcast(device).m_out_irq_cb.set_callback(object); } + + DECLARE_READ8_MEMBER( ins8154_r ); + DECLARE_WRITE8_MEMBER( ins8154_w ); + + DECLARE_WRITE8_MEMBER( ins8154_porta_w ); + DECLARE_WRITE8_MEMBER( ins8154_portb_w ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_post_load() { } + virtual void device_clock_changed() { } + +private: + + /* i/o lines */ + devcb_read8 m_in_a_cb; + devcb_write8 m_out_a_cb; + devcb_read8 m_in_b_cb; + devcb_write8 m_out_b_cb; + devcb_write_line m_out_irq_cb; + + /* registers */ + UINT8 m_in_a; /* Input Latch Port A */ + UINT8 m_in_b; /* Input Latch Port B */ + UINT8 m_out_a; /* Output Latch Port A */ + UINT8 m_out_b; /* Output Latch Port B */ + UINT8 m_mdr; /* Mode Definition Register */ + UINT8 m_odra; /* Output Definition Register Port A */ + UINT8 m_odrb; /* Output Definition Register Port B */ +}; + + +// device type definition +extern const device_type INS8154; + +#endif /* __INS8154_H__ */ diff --git a/src/devices/machine/ins8250.c b/src/devices/machine/ins8250.c new file mode 100644 index 00000000000..bbd0fee1584 --- /dev/null +++ b/src/devices/machine/ins8250.c @@ -0,0 +1,705 @@ +// license:BSD-3-Clause +// copyright-holders:smf, Carl +/********************************************************************** + + National Semiconductor 8250 UART interface and emulation + + More information on the different models can be found in + section 1.6 at this location: + http://www.freebsd.org/doc/en_US.ISO8859-1/articles/serial-uart/ + +Model overview (from page above): + +INS8250 +This part was used in the original IBM PC and IBM PC/XT. The original name +for this part was the INS8250 ACE (Asynchronous Communications Element) and +it is made from NMOS technology. + +The 8250 uses eight I/O ports and has a one-byte send and a one-byte receive +buffer. This original UART has several race conditions and other flaws. The +original IBM BIOS includes code to work around these flaws, but this made +the BIOS dependent on the flaws being present, so subsequent parts like the +8250A, 16450 or 16550 could not be used in the original IBM PC or IBM PC/XT. + +The original 8250 pulses the interrupt line if a higher priority interrupt is +cleared but a lower priority one is still active. It also clears the tsre bit +for a moment before loading the tsr from the thr. These may be the bugs the +PC and XT depend on as the 8250A and up fix them. + +INS8250-B +This is the slower speed of the INS8250 made from NMOS technology. It contains +the same problems as the original INS8250. + +INS8250A +An improved version of the INS8250 using XMOS technology with various functional +flaws corrected. The INS8250A was used initially in PC clone computers by vendors +who used "clean" BIOS designs. Because of the corrections in the chip, this part +could not be used with a BIOS compatible with the INS8250 or INS8250B. + +INS82C50A +This is a CMOS version (low power consumption) of the INS8250A and has similar +functional characteristics. + +NS16450 +Same as NS8250A with improvements so it can be used with faster CPU bus designs. +IBM used this part in the IBM AT and updated the IBM BIOS to no longer rely on +the bugs in the INS8250. + +NS16C450 +This is a CMOS version (low power consumption) of the NS16450. + +NS16550 +Same as NS16450 with a 16-byte send and receive buffer but the buffer design +was flawed and could not be reliably be used. + +The 16550 sometimes will send more then one character over the bus from the fifo +when the rbr is read making the rx fifo useless. It's unlikely anything depends +on this behavior. + +NS16550A +Same as NS16550 with the buffer flaws corrected. The 16550A and its successors +have become the most popular UART design in the PC industry, mainly due to +its ability to reliably handle higher data rates on operating systems with +sluggish interrupt response times. + +NS16C552 +This component consists of two NS16C550A CMOS UARTs in a single package. + +PC16550D +Same as NS16550A with subtle flaws corrected. This is revision D of the +16550 family and is the latest design available from National Semiconductor. + + +Known issues: +- MESS does currently not handle all these model specific features. + + +History: + KT - 14-Jun-2000 - Improved Interrupt setting/clearing + KT - moved into separate file so it can be used in Super I/O emulation and + any other system which uses a PC type COM port + KT - 24-Jun-2000 - removed pc specific input port tests. More compatible + with PCW16 and PCW16 doesn't requre the PC input port definitions + which are not required by the PCW16 hardware + +**********************************************************************/ + +#include "machine/ins8250.h" + +const device_type INS8250 = &device_creator; +const device_type NS16450 = &device_creator; +const device_type NS16550 = &device_creator; +const device_type PC16552D = &device_creator; + +ins8250_uart_device::ins8250_uart_device(const machine_config &mconfig, device_type type, const char* name, const char *tag, device_t *owner, UINT32 clock, const char *shortname) + : device_t(mconfig, type, name, tag, owner, clock, shortname, __FILE__), + device_serial_interface(mconfig, *this), + m_out_tx_cb(*this), + m_out_dtr_cb(*this), + m_out_rts_cb(*this), + m_out_int_cb(*this), + m_out_out1_cb(*this), + m_out_out2_cb(*this), + m_rxd(1), + m_dcd(1), + m_dsr(1), + m_ri(1), + m_cts(1) +{ + m_regs.ier = 0; +} + +ins8250_device::ins8250_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : ins8250_uart_device(mconfig, INS8250, "National Semiconductor INS8250", tag, owner, clock, "ins8250") +{ + m_device_type = TYPE_INS8250; +} + +ns16450_device::ns16450_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : ins8250_uart_device(mconfig, NS16450, "National Semiconductor NS16450", tag, owner, clock, "ns16450") +{ + m_device_type = TYPE_NS16450; +} + +ns16550_device::ns16550_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : ins8250_uart_device(mconfig, NS16550, "National Semiconductor NS16550", tag, owner, clock, "ns16550") +{ + m_device_type = TYPE_NS16550; +} + +pc16552_device::pc16552_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, PC16552D, "National Semiconductor PC16552D", tag, owner, clock, "pc16552d", __FILE__) +{ +} + +void pc16552_device::device_start() +{ + m_chan0 = subdevice("chan0"); + m_chan1 = subdevice("chan1"); +} + +/* int's pending */ +#define COM_INT_PENDING_RECEIVED_DATA_AVAILABLE 0x0001 +#define COM_INT_PENDING_TRANSMITTER_HOLDING_REGISTER_EMPTY 0x0002 +#define COM_INT_PENDING_RECEIVER_LINE_STATUS 0x0004 +#define COM_INT_PENDING_MODEM_STATUS_REGISTER 0x0008 +#define COM_INT_PENDING_CHAR_TIMEOUT 0x0011 + +/* ints will continue to be set for as long as there are ints pending */ +void ins8250_uart_device::update_interrupt() +{ + int state; + + /* if any bits are set and are enabled */ + if (((m_int_pending & m_regs.ier) & 0x0f) != 0) + { + /* trigger next highest priority int */ + + /* set int */ + state = 1; + m_regs.iir &= ~(0x08|0x04|0x02); + + /* highest to lowest */ + if (m_regs.ier & m_int_pending & COM_INT_PENDING_RECEIVER_LINE_STATUS) + m_regs.iir |=0x04|0x02; + else if (m_regs.ier & m_int_pending & COM_INT_PENDING_RECEIVED_DATA_AVAILABLE) + { + m_regs.iir |=0x04; + if ((m_int_pending & COM_INT_PENDING_CHAR_TIMEOUT) == 0x11) + m_regs.iir |= 0x08; + } + else if (m_regs.ier & m_int_pending & COM_INT_PENDING_TRANSMITTER_HOLDING_REGISTER_EMPTY) + m_regs.iir |=0x02; + + /* int pending */ + m_regs.iir &= ~0x01; + } + else + { + /* clear int */ + state = 0; + + /* no ints pending */ + m_regs.iir |= 0x01; + /* priority level */ + m_regs.iir &= ~(0x08|0x04|0x02); + } + + /* set or clear the int */ + m_out_int_cb(state); +} + +/* set pending bit and trigger int */ +void ins8250_uart_device::trigger_int(int flag) +{ + m_int_pending |= flag; + update_interrupt(); +} + +/* clear pending bit, if any ints are pending, then int will be triggered, otherwise it +will be cleared */ +void ins8250_uart_device::clear_int(int flag) +{ + m_int_pending &= ~flag; + update_interrupt(); +} + +WRITE8_MEMBER( ins8250_uart_device::ins8250_w ) +{ + int tmp; + + switch (offset) + { + case 0: + if (m_regs.lcr & 0x80) + { + m_regs.dl = (m_regs.dl & 0xff00) | data; + set_rate(clock(), m_regs.dl*16); + } + else + { + m_regs.thr = data; + m_regs.lsr &= ~0x20; + if((m_device_type >= TYPE_NS16550) && (m_regs.fcr & 1)) + push_tx(data); + clear_int(COM_INT_PENDING_TRANSMITTER_HOLDING_REGISTER_EMPTY); + if(m_regs.lsr & 0x40) + tra_complete(); + } + break; + case 1: + if (m_regs.lcr & 0x80) + { + m_regs.dl = (m_regs.dl & 0xff) | (data << 8); + set_rate(clock(), m_regs.dl*16); + } + else + { + m_regs.ier = data; + update_interrupt(); + } + break; + case 2: + set_fcr(data); + break; + case 3: + m_regs.lcr = data; + + { + int data_bit_count = (m_regs.lcr & 3) + 5; + parity_t parity; + stop_bits_t stop_bits; + + switch ((m_regs.lcr>>3) & 7) + { + case 1: + parity = PARITY_ODD; + break; + + case 3: + parity = PARITY_EVEN; + break; + + case 5: + parity = PARITY_MARK; + break; + + case 7: + parity = PARITY_SPACE; + break; + + default: + parity = PARITY_NONE; + break; + } + + if (!(m_regs.lcr & 4)) + stop_bits = STOP_BITS_1; + else if (data_bit_count == 5) + stop_bits = STOP_BITS_1_5; + else + stop_bits = STOP_BITS_2; + + set_data_frame(1, data_bit_count, parity, stop_bits); + } + break; + case 4: + if ( ( m_regs.mcr & 0x1f ) != ( data & 0x1f ) ) + { + m_regs.mcr = data & 0x1f; + + update_msr(); + + if (m_regs.mcr & 0x10) /* loopback test */ + { + m_out_tx_cb(1); + device_serial_interface::rx_w(m_txd); + m_out_dtr_cb(1); + m_out_rts_cb(1); + m_out_out1_cb(1); + m_out_out2_cb(1); + } + else + { + m_out_tx_cb(m_txd); + device_serial_interface::rx_w(m_rxd); + m_out_dtr_cb((m_regs.mcr & 1) ? 0 : 1); + m_out_rts_cb((m_regs.mcr & 2) ? 0 : 1); + m_out_out1_cb((m_regs.mcr & 4) ? 0 : 1); + m_out_out2_cb((m_regs.mcr & 8) ? 0 : 1); + } + } + break; + case 5: + /* + This register can be written, but if you write a 1 bit into any of + bits 5 - 0, you could cause an interrupt if the appropriate IER bit + is set. + */ + m_regs.lsr = (m_regs.lsr & 0x40) | (data & ~0x40); + + tmp = 0; + tmp |= ( m_regs.lsr & 0x01 ) ? COM_INT_PENDING_RECEIVED_DATA_AVAILABLE : 0; + tmp |= ( m_regs.lsr & 0x1e ) ? COM_INT_PENDING_RECEIVER_LINE_STATUS : 0; + tmp |= ( m_regs.lsr & 0x20 ) ? COM_INT_PENDING_TRANSMITTER_HOLDING_REGISTER_EMPTY : 0; + trigger_int(tmp); + + break; + case 6: + /* + This register can be written, but if you write a 1 bit into any of + bits 3 - 0, you could cause an interrupt if the appropriate IER bit + is set. + */ + m_regs.msr = data; + + if ( m_regs.msr & 0x0f ) + trigger_int(COM_INT_PENDING_MODEM_STATUS_REGISTER); + break; + case 7: + m_regs.scr = data; + break; + } +} + +READ8_MEMBER( ins8250_uart_device::ins8250_r ) +{ + int data = 0x0ff; + + switch (offset) + { + case 0: + if (m_regs.lcr & 0x80) + data = (m_regs.dl & 0xff); + else + { + if((m_device_type >= TYPE_NS16550) && (m_regs.fcr & 1)) + m_regs.rbr = pop_rx(); + else + { + clear_int(COM_INT_PENDING_RECEIVED_DATA_AVAILABLE); + if( m_regs.lsr & 0x01 ) + m_regs.lsr &= ~0x01; + } + data = m_regs.rbr; + } + break; + case 1: + if (m_regs.lcr & 0x80) + data = (m_regs.dl >> 8); + else + data = m_regs.ier & 0x0f; + break; + case 2: + data = m_regs.iir; + /* The documentation says that reading this register will + clear the int if this is the source of the int */ + if ( m_regs.ier & COM_INT_PENDING_TRANSMITTER_HOLDING_REGISTER_EMPTY ) + clear_int(COM_INT_PENDING_TRANSMITTER_HOLDING_REGISTER_EMPTY); + break; + case 3: + data = m_regs.lcr; + break; + case 4: + data = m_regs.mcr; + break; + case 5: + data = m_regs.lsr; + if( m_regs.lsr & 0x1f ) + m_regs.lsr &= 0xe1; /* clear FE, PE and OE and BREAK bits */ + + /* reading line status register clears int */ + clear_int(COM_INT_PENDING_RECEIVER_LINE_STATUS); + break; + case 6: + data = m_regs.msr; + m_regs.msr &= 0xf0; /* reset delta values */ + + /* reading msr clears int */ + clear_int(COM_INT_PENDING_MODEM_STATUS_REGISTER); + + break; + case 7: + data = m_regs.scr; + break; + } + return data; +} + +void ns16550_device::rcv_complete() +{ + if(!(m_regs.fcr & 1)) + return ins8250_uart_device::rcv_complete(); + + receive_register_extract(); + + if(m_rnum == 16) + { + m_regs.lsr |= 0x02; //overrun + trigger_int(COM_INT_PENDING_RECEIVER_LINE_STATUS); + return; + } + + m_regs.lsr |= 0x01; + m_rfifo[m_rhead] = get_received_char(); + ++m_rhead &= 0x0f; + m_rnum++; + if(m_rnum >= m_rintlvl) + trigger_int(COM_INT_PENDING_RECEIVED_DATA_AVAILABLE); + set_timer(); +} + +void ns16550_device::tra_complete() +{ + if(!(m_regs.fcr & 1)) + return ins8250_uart_device::tra_complete(); + + if(m_ttail != m_thead) + { + transmit_register_setup(m_tfifo[m_ttail]); + ++m_ttail &= 0x0f; + m_regs.lsr &= ~0x40; + if(m_ttail == m_thead) + { + m_regs.lsr |= 0x20; + trigger_int(COM_INT_PENDING_TRANSMITTER_HOLDING_REGISTER_EMPTY); + } + } + else + m_regs.lsr |= 0x40; +} + +void ins8250_uart_device::rcv_complete() +{ + if(m_regs.lsr & 0x01) + { + m_regs.lsr |= 0x02; //overrun + trigger_int(COM_INT_PENDING_RECEIVER_LINE_STATUS); + receive_register_reset(); + } + else + { + m_regs.lsr |= 0x01; + receive_register_extract(); + m_regs.rbr = get_received_char(); + trigger_int(COM_INT_PENDING_RECEIVED_DATA_AVAILABLE); + } +} + +void ins8250_uart_device::tra_complete() +{ + if(!(m_regs.lsr & 0x20)) + { + transmit_register_setup(m_regs.thr); + m_regs.lsr &= ~0x40; + m_regs.lsr |= 0x20; + trigger_int(COM_INT_PENDING_TRANSMITTER_HOLDING_REGISTER_EMPTY); + } + else + m_regs.lsr |= 0x40; +} + +void ins8250_uart_device::tra_callback() +{ + m_txd = transmit_register_get_data_bit(); + if (m_regs.mcr & 0x10) + { + device_serial_interface::rx_w(m_txd); + } + else + { + m_out_tx_cb(m_txd); + } +} + +void ins8250_uart_device::update_msr() +{ + UINT8 data; + int change; + + if (m_regs.mcr & 0x10) + { + data = (((m_regs.mcr & 0x0c) << 4) | ((m_regs.mcr & 0x01) << 5) | ((m_regs.mcr & 0x02) << 3)); + change = (m_regs.msr ^ data) >> 4; + if(!(m_regs.msr & 0x40) && (data & 0x40)) + change &= ~4; + } + else + { + data = (!m_dcd << 7) | (!m_ri << 6) | (!m_dsr << 5) | (!m_cts << 4); + change = (m_regs.msr ^ data) >> 4; + } + + m_regs.msr = data | change; + + if(change) + trigger_int(COM_INT_PENDING_MODEM_STATUS_REGISTER); +} + +WRITE_LINE_MEMBER(ins8250_uart_device::dcd_w) +{ + m_dcd = state; + update_msr(); +} + +WRITE_LINE_MEMBER(ins8250_uart_device::dsr_w) +{ + m_dsr = state; + update_msr(); +} + +WRITE_LINE_MEMBER(ins8250_uart_device::ri_w) +{ + m_ri = state; + update_msr(); +} + +WRITE_LINE_MEMBER(ins8250_uart_device::cts_w) +{ + m_cts = state; + update_msr(); +} + +WRITE_LINE_MEMBER(ins8250_uart_device::rx_w) +{ + m_rxd = state; + + if (!(m_regs.mcr & 0x10)) + device_serial_interface::rx_w(m_rxd); +} + +void ins8250_uart_device::device_start() +{ + m_out_tx_cb.resolve_safe(); + m_out_dtr_cb.resolve_safe(); + m_out_rts_cb.resolve_safe(); + m_out_int_cb.resolve_safe(); + m_out_out1_cb.resolve_safe(); + m_out_out2_cb.resolve_safe(); + set_tra_rate(0); + set_rcv_rate(0); + + device_serial_interface::register_save_state(machine().save(), this); + save_item(NAME(m_regs.thr)); + save_item(NAME(m_regs.rbr)); + save_item(NAME(m_regs.ier)); + save_item(NAME(m_regs.dl)); + save_item(NAME(m_regs.iir)); + save_item(NAME(m_regs.fcr)); + save_item(NAME(m_regs.lcr)); + save_item(NAME(m_regs.mcr)); + save_item(NAME(m_regs.lsr)); + save_item(NAME(m_regs.msr)); + save_item(NAME(m_regs.scr)); + save_item(NAME(m_int_pending)); + save_item(NAME(m_txd)); + save_item(NAME(m_rxd)); + save_item(NAME(m_dcd)); + save_item(NAME(m_dsr)); + save_item(NAME(m_ri)); + save_item(NAME(m_cts)); +} + +void ins8250_uart_device::device_reset() +{ + m_regs.ier = 0; + m_regs.iir = 1; + m_regs.lcr = 0; + m_regs.mcr = 0; + m_regs.lsr = (1<<5) | (1<<6); + update_msr(); + m_regs.msr &= 0xf0; + m_int_pending = 0; + update_interrupt(); + receive_register_reset(); + transmit_register_reset(); + m_txd = 1; + m_out_tx_cb(1); + m_out_rts_cb(1); + m_out_dtr_cb(1); + m_out_out1_cb(1); + m_out_out2_cb(1); +} + +void ins8250_uart_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + device_serial_interface::device_timer(timer, id, param, ptr); +} + +void ns16550_device::device_start() +{ + m_timeout = timer_alloc(); + ins8250_uart_device::device_start(); + save_item(NAME(m_rintlvl)); + save_item(NAME(m_rfifo)); + save_item(NAME(m_tfifo)); + save_item(NAME(m_rhead)); + save_item(NAME(m_rtail)); + save_item(NAME(m_rnum)); + save_item(NAME(m_thead)); + save_item(NAME(m_ttail)); +} + +void ns16550_device::device_reset() +{ + memset(&m_rfifo, '\0', sizeof(m_rfifo)); + memset(&m_tfifo, '\0', sizeof(m_tfifo)); + m_rhead = m_rtail = m_rnum = 0; + m_thead = m_ttail = 0; + m_timeout->adjust(attotime::never); + ins8250_uart_device::device_reset(); +} + +void ns16550_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + if(id) + device_serial_interface::device_timer(timer, id, param, ptr); + else + { + trigger_int(COM_INT_PENDING_CHAR_TIMEOUT); + m_timeout->adjust(attotime::never); + } +} + +void ns16550_device::push_tx(UINT8 data) +{ + m_tfifo[m_thead] = data; + ++m_thead &= 0x0f; +} + +UINT8 ns16550_device::pop_rx() +{ + UINT8 data = m_rfifo[m_rtail]; + clear_int(COM_INT_PENDING_CHAR_TIMEOUT & ~1); // don't clear bit 1 yet + + if(m_rnum) + { + ++m_rtail &= 0x0f; + m_rnum--; + } + else + data = 0; + + if(m_rnum < m_rintlvl) + clear_int(COM_INT_PENDING_RECEIVED_DATA_AVAILABLE); + + if(m_rnum) + set_timer(); + else + { + m_timeout->adjust(attotime::never); + m_regs.lsr &= ~1; + } + + return data; +} + +void ns16550_device::set_fcr(UINT8 data) +{ + const int bytes_per_int[] = {1, 4, 8, 14}; + if(!(data & 1)) + { + m_regs.fcr = 0; + m_regs.iir &= ~0xc8; + return; + } + if(!(m_regs.fcr & 1) && (data & 1)) + data |= 0x06; + if(data & 2) + { + memset(&m_rfifo, '\0', sizeof(m_rfifo)); + m_rhead = m_rtail = m_rnum = 0; + clear_int(COM_INT_PENDING_CHAR_TIMEOUT | COM_INT_PENDING_RECEIVED_DATA_AVAILABLE); + m_timeout->adjust(attotime::never); + } + if(data & 4) + { + memset(&m_tfifo, '\0', sizeof(m_tfifo)); + m_thead = m_ttail = 0; + m_regs.lsr |= 0x20; + trigger_int(COM_INT_PENDING_TRANSMITTER_HOLDING_REGISTER_EMPTY); + } + m_rintlvl = bytes_per_int[(data>>6)&3]; + m_regs.iir |= 0xc0; + m_regs.fcr = data & 0xc9; +} diff --git a/src/devices/machine/ins8250.h b/src/devices/machine/ins8250.h new file mode 100644 index 00000000000..9415c2b70ce --- /dev/null +++ b/src/devices/machine/ins8250.h @@ -0,0 +1,174 @@ +// license:BSD-3-Clause +// copyright-holders:smf, Carl +/********************************************************************** + + 8250 UART interface and emulation + +**********************************************************************/ + +#ifndef __INS8250_H_ +#define __INS8250_H_ + +#include "emu.h" + +/*************************************************************************** + CLASS DEFINITIONS +***************************************************************************/ + +class ins8250_uart_device : public device_t, + public device_serial_interface +{ +public: + ins8250_uart_device(const machine_config &mconfig, device_type type, const char* name, const char *tag, device_t *owner, UINT32 clock, const char *shortname); + + template static devcb_base &set_out_tx_callback(device_t &device, _Object object) { return downcast(device).m_out_tx_cb.set_callback(object); } + template static devcb_base &set_out_dtr_callback(device_t &device, _Object object) { return downcast(device).m_out_dtr_cb.set_callback(object); } + template static devcb_base &set_out_rts_callback(device_t &device, _Object object) { return downcast(device).m_out_rts_cb.set_callback(object); } + template static devcb_base &set_out_int_callback(device_t &device, _Object object) { return downcast(device).m_out_int_cb.set_callback(object); } + template static devcb_base &set_out_out1_callback(device_t &device, _Object object) { return downcast(device).m_out_out1_cb.set_callback(object); } + template static devcb_base &set_out_out2_callback(device_t &device, _Object object) { return downcast(device).m_out_out2_cb.set_callback(object); } + + DECLARE_WRITE8_MEMBER( ins8250_w ); + DECLARE_READ8_MEMBER( ins8250_r ); + DECLARE_WRITE_LINE_MEMBER( dcd_w ); + DECLARE_WRITE_LINE_MEMBER( dsr_w ); + DECLARE_WRITE_LINE_MEMBER( ri_w ); + DECLARE_WRITE_LINE_MEMBER( cts_w ); + DECLARE_WRITE_LINE_MEMBER( rx_w ); + +protected: + virtual void device_start(); + virtual void device_reset(); + virtual void rcv_complete(); + virtual void tra_complete(); + virtual void tra_callback(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + virtual void set_fcr(UINT8 data) {} + virtual void push_tx(UINT8 data) {} + virtual UINT8 pop_rx() { return 0; } + + void trigger_int(int flag); + void clear_int(int flag); + + enum { + TYPE_INS8250 = 0, + TYPE_INS8250A, + TYPE_NS16450, + TYPE_NS16550, + TYPE_NS16550A + }; + int m_device_type; + struct { + UINT8 thr; /* 0 -W transmitter holding register */ + UINT8 rbr; /* 0 R- receiver buffer register */ + UINT8 ier; /* 1 RW interrupt enable register */ + UINT16 dl; /* 0/1 RW divisor latch (if DLAB = 1) */ + UINT8 iir; /* 2 R- interrupt identification register */ + UINT8 fcr; + UINT8 lcr; /* 3 RW line control register (bit 7: DLAB) */ + UINT8 mcr; /* 4 RW modem control register */ + UINT8 lsr; /* 5 R- line status register */ + UINT8 msr; /* 6 R- modem status register */ + UINT8 scr; /* 7 RW scratch register */ + } m_regs; +private: + UINT8 m_int_pending; + + devcb_write_line m_out_tx_cb; + devcb_write_line m_out_dtr_cb; + devcb_write_line m_out_rts_cb; + devcb_write_line m_out_int_cb; + devcb_write_line m_out_out1_cb; + devcb_write_line m_out_out2_cb; + + void update_interrupt(); + void update_msr(); + + int m_txd; + int m_rxd; + int m_dcd; + int m_dsr; + int m_ri; + int m_cts; +}; + +class ins8250_device : public ins8250_uart_device +{ +public: + ins8250_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class ns16450_device : public ins8250_uart_device +{ +public: + ns16450_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class ns16550_device : public ins8250_uart_device +{ +public: + ns16550_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +protected: + virtual void device_start(); + virtual void device_reset(); + virtual void rcv_complete(); + virtual void tra_complete(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + virtual void set_fcr(UINT8 data); + virtual void push_tx(UINT8 data); + virtual UINT8 pop_rx(); +private: + void set_timer() { m_timeout->adjust(attotime::from_hz((clock()*4*8)/(m_regs.dl*16))); } + int m_rintlvl; + UINT8 m_rfifo[16]; + UINT8 m_tfifo[16]; + int m_rhead, m_rtail, m_rnum; + int m_thead, m_ttail; + emu_timer *m_timeout; +}; + +class pc16552_device : public device_t +{ +public: + pc16552_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + DECLARE_READ8_MEMBER(read) { return ((offset & 8) ? m_chan1 : m_chan0)->ins8250_r(space, offset & 7, mem_mask); } + DECLARE_WRITE8_MEMBER(write) { ((offset & 8) ? m_chan1 : m_chan0)->ins8250_w(space, offset & 7, data, mem_mask); } + +protected: + virtual void device_start(); + +private: + ns16550_device *m_chan0; + ns16550_device *m_chan1; +}; + +extern const device_type PC16552D; +extern const device_type INS8250; +extern const device_type NS16450; +extern const device_type NS16550; + +/*************************************************************************** + DEVICE CONFIGURATION MACROS +***************************************************************************/ + +#define MCFG_INS8250_OUT_TX_CB(_devcb) \ + devcb = &ins8250_uart_device::set_out_tx_callback(*device, DEVCB_##_devcb); + +#define MCFG_INS8250_OUT_DTR_CB(_devcb) \ + devcb = &ins8250_uart_device::set_out_dtr_callback(*device, DEVCB_##_devcb); + +#define MCFG_INS8250_OUT_RTS_CB(_devcb) \ + devcb = &ins8250_uart_device::set_out_rts_callback(*device, DEVCB_##_devcb); + +#define MCFG_INS8250_OUT_INT_CB(_devcb) \ + devcb = &ins8250_uart_device::set_out_int_callback(*device, DEVCB_##_devcb); + +#define MCFG_INS8250_OUT_OUT1_CB(_devcb) \ + devcb = &ins8250_uart_device::set_out_out1_callback(*device, DEVCB_##_devcb); + +#define MCFG_INS8250_OUT_OUT2_CB(_devcb) \ + devcb = &ins8250_uart_device::set_out_out2_callback(*device, DEVCB_##_devcb); + +#endif diff --git a/src/devices/machine/intelfsh.c b/src/devices/machine/intelfsh.c new file mode 100644 index 00000000000..6f841692bea --- /dev/null +++ b/src/devices/machine/intelfsh.c @@ -0,0 +1,1146 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/* + Flash ROM emulation + + Explicitly supports: + Intel 28F016S5 (byte-wide) + AMD/Fujitsu 29F016 (byte-wide) + Sharp LH28F400 (word-wide) + + Flash ROMs use a standardized command set across manufacturers, + so this emulation should work even for non-Intel and non-Sharp chips + as long as the game doesn't query the maker ID. +*/ + +#include "emu.h" +#include "intelfsh.h" + + +//************************************************************************** +// CONSTANTS +//************************************************************************** + +enum +{ + FM_NORMAL, // normal read/write + FM_READID, // read ID + FM_READSTATUS, // read status + FM_WRITEPART1, // first half of programming, awaiting second + FM_CLEARPART1, // first half of clear, awaiting second + FM_SETMASTER, // first half of set master lock, awaiting on/off + FM_READAMDID1, // part 1 of alt ID sequence + FM_READAMDID2, // part 2 of alt ID sequence + FM_READAMDID3, // part 3 of alt ID sequence + FM_ERASEAMD1, // part 1 of AMD erase sequence + FM_ERASEAMD2, // part 2 of AMD erase sequence + FM_ERASEAMD3, // part 3 of AMD erase sequence + FM_ERASEAMD4, // part 4 of AMD erase sequence + FM_BYTEPROGRAM, + FM_BANKSELECT, + FM_WRITEPAGEATMEL +}; + + +enum +{ + MFG_ALLIANCE = 0x52, + MFG_AMD = 0x01, + MFG_AMIC = 0x37, + MFG_ATMEL = 0x1f, + MFG_BRIGHT = 0xad, + MFG_CATALYST = 0x31, + MFG_EON = 0x1c, + MFG_FUJITSU = 0x04, + MFG_GIGADEVICE = 0xc8, + MFG_HYUNDAI = 0xad, + MFG_INTEL = 0x89, + MFG_ISSI = 0xd5, + MFG_MACRONIX = 0xc2, + MFG_PANASONIC = 0x32, + MFG_PMC = 0x9d, + MFG_SANYO = 0x62, + MFG_SHARP = 0xb0, + MFG_SPANSION = 0x01, + MFG_SST = 0xbf, + MFG_ST = 0x20, + MFG_SYNCMOS = 0x40, + MFG_TI = 0x97, + MFG_TI_OLD = 0x01, + MFG_WINBOND_NEX = 0xef, + MFG_WINBOND = 0xda +}; + + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +// device type definition +const device_type INTEL_28F016S5 = &device_creator; +const device_type SHARP_LH28F016S = &device_creator; +const device_type ATMEL_29C010 = &device_creator; +const device_type AMD_29F010 = &device_creator; +const device_type AMD_29F040 = &device_creator; +const device_type AMD_29F080 = &device_creator; +const device_type AMD_29F400T = &device_creator; +const device_type AMD_29F800T = &device_creator; +const device_type AMD_29LV200T = &device_creator; +const device_type FUJITSU_29F160T = &device_creator; +const device_type FUJITSU_29F016A = &device_creator; +const device_type FUJITSU_29DL16X = &device_creator; +const device_type INTEL_E28F400B = &device_creator; +const device_type MACRONIX_29L001MC = &device_creator; +const device_type MACRONIX_29LV160TMC = &device_creator; +const device_type TMS_29F040 = &device_creator; + +const device_type PANASONIC_MN63F805MNP = &device_creator; +const device_type SANYO_LE26FV10N1TS = &device_creator; +const device_type SST_28SF040 = &device_creator; +const device_type SST_39VF020 = &device_creator; + +const device_type SHARP_LH28F400 = &device_creator; +const device_type INTEL_E28F008SA = &device_creator; +const device_type INTEL_TE28F160 = &device_creator; +const device_type SHARP_UNK128MBIT = &device_creator; +const device_type INTEL_28F320J3D = &device_creator; +const device_type INTEL_28F320J5 = &device_creator; + +const device_type SST_39VF400A = &device_creator; + +static ADDRESS_MAP_START( memory_map8_512Kb, AS_PROGRAM, 8, intelfsh_device ) + AM_RANGE(0x00000, 0x00ffff) AM_RAM +ADDRESS_MAP_END + +static ADDRESS_MAP_START( memory_map8_1Mb, AS_PROGRAM, 8, intelfsh_device ) + AM_RANGE(0x00000, 0x01ffff) AM_RAM +ADDRESS_MAP_END + +static ADDRESS_MAP_START( memory_map8_2Mb, AS_PROGRAM, 8, intelfsh_device ) + AM_RANGE(0x00000, 0x03ffff) AM_RAM +ADDRESS_MAP_END + +static ADDRESS_MAP_START( memory_map8_4Mb, AS_PROGRAM, 8, intelfsh_device ) + AM_RANGE(0x00000, 0x07ffff) AM_RAM +ADDRESS_MAP_END + +static ADDRESS_MAP_START( memory_map8_8Mb, AS_PROGRAM, 8, intelfsh_device ) + AM_RANGE(0x00000, 0x0fffff) AM_RAM +ADDRESS_MAP_END + +static ADDRESS_MAP_START( memory_map8_16Mb, AS_PROGRAM, 8, intelfsh_device ) + AM_RANGE(0x00000, 0x1fffff) AM_RAM +ADDRESS_MAP_END + + +static ADDRESS_MAP_START( memory_map16_4Mb, AS_PROGRAM, 16, intelfsh_device ) + AM_RANGE(0x00000, 0x03ffff) AM_RAM +ADDRESS_MAP_END + +static ADDRESS_MAP_START( memory_map16_16Mb, AS_PROGRAM, 16, intelfsh_device ) + AM_RANGE(0x00000, 0x0fffff) AM_RAM +ADDRESS_MAP_END + +static ADDRESS_MAP_START( memory_map16_32Mb, AS_PROGRAM, 16, intelfsh_device ) + AM_RANGE(0x00000, 0x1fffff) AM_RAM +ADDRESS_MAP_END + +static ADDRESS_MAP_START( memory_map16_64Mb, AS_PROGRAM, 16, intelfsh_device ) + AM_RANGE(0x00000, 0x3fffff) AM_RAM +ADDRESS_MAP_END + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// intelfsh_device - constructor +//------------------------------------------------- + +intelfsh_device::intelfsh_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, UINT32 variant, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_memory_interface(mconfig, *this), + device_nvram_interface(mconfig, *this), + m_type(variant), + m_size(0), + m_bits(8), + m_addrmask(0), + m_device_id(0), + m_maker_id(0), + m_sector_is_4k(false), + m_sector_is_16k(false), + m_top_boot_sector(false), + m_status(0x80), + m_erase_sector(0), + m_flash_mode(FM_NORMAL), + m_flash_master_lock(false), + m_timer(NULL), + m_bank(0) +{ + address_map_constructor map = NULL; + + switch( variant ) + { + case FLASH_INTEL_28F016S5: + case FLASH_SHARP_LH28F016S: + m_bits = 8; + m_size = 0x200000; + m_maker_id = MFG_INTEL; + m_device_id = 0xaa; + map = ADDRESS_MAP_NAME( memory_map8_16Mb ); + break; + case FLASH_ATMEL_29C010: + m_bits = 8; + m_size = 0x20000; + m_page_size = 0x80; + m_maker_id = MFG_ATMEL; + m_device_id = 0xd5; + map = ADDRESS_MAP_NAME( memory_map8_1Mb ); + break; + case FLASH_AMD_29F010: + m_bits = 8; + m_size = 0x20000; + m_maker_id = MFG_AMD; + m_device_id = 0x20; + map = ADDRESS_MAP_NAME( memory_map8_1Mb ); + break; + case FLASH_AMD_29F040: + m_bits = 8; + m_size = 0x80000; + m_maker_id = MFG_AMD; + m_device_id = 0xa4; + map = ADDRESS_MAP_NAME( memory_map8_4Mb ); + break; + case FLASH_AMD_29F080: + m_bits = 8; + m_size = 0x100000; + m_addrmask = 0x7ff; + m_maker_id = MFG_AMD; + m_device_id = 0xd5; + map = ADDRESS_MAP_NAME( memory_map8_8Mb ); + break; + case FLASH_AMD_29F400T: + m_bits = 8; + m_size = 0x80000; + m_maker_id = MFG_AMD; + m_device_id = 0x23; + m_top_boot_sector = true; + map = ADDRESS_MAP_NAME( memory_map8_4Mb ); + break; + case FLASH_AMD_29F800T: + m_bits = 8; + m_size = 0x100000; + m_maker_id = MFG_AMD; + m_device_id = 0xda; + m_top_boot_sector = true; + map = ADDRESS_MAP_NAME( memory_map8_8Mb ); + break; + case FLASH_AMD_29LV200T: + m_bits = 8; + m_size = 0x40000; + m_maker_id = MFG_AMD; + m_device_id = 0x3b; + map = ADDRESS_MAP_NAME( memory_map8_2Mb ); + break; + case FLASH_INTEL_28F320J3D: + m_bits = 16; + m_size = 0x400000; + m_maker_id = MFG_INTEL; + m_device_id = 0x16; + m_sector_is_4k = true; + map = ADDRESS_MAP_NAME( memory_map16_32Mb ); + break; + case FLASH_INTEL_28F320J5: // funkball + m_bits = 16; + m_size = 0x400000; + m_maker_id = MFG_INTEL; + m_device_id = 0x14; +// m_sector_is_4k = true; 128kb? + map = ADDRESS_MAP_NAME( memory_map16_32Mb ); + break; + case FLASH_SST_39VF020: + m_bits = 8; + m_size = 0x40000; + m_maker_id = MFG_SST; + m_device_id = 0xd6; + m_sector_is_4k = true; + map = ADDRESS_MAP_NAME( memory_map8_2Mb ); + break; + case FLASH_SST_39VF400A: + m_bits = 16; + m_size = 0x80000; + m_maker_id = MFG_SST; + m_device_id = 0xd6; + m_sector_is_4k = true; + map = ADDRESS_MAP_NAME( memory_map16_4Mb ); + break; + case FLASH_SHARP_LH28F400: + m_bits = 16; + m_size = 0x80000; + m_maker_id = MFG_SHARP; + m_device_id = 0xed; + map = ADDRESS_MAP_NAME( memory_map16_4Mb ); + break; + case FLASH_INTEL_E28F400B: + m_bits = 16; + m_size = 0x80000; + m_maker_id = MFG_INTEL; + m_device_id = 0x4471; + map = ADDRESS_MAP_NAME( memory_map16_4Mb ); + break; + case FLASH_FUJITSU_29F160T: + m_bits = 8; + m_size = 0x200000; + m_maker_id = MFG_FUJITSU; + m_device_id = 0xad; + m_top_boot_sector = true; + map = ADDRESS_MAP_NAME( memory_map8_16Mb ); + break; + case FLASH_FUJITSU_29F016A: + m_bits = 8; + m_size = 0x200000; + m_maker_id = MFG_FUJITSU; + m_device_id = 0xad; + map = ADDRESS_MAP_NAME( memory_map8_16Mb ); + break; + case FLASH_FUJITSU_29DL16X: + m_bits = 8; + m_size = 0x200000; + m_maker_id = MFG_FUJITSU; + m_device_id = 0x35; + map = ADDRESS_MAP_NAME( memory_map8_16Mb ); + break; + case FLASH_INTEL_E28F008SA: + m_bits = 8; + m_size = 0x100000; + m_maker_id = MFG_INTEL; + m_device_id = 0xa2; + map = ADDRESS_MAP_NAME( memory_map8_8Mb ); + break; + case FLASH_INTEL_TE28F160: + m_bits = 16; + m_size = 0x200000; + m_maker_id = MFG_SHARP; + m_device_id = 0xd0; + map = ADDRESS_MAP_NAME( memory_map16_16Mb ); + break; + case FLASH_SHARP_UNK128MBIT: + m_bits = 16; + m_size = 0x800000; + m_maker_id = MFG_SHARP; + m_device_id = 0xb0; + map = ADDRESS_MAP_NAME( memory_map16_64Mb ); + break; + case FLASH_MACRONIX_29L001MC: + m_bits = 8; + m_size = 0x20000; + m_maker_id = MFG_MACRONIX; + m_device_id = 0x51; + map = ADDRESS_MAP_NAME( memory_map8_1Mb ); + break; + case FLASH_MACRONIX_29LV160TMC: + m_bits = 8; + m_size = 0x20000; + m_maker_id = MFG_MACRONIX; + m_device_id = 0x49; + m_sector_is_16k = true; + map = ADDRESS_MAP_NAME( memory_map8_1Mb ); + break; + case FLASH_PANASONIC_MN63F805MNP: + m_bits = 8; + m_size = 0x10000; + m_maker_id = MFG_PANASONIC; + m_device_id = 0x1b; + m_sector_is_4k = true; + map = ADDRESS_MAP_NAME( memory_map8_512Kb ); + break; + case FLASH_SANYO_LE26FV10N1TS: + m_bits = 8; + m_size = 0x20000; + m_maker_id = MFG_SANYO; + m_device_id = 0x13; + m_sector_is_4k = true; + map = ADDRESS_MAP_NAME( memory_map8_1Mb ); + break; + case FLASH_SST_28SF040: + m_bits = 8; + m_size = 0x80000; + m_maker_id = MFG_SST; + m_device_id = 0x04; + map = ADDRESS_MAP_NAME( memory_map8_4Mb ); + break; + case FLASH_TMS_29F040: + m_bits = 8; + m_addrmask = 0x7fff; + m_size = 0x80000; + m_maker_id = MFG_AMD; + m_device_id = 0xa4; + map = ADDRESS_MAP_NAME( memory_map8_4Mb ); + break; + } + + int addrbits; + for (addrbits = 24; addrbits > 0; addrbits--) + if ((m_size & (1 << addrbits)) != 0) + break; + + m_space_config = address_space_config("flash", ENDIANNESS_BIG, m_bits, addrbits, (m_bits == 8) ? 0 : -1, map); +} + +intelfsh8_device::intelfsh8_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, UINT32 variant, const char *shortname, const char *source) + : intelfsh_device(mconfig, type, name, tag, owner, clock, variant, shortname, source) { } + +intelfsh16_device::intelfsh16_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, UINT32 variant, const char *shortname, const char *source) + : intelfsh_device(mconfig, type, name, tag, owner, clock, variant, shortname, source) { } + + +intel_28f016s5_device::intel_28f016s5_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : intelfsh8_device(mconfig, INTEL_28F016S5, "Intel 28F016S5 Flash", tag, owner, clock, FLASH_INTEL_28F016S5, "intel_28f016s5", __FILE__) { } + +fujitsu_29f160t_device::fujitsu_29f160t_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : intelfsh8_device(mconfig, FUJITSU_29F160T, "Fujitsu 29F160 Flash", tag, owner, clock, FLASH_FUJITSU_29F160T, "fujitsu_29f160t", __FILE__) { } + +fujitsu_29f016a_device::fujitsu_29f016a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : intelfsh8_device(mconfig, FUJITSU_29F016A, "Fujitsu 29F016A Flash", tag, owner, clock, FLASH_FUJITSU_29F016A, "fujitsu_29f016a", __FILE__) { } + +fujitsu_29dl16x_device::fujitsu_29dl16x_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : intelfsh8_device(mconfig, FUJITSU_29DL16X, "Fujitsu 29DL16X Flash", tag, owner, clock, FLASH_FUJITSU_29DL16X, "fujitsu_29dl16x", __FILE__) { } + +sharp_lh28f016s_device::sharp_lh28f016s_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : intelfsh8_device(mconfig, SHARP_LH28F016S, "Sharp LH28F016S Flash", tag, owner, clock, FLASH_SHARP_LH28F016S, "sharp_lh28f016s", __FILE__) { } + +atmel_29c010_device::atmel_29c010_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : intelfsh8_device(mconfig, ATMEL_29C010, "Atmel 29C010 Flash", tag, owner, clock, FLASH_ATMEL_29C010, "atmel_29c010", __FILE__) { } + +amd_29f010_device::amd_29f010_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : intelfsh8_device(mconfig, AMD_29F010, "AMD 29F010 Flash", tag, owner, clock, FLASH_AMD_29F010, "amd_29f010", __FILE__) { } + +amd_29f040_device::amd_29f040_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : intelfsh8_device(mconfig, AMD_29F040, "AMD 29F040 Flash", tag, owner, clock, FLASH_AMD_29F040, "amd_29f040", __FILE__) { } + +amd_29f080_device::amd_29f080_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : intelfsh8_device(mconfig, AMD_29F080, "AMD 29F080 Flash", tag, owner, clock, FLASH_AMD_29F080, "amd_29f080", __FILE__) { } + +amd_29f400t_device::amd_29f400t_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : intelfsh8_device(mconfig, AMD_29F400T, "AMD 29F400 Flash", tag, owner, clock, FLASH_AMD_29F400T, "amd_29f400t", __FILE__) { } + +amd_29f800t_device::amd_29f800t_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : intelfsh8_device(mconfig, AMD_29F800T, "AMD 29F800 Flash", tag, owner, clock, FLASH_AMD_29F800T, "amd_29f800t", __FILE__) { } + +amd_29lv200t_device::amd_29lv200t_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : intelfsh8_device(mconfig, AMD_29LV200T, "AMD 29LV200T Flash", tag, owner, clock, FLASH_AMD_29LV200T, "amd_29lv200t", __FILE__) { } + +intel_e28f008sa_device::intel_e28f008sa_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : intelfsh8_device(mconfig, INTEL_E28F008SA, "Intel E28F008SA Flash", tag, owner, clock, FLASH_INTEL_E28F008SA, "intel_e28f008sa", __FILE__) { } + +macronix_29l001mc_device::macronix_29l001mc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : intelfsh8_device(mconfig, MACRONIX_29L001MC, "Macronix 29L001MC Flash", tag, owner, clock, FLASH_MACRONIX_29L001MC, "macronix_29l001mc", __FILE__) { } + +macronix_29lv160tmc_device::macronix_29lv160tmc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : intelfsh8_device(mconfig, MACRONIX_29LV160TMC, "Macronix 29LV160TMC Flash", tag, owner, clock, FLASH_MACRONIX_29LV160TMC, "macronix_29lv160tmc", __FILE__) { } + +panasonic_mn63f805mnp_device::panasonic_mn63f805mnp_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : intelfsh8_device(mconfig, PANASONIC_MN63F805MNP, "Panasonic MN63F805MNP Flash", tag, owner, clock, FLASH_PANASONIC_MN63F805MNP, "panasonic_mn63f805mnp", __FILE__) { } + +sanyo_le26fv10n1ts_device::sanyo_le26fv10n1ts_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : intelfsh8_device(mconfig, SANYO_LE26FV10N1TS, "Sanyo LE26FV10N1TS Flash", tag, owner, clock, FLASH_SANYO_LE26FV10N1TS, "sanyo_le26fv10n1ts", __FILE__) { } + +sst_28sf040_device::sst_28sf040_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : intelfsh8_device(mconfig, SST_28SF040, "SST 28SF040 Flash", tag, owner, clock, FLASH_SST_28SF040, "sst_28sf040", __FILE__) { } + +sst_39vf020_device::sst_39vf020_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : intelfsh8_device(mconfig, SST_39VF020, "SST 39VF020 Flash", tag, owner, clock, FLASH_SST_39VF020, "sst_39vf020", __FILE__) { } + +sharp_lh28f400_device::sharp_lh28f400_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : intelfsh16_device(mconfig, SHARP_LH28F400, "Sharp LH28F400 Flash", tag, owner, clock, FLASH_SHARP_LH28F400, "sharp_lh28f400", __FILE__) { } + +intel_te28f160_device::intel_te28f160_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : intelfsh16_device(mconfig, INTEL_TE28F160, "Intel TE28F160 Flash", tag, owner, clock, FLASH_INTEL_TE28F160, "intel_te28f160", __FILE__) { } + +intel_e28f400b_device::intel_e28f400b_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : intelfsh16_device(mconfig, INTEL_E28F400B, "Intel E28F400B Flash", tag, owner, clock, FLASH_INTEL_E28F400B, "intel_e28f400b", __FILE__) { } + +sharp_unk128mbit_device::sharp_unk128mbit_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : intelfsh16_device(mconfig, SHARP_UNK128MBIT, "Sharp Unknown 128Mbit Flash", tag, owner, clock, FLASH_SHARP_UNK128MBIT, "sharp_unk128mbit", __FILE__) { } + +intel_28f320j3d_device::intel_28f320j3d_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : intelfsh16_device(mconfig, INTEL_28F320J3D, "Intel 28F320J3D Flash", tag, owner, clock, FLASH_INTEL_28F320J3D, "intel_28f320j3d", __FILE__) { } + +intel_28f320j5_device::intel_28f320j5_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : intelfsh16_device(mconfig, INTEL_28F320J5, "Intel 28F320J3D_a Flash", tag, owner, clock, FLASH_INTEL_28F320J5, "intel_28f320j5", __FILE__) { } + + +sst_39vf400a_device::sst_39vf400a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : intelfsh16_device(mconfig, SST_39VF400A, "SST 39VF400A Flash", tag, owner, clock, FLASH_SST_39VF400A, "sst_39vf400a", __FILE__) { } + + +tms_29f040_device::tms_29f040_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : intelfsh8_device(mconfig, TMS_29F040, "Texas Instruments 29F040 Flash", tag, owner, clock, FLASH_TMS_29F040, "tms_29f040", __FILE__) { } + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void intelfsh_device::device_start() +{ + m_timer = timer_alloc(); + + save_item( NAME(m_status) ); + save_item( NAME(m_flash_mode) ); + save_item( NAME(m_flash_master_lock) ); +} + + +//------------------------------------------------- +// device_timer - handler timer events +//------------------------------------------------- + +void intelfsh_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch( m_flash_mode ) + { + case FM_READSTATUS: + m_status = 0x80; + break; + + case FM_ERASEAMD4: + m_flash_mode = FM_NORMAL; + break; + } +} + + +//------------------------------------------------- +// memory_space_config - return a description of +// any address spaces owned by this device +//------------------------------------------------- + +const address_space_config *intelfsh_device::memory_space_config(address_spacenum spacenum) const +{ + return (spacenum == 0) ? &m_space_config : NULL; +} + + +//------------------------------------------------- +// nvram_default - called to initialize NVRAM to +// its default state +//------------------------------------------------- + +void intelfsh_device::nvram_default() +{ + // region always wins + if (m_region != NULL) + { + UINT32 bytes = m_region->bytes(); + if (bytes > m_size) + bytes = m_size; + + if (m_bits == 8) + { + for (offs_t offs = 0; offs < bytes; offs++) + m_addrspace[0]->write_byte(offs, m_region->u8(offs)); + } + else + { + for (offs_t offs = 0; offs < bytes; offs += 2) + m_addrspace[0]->write_word(offs, m_region->u16(offs / 2)); + } + return; + } + + // otherwise, default to 0xff + for (offs_t offs = 0; offs < m_size; offs++) + m_addrspace[0]->write_byte(offs, 0xff); +} + + +//------------------------------------------------- +// nvram_read - called to read NVRAM from the +// .nv file +//------------------------------------------------- + +void intelfsh_device::nvram_read(emu_file &file) +{ + dynamic_buffer buffer(m_size); + file.read(&buffer[0], m_size); + for (int byte = 0; byte < m_size; byte++) + m_addrspace[0]->write_byte(byte, buffer[byte]); +} + + +//------------------------------------------------- +// nvram_write - called to write NVRAM to the +// .nv file +//------------------------------------------------- + +void intelfsh_device::nvram_write(emu_file &file) +{ + dynamic_buffer buffer(m_size); + for (int byte = 0; byte < m_size; byte++) + buffer[byte] = m_addrspace[0]->read_byte(byte); + file.write(&buffer[0], m_size); +} + + +//------------------------------------------------- +// read_full - generic read, called by the +// bit-width-specific readers +//------------------------------------------------- + +UINT32 intelfsh_device::read_full(UINT32 address) +{ + UINT32 data = 0; + address += m_bank << 16; + switch( m_flash_mode ) + { + default: + case FM_NORMAL: + switch( m_bits ) + { + case 8: + { + data = m_addrspace[0]->read_byte(address); + } + break; + case 16: + { + data = m_addrspace[0]->read_word(address * 2); + } + break; + } + break; + case FM_READSTATUS: + data = m_status; + break; + case FM_READAMDID3: + if ((m_maker_id == MFG_FUJITSU && m_device_id == 0x35) || (m_maker_id == MFG_AMD && m_device_id == 0x3b)) + { + // used in Fujitsu 29DL16X 8bits mode + // used in AMD 29LV200 8bits mode + switch (address) + { + case 0: data = m_maker_id; break; + case 2: data = m_device_id; break; + case 4: data = 0; break; + } + } + else + { + switch (address) + { + case 0: data = m_maker_id; break; + case 1: data = m_device_id; break; + case 2: data = 0; break; + } + } + break; + case FM_READID: + if (m_maker_id == MFG_INTEL && m_device_id == 0x16) + { + switch (address) + { + case 0: data = m_maker_id; break; + case 2: data = m_device_id; break; + case 4: data = 0; break; + } + } + else + { + switch (address) + { + case 0: // maker ID + data = m_maker_id; + break; + case 1: // chip ID + data = m_device_id; + break; + case 2: // block lock config + data = 0; // we don't support this yet + break; + case 3: // master lock config + if (m_flash_master_lock) + { + data = 1; + } + else + { + data = 0; + } + break; + } + } + break; + case FM_ERASEAMD4: + // reads outside of the erasing sector return normal data + if ((address < m_erase_sector) || (address >= m_erase_sector+(64*1024))) + { + switch( m_bits ) + { + case 8: + { + data = m_addrspace[0]->read_byte(address); + } + break; + case 16: + { + data = m_addrspace[0]->read_word(address * 2); + } + break; + } + } + else + { + m_status ^= ( 1 << 6 ) | ( 1 << 2 ); + data = m_status; + } + break; + } + + //logerror( "intelflash_read( %08x ) %08x\n", address, data ); + + return data; +} + + +//------------------------------------------------- +// write_full - generic write, called by the +// bit-width-specific writers +//------------------------------------------------- + +void intelfsh_device::write_full(UINT32 address, UINT32 data) +{ + //logerror( "intelflash_write( %u : %08x, %08x )\n", m_flash_mode, address, data ); + + address += m_bank << 16; + + switch( m_flash_mode ) + { + case FM_NORMAL: + case FM_READSTATUS: + case FM_READID: + case FM_READAMDID3: + switch( data & 0xff ) + { + case 0xf0: + case 0xff: // reset chip mode + m_flash_mode = FM_NORMAL; + break; + case 0x90: // read ID + m_flash_mode = FM_READID; + break; + case 0x40: + case 0x10: // program + m_flash_mode = FM_WRITEPART1; + break; + case 0x50: // clear status reg + m_status = 0x80; + m_flash_mode = FM_READSTATUS; + break; + case 0x20: // block erase + m_flash_mode = FM_CLEARPART1; + break; + case 0x60: // set master lock + m_flash_mode = FM_SETMASTER; + break; + case 0x70: // read status + m_flash_mode = FM_READSTATUS; + break; + case 0xaa: // AMD ID select part 1 + if( ( address & 0xfff ) == 0x555 ) + { + m_flash_mode = FM_READAMDID1; + } + else if( ( address & 0xfff ) == 0xaaa ) + { + m_flash_mode = FM_READAMDID1; + } + break; + default: + logerror( "Unknown flash mode byte %x\n", data & 0xff ); + break; + } + break; + case FM_READAMDID1: + if( ( address & 0xffff ) == 0x2aa && ( data & 0xff ) == 0x55 ) + { + m_flash_mode = FM_READAMDID2; + } + else if( ( address & 0xffff ) == 0x2aaa && ( data & 0xff ) == 0x55 ) + { + m_flash_mode = FM_READAMDID2; + } + else if( ( address & 0xfff ) == 0x555 && ( data & 0xff ) == 0x55 ) + { + m_flash_mode = FM_READAMDID2; + } + // for AMD 29F080 address bits A11-A19 don't care, for TMS 29F040 address bits A15-A18 don't care + else if( ( address & m_addrmask ) == ( 0xaaaa & m_addrmask ) && ( data & 0xff ) == 0x55 && m_addrmask ) + { + m_flash_mode = FM_READAMDID2; + } + else + { + logerror( "unexpected %08x=%02x in FM_READAMDID1\n", address, data & 0xff ); + m_flash_mode = FM_NORMAL; + } + break; + case FM_READAMDID2: + if( ( address & 0xffff ) == 0x555 && ( data & 0xff ) == 0x90 ) + { + m_flash_mode = FM_READAMDID3; + } + else if( ( address & 0xffff ) == 0x5555 && ( data & 0xff ) == 0x90 ) + { + m_flash_mode = FM_READAMDID3; + } + else if( ( address & 0xfff ) == 0xaaa && ( data & 0xff ) == 0x90 ) + { + m_flash_mode = FM_READAMDID3; + } + else if( ( address & 0xffff ) == 0x555 && ( data & 0xff ) == 0x80 ) + { + m_flash_mode = FM_ERASEAMD1; + } + else if( ( address & 0xffff ) == 0x5555 && ( data & 0xff ) == 0x80 ) + { + m_flash_mode = FM_ERASEAMD1; + } + else if( ( address & 0xfff ) == 0xaaa && ( data & 0xff ) == 0x80 ) + { + m_flash_mode = FM_ERASEAMD1; + } + else if( ( address & 0xffff ) == 0x555 && ( data & 0xff ) == 0xa0 ) + { + m_flash_mode = FM_BYTEPROGRAM; + } + else if( ( address & 0xffff ) == 0x5555 && ( data & 0xff ) == 0xa0 ) + { + if (m_type == FLASH_ATMEL_29C010) + { + m_flash_mode = FM_WRITEPAGEATMEL; + m_byte_count = 0; + } + else + { + m_flash_mode = FM_BYTEPROGRAM; + } + } + else if( ( address & 0xfff ) == 0xaaa && ( data & 0xff ) == 0xa0 ) + { + m_flash_mode = FM_BYTEPROGRAM; + } + else if( ( address & 0xffff ) == 0x555 && ( data & 0xff ) == 0xf0 ) + { + m_flash_mode = FM_NORMAL; + } + else if( ( address & 0xffff ) == 0x5555 && ( data & 0xff ) == 0xf0 ) + { + m_flash_mode = FM_NORMAL; + } + else if( ( address & 0xfff ) == 0xaaa && ( data & 0xff ) == 0xf0 ) + { + m_flash_mode = FM_NORMAL; + } + else if( ( address & 0xffff ) == 0x5555 && ( data & 0xff ) == 0xb0 && m_maker_id == 0x62 && m_device_id == 0x13 ) + { + m_flash_mode = FM_BANKSELECT; + } + + // for AMD 29F080 address bits A11-A19 don't care, for TMS 29F040 address bits A15-A18 don't care + else if(( address & m_addrmask ) == ( 0x5555 & m_addrmask ) && ( data & 0xff ) == 0x80 && m_addrmask ) + { + m_flash_mode = FM_ERASEAMD1; + } + else if(( address & m_addrmask ) == ( 0x5555 & m_addrmask ) && ( data & 0xff ) == 0x90 && m_addrmask ) + { + m_flash_mode = FM_READAMDID3; + } + else if(( address & m_addrmask ) == ( 0x5555 & m_addrmask ) && ( data & 0xff ) == 0xa0 && m_addrmask ) + { + m_flash_mode = FM_BYTEPROGRAM; + } + else if(( address & m_addrmask ) == ( 0x5555 & m_addrmask ) && ( data & 0xff ) == 0xf0 && m_addrmask ) + { + m_flash_mode = FM_NORMAL; + } + else + { + logerror( "unexpected %08x=%02x in FM_READAMDID2\n", address, data & 0xff ); + m_flash_mode = FM_NORMAL; + } + break; + case FM_ERASEAMD1: + if( ( address & 0xfff ) == 0x555 && ( data & 0xff ) == 0xaa ) + { + m_flash_mode = FM_ERASEAMD2; + } + else if( ( address & 0xfff ) == 0xaaa && ( data & 0xff ) == 0xaa ) + { + m_flash_mode = FM_ERASEAMD2; + } + else + { + logerror( "unexpected %08x=%02x in FM_ERASEAMD1\n", address, data & 0xff ); + } + break; + case FM_ERASEAMD2: + if( ( address & 0xffff ) == 0x2aa && ( data & 0xff ) == 0x55 ) + { + m_flash_mode = FM_ERASEAMD3; + } + else if( ( address & 0xffff ) == 0x2aaa && ( data & 0xff ) == 0x55 ) + { + m_flash_mode = FM_ERASEAMD3; + } + else if( ( address & 0xfff ) == 0x555 && ( data & 0xff ) == 0x55 ) + { + m_flash_mode = FM_ERASEAMD3; + } + else + { + logerror( "unexpected %08x=%02x in FM_ERASEAMD2\n", address, data & 0xff ); + } + break; + case FM_ERASEAMD3: + if( (( address & 0xfff ) == 0x555 && ( data & 0xff ) == 0x10 ) || + (( address & 0xfff ) == 0xaaa && ( data & 0xff ) == 0x10 ) ) + { + // chip erase + for (offs_t offs = 0; offs < m_size; offs++) + m_addrspace[0]->write_byte(offs, 0xff); + + m_status = 1 << 3; + m_flash_mode = FM_ERASEAMD4; + + if (m_sector_is_4k) + { + m_timer->adjust( attotime::from_seconds( 1 ) ); + } + else if(m_sector_is_16k) + { + m_timer->adjust( attotime::from_seconds( 4 ) ); + } + else + { + m_timer->adjust( attotime::from_seconds( 16 ) ); + } + } + else if( ( data & 0xff ) == 0x30 ) + { + // sector erase + // clear the 4k/64k block containing the current address to all 0xffs + UINT32 base = address * ((m_bits == 16) ? 2 : 1); + if (m_sector_is_4k) + { + for (offs_t offs = 0; offs < 4 * 1024; offs++) + m_addrspace[0]->write_byte((base & ~0xfff) + offs, 0xff); + m_erase_sector = address & ((m_bits == 16) ? ~0x7ff : ~0xfff); + m_timer->adjust( attotime::from_msec( 125 ) ); + } + else if(m_sector_is_16k) + { + for (offs_t offs = 0; offs < 16 * 1024; offs++) + m_addrspace[0]->write_byte((base & ~0x3fff) + offs, 0xff); + m_erase_sector = address & ((m_bits == 16) ? ~0x1fff : ~0x3fff); + m_timer->adjust( attotime::from_msec( 500 ) ); + } + else if(m_top_boot_sector && address >= (m_size - 64*1024)) + { + if (address >= (m_size - (16*1024))) + { + for (offs_t offs = 0; offs < 16 * 1024; offs++) + m_addrspace[0]->write_byte((base & ~0x3fff) + offs, 0xff); + m_erase_sector = address & ((m_bits == 16) ? ~0x1fff : ~0x3fff); + m_timer->adjust( attotime::from_msec( 500 ) ); + } + else if (address >= (m_size - (32*1024))) + { + for (offs_t offs = 0; offs < 8 * 1024; offs++) + m_addrspace[0]->write_byte((base & ~0x1fff) + offs, 0xff); + m_erase_sector = address & ((m_bits == 16) ? ~0xfff : ~0x1fff); + m_timer->adjust( attotime::from_msec( 250 ) ); + } + else + { + for (offs_t offs = 0; offs < 32 * 1024; offs++) + m_addrspace[0]->write_byte((base & ~0x7fff) + offs, 0xff); + m_erase_sector = address & ((m_bits == 16) ? ~0x3fff : ~0x7fff); + m_timer->adjust( attotime::from_msec( 500 ) ); + } + } + else + { + for (offs_t offs = 0; offs < 64 * 1024; offs++) + m_addrspace[0]->write_byte((base & ~0xffff) + offs, 0xff); + m_erase_sector = address & ((m_bits == 16) ? ~0x7fff : ~0xffff); + m_timer->adjust( attotime::from_seconds( 1 ) ); + } + + m_status = 1 << 3; + m_flash_mode = FM_ERASEAMD4; + } + else + { + logerror( "unexpected %08x=%02x in FM_ERASEAMD3\n", address, data & 0xff ); + } + break; + case FM_BYTEPROGRAM: + switch( m_bits ) + { + case 8: + { + m_addrspace[0]->write_byte(address, data); + } + break; + default: + logerror( "FM_BYTEPROGRAM not supported when m_bits == %d\n", m_bits ); + break; + } + m_flash_mode = FM_NORMAL; + break; + case FM_WRITEPART1: + switch( m_bits ) + { + case 8: + { + m_addrspace[0]->write_byte(address, data); + } + break; + case 16: + { + m_addrspace[0]->write_word(address * 2, data); + } + break; + default: + logerror( "FM_WRITEPART1 not supported when m_bits == %d\n", m_bits ); + break; + } + m_status = 0x80; + if (m_type == FLASH_SST_28SF040) + m_flash_mode = FM_NORMAL; + else + m_flash_mode = FM_READSTATUS; + break; + case FM_WRITEPAGEATMEL: + switch( m_bits ) + { + case 8: + { + m_addrspace[0]->write_byte(address, data); + } + break; + case 16: + { + m_addrspace[0]->write_word(address * 2, data); + } + break; + default: + logerror( "FM_WRITEPAGEATMEL not supported when m_bits == %d\n", m_bits ); + break; + } + + m_byte_count++; + + if (m_byte_count == m_page_size) + { + m_flash_mode = FM_NORMAL; + } + break; + case FM_CLEARPART1: + if( ( data & 0xff ) == 0xd0 ) + { + if (m_type == FLASH_SST_28SF040) + { + // clear the 256 bytes block containing the current address to all 0xffs + UINT32 base = address * ((m_bits == 16) ? 2 : 1); + for (offs_t offs = 0; offs < 256; offs++) + m_addrspace[0]->write_byte((base & ~0xff) + offs, 0xff); + + m_timer->adjust( attotime::from_msec( 4 ) ); + } + else if (m_type == FLASH_INTEL_E28F400B) + { + // 00000-03fff - 16KB boot block (may be write protected via external pins) + // 04000-05fff - 8KB parameter block + // 06000-07fff - 8KB parameter block + // 08000-1ffff - 96KB main block + // 20000-3ffff - 128KB main block + // 40000-5ffff - 128KB main block + // 60000-7ffff - 128KB main block + // erase duration is 0.3s for boot and parameter blocks, and 0.6s for main blocks + UINT32 base = (address & 0x3ffff) * 2; + int size, duration; + if (base < 0x4000) + { + base = 0; + size = 0x4000; + duration = 300; + } + else if (base < 0x8000) + { + base &= 0x6000; + size = 0x2000; + duration = 300; + } + else if (base < 0x20000) + { + base = 0x8000; + size = 0x18000; + duration = 600; + } + else + { + base &= 0x60000; + size = 0x20000; + duration = 600; + } + + // clear the block containing the current address to all 0xffffs + for (offs_t offs = 0; offs < size / 2; offs += 2) + m_addrspace[0]->write_word(base | offs, 0xffff); + + m_timer->adjust( attotime::from_msec( duration ) ); + } + else + { + // clear the 64k block containing the current address to all 0xffs + UINT32 base = address * ((m_bits == 16) ? 2 : 1); + for (offs_t offs = 0; offs < 64 * 1024; offs++) + m_addrspace[0]->write_byte((base & ~0xffff) + offs, 0xff); + + m_timer->adjust( attotime::from_seconds( 1 ) ); + } + + m_status = 0x00; + m_flash_mode = FM_READSTATUS; + break; + } + else + { + logerror( "unexpected %02x in FM_CLEARPART1\n", data & 0xff ); + } + break; + case FM_SETMASTER: + switch( data & 0xff ) + { + case 0xf1: + m_flash_master_lock = true; + break; + case 0xd0: + m_flash_master_lock = false; + break; + default: + logerror( "unexpected %08x=%02x in FM_SETMASTER:\n", address, data & 0xff ); + break; + } + m_flash_mode = FM_NORMAL; + break; + case FM_BANKSELECT: + m_bank = data & 0xff; + m_flash_mode = FM_NORMAL; + break; + } +} diff --git a/src/devices/machine/intelfsh.h b/src/devices/machine/intelfsh.h new file mode 100644 index 00000000000..5e4b86f10d2 --- /dev/null +++ b/src/devices/machine/intelfsh.h @@ -0,0 +1,427 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/* + Intel Flash ROM emulation +*/ + +#ifndef _INTELFLASH_H_ +#define _INTELFLASH_H_ + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_INTEL_28F016S5_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, INTEL_28F016S5, 0) + +#define MCFG_SHARP_LH28F016S_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, SHARP_LH28F016S, 0) + +#define MCFG_ATMEL_29C010_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, ATMEL_29C010, 0) + +#define MCFG_AMD_29F010_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, AMD_29F010, 0) + +#define MCFG_AMD_29F040_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, AMD_29F040, 0) + +#define MCFG_AMD_29F080_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, AMD_29F080, 0) + +#define MCFG_AMD_29F400T_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, AMD_29F400T, 0) + +#define MCFG_AMD_29F800T_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, AMD_29F800T, 0) + +#define MCFG_AMD_29LV200T_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, AMD_29LV200T, 0) + +#define MCFG_FUJITSU_29F160T_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, FUJITSU_29F160T, 0) + +#define MCFG_FUJITSU_29F016A_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, FUJITSU_29F016A, 0) + +#define MCFG_FUJITSU_29DL16X_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, FUJITSU_29DL16X, 0) + +#define MCFG_INTEL_E28F400B_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, INTEL_E28F400B, 0) + +#define MCFG_MACRONIX_29L001MC_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, MACRONIX_29L001MC, 0) + +#define MCFG_MACRONIX_29LV160TMC_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, MACRONIX_29LV160TMC, 0) + +#define MCFG_PANASONIC_MN63F805MNP_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, PANASONIC_MN63F805MNP, 0) + +#define MCFG_SANYO_LE26FV10N1TS_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, SANYO_LE26FV10N1TS, 0) + +#define MCFG_SST_28SF040_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, SST_28SF040, 0) + +#define MCFG_SST_39VF020_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, SST_39VF020, 0) + +#define MCFG_SHARP_LH28F400_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, SHARP_LH28F400, 0) + +#define MCFG_INTEL_E28F008SA_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, INTEL_E28F008SA, 0) + +#define MCFG_INTEL_TE28F160_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, INTEL_TE28F160, 0) + +#define MCFG_SHARP_UNK128MBIT_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, SHARP_UNK128MBIT, 0) + +#define MCFG_INTEL_28F320J3D_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, INTEL_28F320J3D, 0) + +#define MCFG_INTEL_28F320J5_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, INTEL_28F320J5, 0) + +#define MCFG_SST_39VF400A_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, SST_39VF400A, 0) + +#define MCFG_TMS_29F040_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, TMS_29F040, 0) + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class intelfsh_device; + + +// ======================> intelfsh_device + +class intelfsh_device : public device_t, + public device_memory_interface, + public device_nvram_interface +{ +public: + enum + { + // 8-bit variants + FLASH_INTEL_28F016S5 = 0x0800, + FLASH_FUJITSU_29F160T, + FLASH_FUJITSU_29F016A, + FLASH_FUJITSU_29DL16X, + FLASH_ATMEL_29C010, + FLASH_AMD_29F010, + FLASH_AMD_29F040, + FLASH_AMD_29F080, + FLASH_AMD_29F400T, + FLASH_AMD_29F800T, + FLASH_AMD_29LV200T, + FLASH_SHARP_LH28F016S, + FLASH_INTEL_E28F008SA, + FLASH_MACRONIX_29L001MC, + FLASH_MACRONIX_29LV160TMC, + FLASH_PANASONIC_MN63F805MNP, + FLASH_SANYO_LE26FV10N1TS, + FLASH_SST_28SF040, + FLASH_SST_39VF020, + FLASH_TMS_29F040, + + // 16-bit variants + FLASH_SHARP_LH28F400 = 0x1000, + FLASH_INTEL_E28F400B, + FLASH_INTEL_TE28F160, + FLASH_SHARP_UNK128MBIT, + FLASH_INTEL_28F320J3D, + FLASH_INTEL_28F320J5, + FLASH_SST_39VF400A + }; + +protected: + // construction/destruction + intelfsh_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, UINT32 variant, const char *shortname, const char *source); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const; + + // device_nvram_interface overrides + virtual void nvram_default(); + virtual void nvram_read(emu_file &file); + virtual void nvram_write(emu_file &file); + + // derived helpers + UINT32 read_full(UINT32 offset); + void write_full(UINT32 offset, UINT32 data); + + // configuration state + address_space_config m_space_config; + UINT32 m_type; + INT32 m_size; + UINT8 m_bits; + UINT32 m_addrmask; + UINT16 m_device_id; + UINT8 m_maker_id; + bool m_sector_is_4k; + bool m_sector_is_16k; + bool m_top_boot_sector; + UINT8 m_page_size; + + // internal state + UINT8 m_status; + INT32 m_erase_sector; + INT32 m_flash_mode; + bool m_flash_master_lock; + emu_timer * m_timer; + INT32 m_bank; + UINT8 m_byte_count; +}; + + +// ======================> intelfsh8_device + +class intelfsh8_device : public intelfsh_device +{ +protected: + // construction/destruction + intelfsh8_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, UINT32 variant, const char *shortname, const char *source); + +public: + // public interface + UINT8 read(offs_t offset) { return read_full(offset); } + void write(offs_t offset, UINT8 data) { write_full(offset, data); } + DECLARE_READ8_MEMBER(read) { return read_full(offset); } + DECLARE_WRITE8_MEMBER(write) { write_full(offset, data); } + + UINT8 read_raw(offs_t offset) { return m_addrspace[0]->read_byte(offset); } + void write_raw(offs_t offset, UINT8 data) { m_addrspace[0]->write_byte(offset, data); } +}; + + +// ======================> intelfsh16_device + +class intelfsh16_device : public intelfsh_device +{ +protected: + // construction/destruction + intelfsh16_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, UINT32 variant, const char *shortname, const char *source); + +public: + // public interface + UINT16 read(offs_t offset) { return read_full(offset); } + void write(offs_t offset, UINT16 data) { write_full(offset, data); } + DECLARE_READ16_MEMBER(read) { return read_full(offset); } + DECLARE_WRITE16_MEMBER(write) { write_full(offset, data); } + + UINT16 read_raw(offs_t offset) { return m_addrspace[0]->read_word(offset * 2); } + void write_raw(offs_t offset, UINT16 data) { m_addrspace[0]->write_word(offset * 2, data); } +}; + + +// ======================> trivial variants + +// 8-bit variants +class intel_28f016s5_device : public intelfsh8_device +{ +public: + intel_28f016s5_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class fujitsu_29f160t_device : public intelfsh8_device +{ +public: + fujitsu_29f160t_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class fujitsu_29f016a_device : public intelfsh8_device +{ +public: + fujitsu_29f016a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class fujitsu_29dl16x_device : public intelfsh8_device +{ +public: + fujitsu_29dl16x_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class atmel_29c010_device : public intelfsh8_device +{ +public: + atmel_29c010_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class amd_29f010_device : public intelfsh8_device +{ +public: + amd_29f010_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class amd_29f040_device : public intelfsh8_device +{ +public: + amd_29f040_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class amd_29f080_device : public intelfsh8_device +{ +public: + amd_29f080_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class amd_29f400t_device : public intelfsh8_device +{ +public: + amd_29f400t_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class amd_29f800t_device : public intelfsh8_device +{ +public: + amd_29f800t_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class amd_29lv200t_device : public intelfsh8_device +{ +public: + amd_29lv200t_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class sharp_lh28f016s_device : public intelfsh8_device +{ +public: + sharp_lh28f016s_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class intel_e28f008sa_device : public intelfsh8_device +{ +public: + intel_e28f008sa_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class macronix_29l001mc_device : public intelfsh8_device +{ +public: + macronix_29l001mc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class macronix_29lv160tmc_device : public intelfsh8_device +{ +public: + macronix_29lv160tmc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class panasonic_mn63f805mnp_device : public intelfsh8_device +{ +public: + panasonic_mn63f805mnp_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class sanyo_le26fv10n1ts_device : public intelfsh8_device +{ +public: + sanyo_le26fv10n1ts_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class sst_28sf040_device : public intelfsh8_device +{ +public: + sst_28sf040_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class sst_39vf020_device : public intelfsh8_device +{ +public: + sst_39vf020_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class tms_29f040_device : public intelfsh8_device +{ +public: + tms_29f040_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +// 16-bit variants +class sharp_lh28f400_device : public intelfsh16_device +{ +public: + sharp_lh28f400_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class intel_te28f160_device : public intelfsh16_device +{ +public: + intel_te28f160_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class intel_e28f400b_device : public intelfsh16_device +{ +public: + intel_e28f400b_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class sharp_unk128mbit_device : public intelfsh16_device +{ +public: + sharp_unk128mbit_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class intel_28f320j3d_device : public intelfsh16_device +{ +public: + intel_28f320j3d_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class intel_28f320j5_device : public intelfsh16_device +{ +public: + intel_28f320j5_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class sst_39vf400a_device : public intelfsh16_device +{ +public: + sst_39vf400a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +// device type definition +extern const device_type INTEL_28F016S5; +extern const device_type SHARP_LH28F016S; +extern const device_type ATMEL_29C010; +extern const device_type AMD_29F010; +extern const device_type AMD_29F040; +extern const device_type AMD_29F080; +extern const device_type AMD_29F400T; +extern const device_type AMD_29F800T; +extern const device_type AMD_29LV200T; +extern const device_type FUJITSU_29F160T; +extern const device_type FUJITSU_29F016A; +extern const device_type FUJITSU_29DL16X; +extern const device_type INTEL_E28F400B; +extern const device_type MACRONIX_29L001MC; +extern const device_type MACRONIX_29LV160TMC; +extern const device_type TMS_29F040; + +extern const device_type PANASONIC_MN63F805MNP; +extern const device_type SANYO_LE26FV10N1TS; +extern const device_type SST_28SF040; +extern const device_type SST_39VF020; + +extern const device_type SHARP_LH28F400; +extern const device_type INTEL_E28F008SA; +extern const device_type INTEL_TE28F160; +extern const device_type SHARP_UNK128MBIT; +extern const device_type INTEL_28F320J3D; +extern const device_type INTEL_28F320J5; +extern const device_type SST_39VF400A; + +#endif diff --git a/src/devices/machine/jvsdev.c b/src/devices/machine/jvsdev.c new file mode 100644 index 00000000000..3357ce90f55 --- /dev/null +++ b/src/devices/machine/jvsdev.c @@ -0,0 +1,260 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +#include "jvsdev.h" +#include "jvshost.h" + +void jvs_device::static_set_jvs_host_tag(device_t &device, const char *jvs_host_tag) +{ + jvs_device &jvsdev = downcast(device); + jvsdev.jvs_host_tag = jvs_host_tag; +} + +jvs_device::jvs_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source) +{ + jvs_host_tag = 0; + next_device = 0; +} + +const char *jvs_device::device_id() +{ + return ""; +} + +UINT8 jvs_device::command_format_version() +{ + return 0x13; +} + +UINT8 jvs_device::jvs_standard_version() +{ + return 0x30; +} + +UINT8 jvs_device::comm_method_version() +{ + return 0x10; +} + +void jvs_device::chain(jvs_device *dev) +{ + if(next_device) + next_device->chain(dev); + else + next_device = dev; +} + +void jvs_device::message(UINT8 dest, const UINT8 *send_buffer, UINT32 send_size, UINT8 *recv_buffer, UINT32 &recv_size) +{ + recv_size = 0; + + // Set Address special case + if(send_size == 2 && send_buffer[0] == 0xf1) { + if(next_device && !next_device->get_address_set_line()) + next_device->message(dest, send_buffer, send_size, recv_buffer, recv_size); + else { + jvs_address = send_buffer[1]; + recv_size = 2; + recv_buffer[0] = 0x01; + recv_buffer[1] = 0x01; + } + return; + } + + // dest=0xff is broadcast + if(dest == 0xff || dest == jvs_address) { + const UINT8 *s = send_buffer; + UINT8 *d = recv_buffer; + *d++ = 0x01; + while(s < send_buffer + send_size) { + int len = handle_message(s, send_size-(s-send_buffer), d); + if(len == -1) { + // Unknown command + recv_size = 1; + recv_buffer[0] = 0x02; + return; + } else if(len == 0) { + // Incorrect parameter + *d++ = 0x02; + break; + } else + s += len; + } + recv_size = d - recv_buffer; + } + + // Pass along the message if the device hasn't replied + // Should we cumulate answers instead? + if(next_device && !recv_size) + next_device->message(dest, send_buffer, send_size, recv_buffer, recv_size); +} + +int jvs_device::handle_message(const UINT8 *send_buffer, UINT32 send_size, UINT8 *&recv_buffer) +{ + UINT32 old_reset_counter = jvs_reset_counter; + jvs_reset_counter = 0; + + switch(send_buffer[0]) { + case 0xf0: + if(send_size < 2 || send_buffer[1] != 0xd9) + return 0; + + // Reset, must be sent twice + jvs_reset_counter = old_reset_counter+1; + if(jvs_reset_counter == 2) + device_reset(); + return 2; + + case 0x10: { + const char *id = device_id(); + int len = strlen(id)+1; + *recv_buffer++ = 0x01; + memcpy(recv_buffer, id, len); + recv_buffer += len; + return 1; + } + + case 0x11: + *recv_buffer++ = 0x01; + *recv_buffer++ = command_format_version(); + return 1; + + case 0x12: + *recv_buffer++ = 0x01; + *recv_buffer++ = jvs_standard_version(); + return 1; + + case 0x13: + *recv_buffer++ = 0x01; + *recv_buffer++ = comm_method_version(); + return 1; + + case 0x14: + *recv_buffer++ = 0x01; + function_list(recv_buffer); + *recv_buffer++ = 0x00; + return 1; + + case 0x20: + if(send_size < 3) + return 0; + *recv_buffer++ = 0x01; + return switches(recv_buffer, send_buffer[1], send_buffer[2]) ? 3 : 0; + + case 0x21: + if(send_size < 2) + return 0; + *recv_buffer++ = 0x01; + return coin_counters(recv_buffer, send_buffer[1]) ? 2 : 0; + + case 0x22: + if(send_size < 2) + return 0; + *recv_buffer++ = 0x01; + return analogs(recv_buffer, send_buffer[1]) ? 2 : 0; + + case 0x30: + if(send_size < 4) + return 0; + *recv_buffer++ = 0x01; + return coin_add(send_buffer[1], -((send_buffer[2] << 8) | send_buffer[3])) ? 4 : 0; + + case 0x31: + if(send_size < 4) + return 0; + *recv_buffer++ = 0x01; + return coin_add(send_buffer[1], ((send_buffer[2] << 8) | send_buffer[3])) ? 4 : 0; + + case 0x32: + if(send_size < 2 || send_size < 2+send_buffer[1]) + return 0; + *recv_buffer++ = 0x01; + return swoutputs(send_buffer[1], send_buffer+2) ? 2+send_buffer[1] : 0; + + case 0x38: + if(send_size < 3) + return 0; + *recv_buffer++ = 0x01; + return swoutputs(send_buffer[1], send_buffer[2]) ? 3 : 0; + + default: + logerror("JVSDEV: unhandled command %02x\n", send_buffer[0]); + return 0; + } + + // never executed + //return -1; +} + +bool jvs_device::get_address_set_line() +{ + return jvs_address != 0xff && (!next_device || next_device->get_address_set_line()); +} + +void jvs_device::device_start() +{ + jvs_host *host = machine().device(jvs_host_tag); + if(!host) + fatalerror("JVS device %s could not find JVS host %s\n", tag(), jvs_host_tag); + host->add_device(this); + + save_item(NAME(jvs_address)); + save_item(NAME(jvs_reset_counter)); +} + +void jvs_device::device_reset() +{ + jvs_address = 0xff; + jvs_reset_counter = 0; + jvs_outputs = 0; +} + +void jvs_device::function_list(UINT8 *&buf) +{ +} + +bool jvs_device::coin_counters(UINT8 *&buf, UINT8 count) +{ + return false; +} + +bool jvs_device::coin_add(UINT8 slot, INT32 count) +{ + return false; +} + + +bool jvs_device::switches(UINT8 *&buf, UINT8 count_players, UINT8 bytes_per_switch) +{ + return false; +} + +bool jvs_device::analogs(UINT8 *&buf, UINT8 count) +{ + return false; +} + +bool jvs_device::swoutputs(UINT8 count, const UINT8 *vals) +{ + return false; +} + +bool jvs_device::swoutputs(UINT8 id, UINT8 val) +{ + return false; +} + +void jvs_device::handle_output(ioport_port *port, UINT8 id, UINT8 val) +{ + UINT32 m = 1 << id; + switch(val) { + case 0: jvs_outputs &= ~m; break; + case 1: jvs_outputs |= m; break; + case 2: jvs_outputs ^= m; break; + } + + if (port) + { + port->write(jvs_outputs, m); + } +} diff --git a/src/devices/machine/jvsdev.h b/src/devices/machine/jvsdev.h new file mode 100644 index 00000000000..97382ea1655 --- /dev/null +++ b/src/devices/machine/jvsdev.h @@ -0,0 +1,54 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +#ifndef __JVSDEV_H__ +#define __JVSDEV_H__ + +#include "emu.h" + +#define MCFG_JVS_DEVICE_ADD(_tag, _type, _host) \ + MCFG_DEVICE_ADD(_tag, _type, 0) \ + jvs_device::static_set_jvs_host_tag(*device, _host); +class jvs_host; + +class jvs_device : public device_t +{ +public: + jvs_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + static void static_set_jvs_host_tag(device_t &device, const char *jvs_host_tag); + + void chain(jvs_device *dev); + void message(UINT8 dest, const UINT8 *send_buffer, UINT32 send_size, UINT8 *recv_buffer, UINT32 &recv_size); + bool get_address_set_line(); + +protected: + UINT32 jvs_outputs; + + void handle_output(ioport_port *port, UINT8 id, UINT8 val); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // JVS device overrides + virtual const char *device_id(); + virtual UINT8 command_format_version(); + virtual UINT8 jvs_standard_version(); + virtual UINT8 comm_method_version(); + virtual void function_list(UINT8 *&buf); + virtual bool switches(UINT8 *&buf, UINT8 count_players, UINT8 bytes_per_switch); + virtual bool coin_counters(UINT8 *&buf, UINT8 count); + virtual bool coin_add(UINT8 slot, INT32 count); + virtual bool analogs(UINT8 *&buf, UINT8 count); + virtual bool swoutputs(UINT8 count, const UINT8 *vals); + virtual bool swoutputs(UINT8 id, UINT8 val); + +private: + const char *jvs_host_tag; + jvs_device *next_device; + UINT8 jvs_address; + UINT32 jvs_reset_counter; + + int handle_message(const UINT8 *send_buffer, UINT32 send_size, UINT8 *&recv_buffer); +}; + +#endif diff --git a/src/devices/machine/jvshost.c b/src/devices/machine/jvshost.c new file mode 100644 index 00000000000..1621d691cea --- /dev/null +++ b/src/devices/machine/jvshost.c @@ -0,0 +1,157 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +#include "jvshost.h" +#include "jvsdev.h" + +void jvs_host::add_device(jvs_device *dev) +{ + if(first_device) + first_device->chain(dev); + else + first_device = dev; +} + +void jvs_host::device_start() +{ + save_item(NAME(send_size)); + save_item(NAME(recv_size)); + save_item(NAME(send_buffer)); + save_item(NAME(recv_buffer)); + save_item(NAME(recv_is_encoded)); +} + +void jvs_host::device_reset() +{ + send_size = recv_size = 0; + recv_is_encoded = false; + memset(send_buffer, 0, sizeof(send_buffer)); + memset(recv_buffer, 0, sizeof(recv_buffer)); +} + +jvs_host::jvs_host(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source) +{ + first_device = 0; +} + +void jvs_host::push(UINT8 val) +{ + send_buffer[send_size++] = val; +} + +void jvs_host::commit_raw() +{ + recv_size = 0; + if(!send_size) + return; + + // Message must: + // - have a non-zero destination in the first byte + // - have the message length without the two header bytes but with the checksum byte in the second byte + // - have at least one command byte + if(send_size < 3 || send_buffer[0] == 0x00 || send_buffer[1] != send_size-1) { + logerror("JVS checksum error\n"); + // "This message is crap" doesn't exist so call it checksum error + recv_buffer[0] = 0x00; + recv_buffer[1] = 0x02; + recv_buffer[2] = 0x03; + recv_size = 3; + } else { + if(first_device) { + first_device->message(send_buffer[0], send_buffer+2, send_size-2, recv_buffer+2, recv_size); + recv_is_encoded = false; + if(recv_size) { + // Add the reply header, host is always destination 0x00 + recv_buffer[0] = 0x00; + recv_buffer[1] = recv_size+1; + recv_size += 2; + } + } else + recv_size = 0; + } + send_size = 0; +} + +void jvs_host::commit_encoded() +{ + recv_size = 0; + if(!send_size) + return; + decode(send_buffer, send_size); + commit_raw(); +} + + +void jvs_host::get_raw_reply(const UINT8 *&buffer, UINT32 &size) +{ + if(recv_is_encoded) { + decode(recv_buffer, recv_size); + recv_is_encoded = false; + } + buffer = recv_buffer; + size = recv_size; +} + +void jvs_host::get_encoded_reply(const UINT8 *&buffer, UINT32 &size) +{ + if(!recv_is_encoded) { + encode(recv_buffer, recv_size); + recv_is_encoded = true; + } + buffer = recv_buffer; + size = recv_size; +} + +bool jvs_host::get_presence_line() +{ + return first_device != 0; +} + +bool jvs_host::get_address_set_line() +{ + return first_device && first_device->get_address_set_line(); +} + + +void jvs_host::encode(UINT8 *buffer, UINT32 &size) +{ + if(!size) + return; + UINT32 add = 1; + UINT8 sum = 0; + for(UINT32 i=0; i; + +//------------------------------------------------- +// k033906_device - constructor +//------------------------------------------------- + +k033906_device::k033906_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, K033906, "K033906 PCI bridge", tag, owner, clock, "k033906", __FILE__) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void k033906_device::device_start() +{ + m_voodoo = machine().device(m_voodoo_tag); + + m_reg_set = 0; + + save_item(NAME(m_reg)); + save_item(NAME(m_ram)); + save_item(NAME(m_reg_set)); +} + + +WRITE_LINE_MEMBER(k033906_device::set_reg) +{ + m_reg_set = state & 1; +} + +UINT32 k033906_device::reg_r(int reg) +{ + switch (reg) + { + case 0x00: return 0x0001121a; // PCI Vendor ID (0x121a = 3dfx), Device ID (0x0001 = Voodoo) + case 0x02: return 0x04000000; // Revision ID + case 0x04: return m_reg[0x04]; // memBaseAddr + case 0x0f: return m_reg[0x0f]; // interrupt_line, interrupt_pin, min_gnt, max_lat + + default: + fatalerror("%s: k033906_reg_r: %08X\n", machine().describe_context(), reg); + } + // never executed + //return 0; +} + +void k033906_device::reg_w(int reg, UINT32 data) +{ + switch (reg) + { + case 0x00: + break; + + case 0x01: // command register + break; + + case 0x04: // memBaseAddr + { + if (data == 0xffffffff) + { + m_reg[0x04] = 0xff000000; + } + else + { + m_reg[0x04] = data & 0xff000000; + } + break; + } + + case 0x0f: // interrupt_line, interrupt_pin, min_gnt, max_lat + { + m_reg[0x0f] = data; + break; + } + + case 0x10: // initEnable + { + voodoo_set_init_enable(m_voodoo, data); + break; + } + + case 0x11: // busSnoop0 + case 0x12: // busSnoop1 + break; + + case 0x38: // ??? + break; + + default: + fatalerror("%s:K033906_w: %08X, %08X\n", machine().describe_context(), data, reg); + } +} + +READ32_MEMBER(k033906_device::read) +{ + if (m_reg_set) + return reg_r(offset); + else + return m_ram[offset]; +} + +WRITE32_MEMBER(k033906_device::write) +{ + if (m_reg_set) + reg_w(offset, data); + else + m_ram[offset] = data; +} diff --git a/src/devices/machine/k033906.h b/src/devices/machine/k033906.h new file mode 100644 index 00000000000..bec3bc1c3ac --- /dev/null +++ b/src/devices/machine/k033906.h @@ -0,0 +1,71 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*************************************************************************** + + Konami 033906 + +***************************************************************************/ + +#pragma once + +#ifndef __K033906_H__ +#define __K033906_H__ + +#include "emu.h" + + + +/*************************************************************************** + DEVICE CONFIGURATION MACROS +***************************************************************************/ + +#define MCFG_K033906_VOODOO(_tag) \ + k033906_device::set_voodoo_tag(*device, _tag); + +/*************************************************************************** + TYPE DEFINITIONS +***************************************************************************/ + + +// ======================> k033906_device + +class k033906_device : public device_t +{ +public: + // construction/destruction + k033906_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + static void set_voodoo_tag(device_t &device, const char *tag) { downcast(device).m_voodoo_tag = tag; } + + DECLARE_READ32_MEMBER( read ); + DECLARE_WRITE32_MEMBER( write ); + DECLARE_WRITE_LINE_MEMBER( set_reg ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset() { } + virtual void device_post_load() { } + virtual void device_clock_changed() { } + +private: + + UINT32 reg_r(int reg); + void reg_w(int reg, UINT32 data); + + /* i/o lines */ + + int m_reg_set; // 1 = access reg / 0 = access ram + + const char *m_voodoo_tag; + device_t *m_voodoo; + + UINT32 m_reg[256]; + UINT32 m_ram[32768]; +}; + + +// device type definition +extern const device_type K033906; + +#endif /* __K033906_H__ */ diff --git a/src/devices/machine/k053252.c b/src/devices/machine/k053252.c new file mode 100644 index 00000000000..1cea029d38d --- /dev/null +++ b/src/devices/machine/k053252.c @@ -0,0 +1,233 @@ +// license:LGPL-2.1+ +// copyright-holders:Angelo Salese +/*************************************************************************************************************************** + + Konami 053252 chip emulation, codenamed "CCU" + + device emulation by Angelo Salese, based off notes by Olivier Galibert + +============================================================================================================================ + +left res = current in game, right res = computed + +hexion: 02 FF 00 4D 00 73 00 00 01 1F 05 0E B7 7C 00 00 512x256 ~ 512x256 <- writes to e and f regs, in an irq ack fashion +overdriv: 01 7F 00 22 00 0D 00 03 01 07 10 0F 73 00 00 00 304x256 ~ 305x224 +esckids: 01 7F 00 12 00 0D 00 01 01 07 08 07 73 00 00 00 304x224 ~ 321x240 +rollerg: 01 7F 00 23 00 1D 02 00 01 07 10 0F 73 00 02 00 288x224 ~ 288x224 <- writes to 6 and e regs, in an irq ack fashion +gaiapols: 01 FB 00 19 00 37 00 00 01 06 10 0E 75 00 D1 00 376x224 ~ 380x224 +mmaulers: 01 7F 00 19 00 27 00 00 01 07 10 0F 73 00 00 00 288x224 ~ 288x224 +mystwarr: 01 7F 00 12 00 2E 00 00 01 07 11 0E 73 00 00 00 288x224 ~ 288x224 +metamrph: 01 7F 00 11 00 27 01 00 01 07 10 0F 74 00 00 00 288x224 ~ 288x224 +viostorm: 01 FF 00 16 00 39 00 00 01 07 11 0E 75 00 00 00 384x224 ~ 385x224 +mtlchamp: 01 FF 00 21 00 37 00 00 01 07 11 0E 74 00 00 00 384x224 ~ 384x224 +dbz: 01 FF 00 21 00 37 00 00 01 20 0C 0E 54 00 00 00 384x256 ~ 384x256 +dbz2: 01 FF 00 21 00 37 00 00 01 20 0C 0E 54 00 00 00 384x256 ~ 384x256 +xexex: 01 FF 00 21 00 37 01 00 00 20 0C 0E 54 00 00 00 384x256 ~ 384x256 (*) +(all konamigx, cowboys of moo mesa, run & gun, dj main) + +(*) hcount total 512 (0x200), hdisp 384 (0x180), vcount total 289 (0x121), vdisp 256 (0x100) + + Definitions from GX, look similar, all values big-endian, write-only: + + 0-1: bits 9-0: HC - Total horizontal count (-1) Hres ~ (HC+1) - HFP - HBP - 8*(HSW+1) + 2-3: bits 8-0: HFP - HBlank front porch + 4-5: bits 8-0: HBP - HBlank back porch + 6 : bits 7-0: INT1EN + 7 : bits 7-0: INT2EN + 8-9: bits 8-0: VC - Total vertical count (-1) Vres ~ (VC+1) - VFP - (VBP+1) - (VSW+1) + a : bits 7-0: VFP - VBlank front porch + b : bits 7-0: VBP - VBlank back porch (-1) (?) + c : bits 7-4: VSW - V-Sync Width + c : bits 3-0: HSW - H-Sync Width + d : bits 7-0: INT-TIME + e : bits 7-0: INT1ACK + f : bits 7-0: INT2ACK + + Read-only: + e-f: bits 8-0: VCT + +TODO: +- xexex sets up 0x20 as the VC? default value? +- xexex layers are offsetted if you try to use the CCU +- according to p.14-15 both HBP and VBP have +1 added, but to get correct visible areas you have to add it only to VBP +- understand how to interpret the back / front porch values, and remove the offset x/y hack +- dual screen support (for Konami GX types 3/4) +- viostorm and dbz reads the VCT port, but their usage is a side effect to send an irq ack thru the same port: + i.e. first one uses move.b $26001d.l, $26001d.l, second one clr.b + +***************************************************************************************************************************/ + + +#include "emu.h" +#include "k053252.h" + + +const device_type K053252 = &device_creator; + +k053252_device::k053252_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, K053252, "K053252 Timing/Interrupt", tag, owner, clock, "k053252", __FILE__), + device_video_interface(mconfig, *this), + m_int1_en_cb(*this), + m_int2_en_cb(*this), + m_int1_ack_cb(*this), + m_int2_ack_cb(*this), + //m_int_time_cb(*this), + m_offsx(0), + m_offsy(0) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void k053252_device::device_start() +{ + m_int1_en_cb.resolve_safe(); + m_int2_en_cb.resolve_safe(); + m_int1_ack_cb.resolve_safe(); + m_int2_ack_cb.resolve_safe(); + //m_int_time_cb.resolve_safe(); + + save_item(NAME(m_regs)); + save_item(NAME(m_hc)); + save_item(NAME(m_hfp)); + save_item(NAME(m_hbp)); + save_item(NAME(m_vc)); + save_item(NAME(m_vfp)); + save_item(NAME(m_vbp)); + save_item(NAME(m_vsw)); + save_item(NAME(m_hsw)); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void k053252_device::device_reset() +{ + int i; + + for (i = 0; i < 16; i++) + m_regs[i] = 0; + + m_regs[0x08] = 1; // Xexex apparently does a wrong assignment for VC (sets up the INT enable register instead) + + m_hc=0; + m_hfp=0; + m_hbp=0; + m_vc=0; + m_vfp=0; + m_vbp=0; + m_vsw=0; + m_hsw=0; +} + + +/***************************************************************************** + DEVICE HANDLERS +*****************************************************************************/ + +READ8_MEMBER( k053252_device::read ) +{ + //TODO: debugger_access() + switch(offset) + { + /* VCT read-back (TODO: values not extensively tested) */ + case 0x0e: + return (m_screen->vpos() >> 8) & 1; + case 0x0f: + return m_screen->vpos() & 0xff; + default: + //popmessage("Warning: k053252 read %02x, contact MAMEdev",offset); + break; + } + + return m_regs[offset]; +} + +void k053252_device::res_change() +{ + if(m_hc && m_vc && + m_hbp && m_hfp && + m_vbp && m_vfp && + m_hsw && m_vsw) //safety checks + { + rectangle visarea; + //(HC+1) - HFP - HBP - 8*(HSW+1) + //VC - VFP - VBP - (VSW+1) + attoseconds_t refresh = HZ_TO_ATTOSECONDS(clock()) * (m_hc) * m_vc; + + //printf("H %d %d %d %d\n",m_hc,m_hfp,m_hbp,m_hsw); + //printf("V %d %d %d %d\n",m_vc,m_vfp,m_vbp,m_vsw); + + visarea.min_x = m_offsx; + visarea.min_y = m_offsy; + visarea.max_x = m_offsx + m_hc - m_hfp - m_hbp - 8*(m_hsw) - 1; + visarea.max_y = m_offsy + m_vc - m_vfp - m_vbp - (m_vsw) - 1; + + m_screen->configure(m_hc, m_vc, visarea, refresh); + } +} + +WRITE8_MEMBER( k053252_device::write ) +{ + m_regs[offset] = data; + + switch(offset) + { + case 0x00: + case 0x01: + m_hc = (m_regs[1]&0xff); + m_hc |= ((m_regs[0]&0x03)<<8); + m_hc++; + logerror("%d (%04x) HC set\n",m_hc,m_hc); + res_change(); + break; + case 0x02: + case 0x03: + m_hfp = (m_regs[3]&0xff); + m_hfp |= ((m_regs[2]&0x01)<<8); + logerror("%d (%04x) HFP set\n",m_hfp,m_hfp); + res_change(); + break; + case 0x04: + case 0x05: + m_hbp = (m_regs[5]&0xff); + m_hbp |= ((m_regs[4]&0x01)<<8); + logerror("%d (%04x) HBP set\n",m_hbp,m_hbp); + res_change(); + break; + case 0x06: m_int1_en_cb(data); break; + case 0x07: m_int2_en_cb(data); break; + case 0x08: + case 0x09: + m_vc = (m_regs[9]&0xff); + m_vc |= ((m_regs[8]&0x01)<<8); + m_vc++; + logerror("%d (%04x) VC set\n",m_vc,m_vc); + res_change(); + break; + case 0x0a: + m_vfp = (m_regs[0x0a]&0xff); + logerror("%d (%04x) VFP set\n",m_vfp,m_vfp); + res_change(); + break; + case 0x0b: + m_vbp = (m_regs[0x0b]&0xff); + m_vbp++; + logerror("%d (%04x) VBP set\n",m_vbp,m_vbp); + res_change(); + break; + case 0x0c: + m_vsw = ((m_regs[0x0c]&0xf0) >> 4) + 1; + m_hsw = ((m_regs[0x0c]&0x0f) >> 0) + 1; + logerror("%02x VSW / %02x HSW set\n",m_vsw,m_hsw); + res_change(); + break; + //case 0x0d: m_int_time(data); break; + case 0x0e: m_int1_ack_cb(1); break; + case 0x0f: m_int2_ack_cb(1); break; + } +} diff --git a/src/devices/machine/k053252.h b/src/devices/machine/k053252.h new file mode 100644 index 00000000000..79bfe9fa7a4 --- /dev/null +++ b/src/devices/machine/k053252.h @@ -0,0 +1,73 @@ +// license:LGPL-2.1+ +// copyright-holders:Angelo Salese +/** Konami 053252 **/ +/* CRT and interrupt control unit */ +#pragma once + +#ifndef __K053252_H__ +#define __K053252_H__ + + +#define MCFG_K053252_INT1_EN_CB(_devcb) \ + devcb = &k053252_device::set_int1_en_callback(*device, DEVCB_##_devcb); + +#define MCFG_K053252_INT2_EN_CB(_devcb) \ + devcb = &k053252_device::set_int2_en_callback(*device, DEVCB_##_devcb); + +#define MCFG_K053252_INT1_ACK_CB(_devcb) \ + devcb = &k053252_device::set_int1_ack_callback(*device, DEVCB_##_devcb); + +#define MCFG_K053252_INT2_ACK_CB(_devcb) \ + devcb = &k053252_device::set_int2_ack_callback(*device, DEVCB_##_devcb); + +/*#define MCFG_K053252_INT_TIME_CB(_devcb) \ + devcb = &k053252_device::set_int_time_callback(*device, DEVCB_##_devcb); */ + +#define MCFG_K053252_OFFSETS(_offsx, _offsy) \ + k053252_device::set_offsets(*device, _offsx, _offsy); + + +class k053252_device : public device_t, + public device_video_interface +{ +public: + k053252_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + ~k053252_device() {} + + template static devcb_base &set_int1_en_callback(device_t &device, _Object object) { return downcast(device).m_int1_en_cb.set_callback(object); } + template static devcb_base &set_int2_en_callback(device_t &device, _Object object) { return downcast(device).m_int2_en_cb.set_callback(object); } + template static devcb_base &set_int1_ack_callback(device_t &device, _Object object) { return downcast(device).m_int1_ack_cb.set_callback(object); } + template static devcb_base &set_int2_ack_callback(device_t &device, _Object object) { return downcast(device).m_int2_ack_cb.set_callback(object); } + //template static devcb_base &set_int_time_callback(device_t &device, _Object object) { return downcast(device).m_int_time_cb.set_callback(object); } + static void set_offsets(device_t &device, int offsx, int offsy) { downcast(device).m_offsx = offsx; downcast(device).m_offsy = offsy;} + + DECLARE_READ8_MEMBER( read ); // CCU registers + DECLARE_WRITE8_MEMBER( write ); + + void res_change(); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + private: + // internal state + UINT8 m_regs[16]; + UINT16 m_hc,m_hfp,m_hbp; + UINT16 m_vc,m_vfp,m_vbp; + UINT8 m_vsw,m_hsw; + + devcb_write_line m_int1_en_cb; + devcb_write_line m_int2_en_cb; + devcb_write_line m_int1_ack_cb; + devcb_write_line m_int2_ack_cb; +// devcb_write8 m_int_time_cb; + int m_offsx; + int m_offsy; +}; + +extern const device_type K053252; + + +#endif /* __K033906_H__ */ diff --git a/src/devices/machine/k056230.c b/src/devices/machine/k056230.c new file mode 100644 index 00000000000..8d750b66a8a --- /dev/null +++ b/src/devices/machine/k056230.c @@ -0,0 +1,112 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*************************************************************************** + + Konami IC 056230 (LANC) + +***************************************************************************/ + +#include "emu.h" +#include "k056230.h" + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +// device type definition +const device_type K056230 = &device_creator; + +//------------------------------------------------- +// k056230_device - constructor +//------------------------------------------------- + +k056230_device::k056230_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, K056230, "K056230 LANC", tag, owner, clock, "k056230", __FILE__), + m_is_thunderh(0), + m_cpu(*this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void k056230_device::device_start() +{ + save_item(NAME(m_ram)); +} + + +READ8_MEMBER(k056230_device::read) +{ + switch (offset) + { + case 0: // Status register + { + return 0x08; + } + } + +// osd_printf_debug("k056230_r: %d at %08X\n", offset, space.device().safe_pc()); + + return 0; +} + +TIMER_CALLBACK( k056230_device::network_irq_clear_callback ) +{ + reinterpret_cast(ptr)->network_irq_clear(); +} + +void k056230_device::network_irq_clear() +{ + if (m_cpu) + m_cpu->set_input_line(INPUT_LINE_IRQ2, CLEAR_LINE); +} + + +WRITE8_MEMBER(k056230_device::write) +{ + switch(offset) + { + case 0: // Mode register + { + break; + } + case 1: // Control register + { + if(data & 0x20) + { + // Thunder Hurricane breaks otherwise... + if (!m_is_thunderh) + { + if (m_cpu) + m_cpu->set_input_line(INPUT_LINE_IRQ2, ASSERT_LINE); + + machine().scheduler().timer_set(attotime::from_usec(10), FUNC(network_irq_clear_callback), 0, (void*)this); + } + } +// else +// m_cpu->set_input_line(INPUT_LINE_IRQ2, CLEAR_LINE); + break; + } + case 2: // Sub ID register + { + break; + } + } +// osd_printf_debug("k056230_w: %d, %02X at %08X\n", offset, data, space.device().safe_pc()); +} + +READ32_MEMBER(k056230_device::lanc_ram_r) +{ + //osd_printf_debug("LANC_RAM_r: %08X, %08X at %08X\n", offset, mem_mask, space.device().safe_pc()); + return m_ram[offset & 0x7ff]; +} + +WRITE32_MEMBER(k056230_device::lanc_ram_w) +{ + //osd_printf_debug("LANC_RAM_w: %08X, %08X, %08X at %08X\n", data, offset, mem_mask, space.device().safe_pc()); + COMBINE_DATA(m_ram + (offset & 0x7ff)); +} diff --git a/src/devices/machine/k056230.h b/src/devices/machine/k056230.h new file mode 100644 index 00000000000..d8ec4a70ebc --- /dev/null +++ b/src/devices/machine/k056230.h @@ -0,0 +1,72 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*************************************************************************** + + Konami 056230 + +***************************************************************************/ + +#pragma once + +#ifndef __K056230_H__ +#define __K056230_H__ + +#include "emu.h" + + + +/*************************************************************************** + DEVICE CONFIGURATION MACROS +***************************************************************************/ + +#define MCFG_K056230_CPU(_tag) \ + k056230_device::set_cpu_tag(*device, "^" _tag); + +#define MCFG_K056230_HACK(_region) \ + k056230_device::set_thunderh_hack(*device, _region); + + +/*************************************************************************** + TYPE DEFINITIONS +***************************************************************************/ + +// ======================> k056230_device + +class k056230_device : public device_t +{ +public: + // construction/destruction + k056230_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + static void set_cpu_tag(device_t &device, const char *tag) { downcast(device).m_cpu.set_tag(tag); } + static void set_thunderh_hack(device_t &device, int thunderh) { downcast(device).m_is_thunderh = thunderh; } + + DECLARE_READ32_MEMBER(lanc_ram_r); + DECLARE_WRITE32_MEMBER(lanc_ram_w); + + DECLARE_READ8_MEMBER(read); + DECLARE_WRITE8_MEMBER(write); + + static TIMER_CALLBACK( network_irq_clear_callback ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset() { } + virtual void device_post_load() { } + virtual void device_clock_changed() { } + +private: + + void network_irq_clear(); + int m_is_thunderh; + + required_device m_cpu; + UINT32 m_ram[0x2000]; +}; + + +// device type definition +extern const device_type K056230; + +#endif /* __K056230_H__ */ diff --git a/src/devices/machine/kb3600.c b/src/devices/machine/kb3600.c new file mode 100644 index 00000000000..f83ba9c46d8 --- /dev/null +++ b/src/devices/machine/kb3600.c @@ -0,0 +1,201 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/********************************************************************** + + General Instruments AY-5-3600 Keyboard Encoder emulation + +*********************************************************************/ + +/* + + TODO: + + - scan timer clock frequency + - more accurate emulation of real chip + +*/ + +#include "kb3600.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define LOG 0 + + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +// devices +const device_type AY3600 = &device_creator; + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// ay3600_device - constructor +//------------------------------------------------- + +ay3600_device::ay3600_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, AY3600, "AY-5-3600", tag, owner, clock, "ay3600", __FILE__), + m_read_x0(*this), + m_read_x1(*this), + m_read_x2(*this), + m_read_x3(*this), + m_read_x4(*this), + m_read_x5(*this), + m_read_x6(*this), + m_read_x7(*this), + m_read_x8(*this), + m_read_shift(*this), + m_read_control(*this), + m_write_data_ready(*this), + m_write_ako(*this) +{ + for (int i = 0; i < 9; i++) + { + m_x_mask[i] = 0; + } +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void ay3600_device::device_start() +{ + // resolve callbacks + m_read_x0.resolve_safe(0); + m_read_x1.resolve_safe(0); + m_read_x2.resolve_safe(0); + m_read_x3.resolve_safe(0); + m_read_x4.resolve_safe(0); + m_read_x5.resolve_safe(0); + m_read_x6.resolve_safe(0); + m_read_x7.resolve_safe(0); + m_read_x8.resolve_safe(0); + m_read_shift.resolve_safe(0); + m_read_control.resolve_safe(0); + m_write_data_ready.resolve_safe(); + m_write_ako.resolve_safe(); + + // allocate timers + m_scan_timer = timer_alloc(); + m_scan_timer->adjust(attotime::from_hz(60), 0, attotime::from_hz(60)); + + m_ako = 0; + + // state saving + save_item(NAME(m_b)); + save_item(NAME(m_ako)); + save_item(NAME(m_x_mask)); +} + + +//------------------------------------------------- +// device_start - device-specific reset +//------------------------------------------------- + +void ay3600_device::device_reset() +{ +} + +//------------------------------------------------- +// device_timer - handler timer events +//------------------------------------------------- + +void ay3600_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + int ako = 0; + + for (int x = 0; x < 9; x++) + { + UINT16 data = 0; + + switch(x) + { + case 0: data = m_read_x0(); break; + case 1: data = m_read_x1(); break; + case 2: data = m_read_x2(); break; + case 3: data = m_read_x3(); break; + case 4: data = m_read_x4(); break; + case 5: data = m_read_x5(); break; + case 6: data = m_read_x6(); break; + case 7: data = m_read_x7(); break; + case 8: data = m_read_x8(); break; + } + + for (int y = 0; y < 10; y++) + { + int b = (x * 10) + y; + + if (b > 63) + { + b -= 64; + b = 0x100 | b; + } + + b |= (m_read_shift() << 6); + b |= (m_read_control() << 7); + + if (BIT(data, y)) + { + ako = 1; + + if (!(m_x_mask[x] & (1 << y))) + { + m_x_mask[x] |= (1 << y); + + if (m_b != b) + { + m_b = b; + + m_write_data_ready(1); + + if (ako != m_ako) + { + m_write_ako(ako); + m_ako = ako; + } + return; + } + } + } + else // key released, unmark it from the "down" info + { + m_x_mask[x] &= ~(1 << y); + } + } + } + + if (!ako) + { + m_b = -1; + } + + if (ako != m_ako) + { + m_write_ako(ako); + m_ako = ako; + } +} + + +//------------------------------------------------- +// b_r - +//------------------------------------------------- + +UINT16 ay3600_device::b_r() +{ + UINT16 data = m_b; + + m_write_data_ready(0); + + return data; +} diff --git a/src/devices/machine/kb3600.h b/src/devices/machine/kb3600.h new file mode 100644 index 00000000000..57a42c906fb --- /dev/null +++ b/src/devices/machine/kb3600.h @@ -0,0 +1,151 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/********************************************************************** + + General Instruments AY-5-3600 Keyboard Encoder emulation + +********************************************************************** + _____ _____ + 1 |* \_/ | 40 X0 + 2 | | 39 X1 + 3 | | 38 X2 + 4 | | 37 X3 + 5 | | 36 X4 + B9 6 | | 35 X5 + B8 7 | | 34 X6 + B7 8 | | 33 X7 + B6 9 | | 32 X8 + B5 10 | AY-5-3600 | 31 DELAY NODE + B4 11 | | 30 Vcc + B3 12 | | 29 SHIFT + B2 13 | | 28 CONTROL + B1 14 | | 27 Vgg + Vdd 15 | | 26 Y9 + DATA READY 16 | | 25 Y8 + Y0 17 | | 24 Y7 + Y1 18 | | 23 Y6 + Y2 19 | | 22 Y5 + Y3 20 |_____________| 21 Y4 + + _____ _____ + Vcc 1 |* \_/ | 40 Vss + B9 2 | | 39 Vgg + B8 3 | | 38 _STCL? + B7 4 | | 37 _MCLR + TEST 5 | | 36 OSC + B6 6 | | 35 CLK OUT + B5 7 | | 34 X7 + B4 8 | | 33 X6 + B3 9 | | 32 X5 + B2 10 | AY-5-3600 | 31 X4 + B1 11 | PRO 002 | 30 X3 + X8 12 | | 29 X2 + AKO 13 | | 28 X1 + CTRL 14 | | 27 X0 + SHIFT 15 | | 26 Y9 + DATA READY 16 | | 25 Y8 + Y0 17 | | 24 Y7 + Y1 18 | | 23 Y6 + Y2 19 | | 22 Y5 + Y3 20 |_____________| 21 Y4 + +**********************************************************************/ + +#pragma once + +#ifndef __AY3600__ +#define __AY3600__ + +#include "emu.h" + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_AY3600_MATRIX_X0(_cb) \ + devcb = &ay3600_device::set_x0_cb(*device, DEVCB_##_cb); +#define MCFG_AY3600_MATRIX_X1(_cb) \ + devcb = &ay3600_device::set_x1_cb(*device, DEVCB_##_cb); +#define MCFG_AY3600_MATRIX_X2(_cb) \ + devcb = &ay3600_device::set_x2_cb(*device, DEVCB_##_cb); +#define MCFG_AY3600_MATRIX_X3(_cb) \ + devcb = &ay3600_device::set_x3_cb(*device, DEVCB_##_cb); +#define MCFG_AY3600_MATRIX_X4(_cb) \ + devcb = &ay3600_device::set_x4_cb(*device, DEVCB_##_cb); +#define MCFG_AY3600_MATRIX_X5(_cb) \ + devcb = &ay3600_device::set_x5_cb(*device, DEVCB_##_cb); +#define MCFG_AY3600_MATRIX_X6(_cb) \ + devcb = &ay3600_device::set_x6_cb(*device, DEVCB_##_cb); +#define MCFG_AY3600_MATRIX_X7(_cb) \ + devcb = &ay3600_device::set_x7_cb(*device, DEVCB_##_cb); +#define MCFG_AY3600_MATRIX_X8(_cb) \ + devcb = &ay3600_device::set_x8_cb(*device, DEVCB_##_cb); +#define MCFG_AY3600_SHIFT_CB(_cb) \ + devcb = &ay3600_device::set_shift_cb(*device, DEVCB_##_cb); +#define MCFG_AY3600_CONTROL_CB(_cb) \ + devcb = &ay3600_device::set_control_cb(*device, DEVCB_##_cb); +#define MCFG_AY3600_DATA_READY_CB(_cb) \ + devcb = &ay3600_device::set_data_ready_cb(*device, DEVCB_##_cb); +#define MCFG_AY3600_AKO_CB(_cb) \ + devcb = &ay3600_device::set_ako_cb(*device, DEVCB_##_cb); + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> ay3600_device + +class ay3600_device : public device_t +{ +public: + // construction/destruction + ay3600_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // public interface + UINT16 b_r(); + + template static devcb_base &set_x0_cb(device_t &device, _Object rd) { return downcast(device).m_read_x0.set_callback(rd); } + template static devcb_base &set_x1_cb(device_t &device, _Object rd) { return downcast(device).m_read_x1.set_callback(rd); } + template static devcb_base &set_x2_cb(device_t &device, _Object rd) { return downcast(device).m_read_x2.set_callback(rd); } + template static devcb_base &set_x3_cb(device_t &device, _Object rd) { return downcast(device).m_read_x3.set_callback(rd); } + template static devcb_base &set_x4_cb(device_t &device, _Object rd) { return downcast(device).m_read_x4.set_callback(rd); } + template static devcb_base &set_x5_cb(device_t &device, _Object rd) { return downcast(device).m_read_x5.set_callback(rd); } + template static devcb_base &set_x6_cb(device_t &device, _Object rd) { return downcast(device).m_read_x6.set_callback(rd); } + template static devcb_base &set_x7_cb(device_t &device, _Object rd) { return downcast(device).m_read_x7.set_callback(rd); } + template static devcb_base &set_x8_cb(device_t &device, _Object rd) { return downcast(device).m_read_x8.set_callback(rd); } + template static devcb_base &set_shift_cb(device_t &device, _Object rd) { return downcast(device).m_read_shift.set_callback(rd); } + template static devcb_base &set_control_cb(device_t &device, _Object rd) { return downcast(device).m_read_control.set_callback(rd); } + template static devcb_base &set_data_ready_cb(device_t &device, _Object wr) { return downcast(device).m_write_data_ready.set_callback(wr); } + template static devcb_base &set_ako_cb(device_t &device, _Object wr) { return downcast(device).m_write_ako.set_callback(wr); } + + devcb_read16 m_read_x0, m_read_x1, m_read_x2, m_read_x3, m_read_x4, m_read_x5, m_read_x6, m_read_x7, m_read_x8; + devcb_read_line m_read_shift, m_read_control; + devcb_write_line m_write_data_ready, m_write_ako; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + +private: + static const int MAX_KEYS_DOWN = 4; + + int m_b; // output buffer + int m_ako; // any key down + + int m_x_mask[9]; // mask of what keys are down + + // timers + emu_timer *m_scan_timer; // keyboard scan timer +}; + + +// device type definition +extern const device_type AY3600; + + + +#endif diff --git a/src/devices/machine/keyboard.c b/src/devices/machine/keyboard.c new file mode 100644 index 00000000000..03d538f2a3e --- /dev/null +++ b/src/devices/machine/keyboard.c @@ -0,0 +1,395 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/*************************************************************************** +Generic ASCII Keyboard + +Use GENERIC_KEYBOARD to attach as a generic ascii input device in +cases where either the driver isn't developed enough yet; or for testing; +or for the case of a computer with an inbuilt (not serial) ascii keyboard. + +Example of usage in a driver. + +In MACHINE_CONFIG + + MCFG_DEVICE_ADD(KEYBOARD_TAG, GENERIC_KEYBOARD, 0) + MCFG_GENERIC_KEYBOARD_CB(WRITE8(xxx_state, kbd_put)) + +In the code: + +WRITE8_MEMBER( xxx_state::kbd_put ) +{ + (code to capture the key as it is pressed) + (if your machine uses function keys, add your conversion code here) +} + +***************************************************************************/ + +#include "machine/keyboard.h" + +/*************************************************************************** + IMPLEMENTATION +***************************************************************************/ + + +generic_keyboard_device::generic_keyboard_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + m_io_kbd0(*this, "TERM_LINE0"), + m_io_kbd1(*this, "TERM_LINE1"), + m_io_kbd2(*this, "TERM_LINE2"), + m_io_kbd3(*this, "TERM_LINE3"), + m_io_kbd4(*this, "TERM_LINE4"), + m_io_kbd5(*this, "TERM_LINE5"), + m_io_kbd6(*this, "TERM_LINE6"), + m_io_kbd7(*this, "TERM_LINE7"), + m_io_kbd8(*this, "TERM_LINE8"), + m_io_kbd9(*this, "TERM_LINE9"), + m_io_kbdc(*this, "TERM_LINEC"), + m_keyboard_cb(*this) +{ +} + +generic_keyboard_device::generic_keyboard_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, GENERIC_KEYBOARD, "Generic Keyboard", tag, owner, clock, "generic_keyboard", __FILE__), + m_io_kbd0(*this, "TERM_LINE0"), + m_io_kbd1(*this, "TERM_LINE1"), + m_io_kbd2(*this, "TERM_LINE2"), + m_io_kbd3(*this, "TERM_LINE3"), + m_io_kbd4(*this, "TERM_LINE4"), + m_io_kbd5(*this, "TERM_LINE5"), + m_io_kbd6(*this, "TERM_LINE6"), + m_io_kbd7(*this, "TERM_LINE7"), + m_io_kbd8(*this, "TERM_LINE8"), + m_io_kbd9(*this, "TERM_LINE9"), + m_io_kbdc(*this, "TERM_LINEC"), + m_keyboard_cb(*this) +{ +} + + +UINT8 generic_keyboard_device::row_number(UINT8 code) +{ + if BIT(code,0) return 0; + if BIT(code,1) return 1; + if BIT(code,2) return 2; + if BIT(code,3) return 3; + if BIT(code,4) return 4; + if BIT(code,5) return 5; + if BIT(code,6) return 6; + if BIT(code,7) return 7; + return 0; +} + +UINT8 generic_keyboard_device::keyboard_handler(UINT8 last_code, UINT8 *scan_line) +{ + int i; + UINT8 code = 0; + UINT8 key_code = 0; + UINT8 retVal = 0; + UINT8 shift = BIT(m_io_kbdc->read(), 1); + UINT8 caps = BIT(m_io_kbdc->read(), 2); + UINT8 ctrl = BIT(m_io_kbdc->read(), 0); + i = *scan_line; + { + if (i == 0) code = m_io_kbd0->read(); + else + if (i == 1) code = m_io_kbd1->read(); + else + if (i == 2) code = m_io_kbd2->read(); + else + if (i == 3) code = m_io_kbd3->read(); + else + if (i == 4) code = m_io_kbd4->read(); + else + if (i == 5) code = m_io_kbd5->read(); + else + if (i == 6) code = m_io_kbd6->read(); + else + if (i == 7) code = m_io_kbd7->read(); + else + if (i == 8) code = m_io_kbd8->read(); + else + if (i == 9) code = m_io_kbd9->read(); + + if (code != 0) + { + if (i==0 && shift==0) { + key_code = 0x30 + row_number(code) + 8*i; // for numbers and some signs + } + if (i==0 && shift==1) { + key_code = 0x20 + row_number(code) + 8*i; // for shifted numbers + } + if (i==1 && shift==0) { + if (row_number(code) < 4) { + key_code = 0x30 + row_number(code) + 8*i; // for numbers and some signs + } else { + key_code = 0x20 + row_number(code) + 8*i; // for numbers and some signs + } + } + if (i==1 && shift==1) { + if (row_number(code) < 4) { + key_code = 0x20 + row_number(code) + 8*i; // for numbers and some signs + } else { + key_code = 0x30 + row_number(code) + 8*i; // for numbers and some signs + } + } + if (i>=2 && i<=4 && (shift ^ caps)==0 && ctrl==0) { + key_code = 0x60 + row_number(code) + (i-2)*8; // for small letters + } + if (i>=2 && i<=4 && (shift ^ caps)==1 && ctrl==0) { + key_code = 0x40 + row_number(code) + (i-2)*8; // for big letters + } + if (i>=2 && i<=5 && ctrl==1) { + key_code = 0x00 + row_number(code) + (i-2)*8; // for CTRL + letters + } + if (i==5 && shift==1 && ctrl==0) { + if (row_number(code)<7) { + if (row_number(code)<3) { + key_code = (caps ? 0x60 : 0x40) + row_number(code) + (i-2)*8; // for big letters + } else { + key_code = 0x60 + row_number(code) + (i-2)*8; // for upper symbols letters + } + } else { + key_code = 0x40 + row_number(code) + (i-2)*8; // for DEL it is switched + } + } + if (i==5 && shift==0 && ctrl==0) { + if (row_number(code)<7) { + if (row_number(code)<3) { + key_code = (caps ? 0x40 : 0x60) + row_number(code) + (i-2)*8; // for small letters + } else { + key_code = 0x40 + row_number(code) + (i-2)*8; // for lower symbols letters + } + } else { + key_code = 0x60 + row_number(code) + (i-2)*8; // for DEL it is switched + } + } + + if (i==6) { + switch(row_number(code)) + { +/* case 0: key_code = 0x11; break; + case 1: key_code = 0x12; break; + case 2: key_code = 0x13; break; + case 3: key_code = 0x14; break;*/ + case 4: key_code = 0x20; break; // Space + case 5: key_code = 0x0A; break; // LineFeed + case 6: key_code = 0x09; break; // TAB + case 7: key_code = 0x0D; break; // Enter + } + } + if (i==7) + { + switch(row_number(code)) + { + case 0: key_code = 0x1B; break; // Escape + case 1: key_code = 0x08; break; // Backspace + } + } + else + if (i==8) + { + key_code = row_number(code)+0x81; + if (ctrl) key_code+=0x10; + if (shift) key_code+=0x20; + } + else + if (i==9) + { + key_code = row_number(code)+0x89; + if (ctrl) key_code+=0x10; + if (shift) key_code+=0x20; + } + + retVal = key_code; + } + else + { + *scan_line += 1; + if (*scan_line==10) + *scan_line = 0; + } + } + return retVal; +} + +void generic_keyboard_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + UINT8 new_code; + new_code = keyboard_handler(m_last_code, &m_scan_line); + if ((m_last_code != new_code) && (new_code)) + send_key(new_code); + m_last_code = new_code; +} + +/*************************************************************************** + VIDEO HARDWARE +***************************************************************************/ + +static MACHINE_CONFIG_FRAGMENT( generic_keyboard ) +MACHINE_CONFIG_END + +machine_config_constructor generic_keyboard_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME(generic_keyboard); +} + +void generic_keyboard_device::device_start() +{ + m_keyboard_cb.resolve_safe(); + m_timer = timer_alloc(); + save_item(NAME(m_last_code)); + save_item(NAME(m_scan_line)); +} + +void generic_keyboard_device::device_reset() +{ + m_last_code = 0; + m_scan_line = 0; + m_timer->adjust(attotime::from_hz(2400), 0, attotime::from_hz(2400)); +} + +/* +Char Dec Oct Hex | Char Dec Oct Hex | Char Dec Oct Hex | Char Dec Oct Hex +------------------------------------------------------------------------------------- +(nul) 0 0000 0x00 | (sp) 32 0040 0x20 | @ 64 0100 0x40 | ` 96 0140 0x60 +(soh) 1 0001 0x01 | ! 33 0041 0x21 | A 65 0101 0x41 | a 97 0141 0x61 +(stx) 2 0002 0x02 | " 34 0042 0x22 | B 66 0102 0x42 | b 98 0142 0x62 +(etx) 3 0003 0x03 | # 35 0043 0x23 | C 67 0103 0x43 | c 99 0143 0x63 +(eot) 4 0004 0x04 | $ 36 0044 0x24 | D 68 0104 0x44 | d 100 0144 0x64 +(enq) 5 0005 0x05 | % 37 0045 0x25 | E 69 0105 0x45 | e 101 0145 0x65 +(ack) 6 0006 0x06 | & 38 0046 0x26 | F 70 0106 0x46 | f 102 0146 0x66 +(bel) 7 0007 0x07 | ' 39 0047 0x27 | G 71 0107 0x47 | g 103 0147 0x67 +(bs) 8 0010 0x08 | ( 40 0050 0x28 | H 72 0110 0x48 | h 104 0150 0x68 +(ht) 9 0011 0x09 | ) 41 0051 0x29 | I 73 0111 0x49 | i 105 0151 0x69 +(nl) 10 0012 0x0a | * 42 0052 0x2a | J 74 0112 0x4a | j 106 0152 0x6a +(vt) 11 0013 0x0b | + 43 0053 0x2b | K 75 0113 0x4b | k 107 0153 0x6b +(np) 12 0014 0x0c | , 44 0054 0x2c | L 76 0114 0x4c | l 108 0154 0x6c +(cr) 13 0015 0x0d | - 45 0055 0x2d | M 77 0115 0x4d | m 109 0155 0x6d +(so) 14 0016 0x0e | . 46 0056 0x2e | N 78 0116 0x4e | n 110 0156 0x6e +(si) 15 0017 0x0f | / 47 0057 0x2f | O 79 0117 0x4f | o 111 0157 0x6f +(dle) 16 0020 0x10 | 0 48 0060 0x30 | P 80 0120 0x50 | p 112 0160 0x70 +(dc1) 17 0021 0x11 | 1 49 0061 0x31 | Q 81 0121 0x51 | q 113 0161 0x71 +(dc2) 18 0022 0x12 | 2 50 0062 0x32 | R 82 0122 0x52 | r 114 0162 0x72 +(dc3) 19 0023 0x13 | 3 51 0063 0x33 | S 83 0123 0x53 | s 115 0163 0x73 +(dc4) 20 0024 0x14 | 4 52 0064 0x34 | T 84 0124 0x54 | t 116 0164 0x74 +(nak) 21 0025 0x15 | 5 53 0065 0x35 | U 85 0125 0x55 | u 117 0165 0x75 +(syn) 22 0026 0x16 | 6 54 0066 0x36 | V 86 0126 0x56 | v 118 0166 0x76 +(etb) 23 0027 0x17 | 7 55 0067 0x37 | W 87 0127 0x57 | w 119 0167 0x77 +(can) 24 0030 0x18 | 8 56 0070 0x38 | X 88 0130 0x58 | x 120 0170 0x78 +(em) 25 0031 0x19 | 9 57 0071 0x39 | Y 89 0131 0x59 | y 121 0171 0x79 +(sub) 26 0032 0x1a | : 58 0072 0x3a | Z 90 0132 0x5a | z 122 0172 0x7a +(esc) 27 0033 0x1b | ; 59 0073 0x3b | [ 91 0133 0x5b | { 123 0173 0x7b +(fs) 28 0034 0x1c | < 60 0074 0x3c | \ 92 0134 0x5c | | 124 0174 0x7c +(gs) 29 0035 0x1d | = 61 0075 0x3d | ] 93 0135 0x5d | } 125 0175 0x7d +(rs) 30 0036 0x1e | > 62 0076 0x3e | ^ 94 0136 0x5e | ~ 126 0176 0x7e +(us) 31 0037 0x1f | ? 63 0077 0x3f | _ 95 0137 0x5f | (del) 127 0177 0x7f + +*/ +INPUT_PORTS_START( generic_keyboard ) + PORT_START("TERM_LINEC") + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Ctrl") PORT_CODE(KEYCODE_LCONTROL) PORT_CODE(KEYCODE_RCONTROL) + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Shift") PORT_CODE(KEYCODE_LSHIFT) PORT_CODE(KEYCODE_RSHIFT) PORT_CHAR(UCHAR_SHIFT_1) + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Caps Lock") PORT_CODE(KEYCODE_CAPSLOCK) PORT_TOGGLE PORT_CHAR(UCHAR_MAMEKEY(CAPSLOCK)) + PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_UNUSED) + PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_UNUSED) + PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_UNUSED) + PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_UNUSED) + PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_UNUSED) + + PORT_START("TERM_LINE0") + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_0) PORT_CHAR('0') + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_1) PORT_CHAR('1') PORT_CHAR('!') + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_2) PORT_CHAR('2') PORT_CHAR('"') + PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_3) PORT_CHAR('3') PORT_CHAR('#') + PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_4) PORT_CHAR('4') PORT_CHAR('$') + PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_5) PORT_CHAR('5') PORT_CHAR('%') + PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_6) PORT_CHAR('6') PORT_CHAR('&') + PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_7) PORT_CHAR('7') PORT_CHAR('\'') + + PORT_START("TERM_LINE1") + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_8) PORT_CHAR('8') PORT_CHAR('(') + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_9) PORT_CHAR('9') PORT_CHAR(')') + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_QUOTE) PORT_CHAR(':') PORT_CHAR('*') + PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_COLON) PORT_CHAR(';') PORT_CHAR('+') + PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_COMMA) PORT_CHAR(',') PORT_CHAR('<') + PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_MINUS) PORT_CHAR('-') PORT_CHAR('=') + PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_STOP) PORT_CHAR('.') PORT_CHAR('>') + PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_SLASH) PORT_CHAR('/') PORT_CHAR('?') + + PORT_START("TERM_LINE2") + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_END) PORT_CHAR('`') PORT_CHAR('@') + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_A) PORT_CHAR('a') PORT_CHAR('A') + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_B) PORT_CHAR('b') PORT_CHAR('B') + PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_C) PORT_CHAR('c') PORT_CHAR('C') + PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_D) PORT_CHAR('d') PORT_CHAR('D') + PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_E) PORT_CHAR('e') PORT_CHAR('E') + PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_F) PORT_CHAR('f') PORT_CHAR('F') + PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_G) PORT_CHAR('g') PORT_CHAR('G') + + PORT_START("TERM_LINE3") + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_H) PORT_CHAR('h') PORT_CHAR('H') + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_I) PORT_CHAR('i') PORT_CHAR('I') + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_J) PORT_CHAR('j') PORT_CHAR('J') + PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_K) PORT_CHAR('k') PORT_CHAR('K') + PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_L) PORT_CHAR('l') PORT_CHAR('L') + PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_M) PORT_CHAR('m') PORT_CHAR('M') + PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_N) PORT_CHAR('n') PORT_CHAR('N') + PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_O) PORT_CHAR('o') PORT_CHAR('O') + + PORT_START("TERM_LINE4") + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_P) PORT_CHAR('p') PORT_CHAR('P') + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_Q) PORT_CHAR('q') PORT_CHAR('Q') + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_R) PORT_CHAR('r') PORT_CHAR('R') + PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_S) PORT_CHAR('s') PORT_CHAR('S') + PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_T) PORT_CHAR('t') PORT_CHAR('T') + PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_U) PORT_CHAR('u') PORT_CHAR('U') + PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_V) PORT_CHAR('v') PORT_CHAR('V') + PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_W) PORT_CHAR('w') PORT_CHAR('W') + + PORT_START("TERM_LINE5") + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_X) PORT_CHAR('x') PORT_CHAR('X') + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_Y) PORT_CHAR('y') PORT_CHAR('Y') + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_Z) PORT_CHAR('z') PORT_CHAR('Z') + PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_OPENBRACE) PORT_CHAR('[') PORT_CHAR('{') + PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_BACKSLASH) PORT_CHAR('\\') PORT_CHAR('|') + PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_CLOSEBRACE) PORT_CHAR(']') PORT_CHAR('}') + PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_TILDE) PORT_CHAR('^') PORT_CHAR('~') + PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("DEL") PORT_CODE(KEYCODE_DEL) PORT_CHAR(UCHAR_MAMEKEY(DEL)) + + PORT_START("TERM_LINE6") + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Left") PORT_CODE(KEYCODE_LEFT) PORT_CHAR(UCHAR_MAMEKEY(LEFT)) + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Right") PORT_CODE(KEYCODE_RIGHT) PORT_CHAR(UCHAR_MAMEKEY(RIGHT)) + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Up") PORT_CODE(KEYCODE_UP) PORT_CHAR(UCHAR_MAMEKEY(UP)) + PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Down") PORT_CODE(KEYCODE_DOWN) PORT_CHAR(UCHAR_MAMEKEY(DOWN)) + PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_SPACE) PORT_CHAR(' ') + PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("LF") PORT_CODE(KEYCODE_RALT) PORT_CHAR(10) + PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_TAB) PORT_CHAR(9) + PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_ENTER) PORT_CHAR(13) + + PORT_START("TERM_LINE7") + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Escape") PORT_CODE(KEYCODE_ESC) PORT_CHAR(UCHAR_MAMEKEY(ESC)) + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Backspace") PORT_CODE(KEYCODE_BACKSPACE) PORT_CHAR(8) + + PORT_START("TERM_LINE8") + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F1") PORT_CODE(KEYCODE_F1) PORT_CHAR(UCHAR_MAMEKEY(F1)) + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F2") PORT_CODE(KEYCODE_F2) PORT_CHAR(UCHAR_MAMEKEY(F2)) + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F3") PORT_CODE(KEYCODE_F3) PORT_CHAR(UCHAR_MAMEKEY(F3)) + PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F4") PORT_CODE(KEYCODE_F4) PORT_CHAR(UCHAR_MAMEKEY(F4)) + PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F5") PORT_CODE(KEYCODE_F5) PORT_CHAR(UCHAR_MAMEKEY(F5)) + PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F6") PORT_CODE(KEYCODE_F6) PORT_CHAR(UCHAR_MAMEKEY(F6)) + PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F7") PORT_CODE(KEYCODE_F7) PORT_CHAR(UCHAR_MAMEKEY(F7)) + PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F8") PORT_CODE(KEYCODE_F8) PORT_CHAR(UCHAR_MAMEKEY(F8)) + + PORT_START("TERM_LINE9") + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F9") PORT_CODE(KEYCODE_F9) PORT_CHAR(UCHAR_MAMEKEY(F9)) + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F10") PORT_CODE(KEYCODE_F10) PORT_CHAR(UCHAR_MAMEKEY(F10)) + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F11") PORT_CODE(KEYCODE_F11) PORT_CHAR(UCHAR_MAMEKEY(F11)) + PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F12") PORT_CODE(KEYCODE_F12) PORT_CHAR(UCHAR_MAMEKEY(F12)) +INPUT_PORTS_END + +ioport_constructor generic_keyboard_device::device_input_ports() const +{ + return INPUT_PORTS_NAME(generic_keyboard); +} + +const device_type GENERIC_KEYBOARD = &device_creator; diff --git a/src/devices/machine/keyboard.h b/src/devices/machine/keyboard.h new file mode 100644 index 00000000000..8658cf3f92f --- /dev/null +++ b/src/devices/machine/keyboard.h @@ -0,0 +1,60 @@ +// license:BSD-3-Clause +// copyright-holders:smf +#ifndef __KEYBOARD_H__ +#define __KEYBOARD_H__ + +#include "emu.h" + +/*************************************************************************** + DEVICE CONFIGURATION MACROS +***************************************************************************/ + +#define MCFG_GENERIC_KEYBOARD_CB(_devcb) \ + devcb = &generic_keyboard_device::set_keyboard_callback(*device, DEVCB_##_devcb); + +/*************************************************************************** + FUNCTION PROTOTYPES +***************************************************************************/ + +INPUT_PORTS_EXTERN( generic_keyboard ); + +class generic_keyboard_device : public device_t +{ +public: + generic_keyboard_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + generic_keyboard_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + template static devcb_base &set_keyboard_callback(device_t &device, _Object object) { return downcast(device).m_keyboard_cb.set_callback(object); } + + virtual ioport_constructor device_input_ports() const; + virtual machine_config_constructor device_mconfig_additions() const; +protected: + required_ioport m_io_kbd0; + required_ioport m_io_kbd1; + required_ioport m_io_kbd2; + required_ioport m_io_kbd3; + required_ioport m_io_kbd4; + required_ioport m_io_kbd5; + required_ioport m_io_kbd6; + required_ioport m_io_kbd7; + required_ioport m_io_kbd8; + required_ioport m_io_kbd9; + required_ioport m_io_kbdc; + + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + virtual void send_key(UINT8 code) { m_keyboard_cb((offs_t)0, code); } + emu_timer *m_timer; +private: + virtual UINT8 keyboard_handler(UINT8 last_code, UINT8 *scan_line); + UINT8 row_number(UINT8 code); + UINT8 m_last_code; + UINT8 m_scan_line; + + devcb_write8 m_keyboard_cb; +}; + +extern const device_type GENERIC_KEYBOARD; + +#endif /* __KEYBOARD_H__ */ diff --git a/src/devices/machine/kr2376.c b/src/devices/machine/kr2376.c new file mode 100644 index 00000000000..d818c52ce68 --- /dev/null +++ b/src/devices/machine/kr2376.c @@ -0,0 +1,350 @@ +// license:??? +// copyright-holders:Roberto Lavarone +/********************************************************************** + + SMC KR2376 Keyboard Encoder emulation + +**********************************************************************/ + +#include "emu.h" +#include "kr2376.h" + +static const UINT8 KR2376_KEY_CODES[3][8][11] = +{ + // normal + { + // Y0 Y1 Y2 Y3 Y4 Y5 Y6 Y7 Y8 Y9 Y10 + // NUL SOH STX ETX EOT ENQ ACK BEL DC1 P O X0 + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x11, 0x50, 0x30 }, // X0 + // DLE K L N M NAK SYN ETB CAN EM SUB X1 + { 0x10, 0x4b, 0x4c, 0x4e, 0x4d, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a }, // X1 + // - FS GS RS US < > , SP . _ X2 + { 0x2d, 0x1c, 0x1d, 0x1e, 0x1f, 0x3c, 0x3e, 0x2c, 0x20, 0x2e, 0x5f }, // X2 + // 0 : p _ @ BS [ ] CR LF DEL X3 + { 0x30, 0x3a, 0x70, 0x5f, 0x40, 0x08, 0x5B, 0x5d, 0x0d, 0x0a, 0x7f }, // X3 + { 0x3b, 0x2f, 0x2e, 0x2c, 0x6d, 0x6e, 0x62, 0x76, 0x63, 0x78, 0x7a }, // X4 + { 0x6c, 0x6b, 0x6a, 0x68, 0x67, 0x66, 0x64, 0x73, 0x61, 0x0c, 0x1b }, // X5 + { 0x6f, 0x69, 0x75, 0x79, 0x74, 0x72, 0x65, 0x77, 0x71, 0x09, 0x0b }, // X6 + { 0x39, 0x38, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x5e, 0x5c } // X7 + }, + + // shift + { + // Y0 Y1 Y2 Y3 Y4 Y5 Y6 Y7 Y8 Y9 Y10 + // NUL SOH STX ETX EOT ENQ ACK BEL DC1 @ _ X0 + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x11, 0x40, 0x5f }, // X0 + // DLE [ \ ^ ] NAK SYN ETB CAN EM SUB X1 + { 0x10, 0x5b, 0x5c, 0x5e, 0x5d, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a }, // X1 + // = FS GS RS US < > , SP . _ X2 + { 0x3d, 0x1c, 0x1d, 0x1e, 0x1f, 0x3c, 0x3e, 0x2c, 0x20, 0x2e, 0x5f }, // X2 + // NUL * P DEL ` BS { } CR LF DEL X3 + { 0x00, 0x2a, 0x50, 0x7f, 0x60, 0x08, 0x7b, 0x7d, 0x0d, 0x0a, 0x7f }, // X3 + { 0x2b, 0x3f, 0x3e, 0x3c, 0x4d, 0x4e, 0x42, 0x56, 0x43, 0x58, 0x5a }, // X4 + { 0x4c, 0x4b, 0x4a, 0x48, 0x47, 0x46, 0x44, 0x53, 0x41, 0x0c, 0x1b }, // X5 + { 0x4f, 0x49, 0x55, 0x59, 0x54, 0x52, 0x45, 0x57, 0x51, 0x09, 0x0b }, // X6 + { 0x29, 0x28, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x7e, 0x7c } // X7 + }, + + // control + { + // Y0 Y1 Y2 Y3 Y4 Y5 Y6 Y7 Y8 Y9 Y10 + // NUL SOH STX ETX EOT ENQ ACK BEL DC1 DLE SI X0 + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x11, 0x10, 0x0f }, // X0 + // DLE VT FF SO CR NAK SYN ETB CAN EM SUB X1 + { 0x10, 0x0b, 0x0c, 0x0e, 0x0d, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a }, // X1 + // NUL FS GS RS US NUL NUL NUL SP NUL US X2 + { 0x00, 0x1c, 0x1d, 0x1e, 0x1f, 0x00, 0x00, 0x00, 0x20, 0x00, 0x1f }, // X2 + // NUL NUL DLE US NUL BS ESC GS CR LF DEL X3 + { 0x00, 0x00, 0x10, 0x1f, 0x00, 0x08, 0x1B, 0x1d, 0x0d, 0x0a, 0x7f }, // X3 + { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x0e, 0x02, 0x16, 0x03, 0x18, 0x1a }, // X4 + { 0x0c, 0x0b, 0x0a, 0x08, 0x07, 0x06, 0x04, 0x13, 0x01, 0x0c, 0x1b }, // X5 + { 0x1f, 0x09, 0x15, 0x19, 0x14, 0x12, 0x05, 0x17, 0x11, 0x09, 0x0b }, // X6 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x1c } // X7 + } +}; + + +const device_type KR2376 = &device_creator; + +kr2376_device::kr2376_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, KR2376, "SMC KR2376", tag, owner, clock, "kr2376", __FILE__), + m_write_strobe(*this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void kr2376_device::device_start() +{ + m_write_strobe.resolve_safe(); + + /* set initial values */ + m_ring11 = 0; + m_ring8 = 0; + m_modifiers = 0; + m_strobe = 0; + m_strobe_old = 0; + m_parity = 0; + m_data = 0; + memset(m_pins, 0x00, sizeof(m_pins)); + change_output_lines(); + + /* create the timers */ + m_scan_timer = timer_alloc(TIMER_SCAN_TICK); + m_scan_timer->adjust(attotime::zero, 0, attotime::from_hz(clock())); + + /* register for state saving */ + save_item(NAME(m_pins)); + save_item(NAME(m_ring11)); + save_item(NAME(m_ring8)); + save_item(NAME(m_modifiers)); + save_item(NAME(m_strobe)); + save_item(NAME(m_strobe_old)); + save_item(NAME(m_parity)); + save_item(NAME(m_data)); +} + +/*------------------------------------------------- + set_input_pin - set an input pin +-------------------------------------------------*/ +void kr2376_device::set_input_pin( kr2376_input_pin_t pin, int data ) +{ + data = data ? 1 : 0; + switch ( pin ) + { + case KR2376_PII: + case KR2376_DSII: + m_pins[pin] = data; + break; + } +} + + +/*------------------------------------------------- + get_output_pin - get the status of an output pin +-------------------------------------------------*/ +int kr2376_device::get_output_pin( kr2376_output_pin_t pin ) +{ + return m_pins[pin]; +} + + +void kr2376_device::change_output_lines() +{ + if (m_strobe != m_strobe_old) + { + m_strobe_old = m_strobe; + + if (m_strobe) // strobe 0 --> 1 transition + { + /* update parity */ + m_pins[KR2376_PO] = m_parity ^ m_pins[KR2376_PII]; + } + m_pins[KR2376_SO] = m_strobe ^ m_pins[KR2376_DSII]; + m_write_strobe(m_strobe ^ m_pins[KR2376_DSII]); + } +} + +void kr2376_device::clock_scan_counters() +{ + /* ring counters inhibited while strobe active */ + if (!m_strobe) + { + m_ring11++; + if (m_ring11 == 11) + { + m_ring11 = 0; + m_ring8++; + if (m_ring8 == 8) + m_ring8 = 0; + } + } +} + +void kr2376_device::detect_keypress() +{ + static const char *const keynames[] = { "X0", "X1", "X2", "X3", "X4", "X5", "X6", "X7" }; + + if (ioport(keynames[m_ring8])->read() == (1 << m_ring11)) + { + m_modifiers = ioport("MODIFIERS")->read(); + + m_strobe = 1; + /* strobe 0->1 transition, encode char and update parity */ + if (!m_strobe_old) + { + int i; + int parbit; + int shift = BIT(m_modifiers, 0); + int control = BIT(m_modifiers, 1); + int alpha = BIT(m_modifiers, 2); + int table = 0; + + if (shift || alpha) + table = 1; + else if (control) + table = 2; + + m_data = KR2376_KEY_CODES[table][m_ring8][m_ring11]; + + /* Compute ODD parity */ + m_parity = m_data; + parbit = 0; + for (i=0; i<8; i++) + parbit ^= (m_parity >> i) & 1; + m_parity = parbit; + } + } + else + { + m_strobe = 0; + } +} + +void kr2376_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch (id) + { + case TIMER_SCAN_TICK: + change_output_lines(); + clock_scan_counters(); + detect_keypress(); + break; + } +} + +/* Keyboard Data */ + +READ8_MEMBER( kr2376_device::data_r ) +{ + if (m_pins[KR2376_DSII]) + return m_data ^ 0xff; + else + return m_data; +} + +/* Input Ports */ + +INPUT_PORTS_START( kr2376 ) + PORT_START("X0") + PORT_BIT( 0x0001, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x0002, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x0004, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x0008, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x0010, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x0020, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x0040, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x0080, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x0100, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x0200, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x0400, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("X1") + PORT_BIT( 0x0001, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x0002, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x0004, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x0008, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x0010, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x0020, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x0040, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x0080, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x0100, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x0200, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x0400, IP_ACTIVE_HIGH, IPT_UNUSED ) + + + PORT_START("X2") + PORT_BIT( 0x0001, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_MINUS) PORT_CHAR('-') PORT_CHAR('=') + PORT_BIT( 0x0002, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x0004, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x0008, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x0010, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x0020, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x0040, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x0080, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x0100, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_SPACE) PORT_CHAR(' ') + PORT_BIT( 0x0200, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x0400, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CHAR('_') + + PORT_START("X3") + PORT_BIT( 0x0001, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_0) PORT_CHAR('0') + PORT_BIT( 0x0002, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_COLON) PORT_CHAR(':') PORT_CHAR('*') + PORT_BIT( 0x0004, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_P) PORT_CHAR('p') PORT_CHAR('P') + PORT_BIT( 0x0008, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x0010, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_QUOTE) PORT_CHAR('`') PORT_CHAR('@') + PORT_BIT( 0x0020, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_BACKSPACE) PORT_CHAR(8) PORT_NAME("Del") + PORT_BIT( 0x0040, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_OPENBRACE) PORT_CHAR('[') PORT_CHAR('{') + PORT_BIT( 0x0080, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_CLOSEBRACE) PORT_CHAR(']') PORT_CHAR('}') + PORT_BIT( 0x0100, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_ENTER) PORT_CHAR(13) PORT_NAME("CR") + PORT_BIT( 0x0200, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_HOME) PORT_CHAR(UCHAR_MAMEKEY(HOME)) PORT_CHAR(10) PORT_NAME("LF") + PORT_BIT( 0x0400, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("X4") + PORT_BIT( 0x0001, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_COLON) PORT_CHAR(';') PORT_CHAR('+') + PORT_BIT( 0x0002, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_SLASH) PORT_CHAR('/') PORT_CHAR('?') + PORT_BIT( 0x0004, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_STOP) PORT_CHAR('.') PORT_CHAR('>') + PORT_BIT( 0x0008, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_COMMA) PORT_CHAR(',') PORT_CHAR('<') + PORT_BIT( 0x0010, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_M) PORT_CHAR('m') PORT_CHAR('M') + PORT_BIT( 0x0020, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_N) PORT_CHAR('n') PORT_CHAR('N') + PORT_BIT( 0x0040, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_B) PORT_CHAR('b') PORT_CHAR('B') + PORT_BIT( 0x0080, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_V) PORT_CHAR('v') PORT_CHAR('V') + PORT_BIT( 0x0100, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_C) PORT_CHAR('c') PORT_CHAR('C') + PORT_BIT( 0x0200, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_X) PORT_CHAR('x') PORT_CHAR('X') + PORT_BIT( 0x0400, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Z) PORT_CHAR('z') PORT_CHAR('Z') + + + PORT_START("X5") + PORT_BIT( 0x0001, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_L) PORT_CHAR('l') PORT_CHAR('L') + PORT_BIT( 0x0002, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_K) PORT_CHAR('k') PORT_CHAR('K') + PORT_BIT( 0x0004, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_J) PORT_CHAR('j') PORT_CHAR('J') + PORT_BIT( 0x0008, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_H) PORT_CHAR('h') PORT_CHAR('H') + PORT_BIT( 0x0010, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_G) PORT_CHAR('c') PORT_CHAR('G') + PORT_BIT( 0x0020, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F) PORT_CHAR('f') PORT_CHAR('F') + PORT_BIT( 0x0040, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_D) PORT_CHAR('d') PORT_CHAR('D') + PORT_BIT( 0x0080, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_S) PORT_CHAR('s') PORT_CHAR('S') + PORT_BIT( 0x0100, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_A) PORT_CHAR('a') PORT_CHAR('A') + PORT_BIT( 0x0200, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x0400, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_ESC) PORT_CHAR(UCHAR_MAMEKEY(ESC)) + + + PORT_START("X6") + PORT_BIT( 0x0001, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_O) PORT_CHAR('o') PORT_CHAR('O') + PORT_BIT( 0x0002, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_I) PORT_CHAR('i') PORT_CHAR('I') + PORT_BIT( 0x0004, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_U) PORT_CHAR('u') PORT_CHAR('U') + PORT_BIT( 0x0008, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Y) PORT_CHAR('y') PORT_CHAR('Y') + PORT_BIT( 0x0010, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_T) PORT_CHAR('t') PORT_CHAR('T') + PORT_BIT( 0x0020, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_R) PORT_CHAR('r') PORT_CHAR('R') + PORT_BIT( 0x0040, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_E) PORT_CHAR('e') PORT_CHAR('E') + PORT_BIT( 0x0080, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_W) PORT_CHAR('w') PORT_CHAR('W') + PORT_BIT( 0x0100, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Q) PORT_CHAR('q') PORT_CHAR('Q') + + PORT_START("X7") + PORT_BIT( 0x0001, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_9) PORT_CHAR('9') PORT_CHAR(')') + PORT_BIT( 0x0002, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_8) PORT_CHAR('8') PORT_CHAR('(') + PORT_BIT( 0x0004, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_7) PORT_CHAR('7') PORT_CHAR('\'') + PORT_BIT( 0x0008, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_6) PORT_CHAR('6') PORT_CHAR('&') + PORT_BIT( 0x0010, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_5) PORT_CHAR('5') PORT_CHAR('%') + PORT_BIT( 0x0020, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_4) PORT_CHAR('4') PORT_CHAR('$') + PORT_BIT( 0x0040, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_3) PORT_CHAR('3') PORT_CHAR('#') + PORT_BIT( 0x0080, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_2) PORT_CHAR('2') PORT_CHAR('"') + PORT_BIT( 0x0100, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_1) PORT_CHAR('1') PORT_CHAR('!') + PORT_BIT( 0x0200, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_TILDE) PORT_CHAR('^') PORT_CHAR('~') + PORT_BIT( 0x0400, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_BACKSLASH) PORT_CHAR('\\') PORT_CHAR('|') + + PORT_START("MODIFIERS") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_LSHIFT) PORT_CODE(KEYCODE_RSHIFT) PORT_CHAR(UCHAR_SHIFT_1) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_LCONTROL) PORT_CODE(KEYCODE_RCONTROL) PORT_CHAR(UCHAR_MAMEKEY(LCONTROL)) PORT_CHAR(UCHAR_MAMEKEY(RCONTROL)) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_CAPSLOCK) PORT_CHAR(UCHAR_MAMEKEY(CAPSLOCK)) +INPUT_PORTS_END + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor kr2376_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( kr2376 ); +} diff --git a/src/devices/machine/kr2376.h b/src/devices/machine/kr2376.h new file mode 100644 index 00000000000..e282362d761 --- /dev/null +++ b/src/devices/machine/kr2376.h @@ -0,0 +1,106 @@ +// license:??? +// copyright-holders:Roberto Lavarone +/********************************************************************** + + SMC KR2376 Keyboard Encoder emulation + +********************************************************************** + _____ _____ + Vcc 1 |* \_/ | 40 Frequency Control A + Frequency Control B 2 | | 39 X0 + Frequency Control C 3 | | 38 X1 + Shift Input 4 | | 37 X2 + Control Input 5 | | 36 X3 + Parity Invert Input 6 | | 35 X4 + Parity Output 7 | | 34 X5 + Data Output B8 8 | | 33 X6 + Data Output B7 9 | | 32 X7 + Data Output B6 10 | KR2376 | 31 Y0 + Data Output B5 11 | | 30 Y1 + Data Output B4 12 | | 29 Y2 + Data Output B3 13 | | 28 Y3 + Data Output B2 14 | | 27 Y4 + Data Output B1 15 | | 26 Y5 + Strobe Output 16 | | 25 Y6 + Ground 17 | | 24 Y7 + Vgg 18 | | 23 Y8 + Strobe Control Input 19 | | 22 Y9 + Invert Input 20 |_____________| 21 Y10 + +**********************************************************************/ + +#ifndef __KR2376__ +#define __KR2376__ + + +#define MCFG_KR2376_STROBE_CALLBACK(_write) \ + devcb = &kr2376_device::set_strobe_wr_callback(*device, DEVCB_##_write); + +/* + * Input pins + */ +enum kr2376_input_pin_t +{ + KR2376_DSII=20, /* DSII - Pin 20 - Data & Strobe Invert Input */ + KR2376_PII=6 /* PII - Pin 6 - Parity Invert Input */ +}; + +enum kr2376_output_pin_t +{ + KR2376_SO=16, /* SO - Pin 16 - Strobe Output */ + KR2376_PO=7 /* PO - Pin 7 - Parity Output */ +}; + +class kr2376_device : public device_t +{ +public: + kr2376_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + ~kr2376_device() {} + + template static devcb_base &set_strobe_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_strobe.set_callback(object); } + + /* keyboard data */ + DECLARE_READ8_MEMBER( data_r ); + + /* Set an input pin */ + void set_input_pin( kr2376_input_pin_t pin, int data ); + + /* Get an output pin */ + int get_output_pin( kr2376_output_pin_t pin ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + virtual ioport_constructor device_input_ports() const; + +private: + // internal state + int m_pins[41]; + + int m_ring11; /* sense input scan counter */ + int m_ring8; /* drive output scan counter */ + int m_modifiers; /* modifier inputs */ + + int m_strobe; /* strobe output */ + int m_strobe_old; + int m_parity; + int m_data; + + /* timers */ + emu_timer *m_scan_timer; /* keyboard scan timer */ + devcb_write_line m_write_strobe; + + enum + { + TIMER_SCAN_TICK + }; + + void change_output_lines(); + void clock_scan_counters(); + void detect_keypress(); +}; + +extern const device_type KR2376; + +#endif diff --git a/src/devices/machine/laserdsc.c b/src/devices/machine/laserdsc.c new file mode 100644 index 00000000000..a027ac62271 --- /dev/null +++ b/src/devices/machine/laserdsc.c @@ -0,0 +1,1229 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/************************************************************************* + + laserdsc.c + + Core laserdisc player implementation. + +*************************************************************************/ + +#include "emu.h" +#include "laserdsc.h" +#include "avhuff.h" +#include "vbiparse.h" +#include "config.h" +#include "render.h" +#include "chd.h" + + + +//************************************************************************** +// DEBUGGING +//************************************************************************** + +#define LOG_SLIDER 0 + + + +//************************************************************************** +// CONSTANTS +//************************************************************************** + +// these specs code from IEC 60857, for NTSC players +const UINT32 LEAD_IN_MIN_RADIUS_IN_UM = 53500; // 53.5 mm +const UINT32 PROGRAM_MIN_RADIUS_IN_UM = 55000; // 55 mm +const UINT32 PROGRAM_MAX_RADIUS_IN_UM = 145000; // 145 mm +const UINT32 LEAD_OUT_MIN_SIZE_IN_UM = 2000; // 2 mm + +// the track pitch is defined as a range; we pick a nominal pitch +// that ensures we can fit 54,000 tracks +//const UINT32 MIN_TRACK_PITCH_IN_NM = 1400; // 1.4 um +//const UINT32 MAX_TRACK_PITCH_IN_NM = 2000; // 2 um +const UINT32 NOMINAL_TRACK_PITCH_IN_NM = (PROGRAM_MAX_RADIUS_IN_UM - PROGRAM_MIN_RADIUS_IN_UM) * 1000 / 54000; + +// we simulate extra lead-in and lead-out tracks +const UINT32 VIRTUAL_LEAD_IN_TRACKS = (PROGRAM_MIN_RADIUS_IN_UM - LEAD_IN_MIN_RADIUS_IN_UM) * 1000 / NOMINAL_TRACK_PITCH_IN_NM; +const UINT32 MAX_TOTAL_TRACKS = 54000; +const UINT32 VIRTUAL_LEAD_OUT_TRACKS = LEAD_OUT_MIN_SIZE_IN_UM * 1000 / NOMINAL_TRACK_PITCH_IN_NM; + + + +//************************************************************************** +// CORE IMPLEMENTATION +//************************************************************************** + +//------------------------------------------------- +// laserdisc_device - constructor +//------------------------------------------------- + +laserdisc_device::laserdisc_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_sound_interface(mconfig, *this), + device_video_interface(mconfig, *this), + m_overwidth(0), + m_overheight(0), + m_overclip(0, -1, 0, -1), + m_disc(NULL), + m_width(0), + m_height(0), + m_fps_times_1million(0), + m_samplerate(0), + m_readresult(CHDERR_NONE), + m_chdtracks(0), + m_work_queue(osd_work_queue_alloc(WORK_QUEUE_FLAG_IO)), + m_audiosquelch(0), + m_videosquelch(0), + m_fieldnum(0), + m_curtrack(0), + m_maxtrack(0), + m_attospertrack(0), + m_sliderupdate(attotime::zero), + m_videoindex(0), + m_stream(NULL), + m_audiobufsize(0), + m_audiobufin(0), + m_audiobufout(0), + m_audiocursamples(0), + m_audiomaxsamples(0), + m_videoenable(false), + m_videotex(NULL), + m_videopalette(NULL), + m_overenable(false), + m_overindex(0), + m_overtex(NULL), + m_overlay_palette(*this) +{ + // initialize overlay_config + m_orig_config.m_overposx = m_orig_config.m_overposy = 0.0f; + m_orig_config.m_overscalex = m_orig_config.m_overscaley = 1.0f; + *static_cast(this) = m_orig_config; +} + + +//------------------------------------------------- +// ~laserdisc_device - destructor +//------------------------------------------------- + +laserdisc_device::~laserdisc_device() +{ + osd_work_queue_free(m_work_queue); +} + + + +//************************************************************************** +// PUBLIC INTERFACES +//************************************************************************** + +//------------------------------------------------- +// get_field_code - return raw field information +// read from the disc +//------------------------------------------------- + +UINT32 laserdisc_device::get_field_code(laserdisc_field_code code, bool zero_if_squelched) +{ + // return nothing if the video is off (external devices can't sense) + if (zero_if_squelched && m_videosquelch) + return 0; + + switch (code) + { + case LASERDISC_CODE_WHITE_FLAG: + return m_metadata[m_fieldnum].white; + + case LASERDISC_CODE_LINE16: + return m_metadata[m_fieldnum].line16; + + case LASERDISC_CODE_LINE17: + return m_metadata[m_fieldnum].line17; + + case LASERDISC_CODE_LINE18: + return m_metadata[m_fieldnum].line18; + + case LASERDISC_CODE_LINE1718: + return m_metadata[m_fieldnum].line1718; + } + return 0; +} + + +//------------------------------------------------- +// screen_update - handle updating the screen +//------------------------------------------------- + +UINT32 laserdisc_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + // handle the overlay if present + screen_bitmap &overbitmap = m_overbitmap[m_overindex]; + if (overbitmap.valid() && (!m_overupdate_ind16.isnull() || !m_overupdate_rgb32.isnull())) + { + // scale the cliprect to the overlay size + rectangle clip(m_overclip); + clip.min_y = cliprect.min_y * overbitmap.height() / bitmap.height(); + if (cliprect.min_y == screen.visible_area().min_y) + clip.min_y = MIN(clip.min_y, m_overclip.min_y); + clip.max_y = (cliprect.max_y + 1) * overbitmap.height() / bitmap.height() - 1; + + // call the update callback + if (!m_overupdate_ind16.isnull()) + m_overupdate_ind16(screen, overbitmap.as_ind16(), clip); + else + m_overupdate_rgb32(screen, overbitmap.as_rgb32(), clip); + } + + // if this is the last update, do the rendering + if (cliprect.max_y == screen.visible_area().max_y) + { + // update the texture with the overlay contents + if (overbitmap.valid()) + m_overtex->set_bitmap(overbitmap, m_overclip, overbitmap.texformat()); + + // get the laserdisc video + bitmap_yuy16 &vidbitmap = get_video(); + m_videotex->set_bitmap(vidbitmap, vidbitmap.cliprect(), TEXFORMAT_YUY16); + + // reset the screen contents + screen.container().empty(); + + // add the video texture + if (m_videoenable) + screen.container().add_quad(0.0f, 0.0f, 1.0f, 1.0f, rgb_t(0xff,0xff,0xff,0xff), m_videotex, PRIMFLAG_BLENDMODE(BLENDMODE_NONE) | PRIMFLAG_SCREENTEX(1)); + + // add the overlay + if (m_overenable && overbitmap.valid()) + { + float x0 = 0.5f - 0.5f * m_overscalex + m_overposx; + float y0 = 0.5f - 0.5f * m_overscaley + m_overposy; + float x1 = x0 + m_overscalex; + float y1 = y0 + m_overscaley; + screen.container().add_quad(x0, y0, x1, y1, rgb_t(0xff,0xff,0xff,0xff), m_overtex, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_SCREENTEX(1)); + } + + // swap to the next bitmap + m_overindex = (m_overindex + 1) % ARRAY_LENGTH(m_overbitmap); + } + return 0; +} + + +//------------------------------------------------- +// static_set_get_disc - set the get disc +// delegate +//------------------------------------------------- + +void laserdisc_device::static_set_get_disc(device_t &device, laserdisc_get_disc_delegate callback) +{ + downcast(device).m_getdisc_callback = callback; +} + + +//------------------------------------------------- +// static_set_get_disc - set the audio interceptor +// delegate +//------------------------------------------------- + +void laserdisc_device::static_set_audio(device_t &device, laserdisc_audio_delegate callback) +{ + downcast(device).m_audio_callback = callback; +} + + +//------------------------------------------------- +// static_set_overlay - set the overlay parameters +//------------------------------------------------- + +void laserdisc_device::static_set_overlay(device_t &device, UINT32 width, UINT32 height, screen_update_ind16_delegate update) +{ + laserdisc_device &ld = downcast(device); + ld.m_overwidth = width; + ld.m_overheight = height; + ld.m_overclip.set(0, width - 1, 0, height - 1); + ld.m_overupdate_ind16 = update; + ld.m_overupdate_rgb32 = screen_update_rgb32_delegate(); +} + +void laserdisc_device::static_set_overlay(device_t &device, UINT32 width, UINT32 height, screen_update_rgb32_delegate update) +{ + laserdisc_device &ld = downcast(device); + ld.m_overwidth = width; + ld.m_overheight = height; + ld.m_overclip.set(0, width - 1, 0, height - 1); + ld.m_overupdate_ind16 = screen_update_ind16_delegate(); + ld.m_overupdate_rgb32 = update; +} + + +//------------------------------------------------- +// static_set_overlay - set the overlay visible +// memregion +//------------------------------------------------- + +void laserdisc_device::static_set_overlay_clip(device_t &device, INT32 minx, INT32 maxx, INT32 miny, INT32 maxy) +{ + downcast(device).m_overclip.set(minx, maxx, miny, maxy); +} + + +//------------------------------------------------- +// static_set_overlay_position - set the overlay +// position parameters +//------------------------------------------------- + +void laserdisc_device::static_set_overlay_position(device_t &device, float posx, float posy) +{ + laserdisc_device &ld = downcast(device); + ld.m_orig_config.m_overposx = ld.m_overposx = posx; + ld.m_orig_config.m_overposy = ld.m_overposy = posy; +} + + +//------------------------------------------------- +// static_set_overlay_scale - set the overlay +// scale parameters +//------------------------------------------------- + +void laserdisc_device::static_set_overlay_scale(device_t &device, float scalex, float scaley) +{ + laserdisc_device &ld = downcast(device); + ld.m_orig_config.m_overscalex = ld.m_overscalex = scalex; + ld.m_orig_config.m_overscaley = ld.m_overscaley = scaley; + +} + +//------------------------------------------------- +// static_set_overlay_palette - set the screen palette +// configuration +//------------------------------------------------- + +void laserdisc_device::static_set_overlay_palette(device_t &device, const char *tag) +{ + downcast(device).m_overlay_palette.set_tag(tag); +} + +//************************************************************************** +// DEVICE INTERFACE +//************************************************************************** + +//------------------------------------------------- +// device start callback +//------------------------------------------------- + +void laserdisc_device::device_start() +{ + // if we have a palette and it's not started, wait for it + if (m_overlay_palette != NULL && !m_overlay_palette->started()) + throw device_missing_dependencies(); + + // initialize the various pieces + init_disc(); + init_video(); + init_audio(); + + // register callbacks + config_register(machine(), "laserdisc", config_saveload_delegate(FUNC(laserdisc_device::config_load), this), config_saveload_delegate(FUNC(laserdisc_device::config_save), this)); +} + + +//------------------------------------------------- +// device stop callback +//------------------------------------------------- + +void laserdisc_device::device_stop() +{ + // make sure all async operations have completed + if (m_disc != NULL) + osd_work_queue_wait(m_work_queue, osd_ticks_per_second() * 10); + + // free any textures and palettes + if (m_videotex != NULL) + machine().render().texture_free(m_videotex); + if (m_videopalette != NULL) + m_videopalette->deref(); + if (m_overtex != NULL) + machine().render().texture_free(m_overtex); +} + + +//------------------------------------------------- +// device reset callback +//------------------------------------------------- + +void laserdisc_device::device_reset() +{ + // attempt to wire up the audio + m_stream->set_sample_rate(m_samplerate); + + // set up the general ld + m_audiosquelch = 3; + m_videosquelch = 1; + m_fieldnum = 0; + m_curtrack = 1; + m_attospertrack = 0; + m_sliderupdate = machine().time(); +} + + +//------------------------------------------------- +// device_validity_check - verify device +// configuration +//------------------------------------------------- + +void laserdisc_device::device_validity_check(validity_checker &valid) const +{ + texture_format texformat = !m_overupdate_ind16.isnull() ? TEXFORMAT_PALETTE16 : TEXFORMAT_RGB32; + if (m_overlay_palette == NULL && texformat == TEXFORMAT_PALETTE16) + osd_printf_error("Overlay screen does not have palette defined\n"); +} + +//------------------------------------------------- +// device_timer - handle timers set by this +// device +//------------------------------------------------- + +void laserdisc_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch (id) + { + case TID_VBI_FETCH: + { + // wait for previous read and decode to finish + process_track_data(); + + // update current track based on slider speed + update_slider_pos(); + + // update the state + add_and_clamp_track(player_update(m_metadata[m_fieldnum], m_fieldnum, machine().time())); + + // flush any audio before we read more + m_stream->update(); + + // start reading the track data for the next round + m_fieldnum ^= 1; + read_track_data(); + break; + } + } +} + + +//------------------------------------------------- +// sound_stream_update - audio streamer for +// laserdiscs +//------------------------------------------------- + +void laserdisc_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + // compute AND values based on the squelch + INT16 leftand = (m_audiosquelch & 1) ? 0x0000 : 0xffff; + INT16 rightand = (m_audiosquelch & 2) ? 0x0000 : 0xffff; + + // see if we have enough samples to fill the buffer; if not, drop out + int samples_avail = m_audiobufin - m_audiobufout; + if (samples_avail < 0) + samples_avail += m_audiobufsize; + + // if no attached ld, just clear the buffers + stream_sample_t *dst0 = outputs[0]; + stream_sample_t *dst1 = outputs[1]; + if (samples_avail < samples) + { + memset(dst0, 0, samples * sizeof(dst0[0])); + memset(dst1, 0, samples * sizeof(dst1[0])); + } + + // otherwise, stream from our buffer + else + { + INT16 *buffer0 = &m_audiobuffer[0][0]; + INT16 *buffer1 = &m_audiobuffer[1][0]; + int sampout = m_audiobufout; + + // copy samples, clearing behind us as we go + while (sampout != m_audiobufin && samples-- > 0) + { + *dst0++ = buffer0[sampout] & leftand; + *dst1++ = buffer1[sampout] & rightand; + buffer0[sampout] = 0; + buffer1[sampout] = 0; + sampout++; + if (sampout >= m_audiobufsize) + sampout = 0; + } + m_audiobufout = sampout; + + // clear out the rest of the buffer + if (samples > 0) + { + sampout = (m_audiobufout == 0) ? m_audiobufsize - 1 : m_audiobufout - 1; + stream_sample_t fill0 = buffer0[sampout] & leftand; + stream_sample_t fill1 = buffer1[sampout] & rightand; + + while (samples-- > 0) + { + *dst0++ = fill0; + *dst1++ = fill1; + } + } + } +} + + +//************************************************************************** +// SUBCLASS HELPERS +//************************************************************************** + +//------------------------------------------------- +// set_slider_speed - dynamically change the +// slider speed +//------------------------------------------------- + +void laserdisc_device::set_slider_speed(INT32 tracks_per_vsync) +{ + // update to the current time + update_slider_pos(); + + // if 0, set the time to 0 + attotime vsyncperiod = m_screen->frame_period(); + if (tracks_per_vsync == 0) + m_attospertrack = 0; + + // positive values store positive times + else if (tracks_per_vsync > 0) + m_attospertrack = (vsyncperiod / tracks_per_vsync).as_attoseconds(); + + // negative values store negative times + else + m_attospertrack = -(vsyncperiod / -tracks_per_vsync).as_attoseconds(); + + if (LOG_SLIDER) + printf("Slider speed = %d\n", tracks_per_vsync); +} + + +//------------------------------------------------- +// advance_slider - advance the slider by +// a certain number of tracks +//------------------------------------------------- + +void laserdisc_device::advance_slider(INT32 numtracks) +{ + // first update to the current time + update_slider_pos(); + + // then update the track position + add_and_clamp_track(numtracks); + if (LOG_SLIDER) + printf("Advance by %d\n", numtracks); +} + + +//------------------------------------------------- +// get_slider_position - get the current +// slider position +//------------------------------------------------- + +laserdisc_device::slider_position laserdisc_device::get_slider_position() +{ + // update the slider position first + update_slider_pos(); + + // return the status + if (m_curtrack == 1) + return SLIDER_MINIMUM; + else if (m_curtrack < VIRTUAL_LEAD_IN_TRACKS) + return SLIDER_VIRTUAL_LEADIN; + else if (m_curtrack < VIRTUAL_LEAD_IN_TRACKS + m_chdtracks) + return SLIDER_CHD; + else if (m_curtrack < VIRTUAL_LEAD_IN_TRACKS + MAX_TOTAL_TRACKS) + return SLIDER_OUTSIDE_CHD; + else if (m_curtrack < m_maxtrack - 1) + return SLIDER_VIRTUAL_LEADOUT; + else + return SLIDER_MAXIMUM; +} + + +//------------------------------------------------- +// generic_update - generically update in a way +// that works for most situations +//------------------------------------------------- + +INT32 laserdisc_device::generic_update(const vbi_metadata &vbi, int fieldnum, const attotime &curtime, player_state_info &newstate) +{ + INT32 advanceby = 0; + int frame; + + // start by assuming the state doesn't change + newstate = m_player_state; + + // handle things based on the state + switch (m_player_state.m_state) + { + case LDSTATE_EJECTING: + // when time expires, switch to the ejected state + if (curtime >= m_player_state.m_endtime) + newstate.m_state = LDSTATE_EJECTED; + break; + + case LDSTATE_EJECTED: + // do nothing + break; + + case LDSTATE_PARKED: + // do nothing + break; + + case LDSTATE_LOADING: + // when time expires, switch to the spinup state + if (curtime >= m_player_state.m_endtime) + newstate.m_state = LDSTATE_SPINUP; + advanceby = -GENERIC_SEARCH_SPEED; + break; + + case LDSTATE_SPINUP: + // when time expires, switch to the playing state + if (curtime >= m_player_state.m_endtime) + newstate.m_state = LDSTATE_PLAYING; + advanceby = -GENERIC_SEARCH_SPEED; + break; + + case LDSTATE_PAUSING: + // if he hit the start of a frame, switch to paused state + if (is_start_of_frame(vbi)) + { + newstate.m_state = LDSTATE_PAUSED; + newstate.m_param = fieldnum; + } + + // else advance until we hit it + else if (fieldnum == 1) + advanceby = 1; + break; + + case LDSTATE_PAUSED: + // if we paused on field 1, we must flip back and forth + if (m_player_state.m_param == 1) + advanceby = (fieldnum == 1) ? 1 : -1; + break; + + case LDSTATE_PLAYING: + // if we hit the target frame, switch to the paused state + if (m_player_state.m_param > 0 && is_start_of_frame(vbi) && frame_from_metadata(vbi) == m_player_state.m_param) + { + newstate.m_state = LDSTATE_PAUSED; + newstate.m_param = fieldnum; + } + + // otherwise after the second field of each frame + else if (fieldnum == 1) + advanceby = 1; + break; + + case LDSTATE_PLAYING_SLOW_REVERSE: + // after the second field of each frame, see if we need to advance + if (fieldnum == 1 && ++m_player_state.m_substate > m_player_state.m_param) + { + advanceby = -1; + m_player_state.m_substate = 0; + } + break; + + case LDSTATE_PLAYING_SLOW_FORWARD: + // after the second field of each frame, see if we need to advance + if (fieldnum == 1 && ++m_player_state.m_substate > m_player_state.m_param) + { + advanceby = 1; + m_player_state.m_substate = 0; + } + break; + + case LDSTATE_PLAYING_FAST_REVERSE: + // advance after the second field of each frame + if (fieldnum == 1) + advanceby = -m_player_state.m_param; + break; + + case LDSTATE_PLAYING_FAST_FORWARD: + // advance after the second field of each frame + if (fieldnum == 1) + advanceby = m_player_state.m_param; + break; + + case LDSTATE_SCANNING: + // advance after the second field of each frame + if (fieldnum == 1) + advanceby = m_player_state.m_param >> 8; + + // after we run out of vsyncs, revert to the saved state + if (++m_player_state.m_substate >= (m_player_state.m_param & 0xff)) + newstate = m_saved_state; + break; + + case LDSTATE_STEPPING_REVERSE: + // wait for the first field of the frame and then leap backwards + if (is_start_of_frame(vbi)) + { + advanceby = (fieldnum == 1) ? -1 : -2; + newstate.m_state = LDSTATE_PAUSING; + } + break; + + case LDSTATE_STEPPING_FORWARD: + // wait for the first field of the frame and then switch to pausing state + if (is_start_of_frame(vbi)) + newstate.m_state = LDSTATE_PAUSING; + break; + + case LDSTATE_SEEKING: + // if we're in the final state, look for a matching frame and pause there + frame = frame_from_metadata(vbi); + if (m_player_state.m_substate == 1 && is_start_of_frame(vbi) && frame == m_player_state.m_param) + { + newstate.m_state = LDSTATE_PAUSED; + newstate.m_param = fieldnum; + } + + // otherwise, if we got frame data from the VBI, update our seeking logic + else if (m_player_state.m_substate == 0 && frame != FRAME_NOT_PRESENT) + { + INT32 delta = (m_player_state.m_param - 2) - frame; + + // if we're within a couple of frames, just play until we hit it + if (delta >= 0 && delta <= 2) + m_player_state.m_substate++; + + // otherwise, compute the delta assuming 1:1 track to frame; this will correct eventually + else + { + if (delta < 0) + delta--; + advanceby = delta; + advanceby = MIN(advanceby, GENERIC_SEARCH_SPEED); + advanceby = MAX(advanceby, -GENERIC_SEARCH_SPEED); + } + } + + // otherwise, keep advancing until we know what's up + else + { + if (fieldnum == 1) + advanceby = 1; + } + break; + + default: + // do nothing + break; + } + + return advanceby; +} + + +//************************************************************************** +// INITIALIZATION +//************************************************************************** + +//------------------------------------------------- +// init_disc - initialize the state of the +// CHD disc +//------------------------------------------------- + +void laserdisc_device::init_disc() +{ + // get a handle to the disc to play + if (!m_getdisc_callback.isnull()) + m_disc = m_getdisc_callback(*this); + else + m_disc = get_disk_handle(machine(), tag()); + + // set default parameters + m_width = 720; + m_height = 240; + m_fps_times_1million = 59940000; + m_samplerate = 48000; + + // get the disc metadata and extract the ld + m_chdtracks = 0; + m_maxtrack = VIRTUAL_LEAD_IN_TRACKS + MAX_TOTAL_TRACKS + VIRTUAL_LEAD_OUT_TRACKS; + if (m_disc != NULL) + { + // require the A/V codec and nothing else + if (m_disc->compression(0) != CHD_CODEC_AVHUFF || m_disc->compression(1) != CHD_CODEC_NONE) + throw emu_fatalerror("Laserdisc video must be compressed with the A/V codec!"); + + // read the metadata + std::string metadata; + chd_error err = m_disc->read_metadata(AV_METADATA_TAG, 0, metadata); + if (err != CHDERR_NONE) + throw emu_fatalerror("Non-A/V CHD file specified"); + + // extract the metadata + int fps, fpsfrac, interlaced, channels; + if (sscanf(metadata.c_str(), AV_METADATA_FORMAT, &fps, &fpsfrac, &m_width, &m_height, &interlaced, &channels, &m_samplerate) != 7) + throw emu_fatalerror("Invalid metadata in CHD file"); + else + m_fps_times_1million = fps * 1000000 + fpsfrac; + + // require interlaced video + if (!interlaced) + throw emu_fatalerror("Laserdisc video must be interlaced!"); + + // determine the maximum track and allocate a frame buffer + UINT32 totalhunks = m_disc->hunk_count(); + m_chdtracks = totalhunks / 2; + + // allocate memory for the precomputed per-frame metadata + err = m_disc->read_metadata(AV_LD_METADATA_TAG, 0, m_vbidata); + if (err != CHDERR_NONE || m_vbidata.size() != totalhunks * VBI_PACKED_BYTES) + throw emu_fatalerror("Precomputed VBI metadata missing or incorrect size"); + } + m_maxtrack = MAX(m_maxtrack, VIRTUAL_LEAD_IN_TRACKS + VIRTUAL_LEAD_OUT_TRACKS + m_chdtracks); +} + + +//------------------------------------------------- +// init_video - initialize the state of the +// video rendering +//------------------------------------------------- + +void laserdisc_device::init_video() +{ + // register for VBLANK callbacks + m_screen->register_vblank_callback(vblank_state_delegate(FUNC(laserdisc_device::vblank_state_changed), this)); + + // allocate palette for applying brightness/contrast/gamma + m_videopalette = palette_t::alloc(256); + if (m_videopalette == NULL) + throw emu_fatalerror("Out of memory allocating video palette"); + for (int index = 0; index < 256; index++) + m_videopalette->entry_set_color(index, rgb_t(index, index, index)); + + // allocate video frames + for (int index = 0; index < ARRAY_LENGTH(m_frame); index++) + { + // first allocate a YUY16 bitmap at 2x the height + frame_data &frame = m_frame[index]; + frame.m_bitmap.allocate(m_width, m_height * 2); + frame.m_bitmap.set_palette(m_videopalette); + fillbitmap_yuy16(frame.m_bitmap, 40, 109, 240); + + // make a copy of the bitmap that clips out the VBI and horizontal blanking areas + frame.m_visbitmap.wrap(&frame.m_bitmap.pix16(44, frame.m_bitmap.width() * 8 / 720), + frame.m_bitmap.width() - 2 * frame.m_bitmap.width() * 8 / 720, + frame.m_bitmap.height() - 44, + frame.m_bitmap.rowpixels()); + frame.m_visbitmap.set_palette(m_videopalette); + } + + // allocate an empty frame of the same size + m_emptyframe.allocate(m_width, m_height * 2); + m_emptyframe.set_palette(m_videopalette); + fillbitmap_yuy16(m_emptyframe, 0, 128, 128); + + // allocate texture for rendering + m_videoenable = true; + m_videotex = machine().render().texture_alloc(); + if (m_videotex == NULL) + fatalerror("Out of memory allocating video texture\n"); + + // allocate overlay + m_overenable = overlay_configured(); + if (m_overenable) + { + // bind our handlers + m_overupdate_ind16.bind_relative_to(*owner()); + m_overupdate_rgb32.bind_relative_to(*owner()); + + // configure bitmap formats + bitmap_format format = !m_overupdate_ind16.isnull() ? BITMAP_FORMAT_IND16 : BITMAP_FORMAT_RGB32; + texture_format texformat = !m_overupdate_ind16.isnull() ? TEXFORMAT_PALETTEA16 : TEXFORMAT_ARGB32; + + // allocate overlay bitmaps + for (int index = 0; index < ARRAY_LENGTH(m_overbitmap); index++) + { + m_overbitmap[index].set_format(format, texformat); + if (format==BITMAP_FORMAT_IND16) + m_overbitmap[index].set_palette(m_overlay_palette->palette()); + m_overbitmap[index].resize(m_overwidth, m_overheight); + } + + // allocate overlay texture + m_overtex = machine().render().texture_alloc(); + if (m_overtex == NULL) + fatalerror("Out of memory allocating overlay texture\n"); + } +} + + +//------------------------------------------------- +// init_audio - initialize the state of the +// audio rendering +//------------------------------------------------- + +void laserdisc_device::init_audio() +{ + // allocate a stream + m_stream = stream_alloc(0, 2, 48000); + + // allocate audio buffers + m_audiomaxsamples = ((UINT64)m_samplerate * 1000000 + m_fps_times_1million - 1) / m_fps_times_1million; + m_audiobufsize = m_audiomaxsamples * 4; + m_audiobuffer[0].resize(m_audiobufsize); + m_audiobuffer[1].resize(m_audiobufsize); +} + + +//************************************************************************** +// INTERNAL HELPERS +//************************************************************************** + +//------------------------------------------------- +// fillbitmap_yuy16 - fill a YUY16 bitmap with a +// given color pattern +//------------------------------------------------- + +void laserdisc_device::fillbitmap_yuy16(bitmap_yuy16 &bitmap, UINT8 yval, UINT8 cr, UINT8 cb) +{ + UINT16 color0 = (yval << 8) | cb; + UINT16 color1 = (yval << 8) | cr; + + // write 32 bits of color (2 pixels at a time) + for (int y = 0; y < bitmap.height(); y++) + { + UINT16 *dest = &bitmap.pix16(y); + for (int x = 0; x < bitmap.width() / 2; x++) + { + *dest++ = color0; + *dest++ = color1; + } + } +} + + +//------------------------------------------------- +// update_slider_pos - based on the current +// speed and elapsed time, update the current +// track position +//------------------------------------------------- + +void laserdisc_device::update_slider_pos() +{ + attotime curtime = machine().time(); + + // if not moving, update to now + if (m_attospertrack == 0) + m_sliderupdate = curtime; + + // otherwise, compute the number of tracks covered + else + { + attoseconds_t delta = (curtime - m_sliderupdate).as_attoseconds(); + + // determine how many tracks we covered and advance + if (m_attospertrack >= 0) + { + INT32 tracks_covered = delta / m_attospertrack; + add_and_clamp_track(tracks_covered); + if (tracks_covered != 0) + m_sliderupdate += attotime(0, tracks_covered * m_attospertrack); + } + else + { + INT32 tracks_covered = delta / -m_attospertrack; + add_and_clamp_track(-tracks_covered); + if (tracks_covered != 0) + m_sliderupdate += attotime(0, tracks_covered * -m_attospertrack); + } + } +} + + +//------------------------------------------------- +// vblank_state_changed - called on each state +// change of the VBLANK signal +//------------------------------------------------- + +void laserdisc_device::vblank_state_changed(screen_device &screen, bool vblank_state) +{ + // update current track based on slider speed + update_slider_pos(); + + // on rising edge, process previously-read frame and inform the player + if (vblank_state) + { + // call the player's VSYNC callback + player_vsync(m_metadata[m_fieldnum], m_fieldnum, machine().time()); + + // set a timer to begin fetching the next frame just before the VBI data would be fetched + timer_set(screen.time_until_pos(16*2), TID_VBI_FETCH); + } +} + + +//------------------------------------------------- +// current_frame - return a reference to the +// currently visible frame +//------------------------------------------------- + +laserdisc_device::frame_data &laserdisc_device::current_frame() +{ + // determine the most recent live set of frames + frame_data *frame = &m_frame[m_videoindex]; + if (frame->m_numfields < 2) + frame = &m_frame[(m_videoindex + ARRAY_LENGTH(m_frame) - 1) % ARRAY_LENGTH(m_frame)]; + return *frame; +} + + +//------------------------------------------------- +// read_track_data - read and process data for +// a particular video track +//------------------------------------------------- + +void laserdisc_device::read_track_data() +{ + // compute the chdhunk number we are going to read + INT32 chdtrack = m_curtrack - 1 - VIRTUAL_LEAD_IN_TRACKS; + chdtrack = MAX(chdtrack, 0); + chdtrack = MIN(chdtrack, m_chdtracks - 1); + UINT32 readhunk = chdtrack * 2 + m_fieldnum; + + // cheat and look up the metadata we are about to retrieve + vbi_metadata vbidata = { 0 }; + if (!m_vbidata.empty()) + vbi_metadata_unpack(&vbidata, NULL, &m_vbidata[readhunk * VBI_PACKED_BYTES]); + + // if we're in the lead-in area, force the VBI data to be standard lead-in + if (m_curtrack - 1 < VIRTUAL_LEAD_IN_TRACKS) + { + vbidata.line16 = 0; + vbidata.line17 = vbidata.line18 = vbidata.line1718 = VBI_CODE_LEADIN; + } +//printf("track %5d.%d: %06X %06X %06X\n", m_curtrack, m_fieldnum, vbidata.line16, vbidata.line17, vbidata.line18); + + // if we're about to read the first field in a frame, advance + frame_data *frame = &m_frame[m_videoindex]; + if ((vbidata.line1718 & VBI_MASK_CAV_PICTURE) == VBI_CODE_CAV_PICTURE) + { + if (frame->m_numfields >= 2) + m_videoindex = (m_videoindex + 1) % ARRAY_LENGTH(m_frame); + frame = &m_frame[m_videoindex]; + frame->m_numfields = 0; + } + + // if we're squelched, reset the frame counter + if (m_videosquelch) + frame->m_numfields = 0; + + // remember the last field number + frame->m_lastfield = m_curtrack * 2 + m_fieldnum; + + // set the video target information + m_avhuff_config.video.wrap(&frame->m_bitmap.pix16(m_fieldnum), frame->m_bitmap.width(), frame->m_bitmap.height() / 2, frame->m_bitmap.rowpixels() * 2); + + // set the audio target information + if (m_audiobufin + m_audiomaxsamples <= m_audiobufsize) + { + // if we can fit without wrapping, just read the data directly + m_avhuff_config.audio[0] = &m_audiobuffer[0][m_audiobufin]; + m_avhuff_config.audio[1] = &m_audiobuffer[1][m_audiobufin]; + } + else + { + // otherwise, read to the beginning of the buffer + m_avhuff_config.audio[0] = &m_audiobuffer[0][0]; + m_avhuff_config.audio[1] = &m_audiobuffer[1][0]; + } + + // override if we're not decoding + m_avhuff_config.maxsamples = m_audiomaxsamples; + m_avhuff_config.actsamples = &m_audiocursamples; + m_audiocursamples = 0; + + // set the VBI data for the new field from our precomputed data + if (!m_vbidata.empty()) + { + UINT32 vbiframe; + vbi_metadata_unpack(&m_metadata[m_fieldnum], &vbiframe, &m_vbidata[readhunk * VBI_PACKED_BYTES]); + } + + // if we're in the lead-in area, force the VBI data to be standard lead-in + if (m_curtrack - 1 < VIRTUAL_LEAD_IN_TRACKS) + { + m_metadata[m_fieldnum].line16 = 0; + m_metadata[m_fieldnum].line17 = m_metadata[m_fieldnum].line18 = m_metadata[m_fieldnum].line1718 = VBI_CODE_LEADIN; + } + + // configure the codec and then read + m_readresult = CHDERR_FILE_NOT_FOUND; + if (m_disc != NULL && !m_videosquelch) + { + m_readresult = m_disc->codec_configure(CHD_CODEC_AVHUFF, AVHUFF_CODEC_DECOMPRESS_CONFIG, &m_avhuff_config); + if (m_readresult == CHDERR_NONE) + { + m_queued_hunknum = readhunk; + m_readresult = CHDERR_OPERATION_PENDING; + osd_work_item_queue(m_work_queue, read_async_static, this, WORK_ITEM_FLAG_AUTO_RELEASE); + } + } +} + + +//------------------------------------------------- +// read_async_static - work item callback for +// asynchronous reads +//------------------------------------------------- + +void *laserdisc_device::read_async_static(void *param, int threadid) +{ + laserdisc_device &ld = *reinterpret_cast(param); + ld.m_readresult = ld.m_disc->read_hunk(ld.m_queued_hunknum, NULL); + return NULL; +} + + +//------------------------------------------------- +// process_track_data - process data from a +// track after it has been read +//------------------------------------------------- + +void laserdisc_device::process_track_data() +{ + // wait for the async operation to complete + if (m_readresult == CHDERR_OPERATION_PENDING) + osd_work_queue_wait(m_work_queue, osd_ticks_per_second() * 10); + assert(m_readresult != CHDERR_OPERATION_PENDING); + + // remove the video if we had an error + if (m_readresult != CHDERR_NONE) + m_avhuff_config.video.reset(); + + // count the field as read if we are successful + if (m_avhuff_config.video.valid()) + { + m_frame[m_videoindex].m_numfields++; + player_overlay(m_avhuff_config.video); + } + + // pass the audio to the callback + if (!m_audio_callback.isnull()) + m_audio_callback(*this, m_samplerate, m_audiocursamples, m_avhuff_config.audio[0], m_avhuff_config.audio[1]); + + // shift audio data if we read it into the beginning of the buffer + if (m_audiocursamples != 0 && m_audiobufin != 0) + for (int chnum = 0; chnum < 2; chnum++) + if (m_avhuff_config.audio[chnum] == &m_audiobuffer[chnum][0]) + { + // move data to the end + int samplesleft = m_audiobufsize - m_audiobufin; + samplesleft = MIN(samplesleft, m_audiocursamples); + memmove(&m_audiobuffer[chnum][m_audiobufin], &m_audiobuffer[chnum][0], samplesleft * 2); + + // shift data at the beginning + if (samplesleft < m_audiocursamples) + memmove(&m_audiobuffer[chnum][0], &m_audiobuffer[chnum][samplesleft], (m_audiocursamples - samplesleft) * 2); + } + + // update the input buffer pointer + m_audiobufin = (m_audiobufin + m_audiocursamples) % m_audiobufsize; +} + + + +//************************************************************************** +// CONFIG SETTINGS ACCESS +//************************************************************************** + +//------------------------------------------------- +// config_load - read and apply data from the +// configuration file +//------------------------------------------------- + +void laserdisc_device::config_load(int config_type, xml_data_node *parentnode) +{ + // we only care about game files + if (config_type != CONFIG_TYPE_GAME) + return; + + // might not have any data + if (parentnode == NULL) + return; + + // iterate over overlay nodes + for (xml_data_node *ldnode = xml_get_sibling(parentnode->child, "device"); ldnode != NULL; ldnode = xml_get_sibling(ldnode->next, "device")) + { + const char *devtag = xml_get_attribute_string(ldnode, "tag", ""); + if (strcmp(devtag, tag()) == 0) + { + // handle the overlay node + xml_data_node *overnode = xml_get_sibling(ldnode->child, "overlay"); + if (overnode != NULL) + { + // fetch positioning controls + m_overposx = xml_get_attribute_float(overnode, "hoffset", m_overposx); + m_overscalex = xml_get_attribute_float(overnode, "hstretch", m_overscalex); + m_overposy = xml_get_attribute_float(overnode, "voffset", m_overposy); + m_overscaley = xml_get_attribute_float(overnode, "vstretch", m_overscaley); + } + } + } +} + + +//------------------------------------------------- +// config_save - save data to the configuration +// file +//------------------------------------------------- + +void laserdisc_device::config_save(int config_type, xml_data_node *parentnode) +{ + // we only care about game files + if (config_type != CONFIG_TYPE_GAME) + return; + + // create a node + xml_data_node *ldnode = xml_add_child(parentnode, "device", NULL); + if (ldnode != NULL) + { + // output the basics + xml_set_attribute(ldnode, "tag", tag()); + + // add an overlay node + xml_data_node *overnode = xml_add_child(ldnode, "overlay", NULL); + bool changed = false; + if (overnode != NULL) + { + // output the positioning controls + if (m_overposx != m_orig_config.m_overposx) + { + xml_set_attribute_float(overnode, "hoffset", m_overposx); + changed = true; + } + + if (m_overscalex != m_orig_config.m_overscalex) + { + xml_set_attribute_float(overnode, "hstretch", m_overscalex); + changed = true; + } + + if (m_overposy != m_orig_config.m_overposy) + { + xml_set_attribute_float(overnode, "voffset", m_overposy); + changed = true; + } + + if (m_overscaley != m_orig_config.m_overscaley) + { + xml_set_attribute_float(overnode, "vstretch", m_overscaley); + changed = true; + } + } + + // if nothing changed, kill the node + if (!changed) + xml_delete_node(ldnode); + } +} diff --git a/src/devices/machine/laserdsc.h b/src/devices/machine/laserdsc.h new file mode 100644 index 00000000000..55d4aeda1b3 --- /dev/null +++ b/src/devices/machine/laserdsc.h @@ -0,0 +1,413 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/************************************************************************* + + laserdsc.h + + Core laserdisc player implementation. + +*************************************************************************/ + +#pragma once + +#ifndef __LASERDSC_H__ +#define __LASERDSC_H__ + +#include "vbiparse.h" +#include "avhuff.h" + + +//************************************************************************** +// CONSTANTS +//************************************************************************** + +// laserdisc field codes +enum laserdisc_field_code +{ + LASERDISC_CODE_WHITE_FLAG = 11, // boolean white flag + LASERDISC_CODE_LINE16 = 16, // 24-bit line 16 code + LASERDISC_CODE_LINE17 = 17, // 24-bit line 17 code + LASERDISC_CODE_LINE18 = 18, // 24-bit line 18 code + LASERDISC_CODE_LINE1718 = 1718 // 24-bit best of line 17/18 code +}; + + +// special frame and chapter numbers from VBI conversion +#define FRAME_NOT_PRESENT -2 // no frame number information present +#define FRAME_LEAD_IN -1 // lead-in code detected +#define FRAME_LEAD_OUT 99999 // lead-out code detected +#define CHAPTER_NOT_PRESENT -2 // no chapter number information present +#define CHAPTER_LEAD_IN -1 // lead-in code detected +#define CHAPTER_LEAD_OUT 100 // lead-out code detected + +// generic head movement speeds; use player-specific information where appropriate +#define GENERIC_SLOW_SPEED (5) // 1/5 normal speed +#define GENERIC_FAST_SPEED (3) // 3x normal speed +#define GENERIC_SCAN_SPEED (50) // 50x normal speed +#define GENERIC_SEARCH_SPEED (5000) // 5000x normal speed + +// generic timings; use player-specific information where appropriate +#define GENERIC_EJECT_TIME (attotime::from_seconds(5)) +#define GENERIC_SPINUP_TIME (attotime::from_seconds(2)) +#define GENERIC_LOAD_TIME (attotime::from_seconds(5)) + + + +//************************************************************************** +// DEVICE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_LASERDISC_GET_DISC(_func) \ + laserdisc_device::static_set_get_disc(*device, _func); +#define MCFG_LASERDISC_AUDIO(_func) \ + laserdisc_device::static_set_audio(*device, _func); +#define MCFG_LASERDISC_SCREEN(_tag) \ + laserdisc_device::static_set_screen(*device, _tag); +#define MCFG_LASERDISC_OVERLAY_STATIC(_width, _height, _func) \ + laserdisc_device::static_set_overlay(*device, _width, _height, screen_update_delegate_smart(&screen_update_##_func, "screen_update_" #_func)); +#define MCFG_LASERDISC_OVERLAY_DRIVER(_width, _height, _class, _method) \ + laserdisc_device::static_set_overlay(*device, _width, _height, screen_update_delegate_smart(&_class::_method, #_class "::" #_method, NULL)); +#define MCFG_LASERDISC_OVERLAY_DEVICE(_width, _height, _device, _class, _method) \ + laserdisc_device::static_set_overlay(*device, _width, _height, screen_update_delegate_smart(&_class::_method, #_class "::" #_method, _device)); +#define MCFG_LASERDISC_OVERLAY_CLIP(_minx, _maxx, _miny, _maxy) \ + laserdisc_device::static_set_overlay_clip(*device, _minx, _maxx, _miny, _maxy); +#define MCFG_LASERDISC_OVERLAY_POSITION(_posx, _posy) \ + laserdisc_device::static_set_overlay_position(*device, _posx, _posy); +#define MCFG_LASERDISC_OVERLAY_SCALE(_scalex, _scaley) \ + laserdisc_device::static_set_overlay_scale(*device, _scalex, _scaley); +#define MCFG_LASERDISC_OVERLAY_PALETTE(_palette_tag) \ + laserdisc_device::static_set_overlay_palette(*device, "^" _palette_tag); + +// use these to add laserdisc screens with proper video update parameters +#define MCFG_LASERDISC_SCREEN_ADD_NTSC(_tag, _ldtag) \ + MCFG_DEVICE_MODIFY(_ldtag) \ + laserdisc_device::static_set_screen(*device, _tag); \ + MCFG_SCREEN_ADD(_tag, RASTER) \ + MCFG_SCREEN_VIDEO_ATTRIBUTES(VIDEO_SELF_RENDER) \ + MCFG_SCREEN_RAW_PARAMS(XTAL_14_31818MHz*2, 910, 0, 704, 525, 44, 524) \ + MCFG_SCREEN_UPDATE_DEVICE(_ldtag, laserdisc_device, screen_update) +// not correct yet; fix me... +#define MCFG_LASERDISC_SCREEN_ADD_PAL(_tag, _ldtag) \ + MCFG_DEVICE_MODIFY(_ldtag) \ + laserdisc_device::static_set_screen(*device, _tag); \ + MCFG_SCREEN_ADD(_tag, RASTER) \ + MCFG_SCREEN_VIDEO_ATTRIBUTES(VIDEO_SELF_RENDER) \ + MCFG_SCREEN_RAW_PARAMS(XTAL_14_31818MHz, 910, 0, 704, 525.0/2, 0, 480/2) \ + MCFG_SCREEN_UPDATE_DEVICE(_ldtag, laserdisc_device, screen_update) + + +//************************************************************************** +// MACROS +//************************************************************************** + +#define SCANNING_PARAM(speed,duration) (((speed) << 8) | ((duration) & 0xff)) + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// forward declarations +class laserdisc_device; + +// delegates +typedef delegate laserdisc_get_disc_delegate; +typedef delegate laserdisc_audio_delegate; + + +// ======================> laserdisc_overlay_config + +// overlay configuration +struct laserdisc_overlay_config +{ + float m_overposx; + float m_overposy; + float m_overscalex; + float m_overscaley; +}; + + +// ======================> laserdisc_device + +// base laserdisc class +class laserdisc_device : public device_t, + public device_sound_interface, + public device_video_interface, + public laserdisc_overlay_config +{ +protected: + // construction/destruction + laserdisc_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + virtual ~laserdisc_device(); + +public: + // reset line control + + // core control and status + bool video_active() { return (!m_videosquelch && current_frame().m_numfields >= 2); } + bitmap_yuy16 &get_video() { return (!video_active()) ? m_emptyframe : current_frame().m_visbitmap; } + UINT32 get_field_code(laserdisc_field_code code, bool zero_if_squelched); + + // video interface + void video_enable(bool enable) { m_videoenable = enable; } + void overlay_enable(bool enable) { m_overenable = enable; } + + // video update callback + UINT32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); + + // configuration + bool overlay_configured() const { return (m_overwidth > 0 && m_overheight > 0 && (!m_overupdate_ind16.isnull() || !m_overupdate_rgb32.isnull())); } + void get_overlay_config(laserdisc_overlay_config &config) { config = static_cast(*this); } + void set_overlay_config(const laserdisc_overlay_config &config) { static_cast(*this) = config; } + + // static configuration helpers + static void static_set_get_disc(device_t &device, laserdisc_get_disc_delegate callback); + static void static_set_audio(device_t &device, laserdisc_audio_delegate callback); + static void static_set_overlay(device_t &device, UINT32 width, UINT32 height, screen_update_ind16_delegate update); + static void static_set_overlay(device_t &device, UINT32 width, UINT32 height, screen_update_rgb32_delegate update); + static void static_set_overlay_clip(device_t &device, INT32 minx, INT32 maxx, INT32 miny, INT32 maxy); + static void static_set_overlay_position(device_t &device, float posx, float posy); + static void static_set_overlay_scale(device_t &device, float scalex, float scaley); + static void static_set_overlay_palette(device_t &device, const char *tag); + +protected: + // timer IDs + enum + { + TID_VBI_FETCH, + TID_FIRST_PLAYER_TIMER + }; + + // common laserdisc states + enum player_state + { + LDSTATE_NONE, // unspecified state + LDSTATE_EJECTING, // in the process of ejecting + LDSTATE_EJECTED, // fully ejected + LDSTATE_PARKED, // head parked in lead-in + LDSTATE_LOADING, // loading from ejected state + LDSTATE_SPINUP, // spinning up + LDSTATE_PAUSING, // looking for a frame boundary to pause + LDSTATE_PAUSED, // found a frame boundary; now paused + // parameter specifies the fieldnum of the first frame + LDSTATE_PLAYING, // playing forward normally, with audio + // parameter specifies the target frame, or 0 if none + LDSTATE_PLAYING_SLOW_REVERSE, // playing slow in the reverse direction, with no audio + // parameter specifies the number of times to repeat each track + LDSTATE_PLAYING_SLOW_FORWARD, // playing slow in the forward direction, with no audio + // parameter specifies the number of times to repeat each track + LDSTATE_PLAYING_FAST_REVERSE, // playing fast in the reverse direction, with no audio + // parameter specifies the number of frames to skip backwards after each frame + LDSTATE_PLAYING_FAST_FORWARD, // playing fast in the forward direction, with no audio + // parameter specifies the number of frames to skip forwards after each frame + LDSTATE_STEPPING_REVERSE, // single frame stepping in the reverse direction + LDSTATE_STEPPING_FORWARD, // single frame stepping in the forward direction + LDSTATE_SCANNING, // scanning in the forward or reverse direction + // parameter(0:7) controls how many vsyncs until revert to savestate + // parameter(8:31) specifies the speed + LDSTATE_SEEKING, // seeking to a specific frame + // parameter specifies the target frame + LDSTATE_OTHER // other states start here + }; + + // slider position + enum slider_position + { + SLIDER_MINIMUM, // at the minimum value + SLIDER_VIRTUAL_LEADIN, // within the virtual lead-in area + SLIDER_CHD, // within the boundaries of the CHD + SLIDER_OUTSIDE_CHD, // outside of the CHD area but before the virtual lead-out area + SLIDER_VIRTUAL_LEADOUT, // within the virtual lead-out area + SLIDER_MAXIMUM // at the maximum value + }; + + // information about the current player state + struct player_state_info + { + player_state m_state; // current state + INT32 m_substate; // internal sub-state; starts at 0 on any state change + INT32 m_param; // parameter for current state + attotime m_endtime; // minimum ending time for current state + }; + + // subclass overrides + virtual void player_vsync(const vbi_metadata &vbi, int fieldnum, const attotime &curtime) = 0; + virtual INT32 player_update(const vbi_metadata &vbi, int fieldnum, const attotime &curtime) = 0; + virtual void player_overlay(bitmap_yuy16 &bitmap) = 0; + + // device-level overrides + virtual void device_start(); + virtual void device_stop(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + virtual void device_validity_check(validity_checker &valid) const; + + // device_sound_interface overrides + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + + // subclass helpers + void set_audio_squelch(bool squelchleft, bool squelchright) { m_stream->update(); m_audiosquelch = (squelchleft ? 1 : 0) | (squelchright ? 2 : 0); } + void set_video_squelch(bool squelch) { m_videosquelch = squelch; } + void set_slider_speed(INT32 tracks_per_vsync); + void advance_slider(INT32 numtracks); + slider_position get_slider_position(); + INT32 generic_update(const vbi_metadata &vbi, int fieldnum, const attotime &curtime, player_state_info &curstate); + + // general helpers + bool is_start_of_frame(const vbi_metadata &vbi); + int frame_from_metadata(const vbi_metadata &metadata); + int chapter_from_metadata(const vbi_metadata &metadata); + + player_state_info m_player_state; // active state + player_state_info m_saved_state; // saved state during temporary operations + +private: + // internal type definitions + struct frame_data + { + bitmap_yuy16 m_bitmap; // cached bitmap + bitmap_yuy16 m_visbitmap; // wrapper around bitmap with only visible lines + UINT8 m_numfields; // number of fields in this frame + INT32 m_lastfield; // last absolute field number + }; + + // internal helpers + void init_disc(); + void init_video(); + void init_audio(); + void add_and_clamp_track(INT32 delta) { m_curtrack += delta; m_curtrack = MAX(m_curtrack, 1); m_curtrack = MIN(m_curtrack, m_maxtrack - 1); } + void fillbitmap_yuy16(bitmap_yuy16 &bitmap, UINT8 yval, UINT8 cr, UINT8 cb); + void update_slider_pos(); + void vblank_state_changed(screen_device &screen, bool vblank_state); + frame_data ¤t_frame(); + void read_track_data(); + static void *read_async_static(void *param, int threadid); + void process_track_data(); + void config_load(int config_type, xml_data_node *parentnode); + void config_save(int config_type, xml_data_node *parentnode); + + // configuration + laserdisc_get_disc_delegate m_getdisc_callback; + laserdisc_audio_delegate m_audio_callback; // audio streaming callback + laserdisc_overlay_config m_orig_config; // original overlay configuration + UINT32 m_overwidth; // overlay screen width + UINT32 m_overheight; // overlay screen height + rectangle m_overclip; // overlay visarea + screen_update_ind16_delegate m_overupdate_ind16; // overlay update delegate + screen_update_rgb32_delegate m_overupdate_rgb32; // overlay update delegate + + // disc parameters + chd_file * m_disc; // handle to the disc itself + dynamic_buffer m_vbidata; // pointer to precomputed VBI data + int m_width; // width of video + int m_height; // height of video + UINT32 m_fps_times_1million; // frame rate of video + int m_samplerate; // audio samplerate + int m_readresult; // result of the most recent read + UINT32 m_chdtracks; // number of tracks in the CHD + avhuff_decompress_config m_avhuff_config; // decompression configuration + + // async operations + osd_work_queue * m_work_queue; // work queue + UINT32 m_queued_hunknum; // queued hunk + + // core states + UINT8 m_audiosquelch; // audio squelch state: bit 0 = audio 1, bit 1 = audio 2 + UINT8 m_videosquelch; // video squelch state: bit 0 = on/off + UINT8 m_fieldnum; // field number (0 or 1) + INT32 m_curtrack; // current track at this end of this vsync + UINT32 m_maxtrack; // maximum track number + attoseconds_t m_attospertrack; // attoseconds per track, or 0 if not moving + attotime m_sliderupdate; // time of last slider update + + // video data + frame_data m_frame[3]; // circular list of frames + UINT8 m_videoindex; // index of the current video buffer + bitmap_yuy16 m_emptyframe; // blank frame + + // audio data + sound_stream * m_stream; + std::vector m_audiobuffer[2]; // buffer for audio samples + UINT32 m_audiobufsize; // size of buffer + UINT32 m_audiobufin; // input index + UINT32 m_audiobufout; // output index + UINT32 m_audiocursamples; // current samples this track + UINT32 m_audiomaxsamples; // maximum samples per track + + // metadata + vbi_metadata m_metadata[2]; // metadata parsed from the stream, for each field + + // video updating + bool m_videoenable; // is video enabled? + render_texture * m_videotex; // texture for the video + palette_t * m_videopalette; // palette for the video + + // overlays + bool m_overenable; // is the overlay enabled? + screen_bitmap m_overbitmap[2]; // overlay bitmaps + int m_overindex; // index of the overlay bitmap + render_texture * m_overtex; // texture for the overlay + optional_device m_overlay_palette; // overlay screen palette +}; + +// iterator - interface iterator works for subclasses too +typedef device_interface_iterator laserdisc_device_iterator; + + + +//************************************************************************** +// INLINE FUNCTIONS +//************************************************************************** + +//------------------------------------------------- +// is_start_of_frame - return true if this is +// the start of a frame +//------------------------------------------------- + +inline bool laserdisc_device::is_start_of_frame(const vbi_metadata &vbi) +{ + // is it not known if the white flag or the presence of a frame code + // determines the start of frame; the former seems to be the "official" + // way, but the latter seems to be the practical implementation + return (vbi.white || (vbi.line1718 & VBI_MASK_CAV_PICTURE) == VBI_CODE_CAV_PICTURE); +} + + +//------------------------------------------------- +// frame_from_metadata - return the frame number +// encoded in the metadata, if present, or +// FRAME_NOT_PRESENT +//------------------------------------------------- + +inline int laserdisc_device::frame_from_metadata(const vbi_metadata &metadata) +{ + if ((metadata.line1718 & VBI_MASK_CAV_PICTURE) == VBI_CODE_CAV_PICTURE) + return VBI_CAV_PICTURE(metadata.line1718); + else if (metadata.line1718 == VBI_CODE_LEADIN) + return FRAME_LEAD_IN; + else if (metadata.line1718 == VBI_CODE_LEADOUT) + return FRAME_LEAD_OUT; + return FRAME_NOT_PRESENT; +} + + +//------------------------------------------------- +// chapter_from_metadata - return the chapter +// number encoded in the metadata, if present, +// or CHAPTER_NOT_PRESENT +//------------------------------------------------- + +inline int laserdisc_device::chapter_from_metadata(const vbi_metadata &metadata) +{ + if ((metadata.line1718 & VBI_MASK_CHAPTER) == VBI_CODE_CHAPTER) + return VBI_CHAPTER(metadata.line1718); + else if (metadata.line1718 == VBI_CODE_LEADIN) + return CHAPTER_LEAD_IN; + else if (metadata.line1718 == VBI_CODE_LEADOUT) + return CHAPTER_LEAD_OUT; + return CHAPTER_NOT_PRESENT; +} + + +#endif diff --git a/src/devices/machine/latch.c b/src/devices/machine/latch.c new file mode 100644 index 00000000000..55aaf7dfeba --- /dev/null +++ b/src/devices/machine/latch.c @@ -0,0 +1,122 @@ +// license:BSD-3-Clause +// copyright-holders:smf +#include "emu.h" +#include "latch.h" + +const device_type OUTPUT_LATCH = &device_creator; + +output_latch_device::output_latch_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, OUTPUT_LATCH, "Output Latch", tag, owner, clock, "output_latch", __FILE__), + m_resolved(false), + m_bit0(-1), + m_bit1(-1), + m_bit2(-1), + m_bit3(-1), + m_bit4(-1), + m_bit5(-1), + m_bit6(-1), + m_bit7(-1), + m_bit0_handler(*this), + m_bit1_handler(*this), + m_bit2_handler(*this), + m_bit3_handler(*this), + m_bit4_handler(*this), + m_bit5_handler(*this), + m_bit6_handler(*this), + m_bit7_handler(*this) +{ +} + +void output_latch_device::device_start() +{ + save_item(NAME(m_bit0)); + save_item(NAME(m_bit1)); + save_item(NAME(m_bit2)); + save_item(NAME(m_bit3)); + save_item(NAME(m_bit4)); + save_item(NAME(m_bit5)); + save_item(NAME(m_bit6)); + save_item(NAME(m_bit7)); +} + +void output_latch_device::write(UINT8 data) +{ + if (!m_resolved) + { + // HACK: move to device_config_complete() when devcb supports that + m_bit0_handler.resolve_safe(); + m_bit1_handler.resolve_safe(); + m_bit2_handler.resolve_safe(); + m_bit3_handler.resolve_safe(); + m_bit4_handler.resolve_safe(); + m_bit5_handler.resolve_safe(); + m_bit6_handler.resolve_safe(); + m_bit7_handler.resolve_safe(); + + m_resolved = true; + } + + int bit0 = (data >> 0) & 1; + if (m_bit0 != bit0) + { + m_bit0 = bit0; + if (!m_bit0_handler.isnull()) + m_bit0_handler(bit0); + } + + int bit1 = (data >> 1) & 1; + if (m_bit1 != bit1) + { + m_bit1 = bit1; + if (!m_bit1_handler.isnull()) + m_bit1_handler(bit1); + } + + int bit2 = (data >> 2) & 1; + if (m_bit2 != bit2) + { + m_bit2 = bit2; + if (!m_bit2_handler.isnull()) + m_bit2_handler(bit2); + } + + int bit3 = (data >> 3) & 1; + if (m_bit3 != bit3) + { + m_bit3 = bit3; + if (!m_bit3_handler.isnull()) + m_bit3_handler(bit3); + } + + int bit4 = (data >> 4) & 1; + if (m_bit4 != bit4) + { + m_bit4 = bit4; + if (!m_bit4_handler.isnull()) + m_bit4_handler(bit4); + } + + int bit5 = (data >> 5) & 1; + if (m_bit5 != bit5) + { + m_bit5 = bit5; + if (!m_bit5_handler.isnull()) + m_bit5_handler(bit5); + } + + int bit6 = (data >> 6) & 1; + if (m_bit6 != bit6) + { + m_bit6 = bit6; + if (!m_bit6_handler.isnull()) + m_bit6_handler(bit6); + } + + int bit7 = (data >> 7) & 1; + if (m_bit7 != bit7) + { + m_bit7 = bit7; + if (!m_bit7_handler.isnull()) + m_bit7_handler(bit7); + } +} diff --git a/src/devices/machine/latch.h b/src/devices/machine/latch.h new file mode 100644 index 00000000000..f184fd3a865 --- /dev/null +++ b/src/devices/machine/latch.h @@ -0,0 +1,74 @@ +// license:BSD-3-Clause +// copyright-holders:smf +#ifndef __LATCH_H__ +#define __LATCH_H__ + +#define MCFG_OUTPUT_LATCH_BIT0_HANDLER(_devcb) \ + devcb = &output_latch_device::set_bit0_handler(*device, DEVCB_##_devcb); + +#define MCFG_OUTPUT_LATCH_BIT1_HANDLER(_devcb) \ + devcb = &output_latch_device::set_bit1_handler(*device, DEVCB_##_devcb); + +#define MCFG_OUTPUT_LATCH_BIT2_HANDLER(_devcb) \ + devcb = &output_latch_device::set_bit2_handler(*device, DEVCB_##_devcb); + +#define MCFG_OUTPUT_LATCH_BIT3_HANDLER(_devcb) \ + devcb = &output_latch_device::set_bit3_handler(*device, DEVCB_##_devcb); + +#define MCFG_OUTPUT_LATCH_BIT4_HANDLER(_devcb) \ + devcb = &output_latch_device::set_bit4_handler(*device, DEVCB_##_devcb); + +#define MCFG_OUTPUT_LATCH_BIT5_HANDLER(_devcb) \ + devcb = &output_latch_device::set_bit5_handler(*device, DEVCB_##_devcb); + +#define MCFG_OUTPUT_LATCH_BIT6_HANDLER(_devcb) \ + devcb = &output_latch_device::set_bit6_handler(*device, DEVCB_##_devcb); + +#define MCFG_OUTPUT_LATCH_BIT7_HANDLER(_devcb) \ + devcb = &output_latch_device::set_bit7_handler(*device, DEVCB_##_devcb); + +class output_latch_device : public device_t +{ +public: + output_latch_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + template static devcb_base &set_bit0_handler(device_t &device, _Object object) { return downcast(device).m_bit0_handler.set_callback(object); } + template static devcb_base &set_bit1_handler(device_t &device, _Object object) { return downcast(device).m_bit1_handler.set_callback(object); } + template static devcb_base &set_bit2_handler(device_t &device, _Object object) { return downcast(device).m_bit2_handler.set_callback(object); } + template static devcb_base &set_bit3_handler(device_t &device, _Object object) { return downcast(device).m_bit3_handler.set_callback(object); } + template static devcb_base &set_bit4_handler(device_t &device, _Object object) { return downcast(device).m_bit4_handler.set_callback(object); } + template static devcb_base &set_bit5_handler(device_t &device, _Object object) { return downcast(device).m_bit5_handler.set_callback(object); } + template static devcb_base &set_bit6_handler(device_t &device, _Object object) { return downcast(device).m_bit6_handler.set_callback(object); } + template static devcb_base &set_bit7_handler(device_t &device, _Object object) { return downcast(device).m_bit7_handler.set_callback(object); } + + void write(UINT8 data); + DECLARE_WRITE8_MEMBER(write) { write(data); } + +protected: + virtual void device_start(); + +private: + bool m_resolved; + + int m_bit0; + int m_bit1; + int m_bit2; + int m_bit3; + int m_bit4; + int m_bit5; + int m_bit6; + int m_bit7; + + devcb_write_line m_bit0_handler; + devcb_write_line m_bit1_handler; + devcb_write_line m_bit2_handler; + devcb_write_line m_bit3_handler; + devcb_write_line m_bit4_handler; + devcb_write_line m_bit5_handler; + devcb_write_line m_bit6_handler; + devcb_write_line m_bit7_handler; +}; + +extern const device_type OUTPUT_LATCH; + +#endif diff --git a/src/devices/machine/latch8.c b/src/devices/machine/latch8.c new file mode 100644 index 00000000000..9213f8e50c6 --- /dev/null +++ b/src/devices/machine/latch8.c @@ -0,0 +1,247 @@ +// license:BSD-3-Clause +// copyright-holders:Couriersud +/********************************************************************** + + 8 bit latch interface and emulation + + 2008/08 couriersud + +**********************************************************************/ + +#include "emu.h" +#include "latch8.h" + +void latch8_device::update(UINT8 new_val, UINT8 mask) +{ + UINT8 old_val = m_value; + + m_value = (m_value & ~mask) | (new_val & mask); + + if (m_has_write) + { + int i; + UINT8 changed = old_val ^ m_value; + for (i=0; i<8; i++) + if (((changed & (1<generic_space(), m_offset[i] , (m_value >> i) & 1); + if (i==1 && !m_write_1.isnull()) m_write_1(machine().driver_data()->generic_space(), m_offset[i] , (m_value >> i) & 1); + if (i==2 && !m_write_2.isnull()) m_write_2(machine().driver_data()->generic_space(), m_offset[i] , (m_value >> i) & 1); + if (i==3 && !m_write_3.isnull()) m_write_3(machine().driver_data()->generic_space(), m_offset[i] , (m_value >> i) & 1); + if (i==4 && !m_write_4.isnull()) m_write_4(machine().driver_data()->generic_space(), m_offset[i] , (m_value >> i) & 1); + if (i==5 && !m_write_5.isnull()) m_write_5(machine().driver_data()->generic_space(), m_offset[i] , (m_value >> i) & 1); + if (i==6 && !m_write_6.isnull()) m_write_6(machine().driver_data()->generic_space(), m_offset[i] , (m_value >> i) & 1); + if (i==7 && !m_write_7.isnull()) m_write_7(machine().driver_data()->generic_space(), m_offset[i] , (m_value >> i) & 1); + } + } +} + +TIMER_CALLBACK_MEMBER( latch8_device::timerproc ) +{ + UINT8 new_val = param & 0xFF; + UINT8 mask = param >> 8; + + update( new_val, mask); +} + +/* ----------------------------------------------------------------------- */ + +READ8_MEMBER( latch8_device::read ) +{ + UINT8 res; + + assert(offset == 0); + + res = m_value; + if (m_has_read) + { + int i; + for (i=0; i<8; i++) + { + if (i==0 && !m_read_0.isnull()) { res &= ~( 1 << i); res |= ((m_read_0(space, 0, 0xff) >> m_offset[i]) & 0x01) << i; } + if (i==1 && !m_read_1.isnull()) { res &= ~( 1 << i); res |= ((m_read_1(space, 0, 0xff) >> m_offset[i]) & 0x01) << i; } + if (i==2 && !m_read_2.isnull()) { res &= ~( 1 << i); res |= ((m_read_2(space, 0, 0xff) >> m_offset[i]) & 0x01) << i; } + if (i==3 && !m_read_3.isnull()) { res &= ~( 1 << i); res |= ((m_read_3(space, 0, 0xff) >> m_offset[i]) & 0x01) << i; } + if (i==4 && !m_read_4.isnull()) { res &= ~( 1 << i); res |= ((m_read_4(space, 0, 0xff) >> m_offset[i]) & 0x01) << i; } + if (i==5 && !m_read_5.isnull()) { res &= ~( 1 << i); res |= ((m_read_5(space, 0, 0xff) >> m_offset[i]) & 0x01) << i; } + if (i==6 && !m_read_6.isnull()) { res &= ~( 1 << i); res |= ((m_read_6(space, 0, 0xff) >> m_offset[i]) & 0x01) << i; } + if (i==7 && !m_read_7.isnull()) { res &= ~( 1 << i); res |= ((m_read_7(space, 0, 0xff) >> m_offset[i]) & 0x01) << i;} + } + } + return (res & ~m_maskout) ^ m_xorvalue; +} + + +WRITE8_MEMBER( latch8_device::write ) +{ + assert(offset == 0); + + if (m_nosync != 0xff) + machine().scheduler().synchronize(timer_expired_delegate(FUNC(latch8_device::timerproc),this), (0xFF << 8) | data); + else + update(data, 0xFF); +} + + +WRITE8_MEMBER( latch8_device::reset_w ) +{ + assert(offset == 0); + + m_value = 0; +} + +/* read bit x */ +/* return (latch >> x) & 0x01 */ + +UINT8 latch8_device::bitx_r( offs_t offset, int bit) +{ + assert( offset == 0); + + return (m_value >> bit) & 0x01; +} + +READ8_MEMBER( latch8_device::bit0_r) { return bitx_r(offset, 0); } +READ8_MEMBER( latch8_device::bit1_r) { return bitx_r(offset, 1); } +READ8_MEMBER( latch8_device::bit2_r) { return bitx_r(offset, 2); } +READ8_MEMBER( latch8_device::bit3_r) { return bitx_r(offset, 3); } +READ8_MEMBER( latch8_device::bit4_r) { return bitx_r(offset, 4); } +READ8_MEMBER( latch8_device::bit5_r) { return bitx_r(offset, 5); } +READ8_MEMBER( latch8_device::bit6_r) { return bitx_r(offset, 6); } +READ8_MEMBER( latch8_device::bit7_r) { return bitx_r(offset, 7); } + +READ8_MEMBER( latch8_device::bit0_q_r) { return bitx_r(offset, 0) ^ 1; } +READ8_MEMBER( latch8_device::bit1_q_r) { return bitx_r(offset, 1) ^ 1; } +READ8_MEMBER( latch8_device::bit2_q_r) { return bitx_r(offset, 2) ^ 1; } +READ8_MEMBER( latch8_device::bit3_q_r) { return bitx_r(offset, 3) ^ 1; } +READ8_MEMBER( latch8_device::bit4_q_r) { return bitx_r(offset, 4) ^ 1; } +READ8_MEMBER( latch8_device::bit5_q_r) { return bitx_r(offset, 5) ^ 1; } +READ8_MEMBER( latch8_device::bit6_q_r) { return bitx_r(offset, 6) ^ 1; } +READ8_MEMBER( latch8_device::bit7_q_r) { return bitx_r(offset, 7) ^ 1; } + +/* write bit x from data into bit determined by offset */ +/* latch = (latch & ~(1<> x) & 0x01) << offset) */ + +void latch8_device::bitx_w(int bit, offs_t offset, UINT8 data) +{ + UINT8 mask = (1<> bit) & 0x01) << offset); + + assert( offset < 8); + + /* No need to synchronize ? */ + if (m_nosync & mask) + update(masked_data, mask); + else + machine().scheduler().synchronize(timer_expired_delegate(FUNC(latch8_device::timerproc),this), (mask << 8) | masked_data); +} + +WRITE8_MEMBER( latch8_device::bit0_w ) { bitx_w(0, offset, data); } +WRITE8_MEMBER( latch8_device::bit1_w ) { bitx_w(1, offset, data); } +WRITE8_MEMBER( latch8_device::bit2_w ) { bitx_w(2, offset, data); } +WRITE8_MEMBER( latch8_device::bit3_w ) { bitx_w(3, offset, data); } +WRITE8_MEMBER( latch8_device::bit4_w ) { bitx_w(4, offset, data); } +WRITE8_MEMBER( latch8_device::bit5_w ) { bitx_w(5, offset, data); } +WRITE8_MEMBER( latch8_device::bit6_w ) { bitx_w(6, offset, data); } +WRITE8_MEMBER( latch8_device::bit7_w ) { bitx_w(7, offset, data); } + +const device_type LATCH8 = &device_creator; + +latch8_device::latch8_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, LATCH8, "8 bit latch", tag, owner, clock, "latch8", __FILE__), + m_value(0), + m_has_write(0), + m_has_read(0), + m_maskout(0), + m_xorvalue(0), + m_nosync(0), + m_write_0(*this), + m_write_1(*this), + m_write_2(*this), + m_write_3(*this), + m_write_4(*this), + m_write_5(*this), + m_write_6(*this), + m_write_7(*this), + m_read_0(*this), + m_read_1(*this), + m_read_2(*this), + m_read_3(*this), + m_read_4(*this), + m_read_5(*this), + m_read_6(*this), + m_read_7(*this) +{ + memset(m_offset, 0, sizeof(m_offset)); +} + + +//------------------------------------------------- +// device_validity_check - validate device +// configuration +//------------------------------------------------- + +void latch8_device::device_validity_check(validity_checker &valid) const +{ + if (!m_read_0.isnull() && !m_write_0.isnull()) osd_printf_error("Device %s: Bit 0 already has a handler.\n", tag()); + if (!m_read_1.isnull() && !m_write_1.isnull()) osd_printf_error("Device %s: Bit 1 already has a handler.\n", tag()); + if (!m_read_2.isnull() && !m_write_2.isnull()) osd_printf_error("Device %s: Bit 2 already has a handler.\n", tag()); + if (!m_read_3.isnull() && !m_write_3.isnull()) osd_printf_error("Device %s: Bit 3 already has a handler.\n", tag()); + if (!m_read_4.isnull() && !m_write_4.isnull()) osd_printf_error("Device %s: Bit 4 already has a handler.\n", tag()); + if (!m_read_5.isnull() && !m_write_5.isnull()) osd_printf_error("Device %s: Bit 5 already has a handler.\n", tag()); + if (!m_read_6.isnull() && !m_write_6.isnull()) osd_printf_error("Device %s: Bit 6 already has a handler.\n", tag()); + if (!m_read_7.isnull() && !m_write_7.isnull()) osd_printf_error("Device %s: Bit 7 already has a handler.\n", tag()); +} +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void latch8_device::device_start() +{ + m_write_0.resolve(); + m_write_1.resolve(); + m_write_2.resolve(); + m_write_3.resolve(); + m_write_4.resolve(); + m_write_5.resolve(); + m_write_6.resolve(); + m_write_7.resolve(); + + m_read_0.resolve(); + m_read_1.resolve(); + m_read_2.resolve(); + m_read_3.resolve(); + m_read_4.resolve(); + m_read_5.resolve(); + m_read_6.resolve(); + m_read_7.resolve(); + + /* setup nodemap */ + if (!m_write_0.isnull()) m_has_write = 1; + if (!m_write_1.isnull()) m_has_write = 1; + if (!m_write_2.isnull()) m_has_write = 1; + if (!m_write_3.isnull()) m_has_write = 1; + if (!m_write_4.isnull()) m_has_write = 1; + if (!m_write_5.isnull()) m_has_write = 1; + if (!m_write_6.isnull()) m_has_write = 1; + if (!m_write_7.isnull()) m_has_write = 1; + + /* setup device read handlers */ + if (!m_read_0.isnull()) m_has_read = 1; + if (!m_read_1.isnull()) m_has_read = 1; + if (!m_read_2.isnull()) m_has_read = 1; + if (!m_read_3.isnull()) m_has_read = 1; + if (!m_read_4.isnull()) m_has_read = 1; + if (!m_read_5.isnull()) m_has_read = 1; + if (!m_read_6.isnull()) m_has_read = 1; + if (!m_read_7.isnull()) m_has_read = 1; + + save_item(NAME(m_value)); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void latch8_device::device_reset() +{ + m_value = 0; +} diff --git a/src/devices/machine/latch8.h b/src/devices/machine/latch8.h new file mode 100644 index 00000000000..6c82bd0689d --- /dev/null +++ b/src/devices/machine/latch8.h @@ -0,0 +1,228 @@ +// license:BSD-3-Clause +// copyright-holders:Couriersud +/********************************************************************** + + 8 bit latch interface and emulation + + Generic emulation of 74LS174/175, 74LS259 and other latches. + Apart from providing synched latch operation, these + latches can be configured to read their input bitwise from other + devices as well and individual bits can be connected to + discrete nodes. + + Please see audio/dkong.c for examples. + +**********************************************************************/ + +#ifndef __LATCH8_H_ +#define __LATCH8_H_ + +#include "sound/discrete.h" + + +/*************************************************************************** + TYPE DEFINITIONS +***************************************************************************/ + +class latch8_device : public device_t +{ +public: + latch8_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + + /* write & read full byte */ + + DECLARE_READ8_MEMBER( read ); + DECLARE_WRITE8_MEMBER( write ); + + /* reset the latch */ + + DECLARE_WRITE8_MEMBER( reset_w ); + + /* read bit x */ + /* return (latch >> x) & 0x01 */ + + DECLARE_READ8_MEMBER( bit0_r ); + DECLARE_READ8_MEMBER( bit1_r ); + DECLARE_READ8_MEMBER( bit2_r ); + DECLARE_READ8_MEMBER( bit3_r ); + DECLARE_READ8_MEMBER( bit4_r ); + DECLARE_READ8_MEMBER( bit5_r ); + DECLARE_READ8_MEMBER( bit6_r ); + DECLARE_READ8_MEMBER( bit7_r ); + + /* read inverted bit x */ + /* return (latch >> x) & 0x01 */ + + DECLARE_READ8_MEMBER( bit0_q_r ); + DECLARE_READ8_MEMBER( bit1_q_r ); + DECLARE_READ8_MEMBER( bit2_q_r ); + DECLARE_READ8_MEMBER( bit3_q_r ); + DECLARE_READ8_MEMBER( bit4_q_r ); + DECLARE_READ8_MEMBER( bit5_q_r ); + DECLARE_READ8_MEMBER( bit6_q_r ); + DECLARE_READ8_MEMBER( bit7_q_r ); + + /* write bit x from data into bit determined by offset */ + /* latch = (latch & ~(1<> x) & 0x01) << offset) */ + + DECLARE_WRITE8_MEMBER( bit0_w ); + DECLARE_WRITE8_MEMBER( bit1_w ); + DECLARE_WRITE8_MEMBER( bit2_w ); + DECLARE_WRITE8_MEMBER( bit3_w ); + DECLARE_WRITE8_MEMBER( bit4_w ); + DECLARE_WRITE8_MEMBER( bit5_w ); + DECLARE_WRITE8_MEMBER( bit6_w ); + DECLARE_WRITE8_MEMBER( bit7_w ); + + static void set_maskout(device_t &device, UINT32 maskout) { downcast(device).m_maskout = maskout; } + static void set_xorvalue(device_t &device, UINT32 xorvalue) { downcast(device).m_xorvalue = xorvalue; } + static void set_nosync(device_t &device, UINT32 nosync) { downcast(device).m_nosync = nosync; } + + template static devcb_base &set_write_0(device_t &device, _Object object, UINT32 offset) { downcast(device).m_offset[0] = offset; return downcast(device).m_write_0.set_callback(object); } + template static devcb_base &set_write_1(device_t &device, _Object object, UINT32 offset) { downcast(device).m_offset[1] = offset; return downcast(device).m_write_1.set_callback(object); } + template static devcb_base &set_write_2(device_t &device, _Object object, UINT32 offset) { downcast(device).m_offset[2] = offset; return downcast(device).m_write_2.set_callback(object); } + template static devcb_base &set_write_3(device_t &device, _Object object, UINT32 offset) { downcast(device).m_offset[3] = offset; return downcast(device).m_write_3.set_callback(object); } + template static devcb_base &set_write_4(device_t &device, _Object object, UINT32 offset) { downcast(device).m_offset[4] = offset; return downcast(device).m_write_4.set_callback(object); } + template static devcb_base &set_write_5(device_t &device, _Object object, UINT32 offset) { downcast(device).m_offset[5] = offset; return downcast(device).m_write_5.set_callback(object); } + template static devcb_base &set_write_6(device_t &device, _Object object, UINT32 offset) { downcast(device).m_offset[6] = offset; return downcast(device).m_write_6.set_callback(object); } + template static devcb_base &set_write_7(device_t &device, _Object object, UINT32 offset) { downcast(device).m_offset[7] = offset; return downcast(device).m_write_7.set_callback(object); } + + template static devcb_base &set_read_0(device_t &device, _Object object, UINT32 offset) { downcast(device).m_offset[0] = offset; return downcast(device).m_read_0.set_callback(object); } + template static devcb_base &set_read_1(device_t &device, _Object object, UINT32 offset) { downcast(device).m_offset[1] = offset; return downcast(device).m_read_1.set_callback(object); } + template static devcb_base &set_read_2(device_t &device, _Object object, UINT32 offset) { downcast(device).m_offset[2] = offset; return downcast(device).m_read_2.set_callback(object); } + template static devcb_base &set_read_3(device_t &device, _Object object, UINT32 offset) { downcast(device).m_offset[3] = offset; return downcast(device).m_read_3.set_callback(object); } + template static devcb_base &set_read_4(device_t &device, _Object object, UINT32 offset) { downcast(device).m_offset[4] = offset; return downcast(device).m_read_4.set_callback(object); } + template static devcb_base &set_read_5(device_t &device, _Object object, UINT32 offset) { downcast(device).m_offset[5] = offset; return downcast(device).m_read_5.set_callback(object); } + template static devcb_base &set_read_6(device_t &device, _Object object, UINT32 offset) { downcast(device).m_offset[6] = offset; return downcast(device).m_read_6.set_callback(object); } + template static devcb_base &set_read_7(device_t &device, _Object object, UINT32 offset) { downcast(device).m_offset[7] = offset; return downcast(device).m_read_7.set_callback(object); } + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_validity_check(validity_checker &valid) const; + + TIMER_CALLBACK_MEMBER( timerproc ); + void update(UINT8 new_val, UINT8 mask); + inline UINT8 bitx_r( offs_t offset, int bit); + inline void bitx_w(int bit, offs_t offset, UINT8 data); +private: + // internal state + UINT8 m_value; + UINT8 m_has_write; + UINT8 m_has_read; + + /* only for byte reads, does not affect bit reads and node_map */ + UINT32 m_maskout; + UINT32 m_xorvalue; /* after mask */ + UINT32 m_nosync; + + devcb_write8 m_write_0; + devcb_write8 m_write_1; + devcb_write8 m_write_2; + devcb_write8 m_write_3; + devcb_write8 m_write_4; + devcb_write8 m_write_5; + devcb_write8 m_write_6; + devcb_write8 m_write_7; + + devcb_read8 m_read_0; + devcb_read8 m_read_1; + devcb_read8 m_read_2; + devcb_read8 m_read_3; + devcb_read8 m_read_4; + devcb_read8 m_read_5; + devcb_read8 m_read_6; + devcb_read8 m_read_7; + + UINT32 m_offset[8]; +}; + +extern const device_type LATCH8; +/*************************************************************************** + DEVICE CONFIGURATION MACROS +***************************************************************************/ + +/* add device */ +#define MCFG_LATCH8_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, LATCH8, 0) + +/* Bit mask specifying bits to be masked *out* */ +#define MCFG_LATCH8_MASKOUT(_maskout) \ + latch8_device::set_maskout(*device, _maskout); + +/* Bit mask specifying bits to be inverted */ +#define MCFG_LATCH8_INVERT(_xor) \ + latch8_device::set_xorvalue(*device, _xor); + +/* Bit mask specifying bits not needing cpu synchronization. */ +#define MCFG_LATCH8_NOSYNC(_nosync) \ + latch8_device::set_nosync(*device, _nosync); + +/* Write bit to discrete node */ +#define MCFG_LATCH8_WRITE_0(_devcb, _node) \ + devcb = &latch8_device::set_write_0(*device, DEVCB_##_devcb, _node); + +#define MCFG_LATCH8_WRITE_1(_devcb, _node) \ + devcb = &latch8_device::set_write_1(*device, DEVCB_##_devcb, _node); + +#define MCFG_LATCH8_WRITE_2(_devcb, _node) \ + devcb = &latch8_device::set_write_2(*device, DEVCB_##_devcb, _node); + +#define MCFG_LATCH8_WRITE_3(_devcb, _node) \ + devcb = &latch8_device::set_write_3(*device, DEVCB_##_devcb, _node); + +#define MCFG_LATCH8_WRITE_4(_devcb, _node) \ + devcb = &latch8_device::set_write_4(*device, DEVCB_##_devcb, _node); + +#define MCFG_LATCH8_WRITE_5(_devcb, _node) \ + devcb = &latch8_device::set_write_5(*device, DEVCB_##_devcb, _node); + +#define MCFG_LATCH8_WRITE_6(_devcb, _node) \ + devcb = &latch8_device::set_write_6(*device, DEVCB_##_devcb, _node); + +#define MCFG_LATCH8_WRITE_7(_devcb, _node) \ + devcb = &latch8_device::set_write_7(*device, DEVCB_##_devcb, _node); + +/* Upon read, replace bits by reading from another device handler */ +#define MCFG_LATCH8_READ_0(_devcb, _from_bit) \ + devcb = &latch8_device::set_read_0(*device, DEVCB_##_devcb, _from_bit); + +#define MCFG_LATCH8_READ_1(_devcb, _from_bit) \ + devcb = &latch8_device::set_read_1(*device, DEVCB_##_devcb, _from_bit); + +#define MCFG_LATCH8_READ_2(_devcb, _from_bit) \ + devcb = &latch8_device::set_read_2(*device, DEVCB_##_devcb, _from_bit); + +#define MCFG_LATCH8_READ_3(_devcb, _from_bit) \ + devcb = &latch8_device::set_read_3(*device, DEVCB_##_devcb, _from_bit); + +#define MCFG_LATCH8_READ_4(_devcb, _from_bit) \ + devcb = &latch8_device::set_read_4(*device, DEVCB_##_devcb, _from_bit); + +#define MCFG_LATCH8_READ_5(_devcb, _from_bit) \ + devcb = &latch8_device::set_read_5(*device, DEVCB_##_devcb, _from_bit); + +#define MCFG_LATCH8_READ_6(_devcb, _from_bit) \ + devcb = &latch8_device::set_read_6(*device, DEVCB_##_devcb, _from_bit); + +#define MCFG_LATCH8_READ_7(_devcb, _from_bit) \ + devcb = &latch8_device::set_read_7(*device, DEVCB_##_devcb, _from_bit); + + +/* Accessor macros */ + +#define AM_LATCH8_READ(_tag) \ + AM_DEVREAD(_tag, latch8_device, read) + +#define AM_LATCH8_READBIT(_tag, _bit) \ + AM_DEVREAD(_tag, latch8_device, bit ## _bit ## _q_r) + +#define AM_LATCH8_WRITE(_tag) \ + AM_DEVWRITE(_tag, latch8_device, write) + +#define AM_LATCH8_READWRITE(_tag) \ + AM_DEVREADWRITE(_tag, latch8_device, read, write) + +#endif /* __LATCH8_H_ */ diff --git a/src/devices/machine/lc89510.c b/src/devices/machine/lc89510.c new file mode 100644 index 00000000000..9ad9f4cb37a --- /dev/null +++ b/src/devices/machine/lc89510.c @@ -0,0 +1,26 @@ +// license:BSD-3-Clause +// copyright-holders:David Haywood +/* LC89510 CD Controller + based off old NeoCD emulator code, adapted to SegaCD, needs reworking to work with NeoCD again + +*/ + + +#include "emu.h" +#include "lc89510.h" + +const device_type LC89510 = &device_creator; + +lc89510_device::lc89510_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, LC89510, "lc89510_device", tag, owner, clock, "lc89510", __FILE__) +{ +} + + +void lc89510_device::device_start() +{ +} + +void lc89510_device::device_reset() +{ +} diff --git a/src/devices/machine/lc89510.h b/src/devices/machine/lc89510.h new file mode 100644 index 00000000000..4866cb24f76 --- /dev/null +++ b/src/devices/machine/lc89510.h @@ -0,0 +1,23 @@ +// license:BSD-3-Clause +// copyright-holders:David Haywood + + + +class lc89510_device : public device_t +{ +public: + lc89510_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + + +protected: + virtual void device_start(); + virtual void device_reset(); + +private: + + +}; + + +extern const device_type LC89510; diff --git a/src/devices/machine/ldpr8210.c b/src/devices/machine/ldpr8210.c new file mode 100644 index 00000000000..967dac974e7 --- /dev/null +++ b/src/devices/machine/ldpr8210.c @@ -0,0 +1,1107 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/************************************************************************* + + ldpr8210.c + + Pioneer PR-8210 laserdisc emulation. + +************************************************************************** + + Still to do: + + * implement SLOW TRG + * figure out Simutrek without jump hack + * figure out serial protocol issues (current hack works nicely) + * determine actual slow/fast speeds + +*************************************************************************/ + + +#include "emu.h" +#include "ldpr8210.h" + + + +//************************************************************************** +// DEBUGGING +//************************************************************************** + +#define LOG_VBLANK_VBI 0 +#define LOG_SERIAL 0 +#define LOG_SIMUTREK 0 + + + +//************************************************************************** +// CONSTANTS +//************************************************************************** + +// Overlay constants, related to 720-pixel wide capture +#define OVERLAY_GROUP0_X (82.0f / 720.0f) +#define OVERLAY_GROUP1_X (162.0f / 720.0f) +#define OVERLAY_GROUP2_X (322.0f / 720.0f) +#define OVERLAY_GROUP3_X (483.0f / 720.0f) +#define OVERLAY_Y (104/2) +#define OVERLAY_PIXEL_WIDTH (4.5f / 720.0f) +#define OVERLAY_PIXEL_HEIGHT 2 +#define OVERLAY_X_PIXELS 5 +#define OVERLAY_Y_PIXELS 7 + +// scanning speeds +#define SCAN_SPEED (2000 / 30) // 2000 frames/second +#define SEEK_FAST_SPEED (4000 / 30) // 4000 frames/second + +// serial timing, mostly from the service manual, derived from the XTAL +#define SERIAL_CLOCK XTAL_455kHz +#define SERIAL_0_BIT_TIME attotime::from_hz((double)SERIAL_CLOCK / 512) +#define SERIAL_1_BIT_TIME attotime::from_hz((double)SERIAL_CLOCK / 1024) +#define SERIAL_MIDPOINT_TIME attotime::from_hz((double)SERIAL_CLOCK / 600) +#define SERIAL_MAX_BIT_TIME attotime::from_hz((double)SERIAL_CLOCK / 4096) +#define SERIAL_MAX_WORD_TIME attotime::from_hz((double)SERIAL_CLOCK / 11520) +#define SERIAL_REJECT_DUPLICATE_TIME attotime::from_hz((double)SERIAL_CLOCK / 11520 / 4) + + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +// devices +const device_type PIONEER_PR8210 = &device_creator; +const device_type SIMUTREK_SPECIAL = &device_creator; + + +// bitmaps for the characters +static const UINT8 text_bitmap[0x40][7] = +{ + { 0 }, // @ + { 0x20,0x50,0x88,0x88,0xf8,0x88,0x88 }, // A + { 0 }, // B + { 0x70,0x88,0x80,0x80,0x80,0x88,0x70 }, // C + { 0 }, // D + { 0xf8,0x80,0x80,0xf0,0x80,0x80,0xf8 }, // E + { 0xf8,0x80,0x80,0xf0,0x80,0x80,0x80 }, // F + { 0 }, // G + { 0x88,0x88,0x88,0xf8,0x88,0x88,0x88 }, // H + { 0 }, // I + { 0 }, // J + { 0 }, // K + { 0 }, // L + { 0x88,0xd8,0xa8,0xa8,0xa8,0x88,0x88 }, // M + { 0 }, // N + { 0 }, // O + { 0xf0,0x88,0x88,0xf0,0x80,0x80,0x80 }, // P + { 0 }, // Q + { 0xf0,0x88,0x88,0xf0,0xa0,0x90,0x88 }, // R + { 0x70,0x88,0x80,0x70,0x08,0x88,0x70 }, // S + { 0 }, // T + { 0 }, // U + { 0 }, // V + { 0 }, // W + { 0 }, // X + { 0 }, // Y + { 0 }, // Z + { 0 }, // [ + { 0 }, // + { 0 }, // ] + { 0 }, // ^ + { 0 }, // _ + + { 0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, // + { 0 }, // ! + { 0 }, // " + { 0 }, // # + { 0 }, // $ + { 0 }, // % + { 0 }, // & + { 0 }, // ' + { 0 }, // ( + { 0 }, // ) + { 0 }, // * + { 0 }, // + + { 0 }, // , + { 0 }, // - + { 0x00,0x00,0x00,0x00,0x00,0x00,0x40 }, // . + { 0 }, // / + { 0x70,0x88,0x88,0x88,0x88,0x88,0x70 }, // 0 + { 0x20,0x60,0x20,0x20,0x20,0x20,0x70 }, // 1 + { 0x70,0x88,0x08,0x70,0x80,0x80,0xf8 }, // 2 + { 0xf8,0x08,0x10,0x30,0x08,0x88,0x70 }, // 3 + { 0x10,0x30,0x50,0x90,0xf8,0x10,0x10 }, // 4 + { 0xf8,0x80,0xf0,0x08,0x08,0x88,0x70 }, // 5 + { 0x78,0x80,0x80,0xf0,0x88,0x88,0x70 }, // 6 + { 0xf8,0x08,0x08,0x10,0x20,0x40,0x80 }, // 7 + { 0x70,0x88,0x88,0x70,0x88,0x88,0x70 }, // 8 + { 0x70,0x88,0x88,0x78,0x08,0x08,0xf0 }, // 9 + { 0 }, // : + { 0 }, // ; + { 0 }, // < + { 0 }, // = + { 0 }, // > + { 0 } // ? +}; + + + +//************************************************************************** +// PR-8210 ROM AND MACHINE INTERFACES +//************************************************************************** + +static ADDRESS_MAP_START( pr8210_portmap, AS_IO, 8, pioneer_pr8210_device ) + AM_RANGE(0x00, 0xff) AM_READWRITE(i8049_pia_r, i8049_pia_w) + AM_RANGE(MCS48_PORT_BUS, MCS48_PORT_BUS) AM_READ(i8049_bus_r) + AM_RANGE(MCS48_PORT_P1, MCS48_PORT_P1) AM_WRITE(i8049_port1_w) + AM_RANGE(MCS48_PORT_P2, MCS48_PORT_P2) AM_WRITE(i8049_port2_w) + AM_RANGE(MCS48_PORT_T0, MCS48_PORT_T0) AM_READ(i8049_t0_r) + AM_RANGE(MCS48_PORT_T1, MCS48_PORT_T1) AM_READ(i8049_t1_r) +ADDRESS_MAP_END + + +static MACHINE_CONFIG_FRAGMENT( pr8210 ) + MCFG_CPU_ADD("pr8210", I8049, XTAL_4_41MHz) + MCFG_CPU_IO_MAP(pr8210_portmap) +MACHINE_CONFIG_END + + +ROM_START( pr8210 ) + ROM_REGION( 0x800, "pr8210", 0 ) + ROM_LOAD( "pr-8210_mcu_ud6005a.bin", 0x000, 0x800, CRC(120fa83b) SHA1(b514326ca1f52d6d89056868f9d17eabd4e3f31d) ) +ROM_END + + + +//************************************************************************** +// PIONEER PR-8210 IMPLEMENTATION +//************************************************************************** + +//------------------------------------------------- +// pioneer_pr8210_device - constructor +//------------------------------------------------- + +pioneer_pr8210_device::pioneer_pr8210_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : laserdisc_device(mconfig, PIONEER_PR8210, "Pioneer PR-8210", tag, owner, clock, "pr8210", __FILE__), + m_control(0), + m_lastcommand(0), + m_accumulator(0), + m_lastcommandtime(attotime::zero), + m_lastbittime(attotime::zero), + m_firstbittime(attotime::zero), + m_i8049_cpu(*this, "pr8210"), + m_slowtrg(attotime::zero), + m_vsync(false), + m_i8049_port1(0), + m_i8049_port2(0) +{ +} + +pioneer_pr8210_device::pioneer_pr8210_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : laserdisc_device(mconfig, type, name, tag, owner, clock, shortname, source), + m_control(0), + m_lastcommand(0), + m_accumulator(0), + m_lastcommandtime(attotime::zero), + m_lastbittime(attotime::zero), + m_firstbittime(attotime::zero), + m_i8049_cpu(*this, "pr8210"), + m_slowtrg(attotime::zero), + m_vsync(false), + m_i8049_port1(0), + m_i8049_port2(0) +{ +} + + +//------------------------------------------------- +// control_w - write callback when the CONTROL +// line is toggled +//------------------------------------------------- + +void pioneer_pr8210_device::control_w(UINT8 data) +{ + // set the new value and remember the last + UINT8 prev = m_control; + m_control = data; + + // handle rising edge + if (prev != ASSERT_LINE && data == ASSERT_LINE) + { + // get the time difference from the last assert + // and update our internal command time + attotime curtime = machine().time(); + attotime delta = curtime - m_lastbittime; + m_lastbittime = curtime; + + // if we timed out since the first bit, reset the accumulator + attotime overalldelta = curtime - m_firstbittime; + if (overalldelta > SERIAL_MAX_WORD_TIME || delta > SERIAL_MAX_BIT_TIME) + { + m_firstbittime = curtime; + m_accumulator = 0x5555; + if (LOG_SERIAL) + printf("Reset accumulator\n"); + } + + // 0 bit delta is 1.05 msec, 1 bit delta is 2.11 msec + int longpulse = (delta < SERIAL_MIDPOINT_TIME) ? 0 : 1; + m_accumulator = (m_accumulator << 1) | longpulse; + + // log the deltas for debugging + if (LOG_SERIAL) + { + int usecdiff = (int)(delta.attoseconds() / ATTOSECONDS_IN_USEC(1)); + printf("bitdelta = %5d (%d) - accum = %04X\n", usecdiff, longpulse, m_accumulator); + } + + // if we have a complete command, signal it + // a complete command is 0,0,1 followed by 5 bits, followed by 0,0 + if ((m_accumulator & 0x383) == 0x80) + { + // data is stored to the PIA in bit-reverse order + UINT8 newcommand = (m_accumulator >> 2) & 0x1f; + m_pia.porta = BITSWAP8(newcommand, 0,1,2,3,4,5,6,7); + + // the MCU logic requires a 0 to execute many commands; however, nobody + // consistently sends a 0, whereas they do tend to send duplicate commands... + // if we assume that each duplicate causes a 0, we get the correct results + attotime rejectuntil = m_lastcommandtime + SERIAL_REJECT_DUPLICATE_TIME; + m_lastcommandtime = curtime; + if (m_pia.porta == m_lastcommand && curtime < rejectuntil) + m_pia.porta = 0x00; + else + m_lastcommand = m_pia.porta; + + // log the command and wait for a keypress + if (LOG_SERIAL) + printf("--- Command = %02X\n", m_pia.porta >> 3); + + // reset the first bit time so that the accumulator clears on the next write + m_firstbittime = curtime - SERIAL_MAX_WORD_TIME; + } + } +} + + +//------------------------------------------------- +// device_start - device initialization +//------------------------------------------------- + +void pioneer_pr8210_device::device_start() +{ + // pass through to the parent + laserdisc_device::device_start(); +} + + +//------------------------------------------------- +// device_reset - device reset +//------------------------------------------------- + +void pioneer_pr8210_device::device_reset() +{ + // pass through to the parent + laserdisc_device::device_reset(); + + // reset our state + attotime curtime = machine().time(); + m_lastcommandtime = curtime; + m_firstbittime = curtime; + m_lastbittime = curtime; + m_slowtrg = curtime; +} + + +//------------------------------------------------- +// device_timer - handle timers set by this +// device +//------------------------------------------------- + +void pioneer_pr8210_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch (id) + { + // update the VBI data in the PIA as soon as it is ready; + // this must happen early in the frame because the player + // logic relies on fetching it here + case TID_VBI_DATA_FETCH: + + // logging + if (LOG_VBLANK_VBI) + { + UINT32 line1718 = get_field_code(LASERDISC_CODE_LINE1718, FALSE); + if ((line1718 & VBI_MASK_CAV_PICTURE) == VBI_CODE_CAV_PICTURE) + printf("%3d:VBI(%05d)\n", screen().vpos(), VBI_CAV_PICTURE(line1718)); + else + printf("%3d:VBI()\n", screen().vpos()); + } + + // update PIA registers based on vbi code + m_pia.vbi1 = 0xff; + m_pia.vbi2 = 0xff; + if (focus_on() && laser_on()) + { + UINT32 line16 = get_field_code(LASERDISC_CODE_LINE16, FALSE); + UINT32 line1718 = get_field_code(LASERDISC_CODE_LINE1718, FALSE); + if (line1718 == VBI_CODE_LEADIN) + m_pia.vbi1 &= ~0x01; + if (line1718 == VBI_CODE_LEADOUT) + m_pia.vbi1 &= ~0x02; + if (line16 == VBI_CODE_STOP) + m_pia.vbi1 &= ~0x04; + // unsure what this bit means: m_pia.vbi1 &= ~0x08; + if ((line1718 & VBI_MASK_CAV_PICTURE) == VBI_CODE_CAV_PICTURE) + { + m_pia.vbi1 &= ~0x10; + m_pia.frame[2] = 0xf0 | ((line1718 >> 16) & 0x07); + m_pia.frame[3] = 0xf0 | ((line1718 >> 12) & 0x0f); + m_pia.frame[4] = 0xf0 | ((line1718 >> 8) & 0x0f); + m_pia.frame[5] = 0xf0 | ((line1718 >> 4) & 0x0f); + m_pia.frame[6] = 0xf0 | ((line1718 >> 0) & 0x0f); + } + if ((line1718 & VBI_MASK_CHAPTER) == VBI_CODE_CHAPTER) + { + m_pia.vbi2 &= ~0x01; + m_pia.frame[0] = 0xf0 | ((line1718 >> 16) & 0x07); + m_pia.frame[1] = 0xf0 | ((line1718 >> 12) & 0x0f); + } + } + break; + + // clear the VSYNC flag + case TID_VSYNC_OFF: + m_vsync = false; + break; + + // pass everything else onto the parent + default: + laserdisc_device::device_timer(timer, id, param, ptr); + break; + } +} + + +//------------------------------------------------- +// device_rom_region - return a pointer to our +// ROM region definitions +//------------------------------------------------- + +const rom_entry *pioneer_pr8210_device::device_rom_region() const +{ + return ROM_NAME(pr8210); +} + + +//------------------------------------------------- +// device_mconfig_additions - return a pointer to +// our machine config fragment +//------------------------------------------------- + +machine_config_constructor pioneer_pr8210_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME(pr8210); +} + + +//------------------------------------------------- +// player_vsync - VSYNC callback, called at the +// start of the blanking period +//------------------------------------------------- + +void pioneer_pr8210_device::player_vsync(const vbi_metadata &vbi, int fieldnum, const attotime &curtime) +{ + // logging + if (LOG_VBLANK_VBI) + { + if ((vbi.line1718 & VBI_MASK_CAV_PICTURE) == VBI_CODE_CAV_PICTURE) + printf("%3d:VSYNC(%d,%05d)\n", screen().vpos(), fieldnum, VBI_CAV_PICTURE(vbi.line1718)); + else + printf("%3d:VSYNC(%d)\n", screen().vpos(), fieldnum); + } + + // signal VSYNC and set a timer to turn it off + m_vsync = true; + timer_set(screen().scan_period() * 4, TID_VSYNC_OFF); + + // also set a timer to fetch the VBI data when it is ready + timer_set(screen().time_until_pos(19*2), TID_VBI_DATA_FETCH); +} + + +//------------------------------------------------- +// player_update - update callback, called on the +// first visible line of the frame +//------------------------------------------------- + +INT32 pioneer_pr8210_device::player_update(const vbi_metadata &vbi, int fieldnum, const attotime &curtime) +{ + // logging + if (LOG_VBLANK_VBI) + printf("%3d:Update(%d)\n", screen().vpos(), fieldnum); + + // if the spindle is on, we advance by 1 track after completing field #1 + return spdl_on() ? fieldnum : 0; +} + + +//------------------------------------------------- +// player_overlay - overlay callback, called +// during frame processing in update to overlay +// player data +//------------------------------------------------- + +void pioneer_pr8210_device::player_overlay(bitmap_yuy16 &bitmap) +{ + // custom display + if (m_pia.display) + { + overlay_draw_group(bitmap, &m_pia.text[2], 5, OVERLAY_GROUP1_X); + overlay_draw_group(bitmap, &m_pia.text[7], 5, OVERLAY_GROUP2_X); + overlay_draw_group(bitmap, &m_pia.text[12], 5, OVERLAY_GROUP3_X); + } + + // chapter/frame display + else + { + // frame display + if (m_pia.latchdisplay & 2) + overlay_draw_group(bitmap, &m_pia.text[2], 5, OVERLAY_GROUP1_X); + + // chapter overlay + if (m_pia.latchdisplay & 1) + overlay_draw_group(bitmap, &m_pia.text[0], 2, OVERLAY_GROUP0_X); + } + m_pia.latchdisplay = 0; +} + + +//------------------------------------------------- +// i8049_pia_r - handle reads from the mystery +// Pioneer PIA +//------------------------------------------------- + +READ8_MEMBER( pioneer_pr8210_device::i8049_pia_r ) +{ + UINT8 result = 0xff; + switch (offset) + { + // (20-26) 7 characters for the chapter/frame + case 0x20: case 0x21: + case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: + result = m_pia.frame[offset - 0x20]; + break; + + // (1D-1F,27) invalid read but normal + case 0x1d: case 0x1e: case 0x1f: + case 0x27: + break; + + // (A0) port A value (from serial decoder) + case 0xa0: + result = m_pia.porta; + break; + + // (C0) VBI decoding state 1 + case 0xc0: + if (LOG_VBLANK_VBI) + printf("%3d:PIA(C0)\n", screen().vpos()); + result = m_pia.vbi1; + break; + + // (E0) VBI decoding state 2 + case 0xe0: + if (LOG_VBLANK_VBI) + printf("%3d:PIA(E0)\n", screen().vpos()); + result = m_pia.vbi2; + break; + + default: + osd_printf_debug("%03X:Unknown PR-8210 PIA read from offset %02X\n", space.device().safe_pc(), offset); + break; + } + return result; +} + + +//------------------------------------------------- +// i8049_pia_w - handle writes to the mystery +// Pioneer PIA +//------------------------------------------------- + +WRITE8_MEMBER( pioneer_pr8210_device::i8049_pia_w ) +{ + UINT8 value; + switch (offset) + { + // (20-30) 17 characters for the display + case 0x20: case 0x21: + case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: + case 0x27: case 0x28: case 0x29: case 0x2a: case 0x2b: + case 0x2c: case 0x2d: case 0x2e: case 0x2f: case 0x30: + m_pia.text[offset - 0x20] = data; + break; + + // (40) control lines + case 0x40: + + // toggle bit 0 to latch chapter number into display area + if (!(data & 0x01) && (m_pia.control & 0x01)) + { + memcpy(&m_pia.text[0], &m_pia.frame[0], 2); + m_pia.latchdisplay |= 1; + } + + // toggle bit 1 to latch frame number into display area + if (!(data & 0x02) && (m_pia.control & 0x02)) + { + memcpy(&m_pia.text[2], &m_pia.frame[2], 5); + m_pia.latchdisplay |= 2; + } + m_pia.control = data; + break; + + // (60) port B value (LEDs) + case 0x60: + + // these 4 are direct-connect + output_set_value("pr8210_audio1", (data & 0x01) != 0); + output_set_value("pr8210_audio2", (data & 0x02) != 0); + output_set_value("pr8210_clv", (data & 0x04) != 0); + output_set_value("pr8210_cav", (data & 0x08) != 0); + + // remaining 3 bits select one of 5 LEDs via a mux + value = ((data & 0x40) >> 6) | ((data & 0x20) >> 4) | ((data & 0x10) >> 2); + output_set_value("pr8210_srev", (value == 0)); + output_set_value("pr8210_sfwd", (value == 1)); + output_set_value("pr8210_play", (value == 2)); + output_set_value("pr8210_step", (value == 3)); + output_set_value("pr8210_pause", (value == 4)); + + m_pia.portb = data; + update_audio_squelch(); + break; + + // (80) display enable + case 0x80: + m_pia.display = data & 0x01; + break; + + // no other writes known + default: + osd_printf_debug("%03X:Unknown PR-8210 PIA write to offset %02X = %02X\n", space.device().safe_pc(), offset, data); + break; + } +} + + +//------------------------------------------------- +// i8049_bus_r - handle reads from the 8049 BUS +// input, which is enabled via the PIA above +//------------------------------------------------- + +READ8_MEMBER( pioneer_pr8210_device::i8049_bus_r ) +{ + /* + $80 = n/c + $40 = (in) slider pot interrupt source (slider position limit detector, inside and outside) + $20 = n/c + $10 = (in) /FOCUS LOCK + $08 = (in) /SPDL LOCK + $04 = (in) SIZE 8/12 + $02 = (in) FG via op-amp (spindle motor stop detector) + $01 = (in) SLOW TIMER OUT + */ + + UINT8 result = 0x00; + + // bus bit 6: slider position limit detector, inside and outside + slider_position sliderpos = get_slider_position(); + if (sliderpos != SLIDER_MINIMUM && sliderpos != SLIDER_MAXIMUM) + result |= 0x40; + + // bus bit 4: /FOCUS LOCK + if (!focus_on()) + result |= 0x10; + + // bus bit 3: /SPDL LOCK + if (!spdl_on()) + result |= 0x08; + + // bus bit 1: spindle motor stop detector + if (!spdl_on()) + result |= 0x02; + + // bus bit 0: SLOW TIMER OUT + + // loop at beginning waits for $40=0, $02=1 + return result; +} + + +//------------------------------------------------- +// i8049_port1_w - handle writes to the 8049 +// port #1 +//------------------------------------------------- + +WRITE8_MEMBER( pioneer_pr8210_device::i8049_port1_w ) +{ + /* + $80 = (out) SCAN C (F/R) + $40 = (out) AUDIO SQ + $20 = (out) VIDEO SQ + $10 = (out) /SPDL ON + $08 = (out) /FOCUS ON + $04 = (out) SCAN B (L/H) + $02 = (out) SCAN A (/SCAN) + $01 = (out) JUMP TRG (jump back trigger, clock on high->low) + */ + + // set the new value + UINT8 prev = m_i8049_port1; + m_i8049_port1 = data; + + // bit 7 selects the direction of slider movement for JUMP TRG and scanning + int direction = (data & 0x80) ? 1 : -1; + + // on the falling edge of bit 0, jump one track in either direction + if (!(data & 0x01) && (prev & 0x01)) + { + // special override for the Simutrek, which takes over control of this is some situations + if (!override_control()) + { + if (LOG_SIMUTREK) + printf("%3d:JUMP TRG\n", screen().vpos()); + advance_slider(direction); + } + else if (LOG_SIMUTREK) + printf("%3d:Skipped JUMP TRG\n", screen().vpos()); + } + + // bit 1 low enables scanning + if (!(data & 0x02)) + { + // bit 2 selects the speed + int delta = (data & 0x04) ? SCAN_SPEED : SEEK_FAST_SPEED; + set_slider_speed(delta * direction); + } + + // bit 1 high stops scanning + else + set_slider_speed(0); + + // video squelch is controlled by bit 5; audio squelch is controlled by bit 6 + update_video_squelch(); + update_audio_squelch(); +} + + +//------------------------------------------------- +// i8049_port2_w - handle writes to the 8049 +// port #2 +//------------------------------------------------- + +WRITE8_MEMBER( pioneer_pr8210_device::i8049_port2_w ) +{ + /* + $80 = (out) /CS on PIA + $40 = (out) 0 to self-generate IRQ + $20 = (out) SLOW TRG + $10 = (out) STANDBY LED + $08 = (out) TP2 + $04 = (out) TP1 + $02 = (out) ??? + $01 = (out) LASER ON + */ + + // set the new value + UINT8 prev = m_i8049_port2; + m_i8049_port2 = data; + + // on the falling edge of bit 5, start the slow timer + if (!(data & 0x20) && (prev & 0x20)) + m_slowtrg = machine().time(); + + // bit 6 when low triggers an IRQ on the MCU + m_i8049_cpu->set_input_line(MCS48_INPUT_IRQ, (data & 0x40) ? CLEAR_LINE : ASSERT_LINE); + + // standby LED is set accordingl to bit 4 + output_set_value("pr8210_standby", (data & 0x10) != 0); +} + + +//------------------------------------------------- +// i8049_t0_r - return the state of the 8049 +// T0 input (connected to VSYNC) +//------------------------------------------------- + +READ8_MEMBER( pioneer_pr8210_device::i8049_t0_r ) +{ + // returns VSYNC state + return !m_vsync; +} + + +//------------------------------------------------- +// i8049_t1_r - return the state of the 8049 +// T1 input (pulled high) +//------------------------------------------------- + +READ8_MEMBER( pioneer_pr8210_device::i8049_t1_r ) +{ + return 1; +} + + +//------------------------------------------------- +// overlay_draw_group - draw a single group of +// characters +//------------------------------------------------- + +void pioneer_pr8210_device::overlay_draw_group(bitmap_yuy16 &bitmap, const UINT8 *text, int count, float xstart) +{ + // rease the background + overlay_erase(bitmap, xstart, xstart + ((OVERLAY_X_PIXELS + 1) * count + 1) * OVERLAY_PIXEL_WIDTH); + + // draw each character, suppressing leading 0's + bool skip = true; + for (int x = 0; x < count; x++) + if (!skip || x == count - 1 || (text[x] & 0x3f) != 0x30) + { + skip = false; + overlay_draw_char(bitmap, text[x], xstart + ((OVERLAY_X_PIXELS + 1) * x + 1) * OVERLAY_PIXEL_WIDTH); + } +} + + +//------------------------------------------------- +// overlay_erase - erase the background area +// where the text overlay will be displayed +//------------------------------------------------- + +void pioneer_pr8210_device::overlay_erase(bitmap_yuy16 &bitmap, float xstart, float xend) +{ + UINT32 xmin = (UINT32)(xstart * 256.0f * float(bitmap.width())); + UINT32 xmax = (UINT32)(xend * 256.0f * float(bitmap.width())); + + for (UINT32 y = OVERLAY_Y; y < (OVERLAY_Y + (OVERLAY_Y_PIXELS + 2) * OVERLAY_PIXEL_HEIGHT); y++) + { + UINT16 *dest = &bitmap.pix16(y, xmin >> 8); + UINT16 ymax = *dest >> 8; + UINT16 ymin = ymax * 3 / 8; + UINT16 yres = ymin + ((ymax - ymin) * (xmin & 0xff)) / 256; + *dest = (yres << 8) | (*dest & 0xff); + dest++; + + for (UINT32 x = (xmin | 0xff) + 1; x < xmax; x += 0x100) + { + yres = (*dest >> 8) * 3 / 8; + *dest = (yres << 8) | (*dest & 0xff); + dest++; + } + + ymax = *dest >> 8; + ymin = ymax * 3 / 8; + yres = ymin + ((ymax - ymin) * (~xmax & 0xff)) / 256; + *dest = (yres << 8) | (*dest & 0xff); + dest++; + } +} + + +//------------------------------------------------- +// overlay_draw_char - draw a single character +// of the text overlay +//------------------------------------------------- + +void pioneer_pr8210_device::overlay_draw_char(bitmap_yuy16 &bitmap, UINT8 ch, float xstart) +{ + UINT32 xminbase = (UINT32)(xstart * 256.0f * float(bitmap.width())); + UINT32 xsize = (UINT32)(OVERLAY_PIXEL_WIDTH * 256.0f * float(bitmap.width())); + + // iterate over pixels + const UINT8 *chdataptr = &text_bitmap[ch & 0x3f][0]; + for (UINT32 y = 0; y < OVERLAY_Y_PIXELS; y++) + { + UINT8 chdata = *chdataptr++; + + for (UINT32 x = 0; x < OVERLAY_X_PIXELS; x++, chdata <<= 1) + if (chdata & 0x80) + { + UINT32 xmin = xminbase + x * xsize; + UINT32 xmax = xmin + xsize; + for (UINT32 yy = 0; yy < OVERLAY_PIXEL_HEIGHT; yy++) + { + UINT16 *dest = &bitmap.pix16(OVERLAY_Y + (y + 1) * OVERLAY_PIXEL_HEIGHT + yy, xmin >> 8); + UINT16 ymax = 0xff; + UINT16 ymin = *dest >> 8; + UINT16 yres = ymin + ((ymax - ymin) * (~xmin & 0xff)) / 256; + *dest = (yres << 8) | (*dest & 0xff); + dest++; + + for (UINT32 xx = (xmin | 0xff) + 1; xx < xmax; xx += 0x100) + *dest++ = 0xf080; + + ymax = 0xff; + ymin = *dest >> 8; + yres = ymin + ((ymax - ymin) * (xmax & 0xff)) / 256; + *dest = (yres << 8) | (*dest & 0xff); + dest++; + } + } + } +} + + + +//************************************************************************** +// SIMUTREK ROM AND MACHINE INTERFACES +//************************************************************************** + +static ADDRESS_MAP_START( simutrek_portmap, AS_IO, 8, simutrek_special_device ) + AM_RANGE(0x00, 0xff) AM_READ(i8748_data_r) + AM_RANGE(MCS48_PORT_P2, MCS48_PORT_P2) AM_READWRITE(i8748_port2_r, i8748_port2_w) + AM_RANGE(MCS48_PORT_T0, MCS48_PORT_T0) AM_READ(i8748_t0_r) +ADDRESS_MAP_END + + +static MACHINE_CONFIG_FRAGMENT( simutrek ) + MCFG_CPU_ADD("simutrek", I8748, XTAL_6MHz) + MCFG_CPU_IO_MAP(simutrek_portmap) + + MCFG_FRAGMENT_ADD(pr8210) +MACHINE_CONFIG_END + + +ROM_START( simutrek ) + ROM_REGION( 0x800, "pr8210", 0 ) + ROM_LOAD( "pr-8210_mcu_ud6005a.bin", 0x000, 0x800, CRC(120fa83b) SHA1(b514326ca1f52d6d89056868f9d17eabd4e3f31d) ) + + ROM_REGION( 0x400, "simutrek", 0) + ROM_LOAD( "laser_player_interface_d8748_a308.bin", 0x0000, 0x0400, CRC(eed3e728) SHA1(1eb3467f1c41553375b2c21952cd593b167f5416) ) +ROM_END + + + +//************************************************************************** +// SIMUTREK IMPLEMENTATION +//************************************************************************** + +//------------------------------------------------- +// simutrek_special_device - constructor +//------------------------------------------------- + +simutrek_special_device::simutrek_special_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : pioneer_pr8210_device(mconfig, SIMUTREK_SPECIAL, "Simutrek Modified PR-8210", tag, owner, clock, "simutrek", __FILE__), + m_i8748_cpu(*this, "simutrek"), + m_audio_squelch(0), + m_data(0), + m_data_ready(false), + m_i8748_port2(0), + m_controlnext(0), + m_controlthis(0) +{ +} + + +//------------------------------------------------- +// data_w - write callback when the parallel data +// port is written to +//------------------------------------------------- + +void simutrek_special_device::data_w(UINT8 data) +{ + synchronize(TID_LATCH_DATA, data); + if (LOG_SIMUTREK) + printf("%03d:**** Simutrek Command = %02X\n", screen().vpos(), data); +} + + +//------------------------------------------------- +// set_external_audio_squelch - Simutrek-specific +// command to enable/disable audio squelch +//------------------------------------------------- + +void simutrek_special_device::set_external_audio_squelch(int state) +{ + if (LOG_SIMUTREK && m_audio_squelch != (state == 0)) + printf("--> audio squelch = %d\n", state == 0); + m_audio_squelch = (state == 0); + update_audio_squelch(); +} + + +//------------------------------------------------- +// player_vsync - VSYNC callback, called at the +// start of the blanking period +//------------------------------------------------- + +void simutrek_special_device::player_vsync(const vbi_metadata &vbi, int fieldnum, const attotime &curtime) +{ + // latch the control state after the second field + if (fieldnum == 1) + { + m_controlthis = m_controlnext; + m_controlnext = 0; + } + + // call the parent + if (LOG_SIMUTREK) + printf("%3d:VSYNC(%d)\n", screen().vpos(), fieldnum); + pioneer_pr8210_device::player_vsync(vbi, fieldnum, curtime); + + // process data + if (m_data_ready) + { + if (LOG_SIMUTREK) + printf("%3d:VSYNC IRQ\n", screen().vpos()); + m_i8748_cpu->set_input_line(MCS48_INPUT_IRQ, ASSERT_LINE); + timer_set(screen().scan_period(), TID_IRQ_OFF); + } +} + + +//------------------------------------------------- +// device_start - device initialization +//------------------------------------------------- + +void simutrek_special_device::device_start() +{ + // pass through to the parent + pioneer_pr8210_device::device_start(); +} + + +//------------------------------------------------- +// device_reset - device reset +//------------------------------------------------- + +void simutrek_special_device::device_reset() +{ + // standard PR-8210 initialization + pioneer_pr8210_device::device_reset(); + + // initialize the Simutrek state + // for proper synchronization of initial attract mode, this needs to be set + m_data_ready = true; +} + + +//------------------------------------------------- +// device_timer - handle timers set by this +// device +//------------------------------------------------- + +void simutrek_special_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch (id) + { + // clear the 8748 IRQ + case TID_IRQ_OFF: + m_i8748_cpu->set_input_line(MCS48_INPUT_IRQ, CLEAR_LINE); + break; + + // latch data + case TID_LATCH_DATA: + m_data = param; + m_data_ready = true; + break; + + // pass everything else onto the parent + default: + pioneer_pr8210_device::device_timer(timer, id, param, ptr); + break; + } +} + + +//------------------------------------------------- +// device_rom_region - return a pointer to our +// ROM region definitions +//------------------------------------------------- + +const rom_entry *simutrek_special_device::device_rom_region() const +{ + return ROM_NAME(simutrek); +} + + +//------------------------------------------------- +// device_mconfig_additions - return a pointer to +// our machine config fragment +//------------------------------------------------- + +machine_config_constructor simutrek_special_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME(simutrek); +} + + +//------------------------------------------------- +// i8748_port2_r - handle reads from the 8748 +// port #2 +//------------------------------------------------- + +READ8_MEMBER( simutrek_special_device::i8748_port2_r ) +{ + // bit $80 is the pr8210 video squelch + return (m_i8049_port1 & 0x20) ? 0x00 : 0x80; +} + + +//------------------------------------------------- +// i8748_port2_w - handle writes to the 8748 +// port #2 +//------------------------------------------------- + +WRITE8_MEMBER( simutrek_special_device::i8748_port2_w ) +{ + // update stat + UINT8 prev = m_i8748_port2; + m_i8748_port2 = data; + + // bit $20 goes to the serial line + if ((data ^ prev) & 0x20) + pioneer_pr8210_device::control_w((data & 0x20) ? ASSERT_LINE : CLEAR_LINE); + + // bit $10 goes to JUMP TRG + // bit $08 controls direction + if (!(data & 0x10) && (prev & 0x10)) + { + int direction = (data & 0x08) ? 1 : -1; + if (LOG_SIMUTREK) + printf("%3d:JUMP TRG (Simutrek PC=%03X)\n", screen().vpos(), space.device().safe_pc()); + advance_slider(direction); + } + + // bit $04 controls who owns the JUMP TRG command + if (LOG_SIMUTREK && ((data ^ prev) & 0x04)) + printf("%3d:Simutrek ownership line = %d (Simutrek PC=%03X)\n", screen().vpos(), (data >> 2) & 1, space.device().safe_pc()); + m_controlnext = (~data >> 2) & 1; + + // bits $03 control something (status?) + if (LOG_SIMUTREK && ((data ^ prev) & 0x03)) + printf("Simutrek Status = %d\n", data & 0x03); +} + + +//------------------------------------------------- +// i8748_data_r - handle external 8748 data reads +//------------------------------------------------- + +READ8_MEMBER( simutrek_special_device::i8748_data_r ) +{ + // acknowledge the read and clear the data ready flag + m_data_ready = false; + return m_data; +} + + +//------------------------------------------------- +// i8748_t0_r - return the status of the 8748 +// T0 input +//------------------------------------------------- + +READ8_MEMBER( simutrek_special_device::i8748_t0_r ) +{ + // return 1 if data is waiting from main CPU + return m_data_ready; +} diff --git a/src/devices/machine/ldpr8210.h b/src/devices/machine/ldpr8210.h new file mode 100644 index 00000000000..96273dcb12a --- /dev/null +++ b/src/devices/machine/ldpr8210.h @@ -0,0 +1,193 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/************************************************************************* + + ldpr8210.h + + Pioneer PR-8210 laserdisc emulation. + +*************************************************************************/ + +#pragma once + +#ifndef __LDPR8210_H__ +#define __LDPR8210_H__ + +#include "laserdsc.h" +#include "cpu/mcs48/mcs48.h" + + +//************************************************************************** +// DEVICE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_LASERDISC_PR8210_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, PIONEER_PR8210, 0) +#define MCFG_LASERDISC_SIMUTREK_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, SIMUTREK_SPECIAL, 0) + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +// device type definition +extern const device_type PIONEER_PR8210; +extern const device_type SIMUTREK_SPECIAL; + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// pioneer PIA subclass +class pioneer_pia +{ +public: + UINT8 frame[7]; // (20-26) 7 characters for the chapter/frame + UINT8 text[17]; // (20-30) 17 characters for the display + UINT8 control; // (40) control lines + UINT8 latchdisplay; // flag: set if the display was latched + UINT8 portb; // (60) port B value (LEDs) + UINT8 display; // (80) display enable + UINT8 porta; // (A0) port A value (from serial decoder) + UINT8 vbi1; // (C0) VBI decoding state 1 + UINT8 vbi2; // (E0) VBI decoding state 2 +}; + + +// ======================> pioneer_pr8210_device + +// base pr8210 class +class pioneer_pr8210_device : public laserdisc_device +{ +public: + // construction/destruction + pioneer_pr8210_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + pioneer_pr8210_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + // input and output + void control_w(UINT8 data); + +protected: + // timer IDs + enum + { + TID_VSYNC_OFF = TID_FIRST_PLAYER_TIMER, + TID_VBI_DATA_FETCH, + TID_FIRST_SUBCLASS_TIMER + }; + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + + // subclass overrides + virtual void player_vsync(const vbi_metadata &vbi, int fieldnum, const attotime &curtime); + virtual INT32 player_update(const vbi_metadata &vbi, int fieldnum, const attotime &curtime); + virtual void player_overlay(bitmap_yuy16 &bitmap); + + // internal helpers + bool focus_on() const { return !(m_i8049_port1 & 0x08); } + bool spdl_on() const { return !(m_i8049_port1 & 0x10); } + bool laser_on() const { return !(m_i8049_port2 & 0x01); } + virtual bool override_control() const { return false; } + void update_video_squelch() { set_video_squelch((m_i8049_port1 & 0x20) != 0); } + virtual void update_audio_squelch() { set_audio_squelch((m_i8049_port1 & 0x40) || !(m_pia.portb & 0x01), (m_i8049_port1 & 0x40) || !(m_pia.portb & 0x02)); } + +public: + // internal read/write handlers + DECLARE_READ8_MEMBER( i8049_pia_r ); + DECLARE_WRITE8_MEMBER( i8049_pia_w ); + DECLARE_READ8_MEMBER( i8049_bus_r ); + DECLARE_WRITE8_MEMBER( i8049_port1_w ); + DECLARE_WRITE8_MEMBER( i8049_port2_w ); + DECLARE_READ8_MEMBER( i8049_t0_r ); + DECLARE_READ8_MEMBER( i8049_t1_r ); + +protected: + // internal overlay helpers + void overlay_draw_group(bitmap_yuy16 &bitmap, const UINT8 *text, int count, float xstart); + void overlay_erase(bitmap_yuy16 &bitmap, float xstart, float xend); + void overlay_draw_char(bitmap_yuy16 &bitmap, UINT8 ch, float xstart); + + // internal state + UINT8 m_control; // control line state + UINT8 m_lastcommand; // last command seen + UINT16 m_accumulator; // bit accumulator + attotime m_lastcommandtime; // time of the last command + attotime m_lastbittime; // time of last bit received + attotime m_firstbittime; // time of first bit in command + + // low-level emulation data + required_device m_i8049_cpu; // 8049 CPU device + attotime m_slowtrg; // time of the last SLOW TRG + pioneer_pia m_pia; // PIA state + bool m_vsync; // live VSYNC state + UINT8 m_i8049_port1; // 8049 port 1 state + UINT8 m_i8049_port2; // 8049 port 2 state +}; + + +// ======================> simutrek_special_device + +class simutrek_special_device : public pioneer_pr8210_device +{ +public: + // construction/destruction + simutrek_special_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // input and output + void data_w(UINT8 data); + UINT8 ready_r() const { return !m_data_ready; } + UINT8 status_r() const { return ((m_i8748_port2 & 0x03) == 0x03) ? ASSERT_LINE : CLEAR_LINE; } + + // external controls + void set_external_audio_squelch(int state); + +protected: + // timer IDs + enum + { + TID_IRQ_OFF = TID_FIRST_SUBCLASS_TIMER, + TID_LATCH_DATA + }; + + // subclass overrides + virtual void player_vsync(const vbi_metadata &vbi, int fieldnum, const attotime &curtime); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + + // internal helpers + virtual bool override_control() const { return m_controlthis; } + virtual void update_audio_squelch() { set_audio_squelch(m_audio_squelch, m_audio_squelch); } + +public: + // internal read/write handlers + DECLARE_READ8_MEMBER( i8748_port2_r ); + DECLARE_WRITE8_MEMBER( i8748_port2_w ); + DECLARE_READ8_MEMBER( i8748_data_r ); + DECLARE_READ8_MEMBER( i8748_t0_r ); + +protected: + // internal state + required_device m_i8748_cpu; + UINT8 m_audio_squelch; // audio squelch value + UINT8 m_data; // parallel data for simutrek + bool m_data_ready; // ready flag for simutrek data + UINT8 m_i8748_port2; // 8748 port 2 state + UINT8 m_controlnext; // latch to control next pair of fields + UINT8 m_controlthis; // latched value for our control over the current pair of fields +}; + + +#endif diff --git a/src/devices/machine/ldstub.c b/src/devices/machine/ldstub.c new file mode 100644 index 00000000000..14dd42fdc2b --- /dev/null +++ b/src/devices/machine/ldstub.c @@ -0,0 +1,22 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/************************************************************************* + + ldstub.c + + Laserdisc player stubs. + +*************************************************************************/ + +#include "emu.h" +#include "ldstub.h" + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +// device type definition +const device_type SONY_LDP1450 = &device_creator; +const device_type PIONEER_PR7820 = &device_creator; +const device_type PHILLIPS_22VP932 = &device_creator; diff --git a/src/devices/machine/ldstub.h b/src/devices/machine/ldstub.h new file mode 100644 index 00000000000..d10cd0313ea --- /dev/null +++ b/src/devices/machine/ldstub.h @@ -0,0 +1,114 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/************************************************************************* + + ldstub.h + + Laserdisc player stubs. + +*************************************************************************/ + +#pragma once + +#ifndef __LDSTUB_H__ +#define __LDSTUB_H__ + +#include "laserdsc.h" + + +//************************************************************************** +// DEVICE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_LASERDISC_LDP1450_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, SONY_LDP1450, 0) +#define MCFG_LASERDISC_PR7820_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, PIONEER_PR7820, 0) +#define MCFG_LASERDISC_22VP932_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, PHILLIPS_22VP932, 0) + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +// device type definition +extern const device_type SONY_LDP1450; +extern const device_type PIONEER_PR7820; +extern const device_type PHILLIPS_22VP932; + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> sony_ldp1450_device + +class sony_ldp1450_device : public laserdisc_device +{ +public: + // construction/destruction + sony_ldp1450_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : laserdisc_device(mconfig, SONY_LDP1450, "Sony LDP-1450", tag, owner, clock, "ldp1450", __FILE__) { } + + // input/output + UINT8 data_available_r() { return CLEAR_LINE; } + UINT8 data_r() { return 0; } + void data_w(UINT8 data) { } + +protected: + // subclass overrides + virtual void player_vsync(const vbi_metadata &vbi, int fieldnum, const attotime &curtime) { } + virtual INT32 player_update(const vbi_metadata &vbi, int fieldnum, const attotime &curtime) { return fieldnum; } + virtual void player_overlay(bitmap_yuy16 &bitmap) { } +}; + + +// ======================> pioneer_pr7820_device + +class pioneer_pr7820_device : public laserdisc_device +{ +public: + // construction/destruction + pioneer_pr7820_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : laserdisc_device(mconfig, PIONEER_PR7820, "Pioneer PR-7820", tag, owner, clock, "pr7820", __FILE__) { } + + // input/output + UINT8 data_available_r() { return CLEAR_LINE; } + UINT8 ready_r() { return ASSERT_LINE; } + UINT8 data_r() { return 0; } + void data_w(UINT8 data) { } + void enter_w(UINT8 data) { } + +protected: + // subclass overrides + virtual void player_vsync(const vbi_metadata &vbi, int fieldnum, const attotime &curtime) { } + virtual INT32 player_update(const vbi_metadata &vbi, int fieldnum, const attotime &curtime) { return fieldnum; } + virtual void player_overlay(bitmap_yuy16 &bitmap) { } +}; + + +// ======================> phillips_22vp932_device + +class phillips_22vp932_device : public laserdisc_device +{ +public: + // construction/destruction + phillips_22vp932_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : laserdisc_device(mconfig, PHILLIPS_22VP932, "Phillips 22VP932", tag, owner, clock, "22vp932", __FILE__) { } + + // input/output + UINT8 data_r() { return 0; } + void data_w(UINT8 data) { } + void enter_w(UINT8 data) { } + +protected: + // subclass overrides + virtual void player_vsync(const vbi_metadata &vbi, int fieldnum, const attotime &curtime) { } + virtual INT32 player_update(const vbi_metadata &vbi, int fieldnum, const attotime &curtime) { return fieldnum; } + virtual void player_overlay(bitmap_yuy16 &bitmap) { } +}; + + +#endif diff --git a/src/devices/machine/ldv1000.c b/src/devices/machine/ldv1000.c new file mode 100644 index 00000000000..18c8d86fc9a --- /dev/null +++ b/src/devices/machine/ldv1000.c @@ -0,0 +1,656 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/************************************************************************* + + ldv1000.c + + Pioneer LD-V1000 laserdisc emulation. + +************************************************************************** + + Still to do: + + * fix issues + * add OSD + +*************************************************************************/ + + +#include "emu.h" +#include "ldv1000.h" +#include "machine/i8255.h" +#include "machine/z80ctc.h" +#include "cpu/z80/z80.h" +#include "cpu/z80/z80daisy.h" + + + +//************************************************************************** +// DEBUGGING +//************************************************************************** + +#define LOG_PORT_IO 0 +#define LOG_STATUS_CHANGES 0 +#define LOG_FRAMES_SEEN 0 +#define LOG_COMMANDS 0 + + + +//************************************************************************** +// CONSTANTS +//************************************************************************** + +#define SCAN_SPEED (2000 / 30) // 2000 frames/second +#define SEEK_FAST_SPEED (4000 / 30) // 4000 frames/second + +#define MULTIJUMP_TRACK_TIME attotime::from_usec(50) + + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +// devices +const device_type PIONEER_LDV1000 = &device_creator; + + + +//************************************************************************** +// LD-V1000 ROM AND MACHINE INTERFACES +//************************************************************************** + +static ADDRESS_MAP_START( ldv1000_map, AS_PROGRAM, 8, pioneer_ldv1000_device ) + AM_RANGE(0x0000, 0x1fff) AM_MIRROR(0x6000) AM_ROM + AM_RANGE(0x8000, 0x87ff) AM_MIRROR(0x3800) AM_RAM + AM_RANGE(0xc000, 0xc003) AM_MIRROR(0x9ff0) AM_DEVREADWRITE("ldvppi0", i8255_device, read, write) + AM_RANGE(0xc004, 0xc007) AM_MIRROR(0x9ff0) AM_DEVREADWRITE("ldvppi1", i8255_device, read, write) +ADDRESS_MAP_END + + +static ADDRESS_MAP_START( ldv1000_portmap, AS_IO, 8, pioneer_ldv1000_device ) + ADDRESS_MAP_GLOBAL_MASK(0xff) + AM_RANGE(0x00, 0x07) AM_MIRROR(0x38) AM_READWRITE(z80_decoder_display_port_r, z80_decoder_display_port_w) + AM_RANGE(0x40, 0x40) AM_MIRROR(0x3f) AM_READ(z80_controller_r) + AM_RANGE(0x80, 0x80) AM_MIRROR(0x3f) AM_WRITE(z80_controller_w) + AM_RANGE(0xc0, 0xc3) AM_MIRROR(0x3c) AM_DEVREADWRITE("ldvctc", z80ctc_device, read, write) +ADDRESS_MAP_END + + +static const z80_daisy_config daisy_chain[] = +{ + { "ldvctc" }, + { NULL } +}; + + +static MACHINE_CONFIG_FRAGMENT( ldv1000 ) + MCFG_CPU_ADD("ldv1000", Z80, XTAL_5MHz/2) + MCFG_CPU_CONFIG(daisy_chain) + MCFG_CPU_PROGRAM_MAP(ldv1000_map) + MCFG_CPU_IO_MAP(ldv1000_portmap) + + MCFG_DEVICE_ADD("ldvctc", Z80CTC, XTAL_5MHz/2) + MCFG_Z80CTC_INTR_CB(WRITELINE(pioneer_ldv1000_device, ctc_interrupt)) + + MCFG_DEVICE_ADD("ldvppi0", I8255, 0) + MCFG_I8255_OUT_PORTA_CB(WRITE8(pioneer_ldv1000_device, ppi0_porta_w)) + MCFG_I8255_IN_PORTB_CB(READ8(pioneer_ldv1000_device, ppi0_portb_r)) + MCFG_I8255_IN_PORTC_CB(READ8(pioneer_ldv1000_device, ppi0_portc_r)) + MCFG_I8255_OUT_PORTC_CB(WRITE8(pioneer_ldv1000_device, ppi0_portc_w)) + + MCFG_DEVICE_ADD("ldvppi1", I8255, 0) + MCFG_I8255_IN_PORTA_CB(READ8(pioneer_ldv1000_device, ppi1_porta_r)) + MCFG_I8255_OUT_PORTB_CB(WRITE8(pioneer_ldv1000_device, ppi1_portb_w)) + MCFG_I8255_OUT_PORTC_CB(WRITE8(pioneer_ldv1000_device, ppi1_portc_w)) +MACHINE_CONFIG_END + + +ROM_START( ldv1000 ) + ROM_REGION( 0x2000, "ldv1000", 0 ) + ROM_LOAD( "z03_1001_vyw-053_v1-0.bin", 0x0000, 0x2000, CRC(31ec4687) SHA1(52f91c304a878ba02b2fa1cda1a9489d6dd5a34f) ) +ROM_END + + + +//************************************************************************** +// PIONEER LD-V1000 IMPLEMENTATION +//************************************************************************** + +//------------------------------------------------- +// pioneer_ldv1000_device - constructor +//------------------------------------------------- + +pioneer_ldv1000_device::pioneer_ldv1000_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : laserdisc_device(mconfig, PIONEER_LDV1000, "Pioneer LD-V1000", tag, owner, clock, "ldv1000", __FILE__), + m_z80_cpu(*this, "ldv1000"), + m_z80_ctc(*this, "ldvctc"), + m_multitimer(NULL), + m_command(0), + m_status(0), + m_vsync(false), + m_counter_start(0), + m_counter(0), + m_portc0(0), + m_portb1(0), + m_portc1(0), + m_portselect(0), + m_dispindex(0), + m_vbiready(false), + m_vbiindex(0) +{ +} + + +//------------------------------------------------- +// data_w - handle a parallel data write to the +// LD-V1000 +//------------------------------------------------- + +void pioneer_ldv1000_device::data_w(UINT8 data) +{ + m_command = data; + if (LOG_COMMANDS) + printf("-> COMMAND = %02X (%s)\n", data, (m_portc1 & 0x10) ? "valid" : "invalid"); +} + + +//------------------------------------------------- +// enter_w - set the state of the ENTER strobe +//------------------------------------------------- + +void pioneer_ldv1000_device::enter_w(UINT8 data) +{ +} + + +//------------------------------------------------- +// device_start - device initialization +//------------------------------------------------- + +void pioneer_ldv1000_device::device_start() +{ + // pass through to the parent + laserdisc_device::device_start(); + + // allocate timers + m_multitimer = timer_alloc(TID_MULTIJUMP); +} + + +//------------------------------------------------- +// device_reset - device reset +//------------------------------------------------- + +void pioneer_ldv1000_device::device_reset() +{ + // pass through to the parent + laserdisc_device::device_reset(); + + // reset our state + m_command = 0; + m_status = 0; + m_vsync = false; + m_counter_start = 0; + m_counter = 0; + m_portc0 = 0; + m_portb1 = 0; + m_portc1 = 0; + m_portselect = 0; + m_dispindex = 0; + m_vbiready = false; + m_vbiindex = 0; +} + + +//------------------------------------------------- +// device_timer - handle timers set by this +// device +//------------------------------------------------- + +void pioneer_ldv1000_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch (id) + { + case TID_MULTIJUMP: + { + // bit 5 of port B on PPI 1 selects the direction of slider movement + int direction = (m_portb1 & 0x20) ? 1 : -1; + advance_slider(direction); + + // update down counter and reschedule + if (--m_counter != 0) + timer.adjust(MULTIJUMP_TRACK_TIME); + break; + } + + case TID_VSYNC_OFF: + m_vsync = false; + break; + + case TID_VBI_DATA_FETCH: + { + // appears to return data in reverse order + UINT32 lines[3]; + lines[0] = get_field_code(LASERDISC_CODE_LINE1718, false); + lines[1] = get_field_code(LASERDISC_CODE_LINE17, false); + lines[2] = get_field_code(LASERDISC_CODE_LINE16, false); + + // fill in the details + memset(m_vbi, 0, sizeof(m_vbi)); + if (focus_on() && laser_on()) + { + // loop over lines + for (int line = 0; line < 3; line++) + { + UINT8 *dest = &m_vbi[line * 7]; + UINT32 data = lines[line]; + + // the logic only processes leadin/leadout/frame number codes + if (data == VBI_CODE_LEADIN || data == VBI_CODE_LEADOUT || (data & VBI_MASK_CAV_PICTURE) == VBI_CODE_CAV_PICTURE) + { + *dest++ = 0x09 | (((data & VBI_MASK_CAV_PICTURE) == VBI_CODE_CAV_PICTURE) ? 0x02 : 0x00); + *dest++ = 0x08; + *dest++ = (data >> 16) & 0x0f; + *dest++ = (data >> 12) & 0x0f; + *dest++ = (data >> 8) & 0x0f; + *dest++ = (data >> 4) & 0x0f; + *dest++ = (data >> 0) & 0x0f; + } + } + } + + // signal that data is ready and reset the readback index + m_vbiready = true; + m_vbiindex = 0; + break; + } + + // pass everything else onto the parent + default: + laserdisc_device::device_timer(timer, id, param, ptr); + break; + } +} + + +//------------------------------------------------- +// device_rom_region - return a pointer to our +// ROM region definitions +//------------------------------------------------- + +const rom_entry *pioneer_ldv1000_device::device_rom_region() const +{ + return ROM_NAME(ldv1000); +} + + +//------------------------------------------------- +// device_mconfig_additions - return a pointer to +// our machine config fragment +//------------------------------------------------- + +machine_config_constructor pioneer_ldv1000_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME(ldv1000); +} + + +//------------------------------------------------- +// player_vsync - VSYNC callback, called at the +// start of the blanking period +//------------------------------------------------- + +void pioneer_ldv1000_device::player_vsync(const vbi_metadata &vbi, int fieldnum, const attotime &curtime) +{ + // generate interrupts if we hit the edges + slider_position sliderpos = get_slider_position(); + m_z80_ctc->trg1(sliderpos == SLIDER_MINIMUM); + m_z80_ctc->trg2(sliderpos == SLIDER_MAXIMUM); + + // signal VSYNC and set a timer to turn it off + m_vsync = true; + timer_set(screen().scan_period() * 4, TID_VSYNC_OFF); + + // also set a timer to fetch the VBI data when it is ready + timer_set(screen().time_until_pos(19*2), TID_VBI_DATA_FETCH); + + // boost interleave for the first 1ms to improve communications + machine().scheduler().boost_interleave(attotime::zero, attotime::from_msec(1)); +} + + +//------------------------------------------------- +// player_update - update callback, called on +// the first visible line of the frame +//------------------------------------------------- + +INT32 pioneer_ldv1000_device::player_update(const vbi_metadata &vbi, int fieldnum, const attotime &curtime) +{ + if (LOG_FRAMES_SEEN) + { + int frame = frame_from_metadata(vbi); + if (frame != FRAME_NOT_PRESENT) printf("== %d\n", frame); + } + return fieldnum; +} + + +//------------------------------------------------- +// ctc_interrupt - called when the CTC triggers +// an interrupt in the daisy chain +//------------------------------------------------- + +WRITE_LINE_MEMBER( pioneer_ldv1000_device::ctc_interrupt ) +{ + m_z80_cpu->set_input_line(0, state ? ASSERT_LINE : CLEAR_LINE); +} + + +//------------------------------------------------- +// z80_decoder_display_port_w - handle writes to +// the decoder/display chips +//------------------------------------------------- + +WRITE8_MEMBER( pioneer_ldv1000_device::z80_decoder_display_port_w ) +{ + /* + TX/RX = /A0 (A0=0 -> TX, A0=1 -> RX) + + Display is 6-bit + Decoder is 4-bit + */ + + // writes to offset 0 select the target for reads/writes of actual data + if (offset == 0) + { + m_portselect = data; + m_dispindex = 0; + } + + // writes to offset 2 constitute actual writes targeted toward the display and decoder chips + else if (offset == 2) + { + // selections 0 and 1 represent the two display lines; only 6 bits are transferred + if (m_portselect < 2) + m_display[m_portselect][m_dispindex++ % 20] = data & 0x3f; + } +} + + +//------------------------------------------------- +// z80_decoder_display_port_r - handle reads from the +// decoder/display chips +//------------------------------------------------- + +READ8_MEMBER( pioneer_ldv1000_device::z80_decoder_display_port_r ) +{ + // reads from offset 3 constitute actual reads from the display and decoder chips + UINT8 result = 0; + if (offset == 3) + { + // selection 4 represents the VBI data reading + if (m_portselect == 4) + { + m_vbiready = false; + result = m_vbi[m_vbiindex++ % ARRAY_LENGTH(m_vbi)]; + } + } + return result; +} + + +//------------------------------------------------- +// z80_controller_r - handle read of the data from +// the controlling system +//------------------------------------------------- + +READ8_MEMBER( pioneer_ldv1000_device::z80_controller_r ) +{ + // note that this is a cheesy implementation; the real thing relies on exquisite timing + UINT8 result = m_command ^ 0xff; + m_command = 0xff; + return result; +} + + +//------------------------------------------------- +// z80_controller_w - handle status latch writes +//------------------------------------------------- + +WRITE8_MEMBER( pioneer_ldv1000_device::z80_controller_w ) +{ + if (LOG_STATUS_CHANGES && data != m_status) + printf("%04X:CONTROLLER.W=%02X\n", space.device().safe_pc(), data); + m_status = data; +} + + +//------------------------------------------------- +// ppi0_porta_w - handle writes to port A of +// PPI #0 +//------------------------------------------------- + +WRITE8_MEMBER( pioneer_ldv1000_device::ppi0_porta_w ) +{ + m_counter_start = data; + if (LOG_PORT_IO) + printf("%s:PORTA.0=%02X\n", machine().describe_context(), data); +} + + +//------------------------------------------------- +// ppi0_portb_r - handle reads from port B of +// PPI #0 +//------------------------------------------------- + +READ8_MEMBER( pioneer_ldv1000_device::ppi0_portb_r ) +{ + return m_counter; +} + + +//------------------------------------------------- +// ppi0_portc_r - handle reads from port C of +// PPI #0 +//------------------------------------------------- + +READ8_MEMBER( pioneer_ldv1000_device::ppi0_portc_r ) +{ + /* + $10 = /VSYNC + $20 = IRQ from decoder chip + $40 = TRKG LOOP (N24-1) + $80 = DUMP (N20-1) -- code reads the state and waits for it to change + */ + + UINT8 result = 0x00; + if (!m_vsync) + result |= 0x10; + if (!m_vbiready) + result |= 0x20; + return result; +} + + +//------------------------------------------------- +// ppi0_portc_w - handle writes to port C of +// PPI #0 +//------------------------------------------------- + +WRITE8_MEMBER( pioneer_ldv1000_device::ppi0_portc_w ) +{ + /* + $01 = preload on up/down counters + $02 = /MULTI JUMP TRIG + $04 = SCAN MODE + $08 = n/c + */ + + // set the new value + UINT8 prev = m_portc0; + m_portc0 = data; + if (LOG_PORT_IO && ((data ^ prev) & 0x0f) != 0) + { + printf("%s:PORTC.0=%02X", machine().describe_context(), data); + if (data & 0x01) printf(" PRELOAD"); + if (!(data & 0x02)) printf(" /MULTIJUMP"); + if (data & 0x04) printf(" SCANMODE"); + printf("\n"); + } + + // on the rising edge of bit 0, clock the down counter load + if ((data & 0x01) && !(prev & 0x01)) + m_counter = m_counter_start; + + // on the falling edge of bit 1, start the multi-jump timer + if (!(data & 0x02) && (prev & 0x02)) + m_multitimer->adjust(MULTIJUMP_TRACK_TIME); +} + + +//------------------------------------------------- +// ppi1_porta_r - handle reads from port A of +// PPI #1 +//------------------------------------------------- + +READ8_MEMBER( pioneer_ldv1000_device::ppi1_porta_r ) +{ + /* + $01 = /FOCS LOCK + $02 = /SPDL LOCK + $04 = INSIDE + $08 = OUTSIDE + $10 = MOTOR STOP + $20 = +5V/test point + $40 = /INT LOCK + $80 = 8 INCH CHK + */ + + slider_position sliderpos = get_slider_position(); + UINT8 result = 0x00; + + // bit 0: /FOCUS LOCK + if (!focus_on()) + result |= 0x01; + + // bit 1: /SPDL LOCK + if (!spdl_on()) + result |= 0x02; + + // bit 2: INSIDE signal + if (sliderpos == SLIDER_MINIMUM) + result |= 0x04; + + // bit 3: OUTSIDE signal + if (sliderpos == SLIDER_MAXIMUM) + result |= 0x08; + + // bit 4: MOTOR STOP + + // bit 5: +5V/test point + result |= 0x20; + + // bit 6: /INT LOCK + + // bit 7: 8 INCH CHK + + return result; +} + + +//------------------------------------------------- +// ppi1_portb_w - handle writes to port B of +// PPI #1 +//------------------------------------------------- + +WRITE8_MEMBER( pioneer_ldv1000_device::ppi1_portb_w ) +{ + /* + $01 = /FOCS ON + $02 = /SPDL RUN + $04 = /JUMP TRIG + $08 = /SCAN A + $10 = SCAN B + $20 = SCAN C + $40 = /LASER ON + $80 = /SYNC ST0 + */ + + // set the new value + UINT8 prev = m_portb1; + m_portb1 = data; + if (LOG_PORT_IO && ((data ^ prev) & 0xff) != 0) + { + printf("%s:PORTB.1=%02X:", machine().describe_context(), data); + if (!(data & 0x01)) printf(" FOCSON"); + if (!(data & 0x02)) printf(" SPDLRUN"); + if (!(data & 0x04)) printf(" JUMPTRIG"); + if (!(data & 0x08)) printf(" SCANA (%c %c)", (data & 0x10) ? 'L' : 'H', (data & 0x20) ? 'F' : 'R'); + if ( (data & 0x40)) printf(" LASERON"); + if (!(data & 0x80)) printf(" SYNCST0"); + printf("\n"); + } + + // bit 5 selects the direction of slider movement for JUMP TRG and scanning + int direction = (data & 0x20) ? 1 : -1; + + // on the falling edge of bit 2, jump one track in either direction + if (!(data & 0x04) && (prev & 0x04)) + advance_slider(direction); + + // bit 3 low enables scanning + if (!(data & 0x08)) + { + // bit 4 selects the speed + int delta = (data & 0x10) ? SCAN_SPEED : SEEK_FAST_SPEED; + set_slider_speed(delta * direction); + } + + // bit 3 high stops scanning + else + set_slider_speed(0); +} + + +//------------------------------------------------- +// ppi1_portc_w - handle writes to port C of +// PPI #1 +//------------------------------------------------- + +WRITE8_MEMBER( pioneer_ldv1000_device::ppi1_portc_w ) +{ + /* + $01 = AUD 1 + $02 = AUD 2 + $04 = AUDIO ENABLE + $08 = /VIDEO SQ + $10 = COMMAND + $20 = STATUS + $40 = SIZE 8/12 + $80 = /LED CAV + */ + + // set the new value + UINT8 prev = m_portc1; + m_portc1 = data; + if (LOG_PORT_IO && ((data ^ prev) & 0xcf) != 0) + { + printf("%s:PORTC.1=%02X", machine().describe_context(), data); + if (data & 0x01) printf(" AUD1"); + if (data & 0x02) printf(" AUD2"); + if (data & 0x04) printf(" AUDEN"); + if (!(data & 0x08)) printf(" VIDEOSQ"); + if (data & 0x10) printf(" COMMAND"); + if (data & 0x20) printf(" STATUS"); + if (data & 0x40) printf(" SIZE8"); + if (!(data & 0x80)) printf(" CAV"); + printf("\n"); + } + + // video squelch is controlled by bit 3 + set_video_squelch((data & 0x08) == 0); + + // audio squelch is controlled by bits 0-2 + set_audio_squelch(!(data & 0x04) || !(data & 0x01), !(data & 0x04) || !(data & 0x02)); +} diff --git a/src/devices/machine/ldv1000.h b/src/devices/machine/ldv1000.h new file mode 100644 index 00000000000..bb65a24515e --- /dev/null +++ b/src/devices/machine/ldv1000.h @@ -0,0 +1,128 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/************************************************************************* + + ldv1000.h + + Pioneer LD-V1000 laserdisc emulation. + +*************************************************************************/ + +#pragma once + +#ifndef __LDV1000_H__ +#define __LDV1000_H__ + +#include "laserdsc.h" +#include "cpu/z80/z80.h" +#include "cpu/mcs48/mcs48.h" +#include "machine/z80ctc.h" + + +//************************************************************************** +// DEVICE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_LASERDISC_LDV1000_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, PIONEER_LDV1000, 0) + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +// device type definition +extern const device_type PIONEER_LDV1000; + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> pioneer_ldv1000_device + +// base ldv1000 class +class pioneer_ldv1000_device : public laserdisc_device +{ +public: + // construction/destruction + pioneer_ldv1000_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // input and output + void data_w(UINT8 data); + void enter_w(UINT8 data); + UINT8 status_r() const { return m_status; } + UINT8 status_strobe_r() const { return (m_portc1 & 0x20) ? ASSERT_LINE : CLEAR_LINE; } + UINT8 command_strobe_r() const { return (m_portc1 & 0x10) ? ASSERT_LINE : CLEAR_LINE; } + +protected: + // timer IDs + enum + { + TID_MULTIJUMP = TID_FIRST_PLAYER_TIMER, + TID_VSYNC_OFF, + TID_VBI_DATA_FETCH + }; + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + + // subclass overrides + virtual void player_vsync(const vbi_metadata &vbi, int fieldnum, const attotime &curtime); + virtual INT32 player_update(const vbi_metadata &vbi, int fieldnum, const attotime &curtime); + virtual void player_overlay(bitmap_yuy16 &bitmap) { } + + // internal helpers + bool focus_on() const { return !(m_portb1 & 0x01); } + bool spdl_on() const { return !(m_portb1 & 0x02); } + bool laser_on() const { return (m_portb1 & 0x40); } + +public: + // internal read/write handlers + DECLARE_WRITE_LINE_MEMBER( ctc_interrupt ); + DECLARE_WRITE8_MEMBER( z80_decoder_display_port_w ); + DECLARE_READ8_MEMBER( z80_decoder_display_port_r ); + DECLARE_READ8_MEMBER( z80_controller_r ); + DECLARE_WRITE8_MEMBER( z80_controller_w ); + DECLARE_WRITE8_MEMBER( ppi0_porta_w ); + DECLARE_READ8_MEMBER( ppi0_portb_r ); + DECLARE_READ8_MEMBER( ppi0_portc_r ); + DECLARE_WRITE8_MEMBER( ppi0_portc_w ); + DECLARE_READ8_MEMBER( ppi1_porta_r ); + DECLARE_WRITE8_MEMBER( ppi1_portb_w ); + DECLARE_WRITE8_MEMBER( ppi1_portc_w ); + +protected: + // internal state + required_device m_z80_cpu; /* CPU index of the Z80 */ + required_device m_z80_ctc; /* CTC device */ + emu_timer * m_multitimer; /* multi-jump timer device */ + + /* communication status */ + UINT8 m_command; /* command byte to the player */ + UINT8 m_status; /* status byte from the player */ + bool m_vsync; /* VSYNC state */ + + /* I/O port states */ + UINT8 m_counter_start; /* starting value for counter */ + UINT8 m_counter; /* current counter value */ + UINT8 m_portc0; /* port C on PPI 0 */ + UINT8 m_portb1; /* port B on PPI 1 */ + UINT8 m_portc1; /* port C on PPI 1 */ + + /* display/decode circuit emulation */ + UINT8 m_portselect; /* selection of which port to access */ + UINT8 m_display[2][20]; /* display lines */ + UINT8 m_dispindex; /* index within the display line */ + UINT8 m_vbi[7*3]; /* VBI data */ + bool m_vbiready; /* VBI ready flag */ + UINT8 m_vbiindex; /* index within the VBI data */ +}; + + +#endif diff --git a/src/devices/machine/ldvp931.c b/src/devices/machine/ldvp931.c new file mode 100644 index 00000000000..0d927fed665 --- /dev/null +++ b/src/devices/machine/ldvp931.c @@ -0,0 +1,653 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/************************************************************************* + + ldvp931.c + + Philips 22VP931 laserdisc emulation. + +************************************************************************** + + Still to do: + + * determine actual slow/fast speeds + * + +*************************************************************************/ + + +#include "emu.h" +#include "ldvp931.h" + + + +//************************************************************************** +// DEBUGGING +//************************************************************************** + +#define LOG_COMMANDS 0 +#define LOG_PORTS 0 + + + +//************************************************************************** +// CONSTANTS +//************************************************************************** + +// scanning speeds +#define SCAN_SPEED (2000 / 30) // 2000 frames/second +#define SCAN_FAST_SPEED (4000 / 30) // 4000 frames/second + + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +// devices +const device_type PHILLIPS_22VP931 = &device_creator; + + + +//************************************************************************** +// 22VP931 ROM AND MACHINE INTERFACES +//************************************************************************** + +static ADDRESS_MAP_START( vp931_portmap, AS_IO, 8, phillips_22vp931_device ) + AM_RANGE(0x00, 0x00) AM_MIRROR(0xcf) AM_READWRITE(i8049_keypad_r, i8049_output0_w) + AM_RANGE(0x10, 0x10) AM_MIRROR(0xcf) AM_READWRITE(i8049_unknown_r, i8049_output1_w) + AM_RANGE(0x20, 0x20) AM_MIRROR(0xcf) AM_READWRITE(i8049_datic_r, i8049_lcd_w) + AM_RANGE(0x30, 0x30) AM_MIRROR(0xcf) AM_READWRITE(i8049_from_controller_r, i8049_to_controller_w) + AM_RANGE(MCS48_PORT_P1, MCS48_PORT_P1) AM_READWRITE(i8049_port1_r, i8049_port1_w) + AM_RANGE(MCS48_PORT_P2, MCS48_PORT_P2) AM_READWRITE(i8049_port2_r, i8049_port2_w) + AM_RANGE(MCS48_PORT_T0, MCS48_PORT_T0) AM_READ(i8049_t0_r) + AM_RANGE(MCS48_PORT_T1, MCS48_PORT_T1) AM_READ(i8049_t1_r) +ADDRESS_MAP_END + + +static MACHINE_CONFIG_FRAGMENT( vp931 ) + MCFG_CPU_ADD("vp931", I8049, XTAL_11MHz) + MCFG_CPU_IO_MAP(vp931_portmap) +MACHINE_CONFIG_END + + +ROM_START( vp931 ) + ROM_REGION( 0x800, "vp931", 0 ) + ROM_LOAD( "at-6-1_a.bin", 0x000, 0x800, CRC(e11b3c8d) SHA1(ea2d7f6a044ed085ce5e09d8b1b1a21c37f0e9b8) ) +ROM_END + + + +//************************************************************************** +// PHILLIPS 22VP931 IMPLEMENTATION +//************************************************************************** + +//------------------------------------------------- +// phillips_22vp931_device - constructor +//------------------------------------------------- + +phillips_22vp931_device::phillips_22vp931_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : laserdisc_device(mconfig, PHILLIPS_22VP931, "Phillips 22VP931", tag, owner, clock, "22vp931", __FILE__), + m_i8049_cpu(*this, "vp931"), + m_tracktimer(NULL), + m_i8049_out0(0), + m_i8049_out1(0), + m_i8049_port1(0), + m_daticval(0), + m_daticerp(0), + m_datastrobe(0), + m_fromcontroller(0), + m_fromcontroller_pending(false), + m_tocontroller(0), + m_tocontroller_pending(false), + m_trackdir(0), + m_trackstate(0), + m_cmdcount(0), + m_advanced(0) +{ +} + + +//------------------------------------------------- +// reset_w - write to the reset line +//------------------------------------------------- + +void phillips_22vp931_device::reset_w(UINT8 data) +{ + // control the CPU state + m_i8049_cpu->set_input_line(INPUT_LINE_RESET, data); + + // on an assert, reset the device state as well + if (data == ASSERT_LINE) + reset(); +} + + +//------------------------------------------------- +// data_r - handle a parallel data read from the +// 22VP931 +//------------------------------------------------- + +UINT8 phillips_22vp931_device::data_r() +{ + // if data is pending, clear the pending flag and notify any callbacks + if (m_tocontroller_pending) + { + m_tocontroller_pending = false; + if (!m_data_ready.isnull()) + m_data_ready(*this, false); + } + + // also boost interleave for 4 scanlines to ensure proper communications + machine().scheduler().boost_interleave(attotime::zero, screen().scan_period() * 4); + return m_tocontroller; +} + + +//------------------------------------------------- +// device_start - device initialization +//------------------------------------------------- + +void phillips_22vp931_device::device_start() +{ + // pass through to the parent + laserdisc_device::device_start(); + + // allocate a timer + m_tracktimer = timer_alloc(TID_HALF_TRACK); +} + + +//------------------------------------------------- +// device_reset - device reset +//------------------------------------------------- + +void phillips_22vp931_device::device_reset() +{ + // pass through to the parent + laserdisc_device::device_reset(); + + // reset our state + m_i8049_out0 = 0; + m_i8049_out1 = 0; + m_i8049_port1 = 0; + + m_daticval = 0; + m_daticerp = 0; + m_datastrobe = 0; + + m_fromcontroller = 0; + m_fromcontroller_pending = false; + m_tocontroller = 0; + m_tocontroller_pending = false; + + m_trackdir = 0; + m_trackstate = 0; + + m_cmdcount = 0; + m_advanced = 0; +} + + +//------------------------------------------------- +// device_timer - handle timers set by this +// device +//------------------------------------------------- + +void phillips_22vp931_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch (id) + { + case TID_VBI_DATA_FETCH: + { + UINT32 line = param >> 2; + int which = param & 3; + UINT32 code = 0; + + // fetch the code and compute the DATIC latched value + if (line >= LASERDISC_CODE_LINE16 && line <= LASERDISC_CODE_LINE18) + code = get_field_code(laserdisc_field_code(line), false); + + // at the start of each line, signal an interrupt and use a timer to turn it off + if (which == 0) + { + m_i8049_cpu->set_input_line(MCS48_INPUT_IRQ, ASSERT_LINE); + timer_set(attotime::from_nsec(5580), TID_IRQ_OFF); + } + + // clock the data strobe on each subsequent callback + else if (code != 0) + { + m_daticval = code >> (8 * (3 - which)); + m_datastrobe = 1; + timer_set(attotime::from_nsec(5000), TID_DATA_STROBE_OFF); + } + + // determine the next bit to fetch and reprime ourself + if (++which == 4) + { + which = 0; + line++; + } + if (line <= LASERDISC_CODE_LINE18 + 1) + timer_set(screen().time_until_pos(line*2, which * 2 * screen().width() / 4), TID_VBI_DATA_FETCH, (line << 2) + which); + break; + } + + case TID_DEFERRED_DATA: + // set the value and mark it pending + if (LOG_COMMANDS && m_fromcontroller_pending) + printf("Dropped previous command byte\n"); + m_fromcontroller = param; + m_fromcontroller_pending = true; + + // track the commands for debugging purposes + if (m_cmdcount < ARRAY_LENGTH(m_cmdbuf)) + { + m_cmdbuf[m_cmdcount++ % 3] = param; + if (LOG_COMMANDS && m_cmdcount % 3 == 0) + printf("Cmd: %02X %02X %02X\n", m_cmdbuf[0], m_cmdbuf[1], m_cmdbuf[2]); + } + break; + + case TID_IRQ_OFF: + m_i8049_cpu->set_input_line(MCS48_INPUT_IRQ, CLEAR_LINE); + break; + + case TID_DATA_STROBE_OFF: + m_datastrobe = 0; + break; + + case TID_ERP_OFF: + m_daticerp = 0; + break; + + case TID_HALF_TRACK: + // advance by the count and toggle the state + m_trackstate ^= 1; + if ((m_trackdir < 0 && !m_trackstate) || (m_trackdir > 0 && m_trackstate)) + { + advance_slider(m_trackdir); + m_advanced += m_trackdir; + } + break; + + // pass everything else onto the parent + default: + laserdisc_device::device_timer(timer, id, param, ptr); + break; + } +} + + +//------------------------------------------------- +// device_rom_region - return a pointer to our +// ROM region definitions +//------------------------------------------------- + +const rom_entry *phillips_22vp931_device::device_rom_region() const +{ + return ROM_NAME(vp931); +} + + +//------------------------------------------------- +// device_mconfig_additions - return a pointer to +// our machine config fragment +//------------------------------------------------- + +machine_config_constructor phillips_22vp931_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME(vp931); +} + + +//------------------------------------------------- +// player_vsync - VSYNC callback, called at the +// start of the blanking period +//------------------------------------------------- + +void phillips_22vp931_device::player_vsync(const vbi_metadata &vbi, int fieldnum, const attotime &curtime) +{ + // reset our command counter (debugging only) + m_cmdcount = 0; + + // set the ERP signal to 1 to indicate start of frame, and set a timer to turn it off + m_daticerp = 1; + timer_set(screen().time_until_pos(15*2), TID_ERP_OFF); +} + + +//------------------------------------------------- +// player_update - update callback, called on +// the first visible line of the frame +//------------------------------------------------- + +INT32 phillips_22vp931_device::player_update(const vbi_metadata &vbi, int fieldnum, const attotime &curtime) +{ + // set the first VBI timer to go at the start of line 16 + timer_set(screen().time_until_pos(16*2), TID_VBI_DATA_FETCH, LASERDISC_CODE_LINE16 << 2); + + // play forward by default + return fieldnum; +} + + +//------------------------------------------------- +// i8049_output0_w - controls audio/video squelch +// and other bits +//------------------------------------------------- + +WRITE8_MEMBER( phillips_22vp931_device::i8049_output0_w ) +{ + /* + $80 = n/c + $40 = LED (?) -> C335 + $20 = LED (?) + $10 = LED (?) -> CX + $08 = EJECT + $04 = inverted -> AUDIO MUTE II + $02 = inverted -> AUDIO MUTE I + $01 = inverted -> VIDEO MUTE + */ + + if (LOG_PORTS && (m_i8049_out0 ^ data) & 0xff) + { + printf("%03X:out0:", space.device().safe_pc()); + if ( (data & 0x80)) printf(" ???"); + if ( (data & 0x40)) printf(" LED1"); + if ( (data & 0x20)) printf(" LED2"); + if ( (data & 0x10)) printf(" LED3"); + if ( (data & 0x08)) printf(" EJECT"); + if (!(data & 0x04)) printf(" AUDMUTE2"); + if (!(data & 0x02)) printf(" AUDMUTE1"); + if (!(data & 0x01)) printf(" VIDMUTE"); + printf("\n"); + m_i8049_out0 = data; + } + + // update a/v squelch + set_audio_squelch(!(data & 0x02), !(data & 0x04)); + set_video_squelch(!(data & 0x01)); +} + + +//------------------------------------------------- +// i8049_output1_w - controls scanning behaviors +//------------------------------------------------- + +WRITE8_MEMBER( phillips_22vp931_device::i8049_output1_w ) +{ + /* + $80 = n/c + $40 = n/c + $20 = n/c + $10 = n/c + $08 = inverted -> SMS + $04 = inverted -> SSS + $02 = inverted -> SCAN CMD + $01 = OSM + */ + + INT32 speed = 0; + + if (LOG_PORTS && (m_i8049_out1 ^ data) & 0x08) + { + osd_printf_debug("%03X:out1:", space.device().safe_pc()); + if (!(data & 0x08)) osd_printf_debug(" SMS"); + osd_printf_debug("\n"); + m_i8049_out1 = data; + } + + // speed is 0 unless SCAN CMD is clear + speed = 0; + if (!(data & 0x02)) + { + // fast/slow is based on bit 2 + speed = (data & 0x04) ? SCAN_FAST_SPEED : SCAN_SPEED; + + // direction is based on bit 0 + if (data & 0x01) + speed = -speed; + } + + // update the speed + set_slider_speed(speed); +} + + +//------------------------------------------------- +// i8049_lcd_w - vestigial LCD frame display +//------------------------------------------------- + +WRITE8_MEMBER( phillips_22vp931_device::i8049_lcd_w ) +{ + /* + Frame number is written as 5 digits here; however, it is not actually + connected + */ +} + + +//------------------------------------------------- +// i8049_unknown_r - unknown input port +//------------------------------------------------- + +READ8_MEMBER( phillips_22vp931_device::i8049_unknown_r ) +{ + // only bit $80 is checked and its effects are minor + return 0x00; +} + + +//------------------------------------------------- +// i8049_keypad_r - vestigial keypad/button +// controls +//------------------------------------------------- + +READ8_MEMBER( phillips_22vp931_device::i8049_keypad_r ) +{ + /* + From the code, this is apparently a vestigial keypad with basic controls: + $01 = play + $02 = still + $04 = jump 25 frames backward + $08 = jump 25 frames forward + $10 = search for frame 50(?) + $20 = search for frame 350(?) + $40 = reset + $80 = play reverse + */ + return 0x00; +} + + +//------------------------------------------------- +// i8049_datic_r - read the latched value from the +// DATIC circuit +//------------------------------------------------- + +READ8_MEMBER( phillips_22vp931_device::i8049_datic_r ) +{ + return m_daticval; +} + + +//------------------------------------------------- +// i8049_from_controller_r - read the value the +// external controller wrote +//------------------------------------------------- + +READ8_MEMBER( phillips_22vp931_device::i8049_from_controller_r ) +{ + // clear the pending flag and return the data + m_fromcontroller_pending = false; + return m_fromcontroller; +} + + +//------------------------------------------------- +// i8049_to_controller_w - write a value back to +// the external controller +//------------------------------------------------- + +WRITE8_MEMBER( phillips_22vp931_device::i8049_to_controller_w ) +{ + // set the pending flag and stash the data + m_tocontroller_pending = TRUE; + m_tocontroller = data; + + // signal to the callback if provided + if (!m_data_ready.isnull()) + m_data_ready(*this, true); + + // also boost interleave for 4 scanlines to ensure proper communications + machine().scheduler().boost_interleave(attotime::zero, screen().scan_period() * 4); +} + + +//------------------------------------------------- +// i8049_port1_r - read the 8048 I/O port 1 +//------------------------------------------------- + +READ8_MEMBER( phillips_22vp931_device::i8049_port1_r ) +{ + /* + $80 = P17 = (in) unsure + $40 = P16 = (in) /ERP from datic circuit + $20 = P15 = (in) D105 + */ + + UINT8 result = 0x00; + if (!m_daticerp) + result |= 0x40; + return result; +} + + +//------------------------------------------------- +// i8049_port1_w - write the 8048 I/O port 1 +//------------------------------------------------- + +WRITE8_MEMBER( phillips_22vp931_device::i8049_port1_w ) +{ + /* + $10 = P14 = (out) D104 -> /SPEED + $08 = P13 = (out) D103 -> /TIMER ENABLE + $04 = P12 = (out) D102 -> /REV + $02 = P11 = (out) D101 -> /FORW + $01 = P10 = (out) D100 -> some op-amp then to C334, B56, B332 + */ + + if (LOG_PORTS && (m_i8049_port1 ^ data) & 0x1f) + { + printf("%03X:port1:", space.device().safe_pc()); + if (!(data & 0x10)) printf(" SPEED"); + if (!(data & 0x08)) printf(" TIMENABLE"); + if (!(data & 0x04)) printf(" REV"); + if (!(data & 0x02)) printf(" FORW"); + if (!(data & 0x01)) printf(" OPAMP"); + printf("\n"); + } + + // if bit 0 is set, we are not tracking + if (data & 0x01) + m_trackdir = 0; + + // if bit 0 is clear and we weren't tracking before, initialize the state + else if (m_trackdir == 0) + { + m_advanced = 0; + + // if bit 2 is clear, we are moving backwards + if (!(data & 0x04)) + { + m_trackdir = -1; + m_trackstate = 1; + } + + // if bit 1 is clear, we are moving forward + else if (!(data & 0x02)) + { + m_trackdir = 1; + m_trackstate = 0; + } + } + + // if we have a timer, adjust it + if (m_tracktimer != NULL) + { + // turn it off if we're not tracking + if (m_trackdir == 0) + m_tracktimer->reset(); + + // if we just started tracking, or if the speed was changed, reprime the timer + else if (((m_i8049_port1 ^ data) & 0x11) != 0) + { + // speeds here are just guesses, but work with the player logic; this is the time per half-track + attotime speed = (data & 0x10) ? attotime::from_usec(60) : attotime::from_usec(10); + + // always start with an initial long delay; the code expects this + m_tracktimer->adjust(attotime::from_usec(100), 0, speed); + } + } + + m_i8049_port1 = data; +} + + +//------------------------------------------------- +// i8049_port2_r - read from the 8048 I/O port 2 +//------------------------------------------------- + +READ8_MEMBER( phillips_22vp931_device::i8049_port2_r ) +{ + /* + $80 = P27 = (in) set/reset latch; set by FOC LS, reset by IGR + $20 = P25 = (in) D125 -> 0 when data written to controller is preset, reset to 1 when read + $10 = P24 = (in) D124 -> 0 when data from controller is present, reset to 1 on a read + */ + + UINT8 result = 0x00; + if (!m_tocontroller_pending) + result |= 0x20; + if (!m_fromcontroller_pending) + result |= 0x10; + return result; +} + + +//------------------------------------------------- +// i8049_port2_w - write the 8048 I/O port 2 +//------------------------------------------------- + +WRITE8_MEMBER( phillips_22vp931_device::i8049_port2_w ) +{ + /* + $40 = P26 = (out) cleared while data is sent back & forth; set afterwards + [Not actually connected, but this is done in the code] + */ +} + + +//------------------------------------------------- +// i8049_t0_r - return the T0 line status, which is +// connected to the DATIC's data strobe line +//------------------------------------------------- + +READ8_MEMBER( phillips_22vp931_device::i8049_t0_r ) +{ + return m_datastrobe; +} + + +//------------------------------------------------- +// i8049_t1_r - return the T1 line status, which +// is connected to the tracking state and is used +// to count the number of tracks advanced +//------------------------------------------------- + +READ8_MEMBER( phillips_22vp931_device::i8049_t1_r ) +{ + return m_trackstate; +} diff --git a/src/devices/machine/ldvp931.h b/src/devices/machine/ldvp931.h new file mode 100644 index 00000000000..636f4529d6b --- /dev/null +++ b/src/devices/machine/ldvp931.h @@ -0,0 +1,138 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/************************************************************************* + + ldvp931.h + + Philips 22VP931 laserdisc emulation. + +*************************************************************************/ + +#pragma once + +#ifndef __LDVP931_H__ +#define __LDVP931_H__ + +#include "laserdsc.h" +#include "cpu/mcs48/mcs48.h" + + +//************************************************************************** +// DEVICE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_LASERDISC_22VP931_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, PHILLIPS_22VP931, 0) + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +// device type definition +extern const device_type PHILLIPS_22VP931; + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> phillips_22vp931_device + +// base _22vp931 class +class phillips_22vp931_device : public laserdisc_device +{ +public: + // types + typedef delegate data_ready_delegate; + + // construction/destruction + phillips_22vp931_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // input and output + void data_w(UINT8 data) { synchronize(TID_DEFERRED_DATA, data); } + void reset_w(UINT8 data); + UINT8 data_r(); + UINT8 ready_r() { return m_fromcontroller_pending ? CLEAR_LINE : ASSERT_LINE; } + UINT8 data_available_r() { return m_tocontroller_pending ? ASSERT_LINE : CLEAR_LINE; } + + // configuration + void set_data_ready_callback(data_ready_delegate callback) { m_data_ready = callback; } + +protected: + // timer IDs + enum + { + TID_IRQ_OFF = TID_FIRST_PLAYER_TIMER, + TID_DATA_STROBE_OFF, + TID_ERP_OFF, + TID_HALF_TRACK, + TID_VBI_DATA_FETCH, + TID_DEFERRED_DATA + }; + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + + // subclass overrides + virtual void player_vsync(const vbi_metadata &vbi, int fieldnum, const attotime &curtime); + virtual INT32 player_update(const vbi_metadata &vbi, int fieldnum, const attotime &curtime); + virtual void player_overlay(bitmap_yuy16 &bitmap) { } + +public: + // internal read/write handlers + DECLARE_WRITE8_MEMBER( i8049_output0_w ); + DECLARE_WRITE8_MEMBER( i8049_output1_w ); + DECLARE_WRITE8_MEMBER( i8049_lcd_w ); + DECLARE_READ8_MEMBER( i8049_unknown_r ); + DECLARE_READ8_MEMBER( i8049_keypad_r ); + DECLARE_READ8_MEMBER( i8049_datic_r ); + DECLARE_READ8_MEMBER( i8049_from_controller_r ); + DECLARE_WRITE8_MEMBER( i8049_to_controller_w ); + DECLARE_READ8_MEMBER( i8049_port1_r ); + DECLARE_WRITE8_MEMBER( i8049_port1_w ); + DECLARE_READ8_MEMBER( i8049_port2_r ); + DECLARE_WRITE8_MEMBER( i8049_port2_w ); + DECLARE_READ8_MEMBER( i8049_t0_r ); + DECLARE_READ8_MEMBER( i8049_t1_r ); + +protected: + // internal state + required_device m_i8049_cpu; // CPU index of the 8049 + emu_timer * m_tracktimer; // timer device + data_ready_delegate m_data_ready; // data ready callback + + // I/O port states + UINT8 m_i8049_out0; // output 0 state + UINT8 m_i8049_out1; // output 1 state + UINT8 m_i8049_port1; // port 1 state + + // DATIC circuit implementation + UINT8 m_daticval; // latched DATIC value + UINT8 m_daticerp; // /ERP value from DATIC + UINT8 m_datastrobe; // DATA STROBE line from DATIC + + // communication status + UINT8 m_reset_state; // state of the reset input + UINT8 m_fromcontroller; // command byte from the controller + bool m_fromcontroller_pending; // true if data is pending + UINT8 m_tocontroller; // command byte to the controller + bool m_tocontroller_pending; // true if data is pending + + // tracking + INT8 m_trackdir; // direction of tracking + UINT8 m_trackstate; // state of tracking + + // debugging + UINT8 m_cmdbuf[3]; // 3 bytes worth of commands + UINT8 m_cmdcount; // number of command bytes seen + INT16 m_advanced; // number of frames advanced +}; + + +#endif diff --git a/src/devices/machine/legscsi.c b/src/devices/machine/legscsi.c new file mode 100644 index 00000000000..4071ccf8c3a --- /dev/null +++ b/src/devices/machine/legscsi.c @@ -0,0 +1,152 @@ +// license:BSD-3-Clause +// copyright-holders:smf +#include "legscsi.h" + +legacy_scsi_host_adapter::legacy_scsi_host_adapter(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + m_scsi_port(*this) +{ +} + +void legacy_scsi_host_adapter::device_start() +{ +} + +void legacy_scsi_host_adapter::reset_bus() +{ + for (int i = 0; i <= 7; i++) + { + scsihle_device *scsidev = get_device(i); + if (scsidev != NULL) + { + scsidev->reset(); + } + } +} + +bool legacy_scsi_host_adapter::select(int id) +{ + m_selected = id; + + scsihle_device *scsidev = get_device(m_selected); + if (scsidev != NULL) + { + return true; + } + + return false; +} + +void legacy_scsi_host_adapter::send_command(UINT8 *data, int bytes) +{ + scsihle_device *scsidev = get_device(m_selected); + if (scsidev != NULL) + { + scsidev->SetCommand(data, bytes); + scsidev->ExecCommand(); + } + else + { + logerror("%s: send_command unknown SCSI id %d\n", tag(), m_selected); + } +} + +int legacy_scsi_host_adapter::get_length(void) +{ + scsihle_device *scsidev = get_device(m_selected); + if (scsidev != NULL) + { + int length; + scsidev->GetLength(&length); + return length; + } + else + { + logerror("%s: get_length unknown SCSI id %d\n", tag(), m_selected); + return 0; + } +} + +int legacy_scsi_host_adapter::get_phase(void) +{ + scsihle_device *scsidev = get_device(m_selected); + if (scsidev != NULL) + { + int phase; + scsidev->GetPhase(&phase); + return phase; + } + else + { + logerror("%s: get_phase unknown SCSI id %d\n", tag(), m_selected); + return 0; + } +} + +void legacy_scsi_host_adapter::read_data(UINT8 *data, int bytes) +{ + scsihle_device *scsidev = get_device(m_selected); + if (scsidev != NULL) + { + scsidev->ReadData(data, bytes); + } + else + { + logerror("%s: read_data unknown SCSI id %d\n", tag(), m_selected); + } +} + +void legacy_scsi_host_adapter::write_data(UINT8 *data, int bytes) +{ + scsihle_device *scsidev = get_device(m_selected); + if (scsidev != NULL) + { + scsidev->WriteData(data, bytes); + } + else + { + logerror("%s: write_data unknown SCSI id %d\n", tag(), m_selected); + } +} + +UINT8 legacy_scsi_host_adapter::get_status() +{ + scsihle_device *scsidev = get_device(m_selected); + if (scsidev != NULL) + { + void *image; + + scsidev->GetDevice(&image); + if (image != NULL) + return 0x00; + + return 0x02; + } + else + { + logerror("%s: get_status unknown SCSI id %d\n", tag(), m_selected); + return 0; + } +} + +scsihle_device *legacy_scsi_host_adapter::get_device(int id) +{ + // steal scsi devices from bus + for (device_t *device = m_scsi_port->first_subdevice(); device != NULL; device = device->next()) + { + SCSI_PORT_SLOT_device *slot = dynamic_cast(device); + if (slot != NULL) + { + scsihle_device *scsidev = dynamic_cast(slot->dev()); + if (scsidev != NULL) + { + if (scsidev->GetDeviceID() == id) + { + return scsidev; + } + } + } + } + + return NULL; +} diff --git a/src/devices/machine/legscsi.h b/src/devices/machine/legscsi.h new file mode 100644 index 00000000000..c7382fa9ad0 --- /dev/null +++ b/src/devices/machine/legscsi.h @@ -0,0 +1,39 @@ +// license:BSD-3-Clause +// copyright-holders:smf +#ifndef _LEGSCSI_H_ +#define _LEGSCSI_H_ + +#pragma once + +#include "bus/scsi/scsihle.h" + +#define MCFG_LEGACY_SCSI_PORT(_tag) \ + legacy_scsi_host_adapter::set_scsi_port(*device, "^" _tag); + +class legacy_scsi_host_adapter : public device_t +{ +public: + legacy_scsi_host_adapter(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + static void set_scsi_port(device_t &device, const char *tag) { downcast(device).m_scsi_port.set_tag(tag); } + +protected: + virtual void device_start(); + + void reset_bus(); + bool select(int id); + void send_command(UINT8 *data, int bytes); + int get_length(); + int get_phase(); + void read_data(UINT8 *data, int bytes); + void write_data(UINT8 *data, int bytes); + UINT8 get_status(); + +private: + int m_selected; + scsihle_device *get_device(int id); + + required_device m_scsi_port; +}; + +#endif diff --git a/src/devices/machine/lh5810.c b/src/devices/machine/lh5810.c new file mode 100644 index 00000000000..296a28a60ec --- /dev/null +++ b/src/devices/machine/lh5810.c @@ -0,0 +1,171 @@ +// license:BSD-3-Clause +// copyright-holders:Sandro Ronco +/********************************************************************** + + LH5810/LH5811 Input/Output Port Controller + + TODO: + - serial data transfer + - data transfer to the cassette tape + +**********************************************************************/ + +#include "emu.h" +#include "lh5810.h" + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type LH5810 = &device_creator; + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// lh5810_device - constructor +//------------------------------------------------- + +lh5810_device::lh5810_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, LH5810, "LH5810", tag, owner, clock, "lh5810", __FILE__), + m_porta_r_cb(*this), + m_porta_w_cb(*this), + m_portb_r_cb(*this), + m_portb_w_cb(*this), + m_portc_w_cb(*this), + m_out_int_cb(*this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void lh5810_device::device_start() +{ + // resolve callbacks + m_porta_r_cb.resolve_safe(0); + m_porta_w_cb.resolve_safe(); + m_portb_r_cb.resolve_safe(0); + m_portb_w_cb.resolve_safe(); + m_portc_w_cb.resolve_safe(); + m_out_int_cb.resolve_safe(); + + // register for state saving + save_item(NAME(m_irq)); + save_item(NAME(m_reg)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void lh5810_device::device_reset() +{ + memset(m_reg, 0, sizeof(m_reg)); + m_irq = 0; +} + + +//------------------------------------------------- +// data_r - data read +//------------------------------------------------- + +READ8_MEMBER( lh5810_device::data_r ) +{ + switch (offset) + { + case LH5810_U: + case LH5810_L: + case LH5810_G: + case LH5810_DDA: + case LH5810_DDB: + case LH5810_OPC: + case LH5820_F: + return m_reg[offset]; + + case LH5810_IF: + if (BIT(m_portb_r_cb(0) & ~m_reg[LH5810_DDB], 7)) + m_reg[offset] |= 2; + else + m_reg[offset] &= 0xfd; + + return m_reg[offset]; + + case LH5810_MSK: + return (m_reg[offset]&0x0f) | (m_irq<<4) | (BIT(m_reg[LH5810_OPB],7)<<5); + + case LH5810_OPA: + m_reg[offset] = (m_reg[offset] & m_reg[LH5810_DDA]) | (m_porta_r_cb(0) & ~m_reg[LH5810_DDA]); + return m_reg[offset]; + + case LH5810_OPB: + m_reg[offset] = (m_reg[offset] & m_reg[LH5810_DDB]) | (m_portb_r_cb(0) & ~m_reg[LH5810_DDB]); + m_out_int_cb((m_reg[offset] & 0x80 && m_reg[LH5810_MSK] & 0x02) ? ASSERT_LINE : CLEAR_LINE); + return m_reg[offset]; + + default: + return 0x00; + } +} + + +//------------------------------------------------- +// data_w - data write +//------------------------------------------------- + +WRITE8_MEMBER( lh5810_device::data_w ) +{ + switch (offset) + { + case LH5810_RESET: + break; + + case LH5810_G: + case LH5820_F: + case LH5810_DDA: + case LH5810_DDB: + m_reg[offset] = data; + break; + + case LH5810_U: + //writing on U register clear the RD flag of IF register + m_reg[LH5810_IF] &= 0xfb; + m_reg[offset] = data; + break; + + case LH5810_L: + //writing on L register clear the TD flag of IF register + m_reg[LH5810_IF] &= 0xf7; + m_reg[offset] = data; + break; + + case LH5810_MSK: + m_reg[offset] = data & 0x0f; + break; + + case LH5810_IF: + //only bit 0 and 1 are writable + m_reg[offset] = (m_reg[offset] & 0xfc) | (data & 0x03); + break; + + case LH5810_OPA: + m_reg[offset] = (data & m_reg[LH5810_DDA]) | (m_reg[offset] & ~m_reg[LH5810_DDA]); + m_porta_w_cb((offs_t)0, m_reg[offset]); + break; + + case LH5810_OPB: + m_reg[offset] = (data & m_reg[LH5810_DDB]) | (m_reg[offset] & ~m_reg[LH5810_DDB]); + m_portb_w_cb((offs_t)0, m_reg[offset]); + m_out_int_cb((m_reg[offset] & 0x80 && m_reg[LH5810_MSK] & 0x02) ? ASSERT_LINE : CLEAR_LINE); + break; + + case LH5810_OPC: + m_reg[offset] = data; + m_portc_w_cb((offs_t)0, m_reg[offset]); + break; + } +} diff --git a/src/devices/machine/lh5810.h b/src/devices/machine/lh5810.h new file mode 100644 index 00000000000..d78458ca172 --- /dev/null +++ b/src/devices/machine/lh5810.h @@ -0,0 +1,106 @@ +// license:BSD-3-Clause +// copyright-holders:Sandro Ronco +/********************************************************************** + + LH5810/LH5811 Input/Output Port Controller + +**********************************************************************/ + +#pragma once + +#ifndef __LH5810__ +#define __LH5810__ + +#include "emu.h" + +//************************************************************************* +// MACROS / CONSTANTS +//************************************************************************* + +enum +{ + LH5810_RESET = 4, + LH5810_U, + LH5810_L, + LH5820_F, + LH5810_OPC, + LH5810_G, + LH5810_MSK, + LH5810_IF, + LH5810_DDA, + LH5810_DDB, + LH5810_OPA, + LH5810_OPB +}; + + +//************************************************************************* +// INTERFACE CONFIGURATION MACROS +//************************************************************************* + +#define MCFG_LH5810_PORTA_R_CB(_devcb) \ + devcb = &lh5810_device::set_porta_r_callback(*device, DEVCB_##_devcb); + +#define MCFG_LH5810_PORTA_W_CB(_devcb) \ + devcb = &lh5810_device::set_porta_w_callback(*device, DEVCB_##_devcb); + +#define MCFG_LH5810_PORTB_R_CB(_devcb) \ + devcb = &lh5810_device::set_portb_r_callback(*device, DEVCB_##_devcb); + +#define MCFG_LH5810_PORTB_W_CB(_devcb) \ + devcb = &lh5810_device::set_portb_w_callback(*device, DEVCB_##_devcb); + +#define MCFG_LH5810_PORTC_W_CB(_devcb) \ + devcb = &lh5810_device::set_portc_w_callback(*device, DEVCB_##_devcb); + +#define MCFG_LH5810_OUT_INT_CB(_devcb) \ + devcb = &lh5810_device::set_out_int_callback(*device, DEVCB_##_devcb); //currently unused + + + +//************************************************************************* +// TYPE DEFINITIONS +//************************************************************************* + +// ======================> lh5810_device + +class lh5810_device : public device_t +{ +public: + // construction/destruction + lh5810_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + template static devcb_base &set_porta_r_callback(device_t &device, _Object object) { return downcast(device).m_porta_r_cb.set_callback(object); } + template static devcb_base &set_porta_w_callback(device_t &device, _Object object) { return downcast(device).m_porta_w_cb.set_callback(object); } + template static devcb_base &set_portb_r_callback(device_t &device, _Object object) { return downcast(device).m_portb_r_cb.set_callback(object); } + template static devcb_base &set_portb_w_callback(device_t &device, _Object object) { return downcast(device).m_portb_w_cb.set_callback(object); } + template static devcb_base &set_portc_w_callback(device_t &device, _Object object) { return downcast(device).m_portc_w_cb.set_callback(object); } + template static devcb_base &set_out_int_callback(device_t &device, _Object object) { return downcast(device).m_out_int_cb.set_callback(object); } + + DECLARE_READ8_MEMBER( data_r ); + DECLARE_WRITE8_MEMBER( data_w ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + +private: + + devcb_read8 m_porta_r_cb; //port A read + devcb_write8 m_porta_w_cb; //port A write + devcb_read8 m_portb_r_cb; //port B read + devcb_write8 m_portb_w_cb; //port B write + devcb_write8 m_portc_w_cb; //port C write + + devcb_write_line m_out_int_cb; //IRQ callback + + UINT8 m_reg[0x10]; + UINT8 m_irq; +}; + + +// device type definition +extern const device_type LH5810; + +#endif diff --git a/src/devices/machine/linflash.c b/src/devices/machine/linflash.c new file mode 100644 index 00000000000..fe72efa921d --- /dev/null +++ b/src/devices/machine/linflash.c @@ -0,0 +1,208 @@ +// license:BSD-3-Clause +// copyright-holders:smf +#include "linflash.h" + +linear_flash_pccard_device::linear_flash_pccard_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock,const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_memory_interface(mconfig, *this), + device_slot_card_interface(mconfig, *this) +{ +} + +void linear_flash_pccard_device::device_start() +{ + m_space = &space(AS_0); +} + +const address_space_config *linear_flash_pccard_device::memory_space_config( address_spacenum spacenum ) const +{ + return ( spacenum == AS_0 ) ? &m_space_config : NULL; +} + +READ16_MEMBER( linear_flash_pccard_device::read_memory ) +{ + UINT16 data = m_space->read_word(offset * 2, mem_mask); + //printf( "<%08x %04x %04x\n", offset, data, mem_mask ); + return data; +} + +WRITE16_MEMBER( linear_flash_pccard_device::write_memory ) +{ + //printf( ">%08x %04x %04x\n", offset, data, mem_mask ); + m_space->write_word(offset * 2, data, mem_mask); +} + + +const device_type LINEAR_FLASH_PCCARD_16MB = &device_creator; + +static ADDRESS_MAP_START(linear_flash_pccard_16mb, AS_0, 16, linear_flash_pccard_16mb_device) + ADDRESS_MAP_UNMAP_HIGH + AM_RANGE(0x00000000, 0x003fffff) AM_DEVREADWRITE8("1l", intelfsh8_device, read, write, 0x00ff) + AM_RANGE(0x00000000, 0x003fffff) AM_DEVREADWRITE8("1u", intelfsh8_device, read, write, 0xff00) + AM_RANGE(0x00400000, 0x007fffff) AM_DEVREADWRITE8("2l", intelfsh8_device, read, write, 0x00ff) + AM_RANGE(0x00400000, 0x007fffff) AM_DEVREADWRITE8("2u", intelfsh8_device, read, write, 0xff00) + AM_RANGE(0x00800000, 0x00bfffff) AM_DEVREADWRITE8("3l", intelfsh8_device, read, write, 0x00ff) + AM_RANGE(0x00800000, 0x00bfffff) AM_DEVREADWRITE8("3u", intelfsh8_device, read, write, 0xff00) + AM_RANGE(0x00c00000, 0x00ffffff) AM_DEVREADWRITE8("4l", intelfsh8_device, read, write, 0x00ff) + AM_RANGE(0x00c00000, 0x00ffffff) AM_DEVREADWRITE8("4u", intelfsh8_device, read, write, 0xff00) +ADDRESS_MAP_END + +linear_flash_pccard_16mb_device::linear_flash_pccard_16mb_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + linear_flash_pccard_device(mconfig, LINEAR_FLASH_PCCARD_16MB, "Linear Flash PCCARD (16MB)", tag, owner, clock, "linearflash16mb", __FILE__) +{ + m_space_config = address_space_config("memory", ENDIANNESS_LITTLE, 16, 26, 0, *ADDRESS_MAP_NAME( linear_flash_pccard_16mb ) ); +} + +static MACHINE_CONFIG_FRAGMENT( linear_flash_pccard_16mb ) + MCFG_FUJITSU_29F016A_ADD("1l") + MCFG_FUJITSU_29F016A_ADD("1u") + MCFG_FUJITSU_29F016A_ADD("2l") + MCFG_FUJITSU_29F016A_ADD("2u") + MCFG_FUJITSU_29F016A_ADD("3l") + MCFG_FUJITSU_29F016A_ADD("3u") + MCFG_FUJITSU_29F016A_ADD("4l") + MCFG_FUJITSU_29F016A_ADD("4u") +MACHINE_CONFIG_END + +machine_config_constructor linear_flash_pccard_16mb_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( linear_flash_pccard_16mb ); +} + + +const device_type LINEAR_FLASH_PCCARD_32MB = &device_creator; + +static ADDRESS_MAP_START(linear_flash_pccard_32mb, AS_0, 16, linear_flash_pccard_32mb_device) + ADDRESS_MAP_UNMAP_HIGH + AM_RANGE(0x00000000, 0x003fffff) AM_DEVREADWRITE8("1l", intelfsh8_device, read, write, 0x00ff) + AM_RANGE(0x00000000, 0x003fffff) AM_DEVREADWRITE8("1u", intelfsh8_device, read, write, 0xff00) + AM_RANGE(0x00400000, 0x007fffff) AM_DEVREADWRITE8("2l", intelfsh8_device, read, write, 0x00ff) + AM_RANGE(0x00400000, 0x007fffff) AM_DEVREADWRITE8("2u", intelfsh8_device, read, write, 0xff00) + AM_RANGE(0x00800000, 0x00bfffff) AM_DEVREADWRITE8("3l", intelfsh8_device, read, write, 0x00ff) + AM_RANGE(0x00800000, 0x00bfffff) AM_DEVREADWRITE8("3u", intelfsh8_device, read, write, 0xff00) + AM_RANGE(0x00c00000, 0x00ffffff) AM_DEVREADWRITE8("4l", intelfsh8_device, read, write, 0x00ff) + AM_RANGE(0x00c00000, 0x00ffffff) AM_DEVREADWRITE8("4u", intelfsh8_device, read, write, 0xff00) + AM_RANGE(0x01000000, 0x013fffff) AM_DEVREADWRITE8("5l", intelfsh8_device, read, write, 0x00ff) + AM_RANGE(0x01000000, 0x013fffff) AM_DEVREADWRITE8("5u", intelfsh8_device, read, write, 0xff00) + AM_RANGE(0x01400000, 0x017fffff) AM_DEVREADWRITE8("6l", intelfsh8_device, read, write, 0x00ff) + AM_RANGE(0x01400000, 0x017fffff) AM_DEVREADWRITE8("6u", intelfsh8_device, read, write, 0xff00) + AM_RANGE(0x01800000, 0x01bfffff) AM_DEVREADWRITE8("7l", intelfsh8_device, read, write, 0x00ff) + AM_RANGE(0x01800000, 0x01bfffff) AM_DEVREADWRITE8("7u", intelfsh8_device, read, write, 0xff00) + AM_RANGE(0x01c00000, 0x01ffffff) AM_DEVREADWRITE8("8l", intelfsh8_device, read, write, 0x00ff) + AM_RANGE(0x01c00000, 0x01ffffff) AM_DEVREADWRITE8("8u", intelfsh8_device, read, write, 0xff00) +ADDRESS_MAP_END + +linear_flash_pccard_32mb_device::linear_flash_pccard_32mb_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + linear_flash_pccard_device(mconfig, LINEAR_FLASH_PCCARD_32MB, "Linear Flash PCCARD (32MB)", tag, owner, clock, "linearflash32mb", __FILE__) +{ + m_space_config = address_space_config("memory", ENDIANNESS_LITTLE, 16, 26, 0, *ADDRESS_MAP_NAME( linear_flash_pccard_32mb ) ); +} + +static MACHINE_CONFIG_FRAGMENT( linear_flash_pccard_32mb ) + MCFG_FUJITSU_29F016A_ADD("1l") + MCFG_FUJITSU_29F016A_ADD("1u") + MCFG_FUJITSU_29F016A_ADD("2l") + MCFG_FUJITSU_29F016A_ADD("2u") + MCFG_FUJITSU_29F016A_ADD("3l") + MCFG_FUJITSU_29F016A_ADD("3u") + MCFG_FUJITSU_29F016A_ADD("4l") + MCFG_FUJITSU_29F016A_ADD("4u") + MCFG_FUJITSU_29F016A_ADD("5l") + MCFG_FUJITSU_29F016A_ADD("5u") + MCFG_FUJITSU_29F016A_ADD("6l") + MCFG_FUJITSU_29F016A_ADD("6u") + MCFG_FUJITSU_29F016A_ADD("7l") + MCFG_FUJITSU_29F016A_ADD("7u") + MCFG_FUJITSU_29F016A_ADD("8l") + MCFG_FUJITSU_29F016A_ADD("8u") +MACHINE_CONFIG_END + +machine_config_constructor linear_flash_pccard_32mb_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( linear_flash_pccard_32mb ); +} + + +const device_type LINEAR_FLASH_PCCARD_64MB = &device_creator; + +static ADDRESS_MAP_START(linear_flash_pccard_64mb, AS_0, 16, linear_flash_pccard_64mb_device) + ADDRESS_MAP_UNMAP_HIGH + AM_RANGE(0x00000000, 0x003fffff) AM_DEVREADWRITE8("1l", intelfsh8_device, read, write, 0x00ff) + AM_RANGE(0x00000000, 0x003fffff) AM_DEVREADWRITE8("1u", intelfsh8_device, read, write, 0xff00) + AM_RANGE(0x00400000, 0x007fffff) AM_DEVREADWRITE8("2l", intelfsh8_device, read, write, 0x00ff) + AM_RANGE(0x00400000, 0x007fffff) AM_DEVREADWRITE8("2u", intelfsh8_device, read, write, 0xff00) + AM_RANGE(0x00800000, 0x00bfffff) AM_DEVREADWRITE8("3l", intelfsh8_device, read, write, 0x00ff) + AM_RANGE(0x00800000, 0x00bfffff) AM_DEVREADWRITE8("3u", intelfsh8_device, read, write, 0xff00) + AM_RANGE(0x00c00000, 0x00ffffff) AM_DEVREADWRITE8("4l", intelfsh8_device, read, write, 0x00ff) + AM_RANGE(0x00c00000, 0x00ffffff) AM_DEVREADWRITE8("4u", intelfsh8_device, read, write, 0xff00) + AM_RANGE(0x01000000, 0x013fffff) AM_DEVREADWRITE8("5l", intelfsh8_device, read, write, 0x00ff) + AM_RANGE(0x01000000, 0x013fffff) AM_DEVREADWRITE8("5u", intelfsh8_device, read, write, 0xff00) + AM_RANGE(0x01400000, 0x017fffff) AM_DEVREADWRITE8("6l", intelfsh8_device, read, write, 0x00ff) + AM_RANGE(0x01400000, 0x017fffff) AM_DEVREADWRITE8("6u", intelfsh8_device, read, write, 0xff00) + AM_RANGE(0x01800000, 0x01bfffff) AM_DEVREADWRITE8("7l", intelfsh8_device, read, write, 0x00ff) + AM_RANGE(0x01800000, 0x01bfffff) AM_DEVREADWRITE8("7u", intelfsh8_device, read, write, 0xff00) + AM_RANGE(0x01c00000, 0x01ffffff) AM_DEVREADWRITE8("8l", intelfsh8_device, read, write, 0x00ff) + AM_RANGE(0x01c00000, 0x01ffffff) AM_DEVREADWRITE8("8u", intelfsh8_device, read, write, 0xff00) + AM_RANGE(0x02000000, 0x023fffff) AM_DEVREADWRITE8("9l", intelfsh8_device, read, write, 0x00ff) + AM_RANGE(0x02000000, 0x023fffff) AM_DEVREADWRITE8("9u", intelfsh8_device, read, write, 0xff00) + AM_RANGE(0x02400000, 0x027fffff) AM_DEVREADWRITE8("10l", intelfsh8_device, read, write, 0x00ff) + AM_RANGE(0x02400000, 0x027fffff) AM_DEVREADWRITE8("10u", intelfsh8_device, read, write, 0xff00) + AM_RANGE(0x02800000, 0x02bfffff) AM_DEVREADWRITE8("11l", intelfsh8_device, read, write, 0x00ff) + AM_RANGE(0x02800000, 0x02bfffff) AM_DEVREADWRITE8("11u", intelfsh8_device, read, write, 0xff00) + AM_RANGE(0x02c00000, 0x02ffffff) AM_DEVREADWRITE8("12l", intelfsh8_device, read, write, 0x00ff) + AM_RANGE(0x02c00000, 0x02ffffff) AM_DEVREADWRITE8("12u", intelfsh8_device, read, write, 0xff00) + AM_RANGE(0x03000000, 0x033fffff) AM_DEVREADWRITE8("13l", intelfsh8_device, read, write, 0x00ff) + AM_RANGE(0x03000000, 0x033fffff) AM_DEVREADWRITE8("13u", intelfsh8_device, read, write, 0xff00) + AM_RANGE(0x03400000, 0x037fffff) AM_DEVREADWRITE8("14l", intelfsh8_device, read, write, 0x00ff) + AM_RANGE(0x03400000, 0x037fffff) AM_DEVREADWRITE8("14u", intelfsh8_device, read, write, 0xff00) + AM_RANGE(0x03800000, 0x03bfffff) AM_DEVREADWRITE8("15l", intelfsh8_device, read, write, 0x00ff) + AM_RANGE(0x03800000, 0x03bfffff) AM_DEVREADWRITE8("15u", intelfsh8_device, read, write, 0xff00) + AM_RANGE(0x03c00000, 0x03ffffff) AM_DEVREADWRITE8("16l", intelfsh8_device, read, write, 0x00ff) + AM_RANGE(0x03c00000, 0x03ffffff) AM_DEVREADWRITE8("16u", intelfsh8_device, read, write, 0xff00) +ADDRESS_MAP_END + +linear_flash_pccard_64mb_device::linear_flash_pccard_64mb_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + linear_flash_pccard_device(mconfig, LINEAR_FLASH_PCCARD_64MB, "Linear Flash PCCARD (64MB)", tag, owner, clock, "linearflash64mb", __FILE__) +{ + m_space_config = address_space_config("memory", ENDIANNESS_LITTLE, 16, 26, 0, *ADDRESS_MAP_NAME( linear_flash_pccard_64mb ) ); +} + +static MACHINE_CONFIG_FRAGMENT( linear_flash_pccard_64mb ) + MCFG_FUJITSU_29F016A_ADD("1l") + MCFG_FUJITSU_29F016A_ADD("1u") + MCFG_FUJITSU_29F016A_ADD("2l") + MCFG_FUJITSU_29F016A_ADD("2u") + MCFG_FUJITSU_29F016A_ADD("3l") + MCFG_FUJITSU_29F016A_ADD("3u") + MCFG_FUJITSU_29F016A_ADD("4l") + MCFG_FUJITSU_29F016A_ADD("4u") + MCFG_FUJITSU_29F016A_ADD("5l") + MCFG_FUJITSU_29F016A_ADD("5u") + MCFG_FUJITSU_29F016A_ADD("6l") + MCFG_FUJITSU_29F016A_ADD("6u") + MCFG_FUJITSU_29F016A_ADD("7l") + MCFG_FUJITSU_29F016A_ADD("7u") + MCFG_FUJITSU_29F016A_ADD("8l") + MCFG_FUJITSU_29F016A_ADD("8u") + MCFG_FUJITSU_29F016A_ADD("9l") + MCFG_FUJITSU_29F016A_ADD("9u") + MCFG_FUJITSU_29F016A_ADD("10l") + MCFG_FUJITSU_29F016A_ADD("10u") + MCFG_FUJITSU_29F016A_ADD("11l") + MCFG_FUJITSU_29F016A_ADD("11u") + MCFG_FUJITSU_29F016A_ADD("12l") + MCFG_FUJITSU_29F016A_ADD("12u") + MCFG_FUJITSU_29F016A_ADD("13l") + MCFG_FUJITSU_29F016A_ADD("13u") + MCFG_FUJITSU_29F016A_ADD("14l") + MCFG_FUJITSU_29F016A_ADD("14u") + MCFG_FUJITSU_29F016A_ADD("15l") + MCFG_FUJITSU_29F016A_ADD("15u") + MCFG_FUJITSU_29F016A_ADD("16l") + MCFG_FUJITSU_29F016A_ADD("16u") +MACHINE_CONFIG_END + +machine_config_constructor linear_flash_pccard_64mb_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( linear_flash_pccard_64mb ); +} diff --git a/src/devices/machine/linflash.h b/src/devices/machine/linflash.h new file mode 100644 index 00000000000..b4bd488d55d --- /dev/null +++ b/src/devices/machine/linflash.h @@ -0,0 +1,72 @@ +// license:BSD-3-Clause +// copyright-holders:smf +#pragma once + +#ifndef __LINFLASH_H__ +#define __LINFLASH_H__ + +#include "emu.h" +#include "intelfsh.h" +#include "machine/pccard.h" + +class linear_flash_pccard_device : public device_t, + public pccard_interface, + public device_memory_interface, + public device_slot_card_interface +{ +public: + virtual DECLARE_READ16_MEMBER(read_memory); + virtual DECLARE_WRITE16_MEMBER(write_memory); + +protected: + linear_flash_pccard_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock,const char *shortname, const char *source); + + // device-level overrides + virtual void device_start(); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config( address_spacenum spacenum = AS_0 ) const; + + address_space_config m_space_config; + address_space *m_space; +}; + + +extern const device_type LINEAR_FLASH_PCCARD_16MB; + +class linear_flash_pccard_16mb_device : public linear_flash_pccard_device +{ +public: + linear_flash_pccard_16mb_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // device-level overrides + virtual machine_config_constructor device_mconfig_additions() const; +}; + + +extern const device_type LINEAR_FLASH_PCCARD_32MB; + +class linear_flash_pccard_32mb_device : public linear_flash_pccard_device +{ +public: + linear_flash_pccard_32mb_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // device-level overrides + virtual machine_config_constructor device_mconfig_additions() const; +}; + +extern const device_type LINEAR_FLASH_PCCARD_64MB; + +class linear_flash_pccard_64mb_device : public linear_flash_pccard_device +{ +public: + linear_flash_pccard_64mb_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // device-level overrides + virtual machine_config_constructor device_mconfig_additions() const; +}; + +#endif diff --git a/src/devices/machine/lpc-acpi.c b/src/devices/machine/lpc-acpi.c new file mode 100644 index 00000000000..72d066affaa --- /dev/null +++ b/src/devices/machine/lpc-acpi.c @@ -0,0 +1,368 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +#include "lpc-acpi.h" + +const device_type LPC_ACPI = &device_creator; + +DEVICE_ADDRESS_MAP_START(map, 32, lpc_acpi_device) + AM_RANGE(0x00, 0x03) AM_READWRITE16(pm1_sts_r, pm1_sts_w, 0x0000ffff) + AM_RANGE(0x00, 0x03) AM_READWRITE16(pm1_en_r, pm1_en_w, 0xffff0000) + AM_RANGE(0x04, 0x07) AM_READWRITE (pm1_cnt_r, pm1_cnt_w) + AM_RANGE(0x08, 0x0b) AM_READ (pm1_tmr_r) + AM_RANGE(0x10, 0x13) AM_READWRITE (proc_cnt_r, proc_cnt_w) + AM_RANGE(0x14, 0x17) AM_READ8 (lv2_r, 0x000000ff) + AM_RANGE(0x28, 0x2b) AM_READWRITE (gpe0_sts_r, gpe0_sts_w) + AM_RANGE(0x2c, 0x2f) AM_READWRITE (gpe0_en_r, gpe0_en_w) + AM_RANGE(0x30, 0x33) AM_READWRITE (smi_en_r, smi_en_w) + AM_RANGE(0x34, 0x37) AM_READWRITE (smi_sts_r, smi_sts_w) + AM_RANGE(0x38, 0x3b) AM_READWRITE16(alt_gp_smi_en_r, alt_gp_smi_en_w, 0x0000ffff) + AM_RANGE(0x38, 0x3b) AM_READWRITE16(alt_gp_smi_sts_r, alt_gp_smi_sts_w, 0xffff0000) + AM_RANGE(0x44, 0x47) AM_READWRITE16(devact_sts_r, devact_sts_w, 0x0000ffff) + AM_RANGE(0x48, 0x4b) AM_READWRITE16(devtrap_en_r, devtrap_en_w, 0x0000ffff) + AM_RANGE(0x4c, 0x4f) AM_READ16 (bus_addr_track_r, 0x0000ffff) + AM_RANGE(0x4c, 0x4f) AM_READ8 (bus_cyc_track_r, 0x00ff0000) + + AM_RANGE(0x60, 0x63) AM_READWRITE8 (tco_rld_r, tco_rld_w, 0x000000ff) + AM_RANGE(0x60, 0x63) AM_READWRITE8 (tco_tmr_r, tco_tmr_w, 0x0000ff00) + AM_RANGE(0x60, 0x63) AM_READWRITE8 (tco_dat_in_r, tco_dat_in_w, 0x00ff0000) + AM_RANGE(0x60, 0x63) AM_READWRITE8 (tco_dat_out_r, tco_dat_out_w, 0xff000000) + AM_RANGE(0x64, 0x67) AM_READWRITE16(tco1_sts_r, tco1_sts_w, 0x0000ffff) + AM_RANGE(0x64, 0x67) AM_READWRITE16(tco2_sts_r, tco2_sts_w, 0xffff0000) + AM_RANGE(0x68, 0x6b) AM_READWRITE16(tco1_cnt_r, tco1_cnt_w, 0x0000ffff) + AM_RANGE(0x68, 0x6b) AM_READWRITE16(tco2_cnt_r, tco2_cnt_w, 0xffff0000) + AM_RANGE(0x6c, 0x6f) AM_READWRITE8 (tco_message1_r, tco_message1_w, 0x000000ff) + AM_RANGE(0x6c, 0x6f) AM_READWRITE8 (tco_message2_r, tco_message2_w, 0x0000ff00) + AM_RANGE(0x6c, 0x6f) AM_READWRITE8 (tco_wdstatus_r, tco_wdstatus_w, 0x00ff0000) + AM_RANGE(0x70, 0x73) AM_READWRITE8 (sw_irq_gen_r, sw_irq_gen_w, 0x000000ff) +ADDRESS_MAP_END + +lpc_acpi_device::lpc_acpi_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : lpc_device(mconfig, LPC_ACPI, "LPC ACPI", tag, owner, clock, "lpc_acpi", __FILE__) +{ +} + +void lpc_acpi_device::map_device(UINT64 memory_window_start, UINT64 memory_window_end, UINT64 memory_offset, address_space *memory_space, + UINT64 io_window_start, UINT64 io_window_end, UINT64 io_offset, address_space *io_space) +{ + io_space->install_device(io_offset, io_window_end, *this, &lpc_acpi_device::map); +} + +void lpc_acpi_device::device_start() +{ +} + +void lpc_acpi_device::device_reset() +{ + pm1_sts = 0; + pm1_en = 0; + pm1_cnt = 0; + proc_cnt = 0; + gpe0_sts = 0; + gpe0_en = 0; + smi_en = 0; + smi_sts = 0; + alt_gp_smi_en = 0; + alt_gp_smi_sts = 0; + devact_sts = 0; + devtrap_en = 0; + + tco_rld = 0; + tco_tmr = 0; + tco_dat_in = 0; + tco_dat_out = 0; + tco1_sts = 0; + tco2_sts = 0; + tco1_cnt = 0; + tco2_cnt = 0; + tco_message1 = 0; + tco_message2 = 0; + tco_wdstatus = 0; + sw_irq_gen = 0; +} + +READ16_MEMBER( lpc_acpi_device::pm1_sts_r) +{ + return pm1_sts; +} + +WRITE16_MEMBER(lpc_acpi_device::pm1_sts_w) +{ + pm1_sts &= ~data; + logerror("%s: pm1_sts = %04x\n", tag(), pm1_sts); +} + +READ16_MEMBER( lpc_acpi_device::pm1_en_r) +{ + return pm1_en; +} + +WRITE16_MEMBER(lpc_acpi_device::pm1_en_w) +{ + COMBINE_DATA(&pm1_en); + logerror("%s: pm1_en = %04x\n", tag(), pm1_en); +} + +READ32_MEMBER( lpc_acpi_device::pm1_cnt_r) +{ + return pm1_cnt; +} + +WRITE32_MEMBER(lpc_acpi_device::pm1_cnt_w) +{ + COMBINE_DATA(&pm1_cnt); + logerror("%s: pm1_cnt = %08x\n", tag(), pm1_cnt); +} + +READ32_MEMBER(lpc_acpi_device::pm1_tmr_r) +{ + return machine().time().as_ticks(3579545) & 0xffffff; +} + +READ32_MEMBER( lpc_acpi_device::proc_cnt_r) +{ + return proc_cnt; +} + +WRITE32_MEMBER(lpc_acpi_device::proc_cnt_w) +{ + COMBINE_DATA(&proc_cnt); + logerror("%s: proc_cnt = %08x\n", tag(), proc_cnt); +} + +READ8_MEMBER( lpc_acpi_device::lv2_r) +{ + return 0x00; +} + +READ32_MEMBER( lpc_acpi_device::gpe0_sts_r) +{ + return gpe0_sts; +} + +WRITE32_MEMBER(lpc_acpi_device::gpe0_sts_w) +{ + COMBINE_DATA(&gpe0_sts); + logerror("%s: gpe0_sts = %08x\n", tag(), gpe0_sts); +} + +READ32_MEMBER( lpc_acpi_device::gpe0_en_r) +{ + return gpe0_en; +} + +WRITE32_MEMBER(lpc_acpi_device::gpe0_en_w) +{ + COMBINE_DATA(&gpe0_en); + logerror("%s: gpe0_en = %08x\n", tag(), gpe0_en); +} + +READ32_MEMBER( lpc_acpi_device::smi_en_r) +{ + return smi_en; +} + +WRITE32_MEMBER(lpc_acpi_device::smi_en_w) +{ + COMBINE_DATA(&smi_en); + logerror("%s: smi_en = %08x\n", tag(), smi_en); +} + +READ32_MEMBER( lpc_acpi_device::smi_sts_r) +{ + return smi_sts; +} + +WRITE32_MEMBER(lpc_acpi_device::smi_sts_w) +{ + COMBINE_DATA(&smi_sts); + logerror("%s: smi_sts = %08x\n", tag(), smi_sts); +} + +READ16_MEMBER( lpc_acpi_device::alt_gp_smi_en_r) +{ + return alt_gp_smi_en; +} + +WRITE16_MEMBER(lpc_acpi_device::alt_gp_smi_en_w) +{ + COMBINE_DATA(&alt_gp_smi_en); + logerror("%s: alt_gp_smi_en = %04x\n", tag(), alt_gp_smi_en); +} + +READ16_MEMBER( lpc_acpi_device::alt_gp_smi_sts_r) +{ + return alt_gp_smi_sts; +} + +WRITE16_MEMBER(lpc_acpi_device::alt_gp_smi_sts_w) +{ + COMBINE_DATA(&alt_gp_smi_sts); + logerror("%s: alt_gp_smi_sts = %04x\n", tag(), alt_gp_smi_sts); +} + +READ16_MEMBER( lpc_acpi_device::devact_sts_r) +{ + return devact_sts; +} + +WRITE16_MEMBER(lpc_acpi_device::devact_sts_w) +{ + COMBINE_DATA(&devact_sts); + logerror("%s: devact_sts = %04x\n", tag(), devact_sts); +} + +READ16_MEMBER( lpc_acpi_device::devtrap_en_r) +{ + return devtrap_en; +} + +WRITE16_MEMBER(lpc_acpi_device::devtrap_en_w) +{ + COMBINE_DATA(&devtrap_en); + logerror("%s: devtrap_en = %04x\n", tag(), devtrap_en); +} + +READ16_MEMBER( lpc_acpi_device::bus_addr_track_r) +{ + logerror("%s: read bus_addr_track\n", tag()); + return 0; +} + +READ8_MEMBER( lpc_acpi_device::bus_cyc_track_r) +{ + logerror("%s: read bus_cyc_track\n", tag()); + return 0; +} + + +READ8_MEMBER( lpc_acpi_device::tco_rld_r) +{ + return tco_rld; +} + +WRITE8_MEMBER( lpc_acpi_device::tco_rld_w) +{ + tco_rld = data; + logerror("%s: tco_rld = %02x\n", tag(), tco_rld); +} + +READ8_MEMBER( lpc_acpi_device::tco_tmr_r) +{ + return tco_tmr; +} + +WRITE8_MEMBER( lpc_acpi_device::tco_tmr_w) +{ + tco_tmr = data; + logerror("%s: tco_tmr = %02x\n", tag(), tco_tmr); +} + +READ8_MEMBER( lpc_acpi_device::tco_dat_in_r) +{ + return tco_dat_in; +} + +WRITE8_MEMBER( lpc_acpi_device::tco_dat_in_w) +{ + tco_dat_in = data; + logerror("%s: tco_dat_in = %02x\n", tag(), tco_dat_in); +} + +READ8_MEMBER( lpc_acpi_device::tco_dat_out_r) +{ + return tco_dat_out; +} + +WRITE8_MEMBER( lpc_acpi_device::tco_dat_out_w) +{ + tco_dat_out = data; + logerror("%s: tco_dat_out = %02x\n", tag(), tco_dat_out); +} + +READ16_MEMBER( lpc_acpi_device::tco1_sts_r) +{ + return tco1_sts; +} + +WRITE16_MEMBER(lpc_acpi_device::tco1_sts_w) +{ + COMBINE_DATA(&tco1_sts); + logerror("%s: tco1_sts = %04x\n", tag(), tco1_sts); +} + +READ16_MEMBER( lpc_acpi_device::tco2_sts_r) +{ + return tco2_sts; +} + +WRITE16_MEMBER(lpc_acpi_device::tco2_sts_w) +{ + COMBINE_DATA(&tco2_sts); + logerror("%s: tco2_sts = %04x\n", tag(), tco2_sts); +} + +READ16_MEMBER( lpc_acpi_device::tco1_cnt_r) +{ + return tco1_cnt; +} + +WRITE16_MEMBER(lpc_acpi_device::tco1_cnt_w) +{ + COMBINE_DATA(&tco1_cnt); + logerror("%s: tco1_cnt = %04x\n", tag(), tco1_cnt); +} + +READ16_MEMBER( lpc_acpi_device::tco2_cnt_r) +{ + return tco2_cnt; +} + +WRITE16_MEMBER(lpc_acpi_device::tco2_cnt_w) +{ + COMBINE_DATA(&tco2_cnt); + logerror("%s: tco2_cnt = %04x\n", tag(), tco2_cnt); +} + +READ8_MEMBER( lpc_acpi_device::tco_message1_r) +{ + return tco_message1; +} + +WRITE8_MEMBER( lpc_acpi_device::tco_message1_w) +{ + tco_message1 = data; + logerror("%s: tco_message1 = %02x\n", tag(), tco_message1); +} + +READ8_MEMBER( lpc_acpi_device::tco_message2_r) +{ + return tco_message2; +} + +WRITE8_MEMBER( lpc_acpi_device::tco_message2_w) +{ + tco_message2 = data; + logerror("%s: tco_message2 = %02x\n", tag(), tco_message2); +} + +READ8_MEMBER( lpc_acpi_device::tco_wdstatus_r) +{ + return tco_wdstatus; +} + +WRITE8_MEMBER( lpc_acpi_device::tco_wdstatus_w) +{ + tco_wdstatus = data; + logerror("%s: tco_wdstatus = %02x\n", tag(), tco_wdstatus); +} + +READ8_MEMBER( lpc_acpi_device::sw_irq_gen_r) +{ + return sw_irq_gen; +} + +WRITE8_MEMBER( lpc_acpi_device::sw_irq_gen_w) +{ + sw_irq_gen = data; + logerror("%s: sw_irq_gen = %02x\n", tag(), sw_irq_gen); +} diff --git a/src/devices/machine/lpc-acpi.h b/src/devices/machine/lpc-acpi.h new file mode 100644 index 00000000000..2abf019d408 --- /dev/null +++ b/src/devices/machine/lpc-acpi.h @@ -0,0 +1,88 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +#ifndef LPC_ACPI_H +#define LPC_ACPI_H + +#include "lpc.h" + +#define MCFG_LPC_ACPI_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, LPC_ACPI, 0) + +class lpc_acpi_device : public lpc_device { +public: + lpc_acpi_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual void map_device(UINT64 memory_window_start, UINT64 memory_window_end, UINT64 memory_offset, address_space *memory_space, + UINT64 io_window_start, UINT64 io_window_end, UINT64 io_offset, address_space *io_space); + + DECLARE_READ16_MEMBER( pm1_sts_r); + DECLARE_WRITE16_MEMBER(pm1_sts_w); + DECLARE_READ16_MEMBER( pm1_en_r); + DECLARE_WRITE16_MEMBER(pm1_en_w); + DECLARE_READ32_MEMBER( pm1_cnt_r); + DECLARE_WRITE32_MEMBER(pm1_cnt_w); + DECLARE_READ32_MEMBER( pm1_tmr_r); + DECLARE_READ32_MEMBER( proc_cnt_r); + DECLARE_WRITE32_MEMBER(proc_cnt_w); + DECLARE_READ8_MEMBER( lv2_r); + DECLARE_READ32_MEMBER( gpe0_sts_r); + DECLARE_WRITE32_MEMBER(gpe0_sts_w); + DECLARE_READ32_MEMBER( gpe0_en_r); + DECLARE_WRITE32_MEMBER(gpe0_en_w); + DECLARE_READ32_MEMBER( smi_en_r); + DECLARE_WRITE32_MEMBER(smi_en_w); + DECLARE_READ32_MEMBER( smi_sts_r); + DECLARE_WRITE32_MEMBER(smi_sts_w); + DECLARE_READ16_MEMBER( alt_gp_smi_en_r); + DECLARE_WRITE16_MEMBER(alt_gp_smi_en_w); + DECLARE_READ16_MEMBER( alt_gp_smi_sts_r); + DECLARE_WRITE16_MEMBER(alt_gp_smi_sts_w); + DECLARE_READ16_MEMBER( devact_sts_r); + DECLARE_WRITE16_MEMBER(devact_sts_w); + DECLARE_READ16_MEMBER( devtrap_en_r); + DECLARE_WRITE16_MEMBER(devtrap_en_w); + DECLARE_READ16_MEMBER( bus_addr_track_r); + DECLARE_READ8_MEMBER( bus_cyc_track_r); + + DECLARE_READ8_MEMBER( tco_rld_r); + DECLARE_WRITE8_MEMBER( tco_rld_w); + DECLARE_READ8_MEMBER( tco_tmr_r); + DECLARE_WRITE8_MEMBER( tco_tmr_w); + DECLARE_READ8_MEMBER( tco_dat_in_r); + DECLARE_WRITE8_MEMBER( tco_dat_in_w); + DECLARE_READ8_MEMBER( tco_dat_out_r); + DECLARE_WRITE8_MEMBER( tco_dat_out_w); + DECLARE_READ16_MEMBER( tco1_sts_r); + DECLARE_WRITE16_MEMBER(tco1_sts_w); + DECLARE_READ16_MEMBER( tco2_sts_r); + DECLARE_WRITE16_MEMBER(tco2_sts_w); + DECLARE_READ16_MEMBER( tco1_cnt_r); + DECLARE_WRITE16_MEMBER(tco1_cnt_w); + DECLARE_READ16_MEMBER( tco2_cnt_r); + DECLARE_WRITE16_MEMBER(tco2_cnt_w); + DECLARE_READ8_MEMBER( tco_message1_r); + DECLARE_WRITE8_MEMBER( tco_message1_w); + DECLARE_READ8_MEMBER( tco_message2_r); + DECLARE_WRITE8_MEMBER( tco_message2_w); + DECLARE_READ8_MEMBER( tco_wdstatus_r); + DECLARE_WRITE8_MEMBER( tco_wdstatus_w); + DECLARE_READ8_MEMBER( sw_irq_gen_r); + DECLARE_WRITE8_MEMBER( sw_irq_gen_w); + +protected: + void device_start(); + void device_reset(); + +private: + UINT32 pm1_cnt, proc_cnt, gpe0_sts, gpe0_en, smi_en, smi_sts; + UINT16 pm1_sts, pm1_en, alt_gp_smi_en, alt_gp_smi_sts, devact_sts, devtrap_en; + UINT16 tco1_sts, tco2_sts, tco1_cnt, tco2_cnt; + UINT8 tco_rld, tco_tmr, tco_dat_in, tco_dat_out, tco_message1, tco_message2; + UINT8 tco_wdstatus, sw_irq_gen; + + DECLARE_ADDRESS_MAP(map, 32); +}; + +extern const device_type LPC_ACPI; + +#endif diff --git a/src/devices/machine/lpc-pit.c b/src/devices/machine/lpc-pit.c new file mode 100644 index 00000000000..19a07373ec5 --- /dev/null +++ b/src/devices/machine/lpc-pit.c @@ -0,0 +1,47 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +#include "lpc-pit.h" + +const device_type LPC_PIT = &device_creator; + +DEVICE_ADDRESS_MAP_START(map, 32, lpc_pit_device) + AM_RANGE(0x40, 0x43) AM_READWRITE8(status_r, access_w, 0x00ffffff) + AM_RANGE(0x40, 0x43) AM_WRITE8 ( control_w, 0xff000000) + AM_RANGE(0x50, 0x53) AM_READWRITE8(status_r, access_w, 0x00ffffff) + AM_RANGE(0x50, 0x53) AM_WRITE8 ( control_w, 0xff000000) +ADDRESS_MAP_END + +lpc_pit_device::lpc_pit_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : lpc_device(mconfig, LPC_PIT, "LPC PIT", tag, owner, clock, "lpc_pit", __FILE__) +{ +} + +void lpc_pit_device::map_device(UINT64 memory_window_start, UINT64 memory_window_end, UINT64 memory_offset, address_space *memory_space, + UINT64 io_window_start, UINT64 io_window_end, UINT64 io_offset, address_space *io_space) +{ + io_space->install_device(io_offset, io_window_end, *this, &lpc_pit_device::map); +} + +void lpc_pit_device::device_start() +{ +} + +void lpc_pit_device::device_reset() +{ +} + +READ8_MEMBER( lpc_pit_device::status_r) +{ + logerror("%s: status_r %d\n", tag(), offset); + return 0xff; +} + +WRITE8_MEMBER(lpc_pit_device::access_w) +{ + logerror("%s: access_w %d, %02x\n", tag(), offset, data); +} + +WRITE8_MEMBER(lpc_pit_device::control_w) +{ + logerror("%s: control_w %02x\n", tag(), data); +} diff --git a/src/devices/machine/lpc-pit.h b/src/devices/machine/lpc-pit.h new file mode 100644 index 00000000000..4a49a76c10c --- /dev/null +++ b/src/devices/machine/lpc-pit.h @@ -0,0 +1,32 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +#ifndef LPC_PIT_H +#define LPC_PIT_H + +#include "lpc.h" + +#define MCFG_LPC_PIT_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, LPC_PIT, 0) + +class lpc_pit_device : public lpc_device { +public: + lpc_pit_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual void map_device(UINT64 memory_window_start, UINT64 memory_window_end, UINT64 memory_offset, address_space *memory_space, + UINT64 io_window_start, UINT64 io_window_end, UINT64 io_offset, address_space *io_space); + + DECLARE_READ8_MEMBER( status_r); + DECLARE_WRITE8_MEMBER(access_w); + DECLARE_WRITE8_MEMBER(control_w); + +protected: + void device_start(); + void device_reset(); + +private: + DECLARE_ADDRESS_MAP(map, 32); +}; + +extern const device_type LPC_PIT; + +#endif diff --git a/src/devices/machine/lpc-rtc.c b/src/devices/machine/lpc-rtc.c new file mode 100644 index 00000000000..d92d7b515d0 --- /dev/null +++ b/src/devices/machine/lpc-rtc.c @@ -0,0 +1,83 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +#include "lpc-rtc.h" + +const device_type LPC_RTC = &device_creator; + +DEVICE_ADDRESS_MAP_START(map, 32, lpc_rtc_device) + AM_RANGE(0x70, 0x77) AM_READWRITE8(index_r, index_w, 0x00ff00ff) + AM_RANGE(0x70, 0x77) AM_READWRITE8(target_r, target_w, 0xff00ff00) +ADDRESS_MAP_END + +DEVICE_ADDRESS_MAP_START(extmap, 32, lpc_rtc_device) + AM_RANGE(0x70, 0x77) AM_READWRITE8(extindex_r, extindex_w, 0x00ff0000) + AM_RANGE(0x70, 0x77) AM_READWRITE8(exttarget_r, exttarget_w, 0xff000000) +ADDRESS_MAP_END + +lpc_rtc_device::lpc_rtc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : lpc_device(mconfig, LPC_RTC, "LPC RTC", tag, owner, clock, "lpc_rtc", __FILE__) +{ +} + +void lpc_rtc_device::map_device(UINT64 memory_window_start, UINT64 memory_window_end, UINT64 memory_offset, address_space *memory_space, + UINT64 io_window_start, UINT64 io_window_end, UINT64 io_offset, address_space *io_space) +{ + io_space->install_device(io_offset, io_window_end, *this, &lpc_rtc_device::map); +} + +void lpc_rtc_device::map_extdevice(UINT64 memory_window_start, UINT64 memory_window_end, UINT64 memory_offset, address_space *memory_space, + UINT64 io_window_start, UINT64 io_window_end, UINT64 io_offset, address_space *io_space) +{ + io_space->install_device(io_offset, io_window_end, *this, &lpc_rtc_device::extmap); +} + +void lpc_rtc_device::device_start() +{ + memset(ram, 0, 256); +} + +void lpc_rtc_device::device_reset() +{ +} + +READ8_MEMBER( lpc_rtc_device::index_r) +{ + return cur_index; +} + +WRITE8_MEMBER( lpc_rtc_device::index_w) +{ + cur_index = data & 0x7f; +} + +READ8_MEMBER( lpc_rtc_device::target_r) +{ + return ram[cur_index]; +} + +WRITE8_MEMBER( lpc_rtc_device::target_w) +{ + ram[cur_index] = data; + logerror("%s: ram[%02x] = %02x\n", tag(), cur_index, data); +} + +READ8_MEMBER( lpc_rtc_device::extindex_r) +{ + return cur_extindex; +} + +WRITE8_MEMBER( lpc_rtc_device::extindex_w) +{ + cur_extindex = data & 0x7f; +} + +READ8_MEMBER( lpc_rtc_device::exttarget_r) +{ + return ram[cur_extindex|128]; +} + +WRITE8_MEMBER( lpc_rtc_device::exttarget_w) +{ + ram[cur_extindex|128] = data; + logerror("%s: ram[%02x] = %02x\n", tag(), cur_extindex|128, data); +} diff --git a/src/devices/machine/lpc-rtc.h b/src/devices/machine/lpc-rtc.h new file mode 100644 index 00000000000..f85c6c5cd11 --- /dev/null +++ b/src/devices/machine/lpc-rtc.h @@ -0,0 +1,44 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +#ifndef LPC_RTC_H +#define LPC_RTC_H + +#include "lpc.h" + +#define MCFG_LPC_RTC_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, LPC_RTC, 0) + +class lpc_rtc_device : public lpc_device { +public: + lpc_rtc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual void map_device(UINT64 memory_window_start, UINT64 memory_window_end, UINT64 memory_offset, address_space *memory_space, + UINT64 io_window_start, UINT64 io_window_end, UINT64 io_offset, address_space *io_space); + + virtual void map_extdevice(UINT64 memory_window_start, UINT64 memory_window_end, UINT64 memory_offset, address_space *memory_space, + UINT64 io_window_start, UINT64 io_window_end, UINT64 io_offset, address_space *io_space); + + DECLARE_READ8_MEMBER( index_r); + DECLARE_WRITE8_MEMBER( index_w); + DECLARE_READ8_MEMBER( target_r); + DECLARE_WRITE8_MEMBER( target_w); + DECLARE_READ8_MEMBER( extindex_r); + DECLARE_WRITE8_MEMBER( extindex_w); + DECLARE_READ8_MEMBER( exttarget_r); + DECLARE_WRITE8_MEMBER( exttarget_w); + +protected: + void device_start(); + void device_reset(); + +private: + DECLARE_ADDRESS_MAP(map, 32); + DECLARE_ADDRESS_MAP(extmap, 32); + + UINT8 cur_index, cur_extindex; + UINT8 ram[256]; +}; + +extern const device_type LPC_RTC; + +#endif diff --git a/src/devices/machine/lpc.c b/src/devices/machine/lpc.c new file mode 100644 index 00000000000..afb51435f23 --- /dev/null +++ b/src/devices/machine/lpc.c @@ -0,0 +1,8 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +#include "lpc.h" + +lpc_device::lpc_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source) +{ +} diff --git a/src/devices/machine/lpc.h b/src/devices/machine/lpc.h new file mode 100644 index 00000000000..6ade06d03ff --- /dev/null +++ b/src/devices/machine/lpc.h @@ -0,0 +1,16 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +#ifndef LPC_H +#define LPC_H + +#include "emu.h" + +class lpc_device : public device_t { +public: + lpc_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + virtual void map_device(UINT64 memory_window_start, UINT64 memory_window_end, UINT64 memory_offset, address_space *memory_space, + UINT64 io_window_start, UINT64 io_window_end, UINT64 io_offset, address_space *io_space) = 0; +}; + +#endif diff --git a/src/devices/machine/lpci.c b/src/devices/machine/lpci.c new file mode 100644 index 00000000000..913dd915184 --- /dev/null +++ b/src/devices/machine/lpci.c @@ -0,0 +1,291 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +/*************************************************************************** + + machine/lpci.c + + Legacy PCI bus + + The PCI bus is a 32-bit bus introduced by Intel, so it is little endian + + Control word: + bit 31: Enable bit + bits 30-24: Reserved + bits 23-16: PCI bus number + bits 15-11: PCI device number + bits 10- 8: PCI function number + bits 7- 0: Offset address + + Standard PCI registers: + 0x00 2 Vendor ID + 0x02 2 Device ID + 0x04 2 PCI Command + 0x06 2 PCI Status + 0x08 1 Revision ID + 0x09 1 Programming Interface + 0x0A 1 Subclass Code + 0x0B 1 Class Code + + Class Code/Subclass Code/Programming Interface + 0x00XXXX Pre-PCI 2.0 devices + 0x000000 Non-VGA device + 0x000101 VGA device + 0x01XXXX Storage Controller + 0x010000 SCSI + 0x0101XX IDE + 0x0102XX Floppy + 0x0103XX IPI + 0x0104XX RAID + 0x0180XX Other + 0x02XXXX Network Card + 0x020000 Ethernet + 0x020100 Tokenring + 0x020200 FDDI + 0x020300 ATM + 0x028000 Other + 0x03XXXX Display Controller + 0x030000 VGA + 0x030001 8514 Compatible + 0x030100 XGA + 0x038000 Other + 0x04XXXX Multimedia + 0x040000 Video + 0x040100 Audio + 0x048000 Other + 0x05XXXX Memory Controller + 0x050000 RAM + 0x050100 Flash + 0x058000 Other + 0x06XXXX Bridge + 0x060000 Host/PCI + 0x060100 PCI/ISA + 0x060200 PCI/EISA + 0x060300 PCI/Micro Channel + 0x060400 PCI/PCI + 0x060500 PCI/PCMCIA + 0x060600 PCI/NuBus + 0x060700 PCI/CardBus + 0x068000 Other + + Information on PCI vendors can be found at http://www.pcidatabase.com/ + +***************************************************************************/ + +#include "emu.h" +#include "machine/lpci.h" + +#define LOG_PCI 0 + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type PCI_BUS_LEGACY = &device_creator; + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// pci_bus_legacy_device - constructor +//------------------------------------------------- +pci_bus_legacy_device::pci_bus_legacy_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, PCI_BUS_LEGACY, "PCI Bus Legacy", tag, owner, clock, "pci_bus_legacy", __FILE__), + m_father(NULL) +{ + for (int i = 0; i < ARRAY_LENGTH(m_devtag); i++) { + m_devtag[i]= NULL; + m_read_callback[i] = NULL; + m_write_callback[i] = NULL; + } + m_siblings_count = 0; +} + +/*************************************************************************** + INLINE FUNCTIONS +***************************************************************************/ + +READ32_MEMBER( pci_bus_legacy_device::read ) +{ + UINT32 result = 0xffffffff; + int function, reg; + + offset %= 2; + + switch (offset) + { + case 0: + result = m_address; + break; + + case 1: + if (m_devicenum != -1) + { + pci_read_func read = m_busnumaddr->m_read_callback[m_devicenum]; + if (read != NULL) + { + function = (m_address >> 8) & 0x07; + reg = (m_address >> 0) & 0xfc; + result = (*read)(m_busnumaddr, m_busnumaddr->m_device[m_devicenum], function, reg, mem_mask); + } + } + break; + } + + if (LOG_PCI) + logerror("read('%s'): offset=%d result=0x%08X\n", tag(), offset, result); + + return result; +} + + + +pci_bus_legacy_device *pci_bus_legacy_device::pci_search_bustree(int busnum, int devicenum, pci_bus_legacy_device *pcibus) +{ + int a; + pci_bus_legacy_device *ret; + + if (pcibus->m_busnum == busnum) + { + return pcibus; + } + for (a = 0; a < pcibus->m_siblings_count; a++) + { + ret = pci_search_bustree(busnum, devicenum, pcibus->m_siblings[a]); + if (ret != NULL) + return ret; + } + return NULL; +} + + + +WRITE32_MEMBER( pci_bus_legacy_device::write ) +{ + offset %= 2; + + if (LOG_PCI) + logerror("write('%s'): offset=%d data=0x%08X\n", tag(), offset, data); + + switch (offset) + { + case 0: + m_address = data; + + /* lookup current device */ + if (m_address & 0x80000000) + { + int busnum = (m_address >> 16) & 0xff; + int devicenum = (m_address >> 11) & 0x1f; + m_busnumaddr = pci_search_bustree(busnum, devicenum, this); + if (m_busnumaddr != NULL) + { + m_busnumber = busnum; + m_devicenum = devicenum; + } + else + m_devicenum = -1; + if (LOG_PCI) + logerror(" bus:%d device:%d\n", busnum, devicenum); + } + break; + + case 1: + if (m_devicenum != -1) + { + pci_write_func write = m_busnumaddr->m_write_callback[m_devicenum]; + if (write != NULL) + { + int function = (m_address >> 8) & 0x07; + int reg = (m_address >> 0) & 0xfc; + (*write)(m_busnumaddr, m_busnumaddr->m_device[m_devicenum], function, reg, data, mem_mask); + } + if (LOG_PCI) + logerror(" function:%d register:%d\n", (m_address >> 8) & 0x07, (m_address >> 0) & 0xfc); + } + break; + } +} + + + +READ64_MEMBER(pci_bus_legacy_device::read_64be) +{ + UINT64 result = 0; + mem_mask = FLIPENDIAN_INT64(mem_mask); + if (ACCESSING_BITS_0_31) + result |= (UINT64)read(space, offset * 2 + 0, mem_mask >> 0) << 0; + if (ACCESSING_BITS_32_63) + result |= (UINT64)read(space, offset * 2 + 1, mem_mask >> 32) << 32; + return FLIPENDIAN_INT64(result); +} + +WRITE64_MEMBER(pci_bus_legacy_device::write_64be) +{ + data = FLIPENDIAN_INT64(data); + mem_mask = FLIPENDIAN_INT64(mem_mask); + if (ACCESSING_BITS_0_31) + write(space, offset * 2 + 0, data >> 0, mem_mask >> 0); + if (ACCESSING_BITS_32_63) + write(space, offset * 2 + 1, data >> 32, mem_mask >> 32); +} + + +void pci_bus_legacy_device::add_sibling(pci_bus_legacy_device *sibling, int busnum) +{ + m_siblings[m_siblings_count] = sibling; + m_siblings_busnum[m_siblings_count] = busnum; + m_siblings_count++; +} + + +//------------------------------------------------- +// device_post_load - handle updating after a +// restore +//------------------------------------------------- + +void pci_bus_legacy_device::device_post_load() +{ + if (m_devicenum != -1) + { + m_busnumaddr = pci_search_bustree(m_busnumber, m_devicenum, this); + } +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void pci_bus_legacy_device::device_start() +{ + /* store a pointer back to the device */ + m_devicenum = -1; + + /* find all our devices */ + for (int i = 0; i < ARRAY_LENGTH(m_devtag); i++) + if (m_devtag[i] != NULL) + m_device[i] = machine().device(m_devtag[i]); + + if (m_father != NULL) { + pci_bus_legacy_device *father = machine().device(m_father); + if (father) + father->add_sibling(this, m_busnum); + } + + /* register pci states */ + save_item(NAME(m_address)); + save_item(NAME(m_devicenum)); + save_item(NAME(m_busnum)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void pci_bus_legacy_device::device_reset() +{ + /* reset the drive state */ + m_devicenum = -1; + m_address = 0; +} diff --git a/src/devices/machine/lpci.h b/src/devices/machine/lpci.h new file mode 100644 index 00000000000..8d420d28a07 --- /dev/null +++ b/src/devices/machine/lpci.h @@ -0,0 +1,83 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +/*************************************************************************** + + machine/lpci.h + + Legacy PCI bus + +***************************************************************************/ + +#ifndef LPCI_H +#define LPCI_H + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +typedef UINT32 (*pci_read_func)(device_t *pcibus, device_t *device, int function, int reg, UINT32 mem_mask); +typedef void (*pci_write_func)(device_t *pcibus, device_t *device, int function, int reg, UINT32 data, UINT32 mem_mask); + +// ======================> pci_bus_legacy_device + +class pci_bus_legacy_device : public device_t +{ +public: + // construction/destruction + pci_bus_legacy_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + DECLARE_READ32_MEMBER( read ); + DECLARE_WRITE32_MEMBER( write ); + + DECLARE_READ64_MEMBER( read_64be ); + DECLARE_WRITE64_MEMBER( write_64be ); + + void set_busnum(int busnum) { m_busnum = busnum; } + void set_father(const char *father) { m_father = father; } + void set_device(int num, const char *tag, pci_read_func read_func, pci_write_func write_func) { + m_devtag[num] = tag; m_read_callback[num] = read_func; m_write_callback[num] = write_func; } + + pci_bus_legacy_device *pci_search_bustree(int busnum, int devicenum, pci_bus_legacy_device *pcibus); + void add_sibling(pci_bus_legacy_device *sibling, int busnum); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_post_load(); + +private: + UINT8 m_busnum; + const char * m_devtag[32]; + pci_read_func m_read_callback[32]; + pci_write_func m_write_callback[32]; + const char * m_father; + device_t * m_device[32]; + pci_bus_legacy_device * m_siblings[8]; + UINT8 m_siblings_busnum[8]; + int m_siblings_count; + + offs_t m_address; + INT8 m_devicenum; // device number we are addressing + INT8 m_busnumber; // pci bus number we are addressing + pci_bus_legacy_device * m_busnumaddr; // pci bus we are addressing +}; + +// device type definition +extern const device_type PCI_BUS_LEGACY; + + +/*************************************************************************** + DEVICE CONFIGURATION MACROS +***************************************************************************/ + +#define MCFG_PCI_BUS_LEGACY_ADD(_tag, _busnum) \ + MCFG_DEVICE_ADD(_tag, PCI_BUS_LEGACY, 0) \ + downcast(device)->set_busnum(_busnum); +#define MCFG_PCI_BUS_LEGACY_DEVICE(_devnum, _devtag, _configread, _configwrite) \ + downcast(device)->set_device(_devnum, _devtag,_configread,_configwrite); +#define MCFG_PCI_BUS_LEGACY_SIBLING(_father_tag) \ + downcast(device)->set_father(_father_tag); + + +#endif /* PCI_H */ diff --git a/src/devices/machine/m6m80011ap.c b/src/devices/machine/m6m80011ap.c new file mode 100644 index 00000000000..776cbcae6e7 --- /dev/null +++ b/src/devices/machine/m6m80011ap.c @@ -0,0 +1,232 @@ +// license:BSD-3-Clause +// copyright-holders:Angelo Salese +/*************************************************************************** + +Template for skeleton device + +***************************************************************************/ + +#include "emu.h" +#include "machine/m6m80011ap.h" + + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +// device type definition +const device_type M6M80011AP = &device_creator; + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// m6m80011ap_device - constructor +//------------------------------------------------- + +m6m80011ap_device::m6m80011ap_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, M6M80011AP, "M6M80011AP EEPROM", tag, owner, clock, "m6m80011ap", __FILE__), + device_nvram_interface(mconfig, *this) +{ +} + + +//------------------------------------------------- +// device_validity_check - perform validity checks +// on this device +//------------------------------------------------- + +void m6m80011ap_device::device_validity_check(validity_checker &valid) const +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void m6m80011ap_device::device_start() +{ +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void m6m80011ap_device::device_reset() +{ +} + +//------------------------------------------------- +// nvram_default - called to initialize NVRAM to +// its default state +//------------------------------------------------- + +void m6m80011ap_device::nvram_default() +{ + for (offs_t offs = 0; offs < 0x80; offs++) + m_eeprom_data[offs] = 0xffff; +} + + + + +//------------------------------------------------- +// nvram_read - called to read NVRAM from the +// .nv file +//------------------------------------------------- + +void m6m80011ap_device::nvram_read(emu_file &file) +{ + file.read(m_eeprom_data, 0x100); +} + + +//------------------------------------------------- +// nvram_write - called to write NVRAM to the +// .nv file +//------------------------------------------------- + +void m6m80011ap_device::nvram_write(emu_file &file) +{ + file.write(m_eeprom_data, 0x100); +} + +//************************************************************************** +// READ/WRITE HANDLERS +//************************************************************************** + + +READ_LINE_MEMBER( m6m80011ap_device::read_bit ) +{ + return m_read_latch; +} + +READ_LINE_MEMBER( m6m80011ap_device::ready_line ) +{ + return 1; // TODO +} + +WRITE_LINE_MEMBER( m6m80011ap_device::set_cs_line ) +{ + m_reset_line = state; + + if (m_reset_line != CLEAR_LINE) + { + m_eeprom_state = EEPROM_GET_CMD; + m_cmd_stream_pos = 0; + m_current_cmd = 0; + } +} + + +WRITE_LINE_MEMBER( m6m80011ap_device::write_bit ) +{ + m_latch = state; +} + +WRITE_LINE_MEMBER( m6m80011ap_device::set_clock_line ) +{ + if (m_reset_line == CLEAR_LINE) + { + if(state == 1) + { + switch(m_eeprom_state) + { + case EEPROM_GET_CMD: + m_current_cmd = (m_current_cmd >> 1) | ((m_latch & 1)<< 7); + m_cmd_stream_pos++; + + if (m_cmd_stream_pos==8) + { + m_cmd_stream_pos = 0; + switch(m_current_cmd) + { + case 0xc5: m_eeprom_state = EEPROM_WRITE_ENABLE; break; + case 0x05: m_eeprom_state = EEPROM_WRITE_DISABLE; break; + case 0x25: m_eeprom_state = EEPROM_WRITE; break; + case 0x15: m_eeprom_state = EEPROM_READ; break; + case 0x95: m_eeprom_state = EEPROM_STATUS_OUTPUT; break; + default: + printf("Write M6M80011 unknown %02x cmd\n",m_current_cmd ); + break; + } + } + break; + + case EEPROM_READ: + m_current_cmd = (m_current_cmd >> 1) | ((m_latch & 1)<< 23); + m_cmd_stream_pos++; + + if (m_cmd_stream_pos==8) + { + m_current_addr = m_current_cmd >> 16; + } + + if(m_cmd_stream_pos>=8) + { + m_read_latch = (m_eeprom_data[m_current_addr] >> (23-m_cmd_stream_pos)) & 1; + //printf("%d %04x <- %04x %d\n",m_read_latch,m_eeprom_data[m_current_addr],m_current_addr,m_cmd_stream_pos-8); + } + + if(m_cmd_stream_pos==24) + { + m_eeprom_state = EEPROM_GET_CMD; + m_cmd_stream_pos = 0; + } + break; + + case EEPROM_WRITE: + m_current_cmd = (m_current_cmd >> 1) | ((m_latch & 1)<< 23); + m_cmd_stream_pos++; + + if (m_cmd_stream_pos==8) + { + m_current_addr = m_current_cmd >> 16; + } + + if(m_cmd_stream_pos==24) + { + if(m_eeprom_we) + m_eeprom_data[m_current_addr] = (m_current_cmd >> 8) & 0xffff; + + //printf("%04x %04x -> %04x\n",m_eeprom_data[m_current_addr],m_current_addr,m_current_cmd >> 8); + + m_eeprom_state = EEPROM_GET_CMD; + m_cmd_stream_pos = 0; + } + break; + + case EEPROM_WRITE_ENABLE: + case EEPROM_WRITE_DISABLE: + m_current_cmd = (m_current_cmd >> 1) | ((m_latch & 1)<< 7); + m_cmd_stream_pos++; + + if (m_cmd_stream_pos==8) + { + m_eeprom_we = (m_eeprom_state == EEPROM_WRITE_ENABLE) ? 1 : 0; + m_eeprom_state = EEPROM_GET_CMD; + m_cmd_stream_pos = 0; + } + + break; + + case EEPROM_STATUS_OUTPUT: + m_current_cmd = (m_current_cmd >> 1) | ((m_latch & 1)<< 7); + m_cmd_stream_pos++; + + if (m_cmd_stream_pos==8) + { + printf("Status output\n"); + m_eeprom_state = EEPROM_GET_CMD; + m_cmd_stream_pos = 0; + } + break; + } + } + } +} diff --git a/src/devices/machine/m6m80011ap.h b/src/devices/machine/m6m80011ap.h new file mode 100644 index 00000000000..196617f2339 --- /dev/null +++ b/src/devices/machine/m6m80011ap.h @@ -0,0 +1,91 @@ +// license:BSD-3-Clause +// copyright-holders:Angelo Salese +/*************************************************************************** + +Template for skeleton device + +***************************************************************************/ + +#pragma once + +#ifndef __M6M80011APDEV_H__ +#define __M6M80011APDEV_H__ + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +/* TODO: frequency */ +#define MCFG_M6M80011AP_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, M6M80011AP, XTAL_32_768kHz) + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +enum eeprom_cmd_t +{ + EEPROM_GET_CMD = 0, + EEPROM_READ, + EEPROM_WRITE, + EEPROM_WRITE_ENABLE, + EEPROM_WRITE_DISABLE, + EEPROM_STATUS_OUTPUT +}; + + +// ======================> m6m80011ap_device + +class m6m80011ap_device : public device_t, + public device_nvram_interface +{ +public: + // construction/destruction + m6m80011ap_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // I/O operations + DECLARE_READ_LINE_MEMBER( read_bit ); + DECLARE_READ_LINE_MEMBER( ready_line ); + DECLARE_WRITE_LINE_MEMBER( set_cs_line ); + DECLARE_WRITE_LINE_MEMBER( set_clock_line ); + DECLARE_WRITE_LINE_MEMBER( write_bit ); + +protected: + // device-level overrides + virtual void device_validity_check(validity_checker &valid) const; + virtual void device_start(); + virtual void device_reset(); + + virtual void nvram_default(); + virtual void nvram_read(emu_file &file); + virtual void nvram_write(emu_file &file); + +private: + UINT8 m_latch; + UINT8 m_reset_line; + UINT8 m_cmd_stream_pos; + UINT32 m_current_cmd; + UINT8 m_read_latch; + UINT8 m_current_addr; + UINT8 m_eeprom_we; + + eeprom_cmd_t m_eeprom_state; + UINT16 m_eeprom_data[0x80]; + +}; + + +// device type definition +extern const device_type M6M80011AP; + + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + + + +#endif diff --git a/src/devices/machine/matsucd.c b/src/devices/machine/matsucd.c new file mode 100644 index 00000000000..6c12c5950d1 --- /dev/null +++ b/src/devices/machine/matsucd.c @@ -0,0 +1,757 @@ +// license:BSD-3-Clause +// copyright-holders:smf, Mariusz Wojcieszek +/*************************************************************************** + + Matsushita/Panasonic CDR521/522 type CDROM drive emulation + +Notes: +This version implements the drive found in Amiga CDTV. There are +different drives supporting this command-set (look in the sbpcd driver +in Linux for examples). Most drives support the exact same command +structure, but the command numbers differ. Eventually this driver +can be expanded with support for the other drives as needed. + +***************************************************************************/ + + +#include "emu.h" +#include "imagedev/chd_cd.h" +#include "sound/cdda.h" +#include "machine/matsucd.h" + + +#define MATSU_STATUS_READY ( 1 << 0 ) /* driver ready */ +#define MATSU_STATUS_DOORLOCKED ( 1 << 1 ) /* door locked */ +#define MATSU_STATUS_PLAYING ( 1 << 2 ) /* drive playing */ +#define MATSU_STATUS_SUCCESS ( 1 << 3 ) /* last command was successful */ +#define MATSU_STATUS_ERROR ( 1 << 4 ) /* last command failed */ +#define MATSU_STATUS_MOTOR ( 1 << 5 ) /* spinning */ +#define MATSU_STATUS_MEDIA ( 1 << 6 ) /* media present (in caddy or tray) */ +#define MATSU_STATUS_DOORCLOSED ( 1 << 7 ) /* tray status */ + +struct matsucd +{ + UINT8 enabled; /* /ENABLE - Unit enabled */ + UINT8 cmd_signal; /* /CMD - Command mode */ + UINT8 stch_signal; /* /STCH - Status Changed */ + UINT8 sten_signal; /* /STEN - Status Enabled */ + UINT8 scor_signal; /* /STEN - Subcode Ready */ + UINT8 input[16]; + UINT8 input_pos; + UINT8 output[16]; + UINT8 output_pos; + UINT8 output_len; + UINT8 status; + UINT8 motor; + UINT16 sector_size; + UINT32 lba; + UINT16 num_blocks; + UINT16 xfer_offset; + UINT8 sector_buffer[CD_MAX_SECTOR_DATA]; + UINT8 cdda_set; + void (*sten_cb)( running_machine &machine, int level ); /* Status enabled callback */ + void (*stch_cb)( running_machine &machine, int level ); /* Status changed callback */ + void (*scor_cb)( running_machine &machine, int level ); /* Subcode ready callback */ + cdrom_file *cdrom; + cdda_device *cdda; + emu_timer *frame_timer; +}; + +static matsucd cd; + +#define MSF2LBA(msf) (((msf >> 16) & 0xff) * 60 * 75 + ((msf >> 8) & 0xff) * 75 + ((msf >> 0) & 0xff)) +#define LBA2MSF(lba) (((lba / (75 * 60)) << 16) | (((lba / 75) % 60) << 8) | (lba % 75)) + +static TIMER_CALLBACK(matsu_subcode_proc); + +void matsucd_init( cdrom_image_device *cdrom_device, const char *cdda_tag ) +{ + memset(&cd, 0, sizeof( matsucd ) ); + + cd.cdrom = cdrom_device->get_cdrom_file(); + cd.cdda = cdrom_device->machine().device(cdda_tag); + + cd.frame_timer = cdrom_device->machine().scheduler().timer_alloc(FUNC(matsu_subcode_proc)); + + cd.stch_signal = 1; +} + +void matsucd_set_status_enabled_callback( void (*sten_cb)( running_machine &machine, int level ) ) +{ + /* add the callback for status enabled signal */ + cd.sten_cb = sten_cb; +} + +void matsucd_set_status_changed_callback( void (*stch_cb)( running_machine &machine, int level ) ) +{ + /* add the callback for status changed signal */ + cd.stch_cb = stch_cb; +} + +void matsucd_set_subcode_ready_callback( void (*scor_cb)( running_machine &machine, int level ) ) +{ + /* add the callback for subcode ready signal */ + cd.scor_cb = scor_cb; +} + +static int matsucd_getsector_type( void ) +{ + switch( cd.sector_size ) + { + case 2048: return CD_TRACK_MODE1; + case 2324: return CD_TRACK_MODE2_FORM2; + case 2336: return CD_TRACK_MODE2; + case 2352: return CD_TRACK_MODE2_RAW; + + default: logerror( "MATSUCD: Sector size %d unsupported!\n", cd.sector_size ); break; + } + + return CD_TRACK_RAW_DONTCARE; +} + +void matsucd_read_next_block( void ) +{ + cd.xfer_offset = 0; + + if ( cd.num_blocks ) + { + cd.lba++; + cd.num_blocks--; + + if (!cdrom_read_data(cd.cdrom, cd.lba, cd.sector_buffer, matsucd_getsector_type())) + { + logerror( "MATSUCD - Warning: Read error on CD!\n" ); + } + } +} + +int matsucd_get_next_byte( UINT8 *data ) +{ + /* no more data to read on this sector */ + if ( cd.xfer_offset >= cd.sector_size ) + return -1; + + if ( data ) + *data = cd.sector_buffer[cd.xfer_offset++]; + + return 0; +} + +static void matsucd_cdda_stop( running_machine &machine ) +{ + if (cd.cdda != NULL) + { + cd.cdda->stop_audio(); + cd.frame_timer->reset( ); + } +} + +static void matsucd_cdda_play( running_machine &machine, UINT32 lba, UINT32 num_blocks ) +{ + if (cd.cdda != NULL) + { + cd.cdda->start_audio(lba, num_blocks); + cd.frame_timer->adjust(attotime::from_hz( 75 )); + } +} + +static void matsucd_cdda_pause( running_machine &machine, int pause ) +{ + if (cd.cdda != NULL) + { + cd.cdda->pause_audio(pause); + + if ( pause ) + { + cd.frame_timer->reset( ); + } + else + { + cd.frame_timer->adjust(attotime::from_hz( 75 )); + } + } +} + +static UINT8 matsucd_cdda_getstatus( running_machine &machine, UINT32 *lba ) +{ + if ( lba ) *lba = 0; + + if (cd.cdda != NULL) + { + if (cd.cdda->audio_active()) + { + if ( lba ) *lba = cd.cdda->get_audio_lba(); + + if (cd.cdda->audio_paused()) + { + return 0x12; /* audio paused */ + } + else + { + return 0x11; /* audio in progress */ + } + } + else if (cd.cdda->audio_ended()) + { + return 0x13; /* audio ended */ + } + } + + return 0x15; /* no audio status */ +} + +void matsucd_enable_w( int level ) +{ + cd.enabled = ( level ) ? 0 : 1; +} + +void matsucd_cmd_w( int level ) +{ + cd.cmd_signal = ( level ) ? 0 : 1; +} + +int matsucd_stch_r( void ) +{ + return cd.stch_signal ? 0 : 1; +} + +int matsucd_sten_r( void ) +{ + return cd.sten_signal ? 0 : 1; +} + +int matsucd_scor_r( void ) +{ + return cd.scor_signal ? 0 : 1; +} + +static void update_status_enable( running_machine &machine, int level ) +{ + cd.sten_signal = level; + + if ( cd.sten_cb ) + { + (*cd.sten_cb)(machine, cd.sten_signal); + } +} + +static void update_status_changed( running_machine &machine, int level ) +{ + cd.stch_signal = level; + + if ( cd.stch_cb ) + { + (*cd.stch_cb)(machine, cd.stch_signal); + } +} + +static void update_subcode_ready( running_machine &machine, int level ) +{ + cd.scor_signal = level; + + if ( cd.scor_cb ) + { + (*cd.scor_cb)(machine, cd.scor_signal); + } +} + +static TIMER_CALLBACK(matsucd_set_status_end) +{ + update_status_changed( machine, 1 ); +} + +static void matsucd_set_status( running_machine &machine, UINT8 status ) +{ + if ( status != cd.status ) + { + cd.status = status; + + if ( cd.stch_signal != 0 ) + { + update_status_changed( machine, 0 ); + machine.scheduler().timer_set(attotime::from_msec(1), FUNC(matsucd_set_status_end)); + } + } +} + +static TIMER_CALLBACK(matsu_subcode_proc) +{ + (void)param; + + if (cd.cdda != NULL) + { + UINT8 s = matsucd_cdda_getstatus(machine, NULL); + UINT8 newstatus = cd.status; + + if ( s == 0x11 || s == 0x12 ) + { + if ( s == 0x11 ) + { + update_subcode_ready( machine, 1 ); + update_subcode_ready( machine, 0 ); + } + + newstatus |= MATSU_STATUS_PLAYING; + + cd.frame_timer->adjust(attotime::from_hz( 75 )); + } + else + { + newstatus &= ~MATSU_STATUS_PLAYING; + } + + matsucd_set_status( machine, newstatus ); + } +} + +static void matsucd_command_error( running_machine &machine ) +{ + UINT8 newstatus = cd.status; + + newstatus &= ~MATSU_STATUS_SUCCESS; + newstatus |= MATSU_STATUS_ERROR; + + matsucd_set_status( machine, newstatus ); +} + +static void matsucd_complete_cmd( running_machine &machine, UINT8 len ) +{ + UINT8 newstatus = cd.status; + + cd.input_pos = 0; + cd.output_pos = 0; + cd.output_len = len; + + newstatus &= ~MATSU_STATUS_ERROR; + newstatus |= MATSU_STATUS_SUCCESS; + + matsucd_set_status( machine, newstatus ); + + update_status_enable( machine, 1 ); + update_status_enable( machine, 0 ); +} + +UINT8 matsucd_response_r( running_machine &machine ) +{ + UINT8 v = cd.output[cd.output_pos++]; + + if ( cd.output_pos < cd.output_len ) + { + update_status_enable( machine, 1 ); + update_status_enable( machine, 0 ); + } + + return v; +} + +void matsucd_command_w( running_machine &machine, UINT8 data ) +{ + UINT8 cmd; + + /* make sure we're enabled */ + if ( cd.enabled == 0 ) + return; + + /* make sure /CMD is asserted */ + if ( cd.cmd_signal == 0 ) + return; + + if ( cd.cdda_set == 0 ) + { + if ( cd.cdrom ) + cd.cdda->set_cdrom(cd.cdrom); + + cd.cdda_set = 1; + } + + cd.input[cd.input_pos++] = data; + + cmd = cd.input[0]; + + switch( cmd ) + { + case 0x01: /* seek */ + { + if ( cd.input_pos < 7 ) + return; + + /* stop CDDA audio if necessary */ + matsucd_cdda_stop(machine); + + cd.motor = 1; + + memset( cd.output, 0, 6 ); + matsucd_complete_cmd( machine, 0 ); + } + break; + + case 0x02: /* read sectors */ + { + if ( cd.input_pos < 7 ) + return; + + /* stop CDDA audio if necessary */ + matsucd_cdda_stop(machine); + + /* LBA */ + cd.lba = cd.input[1]; + cd.lba <<= 8; + cd.lba |= cd.input[2]; + cd.lba <<= 8; + cd.lba |= cd.input[3]; + + /* Number of blocks */ + cd.num_blocks = cd.input[4]; + cd.num_blocks <<= 8; + cd.num_blocks |= cd.input[5]; + + /* Reset transfer count */ + cd.xfer_offset = 0; + + /* go ahead and cache the first block */ + if (!cdrom_read_data(cd.cdrom, cd.lba, cd.sector_buffer, matsucd_getsector_type())) + { + logerror( "MATSUCD - Warning: Read error on CD!\n" ); + matsucd_command_error( machine ); + return; + } + + cd.motor = 1; + + memset( cd.output, 0, 6 ); + matsucd_complete_cmd( machine, 0 ); + } + break; + + case 0x04: /* motor on */ + { + if ( cd.input_pos < 7 ) + return; + + cd.motor = 1; + + memset( cd.output, 0, 6 ); + matsucd_complete_cmd( machine, 0 ); + } + break; + + case 0x05: /* motor off */ + { + if ( cd.input_pos < 7 ) + return; + + /* stop CDDA audio if necessary */ + matsucd_cdda_stop(machine); + + cd.motor = 0; + + memset( cd.output, 0, 6 ); + matsucd_complete_cmd( machine, 0 ); + } + break; + + case 0x09: /* play audio cd, LBA mode */ + { + UINT32 lba, numblocks; + + if ( cd.input_pos < 7 ) + return; + + lba = cd.input[1]; + lba <<= 8; + lba |= cd.input[2]; + lba <<= 8; + lba |= cd.input[3]; + + numblocks = cd.input[4]; + numblocks <<= 8; + numblocks |= cd.input[5]; + numblocks <<= 8; + numblocks |= cd.input[6]; + + matsucd_cdda_play( machine, lba, numblocks ); + + cd.motor = 1; + + memset( cd.output, 0, 6 ); + matsucd_complete_cmd( machine, 0 ); + } + break; + + case 0x0a: /* play audio cd, MSF mode */ + { + UINT32 start, end, lba_start, lba_end; + + if ( cd.input_pos < 7 ) + return; + + start = cd.input[1]; + start <<= 8; + start |= cd.input[2]; + start <<= 8; + start |= cd.input[3]; + + end = cd.input[4]; + end <<= 8; + end |= cd.input[5]; + end <<= 8; + end |= cd.input[6]; + + lba_start = MSF2LBA( start ); + lba_end = MSF2LBA( end ); + + if ( end == 0xffffff ) + { + lba_end = cdrom_get_track_start(cd.cdrom,cdrom_get_last_track(cd.cdrom)-1); + lba_end += cdrom_get_toc(cd.cdrom)->tracks[cdrom_get_last_track(cd.cdrom)-1].frames; + } + + if ( lba_end <= lba_start ) + { + matsucd_cdda_stop(machine); + } + else + { + matsucd_cdda_play( machine, lba_start, lba_end - lba_start ); + cd.motor = 1; + } + + memset( cd.output, 0, 6 ); + matsucd_complete_cmd( machine, 0 ); + } + break; + + case 0x0b: /* play audio track and index */ + { + UINT8 track_start = cd.input[1]; + UINT8 index_start = cd.input[2]; + UINT8 track_end = cd.input[3]; + UINT8 index_end = cd.input[4]; + UINT32 lba_start, lba_end; + + /* TODO: Add index support once the CDDA engine supports it */ + (void)index_start; + (void)index_end; + + /* sanitize values */ + if ( track_start == 0 ) track_start++; + if ( track_end == 0 ) track_end++; + if ( track_end > cdrom_get_last_track(cd.cdrom) ) + track_end = cdrom_get_last_track(cd.cdrom); + + /* find the start and stop positions */ + lba_start = cdrom_get_track_start(cd.cdrom,track_start-1); + lba_end = cdrom_get_track_start(cd.cdrom,track_end-1); + + lba_end += cdrom_get_toc(cd.cdrom)->tracks[track_end-1].frames; + + if ( lba_end <= lba_start ) + { + matsucd_cdda_stop(machine); + } + else + { + matsucd_cdda_play( machine, lba_start, lba_end - lba_start ); + cd.motor = 1; + } + + memset( cd.output, 0, 6 ); + matsucd_complete_cmd( machine, 0 ); + } + break; + + case 0x81: /* status read */ + { + UINT8 newstatus = cd.status; + + newstatus &= MATSU_STATUS_SUCCESS | MATSU_STATUS_ERROR | MATSU_STATUS_PLAYING; + newstatus |= MATSU_STATUS_READY; + + if (cd.cdrom) + { + newstatus |= MATSU_STATUS_MEDIA; + } + + if (cd.motor) + newstatus |= MATSU_STATUS_MOTOR; + + cd.output[0] = newstatus; + + matsucd_set_status( machine, newstatus ); + + matsucd_complete_cmd( machine, 1 ); + } + break; + + case 0x82: /* error read */ + { + if ( cd.input_pos < 7 ) + return; + + memset( cd.output, 0, 6 ); + matsucd_complete_cmd( machine, 6 ); + } + break; + + case 0x84: /* set mode */ + { + if ( cd.input_pos < 7 ) + return; + + cd.sector_size = cd.input[2]; + cd.sector_size <<= 8; + cd.sector_size |= cd.input[3]; + + memset( cd.output, 0, 6 ); + matsucd_complete_cmd( machine, 0 ); + } + break; + + case 0x87: /* read SUBQ */ + { + int msfmode; + UINT32 lba; + UINT8 track; + + if ( cd.input_pos < 7 ) + return; + + msfmode = (cd.input[1] & 0x02) ? 1 : 0; + + memset( cd.output, 0, 13 ); + + cd.output[0] = matsucd_cdda_getstatus( machine, &lba ); + + if ( lba > 0 ) + { + UINT32 disk_pos; + UINT32 track_pos; + + track = cdrom_get_track(cd.cdrom, lba); + + cd.output[1] = cdrom_get_adr_control(cd.cdrom, track); + cd.output[2] = track+1; + cd.output[3] = 0; /* index */ + + disk_pos = lba; + if ( msfmode ) disk_pos = LBA2MSF(disk_pos); + + cd.output[4] = (disk_pos >> 24) & 0xff; + cd.output[5] = (disk_pos >> 16) & 0xff; + cd.output[6] = (disk_pos >> 8) & 0xff; + cd.output[7] = (disk_pos) & 0xff; + + track_pos = lba - cdrom_get_track_start(cd.cdrom, track); + if ( msfmode ) track_pos = LBA2MSF(track_pos); + + cd.output[8] = (track_pos >> 24) & 0xff; + cd.output[9] = (track_pos >> 16) & 0xff; + cd.output[10] = (track_pos >> 8) & 0xff; + cd.output[11] = (track_pos) & 0xff; + + /* TODO: UPC flag at offset 12 */ + cd.output[12] = 0; + } + + matsucd_complete_cmd( machine, 13 ); + } + break; + + case 0x89: /* read disk info */ + { + UINT32 end; + + if ( cd.input_pos < 7 ) + return; + + memset( cd.output, 0, 5 ); + + cd.output[0] = cdrom_get_last_track(cd.cdrom) ? 1 : 0; + cd.output[1] = cdrom_get_last_track(cd.cdrom); + end = cdrom_get_track_start(cd.cdrom,cd.output[1]-1); + end += cdrom_get_toc(cd.cdrom)->tracks[cd.output[1]-1].frames; + end = LBA2MSF(end); + cd.output[2] = (end >> 16) & 0xff; + cd.output[3] = (end >> 8) & 0xff; + cd.output[4] = (end) & 0xff; + + matsucd_complete_cmd( machine, 5 ); + } + break; + + case 0x8a: /* read toc */ + { + UINT8 track; + int msfmode; + UINT32 track_start; + + if ( cd.input_pos < 7 ) + return; + + /* stop CDDA audio if necessary */ + matsucd_cdda_stop(machine); + + track = cd.input[2]; + msfmode = (cd.input[1] & 0x02) ? 1 : 0; + + if ( cd.cdrom == NULL ) + { + logerror( "MATSUCD - Warning: Reading TOC without a CD!\n" ); + matsucd_command_error( machine ); + return; + } + + if ( track > cdrom_get_last_track(cd.cdrom) ) + { + logerror( "MATSUCD - Warning: Reading invalid track entry from TOC!\n" ); + matsucd_command_error( machine ); + return; + } + + memset( cd.output, 0, 7 ); + + track_start = cdrom_get_track_start(cd.cdrom, track > 0 ? (track-1) : track ); + if ( msfmode ) track_start = LBA2MSF( track_start ); + + cd.output[1] = cdrom_get_adr_control(cd.cdrom, track > 0 ? (track-1) : track); + cd.output[2] = track; + cd.output[3] = (track == 0 ) ? cdrom_get_last_track(cd.cdrom) : 0; + cd.output[4] = (track_start >> 24) & 0xff; + cd.output[5] = (track_start >> 16) & 0xff; + cd.output[6] = (track_start >> 8) & 0xff; + cd.output[7] = (track_start) & 0xff; + + cd.motor = 1; + + matsucd_complete_cmd( machine, 8 ); + } + break; + + case 0x8b: /* pause audio */ + { + if ( cd.input_pos < 7 ) + return; + + matsucd_cdda_pause( machine, (cd.input[1] == 0) ? 1 : 0 ); + memset( cd.output, 0, 7 ); + matsucd_complete_cmd( machine, 0 ); + } + break; + + case 0xa3: /* front panel */ + { + if ( cd.input_pos < 7 ) + return; + + /* TODO: ??? */ + + memset( cd.output, 0, 7 ); + matsucd_complete_cmd( machine, 0 ); + } + break; + + default: + logerror( "MATSUCD: Unknown/inimplemented command %08x\n", cmd ); + break; + } +} diff --git a/src/devices/machine/matsucd.h b/src/devices/machine/matsucd.h new file mode 100644 index 00000000000..19a456760a6 --- /dev/null +++ b/src/devices/machine/matsucd.h @@ -0,0 +1,31 @@ +// license:BSD-3-Clause +// copyright-holders:smf, Mariusz Wojcieszek +/*************************************************************************** + + Matsushita/Panasonic CDR521/522 type CDROM drive emulation + +***************************************************************************/ + +/* initialization */ +void matsucd_init( cdrom_image_device *cdrom_device, const char *cdda_tag ); + + +/* signaling */ +extern void matsucd_enable_w( int level ); /* /ENABLE pin */ +extern void matsucd_cmd_w( int level ); /* /CMD pin */ +extern int matsucd_stch_r( void ); /* /STCH pin */ +extern int matsucd_sten_r( void ); /* /STEN pin */ +extern int matsucd_scor_r( void ); /* /SCOR pin */ + +/* callback for signal changes */ +extern void matsucd_set_status_enabled_callback( void (*sten_cb)( running_machine &machine, int level ) ); +extern void matsucd_set_status_changed_callback( void (*stch_cb)( running_machine &machine, int level ) ); +extern void matsucd_set_subcode_ready_callback( void (*scor_cb)( running_machine &machine, int level ) ); + +/* data transfer routines */ +extern void matsucd_read_next_block( void ); +extern int matsucd_get_next_byte( UINT8 *data ); + +/* main command interface */ +extern void matsucd_command_w( running_machine &machine, UINT8 data ); +extern UINT8 matsucd_response_r( running_machine &machine ); diff --git a/src/devices/machine/mb14241.c b/src/devices/machine/mb14241.c new file mode 100644 index 00000000000..732dccf8e1d --- /dev/null +++ b/src/devices/machine/mb14241.c @@ -0,0 +1,73 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/*************************************************************************** + + Midway 8080-based black and white hardware + +****************************************************************************/ + +#include "emu.h" +#include "machine/mb14241.h" + + +//------------------------------------------------- +// mb14241_device - constructor +//------------------------------------------------- + + +const device_type MB14241 = &device_creator; + +mb14241_device::mb14241_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, MB14241, "MB14241 Data Shifter", tag, owner, clock, "mb14241", __FILE__) +{ +} + +//------------------------------------------------- +// device_config_complete - perform any +// operations now that the configuration is +// complete +//------------------------------------------------- + +void mb14241_device::device_config_complete() +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void mb14241_device::device_start() +{ + save_item(NAME(m_shift_data)); + save_item(NAME(m_shift_count)); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void mb14241_device::device_reset() +{ + m_shift_data = 0; + m_shift_count = 0; +} + + +/***************************************************************************** + IMPLEMENTATION +*****************************************************************************/ + +WRITE8_MEMBER( mb14241_device::shift_count_w ) +{ + m_shift_count = ~data & 0x07; +} + +WRITE8_MEMBER( mb14241_device::shift_data_w ) +{ + m_shift_data = (m_shift_data >> 8) | ((UINT16)data << 7); +} + +READ8_MEMBER( mb14241_device::shift_result_r ) +{ + return m_shift_data >> m_shift_count; +} diff --git a/src/devices/machine/mb14241.h b/src/devices/machine/mb14241.h new file mode 100644 index 00000000000..68a85c583ec --- /dev/null +++ b/src/devices/machine/mb14241.h @@ -0,0 +1,45 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli +/***************************************************************************** + + MB14241 shifter IC emulation + + *****************************************************************************/ + +#ifndef __MB14241_H__ +#define __MB14241_H__ + + +class mb14241_device : public device_t +{ +public: + mb14241_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + DECLARE_WRITE8_MEMBER ( shift_count_w ); + DECLARE_WRITE8_MEMBER ( shift_data_w ); + DECLARE_READ8_MEMBER( shift_result_r ); + +protected: + // device-level overrides + virtual void device_config_complete(); + virtual void device_start(); + virtual void device_reset(); + +private: + // internal state + + UINT16 m_shift_data; /* 15 bits only */ + UINT8 m_shift_count; /* 3 bits */ +}; + +extern const device_type MB14241; + + +/*************************************************************************** + DEVICE CONFIGURATION MACROS +***************************************************************************/ + +#define MCFG_MB14241_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, MB14241, 0) + +#endif /* __MB14241_H__ */ diff --git a/src/devices/machine/mb3773.c b/src/devices/machine/mb3773.c new file mode 100644 index 00000000000..b2093787338 --- /dev/null +++ b/src/devices/machine/mb3773.c @@ -0,0 +1,76 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/*************************************************************************** + + Fujitsu MB3773 + + Power Supply Monitor with Watch Dog Timer (i.e. Reset IC) + + + Todo: + Calculate the timeout from parameters. + +***************************************************************************/ + +#include "emu.h" +#include "mb3773.h" + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +// device type definition +const device_type MB3773 = &device_creator; + +//------------------------------------------------- +// mb3773_device - constructor +//------------------------------------------------- + +mb3773_device::mb3773_device( const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock ) + : device_t(mconfig, MB3773, "MB3773 Power Supply Monitor", tag, owner, clock, "mb3773", __FILE__) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void mb3773_device::device_start() +{ + m_watchdog_timer = timer_alloc(); + reset_timer(); + + save_item( NAME(m_ck) ); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void mb3773_device::device_reset() +{ + m_ck = 0; +} + +void mb3773_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + machine().schedule_soft_reset(); +} + +void mb3773_device::reset_timer() +{ + m_watchdog_timer->adjust( attotime::from_seconds( 5 ) ); +} + +WRITE_LINE_MEMBER( mb3773_device::write_line_ck ) +{ + if( state == 0 && m_ck != 0 ) + { + reset_timer(); + } + + m_ck = state; +} diff --git a/src/devices/machine/mb3773.h b/src/devices/machine/mb3773.h new file mode 100644 index 00000000000..3199f545bf7 --- /dev/null +++ b/src/devices/machine/mb3773.h @@ -0,0 +1,56 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/*************************************************************************** + + Fujistu MB3773 + + Power Supply Monitor with Watch Dog Timer (i.e. Reset IC) + +***************************************************************************/ + +#pragma once + +#ifndef __MB3773_H__ +#define __MB3773_H__ + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_MB3773_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, MB3773, 0) + + +// ======================> mb3773_device + +class mb3773_device : + public device_t +{ +public: + // construction/destruction + mb3773_device( const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock ); + + // I/O operations + WRITE_LINE_MEMBER( write_line_ck ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + +private: + void reset_timer(); + + // internal state + emu_timer *m_watchdog_timer; + int m_ck; +}; + + +// device type definition +extern const device_type MB3773; + +#endif diff --git a/src/devices/machine/mb8421.c b/src/devices/machine/mb8421.c new file mode 100644 index 00000000000..0d3cb819a66 --- /dev/null +++ b/src/devices/machine/mb8421.c @@ -0,0 +1,94 @@ +// license:BSD-3-Clause +// copyright-holders:hap +/********************************************************************** + + Fujitsu MB8421/22/31/32-90/-90L/-90LL/-12/-12L/-12LL + CMOS 16K-bit (2KB) dual-port SRAM + + MB84x2 lacks interrupt pins, it's basically as simple as AM_RAM AM_SHARE("x") + MB843x is same as MB842x, except that it supports slave mode. It makes + sure there are no clashes, with the _BUSY pin. + +**********************************************************************/ + +#include "machine/mb8421.h" + + +const device_type MB8421 = &device_creator; + +//------------------------------------------------- +// mb8421_device - constructor +//------------------------------------------------- + +mb8421_device::mb8421_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, MB8421, "MB8421 DPSRAM", tag, owner, clock, "mb8421", __FILE__), + m_intl_handler(*this), + m_intr_handler(*this) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void mb8421_device::device_start() +{ + memset(m_ram, 0, 0x800); + + // resolve callbacks + m_intl_handler.resolve_safe(); + m_intr_handler.resolve_safe(); + + // state save + save_item(NAME(m_ram)); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void mb8421_device::device_reset() +{ + m_intl_handler(0); + m_intr_handler(0); +} + + + +WRITE8_MEMBER(mb8421_device::left_w) +{ + offset &= 0x7ff; + m_ram[offset] = data; + + if (offset == 0x7ff) + m_intr_handler(1); +} + +READ8_MEMBER(mb8421_device::left_r) +{ + offset &= 0x7ff; + + if (offset == 0x7fe && !space.debugger_access()) + m_intl_handler(0); + + return m_ram[offset]; +} + +WRITE8_MEMBER(mb8421_device::right_w) +{ + offset &= 0x7ff; + m_ram[offset] = data; + + if (offset == 0x7fe) + m_intl_handler(1); +} + +READ8_MEMBER(mb8421_device::right_r) +{ + offset &= 0x7ff; + + if (offset == 0x7ff && !space.debugger_access()) + m_intr_handler(0); + + return m_ram[offset]; +} diff --git a/src/devices/machine/mb8421.h b/src/devices/machine/mb8421.h new file mode 100644 index 00000000000..92300e45946 --- /dev/null +++ b/src/devices/machine/mb8421.h @@ -0,0 +1,71 @@ +// license:BSD-3-Clause +// copyright-holders:hap +/********************************************************************** + + Fujitsu MB8421/22/31/32-90/-90L/-90LL/-12/-12L/-12LL + CMOS 16K-bit (2KB) dual-port SRAM + +**********************************************************************/ + +#pragma once + +#ifndef _MB8421_H +#define _MB8421_H + +#include "emu.h" + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +// note: INT pins are only available on MB84x1 +// INTL is for the CPU on the left side, INTR for the one on the right +#define MCFG_MB8421_INTL_HANDLER(_devcb) \ + devcb = &mb8421_device::set_intl_handler(*device, DEVCB_##_devcb); + +#define MCFG_MB8421_INTR_HANDLER(_devcb) \ + devcb = &mb8421_device::set_intr_handler(*device, DEVCB_##_devcb); + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> mb8421_device + +class mb8421_device : public device_t +{ +public: + mb8421_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // static configuration helpers + template static devcb_base &set_intl_handler(device_t &device, _Object object) { return downcast(device).m_intl_handler.set_callback(object); } + template static devcb_base &set_intr_handler(device_t &device, _Object object) { return downcast(device).m_intr_handler.set_callback(object); } + + DECLARE_READ_LINE_MEMBER( busy_r ) { return 0; } // _BUSY pin - not emulated + UINT8 peek(offs_t offset) { return m_ram[offset & 0x7ff]; } + + DECLARE_WRITE8_MEMBER( left_w ); + DECLARE_READ8_MEMBER( left_r ); + DECLARE_WRITE8_MEMBER( right_w ); + DECLARE_READ8_MEMBER( right_r ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + +private: + UINT8 m_ram[0x800]; + + devcb_write_line m_intl_handler; + devcb_write_line m_intr_handler; +}; + +// device type definition +extern const device_type MB8421; + + +#endif /* _MB8421_H */ diff --git a/src/devices/machine/mb87078.c b/src/devices/machine/mb87078.c new file mode 100644 index 00000000000..a94380456f5 --- /dev/null +++ b/src/devices/machine/mb87078.c @@ -0,0 +1,247 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli,Philip Bennett +/***************************************************************************** + + Fujitsu MB87078 6-bit, 4-channel electronic volume controller emulator + + An excerpt from the datasheet about the chip functionality: + "A digital signal input controls gain every 0.5 dB step from 0dB to -32dB. + - Gain variable range: 0 dB to -32 dB by 0.5dB or -infinity + - Gain variable range is expanded to connect two channels serially (0 dB to -64 dB) + - Each channel gain can be set respectively + - Test function is provided (to confirm internal data) + - Data is initialized by reset signal (all channels are set to 0dB) + - Logic I/O is TTL comatible" + + There are 6 digital data input/output pins and DSEL pin that selects + the group (there are two) of internal registers to be read/written. + + Group 0 is 6-bit gain latch + Group 1 is 5-bit control latch (2-bits are channel select and 3-bits are volume control) + + Digital I/O Setting: + /TC DSEL D0 D1 D2 D3 D4 D5 I/O MODES (when /TC==H ->write) + H H DSC1 DSC2 EN C0 C32 X Input mode + H L GD0 GD1 GD2 GD3 GD4 GD5 (set) + L H DSC1 DSC2 EN C0 C32 L Output mode + L L GD0 GD1 GD2 GD3 GD4 GD5 (check) + + Channel Setting: + DSC2 DSC1 CHANNEL + L L 0 + L H 1 + H L 2 + H H 3 + + Electrical Volume Setting: + DATA* GAIN + GD5 GD4 GD3 GD2 GD1 GD0 EN C0 C32 (dB) + 1 1 1 1 1 1 1 0 0 0 + 1 1 1 1 1 0 1 0 0 -0.5 + 1 1 1 1 0 1 1 0 0 -1 + 1 1 1 1 0 0 1 0 0 -1.5 + 1 1 1 0 1 1 1 0 0 -2 + [..........................................] + 0 0 0 0 0 1 1 0 0 -31 + 0 0 0 0 0 0 1 0 0 -31.5 + X X X X X X 1 X 1 -32 + X X X X X X 1 1 0 0 + X X X X X X 0 X X -infinity + + X=don't care + * When reset, DATA is set to 0 dB (code 111111 100) + + + MB87078 pins and assigned interface variables/functions + + /[ 1] D0 /TC [24] + | [ 2] D1 /WR [23] + MB87078_data_w()| [ 3] D2 /CE [22] + MB87078_data_r()| [ 4] D3 DSEL [21]-MB87078_data_w()/data_r() parameter + | [ 5] D4 /RESET [20]-MB87078_reset_comp_w() + \[ 6] D5 /PD [19] + [ 7] DGND VDD [18] + [ 8] AGND 1/2 VDD [17] + [ 9] AIN0 AOUT3 [16] + [10] AOUT0 AIN3 [15] + [11] AIN1 AOUT2 [14] + [12] AOUT1 AIN2 [13] + + + *****************************************************************************/ + +#include "emu.h" +#include "machine/mb87078.h" + + +static const float mb87078_gain_decibel[66] = { + 0.0, -0.5, -1.0, -1.5, -2.0, -2.5, -3.0, -3.5, + -4.0, -4.5, -5.0, -5.5, -6.0, -6.5, -7.0, -7.5, + -8.0, -8.5, -9.0, -9.5,-10.0,-10.5,-11.0,-11.5, + -12.0,-12.5,-13.0,-13.5,-14.0,-14.5,-15.0,-15.5, + -16.0,-16.5,-17.0,-17.5,-18.0,-18.5,-19.0,-19.5, + -20.0,-20.5,-21.0,-21.5,-22.0,-22.5,-23.0,-23.5, + -24.0,-24.5,-25.0,-25.5,-26.0,-26.5,-27.0,-27.5, + -28.0,-28.5,-29.0,-29.5,-30.0,-30.5,-31.0,-31.5, + -32.0, -256.0 + }; + +static const int mb87078_gain_percent[66] = { + 100,94,89,84,79,74,70,66, + 63,59,56,53,50,47,44,42, + 39,37,35,33,31,29,28,26, + 25,23,22,21,19,18,17,16, + 15,14,14,13,12,11,11,10, + 10, 9, 8, 8, 7, 7, 7, 6, + 6, 5, 5, 5, 5, 4, 4, 4, + 3, 3, 3, 3, 3, 2, 2, 2, + 2, 0 +}; + +/***************************************************************************** + DEVICE INTERFACE +*****************************************************************************/ + +const device_type MB87078 = &device_creator; + +mb87078_device::mb87078_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, MB87078, "MB87078 Volume Controller", tag, owner, clock, "mb87078", __FILE__), + m_channel_latch(0), + m_reset_comp(0), + m_gain_changed_cb(*this) +{ + m_gain[0] = m_gain[1] = m_gain[2] = m_gain[3] = 0; + memset(m_latch, 0, sizeof(m_latch)); +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void mb87078_device::device_start() +{ + m_gain_changed_cb.resolve_safe(); + + save_item(NAME(m_channel_latch)); + save_item(NAME(m_reset_comp)); + save_item(NAME(m_latch[0])); + save_item(NAME(m_latch[1])); + save_item(NAME(m_gain)); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void mb87078_device::device_reset() +{ + m_channel_latch = 0; + + /* reset chip */ + reset_comp_w(0); + reset_comp_w(1); +} + +/***************************************************************************** + IMPLEMENTATION +*****************************************************************************/ + +#define GAIN_MAX_INDEX 64 +#define GAIN_INFINITY_INDEX 65 + + +static int calc_gain_index( int data0, int data1 ) +{ +//data 0: GD0-GD5 +//data 1: 1 2 4 8 16 +// c1 c2 EN C0 C32 + + if (!(data1 & 0x04)) + { + return GAIN_INFINITY_INDEX; + } + else + { + if (data1 & 0x10) + { + return GAIN_MAX_INDEX; + } + else + { + if (data1 & 0x08) + { + return 0; + } + else + { + return (data0 ^ 0x3f); + } + } + } +} + + +void mb87078_device::gain_recalc() +{ + int i; + + for (i = 0; i < 4; i++) + { + int old_index = m_gain[i]; + m_gain[i] = calc_gain_index(m_latch[0][i], m_latch[1][i]); + if (old_index != m_gain[i]) + m_gain_changed_cb((offs_t)i, mb87078_gain_percent[m_gain[i]]); + } +} + + + +void mb87078_device::data_w( int data, int dsel ) +{ + if (m_reset_comp == 0) + return; + + if (dsel == 0) /* gd0 - gd5 */ + { + m_latch[0][m_channel_latch] = data & 0x3f; + } + else /* dcs1, dsc2, en, c0, c32, X */ + { + m_channel_latch = data & 3; + m_latch[1][m_channel_latch] = data & 0x1f; //always zero bit 5 + } + gain_recalc(); +} + + +float mb87078_device::gain_decibel_r( int channel ) +{ + return mb87078_gain_decibel[m_gain[channel]]; +} + + +int mb87078_device::gain_percent_r( int channel ) +{ + return mb87078_gain_percent[m_gain[channel]]; +} + +void mb87078_device::reset_comp_w( int level ) +{ + m_reset_comp = level; + + /*this seems to be true, according to the datasheets*/ + if (level == 0) + { + m_latch[0][0] = 0x3f; + m_latch[0][1] = 0x3f; + m_latch[0][2] = 0x3f; + m_latch[0][3] = 0x3f; + + m_latch[1][0] = 0x0 | 0x4; + m_latch[1][1] = 0x1 | 0x4; + m_latch[1][2] = 0x2 | 0x4; + m_latch[1][3] = 0x3 | 0x4; + } + + gain_recalc(); +} diff --git a/src/devices/machine/mb87078.h b/src/devices/machine/mb87078.h new file mode 100644 index 00000000000..15e68b83b22 --- /dev/null +++ b/src/devices/machine/mb87078.h @@ -0,0 +1,68 @@ +// license:BSD-3-Clause +// copyright-holders:Fabio Priuli,Philip Bennett +/***************************************************************************** + + MB87078 6-bit,4-channel electronic volume controller emulator + + +*****************************************************************************/ + +#ifndef __MB87078_H__ +#define __MB87078_H__ + + +/*************************************************************************** + DEVICE CONFIGURATION MACROS +***************************************************************************/ + +#define MCFG_MB87078_GAIN_CHANGED_CB(_devcb) \ + devcb = &mb87078_device::set_gain_changed_callback(*device, DEVCB_##_devcb); + +/*************************************************************************** + TYPE DEFINITIONS +***************************************************************************/ + +class mb87078_device : public device_t +{ +public: + mb87078_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + ~mb87078_device() {} + + template static devcb_base &set_gain_changed_callback(device_t &device, _Object object) { return downcast(device).m_gain_changed_cb.set_callback(object); } + + void data_w(int data, int dsel); + void reset_comp_w(int level); + + + /* gain_decibel_r will return 'channel' gain on the device. + Returned value represents channel gain expressed in decibels, + Range from 0 to -32.0 (or -256.0 for -infinity) */ + float gain_decibel_r(int channel); + + + /* gain_percent_r will return 'channel' gain on the device. + Returned value represents channel gain expressed in percents of maximum volume. + Range from 100 to 0. (100 = 0dB; 50 = -6dB; 0 = -infinity) + This function is designed for use with MAME mixer_xxx() functions. */ + int gain_percent_r(int channel); + + void gain_recalc(); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + +private: + // internal state + int m_gain[4]; /* gain index 0-63,64,65 */ + int m_channel_latch; /* current channel */ + UINT8 m_latch[2][4]; /* 6bit+3bit 4 data latches */ + UINT8 m_reset_comp; + + devcb_write8 m_gain_changed_cb; +}; + +extern const device_type MB87078; + +#endif /* __MB87078_H__ */ diff --git a/src/devices/machine/mb8795.c b/src/devices/machine/mb8795.c new file mode 100644 index 00000000000..3a83f02af94 --- /dev/null +++ b/src/devices/machine/mb8795.c @@ -0,0 +1,335 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert + +#include "emu.h" +#include "mb8795.h" + +const device_type MB8795 = &device_creator; + +DEVICE_ADDRESS_MAP_START(map, 8, mb8795_device) + AM_RANGE(0x0, 0x0) AM_READWRITE(txstat_r, txstat_w) + AM_RANGE(0x1, 0x1) AM_READWRITE(txmask_r, txmask_w) + AM_RANGE(0x2, 0x2) AM_READWRITE(rxstat_r, rxstat_w) + AM_RANGE(0x3, 0x3) AM_READWRITE(rxmask_r, rxmask_w) + AM_RANGE(0x4, 0x4) AM_READWRITE(txmode_r, txmode_w) + AM_RANGE(0x5, 0x5) AM_READWRITE(rxmode_r, rxmode_w) + AM_RANGE(0x6, 0x6) AM_WRITE(reset_w) + AM_RANGE(0x7, 0x7) AM_READ(tdc_lsb_r) + AM_RANGE(0x8, 0xf) AM_READWRITE(mac_r, mac_w) // Mapping limitation, real is up to 0xd +ADDRESS_MAP_END + +mb8795_device::mb8795_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, MB8795, "Fujitsu MB8795", tag, owner, clock, "mb8795", __FILE__), + device_network_interface(mconfig, *this, 10), + irq_tx_cb(*this), + irq_rx_cb(*this), + drq_tx_cb(*this), + drq_rx_cb(*this) +{ +} + +void mb8795_device::check_irq() +{ + bool old_irq_tx = irq_tx; + bool old_irq_rx = irq_rx; + irq_tx = txstat & txmask; + irq_rx = rxstat & rxmask; + if(irq_tx != old_irq_tx && !irq_tx_cb.isnull()) + irq_tx_cb(irq_tx); + if(irq_rx != old_irq_rx && !irq_rx_cb.isnull()) + irq_rx_cb(irq_rx); +} + +void mb8795_device::device_start() +{ + irq_tx_cb.resolve(); + irq_rx_cb.resolve(); + drq_tx_cb.resolve(); + drq_rx_cb.resolve(); + + memset(mac, 0, 6); + timer_tx = timer_alloc(TIMER_TX); + timer_rx = timer_alloc(TIMER_RX); +} + +void mb8795_device::device_reset() +{ + txstat = EN_TXS_READY; + txmask = 0x00; + rxstat = 0x00; + rxmask = 0x00; + txmode = 0x00; + rxmode = 0x00; + + drq_tx = drq_rx = false; + irq_tx = irq_rx = false; + + txlen = rxlen = txcount = 0; + + set_promisc(true); + + start_send(); +} + +void mb8795_device::recv_cb(UINT8 *buf, int len) +{ + memcpy(rxbuf, buf, len); + rxlen = len; + receive(); +} + +READ8_MEMBER(mb8795_device::txstat_r) +{ + // logerror("%s: txstat_r %02x (%08x)\n", tag(), txstat, space.device().safe_pc()); + return txstat; +} + +WRITE8_MEMBER(mb8795_device::txstat_w) +{ + txstat = txstat & (0xf0 | ~data); + check_irq(); + logerror("%s: txstat_w %02x (%08x)\n", tag(), txstat, space.device().safe_pc()); +} + +READ8_MEMBER(mb8795_device::txmask_r) +{ + logerror("%s: txmask_r %02x (%08x)\n", tag(), txmask, space.device().safe_pc()); + return txmask; +} + +WRITE8_MEMBER(mb8795_device::txmask_w) +{ + txmask = data & 0xaf; + check_irq(); + logerror("%s: txmask_w %02x (%08x)\n", tag(), txmask, space.device().safe_pc()); +} + +READ8_MEMBER(mb8795_device::rxstat_r) +{ + logerror("%s: rxstat_r %02x (%08x)\n", tag(), rxstat, space.device().safe_pc()); + return rxstat; +} + +WRITE8_MEMBER(mb8795_device::rxstat_w) +{ + rxstat = rxstat & (0x70 | ~data); + check_irq(); + logerror("%s: rxstat_w %02x (%08x)\n", tag(), rxstat, space.device().safe_pc()); +} + +READ8_MEMBER(mb8795_device::rxmask_r) +{ + logerror("%s: rxmask_r %02x (%08x)\n", tag(), rxmask, space.device().safe_pc()); + return rxmask; +} + +WRITE8_MEMBER(mb8795_device::rxmask_w) +{ + rxmask = data & 0x9f; + check_irq(); + logerror("%s: rxmask_w %02x (%08x)\n", tag(), rxmask, space.device().safe_pc()); +} + +READ8_MEMBER(mb8795_device::txmode_r) +{ + logerror("%s: txmode_r %02x (%08x)\n", tag(), txmode, space.device().safe_pc()); + return txmode; +} + +WRITE8_MEMBER(mb8795_device::txmode_w) +{ + txmode = data; + logerror("%s: txmode_w %02x (%08x)\n", tag(), txmode, space.device().safe_pc()); +} + +READ8_MEMBER(mb8795_device::rxmode_r) +{ + logerror("%s: rxmode_r %02x (%08x)\n", tag(), rxmode, space.device().safe_pc()); + return rxmode; +} + +WRITE8_MEMBER(mb8795_device::rxmode_w) +{ + rxmode = data; + logerror("%s: rxmode_w %02x (%08x)\n", tag(), rxmode, space.device().safe_pc()); +} + +WRITE8_MEMBER(mb8795_device::reset_w) +{ + if(data & EN_RST_RESET) + device_reset(); +} + +READ8_MEMBER(mb8795_device::tdc_lsb_r) +{ + logerror("%s: tdc_lsb_r %02x (%08x)\n", tag(), txcount & 0xff, space.device().safe_pc()); + return txcount; +} + +READ8_MEMBER(mb8795_device::mac_r) +{ + if(offset < 6) + return mac[offset]; + if(offset == 7) { + logerror("%s: tdc_msb_r %02x (%08x)\n", tag(), txcount >> 8, space.device().safe_pc()); + return (txcount >> 8) & 0x3f; + } + return 0; +} + +WRITE8_MEMBER(mb8795_device::mac_w) +{ + if(offset < 6) { + mac[offset] = data; + set_mac((const char *)mac); + } +} + +void mb8795_device::start_send() +{ + timer_tx->adjust(attotime::zero); +} + +void mb8795_device::tx_dma_w(UINT8 data, bool eof) +{ + txbuf[txlen++] = data; + if(txstat & EN_TXS_READY) { + txstat &= ~EN_TXS_READY; + check_irq(); + } + + drq_tx = false; + if(!drq_tx_cb.isnull()) + drq_tx_cb(drq_tx); + + if(eof) { + logerror("%s: send packet, dest=%02x.%02x.%02x.%02x.%02x.%02x len=%04x loopback=%s\n", tag(), + txbuf[0], txbuf[1], txbuf[2], txbuf[3], txbuf[4], txbuf[5], + txlen, + txmode & EN_TMD_LB_DISABLE ? "off" : "on"); + + if(txlen > 1500) + txlen = 1500; // Weird packet send on loopback test in the next + + if(!(txmode & EN_TMD_LB_DISABLE)) { + memcpy(rxbuf, txbuf, txlen); + rxlen = txlen; + receive(); + } + send(txbuf, txlen); + txlen = 0; + txstat |= EN_TXS_READY; + txcount++; + start_send(); + } else + timer_tx->adjust(attotime::from_nsec(800)); +} + +void mb8795_device::rx_dma_r(UINT8 &data, bool &eof) +{ + drq_rx = false; + if(!drq_rx_cb.isnull()) + drq_rx_cb(drq_rx); + + if(rxlen) { + data = rxbuf[0]; + rxlen--; + memmove(rxbuf, rxbuf+1, rxlen); + } else + data = 0; + + if(rxlen) { + timer_rx->adjust(attotime::from_nsec(800)); + eof = false; + } else + eof = true; +} + +void mb8795_device::receive() +{ + bool keep = false; + switch(rxmode & EN_RMD_WHATRECV) { + case EN_RMD_RECV_NONE: + keep = false; + break; + case EN_RMD_RECV_NORMAL: + keep = recv_is_broadcast() || recv_is_me() || recv_is_local_multicast(); + break; + case EN_RMD_RECV_MULTI: + keep = recv_is_broadcast() || recv_is_me() || recv_is_multicast(); + break; + case EN_RMD_RECV_PROMISC: + keep = true; + break; + } + logerror("%s: received packet for %02x.%02x.%02x.%02x.%02x.%02x len=%04x, mode=%d -> %s\n", tag(), + rxbuf[0], rxbuf[1], rxbuf[2], rxbuf[3], rxbuf[4], rxbuf[5], + rxlen, rxmode & 3, keep ? "kept" : "dropped"); + if(!keep) + rxlen = 0; + else { + // Minimal ethernet packet size + if(rxlen < 64) { + memset(rxbuf+rxlen, 0, 64-rxlen); + rxlen = 64; + } + // Checksum? In any case, it's there + memset(rxbuf+rxlen, 0, 4); + rxlen += 4; + + rxstat |= EN_RXS_OK; + check_irq(); + timer_rx->adjust(attotime::zero); + } +} + +bool mb8795_device::recv_is_broadcast() +{ + return + rxbuf[0] == 0xff && + rxbuf[1] == 0xff && + rxbuf[2] == 0xff && + rxbuf[3] == 0xff && + rxbuf[4] == 0xff && + rxbuf[5] == 0xff; +} + +bool mb8795_device::recv_is_me() +{ + return + rxbuf[0] == mac[0] && + rxbuf[1] == mac[1] && + rxbuf[2] == mac[2] && + rxbuf[3] == mac[3] && + rxbuf[4] == mac[4] && + ((rxmode & EN_RMD_ADDRSIZE) || rxbuf[5] == mac[5]); +} + +bool mb8795_device::recv_is_local_multicast() +{ + return + (rxbuf[0] & 0x01) && + (rxbuf[0] & 0xfe) == mac[0] && + rxbuf[1] == mac[1] && + rxbuf[2] == mac[2]; +} + +bool mb8795_device::recv_is_multicast() +{ + return rxbuf[0] & 0x01; +} + +void mb8795_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + if(id == TIMER_TX) { + drq_tx = true; + if(!drq_tx_cb.isnull()) + drq_tx_cb(drq_tx); + } + + if(id == TIMER_RX && rxlen) { + drq_rx = true; + if(!drq_rx_cb.isnull()) + drq_rx_cb(drq_rx); + } +} diff --git a/src/devices/machine/mb8795.h b/src/devices/machine/mb8795.h new file mode 100644 index 00000000000..478d9487263 --- /dev/null +++ b/src/devices/machine/mb8795.h @@ -0,0 +1,124 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +#ifndef MB8795_H +#define MB8795_H + +#define MCFG_MB8795_ADD(_tag, _tx_irq, _rx_irq, _tx_drq, _rx_drq) \ + MCFG_DEVICE_ADD(_tag, MB8795, 0) \ + downcast(device)->set_irq_cb(_tx_irq, _rx_irq); \ + downcast(device)->set_drq_cb(_tx_drq, _rx_drq); + +#define MCFG_MB8795_TX_IRQ_CALLBACK(_write) \ + devcb = &mb8795_device::set_tx_irq_wr_callback(*device, DEVCB_##_write); + +#define MCFG_MB8795_RX_IRQ_CALLBACK(_write) \ + devcb = &mb8795_device::set_rx_irq_wr_callback(*device, DEVCB_##_write); + +#define MCFG_MB8795_TX_DRQ_CALLBACK(_write) \ + devcb = &mb8795_device::set_tx_drq_wr_callback(*device, DEVCB_##_write); + +#define MCFG_MB8795_RX_DRQ_CALLBACK(_write) \ + devcb = &mb8795_device::set_rx_drq_wr_callback(*device, DEVCB_##_write); + +class mb8795_device : public device_t, + public device_network_interface +{ +public: + mb8795_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + template static devcb_base &set_tx_irq_wr_callback(device_t &device, _Object object) { return downcast(device).irq_tx_cb.set_callback(object); } + template static devcb_base &set_rx_irq_wr_callback(device_t &device, _Object object) { return downcast(device).irq_rx_cb.set_callback(object); } + template static devcb_base &set_tx_drq_wr_callback(device_t &device, _Object object) { return downcast(device).drq_tx_cb.set_callback(object); } + template static devcb_base &set_rx_drq_wr_callback(device_t &device, _Object object) { return downcast(device).drq_rx_cb.set_callback(object); } + + DECLARE_ADDRESS_MAP(map, 8); + + DECLARE_READ8_MEMBER(txstat_r); + DECLARE_WRITE8_MEMBER(txstat_w); + DECLARE_READ8_MEMBER(txmask_r); + DECLARE_WRITE8_MEMBER(txmask_w); + DECLARE_READ8_MEMBER(rxstat_r); + DECLARE_WRITE8_MEMBER(rxstat_w); + DECLARE_READ8_MEMBER(rxmask_r); + DECLARE_WRITE8_MEMBER(rxmask_w); + DECLARE_READ8_MEMBER(txmode_r); + DECLARE_WRITE8_MEMBER(txmode_w); + DECLARE_READ8_MEMBER(rxmode_r); + DECLARE_WRITE8_MEMBER(rxmode_w); + DECLARE_WRITE8_MEMBER(reset_w); + DECLARE_READ8_MEMBER(tdc_lsb_r); + DECLARE_READ8_MEMBER(mac_r); + DECLARE_WRITE8_MEMBER(mac_w); + + void tx_dma_w(UINT8 data, bool eof); + void rx_dma_r(UINT8 &data, bool &eof); + +protected: + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + virtual void recv_cb(UINT8 *buf, int len); + +private: + enum { TIMER_TX, TIMER_RX }; + + // Lifted from netbsd + enum { + EN_TXS_READY = 0x80, /* ready for packet */ + EN_TXS_BUSY = 0x40, /* receive carrier detect */ + EN_TXS_TXRECV = 0x20, /* transmission received */ + EN_TXS_SHORTED = 0x10, /* possible coax short */ + EN_TXS_UNDERFLOW = 0x08, /* underflow on xmit */ + EN_TXS_COLLERR = 0x04, /* collision detected */ + EN_TXS_COLLERR16 = 0x02, /* 16th collision error */ + EN_TXS_PARERR = 0x01, /* parity error in tx data */ + + EN_RXS_OK = 0x80, /* packet received ok */ + EN_RXS_RESET = 0x10, /* reset packet received */ + EN_RXS_SHORT = 0x08, /* < minimum length */ + EN_RXS_ALIGNERR = 0x04, /* alignment error */ + EN_RXS_CRCERR = 0x02, /* CRC error */ + EN_RXS_OVERFLOW = 0x01, /* receiver FIFO overflow */ + + EN_TMD_COLLMASK = 0xf0, /* collision count */ + EN_TMD_COLLSHIFT = 4, + EN_TMD_PARIGNORE = 0x08, /* ignore parity */ + EN_TMD_TURBO1 = 0x04, + EN_TMD_LB_DISABLE = 0x02, /* loop back disabled */ + EN_TMD_DISCONTENT = 0x01, /* disable contention (rx carrier) */ + + EN_RMD_TEST = 0x80, /* must be zero */ + EN_RMD_ADDRSIZE = 0x10, /* reduces NODE match to 5 chars */ + EN_RMD_SHORTENABLE = 0x08, /* "rx packets >= 10 bytes" - ; + + +/* + * Device + */ + +mb89352_device::mb89352_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + legacy_scsi_host_adapter(mconfig, MB89352A, "MB89352A", tag, owner, clock, "mb89352", __FILE__), + m_irq_cb(*this), + m_drq_cb(*this) +{ +} + +void mb89352_device::device_start() +{ + legacy_scsi_host_adapter::device_start(); + + m_phase = SCSI_PHASE_BUS_FREE; + m_target = 0; + m_command_index = 0; + m_line_status = 0x00; + m_spc_status = 0x01; // presumably the data reg is empty to start with + m_error_status = 0x00; + m_transfer_count = 0; + if(m_transfer_count == 0) + m_spc_status |= SSTS_TC_ZERO; + m_ints = 0x00; + + m_irq_cb.resolve_safe(); + m_drq_cb.resolve_safe(); + + // allocate read timer + m_transfer_timer = timer_alloc(TIMER_TRANSFER); +} + +void mb89352_device::device_reset() +{ + m_phase = SCSI_PHASE_BUS_FREE; + m_target = 0; + m_command_index = 0; + m_line_status = 0x00; + m_error_status = 0x00; + m_transfer_count = 0; + m_spc_status = 0x05; // presumably the data reg is empty to start with + m_busfree_int_enable = 0; +} + +void mb89352_device::device_stop() +{ +} + +// get the length of a SCSI command based on it's command byte type +int mb89352_device::get_scsi_cmd_len(UINT8 cbyte) +{ + int group; + + group = (cbyte>>5) & 7; + + if (group == 0) return 6; + if (group == 1 || group == 2) return 10; + if (group == 5) return 12; + + fatalerror("MB89352: Unknown SCSI command group %d\n", group); + + // never executed + //return 6; +} + +void mb89352_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch(id) + { + case TIMER_TRANSFER: + // TODO: check interrupts are actually enabled + { + m_drq_cb(1); + } + break; + } +} + +void mb89352_device::set_phase(int phase) +{ + m_phase = phase; + switch(phase) + { + case SCSI_PHASE_BUS_FREE: + m_line_status = 0; + m_spc_status &= ~SSTS_XFER_IN_PROGRESS; + break; + case SCSI_PHASE_COMMAND: + m_line_status |= MB89352_LINE_REQ; + m_line_status &= ~MB89352_LINE_ACK; + m_line_status &= ~MB89352_LINE_MSG; + m_line_status |= MB89352_LINE_CD; + m_line_status &= ~MB89352_LINE_IO; + break; + case SCSI_PHASE_STATUS: +// m_line_status |= MB89352_LINE_REQ; +// m_line_status &= ~MB89352_LINE_ACK; + m_line_status &= ~MB89352_LINE_MSG; + m_line_status |= MB89352_LINE_CD; + m_line_status |= MB89352_LINE_IO; + break; + case SCSI_PHASE_DATAIN: +// m_line_status |= MB89352_LINE_REQ; +// m_line_status &= ~MB89352_LINE_ACK; + m_line_status &= ~MB89352_LINE_MSG; + m_line_status &= ~MB89352_LINE_CD; + m_line_status |= MB89352_LINE_IO; + break; + case SCSI_PHASE_DATAOUT: +// m_line_status |= MB89352_LINE_REQ; +// m_line_status &= ~MB89352_LINE_ACK; + m_line_status &= ~MB89352_LINE_MSG; + m_line_status &= ~MB89352_LINE_CD; + m_line_status &= ~MB89352_LINE_IO; + break; + case SCSI_PHASE_MESSAGE_IN: +// m_line_status |= MB89352_LINE_REQ; +// m_line_status &= ~MB89352_LINE_ACK; + m_line_status |= MB89352_LINE_MSG; + m_line_status |= MB89352_LINE_CD; + m_line_status |= MB89352_LINE_IO; + break; + case SCSI_PHASE_MESSAGE_OUT: +// m_line_status |= MB89352_LINE_REQ; +// m_line_status &= ~MB89352_LINE_ACK; + m_line_status |= MB89352_LINE_MSG; + m_line_status |= MB89352_LINE_CD; + m_line_status &= ~MB89352_LINE_IO; + break; + } + logerror("MB89352: phase set to %i\n",m_phase); +} + +READ8_MEMBER( mb89352_device::mb89352_r ) +{ + UINT8 ret; + switch(offset & 0x0f) + { + case 0x00: // BDID - Bus Device ID + return (1 << m_bdid); + case 0x01: // SCTL - SPC Control + ret = 0x00; + if(m_arbit_enable) + ret |= 0x10; + if(m_parity_enable) + ret |= 0x08; + if(m_sel_enable) + ret |= 0x04; + if(m_resel_enable) + ret |= 0x02; + if(m_int_enable) + ret |= 0x01; + return ret; + case 0x02: // SCMD - Command + return m_scmd; + case 0x03: // Unused + return 0xff; + case 0x04: // INTS - Interrupt Sense + return m_ints; + case 0x05: // PSNS - Phase Sense + return m_line_status; // active low -- but Human68k expects it to be zero? + case 0x06: // SSTS - SPC Status + return m_spc_status; + case 0x07: // SERR - SPC Error Status + /* #define SERR_SCSI_PAR 0x80 + #define SERR_SPC_PAR 0x40 + #define SERR_TC_PAR 0x08 + #define SERR_PHASE_ERR 0x04 + #define SERR_SHORT_XFR 0x02 + #define SERR_OFFSET 0x01*/ + return 0; + case 0x08: // PCTL - Phase Control + return ((m_busfree_int_enable) ? (m_line_status & 0x07) | 0x80 : (m_line_status & 0x07)); + case 0x0a: // DREG - Data register (for data transfers) + if(m_spc_status & SSTS_XFER_IN_PROGRESS) + { + m_data = m_buffer[m_transfer_index % 512]; + m_transfer_index++; + m_transfer_count--; + if(m_transfer_index % 512 == 0) + read_data(m_buffer, 512); + if(m_transfer_count == 0) + { + // End of transfer + m_spc_status &= ~SSTS_XFER_IN_PROGRESS; + m_spc_status |= SSTS_DREG_EMPTY; + m_ints |= INTS_COMMAND_COMPLETE; + if(m_int_enable != 0) + m_irq_cb(1); + if(m_phase == SCSI_PHASE_MESSAGE_IN) + set_phase(SCSI_PHASE_BUS_FREE); + else if(m_phase == SCSI_PHASE_DATAIN) + set_phase(SCSI_PHASE_STATUS); + } + } + return m_data; + case 0x0b: // TEMP - Temporary + logerror("mb89352: read temporary register.\n"); + return m_temp; + case 0x0c: // TCH - Transfer Counter High + return (m_transfer_count & 0x00ff0000) >> 16; + case 0x0d: // TCM - Transfer Counter Mid + return (m_transfer_count & 0x0000ff00) >> 8; + case 0x0e: // TCL - Transfer Counter Low + return (m_transfer_count & 0x000000ff); + default: + logerror("mb89352: read from register %02x\n",offset & 0x0f); + } + return 0xff; +} + +WRITE8_MEMBER( mb89352_device::mb89352_w ) +{ + switch(offset & 0x0f) + { + case 0x00: // BDID - Bus Device ID + m_bdid = data; + m_spc_status &= ~SSTS_TARG_CONNECTED; + m_spc_status |= SSTS_INIT_CONNECTED; + logerror("mb89352: BDID set to %i\n",data); + break; + case 0x01: // SCTL - SPC Control + if(data & 0x80) // reset and disable + { + device_reset(); + logerror("mb89352: SCTL: Reset and disable.\n"); + } + if(data & 0x10) + { + m_arbit_enable = 1; + logerror("mb89352: SCTL: Arbitration enabled.\n"); + } + else + m_arbit_enable = 0; + if(data & 0x08) + { + m_parity_enable = 1; + logerror("mb89352: SCTL: Parity enabled.\n"); + } + else + m_parity_enable = 0; + if(data & 0x04) + { + m_sel_enable = 1; + logerror("mb89352: SCTL: Selection enabled.\n"); + } + else + m_sel_enable = 0; + if(data & 0x02) + { + m_resel_enable = 1; + logerror("mb89352: SCTL: Reselection enabled.\n"); + } + else + m_resel_enable = 0; + if(data & 0x01) + { + m_int_enable = 1; + logerror("mb89352: SCTL: Interrupts enabled.\n"); + } + else + { + m_int_enable = 0; + logerror("mb89352: SCTL: Interrupts disabled.\n"); + } + break; + case 0x02: // SCMD - Command + /* From NetBSD/x68k source + #define SCMD_BUS_REL 0x00 + #define SCMD_SELECT 0x20 + #define SCMD_RST_ATN 0x40 + #define SCMD_SET_ATN 0x60 + #define SCMD_XFR 0x80 + #define SCMD_XFR_PAUSE 0xa0 + #define SCMD_RST_ACK 0xc0 + #define SCMD_SET_ACK 0xe0 + */ + m_scmd = data; + switch((data & 0xe0) >> 5) + { + case 0x00: + // Bus Free + m_line_status = 0; + m_spc_status &= ~SSTS_TARG_CONNECTED; + m_spc_status &= ~SSTS_INIT_CONNECTED; + m_spc_status &= ~SSTS_XFER_IN_PROGRESS; + set_phase(SCSI_PHASE_BUS_FREE); + if(m_busfree_int_enable) + { + if(m_int_enable != 0) + m_irq_cb(1); + } + logerror("mb89352: SCMD: Bus free\n"); + break; + case 0x01: + // Selection + m_target = m_temp; + m_target &= ~(1 << m_bdid); // mask off the bit relating to initiator + switch(m_target) + { + case 0x01: m_target = 0; break; + case 0x02: m_target = 1; break; + case 0x04: m_target = 2; break; + case 0x08: m_target = 3; break; + case 0x10: m_target = 4; break; + case 0x20: m_target = 5; break; + case 0x40: m_target = 6; break; + case 0x80: m_target = 7; break; + } + if(m_sel_enable != 0) + { + //m_ints |= INTS_SELECTION; + } + select(m_target); + set_phase(SCSI_PHASE_COMMAND); // straight to command phase, may need a delay between selection and command phases + m_line_status |= MB89352_LINE_SEL; + m_line_status |= MB89352_LINE_BSY; + m_spc_status &= ~SSTS_TARG_CONNECTED; + m_spc_status |= SSTS_INIT_CONNECTED; + m_spc_status |= SSTS_SPC_BSY; + m_ints |= INTS_COMMAND_COMPLETE; + if(m_int_enable != 0) + m_irq_cb(1); + logerror("mb89352: SCMD: Selection (SCSI ID%i)\n",m_target); + break; + case 0x02: // Reset ATN + m_line_status &= ~MB89352_LINE_ATN; + logerror("mb89352: SCMD: Reset ATN\n"); + break; + case 0x03: // Set ATN + m_line_status |= MB89352_LINE_ATN; + logerror("mb89352: SCMD: Set ATN\n"); + break; + case 0x04: // Transfer + m_transfer_index = 0; + m_spc_status |= SSTS_XFER_IN_PROGRESS; + if(m_phase == SCSI_PHASE_DATAIN) // if we are reading data... + { + m_spc_status &= ~SSTS_DREG_EMPTY; // DREG is no longer empty + read_data(m_buffer, 512); + } + if(m_phase == SCSI_PHASE_MESSAGE_IN) + { + m_spc_status &= ~SSTS_DREG_EMPTY; // DREG is no longer empty + m_data = 0; + m_temp = 0x00; + set_phase(SCSI_PHASE_BUS_FREE); + m_spc_status &= ~SSTS_XFER_IN_PROGRESS; + m_command_index = 0; + } + logerror("mb89352: SCMD: Start Transfer\n"); + break; + case 0x05: // Transfer pause + logerror("mb89352: SCMD: Pause Transfer\n"); + break; + case 0x06: // reset REQ/ACK + m_line_status &= ~MB89352_LINE_ACK; + if(m_phase != SCSI_PHASE_BUS_FREE) + { + m_line_status |= MB89352_LINE_REQ; + } + else + { + m_spc_status &= ~SSTS_INIT_CONNECTED; + m_spc_status &= ~SSTS_TARG_CONNECTED; + m_spc_status &= ~SSTS_SPC_BSY; + } + logerror("mb89352: SCMD: Reset REQ/ACK\n"); + break; + case 0x07: // set REQ/ACK + m_line_status &= ~MB89352_LINE_REQ; + m_line_status |= MB89352_LINE_ACK; + logerror("mb89352: SCMD: Set REQ/ACK\n"); + if(m_phase == SCSI_PHASE_COMMAND) + { + m_command[m_command_index++] = m_temp; // temp register puts data onto the SCSI bus + if(m_command_index >= get_scsi_cmd_len(m_command[0])) + { + int x; + int phase; + // execute SCSI command + send_command(m_command, m_command_index); + phase = get_phase(); + if(m_command[0] == 1) // Rezero Unit - not implemented in SCSI code + set_phase(SCSI_PHASE_STATUS); + else + set_phase(phase); + logerror("Command executed: "); + for(x=0;x> 5); + break; + } + break; + case 0x04: // INTS - Interrupt Sense + m_ints &= ~data; // resets relevant status bits to zero + m_irq_cb(0); // clear IRQ + logerror("mb89352: Reset INTS status bits %02x\n",data); + break; + case 0x08: // PCTL - Phase control + if((data & 0x80) == 0 && (m_phase == SCSI_PHASE_SELECT)) // if writing 0 to bit 7, selection phase is reset + { + m_ints &= ~INTS_SELECTION; + m_target = 0; + logerror("mb89352: PCTL selection cancelled\n"); + } + // writing to the low 3 bits sets the phase + if((m_phase & 0x07) != (data & 0x07)) + set_phase(data & 0x07); + m_busfree_int_enable = data & 0x80; + logerror("mb89352: PCTL write %02x\n",data); + break; + case 0x0a: // DREG - Data register + if(m_phase == SCSI_PHASE_COMMAND) + { + m_command[m_command_index++] = data; + if(m_command_index >= get_scsi_cmd_len(m_command[0])) + { + int x; + int phase; + // execute SCSI command + send_command(m_command, m_command_index); + phase = get_phase(); + if(m_command[0] == 1) // Rezero Unit - not implemented in SCSI code + set_phase(SCSI_PHASE_STATUS); + else + set_phase(phase); + logerror("Command executed: "); + for(x=0;x static devcb_base &set_irq_callback(device_t &device, _Object object) { return downcast(device).m_irq_cb.set_callback(object); } + template static devcb_base &set_drq_callback(device_t &device, _Object object) { return downcast(device).m_drq_cb.set_callback(object); } + + // any publically accessible interfaces needed for runtime + DECLARE_READ8_MEMBER( mb89352_r ); + DECLARE_WRITE8_MEMBER( mb89352_w ); + + void set_phase(int phase); + +protected: + // device-level overrides (none are required, but these are common) + virtual void device_start(); + virtual void device_reset(); + virtual void device_stop(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + +private: + // internal device state goes here + static const device_timer_id TIMER_TRANSFER = 0; + + int get_scsi_cmd_len(UINT8 cbyte); + //void set_ints(UINT8 flag); + + devcb_write_line m_irq_cb; /* irq callback */ + devcb_write_line m_drq_cb; /* drq callback */ + + UINT8 m_phase; // current SCSI phase + UINT8 m_target; // current SCSI target + UINT8 m_bdid; // Bus device ID (SCSI ID of the bus?) + UINT8 m_ints; // Interrupt Sense + UINT8 m_temp; // Temporary register (To/From SCSI bus) + UINT8 m_data; // Data register + UINT8 m_scmd; // SPC Command register + UINT32 m_transfer_count; // byte transfer counter, also used as a timeout counter for selection. + UINT8 m_int_enable; + UINT8 m_sel_enable; + UINT8 m_resel_enable; + UINT8 m_parity_enable; + UINT8 m_arbit_enable; + UINT8 m_busfree_int_enable; + UINT8 m_line_status; + UINT8 m_spc_status; + UINT8 m_error_status; + UINT8 m_command_index; + UINT8 m_command[16]; + UINT32 m_transfer_index; + UINT8 m_buffer[512]; + + emu_timer* m_transfer_timer; +}; + +extern const device_type MB89352A; + +#endif /* MB89352_H_ */ diff --git a/src/devices/machine/mb89363b.c b/src/devices/machine/mb89363b.c new file mode 100644 index 00000000000..2e4f210a865 --- /dev/null +++ b/src/devices/machine/mb89363b.c @@ -0,0 +1,181 @@ +// license:BSD-3-Clause +// copyright-holders:David Haywood +/* + (this acts as a trampoline to 2x i8255 chips) + + + Manufacturer: Fujitsu + Part Number: MB89363 / MB89363B / MB89363R + Package: Surface Mount QFP80 / QFP64P (MB89363R) + Description: 8-bit x 3 x 2 (6 x 8-bit) parallel data I/O port VLSI chip + Parallel Communication Interface + Extended I/O + + Note: MB89363B is compatible with 8255 + + Pin Assignment: + +5v + P P P P P P P P P V P P P P P P P P P + N N 5 4 4 4 4 4 4 4 4 C N 1 1 1 1 1 1 1 1 2 N N + C C 3 0 1 2 3 4 5 6 7 C C 7 6 5 4 3 2 1 0 3 C C + + | | ^ ^ ^ ^ ^ ^ ^ ^ ^ | | ^ ^ ^ ^ ^ ^ ^ ^ ^ | | + | | | | | | | | | | | | | | | | | | | | | | | | + | | v v v v v v v v v | | v v v v v v v v v | | + .-------------------------------------------------------. + | 6 6 6 6 6 5 5 5 5 5 5 5 5 5 5 4 4 4 4 4 4 4 4 4 | + | 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 | + P52 <-> | 65 40 | <-> P22 + P51 <-> | 66 39 | <-> P21 + P50 <-> | 67 38 | <-> P20 + P54 <-> | 68 37 | <-> P24 + P55 <-> | 69 36 | <-> P25 + P56 <-> | 70 35 | <-> P26 + P57 <-> | 71 34 | <-> P27 + NC --- | 72 MB89363B 33 | --- NC + NC --- | 73 32 | <-- RSLCT1 + GND --> | 74 31 | <-- RSLCT0 + CS2 --> | 75 30 | <-- GND + R --> | 76 29 | <-- CS1 + P30 <-> | 77 28 | <-> P00 + P31 <-> | 78 27 | <-> P01 + P32 <-> | 79 26 | <-> P02 + P33 <-> | 80 25 | <-> P03 + \ 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 | + \ 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 | + -----------------------------------------------------' + ^ ^ ^ ^ ^ ^ | | ^ | ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ | + | | | | | | | | | | | | | | | | | | | | | | | | + v v v v | | | | | | | v v v v v v v v v v v v | + + P P P P W R N N R N O D D D D D D D D P P P P N + 3 3 3 3 S C C H C U B B B B B B B B 0 0 0 0 C + 4 5 6 7 T / S 0 1 2 3 4 5 6 7 7 6 5 4 + R / + L I + N + S + + Block Diagram / Pin Descriptions: + http://www.mess.org/_media/datasheets/fujitsu/mb89363b_partial.pdf + + D.C. Characteristics: + (Recommended operating conditions unless otherwise noted) + (VCC = +5V +- 10%, GND = 0V, TA = -40o C to 85o C) + Value + Parameter Symbol Min Max Unit Test Condition + ---------------------------------------------------------------------------------- + Input Low Voltage ViL -0.3 0.8 V + Input High Voltage ViH 2.2 VCC +0.3 V + Output Low Voltage VoL - 0.4 V IoL = 2.5mA + Output High Voltage VoH 3.0 - V IoH =-2.5mA + + Sources: + http://www.emb-tech.co.jp/pc104/96dio.pdf + http://www.pb5800.com/resources/2350ser01.pdf + http://www.diagramasde.com/diagramas/otros2/TS-850S%20Service%20Manual%20.pdf +*/ + +#include "emu.h" +#include "machine/mb89363b.h" + + + +extern const device_type MB89363B = &device_creator; + + +mb89363b_device::mb89363b_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, MB89363B, "MB89363 I/O", tag, owner, clock, "mb89363b", __FILE__), + m_i8255_a(*this, "i8255_a"), + m_i8255_b(*this, "i8255_b"), + m_in_a_pa_cb(*this), + m_in_a_pb_cb(*this), + m_in_a_pc_cb(*this), + m_out_a_pa_cb(*this), + m_out_a_pb_cb(*this), + m_out_a_pc_cb(*this), + m_in_b_pa_cb(*this), + m_in_b_pb_cb(*this), + m_in_b_pc_cb(*this), + m_out_b_pa_cb(*this), + m_out_b_pb_cb(*this), + m_out_b_pc_cb(*this) +{ +} + + +READ8_MEMBER(mb89363b_device::i8255_a_port_a_r) { return m_in_a_pa_cb(space, offset); } +READ8_MEMBER(mb89363b_device::i8255_a_port_b_r) { return m_in_a_pb_cb(space, offset); } +READ8_MEMBER(mb89363b_device::i8255_a_port_c_r) { return m_in_a_pc_cb(space, offset); } +WRITE8_MEMBER(mb89363b_device::i8255_a_port_a_w) { m_out_a_pa_cb(space, offset, data); } +WRITE8_MEMBER(mb89363b_device::i8255_a_port_b_w) { m_out_a_pb_cb(space, offset, data); } +WRITE8_MEMBER(mb89363b_device::i8255_a_port_c_w) { m_out_a_pc_cb(space, offset, data); } +READ8_MEMBER(mb89363b_device::i8255_b_port_a_r) { return m_in_b_pa_cb(space, offset); } +READ8_MEMBER(mb89363b_device::i8255_b_port_b_r) { return m_in_b_pb_cb(space, offset); } +READ8_MEMBER(mb89363b_device::i8255_b_port_c_r) { return m_in_b_pc_cb(space, offset); } +WRITE8_MEMBER(mb89363b_device::i8255_b_port_a_w) { m_out_b_pa_cb(space, offset, data); } +WRITE8_MEMBER(mb89363b_device::i8255_b_port_b_w) { m_out_b_pb_cb(space, offset, data); } +WRITE8_MEMBER(mb89363b_device::i8255_b_port_c_w) { m_out_b_pc_cb(space, offset, data); } + + +READ8_MEMBER( mb89363b_device::read ) +{ + if (offset & 4) + return m_i8255_b->read(space, offset & 3); + else + return m_i8255_a->read(space, offset & 3); +} + +WRITE8_MEMBER( mb89363b_device::write ) +{ + if (offset & 4) + m_i8255_b->write(space, offset & 3, data); + else + m_i8255_a->write(space, offset & 3, data); +} + + +static MACHINE_CONFIG_FRAGMENT( mb89363b ) + MCFG_DEVICE_ADD("i8255_a", I8255, 0) + MCFG_I8255_IN_PORTA_CB(READ8(mb89363b_device, i8255_a_port_a_r)) + MCFG_I8255_IN_PORTB_CB(READ8(mb89363b_device, i8255_a_port_b_r)) + MCFG_I8255_IN_PORTC_CB(READ8(mb89363b_device, i8255_a_port_c_r)) + MCFG_I8255_OUT_PORTA_CB(WRITE8(mb89363b_device, i8255_a_port_a_w)) + MCFG_I8255_OUT_PORTB_CB(WRITE8(mb89363b_device, i8255_a_port_b_w)) + MCFG_I8255_OUT_PORTC_CB(WRITE8(mb89363b_device, i8255_a_port_c_w)) + + MCFG_DEVICE_ADD("i8255_b", I8255, 0) + MCFG_I8255_IN_PORTA_CB(READ8(mb89363b_device, i8255_b_port_a_r)) + MCFG_I8255_IN_PORTB_CB(READ8(mb89363b_device, i8255_b_port_b_r)) + MCFG_I8255_IN_PORTC_CB(READ8(mb89363b_device, i8255_b_port_c_r)) + MCFG_I8255_OUT_PORTA_CB(WRITE8(mb89363b_device, i8255_b_port_a_w)) + MCFG_I8255_OUT_PORTB_CB(WRITE8(mb89363b_device, i8255_b_port_b_w)) + MCFG_I8255_OUT_PORTC_CB(WRITE8(mb89363b_device, i8255_b_port_c_w)) +MACHINE_CONFIG_END + +machine_config_constructor mb89363b_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( mb89363b ); +} + +void mb89363b_device::device_start() +{ + m_in_a_pa_cb.resolve_safe(0xff); + m_in_a_pb_cb.resolve_safe(0xff); + m_in_a_pc_cb.resolve_safe(0xff); + m_out_a_pa_cb.resolve_safe(); + m_out_a_pb_cb.resolve_safe(); + m_out_a_pc_cb.resolve_safe(); + + m_in_b_pa_cb.resolve_safe(0xff); + m_in_b_pb_cb.resolve_safe(0xff); + m_in_b_pc_cb.resolve_safe(0xff); + m_out_b_pa_cb.resolve_safe(); + m_out_b_pb_cb.resolve_safe(); + m_out_b_pc_cb.resolve_safe(); + +} + +void mb89363b_device::device_reset() +{ +} diff --git a/src/devices/machine/mb89363b.h b/src/devices/machine/mb89363b.h new file mode 100644 index 00000000000..e29f75fda41 --- /dev/null +++ b/src/devices/machine/mb89363b.h @@ -0,0 +1,134 @@ +// license:BSD-3-Clause +// copyright-holders:David Haywood +/*************************************************************************** + + Fujitsu MB89363 Parallel Communication Interface + (this acts as a trampoline to 2x i8255 chips) + +***************************************************************************/ + +#pragma once + +#ifndef __MB89363B__ +#define __MB89363B__ + + +#include "machine/i8255.h" + + +extern const device_type MB89363B; + +#define MCFG_MB89363B_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, MB89363B, 0) + + + +#define MCFG_MB89363B_IN_PORTA_CB(_devcb) \ + devcb = &mb89363b_device::set_in_a_pa_callback(*device, DEVCB_##_devcb); + +#define MCFG_MB89363B_IN_PORTB_CB(_devcb) \ + devcb = &mb89363b_device::set_in_a_pb_callback(*device, DEVCB_##_devcb); + +#define MCFG_MB89363B_IN_PORTC_CB(_devcb) \ + devcb = &mb89363b_device::set_in_a_pc_callback(*device, DEVCB_##_devcb); + +#define MCFG_MB89363B_OUT_PORTA_CB(_devcb) \ + devcb = &mb89363b_device::set_out_a_pa_callback(*device, DEVCB_##_devcb); + +#define MCFG_MB89363B_OUT_PORTB_CB(_devcb) \ + devcb = &mb89363b_device::set_out_a_pb_callback(*device, DEVCB_##_devcb); + +#define MCFG_MB89363B_OUT_PORTC_CB(_devcb) \ + devcb = &mb89363b_device::set_out_a_pc_callback(*device, DEVCB_##_devcb); + + +#define MCFG_MB89363B_IN_PORTD_CB(_devcb) \ + devcb = &mb89363b_device::set_in_b_pa_callback(*device, DEVCB_##_devcb); + +#define MCFG_MB89363B_IN_PORTE_CB(_devcb) \ + devcb = &mb89363b_device::set_in_b_pb_callback(*device, DEVCB_##_devcb); + +#define MCFG_MB89363B_IN_PORTF_CB(_devcb) \ + devcb = &mb89363b_device::set_in_b_pc_callback(*device, DEVCB_##_devcb); + +#define MCFG_MB89363B_OUT_PORTD_CB(_devcb) \ + devcb = &mb89363b_device::set_out_b_pa_callback(*device, DEVCB_##_devcb); + +#define MCFG_MB89363B_OUT_PORTE_CB(_devcb) \ + devcb = &mb89363b_device::set_out_b_pb_callback(*device, DEVCB_##_devcb); + +#define MCFG_MB89363B_OUT_PORTF_CB(_devcb) \ + devcb = &mb89363b_device::set_out_b_pc_callback(*device, DEVCB_##_devcb); + + + +class mb89363b_device : public device_t +{ +public: + // construction/destruction + mb89363b_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + DECLARE_READ8_MEMBER(read); + DECLARE_WRITE8_MEMBER(write); + + DECLARE_READ8_MEMBER(i8255_a_port_a_r); + DECLARE_READ8_MEMBER(i8255_a_port_b_r); + DECLARE_READ8_MEMBER(i8255_a_port_c_r); + DECLARE_WRITE8_MEMBER(i8255_a_port_a_w); + DECLARE_WRITE8_MEMBER(i8255_a_port_b_w); + DECLARE_WRITE8_MEMBER(i8255_a_port_c_w); + DECLARE_READ8_MEMBER(i8255_b_port_a_r); + DECLARE_READ8_MEMBER(i8255_b_port_b_r); + DECLARE_READ8_MEMBER(i8255_b_port_c_r); + DECLARE_WRITE8_MEMBER(i8255_b_port_a_w); + DECLARE_WRITE8_MEMBER(i8255_b_port_b_w); + DECLARE_WRITE8_MEMBER(i8255_b_port_c_w); + + + template static devcb_base &set_in_a_pa_callback(device_t &device, _Object object) { return downcast(device).m_in_a_pa_cb.set_callback(object); } + template static devcb_base &set_in_a_pb_callback(device_t &device, _Object object) { return downcast(device).m_in_a_pb_cb.set_callback(object); } + template static devcb_base &set_in_a_pc_callback(device_t &device, _Object object) { return downcast(device).m_in_a_pc_cb.set_callback(object); } + template static devcb_base &set_out_a_pa_callback(device_t &device, _Object object) { return downcast(device).m_out_a_pa_cb.set_callback(object); } + template static devcb_base &set_out_a_pb_callback(device_t &device, _Object object) { return downcast(device).m_out_a_pb_cb.set_callback(object); } + template static devcb_base &set_out_a_pc_callback(device_t &device, _Object object) { return downcast(device).m_out_a_pc_cb.set_callback(object); } + + template static devcb_base &set_in_b_pa_callback(device_t &device, _Object object) { return downcast(device).m_in_b_pa_cb.set_callback(object); } + template static devcb_base &set_in_b_pb_callback(device_t &device, _Object object) { return downcast(device).m_in_b_pb_cb.set_callback(object); } + template static devcb_base &set_in_b_pc_callback(device_t &device, _Object object) { return downcast(device).m_in_b_pc_cb.set_callback(object); } + template static devcb_base &set_out_b_pa_callback(device_t &device, _Object object) { return downcast(device).m_out_b_pa_cb.set_callback(object); } + template static devcb_base &set_out_b_pb_callback(device_t &device, _Object object) { return downcast(device).m_out_b_pb_cb.set_callback(object); } + template static devcb_base &set_out_b_pc_callback(device_t &device, _Object object) { return downcast(device).m_out_b_pc_cb.set_callback(object); } + + + required_device m_i8255_a; + required_device m_i8255_b; + +protected: + virtual machine_config_constructor device_mconfig_additions() const; + virtual void device_start(); + virtual void device_reset(); + + + +private: + + devcb_read8 m_in_a_pa_cb; + devcb_read8 m_in_a_pb_cb; + devcb_read8 m_in_a_pc_cb; + + devcb_write8 m_out_a_pa_cb; + devcb_write8 m_out_a_pb_cb; + devcb_write8 m_out_a_pc_cb; + + devcb_read8 m_in_b_pa_cb; + devcb_read8 m_in_b_pb_cb; + devcb_read8 m_in_b_pc_cb; + + devcb_write8 m_out_b_pa_cb; + devcb_write8 m_out_b_pb_cb; + devcb_write8 m_out_b_pc_cb; + + +}; + +#endif diff --git a/src/devices/machine/mb89371.c b/src/devices/machine/mb89371.c new file mode 100644 index 00000000000..1188f295725 --- /dev/null +++ b/src/devices/machine/mb89371.c @@ -0,0 +1,31 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/* + * MB89371 + * + * Fujitsu + * Dual Serial UART + * + */ + +#include "mb89371.h" + +const device_type MB89371 = &device_creator; + +mb89371_device::mb89371_device( const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock ) + : device_t(mconfig, MB89371, "MB89371 Dual Serial UART", tag, owner, clock, "mb89371", __FILE__) +{ +} + +void mb89371_device::device_start() +{ +} + +WRITE8_MEMBER(mb89371_device::write) +{ +} + +READ8_MEMBER(mb89371_device::read) +{ + return 0xff; +} diff --git a/src/devices/machine/mb89371.h b/src/devices/machine/mb89371.h new file mode 100644 index 00000000000..2f0aa11fc4f --- /dev/null +++ b/src/devices/machine/mb89371.h @@ -0,0 +1,35 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/* + * MB89371 + * + * Fujitsu + * Dual Serial UART + * + */ + +#ifndef __MB89371_H__ +#define __MB89371_H__ + +#include "emu.h" + +class mb89371_device : public device_t +{ +public: + // construction/destruction + mb89371_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + DECLARE_WRITE8_MEMBER( write ); + DECLARE_READ8_MEMBER( read ); + +protected: + + // device-level overrides + virtual void device_start(); +}; + + +// device type definition +extern const device_type MB89371; + +#endif diff --git a/src/devices/machine/mc146818.c b/src/devices/machine/mc146818.c new file mode 100644 index 00000000000..6639710cec6 --- /dev/null +++ b/src/devices/machine/mc146818.c @@ -0,0 +1,593 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************* + + mc146818.c + + Implementation of the MC146818 chip + + Real time clock chip with CMOS battery backed ram + Used in IBM PC/AT, several PC clones, Amstrad NC200, Apollo workstations + +*********************************************************************/ + +#include "coreutil.h" +#include "machine/mc146818.h" + + +//************************************************************************** +// DEBUGGING +//************************************************************************** + +#define LOG_MC146818 0 + + + +// device type definition +const device_type MC146818 = &device_creator; + +//------------------------------------------------- +// mc146818_device - constructor +//------------------------------------------------- + +mc146818_device::mc146818_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, MC146818, "MC146818 RTC", tag, owner, clock, "mc146818", __FILE__), + device_nvram_interface(mconfig, *this), + m_index(0), + m_last_refresh(attotime::zero), + m_write_irq(*this), + m_century_index(-1), + m_use_utc(false) +{ +} + +mc146818_device::mc146818_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_nvram_interface(mconfig, *this), + m_index(0), + m_last_refresh(attotime::zero), + m_write_irq(*this), + m_century_index(-1), + m_use_utc(false) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void mc146818_device::device_start() +{ + m_data.resize(data_size()); + m_last_refresh = machine().time(); + m_clock_timer = timer_alloc(TIMER_CLOCK); + m_periodic_timer = timer_alloc(TIMER_PERIODIC); + + m_write_irq.resolve_safe(); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void mc146818_device::device_reset() +{ + m_data[REG_B] &= ~(REG_B_UIE | REG_B_AIE | REG_B_PIE | REG_B_SQWE); + m_data[REG_C] = 0; + + update_irq(); +} + +//------------------------------------------------- +// device_timer - handler timer events +//------------------------------------------------- + +void mc146818_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch (id) + { + case TIMER_PERIODIC: + m_data[REG_C] |= REG_C_PF; + update_irq(); + break; + + case TIMER_CLOCK: + if (!(m_data[REG_B] & REG_B_SET)) + { + /// TODO: find out how the real chip deals with updates when binary/bcd values are already outside the normal range + int seconds = get_seconds() + 1; + if (seconds < 60) + { + set_seconds(seconds); + } + else + { + set_seconds(0); + + int minutes = get_minutes() + 1; + if (minutes < 60) + { + set_minutes(minutes); + } + else + { + set_minutes(0); + + int hours = get_hours() + 1; + if (hours < 24) + { + set_hours(hours); + } + else + { + set_hours(0); + + int dayofweek = get_dayofweek() + 1; + if (dayofweek <= 7) + { + set_dayofweek(dayofweek); + } + else + { + set_dayofweek(1); + } + + int dayofmonth = get_dayofmonth() + 1; + if (dayofmonth <= gregorian_days_in_month(get_month(), get_year() + 2000)) + { + set_dayofmonth(dayofmonth); + } + else + { + set_dayofmonth(1); + + int month = get_month() + 1; + if (month <= 12) + { + set_month(month); + } + else + { + set_month(1); + + set_year((get_year() + 1) % 100); + } + } + } + } + } + + if ((m_data[REG_ALARM_SECONDS] == m_data[REG_SECONDS] || (m_data[REG_ALARM_SECONDS] & ALARM_DONTCARE) == ALARM_DONTCARE) && + (m_data[REG_ALARM_MINUTES] == m_data[REG_MINUTES] || (m_data[REG_ALARM_MINUTES] & ALARM_DONTCARE) == ALARM_DONTCARE) && + (m_data[REG_ALARM_HOURS] == m_data[REG_HOURS] || (m_data[REG_ALARM_HOURS] & ALARM_DONTCARE) == ALARM_DONTCARE)) + { + // set the alarm interrupt flag AF + m_data[REG_C] |= REG_C_AF; + } + + // set the update-ended interrupt Flag UF + m_data[REG_C] |= REG_C_UF; + update_irq(); + + m_last_refresh = machine().time(); + } + break; + } +} + + +//------------------------------------------------- +// nvram_default - called to initialize NVRAM to +// its default state +//------------------------------------------------- + +void mc146818_device::nvram_default() +{ + // populate from a memory region if present + if (m_region != NULL) + { + UINT32 bytes = m_region->bytes(); + + if (bytes > data_size()) + bytes = data_size(); + + memcpy(&m_data[0], m_region->base(), bytes); + } + else + { + memset(&m_data[0], 0, data_size()); + } + + set_base_datetime(); + update_timer(); + update_irq(); +} + + +//------------------------------------------------- +// nvram_read - called to read NVRAM from the +// .nv file +//------------------------------------------------- + +void mc146818_device::nvram_read(emu_file &file) +{ + file.read(&m_data[0], data_size()); + + set_base_datetime(); + update_timer(); + update_irq(); +} + + +//------------------------------------------------- +// nvram_write - called to write NVRAM to the +// .nv file +//------------------------------------------------- + +void mc146818_device::nvram_write(emu_file &file) +{ + file.write(&m_data[0], data_size()); +} + + +//------------------------------------------------- +// to_ram - convert value to current ram format +//------------------------------------------------- + +int mc146818_device::to_ram(int a) +{ + if (!(m_data[REG_B] & REG_B_DM)) + return dec_2_bcd(a); + + return a; +} + + +//------------------------------------------------- +// from_ram - convert value from current ram format +//------------------------------------------------- + +int mc146818_device::from_ram(int a) +{ + if (!(m_data[REG_B] & REG_B_DM)) + return bcd_2_dec(a); + + return a; +} + + +int mc146818_device::get_seconds() +{ + return from_ram(m_data[REG_SECONDS]); +} + +void mc146818_device::set_seconds(int seconds) +{ + m_data[REG_SECONDS] = to_ram(seconds); +} + +int mc146818_device::get_minutes() +{ + return from_ram(m_data[REG_MINUTES]); +} + +void mc146818_device::set_minutes(int minutes) +{ + m_data[REG_MINUTES] = to_ram(minutes); +} + +int mc146818_device::get_hours() +{ + if (!(m_data[REG_B] & REG_B_24_12)) + { + int hours = from_ram(m_data[REG_HOURS] & ~HOURS_PM); + + if (hours == 12) + { + hours = 0; + } + + if (m_data[REG_HOURS] & HOURS_PM) + { + hours += 12; + } + + return hours; + } + else + { + return from_ram(m_data[REG_HOURS]); + } +} + +void mc146818_device::set_hours(int hours) +{ + if (!(m_data[REG_B] & REG_B_24_12)) + { + int pm = 0; + + if (hours >= 12) + { + hours -= 12; + pm = HOURS_PM; + } + + if (hours == 0) + { + hours = 12; + } + + m_data[REG_HOURS] = to_ram(hours) | pm; + } + else + { + m_data[REG_HOURS] = to_ram(hours); + } +} + +int mc146818_device::get_dayofweek() +{ + return from_ram(m_data[REG_DAYOFWEEK]); +} + +void mc146818_device::set_dayofweek(int dayofweek) +{ + m_data[REG_DAYOFWEEK] = to_ram(dayofweek); +} + +int mc146818_device::get_dayofmonth() +{ + return from_ram(m_data[REG_DAYOFMONTH]); +} + +void mc146818_device::set_dayofmonth(int dayofmonth) +{ + m_data[REG_DAYOFMONTH] = to_ram(dayofmonth); +} + +int mc146818_device::get_month() +{ + return from_ram(m_data[REG_MONTH]); +} + +void mc146818_device::set_month(int month) +{ + m_data[REG_MONTH] = to_ram(month); +} + +int mc146818_device::get_year() +{ + return from_ram(m_data[REG_YEAR]); +} + +void mc146818_device::set_year(int year) +{ + m_data[REG_YEAR] = to_ram(year); +} + + + +//------------------------------------------------- +// set_base_datetime - update clock with real time +//------------------------------------------------- + +void mc146818_device::set_base_datetime() +{ + system_time systime; + system_time::full_time current_time; + + machine().base_datetime(systime); + + current_time = (m_use_utc) ? systime.utc_time: systime.local_time; + +// logerror("mc146818_set_base_datetime %02d/%02d/%02d %02d:%02d:%02d\n", +// current_time.year % 100, current_time.month + 1, current_time.mday, +// current_time.hour,current_time.minute, current_time.second); + + set_seconds(current_time.second); + set_minutes(current_time.minute); + set_hours(current_time.hour); + set_dayofweek(current_time.weekday + 1); + set_dayofmonth(current_time.mday); + set_month(current_time.month + 1); + set_year(current_time.year % 100); + + if (m_century_index >= 0) + m_data[m_century_index] = to_ram(current_time.year / 100); +} + + +//------------------------------------------------- +// update_timer - update timer based on A register +//------------------------------------------------- + +void mc146818_device::update_timer() +{ + int bypass; + + switch (m_data[REG_A] & (REG_A_DV2 | REG_A_DV1 | REG_A_DV0)) + { + case 0: + bypass = 0; + break; + + case REG_A_DV0: + bypass = 2; + break; + + case REG_A_DV1: + bypass = 7; + break; + + case REG_A_DV2 | REG_A_DV1: + case REG_A_DV2 | REG_A_DV1 | REG_A_DV0: + bypass = 22; + break; + + default: + // TODO: other combinations of divider bits are used for test purposes only + bypass = 22; + break; + } + + + attotime update_period = attotime::never; + attotime update_interval = attotime::never; + attotime periodic_period = attotime::never; + attotime periodic_interval = attotime::never; + + if (bypass < 22) + { + int shift = 22 - bypass; + + double update_hz = (double) clock() / (1 << shift); + + // TODO: take the time since last timer into account + update_period = attotime::from_hz(update_hz * 2); + update_interval = attotime::from_hz(update_hz); + + int rate_select = m_data[REG_A] & (REG_A_RS3 | REG_A_RS2 | REG_A_RS1 | REG_A_RS0); + if (rate_select != 0) + { + shift = (rate_select + 6) - bypass; + if (shift <= 1) + shift += 7; + + double periodic_hz = (double) clock() / (1 << shift); + + // TODO: take the time since last timer into account + periodic_period = attotime::from_hz(periodic_hz * 2); + periodic_interval = attotime::from_hz(periodic_hz); + } + } + + m_clock_timer->adjust(update_period, 0, update_interval); + m_periodic_timer->adjust(periodic_period, 0, periodic_interval); +} + + +//------------------------------------------------- +// update_irq - Update irq based on B & C register +//------------------------------------------------- + +void mc146818_device::update_irq() +{ + // IRQ line is active low + if (((m_data[REG_C] & REG_C_UF) && (m_data[REG_B] & REG_B_UIE)) || + ((m_data[REG_C] & REG_C_AF) && (m_data[REG_B] & REG_B_AIE)) || + ((m_data[REG_C] & REG_C_PF) && (m_data[REG_B] & REG_B_PIE))) + { + m_data[REG_C] |= REG_C_IRQF; + m_write_irq(CLEAR_LINE); + } + else + { + m_data[REG_C] &= REG_C_IRQF; + m_write_irq(ASSERT_LINE); + } +} + + + +//------------------------------------------------- +// read - I/O handler for reading +//------------------------------------------------- + +READ8_MEMBER( mc146818_device::read ) +{ + UINT8 data = 0; + switch (offset) + { + case 0: + data = m_index; + break; + + case 1: + switch (m_index) + { + case REG_A: + data = m_data[REG_A]; + // Update In Progress (UIP) time for 32768 Hz is 244+1984usec + /// TODO: support other dividers + /// TODO: don't set this if update is stopped + if ((space.machine().time() - m_last_refresh) < attotime::from_usec(244+1984)) + data |= REG_A_UIP; + break; + + case REG_C: + // the unused bits b0 ... b3 are always read as 0 + data = m_data[REG_C] & (REG_C_IRQF | REG_C_PF | REG_C_AF | REG_C_UF); + // read 0x0c will clear all IRQ flags in register 0x0c + m_data[REG_C] &= ~(REG_C_IRQF | REG_C_PF | REG_C_AF | REG_C_UF); + update_irq(); + break; + + case REG_D: + /* battery ok */ + data = m_data[REG_D] | REG_D_VRT; + break; + + default: + data = m_data[m_index]; + break; + } + break; + } + + if (LOG_MC146818) + logerror("mc146818_port_r(): index=0x%02x data=0x%02x\n", m_index, data); + + return data; +} + + +//------------------------------------------------- +// write - I/O handler for writing +//------------------------------------------------- + +WRITE8_MEMBER( mc146818_device::write ) +{ + if (LOG_MC146818) + logerror("mc146818_port_w(): index=0x%02x data=0x%02x\n", m_index, data); + + switch (offset) + { + case 0: + m_index = data % data_size(); + break; + + case 1: + switch (m_index) + { + case REG_SECONDS: + // top bit of SECONDS is read only + m_data[REG_SECONDS] = data & ~0x80; + break; + + case REG_A: + // top bit of A is read only + m_data[REG_A] = data & ~REG_A_UIP; + update_timer(); + break; + + case REG_B: + if ((data & REG_B_SET) && !(m_data[REG_B] & REG_B_SET)) + data &= ~REG_B_UIE; + + m_data[REG_B] = data; + update_irq(); + break; + + case REG_C: + case REG_D: + // register C & D is readonly + break; + + default: + m_data[m_index] = data; + break; + } + break; + } +} diff --git a/src/devices/machine/mc146818.h b/src/devices/machine/mc146818.h new file mode 100644 index 00000000000..3db19ec533e --- /dev/null +++ b/src/devices/machine/mc146818.h @@ -0,0 +1,177 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************* + + mc146818.h + + Implementation of the MC146818 chip + + Real time clock chip with CMOS battery backed ram + Used in IBM PC/AT, several PC clones, Amstrad NC200, Apollo workstations + +*********************************************************************/ + +#ifndef __MC146818_H__ +#define __MC146818_H__ + +#include "emu.h" + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_MC146818_ADD(_tag, _xtal) \ + MCFG_DEVICE_ADD(_tag, MC146818, _xtal) + +#define MCFG_MC146818_IRQ_HANDLER(_irq) \ + downcast(device)->set_irq_callback(DEVCB_##_irq); + +// The MC146818 doesn't have century support, but when syncing the date & time at startup we can optionally store the century. +#define MCFG_MC146818_CENTURY_INDEX(_century_index) \ + downcast(device)->set_century_index(_century_index); + +// The MC146818 doesn't have UTC support, but when syncing the data & time at startup we can use UTC instead of local time. +#define MCFG_MC146818_UTC(_utc) \ + downcast(device)->set_use_utc(_utc); + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> mc146818_device + +class mc146818_device : public device_t, + public device_nvram_interface +{ +public: + // construction/destruction + mc146818_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + mc146818_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + // callbacks + template void set_irq_callback(_irq irq) { m_write_irq.set_callback(irq); } + void set_century_index(int century_index) { m_century_index = century_index; } + void set_use_utc(bool use_utc) { m_use_utc = use_utc; } + + // read/write access + DECLARE_READ8_MEMBER( read ); + DECLARE_WRITE8_MEMBER( write ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + // device_nvram_interface overrides + virtual void nvram_default(); + virtual void nvram_read(emu_file &file); + virtual void nvram_write(emu_file &file); + + static const unsigned char ALARM_DONTCARE = 0xc0; + static const unsigned char HOURS_PM = 0x80; + + virtual int data_size() { return 64; } + +private: + enum + { + REG_SECONDS = 0, + REG_ALARM_SECONDS = 1, + REG_MINUTES = 2, + REG_ALARM_MINUTES = 3, + REG_HOURS = 4, + REG_ALARM_HOURS = 5, + REG_DAYOFWEEK = 6, + REG_DAYOFMONTH = 7, + REG_MONTH = 8, + REG_YEAR = 9, + REG_A = 0xa, + REG_B = 0xb, + REG_C = 0xc, + REG_D = 0xd + }; + + enum + { + REG_A_RS0 = 1, + REG_A_RS1 = 2, + REG_A_RS2 = 4, + REG_A_RS3 = 8, + REG_A_DV0 = 16, + REG_A_DV1 = 32, + REG_A_DV2 = 64, + REG_A_UIP = 128 + }; + + enum + { + REG_B_DSE = 1, // TODO: When set the chip will adjust the clock by an hour at start and end of DST + REG_B_24_12 = 2, + REG_B_DM = 4, + REG_B_SQWE = 8, // TODO: When set the chip will output a square wave on SQW pin + REG_B_UIE = 16, + REG_B_AIE = 32, + REG_B_PIE = 64, + REG_B_SET = 128 + }; + + enum + { + REG_C_UF = 16, + REG_C_AF = 32, + REG_C_PF = 64, + REG_C_IRQF = 128 + }; + + enum + { + REG_D_VRT = 128 + }; + + // internal helpers + int to_ram(int a); + int from_ram(int a); + void set_base_datetime(); + void update_irq(); + void update_timer(); + + int get_seconds(); + void set_seconds(int seconds); + int get_minutes(); + void set_minutes(int minutes); + int get_hours(); + void set_hours(int hours); + int get_dayofweek(); + void set_dayofweek(int dayofweek); + int get_dayofmonth(); + void set_dayofmonth(int dayofmonth); + int get_month(); + void set_month(int month); + int get_year(); + void set_year(int year); + + // internal state + + UINT8 m_index; + dynamic_buffer m_data; + + attotime m_last_refresh; + + static const device_timer_id TIMER_CLOCK = 0; + static const device_timer_id TIMER_PERIODIC = 1; + + emu_timer *m_clock_timer; + emu_timer *m_periodic_timer; + + devcb_write_line m_write_irq; + int m_century_index; + bool m_use_utc; +}; + + +// device type definition +extern const device_type MC146818; + + +#endif /* __MC146818_H__ */ diff --git a/src/devices/machine/mc2661.c b/src/devices/machine/mc2661.c new file mode 100644 index 00000000000..f93dc1b5ab1 --- /dev/null +++ b/src/devices/machine/mc2661.c @@ -0,0 +1,499 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/*************************************************************************** + + Motorola MC2661/MC68661 Enhanced Programmable Communications Interface + +***************************************************************************/ + +#include "mc2661.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type MC2661 = &device_creator; + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define LOG 0 + + +UINT32 baud_rates[16] = +{ + 50, 75, 110, 135 /*134.5*/, 150, 300, 600, 1200, 1800, 2000, 2400, 3600, 4800, 7200, 9600, 19200 +}; + +enum +{ + REGISTER_HOLDING = 0, + REGISTER_STATUS, + REGISTER_SYNC = REGISTER_STATUS, + REGISTER_MODE, + REGISTER_COMMAND +}; + + +#define MODE_BAUD_RATE (m_mr[0] & 0x03) +#define MODE_CHARACTER ((m_mr[0] >> 2) & 0x03) +#define MODE_PARITY BIT(m_mr[0], 4) +#define MODE_PARITY_EVEN BIT(m_mr[0], 5) +#define MODE_TRANSPARENT BIT(m_mr[0], 6) +#define MODE_SINGLE_SYN BIT(m_mr[0], 7) +#define MODE_STOP_BITS ((m_mr[0] >> 6) & 0x03) + + +#define SYN1 m_sync[0] +#define SYN2 m_sync[1] +#define DLE m_sync[2] + + +#define COMMAND_TXEN BIT(m_cr, 0) +#define COMMAND_DTR BIT(m_cr, 1) +#define COMMAND_RXEN BIT(m_cr, 2) +#define COMMAND_BREAK BIT(m_cr, 3) +#define COMMAND_DLE BIT(m_cr, 3) +#define COMMAND_RESET BIT(m_cr, 4) +#define COMMAND_RTS BIT(m_cr, 5) +#define COMMAND_MODE (m_cr >> 6) + + +enum +{ + MODE_NORMAL = 0, + MODE_ASYNC, + MODE_LOCAL_LOOP_BACK, + MODE_REMOTE_LOOP_BACK +}; + + +#define STATUS_TXRDY 0x01 +#define STATUS_RXRDY 0x02 +#define STATUS_TXEMT 0x04 +#define STATUS_PE 0x08 +#define STATUS_DLE 0x08 +#define STATUS_OVERRUN 0x10 +#define STATUS_FE 0x20 +#define STATUS_SYN 0x20 +#define STATUS_DCD 0x40 +#define STATUS_DSR 0x80 + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// mc2661_device - constructor +//------------------------------------------------- + +mc2661_device::mc2661_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, MC2661, "MC2661", tag, owner, clock, "mc2661", __FILE__), + device_serial_interface(mconfig, *this), + m_write_txd(*this), + m_write_rxrdy(*this), + m_write_txrdy(*this), + m_write_rts(*this), + m_write_dtr(*this), + m_write_txemt_dschg(*this), + m_write_bkdet(*this), + m_write_xsync(*this), + m_rxc(0), + m_txc(0), + m_sr(0) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void mc2661_device::device_start() +{ + // resolve callbacks + m_write_txd.resolve_safe(); + m_write_rxrdy.resolve_safe(); + m_write_txrdy.resolve_safe(); + m_write_rts.resolve_safe(); + m_write_dtr.resolve_safe(); + m_write_txemt_dschg.resolve_safe(); + m_write_bkdet.resolve_safe(); + m_write_xsync.resolve_safe(); + + // create the timers + if (m_rxc > 0) + { + set_rcv_rate(m_rxc); + } + + if (m_txc > 0) + { + set_tra_rate(m_txc); + } + + // save state + save_item(NAME(m_rhr)); + save_item(NAME(m_thr)); + save_item(NAME(m_cr)); + save_item(NAME(m_sr)); + save_item(NAME(m_mr)); + save_item(NAME(m_sync)); + save_item(NAME(m_mode_index)); + save_item(NAME(m_sync_index)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void mc2661_device::device_reset() +{ + receive_register_reset(); + transmit_register_reset(); + + m_mr[0] = m_mr[1] = 0; + m_sync[0] = m_sync[1] = m_sync[2] = 0; + m_cr = 0; + m_sr = 0; + + m_mode_index = 0; + m_sync_index = 0; + + m_write_txd(1); + m_write_rxrdy(CLEAR_LINE); + m_write_txrdy(CLEAR_LINE); + m_write_rts(1); + m_write_dtr(1); + m_write_txemt_dschg(CLEAR_LINE); + m_write_bkdet(0); + m_write_xsync(0); +} + + +//------------------------------------------------- +// tra_callback - +//------------------------------------------------- + +void mc2661_device::tra_callback() +{ + m_write_txd(transmit_register_get_data_bit()); +} + + +//------------------------------------------------- +// tra_complete - +//------------------------------------------------- + +void mc2661_device::tra_complete() +{ + // TODO + m_sr |= STATUS_TXRDY; + m_write_txrdy(ASSERT_LINE); +} + + +//------------------------------------------------- +// rcv_complete - +//------------------------------------------------- + +void mc2661_device::rcv_complete() +{ + // TODO + receive_register_extract(); + m_rhr = get_received_char(); + m_sr |= STATUS_RXRDY; + m_write_rxrdy(ASSERT_LINE); +} + + +//------------------------------------------------- +// read - register read +//------------------------------------------------- + +READ8_MEMBER( mc2661_device::read ) +{ + UINT8 data = 0; + + switch (offset & 0x03) + { + case REGISTER_HOLDING: + data = m_rhr; + m_sr &= ~STATUS_RXRDY; + m_write_rxrdy(CLEAR_LINE); + break; + + case REGISTER_STATUS: + data = m_sr; + break; + + case REGISTER_MODE: + data = m_mr[m_mode_index]; + + m_mode_index++; + m_mode_index &= 0x01; + + break; + + case REGISTER_COMMAND: + m_mode_index = 0; + m_sync_index = 0; + + data = m_cr; + break; + } + + return data; +} + + +//------------------------------------------------- +// write - register write +//------------------------------------------------- + +WRITE8_MEMBER( mc2661_device::write ) +{ + switch (offset & 0x03) + { + case REGISTER_HOLDING: + if (LOG) logerror("MC2661 '%s' Transmit Holding Register: %02x\n", tag(), data); + + m_thr = data; + if(COMMAND_TXEN) + { + if(COMMAND_MODE != 0x02) + transmit_register_setup(m_thr); + m_sr &= ~STATUS_TXRDY; + m_write_txrdy(CLEAR_LINE); + } + if(COMMAND_MODE == 0x02) // loopback - the Wicat will set this after enabling the transmitter + { + m_rhr = data; + m_sr |= STATUS_RXRDY; // pcd expects this + m_write_rxrdy(ASSERT_LINE); + } + break; + + case REGISTER_SYNC: + if (LOG) logerror("MC2661 '%s' Sync Register %u: %02x\n", tag(), m_sync_index + 1, data); + + m_sync[m_sync_index] = data; + + m_sync_index++; + if (m_sync_index == 3) m_sync_index = 0; + break; + + case REGISTER_MODE: + if (LOG) logerror("MC2661 '%s' Mode Register %u: %02x\n", tag(), m_mode_index + 1, data); + + m_mr[m_mode_index] = data; + + if (m_mode_index == 0) + { + int data_bit_count = 5 + MODE_CHARACTER; + parity_t parity; + + if (!MODE_PARITY) parity = PARITY_NONE; + else if (MODE_PARITY_EVEN) parity = PARITY_EVEN; + else parity = PARITY_ODD; + + stop_bits_t stop_bits; + + switch (MODE_STOP_BITS) + { + case 0: + default: + stop_bits = STOP_BITS_0; + break; + + case 1: + stop_bits = STOP_BITS_1; + break; + + case 2: + stop_bits = STOP_BITS_1_5; + break; + + case 3: + stop_bits = STOP_BITS_2; + break; + } + + set_data_frame(1, data_bit_count, parity, stop_bits); + } + if(m_mode_index == 1) + { + UINT32 rx_baud = baud_rates[data & 0x0f]; + UINT32 tx_baud = baud_rates[data & 0x0f]; + if(data & 0x10) // internal receiver clock + { +// if((m_mr[0] & 0x03) != 0) +// rx_baud *= 16; + } + else // external receiver clock + { + switch(m_mr[0] & 0x03) + { + case 0x02: + rx_baud *= 16; + break; + case 0x03: + rx_baud *= 64; + break; + default: + // x1 + break; + } + } + if(data & 0x20) // internal transmitter clock + { +// if((m_mr[0] & 0x03) != 0) +// tx_baud *= 16; + } + else // external transmitter clock + { + switch(m_mr[0] & 0x03) + { + case 0x02: + tx_baud *= 16; + break; + case 0x03: + tx_baud *= 64; + break; + default: + // x1 + break; + } + } + + set_rcv_rate(rx_baud); + set_tra_rate(tx_baud); + } + + m_mode_index++; + m_mode_index &= 0x01; + break; + + case REGISTER_COMMAND: + if (LOG) logerror("MC2661 '%s' Command Register: %02x\n", tag(), data); + + m_cr = data & 0xef; + + m_write_dtr(!COMMAND_DTR); + m_write_rts(!COMMAND_RTS); + + if (COMMAND_MODE == 0x02) // local loopback + { + if(COMMAND_DTR && COMMAND_RTS) // CR1 and CR5 must be set to 1 to use local loopback + { + // probably much more to it that this, but this is enough for the Wicat to be happy + m_rhr = m_thr; + m_sr |= STATUS_RXRDY; + m_write_rxrdy(ASSERT_LINE); + return; + } + } + + if (COMMAND_TXEN) + { + m_sr |= STATUS_TXRDY; + m_write_txrdy(ASSERT_LINE); + } + else + { + m_sr &= ~STATUS_TXRDY; + m_write_txrdy(CLEAR_LINE); + } + if (!COMMAND_RXEN) + { + m_sr &= ~STATUS_RXRDY; + m_write_rxrdy(CLEAR_LINE); + } + if (COMMAND_RESET) + { + m_sr &= ~(STATUS_FE | STATUS_OVERRUN | STATUS_PE); + } + break; + } +} + +//------------------------------------------------- +// dsr_w - data set ready +//------------------------------------------------- + +WRITE_LINE_MEMBER( mc2661_device::dsr_w ) +{ + if (LOG) logerror("MC2661 '%s' Data Set Ready: %u\n", tag(), state); + + if (state) + { + m_sr &= ~STATUS_DSR; + } + else + { + m_sr |= STATUS_DSR; + } +} + + +//------------------------------------------------- +// dcd_w - data carrier detect +//------------------------------------------------- + +WRITE_LINE_MEMBER( mc2661_device::dcd_w ) +{ + if (LOG) logerror("MC2661 '%s' Data Carrier Detect: %u\n", tag(), state); + + if (state) + { + m_sr &= ~STATUS_DCD; + } + else + { + m_sr |= STATUS_DCD; + } +} + + +//------------------------------------------------- +// cts_w - clear to send +//------------------------------------------------- + +WRITE_LINE_MEMBER( mc2661_device::cts_w ) +{ + if (LOG) logerror("MC2661 '%s' Clear to Send: %u\n", tag(), state); +} + + +//------------------------------------------------- +// rxrdy_r - receiver ready +//------------------------------------------------- + +READ_LINE_MEMBER( mc2661_device::rxrdy_r ) +{ + return (m_sr & STATUS_RXRDY) ? ASSERT_LINE : CLEAR_LINE; +} + + +//------------------------------------------------- +// txemt_r - transmitter empty +//------------------------------------------------- + +READ_LINE_MEMBER( mc2661_device::txemt_r ) +{ + return (m_sr & STATUS_TXEMT) ? ASSERT_LINE : CLEAR_LINE; +} + + +void mc2661_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + device_serial_interface::device_timer(timer, id, param, ptr); +} diff --git a/src/devices/machine/mc2661.h b/src/devices/machine/mc2661.h new file mode 100644 index 00000000000..5cc2f3e27fc --- /dev/null +++ b/src/devices/machine/mc2661.h @@ -0,0 +1,149 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/*************************************************************************** + + Motorola MC2661/MC68661 Enhanced Programmable Communications Interface + +**************************************************************************** + _____ _____ + D2 1 |* \_/ | 28 D1 + D3 2 | | 27 D0 + RxD 3 | | 26 Vcc + GND 4 | | 25 _RxC/BKDET + D4 5 | | 24 _DTR + D5 6 | | 23 _RTS + D6 7 | MC2661 | 22 _DSR + D7 8 | MC68661 | 21 RESET + _TxC/XSYNC 9 | | 20 BRCLK + A1 10 | | 19 TxD + _CE 11 | | 18 _TxEMT/DSCHG + A0 12 | | 17 _CTS + _R/W 13 | | 16 _DCD + _RxRDY 14 |_____________| 15 _TxRDY + +***************************************************************************/ + +#pragma once + +#ifndef __MC2661__ +#define __MC2661__ + +#include "emu.h" + + + +/*************************************************************************** + DEVICE CONFIGURATION MACROS +***************************************************************************/ + +#define MCFG_MC2661_RXC(_clock) \ + mc2661_device::static_set_rxc(*device, _clock); + +#define MCFG_MC2661_TXC(_clock) \ + mc2661_device::static_set_txc(*device, _clock); + +#define MCFG_MC2661_TXD_HANDLER(_write) \ + devcb = &mc2661_device::set_txd_callback(*device, DEVCB_##_write); + +#define MCFG_MC2661_RXRDY_HANDLER(_write) \ + devcb = &mc2661_device::set_rxrdy_callback(*device, DEVCB_##_write); + +#define MCFG_MC2661_TXRDY_HANDLER(_write) \ + devcb = &mc2661_device::set_txrdy_callback(*device, DEVCB_##_write); + +#define MCFG_MC2661_RTS_HANDLER(_write) \ + devcb = &mc2661_device::set_rts_callback(*device, DEVCB_##_write); + +#define MCFG_MC2661_DTR_HANDLER(_write) \ + devcb = &mc2661_device::set_dtr_callback(*device, DEVCB_##_write); + +#define MCFG_MC2661_TXEMT_DSCHG_HANDLER(_write) \ + devcb = &mc2661_device::set_txemt_dschg_callback(*device, DEVCB_##_write); + +#define MCFG_MC2661_BKDET_HANDLER(_write) \ + devcb = &mc2661_device::set_bkdet_callback(*device, DEVCB_##_write); + +#define MCFG_MC2661_XSYNC_HANDLER(_write) \ + devcb = &mc2661_device::set_xsync_callback(*device, DEVCB_##_write); + + + +/*************************************************************************** + TYPE DEFINITIONS +***************************************************************************/ + +// ======================> mc2661_device + +class mc2661_device : public device_t, + public device_serial_interface +{ +public: + // construction/destruction + mc2661_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + static void static_set_rxc(device_t &device, int clock) { downcast(device).m_rxc = clock; } + static void static_set_txc(device_t &device, int clock) { downcast(device).m_txc = clock; } + + template static devcb_base &set_txd_callback(device_t &device, _Object object) { return downcast(device).m_write_txd.set_callback(object); } + template static devcb_base &set_rxrdy_callback(device_t &device, _Object object) { return downcast(device).m_write_rxrdy.set_callback(object); } + template static devcb_base &set_txrdy_callback(device_t &device, _Object object) { return downcast(device).m_write_txrdy.set_callback(object); } + template static devcb_base &set_rts_callback(device_t &device, _Object object) { return downcast(device).m_write_rts.set_callback(object); } + template static devcb_base &set_dtr_callback(device_t &device, _Object object) { return downcast(device).m_write_dtr.set_callback(object); } + template static devcb_base &set_txemt_dschg_callback(device_t &device, _Object object) { return downcast(device).m_write_txemt_dschg.set_callback(object); } + template static devcb_base &set_bkdet_callback(device_t &device, _Object object) { return downcast(device).m_write_bkdet.set_callback(object); } + template static devcb_base &set_xsync_callback(device_t &device, _Object object) { return downcast(device).m_write_xsync.set_callback(object); } + + DECLARE_READ8_MEMBER( read ); + DECLARE_WRITE8_MEMBER( write ); + + DECLARE_WRITE_LINE_MEMBER( dsr_w ); + DECLARE_WRITE_LINE_MEMBER( dcd_w ); + DECLARE_WRITE_LINE_MEMBER( cts_w ); + + DECLARE_READ_LINE_MEMBER( rxrdy_r ); + DECLARE_READ_LINE_MEMBER( txemt_r ); + + DECLARE_WRITE_LINE_MEMBER( rx_w ) { device_serial_interface::rx_w(state); } + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + // device_serial_interface overrides + virtual void tra_callback(); + virtual void tra_complete(); + virtual void rcv_complete(); + +private: + devcb_write_line m_write_txd; + devcb_write_line m_write_rxrdy; + devcb_write_line m_write_txrdy; + devcb_write_line m_write_rts; + devcb_write_line m_write_dtr; + devcb_write_line m_write_txemt_dschg; + devcb_write_line m_write_bkdet; + devcb_write_line m_write_xsync; + + int m_rxc; + int m_txc; + + UINT8 m_rhr; + UINT8 m_thr; + UINT8 m_cr; + UINT8 m_sr; + UINT8 m_mr[2]; + UINT8 m_sync[3]; + + int m_mode_index; + int m_sync_index; +}; + + +// device type definition +extern const device_type MC2661; + + + +#endif diff --git a/src/devices/machine/mc68328.c b/src/devices/machine/mc68328.c new file mode 100644 index 00000000000..c97e0aea815 --- /dev/null +++ b/src/devices/machine/mc68328.c @@ -0,0 +1,2871 @@ +// license:BSD-3-Clause +// copyright-holders:Ryan Holtz +/********************************************************************** + + Motorola 68328 ("DragonBall") System-on-a-Chip implementation + + By MooglyGuy + contact mooglyguy@gmail.com with licensing and usage questions. + +**********************************************************************/ + +#include "emu.h" +#include "cpu/m68000/m68000.h" +#include "machine/mc68328.h" +#include "machine/ram.h" + +#define VERBOSE_LEVEL (0) + +INLINE void ATTR_PRINTF(3,4) verboselog(running_machine &machine, int n_level, const char *s_fmt, ...) +{ + if (VERBOSE_LEVEL >= n_level) + { + va_list v; + char buf[32768]; + va_start(v, s_fmt); + vsprintf(buf, s_fmt, v); + va_end(v); + logerror("%s: %s", machine.describe_context(), buf); + } +} + +const device_type MC68328 = &device_creator; + + +mc68328_device::mc68328_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, MC68328, "MC68328 (DragonBall) Integrated Processor", tag, owner, clock, "mc68328", __FILE__), + m_out_port_a_cb(*this), + m_out_port_b_cb(*this), + m_out_port_c_cb(*this), + m_out_port_d_cb(*this), + m_out_port_e_cb(*this), + m_out_port_f_cb(*this), + m_out_port_g_cb(*this), + m_out_port_j_cb(*this), + m_out_port_k_cb(*this), + m_out_port_m_cb(*this), + m_in_port_a_cb(*this), + m_in_port_b_cb(*this), + m_in_port_c_cb(*this), + m_in_port_d_cb(*this), + m_in_port_e_cb(*this), + m_in_port_f_cb(*this), + m_in_port_g_cb(*this), + m_in_port_j_cb(*this), + m_in_port_k_cb(*this), + m_in_port_m_cb(*this), + m_out_pwm_cb(*this), + m_out_spim_cb(*this), + m_in_spim_cb(*this), + m_spim_xch_trigger_cb(*this), + m_cpu(*this) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void mc68328_device::device_start() +{ + m_out_port_a_cb.resolve(); + m_out_port_b_cb.resolve(); + m_out_port_c_cb.resolve(); + m_out_port_d_cb.resolve(); + m_out_port_e_cb.resolve(); + m_out_port_f_cb.resolve(); + m_out_port_g_cb.resolve(); + m_out_port_j_cb.resolve(); + m_out_port_k_cb.resolve(); + m_out_port_m_cb.resolve(); + + m_in_port_a_cb.resolve(); + m_in_port_b_cb.resolve(); + m_in_port_c_cb.resolve(); + m_in_port_d_cb.resolve(); + m_in_port_e_cb.resolve(); + m_in_port_f_cb.resolve(); + m_in_port_g_cb.resolve(); + m_in_port_j_cb.resolve(); + m_in_port_k_cb.resolve(); + m_in_port_m_cb.resolve(); + + m_out_pwm_cb.resolve(); + + m_out_spim_cb.resolve(); + m_in_spim_cb.resolve(); + + m_spim_xch_trigger_cb.resolve(); + + m_gptimer[0] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(mc68328_device::timer1_hit),this)); + m_gptimer[1] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(mc68328_device::timer2_hit),this)); + m_rtc = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(mc68328_device::rtc_tick),this)); + m_pwm = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(mc68328_device::pwm_transition),this)); + + register_state_save(); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void mc68328_device::device_reset() +{ + m_regs.scr = 0x0c; + m_regs.grpbasea = 0x0000; + m_regs.grpbaseb = 0x0000; + m_regs.grpbasec = 0x0000; + m_regs.grpbased = 0x0000; + m_regs.grpmaska = 0x0000; + m_regs.grpmaskb = 0x0000; + m_regs.grpmaskc = 0x0000; + m_regs.grpmaskd = 0x0000; + m_regs.csa0 = 0x00010006; + m_regs.csa1 = 0x00010006; + m_regs.csa2 = 0x00010006; + m_regs.csa3 = 0x00010006; + m_regs.csb0 = 0x00010006; + m_regs.csb1 = 0x00010006; + m_regs.csb2 = 0x00010006; + m_regs.csb3 = 0x00010006; + m_regs.csc0 = 0x00010006; + m_regs.csc1 = 0x00010006; + m_regs.csc2 = 0x00010006; + m_regs.csc3 = 0x00010006; + m_regs.csd0 = 0x00010006; + m_regs.csd1 = 0x00010006; + m_regs.csd2 = 0x00010006; + m_regs.csd3 = 0x00010006; + + m_regs.pllcr = 0x2400; + m_regs.pllfsr = 0x0123; + m_regs.pctlr = 0x1f; + + m_regs.ivr = 0x00; + m_regs.icr = 0x0000; + m_regs.imr = 0x00ffffff; + m_regs.iwr = 0x00ffffff; + m_regs.isr = 0x00000000; + m_regs.ipr = 0x00000000; + + m_regs.padir = 0x00; + m_regs.padata = 0x00; + m_regs.pasel = 0x00; + m_regs.pbdir = 0x00; + m_regs.pbdata = 0x00; + m_regs.pbsel = 0x00; + m_regs.pcdir = 0x00; + m_regs.pcdata = 0x00; + m_regs.pcsel = 0x00; + m_regs.pddir = 0x00; + m_regs.pddata = 0x00; + m_regs.pdpuen = 0xff; + m_regs.pdpol = 0x00; + m_regs.pdirqen = 0x00; + m_regs.pddataedge = 0x00; + m_regs.pdirqedge = 0x00; + m_regs.pedir = 0x00; + m_regs.pedata = 0x00; + m_regs.pepuen = 0x80; + m_regs.pesel = 0x80; + m_regs.pfdir = 0x00; + m_regs.pfdata = 0x00; + m_regs.pfpuen = 0xff; + m_regs.pfsel = 0xff; + m_regs.pgdir = 0x00; + m_regs.pgdata = 0x00; + m_regs.pgpuen = 0xff; + m_regs.pgsel = 0xff; + m_regs.pjdir = 0x00; + m_regs.pjdata = 0x00; + m_regs.pjsel = 0x00; + m_regs.pkdir = 0x00; + m_regs.pkdata = 0x00; + m_regs.pkpuen = 0xff; + m_regs.pksel = 0xff; + m_regs.pmdir = 0x00; + m_regs.pmdata = 0x00; + m_regs.pmpuen = 0xff; + m_regs.pmsel = 0xff; + + m_regs.pwmc = 0x0000; + m_regs.pwmp = 0x0000; + m_regs.pwmw = 0x0000; + m_regs.pwmcnt = 0x0000; + + m_regs.tctl[0] = m_regs.tctl[1] = 0x0000; + m_regs.tprer[0] = m_regs.tprer[1] = 0x0000; + m_regs.tcmp[0] = m_regs.tcmp[1] = 0xffff; + m_regs.tcr[0] = m_regs.tcr[1] = 0x0000; + m_regs.tcn[0] = m_regs.tcn[1] = 0x0000; + m_regs.tstat[0] = m_regs.tstat[1] = 0x0000; + m_regs.wctlr = 0x0000; + m_regs.wcmpr = 0xffff; + m_regs.wcn = 0x0000; + + m_regs.spisr = 0x0000; + + m_regs.spimdata = 0x0000; + m_regs.spimcont = 0x0000; + + m_regs.ustcnt = 0x0000; + m_regs.ubaud = 0x003f; + m_regs.urx = 0x0000; + m_regs.utx = 0x0000; + m_regs.umisc = 0x0000; + + m_regs.lssa = 0x00000000; + m_regs.lvpw = 0xff; + m_regs.lxmax = 0x03ff; + m_regs.lymax = 0x01ff; + m_regs.lcxp = 0x0000; + m_regs.lcyp = 0x0000; + m_regs.lcwch = 0x0101; + m_regs.lblkc = 0x7f; + m_regs.lpicf = 0x00; + m_regs.lpolcf = 0x00; + m_regs.lacdrc = 0x00; + m_regs.lpxcd = 0x00; + m_regs.lckcon = 0x40; + m_regs.llbar = 0x3e; + m_regs.lotcr = 0x3f; + m_regs.lposr = 0x00; + m_regs.lfrcm = 0xb9; + m_regs.lgpmr = 0x1073; + + m_regs.hmsr = 0x00000000; + m_regs.alarm = 0x00000000; + m_regs.rtcctl = 0x00; + m_regs.rtcisr = 0x00; + m_regs.rtcienr = 0x00; + m_regs.stpwtch = 0x00; + + m_rtc->adjust(attotime::from_hz(1), 0, attotime::from_hz(1)); +} + + +void mc68328_device::set_interrupt_line(UINT32 line, UINT32 active) +{ + if (active) + { + m_regs.ipr |= line; + + if (!(m_regs.imr & line) && !(m_regs.isr & line)) + { + m_regs.isr |= line; + + if (m_regs.isr & INT_M68K_LINE7) + { + m_cpu->set_input_line_and_vector(M68K_IRQ_7, ASSERT_LINE, m_regs.ivr | 0x07); + } + else if (m_regs.isr & INT_M68K_LINE6) + { + m_cpu->set_input_line_and_vector(M68K_IRQ_6, ASSERT_LINE, m_regs.ivr | 0x06); + } + else if (m_regs.isr & INT_M68K_LINE5) + { + m_cpu->set_input_line_and_vector(M68K_IRQ_5, ASSERT_LINE, m_regs.ivr | 0x05); + } + else if (m_regs.isr & INT_M68K_LINE4) + { + m_cpu->set_input_line_and_vector(M68K_IRQ_4, ASSERT_LINE, m_regs.ivr | 0x04); + } + else if (m_regs.isr & INT_M68K_LINE3) + { + m_cpu->set_input_line_and_vector(M68K_IRQ_3, ASSERT_LINE, m_regs.ivr | 0x03); + } + else if (m_regs.isr & INT_M68K_LINE2) + { + m_cpu->set_input_line_and_vector(M68K_IRQ_2, ASSERT_LINE, m_regs.ivr | 0x02); + } + else if (m_regs.isr & INT_M68K_LINE1) + { + m_cpu->set_input_line_and_vector(M68K_IRQ_1, ASSERT_LINE, m_regs.ivr | 0x01); + } + } + } + else + { + m_regs.isr &= ~line; + + if ((line & INT_M68K_LINE7) && !(m_regs.isr & INT_M68K_LINE7)) + { + m_cpu->set_input_line(M68K_IRQ_7, CLEAR_LINE); + } + if ((line & INT_M68K_LINE6) && !(m_regs.isr & INT_M68K_LINE6)) + { + m_cpu->set_input_line(M68K_IRQ_6, CLEAR_LINE); + } + if ((line & INT_M68K_LINE5) && !(m_regs.isr & INT_M68K_LINE5)) + { + m_cpu->set_input_line(M68K_IRQ_5, CLEAR_LINE); + } + if ((line & INT_M68K_LINE4) && !(m_regs.isr & INT_M68K_LINE4)) + { + m_cpu->set_input_line(M68K_IRQ_4, CLEAR_LINE); + } + if ((line & INT_M68K_LINE3) && !(m_regs.isr & INT_M68K_LINE3)) + { + m_cpu->set_input_line(M68K_IRQ_3, CLEAR_LINE); + } + if ((line & INT_M68K_LINE2) && !(m_regs.isr & INT_M68K_LINE2)) + { + m_cpu->set_input_line(M68K_IRQ_2, CLEAR_LINE); + } + if ((line & INT_M68K_LINE1) && !(m_regs.isr & INT_M68K_LINE1)) + { + m_cpu->set_input_line(M68K_IRQ_1, CLEAR_LINE); + } + } +} + +void mc68328_device::poll_port_d_interrupts() +{ + UINT8 line_transitions = m_regs.pddataedge & m_regs.pdirqedge; + UINT8 line_holds = m_regs.pddata &~ m_regs.pdirqedge; + UINT8 line_interrupts = (line_transitions | line_holds) & m_regs.pdirqen; + + if (line_interrupts) + { + set_interrupt_line(line_interrupts << 8, 1); + } + else + { + set_interrupt_line(INT_KBDINTS, 0); + } +} + +WRITE_LINE_MEMBER( mc68328_device::set_penirq_line ) +{ + if (state) + { + set_interrupt_line(INT_PEN, 1); + } + else + { + m_regs.ipr &= ~INT_PEN; + set_interrupt_line(INT_PEN, 0); + } +} + +void mc68328_device::set_port_d_lines(UINT8 state, int bit) +{ + UINT8 old_button_state = m_regs.pddata; + + if (state & (1 << bit)) + { + m_regs.pddata |= (1 << bit); + } + else + { + m_regs.pddata &= ~(1 << bit); + } + + m_regs.pddataedge |= ~old_button_state & m_regs.pddata; + + poll_port_d_interrupts(); +} + +UINT32 mc68328_device::get_timer_frequency(UINT32 index) +{ + UINT32 frequency = 0; + + switch (m_regs.tctl[index] & TCTL_CLKSOURCE) + { + case TCTL_CLKSOURCE_SYSCLK: + frequency = 32768 * 506; + break; + + case TCTL_CLKSOURCE_SYSCLK16: + frequency = (32768 * 506) / 16; + break; + + case TCTL_CLKSOURCE_32KHZ4: + case TCTL_CLKSOURCE_32KHZ5: + case TCTL_CLKSOURCE_32KHZ6: + case TCTL_CLKSOURCE_32KHZ7: + frequency = 32768; + break; + } + frequency /= (m_regs.tprer[index] + 1); + + return frequency; +} + +void mc68328_device::maybe_start_timer(UINT32 index, UINT32 new_enable) +{ + if ((m_regs.tctl[index] & TCTL_TEN) == TCTL_TEN_ENABLE && (m_regs.tctl[index] & TCTL_CLKSOURCE) > TCTL_CLKSOURCE_STOP) + { + if ((m_regs.tctl[index] & TCTL_CLKSOURCE) == TCTL_CLKSOURCE_TIN) + { + m_gptimer[index]->adjust(attotime::never); + } + else if (m_regs.tcmp[index] == 0) + { + m_gptimer[index]->adjust(attotime::never); + } + else + { + UINT32 frequency = get_timer_frequency(index); + attotime period = (attotime::from_hz(frequency) * m_regs.tcmp[index]); + + if (new_enable) + { + m_regs.tcn[index] = 0x0000; + } + + m_gptimer[index]->adjust(period); + } + } + else + { + m_gptimer[index]->adjust(attotime::never); + } +} + +void mc68328_device::timer_compare_event(UINT32 index) +{ + m_regs.tcn[index] = m_regs.tcmp[index]; + m_regs.tstat[index] |= TSTAT_COMP; + + if ((m_regs.tctl[index] & TCTL_FRR) == TCTL_FRR_RESTART) + { + UINT32 frequency = get_timer_frequency(index); + + if (frequency > 0) + { + attotime period = attotime::from_hz(frequency) * m_regs.tcmp[index]; + + m_regs.tcn[index] = 0x0000; + + m_gptimer[index]->adjust(period); + } + else + { + m_gptimer[index]->adjust(attotime::never); + } + } + else + { + UINT32 frequency = get_timer_frequency(index); + + if (frequency > 0) + { + attotime period = attotime::from_hz(frequency) * 0x10000; + + m_gptimer[index]->adjust(period); + } + else + { + m_gptimer[index]->adjust(attotime::never); + } + } + if ((m_regs.tctl[index] & TCTL_IRQEN) == TCTL_IRQEN_ENABLE) + { + set_interrupt_line((index == 0) ? INT_TIMER1 : INT_TIMER2, 1); + } +} + +TIMER_CALLBACK_MEMBER( mc68328_device::timer1_hit ) +{ + timer_compare_event(0); +} + +TIMER_CALLBACK_MEMBER( mc68328_device::timer2_hit ) +{ + timer_compare_event(1); +} + +TIMER_CALLBACK_MEMBER( mc68328_device::pwm_transition ) +{ + if (m_regs.pwmw >= m_regs.pwmp || m_regs.pwmw == 0 || m_regs.pwmp == 0) + { + m_pwm->adjust(attotime::never); + return; + } + + if (((m_regs.pwmc & PWMC_POL) == 0 && (m_regs.pwmc & PWMC_PIN) != 0) || + ((m_regs.pwmc & PWMC_POL) != 0 && (m_regs.pwmc & PWMC_PIN) == 0)) + { + UINT32 frequency = 32768 * 506; + UINT32 divisor = 4 << (m_regs.pwmc & PWMC_CLKSEL); // ?? Datasheet says 2 <<, but then we're an octave higher than CoPilot. + attotime period; + + frequency /= divisor; + period = attotime::from_hz(frequency) * (m_regs.pwmp - m_regs.pwmw); + + m_pwm->adjust(period); + + if (m_regs.pwmc & PWMC_IRQEN) + { + set_interrupt_line(INT_PWM, 1); + } + } + else + { + UINT32 frequency = 32768 * 506; + UINT32 divisor = 4 << (m_regs.pwmc & PWMC_CLKSEL); // ?? Datasheet says 2 <<, but then we're an octave higher than CoPilot. + attotime period; + + frequency /= divisor; + period = attotime::from_hz(frequency) * m_regs.pwmw; + + m_pwm->adjust(period); + } + + m_regs.pwmc ^= PWMC_PIN; + + if (!m_out_pwm_cb.isnull()) + { + m_out_pwm_cb((offs_t)0, (m_regs.pwmc & PWMC_PIN) ? 1 : 0); + } +} + +TIMER_CALLBACK_MEMBER( mc68328_device::rtc_tick ) +{ + if (m_regs.rtcctl & RTCCTL_ENABLE) + { + UINT32 set_int = 0; + + m_regs.hmsr++; + + if (m_regs.rtcienr & RTCINT_SECOND) + { + set_int = 1; + m_regs.rtcisr |= RTCINT_SECOND; + } + + if ((m_regs.hmsr & 0x0000003f) == 0x0000003c) + { + m_regs.hmsr &= 0xffffffc0; + m_regs.hmsr += 0x00010000; + + if (m_regs.rtcienr & RTCINT_MINUTE) + { + set_int = 1; + m_regs.rtcisr |= RTCINT_MINUTE; + } + + if ((m_regs.hmsr & 0x003f0000) == 0x003c0000) + { + m_regs.hmsr &= 0xffc0ffff; + m_regs.hmsr += 0x0100000; + + if ((m_regs.hmsr & 0x1f000000) == 0x18000000) + { + m_regs.hmsr &= 0xe0ffffff; + + if (m_regs.rtcienr & RTCINT_DAY) + { + set_int = 1; + m_regs.rtcisr |= RTCINT_DAY; + } + } + } + + if (m_regs.stpwtch != 0x003f) + { + m_regs.stpwtch--; + m_regs.stpwtch &= 0x003f; + + if (m_regs.stpwtch == 0x003f) + { + if (m_regs.rtcienr & RTCINT_STOPWATCH) + { + set_int = 1; + m_regs.rtcisr |= RTCINT_STOPWATCH; + } + } + } + } + + if (m_regs.hmsr == m_regs.alarm) + { + if (m_regs.rtcienr & RTCINT_ALARM) + { + set_int = 1; + m_regs.rtcisr |= RTCINT_STOPWATCH; + } + } + + if (set_int) + { + set_interrupt_line(INT_RTC, 1); + } + else + { + set_interrupt_line(INT_RTC, 0); + } + } +} + +WRITE16_MEMBER( mc68328_device::write ) +{ + UINT32 address = offset << 1; + UINT16 temp16[4] = { 0 }; + UINT32 imr_old = m_regs.imr, imr_diff; + + switch (address) + { + case 0x000: + if (mem_mask & 0x00ff) + { + verboselog(machine(), 2, "mc68328_w: Unknown address (0xfff001) = %02x\n", data & 0x00ff); + } + else + { + verboselog(machine(), 2, "mc68328_w: SCR = %02x\n", (data >> 8) & 0x00ff); + } + break; + + case 0x100: + verboselog(machine(), 2, "mc68328_w: GRPBASEA = %04x\n", data); + m_regs.grpbasea = data; + break; + + case 0x102: + verboselog(machine(), 2, "mc68328_w: GRPBASEB = %04x\n", data); + m_regs.grpbaseb = data; + break; + + case 0x104: + verboselog(machine(), 2, "mc68328_w: GRPBASEC = %04x\n", data); + m_regs.grpbasec = data; + break; + + case 0x106: + verboselog(machine(), 2, "mc68328_w: GRPBASED = %04x\n", data); + m_regs.grpbased = data; + break; + + case 0x108: + verboselog(machine(), 2, "mc68328_w: GRPMASKA = %04x\n", data); + m_regs.grpmaska = data; + break; + + case 0x10a: + verboselog(machine(), 2, "mc68328_w: GRPMASKB = %04x\n", data); + m_regs.grpmaskb = data; + break; + + case 0x10c: + verboselog(machine(), 2, "mc68328_w: GRPMASKC = %04x\n", data); + m_regs.grpmaskc = data; + break; + + case 0x10e: + verboselog(machine(), 2, "mc68328_w: GRPMASKD = %04x\n", data); + m_regs.grpmaskd = data; + break; + + case 0x110: + verboselog(machine(), 5, "mc68328_w: CSA0(0) = %04x\n", data); + m_regs.csa0 &= 0xffff0000 | (~mem_mask); + m_regs.csa0 |= data & mem_mask; + break; + + case 0x112: + verboselog(machine(), 5, "mc68328_w: CSA0(16) = %04x\n", data); + m_regs.csa0 &= ~(mem_mask << 16); + m_regs.csa0 |= (data & mem_mask) << 16; + break; + + case 0x114: + verboselog(machine(), 5, "mc68328_w: CSA1(0) = %04x\n", data); + m_regs.csa1 &= 0xffff0000 | (~mem_mask); + m_regs.csa1 |= data & mem_mask; + break; + + case 0x116: + verboselog(machine(), 5, "mc68328_w: CSA1(16) = %04x\n", data); + m_regs.csa1 &= ~(mem_mask << 16); + m_regs.csa1 |= (data & mem_mask) << 16; + break; + + case 0x118: + verboselog(machine(), 5, "mc68328_w: CSA2(0) = %04x\n", data); + m_regs.csa2 &= 0xffff0000 | (~mem_mask); + m_regs.csa2 |= data & mem_mask; + break; + + case 0x11a: + verboselog(machine(), 5, "mc68328_w: CSA2(16) = %04x\n", data); + m_regs.csa2 &= ~(mem_mask << 16); + m_regs.csa2 |= (data & mem_mask) << 16; + break; + + case 0x11c: + verboselog(machine(), 5, "mc68328_w: CSA3(0) = %04x\n", data); + m_regs.csa3 &= 0xffff0000 | (~mem_mask); + m_regs.csa3 |= data & mem_mask; + break; + + case 0x11e: + verboselog(machine(), 5, "mc68328_w: CSA3(16) = %04x\n", data); + m_regs.csa3 &= ~(mem_mask << 16); + m_regs.csa3 |= (data & mem_mask) << 16; + break; + + case 0x120: + verboselog(machine(), 5, "mc68328_w: CSB0(0) = %04x\n", data); + m_regs.csb0 &= 0xffff0000 | (~mem_mask); + m_regs.csb0 |= data & mem_mask; + break; + + case 0x122: + verboselog(machine(), 5, "mc68328_w: CSB0(16) = %04x\n", data); + m_regs.csb0 &= ~(mem_mask << 16); + m_regs.csb0 |= (data & mem_mask) << 16; + break; + + case 0x124: + verboselog(machine(), 5, "mc68328_w: CSB1(0) = %04x\n", data); + m_regs.csb1 &= 0xffff0000 | (~mem_mask); + m_regs.csb1 |= data & mem_mask; + break; + + case 0x126: + verboselog(machine(), 5, "mc68328_w: CSB1(16) = %04x\n", data); + m_regs.csb1 &= ~(mem_mask << 16); + m_regs.csb1 |= (data & mem_mask) << 16; + break; + + case 0x128: + verboselog(machine(), 5, "mc68328_w: CSB2(0) = %04x\n", data); + m_regs.csb2 &= 0xffff0000 | (~mem_mask); + m_regs.csb2 |= data & mem_mask; + break; + + case 0x12a: + verboselog(machine(), 5, "mc68328_w: CSB2(16) = %04x\n", data); + m_regs.csb2 &= ~(mem_mask << 16); + m_regs.csb2 |= (data & mem_mask) << 16; + break; + + case 0x12c: + verboselog(machine(), 5, "mc68328_w: CSB3(0) = %04x\n", data); + m_regs.csb3 &= 0xffff0000 | (~mem_mask); + m_regs.csb3 |= data & mem_mask; + break; + + case 0x12e: + verboselog(machine(), 5, "mc68328_w: CSB3(16) = %04x\n", data); + m_regs.csb3 &= ~(mem_mask << 16); + m_regs.csb3 |= (data & mem_mask) << 16; + break; + + case 0x130: + verboselog(machine(), 5, "mc68328_w: CSC0(0) = %04x\n", data); + m_regs.csc0 &= 0xffff0000 | (~mem_mask); + m_regs.csc0 |= data & mem_mask; + break; + + case 0x132: + verboselog(machine(), 5, "mc68328_w: CSC0(16) = %04x\n", data); + m_regs.csc0 &= ~(mem_mask << 16); + m_regs.csc0 |= (data & mem_mask) << 16; + break; + + case 0x134: + verboselog(machine(), 5, "mc68328_w: CSC1(0) = %04x\n", data); + m_regs.csc1 &= 0xffff0000 | (~mem_mask); + m_regs.csc1 |= data & mem_mask; + break; + + case 0x136: + verboselog(machine(), 5, "mc68328_w: CSC1(16) = %04x\n", data); + m_regs.csc1 &= ~(mem_mask << 16); + m_regs.csc1 |= (data & mem_mask) << 16; + break; + + case 0x138: + verboselog(machine(), 5, "mc68328_w: CSC2(0) = %04x\n", data); + m_regs.csc2 &= 0xffff0000 | (~mem_mask); + m_regs.csc2 |= data & mem_mask; + break; + + case 0x13a: + verboselog(machine(), 5, "mc68328_w: CSC2(16) = %04x\n", data); + m_regs.csc2 &= ~(mem_mask << 16); + m_regs.csc2 |= (data & mem_mask) << 16; + break; + + case 0x13c: + verboselog(machine(), 5, "mc68328_w: CSC3(0) = %04x\n", data); + m_regs.csc3 &= 0xffff0000 | (~mem_mask); + m_regs.csc3 |= data & mem_mask; + break; + + case 0x13e: + verboselog(machine(), 5, "mc68328_w: CSC3(16) = %04x\n", data); + m_regs.csc3 &= ~(mem_mask << 16); + m_regs.csc3 |= (data & mem_mask) << 16; + break; + + case 0x140: + verboselog(machine(), 5, "mc68328_w: CSD0(0) = %04x\n", data); + m_regs.csd0 &= 0xffff0000 | (~mem_mask); + m_regs.csd0 |= data & mem_mask; + break; + + case 0x142: + verboselog(machine(), 5, "mc68328_w: CSD0(16) = %04x\n", data); + m_regs.csd0 &= ~(mem_mask << 16); + m_regs.csd0 |= (data & mem_mask) << 16; + break; + + case 0x144: + verboselog(machine(), 5, "mc68328_w: CSD1(0) = %04x\n", data); + m_regs.csd1 &= 0xffff0000 | (~mem_mask); + m_regs.csd1 |= data & mem_mask; + break; + + case 0x146: + verboselog(machine(), 5, "mc68328_w: CSD1(16) = %04x\n", data); + m_regs.csd1 &= ~(mem_mask << 16); + m_regs.csd1 |= (data & mem_mask) << 16; + break; + + case 0x148: + verboselog(machine(), 5, "mc68328_w: CSD2(0) = %04x\n", data); + m_regs.csd2 &= 0xffff0000 | (~mem_mask); + m_regs.csd2 |= data & mem_mask; + break; + + case 0x14a: + verboselog(machine(), 5, "mc68328_w: CSD2(16) = %04x\n", data); + m_regs.csd2 &= ~(mem_mask << 16); + m_regs.csd2 |= (data & mem_mask) << 16; + break; + + case 0x14c: + verboselog(machine(), 5, "mc68328_w: CSD3(0) = %04x\n", data); + m_regs.csd3 &= 0xffff0000 | (~mem_mask); + m_regs.csd3 |= data & mem_mask; + break; + + case 0x14e: + verboselog(machine(), 5, "mc68328_w: CSD3(16) = %04x\n", data); + m_regs.csd3 &= ~(mem_mask << 16); + m_regs.csd3 |= (data & mem_mask) << 16; + break; + + case 0x200: + verboselog(machine(), 2, "mc68328_w: PLLCR = %04x\n", data); + m_regs.pllcr = data; + break; + + case 0x202: + verboselog(machine(), 2, "mc68328_w: PLLFSR = %04x\n", data); + m_regs.pllfsr = data; + break; + + case 0x206: + if (mem_mask & 0x00ff) + { + verboselog(machine(), 2, "mc68328_w: PCTLR = %02x\n", data & 0x00ff); + m_regs.pctlr = data & 0x00ff; + } + else + { + verboselog(machine(), 2, "mc68328_w: Unknown address (0xfff206) = %02x\n", (data >> 8) & 0x00ff); + } + break; + + case 0x300: + if (mem_mask & 0x00ff) + { + verboselog(machine(), 2, "mc68328_w: Unknown address (0xfff301) = %02x\n", data & 0x00ff); + } + else + { + verboselog(machine(), 2, "mc68328_w: IVR = %02x\n", (data >> 8) & 0x00ff); + m_regs.ivr = (data >> 8) & 0x00ff; + } + break; + + case 0x302: + verboselog(machine(), 2, "mc68328_w: ICR = %04x\n", data); + m_regs.icr = data; + break; + + case 0x304: + verboselog(machine(), 2, "mc68328_w: IMR(16) = %04x\n", data); + m_regs.imr &= ~(mem_mask << 16); + m_regs.imr |= (data & mem_mask) << 16; + m_regs.isr &= ~((data & mem_mask) << 16); + + imr_diff = imr_old ^ m_regs.imr; + set_interrupt_line(imr_diff, 0); + break; + + case 0x306: + verboselog(machine(), 2, "mc68328_w: IMR(0) = %04x\n", data); + m_regs.imr &= 0xffff0000 | (~mem_mask); + m_regs.imr |= data & mem_mask; + m_regs.isr &= ~(data & mem_mask); + + imr_diff = imr_old ^ m_regs.imr; + set_interrupt_line(imr_diff, 0); + break; + + case 0x308: + verboselog(machine(), 2, "mc68328_w: IWR(16) = %04x\n", data); + m_regs.iwr &= ~(mem_mask << 16); + m_regs.iwr |= (data & mem_mask) << 16; + break; + + case 0x30a: + verboselog(machine(), 2, "mc68328_w: IWR(0) = %04x\n", data); + m_regs.iwr &= 0xffff0000 | (~mem_mask); + m_regs.iwr |= data & mem_mask; + break; + + case 0x30c: + verboselog(machine(), 2, "mc68328_w: ISR(16) = %04x\n", data); + // Clear edge-triggered IRQ1 + if ((m_regs.icr & ICR_ET1) == ICR_ET1 && (data & INT_IRQ1_SHIFT) == INT_IRQ1_SHIFT) + { + m_regs.isr &= ~INT_IRQ1; + } + + // Clear edge-triggered IRQ2 + if ((m_regs.icr & ICR_ET2) == ICR_ET2 && (data & INT_IRQ2_SHIFT) == INT_IRQ2_SHIFT) + { + m_regs.isr &= ~INT_IRQ2; + } + + // Clear edge-triggered IRQ3 + if ((m_regs.icr & ICR_ET3) == ICR_ET3 && (data & INT_IRQ3_SHIFT) == INT_IRQ3_SHIFT) + { + m_regs.isr &= ~INT_IRQ3; + } + + // Clear edge-triggered IRQ6 + if ((m_regs.icr & ICR_ET6) == ICR_ET6 && (data & INT_IRQ6_SHIFT) == INT_IRQ6_SHIFT) + { + m_regs.isr &= ~INT_IRQ6; + } + + // Clear edge-triggered IRQ7 + if ((data & INT_IRQ7_SHIFT) == INT_IRQ7_SHIFT) + { + m_regs.isr &= ~INT_IRQ7; + } + break; + + case 0x30e: + verboselog(machine(), 2, "mc68328_w: ISR(0) = %04x (Ignored)\n", data); + break; + + case 0x310: + verboselog(machine(), 2, "mc68328_w: IPR(16) = %04x (Ignored)\n", data); + break; + + case 0x312: + verboselog(machine(), 2, "mc68328_w: IPR(0) = %04x (Ignored)\n", data); + break; + + case 0x400: + if (mem_mask & 0x00ff) + { + verboselog(machine(), 2, "mc68328_w: PADATA = %02x\n", data & 0x00ff); + m_regs.padata = data & 0x00ff; + if (!m_out_port_a_cb.isnull()) + { + m_out_port_a_cb((offs_t)0, data & 0x00ff); + } + } + else + { + verboselog(machine(), 2, "mc68328_w: PADIR = %02x\n", (data >> 8) & 0x00ff); + m_regs.padir = (data >> 8) & 0x00ff; + } + break; + + case 0x402: + if (mem_mask & 0x00ff) + { + verboselog(machine(), 2, "mc68328_w: PASEL = %02x\n", data & 0x00ff); + m_regs.pasel = data & 0x00ff; + } + else + { + verboselog(machine(), 2, "mc68328_w: Unknown address (0xfff402) = %02x\n", (data >> 8) & 0x00ff); + } + break; + + case 0x408: + if (mem_mask & 0x00ff) + { + verboselog(machine(), 2, "mc68328_w: PBDATA = %02x\n", data & 0x00ff); + m_regs.pbdata = data & 0x00ff; + if (!m_out_port_b_cb.isnull()) + { + m_out_port_b_cb((offs_t)0, data & 0x00ff); + } + } + else + { + verboselog(machine(), 2, "mc68328_w: PBDIR = %02x\n", (data >> 8) & 0x00ff); + m_regs.pbdir = (data >> 8) & 0x00ff; + } + break; + + case 0x40a: + if (mem_mask & 0x00ff) + { + verboselog(machine(), 2, "mc68328_w: PBSEL = %02x\n", data & 0x00ff); + m_regs.pbsel = data & 0x00ff; + } + else + { + verboselog(machine(), 2, "mc68328_w: Unknown address (0xfff40a) = %02x\n", (data >> 8) & 0x00ff); + } + break; + + case 0x410: + if (mem_mask & 0x00ff) + { + verboselog(machine(), 2, "mc68328_w: PCDATA = %02x\n", data & 0x00ff); + m_regs.pcdata = data & 0x00ff; + if (!m_out_port_c_cb.isnull()) + { + m_out_port_c_cb((offs_t)0, data & 0x00ff); + } + } + else + { + verboselog(machine(), 2, "mc68328_w: PCDIR = %02x\n", (data >> 8) & 0x00ff); + m_regs.pcdir = (data >> 8) & 0x00ff; + } + break; + + case 0x412: + if (mem_mask & 0x00ff) + { + verboselog(machine(), 2, "mc68328_w: PCSEL = %02x\n", data & 0x00ff); + m_regs.pcsel = data & 0x00ff; + } + else + { + verboselog(machine(), 2, "mc68328_w: Unknown address (0xfff412) = %02x\n", (data >> 8) & 0x00ff); + } + break; + + case 0x418: + if (mem_mask & 0x00ff) + { + verboselog(machine(), 2, "mc68328_w: PDDATA = %02x\n", data & 0x00ff); + + m_regs.pddataedge &= ~(data & 0x00ff); + poll_port_d_interrupts(); + } + else + { + verboselog(machine(), 2, "mc68328_w: PDDIR = %02x\n", (data >> 8) & 0x00ff); + m_regs.pddir = (data >> 8) & 0x00ff; + } + break; + + case 0x41a: + if (mem_mask & 0x00ff) + { + verboselog(machine(), 2, "mc68328_w: Unknown address (0xfff41b) = %02x\n", data & 0x00ff); + } + else + { + verboselog(machine(), 2, "mc68328_w: PDPUEN = %02x\n", (data >> 8) & 0x00ff); + m_regs.pdpuen = (data >> 8) & 0x00ff; + } + break; + + case 0x41c: + if (mem_mask & 0x00ff) + { + verboselog(machine(), 2, "mc68328_w: PDIRQEN = %02x\n", data & 0x00ff); + m_regs.pdirqen = data & 0x00ff; + + poll_port_d_interrupts(); + } + else + { + verboselog(machine(), 2, "mc68328_w: PDPOL = %02x\n", (data >> 8) & 0x00ff); + m_regs.pdpol = (data >> 8) & 0x00ff; + } + break; + + case 0x41e: + if (mem_mask & 0x00ff) + { + verboselog(machine(), 2, "mc68328_w: PDIRQEDGE = %02x\n", data & 0x00ff); + m_regs.pdirqedge = data & 0x00ff; + } + else + { + verboselog(machine(), 2, "mc68328_w: Unknown address (0xfff41e) = %02x\n", (data >> 8) & 0x00ff); + } + break; + + case 0x420: + if (mem_mask & 0x00ff) + { + verboselog(machine(), 2, "mc68328_w: PEDATA = %02x\n", data & 0x00ff); + m_regs.pedata = data & 0x00ff; + if (!m_out_port_e_cb.isnull()) + { + m_out_port_e_cb((offs_t)0, data & 0x00ff); + } + } + else + { + verboselog(machine(), 2, "mc68328_w: PEDIR = %02x\n", (data >> 8) & 0x00ff); + m_regs.pedir = (data >> 8) & 0x00ff; + } + break; + + case 0x422: + if (mem_mask & 0x00ff) + { + verboselog(machine(), 2, "mc68328_w: PESEL = %02x\n", data & 0x00ff); + m_regs.pesel = data & 0x00ff; + } + else + { + verboselog(machine(), 2, "mc68328_w: PEPUEN = %02x\n", (data >> 8) & 0x00ff); + m_regs.pepuen = (data >> 8) & 0x00ff; + m_regs.pedata |= m_regs.pepuen; + } + break; + + case 0x428: + if (mem_mask & 0x00ff) + { + verboselog(machine(), 2, "mc68328_w: PFDATA = %02x\n", data & 0x00ff); + m_regs.pfdata = data & 0x00ff; + if (!m_out_port_f_cb.isnull()) + { + m_out_port_f_cb((offs_t)0, data & 0x00ff); + } + } + else + { + verboselog(machine(), 2, "mc68328_w: PFDIR = %02x\n", (data >> 8) & 0x00ff); + m_regs.pfdir = (data >> 8) & 0x00ff; + } + break; + + case 0x42a: + if (mem_mask & 0x00ff) + { + verboselog(machine(), 2, "mc68328_w: PFSEL = %02x\n", data & 0x00ff); + m_regs.pfsel = data & 0x00ff; + } + else + { + verboselog(machine(), 2, "mc68328_w: PFPUEN = %02x\n", (data >> 8) & 0x00ff); + m_regs.pfpuen = (data >> 8) & 0x00ff; + } + break; + + case 0x430: + if (mem_mask & 0x00ff) + { + verboselog(machine(), 2, "mc68328_w: PGDATA = %02x\n", data & 0x00ff); + m_regs.pgdata = data & 0x00ff; + if (!m_out_port_g_cb.isnull()) + { + m_out_port_g_cb((offs_t)0, data & 0x00ff); + } + } + else + { + verboselog(machine(), 2, "mc68328_w: PGDIR = %02x\n", (data >> 8) & 0x00ff); + m_regs.pgdir = (data >> 8) & 0x00ff; + } + break; + + case 0x432: + if (mem_mask & 0x00ff) + { + verboselog(machine(), 2, "mc68328_w: PGSEL = %02x\n", data & 0x00ff); + m_regs.pgsel = data & 0x00ff; + } + else + { + verboselog(machine(), 2, "mc68328_w: PGPUEN = %02x\n", (data >> 8) & 0x00ff); + m_regs.pgpuen = (data >> 8) & 0x00ff; + } + break; + + case 0x438: + if (mem_mask & 0x00ff) + { + verboselog(machine(), 2, "mc68328_w: PJDATA = %02x\n", data & 0x00ff); + m_regs.pjdata = data & 0x00ff; + if (!m_out_port_j_cb.isnull()) + { + m_out_port_j_cb((offs_t)0, data & 0x00ff); + } + } + else + { + verboselog(machine(), 2, "mc68328_w: PJDIR = %02x\n", (data >> 8) & 0x00ff); + m_regs.pjdir = (data >> 8) & 0x00ff; + } + break; + + case 0x43a: + if (mem_mask & 0x00ff) + { + verboselog(machine(), 2, "mc68328_w: PJSEL = %02x\n", data & 0x00ff); + m_regs.pjsel = data & 0x00ff; + } + else + { + verboselog(machine(), 2, "mc68328_w: Unknown address (0xfff43a) = %02x\n", (data >> 8) & 0x00ff); + } + break; + + case 0x440: + if (mem_mask & 0x00ff) + { + verboselog(machine(), 2, "mc68328_w: PKDATA = %02x\n", data & 0x00ff); + m_regs.pkdata = data & 0x00ff; + if (!m_out_port_k_cb.isnull()) + { + m_out_port_k_cb((offs_t)0, data & 0x00ff); + } + } + else + { + verboselog(machine(), 2, "mc68328_w: PKDIR = %02x\n", (data >> 8) & 0x00ff); + m_regs.pkdir = (data >> 8) & 0x00ff; + } + break; + + case 0x442: + if (mem_mask & 0x00ff) + { + verboselog(machine(), 2, "mc68328_w: PKSEL = %02x\n", data & 0x00ff); + m_regs.pksel = data & 0x00ff; + } + else + { + verboselog(machine(), 2, "mc68328_w: PKPUEN = %02x\n", (data >> 8) & 0x00ff); + m_regs.pgpuen = (data >> 8) & 0x00ff; + } + break; + + case 0x448: + if (mem_mask & 0x00ff) + { + verboselog(machine(), 2, "mc68328_w: PMDATA = %02x\n", data & 0x00ff); + m_regs.pmdata = data & 0x00ff; + if (!m_out_port_m_cb.isnull()) + { + m_out_port_m_cb((offs_t)0, data & 0x00ff); + } + } + else + { + verboselog(machine(), 2, "mc68328_w: PMDIR = %02x\n", (data >> 8) & 0x00ff); + m_regs.pmdir = (data >> 8) & 0x00ff; + } + break; + + case 0x44a: + if (mem_mask & 0x00ff) + { + verboselog(machine(), 2, "mc68328_w: PMSEL = %02x\n", data & 0x00ff); + m_regs.pmsel = data & 0x00ff; + } + else + { + verboselog(machine(), 2, "mc68328_w: PMPUEN = %02x\n", (data >> 8) & 0x00ff); + m_regs.pmpuen = (data >> 8) & 0x00ff; + } + break; + + case 0x500: + verboselog(machine(), 2, "mc68328_w: PWMC = %04x\n", data); + + m_regs.pwmc = data; + + if (m_regs.pwmc & PWMC_PWMIRQ) + { + set_interrupt_line(INT_PWM, 1); + } + + m_regs.pwmc &= ~PWMC_LOAD; + + if ((m_regs.pwmc & PWMC_PWMEN) != 0 && m_regs.pwmw != 0 && m_regs.pwmp != 0) + { + UINT32 frequency = 32768 * 506; + UINT32 divisor = 4 << (m_regs.pwmc & PWMC_CLKSEL); // ?? Datasheet says 2 <<, but then we're an octave higher than CoPilot. + attotime period; + frequency /= divisor; + period = attotime::from_hz(frequency) * m_regs.pwmw; + m_pwm->adjust(period); + if (m_regs.pwmc & PWMC_IRQEN) + { + set_interrupt_line(INT_PWM, 1); + } + m_regs.pwmc ^= PWMC_PIN; + } + else + { + m_pwm->adjust(attotime::never); + } + break; + + case 0x502: + verboselog(machine(), 2, "mc68328_w: PWMP = %04x\n", data); + m_regs.pwmp = data; + break; + + case 0x504: + verboselog(machine(), 2, "mc68328_w: PWMW = %04x\n", data); + m_regs.pwmw = data; + break; + + case 0x506: + verboselog(machine(), 2, "mc68328_w: PWMCNT = %04x\n", data); + m_regs.pwmcnt = 0; + break; + + case 0x600: + verboselog(machine(), 2, "mc68328_w: TCTL1 = %04x\n", data); + temp16[0] = m_regs.tctl[0]; + m_regs.tctl[0] = data; + if ((temp16[0] & TCTL_TEN) == (m_regs.tctl[0] & TCTL_TEN)) + { + maybe_start_timer(0, 0); + } + else if ((temp16[0] & TCTL_TEN) != TCTL_TEN_ENABLE && (m_regs.tctl[0] & TCTL_TEN) == TCTL_TEN_ENABLE) + { + maybe_start_timer(0, 1); + } + break; + + case 0x602: + verboselog(machine(), 2, "mc68328_w: TPRER1 = %04x\n", data); + m_regs.tprer[0] = data; + maybe_start_timer(0, 0); + break; + + case 0x604: + verboselog(machine(), 2, "mc68328_w: TCMP1 = %04x\n", data); + m_regs.tcmp[0] = data; + maybe_start_timer(0, 0); + break; + + case 0x606: + verboselog(machine(), 2, "mc68328_w: TCR1 = %04x (Ignored)\n", data); + break; + + case 0x608: + verboselog(machine(), 2, "mc68328_w: TCN1 = %04x (Ignored)\n", data); + break; + + case 0x60a: + verboselog(machine(), 5, "mc68328_w: TSTAT1 = %04x\n", data); + m_regs.tstat[0] &= ~m_regs.tclear[0]; + if (!(m_regs.tstat[0] & TSTAT_COMP)) + { + set_interrupt_line(INT_TIMER1, 0); + } + break; + + case 0x60c: + verboselog(machine(), 2, "mc68328_w: TCTL2 = %04x\n", data); + temp16[0] = m_regs.tctl[1]; + m_regs.tctl[1] = data; + if ((temp16[0] & TCTL_TEN) == (m_regs.tctl[1] & TCTL_TEN)) + { + maybe_start_timer(1, 0); + } + else if ((temp16[0] & TCTL_TEN) != TCTL_TEN_ENABLE && (m_regs.tctl[1] & TCTL_TEN) == TCTL_TEN_ENABLE) + { + maybe_start_timer(1, 1); + } + break; + + case 0x60e: + verboselog(machine(), 2, "mc68328_w: TPRER2 = %04x\n", data); + m_regs.tprer[1] = data; + maybe_start_timer(1, 0); + break; + + case 0x610: + verboselog(machine(), 2, "mc68328_w: TCMP2 = %04x\n", data); + m_regs.tcmp[1] = data; + maybe_start_timer(1, 0); + break; + + case 0x612: + verboselog(machine(), 2, "mc68328_w: TCR2 = %04x (Ignored)\n", data); + break; + + case 0x614: + verboselog(machine(), 2, "mc68328_w: TCN2 = %04x (Ignored)\n", data); + break; + + case 0x616: + verboselog(machine(), 2, "mc68328_w: TSTAT2 = %04x\n", data); + m_regs.tstat[1] &= ~m_regs.tclear[1]; + if (!(m_regs.tstat[1] & TSTAT_COMP)) + { + set_interrupt_line(INT_TIMER2, 0); + } + break; + + case 0x618: + verboselog(machine(), 2, "mc68328_w: WCTLR = %04x\n", data); + m_regs.wctlr = data; + break; + + case 0x61a: + verboselog(machine(), 2, "mc68328_w: WCMPR = %04x\n", data); + m_regs.wcmpr = data; + break; + + case 0x61c: + verboselog(machine(), 2, "mc68328_w: WCN = %04x (Ignored)\n", data); + break; + + case 0x700: + verboselog(machine(), 2, "mc68328_w: SPISR = %04x\n", data); + m_regs.spisr = data; + break; + + case 0x800: + verboselog(machine(), 2, "mc68328_w: SPIMDATA = %04x\n", data); + if (!m_out_spim_cb.isnull()) + { + m_out_spim_cb(0, data, 0xffff); + } + else + { + m_regs.spimdata = data; + } + break; + + case 0x802: + verboselog(machine(), 2, "mc68328_w: SPIMCONT = %04x\n", data); + verboselog(machine(), 3, " Count = %d\n", data & SPIM_CLOCK_COUNT); + verboselog(machine(), 3, " Polarity = %s\n", (data & SPIM_POL) ? "Inverted" : "Active-high"); + verboselog(machine(), 3, " Phase = %s\n", (data & SPIM_PHA) ? "Opposite" : "Normal"); + verboselog(machine(), 3, " IRQ Enable = %s\n", (data & SPIM_IRQEN) ? "Enable" : "Disable"); + verboselog(machine(), 3, " IRQ Pending = %s\n", (data & SPIM_SPIMIRQ) ? "Yes" : "No"); + verboselog(machine(), 3, " Exchange = %s\n", (data & SPIM_XCH) ? "Initiate" : "Idle"); + verboselog(machine(), 3, " SPIM Enable = %s\n", (data & SPIM_SPMEN) ? "Enable" : "Disable"); + verboselog(machine(), 3, " Data Rate = Divide By %d\n", 1 << ((((data & SPIM_RATE) >> 13) & 0x0007) + 2) ); + m_regs.spimcont = data; + // $$HACK$$ We should probably emulate the ADS7843 A/D device properly. + if (data & SPIM_XCH) + { + m_regs.spimcont &= ~SPIM_XCH; + if (!m_spim_xch_trigger_cb.isnull()) + { + m_spim_xch_trigger_cb(0); + } + if (data & SPIM_IRQEN) + { + m_regs.spimcont |= SPIM_SPIMIRQ; + verboselog(machine(), 3, "Triggering SPIM Interrupt\n" ); + set_interrupt_line(INT_SPIM, 1); + } + } + if (!(data & SPIM_IRQEN)) + { + set_interrupt_line(INT_SPIM, 0); + } + break; + + case 0x900: + verboselog(machine(), 2, "mc68328_w: USTCNT = %04x\n", data); + m_regs.ustcnt = data; + break; + + case 0x902: + verboselog(machine(), 2, "mc68328_w: UBAUD = %04x\n", data); + m_regs.ubaud = data; + break; + + case 0x904: + verboselog(machine(), 2, "mc68328_w: URX = %04x\n", data); + break; + + case 0x906: + verboselog(machine(), 2, "mc68328_w: UTX = %04x\n", data); + break; + + case 0x908: + verboselog(machine(), 2, "mc68328_w: UMISC = %04x\n", data); + m_regs.umisc = data; + break; + + case 0xa00: + verboselog(machine(), 2, "mc68328_w: LSSA(16) = %04x\n", data); + m_regs.lssa &= ~(mem_mask << 16); + m_regs.lssa |= (data & mem_mask) << 16; + verboselog(machine(), 3, " Address: %08x\n", m_regs.lssa); + break; + + case 0xa02: + verboselog(machine(), 2, "mc68328_w: LSSA(0) = %04x\n", data); + m_regs.lssa &= 0xffff0000 | (~mem_mask); + m_regs.lssa |= data & mem_mask; + verboselog(machine(), 3, " Address: %08x\n", m_regs.lssa); + break; + + case 0xa04: + if (mem_mask & 0x00ff) + { + verboselog(machine(), 2, "mc68328_w: LVPW = %02x\n", data & 0x00ff); + m_regs.lvpw = data & 0x00ff; + verboselog(machine(), 3, " Page Width: %d\n", (m_regs.lvpw + 1) * ((m_regs.lpicf & 0x01) ? 8 : 16)); + } + else + { + verboselog(machine(), 2, "mc68328_w: Unknown address (0xfffa04) = %02x\n", (data >> 8) & 0x00ff); + } + break; + + case 0xa08: + verboselog(machine(), 2, "mc68328_w: LXMAX = %04x\n", data); + m_regs.lxmax = data; + verboselog(machine(), 3, " Width: %d\n", (data & 0x03ff) + 1); + break; + + case 0xa0a: + verboselog(machine(), 2, "mc68328_w: LYMAX = %04x\n", data); + m_regs.lymax = data; + verboselog(machine(), 3, " Height: %d\n", (data & 0x03ff) + 1); + break; + + case 0xa18: + verboselog(machine(), 2, "mc68328_w: LCXP = %04x\n", data); + m_regs.lcxp = data; + verboselog(machine(), 3, " X Position: %d\n", data & 0x03ff); + switch (m_regs.lcxp >> 14) + { + case 0: + verboselog(machine(), 3, " Cursor Control: Transparent\n"); + break; + + case 1: + verboselog(machine(), 3, " Cursor Control: Black\n"); + break; + + case 2: + verboselog(machine(), 3, " Cursor Control: Reverse\n"); + break; + + case 3: + verboselog(machine(), 3, " Cursor Control: Invalid\n"); + break; + } + break; + + case 0xa1a: + verboselog(machine(), 2, "mc68328_w: LCYP = %04x\n", data); + m_regs.lcyp = data; + verboselog(machine(), 3, " Y Position: %d\n", data & 0x01ff); + break; + + case 0xa1c: + verboselog(machine(), 2, "mc68328_w: LCWCH = %04x\n", data); + m_regs.lcwch = data; + verboselog(machine(), 3, " Width: %d\n", (data >> 8) & 0x1f); + verboselog(machine(), 3, " Height: %d\n", data & 0x1f); + break; + + case 0xa1e: + if (mem_mask & 0x00ff) + { + verboselog(machine(), 2, "mc68328_w: LBLKC = %02x\n", data & 0x00ff); + m_regs.lblkc = data & 0x00ff; + verboselog(machine(), 3, " Blink Enable: %d\n", m_regs.lblkc >> 7); + verboselog(machine(), 3, " Blink Divisor: %d\n", m_regs.lblkc & 0x7f); + } + else + { + verboselog(machine(), 2, "mc68328_w: Unknown address (0xfffa1e) = %02x\n", (data >> 8) & 0x00ff); + } + break; + + case 0xa20: + if (mem_mask & 0x00ff) + { + verboselog(machine(), 2, "mc68328_w: LPOLCF = %02x\n", data & 0x00ff); + m_regs.lpolcf = data & 0x00ff; + verboselog(machine(), 3, " LCD Shift Clock Polarity: %s\n", (m_regs.lpicf & 0x08) ? "Active positive edge of LCLK" : "Active negative edge of LCLK"); + verboselog(machine(), 3, " First-line marker polarity: %s\n", (m_regs.lpicf & 0x04) ? "Active Low" : "Active High"); + verboselog(machine(), 3, " Line-pulse polarity: %s\n", (m_regs.lpicf & 0x02) ? "Active Low" : "Active High"); + verboselog(machine(), 3, " Pixel polarity: %s\n", (m_regs.lpicf & 0x01) ? "Active Low" : "Active High"); + } + else + { + verboselog(machine(), 2, "mc68328_w: LPICF = %02x\n", (data >> 8) & 0x00ff); + m_regs.lpicf = (data >> 8) & 0x00ff; + switch((m_regs.lpicf >> 1) & 0x03) + { + case 0: + verboselog(machine(), 3, " Bus Size: 1-bit\n"); + break; + + case 1: + verboselog(machine(), 3, " Bus Size: 2-bit\n"); + break; + + case 2: + verboselog(machine(), 3, " Bus Size: 4-bit\n"); + break; + + case 3: + verboselog(machine(), 3, " Bus Size: unused\n"); + break; + } + verboselog(machine(), 3, " Gray scale enable: %d\n", m_regs.lpicf & 0x01); + } + break; + + case 0xa22: + if (mem_mask & 0x00ff) + { + verboselog(machine(), 2, "mc68328_w: LACDRC = %02x\n", data & 0x00ff); + m_regs.lacdrc = data & 0x00ff; + } + else + { + verboselog(machine(), 2, "mc68328_w: Unknown address (0xfffa22) = %02x\n", (data >> 8) & 0x00ff); + } + break; + + case 0xa24: + if (mem_mask & 0x00ff) + { + verboselog(machine(), 2, "mc68328_w: LPXCD = %02x\n", data & 0x00ff); + m_regs.lpxcd = data & 0x00ff; + verboselog(machine(), 3, " Clock Divisor: %d\n", m_regs.lpxcd + 1); + } + else + { + verboselog(machine(), 2, "mc68328_w: Unknown address (0xfffa24) = %02x\n", (data >> 8) & 0x00ff); + } + break; + + case 0xa26: + if (mem_mask & 0x00ff) + { + verboselog(machine(), 2, "mc68328_w: LCKCON = %02x\n", data & 0x00ff); + m_regs.lckcon = data & 0x00ff; + verboselog(machine(), 3, " LCDC Enable: %d\n", (m_regs.lckcon >> 7) & 0x01); + verboselog(machine(), 3, " DMA Burst Length: %d\n", ((m_regs.lckcon >> 6) & 0x01) ? 16 : 8); + verboselog(machine(), 3, " DMA Bursting Clock Control: %d\n", ((m_regs.lckcon >> 4) & 0x03) + 1); + verboselog(machine(), 3, " Bus Width: %d\n", ((m_regs.lckcon >> 1) & 0x01) ? 8 : 16); + verboselog(machine(), 3, " Pixel Clock Divider Source: %s\n", (m_regs.lckcon & 0x01) ? "PIX" : "SYS"); + } + else + { + verboselog(machine(), 2, "mc68328_w: Unknown address (0xfffa26) = %02x\n", (data >> 8) & 0x00ff); + } + break; + + case 0xa28: + if (mem_mask & 0x00ff) + { + verboselog(machine(), 2, "mc68328_w: LLBAR = %02x\n", data & 0x00ff); + m_regs.llbar = data & 0x00ff; + verboselog(machine(), 3, " Address: %d\n", (m_regs.llbar & 0x7f) * ((m_regs.lpicf & 0x01) ? 8 : 16)); + } + else + { + verboselog(machine(), 2, "mc68328_w: Unknown address (0xfffa28) = %02x\n", (data >> 8) & 0x00ff); + } + break; + + case 0xa2a: + if (mem_mask & 0x00ff) + { + verboselog(machine(), 2, "mc68328_w: LOTCR = %02x\n", data & 0x00ff); + } + else + { + verboselog(machine(), 2, "mc68328_w: Unknown address (0xfffa2a) = %02x\n", (data >> 8) & 0x00ff); + } + break; + + case 0xa2c: + if (mem_mask & 0x00ff) + { + verboselog(machine(), 2, "mc68328_w: LPOSR = %02x\n", data & 0x00ff); + m_regs.lposr = data & 0x00ff; + verboselog(machine(), 3, " Byte Offset: %d\n", (m_regs.lposr >> 3) & 0x01); + verboselog(machine(), 3, " Pixel Offset: %d\n", m_regs.lposr & 0x07); + } + else + { + verboselog(machine(), 2, "mc68328_w: Unknown address (0xfffa2c) = %02x\n", (data >> 8) & 0x00ff); + } + break; + + case 0xa30: + if (mem_mask & 0x00ff) + { + verboselog(machine(), 2, "mc68328_w: LFRCM = %02x\n", data & 0x00ff); + m_regs.lfrcm = data & 0x00ff; + verboselog(machine(), 3, " X Modulation: %d\n", (m_regs.lfrcm >> 4) & 0x0f); + verboselog(machine(), 3, " Y Modulation: %d\n", m_regs.lfrcm & 0x0f); + } + else + { + verboselog(machine(), 2, "mc68328_w: Unknown address (0xfffa30) = %02x\n", (data >> 8) & 0x00ff); + } + break; + + case 0xa32: + verboselog(machine(), 2, "mc68328_w: LGPMR = %04x\n", data); + m_regs.lgpmr = data; + verboselog(machine(), 3, " Palette 0: %d\n", (m_regs.lgpmr >> 8) & 0x07); + verboselog(machine(), 3, " Palette 1: %d\n", (m_regs.lgpmr >> 12) & 0x07); + verboselog(machine(), 3, " Palette 2: %d\n", (m_regs.lgpmr >> 0) & 0x07); + verboselog(machine(), 3, " Palette 3: %d\n", (m_regs.lgpmr >> 4) & 0x07); + break; + + case 0xb00: + verboselog(machine(), 2, "mc68328_w: HMSR(0) = %04x\n", data); + m_regs.hmsr &= ~(mem_mask << 16); + m_regs.hmsr |= (data & mem_mask) << 16; + m_regs.hmsr &= 0x1f3f003f; + break; + + case 0xb02: + verboselog(machine(), 2, "mc68328_w: HMSR(16) = %04x\n", data); + m_regs.hmsr &= 0xffff0000 | (~mem_mask); + m_regs.hmsr |= data & mem_mask; + m_regs.hmsr &= 0x1f3f003f; + break; + + case 0xb04: + verboselog(machine(), 2, "mc68328_w: ALARM(0) = %04x\n", data); + m_regs.alarm &= ~(mem_mask << 16); + m_regs.alarm |= (data & mem_mask) << 16; + m_regs.alarm &= 0x1f3f003f; + break; + + case 0xb06: + verboselog(machine(), 2, "mc68328_w: ALARM(16) = %04x\n", data); + m_regs.alarm &= 0xffff0000 | (~mem_mask); + m_regs.alarm |= data & mem_mask; + m_regs.alarm &= 0x1f3f003f; + break; + + case 0xb0c: + verboselog(machine(), 2, "mc68328_w: RTCCTL = %04x\n", data); + m_regs.rtcctl = data & 0x00a0; + break; + + case 0xb0e: + verboselog(machine(), 2, "mc68328_w: RTCISR = %04x\n", data); + m_regs.rtcisr &= ~data; + if (m_regs.rtcisr == 0) + { + set_interrupt_line(INT_RTC, 0); + } + break; + + case 0xb10: + verboselog(machine(), 2, "mc68328_w: RTCIENR = %04x\n", data); + m_regs.rtcienr = data & 0x001f; + break; + + case 0xb12: + verboselog(machine(), 2, "mc68328_w: STPWTCH = %04x\n", data); + m_regs.stpwtch = data & 0x003f; + break; + + default: + verboselog(machine(), 0, "mc68328_w: Unknown address (0x%06x) = %04x (%04x)\n", 0xfff000 + address, data, mem_mask); + break; + } +} + +READ16_MEMBER( mc68328_device::read ) +{ + UINT16 temp16 = 0; + UINT32 address = offset << 1; + + switch (address) + { + case 0x000: + if (mem_mask & 0x00ff) + { + verboselog(machine(), 2, "mc68328_r (%04x): Unknown address (0xfff001)\n", mem_mask); + } + else + { + verboselog(machine(), 2, "mc68328_r (%04x): SCR = %02x\n", mem_mask, m_regs.scr); + return m_regs.scr << 8; + } + break; + + case 0x100: + verboselog(machine(), 2, "mc68328_r (%04x): GRPBASEA = %04x\n", mem_mask, m_regs.grpbasea); + return m_regs.grpbasea; + + case 0x102: + verboselog(machine(), 2, "mc68328_r (%04x): GRPBASEB = %04x\n", mem_mask, m_regs.grpbaseb); + return m_regs.grpbaseb; + + case 0x104: + verboselog(machine(), 2, "mc68328_r (%04x): GRPBASEC = %04x\n", mem_mask, m_regs.grpbasec); + return m_regs.grpbasec; + + case 0x106: + verboselog(machine(), 2, "mc68328_r (%04x): GRPBASED = %04x\n", mem_mask, m_regs.grpbased); + return m_regs.grpbased; + + case 0x108: + verboselog(machine(), 2, "mc68328_r (%04x): GRPMASKA = %04x\n", mem_mask, m_regs.grpmaska); + return m_regs.grpmaska; + + case 0x10a: + verboselog(machine(), 2, "mc68328_r (%04x): GRPMASKB = %04x\n", mem_mask, m_regs.grpmaskb); + return m_regs.grpmaskb; + + case 0x10c: + verboselog(machine(), 2, "mc68328_r (%04x): GRPMASKC = %04x\n", mem_mask, m_regs.grpmaskc); + return m_regs.grpmaskc; + + case 0x10e: + verboselog(machine(), 2, "mc68328_r (%04x): GRPMASKD = %04x\n", mem_mask, m_regs.grpmaskd); + return m_regs.grpmaskd; + + case 0x110: + verboselog(machine(), 5, "mc68328_r (%04x): CSA0(0) = %04x\n", mem_mask, m_regs.csa0 & 0x0000ffff); + return m_regs.csa0 & 0x0000ffff; + + case 0x112: + verboselog(machine(), 5, "mc68328_r (%04x): CSA0(16) = %04x\n", mem_mask, m_regs.csa0 >> 16); + return m_regs.csa0 >> 16; + + case 0x114: + verboselog(machine(), 5, "mc68328_r (%04x): CSA1(0) = %04x\n", mem_mask, m_regs.csa1 & 0x0000ffff); + return m_regs.csa1 & 0x0000ffff; + + case 0x116: + verboselog(machine(), 5, "mc68328_r (%04x): CSA1(16) = %04x\n", mem_mask, m_regs.csa1 >> 16); + return m_regs.csa1 >> 16; + + case 0x118: + verboselog(machine(), 5, "mc68328_r (%04x): CSA2(0) = %04x\n", mem_mask, m_regs.csa2 & 0x0000ffff); + return m_regs.csa2 & 0x0000ffff; + + case 0x11a: + verboselog(machine(), 5, "mc68328_r (%04x): CSA2(16) = %04x\n", mem_mask, m_regs.csa2 >> 16); + return m_regs.csa2 >> 16; + + case 0x11c: + verboselog(machine(), 5, "mc68328_r (%04x): CSA3(0) = %04x\n", mem_mask, m_regs.csa3 & 0x0000ffff); + return m_regs.csa3 & 0x0000ffff; + + case 0x11e: + verboselog(machine(), 5, "mc68328_r (%04x): CSA3(16) = %04x\n", mem_mask, m_regs.csa3 >> 16); + return m_regs.csa3 >> 16; + + case 0x120: + verboselog(machine(), 5, "mc68328_r (%04x): CSB0(0) = %04x\n", mem_mask, m_regs.csb0 & 0x0000ffff); + return m_regs.csb0 & 0x0000ffff; + + case 0x122: + verboselog(machine(), 5, "mc68328_r (%04x): CSB0(16) = %04x\n", mem_mask, m_regs.csb0 >> 16); + return m_regs.csb0 >> 16; + + case 0x124: + verboselog(machine(), 5, "mc68328_r (%04x): CSB1(0) = %04x\n", mem_mask, m_regs.csb1 & 0x0000ffff); + return m_regs.csb1 & 0x0000ffff; + + case 0x126: + verboselog(machine(), 5, "mc68328_r (%04x): CSB1(16) = %04x\n", mem_mask, m_regs.csb1 >> 16); + return m_regs.csb1 >> 16; + + case 0x128: + verboselog(machine(), 5, "mc68328_r (%04x): CSB2(0) = %04x\n", mem_mask, m_regs.csb2 & 0x0000ffff); + return m_regs.csb2 & 0x0000ffff; + + case 0x12a: + verboselog(machine(), 5, "mc68328_r (%04x): CSB2(16) = %04x\n", mem_mask, m_regs.csb2 >> 16); + return m_regs.csb2 >> 16; + + case 0x12c: + verboselog(machine(), 5, "mc68328_r (%04x): CSB3(0) = %04x\n", mem_mask, m_regs.csb3 & 0x0000ffff); + return m_regs.csb3 & 0x0000ffff; + + case 0x12e: + verboselog(machine(), 5, "mc68328_r (%04x): CSB3(16) = %04x\n", mem_mask, m_regs.csb3 >> 16); + return m_regs.csb3 >> 16; + + case 0x130: + verboselog(machine(), 5, "mc68328_r (%04x): CSC0(0) = %04x\n", mem_mask, m_regs.csc0 & 0x0000ffff); + return m_regs.csc0 & 0x0000ffff; + + case 0x132: + verboselog(machine(), 5, "mc68328_r (%04x): CSC0(16) = %04x\n", mem_mask, m_regs.csc0 >> 16); + return m_regs.csc0 >> 16; + + case 0x134: + verboselog(machine(), 5, "mc68328_r (%04x): CSC1(0) = %04x\n", mem_mask, m_regs.csc1 & 0x0000ffff); + return m_regs.csc1 & 0x0000ffff; + + case 0x136: + verboselog(machine(), 5, "mc68328_r (%04x): CSC1(16) = %04x\n", mem_mask, m_regs.csc1 >> 16); + return m_regs.csc1 >> 16; + + case 0x138: + verboselog(machine(), 5, "mc68328_r (%04x): CSC2(0) = %04x\n", mem_mask, m_regs.csc2 & 0x0000ffff); + return m_regs.csc2 & 0x0000ffff; + + case 0x13a: + verboselog(machine(), 5, "mc68328_r (%04x): CSC2(16) = %04x\n", mem_mask, m_regs.csc2 >> 16); + return m_regs.csc2 >> 16; + + case 0x13c: + verboselog(machine(), 5, "mc68328_r (%04x): CSC3(0) = %04x\n", mem_mask, m_regs.csc3 & 0x0000ffff); + return m_regs.csc3 & 0x0000ffff; + + case 0x13e: + verboselog(machine(), 5, "mc68328_r (%04x): CSC3(16) = %04x\n", mem_mask, m_regs.csc3 >> 16); + return m_regs.csc3 >> 16; + + case 0x140: + verboselog(machine(), 5, "mc68328_r (%04x): CSD0(0) = %04x\n", mem_mask, m_regs.csd0 & 0x0000ffff); + return m_regs.csd0 & 0x0000ffff; + + case 0x142: + verboselog(machine(), 5, "mc68328_r (%04x): CSD0(16) = %04x\n", mem_mask, m_regs.csd0 >> 16); + return m_regs.csd0 >> 16; + + case 0x144: + verboselog(machine(), 5, "mc68328_r (%04x): CSD1(0) = %04x\n", mem_mask, m_regs.csd1 & 0x0000ffff); + return m_regs.csd1 & 0x0000ffff; + + case 0x146: + verboselog(machine(), 5, "mc68328_r (%04x): CSD1(16) = %04x\n", mem_mask, m_regs.csd1 >> 16); + return m_regs.csd1 >> 16; + + case 0x148: + verboselog(machine(), 5, "mc68328_r (%04x): CSD2(0) = %04x\n", mem_mask, m_regs.csd2 & 0x0000ffff); + return m_regs.csd2 & 0x0000ffff; + + case 0x14a: + verboselog(machine(), 5, "mc68328_r (%04x): CSD2(16) = %04x\n", mem_mask, m_regs.csd2 >> 16); + return m_regs.csd2 >> 16; + + case 0x14c: + verboselog(machine(), 5, "mc68328_r (%04x): CSD3(0) = %04x\n", mem_mask, m_regs.csd3 & 0x0000ffff); + return m_regs.csd3 & 0x0000ffff; + + case 0x14e: + verboselog(machine(), 5, "mc68328_r (%04x): CSD3(16) = %04x\n", mem_mask, m_regs.csd3 >> 16); + return m_regs.csd3 >> 16; + + case 0x200: + verboselog(machine(), 2, "mc68328_r (%04x): PLLCR = %04x\n", mem_mask, m_regs.pllcr); + return m_regs.pllcr; + + case 0x202: + verboselog(machine(), 2, "mc68328_r (%04x): PLLFSR = %04x\n", mem_mask, m_regs.pllfsr); + m_regs.pllfsr ^= 0x8000; + return m_regs.pllfsr; + + case 0x206: + if (mem_mask & 0x00ff) + { + verboselog(machine(), 2, "mc68328_r (%04x): Unknown address (0xfff206)\n", mem_mask); + } + else + { + verboselog(machine(), 2, "mc68328_r (%04x): PCTLR = %02x\n", mem_mask, m_regs.pctlr); + return m_regs.pctlr << 8; + } + break; + + case 0x300: + if (mem_mask & 0x00ff) + { + verboselog(machine(), 2, "mc68328_r (%04x): Unknown address (0xfff301)\n", mem_mask); + } + else + { + verboselog(machine(), 2, "mc68328_r (%04x): IVR = %02x\n", mem_mask, m_regs.ivr); + return m_regs.ivr << 8; + } + break; + + case 0x302: + verboselog(machine(), 2, "mc68328_r (%04x): ICR = %04x\n", mem_mask, m_regs.icr); + return m_regs.icr; + + case 0x304: + verboselog(machine(), 2, "mc68328_r (%04x): IMR(16) = %04x\n", mem_mask, m_regs.imr >> 16); + return m_regs.imr >> 16; + + case 0x306: + verboselog(machine(), 2, "mc68328_r (%04x): IMR(0) = %04x\n", mem_mask, m_regs.imr & 0x0000ffff); + return m_regs.imr & 0x0000ffff; + + case 0x308: + verboselog(machine(), 2, "mc68328_r (%04x): IWR(16) = %04x\n", mem_mask, m_regs.iwr >> 16); + return m_regs.iwr >> 16; + + case 0x30a: + verboselog(machine(), 2, "mc68328_r (%04x): IWR(0) = %04x\n", mem_mask, m_regs.iwr & 0x0000ffff); + return m_regs.iwr & 0x0000ffff; + + case 0x30c: + verboselog(machine(), 2, "mc68328_r (%04x): ISR(16) = %04x\n", mem_mask, m_regs.isr >> 16); + return m_regs.isr >> 16; + + case 0x30e: + verboselog(machine(), 2, "mc68328_r (%04x): ISR(0) = %04x\n", mem_mask, m_regs.isr & 0x0000ffff); + return m_regs.isr & 0x0000ffff; + + case 0x310: + verboselog(machine(), 2, "mc68328_r (%04x): IPR(16) = %04x\n", mem_mask, m_regs.ipr >> 16); + return m_regs.ipr >> 16; + + case 0x312: + verboselog(machine(), 2, "mc68328_r (%04x): IPR(0) = %04x\n", mem_mask, m_regs.ipr & 0x0000ffff); + return m_regs.ipr & 0x0000ffff; + + case 0x400: + if (mem_mask & 0x00ff) + { + verboselog(machine(), 2, "mc68328_r (%04x): PADATA = %02x\n", mem_mask, m_regs.padata); + if (!m_in_port_a_cb.isnull()) + { + return m_in_port_a_cb(0); + } + else + { + return m_regs.padata; + } + } + else + { + verboselog(machine(), 2, "mc68328_r (%04x): PADIR = %02x\n", mem_mask, m_regs.padir); + return m_regs.padir << 8; + } + + case 0x402: + if (mem_mask & 0x00ff) + { + verboselog(machine(), 2, "mc68328_r (%04x): PASEL = %02x\n", mem_mask, m_regs.pasel); + return m_regs.pasel; + } + else + { + verboselog(machine(), 2, "mc68328_r (%04x): Unknown address (0xfff402)\n", mem_mask); + } + break; + + case 0x408: + if (mem_mask & 0x00ff) + { + verboselog(machine(), 2, "mc68328_r (%04x): PBDATA = %02x\n", mem_mask, m_regs.pbdata); + if (!m_in_port_b_cb.isnull()) + { + return m_in_port_b_cb(0); + } + else + { + return m_regs.pbdata; + } + } + else + { + verboselog(machine(), 2, "mc68328_r (%04x): PBDIR = %02x\n", mem_mask, m_regs.pbdir); + return m_regs.pbdir << 8; + } + + case 0x40a: + if (mem_mask & 0x00ff) + { + verboselog(machine(), 2, "mc68328_r (%04x): PBSEL = %02x\n", mem_mask, m_regs.pbsel); + return m_regs.pbsel; + } + else + { + verboselog(machine(), 2, "mc68328_r (%04x): Unknown address (0xfff40a)\n", mem_mask); + } + break; + + case 0x410: + if (mem_mask & 0x00ff) + { + verboselog(machine(), 2, "mc68328_r (%04x): PCDATA = %02x\n", mem_mask, m_regs.pcdata); + if (!m_in_port_c_cb.isnull()) + { + return m_in_port_c_cb(0); + } + else + { + return m_regs.pcdata; + } + } + else + { + verboselog(machine(), 2, "mc68328_r (%04x): PCDIR = %02x\n", mem_mask, m_regs.pcdir); + return m_regs.pcdir << 8; + } + + case 0x412: + if (mem_mask & 0x00ff) + { + verboselog(machine(), 2, "mc68328_r (%04x): PCSEL = %02x\n", mem_mask, m_regs.pcsel); + return m_regs.pcsel; + } + else + { + verboselog(machine(), 2, "mc68328_r (%04x): Unknown address (0xfff412)\n", mem_mask); + } + break; + + case 0x418: + if (mem_mask & 0x00ff) + { + verboselog(machine(), 2, "mc68328_r (%04x): PDDATA = %02x\n", mem_mask, m_regs.pddata); + if (!m_in_port_d_cb.isnull()) + { + return m_in_port_d_cb(0); + } + else + { + return m_regs.pddata; + } + } + else + { + verboselog(machine(), 2, "mc68328_r (%04x): PDDIR = %02x\n", mem_mask, m_regs.pddir); + return m_regs.pddir << 8; + } + + case 0x41a: + if (mem_mask & 0x00ff) + { + verboselog(machine(), 2, "mc68328_r (%04x): Unknown address (0xfff41b)\n", mem_mask); + } + else + { + verboselog(machine(), 2, "mc68328_r (%04x): PDPUEN = %02x\n", mem_mask, m_regs.pdpuen); + return m_regs.pdpuen << 8; + } + break; + + case 0x41c: + if (mem_mask & 0x00ff) + { + verboselog(machine(), 2, "mc68328_r (%04x): PDIRQEN = %02x\n", mem_mask, m_regs.pdirqen); + return m_regs.pdirqen; + } + else + { + verboselog(machine(), 2, "mc68328_r (%04x): PDPOL = %02x\n", mem_mask, m_regs.pdpol); + return m_regs.pdpol << 8; + } + + case 0x41e: + if (mem_mask & 0x00ff) + { + verboselog(machine(), 2, "mc68328_r (%04x): PDIRQEDGE = %02x\n", mem_mask, m_regs.pdirqedge); + return m_regs.pdirqedge; + } + else + { + verboselog(machine(), 2, "mc68328_r (%04x): Unknown address (0xfff41e)\n", mem_mask); + } + break; + + case 0x420: + if (mem_mask & 0x00ff) + { + verboselog(machine(), 2, "mc68328_r (%04x): PEDATA = %02x\n", mem_mask, m_regs.pedata); + if (!m_in_port_e_cb.isnull()) + { + return m_in_port_e_cb(0); + } + else + { + return m_regs.pedata; + } + } + else + { + verboselog(machine(), 2, "mc68328_r (%04x): PEDIR = %02x\n", mem_mask, m_regs.pedir); + return m_regs.pedir << 8; + } + + case 0x422: + if (mem_mask & 0x00ff) + { + verboselog(machine(), 2, "mc68328_r (%04x): PESEL = %02x\n", mem_mask, m_regs.pesel); + return m_regs.pesel; + } + else + { + verboselog(machine(), 2, "mc68328_r (%04x): PEPUEN = %02x\n", mem_mask, m_regs.pepuen); + return m_regs.pepuen << 8; + } + + case 0x428: + if (mem_mask & 0x00ff) + { + verboselog(machine(), 2, "mc68328_r (%04x): PFDATA = %02x\n", mem_mask, m_regs.pfdata); + if (!m_in_port_f_cb.isnull()) + { + return m_in_port_f_cb(0); + } + else + { + return m_regs.pfdata; + } + } + else + { + verboselog(machine(), 2, "mc68328_r (%04x): PFDIR = %02x\n", mem_mask, m_regs.pfdir); + return m_regs.pfdir << 8; + } + + case 0x42a: + if (mem_mask & 0x00ff) + { + verboselog(machine(), 2, "mc68328_r (%04x): PFSEL = %02x\n", mem_mask, m_regs.pfsel); + return m_regs.pfsel; + } + else + { + verboselog(machine(), 2, "mc68328_r (%04x): PFPUEN = %02x\n", mem_mask, m_regs.pfpuen); + return m_regs.pfpuen << 8; + } + + case 0x430: + if (mem_mask & 0x00ff) + { + verboselog(machine(), 2, "mc68328_r (%04x): PGDATA = %02x\n", mem_mask, m_regs.pgdata); + if (!m_in_port_g_cb.isnull()) + { + return m_in_port_g_cb(0); + } + else + { + return m_regs.pgdata; + } + } + else + { + verboselog(machine(), 2, "mc68328_r (%04x): PGDIR = %02x\n", mem_mask, m_regs.pgdir); + return m_regs.pgdir << 8; + } + + case 0x432: + if (mem_mask & 0x00ff) + { + verboselog(machine(), 2, "mc68328_r (%04x): PGSEL = %02x\n", mem_mask, m_regs.pgsel); + return m_regs.pgsel; + } + else + { + verboselog(machine(), 2, "mc68328_r (%04x): PGPUEN = %02x\n", mem_mask, m_regs.pgpuen); + return m_regs.pgpuen << 8; + } + + case 0x438: + if (mem_mask & 0x00ff) + { + verboselog(machine(), 2, "mc68328_r (%04x): PJDATA = %02x\n", mem_mask, m_regs.pjdata); + if (!m_in_port_j_cb.isnull()) + { + return m_in_port_j_cb(0); + } + else + { + return m_regs.pjdata; + } + } + else + { + verboselog(machine(), 2, "mc68328_r (%04x): PJDIR = %02x\n", mem_mask, m_regs.pjdir); + return m_regs.pjdir << 8; + } + + case 0x43a: + if (mem_mask & 0x00ff) + { + verboselog(machine(), 2, "mc68328_r (%04x): PJSEL = %02x\n", mem_mask, m_regs.pjsel); + return m_regs.pjsel; + } + else + { + verboselog(machine(), 2, "mc68328_r (%04x): Unknown address (0xfff43a)\n", mem_mask); + } + break; + + case 0x440: + if (mem_mask & 0x00ff) + { + verboselog(machine(), 2, "mc68328_r (%04x): PKDATA = %02x\n", mem_mask, m_regs.pkdata); + if (!m_in_port_k_cb.isnull()) + { + return m_in_port_k_cb(0); + } + else + { + return m_regs.pkdata; + } + } + else + { + verboselog(machine(), 2, "mc68328_r (%04x): PKDIR = %02x\n", mem_mask, m_regs.pkdir); + return m_regs.pkdir << 8; + } + + case 0x442: + if (mem_mask & 0x00ff) + { + verboselog(machine(), 2, "mc68328_r (%04x): PKSEL = %02x\n", mem_mask, m_regs.pksel); + return m_regs.pksel; + } + else + { + verboselog(machine(), 2, "mc68328_r (%04x): PKPUEN = %02x\n", mem_mask, m_regs.pkpuen); + return m_regs.pkpuen << 8; + } + + case 0x448: + if (mem_mask & 0x00ff) + { + verboselog(machine(), 2, "mc68328_r (%04x): PMDATA = %02x\n", mem_mask, m_regs.pmdata); + if (!m_in_port_m_cb.isnull()) + { + return m_in_port_m_cb(0); + } + else + { + return m_regs.pmdata; + } + } + else + { + verboselog(machine(), 2, "mc68328_r (%04x): PMDIR = %02x\n", mem_mask, m_regs.pmdir); + return m_regs.pmdir << 8; + } + + case 0x44a: + if (mem_mask & 0x00ff) + { + verboselog(machine(), 2, "mc68328_r (%04x): PMSEL = %02x\n", mem_mask, m_regs.pmsel); + return m_regs.pmsel; + } + else + { + verboselog(machine(), 2, "mc68328_r (%04x): PMPUEN = %02x\n", mem_mask, m_regs.pmpuen); + return m_regs.pmpuen << 8; + } + + case 0x500: + verboselog(machine(), 2, "mc68328_r (%04x): PWMC = %04x\n", mem_mask, m_regs.pwmc); + temp16 = m_regs.pwmc; + if (m_regs.pwmc & PWMC_PWMIRQ) + { + m_regs.pwmc &= ~PWMC_PWMIRQ; + set_interrupt_line(INT_PWM, 0); + } + return temp16; + + case 0x502: + verboselog(machine(), 2, "mc68328_r (%04x): PWMP = %04x\n", mem_mask, m_regs.pwmp); + return m_regs.pwmp; + + case 0x504: + verboselog(machine(), 2, "mc68328_r (%04x): PWMW = %04x\n", mem_mask, m_regs.pwmw); + return m_regs.pwmw; + + case 0x506: + verboselog(machine(), 2, "mc68328_r (%04x): PWMCNT = %04x\n", mem_mask, m_regs.pwmcnt); + return m_regs.pwmcnt; + + case 0x600: + verboselog(machine(), 2, "mc68328_r (%04x): TCTL1 = %04x\n", mem_mask, m_regs.tctl[0]); + return m_regs.tctl[0]; + + case 0x602: + verboselog(machine(), 2, "mc68328_r (%04x): TPRER1 = %04x\n", mem_mask, m_regs.tprer[0]); + return m_regs.tprer[0]; + + case 0x604: + verboselog(machine(), 2, "mc68328_r (%04x): TCMP1 = %04x\n", mem_mask, m_regs.tcmp[0]); + return m_regs.tcmp[0]; + + case 0x606: + verboselog(machine(), 2, "mc68328_r (%04x): TCR1 = %04x\n", mem_mask, m_regs.tcr[0]); + return m_regs.tcr[0]; + + case 0x608: + verboselog(machine(), 2, "mc68328_r (%04x): TCN1 = %04x\n", mem_mask, m_regs.tcn[0]); + return m_regs.tcn[0]; + + case 0x60a: + verboselog(machine(), 5, "mc68328_r (%04x): TSTAT1 = %04x\n", mem_mask, m_regs.tstat[0]); + m_regs.tclear[0] |= m_regs.tstat[0]; + return m_regs.tstat[0]; + + case 0x60c: + verboselog(machine(), 2, "mc68328_r (%04x): TCTL2 = %04x\n", mem_mask, m_regs.tctl[1]); + return m_regs.tctl[1]; + + case 0x60e: + verboselog(machine(), 2, "mc68328_r (%04x): TPREP2 = %04x\n", mem_mask, m_regs.tprer[1]); + return m_regs.tprer[1]; + + case 0x610: + verboselog(machine(), 2, "mc68328_r (%04x): TCMP2 = %04x\n", mem_mask, m_regs.tcmp[1]); + return m_regs.tcmp[1]; + + case 0x612: + verboselog(machine(), 2, "mc68328_r (%04x): TCR2 = %04x\n", mem_mask, m_regs.tcr[1]); + return m_regs.tcr[1]; + + case 0x614: + verboselog(machine(), 2, "mc68328_r (%04x): TCN2 = %04x\n", mem_mask, m_regs.tcn[1]); + return m_regs.tcn[1]; + + case 0x616: + verboselog(machine(), 2, "mc68328_r (%04x): TSTAT2 = %04x\n", mem_mask, m_regs.tstat[1]); + m_regs.tclear[1] |= m_regs.tstat[1]; + return m_regs.tstat[1]; + + case 0x618: + verboselog(machine(), 2, "mc68328_r (%04x): WCTLR = %04x\n", mem_mask, m_regs.wctlr); + return m_regs.wctlr; + + case 0x61a: + verboselog(machine(), 2, "mc68328_r (%04x): WCMPR = %04x\n", mem_mask, m_regs.wcmpr); + return m_regs.wcmpr; + + case 0x61c: + verboselog(machine(), 2, "mc68328_r (%04x): WCN = %04x\n", mem_mask, m_regs.wcn); + return m_regs.wcn; + + case 0x700: + verboselog(machine(), 2, "mc68328_r (%04x): SPISR = %04x\n", mem_mask, m_regs.spisr); + return m_regs.spisr; + + case 0x800: + verboselog(machine(), 2, "mc68328_r (%04x): SPIMDATA = %04x\n", mem_mask, m_regs.spimdata); + if (!m_in_spim_cb.isnull()) + { + return m_in_spim_cb(0, 0xffff); + } + return m_regs.spimdata; + + case 0x802: + verboselog(machine(), 2, "mc68328_r (%04x): SPIMCONT = %04x\n", mem_mask, m_regs.spimcont); + if (m_regs.spimcont & SPIM_XCH) + { + m_regs.spimcont &= ~SPIM_XCH; + m_regs.spimcont |= SPIM_SPIMIRQ; + return ((m_regs.spimcont | SPIM_XCH) &~ SPIM_SPIMIRQ); + } + return m_regs.spimcont; + + case 0x900: + verboselog(machine(), 2, "mc68328_r (%04x): USTCNT = %04x\n", mem_mask, m_regs.ustcnt); + return m_regs.ustcnt; + + case 0x902: + verboselog(machine(), 2, "mc68328_r (%04x): UBAUD = %04x\n", mem_mask, m_regs.ubaud); + return m_regs.ubaud; + + case 0x904: + verboselog(machine(), 5, "mc68328_r (%04x): URX = %04x\n", mem_mask, m_regs.urx); + return m_regs.urx; + + case 0x906: + verboselog(machine(), 5, "mc68328_r (%04x): UTX = %04x\n", mem_mask, m_regs.utx); + return m_regs.utx | UTX_FIFO_EMPTY | UTX_FIFO_HALF | UTX_TX_AVAIL; + + case 0x908: + verboselog(machine(), 2, "mc68328_r (%04x): UMISC = %04x\n", mem_mask, m_regs.umisc); + return m_regs.umisc; + + case 0xa00: + verboselog(machine(), 2, "mc68328_r (%04x): LSSA(16) = %04x\n", mem_mask, m_regs.lssa >> 16); + return m_regs.lssa >> 16; + + case 0xa02: + verboselog(machine(), 2, "mc68328_r (%04x): LSSA(0) = %04x\n", mem_mask, m_regs.lssa & 0x0000ffff); + return m_regs.lssa & 0x0000ffff; + + case 0xa04: + if (mem_mask & 0x00ff) + { + verboselog(machine(), 2, "mc68328_r (%04x): LVPW = %02x\n", mem_mask, m_regs.lvpw); + return m_regs.lvpw; + } + else + { + verboselog(machine(), 2, "mc68328_r (%04x): Unknown address (0xfffa04)\n", mem_mask); + } + break; + + case 0xa08: + verboselog(machine(), 2, "mc68328_r (%04x): LXMAX = %04x\n", mem_mask, m_regs.lxmax); + return m_regs.lxmax; + + case 0xa0a: + verboselog(machine(), 2, "mc68328_r (%04x): LYMAX = %04x\n", mem_mask, m_regs.lymax); + return m_regs.lymax; + + case 0xa18: + verboselog(machine(), 2, "mc68328_r (%04x): LCXP = %04x\n", mem_mask, m_regs.lcxp); + return m_regs.lcxp; + + case 0xa1a: + verboselog(machine(), 2, "mc68328_r (%04x): LCYP = %04x\n", mem_mask, m_regs.lcyp); + return m_regs.lcyp; + + case 0xa1c: + verboselog(machine(), 2, "mc68328_r (%04x): LCWCH = %04x\n", mem_mask, m_regs.lcwch); + return m_regs.lcwch; + + case 0xa1e: + if (mem_mask & 0x00ff) + { + verboselog(machine(), 2, "mc68328_r (%04x): LBLKC = %02x\n", mem_mask, m_regs.lblkc); + return m_regs.lblkc; + } + else + { + verboselog(machine(), 2, "mc68328_r (%04x): Unknown address (0xfffa1e)\n", mem_mask); + } + break; + + case 0xa20: + if (mem_mask & 0x00ff) + { + verboselog(machine(), 2, "mc68328_r (%04x): LPOLCF = %02x\n", mem_mask, m_regs.lpolcf); + return m_regs.lpolcf; + } + else + { + verboselog(machine(), 2, "mc68328_r (%04x): LPICF = %02x\n", mem_mask, m_regs.lpicf); + return m_regs.lpicf << 8; + } + + case 0xa22: + if (mem_mask & 0x00ff) + { + verboselog(machine(), 2, "mc68328_r (%04x): LACDRC = %02x\n", mem_mask, m_regs.lacdrc); + return m_regs.lacdrc; + } + else + { + verboselog(machine(), 2, "mc68328_r (%04x): Unknown address (0xfffa22)\n", mem_mask); + } + break; + + case 0xa24: + if (mem_mask & 0x00ff) + { + verboselog(machine(), 2, "mc68328_r (%04x): LPXCD = %02x\n", mem_mask, m_regs.lpxcd); + return m_regs.lpxcd; + } + else + { + verboselog(machine(), 2, "mc68328_r (%04x): Unknown address (0xfffa24)\n", mem_mask); + } + break; + + case 0xa26: + if (mem_mask & 0x00ff) + { + verboselog(machine(), 2, "mc68328_r (%04x): LCKCON = %02x\n", mem_mask, m_regs.lckcon); + return m_regs.lckcon; + } + else + { + verboselog(machine(), 2, "mc68328_r (%04x): Unknown address (0xfffa26)\n", mem_mask); + } + break; + + case 0xa28: + if (mem_mask & 0x00ff) + { + verboselog(machine(), 2, "mc68328_r (%04x): LLBAR = %02x\n", mem_mask, m_regs.llbar); + return m_regs.llbar; + } + else + { + verboselog(machine(), 2, "mc68328_r (%04x): Unknown address (0xfffa28)\n", mem_mask); + } + break; + + case 0xa2a: + if (mem_mask & 0x00ff) + { + verboselog(machine(), 2, "mc68328_r (%04x): LOTCR = %02x\n", mem_mask, m_regs.lotcr); + return m_regs.lotcr; + } + else + { + verboselog(machine(), 2, "mc68328_r (%04x): Unknown address (0xfffa2a)\n", mem_mask); + } + break; + + case 0xa2c: + if (mem_mask & 0x00ff) + { + verboselog(machine(), 2, "mc68328_r (%04x): LPOSR = %02x\n", mem_mask, m_regs.lposr); + return m_regs.lposr; + } + else + { + verboselog(machine(), 2, "mc68328_r (%04x): Unknown address (0xfffa2c)\n", mem_mask); + } + break; + + case 0xa30: + if (mem_mask & 0x00ff) + { + verboselog(machine(), 2, "mc68328_r (%04x): LFRCM = %02x\n", mem_mask, m_regs.lfrcm); + return m_regs.lfrcm; + } + else + { + verboselog(machine(), 2, "mc68328_r (%04x): Unknown address (0xfffa30)\n", mem_mask); + } + break; + + case 0xa32: + verboselog(machine(), 2, "mc68328_r (%04x): LGPMR = %04x\n", mem_mask, m_regs.lgpmr); + return m_regs.lgpmr; + + case 0xb00: + verboselog(machine(), 2, "mc68328_r (%04x): HMSR(0) = %04x\n", mem_mask, m_regs.hmsr & 0x0000ffff); + return m_regs.hmsr & 0x0000ffff; + + case 0xb02: + verboselog(machine(), 2, "mc68328_r (%04x): HMSR(16) = %04x\n", mem_mask, m_regs.hmsr >> 16); + return m_regs.hmsr >> 16; + + case 0xb04: + verboselog(machine(), 2, "mc68328_r (%04x): ALARM(0) = %04x\n", mem_mask, m_regs.alarm & 0x0000ffff); + return m_regs.alarm & 0x0000ffff; + + case 0xb06: + verboselog(machine(), 2, "mc68328_r (%04x): ALARM(16) = %04x\n", mem_mask, m_regs.alarm >> 16); + return m_regs.alarm >> 16; + + case 0xb0c: + verboselog(machine(), 2, "mc68328_r (%04x): RTCCTL = %04x\n", mem_mask, m_regs.rtcctl); + return m_regs.rtcctl; + + case 0xb0e: + verboselog(machine(), 2, "mc68328_r (%04x): RTCISR = %04x\n", mem_mask, m_regs.rtcisr); + return m_regs.rtcisr; + + case 0xb10: + verboselog(machine(), 2, "mc68328_r (%04x): RTCIENR = %04x\n", mem_mask, m_regs.rtcienr); + return m_regs.rtcienr; + + case 0xb12: + verboselog(machine(), 2, "mc68328_r (%04x): STPWTCH = %04x\n", mem_mask, m_regs.stpwtch); + return m_regs.stpwtch; + + default: + verboselog(machine(), 0, "mc68328_r (%04x): Unknown address (0x%06x)\n", mem_mask, 0xfff000 + address); + break; + } + return 0; +} + +/* THIS IS PRETTY MUCH TOTALLY WRONG AND DOESN'T REFLECT THE MC68328'S INTERNAL FUNCTIONALITY AT ALL! */ +UINT32 mc68328_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) +{ + UINT16 *video_ram = (UINT16 *)(machine().device(RAM_TAG)->pointer() + (m_regs.lssa & 0x00ffffff)); + UINT16 word; + UINT16 *line; + int y, x, b; + + if (m_regs.lckcon & LCKCON_LCDC_EN) + { + for (y = 0; y < 160; y++) + { + line = &bitmap.pix16(y); + + for (x = 0; x < 160; x += 16) + { + word = *(video_ram++); + for (b = 0; b < 16; b++) + { + line[x + b] = (word >> (15 - b)) & 0x0001; + } + } + } + } + else + { + for (y = 0; y < 160; y++) + { + line = &bitmap.pix16(y); + + for (x = 0; x < 160; x++) + { + line[x] = 0; + } + } + } + return 0; +} + + +void mc68328_device::register_state_save() +{ + save_item(NAME(m_regs.scr)); + save_item(NAME(m_regs.grpbasea)); + save_item(NAME(m_regs.grpbaseb)); + save_item(NAME(m_regs.grpbasec)); + save_item(NAME(m_regs.grpbased)); + save_item(NAME(m_regs.grpmaska)); + save_item(NAME(m_regs.grpmaskb)); + save_item(NAME(m_regs.grpmaskc)); + save_item(NAME(m_regs.grpmaskd)); + save_item(NAME(m_regs.csa0)); + save_item(NAME(m_regs.csa1)); + save_item(NAME(m_regs.csa2)); + save_item(NAME(m_regs.csa3)); + save_item(NAME(m_regs.csb0)); + save_item(NAME(m_regs.csb1)); + save_item(NAME(m_regs.csb2)); + save_item(NAME(m_regs.csb3)); + save_item(NAME(m_regs.csc0)); + save_item(NAME(m_regs.csc1)); + save_item(NAME(m_regs.csc2)); + save_item(NAME(m_regs.csc3)); + save_item(NAME(m_regs.csd0)); + save_item(NAME(m_regs.csd1)); + save_item(NAME(m_regs.csd2)); + save_item(NAME(m_regs.csd3)); + + save_item(NAME(m_regs.pllcr)); + save_item(NAME(m_regs.pllfsr)); + save_item(NAME(m_regs.pctlr)); + + save_item(NAME(m_regs.ivr)); + save_item(NAME(m_regs.icr)); + save_item(NAME(m_regs.imr)); + save_item(NAME(m_regs.iwr)); + save_item(NAME(m_regs.isr)); + save_item(NAME(m_regs.ipr)); + + save_item(NAME(m_regs.padir)); + save_item(NAME(m_regs.padata)); + save_item(NAME(m_regs.pasel)); + save_item(NAME(m_regs.pbdir)); + save_item(NAME(m_regs.pbdata)); + save_item(NAME(m_regs.pbsel)); + save_item(NAME(m_regs.pcdir)); + save_item(NAME(m_regs.pcdata)); + save_item(NAME(m_regs.pcsel)); + save_item(NAME(m_regs.pddir)); + save_item(NAME(m_regs.pddata)); + save_item(NAME(m_regs.pdpuen)); + save_item(NAME(m_regs.pdpol)); + save_item(NAME(m_regs.pdirqen)); + save_item(NAME(m_regs.pddataedge)); + save_item(NAME(m_regs.pdirqedge)); + save_item(NAME(m_regs.pedir)); + save_item(NAME(m_regs.pedata)); + save_item(NAME(m_regs.pepuen)); + save_item(NAME(m_regs.pesel)); + save_item(NAME(m_regs.pfdir)); + save_item(NAME(m_regs.pfdata)); + save_item(NAME(m_regs.pfpuen)); + save_item(NAME(m_regs.pfsel)); + save_item(NAME(m_regs.pgdir)); + save_item(NAME(m_regs.pgdata)); + save_item(NAME(m_regs.pgpuen)); + save_item(NAME(m_regs.pgsel)); + save_item(NAME(m_regs.pjdir)); + save_item(NAME(m_regs.pjdata)); + save_item(NAME(m_regs.pjsel)); + save_item(NAME(m_regs.pkdir)); + save_item(NAME(m_regs.pkdata)); + save_item(NAME(m_regs.pkpuen)); + save_item(NAME(m_regs.pksel)); + save_item(NAME(m_regs.pmdir)); + save_item(NAME(m_regs.pmdata)); + save_item(NAME(m_regs.pmpuen)); + save_item(NAME(m_regs.pmsel)); + + save_item(NAME(m_regs.pwmc)); + save_item(NAME(m_regs.pwmp)); + save_item(NAME(m_regs.pwmw)); + save_item(NAME(m_regs.pwmcnt)); + + save_item(NAME(m_regs.tctl[0])); + save_item(NAME(m_regs.tctl[1])); + save_item(NAME(m_regs.tprer[0])); + save_item(NAME(m_regs.tprer[1])); + save_item(NAME(m_regs.tcmp[0])); + save_item(NAME(m_regs.tcmp[1])); + save_item(NAME(m_regs.tcr[0])); + save_item(NAME(m_regs.tcr[1])); + save_item(NAME(m_regs.tcn[0])); + save_item(NAME(m_regs.tcn[1])); + save_item(NAME(m_regs.tstat[0])); + save_item(NAME(m_regs.tstat[1])); + save_item(NAME(m_regs.wctlr)); + save_item(NAME(m_regs.wcmpr)); + save_item(NAME(m_regs.wcn)); + + save_item(NAME(m_regs.spisr)); + + save_item(NAME(m_regs.spimdata)); + save_item(NAME(m_regs.spimcont)); + + save_item(NAME(m_regs.ustcnt)); + save_item(NAME(m_regs.ubaud)); + save_item(NAME(m_regs.urx)); + save_item(NAME(m_regs.utx)); + save_item(NAME(m_regs.umisc)); + + save_item(NAME(m_regs.lssa)); + save_item(NAME(m_regs.lvpw)); + save_item(NAME(m_regs.lxmax)); + save_item(NAME(m_regs.lymax)); + save_item(NAME(m_regs.lcxp)); + save_item(NAME(m_regs.lcyp)); + save_item(NAME(m_regs.lcwch)); + save_item(NAME(m_regs.lblkc)); + save_item(NAME(m_regs.lpicf)); + save_item(NAME(m_regs.lpolcf)); + save_item(NAME(m_regs.lacdrc)); + save_item(NAME(m_regs.lpxcd)); + save_item(NAME(m_regs.lckcon)); + save_item(NAME(m_regs.llbar)); + save_item(NAME(m_regs.lotcr)); + save_item(NAME(m_regs.lposr)); + save_item(NAME(m_regs.lfrcm)); + save_item(NAME(m_regs.lgpmr)); + + save_item(NAME(m_regs.hmsr)); + save_item(NAME(m_regs.alarm)); + save_item(NAME(m_regs.rtcctl)); + save_item(NAME(m_regs.rtcisr)); + save_item(NAME(m_regs.rtcienr)); + save_item(NAME(m_regs.stpwtch)); +} diff --git a/src/devices/machine/mc68328.h b/src/devices/machine/mc68328.h new file mode 100644 index 00000000000..da680dae32b --- /dev/null +++ b/src/devices/machine/mc68328.h @@ -0,0 +1,784 @@ +// license:BSD-3-Clause +// copyright-holders:Ryan Holtz +/********************************************************************** + + Motorola 68328 ("DragonBall") System-on-a-Chip implementation + + By MooglyGuy + contact mooglyguy@gmail.com with licensing and usage questions. + + **********************************************************************/ + +/***************************************************************************************************************** + + P P P P P P P P P P P P P P + E E E E E E E J J J J J J J + 1 2 3 4 5 6 7 0 1 2 3 4 5 6 + D D D D D / / / / / / / / / / / / / / + 3 4 5 6 7 ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! + / / / / / ! ! C C C C C C C C C C C C C C C + P V P P P P D D G D D D D T T L U V S S S S S S S S G S S S S S S S + B C B B B B D D 1 1 N 1 1 1 1 M C W W C A A A A B B B B N C C C C D D D + 3 C 4 5 6 7 8 9 0 1 D 2 3 4 5 S K E E C 0 1 2 3 0 1 2 3 D 0 1 2 3 0 1 2 + | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | + +-------------------------------------------------------------------------------+ + | | + | | + | | + | | + | | + D2/PB2--| |--PJ7/!CSD3 + D1/PB1--| |--VCC + D0/PB0--| |--PD0/!KBD0/!INT0 + TDO--| |--PD1/!KBD1/!INT1 + TDI--| |--PD2/!KBD2/!INT2 + GND--| |--PD3/!KBD3/!INT3 + !OE--| |--PD4/!KBD4/!INT4 + !UDS/PC1--| |--PD5/!KBD5/!INT5 + !AS--| |--PD6/!KBD6/!INT6 + A0--| |--PD7/!KBD7/!INT7 + !LDS--| |--GND + R/!W--| |--LD0 + !DTACK/PC5--| |--LD1 + !RESET--| |--LD2 + VCC--| |--LD3 + !WE/PC6--| |--LFRM + !JTAGRST--| |--LLP + BBUSW--| MC68328PV |--LCLK + A1--| TOP VIEW |--LACD + A2--| |--VCC + A3--| |--PK0/SPMTXD0 + A4--| |--PK1/SPMRXD0 + A5--| |--PK2/SPMCLK0 + A6--| |--PK3/SPSEN + GND--| |--PK4/SPSRXD1 + A7--| |--PK5/SPSCLK1 + A8--| |--PK6/!CE2 + A9--| |--PK7/!CE1 + A10--| |--GND + A11--| |--PM0/!CTS + A12--| |--PM1/!RTS + A13--| |--PM2/!IRQ6 + A14--| |--PM3/!IRQ3 + VCC--| |--PM4/!IRQ2 + A15--| |--PM5/!IRQ1 + A16/PA0--| |--PM6/!PENIRQ + | | + | _ | + | (_) | + |\ | + | \ | + +-------------------------------------------------------------------------------+ + | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | + P P P P P G P P P P P P P P V P P P P P P P P G P P P V C G P P P E X P + A A A A A N A A F F F F F F C F F G G G G G G N G G C C L N C M L X T L + 1 2 3 4 5 D 6 7 0 1 2 3 4 5 C 6 7 7 6 5 4 3 2 D 1 0 0 C K D 4 7 L T A L + / / / / / / / / / / / / / / / / / / / / / / / / O / / G A L V + A A A A A A A A A A A A A A A R T ! T ! P R T M ! U N L C + 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 T I T I T W X X O I A D C + 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 C N O N O M D D C R R + O 1 U 2 U O L Q T + T T K 7 G + 1 2 P + I + O + + Figure 12-1. MC68328 144-Lead Plastic Thin-Quad Flat Pack Pin Assignment + + Source: MC68328 (DragonBall)(tm) Integrated Processor User's Manual + + *****************************************************************************************************************/ + +#ifndef __MC68328_H__ +#define __MC68328_H__ + + +#define SCR_BETO 0x80 +#define SCR_WPV 0x40 +#define SCR_PRV 0x20 +#define SCR_BETEN 0x10 +#define SCR_SO 0x08 +#define SCR_DMAP 0x04 +#define SCR_WDTH8 0x01 + +#define ICR_POL6 0x0100 +#define ICR_POL3 0x0200 +#define ICR_POL2 0x0400 +#define ICR_POL1 0x0800 +#define ICR_ET6 0x1000 +#define ICR_ET3 0x2000 +#define ICR_ET2 0x4000 +#define ICR_ET1 0x8000 + +#define INT_SPIM 0x000001 +#define INT_TIMER2 0x000002 +#define INT_UART 0x000004 +#define INT_WDT 0x000008 +#define INT_RTC 0x000010 +#define INT_RESERVED 0x000020 +#define INT_KB 0x000040 +#define INT_PWM 0x000080 +#define INT_INT0 0x000100 +#define INT_INT1 0x000200 +#define INT_INT2 0x000400 +#define INT_INT3 0x000800 +#define INT_INT4 0x001000 +#define INT_INT5 0x002000 +#define INT_INT6 0x004000 +#define INT_INT7 0x008000 +#define INT_KBDINTS 0x00ff00 +#define INT_IRQ1 0x010000 +#define INT_IRQ2 0x020000 +#define INT_IRQ3 0x040000 +#define INT_IRQ6 0x080000 +#define INT_PEN 0x100000 +#define INT_SPIS 0x200000 +#define INT_TIMER1 0x400000 +#define INT_IRQ7 0x800000 + +#define INT_M68K_LINE1 (INT_IRQ1) +#define INT_M68K_LINE2 (INT_IRQ2) +#define INT_M68K_LINE3 (INT_IRQ3) +#define INT_M68K_LINE4 (INT_INT0 | INT_INT1 | INT_INT2 | INT_INT3 | INT_INT4 | INT_INT5 | INT_INT6 | INT_INT7 | \ + INT_PWM | INT_KB | INT_RTC | INT_WDT | INT_UART | INT_TIMER2 | INT_SPIM) +#define INT_M68K_LINE5 (INT_PEN) +#define INT_M68K_LINE6 (INT_IRQ6 | INT_TIMER1 | INT_SPIS) +#define INT_M68K_LINE7 (INT_IRQ7) +#define INT_M68K_LINE67 (INT_M68K_LINE6 | INT_M68K_LINE7) +#define INT_M68K_LINE567 (INT_M68K_LINE5 | INT_M68K_LINE6 | INT_M68K_LINE7) +#define INT_M68K_LINE4567 (INT_M68K_LINE4 | INT_M68K_LINE5 | INT_M68K_LINE6 | INT_M68K_LINE7) +#define INT_M68K_LINE34567 (INT_M68K_LINE3 | INT_M68K_LINE4 | INT_M68K_LINE5 | INT_M68K_LINE6 | INT_M68K_LINE7) +#define INT_M68K_LINE234567 (INT_M68K_LINE2 | INT_M68K_LINE3 | INT_M68K_LINE4 | INT_M68K_LINE5 | INT_M68K_LINE6 | INT_M68K_LINE7) + +#define INT_IRQ1_SHIFT 0x000001 +#define INT_IRQ2_SHIFT 0x000002 +#define INT_IRQ3_SHIFT 0x000004 +#define INT_IRQ6_SHIFT 0x000008 +#define INT_PEN_SHIFT 0x000010 +#define INT_SPIS_SHIFT 0x000020 +#define INT_TIMER1_SHIFT 0x000040 +#define INT_IRQ7_SHIFT 0x000080 + +#define INT_ACTIVE 1 +#define INT_INACTIVE 0 + +#define GRPBASE_BASE_ADDR 0xfff0 +#define GRPBASE_VALID 0x0001 + +#define GRPMASK_BASE_MASK 0xfff0 + +#define CSAB_COMPARE 0xff000000 +#define CSAB_BSW 0x00010000 +#define CSAB_MASK 0x0000ff00 +#define CSAB_RO 0x00000008 +#define CSAB_WAIT 0x00000007 + +#define CSCD_COMPARE 0xfff00000 +#define CSCD_BSW 0x00010000 +#define CSCD_MASK 0x0000fff0 +#define CSCD_RO 0x00000008 +#define CSCD_WAIT 0x00000007 + +#define PLLCR_PIXCLK_SEL 0x3800 +#define PLLCR_PIXCLK_SEL_DIV2 0x0000 +#define PLLCR_PIXCLK_SEL_DIV4 0x0800 +#define PLLCR_PIXCLK_SEL_DIV8 0x1000 +#define PLLCR_PIXCLK_SEL_DIV16 0x1800 +#define PLLCR_PIXCLK_SEL_DIV1_0 0x2000 +#define PLLCR_PIXCLK_SEL_DIV1_1 0x2800 +#define PLLCR_PIXCLK_SEL_DIV1_2 0x3000 +#define PLLCR_PIXCLK_SEL_DIV1_3 0x3800 +#define PLLCR_SYSCLK_SEL 0x0700 +#define PLLCR_SYSCLK_SEL_DIV2 0x0000 +#define PLLCR_SYSCLK_SEL_DIV4 0x0100 +#define PLLCR_SYSCLK_SEL_DIV8 0x0200 +#define PLLCR_SYSCLK_SEL_DIV16 0x0300 +#define PLLCR_SYSCLK_SEL_DIV1_0 0x0400 +#define PLLCR_SYSCLK_SEL_DIV1_1 0x0500 +#define PLLCR_SYSCLK_SEL_DIV1_2 0x0600 +#define PLLCR_SYSCLK_SEL_DIV1_3 0x0700 +#define PLLCR_CLKEN 0x0010 +#define PLLCR_DISPLL 0x0008 + +#define PLLFSR_CLK32 0x8000 +#define PLLFSR_PROT 0x4000 +#define PLLFSR_QCNT 0x0f00 +#define PLLFSR_PCNT 0x00ff + +#define PCTLR_PC_EN 0x80 +#define PCTLR_STOP 0x40 +#define PCTLR_WIDTH 0x1f + +#define CXP_CC 0xc000 +#define CXP_CC_XLU 0x0000 +#define CXP_CC_BLACK 0x4000 +#define CXP_CC_INVERSE 0x8000 +#define CXP_CC_INVALID 0xc000 +#define CXP_MASK 0x03ff + +#define CYP_MASK 0x01ff + +#define CWCH_CW 0x1f00 +#define CWCH_CH 0x001f + +#define BLKC_BKEN 0x80 +#define BLKC_BD 0x7f + +#define LPICF_PBSIZ 0x06 +#define LPICF_PBSIZ_1 0x00 +#define LPICF_PBSIZ_2 0x02 +#define LPICF_PBSIZ_4 0x04 +#define LPICF_PBSIZ_INVALID 0x06 + +#define LPOLCF_LCKPOL 0x08 +#define LPOLCF_FLMPOL 0x04 +#define LPOLCF_LPPOL 0x02 +#define LPOLCF_PIXPOL 0x01 + +#define LACDRC_MASK 0x0f + +#define LPXCD_MASK 0x3f + +#define LCKCON_LCDC_EN 0x80 +#define LCKCON_LCDON 0x80 +#define LCKCON_DMA16 0x40 +#define LCKCON_WS 0x30 +#define LCKCON_WS_1 0x00 +#define LCKCON_WS_2 0x10 +#define LCKCON_WS_3 0x20 +#define LCKCON_WS_4 0x30 +#define LCKCON_DWIDTH 0x02 +#define LCKCON_PCDS 0x01 + +#define LBAR_MASK 0x7f + +#define LPOSR_BOS 0x08 +#define LPOSR_POS 0x07 + +#define LFRCM_XMOD 0xf0 +#define LFRCM_YMOD 0x0f + +#define LGPMR_PAL1 0x7000 +#define LGPMR_PAL0 0x0700 +#define LGPMR_PAL3 0x0070 +#define LGPMR_PAL2 0x0007 + +#define RTCHMSR_HOURS 0x1f000000 +#define RTCHMSR_MINUTES 0x003f0000 +#define RTCHMSR_SECONDS 0x0000003f + +#define RTCCTL_38_4 0x0020 +#define RTCCTL_ENABLE 0x0080 + +#define RTCINT_STOPWATCH 0x0001 +#define RTCINT_MINUTE 0x0002 +#define RTCINT_ALARM 0x0004 +#define RTCINT_DAY 0x0008 +#define RTCINT_SECOND 0x0010 + +#define RTCSTPWTCH_MASK 0x003f + +#define TCTL_TEN 0x0001 +#define TCTL_TEN_ENABLE 0x0001 +#define TCTL_CLKSOURCE 0x000e +#define TCTL_CLKSOURCE_STOP 0x0000 +#define TCTL_CLKSOURCE_SYSCLK 0x0002 +#define TCTL_CLKSOURCE_SYSCLK16 0x0004 +#define TCTL_CLKSOURCE_TIN 0x0006 +#define TCTL_CLKSOURCE_32KHZ4 0x0008 +#define TCTL_CLKSOURCE_32KHZ5 0x000a +#define TCTL_CLKSOURCE_32KHZ6 0x000c +#define TCTL_CLKSOURCE_32KHZ7 0x000e +#define TCTL_IRQEN 0x0010 +#define TCTL_IRQEN_ENABLE 0x0010 +#define TCTL_OM 0x0020 +#define TCTL_OM_ACTIVELOW 0x0000 +#define TCTL_OM_TOGGLE 0x0020 +#define TCTL_CAPTURE 0x00c0 +#define TCTL_CAPTURE_NOINT 0x0000 +#define TCTL_CAPTURE_RISING 0x0040 +#define TCTL_CAPTURE_FALLING 0x0080 +#define TCTL_CAPTURE_BOTH 0x00c0 +#define TCTL_FRR 0x0100 +#define TCTL_FRR_RESTART 0x0000 +#define TCTL_FRR_FREERUN 0x0100 + +#define TSTAT_COMP 0x0001 +#define TSTAT_CAPT 0x0002 + +#define WCTLR_WDRST 0x0008 +#define WCTLR_LOCK 0x0004 +#define WCTLR_FI 0x0002 +#define WCTLR_WDEN 0x0001 + +#define USTCNT_UART_EN 0x8000 +#define USTCNT_RX_EN 0x4000 +#define USTCNT_TX_EN 0x2000 +#define USTCNT_RX_CLK_CONT 0x1000 +#define USTCNT_PARITY_EN 0x0800 +#define USTCNT_ODD_EVEN 0x0400 +#define USTCNT_STOP_BITS 0x0200 +#define USTCNT_8_7 0x0100 +#define USTCNT_GPIO_DELTA_EN 0x0080 +#define USTCNT_CTS_DELTA_EN 0x0040 +#define USTCNT_RX_FULL_EN 0x0020 +#define USTCNT_RX_HALF_EN 0x0010 +#define USTCNT_RX_RDY_EN 0x0008 +#define USTCNT_TX_EMPTY_EN 0x0004 +#define USTCNT_TX_HALF_EN 0x0002 +#define USTCNT_TX_AVAIL_EN 0x0001 + +#define UBAUD_GPIO_DELTA 0x8000 +#define UBAUD_GPIO 0x4000 +#define UBAUD_GPIO_DIR 0x2000 +#define UBAUD_GPIO_SRC 0x1000 +#define UBAUD_BAUD_SRC 0x0800 +#define UBAUD_DIVIDE 0x0700 +#define UBAUD_DIVIDE_1 0x0000 +#define UBAUD_DIVIDE_2 0x0100 +#define UBAUD_DIVIDE_4 0x0200 +#define UBAUD_DIVIDE_8 0x0300 +#define UBAUD_DIVIDE_16 0x0400 +#define UBAUD_DIVIDE_32 0x0500 +#define UBAUD_DIVIDE_64 0x0600 +#define UBAUD_DIVIDE_128 0x0700 +#define UBAUD_PRESCALER 0x00ff + +#define URX_FIFO_FULL 0x8000 +#define URX_FIFO_HALF 0x4000 +#define URX_DATA_READY 0x2000 +#define URX_OVRUN 0x0800 +#define URX_FRAME_ERROR 0x0400 +#define URX_BREAK 0x0200 +#define URX_PARITY_ERROR 0x0100 + +#define UTX_FIFO_EMPTY 0x8000 +#define UTX_FIFO_HALF 0x4000 +#define UTX_TX_AVAIL 0x2000 +#define UTX_SEND_BREAK 0x1000 +#define UTX_IGNORE_CTS 0x0800 +#define UTX_CTS_STATUS 0x0200 +#define UTX_CTS_DELTA 0x0100 + +#define UMISC_CLK_SRC 0x4000 +#define UMISC_FORCE_PERR 0x2000 +#define UMISC_LOOP 0x1000 +#define UMISC_RTS_CONT 0x0080 +#define UMISC_RTS 0x0040 +#define UMISC_IRDA_ENABLE 0x0020 +#define UMISC_IRDA_LOOP 0x0010 + +#define SPIS_SPIS_IRQ 0x8000 +#define SPIS_IRQEN 0x4000 +#define SPIS_ENPOL 0x2000 +#define SPIS_DATA_RDY 0x1000 +#define SPIS_OVRWR 0x0800 +#define SPIS_PHA 0x0400 +#define SPIS_POL 0x0200 +#define SPIS_SPISEN 0x0100 + +#define SPIM_CLOCK_COUNT 0x000f +#define SPIM_POL 0x0010 +#define SPIM_POL_HIGH 0x0000 +#define SPIM_POL_LOW 0x0010 +#define SPIM_PHA 0x0020 +#define SPIM_PHA_NORMAL 0x0000 +#define SPIM_PHA_OPPOSITE 0x0020 +#define SPIM_IRQEN 0x0040 +#define SPIM_SPIMIRQ 0x0080 +#define SPIM_XCH 0x0100 +#define SPIM_XCH_IDLE 0x0000 +#define SPIM_XCH_INIT 0x0100 +#define SPIM_SPMEN 0x0200 +#define SPIM_SPMEN_DISABLE 0x0000 +#define SPIM_SPMEN_ENABLE 0x0200 +#define SPIM_RATE 0xe000 +#define SPIM_RATE_4 0x0000 +#define SPIM_RATE_8 0x2000 +#define SPIM_RATE_16 0x4000 +#define SPIM_RATE_32 0x6000 +#define SPIM_RATE_64 0x8000 +#define SPIM_RATE_128 0xa000 +#define SPIM_RATE_256 0xc000 +#define SPIM_RATE_512 0xe000 + +#define PWMC_PWMIRQ 0x8000 +#define PWMC_IRQEN 0x4000 +#define PWMC_LOAD 0x0100 +#define PWMC_PIN 0x0080 +#define PWMC_POL 0x0040 +#define PWMC_PWMEN 0x0010 +#define PWMC_CLKSEL 0x0007 + +struct mc68328_regs_t +{ + // $(FF)FFF000 + UINT8 scr; // System Control Register + UINT8 unused0[255]; + + // $(FF)FFF100 + UINT16 grpbasea; // Chip Select Group A Base Register + UINT16 grpbaseb; // Chip Select Group B Base Register + UINT16 grpbasec; // Chip Select Group C Base Register + UINT16 grpbased; // Chip Select Group D Base Register + UINT16 grpmaska; // Chip Select Group A Mask Register + UINT16 grpmaskb; // Chip Select Group B Mask Register + UINT16 grpmaskc; // Chip Select Group C Mask Register + UINT16 grpmaskd; // Chip Select Group D Mask Register + UINT32 csa0; // Group A Chip Select 0 Register + UINT32 csa1; // Group A Chip Select 1 Register + UINT32 csa2; // Group A Chip Select 2 Register + UINT32 csa3; // Group A Chip Select 3 Register + UINT32 csb0; // Group B Chip Select 0 Register + UINT32 csb1; // Group B Chip Select 1 Register + UINT32 csb2; // Group B Chip Select 2 Register + UINT32 csb3; // Group B Chip Select 3 Register + UINT32 csc0; // Group C Chip Select 0 Register + UINT32 csc1; // Group C Chip Select 1 Register + UINT32 csc2; // Group C Chip Select 2 Register + UINT32 csc3; // Group C Chip Select 3 Register + UINT32 csd0; // Group D Chip Select 0 Register + UINT32 csd1; // Group D Chip Select 1 Register + UINT32 csd2; // Group D Chip Select 2 Register + UINT32 csd3; // Group D Chip Select 3 Register + UINT8 unused1[176]; + + // $(FF)FFF200 + UINT16 pllcr; // PLL Control Register + UINT16 pllfsr; // PLL Frequency Select Register + UINT8 pad2[3]; + UINT8 pctlr; // Power Control Register + UINT8 unused3[248]; + + // $(FF)FFF300 + UINT8 ivr; // Interrupt Vector Register + UINT8 unused4[1]; + UINT16 icr; // Interrupt Control Register + UINT32 imr; // Interrupt Mask Register + UINT32 iwr; // Interrupt Wakeup Enable Register + UINT32 isr; // Interrupt Status Register + UINT32 ipr; // Interrupt Pending Register + UINT8 unused5[236]; + + // $(FF)FFF400 + UINT8 padir; // Port A Direction Register + UINT8 padata; // Port A Data Register + UINT8 unused6[1]; + UINT8 pasel; // Port A Select Register + UINT8 unused7[4]; + + UINT8 pbdir; // Port B Direction Register + UINT8 pbdata; // Port B Data Register + UINT8 unused8[1]; + UINT8 pbsel; // Port B Select Register + UINT8 unused9[4]; + + UINT8 pcdir; // Port C Direction Register + UINT8 pcdata; // Port C Data Register + UINT8 unused10[1]; + UINT8 pcsel; // Port C Select Register + UINT8 unused11[4]; + + UINT8 pddir; // Port D Direction Register + UINT8 pddata; // Port D Data Register + UINT8 pdpuen; // Port D Pullup Enable Register + UINT8 unused12[1]; + UINT8 pdpol; // Port D Polarity Register + UINT8 pdirqen; // Port D IRQ Enable Register + UINT8 pddataedge; // Port D Data Edge Level + UINT8 pdirqedge; // Port D IRQ Edge Register + + UINT8 pedir; // Port E Direction Register + UINT8 pedata; // Port E Data Register + UINT8 pepuen; // Port E Pullup Enable Register + UINT8 pesel; // Port E Select Register + UINT8 unused14[4]; + + UINT8 pfdir; // Port F Direction Register + UINT8 pfdata; // Port F Data Register + UINT8 pfpuen; // Port F Pullup Enable Register + UINT8 pfsel; // Port F Select Register + UINT8 unused15[4]; + + UINT8 pgdir; // Port G Direction Register + UINT8 pgdata; // Port G Data Register + UINT8 pgpuen; // Port G Pullup Enable Register + UINT8 pgsel; // Port G Select Register + UINT8 unused16[4]; + + UINT8 pjdir; // Port J Direction Register + UINT8 pjdata; // Port J Data Register + UINT8 unused17[1]; + UINT8 pjsel; // Port J Select Register + UINT8 unused18[4]; + UINT8 pkdir; // Port K Direction Register + UINT8 pkdata; // Port K Data Register + UINT8 pkpuen; // Port K Pullup Enable Register + UINT8 pksel; // Port K Select Register + UINT8 unused19[4]; + + UINT8 pmdir; // Port M Direction Register + UINT8 pmdata; // Port M Data Register + UINT8 pmpuen; // Port M Pullup Enable Register + UINT8 pmsel; // Port M Select Register + UINT8 unused20[180]; + + // $(FF)FFF500 + UINT16 pwmc; // PWM Control Register + UINT16 pwmp; // PWM Period Register + UINT16 pwmw; // PWM Width Register + UINT16 pwmcnt; // PWN Counter + UINT8 unused21[248]; + + // $(FF)FFF600 + UINT16 tctl[2]; // Timer Control Register + UINT16 tprer[2]; // Timer Prescaler Register + UINT16 tcmp[2]; // Timer Compare Register + UINT16 tcr[2]; // Timer Capture Register + UINT16 tcn[2]; // Timer Counter + UINT16 tstat[2]; // Timer Status + UINT16 wctlr; // Watchdog Control Register + UINT16 wcmpr; // Watchdog Compare Register + UINT16 wcn; // Watchdog Counter + UINT8 tclear[2]; // Timer Clearable Status + UINT8 unused22[224]; + + // $(FF)FFF700 + UINT16 spisr; // SPIS Register + UINT8 unused23[254]; + + // $(FF)FFF800 + UINT16 spimdata; // SPIM Data Register + UINT16 spimcont; // SPIM Control/Status Register + UINT8 unused24[252]; + + // $(FF)FFF900 + UINT16 ustcnt; // UART Status/Control Register + UINT16 ubaud; // UART Baud Control Register + UINT16 urx; // UART RX Register + UINT16 utx; // UART TX Register + UINT16 umisc; // UART Misc Register + UINT8 unused25[246]; + + // $(FF)FFFA00 + UINT32 lssa; // Screen Starting Address Register + UINT8 unused26[1]; + UINT8 lvpw; // Virtual Page Width Register + UINT8 unused27[2]; + UINT16 lxmax; // Screen Width Register + UINT16 lymax; // Screen Height Register + UINT8 unused28[12]; + UINT16 lcxp; // Cursor X Position + UINT16 lcyp; // Cursor Y Position + UINT16 lcwch; // Cursor Width & Height Register + UINT8 unused29[1]; + UINT8 lblkc; // Blink Control Register + UINT8 lpicf; // Panel Interface Config Register + UINT8 lpolcf; // Polarity Config Register + UINT8 unused30[1]; + UINT8 lacdrc; // ACD (M) Rate Control Register + UINT8 unused31[1]; + UINT8 lpxcd; // Pixel Clock Divider Register + UINT8 unused32[1]; + UINT8 lckcon; // Clocking Control Register + UINT8 unused33[1]; + UINT8 llbar; // Last Buffer Address Register + UINT8 unused34[1]; + UINT8 lotcr; // Octet Terminal Count Register + UINT8 unused35[1]; + UINT8 lposr; // Panning Offset Register + UINT8 unused36[3]; + UINT8 lfrcm; // Frame Rate Control Modulation Register + UINT16 lgpmr; // Gray Palette Mapping Register + UINT8 unused37[204]; + + // $(FF)FFFB00 + UINT32 hmsr; // RTC Hours Minutes Seconds Register + UINT32 alarm; // RTC Alarm Register + UINT8 unused38[4]; + UINT16 rtcctl; // RTC Control Register + UINT16 rtcisr; // RTC Interrupt Status Register + UINT16 rtcienr; // RTC Interrupt Enable Register + UINT16 stpwtch; // Stopwatch Minutes + UINT8 unused42[1260]; +}; + + +class mc68328_device : public device_t +{ +public: + mc68328_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + ~mc68328_device() {} + + static void static_set_cpu_tag(device_t &device, const char *tag) { downcast(device).m_cpu.set_tag(tag); } + template static devcb_base &set_out_port_a_callback(device_t &device, _Object object) { return downcast(device).m_out_port_a_cb.set_callback(object); } + template static devcb_base &set_out_port_b_callback(device_t &device, _Object object) { return downcast(device).m_out_port_b_cb.set_callback(object); } + template static devcb_base &set_out_port_c_callback(device_t &device, _Object object) { return downcast(device).m_out_port_c_cb.set_callback(object); } + template static devcb_base &set_out_port_d_callback(device_t &device, _Object object) { return downcast(device).m_out_port_d_cb.set_callback(object); } + template static devcb_base &set_out_port_e_callback(device_t &device, _Object object) { return downcast(device).m_out_port_e_cb.set_callback(object); } + template static devcb_base &set_out_port_f_callback(device_t &device, _Object object) { return downcast(device).m_out_port_f_cb.set_callback(object); } + template static devcb_base &set_out_port_g_callback(device_t &device, _Object object) { return downcast(device).m_out_port_g_cb.set_callback(object); } + template static devcb_base &set_out_port_j_callback(device_t &device, _Object object) { return downcast(device).m_out_port_j_cb.set_callback(object); } + template static devcb_base &set_out_port_k_callback(device_t &device, _Object object) { return downcast(device).m_out_port_k_cb.set_callback(object); } + template static devcb_base &set_out_port_m_callback(device_t &device, _Object object) { return downcast(device).m_out_port_m_cb.set_callback(object); } + template static devcb_base &set_in_port_a_callback(device_t &device, _Object object) { return downcast(device).m_in_port_a_cb.set_callback(object); } + template static devcb_base &set_in_port_b_callback(device_t &device, _Object object) { return downcast(device).m_in_port_b_cb.set_callback(object); } + template static devcb_base &set_in_port_c_callback(device_t &device, _Object object) { return downcast(device).m_in_port_c_cb.set_callback(object); } + template static devcb_base &set_in_port_d_callback(device_t &device, _Object object) { return downcast(device).m_in_port_d_cb.set_callback(object); } + template static devcb_base &set_in_port_e_callback(device_t &device, _Object object) { return downcast(device).m_in_port_e_cb.set_callback(object); } + template static devcb_base &set_in_port_f_callback(device_t &device, _Object object) { return downcast(device).m_in_port_f_cb.set_callback(object); } + template static devcb_base &set_in_port_g_callback(device_t &device, _Object object) { return downcast(device).m_in_port_g_cb.set_callback(object); } + template static devcb_base &set_in_port_j_callback(device_t &device, _Object object) { return downcast(device).m_in_port_j_cb.set_callback(object); } + template static devcb_base &set_in_port_k_callback(device_t &device, _Object object) { return downcast(device).m_in_port_k_cb.set_callback(object); } + template static devcb_base &set_in_port_m_callback(device_t &device, _Object object) { return downcast(device).m_in_port_m_cb.set_callback(object); } + template static devcb_base &set_out_pwm_callback(device_t &device, _Object object) { return downcast(device).m_out_pwm_cb.set_callback(object); } + template static devcb_base &set_out_spim_callback(device_t &device, _Object object) { return downcast(device).m_out_spim_cb.set_callback(object); } + template static devcb_base &set_in_spim_callback(device_t &device, _Object object) { return downcast(device).m_in_spim_cb.set_callback(object); } + template static devcb_base &set_spim_xch_trigger_callback(device_t &device, _Object object) { return downcast(device).m_spim_xch_trigger_cb.set_callback(object); } + + + DECLARE_WRITE16_MEMBER(write); + DECLARE_READ16_MEMBER(read); + DECLARE_WRITE_LINE_MEMBER(set_penirq_line); + void set_port_d_lines(UINT8 state, int bit); + + UINT32 screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + +private: + // internal state + void set_interrupt_line(UINT32 line, UINT32 active); + void poll_port_d_interrupts(); + UINT32 get_timer_frequency(UINT32 index); + void maybe_start_timer(UINT32 index, UINT32 new_enable); + void timer_compare_event(UINT32 index); + + void register_state_save(); + + TIMER_CALLBACK_MEMBER(timer1_hit); + TIMER_CALLBACK_MEMBER(timer2_hit); + TIMER_CALLBACK_MEMBER(pwm_transition); + TIMER_CALLBACK_MEMBER(rtc_tick); + + mc68328_regs_t m_regs; + + emu_timer *m_gptimer[2]; + emu_timer *m_rtc; + emu_timer *m_pwm; + + devcb_write8 m_out_port_a_cb; /* 8-bit output */ + devcb_write8 m_out_port_b_cb; /* 8-bit output */ + devcb_write8 m_out_port_c_cb; /* 8-bit output */ + devcb_write8 m_out_port_d_cb; /* 8-bit output */ + devcb_write8 m_out_port_e_cb; /* 8-bit output */ + devcb_write8 m_out_port_f_cb; /* 8-bit output */ + devcb_write8 m_out_port_g_cb; /* 8-bit output */ + devcb_write8 m_out_port_j_cb; /* 8-bit output */ + devcb_write8 m_out_port_k_cb; /* 8-bit output */ + devcb_write8 m_out_port_m_cb; /* 8-bit output */ + + devcb_read8 m_in_port_a_cb; /* 8-bit input */ + devcb_read8 m_in_port_b_cb; /* 8-bit input */ + devcb_read8 m_in_port_c_cb; /* 8-bit input */ + devcb_read8 m_in_port_d_cb; /* 8-bit input */ + devcb_read8 m_in_port_e_cb; /* 8-bit input */ + devcb_read8 m_in_port_f_cb; /* 8-bit input */ + devcb_read8 m_in_port_g_cb; /* 8-bit input */ + devcb_read8 m_in_port_j_cb; /* 8-bit input */ + devcb_read8 m_in_port_k_cb; /* 8-bit input */ + devcb_read8 m_in_port_m_cb; /* 8-bit input */ + + devcb_write8 m_out_pwm_cb; /* 1-bit output */ + + devcb_write16 m_out_spim_cb; /* 16-bit output */ + devcb_read16 m_in_spim_cb; /* 16-bit input */ + + devcb_write_line m_spim_xch_trigger_cb; /* SPIM exchange trigger */ /*todo: not really a write line, fix*/ + + required_device m_cpu; +}; + + +extern const device_type MC68328; + +#define MCFG_MC68328_CPU(_tag) \ + mc68328_device::static_set_cpu_tag(*device, "^" _tag); + +#define MCFG_MC68328_OUT_PORT_A_CB(_devcb) \ + devcb = &mc68328_device::set_out_port_a_callback(*device, DEVCB_##_devcb); + +#define MCFG_MC68328_OUT_PORT_B_CB(_devcb) \ + devcb = &mc68328_device::set_out_port_b_callback(*device, DEVCB_##_devcb); + +#define MCFG_MC68328_OUT_PORT_C_CB(_devcb) \ + devcb = &mc68328_device::set_out_port_c_callback(*device, DEVCB_##_devcb); + +#define MCFG_MC68328_OUT_PORT_D_CB(_devcb) \ + devcb = &mc68328_device::set_out_port_d_callback(*device, DEVCB_##_devcb); + +#define MCFG_MC68328_OUT_PORT_E_CB(_devcb) \ + devcb = &mc68328_device::set_out_port_e_callback(*device, DEVCB_##_devcb); + +#define MCFG_MC68328_OUT_PORT_F_CB(_devcb) \ + devcb = &mc68328_device::set_out_port_f_callback(*device, DEVCB_##_devcb); + +#define MCFG_MC68328_OUT_PORT_G_CB(_devcb) \ + devcb = &mc68328_device::set_out_port_g_callback(*device, DEVCB_##_devcb); + +#define MCFG_MC68328_OUT_PORT_J_CB(_devcb) \ + devcb = &mc68328_device::set_out_port_j_callback(*device, DEVCB_##_devcb); + +#define MCFG_MC68328_OUT_PORT_K_CB(_devcb) \ + devcb = &mc68328_device::set_out_port_k_callback(*device, DEVCB_##_devcb); + +#define MCFG_MC68328_OUT_PORT_M_CB(_devcb) \ + devcb = &mc68328_device::set_out_port_m_callback(*device, DEVCB_##_devcb); + +#define MCFG_MC68328_IN_PORT_A_CB(_devcb) \ + devcb = &mc68328_device::set_in_port_a_callback(*device, DEVCB_##_devcb); + +#define MCFG_MC68328_IN_PORT_B_CB(_devcb) \ + devcb = &mc68328_device::set_in_port_b_callback(*device, DEVCB_##_devcb); + +#define MCFG_MC68328_IN_PORT_C_CB(_devcb) \ + devcb = &mc68328_device::set_in_port_c_callback(*device, DEVCB_##_devcb); + +#define MCFG_MC68328_IN_PORT_D_CB(_devcb) \ + devcb = &mc68328_device::set_in_port_d_callback(*device, DEVCB_##_devcb); + +#define MCFG_MC68328_IN_PORT_E_CB(_devcb) \ + devcb = &mc68328_device::set_in_port_e_callback(*device, DEVCB_##_devcb); + +#define MCFG_MC68328_IN_PORT_F_CB(_devcb) \ + devcb = &mc68328_device::set_in_port_f_callback(*device, DEVCB_##_devcb); + +#define MCFG_MC68328_IN_PORT_G_CB(_devcb) \ + devcb = &mc68328_device::set_in_port_g_callback(*device, DEVCB_##_devcb); + +#define MCFG_MC68328_IN_PORT_J_CB(_devcb) \ + devcb = &mc68328_device::set_in_port_j_callback(*device, DEVCB_##_devcb); + +#define MCFG_MC68328_IN_PORT_K_CB(_devcb) \ + devcb = &mc68328_device::set_in_port_k_callback(*device, DEVCB_##_devcb); + +#define MCFG_MC68328_IN_PORT_M_CB(_devcb) \ + devcb = &mc68328_device::set_in_port_m_callback(*device, DEVCB_##_devcb); + +#define MCFG_MC68328_OUT_PWM_CB(_devcb) \ + devcb = &mc68328_device::set_out_pwm_callback(*device, DEVCB_##_devcb); + +#define MCFG_MC68328_OUT_SPIM_CB(_devcb) \ + devcb = &mc68328_device::set_out_spim_callback(*device, DEVCB_##_devcb); + +#define MCFG_MC68328_IN_SPIM_CB(_devcb) \ + devcb = &mc68328_device::set_in_spim_callback(*device, DEVCB_##_devcb); + +#define MCFG_MC68328_SPIM_XCH_TRIGGER_CB(_devcb) \ + devcb = &mc68328_device::set_spim_xch_trigger_callback(*device, DEVCB_##_devcb); + + +#endif diff --git a/src/devices/machine/mc6843.c b/src/devices/machine/mc6843.c new file mode 100644 index 00000000000..f30dafde916 --- /dev/null +++ b/src/devices/machine/mc6843.c @@ -0,0 +1,827 @@ +// license:BSD-3-Clause +// copyright-holders:Antoine Mine +/********************************************************************** + + Copyright (C) Antoine Mine' 2007 + + Motorola 6843 Floppy Disk Controller emulation. + +**********************************************************************/ + +/* + Main MC 6843 features are: + - single density floppies + - IBM 3740 compatible + - DMA-able + - high-level commands (including multi-sector read/write) + + CLONES: HD 46503S seems to be a clone of MC 6843 + + BUGS + The driver was designed with Thomson computer emulation in mind + (CD 90-015 5"1/4 floppy controller) and works in this context. + It might work in other contexts but has currently shortcomings: + - DMA is not emulated + - Free-Format Read is not emulated + - Free-Format Write only supports track formatting, in a specific + format (FWF=1, Thomson-like sector formats) + - very rough timing: basically, there is a fixed delay between + a command request (CMR write) and its response (first byte + available, seek complete, etc.); there is no delay between + read / write + */ + + +#include "emu.h" +#include "mc6843.h" + + +/******************* parameters ******************/ + +#define VERBOSE 0 + +/* macro-command numbers */ +#define CMD_STZ 0x2 /* seek track zero */ +#define CMD_SEK 0x3 /* seek */ +#define CMD_SSR 0x4 /* single sector read */ +#define CMD_SSW 0x5 /* single sector write */ +#define CMD_RCR 0x6 /* read CRC */ +#define CMD_SWD 0x7 /* single sector write with delete data mark */ +#define CMD_MSW 0xd /* multiple sector write */ +#define CMD_MSR 0xc /* multiple sector read */ +#define CMD_FFW 0xb /* free format write */ +#define CMD_FFR 0xa /* free format read */ + +/* coarse delays */ +#define DELAY_SEEK attotime::from_usec( 100 ) /* track seek time */ +#define DELAY_ADDR attotime::from_usec( 100 ) /* search-address time */ + + + +static const char *const mc6843_cmd[16] = +{ + "---", "---", "STZ", "SEK", "SSR", "SSW", "RCR", "SWD", + "---", "---", "FFR", "FFW", "MSR", "MSW", "---", "---", +}; + + +/******************* utility function and macros ********************/ + +#define LOG(x) do { if (VERBOSE) logerror x; } while (0) + + + + +const device_type MC6843 = &device_creator; + +mc6843_device::mc6843_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, MC6843, "MC6843 floppy controller", tag, owner, clock, "mc6843", __FILE__), + m_write_irq(*this), + m_CTAR(0), + m_CMR(0), + m_ISR(0), + m_SUR(0), + m_STRA(0), + m_STRB(0), + m_SAR(0), + m_GCR(0), + m_CCR(0), + m_LTAR(0), + m_drive(0), + m_side(0), + m_data_size(0), + m_data_idx(0), + m_data_id(0), + m_index_pulse(0), + m_timer_cont(NULL) +{ + for (int i = 0; i < 128; i++) + { + m_data[i] = 0; + } +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void mc6843_device::device_start() +{ + m_write_irq.resolve_safe(); + + m_timer_cont = timer_alloc(TIMER_CONT); + + save_item(NAME(m_CTAR)); + save_item(NAME(m_CMR)); + save_item(NAME(m_ISR)); + save_item(NAME(m_SUR)); + save_item(NAME(m_STRA)); + save_item(NAME(m_STRB)); + save_item(NAME(m_SAR)); + save_item(NAME(m_GCR)); + save_item(NAME(m_CCR)); + save_item(NAME(m_LTAR)); + save_item(NAME(m_drive)); + save_item(NAME(m_side)); + save_item(NAME(m_data)); + save_item(NAME(m_data_size)); + save_item(NAME(m_data_idx)); + save_item(NAME(m_data_id)); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void mc6843_device::device_reset() +{ + int i; + LOG (( "mc6843 reset\n" )); + + /* setup/reset floppy drive */ + for ( i = 0; i < 4; i++ ) + { + legacy_floppy_image_device * img = floppy_image( i ); + img->floppy_mon_w(CLEAR_LINE); + img->floppy_drive_set_ready_state(FLOPPY_DRIVE_READY, 0 ); + img->floppy_drive_set_rpm( 300. ); + } + + /* reset registers */ + m_CMR &= 0xf0; /* zero only command */ + m_ISR = 0; + m_STRA &= 0x5c; + m_SAR = 0; + m_STRB &= 0x20; + status_update( ); + + m_data_size = 0; + m_data_idx = 0; + m_timer_cont->adjust( attotime::never ); +} + +/************************** floppy interface ****************************/ + + + +legacy_floppy_image_device* mc6843_device::floppy_image( UINT8 drive ) +{ + legacy_floppy_image_device *img = floppy_get_device( machine(), drive ); + if (!img && owner()) { + // For slot devices, drives are typically attached to the slot rather than the machine + const char *floppy_name = NULL; + switch (drive) { + case 0: + floppy_name = FLOPPY_0; + break; + case 1: + floppy_name = FLOPPY_1; + break; + case 2: + floppy_name = FLOPPY_2; + break; + case 3: + floppy_name = FLOPPY_3; + break; + } + img = owner()->subdevice(floppy_name); + } + return img; +} + + +legacy_floppy_image_device* mc6843_device::floppy_image( ) +{ + return floppy_image( m_drive ); +} + + +void mc6843_device::set_drive( int drive ) +{ + m_drive = drive; +} + + + +void mc6843_device::set_side( int side ) +{ + m_side = side; +} + + + +/* called after ISR or STRB has changed */ +void mc6843_device::status_update( ) +{ + int irq = 0; + + /* ISR3 */ + if ( (m_CMR & 0x40) || ! m_STRB ) + m_ISR &= ~8; + else + m_ISR |= 8; + + /* interrupts */ + if ( m_ISR & 4 ) + irq = 1; /* unmaskable */ + if ( ! (m_CMR & 0x80) ) + { + /* maskable */ + if ( m_ISR & ~4 ) + irq = 1; + } + + m_write_irq( irq ); + LOG(( "status_update: irq=%i (CMR=%02X, ISR=%02X)\n", irq, m_CMR, m_ISR )); +} + + +void mc6843_device::set_index_pulse( int index_pulse ) +{ + m_index_pulse = index_pulse; +} + + +/* called at end of command */ +void mc6843_device::cmd_end( ) +{ + int cmd = m_CMR & 0x0f; + if ( ( cmd == CMD_STZ ) || ( cmd == CMD_SEK ) ) + { + m_ISR |= 0x02; /* set Settling Time Complete */ + } + else + { + m_ISR |= 0x01; /* set Macro Command Complete */ + } + m_STRA &= ~0x80; /* clear Busy */ + m_CMR &= 0xf0; /* clear command */ + status_update( ); +} + + + +/* Seek Track Zero bottom half */ +void mc6843_device::finish_STZ( ) +{ + legacy_floppy_image_device* img = floppy_image( ); + int i; + + /* seek to track zero */ + for ( i=0; i<83; i++ ) + { + if (img->floppy_tk00_r() == CLEAR_LINE) + break; + img->floppy_drive_seek( -1 ); + } + + LOG(( "%f mc6843_finish_STZ: actual=%i\n", machine().time().as_double(), img->floppy_drive_get_current_track() )); + + /* update state */ + m_CTAR = 0; + m_GCR = 0; + m_SAR = 0; + m_STRB |= img->floppy_tk00_r() << 4; + + cmd_end( ); +} + + + +/* Seek bottom half */ +void mc6843_device::finish_SEK( ) +{ + legacy_floppy_image_device* img = floppy_image( ); + + /* seek to track */ + // TODO: not sure how CTAR bit 7 is handled here, but this is the safest approach for now + img->floppy_drive_seek( m_GCR - (m_CTAR & 0x7F) ); + + LOG(( "%f mc6843_finish_SEK: from %i to %i (actual=%i)\n", machine().time().as_double(), (m_CTAR & 0x7F), m_GCR, img->floppy_drive_get_current_track() )); + + /* update state */ + m_CTAR = m_GCR; + m_SAR = 0; + cmd_end( ); +} + + + +/* preamble to all sector read / write commands, returns 1 if found */ +int mc6843_device::address_search( chrn_id* id ) +{ + legacy_floppy_image_device* img = floppy_image( ); + int r = 0; + + while ( 1 ) + { + if ( ( ! img->floppy_drive_get_next_id( m_side, id ) ) || ( id->flags & ID_FLAG_CRC_ERROR_IN_ID_FIELD ) || ( id->N != 0 ) ) + { + /* read address error */ + LOG(( "%f mc6843_address_search: get_next_id failed\n", machine().time().as_double() )); + m_STRB |= 0x0a; /* set CRC error & Sector Address Undetected */ + cmd_end( ); + return 0; + } + + if ( id->C != m_LTAR ) + { + /* track mismatch */ + LOG(( "%f mc6843_address_search: track mismatch: logical=%i real=%i\n", machine().time().as_double(), m_LTAR, id->C )); + m_data[0] = id->C; /* make the track number available to the CPU */ + m_STRA |= 0x20; /* set Track Not Equal */ + cmd_end( ); + return 0; + } + + if ( id->R == m_SAR ) + { + /* found! */ + LOG(( "%f mc6843_address_search: sector %i found on track %i\n", machine().time().as_double(), id->R, id->C )); + if ( ! (m_CMR & 0x20) ) + { + m_ISR |= 0x04; /* if no DMA, set Status Sense */ + } + return 1; + } + + if ( img->floppy_drive_get_flag_state( FLOPPY_DRIVE_INDEX ) ) + { + r++; + if ( r >= 4 ) + { + /* time-out after 3 full revolutions */ + LOG(( "%f mc6843_address_search: no sector %i found after 3 revolutions\n", machine().time().as_double(), m_SAR )); + m_STRB |= 0x08; /* set Sector Address Undetected */ + cmd_end( ); + return 0; + } + } + } + + //return 0; /* unreachable */ +} + + + +/* preamble specific to read commands (adds extra checks) */ +int mc6843_device::address_search_read( chrn_id* id ) +{ + if ( ! address_search( id ) ) + return 0; + + if ( id->flags & ID_FLAG_CRC_ERROR_IN_DATA_FIELD ) + { + LOG(( "%f mc6843_address_search_read: data CRC error\n", machine().time().as_double() )); + m_STRB |= 0x06; /* set CRC error & Data Mark Undetected */ + cmd_end( ); + return 0; + } + + if ( id->flags & ID_FLAG_DELETED_DATA ) + { + LOG(( "%f mc6843_address_search_read: deleted data\n", machine().time().as_double() )); + m_STRA |= 0x02; /* set Delete Data Mark Detected */ + } + + return 1; +} + + + + +/* Read CRC bottom half */ +void mc6843_device::finish_RCR( ) +{ + chrn_id id; + if ( ! address_search_read( &id ) ) + return; + cmd_end( ); +} + + + +/* Single / Multiple Sector Read bottom half */ +void mc6843_device::cont_SR( ) +{ + chrn_id id; + legacy_floppy_image_device* img = floppy_image( ); + + /* sector seek */ + if ( ! address_search_read( &id ) ) + return; + + /* sector read */ + img->floppy_drive_read_sector_data( m_side, id.data_id, m_data, 128 ); + m_data_idx = 0; + m_data_size = 128; + m_STRA |= 0x01; /* set Data Transfer Request */ + status_update( ); +} + + + +/* Single / Multiple Sector Write bottom half */ +void mc6843_device::cont_SW( ) +{ + chrn_id id; + + /* sector seek */ + if ( ! address_search( &id ) ) + return; + + /* setup sector write buffer */ + m_data_idx = 0; + m_data_size = 128; + m_STRA |= 0x01; /* set Data Transfer Request */ + m_data_id = id.data_id; /* for subsequent write sector command */ + status_update( ); +} + + + +/* bottom halves, called to continue / finish a command after some delay */ +void mc6843_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch (id) + { + case TIMER_CONT: + { + int cmd = m_CMR & 0x0f; + + LOG(( "%f mc6843_cont: timer called for cmd=%s(%i)\n", machine().time().as_double(), mc6843_cmd[cmd], cmd )); + + m_timer_cont->adjust( attotime::never ); + + switch ( cmd ) + { + case CMD_STZ: finish_STZ( ); break; + case CMD_SEK: finish_SEK( ); break; + case CMD_SSR: cont_SR( ); break; + case CMD_SSW: cont_SW( ); break; + case CMD_RCR: finish_RCR( ); break; + case CMD_SWD: cont_SW( ); break; + case CMD_MSW: cont_SW( ); break; + case CMD_MSR: cont_SR( ); break; + } + } + break; + + default: + break; + } +} + + + +/************************** CPU interface ****************************/ + + + +READ8_MEMBER( mc6843_device::read ) +{ + UINT8 data = 0; + + switch ( offset ) { + case 0: /* Data Input Register (DIR) */ + { + int cmd = m_CMR & 0x0f; + + LOG(( "%f %s mc6843_r: data input cmd=%s(%i), pos=%i/%i, GCR=%i, ", + machine().time().as_double(), machine().describe_context(), + mc6843_cmd[cmd], cmd, m_data_idx, + m_data_size, m_GCR )); + + if ( cmd == CMD_SSR || cmd == CMD_MSR ) + { + /* sector read */ + assert( m_data_size > 0 ); + assert( m_data_idx < m_data_size ); + assert( m_data_idx < sizeof(m_data) ); + data = m_data[ m_data_idx ]; + m_data_idx++; + + if ( m_data_idx >= m_data_size ) + { + /* end of sector read */ + + m_STRA &= ~0x01; /* clear Data Transfer Request */ + + if ( cmd == CMD_MSR ) + { + /* schedule next sector in multiple sector read */ + m_GCR--; + m_SAR++; + if ( m_GCR == 0xff ) + { + cmd_end( ); + } + else if ( m_SAR > 26 ) + + { + m_STRB |= 0x08; /* set Sector Address Undetected */ + cmd_end( ); + } + else + { + m_timer_cont->adjust( DELAY_ADDR ); + } + } + else + { + cmd_end( ); + } + } + } + else if ( cmd == 0 ) + { + data = m_data[0]; + } + else + { + /* XXX TODO: other read modes */ + data = m_data[0]; + logerror( "%s mc6843 read in unsupported command mode %i\n", machine().describe_context(), cmd ); + } + + LOG(( "data=%02X\n", data )); + + break; + } + + case 1: /* Current-Track Address Register (CTAR) */ + data = m_CTAR; + LOG(( "%f %s mc6843_r: read CTAR %i (actual=%i)\n", + machine().time().as_double(), machine().describe_context(), data, + floppy_image()->floppy_drive_get_current_track())); + break; + + case 2: /* Interrupt Status Register (ISR) */ + data = m_ISR; + LOG(( "%f %s mc6843_r: read ISR %02X: cmd=%scomplete settle=%scomplete sense-rq=%i STRB=%i\n", + machine().time().as_double(), machine().describe_context(), data, + (data & 1) ? "" : "not-" , (data & 2) ? "" : "not-", + (data >> 2) & 1, (data >> 3) & 1 )); + + /* reset */ + m_ISR &= 8; /* keep STRB */ + status_update( ); + break; + + case 3: /* Status Register A (STRA) */ + { + /* update */ + legacy_floppy_image_device* img = floppy_image( ); + int flag = img->floppy_drive_get_flag_state( FLOPPY_DRIVE_READY); + m_STRA &= 0xa3; + if ( flag & FLOPPY_DRIVE_READY ) + m_STRA |= 0x04; + + m_STRA |= !img->floppy_tk00_r() << 3; + m_STRA |= !img->floppy_wpt_r() << 4; + + if ( m_index_pulse ) + m_STRA |= 0x40; + + data = m_STRA; + LOG(( "%f %s mc6843_r: read STRA %02X: data-rq=%i del-dta=%i ready=%i t0=%i wp=%i trk-dif=%i idx=%i busy=%i\n", + machine().time().as_double(), machine().describe_context(), data, + data & 1, (data >> 1) & 1, (data >> 2) & 1, (data >> 3) & 1, + (data >> 4) & 1, (data >> 5) & 1, (data >> 6) & 1, (data >> 7) & 1 )); + break; + } + + case 4: /* Status Register B (STRB) */ + data = m_STRB; + LOG(( "%f %s mc6843_r: read STRB %02X: data-err=%i CRC-err=%i dta--mrk-err=%i sect-mrk-err=%i seek-err=%i fi=%i wr-err=%i hard-err=%i\n", + machine().time().as_double(), machine().describe_context(), data, + data & 1, (data >> 1) & 1, (data >> 2) & 1, (data >> 3) & 1, + (data >> 4) & 1, (data >> 5) & 1, (data >> 6) & 1, (data >> 7) & 1 )); + + /* (partial) reset */ + m_STRB &= ~0xfb; + status_update( ); + break; + + case 7: /* Logical-Track Address Register (LTAR) */ + data = m_LTAR; + LOG(( "%f %s mc6843_r: read LTAR %i (actual=%i)\n", + machine().time().as_double(), machine().describe_context(), data, + floppy_image()->floppy_drive_get_current_track())); + break; + + default: + logerror( "%s mc6843 invalid read offset %i\n", machine().describe_context(), offset ); + } + + return data; +} + +WRITE8_MEMBER( mc6843_device::write ) +{ + switch ( offset ) { + case 0: /* Data Output Register (DOR) */ + { + int cmd = m_CMR & 0x0f; + int FWF = (m_CMR >> 4) & 1; + + LOG(( "%f %s mc6843_w: data output cmd=%s(%i), pos=%i/%i, GCR=%i, data=%02X\n", + machine().time().as_double(), machine().describe_context(), + mc6843_cmd[cmd], cmd, m_data_idx, + m_data_size, m_GCR, data )); + + if ( cmd == CMD_SSW || cmd == CMD_MSW || cmd == CMD_SWD ) + { + /* sector write */ + assert( m_data_size > 0 ); + assert( m_data_idx < m_data_size ); + assert( m_data_idx < sizeof(m_data) ); + m_data[ m_data_idx ] = data; + m_data_idx++; + if ( m_data_idx >= m_data_size ) + { + /* end of sector write */ + legacy_floppy_image_device* img = floppy_image( ); + + LOG(( "%f %s mc6843_w: write sector %i\n", machine().time().as_double(), machine().describe_context(), m_data_id )); + + img->floppy_drive_write_sector_data( + m_side, m_data_id, + m_data, m_data_size, + (cmd == CMD_SWD) ? ID_FLAG_DELETED_DATA : 0 ); + + m_STRA &= ~0x01; /* clear Data Transfer Request */ + + if ( cmd == CMD_MSW ) + { + m_GCR--; + m_SAR++; + if ( m_GCR == 0xff ) + { + cmd_end( ); + } + else if ( m_SAR > 26 ) + + { + m_STRB |= 0x08; /* set Sector Address Undetected */ + cmd_end( ); + } + else + { + m_timer_cont->adjust( DELAY_ADDR ); + } + } + else + { + cmd_end( ); + } + } + } + else if ( (cmd == CMD_FFW) && FWF ) + { + /* assume we are formatting */ + UINT8 nibble; + nibble = + (data & 0x01) | + ((data & 0x04) >> 1 )| + ((data & 0x10) >> 2 )| + ((data & 0x40) >> 3 ); + + assert( m_data_idx < sizeof(m_data) ); + + m_data[m_data_idx / 2] = + (m_data[m_data_idx / 2] << 4) | nibble; + + if ( (m_data_idx == 0) && (m_data[0] == 0xfe ) ) + { + /* address mark detected */ + m_data_idx = 2; + } + else if ( m_data_idx == 9 ) + { + /* address id field complete */ + if ( (m_data[2] == 0) && (m_data[4] == 0) ) + { + /* valid address id field */ + legacy_floppy_image_device* img = floppy_image( ); + UINT8 track = m_data[1]; + UINT8 sector = m_data[3]; + UINT8 filler = 0xe5; /* standard Thomson filler */ + LOG(( "%f %s mc6843_w: address id detected track=%i sector=%i\n", machine().time().as_double(), machine().describe_context(), track, sector)); + img->floppy_drive_format_sector( m_side, sector, track, 0, sector, 0, filler ); + } + else + { + /* abort */ + m_data_idx = 0; + } + } + else if ( m_data_idx > 0 ) + { + /* accumulate address id field */ + m_data_idx++; + } + } + else if ( cmd == 0 ) + { + /* nothing */ + } + else + { + /* XXX TODO: other write modes */ + logerror( "%s mc6843 write %02X in unsupported command mode %i (FWF=%i)\n", machine().describe_context(), data, cmd, FWF ); + } + break; + } + + case 1: /* Current-Track Address Register (CTAR) */ + m_CTAR = data; + LOG(( "%f %s mc6843_w: set CTAR to %i %02X (actual=%i) \n", + machine().time().as_double(), machine().describe_context(), m_CTAR, data, + floppy_image()->floppy_drive_get_current_track())); + break; + + case 2: /* Command Register (CMR) */ + { + int cmd = data & 15; + + LOG(( "%f %s mc6843_w: set CMR to $%02X: cmd=%s(%i) FWF=%i DMA=%i ISR3-intr=%i fun-intr=%i\n", + machine().time().as_double(), machine().describe_context(), + data, mc6843_cmd[cmd], cmd, (data >> 4) & 1, (data >> 5) & 1, + (data >> 6) & 1, (data >> 7) & 1 )); + + /* sanitize state */ + m_STRA &= ~0x81; /* clear Busy & Data Transfer Request */ + m_data_idx = 0; + m_data_size = 0; + + /* commands are initiated by updating some flags and scheduling + a bottom-half (mc6843_cont) after some delay */ + + switch (cmd) + { + case CMD_SSW: + case CMD_SSR: + case CMD_SWD: + case CMD_RCR: + case CMD_MSR: + case CMD_MSW: + m_STRA |= 0x80; /* set Busy */ + m_STRA &= ~0x22; /* clear Track Not Equal & Delete Data Mark Detected */ + m_STRB &= ~0x04; /* clear Data Mark Undetected */ + m_timer_cont->adjust( DELAY_ADDR ); + break; + case CMD_STZ: + case CMD_SEK: + m_STRA |= 0x80; /* set Busy */ + m_timer_cont->adjust( DELAY_SEEK ); + break; + case CMD_FFW: + case CMD_FFR: + m_data_idx = 0; + m_STRA |= 0x01; /* set Data Transfer Request */ + break; + } + + m_CMR = data; + status_update( ); + break; + } + + case 3: /* Set-Up Register (SUR) */ + m_SUR = data; + + /* assume CLK freq = 1MHz (IBM 3740 compatibility) */ + LOG(( "%f %s mc6843_w: set SUR to $%02X: head settling time=%fms, track-to-track seek time=%f\n", + machine().time().as_double(), machine().describe_context(), + data, 4.096 * (data & 15), 1.024 * ((data >> 4) & 15) )); + break; + + case 4: /* Sector Address Register (SAR) */ + m_SAR = data & 0x1f; + LOG(( "%f %s mc6843_w: set SAR to %i (%02X)\n", machine().time().as_double(), machine().describe_context(), m_SAR, data )); + break; + + case 5: /* General Count Register (GCR) */ + m_GCR = data & 0x7f; + LOG(( "%f %s mc6843_w: set GCR to %i (%02X)\n", machine().time().as_double(), machine().describe_context(), m_GCR, data )); + break; + + case 6: /* CRC Control Register (CCR) */ + m_CCR = data & 3; + LOG(( "%f %s mc6843_w: set CCR to %02X: CRC=%s shift=%i\n", + machine().time().as_double(), machine().describe_context(), data, + (data & 1) ? "enabled" : "disabled", (data >> 1) & 1 )); + break; + + case 7: /* Logical-Track Address Register (LTAR) */ + m_LTAR = data & 0x7f; + LOG(( "%f %s mc6843_w: set LTAR to %i %02X (actual=%i)\n", + machine().time().as_double(), machine().describe_context(), m_LTAR, data, + floppy_image()->floppy_drive_get_current_track())); + break; + + default: + logerror( "%s mc6843 invalid write offset %i (data=$%02X)\n", machine().describe_context(), offset, data ); + } +} diff --git a/src/devices/machine/mc6843.h b/src/devices/machine/mc6843.h new file mode 100644 index 00000000000..3a855d1c196 --- /dev/null +++ b/src/devices/machine/mc6843.h @@ -0,0 +1,88 @@ +// license:BSD-3-Clause +// copyright-holders:Antoine Mine +/********************************************************************** + + Copyright (C) Antoine Mine' 2007 + + Motorola 6843 Floppy Disk Controller emulation. + +**********************************************************************/ + +#ifndef MC6843_H +#define MC6843_H + +#include "imagedev/flopdrv.h" + +#define MCFG_MC6843_IRQ_CALLBACK(_write) \ + devcb = &mc6843_device::set_irq_wr_callback(*device, DEVCB_##_write); + +class mc6843_device : public device_t +{ +public: + mc6843_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + ~mc6843_device() {} + + template static devcb_base &set_irq_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_irq.set_callback(object); } + + DECLARE_READ8_MEMBER(read); + DECLARE_WRITE8_MEMBER(write); + + void set_drive(int drive); + void set_side(int side); + void set_index_pulse(int index_pulse); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + +private: + enum + { + TIMER_CONT + }; + + devcb_write_line m_write_irq; + + /* registers */ + UINT8 m_CTAR; /* current track */ + UINT8 m_CMR; /* command */ + UINT8 m_ISR; /* interrupt status */ + UINT8 m_SUR; /* set-up */ + UINT8 m_STRA; /* status */ + UINT8 m_STRB; /* status */ + UINT8 m_SAR; /* sector address */ + UINT8 m_GCR; /* general count */ + UINT8 m_CCR; /* CRC control */ + UINT8 m_LTAR; /* logical address track (=track destination) */ + + /* internal state */ + UINT8 m_drive; + UINT8 m_side; + UINT8 m_data[128]; /* sector buffer */ + UINT32 m_data_size; /* size of data */ + UINT32 m_data_idx; /* current read/write position in data */ + UINT32 m_data_id; /* chrd_id for sector write */ + UINT8 m_index_pulse; + + /* trigger delayed actions (bottom halves) */ + emu_timer* m_timer_cont; + + legacy_floppy_image_device* floppy_image(UINT8 drive); + legacy_floppy_image_device* floppy_image(); + void status_update(); + void cmd_end(); + void finish_STZ(); + void finish_SEK(); + int address_search(chrn_id* id); + int address_search_read(chrn_id* id); + void finish_RCR(); + void cont_SR(); + void cont_SW(); + +}; + +extern const device_type MC6843; + +#endif diff --git a/src/devices/machine/mc6846.c b/src/devices/machine/mc6846.c new file mode 100644 index 00000000000..18b9f723bfb --- /dev/null +++ b/src/devices/machine/mc6846.c @@ -0,0 +1,568 @@ +// license:BSD-3-Clause +// copyright-holders:Antoine Mine +/********************************************************************** + + Copyright (C) Antoine Mine' 2006 + + Motorola 6846 emulation. + + The MC6846 chip provides ROM (2048 bytes), I/O (8-bit directional data port + + 2 control lines) and a programmable timer. + It may be interfaced with a M6809 cpu. + It is used in some Thomson computers. + + Not yet implemented: + - external clock (CTC) + - latching of port on CP1 + - gate input (CTG) + - timer comparison modes (frequency and pulse width) + - CP2 acknowledge modes + +**********************************************************************/ + +#include "emu.h" +#include "mc6846.h" + +#define VERBOSE 0 + + +/******************* utility function and macros ********************/ + +#define LOG(x) do { if (VERBOSE) logerror x; } while (0) + +#define PORT \ + ((m_pdr & m_ddr) | \ + ((!m_in_port_cb.isnull() ? m_in_port_cb( 0 ) : 0) & \ + ~m_ddr)) + +#define CTO \ + ((MODE == 0x30 || (m_tcr & 0x80)) ? m_cto : 0) + +#define MODE (m_tcr & 0x38) + +#define FACTOR ((m_tcr & 4) ? 8 : 1) + + +const device_type MC6846 = &device_creator; + +mc6846_device::mc6846_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, MC6846, "MC6846 Programmable Timer", tag, owner, clock, "mc6846", __FILE__), + m_out_port_cb(*this), + m_out_cp1_cb(*this), + m_out_cp2_cb(*this), + m_in_port_cb(*this), + m_out_cto_cb(*this), + m_irq_cb(*this) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void mc6846_device::device_start() +{ + m_interval = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(mc6846_device::timer_expire), this)); + m_one_shot = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(mc6846_device::timer_one_shot), this)); + + m_out_port_cb.resolve(); /* 8-bit output */ + m_out_cp1_cb.resolve_safe(); /* 1-bit output */ + m_out_cp2_cb.resolve(); /* 1-bit output */ + + /* CPU read from the outside through chip */ + m_in_port_cb.resolve(); /* 8-bit input */ + + /* asynchronous timer output to outside world */ + m_out_cto_cb.resolve(); /* 1-bit output */ + + /* timer interrupt */ + m_irq_cb.resolve(); + + save_item(NAME(m_csr)); + save_item(NAME(m_pcr)); + save_item(NAME(m_ddr)); + save_item(NAME(m_pdr)); + save_item(NAME(m_tcr)); + save_item(NAME(m_cp1)); + save_item(NAME(m_cp2)); + save_item(NAME(m_cp2_cpu)); + save_item(NAME(m_cto)); + save_item(NAME(m_time_MSB)); + save_item(NAME(m_csr0_to_be_cleared)); + save_item(NAME(m_csr1_to_be_cleared)); + save_item(NAME(m_csr2_to_be_cleared)); + save_item(NAME(m_latch)); + save_item(NAME(m_preset)); + save_item(NAME(m_timer_started)); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void mc6846_device::device_reset() +{ + m_cto = 0; + m_csr = 0; + m_pcr = 0x80; + m_ddr = 0; + m_pdr = 0; + m_tcr = 1; + m_cp1 = 0; + m_cp2 = 0; + m_cp2_cpu = 0; + m_latch = 0xffff; + m_preset = 0xffff; + m_time_MSB = 0; + m_csr0_to_be_cleared = 0; + m_csr1_to_be_cleared = 0; + m_csr2_to_be_cleared = 0; + m_timer_started = 0; + m_old_cif = 0; + m_old_cto = 0; + m_interval->reset(); + m_one_shot->reset(); +} + + +inline UINT16 mc6846_device::counter() +{ + if ( m_timer_started ) + { + attotime delay = m_interval ->remaining( ); + return delay.as_ticks(1000000) / FACTOR; + } + else + return m_preset; +} + + + +inline void mc6846_device::update_irq() +{ + int cif = 0; + /* composite interrupt flag */ + if ( ( (m_csr & 1) && (m_tcr & 0x40) ) || + ( (m_csr & 2) && (m_pcr & 1) ) || + ( (m_csr & 4) && (m_pcr & 8) && ! (m_pcr & 0x20) ) ) + cif = 1; + if ( m_old_cif != cif ) + { + LOG (( "%f: mc6846 interrupt %i (time=%i cp1=%i cp2=%i)\n", + machine().time().as_double(), cif, + m_csr & 1, (m_csr >> 1 ) & 1, (m_csr >> 2 ) & 1 )); + m_old_cif = cif; + } + if ( cif ) + { + m_csr |= 0x80; + if ( !m_irq_cb.isnull() ) + m_irq_cb( 1 ); + } + else + { + m_csr &= ~0x80; + if ( !m_irq_cb.isnull() ) + m_irq_cb( 0 ); + } +} + + + +inline void mc6846_device::update_cto() +{ + int cto = CTO; + if ( cto != m_old_cto ) + { + LOG (( "%f: mc6846 CTO set to %i\n", machine().time().as_double(), cto )); + m_old_cto = cto; + } + if ( !m_out_cto_cb.isnull() ) + m_out_cto_cb( (offs_t) 0, cto ); +} + + + +inline void mc6846_device::timer_launch() +{ + int delay = FACTOR * (m_preset+1); + LOG (( "%f: mc6846 timer launch called, mode=%i, preset=%i (x%i)\n", machine().time().as_double(), MODE, m_preset, FACTOR )); + + if ( ! (m_tcr & 2) ) + { + logerror( "mc6846 external clock CTC not implemented\n" ); + } + + switch( MODE ) + { + case 0x00: + case 0x10: /* continuous */ + m_cto = 0; + break; + + case 0x20: /* single-shot */ + m_cto = 0; + m_one_shot->reset( attotime::from_usec(FACTOR) ); + break; + + case 0x30: /* cascaded single-shot */ + break; + + default: + logerror( "mc6846 timer mode %i not implemented\n", MODE ); + m_interval->reset(); + m_timer_started = 0; + return; + } + + m_interval->reset( attotime::from_usec(delay) ); + m_timer_started = 1; + + m_csr &= ~1; + update_cto(); + update_irq(); +} + + + +/******************* timer callbacks *********************************/ + +TIMER_CALLBACK_MEMBER( mc6846_device::timer_expire ) +{ + int delay = FACTOR * (m_latch+1); + + LOG (( "%f: mc6846 timer expire called, mode=%i, latch=%i (x%i)\n", machine().time().as_double(), MODE, m_latch, FACTOR )); + + /* latch => counter */ + m_preset = m_latch; + + if ( ! (m_tcr & 2) ) + logerror( "mc6846 external clock CTC not implemented\n" ); + + switch ( MODE ) + { + case 0x00: + case 0x10: /* continuous */ + m_cto = 1 ^ m_cto; + break; + + case 0x20: /* single-shot */ + m_cto = 0; + break; + + case 0x30: /* cascaded single-shot */ + m_cto = ( m_tcr & 0x80 ) ? 1 : 0; + break; + + default: + logerror( "mc6846 timer mode %i not implemented\n", MODE ); + m_interval->reset( ); + m_timer_started = 0; + return; + } + + m_interval->reset( attotime::from_usec(delay) ); + + m_csr |= 1; + update_cto(); + update_irq(); +} + + + +TIMER_CALLBACK_MEMBER( mc6846_device::timer_one_shot ) +{ + LOG (( "%f: mc6846 timer one shot called\n", machine().time().as_double() )); + + /* 1 micro second after one-shot launch, we put cto to high */ + m_cto = 1; + update_cto(); +} + + + +/************************** CPU interface ****************************/ + + +READ8_MEMBER(mc6846_device::read) +{ + switch ( offset ) + { + case 0: + case 4: + LOG (( "%s %f: mc6846 CSR read $%02X intr=%i (timer=%i, cp1=%i, cp2=%i)\n", + machine().describe_context(), space.machine().time().as_double(), + m_csr, (m_csr >> 7) & 1, + m_csr & 1, (m_csr >> 1) & 1, (m_csr >> 2) & 1 )); + m_csr0_to_be_cleared = m_csr & 1; + m_csr1_to_be_cleared = m_csr & 2; + m_csr2_to_be_cleared = m_csr & 4; + return m_csr; + + case 1: + LOG (( "%s %f: mc6846 PCR read $%02X\n", machine().describe_context(), space.machine().time().as_double(), m_pcr )); + return m_pcr; + + case 2: + LOG (( "%s %f: mc6846 DDR read $%02X\n", machine().describe_context(), space.machine().time().as_double(), m_ddr )); + return m_ddr; + + case 3: + LOG (( "%s %f: mc6846 PORT read $%02X\n", machine().describe_context(), space.machine().time().as_double(), PORT )); + if ( ! (m_pcr & 0x80) ) + { + if ( m_csr1_to_be_cleared ) + m_csr &= ~2; + if ( m_csr2_to_be_cleared ) + m_csr &= ~4; + update_irq(); + m_csr1_to_be_cleared = 0; + m_csr2_to_be_cleared = 0; + } + return PORT; + + case 5: + LOG (( "%s %f: mc6846 TCR read $%02X\n",machine().describe_context(), space.machine().time().as_double(), m_tcr )); + return m_tcr; + + case 6: + LOG (( "%s %f: mc6846 COUNTER hi read $%02X\n", machine().describe_context(), space.machine().time().as_double(), counter() >> 8 )); + if ( m_csr0_to_be_cleared ) + { + m_csr &= ~1; + update_irq(); + } + m_csr0_to_be_cleared = 0; + return counter() >> 8; + + case 7: + LOG (( "%s %f: mc6846 COUNTER low read $%02X\n", machine().describe_context(), space.machine().time().as_double(), counter() & 0xff )); + if ( m_csr0_to_be_cleared ) + { + m_csr &= ~1; + update_irq(); + } + m_csr0_to_be_cleared = 0; + return counter() & 0xff; + + default: + logerror( "%s mc6846 invalid read offset %i\n", machine().describe_context(), offset ); + } + return 0; +} + + + +WRITE8_MEMBER(mc6846_device::write) +{ + switch ( offset ) + { + case 0: + case 4: + /* CSR is read-only */ + break; + + case 1: + { + static const char *const cp2[8] = + { + "in,neg-edge", "in,neg-edge,intr", "in,pos-edge", "in,pos-edge,intr", + "out,intr-ack", "out,i/o-ack", "out,0", "out,1" + }; + static const char *const cp1[8] = + { + "neg-edge", "neg-edge,intr", "pos-edge", "pos-edge,intr", + "latched,neg-edge", "latched,neg-edge,intr", + "latcged,pos-edge", "latcged,pos-edge,intr" + }; + LOG (( "%s %f: mc6846 PCR write $%02X reset=%i cp2=%s cp1=%s\n", + machine().describe_context(), space.machine().time().as_double(), data, + (data >> 7) & 1, cp2[ (data >> 3) & 7 ], cp1[ data & 7 ] )); + + } + m_pcr = data; + if ( data & 0x80 ) + { /* data reset */ + m_pdr = 0; + m_ddr = 0; + m_csr &= ~6; + update_irq(); + } + if ( data & 4 ) + logerror( "%s mc6846 CP1 latching not implemented\n", machine().describe_context() ); + if (data & 0x20) + { + if (data & 0x10) + { + m_cp2_cpu = (data >> 3) & 1; + if ( !m_out_cp2_cb.isnull() ) + m_out_cp2_cb( (offs_t) 0, m_cp2_cpu ); + } + else + logerror( "%s mc6846 acknowledge not implemented\n", machine().describe_context() ); + } + break; + + case 2: + LOG (( "%s %f: mc6846 DDR write $%02X\n", machine().describe_context(), space.machine().time().as_double(), data )); + if ( ! (m_pcr & 0x80) ) + { + m_ddr = data; + if ( !m_out_port_cb.isnull() ) + m_out_port_cb( (offs_t) 0, m_pdr & m_ddr ); + } + break; + + case 3: + LOG (( "%s %f: mc6846 PORT write $%02X (mask=$%02X)\n", machine().describe_context(), space.machine().time().as_double(), data,m_ddr )); + if ( ! (m_pcr & 0x80) ) + { + m_pdr = data; + if ( !m_out_port_cb.isnull() ) + m_out_port_cb( (offs_t) 0, m_pdr & m_ddr ); + if ( m_csr1_to_be_cleared && (m_csr & 2) ) + { + m_csr &= ~2; + LOG (( "%s %f: mc6846 CP1 intr reset\n", machine().describe_context(), space.machine().time().as_double() )); + } + if ( m_csr2_to_be_cleared && (m_csr & 4) ) + { + m_csr &= ~4; + LOG (( "%s %f: mc6846 CP2 intr reset\n", machine().describe_context(), space.machine().time().as_double() )); + } + m_csr1_to_be_cleared = 0; + m_csr2_to_be_cleared = 0; + update_irq(); + } + break; + + case 5: + { + static const char *const mode[8] = + { + "continuous", "cascaded", "continuous", "one-shot", + "freq-cmp", "freq-cmp", "pulse-cmp", "pulse-cmp" + }; + LOG (( "%s %f: mc6846 TCR write $%02X reset=%i clock=%s scale=%i mode=%s out=%s\n", + machine().describe_context(), space.machine().time().as_double(), data, + (data >> 7) & 1, (data & 0x40) ? "extern" : "sys", + (data & 0x40) ? 1 : 8, mode[ (data >> 1) & 7 ], + (data & 1) ? "enabled" : "0" )); + + m_tcr = data; + if ( m_tcr & 1 ) + { + /* timer preset = initialization without launch */ + m_preset = m_latch; + m_csr &= ~1; + if ( MODE != 0x30 ) + m_cto = 0; + update_cto(); + m_interval->reset(); + m_one_shot->reset(); + m_timer_started = 0; + } + else + { + /* timer launch */ + if ( ! m_timer_started ) + timer_launch(); + } + update_irq(); + } + break; + + case 6: + m_time_MSB = data; + break; + + case 7: + m_latch = ( ((UINT16) m_time_MSB) << 8 ) + data; + LOG (( "%s %f: mc6846 COUNT write %i\n", machine().describe_context(), space.machine().time().as_double(), m_latch )); + if (!(m_tcr & 0x38)) + { + /* timer initialization */ + m_preset = m_latch; + m_csr &= ~1; + update_irq(); + m_cto = 0; + update_cto(); + /* launch only if started */ + if (!(m_tcr & 1)) + timer_launch(); + } + break; + + default: + logerror( "%s mc6846 invalid write offset %i\n", machine().describe_context(), offset ); + } +} + + + +/******************** outside world interface ************************/ + + + +void mc6846_device::set_input_cp1(int data) +{ + data = (data != 0 ); + if ( data == m_cp1 ) + return; + m_cp1 = data; + LOG (( "%f: mc6846 input CP1 set to %i\n", machine().time().as_double(), data )); + if (( data && (m_pcr & 2)) || (!data && !(m_pcr & 2))) + { + m_csr |= 2; + update_irq(); + } +} + +void mc6846_device::set_input_cp2(int data) +{ + data = (data != 0 ); + if ( data == m_cp2 ) + return; + m_cp2 = data; + LOG (( "%f: mc6846 input CP2 set to %i\n", machine().time().as_double(), data )); + if (m_pcr & 0x20) + { + if (( data && (m_pcr & 0x10)) || (!data && !(m_pcr & 0x10))) + { + m_csr |= 4; + update_irq(); + } + } +} + + + +/************************ accessors **********************************/ + + + +UINT8 mc6846_device::get_output_port() +{ + return PORT; +} + + + +UINT8 mc6846_device::get_output_cto() +{ + return CTO; +} + + + +UINT8 mc6846_device::get_output_cp2() +{ + return m_cp2_cpu; +} + + + +UINT16 mc6846_device::get_preset() +{ + return m_preset; +} diff --git a/src/devices/machine/mc6846.h b/src/devices/machine/mc6846.h new file mode 100644 index 00000000000..0bf6b84658f --- /dev/null +++ b/src/devices/machine/mc6846.h @@ -0,0 +1,125 @@ +// license:BSD-3-Clause +// copyright-holders:Antoine Mine +/********************************************************************** + + Copyright (C) Antoine Mine' 2006 + + Motorola 6846 timer emulation. + +**********************************************************************/ + +#ifndef MC6846_H +#define MC6846_H + + +#define MCFG_MC6846_OUT_PORT_CB(_devcb) \ + devcb = &mc6846_device::set_out_port_callback(*device, DEVCB_##_devcb); + +#define MCFG_MC6846_OUT_CP1_CB(_devcb) \ + devcb = &mc6846_device::set_out_cp1_callback(*device, DEVCB_##_devcb); + +#define MCFG_MC6846_OUT_CP2_CB(_devcb) \ + devcb = &mc6846_device::set_out_cp2_callback(*device, DEVCB_##_devcb); + +#define MCFG_MC6846_IN_PORT_CB(_devcb) \ + devcb = &mc6846_device::set_in_port_callback(*device, DEVCB_##_devcb); + +#define MCFG_MC6846_OUT_CTO_CB(_devcb) \ + devcb = &mc6846_device::set_out_cto_callback(*device, DEVCB_##_devcb); + +#define MCFG_MC6846_IRQ_CB(_devcb) \ + devcb = &mc6846_device::set_irq_callback(*device, DEVCB_##_devcb); + + +class mc6846_device : public device_t +{ +public: + mc6846_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + ~mc6846_device() {} + + template static devcb_base &set_out_port_callback(device_t &device, _Object object) { return downcast(device).m_out_port_cb.set_callback(object); } + template static devcb_base &set_out_cp1_callback(device_t &device, _Object object) { return downcast(device).m_out_cp1_cb.set_callback(object); } + template static devcb_base &set_out_cp2_callback(device_t &device, _Object object) { return downcast(device).m_out_cp2_cb.set_callback(object); } + template static devcb_base &set_in_port_callback(device_t &device, _Object object) { return downcast(device).m_in_port_cb.set_callback(object); } + template static devcb_base &set_out_cto_callback(device_t &device, _Object object) { return downcast(device).m_out_cto_cb.set_callback(object); } + template static devcb_base &set_irq_callback(device_t &device, _Object object) { return downcast(device).m_irq_cb.set_callback(object); } + + /* interface to CPU via address/data bus*/ + DECLARE_READ8_MEMBER(read); + DECLARE_WRITE8_MEMBER(write); + + /* asynchronous write from outside world into interrupt-generating pins */ + void set_input_cp1(int data); + void set_input_cp2(int data); + + /* polling from outside world */ + UINT8 get_output_port(); + UINT8 get_output_cto(); + UINT8 get_output_cp2(); + + /* partial access to internal state */ + UINT16 get_preset(); /* timer interval - 1 in us */ + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + +private: + // internal state + + /* registers */ + UINT8 m_csr; /* 0,4: combination status register */ + UINT8 m_pcr; /* 1: peripheral control register */ + UINT8 m_ddr; /* 2: data direction register */ + UINT8 m_pdr; /* 3: peripheral data register (last cpu write) */ + UINT8 m_tcr; /* 5: timer control register */ + + /* lines */ + UINT8 m_cp1; /* 1-bit input */ + UINT8 m_cp2; /* 1-bit input/output: last external write */ + UINT8 m_cp2_cpu; /* last cpu write */ + UINT8 m_cto; /* 1-bit timer output (unmasked) */ + + /* internal state */ + UINT8 m_time_MSB; /* MSB buffer register */ + UINT8 m_csr0_to_be_cleared; + UINT8 m_csr1_to_be_cleared; + UINT8 m_csr2_to_be_cleared; + UINT16 m_latch; /* timer latch */ + UINT16 m_preset; /* preset value */ + UINT8 m_timer_started; + + /* timers */ + emu_timer *m_interval; /* interval programmable timer */ + emu_timer *m_one_shot; /* 1-us x factor one-shot timer */ + + /* CPU write to the outside through chip */ + devcb_write8 m_out_port_cb; /* 8-bit output */ + devcb_write8 m_out_cp1_cb; /* 1-bit output */ + devcb_write8 m_out_cp2_cb; /* 1-bit output */ + + /* CPU read from the outside through chip */ + devcb_read8 m_in_port_cb; /* 8-bit input */ + + /* asynchronous timer output to outside world */ + devcb_write8 m_out_cto_cb; /* 1-bit output */ + + /* timer interrupt */ + devcb_write_line m_irq_cb; + + int m_old_cif; + int m_old_cto; + + inline UINT16 counter(); + inline void update_irq(); + inline void update_cto(); + inline void timer_launch(); + + TIMER_CALLBACK_MEMBER(timer_expire); + TIMER_CALLBACK_MEMBER(timer_one_shot); +}; + +extern const device_type MC6846; + +#endif diff --git a/src/devices/machine/mc6852.c b/src/devices/machine/mc6852.c new file mode 100644 index 00000000000..b0cf1ff9ca9 --- /dev/null +++ b/src/devices/machine/mc6852.c @@ -0,0 +1,302 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Motorola MC6852 Synchronous Serial Data Adapter emulation + +**********************************************************************/ + +/* + + TODO: + + - FIFO + - receive + - transmit + - parity + - 1-sync-character mode + - 2-sync-character mode + - external sync mode + - interrupts + +*/ + +#include "mc6852.h" + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type MC6852 = &device_creator; + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define LOG 0 + + +#define S_RDA 0x01 +#define S_TDRA 0x02 +#define S_DCD 0x04 +#define S_CTS 0x08 +#define S_TUF 0x10 +#define S_RX_OVRN 0x20 +#define S_PE 0x40 +#define S_IRQ 0x80 + + +#define C1_RX_RS 0x01 +#define C1_TX_RS 0x02 +#define C1_STRIP_SYNC 0x04 +#define C1_CLEAR_SYNC 0x08 +#define C1_TIE 0x10 +#define C1_RIE 0x20 +#define C1_AC_MASK 0xc0 +#define C1_AC_C2 0x00 +#define C1_AC_C3 0x40 +#define C1_AC_SYNC 0x80 +#define C1_AC_TX_FIFO 0xc0 + + +#define C2_PC1 0x01 +#define C2_PC2 0x02 +#define C2_1_2_BYTE 0x04 +#define C2_WS_MASK 0x38 +#define C2_WS_6_E 0x00 +#define C2_WS_6_O 0x08 +#define C2_WS_7 0x10 +#define C2_WS_8 0x18 +#define C2_WS_7_E 0x20 +#define C2_WS_7_O 0x28 +#define C2_WS_8_E 0x30 +#define C2_WS_8_O 0x38 +#define C2_TX_SYNC 0x40 +#define C2_EIE 0x80 + + +#define C3_E_I_SYNC 0x01 +#define C3_1_2_SYNC 0x02 +#define C3_CLEAR_CTS 0x04 +#define C3_CTUF 0x08 + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// mc6852_device - constructor +//------------------------------------------------- + +mc6852_device::mc6852_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, MC6852, "MC6852", tag, owner, clock, "mc6852", __FILE__), + device_serial_interface(mconfig, *this), + m_write_tx_data(*this), + m_write_irq(*this), + m_write_sm_dtr(*this), + m_write_tuf(*this), + m_rx_clock(0), + m_tx_clock(0), + m_cts(1), + m_dcd(1), + m_sm_dtr(0), + m_tuf(0) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void mc6852_device::device_start() +{ + // resolve callbacks + m_write_tx_data.resolve_safe(); + m_write_irq.resolve_safe(); + m_write_sm_dtr.resolve_safe(); + m_write_tuf.resolve_safe(); + + // register for state saving + save_item(NAME(m_status)); + save_item(NAME(m_cr)); + save_item(NAME(m_scr)); + save_item(NAME(m_tdr)); + save_item(NAME(m_tsr)); + save_item(NAME(m_rdr)); + save_item(NAME(m_rsr)); + save_item(NAME(m_cts)); + save_item(NAME(m_dcd)); + save_item(NAME(m_sm_dtr)); + save_item(NAME(m_tuf)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void mc6852_device::device_reset() +{ + m_rx_fifo = std::queue(); + m_tx_fifo = std::queue(); + + transmit_register_reset(); + receive_register_reset(); + + set_rcv_rate(m_rx_clock); + set_tra_rate(m_tx_clock); + + /* set receiver shift register to all 1's */ + m_rsr = 0xff; + + /* reset and inhibit receiver/transmitter sections */ + m_cr[0] |= (C1_TX_RS | C1_RX_RS); +} + + +//------------------------------------------------- +// device_timer - handler timer events +//------------------------------------------------- + +void mc6852_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + device_serial_interface::device_timer(timer, id, param, ptr); +} + + +//------------------------------------------------- +// tra_callback - +//------------------------------------------------- + +void mc6852_device::tra_callback() +{ + m_write_tx_data(transmit_register_get_data_bit()); +} + + +//------------------------------------------------- +// tra_complete - +//------------------------------------------------- + +void mc6852_device::tra_complete() +{ + // TODO +} + + +//------------------------------------------------- +// rcv_complete - +//------------------------------------------------- + +void mc6852_device::rcv_complete() +{ + // TODO +} + + +//------------------------------------------------- +// read - +//------------------------------------------------- + +READ8_MEMBER( mc6852_device::read ) +{ + UINT8 data = 0; + + if (BIT(offset, 0)) + { + if (m_rx_fifo.size() > 0) + { + data = m_rx_fifo.front(); + m_rx_fifo.pop(); + } + } + else + { + data = m_status; + } + + return data; +} + + +//------------------------------------------------- +// write - +//------------------------------------------------- + +WRITE8_MEMBER( mc6852_device::write ) +{ + if (BIT(offset, 0)) + { + switch (m_cr[0] & C1_AC_MASK) + { + case C1_AC_C2: + /* control 2 */ + m_cr[1] = data; + break; + + case C1_AC_C3: + /* control 3 */ + m_cr[2] = data; + break; + + case C1_AC_SYNC: + /* sync code */ + m_scr = data; + break; + + case C1_AC_TX_FIFO: + /* transmit data FIFO */ + if (m_tx_fifo.size() < 3) + { + m_tx_fifo.push(data); + } + break; + } + } + else + { + /* receiver reset */ + if (data & C1_RX_RS) + { + /* When Rx Rs is set, it clears the receiver + control logic, sync logic, error logic, Rx Data FIFO Control, + Parity Error status bit, and DCD interrupt. The Receiver Shift + Register is set to ones. + */ + + if (LOG) logerror("MC6852 '%s' Receiver Reset\n", tag()); + + m_status &= ~(S_RX_OVRN | S_PE | S_DCD | S_RDA); + m_rsr = 0xff; + } + + /* transmitter reset */ + if (data & C1_TX_RS) + { + /* When Tx Rs is set, it clears the transmitter + control section, Transmitter Shift Register, Tx Data FIFO + Control (the Tx Data FIFO can be reloaded after one E clock + pulse), the Transmitter Underflow status bit, and the CTS interrupt, + and inhibits the TDRA status bit (in the one-sync-character + and two-sync-character modes).*/ + + if (LOG) logerror("MC6852 '%s' Transmitter Reset\n", tag()); + + m_status &= ~(S_TUF | S_CTS | S_TDRA); + } + + if (LOG) + { + if (data & C1_STRIP_SYNC) logerror("MC6852 '%s' Strip Synchronization Characters\n", tag()); + if (data & C1_CLEAR_SYNC) logerror("MC6852 '%s' Clear Synchronization\n", tag()); + } + + m_cr[0] = data; + } +} diff --git a/src/devices/machine/mc6852.h b/src/devices/machine/mc6852.h new file mode 100644 index 00000000000..859d9e8bef2 --- /dev/null +++ b/src/devices/machine/mc6852.h @@ -0,0 +1,132 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Motorola MC6852 Synchronous Serial Data Adapter emulation + +********************************************************************** + _____ _____ + Vss 1 |* \_/ | 24 _CTS + Rx DATA 2 | | 23 _DCD + Rx CLK 3 | | 22 D0 + Tx CLK 4 | | 21 D1 + SM/_DTR 5 | | 20 D2 + Tx DATA 6 | MC6852 | 19 D3 + _IRQ 7 | | 18 D4 + TUF 8 | | 17 D5 + _RESET 9 | | 16 D6 + _CS 9 | | 15 D7 + RS 9 | | 14 E + Vcc 10 |_____________| 13 R/_W + +**********************************************************************/ + +#pragma once + +#ifndef __MC6852__ +#define __MC6852__ + +#include "emu.h" +#include + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_MC6852_RX_CLOCK(_clock) \ + mc6852_device::set_rx_clock(*device, _clock); + +#define MCFG_MC6852_TX_CLOCK(_clock) \ + mc6852_device::set_tx_clock(*device, _clock); + +#define MCFG_MC6852_TX_DATA_CALLBACK(_write) \ + devcb = &mc6852_device::set_tx_data_wr_callback(*device, DEVCB_##_write); + +#define MCFG_MC6852_IRQ_CALLBACK(_write) \ + devcb = &mc6852_device::set_irq_wr_callback(*device, DEVCB_##_write); + +#define MCFG_MC6852_SM_DTR_CALLBACK(_write) \ + devcb = &mc6852_device::set_sm_dtr_wr_callback(*device, DEVCB_##_write); + +#define MCFG_MC6852_TUF_CALLBACK(_write) \ + devcb = &mc6852_device::set_tuf_wr_callback(*device, DEVCB_##_write); + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> mc6852_device + +class mc6852_device : public device_t, + public device_serial_interface +{ +public: + // construction/destruction + mc6852_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + static void set_rx_clock(device_t &device, int clock) { downcast(device).m_rx_clock = clock; } + static void set_tx_clock(device_t &device, int clock) { downcast(device).m_tx_clock = clock; } + template static devcb_base &set_tx_data_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_tx_data.set_callback(object); } + template static devcb_base &set_irq_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_irq.set_callback(object); } + template static devcb_base &set_sm_dtr_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_sm_dtr.set_callback(object); } + template static devcb_base &set_tuf_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_tuf.set_callback(object); } + + DECLARE_READ8_MEMBER( read ); + DECLARE_WRITE8_MEMBER( write ); + + DECLARE_WRITE_LINE_MEMBER( rx_data_w ) { device_serial_interface::rx_w(state); } + DECLARE_WRITE_LINE_MEMBER( rx_clk_w ) { rx_clock_w(state); } + DECLARE_WRITE_LINE_MEMBER( tx_clk_w ) { tx_clock_w(state); } + DECLARE_WRITE_LINE_MEMBER( cts_w ) { m_cts = state; } + DECLARE_WRITE_LINE_MEMBER( dcd_w ) { m_dcd = state; } + + DECLARE_READ_LINE_MEMBER( sm_dtr_r ) { return m_sm_dtr; } + DECLARE_READ_LINE_MEMBER( tuf_r ) { return m_tuf; } + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int m_param, void *ptr); + + // device_serial_interface overrides + virtual void tra_callback(); + virtual void tra_complete(); + virtual void rcv_complete(); + +private: + devcb_write_line m_write_tx_data; + devcb_write_line m_write_irq; + devcb_write_line m_write_sm_dtr; + devcb_write_line m_write_tuf; + + UINT8 m_status; // status register + UINT8 m_cr[3]; // control registers + UINT8 m_scr; // sync code register + UINT8 m_tdr; // transmit data register + UINT8 m_tsr; // transmit shift register + UINT8 m_rdr; // receive data register + UINT8 m_rsr; // receive shift register + + std::queue m_rx_fifo; + std::queue m_tx_fifo; + + int m_rx_clock; + int m_tx_clock; + int m_cts; // clear to send + int m_dcd; // data carrier detect + int m_sm_dtr; // sync match/data terminal ready + int m_tuf; // transmitter underflow +}; + + +// device type definition +extern const device_type MC6852; + + + +#endif diff --git a/src/devices/machine/mc6854.c b/src/devices/machine/mc6854.c new file mode 100644 index 00000000000..7ed16885b19 --- /dev/null +++ b/src/devices/machine/mc6854.c @@ -0,0 +1,989 @@ +// license:BSD-3-Clause +// copyright-holders:Antoine Mine +/********************************************************************** + + Copyright (C) Antoine Mine' 2006 + + Motorola 6854 emulation. + + The MC6854 chip is an Advanced Data-Link Controller (ADLC). + It provides a high-level network interface that can transimit frames with + arbitrary data and address length, and is compatible with the following + standards: + - ADCCP (Advanced Data Communication Control Procedure) + - HDLC (High-Level Data-Link Control) + - SDLC (Synchronous Data-Link Control) + It is designed to be interfaced with a M6800-family CPU. + + It is used in the "Nano-network" extension of the Thomson computers to + link up to 32 computers at 500 Kbps. + Many networks involving one PC server and several MO5 or TO7/70 computers + were build in French schools in the 1980's to teach computer science. + + TODO: + - CRC + - DMA mode + - loop mode + - status prioritization + - NRZI vs. NRZ coding + - FD output + +**********************************************************************/ + + +#include "emu.h" +#include "mc6854.h" + + +/******************* parameters ******************/ + + + +#define VERBOSE 0 + + +#define FLAG 0x7e +/* flag value, as defined by HDLC protocol: 01111110 */ + +#define BIT_LENGTH attotime::from_hz( 500000 ) + + +/******************* utility function and macros ********************/ + + + +#define LOG(x) do { if (VERBOSE) logerror x; } while (0) + + + +/* control register 1 */ + +#define AC ( m_cr1 & 1 ) +#define FCTDRA ( m_cr2 & 8 ) +/* extra register select bits */ + +#define RRESET ( m_cr1 & 0x40 ) +#define TRESET ( m_cr1 & 0x80 ) +/* transmit / reset condition */ + +#define RIE ( m_cr1 & 2 ) +#define TIE ( m_cr1 & 4 ) +/* interrupt enable */ + +#define DISCONTINUE ( m_cr1 & 0x20 ) +/* discontinue received frame */ + + + +/* control register 2 */ + +#define PSE ( m_cr2 & 1 ) +/* prioritize status bits (TODO) */ + +#define TWOBYTES ( m_cr2 & 2 ) +/* two-bytes mode */ + +#define FMIDLE ( m_cr2 & 4 ) +/* flag time fill (vs. mark idle) */ + +#define TLAST ( m_cr2 & 0x10 ) +/* transmit last byte of frame */ + +#define RTS ( m_cr2 & 0x80 ) +/* request-to-send */ + + + +/* control register 3 */ + +#define LCF ( m_cr3 & 1 ) +/* logical control field select */ + +#define CEX ( m_cr3 & 2 ) +/* control field is 16 bits instead of 8 */ + +#define AEX ( m_cr3 & 4 ) +/* extended address mode (vs normal 8-bit address mode) */ + +#define IDL0 ( m_cr3 & 8 ) +/* idle condition begins with a '0' instead of a '1" */ + +#define FDSE ( m_cr3 & 0x10 ) +/* enable the flag detect status in SR1 */ + +#define LOOP ( m_cr3 & 0x20 ) +/* loop mode */ + +#define TST ( m_cr3 & 0x40 ) +/* test mode (or go active on poll) */ + +#define DTR ( m_cr3 & 0x80 ) +/* data-transmit-ready (or loop on-line control) */ + + + +/* control register 4 */ + +#define TWOINTER ( m_cr4 & 1 ) +/* both an openning and a closing inter-frame are sent */ + +static const int word_length[4] = { 5, 6, 7, 8 }; +#define TWL word_length[ ( m_cr4 >> 1 ) & 3 ] +#define RWL word_length[ ( m_cr4 >> 3 ) & 3 ] +/* transmit / receive word length */ + +#define ABT ( m_cr4 & 0x20 ) +/* aborts */ + +#define ABTEX ( m_cr4 & 0x40 ) +/* abort generates 16 '1' bits instead of 8 */ + +#define NRZ ( m_cr4 & 0x80 ) +/* zero complement / non-zero complement data format */ + + + +/* status register 1 */ +#define RDA 0x01 /* receiver data available */ +#define S2RQ 0x02 /* status register #2 read request */ +#define FD 0x04 /* flag detect */ +#define CTS 0x10 /* clear-to-send */ +#define TU 0x20 /* transmitter underrun */ +#define TDRA 0x40 /* transmitter data register available */ +#define IRQ 0x80 /* interrupt request */ + + +/* status register 2 */ +#define AP 0x01 /* address present */ +#define FV 0x02 /* frame valid */ +#define RIDLE 0x04 /* receiver idle */ +#define RABT 0x08 /* receiver abort */ +#define ERR 0x10 /* invalid frame error */ +#define DCD 0x20 /* data carrier detect (ignored) */ +#define OVRN 0x40 /* receiver overrun */ +#define RDA2 0x80 /* copy of RDA */ + + + +const device_type MC6854 = &device_creator; + +mc6854_device::mc6854_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, MC6854, "MC6854 ADLC", tag, owner, clock, "mc6854", __FILE__), + m_out_irq_cb(*this), + m_out_txd_cb(*this), + m_out_rts_cb(*this), + m_out_dtr_cb(*this), + m_cr1(0), + m_cr2(0), + m_cr3(0), + m_cr4(0), + m_sr1(0), + m_sr2(0), + m_cts(0), + m_dcd(0), + m_tstate(0), + m_tones(0), + m_ttimer(NULL), + m_rstate(0), + m_rreg(0), + m_rones(0), + m_rsize(0), + m_flen(0), + m_fpos(0) +{ + for (int i = 0; i < MC6854_FIFO_SIZE; i++) + { + m_tfifo[i] = 0; + m_rfifo[i] = 0; + } + + for (int i = 0; i < MAX_FRAME_LENGTH; i++) + { + m_frame[i] = 0; + } +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void mc6854_device::device_start() +{ + m_out_irq_cb.resolve_safe(); + m_out_txd_cb.resolve(); + m_out_frame_cb.bind_relative_to(*owner()); + m_out_rts_cb.resolve_safe(); + m_out_dtr_cb.resolve_safe(); + + m_ttimer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(mc6854_device::tfifo_cb), this)); + + save_item(NAME(m_cr1)); + save_item(NAME(m_cr2)); + save_item(NAME(m_cr3)); + save_item(NAME(m_cr4)); + save_item(NAME(m_sr1)); + save_item(NAME(m_sr2)); + save_item(NAME(m_cts)); + save_item(NAME(m_dcd)); + save_item(NAME(m_tstate)); + save_item(NAME(m_tfifo)); + save_item(NAME(m_tones)); + save_item(NAME(m_rstate)); + save_item(NAME(m_rreg)); + save_item(NAME(m_rones)); + save_item(NAME(m_rsize)); + save_item(NAME(m_rfifo)); + save_item(NAME(m_frame)); + save_item(NAME(m_flen)); + save_item(NAME(m_fpos)); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void mc6854_device::device_reset() +{ + LOG (( "mc6854 reset\n" )); + m_cr1 = 0xc0; /* reset condition */ + m_cr2 = 0; + m_cr3 = 0; + m_cr4 = 0; + m_sr1 = 0; + m_sr2 = 0; + m_cts = 0; + m_dcd = 0; + tfifo_clear( ); + rfifo_clear( ); +} + +/*********************** transmit ***********************/ + + + +/* MC6854 fills bit queue */ +void mc6854_device::send_bits( UINT32 data, int len, int zi ) +{ + attotime expire; + int i; + if ( zi ) + { + /* zero-insertion mode */ + UINT32 d = 0; + int l = 0; + for ( i = 0; i < len; i++, data >>= 1, l++ ) + { + if ( data & 1 ) + { + d |= 1 << l; + m_tones++; + if ( m_tones == 5 ) + { + /* insert a '0' after 5 consecutive '1" */ + m_tones = 0; + l++; + } + } + else + m_tones = 0; + } + data = d; + len = l; + } + else + m_tones = 0; + + /* send bits */ + if ( !m_out_txd_cb.isnull() ) + { + for ( i = 0; i < len; i++, data >>= 1 ) + m_out_txd_cb( data & 1 ); + } + + /* schedule when to ask the MC6854 for more bits */ + expire = m_ttimer ->remaining( ); + if ( expire== attotime::never ) + expire = attotime::zero; + m_ttimer->reset( expire + (BIT_LENGTH * len)); +} + + + +/* CPU push -> tfifo[0] -> ... -> tfifo[MC6854_FIFO_SIZE-1] -> pop */ +void mc6854_device::tfifo_push( UINT8 data ) +{ + int i; + + if ( TRESET ) + return; + + /* push towards the rightmost free entry */ + for ( i = MC6854_FIFO_SIZE - 1; i >= 0; i-- ) + { + if ( ! ( m_tfifo[ i ] & 0x100 ) ) + break; + } + + if ( i >= 0 ) + m_tfifo[ i ] = data | 0x100; + else + logerror( "%f mc6854_tfifo_push: FIFO overrun\n", machine().time().as_double() ); + + /* start frame, if needed */ + if ( ! m_tstate ) + { + LOG(( "%f mc6854_tfifo_push: start frame\n", machine().time().as_double() )); + m_tstate = 2; + send_bits( FLAG, 8, 0 ); + } +} + + + +/* CPU asks for normal frame termination */ +void mc6854_device::tfifo_terminate( ) +{ + /* mark most recently pushed byte as the last one of the frame */ + int i; + for ( i = 0; i < MC6854_FIFO_SIZE; i++ ) + { + if ( m_tfifo[ i ] & 0x100 ) + { + m_tfifo[ i ] |= 0x200; + break; + } + } +} + + + +/* call-back to refill the bit-stream from the FIFO */ +TIMER_CALLBACK_MEMBER(mc6854_device::tfifo_cb) +{ + int i, data = m_tfifo[ MC6854_FIFO_SIZE - 1 ]; + + if ( ! m_tstate ) + return; + + /* shift FIFO to the right */ + for ( i = MC6854_FIFO_SIZE - 1; i > 0; i-- ) + m_tfifo[ i ] = m_tfifo[ i - 1 ]; + m_tfifo[ 0 ] = 0; + + if ( data & 0x100 ) + { + /* got data */ + + int blen = 8; + + switch ( m_tstate ) + { + case 2: /* 8-bit address field */ + if ( ( data & 1 ) || ( ! AEX ) ) + m_tstate = 3; + LOG(( "%f mc6854_tfifo_cb: address field $%02X\n", machine().time().as_double(), data & 0xff )); + break; + + case 3: /* 8-bit control field */ + if ( CEX ) + m_tstate = 4; + else if ( LCF ) + m_tstate = 5; + else + m_tstate = 6; + LOG(( "%f mc6854_tfifo_cb: control field $%02X\n", machine().time().as_double(), data & 0xff )); + break; + + case 4: /* 8-bit extended control field (optional) */ + if ( LCF ) + m_tstate = 5; + else + m_tstate = 6; + LOG(( "%f mc6854_tfifo_cb: control field $%02X\n", machine().time().as_double(), data & 0xff )); + break; + + case 5: /* 8-bit logical control (optional) */ + if ( ! ( data & 0x80 ) ) + m_tstate = 6; + LOG(( "%f mc6854_tfifo_cb: logical control field $%02X\n", machine().time().as_double(), data & 0xff )); + break; + + case 6: /* variable-length data */ + blen = TWL; + LOG(( "%f mc6854_tfifo_cb: data field $%02X, %i bits\n", machine().time().as_double(), data & 0xff, blen )); + break; + + default: + LOG(( "%f mc6854_tfifo_cb: state=%i\n", machine().time().as_double(), m_tstate)); + } + + if ( m_flen < MAX_FRAME_LENGTH ) + m_frame[ m_flen++ ] = data; + else + logerror( "mc6854_tfifo_cb: truncated frame, max=%i\n", MAX_FRAME_LENGTH ); + + send_bits( data, blen, 1 ); + } + else + { + /* data underrun => abort */ + logerror( "%f mc6854_tfifo_cb: FIFO underrun\n", machine().time().as_double() ); + m_sr1 |= TU; + m_tstate = 0; + send_bits( 0xffff, ABTEX ? 16 : 8, 0 ); + m_flen = 0; + } + + /* close frame, if needed */ + if ( data & 0x200 ) + { + int len = m_flen; + + LOG(( "%f mc6854_tfifo_cb: end frame\n", machine().time().as_double() )); + send_bits( 0xdeadbeef, 16, 1 ); /* send check-sum: TODO */ + send_bits( FLAG, 8, 0 ); /* send closing flag */ + + if ( m_tfifo[ MC6854_FIFO_SIZE - 1 ] & 0x100 ) + { + /* re-open frame asap */ + LOG(( "%f mc6854_tfifo_cb: start frame\n", machine().time().as_double() )); + if ( TWOINTER ) + send_bits( FLAG, 8, 0 ); + } + else + m_tstate = 0; + + m_flen = 0; + if ( !m_out_frame_cb.isnull() ) + m_out_frame_cb( m_frame, len ); + } +} + + + +void mc6854_device::tfifo_clear( ) +{ + memset( m_tfifo, 0, sizeof( m_tfifo ) ); + m_tstate = 0; + m_flen = 0; + m_ttimer->reset( ); +} + + + +/*********************** receive ***********************/ + + + +/* MC6854 pushes a field in the FIFO */ +void mc6854_device::rfifo_push( UINT8 d ) +{ + int i, blen = 8; + unsigned data = d; + + switch ( m_rstate ) + { + case 0: + case 1: + case 2: /* 8-bit address field */ + if ( ( data & 1 ) || ( ! AEX ) ) + m_rstate = 3; + else + m_rstate = 2; + LOG(( "%f mc6854_rfifo_push: address field $%02X\n", machine().time().as_double(), data )); + data |= 0x400; /* address marker */ + break; + + case 3: /* 8-bit control field */ + if ( CEX ) + m_rstate = 4; + else if ( LCF ) + m_rstate = 5; + else + m_rstate = 6; + LOG(( "%f mc6854_rfifo_push: control field $%02X\n", machine().time().as_double(), data )); + break; + + case 4: /* 8-bit extended control field (optional) */ + if ( LCF ) + m_rstate = 5; + else + m_rstate = 6; + LOG(( "%f mc6854_rfifo_push: control field $%02X\n", machine().time().as_double(), data )); + break; + + case 5: /* 8-bit logical control (optional) */ + if ( ! ( data & 0x80 ) ) + m_rstate = 6; + LOG(( "%f mc6854_rfifo_push: logical control field $%02X\n", machine().time().as_double(), data )); + break; + + case 6: /* variable-length data */ + blen = RWL; + data >>= 8 - blen; + LOG(( "%f mc6854_rfifo_push: data field $%02X, %i bits\n", machine().time().as_double(), data, blen )); + break; + } + + /* no further FIFO fill until FV is cleared! */ + if ( m_sr2 & FV ) + { + LOG(( "%f mc6854_rfifo_push: field not pushed\n", machine().time().as_double() )); + return; + } + + data |= 0x100; /* entry full marker */ + + /* push towards the rightmost free entry */ + for ( i = MC6854_FIFO_SIZE - 1; i >= 0; i-- ) + { + if ( ! ( m_rfifo[ i ] & 0x100 ) ) + break; + } + + if ( i >= 0 ) + m_rfifo[ i ] = data | 0x100; + else + { + /* FIFO full */ + m_sr2 |= OVRN; + m_rfifo[ 0 ] = data; + logerror( "%f mc6854_rfifo_push: FIFO overrun\n", machine().time().as_double() ); + } + + m_rsize -= blen; +} + + + +void mc6854_device::rfifo_terminate( ) +{ + /* mark most recently pushed byte as the last one of the frame */ + int i; + for ( i = 0; i < MC6854_FIFO_SIZE; i++ ) + { + if ( m_rfifo[ i ] & 0x100 ) + { + m_tfifo[ i ] |= 0x200; + break; + } + + } + + m_flen = 0; + m_rstate = 1; +} + + + +/* CPU pops the FIFO */ +UINT8 mc6854_device::rfifo_pop( ) +{ + int i, data = m_rfifo[ MC6854_FIFO_SIZE - 1 ]; + + /* shift FIFO to the right */ + for ( i = MC6854_FIFO_SIZE - 1; i > 0; i -- ) + m_rfifo[ i ] = m_rfifo[ i - 1 ]; + m_rfifo[ 0 ] = 0; + + if ( m_rfifo[ MC6854_FIFO_SIZE - 1 ] & 0x200 ) + { + /* last byte in frame */ + m_sr2 |= FV; /* TODO: check CRC & set ERR instead of FV if error*/ + } + + /* auto-refill in frame mode */ + if ( m_flen > 0 ) + { + rfifo_push( m_frame[ m_fpos++ ] ); + if ( m_fpos == m_flen ) + rfifo_terminate( ); + } + + return data; +} + + +/* MC6854 makes fields from bits */ +WRITE_LINE_MEMBER( mc6854_device::set_rx ) +{ + int fieldlen = ( m_rstate < 6 ) ? 8 : RWL; + + if ( RRESET || (m_sr2 & DCD) ) + return; + + if ( state ) + { + m_rones++; + m_rreg = (m_rreg >> 1) | 0x80000000; + if ( m_rones >= 8 ) + { + /* abort */ + m_rstate = 0; + m_rsize = 0; + if ( m_rstate > 1 ) + { + /* only in-frame abort */ + m_sr2 |= RABT; + LOG(( "%f mc6854_receive_bit: abort\n", machine().time().as_double() )); + } + } + else + { + m_rsize++; + if ( m_rstate && m_rsize >= fieldlen + 24 ) + rfifo_push( m_rreg ); + } + } + else if ( m_rones == 5 ) + { + /* discards '0' inserted after 5 '1' */ + m_rones = 0; + return; + } + else if ( m_rones == 6 ) + { + /* flag */ + if ( FDSE ) + m_sr1 |= FD; + + if ( m_rstate > 1 ) + { + /* end of frame */ + m_rreg >>= 1; + m_rsize++; + if ( m_rsize >= fieldlen + 24 ) /* last field */ + rfifo_push( m_rreg ); + rfifo_terminate( ); + LOG(( "%f mc6854_receive_bit: end of frame\n", machine().time().as_double() )); + } + m_rones = 0; + m_rstate = 1; + m_rsize = 0; + } else + { + m_rones = 0; + m_rreg >>= 1; + m_rsize++; + if ( m_rstate && m_rsize >= fieldlen + 24 ) + rfifo_push( m_rreg ); + } +} + + + +void mc6854_device::rfifo_clear( ) +{ + memset( m_rfifo, 0, sizeof( m_rfifo ) ); + m_rstate = 0; + m_rreg = 0; + m_rsize = 0; + m_rones = 0; + m_flen = 0; +} + + + +int mc6854_device::send_frame( UINT8* data, int len ) +{ + if ( m_rstate > 1 || m_tstate > 1 || RTS ) + return -1; /* busy */ + + if ( len > MAX_FRAME_LENGTH ) + { + logerror( "mc6854_send_frame: truncated frame, size=%i, max=%i\n", len, MAX_FRAME_LENGTH ); + len = MAX_FRAME_LENGTH; + } + else if ( len < 2 ) + { + logerror( "mc6854_send_frame: frame too short, size=%i, min=2\n", len ); + len = 2; + } + memcpy( m_frame, data, len ); + if ( FDSE ) + m_sr1 |= FD; + m_flen = len; + m_fpos = 0; + rfifo_push( m_frame[ m_fpos++ ] ); + rfifo_push( m_frame[ m_fpos++ ] ); + if ( m_fpos == m_flen ) + rfifo_terminate( ); + return 0; +} + + + +/************************** CPU interface ****************************/ + + + +WRITE_LINE_MEMBER( mc6854_device::set_cts ) +{ + if ( ! m_cts && state ) + m_sr1 |= CTS; + m_cts = state; + + if ( m_cts ) + m_sr1 |= CTS; + else + m_sr1 &= ~CTS; +} + + + +WRITE_LINE_MEMBER( mc6854_device::set_dcd ) +{ + if ( ! m_dcd && state ) + { + m_sr2 |= DCD; + /* partial reset */ + m_rstate = 0; + m_rreg = 0; + m_rsize = 0; + m_rones = 0; + } + m_dcd = state; +} + + + +void mc6854_device::update_sr2( ) +{ + /* update RDA */ + m_sr2 |= RDA2; + if ( ! (m_rfifo[ MC6854_FIFO_SIZE - 1 ] & 0x100) ) + m_sr2 &= ~RDA2; + else if ( TWOBYTES && ! (m_tfifo[ MC6854_FIFO_SIZE - 2 ] & 0x100) ) + m_sr2 &= ~RDA2; + + /* update AP */ + if ( m_rfifo[ MC6854_FIFO_SIZE - 1 ] & 0x400 ) + m_sr2 |= AP; + else + m_sr2 &= ~AP; +} + + + +void mc6854_device::update_sr1( ) +{ + update_sr2( ); + + /* update S2RQ */ + if ( m_sr2 & 0x7f ) + m_sr1 |= S2RQ; + else + m_sr1 &= ~S2RQ; + + /* update TRDA (always prioritized by CTS) */ + if ( TRESET || ( m_sr1 & CTS ) ) + m_sr1 &= ~TDRA; + else + { + m_sr1 |= TDRA; + if ( m_tfifo[ 0 ] & 0x100 ) + m_sr1 &= ~TDRA; + else if ( TWOBYTES && (m_tfifo[ 1 ] & 0x100) ) + m_sr1 &= ~TDRA; + } + + /* update RDA */ + if ( m_sr2 & RDA2 ) + m_sr1 |= RDA; + else + m_sr1 &= ~RDA; + + /* update IRQ */ + m_sr1 &= ~IRQ; + if ( RIE && (m_sr1 & (TU | TDRA) ) ) + m_sr1 |= IRQ; + if ( TIE ) + { + if ( m_sr1 & (S2RQ | RDA | CTS) ) + m_sr1 |= IRQ; + if ( m_sr2 & (ERR | FV | DCD | OVRN | RABT | RIDLE | AP) ) + m_sr1 |= IRQ; + } + + m_out_irq_cb((m_sr1 & IRQ) ? ASSERT_LINE : CLEAR_LINE); +} + + + +READ8_MEMBER( mc6854_device::read ) +{ + switch ( offset ) + { + case 0: /* status register 1 */ + update_sr1( ); + LOG(( "%f %s mc6854_r: get SR1=$%02X (rda=%i,s2rq=%i,fd=%i,cts=%i,tu=%i,tdra=%i,irq=%i)\n", + space.machine().time().as_double(), machine().describe_context(), m_sr1, + ( m_sr1 & RDA) ? 1 : 0, ( m_sr1 & S2RQ) ? 1 : 0, + ( m_sr1 & FD ) ? 1 : 0, ( m_sr1 & CTS ) ? 1 : 0, + ( m_sr1 & TU ) ? 1 : 0, ( m_sr1 & TDRA) ? 1 : 0, + ( m_sr1 & IRQ) ? 1 : 0 )); + return m_sr1; + + case 1: /* status register 2 */ + update_sr2( ); + LOG(( "%f %s mc6854_r: get SR2=$%02X (ap=%i,fv=%i,ridle=%i,rabt=%i,err=%i,dcd=%i,ovrn=%i,rda2=%i)\n", + space.machine().time().as_double(), machine().describe_context(), m_sr2, + ( m_sr2 & AP ) ? 1 : 0, ( m_sr2 & FV ) ? 1 : 0, + ( m_sr2 & RIDLE) ? 1 : 0, ( m_sr2 & RABT) ? 1 : 0, + ( m_sr2 & ERR ) ? 1 : 0, ( m_sr2 & DCD ) ? 1 : 0, + ( m_sr2 & OVRN ) ? 1 : 0, ( m_sr2 & RDA2) ? 1 : 0 )); + return m_sr2; + + case 2: /* receiver data register */ + case 3: + { + UINT8 data = rfifo_pop( ); + LOG(( "%f %s mc6854_r: get data $%02X\n", + space.machine().time().as_double(), machine().describe_context(), data )); + return data; + } + + default: + logerror( "%s mc6854 invalid read offset %i\n", machine().describe_context(), offset ); + } + return 0; +} + + + +WRITE8_MEMBER( mc6854_device::write ) +{ + switch ( offset ) + { + case 0: /* control register 1 */ + m_cr1 = data; + LOG(( "%f %s mc6854_w: set CR1=$%02X (ac=%i,irq=%c%c,%sreset=%c%c)\n", + space.machine().time().as_double(), machine().describe_context(), m_cr1, + AC ? 1 : 0, + RIE ? 'r' : '-', TIE ? 't' : '-', + DISCONTINUE ? "discontinue," : "", + RRESET ? 'r' : '-', TRESET ? 't' : '-' + )); + if ( m_cr1 & 0xc ) + logerror( "%s mc6854 DMA not handled (CR1=$%02X)\n", + machine().describe_context(), m_cr1 ); + if ( DISCONTINUE ) + { + /* abort receive FIFO but keeps shift register & synchro */ + m_rstate = 0; + memset( m_rfifo, 0, sizeof( m_rfifo ) ); + } + if ( RRESET ) + { + /* abort FIFO & synchro */ + rfifo_clear( ); + m_sr1 &= ~FD; + m_sr2 &= ~(AP | FV | RIDLE | RABT | ERR | OVRN | DCD); + if ( m_dcd ) m_sr2 |= DCD; + } + if ( TRESET ) + { + tfifo_clear( ); + m_sr1 &= ~(TU | TDRA | CTS); + if ( m_cts ) m_sr1 |= CTS; + } + break; + + case 1: + if ( AC ) + { + /* control register 3 */ + m_cr3 = data; + LOG(( "%f %s mc6854_w: set CR3=$%02X (lcf=%i,aex=%i,idl=%i,fdse=%i,loop=%i,tst=%i,dtr=%i)\n", + space.machine().time().as_double(), machine().describe_context(), m_cr3, + LCF ? (CEX ? 16 : 8) : 0, AEX ? 1 : 0, + IDL0 ? 0 : 1, FDSE ? 1 : 0, LOOP ? 1 : 0, + TST ? 1 : 0, DTR ? 1 : 0 + )); + if ( LOOP ) + logerror( "%s mc6854 loop mode not handled (CR3=$%02X)\n", machine().describe_context(), m_cr3 ); + if ( TST ) + logerror( "%s mc6854 test mode not handled (CR3=$%02X)\n", machine().describe_context(), m_cr3 ); + + m_out_dtr_cb( DTR ? 1 : 0 ); + + } + else + { + /* control register 2 */ + m_cr2 = data; + LOG(( "%f %s mc6854_w: set CR2=$%02X (pse=%i,bytes=%i,fmidle=%i,%s,tlast=%i,clr=%c%c,rts=%i)\n", + space.machine().time().as_double(), machine().describe_context(), m_cr2, + PSE ? 1 : 0, TWOBYTES ? 2 : 1, FMIDLE ? 1 : 0, + FCTDRA ? "fc" : "tdra", TLAST ? 1 : 0, + data & 0x20 ? 'r' : '-', data & 0x40 ? 't' : '-', + RTS ? 1 : 0 )); + if ( PSE ) + logerror( "%s mc6854 status prioritization not handled (CR2=$%02X)\n", machine().describe_context(), m_cr2 ); + if ( TLAST ) + tfifo_terminate( ); + if ( data & 0x20 ) + { + /* clear receiver status */ + m_sr1 &= ~FD; + m_sr2 &= ~(AP | FV | RIDLE | RABT | ERR | OVRN | DCD); + if ( m_dcd ) + m_sr2 |= DCD; + } + if ( data & 0x40 ) + { + /* clear transmitter status */ + m_sr1 &= ~(TU | TDRA | CTS); + if ( m_cts ) + m_sr1 |= CTS; + } + + m_out_rts_cb( RTS ? 1 : 0 ); + } + break; + + case 2: /* transmitter data: continue data */ + LOG(( "%f %smc6854_w: push data=$%02X\n", space.machine().time().as_double(), machine().describe_context(), data )); + tfifo_push( data ); + break; + + case 3: + if ( AC ) + { + /* control register 4 */ + m_cr4 = data; + LOG(( "%f %s mc6854_w: set CR4=$%02X (interframe=%i,tlen=%i,rlen=%i,%s%s)\n", space.machine().time().as_double(), machine().describe_context(), m_cr4, + TWOINTER ? 2 : 1, + TWL, RWL, + ABT ? ( ABTEX ? "abort-ext," : "abort,") : "", + NRZ ? "nrz" : "nrzi" )); + if ( ABT ) + { + m_tstate = 0; + send_bits( 0xffff, ABTEX ? 16 : 8, 0 ); + m_flen = 0; + } + } + else + { + /* transmitter data: last data */ + LOG(( "%f %s mc6854_w: push last-data=$%02X\n", space.machine().time().as_double(), machine().describe_context(), data )); + tfifo_push( data ); + tfifo_terminate( ); + } + break; + + default: + logerror( "%s mc6854 invalid write offset %i (data=$%02X)\n", machine().describe_context(), offset, data ); + } +} + +WRITE_LINE_MEMBER( mc6854_device::rxc_w ) +{ + // TODO +} + +WRITE_LINE_MEMBER( mc6854_device::txc_w ) +{ + // TODO +} diff --git a/src/devices/machine/mc6854.h b/src/devices/machine/mc6854.h new file mode 100644 index 00000000000..2808255c0f6 --- /dev/null +++ b/src/devices/machine/mc6854.h @@ -0,0 +1,161 @@ +// license:BSD-3-Clause +// copyright-holders:Antoine Mine +/********************************************************************** + + Copyright (C) Antoine Mine' 2006 + + Motorola 6854 emulation (network interface). + +**********************************************************************/ + +#ifndef MC6854_H +#define MC6854_H + + +#define MAX_FRAME_LENGTH 65536 +/* arbitrary value, you may need to enlarge it if you get truncated frames */ + +#define MC6854_FIFO_SIZE 3 +/* hardcoded size of the 6854 FIFO (this is a hardware limit) */ + +typedef device_delegate mc6854_out_frame_delegate; +#define MC6854_OUT_FRAME_CB(name) void name(UINT8 * data, int length) + + +#define MCFG_MC6854_OUT_IRQ_CB(_devcb) \ + devcb = &mc6854_device::set_out_irq_callback(*device, DEVCB_##_devcb); + +#define MCFG_MC6854_OUT_TXD_CB(_devcb) \ + devcb = &mc6854_device::set_out_txd_callback(*device, DEVCB_##_devcb); + +#define MCFG_MC6854_OUT_FRAME_CB(_class, _method) \ + mc6854_device::set_out_frame_callback(*device, mc6854_out_frame_delegate(&_class::_method, #_class "::" #_method, downcast<_class *>(owner))); + +#define MCFG_MC6854_OUT_RTS_CB(_devcb) \ + devcb = &mc6854_device::set_out_rts_callback(*device, DEVCB_##_devcb); + +#define MCFG_MC6854_OUT_DTR_CB(_devcb) \ + devcb = &mc6854_device::set_out_dtr_callback(*device, DEVCB_##_devcb); + + +class mc6854_device : public device_t +{ +public: + mc6854_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + ~mc6854_device() {} + + template static devcb_base &set_out_irq_callback(device_t &device, _Object object) { return downcast(device).m_out_irq_cb.set_callback(object); } + template static devcb_base &set_out_txd_callback(device_t &device, _Object object) { return downcast(device).m_out_txd_cb.set_callback(object); } + static void set_out_frame_callback(device_t &device, mc6854_out_frame_delegate callback) { downcast(device).m_out_frame_cb = callback; } + template static devcb_base &set_out_rts_callback(device_t &device, _Object object) { return downcast(device).m_out_rts_cb.set_callback(object); } + template static devcb_base &set_out_dtr_callback(device_t &device, _Object object) { return downcast(device).m_out_dtr_cb.set_callback(object); } + + /* interface to CPU via address/data bus*/ + DECLARE_READ8_MEMBER( read ); + DECLARE_WRITE8_MEMBER( write ); + + /* low-level, bit-based interface */ + DECLARE_WRITE_LINE_MEMBER( set_rx ); + + /* high-level, frame-based interface */ + int send_frame( UINT8* data, int length ); /* ret -1 if busy */ + + /* control lines */ + DECLARE_WRITE_LINE_MEMBER( set_cts ); /* 1 = clear-to-send, 0 = busy */ + DECLARE_WRITE_LINE_MEMBER( set_dcd ); /* 1 = carrier, 0 = no carrier */ + + /* clock */ + DECLARE_WRITE_LINE_MEMBER( rxc_w ); + DECLARE_WRITE_LINE_MEMBER( txc_w ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + +private: + // internal state + devcb_write_line m_out_irq_cb; /* interrupt request */ + + /* low-level, bit-based interface */ + devcb_write_line m_out_txd_cb; /* transmit bit */ + + /* high-level, frame-based interface */ + mc6854_out_frame_delegate m_out_frame_cb; + + /* control lines */ + devcb_write_line m_out_rts_cb; /* 1 = transmitting, 0 = idle */ + devcb_write_line m_out_dtr_cb; /* 1 = data transmit ready, 0 = busy */ + + /* registers */ + UINT8 m_cr1, m_cr2, m_cr3, m_cr4; /* control registers */ + UINT8 m_sr1, m_sr2; /* status registers */ + + UINT8 m_cts, m_dcd; + + /* transmit state */ + UINT8 m_tstate; + UINT16 m_tfifo[MC6854_FIFO_SIZE]; /* X x 8-bit FIFO + full & last marker bits */ + UINT8 m_tones; /* counter for zero-insertion */ + emu_timer *m_ttimer; /* when to ask for more data */ + + /* receive state */ + UINT8 m_rstate; + UINT32 m_rreg; /* shift register */ + UINT8 m_rones; /* count '1 bits */ + UINT8 m_rsize; /* bits in the shift register */ + UINT16 m_rfifo[MC6854_FIFO_SIZE]; /* X x 8-bit FIFO + full & addr marker bits */ + + /* frame-based interface*/ + UINT8 m_frame[MAX_FRAME_LENGTH]; + UINT32 m_flen, m_fpos; + + + /* meaning of tstate / rtate: + 0 = idle / waiting for frame flag + 1 = flag sync + 2 = 8-bit address field(s) + 3-4 = 8-bit control field(s) + 5 = 8-bit logical control field(s) + 6 = variable-length data field(s) + */ + + void send_bits( UINT32 data, int len, int zi ); + void tfifo_push( UINT8 data ); + void tfifo_terminate( ); + TIMER_CALLBACK_MEMBER(tfifo_cb); + void tfifo_clear( ); + + void rfifo_push( UINT8 d ); + void rfifo_terminate( ); + UINT8 rfifo_pop( ); + void rfifo_clear( ); + + void update_sr2( ); + void update_sr1( ); +}; + +extern const device_type MC6854; + + +/* we provide two interfaces: + - a bit-based interface: out_tx, set_rx + - a frame-based interface: out_frame, send_frame + + The bit-based interface is low-level and slow. + Use it to simulate the actual bits sent into the wires, e.g., to connect + the emulator to another bit-based emulated network device, or an actual + device. + + The frame-based interface is higher-level and faster. + It passes bytes directly from one end to the other without bothering with + the actual bit-encoding, synchronization, and CRC. + Once completed, a frame is sent through out_frame. Aborted frames are not + transmitted at all. No start flag, stop flag, or crc bits are trasmitted. + send_frame makes a frame available to the CPU through the 6854 (it may + fail and return -1 if the 6854 is not ready to accept the frame; even + if the frame is accepted and 0 is returned, the CPU may abort it). Ony + full frames are accepted. +*/ + +#endif diff --git a/src/devices/machine/mc68681.c b/src/devices/machine/mc68681.c new file mode 100644 index 00000000000..8b40488de24 --- /dev/null +++ b/src/devices/machine/mc68681.c @@ -0,0 +1,1152 @@ +// license:BSD-3-Clause +// copyright-holders:Mariusz Wojcieszek, R. Belmont +/* + 68681 DUART + + Written by Mariusz Wojcieszek + Updated by Jonathan Gevaryahu AKA Lord Nightmare + Improved interrupt handling by R. Belmont + Rewrite and modernization in progress by R. Belmont +*/ + +#include "emu.h" +#include "mc68681.h" + +#define VERBOSE 0 +#define LOG(x) do { if (VERBOSE) logerror x; } while (0) + +static const char *const duart68681_reg_read_names[0x10] = +{ + "MRA", "SRA", "BRG Test", "RHRA", "IPCR", "ISR", "CTU", "CTL", "MRB", "SRB", "1X/16X Test", "RHRB", "IVR", "Input Ports", "Start Counter", "Stop Counter" +}; + +static const char *const duart68681_reg_write_names[0x10] = +{ + "MRA", "CSRA", "CRA", "THRA", "ACR", "IMR", "CRUR", "CTLR", "MRB", "CSRB", "CRB", "THRB", "IVR", "OPCR", "Set OP Bits", "Reset OP Bits" +}; + +static const int baud_rate_ACR_0[] = { 50, 110, 134, 200, 300, 600, 1200, 1050, 2400, 4800, 7200, 9600, 38400, 0, 0, 0 }; +static const int baud_rate_ACR_1[] = { 75, 110, 134, 150, 300, 600, 1200, 2000, 2400, 4800, 1800, 9600, 19200, 0, 0, 0 }; + +#define INT_INPUT_PORT_CHANGE 0x80 +#define INT_DELTA_BREAK_B 0x40 +#define INT_RXRDY_FFULLB 0x20 +#define INT_TXRDYB 0x10 +#define INT_COUNTER_READY 0x08 +#define INT_DELTA_BREAK_A 0x04 +#define INT_RXRDY_FFULLA 0x02 +#define INT_TXRDYA 0x01 + +#define STATUS_RECEIVED_BREAK 0x80 +#define STATUS_FRAMING_ERROR 0x40 +#define STATUS_PARITY_ERROR 0x20 +#define STATUS_OVERRUN_ERROR 0x10 +#define STATUS_TRANSMITTER_EMPTY 0x08 +#define STATUS_TRANSMITTER_READY 0x04 +#define STATUS_FIFO_FULL 0x02 +#define STATUS_RECEIVER_READY 0x01 + +#define MODE_RX_INT_SELECT_BIT 0x40 + +#define CHANA_TAG "cha" +#define CHANB_TAG "chb" + +// device type definition +const device_type MC68681 = &device_creator; +const device_type MC68681_CHANNEL = &device_creator; + +MACHINE_CONFIG_FRAGMENT( duart68681 ) + MCFG_DEVICE_ADD(CHANA_TAG, MC68681_CHANNEL, 0) + MCFG_DEVICE_ADD(CHANB_TAG, MC68681_CHANNEL, 0) +MACHINE_CONFIG_END + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +mc68681_device::mc68681_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, MC68681, "MC68681 DUART", tag, owner, clock, "mc68681", __FILE__), + m_chanA(*this, CHANA_TAG), + m_chanB(*this, CHANB_TAG), + write_irq(*this), + write_a_tx(*this), + write_b_tx(*this), + read_inport(*this), + write_outport(*this), + ip3clk(0), + ip4clk(0), + ip5clk(0), + ip6clk(0), + ACR(0), + m_read_vector(false), + IP_last_state(0) +{ +} + +//------------------------------------------------- +// static_set_clocks - configuration helper to set +// the external clocks +//------------------------------------------------- + +void mc68681_device::static_set_clocks(device_t &device, int clk3, int clk4, int clk5, int clk6) +{ + mc68681_device &duart = downcast(device); + duart.ip3clk = clk3; + duart.ip4clk = clk4; + duart.ip5clk = clk5; + duart.ip6clk = clk6; +} + +/*------------------------------------------------- + device start callback +-------------------------------------------------*/ + +void mc68681_device::device_start() +{ + write_irq.resolve_safe(); + write_a_tx.resolve_safe(); + write_b_tx.resolve_safe(); + read_inport.resolve(); + write_outport.resolve_safe(); + + duart_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(mc68681_device::duart_timer_callback),this), NULL); + + save_item(NAME(ACR)); + save_item(NAME(IMR)); + save_item(NAME(ISR)); + save_item(NAME(IVR)); + save_item(NAME(OPCR)); + save_item(NAME(CTR)); + save_item(NAME(IP_last_state)); + save_item(NAME(half_period)); +} + +/*------------------------------------------------- + device reset callback +-------------------------------------------------*/ + +void mc68681_device::device_reset() +{ + ACR = 0; /* Interrupt Vector Register */ + IVR = 0x0f; /* Interrupt Vector Register */ + IMR = 0; /* Interrupt Mask Register */ + ISR = 0; /* Interrupt Status Register */ + OPCR = 0; /* Output Port Conf. Register */ + OPR = 0; /* Output Port Register */ + CTR.d = 0; /* Counter/Timer Preset Value */ + m_read_vector = false; + // "reset clears internal registers (SRA, SRB, IMR, ISR, OPR, OPCR) puts OP0-7 in the high state, stops the counter/timer, and puts channels a/b in the inactive state" + IPCR = 0; + + write_outport(OPR ^ 0xff); +} + +machine_config_constructor mc68681_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( duart68681 ); +} + +void mc68681_device::update_interrupts() +{ + /* update SR state and update interrupt ISR state for the following bits: + SRn: bits 7-4: handled elsewhere. + SRn: bit 3 (TxEMTn) (we can assume since we're not actually emulating the delay/timing of sending bits, that as long as TxRDYn is set, TxEMTn is also set since the transmit byte has 'already happened', therefore TxEMTn is always 1 assuming tx is enabled on channel n and the MSR2n mode is 0 or 2; in mode 1 it is explicitly zeroed, and mode 3 is undefined) + SRn: bit 2 (TxRDYn) (we COULD assume since we're not emulating delay and timing output, that as long as tx is enabled on channel n, TxRDY is 1 for channel n and the MSR2n mode is 0 or 2; in mode 1 it is explicitly zeroed, and mode 3 is undefined; however, tx_ready is already nicely handled for us elsewhere, so we can use that instead for now, though we may need to retool that code as well) + SRn: bit 1 (FFULLn) (this bit we actually emulate; if the receive fifo for channel n is full, this bit is 1, otherwise it is 0. the receive fifo should be three words long.) + SRn: bit 0 (RxRDYn) (this bit we also emulate; the bit is always asserted if the receive fifo is not empty) + ISR: bit 7: Input Port change; this should be handled elsewhere, on the input port handler + ISR: bit 6: Delta Break B; this should be handled elsewhere, on the data receive handler + ISR: bit 5: RxRDYB/FFULLB: this is handled here; depending on whether MSR1B bit 6 is 0 or 1, this bit holds the state of SRB bit 0 or bit 1 respectively + ISR: bit 4: TxRDYB: this is handled here; it mirrors SRB bit 2 + ISR: bit 3: Counter ready; this should be handled by the timer generator + ISR: bit 2: Delta Break A; this should be handled elsewhere, on the data receive handler + ISR: bit 1: RxRDYA/FFULLA: this is handled here; depending on whether MSR1A bit 6 is 0 or 1, this bit holds the state of SRA bit 0 or bit 1 respectively + ISR: bit 0: TxRDYA: this is handled here; it mirrors SRA bit 2 + */ + if ( (ISR & IMR) != 0 ) + { + LOG(( "68681: Interrupt line active (IMR & ISR = %02X)\n", (ISR & IMR) )); + write_irq(ASSERT_LINE); + } + else + { + LOG(( "68681: Interrupt line not active (IMR & ISR = %02X)\n", ISR & IMR)); + write_irq(CLEAR_LINE); + m_read_vector = false; // clear IACK too + } +} + +double mc68681_device::duart68681_get_ct_rate() +{ + double rate = 0.0f; + + if (ACR & 0x40) + { + // Timer mode + switch ((ACR >> 4) & 3) + { + case 0: // IP2 + case 1: // IP2 / 16 + //logerror( "68681 (%s): Unhandled timer/counter mode %d\n", duart68681->tag(), (duart68681->ACR >> 4) & 3); + rate = clock(); + break; + case 2: // X1/CLK + rate = clock(); + break; + case 3: // X1/CLK / 16 + rate = clock() / 16; + break; + } + } + else + { + // Counter mode + switch ((ACR >> 4) & 3) + { + case 0: // IP2 + case 1: // TxCA + case 2: // TxCB + //logerror( "68681 (%s): Unhandled timer/counter mode %d\n", device->tag(), (duart68681->ACR >> 4) & 3); + rate = clock(); + break; + case 3: // X1/CLK / 16 + rate = clock() / 16; + break; + } + } + + return rate; +} + +UINT16 mc68681_device::duart68681_get_ct_count() +{ + double clock = duart68681_get_ct_rate(); + return (duart_timer->remaining() * clock).as_double(); +} + +void mc68681_device::duart68681_start_ct(int count) +{ + double clock = duart68681_get_ct_rate(); + duart_timer->adjust(attotime::from_hz(clock) * count, 0); +} + +TIMER_CALLBACK_MEMBER( mc68681_device::duart_timer_callback ) +{ + if (ACR & 0x40) + { + // Timer mode + half_period ^= 1; + + // timer output to bit 3? + if ((OPCR & 0xc) == 0x4) + { + OPR ^= 0x8; + write_outport(OPR ^ 0xff); + } + + // timer driving any serial channels? + if (BIT(ACR, 7) == 1) + { + UINT8 csr = m_chanA->get_chan_CSR(); + + if ((csr & 0xf0) == 0xd0) // tx is timer driven + { + m_chanA->tx_clock_w(half_period); + } + if ((csr & 0x0f) == 0x0d) // rx is timer driven + { + m_chanA->rx_clock_w(half_period); + } + + csr = m_chanB->get_chan_CSR(); + if ((csr & 0xf0) == 0xd0) // tx is timer driven + { + m_chanB->tx_clock_w(half_period); + } + if ((csr & 0x0f) == 0x0d) // rx is timer driven + { + m_chanB->rx_clock_w(half_period); + } + } + + if (!half_period) + { + ISR |= INT_COUNTER_READY; + update_interrupts(); + } + + int count = MAX(CTR.w.l, 1); + duart68681_start_ct(count); + } + else + { + // Counter mode + ISR |= INT_COUNTER_READY; + update_interrupts(); + duart68681_start_ct(0xffff); + } + +} + +READ8_MEMBER( mc68681_device::read ) +{ + UINT8 r = 0xff; + + offset &= 0xf; + + LOG(( "Reading 68681 (%s) reg %x (%s) ", tag(), offset, duart68681_reg_read_names[offset] )); + + switch (offset) + { + case 0x00: /* MR1A/MR2A */ + case 0x01: /* SRA */ + case 0x03: /* Rx Holding Register A */ + r = m_chanA->read_chan_reg(offset & 3); + break; + + case 0x04: /* IPCR */ + { + r = IPCR; + + // reading this clears all the input change bits + IPCR &= 0x0f; + ISR &= ~INT_INPUT_PORT_CHANGE; + update_interrupts(); + } + break; + + case 0x05: /* ISR */ + r = ISR; + break; + + case 0x06: /* CUR */ + r = duart68681_get_ct_count() >> 8; + break; + + case 0x07: /* CLR */ + r = duart68681_get_ct_count() & 0xff; + break; + + case 0x08: /* MR1B/MR2B */ + case 0x09: /* SRB */ + case 0x0b: /* RHRB */ + r = m_chanB->read_chan_reg(offset & 3); + break; + + case 0x0a: /* 1X/16X Test */ + r = 0x61; // the old 68681 returned this and it makes Apollo happy + break; + + case 0x0d: /* IP */ + if (!read_inport.isnull()) + { + r = read_inport(); // TODO: go away + } + else + { + r = IP_last_state; + } + + r |= 0x80; // bit 7 is always set + + // bit 6 is /IACK (note the active-low) + if (m_read_vector) + { + r &= ~0x40; + } + else + { + r |= 0x40; + } + break; + + case 0x0e: /* Start counter command */ + { + if (ACR & 0x40) + { + // Reset the timer + half_period = 0; + } + + int count = MAX(CTR.w.l, 1); + duart68681_start_ct(count); + break; + } + + case 0x0f: /* Stop counter command */ + ISR &= ~INT_COUNTER_READY; + + // Stop the counter only + if (!(ACR & 0x40)) + duart_timer->adjust(attotime::never); + + update_interrupts(); + break; + + default: + LOG(( "Reading unhandled 68681 reg %x\n", offset )); + break; + } + LOG(("returned %02x\n", r)); + + return r; +} + +WRITE8_MEMBER( mc68681_device::write ) +{ + offset &= 0x0f; + LOG(( "Writing 68681 (%s) reg %x (%s) with %04x\n", tag(), offset, duart68681_reg_write_names[offset], data )); + switch(offset) + { + case 0x00: /* MRA */ + case 0x01: /* CSRA */ + case 0x02: /* CRA */ + case 0x03: /* THRA */ + m_chanA->write_chan_reg(offset&3, data); + break; + + case 0x04: /* ACR */ + { + UINT8 old_acr = ACR; + ACR = data; + + // bits 6-4: Counter/Timer Mode And Clock Source Select + // bits 3-0: IP3-0 Change-Of-State Interrupt Enable + if ((old_acr ^ data) & 0x40) + { + if (data & 0x40) + { + // Entering timer mode + UINT16 count = MAX(CTR.w.l, 1); + half_period = 0; + + duart68681_start_ct(count); + } + else + { + // Leaving timer mode (TODO: is this correct?) + duart_timer->adjust(attotime::never); + } + } + + // check for pending input port delta interrupts + if ((((IPCR>>4) & data) & 0x0f) != 0) + { + ISR |= INT_INPUT_PORT_CHANGE; + } + + m_chanA->ACR_updated(); + m_chanB->ACR_updated(); + m_chanA->update_interrupts(); + m_chanB->update_interrupts(); + update_interrupts(); + break; + } + case 0x05: /* IMR */ + IMR = data; + update_interrupts(); + break; + + case 0x06: /* CTUR */ + CTR.b.h = data; + break; + + case 0x07: /* CTLR */ + CTR.b.l = data; + break; + + case 0x08: /* MRB */ + case 0x09: /* CSRB */ + case 0x0a: /* CRB */ + case 0x0b: /* THRB */ + m_chanB->write_chan_reg(offset&3, data); + break; + + case 0x0c: /* IVR */ + IVR = data; + break; + + case 0x0d: /* OPCR */ + if ((data != 0x00) && ((data & 0xc) != 0x4)) + logerror( "68681 (%s): Unhandled OPCR value: %02x\n", tag(), data); + OPCR = data; + break; + + case 0x0e: /* Set Output Port Bits */ + OPR |= data; + write_outport(OPR ^ 0xff); + break; + + case 0x0f: /* Reset Output Port Bits */ + OPR &= ~data; + write_outport(OPR ^ 0xff); + break; + } +} + +WRITE_LINE_MEMBER( mc68681_device::ip0_w ) +{ + UINT8 newIP = (IP_last_state & ~0x01) | ((state == ASSERT_LINE) ? 1 : 0); + + if (newIP != IP_last_state) + { + IPCR &= ~0x0f; + IPCR |= (newIP & 0x0f); + IPCR |= 0x10; + + if (ACR & 1) + { + ISR |= INT_INPUT_PORT_CHANGE; + update_interrupts(); + } + } + + IP_last_state = newIP; +} + +WRITE_LINE_MEMBER( mc68681_device::ip1_w ) +{ + UINT8 newIP = (IP_last_state & ~0x02) | ((state == ASSERT_LINE) ? 2 : 0); + + if (newIP != IP_last_state) + { + IPCR &= ~0x0f; + IPCR |= (newIP & 0x0f); + IPCR |= 0x20; + + if (ACR & 2) + { + ISR |= INT_INPUT_PORT_CHANGE; + update_interrupts(); + } + } + + IP_last_state = newIP; +} + +WRITE_LINE_MEMBER( mc68681_device::ip2_w ) +{ + UINT8 newIP = (IP_last_state & ~0x04) | ((state == ASSERT_LINE) ? 4 : 0); + + if (newIP != IP_last_state) + { + IPCR &= ~0x0f; + IPCR |= (newIP & 0x0f); + IPCR |= 0x40; + + if (ACR & 4) + { + ISR |= INT_INPUT_PORT_CHANGE; + update_interrupts(); + } + } + + IP_last_state = newIP; +} + +WRITE_LINE_MEMBER( mc68681_device::ip3_w ) +{ + UINT8 newIP = (IP_last_state & ~0x08) | ((state == ASSERT_LINE) ? 8 : 0); + + if (newIP != IP_last_state) + { + IPCR &= ~0x0f; + IPCR |= (newIP & 0x0f); + IPCR |= 0x80; + + if (ACR & 8) + { + ISR |= INT_INPUT_PORT_CHANGE; + update_interrupts(); + } + } + + IP_last_state = newIP; +} + +WRITE_LINE_MEMBER( mc68681_device::ip4_w ) +{ + UINT8 newIP = (IP_last_state & ~0x10) | ((state == ASSERT_LINE) ? 0x10 : 0); +// TODO: special mode for ip4 (Ch. A Rx clock) + IP_last_state = newIP; +} + +WRITE_LINE_MEMBER( mc68681_device::ip5_w ) +{ + UINT8 newIP = (IP_last_state & ~0x20) | ((state == ASSERT_LINE) ? 0x20 : 0); +// TODO: special mode for ip5 (Ch. B Tx clock) + IP_last_state = newIP; +} + +mc68681_channel *mc68681_device::get_channel(int chan) +{ + if (chan == 0) + { + return m_chanA; + } + + return m_chanB; +} + +int mc68681_device::calc_baud(int ch, UINT8 data) +{ + int baud_rate = 0; + + if ( BIT(ACR, 7) == 0 ) + { + baud_rate = baud_rate_ACR_0[data & 0x0f]; + + if (ch == 0) + { + if ((data & 0xf) == 0xe) + { + baud_rate = ip3clk/16; + } + else if ((data & 0xf) == 0xf) + { + baud_rate = ip3clk; + } + } + else if (ch == 1) + { + if ((data & 0xf) == 0xe) + { + baud_rate = ip5clk/16; + } + else if ((data & 0xf) == 0xf) + { + baud_rate = ip5clk; + } + } + } + else + { + baud_rate = baud_rate_ACR_1[data & 0x0f]; + } + + if ((baud_rate == 0) && ((data & 0xf) != 0xd)) + { + LOG(( "Unsupported transmitter clock: channel %d, clock select = %02x\n", ch, data )); + } + + return baud_rate; +} + +void mc68681_device::clear_ISR_bits(int mask) +{ + ISR &= ~mask; +} + +void mc68681_device::set_ISR_bits(int mask) +{ + ISR |= mask; +} + +// DUART channel class stuff + +mc68681_channel::mc68681_channel(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, MC68681_CHANNEL, "MC68681 DUART CHANNEL", tag, owner, clock, "mc68681_channel", __FILE__), + device_serial_interface(mconfig, *this), + MR1(0), + MR2(0), + SR(0), + rx_enabled(0), + rx_fifo_num(0), + tx_enabled(0) +{ +} + +void mc68681_channel::device_start() +{ + m_uart = downcast(owner()); + m_ch = m_uart->get_ch(this); // get our channel number + + save_item(NAME(CR)); + save_item(NAME(CSR)); + save_item(NAME(MR1)); + save_item(NAME(MR2)); + save_item(NAME(MR_ptr)); + save_item(NAME(SR)); + save_item(NAME(rx_baud_rate)); + save_item(NAME(tx_baud_rate)); + save_item(NAME(rx_enabled)); + save_item(NAME(rx_fifo)); + save_item(NAME(rx_fifo_read_ptr)); + save_item(NAME(rx_fifo_write_ptr)); + save_item(NAME(rx_fifo_num)); + save_item(NAME(tx_enabled)); + save_item(NAME(tx_data)); + save_item(NAME(tx_ready)); +} + +void mc68681_channel::device_reset() +{ + write_CR(0x10); // reset MR + write_CR(0x20); // reset Rx + write_CR(0x30); // reset Tx + write_CR(0x40); // reset errors + + set_data_frame(1, 8, PARITY_NONE, STOP_BITS_1); + + tx_baud_rate = rx_baud_rate = 0; + CSR = 0; +} + +void mc68681_channel::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + device_serial_interface::device_timer(timer, id, param, ptr); +} + +// serial device virtual overrides +void mc68681_channel::rcv_complete() +{ + receive_register_extract(); + +// printf("%s ch %d rcv complete\n", tag(), m_ch); + + if ( rx_enabled ) + { + if ( rx_fifo_num >= MC68681_RX_FIFO_SIZE ) + { + logerror("68681: FIFO overflow\n"); + SR |= STATUS_OVERRUN_ERROR; + return; + } + rx_fifo[rx_fifo_write_ptr++] = get_received_char(); + if ( rx_fifo_write_ptr == MC68681_RX_FIFO_SIZE ) + { + rx_fifo_write_ptr = 0; + } + rx_fifo_num++; + update_interrupts(); + } +} + +void mc68681_channel::tra_complete() +{ +// printf("%s ch %d Tx complete\n", tag(), m_ch); + tx_ready = 1; + SR |= STATUS_TRANSMITTER_READY; + + if (m_ch == 0) + m_uart->clear_ISR_bits(INT_TXRDYA); + else + m_uart->clear_ISR_bits(INT_TXRDYB); + + // if local loopback is on, write the transmitted data as if a byte had been received + if ((MR2 & 0xC0) == 0x80) + { + if (rx_fifo_num >= MC68681_RX_FIFO_SIZE) + { + LOG(( "68681: FIFO overflow\n" )); + SR |= STATUS_OVERRUN_ERROR; + } + else + { + rx_fifo[rx_fifo_write_ptr++]= tx_data; + if (rx_fifo_write_ptr == MC68681_RX_FIFO_SIZE) + { + rx_fifo_write_ptr = 0; + } + rx_fifo_num++; + } + } + + update_interrupts(); +} + +void mc68681_channel::tra_callback() +{ + // don't actually send in loopback mode + if ((MR2&0xC0) != 0x80) + { + int bit = transmit_register_get_data_bit(); +// printf("%s ch %d transmit %d\n", tag(), m_ch, bit); + if (m_ch == 0) + { + m_uart->write_a_tx(bit); + } + else + { + m_uart->write_b_tx(bit); + } + } + else // must call this to advance the transmitter + { + transmit_register_get_data_bit(); + } +} + +void mc68681_channel::update_interrupts() +{ + if (rx_enabled) + { + if (rx_fifo_num > 0) + { + SR |= STATUS_RECEIVER_READY; + } + else + { + SR &= ~STATUS_RECEIVER_READY; + } + if ( rx_fifo_num == MC68681_RX_FIFO_SIZE ) + { + SR |= STATUS_FIFO_FULL; + } + else + { + SR &= ~STATUS_FIFO_FULL; + } + } + + // Handle the TxEMT and TxRDY bits based on mode + switch(MR2&0xC0) // what mode are we in? + { + case 0x00: // normal mode + if ( tx_enabled ) + { + SR |= STATUS_TRANSMITTER_EMPTY; + } + else + { + SR &= ~STATUS_TRANSMITTER_EMPTY; + } + break; + case 0x40: // automatic echo mode + SR &= ~STATUS_TRANSMITTER_EMPTY; + SR &= ~STATUS_TRANSMITTER_READY; + break; + case 0x80: // local loopback mode + if ( tx_enabled ) + { + SR |= STATUS_TRANSMITTER_EMPTY; + } + else + { + SR &= ~STATUS_TRANSMITTER_EMPTY; + } + break; + case 0xC0: // remote loopback mode + // write me, what the txrdy/txemt regs do for remote loopback mode is undocumented afaik, for now just clear both + SR &= ~STATUS_TRANSMITTER_EMPTY; + SR &= ~STATUS_TRANSMITTER_READY; + break; + } + // now handle the ISR bits + if ( SR & STATUS_TRANSMITTER_READY ) + { + if (m_ch == 0) + m_uart->set_ISR_bits(INT_TXRDYA); + else + m_uart->set_ISR_bits(INT_TXRDYB); + } + else + { + if (m_ch == 0) + m_uart->clear_ISR_bits(INT_TXRDYA); + else + m_uart->clear_ISR_bits(INT_TXRDYB); + } + //logerror("DEBUG: 68681 int check: before receiver test, SR%c is %02X, ISR is %02X\n", (ch+0x41), duart68681->channel[ch].SR, duart68681->ISR); + if ( MR1 & MODE_RX_INT_SELECT_BIT ) + { + if ( SR & STATUS_FIFO_FULL ) + { + m_uart->set_ISR_bits((m_ch == 0) ? INT_RXRDY_FFULLA : INT_RXRDY_FFULLB); + } + else + { + m_uart->clear_ISR_bits((m_ch == 0) ? INT_RXRDY_FFULLA : INT_RXRDY_FFULLB); + } + } + else + { + if ( SR & STATUS_RECEIVER_READY ) + { + m_uart->set_ISR_bits((m_ch == 0) ? INT_RXRDY_FFULLA : INT_RXRDY_FFULLB); + } + else + { + m_uart->clear_ISR_bits((m_ch == 0) ? INT_RXRDY_FFULLA : INT_RXRDY_FFULLB); + } + } + + m_uart->update_interrupts(); + + //logerror("DEBUG: 68681 int check: after receiver test, SR%c is %02X, ISR is %02X\n", (ch+0x41), duart68681->channel[ch].SR, duart68681->ISR); +} + +UINT8 mc68681_channel::read_rx_fifo() +{ + UINT8 rv = 0; + +// printf("read_rx_fifo: rx_fifo_num %d\n", rx_fifo_num); + + if ( rx_fifo_num == 0 ) + { + LOG(( "68681 channel: rx fifo underflow\n" )); + update_interrupts(); + return 0; + } + + rv = rx_fifo[rx_fifo_read_ptr++]; + if ( rx_fifo_read_ptr == MC68681_RX_FIFO_SIZE ) + { + rx_fifo_read_ptr = 0; + } + + rx_fifo_num--; + update_interrupts(); + +// printf("Rx read %02x\n", rv); + + return rv; +} + +UINT8 mc68681_channel::read_chan_reg(int reg) +{ + UINT8 rv = 0xff; + + switch (reg) + { + case 0: // MR1/MR2 + if ( MR_ptr == 0 ) + { + rv = MR1; + MR_ptr = 1; + } + else + { + rv = MR2; + } + break; + + case 1: // SRA + rv = SR; + break; + + case 2: // CSRA: reading this is prohibited + break; + + case 3: // Rx holding register A + rv = read_rx_fifo(); + break; + } + + return rv; +} + +void mc68681_channel::write_chan_reg(int reg, UINT8 data) +{ + switch (reg) + { + case 0x00: /* MRA */ + write_MR(data); + break; + + case 0x01: /* CSR */ + CSR = data; + tx_baud_rate = m_uart->calc_baud(m_ch, data & 0xf); + rx_baud_rate = m_uart->calc_baud(m_ch, (data>>4) & 0xf); +// printf("%s ch %d CSR %02x Tx baud %d Rx baud %d\n", tag(), m_ch, data, tx_baud_rate, rx_baud_rate); + set_rcv_rate(rx_baud_rate); + set_tra_rate(tx_baud_rate); + break; + + case 0x02: /* CR */ + write_CR(data); + break; + + case 0x03: /* THR */ + write_TX(data); + break; + } +} + +void mc68681_channel::write_MR(UINT8 data) +{ + if ( MR_ptr == 0 ) + { + MR1 = data; + MR_ptr = 1; + } + else + { + MR2 = data; + } + recalc_framing(); + update_interrupts(); +} + +void mc68681_channel::recalc_framing() +{ + parity_t parity = PARITY_NONE; + switch ((MR1>>3) & 3) + { + case 0: // with parity + if (MR1 & 4) + { + parity = PARITY_ODD; + } + else + { + parity = PARITY_EVEN; + } + break; + + case 1: // force parity + if (MR1 & 4) + { + parity = PARITY_MARK; + } + else + { + parity = PARITY_SPACE; + } + break; + + case 2: // no parity + parity = PARITY_NONE; + break; + + case 3: // multidrop mode + // fatalerror("68681: multidrop parity not supported\n"); + // Apollo DEX CPU will test this; omit to abort the emulation + logerror("68681: multidrop parity not supported\n"); + break; + } + + stop_bits_t stopbits = STOP_BITS_0; + switch ((MR2 >> 2) & 3) + { + case 0: + case 1: + stopbits = STOP_BITS_1; + break; + + case 2: // "1.5 async, 2 sync" + stopbits = STOP_BITS_1_5; + break; + + case 3: + stopbits = STOP_BITS_2; + break; + } + +// printf("%s ch %d MR1 %02x MR2 %02x => %d bits / char, %d stop bits, parity %d\n", tag(), m_ch, MR1, MR2, (MR1 & 3)+5, stopbits, parity); + + set_data_frame(1, (MR1 & 3)+5, parity, stopbits); +} + +void mc68681_channel::write_CR(UINT8 data) +{ + CR = data; + + switch( (data >> 4) & 0x07 ) + { + case 0: /* No command */ + break; + case 1: /* Reset MR pointer. Causes the channel MR pointer to point to MR1 */ + MR_ptr = 0; + break; + case 2: /* Reset channel receiver (disable receiver and flush fifo) */ + rx_enabled = 0; + SR &= ~STATUS_RECEIVER_READY; + SR &= ~STATUS_OVERRUN_ERROR; // is this correct? + rx_fifo_read_ptr = 0; + rx_fifo_write_ptr = 0; + rx_fifo_num = 0; + receive_register_reset(); + break; + case 3: /* Reset channel transmitter */ + tx_enabled = 0; + SR &= ~STATUS_TRANSMITTER_READY; + if (m_ch == 0) + m_uart->clear_ISR_bits(INT_TXRDYA); + else + m_uart->clear_ISR_bits(INT_TXRDYB); + transmit_register_reset(); + break; + case 4: /* Reset Error Status */ + SR &= ~(STATUS_RECEIVED_BREAK | STATUS_FRAMING_ERROR | STATUS_PARITY_ERROR | STATUS_OVERRUN_ERROR); + break; + case 5: /* Reset Channel break change interrupt */ + if ( m_ch == 0 ) + { + m_uart->clear_ISR_bits(INT_DELTA_BREAK_A); + } + else + { + m_uart->clear_ISR_bits(INT_DELTA_BREAK_B); + } + break; + /* TODO: case 6 and case 7 are start break and stop break respectively, which start or stop holding the TxDA or TxDB line low (space) after whatever data is in the buffer finishes transmitting (following the stop bit?), or after two bit-times if no data is being transmitted */ + default: + LOG(( "68681: Unhandled command (%x) in CR%d\n", (data >> 4) & 0x07, m_ch )); + break; + } + + if (BIT(data, 0)) { + rx_enabled = 1; + } + if (BIT(data, 1)) { + rx_enabled = 0; + SR &= ~STATUS_RECEIVER_READY; + } + + if (BIT(data, 2)) { + tx_enabled = 1; + tx_ready = 1; + SR |= STATUS_TRANSMITTER_READY; + if (m_ch == 0) + m_uart->set_ISR_bits(INT_TXRDYA); + else + m_uart->set_ISR_bits(INT_TXRDYB); + } + if (BIT(data, 3)) { + tx_enabled = 0; + tx_ready = 0; + SR &= ~STATUS_TRANSMITTER_READY; + if (m_ch == 0) + m_uart->clear_ISR_bits(INT_TXRDYA); + else + m_uart->clear_ISR_bits(INT_TXRDYB); + } + + update_interrupts(); +} + +void mc68681_channel::write_TX(UINT8 data) +{ + tx_data = data; + +/* if (!tx_ready) + { + printf("Write %02x to TX when TX not ready!\n", data); + }*/ + +// printf("%s ch %d Tx %02x\n", tag(), m_ch, data); + + tx_ready = 0; + SR &= ~STATUS_TRANSMITTER_READY; + + if (m_ch == 0) + m_uart->clear_ISR_bits(INT_TXRDYA); + else + m_uart->clear_ISR_bits(INT_TXRDYB); + + // send tx_data + transmit_register_setup(tx_data); + + update_interrupts(); +} + +void mc68681_channel::ACR_updated() +{ + write_chan_reg(1, CSR); +} + +UINT8 mc68681_channel::get_chan_CSR() +{ + return CSR; +} diff --git a/src/devices/machine/mc68681.h b/src/devices/machine/mc68681.h new file mode 100644 index 00000000000..3e4d0b9f256 --- /dev/null +++ b/src/devices/machine/mc68681.h @@ -0,0 +1,180 @@ +// license:BSD-3-Clause +// copyright-holders:Mariusz Wojcieszek, R. Belmont +#ifndef _MC68681_H +#define _MC68681_H + + +#define MCFG_MC68681_ADD(_tag, _clock) \ + MCFG_DEVICE_ADD(_tag, MC68681, _clock) + +#define MCFG_MC68681_REPLACE(_tag, _clock) \ + MCFG_DEVICE_REPLACE(_tag, MC68681, _clock) + +#define MCFG_MC68681_IRQ_CALLBACK(_cb) \ + devcb = &mc68681_device::set_irq_cb(*device, DEVCB_##_cb); + +#define MCFG_MC68681_A_TX_CALLBACK(_cb) \ + devcb = &mc68681_device::set_a_tx_cb(*device, DEVCB_##_cb); + +#define MCFG_MC68681_B_TX_CALLBACK(_cb) \ + devcb = &mc68681_device::set_b_tx_cb(*device, DEVCB_##_cb); + +// deprecated: use ipX_w() instead +#define MCFG_MC68681_INPORT_CALLBACK(_cb) \ + devcb = &mc68681_device::set_inport_cb(*device, DEVCB_##_cb); + +#define MCFG_MC68681_OUTPORT_CALLBACK(_cb) \ + devcb = &mc68681_device::set_outport_cb(*device, DEVCB_##_cb); + +#define MCFG_MC68681_SET_EXTERNAL_CLOCKS(_a, _b, _c, _d) \ + mc68681_device::static_set_clocks(*device, _a, _b, _c, _d); + +#define MC68681_RX_FIFO_SIZE 3 + +// forward declaration +class mc68681_device; + +// mc68681_channel class +class mc68681_channel : public device_t, public device_serial_interface +{ +public: + mc68681_channel(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + // device_serial overrides + virtual void rcv_complete(); // Rx completed receiving byte + virtual void tra_complete(); // Tx completed sending byte + virtual void tra_callback(); // Tx send bit + + UINT8 read_chan_reg(int reg); + void write_chan_reg(int reg, UINT8 data); + void update_interrupts(); + + UINT8 read_rx_fifo(); + + void ACR_updated(); + + UINT8 get_chan_CSR(); + +private: + /* Registers */ + UINT8 CR; /* Command register */ + UINT8 CSR; /* Clock select register */ + UINT8 MR1; /* Mode register 1 */ + UINT8 MR2; /* Mode register 2 */ + UINT8 MR_ptr; /* Mode register pointer */ + UINT8 SR; /* Status register */ + + /* State */ + int tx_baud_rate, rx_baud_rate; + + /* Receiver */ + UINT8 rx_enabled; + UINT8 rx_fifo[MC68681_RX_FIFO_SIZE]; + int rx_fifo_read_ptr; + int rx_fifo_write_ptr; + int rx_fifo_num; + + int m_ch; + + /* Transmitter */ + UINT8 tx_enabled; + UINT8 tx_data; + UINT8 tx_ready; + + mc68681_device *m_uart; + + void write_MR(UINT8 data); + void write_CR(UINT8 data); + void write_TX(UINT8 data); + void recalc_framing(); +}; + +class mc68681_device : public device_t +{ + friend class mc68681_channel; + +public: + mc68681_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + required_device m_chanA; + required_device m_chanB; + + // inline configuration helpers + static void static_set_clocks(device_t &device, int clk3, int clk4, int clk5, int clk6); + + // API + DECLARE_READ8_MEMBER(read); + DECLARE_WRITE8_MEMBER(write); + UINT8 get_irq_vector() { m_read_vector = true; return IVR; } + + DECLARE_WRITE_LINE_MEMBER( rx_a_w ) { m_chanA->device_serial_interface::rx_w((UINT8)state); } + DECLARE_WRITE_LINE_MEMBER( rx_b_w ) { m_chanB->device_serial_interface::rx_w((UINT8)state); } + + template static devcb_base &set_irq_cb(device_t &device, _Object object) { return downcast(device).write_irq.set_callback(object); } + template static devcb_base &set_a_tx_cb(device_t &device, _Object object) { return downcast(device).write_a_tx.set_callback(object); } + template static devcb_base &set_b_tx_cb(device_t &device, _Object object) { return downcast(device).write_b_tx.set_callback(object); } + template static devcb_base &set_inport_cb(device_t &device, _Object object) { return downcast(device).read_inport.set_callback(object); } + template static devcb_base &set_outport_cb(device_t &device, _Object object) { return downcast(device).write_outport.set_callback(object); } + + devcb_write_line write_irq, write_a_tx, write_b_tx; + devcb_read8 read_inport; + devcb_write8 write_outport; + INT32 ip3clk, ip4clk, ip5clk, ip6clk; + + // new-style push handlers for input port bits + DECLARE_WRITE_LINE_MEMBER( ip0_w ); + DECLARE_WRITE_LINE_MEMBER( ip1_w ); + DECLARE_WRITE_LINE_MEMBER( ip2_w ); + DECLARE_WRITE_LINE_MEMBER( ip3_w ); + DECLARE_WRITE_LINE_MEMBER( ip4_w ); + DECLARE_WRITE_LINE_MEMBER( ip5_w ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual machine_config_constructor device_mconfig_additions() const; + +private: + TIMER_CALLBACK_MEMBER( duart_timer_callback ); + + /* registers */ + UINT8 ACR; /* Auxiliary Control Register */ + UINT8 IMR; /* Interrupt Mask Register */ + UINT8 ISR; /* Interrupt Status Register */ + UINT8 IVR; /* Interrupt Vector Register */ + UINT8 OPCR; /* Output Port Conf. Register */ + UINT8 OPR; /* Output Port Register */ + PAIR CTR; /* Counter/Timer Preset Value */ + UINT8 IPCR; /* Input Port Control Register */ + + bool m_read_vector; // if this is read and IRQ is active, it counts as pulling IACK + + /* state */ + UINT8 IP_last_state; /* last state of IP bits */ + + /* timer */ + UINT8 half_period; + emu_timer *duart_timer; + + double duart68681_get_ct_rate(); + UINT16 duart68681_get_ct_count(); + void duart68681_start_ct(int count); + int calc_baud(int ch, UINT8 data); + int get_ch(mc68681_channel *ch) { return (ch == m_chanA) ? 0 : 1; } + void clear_ISR_bits(int mask); + void set_ISR_bits(int mask); + void update_interrupts(); + + mc68681_channel *get_channel(int chan); +}; + +extern const device_type MC68681; +extern const device_type MC68681_CHANNEL; + +#endif //_N68681_H diff --git a/src/devices/machine/mc68901.c b/src/devices/machine/mc68901.c new file mode 100644 index 00000000000..4d35d2a2c44 --- /dev/null +++ b/src/devices/machine/mc68901.c @@ -0,0 +1,1134 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Motorola MC68901 Multi Function Peripheral emulation + +**********************************************************************/ + +/* + + TODO: + + - daisy chaining + - disable GPIO3/4 interrupts when timer A/B in pulse mode + - spurious interrupt + + If you look at the MFP datasheet it is obvious that it can generate the conditions for a spurious interrupt. + However the fact that they indeed happen in the ST is quite interesting. + + The MFP will generate a spurious interrupt if interrupts are disabled (by changing the IERA/IERB registers) + at the 'precise point'. The precise point would be after the system (but not necessarily the CPU, see below) + triggered an MFP interrupt, and before the CPU drives the interrupt acknowledge cycle. + + If the MFP was connected directly to the CPU, spurious interrupts probably couldn't happen. However in the + ST, GLUE seats in the middle and handles all the interrupt timing. It is possible that GLUE introduces a + delay between detecting a change in the MFP interrupt request signal and actually propagating the change to + the CPU IPL signals (it is even possible that GLUE make some kind of latching). This would create a window + long enough for the 'precise point' described above. + + "yes, the spurious interrupt occurs when i mask a timer. i did not notice an occurance of the SPI when changing data and control registers. + if i kill interrupts with the status reg before masking the timer interrupt, then the SPI occurs as soon as the status register is set to re-enable interrupts." + + Well, more experiments show that it's somewhat incorrect, and + the GLUE is essentially invisible w.r.t IPL. The CPU and the + MFP manage to add the delays all by themselves. + + - divide serial clock by 16 + - synchronous mode + - 1.5/2 stop bits + - interrupt on receiver break end + - interrupt on character boundaries during break transmission + - loopback mode + +*/ + +#include "emu.h" +#include "mc68901.h" +#include "cpu/m68000/m68000.h" + + +// device type definition +const device_type MC68901 = &device_creator; + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define LOG 0 + + + +#define AER_GPIP_0 0x01 +#define AER_GPIP_1 0x02 +#define AER_GPIP_2 0x04 +#define AER_GPIP_3 0x08 +#define AER_GPIP_4 0x10 +#define AER_GPIP_5 0x20 +#define AER_GPIP_6 0x40 +#define AER_GPIP_7 0x80 + + +#define VR_S 0x08 + + +#define IR_GPIP_0 0x0001 +#define IR_GPIP_1 0x0002 +#define IR_GPIP_2 0x0004 +#define IR_GPIP_3 0x0008 +#define IR_TIMER_D 0x0010 +#define IR_TIMER_C 0x0020 +#define IR_GPIP_4 0x0040 +#define IR_GPIP_5 0x0080 +#define IR_TIMER_B 0x0100 +#define IR_XMIT_ERROR 0x0200 +#define IR_XMIT_BUFFER_EMPTY 0x0400 +#define IR_RCV_ERROR 0x0800 +#define IR_RCV_BUFFER_FULL 0x1000 +#define IR_TIMER_A 0x2000 +#define IR_GPIP_6 0x4000 +#define IR_GPIP_7 0x8000 + + +#define TCR_TIMER_STOPPED 0x00 +#define TCR_TIMER_DELAY_4 0x01 +#define TCR_TIMER_DELAY_10 0x02 +#define TCR_TIMER_DELAY_16 0x03 +#define TCR_TIMER_DELAY_50 0x04 +#define TCR_TIMER_DELAY_64 0x05 +#define TCR_TIMER_DELAY_100 0x06 +#define TCR_TIMER_DELAY_200 0x07 +#define TCR_TIMER_EVENT 0x08 +#define TCR_TIMER_PULSE_4 0x09 +#define TCR_TIMER_PULSE_10 0x0a +#define TCR_TIMER_PULSE_16 0x0b +#define TCR_TIMER_PULSE_50 0x0c +#define TCR_TIMER_PULSE_64 0x0d +#define TCR_TIMER_PULSE_100 0x0e +#define TCR_TIMER_PULSE_200 0x0f +#define TCR_TIMER_RESET 0x10 + + +#define UCR_PARITY_ENABLED 0x04 +#define UCR_PARITY_EVEN 0x02 +#define UCR_PARITY_ODD 0x00 +#define UCR_WORD_LENGTH_8 0x00 +#define UCR_WORD_LENGTH_7 0x20 +#define UCR_WORD_LENGTH_6 0x40 +#define UCR_WORD_LENGTH_5 0x60 +#define UCR_START_STOP_0_0 0x00 +#define UCR_START_STOP_1_1 0x08 +#define UCR_START_STOP_1_15 0x10 +#define UCR_START_STOP_1_2 0x18 +#define UCR_CLOCK_DIVIDE_16 0x80 +#define UCR_CLOCK_DIVIDE_1 0x00 + + +#define RSR_RCV_ENABLE 0x01 +#define RSR_SYNC_STRIP_ENABLE 0x02 +#define RSR_MATCH 0x04 +#define RSR_CHAR_IN_PROGRESS 0x04 +#define RSR_FOUND_SEARCH 0x08 +#define RSR_BREAK 0x08 +#define RSR_FRAME_ERROR 0x10 +#define RSR_PARITY_ERROR 0x20 +#define RSR_OVERRUN_ERROR 0x40 +#define RSR_BUFFER_FULL 0x80 + +#define TSR_XMIT_ENABLE 0x01 +#define TSR_OUTPUT_HI_Z 0x00 +#define TSR_OUTPUT_LOW 0x02 +#define TSR_OUTPUT_HIGH 0x04 +#define TSR_OUTPUT_LOOP 0x06 +#define TSR_OUTPUT_MASK 0x06 +#define TSR_BREAK 0x08 +#define TSR_END_OF_XMIT 0x10 +#define TSR_AUTO_TURNAROUND 0x20 +#define TSR_UNDERRUN_ERROR 0x40 +#define TSR_BUFFER_EMPTY 0x80 + +#define DIVISOR PRESCALER[data & 0x07] + + +const int mc68901_device::INT_MASK_GPIO[] = +{ + IR_GPIP_0, IR_GPIP_1, IR_GPIP_2, IR_GPIP_3, + IR_GPIP_4, IR_GPIP_5, IR_GPIP_6, IR_GPIP_7 +}; + + +const int mc68901_device::INT_MASK_TIMER[] = +{ + IR_TIMER_A, IR_TIMER_B, IR_TIMER_C, IR_TIMER_D +}; + + +const int mc68901_device::GPIO_TIMER[] = +{ + GPIP_4, GPIP_3 +}; + + +const int mc68901_device::PRESCALER[] = { 0, 4, 10, 16, 50, 64, 100, 200 }; + + +//************************************************************************** +// INLINE HELPERS +//************************************************************************** + +inline void mc68901_device::check_interrupts() +{ + if (m_ipr & m_imr) + { + m_out_irq_cb(ASSERT_LINE); + } + else + { + m_out_irq_cb(CLEAR_LINE); + } +} + +inline void mc68901_device::take_interrupt(UINT16 mask) +{ + m_ipr |= mask; + + check_interrupts(); +} + +inline void mc68901_device::rx_buffer_full() +{ + if (m_ier & IR_RCV_BUFFER_FULL) + { + take_interrupt(IR_RCV_BUFFER_FULL); + } +} + +inline void mc68901_device::rx_error() +{ + if (m_ier & IR_RCV_ERROR) + { + take_interrupt(IR_RCV_ERROR); + } + else + { + rx_buffer_full(); + } +} + +inline void mc68901_device::timer_count(int index) +{ + if (m_tmc[index] == 0x01) + { + /* toggle timer output signal */ + m_to[index] = !m_to[index]; + + switch (index) + { + case TIMER_A: m_out_tao_cb(m_to[index]); break; + case TIMER_B: m_out_tbo_cb(m_to[index]); break; + case TIMER_C: m_out_tco_cb(m_to[index]); break; + case TIMER_D: m_out_tdo_cb(m_to[index]); break; + } + + if (m_ier & INT_MASK_TIMER[index]) + { + /* signal timer elapsed interrupt */ + take_interrupt(INT_MASK_TIMER[index]); + } + + /* load main counter */ + m_tmc[index] = m_tdr[index]; + } + else + { + /* count down */ + m_tmc[index]--; + } +} + + +inline void mc68901_device::timer_input(int index, int value) +{ + int bit = GPIO_TIMER[index]; + int aer = BIT(m_aer, bit); + int cr = index ? m_tbcr : m_tacr; + + switch (cr & 0x0f) + { + case TCR_TIMER_EVENT: + if (((m_ti[index] ^ aer) == 1) && ((value ^ aer) == 0)) + { + timer_count(index); + } + + m_ti[index] = value; + break; + + case TCR_TIMER_PULSE_4: + case TCR_TIMER_PULSE_10: + case TCR_TIMER_PULSE_16: + case TCR_TIMER_PULSE_50: + case TCR_TIMER_PULSE_64: + case TCR_TIMER_PULSE_100: + case TCR_TIMER_PULSE_200: + m_timer[index]->enable((value == aer)); + + if (((m_ti[index] ^ aer) == 0) && ((value ^ aer) == 1)) + { + if (m_ier & INT_MASK_GPIO[bit]) + { + take_interrupt(INT_MASK_GPIO[bit]); + } + } + + m_ti[index] = value; + break; + } +} + + +inline void mc68901_device::gpio_input(int bit, int state) +{ + if (state != BIT(m_gpio_input, bit)) + { + if (state == BIT(m_aer, bit)) + { + if (LOG) logerror("MC68901 '%s' Edge Transition Detected on GPIO%u\n", tag(), bit); + + if (m_ier & INT_MASK_GPIO[bit]) // AND interrupt enabled bit is set... + { + if (LOG) logerror("MC68901 '%s' Interrupt Pending for GPIO%u\n", tag(), bit); + + take_interrupt(INT_MASK_GPIO[bit]); // set interrupt pending bit + } + } + + + if (state) + m_gpio_input |= (1 << bit); + else + m_gpio_input &= ~(1 << bit); + } +} + + +void mc68901_device::gpio_output() +{ + UINT8 new_gpio_output = m_gpip & m_ddr; + + if (m_gpio_output != new_gpio_output) + { + m_gpio_output = new_gpio_output; + m_out_gpio_cb((offs_t)0, m_gpio_output); + } +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// mc68901_device - constructor +//------------------------------------------------- + +mc68901_device::mc68901_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, MC68901, "MC68901 MFP", tag, owner, clock, "mc68901", __FILE__), + device_serial_interface(mconfig, *this), + m_timer_clock(0), + m_rx_clock(0), + m_tx_clock(0), + m_out_irq_cb(*this), + m_out_gpio_cb(*this), + m_out_tao_cb(*this), + m_out_tbo_cb(*this), + m_out_tco_cb(*this), + m_out_tdo_cb(*this), + m_out_so_cb(*this), + //m_out_rr_cb(*this), + //m_out_tr_cb(*this), + m_aer(0), + m_ier(0), + m_gpio_input(0), + m_gpio_output(0xff) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void mc68901_device::device_start() +{ + m_start_bit_hack_for_external_clocks = true; + + /* resolve callbacks */ + m_out_irq_cb.resolve_safe(); + m_out_gpio_cb.resolve_safe(); + m_out_tao_cb.resolve_safe(); + m_out_tbo_cb.resolve_safe(); + m_out_tco_cb.resolve_safe(); + m_out_tdo_cb.resolve_safe(); + m_out_so_cb.resolve_safe(); + //m_out_rr_cb.resolve_safe(); + //m_out_tr_cb.resolve_safe(); + + /* create the timers */ + m_timer[TIMER_A] = timer_alloc(TIMER_A); + m_timer[TIMER_B] = timer_alloc(TIMER_B); + m_timer[TIMER_C] = timer_alloc(TIMER_C); + m_timer[TIMER_D] = timer_alloc(TIMER_D); + + if (m_rx_clock > 0) + { + set_rcv_rate(m_rx_clock); + } + + if (m_tx_clock > 0) + { + set_tra_rate(m_tx_clock); + } + + /* register for state saving */ + save_item(NAME(m_gpip)); + save_item(NAME(m_aer)); + save_item(NAME(m_ddr)); + save_item(NAME(m_ier)); + save_item(NAME(m_ipr)); + save_item(NAME(m_isr)); + save_item(NAME(m_imr)); + save_item(NAME(m_vr)); + save_item(NAME(m_tacr)); + save_item(NAME(m_tbcr)); + save_item(NAME(m_tcdcr)); + save_item(NAME(m_tdr)); + save_item(NAME(m_tmc)); + save_item(NAME(m_to)); + save_item(NAME(m_ti)); + save_item(NAME(m_scr)); + save_item(NAME(m_ucr)); + save_item(NAME(m_rsr)); + save_item(NAME(m_tsr)); + save_item(NAME(m_transmit_buffer)); + save_item(NAME(m_transmit_pending)); + save_item(NAME(m_receive_buffer)); + save_item(NAME(m_receive_pending)); + save_item(NAME(m_gpio_input)); + save_item(NAME(m_gpio_output)); + save_item(NAME(m_rsr_read)); + save_item(NAME(m_next_rsr)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void mc68901_device::device_reset() +{ + m_tsr = 0; + m_transmit_pending = 0; + + // Avoid read-before-write + m_ipr = m_imr = 0; + + m_next_rsr = 0; + + memset(m_tmc, 0, sizeof(m_tmc)); + memset(m_ti, 0, sizeof(m_ti)); + memset(m_to, 0, sizeof(m_to)); + + register_w(REGISTER_GPIP, 0); + register_w(REGISTER_AER, 0); + register_w(REGISTER_DDR, 0); + register_w(REGISTER_IERA, 0); + register_w(REGISTER_IERB, 0); + register_w(REGISTER_IPRA, 0); + register_w(REGISTER_IPRB, 0); + register_w(REGISTER_ISRA, 0); + register_w(REGISTER_ISRB, 0); + register_w(REGISTER_IMRA, 0); + register_w(REGISTER_IMRB, 0); + register_w(REGISTER_VR, 0); + register_w(REGISTER_TACR, 0); + register_w(REGISTER_TBCR, 0); + register_w(REGISTER_TCDCR, 0); + register_w(REGISTER_SCR, 0); + register_w(REGISTER_UCR, 0); + register_w(REGISTER_RSR, 0); + + transmit_register_reset(); + receive_register_reset(); +} + + +//------------------------------------------------- +// device_timer - handler timer events +//------------------------------------------------- + +void mc68901_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + if(id >= TIMER_A && id <= TIMER_D) + timer_count(id); + else + device_serial_interface::device_timer(timer, id, param, ptr); +} + + +//------------------------------------------------- +// tra_callback - +//------------------------------------------------- + +void mc68901_device::tra_callback() +{ + m_out_so_cb(transmit_register_get_data_bit()); +} + + +//------------------------------------------------- +// tra_complete - +//------------------------------------------------- + +void mc68901_device::tra_complete() +{ + if (m_tsr & TSR_XMIT_ENABLE) + { + if (m_transmit_pending) + { + transmit_register_setup(m_transmit_buffer); + m_transmit_pending = 0; + m_tsr |= TSR_BUFFER_EMPTY; + + if (m_ier & IR_XMIT_BUFFER_EMPTY) + { + take_interrupt(IR_XMIT_BUFFER_EMPTY); + } + } + else + { + m_tsr |= TSR_UNDERRUN_ERROR; + // TODO: transmit error? + } + } + else + { + m_tsr |= TSR_END_OF_XMIT; + } +} + + +//------------------------------------------------- +// rcv_complete - +//------------------------------------------------- + +void mc68901_device::rcv_complete() +{ + receive_register_extract(); + m_receive_buffer = get_received_char(); + //if (m_receive_pending) TODO: error? + + m_receive_pending = 1; + rx_buffer_full(); +} + + +//------------------------------------------------- +// read - +//------------------------------------------------- + +READ8_MEMBER( mc68901_device::read ) +{ + switch (offset) + { + case REGISTER_GPIP: return (m_gpio_input & ~m_ddr) | (m_gpip & m_ddr); + + case REGISTER_AER: return m_aer; + case REGISTER_DDR: return m_ddr; + + case REGISTER_IERA: return m_ier >> 8; + case REGISTER_IERB: return m_ier & 0xff; + case REGISTER_IPRA: return m_ipr >> 8; + case REGISTER_IPRB: return m_ipr & 0xff; + case REGISTER_ISRA: return m_isr >> 8; + case REGISTER_ISRB: return m_isr & 0xff; + case REGISTER_IMRA: return m_imr >> 8; + case REGISTER_IMRB: return m_imr & 0xff; + case REGISTER_VR: return m_vr; + + case REGISTER_TACR: return m_tacr; + case REGISTER_TBCR: return m_tbcr; + case REGISTER_TCDCR: return m_tcdcr; + case REGISTER_TADR: return m_tmc[TIMER_A]; + case REGISTER_TBDR: return m_tmc[TIMER_B]; + case REGISTER_TCDR: return m_tmc[TIMER_C]; + case REGISTER_TDDR: return m_tmc[TIMER_D]; + + case REGISTER_SCR: return m_scr; + case REGISTER_UCR: return m_ucr; + case REGISTER_RSR: return m_rsr; + + case REGISTER_TSR: + { + /* clear UE bit (in reality, this won't be cleared until one full clock cycle of the transmitter has passed since the bit was set) */ + UINT8 tsr = m_tsr; + m_tsr &= ~TSR_UNDERRUN_ERROR; + + return tsr; + } + + case REGISTER_UDR: + m_receive_pending = 0; + return m_receive_buffer; + + default: return 0; + } +} + + + +//------------------------------------------------- +// register_w - +//------------------------------------------------- + +void mc68901_device::register_w(offs_t offset, UINT8 data) +{ + switch (offset) + { + case REGISTER_GPIP: + if (LOG) logerror("MC68901 '%s' General Purpose I/O : %x\n", tag(), data); + m_gpip = data; + gpio_output(); + break; + + case REGISTER_AER: + if (LOG) logerror("MC68901 '%s' Active Edge Register : %x\n", tag(), data); + m_aer = data; + break; + + case REGISTER_DDR: + if (LOG) logerror("MC68901 '%s' Data Direction Register : %x\n", tag(), data); + m_ddr = data; + gpio_output(); + break; + + case REGISTER_IERA: + if (LOG) logerror("MC68901 '%s' Interrupt Enable Register A : %x\n", tag(), data); + m_ier = (data << 8) | (m_ier & 0xff); + m_ipr &= m_ier; + check_interrupts(); + break; + + case REGISTER_IERB: + if (LOG) logerror("MC68901 '%s' Interrupt Enable Register B : %x\n", tag(), data); + m_ier = (m_ier & 0xff00) | data; + m_ipr &= m_ier; + check_interrupts(); + break; + + case REGISTER_IPRA: + if (LOG) logerror("MC68901 '%s' Interrupt Pending Register A : %x\n", tag(), data); + m_ipr &= (data << 8) | (m_ipr & 0xff); + check_interrupts(); + break; + + case REGISTER_IPRB: + if (LOG) logerror("MC68901 '%s' Interrupt Pending Register B : %x\n", tag(), data); + m_ipr &= (m_ipr & 0xff00) | data; + check_interrupts(); + break; + + case REGISTER_ISRA: + if (LOG) logerror("MC68901 '%s' Interrupt In-Service Register A : %x\n", tag(), data); + m_isr &= (data << 8) | (m_isr & 0xff); + break; + + case REGISTER_ISRB: + if (LOG) logerror("MC68901 '%s' Interrupt In-Service Register B : %x\n", tag(), data); + m_isr &= (m_isr & 0xff00) | data; + break; + + case REGISTER_IMRA: + if (LOG) logerror("MC68901 '%s' Interrupt Mask Register A : %x\n", tag(), data); + m_imr = (data << 8) | (m_imr & 0xff); + m_isr &= m_imr; + check_interrupts(); + break; + + case REGISTER_IMRB: + if (LOG) logerror("MC68901 '%s' Interrupt Mask Register B : %x\n", tag(), data); + m_imr = (m_imr & 0xff00) | data; + m_isr &= m_imr; + check_interrupts(); + break; + + case REGISTER_VR: + if (LOG) logerror("MC68901 '%s' Interrupt Vector : %x\n", tag(), data & 0xf0); + + m_vr = data & 0xf8; + + if (m_vr & VR_S) + { + if (LOG) logerror("MC68901 '%s' Software End-Of-Interrupt Mode\n", tag()); + } + else + { + if (LOG) logerror("MC68901 '%s' Automatic End-Of-Interrupt Mode\n", tag()); + + m_isr = 0; + } + break; + + case REGISTER_TACR: + m_tacr = data & 0x1f; + + switch (m_tacr & 0x0f) + { + case TCR_TIMER_STOPPED: + if (LOG) logerror("MC68901 '%s' Timer A Stopped\n", tag()); + m_timer[TIMER_A]->enable(false); + break; + + case TCR_TIMER_DELAY_4: + case TCR_TIMER_DELAY_10: + case TCR_TIMER_DELAY_16: + case TCR_TIMER_DELAY_50: + case TCR_TIMER_DELAY_64: + case TCR_TIMER_DELAY_100: + case TCR_TIMER_DELAY_200: + { + int divisor = PRESCALER[m_tacr & 0x07]; + if (LOG) logerror("MC68901 '%s' Timer A Delay Mode : %u Prescale\n", tag(), divisor); + m_timer[TIMER_A]->adjust(attotime::from_hz(m_timer_clock / divisor), 0, attotime::from_hz(m_timer_clock / divisor)); + } + break; + + case TCR_TIMER_EVENT: + if (LOG) logerror("MC68901 '%s' Timer A Event Count Mode\n", tag()); + m_timer[TIMER_A]->enable(false); + break; + + case TCR_TIMER_PULSE_4: + case TCR_TIMER_PULSE_10: + case TCR_TIMER_PULSE_16: + case TCR_TIMER_PULSE_50: + case TCR_TIMER_PULSE_64: + case TCR_TIMER_PULSE_100: + case TCR_TIMER_PULSE_200: + { + int divisor = PRESCALER[m_tacr & 0x07]; + if (LOG) logerror("MC68901 '%s' Timer A Pulse Width Mode : %u Prescale\n", tag(), divisor); + m_timer[TIMER_A]->adjust(attotime::never, 0, attotime::from_hz(m_timer_clock / divisor)); + m_timer[TIMER_A]->enable(false); + } + break; + } + + if (m_tacr & TCR_TIMER_RESET) + { + if (LOG) logerror("MC68901 '%s' Timer A Reset\n", tag()); + + m_to[TIMER_A] = 0; + + m_out_tao_cb(m_to[TIMER_A]); + } + break; + + case REGISTER_TBCR: + m_tbcr = data & 0x1f; + + switch (m_tbcr & 0x0f) + { + case TCR_TIMER_STOPPED: + if (LOG) logerror("MC68901 '%s' Timer B Stopped\n", tag()); + m_timer[TIMER_B]->enable(false); + break; + + case TCR_TIMER_DELAY_4: + case TCR_TIMER_DELAY_10: + case TCR_TIMER_DELAY_16: + case TCR_TIMER_DELAY_50: + case TCR_TIMER_DELAY_64: + case TCR_TIMER_DELAY_100: + case TCR_TIMER_DELAY_200: + { + int divisor = PRESCALER[m_tbcr & 0x07]; + if (LOG) logerror("MC68901 '%s' Timer B Delay Mode : %u Prescale\n", tag(), divisor); + m_timer[TIMER_B]->adjust(attotime::from_hz(m_timer_clock / divisor), 0, attotime::from_hz(m_timer_clock / divisor)); + } + break; + + case TCR_TIMER_EVENT: + if (LOG) logerror("MC68901 '%s' Timer B Event Count Mode\n", tag()); + m_timer[TIMER_B]->enable(false); + break; + + case TCR_TIMER_PULSE_4: + case TCR_TIMER_PULSE_10: + case TCR_TIMER_PULSE_16: + case TCR_TIMER_PULSE_50: + case TCR_TIMER_PULSE_64: + case TCR_TIMER_PULSE_100: + case TCR_TIMER_PULSE_200: + { + int divisor = PRESCALER[m_tbcr & 0x07]; + if (LOG) logerror("MC68901 '%s' Timer B Pulse Width Mode : %u Prescale\n", tag(), DIVISOR); + m_timer[TIMER_B]->adjust(attotime::never, 0, attotime::from_hz(m_timer_clock / divisor)); + m_timer[TIMER_B]->enable(false); + } + break; + } + + if (m_tacr & TCR_TIMER_RESET) + { + if (LOG) logerror("MC68901 '%s' Timer B Reset\n", tag()); + + m_to[TIMER_B] = 0; + + m_out_tbo_cb(m_to[TIMER_B]); + } + break; + + case REGISTER_TCDCR: + m_tcdcr = data & 0x6f; + + switch (m_tcdcr & 0x07) + { + case TCR_TIMER_STOPPED: + if (LOG) logerror("MC68901 '%s' Timer D Stopped\n", tag()); + m_timer[TIMER_D]->enable(false); + break; + + case TCR_TIMER_DELAY_4: + case TCR_TIMER_DELAY_10: + case TCR_TIMER_DELAY_16: + case TCR_TIMER_DELAY_50: + case TCR_TIMER_DELAY_64: + case TCR_TIMER_DELAY_100: + case TCR_TIMER_DELAY_200: + { + int divisor = PRESCALER[m_tcdcr & 0x07]; + if (LOG) logerror("MC68901 '%s' Timer D Delay Mode : %u Prescale\n", tag(), divisor); + m_timer[TIMER_D]->adjust(attotime::from_hz(m_timer_clock / divisor), 0, attotime::from_hz(m_timer_clock / divisor)); + } + break; + } + + switch ((m_tcdcr >> 4) & 0x07) + { + case TCR_TIMER_STOPPED: + if (LOG) logerror("MC68901 '%s' Timer C Stopped\n", tag()); + m_timer[TIMER_C]->enable(false); + break; + + case TCR_TIMER_DELAY_4: + case TCR_TIMER_DELAY_10: + case TCR_TIMER_DELAY_16: + case TCR_TIMER_DELAY_50: + case TCR_TIMER_DELAY_64: + case TCR_TIMER_DELAY_100: + case TCR_TIMER_DELAY_200: + { + int divisor = PRESCALER[(m_tcdcr >> 4) & 0x07]; + if (LOG) logerror("MC68901 '%s' Timer C Delay Mode : %u Prescale\n", tag(), divisor); + m_timer[TIMER_C]->adjust(attotime::from_hz(m_timer_clock / divisor), 0, attotime::from_hz(m_timer_clock / divisor)); + } + break; + } + break; + + case REGISTER_TADR: + if (LOG) logerror("MC68901 '%s' Timer A Data Register : %x\n", tag(), data); + + m_tdr[TIMER_A] = data; + + if (!m_timer[TIMER_A]->enabled()) + { + m_tmc[TIMER_A] = data; + } + break; + + case REGISTER_TBDR: + if (LOG) logerror("MC68901 '%s' Timer B Data Register : %x\n", tag(), data); + + m_tdr[TIMER_B] = data; + + if (!m_timer[TIMER_B]->enabled()) + { + m_tmc[TIMER_B] = data; + } + break; + + case REGISTER_TCDR: + if (LOG) logerror("MC68901 '%s' Timer C Data Register : %x\n", tag(), data); + + m_tdr[TIMER_C] = data; + + if (!m_timer[TIMER_C]->enabled()) + { + m_tmc[TIMER_C] = data; + } + break; + + case REGISTER_TDDR: + if (LOG) logerror("MC68901 '%s' Timer D Data Register : %x\n", tag(), data); + + m_tdr[TIMER_D] = data; + + if (!m_timer[TIMER_D]->enabled()) + { + m_tmc[TIMER_D] = data; + } + break; + + case REGISTER_SCR: + if (LOG) logerror("MC68901 '%s' Sync Character : %x\n", tag(), data); + + m_scr = data; + break; + + case REGISTER_UCR: + { + int data_bit_count; + + switch (data & 0x60) + { + case UCR_WORD_LENGTH_8: default: data_bit_count = 8; break; + case UCR_WORD_LENGTH_7: data_bit_count = 7; break; + case UCR_WORD_LENGTH_6: data_bit_count = 6; break; + case UCR_WORD_LENGTH_5: data_bit_count = 5; break; + } + + parity_t parity; + + if (data & UCR_PARITY_ENABLED) + { + if (data & UCR_PARITY_EVEN) + { + if (LOG) logerror("MC68901 '%s' Parity : Even\n", tag()); + + parity = PARITY_EVEN; + } + else + { + if (LOG) logerror("MC68901 '%s' Parity : Odd\n", tag()); + + parity = PARITY_ODD; + } + } + else + { + if (LOG) logerror("MC68901 '%s' Parity : Disabled\n", tag()); + + parity = PARITY_NONE; + } + + if (LOG) logerror("MC68901 '%s' Word Length : %u bits\n", tag(), data_bit_count); + + + int start_bits; + stop_bits_t stop_bits; + + switch (data & 0x18) + { + case UCR_START_STOP_0_0: + default: + start_bits = 0; + stop_bits = STOP_BITS_0; + if (LOG) logerror("MC68901 '%s' Start Bits : 0, Stop Bits : 0, Format : synchronous\n", tag()); + break; + + case UCR_START_STOP_1_1: + start_bits = 1; + stop_bits = STOP_BITS_1; + if (LOG) logerror("MC68901 '%s' Start Bits : 1, Stop Bits : 1, Format : asynchronous\n", tag()); + break; + + case UCR_START_STOP_1_15: + start_bits = 1; + stop_bits = STOP_BITS_1_5; + if (LOG) logerror("MC68901 '%s' Start Bits : 1, Stop Bits : 1.5, Format : asynchronous\n", tag()); + break; + + case UCR_START_STOP_1_2: + start_bits = 1; + stop_bits = STOP_BITS_2; + if (LOG) logerror("MC68901 '%s' Start Bits : 1, Stop Bits : 2, Format : asynchronous\n", tag()); + break; + } + + if (data & UCR_CLOCK_DIVIDE_16) + { + if (LOG) logerror("MC68901 '%s' Rx/Tx Clock Divisor : 16\n", tag()); + } + else + { + if (LOG) logerror("MC68901 '%s' Rx/Tx Clock Divisor : 1\n", tag()); + } + + set_data_frame(start_bits, data_bit_count, parity, stop_bits); + + m_ucr = data; + } + break; + + case REGISTER_RSR: + if ((data & RSR_RCV_ENABLE) == 0) + { + if (LOG) logerror("MC68901 '%s' Receiver Disabled\n", tag()); + m_rsr = 0; + } + else + { + if (LOG) logerror("MC68901 '%s' Receiver Enabled\n", tag()); + + if (data & RSR_SYNC_STRIP_ENABLE) + { + if (LOG) logerror("MC68901 '%s' Sync Strip Enabled\n", tag()); + } + else + { + if (LOG) logerror("MC68901 '%s' Sync Strip Disabled\n", tag()); + } + + if (data & RSR_FOUND_SEARCH) + if (LOG) logerror("MC68901 '%s' Receiver Search Mode Enabled\n", tag()); + + m_rsr = data & 0x0b; + } + break; + + case REGISTER_TSR: + m_tsr = (m_tsr & (TSR_BUFFER_EMPTY | TSR_UNDERRUN_ERROR | TSR_END_OF_XMIT)) | (data & ~(TSR_BUFFER_EMPTY | TSR_UNDERRUN_ERROR | TSR_END_OF_XMIT)); + + if ((data & TSR_XMIT_ENABLE) == 0) + { + if (LOG) logerror("MC68901 '%s' Transmitter Disabled\n", tag()); + + m_tsr &= ~TSR_UNDERRUN_ERROR; + + if (is_transmit_register_empty()) + m_tsr |= TSR_END_OF_XMIT; + } + else + { + if (LOG) logerror("MC68901 '%s' Transmitter Enabled\n", tag()); + + switch (data & 0x06) + { + case TSR_OUTPUT_HI_Z: + if (LOG) logerror("MC68901 '%s' Transmitter Disabled Output State : Hi-Z\n", tag()); + break; + case TSR_OUTPUT_LOW: + if (LOG) logerror("MC68901 '%s' Transmitter Disabled Output State : 0\n", tag()); + break; + case TSR_OUTPUT_HIGH: + if (LOG) logerror("MC68901 '%s' Transmitter Disabled Output State : 1\n", tag()); + break; + case TSR_OUTPUT_LOOP: + if (LOG) logerror("MC68901 '%s' Transmitter Disabled Output State : Loop\n", tag()); + break; + } + + if (data & TSR_BREAK) + { + if (LOG) logerror("MC68901 '%s' Transmitter Break Enabled\n", tag()); + } + else + { + if (LOG) logerror("MC68901 '%s' Transmitter Break Disabled\n", tag()); + } + + if (data & TSR_AUTO_TURNAROUND) + { + if (LOG) logerror("MC68901 '%s' Transmitter Auto Turnaround Enabled\n", tag()); + } + else + { + if (LOG) logerror("MC68901 '%s' Transmitter Auto Turnaround Disabled\n", tag()); + } + + m_tsr &= ~TSR_END_OF_XMIT; + + if (m_transmit_pending && is_transmit_register_empty()) + { + transmit_register_setup(m_transmit_buffer); + m_transmit_pending = 0; + m_tsr |= TSR_BUFFER_EMPTY; + } + } + break; + + case REGISTER_UDR: + if (LOG) logerror("MC68901 '%s' UDR %x\n", tag(), data); + m_transmit_buffer = data; + m_transmit_pending = 1; + m_tsr &= ~TSR_BUFFER_EMPTY; + + if ((m_tsr & TSR_XMIT_ENABLE) && is_transmit_register_empty()) + { + transmit_register_setup(m_transmit_buffer); + m_transmit_pending = 0; + m_tsr |= TSR_BUFFER_EMPTY; + } + break; + } +} + +WRITE8_MEMBER( mc68901_device::write ) +{ + register_w(offset, data); +} + + +int mc68901_device::get_vector() +{ + int ch; + + for (ch = 15; ch >= 0; ch--) + { + if (BIT(m_imr, ch) && BIT(m_ipr, ch)) + { + if (m_vr & VR_S) + { + /* set interrupt-in-service bit */ + m_isr |= (1 << ch); + } + + /* clear interrupt pending bit */ + m_ipr &= ~(1 << ch); + + check_interrupts(); + + return (m_vr & 0xf0) | ch; + } + } + + return M68K_INT_ACK_SPURIOUS; +} + +WRITE_LINE_MEMBER( mc68901_device::i0_w ) { gpio_input(0, state); } +WRITE_LINE_MEMBER( mc68901_device::i1_w ) { gpio_input(1, state); } +WRITE_LINE_MEMBER( mc68901_device::i2_w ) { gpio_input(2, state); } +WRITE_LINE_MEMBER( mc68901_device::i3_w ) { gpio_input(3, state); } +WRITE_LINE_MEMBER( mc68901_device::i4_w ) { gpio_input(4, state); } +WRITE_LINE_MEMBER( mc68901_device::i5_w ) { gpio_input(5, state); } +WRITE_LINE_MEMBER( mc68901_device::i6_w ) { gpio_input(6, state); } +WRITE_LINE_MEMBER( mc68901_device::i7_w ) { gpio_input(7, state); } + + +WRITE_LINE_MEMBER( mc68901_device::tai_w ) +{ + timer_input(TIMER_A, state); +} + + +WRITE_LINE_MEMBER( mc68901_device::tbi_w ) +{ + timer_input(TIMER_B, state); +} + +WRITE_LINE_MEMBER(mc68901_device::write_rx) +{ + device_serial_interface::rx_w(state); +} diff --git a/src/devices/machine/mc68901.h b/src/devices/machine/mc68901.h new file mode 100644 index 00000000000..7147af2a478 --- /dev/null +++ b/src/devices/machine/mc68901.h @@ -0,0 +1,311 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Motorola MC68901 Multi Function Peripheral emulation + +********************************************************************** + _____ _____ + R/_W 1 |* \_/ | 48 _CS + RS1 2 | | 47 _DS + RS2 3 | | 46 _DTACK + RS3 4 | | 45 _IACK + RS4 5 | | 44 D7 + RS5 6 | | 43 D6 + TC 7 | | 42 D5 + SO 8 | | 41 D4 + SI 9 | | 40 D3 + RC 10 | | 39 D2 + Vcc 11 | | 38 D1 + NC 12 | MC68901 | 37 D0 + TAO 13 | MK68901 | 36 GND + TBO 14 | | 35 CLK + TCO 15 | | 34 _IEI + TDO 16 | | 33 _IEO + XTAL1 17 | | 32 _IRQ + XTAL2 18 | | 31 _RR + TAI 19 | | 30 _TR + TBI 20 | | 29 I7 + _RESET 21 | | 28 I6 + I0 22 | | 27 I5 + I1 23 | | 26 I4 + I2 24 |_____________| 25 I3 + +**********************************************************************/ + +#pragma once + +#ifndef __MC68901__ +#define __MC68901__ + +#include "emu.h" + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_MC68901_TIMER_CLOCK(_clk) \ + mc68901_device::set_timer_clock(*device, _clk); + +#define MCFG_MC68901_RX_CLOCK(_clk) \ + mc68901_device::set_rx_clock(*device, _clk); + +#define MCFG_MC68901_TX_CLOCK(_clk) \ + mc68901_device::set_tx_clock(*device, _clk); + +#define MCFG_MC68901_OUT_IRQ_CB(_devcb) \ + devcb = &mc68901_device::set_out_irq_callback(*device, DEVCB_##_devcb); + +#define MCFG_MC68901_OUT_GPIO_CB(_devcb) \ + devcb = &mc68901_device::set_out_gpio_callback(*device, DEVCB_##_devcb); + +#define MCFG_MC68901_OUT_TAO_CB(_devcb) \ + devcb = &mc68901_device::set_out_tao_callback(*device, DEVCB_##_devcb); + +#define MCFG_MC68901_OUT_TBO_CB(_devcb) \ + devcb = &mc68901_device::set_out_tbo_callback(*device, DEVCB_##_devcb); + +#define MCFG_MC68901_OUT_TCO_CB(_devcb) \ + devcb = &mc68901_device::set_out_tco_callback(*device, DEVCB_##_devcb); + +#define MCFG_MC68901_OUT_TDO_CB(_devcb) \ + devcb = &mc68901_device::set_out_tdo_callback(*device, DEVCB_##_devcb); + +#define MCFG_MC68901_OUT_SO_CB(_devcb) \ + devcb = &mc68901_device::set_out_so_callback(*device, DEVCB_##_devcb); + +/*#define MCFG_MC68901_OUT_RR_CB(_devcb) \ + devcb = &mc68901_device::set_out_rr_callback(*device, DEVCB_##_devcb); + +#define MCFG_MC68901_OUT_TR_CB(_devcb) \ + devcb = &mc68901_device::set_out_tr_callback(*device, DEVCB_##_devcb);*/ + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + + +// ======================> mc68901_device + +class mc68901_device : public device_t, + public device_serial_interface +{ +public: + // construction/destruction + mc68901_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + static void set_timer_clock(device_t &device, int timer_clock) { downcast(device).m_timer_clock = timer_clock; } + static void set_rx_clock(device_t &device, int rx_clock) { downcast(device).m_rx_clock = rx_clock; } + static void set_tx_clock(device_t &device, int tx_clock) { downcast(device).m_tx_clock = tx_clock; } + template static devcb_base &set_out_irq_callback(device_t &device, _Object object) { return downcast(device).m_out_irq_cb.set_callback(object); } + template static devcb_base &set_out_gpio_callback(device_t &device, _Object object) { return downcast(device).m_out_gpio_cb.set_callback(object); } + template static devcb_base &set_out_tao_callback(device_t &device, _Object object) { return downcast(device).m_out_tao_cb.set_callback(object); } + template static devcb_base &set_out_tbo_callback(device_t &device, _Object object) { return downcast(device).m_out_tbo_cb.set_callback(object); } + template static devcb_base &set_out_tco_callback(device_t &device, _Object object) { return downcast(device).m_out_tco_cb.set_callback(object); } + template static devcb_base &set_out_tdo_callback(device_t &device, _Object object) { return downcast(device).m_out_tdo_cb.set_callback(object); } + template static devcb_base &set_out_so_callback(device_t &device, _Object object) { return downcast(device).m_out_so_cb.set_callback(object); } + //template static devcb_base &set_rr_callback(device_t &device, _Object object) { return downcast(device).m_out_rr_cb.set_callback(object); } + //template static devcb_base &set_tr_callback(device_t &device, _Object object) { return downcast(device).m_out_tr_cb.set_callback(object); } + + DECLARE_READ8_MEMBER( read ); + DECLARE_WRITE8_MEMBER( write ); + + int get_vector(); + + DECLARE_WRITE_LINE_MEMBER( i0_w ); + DECLARE_WRITE_LINE_MEMBER( i1_w ); + DECLARE_WRITE_LINE_MEMBER( i2_w ); + DECLARE_WRITE_LINE_MEMBER( i3_w ); + DECLARE_WRITE_LINE_MEMBER( i4_w ); + DECLARE_WRITE_LINE_MEMBER( i5_w ); + DECLARE_WRITE_LINE_MEMBER( i6_w ); + DECLARE_WRITE_LINE_MEMBER( i7_w ); + + DECLARE_WRITE_LINE_MEMBER( tai_w ); + DECLARE_WRITE_LINE_MEMBER( tbi_w ); + + DECLARE_WRITE_LINE_MEMBER( write_rx ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + // device_serial_interface overrides + virtual void tra_callback(); + virtual void tra_complete(); + virtual void rcv_complete(); + + void check_interrupts(); + void take_interrupt(UINT16 mask); + void rx_buffer_full(); + void rx_error(); + void timer_count(int index); + void timer_input(int index, int value); + void gpio_input(int bit, int state); + void gpio_output(); + void register_w(offs_t offset, UINT8 data); + +private: + enum + { + TIMER_A = 0, + TIMER_B, + TIMER_C, + TIMER_D + }; + + enum + { + REGISTER_GPIP = 0, + REGISTER_AER, + REGISTER_DDR, + REGISTER_IERA, + REGISTER_IERB, + REGISTER_IPRA, + REGISTER_IPRB, + REGISTER_ISRA, + REGISTER_ISRB, + REGISTER_IMRA, + REGISTER_IMRB, + REGISTER_VR, + REGISTER_TACR, + REGISTER_TBCR, + REGISTER_TCDCR, + REGISTER_TADR, + REGISTER_TBDR, + REGISTER_TCDR, + REGISTER_TDDR, + REGISTER_SCR, + REGISTER_UCR, + REGISTER_RSR, + REGISTER_TSR, + REGISTER_UDR + }; + + enum + { + INT_GPI0 = 0, + INT_GPI1, + INT_GPI2, + INT_GPI3, + INT_TIMER_D, + INT_TIMER_C, + INT_GPI4, + INT_GPI5, + INT_TIMER_B, + INT_XMIT_ERROR, + INT_XMIT_BUFFER_EMPTY, + INT_RCV_ERROR, + INT_RCV_BUFFER_FULL, + INT_TIMER_A, + INT_GPI6, + INT_GPI7 + }; + + enum + { + GPIP_0 = 0, + GPIP_1, + GPIP_2, + GPIP_3, + GPIP_4, + GPIP_5, + GPIP_6, + GPIP_7 + }; + + enum + { + SERIAL_START = 0, + SERIAL_DATA, + SERIAL_PARITY, + SERIAL_STOP + }; + + enum + { + XMIT_OFF = 0, + XMIT_STARTING, + XMIT_ON, + XMIT_BREAK, + XMIT_STOPPING + }; + + static const int INT_MASK_GPIO[]; + static const int INT_MASK_TIMER[]; + static const int GPIO_TIMER[]; + static const int PRESCALER[]; + + int m_timer_clock; /* timer clock */ + int m_rx_clock; /* serial receive clock */ + int m_tx_clock; /* serial transmit clock */ + + devcb_write_line m_out_irq_cb; + + devcb_write8 m_out_gpio_cb; + + devcb_write_line m_out_tao_cb; + devcb_write_line m_out_tbo_cb; + devcb_write_line m_out_tco_cb; + devcb_write_line m_out_tdo_cb; + + devcb_write_line m_out_so_cb; + //devcb_write_line m_out_rr_cb; + //devcb_write_line m_out_tr_cb; + + //int m_device_type; /* device type */ + + /* registers */ + UINT8 m_gpip; /* general purpose I/O register */ + UINT8 m_aer; /* active edge register */ + UINT8 m_ddr; /* data direction register */ + + UINT16 m_ier; /* interrupt enable register */ + UINT16 m_ipr; /* interrupt pending register */ + UINT16 m_isr; /* interrupt in-service register */ + UINT16 m_imr; /* interrupt mask register */ + UINT8 m_vr; /* vector register */ + + UINT8 m_tacr; /* timer A control register */ + UINT8 m_tbcr; /* timer B control register */ + UINT8 m_tcdcr; /* timers C and D control register */ + UINT8 m_tdr[4]; /* timer data registers */ + + UINT8 m_scr; /* synchronous character register */ + UINT8 m_ucr; /* USART control register */ + UINT8 m_tsr; /* transmitter status register */ + UINT8 m_rsr; /* receiver status register */ + UINT8 m_transmit_buffer; /* USART data register */ + int m_transmit_pending; + UINT8 m_receive_buffer; + int m_receive_pending; + UINT8 m_gpio_input; + UINT8 m_gpio_output; + + /* counter timer state */ + UINT8 m_tmc[4]; /* timer main counters */ + int m_ti[4]; /* timer in latch */ + int m_to[4]; /* timer out latch */ + + /* interrupt state */ + //int m_irqlevel; /* interrupt level latch */ + + /* serial state */ + UINT8 m_next_rsr; /* receiver status register latch */ + int m_rsr_read; /* receiver status register read flag */ + + // timers + emu_timer *m_timer[4]; /* counter timers */ +}; + + +// device type definition +extern const device_type MC68901; + + + +#endif diff --git a/src/devices/machine/mccs1850.c b/src/devices/machine/mccs1850.c new file mode 100644 index 00000000000..b037f184bfc --- /dev/null +++ b/src/devices/machine/mccs1850.c @@ -0,0 +1,584 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Motorola MCCS1850 Serial Real-Time Clock emulation + +*********************************************************************/ + +/* + + TODO: + + - auto restart + - test mode + +*/ + +#include "mccs1850.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define LOG 0 + + +#define RAM_SIZE 0x80 + + +// serial state +enum +{ + STATE_ADDRESS, + STATE_DATA +}; + + +// registers +enum +{ + REGISTER_COUNTER_LATCH = 0x20, + REGISTER_ALARM_LATCH = 0x24, + REGISTER_STATUS = 0x30, + REGISTER_CONTROL = 0x31, + REGISTER_TEST_1 = 0x3e, + REGISTER_TEST_2 = 0x3f, + REGISTER_TEST_KICK_START_COUNTER = 0x40, + REGISTER_TEST_PRESCALE_COUNTER = 0x43, + REGISTER_TEST_COUNTER_INCREMENT = 0x4f +}; + + +// clock status/interrupt register +#define STATUS_TM 0x20 // test mode +#define STATUS_FTU 0x10 // first time up +#define STATUS_IT 0x08 // interrupt true +#define STATUS_LB 0x04 // low battery +#define STATUS_AI 0x02 // alarm +#define STATUS_RPD 0x01 // request to power down + + +// clock control register +#define CONTROL_STR_STP 0x80 // start/stop +#define CONTROL_PD 0x40 // power down +#define CONTROL_AR 0x20 // auto restart +#define CONTROL_AE 0x10 // alarm enable +#define CONTROL_AC 0x08 // alarm clear +#define CONTROL_FTUC 0x04 // first time up clear +#define CONTROL_LBE 0x02 // low battery enable +#define CONTROL_RPCD 0x01 // request to power down clear + + +// test register 1 +#define TEST1_DIV1 0x80 // divide by 1 +#define TEST1_VOVR 0x40 // Vdd override +#define TEST1_VDDUP 0x20 // Vdd up +#define TEST1_VDDON 0x10 // Vdd on +#define TEST1_VRT 0x08 // valid RAM and time +#define TEST1_LOW_BAT 0x08 // low battery +#define TEST1_PCC 0x04 // programmable capacitor C (10.0 pF) +#define TEST1_PCB 0x02 // programmable capacitor B (5.0 pF) +#define TEST1_PCA 0x01 // programmable capacitor A (2.5 pF) + + +// test register 2 +#define TEST2_OSCBY 0x80 // oscillator bypass +#define TEST2_COMPOVR 0x40 // comparator override +#define TEST2_POR 0x20 // power on reset +#define TEST2_SELTCK 0x10 // select test clock +#define TEST2_FRZ 0x08 // freeze mode +#define TEST2_DV_MASK 0x07 // divider bits select + + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +// device type definition +const device_type MCCS1850 = &device_creator; + + + +//************************************************************************** +// INLINE HELPERS +//************************************************************************** + +//------------------------------------------------- +// check_interrupt - +//------------------------------------------------- + +inline void mccs1850_device::check_interrupt() +{ + UINT8 status = m_ram[REGISTER_STATUS]; + UINT8 control = m_ram[REGISTER_CONTROL]; + + bool interrupt = (((status & STATUS_AI) && (control & CONTROL_AE)) // alarm interrupt + || ((status & STATUS_LB) && (control & CONTROL_LBE)) // low battery + || (status & STATUS_FTU) // first time up + || (status & STATUS_RPD)); // request to power down + + if (interrupt) + { + m_ram[REGISTER_STATUS] |= STATUS_IT; + } + else + { + m_ram[REGISTER_STATUS] &= ~STATUS_IT; + } + + if(!int_cb.isnull()) + int_cb(interrupt); +} + + +//------------------------------------------------- +// set_pse_line - +//------------------------------------------------- + +inline void mccs1850_device::set_pse_line(bool state) +{ + m_pse = state; + + if(!pse_cb.isnull()) + pse_cb(m_pse); +} + + +//------------------------------------------------- +// read_register - +//------------------------------------------------- + +inline UINT8 mccs1850_device::read_register(offs_t offset) +{ + switch (offset) + { + case REGISTER_COUNTER_LATCH: + case REGISTER_COUNTER_LATCH+3: // Required by the NeXT power on test + // load counter value into latch + m_ram[REGISTER_COUNTER_LATCH] = m_counter >> 24; + m_ram[REGISTER_COUNTER_LATCH + 1] = m_counter >> 16; + m_ram[REGISTER_COUNTER_LATCH + 2] = m_counter >> 8; + m_ram[REGISTER_COUNTER_LATCH + 3] = m_counter; + break; + + case REGISTER_TEST_1: + case REGISTER_TEST_2: + case REGISTER_TEST_KICK_START_COUNTER: + case REGISTER_TEST_PRESCALE_COUNTER: + case REGISTER_TEST_COUNTER_INCREMENT: + logerror("MCCS1850 '%s' Unsupported read from test register %02x!\n", tag(), offset); + break; + } + + return m_ram[offset]; +} + + +//------------------------------------------------- +// write_register - +//------------------------------------------------- + +inline void mccs1850_device::write_register(offs_t offset, UINT8 data) +{ + switch (offset) + { + case REGISTER_STATUS: + // read only + break; + + case REGISTER_CONTROL: + if (LOG) logerror("MCCS1850 '%s' Counter %s\n", tag(), (data & CONTROL_STR_STP) ? "Start" : "Stop"); + m_clock_timer->enable(data & CONTROL_STR_STP); + + if (data & CONTROL_PD) + { + if (LOG) logerror("MCCS1850 '%s' Power Down\n", tag()); + set_pse_line(false); + } + + if (data & CONTROL_AR) + { + if (LOG) logerror("MCCS1850 '%s' Auto Restart\n", tag()); + } + + if (data & CONTROL_AC) + { + if (LOG) logerror("MCCS1850 '%s' Alarm Clear\n", tag()); + m_ram[REGISTER_STATUS] &= ~STATUS_AI; + } + + if (data & CONTROL_FTUC) + { + if (LOG) logerror("MCCS1850 '%s' First Time Up Clear\n", tag()); + m_ram[REGISTER_STATUS] &= ~STATUS_FTU; + } + + if (data & CONTROL_RPCD) + { + if (LOG) logerror("MCCS1850 '%s' Request to Power Down Clear\n", tag()); + m_ram[REGISTER_STATUS] &= ~STATUS_RPD; + } + + m_ram[REGISTER_CONTROL] = data & 0xb2; + + check_interrupt(); + break; + + case REGISTER_TEST_1: + case REGISTER_TEST_2: + case REGISTER_TEST_KICK_START_COUNTER: + case REGISTER_TEST_PRESCALE_COUNTER: + case REGISTER_TEST_COUNTER_INCREMENT: + logerror("MCCS1850 '%s' Unsupported write to test register %02x!\n", tag(), offset); + break; + + default: + m_ram[offset] = data; + } +} + + +//------------------------------------------------- +// advance_seconds - +//------------------------------------------------- + +inline void mccs1850_device::advance_seconds() +{ + UINT32 alarm = (m_ram[REGISTER_ALARM_LATCH] << 24) | (m_ram[REGISTER_ALARM_LATCH + 1] << 16) | (m_ram[REGISTER_ALARM_LATCH + 2] << 8) | m_ram[REGISTER_ALARM_LATCH + 3]; + + m_counter++; + + if (m_counter == alarm) + { + if (m_pse) + { + // trigger alarm + m_ram[REGISTER_STATUS] |= STATUS_AI; + + check_interrupt(); + } + else + { + // wake up + set_pse_line(true); + } + } +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// mccs1850_device - constructor +//------------------------------------------------- + +mccs1850_device::mccs1850_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, MCCS1850, "MCCS1850", tag, owner, clock, "mccs1850", __FILE__), + device_rtc_interface(mconfig, *this), + device_nvram_interface(mconfig, *this), + int_cb(*this), + pse_cb(*this), + nuc_cb(*this), + m_pse(1), + m_counter(0), + m_ce(0), + m_sck(0), + m_sdo(1), + m_sdi(0), + m_state(STATE_ADDRESS), + m_bits(0) +{ +} + + +//------------------------------------------------- +// set_counter - set the counter at startup time +//------------------------------------------------- + +void mccs1850_device::set_counter(UINT32 value) +{ + m_counter = value; +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void mccs1850_device::device_start() +{ + // resolve callbacks + int_cb.resolve(); + pse_cb.resolve(); + nuc_cb.resolve(); + + // allocate timers + m_clock_timer = timer_alloc(TIMER_CLOCK); + m_clock_timer->adjust(attotime::from_hz(clock() / 32768), 0, attotime::from_hz(clock() / 32768)); + + // state saving + save_item(NAME(m_pse)); + save_item(NAME(m_counter)); + save_item(NAME(m_ce)); + save_item(NAME(m_sck)); + save_item(NAME(m_sdo)); + save_item(NAME(m_sdi)); + save_item(NAME(m_state)); + save_item(NAME(m_address)); + save_item(NAME(m_bits)); + save_item(NAME(m_shift)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void mccs1850_device::device_reset() +{ + if(!m_counter) + m_ram[REGISTER_STATUS] = 0x80 | STATUS_FTU; + else + m_ram[REGISTER_STATUS] = 0x80; + m_ram[REGISTER_CONTROL] = 0x00; +} + + +//------------------------------------------------- +// device_timer - handler timer events +//------------------------------------------------- + +void mccs1850_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch (id) + { + case TIMER_CLOCK: + advance_seconds(); + break; + } +} + + +//------------------------------------------------- +// nvram_default - called to initialize NVRAM to +// its default state +//------------------------------------------------- + +void mccs1850_device::nvram_default() +{ + memset(m_ram, 0xff, RAM_SIZE); + + if (machine().root_device().memregion(tag()) != NULL) + { + UINT8 *nvram = machine().root_device().memregion(tag())->base(); + + // initialize NVRAM + memcpy(m_ram, nvram, 0x20); + } +} + + +//------------------------------------------------- +// nvram_read - called to read NVRAM from the +// .nv file +//------------------------------------------------- + +void mccs1850_device::nvram_read(emu_file &file) +{ + file.read(m_ram, RAM_SIZE); +} + + +//------------------------------------------------- +// nvram_write - called to write NVRAM to the +// .nv file +//------------------------------------------------- + +void mccs1850_device::nvram_write(emu_file &file) +{ + file.write(m_ram, RAM_SIZE); +} + + +//------------------------------------------------- +// ce_w - chip enable write +//------------------------------------------------- + +WRITE_LINE_MEMBER( mccs1850_device::ce_w ) +{ + m_ce = state; + + if (!m_ce) + { + m_state = STATE_ADDRESS; + m_bits = 0; + } +} + + +//------------------------------------------------- +// sck_w - serial clock write +//------------------------------------------------- + +WRITE_LINE_MEMBER( mccs1850_device::sck_w ) +{ + if (!m_ce) return; + + switch (m_state) + { + case STATE_ADDRESS: + if (m_sck && !state) + { + m_address <<= 1; + m_address |= m_sdi; + m_bits++; + + if (m_bits == 8) + { + if (LOG) logerror("MCCS1850 '%s' %s Address %02x\n", tag(), BIT(m_address, 7) ? "Write" : "Read", m_address & 0x7f); + + m_bits = 0; + m_state = STATE_DATA; + + if (!BIT(m_address, 7)) + { + m_shift = read_register(m_address & 0x7f); + + if (LOG) logerror("MCCS1850 '%s' Data Out %02x\n", tag(), m_shift); + } + } + } + break; + + case STATE_DATA: + if (BIT(m_address, 7) && m_sck && !state) + { + // shift data in + m_shift <<= 1; + m_shift |= m_sdi; + m_bits++; + + if (m_bits == 8) + { + if (LOG) logerror("MCCS1850 '%s' Data In %02x\n", tag(), m_shift); + + write_register(m_address & 0x7f, m_shift); + + m_bits = 0; + + // increment address counter + m_address++; + m_address |= 0x80; + } + } + else if (!BIT(m_address, 7) && !m_sck && state) + { + // shift data out + m_sdo = BIT(m_shift, 7); + m_shift <<= 1; + m_bits++; + + if (m_bits == 8) + { + m_bits = 0; + + // increment address counter + m_address++; + m_address &= 0x7f; + m_shift = read_register(m_address & 0x7f); + if (LOG) logerror("MCCS1850 '%s' Data Out %02x\n", tag(), m_shift); + } + } + break; + } + + m_sck = state; +} + + +//------------------------------------------------- +// sdo_r - serial data out read +//------------------------------------------------- + +READ_LINE_MEMBER( mccs1850_device::sdo_r ) +{ + if (!m_ce || BIT(m_address, 7)) + { + // Hi-Z + return 1; + } + else + { + return m_sdo; + } +} + + +//------------------------------------------------- +// sdi_w - serial data in write +//------------------------------------------------- + +WRITE_LINE_MEMBER( mccs1850_device::sdi_w ) +{ + m_sdi = state; +} + + +//------------------------------------------------- +// pwrsw_w - power switch write +//------------------------------------------------- + +WRITE_LINE_MEMBER( mccs1850_device::pwrsw_w ) +{ + if (!state) + { + if (m_pse) + { + // request to power down + m_ram[REGISTER_STATUS] |= STATUS_RPD; + check_interrupt(); + } + + set_pse_line(true); + } +} + + +//------------------------------------------------- +// por_w - power on reset write +//------------------------------------------------- + +WRITE_LINE_MEMBER( mccs1850_device::por_w ) +{ + if (!state) + { + device_reset(); + } +} + + +//------------------------------------------------- +// test_w - test mode write +//------------------------------------------------- + +WRITE_LINE_MEMBER( mccs1850_device::test_w ) +{ + if (state) + { + if (LOG) logerror("MCCS1850 '%s' Test Mode\n", tag()); + + m_ram[REGISTER_STATUS] |= STATUS_TM; + } + else + { + if (LOG) logerror("MCCS1850 '%s' Normal Operation\n", tag()); + + m_ram[REGISTER_STATUS] &= ~STATUS_TM; + } +} diff --git a/src/devices/machine/mccs1850.h b/src/devices/machine/mccs1850.h new file mode 100644 index 00000000000..933e67a5f8f --- /dev/null +++ b/src/devices/machine/mccs1850.h @@ -0,0 +1,123 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Motorola MCCS1850 Serial Real-Time Clock emulation + +********************************************************************** + _____ _____ + Vbat 1 |* \_/ | 16 Vdd + _POR 2 | | 15 TEST + _INT 3 | | 14 XTAL1 + SCK 4 | MCCS1850 | 13 XTAL2 + SDI 5 | | 12 _PWRSW + SDO 6 | | 11 NUC + CE 7 | | 10 _PSE + Vss 8 |_____________| 9 PSE + +**********************************************************************/ + +#pragma once + +#ifndef __MCCS1850__ +#define __MCCS1850__ + +#include "emu.h" + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_MCCS1850_INT_CALLBACK(_write) \ + devcb = &mccs1850_device::set_int_wr_callback(*device, DEVCB_##_write); + +#define MCFG_MCCS1850_PSE_CALLBACK(_write) \ + devcb = &mccs1850_device::set_pse_wr_callback(*device, DEVCB_##_write); + +#define MCFG_MCCS1850_NUC_CALLBACK(_write) \ + devcb = &mccs1850_device::set_nuc_wr_callback(*device, DEVCB_##_write); + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> mccs1850_device + +class mccs1850_device : public device_t, + public device_rtc_interface, + public device_nvram_interface +{ +public: + // construction/destruction + mccs1850_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + template static devcb_base &set_int_wr_callback(device_t &device, _Object object) { return downcast(device).int_cb.set_callback(object); } + template static devcb_base &set_pse_wr_callback(device_t &device, _Object object) { return downcast(device).pse_cb.set_callback(object); } + template static devcb_base &set_nuc_wr_callback(device_t &device, _Object object) { return downcast(device).nuc_cb.set_callback(object); } + + DECLARE_WRITE_LINE_MEMBER( ce_w ); + DECLARE_WRITE_LINE_MEMBER( sck_w ); + DECLARE_READ_LINE_MEMBER( sdo_r ); + DECLARE_WRITE_LINE_MEMBER( sdi_w ); + DECLARE_WRITE_LINE_MEMBER( pwrsw_w ); + DECLARE_WRITE_LINE_MEMBER( por_w ); + DECLARE_WRITE_LINE_MEMBER( test_w ); + + // For setting the time at startup + void set_counter(UINT32 value); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + // device_nvram_interface overrides + virtual void nvram_default(); + virtual void nvram_read(emu_file &file); + virtual void nvram_write(emu_file &file); + +private: + inline void check_interrupt(); + inline void set_pse_line(bool state); + inline UINT8 read_register(offs_t offset); + inline void write_register(offs_t offset, UINT8 data); + inline void advance_seconds(); + + static const device_timer_id TIMER_CLOCK = 0; + + devcb_write_line int_cb, pse_cb, nuc_cb; + + UINT8 m_ram[0x80]; // RAM + + // power supply + int m_pse; // power supply enable + + // counter + UINT32 m_counter; // seconds counter + + // serial interface + int m_ce; // chip enable + int m_sck; // serial clock + int m_sdo; // serial data out + int m_sdi; // serial data in + int m_state; // serial interface state + UINT8 m_address; // address counter + int m_bits; // bit counter + UINT8 m_shift; // shift register + + // timers + emu_timer *m_clock_timer; +}; + + +// device type definition +extern const device_type MCCS1850; + + + +#endif diff --git a/src/devices/machine/mcf5206e.c b/src/devices/machine/mcf5206e.c new file mode 100644 index 00000000000..d993c7235e4 --- /dev/null +++ b/src/devices/machine/mcf5206e.c @@ -0,0 +1,1118 @@ +// license:BSD-3-Clause +// copyright-holders:David Haywood +/* Modern device for the MCF5206e Peripherals + this can be hooked properly to the CPU once the CPU is a modern device too +*/ + +#include "emu.h" +#include "mcf5206e.h" + +static void CLIB_DECL ATTR_PRINTF(1,2) nolog(const char *format, ...) {} + +//#define debuglog printf +#define debuglog logerror + +#define invalidlog printf +//#define invalidlog logerror + +//#define debuglogtimer printf +//#define debuglogtimer logerror +#define debuglogtimer nolog + +static ADDRESS_MAP_START( coldfire_regs_map, AS_0, 32, mcf5206e_peripheral_device ) + + + AM_RANGE(0x014, 0x017) AM_READWRITE8(ICR1_ICR2_ICR3_ICR4_r, ICR1_ICR2_ICR3_ICR4_w, 0xffffffff) + + AM_RANGE(0x01c, 0x01f) AM_READWRITE8(ICR9_ICR10_ICR11_ICR12_r, ICR9_ICR10_ICR11_ICR12_w, 0xffffffff) + AM_RANGE(0x020, 0x023) AM_READWRITE8(ICR13_r, ICR13_w, 0xffffffff) + + AM_RANGE(0x034, 0x037) AM_READWRITE16(IMR_r, IMR_w, 0xffffffff) + + /* Chip Select registers */ + AM_RANGE(0x064, 0x067) AM_READWRITE16(CSAR0_r, CSAR0_w, 0xffffffff) + AM_RANGE(0x068, 0x06b) AM_READWRITE (CSMR0_r, CSMR0_w) + AM_RANGE(0x06c, 0x06f) AM_READWRITE16(CSCR0_r, CSCR0_w, 0xffffffff) + AM_RANGE(0x070, 0x073) AM_READWRITE16(CSAR1_r, CSAR1_w, 0xffffffff) + AM_RANGE(0x074, 0x077) AM_READWRITE (CSMR1_r, CSMR1_w) + AM_RANGE(0x078, 0x07b) AM_READWRITE16(CSCR1_r, CSCR1_w, 0xffffffff) + AM_RANGE(0x07c, 0x07f) AM_READWRITE16(CSAR2_r, CSAR2_w, 0xffffffff) + AM_RANGE(0x080, 0x083) AM_READWRITE (CSMR2_r, CSMR2_w) + AM_RANGE(0x084, 0x087) AM_READWRITE16(CSCR2_r, CSCR2_w, 0xffffffff) + AM_RANGE(0x088, 0x08b) AM_READWRITE16(CSAR3_r, CSAR3_w, 0xffffffff) + AM_RANGE(0x08c, 0x08f) AM_READWRITE (CSMR3_r, CSMR3_w) + AM_RANGE(0x090, 0x093) AM_READWRITE16(CSCR3_r, CSCR3_w, 0xffffffff) + AM_RANGE(0x094, 0x097) AM_READWRITE16(CSAR4_r, CSAR4_w, 0xffffffff) + AM_RANGE(0x098, 0x09b) AM_READWRITE (CSMR4_r, CSMR4_w) + AM_RANGE(0x09c, 0x09f) AM_READWRITE16(CSCR4_r, CSCR4_w, 0xffffffff) + AM_RANGE(0x0a0, 0x0a3) AM_READWRITE16(CSAR5_r, CSAR5_w, 0xffffffff) + AM_RANGE(0x0a4, 0x0a7) AM_READWRITE (CSMR5_r, CSMR5_w) + AM_RANGE(0x0a8, 0x0ab) AM_READWRITE16(CSCR5_r, CSCR5_w, 0xffffffff) + AM_RANGE(0x0ac, 0x0af) AM_READWRITE16(CSAR6_r, CSAR6_w, 0xffffffff) + AM_RANGE(0x0b0, 0x0b3) AM_READWRITE (CSMR6_r, CSMR6_w) + AM_RANGE(0x0b4, 0x0b7) AM_READWRITE16(CSCR6_r, CSCR6_w, 0xffffffff) + AM_RANGE(0x0b8, 0x0bb) AM_READWRITE16(CSAR7_r, CSAR7_w, 0xffffffff) + AM_RANGE(0x0bc, 0x0bf) AM_READWRITE (CSMR7_r, CSMR7_w) + AM_RANGE(0x0c0, 0x0c3) AM_READWRITE16(CSCR7_r, CSCR7_w, 0xffffffff) + + AM_RANGE(0x0c4, 0x0c7) AM_READWRITE16(DMCR_r, DMCR_w, 0xffffffff) + AM_RANGE(0x0c8, 0x0cb) AM_READWRITE16(PAR_r, PAR_w, 0xffffffff) + + AM_RANGE(0x100, 0x103) AM_READWRITE16(TMR1_r, TMR1_w, 0xffffffff) + AM_RANGE(0x104, 0x107) AM_READWRITE16(TRR1_r, TRR1_w, 0xffffffff) + AM_RANGE(0x10c, 0x10f) AM_READWRITE16(TCN1_r, TCN1_w, 0xffffffff) + AM_RANGE(0x110, 0x113) AM_READWRITE8(TER1_r, TER1_w, 0xffffffff) + + + AM_RANGE(0x1c4, 0x1c7) AM_READWRITE8(PPDDR_r, PPDDR_w, 0xffffffff) + AM_RANGE(0x1c8, 0x1cb) AM_READWRITE8(PPDAT_r, PPDAT_w, 0xffffffff) + + AM_RANGE(0x1e4, 0x1e7) AM_READWRITE8(MFDR_r, MFDR_w, 0xffffffff) + AM_RANGE(0x1e8, 0x1eb) AM_READWRITE8(MBCR_r, MBCR_w, 0xffffffff) + AM_RANGE(0x1ec, 0x1ef) AM_READWRITE8(MBSR_r, MBSR_w, 0xffffffff) + AM_RANGE(0x1f0, 0x1f3) AM_READWRITE8(MBDR_r, MBDR_w, 0xffffffff) +ADDRESS_MAP_END + + + +READ8_MEMBER( mcf5206e_peripheral_device::ICR1_ICR2_ICR3_ICR4_r ) +{ + switch (offset) + { + case 0: // 0x014 + debuglog("%s: (External IRQ1/IPL1 Interrupt Vector) ICR1_r\n", this->machine().describe_context()); + return m_ICR[ICR1]; + case 1: // 0x015 + debuglog("%s: (External IPL2 Interrupt Vector) ICR2_r\n", this->machine().describe_context()); + return m_ICR[ICR2]; + case 2: // 0x016 + debuglog("%s: (External IPL3 Interrupt Vector) ICR3_r\n", this->machine().describe_context()); + return m_ICR[ICR3]; + case 3: // 0x017 + debuglog("%s: (External IRQ4/IPL4 Interrupt Vector) ICR4_r\n", this->machine().describe_context()); + return m_ICR[ICR4]; + } + + return 0; +} + +WRITE8_MEMBER( mcf5206e_peripheral_device::ICR1_ICR2_ICR3_ICR4_w ) +{ + switch (offset) + { + case 0: // 0x014 + m_ICR[ICR1] = data; + debuglog("%s: (External IRQ1/IPL1 Interrupt Vector) ICR1_w %02x\n", this->machine().describe_context(), data); + ICR_info(m_ICR[ICR1]); + break; + case 1: // 0x015 + m_ICR[ICR2] = data; + debuglog("%s: (External IPL2 Interrupt Vector) ICR2_w %02x\n", this->machine().describe_context(), data); + ICR_info(m_ICR[ICR2]); + break; + case 2: // 0x016 + m_ICR[ICR3] = data; + debuglog("%s: (External IPL3 Interrupt Vector) ICR3_w %02x\n", this->machine().describe_context(), data); + ICR_info(m_ICR[ICR3]); + break; + case 3: // 0x017 + m_ICR[ICR4] = data; + debuglog("%s: (External IRQ4/IPL4 Interrupt Vector) ICR4_w %02x\n", this->machine().describe_context(), data); + ICR_info(m_ICR[ICR4]); + break; + } +} + +READ8_MEMBER( mcf5206e_peripheral_device::ICR9_ICR10_ICR11_ICR12_r ) +{ + switch (offset) + { + case 0: // 0x01c + debuglog("%s: (Timer 1 Interrupt Vector) ICR9_r\n", this->machine().describe_context()); + return m_ICR[ICR9]; + case 1: // 0x01d + debuglog("%s: (Timer 2 Interrupt Vector) ICR10_r\n", this->machine().describe_context()); + return m_ICR[ICR10]; + case 2: // 0x01e + debuglog("%s: (MBUS Interrupt Vector) ICR11_r\n", this->machine().describe_context()); + return m_ICR[ICR11]; + case 3: // 0x01f + debuglog("%s: (UART1 Interrupt Vector) ICR12_r\n", this->machine().describe_context()); + return m_ICR[ICR12]; + } + + return 0; +} + +WRITE8_MEMBER( mcf5206e_peripheral_device::ICR9_ICR10_ICR11_ICR12_w ) +{ + switch (offset) + { + case 0: // 0x01c + m_ICR[ICR9] = data; + debuglog("%s: (Timer 1 Interrupt Vector) ICR9_w %02x\n", this->machine().describe_context(), data); + ICR_info(m_ICR[ICR9]); + break; + case 1: // 0x01d + m_ICR[ICR10] = data; + debuglog("%s: (Timer 2 Interrupt Vector) ICR10_w %02x\n", this->machine().describe_context(), data); + ICR_info(m_ICR[ICR10]); + break; + case 2: // 0x01e + m_ICR[ICR11] = data; + debuglog("%s: (MBUS Interrupt Vector) ICR11_w %02x\n", this->machine().describe_context(), data); + ICR_info(m_ICR[ICR11]); + break; + case 3: // 0x01f + m_ICR[ICR12] = data; + debuglog("%s: (UART1 Interrupt Vector) ICR12_w %02x\n", this->machine().describe_context(), data); + ICR_info(m_ICR[ICR12]); + break; + } +} + +READ8_MEMBER( mcf5206e_peripheral_device::ICR13_r ) +{ + switch (offset) + { + case 0: // 0x020 + debuglog("%s: (UART2 Interrupt Vector) ICR13_r\n", this->machine().describe_context()); + return m_ICR[ICR13]; + case 1: + case 2: + case 3: + invalidlog("%s: invalid ICR13_r %d\n", this->machine().describe_context(), offset); + return 0; + } + + return 0; +} + +WRITE8_MEMBER( mcf5206e_peripheral_device::ICR13_w ) +{ + switch (offset) + { + case 0: // 0x020 + m_ICR[ICR13] = data; + debuglog("%s: (UART2 Interrupt Vector) ICR13_w %02x\n", this->machine().describe_context(), data); + ICR_info(m_ICR[ICR13]); + break; + case 1: + case 2: + case 3: + invalidlog("%s: invalid ICR13_w %d, %02x\n", this->machine().describe_context(), offset, data); + break; + } +} + + +inline UINT16 mcf5206e_peripheral_device::CSAR_r(int which, int offset, UINT16 mem_mask) +{ + if (offset==0) + { + debuglog("%s: CSAR%d_r\n", this->machine().describe_context(), which); + return m_CSAR[which]; + } + else + { + invalidlog("%s: invalid CSAR%d_r with offset %d\n", this->machine().describe_context(), which, offset); + return 0; + } +} + +inline void mcf5206e_peripheral_device::CSAR_w(int which, int offset, UINT16 data, UINT16 mem_mask) +{ + if (offset==0) + { + COMBINE_DATA( &m_CSAR[which] ); + debuglog("%s: CSAR%d_w %04x\n", this->machine().describe_context(), which, data); + } + else + { + invalidlog("%s: invalid CSAR%d_w with offset %d %04x\n", this->machine().describe_context(), which, offset, data); + } +} + +inline UINT32 mcf5206e_peripheral_device::CSMR_r(int which, UINT32 mem_mask) +{ + debuglog("%s: CSMR%d_r\n", this->machine().describe_context(), which); + return m_CSMR[0]; +} + +inline void mcf5206e_peripheral_device::CSMR_w(int which, UINT32 data, UINT32 mem_mask) +{ + COMBINE_DATA( &m_CSMR[0] ); + debuglog("%s: CSMR%d_w %08x\n", this->machine().describe_context(), which, data); +} + +inline UINT16 mcf5206e_peripheral_device::CSCR_r(int which, int offset, UINT16 mem_mask) +{ + if (offset==1) + { + debuglog("%s: CSCR%d_r\n", this->machine().describe_context(), which); + return m_CSCR[which]; + } + else + { + invalidlog("%s: invalid CSCR%d_r with offset %d\n", this->machine().describe_context(), which, offset); + return 0; + } +} + +inline void mcf5206e_peripheral_device::CSCR_w(int which, int offset, UINT16 data, UINT16 mem_mask) +{ + if (offset==1) + { + COMBINE_DATA( &m_CSCR[which] ); + debuglog("%s: CSCR%d_w %04x\n", this->machine().describe_context(), which, data); + } + else + { + invalidlog("%s: invalid CSCR%d_r with offset %d %04x\n", this->machine().describe_context(), which, offset, data); + } +} + + + + +READ16_MEMBER( mcf5206e_peripheral_device::CSAR0_r) { return CSAR_r(0, offset, mem_mask); } +WRITE16_MEMBER( mcf5206e_peripheral_device::CSAR0_w) { CSAR_w(0, offset, data, mem_mask); } +READ32_MEMBER( mcf5206e_peripheral_device::CSMR0_r) { return CSMR_r(0, mem_mask); } +WRITE32_MEMBER( mcf5206e_peripheral_device::CSMR0_w) { CSMR_w(0, data, mem_mask); } +READ16_MEMBER( mcf5206e_peripheral_device::CSCR0_r) { return CSCR_r(0, offset, mem_mask); } +WRITE16_MEMBER( mcf5206e_peripheral_device::CSCR0_w) { CSCR_w(0, offset, data, mem_mask); } + +READ16_MEMBER( mcf5206e_peripheral_device::CSAR1_r) { return CSAR_r(1, offset, mem_mask); } +WRITE16_MEMBER( mcf5206e_peripheral_device::CSAR1_w) { CSAR_w(1, offset, data, mem_mask); } +READ32_MEMBER( mcf5206e_peripheral_device::CSMR1_r) { return CSMR_r(1, mem_mask); } +WRITE32_MEMBER( mcf5206e_peripheral_device::CSMR1_w) { CSMR_w(1, data, mem_mask); } +READ16_MEMBER( mcf5206e_peripheral_device::CSCR1_r) { return CSCR_r(1, offset, mem_mask); } +WRITE16_MEMBER( mcf5206e_peripheral_device::CSCR1_w) { CSCR_w(1, offset, data, mem_mask); } + +READ16_MEMBER( mcf5206e_peripheral_device::CSAR2_r) { return CSAR_r(2, offset, mem_mask); } +WRITE16_MEMBER( mcf5206e_peripheral_device::CSAR2_w) { CSAR_w(2, offset, data, mem_mask); } +READ32_MEMBER( mcf5206e_peripheral_device::CSMR2_r) { return CSMR_r(2, mem_mask); } +WRITE32_MEMBER( mcf5206e_peripheral_device::CSMR2_w) { CSMR_w(2, data, mem_mask); } +READ16_MEMBER( mcf5206e_peripheral_device::CSCR2_r) { return CSCR_r(2, offset, mem_mask); } +WRITE16_MEMBER( mcf5206e_peripheral_device::CSCR2_w) { CSCR_w(2, offset, data, mem_mask); } + +READ16_MEMBER( mcf5206e_peripheral_device::CSAR3_r) { return CSAR_r(3, offset, mem_mask); } +WRITE16_MEMBER( mcf5206e_peripheral_device::CSAR3_w) { CSAR_w(3, offset, data, mem_mask); } +READ32_MEMBER( mcf5206e_peripheral_device::CSMR3_r) { return CSMR_r(3, mem_mask); } +WRITE32_MEMBER( mcf5206e_peripheral_device::CSMR3_w) { CSMR_w(3, data, mem_mask); } +READ16_MEMBER( mcf5206e_peripheral_device::CSCR3_r) { return CSCR_r(3, offset, mem_mask); } +WRITE16_MEMBER( mcf5206e_peripheral_device::CSCR3_w) { CSCR_w(3, offset, data, mem_mask); } + +READ16_MEMBER( mcf5206e_peripheral_device::CSAR4_r) { return CSAR_r(4, offset, mem_mask); } +WRITE16_MEMBER( mcf5206e_peripheral_device::CSAR4_w) { CSAR_w(4, offset, data, mem_mask); } +READ32_MEMBER( mcf5206e_peripheral_device::CSMR4_r) { return CSMR_r(4, mem_mask); } +WRITE32_MEMBER( mcf5206e_peripheral_device::CSMR4_w) { CSMR_w(4, data, mem_mask); } +READ16_MEMBER( mcf5206e_peripheral_device::CSCR4_r) { return CSCR_r(4, offset, mem_mask); } +WRITE16_MEMBER( mcf5206e_peripheral_device::CSCR4_w) { CSCR_w(4, offset, data, mem_mask); } + +READ16_MEMBER( mcf5206e_peripheral_device::CSAR5_r) { return CSAR_r(5, offset, mem_mask); } +WRITE16_MEMBER( mcf5206e_peripheral_device::CSAR5_w) { CSAR_w(5, offset, data, mem_mask); } +READ32_MEMBER( mcf5206e_peripheral_device::CSMR5_r) { return CSMR_r(5, mem_mask); } +WRITE32_MEMBER( mcf5206e_peripheral_device::CSMR5_w) { CSMR_w(5, data, mem_mask); } +READ16_MEMBER( mcf5206e_peripheral_device::CSCR5_r) { return CSCR_r(5, offset, mem_mask); } +WRITE16_MEMBER( mcf5206e_peripheral_device::CSCR5_w) { CSCR_w(5, offset, data, mem_mask); } + +READ16_MEMBER( mcf5206e_peripheral_device::CSAR6_r) { return CSAR_r(6, offset, mem_mask); } +WRITE16_MEMBER( mcf5206e_peripheral_device::CSAR6_w) { CSAR_w(6, offset, data, mem_mask); } +READ32_MEMBER( mcf5206e_peripheral_device::CSMR6_r) { return CSMR_r(6, mem_mask); } +WRITE32_MEMBER( mcf5206e_peripheral_device::CSMR6_w) { CSMR_w(6, data, mem_mask); } +READ16_MEMBER( mcf5206e_peripheral_device::CSCR6_r) { return CSCR_r(6, offset, mem_mask); } +WRITE16_MEMBER( mcf5206e_peripheral_device::CSCR6_w) { CSCR_w(6, offset, data, mem_mask); } + +READ16_MEMBER( mcf5206e_peripheral_device::CSAR7_r) { return CSAR_r(7, offset, mem_mask); } +WRITE16_MEMBER( mcf5206e_peripheral_device::CSAR7_w) { CSAR_w(7, offset, data, mem_mask); } +READ32_MEMBER( mcf5206e_peripheral_device::CSMR7_r) { return CSMR_r(7, mem_mask); } +WRITE32_MEMBER( mcf5206e_peripheral_device::CSMR7_w) { CSMR_w(7, data, mem_mask); } +READ16_MEMBER( mcf5206e_peripheral_device::CSCR7_r) { return CSCR_r(7, offset, mem_mask); } +WRITE16_MEMBER( mcf5206e_peripheral_device::CSCR7_w) { CSCR_w(7, offset, data, mem_mask); } + + +READ16_MEMBER( mcf5206e_peripheral_device::DMCR_r) +{ + switch (offset) + { + case 1: + debuglog("%s: DMCR_r %04x\n", this->machine().describe_context(), mem_mask); + return m_DMCR; + case 0: + invalidlog("%s: invalid DMCR_r %d %04x\n", this->machine().describe_context(), offset, mem_mask); + return 0; + } + + return 0; +} + +WRITE16_MEMBER( mcf5206e_peripheral_device::DMCR_w) +{ + switch (offset) + { + case 1: + COMBINE_DATA(&m_DMCR); + debuglog("%s: DMCR_w %04x %04x\n", this->machine().describe_context(), data, mem_mask); + break; + case 0: + invalidlog("%s: invalid DMCR_w %d, %04x %04x\n", this->machine().describe_context(), offset, data, mem_mask); + break; + + } +} + + +READ16_MEMBER( mcf5206e_peripheral_device::PAR_r) +{ + switch (offset) + { + case 1: + debuglog("%s: PAR_r %04x\n", this->machine().describe_context(), mem_mask); + return m_PAR; + case 0: + invalidlog("%s: invalid PAR_r %d %04x\n", this->machine().describe_context(), offset, mem_mask); + return 0; + } + + return 0; +} + +WRITE16_MEMBER( mcf5206e_peripheral_device::PAR_w) +{ + switch (offset) + { + case 1: + COMBINE_DATA(&m_PAR); + debuglog("%s: PAR_w %04x %04x\n", this->machine().describe_context(), data, mem_mask); + break; + case 0: + invalidlog("%s: invalid PAR_w %d, %04x %04x\n", this->machine().describe_context(), offset, data, mem_mask); + break; + + } +} + + + +READ8_MEMBER( mcf5206e_peripheral_device::PPDDR_r) +{ + switch (offset) + { + case 0: + case 2: + case 3: + invalidlog("%s: invalid PPDDR_r %d\n", this->machine().describe_context(), offset); + return 0; + case 1: // '$1C5' + debuglog("%s: (Port A Data Direction Register) PPDDR_r\n", this->machine().describe_context()); + return m_PPDDR; + } + + return 0; +} + +WRITE8_MEMBER( mcf5206e_peripheral_device::PPDDR_w) +{ + switch (offset) + { + case 0: + case 2: + case 3: + invalidlog("%s: invalid PPDDR_w %d %02x\n", this->machine().describe_context(), offset, data); + break; + case 1: // '$1C5' + m_PPDDR = data; + debuglog("%s: (Port A Data Direction Register) PPDDR_w %02x\n", this->machine().describe_context(), data); + break; + } +} + +READ8_MEMBER( mcf5206e_peripheral_device::PPDAT_r) +{ + switch (offset) + { + case 0: + case 2: + case 3: + invalidlog("%s: invalid PPDAT_r %d\n", this->machine().describe_context(), offset); + return 0; + case 1: // '$1C9' + debuglog("%s: (Port A Data Register) PPDAT_r\n", this->machine().describe_context()); + return m_PPDAT; // should use a callback. + } + + return 0; +} + +WRITE8_MEMBER( mcf5206e_peripheral_device::PPDAT_w) +{ + switch (offset) + { + case 0: + case 2: + case 3: + invalidlog("%s: invalid PPDAT_w %d, %02x\n", this->machine().describe_context(), offset, data); + break; + case 1: // '$1C9' + m_PPDAT = data; // should use a callback. + debuglog("%s: (Port A Data Register) PPDAT_w %02x\n", this->machine().describe_context(), data); + break; + } + +} + + +READ8_MEMBER( mcf5206e_peripheral_device::MBCR_r) +{ + switch (offset) + { + case 0: + debuglog("%s: (M-Bus Control Register) MBCR_r\n", this->machine().describe_context()); + return m_MBCR; + case 1: + case 2: + case 3: + invalidlog("%s: invalid MBCR_r %d\n", this->machine().describe_context(), offset); + return 0; + } + + return 0; +} + +WRITE8_MEMBER( mcf5206e_peripheral_device::MBCR_w) +{ + switch (offset) + { + case 0: + m_MBCR = data; + debuglog("%s: (M-Bus Control Register) MBCR_w %02x\n", this->machine().describe_context(), data); + break; + case 1: + case 2: + case 3: + invalidlog("%s: invalid MBCR_w %d, %02x\n", this->machine().describe_context(), offset, data); + break; + + } +} + +READ8_MEMBER( mcf5206e_peripheral_device::MFDR_r) +{ + switch (offset) + { + case 0: + debuglog("%s: (M-Bus Frequency Divider Register) MFDR_r\n", this->machine().describe_context()); + return m_MFDR; + case 1: + case 2: + case 3: + invalidlog("%s: invalid MFDR_r %d\n", this->machine().describe_context(), offset); + return 0; + } + + return 0; +} + +WRITE8_MEMBER( mcf5206e_peripheral_device::MFDR_w) +{ + switch (offset) + { + case 0: + m_MFDR = data; + debuglog("%s: (M-Bus Frequency Divider Register) MFDR_w %02x\n", this->machine().describe_context(), data); + break; + case 1: + case 2: + case 3: + invalidlog("%s: invalid MFDR_w %d, %02x\n", this->machine().describe_context(), offset, data); + break; + + } +} + + + + + + +READ8_MEMBER( mcf5206e_peripheral_device::MBSR_r) +{ + int hack = 0x00; + + switch (offset) + { + case 0: + { + hack ^= (machine().rand()&0xff); + debuglog("%s: (M-Bus Status Register) MBSR_r\n", this->machine().describe_context()); + return m_MBSR ^ hack; // will loop on this after a while + } + case 1: + case 2: + case 3: + invalidlog("%s: invalid MBSR_r %d\n", this->machine().describe_context(), offset); + return 0; + } + + return 0; +} + +WRITE8_MEMBER( mcf5206e_peripheral_device::MBSR_w) +{ + switch (offset) + { + case 0: + m_MBSR = data; + debuglog("%s: (M-Bus Status Register) MBSR_w %02x\n", this->machine().describe_context(), data); + break; + case 1: + case 2: + case 3: + invalidlog("%s: invalid MBSR_w %d, %02x\n", this->machine().describe_context(), offset, data); + break; + + } +} + + + + +READ8_MEMBER( mcf5206e_peripheral_device::MBDR_r) +{ + int hack = 0x00; + + switch (offset) + { + case 0: + { + hack ^= (machine().rand()&0xff); + debuglog("%s: (M-Bus Data I/O Register) MBDR_r\n", this->machine().describe_context()); + return m_MBDR ^ hack; + } + case 1: + case 2: + case 3: + invalidlog("%s: invalid MBDR_r %d\n", this->machine().describe_context(), offset); + return 0; + } + + return 0; +} + +WRITE8_MEMBER( mcf5206e_peripheral_device::MBDR_w) +{ + switch (offset) + { + case 0: + m_MBDR = data; + debuglog("%s: (M-Bus Data I/O Register) MBDR_w %02x\n", this->machine().describe_context(), data); + break; + case 1: + case 2: + case 3: + invalidlog("%s: invalid MBDR_w %d, %02x\n", this->machine().describe_context(), offset, data); + break; + + } +} + + + +READ16_MEMBER( mcf5206e_peripheral_device::IMR_r) +{ + switch (offset) + { + case 1: + debuglog("%s: (Interrupt Mask Register) IMR_r %04x\n", this->machine().describe_context(), mem_mask); + return m_IMR; + case 0: + invalidlog("%s: invalid IMR_r %d %04x\n", this->machine().describe_context(), offset, mem_mask); + return 0; + } + + return 0; +} + +WRITE16_MEMBER( mcf5206e_peripheral_device::IMR_w) +{ + switch (offset) + { + case 1: + COMBINE_DATA(&m_IMR); + debuglog("%s: (Interrupt Mask Register) IMR_w %04x %04x\n", this->machine().describe_context(), data, mem_mask); + break; + case 0: + invalidlog("%s: invalid IMR_w %d, %04x %04x\n", this->machine().describe_context(), offset, data, mem_mask); + break; + + } +} + +void mcf5206e_peripheral_device::ICR_info(UINT8 ICR) +{ + debuglog(" (AutoVector) AVEC : %01x | ", (ICR&0x80)>>7); + debuglog("(Interrupt Level) IL : %01x | ", (ICR&0x1c)>>2); // if autovector (AVEC) is used then the vectors referenced are at +24 (+0x18) + IL, ie the standard 68k autovectors, otherwise vector must be provided by device + debuglog("(Interrupt Priority) IP : %01x |", (ICR&0x03)>>0); + debuglog("(Unused bits) : %01x\n", (ICR&0x60)>>5); +} + + + +TIMER_CALLBACK_MEMBER(mcf5206e_peripheral_device::timer1_callback) +{ + UINT8 ICR = m_ICR[ICR9]; + + // technically we should do the vector check in the IRQ callback as well as various checks based on the IRQ masks before asserting the interrupt + if (ICR & 0x80) // AVEC + { + if (!(m_IMR & 0x0200)) m_cpu->set_input_line((ICR&0x1c)>>2, HOLD_LINE); + } + + debuglogtimer("timer1_callback\n"); + m_TER1 |= 0x02; + + m_timer1->adjust(attotime::from_msec(10)); // completely made up value just to fire our timers for now +} + + +READ16_MEMBER( mcf5206e_peripheral_device::TMR1_r) +{ + switch (offset) + { + case 0: + debuglogtimer("%s: (Timer 1 Mode Register) TMR1_r %04x\n", this->machine().describe_context(), mem_mask); + return m_TMR1; + case 1: + invalidlog("%s: invalid TMR1_r %d %04x\n", this->machine().describe_context(), offset, mem_mask); + return 0; + } + + return 0; +} + +WRITE16_MEMBER( mcf5206e_peripheral_device::TMR1_w) +{ + switch (offset) + { + case 0: + COMBINE_DATA(&m_TMR1); + debuglogtimer("%s: (Timer 1 Mode Register) TMR1_w %04x %04x\n", this->machine().describe_context(), data, mem_mask); + + debuglogtimer(" (Prescale) PS : %02x (Capture Edge/Interrupt) CE : %01x (Output Mode) OM : %01x (Output Reference Interrupt En) ORI : %01x Free Run (FRR) : %01x Input Clock Source (ICLK) : %01x (Reset Timer) RST : %01x \n", (m_TMR1 & 0xff00)>>8, (m_TMR1 & 0x00c0)>>6, (m_TMR1 & 0x0020)>>5, (m_TMR1 & 0x0010)>>4, (m_TMR1 & 0x0008)>>3, (m_TMR1 & 0x0006)>>1, (m_TMR1 & 0x0001)>>0); + + if (m_TMR1 & 0x0001) + { + m_timer1->adjust(attotime::from_seconds(1)); // completely made up value just to fire our timers for now + } + else + { + m_timer1->adjust(attotime::never); + } + + + break; + case 1: + invalidlog("%s: invalid TMR1_w %d, %04x %04x\n", this->machine().describe_context(), offset, data, mem_mask); + break; + + } +} + +READ16_MEMBER( mcf5206e_peripheral_device::TRR1_r) +{ + switch (offset) + { + case 0: + debuglogtimer("%s: (Timer 1 Reference Register) TRR1_r %04x\n", this->machine().describe_context(), mem_mask); + return m_TRR1; + case 1: + invalidlog("%s: invalid TRR1_r %d %04x\n", this->machine().describe_context(), offset, mem_mask); + return 0; + } + + return 0; +} + +WRITE16_MEMBER( mcf5206e_peripheral_device::TRR1_w) +{ + switch (offset) + { + case 0: + COMBINE_DATA(&m_TRR1); + debuglogtimer("%s: (Timer 1 Reference Register) TRR1_w %04x %04x\n", this->machine().describe_context(), data, mem_mask); + break; + case 1: + debuglog("%s: invalid TRR1_w %d, %04x %04x\n", this->machine().describe_context(), offset, data, mem_mask); + break; + + } +} + + + +READ8_MEMBER( mcf5206e_peripheral_device::TER1_r) +{ + switch (offset) + { + case 1: + debuglogtimer("%s: TER1_r\n", this->machine().describe_context()); + return m_TER1; // set on timer events, cleared by writing below + case 0: + case 2: + case 3: + invalidlog("%s: invalid TER1_r %d\n", this->machine().describe_context(), offset); + return 0; + } + + return 0; +} + +WRITE8_MEMBER( mcf5206e_peripheral_device::TER1_w) +{ + switch (offset) + { + case 1: + m_TER1 &= ~data; // writes should clear the bits.. + debuglogtimer("%s: TER1_w %02x\n", this->machine().describe_context(), data); + break; + case 0: + case 2: + case 3: + invalidlog("%s: invalid TER1_w %d, %02x\n", this->machine().describe_context(), offset, data); + break; + + } +} + +READ16_MEMBER( mcf5206e_peripheral_device::TCN1_r) +{ + switch (offset) + { + case 0: + debuglogtimer("%s: (Timer 1 Counter) TCN1_r %04x\n", this->machine().describe_context(), mem_mask); + // return 0x9c40; + return 0x8ca0 -1;// m_TCN1; // this should be the counter, code has a hardcoded >= check against 8ca0. + case 1: + invalidlog("%s: invalid TCN1_r %d %04x\n", this->machine().describe_context(), offset, mem_mask); + return 0; + } + + return 0; +} + +WRITE16_MEMBER( mcf5206e_peripheral_device::TCN1_w) +{ + switch (offset) + { + case 0: + COMBINE_DATA(&m_TCN1); + debuglogtimer("%s: (Timer 1 Counter) TCN1_w %04x %04x\n", this->machine().describe_context(), data, mem_mask); + break; + case 1: + invalidlog("%s: invalid TCN1_w %d, %04x %04x\n", this->machine().describe_context(), offset, data, mem_mask); + break; + + } +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +// device type definition +const device_type MCF5206E_PERIPHERAL = &device_creator; + +//------------------------------------------------- +// mcf5206e_peripheral_device - constructor +//------------------------------------------------- + +mcf5206e_peripheral_device::mcf5206e_peripheral_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, MCF5206E_PERIPHERAL, "MCF5206E Peripheral", tag, owner, clock, "mcf5206e_peripheral", __FILE__), + device_memory_interface(mconfig, *this), + m_space_config("coldfire_regs", ENDIANNESS_BIG, 32,10, 0, NULL, *ADDRESS_MAP_NAME(coldfire_regs_map)) + +{ +} + +//------------------------------------------------- +// device_config_complete - perform any +// operations now that the configuration is +// complete +//------------------------------------------------- + +void mcf5206e_peripheral_device::device_config_complete() +{ +} + +const address_space_config *mcf5206e_peripheral_device::memory_space_config(address_spacenum spacenum) const +{ + return (spacenum == AS_0) ? &m_space_config : NULL; +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void mcf5206e_peripheral_device::device_start() +{ + init_regs(true); + + m_timer1 = machine().scheduler().timer_alloc( timer_expired_delegate( FUNC( mcf5206e_peripheral_device::timer1_callback ), this) ); + + save_item(NAME(m_ICR)); + save_item(NAME(m_CSAR)); + save_item(NAME(m_CSMR)); + save_item(NAME(m_CSCR)); + save_item(NAME(m_DMCR)); + save_item(NAME(m_PAR)); + save_item(NAME(m_TMR1)); + save_item(NAME(m_TRR1)); + save_item(NAME(m_TER1)); + save_item(NAME(m_TCN1)); + save_item(NAME(m_PPDDR)); + save_item(NAME(m_PPDAT)); + save_item(NAME(m_IMR)); + save_item(NAME(m_MBCR)); + save_item(NAME(m_MBSR)); + save_item(NAME(m_MFDR)); + save_item(NAME(m_MBDR)); + save_item(NAME(m_coldfire_regs)); +} + +void mcf5206e_peripheral_device::device_reset() +{ + m_cpu = (cpu_device*)machine().device(":maincpu"); // hack. this device should really be attached to a modern CPU core + + init_regs(false); + m_timer1->adjust(attotime::never); +} + +READ32_MEMBER(mcf5206e_peripheral_device::dev_r) +{ + address_space ®_space = this->space(); + return reg_space.read_dword(offset*4, mem_mask); +} + +WRITE32_MEMBER(mcf5206e_peripheral_device::dev_w) +{ + address_space ®_space = this->space(); + reg_space.write_dword(offset*4, data, mem_mask); +} + + +// ColdFire peripherals + +enum { + CF_PPDAT = 0x1c8/4, + CF_MBSR = 0x1ec/4 +}; + +WRITE32_MEMBER(mcf5206e_peripheral_device::seta2_coldfire_regs_w) +{ + COMBINE_DATA( &m_coldfire_regs[offset] ); +} + +READ32_MEMBER(mcf5206e_peripheral_device::seta2_coldfire_regs_r) +{ + switch( offset ) + { + case CF_MBSR: + return machine().rand(); + + case CF_PPDAT: + return ioport(":BATTERY")->read() << 16; + } + + return m_coldfire_regs[offset]; +} + +#define UNINIT 0 +#define UNINIT_NOTE 0 + +void mcf5206e_peripheral_device::init_regs(bool first_init) +{ + m_ICR[ICR1] = 0x04; + m_ICR[ICR2] = 0x08; + m_ICR[ICR3] = 0x0C; + m_ICR[ICR4] = 0x10; + m_ICR[ICR5] = 0x14; + m_ICR[ICR6] = 0x18; + m_ICR[ICR7] = 0x1C; + m_ICR[ICR8] = 0x1C; + m_ICR[ICR9] = 0x80; + m_ICR[ICR10] = 0x80; + m_ICR[ICR11] = 0x80; + m_ICR[ICR12] = 0x00; + m_ICR[ICR13] = 0x00; + + m_CSAR[0] = 0x0000; + m_CSMR[0] = 0x00000000; + m_CSCR[0] = 0x3C1F; /* 3C1F, 3C5F, 3C9F, 3CDF, 3D1F, 3D5F, 3D9F, 3DDF | AA set by IRQ 7 at reset, PS1 set by IRQ 4 at reset, PS0 set by IRQ 1 at reset*/ + + if (first_init) + { + for (int x=1;x<8;x++) + { + m_CSAR[1] = UNINIT; + m_CSMR[1] = UNINIT; + m_CSCR[1] = UNINIT_NOTE; // except BRST=ASET=WRAH=RDAH=WR=RD=0 + } + } + + m_DMCR = 0x0000; + m_PAR = 0x0000; + + m_TMR1 = 0x0000; + m_TRR1 = 0xffff; + m_TER1 = 0x00; + m_TCN1 = 0x0000; + + m_PPDDR = 0x00; + m_PPDAT = 0x00; + + m_IMR = 0x3FFE; + + m_MFDR = 0x00; + m_MBCR = 0x00; + m_MBSR = 0x00; + m_MBDR = 0x00; +} + +/* + +ADDRESS (LE) REG WIDTH NAME/DESCRIPTION INIT VALUE (MR=Master Reset, NR=Normal Reset) Read or Write access +* = inited +- = skeleton handler + +op MOVEC with $C0F MBAR 32 Module Base Address Register uninit (except V=0) W +$003 SIMR 8 SIM Configuration Register C0 R/W +$014*- ICR1 8 Interrupt Control Register 1 - External IRQ1/IPL1 04 R/W +$015*- ICR2 8 Interrupt Control Register 2 - External IPL2 08 R/W +$016*- ICR3 8 Interrupt Control Register 3 - External IPL3 0C R/W +$017*- ICR4 8 Interrupt Control Register 4 - External IRQ4/IPL4 10 R/W +$018* ICR5 8 Interrupt Control Register 5 - External IPL5 14 R/W +$019* ICR6 8 Interrupt Control Register 6 - External IPL6 18 R/W +$01A* ICR7 8 Interrupt Control Register 7 - External IRQ7/IPL7 1C R/W +$01B* ICR8 8 Interrupt Control Register 8 - SWT 1C R/W +$01C*- ICR9 8 Interrupt Control Register 9 - Timer 1 Interrupt 80 R/W +$01D*- ICR10 8 Interrupt Control Register 10 - Timer 2 Interrupt 80 R/W +$01E*- ICR11 8 Interrupt Control Register 11 - MBUS Interrupt 80 R/W +$01F*- ICR12 8 Interrupt Control Register 12 - UART 1 Interrupt 00 R/W +$020*- ICR13 8 Interrupt Control Register 13 - UART 2 Interrupt 00 R/W +$036*- IMR 16 Interrupt Mask Register 3FFE R/W +$03A IPR 16 Interrupt Pending Register 0000 R +$040 RSR 8 Reset Status Register 80 / 20 R/W +$041 SYPCR 8 System Protection Control Register 00 R/W +$042 SWIVR 8 Software Watchdog Interrupt Vector Register 0F R/W +$043 SWSR 8 Software Watchdog Service Register uninit W +$046 DCRR 16 DRAM Controller Refresh MR 0000 - NR uninit R/W +$04A DCTR 16 DRAM Controller Timing Register MR 0000 - NR uninit R/W +$04C DCAR0 16 DRAM Controller 0 Address Register MR uninit - NR uninit R/W +$050 DCMR0 32 DRAM Controller 0 Mask Register MR uninit - NR uninit R/W +$057 DCCR0 8 DRAM Controller 0 Control Register MR 00 - NR 00 R/W +$058 DCAR1 16 DRAM Controller 1 Address Register MR uninit - NR uninit R/W +$05C DCMR1 32 DRAM Controller 1 Mask Register MR uninit - NR uninit R/W +$063 DCCR1 8 DRAM Controller 1 Control Register MR 00 - NR 00 R/W +--------- CHIP SELECTS ----------- +$064*- CSAR0 16 Chip-Select 0 Address Register 0000 R/W +$068*- CSMR0 32 Chip-Select 0 Mask Register 00000000 R/W +$06E*- CSCR0 16 Chip-Select 0 Control Register 3C1F, 3C5F, 3C9F, 3CDF, 3D1F, 3D5F, 3D9F, 3DDF R/W + AA set by IRQ 7 at reset + PS1 set by IRQ 4 at reset + PS0 set by IRQ 1 at reset +$070*- CSAR1 16 Chip-Select 1 Address Register uninit R/W +$074*- CSMR1 32 Chip-Select 1 Mask Register uninit R/W +$07A*- CSCR1 16 Chip-Select 1 Control Register uninit *1 R/W +$07C*- CSAR2 16 Chip-Select 2 Address Register uninit R/W +$080*- CSMR2 32 Chip-Select 2 Mask Register uninit R/W +$086*- CSCR2 16 Chip-Select 2 Control Register uninit *1 R/W +$088*- CSAR3 16 Chip-Select 3 Address Register uninit R/W +$08C*- CSMR3 32 Chip-Select 3 Mask Register uninit R/W +$092*- CSCR3 16 Chip-Select 3 Control Register uninit *1 R/W +$094*- CSAR4 16 Chip-Select 4 Address Register uninit R/W +$098*- CSMR4 32 Chip-Select 4 Mask Register uninit R/W +$09E*- CSCR4 16 Chip-Select 4 Control Register uninit *1 R/W +$0A0*- CSAR5 16 Chip-Select 5 Address Register uninit R/W +$0A4*- CSMR5 32 Chip-Select 5 Mask Register uninit R/W +$0AA*- CSCR5 16 Chip-Select 5 Control Register uninit *1 R/W +$0AC*- CSAR6 16 Chip-Select 6 Address Register uninit R/W +$0B0*- CSMR6 32 Chip-Select 6 Mask Register uninit R/W +$0B6*- CSCR6 16 Chip-Select 6 Control Register uninit *1 R/W +$0B8*- CSAR7 16 Chip-Select 7 Address Register uninit R/W +$0BC*- CSMR7 32 Chip-Select 7 Mask Register uninit R/W +$0C2*- CSCR7 16 Chip-Select 7 Control Register uninit *1 R/W +$0C6*- DMCR 16 Default Memory Control Register 0000 R/W +$0CA*- PAR 16 Pin Assignment Register 00 R/W +--------- TIMER MODULE ----------- +$100*- TMR1 16 Timer 1 Mode Register 0000 R/W +$104*- TRR1 16 Timer 1 Reference Register FFFF R/W +$108 TCR1 16 Timer 1 Capture Register 0000 R +$10C*- TCN1 16 Timer 1 Counter 0000 R/W +$111*- TER1 8 Timer 1 Event Register 00 R/W +$120 TMR2 16 Timer 2 Mode Register 0000 R/W +$124 TRR2 16 Timer 2 Reference Register FFFF R/W +$128 TCR2 16 Timer 2 Capture Register 0000 R +$12C TCN2 16 Timer 2 Counter 0000 R/W +$131 TER2 8 Timer 2 Event Register 00 R/W +------------ UART SERIAL PORTS ----------- +$140 UMR1,2 8 UART 1 Mode Registers 00 R/W +$144 USR 8 UART 1 Status Register 00 R + UCSR 8 UART 1 Clock-Select Register DD W +$148 UCR 8 UART 1 Command Register 00 W +$14C URB 8 UART 1 Receive Buffer FF R + UTB 8 UART 1 Transmit Buffer 00 W +$150 UIPCR 8 UART Input Port Change Register 0F R + UACR 8 UART 1 Auxilary Control Register 00 W +$154 UISR 8 UART 1 Interrupt Status Register 00 R + UIMR 8 UART 1 Interrupt Mask Register 00 W +$158 UBG1 8 UART 1 Baud Rate Generator Prescale MSB uninit W +$15C UBG2 8 UART 1 Baud Rate Generator Prescale LSB uninit W +$170 UIVR 8 UART 1 Interrupt Vector Register 0F R/W +$174 UIP 8 UART 1 Input Port Register FF R +$178 UOP1 8 UART 1 Output Port Bit Set CMD UOP1[7-1]=undef; UOP1=0 W +$17C UOP0 8 UART 1 Output Port Bit Reset CMD uninit W + +$180 UMR1,2 8 UART 2 Mode Registers 00 R/W +$184 USR 8 UART 2 Status Register 00 R + UCSR 8 UART 2 Clock-Select Register DD W +$188 UCR 8 UART 2 Command Register 00 W +$18C URB 8 UART 2 Receive Buffer FF R + UTB 8 UART 2 Transmit Buffer 00 W +$190 UIPCR 8 UART 2 Input Port Change Register 0F R + UACR 8 UART 2 Auxilary Control Register 00 W +$194 UISR 8 UART 2 Interrupt Status Register 00 R + UIMR 8 UART 2 Interrupt Mask Register 00 W +$198 UBG1 8 UART 2 Baud Rate Generator Prescale MSB uninit R/W +$19C UBG2 8 UART 2 Barud Rate Generator Prescale LSB uninit R/W +$1B0 UIVR 8 UART 2 Interrupt Vector Register 0F R/W +$1B4 UIP 8 UART 2 Input Port Register FF R +$1B8 UOP1 8 UART 2 Output Port Bit Set CMD UOP1[7-1]=undef; UOP1=0 W +$1BC UOP0 8 UART 2 Output Port Bit Reset CMD uninit W + +$1C5*- PPDDR 8 Port A Data Direction Register 00 R/W +$1C9*- PPDAT 8 Port A Data Register 00 R/W +------------ MBUS ----------- +$1E0 MADR 8 M-Bus Address Register 00 R/W +$1E4*- MFDR 8 M-Bus Frequency Divider Register 00 R/W +$1E8*- MBCR 8 M-Bus Control Register 00 R/W +$1EC*- MBSR 8 M-Bus Status Register 00 R/W +$1F0*- MBDR 8 M-Bus Data I/O Register 00 R/W +------------ DMA Controller ----------- +$200 DMASAR0 32 Source Address Register 0 00 R/W +$204 DMADAR0 32 Destination Address Register 0 00 R/W +$208 DCR0 16 DMA Control Register 0 00 R/W +$20C BCR0 16 Byte Count Register 0 00 R/W +$210 DSR0 8 Status Register 0 00 R/W +$214 DIVR0 8 Interrupt Vector Register 0 0F R/W +$240 DMASAR1 32 Source Address Register 1 00 R/W +$244 DMADAR1 32 Destination Address Register 1 00 R/W +$248 DCR1 16 DMA Control Register 1 00 R/W +$24C BCR1 16 Byte Count Register 1 00 R/W +$250 DSR1 8 Status Register 1 00 R/W +$254 DIVR1 8 Interrupt Vector Register 1 0F R/W + +*1 - uninit except BRST=ASET=WRAH=RDAH=WR=RD=0 + +*/ diff --git a/src/devices/machine/mcf5206e.h b/src/devices/machine/mcf5206e.h new file mode 100644 index 00000000000..d49b88119d3 --- /dev/null +++ b/src/devices/machine/mcf5206e.h @@ -0,0 +1,215 @@ +// license:BSD-3-Clause +// copyright-holders:David Haywood +/*************************************************************************** + + MCF5206E Peripherals + +***************************************************************************/ + +#pragma once + +#ifndef __MCF5206E_PERIPHERAL_H__ +#define __MCF5206E_PERIPHERAL_H__ + +#include "emu.h" + + + +/*************************************************************************** + DEVICE CONFIGURATION MACROS +***************************************************************************/ + +#define MCFG_MCF5206E_PERIPHERAL_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, MCF5206E_PERIPHERAL, 0) + +/*************************************************************************** + TYPE DEFINITIONS +***************************************************************************/ + +// ======================> mcf5206e_peripheral_device + +enum +{ + ICR1 = 0, + ICR2, + ICR3, + ICR4, + ICR5, + ICR6, + ICR7, + ICR8, + ICR9, + ICR10, + ICR11, + ICR12, + ICR13, + MAX_ICR +}; + +class mcf5206e_peripheral_device : public device_t, + public device_memory_interface +{ +public: + // construction/destruction + mcf5206e_peripheral_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + void ICR_info(UINT8 ICR); + + DECLARE_READ32_MEMBER( dev_r ); + DECLARE_WRITE32_MEMBER( dev_w ); + DECLARE_READ32_MEMBER( seta2_coldfire_regs_r ); + DECLARE_WRITE32_MEMBER( seta2_coldfire_regs_w ); + + DECLARE_READ8_MEMBER( ICR1_ICR2_ICR3_ICR4_r ); + DECLARE_WRITE8_MEMBER( ICR1_ICR2_ICR3_ICR4_w ); + + DECLARE_READ8_MEMBER( ICR9_ICR10_ICR11_ICR12_r ); + DECLARE_WRITE8_MEMBER( ICR9_ICR10_ICR11_ICR12_w ); + DECLARE_READ8_MEMBER( ICR13_r ); + DECLARE_WRITE8_MEMBER( ICR13_w ); + + UINT16 CSAR_r(int which, int offset, UINT16 mem_mask); + void CSAR_w(int which, int offset, UINT16 data, UINT16 mem_mask); + UINT32 CSMR_r(int which, UINT32 mem_mask); + void CSMR_w(int which, UINT32 data, UINT32 mem_mask); + UINT16 CSCR_r(int which, int offset, UINT16 mem_mask); + void CSCR_w(int which, int offset, UINT16 data, UINT16 mem_mask); + + DECLARE_READ16_MEMBER( CSAR0_r ); + DECLARE_WRITE16_MEMBER( CSAR0_w ); + DECLARE_READ32_MEMBER( CSMR0_r ); + DECLARE_WRITE32_MEMBER( CSMR0_w ); + DECLARE_READ16_MEMBER( CSCR0_r ); + DECLARE_WRITE16_MEMBER( CSCR0_w ); + DECLARE_READ16_MEMBER( CSAR1_r ); + DECLARE_WRITE16_MEMBER( CSAR1_w ); + DECLARE_READ32_MEMBER( CSMR1_r ); + DECLARE_WRITE32_MEMBER( CSMR1_w ); + DECLARE_READ16_MEMBER( CSCR1_r ); + DECLARE_WRITE16_MEMBER( CSCR1_w ); + DECLARE_READ16_MEMBER( CSAR2_r ); + DECLARE_WRITE16_MEMBER( CSAR2_w ); + DECLARE_READ32_MEMBER( CSMR2_r ); + DECLARE_WRITE32_MEMBER( CSMR2_w ); + DECLARE_READ16_MEMBER( CSCR2_r ); + DECLARE_WRITE16_MEMBER( CSCR2_w ); + DECLARE_READ16_MEMBER( CSAR3_r ); + DECLARE_WRITE16_MEMBER( CSAR3_w ); + DECLARE_READ32_MEMBER( CSMR3_r ); + DECLARE_WRITE32_MEMBER( CSMR3_w ); + DECLARE_READ16_MEMBER( CSCR3_r ); + DECLARE_WRITE16_MEMBER( CSCR3_w ); + DECLARE_READ16_MEMBER( CSAR4_r ); + DECLARE_WRITE16_MEMBER( CSAR4_w ); + DECLARE_READ32_MEMBER( CSMR4_r ); + DECLARE_WRITE32_MEMBER( CSMR4_w ); + DECLARE_READ16_MEMBER( CSCR4_r ); + DECLARE_WRITE16_MEMBER( CSCR4_w ); + DECLARE_READ16_MEMBER( CSAR5_r ); + DECLARE_WRITE16_MEMBER( CSAR5_w ); + DECLARE_READ32_MEMBER( CSMR5_r ); + DECLARE_WRITE32_MEMBER( CSMR5_w ); + DECLARE_READ16_MEMBER( CSCR5_r ); + DECLARE_WRITE16_MEMBER( CSCR5_w ); + DECLARE_READ16_MEMBER( CSAR6_r ); + DECLARE_WRITE16_MEMBER( CSAR6_w ); + DECLARE_READ32_MEMBER( CSMR6_r ); + DECLARE_WRITE32_MEMBER( CSMR6_w ); + DECLARE_READ16_MEMBER( CSCR6_r ); + DECLARE_WRITE16_MEMBER( CSCR6_w ); + DECLARE_READ16_MEMBER( CSAR7_r ); + DECLARE_WRITE16_MEMBER( CSAR7_w ); + DECLARE_READ32_MEMBER( CSMR7_r ); + DECLARE_WRITE32_MEMBER( CSMR7_w ); + DECLARE_READ16_MEMBER( CSCR7_r ); + DECLARE_WRITE16_MEMBER( CSCR7_w ); + + DECLARE_READ16_MEMBER( DMCR_r ); + DECLARE_WRITE16_MEMBER( DMCR_w ); + DECLARE_READ16_MEMBER( PAR_r ); + DECLARE_WRITE16_MEMBER( PAR_w ); + + DECLARE_READ16_MEMBER( TMR1_r ); + DECLARE_WRITE16_MEMBER( TMR1_w ); + DECLARE_READ16_MEMBER( TRR1_r ); + DECLARE_WRITE16_MEMBER( TRR1_w ); + DECLARE_READ8_MEMBER( TER1_r ); + DECLARE_WRITE8_MEMBER(TER1_w ); + DECLARE_READ16_MEMBER( TCN1_r ); + DECLARE_WRITE16_MEMBER( TCN1_w ); + + DECLARE_READ8_MEMBER( PPDDR_r ); + DECLARE_WRITE8_MEMBER( PPDDR_w ); + DECLARE_READ8_MEMBER( PPDAT_r ); + DECLARE_WRITE8_MEMBER( PPDAT_w ); + + DECLARE_READ16_MEMBER( IMR_r ); + DECLARE_WRITE16_MEMBER( IMR_w ); + + + DECLARE_READ8_MEMBER( MBCR_r ); + DECLARE_WRITE8_MEMBER( MBCR_w ); + DECLARE_READ8_MEMBER( MBSR_r ); + DECLARE_WRITE8_MEMBER( MBSR_w ); + DECLARE_READ8_MEMBER( MFDR_r ); + DECLARE_WRITE8_MEMBER( MFDR_w ); + DECLARE_READ8_MEMBER( MBDR_r ); + DECLARE_WRITE8_MEMBER( MBDR_w ); + + + + + cpu_device* m_cpu; + +protected: + // device-level overrides + virtual void device_config_complete(); + virtual void device_start(); + virtual void device_reset(); + virtual void device_post_load() { } + virtual void device_clock_changed() { } + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const; + address_space_config m_space_config; + + +private: + + void init_regs(bool first_init); + + UINT8 m_ICR[MAX_ICR]; + + UINT16 m_CSAR[8]; + UINT32 m_CSMR[8]; + UINT16 m_CSCR[8]; + + UINT16 m_DMCR; + UINT16 m_PAR; + + emu_timer *m_timer1; + UINT16 m_TMR1; + UINT16 m_TRR1; + UINT8 m_TER1; + UINT16 m_TCN1; + TIMER_CALLBACK_MEMBER(timer1_callback); + + + UINT8 m_PPDDR; + UINT8 m_PPDAT; + + UINT16 m_IMR; + + UINT8 m_MBCR; + UINT8 m_MBSR; + UINT8 m_MFDR; + UINT8 m_MBDR; + + UINT32 m_coldfire_regs[0x400/4]; + +private: +}; + + +// device type definition +extern const device_type MCF5206E_PERIPHERAL; + +#endif /* __MCF5206E_PERIPHERAL_H__ */ diff --git a/src/devices/machine/microtch.c b/src/devices/machine/microtch.c new file mode 100644 index 00000000000..eee87447495 --- /dev/null +++ b/src/devices/machine/microtch.c @@ -0,0 +1,307 @@ +// license:BSD-3-Clause +// copyright-holders:Mariusz Wojcieszek +/* + Microtouch touch screen controller + + Written by Mariusz Wojcieszek + + Notes/ToDo: + - calibration mode (command CX) + - only tablet format and decimal format are supported for returning touch screen state + +*/ + +#include "microtch.h" + +#define LOG 0 + +const device_type MICROTOUCH = &device_creator; + +microtouch_device::microtouch_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, MICROTOUCH, "Microtouch Touchscreen", tag, owner, clock, "microtouch", __FILE__), + device_serial_interface(mconfig, *this), + m_out_stx_func(*this), + m_touch(*this, "TOUCH"), + m_touchx(*this, "TOUCH_X"), + m_touchy(*this, "TOUCH_Y") +{ +} + +int microtouch_device::check_command( const char* commandtocheck, int command_len, UINT8* command_data ) +{ + if ( (command_len == (strlen(commandtocheck) + 2)) && + (command_data[0] == 0x01) && + (strncmp(commandtocheck, (const char*)command_data + 1, strlen(commandtocheck)) == 0) && + (command_data[command_len-1] == 0x0d) ) + { + return 1; + } + else + { + return 0; + } +} + +void microtouch_device::send_format_table_packet(UINT8 flag, int x, int y) +{ + m_tx_buffer[m_tx_buffer_num++] = flag; + // lower byte (7bits) of x coordinate + m_tx_buffer[m_tx_buffer_num++] = x & 0x7f; + // higher byte (7bits) of x coordinate + m_tx_buffer[m_tx_buffer_num++] = (x >> 7) & 0x7f; + // lower byte (7bits) of y coordinate + m_tx_buffer[m_tx_buffer_num++] = y & 0x7f; + // higher byte (7bits) of y coordinate + m_tx_buffer[m_tx_buffer_num++] = (y >> 7) & 0x7f; +} + +void microtouch_device::send_format_decimal_packet(int x, int y) +{ + int decx, decy; + + decx = x / 16; + if ( decx > 999 ) + decx = 999; + decy = y / 16; + if ( decy > 999 ) + decy = 999; + + // header byte + m_tx_buffer[m_tx_buffer_num++] = 0x01; + // x coordinate in decimal mode + m_tx_buffer[m_tx_buffer_num++] = (decx / 100) + '0'; + m_tx_buffer[m_tx_buffer_num++] = ((decx / 10) % 10) + '0'; + m_tx_buffer[m_tx_buffer_num++] = (decx % 10) + '0'; + // comma (separator) + m_tx_buffer[m_tx_buffer_num++] = ','; + // y coordinate in decimal mode + m_tx_buffer[m_tx_buffer_num++] = (decy / 100) + '0'; + m_tx_buffer[m_tx_buffer_num++] = ((decy / 10) % 10) + '0'; + m_tx_buffer[m_tx_buffer_num++] = (decy % 10) + '0'; + // terminator + m_tx_buffer[m_tx_buffer_num++] = 0x0d; +} + +void microtouch_device::send_touch_packet() +{ + int tx = m_touchx->read(); + int ty = m_touchy->read(); + + if ( m_out_touch_cb.isnull() || + m_out_touch_cb( &tx, &ty ) != 0 ) + { + ty = 0x4000 - ty; + + switch( m_format ) + { + case FORMAT_TABLET: + send_format_table_packet(0xc8, tx, ty); + break; + case FORMAT_DECIMAL: + send_format_decimal_packet(tx, ty); + break; + case FORMAT_UNKNOWN: + break; + } + m_last_touch_state = 1; + m_last_x = tx; + m_last_y = ty; + } +} + +void microtouch_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + if(id) + { + device_serial_interface::device_timer(timer, id, param, ptr); + return; + } + + if ( m_tx_buffer_ptr < m_tx_buffer_num ) + { + m_output = m_tx_buffer[m_tx_buffer_ptr++]; + m_output_valid = true; + if(is_transmit_register_empty()) + tra_complete(); + + if ( m_tx_buffer_ptr == m_tx_buffer_num ) + { + m_tx_buffer_ptr = m_tx_buffer_num = 0; + } + return; + } + + if ( (m_reset_done == 0) || + (m_format == FORMAT_UNKNOWN) || + (m_mode != MODE_STREAM)) + { + return; + } + + // send format tablet packet + if (m_touch->read()) + { + send_touch_packet(); + } + else + { + if ( m_last_touch_state == 1 ) + { + m_last_touch_state = 0; + switch( m_format ) + { + case FORMAT_TABLET: + send_format_table_packet(0x88, m_last_x, m_last_y); + break; + case FORMAT_DECIMAL: + send_format_decimal_packet(m_last_x, m_last_y); + break; + case FORMAT_UNKNOWN: + break; + } + } + } +} + +void microtouch_device::device_start() +{ + memset(m_rx_buffer, 0, sizeof(m_rx_buffer)); + memset(m_tx_buffer, 0, sizeof(m_tx_buffer)); + m_rx_buffer_ptr = 0; + m_tx_buffer_ptr = 0; + m_tx_buffer_num = 0; + m_reset_done = 0; + m_format = 0; + m_mode = 0; + m_last_x = 0; + m_last_y = 0; + m_last_touch_state = -1; + + m_timer = timer_alloc(); + m_timer->adjust(attotime::from_hz(167*5), 0, attotime::from_hz(167*5)); + + m_format = FORMAT_UNKNOWN; + m_mode = MODE_INACTIVE; + + save_item(NAME(m_reset_done)); + save_item(NAME(m_last_touch_state)); + save_item(NAME(m_last_x)); + save_item(NAME(m_last_y)); + save_item(NAME(m_rx_buffer)); + save_item(NAME(m_rx_buffer_ptr)); + save_item(NAME(m_tx_buffer)); + save_item(NAME(m_tx_buffer_num)); + save_item(NAME(m_tx_buffer_ptr)); + save_item(NAME(m_format)); + save_item(NAME(m_mode)); + set_data_frame(1, 8, PARITY_NONE, STOP_BITS_1); //8N1? + set_tra_rate(clock()); + set_rcv_rate(clock()); + m_out_stx_func.resolve_safe(); + m_output_valid = false; + + save_item(NAME(m_output_valid)); + save_item(NAME(m_output)); +} + + +void microtouch_device::rcv_complete() +{ + receive_register_extract(); + m_rx_buffer[m_rx_buffer_ptr] = get_received_char(); + m_rx_buffer_ptr++; + if(m_rx_buffer_ptr == 16) + return; + + if (m_rx_buffer_ptr > 0 && (m_rx_buffer[m_rx_buffer_ptr-1] == 0x0d)) + { + if (LOG) + { + char command[16]; + memset(command, 0, sizeof(command)); + strncpy( command, (const char*)m_rx_buffer + 1, m_rx_buffer_ptr - 2 ); + logerror("Microtouch: received command %s\n", command); + } + // check command + if ( check_command( "MS", m_rx_buffer_ptr, m_rx_buffer ) ) + { + m_mode = MODE_STREAM; + } + else if ( check_command( "MI", m_rx_buffer_ptr, m_rx_buffer ) ) + { + m_mode = MODE_INACTIVE; + } + else if ( check_command( "MP", m_rx_buffer_ptr, m_rx_buffer ) ) + { + m_mode = MODE_POINT; + } + else if ( check_command( "R", m_rx_buffer_ptr, m_rx_buffer ) ) + { + m_tx_buffer_num = 0; + m_reset_done = 1; + } + else if ( check_command( "FT", m_rx_buffer_ptr, m_rx_buffer ) ) + { + m_format = FORMAT_TABLET; + } + else if ( check_command( "FD", m_rx_buffer_ptr, m_rx_buffer ) ) + { + m_format = FORMAT_DECIMAL; + } + else if ( check_command("OI", m_rx_buffer_ptr, m_rx_buffer ) ) + { + // output identity - SMT3, ver 01.00 + m_tx_buffer[m_tx_buffer_num++] = 0x01; + m_tx_buffer[m_tx_buffer_num++] = 'Q'; + m_tx_buffer[m_tx_buffer_num++] = '1'; + m_tx_buffer[m_tx_buffer_num++] = '0'; + m_tx_buffer[m_tx_buffer_num++] = '1'; + m_tx_buffer[m_tx_buffer_num++] = '0'; + m_tx_buffer[m_tx_buffer_num++] = '0'; + m_tx_buffer[m_tx_buffer_num++] = 0x0d; + m_rx_buffer_ptr = 0; + return; + } + // send response + m_tx_buffer[m_tx_buffer_num++] = 0x01; + m_tx_buffer[m_tx_buffer_num++] = 0x30; + m_tx_buffer[m_tx_buffer_num++] = 0x0d; + m_rx_buffer_ptr = 0; + } +} + +INPUT_CHANGED_MEMBER( microtouch_device::touch ) +{ + if ( newval && ( m_mode == MODE_POINT ) ) + { + send_touch_packet(); + } +} + +static INPUT_PORTS_START(microtouch) + PORT_START("TOUCH") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME( "Touch screen" ) PORT_CHANGED_MEMBER( DEVICE_SELF,microtouch_device, touch, 0 ) + PORT_START("TOUCH_X") + PORT_BIT( 0x3fff, 0x2000, IPT_LIGHTGUN_X ) PORT_CROSSHAIR(X, 1.0, 0.0, 0) PORT_SENSITIVITY(45) PORT_KEYDELTA(15) + PORT_START("TOUCH_Y") + PORT_BIT( 0x3fff, 0x2000, IPT_LIGHTGUN_Y ) PORT_CROSSHAIR(Y, 1.0, 0.0, 0) PORT_SENSITIVITY(45) PORT_KEYDELTA(15) +INPUT_PORTS_END + +ioport_constructor microtouch_device::device_input_ports() const +{ + return INPUT_PORTS_NAME(microtouch); +} + +void microtouch_device::tra_callback() +{ + m_out_stx_func(transmit_register_get_data_bit()); +} + +void microtouch_device::tra_complete() +{ + if(m_output_valid) + { + transmit_register_setup(m_output); + m_output_valid = false; + } +} diff --git a/src/devices/machine/microtch.h b/src/devices/machine/microtch.h new file mode 100644 index 00000000000..c7ba5a3c00b --- /dev/null +++ b/src/devices/machine/microtch.h @@ -0,0 +1,79 @@ +// license:BSD-3-Clause +// copyright-holders:Mariusz Wojcieszek +#ifndef _MICROTOUCH_H +#define _MICROTOUCH_H + +#include "emu.h" + + +class microtouch_device : + public device_t, + public device_serial_interface +{ +public: + microtouch_device(const machine_config &mconfig, device_type type, const char* name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + microtouch_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + template static devcb_base &static_set_stx_callback(device_t &device, _Object object) { return downcast(device).m_out_stx_func.set_callback(object); } + + virtual ioport_constructor device_input_ports() const; + DECLARE_WRITE_LINE_MEMBER(rx) { device_serial_interface::rx_w(state); } + DECLARE_INPUT_CHANGED_MEMBER(touch); + + typedef delegate touch_cb; + static void static_set_touch_callback(device_t &device, touch_cb object) { downcast(device).m_out_touch_cb = object; } +protected: + virtual void device_start(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + virtual void tra_callback(); + virtual void tra_complete(); + virtual void rcv_complete(); +private: + int check_command( const char* commandtocheck, int command_len, UINT8* command_data ); + void send_format_table_packet(UINT8 flag, int x, int y); + void send_format_decimal_packet(int x, int y); + void send_touch_packet(); + + enum + { + FORMAT_UNKNOWN, + FORMAT_TABLET, + FORMAT_DECIMAL + }; + enum + { + MODE_INACTIVE, + MODE_STREAM, + MODE_POINT + }; + UINT8 m_rx_buffer[16]; + int m_rx_buffer_ptr; + UINT8 m_tx_buffer[16]; + UINT8 m_tx_buffer_num; + UINT8 m_tx_buffer_ptr; + int m_reset_done; + int m_format; + int m_mode; + int m_last_touch_state; + int m_last_x; + int m_last_y; + touch_cb m_out_touch_cb; + devcb_write_line m_out_stx_func; + required_ioport m_touch; + required_ioport m_touchx; + required_ioport m_touchy; + emu_timer* m_timer; + bool m_output_valid; + UINT8 m_output; +}; + +extern const device_type MICROTOUCH; + +#define MCFG_MICROTOUCH_ADD(_tag, _clock, _devcb) \ + MCFG_DEVICE_ADD(_tag, MICROTOUCH, _clock) \ + devcb = µtouch_device::static_set_stx_callback(*device, DEVCB_##_devcb); + +#define MCFG_MICROTOUCH_TOUCH_CB(_class, _touch_cb) \ + microtouch_device::static_set_touch_callback(*device, microtouch_device::touch_cb(FUNC(_class::_touch_cb), (_class *)owner)); + + +#endif //_MICROTOUCH_H diff --git a/src/devices/machine/mm58167.c b/src/devices/machine/mm58167.c new file mode 100644 index 00000000000..74572770710 --- /dev/null +++ b/src/devices/machine/mm58167.c @@ -0,0 +1,261 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/********************************************************************** + + mm58167.c - National Semiconductor MM58167 real-time clock emulation + + TODO: standby interrupt + +**********************************************************************/ + +#include "mm58167.h" + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +// device type definition +const device_type MM58167 = &device_creator; + +// registers (0-7 are the live data, 8-f are the setting for the compare IRQ) +typedef enum +{ + R_CNT_MILLISECONDS = 0, // 0 = milliseconds + R_CNT_HUNDTENTHS, // 1 = hundreds and tenths of seconds + R_CNT_SECONDS, // 2 = seconds + R_CNT_MINUTES, // 3 = minutes + R_CNT_HOURS, // 4 = hours + R_CNT_DAYOFWEEK, // 5 = day of the week + R_CNT_DAYOFMONTH, // 6 = day of the month + R_CNT_MONTH, // 7 = month + R_RAM_MILLISECONDS, // 8 = milliseconds + R_RAM_HUNDTENTHS, // 9 = hundreds and tenths of seconds + R_RAM_SECONDS, // a = seconds + R_RAM_MINUTES, // b = minutes + R_RAM_HOURS, // c = hours + R_RAM_DAYOFWEEK, // d = day of the week + R_RAM_DAYOFMONTH, // e = day of the month + R_RAM_MONTH, // f = month + R_CTL_IRQSTATUS, // 10 = IRQ status (b7 = compare, b6 = 10th sec, b5 = sec, b4 = min, b3 = hour, b2 = day, b1 = week, b0 = month) + R_CTL_IRQCONTROL, // 11 = IRQ control (same bit layout as status, but write here to enable/disable/clear) + R_CTL_RESETCOUNTERS, // 12 = reset counters + R_CTL_RESETRAM, // 13 = reset RAM + R_CTL_STATUS, // 14 = status bit + R_CTL_GOCMD, // 15 = GO Command + R_CTL_STANDBYIRQ, // 16 = standby IRQ + R_CTL_TESTMODE // 17 = test mode +} mm58167_regs_t; + +//------------------------------------------------- +// mm58167_device - constructor +//------------------------------------------------- + +mm58167_device::mm58167_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, MM58167, "National Semiconductor MM58167", tag, owner, clock, "mm58167", __FILE__), + device_rtc_interface(mconfig, *this), + m_irq_w(*this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void mm58167_device::device_start() +{ + // allocate timers + m_clock_timer = timer_alloc(); + m_clock_timer->adjust(attotime::from_hz(clock() / 32.768f), 0, attotime::from_hz(clock() / 32.768f)); + + m_irq_w.resolve_safe(); + + // state saving + save_item(NAME(m_regs)); + save_item(NAME(m_milliseconds)); + save_item(NAME(m_comparator_state)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void mm58167_device::device_reset() +{ + set_current_time(machine()); + + m_regs[R_CTL_STATUS] = 0; // not busy + m_regs[R_CTL_IRQSTATUS] = 0; + m_regs[R_CTL_IRQCONTROL] = 0; + m_milliseconds = 0; + m_comparator_state = false; +} + + +INLINE UINT8 make_bcd(UINT8 data) +{ + return ((data / 10) << 4) | (data % 10); +} + +//------------------------------------------------- +// device_timer - handler timer events +//------------------------------------------------- + +void mm58167_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + m_milliseconds++; + + if (m_milliseconds >= 999) + { + int old_seconds = m_regs[R_CNT_SECONDS]; + int old_minutes = m_regs[R_CNT_MINUTES]; + int old_hours = m_regs[R_CNT_HOURS]; + int old_dayofmonth = m_regs[R_CNT_DAYOFMONTH]; + int old_dayofweek = m_regs[R_CNT_DAYOFWEEK]; + int old_month = m_regs[R_CNT_MONTH]; + + advance_seconds(); + m_milliseconds = 0; + + if ((m_regs[R_CTL_IRQCONTROL] & 0x04) && m_regs[R_CNT_SECONDS] != old_seconds) set_irq(2); // every second + if ((m_regs[R_CTL_IRQCONTROL] & 0x08) && m_regs[R_CNT_MINUTES] != old_minutes) set_irq(3); // every minute + if ((m_regs[R_CTL_IRQCONTROL] & 0x10) && m_regs[R_CNT_HOURS] != old_hours) set_irq(4); // every hour + if ((m_regs[R_CTL_IRQCONTROL] & 0x20) && m_regs[R_CNT_DAYOFMONTH] != old_dayofmonth) set_irq(5); // every day + if ((m_regs[R_CTL_IRQCONTROL] & 0x40) && m_regs[R_CNT_DAYOFWEEK] < old_dayofweek) set_irq(6); // every week + if ((m_regs[R_CTL_IRQCONTROL] & 0x80) && m_regs[R_CNT_MONTH] != old_month) set_irq(7); // every month + } + + m_regs[R_CNT_MILLISECONDS] = make_bcd(m_milliseconds % 10); + m_regs[R_CNT_HUNDTENTHS] = make_bcd(m_milliseconds / 10); + + // 10Hz IRQ + if ((m_regs[R_CTL_IRQCONTROL] & 0x02) && (m_milliseconds % 100) == 0) + set_irq(1); + + // comparator IRQ + bool new_state = true; + for (int i = R_CNT_MILLISECONDS; i <= R_CNT_MONTH; i++) + { + // nibbles that have the 2 MSB set always compares true + // Milliseconds use only the high nibble and Day of Week only the low nibble + if ((i != R_CNT_MILLISECONDS && (m_regs[i + 8] & 0x0c) != 0x0c && (m_regs[i + 8] & 0x0f) != (m_regs[i] & 0x0f)) || + (i != R_CNT_DAYOFWEEK && (m_regs[i + 8] & 0xc0) != 0xc0 && (m_regs[i + 8] & 0xf0) != (m_regs[i] & 0xf0))) + { + new_state = false; + break; + } + } + + if ((m_regs[R_CTL_IRQCONTROL] & 0x01) && !m_comparator_state && new_state) // positive-edge-triggered + set_irq(0); + + m_comparator_state = new_state; +} + + +//------------------------------------------------- +// rtc_clock_updated - +//------------------------------------------------- + +void mm58167_device::rtc_clock_updated(int year, int month, int day, int day_of_week, int hour, int minute, int second) +{ + m_regs[R_CNT_SECONDS] = make_bcd(second); // seconds (BCD) + m_regs[R_CNT_MINUTES] = make_bcd(minute); // minutes (BCD) + m_regs[R_CNT_HOURS] = make_bcd(hour); // hour (BCD) + m_regs[R_CNT_DAYOFWEEK] = make_bcd(day_of_week); // day of the week (BCD) + m_regs[R_CNT_DAYOFMONTH] = make_bcd(day); // day of the month (BCD) + m_regs[R_CNT_MONTH] = make_bcd(month); // month (BCD) +} + +void mm58167_device::set_irq(int bit) +{ + m_regs[R_CTL_IRQSTATUS] |= (1 << bit); + m_irq_w(ASSERT_LINE); +} + +void mm58167_device::update_rtc() +{ + set_clock_register(RTC_SECOND, bcd_to_integer(m_regs[R_CNT_SECONDS])); + set_clock_register(RTC_MINUTE, bcd_to_integer(m_regs[R_CNT_MINUTES])); + set_clock_register(RTC_HOUR, bcd_to_integer(m_regs[R_CNT_HOURS])); + set_clock_register(RTC_DAY, bcd_to_integer(m_regs[R_CNT_DAYOFMONTH])); + set_clock_register(RTC_DAY_OF_WEEK, bcd_to_integer(m_regs[R_CNT_DAYOFWEEK])); + set_clock_register(RTC_MONTH, bcd_to_integer(m_regs[R_CNT_MONTH])); + m_milliseconds = (bcd_to_integer(m_regs[R_CNT_HUNDTENTHS]) * 10) + (bcd_to_integer(m_regs[R_CNT_MILLISECONDS] >> 4) % 10); +} + +READ8_MEMBER(mm58167_device::read) +{ +// printf("read reg %x = %02x\n", offset, m_regs[offset]); + + if (offset == R_CTL_IRQSTATUS && !space.debugger_access()) + { + // reading the IRQ status clears IRQ line and IRQ status + UINT8 data = m_regs[offset]; + m_regs[R_CTL_IRQSTATUS] = 0; + m_irq_w(CLEAR_LINE); + return data; + } + + return m_regs[offset]; +} + +WRITE8_MEMBER(mm58167_device::write) +{ +// printf("%02x to reg %x\n", data, offset); + + if ((offset >= R_RAM_MILLISECONDS) && (offset != R_CTL_IRQSTATUS)) + { + m_regs[offset] = data; + } + + switch (offset) + { + case R_CNT_MILLISECONDS: + case R_CNT_HUNDTENTHS: + case R_CNT_SECONDS: + case R_CNT_MINUTES: + case R_CNT_HOURS: + case R_CNT_DAYOFWEEK: + case R_CNT_DAYOFMONTH: + case R_CNT_MONTH: + m_regs[offset] = data; + update_rtc(); + break; + + // any write to this starts at the current time and zero milliseconds + case R_CTL_GOCMD: + m_milliseconds = 0; + break; + + case R_CTL_RESETCOUNTERS: + if (data == 0xff) + { + for (int i = R_CNT_MILLISECONDS; i <= R_CNT_MONTH; i++) + { + m_regs[i] = 0; + } + + update_rtc(); + } + break; + + case R_CTL_RESETRAM: + if (data == 0xff) + { + for (int i = R_RAM_MILLISECONDS; i < R_CTL_IRQSTATUS; i++) + { + m_regs[i] = 0; + } + } + break; + + case R_CTL_IRQCONTROL: + if (data != 0) + { + logerror("MM58167: IRQs not implemented\n"); + } + break; + } +} diff --git a/src/devices/machine/mm58167.h b/src/devices/machine/mm58167.h new file mode 100644 index 00000000000..83714042433 --- /dev/null +++ b/src/devices/machine/mm58167.h @@ -0,0 +1,70 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/********************************************************************** + + mm58167.h - National Semiconductor MM58167 real-time clock emulation + +**********************************************************************/ + +#pragma once + +#ifndef __MM58167_H__ +#define __MM58167_H__ + +#include "emu.h" + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_MM58167_IRQ_CALLBACK(_cb) \ + devcb = &mm58167_device::set_irq_cb(*device, DEVCB_##_cb); + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> mm58167_device + +class mm58167_device : public device_t, + public device_rtc_interface +{ +public: + // construction/destruction + mm58167_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + DECLARE_READ8_MEMBER(read); + DECLARE_WRITE8_MEMBER(write); + + template static devcb_base &set_irq_cb(device_t &device, _Object wr) { return downcast(device).m_irq_w.set_callback(wr); } + + devcb_write_line m_irq_w; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + // device_rtc_interface overrides + virtual void rtc_clock_updated(int year, int month, int day, int day_of_week, int hour, int minute, int second); + virtual bool rtc_feature_leap_year() { return true; } + + void set_irq(int bit); + void update_rtc(); + +private: + int m_regs[32]; + int m_milliseconds; + bool m_comparator_state; + + // timers + emu_timer *m_clock_timer; +}; + +// device type definition +extern const device_type MM58167; + +#endif diff --git a/src/devices/machine/mm58274c.c b/src/devices/machine/mm58274c.c new file mode 100644 index 00000000000..0690f775b5d --- /dev/null +++ b/src/devices/machine/mm58274c.c @@ -0,0 +1,470 @@ +// license:BSD-3-Clause +// copyright-holders:Raphael Nabet +/*************************************************************************** + + mm58274c.c + + mm58274c emulation + + Reference: + * National Semiconductor MM58274C Microprocessor Compatible Real Time Clock + + + Todo: + * Clock initialization will only work with the BwG: we need to provide + a way to customize it. + * Save the config to NVRAM? + * Support interrupt pin output + + Raphael Nabet, 2002 + +***************************************************************************/ + +#include "emu.h" +#include "machine/mm58274c.h" + +enum +{ + st_dcf = 0x8, /* data-changed flag */ + st_if = 0x1, /* interrupt flag */ + + ctl_test = 0x8, /* test mode (0=normal, 1=test) (not emulated) */ + ctl_clkstop = 0x4, /* clock start/stop (0=run, 1=stop) */ + ctl_intsel = 0x2, /* interrupt select (0=clock setting register, 1=interrupt register) */ + ctl_intstop = 0x1, /* interrupt start stop (0=interrupt run, 1=interrupt stop) */ + + clk_set_leap = 0xc, /* leap year counter (0 indicates a leap year) */ + clk_set_leap_inc = 0x4, /* leap year increment */ + clk_set_pm = 0x2, /* am/pm indicator (0 = am, 1 = pm, 0 in 24-hour mode) */ + clk_set_24 = 0x1, /* 12/24-hour select bit (1= 24-hour mode) */ + + int_ctl_rpt = 0x8, /* 1 for repeated interrupt */ + int_ctl_dly = 0x7 /* 0 no interrupt, 1 = .1 second, 2=.5, 3=1, 4=5, 5=10, 6=30, 7=60 */ +}; + + + +const device_type MM58274C = &device_creator; + + +mm58274c_device::mm58274c_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, MM58274C, "National Semiconductor MM58274C", tag, owner, clock, "mm58274c", __FILE__), + m_mode24(0), + m_day1(0) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void mm58274c_device::device_start() +{ + m_increment_rtc = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(mm58274c_device::rtc_increment_cb),this)); + m_increment_rtc->adjust(attotime::zero, 0, attotime::from_msec(100)); + m_interrupt_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(mm58274c_device::rtc_interrupt_cb),this)); + + // register for state saving + save_item(NAME(m_status)); + save_item(NAME(m_control)); + save_item(NAME(m_clk_set)); + save_item(NAME(m_int_ctl)); + save_item(NAME(m_wday)); + save_item(NAME(m_years1)); + save_item(NAME(m_years2)); + save_item(NAME(m_months1)); + save_item(NAME(m_months2)); + save_item(NAME(m_days1)); + save_item(NAME(m_days2)); + save_item(NAME(m_hours1)); + save_item(NAME(m_hours2)); + save_item(NAME(m_minutes1)); + save_item(NAME(m_minutes2)); + save_item(NAME(m_seconds1)); + save_item(NAME(m_seconds2)); + save_item(NAME(m_tenths)); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void mm58274c_device::device_reset() +{ + system_time systime; + + /* get the current date/time from the core */ + machine().current_datetime(systime); + + m_clk_set = systime.local_time.year & 3 << 2; + if (m_mode24) + m_clk_set |= clk_set_24; + + /* The clock count starts on 1st January 1900 */ + m_wday = 1 + ((systime.local_time.weekday - m_day1) % 7); + m_years1 = (systime.local_time.year / 10) % 10; + m_years2 = systime.local_time.year % 10; + m_months1 = (systime.local_time.month + 1) / 10; + m_months2 = (systime.local_time.month + 1) % 10; + m_days1 = systime.local_time.mday / 10; + m_days2 = systime.local_time.mday % 10; + if (!m_mode24) + { + /* 12-hour mode */ + if (systime.local_time.hour > 12) + { + systime.local_time.hour -= 12; + m_clk_set |= clk_set_pm; + } + if (systime.local_time.hour == 0) + systime.local_time.hour = 12; + } + m_hours1 = systime.local_time.hour / 10; + m_hours2 = systime.local_time.hour % 10; + m_minutes1 = systime.local_time.minute / 10; + m_minutes2 = systime.local_time.minute % 10; + m_seconds1 = systime.local_time.second / 10; + m_seconds2 = systime.local_time.second % 10; + m_tenths = 0; + m_status = 0; + m_control = 0; +} + + + +attotime mm58274c_device::interrupt_period_table(int val) +{ + switch(val) + { + case 0: return attotime::from_msec(0); + case 1: return attotime::from_msec(100); + case 2: return attotime::from_msec(500); + case 3: return attotime::from_seconds(1); + case 4: return attotime::from_seconds(5); + case 5: return attotime::from_seconds(10); + case 6: return attotime::from_seconds(30); + case 7: return attotime::from_seconds(60); + default: fatalerror("out of range\n"); + } +} + +READ8_MEMBER( mm58274c_device::read ) +{ + int reply; + + offset &= 0xf; + + switch (offset) + { + case 0x00: /* Control Register */ + reply = m_status; + m_status = 0; + break; + + case 0x01: /* Tenths of Seconds */ + reply = m_tenths; + break; + + case 0x02: /* Units Seconds */ + reply = m_seconds2; + break; + + case 0x03: /* Tens Seconds */ + reply = m_seconds1; + break; + + case 0x04: /* Units Minutes */ + reply = m_minutes2; + break; + + case 0x05: /* Tens Minutes */ + reply = m_minutes1; + break; + + case 0x06: /* Units Hours */ + reply = m_hours2; + break; + + case 0x07: /* Tens Hours */ + reply = m_hours1; + break; + + case 0x08: /* Units Days */ + reply = m_days2; + break; + + case 0x09: /* Tens Days */ + reply = m_days1; + break; + + case 0x0a: /* Units Months */ + reply = m_months2; + break; + + case 0x0b: /* Tens Months */ + reply = m_months1; + break; + + case 0x0c: /* Units Years */ + reply = m_years2; + break; + + case 0x0d: /* Tens Years */ + reply = m_years1; + break; + + case 0x0e: /* Day of Week */ + reply = m_wday; + break; + + case 0x0f: /* Clock Setting & Interrupt Registers */ + if (m_control & ctl_intsel) /* interrupt register */ + reply = m_int_ctl; + else /* clock setting register */ + { + if (m_clk_set & clk_set_24) /* 24-hour mode */ + reply = m_clk_set & ~clk_set_pm; + else /* 12-hour mode */ + reply = m_clk_set; + } + break; + + default: + reply = 0; + break; + } + + return reply; +} + + +WRITE8_MEMBER( mm58274c_device::write ) +{ + offset &= 0xf; + data &= 0xf; + + switch (offset) + { + case 0x00: /* Control Register (test mode and interrupt not emulated) */ + if ((!(m_control & ctl_intstop)) && (data & ctl_intstop)) /* interrupt stop */ + m_interrupt_timer->enable(0); + else if ((m_control & ctl_intstop) && (!(data & ctl_intstop))) /* interrupt run */ + { + attotime period = interrupt_period_table(m_int_ctl & int_ctl_dly); + + m_interrupt_timer->adjust(period, 0, m_int_ctl & int_ctl_rpt ? period : attotime::zero); + } + if (data & ctl_clkstop) /* stopping the clock clears the tenth counter */ + m_tenths = 0; + m_control = data; + break; + + case 0x01: /* Tenths of Seconds: cannot be written */ + break; + + case 0x02: /* Units Seconds */ + m_seconds2 = data; + break; + + case 0x03: /* Tens Seconds */ + m_seconds1 = data; + break; + + case 0x04: /* Units Minutes */ + m_minutes2 = data; + break; + + case 0x05: /* Tens Minutes */ + m_minutes1 = data; + break; + + case 0x06: /* Units Hours */ + m_hours2 = data; + break; + + case 0x07: /* Tens Hours */ + m_hours1 = data; + break; + + case 0x08: /* Units Days */ + m_days2 = data; + break; + + case 0x09: /* Tens Days */ + m_days1 = data; + break; + + case 0x0a: /* Units Months */ + m_months2 = data; + break; + + case 0x0b: /* Tens Months */ + m_months1 = data; + break; + + case 0x0c: /* Units Years */ + m_years2 = data; + break; + + case 0x0d: /* Tens Years */ + m_years1 = data; + break; + + case 0x0e: /* Day of Week */ + m_wday = data; + break; + + case 0x0f: /* Clock Setting & Interrupt Registers */ + if (m_control & ctl_intsel) /* interrupt register (not emulated) */ + { + m_int_ctl = data; + if (!(m_control & ctl_intstop)) /* interrupt run */ + { + attotime period = interrupt_period_table(m_int_ctl & int_ctl_dly); + + m_interrupt_timer->adjust(period, 0, m_int_ctl & int_ctl_rpt ? period : attotime::zero); + } + } + else /* clock setting register */ + { + m_clk_set = data; +#if 0 + if (m_clk_set & clk_set_24) /* 24-hour mode */ + m_clk_set &= ~clk_set_pm; +#endif + } + break; + } +} + + +// Set RTC interrupt flag +TIMER_CALLBACK_MEMBER(mm58274c_device::rtc_interrupt_cb) +{ + m_status |= st_if; +} + + +// Increment RTC clock (timed interrupt every 1/10s) +TIMER_CALLBACK_MEMBER(mm58274c_device::rtc_increment_cb) +{ + if (!(m_control & ctl_clkstop)) + { + m_status |= st_dcf; + + if ((++m_tenths) == 10) + { + m_tenths = 0; + + if ((++m_seconds2) == 10) + { + m_seconds2 = 0; + + if ((++m_seconds1) == 6) + { + m_seconds1 = 0; + + if ((++m_minutes2) == 10) + { + m_minutes2 = 0; + + if ((++m_minutes1) == 6) + { + m_minutes1 = 0; + + if ((++m_hours2) == 10) + { + m_hours2 = 0; + + m_hours1++; + } + + /* handle wrap-around */ + if ((!(m_clk_set & clk_set_24)) + && ((m_hours1*10 + m_hours2) == 12)) + { + m_clk_set ^= clk_set_pm; + } + if ((!(m_clk_set & clk_set_24)) + && ((m_hours1*10 + m_hours2) == 13)) + { + m_hours1 = 0; + m_hours2 = 1; + } + + if ((m_clk_set & clk_set_24) + && ((m_hours1*10 + m_hours2) == 24)) + { + m_hours1 = m_hours2 = 0; + } + + /* increment day if needed */ + if ((m_clk_set & clk_set_24) + ? ((m_hours1*10 + m_hours2) == 0) + : (((m_hours1*10 + m_hours2) == 12) + && (!(m_clk_set & clk_set_pm)))) + { + int days_in_month; + + if ((++m_days2) == 10) + { + m_days2 = 0; + + m_days1++; + } + + if ((++m_wday) == 8) + m_wday = 1; + + { + static const int days_in_month_array[] = + { + 31,28,31, 30,31,30, + 31,31,30, 31,30,31 + }; + + if (((m_months1*10 + m_months2) != 2) || (m_clk_set & clk_set_leap)) + days_in_month = days_in_month_array[m_months1*10 + m_months2 - 1]; + else + days_in_month = 29; + } + + + if ((m_days1*10 + m_days2) == days_in_month+1) + { + m_days1 = 0; + m_days2 = 1; + + if ((++m_months2) == 10) + { + m_months2 = 0; + + m_months1++; + } + + if ((m_months1*10 + m_months2) == 13) + { + m_months1 = 0; + m_months2 = 1; + + m_clk_set = (m_clk_set & ~clk_set_leap) + | ((m_clk_set + clk_set_leap_inc) & clk_set_leap); + + if ((++m_years2) == 10) + { + m_years2 = 0; + + if ((++m_years1) == 10) + m_years1 = 0; + } + } + } + } + } + } + } + } + } + } +} diff --git a/src/devices/machine/mm58274c.h b/src/devices/machine/mm58274c.h new file mode 100644 index 00000000000..225340721ea --- /dev/null +++ b/src/devices/machine/mm58274c.h @@ -0,0 +1,81 @@ +// license:BSD-3-Clause +// copyright-holders:Raphael Nabet +#ifndef __MM58274C_H__ +#define __MM58274C_H__ + +/*************************************************************************** + MACROS +***************************************************************************/ + +class mm58274c_device : public device_t +{ +public: + mm58274c_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + ~mm58274c_device() {} + + static void set_mode24(device_t &device, int mode) { downcast(device).m_mode24 = mode; } + static void set_day1(device_t &device, int day) { downcast(device).m_day1 = day; } + + DECLARE_READ8_MEMBER(read); + DECLARE_WRITE8_MEMBER(write); + + TIMER_CALLBACK_MEMBER(rtc_increment_cb); + TIMER_CALLBACK_MEMBER(rtc_interrupt_cb); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + +private: + // internal state + + // Initializion the clock chip: + // m_day1 must be set to a value from 0 (sunday), 1 (monday)... + // to 6 (saturday) and is needed to correctly retrieve the + // day-of-week from the host system clock. + int m_mode24; /* 24/12 mode */ + int m_day1; /* first day of week */ + + attotime interrupt_period_table(int val); + + int m_status; /* status register (*read* from address 0 = control register) */ + int m_control; /* control register (*write* to address 0) */ + + int m_clk_set; /* clock setting register */ + int m_int_ctl; /* interrupt control register */ + + int m_wday; /* day of the week (1-7 (1=day1 as set in init)) */ + int m_years1; /* years (BCD: 0-99) */ + int m_years2; + int m_months1; /* months (BCD: 1-12) */ + int m_months2; + int m_days1; /* days (BCD: 1-31) */ + int m_days2; + int m_hours1; /* hours (BCD : 0-23) */ + int m_hours2; + int m_minutes1; /* minutes (BCD : 0-59) */ + int m_minutes2; + int m_seconds1; /* seconds (BCD : 0-59) */ + int m_seconds2; + int m_tenths; /* tenths of second (BCD : 0-9) */ + + emu_timer *m_increment_rtc; + emu_timer *m_interrupt_timer; +}; + +extern const device_type MM58274C; + + +/*************************************************************************** + DEVICE CONFIGURATION MACROS +***************************************************************************/ + +#define MCFG_MM58274C_MODE24(_mode) \ + mm58274c_device::set_mode24(*device, _mode); + +#define MCFG_MM58274C_DAY1(_day) \ + mm58274c_device::set_day1(*device, _day); + + +#endif diff --git a/src/devices/machine/mm74c922.c b/src/devices/machine/mm74c922.c new file mode 100644 index 00000000000..6b7f9b50d53 --- /dev/null +++ b/src/devices/machine/mm74c922.c @@ -0,0 +1,190 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + MM74C922/MM74C923 16/20-Key Encoder emulation + +**********************************************************************/ + +#include "mm74c922.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define LOG 1 + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type MM74C922 = &device_creator; +const device_type MM74C923 = &device_creator; + + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// mm74c922_device - constructor +//------------------------------------------------- + +mm74c922_device::mm74c922_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, MM74C922, "MM74C922", tag, owner, clock, "mm74c922", __FILE__), + m_write_da(*this), + m_read_x1(*this), + m_read_x2(*this), + m_read_x3(*this), + m_read_x4(*this), + m_read_x5(*this), + m_max_y(5), // TODO 4 for 74C922, 5 for 74C923 + m_inhibit(0), + m_x(0), + m_y(0), + m_da(0), + m_next_da(0) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void mm74c922_device::device_start() +{ + // resolve callbacks + m_write_da.resolve_safe(); + m_read_x1.resolve_safe(0); + m_read_x2.resolve_safe(0); + m_read_x3.resolve_safe(0); + m_read_x4.resolve_safe(0); + m_read_x5.resolve_safe(0); + + // set initial values + change_output_lines(); + + // allocate timers + m_scan_timer = timer_alloc(); + m_scan_timer->adjust(attotime::zero, 0, attotime::from_hz(50)); + + // register for state saving + save_item(NAME(m_inhibit)); + save_item(NAME(m_x)); + save_item(NAME(m_y)); + save_item(NAME(m_data)); + save_item(NAME(m_da)); + save_item(NAME(m_next_da)); +} + + +//------------------------------------------------- +// device_timer - handler timer events +//------------------------------------------------- + +void mm74c922_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + change_output_lines(); + clock_scan_counters(); + detect_keypress(); +} + + +//------------------------------------------------- +// read - +//------------------------------------------------- + +UINT8 mm74c922_device::read() +{ + if (LOG) logerror("MM74C922 '%s' Data Read: %02x\n", tag(), m_data); + + return m_data; +} + + +//------------------------------------------------- +// change_output_lines - +//------------------------------------------------- + +void mm74c922_device::change_output_lines() +{ + if (m_next_da != m_da) + { + m_da = m_next_da; + + if (LOG) logerror("MM74C922 '%s' Data Available: %u\n", tag(), m_da); + + m_write_da(m_da); + } +} + + +//------------------------------------------------- +// clock_scan_counters - +//------------------------------------------------- + +void mm74c922_device::clock_scan_counters() +{ + if (!m_inhibit) + { + m_x++; + m_x &= 0x03; + } +} + + +//------------------------------------------------- +// detect_keypress - +//------------------------------------------------- + +void mm74c922_device::detect_keypress() +{ + UINT8 data = 0xff; + + switch (m_x) + { + case 0: data = m_read_x1(0); break; + case 1: data = m_read_x2(0); break; + case 2: data = m_read_x3(0); break; + case 3: data = m_read_x4(0); break; + case 4: data = m_read_x5(0); break; + } + + if (m_inhibit) + { + if (BIT(data, m_y)) + { + // key released + m_inhibit = 0; + m_next_da = 0; + m_data = 0xff; // high-Z + + if (LOG) logerror("MM74C922 '%s' Key Released\n", tag()); + } + } + else + { + for (int y = 0; y < m_max_y; y++) + { + if (!BIT(data, y)) + { + // key depressed + m_inhibit = 1; + m_next_da = 1; + m_y = y; + + m_data = (y << 2) | m_x; + + if (LOG) logerror("MM74C922 '%s' Key Depressed: X %u Y %u = %02x\n", tag(), m_x, y, m_data); + return; + } + } + } +} diff --git a/src/devices/machine/mm74c922.h b/src/devices/machine/mm74c922.h new file mode 100644 index 00000000000..88a7bfde186 --- /dev/null +++ b/src/devices/machine/mm74c922.h @@ -0,0 +1,138 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + MM74C922/MM74C923 16/20-Key Encoder emulation + +********************************************************************** + _____ _____ + ROW Y1 1 |* \_/ | 18 Vcc + ROW Y2 2 | | 17 DATA OUT A + ROW Y3 3 | | 16 DATA OUT B + ROW Y4 4 | | 15 DATA OUT C + OSCILLATOR 5 | MM74C922 | 14 DATA OUT D + KEYBOUNCE MASK 6 | | 13 _OUTPUT ENABLE + COLUMN X4 7 | | 12 DATA AVAILABLE + COLUMN X3 8 | | 11 COLUMN X1 + GND 9 |_____________| 10 COLUMN X2 + + _____ _____ + ROW Y1 1 |* \_/ | 20 Vcc + ROW Y2 2 | | 19 DATA OUT A + ROW Y3 3 | | 18 DATA OUT B + ROW Y4 4 | | 17 DATA OUT C + ROW Y5 5 | MM74C923 | 16 DATA OUT D + OSCILLATOR 6 | | 15 DATA OUT E + KEYBOUNCE MASK 7 | | 14 _OUTPUT ENABLE + COLUMN X4 8 | | 13 DATA AVAILABLE + COLUMN X3 9 | | 12 COLUMN X1 + GND 10 |_____________| 11 COLUMN X2 + +**********************************************************************/ + +#pragma once + +#ifndef __MM74C922__ +#define __MM74C922__ + +#include "emu.h" + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_MM74C922_OSC(_value) \ + mm74c922_device::static_set_cap_osc(*device, _value); + +#define MCFG_MM74C922_DEBOUNCE(_value) \ + mm74c922_device::static_set_cap_debounce(*device, _value); + +#define MCFG_MM74C922_DA_CALLBACK(_write) \ + devcb = &mm74c922_device::set_da_wr_callback(*device, DEVCB_##_write); + +#define MCFG_MM74C922_X1_CALLBACK(_read) \ + devcb = &mm74c922_device::set_x1_rd_callback(*device, DEVCB_##_read); + +#define MCFG_MM74C922_X2_CALLBACK(_read) \ + devcb = &mm74c922_device::set_x2_rd_callback(*device, DEVCB_##_read); + +#define MCFG_MM74C922_X3_CALLBACK(_read) \ + devcb = &mm74c922_device::set_x3_rd_callback(*device, DEVCB_##_read); + +#define MCFG_MM74C922_X4_CALLBACK(_read) \ + devcb = &mm74c922_device::set_x4_rd_callback(*device, DEVCB_##_read); + +#define MCFG_MM74C922_X5_CALLBACK(_read) \ + devcb = &mm74c922_device::set_x5_rd_callback(*device, DEVCB_##_read); + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> mm74c922_device + +class mm74c922_device : public device_t +{ +public: + // construction/destruction + mm74c922_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + static void static_set_cap_osc(device_t &device, double value) { downcast(device).m_cap_osc = value; } + static void static_set_cap_debounce(device_t &device, double value) { downcast(device).m_cap_debounce = value; } + + template static devcb_base &set_da_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_da.set_callback(object); } + template static devcb_base &set_x1_rd_callback(device_t &device, _Object object) { return downcast(device).m_read_x1.set_callback(object); } + template static devcb_base &set_x2_rd_callback(device_t &device, _Object object) { return downcast(device).m_read_x2.set_callback(object); } + template static devcb_base &set_x3_rd_callback(device_t &device, _Object object) { return downcast(device).m_read_x3.set_callback(object); } + template static devcb_base &set_x4_rd_callback(device_t &device, _Object object) { return downcast(device).m_read_x4.set_callback(object); } + template static devcb_base &set_x5_rd_callback(device_t &device, _Object object) { return downcast(device).m_read_x5.set_callback(object); } + + UINT8 read(); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + +private: + void change_output_lines(); + void clock_scan_counters(); + void detect_keypress(); + + devcb_write_line m_write_da; + devcb_read8 m_read_x1; + devcb_read8 m_read_x2; + devcb_read8 m_read_x3; + devcb_read8 m_read_x4; + devcb_read8 m_read_x5; + + double m_cap_osc; + double m_cap_debounce; + + int m_max_y; + + int m_inhibit; // scan counter clock inhibit + int m_x; // currently scanned column + int m_y; // latched row + + UINT8 m_data; // data latch + + int m_da; // data available flag + int m_next_da; // next value of data available flag + + // timers + emu_timer *m_scan_timer; // keyboard scan timer +}; + + +// device type definition +extern const device_type MM74C922; +extern const device_type MM74C923; + + + +#endif diff --git a/src/devices/machine/mos6526.c b/src/devices/machine/mos6526.c new file mode 100644 index 00000000000..3d9561b36f7 --- /dev/null +++ b/src/devices/machine/mos6526.c @@ -0,0 +1,1178 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + MOS 6526/8520 Complex Interface Adapter emulation + +**********************************************************************/ + +/* + + TODO: + + - pass Lorenz test suite 2.15 + - ICR01 + - IMR + - CIA1TA/TB + - CIA2TA/TB + - pass VICE cia tests + - 8520 read/write + - 5710 read/write + - optimize + +*/ + +#include "mos6526.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +// registers +enum +{ + PRA = 0, + PRB, + DDRA, + DDRB, + TA_LO, + TA_HI, + TB_LO, + TB_HI, + TOD_10THS, + TOD_SEC, + TOD_MIN, + TOD_HR, + SDR, + ICR, IMR = ICR, + CRA, + CRB +}; + + +// interrupt control register +#define ICR_TA 0x01 +#define ICR_TB 0x02 +#define ICR_ALARM 0x04 +#define ICR_SP 0x08 +#define ICR_FLAG 0x10 + + +// interrupt mask register +#define IMR_TA BIT(m_imr, 0) +#define IMR_TB BIT(m_imr, 1) +#define IMR_ALARM BIT(m_imr, 2) +#define IMR_SP BIT(m_imr, 3) +#define IMR_FLAG BIT(m_imr, 4) +#define IMR_SET BIT(data, 7) + + +// control register A +enum +{ + CRA_INMODE_PHI2 = 0, + CRA_INMODE_CNT +}; + +#define CRA_START 0x01 +#define CRA_STARTED BIT(m_cra, 0) +#define CRA_PBON BIT(m_cra, 1) +#define CRA_OUTMODE BIT(m_cra, 2) +#define CRA_RUNMODE BIT(m_cra, 3) +#define CRA_LOAD BIT(m_cra, 4) +#define CRA_INMODE BIT(m_cra, 5) +#define CRA_SPMODE BIT(m_cra, 6) +#define CRA_TODIN BIT(m_cra, 7) + + +// control register B +enum +{ + CRB_INMODE_PHI2 = 0, + CRB_INMODE_CNT, + CRB_INMODE_TA, + CRB_INMODE_CNT_TA +}; + +#define CRB_START 0x01 +#define CRB_STARTED BIT(m_crb, 0) +#define CRB_PBON BIT(m_crb, 1) +#define CRB_OUTMODE BIT(m_crb, 2) +#define CRB_RUNMODE BIT(m_crb, 3) +#define CRB_LOAD BIT(m_crb, 4) +#define CRB_INMODE ((m_crb & 0x60) >> 5) +#define CRB_ALARM BIT(m_crb, 7) + + + +//************************************************************************** +// DEVICE TYPE DEFINITIONS +//************************************************************************** + +const device_type MOS6526 = &device_creator; +const device_type MOS6526A = &device_creator; +const device_type MOS8520 = &device_creator; +const device_type MOS5710 = &device_creator; + + + +//************************************************************************** +// INLINE HELPERS +//************************************************************************** + +//------------------------------------------------- +// update_pa - update port A +//------------------------------------------------- + +inline void mos6526_device::update_pa() +{ + UINT8 pa = m_pra | (m_pa_in & ~m_ddra); + + if (m_pa != pa) + { + m_pa = pa; + m_write_pa((offs_t)0, pa); + } +} + + +//------------------------------------------------- +// update_pb - update port B +//------------------------------------------------- + +inline void mos6526_device::update_pb() +{ + UINT8 pb = m_prb | (m_pb_in & ~m_ddrb); + + if (CRA_PBON) + { + int pb6 = CRA_OUTMODE ? m_ta_pb6 : m_ta_out; + + pb &= ~0x40; + pb |= pb6 << 6; + } + + if (CRB_PBON) + { + int pb7 = CRB_OUTMODE ? m_tb_pb7 : m_tb_out; + + pb &= ~0x80; + pb |= pb7 << 7; + } + + if (m_pb != pb) + { + m_write_pb((offs_t)0, pb); + m_pb = pb; + } +} + + +//------------------------------------------------- +// set_cra - control register A write +//------------------------------------------------- + +inline void mos6526_device::set_cra(UINT8 data) +{ + if (!CRA_STARTED && (data & CRA_START)) + { + m_ta_pb6 = 1; + } + + // switching to serial output mode causes sp to go high? + if (!CRA_SPMODE && BIT(data, 6)) + { + m_bits = 0; + m_write_sp(1); + } + + // lower sp again when switching back to input? + if (CRA_SPMODE && !BIT(data, 6)) + { + m_bits = 0; + m_write_sp(0); + } + + m_cra = data; + update_pb(); +} + + +//------------------------------------------------- +// set_crb - control register B write +//------------------------------------------------- + +inline void mos6526_device::set_crb(UINT8 data) +{ + if (!CRB_STARTED && (data & CRB_START)) + { + m_tb_pb7 = 1; + } + + m_crb = data; + update_pb(); +} + + +//------------------------------------------------- +// bcd_increment - +//------------------------------------------------- + +inline UINT8 mos6526_device::bcd_increment(UINT8 value) +{ + value++; + + if ((value & 0x0f) >= 0x0a) + value += 0x10 - 0x0a; + + return value; +} + + +//------------------------------------------------- +// clock_tod - time-of-day clock pulse +//------------------------------------------------- + +inline void mos6526_device::clock_tod() +{ + UINT8 subsecond = (UINT8) (m_tod >> 0); + UINT8 second = (UINT8) (m_tod >> 8); + UINT8 minute = (UINT8) (m_tod >> 16); + UINT8 hour = (UINT8) (m_tod >> 24); + + m_tod_count++; + + if (m_tod_count == (CRA_TODIN ? 5 : 6)) + { + m_tod_count = 0; + + subsecond = bcd_increment(subsecond); + + if (subsecond >= 0x10) + { + subsecond = 0x00; + second = bcd_increment(second); + + if (second >= 60) + { + second = 0x00; + minute = bcd_increment(minute); + + if (minute >= 0x60) + { + minute = 0x00; + + int pm = hour & 0x80; + hour &= 0x1f; + + if (hour == 11) pm ^= 0x80; + if (hour == 12) hour = 0; + + hour = bcd_increment(hour); + + hour |= pm; + } + } + } + } + + m_tod = (((UINT32) subsecond) << 0) + | (((UINT32) second) << 8) + | (((UINT32) minute) << 16) + | (((UINT32) hour) << 24); +} + + +//------------------------------------------------- +// clock_tod - time-of-day clock pulse +//------------------------------------------------- + +inline void mos8520_device::clock_tod() +{ + m_tod++; + m_tod &= 0xffffff; +} + + +//------------------------------------------------- +// read_tod - time-of-day read +//------------------------------------------------- + +inline UINT8 mos6526_device::read_tod(int offset) +{ + int shift = 8 * offset; + + if (m_tod_latched) + { + return m_tod_latch >> shift; + } + else + { + return m_tod >> shift; + } +} + + +//------------------------------------------------- +// write_tod - time-of-day write +//------------------------------------------------- + +inline void mos6526_device::write_tod(int offset, UINT8 data) +{ + int shift = 8 * offset; + + if (CRB_ALARM) + { + m_alarm = (m_alarm & ~(0xff << shift)) | (data << shift); + } + else + { + m_tod = (m_tod & ~(0xff << shift)) | (data << shift); + } +} + + +//------------------------------------------------- +// serial_input - +//------------------------------------------------- + +inline void mos6526_device::serial_input() +{ + m_shift <<= 1; + m_bits++; + + m_shift |= m_sp; + + if (m_bits == 8) + { + m_sdr = m_shift; + m_bits = 0; + + m_icr |= ICR_SP; + } +} + + +//------------------------------------------------- +// clock_ta - clock timer A +//------------------------------------------------- + +inline void mos6526_device::clock_ta() +{ + if (m_count_a3) + { + m_ta--; + } + + m_ta_out = (m_count_a2 && !m_ta); + + if (m_ta_out) + { + m_ta_pb6 = !m_ta_pb6; + + if (CRA_RUNMODE || m_oneshot_a0) + { + m_cra &= ~CRA_START; + m_count_a0 = m_count_a1 = m_count_a2 = 0; + } + + m_load_a1 = 1; + } + + if (m_load_a1) + { + m_count_a2 = 0; + m_ta = m_ta_latch; + } +} + + +//------------------------------------------------- +// serial_output - +//------------------------------------------------- + +inline void mos6526_device::serial_output() +{ + if (m_ta_out && CRA_SPMODE) + { + if (!m_sdr_empty || m_bits) + { + if (m_cnt) + { + if (m_bits == 0) + { + m_sdr_empty = true; + m_shift = m_sdr; + } + + m_sp = BIT(m_shift, 7); + m_write_sp(m_sp); + + m_shift <<= 1; + m_bits++; + + if (m_bits == 8) + { + m_icr |= ICR_SP; + } + } + else + { + if (m_bits == 8) + { + m_bits = 0; + } + } + + m_cnt = !m_cnt; + m_write_cnt(m_cnt); + } + } +} + + +//------------------------------------------------- +// clock_tb - clock timer B +//------------------------------------------------- + +inline void mos6526_device::clock_tb() +{ + if (m_count_b3) + { + m_tb--; + } + + m_tb_out = (m_count_b2 && !m_tb); + + if (m_tb_out) + { + m_tb_pb7 = !m_tb_pb7; + + if (CRB_RUNMODE || m_oneshot_b0) + { + m_crb &= ~CRB_START; + m_count_b0 = m_count_b1 = m_count_b2 = 0; + } + + m_load_b1 = 1; + } + + if (m_load_b1) + { + m_count_b2 = 0; + m_tb = m_tb_latch; + } +} + + +//------------------------------------------------- +// update_interrupt - +//------------------------------------------------- + +inline void mos6526_device::update_interrupt() +{ + if (!m_irq && m_ir1) + { + m_write_irq(ASSERT_LINE); + m_irq = true; + } + + if (m_ta_out) + { + m_icr |= ICR_TA; + } + + if (m_tb_out && !m_icr_read) + { + m_icr |= ICR_TB; + } + + m_icr_read = false; +} + + +//------------------------------------------------- +// clock_pipeline - clock pipeline +//------------------------------------------------- + +inline void mos6526_device::clock_pipeline() +{ + // timer A pipeline + m_count_a3 = m_count_a2; + + if (CRA_INMODE == CRA_INMODE_PHI2) + m_count_a2 = 1; + + m_count_a2 &= CRA_STARTED; + m_count_a1 = m_count_a0; + m_count_a0 = 0; + + m_load_a2 = m_load_a1; + m_load_a1 = m_load_a0; + m_load_a0 = CRA_LOAD; + m_cra &= ~0x10; + + m_oneshot_a0 = CRA_RUNMODE; + + // timer B pipeline + m_count_b3 = m_count_b2; + + switch (CRB_INMODE) + { + case CRB_INMODE_PHI2: + m_count_b2 = 1; + break; + + case CRB_INMODE_TA: + m_count_b2 = m_ta_out; + break; + + case CRB_INMODE_CNT_TA: + m_count_b2 = m_ta_out && m_cnt; + break; + } + + m_count_b2 &= CRB_STARTED; + m_count_b1 = m_count_b0; + m_count_b0 = 0; + + m_load_b2 = m_load_b1; + m_load_b1 = m_load_b0; + m_load_b0 = CRB_LOAD; + m_crb &= ~0x10; + + m_oneshot_b0 = CRB_RUNMODE; + + // interrupt pipeline + if (m_ir0) m_ir1 = 1; + m_ir0 = (m_icr & m_imr) ? 1 : 0; +} + + +//------------------------------------------------- +// synchronize - +//------------------------------------------------- + +inline void mos6526_device::synchronize() +{ + if (!m_pc) + { + m_pc = 1; + m_write_pc(m_pc); + } + + clock_ta(); + + serial_output(); + + clock_tb(); + + update_pb(); + + update_interrupt(); + + clock_pipeline(); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// mos6526_device - constructor +//------------------------------------------------- + +mos6526_device::mos6526_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, UINT32 variant, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_execute_interface(mconfig, *this), + m_icount(0), + m_variant(variant), + m_tod_clock(0), + m_write_irq(*this), + m_write_pc(*this), + m_write_cnt(*this), + m_write_sp(*this), + m_read_pa(*this), + m_write_pa(*this), + m_read_pb(*this), + m_write_pb(*this) +{ +} + +mos6526_device::mos6526_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, MOS6526, "MOS6526", tag, owner, clock, "mos6526", __FILE__), + device_execute_interface(mconfig, *this), + m_icount(0), + m_variant(TYPE_6526), + m_tod_clock(0), + m_write_irq(*this), + m_write_pc(*this), + m_write_cnt(*this), + m_write_sp(*this), + m_read_pa(*this), + m_write_pa(*this), + m_read_pb(*this), + m_write_pb(*this) +{ } + +mos6526a_device::mos6526a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : mos6526_device(mconfig, MOS6526A, "MOS6526A", tag, owner, clock, TYPE_6526A, "mos6526a", __FILE__) { } + +mos8520_device::mos8520_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : mos6526_device(mconfig, MOS8520, "MOS8520", tag, owner, clock, TYPE_8520, "mos8520", __FILE__) { } + +mos5710_device::mos5710_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : mos6526_device(mconfig, MOS5710, "MOS5710", tag, owner, clock, TYPE_5710, "mos5710", __FILE__) { } + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void mos6526_device::device_start() +{ + // set our instruction counter + m_icountptr = &m_icount; + + m_flag = 1; + m_cnt = 1; + m_cra = 0; + + // resolve callbacks + m_write_irq.resolve_safe(); + m_write_pc.resolve_safe(); + m_write_cnt.resolve_safe(); + m_write_sp.resolve_safe(); + m_read_pa.resolve_safe(0xff); + m_write_pa.resolve_safe(); + m_read_pb.resolve_safe(0xff); + m_write_pb.resolve_safe(); + + // allocate timer + if (m_tod_clock > 0) + { + m_tod_timer = timer_alloc(); + m_tod_timer->adjust(attotime::from_hz(m_tod_clock), 0, attotime::from_hz(m_tod_clock)); + } + + // state saving + save_item(NAME(m_ir0)); + save_item(NAME(m_ir1)); + save_item(NAME(m_icr)); + save_item(NAME(m_imr)); + save_item(NAME(m_pc)); + save_item(NAME(m_flag)); + save_item(NAME(m_pra)); + save_item(NAME(m_prb)); + save_item(NAME(m_ddra)); + save_item(NAME(m_ddrb)); + save_item(NAME(m_sp)); + save_item(NAME(m_cnt)); + save_item(NAME(m_sdr)); + save_item(NAME(m_shift)); + save_item(NAME(m_sdr_empty)); + save_item(NAME(m_bits)); + + save_item(NAME(m_ta_out)); + save_item(NAME(m_tb_out)); + save_item(NAME(m_ta_pb6)); + save_item(NAME(m_tb_pb7)); + save_item(NAME(m_ta)); + save_item(NAME(m_tb)); + save_item(NAME(m_ta_latch)); + save_item(NAME(m_tb_latch)); + save_item(NAME(m_cra)); + save_item(NAME(m_crb)); + + save_item(NAME(m_tod_count)); + save_item(NAME(m_tod)); + save_item(NAME(m_tod_latch)); + save_item(NAME(m_alarm)); + save_item(NAME(m_tod_stopped)); + save_item(NAME(m_tod_latched)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void mos6526_device::device_reset() +{ + m_irq = false; + m_ir0 = 0; + m_ir1 = 0; + m_icr = 0; + m_imr = 0; + m_icr_read = false; + + m_pc = 1; + m_flag = 1; + m_pra = 0; + m_prb = 0; + m_ddra = 0; + m_ddrb = 0; + m_pa = 0xff; + m_pb = 0xff; + m_pa_in = 0; + m_pb_in = 0; + + m_sp = 1; + m_cnt = 1; + m_sdr = 0; + m_shift = 0; + m_sdr_empty = true; + m_bits = 0; + + m_ta_out = 0; + m_tb_out = 0; + m_ta_pb6 = 0; + m_tb_pb7 = 0; + m_count_a0 = 0; + m_count_a1 = 0; + m_count_a2 = 0; + m_count_a3 = 0; + m_load_a0 = 0; + m_load_a1 = 0; + m_load_a2 = 0; + m_oneshot_a0 = 0; + m_count_b0 = 0; + m_count_b1 = 0; + m_count_b2 = 0; + m_count_b3 = 0; + m_load_b0 = 0; + m_load_b1 = 0; + m_load_b2 = 0; + m_oneshot_b0 = 0; + m_ta = 0; + m_tb = 0; + m_ta_latch = 0xffff; + m_tb_latch = 0xffff; + m_cra = 0; + m_crb = 0; + + m_tod_count = 0; + m_tod = 0x01000000L; + m_tod_latch = 0; + m_alarm = 0; + m_tod_stopped = true; + m_tod_latched = false; + + m_write_irq(CLEAR_LINE); + m_write_pc(m_pc); + m_write_sp(m_sp); + m_write_cnt(m_cnt); +} + + +//------------------------------------------------- +// device_timer - handler timer events +//------------------------------------------------- + +void mos6526_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + tod_w(1); + tod_w(0); +} + + +//------------------------------------------------- +// execute_run - +//------------------------------------------------- + +void mos6526_device::execute_run() +{ + do + { + synchronize(); + + m_icount--; + } while (m_icount > 0); +} + + +//------------------------------------------------- +// read - +//------------------------------------------------- + +READ8_MEMBER( mos6526_device::read ) +{ + if (space.debugger_access()) + return 0xff; + + UINT8 data = 0; + + switch (offset & 0x0f) + { + case PRA: + if (m_ddra != 0xff) + data = (m_read_pa(0) & ~m_ddra) | (m_pra & m_ddra); + else + data = m_read_pa(0) & m_pra; + m_pa_in = data; + break; + + case PRB: + if (m_ddrb != 0xff) + data = (m_read_pb(0) & ~m_ddrb) | (m_prb & m_ddrb); + else + data = m_read_pb(0) & m_prb; + m_pb_in = data; + + if (CRA_PBON) + { + int pb6 = CRA_OUTMODE ? m_ta_pb6 : m_ta_out; + + data &= ~0x40; + data |= pb6 << 6; + } + + if (CRB_PBON) + { + int pb7 = CRB_OUTMODE ? m_tb_pb7 : m_tb_out; + + data &= ~0x80; + data |= pb7 << 7; + } + + m_pc = 0; + m_write_pc(m_pc); + break; + + case DDRA: + data = m_ddra; + break; + + case DDRB: + data = m_ddrb; + break; + + case TA_LO: + data = m_ta & 0xff; + break; + + case TA_HI: + data = m_ta >> 8; + break; + + case TB_LO: + data = m_tb & 0xff; + break; + + case TB_HI: + data = m_tb >> 8; + break; + + case TOD_10THS: + data = read_tod(0); + + m_tod_latched = false; + break; + + case TOD_SEC: + data = read_tod(1); + break; + + case TOD_MIN: + data = read_tod(2); + break; + + case TOD_HR: + if (!m_tod_latched) + { + m_tod_latched = true; + m_tod_latch = m_tod; + } + + data = read_tod(3); + break; + + case SDR: + data = m_sdr; + break; + + case ICR: + data = (m_ir1 << 7) | m_icr; + + m_icr_read = true; + + m_ir0 = 0; + m_ir1 = 0; + m_icr = 0; + m_irq = false; + m_write_irq(CLEAR_LINE); + break; + + case CRA: + data = m_cra; + break; + + case CRB: + data = m_crb; + break; + } + + return data; +} + +READ8_MEMBER( mos8520_device::read ) +{ + UINT8 data = 0; + + switch (offset & 0x0f) + { + case TOD_MIN: + if (!m_tod_latched) + { + m_tod_latched = true; + m_tod_latch = m_tod; + } + + data = read_tod(2); + break; + + case TOD_HR: + data = read_tod(3); + break; + + default: + data = mos6526_device::read(space, offset); + } + + return data; +} + +//------------------------------------------------- +// write - +//------------------------------------------------- + +WRITE8_MEMBER( mos6526_device::write ) +{ + switch (offset & 0x0f) + { + case PRA: + m_pra = data; + update_pa(); + break; + + case PRB: + m_prb = data; + update_pb(); + + m_pc = 0; + m_write_pc(m_pc); + break; + + case DDRA: + m_ddra = data; + update_pa(); + break; + + case DDRB: + m_ddrb = data; + update_pb(); + break; + + case TA_LO: + m_ta_latch = (m_ta_latch & 0xff00) | data; + + if (m_load_a2) + { + m_ta = (m_ta & 0xff00) | data; + } + break; + + case TA_HI: + m_ta_latch = (data << 8) | (m_ta_latch & 0xff); + + if (!CRA_STARTED) + { + m_load_a0 = 1; + } + + if (CRA_RUNMODE) + { + m_ta = m_ta_latch; + set_cra(m_cra | CRA_START); + } + + if (m_load_a2) + { + m_ta = (data << 8) | (m_ta & 0xff); + } + break; + + case TB_LO: + m_tb_latch = (m_tb_latch & 0xff00) | data; + + if (m_load_b2) + { + m_tb = (m_tb & 0xff00) | data; + } + break; + + case TB_HI: + m_tb_latch = (data << 8) | (m_tb_latch & 0xff); + + if (!CRB_STARTED) + { + m_load_b0 = 1; + } + + if (CRB_RUNMODE) + { + m_tb = m_tb_latch; + set_crb(m_crb | CRB_START); + } + + if (m_load_b2) + { + m_tb = (data << 8) | (m_tb & 0xff); + } + break; + + case TOD_10THS: + write_tod(0, data); + + m_tod_stopped = false; + break; + + case TOD_SEC: + write_tod(1, data); + break; + + case TOD_MIN: + write_tod(2, data); + break; + + case TOD_HR: + m_tod_stopped = true; + + if (((data & 0x1f) == 0x12) && !CRB_ALARM) + { + // toggle AM/PM flag + data ^= 0x80; + } + + write_tod(3, data); + break; + + case SDR: + m_sdr = data; + m_sdr_empty = false; + break; + + case IMR: + if (IMR_SET) + { + m_imr |= (data & 0x1f); + } + else + { + m_imr &= ~(data & 0x1f); + } + + if (!m_irq && (m_icr & m_imr)) + { + m_ir0 = 1; + } + break; + + case CRA: + set_cra(data); + break; + + case CRB: + set_crb(data); + break; + } +} + +WRITE8_MEMBER( mos8520_device::write ) +{ + switch (offset & 0x0f) + { + default: + mos6526_device::write(space, offset, data); + break; + + case TOD_MIN: + m_tod_stopped = true; + write_tod(2, data); + break; + + case TOD_HR: + write_tod(3, data); + break; + } +} + + +//------------------------------------------------- +// sp_w - serial port write +//------------------------------------------------- + +WRITE_LINE_MEMBER( mos6526_device::sp_w ) +{ + m_sp = state; +} + + +//------------------------------------------------- +// cnt_w - serial counter write +//------------------------------------------------- + +WRITE_LINE_MEMBER( mos6526_device::cnt_w ) +{ + if (CRA_SPMODE) return; + + if (!m_cnt && state) + { + serial_input(); + + if (CRA_INMODE == CRA_INMODE_CNT) + m_ta--; + + if (CRB_INMODE == CRB_INMODE_CNT) + m_tb--; + } + + m_cnt = state; +} + + +//------------------------------------------------- +// flag_w - flag write +//------------------------------------------------- + +WRITE_LINE_MEMBER( mos6526_device::flag_w ) +{ + if (m_flag && !state) + { + m_icr |= ICR_FLAG; + } + + m_flag = state; +} + + +//------------------------------------------------- +// tod_w - time-of-day clock write +//------------------------------------------------- + +WRITE_LINE_MEMBER( mos6526_device::tod_w ) +{ + if (state && !m_tod_stopped) + { + clock_tod(); + + if (m_tod == m_alarm) + { + m_icr |= ICR_ALARM; + } + } +} diff --git a/src/devices/machine/mos6526.h b/src/devices/machine/mos6526.h new file mode 100644 index 00000000000..da54967e080 --- /dev/null +++ b/src/devices/machine/mos6526.h @@ -0,0 +1,296 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + MOS 6526/8520 Complex Interface Adapter emulation + +********************************************************************** + _____ _____ + Vss 1 |* \_/ | 40 CNT + PA0 2 | | 39 SP + PA1 3 | | 38 RS0 + PA2 4 | | 37 RS1 + PA3 5 | | 36 RS2 + PA4 6 | | 35 RS3 + PA5 7 | | 34 _RES + PA6 8 | | 33 DB0 + PA7 9 | | 32 DB1 + PB0 10 | MOS6526 | 31 DB2 + PB1 11 | MOS8520 | 30 DB3 + PB2 12 | | 29 DB4 + PB3 13 | | 28 DB5 + PB4 14 | | 27 DB6 + PB5 15 | | 26 DB7 + PB6 16 | | 25 phi2 + PB7 17 | | 24 _FLAG + _PC 18 | | 23 _CS + TOD 19 | | 22 R/W + Vcc 20 |_____________| 21 _IRQ + + _____ _____ + FCO* 1 |* \_/ | 48 FDO* + TED 2 | | 47 FCI* + phi0 3 | | 46 FDI* + CLKIN 4 | | 45 IRQ + CTRLO 5 | | 44 RSET + CTRLI 6 | | 43 + phi2 7 | | 42 + D7 8 | | 41 INDEX* + D6 9 | | 40 WG2* + D5 10 | | 39 WPRT* + D4 11 | | 38 RPULSE + GND 12 | MOS5710 | 37 Q + Vcc 13 | | 36 Vcc + D3 14 | | 35 GND + D2 15 | | 34 CS3* + D1 16 | | 33 CS2* + D0 17 | | 32 CS1* + A15 18 | | 31 R/W* + A14 19 | | 30 OSC + A13 20 | | 29 XTL1 + A12 21 | | 28 XTL2 + A10 22 | | 27 A0 + A4 23 | | 26 A1 + A3 24 |_____________| 25 A2 + +**********************************************************************/ + +#pragma once + +#ifndef __MOS6526__ +#define __MOS6526__ + +#include "emu.h" + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_MOS6526_TOD(_clock) \ + mos6526_device::static_set_tod_clock(*device, _clock); + +#define MCFG_MOS6526_IRQ_CALLBACK(_write) \ + devcb = &mos6526_device::set_irq_wr_callback(*device, DEVCB_##_write); + +#define MCFG_MOS6526_CNT_CALLBACK(_write) \ + devcb = &mos6526_device::set_cnt_wr_callback(*device, DEVCB_##_write); + +#define MCFG_MOS6526_SP_CALLBACK(_write) \ + devcb = &mos6526_device::set_sp_wr_callback(*device, DEVCB_##_write); + +#define MCFG_MOS6526_PA_INPUT_CALLBACK(_read) \ + devcb = &mos6526_device::set_pa_rd_callback(*device, DEVCB_##_read); + +#define MCFG_MOS6526_PA_OUTPUT_CALLBACK(_write) \ + devcb = &mos6526_device::set_pa_wr_callback(*device, DEVCB_##_write); + +#define MCFG_MOS6526_PB_INPUT_CALLBACK(_read) \ + devcb = &mos6526_device::set_pb_rd_callback(*device, DEVCB_##_read); + +#define MCFG_MOS6526_PB_OUTPUT_CALLBACK(_write) \ + devcb = &mos6526_device::set_pb_wr_callback(*device, DEVCB_##_write); + +#define MCFG_MOS6526_PC_CALLBACK(_write) \ + devcb = &mos6526_device::set_pc_wr_callback(*device, DEVCB_##_write); + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> mos6526_device + +class mos6526_device : public device_t, + public device_execute_interface +{ +public: + // construction/destruction + mos6526_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, UINT32 variant, const char *shortname, const char *source); + mos6526_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + static void static_set_tod_clock(device_t &device, int clock) { downcast(device).m_tod_clock = clock; } + + template static devcb_base &set_irq_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_irq.set_callback(object); } + template static devcb_base &set_cnt_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_cnt.set_callback(object); } + template static devcb_base &set_sp_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_sp.set_callback(object); } + template static devcb_base &set_pa_rd_callback(device_t &device, _Object object) { return downcast(device).m_read_pa.set_callback(object); } + template static devcb_base &set_pa_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_pa.set_callback(object); } + template static devcb_base &set_pb_rd_callback(device_t &device, _Object object) { return downcast(device).m_read_pb.set_callback(object); } + template static devcb_base &set_pb_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_pb.set_callback(object); } + template static devcb_base &set_pc_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_pc.set_callback(object); } + + DECLARE_READ8_MEMBER( read ); + DECLARE_WRITE8_MEMBER( write ); + + UINT8 pa_r() { return m_pa; } + DECLARE_READ8_MEMBER( pa_r ) { return pa_r(); } + UINT8 pb_r() { return m_pb; } + DECLARE_READ8_MEMBER( pb_r ) { return pb_r(); } + + DECLARE_READ_LINE_MEMBER( sp_r ) { return m_sp; } + DECLARE_WRITE_LINE_MEMBER( sp_w ); + DECLARE_READ_LINE_MEMBER( cnt_r ) { return m_cnt; } + DECLARE_WRITE_LINE_MEMBER( cnt_w ); + DECLARE_WRITE_LINE_MEMBER( flag_w ); + DECLARE_READ_LINE_MEMBER( irq_r ) { return m_irq; } + DECLARE_WRITE_LINE_MEMBER( tod_w ); + +protected: + enum + { + TYPE_6526, + TYPE_6526A, + TYPE_8520, + TYPE_5710 + }; + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + virtual void execute_run(); + + int m_icount; + int m_variant; + int m_tod_clock; + + inline void update_interrupt(); + inline void update_pa(); + inline void update_pb(); + inline void set_cra(UINT8 data); + inline void set_crb(UINT8 data); + inline void serial_input(); + inline void serial_output(); + inline void clock_ta(); + inline void clock_tb(); + inline void clock_pipeline(); + inline UINT8 bcd_increment(UINT8 value); + virtual inline void clock_tod(); + inline UINT8 read_tod(int offset); + inline void write_tod(int offset, UINT8 data); + inline void synchronize(); + + devcb_write_line m_write_irq; + devcb_write_line m_write_pc; + devcb_write_line m_write_cnt; + devcb_write_line m_write_sp; + devcb_read8 m_read_pa; + devcb_write8 m_write_pa; + devcb_read8 m_read_pb; + devcb_write8 m_write_pb; + + // interrupts + bool m_irq; + int m_ir0; + int m_ir1; + UINT8 m_icr; + UINT8 m_imr; + bool m_icr_read; + + // peripheral ports + int m_pc; + int m_flag; + UINT8 m_pra; + UINT8 m_prb; + UINT8 m_ddra; + UINT8 m_ddrb; + UINT8 m_pa; + UINT8 m_pb; + UINT8 m_pa_in; + UINT8 m_pb_in; + + // serial + int m_sp; + int m_cnt; + UINT8 m_sdr; + UINT8 m_shift; + bool m_sdr_empty; + int m_bits; + + // timers + int m_ta_out; + int m_tb_out; + int m_ta_pb6; + int m_tb_pb7; + int m_count_a0; + int m_count_a1; + int m_count_a2; + int m_count_a3; + int m_load_a0; + int m_load_a1; + int m_load_a2; + int m_oneshot_a0; + int m_count_b0; + int m_count_b1; + int m_count_b2; + int m_count_b3; + int m_load_b0; + int m_load_b1; + int m_load_b2; + int m_oneshot_b0; + UINT16 m_ta; + UINT16 m_tb; + UINT16 m_ta_latch; + UINT16 m_tb_latch; + UINT8 m_cra; + UINT8 m_crb; + + // time-of-day + int m_tod_count; + UINT32 m_tod; + UINT32 m_tod_latch; + UINT32 m_alarm; + bool m_tod_stopped; + bool m_tod_latched; + emu_timer *m_tod_timer; +}; + + +// ======================> mos6526a_device + +class mos6526a_device : public mos6526_device +{ +public: + mos6526a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +// ======================> mos8520_device + +class mos8520_device : public mos6526_device +{ +public: + mos8520_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + DECLARE_READ8_MEMBER( read ); + DECLARE_WRITE8_MEMBER( write ); + +protected: + virtual inline void clock_tod(); +}; + + +// ======================> mos5710_device + +class mos5710_device : public mos6526_device +{ +public: + mos5710_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + //DECLARE_READ8_MEMBER( read ); + //DECLARE_WRITE8_MEMBER( write ); +}; + + +// device type definition +extern const device_type MOS6526; +extern const device_type MOS6526A; +extern const device_type MOS8520; +extern const device_type MOS5710; + + + +#endif diff --git a/src/devices/machine/mos6529.c b/src/devices/machine/mos6529.c new file mode 100644 index 00000000000..ebae2ca6f5a --- /dev/null +++ b/src/devices/machine/mos6529.c @@ -0,0 +1,95 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + MOS Technology 6529 Single Port Interface Adapter emulation + +**********************************************************************/ + +#include "mos6529.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define LOG 0 + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +// device type definition +const device_type MOS6529 = &device_creator; + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// mos6529_device - constructor +//------------------------------------------------- + +mos6529_device::mos6529_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, MOS6529, "MOS6529", tag, owner, clock, "mos6529", __FILE__), + m_input(0), + m_p0_handler(*this), + m_p1_handler(*this), + m_p2_handler(*this), + m_p3_handler(*this), + m_p4_handler(*this), + m_p5_handler(*this), + m_p6_handler(*this), + m_p7_handler(*this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void mos6529_device::device_start() +{ + // resolve callbacks + m_p0_handler.resolve_safe(); + m_p1_handler.resolve_safe(); + m_p2_handler.resolve_safe(); + m_p3_handler.resolve_safe(); + m_p4_handler.resolve_safe(); + m_p5_handler.resolve_safe(); + m_p6_handler.resolve_safe(); + m_p7_handler.resolve_safe(); +} + + +//------------------------------------------------- +// read - +//------------------------------------------------- + +READ8_MEMBER( mos6529_device::read ) +{ + return m_input; +} + + +//------------------------------------------------- +// write - +//------------------------------------------------- + +WRITE8_MEMBER( mos6529_device::write ) +{ + m_p0_handler((data>>0)&1); + m_p1_handler((data>>1)&1); + m_p2_handler((data>>2)&1); + m_p3_handler((data>>3)&1); + m_p4_handler((data>>4)&1); + m_p5_handler((data>>5)&1); + m_p6_handler((data>>6)&1); + m_p7_handler((data>>7)&1); +} diff --git a/src/devices/machine/mos6529.h b/src/devices/machine/mos6529.h new file mode 100644 index 00000000000..0e6f00f4dd0 --- /dev/null +++ b/src/devices/machine/mos6529.h @@ -0,0 +1,113 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + MOS Technology 6529 Single Port Interface Adapter emulation + +********************************************************************** + _____ _____ + R/W 1 |* \_/ | 20 Vdd + P0 2 | | 19 _CS + P1 3 | | 18 D0 + P2 4 | | 17 D1 + P3 5 | MOS6529 | 16 D2 + P4 6 | | 15 D3 + P5 7 | | 14 D4 + P6 8 | | 13 D5 + P7 9 | | 12 D6 + Vss 10 |_____________| 11 D7 + +**********************************************************************/ + +#pragma once + +#ifndef __MOS6529__ +#define __MOS6529__ + +#include "emu.h" + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_MOS6529_P0_HANDLER(_devcb) \ + devcb = &mos6529_device::set_p0_handler(*device, DEVCB_##_devcb); + +#define MCFG_MOS6529_P1_HANDLER(_devcb) \ + devcb = &mos6529_device::set_p1_handler(*device, DEVCB_##_devcb); + +#define MCFG_MOS6529_P2_HANDLER(_devcb) \ + devcb = &mos6529_device::set_p2_handler(*device, DEVCB_##_devcb); + +#define MCFG_MOS6529_P3_HANDLER(_devcb) \ + devcb = &mos6529_device::set_p3_handler(*device, DEVCB_##_devcb); + +#define MCFG_MOS6529_P4_HANDLER(_devcb) \ + devcb = &mos6529_device::set_p4_handler(*device, DEVCB_##_devcb); + +#define MCFG_MOS6529_P5_HANDLER(_devcb) \ + devcb = &mos6529_device::set_p5_handler(*device, DEVCB_##_devcb); + +#define MCFG_MOS6529_P6_HANDLER(_devcb) \ + devcb = &mos6529_device::set_p6_handler(*device, DEVCB_##_devcb); + +#define MCFG_MOS6529_P7_HANDLER(_devcb) \ + devcb = &mos6529_device::set_p7_handler(*device, DEVCB_##_devcb); + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> mos6529_device + +class mos6529_device : public device_t +{ +public: + // construction/destruction + mos6529_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + template static devcb_base &set_p0_handler(device_t &device, _Object object) { return downcast(device).m_p0_handler.set_callback(object); } + template static devcb_base &set_p1_handler(device_t &device, _Object object) { return downcast(device).m_p1_handler.set_callback(object); } + template static devcb_base &set_p2_handler(device_t &device, _Object object) { return downcast(device).m_p2_handler.set_callback(object); } + template static devcb_base &set_p3_handler(device_t &device, _Object object) { return downcast(device).m_p3_handler.set_callback(object); } + template static devcb_base &set_p4_handler(device_t &device, _Object object) { return downcast(device).m_p4_handler.set_callback(object); } + template static devcb_base &set_p5_handler(device_t &device, _Object object) { return downcast(device).m_p5_handler.set_callback(object); } + template static devcb_base &set_p6_handler(device_t &device, _Object object) { return downcast(device).m_p6_handler.set_callback(object); } + template static devcb_base &set_p7_handler(device_t &device, _Object object) { return downcast(device).m_p7_handler.set_callback(object); } + + DECLARE_READ8_MEMBER( read ); + DECLARE_WRITE8_MEMBER( write ); + + DECLARE_WRITE_LINE_MEMBER( write_p0 ) { if (state) m_input |= 1; else m_input &= ~1; } + DECLARE_WRITE_LINE_MEMBER( write_p1 ) { if (state) m_input |= 2; else m_input &= ~2; } + DECLARE_WRITE_LINE_MEMBER( write_p2 ) { if (state) m_input |= 4; else m_input &= ~4; } + DECLARE_WRITE_LINE_MEMBER( write_p3 ) { if (state) m_input |= 8; else m_input &= ~8; } + DECLARE_WRITE_LINE_MEMBER( write_p4 ) { if (state) m_input |= 16; else m_input &= ~16; } + DECLARE_WRITE_LINE_MEMBER( write_p5 ) { if (state) m_input |= 32; else m_input &= ~32; } + DECLARE_WRITE_LINE_MEMBER( write_p6 ) { if (state) m_input |= 64; else m_input &= ~64; } + DECLARE_WRITE_LINE_MEMBER( write_p7 ) { if (state) m_input |= 128; else m_input &= ~128; } + +protected: + // device-level overrides + virtual void device_start(); + + UINT8 m_input; + + devcb_write_line m_p0_handler; + devcb_write_line m_p1_handler; + devcb_write_line m_p2_handler; + devcb_write_line m_p3_handler; + devcb_write_line m_p4_handler; + devcb_write_line m_p5_handler; + devcb_write_line m_p6_handler; + devcb_write_line m_p7_handler; +}; + + +// device type definition +extern const device_type MOS6529; + +#endif diff --git a/src/devices/machine/mos6530.c b/src/devices/machine/mos6530.c new file mode 100644 index 00000000000..a32383fcbda --- /dev/null +++ b/src/devices/machine/mos6530.c @@ -0,0 +1,382 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/*************************************************************************** + + MIOT 6530 emulation + +The timer seems to follow these rules: +- When the timer flag changes from 0 to 1 the timer continues to count + down at a 1 cycle rate. +- When the timer is being read or written the timer flag is reset. +- When the timer flag is set and the timer contents are 0, the counting + stops. + +From the operation of the KIM1 it expects the irqflag to be set whenever +the unit is reset. This is something that is not clear from the datasheet +and should be verified against real hardware. + +***************************************************************************/ + +#include "emu.h" +#include "mos6530.h" + + +/*************************************************************************** + CONSTANTS +***************************************************************************/ + +enum +{ + TIMER_IDLE, + TIMER_COUNTING, + TIMER_FINISHING +}; + +#define TIMER_FLAG 0x80 + +/*************************************************************************** + DEVICE INTERFACE +***************************************************************************/ + +const device_type MOS6530 = &device_creator; + +mos6530_device::mos6530_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, MOS6530, "MOS6530 RRIOT", tag, owner, clock, "mos6530", __FILE__), + m_in_pa_cb(*this), + m_out_pa_cb(*this), + m_in_pb_cb(*this), + m_out_pb_cb(*this) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void mos6530_device::device_start() +{ + /* set static values */ + m_clock = clock(); + + /* resolve callbacks */ + m_in_pa_cb.resolve_safe(0); + m_out_pa_cb.resolve_safe(); + m_in_pb_cb.resolve_safe(0); + m_out_pb_cb.resolve_safe(); + + /* allocate timers */ + m_timer = timer_alloc(TIMER_END_CALLBACK); + + /* register for save states */ + save_item(NAME(m_port[0].m_in)); + save_item(NAME(m_port[0].m_out)); + save_item(NAME(m_port[0].m_ddr)); + save_item(NAME(m_port[1].m_in)); + save_item(NAME(m_port[1].m_out)); + save_item(NAME(m_port[1].m_ddr)); + + save_item(NAME(m_irqstate)); + save_item(NAME(m_irqenable)); + + save_item(NAME(m_timershift)); + save_item(NAME(m_timerstate)); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void mos6530_device::device_reset() +{ + /* reset I/O states */ + m_port[0].m_out = 0; + m_port[0].m_ddr = 0; + m_port[1].m_out = 0; + m_port[1].m_ddr = 0; + + /* reset IRQ states */ + m_irqenable = 0; + m_irqstate = TIMER_FLAG; + update_irqstate(); + + /* reset timer states */ + m_timershift = 0; + m_timerstate = TIMER_IDLE; + m_timer->adjust(attotime::never); +} + + +/*************************************************************************** + TYPE DEFINITIONS +***************************************************************************/ + + +/*------------------------------------------------- + update_irqstate - update the IRQ state + based on interrupt enables +-------------------------------------------------*/ + +void mos6530_device::update_irqstate() +{ + UINT8 out = m_port[1].m_out; + + if (m_irqenable) + out = ((m_irqstate & TIMER_FLAG) ? 0x00 : 0x80) | (out & 0x7F); + + m_out_pb_cb((offs_t)0, out); +} + + +/*------------------------------------------------- + get_timer - return the current timer value +-------------------------------------------------*/ + +UINT8 mos6530_device::get_timer() +{ + /* if idle, return 0 */ + if (m_timerstate == TIMER_IDLE) + return 0; + + /* if counting, return the number of ticks remaining */ + else if (m_timerstate == TIMER_COUNTING) + return m_timer->remaining().as_ticks(m_clock) >> m_timershift; + + /* if finishing, return the number of ticks without the shift */ + else + return m_timer->remaining().as_ticks(m_clock); +} + + +/*************************************************************************** + INTERNAL FUNCTIONS +***************************************************************************/ + +/*------------------------------------------------- + timer_end_callback - callback to process the + timer +-------------------------------------------------*/ + +void mos6530_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch (id) + { + // deferred reset + case TIMER_END_CALLBACK: + assert(m_timerstate != TIMER_IDLE); + + /* if we finished counting, switch to the finishing state */ + if (m_timerstate == TIMER_COUNTING) + { + m_timerstate = TIMER_FINISHING; + m_timer->adjust(attotime::from_ticks(256, m_clock)); + + /* signal timer IRQ as well */ + m_irqstate |= TIMER_FLAG; + update_irqstate(); + } + + /* if we finished finishing, switch to the idle state */ + else if (m_timerstate == TIMER_FINISHING) + { + m_timerstate = TIMER_IDLE; + m_timer->adjust(attotime::never); + } + break; + } +} + +/*************************************************************************** + I/O ACCESS +***************************************************************************/ + +/*------------------------------------------------- + mos6530_w - master I/O write access +-------------------------------------------------*/ + +WRITE8_MEMBER( mos6530_device::write ) +{ + /* if A2 == 1, we are writing to the timer */ + if (offset & 0x04) + { + static const UINT8 timershift[4] = { 0, 3, 6, 10 }; + attotime curtime = space.machine().time(); + INT64 target; + + /* A0-A1 contain the timer divisor */ + m_timershift = timershift[offset & 3]; + + /* A3 contains the timer IRQ enable */ + if (offset & 8) + m_irqenable |= TIMER_FLAG; + else + m_irqenable &= ~TIMER_FLAG; + + /* writes here clear the timer flag */ + if (m_timerstate != TIMER_FINISHING || get_timer() != 0xff) + m_irqstate &= ~TIMER_FLAG; + update_irqstate(); + + /* update the timer */ + m_timerstate = TIMER_COUNTING; + target = curtime.as_ticks(m_clock) + 1 + (data << m_timershift); + m_timer->adjust(attotime::from_ticks(target, m_clock) - curtime); + } + + /* if A2 == 0, we are writing to the I/O section */ + else + { + /* A1 selects the port */ + mos6530_port *port = &m_port[BIT(offset, 1)]; + + /* if A0 == 1, we are writing to the port's DDR */ + if (offset & 1) + port->m_ddr = data; + + /* if A0 == 0, we are writing to the port's output */ + else + { + UINT8 olddata = port->m_out; + port->m_out = data; + + if ((offset & 2) && m_irqenable) + { + olddata = ((m_irqstate & TIMER_FLAG) ? 0x00 : 0x80) | (olddata & 0x7F); + data = ((m_irqstate & TIMER_FLAG) ? 0x00 : 0x80) | (data & 0x7F); + } + + if (!BIT(offset, 1)) + m_out_pa_cb((offs_t)0, data); + else + m_out_pb_cb((offs_t)0, data); + } + } +} + + +/*------------------------------------------------- + mos6530_r - master I/O read access +-------------------------------------------------*/ + +READ8_MEMBER( mos6530_device::read ) +{ + UINT8 val = 0; + + /* if A2 == 1 and A0 == 1, we are reading interrupt flags */ + if ((offset & 0x05) == 0x05) + { + val = m_irqstate; + } + + /* if A2 == 1 and A0 == 0, we are reading the timer */ + else if ((offset & 0x05) == 0x04) + { + val = get_timer(); + + /* A3 contains the timer IRQ enable */ + if (offset & 8) + m_irqenable |= TIMER_FLAG; + else + m_irqenable &= ~TIMER_FLAG; + + /* implicitly clears the timer flag */ + if (m_timerstate != TIMER_FINISHING || val != 0xff) + m_irqstate &= ~TIMER_FLAG; + update_irqstate(); + } + + /* if A2 == 0 and A0 == anything, we are reading from ports */ + else + { + /* A1 selects the port */ + mos6530_port *port = &m_port[BIT(offset, 1)]; + + /* if A0 == 1, we are reading the port's DDR */ + if (offset & 1) + val = port->m_ddr; + + /* if A0 == 0, we are reading the port as an input */ + else + { + UINT8 out = port->m_out; + + if ((offset & 2) && m_irqenable) + out = ((m_irqstate & TIMER_FLAG) ? 0x00 : 0x80) | (out & 0x7F); + + /* call the input callback if it exists */ + if (!BIT(offset, 1)) + port->m_in = m_in_pa_cb(0); + else + port->m_in = m_in_pb_cb(0); + + /* apply the DDR to the result */ + val = (out & port->m_ddr) | (port->m_in & ~port->m_ddr); + } + } + return val; +} + + +/*------------------------------------------------- + mos6530_porta_in_set - set port A input + value +-------------------------------------------------*/ + +void mos6530_device::porta_in_set(UINT8 data, UINT8 mask) +{ + m_port[0].m_in = (m_port[0].m_in & ~mask) | (data & mask); +} + + +/*------------------------------------------------- + mos6530_portb_in_set - set port B input + value +-------------------------------------------------*/ + +void mos6530_device::portb_in_set(UINT8 data, UINT8 mask) +{ + m_port[1].m_in = (m_port[1].m_in & ~mask) | (data & mask); +} + + +/*------------------------------------------------- + mos6530_porta_in_get - return port A input + value +-------------------------------------------------*/ + +UINT8 mos6530_device::porta_in_get() +{ + return m_port[0].m_in; +} + + +/*------------------------------------------------- + mos6530_portb_in_get - return port B input + value +-------------------------------------------------*/ + +UINT8 mos6530_device::portb_in_get() +{ + return m_port[1].m_in; +} + + +/*------------------------------------------------- + mos6530_porta_in_get - return port A output + value +-------------------------------------------------*/ + +UINT8 mos6530_device::porta_out_get() +{ + return m_port[0].m_out; +} + + +/*------------------------------------------------- + mos6530_portb_in_get - return port B output + value +-------------------------------------------------*/ + +UINT8 mos6530_device::portb_out_get() +{ + return m_port[1].m_out; +} diff --git a/src/devices/machine/mos6530.h b/src/devices/machine/mos6530.h new file mode 100644 index 00000000000..d63fdd95a12 --- /dev/null +++ b/src/devices/machine/mos6530.h @@ -0,0 +1,124 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + MOS Technology 6530 Memory, I/O, Timer Array emulation + +********************************************************************** + _____ _____ + Vss 1 |* \_/ | 40 PA1 + PA0 2 | | 39 PA2 + phi2 3 | | 38 PA3 + RS0 4 | | 37 PA4 + A9 5 | | 36 PA5 + A8 6 | | 35 PA6 + A7 7 | | 34 PA7 + A6 8 | | 33 DB0 + R/W 9 | | 32 DB1 + A5 10 | MCS6530 | 31 DB2 + A4 11 | | 30 DB3 + A3 12 | | 29 DB4 + A2 13 | | 28 DB5 + A1 14 | | 27 DB6 + A0 15 | | 26 DB7 + _RES 16 | | 25 PB0 + IRQ/PB7 17 | | 24 PB1 + CS1/PB6 18 | | 23 PB2 + CS2/PB5 19 | | 22 PB3 + Vcc 20 |_____________| 21 PB4 + +**********************************************************************/ + +#ifndef __MIOT6530_H__ +#define __MIOT6530_H__ + + +/*************************************************************************** + TYPE DEFINITIONS +***************************************************************************/ + +struct mos6530_port +{ + UINT8 m_in; + UINT8 m_out; + UINT8 m_ddr; +}; + +/*************************************************************************** + MACROS / CONSTANTS +***************************************************************************/ + +class mos6530_device : public device_t +{ +public: + mos6530_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + ~mos6530_device() {} + + template static devcb_base &set_in_pa_callback(device_t &device, _Object object) { return downcast(device).m_in_pa_cb.set_callback(object); } + template static devcb_base &set_out_pa_callback(device_t &device, _Object object) { return downcast(device).m_out_pa_cb.set_callback(object); } + template static devcb_base &set_in_pb_callback(device_t &device, _Object object) { return downcast(device).m_in_pb_cb.set_callback(object); } + template static devcb_base &set_out_pb_callback(device_t &device, _Object object) { return downcast(device).m_out_pb_cb.set_callback(object); } + + DECLARE_READ8_MEMBER( read ); + DECLARE_WRITE8_MEMBER( write ); + + UINT8 porta_in_get(); + UINT8 portb_in_get(); + + UINT8 porta_out_get(); + UINT8 portb_out_get(); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + +private: + // internal state + devcb_read8 m_in_pa_cb; + devcb_write8 m_out_pa_cb; + + devcb_read8 m_in_pb_cb; + devcb_write8 m_out_pb_cb; + + mos6530_port m_port[2]; + + UINT8 m_irqstate; + UINT8 m_irqenable; + + UINT8 m_timershift; + UINT8 m_timerstate; + emu_timer * m_timer; + + UINT32 m_clock; + + void update_irqstate(); + UINT8 get_timer(); + + void porta_in_set(UINT8 data, UINT8 mask); + void portb_in_set(UINT8 data, UINT8 mask); + + enum + { + TIMER_END_CALLBACK + }; +}; + +extern const device_type MOS6530; + + +#define MCFG_MOS6530_IN_PA_CB(_devcb) \ + devcb = &mos6530_device::set_in_pa_callback(*device, DEVCB_##_devcb); + +#define MCFG_MOS6530_OUT_PA_CB(_devcb) \ + devcb = &mos6530_device::set_out_pa_callback(*device, DEVCB_##_devcb); + +#define MCFG_MOS6530_IN_PB_CB(_devcb) \ + devcb = &mos6530_device::set_in_pb_callback(*device, DEVCB_##_devcb); + +#define MCFG_MOS6530_OUT_PB_CB(_devcb) \ + devcb = &mos6530_device::set_out_pb_callback(*device, DEVCB_##_devcb); + + +#endif diff --git a/src/devices/machine/mos6530n.c b/src/devices/machine/mos6530n.c new file mode 100644 index 00000000000..58f279f5437 --- /dev/null +++ b/src/devices/machine/mos6530n.c @@ -0,0 +1,844 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + MOS Technology 6530 Memory, I/O, Timer Array emulation + MOS Technology 6532 RAM, I/O, Timer Array emulation + +**********************************************************************/ + +#include "mos6530n.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define LOG 0 +#define LOG_TIMER 0 + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type MOS6530n = &device_creator; +const device_type MOS6532n = &device_creator; + + +DEVICE_ADDRESS_MAP_START( rom_map, 8, mos6530_t ) + ADDRESS_MAP_GLOBAL_MASK(0x3ff) + AM_RANGE(0x000, 0x3ff) AM_READ(rom_r) +ADDRESS_MAP_END + +DEVICE_ADDRESS_MAP_START( ram_map, 8, mos6530_t ) + ADDRESS_MAP_GLOBAL_MASK(0x3f) + AM_RANGE(0x00, 0x3f) AM_READWRITE(ram_r, ram_w) +ADDRESS_MAP_END + +DEVICE_ADDRESS_MAP_START( io_map, 8, mos6530_t ) + ADDRESS_MAP_GLOBAL_MASK(0xf) + AM_RANGE(0x00, 0x00) AM_MIRROR(0x8) AM_READWRITE(pa_data_r, pa_data_w) + AM_RANGE(0x01, 0x01) AM_MIRROR(0x8) AM_READWRITE(pa_ddr_r, pa_ddr_w) + AM_RANGE(0x02, 0x02) AM_MIRROR(0x8) AM_READWRITE(pb_data_r, pb_data_w) + AM_RANGE(0x03, 0x03) AM_MIRROR(0x8) AM_READWRITE(pb_ddr_r, pb_ddr_w) + AM_RANGE(0x04, 0x07) AM_WRITE(timer_off_w) + AM_RANGE(0x0c, 0x0f) AM_WRITE(timer_on_w) + AM_RANGE(0x04, 0x04) AM_MIRROR(0x2) AM_READ(timer_off_r) + AM_RANGE(0x0c, 0x0c) AM_MIRROR(0x2) AM_READ(timer_on_r) + AM_RANGE(0x05, 0x05) AM_MIRROR(0xa) AM_READ(irq_r) +ADDRESS_MAP_END + +DEVICE_ADDRESS_MAP_START( ram_map, 8, mos6532_t ) + ADDRESS_MAP_GLOBAL_MASK(0x7f) + AM_RANGE(0x00, 0x7f) AM_READWRITE(ram_r, ram_w) +ADDRESS_MAP_END + +DEVICE_ADDRESS_MAP_START( io_map, 8, mos6532_t ) + ADDRESS_MAP_GLOBAL_MASK(0x1f) + AM_RANGE(0x00, 0x00) AM_MIRROR(0x18) AM_READWRITE(pa_data_r, pa_data_w) + AM_RANGE(0x01, 0x01) AM_MIRROR(0x18) AM_READWRITE(pa_ddr_r, pa_ddr_w) + AM_RANGE(0x02, 0x02) AM_MIRROR(0x18) AM_READWRITE(pb_data_r, pb_data_w) + AM_RANGE(0x03, 0x03) AM_MIRROR(0x18) AM_READWRITE(pb_ddr_r, pb_ddr_w) + AM_RANGE(0x14, 0x17) AM_WRITE(timer_off_w) + AM_RANGE(0x1c, 0x1f) AM_WRITE(timer_on_w) + AM_RANGE(0x04, 0x04) AM_MIRROR(0x12) AM_READ(timer_off_r) + AM_RANGE(0x0c, 0x0c) AM_MIRROR(0x12) AM_READ(timer_on_r) + AM_RANGE(0x05, 0x05) AM_MIRROR(0x1a) AM_READ(irq_r) + AM_RANGE(0x04, 0x07) AM_MIRROR(0x8) AM_WRITE(edge_w) +ADDRESS_MAP_END + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// mos6530_base_t - constructor +//------------------------------------------------- + +mos6530_base_t::mos6530_base_t(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + m_ram(*this), + m_irq_cb(*this), + m_in_pa_cb(*this), + m_out_pa_cb(*this), + m_in_pb_cb(*this), + m_out_pb_cb(*this), + m_in_pa0_cb(*this), + m_in_pa1_cb(*this), + m_in_pa2_cb(*this), + m_in_pa3_cb(*this), + m_in_pa4_cb(*this), + m_in_pa5_cb(*this), + m_in_pa6_cb(*this), + m_in_pa7_cb(*this), + m_out_pa0_cb(*this), + m_out_pa1_cb(*this), + m_out_pa2_cb(*this), + m_out_pa3_cb(*this), + m_out_pa4_cb(*this), + m_out_pa5_cb(*this), + m_out_pa6_cb(*this), + m_out_pa7_cb(*this), + m_in_pb0_cb(*this), + m_in_pb1_cb(*this), + m_in_pb2_cb(*this), + m_in_pb3_cb(*this), + m_in_pb4_cb(*this), + m_in_pb5_cb(*this), + m_in_pb6_cb(*this), + m_in_pb7_cb(*this), + m_out_pb0_cb(*this), + m_out_pb1_cb(*this), + m_out_pb2_cb(*this), + m_out_pb3_cb(*this), + m_out_pb4_cb(*this), + m_out_pb5_cb(*this), + m_out_pb6_cb(*this), + m_out_pb7_cb(*this), + m_pa_in(0xff), + m_pa_out(0), + m_pa_ddr(0), + m_pa7(0), + m_pa7_dir(0), + m_pb_in(0xff), + m_pb_out(0), + m_pb_ddr(0), + m_ie_timer(false), + m_irq_timer(true), + m_ie_edge(false), + m_irq_edge(false) +{ + cur_live.tm = attotime::never; + cur_live.state = IDLE; + cur_live.next_state = -1; +} + + +//------------------------------------------------- +// mos6530_t - constructor +//------------------------------------------------- + +mos6530_t::mos6530_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : mos6530_base_t(mconfig, MOS6530n, "MOS6530n", tag, owner, clock, "mos6530n", __FILE__) { } + + +//------------------------------------------------- +// mos6532_t - constructor +//------------------------------------------------- + +mos6532_t::mos6532_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : mos6530_base_t(mconfig, MOS6532n, "MOS6532n", tag, owner, clock, "mos6532n", __FILE__) { } + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void mos6530_base_t::device_start() +{ + // resolve callbacks + m_irq_cb.resolve_safe(); + m_in_pa_cb.resolve(); + m_out_pa_cb.resolve(); + m_in_pb_cb.resolve(); + m_out_pb_cb.resolve(); + m_in_pa0_cb.resolve(); + m_in_pa1_cb.resolve(); + m_in_pa2_cb.resolve(); + m_in_pa3_cb.resolve(); + m_in_pa4_cb.resolve(); + m_in_pa5_cb.resolve(); + m_in_pa6_cb.resolve(); + m_in_pa7_cb.resolve(); + m_out_pa0_cb.resolve_safe(); + m_out_pa1_cb.resolve_safe(); + m_out_pa2_cb.resolve_safe(); + m_out_pa3_cb.resolve_safe(); + m_out_pa4_cb.resolve_safe(); + m_out_pa5_cb.resolve_safe(); + m_out_pa6_cb.resolve_safe(); + m_out_pa7_cb.resolve_safe(); + m_in_pb0_cb.resolve(); + m_in_pb1_cb.resolve(); + m_in_pb2_cb.resolve(); + m_in_pb3_cb.resolve(); + m_in_pb4_cb.resolve(); + m_in_pb5_cb.resolve(); + m_in_pb6_cb.resolve(); + m_in_pb7_cb.resolve(); + m_out_pb0_cb.resolve_safe(); + m_out_pb1_cb.resolve_safe(); + m_out_pb2_cb.resolve_safe(); + m_out_pb3_cb.resolve_safe(); + m_out_pb4_cb.resolve_safe(); + m_out_pb5_cb.resolve_safe(); + m_out_pb6_cb.resolve_safe(); + m_out_pb7_cb.resolve_safe(); + + // allocate timer + t_gen = timer_alloc(0); + + // state saving + save_item(NAME(m_pa_in)); + save_item(NAME(m_pa_out)); + save_item(NAME(m_pa_ddr)); + save_item(NAME(m_pa7)); + save_item(NAME(m_pa7_dir)); + save_item(NAME(m_pb_in)); + save_item(NAME(m_pb_out)); + save_item(NAME(m_pb_ddr)); + save_item(NAME(m_ie_timer)); + save_item(NAME(m_irq_timer)); + save_item(NAME(m_ie_edge)); + save_item(NAME(m_irq_edge)); + save_item(NAME(m_prescale)); + save_item(NAME(m_timer)); +} + +void mos6530_t::device_start() +{ + mos6530_base_t::device_start(); + + // allocate RAM + m_ram.allocate(0x40); +} + +void mos6532_t::device_start() +{ + mos6530_base_t::device_start(); + + // allocate RAM + m_ram.allocate(0x80); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void mos6530_base_t::device_reset() +{ + m_pa_out = 0; + m_pa_ddr = 0; + m_pb_out = 0; + m_pb_ddr = 0; + + m_ie_timer = false; + m_irq_timer = false; + m_ie_edge = false; + m_irq_edge = false; + m_pa7_dir = 0; + + update_pa(); + update_pb(); + update_irq(); + edge_detect(); + + m_timer = 0xff; + m_prescale = 1024; + + if (cur_live.state != IDLE) { + live_abort(); + } + + live_start(); + live_run(); +} + + +//------------------------------------------------- +// device_timer - handler timer events +//------------------------------------------------- + +void mos6530_base_t::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + live_sync(); + live_run(); +} + + +//------------------------------------------------- +// update_pa - +//------------------------------------------------- + +void mos6530_base_t::update_pa() +{ + UINT8 out = m_pa_out; + UINT8 ddr = m_pa_ddr; + UINT8 data = (out & ddr) | (ddr ^ 0xff); + + if (m_out_pa_cb.isnull()) + { + m_out_pa0_cb(BIT(data, 0)); + m_out_pa1_cb(BIT(data, 1)); + m_out_pa2_cb(BIT(data, 2)); + m_out_pa3_cb(BIT(data, 3)); + m_out_pa4_cb(BIT(data, 4)); + m_out_pa5_cb(BIT(data, 5)); + m_out_pa6_cb(BIT(data, 6)); + m_out_pa7_cb(BIT(data, 7)); + } + else + { + m_out_pa_cb(data); + } +} + + +//------------------------------------------------- +// update_pb - +//------------------------------------------------- + +void mos6530_base_t::update_pb() +{ + UINT8 out = m_pb_out; + UINT8 ddr = m_pb_ddr; + UINT8 data = (out & ddr) | (ddr ^ 0xff); + + if (m_out_pb_cb.isnull()) + { + m_out_pb0_cb(BIT(data, 0)); + m_out_pb1_cb(BIT(data, 1)); + m_out_pb2_cb(BIT(data, 2)); + m_out_pb3_cb(BIT(data, 3)); + m_out_pb4_cb(BIT(data, 4)); + m_out_pb5_cb(BIT(data, 5)); + m_out_pb6_cb(BIT(data, 6)); + m_out_pb7_cb(BIT(data, 7)); + } + else + { + m_out_pb_cb(data); + } +} + +void mos6530_t::update_pb() +{ + UINT8 out = m_pb_out; + UINT8 ddr = m_pb_ddr; + UINT8 data = (out & ddr) | (ddr ^ 0xff); + + if (m_ie_timer) + { + if (m_irq_timer) { + data |= IRQ_TIMER; + } else { + data &= ~IRQ_TIMER; + } + } + + if (m_out_pb_cb.isnull()) + { + m_out_pb0_cb(BIT(data, 0)); + m_out_pb1_cb(BIT(data, 1)); + m_out_pb2_cb(BIT(data, 2)); + m_out_pb3_cb(BIT(data, 3)); + m_out_pb4_cb(BIT(data, 4)); + m_out_pb5_cb(BIT(data, 5)); + m_out_pb6_cb(BIT(data, 6)); + m_out_pb7_cb(BIT(data, 7)); + } + else + { + m_out_pb_cb(data); + } +} + + +//------------------------------------------------- +// update_irq - +//------------------------------------------------- + +void mos6530_base_t::update_irq() +{ + int state = CLEAR_LINE; + + if (m_ie_timer && m_irq_timer) state = ASSERT_LINE; + if (m_ie_edge && m_irq_edge) state = ASSERT_LINE; + + m_irq_cb(state); +} + +void mos6530_t::update_irq() +{ + update_pb(); +} + + +//------------------------------------------------- +// get_irq_flags - +//------------------------------------------------- + +UINT8 mos6530_base_t::get_irq_flags() +{ + UINT8 data = 0; + + if (m_irq_timer) data |= IRQ_TIMER; + if (m_irq_edge) data |= IRQ_EDGE; + + return data; +} + +UINT8 mos6530_t::get_irq_flags() +{ + UINT8 data = 0; + + if (m_irq_timer) data |= IRQ_TIMER; + + return data; +} + + +//------------------------------------------------- +// edge_detect - +//------------------------------------------------- + +void mos6530_base_t::edge_detect() +{ + UINT8 ddr_out = m_pa_ddr; + UINT8 ddr_in = m_pa_ddr ^ 0xff; + UINT8 data = (m_pa_out & ddr_out) | (m_pa_in & ddr_in); + int state = BIT(data, 7); + + if ((m_pa7 ^ state) && (m_pa7_dir ^ state) == 0) + { + if (LOG) logerror("%s %s '%s' edge-detect IRQ\n", machine().time().as_string(), name(), tag()); + + m_irq_edge = true; + update_irq(); + } + + m_pa7 = state; +} + + +//------------------------------------------------- +// pa_w - +//------------------------------------------------- + +void mos6530_base_t::pa_w(int bit, int state) +{ + if (LOG) logerror("%s %s %s '%s' Port A Data Bit %u State %u\n", machine().time().as_string(), machine().describe_context(), name(), tag(), bit, state); + + m_pa_in &= ~(1 << bit); + m_pa_in |= (state << bit); + + edge_detect(); +} + + +//------------------------------------------------- +// pb_w - +//------------------------------------------------- + +void mos6530_base_t::pb_w(int bit, int state) +{ + if (LOG) logerror("%s %s %s '%s' Port B Data Bit %u State %u\n", machine().time().as_string(), machine().describe_context(), name(), tag(), bit, state); + + m_pb_in &= ~(1 << bit); + m_pb_in |= (state << bit); +} + + +//------------------------------------------------- +// pa_data_r - +//------------------------------------------------- + +READ8_MEMBER( mos6530_base_t::pa_data_r ) +{ + UINT8 in = 0; + + if (m_in_pa_cb.isnull()) + { + in |= (m_in_pa0_cb.isnull() ? BIT(m_pa_in, 0) : m_in_pa0_cb()); + in |= (m_in_pa1_cb.isnull() ? BIT(m_pa_in, 1) : m_in_pa1_cb()) << 1; + in |= (m_in_pa2_cb.isnull() ? BIT(m_pa_in, 2) : m_in_pa2_cb()) << 2; + in |= (m_in_pa3_cb.isnull() ? BIT(m_pa_in, 3) : m_in_pa3_cb()) << 3; + in |= (m_in_pa4_cb.isnull() ? BIT(m_pa_in, 4) : m_in_pa4_cb()) << 4; + in |= (m_in_pa5_cb.isnull() ? BIT(m_pa_in, 5) : m_in_pa5_cb()) << 5; + in |= (m_in_pa6_cb.isnull() ? BIT(m_pa_in, 6) : m_in_pa6_cb()) << 6; + in |= (m_in_pa7_cb.isnull() ? BIT(m_pa_in, 7) : m_in_pa7_cb()) << 7; + } + else + { + in = m_in_pa_cb(); + } + + UINT8 out = m_pa_out; + UINT8 ddr_out = m_pa_ddr; + UINT8 ddr_in = m_pa_ddr ^ 0xff; + UINT8 data = (out & ddr_out) | (in & ddr_in); + + if (LOG) logerror("%s %s %s '%s' Port A Data In %02x\n", machine().time().as_string(), machine().describe_context(), name(), tag(), data); + + return data; +} + + +//------------------------------------------------- +// pa_data_w - +//------------------------------------------------- + +WRITE8_MEMBER( mos6530_base_t::pa_data_w ) +{ + m_pa_out = data; + + if (LOG) logerror("%s %s %s '%s' Port A Data Out %02x\n", machine().time().as_string(), machine().describe_context(), name(), tag(), data); + + update_pa(); + edge_detect(); +} + + +//------------------------------------------------- +// pa_ddr_w - +//------------------------------------------------- + +WRITE8_MEMBER( mos6530_base_t::pa_ddr_w ) +{ + m_pa_ddr = data; + + if (LOG) logerror("%s %s %s '%s' Port A DDR %02x\n", machine().time().as_string(), machine().describe_context(), name(), tag(), data); + + update_pa(); + edge_detect(); +} + + +//------------------------------------------------- +// pb_data_r - +//------------------------------------------------- + +READ8_MEMBER( mos6530_base_t::pb_data_r ) +{ + UINT8 in = 0; + + if (m_in_pb_cb.isnull()) + { + in |= (m_in_pb0_cb.isnull() ? BIT(m_pb_in, 0) : m_in_pb0_cb()); + in |= (m_in_pb1_cb.isnull() ? BIT(m_pb_in, 1) : m_in_pb1_cb()) << 1; + in |= (m_in_pb2_cb.isnull() ? BIT(m_pb_in, 2) : m_in_pb2_cb()) << 2; + in |= (m_in_pb3_cb.isnull() ? BIT(m_pb_in, 3) : m_in_pb3_cb()) << 3; + in |= (m_in_pb4_cb.isnull() ? BIT(m_pb_in, 4) : m_in_pb4_cb()) << 4; + in |= (m_in_pb5_cb.isnull() ? BIT(m_pb_in, 5) : m_in_pb5_cb()) << 5; + in |= (m_in_pb6_cb.isnull() ? BIT(m_pb_in, 6) : m_in_pb6_cb()) << 6; + in |= (m_in_pb7_cb.isnull() ? BIT(m_pb_in, 7) : m_in_pb7_cb()) << 7; + } + else + { + in = m_in_pb_cb(); + } + + UINT8 out = m_pb_out; + UINT8 ddr_out = m_pb_ddr; + UINT8 ddr_in = m_pb_ddr ^ 0xff; + UINT8 data = (out & ddr_out) | (in & ddr_in); + + if (LOG) logerror("%s %s %s '%s' Port B Data In %02x\n", machine().time().as_string(), machine().describe_context(), name(), tag(), data); + + return data; +} + + +//------------------------------------------------- +// pb_data_w - +//------------------------------------------------- + +WRITE8_MEMBER( mos6530_base_t::pb_data_w ) +{ + m_pb_out = data; + + if (LOG) logerror("%s %s %s '%s' Port B Data Out %02x\n", machine().time().as_string(), machine().describe_context(), name(), tag(), data); + + update_pb(); +} + + +//------------------------------------------------- +// pb_ddr_w - +//------------------------------------------------- + +WRITE8_MEMBER( mos6530_base_t::pb_ddr_w ) +{ + m_pb_ddr = data; + + if (LOG) logerror("%s %s %s '%s' Port B DDR %02x\n", machine().time().as_string(), machine().describe_context(), name(), tag(), data); + + update_pb(); +} + + +//------------------------------------------------- +// timer_r - +//------------------------------------------------- + +READ8_MEMBER( mos6530_base_t::timer_off_r ) +{ + if (space.debugger_access()) + return 0; + + return timer_r(false); +} + +READ8_MEMBER( mos6530_base_t::timer_on_r ) +{ + if (space.debugger_access()) + return 0; + + return timer_r(true); +} + +UINT8 mos6530_base_t::timer_r(bool ie) +{ + UINT8 data = 0; + + live_sync(); + + m_ie_timer = ie; + if (cur_live.tm_irq != machine().time()) { + m_irq_timer = false; + } + update_irq(); + + data = cur_live.value; + + if (LOG_TIMER) logerror("%s %s %s '%s' Timer read %02x IE %u\n", machine().time().as_string(), machine().describe_context(), name(), tag(), data, m_ie_timer ? 1 : 0); + + checkpoint(); + live_run(); + + return data; +} + + +//------------------------------------------------- +// irq_r - +//------------------------------------------------- + +READ8_MEMBER( mos6530_base_t::irq_r ) +{ + UINT8 data = get_irq_flags(); + + if (!space.debugger_access()) { + if (m_irq_edge) { + m_irq_edge = false; + update_irq(); + } + } + + return data; +} + + +//------------------------------------------------- +// timer_w - +//------------------------------------------------- + +WRITE8_MEMBER( mos6530_base_t::timer_off_w ) +{ + timer_w(offset, data, false); +} + +WRITE8_MEMBER( mos6530_base_t::timer_on_w ) +{ + timer_w(offset, data, true); +} + +void mos6530_base_t::timer_w(offs_t offset, UINT8 data, bool ie) +{ + live_sync(); + + m_timer = data; + + switch (offset & 0x03) { + case 0: m_prescale = 1; break; + case 1: m_prescale = 8; break; + case 2: m_prescale = 64; break; + case 3: m_prescale = 1024; break; + } + + m_ie_timer = ie; + if (cur_live.tm_irq != machine().time()) { + m_irq_timer = false; + } + update_irq(); + + if (LOG_TIMER) logerror("%s %s %s '%s' Timer value %02x prescale %u IE %u\n", machine().time().as_string(), machine().describe_context(), name(), tag(), data, m_prescale, m_ie_timer ? 1 : 0); + + checkpoint(); + + if (cur_live.state != IDLE) { + live_abort(); + } + + live_start(); + live_run(); +} + + +//------------------------------------------------- +// edge_w - +//------------------------------------------------- + +WRITE8_MEMBER( mos6530_base_t::edge_w ) +{ + m_pa7_dir = BIT(data, 0); + m_ie_edge = BIT(data, 1) ? false : true; + + if (LOG) logerror("%s %s %s '%s' %s edge-detect, %s interrupt\n", machine().time().as_string(), machine().describe_context(), name(), tag(), m_pa7_dir ? "positive" : "negative", m_ie_edge ? "enable" : "disable"); +} + + +//------------------------------------------------- +// live_start - +//------------------------------------------------- + +void mos6530_base_t::live_start() +{ + cur_live.period = attotime::from_ticks(m_prescale, clock()); + cur_live.tm = machine().time() + attotime::from_hz(clock()); + cur_live.state = RUNNING; + cur_live.next_state = -1; + + cur_live.value = m_timer; + + checkpoint(); + + live_run(); +} + +void mos6530_base_t::checkpoint() +{ + checkpoint_live = cur_live; +} + +void mos6530_base_t::rollback() +{ + cur_live = checkpoint_live; +} + +void mos6530_base_t::live_delay(int state) +{ + cur_live.next_state = state; + if(cur_live.tm != machine().time()) + t_gen->adjust(cur_live.tm - machine().time()); + else + live_sync(); +} + +void mos6530_base_t::live_sync() +{ + if(!cur_live.tm.is_never()) { + if(cur_live.tm > machine().time()) { + rollback(); + live_run(machine().time()); + } else { + if(cur_live.next_state != -1) { + cur_live.state = cur_live.next_state; + cur_live.next_state = -1; + } + if(cur_live.state == IDLE) { + cur_live.tm = attotime::never; + } + } + cur_live.next_state = -1; + checkpoint(); + } +} + +void mos6530_base_t::live_abort() +{ + if(!cur_live.tm.is_never() && cur_live.tm > machine().time()) { + rollback(); + live_run(machine().time()); + } + + cur_live.tm = attotime::never; + cur_live.state = IDLE; + cur_live.next_state = -1; + cur_live.tm_irq = attotime::never; +} + +void mos6530_base_t::live_run(const attotime &limit) +{ + if(cur_live.state == IDLE || cur_live.next_state != -1) + return; + + for(;;) { + switch(cur_live.state) { + case RUNNING: { + if (cur_live.tm > limit) + return; + + cur_live.value--; + + if (cur_live.value == 0xff) { + live_delay(RUNNING_SYNCPOINT); + return; + } else { + if (LOG_TIMER) logerror("%s %s '%s' timer %02x\n", cur_live.tm.as_string(), name(), tag(), cur_live.value); + + cur_live.tm += cur_live.period; + } + break; + } + + case RUNNING_SYNCPOINT: { + if (LOG_TIMER) logerror("%s %s '%s' timer %02x interrupt\n", cur_live.tm.as_string(), name(), tag(), cur_live.value); + + cur_live.tm_irq = cur_live.tm; + m_irq_timer = true; + update_irq(); + + checkpoint(); + + cur_live.state = RUNNING_AFTER_INTERRUPT; + cur_live.period = attotime::from_hz(clock()); + cur_live.tm += cur_live.period; + break; + } + + case RUNNING_AFTER_INTERRUPT: { + if (cur_live.tm > limit) + return; + + cur_live.value--; + + if (LOG_TIMER) logerror("%s %s '%s' timer %02x\n", cur_live.tm.as_string(), name(), tag(), cur_live.value); + + if (!cur_live.value) { + cur_live.state = IDLE; + return; + } + + cur_live.tm += cur_live.period; + break; + } + } + } +} diff --git a/src/devices/machine/mos6530n.h b/src/devices/machine/mos6530n.h new file mode 100644 index 00000000000..01044ac7c7b --- /dev/null +++ b/src/devices/machine/mos6530n.h @@ -0,0 +1,415 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + MOS Technology 6530 Memory, I/O, Timer Array emulation + MOS Technology 6532 RAM, I/O, Timer Array emulation + +********************************************************************** + _____ _____ + Vss 1 |* \_/ | 40 PA1 + PA0 2 | | 39 PA2 + phi2 3 | | 38 PA3 + RS0 4 | | 37 PA4 + A9 5 | | 36 PA5 + A8 6 | | 35 PA6 + A7 7 | | 34 PA7 + A6 8 | | 33 DB0 + R/W 9 | | 32 DB1 + A5 10 | MCS6530 | 31 DB2 + A4 11 | | 30 DB3 + A3 12 | | 29 DB4 + A2 13 | | 28 DB5 + A1 14 | | 27 DB6 + A0 15 | | 26 DB7 + _RES 16 | | 25 PB0 + IRQ/PB7 17 | | 24 PB1 + CS1/PB6 18 | | 23 PB2 + CS2/PB5 19 | | 22 PB3 + Vcc 20 |_____________| 21 PB4 + + _____ _____ + Vss 1 |* \_/ | 40 A6 + A5 2 | | 39 phi2 + A4 3 | | 38 CS1 + A3 4 | | 37 _CS2 + A2 5 | | 36 _RS + A1 6 | | 35 R/W + A0 7 | | 34 _RES + PA0 8 | | 33 D0 + PA1 9 | | 32 D1 + PA2 10 | MCS6532 | 31 D2 + PA3 11 | | 30 D3 + PA4 12 | | 29 D4 + PA5 13 | | 28 D5 + PA6 14 | | 27 D6 + PA7 15 | | 26 D7 + PB7 16 | | 25 _IRQ + PB6 17 | | 24 PB0 + PB5 18 | | 23 PB1 + PB4 19 | | 22 PB2 + Vcc 20 |_____________| 21 PB3 + +**********************************************************************/ + +#pragma once + +#ifndef __MOS6530n__ +#define __MOS6530n__ + +#include "emu.h" + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_MOS6530n_IRQ_CB(_write) \ + devcb = &mos6530_base_t::set_irq_wr_callback(*device, DEVCB_##_write); + +#define MCFG_MOS6530n_IN_PA_CB(_read) \ + devcb = &mos6530_base_t::set_pa_rd_callback(*device, DEVCB_##_read); + +#define MCFG_MOS6530n_OUT_PA_CB(_write) \ + devcb = &mos6530_base_t::set_pa_wr_callback(*device, DEVCB_##_write); + +#define MCFG_MOS6530n_IN_PB_CB(_read) \ + devcb = &mos6530_base_t::set_pb_rd_callback(*device, DEVCB_##_read); + +#define MCFG_MOS6530n_OUT_PB_CB(_write) \ + devcb = &mos6530_base_t::set_pb_wr_callback(*device, DEVCB_##_write); + +#define MCFG_MOS6530n_IN_PA0_CB(_read) \ + devcb = &mos6530_base_t::set_pa0_rd_callback(*device, DEVCB_##_read); + +#define MCFG_MOS6530n_IN_PA1_CB(_read) \ + devcb = &mos6530_base_t::set_pa1_rd_callback(*device, DEVCB_##_read); + +#define MCFG_MOS6530n_IN_PA2_CB(_read) \ + devcb = &mos6530_base_t::set_pa2_rd_callback(*device, DEVCB_##_read); + +#define MCFG_MOS6530n_IN_PA3_CB(_read) \ + devcb = &mos6530_base_t::set_pa3_rd_callback(*device, DEVCB_##_read); + +#define MCFG_MOS6530n_IN_PA4_CB(_read) \ + devcb = &mos6530_base_t::set_pa4_rd_callback(*device, DEVCB_##_read); + +#define MCFG_MOS6530n_IN_PA5_CB(_read) \ + devcb = &mos6530_base_t::set_pa5_rd_callback(*device, DEVCB_##_read); + +#define MCFG_MOS6530n_IN_PA6_CB(_read) \ + devcb = &mos6530_base_t::set_pa6_rd_callback(*device, DEVCB_##_read); + +#define MCFG_MOS6530n_IN_PA7_CB(_read) \ + devcb = &mos6530_base_t::set_pa7_rd_callback(*device, DEVCB_##_read); + +#define MCFG_MOS6530n_OUT_PA0_CB(_write) \ + devcb = &mos6530_base_t::set_pa0_wr_callback(*device, DEVCB_##_write); + +#define MCFG_MOS6530n_OUT_PA1_CB(_write) \ + devcb = &mos6530_base_t::set_pa1_wr_callback(*device, DEVCB_##_write); + +#define MCFG_MOS6530n_OUT_PA2_CB(_write) \ + devcb = &mos6530_base_t::set_pa2_wr_callback(*device, DEVCB_##_write); + +#define MCFG_MOS6530n_OUT_PA3_CB(_write) \ + devcb = &mos6530_base_t::set_pa3_wr_callback(*device, DEVCB_##_write); + +#define MCFG_MOS6530n_OUT_PA4_CB(_write) \ + devcb = &mos6530_base_t::set_pa4_wr_callback(*device, DEVCB_##_write); + +#define MCFG_MOS6530n_OUT_PA5_CB(_write) \ + devcb = &mos6530_base_t::set_pa5_wr_callback(*device, DEVCB_##_write); + +#define MCFG_MOS6530n_OUT_PA6_CB(_write) \ + devcb = &mos6530_base_t::set_pa6_wr_callback(*device, DEVCB_##_write); + +#define MCFG_MOS6530n_OUT_PA7_CB(_write) \ + devcb = &mos6530_base_t::set_pa7_wr_callback(*device, DEVCB_##_write); + +#define MCFG_MOS6530n_IN_PB0_CB(_read) \ + devcb = &mos6530_base_t::set_pb0_rd_callback(*device, DEVCB_##_read); + +#define MCFG_MOS6530n_IN_PB1_CB(_read) \ + devcb = &mos6530_base_t::set_pb1_rd_callback(*device, DEVCB_##_read); + +#define MCFG_MOS6530n_IN_PB2_CB(_read) \ + devcb = &mos6530_base_t::set_pb2_rd_callback(*device, DEVCB_##_read); + +#define MCFG_MOS6530n_IN_PB3_CB(_read) \ + devcb = &mos6530_base_t::set_pb3_rd_callback(*device, DEVCB_##_read); + +#define MCFG_MOS6530n_IN_PB4_CB(_read) \ + devcb = &mos6530_base_t::set_pb4_rd_callback(*device, DEVCB_##_read); + +#define MCFG_MOS6530n_IN_PB5_CB(_read) \ + devcb = &mos6530_base_t::set_pb5_rd_callback(*device, DEVCB_##_read); + +#define MCFG_MOS6530n_IN_PB6_CB(_read) \ + devcb = &mos6530_base_t::set_pb6_rd_callback(*device, DEVCB_##_read); + +#define MCFG_MOS6530n_IN_PB7_CB(_read) \ + devcb = &mos6530_base_t::set_pb7_rd_callback(*device, DEVCB_##_read); + +#define MCFG_MOS6530n_OUT_PB0_CB(_write) \ + devcb = &mos6530_base_t::set_pb0_wr_callback(*device, DEVCB_##_write); + +#define MCFG_MOS6530n_OUT_PB1_CB(_write) \ + devcb = &mos6530_base_t::set_pb1_wr_callback(*device, DEVCB_##_write); + +#define MCFG_MOS6530n_OUT_PB2_CB(_write) \ + devcb = &mos6530_base_t::set_pb2_wr_callback(*device, DEVCB_##_write); + +#define MCFG_MOS6530n_OUT_PB3_CB(_write) \ + devcb = &mos6530_base_t::set_pb3_wr_callback(*device, DEVCB_##_write); + +#define MCFG_MOS6530n_OUT_PB4_CB(_write) \ + devcb = &mos6530_base_t::set_pb4_wr_callback(*device, DEVCB_##_write); + +#define MCFG_MOS6530n_OUT_PB5_CB(_write) \ + devcb = &mos6530_base_t::set_pb5_wr_callback(*device, DEVCB_##_write); + +#define MCFG_MOS6530n_OUT_PB6_CB(_write) \ + devcb = &mos6530_base_t::set_pb6_wr_callback(*device, DEVCB_##_write); + +#define MCFG_MOS6530n_OUT_PB7_CB(_write) \ + devcb = &mos6530_base_t::set_pb7_wr_callback(*device, DEVCB_##_write); + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> mos6530_base_t + +class mos6530_base_t : public device_t +{ +public: + // construction/destruction + mos6530_base_t(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + template static devcb_base &set_irq_wr_callback(device_t &device, _Object object) { return downcast(device).m_irq_cb.set_callback(object); } + template static devcb_base &set_pa_rd_callback(device_t &device, _Object object) { return downcast(device).m_in_pa_cb.set_callback(object); } + template static devcb_base &set_pa_wr_callback(device_t &device, _Object object) { return downcast(device).m_out_pa_cb.set_callback(object); } + template static devcb_base &set_pb_rd_callback(device_t &device, _Object object) { return downcast(device).m_in_pb_cb.set_callback(object); } + template static devcb_base &set_pb_wr_callback(device_t &device, _Object object) { return downcast(device).m_out_pb_cb.set_callback(object); } + template static devcb_base &set_pa0_rd_callback(device_t &device, _Object object) { return downcast(device).m_in_pa0_cb.set_callback(object); } + template static devcb_base &set_pa1_rd_callback(device_t &device, _Object object) { return downcast(device).m_in_pa1_cb.set_callback(object); } + template static devcb_base &set_pa2_rd_callback(device_t &device, _Object object) { return downcast(device).m_in_pa2_cb.set_callback(object); } + template static devcb_base &set_pa3_rd_callback(device_t &device, _Object object) { return downcast(device).m_in_pa3_cb.set_callback(object); } + template static devcb_base &set_pa4_rd_callback(device_t &device, _Object object) { return downcast(device).m_in_pa4_cb.set_callback(object); } + template static devcb_base &set_pa5_rd_callback(device_t &device, _Object object) { return downcast(device).m_in_pa5_cb.set_callback(object); } + template static devcb_base &set_pa6_rd_callback(device_t &device, _Object object) { return downcast(device).m_in_pa6_cb.set_callback(object); } + template static devcb_base &set_pa7_rd_callback(device_t &device, _Object object) { return downcast(device).m_in_pa7_cb.set_callback(object); } + template static devcb_base &set_pa0_wr_callback(device_t &device, _Object object) { return downcast(device).m_out_pa0_cb.set_callback(object); } + template static devcb_base &set_pa1_wr_callback(device_t &device, _Object object) { return downcast(device).m_out_pa1_cb.set_callback(object); } + template static devcb_base &set_pa2_wr_callback(device_t &device, _Object object) { return downcast(device).m_out_pa2_cb.set_callback(object); } + template static devcb_base &set_pa3_wr_callback(device_t &device, _Object object) { return downcast(device).m_out_pa3_cb.set_callback(object); } + template static devcb_base &set_pa4_wr_callback(device_t &device, _Object object) { return downcast(device).m_out_pa4_cb.set_callback(object); } + template static devcb_base &set_pa5_wr_callback(device_t &device, _Object object) { return downcast(device).m_out_pa5_cb.set_callback(object); } + template static devcb_base &set_pa6_wr_callback(device_t &device, _Object object) { return downcast(device).m_out_pa6_cb.set_callback(object); } + template static devcb_base &set_pa7_wr_callback(device_t &device, _Object object) { return downcast(device).m_out_pa7_cb.set_callback(object); } + template static devcb_base &set_pb0_rd_callback(device_t &device, _Object object) { return downcast(device).m_in_pb0_cb.set_callback(object); } + template static devcb_base &set_pb1_rd_callback(device_t &device, _Object object) { return downcast(device).m_in_pb1_cb.set_callback(object); } + template static devcb_base &set_pb2_rd_callback(device_t &device, _Object object) { return downcast(device).m_in_pb2_cb.set_callback(object); } + template static devcb_base &set_pb3_rd_callback(device_t &device, _Object object) { return downcast(device).m_in_pb3_cb.set_callback(object); } + template static devcb_base &set_pb4_rd_callback(device_t &device, _Object object) { return downcast(device).m_in_pb4_cb.set_callback(object); } + template static devcb_base &set_pb5_rd_callback(device_t &device, _Object object) { return downcast(device).m_in_pb5_cb.set_callback(object); } + template static devcb_base &set_pb6_rd_callback(device_t &device, _Object object) { return downcast(device).m_in_pb6_cb.set_callback(object); } + template static devcb_base &set_pb7_rd_callback(device_t &device, _Object object) { return downcast(device).m_in_pb7_cb.set_callback(object); } + template static devcb_base &set_pb0_wr_callback(device_t &device, _Object object) { return downcast(device).m_out_pb0_cb.set_callback(object); } + template static devcb_base &set_pb1_wr_callback(device_t &device, _Object object) { return downcast(device).m_out_pb1_cb.set_callback(object); } + template static devcb_base &set_pb2_wr_callback(device_t &device, _Object object) { return downcast(device).m_out_pb2_cb.set_callback(object); } + template static devcb_base &set_pb3_wr_callback(device_t &device, _Object object) { return downcast(device).m_out_pb3_cb.set_callback(object); } + template static devcb_base &set_pb4_wr_callback(device_t &device, _Object object) { return downcast(device).m_out_pb4_cb.set_callback(object); } + template static devcb_base &set_pb5_wr_callback(device_t &device, _Object object) { return downcast(device).m_out_pb5_cb.set_callback(object); } + template static devcb_base &set_pb6_wr_callback(device_t &device, _Object object) { return downcast(device).m_out_pb6_cb.set_callback(object); } + template static devcb_base &set_pb7_wr_callback(device_t &device, _Object object) { return downcast(device).m_out_pb7_cb.set_callback(object); } + + DECLARE_WRITE_LINE_MEMBER( pa0_w ) { pa_w(0, state); } + DECLARE_WRITE_LINE_MEMBER( pa1_w ) { pa_w(1, state); } + DECLARE_WRITE_LINE_MEMBER( pa2_w ) { pa_w(2, state); } + DECLARE_WRITE_LINE_MEMBER( pa3_w ) { pa_w(3, state); } + DECLARE_WRITE_LINE_MEMBER( pa4_w ) { pa_w(4, state); } + DECLARE_WRITE_LINE_MEMBER( pa5_w ) { pa_w(5, state); } + DECLARE_WRITE_LINE_MEMBER( pa6_w ) { pa_w(6, state); } + DECLARE_WRITE_LINE_MEMBER( pa7_w ) { pa_w(7, state); } + + DECLARE_WRITE_LINE_MEMBER( pb0_w ) { pb_w(0, state); } + DECLARE_WRITE_LINE_MEMBER( pb1_w ) { pb_w(1, state); } + DECLARE_WRITE_LINE_MEMBER( pb2_w ) { pb_w(2, state); } + DECLARE_WRITE_LINE_MEMBER( pb3_w ) { pb_w(3, state); } + DECLARE_WRITE_LINE_MEMBER( pb4_w ) { pb_w(4, state); } + DECLARE_WRITE_LINE_MEMBER( pb5_w ) { pb_w(5, state); } + DECLARE_WRITE_LINE_MEMBER( pb6_w ) { pb_w(6, state); } + DECLARE_WRITE_LINE_MEMBER( pb7_w ) { pb_w(7, state); } + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + enum + { + IRQ_EDGE = 0x40, + IRQ_TIMER = 0x80 + }; + + void update_pa(); + virtual void update_pb(); + virtual void update_irq(); + virtual UINT8 get_irq_flags(); + void edge_detect(); + void pa_w(int bit, int state); + void pb_w(int bit, int state); + void timer_w(offs_t offset, UINT8 data, bool ie); + UINT8 timer_r(bool ie); + + DECLARE_READ8_MEMBER( rom_r ) { return m_region->base()[offset]; } + DECLARE_READ8_MEMBER( ram_r ) { return m_ram[offset]; } + DECLARE_WRITE8_MEMBER( ram_w ) { m_ram[offset] = data; } + DECLARE_READ8_MEMBER( pa_data_r ); + DECLARE_WRITE8_MEMBER( pa_data_w ); + DECLARE_READ8_MEMBER( pb_data_r ); + DECLARE_WRITE8_MEMBER( pb_data_w ); + DECLARE_READ8_MEMBER( pa_ddr_r ) { return m_pa_ddr; } + DECLARE_WRITE8_MEMBER( pa_ddr_w ); + DECLARE_READ8_MEMBER( pb_ddr_r ) { return m_pb_ddr; } + DECLARE_WRITE8_MEMBER( pb_ddr_w ); + DECLARE_READ8_MEMBER( timer_off_r ); + DECLARE_READ8_MEMBER( timer_on_r ); + DECLARE_READ8_MEMBER( irq_r ); + DECLARE_WRITE8_MEMBER( timer_off_w ); + DECLARE_WRITE8_MEMBER( timer_on_w ); + DECLARE_WRITE8_MEMBER( edge_w ); + + optional_shared_ptr m_ram; + + devcb_write_line m_irq_cb; + devcb_read8 m_in_pa_cb; + devcb_write8 m_out_pa_cb; + devcb_read8 m_in_pb_cb; + devcb_write8 m_out_pb_cb; + devcb_read_line m_in_pa0_cb; + devcb_read_line m_in_pa1_cb; + devcb_read_line m_in_pa2_cb; + devcb_read_line m_in_pa3_cb; + devcb_read_line m_in_pa4_cb; + devcb_read_line m_in_pa5_cb; + devcb_read_line m_in_pa6_cb; + devcb_read_line m_in_pa7_cb; + devcb_write_line m_out_pa0_cb; + devcb_write_line m_out_pa1_cb; + devcb_write_line m_out_pa2_cb; + devcb_write_line m_out_pa3_cb; + devcb_write_line m_out_pa4_cb; + devcb_write_line m_out_pa5_cb; + devcb_write_line m_out_pa6_cb; + devcb_write_line m_out_pa7_cb; + devcb_read_line m_in_pb0_cb; + devcb_read_line m_in_pb1_cb; + devcb_read_line m_in_pb2_cb; + devcb_read_line m_in_pb3_cb; + devcb_read_line m_in_pb4_cb; + devcb_read_line m_in_pb5_cb; + devcb_read_line m_in_pb6_cb; + devcb_read_line m_in_pb7_cb; + devcb_write_line m_out_pb0_cb; + devcb_write_line m_out_pb1_cb; + devcb_write_line m_out_pb2_cb; + devcb_write_line m_out_pb3_cb; + devcb_write_line m_out_pb4_cb; + devcb_write_line m_out_pb5_cb; + devcb_write_line m_out_pb6_cb; + devcb_write_line m_out_pb7_cb; + + UINT8 m_pa_in; + UINT8 m_pa_out; + UINT8 m_pa_ddr; + int m_pa7; + int m_pa7_dir; + + UINT8 m_pb_in; + UINT8 m_pb_out; + UINT8 m_pb_ddr; + + bool m_ie_timer; + bool m_irq_timer; + bool m_ie_edge; + bool m_irq_edge; + + int m_prescale; + UINT8 m_timer; + + enum { + IDLE, + RUNNING, + RUNNING_SYNCPOINT, + RUNNING_AFTER_INTERRUPT + }; + + struct live_info { + attotime tm, tm_irq; + attotime period; + int state, next_state; + UINT8 value; + }; + + live_info cur_live, checkpoint_live; + emu_timer *t_gen; + + void live_start(); + void checkpoint(); + void rollback(); + void live_delay(int state); + void live_sync(); + void live_abort(); + void live_run(const attotime &limit = attotime::never); +}; + + +class mos6530_t : public mos6530_base_t +{ +public: + // construction/destruction + mos6530_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual DECLARE_ADDRESS_MAP(rom_map, 8); + virtual DECLARE_ADDRESS_MAP(ram_map, 8); + virtual DECLARE_ADDRESS_MAP(io_map, 8); + +protected: + // device-level overrides + virtual void device_start(); + + void update_pb(); + void update_irq(); + UINT8 get_irq_flags(); +}; + + +class mos6532_t : public mos6530_base_t +{ +public: + // construction/destruction + mos6532_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual DECLARE_ADDRESS_MAP(ram_map, 8); + virtual DECLARE_ADDRESS_MAP(io_map, 8); + +protected: + // device-level overrides + virtual void device_start(); +}; + + +// device type definition +extern const device_type MOS6530n; +extern const device_type MOS6532n; + + + +#endif diff --git a/src/devices/machine/mos6551.c b/src/devices/machine/mos6551.c new file mode 100644 index 00000000000..6f240799af2 --- /dev/null +++ b/src/devices/machine/mos6551.c @@ -0,0 +1,833 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/********************************************************************** + + MOS Technology 6551 Asynchronous Communication Interface Adapter + +**********************************************************************/ + +#include "mos6551.h" + +#define LOG 0 + +const device_type MOS6551 = &device_creator; + +mos6551_device::mos6551_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, MOS6551, "MOS6551", tag, owner, clock, "mos6551", __FILE__), + m_internal_clock(*this, "clock"), + m_irq_handler(*this), + m_txd_handler(*this), + m_rxc_handler(*this), + m_rts_handler(*this), + m_dtr_handler(*this), + m_control(0), + m_status(0), + m_tdr(0), + m_irq_state(0), + m_irq(0), + m_txd(0), + m_rxc(0), + m_rts(0), + m_dtr(0), + m_xtal(0), + m_divide(0), + m_cts(1), + m_dsr(1), + m_dcd(1), + m_rxd(1), + m_rx_state(STATE_START), + m_rx_clock(0), + m_rx_counter(0), + m_rx_internal_clock(0), + m_tx_state(STATE_START), + m_tx_output(OUTPUT_MARK), + m_tx_clock(0), + m_tx_counter(0) +{ +} + +const int mos6551_device::internal_divider[] = +{ + 1, 2304, 1536, 1048, 856, 768, 384, 192, 96, 64, 48, 32, 24, 16, 12, 6 +}; + +const int mos6551_device::transmitter_controls[4][3] = +{ + //tx irq, tx ena, brk + {0, 0, 0}, + {1, 1, 0}, + {0, 1, 0}, + {0, 1, 1} +}; + +static MACHINE_CONFIG_FRAGMENT( mos6551 ) + MCFG_DEVICE_ADD("clock", CLOCK, 0) + MCFG_CLOCK_SIGNAL_HANDLER(WRITELINE(mos6551_device, internal_clock)) +MACHINE_CONFIG_END + +machine_config_constructor mos6551_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( mos6551 ); +} + +void mos6551_device::device_start() +{ + // resolve callbacks + m_irq_handler.resolve_safe(); + m_txd_handler.resolve_safe(); + m_rxc_handler.resolve_safe(); + m_rts_handler.resolve_safe(); + m_dtr_handler.resolve_safe(); + + // state saving + save_item(NAME(m_control)); + save_item(NAME(m_command)); + save_item(NAME(m_status)); + save_item(NAME(m_tdr)); + save_item(NAME(m_rdr)); + + save_item(NAME(m_irq_state)); + + save_item(NAME(m_irq)); + save_item(NAME(m_txd)); + save_item(NAME(m_rxc)); + save_item(NAME(m_rts)); + save_item(NAME(m_dtr)); + + save_item(NAME(m_xtal)); + save_item(NAME(m_divide)); + save_item(NAME(m_cts)); + save_item(NAME(m_dsr)); + save_item(NAME(m_dcd)); + save_item(NAME(m_rxd)); + + save_item(NAME(m_wordlength)); + save_item(NAME(m_extrastop)); + save_item(NAME(m_brk)); + save_item(NAME(m_echo_mode)); + save_item(NAME(m_parity)); + + save_item(NAME(m_rx_state)); + save_item(NAME(m_rx_clock)); + save_item(NAME(m_rx_bits)); + save_item(NAME(m_rx_shift)); + save_item(NAME(m_rx_parity)); + save_item(NAME(m_rx_counter)); + save_item(NAME(m_rx_irq_enable)); + save_item(NAME(m_rx_internal_clock)); + + save_item(NAME(m_tx_state)); + save_item(NAME(m_tx_output)); + save_item(NAME(m_tx_clock)); + save_item(NAME(m_tx_bits)); + save_item(NAME(m_tx_shift)); + save_item(NAME(m_tx_parity)); + save_item(NAME(m_tx_counter)); + save_item(NAME(m_tx_enable)); + save_item(NAME(m_tx_irq_enable)); + save_item(NAME(m_tx_internal_clock)); + + m_internal_clock->set_unscaled_clock(m_xtal); + + output_irq(1); + output_txd(1); + output_rxc(1); + output_rts(1); + output_dtr(1); +} + +void mos6551_device::device_reset() +{ + m_status = SR_TDRE; + + if (m_dsr) + { + m_status |= SR_DSR; + } + + if (m_dcd) + { + m_status |= SR_DCD; + } + + m_rx_state = STATE_START; + m_rx_counter = 0; + + write_command(0); + write_control(0); +} + +void mos6551_device::output_irq(int irq) +{ + if (m_irq != irq) + { + m_irq = irq; + + if (m_irq) + { + m_status &= ~SR_IRQ; + } + else + { + m_status |= SR_IRQ; + } + + m_irq_handler(!m_irq); + } +} + +void mos6551_device::output_txd(int txd) +{ + switch (m_tx_output) + { + case OUTPUT_MARK: + txd = 1; + break; + + case OUTPUT_BREAK: + txd = 0; + break; + } + + if (m_txd != txd) + { + m_txd = txd; + m_txd_handler(m_txd); + } +} + +void mos6551_device::output_rxc(int rxc) +{ + if (m_rxc != rxc) + { + m_rxc = rxc; + m_rxc_handler(m_rxc); + } +} + +void mos6551_device::output_rts(int rts) +{ + if (m_rts != rts) + { + m_rts = rts; + m_rts_handler(m_rts); + } +} + +void mos6551_device::output_dtr(int dtr) +{ + if (m_dtr != dtr) + { + m_dtr = dtr; + m_dtr_handler(m_dtr); + } +} + +void mos6551_device::update_irq() +{ + if (m_irq_state != 0) + { + output_irq(0); + } + else + { + output_irq(1); + } +} + +void mos6551_device::update_divider() +{ + // bits 0-3 + double scale = internal_divider[(m_control >> 0) & 0xf]; + + // The 6551 allows an external clock (hooked up to xtal1 with xtal2 floating) with the internal clock generator, + // it is unknown whether it allows a xtal (hooked up to xtal1 & xtal2) to be used as an external clock. It is + // allowed here for performance reasons. + if (m_xtal != 0) + { + m_tx_internal_clock = true; + + m_divide = 16; + + if (!m_dtr || m_rx_state != STATE_START) + { + scale = (double) 1 / scale; + } + else + { + scale = 0; + } + } + else + { + m_tx_internal_clock = false; + + m_divide = scale * 16; + scale = 0; + } + + m_internal_clock->set_clock_scale(scale); +} + +UINT8 mos6551_device::read_rdr() +{ + m_status &= ~(SR_PARITY_ERROR | SR_FRAMING_ERROR | SR_OVERRUN | SR_RDRF); + return m_rdr; +} + +UINT8 mos6551_device::read_status() +{ + UINT8 status = m_status; + + if (m_cts) + { + status &= ~SR_TDRE; + } + + if (m_irq_state != 0) + { + m_irq_state = 0; + update_irq(); + } + + return status; +} + +UINT8 mos6551_device::read_command() +{ + return m_command; +} + +UINT8 mos6551_device::read_control() +{ + return m_control; +} + +void mos6551_device::write_tdr(UINT8 data) +{ + m_tdr = data; + m_status &= ~SR_TDRE; +} + +void mos6551_device::write_reset(UINT8 data) +{ + m_status &= ~SR_OVERRUN; + m_irq_state &= ~(IRQ_DCD | IRQ_DSR); + + write_command(m_command & ~0x1f); +} + +void mos6551_device::write_control(UINT8 data) +{ + m_control = data; + + update_divider(); + + // bit 4 + m_rx_internal_clock = (m_control >> 4) & 1; + + // bits 5-6 + m_wordlength = 8 - ((m_control >> 5) & 3); + + // bit 7 + m_extrastop = (m_control >> 7) & 1; + + if (!m_rx_internal_clock) + { + output_rxc(1); + } +} + +void mos6551_device::write_command(UINT8 data) +{ + m_command = data; + + // bit 0 + output_dtr(!((m_command >> 0) & 1)); + + // bit 1 + m_rx_irq_enable = !((m_command >> 1) & 1) && !m_dtr; + + // bits 2-3 + int transmitter_control = (m_command >> 2) & 3; + m_tx_irq_enable = transmitter_controls[transmitter_control][0] && !m_dtr; + m_tx_enable = transmitter_controls[transmitter_control][1]; + m_brk = transmitter_controls[transmitter_control][2]; + + // bit 4 + m_echo_mode = (m_command >> 4) & 1; + + // bits 5-7 + m_parity = (m_command >> 5) & 7; + if (!(m_parity & 1)) + { + m_parity = PARITY_NONE; + } + + output_rts(!(m_tx_enable || m_echo_mode)); + + if (m_dtr || m_rts) + { + m_tx_output = OUTPUT_MARK; + output_txd(1); + } + + update_divider(); +} + +READ8_MEMBER( mos6551_device::read ) +{ + if (space.debugger_access()) + return 0xff; + + switch (offset & 0x03) + { + case 0: + return read_rdr(); + + case 1: + return read_status(); + + case 2: + return read_command(); + + case 3: + default: + return read_control(); + } +} + +WRITE8_MEMBER( mos6551_device::write ) +{ + switch (offset & 0x03) + { + case 0: + write_tdr(data); + break; + + case 1: + write_reset(data); + break; + + case 2: + write_command(data); + break; + + case 3: + write_control(data); + break; + } +} + +int mos6551_device::stoplength() +{ + if (m_extrastop == 1) + { + if (m_wordlength == 5 && m_parity == PARITY_NONE) + { + return m_divide + (m_divide / 2); + } + + if (m_wordlength < 8 || m_parity == PARITY_NONE) + { + return m_divide * 2; + } + } + + return m_divide; +} + +void mos6551_device::set_xtal(UINT32 xtal) +{ + m_xtal = xtal; + + if (started()) + { + m_internal_clock->set_unscaled_clock(m_xtal); + update_divider(); + } +} + +WRITE_LINE_MEMBER( mos6551_device::internal_clock ) +{ + if (m_tx_internal_clock) + { + transmitter_clock(state); + } +} + +WRITE_LINE_MEMBER(mos6551_device::write_xtal1) +{ + if (!m_tx_internal_clock) + { + transmitter_clock(state); + } +} + +WRITE_LINE_MEMBER( mos6551_device::write_rxd ) +{ + m_rxd = state; +} + +WRITE_LINE_MEMBER( mos6551_device::write_rxc ) +{ + if (!m_rx_internal_clock) + { + receiver_clock(state); + } +} + +WRITE_LINE_MEMBER( mos6551_device::write_cts ) +{ + if (m_cts != state) + { + m_cts = state; + + if (m_cts) + { + if (m_tx_output == OUTPUT_TXD) + { + m_tx_output = OUTPUT_MARK; + output_txd(1); + } + } + } +} + +WRITE_LINE_MEMBER( mos6551_device::write_dsr ) +{ + if (m_dsr != state) + { + m_dsr = state; + } +} + +WRITE_LINE_MEMBER( mos6551_device::write_dcd ) +{ + if (m_dcd != state) + { + m_dcd = state; + } +} + +WRITE_LINE_MEMBER(mos6551_device::receiver_clock) +{ + if (m_rx_clock != state) + { + m_rx_clock = state; + + if (m_rx_clock) + { + /// TODO: find out whether this should be here or in write_dcd + if ((m_irq_state & IRQ_DCD) == 0 && !m_dcd != !(m_status & SR_DCD)) + { + m_status ^= SR_DCD; + + if (!m_dtr) + { + m_irq_state |= IRQ_DCD; + update_irq(); + } + } + + /// TODO: find out whether this should be here or in write_dsr + if ((m_irq_state & IRQ_DSR) == 0 && !m_dsr != !(m_status & SR_DSR)) + { + m_status ^= SR_DSR; + + if (!m_dtr) + { + m_irq_state |= IRQ_DSR; + update_irq(); + } + } + + m_rx_counter++; + + switch (m_rx_state) + { + case STATE_START: + if (m_rx_counter == 1) + { + if (!m_rxd && !m_dtr) + { + if (LOG) logerror("MOS6551 '%s': RX START BIT\n", tag()); + } + else + { + m_rx_counter = 0; + } + } + + if (m_rx_counter >= m_divide / 2) + { + if (!m_rxd) + { + m_rx_state = STATE_DATA; + m_rx_counter = 0; + m_rx_shift = 0; + m_rx_parity = 0; + m_rx_bits = 0; + } + else + { + m_rx_counter = 0; + + if (LOG) logerror("MOS6551 '%s': RX FALSE START BIT\n", tag()); + } + } + break; + + case STATE_DATA: + if (m_rx_counter == m_divide) + { + m_rx_counter = 0; + + if (m_rx_bits < m_wordlength) + { + if (LOG) logerror("MOS6551 '%s': RX DATA BIT %d %d\n", tag(), m_rx_bits, m_rxd); + } + else + { + if (LOG) logerror("MOS6551 '%s': RX PARITY BIT %x\n", tag(), m_rxd); + } + + if (m_rxd) + { + m_rx_shift |= 1 << m_rx_bits; + } + + m_rx_bits++; + + m_rx_parity ^= m_rxd; + + if ((m_rx_bits == m_wordlength && m_parity == PARITY_NONE) || + (m_rx_bits == (m_wordlength + 1) && m_parity != PARITY_NONE)) + { + m_rx_state = STATE_STOP; + } + } + break; + + case STATE_STOP: + if (m_rx_counter >= stoplength()) + { + m_rx_counter = 0; + + if (LOG) logerror("MOS6551 '%s': RX STOP BIT\n", tag()); + + if (!(m_status & SR_RDRF)) + { + if (!m_rxd) + { + m_status |= SR_FRAMING_ERROR; + } + + if ((m_parity == PARITY_ODD && !m_rx_parity) || + (m_parity == PARITY_EVEN && m_rx_parity)) + { + m_status |= SR_PARITY_ERROR; + } + + m_rdr = m_rx_shift; + + if (m_wordlength == 7 && m_parity != PARITY_NONE) + { + m_rdr &= 0x7f; + } + + m_status |= SR_RDRF; + } + else + { + m_status |= SR_OVERRUN; + } + + if (m_rx_irq_enable) + { + m_irq_state |= IRQ_RDRF; + update_irq(); + } + + m_rx_state = STATE_START; + + if (m_dtr) + { + update_divider(); + } + } + break; + } + } + } +} + +WRITE_LINE_MEMBER(mos6551_device::transmitter_clock) +{ + if (m_rx_internal_clock) + { + output_rxc(state); + receiver_clock(state); + } + + if (m_tx_clock != state) + { + m_tx_clock = state; + + if (!m_tx_clock && !m_dtr) + { + if (m_echo_mode) + { + if (!(m_status & SR_OVERRUN)) + { + output_txd(m_rxd); + } + else + { + output_txd(1); + } + } + + if (m_tx_enable) + { + if (!m_cts && m_tx_output == OUTPUT_MARK && !(m_status & SR_TDRE)) + { + m_tx_state = STATE_START; + m_tx_counter = 0; + } + + m_tx_counter++; + + switch (m_tx_state) + { + case STATE_START: + m_tx_counter = 0; + + m_tx_state = STATE_DATA; + m_tx_shift = m_tdr; + m_tx_bits = 0; + m_tx_parity = 0; + + if (m_cts) + { + m_tx_output = OUTPUT_MARK; + } + else if (!(m_status & SR_TDRE)) + { + if (LOG) logerror("MOS6551 '%s': TX DATA %x\n", tag(), m_tdr); + + m_tx_output = OUTPUT_TXD; + + if (LOG) logerror("MOS6551 '%s': TX START BIT\n", tag()); + + m_status |= SR_TDRE; + } + else if (m_brk) + { + m_tx_output = OUTPUT_BREAK; + + if (LOG) logerror("MOS6551 '%s': TX BREAK START\n", tag()); + } + else + { + m_tx_output = OUTPUT_MARK; + } + + if (m_tx_irq_enable && m_tx_output != OUTPUT_BREAK) + { + m_irq_state |= IRQ_TDRE; + update_irq(); + } + + output_txd(0); + break; + + case STATE_DATA: + if (m_tx_counter == m_divide) + { + m_tx_counter = 0; + + if (m_tx_bits < m_wordlength) + { + output_txd((m_tx_shift >> m_tx_bits) & 1); + + m_tx_bits++; + m_tx_parity ^= m_txd; + + if (m_tx_output == OUTPUT_TXD) + { + if (LOG) logerror("MOS6551 '%s': TX DATA BIT %d %d\n", tag(), m_tx_bits, m_txd); + } + } + else if (m_tx_bits == m_wordlength && m_parity != PARITY_NONE) + { + m_tx_bits++; + + switch (m_parity) + { + case PARITY_ODD: + m_tx_parity = !m_tx_parity; + break; + + case PARITY_MARK: + m_tx_parity = 1; + break; + + case PARITY_SPACE: + m_tx_parity = 0; + break; + } + + output_txd(m_tx_parity); + + if (m_tx_output == OUTPUT_TXD) + { + if (LOG) logerror("MOS6551 '%s': TX PARITY BIT %d\n", tag(), m_txd); + } + } + else + { + m_tx_state = STATE_STOP; + + output_txd(1); + + if (m_tx_output == OUTPUT_TXD) + { + if (LOG) logerror("MOS6551 '%s': TX STOP BIT\n", tag()); + } + } + } + break; + + case STATE_STOP: + if (m_tx_counter >= stoplength()) + { + if (m_tx_output == OUTPUT_BREAK) + { + if (!m_brk) + { + if (LOG) logerror("MOS6551 '%s': TX BREAK END\n", tag()); + + m_tx_counter = 0; + m_tx_state = STATE_STOP; + m_tx_output = OUTPUT_TXD; + + output_txd(1); + } + else + { + m_tx_counter--; + } + } + else + { + m_tx_state = STATE_START; + m_tx_counter = 0; + } + } + break; + } + } + } + } +} diff --git a/src/devices/machine/mos6551.h b/src/devices/machine/mos6551.h new file mode 100644 index 00000000000..7ba7d6bc7f3 --- /dev/null +++ b/src/devices/machine/mos6551.h @@ -0,0 +1,212 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/********************************************************************** + + MOS Technology 6551 Asynchronous Communication Interface Adapter + +********************************************************************** + _____ _____ + GND 1 |* \_/ | 28 R/_W + CS0 2 | | 27 phi2 + _CS1 3 | | 26 _IRQ + _RES 4 | | 25 DB7 + RxC 5 | | 24 DB6 + XTAL1 6 | | 23 DB5 + XTAL2 7 | MOS6551 | 22 DB4 + _RTS 8 | | 21 DB3 + _CTS 9 | | 20 DB2 + TxD 10 | | 19 DB1 + _DTR 11 | | 18 DB0 + RxD 12 | | 17 _DBR + RS0 13 | | 16 _DCD + RS1 14 |_____________| 15 Vcc + +**********************************************************************/ + +#pragma once + +#ifndef __MOS6551__ +#define __MOS6551__ + +#include "emu.h" +#include "machine/clock.h" + +#define MCFG_MOS6551_XTAL(_xtal) \ + mos6551_device::set_xtal(*device, _xtal); + +#define MCFG_MOS6551_IRQ_HANDLER(_devcb) \ + devcb = &mos6551_device::set_irq_handler(*device, DEVCB_##_devcb); + +#define MCFG_MOS6551_TXD_HANDLER(_devcb) \ + devcb = &mos6551_device::set_txd_handler(*device, DEVCB_##_devcb); + +#define MCFG_MOS6551_RXC_HANDLER(_devcb) \ + devcb = &mos6551_device::set_rxc_handler(*device, DEVCB_##_devcb); + +#define MCFG_MOS6551_RTS_HANDLER(_devcb) \ + devcb = &mos6551_device::set_rts_handler(*device, DEVCB_##_devcb); + +#define MCFG_MOS6551_DTR_HANDLER(_devcb) \ + devcb = &mos6551_device::set_dtr_handler(*device, DEVCB_##_devcb); + +class mos6551_device : public device_t +{ +public: + mos6551_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + static void set_xtal(device_t &device, UINT32 xtal) { downcast(device).set_xtal(xtal); } + template static devcb_base &set_irq_handler(device_t &device, _Object object) { return downcast(device).m_irq_handler.set_callback(object); } + template static devcb_base &set_txd_handler(device_t &device, _Object object) { return downcast(device).m_txd_handler.set_callback(object); } + template static devcb_base &set_rxc_handler(device_t &device, _Object object) { return downcast(device).m_rxc_handler.set_callback(object); } + template static devcb_base &set_rts_handler(device_t &device, _Object object) { return downcast(device).m_rts_handler.set_callback(object); } + template static devcb_base &set_dtr_handler(device_t &device, _Object object) { return downcast(device).m_dtr_handler.set_callback(object); } + + DECLARE_READ8_MEMBER(read); + DECLARE_WRITE8_MEMBER(write); + + DECLARE_WRITE_LINE_MEMBER(write_xtal1); // txc + DECLARE_WRITE_LINE_MEMBER(write_rxd); + DECLARE_WRITE_LINE_MEMBER(write_rxc); + DECLARE_WRITE_LINE_MEMBER(write_cts); + DECLARE_WRITE_LINE_MEMBER(write_dsr); + DECLARE_WRITE_LINE_MEMBER(write_dcd); + + DECLARE_WRITE_LINE_MEMBER(internal_clock); + + void set_xtal(UINT32 clock); + +protected: + virtual void device_start(); + virtual void device_reset(); + virtual machine_config_constructor device_mconfig_additions() const; + +private: + enum + { + SR_PARITY_ERROR = 0x01, + SR_FRAMING_ERROR = 0x02, + SR_OVERRUN = 0x04, + SR_RDRF = 0x08, + SR_TDRE = 0x10, + SR_DCD = 0x20, + SR_DSR = 0x40, + SR_IRQ = 0x80 + }; + + enum + { + PARITY_NONE = 0, + PARITY_ODD = 1, + PARITY_EVEN = 3, + PARITY_MARK = 5, + PARITY_SPACE = 7 + }; + + enum + { + IRQ_DCD = 1, + IRQ_DSR = 2, + IRQ_RDRF = 4, + IRQ_TDRE = 8, + IRQ_CTS = 16 + }; + + enum + { + STATE_START, + STATE_DATA, + STATE_STOP + }; + + enum + { + OUTPUT_TXD, + OUTPUT_MARK, + OUTPUT_BREAK + }; + + void output_irq(int irq); + void output_txd(int txd); + void output_rxc(int rxc); + void output_rts(int rts); + void output_dtr(int dtr); + + void update_irq(); + void update_divider(); + + UINT8 read_rdr(); + UINT8 read_status(); + UINT8 read_command(); + UINT8 read_control(); + + void write_tdr(UINT8 data); + void write_reset(UINT8 data); + void write_command(UINT8 data); + void write_control(UINT8 data); + + int stoplength(); + + DECLARE_WRITE_LINE_MEMBER(receiver_clock); + DECLARE_WRITE_LINE_MEMBER(transmitter_clock); + + static const int internal_divider[16]; + static const int transmitter_controls[4][3]; + + required_device m_internal_clock; + devcb_write_line m_irq_handler; + devcb_write_line m_txd_handler; + devcb_write_line m_rxc_handler; + devcb_write_line m_rts_handler; + devcb_write_line m_dtr_handler; + + UINT8 m_control; + UINT8 m_command; + UINT8 m_status; + UINT8 m_tdr; + UINT8 m_rdr; + + UINT8 m_irq_state; + + int m_irq; + int m_txd; + int m_rxc; + int m_rts; + int m_dtr; + + UINT32 m_xtal; + int m_divide; + int m_cts; + int m_dsr; + int m_dcd; + int m_rxd; + + int m_wordlength; + int m_extrastop; + int m_brk; + int m_echo_mode; + int m_parity; + + int m_rx_state; + int m_rx_clock; + int m_rx_bits; + int m_rx_shift; + int m_rx_parity; + int m_rx_counter; + int m_rx_irq_enable; + int m_rx_internal_clock; + + int m_tx_state; + int m_tx_output; + int m_tx_clock; + int m_tx_bits; + int m_tx_shift; + int m_tx_parity; + int m_tx_counter; + int m_tx_enable; + int m_tx_irq_enable; + int m_tx_internal_clock; +}; + +extern const device_type MOS6551; + +#endif diff --git a/src/devices/machine/mos6702.c b/src/devices/machine/mos6702.c new file mode 100644 index 00000000000..9dc11e24af9 --- /dev/null +++ b/src/devices/machine/mos6702.c @@ -0,0 +1,68 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + MOS Technology 6702 Mystery Device emulation + +**********************************************************************/ + +#include "mos6702.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define LOG 0 + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type MOS6702 = &device_creator; + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// mos6702_device - constructor +//------------------------------------------------- + +mos6702_device::mos6702_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, MOS6702, "MOS6702", tag, owner, clock, "mos6702", __FILE__) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void mos6702_device::device_start() +{ +} + + +//------------------------------------------------- +// read - +//------------------------------------------------- + +READ8_MEMBER( mos6702_device::read ) +{ + return 0; +} + + +//------------------------------------------------- +// write - +//------------------------------------------------- + +WRITE8_MEMBER( mos6702_device::write ) +{ +} diff --git a/src/devices/machine/mos6702.h b/src/devices/machine/mos6702.h new file mode 100644 index 00000000000..d0675e5140b --- /dev/null +++ b/src/devices/machine/mos6702.h @@ -0,0 +1,66 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + MOS Technology 6702 Mystery Device emulation + +********************************************************************** + _____ _____ + R/_W 1 |* \_/ | 20 Vcc + D7 2 | | 19 CS0 + D6 3 | | 18 CS1 + D5 4 | | 17 CS2 + D4 5 | MOS6702 | 16 CS3 + D3 6 | | 15 _CS4 + D2 7 | | 14 _CS5 + D1 8 | | 13 _CS5 + D0 9 | | 12 _RTS + Vss 10 |_____________| 11 phi2 + +**********************************************************************/ + +#pragma once + +#ifndef __MOS6702__ +#define __MOS6702__ + +#include "emu.h" + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_MOS6702_ADD(_tag, _clock) \ + MCFG_DEVICE_ADD(_tag, MOS6702, _clock) + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> mos6702_device + +class mos6702_device : public device_t +{ +public: + // construction/destruction + mos6702_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + DECLARE_READ8_MEMBER( read ); + DECLARE_WRITE8_MEMBER( write ); + +protected: + // device-level overrides + virtual void device_start(); +}; + + +// device type definition +extern const device_type MOS6702; + + + +#endif diff --git a/src/devices/machine/mos8706.c b/src/devices/machine/mos8706.c new file mode 100644 index 00000000000..ca07506423b --- /dev/null +++ b/src/devices/machine/mos8706.c @@ -0,0 +1,78 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + MOS 8706 Speech Glue Logic ASIC emulation + +**********************************************************************/ + +#include "mos8706.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define LOG 0 + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +// device type definition +const device_type MOS8706 = &device_creator; + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// mos8706_device - constructor +//------------------------------------------------- + +mos8706_device::mos8706_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, MOS8706, "MOS8706", tag, owner, clock, "mos8706", __FILE__) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void mos8706_device::device_start() +{ +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void mos8706_device::device_reset() +{ +} + + +//------------------------------------------------- +// read - +//------------------------------------------------- + +READ8_MEMBER( mos8706_device::read ) +{ + return 0; +} + + +//------------------------------------------------- +// write - +//------------------------------------------------- + +WRITE8_MEMBER( mos8706_device::write ) +{ +} diff --git a/src/devices/machine/mos8706.h b/src/devices/machine/mos8706.h new file mode 100644 index 00000000000..070c592b9fe --- /dev/null +++ b/src/devices/machine/mos8706.h @@ -0,0 +1,70 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + MOS 8706 Speech Glue Logic ASIC emulation + +********************************************************************** + _____ _____ + _RES 1 |* \_/ | 28 Vdd + _IRQ 2 | | 27 D0 + R/_W 3 | | 26 T6721A D0 + phi0 4 | | 25 D1 + _CS 5 | | 24 T6721A D1 + A0 6 | | 23 D2 + A1 7 | MOS8706 | 22 T6721A D2 + 8 | | 21 D3 + _EOS 9 | | 20 T6721A D3 + APD 10 | | 19 D4 + phi2 11 | | 18 D5 + DI 12 | | 17 D6 + DTRD 13 | | 16 D7 + GND 14 |_____________| 15 _WR + +**********************************************************************/ + +#pragma once + +#ifndef __MOS8706__ +#define __MOS8706__ + +#include "emu.h" + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_MOS8706_ADD(_tag, _clock) \ + MCFG_DEVICE_ADD((_tag), MOS8706, _clock) + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> mos8706_device + +class mos8706_device : public device_t +{ +public: + mos8706_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + DECLARE_READ8_MEMBER( read ); + DECLARE_WRITE8_MEMBER( write ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); +}; + + +// device type definition +extern const device_type MOS8706; + + + +#endif diff --git a/src/devices/machine/mos8722.c b/src/devices/machine/mos8722.c new file mode 100644 index 00000000000..31b2beb1f27 --- /dev/null +++ b/src/devices/machine/mos8722.c @@ -0,0 +1,366 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + MOS Technology 8722 Memory Management Unit emulation + +**********************************************************************/ + +#include "mos8722.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type MOS8722 = &device_creator; + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define LOG 0 + + +#define CR_IO BIT(m_reg[CR], 0) +#define CR_ROM_LO BIT(m_reg[CR], 1) +#define CR_ROM_MID ((m_reg[CR] >> 2) & 0x03) +#define CR_ROM_HI ((m_reg[CR] >> 4) & 0x03) +#define CR_A16 BIT(m_reg[CR], 6) + + +// mode configuration register +#define MCR_8500 BIT(m_reg[MCR], 0) +#define MCR_FSDIR BIT(m_reg[MCR], 3) +#define MCR_GAME BIT(m_reg[MCR], 4) +#define MCR_EXROM BIT(m_reg[MCR], 5) +#define MCR_C64 BIT(m_reg[MCR], 6) +#define MCR_40_80 BIT(m_reg[MCR], 7) + + +// RAM configuration register +static const offs_t RCR_BOTTOM_ADDRESS[4] = { 0x0400, 0x1000, 0x0400, 0x1000 }; +static const offs_t RCR_TOP_ADDRESS[4] = { 0xf000, 0xf000, 0xe000, 0xc000 }; + +#define RCR_SHARE (m_reg[RCR] & 0x03) +#define RCR_BOTTOM BIT(m_reg[RCR], 2) +#define RCR_TOP BIT(m_reg[RCR], 3) +#define RCR_VA16 BIT(m_reg[RCR], 6) + + +// page 0 pointer register +#define P0H_A16 BIT(m_reg[P0H], 0) + + +// page 1 pointer register +#define P1H_A16 BIT(m_reg[P1H], 0) + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// mos8722_device - constructor +//------------------------------------------------- + +mos8722_device::mos8722_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, MOS8722, "MOS8722", tag, owner, clock, "mos8722", __FILE__), + m_write_z80en(*this), + m_write_fsdir(*this), + m_read_game(*this), + m_read_exrom(*this), + m_read_sense40(*this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void mos8722_device::device_start() +{ + // resolve callbacks + m_write_z80en.resolve_safe(); + m_write_fsdir.resolve_safe(); + m_read_game.resolve_safe(1); + m_read_exrom.resolve_safe(1); + m_read_sense40.resolve_safe(1); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void mos8722_device::device_reset() +{ + for (int i = 0; i < 16; i++) + { + m_reg[i] = 0; + } + + m_reg[P1L] = 0x01; + + m_p0h_latch = 0; + m_p1h_latch = 0; + + m_write_z80en(MCR_8500); + m_write_fsdir(MCR_FSDIR); +} + + +//------------------------------------------------- +// read - register read +//------------------------------------------------- + +UINT8 mos8722_device::read(offs_t offset, UINT8 data) +{ + if (MCR_C64) return data; + + if (!CR_IO && offset >= 0xd500 && offset < 0xd50c) + { + switch (offset & 0x0f) + { + case CR: + data = m_reg[CR] | 0x80; + break; + + case MCR: + data = m_reg[MCR] | 0x06; + + data &= ((m_read_game() << 4) | ~0x10); + data &= ((m_read_exrom() << 5) | ~0x20); + data &= ((m_read_sense40() << 7) | ~0x80); + break; + + case VR: + data = 0x20; + break; + + default: + data = m_reg[offset & 0x0f]; + break; + } + } + else if (offset >= 0xff00 && offset < 0xff05) + { + switch (offset & 0x0f) + { + case CR: + data = m_reg[CR] | 0x80; + break; + + default: + data = m_reg[offset & 0x0f]; + break; + } + } + + return data; +} + + +//------------------------------------------------- +// write - register write +//------------------------------------------------- + +WRITE8_MEMBER( mos8722_device::write ) +{ + if (MCR_C64) return; + + if (!CR_IO && offset >= 0xd500 && offset < 0xd50c) + { + if (LOG) logerror("MOS8722 '%s' Write %01x : %02x\n", tag(), offset & 0x0f, data); + + switch (offset & 0x0f) + { + case CR: + m_reg[CR] = data & 0x7f; + break; + + case PCRA: + case PCRB: + case PCRC: + case PCRD: + m_reg[offset & 0x0f] = data & 0x7f; + break; + + case MCR: + { + int _8500 = MCR_8500; + int fsdir = MCR_FSDIR; + + m_reg[MCR] = data; + + if (_8500 != MCR_8500) m_write_z80en(MCR_8500); + if (fsdir != MCR_FSDIR) m_write_fsdir(MCR_FSDIR); + break; + } + + case RCR: + m_reg[RCR] = data & 0x4f; + break; + + case P0L: + m_reg[P0L] = data; + m_reg[P0H] = m_p0h_latch; + break; + + case P0H: + m_p0h_latch = data & 0x01; + break; + + case P1L: + m_reg[P1L] = data; + m_reg[P1H] = m_p1h_latch; + break; + + case P1H: + m_p1h_latch = data & 0x01; + break; + + default: + m_reg[offset & 0x0f] = data; + } + } + else if (offset >= 0xff00 && offset < 0xff05) + { + if (LOG) logerror("MOS8722 '%s' Write %01x : %02x\n", tag(), offset & 0x0f, data); + + switch (offset & 0x0f) + { + case CR: + m_reg[CR] = data & 0x7f; + break; + + default: + m_reg[CR] = m_reg[offset & 0x0f]; + break; + } + } +} + + +//------------------------------------------------- +// fsdir_r - fast serial direction read +//------------------------------------------------- + +READ_LINE_MEMBER( mos8722_device::fsdir_r ) +{ + return MCR_FSDIR; +} + + +//------------------------------------------------- +// ta_r - translated address read +//------------------------------------------------- + +offs_t mos8722_device::ta_r(offs_t offset, int aec, int *ms0, int *ms1, int *ms2, int *ms3, int *cas0, int *cas1) +{ + offs_t ta; + + *ms0 = 1; + *ms1 = 1; + *ms2 = CR_IO; + *ms3 = !MCR_C64; + + if (aec) + { + // CPU access + ta = offset & 0xff00; + + *cas0 = CR_A16; + *cas1 = !*cas0; + + if (!MCR_C64) + { + if (offset >= 0xff00 && offset < 0xff05) + { + // MMU registers + *cas0 = 1; + *cas1 = 1; + } + else if (!MCR_8500 && !CR_A16 && offset < 0x1000) + { + // Z80 ROM + ta = 0xd000 | (offset & 0xf00); + + *ms0 = 0; + *ms1 = 0; + } + else + { + if (offset < 0x0100) + { + // page 0 pointer + ta = m_reg[P0L] << 8; + + *cas0 = P0H_A16; + *cas1 = !*cas0; + } + else if (offset < 0x0200) + { + // page 1 pointer + ta = m_reg[P1L] << 8; + + *cas0 = P1H_A16; + *cas1 = !*cas0; + } + else if (offset >= 0x4000 && offset < 0x8000) + { + // low ROM + *ms0 = CR_ROM_LO; + *ms1 = CR_ROM_LO; + } + else if (offset >= 0x8000 && offset < 0xc000) + { + // middle ROM + *ms0 = BIT(CR_ROM_MID, 1); + *ms1 = BIT(CR_ROM_MID, 0); + } + else if (offset >= 0xc000) + { + // high ROM + *ms0 = BIT(CR_ROM_HI, 1); + *ms1 = BIT(CR_ROM_HI, 0); + } + + if (*ms0 && *ms1) + { + if ((offset >> 8) == m_reg[P0L]) + { + ta = 0x0000; + } + else if ((offset >> 8) == m_reg[P1L]) + { + ta = 0x0100; + } + } + + if ((RCR_BOTTOM && offset < RCR_BOTTOM_ADDRESS[RCR_SHARE]) || + (RCR_TOP && offset >= RCR_TOP_ADDRESS[RCR_SHARE])) + { + // RAM sharing + *cas0 = 0; + *cas1 = !*cas0; + } + } + } + } + else + { + // VIC access + ta = 0xf000 | (offset & 0xf00); + + *cas0 = RCR_VA16; + *cas1 = !*cas0; + } + + return ta; +} diff --git a/src/devices/machine/mos8722.h b/src/devices/machine/mos8722.h new file mode 100644 index 00000000000..d342781fc4e --- /dev/null +++ b/src/devices/machine/mos8722.h @@ -0,0 +1,154 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + MOS Technology 8722 Memory Management Unit emulation + +********************************************************************** + _____ _____ + Vdd 1 |* \_/ | 48 SENSE40 + _RESET 2 | | 47 (MS3) 128/64 + TA15 3 | | 46 _EXROM + TA14 4 | | 45 _GAME + TA13 5 | | 44 FSDIR + TA12 6 | | 43 _Z80EN + TA11 7 | | 42 D7 + TA10 8 | | 41 D6 + TA9 9 | | 40 D5 + TA8 10 | | 39 D4 + _CAS1 11 | | 38 D3 + _CAS0 12 | MOS8722 | 37 D2 + I/O SEL (MS2) 13 | | 36 D1 + ROMBANK1 (MS1) 14 | | 35 D0 + ROMBANK0 (MS0) 15 | | 34 Vss + AEC 16 | | 33 phi0 + MUX 17 | | 32 R/_W + A0 18 | | 31 A15 + A1 19 | | 30 A14 + A2 20 | | 29 A13 + A3 21 | | 28 A12 + A4/A5 22 | | 27 A11 + A6/A7 23 | | 26 A10 + A8 24 |_____________| 25 A9 + +**********************************************************************/ + +#pragma once + +#ifndef __MOS8722__ +#define __MOS8722__ + +#include "emu.h" + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_MOS8722_Z80EN_CALLBACK(_write) \ + devcb = &mos8722_device::set_z80en_wr_callback(*device, DEVCB_##_write); + +#define MCFG_MOS8722_FSDIR_CALLBACK(_write) \ + devcb = &mos8722_device::set_fsdir_wr_callback(*device, DEVCB_##_write); + +#define MCFG_MOS8722_GAME_CALLBACK(_read) \ + devcb = &mos8722_device::set_game_rd_callback(*device, DEVCB_##_read); + +#define MCFG_MOS8722_EXROM_CALLBACK(_read) \ + devcb = &mos8722_device::set_exrom_rd_callback(*device, DEVCB_##_read); + +#define MCFG_MOS8722_SENSE40_CALLBACK(_read) \ + devcb = &mos8722_device::set_sense40_rd_callback(*device, DEVCB_##_read); + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> mos8722_device + +class mos8722_device : public device_t +{ +public: + // construction/destruction + mos8722_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + template static devcb_base &set_z80en_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_z80en.set_callback(object); } + template static devcb_base &set_fsdir_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_fsdir.set_callback(object); } + template static devcb_base &set_game_rd_callback(device_t &device, _Object object) { return downcast(device).m_read_game.set_callback(object); } + template static devcb_base &set_exrom_rd_callback(device_t &device, _Object object) { return downcast(device).m_read_exrom.set_callback(object); } + template static devcb_base &set_sense40_rd_callback(device_t &device, _Object object) { return downcast(device).m_read_sense40.set_callback(object); } + + + UINT8 read(offs_t offset, UINT8 data); + DECLARE_WRITE8_MEMBER( write ); + + DECLARE_READ_LINE_MEMBER( fsdir_r ); + + offs_t ta_r(offs_t offset, int aec, int *ms0, int *ms1, int *ms2, int *ms3, int *cas0, int *cas1); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + +private: + enum + { + CR = 0, + PCRA, LCRA = PCRA, + PCRB, LCRB = PCRB, + PCRC, LCRC = PCRC, + PCRD, LCRD = PCRD, + MCR, + RCR, + P0L, + P0H, + P1L, + P1H, + VR + }; + + enum + { + CR_IO_SYSTEM_IO = 0, + CR_IO_HI_ROM + }; + + enum + { + CR_ROM_SYSTEM_ROM = 0, + CR_ROM_INT_FUNC_ROM, + CR_ROM_EXT_FUNC_ROM, + CR_ROM_RAM + }; + + enum + { + RCR_SHARE_1K = 0, + RCR_SHARE_4K, + RCR_SHARE_8K, + RCR_SHARE_16K + }; + + devcb_write_line m_write_z80en; + devcb_write_line m_write_fsdir; + devcb_read_line m_read_game; + devcb_read_line m_read_exrom; + devcb_read_line m_read_sense40; + + UINT8 m_reg[16]; + + UINT8 m_p0h_latch; + UINT8 m_p1h_latch; +}; + + +// device type definition +extern const device_type MOS8722; + + + +#endif diff --git a/src/devices/machine/mos8726.c b/src/devices/machine/mos8726.c new file mode 100644 index 00000000000..eca6ada5187 --- /dev/null +++ b/src/devices/machine/mos8726.c @@ -0,0 +1,125 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + MOS 8726R1 DMA Controller emulation + +**********************************************************************/ + +/* + + TODO: + + - all + +*/ + +#include "mos8726.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + + + +//************************************************************************** +// DEVICE TYPE DEFINITIONS +//************************************************************************** + +const device_type MOS8726 = &device_creator; + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// mos8726_device - constructor +//------------------------------------------------- + +mos8726_device::mos8726_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, MOS8726, "MOS8726", tag, owner, clock, "mos8726", __FILE__), + device_execute_interface(mconfig, *this), + m_icount(0), + m_bs(1) +{ } + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void mos8726_device::device_start() +{ + // set our instruction counter + m_icountptr = &m_icount; + + // save state + save_item(NAME(m_bs)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void mos8726_device::device_reset() +{ +} + + +//------------------------------------------------- +// execute_run - +//------------------------------------------------- + +void mos8726_device::execute_run() +{ + do + { + m_icount--; + } while (m_icount > 0); +} + + +//------------------------------------------------- +// read - +//------------------------------------------------- + +READ8_MEMBER( mos8726_device::read ) +{ + UINT8 data = 0; + + return data; +} + + +//------------------------------------------------- +// write - +//------------------------------------------------- + +WRITE8_MEMBER( mos8726_device::write ) +{ +} + + +//------------------------------------------------- +// bs_w - bank select write +//------------------------------------------------- + +WRITE_LINE_MEMBER( mos8726_device::bs_w ) +{ + m_bs = state; +} + + +//------------------------------------------------- +// romsel_r - ROM select read +//------------------------------------------------- + +int mos8726_device::romsel_r(int roml, int romh) +{ + return roml && romh; +} diff --git a/src/devices/machine/mos8726.h b/src/devices/machine/mos8726.h new file mode 100644 index 00000000000..324d99794de --- /dev/null +++ b/src/devices/machine/mos8726.h @@ -0,0 +1,98 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + MOS 8726R1 DMA Controller emulation + +********************************************************************** + _____ _____ + /RESET 1 |* \_/ | 64 Vcc + /IRQ 2 | | 63 BS + DOTCLK 3 | | 62 CAS1 + R/W 4 | | 61 CAS0 + 1 MHz 5 | | 60 RAS1 + /CS 6 | | 59 RAS0 + /BA 7 | | 58 /DWE + /DMA 8 | | 57 DD0 + D7 9 | | 56 DD1 + D6 10 | | 55 DD2 + D5 11 | | 54 DD3 + D4 12 | | 53 DD4 + D3 13 | | 52 DD5 + D2 14 | | 51 DD6 + D1 15 | MOS8726 | 50 DD7 + D0 16 | MOS8726R1 | 49 Vss + Vss 17 | | 48 MA8 + A15 18 | | 47 MA7 + A14 19 | | 46 MA6 + A13 20 | | 45 MA5 + A12 21 | | 44 MA4 + A11 22 | | 43 MA3 + A10 23 | | 42 MA2 + A9 24 | | 41 MA1 + A8 25 | | 40 MA0 + A7 26 | | 39 TEST + A6 27 | | 38 Vss + A5 28 | | 37 Vcc + A4 29 | | 36 /ROMSEL + A3 30 | | 35 /ROML + A2 31 | | 34 /ROMH + A1 32 |_____________| 33 A0 + +**********************************************************************/ + +#pragma once + +#ifndef __MOS8726__ +#define __MOS8726__ + +#include "emu.h" + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_MOS8726_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, MOS8726, 1000000) // dummy clock + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> mos8726_device + +class mos8726_device : public device_t, + public device_execute_interface +{ +public: + // construction/destruction + mos8726_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + DECLARE_READ8_MEMBER( read ); + DECLARE_WRITE8_MEMBER( write ); + + DECLARE_WRITE_LINE_MEMBER( bs_w ); + + int romsel_r(int roml, int romh); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void execute_run(); + + int m_icount; + int m_bs; +}; + + +// device type definition +extern const device_type MOS8726; + + + +#endif diff --git a/src/devices/machine/mpu401.c b/src/devices/machine/mpu401.c new file mode 100644 index 00000000000..5a2933380df --- /dev/null +++ b/src/devices/machine/mpu401.c @@ -0,0 +1,289 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/*************************************************************************** + + Roland MPU-401 core + + This emulates the MPU-401 external box with the 6801, ASIC, and RAM in it. + + We do it this way to facilitate the various PC, Apple II, C64, and other + possible hookups. + + 6801 GPIO port hookups (from the schematics) + + P10 / P11 / P12: drive the metronome and speaker + P13 / P14 / P15: drive 3 pins on the SYNC OUT connector + P16: to DSRD on gate array + P17: to DRRD on gate array + + P20: to SYC OUT on gate array + P21: to SYC IN on gate array, pulled up to Vcc via 4.7K resistor + programmed as output of timer (OLVL) + P22: to SRCK on gate array, inverted + P23: MIDI IN serial data (SCI in) + P24: MIDI OUT serial data (SCI out) + + ASIC addresses from the 6801: + 0x20: (r) read pending byte from the PC (w) apparently nothing + 0x21: (r) ASIC status, see STAT_xxx bits below (w) send new byte to PC data port + + Theory of operation: 6801's timer/counter is set up to drive a pulse stream + out P21 to the ASIC's SYC IN pin. The ASIC in turn generates the MIDI baud + rate (times 8) and returns that on pin P22. + + The 6801 is believed to run in mode 2, based on a combination of the + schematics and the behavior (ie, internal RAM from 80-FF is clearly + present from the program's behavior, and ports 3/4 are obviously external + address/data buses) + +***************************************************************************/ + +#include "machine/mpu401.h" +#include "bus/midi/midi.h" + +#define M6801_TAG "mpu6801" +#define ROM_TAG "mpurom" +#define MIDIIN_TAG "mdin" +#define MIDIOUT_TAG "mdout" + +#define P2_SYNC_OUT (0x01) +#define P2_SYNC_IN (0x02) +#define P2_SRCK_OUT (0x04) +#define P2_MIDI_IN (0x08) +#define P2_MIDI_OUT (0x10) + +#define STAT_CMD_PORT (0x01) // set if the new byte indicated by TX FULL was written to the command port, clear for data port +#define STAT_TX_FULL (0x40) // indicates the PC has written a new byte we haven't read yet +#define STAT_RX_EMPTY (0x80) // indicates we've written a new byte the PC hasn't read yet + +static ADDRESS_MAP_START( mpu401_map, AS_PROGRAM, 8, mpu401_device ) + AM_RANGE(0x0000, 0x001f) AM_READWRITE(regs_mode2_r, regs_mode2_w) + AM_RANGE(0x0020, 0x0021) AM_READWRITE(asic_r, asic_w) + AM_RANGE(0x0080, 0x00ff) AM_RAM // on-chip RAM + AM_RANGE(0x0800, 0x0fff) AM_RAM // external RAM + AM_RANGE(0xf000, 0xffff) AM_ROM AM_REGION(ROM_TAG, 0) +ADDRESS_MAP_END + +static ADDRESS_MAP_START( mpu401_io_map, AS_IO, 8, mpu401_device ) + AM_RANGE(M6801_PORT1, M6801_PORT1) AM_READWRITE(port1_r, port1_w) + AM_RANGE(M6801_PORT2, M6801_PORT2) AM_READWRITE(port2_r, port2_w) +ADDRESS_MAP_END + +MACHINE_CONFIG_FRAGMENT( mpu401 ) + MCFG_CPU_ADD(M6801_TAG, M6801, 4000000) /* 4 MHz as per schematics */ + MCFG_CPU_PROGRAM_MAP(mpu401_map) + MCFG_CPU_IO_MAP(mpu401_io_map) + MCFG_M6801_SER_TX(DEVWRITELINE(MIDIOUT_TAG, midi_port_device, write_txd)) + + MCFG_MIDI_PORT_ADD(MIDIIN_TAG, midiin_slot, "midiin") + MCFG_MIDI_RX_HANDLER(DEVWRITELINE(DEVICE_SELF, mpu401_device, midi_rx_w)) + + MCFG_MIDI_PORT_ADD(MIDIOUT_TAG, midiout_slot, "midiout") +MACHINE_CONFIG_END + +ROM_START( mpu401 ) + ROM_REGION(0x1000, ROM_TAG, 0) + ROM_LOAD( "roland_6801v0b55p.bin", 0x000000, 0x001000, CRC(65d3a151) SHA1(00efbfb96aeb997b69bb16981c6751d3c784bb87) ) +ROM_END + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type MPU401 = &device_creator; + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor mpu401_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( mpu401 ); +} + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *mpu401_device::device_rom_region() const +{ + return ROM_NAME( mpu401 ); +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// mpu401_device - constructor +//------------------------------------------------- + +mpu401_device::mpu401_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, MPU401, "Roland MPU-401 I/O box", tag, owner, clock, "mpu401", __FILE__), + m_ourcpu(*this, M6801_TAG), + write_irq(*this) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void mpu401_device::device_start() +{ + write_irq.resolve_safe(); + m_timer = timer_alloc(0, NULL); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void mpu401_device::device_reset() +{ + m_port2 = 0xff & ~(P2_SRCK_OUT | P2_MIDI_IN); // prevent spurious reception + m_command = 0; + m_mpudata = 0; + m_gatearrstat = 0; + + m_timer->adjust(attotime::zero, 0, attotime::from_hz(31250*8)); +} + +//------------------------------------------------- +// device_timer - called when our device timer expires +//------------------------------------------------- + +void mpu401_device::device_timer(emu_timer &timer, device_timer_id tid, int param, void *ptr) +{ + m_ourcpu->m6801_clock_serial(); +} + +READ8_MEMBER(mpu401_device::regs_mode2_r) +{ + switch (offset) + { + case 4: + case 5: + case 6: + case 7: + case 0xf: +// printf("MPU401: read @ unk %x (PC=%x)\n", offset, space.device().safe_pc()); + break; + + default: + return m_ourcpu->m6801_io_r(space, offset); + } + + return 0xff; +} + +WRITE8_MEMBER(mpu401_device::regs_mode2_w) +{ + switch (offset) + { + case 4: + case 5: + case 6: + case 7: + case 0xf: +// printf("MPU401: %02x @ unk %x (PC=%x)\n", data, offset, space.device().safe_pc()); + break; + + default: + return m_ourcpu->m6801_io_w(space, offset, data); + } +} + +READ8_MEMBER(mpu401_device::port1_r) +{ + return 0xff; +} + +WRITE8_MEMBER(mpu401_device::port1_w) +{ +// printf("port1_w: %02x met %x syncout %x DSRD %d DRRD %d\n", data, data & 3, (data>>3) & 3, (data>>6) & 1, (data>>7) & 1); +} + +READ8_MEMBER(mpu401_device::port2_r) +{ +// printf("Read P2 (PC=%x)\n", space.device().safe_pc()); + return m_port2; +} + +WRITE8_MEMBER(mpu401_device::port2_w) +{ +// printf("port2_w: %02x SYCOUT %d SYCIN %d SRCK %d MIDI OUT %d\n", data, (data & 1), (data>>1) & 1, (data>>2) & 1, (data>>4) & 1); +} + +READ8_MEMBER(mpu401_device::mpu_r) +{ +// printf("mpu_r @ %d\n", offset); + + if (offset == 1) // status + { + return m_gatearrstat; + } + else // data + { + write_irq(CLEAR_LINE); + m_gatearrstat |= STAT_RX_EMPTY; + return m_mpudata; + } +} + +WRITE8_MEMBER(mpu401_device::mpu_w) +{ +// printf("%02x to MPU-401 @ %d\n", data, offset); + m_command = data; + m_gatearrstat |= STAT_TX_FULL; + + if (offset == 1) + { + m_gatearrstat |= STAT_CMD_PORT; + } + else + { + m_gatearrstat &= ~STAT_CMD_PORT; + } +} + +READ8_MEMBER(mpu401_device::asic_r) +{ + if (offset == 0) + { + m_gatearrstat &= ~STAT_TX_FULL; + return m_command; + } + else if (offset == 1) + { + return m_gatearrstat; + } + + return 0xff; +} + +WRITE8_MEMBER(mpu401_device::asic_w) +{ +// printf("MPU401: %02x to gate array @ %d\n", data, offset); + + if (offset == 1) + { + m_mpudata = data; + m_gatearrstat &= ~STAT_RX_EMPTY; + write_irq(ASSERT_LINE); + } +} + +// MIDI receive +WRITE_LINE_MEMBER( mpu401_device::midi_rx_w ) +{ + if (state == ASSERT_LINE) + { + m_port2 |= P2_MIDI_IN; + } + else + { + m_port2 &= ~P2_MIDI_IN; + } +} diff --git a/src/devices/machine/mpu401.h b/src/devices/machine/mpu401.h new file mode 100644 index 00000000000..58acb3ab98e --- /dev/null +++ b/src/devices/machine/mpu401.h @@ -0,0 +1,72 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +#pragma once + +#ifndef __MPU401_H__ +#define __MPU401_H__ + +#include "emu.h" +#include "cpu/m6800/m6800.h" + +#define MCFG_MPU401_ADD(_tag, _irqf ) \ + MCFG_DEVICE_ADD(_tag, MPU401, 0) \ + MCFG_IRQ_FUNC(_irqf) + +#define MCFG_IRQ_FUNC(_irqf) \ + downcast(device)->set_irqf(DEVCB_##_irqf); + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class mpu401_device : public device_t +{ +public: + // construction/destruction + mpu401_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + + required_device m_ourcpu; + + template void set_irqf(_write wr) + { + write_irq.set_callback(wr); + } + + devcb_write_line write_irq; + + DECLARE_READ8_MEMBER(regs_mode2_r); + DECLARE_WRITE8_MEMBER(regs_mode2_w); + DECLARE_READ8_MEMBER(asic_r); + DECLARE_WRITE8_MEMBER(asic_w); + DECLARE_READ8_MEMBER(port1_r); + DECLARE_WRITE8_MEMBER(port1_w); + DECLARE_READ8_MEMBER(port2_r); + DECLARE_WRITE8_MEMBER(port2_w); + DECLARE_WRITE_LINE_MEMBER(midi_rx_w); + + // public API - call for reads/writes at I/O 330/331 on PC, C0n0/C0n1 on Apple II, etc. + DECLARE_READ8_MEMBER(mpu_r); + DECLARE_WRITE8_MEMBER(mpu_w); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual const rom_entry *device_rom_region() const; + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + +private: + UINT8 m_port2; + UINT8 m_command; + UINT8 m_mpudata; + UINT8 m_gatearrstat; + emu_timer *m_timer; +}; + +// device type definition +extern const device_type MPU401; + +#endif /* __MPU401_H__ */ diff --git a/src/devices/machine/msm5832.c b/src/devices/machine/msm5832.c new file mode 100644 index 00000000000..7bc6fa70bfa --- /dev/null +++ b/src/devices/machine/msm5832.c @@ -0,0 +1,306 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + OKI MSM5832 Real Time Clock/Calendar emulation + +**********************************************************************/ + +/* + + TODO: + + - 12/24 hour + - AM/PM + - leap year + - test input + - reference signal output + +*/ + +#include "msm5832.h" + + +// device type definition +const device_type MSM5832 = &device_creator; + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define LOG 0 + + +// registers +enum +{ + REGISTER_S1 = 0, + REGISTER_S10, + REGISTER_MI1, + REGISTER_MI10, + REGISTER_H1, + REGISTER_H10, + REGISTER_W, + REGISTER_D1, + REGISTER_D10, + REGISTER_MO1, + REGISTER_MO10, + REGISTER_Y1, + REGISTER_Y10, + REGISTER_REF = 15 +}; + + + +//************************************************************************** +// INLINE HELPERS +//************************************************************************** + +//------------------------------------------------- +// read_counter - +//------------------------------------------------- + +inline int msm5832_device::read_counter(int counter) +{ + return (m_reg[counter + 1] * 10) + m_reg[counter]; +} + + +//------------------------------------------------- +// write_counter - +//------------------------------------------------- + +inline void msm5832_device::write_counter(int counter, int value) +{ + m_reg[counter] = value % 10; + m_reg[counter + 1] = value / 10; +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// msm5832_device - constructor +//------------------------------------------------- + +msm5832_device::msm5832_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, MSM5832, "MSM5832", tag, owner, clock, "msm5832", __FILE__), + device_rtc_interface(mconfig, *this), + m_hold(0), + m_address(0), + m_read(0), + m_write(0), + m_cs(0) +{ + for (int i = 0; i < 13; i++) + m_reg[i] = 0; +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void msm5832_device::device_start() +{ + // allocate timers + m_clock_timer = timer_alloc(TIMER_CLOCK); + m_clock_timer->adjust(attotime::from_hz(clock() / 32768), 0, attotime::from_hz(clock() / 32768)); + + // state saving + save_item(NAME(m_reg)); + save_item(NAME(m_hold)); + save_item(NAME(m_address)); + save_item(NAME(m_read)); + save_item(NAME(m_write)); + save_item(NAME(m_cs)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void msm5832_device::device_reset() +{ + set_current_time(machine()); +} + + +//------------------------------------------------- +// device_timer - handler timer events +//------------------------------------------------- + +void msm5832_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch (id) + { + case TIMER_CLOCK: + if (!m_hold) + { + advance_seconds(); + } + break; + } +} + + +//------------------------------------------------- +// rtc_clock_updated - +//------------------------------------------------- + +void msm5832_device::rtc_clock_updated(int year, int month, int day, int day_of_week, int hour, int minute, int second) +{ + write_counter(REGISTER_Y1, year); + write_counter(REGISTER_MO1, month); + write_counter(REGISTER_D1, day); + m_reg[REGISTER_W] = day_of_week-1; + write_counter(REGISTER_H1, hour); + write_counter(REGISTER_MI1, minute); + write_counter(REGISTER_S1, second); +} + + +//------------------------------------------------- +// data_r - +//------------------------------------------------- + +READ8_MEMBER( msm5832_device::data_r ) +{ + UINT8 data = 0; + + if (m_cs && m_read) + { + if (m_address == REGISTER_REF) + { + // TODO reference output + } + else if (m_address <= REGISTER_Y10) + { + data = m_reg[m_address]; + } + else + { + // Otrona Attache CP/M BIOS checks unused registers to detect it + data = 0x0f; + } + } + + if (LOG) logerror("MSM5832 '%s' Register Read %01x: %01x\n", tag(), m_address, data & 0x0f); + + return data & 0x0f; +} + + +//------------------------------------------------- +// data_w - +//------------------------------------------------- + +WRITE8_MEMBER( msm5832_device::data_w ) +{ + if (LOG) logerror("MSM5832 '%s' Register Write %01x: %01x\n", tag(), m_address, data & 0x0f); + + if (m_cs && m_write) + { + if (m_address == REGISTER_REF) + { + // TODO reference output + } + else if (m_address <= REGISTER_Y10) + { + m_reg[m_address] = data & 0x0f; + + set_time(false, read_counter(REGISTER_Y1), read_counter(REGISTER_MO1), read_counter(REGISTER_D1), m_reg[REGISTER_W], + read_counter(REGISTER_H1), read_counter(REGISTER_MI1), read_counter(REGISTER_S1)); + } + } +} + + +//------------------------------------------------- +// address_w - +//------------------------------------------------- + +void msm5832_device::address_w(UINT8 data) +{ + if (LOG) logerror("MSM5832 '%s' Address: %01x\n", tag(), data & 0x0f); + + m_address = data & 0x0f; +} + + +//------------------------------------------------- +// adj_w - +//------------------------------------------------- + +WRITE_LINE_MEMBER( msm5832_device::adj_w ) +{ + if (LOG) logerror("MSM5832 '%s' 30 ADJ: %u\n", tag(), state); + + if (state) + { + adjust_seconds(); + } +} + + +//------------------------------------------------- +// test_w - +//------------------------------------------------- + +WRITE_LINE_MEMBER( msm5832_device::test_w ) +{ + if (LOG) logerror("MSM5832 '%s' TEST: %u\n", tag(), state); +} + + +//------------------------------------------------- +// hold_w - +//------------------------------------------------- + +WRITE_LINE_MEMBER( msm5832_device::hold_w ) +{ + if (LOG) logerror("MSM5832 '%s' HOLD: %u\n", tag(), state); + + m_hold = state; +} + + +//------------------------------------------------- +// read_w - +//------------------------------------------------- + +WRITE_LINE_MEMBER( msm5832_device::read_w ) +{ + if (LOG) logerror("MSM5832 '%s' READ: %u\n", tag(), state); + + m_read = state; +} + + +//------------------------------------------------- +// write_w - +//------------------------------------------------- + +WRITE_LINE_MEMBER( msm5832_device::write_w ) +{ + if (LOG) logerror("MSM5832 '%s' WR: %u\n", tag(), state); + + m_write = state; +} + + +//------------------------------------------------- +// cs_w - +//------------------------------------------------- + +WRITE_LINE_MEMBER( msm5832_device::cs_w ) +{ + if (LOG) logerror("MSM5832 '%s' CS: %u\n", tag(), state); + + m_cs = state; +} diff --git a/src/devices/machine/msm5832.h b/src/devices/machine/msm5832.h new file mode 100644 index 00000000000..68b72a3f8bf --- /dev/null +++ b/src/devices/machine/msm5832.h @@ -0,0 +1,99 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + OKI MSM5832 Real Time Clock/Calendar emulation + +********************************************************************** + _____ _____ + Vdd 1 |* \_/ | 18 HOLD + WRITE 2 | | 17 _XT + READ 3 | | 16 XT + A0 4 | | 15 +- 30 ADJ + A1 5 | MSM5832 | 14 TEST + A2 6 | | 13 GND + A3 7 | | 12 D3 + CS 8 | | 11 D2 + D0 9 |_____________| 10 D1 + +**********************************************************************/ + +#pragma once + +#ifndef __MSM5832__ +#define __MSM5832__ + +#include "emu.h" + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_MSM5832_ADD(_tag, _clock) \ + MCFG_DEVICE_ADD(_tag, MSM5832, _clock) + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> msm5832_device + +class msm5832_device : public device_t, + public device_rtc_interface +{ +public: + // construction/destruction + msm5832_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + DECLARE_READ8_MEMBER( data_r ); + DECLARE_WRITE8_MEMBER( data_w ); + + void address_w(UINT8 data); + + DECLARE_WRITE_LINE_MEMBER( adj_w ); + DECLARE_WRITE_LINE_MEMBER( test_w ); + DECLARE_WRITE_LINE_MEMBER( hold_w ); + + DECLARE_WRITE_LINE_MEMBER( read_w ); + DECLARE_WRITE_LINE_MEMBER( write_w ); + DECLARE_WRITE_LINE_MEMBER( cs_w ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + // device_rtc_interface overrides + virtual void rtc_clock_updated(int year, int month, int day, int day_of_week, int hour, int minute, int second); + +private: + static const device_timer_id TIMER_CLOCK = 0; + + inline int read_counter(int counter); + inline void write_counter(int counter, int value); + + UINT8 m_reg[13]; // registers + + int m_hold; // counter hold + int m_address; // address + + int m_read; + int m_write; + int m_cs; + + // timers + emu_timer *m_clock_timer; +}; + + +// device type definition +extern const device_type MSM5832; + + + +#endif diff --git a/src/devices/machine/msm58321.c b/src/devices/machine/msm58321.c new file mode 100644 index 00000000000..679b85584ff --- /dev/null +++ b/src/devices/machine/msm58321.c @@ -0,0 +1,646 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + OKI MSM58321RS Real Time Clock/Calendar emulation + +**********************************************************************/ + +/* + + TODO: + + - leap year + - test + - reference registers + +*/ + +#include "msm58321.h" + + +// device type definition +const device_type MSM58321 = &device_creator; + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define LOG 0 + + +// registers +enum +{ + REGISTER_S1 = 0, + REGISTER_S10, + REGISTER_MI1, + REGISTER_MI10, + REGISTER_H1, + REGISTER_H10, + REGISTER_W, + REGISTER_D1, + REGISTER_D10, + REGISTER_MO1, + REGISTER_MO10, + REGISTER_Y1, + REGISTER_Y10, + REGISTER_RESET, + REGISTER_REF0, + REGISTER_REF1 +}; + +static const char *reg_name(UINT8 address) +{ + switch(address) + { + case REGISTER_S1: return "S1"; + case REGISTER_S10: return "S10"; + case REGISTER_MI1: return "MI1"; + case REGISTER_MI10: return "MI10"; + case REGISTER_H1: return "H1"; + case REGISTER_H10: return "H10"; + case REGISTER_W: return "W"; + case REGISTER_D1: return "D1"; + case REGISTER_D10: return "D10"; + case REGISTER_MO1: return "MO1"; + case REGISTER_MO10: return "MO10"; + case REGISTER_Y1: return "Y1"; + case REGISTER_Y10: return "Y10"; + case REGISTER_RESET: return "RESET"; + case REGISTER_REF0: return "REF0"; + case REGISTER_REF1: return "REF1"; + } + + return "INVALID REGISTER"; +} + +enum +{ + H10_PM = 4, + H10_24 = 8 +}; + + +//************************************************************************** +// INLINE HELPERS +//************************************************************************** + +//------------------------------------------------- +// read_counter - +//------------------------------------------------- + +inline int msm58321_device::read_counter(int counter) +{ + int data = m_reg[counter]; + + if (counter == REGISTER_H1) + { + int h10 = m_reg[REGISTER_H10]; + + if (h10 & H10_24) + { + data += (h10 & 3) * 10; + } + else + { + data += (h10 & 1) * 10; + + if (h10 & H10_PM) + { + if (data != 12) + { + data += 12; + } + } + else if (data == 12) + { + data = 0; + } + } + } + else + { + data += (m_reg[counter + 1] * 10); + } + + return data; +} + + +//------------------------------------------------- +// write_counter - +//------------------------------------------------- + +inline void msm58321_device::write_counter(int address, int data) +{ + int flag = 0; + + switch (address) + { + case REGISTER_H1: + flag = m_reg[REGISTER_H10] & H10_24; + if (!flag) + { + if (data >= 12) + { + data -= 12; + flag = H10_PM; + } + + if (data == 0) + { + data = 12; + } + } + break; + + case REGISTER_D1: + flag = (m_reg[REGISTER_D10] & ~3); + break; + } + + m_reg[address] = data % 10; + m_reg[address + 1] = (data / 10) | flag; +} + + + +//------------------------------------------------- +// msm58321_device - constructor +//------------------------------------------------- + +msm58321_device::msm58321_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, MSM58321, "MSM58321", tag, owner, clock, "msm58321", __FILE__), + device_rtc_interface(mconfig, *this), + device_nvram_interface(mconfig, *this), + m_year0(0), + m_default_24h(false), + m_d0_handler(*this), + m_d1_handler(*this), + m_d2_handler(*this), + m_d3_handler(*this), + m_busy_handler(*this), + m_cs2(0), + m_write(0), + m_read(0), + m_d0_in(0), + m_d0_out(0), + m_d1_in(0), + m_d1_out(0), + m_d2_in(0), + m_d2_out(0), + m_d3_in(0), + m_d3_out(0), + m_address_write(0), + m_busy(0), + m_stop(0), + m_test(0), + m_cs1(0), + m_address(0xf) +{ + memset(m_reg, 0x00, sizeof(m_reg)); +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void msm58321_device::device_start() +{ + // resolve callbacks + m_d0_handler.resolve_safe(); + m_d1_handler.resolve_safe(); + m_d2_handler.resolve_safe(); + m_d3_handler.resolve_safe(); + m_busy_handler.resolve_safe(); + + // allocate timers + m_clock_timer = timer_alloc(TIMER_CLOCK); + m_clock_timer->adjust(attotime::from_hz(clock() / 32768), 0, attotime::from_hz(clock() / 32768)); + + m_busy_timer = timer_alloc(TIMER_BUSY); + m_busy_timer->adjust(attotime::from_hz(clock() / 16384), 0, attotime::from_hz(clock() / 16384)); + + // state saving + save_item(NAME(m_cs2)); + save_item(NAME(m_write)); + save_item(NAME(m_read)); + save_item(NAME(m_d0_in)); + save_item(NAME(m_d0_out)); + save_item(NAME(m_d1_in)); + save_item(NAME(m_d1_out)); + save_item(NAME(m_d2_in)); + save_item(NAME(m_d2_out)); + save_item(NAME(m_d3_in)); + save_item(NAME(m_d3_out)); + save_item(NAME(m_address_write)); + save_item(NAME(m_busy)); + save_item(NAME(m_stop)); + save_item(NAME(m_test)); + save_item(NAME(m_cs1)); + save_item(NAME(m_address)); + save_item(NAME(m_reg)); + + set_current_time(machine()); + + update_output(); +} + + +//------------------------------------------------- +// device_timer - handler timer events +//------------------------------------------------- + +void msm58321_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch (id) + { + case TIMER_CLOCK: + if (!m_stop) + advance_seconds(); + break; + + case TIMER_BUSY: + if (!m_cs1 || !m_cs2 || !m_write || m_address != REGISTER_RESET) + { + m_busy = !m_busy; + m_busy_handler(m_busy); + } + break; + } +} + + +//------------------------------------------------- +// rtc_clock_updated - +//------------------------------------------------- + +void msm58321_device::rtc_clock_updated(int year, int month, int day, int day_of_week, int hour, int minute, int second) +{ + write_counter(REGISTER_Y1, (year - m_year0) % 100); + write_counter(REGISTER_MO1, month); + write_counter(REGISTER_D1, day); + m_reg[REGISTER_W] = day_of_week; + write_counter(REGISTER_H1, hour); + write_counter(REGISTER_MI1, minute); + write_counter(REGISTER_S1, second); + + update_output(); +} + +//------------------------------------------------- +// nvram_default - called to initialize NVRAM to +// its default state +//------------------------------------------------- + +void msm58321_device::nvram_default() +{ + for (int i = 0; i < 13; i++) + m_reg[i] = 0; + + if (m_default_24h) + m_reg[REGISTER_H10] = H10_24; + + clock_updated(); +} + + +//------------------------------------------------- +// nvram_read - called to read NVRAM from the +// .nv file +//------------------------------------------------- + +void msm58321_device::nvram_read(emu_file &file) +{ + file.read(m_reg, sizeof(m_reg)); + + clock_updated(); +} + + +//------------------------------------------------- +// nvram_write - called to write NVRAM to the +// .nv file +//------------------------------------------------- + +void msm58321_device::nvram_write(emu_file &file) +{ + file.write(m_reg, sizeof(m_reg)); +} + +//------------------------------------------------- +// update_output - +//------------------------------------------------- + +void msm58321_device::update_output() +{ + UINT8 data = 0xf; + + if (m_cs1 && m_cs2 && m_read) + { + switch (m_address) + { + case REGISTER_RESET: + data = 0; + break; + + case REGISTER_REF0: + case REGISTER_REF1: + // TODO: output reference values + data = 0; + break; + + default: + data = m_reg[m_address]; + break; + } + + if (LOG) logerror("MSM58321 '%s' Register Read %s (%01x): %01x\n", tag(), reg_name(m_address), m_address, data & 0x0f); + } + + int d0 = (data >> 0) & 1; + if (m_d0_out != d0) + { + m_d0_out = d0; + m_d0_handler(d0); + } + + int d1 = (data >> 1) & 1; + if (m_d1_out != d1) + { + m_d1_out = d1; + m_d1_handler(d1); + } + + int d2 = (data >> 2) & 1; + if (m_d2_out != d2) + { + m_d2_out = d2; + m_d2_handler(d2); + } + + int d3 = (data >> 3) & 1; + if (m_d3_out != d3) + { + m_d3_out = d3; + m_d3_handler(d3); + } +} + + +//------------------------------------------------- +// update_input() - +//------------------------------------------------- + +void msm58321_device::update_input() +{ + if (m_cs1 && m_cs2) + { + UINT8 data = m_d0_in | (m_d1_in << 1) | (m_d2_in << 2) | (m_d3_in << 3); + + if (m_address_write) + { + if (LOG) logerror("MSM58321 '%s' Latch Address %01x\n", tag(), data); + + // latch address + m_address = data; + } + + if (m_write) + { + switch(m_address) + { + case REGISTER_RESET: + if (LOG) logerror("MSM58321 '%s' Reset\n", tag()); + + if (!m_busy) + { + m_busy = 1; + m_busy_handler(m_busy); + } + break; + + case REGISTER_REF0: + case REGISTER_REF1: + if (LOG) logerror("MSM58321 '%s' Reference Signal\n", tag()); + break; + + default: + if (LOG) logerror("MSM58321 '%s' Register Write %s (%01x): %01x\n", tag(), reg_name(m_address), m_address, data); + + switch (m_address) + { + case REGISTER_S10: + case REGISTER_MI10: + case REGISTER_W: + m_reg[m_address] = data & 7; + break; + + case REGISTER_H10: + if (data & H10_24) + { + // "When D3 = 1 is written, the D2 bit is reset inside the IC." + // but it doesn't say if this is done immediately or on the next update + m_reg[m_address] = data & ~H10_PM; + } + else + { + m_reg[m_address] = data; + } + break; + + case REGISTER_MO10: + m_reg[m_address] = data & 1; + break; + + default: + m_reg[m_address] = data; + break; + } + + set_time(false, read_counter(REGISTER_Y1) + m_year0, read_counter(REGISTER_MO1), read_counter(REGISTER_D1), m_reg[REGISTER_W], + read_counter(REGISTER_H1), read_counter(REGISTER_MI1), read_counter(REGISTER_S1)); + break; + } + } + } +} + +//------------------------------------------------- +// cs2_w - +//------------------------------------------------- + +WRITE_LINE_MEMBER( msm58321_device::cs2_w ) +{ + if (m_cs2 != state) + { + if (LOG) logerror("MSM58321 '%s' CS2: %u\n", tag(), state); + + m_cs2 = state; + + update_input(); + } +} + + +//------------------------------------------------- +// write_w - +//------------------------------------------------- + +WRITE_LINE_MEMBER( msm58321_device::write_w ) +{ + if (m_write != state) + { + if (LOG) logerror("MSM58321 '%s' WRITE: %u\n", tag(), state); + + m_write = state; + + update_input(); + } +} + + +//------------------------------------------------- +// read_w - +//------------------------------------------------- + +WRITE_LINE_MEMBER( msm58321_device::read_w ) +{ + if (m_read != state) + { + if (LOG) logerror("MSM58321 '%s' READ: %u\n", tag(), state); + + m_read = state; + + update_output(); + } +} + + + +//------------------------------------------------- +// d0_w - +//------------------------------------------------- + +WRITE_LINE_MEMBER( msm58321_device::d0_w ) +{ + if (m_d0_in != state) + { + m_d0_in = state; + + update_input(); + } +} + + +//------------------------------------------------- +// d1_w - +//------------------------------------------------- + +WRITE_LINE_MEMBER( msm58321_device::d1_w ) +{ + if (m_d1_in != state) + { + m_d1_in = state; + + update_input(); + } +} + + +//------------------------------------------------- +// d2_w - +//------------------------------------------------- + +WRITE_LINE_MEMBER( msm58321_device::d2_w ) +{ + if (m_d2_in != state) + { + m_d2_in = state; + + update_input(); + } +} + + +//------------------------------------------------- +// d3_w - +//------------------------------------------------- + +WRITE_LINE_MEMBER( msm58321_device::d3_w ) +{ + if (m_d3_in != state) + { + m_d3_in = state; + + update_input(); + } +} + + +//------------------------------------------------- +// address_write_w - +//------------------------------------------------- + +WRITE_LINE_MEMBER( msm58321_device::address_write_w ) +{ + if (m_address_write != state) + { + if (LOG) logerror("MSM58321 '%s' ADDRESS WRITE: %u\n", tag(), state); + + m_address_write = state; + + update_input(); + } +} + + +//------------------------------------------------- +// stop_w - +//------------------------------------------------- + +WRITE_LINE_MEMBER( msm58321_device::stop_w ) +{ + if (m_stop != state) + { + if (LOG) logerror("MSM58321 '%s' STOP: %u\n", tag(), state); + + m_stop = state; + } +} + + +//------------------------------------------------- +// test_w - +//------------------------------------------------- + +WRITE_LINE_MEMBER( msm58321_device::test_w ) +{ + if (m_test != state) + { + if (LOG) logerror("MSM58321 '%s' TEST: %u\n", tag(), state); + + m_test = state; + } +} + + + +//------------------------------------------------- +// cs1_w - +//------------------------------------------------- + +WRITE_LINE_MEMBER( msm58321_device::cs1_w ) +{ + if (m_cs1 != state) + { + if (LOG) logerror("MSM58321 '%s' CS1: %u\n", tag(), state); + + m_cs1 = state; + + update_input(); + } +} diff --git a/src/devices/machine/msm58321.h b/src/devices/machine/msm58321.h new file mode 100644 index 00000000000..8b1ad54edd9 --- /dev/null +++ b/src/devices/machine/msm58321.h @@ -0,0 +1,146 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + OKI MSM58321RS Real Time Clock/Calendar emulation + +********************************************************************** + _____ _____ + CS2 1 |* \_/ | 16 Vdd + WRITE 2 | | 15 XT + READ 3 | | 14 _XT + D0 4 | MSM58321 | 13 CS1 + D1 5 | RTC58321 | 12 TEST + D2 6 | | 11 STOP + D3 7 | | 10 _BUSY + GND 8 |_____________| 9 ADDRESS WRITE + +**********************************************************************/ + +#pragma once + +#ifndef __MSM58321__ +#define __MSM58321__ + +#include "emu.h" + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_MSM58321_D0_HANDLER(_devcb) \ + devcb = &msm58321_device::set_d0_handler(*device, DEVCB_##_devcb); + +#define MCFG_MSM58321_D1_HANDLER(_devcb) \ + devcb = &msm58321_device::set_d1_handler(*device, DEVCB_##_devcb); + +#define MCFG_MSM58321_D2_HANDLER(_devcb) \ + devcb = &msm58321_device::set_d2_handler(*device, DEVCB_##_devcb); + +#define MCFG_MSM58321_D3_HANDLER(_devcb) \ + devcb = &msm58321_device::set_d3_handler(*device, DEVCB_##_devcb); + +#define MCFG_MSM58321_BUSY_HANDLER(_devcb) \ + devcb = &msm58321_device::set_busy_handler(*device, DEVCB_##_devcb); + +#define MCFG_MSM58321_YEAR0(_year0) \ + msm58321_device::set_year0(*device, _year0); + +#define MCFG_MSM58321_DEFAULT_24H(_default_24h) \ + msm58321_device::set_default_24h(*device, _default_24h); + +// ======================> msm58321_device + +class msm58321_device : public device_t, + public device_rtc_interface, + public device_nvram_interface +{ +public: + // construction/destruction + msm58321_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // static configuration helpers + template static devcb_base &set_d0_handler(device_t &device, _Object object) { return downcast(device).m_d0_handler.set_callback(object); } + template static devcb_base &set_d1_handler(device_t &device, _Object object) { return downcast(device).m_d1_handler.set_callback(object); } + template static devcb_base &set_d2_handler(device_t &device, _Object object) { return downcast(device).m_d2_handler.set_callback(object); } + template static devcb_base &set_d3_handler(device_t &device, _Object object) { return downcast(device).m_d3_handler.set_callback(object); } + template static devcb_base &set_busy_handler(device_t &device, _Object object) { return downcast(device).m_busy_handler.set_callback(object); } + static void set_year0(device_t &device, int year0) { downcast(device).m_year0 = year0; } + static void set_default_24h(device_t &device, bool default_24h) { downcast(device).m_default_24h = default_24h; } + + DECLARE_WRITE_LINE_MEMBER( cs2_w ); + DECLARE_WRITE_LINE_MEMBER( write_w ); + DECLARE_WRITE_LINE_MEMBER( read_w ); + DECLARE_WRITE_LINE_MEMBER( d0_w ); + DECLARE_WRITE_LINE_MEMBER( d1_w ); + DECLARE_WRITE_LINE_MEMBER( d2_w ); + DECLARE_WRITE_LINE_MEMBER( d3_w ); + DECLARE_WRITE_LINE_MEMBER( address_write_w ); + DECLARE_WRITE_LINE_MEMBER( stop_w ); + DECLARE_WRITE_LINE_MEMBER( test_w ); + DECLARE_WRITE_LINE_MEMBER( cs1_w ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + // device_rtc_interface overrides + virtual void rtc_clock_updated(int year, int month, int day, int day_of_week, int hour, int minute, int second); + virtual bool rtc_feature_y2k() { return m_year0 != 0; } + + // device_nvram_interface overrides + virtual void nvram_default(); + virtual void nvram_read(emu_file &file); + virtual void nvram_write(emu_file &file); + +private: + static const device_timer_id TIMER_CLOCK = 0; + static const device_timer_id TIMER_BUSY = 1; + + void update_input(); + void update_output(); + + inline int read_counter(int counter); + inline void write_counter(int counter, int value); + + int m_year0; + bool m_default_24h; + devcb_write_line m_d0_handler; + devcb_write_line m_d1_handler; + devcb_write_line m_d2_handler; + devcb_write_line m_d3_handler; + devcb_write_line m_busy_handler; + + int m_cs2; // chip select 2 + int m_write; // write data + int m_read; // read data + int m_d0_in; // d0 + int m_d0_out; // d0 + int m_d1_in; // d1 + int m_d1_out; // d1 + int m_d2_in; // d2 + int m_d2_out; // d2 + int m_d3_in; // d3 + int m_d3_out; // d3 + int m_address_write; // write address + int m_busy; // busy flag + int m_stop; // stop flag + int m_test; // test flag + int m_cs1; // chip select 1 + + UINT8 m_address; // address latch + UINT8 m_reg[13]; // registers + + // timers + emu_timer *m_clock_timer; + emu_timer *m_busy_timer; +}; + + +// device type definition +extern const device_type MSM58321; + +#endif diff --git a/src/devices/machine/msm6242.c b/src/devices/machine/msm6242.c new file mode 100644 index 00000000000..a4a188cbcb6 --- /dev/null +++ b/src/devices/machine/msm6242.c @@ -0,0 +1,557 @@ +// license:BSD-3-Clause +// copyright-holders:Nathan Woods +/*************************************************************************** + + MSM6242 / Epson RTC 62421 / 62423 Real Time Clock + + TODO: + - Stop timer callbacks on every single tick + - HOLD mechanism + - IRQs are grossly mapped + - STOP / RESET mechanism + - why skns.c games try to read uninitialized registers? + +***************************************************************************/ + +#include "emu.h" +#include "machine/msm6242.h" + + +//************************************************************************** +// CONSTANTS +//************************************************************************** + +enum +{ + MSM6242_REG_S1 = 0, + MSM6242_REG_S10, + MSM6242_REG_MI1, + MSM6242_REG_MI10, + MSM6242_REG_H1, + MSM6242_REG_H10, + MSM6242_REG_D1, + MSM6242_REG_D10, + MSM6242_REG_MO1, + MSM6242_REG_MO10, + MSM6242_REG_Y1, + MSM6242_REG_Y10, + MSM6242_REG_W, + MSM6242_REG_CD, + MSM6242_REG_CE, + MSM6242_REG_CF +}; + +#define TIMER_RTC_CALLBACK 1 + +#define LOG_UNMAPPED 0 +#define LOG_IRQ 0 +#define LOG_IRQ_ENABLE 0 + + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +// device type definition +const device_type MSM6242 = &device_creator; + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// msm6242_device - constructor +//------------------------------------------------- + +msm6242_device::msm6242_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, MSM6242, "MSM6242 RTC", tag, owner, clock, "msm6242", __FILE__), + device_rtc_interface(mconfig, *this), + m_out_int_handler(*this) +{ +} + + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void msm6242_device::device_start() +{ + m_out_int_handler.resolve(); + + // let's call the timer callback every tick + m_timer = timer_alloc(TIMER_RTC_CALLBACK); + m_timer->adjust(attotime::zero); + + // get real time from system + set_current_time(machine()); + + // set up registers + m_tick = 0; + m_irq_flag = 0; + m_irq_type = 0; + + // TODO: skns writes 0x4 to D then expects E == 6 and F == 4, perhaps those are actually saved in the RTC CMOS? + m_reg[0] = 0; + m_reg[1] = 0x6; + m_reg[2] = 0x4; + + // save states + save_item(NAME(m_reg)); + save_item(NAME(m_irq_flag)); + save_item(NAME(m_irq_type)); + save_item(NAME(m_tick)); + save_item(NAME(m_last_update_time)); +} + + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void msm6242_device::device_reset() +{ + if (!m_out_int_handler.isnull()) + m_out_int_handler(CLEAR_LINE); +} + + + +//------------------------------------------------- +// device_pre_save - called prior to saving the +// state, so that registered variables can be +// properly normalized +//------------------------------------------------- + +void msm6242_device::device_pre_save() +{ + // update the RTC registers so that we can get the right values + update_rtc_registers(); +} + + + +//------------------------------------------------- +// device_post_load - called after the loading a +// saved state, so that registered variables can +// be expaneded as necessary +//------------------------------------------------- + +void msm6242_device::device_post_load() +{ + // this is probably redundant, because the timer state is saved; but it isn't + // a terribly bad idea + update_timer(); +} + + + +//------------------------------------------------- +// device_timer - called whenever a device timer +// fires +//------------------------------------------------- + +void msm6242_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch(id) + { + case TIMER_RTC_CALLBACK: + rtc_timer_callback(); + break; + } +} + + + +//------------------------------------------------- +// irq +//------------------------------------------------- + +void msm6242_device::irq(UINT8 irq_type) +{ + // are we actually raising this particular IRQ? + if (m_irq_flag == 1 && m_irq_type == irq_type) + { + // log if appropriate + if (LOG_IRQ) + logerror("%s: MSM6242 logging IRQ #%d\n", machine().describe_context(), (int) irq_type); + + // ...and assert the output line + if (!m_out_int_handler.isnull()) + m_out_int_handler(ASSERT_LINE); + } +} + + + +//------------------------------------------------- +// bump +//------------------------------------------------- + +UINT64 msm6242_device::bump(int rtc_register, UINT64 delta, UINT64 register_min, UINT64 register_range) +{ + UINT64 carry = 0; + + if (delta > 0) + { + // get the register value + UINT64 register_value = (rtc_register == RTC_TICKS) + ? m_tick + : get_clock_register(rtc_register); + + // increment the value + UINT64 new_register_value = ((register_value - register_min + delta) % register_range) + register_min; + + // calculate the cary + carry = ((register_value - register_min) + delta) / register_range; + + // store the new register value + if (rtc_register == RTC_TICKS) + m_tick = (UINT16) new_register_value; + else + set_clock_register(rtc_register, (int) new_register_value); + } + + return carry; +} + + + +//------------------------------------------------- +// current_time +//------------------------------------------------- + +UINT64 msm6242_device::current_time() +{ + return machine().time().as_ticks(clock()); +} + + + +//------------------------------------------------- +// update_rtc_registers +//------------------------------------------------- + +void msm6242_device::update_rtc_registers() +{ + // get the absolute current time, in ticks + UINT64 curtime = current_time(); + + // how long as it been since we last updated? + UINT64 delta = curtime - m_last_update_time; + + // set current time + m_last_update_time = curtime; + + // no delta? just return + if (delta == 0) + return; + + // ticks + if ((m_tick % 200) != (int)((delta + m_tick) % 0x200)) + irq(IRQ_64THSECOND); + delta = bump(RTC_TICKS, delta, 0, 0x8000); + if (delta == 0) + return; + + // seconds + irq(IRQ_SECOND); + delta = bump(RTC_SECOND, delta, 0, 60); + if (delta == 0) + return; + + // minutes + irq(IRQ_MINUTE); + delta = bump(RTC_MINUTE, delta, 0, 60); + if (delta == 0) + return; + + // hours + irq(IRQ_HOUR); + delta = bump(RTC_HOUR, delta, 0, 24); + if (delta == 0) + return; + + // days + while(delta--) + advance_days(); +} + + + +//------------------------------------------------- +// update_timer +//------------------------------------------------- + +void msm6242_device::update_timer() +{ + UINT64 callback_ticks = 0; + attotime callback_time = attotime::never; + + // we only need to call back if the IRQ flag is on, and we have a handler + if (!m_out_int_handler.isnull() && m_irq_flag == 1) + { + switch(m_irq_type) + { + case IRQ_HOUR: + callback_ticks += (59 - get_clock_register(RTC_MINUTE)) * (0x8000 * 60); + // fall through + + case IRQ_MINUTE: + callback_ticks += (59 - get_clock_register(RTC_SECOND)) * 0x8000; + // fall through + + case IRQ_SECOND: + callback_ticks += 0x8000 - m_tick; + break; + + case IRQ_64THSECOND: + callback_ticks += 0x200 - (m_tick % 0x200); + break; + } + } + + // if set, convert ticks to an attotime + if (callback_ticks > 0) + { + // get the current time + UINT64 curtime = current_time(); + + // we need the absolute callback time, in ticks + UINT64 absolute_callback_ticks = curtime + callback_ticks; + + // convert that to an attotime + attotime absolute_callback_time = attotime::from_ticks(absolute_callback_ticks, clock()); + + // and finally get the delta as an attotime + callback_time = absolute_callback_time - machine().time(); + } + + m_timer->adjust(callback_time); +} + + + +//------------------------------------------------- +// rtc_clock_updated +//------------------------------------------------- + +void msm6242_device::rtc_clock_updated(int year, int month, int day, int day_of_week, int hour, int minute, int second) +{ + m_last_update_time = current_time(); +} + + + +//------------------------------------------------- +// rtc_timer_callback +//------------------------------------------------- + +void msm6242_device::rtc_timer_callback() +{ + update_rtc_registers(); + update_timer(); +} + + + +//------------------------------------------------- +// get_clock_nibble +//------------------------------------------------- + +UINT8 msm6242_device::get_clock_nibble(int rtc_register, bool high) +{ + int value = get_clock_register(rtc_register); + value /= high ? 10 : 1; + return (UINT8) ((value % 10) & 0x0F); +} + + + +//------------------------------------------------- +// get_clock_nibble +//------------------------------------------------- + +const char *msm6242_device::irq_type_string(UINT8 irq_type) +{ + switch(irq_type) + { + case IRQ_64THSECOND: return "1/64th second"; + case IRQ_SECOND: return "second"; + case IRQ_MINUTE: return "minute"; + case IRQ_HOUR: return "hour"; + default: return "???"; + } +} + + + +//************************************************************************** +// READ/WRITE HANDLERS +//************************************************************************** + +//------------------------------------------------- +// read +//------------------------------------------------- + +READ8_MEMBER( msm6242_device::read ) +{ + int hour, pm; + UINT8 result; + + // update the registers; they may have changed + update_rtc_registers(); + + switch(offset) + { + case MSM6242_REG_S1: + result = get_clock_nibble(RTC_SECOND, false); + break; + + case MSM6242_REG_S10: + result = get_clock_nibble(RTC_SECOND, true); + break; + + case MSM6242_REG_MI1: + result = get_clock_nibble(RTC_MINUTE, false); + break; + + case MSM6242_REG_MI10: + result = get_clock_nibble(RTC_MINUTE, true); + break; + + case MSM6242_REG_H1: + case MSM6242_REG_H10: + pm = 0; + hour = get_clock_register(RTC_HOUR); + + // check for 12/24 hour mode + if ((m_reg[2] & 0x04) == 0) // 12 hour mode? + { + if (hour >= 12) + pm = 1; + + hour %= 12; + + if ( hour == 0 ) + hour = 12; + } + + if ( offset == MSM6242_REG_H1 ) + result = hour % 10; + else + result = (hour / 10) | (pm <<2); + break; + + case MSM6242_REG_D1: + result = get_clock_nibble(RTC_DAY, false); + break; + + case MSM6242_REG_D10: + result = get_clock_nibble(RTC_DAY, true); + break; + + case MSM6242_REG_MO1: + result = get_clock_nibble(RTC_MONTH, false); + break; + + case MSM6242_REG_MO10: + result = get_clock_nibble(RTC_MONTH, true); + break; + + case MSM6242_REG_Y1: + result = get_clock_nibble(RTC_YEAR, false); + break; + + case MSM6242_REG_Y10: + result = get_clock_nibble(RTC_YEAR, true); + break; + + case MSM6242_REG_W: + result = (UINT8) (get_clock_register(RTC_DAY_OF_WEEK) - 1); + break; + + case MSM6242_REG_CD: + case MSM6242_REG_CE: + case MSM6242_REG_CF: + result = m_reg[offset - MSM6242_REG_CD]; + break; + + default: + result = 0x00; + if (LOG_UNMAPPED) + logerror("%s: MSM6242 unmapped offset %02x read\n", machine().describe_context(), offset); + break; + } + + return result; +} + + + +//------------------------------------------------- +// write +//------------------------------------------------- + +WRITE8_MEMBER( msm6242_device::write ) +{ + switch(offset) + { + case MSM6242_REG_CD: + // x--- 30s ADJ + // -x-- IRQ FLAG + // --x- BUSY + // ---x HOLD + m_reg[0] = data & 0x0f; + break; + + case MSM6242_REG_CE: + // xx-- t0,t1 (timing irq) + // --x- STD + // ---x MASK + m_reg[1] = data & 0x0f; + if((data & 3) == 0) // MASK & STD = 0 + { + m_irq_flag = 1; + m_irq_type = (data & 0xc) >> 2; + + if (LOG_IRQ_ENABLE) + logerror("%s: MSM6242 enabling irq '%s'\n", machine().describe_context(), irq_type_string(m_irq_type)); + } + else + { + m_irq_flag = 0; + if ( !m_out_int_handler.isnull() ) + m_out_int_handler( CLEAR_LINE ); + + if (LOG_IRQ_ENABLE) + logerror("%s: MSM6242 disabling irq\n", machine().describe_context()); + } + break; + + case MSM6242_REG_CF: + // x--- TEST + // -x-- 24/12 + // --x- STOP + // ---x RESET + + // the 12/24 mode bit can only be changed when RESET does a 1 -> 0 transition + if (((data & 0x01) == 0x00) && (m_reg[2] & 0x01)) + m_reg[2] = (m_reg[2] & ~0x04) | (data & 0x04); + else + m_reg[2] = (data & 0x0b) | (m_reg[2] & 4); + break; + + default: + if (LOG_UNMAPPED) + logerror("%s: MSM6242 unmapped offset %02x written with %02x\n", machine().describe_context(), offset, data); + break; + } + + // update the timer variable in response to potential changes + update_timer(); +} diff --git a/src/devices/machine/msm6242.h b/src/devices/machine/msm6242.h new file mode 100644 index 00000000000..4d44fd1b860 --- /dev/null +++ b/src/devices/machine/msm6242.h @@ -0,0 +1,83 @@ +// license:BSD-3-Clause +// copyright-holders:Nathan Woods +/*************************************************************************** + + MSM6242 Real Time Clock + +***************************************************************************/ + +#pragma once + +#ifndef __MSM6242DEV_H__ +#define __MSM6242DEV_H__ + +#include "emu.h" + + +#define MCFG_MSM6242_OUT_INT_HANDLER(_devcb) \ + devcb = &msm6242_device::set_out_int_handler(*device, DEVCB_##_devcb); + + +// ======================> msm6242_device + +class msm6242_device : public device_t, + public device_rtc_interface +{ +public: + // construction/destruction + msm6242_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + + template static devcb_base &set_out_int_handler(device_t &device, _Object object) { return downcast(device).m_out_int_handler.set_callback(object); } + + // I/O operations + DECLARE_WRITE8_MEMBER( write ); + DECLARE_READ8_MEMBER( read ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_pre_save(); + virtual void device_post_load(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + // rtc overrides + virtual void rtc_clock_updated(int year, int month, int day, int day_of_week, int hour, int minute, int second); + +private: + static const int RTC_TICKS = ~0; + + static const UINT8 IRQ_64THSECOND = 0; + static const UINT8 IRQ_SECOND = 1; + static const UINT8 IRQ_MINUTE = 2; + static const UINT8 IRQ_HOUR = 3; + + // state + UINT8 m_reg[3]; + UINT8 m_irq_flag; + UINT8 m_irq_type; + UINT16 m_tick; + + // incidentals + devcb_write_line m_out_int_handler; + emu_timer * m_timer; + UINT64 m_last_update_time; // last update time, in clock cycles + + // methods + void rtc_timer_callback(); + UINT64 current_time(); + void irq(UINT8 irq_type); + UINT64 bump(int rtc_register, UINT64 delta, UINT64 register_min, UINT64 register_range); + void update_rtc_registers(); + void update_timer(); + UINT8 get_clock_nibble(int rtc_register, bool high); + static const char *irq_type_string(UINT8 irq_type); +}; + + +// device type definition +extern const device_type MSM6242; + + +#endif /* __MSM6242DEV_H__ */ diff --git a/src/devices/machine/ncr5380.c b/src/devices/machine/ncr5380.c new file mode 100644 index 00000000000..175e9130c1c --- /dev/null +++ b/src/devices/machine/ncr5380.c @@ -0,0 +1,424 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/* + * ncr5380.c + * + * NCR 5380 SCSI controller, as seen in many 680x0 Macs, + * official Apple add-on cards for the Apple II series, + * and probably some PC and Amiga cards as well. + * + * Emulation by R. Belmont. + * + * References: + * Zilog 5380 manual + * "Inside Macintosh: Devices" (formerly online at http://www.manolium.org/dev/techsupport/insidemac/Devices/Devices-2.html ) + * + * NOTES: + * This implementation is tied closely to the drivers found in the Mac Plus ROM and the routines in Mac + * System 6 and 7 that it patches out the ROM traps with. While attempts have been made to + * have the behavior work according to the manual and not the specific Apple driver code, + * there are almost certainly areas where that is true. + * + */ + +#include "emu.h" +#include "ncr5380.h" + +#define VERBOSE (0) + +static const char *const rnames[] = +{ + "Current data", + "Initiator cmd", + "Mode", + "Target cmd", + "Bus status", + "Bus and status", + "Input data", + "Reset parity" +}; + +static const char *const wnames[] = +{ + "Output data", + "Initiator cmd", + "Mode", + "Target cmd", + "Select enable", + "Start DMA", + "DMA target", + "DMA initiator rec" +}; + +// get the length of a SCSI command based on it's command byte type +static int get_cmd_len(int cbyte) +{ + int group; + + group = (cbyte>>5) & 7; + + if (group == 0) return 6; + if (group == 1 || group == 2) return 10; + if (group == 5) return 12; + + fatalerror("NCR5380: Unknown SCSI command group %d\n", group); + + // never executed + //return 6; +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +const device_type NCR5380 = &device_creator; + +//------------------------------------------------- +// ncr5380_device - constructor/destructor +//------------------------------------------------- + +ncr5380_device::ncr5380_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + legacy_scsi_host_adapter(mconfig, NCR5380, "5380 SCSI", tag, owner, clock, "ncr5380", __FILE__), + m_irq_cb(*this) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void ncr5380_device::device_start() +{ + legacy_scsi_host_adapter::device_start(); + + memset(m_5380_Registers, 0, sizeof(m_5380_Registers)); + memset(m_5380_Data, 0, sizeof(m_5380_Data)); + + m_next_req_flag = 0; + m_irq_cb.resolve_safe(); + + save_item(NAME(m_5380_Registers)); + save_item(NAME(m_5380_Command)); + save_item(NAME(m_5380_Data)); + save_item(NAME(m_last_id)); + save_item(NAME(m_cmd_ptr)); + save_item(NAME(m_d_ptr)); + save_item(NAME(m_d_limit)); + save_item(NAME(m_next_req_flag)); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void ncr5380_device::device_reset() +{ + memset(m_5380_Registers, 0, sizeof(m_5380_Registers)); + memset(m_5380_Data, 0, sizeof(m_5380_Data)); + + m_next_req_flag = 0; + m_cmd_ptr = 0; + m_d_ptr = 0; + m_d_limit = 0; + m_last_id = 0; +} + +//------------------------------------------------- +// device_stop - device-specific stop/shutdown +//------------------------------------------------- +void ncr5380_device::device_stop() +{ +} + +//------------------------------------------------- +// Public API +//------------------------------------------------- +UINT8 ncr5380_device::ncr5380_read_reg(UINT32 offset) +{ + int reg = offset & 7; + UINT8 rv = 0; + + switch( reg ) + { + case R5380_CURDATA: + case R5380_INPUTDATA: + rv = m_5380_Registers[reg]; + + // if we're in the data transfer phase or DMA, readback device data instead + if (((m_5380_Registers[R5380_BUSSTATUS] & 0x1c) == 0x04) || (m_5380_Registers[R5380_BUSSTATUS] & 0x40)) + { + rv = m_5380_Data[m_d_ptr]; + + // if the limit's less than 512, only read "limit" bytes + if (m_d_limit < 512) + { + if (m_d_ptr < (m_d_limit-1)) + { + m_d_ptr++; + } + else + { + m_next_req_flag = 1; + } + } + else + { + if (m_d_ptr < 511) + { + m_d_ptr++; + } + else + { + m_d_limit -= 512; + m_d_ptr = 0; + + m_next_req_flag = 1; + + // don't issue a "false" read + if (m_d_limit > 0) + { + read_data(m_5380_Data, (m_d_limit < 512) ? m_d_limit : 512); + } + else + { + // if this is DMA, signal DMA end + if (m_5380_Registers[R5380_BUSSTATUS] & 0x40) + { + m_5380_Registers[R5380_BUSSTATUS] |= 0x80; + } + + // drop /REQ + m_5380_Registers[R5380_BUSSTATUS] &= ~0x20; + + // clear phase match + m_5380_Registers[R5380_BUSANDSTAT] &= ~0x08; + } + } + } + + } + break; + + default: + rv = m_5380_Registers[reg]; + + // temporarily drop /REQ + if ((reg == R5380_BUSSTATUS) && (m_next_req_flag)) + { + rv &= ~0x20; + m_next_req_flag = 0; + } + break; + } + + if (VERBOSE) + logerror("%s NCR5380: read %s (reg %d) = %02x\n", machine().describe_context(), rnames[reg], reg, rv); + + return rv; +} + +void ncr5380_device::ncr5380_write_reg(UINT32 offset, UINT8 data) +{ + int reg = offset & 7; + + if (VERBOSE) + logerror("%s NCR5380: %02x to %s (reg %d)\n", machine().describe_context(), data, wnames[reg], reg); + + switch( reg ) + { + case R5380_OUTDATA: + // if we're in the command phase, collect the command bytes + if ((m_5380_Registers[R5380_BUSSTATUS] & 0x1c) == 0x08) + { + m_5380_Command[m_cmd_ptr++] = data; + } + + // if we're in the select phase, this is the target id + if (m_5380_Registers[R5380_INICOMMAND] == 0x04) + { + data &= 0x7f; // clear the high bit + if (data == 0x40) + { + m_last_id = 6; + } + else if (data == 0x20) + { + m_last_id = 5; + } + else if (data == 0x10) + { + m_last_id = 4; + } + else if (data == 0x08) + { + m_last_id = 3; + } + else if (data == 0x04) + { + m_last_id = 2; + } + else if (data == 0x02) + { + m_last_id = 1; + } + else if (data == 0x01) + { + m_last_id = 0; + } + } + + // if this is a write, accumulate accordingly + if (((m_5380_Registers[R5380_BUSSTATUS] & 0x1c) == 0x00) && (m_5380_Registers[R5380_INICOMMAND] == 1)) + { + m_5380_Data[m_d_ptr] = data; + + // if we've hit a sector, flush + if (m_d_ptr == 511) + { + write_data(&m_5380_Data[0], 512); + + m_d_limit -= 512; + m_d_ptr = 0; + + // no more data? set DMA END flag + if (m_d_limit <= 0) + { + m_5380_Registers[R5380_BUSANDSTAT] = 0xc8; + } + } + else + { + m_d_ptr++; + } + + // make sure we don't upset the status readback + data = 0; + } + break; + + case R5380_INICOMMAND: + if (data == 0) // dropping the bus + { + // make sure it's not busy + m_5380_Registers[R5380_BUSSTATUS] &= ~0x40; + + // are we in the command phase? + if ((m_5380_Registers[R5380_BUSSTATUS] & 0x1c) == 0x08) + { + // is the current command complete? + if (get_cmd_len(m_5380_Command[0]) == m_cmd_ptr) + { + if (VERBOSE) + logerror("%s NCR5380: Command (to ID %d): %x %x %x %x %x %x %x %x %x %x\n", machine().describe_context(), m_last_id, m_5380_Command[0], m_5380_Command[1], m_5380_Command[2], m_5380_Command[3], m_5380_Command[4], m_5380_Command[5], m_5380_Command[6], m_5380_Command[7], m_5380_Command[8], m_5380_Command[9]); + + send_command(&m_5380_Command[0], 16); + m_d_limit = get_length(); + + if (VERBOSE) + logerror("NCR5380: Command returned %d bytes\n", m_d_limit); + + m_d_ptr = 0; + + // is data available? + if (m_d_limit > 0) + { + // make sure for transfers under 512 bytes that we always pad with a zero + if (m_d_limit < 512) + { + m_5380_Data[m_d_limit] = 0; + } + + // read back the amount available, or 512 bytes, whichever is smaller + read_data(m_5380_Data, (m_d_limit < 512) ? m_d_limit : 512); + + // raise REQ to indicate data is available + m_5380_Registers[R5380_BUSSTATUS] |= 0x20; + } + } + } + + } + + if (data == 5) // want the bus? + { + // if the device exists, make the bus busy. + // otherwise don't. + + if (select(m_last_id)) + { + if (VERBOSE) + logerror("NCR5380: Giving the bus for ID %d\n", m_last_id); + m_5380_Registers[R5380_BUSSTATUS] |= 0x40; + } + else + { + if (VERBOSE) + logerror("NCR5380: Rejecting the bus for ID %d\n", m_last_id); + m_5380_Registers[R5380_BUSSTATUS] &= ~0x40; + } + } + + if (data == 1) // data bus (prelude to command?) + { + // raise REQ + m_5380_Registers[R5380_BUSSTATUS] |= 0x20; + } + + if (data & 0x10) // ACK drops REQ + { + // drop REQ + m_5380_Registers[R5380_BUSSTATUS] &= ~0x20; + } + break; + + case R5380_MODE: + if (data == 2) // DMA + { + // put us in DMA mode + m_5380_Registers[R5380_BUSANDSTAT] |= 0x40; + } + + if (data == 1) // arbitrate? + { + m_5380_Registers[R5380_INICOMMAND] |= 0x40; // set arbitration in progress + m_5380_Registers[R5380_INICOMMAND] &= ~0x20; // clear "lost arbitration" + } + + if (data == 0) + { + // drop DMA mode + m_5380_Registers[R5380_BUSANDSTAT] &= ~0x40; + } + break; + + case R5380_TARGETCMD: + // sync the bus phase with what was just written + m_5380_Registers[R5380_BUSSTATUS] &= ~0x1c; + m_5380_Registers[R5380_BUSSTATUS] |= (data & 7)<<2; + + // and set the "phase match" flag + m_5380_Registers[R5380_BUSANDSTAT] |= 0x08; + + // and set /REQ + m_5380_Registers[R5380_BUSSTATUS] |= 0x20; + + // if we're entering the command phase, start accumulating the data + if ((m_5380_Registers[R5380_BUSSTATUS] & 0x1c) == 0x08) + { + m_cmd_ptr = 0; + } + break; + + default: + break; + } + + m_5380_Registers[reg] = data; + + // note: busandstat overlaps startdma, so we need to do this here! + if (reg == R5380_STARTDMA) + { + m_5380_Registers[R5380_BUSANDSTAT] = 0x48; + } +} diff --git a/src/devices/machine/ncr5380.h b/src/devices/machine/ncr5380.h new file mode 100644 index 00000000000..678460f6133 --- /dev/null +++ b/src/devices/machine/ncr5380.h @@ -0,0 +1,70 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/* + * ncr5380.h SCSI controller + * + */ + +#ifndef _NCR5380_H_ +#define _NCR5380_H_ + +#include "legscsi.h" + +// 5380 registers +enum +{ + R5380_CURDATA = 0, // current SCSI data (read only) + R5380_OUTDATA = 0, // output data (write only) + R5380_INICOMMAND, // initiator command + R5380_MODE, // mode + R5380_TARGETCMD, // target command + R5380_SELENABLE, // select enable (write only) + R5380_BUSSTATUS = R5380_SELENABLE, // bus status (read only) + R5380_STARTDMA, // start DMA send (write only) + R5380_BUSANDSTAT = R5380_STARTDMA, // bus and status (read only) + R5380_DMATARGET, // DMA target (write only) + R5380_INPUTDATA = R5380_DMATARGET, // input data (read only) + R5380_DMAINIRECV, // DMA initiator receive (write only) + R5380_RESETPARITY = R5380_DMAINIRECV // reset parity/interrupt (read only) +}; + +// special Mac Plus registers - they implemented it weird +#define R5380_OUTDATA_DTACK (R5380_OUTDATA | 0x10) +#define R5380_CURDATA_DTACK (R5380_CURDATA | 0x10) + +// device stuff + +#define MCFG_NCR5380_IRQ_CB(_devcb) \ + devcb = &ncr5380_device::set_irq_callback(*device, DEVCB_##_devcb); + +class ncr5380_device : public legacy_scsi_host_adapter +{ +public: + // construction/destruction + ncr5380_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + template static devcb_base &set_irq_callback(device_t &device, _Object object) { return downcast(device).m_irq_cb.set_callback(object); } + + // our API + UINT8 ncr5380_read_reg(UINT32 offset); + void ncr5380_write_reg(UINT32 offset, UINT8 data); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_stop(); + +private: + UINT8 m_5380_Registers[8]; + UINT8 m_last_id; + UINT8 m_5380_Command[32]; + INT32 m_cmd_ptr, m_d_ptr, m_d_limit, m_next_req_flag; + UINT8 m_5380_Data[512]; + devcb_write_line m_irq_cb; /* irq callback */ +}; + +// device type definition +extern const device_type NCR5380; + +#endif diff --git a/src/devices/machine/ncr5380n.c b/src/devices/machine/ncr5380n.c new file mode 100644 index 00000000000..ed2270ba097 --- /dev/null +++ b/src/devices/machine/ncr5380n.c @@ -0,0 +1,586 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont, Olivier Galibert +/********************************************************************* + + ncr5380n.c + + Implementation of the NCR 5380, aka the Zilog Z5380 + + TODO: + - IRQs + - Target mode + + 40801766 - IIx ROM waiting point for "next read fails" + +*********************************************************************/ + +#include "emu.h" +#include "ncr5380n.h" + +const device_type NCR5380N = &device_creator; + +DEVICE_ADDRESS_MAP_START(map, 8, ncr5380n_device) + AM_RANGE(0x0, 0x0) AM_READWRITE(scsidata_r, outdata_w) + AM_RANGE(0x1, 0x1) AM_READWRITE(icmd_r, icmd_w) + AM_RANGE(0x2, 0x2) AM_READWRITE(mode_r, mode_w) + AM_RANGE(0x3, 0x3) AM_READWRITE(command_r, command_w) + AM_RANGE(0x4, 0x4) AM_READWRITE(status_r, selenable_w) + AM_RANGE(0x5, 0x5) AM_READWRITE(busandstatus_r, startdmasend_w) + AM_RANGE(0x6, 0x6) AM_READWRITE(indata_r, startdmatargetrx_w) + AM_RANGE(0x7, 0x7) AM_READWRITE(resetparityirq_r, startdmainitrx_w) +ADDRESS_MAP_END + +ncr5380n_device::ncr5380n_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nscsi_device(mconfig, NCR5380N, "5380 SCSI (new)", tag, owner, clock, "ncr5380", __FILE__), + m_irq_handler(*this), + m_drq_handler(*this) +{ +} + +void ncr5380n_device::device_start() +{ + save_item(NAME(m_tcommand)); + save_item(NAME(m_icommand)); + save_item(NAME(status)); + save_item(NAME(istatus)); + save_item(NAME(m_busstatus)); + save_item(NAME(tcount)); + save_item(NAME(mode)); + save_item(NAME(irq)); + save_item(NAME(drq)); + save_item(NAME(clock_conv)); + save_item(NAME(m_dmalatch)); + + m_irq_handler.resolve_safe(); + m_drq_handler.resolve_safe(); + + tcount = 0; + status = 0; + bus_id = 0; + select_timeout = 0; + tm = timer_alloc(0); +} + +void ncr5380n_device::device_reset() +{ + clock_conv = 2; + sync_period = 5; + sync_offset = 0; + seq = 0; + status = 0; + m_tcommand = 0; + m_icommand = 0; + istatus = 0; + m_busstatus = 0; + irq = false; + m_irq_handler(irq); + reset_soft(); +} + +void ncr5380n_device::reset_soft() +{ + state = IDLE; + scsi_bus->ctrl_w(scsi_refid, 0, S_ALL); // clear any signals we're driving + scsi_bus->ctrl_wait(scsi_refid, S_ALL, S_ALL); + status = 0; + drq = false; + m_drq_handler(drq); + reset_disconnect(); +} + +void ncr5380n_device::reset_disconnect() +{ + mode = MODE_D; +} + +//static int last_phase = -1; + +void ncr5380n_device::scsi_ctrl_changed() +{ + UINT32 ctrl = scsi_bus->ctrl_r(); + +// printf("scsi_ctrl_changed: lines now %x\n", ctrl); + +/* if ((ctrl & (S_PHASE_MASK|S_SEL|S_BSY)) != last_phase) + { + printf("phase now %d, REQ %x SEL %x BSY %x\n", ctrl & S_PHASE_MASK, ctrl & S_REQ, ctrl & S_SEL, ctrl & S_BSY); + last_phase = (S_PHASE_MASK|S_SEL|S_BSY); + }*/ + + // recalculate phase match + m_busstatus &= ~BAS_PHASEMATCH; + if ((ctrl & S_PHASE_MASK) == (m_tcommand & S_PHASE_MASK)) + { + m_busstatus |= BAS_PHASEMATCH; + } + + if (m_mode & MODE_DMA) + { + // if BSY drops or the phase goes mismatch, that terminates the DMA + if ((!(ctrl & S_BSY)) || !(m_busstatus & BAS_PHASEMATCH)) + { +// printf("BSY dropped or phase mismatch during DMA, ending DMA\n"); + m_mode &= ~MODE_DMA; + m_busstatus |= BAS_ENDOFDMA; + drq_clear(); + } + } + + if(ctrl & S_RST) { + logerror("%s: scsi bus reset\n", tag()); + return; + } + + step(false); +} + +void ncr5380n_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + step(true); +} + +void ncr5380n_device::step(bool timeout) +{ + UINT32 ctrl = scsi_bus->ctrl_r(); + UINT32 data = scsi_bus->data_r(); + + if(0) + printf("%s: state=%d.%d %s\n", + tag(), state & STATE_MASK, (state & SUB_MASK) >> SUB_SHIFT, + timeout ? "timeout" : "change"); + + if(mode == MODE_I && !(ctrl & S_BSY)) { + state = IDLE; + reset_disconnect(); + check_irq(); + } + switch(state & SUB_MASK ? state & SUB_MASK : state & STATE_MASK) { + case IDLE: + break; + + case ARB_COMPLETE << SUB_SHIFT: { + if(!timeout) + break; + + int win; + for(win=7; win>=0 && !(data & (1<data_w(scsi_refid, 0); + scsi_bus->ctrl_w(scsi_refid, 0, S_ALL); + fatalerror("need to wait for bus free\n"); + } + + state &= STATE_MASK; + step(true); + break; + } + + case SEND_WAIT_SETTLE << SUB_SHIFT: + if(!timeout) + break; + + state = (state & STATE_MASK) | (SEND_WAIT_REQ_0 << SUB_SHIFT); + step(false); + break; + + case SEND_WAIT_REQ_0 << SUB_SHIFT: + if(ctrl & S_REQ) + break; + state = state & STATE_MASK; + scsi_bus->data_w(scsi_refid, 0); + scsi_bus->ctrl_w(scsi_refid, 0, S_ACK); + step(false); + + // byte's done, ask for another if the target hasn't said otherwise + if (m_mode & MODE_DMA) + { + drq_set(); + } + break; + + case RECV_WAIT_REQ_1 << SUB_SHIFT: + if(!(ctrl & S_REQ)) + break; + + state = (state & STATE_MASK) | (RECV_WAIT_SETTLE << SUB_SHIFT); + delay_cycles(sync_period); + break; + + case RECV_WAIT_SETTLE << SUB_SHIFT: + if(!timeout) + break; + + m_dmalatch = scsi_bus->data_r(); + scsi_bus->ctrl_w(scsi_refid, S_ACK, S_ACK); + state = (state & STATE_MASK) | (RECV_WAIT_REQ_0 << SUB_SHIFT); + step(false); + break; + + case RECV_WAIT_REQ_0 << SUB_SHIFT: + if(ctrl & S_REQ) + break; + state = state & STATE_MASK; + step(false); + + drq_set(); // raise DRQ now that we've completed + break; + + default: + printf("%s: step() unexpected state %d.%d\n", + tag(), + state & STATE_MASK, (state & SUB_MASK) >> SUB_SHIFT); + exit(0); + } +} + +void ncr5380n_device::send_byte() +{ + state = (state & STATE_MASK) | (SEND_WAIT_SETTLE << SUB_SHIFT); + scsi_bus->data_w(scsi_refid, m_dmalatch); + + scsi_bus->ctrl_w(scsi_refid, S_ACK, S_ACK); + scsi_bus->ctrl_wait(scsi_refid, S_REQ, S_REQ); + delay_cycles(sync_period); +} + +void ncr5380n_device::recv_byte() +{ + state = (state & STATE_MASK) | (RECV_WAIT_REQ_1 << SUB_SHIFT); + step(false); +} + +void ncr5380n_device::function_bus_complete() +{ + state = IDLE; +// istatus |= I_FUNCTION|I_BUS; + check_irq(); +} + +void ncr5380n_device::function_complete() +{ + state = IDLE; +// istatus |= I_FUNCTION; + check_irq(); +} + +void ncr5380n_device::bus_complete() +{ + state = IDLE; +// istatus |= I_BUS; + check_irq(); +} + +void ncr5380n_device::delay(int cycles) +{ + if(!clock_conv) + return; + cycles *= clock_conv; + tm->adjust(clocks_to_attotime(cycles)); +} + +void ncr5380n_device::delay_cycles(int cycles) +{ + tm->adjust(clocks_to_attotime(cycles)); +} + +READ8_MEMBER(ncr5380n_device::scsidata_r) +{ + return scsi_bus->data_r(); +} + +WRITE8_MEMBER(ncr5380n_device::outdata_w) +{ + m_outdata = data; + + // are we driving the data bus? + if (m_icommand & IC_DBUS) + { + scsi_bus->data_w(scsi_refid, data); + } +} + +READ8_MEMBER(ncr5380n_device::icmd_r) +{ + return m_icommand; +} + +WRITE8_MEMBER(ncr5380n_device::icmd_w) +{ + // asserting to drive the data bus? + if ((data & IC_DBUS) && !(m_icommand & IC_DBUS)) + { +// printf("%s: driving data bus with %02x\n", tag(), m_outdata); + scsi_bus->data_w(scsi_refid, m_outdata); + delay(2); + } + + // any control lines changing? + UINT8 mask = (data & IC_PHASEMASK) ^ (m_icommand & IC_PHASEMASK); + if (mask) + { + // translate data to nscsi + UINT8 newdata = 0; + + newdata = (data & IC_RST ? S_RST : 0) | + (data & IC_ACK ? S_ACK : 0) | + (data & IC_BSY ? S_BSY : 0) | + (data & IC_SEL ? S_SEL : 0) | + (data & IC_ATN ? S_ATN : 0); + +// printf("%s: changing control lines %04x\n", tag(), newdata); + scsi_bus->ctrl_w(scsi_refid, newdata, S_RST|S_ACK|S_BSY|S_SEL|S_ATN); + } + + m_icommand = (data & IC_WRITEMASK); + delay(2); +} + +READ8_MEMBER(ncr5380n_device::mode_r) +{ + return m_mode; +} + +WRITE8_MEMBER(ncr5380n_device::mode_w) +{ +// printf("%s: mode_w %02x (%08x)\n", tag(), data, space.device().safe_pc()); + // arbitration bit being set? + if ((data & MODE_ARBITRATE) && !(m_mode & MODE_ARBITRATE)) + { + // if SEL is selected and the assert SEL bit in the initiator + // command register is clear, fail + if ((scsi_bus->ctrl_r() & S_SEL) && !(m_icommand & IC_SEL)) + { + m_icommand |= IC_ARBLOST; + } + else + { + seq = 0; +// state = DISC_SEL_ARBITRATION; + arbitrate(); + } + } + else if (!(data & MODE_ARBITRATE) && (m_mode & MODE_ARBITRATE)) + { + // arbitration in progress bit ONLY clears when the host disables arbitration. (thanks, Zilog Z8530 manual!) + // the Apple II High Speed SCSI Card boot code explicitly requires this. + m_icommand &= ~ IC_ARBITRATION; + } + m_mode = data; +} + +READ8_MEMBER(ncr5380n_device::command_r) +{ +// logerror("%s: command_r %02x (%08x)\n", tag(), m_tcommand, space.device().safe_pc()); + return m_tcommand; +} + +WRITE8_MEMBER(ncr5380n_device::command_w) +{ +// printf("%s: command_w %02x (%08x)\n", tag(), data, space.device().safe_pc()); + m_tcommand = data; + + // recalculate phase match + m_busstatus &= ~BAS_PHASEMATCH; + if ((scsi_bus->ctrl_r() & S_PHASE_MASK) == (m_tcommand & S_PHASE_MASK)) + { + m_busstatus |= BAS_PHASEMATCH; + } +} + +void ncr5380n_device::arbitrate() +{ + m_icommand &= ~IC_ARBLOST; + m_icommand |= IC_ARBITRATION; // set in progress flag + state = (state & STATE_MASK) | (ARB_COMPLETE << SUB_SHIFT); + scsi_bus->data_w(scsi_refid, m_outdata); + scsi_bus->ctrl_w(scsi_refid, S_BSY, S_BSY); + m_icommand |= IC_BSY; // make sure BSY shows in icommand (Zilog 5380 manual suggests this behavior, Apple II High-Speed SCSI Card firmware requires it) + delay(11); +} + +void ncr5380n_device::check_irq() +{ + #if 0 + bool oldirq = irq; + irq = istatus != 0; + if(irq != oldirq) + m_irq_handler(irq); + #endif +} + +READ8_MEMBER(ncr5380n_device::status_r) +{ + UINT32 ctrl = scsi_bus->ctrl_r(); + UINT8 res = status | + (ctrl & S_RST ? ST_RST : 0) | + (ctrl & S_BSY ? ST_BSY : 0) | + (ctrl & S_REQ ? ST_REQ : 0) | + (ctrl & S_MSG ? ST_MSG : 0) | + (ctrl & S_CTL ? ST_CD : 0) | + (ctrl & S_INP ? ST_IO : 0) | + (ctrl & S_SEL ? ST_SEL : 0); + +// printf("%s: status_r %02x (%08x)\n", tag(), res, space.device().safe_pc()); + return res; +} + +WRITE8_MEMBER(ncr5380n_device::selenable_w) +{ +} + +READ8_MEMBER(ncr5380n_device::busandstatus_r) +{ + UINT32 ctrl = scsi_bus->ctrl_r(); + UINT8 res = m_busstatus | + (ctrl & S_ATN ? BAS_ATN : 0) | + (ctrl & S_ACK ? BAS_ACK : 0); + +// printf("%s: busandstatus_r %02x (%08x)\n", tag(), res, space.device().safe_pc()); + + return res; +} + +WRITE8_MEMBER(ncr5380n_device::startdmasend_w) +{ + printf("%02x to start dma send\n", data); + drq_set(); +} + +READ8_MEMBER(ncr5380n_device::indata_r) +{ + return dma_r(); +} + +WRITE8_MEMBER(ncr5380n_device::startdmatargetrx_w) +{ + printf("%02x to start dma target Rx\n", data); +} + +READ8_MEMBER(ncr5380n_device::resetparityirq_r) +{ + return 0; +} + +WRITE8_MEMBER(ncr5380n_device::startdmainitrx_w) +{ +// printf("%02x to start dma initiator Rx\n", data); + recv_byte(); +} + +void ncr5380n_device::dma_w(UINT8 val) +{ + // drop DRQ until we're ready for another byte + drq_clear(); + + if (m_mode & MODE_DMA) + { + m_dmalatch = val; + send_byte(); + } +} + +UINT8 ncr5380n_device::dma_r() +{ + // drop DRQ + drq_clear(); + + // set up to receive our next byte if still in DMA mode + scsi_bus->ctrl_w(scsi_refid, 0, S_ACK); + if (m_mode & MODE_DMA) + { + recv_byte(); + } + return m_dmalatch; +} + +void ncr5380n_device::drq_set() +{ + if(!drq) + { + drq = true; + m_busstatus |= BAS_DMAREQUEST; + m_drq_handler(drq); + } +} + +void ncr5380n_device::drq_clear() +{ + if(drq) + { + drq = false; + m_busstatus &= ~BAS_DMAREQUEST; + m_drq_handler(drq); + } +} + +READ8_MEMBER(ncr5380n_device::read) +{ + switch (offset & 7) + { + case 0: + return scsidata_r(space, offset); + + case 1: + return icmd_r(space, offset); + + case 2: + return mode_r(space, offset); + + case 3: + return command_r(space, offset); + + case 4: + return status_r(space, offset); + + case 5: + return busandstatus_r(space, offset); + + case 6: + return indata_r(space, offset); + + case 7: + return resetparityirq_r(space, offset); + } + + return 0xff; +} + +WRITE8_MEMBER(ncr5380n_device::write) +{ +// printf("%x to 5380 @ %x\n", data, offset); + switch (offset & 7) + { + case 0: + outdata_w(space, offset, data); + break; + + case 1: + icmd_w(space, offset, data); + break; + + case 2: + mode_w(space, offset, data); + break; + + case 3: + command_w(space, offset, data); + break; + + case 4: + selenable_w(space, offset, data); + break; + + case 5: + startdmasend_w(space, offset, data); + break; + + case 6: + startdmatargetrx_w(space, offset, data); + break; + + case 7: + startdmainitrx_w(space, offset, data); + break; + } +} diff --git a/src/devices/machine/ncr5380n.h b/src/devices/machine/ncr5380n.h new file mode 100644 index 00000000000..e9a142d78e5 --- /dev/null +++ b/src/devices/machine/ncr5380n.h @@ -0,0 +1,227 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont, Olivier Galibert +/********************************************************************* + + ncr5380n.c + + Implementation of the NCR 5380 + +*********************************************************************/ + +#ifndef NCR5380N_H +#define NCR5380N_H + +#include "machine/nscsi_bus.h" + +#define MCFG_NCR5380N_IRQ_HANDLER(_devcb) \ + devcb = &ncr5380n_device::set_irq_handler(*device, DEVCB_##_devcb); + +#define MCFG_NCR5380N_DRQ_HANDLER(_devcb) \ + devcb = &ncr5380n_device::set_drq_handler(*device, DEVCB_##_devcb); + +class ncr5380n_device : public nscsi_device +{ +public: + ncr5380n_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // static configuration helpers + template static devcb_base &set_irq_handler(device_t &device, _Object object) { return downcast(device).m_irq_handler.set_callback(object); } + template static devcb_base &set_drq_handler(device_t &device, _Object object) { return downcast(device).m_drq_handler.set_callback(object); } + + DECLARE_ADDRESS_MAP(map, 8); + + DECLARE_READ8_MEMBER(scsidata_r); + DECLARE_WRITE8_MEMBER(outdata_w); + DECLARE_READ8_MEMBER(icmd_r); + DECLARE_WRITE8_MEMBER(icmd_w); + DECLARE_READ8_MEMBER(mode_r); + DECLARE_WRITE8_MEMBER(mode_w); + DECLARE_READ8_MEMBER(command_r); + DECLARE_WRITE8_MEMBER(command_w); + DECLARE_READ8_MEMBER(status_r); + DECLARE_WRITE8_MEMBER(selenable_w); + DECLARE_READ8_MEMBER(busandstatus_r); + DECLARE_WRITE8_MEMBER(startdmasend_w); + DECLARE_READ8_MEMBER(indata_r); + DECLARE_WRITE8_MEMBER(startdmatargetrx_w); + DECLARE_READ8_MEMBER(resetparityirq_r); + DECLARE_WRITE8_MEMBER(startdmainitrx_w); + + DECLARE_READ8_MEMBER(read); + DECLARE_WRITE8_MEMBER(write); + + virtual void scsi_ctrl_changed(); + + UINT8 dma_r(); + void dma_w(UINT8 val); + +protected: + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + +private: + enum { MODE_D, MODE_T, MODE_I }; + enum { IDLE }; + + enum { + // Bus initiated sequences + BUSINIT_SETTLE_DELAY = 1, + BUSINIT_ASSERT_BUS_SEL, + BUSINIT_MSG_OUT, + BUSINIT_RECV_BYTE, + BUSINIT_ASSERT_BUS_RESEL, + BUSINIT_WAIT_REQ, + BUSINIT_RECV_BYTE_NACK, + + // Bus SCSI Reset + BUSRESET_WAIT_INT, + BUSRESET_RESET_BOARD, + + // Disconnected state commands + DISC_SEL_ARBITRATION, + DISC_SEL_ATN_WAIT_REQ, + DISC_SEL_ATN_SEND_BYTE, + DISC_SEL_WAIT_REQ, + DISC_SEL_SEND_BYTE, + DISC_REC_ARBITRATION, + DISC_REC_MSG_IN, + DISC_REC_SEND_BYTE, + DISC_RESET, + + // Command sequence + CMDSEQ_CMD_PHASE, + CMDSEQ_RECV_BYTE, + + // Target commands + TARGET_SEND_BYTE, + TARGET_CMD_RECV_BYTE, + TARGET_MSG_RECV_BYTE, + TARGET_MSG_RECV_PAD, + TARGET_DISC_SEND_BYTE, + TARGET_DISC_MSG_IN, + TARGET_DISC_SEND_BYTE_2, + + // Initiator commands + INIT_MSG_WAIT_REQ, + INIT_XFR, + INIT_XFR_SEND_BYTE, + INIT_XFR_SEND_PAD_WAIT_REQ, + INIT_XFR_SEND_PAD, + INIT_XFR_RECV_PAD_WAIT_REQ, + INIT_XFR_RECV_PAD, + INIT_XFR_RECV_BYTE_ACK, + INIT_XFR_RECV_BYTE_NACK, + INIT_XFR_WAIT_REQ, + INIT_CPT_RECV_BYTE_ACK, + INIT_CPT_RECV_WAIT_REQ, + INIT_CPT_RECV_BYTE_NACK + }; + + enum { + // Arbitration + ARB_WAIT_BUS_FREE = 1, + ARB_COMPLETE, + ARB_ASSERT_SEL, + ARB_SET_DEST, + ARB_RELEASE_BUSY, + ARB_TIMEOUT_BUSY, + ARB_TIMEOUT_ABORT, + ARB_DESKEW_WAIT, + + // Send/receive byte + SEND_WAIT_SETTLE, + SEND_WAIT_REQ_0, + RECV_WAIT_REQ_1, + RECV_WAIT_SETTLE, + RECV_WAIT_REQ_0 + }; + + enum { + STATE_MASK = 0x00ff, + SUB_SHIFT = 8, + SUB_MASK = 0xff00 + }; + + enum { BUS_BUSY, BUS_FREE_WAIT, BUS_FREE }; + + enum { + ST_RST = 0x80, + ST_BSY = 0x40, + ST_REQ = 0x20, + ST_MSG = 0x10, + ST_CD = 0x08, + ST_IO = 0x04, + ST_SEL = 0x02, + ST_DBP = 0x01, + + BAS_ENDOFDMA = 0x80, + BAS_DMAREQUEST = 0x40, + BAS_PARITYERROR = 0x20, + BAS_IRQACTIVE = 0x10, + BAS_PHASEMATCH = 0x08, + BAS_BUSYERROR = 0x04, + BAS_ATN = 0x02, + BAS_ACK = 0x01, + + IC_RST = 0x80, + IC_ARBITRATION = 0x40, + IC_ARBLOST = 0x20, + IC_ACK = 0x10, + IC_BSY = 0x08, + IC_SEL = 0x04, + IC_ATN = 0x02, + IC_DBUS = 0x01, + IC_PHASEMASK = 0x9e, + IC_WRITEMASK = 0x9f, + + MODE_BLOCKDMA = 0x80, + MODE_TARGET = 0x40, + MODE_PARITYCHK = 0x20, + MODE_PARITYIRQ = 0x10, + MODE_EOPIRQ = 0x08, + MODE_BSYIRQ = 0x04, + MODE_DMA = 0x02, + MODE_ARBITRATE = 0x01 + }; + + enum { DMA_NONE, DMA_IN, DMA_OUT }; + + emu_timer *tm; + + UINT8 status, istatus, m_mode, m_outdata, m_busstatus, m_dmalatch; + UINT8 m_icommand, m_tcommand; + UINT8 clock_conv, sync_offset, sync_period, bus_id, select_timeout, seq; + UINT16 tcount; + int mode; + int state/*, xfr_phase*/; + + bool irq, drq; + + void drq_set(); + void drq_clear(); + + void step(bool timeout); + void function_complete(); + void function_bus_complete(); + void bus_complete(); + + void arbitrate(); + void check_irq(); + + void reset_soft(); + void reset_disconnect(); + + void send_byte(); + void recv_byte(); + + void delay(int cycles); + void delay_cycles(int cycles); + + devcb_write_line m_irq_handler; + devcb_write_line m_drq_handler; +}; + +extern const device_type NCR5380N; + +#endif diff --git a/src/devices/machine/ncr5390.c b/src/devices/machine/ncr5390.c new file mode 100644 index 00000000000..26e4218b226 --- /dev/null +++ b/src/devices/machine/ncr5390.c @@ -0,0 +1,862 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert + +#include "emu.h" +#include "ncr5390.h" + +#define DELAY_HACK + +const device_type NCR5390 = &device_creator; + +DEVICE_ADDRESS_MAP_START(map, 8, ncr5390_device) + AM_RANGE(0x0, 0x0) AM_READWRITE(tcount_lo_r, tcount_lo_w) + AM_RANGE(0x1, 0x1) AM_READWRITE(tcount_hi_r, tcount_hi_w) + AM_RANGE(0x2, 0x2) AM_READWRITE(fifo_r, fifo_w) + AM_RANGE(0x3, 0x3) AM_READWRITE(command_r, command_w) + AM_RANGE(0x4, 0x4) AM_READWRITE(status_r, bus_id_w) + AM_RANGE(0x5, 0x5) AM_READWRITE(istatus_r, timeout_w) + AM_RANGE(0x6, 0x6) AM_READWRITE(seq_step_r, sync_period_w) + AM_RANGE(0x7, 0x7) AM_READWRITE(fifo_flags_r, sync_offset_w) + AM_RANGE(0x8, 0x8) AM_READWRITE(conf_r, conf_w) + AM_RANGE(0x9, 0x9) AM_WRITE(clock_w) +ADDRESS_MAP_END + +ncr5390_device::ncr5390_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nscsi_device(mconfig, NCR5390, "5390 SCSI", tag, owner, clock, "ncr5390", __FILE__), + m_irq_handler(*this), + m_drq_handler(*this) +{ +} + +void ncr5390_device::device_start() +{ + nscsi_device::device_start(); + + save_item(NAME(command)); + save_item(NAME(config)); + save_item(NAME(status)); + save_item(NAME(istatus)); + save_item(NAME(clock_conv)); + save_item(NAME(sync_offset)); + save_item(NAME(sync_period)); + save_item(NAME(bus_id)); + save_item(NAME(select_timeout)); + save_item(NAME(seq)); + save_item(NAME(fifo)); + save_item(NAME(tcount)); + save_item(NAME(mode)); + save_item(NAME(fifo_pos)); + save_item(NAME(command_pos)); + save_item(NAME(state)); + save_item(NAME(xfr_phase)); + save_item(NAME(command_length)); + save_item(NAME(dma_dir)); + save_item(NAME(irq)); + save_item(NAME(drq)); + + m_irq_handler.resolve_safe(); + m_drq_handler.resolve_safe(); + + tcount = 0; + config = 0; + status = 0; + bus_id = 0; + select_timeout = 0; + tm = timer_alloc(0); +} + +void ncr5390_device::device_reset() +{ + fifo_pos = 0; + memset(fifo, 0, sizeof(fifo)); + + clock_conv = 2; + sync_period = 5; + sync_offset = 0; + seq = 0; + config &= 7; + status &= 0x90; + istatus = 0; + irq = false; + m_irq_handler(irq); + reset_soft(); +} + +void ncr5390_device::reset_soft() +{ + state = IDLE; + scsi_bus->ctrl_wait(scsi_refid, S_SEL|S_BSY|S_RST, S_ALL); + status &= 0xef; + drq = false; + m_drq_handler(drq); + reset_disconnect(); +} + +void ncr5390_device::reset_disconnect() +{ + command_pos = 0; + command_length = 0; + memset(command, 0, sizeof(command)); + mode = MODE_D; +} + +void ncr5390_device::scsi_ctrl_changed() +{ + UINT32 ctrl = scsi_bus->ctrl_r(); + if(ctrl & S_RST) { + logerror("%s: scsi bus reset\n", tag()); + return; + } + + step(false); +} + +void ncr5390_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + step(true); +} + +void ncr5390_device::step(bool timeout) +{ + UINT32 ctrl = scsi_bus->ctrl_r(); + UINT32 data = scsi_bus->data_r(); + UINT8 c = command[0] & 0x7f; + + if(0) + logerror("%s: state=%d.%d %s\n", + tag(), state & STATE_MASK, (state & SUB_MASK) >> SUB_SHIFT, + timeout ? "timeout" : "change"); + + if(mode == MODE_I && !(ctrl & S_BSY)) { + state = IDLE; + istatus |= I_DISCONNECT; + reset_disconnect(); + check_irq(); + } + switch(state & SUB_MASK ? state & SUB_MASK : state & STATE_MASK) { + case IDLE: + break; + + case ARB_COMPLETE << SUB_SHIFT: { + if(!timeout) + break; + + int win; + for(win=7; win>=0 && !(data & (1<data_w(scsi_refid, 0); + scsi_bus->ctrl_w(scsi_refid, 0, S_ALL); + fatalerror("need to wait for bus free\n"); + } + state = (state & STATE_MASK) | (ARB_ASSERT_SEL << SUB_SHIFT); + scsi_bus->ctrl_w(scsi_refid, S_SEL, S_SEL); + delay(6); + break; + } + + case ARB_ASSERT_SEL << SUB_SHIFT: + if(!timeout) + break; + + scsi_bus->data_w(scsi_refid, (1<ctrl_w(scsi_refid, c == CD_SELECT_ATN || c == CD_SELECT_ATN_STOP ? S_ATN : 0, S_ATN|S_BSY); + delay(2); + break; + + case ARB_RELEASE_BUSY << SUB_SHIFT: + if(!timeout) + break; + + if(ctrl & S_BSY) { + state = (state & STATE_MASK) | (ARB_DESKEW_WAIT << SUB_SHIFT); + if(c == CD_RESELECT) + scsi_bus->ctrl_w(scsi_refid, S_BSY, S_BSY); + delay_cycles(2); + } else { + state = (state & STATE_MASK) | (ARB_TIMEOUT_BUSY << SUB_SHIFT); +#ifdef DELAY_HACK + delay(1); +#else + delay(8192*select_timeout); +#endif + } + break; + + case ARB_DESKEW_WAIT << SUB_SHIFT: + if(!timeout) + break; + + scsi_bus->data_w(scsi_refid, 0); + scsi_bus->ctrl_w(scsi_refid, 0, S_SEL); + + if(c == CD_RESELECT) { + logerror("%s: mode switch to Target\n", tag()); + mode = MODE_T; + } else { + logerror("%s: mode switch to Initiator\n", tag()); + mode = MODE_I; + } + state &= STATE_MASK; + step(true); + break; + + case ARB_TIMEOUT_BUSY << SUB_SHIFT: + if(timeout) { + scsi_bus->data_w(scsi_refid, 0); + logerror("%s: select timeout\n", tag()); + state = (state & STATE_MASK) | (ARB_TIMEOUT_ABORT << SUB_SHIFT); + delay(1000); + } else if(ctrl & S_BSY) { + state = (state & STATE_MASK) | (ARB_DESKEW_WAIT << SUB_SHIFT); + if(c == CD_RESELECT) + scsi_bus->ctrl_w(scsi_refid, S_BSY, S_BSY); + delay_cycles(2); + } + break; + + case ARB_TIMEOUT_ABORT << SUB_SHIFT: + if(!timeout) + break; + + if(ctrl & S_BSY) { + state = (state & STATE_MASK) | (ARB_DESKEW_WAIT << SUB_SHIFT); + if(c == CD_RESELECT) + scsi_bus->ctrl_w(scsi_refid, S_BSY, S_BSY); + delay_cycles(2); + } else { + scsi_bus->ctrl_w(scsi_refid, 0, S_ALL); + state = IDLE; + istatus |= I_DISCONNECT; + reset_disconnect(); + check_irq(); + } + break; + + case SEND_WAIT_SETTLE << SUB_SHIFT: + if(!timeout) + break; + + state = (state & STATE_MASK) | (SEND_WAIT_REQ_0 << SUB_SHIFT); + step(false); + break; + + case SEND_WAIT_REQ_0 << SUB_SHIFT: + if(ctrl & S_REQ) + break; + state = state & STATE_MASK; + scsi_bus->data_w(scsi_refid, 0); + scsi_bus->ctrl_w(scsi_refid, 0, S_ACK); + step(false); + break; + + case RECV_WAIT_REQ_1 << SUB_SHIFT: + if(!(ctrl & S_REQ)) + break; + + state = (state & STATE_MASK) | (RECV_WAIT_SETTLE << SUB_SHIFT); + delay_cycles(sync_period); + break; + + case RECV_WAIT_SETTLE << SUB_SHIFT: + if(!timeout) + break; + + if((state & STATE_MASK) != INIT_XFR_RECV_PAD) + fifo_push(scsi_bus->data_r()); + scsi_bus->ctrl_w(scsi_refid, S_ACK, S_ACK); + state = (state & STATE_MASK) | (RECV_WAIT_REQ_0 << SUB_SHIFT); + step(false); + break; + + case RECV_WAIT_REQ_0 << SUB_SHIFT: + if(ctrl & S_REQ) + break; + state = state & STATE_MASK; + step(false); + break; + + case DISC_SEL_ARBITRATION: + if(c == CD_SELECT) { + state = DISC_SEL_WAIT_REQ; + command_length = derive_msg_size(fifo[0]); + } else + state = DISC_SEL_ATN_WAIT_REQ; + + scsi_bus->ctrl_wait(scsi_refid, S_REQ, S_REQ); + if(ctrl & S_REQ) + step(false); + break; + + case DISC_SEL_ATN_WAIT_REQ: + if(!(ctrl & S_REQ)) + break; + if((ctrl & S_PHASE_MASK) != S_PHASE_MSG_OUT) { + function_complete(); + break; + } + if(c == CD_SELECT_ATN) + scsi_bus->ctrl_w(scsi_refid, 0, S_ATN); + state = DISC_SEL_ATN_SEND_BYTE; + send_byte(); + break; + + case DISC_SEL_ATN_SEND_BYTE: + if(c == CD_SELECT_ATN_STOP) { + seq = 1; + function_complete(); + } else { + command_length = derive_msg_size(fifo[0]); + state = DISC_SEL_WAIT_REQ; + } + break; + + case DISC_SEL_WAIT_REQ: + if(!(ctrl & S_REQ)) + break; + if((ctrl & S_PHASE_MASK) != S_PHASE_COMMAND) { + if(!command_length) + seq = 4; + scsi_bus->ctrl_wait(scsi_refid, 0, S_REQ); + function_bus_complete(); + break; + } + if(seq < 3) + seq = 3; + state = DISC_SEL_SEND_BYTE; + send_byte(); + break; + + case DISC_SEL_SEND_BYTE: + if(command_length) { + command_length--; + if(!command_length) + seq = 4; + } + + state = DISC_SEL_WAIT_REQ; + break; + + case INIT_CPT_RECV_BYTE_ACK: + state = INIT_CPT_RECV_WAIT_REQ; + scsi_bus->ctrl_w(scsi_refid, 0, S_ACK); + break; + + case INIT_CPT_RECV_WAIT_REQ: + if(!(ctrl & S_REQ)) + break; + + if((ctrl & S_PHASE_MASK) != S_PHASE_MSG_IN) { + command_pos = 0; + bus_complete(); + } else { + state = INIT_CPT_RECV_BYTE_NACK; + recv_byte(); + } + break; + + case INIT_CPT_RECV_BYTE_NACK: + scsi_bus->ctrl_wait(scsi_refid, 0, S_REQ); + function_complete(); + break; + + case INIT_MSG_WAIT_REQ: + if((ctrl & (S_REQ|S_BSY)) == S_BSY) + break; + bus_complete(); + break; + + case INIT_XFR: + switch(xfr_phase) { + case S_PHASE_DATA_OUT: + dma_set(DMA_OUT); + if(tcount == 0 && fifo_pos == 1) + scsi_bus->ctrl_w(scsi_refid, 0, S_ATN); + state = INIT_XFR_SEND_BYTE; + send_byte(); + break; + + case S_PHASE_DATA_IN: + dma_set(DMA_IN); + state = tcount == fifo_pos+1 ? + INIT_XFR_RECV_BYTE_NACK : INIT_XFR_RECV_BYTE_ACK; + recv_byte(); + break; + + default: + logerror("%s: xfer on phase %d\n", tag(), scsi_bus->ctrl_r() & S_PHASE_MASK); + function_complete(); + break; + } + break; + + case INIT_XFR_WAIT_REQ: + if(!(ctrl & S_REQ)) + break; + + if((ctrl & S_PHASE_MASK) != xfr_phase) { + command_pos = 0; + bus_complete(); + } else { + state = INIT_XFR; + step(false); + } + break; + + case INIT_XFR_SEND_BYTE: + if(tcount == 0 && fifo_pos == 0) + bus_complete(); + else + state = INIT_XFR_WAIT_REQ; + break; + + case INIT_XFR_RECV_BYTE_ACK: + state = INIT_XFR_WAIT_REQ; + scsi_bus->ctrl_w(scsi_refid, 0, S_ACK); + break; + + case INIT_XFR_RECV_BYTE_NACK: + function_complete(); + break; + + case INIT_XFR_SEND_PAD_WAIT_REQ: + if(!(ctrl & S_REQ)) + break; + + if((ctrl & S_PHASE_MASK) != xfr_phase) { + command_pos = 0; + bus_complete(); + } else { + state = INIT_XFR_SEND_PAD; + send_byte(); + } + break; + + case INIT_XFR_SEND_PAD: + tcount--; + if(tcount) { + state = INIT_XFR_SEND_PAD_WAIT_REQ; + step(false); + } else + function_complete(); + break; + + case INIT_XFR_RECV_PAD_WAIT_REQ: + if(!(ctrl & S_REQ)) + break; + + if((ctrl & S_PHASE_MASK) != xfr_phase) { + command_pos = 0; + bus_complete(); + } else { + state = INIT_XFR_RECV_PAD; + recv_byte(); + } + break; + + case INIT_XFR_RECV_PAD: + tcount--; + if(tcount) { + state = INIT_XFR_RECV_PAD_WAIT_REQ; + scsi_bus->ctrl_w(scsi_refid, 0, S_ACK); + step(false); + } else + function_complete(); + break; + + default: + logerror("%s: step() unexpected state %d.%d\n", + tag(), + state & STATE_MASK, (state & SUB_MASK) >> SUB_SHIFT); + exit(0); + } +} + +void ncr5390_device::send_byte() +{ + if(!fifo_pos) + fatalerror("ncr5390_device::send_byte - !fifo_pos\n"); + + state = (state & STATE_MASK) | (SEND_WAIT_SETTLE << SUB_SHIFT); + if((state & STATE_MASK) != INIT_XFR_SEND_PAD && + ((state & STATE_MASK) != DISC_SEL_SEND_BYTE || + command_length)) + scsi_bus->data_w(scsi_refid, fifo_pop()); + else + scsi_bus->data_w(scsi_refid, 0); + + scsi_bus->ctrl_w(scsi_refid, S_ACK, S_ACK); + scsi_bus->ctrl_wait(scsi_refid, S_REQ, S_REQ); + delay_cycles(sync_period); +} + +void ncr5390_device::recv_byte() +{ + scsi_bus->ctrl_wait(scsi_refid, S_REQ, S_REQ); + state = (state & STATE_MASK) | (RECV_WAIT_REQ_1 << SUB_SHIFT); + step(false); +} + +void ncr5390_device::function_bus_complete() +{ + state = IDLE; + istatus |= I_FUNCTION|I_BUS; + dma_set(DMA_NONE); + check_irq(); +} + +void ncr5390_device::function_complete() +{ + state = IDLE; + istatus |= I_FUNCTION; + dma_set(DMA_NONE); + check_irq(); +} + +void ncr5390_device::bus_complete() +{ + state = IDLE; + istatus |= I_BUS; + dma_set(DMA_NONE); + check_irq(); +} + +void ncr5390_device::delay(int cycles) +{ + if(!clock_conv) + return; + cycles *= clock_conv; + tm->adjust(clocks_to_attotime(cycles)); +} + +void ncr5390_device::delay_cycles(int cycles) +{ + tm->adjust(clocks_to_attotime(cycles)); +} + +READ8_MEMBER(ncr5390_device::tcount_lo_r) +{ + logerror("%s: tcount_lo_r %02x (%08x)\n", tag(), tcount & 0xff, space.device().safe_pc()); + return tcount; +} + +WRITE8_MEMBER(ncr5390_device::tcount_lo_w) +{ + tcount = (tcount & 0xff00) | data; + status &= ~S_TC0; + logerror("%s: tcount_lo_w %02x (%08x)\n", tag(), data, space.device().safe_pc()); +} + +READ8_MEMBER(ncr5390_device::tcount_hi_r) +{ + logerror("%s: tcount_hi_r %02x (%08x)\n", tag(), tcount >> 8, space.device().safe_pc()); + return tcount >> 8; +} + +WRITE8_MEMBER(ncr5390_device::tcount_hi_w) +{ + tcount = (tcount & 0x00ff) | (data << 8); + status &= ~S_TC0; + logerror("%s: tcount_hi_w %02x (%08x)\n", tag(), data, space.device().safe_pc()); +} + +UINT8 ncr5390_device::fifo_pop() +{ + UINT8 r = fifo[0]; + fifo_pos--; + memmove(fifo, fifo+1, fifo_pos); + if((!fifo_pos) && tcount && dma_dir == DMA_OUT) + drq_set(); + return r; +} + +void ncr5390_device::fifo_push(UINT8 val) +{ + fifo[fifo_pos++] = val; + if(!drq && dma_dir == DMA_IN) + drq_set(); +} + +READ8_MEMBER(ncr5390_device::fifo_r) +{ + UINT8 r; + if(fifo_pos) { + r = fifo[0]; + fifo_pos--; + memmove(fifo, fifo+1, fifo_pos); + } else + r = 0; + return r; +} + +WRITE8_MEMBER(ncr5390_device::fifo_w) +{ + if(fifo_pos != 16) + fifo[fifo_pos++] = data; +} + +READ8_MEMBER(ncr5390_device::command_r) +{ + logerror("%s: command_r (%08x)\n", tag(), space.device().safe_pc()); + return command[0]; +} + +WRITE8_MEMBER(ncr5390_device::command_w) +{ + // logerror("%s: command_w %02x (%08x)\n", tag(), data, space.device().safe_pc()); + if(command_pos == 2) { + status |= S_GROSS_ERROR; + check_irq(); + return; + } + command[command_pos++] = data; + if(command_pos == 1) + start_command(); +} + +void ncr5390_device::command_pop_and_chain() +{ + if(command_pos) { + command_pos--; + if(command_pos) { + command[0] = command[1]; + start_command(); + } + } +} + +void ncr5390_device::start_command() +{ + UINT8 c = command[0] & 0x7f; + if(!check_valid_command(c)) { + logerror("%s: invalid command %02x\n", tag(), command[0]); + istatus |= I_ILLEGAL; + check_irq(); + return; + } + + switch(c) { + case CM_NOP: + command_pop_and_chain(); + break; + + case CM_FLUSH_FIFO: + fifo_pos = 0; + command_pop_and_chain(); + break; + + case CM_RESET: + device_reset(); + break; + + case CM_RESET_BUS: + reset_soft(); + break; + + case CD_RESELECT: + state = DISC_REC_ARBITRATION; + arbitrate(); + break; + + case CD_SELECT: + case CD_SELECT_ATN: + case CD_SELECT_ATN_STOP: + seq = 0; + state = DISC_SEL_ARBITRATION; + arbitrate(); + break; + + case CD_ENABLE_SEL: + command_pop_and_chain(); + break; + + case CI_XFER: + state = INIT_XFR; + xfr_phase = scsi_bus->ctrl_r() & S_PHASE_MASK; + step(false); + break; + + case CI_COMPLETE: + state = INIT_CPT_RECV_BYTE_ACK; + recv_byte(); + break; + + case CI_MSG_ACCEPT: + state = INIT_MSG_WAIT_REQ; + scsi_bus->ctrl_w(scsi_refid, 0, S_ACK); + step(false); + break; + + case CI_PAD: + xfr_phase = scsi_bus->ctrl_r() & S_PHASE_MASK; + if(xfr_phase & S_INP) + state = INIT_XFR_RECV_PAD_WAIT_REQ; + else + state = INIT_XFR_SEND_PAD_WAIT_REQ; + scsi_bus->ctrl_w(scsi_refid, 0, S_ACK); + step(false); + break; + + default: + logerror("%s: start unimplemented command %02x\n", tag(), c); + exit(0); + } +} + +bool ncr5390_device::check_valid_command(UINT8 cmd) +{ + int subcmd = cmd & 15; + switch((cmd >> 4) & 7) { + case 0: return subcmd <= 3; + case 4: return mode == MODE_D && subcmd <= 5; + case 2: return mode == MODE_T && subcmd <= 13 && subcmd != 6; + case 1: return mode == MODE_I && (subcmd <= 2 || subcmd == 8 || subcmd == 10); + } + return false; +} + +int ncr5390_device::derive_msg_size(UINT8 msg_id) +{ + const static int sizes[8] = { 6, 10, 6, 6, 6, 12, 6, 10 }; + return sizes[msg_id >> 5]; +} + +void ncr5390_device::arbitrate() +{ + state = (state & STATE_MASK) | (ARB_COMPLETE << SUB_SHIFT); + scsi_bus->data_w(scsi_refid, 1 << scsi_id); + scsi_bus->ctrl_w(scsi_refid, S_BSY, S_BSY); + delay(11); +} + +void ncr5390_device::check_irq() +{ + bool oldirq = irq; + irq = istatus != 0; + if(irq != oldirq) + m_irq_handler(irq); + +} + +READ8_MEMBER(ncr5390_device::status_r) +{ + UINT32 ctrl = scsi_bus->ctrl_r(); + UINT8 res = status | (ctrl & S_MSG ? 4 : 0) | (ctrl & S_CTL ? 2 : 0) | (ctrl & S_INP ? 1 : 0); + logerror("%s: status_r %02x (%08x)\n", tag(), res, space.device().safe_pc()); + if(irq) + status &= ~(S_GROSS_ERROR|S_PARITY|S_TCC); + return res; +} + +WRITE8_MEMBER(ncr5390_device::bus_id_w) +{ + bus_id = data & 7; + logerror("%s: bus_id=%d\n", tag(), bus_id); +} + +READ8_MEMBER(ncr5390_device::istatus_r) +{ + UINT8 res = istatus; + istatus = 0; + seq = 0; + check_irq(); + if(res) + command_pop_and_chain(); + + logerror("%s: istatus_r %02x (%08x)\n", tag(), res, space.device().safe_pc()); + return res; +} + +WRITE8_MEMBER(ncr5390_device::timeout_w) +{ + select_timeout = data; +} + +READ8_MEMBER(ncr5390_device::seq_step_r) +{ + logerror("%s: seq_step_r %d (%08x)\n", tag(), seq, space.device().safe_pc()); + return seq; +} + +WRITE8_MEMBER(ncr5390_device::sync_period_w) +{ + sync_period = data & 0x1f; +} + +READ8_MEMBER(ncr5390_device::fifo_flags_r) +{ + return fifo_pos; +} + +WRITE8_MEMBER(ncr5390_device::sync_offset_w) +{ + sync_offset = data & 0x0f; +} + +READ8_MEMBER(ncr5390_device::conf_r) +{ + return config; +} + +WRITE8_MEMBER(ncr5390_device::conf_w) +{ + config = data; + scsi_id = data & 7; +} + +WRITE8_MEMBER(ncr5390_device::clock_w) +{ + clock_conv = data & 0x07; +} + +void ncr5390_device::dma_set(int dir) +{ + dma_dir = dir; + if(dma_dir == DMA_OUT && fifo_pos != 16 && tcount != 0) + drq_set(); +} + +void ncr5390_device::dma_w(UINT8 val) +{ + fifo_push(val); + tcount--; + if(fifo_pos == 16 || tcount == 0) + drq_clear(); +} + +UINT8 ncr5390_device::dma_r() +{ + UINT8 r = fifo_pop(); + if(!fifo_pos) + drq_clear(); + tcount--; + if(tcount == 0) { + status |= S_TC0; + step(false); + } + return r; +} + +void ncr5390_device::drq_set() +{ + if(!drq) { + drq = true; + m_drq_handler(drq); + } +} + +void ncr5390_device::drq_clear() +{ + if(drq) { + drq = false; + m_drq_handler(drq); + } +} diff --git a/src/devices/machine/ncr5390.h b/src/devices/machine/ncr5390.h new file mode 100644 index 00000000000..93cf76a5486 --- /dev/null +++ b/src/devices/machine/ncr5390.h @@ -0,0 +1,232 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +#ifndef NCR5390_H +#define NCR5390_H + +#include "machine/nscsi_bus.h" + +#define MCFG_NCR5390_IRQ_HANDLER(_devcb) \ + devcb = &ncr5390_device::set_irq_handler(*device, DEVCB_##_devcb); + +#define MCFG_NCR5390_DRQ_HANDLER(_devcb) \ + devcb = &ncr5390_device::set_drq_handler(*device, DEVCB_##_devcb); + +class ncr5390_device : public nscsi_device +{ +public: + ncr5390_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // static configuration helpers + template static devcb_base &set_irq_handler(device_t &device, _Object object) { return downcast(device).m_irq_handler.set_callback(object); } + template static devcb_base &set_drq_handler(device_t &device, _Object object) { return downcast(device).m_drq_handler.set_callback(object); } + + DECLARE_ADDRESS_MAP(map, 8); + + DECLARE_READ8_MEMBER(tcount_lo_r); + DECLARE_WRITE8_MEMBER(tcount_lo_w); + DECLARE_READ8_MEMBER(tcount_hi_r); + DECLARE_WRITE8_MEMBER(tcount_hi_w); + DECLARE_READ8_MEMBER(fifo_r); + DECLARE_WRITE8_MEMBER(fifo_w); + DECLARE_READ8_MEMBER(command_r); + DECLARE_WRITE8_MEMBER(command_w); + DECLARE_READ8_MEMBER(status_r); + DECLARE_WRITE8_MEMBER(bus_id_w); + DECLARE_READ8_MEMBER(istatus_r); + DECLARE_WRITE8_MEMBER(timeout_w); + DECLARE_READ8_MEMBER(seq_step_r); + DECLARE_WRITE8_MEMBER(sync_period_w); + DECLARE_READ8_MEMBER(fifo_flags_r); + DECLARE_WRITE8_MEMBER(sync_offset_w); + DECLARE_READ8_MEMBER(conf_r); + DECLARE_WRITE8_MEMBER(conf_w); + DECLARE_WRITE8_MEMBER(clock_w); + + virtual void scsi_ctrl_changed(); + + UINT8 dma_r(); + void dma_w(UINT8 val); + +protected: + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + +private: + enum { MODE_D, MODE_T, MODE_I }; + enum { IDLE }; + + enum { + // Bus initiated sequences + BUSINIT_SETTLE_DELAY = 1, + BUSINIT_ASSERT_BUS_SEL, + BUSINIT_MSG_OUT, + BUSINIT_RECV_BYTE, + BUSINIT_ASSERT_BUS_RESEL, + BUSINIT_WAIT_REQ, + BUSINIT_RECV_BYTE_NACK, + + // Bus SCSI Reset + BUSRESET_WAIT_INT, + BUSRESET_RESET_BOARD, + + // Disconnected state commands + DISC_SEL_ARBITRATION, + DISC_SEL_ATN_WAIT_REQ, + DISC_SEL_ATN_SEND_BYTE, + DISC_SEL_WAIT_REQ, + DISC_SEL_SEND_BYTE, + DISC_REC_ARBITRATION, + DISC_REC_MSG_IN, + DISC_REC_SEND_BYTE, + DISC_RESET, + + // Command sequence + CMDSEQ_CMD_PHASE, + CMDSEQ_RECV_BYTE, + + // Target commands + TARGET_SEND_BYTE, + TARGET_CMD_RECV_BYTE, + TARGET_MSG_RECV_BYTE, + TARGET_MSG_RECV_PAD, + TARGET_DISC_SEND_BYTE, + TARGET_DISC_MSG_IN, + TARGET_DISC_SEND_BYTE_2, + + // Initiator commands + INIT_MSG_WAIT_REQ, + INIT_XFR, + INIT_XFR_SEND_BYTE, + INIT_XFR_SEND_PAD_WAIT_REQ, + INIT_XFR_SEND_PAD, + INIT_XFR_RECV_PAD_WAIT_REQ, + INIT_XFR_RECV_PAD, + INIT_XFR_RECV_BYTE_ACK, + INIT_XFR_RECV_BYTE_NACK, + INIT_XFR_WAIT_REQ, + INIT_CPT_RECV_BYTE_ACK, + INIT_CPT_RECV_WAIT_REQ, + INIT_CPT_RECV_BYTE_NACK + }; + + enum { + // Arbitration + ARB_WAIT_BUS_FREE = 1, + ARB_COMPLETE, + ARB_ASSERT_SEL, + ARB_SET_DEST, + ARB_RELEASE_BUSY, + ARB_TIMEOUT_BUSY, + ARB_TIMEOUT_ABORT, + ARB_DESKEW_WAIT, + + // Send/receive byte + SEND_WAIT_SETTLE, + SEND_WAIT_REQ_0, + RECV_WAIT_REQ_1, + RECV_WAIT_SETTLE, + RECV_WAIT_REQ_0 + }; + + enum { + STATE_MASK = 0x00ff, + SUB_SHIFT = 8, + SUB_MASK = 0xff00 + }; + + enum { BUS_BUSY, BUS_FREE_WAIT, BUS_FREE }; + + enum { + S_GROSS_ERROR = 0x40, + S_PARITY = 0x20, + S_TC0 = 0x10, + S_TCC = 0x08, + + I_SCSI_RESET = 0x80, + I_ILLEGAL = 0x40, + I_DISCONNECT = 0x20, + I_BUS = 0x10, + I_FUNCTION = 0x08, + I_RESELECTED = 0x04, + I_SELECT_ATN = 0x02, + I_SELECTED = 0x01, + + CM_NOP = 0x00, + CM_FLUSH_FIFO = 0x01, + CM_RESET = 0x02, + CM_RESET_BUS = 0x03, + CD_RESELECT = 0x40, + CD_SELECT = 0x41, + CD_SELECT_ATN = 0x42, + CD_SELECT_ATN_STOP = 0x43, + CD_ENABLE_SEL = 0x44, + CD_DISABLE_SEL = 0x45, + CT_SEND_MSG = 0x20, + CT_SEND_STATUS = 0x21, + CT_SEND_DATA = 0x22, + CT_DISCONNECT_SEQ = 0x23, + CT_TERMINATE = 0x24, + CT_COMPLETE = 0x25, + CT_DISCONNECT = 0x27, + CT_RECV_MSG = 0x28, + CT_RECV_CMD = 0x29, + CT_RECV_DATA = 0x2a, + CT_RECV_CMD_SEQ = 0x2b, + CI_XFER = 0x10, + CI_COMPLETE = 0x11, + CI_MSG_ACCEPT = 0x12, + CI_PAD = 0x18, + CI_SET_ATN = 0x1a + }; + + enum { DMA_NONE, DMA_IN, DMA_OUT }; + + emu_timer *tm; + + UINT8 command[2], config, status, istatus; + UINT8 clock_conv, sync_offset, sync_period, bus_id, select_timeout, seq; + UINT8 fifo[16]; + UINT16 tcount; + int mode, fifo_pos, command_pos; + int state, xfr_phase; + int command_length; + + int dma_dir; + + bool irq, drq; + + void dma_set(int dir); + void drq_set(); + void drq_clear(); + + void start_command(); + void step(bool timeout); + bool check_valid_command(UINT8 cmd); + int derive_msg_size(UINT8 msg_id); + void function_complete(); + void function_bus_complete(); + void bus_complete(); + + void arbitrate(); + void command_pop_and_chain(); + void check_irq(); + + void reset_soft(); + void reset_disconnect(); + + UINT8 fifo_pop(); + void fifo_push(UINT8 val); + void send_byte(); + void recv_byte(); + + void delay(int cycles); + void delay_cycles(int cycles); + + devcb_write_line m_irq_handler; + devcb_write_line m_drq_handler; +}; + +extern const device_type NCR5390; + +#endif diff --git a/src/devices/machine/ncr539x.c b/src/devices/machine/ncr539x.c new file mode 100644 index 00000000000..fe1fd9919e1 --- /dev/null +++ b/src/devices/machine/ncr539x.c @@ -0,0 +1,831 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/* + * ncr539x.c + * + * NCR 53(CF)94/53(CF)96 SCSI controller + * Includes enhanced features of the AMD 53CF94/96 and compatibles + * + * All new emulation in 2011 by R. Belmont. + * + */ + +#include "emu.h" +#include "ncr539x.h" + +#define VERBOSE (0) +#define VERBOSE_READS (0) + +enum +{ + TIMER_539X_COMMAND, + + TIMER_539X_END +}; + +#define MAIN_STATUS_INTERRUPT 0x80 +#define MAIN_STATUS_ILLEGAL_OPER 0x40 +#define MAIN_STATUS_PARITY_ERROR 0x20 +#define MAIN_STATUS_COUNT_TO_ZERO 0x10 +#define MAIN_STATUS_GROUP_VALID 0x08 +#define MAIN_STATUS_MESSAGE 0x04 +#define MAIN_STATUS_CMD_DATA 0x02 +#define MAIN_STATUS_IO 0x01 + +#define IRQ_STATUS_RESET 0x80 +#define IRQ_STATUS_INVALID_COMMAND 0x40 +#define IRQ_STATUS_DISCONNECTED 0x20 +#define IRQ_STATUS_SERVICE_REQUEST 0x10 +#define IRQ_STATUS_SUCCESS 0x08 +#define IRQ_STATUS_RESELECTED 0x04 // we were reselected as a target +#define IRQ_STATUS_SELECTED_WITH_ATN 0x02 // we were selected as a target with ATN steps +#define IRQ_STATUS_SELECTED 0x01 // we were selected as a target + +#define CR2_ALIGN_ENABLE 0x80 +#define CR2_FEATURES_ENABLE 0x40 +#define CR2_BYTE_ORDER 0x20 +#define CR2_TRISTATE_DMA 0x10 +#define CR2_SCSI2_ENABLE 0x08 +#define CR2_ABORT_ON_PARITY_ERROR 0x04 +#define CR2_GENERATE_REGISTER_PARITY 0x02 +#define CR2_GENERATE_DATA_PARITY 0x01 + +#if VERBOSE +#if VERBOSE_READS +static const char *rdregs[16] = { + "Transfer count LSB", // 0 + "Transfer count MSB", // 1 + "FIFO", // 2 + "Command", // 3 + "Status", // 4 + "Interrupt Status", // 5 + "Internal State", // 6 + "Current FIFO/Internal State", // 7 + "Control Register 1", // 8 + "0x9", + "0xA", + "Control Register 2", + "Control Register 3", + "Control Register 4", + "Transfer count HSB/Chip ID", + "0xF" +}; +#endif + +static const char *wrregs[16] = { + "Start Transfer count LSB", + "Start Transfer count MSB", + "FIFO", + "Command", + "SCSI Destination ID", + "SCSI Timeout", + "Synchronous Transfer Period", + "Synchronous Offset", + "Control Register 1", + "Clock Factor", + "Forced Test Mode", + "Control Register 2", + "Control Register 3", + "Control Register 4", + "Start Transfer count HSB", + "Data Alignment" +}; +#endif + +// get the length of a SCSI command based on its command byte type +static int get_cmd_len(int cbyte) +{ + int group; + + group = (cbyte>>5) & 7; + + if (group == 0) return 6; + if (group == 1 || group == 2) return 10; + if (group == 5) return 12; + + return 6; +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +const device_type NCR539X = &device_creator; + +//------------------------------------------------- +// ncr539x_device - constructor/destructor +//------------------------------------------------- + +ncr539x_device::ncr539x_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + legacy_scsi_host_adapter(mconfig, NCR539X, "539x SCSI", tag, owner, clock, "ncr539x", __FILE__), + m_out_irq_cb(*this), + m_out_drq_cb(*this) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void ncr539x_device::device_start() +{ + legacy_scsi_host_adapter::device_start(); + + // resolve line callbacks + m_out_irq_cb.resolve_safe(); + m_out_drq_cb.resolve_safe(); + + m_operation_timer = timer_alloc(0, NULL); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void ncr539x_device::device_reset() +{ + m_fifo_ptr = 0; + m_fifo_read_ptr = 0; + m_irq_status = 0; + m_status = SCSI_PHASE_STATUS; + m_internal_state = 0; + m_buffer_offset = 512; + m_buffer_remaining = 0; + m_dma_size = 0; + m_xfer_count = 0; + m_total_data = 0; + m_selected = false; + m_control1 = m_control2 = m_control3 = m_control4 = 0; + m_chipid_available = false; + m_chipid_lock = false; + + m_out_irq_cb(CLEAR_LINE); + m_out_drq_cb(CLEAR_LINE); +} + +void ncr539x_device::dma_read_data(int bytes, UINT8 *pData) +{ + read_data(pData, bytes); +} + + +void ncr539x_device::dma_write_data(int bytes, UINT8 *pData) +{ + write_data(pData, bytes); +} + +void ncr539x_device::device_timer(emu_timer &timer, device_timer_id tid, int param, void *ptr) +{ + //printf("539X: device_timer expired, param = %d, m_command = %02x\n", param, m_command); + + switch (param) + { + case TIMER_539X_COMMAND: + // if this is a DMA command, raise DRQ now + if (m_command & 0x80) + { + m_out_drq_cb(ASSERT_LINE); + } + + switch (m_command & 0x7f) + { + case 0x41: // select without ATN steps + if (select(m_last_id)) + { + m_irq_status |= IRQ_STATUS_SERVICE_REQUEST | IRQ_STATUS_SUCCESS; + // we should now be in the command phase + m_status &= ~7; // clear bus phases + m_status |= MAIN_STATUS_INTERRUPT | SCSI_PHASE_COMMAND; + m_fifo_ptr = 0; + m_selected = true; + + #if VERBOSE + printf("Selecting w/o ATN, irq_status = %02x, status = %02x!\n", m_irq_status, m_status); + #endif + + // if DMA is not enabled, there should already be a command loaded into the FIFO + if (!(m_command & 0x80)) + { + exec_fifo(); + } + update_fifo_internal_state(0); + } + else + { + #if VERBOSE + printf("Select failed, no device @ ID %d!\n", m_last_id); + #endif + m_status |= MAIN_STATUS_INTERRUPT; + m_irq_status |= IRQ_STATUS_DISCONNECTED; + } + m_out_irq_cb(ASSERT_LINE); + break; + + case 0x42: // Select with ATN steps + if (select(m_last_id)) + { + m_irq_status |= IRQ_STATUS_SERVICE_REQUEST | IRQ_STATUS_SUCCESS; + // we should now be in the command phase + m_status &= ~7; // clear bus phases + m_status |= MAIN_STATUS_INTERRUPT | SCSI_PHASE_COMMAND; + m_fifo_ptr = 0; + m_selected = true; + #if VERBOSE + printf("Selecting with ATN, irq_status = %02x, status = %02x!\n", m_irq_status, m_status); + #endif + + // if DMA is not enabled, there should already be a command loaded into the FIFO + if (!(m_command & 0x80)) + { + exec_fifo(); + } + update_fifo_internal_state(0); + } + else + { + #if VERBOSE + printf("Select failed, no device @ ID %d!\n", m_last_id); + #endif + m_status |= MAIN_STATUS_INTERRUPT; + m_irq_status |= IRQ_STATUS_DISCONNECTED; + } + m_out_irq_cb(ASSERT_LINE); + break; + + case 0x11: // initiator command complete + #if VERBOSE + printf("Initiator command complete\n"); + #endif + m_irq_status = IRQ_STATUS_SERVICE_REQUEST; + m_status &= ~7; // clear phase bits + m_status |= MAIN_STATUS_INTERRUPT | SCSI_PHASE_DATAIN; // go to data in phase (?) + m_out_irq_cb(ASSERT_LINE); + + // this puts status and message bytes into the FIFO (todo: what are these?) + m_fifo_ptr = 0; + m_xfer_count = 2; + m_buffer_remaining = m_total_data = 0; + m_fifo[0] = 0; // status byte + m_fifo[1] = 0; // message byte + m_selected = false; + update_fifo_internal_state(2); + break; + + case 0x12: // message accepted + #if VERBOSE + printf("Message accepted\n"); + #endif + m_irq_status = IRQ_STATUS_SERVICE_REQUEST; + m_status |= MAIN_STATUS_INTERRUPT; + m_out_irq_cb(ASSERT_LINE); + break; + + default: + fatalerror("539x: Unhandled command %02x\n", m_command); + } + break; + + default: + break; + } +} + +READ8_MEMBER( ncr539x_device::read ) +{ + UINT8 rv = 0; + + #if VERBOSE + #if VERBOSE_READS + printf("539x: Read @ %s (%02x) (PC=%x) (status %02x irq_status %02x)\n", rdregs[offset], offset, space.device().safe_pc(), m_status, m_irq_status); + #endif + #endif + + switch (offset) + { + case 0: + rv = m_xfer_count & 0xff; + break; + + case 1: + rv = (m_xfer_count>>8) & 0xff; + break; + + case 2: // FIFO + { + UINT8 fifo_bytes = m_fifo_internal_state & 0x1f; + + if (!fifo_bytes) + { + rv = 0; + } + else + { + rv = m_fifo[m_fifo_read_ptr++]; + m_fifo_read_ptr &= (m_fifo_size-1); + + fifo_bytes--; + m_xfer_count--; + update_fifo_internal_state(fifo_bytes); + + #if VERBOSE + printf("Read %02x from FIFO[%d], FIFO now contains %d bytes (PC=%x, m_buffer_remaining %x)\n", rv, m_fifo_read_ptr-1, fifo_bytes, space.device().safe_pc(), m_buffer_remaining); + #endif + + if (fifo_bytes == 0) + { + // the last transfer command has more data for us + if (m_xfer_count > 0) + { + int fifo_fill_size = m_fifo_size; + if (m_xfer_count < fifo_fill_size) + { + fifo_fill_size = m_xfer_count; + } + assert(m_buffer_offset < m_buffer_size); + assert((m_buffer_offset + fifo_fill_size) <= m_buffer_size); + memcpy(m_fifo, &m_buffer[m_buffer_offset], fifo_fill_size); + m_buffer_offset += fifo_fill_size; + m_buffer_remaining -= fifo_fill_size; + m_fifo_ptr = 0; + update_fifo_internal_state(fifo_fill_size); + #if VERBOSE + printf("Refreshing FIFO (%x remaining from transfer, %x in buffer, %x in total)\n", m_xfer_count, m_buffer_remaining, m_total_data); + #endif + } + else + { + #if VERBOSE + printf("FIFO empty, asserting service request (buffer_remaining %x)\n", m_buffer_remaining); + #endif + m_irq_status = IRQ_STATUS_SERVICE_REQUEST; + m_status &= 0x7; // clear everything but the phase bits + m_status |= MAIN_STATUS_INTERRUPT | MAIN_STATUS_COUNT_TO_ZERO; + m_out_irq_cb(ASSERT_LINE); + + // if no data at all, drop the phase + if ((m_buffer_remaining + m_total_data) == 0) + { + #if VERBOSE + printf("Out of data, setting phase STATUS\n"); + #endif + m_status &= ~0x7; + m_status |= SCSI_PHASE_STATUS; + } + } + } + } + } + break; + + case 3: + rv = m_command; + break; + + case 4: + rv = m_status; + break; + + case 5: + rv = m_irq_status; + // clear the interrupt state + m_status &= ~MAIN_STATUS_INTERRUPT; + m_out_irq_cb(CLEAR_LINE); + break; + + case 6: + rv = m_internal_state; + break; + + case 7: + rv = m_fifo_internal_state; + break; + + case 8: + rv = m_control1; + break; + + case 0xb: + rv = m_control2; + break; + + case 0xc: + rv = m_control3; + break; + + case 0xd: + rv = m_control4; + break; + + case 0xe: + if (m_control2 & CR2_FEATURES_ENABLE) + { + if (m_chipid_available) + { + rv = 0xa2; // 0x12 for CF94, 0xa2 for CF96 + } + else + { + rv = (m_xfer_count>>16) & 0xff; + } + } + break; + + } + return rv; +} + +WRITE8_MEMBER( ncr539x_device::write ) +{ + #if VERBOSE + //if (offset != 2) + printf("539x: Write %02x @ %s (%02x) (PC=%x)\n", data, wrregs[offset], offset, space.device().safe_pc()); + #endif + + switch (offset) + { + case 0: + m_dma_size &= 0xff00; + m_dma_size |= data; + break; + + case 1: + m_dma_size &= 0x00ff; + m_dma_size |= (data<<8); + break; + + case 2: // FIFO + fifo_write(data); + break; + + case 3: + m_command = data; + + // clear status bits (OK to do here?) + m_status &= ~MAIN_STATUS_INTERRUPT; + m_irq_status = 0; + + switch (data & 0x7f) + { + case 0x00: // NOP + m_irq_status = IRQ_STATUS_SUCCESS; + m_status |= MAIN_STATUS_INTERRUPT; + m_out_irq_cb(ASSERT_LINE); + + // DMA NOP? allow chip ID + if ((m_command == 0x80) && (!m_chipid_lock)) + { + m_chipid_available = true; + } + break; + + case 0x01: // Clear FIFO (must not change buffer state) + m_fifo_ptr = 0; + update_fifo_internal_state(0); + m_irq_status = IRQ_STATUS_SUCCESS; + m_status |= MAIN_STATUS_INTERRUPT; + m_out_irq_cb(ASSERT_LINE); + break; + + case 0x02: // Reset device + device_reset(); + + m_irq_status = IRQ_STATUS_SUCCESS; + m_status |= MAIN_STATUS_INTERRUPT; + m_out_irq_cb(ASSERT_LINE); + break; + + case 0x03: // Reset SCSI bus + m_status = 0; + m_irq_status = IRQ_STATUS_SUCCESS; + m_status |= MAIN_STATUS_INTERRUPT; + m_out_irq_cb(ASSERT_LINE); + break; + + case 0x10: // information transfer (must happen immediately) + m_status &= 0x7; // clear everything but the phase bits + m_status |= MAIN_STATUS_INTERRUPT; + m_irq_status = IRQ_STATUS_SUCCESS; + + int phase; + phase = get_phase(); + + #if VERBOSE + printf("Information transfer: phase %d buffer remaining %x\n", phase, m_buffer_remaining); + #endif + + if (phase == SCSI_PHASE_DATAIN) // target -> initiator transfer + { + int amtToGet = m_buffer_size; + + // fill the internal sector buffer + if (m_buffer_remaining <= 0) + { + if (m_total_data < m_buffer_size) + { + amtToGet = m_total_data; + } + + #if VERBOSE + printf("amtToGet = %x\n", amtToGet); + #endif + + if (amtToGet > 0) + { + read_data(m_buffer, amtToGet); + + m_total_data -= amtToGet; + m_buffer_offset = 0; + m_buffer_remaining = amtToGet; + } + } + + // copy the requested amount into the FIFO + if (amtToGet > 0) + { + if (m_buffer_remaining < m_dma_size) + { + m_dma_size = m_buffer_remaining; + } + + int fifo_fill_size = m_fifo_size; + + if (m_dma_size < fifo_fill_size) + { + fifo_fill_size = m_dma_size; + } + + #if VERBOSE + printf("filling FIFO from buffer[%x] for %x bytes\n", m_buffer_offset, fifo_fill_size); + #endif + + memcpy(m_fifo, &m_buffer[m_buffer_offset], fifo_fill_size); + m_buffer_offset += fifo_fill_size; + m_buffer_remaining -= fifo_fill_size; + + m_xfer_count = m_dma_size; + m_fifo_ptr = 0; + update_fifo_internal_state(fifo_fill_size); + m_out_drq_cb(ASSERT_LINE); + } + + m_status |= MAIN_STATUS_COUNT_TO_ZERO; + + #if VERBOSE + printf("Information transfer: put %02x bytes into FIFO (dma size %x) (buffer remaining %x)\n", m_fifo_internal_state & 0x1f, m_dma_size, m_buffer_remaining); + #endif + } + else if (phase == SCSI_PHASE_DATAOUT) + { + m_xfer_count = m_dma_size; + if (m_xfer_count == 0) + { + m_xfer_count = 0x10000; + } + #if VERBOSE + printf("dma_size %x, xfer_count %x\n", m_dma_size, m_xfer_count); + #endif + m_status &= ~MAIN_STATUS_COUNT_TO_ZERO; + m_fifo_ptr = 0; + m_buffer_offset = 0; + m_buffer_remaining = 0; + } + m_out_irq_cb(ASSERT_LINE); + break; + + case 0x24: // Terminate steps + #if VERBOSE + printf("Terminate steps\n"); + #endif + m_irq_status = IRQ_STATUS_SUCCESS | IRQ_STATUS_DISCONNECTED; + m_status |= MAIN_STATUS_INTERRUPT; + m_out_irq_cb(ASSERT_LINE); + m_fifo_ptr = 0; + update_fifo_internal_state(0); + break; + + case 0x27: // Disconnect + #if VERBOSE + printf("Disconnect\n"); + #endif + m_irq_status = IRQ_STATUS_SUCCESS; + m_status |= MAIN_STATUS_INTERRUPT; + m_out_irq_cb(ASSERT_LINE); + break; + + case 0x44: // Enable selection/reselection + #if VERBOSE + printf("Enable selection/reselection\n"); + #endif + m_irq_status = IRQ_STATUS_SUCCESS; + m_status |= MAIN_STATUS_INTERRUPT; + m_out_irq_cb(ASSERT_LINE); + break; + + case 0x47: // Reselect with ATN3 steps + if (select(m_last_id)) + { + m_irq_status |= IRQ_STATUS_SERVICE_REQUEST | IRQ_STATUS_SUCCESS; + // we should now be in the command phase + m_status &= ~7; // clear bus phases + m_status |= MAIN_STATUS_INTERRUPT | SCSI_PHASE_COMMAND; + m_fifo_ptr = 0; + m_selected = true; + #if VERBOSE + printf("Reselecting with ATN3, irq_status = %02x, status = %02x!\n", m_irq_status, m_status); + #endif + + // if DMA is not enabled, there should already be a command loaded into the FIFO + if (!(m_command & 0x80)) + { + exec_fifo(); + } + update_fifo_internal_state(0); + } + else + { + #if VERBOSE + printf("Reselect with ATN3 failed, no device @ ID %d!\n", m_last_id); + #endif + m_status |= MAIN_STATUS_INTERRUPT; + m_irq_status |= IRQ_STATUS_DISCONNECTED; + } + m_out_irq_cb(ASSERT_LINE); + break; + + default: // other commands are not instantaneous + #if VERBOSE + printf("Setting timer for command %02x\n", data); + #endif + // 1x commands happen much faster + if ((m_command & 0x70) == 0x10) + { + m_operation_timer->adjust(attotime::from_hz(65536), TIMER_539X_COMMAND); + } + else + { + m_operation_timer->adjust(attotime::from_hz(16384), TIMER_539X_COMMAND); + } + break; + } + break; + + case 4: + m_last_id = data; + break; + + case 5: + m_timeout = data; + break; + + case 6: + m_sync_xfer_period = data; + break; + + case 7: + m_sync_offset = data; + break; + + case 8: + m_control1 = data; + break; + + case 9: + m_clock_factor = data; + break; + + case 0xa: + m_forced_test = data; + break; + + case 0xb: + m_control2 = data; + break; + + case 0xc: + m_control3 = data; + break; + + case 0xd: + m_control4 = data; + break; + + case 0xe: + if (m_control2 & CR2_FEATURES_ENABLE) + { + m_dma_size &= 0xffff; + m_dma_size |= (data<<16); + m_chipid_available = false; + m_chipid_lock = true; + } + break; + + case 0xf: + m_data_alignment = data; + break; + } +} + +void ncr539x_device::exec_fifo() +{ + int length, phase; + + send_command(&m_fifo[0], 12); + length = get_length(); + phase = get_phase(); + + #if VERBOSE + printf("Command executed (id %d), new phase %d, length %x\n", m_last_id, phase, length); + #endif + + m_buffer_offset = m_buffer_size; + m_buffer_remaining = 0; + m_total_data = length; + + m_status &= ~7; // clear bus phases + m_status |= (phase & 7); // set the phase reported by the device +} + +void ncr539x_device::check_fifo_executable() +{ + if (get_cmd_len(m_fifo[0]) == m_fifo_ptr) + { + exec_fifo(); + } +} + +void ncr539x_device::fifo_write(UINT8 data) +{ + int phase = (m_status & 7); + + if (phase != SCSI_PHASE_DATAOUT) + { + #if VERBOSE + printf("539x: Write %02x @ FIFO[%x]\n", data, m_fifo_ptr); + #endif + m_fifo[m_fifo_ptr++] = data; + update_fifo_internal_state(m_fifo_ptr); + + if (m_selected) + { + check_fifo_executable(); + } + } + else // phase is DATAOUT + { + m_buffer[m_buffer_offset++] = data; + m_xfer_count--; + m_total_data--; + #if VERBOSE + printf("539x: Write %02x @ buffer[%x], xfer_count %x, total %x\n", data, m_buffer_offset-1, m_xfer_count, m_total_data); + #endif + + // default to flushing our entire buffer + int flush_size = m_buffer_size; + + // if the actual size is less than the buffer size, flush that instead + if (m_dma_size < m_buffer_size) + { + flush_size = m_dma_size; + } + + if ((m_buffer_offset == flush_size) || (m_xfer_count == 0)) + { + #if VERBOSE + printf("Flushing buffer to device, %x bytes left in buffer (%x total)\n", m_xfer_count, m_total_data); + #endif + write_data(m_buffer, flush_size); + m_buffer_offset = 0; + + // need a service request here too + m_irq_status = IRQ_STATUS_SERVICE_REQUEST; + m_status &= 7; + m_status |= MAIN_STATUS_INTERRUPT; + m_out_irq_cb(ASSERT_LINE); + } + + if ((m_xfer_count == 0) && (m_total_data == 0)) + { + #if VERBOSE + printf("End of write, asserting service request\n"); + #endif + + m_buffer_offset = 0; + m_irq_status = IRQ_STATUS_SERVICE_REQUEST; + m_status = MAIN_STATUS_INTERRUPT | SCSI_PHASE_STATUS; + m_out_irq_cb(ASSERT_LINE); + } + } +} + +void ncr539x_device::update_fifo_internal_state(int bytes) +{ + if (bytes >= 0x1f) + { + m_fifo_internal_state |= 0x1f; + } + else + { + m_fifo_internal_state &= ~0x1f; + m_fifo_internal_state |= (bytes & 0x1f); + } +} diff --git a/src/devices/machine/ncr539x.h b/src/devices/machine/ncr539x.h new file mode 100644 index 00000000000..2280613d22f --- /dev/null +++ b/src/devices/machine/ncr539x.h @@ -0,0 +1,90 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/* + * ncr5394/5396.h SCSI controller + * + */ + +#ifndef _NCR539x_H_ +#define _NCR539x_H_ + +#include "legscsi.h" + +//// 539x registers +//enum +//{ +//}; + +// device stuff + +#define MCFG_NCR539X_OUT_IRQ_CB(_devcb) \ + devcb = &ncr539x_device::set_out_irq_callback(*device, DEVCB_##_devcb); + +#define MCFG_NCR539X_OUT_DRQ_CB(_devcb) \ + devcb = &ncr539x_device::set_out_drq_callback(*device, DEVCB_##_devcb); + +class ncr539x_device : public legacy_scsi_host_adapter +{ +public: + // construction/destruction + ncr539x_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + template static devcb_base &set_out_irq_callback(device_t &device, _Object object) { return downcast(device).m_out_irq_cb.set_callback(object); } + template static devcb_base &set_out_drq_callback(device_t &device, _Object object) { return downcast(device).m_out_drq_cb.set_callback(object); } + + // our API + DECLARE_READ8_MEMBER(read); + DECLARE_WRITE8_MEMBER(write); + + void dma_read_data(int bytes, UINT8 *pData); + void dma_write_data(int bytes, UINT8 *pData); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + +private: + void fifo_write(UINT8 data); + void check_fifo_executable(); + void exec_fifo(); + void update_fifo_internal_state(int bytes); + + UINT32 m_xfer_count; + UINT32 m_dma_size; + UINT8 m_command; + UINT8 m_last_id; + UINT8 m_timeout; + UINT8 m_sync_xfer_period; + UINT8 m_sync_offset; + UINT8 m_control1, m_control2, m_control3, m_control4; + UINT8 m_clock_factor; + UINT8 m_forced_test; + UINT8 m_data_alignment; + + bool m_selected; + bool m_chipid_available, m_chipid_lock; + + static const int m_fifo_size = 16; + UINT8 m_fifo_ptr, m_fifo_read_ptr, m_fifo[m_fifo_size]; + + //int m_xfer_remaining; // amount in the FIFO when we're in data in phase + + // read-only registers + UINT8 m_status, m_irq_status, m_internal_state, m_fifo_internal_state; + + static const int m_buffer_size = 2048; + + UINT8 m_buffer[m_buffer_size]; + int m_buffer_offset, m_buffer_remaining, m_total_data; + + emu_timer *m_operation_timer; + + devcb_write_line m_out_irq_cb; /* IRQ line */ + devcb_write_line m_out_drq_cb; /* DRQ line */ +}; + +// device type definition +extern const device_type NCR539X; +#endif diff --git a/src/devices/machine/netlist.c b/src/devices/machine/netlist.c new file mode 100644 index 00000000000..cdbfe89d91b --- /dev/null +++ b/src/devices/machine/netlist.c @@ -0,0 +1,660 @@ +// license:GPL-2.0+ +// copyright-holders:Couriersud +/*************************************************************************** + + netlist.c + + Discrete netlist implementation. + +****************************************************************************/ + +#include "emu.h" +#include "netlist.h" +#include "netlist/nl_base.h" +#include "netlist/nl_setup.h" +#include "netlist/nl_factory.h" +#include "netlist/nl_parser.h" +#include "netlist/devices/net_lib.h" +#include "debugger.h" + +//#define LOG_DEV_CALLS(x) printf x +#define LOG_DEV_CALLS(x) do { } while (0) + +const device_type NETLIST_CORE = &device_creator; +const device_type NETLIST_CPU = &device_creator; +const device_type NETLIST_SOUND = &device_creator; + +/* subdevices */ + +const device_type NETLIST_ANALOG_INPUT = &device_creator; +const device_type NETLIST_LOGIC_INPUT = &device_creator; +const device_type NETLIST_STREAM_INPUT = &device_creator; + +const device_type NETLIST_ANALOG_OUTPUT = &device_creator; +const device_type NETLIST_STREAM_OUTPUT = &device_creator; + +// ---------------------------------------------------------------------------------------- +// netlist_mame_analog_input_t +// ---------------------------------------------------------------------------------------- + +void netlist_mame_sub_interface::static_set_mult_offset(device_t &device, const double mult, const double offset) +{ + netlist_mame_sub_interface &netlist = dynamic_cast(device); + netlist.m_mult = mult; + netlist.m_offset = offset; +} + + +netlist_mame_analog_input_t::netlist_mame_analog_input_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, NETLIST_ANALOG_INPUT, "Netlist Analog Input", tag, owner, clock, "netlist_analog_input", __FILE__), + netlist_mame_sub_interface(*owner), + m_param(0), + m_auto_port(true), + m_param_name("") +{ +} + +void netlist_mame_analog_input_t::static_set_name(device_t &device, const char *param_name) +{ + netlist_mame_analog_input_t &netlist = downcast(device); + netlist.m_param_name = param_name; +} + +void netlist_mame_analog_input_t::device_start() +{ + LOG_DEV_CALLS(("start %s\n", tag())); + netlist::param_t *p = this->nl_owner().setup().find_param(m_param_name); + m_param = dynamic_cast(p); + if (m_param == NULL) + { + fatalerror("device %s wrong parameter type for %s\n", basetag(), m_param_name.cstr()); + } + if (m_mult != 1.0 || m_offset != 0.0) + { + // disable automatic scaling for ioports + m_auto_port = false; + } + +} + +// ---------------------------------------------------------------------------------------- +// netlist_mame_analog_output_t +// ---------------------------------------------------------------------------------------- + +netlist_mame_analog_output_t::netlist_mame_analog_output_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, NETLIST_ANALOG_INPUT, "Netlist Analog Output", tag, owner, clock, "netlist_analog_output", __FILE__), + netlist_mame_sub_interface(*owner), + m_in("") +{ +} + +void netlist_mame_analog_output_t::static_set_params(device_t &device, const char *in_name, netlist_analog_output_delegate adelegate) +{ + netlist_mame_analog_output_t &netlist = downcast(device); + netlist.m_in = in_name; + netlist.m_delegate = adelegate; +} + +void netlist_mame_analog_output_t::custom_netlist_additions(netlist::setup_t &setup) +{ + pstring dname = "OUT_" + m_in; + m_delegate.bind_relative_to(owner()->machine().root_device()); + NETLIB_NAME(analog_callback) *dev = downcast( + setup.register_dev("NETDEV_CALLBACK", dname)); + + dev->register_callback(m_delegate); + setup.register_link(dname + ".IN", m_in); +} + +void netlist_mame_analog_output_t::device_start() +{ + LOG_DEV_CALLS(("start %s\n", tag())); +} + + +// ---------------------------------------------------------------------------------------- +// netlist_mame_logic_input_t +// ---------------------------------------------------------------------------------------- + +netlist_mame_logic_input_t::netlist_mame_logic_input_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, NETLIST_ANALOG_INPUT, "Netlist Logic Input", tag, owner, clock, "netlist_logic_input", __FILE__), + netlist_mame_sub_interface(*owner), + m_param(0), + m_mask(0xffffffff), + m_shift(0), + m_param_name("") +{ +} + +void netlist_mame_logic_input_t::static_set_params(device_t &device, const char *param_name, const UINT32 mask, const UINT32 shift) +{ + netlist_mame_logic_input_t &netlist = downcast(device); + netlist.m_param_name = param_name; + netlist.m_shift = shift; + netlist.m_mask = mask; +} + +void netlist_mame_logic_input_t::device_start() +{ + LOG_DEV_CALLS(("start %s\n", tag())); + netlist::param_t *p = downcast(this->owner())->setup().find_param(m_param_name); + m_param = dynamic_cast(p); + if (m_param == NULL) + { + fatalerror("device %s wrong parameter type for %s\n", basetag(), m_param_name.cstr()); + } +} + +// ---------------------------------------------------------------------------------------- +// netlist_mame_stream_input_t +// ---------------------------------------------------------------------------------------- + +netlist_mame_stream_input_t::netlist_mame_stream_input_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, NETLIST_ANALOG_INPUT, "Netlist Stream Input", tag, owner, clock, "netlist_stream_input", __FILE__), + netlist_mame_sub_interface(*owner), + m_channel(0), + m_param_name("") +{ +} + +void netlist_mame_stream_input_t::static_set_params(device_t &device, int channel, const char *param_name) +{ + netlist_mame_stream_input_t &netlist = downcast(device); + netlist.m_param_name = param_name; + netlist.m_channel = channel; +} + +void netlist_mame_stream_input_t::device_start() +{ + LOG_DEV_CALLS(("start %s\n", tag())); +} + +void netlist_mame_stream_input_t::custom_netlist_additions(netlist::setup_t &setup) +{ + NETLIB_NAME(sound_in) *snd_in = setup.netlist().get_first_device(); + if (snd_in == NULL) + snd_in = dynamic_cast(setup.register_dev("NETDEV_SOUND_IN", "STREAM_INPUT")); + + pstring sparam = pfmt("STREAM_INPUT.CHAN{1}")(m_channel); + setup.register_param(sparam, m_param_name); + sparam = pfmt("STREAM_INPUT.MULT{1}")(m_channel); + setup.register_param(sparam, m_mult); + sparam = pfmt("STREAM_INPUT.OFFSET{1}")(m_channel); + setup.register_param(sparam, m_offset); +} + +// ---------------------------------------------------------------------------------------- +// netlist_mame_stream_output_t +// ---------------------------------------------------------------------------------------- + +netlist_mame_stream_output_t::netlist_mame_stream_output_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, NETLIST_ANALOG_INPUT, "Netlist Stream Output", tag, owner, clock, "netlist_stream_output", __FILE__), + netlist_mame_sub_interface(*owner), + m_channel(0), + m_out_name("") +{ +} + +void netlist_mame_stream_output_t::static_set_params(device_t &device, int channel, const char *out_name) +{ + netlist_mame_stream_output_t &netlist = downcast(device); + netlist.m_out_name = out_name; + netlist.m_channel = channel; +} + +void netlist_mame_stream_output_t::device_start() +{ + LOG_DEV_CALLS(("start %s\n", tag())); +} + +void netlist_mame_stream_output_t::custom_netlist_additions(netlist::setup_t &setup) +{ + //NETLIB_NAME(sound_out) *snd_out; + pstring sname = pfmt("STREAM_OUT_{1}")(m_channel); + + //snd_out = dynamic_cast(setup.register_dev("nld_sound_out", sname)); + setup.register_dev("NETDEV_SOUND_OUT", sname); + + setup.register_param(sname + ".CHAN" , m_channel); + setup.register_param(sname + ".MULT", m_mult); + setup.register_param(sname + ".OFFSET", m_offset); + setup.register_link(sname + ".IN", m_out_name); +} + + +// ---------------------------------------------------------------------------------------- +// netlist_mame_t +// ---------------------------------------------------------------------------------------- + +void netlist_mame_t::vlog(const plog_level &l, const pstring &ls) const +{ + pstring errstr = ls; + + switch (l) + { + case DEBUG: + logerror("netlist DEBUG: %s\n", errstr.cstr()); + break; + case INFO: + logerror("netlist INFO: %s\n", errstr.cstr()); + break; + case VERBOSE: + logerror("netlist VERBOSE: %s\n", errstr.cstr()); + break; + case WARNING: + logerror("netlist WARNING: %s\n", errstr.cstr()); + break; + case ERROR: + logerror("netlist ERROR: %s\n", errstr.cstr()); + break; + case FATAL: + emu_fatalerror error("netlist ERROR: %s\n", errstr.cstr()); + throw error; + } +} + +// ---------------------------------------------------------------------------------------- +// netlist_mame_device_t +// ---------------------------------------------------------------------------------------- + +static ADDRESS_MAP_START(program_dummy, AS_PROGRAM, 8, netlist_mame_device_t) + AM_RANGE(0x000, 0x3ff) AM_ROM +ADDRESS_MAP_END + +netlist_mame_device_t::netlist_mame_device_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, NETLIST_CORE, "Netlist core device", tag, owner, clock, "netlist_core", __FILE__), + m_icount(0), + m_old(netlist::netlist_time::zero), + m_netlist(NULL), + m_setup(NULL), + m_setup_func(NULL) +{ +} + +netlist_mame_device_t::netlist_mame_device_t(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *file) + : device_t(mconfig, type, name, tag, owner, clock, shortname, file), + m_icount(0), + m_old(netlist::netlist_time::zero), + m_netlist(NULL), + m_setup(NULL), + m_setup_func(NULL) +{ +} + +void netlist_mame_device_t::static_set_constructor(device_t &device, void (*setup_func)(netlist::setup_t &)) +{ + LOG_DEV_CALLS(("static_set_constructor\n")); + netlist_mame_device_t &netlist = downcast(device); + netlist.m_setup_func = setup_func; +} + +void netlist_mame_device_t::device_config_complete() +{ + LOG_DEV_CALLS(("device_config_complete\n")); +} + +void netlist_mame_device_t::device_start() +{ + LOG_DEV_CALLS(("device_start %s\n", tag())); + + //printf("clock is %d\n", clock()); + + m_netlist = global_alloc(netlist_mame_t(*this)); + m_setup = global_alloc(netlist::setup_t(m_netlist)); + netlist().init_object(*m_netlist, "netlist"); + m_setup->init(); + + // register additional devices + + nl_register_devices(); + + m_setup_func(*m_setup); + + /* let sub-devices tweak the netlist */ + for( device_t *d = this->first_subdevice(); d != NULL; d = d->next() ) + { + netlist_mame_sub_interface *sdev = dynamic_cast(d); + if( sdev != NULL ) + { + LOG_DEV_CALLS(("Found subdevice %s/%s\n", d->name(), d->shortname())); + sdev->custom_netlist_additions(*m_setup); + } + } + + m_setup->start_devices(); + m_setup->resolve_inputs(); + + netlist().save(NAME(m_rem)); + netlist().save(NAME(m_div)); + netlist().save(NAME(m_old)); + + save_state(); + + m_old = netlist::netlist_time::zero; + m_rem = netlist::netlist_time::zero; + +} + +void netlist_mame_device_t::device_clock_changed() +{ + m_div = netlist::netlist_time::from_hz(clock()); + netlist().log().debug("Setting clock {1} and divisor {2}\n", clock(), m_div.as_double()); +} + + +void netlist_mame_device_t::device_reset() +{ + LOG_DEV_CALLS(("device_reset\n")); + m_old = netlist::netlist_time::zero; + m_rem = netlist::netlist_time::zero; + netlist().do_reset(); +} + +void netlist_mame_device_t::device_stop() +{ + LOG_DEV_CALLS(("device_stop\n")); + m_setup->print_stats(); + + m_netlist->stop(); + + global_free(m_setup); + m_setup = NULL; + global_free(m_netlist); + m_netlist = NULL; +} + +ATTR_COLD void netlist_mame_device_t::device_post_load() +{ + LOG_DEV_CALLS(("device_post_load\n")); + + netlist().post_load(); + netlist().rebuild_lists(); +} + +ATTR_COLD void netlist_mame_device_t::device_pre_save() +{ + LOG_DEV_CALLS(("device_pre_save\n")); + + netlist().pre_save(); +} + +void netlist_mame_device_t::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ +} + +ATTR_HOT ATTR_ALIGN void netlist_mame_device_t::update_time_x() +{ + const netlist::netlist_time newt = netlist().time(); + const netlist::netlist_time delta = newt - m_old + m_rem; + const UINT64 d = delta / m_div; + m_old = newt; + m_rem = delta - (m_div * d); + m_icount -= d; +} + +ATTR_HOT ATTR_ALIGN void netlist_mame_device_t::check_mame_abort_slice() +{ + if (m_icount <= 0) + netlist().abort_current_queue_slice(); +} + +ATTR_COLD void netlist_mame_device_t::save_state() +{ + for (int i=0; i< netlist().save_list().size(); i++) + { + pstate_entry_t *s = netlist().save_list()[i]; + netlist().log().debug("saving state for {1}\n", s->m_name.cstr()); + switch (s->m_dt) + { + case DT_DOUBLE: + { + double *td = s->resolved(); + if (td != NULL) save_pointer(td, s->m_name.cstr(), s->m_count); + } + break; + case DT_FLOAT: + { + float *td = s->resolved(); + if (td != NULL) save_pointer(td, s->m_name.cstr(), s->m_count); + } + break; +#if (PHAS_INT128) + case DT_INT128: + // FIXME: we are cheating here + save_pointer((char *) s->m_ptr, s->m_name.cstr(), s->m_count * sizeof(INT128)); + break; +#endif + case DT_INT64: + save_pointer((INT64 *) s->m_ptr, s->m_name.cstr(), s->m_count); + break; + case DT_INT16: + save_pointer((INT16 *) s->m_ptr, s->m_name.cstr(), s->m_count); + break; + case DT_INT8: + save_pointer((INT8 *) s->m_ptr, s->m_name.cstr(), s->m_count); + break; + case DT_INT: + save_pointer((int *) s->m_ptr, s->m_name.cstr(), s->m_count); + break; + case DT_BOOLEAN: + save_pointer((bool *) s->m_ptr, s->m_name.cstr(), s->m_count); + break; + case DT_CUSTOM: + break; + case NOT_SUPPORTED: + default: + netlist().log().fatal("found unsupported save element %s\n", s->m_name); + break; + } + } + +} + +// ---------------------------------------------------------------------------------------- +// netlist_mame_cpu_device_t +// ---------------------------------------------------------------------------------------- + +netlist_mame_cpu_device_t::netlist_mame_cpu_device_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : netlist_mame_device_t(mconfig, NETLIST_CPU, "Netlist CPU Device", tag, owner, clock, "netlist_cpu", __FILE__), + device_execute_interface(mconfig, *this), + device_state_interface(mconfig, *this), + device_disasm_interface(mconfig, *this), + device_memory_interface(mconfig, *this), + m_program_config("program", ENDIANNESS_LITTLE, 8, 12, 0, ADDRESS_MAP_NAME(program_dummy)) +{ +} + + +void netlist_mame_cpu_device_t::device_start() +{ + netlist_mame_device_t::device_start(); + + LOG_DEV_CALLS(("cpu device_start %s\n", tag())); + + // State support + + state_add(STATE_GENPC, "curpc", m_genPC).noshow(); + + for (int i=0; i < netlist().m_nets.size(); i++) + { + netlist::net_t *n = netlist().m_nets[i]; + if (n->isFamily(netlist::object_t::LOGIC)) + { + state_add(i*2, n->name().cstr(), downcast(n)->Q_state_ptr()); + } + else + { + state_add(i*2+1, n->name().cstr(), downcast(n)->Q_Analog_state_ptr()).formatstr("%20s"); + } + } + + // set our instruction counter + m_icountptr = &m_icount; +} + + +void netlist_mame_cpu_device_t::nl_register_devices() +{ + setup().factory().register_device( "NETDEV_CALLBACK", "nld_analog_callback", "-"); +} + +ATTR_COLD UINT64 netlist_mame_cpu_device_t::execute_clocks_to_cycles(UINT64 clocks) const +{ + return clocks; +} + +ATTR_COLD UINT64 netlist_mame_cpu_device_t::execute_cycles_to_clocks(UINT64 cycles) const +{ + return cycles; +} + +ATTR_COLD offs_t netlist_mame_cpu_device_t::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + //char tmp[16]; + unsigned startpc = pc; + int relpc = pc - m_genPC; + if (relpc >= 0 && relpc < netlist().queue().count()) + { + int dpc = netlist().queue().count() - relpc - 1; + // FIXME: 50 below fixes crash in mame-debugger. It's based on try on error. + snprintf(buffer, 50, "%c %s @%10.7f", (relpc == 0) ? '*' : ' ', netlist().queue()[dpc].object()->name().cstr(), + netlist().queue()[dpc].exec_time().as_double()); + } + else + sprintf(buffer, "%s", ""); + + pc+=1; + return (pc - startpc); +} + +ATTR_HOT void netlist_mame_cpu_device_t::execute_run() +{ + bool check_debugger = ((device_t::machine().debug_flags & DEBUG_FLAG_ENABLED) != 0); + // debugging + //m_ppc = m_pc; // copy PC to previous PC + if (check_debugger) + { + while (m_icount > 0) + { + m_genPC++; + m_genPC &= 255; + debugger_instruction_hook(this, m_genPC); + netlist().process_queue(m_div); + update_time_x(); + } + } + else + { + netlist().process_queue(m_div * m_icount); + update_time_x(); + } +} + +// ---------------------------------------------------------------------------------------- +// netlist_mame_sound_device_t +// ---------------------------------------------------------------------------------------- + +netlist_mame_sound_device_t::netlist_mame_sound_device_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : netlist_mame_device_t(mconfig, NETLIST_CPU, "Netlist Sound Device", tag, owner, clock, "netlist_sound", __FILE__), + device_sound_interface(mconfig, *this) +{ +} + +void netlist_mame_sound_device_t::device_start() +{ + netlist_mame_device_t::device_start(); + + LOG_DEV_CALLS(("sound device_start %s\n", tag())); + + // Configure outputs + + plist_t outdevs = netlist().get_device_list(); + if (outdevs.size() == 0) + fatalerror("No output devices"); + + m_num_outputs = outdevs.size(); + + /* resort channels */ + for (int i=0; i < MAX_OUT; i++) m_out[i] = NULL; + for (int i=0; i < m_num_outputs; i++) + { + int chan = outdevs[i]->m_channel.Value(); + + netlist().log().verbose("Output %d on channel %d", i, chan); + + if (chan < 0 || chan >= MAX_OUT || chan >= outdevs.size()) + fatalerror("illegal channel number"); + m_out[chan] = outdevs[i]; + m_out[chan]->m_sample = netlist::netlist_time::from_hz(clock()); + m_out[chan]->m_buffer = NULL; + } + + // Configure inputs + + m_num_inputs = 0; + m_in = NULL; + + plist_t indevs = netlist().get_device_list(); + if (indevs.size() > 1) + fatalerror("A maximum of one input device is allowed!"); + if (indevs.size() == 1) + { + m_in = indevs[0]; + m_num_inputs = m_in->resolve(); + m_in->m_inc = netlist::netlist_time::from_hz(clock()); + } + + /* initialize the stream(s) */ + m_stream = machine().sound().stream_alloc(*this, m_num_inputs, m_num_outputs, clock()); + +} + +void netlist_mame_sound_device_t::nl_register_devices() +{ + setup().factory().register_device("NETDEV_SOUND_OUT", "nld_sound_out", "+CHAN"); + setup().factory().register_device("NETDEV_SOUND_IN", "nld_sound_in", "-"); +} + + +void netlist_mame_sound_device_t::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + for (int i=0; i < m_num_outputs; i++) + { + m_out[i]->m_buffer = outputs[i]; + } + + if (m_num_inputs) + m_in->buffer_reset(); + + for (int i=0; i < m_num_inputs; i++) + { + m_in->m_buffer[i] = inputs[i]; + } + + netlist::netlist_time cur = netlist().time(); + + netlist().process_queue(m_div * samples); + + cur += (m_div * samples); + + for (int i=0; i < m_num_outputs; i++) + { + m_out[i]->sound_update(cur); + m_out[i]->buffer_reset(cur); + } +} + +// ---------------------------------------------------------------------------------------- +// memregion source support +// ---------------------------------------------------------------------------------------- + +bool netlist_source_memregion_t::parse(netlist::setup_t &setup, const pstring &name) +{ + // FIXME: preprocessor should be a stream! + memory_region *mem = downcast(setup.netlist()).machine().root_device().memregion(m_name.cstr()); + pimemstream istrm(mem->base(),mem->bytes() ); + pomemstream ostrm; + + pimemstream istrm2(ppreprocessor().process(istrm, ostrm)); + return netlist::parser_t(istrm2, setup).parse(name); +} diff --git a/src/devices/machine/netlist.h b/src/devices/machine/netlist.h new file mode 100644 index 00000000000..32b19070d4e --- /dev/null +++ b/src/devices/machine/netlist.h @@ -0,0 +1,725 @@ +// license:GPL-2.0+ +// copyright-holders:Couriersud +/*************************************************************************** + + netlist.h + + Discrete netlist implementation. + +****************************************************************************/ + +#ifndef NETLIST_H +#define NETLIST_H + +#include "emu.h" +#include "tagmap.h" + +#include "netlist/nl_base.h" +#include "netlist/nl_setup.h" + +// MAME specific configuration + + +#define MCFG_NETLIST_SETUP(_setup) \ + netlist_mame_device_t::static_set_constructor(*device, NETLIST_NAME(_setup)); + +#define MCFG_NETLIST_ANALOG_INPUT(_basetag, _tag, _name) \ + MCFG_DEVICE_ADD(_basetag ":" _tag, NETLIST_ANALOG_INPUT, 0) \ + netlist_mame_analog_input_t::static_set_name(*device, _name); + +#define MCFG_NETLIST_ANALOG_MULT_OFFSET(_mult, _offset) \ + netlist_mame_sub_interface::static_set_mult_offset(*device, _mult, _offset); + +#define MCFG_NETLIST_ANALOG_OUTPUT(_basetag, _tag, _IN, _class, _member, _class_tag) \ + MCFG_DEVICE_ADD(_basetag ":" _tag, NETLIST_ANALOG_OUTPUT, 0) \ + netlist_mame_analog_output_t::static_set_params(*device, _IN, \ + netlist_analog_output_delegate(& _class :: _member, \ + # _class "::" # _member, _class_tag, (_class *) 0) ); + +#define MCFG_NETLIST_LOGIC_INPUT(_basetag, _tag, _name, _shift, _mask) \ + MCFG_DEVICE_ADD(_basetag ":" _tag, NETLIST_LOGIC_INPUT, 0) \ + netlist_mame_logic_input_t::static_set_params(*device, _name, _mask, _shift); + +#define MCFG_NETLIST_STREAM_INPUT(_basetag, _chan, _name) \ + MCFG_DEVICE_ADD(_basetag ":cin" # _chan, NETLIST_STREAM_INPUT, 0) \ + netlist_mame_stream_input_t::static_set_params(*device, _chan, _name); + +#define MCFG_NETLIST_STREAM_OUTPUT(_basetag, _chan, _name) \ + MCFG_DEVICE_ADD(_basetag ":cout" # _chan, NETLIST_STREAM_OUTPUT, 0) \ + netlist_mame_stream_output_t::static_set_params(*device, _chan, _name); + + +#define NETLIST_LOGIC_PORT_CHANGED(_base, _tag) \ + PORT_CHANGED_MEMBER(_base ":" _tag, netlist_mame_logic_input_t, input_changed, 0) + +#define NETLIST_ANALOG_PORT_CHANGED(_base, _tag) \ + PORT_CHANGED_MEMBER(_base ":" _tag, netlist_mame_analog_input_t, input_changed, 0) + + +// ---------------------------------------------------------------------------------------- +// Extensions to interface netlist with MAME code .... +// ---------------------------------------------------------------------------------------- + +class netlist_source_memregion_t : public netlist::setup_t::source_t +{ +public: + netlist_source_memregion_t(pstring name) + : netlist::setup_t::source_t(), m_name(name) + { + } + + bool parse(netlist::setup_t &setup, const pstring &name); +private: + pstring m_name; +}; + +#define MEMREGION_SOURCE(_name) \ + setup.register_source(palloc(netlist_source_memregion_t(_name))); + +#define NETDEV_ANALOG_CALLBACK_MEMBER(_name) \ + void _name(const double data, const attotime &time) + +class netlist_mame_device_t; + +class netlist_mame_t : public netlist::netlist_t +{ +public: + + netlist_mame_t(netlist_mame_device_t &parent) + : netlist::netlist_t(), + m_parent(parent) + {} + virtual ~netlist_mame_t() { }; + + inline running_machine &machine(); + + netlist_mame_device_t &parent() { return m_parent; } + +protected: + + void vlog(const plog_level &l, const pstring &ls) const; + +private: + netlist_mame_device_t &m_parent; +}; + +// ---------------------------------------------------------------------------------------- +// netlist_mame_device_t +// ---------------------------------------------------------------------------------------- + +class netlist_mame_device_t : public device_t +{ +public: + + // construction/destruction + netlist_mame_device_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + netlist_mame_device_t(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *file); + virtual ~netlist_mame_device_t() {} + + static void static_set_constructor(device_t &device, void (*setup_func)(netlist::setup_t &)); + + ATTR_HOT inline netlist::setup_t &setup() { return *m_setup; } + ATTR_HOT inline netlist_mame_t &netlist() { return *m_netlist; } + + ATTR_HOT inline netlist::netlist_time last_time_update() { return m_old; } + ATTR_HOT void update_time_x(); + ATTR_HOT void check_mame_abort_slice(); + + int m_icount; + +protected: + // Custom to netlist ... + + virtual void nl_register_devices() { }; + + // device_t overrides + virtual void device_config_complete(); + virtual void device_start(); + virtual void device_stop(); + virtual void device_reset(); + virtual void device_post_load(); + virtual void device_pre_save(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + //virtual void device_debug_setup(); + virtual void device_clock_changed(); + + netlist::netlist_time m_div; + +private: + void save_state(); + + /* timing support here - so sound can hijack it ... */ + netlist::netlist_time m_rem; + netlist::netlist_time m_old; + + netlist_mame_t * m_netlist; + netlist::setup_t * m_setup; + + void (*m_setup_func)(netlist::setup_t &); +}; + +inline running_machine &netlist_mame_t::machine() +{ + return m_parent.machine(); +} + +// ---------------------------------------------------------------------------------------- +// netlist_mame_cpu_device_t +// ---------------------------------------------------------------------------------------- + +class netlist_mame_cpu_device_t : public netlist_mame_device_t, + public device_execute_interface, + public device_state_interface, + public device_disasm_interface, + public device_memory_interface +{ +public: + + // construction/destruction + netlist_mame_cpu_device_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual ~netlist_mame_cpu_device_t() {} + + static void static_set_constructor(device_t &device, void (*setup_func)(netlist::setup_t &)); + +protected: + // netlist_mame_device_t + virtual void nl_register_devices(); + + // device_t overrides + + //virtual void device_config_complete(); + virtual void device_start(); + //virtual void device_stop(); + //virtual void device_reset(); + //virtual void device_post_load(); + //virtual void device_pre_save(); + //virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + // device_execute_interface overrides + + virtual UINT64 execute_clocks_to_cycles(UINT64 clocks) const; + virtual UINT64 execute_cycles_to_clocks(UINT64 cycles) const; + + ATTR_HOT virtual void execute_run(); + + // device_disasm_interface overrides + ATTR_COLD virtual UINT32 disasm_min_opcode_bytes() const { return 1; } + ATTR_COLD virtual UINT32 disasm_max_opcode_bytes() const { return 1; } + ATTR_COLD virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + + // device_memory_interface overrides + + address_space_config m_program_config; + + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const + { + switch (spacenum) + { + case AS_PROGRAM: return &m_program_config; + case AS_IO: return NULL; + default: return NULL; + } + } + + // device_state_interface overrides + + virtual void state_string_export(const device_state_entry &entry, std::string &str) + { + if (entry.index() >= 0) + { + if (entry.index() & 1) + strprintf(str,"%10.6f", *((double *)entry.dataptr())); + else + strprintf(str, "%d", *((netlist_sig_t *)entry.dataptr())); + } + } + +private: + + int m_genPC; + +}; + +class nld_sound_out; +class nld_sound_in; + +// ---------------------------------------------------------------------------------------- +// netlist_mame_sound_device_t +// ---------------------------------------------------------------------------------------- + +class netlist_mame_sound_device_t : public netlist_mame_device_t, + public device_sound_interface +{ +public: + + // construction/destruction + netlist_mame_sound_device_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual ~netlist_mame_sound_device_t() {} + + static void static_set_constructor(device_t &device, void (*setup_func)(netlist::setup_t &)); + + inline sound_stream *get_stream() { return m_stream; } + + + // device_sound_interface overrides + + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + +protected: + // netlist_mame_device_t + virtual void nl_register_devices(); + + // device_t overrides + + //virtual void device_config_complete(); + virtual void device_start(); + //virtual void device_stop(); + //virtual void device_reset(); + //virtual void device_post_load(); + //virtual void device_pre_save(); + //virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + +private: + + static const int MAX_OUT = 10; + nld_sound_out *m_out[MAX_OUT]; + nld_sound_in *m_in; + sound_stream *m_stream; + int m_num_inputs; + int m_num_outputs; + +}; + +// ---------------------------------------------------------------------------------------- +// netlist_mame_sub_interface +// ---------------------------------------------------------------------------------------- + +class netlist_mame_sub_interface +{ +public: + // construction/destruction + netlist_mame_sub_interface(device_t &aowner) + : m_offset(0.0), m_mult(1.0) + { + m_owner = dynamic_cast(&aowner); + m_sound = dynamic_cast(&aowner); + } + virtual ~netlist_mame_sub_interface() { } + + virtual void custom_netlist_additions(netlist::setup_t &setup) { } + + inline netlist_mame_device_t &nl_owner() const { return *m_owner; } + + inline bool is_sound_device() const { return (m_sound != NULL); } + + inline void update_to_current_time() + { + m_sound->get_stream()->update(); + } + + static void static_set_mult_offset(device_t &device, const double mult, const double offset); + +protected: + double m_offset; + double m_mult; + +private: + netlist_mame_device_t *m_owner; + netlist_mame_sound_device_t *m_sound; +}; + +// ---------------------------------------------------------------------------------------- +// netlist_mame_analog_input_t +// ---------------------------------------------------------------------------------------- + +class netlist_mame_analog_input_t : public device_t, + public netlist_mame_sub_interface +{ +public: + + // construction/destruction + netlist_mame_analog_input_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual ~netlist_mame_analog_input_t() { } + + static void static_set_name(device_t &device, const char *param_name); + + inline void write(const double val) + { + if (is_sound_device()) + { + update_to_current_time(); + m_param->setTo(val * m_mult + m_offset); + } + else + { + // FIXME: use device timer .... + m_param->setTo(val * m_mult + m_offset); + } + } + + inline DECLARE_INPUT_CHANGED_MEMBER(input_changed) + { + if (m_auto_port) + write(((double) newval - (double) field.minval())/((double) (field.maxval()-field.minval()) ) ); + else + write(newval); + } + inline DECLARE_WRITE_LINE_MEMBER(write_line) { write(state); } + inline DECLARE_WRITE8_MEMBER(write8) { write(data); } + inline DECLARE_WRITE16_MEMBER(write16) { write(data); } + inline DECLARE_WRITE32_MEMBER(write32) { write(data); } + inline DECLARE_WRITE64_MEMBER(write64) { write(data); } + +protected: + // device-level overrides + virtual void device_start(); + +private: + netlist::param_double_t *m_param; + bool m_auto_port; + pstring m_param_name; +}; + +// ---------------------------------------------------------------------------------------- +// netlist_mame_analog_output_t +// ---------------------------------------------------------------------------------------- + +typedef device_delegate netlist_analog_output_delegate; + +class netlist_mame_analog_output_t : public device_t, + public netlist_mame_sub_interface +{ +public: + + // construction/destruction + netlist_mame_analog_output_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual ~netlist_mame_analog_output_t() { } + + static void static_set_params(device_t &device, const char *in_name, netlist_analog_output_delegate adelegate); + +protected: + // device-level overrides + virtual void device_start(); + virtual void custom_netlist_additions(netlist::setup_t &setup); + +private: + pstring m_in; + netlist_analog_output_delegate m_delegate; +}; + + +// ---------------------------------------------------------------------------------------- +// netlist_mame_logic_input_t +// ---------------------------------------------------------------------------------------- + +class netlist_mame_logic_input_t : public device_t, + public netlist_mame_sub_interface +{ +public: + + // construction/destruction + netlist_mame_logic_input_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual ~netlist_mame_logic_input_t() { } + + static void static_set_params(device_t &device, const char *param_name, const UINT32 mask, const UINT32 shift); + + inline void write(const UINT32 val) + { + const UINT32 v = (val >> m_shift) & m_mask; + if (v != m_param->Value()) + synchronize(0, v); + } + + inline DECLARE_INPUT_CHANGED_MEMBER(input_changed) { write(newval); } + DECLARE_WRITE_LINE_MEMBER(write_line) { write(state); } + DECLARE_WRITE8_MEMBER(write8) { write(data); } + DECLARE_WRITE16_MEMBER(write16) { write(data); } + DECLARE_WRITE32_MEMBER(write32) { write(data); } + DECLARE_WRITE64_MEMBER(write64) { write(data); } + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) + { + if (is_sound_device()) + update_to_current_time(); + m_param->setTo(param); + } + +private: + netlist::param_int_t *m_param; + UINT32 m_mask; + UINT32 m_shift; + pstring m_param_name; +}; + +// ---------------------------------------------------------------------------------------- +// netlist_mame_stream_input_t +// ---------------------------------------------------------------------------------------- + +class netlist_mame_stream_input_t : public device_t, + public netlist_mame_sub_interface +{ +public: + + // construction/destruction + netlist_mame_stream_input_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual ~netlist_mame_stream_input_t() { } + + static void static_set_params(device_t &device, int channel, const char *param_name); + +protected: + // device-level overrides + virtual void device_start(); + virtual void custom_netlist_additions(netlist::setup_t &setup); +private: + UINT32 m_channel; + pstring m_param_name; +}; + +// ---------------------------------------------------------------------------------------- +// netlist_mame_stream_output_t +// ---------------------------------------------------------------------------------------- + +class netlist_mame_stream_output_t : public device_t, + public netlist_mame_sub_interface +{ +public: + + // construction/destruction + netlist_mame_stream_output_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual ~netlist_mame_stream_output_t() { } + + static void static_set_params(device_t &device, int channel, const char *out_name); + +protected: + // device-level overrides + virtual void device_start(); + virtual void custom_netlist_additions(netlist::setup_t &setup); +private: + UINT32 m_channel; + pstring m_out_name; +}; +// ---------------------------------------------------------------------------------------- +// netdev_callback +// ---------------------------------------------------------------------------------------- + +class NETLIB_NAME(analog_callback) : public netlist::device_t +{ +public: + NETLIB_NAME(analog_callback)() + : device_t(), m_cpu_device(NULL), m_last(0) { } + + ATTR_COLD void start() + { + register_input("IN", m_in); + m_cpu_device = downcast(&downcast(netlist()).parent()); + save(NLNAME(m_last)); + } + + ATTR_COLD void reset() + { + m_last = 0.0; + } + + ATTR_COLD void register_callback(netlist_analog_output_delegate callback) + { + m_callback = callback; + } + + ATTR_HOT void update() + { + nl_double cur = INPANALOG(m_in); + + // FIXME: make this a parameter + // avoid calls due to noise + if (fabs(cur - m_last) > 1e-6) + { + m_cpu_device->update_time_x(); + m_callback(cur, m_cpu_device->local_time()); + m_cpu_device->check_mame_abort_slice(); + m_last = cur; + } + } + +private: + netlist::analog_input_t m_in; + netlist_analog_output_delegate m_callback; + netlist_mame_cpu_device_t *m_cpu_device; + nl_double m_last; +}; + +// ---------------------------------------------------------------------------------------- +// sound_out +// ---------------------------------------------------------------------------------------- + +class NETLIB_NAME(sound_out) : public netlist::device_t +{ +public: + NETLIB_NAME(sound_out)() + : netlist::device_t() { } + + static const int BUFSIZE = 2048; + + ATTR_COLD void start() + { + register_input("IN", m_in); + register_param("CHAN", m_channel, 0); + register_param("MULT", m_mult, 1000.0); + register_param("OFFSET", m_offset, 0.0); + m_sample = netlist::netlist_time::from_hz(1); //sufficiently big enough + save(NAME(m_last_buffer)); + } + + ATTR_COLD void reset() + { + m_cur = 0.0; + m_last_pos = 0; + m_last_buffer = netlist::netlist_time::zero; + } + + ATTR_HOT void sound_update(const netlist::netlist_time upto) + { + int pos = (upto - m_last_buffer) / m_sample; + if (pos >= BUFSIZE) + netlist().log().fatal("sound {1}: exceeded BUFSIZE\n", name().cstr()); + while (m_last_pos < pos ) + { + m_buffer[m_last_pos++] = (stream_sample_t) m_cur; + } + } + + ATTR_HOT void update() + { + nl_double val = INPANALOG(m_in) * m_mult.Value() + m_offset.Value(); + sound_update(netlist().time()); + /* ignore spikes */ + if (std::abs(val) < 32767.0) + m_cur = val; + else if (val > 0.0) + m_cur = 32767.0; + else + m_cur = -32767.0; + + } + + ATTR_HOT void buffer_reset(netlist::netlist_time upto) + { + m_last_pos = 0; + m_last_buffer = upto; + m_cur = 0.0; + } + + netlist::param_int_t m_channel; + netlist::param_double_t m_mult; + netlist::param_double_t m_offset; + stream_sample_t *m_buffer; + netlist::netlist_time m_sample; + +private: + netlist::analog_input_t m_in; + double m_cur; + int m_last_pos; + netlist::netlist_time m_last_buffer; +}; + +// ---------------------------------------------------------------------------------------- +// sound_in +// ---------------------------------------------------------------------------------------- + +class NETLIB_NAME(sound_in) : public netlist::device_t +{ +public: + NETLIB_NAME(sound_in)() + : netlist::device_t() { } + + static const int MAX_INPUT_CHANNELS = 10; + + ATTR_COLD void start() + { + // clock part + register_output("Q", m_Q); + register_input("FB", m_feedback); + + connect_late(m_feedback, m_Q); + m_inc = netlist::netlist_time::from_nsec(1); + + + for (int i = 0; i < MAX_INPUT_CHANNELS; i++) + { + register_param(pfmt("CHAN{1}")(i), m_param_name[i], ""); + register_param(pfmt("MULT{1}")(i), m_param_mult[i], 1.0); + register_param(pfmt("OFFSET{1}")(i), m_param_offset[i], 0.0); + } + m_num_channel = 0; + } + + ATTR_COLD void reset() + { + m_pos = 0; + for (int i = 0; i < MAX_INPUT_CHANNELS; i++) + m_buffer[i] = NULL; + } + + ATTR_COLD int resolve() + { + m_pos = 0; + for (int i = 0; i < MAX_INPUT_CHANNELS; i++) + { + if (m_param_name[i].Value() != "") + { + if (i != m_num_channel) + netlist().log().fatal("sound input numbering has to be sequential!"); + m_num_channel++; + m_param[i] = dynamic_cast(setup().find_param(m_param_name[i].Value(), true)); + } + } + return m_num_channel; + } + + ATTR_HOT void update() + { + for (int i=0; isetTo(v * m_param_mult[i].Value() + m_param_offset[i].Value()); + } + m_pos++; + OUTLOGIC(m_Q, !m_Q.net().as_logic().new_Q(), m_inc ); + } + + ATTR_HOT void buffer_reset() + { + m_pos = 0; + } + + netlist::param_str_t m_param_name[MAX_INPUT_CHANNELS]; + netlist::param_double_t *m_param[MAX_INPUT_CHANNELS]; + stream_sample_t *m_buffer[MAX_INPUT_CHANNELS]; + netlist::param_double_t m_param_mult[MAX_INPUT_CHANNELS]; + netlist::param_double_t m_param_offset[MAX_INPUT_CHANNELS]; + netlist::netlist_time m_inc; + +private: + netlist::logic_input_t m_feedback; + netlist::logic_output_t m_Q; + + int m_pos; + int m_num_channel; +}; + +// device type definition +extern const device_type NETLIST_CORE; +extern const device_type NETLIST_CPU; +extern const device_type NETLIST_SOUND; +extern const device_type NETLIST_ANALOG_INPUT; +extern const device_type NETLIST_LOGIC_INPUT; + +extern const device_type NETLIST_ANALOG_OUTPUT; +extern const device_type NETLIST_STREAM_INPUT; +extern const device_type NETLIST_STREAM_OUTPUT; + +#endif diff --git a/src/devices/machine/nmc9306.c b/src/devices/machine/nmc9306.c new file mode 100644 index 00000000000..0b23eda21d7 --- /dev/null +++ b/src/devices/machine/nmc9306.c @@ -0,0 +1,322 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + National Semiconductor NMC9306 256-Bit Serial EEPROM emulation + +**********************************************************************/ + +#include "emu.h" +#include "nmc9306.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define LOG 1 + +#define RAM_SIZE 32 + + +// instructions +enum +{ + OTHER = 0, + WRITE, // write register A3A2A1A0 + READ, // read register A3A2A1A0 + ERASE // erase register A3A2A1A0 +}; + +// other instructions +enum +{ + EWDS = 0, // erase/write disable + WRAL, // write all registers + ERAL, // erase all registers + EWEN // erase/write enable +}; + +// states +enum +{ + STATE_IDLE = 0, + STATE_COMMAND, + STATE_ADDRESS, + STATE_DATA_IN, + STATE_DATA_OUT, + STATE_ERASE +}; + + + +//************************************************************************** +// INLINE HELPERS +//************************************************************************** + +// device type definition +const device_type NMC9306 = &device_creator; + +//------------------------------------------------- +// nmc9306_device - constructor +//------------------------------------------------- + +inline UINT16 nmc9306_device::read(offs_t offset) +{ + return m_register[offset]; +} + + +//------------------------------------------------- +// nmc9306_device - constructor +//------------------------------------------------- + +inline void nmc9306_device::write(offs_t offset, UINT16 data) +{ + if (m_ewen) + { + m_register[offset] &= data; + } +} + + +//------------------------------------------------- +// nmc9306_device - constructor +//------------------------------------------------- + +inline void nmc9306_device::erase(offs_t offset) +{ + if (m_ewen) + { + m_register[offset] = 0xffff; + } +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// nmc9306_device - constructor +//------------------------------------------------- + +nmc9306_device::nmc9306_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, NMC9306, "NMC9306", tag, owner, clock, "nmc9306", __FILE__), + device_nvram_interface(mconfig, *this), + m_state(STATE_IDLE), + m_ewen(false) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void nmc9306_device::device_start() +{ + memset(m_register, 0, sizeof(m_register)); + + // state saving + save_item(NAME(m_bits)); + save_item(NAME(m_state)); + save_item(NAME(m_command)); + save_item(NAME(m_address)); + save_item(NAME(m_data)); + save_item(NAME(m_ewen)); + save_item(NAME(m_cs)); + save_item(NAME(m_sk)); + save_item(NAME(m_do)); + save_item(NAME(m_di)); +} + + +//------------------------------------------------- +// nvram_default - called to initialize NVRAM to +// its default state +//------------------------------------------------- + +void nmc9306_device::nvram_default() +{ +} + + +//------------------------------------------------- +// nvram_read - called to read NVRAM from the +// .nv file +//------------------------------------------------- + +void nmc9306_device::nvram_read(emu_file &file) +{ + file.read(m_register, RAM_SIZE); +} + + +//------------------------------------------------- +// nvram_write - called to write NVRAM to the +// .nv file +//------------------------------------------------- + +void nmc9306_device::nvram_write(emu_file &file) +{ + file.write(m_register, RAM_SIZE); +} + + +//------------------------------------------------- +// cs_w - chip select input +//------------------------------------------------- + +WRITE_LINE_MEMBER( nmc9306_device::cs_w ) +{ + m_cs = state; +} + + +//------------------------------------------------- +// ck_w - serial clock input +//------------------------------------------------- + +WRITE_LINE_MEMBER( nmc9306_device::sk_w ) +{ + m_sk = state; + + if (!m_cs || !m_sk) return; + + switch (m_state) + { + case STATE_IDLE: + if (LOG) logerror("NMC9306 '%s' Idle %u\n", tag(), m_di); + + if (m_di) + { + // start bit received + m_state = STATE_COMMAND; + m_bits = 0; + } + break; + + case STATE_COMMAND: + if (LOG) logerror("NMC9306 '%s' Command Bit %u\n", tag(), m_di); + + m_command <<= 1; + m_command |= m_di; + m_bits++; + + if (m_bits == 4) + { + m_state = STATE_ADDRESS; + m_bits = 0; + } + break; + + case STATE_ADDRESS: + if (LOG) logerror("NMC9306 '%s' Address Bit %u\n", tag(), m_di); + + m_address <<= 1; + m_address |= m_di; + m_bits++; + + if (m_bits == 4) + { + switch ((m_command >> 2) & 0x03) + { + case OTHER: + switch (m_command & 0x03) + { + case EWDS: + if (LOG) logerror("NMC9306 '%s' EWDS\n", tag()); + m_ewen = false; + m_state = STATE_IDLE; + break; + + case WRAL: + if (LOG) logerror("NMC9306 '%s' WRAL\n", tag()); + break; + + case ERAL: + if (LOG) logerror("NMC9306 '%s' ERAL\n", tag()); + break; + + case EWEN: + if (LOG) logerror("NMC9306 '%s' EWEN\n", tag()); + m_ewen = true; + m_state = STATE_IDLE; + break; + } + break; + + case WRITE: + if (LOG) logerror("NMC9306 '%s' WRITE %u\n", tag(), m_address & 0x0f); + m_state = STATE_DATA_IN; + break; + + case READ: + if (LOG) logerror("NMC9306 '%s' READ %u\n", tag(), m_address & 0x0f); + m_data = read(m_address & 0x0f); + m_state = STATE_DATA_OUT; + break; + + case ERASE: + if (LOG) logerror("NMC9306 '%s' ERASE %u\n", tag(), m_address & 0x0f); + erase(m_address & 0x0f); + m_state = STATE_ERASE; + break; + } + + m_bits = 0; + } + break; + + case STATE_DATA_IN: + if (LOG) logerror("NMC9306 '%s' Data Bit IN %u\n", tag(), m_di); + + m_data <<= 1; + m_data |= m_di; + m_bits++; + + if (m_bits == 16) + { + write(m_address & 0x0f, m_data); + + m_state = STATE_IDLE; + } + break; + + case STATE_DATA_OUT: + if (LOG) logerror("NMC9306 '%s' Data Bit OUT %u\n", tag(), m_di); + + m_do = BIT(m_data, 15); + m_data <<= 1; + m_bits++; + + if (m_bits == 16) + { + m_state = STATE_IDLE; + } + break; + } +} + + +//------------------------------------------------- +// di_w - serial data input +//------------------------------------------------- + +WRITE_LINE_MEMBER( nmc9306_device::di_w ) +{ + m_di = state; +} + + +//------------------------------------------------- +// do_r - serial data output +//------------------------------------------------- + +READ_LINE_MEMBER( nmc9306_device::do_r ) +{ + return m_do; +} diff --git a/src/devices/machine/nmc9306.h b/src/devices/machine/nmc9306.h new file mode 100644 index 00000000000..95db0133025 --- /dev/null +++ b/src/devices/machine/nmc9306.h @@ -0,0 +1,93 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + National Semiconductor NMC9306 256-Bit Serial EEPROM emulation + +********************************************************************** + _____ _____ + CS 1 |* \_/ | 8 Vcc + SK 2 | | 7 NC + DI 3 | | 6 NC + DO 4 |_____________| 5 GND + +**********************************************************************/ + +#pragma once + +#ifndef __NMC9306__ +#define __NMC9306__ + +#include "emu.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_NMC9306_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, NMC9306, 0) + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + + +// ======================> nmc9306_device + +class nmc9306_device : public device_t, + public device_nvram_interface +{ +public: + // construction/destruction + nmc9306_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + DECLARE_WRITE_LINE_MEMBER( cs_w ); + DECLARE_WRITE_LINE_MEMBER( sk_w ); + DECLARE_WRITE_LINE_MEMBER( di_w ); + DECLARE_READ_LINE_MEMBER( do_r ); + +protected: + // device-level overrides + virtual void device_start(); + + // device_nvram_interface overrides + virtual void nvram_default(); + virtual void nvram_read(emu_file &file); + virtual void nvram_write(emu_file &file); + +private: + inline UINT16 read(offs_t offset); + inline void write(offs_t offset, UINT16 data); + inline void erase(offs_t offset); + + UINT16 m_register[16]; + + int m_bits; + int m_state; + UINT8 m_command; + UINT8 m_address; + UINT16 m_data; + bool m_ewen; + int m_cs; + int m_sk; + int m_do; + int m_di; +}; + + +// device type definition +extern const device_type NMC9306; + + +#endif diff --git a/src/devices/machine/nsc810.c b/src/devices/machine/nsc810.c new file mode 100644 index 00000000000..51aec5cf654 --- /dev/null +++ b/src/devices/machine/nsc810.c @@ -0,0 +1,312 @@ +// license:BSD-3-Clause +// copyright-holders:Barry Rodewald +/* + * nsc810.c + * + * Created on: 10/03/2014 + * + * TODO: + * - 128 byte RAM + * - other timer modes (only mode 1 - event counter - is implemented currently) + * - port bit set/clear + * - and lots of other stuff + */ + +#include "nsc810.h" + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +#define LOG (1) + +const device_type NSC810 = &device_creator; + +nsc810_device::nsc810_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, NSC810, "National Semiconductor NSC810", tag, owner, clock, "nsc810", __FILE__), + m_portA_r(*this), + m_portB_r(*this), + m_portC_r(*this), + m_portA_w(*this), + m_portB_w(*this), + m_portC_w(*this), + m_timer0_out(*this), + m_timer1_out(*this) +{ +} + +void nsc810_device::device_start() +{ + m_portA_r.resolve_safe(0); + m_portB_r.resolve_safe(0); + m_portC_r.resolve_safe(0); + m_portA_w.resolve_safe(); + m_portB_w.resolve_safe(); + m_portC_w.resolve_safe(); + m_timer0_out.resolve_safe(); + m_timer1_out.resolve_safe(); + + m_portA_w(0); + m_portB_w(0); + m_portC_w(0); + m_timer0_out(0); + m_timer1_out(0); + + m_timer0 = timer_alloc(TIMER0_CLOCK); + m_timer1 = timer_alloc(TIMER1_CLOCK); +} + +void nsc810_device::device_reset() +{ + m_portA_latch = 0; + m_portB_latch = 0; + m_portC_latch = 0; + m_ddrA = 0; + m_ddrB = 0; + m_ddrC = 0; + m_mode = 0; + m_timer0_mode = 0; + m_timer1_mode = 0; + m_timer0_counter = 0; + m_timer1_counter = 0; + m_timer0_running = false; + m_timer1_running = false; + m_ramselect = false; +} + +void nsc810_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch(id) + { + case TIMER0_CLOCK: + m_timer0_counter--; + if((m_timer0_mode & 0x07) == 0x01 || (m_timer0_mode & 0x07) == 0x02) + { + if(m_timer0_counter == 0) + { + m_timer0_out(ASSERT_LINE); + m_timer0_counter = m_timer0_base; + if(LOG) logerror("NSC810 '%s': Timer 0 output set\n",tag()); + } + } + break; + case TIMER1_CLOCK: + m_timer1_counter--; + if((m_timer1_mode & 0x07) == 0x01 || (m_timer1_mode & 0x07) == 0x02) + { + if(m_timer1_counter == 0) + { + m_timer1_out(ASSERT_LINE); + m_timer1_counter = m_timer1_base; + if(LOG) logerror("NSC810 '%s': Timer 1 output set\n",tag()); + } + } + break; + } +} + +READ8_MEMBER(nsc810_device::read) +{ + UINT8 res = 0xff; + + if(m_ramselect) + { + // TODO: 128 byte RAM access + } + else + { + // Register access + switch(offset & 0x1f) + { + case REG_PORTA: + res = m_portA_latch &= m_ddrA; + res |= (m_portA_r() & ~m_ddrA); + //if(LOG) logerror("NSC810 '%s': Port A data read %02x\n",tag(),res); + break; + case REG_PORTB: + res = m_portB_latch &= m_ddrB; + res |= (m_portB_r() & ~m_ddrB); + //if(LOG) logerror("NSC810 '%s': Port B data read %02x\n",tag(),res); + break; + case REG_PORTC: + res = m_portC_latch &= m_ddrC; + res |= (m_portC_r() & ~m_ddrC); + //if(LOG) logerror("NSC810 '%s': Port C data read %02x\n",tag(),res); + break; + case REG_MODE_TIMER0: + res = m_timer0_mode; + break; + case REG_MODE_TIMER1: + res = m_timer1_mode; + break; + case REG_TIMER0_LOW: + res = m_timer0_counter & 0xff; + if((m_timer0_mode & 0x07) == 0x01 || (m_timer0_mode & 0x07) == 0x02) + { + m_timer0_out(CLEAR_LINE); + if(LOG) logerror("NSC810 '%s': Timer 0 output reset\n",tag()); + } + break; + case REG_TIMER0_HIGH: + res = m_timer0_counter >> 8; + if((m_timer0_mode & 0x07) == 0x01 || (m_timer0_mode & 0x07) == 0x02) + { + m_timer0_out(CLEAR_LINE); + if(LOG) logerror("NSC810 '%s': Timer 0 output reset\n",tag()); + } + break; + case REG_TIMER1_LOW: + res = m_timer1_counter & 0xff; + if((m_timer1_mode & 0x07) == 0x01 || (m_timer1_mode & 0x07) == 0x02) + { + m_timer1_out(0); + if(LOG) logerror("NSC810 '%s': Timer 1 output reset\n",tag()); + } + break; + case REG_TIMER1_HIGH: + res = m_timer1_counter >> 8; + if((m_timer1_mode & 0x07) == 0x01 || (m_timer1_mode & 0x07) == 0x02) + { + m_timer1_out(0); + if(LOG) logerror("NSC810 '%s': Timer 1 output reset\n",tag()); + } + break; + default: + if(LOG) logerror("NSC810 '%s': unused port %02x read\n",tag(),offset); + } + } + return res; +} + +WRITE8_MEMBER(nsc810_device::write) +{ + UINT32 rate; + + if(m_ramselect) + { + // TODO: 128 byte RAM access + } + else + { + // Register access + switch(offset & 0x1f) + { + case REG_PORTA: + m_portA_latch = data & ~m_ddrA; + m_portA_w((0xff & ~m_ddrA) | (data & m_ddrA)); + if(LOG) logerror("NSC810 '%s': Port A data write %02x\n",tag(),data); + break; + case REG_PORTB: + m_portB_latch = data & ~m_ddrB; + m_portB_w((0xff & ~m_ddrB) | (data & m_ddrB)); + if(LOG) logerror("NSC810 '%s': Port B data write %02x\n",tag(),data); + break; + case REG_PORTC: + m_portC_latch = data & ~m_ddrC; + m_portC_w((0xff & ~m_ddrC) | (data & m_ddrC)); + if(LOG) logerror("NSC810 '%s': Port C data write %02x\n",tag(),data); + break; + case REG_DDRA: + m_ddrA = data; + if(LOG) logerror("NSC810 '%s': Port A direction write %02x\n",tag(),data); + break; + case REG_DDRB: + m_ddrB = data; + if(LOG) logerror("NSC810 '%s': Port B direction write %02x\n",tag(),data); + break; + case REG_DDRC: + m_ddrC = data; + if(LOG) logerror("NSC810 '%s': Port C direction write %02x\n",tag(),data); + break; + case REG_MODE_DEF: + if(LOG) logerror("NSC810 '%s': Mode Definition write %02x\n",tag(),data); + break; + case REG_PORTA_BITCLR: + if(LOG) logerror("NSC810 '%s': Port A bit-clear write %02x\n",tag(),data); + break; + case REG_PORTB_BITCLR: + if(LOG) logerror("NSC810 '%s': Port B bit-clear write %02x\n",tag(),data); + break; + case REG_PORTC_BITCLR: + if(LOG) logerror("NSC810 '%s': Port C bit-clear write %02x\n",tag(),data); + break; + case REG_PORTA_BITSET: + if(LOG) logerror("NSC810 '%s': Port A bit-set write %02x\n",tag(),data); + break; + case REG_PORTB_BITSET: + if(LOG) logerror("NSC810 '%s': Port B bit-set write %02x\n",tag(),data); + break; + case REG_PORTC_BITSET: + if(LOG) logerror("NSC810 '%s': Port C bit-set write %02x\n",tag(),data); + break; + case REG_TIMER0_LOW: + m_timer0_base = (m_timer0_base & 0xff00) | data; + m_timer0_counter = (m_timer0_counter & 0xff00) | data; + if(LOG) logerror("NSC810 '%s': Timer 0 low-byte write %02x (base=%04x)\n",tag(),data,m_timer0_base); + break; + case REG_TIMER0_HIGH: + m_timer0_base = (m_timer0_base & 0x00ff) | (data << 8); + m_timer0_counter = (m_timer0_counter & 0x00ff) | (data << 8); + if(LOG) logerror("NSC810 '%s': Timer 0 high-byte write %02x (base=%04x)\n",tag(),data,m_timer0_base); + break; + case REG_TIMER1_LOW: + m_timer1_base = (m_timer1_base & 0xff00) | data; + m_timer1_counter = (m_timer1_counter & 0xff00) | data; + if(LOG) logerror("NSC810 '%s': Timer 1 low-byte write %02x (base=%04x)\n",tag(),data,m_timer1_base); + break; + case REG_TIMER1_HIGH: + m_timer1_base = (m_timer1_base & 0x00ff) | (data << 8); + m_timer1_counter = (m_timer1_counter & 0x00ff) | (data << 8); + if(LOG) logerror("NSC810 '%s': Timer 1 high-byte write %02x (base=%04x)\n",tag(),data,m_timer1_base); + break; + case REG_TIMER0_STOP: + m_timer0_running = false; + m_timer0->reset(); + if(LOG) logerror("NSC810 '%s': Timer 0 Stop write %02x\n",tag(),data); + break; + case REG_TIMER0_START: + if((m_timer0_mode & 0x07) != 0x00 && (m_timer0_mode & 0x07) != 0x07) + { + m_timer0_running = true; + if(m_timer0_mode & 0x10) + rate = m_timer0_clock / 64; + else + if(m_timer0_mode & 0x08) + rate = m_timer0_clock / 2; + else + rate = m_timer0_clock; + m_timer0->adjust(attotime::zero,0,attotime::from_hz(rate)); + } + if(LOG) logerror("NSC810 '%s': Timer 0 Start write %02x\n",tag(),data); + break; + case REG_TIMER1_STOP: + m_timer1_running = false; + m_timer1->reset(); + if(LOG) logerror("NSC810 '%s': Timer 1 Stop write %02x\n",tag(),data); + break; + case REG_TIMER1_START: + if((m_timer1_mode & 0x07) != 0x00 && (m_timer1_mode & 0x07) != 0x07) + { + m_timer1_running = true; + // no /64 prescaler on timer 1 + if(m_timer0_mode & 0x08) + rate = m_timer0_clock / 2; + else + rate = m_timer0_clock; + m_timer1->adjust(attotime::zero,0,attotime::from_hz(rate)); + } + if(LOG) logerror("NSC810 '%s': Timer 1 Start write %02x\n",tag(),data); + break; + case REG_MODE_TIMER0: + m_timer0_mode = data; + if(LOG) logerror("NSC810 '%s': Timer 0 Mode write %02x\n",tag(),data); + break; + case REG_MODE_TIMER1: + m_timer1_mode = data; + if(LOG) logerror("NSC810 '%s': Timer 1 Mode write %02x\n",tag(),data); + break; + default: + logerror("NSC810 '%s': Unused register %02x write %02x\n",tag(),offset,data); + } + } +} diff --git a/src/devices/machine/nsc810.h b/src/devices/machine/nsc810.h new file mode 100644 index 00000000000..f7aea895f0b --- /dev/null +++ b/src/devices/machine/nsc810.h @@ -0,0 +1,135 @@ +// license:BSD-3-Clause +// copyright-holders:Barry Rodewald +/* + * nsc810.h + * + * Created on: 10/03/2014 + */ + +#ifndef NSC810_H_ +#define NSC810_H_ + +#include "emu.h" + +class nsc810_device : public device_t +{ +public: + // construction/destruction + nsc810_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + template static devcb_base &set_portA_read_callback(device_t &device, _Object object) { return downcast(device).m_portA_r.set_callback(object); } + template static devcb_base &set_portB_read_callback(device_t &device, _Object object) { return downcast(device).m_portB_r.set_callback(object); } + template static devcb_base &set_portC_read_callback(device_t &device, _Object object) { return downcast(device).m_portC_r.set_callback(object); } + template static devcb_base &set_portA_write_callback(device_t &device, _Object object) { return downcast(device).m_portA_w.set_callback(object); } + template static devcb_base &set_portB_write_callback(device_t &device, _Object object) { return downcast(device).m_portB_w.set_callback(object); } + template static devcb_base &set_portC_write_callback(device_t &device, _Object object) { return downcast(device).m_portC_w.set_callback(object); } + template static devcb_base &set_timer0_callback(device_t &device, _Object object) { return downcast(device).m_timer0_out.set_callback(object); } + template static devcb_base &set_timer1_callback(device_t &device, _Object object) { return downcast(device).m_timer1_out.set_callback(object); } + + void set_timer0_clock(UINT32 clk) { m_timer0_clock = clk; } + void set_timer1_clock(UINT32 clk) { m_timer1_clock = clk; } + + DECLARE_READ8_MEMBER(read); + DECLARE_WRITE8_MEMBER(write); + +protected: + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + +private: + UINT8 m_portA_latch; + UINT8 m_portB_latch; + UINT8 m_portC_latch; + UINT8 m_ddrA; + UINT8 m_ddrB; + UINT8 m_ddrC; + UINT8 m_mode; + emu_timer* m_timer0; + emu_timer* m_timer1; + UINT8 m_timer0_mode; + UINT8 m_timer1_mode; + UINT16 m_timer0_counter; + UINT16 m_timer1_counter; + UINT16 m_timer0_base; + UINT16 m_timer1_base; + bool m_timer0_running; + bool m_timer1_running; + UINT32 m_timer0_clock; + UINT32 m_timer1_clock; + bool m_ramselect; + + devcb_read8 m_portA_r; + devcb_read8 m_portB_r; + devcb_read8 m_portC_r; + devcb_write8 m_portA_w; + devcb_write8 m_portB_w; + devcb_write8 m_portC_w; + devcb_write_line m_timer0_out; + devcb_write_line m_timer1_out; + + static const device_timer_id TIMER0_CLOCK = 0; + static const device_timer_id TIMER1_CLOCK = 1; + + enum + { + REG_PORTA = 0x00, + REG_PORTB, + REG_PORTC, + REG_DDRA = 0x04, + REG_DDRB, + REG_DDRC, + REG_MODE_DEF, + REG_PORTA_BITCLR, + REG_PORTB_BITCLR, + REG_PORTC_BITCLR, + REG_PORTA_BITSET = 0x0c, + REG_PORTB_BITSET, + REG_PORTC_BITSET, + REG_TIMER0_LOW = 0x10, + REG_TIMER0_HIGH, + REG_TIMER1_LOW, + REG_TIMER1_HIGH, + REG_TIMER0_STOP, + REG_TIMER0_START, + REG_TIMER1_STOP, + REG_TIMER1_START, + REG_MODE_TIMER0, + REG_MODE_TIMER1 + }; +}; + +#define MCFG_NSC810_ADD(_tag, _t0clk, _t1clk) \ + MCFG_DEVICE_ADD(_tag, NSC810, 0) \ + downcast(device)->set_timer0_clock(_t0clk); \ + downcast(device)->set_timer1_clock(_t1clk); + +#define MCFG_NSC810_PORTA_READ(_read) \ + devcb = &nsc810_device::set_portA_read_callback(*device, DEVCB_##_read); + +#define MCFG_NSC810_PORTB_READ(_read) \ + devcb = &nsc810_device::set_portB_read_callback(*device, DEVCB_##_read); + +#define MCFG_NSC810_PORTC_READ(_read) \ + devcb = &nsc810_device::set_portC_read_callback(*device, DEVCB_##_read); + +#define MCFG_NSC810_PORTA_WRITE(_write) \ + devcb = &nsc810_device::set_portA_write_callback(*device, DEVCB_##_write); + +#define MCFG_NSC810_PORTB_WRITE(_write) \ + devcb = &nsc810_device::set_portB_write_callback(*device, DEVCB_##_write); + +#define MCFG_NSC810_PORTC_WRITE(_write) \ + devcb = &nsc810_device::set_portC_write_callback(*device, DEVCB_##_write); + +#define MCFG_NSC810_TIMER0_OUT(_write) \ + devcb = &nsc810_device::set_timer0_callback(*device, DEVCB_##_write); + +#define MCFG_NSC810_TIMER1_OUT(_write) \ + devcb = &nsc810_device::set_timer1_callback(*device, DEVCB_##_write); + +// device type definition +extern const device_type NSC810; + + +#endif /* NSC810_H_ */ diff --git a/src/devices/machine/nscsi_bus.c b/src/devices/machine/nscsi_bus.c new file mode 100644 index 00000000000..182fe98e0aa --- /dev/null +++ b/src/devices/machine/nscsi_bus.c @@ -0,0 +1,741 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +#include "nscsi_bus.h" + +const device_type NSCSI_BUS = &device_creator; +const device_type NSCSI_CONNECTOR = &device_creator; + +nscsi_bus_device::nscsi_bus_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, NSCSI_BUS, "NSCSI Bus", tag, owner, clock, "nscsi_bus", __FILE__) +{ + devcnt = 0; + memset(dev, 0, sizeof(dev)); +} + +void nscsi_bus_device::device_start() +{ + data = 0; + ctrl = 0; + save_item(NAME(data)); + save_item(NAME(ctrl)); + for(int i=0; iscsi_ctrl_changed(); +} + +UINT32 nscsi_bus_device::data_r() const +{ + return data; +} + +UINT32 nscsi_bus_device::ctrl_r() const +{ + return ctrl; +} + +void nscsi_bus_device::ctrl_w(int refid, UINT32 lines, UINT32 mask) +{ + UINT32 c = dev[refid].ctrl; + dev[refid].ctrl = (c & ~mask) | (lines & mask); + regen_ctrl(refid); +} + +void nscsi_bus_device::data_w(int refid, UINT32 lines) +{ + dev[refid].data = lines; + regen_data(); +} + +void nscsi_bus_device::ctrl_wait(int refid, UINT32 lines, UINT32 mask) +{ + UINT32 w = dev[refid].wait_ctrl; + dev[refid].wait_ctrl = (w & ~mask) | (lines & mask); +} + +void nscsi_bus_device::device_config_complete() +{ + char id[3]; + for(int i=0; i<16; i++) { + sprintf(id, "%d", i); + nscsi_connector *conn = downcast(subdevice(id)); + if(conn) { + nscsi_device *sdev = conn->get_device(); + if(sdev) { + int rid = devcnt++; + dev[rid].dev = sdev; + sdev->connect_to_bus(this, rid, i); + } + } + } +} + + +nscsi_connector::nscsi_connector(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, NSCSI_CONNECTOR, "NSCSI Connector Abstraction", tag, owner, clock, "nscsi_connector", __FILE__), + device_slot_interface(mconfig, *this) +{ +} + +nscsi_connector::~nscsi_connector() +{ +} + +void nscsi_connector::device_start() +{ +} + +nscsi_device *nscsi_connector::get_device() +{ + return dynamic_cast(get_card_device()); +} + +nscsi_device::nscsi_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_slot_card_interface(mconfig, *this) +{ + scsi_id = scsi_refid = -1; + scsi_bus = 0; +} + +void nscsi_device::connect_to_bus(nscsi_bus_device *bus, int refid, int default_scsi_id) +{ + scsi_bus = bus; + scsi_refid = refid; + scsi_id = default_scsi_id; +} + +void nscsi_device::scsi_ctrl_changed() +{ +} + +void nscsi_device::device_start() +{ + save_item(NAME(scsi_id)); +} + +nscsi_full_device::nscsi_full_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + nscsi_device(mconfig, type, name, tag, owner, clock, shortname, source) +{ +} + + +const char *const nscsi_full_device::command_names[256] = { + /* 00 */ "TEST_UNIT_READY", "REZERO", "?", "REQUEST_SENSE", "FORMAT_UNIT", "?", "?", "REASSIGN_BLOCKS", + /* 08 */ "READ_6/RECIEVE", "?", "WRITE_6/SEND", "SEEK", "?", "?", "?", "?", + /* 10 */ "?", "?", "INQUIRY", "?", "?", "MODE_SELECT_6", "RESERVE_6", "RELEASE_6", + /* 18 */ "?", "?", "MODE_SENSE_6", "START_STOP_UNIT", "RECIEVE_DIAG_RES", "SEND_DIAGNOSTICS", "PREVENT_ALLOW_MEDIUM_REMOVAL", "?", + /* 20 */ "?", "?", "?", "READ_FORMAT_CAPACITIES", "?", "READ_CAPACITY", "?", "?", + + /* 28 */ "READ_10", "READ_GENERATION", "WRITE_10", "SEEK_10", "ERASE_10", "READ_UPDATED_BLOCK_10", "WRITE_VERIFY", "VERIFY", + /* 30 */ "SEARCH_DATA_HIGH_10", "SEARCH_DATA_EQUAL_10", "SEARCH_DATA_LOW_10", "SET_LIMITS_10", "PREFETCH", "SYNC_CACHE", "LOCK_UNLOCK_CACHE", "READ_DEFECT_DATA", + /* 38 */ "MEDIUM_SCAN", "COMPARE", "COPY_AND_VERIFY", "WRITE_BUFFER", "READ_DATA_BUFFER", "UPDATE_BLOCK", "READ_LONG", "WRITE_LONG", + /* 40 */ "CHANGE_DEFINITION", "WRITE_SAME", "READ_SUB_CHANNEL", "READ_TOC_PMA_ATIP", "READ_HEADER", "PLAY_AUDIO_10", "GET_CONFIGURATION", "PLAY_AUDIO_MSF", + /* 48 */ "PLAY_AUDIO_TRACK_INDEX", "PLAY_RELATIVE_10", "GET_EVENT_STATUS_NOTIFICATION", "PAUSE_RESUME", "LOG_SELECT", "LOG_SENSE", "STOP_PLAY_SCAN", "?", + /* 50 */ "XDWRITE", "READ_DISC_INFORMATION/XPWRITE", "READ_TRACK_INFORMATION/XDREAD", "RESERVE_TRACK", "SEND_OPC_INFORMATION", "MODE_SELECT_10", "RESERVE_10", "RELEASE_10", + /* 58 */ "REPAIR_TRACK", "READ_MASTER_CUE", "MODE_SENSE_10", "CLOSE_TRACK_SESSION", "READ_BUFFER_CAPACITY", "SEND_CUE_SHEET", "PERSISTENT_RESERVE_IN", "PERSISTENT_RESERVE_OUT", + /* 80 */ "XDWRITE_EXTENDED", "REBUILD", "REGENERATE", "EXTENDED_COPY", "RECEIVE_COPY_RESULTS", "?", "?", "?", + /* 88 */ "?", "?", "?", "?", "?", "?", "?", "?", + /* 90 */ "?", "?", "?", "?", "?", "?", "?", "?", + /* 98 */ "?", "?", "?", "?", "?", "?", "?", "?", + /* a0 */ "REPORT_LUNS", "BLANK", "SEND_EVENT", "REPORT_DEVICE_IDENTIFIER/SEND_KEY", "SET_DEVICE_IDENTIFIER/REPORT_KEY", "PLAY_AUDIO_12", "LOAD_UNLOAD_MEDIUM", "MOVE_MEDIUM_ATTACHED/SET_READ_AHEAD", + /* a8 */ "READ_12", "PLAY_RELATIVE_12", "WRITE_12", "?", "ERASE_12/GET_PERFORMANCE", "READ_DVD_STRUCTURE", "WRITE_AND_VERIFY_12", "VERIFY_12", + /* b0 */ "SEARCH_DATA_HIGH_12", "SEARCH_DATA_EQUAL_12", "SEARCH_DATA_LOW_12", "SET_LIMITS_12", "READ_ELEMENT_STATUS_ATTACHED", "?", "SET_STREAMING", "READ_DEFECT_DATA_12", + /* b8 */ "?", "READ_CD_MSF", "SCAN_MMC", "SET_CD_SPEED", "PLAY_CD", "MECHANISM_STATUS", "READ_CD", "SEND_DVD_STRUCTURE", + /* c0 */ "?", "?", "?", "?", "?", "?", "?", "?", + /* c8 */ "?", "?", "?", "?", "?", "?", "?", "?", + /* d0 */ "?", "?", "?", "?", "?", "?", "?", "?", + /* d8 */ "?", "?", "?", "?", "?", "?", "?", "?", + /* e0 */ "?", "?", "?", "?", "?", "?", "?", "?", + /* e8 */ "?", "?", "?", "?", "?", "?", "?", "?", + /* f0 */ "?", "?", "?", "?", "?", "?", "?", "?", + /* f8 */ "?", "?", "?", "?", "?", "?", "?", "?", +}; + +void nscsi_full_device::device_start() +{ + nscsi_device::device_start(); + scsi_timer = timer_alloc(SCSI_TIMER); + save_item(NAME(scsi_cmdbuf)); + save_item(NAME(scsi_sense_buffer)); + save_item(NAME(scsi_cmdsize)); + save_item(NAME(scsi_identify)); + save_item(NAME(scsi_state)); + save_item(NAME(scsi_substate)); + save_item(NAME(scsi_initiator_id)); + save_item(NAME(data_buffer_id)); + save_item(NAME(data_buffer_size)); + save_item(NAME(data_buffer_pos)); + save_item(NAME(buf_control_rpos)); + save_item(NAME(buf_control_wpos)); + for(int i=0; i<32; i++) { + save_item(NAME(buf_control[i].action), i); + save_item(NAME(buf_control[i].param1), i); + save_item(NAME(buf_control[i].param2), i); + } +} + +void nscsi_full_device::device_reset() +{ + scsi_state = scsi_substate = IDLE; + buf_control_rpos = buf_control_wpos = 0; + scsi_identify = 0; + scsi_bus->data_w(scsi_refid, 0); + scsi_bus->ctrl_w(scsi_refid, 0, S_ALL); + scsi_bus->ctrl_wait(scsi_refid, S_SEL|S_BSY|S_RST, S_ALL); +} + +void nscsi_full_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + if(id != SCSI_TIMER) + return; + + step(true); + +} + +void nscsi_full_device::scsi_ctrl_changed() +{ + step(false); +} + +void nscsi_full_device::step(bool timeout) +{ + UINT32 ctrl = scsi_bus->ctrl_r(); + UINT32 data = scsi_bus->data_r(); + if(ctrl & S_RST) { + scsi_bus->data_w(scsi_refid, 0); + scsi_bus->ctrl_w(scsi_refid, 0, S_ALL); + scsi_state = IDLE; + logerror("%s: scsi bus reset\n", tag()); + return; + } + + if(0) + logerror("%s: state=%d.%d %s\n", + tag(), scsi_state & STATE_MASK, (scsi_state & SUB_MASK) >> SUB_SHIFT, + timeout ? "timeout" : "change"); + + switch(scsi_state & SUB_MASK ? scsi_state & SUB_MASK : scsi_state & STATE_MASK) { + case IDLE: + if(((ctrl & (S_SEL|S_BSY)) == S_SEL) && (scsi_id != -1) && ((data & (1 << scsi_id)) != 0)) { + for(scsi_initiator_id = 0; scsi_initiator_id != 16 && (scsi_initiator_id == scsi_id || (data & (1 << scsi_initiator_id))); scsi_initiator_id++); + if(scsi_initiator_id == 16) + scsi_initiator_id = -1; + scsi_state = TARGET_SELECT_WAIT_BUS_SETTLE; + scsi_timer->adjust(scsi_bus_settle_delay()); + } + break; + + case TARGET_SELECT_WAIT_BUS_SETTLE: + if((ctrl & (S_SEL|S_BSY)) == S_SEL) { + scsi_state = TARGET_SELECT_WAIT_SEL_0; + scsi_bus->ctrl_w(scsi_refid, S_BSY, S_BSY); + } else + scsi_state = IDLE; + break; + + case TARGET_SELECT_WAIT_SEL_0: + if(ctrl & S_SEL) + break; + buf_control_push()->action = BC_MSG_OR_COMMAND; + scsi_state = TARGET_NEXT_CONTROL; + step(false); + break; + + case RECV_BYTE_T_WAIT_ACK_1 << SUB_SHIFT: + if(ctrl & S_ACK) { + scsi_put_data(data_buffer_id, data_buffer_pos++, scsi_bus->data_r()); + scsi_state = (scsi_state & STATE_MASK) | (RECV_BYTE_T_WAIT_ACK_0 << SUB_SHIFT); + scsi_bus->ctrl_w(scsi_refid, 0, S_REQ); + } + break; + + case RECV_BYTE_T_WAIT_ACK_0 << SUB_SHIFT: + if(!(ctrl & S_ACK)) { + scsi_state &= STATE_MASK; + scsi_bus->ctrl_wait(scsi_refid, 0, S_ACK); + step(false); + } + break; + + case SEND_BYTE_T_WAIT_ACK_1 << SUB_SHIFT: + if(ctrl & S_ACK) { + scsi_state = (scsi_state & STATE_MASK) | (SEND_BYTE_T_WAIT_ACK_0 << SUB_SHIFT); + scsi_bus->data_w(scsi_refid, 0); + scsi_bus->ctrl_w(scsi_refid, 0, S_REQ); + } + break; + + case SEND_BYTE_T_WAIT_ACK_0 << SUB_SHIFT: + if(!(ctrl & S_ACK)) { + scsi_state &= STATE_MASK; + scsi_bus->ctrl_wait(scsi_refid, 0, S_ACK); + step(false); + } + break; + + case TARGET_NEXT_CONTROL: { + control *ctl = buf_control_pop(); + switch(ctl->action) { + case BC_MSG_OR_COMMAND: + data_buffer_id = SBUF_MAIN; + data_buffer_pos = 0; + if(ctrl & S_ATN) { + scsi_state = TARGET_WAIT_MSG_BYTE; + scsi_bus->ctrl_w(scsi_refid, S_PHASE_MSG_OUT, S_PHASE_MASK); + } else { + scsi_state = TARGET_WAIT_CMD_BYTE; + scsi_bus->ctrl_w(scsi_refid, S_PHASE_COMMAND, S_PHASE_MASK); + } + target_recv_byte(); + break; + + case BC_STATUS: + scsi_bus->ctrl_w(scsi_refid, S_PHASE_STATUS, S_PHASE_MASK); + target_send_byte(ctl->param1); + break; + + case BC_DATA_IN: + scsi_bus->ctrl_w(scsi_refid, S_PHASE_DATA_IN, S_PHASE_MASK); + data_buffer_id = ctl->param1; + data_buffer_size = ctl->param2; + data_buffer_pos = 0; + scsi_state = TARGET_WAIT_DATA_IN_BYTE; + target_send_buffer_byte(); + break; + + case BC_DATA_OUT: + scsi_bus->ctrl_w(scsi_refid, S_PHASE_DATA_OUT, S_PHASE_MASK); + data_buffer_id = ctl->param1; + data_buffer_size = ctl->param2; + data_buffer_pos = 0; + scsi_state = TARGET_WAIT_DATA_OUT_BYTE; + target_recv_byte(); + break; + + case BC_MESSAGE_1: + scsi_bus->ctrl_w(scsi_refid, S_PHASE_MSG_IN, S_PHASE_MASK); + target_send_byte(ctl->param1); + break; + + case BC_BUS_FREE: + scsi_bus->data_w(scsi_refid, 0); + scsi_bus->ctrl_wait(scsi_refid, S_BSY|S_SEL|S_RST, S_ALL); + scsi_bus->ctrl_w(scsi_refid, 0, S_ALL); + scsi_state = IDLE; + break; + }; + break; + } + + case TARGET_WAIT_DATA_IN_BYTE: + if(data_buffer_pos == data_buffer_size-1) + scsi_state = TARGET_NEXT_CONTROL; + target_send_buffer_byte(); + break; + + case TARGET_WAIT_DATA_OUT_BYTE: + if(data_buffer_pos == data_buffer_size-1) + scsi_state = TARGET_NEXT_CONTROL; + target_recv_byte(); + break; + + case TARGET_WAIT_MSG_BYTE: + if(ctrl & S_SEL) + return; + if(!(ctrl & S_ATN)) { + scsi_cmdsize = data_buffer_pos; + scsi_message(); + data_buffer_id = SBUF_MAIN; + data_buffer_pos = 0; + scsi_state = TARGET_WAIT_CMD_BYTE; + scsi_bus->ctrl_w(scsi_refid, S_PHASE_COMMAND, S_PHASE_MASK); + } + target_recv_byte(); + break; + + case TARGET_WAIT_CMD_BYTE: + if(ctrl & S_SEL) + return; + if(ctrl & S_ATN) { + logerror("%s: Parity error? Say what?\n", tag()); + scsi_state = IDLE; + break; + } + + if(command_done()) { + scsi_cmdsize = data_buffer_pos; + scsi_bus->ctrl_wait(scsi_refid, 0, S_ACK); + scsi_command(); + scsi_state = TARGET_NEXT_CONTROL; + step(false); + } else + target_recv_byte(); + break; + + default: + logerror("%s: step() unexpected state %d.%d\n", + tag(), + scsi_state & STATE_MASK, (scsi_state & SUB_MASK) >> SUB_SHIFT); + exit(0); + } +} + +void nscsi_full_device::target_recv_byte() +{ + scsi_bus->ctrl_wait(scsi_refid, S_ACK, S_ACK); + scsi_state = (scsi_state & STATE_MASK) | (RECV_BYTE_T_WAIT_ACK_1 << SUB_SHIFT); + scsi_bus->ctrl_w(scsi_refid, S_REQ, S_REQ); + step(false); +} + +void nscsi_full_device::target_send_byte(UINT8 val) +{ + scsi_bus->ctrl_wait(scsi_refid, S_ACK, S_ACK); + scsi_state = (scsi_state & STATE_MASK) | (SEND_BYTE_T_WAIT_ACK_1 << SUB_SHIFT); + scsi_bus->data_w(scsi_refid, val); + scsi_bus->ctrl_w(scsi_refid, S_REQ, S_REQ); + step(false); +} + +UINT8 nscsi_full_device::scsi_get_data(int id, int pos) +{ + switch(id) { + case SBUF_MAIN: + return scsi_cmdbuf[pos]; + case SBUF_SENSE: + return scsi_sense_buffer[pos]; + default: + fatalerror("nscsi_full_device::scsi_get_data - unknown id\n"); + } +} + +void nscsi_full_device::scsi_put_data(int id, int pos, UINT8 data) +{ + switch(id) { + case SBUF_MAIN: + scsi_cmdbuf[pos] = data; + break; + case SBUF_SENSE: + scsi_sense_buffer[pos] = data; + break; + default: + fatalerror("nscsi_full_device::scsi_put_data - unknown id\n"); + } +} + +void nscsi_full_device::target_send_buffer_byte() +{ + target_send_byte(scsi_get_data(data_buffer_id, data_buffer_pos++)); +} + +bool nscsi_full_device::command_done() +{ + if(!data_buffer_pos) + return false; + UINT8 h = scsi_cmdbuf[0]; + switch(h >> 5) { + case 0: return data_buffer_pos == 6; + case 1: return data_buffer_pos == 10; + case 2: return data_buffer_pos == 10; + case 3: return true; + case 4: return true; + case 5: return data_buffer_pos == 12; + case 6: return true; + case 7: return true; + } + return true; +} + +nscsi_full_device::control *nscsi_full_device::buf_control_push() +{ + if(buf_control_wpos == int(ARRAY_LENGTH(buf_control))) + throw emu_fatalerror("%s: buf_control overflow\n", tag()); + + control *c = buf_control + buf_control_wpos; + buf_control_wpos++; + return c; +} + +nscsi_full_device::control *nscsi_full_device::buf_control_pop() +{ + if(buf_control_rpos == buf_control_wpos) + throw emu_fatalerror("%s: buf_control underflow\n", tag()); + + control *c = buf_control + buf_control_rpos; + buf_control_rpos++; + if(buf_control_rpos == buf_control_wpos) + buf_control_rpos = buf_control_wpos = 0; + return c; +} + +void nscsi_full_device::scsi_status_complete(UINT8 st) +{ + control *c; + c = buf_control_push(); + c->action = BC_STATUS; + c->param1 = st; + c = buf_control_push(); + c->action = BC_MESSAGE_1; + c->param1 = SM_COMMAND_COMPLETE; + c = buf_control_push(); + c->action = BC_BUS_FREE; +} + +void nscsi_full_device::scsi_data_in(int buf, int size) +{ + control *c; + c = buf_control_push(); + c->action = BC_DATA_IN; + c->param1 = buf; + c->param2 = size; +} + +void nscsi_full_device::scsi_data_out(int buf, int size) +{ + control *c; + c = buf_control_push(); + c->action = BC_DATA_OUT; + c->param1 = buf; + c->param2 = size; +} + +void nscsi_full_device::sense(bool deferred, UINT8 key) +{ + memset(scsi_sense_buffer, 0, sizeof(scsi_sense_buffer)); + scsi_sense_buffer[0] = deferred ? 0x71 : 0x70; + scsi_sense_buffer[2] = key; +} + +void nscsi_full_device::scsi_unknown_command() +{ + logerror("%s: Unhandled command %s", tag(), command_names[scsi_cmdbuf[0]]); + for(int i=0; i != scsi_cmdsize; i++) + logerror(" %02x", scsi_cmdbuf[i]); + logerror("\n"); + + scsi_status_complete(SS_CHECK_CONDITION); + sense(false, 5); +} + +void nscsi_full_device::scsi_command() +{ + switch(scsi_cmdbuf[0]) { + case SC_REQUEST_SENSE: + logerror("%s: command REQUEST SENSE\n", tag()); + scsi_data_in(SBUF_SENSE, 8); + scsi_status_complete(SS_GOOD); + break; + default: + scsi_unknown_command(); + break; + } +} + +void nscsi_full_device::scsi_message() +{ + if(scsi_cmdbuf[0] & 0x80) { + scsi_identify = scsi_cmdbuf[0]; + return; + } + + logerror("%s: Unknown message", tag()); + for(int i=0; i != scsi_cmdsize; i++) + logerror(" %02x", scsi_cmdbuf[i]); + logerror("\n"); +} + +int nscsi_full_device::get_lun(int def) +{ + if(scsi_identify & 0x80) + return scsi_identify & 0x7f; + return def; +} + +void nscsi_full_device::bad_lun() +{ + scsi_status_complete(SS_CHECK_CONDITION); + sense(false, 2); +} + +// Arbitration delay (2.4us) +attotime nscsi_full_device::scsi_arbitation_delay() +{ + return attotime::from_nsec(2400); +} + +// Assertion period (90ns) +attotime nscsi_full_device::scsi_assertion_period() +{ + return attotime::from_nsec(90); +} + +// Bus clear delay (800ns) +attotime nscsi_full_device::scsi_bus_clear_delay() +{ + return attotime::from_nsec(800); +} + +// Bus free delay (800ns) +attotime nscsi_full_device::scsi_bus_free_delay() +{ + return attotime::from_nsec(800); +} + +// Bus set delay (1.8us) +attotime nscsi_full_device::scsi_bus_set_delay() +{ + return attotime::from_nsec(1800); +} + +// Bus settle delay (400ns) +attotime nscsi_full_device::scsi_bus_settle_delay() +{ + return attotime::from_nsec(400); +} + +// Cable skew delay (10ns) +attotime nscsi_full_device::scsi_cable_skew_delay() +{ + return attotime::from_nsec(10); +} + +// Data release delay (400ns) +attotime nscsi_full_device::scsi_data_release_delay() +{ + return attotime::from_nsec(40); +} + +// Deskew delay (45ns) +attotime nscsi_full_device::scsi_deskew_delay() +{ + return attotime::from_nsec(45); +} + +// Disconnection delay (200us) +attotime nscsi_full_device::scsi_disconnection_delay() +{ + return attotime::from_usec(200); +} + +// Hold time (45ns) +attotime nscsi_full_device::scsi_hold_time() +{ + return attotime::from_nsec(45); +} + +// Negation period (90ns) +attotime nscsi_full_device::scsi_negation_period() +{ + return attotime::from_nsec(90); +} + +// Reset hold time (25us) +attotime nscsi_full_device::scsi_reset_hold_time() +{ + return attotime::from_usec(25); +} + +// Selection abort time (200us) +attotime nscsi_full_device::scsi_selection_abort_time() +{ + return attotime::from_usec(200); +} + +// Selection timeout delay (250ms) +attotime nscsi_full_device::scsi_selection_timeout_delay() +{ + return attotime::from_msec(250); +} + +// Fast assertion period (30ns) +attotime nscsi_full_device::scsi_fast_assertion_period() +{ + return attotime::from_nsec(30); +} + +// Fast cable skew delay (5ns) +attotime nscsi_full_device::scsi_fast_cable_skew_delay() +{ + return attotime::from_nsec(5); +} + +// Fast deskew delay (20ns) +attotime nscsi_full_device::scsi_fast_deskew_delay() +{ + return attotime::from_nsec(20); +} + +// Fast hold time (10ns) +attotime nscsi_full_device::scsi_fast_hold_time() +{ + return attotime::from_nsec(10); +} + +// Fast negation period (30ns) +attotime nscsi_full_device::scsi_fast_negation_period() +{ + return attotime::from_nsec(30); +} diff --git a/src/devices/machine/nscsi_bus.h b/src/devices/machine/nscsi_bus.h new file mode 100644 index 00000000000..2aa4a57db7e --- /dev/null +++ b/src/devices/machine/nscsi_bus.h @@ -0,0 +1,428 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +#ifndef __NSCSI_BUS_H__ +#define __NSCSI_BUS_H__ + +#include "emu.h" + +#define MCFG_NSCSI_BUS_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, NSCSI_BUS, 0) + +#define MCFG_NSCSI_ADD(_tag, _slot_intf, _def_slot, _fixed) \ + MCFG_DEVICE_ADD(_tag, NSCSI_CONNECTOR, 0) \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, _fixed) + +class nscsi_device; + +class nscsi_bus_device : public device_t +{ +public: + nscsi_bus_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + void ctrl_w(int refid, UINT32 lines, UINT32 mask); + void data_w(int refid, UINT32 lines); + void ctrl_wait(int refid, UINT32 lines, UINT32 mask); + + UINT32 ctrl_r() const; + UINT32 data_r() const; + +protected: + virtual void device_start(); + virtual void device_reset(); + virtual void device_config_complete(); + +private: + struct dev_t { + nscsi_device *dev; + UINT32 ctrl, wait_ctrl; + UINT32 data; + }; + + dev_t dev[16]; + int devcnt; + + UINT32 data, ctrl; + + void regen_data(); + void regen_ctrl(int refid); +}; + +class nscsi_connector: public device_t, + public device_slot_interface +{ +public: + nscsi_connector(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual ~nscsi_connector(); + + nscsi_device *get_device(); + +protected: + virtual void device_start(); +}; + +class nscsi_device : public device_t, + public device_slot_card_interface +{ +public: + // Here because the biggest users are the devices, not the bus + enum { + S_INP = 0x0001, + S_CTL = 0x0002, + S_MSG = 0x0004, + S_BSY = 0x0008, + S_SEL = 0x0010, + S_REQ = 0x0020, + S_ACK = 0x0040, + S_ATN = 0x0080, + S_RST = 0x0100, + S_ALL = 0x01ff, + + S_PHASE_DATA_OUT = 0, + S_PHASE_DATA_IN = S_INP, + S_PHASE_COMMAND = S_CTL, + S_PHASE_STATUS = S_CTL|S_INP, + S_PHASE_MSG_OUT = S_MSG|S_CTL, + S_PHASE_MSG_IN = S_MSG|S_CTL|S_INP, + S_PHASE_MASK = S_MSG|S_CTL|S_INP + }; + + nscsi_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + void connect_to_bus(nscsi_bus_device *bus, int refid, int default_scsi_id); + virtual void scsi_ctrl_changed(); +protected: + int scsi_id; + int scsi_refid; + nscsi_bus_device *scsi_bus; + + virtual void device_start(); +}; + +class nscsi_full_device : public nscsi_device +{ +public: + nscsi_full_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + virtual void scsi_ctrl_changed(); +protected: + enum { SCSI_TIMER = 100 }; + + // SCSI status returns + enum { + SS_GOOD = 0x00, + SS_CHECK_CONDITION = 0x02, + SS_CONDITION_MET = 0x04, + SS_BUSY = 0x08, + SS_INT_GOOD = 0x10, + SS_INT_CONDITION_MET = 0x14, + SS_RESV_CONFLICT = 0x18, + SS_TERMINATED = 0x22, + SS_QUEUE_FULL = 0x28 + }; + + // SCSI commands + static const char *const command_names[256]; + enum { + SC_TEST_UNIT_READY = 0x00, + SC_REZERO = 0x01, + SC_REQUEST_SENSE = 0x03, + SC_FORMAT_UNIT = 0x04, + SC_REASSIGN_BLOCKS = 0x07, + SC_READ_6 = 0x08, + SC_RECIEVE = 0x08, + SC_WRITE_6 = 0x0a, + SC_SEND = 0x0a, + SC_SEEK = 0x0b, + SC_INQUIRY = 0x12, + SC_MODE_SELECT_6 = 0x15, + SC_RESERVE_6 = 0x16, + SC_RELEASE_6 = 0x17, + SC_MODE_SENSE_6 = 0x1a, + SC_START_STOP_UNIT = 0x1b, + SC_RECIEVE_DIAG_RES = 0x1c, + SC_SEND_DIAGNOSTICS = 0x1d, + SC_PREVENT_ALLOW_MEDIUM_REMOVAL = 0x1e, + SC_READ_FORMAT_CAPACITIES = 0x23, + SC_READ_CAPACITY = 0x25, + SC_READ_10 = 0x28, + SC_READ_GENERATION = 0x29, + SC_WRITE_10 = 0x2a, + SC_SEEK_10 = 0x2b, + SC_ERASE_10 = 0x2c, + SC_READ_UPDATED_BLOCK_10 = 0x2d, + SC_WRITE_VERIFY = 0x2e, + SC_VERIFY = 0x2f, + SC_SEARCH_DATA_HIGH_10 = 0x30, + SC_SEARCH_DATA_EQUAL_10 = 0x31, + SC_SEARCH_DATA_LOW_10 = 0x32, + SC_SET_LIMITS_10 = 0x33, + SC_PREFETCH = 0x34, + SC_SYNC_CACHE = 0x35, + SC_LOCK_UNLOCK_CACHE = 0x36, + SC_READ_DEFECT_DATA = 0x37, + SC_MEDIUM_SCAN = 0x38, + SC_COMPARE = 0x39, + SC_COPY_AND_VERIFY = 0x3a, + SC_WRITE_BUFFER = 0x3b, + SC_READ_DATA_BUFFER = 0x3c, + SC_UPDATE_BLOCK = 0x3d, + SC_READ_LONG = 0x3e, + SC_WRITE_LONG = 0x3f, + SC_CHANGE_DEFINITION = 0x40, + SC_WRITE_SAME = 0x41, + SC_READ_SUB_CHANNEL = 0x42, + SC_READ_TOC_PMA_ATIP = 0x43, + SC_READ_HEADER = 0x44, + SC_PLAY_AUDIO_10 = 0x45, + SC_GET_CONFIGURATION = 0x46, + SC_PLAY_AUDIO_MSF = 0x47, + SC_PLAY_AUDIO_TRACK_INDEX = 0x48, + SC_PLAY_RELATIVE_10 = 0x49, + SC_GET_EVENT_STATUS_NOTIFICATION = 0x4a, + SC_PAUSE_RESUME = 0x4b, + SC_LOG_SELECT = 0x4c, + SC_LOG_SENSE = 0x4d, + SC_STOP_PLAY_SCAN = 0x4e, + SC_XDWRITE = 0x50, + SC_XPWRITE = 0x51, + SC_READ_DISC_INFORMATION = 0x51, + SC_READ_TRACK_INFORMATION = 0x52, + SC_XDREAD = 0x52, + SC_RESERVE_TRACK = 0x53, + SC_SEND_OPC_INFORMATION = 0x54, + SC_MODE_SELECT_10 = 0x55, + SC_RESERVE_10 = 0x56, + SC_RELEASE_10 = 0x57, + SC_REPAIR_TRACK = 0x58, + SC_READ_MASTER_CUE = 0x59, + SC_MODE_SENSE_10 = 0x5a, + SC_CLOSE_TRACK_SESSION = 0x5b, + SC_READ_BUFFER_CAPACITY = 0x5c, + SC_SEND_CUE_SHEET = 0x5d, + SC_PERSISTENT_RESERVE_IN = 0x5e, + SC_PERSISTENT_RESERVE_OUT = 0x5f, + SC_XDWRITE_EXTENDED = 0x80, + SC_REBUILD = 0x81, + SC_REGENERATE = 0x82, + SC_EXTENDED_COPY = 0x83, + SC_RECEIVE_COPY_RESULTS = 0x84, + SC_REPORT_LUNS = 0xa0, + SC_BLANK = 0xa1, + SC_SEND_EVENT = 0xa2, + SC_REPORT_DEVICE_IDENTIFIER = 0xa3, + SC_SEND_KEY = 0xa3, + SC_REPORT_KEY = 0xa4, + SC_SET_DEVICE_IDENTIFIER = 0xa4, + SC_PLAY_AUDIO_12 = 0xa5, + SC_LOAD_UNLOAD_MEDIUM = 0xa6, + SC_MOVE_MEDIUM_ATTACHED = 0xa7, + SC_SET_READ_AHEAD = 0xa7, + SC_READ_12 = 0xa8, + SC_PLAY_RELATIVE_12 = 0xa9, + SC_WRITE_12 = 0xaa, + SC_ERASE_12 = 0xac, + SC_GET_PERFORMANCE = 0xac, + SC_READ_DVD_STRUCTURE = 0xad, + SC_WRITE_AND_VERIFY_12 = 0xae, + SC_VERIFY_12 = 0xaf, + SC_SEARCH_DATA_HIGH_12 = 0xb0, + SC_SEARCH_DATA_EQUAL_12 = 0xb1, + SC_SEARCH_DATA_LOW_12 = 0xb2, + SC_SET_LIMITS_12 = 0xb3, + SC_READ_ELEMENT_STATUS_ATTACHED = 0xb4, + SC_SET_STREAMING = 0xb6, + SC_READ_DEFECT_DATA_12 = 0xb7, + SC_READ_CD_MSF = 0xb9, + SC_SCAN_MMC = 0xba, + SC_SET_CD_SPEED = 0xbb, + SC_PLAY_CD = 0xbc, + SC_MECHANISM_STATUS = 0xbd, + SC_READ_CD = 0xbe, + SC_SEND_DVD_STRUCTURE = 0xbf + }; + + // SCSI Messages + enum { + SM_COMMAND_COMPLETE = 0x00, + SM_EXTENDED_MSG = 0x01, + SM_SAVE_DATA_PTR = 0x02, + SM_RESTORE_PTR = 0x03, + SM_DISCONNECT = 0x04, + SM_INITIATOR_ERROR = 0x05, + SM_ABORT = 0x06, + SM_MSG_REJECT = 0x07, + SM_NOP = 0x08, + SM_MSG_PARITY = 0x09, + SM_LCMD_COMPLETE = 0x0a, + SM_LCMD_COMPLETE_F = 0x0b, + SM_BUS_DEVICE_RESET = 0x0c, + SM_ABORT_TAG = 0x0d, + SM_CLEAR_QUEUE = 0x0e, + SM_INIT_RECOVERY = 0x0f, + SM_RELEASE_RECOVERY = 0x10, + SM_TERMINATE_IO = 0x11, + SM_SIMPLE_QUEUE = 0x20, + SM_HEAD_QUEUE = 0x21, + SM_ORDERED_QUEUE = 0x22, + SM_IGNORE_WIDE_RES = 0x23 + }; + + enum { + SBUF_MAIN, + SBUF_SENSE + }; + + UINT8 scsi_cmdbuf[4096], scsi_sense_buffer[8]; + int scsi_cmdsize; + UINT8 scsi_identify; + + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + virtual void scsi_message(); + virtual void scsi_command(); + + void scsi_unknown_command(); + void scsi_status_complete(UINT8 st); + void scsi_data_in(int buf, int size); + void scsi_data_out(int buf, int size); + + void sense(bool deferred, UINT8 key); + int get_lun(int def = 0); + void bad_lun(); + + virtual UINT8 scsi_get_data(int buf, int offset); + virtual void scsi_put_data(int buf, int offset, UINT8 data); + + // Default delays: + + // Arbitration delay (2.4us) + virtual attotime scsi_arbitation_delay(); + + // Assertion period (90ns) + virtual attotime scsi_assertion_period(); + + // Bus clear delay (800ns) + virtual attotime scsi_bus_clear_delay(); + + // Bus free delay (800ns) + virtual attotime scsi_bus_free_delay(); + + // Bus set delay (1.8us) + virtual attotime scsi_bus_set_delay(); + + // Bus settle delay (400ns) + virtual attotime scsi_bus_settle_delay(); + + // Cable skew delay (10ns) + virtual attotime scsi_cable_skew_delay(); + + // Data release delay (400ns) + virtual attotime scsi_data_release_delay(); + + // Deskew delay (45ns) + virtual attotime scsi_deskew_delay(); + + // Disconnection delay (200us) + virtual attotime scsi_disconnection_delay(); + + // Hold time (45ns) + virtual attotime scsi_hold_time(); + + // Negation period (90ns) + virtual attotime scsi_negation_period(); + + // Reset hold time (25us) + virtual attotime scsi_reset_hold_time(); + + // Selection abort time (200us) + virtual attotime scsi_selection_abort_time(); + + // Selection timeout delay (250ms) + virtual attotime scsi_selection_timeout_delay(); + + // Fast assertion period (30ns) + virtual attotime scsi_fast_assertion_period(); + + // Fast cable skew delay (5ns) + virtual attotime scsi_fast_cable_skew_delay(); + + // Fast deskew delay (20ns) + virtual attotime scsi_fast_deskew_delay(); + + // Fast hold time (10ns) + virtual attotime scsi_fast_hold_time(); + + // Fast negation period (30ns) + virtual attotime scsi_fast_negation_period(); + +private: + enum { + IDLE + }; + + enum { + TARGET_SELECT_WAIT_BUS_SETTLE = 1, + TARGET_SELECT_WAIT_SEL_0, + + TARGET_NEXT_CONTROL, + TARGET_WAIT_MSG_BYTE, + TARGET_WAIT_CMD_BYTE, + TARGET_WAIT_DATA_IN_BYTE, + TARGET_WAIT_DATA_OUT_BYTE + }; + + enum { + RECV_BYTE_T_WAIT_ACK_0 = 1, + RECV_BYTE_T_WAIT_ACK_1, + SEND_BYTE_T_WAIT_ACK_0, + SEND_BYTE_T_WAIT_ACK_1 + }; + + enum { + STATE_MASK = 0x00ff, + SUB_SHIFT = 8, + SUB_MASK = 0xff00 + }; + + enum { + BC_MSG_OR_COMMAND, + BC_STATUS, + BC_MESSAGE_1, + BC_MESSAGE_2, + BC_DATA_IN, + BC_DATA_OUT, + BC_BUS_FREE + }; + + struct control { + int action; + int param1, param2; + }; + + emu_timer *scsi_timer; + + int scsi_state, scsi_substate; + int scsi_initiator_id; + int data_buffer_id, data_buffer_size, data_buffer_pos; + + control buf_control[32]; + int buf_control_rpos; + int buf_control_wpos; + + control *buf_control_push(); + control *buf_control_pop(); + + void step(bool timeout); + void target_recv_byte(); + void target_send_byte(UINT8 val); + void target_send_buffer_byte(); + bool command_done(); +}; + + +extern const device_type NSCSI_BUS; +extern const device_type NSCSI_CONNECTOR; + +#endif diff --git a/src/devices/machine/nscsi_cb.c b/src/devices/machine/nscsi_cb.c new file mode 100644 index 00000000000..5c3c12e8a34 --- /dev/null +++ b/src/devices/machine/nscsi_cb.c @@ -0,0 +1,57 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +#include "nscsi_cb.h" + +const device_type NSCSI_CB = &device_creator; + +nscsi_callback_device::nscsi_callback_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : nscsi_device(mconfig, NSCSI_CB, "SCSI callback (new)", tag, owner, clock, "nscsi_cb", __FILE__), + m_write_rst(*this), + m_write_atn(*this), + m_write_ack(*this), + m_write_req(*this), + m_write_msg(*this), + m_write_io(*this), + m_write_cd(*this), + m_write_sel(*this), + m_write_bsy(*this) +{ +} + +void nscsi_callback_device::device_start() +{ + // resolve callbacks + m_write_rst.resolve_safe(); + m_write_atn.resolve_safe(); + m_write_ack.resolve_safe(); + m_write_req.resolve_safe(); + m_write_msg.resolve_safe(); + m_write_io.resolve_safe(); + m_write_cd.resolve_safe(); + m_write_sel.resolve_safe(); + m_write_bsy.resolve_safe(); + + // state saving + save_item(NAME(m_ctrl)); +} + +void nscsi_callback_device::device_reset() +{ + scsi_bus->ctrl_w(scsi_refid, 0, S_ALL); + scsi_bus->ctrl_wait(scsi_refid, S_ALL, S_ALL); +} + +void nscsi_callback_device::scsi_ctrl_changed() +{ + m_ctrl = scsi_bus->ctrl_r(); + + m_write_rst((m_ctrl & S_RST) ? 1 : 0); + m_write_atn((m_ctrl & S_ATN) ? 1 : 0); + m_write_ack((m_ctrl & S_ACK) ? 1 : 0); + m_write_req((m_ctrl & S_REQ) ? 1 : 0); + m_write_msg((m_ctrl & S_MSG) ? 1 : 0); + m_write_io((m_ctrl & S_INP) ? 1 : 0); + m_write_cd((m_ctrl & S_CTL) ? 1 : 0); + m_write_sel((m_ctrl & S_SEL) ? 1 : 0); + m_write_bsy((m_ctrl & S_BSY) ? 1 : 0); +} diff --git a/src/devices/machine/nscsi_cb.h b/src/devices/machine/nscsi_cb.h new file mode 100644 index 00000000000..9152ddaf8f9 --- /dev/null +++ b/src/devices/machine/nscsi_cb.h @@ -0,0 +1,97 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +#ifndef NSCSI_CB_H +#define NSCSI_CB_H + +#include "emu.h" +#include "machine/nscsi_bus.h" + +#define MCFG_NSCSICB_RST_HANDLER(_line) \ + downcast(device)->set_rst_callback(DEVCB_##_line); + +#define MCFG_NSCSICB_ATN_HANDLER(_line) \ + downcast(device)->set_atn_callback(DEVCB_##_line); + +#define MCFG_NSCSICB_ACK_HANDLER(_line) \ + downcast(device)->set_ack_callback(DEVCB_##_line); + +#define MCFG_NSCSICB_REQ_HANDLER(_line) \ + downcast(device)->set_req_callback(DEVCB_##_line); + +#define MCFG_NSCSICB_MSG_HANDLER(_line) \ + downcast(device)->set_msg_callback(DEVCB_##_line); + +#define MCFG_NSCSICB_IO_HANDLER(_line) \ + downcast(device)->set_io_callback(DEVCB_##_line); + +#define MCFG_NSCSICB_CD_HANDLER(_line) \ + downcast(device)->set_cd_callback(DEVCB_##_line); + +#define MCFG_NSCSICB_SEL_HANDLER(_line) \ + downcast(device)->set_sel_callback(DEVCB_##_line); + +#define MCFG_NSCSICB_BSY_HANDLER(_line) \ + downcast(device)->set_bsy_callback(DEVCB_##_line); + +class nscsi_callback_device : public nscsi_device +{ +public: + nscsi_callback_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + template void set_rst_callback(_line line) { m_write_rst.set_callback(line); } + template void set_atn_callback(_line line) { m_write_atn.set_callback(line); } + template void set_ack_callback(_line line) { m_write_ack.set_callback(line); } + template void set_req_callback(_line line) { m_write_req.set_callback(line); } + template void set_msg_callback(_line line) { m_write_msg.set_callback(line); } + template void set_io_callback(_line line) { m_write_io.set_callback(line); } + template void set_cd_callback(_line line) { m_write_cd.set_callback(line); } + template void set_sel_callback(_line line) { m_write_sel.set_callback(line); } + template void set_bsy_callback(_line line) { m_write_bsy.set_callback(line); } + + virtual void scsi_ctrl_changed(); + + UINT8 read() { return scsi_bus->data_r(); } + DECLARE_READ8_MEMBER( read ) { return read(); } + void write(UINT8 data) { scsi_bus->data_w(scsi_refid, data); } + DECLARE_WRITE8_MEMBER( write ) { write(data); } + + DECLARE_READ_LINE_MEMBER( rst_r ) { return (m_ctrl & S_RST) ? 1 : 0; } + DECLARE_READ_LINE_MEMBER( atn_r ) { return (m_ctrl & S_ATN) ? 1 : 0; } + DECLARE_READ_LINE_MEMBER( ack_r ) { return (m_ctrl & S_ACK) ? 1 : 0; } + DECLARE_READ_LINE_MEMBER( req_r ) { return (m_ctrl & S_REQ) ? 1 : 0; } + DECLARE_READ_LINE_MEMBER( msg_r ) { return (m_ctrl & S_MSG) ? 1 : 0; } + DECLARE_READ_LINE_MEMBER( io_r ) { return (m_ctrl & S_INP) ? 1 : 0; } + DECLARE_READ_LINE_MEMBER( cd_r ) { return (m_ctrl & S_CTL) ? 1 : 0; } + DECLARE_READ_LINE_MEMBER( sel_r ) { return (m_ctrl & S_SEL) ? 1 : 0; } + DECLARE_READ_LINE_MEMBER( bsy_r ) { return (m_ctrl & S_BSY) ? 1 : 0; } + + DECLARE_WRITE_LINE_MEMBER( rst_w ) { scsi_bus->ctrl_w(scsi_refid, state ? S_RST : 0, S_RST); } + DECLARE_WRITE_LINE_MEMBER( atn_w ) { scsi_bus->ctrl_w(scsi_refid, state ? S_ATN : 0, S_ATN); } + DECLARE_WRITE_LINE_MEMBER( ack_w ) { scsi_bus->ctrl_w(scsi_refid, state ? S_ACK : 0, S_ACK); } + DECLARE_WRITE_LINE_MEMBER( req_w ) { scsi_bus->ctrl_w(scsi_refid, state ? S_REQ : 0, S_REQ); } + DECLARE_WRITE_LINE_MEMBER( msg_w ) { scsi_bus->ctrl_w(scsi_refid, state ? S_MSG : 0, S_MSG); } + DECLARE_WRITE_LINE_MEMBER( io_w ) { scsi_bus->ctrl_w(scsi_refid, state ? S_INP : 0, S_INP); } + DECLARE_WRITE_LINE_MEMBER( cd_w ) { scsi_bus->ctrl_w(scsi_refid, state ? S_CTL : 0, S_CTL); } + DECLARE_WRITE_LINE_MEMBER( sel_w ) { scsi_bus->ctrl_w(scsi_refid, state ? S_SEL : 0, S_SEL); } + DECLARE_WRITE_LINE_MEMBER( bsy_w ) { scsi_bus->ctrl_w(scsi_refid, state ? S_BSY : 0, S_BSY); } + +protected: + virtual void device_start(); + virtual void device_reset(); + + devcb_write_line m_write_rst; + devcb_write_line m_write_atn; + devcb_write_line m_write_ack; + devcb_write_line m_write_req; + devcb_write_line m_write_msg; + devcb_write_line m_write_io; + devcb_write_line m_write_cd; + devcb_write_line m_write_sel; + devcb_write_line m_write_bsy; + + UINT32 m_ctrl; +}; + +extern const device_type NSCSI_CB; + +#endif diff --git a/src/devices/machine/nscsi_cd.c b/src/devices/machine/nscsi_cd.c new file mode 100644 index 00000000000..c8d8440b3ce --- /dev/null +++ b/src/devices/machine/nscsi_cd.c @@ -0,0 +1,251 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +#include "machine/nscsi_cd.h" +#include "imagedev/chd_cd.h" + +const device_type NSCSI_CDROM = &device_creator; + +nscsi_cdrom_device::nscsi_cdrom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + nscsi_full_device(mconfig, NSCSI_CDROM, "SCSI CDROM", tag, owner, clock, "scsi_cdrom", __FILE__) +{ +} + +void nscsi_cdrom_device::device_start() +{ + nscsi_full_device::device_start(); + bytes_per_sector = 2048; + save_item(NAME(block)); + save_item(NAME(lba)); + save_item(NAME(cur_lba)); + save_item(NAME(blocks)); + save_item(NAME(bytes_per_sector)); +} + +void nscsi_cdrom_device::device_reset() +{ + nscsi_full_device::device_reset(); + cdrom = subdevice("image")->get_cdrom_file(); + lba = 0; + blocks = 0; + cur_lba = -1; +} + +static MACHINE_CONFIG_FRAGMENT(scsi_cdrom) + MCFG_CDROM_ADD("image") + MCFG_CDROM_INTERFACE("cdrom") +MACHINE_CONFIG_END + +machine_config_constructor nscsi_cdrom_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME(scsi_cdrom); +} + +UINT8 nscsi_cdrom_device::scsi_get_data(int id, int pos) +{ + if(id != 2) + return nscsi_full_device::scsi_get_data(id, pos); + int clba = lba + pos / bytes_per_sector; + if(clba != cur_lba) { + cur_lba = clba; + if(!cdrom_read_data(cdrom, cur_lba, block, CD_TRACK_MODE1)) { + logerror("%s: CD READ ERROR !\n", tag()); + memset(block, 0, sizeof(block)); + } + } + return block[pos & (bytes_per_sector - 1)]; +} + +void nscsi_cdrom_device::return_no_cd() +{ + sense(false, 3); + scsi_status_complete(SS_CHECK_CONDITION); +} + +void nscsi_cdrom_device::scsi_command() +{ + switch(scsi_cmdbuf[0]) { + case SC_TEST_UNIT_READY: + logerror("%s: command TEST UNIT READY\n", tag()); + if(cdrom) + scsi_status_complete(SS_GOOD); + else + return_no_cd(); + break; + + case SC_READ_6: + if(!cdrom) { + return_no_cd(); + break; + } + + lba = ((scsi_cmdbuf[1] & 0x1f)<<16) | (scsi_cmdbuf[2]<<8) | scsi_cmdbuf[3]; + blocks = scsi_cmdbuf[4]; + if(!blocks) + blocks = 256; + + logerror("%s: command READ start=%08x blocks=%04x\n", + tag(), lba, blocks); + + scsi_data_in(2, blocks*bytes_per_sector); + scsi_status_complete(SS_GOOD); + break; + + case SC_INQUIRY: { + int lun = get_lun(scsi_cmdbuf[1] >> 5); + logerror("%s: command INQUIRY lun=%d EVPD=%d page=%d alloc=%02x link=%02x\n", + tag(), + lun, scsi_cmdbuf[1] & 1, scsi_cmdbuf[2], scsi_cmdbuf[4], scsi_cmdbuf[5]); + if(lun) { + bad_lun(); + return; + } + + int page = scsi_cmdbuf[2]; + int size = scsi_cmdbuf[4]; + switch(page) { + case 0: + memset(scsi_cmdbuf, 0, 148); + scsi_cmdbuf[0] = 0x05; // device is present, device is CD/DVD (MMC-3) + scsi_cmdbuf[1] = 0x80; // media is removable + scsi_cmdbuf[2] = 0x05; // device complies with SPC-3 standard + scsi_cmdbuf[3] = 0x02; // response data format = SPC-3 standard + // some Konami games freak out if this isn't "Sony", so we'll lie + // this is the actual drive on my Nagano '98 board + strcpy((char *)&scsi_cmdbuf[8], "Sony"); + strcpy((char *)&scsi_cmdbuf[16], "CDU-76S"); + strcpy((char *)&scsi_cmdbuf[32], "1.0"); + if(size > 148) + size = 148; + scsi_data_in(SBUF_MAIN, size); + break; + } + scsi_status_complete(SS_GOOD); + break; + } + + case SC_START_STOP_UNIT: + logerror("%s: command START STOP UNIT\n", tag()); + scsi_status_complete(SS_GOOD); + break; + + case SC_READ_CAPACITY: { + if(!cdrom) { + return_no_cd(); + break; + } + + logerror("%s: command READ CAPACITY\n", tag()); + + UINT32 temp = cdrom_get_track_start(cdrom, 0xaa); + temp--; // return the last used block on the disc + + scsi_cmdbuf[0] = (temp>>24) & 0xff; + scsi_cmdbuf[1] = (temp>>16) & 0xff; + scsi_cmdbuf[2] = (temp>>8) & 0xff; + scsi_cmdbuf[3] = (temp & 0xff); + scsi_cmdbuf[4] = 0; + scsi_cmdbuf[5] = 0; + scsi_cmdbuf[6] = (bytes_per_sector>>8)&0xff; + scsi_cmdbuf[7] = (bytes_per_sector & 0xff); + + scsi_data_in(SBUF_MAIN, 8); + scsi_status_complete(SS_GOOD); + break; + } + + case SC_READ_10: + if(!cdrom) { + return_no_cd(); + break; + } + + lba = (scsi_cmdbuf[2]<<24) | (scsi_cmdbuf[3]<<16) | (scsi_cmdbuf[4]<<8) | scsi_cmdbuf[5]; + blocks = (scsi_cmdbuf[7] << 8) | scsi_cmdbuf[8]; + + logerror("%s: command READ EXTENDED start=%08x blocks=%04x\n", + tag(), lba, blocks); + + scsi_data_in(2, blocks*bytes_per_sector); + scsi_status_complete(SS_GOOD); + break; + + case SC_MODE_SENSE_6: { + int lun = get_lun(scsi_cmdbuf[1] >> 5); + logerror("%s: command MODE SENSE 6 lun=%d page=%02x alloc=%02x link=%02x\n", + tag(), + lun, scsi_cmdbuf[2] & 0x3f, scsi_cmdbuf[4], scsi_cmdbuf[5]); + if(lun) { + bad_lun(); + return; + } + + int page = scsi_cmdbuf[2] & 0x3f; + int size = scsi_cmdbuf[4]; + int pos = 1; + scsi_cmdbuf[pos++] = 0x00; // medium type + scsi_cmdbuf[pos++] = 0x80; // WP, cache + + UINT32 temp = cdrom_get_track_start(cdrom, 0xaa); + temp--; // return the last used block on the disc + scsi_cmdbuf[pos++] = 0x08; // Block descriptor length + + scsi_cmdbuf[pos++] = (temp>>24) & 0xff; + scsi_cmdbuf[pos++] = (temp>>16) & 0xff; + scsi_cmdbuf[pos++] = (temp>>8) & 0xff; + scsi_cmdbuf[pos++] = (temp & 0xff); + scsi_cmdbuf[pos++] = 0; + scsi_cmdbuf[pos++] = 0; + scsi_cmdbuf[pos++] = (bytes_per_sector>>8)&0xff; + scsi_cmdbuf[pos++] = (bytes_per_sector & 0xff); + + int pmax = page == 0x3f ? 0x3e : page; + int pmin = page == 0x3f ? 0x00 : page; + for(int page=pmax; page >= pmin; page--) { + switch(page) { + case 0x00: // Unit attention parameters page (weird) + scsi_cmdbuf[pos++] = 0x80; // PS, page id + scsi_cmdbuf[pos++] = 0x02; // Page length + scsi_cmdbuf[pos++] = 0x00; // Meh + scsi_cmdbuf[pos++] = 0x00; // Double meh + break; + + case 0x02: // Disconnect/reconnect control parameters (guessed) + scsi_cmdbuf[pos++] = 0x82; // PS, page id + scsi_cmdbuf[pos++] = 0x0e; // Page length + scsi_cmdbuf[pos++] = 0xe6; // Buffer full ratio, 90% + scsi_cmdbuf[pos++] = 0x1a; // Buffer empty ratio, 10% + scsi_cmdbuf[pos++] = 0x00; // Bus inactivity limit, 0 + scsi_cmdbuf[pos++] = 0x00; + scsi_cmdbuf[pos++] = 0x00; // Disconnect time limit, 0 + scsi_cmdbuf[pos++] = 0x00; + scsi_cmdbuf[pos++] = 0x00; // Connect time limit, 0 + scsi_cmdbuf[pos++] = 0x00; + scsi_cmdbuf[pos++] = 0x00; // Maximum burst size, 0 + scsi_cmdbuf[pos++] = 0x00; + scsi_cmdbuf[pos++] = 0x00; // EMDP, Dimm, DTDC + scsi_cmdbuf[pos++] = 0x00; // Reserved + scsi_cmdbuf[pos++] = 0x00; // Reserved + scsi_cmdbuf[pos++] = 0x00; // Reserved + break; + + default: + logerror("%s: mode sense page %02x unhandled\n", tag(), page); + break; + } + } + scsi_cmdbuf[0] = pos; + if(pos > size) + pos = size; + + scsi_data_in(0, pos); + scsi_status_complete(SS_GOOD); + break; + } + + default: + fprintf(stderr, "scsi %02x\n", scsi_cmdbuf[0]); + + nscsi_full_device::scsi_command(); + break; + } +} diff --git a/src/devices/machine/nscsi_cd.h b/src/devices/machine/nscsi_cd.h new file mode 100644 index 00000000000..a890848152d --- /dev/null +++ b/src/devices/machine/nscsi_cd.h @@ -0,0 +1,33 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +#ifndef __NSCSI_CD_H__ +#define __NSCSI_CD_H__ + +#include "machine/nscsi_bus.h" +#include "cdrom.h" + +class nscsi_cdrom_device : public nscsi_full_device +{ +public: + nscsi_cdrom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual machine_config_constructor device_mconfig_additions() const; + +protected: + virtual void device_start(); + virtual void device_reset(); + + virtual void scsi_command(); + virtual UINT8 scsi_get_data(int id, int pos); + +private: + UINT8 block[2048]; + cdrom_file *cdrom; + int bytes_per_sector; + int lba, cur_lba, blocks; + + void return_no_cd(); +}; + +extern const device_type NSCSI_CDROM; + +#endif diff --git a/src/devices/machine/nscsi_hd.c b/src/devices/machine/nscsi_hd.c new file mode 100644 index 00000000000..96aec81979c --- /dev/null +++ b/src/devices/machine/nscsi_hd.c @@ -0,0 +1,369 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +#include "machine/nscsi_hd.h" +#include "imagedev/harddriv.h" + +const device_type NSCSI_HARDDISK = &device_creator; + +nscsi_harddisk_device::nscsi_harddisk_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + nscsi_full_device(mconfig, NSCSI_HARDDISK, "SCSI HARDDISK", tag, owner, clock, "scsi_harddisk", __FILE__) +{ +} + +nscsi_harddisk_device::nscsi_harddisk_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + nscsi_full_device(mconfig, type, name, tag, owner, clock, shortname, source) +{ +} + +void nscsi_harddisk_device::device_start() +{ + nscsi_full_device::device_start(); + save_item(NAME(block)); + save_item(NAME(lba)); + save_item(NAME(cur_lba)); + save_item(NAME(blocks)); + save_item(NAME(bytes_per_sector)); +} + +void nscsi_harddisk_device::device_reset() +{ + nscsi_full_device::device_reset(); + harddisk_image_device *hd = subdevice("image"); + harddisk = hd->get_hard_disk_file(); + if(!harddisk) { + scsi_id = -1; + bytes_per_sector = 0; + } else { + const hard_disk_info *hdinfo = hard_disk_get_info(harddisk); + bytes_per_sector = hdinfo->sectorbytes; + } + cur_lba = -1; +} + +static MACHINE_CONFIG_FRAGMENT(scsi_harddisk) + MCFG_HARDDISK_ADD("image") + MCFG_HARDDISK_INTERFACE("scsi_hdd") +MACHINE_CONFIG_END + +machine_config_constructor nscsi_harddisk_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME(scsi_harddisk); +} + +UINT8 nscsi_harddisk_device::scsi_get_data(int id, int pos) +{ + if(id != 2) + return nscsi_full_device::scsi_get_data(id, pos); + int clba = lba + pos / bytes_per_sector; + if(clba != cur_lba) { + cur_lba = clba; + if(!hard_disk_read(harddisk, cur_lba, block)) { + logerror("%s: HD READ ERROR !\n", tag()); + memset(block, 0, sizeof(block)); + } + } + return block[pos % bytes_per_sector]; +} + +void nscsi_harddisk_device::scsi_put_data(int id, int pos, UINT8 data) +{ + if(id != 2) { + nscsi_full_device::scsi_put_data(id, pos, data); + return; + } + + int offset = pos % bytes_per_sector; + block[offset] = data; + int clba = lba + pos / bytes_per_sector; + if(offset == bytes_per_sector-1) { + if(!hard_disk_write(harddisk, clba, block)) + logerror("%s: HD WRITE ERROR !\n", tag()); + } +} + +void nscsi_harddisk_device::scsi_command() +{ + #if 0 + if (scsi_cmdbuf[0] != SC_READ) + { + logerror("%s: ", tag()); + for (int i = 0; i < 6; i++) + { + logerror("%02x ", scsi_cmdbuf[i]); + } + logerror("\n"); + } + #endif + + switch(scsi_cmdbuf[0]) { + case SC_TEST_UNIT_READY: + logerror("%s: command TEST UNIT READY\n", tag()); + scsi_status_complete(SS_GOOD); + break; + + case SC_READ_6: + lba = ((scsi_cmdbuf[1] & 0x1f)<<16) | (scsi_cmdbuf[2]<<8) | scsi_cmdbuf[3]; + blocks = scsi_cmdbuf[4]; + if(!blocks) + blocks = 256; + + logerror("%s: command READ start=%08x blocks=%04x\n", + tag(), lba, blocks); + + scsi_data_in(2, blocks*bytes_per_sector); + scsi_status_complete(SS_GOOD); + break; + + case SC_WRITE_6: + lba = ((scsi_cmdbuf[1] & 0x1f)<<16) | (scsi_cmdbuf[2]<<8) | scsi_cmdbuf[3]; + blocks = scsi_cmdbuf[4]; + if(!blocks) + blocks = 256; + + logerror("%s: command WRITE start=%08x blocks=%04x\n", + tag(), lba, blocks); + + scsi_data_out(2, blocks*bytes_per_sector); + scsi_status_complete(SS_GOOD); + break; + + case SC_INQUIRY: { + int lun = get_lun(scsi_cmdbuf[1] >> 5); + logerror("%s: command INQUIRY lun=%d EVPD=%d page=%d alloc=%02x link=%02x\n", + tag(), + lun, scsi_cmdbuf[1] & 1, scsi_cmdbuf[2], scsi_cmdbuf[4], scsi_cmdbuf[5]); + if(lun) { + bad_lun(); + return; + } + + int page = scsi_cmdbuf[2]; + int size = scsi_cmdbuf[4]; + switch(page) { + case 0: + memset(scsi_cmdbuf, 0, 148); + scsi_cmdbuf[0] = 0x00; // device is direct-access (e.g. hard disk) + scsi_cmdbuf[1] = 0x00; // media is not removable + scsi_cmdbuf[2] = 0x05; // device complies with SPC-3 standard + scsi_cmdbuf[3] = 0x01; // response data format = CCS + // Apple HD SC setup utility needs to see this + strcpy((char *)&scsi_cmdbuf[8], " SEAGATE"); + strcpy((char *)&scsi_cmdbuf[15], " ST225N"); + strcpy((char *)&scsi_cmdbuf[31], "1.00"); + scsi_cmdbuf[36] = 0x00; // # of extents high + scsi_cmdbuf[37] = 0x08; // # of extents low + scsi_cmdbuf[38] = 0x00; // group 0 commands 0-1f + scsi_cmdbuf[39] = 0x99; // commands 0,3,4,7 + scsi_cmdbuf[40] = 0xa0; // commands 8, a + scsi_cmdbuf[41] = 0x27; // commands 12,15,16,17 + scsi_cmdbuf[42] = 0x34; // commands 1a,1b,1d + scsi_cmdbuf[43] = 0x01; // group 1 commands 20-3f + scsi_cmdbuf[44] = 0x04; + scsi_cmdbuf[45] = 0xa0; + scsi_cmdbuf[46] = 0x01; + scsi_cmdbuf[47] = 0x18; + scsi_cmdbuf[48] = 0x07; // group 7 commands e0-ff + scsi_cmdbuf[49] = 0x00; + scsi_cmdbuf[50] = 0xa0; // commands 8, a + scsi_cmdbuf[51] = 0x00; + scsi_cmdbuf[52] = 0x00; + scsi_cmdbuf[53] = 0xff; // end of list + if(size > 54) + size = 54; + scsi_data_in(0, size); + break; + } + scsi_status_complete(SS_GOOD); + break; + } + + case SC_MODE_SENSE_6: { + int lun = get_lun(scsi_cmdbuf[1] >> 5); + logerror("%s: command MODE SENSE 6 lun=%d page=%02x alloc=%02x link=%02x\n", + tag(), + lun, scsi_cmdbuf[2] & 0x3f, scsi_cmdbuf[4], scsi_cmdbuf[5]); + if(lun) { + bad_lun(); + return; + } + + int page = scsi_cmdbuf[2] & 0x3f; + int size = scsi_cmdbuf[4]; + int pos = 1; + scsi_cmdbuf[pos++] = 0x00; // medium type + scsi_cmdbuf[pos++] = 0x00; // WP, cache + + hard_disk_info *info = hard_disk_get_info(harddisk); + UINT32 dsize = info->cylinders * info->heads * info->sectors - 1; + scsi_cmdbuf[pos++] = 0x08; // Block descriptor length + scsi_cmdbuf[pos++] = 0x00; + scsi_cmdbuf[pos++] = (dsize>>16) & 0xff; + scsi_cmdbuf[pos++] = (dsize>>8) & 0xff; + scsi_cmdbuf[pos++] = (dsize & 0xff); + scsi_cmdbuf[pos++] = 0x00; + scsi_cmdbuf[pos++] = (info->sectorbytes>>16)&0xff; + scsi_cmdbuf[pos++] = (info->sectorbytes>>8)&0xff; + scsi_cmdbuf[pos++] = (info->sectorbytes & 0xff); + + int pmax = page == 0x3f ? 0x3e : page; + int pmin = page == 0x3f ? 0x00 : page; + for(int page=pmax; page >= pmin; page--) { + switch(page) { + case 0x00: // Unit attention parameters page (weird) + scsi_cmdbuf[pos++] = 0x80; // PS, page id + scsi_cmdbuf[pos++] = 0x02; // Page length + scsi_cmdbuf[pos++] = 0x00; // Meh + scsi_cmdbuf[pos++] = 0x00; // Double meh + break; + + case 0x03: { // Format parameters page + scsi_cmdbuf[pos++] = 0x83; // PS, page id + scsi_cmdbuf[pos++] = 0x16; // Page length + scsi_cmdbuf[pos++] = (info->cylinders * info->heads) >> 8; // Track/zone + scsi_cmdbuf[pos++] = info->cylinders * info->heads; // Track/zone + scsi_cmdbuf[pos++] = 0x00; // Alt sect/zone + scsi_cmdbuf[pos++] = 0x00; // Alt sect/zone + scsi_cmdbuf[pos++] = 0x00; // Alt track/zone + scsi_cmdbuf[pos++] = 0x00; // Alt track/zone + scsi_cmdbuf[pos++] = 0x00; // Alt track/volume + scsi_cmdbuf[pos++] = 0x00; // Alt track/volume + scsi_cmdbuf[pos++] = info->sectors >> 8; // Sectors/track + scsi_cmdbuf[pos++] = info->sectors; // Sectors/track + scsi_cmdbuf[pos++] = info->sectorbytes >> 8; // Bytes/sector + scsi_cmdbuf[pos++] = info->sectorbytes; // Bytes/sector + scsi_cmdbuf[pos++] = 0x00; // Interleave + scsi_cmdbuf[pos++] = 0x00; // Interleave + scsi_cmdbuf[pos++] = 0x00; // Track skew + scsi_cmdbuf[pos++] = 0x00; // Track skew + scsi_cmdbuf[pos++] = 0x00; // Cylinder skew + scsi_cmdbuf[pos++] = 0x00; // Cylinder skew + scsi_cmdbuf[pos++] = 0x00; // Sectoring type + scsi_cmdbuf[pos++] = 0x00; // Reserved + scsi_cmdbuf[pos++] = 0x00; // Reserved + scsi_cmdbuf[pos++] = 0x00; // Reserved + break; + } + + case 0x04: { // Rigid drive geometry page + scsi_cmdbuf[pos++] = 0x84; // PS, page id + scsi_cmdbuf[pos++] = 0x16; // Page length + scsi_cmdbuf[pos++] = info->cylinders >> 16; // Cylinders + scsi_cmdbuf[pos++] = info->cylinders >> 8; // Cylinders + scsi_cmdbuf[pos++] = info->cylinders; // Cylinders + scsi_cmdbuf[pos++] = info->heads; // Heads + scsi_cmdbuf[pos++] = 0x00; // Starting cylinder - write precomp + scsi_cmdbuf[pos++] = 0x00; // Starting cylinder - write precomp + scsi_cmdbuf[pos++] = 0x00; // Starting cylinder - write precomp + scsi_cmdbuf[pos++] = 0x00; // Starting cylinder - reduced write current + scsi_cmdbuf[pos++] = 0x00; // Starting cylinder - reduced write current + scsi_cmdbuf[pos++] = 0x00; // Starting cylinder - reduced write current + scsi_cmdbuf[pos++] = 0x00; // Drive step rate + scsi_cmdbuf[pos++] = 0x00; // Drive step rate + scsi_cmdbuf[pos++] = 0x00; // Landing zone cylinder + scsi_cmdbuf[pos++] = 0x00; // Landing zone cylinder + scsi_cmdbuf[pos++] = 0x00; // Landing zone cylinder + scsi_cmdbuf[pos++] = 0x00; // RPL + scsi_cmdbuf[pos++] = 0x00; // Rotational offset + scsi_cmdbuf[pos++] = 0x00; // Reserved + scsi_cmdbuf[pos++] = UINT8(10000 >> 8); // Medium rotation rate + scsi_cmdbuf[pos++] = UINT8(10000); // Medium rotation rate + scsi_cmdbuf[pos++] = 0x00; // Reserved + scsi_cmdbuf[pos++] = 0x00; // Reserved + break; + } + + case 0x30: { // Apple firmware ID page + scsi_cmdbuf[pos++] = 0xb0; // cPS, page id + scsi_cmdbuf[pos++] = 0x16; // Page length + scsi_cmdbuf[pos++] = 'A'; + scsi_cmdbuf[pos++] = 'P'; + scsi_cmdbuf[pos++] = 'P'; + scsi_cmdbuf[pos++] = 'L'; + scsi_cmdbuf[pos++] = 'E'; + scsi_cmdbuf[pos++] = ' '; + scsi_cmdbuf[pos++] = 'C'; + scsi_cmdbuf[pos++] = 'O'; + scsi_cmdbuf[pos++] = 'M'; + scsi_cmdbuf[pos++] = 'P'; + scsi_cmdbuf[pos++] = 'U'; + scsi_cmdbuf[pos++] = 'T'; + scsi_cmdbuf[pos++] = 'E'; + scsi_cmdbuf[pos++] = 'R'; + scsi_cmdbuf[pos++] = ','; + scsi_cmdbuf[pos++] = ' '; + scsi_cmdbuf[pos++] = 'I'; + scsi_cmdbuf[pos++] = 'N'; + scsi_cmdbuf[pos++] = 'C'; + scsi_cmdbuf[pos++] = ' '; + scsi_cmdbuf[pos++] = ' '; + scsi_cmdbuf[pos++] = ' '; + break; + } + + default: + logerror("%s: mode sense page %02x unhandled\n", tag(), page); + break; + } + } + scsi_cmdbuf[0] = pos; + if(pos > size) + pos = size; + + scsi_data_in(0, pos); + scsi_status_complete(SS_GOOD); + break; + } + + case SC_START_STOP_UNIT: + logerror("%s: command START STOP UNIT\n", tag()); + scsi_status_complete(SS_GOOD); + break; + + case SC_READ_CAPACITY: { + logerror("%s: command READ CAPACITY\n", tag()); + + hard_disk_info *info = hard_disk_get_info(harddisk); + UINT32 size = info->cylinders * info->heads * info->sectors - 1; + + scsi_cmdbuf[0] = (size>>24) & 0xff; + scsi_cmdbuf[1] = (size>>16) & 0xff; + scsi_cmdbuf[2] = (size>>8) & 0xff; + scsi_cmdbuf[3] = (size & 0xff); + scsi_cmdbuf[4] = (info->sectorbytes>>24)&0xff; + scsi_cmdbuf[5] = (info->sectorbytes>>16)&0xff; + scsi_cmdbuf[6] = (info->sectorbytes>>8)&0xff; + scsi_cmdbuf[7] = (info->sectorbytes & 0xff); + + scsi_data_in(0, 8); + scsi_status_complete(SS_GOOD); + break; + } + + case SC_READ_10: + lba = (scsi_cmdbuf[2]<<24) | (scsi_cmdbuf[3]<<16) | (scsi_cmdbuf[4]<<8) | scsi_cmdbuf[5]; + blocks = (scsi_cmdbuf[7] << 8) | scsi_cmdbuf[8]; + + logerror("%s: command READ EXTENDED start=%08x blocks=%04x\n", + tag(), lba, blocks); + + scsi_data_in(2, blocks*bytes_per_sector); + scsi_status_complete(SS_GOOD); + break; + + case SC_WRITE_10: + lba = (scsi_cmdbuf[2]<<24) | (scsi_cmdbuf[3]<<16) | (scsi_cmdbuf[4]<<8) | scsi_cmdbuf[5]; + blocks = (scsi_cmdbuf[7] << 8) | scsi_cmdbuf[8]; + + logerror("%s: command WRITE EXTENDED start=%08x blocks=%04x\n", + tag(), lba, blocks); + + scsi_data_out(2, blocks*bytes_per_sector); + scsi_status_complete(SS_GOOD); + break; + + default: + logerror("%s: command %02x ***UNKNOWN***\n", tag(), scsi_cmdbuf[0]); + nscsi_full_device::scsi_command(); + break; + } +} diff --git a/src/devices/machine/nscsi_hd.h b/src/devices/machine/nscsi_hd.h new file mode 100644 index 00000000000..855c125294d --- /dev/null +++ b/src/devices/machine/nscsi_hd.h @@ -0,0 +1,33 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +#ifndef __NSCSI_HD_H__ +#define __NSCSI_HD_H__ + +#include "machine/nscsi_bus.h" +#include "harddisk.h" + +class nscsi_harddisk_device : public nscsi_full_device +{ +public: + nscsi_harddisk_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + nscsi_harddisk_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + virtual machine_config_constructor device_mconfig_additions() const; + +protected: + virtual void device_start(); + virtual void device_reset(); + + virtual void scsi_command(); + virtual UINT8 scsi_get_data(int id, int pos); + virtual void scsi_put_data(int buf, int offset, UINT8 data); + + UINT8 block[512]; + hard_disk_file *harddisk; + int lba, cur_lba, blocks; + int bytes_per_sector; +}; + +extern const device_type NSCSI_HARDDISK; + +#endif diff --git a/src/devices/machine/nscsi_s1410.c b/src/devices/machine/nscsi_s1410.c new file mode 100644 index 00000000000..b486b4994e9 --- /dev/null +++ b/src/devices/machine/nscsi_s1410.c @@ -0,0 +1,151 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +#include "machine/nscsi_s1410.h" + +const device_type NSCSI_S1410 = &device_creator; + +nscsi_s1410_device::nscsi_s1410_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + nscsi_harddisk_device(mconfig, NSCSI_S1410, "S1410", tag, owner, clock, "scsi_s1410", __FILE__) +{ +} + +void nscsi_s1410_device::device_reset() +{ + nscsi_harddisk_device::device_reset(); + + // initialize drive characteristics + params[0] = 0; + params[1] = 153; + params[2] = 4; + params[3] = 0; + params[4] = 128; + params[5] = 0; + params[6] = 64; + params[7] = 11; +} + +void nscsi_s1410_device::scsi_command() +{ + switch(scsi_cmdbuf[0]) { + case SC_TEST_UNIT_READY: + case SC_REZERO: + case SC_REQUEST_SENSE: + case SC_REASSIGN_BLOCKS: + case SC_READ: + case SC_WRITE: + case SC_SEEK: + if (scsi_cmdbuf[1] >> 5) { + scsi_status_complete(SS_NOT_READY); + } else { + nscsi_harddisk_device::scsi_command(); + } + break; + + case SC_FORMAT_UNIT: + if (scsi_cmdbuf[1] >> 5) { + scsi_status_complete(SS_NOT_READY); + return; + } + + scsi_status_complete(SS_GOOD); + break; + + case SC_FORMAT_TRACK: { + if (scsi_cmdbuf[1] >> 5) { + scsi_status_complete(SS_NOT_READY); + return; + } + + lba = ((scsi_cmdbuf[1] & 0x1f)<<16) | (scsi_cmdbuf[2]<<8) | scsi_cmdbuf[3]; + blocks = (bytes_per_sector == 256) ? 32 : 17; + + int track_length = blocks*bytes_per_sector; + dynamic_buffer data(track_length); + memset(&data[0], 0xc6, track_length); + + if(!hard_disk_write(harddisk, lba, &data[0])) { + logerror("%s: HD WRITE ERROR !\n", tag()); + scsi_status_complete(SS_FORMAT_ERROR); + } else { + scsi_status_complete(SS_GOOD); + } + } + break; + + case SC_FORMAT_ALT_TRACK: + if (scsi_cmdbuf[1] >> 5) { + scsi_status_complete(SS_NOT_READY); + return; + } + + scsi_data_in(2, 3); + scsi_status_complete(SS_GOOD); + break; + + case SC_INIT_DRIVE_PARAMS: + scsi_data_in(2, 8); + scsi_status_complete(SS_GOOD); + break; + + case SC_WRITE_SECTOR_BUFFER: + scsi_data_in(2, 512); + scsi_status_complete(SS_GOOD); + break; + + case SC_READ_SECTOR_BUFFER: + scsi_data_out(2, 512); + scsi_status_complete(SS_GOOD); + break; + + case SC_CHECK_TRACK_FORMAT: + if (scsi_cmdbuf[1] >> 5) { + scsi_status_complete(SS_NOT_READY); + return; + } + scsi_status_complete(SS_GOOD); + break; + + case SC_READ_ECC_BURST: + case SC_RAM_DIAG: + case SC_DRIVE_DIAG: + case SC_CONTROLLER_DIAG: + case SC_READ_LONG: + case SC_WRITE_LONG: + scsi_status_complete(SS_GOOD); + break; + + default: + logerror("%s: command %02x ***UNKNOWN***\n", tag(), scsi_cmdbuf[0]); + break; + } +} + +UINT8 nscsi_s1410_device::scsi_get_data(int id, int pos) +{ + switch(scsi_cmdbuf[0]) { + case SC_READ_SECTOR_BUFFER: + return block[pos]; + + default: + return nscsi_harddisk_device::scsi_get_data(id, pos); + } +} + +void nscsi_s1410_device::scsi_put_data(int id, int pos, UINT8 data) +{ + switch(scsi_cmdbuf[0]) { + case SC_FORMAT_ALT_TRACK: + break; + + case SC_INIT_DRIVE_PARAMS: + params[pos] = data; + break; + + case SC_WRITE_SECTOR_BUFFER: + block[pos] = data; + break; + + default: + return nscsi_harddisk_device::scsi_put_data(id, pos, data); + } +} diff --git a/src/devices/machine/nscsi_s1410.h b/src/devices/machine/nscsi_s1410.h new file mode 100644 index 00000000000..f9dc2707887 --- /dev/null +++ b/src/devices/machine/nscsi_s1410.h @@ -0,0 +1,76 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +#ifndef __NSCSI_S1410_H__ +#define __NSCSI_S1410_H__ + +#include "machine/nscsi_bus.h" +#include "machine/nscsi_hd.h" + +class nscsi_s1410_device : public nscsi_harddisk_device +{ +public: + nscsi_s1410_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // SCSI status returns + enum { + SS_GOOD = 0x00, + SS_NO_INDEX = 0x01, + SS_NO_SEEK_COMPLETE = 0x02, + SS_WRITE_FAULT = 0x03, + SS_NOT_READY = 0x04, + SS_TK00_NOT_FOUND = 0x06, + SS_SEEK_IN_PROGRESS = 0x08, + SS_ID_FIELD_ERROR = 0x10, + SS_DATA_ERROR = 0x11, + SS_SAM_NOT_FOUND = 0x12, + SS_SECTOR_NOT_FOUND = 0x14, + SS_SEEK_ERROR = 0x15, + SS_ECC = 0x18, + SS_BAD_TRACK = 0x19, + SS_FORMAT_ERROR = 0x1a, + SS_ALT_TRACK = 0x1c, + SS_ALT_TRACK_DEFECT = 0x1d, + SS_ALT_TRACK_NOT_FOUND = 0x1e, + SS_ALT_TRACK_SAME = 0x1f, + SS_RAM_ERROR = 0x30, + SS_ROM_ERROR = 0x31, + SS_ECC_CHECK_FAILURE = 0x32 + }; + + // SCSI commands + enum { + SC_TEST_UNIT_READY = 0x00, + SC_REZERO = 0x01, + SC_REQUEST_SENSE = 0x03, + SC_FORMAT_UNIT = 0x04, + SC_CHECK_TRACK_FORMAT = 0x05, + SC_FORMAT_TRACK = 0x06, + SC_REASSIGN_BLOCKS = 0x07, + SC_READ = 0x08, + SC_WRITE = 0x0a, + SC_SEEK = 0x0b, + SC_INIT_DRIVE_PARAMS = 0x0c, + SC_READ_ECC_BURST = 0x0d, + SC_FORMAT_ALT_TRACK = 0x0e, + SC_WRITE_SECTOR_BUFFER = 0x0f, + SC_READ_SECTOR_BUFFER = 0x10, + SC_RAM_DIAG = 0xe0, + SC_DRIVE_DIAG = 0xe3, + SC_CONTROLLER_DIAG = 0xe4, + SC_READ_LONG = 0xe5, + SC_WRITE_LONG = 0xe6 + }; + + virtual void device_reset(); + + virtual void scsi_command(); + virtual UINT8 scsi_get_data(int id, int pos); + virtual void scsi_put_data(int buf, int offset, UINT8 data); + + UINT8 params[8]; +}; + +extern const device_type NSCSI_S1410; + +#endif diff --git a/src/devices/machine/nvram.c b/src/devices/machine/nvram.c new file mode 100644 index 00000000000..a1c9d734e2e --- /dev/null +++ b/src/devices/machine/nvram.c @@ -0,0 +1,181 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + nvram.c + + Generic non-volatile RAM. + +***************************************************************************/ + +#include "emu.h" +#include "machine/nvram.h" + + +// for now, make buggy GCC/Mingw STFU about I64FMT +#if (defined(__MINGW32__) && (__GNUC__ >= 5)) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wformat" +#pragma GCC diagnostic ignored "-Wformat-extra-args" +#endif + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +// device type definition +const device_type NVRAM = &device_creator; + +//------------------------------------------------- +// nvram_device - constructor +//------------------------------------------------- + +nvram_device::nvram_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, NVRAM, "NVRAM", tag, owner, clock, "nvram", __FILE__), + device_nvram_interface(mconfig, *this), + m_default_value(DEFAULT_ALL_1), + m_base(NULL), + m_length(0) +{ +} + + +//------------------------------------------------- +// static_set_interface - configuration helper +// to set the interface +//------------------------------------------------- + +void nvram_device::static_set_default_value(device_t &device, default_value value) +{ + nvram_device &nvram = downcast(device); + nvram.m_default_value = value; +} + + +//------------------------------------------------- +// static_set_custom_handler - configuration +// helper to set a custom callback +//------------------------------------------------- + +void nvram_device::static_set_custom_handler(device_t &device, nvram_init_delegate handler) +{ + nvram_device &nvram = downcast(device); + nvram.m_default_value = DEFAULT_CUSTOM; + nvram.m_custom_handler = handler; +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void nvram_device::device_start() +{ + // bind our handler + m_custom_handler.bind_relative_to(*owner()); +} + + +//------------------------------------------------- +// nvram_default - called to initialize NVRAM to +// its default state +//------------------------------------------------- + +void nvram_device::nvram_default() +{ + // make sure we have a valid base pointer + determine_final_base(); + + // region always wins + if (m_region != NULL) + { + memcpy(m_base, m_region->base(), m_length); + return; + } + + // default values for other cases + switch (m_default_value) + { + // all-0's + case DEFAULT_ALL_0: + memset(m_base, 0, m_length); + break; + + // all 1's + default: + case DEFAULT_ALL_1: + memset(m_base, 0xff, m_length); + break; + + // random values + case DEFAULT_RANDOM: + { + UINT8 *nvram = reinterpret_cast(m_base); + for (int index = 0; index < m_length; index++) + nvram[index] = machine().rand(); + break; + } + + // custom handler + case DEFAULT_CUSTOM: + m_custom_handler(*this, m_base, m_length); + break; + + // none - do nothing + case DEFAULT_NONE: + break; + } +} + + +//------------------------------------------------- +// nvram_read - called to read NVRAM from the +// .nv file +//------------------------------------------------- + +void nvram_device::nvram_read(emu_file &file) +{ + // make sure we have a valid base pointer + determine_final_base(); + + file.read(m_base, m_length); +} + + +//------------------------------------------------- +// nvram_write - called to write NVRAM to the +// .nv file +//------------------------------------------------- + +void nvram_device::nvram_write(emu_file &file) +{ + file.write(m_base, m_length); +} + + +//------------------------------------------------- +// determine_final_base - get the final base +// pointer by looking up the memory share, unless +// a pointer was provided to us +//------------------------------------------------- + +void nvram_device::determine_final_base() +{ + // find our shared pointer with the target RAM + if (m_base == NULL) + { + memory_share *share = owner()->memshare(tag()); + if (share == NULL) + throw emu_fatalerror("NVRAM device '%s' has no corresponding AM_SHARE region", tag()); + m_base = share->ptr(); + m_length = share->bytes(); + } + + // if we are region-backed for the default, find it now and make sure it's the right size + if (m_region != NULL && m_region->bytes() != m_length) + throw emu_fatalerror("NVRAM device '%s' has a default region, but it should be 0x%" SIZETFMT "X bytes", tag(), m_length); +} + +#if (defined(__MINGW32__) && (__GNUC__ >= 5)) +#pragma GCC diagnostic pop +#endif diff --git a/src/devices/machine/nvram.h b/src/devices/machine/nvram.h new file mode 100644 index 00000000000..10c3954a83c --- /dev/null +++ b/src/devices/machine/nvram.h @@ -0,0 +1,115 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + nvram.h + + Generic non-volatile RAM. + +***************************************************************************/ + +#pragma once + +#ifndef __NVRAM_H__ +#define __NVRAM_H__ + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_NVRAM_ADD_0FILL(_tag) \ + MCFG_DEVICE_ADD(_tag, NVRAM, 0) \ + nvram_device::static_set_default_value(*device, nvram_device::DEFAULT_ALL_0); +#define MCFG_NVRAM_ADD_1FILL(_tag) \ + MCFG_DEVICE_ADD(_tag, NVRAM, 0) \ + nvram_device::static_set_default_value(*device, nvram_device::DEFAULT_ALL_1); +#define MCFG_NVRAM_ADD_RANDOM_FILL(_tag) \ + MCFG_DEVICE_ADD(_tag, NVRAM, 0) \ + nvram_device::static_set_default_value(*device, nvram_device::DEFAULT_RANDOM); +#define MCFG_NVRAM_ADD_NO_FILL(_tag) \ + MCFG_DEVICE_ADD(_tag, NVRAM, 0) \ + nvram_device::static_set_default_value(*device, nvram_device::DEFAULT_NONE); +#define MCFG_NVRAM_ADD_CUSTOM_DRIVER(_tag, _class, _method) \ + MCFG_DEVICE_ADD(_tag, NVRAM, 0) \ + nvram_device::static_set_custom_handler(*device, nvram_init_delegate(&_class::_method, #_class "::" #_method, NULL, (_class *)0)); + +#define MCFG_NVRAM_REPLACE_0FILL(_tag) \ + MCFG_DEVICE_REPLACE(_tag, NVRAM, 0) \ + nvram_device::static_set_default_value(*device, nvram_device::DEFAULT_ALL_0); +#define MCFG_NVRAM_REPLACE_1FILL(_tag) \ + MCFG_DEVICE_REPLACE(_tag, NVRAM, 0) \ + nvram_device::static_set_default_value(*device, nvram_device::DEFAULT_ALL_1); +#define MCFG_NVRAM_REPLACE_RANDOM_FILL(_tag) \ + MCFG_DEVICE_REPLACE(_tag, NVRAM, 0) \ + nvram_device::static_set_default_value(*device, nvram_device::DEFAULT_RANDOM); +#define MCFG_NVRAM_REPLACE_CUSTOM_DRIVER(_tag, _class, _method) \ + MCFG_DEVICE_REPLACE(_tag, NVRAM, 0) \ + nvram_device::static_set_custom_handler(*device, nvram_init_delegate(&_class::_method, #_class "::" #_method, NULL, (_class *)0)); + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class nvram_device; + + +// custom initialization for default state +typedef device_delegate nvram_init_delegate; + + +// ======================> nvram_device + +class nvram_device : public device_t, + public device_nvram_interface +{ +public: + // values + enum default_value + { + DEFAULT_ALL_0, + DEFAULT_ALL_1, + DEFAULT_RANDOM, + DEFAULT_CUSTOM, + DEFAULT_NONE + }; + + // construction/destruction + nvram_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // inline configuration helpers + static void static_set_default_value(device_t &device, default_value value); + static void static_set_custom_handler(device_t &device, nvram_init_delegate callback); + + // controls + void set_base(void *base, size_t length) { m_base = base; m_length = length; } + +protected: + // device-level overrides + virtual void device_start(); + + // device_nvram_interface overrides + virtual void nvram_default(); + virtual void nvram_read(emu_file &file); + virtual void nvram_write(emu_file &file); + + // internal helpers + void determine_final_base(); + + // configuration state + default_value m_default_value; + nvram_init_delegate m_custom_handler; + + // runtime state + void * m_base; + size_t m_length; +}; + + +// device type definition +extern const device_type NVRAM; + + +#endif diff --git a/src/devices/machine/pc_fdc.c b/src/devices/machine/pc_fdc.c new file mode 100644 index 00000000000..5c56a53d3d6 --- /dev/null +++ b/src/devices/machine/pc_fdc.c @@ -0,0 +1,192 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +/********************************************************************** + + PC-style floppy disk controller emulation + + TODO: + - check how the drive select from DOR register, and the drive select + from the fdc are related !!!! + - if all drives do not have a disk in them, and the fdc is reset, is a int generated? + (if yes, indicates drives are ready without discs, if no indicates no drives are ready) + - status register a, status register b + +**********************************************************************/ + +#include "emu.h" +#include "machine/pc_fdc.h" + +const device_type PC_FDC_XT = &device_creator; +const device_type PC_FDC_AT = &device_creator; + +static MACHINE_CONFIG_FRAGMENT( cfg ) + MCFG_UPD765A_ADD("upd765", false, false) + MCFG_UPD765_INTRQ_CALLBACK(WRITELINE(pc_fdc_family_device, irq_w)) + MCFG_UPD765_DRQ_CALLBACK(WRITELINE(pc_fdc_family_device, drq_w)) +MACHINE_CONFIG_END + +DEVICE_ADDRESS_MAP_START(map, 8, pc_fdc_family_device) +ADDRESS_MAP_END + +// The schematics show address decoding is minimal +DEVICE_ADDRESS_MAP_START(map, 8, pc_fdc_xt_device) + AM_RANGE(0x0, 0x0) AM_DEVREAD("upd765", upd765a_device, msr_r) AM_WRITE(dor_w) + AM_RANGE(0x1, 0x1) AM_DEVREAD("upd765", upd765a_device, fifo_r) AM_WRITE(dor_fifo_w) + AM_RANGE(0x2, 0x2) AM_WRITE(dor_w) + AM_RANGE(0x3, 0x3) AM_WRITE(dor_w) + AM_RANGE(0x4, 0x5) AM_DEVICE("upd765", upd765a_device, map) +ADDRESS_MAP_END + + +// Decoding is through a PAL, so presumably complete +DEVICE_ADDRESS_MAP_START(map, 8, pc_fdc_at_device) + AM_RANGE(0x2, 0x2) AM_READWRITE(dor_r, dor_w) + AM_RANGE(0x4, 0x5) AM_DEVICE("upd765", upd765a_device, map) + AM_RANGE(0x7, 0x7) AM_READWRITE(dir_r, ccr_w) +ADDRESS_MAP_END + +pc_fdc_family_device::pc_fdc_family_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + pc_fdc_interface(mconfig, type, name, tag, owner, clock, shortname, source), fdc(*this, "upd765"), + intrq_cb(*this), + drq_cb(*this) +{ +} + +void pc_fdc_family_device::tc_w(bool state) +{ + fdc->tc_w(state); +} + +UINT8 pc_fdc_family_device::dma_r() +{ + return fdc->dma_r(); +} + +void pc_fdc_family_device::dma_w(UINT8 data) +{ + fdc->dma_w(data); +} + +machine_config_constructor pc_fdc_family_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME(cfg); +} + +void pc_fdc_family_device::device_start() +{ + intrq_cb.resolve(); + drq_cb.resolve(); + + for(int i=0; i<4; i++) { + char name[2] = {'0'+i, 0}; + floppy_connector *conn = subdevice(name); + floppy[i] = conn ? conn->get_device() : NULL; + } + + irq = drq = false; + fdc_irq = fdc_drq = false; + dor = 0x00; +} + +void pc_fdc_family_device::device_reset() +{ +} + +// Bits 0-1 select one of the 4 drives, but only if the associated +// motor bit is on + +// Bit 2 is tied to the upd765 reset line + +// Bit 3 enables the irq and drq lines + +// Bit 4-7 control the drive motors + +WRITE8_MEMBER( pc_fdc_family_device::dor_w ) +{ + logerror("%s: dor = %02x\n", tag(), data); + UINT8 pdor = dor; + dor = data; + + for(int i=0; i<4; i++) + if(floppy[i]) + floppy[i]->mon_w(!(dor & (0x10 << i))); + + int fid = dor & 3; + if(dor & (0x10 << fid)) + fdc->set_floppy(floppy[fid]); + else + fdc->set_floppy(NULL); + + check_irq(); + check_drq(); + if((pdor^dor) & 4) + fdc->reset(); +} + +READ8_MEMBER( pc_fdc_family_device::dor_r ) +{ + return dor; +} + +READ8_MEMBER( pc_fdc_family_device::dir_r ) +{ + return do_dir_r(); +} + +WRITE8_MEMBER( pc_fdc_family_device::ccr_w ) +{ + static const int rates[4] = { 500000, 300000, 250000, 1000000 }; + logerror("%s: ccr = %02x\n", tag(), data); + fdc->set_rate(rates[data & 3]); +} + +UINT8 pc_fdc_family_device::do_dir_r() +{ + if(floppy[dor & 3]) + return floppy[dor & 3]->dskchg_r() ? 0x00 : 0x80; + return 0x00; +} + +WRITE8_MEMBER( pc_fdc_xt_device::dor_fifo_w) +{ + fdc->fifo_w(space, 0, data, mem_mask); + dor_w(space, 0, data, mem_mask); +} + +WRITE_LINE_MEMBER( pc_fdc_family_device::irq_w ) +{ + fdc_irq = state; + check_irq(); +} + +WRITE_LINE_MEMBER( pc_fdc_family_device::drq_w ) +{ + fdc_drq = state; + check_drq(); +} + +void pc_fdc_family_device::check_irq() +{ + bool pirq = irq; + irq = fdc_irq && (dor & 4) && (dor & 8); + if(irq != pirq && !intrq_cb.isnull()) { + logerror("%s: pc_irq = %d\n", tag(), irq); + intrq_cb(irq); + } +} + +void pc_fdc_family_device::check_drq() +{ + bool pdrq = drq; + drq = fdc_drq && (dor & 4) && (dor & 8); + if(drq != pdrq && !drq_cb.isnull()) + drq_cb(drq); +} + +pc_fdc_xt_device::pc_fdc_xt_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : pc_fdc_family_device(mconfig, PC_FDC_XT, "PC FDC XT", tag, owner, clock, "pc_fdc_xt", __FILE__) +{ +} + +pc_fdc_at_device::pc_fdc_at_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : pc_fdc_family_device(mconfig, PC_FDC_AT, "PC FDC AT", tag, owner, clock, "pc_fdc_at", __FILE__) +{ +} diff --git a/src/devices/machine/pc_fdc.h b/src/devices/machine/pc_fdc.h new file mode 100644 index 00000000000..159bb89a59b --- /dev/null +++ b/src/devices/machine/pc_fdc.h @@ -0,0 +1,83 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +/********************************************************************** + + PC-style floppy disk controller emulation + +**********************************************************************/ + +#ifndef PC_FDC_H +#define PC_FDC_H + +#include "emu.h" +#include "machine/upd765.h" + +#define MCFG_PC_FDC_XT_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, PC_FDC_XT, 0) + +#define MCFG_PC_FDC_AT_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, PC_FDC_AT, 0) + +#define MCFG_PC_FDC_INTRQ_CALLBACK(_write) \ + devcb = &pc_fdc_family_device::set_intrq_wr_callback(*device, DEVCB_##_write); + +#define MCFG_PC_FDC_DRQ_CALLBACK(_write) \ + devcb = &pc_fdc_family_device::set_drq_wr_callback(*device, DEVCB_##_write); + +class pc_fdc_family_device : public pc_fdc_interface { +public: + pc_fdc_family_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + template static devcb_base &set_intrq_wr_callback(device_t &device, _Object object) { return downcast(device).intrq_cb.set_callback(object); } + template static devcb_base &set_drq_wr_callback(device_t &device, _Object object) { return downcast(device).drq_cb.set_callback(object); } + + required_device fdc; + + virtual DECLARE_ADDRESS_MAP(map, 8); + + virtual void tc_w(bool state); + virtual UINT8 dma_r(); + virtual void dma_w(UINT8 data); + virtual UINT8 do_dir_r(); + + READ8_MEMBER(dor_r); + WRITE8_MEMBER(dor_w); + READ8_MEMBER(dir_r); + WRITE8_MEMBER(ccr_w); + DECLARE_WRITE_LINE_MEMBER( irq_w ); + DECLARE_WRITE_LINE_MEMBER( drq_w ); + +protected: + virtual void device_start(); + virtual void device_reset(); + virtual machine_config_constructor device_mconfig_additions() const; + + bool irq, drq, fdc_drq, fdc_irq; + devcb_write_line intrq_cb, drq_cb; + UINT8 dor; + + floppy_image_device *floppy[4]; + + void check_irq(); + void check_drq(); +}; + +class pc_fdc_xt_device : public pc_fdc_family_device { +public: + pc_fdc_xt_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual DECLARE_ADDRESS_MAP(map, 8); + WRITE8_MEMBER(dor_fifo_w); +}; + +class pc_fdc_at_device : public pc_fdc_family_device { +public: + pc_fdc_at_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual DECLARE_ADDRESS_MAP(map, 8); +}; + +extern const device_type PC_FDC_XT; +extern const device_type PC_FDC_AT; + +#endif /* PC_FDC_H */ diff --git a/src/devices/machine/pc_lpt.c b/src/devices/machine/pc_lpt.c new file mode 100644 index 00000000000..319a5cb0a2c --- /dev/null +++ b/src/devices/machine/pc_lpt.c @@ -0,0 +1,163 @@ +// license:BSD-3-Clause +// copyright-holders:Dirk Best +/*************************************************************************** + + IBM-PC printer interface + +***************************************************************************/ + +#include "emu.h" +#include "pc_lpt.h" + + +const device_type PC_LPT = &device_creator; + +pc_lpt_device::pc_lpt_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, PC_LPT, "PC-LPT", tag, owner, clock, "pc_lpt", __FILE__), + m_irq(1), + m_data(0xff), + m_irq_enabled(1), + m_centronics_ack(1), + m_irq_handler(*this), + m_cent_data_in(*this, "cent_data_in"), + m_cent_data_out(*this, "cent_data_out"), + m_cent_status_in(*this, "cent_status_in"), + m_cent_ctrl_in(*this, "cent_ctrl_in"), + m_cent_ctrl_out(*this, "cent_ctrl_out") +{ +} + +void pc_lpt_device::device_start() +{ + m_irq_handler.resolve_safe(); + + save_item(NAME(m_irq)); + save_item(NAME(m_data)); + save_item(NAME(m_control)); + save_item(NAME(m_centronics_ack)); + save_item(NAME(m_irq_enabled)); + + m_cent_data_out->write(m_data); +} + +void pc_lpt_device::device_reset() +{ + m_control = ~(0 ^ CONTROL_INIT); + m_cent_ctrl_out->write(m_control); +} + +static MACHINE_CONFIG_FRAGMENT( pc_lpt ) + MCFG_CENTRONICS_ADD("centronics", centronics_devices, "printer") + MCFG_CENTRONICS_DATA_INPUT_BUFFER("cent_data_in") + MCFG_CENTRONICS_FAULT_HANDLER(DEVWRITELINE("cent_status_in", input_buffer_device, write_bit3)) + MCFG_CENTRONICS_SELECT_HANDLER(DEVWRITELINE("cent_status_in", input_buffer_device, write_bit4)) + MCFG_CENTRONICS_PERROR_HANDLER(DEVWRITELINE("cent_status_in", input_buffer_device, write_bit5)) + MCFG_CENTRONICS_ACK_HANDLER(WRITELINE(pc_lpt_device, write_centronics_ack)) + MCFG_CENTRONICS_BUSY_HANDLER(DEVWRITELINE("cent_status_in", input_buffer_device, write_bit7)) + + MCFG_CENTRONICS_STROBE_HANDLER(DEVWRITELINE("cent_ctrl_in", input_buffer_device, write_bit0)) + MCFG_CENTRONICS_AUTOFD_HANDLER(DEVWRITELINE("cent_ctrl_in", input_buffer_device, write_bit1)) + MCFG_CENTRONICS_INIT_HANDLER(DEVWRITELINE("cent_ctrl_in", input_buffer_device, write_bit2)) + MCFG_CENTRONICS_SELECT_IN_HANDLER(DEVWRITELINE("cent_ctrl_in", input_buffer_device, write_bit3)) + + MCFG_DEVICE_ADD("cent_data_in", INPUT_BUFFER, 0) + MCFG_DEVICE_ADD("cent_ctrl_in", INPUT_BUFFER, 0) + MCFG_DEVICE_ADD("cent_status_in", INPUT_BUFFER, 0) + + MCFG_CENTRONICS_OUTPUT_LATCH_ADD("cent_data_out", "centronics") + + MCFG_DEVICE_ADD("cent_ctrl_out", OUTPUT_LATCH, 0) + MCFG_OUTPUT_LATCH_BIT0_HANDLER(DEVWRITELINE("centronics", centronics_device, write_strobe)) + MCFG_OUTPUT_LATCH_BIT1_HANDLER(DEVWRITELINE("centronics", centronics_device, write_autofd)) + MCFG_OUTPUT_LATCH_BIT2_HANDLER(DEVWRITELINE("centronics", centronics_device, write_init)) + MCFG_OUTPUT_LATCH_BIT3_HANDLER(DEVWRITELINE("centronics", centronics_device, write_select_in)) + MCFG_OUTPUT_LATCH_BIT4_HANDLER(WRITELINE(pc_lpt_device, write_irq_enabled)) +MACHINE_CONFIG_END + +machine_config_constructor pc_lpt_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( pc_lpt ); +} + +READ8_MEMBER( pc_lpt_device::data_r ) +{ + // pull up mechanism for input lines, zeros are provided by peripheral + return m_data & m_cent_data_in->read(); +} + +WRITE8_MEMBER( pc_lpt_device::data_w ) +{ + m_data = data; + m_cent_data_out->write(m_data); +} + +READ8_MEMBER( pc_lpt_device::status_r ) +{ + return m_cent_status_in->read() ^ STATUS_BUSY; +} + +READ8_MEMBER( pc_lpt_device::control_r ) +{ + return ~((m_control & m_cent_ctrl_in->read() & 0x3f) ^ CONTROL_INIT); +} + +WRITE8_MEMBER( pc_lpt_device::control_w ) +{ + // logerror("pc_lpt_control_w: 0x%02x\n", data); + + m_control = ~(data ^ CONTROL_INIT); + m_cent_ctrl_out->write(m_control); +} + +READ8_MEMBER( pc_lpt_device::read ) +{ + switch (offset) + { + case 0: return data_r(space, 0); + case 1: return status_r(space, 0); + case 2: return control_r(space, 0); + } + + /* if we reach this its an error */ + logerror("PC-LPT %s: Read from invalid offset %x\n", tag(), offset); + + return 0xff; +} + +WRITE8_MEMBER( pc_lpt_device::write ) +{ + switch (offset) + { + case 0: data_w(space, 0, data); break; + case 1: break; + case 2: control_w(space, 0, data); break; + } +} + +void pc_lpt_device::update_irq() +{ + int irq = 1; // high impedance + if (!m_irq_enabled) + { + irq = m_centronics_ack; + } + + if (m_irq != irq) + { + m_irq = irq; + m_irq_handler(!irq); + } +} + +WRITE_LINE_MEMBER( pc_lpt_device::write_irq_enabled ) +{ + m_irq_enabled = state; + update_irq(); +} + +WRITE_LINE_MEMBER( pc_lpt_device::write_centronics_ack ) +{ + m_centronics_ack = state; + m_cent_status_in->write_bit6(state); + update_irq(); +} diff --git a/src/devices/machine/pc_lpt.h b/src/devices/machine/pc_lpt.h new file mode 100644 index 00000000000..08de865ce94 --- /dev/null +++ b/src/devices/machine/pc_lpt.h @@ -0,0 +1,87 @@ +// license:BSD-3-Clause +// copyright-holders:Dirk Best +/*************************************************************************** + + IBM-PC printer interface + +***************************************************************************/ + +#ifndef __PC_LPT_H__ +#define __PC_LPT_H__ + +#include "bus/centronics/ctronics.h" + +#define MCFG_PC_LPT_IRQ_HANDLER(_devcb) \ + devcb = &pc_lpt_device::set_irq_handler(*device, DEVCB_##_devcb); + +/*************************************************************************** + DEVICE CONFIGURATION MACROS +***************************************************************************/ + +class pc_lpt_device : public device_t +{ +public: + pc_lpt_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // static configuration helpers + template static devcb_base &set_irq_handler(device_t &device, _Object object) { return downcast(device).m_irq_handler.set_callback(object); } + + DECLARE_READ8_MEMBER( read ); + DECLARE_WRITE8_MEMBER( write ); + + DECLARE_READ8_MEMBER( data_r ); + DECLARE_WRITE8_MEMBER( data_w ); + DECLARE_READ8_MEMBER( status_r ); + DECLARE_READ8_MEMBER( control_r ); + DECLARE_WRITE8_MEMBER( control_w ); + + DECLARE_WRITE_LINE_MEMBER( write_irq_enabled ); + DECLARE_WRITE_LINE_MEMBER( write_centronics_ack ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual machine_config_constructor device_mconfig_additions() const; + +private: + void update_irq(); + + enum + { + CONTROL_STROBE = 1, + CONTROL_AUTOFD = 2, + CONTROL_INIT = 4, + CONTROL_SELECT = 8, + CONTROL_IRQ_ENABLED = 16, + CONTROL_OUTPUT_ENABLED = 32 + }; + + enum + { + STATUS_FAULT = 8, + STATUS_SELECT = 16, + STATUS_PERROR = 32, + STATUS_ACK = 64, + STATUS_BUSY = 128 + }; + + // internal state + + int m_irq; + UINT8 m_data; + UINT8 m_control; + int m_irq_enabled; + int m_centronics_ack; + + devcb_write_line m_irq_handler; + required_device m_cent_data_in; + required_device m_cent_data_out; + required_device m_cent_status_in; + required_device m_cent_ctrl_in; + required_device m_cent_ctrl_out; +}; + +extern const device_type PC_LPT; + +#endif /* __PC_LPT__ */ diff --git a/src/devices/machine/pccard.c b/src/devices/machine/pccard.c new file mode 100644 index 00000000000..0d9887fa15f --- /dev/null +++ b/src/devices/machine/pccard.c @@ -0,0 +1,76 @@ +// license:BSD-3-Clause +// copyright-holders:smf +#include "pccard.h" + +READ16_MEMBER( pccard_interface::read_memory ) +{ + return 0xffff; +} + +WRITE16_MEMBER( pccard_interface::write_memory ) +{ +} + +READ16_MEMBER( pccard_interface::read_reg ) +{ + return 0xffff; +} + +WRITE16_MEMBER( pccard_interface::write_reg ) +{ +} + +const device_type PCCARD_SLOT = &device_creator; + +pccard_slot_device::pccard_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, PCCARD_SLOT, "PCCARD SLOT", tag, owner, clock, "pccard", __FILE__), + device_slot_interface(mconfig, *this), + m_pccard(NULL) +{ +} + +void pccard_slot_device::device_start() +{ + m_pccard = dynamic_cast(get_card_device()); +} + +READ_LINE_MEMBER(pccard_slot_device::read_line_inserted) +{ + return m_pccard != NULL; +} + +READ16_MEMBER( pccard_slot_device::read_memory ) +{ + if( m_pccard != NULL ) + { + return m_pccard->read_memory( space, offset, mem_mask ); + } + + return 0xffff; +} + +WRITE16_MEMBER( pccard_slot_device::write_memory ) +{ + if( m_pccard != NULL ) + { + m_pccard->write_memory( space, offset, data, mem_mask ); + } +} + +READ16_MEMBER( pccard_slot_device::read_reg ) +{ + if( m_pccard != NULL ) + { + return m_pccard->read_reg( space, offset, mem_mask ); + } + + return 0xffff; +} + +WRITE16_MEMBER( pccard_slot_device::write_reg ) +{ + if( m_pccard != NULL ) + { + m_pccard->write_reg( space, offset, data, mem_mask ); + } +} diff --git a/src/devices/machine/pccard.h b/src/devices/machine/pccard.h new file mode 100644 index 00000000000..7a7b9abd1ab --- /dev/null +++ b/src/devices/machine/pccard.h @@ -0,0 +1,43 @@ +// license:BSD-3-Clause +// copyright-holders:smf +#pragma once + +#ifndef __PCCARD_H__ +#define __PCCARD_H__ + +#include "emu.h" + +class pccard_interface +{ +public: + virtual DECLARE_READ16_MEMBER(read_memory); + virtual DECLARE_READ16_MEMBER(read_reg); + virtual DECLARE_WRITE16_MEMBER(write_memory); + virtual DECLARE_WRITE16_MEMBER(write_reg); + + virtual ~pccard_interface() {} +}; + +extern const device_type PCCARD_SLOT; + +class pccard_slot_device : public device_t, + public device_slot_interface +{ +public: + pccard_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + DECLARE_READ_LINE_MEMBER(read_line_inserted); + DECLARE_READ16_MEMBER(read_memory); + DECLARE_READ16_MEMBER(read_reg); + DECLARE_WRITE16_MEMBER(write_memory); + DECLARE_WRITE16_MEMBER(write_reg); + +protected: + virtual void device_start(); + +private: + // internal state + pccard_interface *m_pccard; +}; + +#endif diff --git a/src/devices/machine/pcf8593.c b/src/devices/machine/pcf8593.c new file mode 100644 index 00000000000..48e002fdf2d --- /dev/null +++ b/src/devices/machine/pcf8593.c @@ -0,0 +1,285 @@ +// license:BSD-3-Clause +// copyright-holders:Tim Schuerewegen +/********************************************************************* + + Philips PCF8593 CMOS clock/calendar circuit + + (c) 2001-2007 Tim Schuerewegen + +*********************************************************************/ + +#include "pcf8593.h" + + +/*************************************************************************** + PARAMETERS/CONSTANTS/MACROS +***************************************************************************/ + +#define LOG_LEVEL 1 +#define _logerror(level,x) do { if (LOG_LEVEL > level) logerror x; } while (0) + +// get/set date +#define RTC_GET_DATE_YEAR ((m_data[5] >> 6) & 3) +#define RTC_SET_DATE_YEAR(x) m_data[5] = (m_data[5] & 0x3F) | (((x) % 4) << 6) +#define RTC_GET_DATE_MONTH bcd_to_integer( m_data[6]) +#define RTC_SET_DATE_MONTH(x) m_data[6] = convert_to_bcd( x) +#define RTC_GET_DATE_DAY (bcd_to_integer( m_data[5] & 0x3F)) +#define RTC_SET_DATE_DAY(x) m_data[5] = (m_data[5] & 0xC0) | convert_to_bcd( x) + +// get/set time +#define RTC_GET_TIME_HOUR bcd_to_integer( m_data[4]) +#define RTC_SET_TIME_HOUR(x) m_data[4] = convert_to_bcd( x) +#define RTC_GET_TIME_MINUTE bcd_to_integer( m_data[3]) +#define RTC_SET_TIME_MINUTE(x) m_data[3] = convert_to_bcd( x) +#define RTC_GET_TIME_SECOND bcd_to_integer( m_data[2]) +#define RTC_SET_TIME_SECOND(x) m_data[2] = convert_to_bcd( x) + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type PCF8593 = &device_creator; + + +//------------------------------------------------- +// pcf8593_device - constructor +//------------------------------------------------- + +pcf8593_device::pcf8593_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, PCF8593, "PCF8593 RTC", tag, owner, clock, "pcf8593", __FILE__), + device_rtc_interface(mconfig, *this), + device_nvram_interface(mconfig, *this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void pcf8593_device::device_start() +{ + _logerror( 0, ("pcf8593_init\n")); + memset(m_register, 0, sizeof(m_register)); + m_timer = timer_alloc(TIMER_UPDATE_COUNTER); + m_timer->adjust(attotime::from_seconds(1), 0, attotime::from_seconds(1)); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void pcf8593_device::device_reset() +{ + _logerror( 0, ("pcf8593_reset\n")); + m_pin_scl = 1; + m_pin_sda = 1; + m_active = FALSE; + m_inp = 0; + m_mode = RTC_MODE_RECV; + m_bits = 0; + m_pos = 0; + clear_buffer_rx(); + set_time(true, RTC_GET_DATE_YEAR, RTC_GET_DATE_MONTH, RTC_GET_DATE_DAY, 0, RTC_GET_TIME_HOUR, RTC_GET_TIME_MINUTE, RTC_GET_TIME_SECOND); +} + + +//------------------------------------------------- +// device_timer - handler timer events +//------------------------------------------------- + +void pcf8593_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch(id) + { + case TIMER_UPDATE_COUNTER: + _logerror( 2, ("pcf8593_timer_callback (%d)\n", param)); + // check if counting is enabled + if (!(m_data[0] & 0x80)) + advance_seconds(); + break; + } +} + + +//------------------------------------------------- +// rtc_clock_updated - +//------------------------------------------------- + +void pcf8593_device::rtc_clock_updated(int year, int month, int day, int day_of_week, int hour, int minute, int second) +{ + RTC_SET_TIME_SECOND(second); + RTC_SET_TIME_MINUTE(minute); + RTC_SET_TIME_HOUR(hour); + RTC_SET_DATE_DAY(day); + RTC_SET_DATE_MONTH(month); + RTC_SET_DATE_YEAR(year); +} + + +//------------------------------------------------- +// nvram_default - called to initialize NVRAM to +// its default state +//------------------------------------------------- + +void pcf8593_device::nvram_default() +{ + memset(m_data, 0, sizeof(m_data)); +} + +//------------------------------------------------- +// nvram_read - called to read NVRAM from the +// .nv file +//------------------------------------------------- + +void pcf8593_device::nvram_read(emu_file &file) +{ + file.read(m_data, sizeof(m_data)); +} + + +//------------------------------------------------- +// nvram_write - called to write NVRAM to the +// .nv file +//------------------------------------------------- + +void pcf8593_device::nvram_write(emu_file &file) +{ + file.write(m_data, sizeof(m_data)); +} + + + +/*------------------------------------------------- + pcf8593_pin_scl +-------------------------------------------------*/ + +WRITE_LINE_MEMBER(pcf8593_device::scl_w) +{ + // send bit + if ((m_active) && (!m_pin_scl) && (state)) + { + switch (m_mode) + { + // HOST -> RTC + case RTC_MODE_RECV : + { + // get bit + if (m_pin_sda) m_data_recv[m_data_recv_index] = m_data_recv[m_data_recv_index] | (0x80 >> m_bits); + m_bits++; + // bit 9 = end + if (m_bits > 8) + { + _logerror( 2, ("pcf8593_write_byte(%02X)\n", m_data_recv[m_data_recv_index])); + // enter receive mode when 1st byte = 0xA3 + if ((m_data_recv[0] == 0xA3) && (m_data_recv_index == 0)) + { + m_mode = RTC_MODE_SEND; + } + // A2 + xx = "read from pos xx" command + if ((m_data_recv[0] == 0xA2) && (m_data_recv_index == 1)) + { + m_pos = m_data_recv[1]; + } + // A2 + xx + .. = write byte + if ((m_data_recv[0] == 0xA2) && (m_data_recv_index >= 2)) + { + UINT8 rtc_pos, rtc_val; + rtc_pos = m_data_recv[1] + (m_data_recv_index - 2); + rtc_val = m_data_recv[m_data_recv_index]; + //if (rtc_pos == 0) rtc_val = rtc_val & 3; // what is this doing here? + m_data[rtc_pos] = rtc_val; + set_time(false, RTC_GET_DATE_YEAR, RTC_GET_DATE_MONTH, RTC_GET_DATE_DAY, 0, RTC_GET_TIME_HOUR, RTC_GET_TIME_MINUTE, RTC_GET_TIME_SECOND); + } + // next byte + m_bits = 0; + m_data_recv_index++; + } + } + break; + // RTC -> HOST + case RTC_MODE_SEND : + { + // set bit + m_inp = (m_data[m_pos] >> (7 - m_bits)) & 1; + m_bits++; + // bit 9 = end + if (m_bits > 8) + { + _logerror( 2, ("pcf8593_read_byte(%02X)\n", m_data[m_pos])); + // end ? + if (m_pin_sda) + { + _logerror( 2, ("pcf8593 end\n")); + m_mode = RTC_MODE_RECV; + clear_buffer_rx(); + } + // next byte + m_bits = 0; + m_pos++; + } + } + break; + } + } + // save scl + m_pin_scl = state; +} + + + +/*------------------------------------------------- + pcf8593_pin_sda_w +-------------------------------------------------*/ + +WRITE_LINE_MEMBER(pcf8593_device::sda_w) +{ + // clock is high + if (m_pin_scl) + { + // log init I2C + if (state) _logerror( 1, ("pcf8593 init i2c\n")); + // start condition (high to low when clock is high) + if ((!state) && (m_pin_sda)) + { + _logerror( 1, ("pcf8593 start condition\n")); + m_active = TRUE; + m_bits = 0; + m_data_recv_index = 0; + clear_buffer_rx(); + //m_pos = 0; + } + // stop condition (low to high when clock is high) + if ((state) && (!m_pin_sda)) + { + _logerror( 1, ("pcf8593 stop condition\n")); + m_active = FALSE; + } + } + // save sda + m_pin_sda = state; +} + + + +/*------------------------------------------------- + pcf8593_pin_sda_r +-------------------------------------------------*/ + +READ_LINE_MEMBER(pcf8593_device::sda_r) +{ + return m_inp; +} + + + +/*------------------------------------------------- + pcf8593_clear_buffer_rx +-------------------------------------------------*/ + +void pcf8593_device::clear_buffer_rx() +{ + memset(&m_data_recv[0], 0, sizeof( m_data_recv)); + m_data_recv_index = 0; +} diff --git a/src/devices/machine/pcf8593.h b/src/devices/machine/pcf8593.h new file mode 100644 index 00000000000..2475f0a2dfe --- /dev/null +++ b/src/devices/machine/pcf8593.h @@ -0,0 +1,79 @@ +// license:BSD-3-Clause +// copyright-holders:Tim Schuerewegen +/********************************************************************* + + Philips PCF8593 CMOS clock/calendar circuit + + (c) 2001-2007 Tim Schuerewegen + +*********************************************************************/ + +#ifndef __PCF8593_H__ +#define __PCF8593_H__ + +#include "emu.h" + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_PCF8593_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, PCF8593, 0) + +#define MCFG_PCF8593_REMOVE(_tag) \ + MCFG_DEVICE_REMOVE(_tag) + + +// ======================> pcf8593_device + +class pcf8593_device : public device_t, + public device_rtc_interface, + public device_nvram_interface +{ +public: + pcf8593_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + DECLARE_WRITE_LINE_MEMBER(scl_w); + DECLARE_WRITE_LINE_MEMBER(sda_w); + DECLARE_READ_LINE_MEMBER(sda_r); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + // device_rtc_interface overrides + virtual bool rtc_feature_y2k() { return true; } + virtual void rtc_clock_updated(int year, int month, int day, int day_of_week, int hour, int minute, int second); + + // device_nvram_interface overrides + virtual void nvram_default(); + virtual void nvram_read(emu_file &file); + virtual void nvram_write(emu_file &file); + +private: + void clear_buffer_rx(); + + static const device_timer_id TIMER_UPDATE_COUNTER = 0; + + // internal state + UINT8 m_data[16]; + int m_pin_scl; + int m_pin_sda; + int m_inp; + int m_active; + int m_bits; + UINT8 m_data_recv_index; + UINT8 m_data_recv[50]; + UINT8 m_mode; + UINT8 m_pos; + emu_timer * m_timer; + enum { RTC_MODE_NONE, RTC_MODE_SEND, RTC_MODE_RECV }; +}; + +// device type definition +extern const device_type PCF8593; + +#endif /* __PCF8593_H__ */ diff --git a/src/devices/machine/pci-apic.c b/src/devices/machine/pci-apic.c new file mode 100644 index 00000000000..ce32692c7e6 --- /dev/null +++ b/src/devices/machine/pci-apic.c @@ -0,0 +1,20 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +#include "pci-apic.h" + +const device_type APIC = &device_creator; + +apic_device::apic_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : pci_device(mconfig, APIC, "I/O Advanced Programmable Interrupt Controller", tag, owner, clock, "apic", __FILE__) +{ +} + +void apic_device::device_start() +{ + pci_device::device_start(); +} + +void apic_device::device_reset() +{ + pci_device::device_reset(); +} diff --git a/src/devices/machine/pci-apic.h b/src/devices/machine/pci-apic.h new file mode 100644 index 00000000000..85b8de34b4d --- /dev/null +++ b/src/devices/machine/pci-apic.h @@ -0,0 +1,22 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +#ifndef PCI_APIC_H +#define PCI_APIC_H + +#include "pci.h" + +#define MCFG_APIC_ADD(_tag, _main_id, _revision, _subdevice_id) \ + MCFG_PCI_DEVICE_ADD(_tag, APIC, _main_id, _revision, 0x0c0320, _subdevice_id) + +class apic_device : public pci_device { +public: + apic_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual void device_start(); + virtual void device_reset(); +}; + +extern const device_type APIC; + +#endif diff --git a/src/devices/machine/pci-sata.c b/src/devices/machine/pci-sata.c new file mode 100644 index 00000000000..65cc090848b --- /dev/null +++ b/src/devices/machine/pci-sata.c @@ -0,0 +1,46 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +#include "pci-sata.h" + +const device_type SATA = &device_creator; + +sata_device::sata_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : pci_device(mconfig, SATA, "SATA AHCI interface", tag, owner, clock, "sata", __FILE__) +{ +} + +DEVICE_ADDRESS_MAP_START(primary_command_map, 32, sata_device) +ADDRESS_MAP_END + +DEVICE_ADDRESS_MAP_START(primary_control_map, 32, sata_device) +ADDRESS_MAP_END + +DEVICE_ADDRESS_MAP_START(secondary_command_map, 32, sata_device) +ADDRESS_MAP_END + +DEVICE_ADDRESS_MAP_START(secondary_control_map, 32, sata_device) +ADDRESS_MAP_END + +DEVICE_ADDRESS_MAP_START(bus_master_map, 32, sata_device) +ADDRESS_MAP_END + +DEVICE_ADDRESS_MAP_START(ide_command_posting_map, 32, sata_device) +ADDRESS_MAP_END + + +void sata_device::device_start() +{ + pci_device::device_start(); + + add_map(8, M_IO, FUNC(sata_device::primary_command_map)); + add_map(4, M_IO, FUNC(sata_device::primary_control_map)); + add_map(8, M_IO, FUNC(sata_device::secondary_command_map)); + add_map(4, M_IO, FUNC(sata_device::secondary_control_map)); + add_map(16, M_IO, FUNC(sata_device::bus_master_map)); + add_map(1024, M_MEM, FUNC(sata_device::ide_command_posting_map)); +} + +void sata_device::device_reset() +{ + pci_device::device_reset(); +} diff --git a/src/devices/machine/pci-sata.h b/src/devices/machine/pci-sata.h new file mode 100644 index 00000000000..59b41635622 --- /dev/null +++ b/src/devices/machine/pci-sata.h @@ -0,0 +1,30 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +#ifndef PCI_SATA_H +#define PCI_SATA_H + +#include "pci.h" + +#define MCFG_SATA_ADD(_tag, _main_id, _revision, _subdevice_id) \ + MCFG_PCI_DEVICE_ADD(_tag, SATA, _main_id, _revision, 0x01018a, _subdevice_id) + +class sata_device : public pci_device { +public: + sata_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual void device_start(); + virtual void device_reset(); + +private: + DECLARE_ADDRESS_MAP(primary_command_map, 32); + DECLARE_ADDRESS_MAP(primary_control_map, 32); + DECLARE_ADDRESS_MAP(secondary_command_map, 32); + DECLARE_ADDRESS_MAP(secondary_control_map, 32); + DECLARE_ADDRESS_MAP(bus_master_map, 32); + DECLARE_ADDRESS_MAP(ide_command_posting_map, 32); +}; + +extern const device_type SATA; + +#endif diff --git a/src/devices/machine/pci-smbus.c b/src/devices/machine/pci-smbus.c new file mode 100644 index 00000000000..13d4d491570 --- /dev/null +++ b/src/devices/machine/pci-smbus.c @@ -0,0 +1,280 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +#include "pci-smbus.h" + +const device_type SMBUS = &device_creator; + +DEVICE_ADDRESS_MAP_START(map, 32, smbus_device) + AM_RANGE(0x00, 0x03) AM_READWRITE8 (hst_sts_r, hst_sts_w, 0x000000ff) + AM_RANGE(0x00, 0x03) AM_READWRITE8 (hst_cnt_r, hst_cnt_w, 0x00ff0000) + AM_RANGE(0x00, 0x03) AM_READWRITE8 (hst_cmd_r, hst_cmd_w, 0xff000000) + AM_RANGE(0x04, 0x07) AM_READWRITE8 (xmit_slva_r, xmit_slva_w, 0x000000ff) + AM_RANGE(0x04, 0x07) AM_READWRITE8 (hst_d0_r, hst_d0_w, 0x0000ff00) + AM_RANGE(0x04, 0x07) AM_READWRITE8 (hst_d1_r, hst_d1_w, 0x00ff0000) + AM_RANGE(0x04, 0x07) AM_READWRITE8 (host_block_db_r, host_block_db_w, 0xff000000) + AM_RANGE(0x08, 0x0b) AM_READWRITE8 (pec_r, pec_w, 0x000000ff) + AM_RANGE(0x08, 0x0b) AM_READWRITE8 (rcv_slva_r, rcv_slva_w, 0x0000ff00) + AM_RANGE(0x08, 0x0b) AM_READWRITE16(slv_data_r, slv_data_w, 0xffff0000) + AM_RANGE(0x0c, 0x0f) AM_READWRITE8 (aux_sts_r, aux_sts_w, 0x000000ff) + AM_RANGE(0x0c, 0x0f) AM_READWRITE8 (aux_ctl_r, aux_ctl_w, 0x0000ff00) + AM_RANGE(0x0c, 0x0f) AM_READWRITE8 (smlink_pin_ctl_r, smlink_pin_ctl_w, 0x00ff0000) + AM_RANGE(0x0c, 0x0f) AM_READWRITE8 (smbus_pin_ctl_r, smbus_pin_ctl_w, 0xff000000) + AM_RANGE(0x10, 0x13) AM_READWRITE8 (slv_sts_r, slv_sts_w, 0x000000ff) + AM_RANGE(0x10, 0x13) AM_READWRITE8 (slv_cmd_r, slv_cmd_w, 0x0000ff00) + AM_RANGE(0x14, 0x17) AM_READ8 (notify_daddr_r, 0x000000ff) + AM_RANGE(0x14, 0x17) AM_READ8 (notify_dlow_r, 0x00ff0000) + AM_RANGE(0x14, 0x17) AM_READ8 (notify_dhigh_r, 0xff000000) +ADDRESS_MAP_END + +smbus_device::smbus_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : pci_device(mconfig, SMBUS, "SMBUS interface", tag, owner, clock, "smbus", __FILE__) +{ +} + +void smbus_device::device_start() +{ + pci_device::device_start(); + skip_map_regs(4); + add_map(32, M_IO, FUNC(smbus_device::map)); +} + +void smbus_device::device_reset() +{ + pci_device::device_reset(); + hst_sts = 0x00; + hst_cnt = 0x00; + hst_cmd = 0x00; + xmit_slva = 0x00; + hst_d0 = 0x00; + hst_d1 = 0x00; + host_block_db = 0x00; + pec = 0x00; + rcv_slva = 0x44; + slv_data = 0x0000; + aux_sts = 0x00; + aux_ctl = 0x00; + smlink_pin_ctl = 0x00; + smbus_pin_ctl = 0x00; + slv_sts = 0x00; + slv_cmd = 0x00; + notify_daddr = 0x00; + notify_dlow = 0x00; + notify_dhigh = 0x00; +} + +READ8_MEMBER (smbus_device::hst_sts_r) +{ + return hst_sts; +} + +WRITE8_MEMBER (smbus_device::hst_sts_w) +{ + hst_sts &= ~data; + logerror("%s: hst_sts = %02x\n", tag(), hst_sts); +} + +READ8_MEMBER (smbus_device::hst_cnt_r) +{ + return hst_cnt; +} + +WRITE8_MEMBER (smbus_device::hst_cnt_w) +{ + hst_cnt = data; + logerror("%s: hst_cnt = %02x\n", tag(), hst_cnt); + + if(xmit_slva != 0xa1) + hst_sts = 4; + else { + const UINT8 eeprom[256] = { + 0x80, 0x08, 0x07, 0x0D, 0x0A, 0x02, 0x40, 0x00, 0x04, 0x50, 0x60, 0x00, 0x82, 0x08, 0x00, 0x01, + 0x0E, 0x04, 0x08, 0x01, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x28, 0x3C, 0x28, 0x40, + 0x60, 0x60, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x37, 0x46, 0x28, 0x28, 0x55, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCE, + 0x7F, 0x7F, 0x9E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x56, 0x53, 0x35, 0x31, 0x32, 0x4D, 0x42, + 0x34, 0x30, 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }; + + hst_sts = 2; + hst_d0 = eeprom[hst_cmd]; + } +} + +READ8_MEMBER (smbus_device::hst_cmd_r) +{ + return hst_cmd; +} + +WRITE8_MEMBER (smbus_device::hst_cmd_w) +{ + hst_cmd = data; + logerror("%s: hst_cmd = %02x\n", tag(), hst_cmd); +} + +READ8_MEMBER (smbus_device::xmit_slva_r) +{ + return xmit_slva; +} + +WRITE8_MEMBER (smbus_device::xmit_slva_w) +{ + xmit_slva = data; + logerror("%s: xmit_slva = %02x\n", tag(), xmit_slva); +} + +READ8_MEMBER (smbus_device::hst_d0_r) +{ + return hst_d0; +} + +WRITE8_MEMBER (smbus_device::hst_d0_w) +{ + hst_d0 = data; + logerror("%s: hst_d0 = %02x\n", tag(), hst_d0); +} + +READ8_MEMBER (smbus_device::hst_d1_r) +{ + return hst_d1; +} + +WRITE8_MEMBER (smbus_device::hst_d1_w) +{ + hst_d1 = data; + logerror("%s: hst_d1 = %02x\n", tag(), hst_d1); +} + +READ8_MEMBER (smbus_device::host_block_db_r) +{ + return host_block_db; +} + +WRITE8_MEMBER (smbus_device::host_block_db_w) +{ + host_block_db = data; + logerror("%s: host_block_db = %02x\n", tag(), host_block_db); +} + +READ8_MEMBER (smbus_device::pec_r) +{ + return pec; +} + +WRITE8_MEMBER (smbus_device::pec_w) +{ + pec = data; + logerror("%s: pec = %02x\n", tag(), pec); +} + +READ8_MEMBER (smbus_device::rcv_slva_r) +{ + return rcv_slva; +} + +WRITE8_MEMBER (smbus_device::rcv_slva_w) +{ + rcv_slva = data; + logerror("%s: rcv_slva = %02x\n", tag(), rcv_slva); +} + +READ16_MEMBER (smbus_device::slv_data_r) +{ + return slv_data; +} + +WRITE16_MEMBER(smbus_device::slv_data_w) +{ + slv_data = data; + logerror("%s: slv_data = %02x\n", tag(), slv_data); +} + +READ8_MEMBER (smbus_device::aux_sts_r) +{ + return aux_sts; +} + +WRITE8_MEMBER (smbus_device::aux_sts_w) +{ + aux_sts = data; + logerror("%s: aux_sts = %02x\n", tag(), aux_sts); +} + +READ8_MEMBER (smbus_device::aux_ctl_r) +{ + return aux_ctl; +} + +WRITE8_MEMBER (smbus_device::aux_ctl_w) +{ + aux_ctl = data; + logerror("%s: aux_ctl = %02x\n", tag(), aux_ctl); +} + +READ8_MEMBER (smbus_device::smlink_pin_ctl_r) +{ + return smlink_pin_ctl; +} + +WRITE8_MEMBER (smbus_device::smlink_pin_ctl_w) +{ + smlink_pin_ctl = data; + logerror("%s: smlink_pin_ctl = %02x\n", tag(), smlink_pin_ctl); +} + +READ8_MEMBER (smbus_device::smbus_pin_ctl_r) +{ + return smbus_pin_ctl; +} + +WRITE8_MEMBER (smbus_device::smbus_pin_ctl_w) +{ + smbus_pin_ctl = data; + logerror("%s: smbus_pin_ctl = %02x\n", tag(), smbus_pin_ctl); +} + +READ8_MEMBER (smbus_device::slv_sts_r) +{ + return slv_sts; +} + +WRITE8_MEMBER (smbus_device::slv_sts_w) +{ + slv_sts = data; + logerror("%s: slv_sts = %02x\n", tag(), slv_sts); +} + +READ8_MEMBER (smbus_device::slv_cmd_r) +{ + return slv_cmd; +} + +WRITE8_MEMBER (smbus_device::slv_cmd_w) +{ + slv_cmd = data; + logerror("%s: slv_cmd = %02x\n", tag(), slv_cmd); +} + +READ8_MEMBER (smbus_device::notify_daddr_r) +{ + return notify_daddr; +} + +READ8_MEMBER (smbus_device::notify_dlow_r) +{ + return notify_dlow; +} + +READ8_MEMBER (smbus_device::notify_dhigh_r) +{ + return notify_dhigh; +} diff --git a/src/devices/machine/pci-smbus.h b/src/devices/machine/pci-smbus.h new file mode 100644 index 00000000000..e149e3e547c --- /dev/null +++ b/src/devices/machine/pci-smbus.h @@ -0,0 +1,67 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +#ifndef PCI_SMBUS_H +#define PCI_SMBUS_H + +#include "pci.h" + +#define MCFG_SMBUS_ADD(_tag, _main_id, _revision, _subdevice_id) \ + MCFG_PCI_DEVICE_ADD(_tag, SMBUS, _main_id, _revision, 0x0c0500, _subdevice_id) + +class smbus_device : public pci_device { +public: + smbus_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + DECLARE_READ8_MEMBER (hst_sts_r); + DECLARE_WRITE8_MEMBER (hst_sts_w); + DECLARE_READ8_MEMBER (hst_cnt_r); + DECLARE_WRITE8_MEMBER (hst_cnt_w); + DECLARE_READ8_MEMBER (hst_cmd_r); + DECLARE_WRITE8_MEMBER (hst_cmd_w); + DECLARE_READ8_MEMBER (xmit_slva_r); + DECLARE_WRITE8_MEMBER (xmit_slva_w); + DECLARE_READ8_MEMBER (hst_d0_r); + DECLARE_WRITE8_MEMBER (hst_d0_w); + DECLARE_READ8_MEMBER (hst_d1_r); + DECLARE_WRITE8_MEMBER (hst_d1_w); + DECLARE_READ8_MEMBER (host_block_db_r); + DECLARE_WRITE8_MEMBER (host_block_db_w); + DECLARE_READ8_MEMBER (pec_r); + DECLARE_WRITE8_MEMBER (pec_w); + DECLARE_READ8_MEMBER (rcv_slva_r); + DECLARE_WRITE8_MEMBER (rcv_slva_w); + DECLARE_READ16_MEMBER (slv_data_r); + DECLARE_WRITE16_MEMBER(slv_data_w); + DECLARE_READ8_MEMBER (aux_sts_r); + DECLARE_WRITE8_MEMBER (aux_sts_w); + DECLARE_READ8_MEMBER (aux_ctl_r); + DECLARE_WRITE8_MEMBER (aux_ctl_w); + DECLARE_READ8_MEMBER (smlink_pin_ctl_r); + DECLARE_WRITE8_MEMBER (smlink_pin_ctl_w); + DECLARE_READ8_MEMBER (smbus_pin_ctl_r); + DECLARE_WRITE8_MEMBER (smbus_pin_ctl_w); + DECLARE_READ8_MEMBER (slv_sts_r); + DECLARE_WRITE8_MEMBER (slv_sts_w); + DECLARE_READ8_MEMBER (slv_cmd_r); + DECLARE_WRITE8_MEMBER (slv_cmd_w); + DECLARE_READ8_MEMBER (notify_daddr_r); + DECLARE_READ8_MEMBER (notify_dlow_r); + DECLARE_READ8_MEMBER (notify_dhigh_r); + +protected: + virtual void device_start(); + virtual void device_reset(); + +private: + DECLARE_ADDRESS_MAP(map, 32); + + UINT16 slv_data; + + UINT8 hst_sts, hst_cnt, hst_cmd, xmit_slva, hst_d0, hst_d1; + UINT8 host_block_db, pec, rcv_slva, aux_sts, aux_ctl; + UINT8 smlink_pin_ctl, smbus_pin_ctl, slv_sts, slv_cmd, notify_daddr, notify_dlow, notify_dhigh; +}; + +extern const device_type SMBUS; + +#endif diff --git a/src/devices/machine/pci-usb.c b/src/devices/machine/pci-usb.c new file mode 100644 index 00000000000..56789e12eb3 --- /dev/null +++ b/src/devices/machine/pci-usb.c @@ -0,0 +1,44 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +#include "pci-usb.h" + +const device_type USB_UHCI = &device_creator; +const device_type USB_EHCI = &device_creator; + +DEVICE_ADDRESS_MAP_START(map, 32, usb_uhci_device) +ADDRESS_MAP_END + +usb_uhci_device::usb_uhci_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : pci_device(mconfig, USB_UHCI, "USB 1.1 UHCI interface", tag, owner, clock, "usb_uhci", __FILE__) +{ +} + +void usb_uhci_device::device_start() +{ + pci_device::device_start(); + add_map(32, M_IO, FUNC(usb_uhci_device::map)); +} + +void usb_uhci_device::device_reset() +{ + pci_device::device_reset(); +} + +DEVICE_ADDRESS_MAP_START(map, 32, usb_ehci_device) +ADDRESS_MAP_END + +usb_ehci_device::usb_ehci_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : pci_device(mconfig, USB_EHCI, "USB 2.0 EHCI interface", tag, owner, clock, "usb_ehci", __FILE__) +{ +} + +void usb_ehci_device::device_start() +{ + pci_device::device_start(); + add_map(1024, M_MEM, FUNC(usb_ehci_device::map)); +} + +void usb_ehci_device::device_reset() +{ + pci_device::device_reset(); +} diff --git a/src/devices/machine/pci-usb.h b/src/devices/machine/pci-usb.h new file mode 100644 index 00000000000..e103e89d968 --- /dev/null +++ b/src/devices/machine/pci-usb.h @@ -0,0 +1,41 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +#ifndef PCI_USB_H +#define PCI_USB_H + +#include "pci.h" + +#define MCFG_USB_UHCI_ADD(_tag, _main_id, _revision, _subdevice_id) \ + MCFG_PCI_DEVICE_ADD(_tag, USB_UHCI, _main_id, _revision, 0x0c0300, _subdevice_id) + +#define MCFG_USB_EHCI_ADD(_tag, _main_id, _revision, _subdevice_id) \ + MCFG_PCI_DEVICE_ADD(_tag, USB_EHCI, _main_id, _revision, 0x0c0320, _subdevice_id) + +class usb_uhci_device : public pci_device { +public: + usb_uhci_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual void device_start(); + virtual void device_reset(); + +private: + DECLARE_ADDRESS_MAP(map, 32); +}; + +class usb_ehci_device : public pci_device { +public: + usb_ehci_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual void device_start(); + virtual void device_reset(); + +private: + DECLARE_ADDRESS_MAP(map, 32); +}; + +extern const device_type USB_UHCI; +extern const device_type USB_EHCI; + +#endif diff --git a/src/devices/machine/pci.c b/src/devices/machine/pci.c new file mode 100644 index 00000000000..a5c95198c75 --- /dev/null +++ b/src/devices/machine/pci.c @@ -0,0 +1,908 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +#include "pci.h" + +// for now, make buggy GCC/Mingw STFU about I64FMT +#if (defined(__MINGW32__) && (__GNUC__ >= 5)) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wformat" +#pragma GCC diagnostic ignored "-Wformat-extra-args" +#endif + +const device_type PCI_ROOT = &device_creator; +const device_type PCI_BRIDGE = &device_creator; + +DEVICE_ADDRESS_MAP_START(config_map, 32, pci_device) + AM_RANGE(0x00, 0x03) AM_READ16 (vendor_r, 0x0000ffff) + AM_RANGE(0x00, 0x03) AM_READ16 (device_r, 0xffff0000) + AM_RANGE(0x04, 0x07) AM_READWRITE16(command_r, command_w, 0x0000ffff) + AM_RANGE(0x04, 0x07) AM_READ16 (status_r, 0xffff0000) + AM_RANGE(0x08, 0x0b) AM_READ (class_rev_r) + AM_RANGE(0x0c, 0x0f) AM_READ8 (cache_line_size_r, 0x000000ff) + AM_RANGE(0x0c, 0x0f) AM_READ8 (latency_timer_r, 0x0000ff00) + AM_RANGE(0x0c, 0x0f) AM_READ8 (header_type_r, 0x00ff0000) + AM_RANGE(0x0c, 0x0f) AM_READ8 (bist_r, 0xff000000) + AM_RANGE(0x0c, 0x0f) AM_WRITENOP + AM_RANGE(0x10, 0x27) AM_READWRITE (address_base_r, address_base_w) + // Cardbus CIS pointer at 28 + AM_RANGE(0x2c, 0x2f) AM_READ16 (subvendor_r, 0x0000ffff) + AM_RANGE(0x2c, 0x2f) AM_READ16 (subsystem_r, 0xffff0000) + AM_RANGE(0x2c, 0x2f) AM_WRITENOP + AM_RANGE(0x30, 0x33) AM_READWRITE (expansion_base_r, expansion_base_w) + AM_RANGE(0x34, 0x37) AM_READ8 (capptr_r, 0x000000ff) +ADDRESS_MAP_END + +DEVICE_ADDRESS_MAP_START(config_map, 32, pci_bridge_device) + AM_RANGE(0x00, 0x03) AM_READ16 (vendor_r, 0x0000ffff) + AM_RANGE(0x00, 0x03) AM_READ16 (device_r, 0xffff0000) + AM_RANGE(0x04, 0x07) AM_READWRITE16(command_r, command_w, 0x0000ffff) + AM_RANGE(0x04, 0x07) AM_READ16 (status_r, 0xffff0000) + AM_RANGE(0x08, 0x0b) AM_READ (class_rev_r) + AM_RANGE(0x0c, 0x0f) AM_READ8 (cache_line_size_r, 0x000000ff) + AM_RANGE(0x0c, 0x0f) AM_READ8 (latency_timer_r, 0x0000ff00) + AM_RANGE(0x0c, 0x0f) AM_READ8 (header_type_r, 0x00ff0000) + AM_RANGE(0x0c, 0x0f) AM_READ8 (bist_r, 0xff000000) + AM_RANGE(0x10, 0x17) AM_READWRITE (b_address_base_r, b_address_base_w) + AM_RANGE(0x18, 0x1b) AM_READWRITE8 (primary_bus_r, primary_bus_w, 0x000000ff) + AM_RANGE(0x18, 0x1b) AM_READWRITE8 (secondary_bus_r, secondary_bus_w, 0x0000ff00) + AM_RANGE(0x18, 0x1b) AM_READWRITE8 (subordinate_bus_r, subordinate_bus_w, 0x00ff0000) + AM_RANGE(0x18, 0x1b) AM_READWRITE8 (secondary_latency_r, secondary_latency_w, 0xff000000) + AM_RANGE(0x1c, 0x1f) AM_READWRITE8 (iobase_r, iobase_w, 0x000000ff) + AM_RANGE(0x1c, 0x1f) AM_READWRITE8 (iolimit_r, iolimit_w, 0x0000ff00) + AM_RANGE(0x1c, 0x1f) AM_READWRITE16(secondary_status_r, secondary_status_w, 0xffff0000) + AM_RANGE(0x20, 0x23) AM_READWRITE16(memory_base_r, memory_base_w, 0x0000ffff) + AM_RANGE(0x20, 0x23) AM_READWRITE16(memory_limit_r, memory_limit_w, 0xffff0000) + AM_RANGE(0x24, 0x27) AM_READWRITE16(prefetch_base_r, prefetch_base_w, 0x0000ffff) + AM_RANGE(0x24, 0x27) AM_READWRITE16(prefetch_limit_r, prefetch_limit_w, 0xffff0000) + AM_RANGE(0x28, 0x2b) AM_READWRITE (prefetch_baseu_r, prefetch_baseu_w) + AM_RANGE(0x2c, 0x2f) AM_READWRITE (prefetch_limitu_r, prefetch_limitu_w) + AM_RANGE(0x30, 0x33) AM_READWRITE16(iobaseu_r, iobaseu_w, 0x0000ffff) + AM_RANGE(0x30, 0x33) AM_READWRITE16(iolimitu_r, iolimitu_w, 0xffff0000) + AM_RANGE(0x34, 0x37) AM_READ8 (capptr_r, 0x000000ff) + AM_RANGE(0x38, 0x3b) AM_READWRITE (expansion_base_r, expansion_base_w) + AM_RANGE(0x3c, 0x3f) AM_READWRITE8 (interrupt_line_r, interrupt_line_w, 0x000000ff) + AM_RANGE(0x3c, 0x3f) AM_READWRITE8 (interrupt_pin_r, interrupt_pin_w, 0x0000ff00) + AM_RANGE(0x3c, 0x3f) AM_READWRITE16(bridge_control_r, bridge_control_w, 0xffff0000) +ADDRESS_MAP_END + +pci_device::pci_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source) +{ + main_id = 0xffffffff; + revision = 0x00; + pclass = 0xffffff; + subsystem_id = 0xffffffff; + is_multifunction_device = false; +} + +void pci_device::set_ids(UINT32 _main_id, UINT8 _revision, UINT32 _pclass, UINT32 _subsystem_id) +{ + main_id = _main_id; + revision = _revision; + pclass = _pclass; + subsystem_id = _subsystem_id; +} + +void pci_device::device_start() +{ + command = 0x0080; + command_mask = 0x01bf; + status = 0x0000; + + for(int i=0; i<6; i++) { + bank_infos[i].adr = -1; + bank_infos[i].size = 0; + bank_infos[i].flags = 0; + bank_reg_infos[i].bank = -1; + bank_reg_infos[i].hi = 0; + } + + bank_count = 0; + bank_reg_count = 0; + + expansion_rom = 0; + expansion_rom_size = 0; + expansion_rom_base = 0; +} + +void pci_device::device_reset() +{ +} + +UINT32 pci_device::unmapped_r(offs_t offset, UINT32 mem_mask, int bank) +{ + logerror("%s: unmapped read from %08x & %08x (%s)\n", machine().describe_context(), offset*4, mem_mask, bank_infos[bank].map.name()); + return 0; +} + +void pci_device::unmapped_w(offs_t offset, UINT32 data, UINT32 mem_mask, int bank) +{ + logerror("%s: unmapped write to %08x = %08x & %08x (%s)\n", machine().describe_context(), offset*4, data, mem_mask, bank_infos[bank].map.name()); +} + +READ32_MEMBER(pci_device::unmapped0_r) { return unmapped_r(offset, mem_mask, 0); } +WRITE32_MEMBER(pci_device::unmapped0_w) { return unmapped_w(offset, data, mem_mask, 0); } +READ32_MEMBER(pci_device::unmapped1_r) { return unmapped_r(offset, mem_mask, 1); } +WRITE32_MEMBER(pci_device::unmapped1_w) { return unmapped_w(offset, data, mem_mask, 1); } +READ32_MEMBER(pci_device::unmapped2_r) { return unmapped_r(offset, mem_mask, 2); } +WRITE32_MEMBER(pci_device::unmapped2_w) { return unmapped_w(offset, data, mem_mask, 2); } +READ32_MEMBER(pci_device::unmapped3_r) { return unmapped_r(offset, mem_mask, 3); } +WRITE32_MEMBER(pci_device::unmapped3_w) { return unmapped_w(offset, data, mem_mask, 3); } +READ32_MEMBER(pci_device::unmapped4_r) { return unmapped_r(offset, mem_mask, 4); } +WRITE32_MEMBER(pci_device::unmapped4_w) { return unmapped_w(offset, data, mem_mask, 4); } +READ32_MEMBER(pci_device::unmapped5_r) { return unmapped_r(offset, mem_mask, 5); } +WRITE32_MEMBER(pci_device::unmapped5_w) { return unmapped_w(offset, data, mem_mask, 5); } + + +READ32_MEMBER(pci_device::address_base_r) +{ + if(bank_reg_infos[offset].bank == -1) + return 0; + int bid = bank_reg_infos[offset].bank; + if(bank_reg_infos[offset].hi) + return bank_infos[bid].adr >> 32; + int flags = bank_infos[bid].flags; + return (bank_infos[bid].adr & ~(bank_infos[bid].size - 1)) | (flags & M_IO ? 1 : 0) | (flags & M_64A ? 4 : 0) | (flags & M_PREF ? 8 : 0); +} + +WRITE32_MEMBER(pci_device::address_base_w) +{ + if(bank_reg_infos[offset].bank == -1) { + logerror("%s: write to address base (%d, %08x) not linked to any bank\n", tag(), offset, data); + return; + } + + int bid = bank_reg_infos[offset].bank; + if(bank_reg_infos[offset].hi) + bank_infos[bid].adr = (bank_infos[bid].adr & 0xffffffff) | (UINT64(data) << 32); + else { + bank_infos[bid].adr = (bank_infos[bid].adr & U64(0xffffffff00000000)) | data; + } + remap_cb(); +} + +READ16_MEMBER(pci_device::vendor_r) +{ + return main_id >> 16; +} + +READ16_MEMBER(pci_device::device_r) +{ + return main_id; +} + +READ16_MEMBER(pci_device::command_r) +{ + return command; +} + +WRITE16_MEMBER(pci_device::command_w) +{ + mem_mask &= command_mask; + COMBINE_DATA(&command); + logerror("%s: command = %04x\n", tag(), command); +} + +READ16_MEMBER(pci_device::status_r) +{ + return status; +} + +READ32_MEMBER(pci_device::class_rev_r) +{ + return (pclass << 8) | revision; +} + +READ8_MEMBER(pci_device::cache_line_size_r) +{ + return 0x00; +} + +READ8_MEMBER(pci_device::latency_timer_r) +{ + return 0x00; +} + +void pci_device::set_multifunction_device(bool enable) +{ + is_multifunction_device = enable; +} + +READ8_MEMBER(pci_device::header_type_r) +{ + return is_multifunction_device ? 0x80 : 0x00; +} + +READ8_MEMBER(pci_device::bist_r) +{ + return 0x00; +} + +READ16_MEMBER(pci_device::subvendor_r) +{ + return subsystem_id >> 16; +} + +READ16_MEMBER(pci_device::subsystem_r) +{ + return subsystem_id; +} + +READ32_MEMBER(pci_device::expansion_base_r) +{ + return expansion_rom_base; +} + + +WRITE32_MEMBER(pci_device::expansion_base_w) +{ + COMBINE_DATA(&expansion_rom_base); + if(!expansion_rom_size) + expansion_rom_base = 0; + else { + // Trick to get an address resolution at expansion_rom_size with minimal granularity of 0x800, plus bit 1 set to keep the on/off information + expansion_rom_base &= 0xfffff801 & (1-expansion_rom_size); + } + remap_cb(); +} + +READ8_MEMBER(pci_device::capptr_r) +{ + return 0x00; +} + +void pci_device::set_remap_cb(mapper_cb _remap_cb) +{ + remap_cb = _remap_cb; +} + +void pci_device::reset_all_mappings() +{ +} + +void pci_device::map_device(UINT64 memory_window_start, UINT64 memory_window_end, UINT64 memory_offset, address_space *memory_space, + UINT64 io_window_start, UINT64 io_window_end, UINT64 io_offset, address_space *io_space) +{ + for(int i=0; iinstall_readwrite_handler(start, end, 0, 0, read32_delegate(FUNC(pci_device::unmapped0_r), this), write32_delegate(FUNC(pci_device::unmapped0_w), this)); break; + case 1: space->install_readwrite_handler(start, end, 0, 0, read32_delegate(FUNC(pci_device::unmapped1_r), this), write32_delegate(FUNC(pci_device::unmapped1_w), this)); break; + case 2: space->install_readwrite_handler(start, end, 0, 0, read32_delegate(FUNC(pci_device::unmapped2_r), this), write32_delegate(FUNC(pci_device::unmapped2_w), this)); break; + case 3: space->install_readwrite_handler(start, end, 0, 0, read32_delegate(FUNC(pci_device::unmapped3_r), this), write32_delegate(FUNC(pci_device::unmapped3_w), this)); break; + case 4: space->install_readwrite_handler(start, end, 0, 0, read32_delegate(FUNC(pci_device::unmapped4_r), this), write32_delegate(FUNC(pci_device::unmapped4_w), this)); break; + case 5: space->install_readwrite_handler(start, end, 0, 0, read32_delegate(FUNC(pci_device::unmapped5_r), this), write32_delegate(FUNC(pci_device::unmapped5_w), this)); break; + } + + space->install_device_delegate(start, end, *this, bi.map); + logerror("%s: map %s at %0*x-%0*x\n", tag(), bi.map.name(), bi.flags & M_IO ? 4 : 8, UINT32(start), bi.flags & M_IO ? 4 : 8, UINT32(end)); + } + + map_extra(memory_window_start, memory_window_end, memory_offset, memory_space, + io_window_start, io_window_end, io_offset, io_space); + + if(expansion_rom_base & 1) { + logerror("%s: map expansion rom at %08x-%08x\n", tag(), expansion_rom_base & ~1, (expansion_rom_base & ~1) + expansion_rom_size - 1); + UINT32 start = (expansion_rom_base & ~1) + memory_offset; + UINT32 end = start + expansion_rom_size - 1; + if(end > memory_window_end) + end = memory_window_end; + memory_space->install_rom(start, end, (void *)expansion_rom); + } +} + +void pci_device::map_extra(UINT64 memory_window_start, UINT64 memory_window_end, UINT64 memory_offset, address_space *memory_space, + UINT64 io_window_start, UINT64 io_window_end, UINT64 io_offset, address_space *io_space) +{ +} + +void pci_device::map_config(UINT8 device, address_space *config_space) +{ + config_space->install_device(device << 12, (device << 12) | 0xfff, *this, &pci_device::config_map); +} + +void pci_device::skip_map_regs(int count) +{ + bank_reg_count += count; + assert(bank_reg_count <= 6); +} + +void pci_device::add_map(UINT64 size, int flags, address_map_delegate &map) +{ + assert(bank_count < 6); + int bid = bank_count++; + bank_infos[bid].map = map; + bank_infos[bid].adr = 0; + bank_infos[bid].size = size; + bank_infos[bid].flags = flags; + + if(flags & M_64A) { + assert(bank_reg_count < 5); + int breg = bank_reg_count; + bank_reg_infos[breg].bank = bid; + bank_reg_infos[breg].hi = 0; + bank_reg_infos[breg+1].bank = bid; + bank_reg_infos[breg+1].hi = 1; + bank_reg_count += 2; + } else { + assert(bank_reg_count < 6); + int breg = bank_reg_count++; + bank_reg_infos[breg].bank = bid; + bank_reg_infos[breg].hi = 0; + } + + logerror("Device %s (%s) has 0x%" I64FMT "x bytes of %s named %s\n", tag(), name(), size, flags & M_IO ? "io" : "memory", bank_infos[bid].map.name()); +} + +void pci_device::add_rom(const UINT8 *rom, UINT32 size) +{ + expansion_rom = rom; + expansion_rom_size = size; + logerror("Device %s (%s) has 0x%x bytes of expansion rom\n", tag(), name(), size); +} + +void pci_device::add_rom_from_region() +{ + add_rom(m_region->base(), m_region->bytes()); +} + +void pci_device::set_map_address(int id, UINT64 adr) +{ + bank_infos[id].adr = adr; + remap_cb(); +} + +void pci_device::set_map_size(int id, UINT64 size) +{ + bank_infos[id].size = size; + remap_cb(); +} + +void pci_device::set_map_flags(int id, int flags) +{ + bank_infos[id].flags = flags; + remap_cb(); +} + +agp_device::agp_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : pci_device(mconfig, type, name, tag, owner, clock, shortname, source) +{ +} + +void agp_device::device_start() +{ + pci_device::device_start(); +} + +void agp_device::device_reset() +{ + pci_device::device_reset(); +} + + + +pci_bridge_device::pci_bridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : pci_device(mconfig, PCI_BRIDGE, "PCI-PCI Bridge", tag, owner, clock, "pci_bridge", __FILE__), + device_memory_interface(mconfig, *this), + configure_space_config("configuration_space", ENDIANNESS_LITTLE, 32, 20) +{ +} + +pci_bridge_device::pci_bridge_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : pci_device(mconfig, type, name, tag, owner, clock, shortname, source), + device_memory_interface(mconfig, *this), + configure_space_config("configuration_space", ENDIANNESS_LITTLE, 32, 20) +{ +} + +READ8_MEMBER(pci_bridge_device::header_type_r) +{ + return 0x01; +} + +const address_space_config *pci_bridge_device::memory_space_config(address_spacenum spacenum) const +{ + return spacenum == AS_PROGRAM ? &configure_space_config : NULL; +} + +device_t *pci_bridge_device::bus_root() +{ + return this; +} + +void pci_bridge_device::set_remap_cb(mapper_cb _remap_cb) +{ + remap_cb = _remap_cb; + for(unsigned int i=0; i != all_devices.size(); i++) + if(all_devices[i] != this) + all_devices[i]->set_remap_cb(_remap_cb); +} + +void pci_bridge_device::device_start() +{ + pci_device::device_start(); + + for(int i=0; i<32*8; i++) + sub_devices[i] = NULL; + + for(device_t *d = bus_root()->first_subdevice(); d != NULL; d = d->next()) { + const char *t = d->tag(); + int l = strlen(t); + if(l <= 4 || t[l-5] != ':' || t[l-2] != '.') + continue; + int id = strtol(t+l-4, 0, 16); + int fct = t[l-1] - '0'; + sub_devices[(id << 3) | fct] = downcast(d); + } + + mapper_cb cf_cb(FUNC(pci_bridge_device::regenerate_config_mapping), this); + + for(int i=0; i<32*8; i++) + if(sub_devices[i]) { + if((i & 7) && sub_devices[i & ~7]) + sub_devices[i & ~7]->set_multifunction_device(true); + + all_devices.push_back(sub_devices[i]); + if(sub_devices[i] != this) { + sub_devices[i]->remap_config_cb = cf_cb; + sub_devices[i]->set_remap_cb(remap_cb); + pci_bridge_device *bridge = dynamic_cast(sub_devices[i]); + if(bridge) + all_bridges.push_back(bridge); + } + } +} + +void pci_bridge_device::device_reset() +{ + pci_device::device_reset(); + + bridge_control = 0x0000; + primary_bus = 0x00; + secondary_bus = 0x00; + subordinate_bus = 0x00; + regenerate_config_mapping(); +} + +void pci_bridge_device::reset_all_mappings() +{ + pci_device::reset_all_mappings(); + + for(unsigned int i=0; i != all_devices.size(); i++) + if(all_devices[i] != this) + all_devices[i]->reset_all_mappings(); + + prefetch_baseu = 0; + prefetch_limitu = 0; + memory_base = 0; + memory_limit = 0; + prefetch_base = 0; + prefetch_limit = 0; + iobaseu = 0; + iolimitu = 0; + iobase = 0; + iolimit = 0; +} + +void pci_bridge_device::map_device(UINT64 memory_window_start, UINT64 memory_window_end, UINT64 memory_offset, address_space *memory_space, + UINT64 io_window_start, UINT64 io_window_end, UINT64 io_offset, address_space *io_space) +{ + for(int i = int(all_devices.size())-1; i>=0; i--) + if(all_devices[i] != this) + all_devices[i]->map_device(memory_window_start, memory_window_end, memory_offset, memory_space, + io_window_start, io_window_end, io_offset, io_space); + + map_extra(memory_window_start, memory_window_end, memory_offset, memory_space, + io_window_start, io_window_end, io_offset, io_space); +} + + +void pci_bridge_device::regenerate_config_mapping() +{ + address_space *config_space = &space(AS_PROGRAM); + config_space->unmap_readwrite(0x00000, 0xfffff); + for(int i=0; i<32*8; i++) + if(sub_devices[i]) + sub_devices[i]->map_config(i, config_space); +} + +UINT32 pci_bridge_device::do_config_read(UINT8 bus, UINT8 device, UINT16 reg, UINT32 mem_mask) +{ + if(sub_devices[device]) { + UINT32 data = space(AS_PROGRAM).read_dword((device << 12) | reg, mem_mask); + logerror("%s: config_read %02x:%02x.%x:%02x %08x @ %08x\n", tag(), bus, device >> 3, device & 7, reg, data, mem_mask); + return data; + } else + return 0xffffffff; +} + +UINT32 pci_bridge_device::propagate_config_read(UINT8 bus, UINT8 device, UINT16 reg, UINT32 mem_mask) +{ + UINT32 data = 0xffffffff; + for(unsigned int i=0; i != all_bridges.size(); i++) + data &= all_bridges[i]->config_read(bus, device, reg, mem_mask); + return data; +} + +UINT32 pci_bridge_device::config_read(UINT8 bus, UINT8 device, UINT16 reg, UINT32 mem_mask) +{ + if(bus == secondary_bus) + return do_config_read(bus, device, reg, mem_mask); + + if(bus > secondary_bus && bus <= subordinate_bus) + return propagate_config_read(bus, device, reg, mem_mask); + + return 0xffffffff; +} + +void pci_bridge_device::do_config_write(UINT8 bus, UINT8 device, UINT16 reg, UINT32 data, UINT32 mem_mask) +{ + if(sub_devices[device]) { + space(AS_PROGRAM).write_dword((device << 12) | reg, data, mem_mask); + logerror("%s: config_write %02x:%02x.%x:%02x %08x @ %08x\n", tag(), bus, device >> 3, device & 7, reg, data, mem_mask); + } +} + +void pci_bridge_device::propagate_config_write(UINT8 bus, UINT8 device, UINT16 reg, UINT32 data, UINT32 mem_mask) +{ + for(unsigned int i=0; i != all_bridges.size(); i++) + all_bridges[i]->config_write(bus, device, reg, data, mem_mask); +} + +void pci_bridge_device::config_write(UINT8 bus, UINT8 device, UINT16 reg, UINT32 data, UINT32 mem_mask) +{ + if(bus == secondary_bus) + do_config_write(bus, device, reg, data, mem_mask); + + else if(bus > secondary_bus && bus <= subordinate_bus) + propagate_config_write(bus, device, reg, data, mem_mask); +} + +READ32_MEMBER (pci_bridge_device::b_address_base_r) +{ + logerror("%s: b_address_base_r %d\n", tag(), offset); + return 0xffffffff; +} + +WRITE32_MEMBER(pci_bridge_device::b_address_base_w) +{ + logerror("%s: b_address_base_w %d, %08x\n", tag(), offset, data); +} + +READ8_MEMBER (pci_bridge_device::primary_bus_r) +{ + logerror("%s: primary_bus_r\n", tag()); + return primary_bus; +} + +WRITE8_MEMBER (pci_bridge_device::primary_bus_w) +{ + primary_bus = data; + logerror("%s: primary_bus_w %02x\n", tag(), data); +} + +READ8_MEMBER (pci_bridge_device::secondary_bus_r) +{ + logerror("%s: secondary_bus_r\n", tag()); + return secondary_bus; +} + +WRITE8_MEMBER (pci_bridge_device::secondary_bus_w) +{ + secondary_bus = data; + logerror("%s: secondary_bus_w %02x\n", tag(), data); +} + +READ8_MEMBER (pci_bridge_device::subordinate_bus_r) +{ + logerror("%s: subordinate_bus_r\n", tag()); + return subordinate_bus; +} + +WRITE8_MEMBER (pci_bridge_device::subordinate_bus_w) +{ + subordinate_bus = data; + logerror("%s: subordinate_bus_w %02x\n", tag(), data); +} + +READ8_MEMBER (pci_bridge_device::secondary_latency_r) +{ + logerror("%s: secondary_latency_r\n", tag()); + return 0xff; +} + +WRITE8_MEMBER (pci_bridge_device::secondary_latency_w) +{ + logerror("%s: secondary_latency_w %02x\n", tag(), data); +} + +READ8_MEMBER (pci_bridge_device::iobase_r) +{ + return iobase; +} + +WRITE8_MEMBER (pci_bridge_device::iobase_w) +{ + iobase = data; + logerror("%s: iobase_w %02x\n", tag(), data); +} + +READ8_MEMBER (pci_bridge_device::iolimit_r) +{ + return iolimit; +} + +WRITE8_MEMBER (pci_bridge_device::iolimit_w) +{ + iolimit = data; + logerror("%s: iolimit_w %02x\n", tag(), data); +} + +READ16_MEMBER (pci_bridge_device::secondary_status_r) +{ + logerror("%s: secondary_status_r\n", tag()); + return 0xffff; +} + +WRITE16_MEMBER(pci_bridge_device::secondary_status_w) +{ + logerror("%s: secondary_status_w %04x\n", tag(), data); +} + +READ16_MEMBER (pci_bridge_device::memory_base_r) +{ + return memory_base; +} + +WRITE16_MEMBER(pci_bridge_device::memory_base_w) +{ + COMBINE_DATA(&memory_base); + logerror("%s: memory_base_w %04x\n", tag(), memory_base); +} + +READ16_MEMBER (pci_bridge_device::memory_limit_r) +{ + return memory_limit; +} + +WRITE16_MEMBER(pci_bridge_device::memory_limit_w) +{ + COMBINE_DATA(&memory_limit); + logerror("%s: memory_limit_w %04x\n", tag(), memory_limit); +} + +READ16_MEMBER (pci_bridge_device::prefetch_base_r) +{ + return prefetch_base; +} + +WRITE16_MEMBER(pci_bridge_device::prefetch_base_w) +{ + COMBINE_DATA(&prefetch_base); + logerror("%s: prefetch_base_w %04x\n", tag(), prefetch_base); +} + +READ16_MEMBER (pci_bridge_device::prefetch_limit_r) +{ + return prefetch_limit; +} + +WRITE16_MEMBER(pci_bridge_device::prefetch_limit_w) +{ + COMBINE_DATA(&prefetch_limit); + logerror("%s: prefetch_limit_w %04x\n", tag(), prefetch_limit); +} + +READ32_MEMBER (pci_bridge_device::prefetch_baseu_r) +{ + return prefetch_baseu; +} + +WRITE32_MEMBER(pci_bridge_device::prefetch_baseu_w) +{ + COMBINE_DATA(&prefetch_baseu); + logerror("%s: prefetch_baseu_w %08x\n", tag(), prefetch_baseu); +} + +READ32_MEMBER (pci_bridge_device::prefetch_limitu_r) +{ + return prefetch_limitu; +} + +WRITE32_MEMBER(pci_bridge_device::prefetch_limitu_w) +{ + COMBINE_DATA(&prefetch_limitu); + logerror("%s: prefetch_limitu_w %08x\n", tag(), prefetch_limitu); +} + +READ16_MEMBER (pci_bridge_device::iobaseu_r) +{ + return iobaseu; +} + +WRITE16_MEMBER(pci_bridge_device::iobaseu_w) +{ + COMBINE_DATA(&iobaseu); + logerror("%s: iobaseu_w %04x\n", tag(), iobaseu); +} + +READ16_MEMBER (pci_bridge_device::iolimitu_r) +{ + return iolimitu; +} + +WRITE16_MEMBER(pci_bridge_device::iolimitu_w) +{ + COMBINE_DATA(&iolimitu); + logerror("%s: iolimitu_w %04x\n", tag(), iolimitu); +} + +READ8_MEMBER (pci_bridge_device::interrupt_line_r) +{ + logerror("%s: interrupt_line_r\n", tag()); + return 0xff; +} + +WRITE8_MEMBER (pci_bridge_device::interrupt_line_w) +{ + logerror("%s: interrupt_line_w %02x\n", tag(), data); +} + +READ8_MEMBER (pci_bridge_device::interrupt_pin_r) +{ + logerror("%s: interrupt_pin_r\n", tag()); + return 0xff; +} + +WRITE8_MEMBER (pci_bridge_device::interrupt_pin_w) +{ + logerror("%s: interrupt_pin_w %02x\n", tag(), data); +} + +READ16_MEMBER (pci_bridge_device::bridge_control_r) +{ + return bridge_control; +} + +WRITE16_MEMBER(pci_bridge_device::bridge_control_w) +{ + COMBINE_DATA(&bridge_control); + logerror("%s: bridge_control_w %04x\n", tag(), bridge_control); +} + + +agp_bridge_device::agp_bridge_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : pci_bridge_device(mconfig, type, name, tag, owner, clock, shortname, source) +{ +} + +void agp_bridge_device::device_start() +{ + pci_bridge_device::device_start(); +} + +void agp_bridge_device::device_reset() +{ + pci_bridge_device::device_reset(); +} + + + +DEVICE_ADDRESS_MAP_START(io_configuration_access_map, 32, pci_host_device) + AM_RANGE(0xcf8, 0xcfb) AM_READWRITE(config_address_r, config_address_w) + AM_RANGE(0xcfc, 0xcff) AM_READWRITE(config_data_r, config_data_w) +ADDRESS_MAP_END + + +pci_host_device::pci_host_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : pci_bridge_device(mconfig, type, name, tag, owner, clock, shortname, source) +{ +} + +device_t *pci_host_device::bus_root() +{ + return owner(); +} + +void pci_host_device::device_start() +{ + remap_cb = mapper_cb(FUNC(pci_host_device::regenerate_mapping), this); + + pci_bridge_device::device_start(); + + memory_window_start = memory_window_end = memory_offset = 0; + io_window_start = io_window_end = io_offset = 0; + + reset_all_mappings(); +} + +void pci_host_device::device_reset() +{ + pci_bridge_device::device_reset(); + reset_all_mappings(); + regenerate_mapping(); + + config_address = 0; +} + +void pci_host_device::regenerate_mapping() +{ + logerror("Regenerating mapping\n"); + memory_space->unmap_readwrite(memory_window_start, memory_window_end); + io_space->unmap_readwrite(io_window_start, io_window_end); + + map_device(memory_window_start, memory_window_end, memory_offset, memory_space, + io_window_start, io_window_end, io_offset, io_space); +} + +READ32_MEMBER(pci_host_device::config_address_r) +{ + return config_address; +} + +WRITE32_MEMBER(pci_host_device::config_address_w) +{ + COMBINE_DATA(&config_address); +} + +READ32_MEMBER(pci_host_device::config_data_r) +{ + return config_address & 0x80000000 ? root_config_read((config_address >> 16) & 0xff, (config_address >> 8) & 0xff, config_address & 0xfc, mem_mask) : 0xffffffff; +} + +WRITE32_MEMBER(pci_host_device::config_data_w) +{ + if(config_address & 0x80000000) + root_config_write((config_address >> 16) & 0xff, (config_address >> 8) & 0xff, config_address & 0xfc, data, mem_mask); +} + +UINT32 pci_host_device::root_config_read(UINT8 bus, UINT8 device, UINT16 reg, UINT32 mem_mask) +{ + if(bus == 0x00) + return do_config_read(bus, device, reg, mem_mask); + + return propagate_config_read(bus, device, reg, mem_mask); +} + +void pci_host_device::root_config_write(UINT8 bus, UINT8 device, UINT16 reg, UINT32 data, UINT32 mem_mask) +{ + if(bus == 0x00) + do_config_write(bus, device, reg, data, mem_mask); + + else + propagate_config_write(bus, device, reg, data, mem_mask); +} + + +pci_root_device::pci_root_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, PCI_ROOT,"PCI virtual root", tag, owner, clock, "pci_root", __FILE__) +{ +} + +void pci_root_device::device_start() +{ +} + +void pci_root_device::device_reset() +{ +} + +#if (defined(__MINGW32__) && (__GNUC__ >= 5)) +#pragma GCC diagnostic pop +#endif diff --git a/src/devices/machine/pci.h b/src/devices/machine/pci.h new file mode 100644 index 00000000000..34566f5f1e6 --- /dev/null +++ b/src/devices/machine/pci.h @@ -0,0 +1,282 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +#ifndef PCI_H +#define PCI_H + +#include "emu.h" + +#define MCFG_PCI_ROOT_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, PCI_ROOT, 0) + +#define MCFG_PCI_DEVICE_ADD(_tag, _type, _main_id, _revision, _pclass, _subsystem_id) \ + MCFG_DEVICE_ADD(_tag, _type, 0) \ + downcast(device)->set_ids(_main_id, _revision, _pclass, _subsystem_id); + +#define MCFG_AGP_DEVICE_ADD(_tag, _type, _main_id, _revision, _subsystem_id) \ + MCFG_PCI_DEVICE_ADD(_tag, _type, _main_id, _revision, 0x030000, _subsystem_id) + +#define MCFG_PCI_HOST_ADD(_tag, _type, _main_id, _revision, _subsystem_id) \ + MCFG_PCI_DEVICE_ADD(_tag, _type, _main_id, _revision, 0x060000, _subsystem_id) + +#define MCFG_PCI_BRIDGE_ADD(_tag, _main_id, _revision) \ + MCFG_PCI_DEVICE_ADD(_tag, PCI_BRIDGE, _main_id, _revision, 0x060400, 0x00000000) + +#define MCFG_AGP_BRIDGE_ADD(_tag, _type, _main_id, _revision) \ + MCFG_PCI_DEVICE_ADD(_tag, _type, _main_id, _revision, 0x060400, 0x00000000) + +class pci_device : public device_t { +public: + typedef delegate mapper_cb; + + mapper_cb remap_cb, remap_config_cb; + + pci_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + void set_ids(UINT32 main_id, UINT8 revision, UINT32 pclass, UINT32 subsystem_id); + void set_multifunction_device(bool enable); + + virtual void set_remap_cb(mapper_cb _remap_cb); + virtual void reset_all_mappings(); + virtual void map_device(UINT64 memory_window_start, UINT64 memory_window_end, UINT64 memory_offset, address_space *memory_space, + UINT64 io_window_start, UINT64 io_window_end, UINT64 io_offset, address_space *io_space); + virtual void map_extra(UINT64 memory_window_start, UINT64 memory_window_end, UINT64 memory_offset, address_space *memory_space, + UINT64 io_window_start, UINT64 io_window_end, UINT64 io_offset, address_space *io_space); + + void map_config(UINT8 device, address_space *config_space); + + virtual DECLARE_ADDRESS_MAP(config_map, 32); + + UINT32 unmapped_r(offs_t offset, UINT32 mem_mask, int bank); + void unmapped_w(offs_t offset, UINT32 data, UINT32 mem_mask, int bank); + + READ32_MEMBER (unmapped0_r); + WRITE32_MEMBER(unmapped0_w); + READ32_MEMBER (unmapped1_r); + WRITE32_MEMBER(unmapped1_w); + READ32_MEMBER (unmapped2_r); + WRITE32_MEMBER(unmapped2_w); + READ32_MEMBER (unmapped3_r); + WRITE32_MEMBER(unmapped3_w); + READ32_MEMBER (unmapped4_r); + WRITE32_MEMBER(unmapped4_w); + READ32_MEMBER (unmapped5_r); + WRITE32_MEMBER(unmapped5_w); + + + DECLARE_READ16_MEMBER(vendor_r); + DECLARE_READ16_MEMBER(device_r); + DECLARE_READ16_MEMBER(command_r); + DECLARE_WRITE16_MEMBER(command_w); + DECLARE_READ16_MEMBER(status_r); + DECLARE_READ32_MEMBER(class_rev_r); + virtual DECLARE_READ8_MEMBER(cache_line_size_r); + virtual DECLARE_READ8_MEMBER(latency_timer_r); + virtual DECLARE_READ8_MEMBER(header_type_r); + virtual DECLARE_READ8_MEMBER(bist_r); + DECLARE_READ32_MEMBER(address_base_r); + DECLARE_WRITE32_MEMBER(address_base_w); + DECLARE_READ16_MEMBER(subvendor_r); + DECLARE_READ16_MEMBER(subsystem_r); + DECLARE_READ32_MEMBER (expansion_base_r); + DECLARE_WRITE32_MEMBER(expansion_base_w); + virtual DECLARE_READ8_MEMBER(capptr_r); + +protected: + enum { + M_MEM = 0, + M_IO = 1, + M_64D = 2, + M_64A = 4, + M_PREF = 8, + M_DISABLED = 16 + }; + + struct bank_info { + // One of the two + address_map_delegate map; + + UINT64 adr; + UINT32 size; + int flags; + }; + + struct bank_reg_info { + int bank, hi; + }; + + bank_info bank_infos[6]; + int bank_count, bank_reg_count; + bank_reg_info bank_reg_infos[6]; + + UINT32 main_id, subsystem_id; + UINT32 pclass; + UINT8 revision; + UINT16 command, command_mask, status; + const UINT8 *expansion_rom; + UINT32 expansion_rom_size; + UINT32 expansion_rom_base; + bool is_multifunction_device; + + virtual void device_start(); + virtual void device_reset(); + + void skip_map_regs(int count); + void add_map(UINT64 size, int flags, address_map_delegate &map); + template void add_map(UINT64 size, int flags, void (T::*map)(address_map &map, device_t &device), const char *name) { + address_map_delegate delegate(map, name, static_cast(this)); + add_map(size, flags, delegate); + } + + void add_rom(const UINT8 *data, UINT32 size); + void add_rom_from_region(); + + void set_map_address(int id, UINT64 adr); + void set_map_size(int id, UINT64 size); + void set_map_flags(int id, int flags); + +private: + void add_map_finish(int bid, UINT64 size, int flags); + +}; + +class agp_device : public pci_device { +public: + agp_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + +protected: + virtual void device_start(); + virtual void device_reset(); +}; + +class pci_bridge_device : public pci_device, public device_memory_interface { +public: + pci_bridge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + pci_bridge_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + virtual void set_remap_cb(mapper_cb _remap_cb); + virtual void map_device(UINT64 memory_window_start, UINT64 memory_window_end, UINT64 memory_offset, address_space *memory_space, + UINT64 io_window_start, UINT64 io_window_end, UINT64 io_offset, address_space *io_space); + virtual void reset_all_mappings(); + + virtual DECLARE_READ8_MEMBER(header_type_r); + + virtual DECLARE_ADDRESS_MAP(config_map, 32); + + DECLARE_READ32_MEMBER (b_address_base_r); + DECLARE_WRITE32_MEMBER(b_address_base_w); + DECLARE_READ8_MEMBER (primary_bus_r); + DECLARE_WRITE8_MEMBER (primary_bus_w); + DECLARE_READ8_MEMBER (secondary_bus_r); + DECLARE_WRITE8_MEMBER (secondary_bus_w); + DECLARE_READ8_MEMBER (subordinate_bus_r); + DECLARE_WRITE8_MEMBER (subordinate_bus_w); + DECLARE_READ8_MEMBER (secondary_latency_r); + DECLARE_WRITE8_MEMBER (secondary_latency_w); + DECLARE_READ8_MEMBER (iobase_r); + DECLARE_WRITE8_MEMBER (iobase_w); + DECLARE_READ8_MEMBER (iolimit_r); + DECLARE_WRITE8_MEMBER (iolimit_w); + DECLARE_READ16_MEMBER (secondary_status_r); + DECLARE_WRITE16_MEMBER(secondary_status_w); + DECLARE_READ16_MEMBER (memory_base_r); + DECLARE_WRITE16_MEMBER(memory_base_w); + DECLARE_READ16_MEMBER (memory_limit_r); + DECLARE_WRITE16_MEMBER(memory_limit_w); + DECLARE_READ16_MEMBER (prefetch_base_r); + DECLARE_WRITE16_MEMBER(prefetch_base_w); + DECLARE_READ16_MEMBER (prefetch_limit_r); + DECLARE_WRITE16_MEMBER(prefetch_limit_w); + DECLARE_READ32_MEMBER (prefetch_baseu_r); + DECLARE_WRITE32_MEMBER(prefetch_baseu_w); + DECLARE_READ32_MEMBER (prefetch_limitu_r); + DECLARE_WRITE32_MEMBER(prefetch_limitu_w); + DECLARE_READ16_MEMBER (iobaseu_r); + DECLARE_WRITE16_MEMBER(iobaseu_w); + DECLARE_READ16_MEMBER (iolimitu_r); + DECLARE_WRITE16_MEMBER(iolimitu_w); + DECLARE_READ8_MEMBER (interrupt_line_r); + DECLARE_WRITE8_MEMBER (interrupt_line_w); + DECLARE_READ8_MEMBER (interrupt_pin_r); + DECLARE_WRITE8_MEMBER (interrupt_pin_w); + DECLARE_READ16_MEMBER (bridge_control_r); + DECLARE_WRITE16_MEMBER(bridge_control_w); + +protected: + pci_device *sub_devices[32*8]; + std::vector all_devices; + std::vector all_bridges; + + UINT32 prefetch_baseu, prefetch_limitu; + UINT16 bridge_control, memory_base, memory_limit, prefetch_base, prefetch_limit, iobaseu, iolimitu; + UINT8 primary_bus, secondary_bus, subordinate_bus, iobase, iolimit; + + virtual void device_start(); + virtual void device_reset(); + virtual const address_space_config *memory_space_config(address_spacenum spacenum) const; + + virtual device_t *bus_root(); + virtual void regenerate_config_mapping(); + + UINT32 do_config_read(UINT8 bus, UINT8 device, UINT16 reg, UINT32 mem_mask); + UINT32 propagate_config_read(UINT8 bus, UINT8 device, UINT16 reg, UINT32 mem_mask); + UINT32 config_read(UINT8 bus, UINT8 device, UINT16 reg, UINT32 mem_mask); + void do_config_write(UINT8 bus, UINT8 device, UINT16 reg, UINT32 data, UINT32 mem_mask); + void propagate_config_write(UINT8 bus, UINT8 device, UINT16 reg, UINT32 data, UINT32 mem_mask); + void config_write(UINT8 bus, UINT8 device, UINT16 reg, UINT32 data, UINT32 mem_mask); + +private: + address_space_config configure_space_config; +}; + +class agp_bridge_device : public pci_bridge_device { +public: + agp_bridge_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + +protected: + virtual void device_start(); + virtual void device_reset(); +}; + +class pci_host_device : public pci_bridge_device { +public: + DECLARE_ADDRESS_MAP(io_configuration_access_map, 32); + + pci_host_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + +protected: + address_space *memory_space, *io_space; + + UINT64 memory_window_start, memory_window_end, memory_offset; + UINT64 io_window_start, io_window_end, io_offset; + + virtual void device_start(); + virtual void device_reset(); + + virtual device_t *bus_root(); + + UINT32 config_address; + + DECLARE_READ32_MEMBER(config_address_r); + DECLARE_WRITE32_MEMBER(config_address_w); + DECLARE_READ32_MEMBER(config_data_r); + DECLARE_WRITE32_MEMBER(config_data_w); + + UINT32 root_config_read(UINT8 bus, UINT8 device, UINT16 reg, UINT32 mem_mask); + void root_config_write(UINT8 bus, UINT8 device, UINT16 reg, UINT32 data, UINT32 mem_mask); + + void regenerate_mapping(); +}; + +class pci_root_device : public device_t { +public: + pci_root_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual void device_start(); + virtual void device_reset(); +}; + +extern const device_type PCI_ROOT; +extern const device_type PCI_BRIDGE; + +#endif diff --git a/src/devices/machine/pci9050.c b/src/devices/machine/pci9050.c new file mode 100644 index 00000000000..2687966c718 --- /dev/null +++ b/src/devices/machine/pci9050.c @@ -0,0 +1,254 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/********************************************************************* + + pci9050.c - PLX PCI9050 PCI to 4x Local Bus Bridge + + by R. Belmont + + PCI spaces: + 0 - (config memory) not used + 1 - (config I/O) config regs + 2 - local bus 1 window + 3 - local bus 2 window + 4 - local bus 3 window + 5 - local bus 4 window + + PCI9050 is located, mapped, and initialized at BFC00700. + + The boot ROM then copies ROM to RAM, jumps to RAM, and starts trying to + access Zeus 2 video through the mapped windows. + +*********************************************************************/ + +#include "pci9050.h" + +const device_type PCI9050 = &device_creator; + +DEVICE_ADDRESS_MAP_START(map, 32, pci9050_device) + AM_RANGE(0x00, 0x0f) AM_READWRITE(lasrr_r, lasrr_w ) + AM_RANGE(0x10, 0x13) AM_READWRITE(eromrr_r, eromrr_w ) + AM_RANGE(0x14, 0x23) AM_READWRITE(lasba_r, lasba_w ) + AM_RANGE(0x24, 0x27) AM_READWRITE(eromba_r, eromba_w ) + AM_RANGE(0x28, 0x37) AM_READWRITE(lasbrd_r, lasbrd_w ) + AM_RANGE(0x38, 0x3b) AM_READWRITE(erombrd_r, erombrd_w) + AM_RANGE(0x3c, 0x4b) AM_READWRITE(csbase_r, csbase_w ) + AM_RANGE(0x4c, 0x4f) AM_READWRITE(intcsr_r, intcsr_w ) + AM_RANGE(0x50, 0x53) AM_READWRITE(cntrl_r, cntrl_w ) +ADDRESS_MAP_END + +DEVICE_ADDRESS_MAP_START(empty, 32, pci9050_device) +ADDRESS_MAP_END + +pci9050_device::pci9050_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : pci_device(mconfig, PCI9050, "PLX PCI9050 PCI to Local Bus Bridge", tag, owner, clock, "pci9050", __FILE__) +{ + for(int i=0; i<4; i++) { + m_devices[i] = NULL; + m_names[i] = NULL; + } +} + +void pci9050_device::set_map(int id, address_map_constructor map, const char *name, device_t *device) +{ + m_maps[id] = map; + m_names[id] = name; + m_devices[id] = device; +} + +void pci9050_device::device_start() +{ + typedef void (pci9050_device::*tramp_t)(address_map &, device_t &); + static const tramp_t trampolines[4] = { + &pci9050_device::map_trampoline<0>, + &pci9050_device::map_trampoline<1>, + &pci9050_device::map_trampoline<2>, + &pci9050_device::map_trampoline<3> + }; + + pci_device::device_start(); + + add_map(0x100, M_MEM, FUNC(pci9050_device::map)); // map 0 is our config registers, mem space + add_map(0x100, M_IO, FUNC(pci9050_device::map)); // map 1 is our config registers, i/o space + + for(int i=0; i<4; i++) + if(m_names[i]) + // add_map(0, M_MEM | M_DISABLED, m_maps[i], m_names[i], m_devices[i]); + add_map(0, M_MEM | M_DISABLED, trampolines[i], m_names[i]); + else + add_map(0, M_MEM | M_DISABLED, FUNC(pci9050_device::empty)); +} + +void pci9050_device::device_config_complete() +{ +} + +void pci9050_device::device_reset() +{ + pci_device::device_reset(); + set_map_address(0, 0); + set_map_address(1, 0); + for(int i=0; i<4; i++) { + m_lasrr[i] = i ? 0 : 0x0ff00000; + m_lasba[i] = 0; + m_lasbrd[i] = 0x00800000; + m_csbase[i] = 0; + set_map_flags(i+2, M_MEM | M_DISABLED); + } + m_eromrr = 0x07ff8000; + m_eromba = 0x00080000; + m_erombrd = 0x00800000; + m_intcsr = 0; + m_cntrl = 0; +} + +void pci9050_device::remap_local(int id) +{ + UINT32 csbase = m_csbase[id]; + UINT32 lasrr = m_lasrr[id]; + logerror("%d csbase=%08x lasrr=%08x\n", id, csbase, lasrr); + + if(!(csbase & 1)) { + set_map_flags(id+2, M_MEM | M_DISABLED); + return; + } + int lsize; + for(lsize=1; lsize<28 && !(csbase & (1<>1, (data & 8)>>3, data & 0xfffffff); + m_lasrr[offset] = data; + remap_local(offset); +} + +READ32_MEMBER (pci9050_device::eromrr_r) +{ + return m_eromrr; +} + +WRITE32_MEMBER(pci9050_device::eromrr_w) +{ + logerror("%06X:PCI9050 ROM range %08x: addr bits 27-11 %08x\n", space.device().safe_pc(), data, data & 0xfffff800); + m_eromrr = data; + remap_rom(); +} + +READ32_MEMBER (pci9050_device::lasba_r) +{ + return m_lasba[offset]; +} + +WRITE32_MEMBER(pci9050_device::lasba_w) +{ + logerror("%06X:PCI9050 local bus %d base %08x: enable %d remap %08x\n", space.device().safe_pc(), offset, data, data&1, data & 0x0ffffffe); + m_lasba[offset] = data; + remap_local(offset); +} + +READ32_MEMBER (pci9050_device::eromba_r) +{ + return m_eromba; +} + +WRITE32_MEMBER(pci9050_device::eromba_w) +{ + logerror("%06X:PCI9050 ROM base %08x: remap %08x\n", space.device().safe_pc(), data, data & 0x0ffff800); + m_eromba = data; + remap_rom(); +} + +READ32_MEMBER (pci9050_device::lasbrd_r) +{ + return m_lasbrd[offset]; +} + +WRITE32_MEMBER(pci9050_device::lasbrd_w) +{ + logerror("%06X:PCI9050 local bus %d descriptors %08x: burst %d prefetch %d width %d, endian %s, endian mode %d\n", space.device().safe_pc(), offset, data, data&1, (data >> 5) & 1, (data >> 22) & 3, ((data >> 24) & 1) ? "BE" : "LE", (data >> 25) & 1); + m_lasbrd[offset] = data; + remap_local(offset); +} + +READ32_MEMBER (pci9050_device::erombrd_r) +{ + return m_erombrd; +} + +WRITE32_MEMBER(pci9050_device::erombrd_w) +{ + logerror("%06X:PCI9050 ROM descriptors %08x: burst %d prefetch %d bits %d, endian %s, endian mode %d\n", space.device().safe_pc(), data, data&1, (data >> 5) & 1, (data >> 22) & 3, ((data >> 24) & 1) ? "BE" : "LE", (data >> 25) & 1); + m_erombrd = data; + remap_rom(); +} + +READ32_MEMBER (pci9050_device::csbase_r) +{ + return m_csbase[offset]; +} + +WRITE32_MEMBER(pci9050_device::csbase_w) +{ + logerror("%06X:PCI9050 chip select %d base %08x: enable %d size %08x\n", space.device().safe_pc(), offset, data, data&1, data&0xfffffffe); + m_csbase[offset] = data; + remap_local(offset); +} + +READ32_MEMBER (pci9050_device::intcsr_r) +{ + return m_intcsr; +} + +WRITE32_MEMBER(pci9050_device::intcsr_w) +{ + logerror("%06X:PCI9050 IRQ control %08x\n", space.device().safe_pc(), data); + m_intcsr = data; + remap_rom(); +} + +READ32_MEMBER (pci9050_device::cntrl_r) +{ + return m_cntrl; +} + +WRITE32_MEMBER(pci9050_device::cntrl_w) +{ + logerror("%06X:PCI9050 IRQ control %08x\n", space.device().safe_pc(), data); + m_cntrl = data; + remap_rom(); +} diff --git a/src/devices/machine/pci9050.h b/src/devices/machine/pci9050.h new file mode 100644 index 00000000000..7915e46b9ea --- /dev/null +++ b/src/devices/machine/pci9050.h @@ -0,0 +1,76 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/********************************************************************* + + pci9050.h - PLX PCI9050 PCI to 4x Local Bus Bridge + + by R. Belmont + +*********************************************************************/ + +#ifndef _PCI9050_H +#define _PCI9050_H + +#include "machine/pci.h" + +#define MCFG_PCI9050_ADD(_tag) \ + MCFG_PCI_DEVICE_ADD(_tag, PCI9050, 0x10b59050, 0x01, 0x06800000, 0x10b59050) + +#define MCFG_PCI9050_SET_MAP(id, map) \ + downcast(device)->set_map(id, ADDRESS_MAP_NAME(map), #map, owner); + +class pci9050_device : + public pci_device +{ +public: + pci9050_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // PCI9050 I/O register space handlers + DECLARE_READ32_MEMBER( lasrr_r ); + DECLARE_WRITE32_MEMBER(lasrr_w ); + DECLARE_READ32_MEMBER( eromrr_r ); + DECLARE_WRITE32_MEMBER(eromrr_w ); + DECLARE_READ32_MEMBER( lasba_r ); + DECLARE_WRITE32_MEMBER(lasba_w ); + DECLARE_READ32_MEMBER( eromba_r ); + DECLARE_WRITE32_MEMBER(eromba_w ); + DECLARE_READ32_MEMBER( lasbrd_r ); + DECLARE_WRITE32_MEMBER(lasbrd_w ); + DECLARE_READ32_MEMBER( erombrd_r); + DECLARE_WRITE32_MEMBER(erombrd_w); + DECLARE_READ32_MEMBER( csbase_r ); + DECLARE_WRITE32_MEMBER(csbase_w ); + DECLARE_READ32_MEMBER( intcsr_r ); + DECLARE_WRITE32_MEMBER(intcsr_w ); + DECLARE_READ32_MEMBER( cntrl_r ); + DECLARE_WRITE32_MEMBER(cntrl_w ); + + void set_map(int id, address_map_constructor map, const char *name, device_t *device); + +protected: + virtual void device_start(); + virtual void device_config_complete(); + virtual void device_reset(); + +private: + DECLARE_ADDRESS_MAP(map, 32); + DECLARE_ADDRESS_MAP(empty, 32); + + const char *m_names[4]; + device_t *m_devices[4]; + address_map_constructor m_maps[4]; + + UINT32 m_lasrr[4], m_lasba[4], m_lasbrd[4], m_csbase[4]; + UINT32 m_eromrr, m_eromba, m_erombrd, m_intcsr, m_cntrl; + + void remap_local(int id); + void remap_rom(); + + template void map_trampoline(address_map &map, device_t &device) { + m_maps[id](map, *m_devices[id]); + } +}; + +extern const device_type PCI9050; + +#endif diff --git a/src/devices/machine/pckeybrd.c b/src/devices/machine/pckeybrd.c new file mode 100644 index 00000000000..f7a049e2469 --- /dev/null +++ b/src/devices/machine/pckeybrd.c @@ -0,0 +1,1305 @@ +// license:BSD-3-Clause +// copyright-holders:Peter Trauner, Kevin Thacker +/********************************************************************** + + pckeybrd.c + + PC-style keyboard emulation + + This emulation is decoupled from the AT 8042 emulation used in the + IBM ATs and above + +**********************************************************************/ + +/* Todo: (added by KT 22-Jun-2000 + 1. Check scancodes I have added are the actual scancodes for set 2 or 3. + 2. Check how codes are changed based on Shift/Control states for those sets + that require it - info in Help PC! + +*/ + +#include "emu.h" +#include "pckeybrd.h" + +/* AT keyboard documentation comes from www.beyondlogic.org and HelpPC documentation */ + +/* to enable logging of keyboard read/writes */ +#define LOG_KEYBOARD 0 + + +/* + The PS/2 models have three make/break scan code sets. The first + set matches the PC & XT make/break scan code set and is the one + listed here. Scan code sets are selected by writing the value F0 + to the keyboard via the ~8042~ (port 60h). The following is a brief + description of the scan code sets (see the PS/2 Technical Reference + manuals for more information on scan code sets 2 and 3): + + * set 1, each key has a base scan code. Some keys generate + extra scan codes to generate artificial shift states. This + is similar to the standard scan code set used on the PC and XT. + * set 2, each key sends one make scan code and two break scan + codes bytes (F0 followed by the make code). This scan code + set is available on the IBM AT also. + * set 3, each key sends one make scan code and two break scan + codes bytes (F0 followed by the make code) and no keys are + altered by Shift/Alt/Ctrl keys. + * typematic scan codes are the same as the make scan code + +*/ + + +/* using the already existing input port definitions, this table re-maps +to scancode set 3. +I don't have the details for scan-code set 2,3 but they sound very similar +to the scancode set I have here. - KT 22/Jun/2000 */ + + +/* key set 3 */ +const int at_keyboard_device::m_scancode_set_2_3[]= +{ + 0, + 0x076, + 0x016, + 0x01e, + 0x026, + 0x025, + 0x02e, + 0x036, + 0x03d, + 0x03e, + 0x046, + 0x045, + 0x04e, + 0x055, + 0x066, + 0x00d, + 0x015, + 0x01d, + 0x024, + 0x02d, + 0x02c, + 0x035, + 0x03c, + 0x043, + 0x044, + 0x04d, + 0x054, + 0x05b, + 0x05a, + 0x014, + 0x01c, + 0x01b, + 0x023, + 0x02b, + 0x034, + 0x033, + 0x03b, + 0x042, + 0x04b, + 0x04c, + 0x052, + 0x00e, + 0x012, + 0x05d, + 0x01a, + 0x022, + 0x021, + 0x02a, + 0x032, + 0x031, + 0x03a, + 0x041, + 0x049, + 0x04a, + 0x059, + 0x000, + 0x011, + 0x029, + 0x058, + 0x05, + 0x06, + 0x04, + 0x0c, + 0x03, + 0x0b, + 0x083, + 0x0a, + 0x01, + 0x09, + 0x077, + 0x07e, + 0x06c, + 0x075, + 0x07d, + 0x07b, + 0x06b, + 0x073, + 0x074, + 0x079, + 0x069, + 0x072, + 0x07a, + 0x070, + 0x071, + 0x00, + 0x00, + 0x078, + 0x07, + 0x05a, + 0x014, + 0x04a, + 0x000, + 0x011, + 0x06c, + 0x075, + 0x07d, + 0x06b, + 0x074, + 0x069, + 0x072, + 0x07a, + 0x070, + 0x071, + 0x000, + 0x000, + 0x000 +}; + + +const at_keyboard_device::extended_keyboard_code at_keyboard_device::m_mf2_code[0x10][2/*numlock off, on*/]={ + { { "\xe0\x1c", "\xe0\x9c" } }, // keypad enter + { { "\xe0\x1d", "\xe0\x9d" } }, // right control + { { "\xe0\x35", "\xe0\xb5" } }, + { { "\xe0\x37", "\xe0\xb7" } }, + { { "\xe0\x38", "\xe0\xb8" } }, + { { "\xe0\x47", "\xe0\xc7" }, { "\xe0\x2a\xe0\x47", "\xe0\xc7\xe0\xaa" } }, + { { "\xe0\x48", "\xe0\xc8" }, { "\xe0\x2a\xe0\x48", "\xe0\xc8\xe0\xaa" } }, + { { "\xe0\x49", "\xe0\xc9" }, { "\xe0\x2a\xe0\x49", "\xe0\xc9\xe0\xaa" } }, + { { "\xe0\x4b", "\xe0\xcb" }, { "\xe0\x2a\xe0\x4b", "\xe0\xcb\xe0\xaa" } }, + { { "\xe0\x4d", "\xe0\xcd" }, { "\xe0\x2a\xe0\x4d", "\xe0\xcd\xe0\xaa" } }, + { { "\xe0\x4f", "\xe0\xcf" }, { "\xe0\x2a\xe0\x4f", "\xe0\xcf\xe0\xaa" } }, + { { "\xe0\x50", "\xe0\xd0" }, { "\xe0\x2a\xe0\x50", "\xe0\xd0\xe0\xaa" } }, + { { "\xe0\x51", "\xe0\xd1" }, { "\xe0\x2a\xe0\x51", "\xe0\xd1\xe0\xaa" } }, + { { "\xe0\x52", "\xe0\xd2" }, { "\xe0\x2a\xe0\x52", "\xe0\xd2\xe0\xaa" } }, + { { "\xe0\x53", "\xe0\xd3" }, { "\xe0\x2a\xe0\x53", "\xe0\xd3\xe0\xaa" } }, + { { "\xe1\x1d\x45\xe1\x9d\xc5" }, { "\xe0\x2a\xe1\x1d\x45\xe1\x9d\xc5" } } +}; + +/* I don't think these keys change if num-lock is active! */ +/* pc-at extended keyboard make/break codes for code set 3 */ +const at_keyboard_device::extended_keyboard_code at_keyboard_device::m_extended_codes_set_2_3[]= +{ + /*keypad enter */ + { + "\xe0\x5a", + "\xe0\xf0\x5a" + }, + /* right control */ + { + "\xe0\x14", + "\xe0\xf0\x14" + }, + /* keypad slash */ + { + "\xe0\x4a", + "\xe0\xf0\x4a" + }, + /* print screen */ + { + "\xe0\x12\xe0\x7c", + 0, /* I don't know the break sequence */ + + }, + /* right alt */ + { + "\xe0\x11", + "\xe0\xf0\x11" + }, + /* home */ + { + "\xe0\x6c", + "\xe0\xf0\x6c" + }, + /* cursor up */ + { + "\xe0\x75", + "\xe0\xf0\x75" + }, + /* page up */ + { + "\xe0\x7d", + "\xe0\xf0\x7d" + }, + /* cursor left */ + { + "\xe0\x6b", + "\xe0\xf0\x6b", + }, + /* cursor right */ + { + "\xe0\x74", + "\xe0\xf0\x74" + }, + /* end */ + { + "\xe0\x69", + "\xe0\xf0\x69", + }, + /* cursor down */ + { + "\xe0\x72", + "\xe0\xf0\x72" + }, + /* page down */ + { + "\xe0\x7a", + "\xe0\xf0\x7a" + }, + /* insert */ + { + "\xe0\x70", + "\xe0\xf0\x70", + }, + /* delete */ + { + "\xe0\x71", + "\xe0\xf0\x71" + }, + /* pause */ + { + "\xe1\x14\x77\xe1\xf0\x14\xf0\x77", + 0, /*?? I don't know the break sequence */ + } + +}; + +const device_type PC_KEYB = &device_creator; +const device_type AT_KEYB = &device_creator; + +pc_keyboard_device::pc_keyboard_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, PC_KEYB, "PC Keyboard", tag, owner, clock, "pc_keyb", __FILE__), + m_type(KEYBOARD_TYPE_PC), + m_ioport_0(*this, ":pc_keyboard_0"), + m_ioport_1(*this, ":pc_keyboard_1"), + m_ioport_2(*this, ":pc_keyboard_2"), + m_ioport_3(*this, ":pc_keyboard_3"), + m_ioport_4(*this, ":pc_keyboard_4"), + m_ioport_5(*this, ":pc_keyboard_5"), + m_ioport_6(*this, ":pc_keyboard_6"), + m_ioport_7(*this, ":pc_keyboard_7"), + m_out_keypress_func(*this) +{ +} + +pc_keyboard_device::pc_keyboard_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + m_ioport_0(*this, ":pc_keyboard_0"), + m_ioport_1(*this, ":pc_keyboard_1"), + m_ioport_2(*this, ":pc_keyboard_2"), + m_ioport_3(*this, ":pc_keyboard_3"), + m_ioport_4(*this, ":pc_keyboard_4"), + m_ioport_5(*this, ":pc_keyboard_5"), + m_ioport_6(*this, ":pc_keyboard_6"), + m_ioport_7(*this, ":pc_keyboard_7"), + m_out_keypress_func(*this) +{ +} + +at_keyboard_device::at_keyboard_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + pc_keyboard_device(mconfig, AT_KEYB, "AT Keyboard", tag, owner, clock, "at_keyb", __FILE__), + m_scan_code_set(1) +{ + m_type = KEYBOARD_TYPE_AT; +} + + +void pc_keyboard_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + polling(); + if(!charqueue_empty()) + m_out_keypress_func(1); +} + +void pc_keyboard_device::device_start() +{ + save_item(NAME(m_delay)); + save_item(NAME(m_repeat)); + save_item(NAME(m_numlock)); + save_item(NAME(m_on)); + save_item(NAME(m_head)); + save_item(NAME(m_tail)); + save_pointer(NAME(m_queue), ARRAY_LENGTH(m_queue)); + save_pointer(NAME(m_make), ARRAY_LENGTH(m_make)); + + memset(m_make, 0, sizeof(m_make)); + + machine().ioport().natkeyboard().configure( + ioport_queue_chars_delegate(FUNC(pc_keyboard_device::queue_chars), this), + ioport_accept_char_delegate(FUNC(pc_keyboard_device::accept_char), this), + ioport_charqueue_empty_delegate(FUNC(pc_keyboard_device::charqueue_empty), this)); + + m_out_keypress_func.resolve_safe(); + m_keyboard_timer = timer_alloc(); +} + +void at_keyboard_device::device_start() +{ + save_item(NAME(m_scan_code_set)); + save_item(NAME(m_input_state)); + pc_keyboard_device::device_start(); +} + +void pc_keyboard_device::device_reset() +{ + m_delay = 60; + m_repeat = 8; + m_numlock = 0; + m_on = true; + /* set default led state */ + set_led_status(machine(), 2, 0); + set_led_status(machine(), 0, 0); + set_led_status(machine(), 1, 0); + + m_head = m_tail = 0; + queue_insert(0xaa); + m_keyboard_timer->adjust(attotime::from_msec(5), 0, attotime::from_hz(60)); +} + +void at_keyboard_device::device_reset() +{ + m_input_state = 0; + pc_keyboard_device::device_reset(); +} + +WRITE_LINE_MEMBER(pc_keyboard_device::enable) +{ + if(state && !m_on) + { + if(m_type == KEYBOARD_TYPE_PC) + reset(); + else + m_keyboard_timer->adjust(attotime::from_msec(5), 0, attotime::from_hz(60)); + } + else if(!state) + m_keyboard_timer->adjust(attotime::never); + + m_on = state ? true : false; +} + +/* insert a code into the buffer */ +void pc_keyboard_device::queue_insert(UINT8 data) +{ + if (LOG_KEYBOARD) + logerror("keyboard queueing %.2x\n",data); + + m_queue[m_head] = data; + m_head++; + m_head %= ARRAY_LENGTH(m_queue); +} + + +int pc_keyboard_device::queue_size(void) +{ + int queue_size; + queue_size = m_head - m_tail; + if (queue_size < 0) + queue_size += ARRAY_LENGTH(m_queue); + return queue_size; +} + +void pc_keyboard_device::standard_scancode_insert(int our_code, int pressed) +{ + if (!pressed) + { + /* adjust code for break code */ + our_code|=0x080; + } + queue_insert(our_code); +} + +/* add codes for standard keys */ +void at_keyboard_device::standard_scancode_insert(int our_code, int pressed) +{ + int scancode = our_code; + + switch (m_scan_code_set) + { + case 1: + default: + { + /* the original code was designed for this set, and there is + a 1:1 correspondance for the scancodes */ + scancode = our_code; + + if (!pressed) + { + /* adjust code for break code */ + scancode|=0x080; + } + } + break; + + case 2: + case 3: + { + /* lookup scancode */ + scancode = m_scancode_set_2_3[our_code]; + + if (!pressed) + { + /* break code */ + queue_insert(0x0f0); + } + + } + break; + } + + queue_insert(scancode); +} + +void at_keyboard_device::extended_scancode_insert(int code, int pressed) +{ + code = code - 0x060; + + switch (m_scan_code_set) + { + case 1: + default: + { + if (pressed) + { + if (m_mf2_code[code][m_numlock].pressed) + helper(m_mf2_code[code][m_numlock].pressed); + else + helper(m_mf2_code[code][0].pressed); + } + else + { + if (m_mf2_code[code][m_numlock].released) + helper(m_mf2_code[code][m_numlock].released); + else if (m_mf2_code[code][0].released) + helper(m_mf2_code[code][0].released); + } + } + break; + + case 2: + case 3: + { + const extended_keyboard_code *key = &m_extended_codes_set_2_3[code]; + + if (pressed) + { + if (key->pressed) + { + helper(key->pressed); + } + } + else + { + if (key->released) + { + helper(key->released); + } + } + } + break; + } + +} + +/* add a list of codes to the keyboard buffer */ +void at_keyboard_device::helper(const char *codes) +{ + int i; + for (i = 0; codes[i]; i++) + queue_insert(codes[i]); +} + +/************************************************************************** + * scan keys and stuff make/break codes + **************************************************************************/ + +UINT32 pc_keyboard_device::readport(int port) +{ + UINT32 result = 0; + switch(port) + { + case 0: + if(m_ioport_0) + result = m_ioport_0->read(); + break; + case 1: + if(m_ioport_1) + result = m_ioport_1->read(); + break; + case 2: + if(m_ioport_2) + result = m_ioport_2->read(); + break; + case 3: + if(m_ioport_3) + result = m_ioport_3->read(); + break; + case 4: + if(m_ioport_4) + result = m_ioport_4->read(); + break; + case 5: + if(m_ioport_5) + result = m_ioport_5->read(); + break; + case 6: + if(m_ioport_6) + result = m_ioport_6->read(); + break; + case 7: + if(m_ioport_7) + result = m_ioport_7->read(); + break; + } + return result; +} + +void pc_keyboard_device::polling(void) +{ + int i; + + if (m_on) + { + /* add codes for keys that are set */ + for( i = 0x01; i < 0x80; i++ ) + { + if (i==0x60) i+=0x10; // keys 0x60..0x6f need special handling + + if( readport(i/16) & (1 << (i & 15)) ) + { + if( m_make[i] == 0 ) + { + m_make[i] = 1; + + if (i==0x45) m_numlock^=1; + + standard_scancode_insert(i,1); + } + else if((i != 0x45) && (i != 0x3a)) // don't send repeats for caps or num lock + { + m_make[i] += 1; + + if( m_make[i] == m_delay ) + { + standard_scancode_insert(i, 1); + } + else + { + if( m_make[i] == m_delay + m_repeat ) + { + m_make[i] = m_delay; + standard_scancode_insert(i, 1); + } + } + } + } + else + { + if( m_make[i] ) + { + m_make[i] = 0; + + standard_scancode_insert(i, 0); + } + } + } + + if(m_type != KEYBOARD_TYPE_PC) + { + /* extended scan-codes */ + for( i = 0x60; i < 0x70; i++ ) + { + if( readport(i/16) & (1 << (i & 15)) ) + { + if( m_make[i] == 0 ) + { + m_make[i] = 1; + + extended_scancode_insert(i,1); + + } + else + { + m_make[i] += 1; + if( m_make[i] == m_delay ) + { + extended_scancode_insert(i, 1); + } + else + { + if( m_make[i] == m_delay + m_repeat ) + { + m_make[i]=m_delay; + + extended_scancode_insert(i, 1); + } + } + } + } + else + { + if( m_make[i] ) + { + m_make[i] = 0; + + extended_scancode_insert(i,0); + } + } + } + } + } +} + +READ8_MEMBER(pc_keyboard_device::read) +{ + int data; + if (m_tail == m_head) + return 0; + + data = m_queue[m_tail]; + + if (LOG_KEYBOARD) + logerror("read(): Keyboard Read 0x%02x\n",data); + + m_tail++; + m_tail %= ARRAY_LENGTH(m_queue); + return data; +} + +void pc_keyboard_device::clear_buffer(void) +{ + m_head = m_tail = 0; +} + +void at_keyboard_device::clear_buffer_and_acknowledge(void) +{ + clear_buffer(); + queue_insert(0x0fa); +} + +/* From Ralf Browns Interrupt list: + +Values for keyboard commands (data also goes to PORT 0060h): +Value Count Description + EDh double set/reset mode indicators Caps Num Scrl + bit 2 = CapsLk, bit 1 = NumLk, bit 0 = ScrlLk + all other bits must be zero. + EEh sngl diagnostic echo. returns EEh. + EFh sngl NOP (No OPeration). reserved for future use + EF+26h double [Cherry MF2 G80-1501HAD] read 256 bytes of chipcard data + keyboard must be disabled before this and has to + be enabled after finished. + F0h double get/set scan code set + 00h get current set + 01h scancode set 1 (PCs and PS/2 mod 30, except Type 2 ctrlr) + + 02h scancode set 2 (ATs, PS/2, default) + 03h scancode set 3 + F2h sngl read keyboard ID (read two ID bytes) + AT keyboards returns FA (ACK) + MF2 returns AB 41 (translation) or + AB 83 (pass through) + F3h double set typematic rate/delay + format of the second byte: + bit7=0 : reserved + bit6-5 : typemativ delay + 00b=250ms 10b= 750ms + 01b=500ms 11b=1000ms + bit4-0 : typematic rate (see #P050) + F4h sngl enable keyboard + F5h sngl disable keyboard. set default parameters (no keyboard scanning) + F6h sngl set default parameters + F7h sngl [MCA] set all keys to typematic (scancode set 3) + + F8h sngl [MCA] set all keys to make/release + F9h sngl [MCA] set all keys to make only + FAh sngl [MCA] set all keys to typematic/make/release + FBh sngl [MCA] set al keys to typematic + FCh double [MCA] set specific key to make/release + FDh double [MCA] set specific key to make only + FEh sngl resend last scancode + FFh sngl perform internal power-on reset function +Note: each command is acknowledged by FAh (ACK), if not mentioned otherwise. + See PORT 0060h-R for details. +SeeAlso: #P046 +*/ + +WRITE8_MEMBER(at_keyboard_device::write) +{ + if (LOG_KEYBOARD) + logerror("keyboard write %.2x\n",data); + + switch (m_input_state) + { + case 0: + switch (data) { + case 0xed: // leds schalten + /* acknowledge */ + queue_insert(0x0fa); + /* now waiting for code... */ + m_input_state=1; + break; + case 0xee: // echo + /* echo code with no acknowledge */ + queue_insert(0xee); + break; + case 0xf0: // scancodes adjust + /* acknowledge */ + clear_buffer_and_acknowledge(); + /* waiting for data */ + m_input_state=2; + break; + case 0xf2: // identify keyboard + /* ack and two byte keyboard id */ + queue_insert(0xfa); + + /* send keyboard code */ + if (m_type == KEYBOARD_TYPE_MF2) { + queue_insert(0xab); + queue_insert(0x41); + } + else + { + /* from help-pc docs */ + queue_insert(0x0ab); + queue_insert(0x083); + } + + break; + case 0xf3: // adjust rates + /* acknowledge */ + queue_insert(0x0fa); + + m_input_state=3; + break; + case 0xf4: // activate + clear_buffer_and_acknowledge(); + + enable(1); + break; + case 0xf5: + /* acknowledge */ + clear_buffer_and_acknowledge(); + // standardvalues + enable(0); + break; + case 0xf6: + clear_buffer_and_acknowledge(); + // standardvalues + enable(1); + break; + case 0xfe: // resend + // should not happen, for now send 0 + queue_insert(0); //m_last_code); + break; + case 0xff: // reset + /* it doesn't state this in the docs I have read, but I assume + that the keyboard input buffer is cleared. The PCW16 sends &ff, + and requires that 0x0fa is the first byte to be read */ + + reset(); + clear_buffer_and_acknowledge(); + queue_insert(0xaa); + break; + } + break; + case 1: + /* code received */ + m_input_state=0; + + /* command? */ + if (data & 0x080) + { + /* command received instead of code - execute command */ + write(space, offset, data); + } + else + { + /* send acknowledge */ + queue_insert(0x0fa); + + /* led bits */ + /* bits: 0 scroll lock, 1 num lock, 2 capslock */ + + /* led's in same order as my keyboard leds. */ + /* num lock, caps lock, scroll lock */ + set_led_status(machine(), 2, (data & 0x01)); + set_led_status(machine(), 0, ((data & 0x02)>>1)); + set_led_status(machine(), 1, ((data & 0x04)>>2)); + + } + break; + case 2: + m_input_state=0; + + /* command? */ + if (data & 0x080) + { + /* command received instead of code - execute command */ + write(space, offset, data); + } + else + { + /* 00 return byte indicating scan code set in use + 01 select scan code set 1 (used on PC & XT) + 02 select scan code set 2 + 03 select scan code set 3 + */ + + if (data == 0x00) + { + queue_insert(m_scan_code_set); + } + else + { + if(data && (data <= 3)) + m_scan_code_set = data; + } + } + + break; + case 3: + /* 6,5: 250ms, 500ms, 750ms, 1s */ + /* 4..0: 30 26.7 .... 2 chars/s*/ + + /* command? */ + m_input_state=0; + if (data & 0x080) + { + /* command received instead of code - execute command */ + write(space, offset, data); + } + else + { + /* received keyboard repeat */ + + } + + break; + } +} + +/*************************************************************************** + unicode_char_to_at_keycode +***************************************************************************/ + +UINT8 pc_keyboard_device::unicode_char_to_at_keycode(unicode_char ch) +{ + UINT8 b; + switch(ch) + { + case '\033': b = 1; break; + case '1': b = 2; break; + case '2': b = 3; break; + case '3': b = 4; break; + case '4': b = 5; break; + case '5': b = 6; break; + case '6': b = 7; break; + case '7': b = 8; break; + case '8': b = 9; break; + case '9': b = 10; break; + case '0': b = 11; break; + case '-': b = 12; break; + case '=': b = 13; break; + case '\010': b = 14; break; + case '\t': b = 15; break; + case 'q': b = 16; break; + case 'w': b = 17; break; + case 'e': b = 18; break; + case 'r': b = 19; break; + case 't': b = 20; break; + case 'y': b = 21; break; + case 'u': b = 22; break; + case 'i': b = 23; break; + case 'o': b = 24; break; + case 'p': b = 25; break; + case '[': b = 26; break; + case ']': b = 27; break; + case '\r': b = 28; break; + case UCHAR_MAMEKEY(CAPSLOCK): b = 29; break; + case 'a': b = 30; break; + case 's': b = 31; break; + case 'd': b = 32; break; + case 'f': b = 33; break; + case 'g': b = 34; break; + case 'h': b = 35; break; + case 'j': b = 36; break; + case 'k': b = 37; break; + case 'l': b = 38; break; + case ';': b = 39; break; + case '\'': b = 40; break; + case '`': b = 41; break; + case '\\': b = 43; break; + case 'z': b = 44; break; + case 'x': b = 45; break; + case 'c': b = 46; break; + case 'v': b = 47; break; + case 'b': b = 48; break; + case 'n': b = 49; break; + case 'm': b = 50; break; + case ',': b = 51; break; + case '.': b = 52; break; + case '/': b = 53; break; + case ' ': b = 0x39; break; + case UCHAR_MAMEKEY(F1): b = 0x3b; break; + case UCHAR_MAMEKEY(F2): b = 0x3c; break; + case UCHAR_MAMEKEY(F3): b = 0x3d; break; + case UCHAR_MAMEKEY(F4): b = 0x3e; break; + case UCHAR_MAMEKEY(F5): b = 0x3f; break; + case UCHAR_MAMEKEY(F6): b = 0x40; break; + case UCHAR_MAMEKEY(F7): b = 0x41; break; + case UCHAR_MAMEKEY(F8): b = 0x42; break; + case UCHAR_MAMEKEY(F9): b = 0x43; break; + case UCHAR_MAMEKEY(F10): b = 0x44; break; + case UCHAR_MAMEKEY(NUMLOCK): b = 0x45; break; + case UCHAR_MAMEKEY(SCRLOCK): b = 0x46; break; + case UCHAR_MAMEKEY(7_PAD): b = 0x47; break; + case UCHAR_MAMEKEY(8_PAD): b = 0x48; break; + case UCHAR_MAMEKEY(9_PAD): b = 0x49; break; + case UCHAR_MAMEKEY(MINUS_PAD): b = 0x4a; break; + case UCHAR_MAMEKEY(4_PAD): b = 0x4b; break; + case UCHAR_MAMEKEY(5_PAD): b = 0x4c; break; + case UCHAR_MAMEKEY(6_PAD): b = 0x4d; break; + case UCHAR_MAMEKEY(PLUS_PAD): b = 0x4e; break; + case UCHAR_MAMEKEY(1_PAD): b = 0x4f; break; + case UCHAR_MAMEKEY(2_PAD): b = 0x50; break; + case UCHAR_MAMEKEY(3_PAD): b = 0x51; break; + case UCHAR_MAMEKEY(0_PAD): b = 0x52; break; + case UCHAR_MAMEKEY(DEL_PAD): b = 0x53; break; + case UCHAR_MAMEKEY(F11): b = 0x57; break; + case UCHAR_MAMEKEY(F12): b = 0x58; break; + case '~': b = 0x81; break; + case '!': b = 0x82; break; + case '@': b = 0x83; break; + case '#': b = 0x84; break; + case '$': b = 0x85; break; + case '%': b = 0x86; break; + case '^': b = 0x87; break; + case '&': b = 0x88; break; + case '*': b = 0x89; break; + case '(': b = 0x8a; break; + case ')': b = 0x8b; break; + case '_': b = 0x8c; break; + case '+': b = 0x8d; break; + case 'Q': b = 0x90; break; + case 'W': b = 0x91; break; + case 'E': b = 0x92; break; + case 'R': b = 0x93; break; + case 'T': b = 0x94; break; + case 'Y': b = 0x95; break; + case 'U': b = 0x96; break; + case 'I': b = 0x97; break; + case 'O': b = 0x98; break; + case 'P': b = 0x99; break; + case '{': b = 0x9a; break; + case '}': b = 0x9b; break; + case 'A': b = 0x9e; break; + case 'S': b = 0x9f; break; + case 'D': b = 0xa0; break; + case 'F': b = 0xa1; break; + case 'G': b = 0xa2; break; + case 'H': b = 0xa3; break; + case 'J': b = 0xa4; break; + case 'K': b = 0xa5; break; + case 'L': b = 0xa6; break; + case ':': b = 0xa7; break; + case '\"': b = 0xa8; break; + case '|': b = 0xab; break; + case 'Z': b = 0xac; break; + case 'X': b = 0xad; break; + case 'C': b = 0xae; break; + case 'V': b = 0xaf; break; + case 'B': b = 0xb0; break; + case 'N': b = 0xb1; break; + case 'M': b = 0xb2; break; + case '<': b = 0xb3; break; + case '>': b = 0xb4; break; + case '?': b = 0xb5; break; + default: b = 0; break; + } + return b; +} + +/*************************************************************************** + queue_chars +***************************************************************************/ + +int pc_keyboard_device::queue_chars(const unicode_char *text, size_t text_len) +{ + int i; + UINT8 b; + + for (i = 0; (i < text_len) && ((queue_size()) + 4 < sizeof(m_queue)); i++) + { + b = unicode_char_to_at_keycode(text[i]); + if (b) + { + if (b & 0x80) + standard_scancode_insert(0x36, 1); + + standard_scancode_insert(b & 0x7f, 1); + standard_scancode_insert(b & 0x7f, 0); + + if (b & 0x80) + standard_scancode_insert(0x36, 0); + } + } + return i; +} + + + +/*************************************************************************** + Keyboard declaration +***************************************************************************/ + +INPUT_PORTS_START( pc_keyboard ) + PORT_START("pc_keyboard_0") + PORT_BIT ( 0x0001, 0x0000, IPT_UNUSED ) /* unused scancode 0 */ + PORT_BIT( 0x0002, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_ESC) PORT_CHAR(27) /* Esc 01 81 */ + PORT_BIT( 0x0004, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_1) PORT_CHAR('1') PORT_CHAR('!') /* 1 02 82 */ + PORT_BIT( 0x0008, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_2) PORT_CHAR('2') PORT_CHAR('@') /* 2 03 83 */ + PORT_BIT( 0x0010, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_3) PORT_CHAR('3') PORT_CHAR('#') /* 3 04 84 */ + PORT_BIT( 0x0020, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_4) PORT_CHAR('4') PORT_CHAR('$') /* 4 05 85 */ + PORT_BIT( 0x0040, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_5) PORT_CHAR('5') PORT_CHAR('%') /* 5 06 86 */ + PORT_BIT( 0x0080, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_6) PORT_CHAR('6') PORT_CHAR('^') /* 6 07 87 */ + PORT_BIT( 0x0100, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_7) PORT_CHAR('7') PORT_CHAR('&') /* 7 08 88 */ + PORT_BIT( 0x0200, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_8) PORT_CHAR('8') PORT_CHAR('*') /* 8 09 89 */ + PORT_BIT( 0x0400, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_9) PORT_CHAR('9') PORT_CHAR('(') /* 9 0A 8A */ + PORT_BIT( 0x0800, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_0) PORT_CHAR('0') PORT_CHAR(')') /* 0 0B 8B */ + PORT_BIT( 0x1000, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_MINUS) PORT_CHAR('-') PORT_CHAR('_') /* - 0C 8C */ + PORT_BIT( 0x2000, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_EQUALS) PORT_CHAR('=') PORT_CHAR('+') /* = 0D 8D */ + PORT_BIT( 0x4000, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_BACKSPACE) PORT_CHAR(8) /* Backspace 0E 8E */ + PORT_BIT( 0x8000, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_TAB) PORT_CHAR(9) /* Tab 0F 8F */ + + PORT_START("pc_keyboard_1") + PORT_BIT( 0x0001, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_Q) PORT_CHAR('Q') /* Q 10 90 */ + PORT_BIT( 0x0002, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_W) PORT_CHAR('W') /* W 11 91 */ + PORT_BIT( 0x0004, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_E) PORT_CHAR('E') /* E 12 92 */ + PORT_BIT( 0x0008, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_R) PORT_CHAR('R') /* R 13 93 */ + PORT_BIT( 0x0010, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_T) PORT_CHAR('T') /* T 14 94 */ + PORT_BIT( 0x0020, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_Y) PORT_CHAR('Y') /* Y 15 95 */ + PORT_BIT( 0x0040, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_U) PORT_CHAR('U') /* U 16 96 */ + PORT_BIT( 0x0080, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_I) PORT_CHAR('I') /* I 17 97 */ + PORT_BIT( 0x0100, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_O) PORT_CHAR('O') /* O 18 98 */ + PORT_BIT( 0x0200, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_P) PORT_CHAR('P') /* P 19 99 */ + PORT_BIT( 0x0400, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_OPENBRACE) PORT_CHAR('[') PORT_CHAR('{') /* [ 1A 9A */ + PORT_BIT( 0x0800, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_CLOSEBRACE) PORT_CHAR(']') PORT_CHAR('}') /* ] 1B 9B */ + PORT_BIT( 0x1000, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_ENTER) PORT_CHAR(13) /* Enter 1C 9C */ + PORT_BIT( 0x2000, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_LCONTROL) PORT_CHAR(UCHAR_MAMEKEY(LCONTROL)) /* Left Ctrl 1D 9D */ + PORT_BIT( 0x4000, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_A) PORT_CHAR('A') /* A 1E 9E */ + PORT_BIT( 0x8000, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_S) PORT_CHAR('S') /* S 1F 9F */ + + PORT_START("pc_keyboard_2") + PORT_BIT( 0x0001, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_D) PORT_CHAR('D') /* D 20 A0 */ + PORT_BIT( 0x0002, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_F) PORT_CHAR('F') /* F 21 A1 */ + PORT_BIT( 0x0004, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_G) PORT_CHAR('G') /* G 22 A2 */ + PORT_BIT( 0x0008, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_H) PORT_CHAR('H') /* H 23 A3 */ + PORT_BIT( 0x0010, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_J) PORT_CHAR('J') /* J 24 A4 */ + PORT_BIT( 0x0020, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_K) PORT_CHAR('K') /* K 25 A5 */ + PORT_BIT( 0x0040, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_L) PORT_CHAR('L') /* L 26 A6 */ + PORT_BIT( 0x0080, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_COLON) PORT_CHAR(';') PORT_CHAR(':') /* ; 27 A7 */ + PORT_BIT( 0x0100, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_QUOTE) PORT_CHAR('\'') PORT_CHAR('\"') /* ' 28 A8 */ + PORT_BIT( 0x0200, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_TILDE) PORT_CHAR('`') PORT_CHAR('~') /* ` 29 A9 */ + PORT_BIT( 0x0400, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_LSHIFT) PORT_CHAR(UCHAR_MAMEKEY(LSHIFT)) /* Left Shift 2A AA */ + PORT_BIT( 0x0800, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_BACKSLASH) PORT_CHAR('\\') PORT_CHAR('|') /* \ 2B AB */ + PORT_BIT( 0x1000, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_Z) PORT_CHAR('Z') /* Z 2C AC */ + PORT_BIT( 0x2000, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_X) PORT_CHAR('X') /* X 2D AD */ + PORT_BIT( 0x4000, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_C) PORT_CHAR('C') /* C 2E AE */ + PORT_BIT( 0x8000, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_V) PORT_CHAR('V') /* V 2F AF */ + + PORT_START("pc_keyboard_3") + PORT_BIT( 0x0001, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_B) PORT_CHAR('B') /* B 30 B0 */ + PORT_BIT( 0x0002, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_N) PORT_CHAR('N') /* N 31 B1 */ + PORT_BIT( 0x0004, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_M) PORT_CHAR('M') /* M 32 B2 */ + PORT_BIT( 0x0008, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_COMMA) PORT_CHAR(',') PORT_CHAR('<') /* , 33 B3 */ + PORT_BIT( 0x0010, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_STOP) PORT_CHAR('.') PORT_CHAR('>') /* . 34 B4 */ + PORT_BIT( 0x0020, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_SLASH) PORT_CHAR('/') PORT_CHAR('?') /* / 35 B5 */ + PORT_BIT( 0x0040, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_RSHIFT) PORT_CHAR(UCHAR_MAMEKEY(RSHIFT)) /* Right Shift 36 B6 */ + PORT_BIT( 0x0080, 0x0000, IPT_KEYBOARD) PORT_NAME("KP * (PrtScr)") PORT_CODE(KEYCODE_ASTERISK) /* Keypad * (PrtSc) 37 B7 */ + PORT_BIT( 0x0100, 0x0000, IPT_KEYBOARD) PORT_NAME("Alt") PORT_CODE(KEYCODE_LALT) /* Left Alt 38 B8 */ + PORT_BIT( 0x0200, 0x0000, IPT_KEYBOARD) PORT_NAME("Space") PORT_CODE(KEYCODE_SPACE) PORT_CHAR(' ') /* Space 39 B9 */ + PORT_BIT( 0x0400, 0x0000, IPT_KEYBOARD) PORT_NAME("Caps") PORT_CODE(KEYCODE_CAPSLOCK) /* Caps Lock 3A BA */ + PORT_BIT( 0x0800, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_F1) PORT_CHAR(UCHAR_MAMEKEY(F1)) /* F1 3B BB */ + PORT_BIT( 0x1000, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_F2) PORT_CHAR(UCHAR_MAMEKEY(F2)) /* F2 3C BC */ + PORT_BIT( 0x2000, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_F3) PORT_CHAR(UCHAR_MAMEKEY(F3)) /* F3 3D BD */ + PORT_BIT( 0x4000, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_F4) PORT_CHAR(UCHAR_MAMEKEY(F4)) /* F4 3E BE */ + PORT_BIT( 0x8000, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_F5) PORT_CHAR(UCHAR_MAMEKEY(F5)) /* F5 3F BF */ + + PORT_START("pc_keyboard_4") + PORT_BIT( 0x0001, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_F6) PORT_CHAR(UCHAR_MAMEKEY(F6)) /* F6 40 C0 */ + PORT_BIT( 0x0002, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_F7) PORT_CHAR(UCHAR_MAMEKEY(F7)) /* F7 41 C1 */ + PORT_BIT( 0x0004, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_F8) PORT_CHAR(UCHAR_MAMEKEY(F8)) /* F8 42 C2 */ + PORT_BIT( 0x0008, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_F9) PORT_CHAR(UCHAR_MAMEKEY(F9)) /* F9 43 C3 */ + PORT_BIT( 0x0010, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_F10) PORT_CHAR(UCHAR_MAMEKEY(F10)) /* F10 44 C4 */ + PORT_BIT(0x0020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("NumLock") PORT_CODE(KEYCODE_NUMLOCK) /* Num Lock 45 C5 */ + PORT_BIT(0x0040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("ScrLock") PORT_CODE(KEYCODE_SCRLOCK) /* Scroll Lock 46 C6 */ + PORT_BIT(0x0080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("KP 7 (Home)") PORT_CODE(KEYCODE_7_PAD) PORT_CODE(KEYCODE_HOME ) /* Keypad 7 (Home) 47 C7 */ + PORT_BIT(0x0100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("KP 8 (Up)") PORT_CODE(KEYCODE_8_PAD) PORT_CODE(KEYCODE_UP ) /* Keypad 8 (Up arrow) 48 C8 */ + PORT_BIT(0x0200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("KP 9 (PgUp)") PORT_CODE(KEYCODE_9_PAD) PORT_CODE(KEYCODE_PGUP) /* Keypad 9 (PgUp) 49 C9 */ + PORT_BIT(0x0400, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("KP -") PORT_CODE(KEYCODE_MINUS_PAD) /* Keypad - 4A CA */ + PORT_BIT(0x0800, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("KP 4 (Left)") PORT_CODE(KEYCODE_4_PAD) PORT_CODE(KEYCODE_LEFT ) /* Keypad 4 (Left arrow) 4B CB */ + PORT_BIT(0x1000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("KP 5") PORT_CODE(KEYCODE_5_PAD) /* Keypad 5 4C CC */ + PORT_BIT(0x2000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("KP 6 (Right)") PORT_CODE(KEYCODE_6_PAD) PORT_CODE(KEYCODE_RIGHT ) /* Keypad 6 (Right arrow) 4D CD */ + PORT_BIT(0x4000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("KP +") PORT_CODE(KEYCODE_PLUS_PAD) /* Keypad + 4E CE */ + PORT_BIT(0x8000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("KP 1 (End)") PORT_CODE(KEYCODE_1_PAD) PORT_CODE(KEYCODE_END ) /* Keypad 1 (End) 4F CF */ + + PORT_START("pc_keyboard_5") + PORT_BIT(0x0001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("KP 2 (Down)") PORT_CODE(KEYCODE_2_PAD) PORT_CODE(KEYCODE_DOWN ) /* Keypad 2 (Down arrow) 50 D0 */ + PORT_BIT(0x0002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("KP 3 (PgDn)") PORT_CODE(KEYCODE_3_PAD) PORT_CODE(KEYCODE_PGDN ) /* Keypad 3 (PgDn) 51 D1 */ + PORT_BIT(0x0004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("KP 0 (Ins)") PORT_CODE(KEYCODE_0_PAD) PORT_CODE(KEYCODE_INSERT ) /* Keypad 0 (Ins) 52 D2 */ + PORT_BIT(0x0008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("KP . (Del)") PORT_CODE(KEYCODE_DEL_PAD) PORT_CODE(KEYCODE_DEL ) /* Keypad . (Del) 53 D3 */ + PORT_BIT ( 0x0030, 0x0000, IPT_UNUSED ) + PORT_BIT(0x0040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("(84/102)\\") PORT_CODE(KEYCODE_BACKSLASH2) /* Backslash 2 56 D6 */ + PORT_BIT ( 0xff80, 0x0000, IPT_UNUSED ) +INPUT_PORTS_END + +INPUT_PORTS_START( at_keyboard ) + PORT_START("pc_keyboard_0") + PORT_BIT ( 0x0001, 0x0000, IPT_UNUSED ) /* unused scancode 0 */ + PORT_BIT(0x0002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Esc") PORT_CODE(KEYCODE_ESC) /* Esc 01 81 */ + PORT_BIT(0x0004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("1 !") PORT_CODE(KEYCODE_1) /* 1 02 82 */ + PORT_BIT(0x0008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("2 @") PORT_CODE(KEYCODE_2) /* 2 03 83 */ + PORT_BIT(0x0010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("3 #") PORT_CODE(KEYCODE_3) /* 3 04 84 */ + PORT_BIT(0x0020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("4 $") PORT_CODE(KEYCODE_4) /* 4 05 85 */ + PORT_BIT(0x0040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("5 %") PORT_CODE(KEYCODE_5) /* 5 06 86 */ + PORT_BIT(0x0080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("6 ^") PORT_CODE(KEYCODE_6) /* 6 07 87 */ + PORT_BIT(0x0100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("7 &") PORT_CODE(KEYCODE_7) /* 7 08 88 */ + PORT_BIT(0x0200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("8 *") PORT_CODE(KEYCODE_8) /* 8 09 89 */ + PORT_BIT(0x0400, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("9 (") PORT_CODE(KEYCODE_9) /* 9 0A 8A */ + PORT_BIT(0x0800, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("0 )") PORT_CODE(KEYCODE_0) /* 0 0B 8B */ + PORT_BIT(0x1000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("- _") PORT_CODE(KEYCODE_MINUS) /* - 0C 8C */ + PORT_BIT(0x2000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("= +") PORT_CODE(KEYCODE_EQUALS) /* = 0D 8D */ + PORT_BIT(0x4000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("<--") PORT_CODE(KEYCODE_BACKSPACE) /* Backspace 0E 8E */ + PORT_BIT(0x8000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Tab") PORT_CODE(KEYCODE_TAB) /* Tab 0F 8F */ + + PORT_START("pc_keyboard_1") + PORT_BIT(0x0001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Q") PORT_CODE(KEYCODE_Q) /* Q 10 90 */ + PORT_BIT(0x0002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("W") PORT_CODE(KEYCODE_W) /* W 11 91 */ + PORT_BIT(0x0004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("E") PORT_CODE(KEYCODE_E) /* E 12 92 */ + PORT_BIT(0x0008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("R") PORT_CODE(KEYCODE_R) /* R 13 93 */ + PORT_BIT(0x0010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("T") PORT_CODE(KEYCODE_T) /* T 14 94 */ + PORT_BIT(0x0020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Y") PORT_CODE(KEYCODE_Y) /* Y 15 95 */ + PORT_BIT(0x0040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("U") PORT_CODE(KEYCODE_U) /* U 16 96 */ + PORT_BIT(0x0080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("I") PORT_CODE(KEYCODE_I) /* I 17 97 */ + PORT_BIT(0x0100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("O") PORT_CODE(KEYCODE_O) /* O 18 98 */ + PORT_BIT(0x0200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("P") PORT_CODE(KEYCODE_P) /* P 19 99 */ + PORT_BIT(0x0400, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("[ {") PORT_CODE(KEYCODE_OPENBRACE) /* [ 1A 9A */ + PORT_BIT(0x0800, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("] }") PORT_CODE(KEYCODE_CLOSEBRACE) /* ] 1B 9B */ + PORT_BIT(0x1000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Enter") PORT_CODE(KEYCODE_ENTER) /* Enter 1C 9C */ + PORT_BIT(0x2000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("L-Ctrl") PORT_CODE(KEYCODE_LCONTROL) /* Left Ctrl 1D 9D */ + PORT_BIT(0x4000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("A") PORT_CODE(KEYCODE_A) /* A 1E 9E */ + PORT_BIT(0x8000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("S") PORT_CODE(KEYCODE_S) /* S 1F 9F */ + + PORT_START("pc_keyboard_2") + PORT_BIT(0x0001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("D") PORT_CODE(KEYCODE_D) /* D 20 A0 */ + PORT_BIT(0x0002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F") PORT_CODE(KEYCODE_F) /* F 21 A1 */ + PORT_BIT(0x0004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("G") PORT_CODE(KEYCODE_G) /* G 22 A2 */ + PORT_BIT(0x0008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("H") PORT_CODE(KEYCODE_H) /* H 23 A3 */ + PORT_BIT(0x0010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("J") PORT_CODE(KEYCODE_J) /* J 24 A4 */ + PORT_BIT(0x0020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("K") PORT_CODE(KEYCODE_K) /* K 25 A5 */ + PORT_BIT(0x0040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("L") PORT_CODE(KEYCODE_L) /* L 26 A6 */ + PORT_BIT(0x0080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("; :") PORT_CODE(KEYCODE_COLON) /* ; 27 A7 */ + PORT_BIT(0x0100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("' \"") PORT_CODE(KEYCODE_QUOTE) /* ' 28 A8 */ + PORT_BIT(0x0200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("` ~") PORT_CODE(KEYCODE_TILDE) /* ` 29 A9 */ + PORT_BIT(0x0400, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("L-Shift") PORT_CODE(KEYCODE_LSHIFT) /* Left Shift 2A AA */ + PORT_BIT(0x0800, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("\\ |") PORT_CODE(KEYCODE_BACKSLASH) /* \ 2B AB */ + PORT_BIT(0x1000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Z") PORT_CODE(KEYCODE_Z) /* Z 2C AC */ + PORT_BIT(0x2000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("X") PORT_CODE(KEYCODE_X) /* X 2D AD */ + PORT_BIT(0x4000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("C") PORT_CODE(KEYCODE_C) /* C 2E AE */ + PORT_BIT(0x8000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("V") PORT_CODE(KEYCODE_V) /* V 2F AF */ + + PORT_START("pc_keyboard_3") + PORT_BIT(0x0001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("B") PORT_CODE(KEYCODE_B) /* B 30 B0 */ + PORT_BIT(0x0002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("N") PORT_CODE(KEYCODE_N) /* N 31 B1 */ + PORT_BIT(0x0004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("M") PORT_CODE(KEYCODE_M) /* M 32 B2 */ + PORT_BIT(0x0008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME(", <") PORT_CODE(KEYCODE_COMMA) /* , 33 B3 */ + PORT_BIT(0x0010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME(". >") PORT_CODE(KEYCODE_STOP) /* . 34 B4 */ + PORT_BIT(0x0020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("/ ?") PORT_CODE(KEYCODE_SLASH) /* / 35 B5 */ + PORT_BIT(0x0040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("R-Shift") PORT_CODE(KEYCODE_RSHIFT) /* Right Shift 36 B6 */ + PORT_BIT(0x0080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("KP * (PrtScr)") PORT_CODE(KEYCODE_ASTERISK ) /* Keypad * (PrtSc) 37 B7 */ + PORT_BIT(0x0100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Alt") PORT_CODE(KEYCODE_LALT) /* Left Alt 38 B8 */ + PORT_BIT(0x0200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Space") PORT_CODE(KEYCODE_SPACE) /* Space 39 B9 */ + PORT_BIT(0x0400, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Caps") PORT_CODE(KEYCODE_CAPSLOCK) /* Caps Lock 3A BA */ + PORT_BIT(0x0800, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F1") PORT_CODE(KEYCODE_F1) /* F1 3B BB */ + PORT_BIT(0x1000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F2") PORT_CODE(KEYCODE_F2) /* F2 3C BC */ + PORT_BIT(0x2000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F3") PORT_CODE(KEYCODE_F3) /* F3 3D BD */ + PORT_BIT(0x4000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F4") PORT_CODE(KEYCODE_F4) /* F4 3E BE */ + PORT_BIT(0x8000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F5") PORT_CODE(KEYCODE_F5) /* F5 3F BF */ + + PORT_START("pc_keyboard_4") + PORT_BIT(0x0001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F6") PORT_CODE(KEYCODE_F6) /* F6 40 C0 */ + PORT_BIT(0x0002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F7") PORT_CODE(KEYCODE_F7) /* F7 41 C1 */ + PORT_BIT(0x0004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F8") PORT_CODE(KEYCODE_F8) /* F8 42 C2 */ + PORT_BIT(0x0008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F9") PORT_CODE(KEYCODE_F9) /* F9 43 C3 */ + PORT_BIT(0x0010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F10") PORT_CODE(KEYCODE_F10) /* F10 44 C4 */ + PORT_BIT(0x0020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("NumLock") PORT_CODE(KEYCODE_NUMLOCK) /* Num Lock 45 C5 */ + PORT_BIT(0x0040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("ScrLock") PORT_CODE(KEYCODE_SCRLOCK) /* Scroll Lock 46 C6 */ + PORT_BIT(0x0080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("KP 7 (Home)") PORT_CODE(KEYCODE_7_PAD ) /* Keypad 7 (Home) 47 C7 */ + PORT_BIT(0x0100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("KP 8 (Up)") PORT_CODE(KEYCODE_8_PAD ) /* Keypad 8 (Up arrow) 48 C8 */ + PORT_BIT(0x0200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("KP 9 (PgUp)") PORT_CODE(KEYCODE_9_PAD ) /* Keypad 9 (PgUp) 49 C9 */ + PORT_BIT(0x0400, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("KP -") PORT_CODE(KEYCODE_MINUS_PAD) /* Keypad - 4A CA */ + PORT_BIT(0x0800, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("KP 4 (Left)") PORT_CODE(KEYCODE_4_PAD ) /* Keypad 4 (Left arrow) 4B CB */ + PORT_BIT(0x1000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("KP 5") PORT_CODE(KEYCODE_5_PAD) /* Keypad 5 4C CC */ + PORT_BIT(0x2000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("KP 6 (Right)") PORT_CODE(KEYCODE_6_PAD ) /* Keypad 6 (Right arrow) 4D CD */ + PORT_BIT(0x4000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("KP +") PORT_CODE(KEYCODE_PLUS_PAD) /* Keypad + 4E CE */ + PORT_BIT(0x8000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("KP 1 (End)") PORT_CODE(KEYCODE_1_PAD ) /* Keypad 1 (End) 4F CF */ + + PORT_START("pc_keyboard_5") + PORT_BIT(0x0001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("KP 2 (Down)") PORT_CODE(KEYCODE_2_PAD ) /* Keypad 2 (Down arrow) 50 D0 */ + PORT_BIT(0x0002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("KP 3 (PgDn)") PORT_CODE(KEYCODE_3_PAD ) /* Keypad 3 (PgDn) 51 D1 */ + PORT_BIT(0x0004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("KP 0 (Ins)") PORT_CODE(KEYCODE_0_PAD ) /* Keypad 0 (Ins) 52 D2 */ + PORT_BIT(0x0008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("KP . (Del)") PORT_CODE(KEYCODE_DEL_PAD ) /* Keypad . (Del) 53 D3 */ + PORT_BIT ( 0x0030, 0x0000, IPT_UNUSED ) + PORT_BIT(0x0040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("(84/102)\\") PORT_CODE(KEYCODE_BACKSLASH2) /* Backslash 2 56 D6 */ + PORT_BIT(0x0080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("(MF2)F11") PORT_CODE(KEYCODE_F11) /* F11 57 D7 */ + PORT_BIT(0x0100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("(MF2)F12") PORT_CODE(KEYCODE_F12) /* F12 58 D8 */ + PORT_BIT ( 0xfe00, 0x0000, IPT_UNUSED ) + + PORT_START("pc_keyboard_6") + PORT_BIT(0x0001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("(MF2)KP Enter") PORT_CODE(KEYCODE_ENTER_PAD) /* PAD Enter 60 e0 */ + PORT_BIT(0x0002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("(MF2)Right Control") PORT_CODE(KEYCODE_RCONTROL) /* Right Control 61 e1 */ + PORT_BIT(0x0004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("(MF2)KP /") PORT_CODE(KEYCODE_SLASH_PAD) /* PAD Slash 62 e2 */ + PORT_BIT(0x0008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("(MF2)PRTSCR") PORT_CODE(KEYCODE_PRTSCR) /* Print Screen 63 e3 */ + PORT_BIT(0x0010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("(MF2)ALTGR") PORT_CODE(KEYCODE_RALT) /* ALTGR 64 e4 */ + PORT_BIT(0x0020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("(MF2)Home") PORT_CODE(KEYCODE_HOME) /* Home 66 e6 */ + PORT_BIT(0x0040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("(MF2)Cursor Up") PORT_CODE(KEYCODE_UP) /* Up 67 e7 */ + PORT_BIT(0x0080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("(MF2)Page Up") PORT_CODE(KEYCODE_PGUP) /* Page Up 68 e8 */ + PORT_BIT(0x0100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("(MF2)Cursor Left") PORT_CODE(KEYCODE_LEFT) /* Left 69 e9 */ + PORT_BIT(0x0200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("(MF2)Cursor Right") PORT_CODE(KEYCODE_RIGHT) /* Right 6a ea */ + PORT_BIT(0x0400, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("(MF2)End") PORT_CODE(KEYCODE_END) /* End 6b eb */ + PORT_BIT(0x0800, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("(MF2)Cursor Down") PORT_CODE(KEYCODE_DOWN) /* Down 6c ec */ + PORT_BIT(0x1000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("(MF2)Page Down") PORT_CODE(KEYCODE_PGDN) /* Page Down 6d ed */ + PORT_BIT(0x2000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("(MF2)Insert") PORT_CODE(KEYCODE_INSERT) /* Insert 6e ee */ + PORT_BIT(0x4000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("(MF2)Delete") PORT_CODE(KEYCODE_DEL) /* Delete 6f ef */ + PORT_BIT(0x8000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("(MF2)Pause") PORT_CODE(KEYCODE_PAUSE) /* Pause 65 e5 */ + + PORT_START("pc_keyboard_7") + PORT_BIT(0x0001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Print Screen") PORT_CODE(KEYCODE_PRTSCR) /* Print Screen alternate 77 f7 */ + PORT_BIT ( 0xfffe, 0x0000, IPT_UNUSED ) +INPUT_PORTS_END + +/*************************************************************************** + Inputx stuff +***************************************************************************/ + +bool pc_keyboard_device::accept_char(unicode_char ch) +{ + return unicode_char_to_at_keycode(ch) != 0; +} + + + +bool pc_keyboard_device::charqueue_empty() +{ + return queue_size() == 0; +} diff --git a/src/devices/machine/pckeybrd.h b/src/devices/machine/pckeybrd.h new file mode 100644 index 00000000000..12ca33f0f4c --- /dev/null +++ b/src/devices/machine/pckeybrd.h @@ -0,0 +1,137 @@ +// license:BSD-3-Clause +// copyright-holders:Peter Trauner, Kevin Thacker +/********************************************************************** + + pckeybrd.h + + PC-style keyboard emulation + + This emulation is decoupled from the AT 8042 emulation used in the + IBM ATs and above + +**********************************************************************/ + +#ifndef PCKEYBRD_H +#define PCKEYBRD_H + +#include "emu.h" + +class pc_keyboard_device : public device_t +{ +public: + pc_keyboard_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + pc_keyboard_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + DECLARE_READ8_MEMBER(read); + DECLARE_WRITE_LINE_MEMBER(enable); + + template static devcb_base &static_set_keypress_callback(device_t &device, _Object object) + { return downcast(device).m_out_keypress_func.set_callback(object); } + + enum KEYBOARD_TYPE + { + KEYBOARD_TYPE_PC, + KEYBOARD_TYPE_AT, + KEYBOARD_TYPE_MF2 + }; + + +protected: + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + void queue_insert(UINT8 data); + void clear_buffer(void); + + int m_numlock; + KEYBOARD_TYPE m_type; + +private: + void polling(void); + UINT32 readport(int port); + UINT8 unicode_char_to_at_keycode(unicode_char ch); + + virtual void standard_scancode_insert(int our_code, int pressed); + virtual void extended_scancode_insert(int code, int pressed) { } + int queue_size(void); + int queue_chars(const unicode_char *text, size_t text_len); + bool accept_char(unicode_char ch); + bool charqueue_empty(); + + bool m_on; + UINT8 m_delay; /* 240/60 -> 0,25s */ + UINT8 m_repeat; /* 240/ 8 -> 30/s */ + + UINT8 m_queue[256]; + UINT8 m_head; + UINT8 m_tail; + UINT8 m_make[128]; + + optional_ioport m_ioport_0; + optional_ioport m_ioport_1; + optional_ioport m_ioport_2; + optional_ioport m_ioport_3; + optional_ioport m_ioport_4; + optional_ioport m_ioport_5; + optional_ioport m_ioport_6; + optional_ioport m_ioport_7; + + devcb_write_line m_out_keypress_func; + emu_timer *m_keyboard_timer; +}; + +class at_keyboard_device : public pc_keyboard_device +{ +public: + at_keyboard_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + DECLARE_WRITE8_MEMBER( write ); + + static void static_set_type(device_t &device, KEYBOARD_TYPE type, int default_set) + { downcast(device).m_scan_code_set = default_set; downcast(device).m_type = type; } + +protected: + virtual void device_reset(); + virtual void device_start(); + +private: + virtual void standard_scancode_insert(int our_code, int pressed); + virtual void extended_scancode_insert(int code, int pressed); + void helper(const char *codes); + void clear_buffer_and_acknowledge(void); + + struct extended_keyboard_code + { + const char *pressed; + const char *released; + }; + + static const extended_keyboard_code m_extended_codes_set_2_3[]; + static const int m_scancode_set_2_3[]; + static const extended_keyboard_code m_mf2_code[0x10][2]; + + int m_scan_code_set; + int m_input_state; +}; + +INPUT_PORTS_EXTERN( pc_keyboard ); +INPUT_PORTS_EXTERN( at_keyboard ); + +extern const device_type PC_KEYB; +extern const device_type AT_KEYB; + +#define MCFG_PC_KEYB_ADD(_tag, _cb) \ + MCFG_DEVICE_ADD(_tag, PC_KEYB, 0) \ + devcb = &pc_keyboard_device::static_set_keypress_callback(*device, DEVCB_##_cb); + +#define MCFG_AT_KEYB_ADD(_tag, _def_set, _cb) \ + MCFG_DEVICE_ADD(_tag, AT_KEYB, 0) \ + at_keyboard_device::static_set_type(*device, pc_keyboard_device::KEYBOARD_TYPE_AT, _def_set); \ + devcb = &pc_keyboard_device::static_set_keypress_callback(*device, DEVCB_##_cb); + +#define MCFG_AT_MF2_KEYB_ADD(_tag, _def_set, _cb) \ + MCFG_DEVICE_ADD(_tag, AT_KEYB, 0) \ + at_keyboard_device::static_set_type(*device, pc_keyboard_device::KEYBOARD_TYPE_MF2, _def_set); \ + devcb = &pc_keyboard_device::static_set_keypress_callback(*device, DEVCB_##_cb); + +#endif /* PCKEYBRD_H */ diff --git a/src/devices/machine/pic8259.c b/src/devices/machine/pic8259.c new file mode 100644 index 00000000000..40fe6fd916c --- /dev/null +++ b/src/devices/machine/pic8259.c @@ -0,0 +1,439 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +/********************************************************************** + + 8259 PIC interface and emulation + + The 8259 is a programmable interrupt controller used to multiplex + interrupts for x86 and other computers. The chip is set up by + writing a series of Initialization Command Words (ICWs) after which + the chip is operational and capable of dispatching interrupts. After + this, Operation Command Words (OCWs) can be written to control further + behavior. + +**********************************************************************/ + +#include "emu.h" +#include "machine/pic8259.h" + +#define LOG_ICW 0 +#define LOG_OCW 0 +#define LOG_GENERAL 0 + +ALLOW_SAVE_TYPE(pic8259_device::pic8259_state_t); // allow save_item on a non-fundamental type + +void pic8259_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + /* check the various IRQs */ + for (int n = 0, irq = m_prio; n < 8; n++, irq = (irq + 1) & 7) + { + UINT8 mask = 1 << irq; + + /* is this IRQ in service and not cascading and sfnm? */ + if ((m_isr & mask) && !(m_master && m_cascade && m_nested && (m_slave & mask))) + { + if (LOG_GENERAL) + { + logerror("pic8259_timerproc() %s: PIC IRQ #%d still in service\n", tag(), irq); + } + break; + } + + /* is this IRQ pending and enabled? */ + if ((m_state == STATE_READY) && (m_irr & mask) && !(m_imr & mask)) + { + if (LOG_GENERAL) + { + logerror("pic8259_timerproc() %s: PIC triggering IRQ #%d\n", tag(), irq); + } + m_out_int_func(1); + return; + } + // if sfnm and in-service don't continue + if((m_isr & mask) && m_master && m_cascade && m_nested && (m_slave & mask)) + break; + } + m_out_int_func(0); +} + + +void pic8259_device::set_irq_line(int irq, int state) +{ + UINT8 mask = (1 << irq); + + if (state) + { + /* setting IRQ line */ + if (LOG_GENERAL) + logerror("pic8259_set_irq_line() %s: PIC set IRQ line #%d\n", tag(), irq); + + if(m_level_trig_mode || (!m_level_trig_mode && !(m_irq_lines & mask))) + { + m_irr |= mask; + } + m_irq_lines |= mask; + } + else + { + /* clearing IRQ line */ + if (LOG_GENERAL) + { + logerror("pic8259_device::set_irq_line() %s: PIC cleared IRQ line #%d\n", tag(), irq); + } + + m_irq_lines &= ~mask; + m_irr &= ~mask; + } + set_timer(); +} + + +UINT32 pic8259_device::acknowledge() +{ + for (int n = 0, irq = m_prio; n < 8; n++, irq = (irq + 1) & 7) + { + UINT8 mask = 1 << irq; + + /* is this IRQ pending and enabled? */ + if ((m_irr & mask) && !(m_imr & mask)) + { + if (LOG_GENERAL) + { + logerror("pic8259_acknowledge() %s: PIC acknowledge IRQ #%d\n", tag(), irq); + } + if (!m_level_trig_mode) + { + m_irr &= ~mask; + } + + if (!m_auto_eoi) + { + m_isr |= mask; + } + + set_timer(); + + if ((m_cascade!=0) && (m_master!=0) && (mask & m_slave)) + { + // it's from slave device + return m_read_slave_ack_func(irq); + } + else + { + if (m_is_x86) + { + /* For x86 mode*/ + return irq + m_base; + } + else + { + /* in case of 8080/85) */ + return 0xcd0000 + (m_vector_addr_high << 8) + m_vector_addr_low + (irq << (3-m_vector_size)); + } + } + } + } + return 0; +} + + +IRQ_CALLBACK_MEMBER(pic8259_device::inta_cb) +{ + return acknowledge(); +} + + +READ8_MEMBER( pic8259_device::read ) +{ + /* NPW 18-May-2003 - Changing 0xFF to 0x00 as per Ruslan */ + UINT8 data = 0x00; + + switch(offset) + { + case 0: /* PIC acknowledge IRQ */ + if ( m_ocw3 & 0x04 ) + { + /* Polling mode */ + if ( m_irr & ~m_imr ) + { + /* check the various IRQs */ + for (int n = 0, irq = m_prio; n < 8; n++, irq = (irq + 1) & 7) + { + if ( ( 1 << irq ) & m_irr & ~m_imr ) + { + data = 0x80 | irq; + break; + } + } + acknowledge(); + } + } + else + { + switch ( m_ocw3 & 0x03 ) + { + case 2: + data = m_irr; + break; + case 3: + data = m_isr & ~m_imr; + break; + default: + data = 0x00; + break; + } + } + break; + + case 1: /* PIC mask register */ + data = m_imr; + break; + } + return data; +} + + +WRITE8_MEMBER( pic8259_device::write ) +{ + switch(offset) + { + case 0: /* PIC acknowledge IRQ */ + if (data & 0x10) + { + /* write ICW1 - this pretty much resets the chip */ + if (LOG_ICW) + { + logerror("pic8259_device::write() %s: ICW1; data=0x%02X\n", tag(), data); + } + + m_imr = 0x00; + m_isr = 0x00; + m_irr = 0x00; + m_level_trig_mode = (data & 0x08) ? 1 : 0; + m_vector_size = (data & 0x04) ? 1 : 0; + m_cascade = (data & 0x02) ? 0 : 1; + m_icw4_needed = (data & 0x01) ? 1 : 0; + m_vector_addr_low = (data & 0xe0); + m_state = STATE_ICW2; + m_out_int_func(0); + } + else if (m_state == STATE_READY) + { + if ((data & 0x98) == 0x08) + { + /* write OCW3 */ + if (LOG_OCW) + { + logerror("pic8259_device::write() %s: OCW3; data=0x%02X\n", tag(), data); + } + + m_ocw3 = data; + } + else if ((data & 0x18) == 0x00) + { + int n = data & 7; + UINT8 mask = 1 << n; + + /* write OCW2 */ + if (LOG_OCW) + { + logerror("pic8259_device::write() %s: OCW2; data=0x%02X\n", tag(), data); + } + + switch (data & 0xe0) + { + case 0x00: + m_prio = 0; + break; + case 0x20: + for (n = 0, mask = 1<>7)) + { + if (m_isr & mask) + { + m_isr &= ~mask; + break; + } + } + break; + case 0x40: + break; + case 0x60: + if( m_isr & mask ) + { + m_isr &= ~mask; + } + break; + case 0x80: + m_prio = (m_prio + 1) & 7; + break; + case 0xa0: + for (n = 0, mask = 1<>7)) + { + if( m_isr & mask ) + { + m_isr &= ~mask; + m_prio = (m_prio + 1) & 7; + break; + } + } + break; + case 0xc0: + m_prio = (n + 1) & 7; + break; + case 0xe0: + if( m_isr & mask ) + { + m_isr &= ~mask; + m_prio = (n + 1) & 7; + } + break; + } + } + } + break; + + case 1: + switch(m_state) + { + case STATE_ICW1: + break; + + case STATE_ICW2: + /* write ICW2 */ + if (LOG_ICW) + { + logerror("pic8259_device::write() %s: ICW2; data=0x%02X\n", tag(), data); + } + + m_base = data & 0xf8; + m_vector_addr_high = data ; + if (m_cascade) + { + m_state = STATE_ICW3; + } + else + { + m_state = m_icw4_needed ? STATE_ICW4 : STATE_READY; + } + break; + + case STATE_ICW3: + /* write ICW3 */ + if (LOG_ICW) + { + logerror("pic8259_device::write() %s: ICW3; data=0x%02X\n", tag(), data); + } + + m_slave = data; + m_state = m_icw4_needed ? STATE_ICW4 : STATE_READY; + break; + + case STATE_ICW4: + /* write ICW4 */ + if (LOG_ICW) + { + logerror("pic8259_device::write() %s: ICW4; data=0x%02X\n", tag(), data); + } + + m_nested = (data & 0x10) ? 1 : 0; + m_mode = (data >> 2) & 3; + m_auto_eoi = (data & 0x02) ? 1 : 0; + m_is_x86 = (data & 0x01) ? 1 : 0; + m_state = STATE_READY; + break; + + case STATE_READY: + /* write OCW1 - set interrupt mask register */ + if (LOG_OCW) + { + logerror("pic8259_device::write(): OCW1; data=0x%02X\n", data); + } + + //printf("%s %02x\n",m_master ? "master pic8259 mask" : "slave pic8259 mask",data); + m_imr = data; + break; + } + break; + } + set_timer(); +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void pic8259_device::device_start() +{ + // resolve callbacks + m_out_int_func.resolve(); + m_sp_en_func.resolve(); + m_read_slave_ack_func.resolve(); + + // Register save state items + save_item(NAME(m_state)); + save_item(NAME(m_isr)); + save_item(NAME(m_irr)); + save_item(NAME(m_prio)); + save_item(NAME(m_imr)); + save_item(NAME(m_irq_lines)); + save_item(NAME(m_input)); + save_item(NAME(m_ocw3)); + save_item(NAME(m_master)); + save_item(NAME(m_level_trig_mode)); + save_item(NAME(m_vector_size)); + save_item(NAME(m_cascade)); + save_item(NAME(m_icw4_needed)); + save_item(NAME(m_vector_addr_low)); + save_item(NAME(m_base)); + save_item(NAME(m_vector_addr_high)); + save_item(NAME(m_slave)); + save_item(NAME(m_nested)); + save_item(NAME(m_mode)); + save_item(NAME(m_auto_eoi)); + save_item(NAME(m_is_x86)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void pic8259_device::device_reset() +{ + m_state = STATE_READY; + m_isr = 0; + m_irr = 0; + m_irq_lines = 0; + m_prio = 0; + m_imr = 0; + m_input = 0; + m_ocw3 = 2; + m_level_trig_mode = 0; + m_vector_size = 0; + m_cascade = 0; + m_icw4_needed = 0; + m_base = 0; + m_slave = 0; + m_nested = 0; + m_mode = 0; + m_auto_eoi = 0; + m_is_x86 = 0; + m_vector_addr_low = 0; + m_vector_addr_high = 0; + + m_master = m_sp_en_func(); +} + +const device_type PIC8259 = &device_creator; + +pic8259_device::pic8259_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, PIC8259, "8259 PIC", tag, owner, clock, "pit8259", __FILE__) + , m_out_int_func(*this) + , m_sp_en_func(*this) + , m_read_slave_ack_func(*this) + , m_irr(0) + , m_irq_lines(0) + , m_level_trig_mode(0) +{ +} diff --git a/src/devices/machine/pic8259.h b/src/devices/machine/pic8259.h new file mode 100644 index 00000000000..48914c07fe9 --- /dev/null +++ b/src/devices/machine/pic8259.h @@ -0,0 +1,126 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +/*************************************************************************** + + Intel 8259A + + Programmable Interrupt Controller + + _____ _____ + _CS 1 |* \_/ | 28 VCC + _WR 2 | | 27 A0 + _RD 3 | | 26 _INTA + D7 4 | | 25 IR7 + D6 5 | | 24 IR6 + D5 6 | | 23 IR5 + D4 7 | 8259A | 22 IR4 + D3 8 | | 21 IR3 + D2 9 | | 20 IR2 + D1 10 | | 19 IR1 + D0 11 | | 18 IR0 + CAS0 12 | | 17 INT + CAS1 13 | | 16 _SP/_EN + GND 14 |_____________| 15 CAS2 + +***************************************************************************/ + +#ifndef __PIC8259_H__ +#define __PIC8259_H__ + + +/*************************************************************************** + DEVICE CONFIGURATION MACROS +***************************************************************************/ + +#define MCFG_PIC8259_ADD(_tag, _out_int, _sp_en, _read_slave_ack) \ + MCFG_DEVICE_ADD(_tag, PIC8259, 0) \ + devcb = &pic8259_device::static_set_out_int_callback( *device, DEVCB_##_out_int ); \ + devcb = &pic8259_device::static_set_sp_en_callback( *device, DEVCB_##_sp_en ); \ + devcb = &pic8259_device::static_set_read_slave_ack_callback( *device, DEVCB_##_read_slave_ack ); + + +class pic8259_device : public device_t +{ +public: + pic8259_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + template static devcb_base &static_set_out_int_callback(device_t &device, _Object object) { return downcast(device).m_out_int_func.set_callback(object); } + template static devcb_base &static_set_sp_en_callback(device_t &device, _Object object) { return downcast(device).m_sp_en_func.set_callback(object); } + template static devcb_base &static_set_read_slave_ack_callback(device_t &device, _Object object) { return downcast(device).m_read_slave_ack_func.set_callback(object); } + + DECLARE_READ8_MEMBER( read ); + DECLARE_WRITE8_MEMBER( write ); + UINT32 acknowledge(); + + DECLARE_WRITE_LINE_MEMBER( ir0_w ) { set_irq_line(0, state); } + DECLARE_WRITE_LINE_MEMBER( ir1_w ) { set_irq_line(1, state); } + DECLARE_WRITE_LINE_MEMBER( ir2_w ) { set_irq_line(2, state); } + DECLARE_WRITE_LINE_MEMBER( ir3_w ) { set_irq_line(3, state); } + DECLARE_WRITE_LINE_MEMBER( ir4_w ) { set_irq_line(4, state); } + DECLARE_WRITE_LINE_MEMBER( ir5_w ) { set_irq_line(5, state); } + DECLARE_WRITE_LINE_MEMBER( ir6_w ) { set_irq_line(6, state); } + DECLARE_WRITE_LINE_MEMBER( ir7_w ) { set_irq_line(7, state); } + + IRQ_CALLBACK_MEMBER(inta_cb); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + +private: + static const device_timer_id TIMER_CHECK_IRQ = 0; + + inline void set_timer() { timer_set(attotime::zero, TIMER_CHECK_IRQ); } + void set_irq_line(int irq, int state); + + + enum pic8259_state_t + { + STATE_ICW1, + STATE_ICW2, + STATE_ICW3, + STATE_ICW4, + STATE_READY + }; + + devcb_write_line m_out_int_func; + devcb_read_line m_sp_en_func; + devcb_read8 m_read_slave_ack_func; + + pic8259_state_t m_state; + + UINT8 m_isr; + UINT8 m_irr; + UINT8 m_prio; + UINT8 m_imr; + UINT8 m_irq_lines; + + UINT8 m_input; + UINT8 m_ocw3; + + UINT8 m_master; + /* ICW1 state */ + UINT8 m_level_trig_mode; + UINT8 m_vector_size; + UINT8 m_cascade; + UINT8 m_icw4_needed; + UINT32 m_vector_addr_low; + /* ICW2 state */ + UINT8 m_base; + UINT8 m_vector_addr_high; + + /* ICW3 state */ + UINT8 m_slave; + + /* ICW4 state */ + UINT8 m_nested; + UINT8 m_mode; + UINT8 m_auto_eoi; + UINT8 m_is_x86; +}; + +extern const device_type PIC8259; + +#endif /* __PIC8259_H__ */ diff --git a/src/devices/machine/pit8253.c b/src/devices/machine/pit8253.c new file mode 100644 index 00000000000..1ad506686e0 --- /dev/null +++ b/src/devices/machine/pit8253.c @@ -0,0 +1,1135 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol, Nathan Woods +/***************************************************************************** + * + * Programmable Interval Timer 8253/8254 + * + * Three Independent Timers + * (gate, clock, out pins) + * + * 8254 has an additional readback feature + * + * Revision History + * 1-Apr-2008 - WFP: Changed the implementation into a device. + * 8-Jul-2004 - AJ: Fixed some bugs. Styx now runs correctly. + * Implemented 8254 features. + * 1-Mar-2004 - NPW: Did an almost total rewrite and cleaned out much + * of the ugliness in the previous design. Bug #430 + * seems to be fixed + * 1-Jul-2000 - PeT: Split off from PC driver and componentized + * + *****************************************************************************/ + +#include "emu.h" +#include "machine/pit8253.h" + +// for now, make buggy GCC/Mingw STFU about I64FMT +#if (defined(__MINGW32__) && (__GNUC__ >= 5)) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wformat" +#pragma GCC diagnostic ignored "-Wformat-extra-args" +#endif + +/* device types */ +enum +{ + TYPE_PIT8253 = 0, + TYPE_PIT8254 +}; + + +/*************************************************************************** + + Structures & macros + +***************************************************************************/ + +#define VERBOSE 0 + +#define LOG1(msg) do { if (VERBOSE >= 1) logerror msg; } while (0) +#define LOG2(msg) do { if (VERBOSE >= 2) logerror msg; } while (0) + + +const device_type PIT8253 = &device_creator; + + +pit8253_device::pit8253_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, PIT8253, "8253 PIT", tag, owner, clock, "pit8253", __FILE__), + m_clk0(0), + m_clk1(0), + m_clk2(0), + m_out0_handler(*this), + m_out1_handler(*this), + m_out2_handler(*this) +{ +} + +pit8253_device::pit8253_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + m_clk0(0), + m_clk1(0), + m_clk2(0), + m_out0_handler(*this), + m_out1_handler(*this), + m_out2_handler(*this) +{ +} + + +const device_type PIT8254 = &device_creator; + +pit8254_device::pit8254_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : pit8253_device(mconfig, PIT8254, "8254 PIT", tag, owner, clock, "pit8254", __FILE__) +{ +} + + +pit8253_device::pit8253_timer *pit8253_device::get_timer(int which) +{ + which &= 3; + if (which < PIT8253_MAX_TIMER) + return &m_timers[which]; + + return NULL; +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void pit8253_device::device_start() +{ + m_timers[0].clockin = m_clk0; + m_timers[1].clockin = m_clk1; + m_timers[2].clockin = m_clk2; + + m_out0_handler.resolve_safe(); + m_out1_handler.resolve_safe(); + m_out2_handler.resolve_safe(); + + for (int timerno = 0; timerno < PIT8253_MAX_TIMER; timerno++) + { + pit8253_timer *timer = get_timer(timerno); + + /* initialize timer */ + timer->updatetimer = timer_alloc(timerno); + timer->updatetimer->adjust(attotime::never, timerno); + + /* set up state save values */ + save_item(NAME(timer->clockin), timerno); + save_item(NAME(timer->control), timerno); + save_item(NAME(timer->status), timerno); + save_item(NAME(timer->lowcount), timerno); + save_item(NAME(timer->latch), timerno); + save_item(NAME(timer->count), timerno); + save_item(NAME(timer->value), timerno); + save_item(NAME(timer->wmsb), timerno); + save_item(NAME(timer->rmsb), timerno); + save_item(NAME(timer->output), timerno); + save_item(NAME(timer->gate), timerno); + save_item(NAME(timer->latched_count), timerno); + save_item(NAME(timer->latched_status), timerno); + save_item(NAME(timer->null_count), timerno); + save_item(NAME(timer->phase), timerno); + save_item(NAME(timer->last_updated), timerno); + save_item(NAME(timer->clock), timerno); + + /* zerofill */ + timer->gate = 1; + timer->phase = 0; + timer->clock = 0; + + timer->index = timerno; + timer->control = timer->status = 0x30; + timer->rmsb = timer->wmsb = 0; + timer->count = timer->value = timer->latch = 0; + timer->lowcount = 0; + + timer->output = 0; + timer->latched_count = 0; + timer->latched_status = 0; + timer->null_count = 1; + + timer->last_updated = machine().time(); + } +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void pit8253_device::device_reset() +{ + for (int i = 0; i < PIT8253_MAX_TIMER; i++) + { + pit8253_timer *timer = get_timer(i); + + /* According to Intel's 8254 docs, the state of a timer is undefined + until the first mode control word is written. Here we define this + undefined behaviour */ + timer->control = timer->status = 0x30; + timer->rmsb = timer->wmsb = 0; + timer->count = timer->value = timer->latch = 0; + timer->lowcount = 0; + + timer->output = 2; /* output is undetermined */ + timer->latched_count = 0; + timer->latched_status = 0; + timer->null_count = 1; + + timer->last_updated = machine().time(); + + update(timer); + } +} + + +/*************************************************************************** + + Functions + +***************************************************************************/ + +#define CTRL_ACCESS(control) (((control) >> 4) & 0x03) +#define CTRL_MODE(control) (((control) >> 1) & (((control) & 0x04) ? 0x03 : 0x07)) +#define CTRL_BCD(control) (((control) >> 0) & 0x01) + + +inline UINT32 pit8253_device::adjusted_count(int bcd, UINT16 val) +{ + if (!bcd) + return (val == 0) ? 0x10000 : val; + else if (val == 0) + return 10000; + + /* In BCD mode, a nybble loaded with value A-F counts down the same as in + binary mode, but wraps around to 9 instead of F after 0, so loading the + count register with 0xFFFF gives a period of + 0xF - for the units to count down to 0 + + 10*0xF - for the tens to count down to 0 + + 100*0xF - for the hundreds to count down to 0 + + 1000*0xF - for the thousands to count down to 0 + = 16665 cycles + */ + return + ((val>>12) & 0xF) * 1000 + + ((val>> 8) & 0xF) * 100 + + ((val>> 4) & 0xF) * 10 + + ( val & 0xF); +} + + +/* This function subtracts 1 from timer->value "cycles" times, taking into + account binary or BCD operation, and wrapping around from 0 to 0xFFFF or + 0x9999 as necessary. */ +void pit8253_device::decrease_counter_value(pit8253_timer *timer, INT64 cycles) +{ + UINT16 value; + UINT8 units, tens, hundreds, thousands; + + if (CTRL_BCD(timer->control) == 0) + { + timer->value -= (cycles & 0xffff); + return; + } + + value = timer->value; + units = value & 0xf; + tens = (value >> 4) & 0xf; + hundreds = (value >> 8) & 0xf; + thousands = (value >> 12) & 0xf; + + if (cycles <= units) + { + units -= cycles; + } + else + { + cycles -= units; + units = (10 - cycles % 10) % 10; + + cycles = (cycles + 9) / 10; /* the +9 is so we get a carry if cycles%10 wasn't 0 */ + if (cycles <= tens) + { + tens -= cycles; + } + else + { + cycles -= tens; + tens = (10 - cycles % 10) % 10; + + cycles = (cycles + 9) / 10; + if (cycles <= hundreds) + { + hundreds -= cycles; + } + else + { + cycles -= hundreds; + hundreds = (10 - cycles % 10) % 10; + cycles = (cycles + 9) / 10; + thousands = (10 + thousands - cycles % 10) % 10; + } + } + } + + timer->value = (thousands << 12) | (hundreds << 8) | (tens << 4) | units; +} + + +/* Counter loading: transfer of a count from the CR to the CE */ +void pit8253_device::load_counter_value(pit8253_timer *timer) +{ + timer->value = timer->count; + timer->null_count = 0; + + if (CTRL_MODE(timer->control) == 3 && timer->output == 0) + timer->value &= 0xfffe; +} + + +void pit8253_device::set_output(pit8253_timer *timer, int output) +{ + if (output != timer->output) + { + timer->output = output; + + switch (timer->index) + { + case 0: + m_out0_handler(output); + break; + + case 1: + m_out1_handler(output); + break; + + case 2: + m_out2_handler(output); + break; + } + } +} + + +/* This emulates timer "timer" for "elapsed_cycles" cycles and assumes no + callbacks occur during that time. */ +void pit8253_device::simulate2(pit8253_timer *timer, INT64 elapsed_cycles) +{ + UINT32 adjusted_value; + int bcd = CTRL_BCD(timer->control); + int mode = CTRL_MODE(timer->control); + static const UINT32 CYCLES_NEVER = (0xffffffff); + UINT32 cycles_to_output = 0; + + LOG2(("pit8253: simulate2(): simulating %d cycles for %d in mode %d, bcd = %d, phase = %d, gate = %d, output %d, value = 0x%04x\n", + (int)elapsed_cycles, timer->index, mode, bcd, timer->phase, timer->gate, timer->output, timer->value)); + + switch (mode) + { + case 0: + /* Mode 0: (Interrupt on Terminal Count) + + +------------------ + | + ----------+ + <- n+1 -> + + ^ + +- counter load + + phase|output|length |value|next|comment + -----+------+--------+-----+----+---------------------------------- + 0|low |infinity| |1 |waiting for count + 1|low |1 | |2 |internal delay when counter loaded + 2|low |n |n..1 |3 |counting down + 3|high |infinity|0..1 |3 |counting down + + Gate level sensitive only. Low disables counting, high enables it. */ + + if (timer->phase == 0) + { + cycles_to_output = CYCLES_NEVER; + } + else + { + if (elapsed_cycles >= 0 && timer->phase == 1) + { + /* Counter load cycle */ + if (elapsed_cycles > 0) + { + --elapsed_cycles; + timer->phase = 2; + } + load_counter_value(timer); + } + + if (timer->gate == 0) + { + cycles_to_output = CYCLES_NEVER; + } + else + { + if (timer->phase == 2) + { + adjusted_value = adjusted_count(bcd, timer->value); + if (elapsed_cycles >= adjusted_value) + { + /* Counter wrapped, output goes high */ + elapsed_cycles -= adjusted_value; + timer->phase = 3; + timer->value = 0; + set_output(timer, 1); + } + } + + decrease_counter_value(timer, elapsed_cycles); + + switch (timer->phase) + { + case 1: cycles_to_output = 1; break; + case 2: cycles_to_output = adjusted_count(bcd, timer->value); break; + case 3: cycles_to_output = adjusted_count(bcd, timer->value); break; + } + } + } + break; + + + case 1: + /* Mode 1: (Hardware Retriggerable One-Shot a.k.a. Programmable One-Shot) + + -----+ +------------------ + | | + +-------+ + <- n -> + + ^ + +- trigger + + phase|output|length |value|next|comment + -----+------+--------+-----+----+---------------------------------- + 0|high |infinity| |1 |counting down + 1|high |1 | |2 |internal delay to load counter + 2|low |n |n..1 |3 |counting down + 3|high |infinity|0..1 |3 |counting down + + Gate rising-edge sensitive only. + Rising edge initiates counting and resets output after next clock. */ + + if (elapsed_cycles >= 0 && timer->phase == 1) + { + /* Counter load cycle, output goes low */ + if (elapsed_cycles > 0) + { + --elapsed_cycles; + timer->phase = 2; + } + load_counter_value(timer); + set_output(timer, 0); + } + + if (timer->phase == 2) + { + adjusted_value = adjusted_count(bcd, timer->value); + if (elapsed_cycles >= adjusted_value) + { + /* Counter wrapped, output goes high */ + timer->phase = 3; + set_output(timer, 1); + } + } + + decrease_counter_value(timer, elapsed_cycles); + + switch (timer->phase) + { + case 1: cycles_to_output = 1; break; + case 2: cycles_to_output = adjusted_count(bcd, timer->value); break; + default: cycles_to_output = CYCLES_NEVER; break; + } + break; + + + case 2: + /* Mode 2: (Rate Generator) + + --------------+ +---------+ +---- + | | | | + +-+ +-+ + <- n -X- n -> + <1> + ^ + +- counter load or trigger + + phase|output|length |value|next|comment + -----+------+--------+-----+----+---------------------------------- + 0|high |infinity| |1 |waiting for count + 1|high |1 | |2 |internal delay to load counter + 2|high |n |n..2 |3 |counting down + 3|low |1 |1 |2 |reload counter + + Counter rewrite has no effect until repeated + + Gate rising-edge and level sensitive. + Gate low disables counting and sets output immediately high. + Rising-edge reloads count and initiates counting + Gate high enables counting. */ + + if (timer->gate == 0 || timer->phase == 0) + { + /* Gate low or mode control write forces output high */ + set_output(timer, 1); + cycles_to_output = CYCLES_NEVER; + } + else + { + if (elapsed_cycles >= 0 && timer->phase == 1) + { + if (elapsed_cycles > 0) + { + --elapsed_cycles; + timer->phase = 2; + } + load_counter_value(timer); + } + + adjusted_value = adjusted_count(bcd, timer->value); + + do + { + if (timer->phase == 2) + { + if (elapsed_cycles + 1 >= adjusted_value) + { + /* Counter hits 1, output goes low */ + timer->phase = 3; + set_output(timer, 0); + } + } + + if (elapsed_cycles > 0 && timer->phase == 3) + { + /* Reload counter, output goes high */ + elapsed_cycles -= adjusted_value; + timer->phase = 2; + load_counter_value(timer); + adjusted_value = adjusted_count(bcd, timer->value); + set_output(timer, 1); + } + } + while (elapsed_cycles >= adjusted_value); + + /* Calculate counter value */ + decrease_counter_value(timer, elapsed_cycles); + + switch (timer->phase) + { + case 1: cycles_to_output = 1; break; + default: cycles_to_output = (timer->value == 1) ? 1 : (adjusted_count(bcd, timer->value) - 1); break; + } + } + break; + + + case 3: + /* Mode 3: (Square Wave Generator) + + ----------------+ +-----------+ +---- + | | | | + +-----------+ +-----------+ + <- (n+1)/2 -X- n/2 -> + ^ + +- counter load or trigger + + phase|output|length |value|next|comment + -----+------+--------+-----+----+---------------------------------- + 0|high |infinity| |1 |waiting for count + 1|high |1 | |2 |internal delay to load counter + 2|high |n/2(+1) |n..0 |3 |counting down double speed, reload counter + 3|low |n/2 |n..0 |2 |counting down double speed, reload counter + + Counter rewrite has no effect until repeated (output falling or rising) + + Gate rising-edge and level sensitive. + Gate low disables counting and sets output immediately high. + Rising-edge reloads count and initiates counting + Gate high enables counting. */ + + if (timer->gate == 0 || timer->phase == 0) + { + /* Gate low or mode control write forces output high */ + set_output(timer, 1); + cycles_to_output = CYCLES_NEVER; + } + else + { + if (elapsed_cycles >= 0 && timer->phase == 1) + { + if (elapsed_cycles > 0) + { + --elapsed_cycles; + timer->phase = 2; + } + load_counter_value(timer); + } + + if (elapsed_cycles > 0) + { + adjusted_value = adjusted_count(bcd, timer->value); + + do + { + if (timer->phase == 2 && elapsed_cycles >= ((adjusted_value + 1) >> 1)) + { + /* High phase expired, output goes low */ + elapsed_cycles -= ((adjusted_value + 1) >> 1); + timer->phase = 3; + load_counter_value(timer); + adjusted_value = adjusted_count(bcd, timer->value); + set_output(timer, 0); + } + + if (timer->phase == 3 && elapsed_cycles >= (adjusted_value >> 1)) + { + /* Low phase expired, output goes high */ + elapsed_cycles -= (adjusted_value >> 1); + timer->phase = 2; + load_counter_value(timer); + adjusted_value = adjusted_count(bcd, timer->value); + set_output(timer, 1); + } + } + while ((timer->phase == 2 && elapsed_cycles >= ((adjusted_value + 1) >> 1)) || + (timer->phase == 3 && elapsed_cycles >= (adjusted_value >> 1))); + + decrease_counter_value(timer, elapsed_cycles * 2); + + switch (timer->phase) + { + case 1: cycles_to_output = 1; break; + case 2: cycles_to_output = (adjusted_count(bcd, timer->value) + 1) >> 1; break; + case 3: cycles_to_output = adjusted_count(bcd, timer->value) >> 1; break; + } + } + } + break; + + + case 4: + case 5: + /* Mode 4: (Software Trigger Strobe) + Mode 5: (Hardware Trigger Strobe) + + --------------+ +-------------------- + | | + +-+ + <- n+1 -> + ^ <1> + +- counter load (mode 4) or trigger (mode 5) + + phase|output|length |value|next|comment + -----+------+--------+-----+----+---------------------------------- + 0|high |infinity|0..1 |0 |waiting for count/counting down + 1|high |1 | |2 |internal delay when counter loaded + 2|high |n |n..1 |3 |counting down + 3|low |1 |0 |0 |strobe + + Mode 4 only: counter rewrite loads new counter + Mode 5 only: count not reloaded immediately. + Mode control write doesn't stop count but sets output high + + Mode 4 only: Gate level sensitive only. Low disables counting, high enables it. + Mode 5 only: Gate rising-edge sensitive only. Rising edge initiates counting */ + + if (timer->gate == 0 && mode == 4) + { + cycles_to_output = CYCLES_NEVER; + } + else + { + if (elapsed_cycles >= 0 && timer->phase == 1) + { + if (elapsed_cycles > 0) + { + --elapsed_cycles; + timer->phase = 2; + } + load_counter_value(timer); + } + + if (timer->value == 0 && timer->phase == 2) + adjusted_value = 0; + else + adjusted_value = adjusted_count(bcd, timer->value); + + if (timer->phase == 2 && elapsed_cycles >= adjusted_value) + { + /* Counter has hit zero, set output to low */ + elapsed_cycles -= adjusted_value; + timer->phase = 3; + timer->value = 0; + set_output(timer, 0); + } + + if (elapsed_cycles > 0 && timer->phase == 3) + { + --elapsed_cycles; + timer->phase = 0; + decrease_counter_value(timer, 1); + set_output(timer, 1); + } + + decrease_counter_value(timer, elapsed_cycles); + + switch (timer->phase) + { + case 1: cycles_to_output = 1; break; + case 2: cycles_to_output = adjusted_count(bcd, timer->value); break; + case 3: cycles_to_output = 1; break; + } + } + break; + } + + if (cycles_to_output == CYCLES_NEVER || timer->clockin == 0) + { + timer->updatetimer->adjust(attotime::never, timer->index); + } + else + { + attotime next_fire_time = timer->last_updated + cycles_to_output * attotime::from_hz(timer->clockin); + + timer->updatetimer->adjust(next_fire_time - machine().time(), timer->index); + } + + LOG2(("pit8253: simulate2(): simulating %d cycles for %d in mode %d, bcd = %d, phase = %d, gate = %d, output %d, value = 0x%04x, cycles_to_output = %04x\n", + (int)elapsed_cycles, timer->index, mode, bcd, timer->phase, timer->gate, timer->output, timer->value, cycles_to_output)); +} + + +/* This emulates timer "timer" for "elapsed_cycles" cycles, broken down into + sections punctuated by callbacks. */ +void pit8253_device::simulate(pit8253_timer *timer, INT64 elapsed_cycles) +{ + if (elapsed_cycles > 0) + simulate2(timer, elapsed_cycles); + else if (timer->clockin) + timer->updatetimer->adjust(attotime::from_hz(timer->clockin), timer->index); +} + + +/* This brings timer "timer" up to date */ +void pit8253_device::update(pit8253_timer *timer) +{ + /* With the 82C54's maximum clockin of 10MHz, 64 bits is nearly 60,000 + years of time. Should be enough for now. */ + attotime now = machine().time(); + attotime elapsed_time = now - timer->last_updated; + INT64 elapsed_cycles = elapsed_time.as_double() * timer->clockin; + + LOG1(("pit8253: update(): timer %d, %" I64FMT "d elapsed_cycles\n", timer->index, elapsed_cycles)); + + if (timer->clockin) + timer->last_updated += elapsed_cycles * attotime::from_hz(timer->clockin); + else + timer->last_updated = now; + + simulate(timer, elapsed_cycles); +} + + +/* We recycle bit 0 of timer->value to hold the phase in mode 3 when count is + odd. Since read commands in mode 3 always return even numbers, we need to + mask this bit off. */ +UINT16 pit8253_device::masked_value(pit8253_timer *timer) +{ + LOG2(("pit8253: masked_value\n")); + if (CTRL_MODE(timer->control) == 3) + return timer->value & 0xfffe; + return timer->value; +} + +/* Reads only affect the following bits of the counter state: + latched_status + latched_count + rmsb + so they don't affect any timer operations except other reads. */ +READ8_MEMBER( pit8253_device::read ) +{ + pit8253_timer *timer = get_timer(offset); + UINT8 data; + UINT16 value; + + LOG2(("pit8253_r(): offset %d\n", offset)); + + if (timer == NULL) + { + /* Reading mode control register is illegal according to docs */ + /* Experimentally determined: reading it returns 0 */ + data = 0; + } + else + { + update(timer); + + if (timer->latched_status) + { + /* Read status register (8254 only) */ + data = timer->status; + timer->latched_status = 0; + } + else + { + if (timer->latched_count != 0) + { + /* Read back latched count */ + data = (timer->latch >> (timer->rmsb ? 8 : 0)) & 0xff; + timer->rmsb = 1 - timer->rmsb; + --timer->latched_count; + } + else + { + value = masked_value(timer); + + /* Read back current count */ + switch (CTRL_ACCESS(timer->control)) + { + case 0: + default: + /* This should never happen */ + data = 0; /* Appease compiler */ + break; + + case 1: + /* read counter bits 0-7 only */ + data = (value >> 0) & 0xff; + break; + + case 2: + /* read counter bits 8-15 only */ + data = (value >> 8) & 0xff; + break; + + case 3: + /* read bits 0-7 first, then 8-15 */ + data = (value >> (timer->rmsb ? 8 : 0)) & 0xff; + timer->rmsb = 1 - timer->rmsb; + break; + } + } + } + } + + LOG2(("pit8253: read(): offset=%d data=0x%02x\n", offset, data)); + return data; +} + + +/* Loads a new value from the bus to the count register (CR) */ +void pit8253_device::load_count(pit8253_timer *timer, UINT16 newcount) +{ + int mode = CTRL_MODE(timer->control); + LOG1(("pit8253: load_count(): %04x\n", newcount)); + + if (newcount == 1) + { + /* Count of 1 is illegal in modes 2 and 3. What happens here was + determined experimentally. */ + if (mode == 2) + newcount = 2; + if (mode == 3) + newcount = 0; + } + + timer->count = newcount; + + if (mode == 2 || mode == 3) + { + if (timer->phase == 0) + timer->phase = 1; + } + else + { + if (mode == 0 || mode == 4) + timer->phase = 1; + } +} + + +void pit8253_device::readback(pit8253_timer *timer, int command) +{ + UINT16 value; + update(timer); + + if ((command & 1) == 0) + { + /* readback status command */ + if (!timer->latched_status) + { + timer->status = (timer->control & 0x3f) | ((timer->output != 0) ? 0x80 : 0) | (timer->null_count ? 0x40 : 0); + timer->latched_status = 1; + } + } + + /* Experimentally determined: the read latch command seems to have no + effect if we're halfway through a 16-bit read */ + if ((command & 2) == 0 && !timer->rmsb) + { + /* readback count command */ + if (timer->latched_count == 0) + { + value = masked_value(timer); + switch (CTRL_ACCESS(timer->control)) + { + case 0: + /* This should never happen */ + break; + + case 1: + /* latch bits 0-7 only */ + timer->latch = ((value << 8) & 0xff00) | (value & 0xff); + timer->latched_count = 1; + break; + + case 2: + /* read bits 8-15 only */ + timer->latch = (value & 0xff00) | ((value >> 8) & 0xff); + timer->latched_count = 1; + break; + + case 3: + /* latch all 16 bits */ + timer->latch = value; + timer->latched_count = 2; + break; + } + } + } +} + + +void pit8253_device::readback_command(UINT8 data) +{ + /* Readback command. Illegal on 8253 */ + /* Todo: find out what (if anything) the 8253 hardware actually does here. */ +} + +void pit8254_device::readback_command(UINT8 data) +{ + LOG1(("pit8253: write(): readback %02x\n", data & 0x3f)); + + /* Bit 0 of data must be 0. Todo: find out what the hardware does if it isn't. */ + int read_command = (data >> 4) & 3; + if ((data & 2) != 0) + readback(get_timer(0), read_command); + if ((data & 4) != 0) + readback(get_timer(1), read_command); + if ((data & 8) != 0) + readback(get_timer(2), read_command); +} + +void pit8253_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + update(get_timer(id)); +} + +WRITE8_MEMBER( pit8253_device::write ) +{ + pit8253_timer *timer = get_timer(offset); + + LOG2(("pit8253: write(): offset=%d data=0x%02x\n", offset, data)); + + if (timer == NULL) + { + /* Write to mode control register */ + timer = get_timer((data >> 6) & 3); + if (timer == NULL) + { + readback_command(data); + return; + } + + update(timer); + + if (CTRL_ACCESS(data) == 0) + { + LOG1(("pit8253: write(): timer=%d readback\n", (data >> 6) & 3)); + + /* Latch current timer value */ + /* Experimentally verified: this command does not affect the mode control register */ + readback(timer, 1); + } + else + { + LOG1(("pit8253: write(): timer=%d bytes=%d mode=%d bcd=%d\n", (data >> 6) & 3, (data >> 4) & 3, (data >> 1) & 7, data & 1)); + + timer->control = (data & 0x3f); + timer->null_count = 1; + timer->wmsb = timer->rmsb = 0; + /* Phase 0 is always the phase after a mode control write */ + timer->phase = 0; + set_output(timer, CTRL_MODE(timer->control) ? 1 : 0); + } + } + else + { + int middle_of_a_cycle = 0; + + update(timer); + + if (machine().time() > timer->last_updated && timer->clockin != 0) + middle_of_a_cycle = 1; + + switch (CTRL_ACCESS(timer->control)) + { + case 0: + /* This should never happen */ + break; + + case 1: + /* read/write counter bits 0-7 only */ + + /* check if we should compensate for not being on a cycle boundary */ + if (middle_of_a_cycle) + timer->last_updated += attotime::from_hz(timer->clockin); + + load_count(timer, data); + simulate2(timer, 0); + + if (CTRL_MODE(timer->control) == 0) + { + set_output(timer, 0); + } + break; + + case 2: + /* read/write counter bits 8-15 only */ + + /* check if we should compensate for not being on a cycle boundary */ + if (middle_of_a_cycle) + timer->last_updated += attotime::from_hz(timer->clockin); + + load_count(timer, data << 8); + simulate2(timer, 0); + break; + + case 3: + /* read/write bits 0-7 first, then 8-15 */ + if (timer->wmsb) + { + /* check if we should compensate for not being on a cycle boundary */ + if (middle_of_a_cycle) + timer->last_updated += attotime::from_hz(timer->clockin); + + load_count(timer, timer->lowcount | (data << 8)); + simulate2(timer, 0); + } + else + { + timer->lowcount = data; + if (CTRL_MODE(timer->control) == 0) + { + /* The Intel docs say that writing the MSB in mode 0, phase + 2 won't stop the count, but this was experimentally + determined to be false. */ + timer->phase = 0; + set_output(timer, 0); + } + } + timer->wmsb = 1 - timer->wmsb; + break; + } + } +} + +void pit8253_device::gate_w(int gate, int state) +{ + pit8253_timer *timer = get_timer(gate); + + if (timer == NULL) + return; + + LOG2(("pit8253 : gate_w(): gate=%d state=%d\n", gate, state)); + + if (state != timer->gate) + { + int mode = CTRL_MODE(timer->control); + + update(timer); + timer->gate = state; + if (state != 0 && ( mode == 1 || mode == 2 || mode == 5 )) + { + timer->phase = 1; + } + update(timer); + } +} + +WRITE_LINE_MEMBER( pit8253_device::write_gate0 ) +{ + gate_w(0, state); +} + +WRITE_LINE_MEMBER( pit8253_device::write_gate1 ) +{ + gate_w(1, state); +} + +WRITE_LINE_MEMBER( pit8253_device::write_gate2 ) +{ + gate_w(2, state); +} + + +/* ----------------------------------------------------------------------- */ + +void pit8253_device::set_clockin(int timerno, double new_clockin) +{ + pit8253_timer *timer = get_timer(timerno); + assert(timer != NULL); + + LOG2(("pit8253_set_clockin(): PIT timer=%d, clockin = %f\n", timerno, new_clockin)); + + update(timer); + timer->clockin = new_clockin; + update(timer); +} + + +void pit8253_device::set_clock_signal(int timerno, int state) +{ + pit8253_timer *timer = get_timer(timerno); + assert(timer != NULL); + + LOG2(("pit8253_set_clock_signal(): PIT timer=%d, state = %d\n", timerno, state)); + + /* Trigger on low to high transition */ + if (!timer->clock && state) + { + /* Advance a cycle */ + simulate2(timer, 1); + } + timer->clock = state; +} + +WRITE_LINE_MEMBER( pit8253_device::write_clk0 ) +{ + set_clock_signal(0, state); +} + +WRITE_LINE_MEMBER( pit8253_device::write_clk1 ) +{ + set_clock_signal(1, state); +} + +WRITE_LINE_MEMBER( pit8253_device::write_clk2 ) +{ + set_clock_signal(2, state); +} + +#if (defined(__MINGW32__) && (__GNUC__ >= 5)) +#pragma GCC diagnostic pop +#endif diff --git a/src/devices/machine/pit8253.h b/src/devices/machine/pit8253.h new file mode 100644 index 00000000000..67e3f86b23b --- /dev/null +++ b/src/devices/machine/pit8253.h @@ -0,0 +1,172 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol, Nathan Woods +/*************************************************************************** + + Intel 8253/8254 + Programmable Interval Timer + + As uPD71054C (8MHz), uPD71054C-10 (10MHz) - it is a clone of Intel 82C54 + also available in 28-pin QFP and 44-pin PLCC (many pins NC) + + _____ _____ + D7 1 |* \_/ | 24 VCC + D6 2 | | 23 _WR + D5 3 | | 22 _RD + D4 4 | | 21 _CS + D3 5 | | 20 A1 + D2 6 | 8253 | 19 A0 + D1 7 | 8254 | 18 CLK2 + D0 8 | | 17 OUT2 + CLK0 9 | | 16 GATE2 + OUT0 10 | | 15 CLK1 + GATE0 11 | | 14 GATE1 + GND 12 |_____________| 13 OUT1 + + +***************************************************************************/ + +#ifndef __PIT8253_H__ +#define __PIT8253_H__ + +/*************************************************************************** + DEVICE CONFIGURATION MACROS +***************************************************************************/ + +#define MCFG_PIT8253_CLK0(_clk) \ + pit8253_device::set_clk0(*device, _clk); + +#define MCFG_PIT8253_CLK1(_clk) \ + pit8253_device::set_clk1(*device, _clk); + +#define MCFG_PIT8253_CLK2(_clk) \ + pit8253_device::set_clk2(*device, _clk); + +#define MCFG_PIT8253_OUT0_HANDLER(_devcb) \ + devcb = &pit8253_device::set_out0_handler(*device, DEVCB_##_devcb); + +#define MCFG_PIT8253_OUT1_HANDLER(_devcb) \ + devcb = &pit8253_device::set_out1_handler(*device, DEVCB_##_devcb); + +#define MCFG_PIT8253_OUT2_HANDLER(_devcb) \ + devcb = &pit8253_device::set_out2_handler(*device, DEVCB_##_devcb); + + +class pit8253_device : public device_t +{ +public: + pit8253_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + pit8253_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + ~pit8253_device() {} + + // static configuration helpers + static void set_clk0(device_t &device, double clk0) { downcast(device).m_clk0 = clk0; } + static void set_clk1(device_t &device, double clk1) { downcast(device).m_clk1 = clk1; } + static void set_clk2(device_t &device, double clk2) { downcast(device).m_clk2 = clk2; } + template static devcb_base &set_out0_handler(device_t &device, _Object object) { return downcast(device).m_out0_handler.set_callback(object); } + template static devcb_base &set_out1_handler(device_t &device, _Object object) { return downcast(device).m_out1_handler.set_callback(object); } + template static devcb_base &set_out2_handler(device_t &device, _Object object) { return downcast(device).m_out2_handler.set_callback(object); } + + DECLARE_READ8_MEMBER(read); + DECLARE_WRITE8_MEMBER(write); + + WRITE_LINE_MEMBER(write_gate0); + WRITE_LINE_MEMBER(write_gate1); + WRITE_LINE_MEMBER(write_gate2); + + /* In the 8253/8254 the CLKx input lines can be attached to a regular clock + signal. Another option is to use the output from one timer as the input + clock to another timer. + + The functions below should supply both functionalities. If the signal is + a regular clock signal, use the pit8253_set_clockin function. If the + CLKx input signal is the output of the different source, set the new_clockin + to 0 with pit8253_set_clockin and call pit8253_clkX_w to change + the state of the input CLKx signal. + */ + WRITE_LINE_MEMBER(write_clk0); + WRITE_LINE_MEMBER(write_clk1); + WRITE_LINE_MEMBER(write_clk2); + + void set_clockin(int timer, double new_clockin); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + // internal state + struct pit8253_timer + { + int index; /* index number of the timer */ + double clockin; /* input clock frequency in Hz */ + int clock; /* clock signal when clockin is 0 */ + + attotime last_updated; /* time when last updated */ + + emu_timer *updatetimer; /* MAME timer to process updates */ + + UINT16 value; /* current counter value ("CE" in Intel docs) */ + UINT16 latch; /* latched counter value ("OL" in Intel docs) */ + UINT16 count; /* new counter value ("CR" in Intel docs) */ + UINT8 control; /* 6-bit control byte */ + UINT8 status; /* status byte - 8254 only */ + UINT8 lowcount; /* LSB of new counter value for 16-bit writes */ + int rmsb; /* 1 = Next read is MSB of 16-bit value */ + int wmsb; /* 1 = Next write is MSB of 16-bit value */ + int output; /* 0 = low, 1 = high */ + + int gate; /* gate input (0 = low, 1 = high) */ + int latched_count; /* number of bytes of count latched */ + int latched_status; /* 1 = status latched (8254 only) */ + int null_count; /* 1 = mode control or count written, 0 = count loaded */ + int phase; /* see phase definition tables in simulate2(), below */ + }; + + void readback(pit8253_timer *timer, int command); + virtual void readback_command(UINT8 data); + pit8253_timer *get_timer(int which); + +private: + double m_clk0; + double m_clk1; + double m_clk2; + devcb_write_line m_out0_handler; + devcb_write_line m_out1_handler; + devcb_write_line m_out2_handler; + + enum + { + PIT8253_MAX_TIMER = 3 + }; + + pit8253_timer m_timers[PIT8253_MAX_TIMER]; + + inline UINT32 adjusted_count(int bcd, UINT16 val); + void decrease_counter_value(pit8253_timer *timer, INT64 cycles); + void load_counter_value(pit8253_timer *timer); + void set_output(pit8253_timer *timer, int output); + void simulate2(pit8253_timer *timer, INT64 elapsed_cycles); + void simulate(pit8253_timer *timer, INT64 elapsed_cycles); + void update(pit8253_timer *timer); + UINT16 masked_value(pit8253_timer *timer); + void load_count(pit8253_timer *timer, UINT16 newcount); + void gate_w(int gate, int state); + void set_clock_signal(int timerno, int state); +}; + +extern const device_type PIT8253; + + +class pit8254_device : public pit8253_device +{ +public: + pit8254_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual void readback_command(UINT8 data); +}; + +extern const device_type PIT8254; + +#endif /* __PIT8253_H__ */ diff --git a/src/devices/machine/pla.c b/src/devices/machine/pla.c new file mode 100644 index 00000000000..e8ca43d448f --- /dev/null +++ b/src/devices/machine/pla.c @@ -0,0 +1,181 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder, hap +/********************************************************************** + + PLA (Programmable Logic Array) emulation + +**********************************************************************/ + +#include "pla.h" +#include "jedparse.h" +#include "plaparse.h" + + +const device_type PLA = &device_creator; + +//------------------------------------------------- +// pla_device - constructor +//------------------------------------------------- + +pla_device::pla_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, PLA, "PLA", tag, owner, clock, "pla", __FILE__), + m_format(PLA_FMT_JEDBIN), + m_inputs(0), + m_outputs(0), + m_terms(0), + m_input_mask(0), + m_xor(0) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void pla_device::device_start() +{ + assert(region() != NULL); + assert(m_terms < MAX_TERMS); + assert(m_inputs < 32 && m_outputs <= 32); + + if (m_input_mask == 0) + m_input_mask = ((UINT64)1 << m_inputs) - 1; + m_input_mask = ((UINT64)m_input_mask << 32) | m_input_mask; + + // parse fusemap + parse_fusemap(); + + // initialize cache + m_cache2_ptr = 0; + for (int i = 0; i < CACHE2_SIZE; i++) + m_cache2[i] = 0x80000000; + + m_cache_size = 0; + int csize = 1 << ((m_inputs > MAX_CACHE_BITS) ? MAX_CACHE_BITS : m_inputs); + m_cache.resize(csize); + for (int i = 0; i < csize; i++) + m_cache[i] = read(i); + + m_cache_size = csize; +} + + +//------------------------------------------------- +// parse_fusemap - +//------------------------------------------------- + +void pla_device::parse_fusemap() +{ + jed_data jed; + int result = JEDERR_NONE; + + // read pla file + switch (m_format) + { + case PLA_FMT_JEDBIN: + result = jedbin_parse(region()->base(), region()->bytes(), &jed); + break; + + case PLA_FMT_BERKELEY: + result = pla_parse(region()->base(), region()->bytes(), &jed); + break; + } + + if (result != JEDERR_NONE) + { + for (int p = 0; p < m_terms; p++) + { + m_term[p].and_mask = 0; + m_term[p].or_mask = 0; + } + + logerror("%s PLA parse error %d!\n", tag(), result); + return; + } + + // parse it + UINT32 fusenum = 0; + + for (int p = 0; p < m_terms; p++) + { + term *term = &m_term[p]; + + // AND mask + term->and_mask = 0; + + for (int i = 0; i < m_inputs; i++) + { + // complement + term->and_mask |= (UINT64)jed_get_fuse(&jed, fusenum++) << (i + 32); + + // true + term->and_mask |= (UINT64)jed_get_fuse(&jed, fusenum++) << i; + } + + // OR mask + term->or_mask = 0; + + for (int f = 0; f < m_outputs; f++) + { + term->or_mask |= !jed_get_fuse(&jed, fusenum++) << f; + } + + term->or_mask <<= 32; + } + + // XOR mask + m_xor = 0; + + for (int f = 0; f < m_outputs; f++) + { + m_xor |= jed_get_fuse(&jed, fusenum++) << f; + } + + m_xor <<= 32; +} + + +//------------------------------------------------- +// read - +//------------------------------------------------- + +UINT32 pla_device::read(UINT32 input) +{ + // try the cache first + if (input < m_cache_size) + return m_cache[input]; + + for (int i = 0; i < CACHE2_SIZE; ++i) + { + UINT64 cache2_entry = m_cache2[i]; + + if ((UINT32)cache2_entry == input) + { + // cache2 hit + return cache2_entry >> 32; + } + } + + // cache miss, process terms + UINT64 inputs = ((~(UINT64)input << 32) | input) & m_input_mask; + UINT64 s = 0; + + for (int i = 0; i < m_terms; ++i) + { + term* term = &m_term[i]; + + if ((term->and_mask | inputs) == m_input_mask) + { + s |= term->or_mask; + } + } + + s ^= m_xor; + + // store output in cache2 + m_cache2[m_cache2_ptr] = s | input; + ++m_cache2_ptr &= (CACHE2_SIZE - 1); + + return s >> 32; +} diff --git a/src/devices/machine/pla.h b/src/devices/machine/pla.h new file mode 100644 index 00000000000..10dbc850370 --- /dev/null +++ b/src/devices/machine/pla.h @@ -0,0 +1,137 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder, hap +/********************************************************************** + + PLA (Programmable Logic Array) emulation + +**********************************************************************/ + +#pragma once + +#ifndef __PLA__ +#define __PLA__ + +#include "emu.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define MAX_TERMS 512 +#define MAX_CACHE_BITS 20 +#define CACHE2_SIZE 8 + +enum +{ + PLA_FMT_JEDBIN = 0, + PLA_FMT_BERKELEY +}; + + + +///************************************************************************* +// INTERFACE CONFIGURATION MACROS +///************************************************************************* + +#define MCFG_PLA_ADD(_tag, _inputs, _outputs, _terms) \ + MCFG_DEVICE_ADD(_tag, PLA, 0) \ + pla_device::set_num_inputs(*device, _inputs); \ + pla_device::set_num_outputs(*device, _outputs); \ + pla_device::set_num_terms(*device, _terms); + +#define MCFG_PLA_INPUTMASK(_mask) \ + pla_device::set_inputmask(*device, _mask); + +#define MCFG_PLA_FILEFORMAT(_format) \ + pla_device::set_format(*device, _format); + + +// macros for known (and used) devices + +// 82S100, 82S101, PLS100, PLS101 +// 16x48x8 PLA, 28-pin: +/* _____ _____ + FE 1 |* \_/ | 28 Vcc + I7 2 | | 27 I8 + I6 3 | | 26 I9 + I5 4 | | 25 I10 + I4 5 | | 24 I11 + I3 6 | 82S100 | 23 I12 + I2 7 | 82S101 | 22 I13 + I1 8 | PLS100 | 21 I14 + I0 9 | PLS101 | 20 I15 + F7 10 | | 19 _CE + F6 11 | | 18 F0 + F5 12 | | 17 F1 + F4 13 | | 16 F2 + GND 14 |_____________| 15 F3 +*/ +#define MCFG_PLS100_ADD(_tag) \ + MCFG_PLA_ADD(_tag, 16, 8, 48) + +// MOS 8721 PLA +// TODO: actual number of terms is unknown +#define MCFG_MOS8721_ADD(_tag) \ + MCFG_PLA_ADD(_tag, 27, 18, 379) + + + +///************************************************************************* +// TYPE DEFINITIONS +///************************************************************************* + +// ======================> pla_device + +class pla_device : public device_t +{ +public: + // construction/destruction + pla_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // static configuration helpers + static void set_num_inputs(device_t &device, UINT32 i) { downcast(device).m_inputs = i; } + static void set_num_outputs(device_t &device, UINT32 o) { downcast(device).m_outputs = o; } + static void set_num_terms(device_t &device, UINT32 t) { downcast(device).m_terms = t; } + static void set_inputmask(device_t &device, UINT32 mask) { downcast(device).m_input_mask = mask; } // UINT32! + static void set_format(device_t &device, int format) { downcast(device).m_format = format; } + + UINT32 inputs() { return m_inputs; } + UINT32 outputs() { return m_outputs; } + + UINT32 read(UINT32 input); + +protected: + // device-level overrides + virtual void device_start(); + +private: + void parse_fusemap(); + + int m_format; + + UINT32 m_inputs; + UINT32 m_outputs; + UINT32 m_terms; + UINT64 m_input_mask; + UINT64 m_xor; + + int m_cache_size; + std::vector m_cache; + UINT64 m_cache2[CACHE2_SIZE]; + UINT8 m_cache2_ptr; + + struct term + { + UINT64 and_mask; + UINT64 or_mask; + } m_term[MAX_TERMS]; +}; + + +// device type definition +extern const device_type PLA; + + +#endif diff --git a/src/devices/machine/r10696.c b/src/devices/machine/r10696.c new file mode 100644 index 00000000000..ab20caed731 --- /dev/null +++ b/src/devices/machine/r10696.c @@ -0,0 +1,185 @@ +// license:BSD-3-Clause +// copyright-holders:Juergen Buchmueller +/********************************************************************** + + Rockwell 10696 General Purpose Input/Output (I/O) + + REGISTER DESCRIPTION + + HEX Address Select Names + ------------------------------------------------------- + A x x x x 1 0 1 0 Read Group A + 9 x x x x 1 0 0 1 Read Group B + 3 x x x x 0 0 1 1 Read Group C + 0 x x x x 0 0 0 0 Read Groups A | B | C + 1 x x x x 0 0 0 1 Read Groups B | C + 2 x x x x 0 0 1 0 Read Groups A | C + 8 x x x x 1 0 0 0 Read Groups A | B + + E x x x x 1 1 1 0 Set Group A + D x x x x 1 1 0 1 Set Group B + 7 x x x x 0 1 1 1 Set Group C + 4 x x x x 0 1 0 0 Set Groups A, B and C + 5 x x x x 0 1 0 1 Set Groups B and C + 6 x x x x 0 1 1 0 Set Groups A and C + C x x x x 1 1 0 0 Set Groups A and B + + Notes: + Any of the I/O chips may be used to read or set any group + (A, B, C) or combination of groups. +**********************************************************************/ + +#include "emu.h" +#include "machine/r10696.h" + +#define VERBOSE 1 +#if VERBOSE +#define LOG(x) logerror x +#else +#define LOG(x) +#endif + +/************************************* + * + * Device interface + * + *************************************/ + +const device_type R10696 = &device_creator; + +r10696_device::r10696_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, R10696, "Rockwell 10696", tag, owner, clock, "r10696", __FILE__), + m_io_a(0), m_io_b(0), m_io_c(0), + m_iord(*this), m_iowr(*this) +{ +} + +/** + * @brief r10696_device::device_start device-specific startup + */ +void r10696_device::device_start() +{ + m_iord.resolve(); + m_iowr.resolve(); + + save_item(NAME(m_io_a)); + save_item(NAME(m_io_b)); + save_item(NAME(m_io_c)); +} + +/** + * @brief r10696_device::device_reset device-specific reset + */ +void r10696_device::device_reset() +{ + m_io_a = 0; + m_io_b = 0; + m_io_c = 0; +} + +/************************************* + * + * Command access handlers + * + *************************************/ + +WRITE8_MEMBER( r10696_device::io_w ) +{ + assert(offset < 16); + const UINT8 io_a = m_io_a; + const UINT8 io_b = m_io_b; + const UINT8 io_c = m_io_c; + switch (offset) + { + case 0x0A: // Read Group A + case 0x09: // Read Group B + case 0x03: // Read Group C + case 0x00: // Read Groups A | B | C + case 0x01: // Read Groups B | C + case 0x02: // Read Groups A | C + case 0x08: // Read Groups A | B + break; + + case 0x0E: // Set Group A + m_io_a = data & 0x0f; + break; + case 0x0D: // Set Group B + m_io_b = data & 0x0f; + break; + case 0x07: // Set Group C + m_io_c = data & 0x0f; + break; + case 0x04: // Set Groups A, B and C + m_io_a = m_io_b = m_io_c = data & 0x0f; + break; + case 0x05: // Set Groups B and C + m_io_b = m_io_c = data & 0x0f; + break; + case 0x06: // Set Groups A and C + m_io_a = m_io_c = data & 0x0f; + break; + case 0x0C: // Set Groups A and B + m_io_a = m_io_b = data & 0x0f; + break; + } + if (io_a != m_io_a) + m_iowr(0, m_io_a, 0x0f); + if (io_b != m_io_b) + m_iowr(1, m_io_b, 0x0f); + if (io_c != m_io_c) + m_iowr(2, m_io_c, 0x0f); +} + + +READ8_MEMBER( r10696_device::io_r ) +{ + assert(offset < 16); + UINT8 io_a, io_b, io_c; + UINT8 data = 0xf; + switch (offset) + { + case 0x0A: // Read Group A + io_a = m_iord(0); + data = io_a & 0x0f; + break; + case 0x09: // Read Group B + io_b = m_iord(1); + data = io_b & 0x0f; + break; + case 0x03: // Read Group C + io_c = m_iord(2); + data = io_c & 0x0f; + break; + case 0x00: // Read Groups A | B | C + io_a = m_iord(0); + io_b = m_iord(1); + io_c = m_iord(2); + data = (io_a | io_b | io_a) & 0x0f; + break; + case 0x01: // Read Groups B | C + io_b = m_iord(1); + io_c = m_iord(2); + data = (io_b | io_c) & 0x0f; + break; + case 0x02: // Read Groups A | C + io_a = m_iord(0); + io_c = m_iord(2); + data = (io_a | io_c) & 0x0f; + break; + case 0x08: // Read Groups A | B + io_a = m_iord(0); + io_b = m_iord(1); + data = (io_a | io_b) & 0x0f; + break; + + case 0x0E: // Set Group A + case 0x0D: // Set Group B + case 0x07: // Set Group C + case 0x04: // Set Groups A, B and C + case 0x05: // Set Groups B and C + case 0x06: // Set Groups A and C + case 0x0C: // Set Groups A and B + break; + } + return data; +} diff --git a/src/devices/machine/r10696.h b/src/devices/machine/r10696.h new file mode 100644 index 00000000000..ca3b87c935e --- /dev/null +++ b/src/devices/machine/r10696.h @@ -0,0 +1,58 @@ +// license:BSD-3-Clause +// copyright-holders:Juergen Buchmueller +/********************************************************************** + + Rockwell 10696 General Purpose Input/Output (I/O) + + Juergen Buchmueller + + The device decodes reads/write to a 16 byte I/O range defined + by four wired inputs SC1, SC2, SC3 and SC4. + It provides 12 inputs and 12 outputs in groups of three + time 4 bits each. + +**********************************************************************/ + +#ifndef __R10696_H__ +#define __R10696_H__ + +#include "device.h" + +/************************************* + * + * Device configuration macros + * + *************************************/ + +/* Set the read and write group (4-bit; nibble) delegates */ +#define MCFG_R10696_IO(_devcb_rd,_devcb_wr) \ + r10696_device::set_iord(*device, DEVCB_##_devcb_rd); \ + r10696_device::set_iowr(*device, DEVCB_##_devcb_wr); + +class r10696_device : public device_t +{ +public: + r10696_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + ~r10696_device() {} + + DECLARE_READ8_MEMBER ( io_r ); + DECLARE_WRITE8_MEMBER( io_w ); + + template static devcb_base &set_iord(device_t &device, _Object object) { return downcast(device).m_iord.set_callback(object); } + template static devcb_base &set_iowr(device_t &device, _Object object) { return downcast(device).m_iowr.set_callback(object); } +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + +private: + UINT8 m_io_a; //!< input/output flip-flops group A + UINT8 m_io_b; //!< input/output flip-flops group B + UINT8 m_io_c; //!< input/output flip-flops group C + devcb_read8 m_iord; //!< input line (read, offset = group, data = 4 bits) + devcb_write8 m_iowr; //!< output line (write, offset = group, data = 4 bits) +}; + +extern const device_type R10696; + +#endif /* __R10696_H__ */ diff --git a/src/devices/machine/r10788.c b/src/devices/machine/r10788.c new file mode 100644 index 00000000000..f6e9d65ecbf --- /dev/null +++ b/src/devices/machine/r10788.c @@ -0,0 +1,226 @@ +// license:BSD-3-Clause +// copyright-holders:Juergen Buchmueller +/********************************************************************** + + Rockwell 10788 General Purpose Keyboard and Display circuit + + REGISTER DESCRIPTION + + + [ Opcodes IOL, I2 ] + NAME W/IO CS I/O CMD I/O Names + -------------------------------------------------------------- + KTR 1 1 x x x 1 1 0 0 Transfer Keyboard Return + KTS 1 1 x x x 1 0 1 0 Transfer Keyboard Strobe + KLA 1 1 x x x 1 1 1 0 Load Display Register A + KLB 1 1 x x x 1 1 0 1 Load Display Register A + KDN 1 1 x x x 0 0 1 1 Turn On Display + KAF 1 1 x x x 1 0 1 1 Turn Off A + KBF 1 1 x x x 0 1 1 1 Turn Off B + KER 1 1 x x x 0 1 1 0 Reset Keyboard Error + + Notes: + 1.) W/IO is generated by the first word of the PPS IOL instruction. + 2.) Polarities of I/O7, I/O6 and I/O5 must be the same as the + polarities of the chip select straps SC7, SC6 and SC5. + 3.) KLA resets DA1-DA4 and DB1 and DB2 to VSS level. KLB resets + DB3 and DB4 to VSS level. + 4.) KAF and KBF is used to blank the display without changing the + contents of display data registers. + 5.) KAF resets output lines DA1, DA2, DA3, DA4, DB1 and DB2 to + VSS level. KBF resets output lines DB3 and DB4 to VSS level. + 6.) KAF stops the circulation of the display register A, and KBF + stops the circulation of the display register B. + 7.) KER takes a maximum of 10-bit times to complete (= 80 clocks) + Therefore, there must be at least 10 bit times between KER + and the next KTS instruction. +**********************************************************************/ + +#include "emu.h" +#include "machine/r10788.h" + +#define VERBOSE 0 +#if VERBOSE +#define LOG(x) logerror x +#else +#define LOG(x) +#endif + +/************************************* + * + * Device interface + * + *************************************/ + +const device_type R10788 = &device_creator; + +r10788_device::r10788_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, R10788, "Rockwell 10788", tag, owner, clock, "r10788", __FILE__), + m_ktr(0), m_kts(0), m_kla(0), m_klb(0), m_mask_a(15), m_mask_b(15), m_ker(0), + m_io_counter(0), m_scan_counter(0), + m_display(*this) +{ +} + +/** + * @brief r10788_device::device_start device-specific startup + */ +void r10788_device::device_start() +{ + m_display.resolve(); + + save_item(NAME(m_reg)); + save_item(NAME(m_ktr)); + save_item(NAME(m_kts)); + save_item(NAME(m_kla)); + save_item(NAME(m_klb)); + save_item(NAME(m_mask_a)); + save_item(NAME(m_mask_b)); + save_item(NAME(m_ker)); + save_item(NAME(m_io_counter)); + save_item(NAME(m_scan_counter)); + + m_timer = timer_alloc(TIMER_DISPLAY); + // recurring timer every 36 cycles + m_timer->adjust(clocks_to_attotime(36), 0, clocks_to_attotime(36)); +} + +/** + * @brief r10788_device::device_reset device-specific reset + */ +void r10788_device::device_reset() +{ + memset(m_reg, 0x00, sizeof(m_reg)); + m_ktr = 0; + m_kts = 0; + m_kla = 0; + m_klb = 0; + m_mask_a = 15; + m_mask_b = 15; + m_ker = 0; + m_scan_counter = 0; +} + + +/** + * @brief r10788_device::device_timer timer event callback + * @param timer emu_timer which fired + * @param id timer identifier + * @param param parameter + * @param ptr pointer parameter + */ +void r10788_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + UINT8 data; + switch (id) + { + case TIMER_DISPLAY: + data = (m_reg[0][m_scan_counter] & m_mask_a) + + 16 * (m_reg[1][m_scan_counter] & m_mask_b); + LOG(("%s: scan counter:%2d data:%02x\n", __FUNCTION__, m_scan_counter, data)); + m_display(m_scan_counter, data, 0xff); + break; + default: + LOG(("%s: invalid timer id:%d\n", __FUNCTION__, id)); + } + m_scan_counter = (m_scan_counter + 1) % 16; +} + +/************************************* + * + * Constants + * + *************************************/ + +/************************************* + * + * Command access handlers + * + *************************************/ + +WRITE8_MEMBER( r10788_device::io_w ) +{ + assert(offset < 16); + switch (offset) + { + case KTR: // Transfer Keyboard Return + LOG(("%s: KTR data:%02x\n", __FUNCTION__, data)); + m_ktr = data; + break; + case KTS: // Transfer Keyboard Strobe + LOG(("%s: KTS data:%02x\n", __FUNCTION__, data)); + m_kts = data; + break; + case KLA: // Load Display Register A + LOG(("%s: KLA [%2d] data:%02x\n", __FUNCTION__, m_io_counter, data)); + m_kla = data; + m_reg[0][m_io_counter] = m_kla; + break; + case KLB: // Load Display Register B + LOG(("%s: KLB [%2d] data:%02x\n", __FUNCTION__, m_io_counter, data)); + m_klb = data; + m_reg[1][m_io_counter] = m_kla; + break; + case KDN: // Turn On Display + LOG(("%s: KDN data:%02x\n", __FUNCTION__, data)); + m_mask_a = 15; + m_mask_b = 15; + break; + case KAF: // Turn Off A + LOG(("%s: KAF data:%02x\n", __FUNCTION__, data)); + m_mask_a = 0; + m_mask_b &= ~3; + break; + case KBF: // Turn Off B + LOG(("%s: KBF data:%02x\n", __FUNCTION__, data)); + m_mask_b &= ~12; + break; + case KER: // Reset Keyboard Error + LOG(("%s: KER data:%02x\n", __FUNCTION__, data)); + m_ker = 10; + break; + } +} + + +READ8_MEMBER( r10788_device::io_r ) +{ + assert(offset < 16); + UINT8 data = 0xf; + switch (offset) + { + case KTR: // Transfer Keyboard Return + data = m_ktr; + LOG(("%s: KTR data:%02x\n", __FUNCTION__, data)); + break; + case KTS: // Transfer Keyboard Strobe + data = m_kts; + LOG(("%s: KTS data:%02x\n", __FUNCTION__, data)); + break; + case KLA: // Load Display Register A + m_kla = m_reg[0][m_io_counter]; + data = m_kla; + LOG(("%s: KLA [%2d] data:%02x\n", __FUNCTION__, m_io_counter, data)); + break; + case KLB: // Load Display Register B + m_klb = m_reg[1][m_io_counter]; + data = m_klb; + LOG(("%s: KLB [%2d] data:%02x\n", __FUNCTION__, m_io_counter, data)); + // FIXME: does it automagically increment at KLB write? + m_io_counter = (m_io_counter + 1) % 16; + break; + case KDN: // Turn On Display + LOG(("%s: KDN data:%02x\n", __FUNCTION__, data)); + break; + case KAF: // Turn Off A + LOG(("%s: KAF data:%02x\n", __FUNCTION__, data)); + break; + case KBF: // Turn Off B + LOG(("%s: KBF data:%02x\n", __FUNCTION__, data)); + break; + case KER: // Reset Keyboard Error + LOG(("%s: KER data:%02x\n", __FUNCTION__, data)); + break; + } + return data; +} diff --git a/src/devices/machine/r10788.h b/src/devices/machine/r10788.h new file mode 100644 index 00000000000..af58aca65c7 --- /dev/null +++ b/src/devices/machine/r10788.h @@ -0,0 +1,76 @@ +// license:BSD-3-Clause +// copyright-holders:Juergen Buchmueller +/********************************************************************** + + Rockwell 10788 General Purpose Keyboard and Display circuit + + Juergen Buchmueller + + The device decodes reads/write to a 16 byte I/O range defined + by three wired inputs SC5, SC6 and SC7. The range is one of + 80-8f, 90-9f, ..., f0-ff depending on the wiring. + +**********************************************************************/ + +#ifndef __R10788_H__ +#define __R10788_H__ + +#include "device.h" + +/************************************* + * + * Device configuration macros + * + *************************************/ + +/* Set the writer used to update a display digit */ +#define MCFG_R10788_UPDATE(_devcb) \ + r10788_device::set_update(*device, DEVCB_##_devcb); + +class r10788_device : public device_t +{ +public: + r10788_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + ~r10788_device() {} + + enum { + KTR = 0xc, //!< Transfer Keyboard Return + KTS = 0xa, //!< Transfer Keyboard Strobe + KLA = 0xe, //!< Load Display Register A + KLB = 0xd, //!< Load Display Register B + KDN = 0x3, //!< Turn On Display + KAF = 0xb, //!< Turn Off A + KBF = 0x7, //!< Turn Off B + KER = 0x6 //!< Reset Keyboard Error + }; + + DECLARE_READ8_MEMBER ( io_r ); + DECLARE_WRITE8_MEMBER( io_w ); + + template static devcb_base &set_update(device_t &device, _Object object) { return downcast(device).m_display.set_callback(object); } +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + +private: + static const device_timer_id TIMER_DISPLAY = 0; + + UINT8 m_reg[2][16]; //!< display registers + UINT8 m_ktr; //!< transfer keyboard return value + UINT8 m_kts; //!< transfer keyboard strobe value + UINT8 m_kla; //!< display register A value + UINT8 m_klb; //!< display register B value + UINT8 m_mask_a; //!< display enable bits for A + UINT8 m_mask_b; //!< display enable bits for B + UINT8 m_ker; //!< keyboard error value + int m_io_counter; //!< current I/O register index + int m_scan_counter; //!< current display scan + devcb_write8 m_display; //!< display updater + emu_timer* m_timer; //!< timer running at clock / 18 / 36 +}; + +extern const device_type R10788; + +#endif /* __R10788_H__ */ diff --git a/src/devices/machine/ra17xx.c b/src/devices/machine/ra17xx.c new file mode 100644 index 00000000000..c1252181c7d --- /dev/null +++ b/src/devices/machine/ra17xx.c @@ -0,0 +1,131 @@ +// license:BSD-3-Clause +// copyright-holders:Juergen Buchmueller +/********************************************************************** + + Rockwell A17XX ROM, RAM and I/O chip + + A ROM of 2048 x 8 bits is addressed whenever the RRSEL line + (ROM/RAM select) is 0. A RAM of 128 x 4 bit is addressed when + RRSEL is 1. The 16 I/O ports are addressed when the WI/O line + is 1, i.e. whenever the CPU executes an IOL instruction. + There are two basic I/O instructions: + SES = Select Enable Status and SOS = Select Output Status + The lower 4 bits of the I/O address select one of 16 I/O lines. + + There are at most two A17XX per system, one for the lower + ROM and RAM portion and one for the higher. + + I/O section instructions + + Menmonic I/O bus Accu Description + ------------------------------------------------------------------ + SES 0 S S 0 X X X 0 1 X X X Enable all outputs + Acuu:3 <- I/O(BL) + ------------------------------------------------------------------ + SES 0 S S 0 X X X 0 0 X X X Disable all outputs + Acuu:3 <- I/O(BL) + ------------------------------------------------------------------ + SOS 0 S S 0 X X X 1 1 X X X I/O(BL) <- 1 + Acuu:3 <- I/O(BL) + ------------------------------------------------------------------ + SOS 0 S S 0 X X X 1 0 X X X I/O(BL) <- 0 + Acuu:3 <- I/O(BL) + + This device emulation takes care of the I/O commands, not the + ROM and RAM, because these are emulated using the generic MAME + memory system. +**********************************************************************/ + +#include "emu.h" +#include "machine/ra17xx.h" + +#define VERBOSE 1 +#if VERBOSE +#define LOG(x) logerror x +#else +#define LOG(x) +#endif + +/************************************* + * + * Device interface + * + *************************************/ + +const device_type RA17XX = &device_creator; + +ra17xx_device::ra17xx_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, RA17XX, "Rockwell A17XX", tag, owner, clock, "ra17xx", __FILE__), + m_enable(false), + m_iord(*this), + m_iowr(*this) +{ +} + +/** + * @brief ra17xx_device::device_start device-specific startup + */ +void ra17xx_device::device_start() +{ + m_iord.resolve(); + m_iowr.resolve(); + + save_item(NAME(m_line)); +} + +/** + * @brief ra17xx_device::device_reset device-specific reset + */ +void ra17xx_device::device_reset() +{ + memset(m_line, 0, sizeof(m_line)); +} + + +/************************************* + * + * Constants + * + *************************************/ + +/************************************* + * + * Command access handlers + * + *************************************/ + +WRITE8_MEMBER( ra17xx_device::io_w ) +{ + assert(offset < 16); + m_bl = (data >> 4) & 15; // BL on the data bus most significant bits + if (offset & 1) { + // SOS command + if (data & (1 << 3)) { + m_line[m_bl] = 1; // enable output +// if (m_enable) + m_iowr(m_bl, 1, 1); + } else { + m_line[m_bl] = 0; // disable output +// if (m_enable) + m_iowr(m_bl, 0, 1); + } + } else { + // SES command + if (data & (1 << 3)) { + // enable all outputs + m_enable = true; + for (int i = 0; i < 16; i++) + m_iowr(i, m_line[i], 1); + } else { + // disable all outputs + m_enable = false; + } + } +} + + +READ8_MEMBER( ra17xx_device::io_r ) +{ + assert(offset < 16); + return (m_iord(m_bl) & 1) ? 0x0f : 0x07; +} diff --git a/src/devices/machine/ra17xx.h b/src/devices/machine/ra17xx.h new file mode 100644 index 00000000000..3ca8877d7de --- /dev/null +++ b/src/devices/machine/ra17xx.h @@ -0,0 +1,58 @@ +// license:BSD-3-Clause +// copyright-holders:Juergen Buchmueller +/********************************************************************** + + Rockwell RA17xx (e.g. A1752, A1753) ROM, RAM and I/O chip + + Juergen Buchmueller + + The device integrates a 2048 x 8 ROM, a 128 x 4 RAM and + and 16 I/O ports at one of the port ranges 00 ... 0f, + 20 ... 2f, 40 ... 4f or 60 ... 6f. + +**********************************************************************/ + +#ifndef __RA17XX_H__ +#define __RA17XX_H__ + +#include "device.h" + +/************************************* + * + * Device configuration macros + * + *************************************/ + +/* Set the read line handler */ +#define MCFG_RA17XX_READ(_devcb) \ + ra17xx_device::set_iord(*device, DEVCB_##_devcb); +/* Set the write line handler */ +#define MCFG_RA17XX_WRITE(_devcb) \ + ra17xx_device::set_iowr(*device, DEVCB_##_devcb); +class ra17xx_device : public device_t +{ +public: + ra17xx_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + ~ra17xx_device() {} + + DECLARE_READ8_MEMBER ( io_r ); + DECLARE_WRITE8_MEMBER( io_w ); + + template static devcb_base &set_iord(device_t &device, _Object object) { return downcast(device).m_iord.set_callback(object); } + template static devcb_base &set_iowr(device_t &device, _Object object) { return downcast(device).m_iowr.set_callback(object); } +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + +private: + UINT8 m_line[16]; //!< input/output flip-flops for 16 I/O lines + UINT8 m_bl; //!< value of BL during the most recent output + bool m_enable; //!< true if outputs are enabled + devcb_read8 m_iord; //!< input line (read, offset = line, data = 0/1) + devcb_write8 m_iowr; //!< output line (write, offset = line, data = 0/1) +}; + +extern const device_type RA17XX; + +#endif /* __RA17XX_H__ */ diff --git a/src/devices/machine/ram.c b/src/devices/machine/ram.c new file mode 100644 index 00000000000..3a92aa48c1b --- /dev/null +++ b/src/devices/machine/ram.c @@ -0,0 +1,222 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best +/************************************************************************* + + RAM device + + Provides a configurable amount of RAM to drivers + +**************************************************************************/ + +#include +#include + +#include "emu.h" +#include "emuopts.h" +#include "ram.h" + + +/***************************************************************************** + LIVE DEVICE +*****************************************************************************/ + +// device type definition +const device_type RAM = &device_creator; + + + +//------------------------------------------------- +// ram_device - constructor +//------------------------------------------------- + +ram_device::ram_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, RAM, "RAM", tag, owner, clock, "ram", __FILE__) +{ + m_size = 0; + m_default_size = NULL; + m_extra_options = NULL; + m_default_value = 0xCD; +} + + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void ram_device::device_start() +{ + /* the device named 'ram' can get ram options from command line */ + m_size = 0; + if (strcmp(tag(), ":" RAM_TAG) == 0) + { + const char *ramsize_string = machine().options().ram_size(); + if ((ramsize_string != NULL) && (ramsize_string[0] != '\0')) + m_size = parse_string(ramsize_string); + } + + /* if we didn't get a size yet, use the default */ + if (m_size == 0) + m_size = default_size(); + + /* allocate space for the ram */ + m_pointer.resize(m_size); + memset(&m_pointer[0], m_default_value, m_size); + + /* register for state saving */ + save_item(NAME(m_size)); + save_item(NAME(m_pointer)); +} + + +//------------------------------------------------- +// device_validity_check - device-specific validity +// checks +//------------------------------------------------- + +void ram_device::device_validity_check(validity_checker &valid) const +{ + const char *ramsize_string = NULL; + int is_valid = FALSE; + UINT32 specified_ram = 0; + const char *gamename_option = NULL; + + /* verify default ram value */ + if (default_size() == 0) + osd_printf_error("Invalid default RAM option: %s\n", m_default_size); + + /* command line options are only parsed for the device named RAM_TAG */ + if (tag() != NULL && strcmp(tag(), ":" RAM_TAG) == 0) + { + /* verify command line ram option */ + ramsize_string = mconfig().options().ram_size(); + gamename_option = mconfig().options().system_name(); + + if ((ramsize_string != NULL) && (ramsize_string[0] != '\0')) + { + specified_ram = parse_string(ramsize_string); + + if (specified_ram == 0) + osd_printf_error("Cannot recognize the RAM option %s\n", ramsize_string); + + if (gamename_option != NULL && *gamename_option != 0 && strcmp(gamename_option, mconfig().gamedrv().name) == 0) + { + /* compare command line option to default value */ + if (default_size() == specified_ram) + is_valid = TRUE; + + /* verify extra ram options */ + if (m_extra_options != NULL) + { + int j; + int size = strlen(m_extra_options); + char * const s = core_strdup(m_extra_options); + char * const e = s + size; + char *p = s; + for (j=0;j(device).m_default_size = default_size; } + static void static_set_extra_options(device_t &device, const char *extra_options) { downcast(device).m_extra_options = extra_options; } + static void static_set_default_value(device_t &device, UINT8 default_value) { downcast(device).m_default_value = default_value; } + +protected: + virtual void device_start(void); + virtual void device_validity_check(validity_checker &valid) const; + +private: + // device state + UINT32 m_size; + dynamic_buffer m_pointer; + + // device config + const char *m_default_size; + const char *m_extra_options; + UINT8 m_default_value; +}; + + +// device type definition +extern const device_type RAM; + +// device iterator +typedef device_type_iterator<&device_creator, ram_device> ram_device_iterator; + +#endif /* __RAM_H__ */ diff --git a/src/devices/machine/rescap.h b/src/devices/machine/rescap.h new file mode 100644 index 00000000000..23e4b9f4329 --- /dev/null +++ b/src/devices/machine/rescap.h @@ -0,0 +1,29 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +#ifndef RC_MACROS_H +#define RC_MACROS_H + +/* Little helpers for magnitude conversions */ +#define RES_R(res) ((double)(res)) +#define RES_K(res) ((double)(res) * 1e3) +#define RES_M(res) ((double)(res) * 1e6) +#define RES_INF (-1) +#define CAP_U(cap) ((double)(cap) * 1e-6) +#define CAP_N(cap) ((double)(cap) * 1e-9) +#define CAP_P(cap) ((double)(cap) * 1e-12) +#define IND_U(ind) ((double)(ind) * 1e-6) +#define IND_N(ind) ((double)(ind) * 1e-9) +#define IND_P(ind) ((double)(ind) * 1e-12) + +/* vin --/\r1/\-- out --/\r2/\-- gnd */ +#define RES_VOLTAGE_DIVIDER(r1, r2) ((double)(r2) / ((double)(r1) + (double)(r2))) + +#define RES_2_PARALLEL(r1, r2) (((r1) * (r2)) / ((r1) + (r2))) +#define RES_3_PARALLEL(r1, r2, r3) (1.0 / (1.0 / (r1) + 1.0 / (r2) + 1.0 / (r3))) +#define RES_4_PARALLEL(r1, r2, r3, r4) (1.0 / (1.0 / (r1) + 1.0 / (r2) + 1.0 / (r3) + 1.0 / (r4))) +#define RES_5_PARALLEL(r1, r2, r3, r4, r5) (1.0 / (1.0 / (r1) + 1.0 / (r2) + 1.0 / (r3) + 1.0 / (r4) + 1.0 / (r5))) +#define RES_6_PARALLEL(r1, r2, r3, r4, r5, r6) (1.0 / (1.0 / (r1) + 1.0 / (r2) + 1.0 / (r3) + 1.0 / (r4) + 1.0 / (r5) + 1.0 / (r6))) + +#define RES_2_SERIAL(r1,r2) ((r1)+(r2)) + +#endif diff --git a/src/devices/machine/rf5c296.c b/src/devices/machine/rf5c296.c new file mode 100644 index 00000000000..72fea9ede66 --- /dev/null +++ b/src/devices/machine/rf5c296.c @@ -0,0 +1,113 @@ +// license:BSD-3-Clause +// copyright-holders:smf +#include "rf5c296.h" + +// rf5c296 is very inaccurate at that point, it hardcodes the gnet config + +const device_type RF5C296 = &device_creator; + +rf5c296_device::rf5c296_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, PCCARD_SLOT, "PCCARD SLOT", tag, owner, clock, "pccard", __FILE__) +{ +} + +void rf5c296_device::device_start() +{ + m_pccard = machine().device(m_pccard_name); +} + +void rf5c296_device::reg_w(ATTR_UNUSED UINT8 reg, UINT8 data) +{ + // fprintf(stderr, "rf5c296_reg_w %02x, %02x (%s)\n", reg, data, machine().describe_context()); + switch (reg) + { + // Interrupt and General Control Register + case 0x03: + // Check for card reset + if (!(data & 0x40)) + { + m_pccard->reset(); + } + break; + + default: + break; + } +} + +UINT8 rf5c296_device::reg_r(ATTR_UNUSED UINT8 reg) +{ + // fprintf(stderr, "rf5c296_reg_r %02x (%s)\n", reg, machine().describe_context()); + return 0x00; +} + +WRITE16_MEMBER(rf5c296_device::io_w) +{ + /// TODO: find out if this should be done here. + offset *= 2; + if (mem_mask == 0xff00) + { + mem_mask >>= 8; + data >>= 8; + offset++; + } + + switch(offset) + { + case 0x3e0: + m_rf5c296_reg = data; + break; + + case 0x3e1: + reg_w(m_rf5c296_reg, data); + break; + + default: + m_pccard->write_memory(space, offset, data, mem_mask); + break; + } +} + +READ16_MEMBER(rf5c296_device::io_r) +{ + /// TODO: find out if this should be done here. + offset *= 2; + int shift = 0; + if (mem_mask == 0xff00) + { + shift = 8; + mem_mask >>= 8; + offset++; + } + + UINT16 data; + + switch( offset ) + { + case 0x3e0: + data = m_rf5c296_reg; + break; + + case 0x3e1: + data = reg_r(m_rf5c296_reg); + break; + + default: + data = m_pccard->read_memory(space, offset, mem_mask); + break; + } + + return data << shift; +} + +// Hardcoded to reach the pcmcia CIS + +READ16_MEMBER(rf5c296_device::mem_r) +{ + return m_pccard->read_reg(space, offset, mem_mask); +} + +WRITE16_MEMBER(rf5c296_device::mem_w) +{ + m_pccard->write_reg(space, offset, data, mem_mask); +} diff --git a/src/devices/machine/rf5c296.h b/src/devices/machine/rf5c296.h new file mode 100644 index 00000000000..61556b677b7 --- /dev/null +++ b/src/devices/machine/rf5c296.h @@ -0,0 +1,42 @@ +// license:BSD-3-Clause +// copyright-holders:smf +#pragma once + +#ifndef __RF5C296_H__ +#define __RF5C296_H__ + +#include "pccard.h" + +#define MCFG_RF5C296_SLOT(name) \ + rf5c296_device::set_pccard_name(*device, name); + +class rf5c296_device : public device_t +{ +public: + rf5c296_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // static configuration helpers + static void set_pccard_name(device_t &device, const char *name) { downcast(device).m_pccard_name = name; } + + DECLARE_WRITE16_MEMBER(io_w); + DECLARE_READ16_MEMBER(io_r); + DECLARE_READ16_MEMBER(mem_r); + DECLARE_WRITE16_MEMBER(mem_w); + +protected: + // device-level overrides + virtual void device_start(); + +private: + private: + void reg_w(ATTR_UNUSED UINT8 reg, UINT8 data); + UINT8 reg_r(ATTR_UNUSED UINT8 reg); + + unsigned char m_rf5c296_reg; + pccard_slot_device *m_pccard; + const char *m_pccard_name; +}; + +extern const device_type RF5C296; + +#endif diff --git a/src/devices/machine/roc10937.c b/src/devices/machine/roc10937.c new file mode 100644 index 00000000000..fbfda7ce0e8 --- /dev/null +++ b/src/devices/machine/roc10937.c @@ -0,0 +1,388 @@ +// license:BSD-3-Clause +// copyright-holders:James Wallace +/********************************************************************** + + Rockwell 10937/10957 interface and emulation by J.Wallace + OKI MSC1937 is a clone of this chip + +**********************************************************************/ + +#include "emu.h" +#include "roc10937.h" + +/* + Rockwell 10937 16 segment charset lookup table + 0 1 + ---- ---- + |\ | /| + 7 | \F |8 /9| 2 + | \ | / | + -E-- --A- + | / | \ | + 6 | /D |C \B| 3 + |/ | \| + ---- ---- .11 + 5 4 ,10 + +In 14 segment mode, 0 represents the whole top line, +and 5 the bottom line, allowing both modes to share +a charset. + +Note that, although we call this a '16 segment' display, +we actually have 18 segments, including the semicolon portions. +16-bit tables are used to hold the main characters, the rest are OR'd in +*/ + +static const UINT16 roc10937charset[]= +{ // FEDC BA98 7654 3210 + 0x507F, // 0101 0000 0111 1111 @. + 0x44CF, // 0100 0100 1100 1111 A. + 0x153F, // 0001 0101 0011 1111 B. + 0x00F3, // 0000 0000 1111 0011 C. + 0x113F, // 0001 0001 0011 1111 D. + 0x40F3, // 0100 0000 1111 0011 E. + 0x40C3, // 0100 0000 1100 0011 F. + 0x04FB, // 0000 0100 1111 1011 G. + 0x44CC, // 0100 0100 1100 1100 H. + 0x1133, // 0001 0001 0011 0011 I. + 0x007C, // 0000 0000 0111 1100 J. + 0x4AC0, // 0100 1010 1100 0000 K. + 0x00F0, // 0000 0000 1111 0000 L. + 0x82CC, // 1000 0010 1100 1100 M. + 0x88CC, // 1000 1000 1100 1100 N. + 0x00FF, // 0000 0000 1111 1111 O. + 0x44C7, // 0100 0100 1100 0111 P. + 0x08FF, // 0000 1000 1111 1111 Q. + 0x4CC7, // 0100 1100 1100 0111 R. + 0x44BB, // 0100 0100 1011 1011 S. + 0x1103, // 0001 0001 0000 0011 T. + 0x00FC, // 0000 0000 1111 1100 U. + 0x22C0, // 0010 0010 1100 0000 V. + 0x28CC, // 0010 1000 1100 1100 W. + 0xAA00, // 1010 1010 0000 0000 X. + 0x9200, // 1001 0010 0000 0000 Y. + 0x2233, // 0010 0010 0011 0011 Z. + 0x00E1, // 0000 0000 1110 0001 [. + 0x8800, // 1000 1000 0000 0000 \. + 0x001E, // 0000 0000 0001 1110 ]. + 0x2800, // 0010 1000 0000 0000 ^. + 0x0030, // 0000 0000 0011 0000 _. + 0x0000, // 0000 0000 0000 0000 dummy. + 0x8121, // 1000 0001 0010 0001 !. + 0x0180, // 0000 0001 1000 0000 ". + 0x553C, // 0101 0101 0011 1100 #. + 0x55BB, // 0101 0101 1011 1011 $. + 0x7799, // 0111 0111 1001 1001 %. + 0xC979, // 1100 1001 0111 1001 &. + 0x0200, // 0000 0010 0000 0000 '. + 0x0A00, // 0000 1010 0000 0000 (. + 0xA050, // 1010 0000 0000 0000 ). + 0xFF00, // 1111 1111 0000 0000 *. + 0x5500, // 0101 0101 0000 0000 +. + 0x0000, // 0000 0000 0000 0000 ;. (Set separately) + 0x4400, // 0100 0100 0000 0000 --. + 0x0000, // 0000 0000 0000 0000 . .(Set separately) + 0x2200, // 0010 0010 0000 0000 /. + 0x22FF, // 0010 0010 1111 1111 0. + 0x1100, // 0001 0001 0000 0000 1. + 0x4477, // 0100 0100 0111 0111 2. + 0x443F, // 0100 0100 0011 1111 3. + 0x448C, // 0100 0100 1000 1100 4. + 0x44BB, // 0100 0100 1011 1011 5. + 0x44FB, // 0100 0100 1111 1011 6. + 0x000F, // 0000 0000 0000 1111 7. + 0x44FF, // 0100 0100 1111 1111 8. + 0x44BF, // 0100 0100 1011 1111 9. + 0x0021, // 0000 0000 0010 0001 - + // -. + 0x2001, // 0010 0000 0000 0001 - + // /. + 0x2230, // 0010 0010 0011 0000 <. + 0x4430, // 0100 0100 0011 0000 =. + 0x8830, // 1000 1000 0011 0000 >. + 0x1407, // 0001 0100 0000 0111 ?. +}; + + +/////////////////////////////////////////////////////////////////////////// +static const int roc10937poslut[]= +{ + 1,//0 + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 0//15 +}; + +const device_type ROC10937 = &device_creator; + +rocvfd_t::rocvfd_t(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source) +{ + m_port_val=0; +} + + +void rocvfd_t::static_set_value(device_t &device, int val) +{ + rocvfd_t &roc = downcast(device); + roc.m_port_val = val; +} + +void rocvfd_t::device_start() +{ + save_item(NAME(m_port_val)); + save_item(NAME(m_cursor_pos)); + save_item(NAME(m_window_size)); + save_item(NAME(m_shift_count)); + save_item(NAME(m_shift_data)); + save_item(NAME(m_pcursor_pos)); + save_item(NAME(m_chars)); + save_item(NAME(m_outputs)); + save_item(NAME(m_brightness)); + save_item(NAME(m_count)); + save_item(NAME(m_sclk)); + save_item(NAME(m_data)); + save_item(NAME(m_duty)); + save_item(NAME(m_disp)); + + + device_reset(); +} + +void rocvfd_t::device_reset() +{ + m_cursor_pos = 0; + m_window_size = 16; + m_shift_count = 0; + m_shift_data = 0; + m_pcursor_pos = 0; + m_brightness =31; + m_count=0; + m_duty=31; + m_disp = 0; + m_sclk = 0; + m_data = 0; + + memset(m_chars, 0, sizeof(m_chars)); + memset(m_outputs, 0, sizeof(m_outputs)); +} + +/////////////////////////////////////////////////////////////////////////// +UINT32 rocvfd_t::set_display(UINT32 segin) +{ + return BITSWAP32(segin, 31,30,29,28,27,26,25,24,23,22,21,20,19,18,17,16,11,9,15,13,12,8,10,14,7,6,5,4,3,2,1,0); + +} + +/////////////////////////////////////////////////////////////////////////// +void rocvfd_t::device_post_load() +{ + update_display(); +} + +void rocvfd_t::update_display() +{ + for (int i =0; i<16; i++) + { + m_outputs[i] = set_display(m_chars[i]); + output_set_indexed_value("vfd", (m_port_val*16) + i, m_outputs[i]); + } +} + +WRITE_LINE_MEMBER( rocvfd_t::sclk ) +{ + shift_clock(state); +} + +WRITE_LINE_MEMBER( rocvfd_t::data ) +{ + m_data = state; +} + +WRITE_LINE_MEMBER( rocvfd_t::por ) +{ + //If line goes low, reset mode is engaged, until such a time as it goes high again. + if (!state) + { + reset(); + } +} + + +void rocvfd_t::shift_clock(int state) +{ + if (m_sclk != state) + { + //Clock data on FALLING edge + if (!m_sclk) + { + m_shift_data <<= 1; + + if ( m_data ) m_shift_data |= 1; + + if ( ++m_shift_count >= 8 ) + { + write_char(m_shift_data); + m_shift_count = 0; + m_shift_data = 0; + } + update_display(); + + } + } + m_sclk = state; +} + +/////////////////////////////////////////////////////////////////////////// +roc10937_t::roc10937_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : rocvfd_t(mconfig, ROC10937, "Rockwell 10937 VFD controller and compatible", tag, owner, clock, "roc10937", __FILE__) +{ + m_port_val=0; +} + +const device_type MSC1937 = &device_creator; + +msc1937_t::msc1937_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : rocvfd_t(mconfig, MSC1937, "OKI MSC1937 VFD controller", tag, owner, clock, "msc1937", __FILE__) +{ + m_port_val=0; +} + +void rocvfd_t::write_char(int data) +{ + if ( data & 0x80 ) + { // Control data received + if ( (data & 0xF0) == 0xA0 ) // 1010 xxxx + { // 1 010 xxxx Buffer Pointer control + m_cursor_pos = roc10937poslut[data & 0x0F]; + } + else if ( (data & 0xF0) == 0xC0 ) // 1100 xxxx + { // 1100 xxxx Set number of digits + data &= 0x0F; + + if ( data == 0 ) m_window_size = 16; + else m_window_size = data; + } + else if ( (data & 0xE0) == 0xE0 ) // 111x xxxx + { // 111x xxxx Set duty cycle ( brightness ) + m_brightness = (data & 0x1F); + } + else if ( (data & 0xE0) == 0x80 ) // 100x --- + { // 100x xxxx Test mode + m_duty =4; + } + } + else + { // Display data +// data &= 0x3F; + + switch ( data ) + { + case 0x2C: // ; + m_chars[m_pcursor_pos] |= (1<<16);//. + m_chars[m_pcursor_pos] |= (1<<17);//, + break; + case 0x2E: // + m_chars[m_pcursor_pos] |= (1<<16);//. + break; + default : + m_pcursor_pos = m_cursor_pos; + m_chars[m_cursor_pos] = roc10937charset[data & 0x3F]; + + m_cursor_pos++; + if ( m_cursor_pos > (m_window_size -1) ) + { + m_cursor_pos = 0; + } + break; + } + } +} + +const device_type ROC10957 = &device_creator; + +roc10957_t::roc10957_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : rocvfd_t(mconfig, ROC10957, "Rockwell 10957 VFD controller and compatible", tag, owner, clock, "roc10957", __FILE__) +{ + m_port_val=0; +} + +void roc10957_t::write_char(int data) +{ + if ( data & 0x80 ) + { // Control data received + if ( (data & 0xF0) == 0xA0 ) // 1010 xxxx + { // 1 010 xxxx Buffer Pointer control + m_cursor_pos = roc10937poslut[data & 0x0F]; + } + else if ( (data & 0xF0) == 0xC0 ) // 1100 xxxx + { // 1100 xxxx Set number of digits + data &= 0x0F; + + if ( data == 0 ) m_window_size = 16; + else m_window_size = data; + } + else if ( (data & 0xE0) == 0xE0 ) // 111x xxxx + { // 111x xxxx Set duty cycle ( brightness ) + m_brightness = (data & 0x1F); + } + else if ( (data & 0xE0) == 0x80 ) // 100x --- + { // 100x xxxx Test mode + popmessage("TEST MODE ENABLED!"); + m_duty = 4; + } + } + else + { // Display data + data &= 0x3F; + + switch ( data ) + { + case 0x2C: // ; + m_chars[m_pcursor_pos] |= (1<<16);//. + m_chars[m_pcursor_pos] |= (1<<17);//, + break; + case 0x2E: // + m_chars[m_pcursor_pos] |= (1<<16);//. + break; + case 0x6C: // ; + m_chars[m_pcursor_pos] |= (1<<16);//. + break; + case 0x6E: // + { + m_chars[m_pcursor_pos] = 0; + } + break; + default : + m_pcursor_pos = m_cursor_pos; + m_chars[m_cursor_pos] = roc10937charset[data & 0x3F]; + + m_cursor_pos++; + if ( m_cursor_pos > (m_window_size -1) ) + { + m_cursor_pos = 0; + } + break; + } + } +} + +const device_type S16LF01 = &device_creator; + +s16lf01_t::s16lf01_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : rocvfd_t(mconfig, S16LF01, "Samsung 16LF01 Series VFD controller and compatible", tag, owner, clock, "s16lf01", __FILE__) +{ + m_port_val=0; +} diff --git a/src/devices/machine/roc10937.h b/src/devices/machine/roc10937.h new file mode 100644 index 00000000000..9aee3bf6997 --- /dev/null +++ b/src/devices/machine/roc10937.h @@ -0,0 +1,128 @@ +// license:BSD-3-Clause +// copyright-holders:James Wallace +/********************************************************************** + + Rockwell 10937/10957 interface and simlar chips + Emulation by J.Wallace + OKI MSC1937 is a clone of this chip, with many others. + +**********************************************************************/ +#pragma once + +#ifndef ROC10937_H +#define ROC10937_H + +#define MCFG_ROC10937_ADD(_tag,_val) \ + MCFG_DEVICE_ADD(_tag, ROC10937,60)\ + MCFG_ROC10937_PORT(_val) + +#define MCFG_ROC10937_PORT(_val) \ + roc10937_t::static_set_value(*device, _val); +#define MCFG_ROC10937_REMOVE(_tag) \ + MCFG_DEVICE_REMOVE(_tag) + +#define MCFG_ROC10957_ADD(_tag,_val) \ + MCFG_DEVICE_ADD(_tag, ROC10957,60)\ + MCFG_ROC10957_PORT(_val) + +#define MCFG_ROC10957_PORT(_val) \ + roc10957_t::static_set_value(*device, _val); +#define MCFG_ROC10957_REMOVE(_tag) \ + MCFG_DEVICE_REMOVE(_tag) + +#define MCFG_MSC1937_ADD(_tag,_val) \ + MCFG_DEVICE_ADD(_tag, ROC10937,60)\ + MCFG_MSC1937_PORT(_val) + +#define MCFG_MSC1937_PORT(_val) \ + MCFG_ROC10937_PORT(_val) + +#define MCFG_MSC1937_REMOVE(_tag) \ + MCFG_DEVICE_REMOVE(_tag) + +#define MCFG_S16LF01_ADD(_tag,_val) \ + MCFG_DEVICE_ADD(_tag, S16LF01,60)\ + MCFG_S16LF01_PORT(_val) + +#define MCFG_S16LF01_PORT(_val) \ + MCFG_ROC10937_PORT(_val) + +class rocvfd_t : public device_t { +public: + rocvfd_t(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + // inline configuration helpers + static void static_set_value(device_t &device, int val); + virtual void update_display(); + UINT8 m_port_val; + void blank(int data); + void shift_clock(int data); + void write_char(int data); + void setdata(int segdata, int data); + UINT32 set_display(UINT32 segin); + DECLARE_WRITE_LINE_MEMBER( sclk ); + DECLARE_WRITE_LINE_MEMBER( data ); + DECLARE_WRITE_LINE_MEMBER( por ); + + +protected: + int m_cursor_pos; + int m_window_size; // window size + int m_shift_count; + int m_shift_data; + int m_pcursor_pos; + int m_brightness; + int m_count; + int m_data; + int m_duty; + int m_disp; + int m_sclk; + UINT8 m_cursor; + UINT32 m_chars[16]; + UINT32 m_outputs[16]; + + virtual void device_start(); + virtual void device_reset(); + virtual void device_post_load(); +}; + + +class roc10937_t : public rocvfd_t { +public: + roc10937_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + +}; + +class msc1937_t : public rocvfd_t { +public: + msc1937_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + +}; + +class roc10957_t : public rocvfd_t { +public: + roc10957_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + void write_char(int data); + +protected: + +}; + +class s16lf01_t : public rocvfd_t { +public: + s16lf01_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +protected: + +}; + +extern const device_type ROC10937; +extern const device_type MSC1937; +extern const device_type ROC10957; +extern const device_type S16LF01; + +#endif diff --git a/src/devices/machine/rp5c01.c b/src/devices/machine/rp5c01.c new file mode 100644 index 00000000000..5ac56b4b415 --- /dev/null +++ b/src/devices/machine/rp5c01.c @@ -0,0 +1,428 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Ricoh RP5C01(A) Real Time Clock With Internal RAM emulation + +*********************************************************************/ + +/* + + TODO: + + - 12 hour clock + - test register + - timer reset + +*/ + +#include "rp5c01.h" + + +// device type definition +const device_type RP5C01 = &device_creator; + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define LOG 0 + + +#define RAM_SIZE 13 + + +// registers +enum +{ + REGISTER_1_SECOND = 0, + REGISTER_10_SECOND, + REGISTER_1_MINUTE, + REGISTER_10_MINUTE, + REGISTER_1_HOUR, + REGISTER_10_HOUR, + REGISTER_DAY_OF_THE_WEEK, + REGISTER_1_DAY, + REGISTER_10_DAY, + REGISTER_1_MONTH, + REGISTER_10_MONTH, REGISTER_12_24_SELECT = REGISTER_10_MONTH, + REGISTER_1_YEAR, REGISTER_LEAP_YEAR = REGISTER_1_YEAR, + REGISTER_10_YEAR, + REGISTER_MODE, + REGISTER_TEST, + REGISTER_RESET +}; + + +// register write mask +static const int register_write_mask[2][16] = +{ + { 0xf, 0x7, 0xf, 0x7, 0xf, 0x3, 0x7, 0xf, 0x3, 0xf, 0x1, 0xf, 0xf, 0xf, 0xf, 0xf }, + { 0x0, 0x0, 0xf, 0x7, 0xf, 0x3, 0x7, 0xf, 0x3, 0x0, 0x1, 0x3, 0x0, 0xf, 0xf, 0xf } +}; + + +// modes +enum +{ + MODE00 = 0, + MODE01, + BLOCK10, + BLOCK11 +}; + + +// mode register +#define MODE_MASK 0x03 +#define MODE_ALARM_EN 0x04 +#define MODE_TIMER_EN 0x08 + + +// test register +#define TEST_0 0x01 +#define TEST_1 0x02 +#define TEST_2 0x04 +#define TEST_3 0x08 + + +// reset register +#define RESET_ALARM 0x01 +#define RESET_TIMER 0x02 +#define RESET_16_HZ 0x04 +#define RESET_1_HZ 0x08 + + + +//************************************************************************** +// INLINE HELPERS +//************************************************************************** + +//------------------------------------------------- +// set_alarm_line - +//------------------------------------------------- + +inline void rp5c01_device::set_alarm_line() +{ + int alarm = ((m_mode & MODE_ALARM_EN) ? m_alarm_on : 1) & + ((m_reset & RESET_16_HZ) ? 1 : m_16hz) & + ((m_reset & RESET_1_HZ) ? 1 : m_1hz); + + if (m_alarm != alarm) + { + if (LOG) logerror("RP5C01 '%s' Alarm %u\n", tag(), alarm); + + m_out_alarm_cb(alarm); + m_alarm = alarm; + } +} + + +//------------------------------------------------- +// read_counter - +//------------------------------------------------- + +inline int rp5c01_device::read_counter(int counter) +{ + return (m_reg[MODE00][counter + 1] * 10) + m_reg[MODE00][counter]; +} + + +//------------------------------------------------- +// write_counter - +//------------------------------------------------- + +inline void rp5c01_device::write_counter(int counter, int value) +{ + m_reg[MODE00][counter] = value % 10; + m_reg[MODE00][counter + 1] = value / 10; +} + + +//------------------------------------------------- +// check_alarm - +//------------------------------------------------- + +inline void rp5c01_device::check_alarm() +{ + bool all_match = true; + bool all_zeroes = true; + + for (int i = REGISTER_1_MINUTE; i < REGISTER_1_MONTH; i++) + { + if (m_reg[MODE01][i] != 0) all_zeroes = false; + if (m_reg[MODE01][i] != m_reg[MODE00][i]) all_match = false; + } + + m_alarm_on = (all_match || (!m_alarm_on && all_zeroes)) ? 0 : 1; +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// rp5c01_device - constructor +//------------------------------------------------- + +rp5c01_device::rp5c01_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, RP5C01, "RP5C01", tag, owner, clock, "rp5c01", __FILE__), + device_rtc_interface(mconfig, *this), + device_nvram_interface(mconfig, *this), + m_out_alarm_cb(*this), + m_battery_backed(true), + m_mode(0), + m_reset(0), + m_alarm(1), + m_alarm_on(1), + m_1hz(1), + m_16hz(1) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void rp5c01_device::device_start() +{ + // resolve callbacks + m_out_alarm_cb.resolve_safe(); + + // allocate timers + if (clock() > 0) + { + m_clock_timer = timer_alloc(TIMER_CLOCK); + m_clock_timer->adjust(attotime::from_hz(clock() / 16384), 0, attotime::from_hz(clock() / 16384)); + + m_16hz_timer = timer_alloc(TIMER_16HZ); + m_16hz_timer->adjust(attotime::from_hz(clock() / 1024), 0, attotime::from_hz(clock() / 1024)); + } + + // state saving + save_item(NAME(m_reg[MODE00])); + save_item(NAME(m_reg[MODE01])); + save_item(NAME(m_mode)); + save_item(NAME(m_reset)); + save_item(NAME(m_alarm)); + save_item(NAME(m_alarm_on)); + save_item(NAME(m_1hz)); + save_item(NAME(m_16hz)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void rp5c01_device::device_reset() +{ + memset(m_reg, 0, sizeof(m_reg)); + memset(m_ram, 0, sizeof(m_ram)); + + // 24 hour mode + m_reg[MODE01][REGISTER_12_24_SELECT] = 1; + + if (m_battery_backed && clock() > 0) + set_current_time(machine()); +} + + +//------------------------------------------------- +// device_timer - handler timer events +//------------------------------------------------- + +void rp5c01_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch (id) + { + case TIMER_CLOCK: + if (m_1hz && (m_mode & MODE_TIMER_EN)) + { + advance_seconds(); + } + + m_1hz = !m_1hz; + set_alarm_line(); + break; + + case TIMER_16HZ: + m_16hz = !m_16hz; + set_alarm_line(); + break; + } +} + + +//------------------------------------------------- +// rtc_clock_updated - +//------------------------------------------------- + +void rp5c01_device::rtc_clock_updated(int year, int month, int day, int day_of_week, int hour, int minute, int second) +{ + m_reg[MODE01][REGISTER_LEAP_YEAR] = year % 4; + write_counter(REGISTER_1_YEAR, year); + write_counter(REGISTER_1_MONTH, month); + write_counter(REGISTER_1_DAY, day); + m_reg[MODE00][REGISTER_DAY_OF_THE_WEEK] = day_of_week; + write_counter(REGISTER_1_HOUR, hour); + write_counter(REGISTER_1_MINUTE, minute); + write_counter(REGISTER_1_SECOND, second); + + check_alarm(); + set_alarm_line(); +} + + +//------------------------------------------------- +// nvram_default - called to initialize NVRAM to +// its default state +//------------------------------------------------- + +void rp5c01_device::nvram_default() +{ +} + + +//------------------------------------------------- +// nvram_read - called to read NVRAM from the +// .nv file +//------------------------------------------------- + +void rp5c01_device::nvram_read(emu_file &file) +{ + if (m_battery_backed) + file.read(m_ram, RAM_SIZE); +} + + +//------------------------------------------------- +// nvram_write - called to write NVRAM to the +// .nv file +//------------------------------------------------- + +void rp5c01_device::nvram_write(emu_file &file) +{ + if (m_battery_backed) + file.write(m_ram, RAM_SIZE); +} + + +//------------------------------------------------- +// read - +//------------------------------------------------- + +READ8_MEMBER( rp5c01_device::read ) +{ + UINT8 data = 0; + offset &= 0x0f; + + switch (offset) + { + case REGISTER_MODE: + data = m_mode; + break; + + case REGISTER_TEST: + case REGISTER_RESET: + // write only + break; + + default: + switch (m_mode & MODE_MASK) + { + case MODE00: + case MODE01: + data = m_reg[m_mode & MODE_MASK][offset]; + break; + + case BLOCK10: + data = m_ram[offset]; + break; + + case BLOCK11: + data = m_ram[offset] >> 4; + break; + } + break; + } + + if (LOG) logerror("RP5C01 '%s' Register %u Read %02x\n", tag(), offset, data); + + return data & 0x0f; +} + + +//------------------------------------------------- +// write - +//------------------------------------------------- + +WRITE8_MEMBER( rp5c01_device::write ) +{ + data &= 0x0f; + offset &= 0x0f; + + switch (offset) + { + case REGISTER_MODE: + m_mode = data; + + if (LOG) + { + logerror("RP5C01 '%s' Mode %u\n", tag(), data & MODE_MASK); + logerror("RP5C01 '%s' Timer %s\n", tag(), (data & MODE_TIMER_EN) ? "enabled" : "disabled"); + logerror("RP5C01 '%s' Alarm %s\n", tag(), (data & MODE_ALARM_EN) ? "enabled" : "disabled"); + } + break; + + case REGISTER_TEST: + if (LOG) logerror("RP5C01 '%s' Test %u not supported!\n", tag(), data); + break; + + case REGISTER_RESET: + m_reset = data; + + if (data & RESET_ALARM) + { + // reset alarm registers + for (int i = REGISTER_1_MINUTE; i < REGISTER_1_MONTH; i++) + { + m_reg[MODE01][i] = 0; + } + } + + if (LOG) + { + if (data & RESET_ALARM) logerror("RP5C01 '%s' Alarm Reset\n", tag()); + if (data & RESET_TIMER) logerror("RP5C01 '%s' Timer Reset not supported!\n", tag()); + logerror("RP5C01 '%s' 16Hz Signal %s\n", tag(), (data & RESET_16_HZ) ? "disabled" : "enabled"); + logerror("RP5C01 '%s' 1Hz Signal %s\n", tag(), (data & RESET_1_HZ) ? "disabled" : "enabled"); + } + break; + + default: + switch (m_mode & MODE_MASK) + { + case MODE00: + case MODE01: + m_reg[m_mode & MODE_MASK][offset] = data & register_write_mask[m_mode & MODE_MASK][offset]; + + set_time(false, read_counter(REGISTER_1_YEAR), read_counter(REGISTER_1_MONTH), read_counter(REGISTER_1_DAY), m_reg[MODE00][REGISTER_DAY_OF_THE_WEEK], + read_counter(REGISTER_1_HOUR), read_counter(REGISTER_1_MINUTE), read_counter(REGISTER_1_SECOND)); + break; + + case BLOCK10: + m_ram[offset] = (m_ram[offset] & 0xf0) | data; + break; + + case BLOCK11: + m_ram[offset] = (data << 4) | (m_ram[offset] & 0x0f); + break; + } + + if (LOG) logerror("RP5C01 '%s' Register %u Write %02x\n", tag(), offset, data); + break; + } +} diff --git a/src/devices/machine/rp5c01.h b/src/devices/machine/rp5c01.h new file mode 100644 index 00000000000..e0283816067 --- /dev/null +++ b/src/devices/machine/rp5c01.h @@ -0,0 +1,112 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Ricoh RP5C01(A) Real Time Clock With Internal RAM emulation + +********************************************************************** + _____ _____ + _CS 1 |* \_/ | 18 Vcc + CS 2 | | 17 OSCOUT + ADJ 3 | | 16 OSCIN + A0 4 | RP5C01 | 15 _ALARM + A1 5 | RP5C01A | 14 D3 + A2 6 | RF5C01A | 13 D2 + A3 7 | TC8521 | 12 D1 + _RD 8 | | 11 D0 + GND 9 |_____________| 10 _WR + +**********************************************************************/ + +#pragma once + +#ifndef __RP5C01__ +#define __RP5C01__ + +#include "emu.h" + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_RP5C01_OUT_ALARM_CB(_devcb) \ + devcb = &rp5c01_device::set_out_alarm_callback(*device, DEVCB_##_devcb); + +// include this macro if the chip is not battery backed +#define MCFG_RP5C01_REMOVE_BATTERY() \ + rp5c01_device::remove_battery(*device); + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> rp5c01_device + +class rp5c01_device : public device_t, + public device_rtc_interface, + public device_nvram_interface +{ +public: + // construction/destruction + rp5c01_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + template static devcb_base &set_out_alarm_callback(device_t &device, _Object object) { return downcast(device).m_out_alarm_cb.set_callback(object); } + static void remove_battery(device_t &device) { downcast(device).m_battery_backed = false; } + + DECLARE_READ8_MEMBER( read ); + DECLARE_WRITE8_MEMBER( write ); + DECLARE_READ_LINE_MEMBER( alarm_r ) { return m_alarm; } + DECLARE_WRITE_LINE_MEMBER( adj_w ) { if (state) adjust_seconds(); } + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + // device_rtc_interface overrides + virtual bool rtc_feature_leap_year() { return true; } + virtual void rtc_clock_updated(int year, int month, int day, int day_of_week, int hour, int minute, int second); + + // device_nvram_interface overrides + virtual void nvram_default(); + virtual void nvram_read(emu_file &file); + virtual void nvram_write(emu_file &file); + +private: + inline void set_alarm_line(); + inline int read_counter(int counter); + inline void write_counter(int counter, int value); + inline void check_alarm(); + + static const device_timer_id TIMER_CLOCK = 0; + static const device_timer_id TIMER_16HZ = 1; + + devcb_write_line m_out_alarm_cb; + bool m_battery_backed; + + UINT8 m_reg[2][13]; // clock registers + UINT8 m_ram[13]; // RAM + + UINT8 m_mode; // mode register + UINT8 m_reset; // reset register + int m_alarm; // alarm output + int m_alarm_on; // alarm condition + int m_1hz; // 1 Hz condition + int m_16hz; // 16 Hz condition + + // timers + emu_timer *m_clock_timer; + emu_timer *m_16hz_timer; +}; + + +// device type definition +extern const device_type RP5C01; + + + +#endif diff --git a/src/devices/machine/rp5c15.c b/src/devices/machine/rp5c15.c new file mode 100644 index 00000000000..7967366c349 --- /dev/null +++ b/src/devices/machine/rp5c15.c @@ -0,0 +1,447 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Ricoh RP5C15 Real Time Clock emulation + +*********************************************************************/ + +/* + + TODO: + + - 12 hour clock + - test register + - timer reset + +*/ + +#include "rp5c15.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define LOG 0 + + +// registers +enum +{ + REGISTER_1_SECOND = 0, REGISTER_CLOCK_OUTPUT = REGISTER_1_SECOND, + REGISTER_10_SECOND, REGISTER_ADJUST = REGISTER_10_SECOND, + REGISTER_1_MINUTE, + REGISTER_10_MINUTE, + REGISTER_1_HOUR, + REGISTER_10_HOUR, + REGISTER_DAY_OF_THE_WEEK, + REGISTER_1_DAY, + REGISTER_10_DAY, + REGISTER_1_MONTH, + REGISTER_10_MONTH, REGISTER_12_24_SELECT = REGISTER_10_MONTH, + REGISTER_1_YEAR, REGISTER_LEAP_YEAR = REGISTER_1_YEAR, + REGISTER_10_YEAR, + REGISTER_MODE, + REGISTER_TEST, + REGISTER_RESET +}; + + +// clock output select +enum +{ + CLKOUT_Z = 0, + CLKOUT_16384_HZ, + CLKOUT_1024_HZ, + CLKOUT_128_HZ, + CLKOUT_16_HZ, + CLKOUT_1_HZ, + CLKOUT_1_DIV_60_HZ, + CLKOUT_L +}; + + +// register write mask +static const int register_write_mask[2][16] = +{ + { 0xf, 0x7, 0xf, 0x7, 0xf, 0x3, 0x7, 0xf, 0x3, 0xf, 0x1, 0xf, 0xf, 0xf, 0xf, 0xf }, + { 0x3, 0x1, 0xf, 0x7, 0xf, 0x3, 0x7, 0xf, 0x3, 0x0, 0x1, 0x3, 0x0, 0xf, 0xf, 0xf } +}; + + +// modes +enum +{ + MODE00 = 0, + MODE01 +}; + + +// mode register +#define MODE_MASK 0x01 +#define MODE_ALARM_EN 0x04 +#define MODE_TIMER_EN 0x08 + + +// test register +#define TEST_0 0x01 +#define TEST_1 0x02 +#define TEST_2 0x04 +#define TEST_3 0x08 + + +// reset register +#define RESET_ALARM 0x01 +#define RESET_TIMER 0x02 +#define RESET_16_HZ 0x04 +#define RESET_1_HZ 0x08 + + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +// devices +const device_type RP5C15 = &device_creator; + + + +//************************************************************************** +// INLINE HELPERS +//************************************************************************** + +//------------------------------------------------- +// set_alarm_line - +//------------------------------------------------- + +inline void rp5c15_device::set_alarm_line() +{ + int alarm = ((m_mode & MODE_ALARM_EN) ? m_alarm_on : 1) & + ((m_reset & RESET_16_HZ) ? 1 : m_16hz) & + ((m_reset & RESET_1_HZ) ? 1 : m_1hz); + + if (m_alarm != alarm) + { + if (LOG) logerror("RP5C15 '%s' Alarm %u\n", tag(), alarm); + + m_out_alarm_cb(alarm); + m_alarm = alarm; + } +} + + +//------------------------------------------------- +// read_counter - +//------------------------------------------------- + +inline int rp5c15_device::read_counter(int counter) +{ + return (m_reg[MODE00][counter + 1] * 10) + m_reg[MODE00][counter]; +} + + +//------------------------------------------------- +// write_counter - +//------------------------------------------------- + +inline void rp5c15_device::write_counter(int counter, int value) +{ + m_reg[MODE00][counter] = value % 10; + m_reg[MODE00][counter + 1] = value / 10; +} + + +//------------------------------------------------- +// check_alarm - +//------------------------------------------------- + +inline void rp5c15_device::check_alarm() +{ + bool all_match = true; + bool all_zeroes = true; + + for (int i = REGISTER_1_MINUTE; i < REGISTER_1_MONTH; i++) + { + if (m_reg[MODE01][i] != 0) all_zeroes = false; + if (m_reg[MODE01][i] != m_reg[MODE00][i]) all_match = false; + } + + m_alarm_on = (all_match || (!m_alarm_on && all_zeroes)) ? 0 : 1; +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// rp5c15_device - constructor +//------------------------------------------------- + +rp5c15_device::rp5c15_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, RP5C15, "RP5C15", tag, owner, clock, "rp5c15", __FILE__), + device_rtc_interface(mconfig, *this), + m_out_alarm_cb(*this), + m_out_clkout_cb(*this), + m_alarm(1), + m_alarm_on(1), + m_1hz(1), + m_16hz(1), + m_clkout(1) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void rp5c15_device::device_start() +{ + // resolve callbacks + m_out_alarm_cb.resolve_safe(); + m_out_clkout_cb.resolve_safe(); + + // allocate timers + m_clock_timer = timer_alloc(TIMER_CLOCK); + m_clock_timer->adjust(attotime::from_hz(clock() / 16384), 0, attotime::from_hz(clock() / 16384)); + + m_16hz_timer = timer_alloc(TIMER_16HZ); + m_16hz_timer->adjust(attotime::from_hz(clock() / 1024), 0, attotime::from_hz(clock() / 1024)); + + m_clkout_timer = timer_alloc(TIMER_CLKOUT); + + memset(m_reg, 0, sizeof(m_reg)); + memset(m_ram, 0, sizeof(m_ram)); + m_mode = 0; + m_reset = 0; + m_alarm = 0; + m_alarm_on = 0; + m_1hz = 0; + m_16hz = 0; + m_clkout = 0; + + // state saving + save_item(NAME(m_reg[MODE00])); + save_item(NAME(m_reg[MODE01])); + save_item(NAME(m_mode)); + save_item(NAME(m_reset)); + save_item(NAME(m_alarm)); + save_item(NAME(m_alarm_on)); + save_item(NAME(m_1hz)); + save_item(NAME(m_16hz)); + save_item(NAME(m_clkout)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void rp5c15_device::device_reset() +{ + set_current_time(machine()); +} + + +//------------------------------------------------- +// device_timer - handler timer events +//------------------------------------------------- + +void rp5c15_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch (id) + { + case TIMER_CLOCK: + if (m_1hz && (m_mode & MODE_TIMER_EN)) + { + advance_seconds(); + } + + m_1hz = !m_1hz; + set_alarm_line(); + break; + + case TIMER_16HZ: + m_16hz = !m_16hz; + set_alarm_line(); + break; + + case TIMER_CLKOUT: + m_clkout = !m_clkout; + m_out_clkout_cb(m_clkout); + break; + } +} + + +//------------------------------------------------- +// rtc_clock_updated - +//------------------------------------------------- + +void rp5c15_device::rtc_clock_updated(int year, int month, int day, int day_of_week, int hour, int minute, int second) +{ + m_reg[MODE01][REGISTER_LEAP_YEAR] = year % 4; + write_counter(REGISTER_1_YEAR, year); + write_counter(REGISTER_1_MONTH, month); + write_counter(REGISTER_1_DAY, day); + m_reg[MODE00][REGISTER_DAY_OF_THE_WEEK] = day_of_week; + write_counter(REGISTER_1_HOUR, hour); + write_counter(REGISTER_1_MINUTE, minute); + write_counter(REGISTER_1_SECOND, second); + + check_alarm(); + set_alarm_line(); +} + + +//------------------------------------------------- +// read - +//------------------------------------------------- + +READ8_MEMBER( rp5c15_device::read ) +{ + UINT8 data = 0; + offset &= 0x0f; + + switch (offset) + { + case REGISTER_MODE: + data = m_mode; + break; + + case REGISTER_TEST: + case REGISTER_RESET: + // write only + break; + + default: + data = m_reg[m_mode & MODE_MASK][offset]; + break; + } + + if (LOG) logerror("RP5C15 '%s' Register %u Read %02x\n", tag(), offset, data); + + return data & 0x0f; +} + + +//------------------------------------------------- +// write - +//------------------------------------------------- + +WRITE8_MEMBER( rp5c15_device::write ) +{ + data &= 0x0f; + offset &= 0x0f; + + switch (offset) + { + case REGISTER_MODE: + m_mode = data; + + if (LOG) + { + logerror("RP5C15 '%s' Mode %u\n", tag(), data & MODE_MASK); + logerror("RP5C15 '%s' Timer %s\n", tag(), (data & MODE_TIMER_EN) ? "enabled" : "disabled"); + logerror("RP5C15 '%s' Alarm %s\n", tag(), (data & MODE_ALARM_EN) ? "enabled" : "disabled"); + } + break; + + case REGISTER_TEST: + if (LOG) logerror("RP5C15 '%s' Test %u not supported!\n", tag(), data); + break; + + case REGISTER_RESET: + m_reset = data; + + if (data & RESET_ALARM) + { + // reset alarm registers + for (int i = REGISTER_1_MINUTE; i < REGISTER_1_MONTH; i++) + { + m_reg[MODE01][i] = 0; + } + } + + if (LOG) + { + if (data & RESET_ALARM) logerror("RP5C15 '%s' Alarm Reset\n", tag()); + if (data & RESET_TIMER) logerror("RP5C15 '%s' Timer Reset not supported!\n", tag()); + logerror("RP5C15 '%s' 16Hz Signal %s\n", tag(), (data & RESET_16_HZ) ? "disabled" : "enabled"); + logerror("RP5C15 '%s' 1Hz Signal %s\n", tag(), (data & RESET_1_HZ) ? "disabled" : "enabled"); + } + break; + + default: + switch (m_mode & MODE_MASK) + { + case MODE00: + m_reg[MODE00][offset] = data & register_write_mask[MODE00][offset]; + + set_time(false, read_counter(REGISTER_1_YEAR), read_counter(REGISTER_1_MONTH), read_counter(REGISTER_1_DAY), m_reg[MODE00][REGISTER_DAY_OF_THE_WEEK], + read_counter(REGISTER_1_HOUR), read_counter(REGISTER_1_MINUTE), read_counter(REGISTER_1_SECOND)); + break; + + case MODE01: + switch (offset) + { + case REGISTER_CLOCK_OUTPUT: + switch (data & 0x07) + { + case CLKOUT_16384_HZ: + m_clkout_timer->adjust(attotime::from_hz(clock()), 0, attotime::from_hz(clock())); + break; + + case CLKOUT_1024_HZ: + m_clkout_timer->adjust(attotime::from_hz(clock() / 16), 0, attotime::from_hz(clock() / 16)); + break; + + case CLKOUT_128_HZ: + m_clkout_timer->adjust(attotime::from_hz(clock() / 128), 0, attotime::from_hz(clock() / 128)); + break; + + case CLKOUT_16_HZ: + m_clkout_timer->adjust(attotime::from_hz(clock() / 1024), 0, attotime::from_hz(clock() / 1024)); + break; + + case CLKOUT_1_HZ: + m_clkout_timer->adjust(attotime::from_hz(clock() / 16384), 0, attotime::from_hz(clock() / 16384)); + break; + + case CLKOUT_1_DIV_60_HZ: + // TODO + break; + + case CLKOUT_L: + case CLKOUT_Z: + m_clkout = 1; + m_clkout_timer->adjust(attotime::zero, 0); + break; + } + + m_reg[MODE01][offset] = data & register_write_mask[MODE01][offset]; + break; + + case REGISTER_ADJUST: + if (data & 0x01) + { + adjust_seconds(); + } + m_reg[MODE01][offset] = data & register_write_mask[MODE01][offset]; + break; + + default: + m_reg[MODE01][offset] = data & register_write_mask[MODE01][offset]; + break; + } + break; + } + + if (LOG) logerror("RP5C15 '%s' Register %u Write %02x\n", tag(), offset, data); + break; + } +} diff --git a/src/devices/machine/rp5c15.h b/src/devices/machine/rp5c15.h new file mode 100644 index 00000000000..2f97d49d99f --- /dev/null +++ b/src/devices/machine/rp5c15.h @@ -0,0 +1,106 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Ricoh RP5C15 Real Time Clock emulation + +********************************************************************** + _____ _____ + _CS 1 |* \_/ | 18 Vcc + CS 2 | | 17 OSCOUT + CLKOUT 3 | | 16 OSCIN + A0 4 | RP5C15 | 15 _ALARM + A1 5 | RF5C15 | 14 D3 + A2 6 | RJ5C15 | 13 D2 + A3 7 | | 12 D1 + _RD 8 | | 11 D0 + GND 9 |_____________| 10 _WR + +**********************************************************************/ + +#pragma once + +#ifndef __RP5C15__ +#define __RP5C15__ + +#include "emu.h" + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_RP5C15_OUT_ALARM_CB(_devcb) \ + devcb = &rp5c15_device::set_out_alarm_callback(*device, DEVCB_##_devcb); + +#define MCFG_RP5C15_OUT_CLKOUT_CB(_devcb) \ + devcb = &rp5c15_device::set_out_clkout_callback(*device, DEVCB_##_devcb); + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> rp5c15_device + +class rp5c15_device : public device_t, + public device_rtc_interface +{ +public: + // construction/destruction + rp5c15_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + template static devcb_base &set_out_alarm_callback(device_t &device, _Object object) { return downcast(device).m_out_alarm_cb.set_callback(object); } + template static devcb_base &set_out_clkout_callback(device_t &device, _Object object) { return downcast(device).m_out_clkout_cb.set_callback(object); } + + DECLARE_READ8_MEMBER( read ); + DECLARE_WRITE8_MEMBER( write ); + DECLARE_WRITE_LINE_MEMBER( adj_w ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + // device_rtc_interface overrides + virtual bool rtc_feature_leap_year() { return true; } + virtual void rtc_clock_updated(int year, int month, int day, int day_of_week, int hour, int minute, int second); + +private: + inline void set_alarm_line(); + inline int read_counter(int counter); + inline void write_counter(int counter, int value); + inline void check_alarm(); + + static const device_timer_id TIMER_CLOCK = 0; + static const device_timer_id TIMER_16HZ = 1; + static const device_timer_id TIMER_CLKOUT = 2; + + devcb_write_line m_out_alarm_cb; + devcb_write_line m_out_clkout_cb; + + UINT8 m_reg[2][13]; // clock registers + UINT8 m_ram[13]; // RAM + + UINT8 m_mode; // mode register + UINT8 m_reset; // reset register + int m_alarm; // alarm output + int m_alarm_on; // alarm condition + int m_1hz; // 1 Hz condition + int m_16hz; // 16 Hz condition + int m_clkout; // clock output + + // timers + emu_timer *m_clock_timer; + emu_timer *m_16hz_timer; + emu_timer *m_clkout_timer; +}; + + +// device type definition +extern const device_type RP5C15; + + + +#endif diff --git a/src/devices/machine/rp5h01.c b/src/devices/machine/rp5h01.c new file mode 100644 index 00000000000..53691cf160f --- /dev/null +++ b/src/devices/machine/rp5h01.c @@ -0,0 +1,201 @@ +// license:BSD-3-Clause +// copyright-holders:Nicola Salmoria +/*************************************************************************** + + RP5H01 - Ricoh 64x1bit(+8bit) PROM with 6/7-bit counter + + In reality, PROM data is 72bits (64 + 8bit 'dummy'). In 7-bit counter mode, + from 64 to 127 (%1000000 to %1111111), the dummy bits are read repeatedly, + with a mask of %1010111. For example if the 8 dummy bits are $7c, + bits 64 to 127 are read as $7c $7c $00 $00 $7c $7c $00 $00. + To simplify this, our emulation expects 'overdumps', 128bits total. + + TODO: + - not sure if the polarity of our PROM dumps (playch10) is correct, + same goes for the bit order (note: does not require new dumps) + +***************************************************************************/ + +#include "emu.h" +#include "machine/rp5h01.h" + +// this is the contents of an unprogrammed PROM +static const UINT8 initial_data[0x10] = +{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00 +}; + +//------------------------------------------------- +// rp5h01_device - constructor +//------------------------------------------------- + +const device_type RP5H01 = &device_creator; + +rp5h01_device::rp5h01_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, RP5H01, "RP5H01 6/7-bit Counter", tag, owner, clock, "rp5h01", __FILE__) +{ +} + +//------------------------------------------------- +// device_config_complete - perform any +// operations now that the configuration is +// complete +//------------------------------------------------- + +void rp5h01_device::device_config_complete() +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void rp5h01_device::device_start() +{ + m_data = region()->base(); + if (m_data == NULL) + m_data = initial_data; + else + assert(region()->bytes() == 0x10); + + /* register for state saving */ + save_item(NAME(m_counter)); + save_item(NAME(m_counter_mode)); + save_item(NAME(m_enabled)); + save_item(NAME(m_old_reset)); + save_item(NAME(m_old_clock)); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void rp5h01_device::device_reset() +{ + m_counter = 0; + m_counter_mode = COUNTER_MODE_6_BITS; + m_enabled = 0; + m_old_reset = 0; + m_old_clock = 0; +} + + +/*************************************************************************** + IMPLEMENTATION +***************************************************************************/ + +/*------------------------------------------------- + enable_w +-------------------------------------------------*/ + +WRITE_LINE_MEMBER( rp5h01_device::enable_w ) +{ + /* process the /CE signal and enable/disable the IC */ + m_enabled = state ? 0 : 1; +} + +/*------------------------------------------------- + reset_w +-------------------------------------------------*/ + +WRITE_LINE_MEMBER( rp5h01_device::reset_w ) +{ + /* if it's not enabled, ignore */ + if (!m_enabled) + return; + + /* now look for a 0->1 transition */ + if (!m_old_reset && state) + { + /* reset the counter */ + m_counter = 0; + } + + /* update the pin */ + m_old_reset = state; +} + +/*------------------------------------------------- + cs_w +-------------------------------------------------*/ + +WRITE_LINE_MEMBER( rp5h01_device::cs_w ) +{ + /* if it's not enabled, ignore */ + if (!m_enabled) + return; + + if (state) + { + /* reset the counter */ + m_counter = 0; + } +} + +/*------------------------------------------------- + clock_w +-------------------------------------------------*/ + +WRITE_LINE_MEMBER( rp5h01_device::clock_w ) +{ + /* if it's not enabled, ignore */ + if (!m_enabled) + return; + + /* now look for a 1->0 transition */ + if (m_old_clock && !state) + { + /* increment the counter, and mask it with the mode */ + m_counter++; + } + + /* update the pin */ + m_old_clock = state; +} + +/*------------------------------------------------- + test_w +-------------------------------------------------*/ + +WRITE_LINE_MEMBER( rp5h01_device::test_w ) +{ + /* if it's not enabled, ignore */ + if (!m_enabled) + return; + + /* process the test signal and change the counter mode */ + m_counter_mode = (state) ? COUNTER_MODE_7_BITS : COUNTER_MODE_6_BITS; +} + +/*------------------------------------------------- + counter_r +-------------------------------------------------*/ + +READ_LINE_MEMBER( rp5h01_device::counter_r ) +{ + /* if it's not enabled, ignore */ + if (!m_enabled) + return 1; /* high impedance */ + + /* return A5 */ + return (m_counter >> 5) & 1; +} + +/*------------------------------------------------- + data_r +-------------------------------------------------*/ + +READ_LINE_MEMBER( rp5h01_device::data_r ) +{ + /* if it's not enabled, ignore */ + if (!m_enabled) + return 1; /* high impedance */ + + /* get the byte offset and bit offset */ + int byte = (m_counter & m_counter_mode) >> 3; + int bit = 7 - (m_counter & 7); + + /* return the data */ + return (m_data[byte] >> bit) & 1; +} diff --git a/src/devices/machine/rp5h01.h b/src/devices/machine/rp5h01.h new file mode 100644 index 00000000000..016f05884ae --- /dev/null +++ b/src/devices/machine/rp5h01.h @@ -0,0 +1,77 @@ +// license:BSD-3-Clause +// copyright-holders:Nicola Salmoria +/*************************************************************************** + + RP5H01 - Ricoh 64x1bit(+8bit) PROM with 6/7-bit counter + +**************************************************************************** + ___________ + DATA 1 |* | 8 COUNTER OUT + | | + _CE/Vpp 2 | RP5H01 | 7 RESET + | RF5H01 | + Vcc 3 | | 6 DATA CLOCK + | | + GND 4 |___________| 5 TEST + +***************************************************************************/ + +#ifndef __RP5H01_H__ +#define __RP5H01_H__ + + +/*************************************************************************** + PARAMETERS +***************************************************************************/ + +/* these also work as the address masks */ +enum { + COUNTER_MODE_6_BITS = 0x3f, + COUNTER_MODE_7_BITS = 0x7f +}; + +/*************************************************************************** + MACROS / CONSTANTS +***************************************************************************/ + +class rp5h01_device : public device_t +{ +public: + rp5h01_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + DECLARE_WRITE_LINE_MEMBER( enable_w ); /* /CE */ + DECLARE_WRITE_LINE_MEMBER( reset_w ); /* RESET */ + DECLARE_WRITE_LINE_MEMBER( cs_w ); /* CS */ + DECLARE_WRITE_LINE_MEMBER( clock_w ); /* DATA CLOCK (active low) */ + DECLARE_WRITE_LINE_MEMBER( test_w ); /* TEST */ + DECLARE_READ_LINE_MEMBER( counter_r ); /* COUNTER OUT */ + DECLARE_READ_LINE_MEMBER( data_r ); /* DATA */ + +protected: + // device-level overrides + virtual void device_config_complete(); + virtual void device_start(); + virtual void device_reset(); +private: + // internal state + int m_counter; + int m_counter_mode; /* test pin */ + int m_enabled; /* chip enable */ + int m_old_reset; /* reset pin state (level-triggered) */ + int m_old_clock; /* clock pin state (level-triggered) */ + const UINT8 *m_data; +}; + +extern const device_type RP5H01; + + +#define MCFG_RP5H01_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, RP5H01, 0) + +/* + * Device uses memory region + * with the same tag as the one + * assigned to device. + */ + +#endif /* __RP5H01_H__ */ diff --git a/src/devices/machine/rtc4543.c b/src/devices/machine/rtc4543.c new file mode 100644 index 00000000000..ccbf32b5faa --- /dev/null +++ b/src/devices/machine/rtc4543.c @@ -0,0 +1,206 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/********************************************************************** + + rtc4543.c - Epson R4543 real-time clock chip emulation + by R. Belmont + + TODO: writing (not done by System 12 or 23 so no test case) + +**********************************************************************/ + +#include "rtc4543.h" + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define VERBOSE 0 + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +// device type definition +const device_type RTC4543 = &device_creator; + + +//------------------------------------------------- +// rtc4543_device - constructor +//------------------------------------------------- + +rtc4543_device::rtc4543_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, RTC4543, "R4543 RTC", tag, owner, clock, "rtc4543", __FILE__), + device_rtc_interface(mconfig, *this), + data_cb(*this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void rtc4543_device::device_start() +{ + data_cb.resolve_safe(); + + // allocate timers + m_clock_timer = timer_alloc(); + m_clock_timer->adjust(attotime::from_hz(clock() / 32768), 0, attotime::from_hz(clock() / 32768)); + + // state saving + save_item(NAME(m_ce)); + save_item(NAME(m_clk)); + save_item(NAME(m_wr)); + save_item(NAME(m_data)); + save_item(NAME(m_shiftreg)); + save_item(NAME(m_regs)); + save_item(NAME(m_curreg)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void rtc4543_device::device_reset() +{ + set_current_time(machine()); + + m_ce = 0; + m_wr = 0; + m_clk = 0; + m_data = 0; + m_shiftreg = 0; + m_curreg = 0; + m_curbit = 0; +} + + +//------------------------------------------------- +// device_timer - handler timer events +//------------------------------------------------- + +void rtc4543_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + advance_seconds(); +} + + +INLINE UINT8 make_bcd(UINT8 data) +{ + return ((data / 10) << 4) | (data % 10); +} + +//------------------------------------------------- +// rtc_clock_updated - +//------------------------------------------------- + +void rtc4543_device::rtc_clock_updated(int year, int month, int day, int day_of_week, int hour, int minute, int second) +{ + static const int weekday[7] = { 7, 1, 2, 3, 4, 5, 6 }; + + m_regs[0] = make_bcd(second); // seconds (BCD, 0-59) in bits 0-6, bit 7 = battery low + m_regs[1] = make_bcd(minute); // minutes (BCD, 0-59) + m_regs[2] = make_bcd(hour); // hour (BCD, 0-23) + m_regs[3] = make_bcd(weekday[day_of_week - 1]); // low nibble = day of the week + m_regs[3] |= (make_bcd(day) & 0x0f) << 4; // high nibble = low digit of day + m_regs[4] = (make_bcd(day) >> 4); // low nibble = high digit of day + m_regs[4] |= (make_bcd(month & 0x0f) << 4); // high nibble = low digit of month + m_regs[5] = make_bcd(month & 0x0f) >> 4; // low nibble = high digit of month + m_regs[5] |= (make_bcd(year % 10) << 4); // high nibble = low digit of year + m_regs[6] = make_bcd(year % 100) >> 4; // low nibble = tens digit of year (BCD, 0-9) +} + +//------------------------------------------------- +// ce_w - chip enable write +//------------------------------------------------- + +WRITE_LINE_MEMBER( rtc4543_device::ce_w ) +{ + if (VERBOSE) printf("RTC4543 '%s' CE: %u\n", tag(), state); + + if (!state && m_ce) // complete transfer + { + } + else if (state && !m_ce) // start new data transfer + { + m_curreg = 0; + m_curbit = 0; // force immediate reload of output data + } + + m_ce = state; +} + +//------------------------------------------------- +// wr_w - data direction line write +//------------------------------------------------- + +WRITE_LINE_MEMBER( rtc4543_device::wr_w ) +{ + if (VERBOSE) logerror("RTC4543 '%s' WR: %u\n", tag(), state); + + m_wr = state; +} + +//------------------------------------------------- +// clk_w - serial clock write +//------------------------------------------------- + +WRITE_LINE_MEMBER( rtc4543_device::clk_w ) +{ + if (VERBOSE) logerror("RTC4543 '%s' CLK: %u\n", tag(), state); + + if (!m_ce) return; + + // rising edge - read data becomes valid here + if (!m_clk && state) + { + if (!m_wr) + { + // reload data? + if ((m_curbit & 7) == 0) + { + m_shiftreg = m_regs[m_curreg++]; + + if (VERBOSE) + logerror("RTC4543 '%s' sending byte: %02x\n", tag(), m_shiftreg); + } + + // shift data bit + // note: output data does not change when clk at final bit + if (m_curbit != 55) + { + m_data = m_shiftreg & 1; + m_curbit++; + m_shiftreg >>= 1; + data_cb(m_data); + } + } + } + + m_clk = state; +} + + +//------------------------------------------------- +// data_w - I/O write +//------------------------------------------------- + +WRITE_LINE_MEMBER( rtc4543_device::data_w ) +{ + if (VERBOSE) logerror("RTC4543 '%s' I/O: %u\n", tag(), state); + + m_data = state & 1; +} + + +//------------------------------------------------- +// data_r - I/O read +//------------------------------------------------- + +READ_LINE_MEMBER( rtc4543_device::data_r ) +{ + return m_data; +} diff --git a/src/devices/machine/rtc4543.h b/src/devices/machine/rtc4543.h new file mode 100644 index 00000000000..c1eafb47efb --- /dev/null +++ b/src/devices/machine/rtc4543.h @@ -0,0 +1,82 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/********************************************************************** + + rtc4543.h - Epson R4543 real-time clock emulation + by R. Belmont + +**********************************************************************/ + +#pragma once + +#ifndef __RTC4543_H__ +#define __RTC4543_H__ + +#include "emu.h" + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_RTC4543_ADD(_tag, _clock) \ + MCFG_DEVICE_ADD(_tag, RTC4543, _clock) + +#define MCFG_RTC4543_DATA_CALLBACK(_devcb) \ + devcb = &rtc4543_device::set_data_cb(*device, DEVCB_##_devcb); + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> rtc4543_device + +class rtc4543_device : public device_t, + public device_rtc_interface +{ +public: + // construction/destruction + rtc4543_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + DECLARE_WRITE_LINE_MEMBER( ce_w ); + DECLARE_WRITE_LINE_MEMBER( wr_w ); + DECLARE_WRITE_LINE_MEMBER( clk_w ); + DECLARE_READ_LINE_MEMBER( data_r ); + DECLARE_WRITE_LINE_MEMBER( data_w ); + + template static devcb_base &set_data_cb(device_t &device, _Object object) { return downcast(device).data_cb.set_callback(object); } + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + // device_rtc_interface overrides + virtual void rtc_clock_updated(int year, int month, int day, int day_of_week, int hour, int minute, int second); + virtual bool rtc_feature_leap_year() { return true; } + +private: + devcb_write_line data_cb; + + int m_ce; + int m_clk; + int m_wr; + int m_data; + int m_shiftreg; + int m_regs[7]; + int m_curreg; + int m_curbit; + + // timers + emu_timer *m_clock_timer; +}; + + +// device type definition +extern const device_type RTC4543; + +#endif diff --git a/src/devices/machine/rtc65271.c b/src/devices/machine/rtc65271.c new file mode 100644 index 00000000000..074b8d87f48 --- /dev/null +++ b/src/devices/machine/rtc65271.c @@ -0,0 +1,697 @@ +// license:BSD-3-Clause +// copyright-holders:Raphael Nabet, R. Belmont +/* + rtc65271 emulation + + This chip is an RTC for computer built by Epson and Spezial-Electronic (I + think SE is the second source here). + + Reference: + * Realtime Clock Module RTC-65271 Application Manual + + + Todo: + * Support square wave pin output? + * Support DSE mode? + + Raphael Nabet, 2003-2004 + R. Belmont, 2012 +*/ + +#include "emu.h" +#include "rtc65271.h" + +/* Delay between the beginning (UIP asserted) and the end (UIP cleared and +update interrupt asserted) of the update cycle */ +#define UPDATE_CYCLE_TIME attotime::from_usec(1984) +/* Delay between the assertion of UIP and the effective start of the update +cycle */ +/*#define UPDATE_CYCLE_DELAY attotime::from_usec(244)*/ + +enum +{ + reg_second = 0, + reg_alarm_second, + reg_minute, + reg_alarm_minute, + reg_hour, + reg_alarm_hour, + reg_weekday, + reg_monthday, + reg_month, + reg_year, + reg_A, + reg_B, + reg_C, + reg_D +}; + +enum +{ + reg_A_UIP = 0x80, + reg_A_DV = 0x70, + reg_A_RS = 0x0F, + + reg_B_SET = 0x80, + reg_B_PIE = 0x40, + reg_B_AIE = 0x20, + reg_B_UIE = 0x10, + reg_B_SQW = 0x08, + reg_B_DM = 0x04, + reg_B_24h = 0x02, + reg_B_DSE = 0x01, + + reg_C_IRQF = 0x80, + reg_C_PF = 0x40, + reg_C_AF = 0x20, + reg_C_UF = 0x10, + + reg_D_VRT = 0x80 +}; + +static const int SQW_freq_table[16] = +{ + 0, + 256, + 128, + 8192, + 4096, + 2048, + 1024, + 512, + 256, + 128, + 64, + 32, + 16, + 8, + 4, + 2, +}; + + +/* + BCD utilities +*/ + +/* + Increment a binary-encoded UINT8 +*/ +static UINT8 increment_binary(UINT8 data) +{ + return data+1; +} + + +/* + Increment a BCD-encoded UINT8 +*/ +static UINT8 increment_BCD(UINT8 data) +{ + if ((data & 0x0f) < 0x09) + { + if ((data & 0xf0) < 0xa0) + data++; + else + data = data + 0x01 - 0xa0; + } + else + { + if ((data & 0xf0) < 0xa0) + data = data - 0x09 + 0x10; + else + data = data - 0x09 - 0x90; + } + return data; +} + + +/* + Convert a binary-encoded UINT8 to BCD +*/ +static UINT8 binary_to_BCD(UINT8 data) +{ + data %= 100; + + return ((data / 10) << 4) | (data %10); +} + + +/* + Convert a BCD-encoded UINT8 to binary +*/ +static UINT8 BCD_to_binary(UINT8 data) +{ + if ((data & 0x0f) >= 0x0a) + data = data - 0x0a + 0x10; + if ((data & 0xf0) >= 0xa0) + data = data - 0xa0; + + return (data & 0x0f) + (((data & 0xf0) >> 4) * 10); +} + + +/* + Public functions +*/ + +//------------------------------------------------- +// nvram_default - called to initialize NVRAM to +// its default state +//------------------------------------------------- + +void rtc65271_device::nvram_default() +{ + memset(m_regs,0, sizeof(m_regs)); + memset(m_xram,0, sizeof(m_xram)); + + m_regs[reg_B] |= reg_B_DM; // Firebeat assumes the chip factory defaults to non-BCD mode (or maybe Konami programs it that way?) +} + +//------------------------------------------------- +// nvram_read - called to read NVRAM from the +// .nv file +//------------------------------------------------- + +void rtc65271_device::nvram_read(emu_file &file) +{ + UINT8 buf; + + /* version flag */ + if (file.read(&buf, 1) != 1) + return; + if (buf != 0) + return; + + /* control registers */ + if (file.read(&buf, 1) != 1) + return; + m_regs[reg_A] = buf & (reg_A_DV /*| reg_A_RS*/); + if (file.read(&buf, 1) != 1) + return; + m_regs[reg_B] = buf & (reg_B_SET | reg_B_DM | reg_B_24h | reg_B_DSE); + + /* alarm registers */ + if (file.read(&m_regs[reg_alarm_second], 1) != 1) + return; + if (file.read(&m_regs[reg_alarm_minute], 1) != 1) + return; + if (file.read(&m_regs[reg_alarm_hour], 1) != 1) + return; + + /* user RAM */ + if (file.read(m_regs+14, 50) != 50) + return; + + /* extended RAM */ + if (file.read(m_xram, 4096) != 4096) + return; + + m_regs[reg_D] |= reg_D_VRT; /* the data was backed up successfully */ + /*m_dirty = FALSE;*/ + + { + system_time systime; + + /* get the current date/time from the core */ + machine().current_datetime(systime); + + /* set clock registers */ + m_regs[reg_second] = systime.local_time.second; + m_regs[reg_minute] = systime.local_time.minute; + if (m_regs[reg_B] & reg_B_24h) + /* 24-hour mode */ + m_regs[reg_hour] = systime.local_time.hour; + else + { /* 12-hour mode */ + if (systime.local_time.hour >= 12) + { + m_regs[reg_hour] = 0x80; + systime.local_time.hour -= 12; + } + else + { + m_regs[reg_hour] = 0; + } + + // Firebeat indicates non-BCD 12-hour mode has 0-based hour, so 12 AM is 0x00 and 12 PM is 0x80 + m_regs[reg_hour] |= systime.local_time.hour; // ? systime.local_time.hour : 12; + } + m_regs[reg_weekday] = systime.local_time.weekday + 1; + m_regs[reg_monthday] = systime.local_time.mday; + m_regs[reg_month] = systime.local_time.month + 1; + m_regs[reg_year] = systime.local_time.year % 100; + if (! (m_regs[reg_B] & reg_B_DM)) + { /* BCD mode */ + m_regs[reg_second] = binary_to_BCD(m_regs[reg_second]); + m_regs[reg_minute] = binary_to_BCD(m_regs[reg_minute]); + m_regs[reg_hour] = (m_regs[reg_hour] & 0x80) | binary_to_BCD(m_regs[reg_hour] & 0x7f); + /*m_regs[reg_weekday] = binary_to_BCD(m_regs[reg_weekday]);*/ + m_regs[reg_monthday] = binary_to_BCD(m_regs[reg_monthday]); + m_regs[reg_month] = binary_to_BCD(m_regs[reg_month]); + m_regs[reg_year] = binary_to_BCD(m_regs[reg_year]); + } + } +} + +//------------------------------------------------- +// nvram_write - called to write NVRAM to the +// .nv file +//------------------------------------------------- + +void rtc65271_device::nvram_write(emu_file &file) +{ + UINT8 buf; + + + /* version flag */ + buf = 0; + if (file.write(& buf, 1) != 1) + return; + + /* control registers */ + buf = m_regs[reg_A] & (reg_A_DV | reg_A_RS); + if (file.write(&buf, 1) != 1) + return; + buf = m_regs[reg_B] & (reg_B_SET | reg_B_DM | reg_B_24h | reg_B_DSE); + if (file.write(&buf, 1) != 1) + return; + + /* alarm registers */ + if (file.write(&m_regs[reg_alarm_second], 1) != 1) + return; + if (file.write(&m_regs[reg_alarm_minute], 1) != 1) + return; + if (file.write(&m_regs[reg_alarm_hour], 1) != 1) + return; + + /* user RAM */ + if (file.write(m_regs+14, 50) != 50) + return; + + /* extended RAM */ + if (file.write(m_xram, 4096) != 4096) + return; +} + +/* + Read a byte from clock + + xramsel: select RTC register if 0, XRAM if 1 + offset: address (A0-A5 pins) +*/ +UINT8 rtc65271_device::read(int xramsel, offs_t offset) +{ + int reply; + + if (xramsel) + { + if (offset & 0x20) + /* XRAM page register */ + reply = m_cur_xram_page; + else + /* XRAM data */ + reply = m_xram[(offset & 0x1f) + 0x0020*m_cur_xram_page]; + } + else + { + if (offset & 0x01) + /* data register */ + switch (m_cur_reg) + { + case reg_A: + reply = m_regs[m_cur_reg] & ~reg_A_DV; + reply |= 0x20; // indicate normal RTC operation + break; + + case reg_C: + reply = m_regs[m_cur_reg]; + m_regs[m_cur_reg] = 0; + field_interrupts(); + break; + case reg_D: + reply = m_regs[m_cur_reg]; + m_regs[m_cur_reg] = /*0*/reg_D_VRT; /* set VRT flag so that the computer does not complain that the battery is low */ + break; + + default: + reply = m_regs[m_cur_reg]; + break; + } + else + /* indirect address register */ + reply = m_cur_reg; + } + + return reply; +} + +READ8_MEMBER( rtc65271_device::rtc_r ) +{ + return read(0, offset ); +} + +READ8_MEMBER( rtc65271_device::xram_r ) +{ + return read(1, offset ); +} + +/* + Write a byte to clock + + xramsel: select RTC register if 0, XRAM if 1 + offset: address (A0-A5 pins) +*/ +void rtc65271_device::write(int xramsel, offs_t offset, UINT8 data) +{ + if (xramsel) + { + if (offset & 0x20) + /* XRAM page register */ + m_cur_xram_page = data & 0x7f; + else + /* XRAM data */ + m_xram[(offset & 0x1f) + 0x0020*m_cur_xram_page] = data; + } + else + { + if (offset & 0x01) + /* data register */ + switch (m_cur_reg) + { + case reg_second: + /* the data sheet says bit 7 is read-only. (I have no idea of + the reason why it is.) */ + m_regs[reg_second] = data & 0x7f; + break; + + case reg_A: + if ((data & reg_A_RS) != (m_regs[m_cur_reg] & reg_A_RS)) + { + if (data & reg_A_RS) + { + attotime period = attotime::from_hz(SQW_freq_table[data & reg_A_RS]); + attotime half_period = period / 2; + attotime elapsed = m_update_timer->elapsed(); + + if (half_period > elapsed) + m_SQW_timer->adjust(half_period - elapsed); + else + m_SQW_timer->adjust(half_period); + } + else + { + m_SQW_internal_state = 0; /* right??? */ + + /* Stop the divider used for SQW and periodic interrupts. */ + m_SQW_timer->adjust(attotime::never); + } + } + /* The UIP bit is read-only */ + m_regs[reg_A] = (data & ~reg_A_UIP) | (m_regs[reg_A] & reg_A_UIP); + break; + + case reg_B: + m_regs[m_cur_reg] = data; + if (data & reg_B_SET) + { + /* if we are in SET mode, clear update cycle */ + m_regs[reg_A] &= ~reg_A_UIP; + m_regs[reg_B] &= ~reg_B_UIE; /* the data sheet tells this, but I wonder how much sense it makes */ + field_interrupts(); + } + break; + + case reg_C: + case reg_D: + break; + + default: + m_regs[m_cur_reg] = data; + break; + } + else + /* indirect address register */ + m_cur_reg = data & 0x3f; + } +} + +WRITE8_MEMBER( rtc65271_device::rtc_w ) +{ + write(0, offset, data ); +} + +WRITE8_MEMBER( rtc65271_device::xram_w ) +{ + write(1, offset, data ); +} + +void rtc65271_device::field_interrupts() +{ + if (m_regs[reg_C] & m_regs[reg_B] & (reg_C_PF | reg_C_AF | reg_C_UF)) + { + m_regs[reg_C] |= reg_C_IRQF; + if (!m_interrupt_cb.isnull()) + m_interrupt_cb(1); + } + else + { + m_regs[reg_C] &= ~reg_C_IRQF; + if (!m_interrupt_cb.isnull()) + m_interrupt_cb(0); + } +} + + +/* + Timer handlers +*/ +TIMER_CALLBACK( rtc65271_device::rtc_SQW_callback ) +{ + rtc65271_device *rtc = reinterpret_cast(ptr); + rtc->rtc_SQW_cb(); +} + +TIMER_CALLBACK( rtc65271_device::rtc_begin_update_callback ) +{ + rtc65271_device *rtc = reinterpret_cast(ptr); + rtc->rtc_begin_update_cb(); +} + +TIMER_CALLBACK( rtc65271_device::rtc_end_update_callback ) +{ + rtc65271_device *rtc = reinterpret_cast(ptr); + rtc->rtc_end_update_cb(); +} +/* + Update SQW output state each half-period and assert periodic interrupt each + period. +*/ +void rtc65271_device::rtc_SQW_cb() +{ + attotime half_period; + + m_SQW_internal_state = ! m_SQW_internal_state; + if (! m_SQW_internal_state) + { + /* high-to-low??? transition -> interrupt (or should it be low-to-high?) */ + m_regs[reg_C] |= reg_C_PF; + field_interrupts(); + } + + half_period = attotime::from_hz(SQW_freq_table[m_regs[reg_A] & reg_A_RS]) / 2; + m_SQW_timer->adjust(half_period); +} + +/* + Begin update cycle (called every second) +*/ +void rtc65271_device::rtc_begin_update_cb() +{ + if (((m_regs[reg_A] & reg_A_DV) == 0x20) && ! (m_regs[reg_B] & reg_B_SET)) + { + m_regs[reg_A] |= reg_A_UIP; + + /* schedule end of update cycle */ + machine().scheduler().timer_set(UPDATE_CYCLE_TIME, FUNC(rtc_end_update_callback), 0, (void *)this); + } +} + +/* + End update cycle (called UPDATE_CYCLE_TIME = 1948us after start of update + cycle) +*/ +void rtc65271_device::rtc_end_update_cb() +{ + static const int days_in_month_table[12] = + { + 31,28,31, 30,31,30, + 31,31,30, 31,30,31 + }; + UINT8 (*increment)(UINT8 data); + int c59, c23, c12, c11, c29; + + if (! (m_regs[reg_A] & reg_A_UIP)) + /* abort if update cycle has been canceled */ + return; + + if (m_regs[reg_B] & reg_B_DM) + { + /* binary mode */ + increment = increment_binary; + c59 = 59; + c23 = 23; + c12 = 12; + c11 = 11; + c29 = 29; + } + else + { + /* BCD mode */ + increment = increment_BCD; + c59 = 0x59; + c23 = 0x23; + c12 = 0x12; + c11 = 0x11; + c29 = 0x29; + } + + /* increment second */ + if (m_regs[reg_second] < c59) + m_regs[reg_second] = (*increment)(m_regs[reg_second]); + else + { + m_regs[reg_second] = 0; + + /* increment minute */ + if (m_regs[reg_minute] < c59) + m_regs[reg_minute] = (*increment)(m_regs[reg_minute]); + else + { + m_regs[reg_minute] = 0; + + /* increment hour */ + if (m_regs[reg_B] & reg_B_24h) + { + /* 24 hour mode */ + if (m_regs[reg_hour] < c23) + m_regs[reg_hour] = (*increment)(m_regs[reg_hour]); + else + m_regs[reg_hour] = 0; + } + else + { + /* 12 hour mode */ + if (m_regs[reg_hour] < c12) + { + if ((m_regs[reg_hour] & 0x7f) == c11) + m_regs[reg_hour] ^= 0x80; + m_regs[reg_hour] = ((*increment)(m_regs[reg_hour] & 0x7f) & 0x7f) + | (m_regs[reg_hour] & 0x80); + } + else + m_regs[reg_hour] = 1 | (m_regs[reg_hour] & 0x80); + } + + /* increment day if needed */ + if (m_regs[reg_hour] == ((m_regs[reg_B] & reg_B_24h) ? 0 : c12)) + { + /* increment day */ + int days_in_month; + + if (m_regs[reg_weekday] < 7) + m_regs[reg_weekday]++; + else + m_regs[reg_weekday] = 1; + + if ((m_regs[reg_month] != 2) || (m_regs[reg_year] & 0x03)) + { + if (m_regs[reg_B] & reg_B_DM) + { + /* binary mode */ + days_in_month = days_in_month_table[m_regs[reg_month] - 1]; + } + else + { + /* BCD mode */ + days_in_month = binary_to_BCD(days_in_month_table[BCD_to_binary(m_regs[reg_month]) - 1]); + } + } + else + days_in_month = c29; + + if (m_regs[reg_monthday] < days_in_month) + m_regs[reg_monthday] = (*increment)(m_regs[reg_monthday]); + else + { + /* increment month */ + m_regs[reg_monthday] = 1; + + if (m_regs[reg_month] < c12) + m_regs[reg_month] = (*increment)(m_regs[reg_month]); + else + { + /* increment year */ + m_regs[reg_month] = 1; + + if (m_regs[reg_B] & reg_B_DM) + { + /* binary mode */ + if (m_regs[reg_year] < 99) + m_regs[reg_year]++; + else + m_regs[reg_year] = 0; + } + else + { + /* BCD mode */ + m_regs[reg_year] = increment_BCD(m_regs[reg_year]); + } + } + } + } + } + } + + m_regs[reg_A] &= ~reg_A_UIP; + m_regs[reg_C] |= reg_C_UF; + + /* test for alarm (values in range 0xc0-0xff mean "don't care") */ + if ((((m_regs[reg_alarm_second] & 0xc0) == 0xc0) || (m_regs[reg_alarm_second] == m_regs[reg_second])) + && (((m_regs[reg_alarm_minute] & 0xc0) == 0xc0) || (m_regs[reg_alarm_minute] == m_regs[reg_minute])) + && (((m_regs[reg_alarm_hour] & 0xc0) == 0xc0) || (m_regs[reg_alarm_hour] == m_regs[reg_hour]))) + m_regs[reg_C] |= reg_C_AF; + + field_interrupts(); +} + +// device type definition +const device_type RTC65271 = &device_creator; + +//------------------------------------------------- +// rtc65271_device - constructor +//------------------------------------------------- + +rtc65271_device::rtc65271_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, RTC65271, "RTC-65271", tag, owner, clock, "rtc65271", __FILE__), + device_nvram_interface(mconfig, *this), + m_interrupt_cb(*this) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- +void rtc65271_device::device_start() +{ + m_update_timer = machine().scheduler().timer_alloc(FUNC(rtc_begin_update_callback), (void *)this); + m_update_timer->adjust(attotime::from_seconds(1), 0, attotime::from_seconds(1)); + m_SQW_timer = machine().scheduler().timer_alloc(FUNC(rtc_SQW_callback), (void *)this); + m_interrupt_cb.resolve(); + + save_item(NAME(m_regs)); + save_item(NAME(m_cur_reg)); + save_item(NAME(m_xram)); + save_item(NAME(m_cur_xram_page)); + save_item(NAME(m_SQW_internal_state)); +} diff --git a/src/devices/machine/rtc65271.h b/src/devices/machine/rtc65271.h new file mode 100644 index 00000000000..b81e92755d5 --- /dev/null +++ b/src/devices/machine/rtc65271.h @@ -0,0 +1,76 @@ +// license:BSD-3-Clause +// copyright-holders:Raphael Nabet, R. Belmont +/* + rtc65271.h: include file for rtc65271.c +*/ + +#ifndef __RTC65271_H__ +#define __RTC65271_H__ + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_RTC65271_INTERRUPT_CB(_devcb) \ + devcb = &rtc65271_device::set_interrupt_callback(*device, DEVCB_##_devcb); + + +// ======================> rtc65271_device + +class rtc65271_device : public device_t, + public device_nvram_interface +{ +public: + // construction/destruction + rtc65271_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +protected: + // device-level overrides + virtual void device_start(); + // device_nvram_interface overrides + virtual void nvram_default(); + virtual void nvram_read(emu_file &file); + virtual void nvram_write(emu_file &file); +public: + + template static devcb_base &set_interrupt_callback(device_t &device, _Object object) { return downcast(device).m_interrupt_cb.set_callback(object); } + + DECLARE_READ8_MEMBER( rtc_r ); + DECLARE_READ8_MEMBER( xram_r ); + DECLARE_WRITE8_MEMBER( rtc_w ); + DECLARE_WRITE8_MEMBER( xram_w ); +private: + UINT8 read(int xramsel, offs_t offset); + void write(int xramsel, offs_t offset, UINT8 data); + void field_interrupts(); + + static TIMER_CALLBACK( rtc_SQW_callback ); + static TIMER_CALLBACK( rtc_begin_update_callback ); + static TIMER_CALLBACK( rtc_end_update_callback ); + + void rtc_SQW_cb(); + void rtc_begin_update_cb(); + void rtc_end_update_cb(); + /* 64 8-bit registers (10 clock registers, 4 control/status registers, and + 50 bytes of user RAM) */ + UINT8 m_regs[64]; + UINT8 m_cur_reg; + + /* extended RAM: 4kbytes of battery-backed RAM (in pages of 32 bytes) */ + UINT8 m_xram[4096]; + UINT8 m_cur_xram_page; + + /* update timer: called every second */ + emu_timer *m_update_timer; + + /* SQW timer: called every periodic clock half-period */ + emu_timer *m_SQW_timer; + UINT8 m_SQW_internal_state; + + /* callback called when interrupt pin state changes (may be NULL) */ + devcb_write_line m_interrupt_cb; +}; + +// device type definition +extern const device_type RTC65271; + +#endif diff --git a/src/devices/machine/rtc9701.c b/src/devices/machine/rtc9701.c new file mode 100644 index 00000000000..afa46572ef4 --- /dev/null +++ b/src/devices/machine/rtc9701.c @@ -0,0 +1,469 @@ +// license:BSD-3-Clause +// copyright-holders:Angelo Salese, David Haywood +/*************************************************************************** + + rtc9701.c + + Epson RTC-9701-JE + + Serial Real Time Clock + EEPROM + + +***************************************************************************/ + +#include "emu.h" +#include "machine/rtc9701.h" + + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +// device type definition +const device_type rtc9701 = &device_creator; + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// rtc9701_device - constructor +//------------------------------------------------- + +rtc9701_device::rtc9701_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, rtc9701, "RTC-9701", tag, owner, clock, "rtc9701", __FILE__), + device_nvram_interface(mconfig, *this), + m_latch(0), + m_reset_line(CLEAR_LINE), + m_clock_line(CLEAR_LINE) +{ +} + +void rtc9701_device::timer_callback() +{ + static const UINT8 dpm[12] = { 0x31, 0x28, 0x31, 0x30, 0x31, 0x30, 0x31, 0x31, 0x30, 0x31, 0x30, 0x31 }; + int dpm_count; + + m_rtc.sec++; + + if((m_rtc.sec & 0x0f) >= 0x0a) { m_rtc.sec+=0x10; m_rtc.sec&=0xf0; } + if((m_rtc.sec & 0xf0) >= 0x60) { m_rtc.min++; m_rtc.sec = 0; } + if((m_rtc.min & 0x0f) >= 0x0a) { m_rtc.min+=0x10; m_rtc.min&=0xf0; } + if((m_rtc.min & 0xf0) >= 0x60) { m_rtc.hour++; m_rtc.min = 0; } + if((m_rtc.hour & 0x0f) >= 0x0a) { m_rtc.hour+=0x10; m_rtc.hour&=0xf0; } + if((m_rtc.hour & 0xff) >= 0x24) { m_rtc.day++; m_rtc.wday<<=1; m_rtc.hour = 0; } + if(m_rtc.wday & 0x80) { m_rtc.wday = 1; } + if((m_rtc.day & 0x0f) >= 0x0a) { m_rtc.day+=0x10; m_rtc.day&=0xf0; } + + /* TODO: crude leap year support */ + dpm_count = (m_rtc.month & 0xf) + (((m_rtc.month & 0x10) >> 4)*10)-1; + + if(((m_rtc.year % 4) == 0) && m_rtc.month == 2) + { + if((m_rtc.day & 0xff) >= dpm[dpm_count]+1+1) + { m_rtc.month++; m_rtc.day = 0x01; } + } + else if((m_rtc.day & 0xff) >= dpm[dpm_count]+1){ m_rtc.month++; m_rtc.day = 0x01; } + if((m_rtc.month & 0x0f) >= 0x0a) { m_rtc.month = 0x10; } + if(m_rtc.month >= 0x13) { m_rtc.year++; m_rtc.month = 1; } + if((m_rtc.year & 0x0f) >= 0x0a) { m_rtc.year+=0x10; m_rtc.year&=0xf0; } + if((m_rtc.year & 0xf0) >= 0xa0) { m_rtc.year = 0; } //2000-2099 possible timeframe +} + +TIMER_CALLBACK( rtc9701_device::rtc_inc_callback ) +{ + reinterpret_cast(ptr)->timer_callback(); +} + +//------------------------------------------------- +// device_validity_check - perform validity checks +// on this device +//------------------------------------------------- + +void rtc9701_device::device_validity_check(validity_checker &valid) const +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void rtc9701_device::device_start() +{ + /* let's call the timer callback every second */ + machine().scheduler().timer_pulse(attotime::from_hz(clock() / XTAL_32_768kHz), FUNC(rtc_inc_callback), 0, (void *)this); + + system_time systime; + machine().base_datetime(systime); + + m_rtc.day = ((systime.local_time.mday / 10)<<4) | ((systime.local_time.mday % 10) & 0xf); + m_rtc.month = (((systime.local_time.month+1) / 10) << 4) | (((systime.local_time.month+1) % 10) & 0xf); + m_rtc.wday = 1 << systime.local_time.weekday; + m_rtc.year = (((systime.local_time.year % 100)/10)<<4) | ((systime.local_time.year % 10) & 0xf); + m_rtc.hour = ((systime.local_time.hour / 10)<<4) | ((systime.local_time.hour % 10) & 0xf); + m_rtc.min = ((systime.local_time.minute / 10)<<4) | ((systime.local_time.minute % 10) & 0xf); + m_rtc.sec = ((systime.local_time.second / 10)<<4) | ((systime.local_time.second % 10) & 0xf); + + rtc_state = RTC9701_CMD_WAIT; + cmd_stream_pos = 0; + current_cmd = 0; +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void rtc9701_device::device_reset() +{ +} + + + +//------------------------------------------------- +// nvram_default - called to initialize NVRAM to +// its default state +//------------------------------------------------- + +void rtc9701_device::nvram_default() +{ + for (offs_t offs = 0; offs < 0x100; offs++) + rtc9701_data[offs] = 0xffff; +} + + + + +//------------------------------------------------- +// nvram_read - called to read NVRAM from the +// .nv file +//------------------------------------------------- + +void rtc9701_device::nvram_read(emu_file &file) +{ + file.read(rtc9701_data, 0x200); +} + + +//------------------------------------------------- +// nvram_write - called to write NVRAM to the +// .nv file +//------------------------------------------------- + +void rtc9701_device::nvram_write(emu_file &file) +{ + file.write(rtc9701_data, 0x200); +} + +//------------------------------------------------- +// rtc_read - used to route RTC reading registers +//------------------------------------------------- + +inline UINT8 rtc9701_device::rtc_read(UINT8 offset) +{ + UINT8 res; + + res = 0; + + switch(offset) + { + case 0: res = m_rtc.sec; break; + case 1: res = m_rtc.min; break; + case 2: res = m_rtc.hour; break; + case 3: res = m_rtc.wday; break; /* untested */ + case 4: res = m_rtc.day; break; + case 5: res = m_rtc.month; break; + case 6: res = m_rtc.year & 0xff; break; + case 7: res = 0x20; break; + } + + return res; +} + +inline void rtc9701_device::rtc_write(UINT8 offset,UINT8 data) +{ + switch(offset) + { + case 0: m_rtc.sec = data; break; + case 1: m_rtc.min = data; break; + case 2: m_rtc.hour = data; break; + case 3: m_rtc.wday = data; break; /* untested */ + case 4: m_rtc.day = data; break; + case 5: m_rtc.month = data; break; + case 6: m_rtc.year = data; break; + case 7: break; // NOP + } +} + +//************************************************************************** +// READ/WRITE HANDLERS +//************************************************************************** + +WRITE_LINE_MEMBER( rtc9701_device::write_bit ) +{ + m_latch = state; +} + + +READ_LINE_MEMBER( rtc9701_device::read_bit ) +{ + if (rtc_state == RTC9701_RTC_READ) + { + //printf("RTC data bits left c9701_data_pos %02x\n", rtc9701_data_pos); + return ((rtc9701_current_data) >> (rtc9701_data_pos-1))&1; + + } + else if (rtc_state == RTC9701_EEPROM_READ) + { + //printf("EEPROM data bits left c9701_data_pos %02x\n", rtc9701_data_pos); + return ((rtc9701_current_data) >> (rtc9701_data_pos-1))&1; + + } + else + { + //printf("read something else (status?) %02x\n", rtc9701_data_pos); + } + + + + return 0; +} + + +WRITE_LINE_MEMBER( rtc9701_device::set_cs_line ) +{ + //logerror("set reset line %d\n",state); + m_reset_line = state; + + if (m_reset_line != CLEAR_LINE) + { + rtc_state = RTC9701_CMD_WAIT; + cmd_stream_pos = 0; + current_cmd = 0; + rtc9701_address_pos = 0; + rtc9701_current_address = 0; + rtc9701_current_data = 0; + rtc9701_data_pos = 0; + + } +} + + + +WRITE_LINE_MEMBER( rtc9701_device::set_clock_line ) +{ + //logerror("set clock line %d\n",state); + + if (m_reset_line == CLEAR_LINE) + { + if (state==1) + { + //logerror("write latched bit %d\n",m_latch); + + switch (rtc_state) + { + case RTC9701_CMD_WAIT: + + //logerror("xx\n"); + current_cmd = (current_cmd << 1) | (m_latch&1); + cmd_stream_pos++; + + if (cmd_stream_pos==4) + { + cmd_stream_pos = 0; + //logerror("Comamnd is %02x\n", current_cmd); + + if (current_cmd==0x00) /* 0000 */ + { + //logerror("WRITE RTC MODE\n"); + rtc_state = RTC9701_RTC_WRITE; + cmd_stream_pos = 0; + rtc9701_address_pos = 0; + rtc9701_current_address = 0; + rtc9701_data_pos = 0; + rtc9701_current_data = 0; + } + else if (current_cmd==0x02) /* 0010 */ + { + //logerror("WRITE EEPROM MODE\n"); + rtc_state = RTC9701_EEPROM_WRITE; + cmd_stream_pos = 0; + rtc9701_address_pos = 0; + rtc9701_current_address = 0; + rtc9701_data_pos = 0; + rtc9701_current_data = 0; + + } + else if (current_cmd==0x06) /* 0110 */ + { + //logerror("WRITE ENABLE\n"); + rtc_state = RTC9701_AFTER_WRITE_ENABLE; + cmd_stream_pos = 0; + } + else if (current_cmd==0x08) /* 1000 */ + { + //logerror("READ RTC MODE\n"); + rtc_state = RTC9701_RTC_READ; + cmd_stream_pos = 0; + rtc9701_address_pos = 0; + rtc9701_current_address = 0; + rtc9701_data_pos = 0; + rtc9701_current_data = 0; + } + else if (current_cmd==0x0a) /* 1010 */ + { + //logerror("READ EEPROM MODE\n"); + rtc_state = RTC9701_EEPROM_READ; + cmd_stream_pos = 0; + rtc9701_address_pos = 0; + rtc9701_current_address = 0; + rtc9701_data_pos = 0; + rtc9701_current_data = 0; + + + } + else + { + //logerror("RTC9701 UNKNOWN MODE\n"); + } + + current_cmd = 0; + } + break; + + case RTC9701_AFTER_WRITE_ENABLE: + cmd_stream_pos++; + if (cmd_stream_pos==12) + { + cmd_stream_pos = 0; + //logerror("Written 12 bits, going back to WAIT mode\n"); + rtc_state = RTC9701_CMD_WAIT; + } + break; + + case RTC9701_RTC_WRITE: + cmd_stream_pos++; + if (cmd_stream_pos<=4) + { + rtc9701_address_pos++; + rtc9701_current_address = (rtc9701_current_address << 1) | (m_latch&1); + if (cmd_stream_pos==4) + { + //printf("Set RTC Write Address To %04x\n", rtc9701_current_address ); + } + } + + if (cmd_stream_pos>4) + { + rtc9701_data_pos++; + rtc9701_current_data = (rtc9701_current_data << 1) | (m_latch&1);; + } + + if (cmd_stream_pos==12) + { + cmd_stream_pos = 0; + rtc_write(rtc9701_current_address,rtc9701_current_data); + //logerror("Written 12 bits, going back to WAIT mode\n"); + rtc_state = RTC9701_CMD_WAIT; + } + break; + + + + case RTC9701_EEPROM_READ: + cmd_stream_pos++; + if (cmd_stream_pos<=12) + { + rtc9701_address_pos++; + rtc9701_current_address = (rtc9701_current_address << 1) | (m_latch&1); + if (cmd_stream_pos==12) + { + //printf("Set EEPROM Read Address To %04x - ", (rtc9701_current_address>>1)&0xff ); + rtc9701_current_data = rtc9701_data[(rtc9701_current_address>>1)&0xff]; + //printf("Setting data latch for reading to %04x\n", rtc9701_current_data); + rtc9701_data_pos = 16; + } + } + + if (cmd_stream_pos>12) + { + rtc9701_data_pos--; + + } + + if (cmd_stream_pos==28) + { + cmd_stream_pos = 0; + // //logerror("accesed 28 bits, going back to WAIT mode\n"); + // rtc_state = RTC9701_CMD_WAIT; + } + break; + + + + case RTC9701_EEPROM_WRITE: + cmd_stream_pos++; + + if (cmd_stream_pos<=12) + { + rtc9701_address_pos++; + rtc9701_current_address = (rtc9701_current_address << 1) | (m_latch&1); + if (cmd_stream_pos==12) + { + //printf("Set EEPROM Write Address To %04x\n", rtc9701_current_address ); + } + } + + if (cmd_stream_pos>12) + { + rtc9701_data_pos++; + rtc9701_current_data = (rtc9701_current_data << 1) | (m_latch&1);; + } + + if (cmd_stream_pos==28) + { + cmd_stream_pos = 0; + //printf("written 28 bits - writing data %04x to %04x and going back to WAIT mode\n", rtc9701_current_data, (rtc9701_current_address>>1)&0xff); + rtc9701_data[(rtc9701_current_address>>1)&0xff] = rtc9701_current_data; + rtc_state = RTC9701_CMD_WAIT; + } + break; + + case RTC9701_RTC_READ: + cmd_stream_pos++; + if (cmd_stream_pos<=4) + { + rtc9701_address_pos++; + rtc9701_current_address = (rtc9701_current_address << 1) | (m_latch&1); + if (cmd_stream_pos==4) + { + //printf("Set RTC Read Address To %04x\n", rtc9701_current_address ); + rtc9701_current_data = rtc_read(rtc9701_current_address); + //printf("Setting data latch for reading to %04x\n", rtc9701_current_data); + rtc9701_data_pos = 8; + } + } + + if (cmd_stream_pos>4) + { + rtc9701_data_pos--; + } + + if (cmd_stream_pos==12) + { + cmd_stream_pos = 0; + // //logerror("accessed 12 bits, going back to WAIT mode\n"); + // rtc_state = RTC9701_CMD_WAIT; + } + break; + + + default: + break; + + } + } + } +} diff --git a/src/devices/machine/rtc9701.h b/src/devices/machine/rtc9701.h new file mode 100644 index 00000000000..eaad28ad0b5 --- /dev/null +++ b/src/devices/machine/rtc9701.h @@ -0,0 +1,111 @@ +// license:BSD-3-Clause +// copyright-holders:Angelo Salese, David Haywood +/*************************************************************************** + + rtc9701.h + + Serial rtc9701s. + +***************************************************************************/ + +#pragma once + +#ifndef __rtc9701DEV_H__ +#define __rtc9701DEV_H__ + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_RTC9701_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, rtc9701, XTAL_32_768kHz) + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + + +enum rtc9701_state_t +{ + RTC9701_CMD_WAIT = 0, + RTC9701_RTC_READ, + RTC9701_RTC_WRITE, + RTC9701_EEPROM_READ, + RTC9701_EEPROM_WRITE, + RTC9701_AFTER_WRITE_ENABLE + +}; + +struct rtc_regs_t +{ + UINT8 sec, min, hour, day, wday, month, year; +}; + + +// ======================> rtc9701_device + +class rtc9701_device : public device_t, + public device_nvram_interface +{ +public: + // construction/destruction + rtc9701_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + + // I/O operations + DECLARE_WRITE_LINE_MEMBER( write_bit ); + DECLARE_READ_LINE_MEMBER( read_bit ); + DECLARE_WRITE_LINE_MEMBER( set_cs_line ); + DECLARE_WRITE_LINE_MEMBER( set_clock_line ); + void timer_callback(); + +protected: + // device-level overrides + virtual void device_validity_check(validity_checker &valid) const; + virtual void device_start(); + virtual void device_reset(); + + // device_nvram_interface overrides + virtual void nvram_default(); + virtual void nvram_read(emu_file &file); + virtual void nvram_write(emu_file &file); + inline UINT8 rtc_read(UINT8 offset); + inline void rtc_write(UINT8 offset,UINT8 data); + + static TIMER_CALLBACK( rtc_inc_callback ); + + int m_latch; + int m_reset_line; + int m_clock_line; + + + rtc9701_state_t rtc_state; + int cmd_stream_pos; + int current_cmd; + + int rtc9701_address_pos; + int rtc9701_current_address; + + UINT16 rtc9701_current_data; + int rtc9701_data_pos; + + UINT16 rtc9701_data[0x100]; + + rtc_regs_t m_rtc; +}; + + +// device type definition +extern const device_type rtc9701; + + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + + + +#endif diff --git a/src/devices/machine/s2636.c b/src/devices/machine/s2636.c new file mode 100644 index 00000000000..c3cf7bb8178 --- /dev/null +++ b/src/devices/machine/s2636.c @@ -0,0 +1,367 @@ +// license:BSD-3-Clause +// copyright-holders:Mariusz Wojcieszek, Peter Trauner +/********************************************************************** + + Signetics 2636 video chip + + PVI REGISTER DESCRIPTION + ------------------------ + + | bit |R/W| description + byte | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | | + | | | + FC0 | size 4| size 3| size 2| size 1| W | size of the 4 objects(=sprites) + | | | + FC1 | |C1 |C2 |C3 |C1 |C2 |C3 | W | colors of the 4 objects + | | color 1 | color 2 | | + FC2 | |C1 |C2 |C3 |C1 |C2 |C3 | W | + | | color 3 | color 4 | | + | | | + FC3 | |sh |pos| W | 1=shape 0=position + | | | display format and position + FC4 | (free) | | + FC5 | (free) | | + | | | + FC6 | |C1 |C2 |C3 |BG |scrn colr | W | background lock and color + | |backg colr |enb|C1 |C2 |C3 | | 3="enable" + | | | + FC7 | sound | W | squarewave output + | | | + FC8 | N1 | N2 | W | range of the 4 display digits + FC9 | N3 | N4 | W | + | | | + |obj/backgrnd |complete object| R | + FCA | 1 | 2 | 3 | 4 | 1 | 2 | 3 | 4 | | + | | | + FCB | |VR-| object collisions | R | Composition of object and back- + | |LE |1/2|1/3|1/3|1/4|2/4|3/4| | ground,collision detection and + | | | object display as a state display + | | | for the status register.Set VRLE. + | | | wait for VRST.Read out or transmit + | | | [copy?] all bits until reset by + | | | VRST. + | | | + FCC | PORT1 | R | PORT1 and PORT2 for the range of + FCD | PORT2 | | the A/D conversion.Cleared by VRST + FCE | (free) | | + FCF | (free) | | + + + Size control by byte FC0 + + bit matrix + |0|0| 8x10 + |0|1| 16x20 + |1|0| 32x40 + |1|1| 64x80 + + CE1 and not-CE2 are outputs from the PVI.$E80..$EFF also controls the + analog multiplexer. + + + SPRITES + ------- + + each object field: (=sprite data structure) + + 0 \ 10 bytes of bitmap (Each object is 8 pixels wide.) + 9 / + A HC horizontal object coordinate + B HCB horizontal duplicate coordinate + C VC vertical object coordinate + D VCB vertical duplicate coordinate + +*************************************************************/ + +#include "emu.h" +#include "machine/s2636.h" + + +/************************************* + * + * Device interface + * + *************************************/ + +const device_type S2636 = &device_creator; + +s2636_device::s2636_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, S2636, "Signetics 2636", tag, owner, clock, "s2636", __FILE__), + device_video_interface(mconfig, *this), + device_sound_interface(mconfig, *this), + m_channel(NULL), + m_size(0), + m_pos(0), + m_level(0), + m_work_ram_size(0), + m_y_offset(0), + m_x_offset(0) +{ + for (int i = 0; i < 1; i++) + m_reg[i] = 0; +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void s2636_device::device_start() +{ + int width = m_screen->width(); + int height = m_screen->height(); + + m_work_ram.resize(m_work_ram_size); + memset(&m_work_ram[0], 0, m_work_ram_size); + m_bitmap.resize(width, height); + m_collision_bitmap.resize(width, height); + + save_item(NAME(m_work_ram)); + save_item(NAME(m_bitmap)); + save_item(NAME(m_collision_bitmap)); + + m_channel = machine().sound().stream_alloc(*this, 0, 1, machine().sample_rate()); + save_item(NAME(m_size)); + save_item(NAME(m_pos)); + save_item(NAME(m_level)); + save_item(NAME(m_reg)); +} + +/************************************* + * + * Constants + * + *************************************/ + +#define SPRITE_WIDTH (8) +#define SPRITE_HEIGHT (10) + +static const int sprite_offsets[4] = { 0x00, 0x10, 0x20, 0x40 }; + + +/************************************* + * + * Draw a sprite + * + *************************************/ + +static void draw_sprite( UINT8 *gfx, int color, int y, int x, int expand, int or_mode, bitmap_ind16 &bitmap, const rectangle &cliprect ) +{ + /* for each row */ + for (int sy = 0; sy < SPRITE_HEIGHT; sy++) + { + /* for each pixel on the row */ + for (int sx = 0; sx < SPRITE_WIDTH; sx++) + { + /* each pixel can be expanded */ + for (int ey = 0; ey <= expand; ey++) + { + for (int ex = 0; ex <= expand; ex++) + { + /* compute effective destination pixel */ + int ty = y + sy * (expand + 1) + ey; + int tx = x + sx * (expand + 1) + ex; + + /* get out if outside the drawing region */ + if (!cliprect.contains(tx, ty)) + continue; + + /* get out if current image bit is transparent */ + if (((gfx[sy] << sx) & 0x80) == 0x00) + continue; + + if (or_mode) + bitmap.pix16(ty, tx) = 0x08 | bitmap.pix16(ty, tx) | color; + else + bitmap.pix16(ty, tx) = 0x08 | color; + } + } + } + } +} + + +/************************************* + * + * Collision detection + * + *************************************/ + +int s2636_device::check_collision( int spriteno1, int spriteno2, const rectangle &cliprect ) +{ + int checksum = 0; + + UINT8* attr1 = &m_work_ram[sprite_offsets[spriteno1]]; + UINT8* attr2 = &m_work_ram[sprite_offsets[spriteno2]]; + + /* TODO: does not check shadow sprites yet */ + + m_collision_bitmap.fill(0, cliprect); + + if ((attr1[0x0a] != 0xff) && (attr2[0x0a] != 0xff)) + { + int x, y; + + int x1 = attr1[0x0a] + m_x_offset; + int y1 = attr1[0x0c] + m_y_offset; + int x2 = attr2[0x0a] + m_x_offset; + int y2 = attr2[0x0c] + m_y_offset; + + int expand1 = (m_work_ram[0xc0] >> (spriteno1 << 1)) & 0x03; + int expand2 = (m_work_ram[0xc0] >> (spriteno2 << 1)) & 0x03; + + /* draw first sprite */ + draw_sprite(attr1, 1, y1, x1, expand1, FALSE, m_collision_bitmap, cliprect); + + /* get fingerprint */ + for (x = x1; x < x1 + SPRITE_WIDTH; x++) + for (y = y1; y < y1 + SPRITE_HEIGHT; y++) + { + if (!cliprect.contains(x, y)) + continue; + + checksum = checksum + m_collision_bitmap.pix16(y, x); + } + + /* black out second sprite */ + draw_sprite(attr2, 0, y2, x2, expand2, FALSE, m_collision_bitmap, cliprect); + + /* remove fingerprint */ + for (x = x1; x < x1 + SPRITE_WIDTH; x++) + for (y = y1; y < y1 + SPRITE_HEIGHT; y++) + { + if (!cliprect.contains(x, y)) + continue; + + checksum = checksum - m_collision_bitmap.pix16(y, x); + } + } + + return (checksum != 0); +} + + + +/************************************* + * + * Main drawing + * + *************************************/ + +bitmap_ind16 &s2636_device::update( const rectangle &cliprect ) +{ + UINT8 collision = 0; + int spriteno; + + m_bitmap.fill(0, cliprect); + + for (spriteno = 0; spriteno < 4; spriteno++) + { + int color, expand, x, y; + UINT8* attr = &m_work_ram[sprite_offsets[spriteno]]; + + /* get out if sprite is turned off */ + if (attr[0x0a] == 0xff) + continue; + + x = attr[0x0a] + m_x_offset; + y = attr[0x0c] + m_y_offset; + + color = (m_work_ram[0xc1 + (spriteno >> 1)] >> ((spriteno & 1) ? 0 : 3)) & 0x07; + expand = (m_work_ram[0xc0] >> (spriteno << 1)) & 0x03; + + draw_sprite(attr, color, y, x, expand, TRUE, m_bitmap, cliprect); + + /* bail if no shadow sprites */ + if ((attr[0x0b] == 0xff) || (attr[0x0d] == 0xfe)) + continue; + + x = attr[0x0b] + m_x_offset; + + while (y < 0xff) + { + y = y + SPRITE_HEIGHT + attr[0x0d]; + + draw_sprite(attr, color, y, x, expand, TRUE, m_bitmap, cliprect); + } + } + + /* collision detection */ + if (check_collision(0, 1, cliprect)) collision |= 0x20; + if (check_collision(0, 2, cliprect)) collision |= 0x10; + if (check_collision(0, 3, cliprect)) collision |= 0x08; + if (check_collision(1, 2, cliprect)) collision |= 0x04; + if (check_collision(1, 3, cliprect)) collision |= 0x02; + if (check_collision(2, 3, cliprect)) collision |= 0x01; + + m_work_ram[0xcb] = collision; + + return m_bitmap; +} + + +/************************************* + * + * Work RAM access handlers + * + *************************************/ + +WRITE8_MEMBER( s2636_device::work_ram_w ) +{ + assert(offset < m_work_ram_size); + + if ( offset == 0xc7 ) + { + soundport_w(0, data); + } + + m_work_ram[offset] = data; +} + + +READ8_MEMBER( s2636_device::work_ram_r ) +{ + assert(offset < m_work_ram_size); + + return m_work_ram[offset]; +} + +/* Sound */ + +void s2636_device::soundport_w (int offset, int data) +{ + m_channel->update(); + m_reg[offset] = data; + switch (offset) + { + case 0: + m_pos = 0; + m_level = TRUE; + // frequency 7874/(data+1) + m_size = machine().sample_rate() * (data + 1) /7874; + break; + } +} + + +//------------------------------------------------- +// sound_stream_update - handle a stream update +//------------------------------------------------- + +void s2636_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + int i; + stream_sample_t *buffer = outputs[0]; + + for (i = 0; i < samples; i++, buffer++) + { + *buffer = 0; + if (m_reg[0] && m_pos <= m_size / 2) + { + *buffer = 0x7fff; + } + if (m_pos <= m_size) + m_pos++; + if (m_pos > m_size) + m_pos = 0; + } +} diff --git a/src/devices/machine/s2636.h b/src/devices/machine/s2636.h new file mode 100644 index 00000000000..082eeabab9f --- /dev/null +++ b/src/devices/machine/s2636.h @@ -0,0 +1,84 @@ +// license:BSD-3-Clause +// copyright-holders:Mariusz Wojcieszek, Peter Trauner +/********************************************************************** + + Signetics 2636 video chip + +**********************************************************************/ + +#ifndef __S2636_H__ +#define __S2636_H__ + + +#define S2636_IS_PIXEL_DRAWN(p) (((p) & 0x08) ? TRUE : FALSE) +#define S2636_PIXEL_COLOR(p) ((p) & 0x07) + +/************************************* + * + * Device configuration macros + * + *************************************/ + +class s2636_device : public device_t, + public device_video_interface, + public device_sound_interface +{ +public: + s2636_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + ~s2636_device() {} + + static void set_workram_size(device_t &device, int size) { downcast(device).m_work_ram_size = size; } + static void set_offsets(device_t &device, int y_offset, int x_offset) + { + s2636_device &dev = downcast(device); + dev.m_x_offset = x_offset; + dev.m_y_offset = y_offset; + } + + // returns a BITMAP_FORMAT_IND16 bitmap the size of the screen + // D0-D2 of each pixel is the pixel color + // D3 indicates whether the S2636 drew this pixel - 0 = not drawn, 1 = drawn + bitmap_ind16 &update(const rectangle &cliprect); + + DECLARE_WRITE8_MEMBER( work_ram_w ); + DECLARE_READ8_MEMBER( work_ram_r ); + + void soundport_w(int mode, int data); + +protected: + // device-level overrides + virtual void device_start(); + + // sound stream update overrides + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + +private: + // internal state + dynamic_buffer m_work_ram; + bitmap_ind16 m_bitmap; + bitmap_ind16 m_collision_bitmap; + + sound_stream *m_channel; + UINT8 m_reg[1]; + int m_size; + int m_pos; + unsigned m_level; + + int m_work_ram_size; + int m_y_offset; + int m_x_offset; + + int check_collision( int spriteno1, int spriteno2, const rectangle &cliprect ); +}; + +extern const device_type S2636; + + +#define MCFG_S2636_OFFSETS(_yoffs, _xoffs) \ + s2636_device::set_offsets(*device, _yoffs, _xoffs); + +#define MCFG_S2636_WORKRAM_SIZE(_size) \ + s2636_device::set_workram_size(*device, _size); + + +#endif /* __S2636_H__ */ diff --git a/src/devices/machine/s3520cf.c b/src/devices/machine/s3520cf.c new file mode 100644 index 00000000000..3a183982298 --- /dev/null +++ b/src/devices/machine/s3520cf.c @@ -0,0 +1,265 @@ +// license:BSD-3-Clause +// copyright-holders:Angelo Salese +/*************************************************************************** + +Seiko/Epson S-3520CF + +preliminary device by Angelo Salese + +TODO: +- kludge on address? +- SRAM hook-ups; +- SRAM load/save; +- system bits; + +***************************************************************************/ + +#include "emu.h" +#include "machine/s3520cf.h" + + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +// device type definition +const device_type S3520CF = &device_creator; + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// s3520cf_device - constructor +//------------------------------------------------- + +s3520cf_device::s3520cf_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, S3520CF, "S-3520CF RTC", tag, owner, clock, "s3520cf", __FILE__) +{ +} + +void s3520cf_device::timer_callback() +{ + static const UINT8 dpm[12] = { 0x31, 0x28, 0x31, 0x30, 0x31, 0x30, 0x31, 0x31, 0x30, 0x31, 0x30, 0x31 }; + int dpm_count; + + m_rtc.sec++; + + if((m_rtc.sec & 0x0f) >= 0x0a) { m_rtc.sec+=0x10; m_rtc.sec&=0xf0; } + if((m_rtc.sec & 0xf0) >= 0x60) { m_rtc.min++; m_rtc.sec = 0; } + if((m_rtc.min & 0x0f) >= 0x0a) { m_rtc.min+=0x10; m_rtc.min&=0xf0; } + if((m_rtc.min & 0xf0) >= 0x60) { m_rtc.hour++; m_rtc.min = 0; } + if((m_rtc.hour & 0x0f) >= 0x0a) { m_rtc.hour+=0x10; m_rtc.hour&=0xf0; } + if((m_rtc.hour & 0xff) >= 0x24) { m_rtc.day++; m_rtc.wday++; m_rtc.hour = 0; } + if(m_rtc.wday >= 7) { m_rtc.wday = 0; } + if((m_rtc.day & 0x0f) >= 0x0a) { m_rtc.day+=0x10; m_rtc.day&=0xf0; } + + /* TODO: crude leap year support */ + dpm_count = (m_rtc.month & 0xf) + (((m_rtc.month & 0x10) >> 4)*10)-1; + + if(((m_rtc.year % 4) == 0) && m_rtc.month == 2) + { + if((m_rtc.day & 0xff) >= dpm[dpm_count]+1+1) + { m_rtc.month++; m_rtc.day = 0x01; } + } + else if((m_rtc.day & 0xff) >= dpm[dpm_count]+1){ m_rtc.month++; m_rtc.day = 0x01; } + if((m_rtc.month & 0x0f) >= 0x0a) { m_rtc.month = 0x10; } + if(m_rtc.month >= 0x13) { m_rtc.year++; m_rtc.month = 1; } + if((m_rtc.year & 0x0f) >= 0x0a) { m_rtc.year+=0x10; m_rtc.year&=0xf0; } + if((m_rtc.year & 0xf0) >= 0xa0) { m_rtc.year = 0; } //1901-2000 possible timeframe +} + +TIMER_CALLBACK( s3520cf_device::rtc_inc_callback ) +{ + reinterpret_cast(ptr)->timer_callback(); +} + +//------------------------------------------------- +// device_validity_check - perform validity checks +// on this device +//------------------------------------------------- + +void s3520cf_device::device_validity_check(validity_checker &valid) const +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void s3520cf_device::device_start() +{ + /* let's call the timer callback every second for now */ + machine().scheduler().timer_pulse(attotime::from_hz(clock() / XTAL_32_768kHz), FUNC(rtc_inc_callback), 0, (void *)this); + + system_time systime; + machine().base_datetime(systime); + + m_rtc.day = ((systime.local_time.mday / 10)<<4) | ((systime.local_time.mday % 10) & 0xf); + m_rtc.month = (((systime.local_time.month+1) / 10) << 4) | (((systime.local_time.month+1) % 10) & 0xf); + m_rtc.wday = systime.local_time.weekday; + m_rtc.year = (((systime.local_time.year % 100)/10)<<4) | ((systime.local_time.year % 10) & 0xf); + m_rtc.hour = ((systime.local_time.hour / 10)<<4) | ((systime.local_time.hour % 10) & 0xf); + m_rtc.min = ((systime.local_time.minute / 10)<<4) | ((systime.local_time.minute % 10) & 0xf); + m_rtc.sec = ((systime.local_time.second / 10)<<4) | ((systime.local_time.second % 10) & 0xf); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void s3520cf_device::device_reset() +{ + m_mode = 0; +} + +//------------------------------------------------- +// rtc_read - used to route RTC reading registers +//------------------------------------------------- + +inline UINT8 s3520cf_device::rtc_read(UINT8 offset) +{ + UINT8 res; + + res = 0; + + if(m_mode != 0) + { + if(offset == 0xf) + res = (m_sysr << 3) | m_mode; + else + { + res = 0; + printf("Warning: S-3520CF RTC reads SRAM %02x %02x\n",offset,m_mode); + } + } + else + { + switch(offset) + { + case 0x0: res = m_rtc.sec & 0xf; break; + case 0x1: res = m_rtc.sec >> 4; break; + case 0x2: res = m_rtc.min & 0xf; break; + case 0x3: res = m_rtc.min >> 4; break; + case 0x4: res = m_rtc.hour & 0xf; break; + case 0x5: res = m_rtc.hour >> 4; break; + case 0x6: res = m_rtc.wday & 0xf; break; + case 0x7: res = m_rtc.day & 0xf; break; + case 0x8: res = m_rtc.day >> 4; break; + case 0x9: res = m_rtc.month & 0xf; break; + case 0xa: res = m_rtc.month >> 4; break; + case 0xb: res = m_rtc.year & 0xf; break; + case 0xc: res = m_rtc.year >> 4; break; + } + } + + return res; +} + +inline void s3520cf_device::rtc_write(UINT8 offset,UINT8 data) +{ + if(offset == 0xf) + { + m_mode = data & 3; + m_sysr = (data & 8) >> 3; + printf("%02x\n",data); + } + else + { + if(m_mode != 0) + printf("Warning: S-3520CF RTC writes SRAM %02x %d\n",offset,m_mode); + } +} + + +//************************************************************************** +// READ/WRITE HANDLERS +//************************************************************************** + +READ_LINE_MEMBER( s3520cf_device::read_bit ) +{ + return m_read_latch; +} + +WRITE_LINE_MEMBER( s3520cf_device::set_dir_line ) +{ + //printf("%d DIR LINE\n",state); + + m_dir = state; +} + +WRITE_LINE_MEMBER( s3520cf_device::set_cs_line ) +{ + m_reset_line = state; + + //printf("%d CS LINE\n",state); + + if(m_reset_line != CLEAR_LINE) + { + //printf("Reset asserted\n"); + m_current_cmd = 0; + m_cmd_stream_pos = 0; + m_rtc_state = RTC_SET_ADDRESS; + //m_latch = 0; + } +} + +WRITE_LINE_MEMBER( s3520cf_device::write_bit ) +{ + m_latch = state; +// printf("%d LATCH LINE\n",state); +} + +WRITE_LINE_MEMBER( s3520cf_device::set_clock_line ) +{ + if(state == 1 && m_reset_line == CLEAR_LINE) + { + //printf("%d %d\n",m_latch, m_dir); + + switch(m_rtc_state) + { + case RTC_SET_ADDRESS: + m_current_cmd = (m_current_cmd >> 1) | ((m_latch<<3)&8); + m_cmd_stream_pos++; + + if(m_cmd_stream_pos == 4) + { + m_rtc_addr = (m_current_cmd) & 0xf; + m_rtc_state = RTC_SET_DATA; + m_cmd_stream_pos = 0; + m_current_cmd = 0; + } + break; + case RTC_SET_DATA: + if(m_dir == 1) // READ + { + //if(m_cmd_stream_pos == 0) + { + //printf("%02x %d\n",m_rtc_addr,m_cmd_stream_pos); + } + m_read_latch = (rtc_read((m_rtc_addr+1) & 0xf) >> (m_cmd_stream_pos)) & 1; /* TODO: +1??? */ + } + + m_current_cmd = (m_current_cmd >> 1) | ((m_latch<<3)&8); + m_cmd_stream_pos++; + if(m_cmd_stream_pos == 4) + { + if(m_dir == 0) // WRITE + { + //printf("%02x %02x\n",m_rtc_addr,m_current_cmd); + rtc_write((m_rtc_addr - 1) & 0xf,m_current_cmd); /* TODO: -1??? */ + } + + m_rtc_addr = m_current_cmd; + m_rtc_state = RTC_SET_ADDRESS; + m_cmd_stream_pos = 0; + m_current_cmd = 0; + } + break; + } + } +} diff --git a/src/devices/machine/s3520cf.h b/src/devices/machine/s3520cf.h new file mode 100644 index 00000000000..af7ba33a835 --- /dev/null +++ b/src/devices/machine/s3520cf.h @@ -0,0 +1,91 @@ +// license:BSD-3-Clause +// copyright-holders:Angelo Salese +/*************************************************************************** + +Seiko/Epson S-3520CF + +***************************************************************************/ + +#pragma once + +#ifndef __S3520CFDEV_H__ +#define __S3520CFDEV_H__ + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_S3520CF_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, S3520CF, XTAL_32_768kHz) + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +enum s3520cf_state_t +{ + RTC_SET_ADDRESS = 0, + RTC_SET_DATA +}; + +struct rtc_regs_t +{ + UINT8 sec, min, hour, day, wday, month, year; +}; + + +// ======================> s3520cf_device + +class s3520cf_device : public device_t +{ +public: + // construction/destruction + s3520cf_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // I/O operations + DECLARE_READ_LINE_MEMBER( read_bit ); + DECLARE_WRITE_LINE_MEMBER( set_dir_line ); + DECLARE_WRITE_LINE_MEMBER( set_cs_line ); + DECLARE_WRITE_LINE_MEMBER( set_clock_line ); + DECLARE_WRITE_LINE_MEMBER( write_bit ); + void timer_callback(); + +protected: + // device-level overrides + virtual void device_validity_check(validity_checker &valid) const; + virtual void device_start(); + virtual void device_reset(); + inline UINT8 rtc_read(UINT8 offset); + inline void rtc_write(UINT8 offset,UINT8 data); + + static TIMER_CALLBACK( rtc_inc_callback ); + + int m_dir; + int m_latch; + int m_reset_line; + int m_read_latch; + UINT8 m_current_cmd; + UINT8 m_cmd_stream_pos; + UINT8 m_rtc_addr; + UINT8 m_mode, m_sysr; + + s3520cf_state_t m_rtc_state; + rtc_regs_t m_rtc; + +}; + + +// device type definition +extern const device_type S3520CF; + + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + + + +#endif diff --git a/src/devices/machine/s3c2400.c b/src/devices/machine/s3c2400.c new file mode 100644 index 00000000000..d47e81b08ce --- /dev/null +++ b/src/devices/machine/s3c2400.c @@ -0,0 +1,140 @@ +// license:BSD-3-Clause +// copyright-holders:Tim Schuerewegen +/******************************************************************************* + + Samsung S3C2400 + + (c) 2010 Tim Schuerewegen + +*******************************************************************************/ + +#include "emu.h" +#include "cpu/arm7/arm7.h" +#include "cpu/arm7/arm7core.h" +#include "machine/s3c2400.h" +#include "sound/dac.h" + +#define VERBOSE_LEVEL ( 0 ) + +INLINE void ATTR_PRINTF(3,4) verboselog( running_machine &machine, int n_level, const char *s_fmt, ...) +{ + if (VERBOSE_LEVEL >= n_level) + { + va_list v; + char buf[32768]; + va_start( v, s_fmt); + vsprintf( buf, s_fmt, v); + va_end( v); + logerror( "%s: %s", machine.describe_context( ), buf); + } +} + +#define DEVICE_S3C2400 +#define S3C24_CLASS_NAME s3c2400_device +#include "machine/s3c24xx.inc" +#undef DEVICE_S3C2400 + +UINT32 s3c2400_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + return s3c24xx_video_update(screen, bitmap, cliprect); +} + +const device_type S3C2400 = &device_creator; + +s3c2400_device::s3c2400_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, S3C2400, "Samsung S3C2400", tag, owner, clock, "s3c2400", __FILE__), + m_palette(*this), + m_cpu(*this, ":maincpu"), + m_pin_r_cb(*this), + m_pin_w_cb(*this), + m_port_r_cb(*this), + m_port_w_cb(*this), + m_scl_w_cb(*this), + m_sda_r_cb(*this), + m_sda_w_cb(*this), + m_data_r_cb(*this), + m_data_w_cb(*this), + m_flags(0) +{ + memset(&m_memcon, 0, sizeof(m_memcon)); + memset(&m_usbhost, 0, sizeof(m_usbhost)); + memset(&m_irq, 0, sizeof(m_irq)); + memset(m_dma, 0, sizeof(m_dma)); + memset(&m_clkpow, 0, sizeof(m_clkpow)); + memset(&m_lcd, 0, sizeof(m_lcd)); + memset(&m_lcdpal, 0, sizeof(m_lcdpal)); + memset(m_uart, 0, sizeof(m_uart)); + memset(&m_pwm, 0, sizeof(m_pwm)); + memset(&m_usbdev, 0, sizeof(m_usbdev)); + memset(&m_wdt, 0, sizeof(m_wdt)); + memset(&m_iic, 0, sizeof(m_iic)); + memset(&m_iis, 0, sizeof(m_iis)); + memset(&m_gpio, 0, sizeof(m_gpio)); + memset(&m_rtc, 0, sizeof(m_rtc)); + memset(&m_adc, 0, sizeof(m_adc)); + memset(m_spi, 0, sizeof(m_spi)); + memset(&m_mmc, 0, sizeof(m_mmc)); +} + +s3c2400_device::~s3c2400_device() +{ +} + +//------------------------------------------------- +// static_set_palette_tag: Set the tag of the +// palette device +//------------------------------------------------- + +void s3c2400_device::static_set_palette_tag(device_t &device, const char *tag) +{ + downcast(device).m_palette.set_tag(tag); +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void s3c2400_device::device_start() +{ + s3c24xx_device_start(); + + address_space &space = m_cpu->memory().space( AS_PROGRAM); + space.install_readwrite_handler(0x14000000, 0x1400003b, read32_delegate(FUNC(s3c2400_device::s3c24xx_memcon_r), this), write32_delegate(FUNC(s3c2400_device::s3c24xx_memcon_w), this)); + space.install_readwrite_handler(0x14200000, 0x1420005b, read32_delegate(FUNC(s3c2400_device::s3c24xx_usb_host_r), this), write32_delegate(FUNC(s3c2400_device::s3c24xx_usb_host_w), this)); + space.install_readwrite_handler(0x14400000, 0x14400017, read32_delegate(FUNC(s3c2400_device::s3c24xx_irq_r), this), write32_delegate(FUNC(s3c2400_device::s3c24xx_irq_w), this)); + space.install_readwrite_handler(0x14600000, 0x1460001b, read32_delegate(FUNC(s3c2400_device::s3c24xx_dma_0_r), this), write32_delegate(FUNC(s3c2400_device::s3c24xx_dma_0_w), this)); + space.install_readwrite_handler(0x14600020, 0x1460003b, read32_delegate(FUNC(s3c2400_device::s3c24xx_dma_1_r), this), write32_delegate(FUNC(s3c2400_device::s3c24xx_dma_1_w), this)); + space.install_readwrite_handler(0x14600040, 0x1460005b, read32_delegate(FUNC(s3c2400_device::s3c24xx_dma_2_r), this), write32_delegate(FUNC(s3c2400_device::s3c24xx_dma_2_w), this)); + space.install_readwrite_handler(0x14600060, 0x1460007b, read32_delegate(FUNC(s3c2400_device::s3c24xx_dma_3_r), this), write32_delegate(FUNC(s3c2400_device::s3c24xx_dma_3_w), this)); + space.install_readwrite_handler(0x14800000, 0x14800017, read32_delegate(FUNC(s3c2400_device::s3c24xx_clkpow_r), this), write32_delegate(FUNC(s3c2400_device::s3c24xx_clkpow_w), this)); + space.install_readwrite_handler(0x14a00000, 0x14a003ff, read32_delegate(FUNC(s3c2400_device::s3c24xx_lcd_r), this), write32_delegate(FUNC(s3c2400_device::s3c24xx_lcd_w), this)); + space.install_readwrite_handler(0x14a00400, 0x14a007ff, read32_delegate(FUNC(s3c2400_device::s3c24xx_lcd_palette_r), this), write32_delegate(FUNC(s3c2400_device::s3c24xx_lcd_palette_w), this)); + space.install_readwrite_handler(0x15000000, 0x1500002b, read32_delegate(FUNC(s3c2400_device::s3c24xx_uart_0_r), this), write32_delegate(FUNC(s3c2400_device::s3c24xx_uart_0_w), this)); + space.install_readwrite_handler(0x15004000, 0x1500402b, read32_delegate(FUNC(s3c2400_device::s3c24xx_uart_1_r), this), write32_delegate(FUNC(s3c2400_device::s3c24xx_uart_1_w), this)); + space.install_readwrite_handler(0x15100000, 0x15100043, read32_delegate(FUNC(s3c2400_device::s3c24xx_pwm_r), this), write32_delegate(FUNC(s3c2400_device::s3c24xx_pwm_w), this)); + space.install_readwrite_handler(0x15200140, 0x152001fb, read32_delegate(FUNC(s3c2400_device::s3c24xx_usb_device_r), this), write32_delegate(FUNC(s3c2400_device::s3c24xx_usb_device_w), this)); + space.install_readwrite_handler(0x15300000, 0x1530000b, read32_delegate(FUNC(s3c2400_device::s3c24xx_wdt_r), this), write32_delegate(FUNC(s3c2400_device::s3c24xx_wdt_w), this)); + space.install_readwrite_handler(0x15400000, 0x1540000f, read32_delegate(FUNC(s3c2400_device::s3c24xx_iic_r), this), write32_delegate(FUNC(s3c2400_device::s3c24xx_iic_w), this)); + space.install_readwrite_handler(0x15508000, 0x15508013, read32_delegate(FUNC(s3c2400_device::s3c24xx_iis_r), this), write32_delegate(FUNC(s3c2400_device::s3c24xx_iis_w), this)); + space.install_readwrite_handler(0x15600000, 0x1560005b, read32_delegate(FUNC(s3c2400_device::s3c24xx_gpio_r), this), write32_delegate(FUNC(s3c2400_device::s3c24xx_gpio_w), this)); + space.install_readwrite_handler(0x15700040, 0x1570008b, read32_delegate(FUNC(s3c2400_device::s3c24xx_rtc_r), this), write32_delegate(FUNC(s3c2400_device::s3c24xx_rtc_w), this)); + space.install_readwrite_handler(0x15800000, 0x15800007, read32_delegate(FUNC(s3c2400_device::s3c24xx_adc_r), this), write32_delegate(FUNC(s3c2400_device::s3c24xx_adc_w), this)); + space.install_readwrite_handler(0x15900000, 0x15900017, read32_delegate(FUNC(s3c2400_device::s3c24xx_spi_0_r), this), write32_delegate(FUNC(s3c2400_device::s3c24xx_spi_0_w), this)); + space.install_readwrite_handler(0x15a00000, 0x15a0003f, read32_delegate(FUNC(s3c2400_device::s3c24xx_mmc_r), this), write32_delegate(FUNC(s3c2400_device::s3c24xx_mmc_w), this)); + + s3c24xx_video_start(); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void s3c2400_device::device_reset() +{ + s3c24xx_device_reset(); +} + +void s3c2400_device::s3c2400_uart_fifo_w(int uart, UINT8 data) +{ + s3c24xx_uart_fifo_w(uart, data); +} diff --git a/src/devices/machine/s3c2400.h b/src/devices/machine/s3c2400.h new file mode 100644 index 00000000000..f274e5ad36d --- /dev/null +++ b/src/devices/machine/s3c2400.h @@ -0,0 +1,894 @@ +// license:BSD-3-Clause +// copyright-holders:Tim Schuerewegen +/******************************************************************************* + + Samsung S3C2400 + +*******************************************************************************/ + +#ifndef __S3C2400_H__ +#define __S3C2400_H__ + + +/******************************************************************************* + MACROS / CONSTANTS +*******************************************************************************/ + +#define S3C2400_TAG "s3c2400" + +#define MCFG_S3C2400_PALETTE(_palette_tag) \ + s3c2400_device::static_set_palette_tag(*device, "^" _palette_tag); + +#define MCFG_S3C2400_CORE_PIN_R_CB(_devcb) \ + devcb = &s3c2400_device::set_core_pin_r_callback(*device, DEVCB_##_devcb); + +#define MCFG_S3C2400_CORE_PIN_W_CB(_devcb) \ + devcb = &s3c2400_device::set_core_pin_w_callback(*device, DEVCB_##_devcb); + +#define MCFG_S3C2400_GPIO_PORT_R_CB(_devcb) \ + devcb = &s3c2400_device::set_gpio_port_r_callback(*device, DEVCB_##_devcb); + +#define MCFG_S3C2400_GPIO_PORT_W_CB(_devcb) \ + devcb = &s3c2400_device::set_gpio_port_w_callback(*device, DEVCB_##_devcb); + +#define MCFG_S3C2400_I2C_SCL_W_CB(_devcb) \ + devcb = &s3c2400_device::set_i2c_scl_w_callback(*device, DEVCB_##_devcb); + +#define MCFG_S3C2400_I2C_SDA_R_CB(_devcb) \ + devcb = &s3c2400_device::set_i2c_sda_r_callback(*device, DEVCB_##_devcb); + +#define MCFG_S3C2400_I2C_SDA_W_CB(_devcb) \ + devcb = &s3c2400_device::set_i2c_sda_w_callback(*device, DEVCB_##_devcb); + +#define MCFG_S3C2400_ADC_DATA_R_CB(_devcb) \ + devcb = &s3c2400_device::set_adc_data_r_callback(*device, DEVCB_##_devcb); + +#define MCFG_S3C2400_I2S_DATA_W_CB(_devcb) \ + devcb = &s3c2400_device::set_i2s_data_w_callback(*device, DEVCB_##_devcb); + +#define MCFG_S3C2400_LCD_FLAGS(_flags) \ + s3c2400_device::set_lcd_flags(*device, _flags); + +enum +{ + S3C2400_GPIO_PORT_A = 0, + S3C2400_GPIO_PORT_B, + S3C2400_GPIO_PORT_C, + S3C2400_GPIO_PORT_D, + S3C2400_GPIO_PORT_E, + S3C2400_GPIO_PORT_F, + S3C2400_GPIO_PORT_G +}; + + +/******************************************************************************* + MACROS & CONSTANTS +*******************************************************************************/ + +/* Interface */ + +#define S3C24XX_INTERFACE_LCD_REVERSE 1 + +/* Memory Controller */ + +#define S3C24XX_BASE_MEMCON 0x14000000 + +/* USB Host Controller */ + +#define S3C24XX_BASE_USBHOST 0x14200000 + +/* Interrupt Controller */ + +#define S3C24XX_BASE_INT 0x14400000 + +#define S3C24XX_SRCPND (0x00 / 4) // Interrupt Request Status +#define S3C24XX_INTMOD (0x04 / 4) // Interrupt Mode Control +#define S3C24XX_INTMSK (0x08 / 4) // Interrupt Mask Control +#define S3C24XX_PRIORITY (0x0C / 4) // IRQ Priority Control +#define S3C24XX_INTPND (0x10 / 4) // Interrupt Request Status +#define S3C24XX_INTOFFSET (0x14 / 4) // Interrupt Request Source Offset + +/* DMA */ + +#define S3C24XX_BASE_DMA_0 0x14600000 +#define S3C24XX_BASE_DMA_1 0x14600020 +#define S3C24XX_BASE_DMA_2 0x14600040 +#define S3C24XX_BASE_DMA_3 0x14600060 + +#define S3C24XX_DISRC (0x00 / 4) // DMA Initial Source +#define S3C24XX_DIDST (0x04 / 4) // DMA Initial Destination +#define S3C24XX_DCON (0x08 / 4) // DMA Control +#define S3C24XX_DSTAT (0x0C / 4) // DMA Count +#define S3C24XX_DCSRC (0x10 / 4) // DMA Current Source Address +#define S3C24XX_DCDST (0x14 / 4) // DMA Current Destination Address +#define S3C24XX_DMASKTRIG (0x18 / 4) // DMA Mask Trigger + +/* Clock & Power Management */ + +#define S3C24XX_BASE_CLKPOW 0x14800000 + +#define S3C24XX_LOCKTIME (0x00 / 4) // PLL Lock Time Counter +#define S3C24XX_MPLLCON (0x04 / 4) // MPLL Control +#define S3C24XX_UPLLCON (0x08 / 4) // UPLL Control +#define S3C24XX_CLKCON (0x0C / 4) // Clock Generator Control +#define S3C24XX_CLKSLOW (0x10 / 4) // Slow Clock Control +#define S3C24XX_CLKDIVN (0x14 / 4) // Clock Divider Control + +/* LCD Controller */ + +#define S3C24XX_BASE_LCD 0x14a00000 +#define S3C24XX_BASE_LCDPAL 0x14a00400 + +#define S3C24XX_LCDCON1 (0x00 / 4) // LCD Control 1 +#define S3C24XX_LCDCON2 (0x04 / 4) // LCD Control 2 +#define S3C24XX_LCDCON3 (0x08 / 4) // LCD Control 3 +#define S3C24XX_LCDCON4 (0x0C / 4) // LCD Control 4 +#define S3C24XX_LCDCON5 (0x10 / 4) // LCD Control 5 +#define S3C24XX_LCDSADDR1 (0x14 / 4) // STN/TFT: Frame Buffer Start Address 1 +#define S3C24XX_LCDSADDR2 (0x18 / 4) // STN/TFT: Frame Buffer Start Address 2 +#define S3C24XX_LCDSADDR3 (0x1C / 4) // STN/TFT: Virtual Screen Address Set +#define S3C24XX_REDLUT (0x20 / 4) // STN: Red Lookup Table +#define S3C24XX_GREENLUT (0x24 / 4) // STN: Green Lookup Table +#define S3C24XX_BLUELUT (0x28 / 4) // STN: Blue Lookup Table +#define S3C24XX_DITHMODE (0x4C / 4) // STN: Dithering Mode +#define S3C24XX_TPAL (0x50 / 4) // TFT: Temporary Palette + +/* UART */ + +#define S3C24XX_BASE_UART_0 0x15000000 +#define S3C24XX_BASE_UART_1 0x15004000 + +#define S3C24XX_ULCON (0x00 / 4) // UART Line Control +#define S3C24XX_UCON (0x04 / 4) // UART Control +#define S3C24XX_UFCON (0x08 / 4) // UART FIFO Control +#define S3C24XX_UMCON (0x0C / 4) // UART Modem Control +#define S3C24XX_UTRSTAT (0x10 / 4) // UART Tx/Rx Status +#define S3C24XX_UERSTAT (0x14 / 4) // UART Rx Error Status +#define S3C24XX_UFSTAT (0x18 / 4) // UART FIFO Status +#define S3C24XX_UMSTAT (0x1C / 4) // UART Modem Status +#define S3C24XX_UTXH (0x20 / 4) // UART Transmission Hold +#define S3C24XX_URXH (0x24 / 4) // UART Receive Buffer +#define S3C24XX_UBRDIV (0x28 / 4) // UART Baud Rate Divisor + +/* PWM Timer */ + +#define S3C24XX_BASE_PWM 0x15100000 + +#define S3C24XX_TCFG0 (0x00 / 4) // Timer Configuration +#define S3C24XX_TCFG1 (0x04 / 4) // Timer Configuration +#define S3C24XX_TCON (0x08 / 4) // Timer Control +#define S3C24XX_TCNTB0 (0x0C / 4) // Timer Count Buffer 0 +#define S3C24XX_TCMPB0 (0x10 / 4) // Timer Compare Buffer 0 +#define S3C24XX_TCNTO0 (0x14 / 4) // Timer Count Observation 0 +#define S3C24XX_TCNTB1 (0x18 / 4) // Timer Count Buffer 1 +#define S3C24XX_TCMPB1 (0x1C / 4) // Timer Compare Buffer 1 +#define S3C24XX_TCNTO1 (0x20 / 4) // Timer Count Observation 1 +#define S3C24XX_TCNTB2 (0x24 / 4) // Timer Count Buffer 2 +#define S3C24XX_TCMPB2 (0x28 / 4) // Timer Compare Buffer 2 +#define S3C24XX_TCNTO2 (0x2C / 4) // Timer Count Observation 2 +#define S3C24XX_TCNTB3 (0x30 / 4) // Timer Count Buffer 3 +#define S3C24XX_TCMPB3 (0x34 / 4) // Timer Compare Buffer 3 +#define S3C24XX_TCNTO3 (0x38 / 4) // Timer Count Observation 3 +#define S3C24XX_TCNTB4 (0x3C / 4) // Timer Count Buffer 4 +#define S3C24XX_TCNTO4 (0x40 / 4) // Timer Count Observation 4 + +/* USB Device */ + +#define S3C24XX_BASE_USBDEV 0x15200140 + +/* Watchdog Timer */ + +#define S3C24XX_BASE_WDT 0x15300000 + +#define S3C24XX_WTCON (0x00 / 4) // Watchdog Timer Mode +#define S3C24XX_WTDAT (0x04 / 4) // Watchdog Timer Data +#define S3C24XX_WTCNT (0x08 / 4) // Watchdog Timer Count + +/* IIC */ + +#define S3C24XX_BASE_IIC 0x15400000 + +#define S3C24XX_IICCON (0x00 / 4) // IIC Control +#define S3C24XX_IICSTAT (0x04 / 4) // IIC Status +#define S3C24XX_IICADD (0x08 / 4) // IIC Address +#define S3C24XX_IICDS (0x0C / 4) // IIC Data Shift + +/* IIS */ + +#define S3C24XX_BASE_IIS 0x15508000 + +#define S3C24XX_IISCON (0x00 / 4) // IIS Control +#define S3C24XX_IISMOD (0x04 / 4) // IIS Mode +#define S3C24XX_IISPSR (0x08 / 4) // IIS Prescaler +#define S3C24XX_IISFCON (0x0C / 4) // IIS FIFO Control +#define S3C24XX_IISFIFO (0x10 / 4) // IIS FIFO Entry + +/* I/O Port */ + +#define S3C24XX_BASE_GPIO 0x15600000 + +#define S3C24XX_GPACON (0x00 / 4) // Port A Control +#define S3C24XX_GPADAT (0x04 / 4) // Port A Data +#define S3C24XX_GPBCON (0x08 / 4) // Port B Control +#define S3C24XX_GPBDAT (0x0C / 4) // Port B Data +#define S3C24XX_GPBUP (0x10 / 4) // Pull-up Control B +#define S3C24XX_GPCCON (0x14 / 4) // Port C Control +#define S3C24XX_GPCDAT (0x18 / 4) // Port C Data +#define S3C24XX_GPCUP (0x1C / 4) // Pull-up Control C +#define S3C24XX_GPDCON (0x20 / 4) // Port D Control +#define S3C24XX_GPDDAT (0x24 / 4) // Port D Data +#define S3C24XX_GPDUP (0x28 / 4) // Pull-up Control D +#define S3C24XX_GPECON (0x2C / 4) // Port E Control +#define S3C24XX_GPEDAT (0x30 / 4) // Port E Data +#define S3C24XX_GPEUP (0x34 / 4) // Pull-up Control E +#define S3C24XX_GPFCON (0x38 / 4) // Port F Control +#define S3C24XX_GPFDAT (0x3C / 4) // Port F Data +#define S3C24XX_GPFUP (0x40 / 4) // Pull-up Control F +#define S3C24XX_GPGCON (0x44 / 4) // Port G Control +#define S3C24XX_GPGDAT (0x48 / 4) // Port G Data +#define S3C24XX_GPGUP (0x4C / 4) // Pull-up Control G +#define S3C24XX_OPENCR (0x50 / 4) // Open Drain Enable +#define S3C24XX_MISCCR (0x54 / 4) // Miscellaneous Control +#define S3C24XX_EXTINT (0x58 / 4) // External Interrupt Control + +#define S3C24XX_GPADAT_MASK 0x0003FFFF +#define S3C24XX_GPBDAT_MASK 0x0000FFFF +#define S3C24XX_GPCDAT_MASK 0x0000FFFF +#define S3C24XX_GPDDAT_MASK 0x000007FF +#define S3C24XX_GPEDAT_MASK 0x00000FFF +#define S3C24XX_GPFDAT_MASK 0x0000007F +#define S3C24XX_GPGDAT_MASK 0x000003FF + +/* RTC */ + +#define S3C24XX_BASE_RTC 0x15700040 + +#define S3C24XX_RTCCON (0x00 / 4) // RTC Control +#define S3C24XX_TICNT (0x04 / 4) // Tick Time count +#define S3C24XX_RTCALM (0x10 / 4) // RTC Alarm Control +#define S3C24XX_ALMSEC (0x14 / 4) // Alarm Second +#define S3C24XX_ALMMIN (0x18 / 4) // Alarm Minute +#define S3C24XX_ALMHOUR (0x1C / 4) // Alarm Hour +#define S3C24XX_ALMDAY (0x20 / 4) // Alarm Day +#define S3C24XX_ALMMON (0x24 / 4) // Alarm Month +#define S3C24XX_ALMYEAR (0x28 / 4) // Alarm Year +#define S3C24XX_RTCRST (0x2C / 4) // RTC Round Reset +#define S3C24XX_BCDSEC (0x30 / 4) // BCD Second +#define S3C24XX_BCDMIN (0x34 / 4) // BCD Minute +#define S3C24XX_BCDHOUR (0x38 / 4) // BCD Hour +#define S3C24XX_BCDDAY (0x3C / 4) // BCD Day +#define S3C24XX_BCDDOW (0x40 / 4) // BCD Day of Week +#define S3C24XX_BCDMON (0x44 / 4) // BCD Month +#define S3C24XX_BCDYEAR (0x48 / 4) // BCD Year + +/* A/D Converter */ + +#define S3C24XX_BASE_ADC 0x15800000 + +#define S3C24XX_ADCCON (0x00 / 4) // ADC Control +#define S3C24XX_ADCDAT (0x04 / 4) // ADC Data + +/* SPI */ + +#define S3C24XX_BASE_SPI_0 0x15900000 + +#define S3C24XX_SPCON (0x00 / 4) // SPI Control +#define S3C24XX_SPSTA (0x04 / 4) // SPI Status +#define S3C24XX_SPPIN (0x08 / 4) // SPI Pin Control +#define S3C24XX_SPPRE (0x0C / 4) // SPI Baud Rate Prescaler +#define S3C24XX_SPTDAT (0x10 / 4) // SPI Tx Data +#define S3C24XX_SPRDAT (0x14 / 4) // SPI Rx Data + +/* MMC Interface */ + +#define S3C24XX_BASE_MMC 0x15a00000 + +/* ... */ + +#define S3C24XX_INT_ADC 31 +#define S3C24XX_INT_RTC 30 +#define S3C24XX_INT_UTXD1 29 +#define S3C24XX_INT_UTXD0 28 +#define S3C24XX_INT_IIC 27 +#define S3C24XX_INT_USBH 26 +#define S3C24XX_INT_USBD 25 +#define S3C24XX_INT_URXD1 24 +#define S3C24XX_INT_URXD0 23 +#define S3C24XX_INT_SPI 22 +#define S3C24XX_INT_MMC 21 +#define S3C24XX_INT_DMA3 20 +#define S3C24XX_INT_DMA2 19 +#define S3C24XX_INT_DMA1 18 +#define S3C24XX_INT_DMA0 17 +#define S3C24XX_INT_RESERVED 16 +#define S3C24XX_INT_UERR 15 +#define S3C24XX_INT_TIMER4 14 +#define S3C24XX_INT_TIMER3 13 +#define S3C24XX_INT_TIMER2 12 +#define S3C24XX_INT_TIMER1 11 +#define S3C24XX_INT_TIMER0 10 +#define S3C24XX_INT_WDT 9 +#define S3C24XX_INT_TICK 8 +#define S3C24XX_INT_EINT7 7 +#define S3C24XX_INT_EINT6 6 +#define S3C24XX_INT_EINT5 5 +#define S3C24XX_INT_EINT4 4 +#define S3C24XX_INT_EINT3 3 +#define S3C24XX_INT_EINT2 2 +#define S3C24XX_INT_EINT1 1 +#define S3C24XX_INT_EINT0 0 + +#define S3C24XX_BPPMODE_STN_01 0x00 +#define S3C24XX_BPPMODE_STN_02 0x01 +#define S3C24XX_BPPMODE_STN_04 0x02 +#define S3C24XX_BPPMODE_STN_08 0x03 +#define S3C24XX_BPPMODE_STN_12_P 0x04 +#define S3C24XX_BPPMODE_STN_12_U 0x05 +#define S3C24XX_BPPMODE_STN_16 0x06 +#define S3C24XX_BPPMODE_TFT_01 0x08 +#define S3C24XX_BPPMODE_TFT_02 0x09 +#define S3C24XX_BPPMODE_TFT_04 0x0A +#define S3C24XX_BPPMODE_TFT_08 0x0B +#define S3C24XX_BPPMODE_TFT_16 0x0C +#define S3C24XX_BPPMODE_TFT_24 0x0D + +#define S3C24XX_PNRMODE_STN_04_DS 0 +#define S3C24XX_PNRMODE_STN_04_SS 1 +#define S3C24XX_PNRMODE_STN_08_SS 2 +#define S3C24XX_PNRMODE_TFT 3 + +#define S3C24XX_GPIO_PORT_A S3C2400_GPIO_PORT_A +#define S3C24XX_GPIO_PORT_B S3C2400_GPIO_PORT_B +#define S3C24XX_GPIO_PORT_C S3C2400_GPIO_PORT_C +#define S3C24XX_GPIO_PORT_D S3C2400_GPIO_PORT_D +#define S3C24XX_GPIO_PORT_E S3C2400_GPIO_PORT_E +#define S3C24XX_GPIO_PORT_F S3C2400_GPIO_PORT_F +#define S3C24XX_GPIO_PORT_G S3C2400_GPIO_PORT_G + +#define S3C24XX_UART_COUNT 2 +#define S3C24XX_DMA_COUNT 4 +#define S3C24XX_SPI_COUNT 1 + +class s3c2400_device : public device_t +{ +public: + s3c2400_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + ~s3c2400_device(); + + // static configuration + static void static_set_palette_tag(device_t &device, const char *tag); + template static devcb_base &set_core_pin_r_callback(device_t &device, _Object object) { return downcast(device).m_pin_r_cb.set_callback(object); } + template static devcb_base &set_core_pin_w_callback(device_t &device, _Object object) { return downcast(device).m_pin_w_cb.set_callback(object); } + template static devcb_base &set_gpio_port_r_callback(device_t &device, _Object object) { return downcast(device).m_port_r_cb.set_callback(object); } + template static devcb_base &set_gpio_port_w_callback(device_t &device, _Object object) { return downcast(device).m_port_w_cb.set_callback(object); } + template static devcb_base &set_i2c_scl_w_callback(device_t &device, _Object object) { return downcast(device).m_scl_w_cb.set_callback(object); } + template static devcb_base &set_i2c_sda_r_callback(device_t &device, _Object object) { return downcast(device).m_sda_r_cb.set_callback(object); } + template static devcb_base &set_i2c_sda_w_callback(device_t &device, _Object object) { return downcast(device).m_sda_w_cb.set_callback(object); } + template static devcb_base &set_adc_data_r_callback(device_t &device, _Object object) { return downcast(device).m_data_r_cb.set_callback(object); } + template static devcb_base &set_i2s_data_w_callback(device_t &device, _Object object) { return downcast(device).m_data_w_cb.set_callback(object); } + static void set_lcd_flags(device_t &device, int flags) { downcast(device).m_flags = flags; } + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); +private: + // internal state + required_device m_palette; +public: + UINT32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); + + void s3c24xx_reset(); + inline int iface_core_pin_r(int pin); + void s3c24xx_lcd_reset(); + rgb_t s3c24xx_get_color_tft_16(UINT16 data); + rgb_t s3c24xx_get_color_stn_12(UINT16 data); + rgb_t s3c24xx_get_color_stn_08( UINT8 data); + rgb_t s3c24xx_get_color_stn_01(UINT8 data); + rgb_t s3c24xx_get_color_stn_02(UINT8 data); + rgb_t s3c24xx_get_color_stn_04(UINT8 data); + rgb_t s3c24xx_get_color_tpal(); + void s3c24xx_lcd_dma_reload(); + void s3c24xx_lcd_dma_init(); + UINT32 s3c24xx_lcd_dma_read(); + UINT32 s3c24xx_lcd_dma_read_bits(int count); + void s3c24xx_lcd_render_tpal(); + void s3c24xx_lcd_render_stn_01(); + void s3c24xx_lcd_render_stn_02(); + void s3c24xx_lcd_render_stn_04(); + void s3c24xx_lcd_render_stn_08(); + void s3c24xx_lcd_render_stn_12_p(); + void s3c24xx_lcd_render_stn_12_u(); // not tested + void s3c24xx_lcd_render_tft_01(); + void s3c24xx_lcd_render_tft_02(); + void s3c24xx_lcd_render_tft_04(); + void s3c24xx_lcd_render_tft_08(); + void s3c24xx_lcd_render_tft_16(); + TIMER_CALLBACK_MEMBER( s3c24xx_lcd_timer_exp ); + void s3c24xx_video_start(); + void bitmap_blend( bitmap_rgb32 &bitmap_dst, bitmap_rgb32 &bitmap_src_1, bitmap_rgb32 &bitmap_src_2); + UINT32 s3c24xx_video_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); + READ32_MEMBER( s3c24xx_lcd_r ); + int s3c24xx_lcd_configure_tft(); + int s3c24xx_lcd_configure_stn(); + int s3c24xx_lcd_configure(); + void s3c24xx_lcd_start(); + void s3c24xx_lcd_stop(); + void s3c24xx_lcd_recalc(); + WRITE32_MEMBER( s3c24xx_lcd_w ); + READ32_MEMBER( s3c24xx_lcd_palette_r ); + WRITE32_MEMBER( s3c24xx_lcd_palette_w ); + void s3c24xx_clkpow_reset(); + UINT32 s3c24xx_get_fclk(); + UINT32 s3c24xx_get_hclk(); + UINT32 s3c24xx_get_pclk(); + READ32_MEMBER( s3c24xx_clkpow_r ); + WRITE32_MEMBER( s3c24xx_clkpow_w ); + void s3c24xx_irq_reset(); + void s3c24xx_check_pending_irq(); + void s3c24xx_request_irq(UINT32 int_type); + READ32_MEMBER( s3c24xx_irq_r ); + WRITE32_MEMBER( s3c24xx_irq_w ); + void s3c24xx_pwm_reset(); + UINT16 s3c24xx_pwm_calc_observation(int ch); + READ32_MEMBER( s3c24xx_pwm_r ); + void s3c24xx_pwm_start(int timer); + void s3c24xx_pwm_stop(int timer); + void s3c24xx_pwm_recalc(int timer); + WRITE32_MEMBER( s3c24xx_pwm_w ); + TIMER_CALLBACK_MEMBER( s3c24xx_pwm_timer_exp ); + void s3c24xx_dma_reset(); + void s3c24xx_dma_reload(int ch); + void s3c24xx_dma_trigger(int ch); + void s3c24xx_dma_request_iis(); + void s3c24xx_dma_request_pwm(); + void s3c24xx_dma_start(int ch); + void s3c24xx_dma_stop(int ch); + void s3c24xx_dma_recalc(int ch); + UINT32 s3c24xx_dma_r(UINT32 ch, UINT32 offset); + void s3c24xx_dma_w(UINT32 ch, UINT32 offset, UINT32 data, UINT32 mem_mask); + READ32_MEMBER( s3c24xx_dma_0_r ); + READ32_MEMBER( s3c24xx_dma_1_r ); + READ32_MEMBER( s3c24xx_dma_2_r ); + READ32_MEMBER( s3c24xx_dma_3_r ); + WRITE32_MEMBER( s3c24xx_dma_0_w ); + WRITE32_MEMBER( s3c24xx_dma_1_w ); + WRITE32_MEMBER( s3c24xx_dma_2_w ); + WRITE32_MEMBER( s3c24xx_dma_3_w ); + TIMER_CALLBACK_MEMBER( s3c24xx_dma_timer_exp ); + void s3c24xx_gpio_reset(); + inline UINT32 iface_gpio_port_r(int port, UINT32 mask); + inline void iface_gpio_port_w(int port, UINT32 mask, UINT32 data); + UINT16 s3c24xx_gpio_get_mask( UINT32 con, int val); + READ32_MEMBER( s3c24xx_gpio_r ); + WRITE32_MEMBER( s3c24xx_gpio_w ); + void s3c24xx_memcon_reset(); + READ32_MEMBER( s3c24xx_memcon_r ); + WRITE32_MEMBER( s3c24xx_memcon_w ); + void s3c24xx_usb_host_reset(); + READ32_MEMBER( s3c24xx_usb_host_r ); + WRITE32_MEMBER( s3c24xx_usb_host_w ); + void s3c24xx_uart_reset(); + UINT32 s3c24xx_uart_r(UINT32 ch, UINT32 offset); + void s3c24xx_uart_w(UINT32 ch, UINT32 offset, UINT32 data, UINT32 mem_mask); + READ32_MEMBER( s3c24xx_uart_0_r ); + READ32_MEMBER( s3c24xx_uart_1_r ); + WRITE32_MEMBER( s3c24xx_uart_0_w ); + WRITE32_MEMBER( s3c24xx_uart_1_w ); + void s3c24xx_uart_fifo_w(int uart, UINT8 data); + void s3c24xx_usb_device_reset(); + READ32_MEMBER( s3c24xx_usb_device_r ); + WRITE32_MEMBER( s3c24xx_usb_device_w ); + void s3c24xx_wdt_reset(); + UINT16 s3c24xx_wdt_calc_current_count(); + READ32_MEMBER( s3c24xx_wdt_r ); + void s3c24xx_wdt_start(); + void s3c24xx_wdt_stop(); + void s3c24xx_wdt_recalc(); + WRITE32_MEMBER( s3c24xx_wdt_w ); + TIMER_CALLBACK_MEMBER( s3c24xx_wdt_timer_exp ); + void s3c24xx_iic_reset(); + inline void iface_i2c_scl_w( int state); + inline void iface_i2c_sda_w(int state); + inline int iface_i2c_sda_r(); + void i2c_send_start(); + void i2c_send_stop(); + UINT8 i2c_receive_byte(int ack); + int i2c_send_byte(UINT8 data); + void iic_start(); + void iic_stop(); + void iic_resume(); + READ32_MEMBER( s3c24xx_iic_r ); + WRITE32_MEMBER( s3c24xx_iic_w ); + TIMER_CALLBACK_MEMBER( s3c24xx_iic_timer_exp ); + void s3c24xx_iis_reset(); + inline void iface_i2s_data_w(int ch, UINT16 data); + void s3c24xx_iis_start(); + void s3c24xx_iis_stop(); + void s3c24xx_iis_recalc(); + READ32_MEMBER( s3c24xx_iis_r ); + WRITE32_MEMBER( s3c24xx_iis_w ); + TIMER_CALLBACK_MEMBER( s3c24xx_iis_timer_exp ); + void s3c24xx_rtc_reset(); + READ32_MEMBER( s3c24xx_rtc_r ); + void s3c24xx_rtc_recalc(); + WRITE32_MEMBER( s3c24xx_rtc_w ); + TIMER_CALLBACK_MEMBER( s3c24xx_rtc_timer_tick_count_exp ); + void s3c24xx_rtc_update(); + void s3c24xx_rtc_check_alarm(); + TIMER_CALLBACK_MEMBER( s3c24xx_rtc_timer_update_exp ); + void s3c24xx_adc_reset(); + UINT32 iface_adc_data_r(int ch); + READ32_MEMBER( s3c24xx_adc_r ); + void s3c24xx_adc_start(); + WRITE32_MEMBER( s3c24xx_adc_w ); + void s3c24xx_spi_reset(); + UINT32 s3c24xx_spi_r(UINT32 ch, UINT32 offset); + void s3c24xx_spi_w(UINT32 ch, UINT32 offset, UINT32 data, UINT32 mem_mask); + READ32_MEMBER( s3c24xx_spi_0_r ); + WRITE32_MEMBER( s3c24xx_spi_0_w ); + void s3c24xx_mmc_reset(); + READ32_MEMBER( s3c24xx_mmc_r ); + WRITE32_MEMBER( s3c24xx_mmc_w ); + void s3c24xx_device_reset(); + void s3c24xx_device_start(); + + + void s3c2400_uart_fifo_w(int uart, UINT8 data); + + /******************************************************************************* + TYPE DEFINITIONS + *******************************************************************************/ + + struct s3c24xx_memcon_regs_t + { + UINT32 data[0x34/4]; + }; + + struct s3c24xx_usbhost_regs_t + { + UINT32 data[0x5C/4]; + }; + + struct s3c24xx_irq_regs_t + { + UINT32 srcpnd; + UINT32 intmod; + UINT32 intmsk; + UINT32 priority; + UINT32 intpnd; + UINT32 intoffset; + }; + + struct s3c24xx_dma_regs_t + { + UINT32 disrc; + UINT32 didst; + UINT32 dcon; + UINT32 dstat; + UINT32 dcsrc; + UINT32 dcdst; + UINT32 dmasktrig; + }; + + struct s3c24xx_clkpow_regs_t + { + UINT32 locktime; + UINT32 mpllcon; + UINT32 upllcon; + UINT32 clkcon; + UINT32 clkslow; + UINT32 clkdivn; + }; + + struct s3c24xx_lcd_regs_t + { + UINT32 lcdcon1; + UINT32 lcdcon2; + UINT32 lcdcon3; + UINT32 lcdcon4; + UINT32 lcdcon5; + UINT32 lcdsaddr1; + UINT32 lcdsaddr2; + UINT32 lcdsaddr3; + UINT32 redlut; + UINT32 greenlut; + UINT32 bluelut; + UINT32 reserved[8]; + UINT32 dithmode; + UINT32 tpal; + }; + + struct s3c24xx_lcdpal_regs_t + { + UINT32 data[0x400/4]; + }; + + struct s3c24xx_uart_regs_t + { + UINT32 ulcon; + UINT32 ucon; + UINT32 ufcon; + UINT32 umcon; + UINT32 utrstat; + UINT32 uerstat; + UINT32 ufstat; + UINT32 umstat; + UINT32 utxh; + UINT32 urxh; + UINT32 ubrdiv; + }; + + struct s3c24xx_pwm_regs_t + { + UINT32 tcfg0; + UINT32 tcfg1; + UINT32 tcon; + UINT32 tcntb0; + UINT32 tcmpb0; + UINT32 tcnto0; + UINT32 tcntb1; + UINT32 tcmpb1; + UINT32 tcnto1; + UINT32 tcntb2; + UINT32 tcmpb2; + UINT32 tcnto2; + UINT32 tcntb3; + UINT32 tcmpb3; + UINT32 tcnto3; + UINT32 tcntb4; + UINT32 tcnto4; + }; + + struct s3c24xx_usbdev_regs_t + { + UINT32 data[0xBC/4]; + }; + + struct s3c24xx_wdt_regs_t + { + UINT32 wtcon; + UINT32 wtdat; + UINT32 wtcnt; + }; + + struct s3c24xx_iic_regs_t + { + UINT32 iiccon; + UINT32 iicstat; + UINT32 iicadd; + UINT32 iicds; + }; + + struct s3c24xx_iis_regs_t + { + UINT32 iiscon; + UINT32 iismod; + UINT32 iispsr; + UINT32 iisfcon; + UINT32 iisfifo; + }; + + struct s3c24xx_gpio_regs_t + { + UINT32 gpacon; + UINT32 gpadat; + UINT32 gpbcon; + UINT32 gpbdat; + UINT32 gpbup; + UINT32 gpccon; + UINT32 gpcdat; + UINT32 gpcup; + UINT32 gpdcon; + UINT32 gpddat; + UINT32 gpdup; + UINT32 gpecon; + UINT32 gpedat; + UINT32 gpeup; + UINT32 gpfcon; + UINT32 gpfdat; + UINT32 gpfup; + UINT32 gpgcon; + UINT32 gpgdat; + UINT32 gpgup; + UINT32 opencr; + UINT32 misccr; + UINT32 extint; + }; + + struct s3c24xx_rtc_regs_t + { + UINT32 rtccon; + UINT32 ticnt; + UINT32 reserved[2]; + UINT32 rtcalm; + UINT32 almsec; + UINT32 almmin; + UINT32 almhour; + UINT32 almday; + UINT32 almmon; + UINT32 almyear; + UINT32 rtcrst; + UINT32 bcdsec; + UINT32 bcdmin; + UINT32 bcdhour; + UINT32 bcdday; + UINT32 bcddow; + UINT32 bcdmon; + UINT32 bcdyear; + }; + + struct s3c24xx_adc_regs_t + { + UINT32 adccon; + UINT32 adcdat; + }; + + struct s3c24xx_spi_regs_t + { + UINT32 spcon; + UINT32 spsta; + UINT32 sppin; + UINT32 sppre; + UINT32 sptdat; + UINT32 sprdat; + }; + + struct s3c24xx_mmc_regs_t + { + UINT32 data[0x40/4]; + }; + + struct s3c24xx_memcon_t + { + s3c24xx_memcon_regs_t regs; + }; + + struct s3c24xx_usbhost_t + { + s3c24xx_usbhost_regs_t regs; + }; + + struct s3c24xx_irq_t + { + s3c24xx_irq_regs_t regs; + int line_irq, line_fiq; + }; + + struct s3c24xx_dma_t + { + s3c24xx_dma_regs_t regs; + emu_timer *timer; + }; + + struct s3c24xx_clkpow_t + { + s3c24xx_clkpow_regs_t regs; + }; + + struct s3c24xx_lcd_t + { + s3c24xx_lcd_regs_t regs; + emu_timer *timer; + bitmap_rgb32 *bitmap[2]; + UINT32 vramaddr_cur; + UINT32 vramaddr_max; + UINT32 offsize; + UINT32 pagewidth_cur; + UINT32 pagewidth_max; + UINT32 bppmode; + UINT32 bswp, hwswp; + int vpos, hpos; + double framerate; + UINT32 tpal; + UINT32 hpos_min, hpos_max, vpos_min, vpos_max; + UINT32 dma_data, dma_bits; + }; + + struct s3c24xx_lcdpal_t + { + s3c24xx_lcdpal_regs_t regs; + }; + + struct s3c24xx_uart_t + { + s3c24xx_uart_regs_t regs; + }; + + struct s3c24xx_pwm_t + { + s3c24xx_pwm_regs_t regs; + emu_timer *timer[5]; + UINT32 cnt[5]; + UINT32 cmp[5]; + UINT32 freq[5]; + }; + + struct s3c24xx_usbdev_t + { + s3c24xx_usbdev_regs_t regs; + }; + + struct s3c24xx_wdt_t + { + s3c24xx_wdt_regs_t regs; + emu_timer *timer; + }; + + struct s3c24xx_iic_t + { + s3c24xx_iic_regs_t regs; + emu_timer *timer; + int count; + }; + + struct s3c24xx_iis_t + { + s3c24xx_iis_regs_t regs; + emu_timer *timer; + UINT16 fifo[16/2]; + int fifo_index; + }; + + struct s3c24xx_gpio_t + { + s3c24xx_gpio_regs_t regs; + }; + + struct s3c24xx_rtc_t + { + s3c24xx_rtc_regs_t regs; + emu_timer *timer_tick_count; + emu_timer *timer_update; + }; + + struct s3c24xx_adc_t + { + s3c24xx_adc_regs_t regs; + }; + + struct s3c24xx_spi_t + { + s3c24xx_spi_regs_t regs; + }; + + struct s3c24xx_mmc_t + { + s3c24xx_mmc_regs_t regs; + }; + + + s3c24xx_memcon_t m_memcon; + s3c24xx_usbhost_t m_usbhost; + s3c24xx_irq_t m_irq; + s3c24xx_dma_t m_dma[S3C24XX_DMA_COUNT]; + s3c24xx_clkpow_t m_clkpow; + s3c24xx_lcd_t m_lcd; + s3c24xx_lcdpal_t m_lcdpal; + s3c24xx_uart_t m_uart[S3C24XX_UART_COUNT]; + s3c24xx_pwm_t m_pwm; + s3c24xx_usbdev_t m_usbdev; + s3c24xx_wdt_t m_wdt; + s3c24xx_iic_t m_iic; + s3c24xx_iis_t m_iis; + s3c24xx_gpio_t m_gpio; + s3c24xx_rtc_t m_rtc; + s3c24xx_adc_t m_adc; + s3c24xx_spi_t m_spi[S3C24XX_SPI_COUNT]; + s3c24xx_mmc_t m_mmc; + required_device m_cpu; + devcb_read32 m_pin_r_cb; + devcb_write32 m_pin_w_cb; + devcb_read32 m_port_r_cb; + devcb_write32 m_port_w_cb; + devcb_write_line m_scl_w_cb; + devcb_read_line m_sda_r_cb; + devcb_write_line m_sda_w_cb; + devcb_read32 m_data_r_cb; + devcb_write16 m_data_w_cb; + int m_flags; +}; + +extern const device_type S3C2400; + + +#endif diff --git a/src/devices/machine/s3c2410.c b/src/devices/machine/s3c2410.c new file mode 100644 index 00000000000..ac5bec78180 --- /dev/null +++ b/src/devices/machine/s3c2410.c @@ -0,0 +1,170 @@ +// license:BSD-3-Clause +// copyright-holders:Tim Schuerewegen +/******************************************************************************* + + Samsung S3C2410 + + (c) 2010 Tim Schuerewegen + +*******************************************************************************/ + +#include "emu.h" +#include "cpu/arm7/arm7.h" +#include "cpu/arm7/arm7core.h" +#include "machine/s3c2410.h" +#include "sound/dac.h" + +#define VERBOSE_LEVEL ( 0 ) + +INLINE void ATTR_PRINTF(3,4) verboselog( running_machine &machine, int n_level, const char *s_fmt, ...) +{ + if (VERBOSE_LEVEL >= n_level) + { + va_list v; + char buf[32768]; + va_start( v, s_fmt); + vsprintf( buf, s_fmt, v); + va_end( v); + logerror( "%s: %s", machine.describe_context( ), buf); + } +} + +#define DEVICE_S3C2410 +#define S3C24_CLASS_NAME s3c2410_device +#include "machine/s3c24xx.inc" +#undef DEVICE_S3C2410 + +UINT32 s3c2410_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + return s3c24xx_video_update(screen, bitmap, cliprect); +} + +const device_type S3C2410 = &device_creator; + +s3c2410_device::s3c2410_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, S3C2410, "S3C2410 MCU", tag, owner, clock, "s3c2410", __FILE__), + m_palette(*this), + m_cpu(*this, ":maincpu"), + m_pin_r_cb(*this), + m_pin_w_cb(*this), + m_port_r_cb(*this), + m_port_w_cb(*this), + m_scl_w_cb(*this), + m_sda_r_cb(*this), + m_sda_w_cb(*this), + m_data_r_cb(*this), + m_data_w_cb(*this), + m_command_w_cb(*this), + m_address_w_cb(*this), + m_nand_data_r_cb(*this), + m_nand_data_w_cb(*this), + m_flags(0) +{ + memset(m_steppingstone, 0, sizeof(m_steppingstone)); + memset(&m_memcon, 0, sizeof(m_memcon)); + memset(&m_usbhost, 0, sizeof(m_usbhost)); + memset(&m_irq, 0, sizeof(m_irq)); + memset(m_dma, 0, sizeof(m_dma)); + memset(&m_clkpow, 0, sizeof(m_clkpow)); + memset(&m_lcd, 0, sizeof(m_lcd)); + memset(&m_lcdpal, 0, sizeof(m_lcdpal)); + memset(&m_nand, 0, sizeof(m_nand)); + memset(m_uart, 0, sizeof(m_uart)); + memset(&m_pwm, 0, sizeof(m_pwm)); + memset(&m_usbdev, 0, sizeof(m_usbdev)); + memset(&m_wdt, 0, sizeof(m_wdt)); + memset(&m_iic, 0, sizeof(m_iic)); + memset(&m_iis, 0, sizeof(m_iis)); + memset(&m_gpio, 0, sizeof(m_gpio)); + memset(&m_rtc, 0, sizeof(m_rtc)); + memset(&m_adc, 0, sizeof(m_adc)); + memset(m_spi, 0, sizeof(m_spi)); + memset(&m_sdi, 0, sizeof(m_sdi)); +} + +s3c2410_device::~s3c2410_device() +{ +} + +//------------------------------------------------- +// static_set_palette_tag: Set the tag of the +// palette device +//------------------------------------------------- + +void s3c2410_device::static_set_palette_tag(device_t &device, const char *tag) +{ + downcast(device).m_palette.set_tag(tag); +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void s3c2410_device::device_start() +{ + s3c24xx_device_start(); + + address_space &space = m_cpu->memory().space( AS_PROGRAM); + space.install_readwrite_handler( 0x48000000, 0x4800003b, read32_delegate(FUNC(s3c2410_device::s3c24xx_memcon_r), this), write32_delegate(FUNC(s3c2410_device::s3c24xx_memcon_w), this)); + space.install_readwrite_handler( 0x49000000, 0x4900005b, read32_delegate(FUNC(s3c2410_device::s3c24xx_usb_host_r), this), write32_delegate(FUNC(s3c2410_device::s3c24xx_usb_host_w), this)); + space.install_readwrite_handler( 0x4a000000, 0x4a00001f, read32_delegate(FUNC(s3c2410_device::s3c24xx_irq_r), this), write32_delegate(FUNC(s3c2410_device::s3c24xx_irq_w), this)); + space.install_readwrite_handler( 0x4b000000, 0x4b000023, read32_delegate(FUNC(s3c2410_device::s3c24xx_dma_0_r), this), write32_delegate(FUNC(s3c2410_device::s3c24xx_dma_0_w), this)); + space.install_readwrite_handler( 0x4b000040, 0x4b000063, read32_delegate(FUNC(s3c2410_device::s3c24xx_dma_1_r), this), write32_delegate(FUNC(s3c2410_device::s3c24xx_dma_1_w), this)); + space.install_readwrite_handler( 0x4b000080, 0x4b0000a3, read32_delegate(FUNC(s3c2410_device::s3c24xx_dma_2_r), this), write32_delegate(FUNC(s3c2410_device::s3c24xx_dma_2_w), this)); + space.install_readwrite_handler( 0x4b0000c0, 0x4b0000e3, read32_delegate(FUNC(s3c2410_device::s3c24xx_dma_3_r), this), write32_delegate(FUNC(s3c2410_device::s3c24xx_dma_3_w), this)); + space.install_readwrite_handler( 0x4c000000, 0x4c000017, read32_delegate(FUNC(s3c2410_device::s3c24xx_clkpow_r), this), write32_delegate(FUNC(s3c2410_device::s3c24xx_clkpow_w), this)); + space.install_readwrite_handler( 0x4d000000, 0x4d000063, read32_delegate(FUNC(s3c2410_device::s3c24xx_lcd_r), this), write32_delegate(FUNC(s3c2410_device::s3c24xx_lcd_w), this)); + space.install_readwrite_handler( 0x4d000400, 0x4d0007ff, read32_delegate(FUNC(s3c2410_device::s3c24xx_lcd_palette_r), this), write32_delegate(FUNC(s3c2410_device::s3c24xx_lcd_palette_w), this)); + space.install_readwrite_handler( 0x4e000000, 0x4e000017, read32_delegate(FUNC(s3c2410_device::s3c24xx_nand_r), this), write32_delegate(FUNC(s3c2410_device::s3c24xx_nand_w), this)); + space.install_readwrite_handler( 0x50000000, 0x5000002b, read32_delegate(FUNC(s3c2410_device::s3c24xx_uart_0_r), this), write32_delegate(FUNC(s3c2410_device::s3c24xx_uart_0_w), this)); + space.install_readwrite_handler( 0x50004000, 0x5000402b, read32_delegate(FUNC(s3c2410_device::s3c24xx_uart_1_r), this), write32_delegate(FUNC(s3c2410_device::s3c24xx_uart_1_w), this)); + space.install_readwrite_handler( 0x50008000, 0x5000802b, read32_delegate(FUNC(s3c2410_device::s3c24xx_uart_2_r), this), write32_delegate(FUNC(s3c2410_device::s3c24xx_uart_2_w), this)); + space.install_readwrite_handler( 0x51000000, 0x51000043, read32_delegate(FUNC(s3c2410_device::s3c24xx_pwm_r), this), write32_delegate(FUNC(s3c2410_device::s3c24xx_pwm_w), this)); + space.install_readwrite_handler( 0x52000140, 0x5200026f, read32_delegate(FUNC(s3c2410_device::s3c24xx_usb_device_r), this), write32_delegate(FUNC(s3c2410_device::s3c24xx_usb_device_w), this)); + space.install_readwrite_handler( 0x53000000, 0x5300000b, read32_delegate(FUNC(s3c2410_device::s3c24xx_wdt_r), this), write32_delegate(FUNC(s3c2410_device::s3c24xx_wdt_w), this)); + space.install_readwrite_handler( 0x54000000, 0x5400000f, read32_delegate(FUNC(s3c2410_device::s3c24xx_iic_r), this), write32_delegate(FUNC(s3c2410_device::s3c24xx_iic_w), this)); + space.install_readwrite_handler( 0x55000000, 0x55000013, read32_delegate(FUNC(s3c2410_device::s3c24xx_iis_r), this), write32_delegate(FUNC(s3c2410_device::s3c24xx_iis_w), this)); + space.install_readwrite_handler( 0x56000000, 0x560000bf, read32_delegate(FUNC(s3c2410_device::s3c24xx_gpio_r), this), write32_delegate(FUNC(s3c2410_device::s3c24xx_gpio_w), this)); + space.install_readwrite_handler( 0x57000040, 0x5700008b, read32_delegate(FUNC(s3c2410_device::s3c24xx_rtc_r), this), write32_delegate(FUNC(s3c2410_device::s3c24xx_rtc_w), this)); + space.install_readwrite_handler( 0x58000000, 0x58000013, read32_delegate(FUNC(s3c2410_device::s3c24xx_adc_r), this), write32_delegate(FUNC(s3c2410_device::s3c24xx_adc_w), this)); + space.install_readwrite_handler( 0x59000000, 0x59000017, read32_delegate(FUNC(s3c2410_device::s3c24xx_spi_0_r), this), write32_delegate(FUNC(s3c2410_device::s3c24xx_spi_0_w), this)); + space.install_readwrite_handler( 0x59000020, 0x59000037, read32_delegate(FUNC(s3c2410_device::s3c24xx_spi_1_r), this), write32_delegate(FUNC(s3c2410_device::s3c24xx_spi_1_w), this)); + space.install_readwrite_handler( 0x5a000000, 0x5a000043, read32_delegate(FUNC(s3c2410_device::s3c24xx_sdi_r), this), write32_delegate(FUNC(s3c2410_device::s3c24xx_sdi_w), this)); + + s3c24xx_video_start(); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void s3c2410_device::device_reset() +{ + s3c24xx_device_reset(); +} + +void s3c2410_device::s3c2410_uart_fifo_w( int uart, UINT8 data) +{ + s3c24xx_uart_fifo_w( uart, data); +} + +void s3c2410_device::s3c2410_touch_screen( int state) +{ + s3c24xx_touch_screen(state); +} + +WRITE_LINE_MEMBER( s3c2410_device::frnb_w ) +{ + s3c24xx_pin_frnb_w(state); +} + +void s3c2410_device::s3c2410_nand_calculate_mecc( UINT8 *data, UINT32 size, UINT8 *mecc) +{ + mecc[0] = mecc[1] = mecc[2] = mecc[3] = 0xFF; + for (int i = 0; i < size; i++) nand_update_mecc( mecc, i, data[i]); +} + +void s3c2410_device::s3c2410_request_eint(UINT32 number) +{ + s3c24xx_request_eint(number); +} diff --git a/src/devices/machine/s3c2410.h b/src/devices/machine/s3c2410.h new file mode 100644 index 00000000000..6ad02c90d1e --- /dev/null +++ b/src/devices/machine/s3c2410.h @@ -0,0 +1,1073 @@ +// license:BSD-3-Clause +// copyright-holders:Tim Schuerewegen +/******************************************************************************* + + Samsung S3C2410 + +*******************************************************************************/ + +#ifndef __S3C2410_H__ +#define __S3C2410_H__ + + +/******************************************************************************* + MACROS / CONSTANTS +*******************************************************************************/ + +#define S3C2410_TAG "s3c2410" + +#define MCFG_S3C2410_PALETTE(_palette_tag) \ + s3c2410_device::static_set_palette_tag(*device, "^" _palette_tag); + +#define MCFG_S3C2410_CORE_PIN_R_CB(_devcb) \ + devcb = &s3c2410_device::set_core_pin_r_callback(*device, DEVCB_##_devcb); + +#define MCFG_S3C2410_CORE_PIN_W_CB(_devcb) \ + devcb = &s3c2410_device::set_core_pin_w_callback(*device, DEVCB_##_devcb); + +#define MCFG_S3C2410_GPIO_PORT_R_CB(_devcb) \ + devcb = &s3c2410_device::set_gpio_port_r_callback(*device, DEVCB_##_devcb); + +#define MCFG_S3C2410_GPIO_PORT_W_CB(_devcb) \ + devcb = &s3c2410_device::set_gpio_port_w_callback(*device, DEVCB_##_devcb); + +#define MCFG_S3C2410_I2C_SCL_W_CB(_devcb) \ + devcb = &s3c2410_device::set_i2c_scl_w_callback(*device, DEVCB_##_devcb); + +#define MCFG_S3C2410_I2C_SDA_R_CB(_devcb) \ + devcb = &s3c2410_device::set_i2c_sda_r_callback(*device, DEVCB_##_devcb); + +#define MCFG_S3C2410_I2C_SDA_W_CB(_devcb) \ + devcb = &s3c2410_device::set_i2c_sda_w_callback(*device, DEVCB_##_devcb); + +#define MCFG_S3C2410_ADC_DATA_R_CB(_devcb) \ + devcb = &s3c2410_device::set_adc_data_r_callback(*device, DEVCB_##_devcb); + +#define MCFG_S3C2410_I2S_DATA_W_CB(_devcb) \ + devcb = &s3c2410_device::set_i2s_data_w_callback(*device, DEVCB_##_devcb); + +#define MCFG_S3C2410_NAND_COMMAND_W_CB(_devcb) \ + devcb = &s3c2410_device::set_nand_command_w_callback(*device, DEVCB_##_devcb); + +#define MCFG_S3C2410_NAND_ADDRESS_W_CB(_devcb) \ + devcb = &s3c2410_device::set_nand_address_w_callback(*device, DEVCB_##_devcb); + +#define MCFG_S3C2410_NAND_DATA_R_CB(_devcb) \ + devcb = &s3c2410_device::set_nand_data_r_callback(*device, DEVCB_##_devcb); + +#define MCFG_S3C2410_NAND_DATA_W_CB(_devcb) \ + devcb = &s3c2410_device::set_nand_data_w_callback(*device, DEVCB_##_devcb); + +#define MCFG_S3C2410_LCD_FLAGS(_flags) \ + s3c2410_device::set_lcd_flags(*device, _flags); + +enum +{ + S3C2410_GPIO_PORT_A = 0, + S3C2410_GPIO_PORT_B, + S3C2410_GPIO_PORT_C, + S3C2410_GPIO_PORT_D, + S3C2410_GPIO_PORT_E, + S3C2410_GPIO_PORT_F, + S3C2410_GPIO_PORT_G, + S3C2410_GPIO_PORT_H +}; + +enum +{ + S3C2410_CORE_PIN_NCON = 0, + S3C2410_CORE_PIN_OM0, + S3C2410_CORE_PIN_OM1 +}; + + +/******************************************************************************* + MACROS & CONSTANTS +*******************************************************************************/ + +/* Interface */ + +#define S3C24XX_INTERFACE_LCD_REVERSE 1 + +/* Memory Controller */ + +#define S3C24XX_BASE_MEMCON 0x48000000 + +/* USB Host Controller */ + +#define S3C24XX_BASE_USBHOST 0x49000000 + +/* Interrupt Controller */ + +#define S3C24XX_BASE_INT 0x4A000000 + +#define S3C24XX_SRCPND (0x00 / 4) // Interrupt Request Status +#define S3C24XX_INTMOD (0x04 / 4) // Interrupt Mode Control +#define S3C24XX_INTMSK (0x08 / 4) // Interrupt Mask Control +#define S3C24XX_PRIORITY (0x0C / 4) // IRQ Priority Control +#define S3C24XX_INTPND (0x10 / 4) // Interrupt Request Status +#define S3C24XX_INTOFFSET (0x14 / 4) // Interrupt Request Source Offset +#define S3C24XX_SUBSRCPND (0x18 / 4) // Sub Source Pending +#define S3C24XX_INTSUBMSK (0x1C / 4) // Interrupt Sub Mask + +/* DMA */ + +#define S3C24XX_BASE_DMA_0 0x4B000000 +#define S3C24XX_BASE_DMA_1 0x4B000040 +#define S3C24XX_BASE_DMA_2 0x4B000080 +#define S3C24XX_BASE_DMA_3 0x4B0000C0 + +#define S3C24XX_DISRC (0x00 / 4) // DMA Initial Source +#define S3C24XX_DISRCC (0x04 / 4) // DMA Initial Source Control +#define S3C24XX_DIDST (0x08 / 4) // DMA Initial Destination +#define S3C24XX_DIDSTC (0x0C / 4) // DMA Initial Destination Control +#define S3C24XX_DCON (0x10 / 4) // DMA Control +#define S3C24XX_DSTAT (0x14 / 4) // DMA Count +#define S3C24XX_DCSRC (0x18 / 4) // DMA Current Source +#define S3C24XX_DCDST (0x1C / 4) // DMA Current Destination +#define S3C24XX_DMASKTRIG (0x20 / 4) // DMA Mask Trigger + +/* Clock & Power Management */ + +#define S3C24XX_BASE_CLKPOW 0x4C000000 + +#define S3C24XX_LOCKTIME (0x00 / 4) // PLL Lock Time Counter +#define S3C24XX_MPLLCON (0x04 / 4) // MPLL Control +#define S3C24XX_UPLLCON (0x08 / 4) // UPLL Control +#define S3C24XX_CLKCON (0x0C / 4) // Clock Generator Control +#define S3C24XX_CLKSLOW (0x10 / 4) // Slow Clock Control +#define S3C24XX_CLKDIVN (0x14 / 4) // Clock Divider Control + +/* LCD Controller */ + +#define S3C24XX_BASE_LCD 0x4D000000 +#define S3C24XX_BASE_LCDPAL 0x4D000400 + +#define S3C24XX_LCDCON1 (0x00 / 4) // LCD Control 1 +#define S3C24XX_LCDCON2 (0x04 / 4) // LCD Control 2 +#define S3C24XX_LCDCON3 (0x08 / 4) // LCD Control 3 +#define S3C24XX_LCDCON4 (0x0C / 4) // LCD Control 4 +#define S3C24XX_LCDCON5 (0x10 / 4) // LCD Control 5 +#define S3C24XX_LCDSADDR1 (0x14 / 4) // STN/TFT: Frame Buffer Start Address 1 +#define S3C24XX_LCDSADDR2 (0x18 / 4) // STN/TFT: Frame Buffer Start Address 2 +#define S3C24XX_LCDSADDR3 (0x1C / 4) // STN/TFT: Virtual Screen Address Set +#define S3C24XX_REDLUT (0x20 / 4) // STN: Red Lookup Table +#define S3C24XX_GREENLUT (0x24 / 4) // STN: Green Lookup Table +#define S3C24XX_BLUELUT (0x28 / 4) // STN: Blue Lookup Table +#define S3C24XX_DITHMODE (0x4C / 4) // STN: Dithering Mode +#define S3C24XX_TPAL (0x50 / 4) // TFT: Temporary Palette +#define S3C24XX_LCDINTPND (0x54 / 4) // LCD Interrupt Pending +#define S3C24XX_LCDSRCPND (0x58 / 4) // LCD Interrupt Source +#define S3C24XX_LCDINTMSK (0x5C / 4) // LCD Interrupt Mask +#define S3C24XX_LPCSEL (0x60 / 4) // LPC3600 Control + +/* NAND Flash */ + +#define S3C24XX_BASE_NAND 0x4E000000 + +#define S3C24XX_NFCONF (0x00 / 4) // NAND Flash Configuration +#define S3C24XX_NFCMD (0x04 / 4) // NAND Flash Command +#define S3C24XX_NFADDR (0x08 / 4) // NAND Flash Address +#define S3C24XX_NFDATA (0x0C / 4) // NAND Flash Data +#define S3C24XX_NFSTAT (0x10 / 4) // NAND Flash Operation Status +#define S3C24XX_NFECC (0x14 / 4) // NAND Flash ECC + +/* UART */ + +#define S3C24XX_BASE_UART_0 0x50000000 +#define S3C24XX_BASE_UART_1 0x50004000 +#define S3C24XX_BASE_UART_2 0x50008000 + +#define S3C24XX_ULCON (0x00 / 4) // UART Line Control +#define S3C24XX_UCON (0x04 / 4) // UART Control +#define S3C24XX_UFCON (0x08 / 4) // UART FIFO Control +#define S3C24XX_UMCON (0x0C / 4) // UART Modem Control +#define S3C24XX_UTRSTAT (0x10 / 4) // UART Tx/Rx Status +#define S3C24XX_UERSTAT (0x14 / 4) // UART Rx Error Status +#define S3C24XX_UFSTAT (0x18 / 4) // UART FIFO Status +#define S3C24XX_UMSTAT (0x1C / 4) // UART Modem Status +#define S3C24XX_UTXH (0x20 / 4) // UART Transmission Hold +#define S3C24XX_URXH (0x24 / 4) // UART Receive Buffer +#define S3C24XX_UBRDIV (0x28 / 4) // UART Baud Rate Divisor + +/* PWM Timer */ + +#define S3C24XX_BASE_PWM 0x51000000 + +#define S3C24XX_TCFG0 (0x00 / 4) // Timer Configuration +#define S3C24XX_TCFG1 (0x04 / 4) // Timer Configuration +#define S3C24XX_TCON (0x08 / 4) // Timer Control +#define S3C24XX_TCNTB0 (0x0C / 4) // Timer Count Buffer 0 +#define S3C24XX_TCMPB0 (0x10 / 4) // Timer Compare Buffer 0 +#define S3C24XX_TCNTO0 (0x14 / 4) // Timer Count Observation 0 +#define S3C24XX_TCNTB1 (0x18 / 4) // Timer Count Buffer 1 +#define S3C24XX_TCMPB1 (0x1C / 4) // Timer Compare Buffer 1 +#define S3C24XX_TCNTO1 (0x20 / 4) // Timer Count Observation 1 +#define S3C24XX_TCNTB2 (0x24 / 4) // Timer Count Buffer 2 +#define S3C24XX_TCMPB2 (0x28 / 4) // Timer Compare Buffer 2 +#define S3C24XX_TCNTO2 (0x2C / 4) // Timer Count Observation 2 +#define S3C24XX_TCNTB3 (0x30 / 4) // Timer Count Buffer 3 +#define S3C24XX_TCMPB3 (0x34 / 4) // Timer Compare Buffer 3 +#define S3C24XX_TCNTO3 (0x38 / 4) // Timer Count Observation 3 +#define S3C24XX_TCNTB4 (0x3C / 4) // Timer Count Buffer 4 +#define S3C24XX_TCNTO4 (0x40 / 4) // Timer Count Observation 4 + +/* USB Device */ + +#define S3C24XX_BASE_USBDEV 0x52000140 + +/* Watchdog Timer */ + +#define S3C24XX_BASE_WDT 0x53000000 + +#define S3C24XX_WTCON (0x00 / 4) // Watchdog Timer Mode +#define S3C24XX_WTDAT (0x04 / 4) // Watchdog Timer Data +#define S3C24XX_WTCNT (0x08 / 4) // Watchdog Timer Count + +/* IIC */ + +#define S3C24XX_BASE_IIC 0x54000000 + +#define S3C24XX_IICCON (0x00 / 4) // IIC Control +#define S3C24XX_IICSTAT (0x04 / 4) // IIC Status +#define S3C24XX_IICADD (0x08 / 4) // IIC Address +#define S3C24XX_IICDS (0x0C / 4) // IIC Data Shift + +/* IIS */ + +#define S3C24XX_BASE_IIS 0x55000000 + +#define S3C24XX_IISCON (0x00 / 4) // IIS Control +#define S3C24XX_IISMOD (0x04 / 4) // IIS Mode +#define S3C24XX_IISPSR (0x08 / 4) // IIS Prescaler +#define S3C24XX_IISFCON (0x0C / 4) // IIS FIFO Control +#define S3C24XX_IISFIFO (0x10 / 4) // IIS FIFO Entry + +/* I/O Port */ + +#define S3C24XX_BASE_GPIO 0x56000000 + +#define S3C24XX_GPACON (0x00 / 4) // Port A Control +#define S3C24XX_GPADAT (0x04 / 4) // Port A Data +#define S3C24XX_GPBCON (0x10 / 4) // Port B Control +#define S3C24XX_GPBDAT (0x14 / 4) // Port B Data +#define S3C24XX_GPBUP (0x18 / 4) // Pull-up Control B +#define S3C24XX_GPCCON (0x20 / 4) // Port C Control +#define S3C24XX_GPCDAT (0x24 / 4) // Port C Data +#define S3C24XX_GPCUP (0x28 / 4) // Pull-up Control C +#define S3C24XX_GPDCON (0x30 / 4) // Port D Control +#define S3C24XX_GPDDAT (0x34 / 4) // Port D Data +#define S3C24XX_GPDUP (0x38 / 4) // Pull-up Control D +#define S3C24XX_GPECON (0x40 / 4) // Port E Control +#define S3C24XX_GPEDAT (0x44 / 4) // Port E Data +#define S3C24XX_GPEUP (0x48 / 4) // Pull-up Control E +#define S3C24XX_GPFCON (0x50 / 4) // Port F Control +#define S3C24XX_GPFDAT (0x54 / 4) // Port F Data +#define S3C24XX_GPFUP (0x58 / 4) // Pull-up Control F +#define S3C24XX_GPGCON (0x60 / 4) // Port G Control +#define S3C24XX_GPGDAT (0x64 / 4) // Port G Data +#define S3C24XX_GPGUP (0x68 / 4) // Pull-up Control G +#define S3C24XX_GPHCON (0x70 / 4) // Port H Control +#define S3C24XX_GPHDAT (0x74 / 4) // Port H Data +#define S3C24XX_GPHUP (0x78 / 4) // Pull-up Control H +#define S3C24XX_MISCCR (0x80 / 4) // Miscellaneous Control +#define S3C24XX_DCLKCON (0x84 / 4) // DCLK0/1 Control +#define S3C24XX_EXTINT0 (0x88 / 4) // External Interrupt Control Register 0 +#define S3C24XX_EXTINT1 (0x8C / 4) // External Interrupt Control Register 1 +#define S3C24XX_EXTINT2 (0x90 / 4) // External Interrupt Control Register 2 +#define S3C24XX_EINTFLT0 (0x94 / 4) // Reserved +#define S3C24XX_EINTFLT1 (0x98 / 4) // Reserved +#define S3C24XX_EINTFLT2 (0x9C / 4) // External Interrupt Filter Control Register 2 +#define S3C24XX_EINTFLT3 (0xA0 / 4) // External Interrupt Filter Control Register 3 +#define S3C24XX_EINTMASK (0xA4 / 4) // External Interrupt Mask +#define S3C24XX_EINTPEND (0xA8 / 4) // External Interrupt Pending +#define S3C24XX_GSTATUS0 (0xAC / 4) // External Pin Status +#define S3C24XX_GSTATUS1 (0xB0 / 4) // Chip ID +#define S3C24XX_GSTATUS2 (0xB4 / 4) // Reset Status +#define S3C24XX_GSTATUS3 (0xB8 / 4) // Inform Register +#define S3C24XX_GSTATUS4 (0xBC / 4) // Inform Register + +#define S3C24XX_GPADAT_MASK 0x007FFFFF +#define S3C24XX_GPBDAT_MASK 0x000007FF +#define S3C24XX_GPCDAT_MASK 0x0000FFFF +#define S3C24XX_GPDDAT_MASK 0x0000FFFF +#define S3C24XX_GPEDAT_MASK 0x0000FFFF +#define S3C24XX_GPFDAT_MASK 0x000000FF +#define S3C24XX_GPGDAT_MASK 0x0000FFFF +#define S3C24XX_GPHDAT_MASK 0x000007FF + +/* RTC */ + +#define S3C24XX_BASE_RTC 0x57000040 + +#define S3C24XX_RTCCON (0x00 / 4) // RTC Control +#define S3C24XX_TICNT (0x04 / 4) // Tick Time count +#define S3C24XX_RTCALM (0x10 / 4) // RTC Alarm Control +#define S3C24XX_ALMSEC (0x14 / 4) // Alarm Second +#define S3C24XX_ALMMIN (0x18 / 4) // Alarm Minute +#define S3C24XX_ALMHOUR (0x1C / 4) // Alarm Hour +#define S3C24XX_ALMDAY (0x20 / 4) // Alarm Day +#define S3C24XX_ALMMON (0x24 / 4) // Alarm Month +#define S3C24XX_ALMYEAR (0x28 / 4) // Alarm Year +#define S3C24XX_RTCRST (0x2C / 4) // RTC Round Reset +#define S3C24XX_BCDSEC (0x30 / 4) // BCD Second +#define S3C24XX_BCDMIN (0x34 / 4) // BCD Minute +#define S3C24XX_BCDHOUR (0x38 / 4) // BCD Hour +#define S3C24XX_BCDDAY (0x3C / 4) // BCD Day +#define S3C24XX_BCDDOW (0x40 / 4) // BCD Day of Week +#define S3C24XX_BCDMON (0x44 / 4) // BCD Month +#define S3C24XX_BCDYEAR (0x48 / 4) // BCD Year + +/* A/D Converter */ + +#define S3C24XX_BASE_ADC 0x58000000 + +#define S3C24XX_ADCCON (0x00 / 4) // ADC Control +#define S3C24XX_ADCTSC (0x04 / 4) // ADC Touch Screen Control +#define S3C24XX_ADCDLY (0x08 / 4) // ADC Start or Interval Delay +#define S3C24XX_ADCDAT0 (0x0C / 4) // ADC Conversion Data +#define S3C24XX_ADCDAT1 (0x10 / 4) // ADC Conversion Data + +/* SPI */ + +#define S3C24XX_BASE_SPI_0 0x59000000 +#define S3C24XX_BASE_SPI_1 0x59000020 + +#define S3C24XX_SPCON (0x00 / 4) // SPI Control +#define S3C24XX_SPSTA (0x04 / 4) // SPI Status +#define S3C24XX_SPPIN (0x08 / 4) // SPI Pin Control +#define S3C24XX_SPPRE (0x0C / 4) // SPI Baud Rate Prescaler +#define S3C24XX_SPTDAT (0x10 / 4) // SPI Tx Data +#define S3C24XX_SPRDAT (0x14 / 4) // SPI Rx Data + +/* SD Interface */ + +#define S3C24XX_BASE_SDI 0x5A000000 + +/* ... */ + +#define S3C24XX_INT_ADC 31 +#define S3C24XX_INT_RTC 30 +#define S3C24XX_INT_SPI1 29 +#define S3C24XX_INT_UART0 28 +#define S3C24XX_INT_IIC 27 +#define S3C24XX_INT_USBH 26 +#define S3C24XX_INT_USBD 25 +#define S3C24XX_INT_24 24 +#define S3C24XX_INT_UART1 23 +#define S3C24XX_INT_SPI0 22 +#define S3C24XX_INT_SDI 21 +#define S3C24XX_INT_DMA3 20 +#define S3C24XX_INT_DMA2 19 +#define S3C24XX_INT_DMA1 18 +#define S3C24XX_INT_DMA0 17 +#define S3C24XX_INT_LCD 16 +#define S3C24XX_INT_UART2 15 +#define S3C24XX_INT_TIMER4 14 +#define S3C24XX_INT_TIMER3 13 +#define S3C24XX_INT_TIMER2 12 +#define S3C24XX_INT_TIMER1 11 +#define S3C24XX_INT_TIMER0 10 +#define S3C24XX_INT_WDT 9 +#define S3C24XX_INT_TICK 8 +#define S3C24XX_INT_BATT_FLT 7 +#define S3C24XX_INT_6 6 +#define S3C24XX_INT_EINT8_23 5 +#define S3C24XX_INT_EINT4_7 4 +#define S3C24XX_INT_EINT3 3 +#define S3C24XX_INT_EINT2 2 +#define S3C24XX_INT_EINT1 1 +#define S3C24XX_INT_EINT0 0 + +#define S3C24XX_SUBINT_ADC 10 +#define S3C24XX_SUBINT_TC 9 +#define S3C24XX_SUBINT_ERR2 8 +#define S3C24XX_SUBINT_TXD2 7 +#define S3C24XX_SUBINT_RXD2 6 +#define S3C24XX_SUBINT_ERR1 5 +#define S3C24XX_SUBINT_TXD1 4 +#define S3C24XX_SUBINT_RXD1 3 +#define S3C24XX_SUBINT_ERR0 2 +#define S3C24XX_SUBINT_TXD0 1 +#define S3C24XX_SUBINT_RXD0 0 + +static const UINT32 MAP_SUBINT_TO_INT[11] = +{ + S3C24XX_INT_UART0, S3C24XX_INT_UART0, S3C24XX_INT_UART0, + S3C24XX_INT_UART1, S3C24XX_INT_UART1, S3C24XX_INT_UART1, + S3C24XX_INT_UART2, S3C24XX_INT_UART2, S3C24XX_INT_UART2, + S3C24XX_INT_ADC, S3C24XX_INT_ADC +}; + +#define S3C24XX_BPPMODE_STN_01 0x00 +#define S3C24XX_BPPMODE_STN_02 0x01 +#define S3C24XX_BPPMODE_STN_04 0x02 +#define S3C24XX_BPPMODE_STN_08 0x03 +#define S3C24XX_BPPMODE_STN_12_P 0x04 +#define S3C24XX_BPPMODE_STN_12_U 0x05 +#define S3C24XX_BPPMODE_STN_16 0x06 +#define S3C24XX_BPPMODE_TFT_01 0x08 +#define S3C24XX_BPPMODE_TFT_02 0x09 +#define S3C24XX_BPPMODE_TFT_04 0x0A +#define S3C24XX_BPPMODE_TFT_08 0x0B +#define S3C24XX_BPPMODE_TFT_16 0x0C +#define S3C24XX_BPPMODE_TFT_24 0x0D + +#define S3C24XX_PNRMODE_STN_04_DS 0 +#define S3C24XX_PNRMODE_STN_04_SS 1 +#define S3C24XX_PNRMODE_STN_08_SS 2 +#define S3C24XX_PNRMODE_TFT 3 + +#define S3C24XX_GPIO_PORT_A S3C2410_GPIO_PORT_A +#define S3C24XX_GPIO_PORT_B S3C2410_GPIO_PORT_B +#define S3C24XX_GPIO_PORT_C S3C2410_GPIO_PORT_C +#define S3C24XX_GPIO_PORT_D S3C2410_GPIO_PORT_D +#define S3C24XX_GPIO_PORT_E S3C2410_GPIO_PORT_E +#define S3C24XX_GPIO_PORT_F S3C2410_GPIO_PORT_F +#define S3C24XX_GPIO_PORT_G S3C2410_GPIO_PORT_G +#define S3C24XX_GPIO_PORT_H S3C2410_GPIO_PORT_H + +#define S3C24XX_CORE_PIN_NCON S3C2410_CORE_PIN_NCON +#define S3C24XX_CORE_PIN_OM0 S3C2410_CORE_PIN_OM0 +#define S3C24XX_CORE_PIN_OM1 S3C2410_CORE_PIN_OM1 + +#define S3C24XX_UART_COUNT 3 +#define S3C24XX_DMA_COUNT 4 +#define S3C24XX_SPI_COUNT 2 + +class s3c2410_device : public device_t +{ +public: + s3c2410_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + ~s3c2410_device(); + + // static configuration + static void static_set_palette_tag(device_t &device, const char *tag); + template static devcb_base &set_core_pin_r_callback(device_t &device, _Object object) { return downcast(device).m_pin_r_cb.set_callback(object); } + template static devcb_base &set_core_pin_w_callback(device_t &device, _Object object) { return downcast(device).m_pin_w_cb.set_callback(object); } + template static devcb_base &set_gpio_port_r_callback(device_t &device, _Object object) { return downcast(device).m_port_r_cb.set_callback(object); } + template static devcb_base &set_gpio_port_w_callback(device_t &device, _Object object) { return downcast(device).m_port_w_cb.set_callback(object); } + template static devcb_base &set_i2c_scl_w_callback(device_t &device, _Object object) { return downcast(device).m_scl_w_cb.set_callback(object); } + template static devcb_base &set_i2c_sda_r_callback(device_t &device, _Object object) { return downcast(device).m_sda_r_cb.set_callback(object); } + template static devcb_base &set_i2c_sda_w_callback(device_t &device, _Object object) { return downcast(device).m_sda_w_cb.set_callback(object); } + template static devcb_base &set_adc_data_r_callback(device_t &device, _Object object) { return downcast(device).m_data_r_cb.set_callback(object); } + template static devcb_base &set_i2s_data_w_callback(device_t &device, _Object object) { return downcast(device).m_data_w_cb.set_callback(object); } + template static devcb_base &set_nand_command_w_callback(device_t &device, _Object object) { return downcast(device).m_command_w_cb.set_callback(object); } + template static devcb_base &set_nand_address_w_callback(device_t &device, _Object object) { return downcast(device).m_address_w_cb.set_callback(object); } + template static devcb_base &set_nand_data_r_callback(device_t &device, _Object object) { return downcast(device).m_nand_data_r_cb.set_callback(object); } + template static devcb_base &set_nand_data_w_callback(device_t &device, _Object object) { return downcast(device).m_nand_data_w_cb.set_callback(object); } + static void set_lcd_flags(device_t &device, int flags) { downcast(device).m_flags = flags; } + + DECLARE_WRITE_LINE_MEMBER( frnb_w ); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); +private: + // internal state + required_device m_palette; +public: + UINT32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); + + void s3c24xx_reset(); + inline int iface_core_pin_r(int pin); + void s3c24xx_lcd_reset(); + rgb_t s3c24xx_get_color_tft_16(UINT16 data); + rgb_t s3c24xx_get_color_tft_24(UINT32 data); + rgb_t s3c24xx_get_color_stn_12(UINT16 data); + rgb_t s3c24xx_get_color_stn_08( UINT8 data); + rgb_t s3c24xx_get_color_stn_01(UINT8 data); + rgb_t s3c24xx_get_color_stn_02(UINT8 data); + rgb_t s3c24xx_get_color_stn_04(UINT8 data); + rgb_t s3c24xx_get_color_tpal(); + void s3c24xx_lcd_dma_reload(); + void s3c24xx_lcd_dma_init(); + UINT32 s3c24xx_lcd_dma_read(); + UINT32 s3c24xx_lcd_dma_read_bits(int count); + void s3c24xx_lcd_render_tpal(); + void s3c24xx_lcd_render_stn_01(); + void s3c24xx_lcd_render_stn_02(); + void s3c24xx_lcd_render_stn_04(); + void s3c24xx_lcd_render_stn_08(); + void s3c24xx_lcd_render_stn_12_p(); + void s3c24xx_lcd_render_stn_12_u(); // not tested + void s3c24xx_lcd_render_tft_01(); + void s3c24xx_lcd_render_tft_02(); + void s3c24xx_lcd_render_tft_04(); + void s3c24xx_lcd_render_tft_08(); + void s3c24xx_lcd_render_tft_16(); + TIMER_CALLBACK_MEMBER( s3c24xx_lcd_timer_exp ); + void s3c24xx_video_start(); + void bitmap_blend( bitmap_rgb32 &bitmap_dst, bitmap_rgb32 &bitmap_src_1, bitmap_rgb32 &bitmap_src_2); + UINT32 s3c24xx_video_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); + READ32_MEMBER( s3c24xx_lcd_r ); + int s3c24xx_lcd_configure_tft(); + int s3c24xx_lcd_configure_stn(); + int s3c24xx_lcd_configure(); + void s3c24xx_lcd_start(); + void s3c24xx_lcd_stop(); + void s3c24xx_lcd_recalc(); + WRITE32_MEMBER( s3c24xx_lcd_w ); + READ32_MEMBER( s3c24xx_lcd_palette_r ); + WRITE32_MEMBER( s3c24xx_lcd_palette_w ); + void s3c24xx_clkpow_reset(); + UINT32 s3c24xx_get_fclk(); + UINT32 s3c24xx_get_hclk(); + UINT32 s3c24xx_get_pclk(); + READ32_MEMBER( s3c24xx_clkpow_r ); + WRITE32_MEMBER( s3c24xx_clkpow_w ); + void s3c24xx_irq_reset(); + void s3c24xx_check_pending_irq(); + void s3c24xx_request_irq(UINT32 int_type); + void s3c24xx_check_pending_subirq(); + void s3c24xx_request_subirq( UINT32 int_type); + void s3c24xx_check_pending_eint(); + void s3c24xx_request_eint(UINT32 number); + READ32_MEMBER( s3c24xx_irq_r ); + WRITE32_MEMBER( s3c24xx_irq_w ); + void s3c24xx_pwm_reset(); + UINT16 s3c24xx_pwm_calc_observation(int ch); + READ32_MEMBER( s3c24xx_pwm_r ); + void s3c24xx_pwm_start(int timer); + void s3c24xx_pwm_stop(int timer); + void s3c24xx_pwm_recalc(int timer); + WRITE32_MEMBER( s3c24xx_pwm_w ); + TIMER_CALLBACK_MEMBER( s3c24xx_pwm_timer_exp ); + void s3c24xx_dma_reset(); + void s3c24xx_dma_reload(int ch); + void s3c24xx_dma_trigger(int ch); + void s3c24xx_dma_request_iis(); + void s3c24xx_dma_request_pwm(); + void s3c24xx_dma_start(int ch); + void s3c24xx_dma_stop(int ch); + void s3c24xx_dma_recalc(int ch); + UINT32 s3c24xx_dma_r(UINT32 ch, UINT32 offset); + void s3c24xx_dma_w(UINT32 ch, UINT32 offset, UINT32 data, UINT32 mem_mask); + READ32_MEMBER( s3c24xx_dma_0_r ); + READ32_MEMBER( s3c24xx_dma_1_r ); + READ32_MEMBER( s3c24xx_dma_2_r ); + READ32_MEMBER( s3c24xx_dma_3_r ); + WRITE32_MEMBER( s3c24xx_dma_0_w ); + WRITE32_MEMBER( s3c24xx_dma_1_w ); + WRITE32_MEMBER( s3c24xx_dma_2_w ); + WRITE32_MEMBER( s3c24xx_dma_3_w ); + TIMER_CALLBACK_MEMBER( s3c24xx_dma_timer_exp ); + void s3c24xx_gpio_reset(); + inline UINT32 iface_gpio_port_r(int port, UINT32 mask); + inline void iface_gpio_port_w(int port, UINT32 mask, UINT32 data); + UINT16 s3c24xx_gpio_get_mask( UINT32 con, int val); + READ32_MEMBER( s3c24xx_gpio_r ); + WRITE32_MEMBER( s3c24xx_gpio_w ); + void s3c24xx_memcon_reset(); + READ32_MEMBER( s3c24xx_memcon_r ); + WRITE32_MEMBER( s3c24xx_memcon_w ); + void s3c24xx_usb_host_reset(); + READ32_MEMBER( s3c24xx_usb_host_r ); + WRITE32_MEMBER( s3c24xx_usb_host_w ); + void s3c24xx_uart_reset(); + UINT32 s3c24xx_uart_r(UINT32 ch, UINT32 offset); + void s3c24xx_uart_w(UINT32 ch, UINT32 offset, UINT32 data, UINT32 mem_mask); + READ32_MEMBER( s3c24xx_uart_0_r ); + READ32_MEMBER( s3c24xx_uart_1_r ); + READ32_MEMBER( s3c24xx_uart_2_r ); + WRITE32_MEMBER( s3c24xx_uart_0_w ); + WRITE32_MEMBER( s3c24xx_uart_1_w ); + WRITE32_MEMBER( s3c24xx_uart_2_w ); + void s3c24xx_uart_fifo_w(int uart, UINT8 data); + void s3c24xx_usb_device_reset(); + READ32_MEMBER( s3c24xx_usb_device_r ); + WRITE32_MEMBER( s3c24xx_usb_device_w ); + void s3c24xx_wdt_reset(); + UINT16 s3c24xx_wdt_calc_current_count(); + READ32_MEMBER( s3c24xx_wdt_r ); + void s3c24xx_wdt_start(); + void s3c24xx_wdt_stop(); + void s3c24xx_wdt_recalc(); + WRITE32_MEMBER( s3c24xx_wdt_w ); + TIMER_CALLBACK_MEMBER( s3c24xx_wdt_timer_exp ); + void s3c24xx_iic_reset(); + inline void iface_i2c_scl_w( int state); + inline void iface_i2c_sda_w(int state); + inline int iface_i2c_sda_r(); + void i2c_send_start(); + void i2c_send_stop(); + UINT8 i2c_receive_byte(int ack); + int i2c_send_byte(UINT8 data); + void iic_start(); + void iic_stop(); + void iic_resume(); + READ32_MEMBER( s3c24xx_iic_r ); + WRITE32_MEMBER( s3c24xx_iic_w ); + TIMER_CALLBACK_MEMBER( s3c24xx_iic_timer_exp ); + void s3c24xx_iis_reset(); + inline void iface_i2s_data_w(int ch, UINT16 data); + void s3c24xx_iis_start(); + void s3c24xx_iis_stop(); + void s3c24xx_iis_recalc(); + READ32_MEMBER( s3c24xx_iis_r ); + WRITE32_MEMBER( s3c24xx_iis_w ); + TIMER_CALLBACK_MEMBER( s3c24xx_iis_timer_exp ); + void s3c24xx_rtc_reset(); + READ32_MEMBER( s3c24xx_rtc_r ); + void s3c24xx_rtc_recalc(); + WRITE32_MEMBER( s3c24xx_rtc_w ); + TIMER_CALLBACK_MEMBER( s3c24xx_rtc_timer_tick_count_exp ); + void s3c24xx_rtc_update(); + void s3c24xx_rtc_check_alarm(); + TIMER_CALLBACK_MEMBER( s3c24xx_rtc_timer_update_exp ); + void s3c24xx_adc_reset(); + UINT32 iface_adc_data_r(int ch); + READ32_MEMBER( s3c24xx_adc_r ); + void s3c24xx_adc_start(); + WRITE32_MEMBER( s3c24xx_adc_w ); + void s3c24xx_touch_screen(int state); + void s3c24xx_spi_reset(); + UINT32 s3c24xx_spi_r(UINT32 ch, UINT32 offset); + void s3c24xx_spi_w(UINT32 ch, UINT32 offset, UINT32 data, UINT32 mem_mask); + READ32_MEMBER( s3c24xx_spi_0_r ); + READ32_MEMBER( s3c24xx_spi_1_r ); + WRITE32_MEMBER( s3c24xx_spi_0_w ); + WRITE32_MEMBER( s3c24xx_spi_1_w ); + void s3c24xx_sdi_reset(); + READ32_MEMBER( s3c24xx_sdi_r ); + WRITE32_MEMBER( s3c24xx_sdi_w ); + void s3c24xx_nand_reset(); + inline void iface_nand_command_w(UINT8 data); + inline void iface_nand_address_w(UINT8 data); + inline UINT8 iface_nand_data_r(); + inline void iface_nand_data_w(UINT8 data); + void nand_update_mecc( UINT8 *ecc, int pos, UINT8 data); + void s3c24xx_nand_update_ecc(UINT8 data); + void s3c24xx_nand_command_w(UINT8 data); + void s3c24xx_nand_address_w(UINT8 data); + UINT8 s3c24xx_nand_data_r(); + void s3c24xx_nand_data_w(UINT8 data); + READ32_MEMBER( s3c24xx_nand_r ); + void s3c24xx_nand_init_ecc(); + WRITE32_MEMBER( s3c24xx_nand_w ); + ATTR_UNUSED WRITE_LINE_MEMBER( s3c24xx_pin_frnb_w ); + void s3c24xx_nand_auto_boot(); + void s3c24xx_device_reset(); + void s3c24xx_device_start(); + + void s3c2410_uart_fifo_w( int uart, UINT8 data); + void s3c2410_touch_screen( int state); + void s3c2410_request_eint( UINT32 number); + void s3c2410_nand_calculate_mecc( UINT8 *data, UINT32 size, UINT8 *mecc); + + /******************************************************************************* + TYPE DEFINITIONS + *******************************************************************************/ + + struct s3c24xx_memcon_regs_t + { + UINT32 data[0x34/4]; + }; + + struct s3c24xx_usbhost_regs_t + { + UINT32 data[0x5C/4]; + }; + + struct s3c24xx_irq_regs_t + { + UINT32 srcpnd; + UINT32 intmod; + UINT32 intmsk; + UINT32 priority; + UINT32 intpnd; + UINT32 intoffset; + UINT32 subsrcpnd; + UINT32 intsubmsk; + }; + + struct s3c24xx_dma_regs_t + { + UINT32 disrc; + UINT32 disrcc; + UINT32 didst; + UINT32 didstc; + UINT32 dcon; + UINT32 dstat; + UINT32 dcsrc; + UINT32 dcdst; + UINT32 dmasktrig; + }; + + struct s3c24xx_clkpow_regs_t + { + UINT32 locktime; + UINT32 mpllcon; + UINT32 upllcon; + UINT32 clkcon; + UINT32 clkslow; + UINT32 clkdivn; + }; + + struct s3c24xx_lcd_regs_t + { + UINT32 lcdcon1; + UINT32 lcdcon2; + UINT32 lcdcon3; + UINT32 lcdcon4; + UINT32 lcdcon5; + UINT32 lcdsaddr1; + UINT32 lcdsaddr2; + UINT32 lcdsaddr3; + UINT32 redlut; + UINT32 greenlut; + UINT32 bluelut; + UINT32 reserved[8]; + UINT32 dithmode; + UINT32 tpal; + UINT32 lcdintpnd; + UINT32 lcdsrcpnd; + UINT32 lcdintmsk; + UINT32 lpcsel; + }; + + struct s3c24xx_lcdpal_regs_t + { + UINT32 data[0x400/4]; + }; + + struct s3c24xx_nand_regs_t + { + UINT32 nfconf; + UINT32 nfcmd; + UINT32 nfaddr; + UINT32 nfdata; + UINT32 nfstat; + UINT32 nfecc; + }; + + struct s3c24xx_uart_regs_t + { + UINT32 ulcon; + UINT32 ucon; + UINT32 ufcon; + UINT32 umcon; + UINT32 utrstat; + UINT32 uerstat; + UINT32 ufstat; + UINT32 umstat; + UINT32 utxh; + UINT32 urxh; + UINT32 ubrdiv; + }; + + struct s3c24xx_pwm_regs_t + { + UINT32 tcfg0; + UINT32 tcfg1; + UINT32 tcon; + UINT32 tcntb0; + UINT32 tcmpb0; + UINT32 tcnto0; + UINT32 tcntb1; + UINT32 tcmpb1; + UINT32 tcnto1; + UINT32 tcntb2; + UINT32 tcmpb2; + UINT32 tcnto2; + UINT32 tcntb3; + UINT32 tcmpb3; + UINT32 tcnto3; + UINT32 tcntb4; + UINT32 tcnto4; + }; + + struct s3c24xx_usbdev_regs_t + { + UINT32 data[0x130/4]; + }; + + struct s3c24xx_wdt_regs_t + { + UINT32 wtcon; + UINT32 wtdat; + UINT32 wtcnt; + }; + + struct s3c24xx_iic_regs_t + { + UINT32 iiccon; + UINT32 iicstat; + UINT32 iicadd; + UINT32 iicds; + }; + + struct s3c24xx_iis_regs_t + { + UINT32 iiscon; + UINT32 iismod; + UINT32 iispsr; + UINT32 iisfcon; + UINT32 iisfifo; + }; + + struct s3c24xx_gpio_regs_t + { + UINT32 gpacon; + UINT32 gpadat; + UINT32 pad_08; + UINT32 pad_0c; + UINT32 gpbcon; + UINT32 gpbdat; + UINT32 gpbup; + UINT32 pad_1c; + UINT32 gpccon; + UINT32 gpcdat; + UINT32 gpcup; + UINT32 pad_2c; + UINT32 gpdcon; + UINT32 gpddat; + UINT32 gpdup; + UINT32 pad_3c; + UINT32 gpecon; + UINT32 gpedat; + UINT32 gpeup; + UINT32 pad_4c; + UINT32 gpfcon; + UINT32 gpfdat; + UINT32 gpfup; + UINT32 pad_5c; + UINT32 gpgcon; + UINT32 gpgdat; + UINT32 gpgup; + UINT32 pad_6c; + UINT32 gphcon; + UINT32 gphdat; + UINT32 gphup; + UINT32 pad_7c; + UINT32 misccr; + UINT32 dclkcon; + UINT32 extint0; + UINT32 extint1; + UINT32 extint2; + UINT32 eintflt0; + UINT32 eintflt1; + UINT32 eintflt2; + UINT32 eintflt3; + UINT32 eintmask; + UINT32 eintpend; + UINT32 gstatus0; + UINT32 gstatus1; + UINT32 gstatus2; + UINT32 gstatus3; + UINT32 gstatus4; + }; + + struct s3c24xx_rtc_regs_t + { + UINT32 rtccon; + UINT32 ticnt; + UINT32 reserved[2]; + UINT32 rtcalm; + UINT32 almsec; + UINT32 almmin; + UINT32 almhour; + UINT32 almday; + UINT32 almmon; + UINT32 almyear; + UINT32 rtcrst; + UINT32 bcdsec; + UINT32 bcdmin; + UINT32 bcdhour; + UINT32 bcdday; + UINT32 bcddow; + UINT32 bcdmon; + UINT32 bcdyear; + }; + + struct s3c24xx_adc_regs_t + { + UINT32 adccon; + UINT32 adctsc; + UINT32 adcdly; + UINT32 adcdat0; + UINT32 adcdat1; + }; + + struct s3c24xx_spi_regs_t + { + UINT32 spcon; + UINT32 spsta; + UINT32 sppin; + UINT32 sppre; + UINT32 sptdat; + UINT32 sprdat; + }; + + struct s3c24xx_sdi_regs_t + { + UINT32 data[0x44/4]; + }; + + struct s3c24xx_memcon_t + { + s3c24xx_memcon_regs_t regs; + }; + + struct s3c24xx_usbhost_t + { + s3c24xx_usbhost_regs_t regs; + }; + + struct s3c24xx_irq_t + { + s3c24xx_irq_regs_t regs; + int line_irq, line_fiq; + }; + + struct s3c24xx_dma_t + { + s3c24xx_dma_regs_t regs; + emu_timer *timer; + }; + + struct s3c24xx_clkpow_t + { + s3c24xx_clkpow_regs_t regs; + }; + + struct s3c24xx_lcd_t + { + s3c24xx_lcd_regs_t regs; + emu_timer *timer; + bitmap_rgb32 *bitmap[2]; + UINT32 vramaddr_cur; + UINT32 vramaddr_max; + UINT32 offsize; + UINT32 pagewidth_cur; + UINT32 pagewidth_max; + UINT32 bppmode; + UINT32 bswp, hwswp; + int vpos, hpos; + double framerate; + UINT32 tpal; + UINT32 hpos_min, hpos_max, vpos_min, vpos_max; + UINT32 dma_data, dma_bits; + }; + + struct s3c24xx_lcdpal_t + { + s3c24xx_lcdpal_regs_t regs; + }; + + struct s3c24xx_nand_t + { + s3c24xx_nand_regs_t regs; + UINT8 mecc[3]; + int ecc_pos, data_count; + }; + + struct s3c24xx_uart_t + { + s3c24xx_uart_regs_t regs; + }; + + struct s3c24xx_pwm_t + { + s3c24xx_pwm_regs_t regs; + emu_timer *timer[5]; + UINT32 cnt[5]; + UINT32 cmp[5]; + UINT32 freq[5]; + }; + + struct s3c24xx_usbdev_t + { + s3c24xx_usbdev_regs_t regs; + }; + + struct s3c24xx_wdt_t + { + s3c24xx_wdt_regs_t regs; + emu_timer *timer; + UINT32 freq, cnt; + }; + + struct s3c24xx_iic_t + { + s3c24xx_iic_regs_t regs; + emu_timer *timer; + int count; + }; + + struct s3c24xx_iis_t + { + s3c24xx_iis_regs_t regs; + emu_timer *timer; + UINT16 fifo[16/2]; + int fifo_index; + }; + + struct s3c24xx_gpio_t + { + s3c24xx_gpio_regs_t regs; + }; + + struct s3c24xx_rtc_t + { + s3c24xx_rtc_regs_t regs; + emu_timer *timer_tick_count; + emu_timer *timer_update; + }; + + struct s3c24xx_adc_t + { + s3c24xx_adc_regs_t regs; + }; + + struct s3c24xx_spi_t + { + s3c24xx_spi_regs_t regs; + }; + + struct s3c24xx_sdi_t + { + s3c24xx_sdi_regs_t regs; + }; + + UINT8 m_steppingstone[4*1024]; + s3c24xx_memcon_t m_memcon; + s3c24xx_usbhost_t m_usbhost; + s3c24xx_irq_t m_irq; + s3c24xx_dma_t m_dma[S3C24XX_DMA_COUNT]; + s3c24xx_clkpow_t m_clkpow; + s3c24xx_lcd_t m_lcd; + s3c24xx_lcdpal_t m_lcdpal; + s3c24xx_nand_t m_nand; + s3c24xx_uart_t m_uart[S3C24XX_UART_COUNT]; + s3c24xx_pwm_t m_pwm; + s3c24xx_usbdev_t m_usbdev; + s3c24xx_wdt_t m_wdt; + s3c24xx_iic_t m_iic; + s3c24xx_iis_t m_iis; + s3c24xx_gpio_t m_gpio; + s3c24xx_rtc_t m_rtc; + s3c24xx_adc_t m_adc; + s3c24xx_spi_t m_spi[S3C24XX_SPI_COUNT]; + s3c24xx_sdi_t m_sdi; + required_device m_cpu; + devcb_read32 m_pin_r_cb; + devcb_write32 m_pin_w_cb; + devcb_read32 m_port_r_cb; + devcb_write32 m_port_w_cb; + devcb_write_line m_scl_w_cb; + devcb_read_line m_sda_r_cb; + devcb_write_line m_sda_w_cb; + devcb_read32 m_data_r_cb; + devcb_write16 m_data_w_cb; + devcb_write8 m_command_w_cb; + devcb_write8 m_address_w_cb; + devcb_read8 m_nand_data_r_cb; + devcb_write8 m_nand_data_w_cb; + int m_flags; +}; + +extern const device_type S3C2410; + + +#endif diff --git a/src/devices/machine/s3c2440.c b/src/devices/machine/s3c2440.c new file mode 100644 index 00000000000..eaa0301d157 --- /dev/null +++ b/src/devices/machine/s3c2440.c @@ -0,0 +1,175 @@ +// license:BSD-3-Clause +// copyright-holders:Tim Schuerewegen +/******************************************************************************* + + Samsung S3C2440 + + (c) 2010 Tim Schuerewegen + +*******************************************************************************/ + +#include "emu.h" +#include "cpu/arm7/arm7.h" +#include "cpu/arm7/arm7core.h" +#include "machine/s3c2440.h" +#include "sound/dac.h" + +#define VERBOSE_LEVEL ( 0 ) + +INLINE void ATTR_PRINTF(3,4) verboselog( running_machine &machine, int n_level, const char *s_fmt, ...) +{ + if (VERBOSE_LEVEL >= n_level) + { + va_list v; + char buf[32768]; + va_start( v, s_fmt); + vsprintf( buf, s_fmt, v); + va_end( v); + logerror( "%s: %s", machine.describe_context( ), buf); + } +} + +#define DEVICE_S3C2440 +#define S3C24_CLASS_NAME s3c2440_device +#include "machine/s3c24xx.inc" +#undef DEVICE_S3C2440 + +UINT32 s3c2440_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + return s3c24xx_video_update( screen, bitmap, cliprect); +} + +const device_type S3C2440 = &device_creator; + +s3c2440_device::s3c2440_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, S3C2440, "Samsung S3C2440", tag, owner, clock, "s3c2440", __FILE__), + m_palette(*this), + m_cpu(*this, ":maincpu"), + m_pin_r_cb(*this), + m_pin_w_cb(*this), + m_port_r_cb(*this), + m_port_w_cb(*this), + m_scl_w_cb(*this), + m_sda_r_cb(*this), + m_sda_w_cb(*this), + m_data_r_cb(*this), + m_data_w_cb(*this), + m_command_w_cb(*this), + m_address_w_cb(*this), + m_nand_data_r_cb(*this), + m_nand_data_w_cb(*this), + m_flags(0) +{ + memset(m_steppingstone, 0, sizeof(m_steppingstone)); + memset(&m_memcon, 0, sizeof(m_memcon)); + memset(&m_usbhost, 0, sizeof(m_usbhost)); + memset(&m_irq, 0, sizeof(m_irq)); + memset(m_dma, 0, sizeof(m_dma)); + memset(&m_clkpow, 0, sizeof(m_clkpow)); + memset(&m_lcd, 0, sizeof(m_lcd)); + memset(&m_lcdpal, 0, sizeof(m_lcdpal)); + memset(&m_nand, 0, sizeof(m_nand)); + memset(&m_cam, 0, sizeof(m_cam)); + memset(m_uart, 0, sizeof(m_uart)); + memset(&m_pwm, 0, sizeof(m_pwm)); + memset(&m_usbdev, 0, sizeof(m_usbdev)); + memset(&m_wdt, 0, sizeof(m_wdt)); + memset(&m_iic, 0, sizeof(m_iic)); + memset(&m_iis, 0, sizeof(m_iis)); + memset(&m_gpio, 0, sizeof(m_gpio)); + memset(&m_rtc, 0, sizeof(m_rtc)); + memset(&m_adc, 0, sizeof(m_adc)); + memset(m_spi, 0, sizeof(m_spi)); + memset(&m_sdi, 0, sizeof(m_sdi)); + memset(&m_ac97, 0, sizeof(m_ac97)); +} + +s3c2440_device::~s3c2440_device() +{ +} + +//------------------------------------------------- +// static_set_palette_tag: Set the tag of the +// palette device +//------------------------------------------------- + +void s3c2440_device::static_set_palette_tag(device_t &device, const char *tag) +{ + downcast(device).m_palette.set_tag(tag); +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void s3c2440_device::device_start() +{ + address_space &space = m_cpu->memory().space( AS_PROGRAM); + space.install_readwrite_handler(0x48000000, 0x4800003b, read32_delegate(FUNC(s3c2440_device::s3c24xx_memcon_r), this), write32_delegate(FUNC(s3c2440_device::s3c24xx_memcon_w), this)); + space.install_readwrite_handler(0x49000000, 0x4900005b, read32_delegate(FUNC(s3c2440_device::s3c24xx_usb_host_r), this), write32_delegate(FUNC(s3c2440_device::s3c24xx_usb_host_w), this)); + space.install_readwrite_handler(0x4a000000, 0x4a00001f, read32_delegate(FUNC(s3c2440_device::s3c24xx_irq_r), this), write32_delegate(FUNC(s3c2440_device::s3c24xx_irq_w), this)); + space.install_readwrite_handler(0x4b000000, 0x4b000023, read32_delegate(FUNC(s3c2440_device::s3c24xx_dma_0_r), this), write32_delegate(FUNC(s3c2440_device::s3c24xx_dma_0_w), this)); + space.install_readwrite_handler(0x4b000040, 0x4b000063, read32_delegate(FUNC(s3c2440_device::s3c24xx_dma_1_r), this), write32_delegate(FUNC(s3c2440_device::s3c24xx_dma_1_w), this)); + space.install_readwrite_handler(0x4b000080, 0x4b0000a3, read32_delegate(FUNC(s3c2440_device::s3c24xx_dma_2_r), this), write32_delegate(FUNC(s3c2440_device::s3c24xx_dma_2_w), this)); + space.install_readwrite_handler(0x4b0000c0, 0x4b0000e3, read32_delegate(FUNC(s3c2440_device::s3c24xx_dma_3_r), this), write32_delegate(FUNC(s3c2440_device::s3c24xx_dma_3_w), this)); + space.install_readwrite_handler(0x4c000000, 0x4c00001b, read32_delegate(FUNC(s3c2440_device::s3c24xx_clkpow_r), this), write32_delegate(FUNC(s3c2440_device::s3c24xx_clkpow_w), this)); + space.install_readwrite_handler(0x4d000000, 0x4d000063, read32_delegate(FUNC(s3c2440_device::s3c24xx_lcd_r), this), write32_delegate(FUNC(s3c2440_device::s3c24xx_lcd_w), this)); + space.install_readwrite_handler(0x4d000400, 0x4d0007ff, read32_delegate(FUNC(s3c2440_device::s3c24xx_lcd_palette_r), this), write32_delegate(FUNC(s3c2440_device::s3c24xx_lcd_palette_w), this)); + space.install_readwrite_handler(0x4e000000, 0x4e00003f, read32_delegate(FUNC(s3c2440_device::s3c24xx_nand_r), this), write32_delegate(FUNC(s3c2440_device::s3c24xx_nand_w), this)); + space.install_readwrite_handler(0x4f000000, 0x4f0000a3, read32_delegate(FUNC(s3c2440_device::s3c24xx_cam_r), this), write32_delegate(FUNC(s3c2440_device::s3c24xx_cam_w), this)); + space.install_readwrite_handler(0x50000000, 0x5000002b, read32_delegate(FUNC(s3c2440_device::s3c24xx_uart_0_r), this), write32_delegate(FUNC(s3c2440_device::s3c24xx_uart_0_w), this)); + space.install_readwrite_handler(0x50004000, 0x5000402b, read32_delegate(FUNC(s3c2440_device::s3c24xx_uart_1_r), this), write32_delegate(FUNC(s3c2440_device::s3c24xx_uart_1_w), this)); + space.install_readwrite_handler(0x50008000, 0x5000802b, read32_delegate(FUNC(s3c2440_device::s3c24xx_uart_2_r), this), write32_delegate(FUNC(s3c2440_device::s3c24xx_uart_2_w), this)); + space.install_readwrite_handler(0x51000000, 0x51000043, read32_delegate(FUNC(s3c2440_device::s3c24xx_pwm_r), this), write32_delegate(FUNC(s3c2440_device::s3c24xx_pwm_w), this)); + space.install_readwrite_handler(0x52000140, 0x5200026f, read32_delegate(FUNC(s3c2440_device::s3c24xx_usb_device_r), this), write32_delegate(FUNC(s3c2440_device::s3c24xx_usb_device_w), this)); + space.install_readwrite_handler(0x53000000, 0x5300000b, read32_delegate(FUNC(s3c2440_device::s3c24xx_wdt_r), this), write32_delegate(FUNC(s3c2440_device::s3c24xx_wdt_w), this)); + space.install_readwrite_handler(0x54000000, 0x54000013, read32_delegate(FUNC(s3c2440_device::s3c24xx_iic_r), this), write32_delegate(FUNC(s3c2440_device::s3c24xx_iic_w), this)); + space.install_readwrite_handler(0x55000000, 0x55000013, read32_delegate(FUNC(s3c2440_device::s3c24xx_iis_r), this), write32_delegate(FUNC(s3c2440_device::s3c24xx_iis_w), this)); + space.install_readwrite_handler(0x56000000, 0x560000df, read32_delegate(FUNC(s3c2440_device::s3c24xx_gpio_r), this), write32_delegate(FUNC(s3c2440_device::s3c24xx_gpio_w), this)); + space.install_readwrite_handler(0x57000040, 0x5700008b, read32_delegate(FUNC(s3c2440_device::s3c24xx_rtc_r), this), write32_delegate(FUNC(s3c2440_device::s3c24xx_rtc_w), this)); + space.install_readwrite_handler(0x58000000, 0x58000017, read32_delegate(FUNC(s3c2440_device::s3c24xx_adc_r), this), write32_delegate(FUNC(s3c2440_device::s3c24xx_adc_w), this)); + space.install_readwrite_handler(0x59000000, 0x59000017, read32_delegate(FUNC(s3c2440_device::s3c24xx_spi_0_r), this), write32_delegate(FUNC(s3c2440_device::s3c24xx_spi_0_w), this)); + space.install_readwrite_handler(0x59000020, 0x59000037, read32_delegate(FUNC(s3c2440_device::s3c24xx_spi_1_r), this), write32_delegate(FUNC(s3c2440_device::s3c24xx_spi_1_w), this)); + space.install_readwrite_handler(0x5a000000, 0x5a000043, read32_delegate(FUNC(s3c2440_device::s3c24xx_sdi_r), this), write32_delegate(FUNC(s3c2440_device::s3c24xx_sdi_w), this)); + space.install_readwrite_handler(0x5b000000, 0x5b00001f, read32_delegate(FUNC(s3c2440_device::s3c24xx_ac97_r), this), write32_delegate(FUNC(s3c2440_device::s3c24xx_ac97_w), this)); + + s3c24xx_device_start(); + + s3c24xx_video_start(); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void s3c2440_device::device_reset() +{ + s3c24xx_device_reset(); +} + + +void s3c2440_device::s3c2440_uart_fifo_w(int uart, UINT8 data) +{ + s3c24xx_uart_fifo_w( uart, data); +} + +void s3c2440_device::s3c2440_touch_screen(int state) +{ + s3c24xx_touch_screen( state); +} + +void s3c2440_device::s3c2440_request_irq(UINT32 int_type) +{ + s3c24xx_request_irq( int_type); +} + +void s3c2440_device::s3c2440_request_eint(UINT32 number) +{ + s3c24xx_request_eint( number); +} + +WRITE_LINE_MEMBER( s3c2440_device::frnb_w ) +{ + s3c24xx_pin_frnb_w(state); +} diff --git a/src/devices/machine/s3c2440.h b/src/devices/machine/s3c2440.h new file mode 100644 index 00000000000..b76148eca09 --- /dev/null +++ b/src/devices/machine/s3c2440.h @@ -0,0 +1,1157 @@ +// license:BSD-3-Clause +// copyright-holders:Tim Schuerewegen +/******************************************************************************* + + Samsung S3C2440 + +*******************************************************************************/ + +#ifndef __S3C2440_H__ +#define __S3C2440_H__ + +/******************************************************************************* + MACROS / CONSTANTS +*******************************************************************************/ + +#define S3C2440_TAG "s3c2440" + +#define MCFG_S3C2440_PALETTE(_palette_tag) \ + s3c2440_device::static_set_palette_tag(*device, "^" _palette_tag); + +#define MCFG_S3C2440_CORE_PIN_R_CB(_devcb) \ + devcb = &s3c2440_device::set_core_pin_r_callback(*device, DEVCB_##_devcb); + +#define MCFG_S3C2440_CORE_PIN_W_CB(_devcb) \ + devcb = &s3c2440_device::set_core_pin_w_callback(*device, DEVCB_##_devcb); + +#define MCFG_S3C2440_GPIO_PORT_R_CB(_devcb) \ + devcb = &s3c2440_device::set_gpio_port_r_callback(*device, DEVCB_##_devcb); + +#define MCFG_S3C2440_GPIO_PORT_W_CB(_devcb) \ + devcb = &s3c2440_device::set_gpio_port_w_callback(*device, DEVCB_##_devcb); + +#define MCFG_S3C2440_I2C_SCL_W_CB(_devcb) \ + devcb = &s3c2440_device::set_i2c_scl_w_callback(*device, DEVCB_##_devcb); + +#define MCFG_S3C2440_I2C_SDA_R_CB(_devcb) \ + devcb = &s3c2440_device::set_i2c_sda_r_callback(*device, DEVCB_##_devcb); + +#define MCFG_S3C2440_I2C_SDA_W_CB(_devcb) \ + devcb = &s3c2440_device::set_i2c_sda_w_callback(*device, DEVCB_##_devcb); + +#define MCFG_S3C2440_ADC_DATA_R_CB(_devcb) \ + devcb = &s3c2440_device::set_adc_data_r_callback(*device, DEVCB_##_devcb); + +#define MCFG_S3C2440_I2S_DATA_W_CB(_devcb) \ + devcb = &s3c2440_device::set_i2s_data_w_callback(*device, DEVCB_##_devcb); + +#define MCFG_S3C2440_NAND_COMMAND_W_CB(_devcb) \ + devcb = &s3c2440_device::set_nand_command_w_callback(*device, DEVCB_##_devcb); + +#define MCFG_S3C2440_NAND_ADDRESS_W_CB(_devcb) \ + devcb = &s3c2440_device::set_nand_address_w_callback(*device, DEVCB_##_devcb); + +#define MCFG_S3C2440_NAND_DATA_R_CB(_devcb) \ + devcb = &s3c2440_device::set_nand_data_r_callback(*device, DEVCB_##_devcb); + +#define MCFG_S3C2440_NAND_DATA_W_CB(_devcb) \ + devcb = &s3c2440_device::set_nand_data_w_callback(*device, DEVCB_##_devcb); + +#define MCFG_S3C2440_LCD_FLAGS(_flags) \ + s3c2440_device::set_lcd_flags(*device, _flags); + +enum +{ + S3C2440_GPIO_PORT_A = 0, + S3C2440_GPIO_PORT_B, + S3C2440_GPIO_PORT_C, + S3C2440_GPIO_PORT_D, + S3C2440_GPIO_PORT_E, + S3C2440_GPIO_PORT_F, + S3C2440_GPIO_PORT_G, + S3C2440_GPIO_PORT_H, + S3C2440_GPIO_PORT_J +}; + +enum +{ + S3C2440_CORE_PIN_NCON = 0, + S3C2440_CORE_PIN_OM0, + S3C2440_CORE_PIN_OM1 +}; + +/******************************************************************************* + MACROS & CONSTANTS +*******************************************************************************/ + +/* Interface */ + +#define S3C24XX_INTERFACE_LCD_REVERSE 1 + +/* Memory Controller */ + +#define S3C24XX_BASE_MEMCON 0x48000000 + +/* USB Host Controller */ + +#define S3C24XX_BASE_USBHOST 0x49000000 + +/* Interrupt Controller */ + +#define S3C24XX_BASE_INT 0x4A000000 + +#define S3C24XX_SRCPND (0x00 / 4) // Interrupt Request Status +#define S3C24XX_INTMOD (0x04 / 4) // Interrupt Mode Control +#define S3C24XX_INTMSK (0x08 / 4) // Interrupt Mask Control +#define S3C24XX_PRIORITY (0x0C / 4) // IRQ Priority Control +#define S3C24XX_INTPND (0x10 / 4) // Interrupt Request Status +#define S3C24XX_INTOFFSET (0x14 / 4) // Interrupt Request Source Offset +#define S3C24XX_SUBSRCPND (0x18 / 4) // Sub Source Pending +#define S3C24XX_INTSUBMSK (0x1C / 4) // Interrupt Sub Mask + +/* DMA */ + +#define S3C24XX_BASE_DMA_0 0x4B000000 +#define S3C24XX_BASE_DMA_1 0x4B000040 +#define S3C24XX_BASE_DMA_2 0x4B000080 +#define S3C24XX_BASE_DMA_3 0x4B0000C0 + +#define S3C24XX_DISRC (0x00 / 4) // DMA Initial Source +#define S3C24XX_DISRCC (0x04 / 4) // DMA Initial Source Control +#define S3C24XX_DIDST (0x08 / 4) // DMA Initial Destination +#define S3C24XX_DIDSTC (0x0C / 4) // DMA Initial Destination Control +#define S3C24XX_DCON (0x10 / 4) // DMA Control +#define S3C24XX_DSTAT (0x14 / 4) // DMA Count +#define S3C24XX_DCSRC (0x18 / 4) // DMA Current Source +#define S3C24XX_DCDST (0x1C / 4) // DMA Current Destination +#define S3C24XX_DMASKTRIG (0x20 / 4) // DMA Mask Trigger + +/* Clock & Power Management */ + +#define S3C24XX_BASE_CLKPOW 0x4C000000 + +#define S3C24XX_LOCKTIME (0x00 / 4) // PLL Lock Time Counter +#define S3C24XX_MPLLCON (0x04 / 4) // MPLL Control +#define S3C24XX_UPLLCON (0x08 / 4) // UPLL Control +#define S3C24XX_CLKCON (0x0C / 4) // Clock Generator Control +#define S3C24XX_CLKSLOW (0x10 / 4) // Slow Clock Control +#define S3C24XX_CLKDIVN (0x14 / 4) // Clock Divider Control +#define S3C24XX_CAMDIVN (0x18 / 4) // Camera Clock Divider Control + +/* LCD Controller */ + +#define S3C24XX_BASE_LCD 0x4D000000 +#define S3C24XX_BASE_LCDPAL 0x4D000400 + +#define S3C24XX_LCDCON1 (0x00 / 4) // LCD Control 1 +#define S3C24XX_LCDCON2 (0x04 / 4) // LCD Control 2 +#define S3C24XX_LCDCON3 (0x08 / 4) // LCD Control 3 +#define S3C24XX_LCDCON4 (0x0C / 4) // LCD Control 4 +#define S3C24XX_LCDCON5 (0x10 / 4) // LCD Control 5 +#define S3C24XX_LCDSADDR1 (0x14 / 4) // STN/TFT: Frame Buffer Start Address 1 +#define S3C24XX_LCDSADDR2 (0x18 / 4) // STN/TFT: Frame Buffer Start Address 2 +#define S3C24XX_LCDSADDR3 (0x1C / 4) // STN/TFT: Virtual Screen Address Set +#define S3C24XX_REDLUT (0x20 / 4) // STN: Red Lookup Table +#define S3C24XX_GREENLUT (0x24 / 4) // STN: Green Lookup Table +#define S3C24XX_BLUELUT (0x28 / 4) // STN: Blue Lookup Table +#define S3C24XX_DITHMODE (0x4C / 4) // STN: Dithering Mode +#define S3C24XX_TPAL (0x50 / 4) // TFT: Temporary Palette +#define S3C24XX_LCDINTPND (0x54 / 4) // LCD Interrupt Pending +#define S3C24XX_LCDSRCPND (0x58 / 4) // LCD Interrupt Source +#define S3C24XX_LCDINTMSK (0x5C / 4) // LCD Interrupt Mask +#define S3C24XX_TCONSEL (0x60 / 4) // TCON (LPC3600/LCC3600) Control + +/* NAND Flash */ + +#define S3C24XX_BASE_NAND 0x4E000000 + +#define S3C24XX_NFCONF (0x00 / 4) // NAND Flash Configuration +#define S3C24XX_NFCONT (0x04 / 4) // NAND Flash Control +#define S3C24XX_NFCMD (0x08 / 4) // NAND Flash Command +#define S3C24XX_NFADDR (0x0C / 4) // NAND Flash Address +#define S3C24XX_NFDATA (0x10 / 4) // NAND Flash Data +#define S3C24XX_NFMECCD0 (0x14 / 4) // NAND Flash Main Area ECC0/1 +#define S3C24XX_NFMECCD1 (0x18 / 4) // NAND Flash Main Area ECC2/3 +#define S3C24XX_NFSECCD (0x1C / 4) // NAND Flash Spare Area Ecc +#define S3C24XX_NFSTAT (0x20 / 4) // NAND Flash Operation Status +#define S3C24XX_NFESTAT0 (0x24 / 4) // NAND Flash ECC Status For I/O[7:0] +#define S3C24XX_NFESTAT1 (0x28 / 4) // NAND Flash ECC Status For I/O[15:8] +#define S3C24XX_NFMECC0 (0x2C / 4) // NAND Flash Main Area ECC0 Status +#define S3C24XX_NFMECC1 (0x30 / 4) // NAND Flash Main Area ECC1 Status +#define S3C24XX_NFSECC (0x34 / 4) // NAND Flash Spare Area ECC Status +#define S3C24XX_NFSBLK (0x38 / 4) // NAND Flash Start Block Address +#define S3C24XX_NFEBLK (0x3C / 4) // NAND Flash End Block Address + +/* Camera Interface */ + +#define S3C24XX_BASE_CAM 0x4F000000 + +/* UART */ + +#define S3C24XX_BASE_UART_0 0x50000000 +#define S3C24XX_BASE_UART_1 0x50004000 +#define S3C24XX_BASE_UART_2 0x50008000 + +#define S3C24XX_ULCON (0x00 / 4) // UART Line Control +#define S3C24XX_UCON (0x04 / 4) // UART Control +#define S3C24XX_UFCON (0x08 / 4) // UART FIFO Control +#define S3C24XX_UMCON (0x0C / 4) // UART Modem Control +#define S3C24XX_UTRSTAT (0x10 / 4) // UART Tx/Rx Status +#define S3C24XX_UERSTAT (0x14 / 4) // UART Rx Error Status +#define S3C24XX_UFSTAT (0x18 / 4) // UART FIFO Status +#define S3C24XX_UMSTAT (0x1C / 4) // UART Modem Status +#define S3C24XX_UTXH (0x20 / 4) // UART Transmission Hold +#define S3C24XX_URXH (0x24 / 4) // UART Receive Buffer +#define S3C24XX_UBRDIV (0x28 / 4) // UART Baud Rate Divisor + +/* PWM Timer */ + +#define S3C24XX_BASE_PWM 0x51000000 + +#define S3C24XX_TCFG0 (0x00 / 4) // Timer Configuration +#define S3C24XX_TCFG1 (0x04 / 4) // Timer Configuration +#define S3C24XX_TCON (0x08 / 4) // Timer Control +#define S3C24XX_TCNTB0 (0x0C / 4) // Timer Count Buffer 0 +#define S3C24XX_TCMPB0 (0x10 / 4) // Timer Compare Buffer 0 +#define S3C24XX_TCNTO0 (0x14 / 4) // Timer Count Observation 0 +#define S3C24XX_TCNTB1 (0x18 / 4) // Timer Count Buffer 1 +#define S3C24XX_TCMPB1 (0x1C / 4) // Timer Compare Buffer 1 +#define S3C24XX_TCNTO1 (0x20 / 4) // Timer Count Observation 1 +#define S3C24XX_TCNTB2 (0x24 / 4) // Timer Count Buffer 2 +#define S3C24XX_TCMPB2 (0x28 / 4) // Timer Compare Buffer 2 +#define S3C24XX_TCNTO2 (0x2C / 4) // Timer Count Observation 2 +#define S3C24XX_TCNTB3 (0x30 / 4) // Timer Count Buffer 3 +#define S3C24XX_TCMPB3 (0x34 / 4) // Timer Compare Buffer 3 +#define S3C24XX_TCNTO3 (0x38 / 4) // Timer Count Observation 3 +#define S3C24XX_TCNTB4 (0x3C / 4) // Timer Count Buffer 4 +#define S3C24XX_TCNTO4 (0x40 / 4) // Timer Count Observation 4 + +/* USB Device */ + +#define S3C24XX_BASE_USBDEV 0x52000140 + +/* Watchdog Timer */ + +#define S3C24XX_BASE_WDT 0x53000000 + +#define S3C24XX_WTCON (0x00 / 4) // Watchdog Timer Mode +#define S3C24XX_WTDAT (0x04 / 4) // Watchdog Timer Data +#define S3C24XX_WTCNT (0x08 / 4) // Watchdog Timer Count + +/* IIC */ + +#define S3C24XX_BASE_IIC 0x54000000 + +#define S3C24XX_IICCON (0x00 / 4) // IIC Control +#define S3C24XX_IICSTAT (0x04 / 4) // IIC Status +#define S3C24XX_IICADD (0x08 / 4) // IIC Address +#define S3C24XX_IICDS (0x0C / 4) // IIC Data Shift +#define S3C24XX_IICLC (0x10 / 4) // IIC Multi-Master Line Control + +/* IIS */ + +#define S3C24XX_BASE_IIS 0x55000000 + +#define S3C24XX_IISCON (0x00 / 4) // IIS Control +#define S3C24XX_IISMOD (0x04 / 4) // IIS Mode +#define S3C24XX_IISPSR (0x08 / 4) // IIS Prescaler +#define S3C24XX_IISFCON (0x0C / 4) // IIS FIFO Control +#define S3C24XX_IISFIFO (0x10 / 4) // IIS FIFO Entry + +/* I/O Port */ + +#define S3C24XX_BASE_GPIO 0x56000000 + +#define S3C24XX_GPACON (0x00 / 4) // Port A Control +#define S3C24XX_GPADAT (0x04 / 4) // Port A Data +#define S3C24XX_GPBCON (0x10 / 4) // Port B Control +#define S3C24XX_GPBDAT (0x14 / 4) // Port B Data +#define S3C24XX_GPBUP (0x18 / 4) // Pull-up Control B +#define S3C24XX_GPCCON (0x20 / 4) // Port C Control +#define S3C24XX_GPCDAT (0x24 / 4) // Port C Data +#define S3C24XX_GPCUP (0x28 / 4) // Pull-up Control C +#define S3C24XX_GPDCON (0x30 / 4) // Port D Control +#define S3C24XX_GPDDAT (0x34 / 4) // Port D Data +#define S3C24XX_GPDUP (0x38 / 4) // Pull-up Control D +#define S3C24XX_GPECON (0x40 / 4) // Port E Control +#define S3C24XX_GPEDAT (0x44 / 4) // Port E Data +#define S3C24XX_GPEUP (0x48 / 4) // Pull-up Control E +#define S3C24XX_GPFCON (0x50 / 4) // Port F Control +#define S3C24XX_GPFDAT (0x54 / 4) // Port F Data +#define S3C24XX_GPFUP (0x58 / 4) // Pull-up Control F +#define S3C24XX_GPGCON (0x60 / 4) // Port G Control +#define S3C24XX_GPGDAT (0x64 / 4) // Port G Data +#define S3C24XX_GPGUP (0x68 / 4) // Pull-up Control G +#define S3C24XX_GPHCON (0x70 / 4) // Port H Control +#define S3C24XX_GPHDAT (0x74 / 4) // Port H Data +#define S3C24XX_GPHUP (0x78 / 4) // Pull-up Control H +#define S3C24XX_MISCCR (0x80 / 4) // Miscellaneous Control +#define S3C24XX_DCLKCON (0x84 / 4) // DCLK0/1 Control +#define S3C24XX_EXTINT0 (0x88 / 4) // External Interrupt Control Register 0 +#define S3C24XX_EXTINT1 (0x8C / 4) // External Interrupt Control Register 1 +#define S3C24XX_EXTINT2 (0x90 / 4) // External Interrupt Control Register 2 +#define S3C24XX_EINTFLT0 (0x94 / 4) // Reserved +#define S3C24XX_EINTFLT1 (0x98 / 4) // Reserved +#define S3C24XX_EINTFLT2 (0x9C / 4) // External Interrupt Filter Control Register 2 +#define S3C24XX_EINTFLT3 (0xA0 / 4) // External Interrupt Filter Control Register 3 +#define S3C24XX_EINTMASK (0xA4 / 4) // External Interrupt Mask +#define S3C24XX_EINTPEND (0xA8 / 4) // External Interrupt Pending +#define S3C24XX_GSTATUS0 (0xAC / 4) // External Pin Status +#define S3C24XX_GSTATUS1 (0xB0 / 4) // Chip ID +#define S3C24XX_GSTATUS2 (0xB4 / 4) // Reset Status +#define S3C24XX_GSTATUS3 (0xB8 / 4) // Inform Register +#define S3C24XX_GSTATUS4 (0xBC / 4) // Inform Register +#define S3C24XX_MSLCON (0xCC / 4) // Memory Sleep Control Register +#define S3C24XX_GPJCON (0xD0 / 4) // Port J Control +#define S3C24XX_GPJDAT (0xD4 / 4) // Port J Data +#define S3C24XX_GPJUP (0xD8 / 4) // Pull-up Control J + +#define S3C24XX_GPADAT_MASK 0x01FFFFFF +#define S3C24XX_GPBDAT_MASK 0x000007FF +#define S3C24XX_GPCDAT_MASK 0x0000FFFF +#define S3C24XX_GPDDAT_MASK 0x0000FFFF +#define S3C24XX_GPEDAT_MASK 0x0000FFFF +#define S3C24XX_GPFDAT_MASK 0x000000FF +#define S3C24XX_GPGDAT_MASK 0x0000FFFF +#define S3C24XX_GPHDAT_MASK 0x000007FF +#define S3C24XX_GPJDAT_MASK 0x0000FFFF + +/* RTC */ + +#define S3C24XX_BASE_RTC 0x57000040 + +#define S3C24XX_RTCCON (0x00 / 4) // RTC Control +#define S3C24XX_TICNT (0x04 / 4) // Tick Time count +#define S3C24XX_RTCALM (0x10 / 4) // RTC Alarm Control +#define S3C24XX_ALMSEC (0x14 / 4) // Alarm Second +#define S3C24XX_ALMMIN (0x18 / 4) // Alarm Minute +#define S3C24XX_ALMHOUR (0x1C / 4) // Alarm Hour +#define S3C24XX_ALMDAY (0x20 / 4) // Alarm Day +#define S3C24XX_ALMMON (0x24 / 4) // Alarm Month +#define S3C24XX_ALMYEAR (0x28 / 4) // Alarm Year +#define S3C24XX_BCDSEC (0x30 / 4) // BCD Second +#define S3C24XX_BCDMIN (0x34 / 4) // BCD Minute +#define S3C24XX_BCDHOUR (0x38 / 4) // BCD Hour +#define S3C24XX_BCDDAY (0x3C / 4) // BCD Day +#define S3C24XX_BCDDOW (0x40 / 4) // BCD Day of Week +#define S3C24XX_BCDMON (0x44 / 4) // BCD Month +#define S3C24XX_BCDYEAR (0x48 / 4) // BCD Year + +/* A/D Converter */ + +#define S3C24XX_BASE_ADC 0x58000000 + +#define S3C24XX_ADCCON (0x00 / 4) // ADC Control +#define S3C24XX_ADCTSC (0x04 / 4) // ADC Touch Screen Control +#define S3C24XX_ADCDLY (0x08 / 4) // ADC Start or Interval Delay +#define S3C24XX_ADCDAT0 (0x0C / 4) // ADC Conversion Data +#define S3C24XX_ADCDAT1 (0x10 / 4) // ADC Conversion Data +#define S3C24XX_ADCUPDN (0x14 / 4) // Stylus up or down interrupt status + +/* SPI */ + +#define S3C24XX_BASE_SPI_0 0x59000000 +#define S3C24XX_BASE_SPI_1 0x59000020 + +#define S3C24XX_SPCON (0x00 / 4) // SPI Control +#define S3C24XX_SPSTA (0x04 / 4) // SPI Status +#define S3C24XX_SPPIN (0x08 / 4) // SPI Pin Control +#define S3C24XX_SPPRE (0x0C / 4) // SPI Baud Rate Prescaler +#define S3C24XX_SPTDAT (0x10 / 4) // SPI Tx Data +#define S3C24XX_SPRDAT (0x14 / 4) // SPI Rx Data + +/* SD Interface */ + +#define S3C24XX_BASE_SDI 0x5A000000 + +/* AC97 Interface */ + +#define S3C24XX_BASE_AC97 0x5B000000 + +/* ... */ + +#define S3C24XX_INT_ADC 31 +#define S3C24XX_INT_RTC 30 +#define S3C24XX_INT_SPI1 29 +#define S3C24XX_INT_UART0 28 +#define S3C24XX_INT_IIC 27 +#define S3C24XX_INT_USBH 26 +#define S3C24XX_INT_USBD 25 +#define S3C24XX_INT_NFCON 24 +#define S3C24XX_INT_UART1 23 +#define S3C24XX_INT_SPI0 22 +#define S3C24XX_INT_SDI 21 +#define S3C24XX_INT_DMA3 20 +#define S3C24XX_INT_DMA2 19 +#define S3C24XX_INT_DMA1 18 +#define S3C24XX_INT_DMA0 17 +#define S3C24XX_INT_LCD 16 +#define S3C24XX_INT_UART2 15 +#define S3C24XX_INT_TIMER4 14 +#define S3C24XX_INT_TIMER3 13 +#define S3C24XX_INT_TIMER2 12 +#define S3C24XX_INT_TIMER1 11 +#define S3C24XX_INT_TIMER0 10 +#define S3C24XX_INT_WDT_AC97 9 +#define S3C24XX_INT_TICK 8 +#define S3C24XX_INT_BATT_FLT 7 +#define S3C24XX_INT_CAM 6 +#define S3C24XX_INT_EINT8_23 5 +#define S3C24XX_INT_EINT4_7 4 +#define S3C24XX_INT_EINT3 3 +#define S3C24XX_INT_EINT2 2 +#define S3C24XX_INT_EINT1 1 +#define S3C24XX_INT_EINT0 0 + +#define S3C24XX_SUBINT_AC97 14 +#define S3C24XX_SUBINT_WDT 13 +#define S3C24XX_SUBINT_CAM_P 12 +#define S3C24XX_SUBINT_CAM_C 11 +#define S3C24XX_SUBINT_ADC 10 +#define S3C24XX_SUBINT_TC 9 +#define S3C24XX_SUBINT_ERR2 8 +#define S3C24XX_SUBINT_TXD2 7 +#define S3C24XX_SUBINT_RXD2 6 +#define S3C24XX_SUBINT_ERR1 5 +#define S3C24XX_SUBINT_TXD1 4 +#define S3C24XX_SUBINT_RXD1 3 +#define S3C24XX_SUBINT_ERR0 2 +#define S3C24XX_SUBINT_TXD0 1 +#define S3C24XX_SUBINT_RXD0 0 + +static const UINT32 MAP_SUBINT_TO_INT[15] = +{ + S3C24XX_INT_UART0, S3C24XX_INT_UART0, S3C24XX_INT_UART0, + S3C24XX_INT_UART1, S3C24XX_INT_UART1, S3C24XX_INT_UART1, + S3C24XX_INT_UART2, S3C24XX_INT_UART2, S3C24XX_INT_UART2, + S3C24XX_INT_ADC, S3C24XX_INT_ADC, + S3C24XX_INT_CAM, S3C24XX_INT_CAM, + S3C24XX_INT_WDT_AC97, S3C24XX_INT_WDT_AC97 +}; + +#define S3C24XX_BPPMODE_STN_01 0x00 +#define S3C24XX_BPPMODE_STN_02 0x01 +#define S3C24XX_BPPMODE_STN_04 0x02 +#define S3C24XX_BPPMODE_STN_08 0x03 +#define S3C24XX_BPPMODE_STN_12_P 0x04 +#define S3C24XX_BPPMODE_STN_12_U 0x05 +#define S3C24XX_BPPMODE_STN_16 0x06 +#define S3C24XX_BPPMODE_TFT_01 0x08 +#define S3C24XX_BPPMODE_TFT_02 0x09 +#define S3C24XX_BPPMODE_TFT_04 0x0A +#define S3C24XX_BPPMODE_TFT_08 0x0B +#define S3C24XX_BPPMODE_TFT_16 0x0C +#define S3C24XX_BPPMODE_TFT_24 0x0D + +#define S3C24XX_PNRMODE_STN_04_DS 0 +#define S3C24XX_PNRMODE_STN_04_SS 1 +#define S3C24XX_PNRMODE_STN_08_SS 2 +#define S3C24XX_PNRMODE_TFT 3 + +#define S3C24XX_GPIO_PORT_A S3C2440_GPIO_PORT_A +#define S3C24XX_GPIO_PORT_B S3C2440_GPIO_PORT_B +#define S3C24XX_GPIO_PORT_C S3C2440_GPIO_PORT_C +#define S3C24XX_GPIO_PORT_D S3C2440_GPIO_PORT_D +#define S3C24XX_GPIO_PORT_E S3C2440_GPIO_PORT_E +#define S3C24XX_GPIO_PORT_F S3C2440_GPIO_PORT_F +#define S3C24XX_GPIO_PORT_G S3C2440_GPIO_PORT_G +#define S3C24XX_GPIO_PORT_H S3C2440_GPIO_PORT_H +#define S3C24XX_GPIO_PORT_J S3C2440_GPIO_PORT_J + +#define S3C24XX_CORE_PIN_NCON S3C2440_CORE_PIN_NCON +#define S3C24XX_CORE_PIN_OM0 S3C2440_CORE_PIN_OM0 +#define S3C24XX_CORE_PIN_OM1 S3C2440_CORE_PIN_OM1 + +#define S3C24XX_UART_COUNT 3 +#define S3C24XX_DMA_COUNT 4 +#define S3C24XX_SPI_COUNT 2 + +class s3c2440_device : public device_t +{ +public: + s3c2440_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + ~s3c2440_device(); + + // static configuration + static void static_set_palette_tag(device_t &device, const char *tag); + template static devcb_base &set_core_pin_r_callback(device_t &device, _Object object) { return downcast(device).m_pin_r_cb.set_callback(object); } + template static devcb_base &set_core_pin_w_callback(device_t &device, _Object object) { return downcast(device).m_pin_w_cb.set_callback(object); } + template static devcb_base &set_gpio_port_r_callback(device_t &device, _Object object) { return downcast(device).m_port_r_cb.set_callback(object); } + template static devcb_base &set_gpio_port_w_callback(device_t &device, _Object object) { return downcast(device).m_port_w_cb.set_callback(object); } + template static devcb_base &set_i2c_scl_w_callback(device_t &device, _Object object) { return downcast(device).m_scl_w_cb.set_callback(object); } + template static devcb_base &set_i2c_sda_r_callback(device_t &device, _Object object) { return downcast(device).m_sda_r_cb.set_callback(object); } + template static devcb_base &set_i2c_sda_w_callback(device_t &device, _Object object) { return downcast(device).m_sda_w_cb.set_callback(object); } + template static devcb_base &set_adc_data_r_callback(device_t &device, _Object object) { return downcast(device).m_data_r_cb.set_callback(object); } + template static devcb_base &set_i2s_data_w_callback(device_t &device, _Object object) { return downcast(device).m_data_w_cb.set_callback(object); } + template static devcb_base &set_nand_command_w_callback(device_t &device, _Object object) { return downcast(device).m_command_w_cb.set_callback(object); } + template static devcb_base &set_nand_address_w_callback(device_t &device, _Object object) { return downcast(device).m_address_w_cb.set_callback(object); } + template static devcb_base &set_nand_data_r_callback(device_t &device, _Object object) { return downcast(device).m_nand_data_r_cb.set_callback(object); } + template static devcb_base &set_nand_data_w_callback(device_t &device, _Object object) { return downcast(device).m_nand_data_w_cb.set_callback(object); } + static void set_lcd_flags(device_t &device, int flags) { downcast(device).m_flags = flags; } + + DECLARE_WRITE_LINE_MEMBER( frnb_w ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); +private: + // internal state + required_device m_palette; +public: + UINT32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); + + void s3c24xx_reset(); + inline int iface_core_pin_r(int pin); + void s3c24xx_lcd_reset(); + rgb_t s3c24xx_get_color_tft_16(UINT16 data); + rgb_t s3c24xx_get_color_tft_24(UINT32 data); + rgb_t s3c24xx_get_color_stn_12(UINT16 data); + rgb_t s3c24xx_get_color_stn_08( UINT8 data); + rgb_t s3c24xx_get_color_stn_01(UINT8 data); + rgb_t s3c24xx_get_color_stn_02(UINT8 data); + rgb_t s3c24xx_get_color_stn_04(UINT8 data); + rgb_t s3c24xx_get_color_tpal(); + void s3c24xx_lcd_dma_reload(); + void s3c24xx_lcd_dma_init(); + UINT32 s3c24xx_lcd_dma_read(); + UINT32 s3c24xx_lcd_dma_read_bits(int count); + void s3c24xx_lcd_render_tpal(); + void s3c24xx_lcd_render_stn_01(); + void s3c24xx_lcd_render_stn_02(); + void s3c24xx_lcd_render_stn_04(); + void s3c24xx_lcd_render_stn_08(); + void s3c24xx_lcd_render_stn_12_p(); + void s3c24xx_lcd_render_stn_12_u(); // not tested + void s3c24xx_lcd_render_tft_01(); + void s3c24xx_lcd_render_tft_02(); + void s3c24xx_lcd_render_tft_04(); + void s3c24xx_lcd_render_tft_08(); + void s3c24xx_lcd_render_tft_16(); + TIMER_CALLBACK_MEMBER( s3c24xx_lcd_timer_exp ); + void s3c24xx_video_start(); + void bitmap_blend( bitmap_rgb32 &bitmap_dst, bitmap_rgb32 &bitmap_src_1, bitmap_rgb32 &bitmap_src_2); + UINT32 s3c24xx_video_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); + READ32_MEMBER( s3c24xx_lcd_r ); + int s3c24xx_lcd_configure_tft(); + int s3c24xx_lcd_configure_stn(); + int s3c24xx_lcd_configure(); + void s3c24xx_lcd_start(); + void s3c24xx_lcd_stop(); + void s3c24xx_lcd_recalc(); + WRITE32_MEMBER( s3c24xx_lcd_w ); + READ32_MEMBER( s3c24xx_lcd_palette_r ); + WRITE32_MEMBER( s3c24xx_lcd_palette_w ); + void s3c24xx_clkpow_reset(); + UINT32 s3c24xx_get_fclk(); + UINT32 s3c24xx_get_hclk(); + UINT32 s3c24xx_get_pclk(); + READ32_MEMBER( s3c24xx_clkpow_r ); + WRITE32_MEMBER( s3c24xx_clkpow_w ); + void s3c24xx_irq_reset(); + void s3c24xx_check_pending_irq(); + void s3c24xx_request_irq(UINT32 int_type); + void s3c24xx_check_pending_subirq(); + void s3c24xx_request_subirq( UINT32 int_type); + void s3c24xx_check_pending_eint(); + void s3c24xx_request_eint(UINT32 number); + READ32_MEMBER( s3c24xx_irq_r ); + WRITE32_MEMBER( s3c24xx_irq_w ); + void s3c24xx_pwm_reset(); + UINT16 s3c24xx_pwm_calc_observation(int ch); + READ32_MEMBER( s3c24xx_pwm_r ); + void s3c24xx_pwm_start(int timer); + void s3c24xx_pwm_stop(int timer); + void s3c24xx_pwm_recalc(int timer); + WRITE32_MEMBER( s3c24xx_pwm_w ); + TIMER_CALLBACK_MEMBER( s3c24xx_pwm_timer_exp ); + void s3c24xx_dma_reset(); + void s3c24xx_dma_reload(int ch); + void s3c24xx_dma_trigger(int ch); + void s3c24xx_dma_request_iis(); + void s3c24xx_dma_request_pwm(); + void s3c24xx_dma_start(int ch); + void s3c24xx_dma_stop(int ch); + void s3c24xx_dma_recalc(int ch); + UINT32 s3c24xx_dma_r(UINT32 ch, UINT32 offset); + void s3c24xx_dma_w(UINT32 ch, UINT32 offset, UINT32 data, UINT32 mem_mask); + READ32_MEMBER( s3c24xx_dma_0_r ); + READ32_MEMBER( s3c24xx_dma_1_r ); + READ32_MEMBER( s3c24xx_dma_2_r ); + READ32_MEMBER( s3c24xx_dma_3_r ); + WRITE32_MEMBER( s3c24xx_dma_0_w ); + WRITE32_MEMBER( s3c24xx_dma_1_w ); + WRITE32_MEMBER( s3c24xx_dma_2_w ); + WRITE32_MEMBER( s3c24xx_dma_3_w ); + TIMER_CALLBACK_MEMBER( s3c24xx_dma_timer_exp ); + void s3c24xx_gpio_reset(); + inline UINT32 iface_gpio_port_r(int port, UINT32 mask); + inline void iface_gpio_port_w(int port, UINT32 mask, UINT32 data); + UINT16 s3c24xx_gpio_get_mask( UINT32 con, int val); + READ32_MEMBER( s3c24xx_gpio_r ); + WRITE32_MEMBER( s3c24xx_gpio_w ); + void s3c24xx_memcon_reset(); + READ32_MEMBER( s3c24xx_memcon_r ); + WRITE32_MEMBER( s3c24xx_memcon_w ); + void s3c24xx_usb_host_reset(); + READ32_MEMBER( s3c24xx_usb_host_r ); + WRITE32_MEMBER( s3c24xx_usb_host_w ); + void s3c24xx_uart_reset(); + UINT32 s3c24xx_uart_r(UINT32 ch, UINT32 offset); + void s3c24xx_uart_w(UINT32 ch, UINT32 offset, UINT32 data, UINT32 mem_mask); + READ32_MEMBER( s3c24xx_uart_0_r ); + READ32_MEMBER( s3c24xx_uart_1_r ); + READ32_MEMBER( s3c24xx_uart_2_r ); + WRITE32_MEMBER( s3c24xx_uart_0_w ); + WRITE32_MEMBER( s3c24xx_uart_1_w ); + WRITE32_MEMBER( s3c24xx_uart_2_w ); + void s3c24xx_uart_fifo_w(int uart, UINT8 data); + void s3c24xx_usb_device_reset(); + READ32_MEMBER( s3c24xx_usb_device_r ); + WRITE32_MEMBER( s3c24xx_usb_device_w ); + void s3c24xx_wdt_reset(); + UINT16 s3c24xx_wdt_calc_current_count(); + READ32_MEMBER( s3c24xx_wdt_r ); + void s3c24xx_wdt_start(); + void s3c24xx_wdt_stop(); + void s3c24xx_wdt_recalc(); + WRITE32_MEMBER( s3c24xx_wdt_w ); + TIMER_CALLBACK_MEMBER( s3c24xx_wdt_timer_exp ); + void s3c24xx_iic_reset(); + inline void iface_i2c_scl_w( int state); + inline void iface_i2c_sda_w(int state); + inline int iface_i2c_sda_r(); + void i2c_send_start(); + void i2c_send_stop(); + UINT8 i2c_receive_byte(int ack); + int i2c_send_byte(UINT8 data); + void iic_start(); + void iic_stop(); + void iic_resume(); + READ32_MEMBER( s3c24xx_iic_r ); + WRITE32_MEMBER( s3c24xx_iic_w ); + TIMER_CALLBACK_MEMBER( s3c24xx_iic_timer_exp ); + void s3c24xx_iis_reset(); + inline void iface_i2s_data_w(int ch, UINT16 data); + void s3c24xx_iis_start(); + void s3c24xx_iis_stop(); + void s3c24xx_iis_recalc(); + READ32_MEMBER( s3c24xx_iis_r ); + WRITE32_MEMBER( s3c24xx_iis_w ); + TIMER_CALLBACK_MEMBER( s3c24xx_iis_timer_exp ); + void s3c24xx_rtc_reset(); + READ32_MEMBER( s3c24xx_rtc_r ); + void s3c24xx_rtc_recalc(); + WRITE32_MEMBER( s3c24xx_rtc_w ); + TIMER_CALLBACK_MEMBER( s3c24xx_rtc_timer_tick_count_exp ); + void s3c24xx_rtc_update(); + void s3c24xx_rtc_check_alarm(); + TIMER_CALLBACK_MEMBER( s3c24xx_rtc_timer_update_exp ); + void s3c24xx_adc_reset(); + UINT32 iface_adc_data_r(int ch); + READ32_MEMBER( s3c24xx_adc_r ); + void s3c24xx_adc_start(); + WRITE32_MEMBER( s3c24xx_adc_w ); + void s3c24xx_touch_screen(int state); + void s3c24xx_spi_reset(); + UINT32 s3c24xx_spi_r(UINT32 ch, UINT32 offset); + void s3c24xx_spi_w(UINT32 ch, UINT32 offset, UINT32 data, UINT32 mem_mask); + READ32_MEMBER( s3c24xx_spi_0_r ); + READ32_MEMBER( s3c24xx_spi_1_r ); + WRITE32_MEMBER( s3c24xx_spi_0_w ); + WRITE32_MEMBER( s3c24xx_spi_1_w ); + void s3c24xx_sdi_reset(); + READ32_MEMBER( s3c24xx_sdi_r ); + WRITE32_MEMBER( s3c24xx_sdi_w ); + void s3c24xx_nand_reset(); + inline void iface_nand_command_w(UINT8 data); + inline void iface_nand_address_w(UINT8 data); + inline UINT8 iface_nand_data_r(); + inline void iface_nand_data_w(UINT8 data); + void nand_update_mecc( UINT8 *ecc, int pos, UINT8 data); + void nand_update_secc( UINT8 *ecc, int pos, UINT8 data); + void s3c24xx_nand_update_ecc(UINT8 data); + void s3c24xx_nand_command_w(UINT8 data); + void s3c24xx_nand_address_w(UINT8 data); + UINT8 s3c24xx_nand_data_r(); + void s3c24xx_nand_data_w(UINT8 data); + READ32_MEMBER( s3c24xx_nand_r ); + void s3c24xx_nand_init_ecc(); + WRITE32_MEMBER( s3c24xx_nand_w ); + ATTR_UNUSED WRITE_LINE_MEMBER( s3c24xx_pin_frnb_w ); + void s3c24xx_cam_reset(); + READ32_MEMBER( s3c24xx_cam_r ); + WRITE32_MEMBER( s3c24xx_cam_w ); + void s3c24xx_ac97_reset(); + READ32_MEMBER( s3c24xx_ac97_r ); + WRITE32_MEMBER( s3c24xx_ac97_w ); + void s3c24xx_nand_auto_boot(); + void s3c24xx_device_reset(); + void s3c24xx_device_start(); + + + void s3c2440_uart_fifo_w( int uart, UINT8 data); + void s3c2440_touch_screen( int state); + void s3c2440_request_irq( UINT32 int_type); + void s3c2440_request_eint( UINT32 number); + + + /******************************************************************************* + TYPE DEFINITIONS + *******************************************************************************/ + + struct s3c24xx_memcon_regs_t + { + UINT32 data[0x34/4]; + }; + + struct s3c24xx_usbhost_regs_t + { + UINT32 data[0x5C/4]; + }; + + struct s3c24xx_irq_regs_t + { + UINT32 srcpnd; + UINT32 intmod; + UINT32 intmsk; + UINT32 priority; + UINT32 intpnd; + UINT32 intoffset; + UINT32 subsrcpnd; + UINT32 intsubmsk; + }; + + struct s3c24xx_dma_regs_t + { + UINT32 disrc; + UINT32 disrcc; + UINT32 didst; + UINT32 didstc; + UINT32 dcon; + UINT32 dstat; + UINT32 dcsrc; + UINT32 dcdst; + UINT32 dmasktrig; + }; + + struct s3c24xx_clkpow_regs_t + { + UINT32 locktime; + UINT32 mpllcon; + UINT32 upllcon; + UINT32 clkcon; + UINT32 clkslow; + UINT32 clkdivn; + UINT32 camdivn; + }; + + struct s3c24xx_lcd_regs_t + { + UINT32 lcdcon1; + UINT32 lcdcon2; + UINT32 lcdcon3; + UINT32 lcdcon4; + UINT32 lcdcon5; + UINT32 lcdsaddr1; + UINT32 lcdsaddr2; + UINT32 lcdsaddr3; + UINT32 redlut; + UINT32 greenlut; + UINT32 bluelut; + UINT32 reserved[8]; + UINT32 dithmode; + UINT32 tpal; + UINT32 lcdintpnd; + UINT32 lcdsrcpnd; + UINT32 lcdintmsk; + UINT32 tconsel; + }; + + struct s3c24xx_lcdpal_regs_t + { + UINT32 data[0x400/4]; + }; + + struct s3c24xx_nand_regs_t + { + UINT32 nfconf; + UINT32 nfcont; + UINT32 nfcmd; + UINT32 nfaddr; + UINT32 nfdata; + UINT32 nfmeccd0; + UINT32 nfmeccd1; + UINT32 nfseccd; + UINT32 nfstat; + UINT32 nfestat0; + UINT32 nfestat1; + UINT32 nfmecc0; + UINT32 nfmecc1; + UINT32 nfsecc; + UINT32 nfsblk; + UINT32 nfeblk; + }; + + struct s3c24xx_cam_regs_t + { + UINT32 data[0xA4/4]; + }; + + struct s3c24xx_uart_regs_t + { + UINT32 ulcon; + UINT32 ucon; + UINT32 ufcon; + UINT32 umcon; + UINT32 utrstat; + UINT32 uerstat; + UINT32 ufstat; + UINT32 umstat; + UINT32 utxh; + UINT32 urxh; + UINT32 ubrdiv; + }; + + struct s3c24xx_pwm_regs_t + { + UINT32 tcfg0; + UINT32 tcfg1; + UINT32 tcon; + UINT32 tcntb0; + UINT32 tcmpb0; + UINT32 tcnto0; + UINT32 tcntb1; + UINT32 tcmpb1; + UINT32 tcnto1; + UINT32 tcntb2; + UINT32 tcmpb2; + UINT32 tcnto2; + UINT32 tcntb3; + UINT32 tcmpb3; + UINT32 tcnto3; + UINT32 tcntb4; + UINT32 tcnto4; + }; + + struct s3c24xx_usbdev_regs_t + { + UINT32 data[0x130/4]; + }; + + struct s3c24xx_wdt_regs_t + { + UINT32 wtcon; + UINT32 wtdat; + UINT32 wtcnt; + }; + + struct s3c24xx_iic_regs_t + { + UINT32 iiccon; + UINT32 iicstat; + UINT32 iicadd; + UINT32 iicds; + UINT32 iiclc; + }; + + struct s3c24xx_iis_regs_t + { + UINT32 iiscon; + UINT32 iismod; + UINT32 iispsr; + UINT32 iisfcon; + UINT32 iisfifo; + }; + + struct s3c24xx_gpio_regs_t + { + UINT32 gpacon; + UINT32 gpadat; + UINT32 pad_08; + UINT32 pad_0c; + UINT32 gpbcon; + UINT32 gpbdat; + UINT32 gpbup; + UINT32 pad_1c; + UINT32 gpccon; + UINT32 gpcdat; + UINT32 gpcup; + UINT32 pad_2c; + UINT32 gpdcon; + UINT32 gpddat; + UINT32 gpdup; + UINT32 pad_3c; + UINT32 gpecon; + UINT32 gpedat; + UINT32 gpeup; + UINT32 pad_4c; + UINT32 gpfcon; + UINT32 gpfdat; + UINT32 gpfup; + UINT32 pad_5c; + UINT32 gpgcon; + UINT32 gpgdat; + UINT32 gpgup; + UINT32 pad_6c; + UINT32 gphcon; + UINT32 gphdat; + UINT32 gphup; + UINT32 pad_7c; + UINT32 misccr; + UINT32 dclkcon; + UINT32 extint0; + UINT32 extint1; + UINT32 extint2; + UINT32 eintflt0; + UINT32 eintflt1; + UINT32 eintflt2; + UINT32 eintflt3; + UINT32 eintmask; + UINT32 eintpend; + UINT32 gstatus0; + UINT32 gstatus1; + UINT32 gstatus2; + UINT32 gstatus3; + UINT32 gstatus4; + UINT32 pad_c0; + UINT32 pad_c4; + UINT32 pad_c8; + UINT32 mslcon; + UINT32 gpjcon; + UINT32 gpjdat; + UINT32 gpjup; + }; + + struct s3c24xx_rtc_regs_t + { + UINT32 rtccon; + UINT32 ticnt; + UINT32 reserved[2]; + UINT32 rtcalm; + UINT32 almsec; + UINT32 almmin; + UINT32 almhour; + UINT32 almday; + UINT32 almmon; + UINT32 almyear; + UINT32 rtcrst; + UINT32 bcdsec; + UINT32 bcdmin; + UINT32 bcdhour; + UINT32 bcdday; + UINT32 bcddow; + UINT32 bcdmon; + UINT32 bcdyear; + }; + + struct s3c24xx_adc_regs_t + { + UINT32 adccon; + UINT32 adctsc; + UINT32 adcdly; + UINT32 adcdat0; + UINT32 adcdat1; + UINT32 adcupdn; + }; + + struct s3c24xx_spi_regs_t + { + UINT32 spcon; + UINT32 spsta; + UINT32 sppin; + UINT32 sppre; + UINT32 sptdat; + UINT32 sprdat; + }; + + struct s3c24xx_sdi_regs_t + { + UINT32 data[0x44/4]; + }; + + struct s3c24xx_ac97_regs_t + { + UINT32 data[0x20/4]; + }; + + struct s3c24xx_memcon_t + { + s3c24xx_memcon_regs_t regs; + }; + + struct s3c24xx_usbhost_t + { + s3c24xx_usbhost_regs_t regs; + }; + + struct s3c24xx_irq_t + { + s3c24xx_irq_regs_t regs; + int line_irq, line_fiq; + }; + + struct s3c24xx_dma_t + { + s3c24xx_dma_regs_t regs; + emu_timer *timer; + }; + + struct s3c24xx_clkpow_t + { + s3c24xx_clkpow_regs_t regs; + }; + + struct s3c24xx_lcd_t + { + s3c24xx_lcd_regs_t regs; + emu_timer *timer; + bitmap_rgb32 *bitmap[2]; + UINT32 vramaddr_cur; + UINT32 vramaddr_max; + UINT32 offsize; + UINT32 pagewidth_cur; + UINT32 pagewidth_max; + UINT32 bppmode; + UINT32 bswp, hwswp; + int vpos, hpos; + double framerate; + UINT32 tpal; + UINT32 hpos_min, hpos_max, vpos_min, vpos_max; + UINT32 dma_data, dma_bits; + }; + + struct s3c24xx_lcdpal_t + { + s3c24xx_lcdpal_regs_t regs; + }; + + struct s3c24xx_nand_t + { + s3c24xx_nand_regs_t regs; + UINT8 mecc[4]; + UINT8 secc[2]; + int ecc_pos, data_count; + }; + + struct s3c24xx_cam_t + { + s3c24xx_cam_regs_t regs; + }; + + struct s3c24xx_uart_t + { + s3c24xx_uart_regs_t regs; + }; + + struct s3c24xx_pwm_t + { + s3c24xx_pwm_regs_t regs; + emu_timer *timer[5]; + UINT32 cnt[5]; + UINT32 cmp[5]; + UINT32 freq[5]; + }; + + struct s3c24xx_usbdev_t + { + s3c24xx_usbdev_regs_t regs; + }; + + struct s3c24xx_wdt_t + { + s3c24xx_wdt_regs_t regs; + emu_timer *timer; + }; + + struct s3c24xx_iic_t + { + s3c24xx_iic_regs_t regs; + emu_timer *timer; + int count; + }; + + struct s3c24xx_iis_t + { + s3c24xx_iis_regs_t regs; + emu_timer *timer; + UINT16 fifo[16/2]; + int fifo_index; + }; + + struct s3c24xx_gpio_t + { + s3c24xx_gpio_regs_t regs; + }; + + struct s3c24xx_rtc_t + { + s3c24xx_rtc_regs_t regs; + emu_timer *timer_tick_count; + emu_timer *timer_update; + }; + + struct s3c24xx_adc_t + { + s3c24xx_adc_regs_t regs; + }; + + struct s3c24xx_spi_t + { + s3c24xx_spi_regs_t regs; + }; + + struct s3c24xx_sdi_t + { + s3c24xx_sdi_regs_t regs; + }; + + struct s3c24xx_ac97_t + { + s3c24xx_ac97_regs_t regs; + }; + + + UINT8 m_steppingstone[4*1024]; + s3c24xx_memcon_t m_memcon; + s3c24xx_usbhost_t m_usbhost; + s3c24xx_irq_t m_irq; + s3c24xx_dma_t m_dma[S3C24XX_DMA_COUNT]; + s3c24xx_clkpow_t m_clkpow; + s3c24xx_lcd_t m_lcd; + s3c24xx_lcdpal_t m_lcdpal; + s3c24xx_nand_t m_nand; + s3c24xx_cam_t m_cam; + s3c24xx_uart_t m_uart[S3C24XX_UART_COUNT]; + s3c24xx_pwm_t m_pwm; + s3c24xx_usbdev_t m_usbdev; + s3c24xx_wdt_t m_wdt; + s3c24xx_iic_t m_iic; + s3c24xx_iis_t m_iis; + s3c24xx_gpio_t m_gpio; + s3c24xx_rtc_t m_rtc; + s3c24xx_adc_t m_adc; + s3c24xx_spi_t m_spi[S3C24XX_SPI_COUNT]; + s3c24xx_sdi_t m_sdi; + s3c24xx_ac97_t m_ac97; + required_device m_cpu; + devcb_read32 m_pin_r_cb; + devcb_write32 m_pin_w_cb; + devcb_read32 m_port_r_cb; + devcb_write32 m_port_w_cb; + devcb_write_line m_scl_w_cb; + devcb_read_line m_sda_r_cb; + devcb_write_line m_sda_w_cb; + devcb_read32 m_data_r_cb; + devcb_write16 m_data_w_cb; + devcb_write8 m_command_w_cb; + devcb_write8 m_address_w_cb; + devcb_read8 m_nand_data_r_cb; + devcb_write8 m_nand_data_w_cb; + int m_flags; +}; + +extern const device_type S3C2440; + + +#endif diff --git a/src/devices/machine/s3c24xx.inc b/src/devices/machine/s3c24xx.inc new file mode 100644 index 00000000000..d90f105b7bb --- /dev/null +++ b/src/devices/machine/s3c24xx.inc @@ -0,0 +1,3519 @@ +/******************************************************************************* + + Samsung S3C2400 / S3C2410 / S3C2440 + +*******************************************************************************/ + +#include "emu.h" +#include "cpu/arm7/arm7.h" +#include "cpu/arm7/arm7core.h" +#include "coreutil.h" + +/******************************************************************************* + MACROS & CONSTANTS +*******************************************************************************/ + +//#define UART_PRINTF + +#define CLOCK_MULTIPLIER 1 + +#define BIT(x,n) (((x)>>(n))&1) +#define BITS(x,m,n) (((x)>>(n))&(((UINT32)1<<((m)-(n)+1))-1)) +#define CLR_BITS(x,m,n) ((x) & ~((((UINT32)1 << ((m) - (n) + 1)) - 1) << n)) + +#if defined(DEVICE_S3C2400) + +#define S3C24XX_TPAL_GET_TPALEN(x) BIT(x,16) +#define S3C24XX_TPAL_GET_TPALVAL(x) BITS(x,15,0) + +#else + +#define S3C24XX_TPAL_GET_TPALEN(x) BIT(x,24) +#define S3C24XX_TPAL_GET_TPALVAL(x) BITS(x,23,0) + +#endif + +#define S3C24XX_DCON_GET_TC(x) BITS(x,19,0) +#define S3C24XX_DCON_GET_DSZ(x) BITS(x,21,20) +#define S3C24XX_DCON_GET_RELOAD(x) BIT(x,22) +#define S3C24XX_DCON_GET_SWHWSEL(x) BIT(x,23) + +#define S3C24XX_DSTAT_GET_CURR_TC(x) BITS(x,19,0) +#define S3C24XX_DSTAT_SET_CURR_TC(x,m) (CLR_BITS(x,19,0) | m) + +#define S3C24XX_DMASKTRIG_GET_ON_OFF(x) BIT(x,1) + +#if defined(DEVICE_S3C2400) + +#define S3C24XX_DCON_GET_HWSRCSEL(x) BITS(x,25,24) +#define S3C24XX_DCON_GET_SERVMODE(x) BIT(x,26) +#define S3C24XX_DCON_GET_TSZ(x) BIT(x,27) +#define S3C24XX_DCON_GET_INT(x) BIT(x,28) + +#define S3C24XX_DISRC_GET_SADDR(x) BITS(x,28,0) + +#define S3C24XX_DIDST_GET_DADDR(x) BITS(x,28,0) + +#define S3C24XX_DCSRC_GET_CURR_SRC(x) BITS(x,28,0) +#define S3C24XX_DCSRC_SET_CURR_SRC(x,m) (CLR_BITS(x,28,0) | m) + +#define S3C24XX_DCDST_GET_CURR_DST(x) BITS(x,28,0) +#define S3C24XX_DCDST_SET_CURR_DST(x,m) (CLR_BITS(x,28,0) | m) + +#else + +#define S3C24XX_DCON_GET_HWSRCSEL(x) BITS(x,26,24) +#define S3C24XX_DCON_GET_SERVMODE(x) BIT(x,27) +#define S3C24XX_DCON_GET_TSZ(x) BIT(x,28) +#define S3C24XX_DCON_GET_INT(x) BIT(x,29) + +#define S3C24XX_DISRC_GET_SADDR(x) BITS(x,30,0) + +#define S3C24XX_DIDST_GET_DADDR(x) BITS(x,30,0) + +#define S3C24XX_DCSRC_GET_CURR_SRC(x) BITS(x,30,0) +#define S3C24XX_DCSRC_SET_CURR_SRC(x,m) (CLR_BITS(x,30,0) | m) + +#define S3C24XX_DCDST_GET_CURR_DST(x) BITS(x,30,0) +#define S3C24XX_DCDST_SET_CURR_DST(x,m) (CLR_BITS(x,30,0) | m) + +#endif + +/*************************************************************************** + IMPLEMENTATION +***************************************************************************/ + +/* ... */ + +void S3C24_CLASS_NAME::s3c24xx_reset() +{ + verboselog( machine(), 1, "reset\n"); + m_cpu->reset(); + this->reset(); +} + +int S3C24_CLASS_NAME::iface_core_pin_r(int pin) +{ + if (!m_pin_r_cb.isnull()) + { + return (m_pin_r_cb)(pin); + } + else + { + return 0; + } +} + +/* LCD Controller */ + +void S3C24_CLASS_NAME::s3c24xx_lcd_reset() +{ + s3c24xx_lcd_t *lcd = &m_lcd; + memset( &lcd->regs, 0, sizeof( lcd->regs)); + #if defined(DEVICE_S3C2410) + lcd->regs.lcdintmsk = 3; + lcd->regs.lpcsel = 4; + #elif defined(DEVICE_S3C2440) + lcd->regs.lcdintmsk = 3; + lcd->regs.tconsel = 0x0F84; + #endif + lcd->vramaddr_cur = lcd->vramaddr_max = 0; + lcd->offsize = 0; + lcd->pagewidth_cur = lcd->pagewidth_max = 0; + lcd->bppmode = 0; + lcd->bswp = lcd->hwswp = 0; + lcd->vpos = lcd->hpos = 0; + lcd->framerate = 0; + lcd->tpal = 0; + lcd->hpos_min = lcd->hpos_max = lcd->vpos_min = lcd->vpos_max = 0; + lcd->dma_data = lcd->dma_bits = 0; + lcd->timer->adjust( attotime::never); +} + +rgb_t S3C24_CLASS_NAME::s3c24xx_get_color_tft_16(UINT16 data) +{ + if ((m_lcd.regs.lcdcon5 & (1 << 11)) == 0) + { + UINT8 r, g, b, i; + r = (BITS( data, 15, 11) << 3); + g = (BITS( data, 10, 6) << 3); + b = (BITS( data, 5, 1) << 3); + i = BIT( data, 1) << 2; + return rgb_t( r | i, g | i, b | i); + } + else + { + UINT8 r, g, b; + r = BITS( data, 15, 11) << 3; + g = BITS( data, 10, 5) << 2; + b = BITS( data, 4, 0) << 3; + return rgb_t( r, g, b); + } +} + +#if defined(DEVICE_S3C2410) || defined(DEVICE_S3C2440) + +rgb_t S3C24_CLASS_NAME::s3c24xx_get_color_tft_24(UINT32 data) +{ + UINT8 r, g, b; + r = BITS( data, 23, 16); + g = BITS( data, 15, 8); + b = BITS( data, 7, 0); + return rgb_t( r, g, b); +} + +#endif + +rgb_t S3C24_CLASS_NAME::s3c24xx_get_color_stn_12(UINT16 data) +{ + UINT8 r, g, b; + r = BITS( data, 11, 8) << 4; + g = BITS( data, 7, 4) << 4; + b = BITS( data, 3, 0) << 4; + return rgb_t( r, g, b); +} + +rgb_t S3C24_CLASS_NAME::s3c24xx_get_color_stn_08( UINT8 data) +{ + UINT8 r, g, b; + r = ((m_lcd.regs.redlut >> (BITS( data, 7, 5) << 2)) & 0xF) << 4; + g = ((m_lcd.regs.greenlut >> (BITS( data, 4, 2) << 2)) & 0xF) << 4; + b = ((m_lcd.regs.bluelut >> (BITS( data, 1, 0) << 2)) & 0xF) << 4; + return rgb_t( r, g, b); +} + +rgb_t S3C24_CLASS_NAME::s3c24xx_get_color_stn_01(UINT8 data) +{ + if ((data & 1) == 0) + { + return rgb_t::black; + } + else + { + return rgb_t::white; + } +} + +rgb_t S3C24_CLASS_NAME::s3c24xx_get_color_stn_02(UINT8 data) +{ + UINT8 r, g, b; + r = g = b = ((m_lcd.regs.bluelut >> (BITS( data, 1, 0) << 2)) & 0xF) << 4; + return rgb_t( r, g, b); +} + +rgb_t S3C24_CLASS_NAME::s3c24xx_get_color_stn_04(UINT8 data) +{ + UINT8 r, g, b; + r = g = b = BITS( data, 3, 0) << 4; + return rgb_t( r, g, b); +} + +rgb_t S3C24_CLASS_NAME::s3c24xx_get_color_tpal() +{ +#if defined(DEVICE_S3C2400) + return s3c24xx_get_color_tft_16(S3C24XX_TPAL_GET_TPALVAL( m_lcd.tpal)); +#else + return s3c24xx_get_color_tft_24(S3C24XX_TPAL_GET_TPALVAL( m_lcd.tpal)); +#endif +} + +void S3C24_CLASS_NAME::s3c24xx_lcd_dma_reload() +{ + m_lcd.vramaddr_cur = m_lcd.regs.lcdsaddr1 << 1; + m_lcd.vramaddr_max = ((m_lcd.regs.lcdsaddr1 & 0xFFE00000) | m_lcd.regs.lcdsaddr2) << 1; + m_lcd.offsize = BITS( m_lcd.regs.lcdsaddr3, 21, 11); + m_lcd.pagewidth_cur = 0; + m_lcd.pagewidth_max = BITS( m_lcd.regs.lcdsaddr3, 10, 0); + if (m_lcd.pagewidth_max == 0) + { + if (m_lcd.bppmode == S3C24XX_BPPMODE_STN_12_P) + { + m_lcd.pagewidth_max = (m_lcd.hpos_max - m_lcd.hpos_min + 1) / 16 * 12; + } + } + verboselog( machine(), 3, "LCD - vramaddr %08X %08X offsize %08X pagewidth %08X\n", m_lcd.vramaddr_cur, m_lcd.vramaddr_max, m_lcd.offsize, m_lcd.pagewidth_max); + m_lcd.dma_data = 0; + m_lcd.dma_bits = 0; +} + +void S3C24_CLASS_NAME::s3c24xx_lcd_dma_init() +{ + m_lcd.bppmode = BITS( m_lcd.regs.lcdcon1, 4, 1); + s3c24xx_lcd_dma_reload(); + m_lcd.bswp = BIT( m_lcd.regs.lcdcon5, 1); + m_lcd.hwswp = BIT( m_lcd.regs.lcdcon5, 0); + m_lcd.tpal = m_lcd.regs.tpal; + verboselog( machine(), 3, "LCD - bppmode %d hwswp %d bswp %d\n", m_lcd.bppmode, m_lcd.hwswp, m_lcd.bswp); + m_lcd.dma_data = 0; + m_lcd.dma_bits = 0; +} + +#if 0 +UINT32 S3C24_CLASS_NAME::s3c24xx_lcd_dma_read() +{ + address_space& space = m_cpu->memory().space( AS_PROGRAM); + UINT8 *vram, data[4]; + vram = (UINT8 *)space.get_read_ptr( m_lcd.vramaddr_cur); + for (int i = 0; i < 2; i++) + { + data[i*2+0] = *vram++; + data[i*2+1] = *vram++; + m_lcd.vramaddr_cur += 2; + m_lcd.pagewidth_cur++; + if (m_lcd.pagewidth_cur >= m_lcd.pagewidth_max) + { + m_lcd.vramaddr_cur += m_lcd.offsize << 1; + m_lcd.pagewidth_cur = 0; + vram = (UINT8 *)space.get_read_ptr( m_lcd.vramaddr_cur); + } + } + if (m_lcd.hwswp == 0) + { + if (m_lcd.bswp == 0) + { + return (data[3] << 24) | (data[2] << 16) | (data[1] << 8) | (data[0] << 0); + } + else + { + return (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | (data[3] << 0); + } + } + else + { + if (m_lcd.bswp == 0) + { + return (data[1] << 24) | (data[0] << 16) | (data[3] << 8) | (data[2] << 0); + } + else + { + return (data[2] << 24) | (data[3] << 16) | (data[0] << 8) | (data[1] << 0); + } + } +} +#endif + +UINT32 S3C24_CLASS_NAME::s3c24xx_lcd_dma_read() +{ + address_space& space = m_cpu->memory().space( AS_PROGRAM); + UINT8 *vram, data[4]; + vram = (UINT8 *)space.get_read_ptr( m_lcd.vramaddr_cur); + for (int i = 0; i < 2; i++) + { + if (m_lcd.hwswp == 0) + { + if (m_lcd.bswp == 0) + { + if ((m_lcd.vramaddr_cur & 2) == 0) + { + data[i*2+0] = *(vram + 3); + data[i*2+1] = *(vram + 2); + } + else + { + data[i*2+0] = *(vram - 1); + data[i*2+1] = *(vram - 2); + } + } + else + { + data[i*2+0] = *(vram + 0); + data[i*2+1] = *(vram + 1); + } + } + else + { + if (m_lcd.bswp == 0) + { + data[i*2+0] = *(vram + 1); + data[i*2+1] = *(vram + 0); + } + else + { + if ((m_lcd.vramaddr_cur & 2) == 0) + { + data[i*2+0] = *(vram + 2); + data[i*2+1] = *(vram + 3); + } + else + { + data[i*2+0] = *(vram - 2); + data[i*2+1] = *(vram - 1); + } + } + } + m_lcd.vramaddr_cur += 2; + m_lcd.pagewidth_cur++; + if (m_lcd.pagewidth_cur >= m_lcd.pagewidth_max) + { + m_lcd.vramaddr_cur += m_lcd.offsize << 1; + m_lcd.pagewidth_cur = 0; + vram = (UINT8 *)space.get_read_ptr( m_lcd.vramaddr_cur); + } + else + { + vram += 2; + } + } + if (m_flags & S3C24XX_INTERFACE_LCD_REVERSE) + { + return (data[3] << 24) | (data[2] << 16) | (data[1] << 8) | (data[0] << 0); + } + else + { + return (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | (data[3] << 0); + } +} + +UINT32 S3C24_CLASS_NAME::s3c24xx_lcd_dma_read_bits(int count) +{ + UINT32 data; + if (count <= m_lcd.dma_bits) + { + m_lcd.dma_bits -= count; + data = BITS( m_lcd.dma_data, 31, 32 - count); + m_lcd.dma_data = m_lcd.dma_data << count; + } + else + { + if (m_lcd.dma_bits == 0) + { + if (count == 32) + { + data = s3c24xx_lcd_dma_read(); + } + else + { + UINT32 temp = s3c24xx_lcd_dma_read(); + data = BITS( temp, 31, 32 - count); + m_lcd.dma_data = temp << count; + m_lcd.dma_bits = 32 - count; + } + } + else + { + UINT32 temp = s3c24xx_lcd_dma_read(); + data = (m_lcd.dma_data >> (32 - count)) | BITS( temp, 31, 32 - (count - m_lcd.dma_bits)); + m_lcd.dma_data = temp << (count - m_lcd.dma_bits); + m_lcd.dma_bits = 32 - (count - m_lcd.dma_bits); + } + } + return data; +} + +void S3C24_CLASS_NAME::s3c24xx_lcd_render_tpal() +{ + bitmap_rgb32 &bitmap = *m_lcd.bitmap[0]; + UINT32 color = s3c24xx_get_color_tpal(); + for (int y = m_lcd.vpos_min; y <= m_lcd.vpos_max; y++) + { + UINT32 *scanline = &bitmap.pix32(y, m_lcd.hpos_min); + for (int x = m_lcd.hpos_min; x <= m_lcd.hpos_max; x++) + { + *scanline++ = color; + } + } +} + +void S3C24_CLASS_NAME::s3c24xx_lcd_render_stn_01() +{ + bitmap_rgb32 &bitmap = *m_lcd.bitmap[0]; + UINT32 *scanline = &bitmap.pix32(m_lcd.vpos, m_lcd.hpos); + for (int i = 0; i < 4; i++) + { + UINT32 data = s3c24xx_lcd_dma_read(); + for (int j = 0; j < 32; j++) + { + if (m_flags & S3C24XX_INTERFACE_LCD_REVERSE) + { + *scanline++ = s3c24xx_get_color_stn_01( data & 0x01); + data = data >> 1; + } + else + { + *scanline++ = s3c24xx_get_color_stn_01((data >> 31) & 0x01); + data = data << 1; + } + m_lcd.hpos++; + if (m_lcd.hpos >= m_lcd.hpos_min + (m_lcd.pagewidth_max << 4)) + { + m_lcd.vpos++; + if (m_lcd.vpos > m_lcd.vpos_max) m_lcd.vpos = m_lcd.vpos_min; + m_lcd.hpos = m_lcd.hpos_min; + scanline = &bitmap.pix32(m_lcd.vpos, m_lcd.hpos); + } + } + } +} + +void S3C24_CLASS_NAME::s3c24xx_lcd_render_stn_02() +{ + bitmap_rgb32 &bitmap = *m_lcd.bitmap[0]; + UINT32 *scanline = &bitmap.pix32(m_lcd.vpos, m_lcd.hpos); + for (int i = 0; i < 4; i++) + { + UINT32 data = s3c24xx_lcd_dma_read(); + for (int j = 0; j < 16; j++) + { + *scanline++ = s3c24xx_get_color_stn_02((data >> 30) & 0x03); + data = data << 2; + m_lcd.hpos++; + if (m_lcd.hpos >= m_lcd.hpos_min + (m_lcd.pagewidth_max << 3)) + { + m_lcd.vpos++; + if (m_lcd.vpos > m_lcd.vpos_max) m_lcd.vpos = m_lcd.vpos_min; + m_lcd.hpos = m_lcd.hpos_min; + scanline = &bitmap.pix32(m_lcd.vpos, m_lcd.hpos); + } + } + } +} + +void S3C24_CLASS_NAME::s3c24xx_lcd_render_stn_04() +{ + bitmap_rgb32 &bitmap = *m_lcd.bitmap[0]; + UINT32 *scanline = &bitmap.pix32(m_lcd.vpos, m_lcd.hpos); + for (int i = 0; i < 4; i++) + { + UINT32 data = s3c24xx_lcd_dma_read(); + for (int j = 0; j < 8; j++) + { + *scanline++ = s3c24xx_get_color_stn_04((data >> 28) & 0x0F); + data = data << 4; + m_lcd.hpos++; + if (m_lcd.hpos >= m_lcd.hpos_min + (m_lcd.pagewidth_max << 2)) + { + m_lcd.vpos++; + if (m_lcd.vpos > m_lcd.vpos_max) m_lcd.vpos = m_lcd.vpos_min; + m_lcd.hpos = m_lcd.hpos_min; + scanline = &bitmap.pix32(m_lcd.vpos, m_lcd.hpos); + } + } + } +} + +void S3C24_CLASS_NAME::s3c24xx_lcd_render_stn_08() +{ + bitmap_rgb32 &bitmap = *m_lcd.bitmap[0]; + UINT32 *scanline = &bitmap.pix32(m_lcd.vpos, m_lcd.hpos); + for (int i = 0; i < 4; i++) + { + UINT32 data = s3c24xx_lcd_dma_read(); + for (int j = 0; j < 4; j++) + { + *scanline++ = s3c24xx_get_color_stn_08((data >> 24) & 0xFF); + data = data << 8; + m_lcd.hpos++; + if (m_lcd.hpos >= m_lcd.hpos_min + (m_lcd.pagewidth_max << 1)) + { + m_lcd.vpos++; + if (m_lcd.vpos > m_lcd.vpos_max) m_lcd.vpos = m_lcd.vpos_min; + m_lcd.hpos = m_lcd.hpos_min; + scanline = &bitmap.pix32(m_lcd.vpos, m_lcd.hpos); + } + } + } +} + +void S3C24_CLASS_NAME::s3c24xx_lcd_render_stn_12_p() +{ + bitmap_rgb32 &bitmap = *m_lcd.bitmap[0]; + UINT32 *scanline = &bitmap.pix32(m_lcd.vpos, m_lcd.hpos); + for (int i = 0; i < 16; i++) + { + *scanline++ = s3c24xx_get_color_stn_12(s3c24xx_lcd_dma_read_bits(12)); + m_lcd.hpos++; + if (m_lcd.hpos >= m_lcd.hpos_min + (m_lcd.pagewidth_max * 16 / 12)) + { + m_lcd.vpos++; + if (m_lcd.vpos > m_lcd.vpos_max) m_lcd.vpos = m_lcd.vpos_min; + m_lcd.hpos = m_lcd.hpos_min; + scanline = &bitmap.pix32(m_lcd.vpos, m_lcd.hpos); + } + } +} + +void S3C24_CLASS_NAME::s3c24xx_lcd_render_stn_12_u() // not tested +{ + bitmap_rgb32 &bitmap = *m_lcd.bitmap[0]; + UINT32 *scanline = &bitmap.pix32(m_lcd.vpos, m_lcd.hpos); + for (int i = 0; i < 4; i++) + { + UINT32 data = s3c24xx_lcd_dma_read(); + for (int j = 0; j < 2; j++) + { + *scanline++ = s3c24xx_get_color_stn_12((data >> 16) & 0x0FFF); + data = data << 16; + m_lcd.hpos++; + if (m_lcd.hpos >= m_lcd.hpos_min + (m_lcd.pagewidth_max << 0)) + { + m_lcd.vpos++; + if (m_lcd.vpos > m_lcd.vpos_max) m_lcd.vpos = m_lcd.vpos_min; + m_lcd.hpos = m_lcd.hpos_min; + scanline = &bitmap.pix32(m_lcd.vpos, m_lcd.hpos); + } + } + } +} + +void S3C24_CLASS_NAME::s3c24xx_lcd_render_tft_01() +{ + bitmap_rgb32 &bitmap = *m_lcd.bitmap[0]; + UINT32 *scanline = &bitmap.pix32(m_lcd.vpos, m_lcd.hpos); + for (int i = 0; i < 4; i++) + { + UINT32 data = s3c24xx_lcd_dma_read(); + for (int j = 0; j < 32; j++) + { + *scanline++ = m_palette->pen_color((data >> 31) & 0x01); + data = data << 1; + m_lcd.hpos++; + if (m_lcd.hpos >= m_lcd.hpos_min + (m_lcd.pagewidth_max << 4)) + { + m_lcd.vpos++; + if (m_lcd.vpos > m_lcd.vpos_max) m_lcd.vpos = m_lcd.vpos_min; + m_lcd.hpos = m_lcd.hpos_min; + scanline = &bitmap.pix32(m_lcd.vpos, m_lcd.hpos); + } + } + } +} + +void S3C24_CLASS_NAME::s3c24xx_lcd_render_tft_02() +{ + bitmap_rgb32 &bitmap = *m_lcd.bitmap[0]; + UINT32 *scanline = &bitmap.pix32(m_lcd.vpos, m_lcd.hpos); + for (int i = 0; i < 4; i++) + { + UINT32 data = s3c24xx_lcd_dma_read(); + for (int j = 0; j < 16; j++) + { + *scanline++ = m_palette->pen_color((data >> 30) & 0x03); + data = data << 2; + m_lcd.hpos++; + if (m_lcd.hpos >= m_lcd.hpos_min + (m_lcd.pagewidth_max << 3)) + { + m_lcd.vpos++; + if (m_lcd.vpos > m_lcd.vpos_max) m_lcd.vpos = m_lcd.vpos_min; + m_lcd.hpos = m_lcd.hpos_min; + scanline = &bitmap.pix32(m_lcd.vpos, m_lcd.hpos); + } + } + } +} + +void S3C24_CLASS_NAME::s3c24xx_lcd_render_tft_04() +{ + bitmap_rgb32 &bitmap = *m_lcd.bitmap[0]; + UINT32 *scanline = &bitmap.pix32(m_lcd.vpos, m_lcd.hpos); + for (int i = 0; i < 4; i++) + { + UINT32 data = s3c24xx_lcd_dma_read(); + for (int j = 0; j < 8; j++) + { + *scanline++ = m_palette->pen_color((data >> 28) & 0x0F); + data = data << 4; + m_lcd.hpos++; + if (m_lcd.hpos >= m_lcd.hpos_min + (m_lcd.pagewidth_max << 2)) + { + m_lcd.vpos++; + if (m_lcd.vpos > m_lcd.vpos_max) m_lcd.vpos = m_lcd.vpos_min; + m_lcd.hpos = m_lcd.hpos_min; + scanline = &bitmap.pix32(m_lcd.vpos, m_lcd.hpos); + } + } + } +} + +void S3C24_CLASS_NAME::s3c24xx_lcd_render_tft_08() +{ + bitmap_rgb32 &bitmap = *m_lcd.bitmap[0]; + UINT32 *scanline = &bitmap.pix32(m_lcd.vpos, m_lcd.hpos); + for (int i = 0; i < 4; i++) + { + UINT32 data = s3c24xx_lcd_dma_read(); + for (int j = 0; j < 4; j++) + { + *scanline++ = m_palette->pen_color((data >> 24) & 0xFF); + data = data << 8; + m_lcd.hpos++; + if (m_lcd.hpos >= m_lcd.hpos_min + (m_lcd.pagewidth_max << 1)) + { + m_lcd.vpos++; + if (m_lcd.vpos > m_lcd.vpos_max) m_lcd.vpos = m_lcd.vpos_min; + m_lcd.hpos = m_lcd.hpos_min; + scanline = &bitmap.pix32(m_lcd.vpos, m_lcd.hpos); + } + } + } +} + +void S3C24_CLASS_NAME::s3c24xx_lcd_render_tft_16() +{ + bitmap_rgb32 &bitmap = *m_lcd.bitmap[0]; + UINT32 *scanline = &bitmap.pix32(m_lcd.vpos, m_lcd.hpos); + for (int i = 0; i < 4; i++) + { + UINT32 data = s3c24xx_lcd_dma_read(); + for (int j = 0; j < 2; j++) + { + *scanline++ = s3c24xx_get_color_tft_16((data >> 16) & 0xFFFF); + data = data << 16; + m_lcd.hpos++; + if (m_lcd.hpos >= m_lcd.hpos_min + (m_lcd.pagewidth_max << 0)) + { + m_lcd.vpos++; + if (m_lcd.vpos > m_lcd.vpos_max) m_lcd.vpos = m_lcd.vpos_min; + m_lcd.hpos = m_lcd.hpos_min; + scanline = &bitmap.pix32(m_lcd.vpos, m_lcd.hpos); + } + } + } +} + +TIMER_CALLBACK_MEMBER( S3C24_CLASS_NAME::s3c24xx_lcd_timer_exp ) +{ + screen_device *screen = machine().first_screen(); + UINT32 tpalen; + verboselog( machine(), 2, "LCD timer callback\n"); + m_lcd.vpos = screen->vpos(); + m_lcd.hpos = screen->hpos(); + verboselog( machine(), 3, "LCD - vpos %d hpos %d\n", m_lcd.vpos, m_lcd.hpos); + tpalen = S3C24XX_TPAL_GET_TPALEN( m_lcd.tpal); + if (tpalen == 0) + { + if (m_lcd.vramaddr_cur >= m_lcd.vramaddr_max) + { + s3c24xx_lcd_dma_reload(); + } + verboselog( machine(), 3, "LCD - vramaddr %08X\n", m_lcd.vramaddr_cur); + while (m_lcd.vramaddr_cur < m_lcd.vramaddr_max) + { + switch (m_lcd.bppmode) + { + case S3C24XX_BPPMODE_STN_01 : s3c24xx_lcd_render_stn_01(); break; + case S3C24XX_BPPMODE_STN_02 : s3c24xx_lcd_render_stn_02(); break; + case S3C24XX_BPPMODE_STN_04 : s3c24xx_lcd_render_stn_04(); break; + case S3C24XX_BPPMODE_STN_08 : s3c24xx_lcd_render_stn_08(); break; + case S3C24XX_BPPMODE_STN_12_P : s3c24xx_lcd_render_stn_12_p(); break; + case S3C24XX_BPPMODE_STN_12_U : s3c24xx_lcd_render_stn_12_u(); break; + case S3C24XX_BPPMODE_TFT_01 : s3c24xx_lcd_render_tft_01(); break; + case S3C24XX_BPPMODE_TFT_02 : s3c24xx_lcd_render_tft_02(); break; + case S3C24XX_BPPMODE_TFT_04 : s3c24xx_lcd_render_tft_04(); break; + case S3C24XX_BPPMODE_TFT_08 : s3c24xx_lcd_render_tft_08(); break; + case S3C24XX_BPPMODE_TFT_16 : s3c24xx_lcd_render_tft_16(); break; + default : verboselog( machine(), 0, "s3c24xx_lcd_timer_exp: bppmode %d not supported\n", m_lcd.bppmode); break; + } + if ((m_lcd.vpos == m_lcd.vpos_min) && (m_lcd.hpos == m_lcd.hpos_min)) break; + } + } + else + { + s3c24xx_lcd_render_tpal(); + } + m_lcd.timer->adjust( screen->time_until_pos( m_lcd.vpos, m_lcd.hpos)); +} + +void S3C24_CLASS_NAME::s3c24xx_video_start() +{ + screen_device *screen = machine().first_screen(); + m_lcd.bitmap[0] = auto_bitmap_rgb32_alloc(machine(), screen->width(), screen->height()); + m_lcd.bitmap[1] = auto_bitmap_rgb32_alloc(machine(), screen->width(), screen->height()); +} + +void S3C24_CLASS_NAME::bitmap_blend( bitmap_rgb32 &bitmap_dst, bitmap_rgb32 &bitmap_src_1, bitmap_rgb32 &bitmap_src_2) +{ + for (int y = 0; y < bitmap_dst.height(); y++) + { + UINT32 *line0 = &bitmap_src_1.pix32(y); + UINT32 *line1 = &bitmap_src_2.pix32(y); + UINT32 *line2 = &bitmap_dst.pix32(y); + for (int x = 0; x < bitmap_dst.width(); x++) + { + UINT32 color0 = line0[x]; + UINT32 color1 = line1[x]; + UINT16 r0 = (color0 >> 16) & 0x000000ff; + UINT16 g0 = (color0 >> 8) & 0x000000ff; + UINT16 b0 = (color0 >> 0) & 0x000000ff; + UINT16 r1 = (color1 >> 16) & 0x000000ff; + UINT16 g1 = (color1 >> 8) & 0x000000ff; + UINT16 b1 = (color1 >> 0) & 0x000000ff; + UINT8 r = (UINT8)((r0 + r1) >> 1); + UINT8 g = (UINT8)((g0 + g1) >> 1); + UINT8 b = (UINT8)((b0 + b1) >> 1); + line2[x] = (r << 16) | (g << 8) | b; + } + } +} + +UINT32 S3C24_CLASS_NAME::s3c24xx_video_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + if (m_lcd.regs.lcdcon1 & (1 << 0)) + { + if (m_lcd.framerate >= 1195) + { + bitmap_blend( bitmap, *m_lcd.bitmap[0], *m_lcd.bitmap[1]); + copybitmap( *m_lcd.bitmap[1], *m_lcd.bitmap[0], 0, 0, 0, 0, cliprect); + } + else + { + copybitmap( bitmap, *m_lcd.bitmap[0], 0, 0, 0, 0, cliprect); + } + s3c24xx_lcd_dma_init(); + } + return 0; +} + + +READ32_MEMBER( S3C24_CLASS_NAME::s3c24xx_lcd_r ) +{ + UINT32 data = ((UINT32*)&m_lcd.regs)[offset]; + switch (offset) + { + case S3C24XX_LCDCON1 : + { + // make sure line counter is going + UINT32 vpos = machine().first_screen()->vpos(); + if (vpos < m_lcd.vpos_min) vpos = m_lcd.vpos_min; + if (vpos > m_lcd.vpos_max) vpos = m_lcd.vpos_max; + data = (data & ~0xFFFC0000) | ((m_lcd.vpos_max - vpos) << 18); + } + break; + case S3C24XX_LCDCON5 : + { + UINT32 vpos = machine().first_screen()->vpos(); + data = data & ~0x00018000; + if (vpos < m_lcd.vpos_min) data = data | 0x00000000; + if (vpos > m_lcd.vpos_max) data = data | 0x00018000; + // todo: 00 = VSYNC, 01 = BACK Porch, 10 = ACTIVE, 11 = FRONT Porch + } + break; + } + verboselog( machine(), 9, "(LCD) %08X -> %08X\n", S3C24XX_BASE_LCD + (offset << 2), data); + return data; +} + +int S3C24_CLASS_NAME::s3c24xx_lcd_configure_tft() +{ + screen_device *screen = machine().first_screen(); + UINT32 vspw, vbpd, lineval, vfpd, hspw, hbpd, hfpd, hozval, clkval, hclk; + double framerate, vclk; + UINT32 width, height; + rectangle visarea; + verboselog( machine(), 5, "s3c24xx_lcd_configure_tft\n"); + vspw = BITS( m_lcd.regs.lcdcon2, 5, 0); + vbpd = BITS( m_lcd.regs.lcdcon2, 31, 24); + lineval = BITS( m_lcd.regs.lcdcon2, 23, 14); + vfpd = BITS( m_lcd.regs.lcdcon2, 13, 6); + hspw = BITS( m_lcd.regs.lcdcon4, 7, 0); + hbpd = BITS( m_lcd.regs.lcdcon3, 25, 19); + hfpd = BITS( m_lcd.regs.lcdcon3, 7, 0); + hozval = BITS( m_lcd.regs.lcdcon3, 18, 8); + clkval = BITS( m_lcd.regs.lcdcon1, 17, 8); + hclk = s3c24xx_get_hclk(); + verboselog( machine(), 3, "LCD - vspw %d vbpd %d lineval %d vfpd %d hspw %d hbpd %d hfpd %d hozval %d clkval %d hclk %d\n", vspw, vbpd, lineval, vfpd, hspw, hbpd, hfpd, hozval, clkval, hclk); + vclk = (double)(hclk / ((clkval + 1) * 2)); + verboselog( machine(), 3, "LCD - vclk %f\n", vclk); + framerate = vclk / (((vspw + 1) + (vbpd + 1) + (lineval + 1) + (vfpd + 1)) * ((hspw + 1) + (hbpd + 1) + (hozval + 1) + (hfpd + 1))); + verboselog( machine(), 3, "LCD - framerate %f\n", framerate); + m_lcd.framerate = framerate; + width = (hspw + 1) + (hbpd + 1) + (hozval + 1) + (hfpd + 1); + height = (vspw + 1) + (vbpd + 1) + (lineval + 1) + (vfpd + 1); + visarea.min_x = (hspw + 1) + (hbpd + 1); + visarea.min_y = (vspw + 1) + (vbpd + 1); + visarea.max_x = visarea.min_x + (hozval + 1) - 1; + visarea.max_y = visarea.min_y + (lineval + 1) - 1; + verboselog( machine(), 3, "LCD - visarea min_x %d min_y %d max_x %d max_y %d\n", visarea.min_x, visarea.min_y, visarea.max_x, visarea.max_y); + verboselog( machine(), 3, "video_screen_configure %d %d %f\n", width, height, m_lcd.framerate); + m_lcd.hpos_min = (hspw + 1) + (hbpd + 1); + m_lcd.hpos_max = m_lcd.hpos_min + (hozval + 1) - 1; + m_lcd.vpos_min = (vspw + 1) + (vbpd + 1); + m_lcd.vpos_max = m_lcd.vpos_min + (lineval + 1) - 1; + screen->configure( width, height, visarea, HZ_TO_ATTOSECONDS( m_lcd.framerate)); + return TRUE; +} + +int S3C24_CLASS_NAME::s3c24xx_lcd_configure_stn() +{ + screen_device *screen = machine().first_screen(); + UINT32 pnrmode, bppmode, clkval, lineval, wdly, hozval, lineblank, wlh, hclk; + double vclk, framerate; + UINT32 width, height; + rectangle visarea; + verboselog( machine(), 5, "s3c24xx_lcd_configure_stn\n"); + pnrmode = BITS( m_lcd.regs.lcdcon1, 6, 5); + bppmode = BITS( m_lcd.regs.lcdcon1, 4, 1); + clkval = BITS( m_lcd.regs.lcdcon1, 17, 8); + lineval = BITS( m_lcd.regs.lcdcon2, 23, 14); + wdly = BITS( m_lcd.regs.lcdcon3, 20, 19); + hozval = BITS( m_lcd.regs.lcdcon3, 18, 8); + lineblank = BITS( m_lcd.regs.lcdcon3, 7, 0); + wlh = BITS( m_lcd.regs.lcdcon4, 1, 0); + hclk = s3c24xx_get_hclk(); + verboselog( machine(), 3, "LCD - pnrmode %d bppmode %d clkval %d lineval %d wdly %d hozval %d lineblank %d wlh %d hclk %d\n", pnrmode, bppmode, clkval, lineval, wdly, hozval, lineblank, wlh, hclk); + if (clkval == 0) + { + return FALSE; + } + vclk = (double)(hclk / ((clkval + 0) * 2)); + verboselog( machine(), 3, "LCD - vclk %f\n", vclk); + framerate = 1 / (((1 / vclk) * (hozval + 1) + (1 / hclk) * ((1 << (4 + wlh)) + (1 << (4 + wdly)) + (lineblank * 8))) * (lineval + 1)); + verboselog( machine(), 3, "LCD - framerate %f\n", framerate); + switch (pnrmode) + { + case S3C24XX_PNRMODE_STN_04_SS : width = ((hozval + 1) * 4); break; + case S3C24XX_PNRMODE_STN_04_DS : width = ((hozval + 1) * 4); break; + case S3C24XX_PNRMODE_STN_08_SS : width = ((hozval + 1) * 8 / 3); break; + default : width = 0; break; + } + height = lineval + 1; + m_lcd.framerate = framerate; + visarea.set(0, width - 1, 0, height - 1); + verboselog( machine(), 3, "LCD - visarea min_x %d min_y %d max_x %d max_y %d\n", visarea.min_x, visarea.min_y, visarea.max_x, visarea.max_y); + verboselog( machine(), 3, "video_screen_configure %d %d %f\n", width, height, m_lcd.framerate); + m_lcd.hpos_min = 0; + m_lcd.hpos_max = width - 1; + m_lcd.vpos_min = 0; + m_lcd.vpos_max = height - 1; + screen->configure( width, height, visarea, HZ_TO_ATTOSECONDS( m_lcd.framerate)); + return TRUE; +} + +int S3C24_CLASS_NAME::s3c24xx_lcd_configure() +{ + UINT32 bppmode; + verboselog( machine(), 5, "s3c24xx_lcd_configure\n"); + bppmode = BITS( m_lcd.regs.lcdcon1, 4, 1); + if ((bppmode & (1 << 3)) == 0) + { + return s3c24xx_lcd_configure_stn(); + } + else + { + return s3c24xx_lcd_configure_tft(); + } +} + +void S3C24_CLASS_NAME::s3c24xx_lcd_start() +{ + screen_device *screen = machine().first_screen(); + verboselog( machine(), 1, "LCD start\n"); + if (s3c24xx_lcd_configure()) + { + s3c24xx_lcd_dma_init(); + m_lcd.timer->adjust( screen->time_until_pos( m_lcd.vpos_min, m_lcd.hpos_min)); + } +} + +void S3C24_CLASS_NAME::s3c24xx_lcd_stop() +{ + verboselog( machine(), 1, "LCD stop\n"); + m_lcd.timer->adjust( attotime::never); +} + +void S3C24_CLASS_NAME::s3c24xx_lcd_recalc() +{ + if (m_lcd.regs.lcdcon1 & (1 << 0)) + { + s3c24xx_lcd_start(); + } + else + { + s3c24xx_lcd_stop(); + } +} + +WRITE32_MEMBER( S3C24_CLASS_NAME::s3c24xx_lcd_w ) +{ + UINT32 old_value = ((UINT32*)&m_lcd.regs)[offset]; + verboselog( machine(), 9, "(LCD) %08X <- %08X\n", S3C24XX_BASE_LCD + (offset << 2), data); + COMBINE_DATA(&((UINT32*)&m_lcd.regs)[offset]); + switch (offset) + { + case S3C24XX_LCDCON1 : + { + if ((old_value & (1 << 0)) != (data & (1 << 0))) + { + s3c24xx_lcd_recalc(); + } + } + break; + } +} + +/* LCD Palette */ + +READ32_MEMBER( S3C24_CLASS_NAME::s3c24xx_lcd_palette_r ) +{ + UINT32 data = m_lcdpal.regs.data[offset]; + verboselog( machine(), 9, "(LCD) %08X -> %08X\n", S3C24XX_BASE_LCDPAL + (offset << 2), data); + return data; +} + +WRITE32_MEMBER( S3C24_CLASS_NAME::s3c24xx_lcd_palette_w ) +{ + verboselog( machine(), 9, "(LCD) %08X <- %08X\n", S3C24XX_BASE_LCDPAL + (offset << 2), data); + COMBINE_DATA(&m_lcdpal.regs.data[offset]); + if (mem_mask != 0xffffffff) + { + verboselog( machine(), 0, "s3c24xx_lcd_palette_w: unknown mask %08x\n", mem_mask); + } + m_palette->set_pen_color( offset, s3c24xx_get_color_tft_16(data & 0xFFFF)); +} + +/* Clock & Power Management */ + +void S3C24_CLASS_NAME::s3c24xx_clkpow_reset() +{ + s3c24xx_clkpow_t *clkpow = &m_clkpow; + memset( &clkpow->regs, 0, sizeof( clkpow->regs)); + #if defined(DEVICE_S3C2400) + clkpow->regs.locktime = 0x00FFFFFF; + clkpow->regs.mpllcon = 0x0005C080; + clkpow->regs.upllcon = 0x00028080; + clkpow->regs.clkcon = 0x0000FFF8; + #elif defined(DEVICE_S3C2410) + clkpow->regs.locktime = 0x00FFFFFF; + clkpow->regs.mpllcon = 0x0005C080; + clkpow->regs.upllcon = 0x00028080; + clkpow->regs.clkcon = 0x0007FFF0; + #elif defined(DEVICE_S3C2440) + clkpow->regs.locktime = 0xFFFFFFFF; + clkpow->regs.mpllcon = 0x00096030; + clkpow->regs.upllcon = 0x0004D030; + clkpow->regs.clkcon = 0x00FFFFF0; + #endif + clkpow->regs.clkslow = 4; +} + +UINT32 S3C24_CLASS_NAME::s3c24xx_get_fclk() +{ + UINT32 mpllcon, clkslow, mdiv, pdiv, sdiv, fclk; + double temp1, temp2; + mpllcon = m_clkpow.regs.mpllcon; + mdiv = BITS( mpllcon, 19, 12); + pdiv = BITS( mpllcon, 9, 4); + sdiv = BITS( mpllcon, 1, 0); +#if defined(DEVICE_S3C2400) || defined(DEVICE_S3C2410) + temp1 = 1 * (mdiv + 8) * (double)clock(); +#else + temp1 = 2 * (mdiv + 8) * (double)clock(); +#endif + temp2 = (double)((pdiv + 2) * (1 << sdiv)); + fclk = (UINT32)(temp1 / temp2); + clkslow = m_clkpow.regs.clkslow; + if (BIT( clkslow, 4) == 1) + { + UINT32 slow_val = BITS( clkslow, 2, 0); + if (slow_val > 0) + { + fclk = fclk / (2 * slow_val); + } + } + return fclk; +} + +UINT32 S3C24_CLASS_NAME::s3c24xx_get_hclk() +{ +#if defined(DEVICE_S3C2400) || defined(DEVICE_S3C2410) + return s3c24xx_get_fclk() / (BIT( m_clkpow.regs.clkdivn, 1) + 1); +#else + switch (BITS( m_clkpow.regs.clkdivn, 2, 1)) + { + case 0 : return s3c24xx_get_fclk() / 1; + case 1 : return s3c24xx_get_fclk() / 2; + case 2 : return s3c24xx_get_fclk() / (4 * (BIT( m_clkpow.regs.camdivn, 9) + 1)); + case 3 : return s3c24xx_get_fclk() / (3 * (BIT( m_clkpow.regs.camdivn, 8) + 1)); + } + return 0; +#endif +} + +UINT32 S3C24_CLASS_NAME::s3c24xx_get_pclk() +{ + return s3c24xx_get_hclk() / (1 << BIT( m_clkpow.regs.clkdivn, 0)); +} + +READ32_MEMBER( S3C24_CLASS_NAME::s3c24xx_clkpow_r ) +{ + UINT32 data = ((UINT32*)&m_clkpow.regs)[offset]; + verboselog(machine(), 9, "(CLKPOW) %08X -> %08X\n", S3C24XX_BASE_CLKPOW + (offset << 2), data); + return data; +} + +WRITE32_MEMBER( S3C24_CLASS_NAME::s3c24xx_clkpow_w ) +{ + verboselog( machine(), 9, "(CLKPOW) %08X <- %08X\n", S3C24XX_BASE_CLKPOW + (offset << 2), data); + COMBINE_DATA(&((UINT32*)&m_clkpow.regs)[offset]); + switch (offset) + { + case S3C24XX_MPLLCON : + { + verboselog( machine(), 5, "CLKPOW - fclk %d hclk %d pclk %d\n", s3c24xx_get_fclk(), s3c24xx_get_hclk(), s3c24xx_get_pclk()); + m_cpu->set_unscaled_clock(s3c24xx_get_fclk() * CLOCK_MULTIPLIER); + } + break; + case S3C24XX_CLKSLOW : + { + verboselog( machine(), 5, "CLKPOW - fclk %d hclk %d pclk %d\n", s3c24xx_get_fclk(), s3c24xx_get_hclk(), s3c24xx_get_pclk()); + m_cpu->set_unscaled_clock(s3c24xx_get_fclk() * CLOCK_MULTIPLIER); + } + break; + } +} + +/* Interrupt Controller */ + +void S3C24_CLASS_NAME::s3c24xx_irq_reset() +{ + s3c24xx_irq_t *irq = &m_irq; + memset( &irq->regs, 0, sizeof( irq->regs)); + irq->line_irq = irq->line_fiq = CLEAR_LINE; + irq->regs.intmsk = 0xFFFFFFFF; + irq->regs.priority = 0x7F; + #if defined(DEVICE_S3C2410) + irq->regs.intsubmsk = 0x07FF; + #elif defined(DEVICE_S3C2440) + irq->regs.intsubmsk = 0xFFFF; + #endif +} + +void S3C24_CLASS_NAME::s3c24xx_check_pending_irq() +{ + UINT32 temp; + // normal irq + + if ((m_irq.regs.intpnd == 0) && (m_irq.regs.intoffset == 0)) // without this "touryuu" crashes + { + temp = (m_irq.regs.srcpnd & ~m_irq.regs.intmsk) & ~m_irq.regs.intmod; + if (temp != 0) + { + UINT32 int_type = 0; + verboselog( machine(), 5, "srcpnd %08X intmsk %08X intmod %08X\n", m_irq.regs.srcpnd, m_irq.regs.intmsk, m_irq.regs.intmod); + while ((temp & 1) == 0) + { + int_type++; + temp = temp >> 1; + } + verboselog( machine(), 5, "intpnd set bit %d\n", int_type); + m_irq.regs.intpnd |= (1 << int_type); + m_irq.regs.intoffset = int_type; + if (m_irq.line_irq != ASSERT_LINE) + { + verboselog( machine(), 5, "ARM7_IRQ_LINE -> ASSERT_LINE\n"); + m_cpu->execute().set_input_line(ARM7_IRQ_LINE, ASSERT_LINE); + m_irq.line_irq = ASSERT_LINE; + } + } + else + { + if (m_irq.line_irq != CLEAR_LINE) + { + verboselog( machine(), 5, "srcpnd %08X intmsk %08X intmod %08X\n", m_irq.regs.srcpnd, m_irq.regs.intmsk, m_irq.regs.intmod); + verboselog( machine(), 5, "ARM7_IRQ_LINE -> CLEAR_LINE\n"); + m_cpu->execute().set_input_line(ARM7_IRQ_LINE, CLEAR_LINE); + m_irq.line_irq = CLEAR_LINE; + } + } + } + + // fast irq + temp = (m_irq.regs.srcpnd & ~m_irq.regs.intmsk) & m_irq.regs.intmod; + if (temp != 0) + { + UINT32 int_type = 0; + while ((temp & 1) == 0) + { + int_type++; + temp = temp >> 1; + } + if (m_irq.line_fiq != ASSERT_LINE) + { + verboselog( machine(), 5, "ARM7_FIRQ_LINE -> ASSERT_LINE\n"); + m_cpu->execute().set_input_line(ARM7_FIRQ_LINE, ASSERT_LINE); + m_irq.line_fiq = ASSERT_LINE; + } + } + else + { + if (m_irq.line_fiq != CLEAR_LINE) + { + verboselog( machine(), 5, "ARM7_FIRQ_LINE -> CLEAR_LINE\n"); + m_cpu->execute().set_input_line(ARM7_FIRQ_LINE, CLEAR_LINE); + m_irq.line_fiq = CLEAR_LINE; + } + } +} + +void S3C24_CLASS_NAME::s3c24xx_request_irq(UINT32 int_type) +{ + verboselog( machine(), 5, "request irq %d\n", int_type); + m_irq.regs.srcpnd |= (1 << int_type); + s3c24xx_check_pending_irq(); +} + +#if defined(DEVICE_S3C2410) || defined(DEVICE_S3C2440) + +void S3C24_CLASS_NAME::s3c24xx_check_pending_subirq() +{ + UINT32 temp = m_irq.regs.subsrcpnd & ~m_irq.regs.intsubmsk; + if (temp != 0) + { + UINT32 int_type = 0; + while ((temp & 1) == 0) + { + int_type++; + temp = temp >> 1; + } + s3c24xx_request_irq( MAP_SUBINT_TO_INT[int_type]); + } +} + +ATTR_UNUSED void S3C24_CLASS_NAME::s3c24xx_request_subirq( UINT32 int_type) +{ + verboselog( machine(), 5, "request subirq %d\n", int_type); + m_irq.regs.subsrcpnd |= (1 << int_type); + s3c24xx_check_pending_subirq(); +} + +void S3C24_CLASS_NAME::s3c24xx_check_pending_eint() +{ + UINT32 temp = m_gpio.regs.eintpend & ~m_gpio.regs.eintmask; + if (temp != 0) + { + UINT32 int_type = 0; + while ((temp & 1) == 0) + { + int_type++; + temp = temp >> 1; + } + if (int_type < 8) + { + s3c24xx_request_irq(S3C24XX_INT_EINT4_7); + } + else + { + s3c24xx_request_irq(S3C24XX_INT_EINT8_23); + } + } +} + +ATTR_UNUSED void S3C24_CLASS_NAME::s3c24xx_request_eint(UINT32 number) +{ + verboselog( machine(), 5, "request external interrupt %d\n", number); + if (number < 4) + { + s3c24xx_request_irq( S3C24XX_INT_EINT0 + number); + } + else + { + m_gpio.regs.eintpend |= (1 << number); + s3c24xx_check_pending_eint(); + } +} + +#endif + +READ32_MEMBER( S3C24_CLASS_NAME::s3c24xx_irq_r ) +{ + UINT32 data = ((UINT32*)&m_irq.regs)[offset]; + verboselog( machine(), 9, "(IRQ) %08X -> %08X\n", S3C24XX_BASE_INT + (offset << 2), data); + return data; +} + +WRITE32_MEMBER( S3C24_CLASS_NAME::s3c24xx_irq_w ) +{ + UINT32 old_value = ((UINT32*)&m_irq.regs)[offset]; + verboselog( machine(), 9, "(IRQ) %08X <- %08X\n", S3C24XX_BASE_INT + (offset << 2), data); + COMBINE_DATA(&((UINT32*)&m_irq.regs)[offset]); + switch (offset) + { + case S3C24XX_SRCPND : + { + m_irq.regs.srcpnd = (old_value & ~data); // clear only the bit positions of SRCPND corresponding to those set to one in the data + m_irq.regs.intoffset = 0; // "This bit can be cleared automatically by clearing SRCPND and INTPND." + s3c24xx_check_pending_irq(); + } + break; + case S3C24XX_INTMSK : + { + s3c24xx_check_pending_irq(); + } + break; + case S3C24XX_INTPND : + { + m_irq.regs.intpnd = (old_value & ~data); // clear only the bit positions of INTPND corresponding to those set to one in the data + m_irq.regs.intoffset = 0; // "This bit can be cleared automatically by clearing SRCPND and INTPND." + s3c24xx_check_pending_irq(); + } + break; +#if defined(DEVICE_S3C2410) || defined(DEVICE_S3C2440) + case S3C24XX_SUBSRCPND : + { + m_irq.regs.subsrcpnd = (old_value & ~data); // clear only the bit positions of SRCPND corresponding to those set to one in the data + s3c24xx_check_pending_subirq(); + } + break; + case S3C24XX_INTSUBMSK : + { + s3c24xx_check_pending_subirq(); + } + break; +#endif + } +} + +/* PWM Timer */ + +void S3C24_CLASS_NAME::s3c24xx_pwm_reset() +{ + s3c24xx_pwm_t *pwm = &m_pwm; + memset( &pwm->regs, 0, sizeof( pwm->regs)); + for (int i = 0; i < 5; i++) + { + pwm->timer[i]->adjust( attotime::never); + } +} + +UINT16 S3C24_CLASS_NAME::s3c24xx_pwm_calc_observation(int ch) +{ + double timeleft, x1, x2; + UINT32 cnto; + timeleft = m_pwm.timer[ch]->remaining( ).as_double(); +// printf( "timeleft %f freq %d cntb %d cmpb %d\n", timeleft, m_pwm.freq[ch], m_pwm.cnt[ch], m_pwm.cmp[ch]); + x1 = 1 / ((double)m_pwm.freq[ch] / (m_pwm.cnt[ch]- m_pwm.cmp[ch] + 1)); + x2 = x1 / timeleft; +// printf( "x1 %f\n", x1); + cnto = m_pwm.cmp[ch] + ((m_pwm.cnt[ch]- m_pwm.cmp[ch]) / x2); +// printf( "cnto %d\n", cnto); + return cnto; +} + +READ32_MEMBER( S3C24_CLASS_NAME::s3c24xx_pwm_r ) +{ + UINT32 data = ((UINT32*)&m_pwm.regs)[offset]; + switch (offset) + { + case S3C24XX_TCNTO0 : + { + data = (data & ~0x0000FFFF) | s3c24xx_pwm_calc_observation( 0); + } + break; + case S3C24XX_TCNTO1 : + { + data = (data & ~0x0000FFFF) | s3c24xx_pwm_calc_observation( 1); + } + break; + case S3C24XX_TCNTO2 : + { + data = (data & ~0x0000FFFF) | s3c24xx_pwm_calc_observation( 2); + } + break; + case S3C24XX_TCNTO3 : + { + data = (data & ~0x0000FFFF) | s3c24xx_pwm_calc_observation( 3); + } + break; + case S3C24XX_TCNTO4 : + { + data = (data & ~0x0000FFFF) | s3c24xx_pwm_calc_observation( 4); + } + break; + } + verboselog( machine(), 9, "(PWM) %08X -> %08X\n", S3C24XX_BASE_PWM + (offset << 2), data); + return data; +} + +void S3C24_CLASS_NAME::s3c24xx_pwm_start(int timer) +{ + const int mux_table[] = { 2, 4, 8, 16}; + const int prescaler_shift[] = { 0, 0, 8, 8, 8}; + const int mux_shift[] = { 0, 4, 8, 12, 16}; + UINT32 pclk, prescaler, mux, cnt, cmp, auto_reload; + double freq, hz; + verboselog( machine(), 1, "PWM %d start\n", timer); + pclk = s3c24xx_get_pclk(); + prescaler = (m_pwm.regs.tcfg0 >> prescaler_shift[timer]) & 0xFF; + mux = (m_pwm.regs.tcfg1 >> mux_shift[timer]) & 0x0F; + if (mux < 4) + { + freq = (double)pclk / (prescaler + 1) / mux_table[mux]; + } + else + { + // todo + freq = (double)pclk / (prescaler + 1) / 1; + } + switch (timer) + { + case 0 : + { + cnt = BITS( m_pwm.regs.tcntb0, 15, 0); + cmp = BITS( m_pwm.regs.tcmpb0, 15, 0); + auto_reload = BIT( m_pwm.regs.tcon, 3); + } + break; + case 1 : + { + cnt = BITS( m_pwm.regs.tcntb1, 15, 0); + cmp = BITS( m_pwm.regs.tcmpb1, 15, 0); + auto_reload = BIT( m_pwm.regs.tcon, 11); + } + break; + case 2 : + { + cnt = BITS( m_pwm.regs.tcntb2, 15, 0); + cmp = BITS( m_pwm.regs.tcmpb2, 15, 0); + auto_reload = BIT( m_pwm.regs.tcon, 15); + } + break; + case 3 : + { + cnt = BITS( m_pwm.regs.tcntb3, 15, 0); + cmp = BITS( m_pwm.regs.tcmpb3, 15, 0); + auto_reload = BIT( m_pwm.regs.tcon, 19); + } + break; + case 4 : + { + cnt = BITS( m_pwm.regs.tcntb4, 15, 0); + cmp = 0; + auto_reload = BIT( m_pwm.regs.tcon, 22); + } + break; + default : + { + cnt = cmp = auto_reload = 0; + } + break; + } +// hz = freq / (cnt - cmp + 1); + if (cnt < 2) + { + hz = freq; + } + else + { + hz = freq / cnt; + } + verboselog( machine(), 5, "PWM %d - pclk=%d prescaler=%d div=%d freq=%f cnt=%d cmp=%d auto_reload=%d hz=%f\n", timer, pclk, prescaler, mux_table[mux], freq, cnt, cmp, auto_reload, hz); + m_pwm.cnt[timer] = cnt; + m_pwm.cmp[timer] = cmp; + m_pwm.freq[timer] = freq; + if (auto_reload) + { + m_pwm.timer[timer]->adjust( attotime::from_hz( hz), timer, attotime::from_hz( hz)); + } + else + { + m_pwm.timer[timer]->adjust( attotime::from_hz( hz), timer); + } +} + +void S3C24_CLASS_NAME::s3c24xx_pwm_stop(int timer) +{ + verboselog( machine(), 1, "PWM %d stop\n", timer); + m_pwm.timer[timer]->adjust( attotime::never); +} + +void S3C24_CLASS_NAME::s3c24xx_pwm_recalc(int timer) +{ + const int tcon_shift[] = { 0, 8, 12, 16, 20}; + if (m_pwm.regs.tcon & (1 << tcon_shift[timer])) + { + s3c24xx_pwm_start(timer); + } + else + { + s3c24xx_pwm_stop(timer); + } +} + +WRITE32_MEMBER( S3C24_CLASS_NAME::s3c24xx_pwm_w ) +{ + UINT32 old_value = ((UINT32*)&m_pwm.regs)[offset]; + verboselog( machine(), 9, "(PWM) %08X <- %08X\n", S3C24XX_BASE_PWM + (offset << 2), data); + COMBINE_DATA(&((UINT32*)&m_pwm.regs)[offset]); + switch (offset) + { + case S3C24XX_TCON : + { + if ((data & (1 << 0)) != (old_value & (1 << 0))) + { + s3c24xx_pwm_recalc( 0); + } + if ((data & (1 << 8)) != (old_value & (1 << 8))) + { + s3c24xx_pwm_recalc( 1); + } + if ((data & (1 << 12)) != (old_value & (1 << 12))) + { + s3c24xx_pwm_recalc(2); + } + if ((data & (1 << 16)) != (old_value & (1 << 16))) + { + s3c24xx_pwm_recalc(3); + } + if ((data & (1 << 20)) != (old_value & (1 << 20))) + { + s3c24xx_pwm_recalc(4); + } + } + break; + } +} + +TIMER_CALLBACK_MEMBER( S3C24_CLASS_NAME::s3c24xx_pwm_timer_exp ) +{ + int ch = param; + const int ch_int[] = { S3C24XX_INT_TIMER0, S3C24XX_INT_TIMER1, S3C24XX_INT_TIMER2, S3C24XX_INT_TIMER3, S3C24XX_INT_TIMER4 }; + verboselog( machine(), 2, "PWM %d timer callback\n", ch); + if (BITS( m_pwm.regs.tcfg1, 23, 20) == (ch + 1)) + { + s3c24xx_dma_request_pwm(); + } + else + { + s3c24xx_request_irq(ch_int[ch]); + } +} + +/* DMA */ + +void S3C24_CLASS_NAME::s3c24xx_dma_reset() +{ + for (int i = 0; i < S3C24XX_DMA_COUNT; i++) + { + s3c24xx_dma_t *dma = &m_dma[i]; + memset( &dma->regs, 0, sizeof( dma->regs)); + dma->timer->adjust( attotime::never); + } +} + +void S3C24_CLASS_NAME::s3c24xx_dma_reload(int ch) +{ + s3c24xx_dma_regs_t *regs = &m_dma[ch].regs; + regs->dstat = S3C24XX_DSTAT_SET_CURR_TC( regs->dstat, S3C24XX_DCON_GET_TC( regs->dcon)); + regs->dcsrc = S3C24XX_DCSRC_SET_CURR_SRC( regs->dcsrc, S3C24XX_DISRC_GET_SADDR( regs->disrc)); + regs->dcdst = S3C24XX_DCDST_SET_CURR_DST( regs->dcdst, S3C24XX_DIDST_GET_DADDR( regs->didst)); +} + +void S3C24_CLASS_NAME::s3c24xx_dma_trigger(int ch) +{ + s3c24xx_dma_regs_t *regs = &m_dma[ch].regs; + UINT32 curr_tc, curr_src, curr_dst; + address_space &space = m_cpu->memory().space( AS_PROGRAM); + int dsz, inc_src, inc_dst, servmode, tsz; + const UINT32 ch_int[] = { S3C24XX_INT_DMA0, S3C24XX_INT_DMA1, S3C24XX_INT_DMA2, S3C24XX_INT_DMA3}; + verboselog( machine(), 5, "DMA %d trigger\n", ch); + curr_tc = S3C24XX_DSTAT_GET_CURR_TC( regs->dstat); + dsz = S3C24XX_DCON_GET_DSZ( regs->dcon); + curr_src = S3C24XX_DCSRC_GET_CURR_SRC( regs->dcsrc); + curr_dst = S3C24XX_DCDST_GET_CURR_DST( regs->dcdst); + servmode = S3C24XX_DCON_GET_SERVMODE( regs->dcon); + tsz = S3C24XX_DCON_GET_TSZ( regs->dcon); +#if defined(DEVICE_S3C2400) + inc_src = BIT( regs->disrc, 29); + inc_dst = BIT( regs->didst, 29); +#else + inc_src = BIT( regs->disrcc, 0); + inc_dst = BIT( regs->didstc, 0); +#endif + verboselog( machine(), 5, "DMA %d - curr_src %08X curr_dst %08X curr_tc %d dsz %d\n", ch, curr_src, curr_dst, curr_tc, dsz); + while (curr_tc > 0) + { + curr_tc--; + for (int i = 0; i < 1 << (tsz << 1); i++) + { + switch (dsz) + { + case 0 : space.write_byte( curr_dst, space.read_byte( curr_src)); break; + case 1 : space.write_word( curr_dst, space.read_word( curr_src)); break; + case 2 : space.write_dword( curr_dst, space.read_dword( curr_src)); break; + } + if (inc_src == 0) curr_src += (1 << dsz); + if (inc_dst == 0) curr_dst += (1 << dsz); + } + if (servmode == 0) break; + } + regs->dcsrc = S3C24XX_DCSRC_SET_CURR_SRC( regs->dcsrc, curr_src); + regs->dcdst = S3C24XX_DCDST_SET_CURR_DST( regs->dcdst, curr_dst); + regs->dstat = S3C24XX_DSTAT_SET_CURR_TC( regs->dstat, curr_tc); + if (curr_tc == 0) + { + if (S3C24XX_DCON_GET_RELOAD( regs->dcon) == 0) + { + s3c24xx_dma_reload(ch); + } + else + { + regs->dmasktrig &= ~(1 << 1); // clear on/off + } + if (S3C24XX_DCON_GET_INT( regs->dcon) != 0) + { + s3c24xx_request_irq(ch_int[ch]); + } + } +} + +void S3C24_CLASS_NAME::s3c24xx_dma_request_iis() +{ + s3c24xx_dma_regs_t *regs = &m_dma[2].regs; + verboselog( machine(), 5, "s3c24xx_dma_request_iis\n"); + if ((S3C24XX_DMASKTRIG_GET_ON_OFF( regs->dmasktrig) != 0) && (S3C24XX_DCON_GET_SWHWSEL( regs->dcon) != 0) && (S3C24XX_DCON_GET_HWSRCSEL( regs->dcon) == 0)) + { + s3c24xx_dma_trigger(2); + } +} + +void S3C24_CLASS_NAME::s3c24xx_dma_request_pwm() +{ + verboselog( machine(), 5, "s3c24xx_dma_request_pwm\n"); + for (int i = 0; i < 4; i++) + { + if (i != 1) + { + s3c24xx_dma_regs_t *regs = &m_dma[i].regs; + if ((S3C24XX_DMASKTRIG_GET_ON_OFF( regs->dmasktrig) != 0) && (S3C24XX_DCON_GET_SWHWSEL( regs->dcon) != 0) && (S3C24XX_DCON_GET_HWSRCSEL( regs->dcon) == 3)) + { + s3c24xx_dma_trigger(i); + } + } + } +} + +void S3C24_CLASS_NAME::s3c24xx_dma_start(int ch) +{ + UINT32 addr_src, addr_dst, tc; + s3c24xx_dma_regs_t *regs = &m_dma[ch].regs; + UINT32 dsz, tsz, reload; + int inc_src, inc_dst, _int, servmode, swhwsel, hwsrcsel; + verboselog( machine(), 1, "DMA %d start\n", ch); + addr_src = S3C24XX_DISRC_GET_SADDR( regs->disrc); + addr_dst = S3C24XX_DIDST_GET_DADDR( regs->didst); + tc = S3C24XX_DCON_GET_TC( regs->dcon); + _int = S3C24XX_DCON_GET_INT( regs->dcon); + servmode = S3C24XX_DCON_GET_SERVMODE( regs->dcon); + hwsrcsel = S3C24XX_DCON_GET_HWSRCSEL( regs->dcon); + swhwsel = S3C24XX_DCON_GET_SWHWSEL( regs->dcon); + reload = S3C24XX_DCON_GET_RELOAD( regs->dcon); + dsz = S3C24XX_DCON_GET_DSZ( regs->dcon); + tsz = S3C24XX_DCON_GET_TSZ( regs->dcon); +#if defined(DEVICE_S3C2400) + inc_src = BIT( regs->disrc, 29); + inc_dst = BIT( regs->didst, 29); +#else + inc_src = BIT( regs->disrcc, 0); + inc_dst = BIT( regs->didstc, 0); +#endif + verboselog( machine(), 5, "DMA %d - addr_src %08X inc_src %d addr_dst %08X inc_dst %d int %d tsz %d servmode %d hwsrcsel %d swhwsel %d reload %d dsz %d tc %d\n", ch, addr_src, inc_src, addr_dst, inc_dst, _int, tsz, servmode, hwsrcsel, swhwsel, reload, dsz, tc); + verboselog( machine(), 5, "DMA %d - copy %08X bytes from %08X (%s) to %08X (%s)\n", ch, (tc << dsz) << (tsz << 1), addr_src, inc_src ? "fix" : "inc", addr_dst, inc_dst ? "fix" : "inc"); + s3c24xx_dma_reload(ch); + if (swhwsel == 0) + { + s3c24xx_dma_trigger(ch); + } +} + +void S3C24_CLASS_NAME::s3c24xx_dma_stop(int ch) +{ + verboselog( machine(), 1, "DMA %d stop\n", ch); +} + +void S3C24_CLASS_NAME::s3c24xx_dma_recalc(int ch) +{ + if ((m_dma[ch].regs.dmasktrig & (1 << 1)) != 0) + { + s3c24xx_dma_start(ch); + } + else + { + s3c24xx_dma_stop(ch); + } +} + +UINT32 S3C24_CLASS_NAME::s3c24xx_dma_r(UINT32 ch, UINT32 offset) +{ + return ((UINT32*)&m_dma[ch].regs)[offset]; +} + +void S3C24_CLASS_NAME::s3c24xx_dma_w(UINT32 ch, UINT32 offset, UINT32 data, UINT32 mem_mask) +{ + UINT32 old_value = ((UINT32*)&m_dma[ch].regs)[offset]; + COMBINE_DATA(&((UINT32*)&m_dma[ch].regs)[offset]); + switch (offset) + { + case S3C24XX_DCON : + { + #if 0 // is this code necessary ??? + if ((data & (1 << 22)) != 0) // reload + { + s3c24xx_dma_regs_t *regs = &m_dma[ch].regs; + regs->dmasktrig &= ~(1 << 1); // clear on/off + } + #endif + } + break; + case S3C24XX_DMASKTRIG : + { + if ((old_value & (1 << 1)) != (data & (1 << 1))) + { + s3c24xx_dma_recalc(ch); + } + } + break; + } +} + +READ32_MEMBER( S3C24_CLASS_NAME::s3c24xx_dma_0_r ) +{ + UINT32 data = s3c24xx_dma_r( 0, offset); + verboselog( machine(), 9, "(DMA 0) %08X -> %08X\n", S3C24XX_BASE_DMA_0 + (offset << 2), data); + return data; +} + +READ32_MEMBER( S3C24_CLASS_NAME::s3c24xx_dma_1_r ) +{ + UINT32 data = s3c24xx_dma_r( 1, offset); + verboselog( machine(), 9, "(DMA 1) %08X -> %08X\n", S3C24XX_BASE_DMA_1 + (offset << 2), data); + return data; +} + +READ32_MEMBER( S3C24_CLASS_NAME::s3c24xx_dma_2_r ) +{ + UINT32 data = s3c24xx_dma_r( 2, offset); + verboselog( machine(), 9, "(DMA 2) %08X -> %08X\n", S3C24XX_BASE_DMA_2 + (offset << 2), data); + return data; +} + +READ32_MEMBER( S3C24_CLASS_NAME::s3c24xx_dma_3_r ) +{ + UINT32 data = s3c24xx_dma_r( 3, offset); + verboselog( machine(), 9, "(DMA 3) %08X -> %08X\n", S3C24XX_BASE_DMA_3 + (offset << 2), data); + return data; +} + +WRITE32_MEMBER( S3C24_CLASS_NAME::s3c24xx_dma_0_w ) +{ + verboselog( machine(), 9, "(DMA 0) %08X <- %08X\n", S3C24XX_BASE_DMA_0 + (offset << 2), data); + s3c24xx_dma_w( 0, offset, data, mem_mask); +} + +WRITE32_MEMBER( S3C24_CLASS_NAME::s3c24xx_dma_1_w ) +{ + verboselog( machine(), 9, "(DMA 1) %08X <- %08X\n", S3C24XX_BASE_DMA_1 + (offset << 2), data); + s3c24xx_dma_w( 1, offset, data, mem_mask); +} + +WRITE32_MEMBER( S3C24_CLASS_NAME::s3c24xx_dma_2_w ) +{ + verboselog( machine(), 9, "(DMA 2) %08X <- %08X\n", S3C24XX_BASE_DMA_2 + (offset << 2), data); + s3c24xx_dma_w( 2, offset, data, mem_mask); +} + +WRITE32_MEMBER( S3C24_CLASS_NAME::s3c24xx_dma_3_w ) +{ + verboselog( machine(), 9, "(DMA 3) %08X <- %08X\n", S3C24XX_BASE_DMA_3 + (offset << 2), data); + s3c24xx_dma_w( 3, offset, data, mem_mask); +} + +TIMER_CALLBACK_MEMBER( S3C24_CLASS_NAME::s3c24xx_dma_timer_exp ) +{ + int ch = param; + verboselog( machine(), 2, "DMA %d timer callback\n", ch); +} + +/* I/O Port */ + +void S3C24_CLASS_NAME::s3c24xx_gpio_reset() +{ + s3c24xx_gpio_t *gpio = &m_gpio; + memset( &gpio->regs, 0, sizeof( gpio->regs)); + #if defined(DEVICE_S3C2400) + gpio->regs.gpacon = 0x0003FFFF; + gpio->regs.gpbcon = 0xAAAAAAAA; + gpio->regs.gpdup = 0x0620; + gpio->regs.gpeup = 0x0003; + #elif defined(DEVICE_S3C2410) + gpio->regs.gpacon = 0x007FFFFF; + gpio->regs.gpgup = 0xF800; + gpio->regs.misccr = 0x00010330; + gpio->regs.eintmask = 0x00FFFFF0; + gpio->regs.gstatus1 = 0x32410002; + #elif defined(DEVICE_S3C2440) + gpio->regs.gpacon = 0x00FFFFFF; + gpio->regs.gpgup = 0xFC00; + gpio->regs.misccr = 0x00010020; + gpio->regs.eintmask = 0x000FFFFF; + gpio->regs.gstatus1 = 0x32440001; + #endif + gpio->regs.gpdup = 0xF000; + #if defined(DEVICE_S3C2410) || defined(DEVICE_S3C2440) + gpio->regs.gstatus2 = 1 << 0; // Boot is caused by power on reset + #endif +} + +UINT32 S3C24_CLASS_NAME::iface_gpio_port_r(int port, UINT32 mask) +{ + if (!m_port_r_cb.isnull()) + { + // TO CHECK : masking is not done in any of handlers + // devcb do it automatically so guess is masks are not proper right now + // without masking works fine + return (m_port_r_cb)( port ); //, mask); + } + else + { + return 0; + } +} + +void S3C24_CLASS_NAME::iface_gpio_port_w(int port, UINT32 mask, UINT32 data) +{ + if (!m_port_w_cb.isnull()) + { + (m_port_w_cb)( port, data, mask ); + } +} + +UINT16 S3C24_CLASS_NAME::s3c24xx_gpio_get_mask( UINT32 con, int val) +{ + UINT16 mask = 0; + for (int i = 0; i < 16; i++) + { + if (((con >> (i << 1)) & 3) == val) + { + mask = mask | (1 << i); + } + } + return mask; +} + +READ32_MEMBER( S3C24_CLASS_NAME::s3c24xx_gpio_r ) +{ + s3c24xx_gpio_t *gpio = &m_gpio; + UINT32 data = ((UINT32*)&m_gpio.regs)[offset]; + switch (offset) + { + case S3C24XX_GPADAT : + { + data = iface_gpio_port_r( S3C24XX_GPIO_PORT_A, 0) & S3C24XX_GPADAT_MASK; + } + break; + case S3C24XX_GPBDAT : + { + data = iface_gpio_port_r( S3C24XX_GPIO_PORT_B, s3c24xx_gpio_get_mask( gpio->regs.gpbcon, 0) & S3C24XX_GPBDAT_MASK) & S3C24XX_GPBDAT_MASK; + } + break; + case S3C24XX_GPCDAT : + { + data = iface_gpio_port_r( S3C24XX_GPIO_PORT_C, s3c24xx_gpio_get_mask( gpio->regs.gpccon, 0) & S3C24XX_GPCDAT_MASK) & S3C24XX_GPCDAT_MASK; + } + break; + case S3C24XX_GPDDAT : + { + data = iface_gpio_port_r( S3C24XX_GPIO_PORT_D, s3c24xx_gpio_get_mask( gpio->regs.gpdcon, 0) & S3C24XX_GPDDAT_MASK) & S3C24XX_GPDDAT_MASK; + } + break; + case S3C24XX_GPEDAT : + { + data = iface_gpio_port_r( S3C24XX_GPIO_PORT_E, s3c24xx_gpio_get_mask( gpio->regs.gpecon, 0) & S3C24XX_GPEDAT_MASK) & S3C24XX_GPEDAT_MASK; + } + break; + case S3C24XX_GPFDAT : + { + data = iface_gpio_port_r( S3C24XX_GPIO_PORT_F, s3c24xx_gpio_get_mask( gpio->regs.gpfcon, 0) & S3C24XX_GPFDAT_MASK) & S3C24XX_GPFDAT_MASK; + } + break; + case S3C24XX_GPGDAT : + { + data = iface_gpio_port_r( S3C24XX_GPIO_PORT_G, s3c24xx_gpio_get_mask( gpio->regs.gpgcon, 0) & S3C24XX_GPGDAT_MASK) & S3C24XX_GPGDAT_MASK; + } + break; +#if defined(DEVICE_S3C2410) || defined(DEVICE_S3C2440) + case S3C24XX_GPHDAT : + { + data = iface_gpio_port_r( S3C24XX_GPIO_PORT_H, s3c24xx_gpio_get_mask( gpio->regs.gphcon, 0) & S3C24XX_GPHDAT_MASK) & S3C24XX_GPHDAT_MASK; + } + break; +#endif +#if defined(DEVICE_S3C2440) + case S3C24XX_GPJDAT : + { + data = iface_gpio_port_r( S3C24XX_GPIO_PORT_J, s3c24xx_gpio_get_mask( gpio->regs.gpjcon, 0) & S3C24XX_GPJDAT_MASK) & S3C24XX_GPJDAT_MASK; + } + break; +#endif + } + verboselog( machine(), 9, "(GPIO) %08X -> %08X\n", S3C24XX_BASE_GPIO + (offset << 2), data); + return data; +} + +WRITE32_MEMBER( S3C24_CLASS_NAME::s3c24xx_gpio_w ) +{ + s3c24xx_gpio_t *gpio = &m_gpio; +#if defined(DEVICE_S3C2410) || defined(DEVICE_S3C2440) + UINT32 old_value = ((UINT32*)&m_gpio.regs)[offset]; +#endif + verboselog( machine(), 9, "(GPIO) %08X <- %08X\n", S3C24XX_BASE_GPIO + (offset << 2), data); + COMBINE_DATA(&((UINT32*)&m_gpio.regs)[offset]); + switch (offset) + { + case S3C24XX_GPADAT : + { + iface_gpio_port_w( S3C24XX_GPIO_PORT_A, gpio->regs.gpacon ^ 0xFFFFFFFF, data & S3C24XX_GPADAT_MASK); + } + break; + case S3C24XX_GPBDAT : + { + iface_gpio_port_w( S3C24XX_GPIO_PORT_B, s3c24xx_gpio_get_mask( gpio->regs.gpbcon, 1) & S3C24XX_GPBDAT_MASK, data & S3C24XX_GPBDAT_MASK); + } + break; + case S3C24XX_GPCDAT : + { + iface_gpio_port_w( S3C24XX_GPIO_PORT_C, s3c24xx_gpio_get_mask( gpio->regs.gpccon, 1) & S3C24XX_GPCDAT_MASK, data & S3C24XX_GPCDAT_MASK); + } + break; + case S3C24XX_GPDDAT : + { + iface_gpio_port_w( S3C24XX_GPIO_PORT_D, s3c24xx_gpio_get_mask( gpio->regs.gpdcon, 1) & S3C24XX_GPDDAT_MASK, data & S3C24XX_GPDDAT_MASK); + } + break; + case S3C24XX_GPEDAT : + { + iface_gpio_port_w( S3C24XX_GPIO_PORT_E, s3c24xx_gpio_get_mask( gpio->regs.gpecon, 1) & S3C24XX_GPEDAT_MASK, data & S3C24XX_GPEDAT_MASK); + } + break; + case S3C24XX_GPFDAT : + { + iface_gpio_port_w( S3C24XX_GPIO_PORT_F, s3c24xx_gpio_get_mask( gpio->regs.gpfcon, 1) & S3C24XX_GPFDAT_MASK, data & S3C24XX_GPFDAT_MASK); + } + break; + case S3C24XX_GPGDAT : + { + iface_gpio_port_w( S3C24XX_GPIO_PORT_G, s3c24xx_gpio_get_mask( gpio->regs.gpgcon, 1) & S3C24XX_GPGDAT_MASK, data & S3C24XX_GPGDAT_MASK); + } + break; +#if defined(DEVICE_S3C2410) || defined(DEVICE_S3C2440) + case S3C24XX_GPHDAT : + { + iface_gpio_port_w( S3C24XX_GPIO_PORT_H, s3c24xx_gpio_get_mask( gpio->regs.gphcon, 1) & S3C24XX_GPHDAT_MASK, data & S3C24XX_GPHDAT_MASK); + } + break; + case S3C24XX_EINTPEND : + { + m_gpio.regs.eintpend = (old_value & ~data); + s3c24xx_check_pending_eint(); + } + break; + case S3C24XX_EINTMASK : + { + s3c24xx_check_pending_eint(); + } + break; + case S3C24XX_GSTATUS2 : + { + m_gpio.regs.gstatus2 = (old_value & ~data) & 7; // "The setting is cleared by writing '1' to this bit" + } + break; +#endif +#if defined(DEVICE_S3C2440) + case S3C24XX_GPJDAT : + { + iface_gpio_port_w( S3C24XX_GPIO_PORT_J, s3c24xx_gpio_get_mask( gpio->regs.gpjcon, 1) & S3C24XX_GPJDAT_MASK, data & S3C24XX_GPJDAT_MASK); + } + break; +#endif + } +} + +/* Memory Controller */ + +void S3C24_CLASS_NAME::s3c24xx_memcon_reset() +{ + s3c24xx_memcon_t *memcon = &m_memcon; + memset( &memcon->regs, 0, sizeof( memcon->regs)); + memcon->regs.data[0x04/4] = 0x00000700; + memcon->regs.data[0x08/4] = 0x00000700; + memcon->regs.data[0x0C/4] = 0x00000700; + memcon->regs.data[0x10/4] = 0x00000700; + memcon->regs.data[0x14/4] = 0x00000700; + memcon->regs.data[0x18/4] = 0x00000700; + memcon->regs.data[0x1C/4] = 0x00018008; + memcon->regs.data[0x20/4] = 0x00018008; + memcon->regs.data[0x24/4] = 0x00AC0000; +} + +READ32_MEMBER( S3C24_CLASS_NAME::s3c24xx_memcon_r ) +{ + assert(offset < ARRAY_LENGTH(m_memcon.regs.data)); + UINT32 data = m_memcon.regs.data[offset]; + verboselog( machine(), 9, "(MEMCON) %08X -> %08X\n", S3C24XX_BASE_MEMCON + (offset << 2), data); + return data; +} + +WRITE32_MEMBER( S3C24_CLASS_NAME::s3c24xx_memcon_w ) +{ + verboselog( machine(), 9, "(MEMCON) %08X <- %08X\n", S3C24XX_BASE_MEMCON + (offset << 2), data); + COMBINE_DATA(&m_memcon.regs.data[offset]); +} + +/* USB Host Controller */ + +void S3C24_CLASS_NAME::s3c24xx_usb_host_reset() +{ + s3c24xx_usbhost_t *usbhost = &m_usbhost; + memset( &usbhost->regs, 0, sizeof( usbhost->regs)); +} + +READ32_MEMBER( S3C24_CLASS_NAME::s3c24xx_usb_host_r ) +{ + UINT32 data = m_usbhost.regs.data[offset]; + switch (offset) + { + // HcCommandStatus + case 0x08 / 4 : + { + data = data & ~(1 << 0); // [bit 0] HostControllerReset + } + break; + // HcPeriodStart + case 0x40 / 4: + { + // "After a hardware reset, this field is cleared. This is then set by" + // "HCD during the HC initialization. The value is calculated" + // "roughly as 10% off from HcFmInterval.. A typical value will be 3E67h." + data = (data & ~0x00003FFF) | 0x3E67; + } + break; + // HcRhDescriptorA + case 0x48 / 4: + { + data = (data & ~0xFF) | 2; // number of ports + } + break; + // HcRhStatus + case 0x50 / 4: + { + data = data & ~(1 << 16); // "The Root Hub does not support the local power status feature; thus, this bit is always read as ?0?." + } + break; + } + verboselog( machine(), 9, "(USB H) %08X -> %08X\n", S3C24XX_BASE_USBHOST + (offset << 2), data); + return data; +} + +WRITE32_MEMBER( S3C24_CLASS_NAME::s3c24xx_usb_host_w ) +{ + verboselog( machine(), 9, "(USB H) %08X <- %08X\n", S3C24XX_BASE_USBHOST + (offset << 2), data); + COMBINE_DATA(&m_usbhost.regs.data[offset]); +} + +/* UART */ + +void S3C24_CLASS_NAME::s3c24xx_uart_reset() +{ + for (int i = 0; i < S3C24XX_UART_COUNT; i++) + { + s3c24xx_uart_t *uart = &m_uart[i]; + memset( &uart->regs, 0, sizeof( uart->regs)); + uart->regs.utrstat = 6; + } +} + +UINT32 S3C24_CLASS_NAME::s3c24xx_uart_r(UINT32 ch, UINT32 offset) +{ + UINT32 data = ((UINT32*)&m_uart[ch].regs)[offset]; + switch (offset) + { + case S3C24XX_UTRSTAT : + { + data = (data & ~0x00000006) | 0x00000004 | 0x00000002; // [bit 2] Transmitter empty / [bit 1] Transmit buffer empty + } + break; + case S3C24XX_URXH : + { + UINT8 rxdata = data & 0xFF; + verboselog( machine(), 5, "UART %d read %02X (%c)\n", ch, rxdata, ((rxdata >= 32) && (rxdata < 128)) ? (char)rxdata : '?'); + m_uart[ch].regs.utrstat &= ~1; // [bit 0] Receive buffer data ready + } + break; + } + return data; +} + +void S3C24_CLASS_NAME::s3c24xx_uart_w(UINT32 ch, UINT32 offset, UINT32 data, UINT32 mem_mask) +{ + COMBINE_DATA(&((UINT32*)&m_uart[ch].regs)[offset]); + switch (offset) + { + case S3C24XX_UFCON : + { + m_uart[ch].regs.ufcon &= ~((1 << 2) | (1 << 1)); // bits 1 and 2 are auto-cleared after resetting FIFO + } + break; + case S3C24XX_UTXH : + { + UINT8 txdata = data & 0xFF; + verboselog( machine(), 5, "UART %d write %02X (%c)\n", ch, txdata, ((txdata >= 32) && (txdata < 128)) ? (char)txdata : '?'); +#ifdef UART_PRINTF + printf( "%c", ((txdata >= 32) && (txdata < 128)) ? (char)txdata : '?'); +#endif + } + break; + } +} + +READ32_MEMBER( S3C24_CLASS_NAME::s3c24xx_uart_0_r ) +{ + UINT32 data = s3c24xx_uart_r( 0, offset); +// verboselog( machine(), 9, "(UART 0) %08X -> %08X\n", S3C24XX_BASE_UART_0 + (offset << 2), data); + return data; +} + +READ32_MEMBER( S3C24_CLASS_NAME::s3c24xx_uart_1_r ) +{ + UINT32 data = s3c24xx_uart_r( 1, offset); +// verboselog( machine(), 9, "(UART 1) %08X -> %08X\n", S3C24XX_BASE_UART_1 + (offset << 2), data); + return data; +} + +#if defined(DEVICE_S3C2410) || defined(DEVICE_S3C2440) + +READ32_MEMBER( S3C24_CLASS_NAME::s3c24xx_uart_2_r ) +{ + UINT32 data = s3c24xx_uart_r( 2, offset); +// verboselog( machine(), 9, "(UART 2) %08X -> %08X\n", S3C24XX_BASE_UART_2 + (offset << 2), data); + return data; +} + +#endif + +WRITE32_MEMBER( S3C24_CLASS_NAME::s3c24xx_uart_0_w ) +{ +// verboselog( machine(), 9, "(UART 0) %08X <- %08X\n", S3C24XX_BASE_UART_0 + (offset << 2), data); + s3c24xx_uart_w( 0, offset, data, mem_mask); +} + +WRITE32_MEMBER( S3C24_CLASS_NAME::s3c24xx_uart_1_w ) +{ +// verboselog( machine(), 9, "(UART 1) %08X <- %08X\n", S3C24XX_BASE_UART_1 + (offset << 2), data); + s3c24xx_uart_w( 1, offset, data, mem_mask); +} + +#if defined(DEVICE_S3C2410) || defined(DEVICE_S3C2440) + +WRITE32_MEMBER( S3C24_CLASS_NAME::s3c24xx_uart_2_w ) +{ +// verboselog( machine(), 9, "(UART 2) %08X <- %08X\n", S3C24XX_BASE_UART_2 + (offset << 2), data); + s3c24xx_uart_w( 2, offset, data, mem_mask); +} + +#endif + +void S3C24_CLASS_NAME::s3c24xx_uart_fifo_w(int uart, UINT8 data) +{ +// printf( "s3c24xx_uart_fifo_w (%c)\n", data); + m_uart[uart].regs.urxh = data; + m_uart[uart].regs.utrstat |= 1; // [bit 0] Receive buffer data ready +} + +/* USB Device */ + +void S3C24_CLASS_NAME::s3c24xx_usb_device_reset() +{ + s3c24xx_usbdev_t *usbdev = &m_usbdev; + memset( &usbdev->regs, 0, sizeof( usbdev->regs)); + #if defined(DEVICE_S3C2400) + usbdev->regs.data[0x0C/4] = 0x033F; + usbdev->regs.data[0x14/4] = 0x000A; + usbdev->regs.data[0x24/4] = 0x0001; + usbdev->regs.data[0x44/4] = 0x0001; + usbdev->regs.data[0x54/4] = 0x0001; + usbdev->regs.data[0x64/4] = 0x0001; + usbdev->regs.data[0x74/4] = 0x0001; + usbdev->regs.data[0xB8/4] = 0x00FF; + #elif defined(DEVICE_S3C2410) || defined(DEVICE_S3C2440) + usbdev->regs.data[0x1C/4] = 0xFF; + usbdev->regs.data[0x2C/4] = 0x04; + usbdev->regs.data[0x40/4] = 0x01; + usbdev->regs.data[0x48/4] = 0x20; + #endif +} + +READ32_MEMBER( S3C24_CLASS_NAME::s3c24xx_usb_device_r ) +{ + UINT32 data = m_usbdev.regs.data[offset]; + verboselog( machine(), 9, "(USB D) %08X -> %08X\n", S3C24XX_BASE_USBDEV + (offset << 2), data); + return data; +} + +WRITE32_MEMBER( S3C24_CLASS_NAME::s3c24xx_usb_device_w ) +{ + verboselog( machine(), 9, "(USB D) %08X <- %08X\n", S3C24XX_BASE_USBDEV + (offset << 2), data); + COMBINE_DATA(&m_usbdev.regs.data[offset]); +} + +/* Watchdog Timer */ + +void S3C24_CLASS_NAME::s3c24xx_wdt_reset() +{ + s3c24xx_wdt_t *wdt = &m_wdt; + memset( &wdt->regs, 0, sizeof( wdt->regs)); + wdt->regs.wtcon = 0x8021; + wdt->regs.wtdat = 0x8000; + wdt->regs.wtcnt = 0x8000; + wdt->timer->adjust( attotime::never); +} + +#if defined(DEVICE_S3C2410) + +UINT16 S3C24_CLASS_NAME::s3c24xx_wdt_calc_current_count() +{ + double timeleft, x1, x2; + UINT32 cnt; + timeleft = m_wdt.timer->remaining( ).as_double(); +// printf( "timeleft %f freq %d cnt %d\n", timeleft, m_wdt.freq, m_wdt.cnt); + x1 = 1 / ((double)m_wdt.freq / m_wdt.cnt); + x2 = x1 / timeleft; +// printf( "x1 %f\n", x1); + cnt = m_wdt.cnt / x2; +// printf( "cnt %d\n", cnt); + return cnt; +} + +#else + +UINT16 S3C24_CLASS_NAME::s3c24xx_wdt_calc_current_count() +{ + return 0; +} + +#endif + +READ32_MEMBER( S3C24_CLASS_NAME::s3c24xx_wdt_r ) +{ + UINT32 data = ((UINT32*)&m_wdt.regs)[offset]; + switch (offset) + { + case S3C24XX_WTCNT : + { + // is wdt active? + if ((m_wdt.regs.wtcon & (1 << 5)) != 0) + { + data = s3c24xx_wdt_calc_current_count(); + } + } + break; + } + verboselog( machine(), 9, "(WDT) %08X -> %08X\n", S3C24XX_BASE_WDT + (offset << 2), data); + return data; +} + +void S3C24_CLASS_NAME::s3c24xx_wdt_start() +{ + UINT32 pclk, prescaler, clock; + double freq, hz; + verboselog( machine(), 1, "WDT start\n"); + pclk = s3c24xx_get_pclk(); + prescaler = BITS( m_wdt.regs.wtcon, 15, 8); + clock = 16 << BITS( m_wdt.regs.wtcon, 4, 3); + freq = (double)pclk / (prescaler + 1) / clock; + hz = freq / m_wdt.regs.wtcnt; + verboselog( machine(), 5, "WDT pclk %d prescaler %d clock %d freq %f hz %f\n", pclk, prescaler, clock, freq, hz); + m_wdt.timer->adjust( attotime::from_hz( hz), 0, attotime::from_hz( hz)); +#if defined(DEVICE_S3C2410) + m_wdt.freq = freq; + m_wdt.cnt = m_wdt.regs.wtcnt; +#endif +} + +void S3C24_CLASS_NAME::s3c24xx_wdt_stop() +{ + verboselog( machine(), 1, "WDT stop\n"); + m_wdt.regs.wtcnt = s3c24xx_wdt_calc_current_count(); + m_wdt.timer->adjust( attotime::never); +} + +void S3C24_CLASS_NAME::s3c24xx_wdt_recalc() +{ + if ((m_wdt.regs.wtcon & (1 << 5)) != 0) + { + s3c24xx_wdt_start(); + } + else + { + s3c24xx_wdt_stop(); + } +} + +WRITE32_MEMBER( S3C24_CLASS_NAME::s3c24xx_wdt_w ) +{ + UINT32 old_value = ((UINT32*)&m_wdt.regs)[offset]; + verboselog( machine(), 9, "(WDT) %08X <- %08X\n", S3C24XX_BASE_WDT + (offset << 2), data); + COMBINE_DATA(&((UINT32*)&m_wdt.regs)[offset]); + switch (offset) + { + case S3C24XX_WTCON : + { + if ((data & (1 << 5)) != (old_value & (1 << 5))) + { + s3c24xx_wdt_recalc(); + } + } + break; + } +} + +TIMER_CALLBACK_MEMBER( S3C24_CLASS_NAME::s3c24xx_wdt_timer_exp ) +{ + verboselog( machine(), 2, "WDT timer callback\n"); + if ((m_wdt.regs.wtcon & (1 << 2)) != 0) + { +#if defined(DEVICE_S3C2400) || defined(DEVICE_S3C2410) + s3c24xx_request_irq( S3C24XX_INT_WDT); +#else + s3c24xx_request_subirq( S3C24XX_SUBINT_WDT); +#endif + } + if ((m_wdt.regs.wtcon & (1 << 0)) != 0) + { + s3c24xx_reset(); + #if defined(DEVICE_S3C2410) || defined(DEVICE_S3C2440) + m_gpio.regs.gstatus2 = 1 << 2; // Watchdog reset + #endif + } +} + +/* IIC */ + +void S3C24_CLASS_NAME::s3c24xx_iic_reset() +{ + s3c24xx_iic_t *iic = &m_iic; + memset( &iic->regs, 0, sizeof( iic->regs)); + iic->count = 0; + iic->timer->adjust( attotime::never); +} + +void S3C24_CLASS_NAME::iface_i2c_scl_w( int state) +{ + if (!m_scl_w_cb.isnull()) + { + (m_scl_w_cb)( state); + } +} + +void S3C24_CLASS_NAME::iface_i2c_sda_w(int state) +{ + if (!m_sda_w_cb.isnull()) + { + (m_sda_w_cb)(state); + } +} + +int S3C24_CLASS_NAME::iface_i2c_sda_r() +{ + if (!m_sda_r_cb.isnull()) + { + return (m_sda_r_cb)(); + } + else + { + return 0; + } +} + +void S3C24_CLASS_NAME::i2c_send_start() +{ + verboselog( machine(), 5, "i2c_send_start\n"); + iface_i2c_sda_w( 1); + iface_i2c_scl_w( 1); + iface_i2c_sda_w( 0); + iface_i2c_scl_w( 0); +} + +void S3C24_CLASS_NAME::i2c_send_stop() +{ + verboselog( machine(), 5, "i2c_send_stop\n"); + iface_i2c_sda_w( 0); + iface_i2c_scl_w( 1); + iface_i2c_sda_w( 1); + iface_i2c_scl_w( 0); +} + +UINT8 S3C24_CLASS_NAME::i2c_receive_byte(int ack) +{ + UINT8 data = 0; + verboselog( machine(), 5, "i2c_receive_byte ...\n"); + iface_i2c_sda_w( 1); + for (int i = 0; i < 8; i++) + { + iface_i2c_scl_w( 1); + data = (data << 1) + (iface_i2c_sda_r() ? 1 : 0); + iface_i2c_scl_w( 0); + } + verboselog( machine(), 5, "recv data %02X\n", data); + verboselog( machine(), 5, "send ack %d\n", ack); + iface_i2c_sda_w( ack ? 0 : 1); + iface_i2c_scl_w( 1); + iface_i2c_scl_w( 0); + return data; +} + +int S3C24_CLASS_NAME::i2c_send_byte(UINT8 data) +{ + int ack; + verboselog( machine(), 5, "i2c_send_byte ...\n"); + verboselog( machine(), 5, "send data %02X\n", data); + for (int i = 0; i < 8; i++) + { + iface_i2c_sda_w( (data & 0x80) ? 1 : 0); + data = data << 1; + iface_i2c_scl_w( 1); + iface_i2c_scl_w( 0); + } + iface_i2c_sda_w( 1); // ack bit + iface_i2c_scl_w( 1); + ack = iface_i2c_sda_r(); + verboselog( machine(), 5, "recv ack %d\n", ack); + iface_i2c_scl_w( 0); + return ack; +} + +void S3C24_CLASS_NAME::iic_start() +{ + int mode_selection; + verboselog( machine(), 1, "IIC start\n"); + i2c_send_start(); + mode_selection = BITS( m_iic.regs.iicstat, 7, 6); + switch (mode_selection) + { + case 2 : i2c_send_byte( m_iic.regs.iicds | 0x01); break; + case 3 : i2c_send_byte( m_iic.regs.iicds & 0xFE); break; + } + m_iic.timer->adjust( attotime::from_usec( 1)); +} + +void S3C24_CLASS_NAME::iic_stop() +{ + verboselog( machine(), 1, "IIC stop\n"); + i2c_send_stop(); + m_iic.timer->adjust( attotime::never); +} + +void S3C24_CLASS_NAME::iic_resume() +{ + int mode_selection; + verboselog(machine(), 1, "IIC resume\n"); + mode_selection = BITS( m_iic.regs.iicstat, 7, 6); + switch (mode_selection) + { + case 2 : m_iic.regs.iicds = i2c_receive_byte( BIT( m_iic.regs.iiccon, 7)); break; + case 3 : i2c_send_byte( m_iic.regs.iicds & 0xFF); break; + } + m_iic.timer->adjust( attotime::from_usec( 1)); +} + +READ32_MEMBER( S3C24_CLASS_NAME::s3c24xx_iic_r ) +{ + UINT32 data = ((UINT32*)&m_iic.regs)[offset]; + switch (offset) + { + case S3C24XX_IICSTAT : + { + data = data & ~0x0000000F; + } + break; + } + verboselog( machine(), 9, "(IIC) %08X -> %08X\n", S3C24XX_BASE_IIC + (offset << 2), data); + return data; +} + +WRITE32_MEMBER( S3C24_CLASS_NAME::s3c24xx_iic_w ) +{ + UINT32 old_value = ((UINT32*)&m_iic.regs)[offset]; + verboselog( machine(), 9, "(IIC) %08X <- %08X\n", S3C24XX_BASE_IIC + (offset << 2), data); + COMBINE_DATA(&((UINT32*)&m_iic.regs)[offset]); + switch (offset) + { + case S3C24XX_IICCON : + { + int interrupt_pending_flag; +#if 0 + const int div_table[] = { 16, 512}; + int enable_interrupt, transmit_clock_value, tx_clock_source_selection + double clock; + transmit_clock_value = (data >> 0) & 0xF; + tx_clock_source_selection = (data >> 6) & 1; + enable_interrupt = (data >> 5) & 1; + clock = (double)s3c24xx_get_pclk() / div_table[tx_clock_source_selection] / (transmit_clock_value + 1); +#endif + interrupt_pending_flag = BIT( old_value, 4); + if (interrupt_pending_flag != 0) + { + interrupt_pending_flag = BIT( data, 4); + if (interrupt_pending_flag == 0) + { + int start_stop_condition; + start_stop_condition = BIT( m_iic.regs.iicstat, 5); + if (start_stop_condition != 0) + { + if (m_iic.count == 0) + { + iic_start(); + + } + else + { + iic_resume(); + } + } + else + { + iic_stop(); + } + } + } + } + break; + case S3C24XX_IICSTAT : + { + int interrupt_pending_flag; + m_iic.count = 0; + interrupt_pending_flag = BIT( m_iic.regs.iiccon, 4); + if (interrupt_pending_flag == 0) + { + int start_stop_condition; + start_stop_condition = BIT( data, 5); + if (start_stop_condition != 0) + { + if (m_iic.count == 0) + { + iic_start(); + + } + else + { + iic_resume(); + } + } + else + { + iic_stop(); + } + } + } + break; + } +} + +TIMER_CALLBACK_MEMBER( S3C24_CLASS_NAME::s3c24xx_iic_timer_exp ) +{ + int enable_interrupt; + verboselog( machine(), 2, "IIC timer callback\n"); + m_iic.count++; + enable_interrupt = BIT( m_iic.regs.iiccon, 5); + if (enable_interrupt) + { + m_iic.regs.iiccon |= (1 << 4); // [bit 4] interrupt is pending + s3c24xx_request_irq(S3C24XX_INT_IIC); + } +} + +/* IIS */ + +void S3C24_CLASS_NAME::s3c24xx_iis_reset() +{ + s3c24xx_iis_t *iis = &m_iis; + memset( &iis->regs, 0, sizeof( iis->regs)); + iis->fifo_index = 0; + iis->regs.iiscon = 0x0100; + iis->timer->adjust( attotime::never); +} + +void S3C24_CLASS_NAME::iface_i2s_data_w(int ch, UINT16 data) +{ + if (!m_data_w_cb.isnull()) + { + (m_data_w_cb)( ch, data, 0); + } +} + +void S3C24_CLASS_NAME::s3c24xx_iis_start() +{ + const UINT32 codeclk_table[] = { 256, 384}; + double freq; + int pclk, prescaler_enable, prescaler_control_a, prescaler_control_b, codeclk; + verboselog( machine(), 1, "IIS start\n"); + prescaler_enable = BIT( m_iis.regs.iiscon, 1); + prescaler_control_a = BITS( m_iis.regs.iispsr, 9, 5); + prescaler_control_b = BITS( m_iis.regs.iispsr, 4, 0); + codeclk = BIT( m_iis.regs.iismod, 2); + pclk = s3c24xx_get_pclk(); + freq = ((double)pclk / (prescaler_control_a + 1) / codeclk_table[codeclk]) * 2; // why do I have to multiply by two? + verboselog( machine(), 5, "IIS - pclk %d psc_enable %d psc_a %d psc_b %d codeclk %d freq %f\n", pclk, prescaler_enable, prescaler_control_a, prescaler_control_b, codeclk_table[codeclk], freq); + m_iis.timer->adjust( attotime::from_hz( freq), 0, attotime::from_hz( freq)); +} + +void S3C24_CLASS_NAME::s3c24xx_iis_stop() +{ + verboselog( machine(), 1, "IIS stop\n"); + m_iis.timer->adjust( attotime::never); +} + +void S3C24_CLASS_NAME::s3c24xx_iis_recalc() +{ + if ((m_iis.regs.iiscon & (1 << 0)) != 0) + { + s3c24xx_iis_start(); + } + else + { + s3c24xx_iis_stop(); + } +} + +READ32_MEMBER( S3C24_CLASS_NAME::s3c24xx_iis_r ) +{ + UINT32 data = ((UINT32*)&m_iis.regs)[offset]; +#if 0 + switch (offset) + { + case S3C24XX_IISCON : + { + data = data & ~1; // hack for mp3 player + } + break; + } +#endif + verboselog( machine(), 9, "(IIS) %08X -> %08X\n", S3C24XX_BASE_IIS + (offset << 2), data); + return data; +} + +WRITE32_MEMBER( S3C24_CLASS_NAME::s3c24xx_iis_w ) +{ + UINT32 old_value = ((UINT32*)&m_iis.regs)[offset]; + verboselog( machine(), 9, "(IIS) %08X <- %08X\n", S3C24XX_BASE_IIS + (offset << 2), data); + COMBINE_DATA(&((UINT32*)&m_iis.regs)[offset]); + switch (offset) + { + case S3C24XX_IISCON : + { + if ((old_value & (1 << 0)) != (data & (1 << 0))) + { + s3c24xx_iis_recalc(); + } + } + break; + case S3C24XX_IISFIFO : + { + if (ACCESSING_BITS_16_31) + { + m_iis.fifo[m_iis.fifo_index++] = BITS( data, 31, 16); + } + if (ACCESSING_BITS_0_15) + { + m_iis.fifo[m_iis.fifo_index++] = BITS( data, 15, 0); + } + if (m_iis.fifo_index == 2) + { + m_iis.fifo_index = 0; + iface_i2s_data_w( 0, m_iis.fifo[0]); + iface_i2s_data_w( 1, m_iis.fifo[1]); + } + } + break; + } +} + +TIMER_CALLBACK_MEMBER( S3C24_CLASS_NAME::s3c24xx_iis_timer_exp ) +{ + verboselog( machine(), 2, "IIS timer callback\n"); + s3c24xx_dma_request_iis(); +} + +/* RTC */ + +void S3C24_CLASS_NAME::s3c24xx_rtc_reset() +{ + s3c24xx_rtc_t *rtc = &m_rtc; + memset( &rtc->regs, 0, sizeof( rtc->regs)); + rtc->regs.almday = 1; + rtc->regs.almmon = 1; + rtc->timer_update->adjust( attotime::never); + rtc->timer_update->adjust( attotime::from_msec( 1000), 0, attotime::from_msec( 1000)); +} + +READ32_MEMBER( S3C24_CLASS_NAME::s3c24xx_rtc_r ) +{ + UINT32 data = ((UINT32*)&m_rtc.regs)[offset]; + verboselog( machine(), 9, "(RTC) %08X -> %08X\n", S3C24XX_BASE_RTC + (offset << 2), data); + return data; +} + +void S3C24_CLASS_NAME::s3c24xx_rtc_recalc() +{ + if (m_rtc.regs.ticnt & (1 << 7)) + { + UINT32 ttc; + double freq; + ttc = BITS( m_rtc.regs.ticnt, 6, 0); + freq = 128 / (ttc + 1); +// printf( "ttc %d freq %f\n", ttc, freq); + m_rtc.timer_tick_count->adjust( attotime::from_hz( freq), 0, attotime::from_hz( freq)); + } + else + { + m_rtc.timer_tick_count->adjust( attotime::never); + } +} + +WRITE32_MEMBER( S3C24_CLASS_NAME::s3c24xx_rtc_w ) +{ + verboselog( machine(), 9, "(RTC) %08X <- %08X\n", S3C24XX_BASE_RTC + (offset << 2), data); + COMBINE_DATA(&((UINT32*)&m_rtc.regs)[offset]); + switch (offset) + { + case S3C24XX_TICNT : + { + s3c24xx_rtc_recalc(); + } + break; + } +} + +TIMER_CALLBACK_MEMBER( S3C24_CLASS_NAME::s3c24xx_rtc_timer_tick_count_exp ) +{ + verboselog( machine(), 2, "RTC timer callback (tick count)\n"); + s3c24xx_request_irq( S3C24XX_INT_TICK); +} + +void S3C24_CLASS_NAME::s3c24xx_rtc_update() +{ + UINT32 bcdday_max; + // increase second + m_rtc.regs.bcdsec = bcd_adjust( m_rtc.regs.bcdsec + 1); + if (m_rtc.regs.bcdsec >= 0x60) + { + m_rtc.regs.bcdsec = 0; + // increase minute + m_rtc.regs.bcdmin = bcd_adjust( m_rtc.regs.bcdmin + 1); + if (m_rtc.regs.bcdmin >= 0x60) + { + m_rtc.regs.bcdmin = 0; + // increase hour + m_rtc.regs.bcdhour = bcd_adjust( m_rtc.regs.bcdhour + 1); + if (m_rtc.regs.bcdhour >= 0x24) + { + m_rtc.regs.bcdhour = 0; + // increase day-of-week + m_rtc.regs.bcddow = (m_rtc.regs.bcddow % 7) + 1; + // increase day + m_rtc.regs.bcdday = bcd_adjust( m_rtc.regs.bcdday + 1); + bcdday_max = dec_2_bcd( gregorian_days_in_month( bcd_2_dec( m_rtc.regs.bcdmon), bcd_2_dec( m_rtc.regs.bcdyear) + 2000)); + if (m_rtc.regs.bcdday > bcdday_max) + { + m_rtc.regs.bcdday = 1; + // increase month + m_rtc.regs.bcdmon = bcd_adjust( m_rtc.regs.bcdmon + 1); + if (m_rtc.regs.bcdmon >= 0x12) + { + m_rtc.regs.bcdmon = 1; + // increase year + m_rtc.regs.bcdyear = bcd_adjust( m_rtc.regs.bcdyear + 1); + if (m_rtc.regs.bcdyear >= 0x100) + { + m_rtc.regs.bcdyear = 0; + } + } + } + } + } + } + verboselog( machine(), 5, "RTC - %04d/%02d/%02d %02d:%02d:%02d\n", bcd_2_dec( m_rtc.regs.bcdyear) + 2000, bcd_2_dec( m_rtc.regs.bcdmon), bcd_2_dec( m_rtc.regs.bcdday), bcd_2_dec( m_rtc.regs.bcdhour), bcd_2_dec( m_rtc.regs.bcdmin), bcd_2_dec( m_rtc.regs.bcdsec)); +} + +void S3C24_CLASS_NAME::s3c24xx_rtc_check_alarm() +{ + if (m_rtc.regs.rtcalm & 0x40) + { + int isalarm = 1; + isalarm = isalarm && (((m_rtc.regs.rtcalm & 0x20) == 0) || (m_rtc.regs.almyear == m_rtc.regs.bcdyear)); + isalarm = isalarm && (((m_rtc.regs.rtcalm & 0x10) == 0) || (m_rtc.regs.almmon == m_rtc.regs.bcdmon)); + isalarm = isalarm && (((m_rtc.regs.rtcalm & 0x08) == 0) || (m_rtc.regs.almday == m_rtc.regs.bcdday)); + isalarm = isalarm && (((m_rtc.regs.rtcalm & 0x04) == 0) || (m_rtc.regs.almhour == m_rtc.regs.bcdhour)); + isalarm = isalarm && (((m_rtc.regs.rtcalm & 0x02) == 0) || (m_rtc.regs.almmin == m_rtc.regs.bcdmin)); + isalarm = isalarm && (((m_rtc.regs.rtcalm & 0x01) == 0) || (m_rtc.regs.almsec == m_rtc.regs.bcdsec)); + if (isalarm != 0) + { + s3c24xx_request_irq(S3C24XX_INT_RTC); + } + } +} + +TIMER_CALLBACK_MEMBER( S3C24_CLASS_NAME::s3c24xx_rtc_timer_update_exp ) +{ + verboselog( machine(), 2, "RTC timer callback (update)\n"); + s3c24xx_rtc_update(); + s3c24xx_rtc_check_alarm(); +} + +/* A/D Converter */ + +void S3C24_CLASS_NAME::s3c24xx_adc_reset() +{ + s3c24xx_adc_t *adc = &m_adc; + memset( &adc->regs, 0, sizeof( adc->regs)); + adc->regs.adccon = 0x3FC4; + #if defined(DEVICE_S3C2410) || defined(DEVICE_S3C2440) + adc->regs.adctsc = 0x58; + adc->regs.adcdly = 0xFF; + #endif +} + +UINT32 S3C24_CLASS_NAME::iface_adc_data_r(int ch) +{ + if (!m_data_r_cb.isnull()) + { + int offs = ch; + #if defined(DEVICE_S3C2410) || defined(DEVICE_S3C2440) + if (BIT( m_adc.regs.adctsc, 2) != 0) + { + offs += 2; + } + #endif + return (m_data_r_cb)(offs, 0); + } + else + { + return 0; + } +} + +READ32_MEMBER( S3C24_CLASS_NAME::s3c24xx_adc_r ) +{ + UINT32 data = ((UINT32*)&m_adc.regs)[offset]; + switch (offset) + { +#if defined(DEVICE_S3C2400) + case S3C24XX_ADCDAT : + { + data = (data & ~0x3FF) | (iface_adc_data_r( 0) & 0x3FF); + } + break; +#else + case S3C24XX_ADCDAT0 : + { + data = (data & ~0x3FF) | (iface_adc_data_r( 0) & 0x3FF); + } + break; + case S3C24XX_ADCDAT1 : + { + data = (data & ~0x3FF) | (iface_adc_data_r( 1) & 0x3FF); + } + break; +#endif + } + verboselog( machine(), 9, "(ADC) %08X -> %08X\n", S3C24XX_BASE_ADC + (offset << 2), data); + return data; +} + +void S3C24_CLASS_NAME::s3c24xx_adc_start() +{ + verboselog( machine(), 1, "ADC start\n"); + m_adc.regs.adccon &= ~(1 << 0); // A/D conversion is completed + m_adc.regs.adccon |= (1 << 15); // End of A/D conversion + #if defined(DEVICE_S3C2410) || defined(DEVICE_S3C2440) + s3c24xx_request_subirq( S3C24XX_SUBINT_ADC); + #endif +} + +WRITE32_MEMBER( S3C24_CLASS_NAME::s3c24xx_adc_w ) +{ + UINT32 old_value = ((UINT32*)&m_adc.regs)[offset]; + verboselog( machine(), 9, "(ADC) %08X <- %08X\n", S3C24XX_BASE_ADC + (offset << 2), data); + COMBINE_DATA(&((UINT32*)&m_adc.regs)[offset]); + switch (offset) + { + case S3C24XX_ADCCON : + { + if (((old_value & (1 << 0)) == 0) && ((data & (1 << 0)) != 0)) + { + s3c24xx_adc_start(); + } + } + break; + } +} + +#if defined(DEVICE_S3C2410) || defined(DEVICE_S3C2440) + +void S3C24_CLASS_NAME::s3c24xx_touch_screen(int state) +{ + m_adc.regs.adcdat0 = ((state ? 0 : 1) << 15); + m_adc.regs.adcdat1 = ((state ? 0 : 1) << 15); + s3c24xx_request_subirq( S3C24XX_SUBINT_TC); +} + +#endif + +/* SPI */ + +void S3C24_CLASS_NAME::s3c24xx_spi_reset() +{ + for (int i = 0; i < S3C24XX_SPI_COUNT; i++) + { + s3c24xx_spi_t *spi = &m_spi[i]; + memset( &spi->regs, 0, sizeof( spi->regs)); + spi->regs.spsta = 1; + #if defined(DEVICE_S3C2400) || defined(DEVICE_S3C2410) + spi->regs.sppin = 2; + #endif + } +} + +UINT32 S3C24_CLASS_NAME::s3c24xx_spi_r(UINT32 ch, UINT32 offset) +{ + UINT32 data = ((UINT32*)&m_spi[ch].regs)[offset]; + switch (offset) + { + case S3C24XX_SPSTA : + { + data = data | (1 << 0); // [bit 0] Transfer Ready Flag + } + break; + } + return data; +} + +void S3C24_CLASS_NAME::s3c24xx_spi_w(UINT32 ch, UINT32 offset, UINT32 data, UINT32 mem_mask) +{ + COMBINE_DATA(&((UINT32*)&m_spi[ch].regs)[offset]); +} + +READ32_MEMBER( S3C24_CLASS_NAME::s3c24xx_spi_0_r ) +{ + UINT32 data = s3c24xx_spi_r( 0, offset); + verboselog( machine(), 9, "(SPI 0) %08X -> %08X\n", S3C24XX_BASE_SPI_0 + (offset << 2), data); + return data; +} + +#if defined(DEVICE_S3C2410) || defined(DEVICE_S3C2440) + +READ32_MEMBER( S3C24_CLASS_NAME::s3c24xx_spi_1_r ) +{ + UINT32 data = s3c24xx_spi_r( 1, offset); + verboselog( machine(), 9, "(SPI 1) %08X -> %08X\n", S3C24XX_BASE_SPI_1 + (offset << 2), data); + return data; +} + +#endif + +WRITE32_MEMBER( S3C24_CLASS_NAME::s3c24xx_spi_0_w ) +{ + verboselog( machine(), 9, "(SPI 0) %08X <- %08X\n", S3C24XX_BASE_SPI_0 + (offset << 2), data); + s3c24xx_spi_w( 0, offset, data, mem_mask); +} + +#if defined(DEVICE_S3C2410) || defined(DEVICE_S3C2440) + +WRITE32_MEMBER( S3C24_CLASS_NAME::s3c24xx_spi_1_w ) +{ + verboselog( machine(), 9, "(SPI 1) %08X <- %08X\n", S3C24XX_BASE_SPI_1 + (offset << 2), data); + s3c24xx_spi_w( 1, offset, data, mem_mask); +} + +#endif + +/* MMC Interface */ + +#if defined(DEVICE_S3C2400) + +void S3C24_CLASS_NAME::s3c24xx_mmc_reset() +{ + s3c24xx_mmc_t *mmc = &m_mmc; + memset( &mmc->regs, 0, sizeof( mmc->regs)); +} + +READ32_MEMBER( S3C24_CLASS_NAME::s3c24xx_mmc_r ) +{ + UINT32 data = m_mmc.regs.data[offset]; + verboselog( machine(), 9, "(MMC) %08X -> %08X\n", S3C24XX_BASE_MMC + (offset << 2), data); + return data; +} + +WRITE32_MEMBER( S3C24_CLASS_NAME::s3c24xx_mmc_w ) +{ + verboselog( machine(), 9, "(MMC) %08X <- %08X\n", S3C24XX_BASE_MMC + (offset << 2), data); + COMBINE_DATA(&m_mmc.regs.data[offset]); +} + +#endif + +/* SD Interface */ + +#if defined(DEVICE_S3C2410) || defined(DEVICE_S3C2440) + +void S3C24_CLASS_NAME::s3c24xx_sdi_reset() +{ + s3c24xx_sdi_t *sdi = &m_sdi; + memset( &sdi->regs, 0, sizeof( sdi->regs)); + #if defined(DEVICE_S3C2410) + sdi->regs.data[0x24/4] = 0x2000; + #elif defined(DEVICE_S3C2440) + sdi->regs.data[0x04/4] = 1; + sdi->regs.data[0x24/4] = 0x10000; + #endif +} + +READ32_MEMBER( S3C24_CLASS_NAME::s3c24xx_sdi_r ) +{ + UINT32 data = m_sdi.regs.data[offset]; + verboselog( machine(), 9, "(SDI) %08X -> %08X\n", S3C24XX_BASE_SDI + (offset << 2), data); + return data; +} + +WRITE32_MEMBER( S3C24_CLASS_NAME::s3c24xx_sdi_w ) +{ + verboselog( machine(), 9, "(SDI) %08X <- %08X\n", S3C24XX_BASE_SDI + (offset << 2), data); + COMBINE_DATA(&m_sdi.regs.data[offset]); +} + +#endif + +/* NAND Flash */ + +#if defined(DEVICE_S3C2410) || defined(DEVICE_S3C2440) + +void S3C24_CLASS_NAME::s3c24xx_nand_reset() +{ + s3c24xx_nand_t *nand = &m_nand; + memset( &nand->regs, 0, sizeof( nand->regs)); + #if defined(DEVICE_S3C2440) + nand->regs.nfconf = 0x1000; + nand->regs.nfcont = 0x0384; + #endif +} + +void S3C24_CLASS_NAME::iface_nand_command_w(UINT8 data) +{ + if (!m_command_w_cb.isnull()) + { + (m_command_w_cb)( 0, data, 0xff); + } +} + +void S3C24_CLASS_NAME::iface_nand_address_w(UINT8 data) +{ + if (!m_address_w_cb.isnull()) + { + (m_address_w_cb)( 0, data, 0xff); + } +} + +UINT8 S3C24_CLASS_NAME::iface_nand_data_r() +{ + if (!m_nand_data_r_cb.isnull()) + { + return (m_nand_data_r_cb)( 0, 0xff); + } + else + { + return 0; + } +} + +void S3C24_CLASS_NAME::iface_nand_data_w(UINT8 data) +{ + if (!m_nand_data_w_cb.isnull()) + { + (m_nand_data_w_cb)(0, data, 0xff); + } +} + +void S3C24_CLASS_NAME::nand_update_mecc( UINT8 *ecc, int pos, UINT8 data) +{ + int bit[8]; + UINT8 temp; + bit[0] = (data >> 0) & 1; + bit[1] = (data >> 1) & 1; + bit[2] = (data >> 2) & 1; + bit[3] = (data >> 3) & 1; + bit[4] = (data >> 4) & 1; + bit[5] = (data >> 5) & 1; + bit[6] = (data >> 6) & 1; + bit[7] = (data >> 7) & 1; + // column parity + ecc[2] ^= ((bit[6] ^ bit[4] ^ bit[2] ^ bit[0]) << 2); + ecc[2] ^= ((bit[7] ^ bit[5] ^ bit[3] ^ bit[1]) << 3); + ecc[2] ^= ((bit[5] ^ bit[4] ^ bit[1] ^ bit[0]) << 4); + ecc[2] ^= ((bit[7] ^ bit[6] ^ bit[3] ^ bit[2]) << 5); + ecc[2] ^= ((bit[3] ^ bit[2] ^ bit[1] ^ bit[0]) << 6); + ecc[2] ^= ((bit[7] ^ bit[6] ^ bit[5] ^ bit[4]) << 7); + // line parity + temp = bit[7] ^ bit[6] ^ bit[5] ^ bit[4] ^ bit[3] ^ bit[2] ^ bit[1] ^ bit[0]; + if (pos & 0x001) ecc[0] ^= (temp << 1); else ecc[0] ^= (temp << 0); + if (pos & 0x002) ecc[0] ^= (temp << 3); else ecc[0] ^= (temp << 2); + if (pos & 0x004) ecc[0] ^= (temp << 5); else ecc[0] ^= (temp << 4); + if (pos & 0x008) ecc[0] ^= (temp << 7); else ecc[0] ^= (temp << 6); + if (pos & 0x010) ecc[1] ^= (temp << 1); else ecc[1] ^= (temp << 0); + if (pos & 0x020) ecc[1] ^= (temp << 3); else ecc[1] ^= (temp << 2); + if (pos & 0x040) ecc[1] ^= (temp << 5); else ecc[1] ^= (temp << 4); + if (pos & 0x080) ecc[1] ^= (temp << 7); else ecc[1] ^= (temp << 6); + if (pos & 0x100) ecc[2] ^= (temp << 1); else ecc[2] ^= (temp << 0); + if (pos & 0x200) ecc[3] ^= (temp << 5); else ecc[3] ^= (temp << 4); + if (pos & 0x400) ecc[3] ^= (temp << 7); else ecc[3] ^= (temp << 6); +} + +#if defined(DEVICE_S3C2440) + +void S3C24_CLASS_NAME::nand_update_secc( UINT8 *ecc, int pos, UINT8 data) +{ + int bit[8]; + UINT8 temp; + bit[0] = (data >> 0) & 1; + bit[1] = (data >> 1) & 1; + bit[2] = (data >> 2) & 1; + bit[3] = (data >> 3) & 1; + bit[4] = (data >> 4) & 1; + bit[5] = (data >> 5) & 1; + bit[6] = (data >> 6) & 1; + bit[7] = (data >> 7) & 1; + // column parity + ecc[1] ^= ((bit[6] ^ bit[4] ^ bit[2] ^ bit[0]) << 6); + ecc[1] ^= ((bit[7] ^ bit[5] ^ bit[3] ^ bit[1]) << 7); + ecc[0] ^= ((bit[5] ^ bit[4] ^ bit[1] ^ bit[0]) << 0); + ecc[0] ^= ((bit[7] ^ bit[6] ^ bit[3] ^ bit[2]) << 1); + ecc[0] ^= ((bit[3] ^ bit[2] ^ bit[1] ^ bit[0]) << 2); + ecc[0] ^= ((bit[7] ^ bit[6] ^ bit[5] ^ bit[4]) << 3); + // line parity + temp = bit[7] ^ bit[6] ^ bit[5] ^ bit[4] ^ bit[3] ^ bit[2] ^ bit[1] ^ bit[0]; + if (pos & 0x001) ecc[0] ^= (temp << 5); else ecc[0] ^= (temp << 4); + if (pos & 0x002) ecc[0] ^= (temp << 7); else ecc[0] ^= (temp << 6); + if (pos & 0x004) ecc[1] ^= (temp << 3); else ecc[1] ^= (temp << 2); + if (pos & 0x008) ecc[1] ^= (temp << 5); else ecc[1] ^= (temp << 4); +} + +#endif + +void S3C24_CLASS_NAME::s3c24xx_nand_update_ecc(UINT8 data) +{ + s3c24xx_nand_t *nand = &m_nand; + UINT8 temp[4]; +#if defined(DEVICE_S3C2410) + temp[0] = nand->mecc[0]; + temp[1] = nand->mecc[1]; + temp[2] = nand->mecc[2]; + nand_update_mecc( nand->mecc, nand->ecc_pos++, data); + verboselog( machine(), 5, "NAND - MECC %03X - %02X %02X %02X -> %02X %02X %02X\n", nand->ecc_pos - 1, temp[0], temp[1], temp[2], nand->mecc[0], nand->mecc[1], nand->mecc[2]); + if (nand->ecc_pos == 512) nand->ecc_pos = 0; +#else + if ((nand->regs.nfcont & (1 << 5)) == 0) + { + temp[0] = nand->mecc[0]; + temp[1] = nand->mecc[1]; + temp[2] = nand->mecc[2]; + temp[3] = nand->mecc[3]; + nand_update_mecc( nand->mecc, nand->ecc_pos++, data); + verboselog( machine(), 5, "NAND - MECC %03X - %02X %02X %02X %02X -> %02X %02X %02X %02X\n", nand->ecc_pos - 1, temp[0], temp[1], temp[2], temp[3], nand->mecc[0], nand->mecc[1], nand->mecc[2], nand->mecc[3]); + if (nand->ecc_pos == 2048) nand->ecc_pos = 0; + } + if ((nand->regs.nfcont & (1 << 6)) == 0) + { + temp[0] = nand->secc[0]; + temp[1] = nand->secc[1]; + nand_update_secc( nand->secc, nand->ecc_pos++, data); + verboselog( machine(), 5, "NAND - SECC %02X - %02X %02X -> %02X %02X\n", nand->ecc_pos - 1, temp[0], temp[1], nand->secc[0], nand->secc[1]); + if (nand->ecc_pos == 16) nand->ecc_pos = 0; + } +#endif +} + +void S3C24_CLASS_NAME::s3c24xx_nand_command_w(UINT8 data) +{ + verboselog( machine(), 5, "NAND write command %02X\n", data); + m_nand.data_count = 0; + iface_nand_command_w( data); +} + +void S3C24_CLASS_NAME::s3c24xx_nand_address_w(UINT8 data) +{ + verboselog( machine(), 5, "NAND write address %02X\n", data); + m_nand.data_count = 0; + iface_nand_address_w( data); +} + +UINT8 S3C24_CLASS_NAME::s3c24xx_nand_data_r() +{ + UINT8 data = iface_nand_data_r(); + verboselog( machine(), 5, "NAND read data %02X [%04X]\n", data, m_nand.data_count++); + s3c24xx_nand_update_ecc( data); + return data; +} + +void S3C24_CLASS_NAME::s3c24xx_nand_data_w(UINT8 data) +{ + verboselog( machine(), 5, "NAND write data %02X [%04X]\n", data, m_nand.data_count++); + iface_nand_data_w( data); + s3c24xx_nand_update_ecc( data); +} + +READ32_MEMBER( S3C24_CLASS_NAME::s3c24xx_nand_r ) +{ + UINT32 data = ((UINT32*)&m_nand.regs)[offset]; + switch (offset) + { + case S3C24XX_NFDATA : + { + data = 0; + #if defined(DEVICE_S3C2410) + data = data | s3c24xx_nand_data_r(); + #elif defined(DEVICE_S3C2440) + if ((mem_mask & 0x000000FF) != 0) data = data | (s3c24xx_nand_data_r() << 0); + if ((mem_mask & 0x0000FF00) != 0) data = data | (s3c24xx_nand_data_r() << 8); + if ((mem_mask & 0x00FF0000) != 0) data = data | (s3c24xx_nand_data_r() << 16); + if ((mem_mask & 0xFF000000) != 0) data = data | (s3c24xx_nand_data_r() << 24); + #endif + } + break; +#if defined(DEVICE_S3C2410) + case S3C24XX_NFECC : + { + data = ((m_nand.mecc[2] << 16) | (m_nand.mecc[1] << 8) | (m_nand.mecc[0] << 0)); + } + break; +#endif +#if defined(DEVICE_S3C2440) + case S3C24XX_NFMECC0 : + { + data = (m_nand.mecc[3] << 24) | (m_nand.mecc[2] << 16) | (m_nand.mecc[1] << 8) | (m_nand.mecc[0] << 0); + } + break; + case S3C24XX_NFSECC : + { + data = (m_nand.secc[1] << 8) | (m_nand.secc[0] << 0); + } + break; + case S3C24XX_NFESTAT0 : + { + data &= ~0x000000F; // no main/spare ECC errors + } + break; + case S3C24XX_NFESTAT1 : + { + data &= ~0x000000F; // no main/spare ECC errors + } + break; +#endif + } + verboselog( machine(), 9, "(NAND) %08X -> %08X (%08X)\n", S3C24XX_BASE_NAND + (offset << 2), data, mem_mask); + return data; +} + +void S3C24_CLASS_NAME::s3c24xx_nand_init_ecc() +{ + verboselog( machine(), 5, "NAND - init ecc\n"); + m_nand.mecc[0] = 0xFF; + m_nand.mecc[1] = 0xFF; + m_nand.mecc[2] = 0xFF; + #if defined(DEVICE_S3C2440) + m_nand.mecc[3] = 0xFF; + m_nand.secc[0] = 0; + m_nand.secc[1] = 0; + #endif + m_nand.ecc_pos = 0; +} + +WRITE32_MEMBER( S3C24_CLASS_NAME::s3c24xx_nand_w ) +{ + UINT32 old_value = ((UINT32*)&m_nand.regs)[offset]; + verboselog( machine(), 9, "(NAND) %08X <- %08X (%08X)\n", S3C24XX_BASE_NAND + (offset << 2), data, mem_mask); + COMBINE_DATA(&((UINT32*)&m_nand.regs)[offset]); + switch (offset) + { +#if defined(DEVICE_S3C2410) + case S3C24XX_NFCONF : + { + if ((data & (1 << 12)) != 0) + { + s3c24xx_nand_init_ecc(); + } + } + break; +#endif +#if defined(DEVICE_S3C2440) + case S3C24XX_NFCONT : + { + if ((data & (1 << 4)) != 0) + { + s3c24xx_nand_init_ecc(); + } + } + break; +#endif + case S3C24XX_NFSTAT : + { + m_nand.regs.nfstat = (m_nand.regs.nfstat & ~0x03) | (old_value & 0x03); // read-only +#if defined(DEVICE_S3C2440) + if ((data & (1 << 2)) != 0) + { + m_nand.regs.nfstat &= ~(1 << 2); // "RnB_TransDetect, to clear this value write 1" + } +#endif + } + break; + case S3C24XX_NFCMD : + { + s3c24xx_nand_command_w(data); + } + break; + case S3C24XX_NFADDR : + { + s3c24xx_nand_address_w(data); + } + break; + case S3C24XX_NFDATA : + { + #if defined(DEVICE_S3C2410) + s3c24xx_nand_data_w(data & 0xFF); + #elif defined(DEVICE_S3C2440) + if ((mem_mask & 0x000000FF) != 0) s3c24xx_nand_data_w((data >> 0) & 0xFF); + if ((mem_mask & 0x0000FF00) != 0) s3c24xx_nand_data_w((data >> 8) & 0xFF); + if ((mem_mask & 0x00FF0000) != 0) s3c24xx_nand_data_w((data >> 16) & 0xFF); + if ((mem_mask & 0xFF000000) != 0) s3c24xx_nand_data_w((data >> 24) & 0xFF); + #endif + } + break; + } +} + +ATTR_UNUSED WRITE_LINE_MEMBER( S3C24_CLASS_NAME::s3c24xx_pin_frnb_w ) +{ + verboselog( machine(), 9, "s3c24xx_pin_frnb_w (%d)\n", state); +#if defined(DEVICE_S3C2440) + if ((BIT( m_nand.regs.nfstat, 0) == 0) && (state != 0)) + { + m_nand.regs.nfstat |= (1 << 2); + if (BIT( m_nand.regs.nfcont, 9) != 0) + { + s3c24xx_request_irq( S3C24XX_INT_NFCON); + } + } +#endif + if (state == 0) + { + m_nand.regs.nfstat &= ~(1 << 0); + } + else + { + m_nand.regs.nfstat |= (1 << 0); + } +} + +#endif + +/* Camera Interface */ + +#if defined(DEVICE_S3C2440) + +void S3C24_CLASS_NAME::s3c24xx_cam_reset() +{ + s3c24xx_cam_t *cam = &m_cam; + memset( &cam->regs, 0, sizeof( cam->regs)); +} + +READ32_MEMBER( S3C24_CLASS_NAME::s3c24xx_cam_r ) +{ + UINT32 data = m_cam.regs.data[offset]; + verboselog( machine(), 9, "(CAM) %08X -> %08X\n", S3C24XX_BASE_CAM + (offset << 2), data); + return data; +} + +WRITE32_MEMBER( S3C24_CLASS_NAME::s3c24xx_cam_w ) +{ + verboselog( machine(), 9, "(CAM) %08X <- %08X\n", S3C24XX_BASE_CAM + (offset << 2), data); + COMBINE_DATA(&m_cam.regs.data[offset]); +} + +#endif + +/* AC97 Interface */ + +#if defined(DEVICE_S3C2440) + +void S3C24_CLASS_NAME::s3c24xx_ac97_reset() +{ + s3c24xx_ac97_t *ac97 = &m_ac97; + memset( &ac97->regs, 0, sizeof( ac97->regs)); +} + +READ32_MEMBER( S3C24_CLASS_NAME::s3c24xx_ac97_r ) +{ + UINT32 data = m_ac97.regs.data[offset]; + verboselog( machine(), 9, "(AC97) %08X -> %08X\n", S3C24XX_BASE_AC97 + (offset << 2), data); + return data; +} + +WRITE32_MEMBER( S3C24_CLASS_NAME::s3c24xx_ac97_w ) +{ + verboselog( machine(), 9, "(AC97) %08X <- %08X\n", S3C24XX_BASE_AC97 + (offset << 2), data); + COMBINE_DATA(&m_ac97.regs.data[offset]); +} + +#endif + +// ... + +#if defined(DEVICE_S3C2410) || defined(DEVICE_S3C2440) + +void S3C24_CLASS_NAME::s3c24xx_nand_auto_boot() +{ + int om0 = iface_core_pin_r( S3C24XX_CORE_PIN_OM0); + int om1 = iface_core_pin_r( S3C24XX_CORE_PIN_OM1); + if ((om0 == 0) && (om1 == 0)) + { + int ncon = iface_core_pin_r( S3C24XX_CORE_PIN_NCON); + UINT8 *ptr = m_steppingstone; + int page_size, address_cycle; + #if defined(DEVICE_S3C2410) + page_size = 512; + if (ncon == 0) + { + address_cycle = 3; // byte-page-page + } + else + { + address_cycle = 4; // byte-page-page-page + } + #elif defined(DEVICE_S3C2440) + UINT32 port_g = iface_gpio_port_r( S3C24XX_GPIO_PORT_G, 0); + if (ncon == 0) + { + if (BIT( port_g, 13) == 0) + { + page_size = 256; + address_cycle = 3; // byte-page-page + } + else + { + page_size = 512; + address_cycle = 4; // byte-page-page-page + } + } + else + { + if (BIT( port_g, 13) == 0) + { + page_size = 1024; + address_cycle = 4; // byte-byte-page-page or byte-page-page-page ??? assume latter + } + else + { + page_size = 2048; + address_cycle = 5; // byte-byte-page-page-page + } + } + #endif + iface_nand_command_w( 0xFF); + for (int page = 0; page < (4 * 1024) / page_size; page++) + { + iface_nand_command_w( 0x00); + iface_nand_address_w( 0x00); + if (address_cycle > 4) + { + iface_nand_address_w( 0x00); + } + iface_nand_address_w( (page >> 0) & 0xFF); + iface_nand_address_w( (page >> 8) & 0xFF); + if (address_cycle > 3) + { + iface_nand_address_w( (page >> 16) & 0xFF); + } + for (int i = 0; i < page_size; i++) + { + *ptr++ = iface_nand_data_r(); + } + } + iface_nand_command_w( 0xFF); + } +} + +#endif + +void S3C24_CLASS_NAME::s3c24xx_device_reset() +{ + verboselog( machine(), 1, "s3c24xx device reset\n"); + s3c24xx_uart_reset( ); + s3c24xx_pwm_reset(); + s3c24xx_dma_reset(); + s3c24xx_iic_reset(); + s3c24xx_iis_reset(); + s3c24xx_lcd_reset(); + s3c24xx_rtc_reset(); + s3c24xx_wdt_reset(); + s3c24xx_irq_reset(); + s3c24xx_gpio_reset(); + s3c24xx_memcon_reset(); + s3c24xx_clkpow_reset(); + s3c24xx_usb_host_reset(); + s3c24xx_usb_device_reset(); + s3c24xx_adc_reset(); + s3c24xx_spi_reset(); + #if defined(DEVICE_S3C2400) + s3c24xx_mmc_reset(); + #endif + #if defined(DEVICE_S3C2410) || defined(DEVICE_S3C2440) + s3c24xx_sdi_reset(); + s3c24xx_nand_reset(); + #endif + #if defined(DEVICE_S3C2440) + s3c24xx_cam_reset(); + s3c24xx_ac97_reset(); + #endif + #if defined(DEVICE_S3C2410) || defined(DEVICE_S3C2440) + s3c24xx_nand_auto_boot(); + #endif +} + +void S3C24_CLASS_NAME::s3c24xx_device_start() +{ + verboselog( machine(), 1, "s3c24xx device start\n"); + m_pin_r_cb.resolve(); + m_pin_w_cb.resolve_safe(); + m_port_r_cb.resolve(); + m_port_w_cb.resolve(); + m_scl_w_cb.resolve(); + m_sda_r_cb.resolve(); + m_sda_w_cb.resolve(); + m_data_r_cb.resolve(); + m_data_w_cb.resolve(); + #if !defined(DEVICE_S3C2400) + m_command_w_cb.resolve(); + m_address_w_cb.resolve(); + m_nand_data_r_cb.resolve(); + m_nand_data_w_cb.resolve(); + #endif + for (int i = 0; i < 5; i++) + { + m_pwm.timer[i] = machine().scheduler().timer_alloc(timer_expired_delegate( FUNC(S3C24_CLASS_NAME::s3c24xx_pwm_timer_exp), this)); + } + for (int i = 0; i < S3C24XX_DMA_COUNT; i++) + { + m_dma[i].timer = machine().scheduler().timer_alloc(timer_expired_delegate( FUNC(S3C24_CLASS_NAME::s3c24xx_dma_timer_exp), this)); + } + m_iic.timer = machine().scheduler().timer_alloc(timer_expired_delegate( FUNC(S3C24_CLASS_NAME::s3c24xx_iic_timer_exp), this)); + m_iis.timer = machine().scheduler().timer_alloc(timer_expired_delegate( FUNC(S3C24_CLASS_NAME::s3c24xx_iis_timer_exp), this)); + m_lcd.timer = machine().scheduler().timer_alloc(timer_expired_delegate( FUNC(S3C24_CLASS_NAME::s3c24xx_lcd_timer_exp), this)); + m_rtc.timer_tick_count = machine().scheduler().timer_alloc(timer_expired_delegate( FUNC(S3C24_CLASS_NAME::s3c24xx_rtc_timer_tick_count_exp), this)); + m_rtc.timer_update = machine().scheduler().timer_alloc(timer_expired_delegate( FUNC(S3C24_CLASS_NAME::s3c24xx_rtc_timer_update_exp), this)); + m_wdt.timer = machine().scheduler().timer_alloc(timer_expired_delegate( FUNC(S3C24_CLASS_NAME::s3c24xx_wdt_timer_exp), this)); + #if defined(DEVICE_S3C2410) || defined(DEVICE_S3C2440) + int om0 = iface_core_pin_r( S3C24XX_CORE_PIN_OM0); + int om1 = iface_core_pin_r( S3C24XX_CORE_PIN_OM1); + if ((om0 == 0) && (om1 == 0)) + { + address_space &space = m_cpu->memory().space( AS_PROGRAM); + space.install_ram( 0x00000000, 0x00000fff, m_steppingstone); + space.install_ram( 0x40000000, 0x40000fff, m_steppingstone); + } + #endif +} diff --git a/src/devices/machine/s3c44b0.c b/src/devices/machine/s3c44b0.c new file mode 100644 index 00000000000..fb9d3f15036 --- /dev/null +++ b/src/devices/machine/s3c44b0.c @@ -0,0 +1,2055 @@ +// license:BSD-3-Clause +// copyright-holders:Tim Schuerewegen +/******************************************************************************* + + Samsung S3C44B0 + + (c) 2011 Tim Schuerewegen + +*******************************************************************************/ + +#include "emu.h" +#include "cpu/arm7/arm7.h" +#include "cpu/arm7/arm7core.h" +#include "machine/s3c44b0.h" +#include "sound/dac.h" +#include "coreutil.h" + +#define VERBOSE_LEVEL ( 0 ) + +INLINE void ATTR_PRINTF(3,4) verboselog( running_machine &machine, int n_level, const char *s_fmt, ...) +{ + if (VERBOSE_LEVEL >= n_level) + { + va_list v; + char buf[32768]; + va_start(v, s_fmt); + vsprintf(buf, s_fmt, v); + va_end(v); + logerror("%s: %s", machine.describe_context(), buf); + } +} + +const device_type S3C44B0 = &device_creator; + +s3c44b0_device::s3c44b0_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, S3C44B0, "Samsung S3C44B0", tag, owner, clock, "s3c44b0", __FILE__), + m_port_r_cb(*this), + m_port_w_cb(*this), + m_scl_w_cb(*this), + m_sda_r_cb(*this), + m_sda_w_cb(*this), + m_data_r_cb(*this), + m_data_w_cb(*this) +{ + memset(&m_irq, 0, sizeof(s3c44b0_irq_t)); + memset(m_zdma, 0, sizeof(s3c44b0_dma_t)*2); + memset(m_bdma, 0, sizeof(s3c44b0_dma_t)*2); + memset(&m_clkpow, 0, sizeof(s3c44b0_clkpow_t)); + memset(&m_lcd, 0, sizeof(s3c44b0_lcd_t)); + memset(m_uart, 0, sizeof(s3c44b0_uart_t)*2); + memset(&m_sio, 0, sizeof(s3c44b0_sio_t)); + memset(&m_pwm, 0, sizeof(s3c44b0_pwm_t)); + memset(&m_wdt, 0, sizeof(s3c44b0_wdt_t)); + memset(&m_iic, 0, sizeof(s3c44b0_iic_t)); + memset(&m_iis, 0, sizeof(s3c44b0_iis_t)); + memset(&m_gpio, 0, sizeof(s3c44b0_gpio_t)); + memset(&m_adc, 0, sizeof(s3c44b0_adc_t)); + memset(&m_cpuwrap, 0, sizeof(s3c44b0_cpuwrap_t)); +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void s3c44b0_device::device_start() +{ + m_cpu = machine().device("maincpu"); + + m_port_r_cb.resolve(); + m_port_w_cb.resolve(); + m_scl_w_cb.resolve(); + m_sda_r_cb.resolve(); + m_sda_w_cb.resolve(); + m_data_r_cb.resolve_safe(0); + m_data_w_cb.resolve(); + + + for (int i = 0; i < 6; i++) m_pwm.timer[i] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(s3c44b0_device::pwm_timer_exp),this)); + for (int i = 0; i < 2; i++) m_uart[i].timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(s3c44b0_device::uart_timer_exp),this)); + for (int i = 0; i < 2; i++) m_zdma[i].timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(s3c44b0_device::zdma_timer_exp),this)); + for (int i = 0; i < 2; i++) m_bdma[i].timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(s3c44b0_device::bdma_timer_exp),this)); + + m_lcd.timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(s3c44b0_device::lcd_timer_exp),this)); + m_wdt.timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(s3c44b0_device::wdt_timer_exp),this)); + m_sio.timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(s3c44b0_device::sio_timer_exp),this)); + m_adc.timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(s3c44b0_device::adc_timer_exp),this)); + m_iic.timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(s3c44b0_device::iic_timer_exp),this)); + m_iis.timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(s3c44b0_device::iis_timer_exp),this)); + + video_start(); + + save_item(NAME(m_irq.regs.intcon)); + save_item(NAME(m_irq.regs.intpnd)); + save_item(NAME(m_irq.regs.intmod)); + save_item(NAME(m_irq.regs.intmsk)); + save_item(NAME(m_irq.regs.i_pslv)); + save_item(NAME(m_irq.regs.i_pmst)); + save_item(NAME(m_irq.regs.i_cslv)); + save_item(NAME(m_irq.regs.i_cmst)); + save_item(NAME(m_irq.regs.i_ispr)); + save_item(NAME(m_irq.regs.i_ispc)); + save_item(NAME(m_irq.regs.reserved)); + save_item(NAME(m_irq.regs.f_ispr)); + save_item(NAME(m_irq.regs.f_ispc)); + save_item(NAME(m_irq.line_irq)); + save_item(NAME(m_irq.line_fiq)); + + save_item(NAME(m_clkpow.regs.pllcon)); + save_item(NAME(m_clkpow.regs.clkcon)); + save_item(NAME(m_clkpow.regs.clkslow)); + save_item(NAME(m_clkpow.regs.locktime)); + + // FIXME: how to save m_lcd.bitmap which gets allocated/freed during emulation? + save_item(NAME(m_lcd.regs.lcdcon1)); + save_item(NAME(m_lcd.regs.lcdcon2)); + save_item(NAME(m_lcd.regs.lcdsaddr1)); + save_item(NAME(m_lcd.regs.lcdsaddr2)); + save_item(NAME(m_lcd.regs.lcdsaddr3)); + save_item(NAME(m_lcd.regs.redlut)); + save_item(NAME(m_lcd.regs.greenlut)); + save_item(NAME(m_lcd.regs.bluelut)); + save_item(NAME(m_lcd.regs.reserved)); + save_item(NAME(m_lcd.regs.lcdcon3)); + save_item(NAME(m_lcd.regs.dithmode)); + save_item(NAME(m_lcd.vramaddr_cur)); + save_item(NAME(m_lcd.vramaddr_max)); + save_item(NAME(m_lcd.offsize)); + save_item(NAME(m_lcd.pagewidth_cur)); + save_item(NAME(m_lcd.pagewidth_max)); + save_item(NAME(m_lcd.modesel)); + save_item(NAME(m_lcd.bswp)); + save_item(NAME(m_lcd.vpos)); + save_item(NAME(m_lcd.hpos)); + save_item(NAME(m_lcd.framerate)); + save_item(NAME(m_lcd.hpos_min)); + save_item(NAME(m_lcd.hpos_max)); + save_item(NAME(m_lcd.hpos_end)); + save_item(NAME(m_lcd.vpos_min)); + save_item(NAME(m_lcd.vpos_max)); + save_item(NAME(m_lcd.vpos_end)); + save_item(NAME(m_lcd.frame_time)); + + machine().save().register_postload(save_prepost_delegate(FUNC(s3c44b0_device::s3c44b0_postload), this)); + + for (int i = 0; i < 2; i++) + { + save_item(NAME(m_zdma[i].regs.dcon), i); + save_item(NAME(m_zdma[i].regs.disrc), i); + save_item(NAME(m_zdma[i].regs.didst), i); + save_item(NAME(m_zdma[i].regs.dicnt), i); + save_item(NAME(m_zdma[i].regs.dcsrc), i); + save_item(NAME(m_zdma[i].regs.dcdst), i); + save_item(NAME(m_zdma[i].regs.dccnt), i); + + save_item(NAME(m_bdma[i].regs.dcon), i); + save_item(NAME(m_bdma[i].regs.disrc), i); + save_item(NAME(m_bdma[i].regs.didst), i); + save_item(NAME(m_bdma[i].regs.dicnt), i); + save_item(NAME(m_bdma[i].regs.dcsrc), i); + save_item(NAME(m_bdma[i].regs.dcdst), i); + save_item(NAME(m_bdma[i].regs.dccnt), i); + + save_item(NAME(m_uart[i].regs.ulcon), i); + save_item(NAME(m_uart[i].regs.ucon), i); + save_item(NAME(m_uart[i].regs.ufcon), i); + save_item(NAME(m_uart[i].regs.umcon), i); + save_item(NAME(m_uart[i].regs.utrstat), i); + save_item(NAME(m_uart[i].regs.uerstat), i); + save_item(NAME(m_uart[i].regs.ufstat), i); + save_item(NAME(m_uart[i].regs.umstat), i); + save_item(NAME(m_uart[i].regs.utxh), i); + save_item(NAME(m_uart[i].regs.urxh), i); + save_item(NAME(m_uart[i].regs.ubrdiv), i); + } + + save_item(NAME(m_sio.regs.siocon)); + save_item(NAME(m_sio.regs.siodat)); + save_item(NAME(m_sio.regs.sbrdr)); + save_item(NAME(m_sio.regs.itvcnt)); + save_item(NAME(m_sio.regs.dcntz)); + + save_item(NAME(m_pwm.regs.tcfg0)); + save_item(NAME(m_pwm.regs.tcfg1)); + save_item(NAME(m_pwm.regs.tcon)); + save_item(NAME(m_pwm.regs.tcntb0)); + save_item(NAME(m_pwm.regs.tcmpb0)); + save_item(NAME(m_pwm.regs.tcnto0)); + save_item(NAME(m_pwm.regs.tcntb1)); + save_item(NAME(m_pwm.regs.tcmpb1)); + save_item(NAME(m_pwm.regs.tcnto1)); + save_item(NAME(m_pwm.regs.tcntb2)); + save_item(NAME(m_pwm.regs.tcmpb2)); + save_item(NAME(m_pwm.regs.tcnto2)); + save_item(NAME(m_pwm.regs.tcntb3)); + save_item(NAME(m_pwm.regs.tcmpb3)); + save_item(NAME(m_pwm.regs.tcnto3)); + save_item(NAME(m_pwm.regs.tcntb4)); + save_item(NAME(m_pwm.regs.tcmpb4)); + save_item(NAME(m_pwm.regs.tcnto4)); + save_item(NAME(m_pwm.regs.tcntb5)); + save_item(NAME(m_pwm.regs.tcnto5)); + save_item(NAME(m_pwm.cnt)); + save_item(NAME(m_pwm.cmp)); + save_item(NAME(m_pwm.freq)); + + save_item(NAME(m_wdt.regs.wtcon)); + save_item(NAME(m_wdt.regs.wtdat)); + save_item(NAME(m_wdt.regs.wtcnt)); + + save_item(NAME(m_iic.regs.iiccon)); + save_item(NAME(m_iic.regs.iicstat)); + save_item(NAME(m_iic.regs.iicadd)); + save_item(NAME(m_iic.regs.iicds)); + save_item(NAME(m_iic.count)); + + save_item(NAME(m_iis.regs.iiscon)); + save_item(NAME(m_iis.regs.iismod)); + save_item(NAME(m_iis.regs.iispsr)); + save_item(NAME(m_iis.regs.iisfcon)); + save_item(NAME(m_iis.regs.iisfifo)); + save_item(NAME(m_iis.fifo)); + save_item(NAME(m_iis.fifo_index)); + + save_item(NAME(m_gpio.regs.gpacon)); + save_item(NAME(m_gpio.regs.gpadat)); + save_item(NAME(m_gpio.regs.gpbcon)); + save_item(NAME(m_gpio.regs.gpbdat)); + save_item(NAME(m_gpio.regs.gpccon)); + save_item(NAME(m_gpio.regs.gpcdat)); + save_item(NAME(m_gpio.regs.gpcup)); + save_item(NAME(m_gpio.regs.gpdcon)); + save_item(NAME(m_gpio.regs.gpddat)); + save_item(NAME(m_gpio.regs.gpdup)); + save_item(NAME(m_gpio.regs.gpecon)); + save_item(NAME(m_gpio.regs.gpedat)); + save_item(NAME(m_gpio.regs.gpeup)); + save_item(NAME(m_gpio.regs.gpfcon)); + save_item(NAME(m_gpio.regs.gpfdat)); + save_item(NAME(m_gpio.regs.gpfup)); + save_item(NAME(m_gpio.regs.gpgcon)); + save_item(NAME(m_gpio.regs.gpgdat)); + save_item(NAME(m_gpio.regs.gpgup)); + save_item(NAME(m_gpio.regs.spucr)); + save_item(NAME(m_gpio.regs.extint)); + save_item(NAME(m_gpio.regs.extintpnd)); + + save_item(NAME(m_adc.regs.adccon)); + save_item(NAME(m_adc.regs.adcpsr)); + save_item(NAME(m_adc.regs.adcdat)); + + save_item(NAME(m_cpuwrap.regs.syscfg)); + save_item(NAME(m_cpuwrap.regs.ncachbe0)); + save_item(NAME(m_cpuwrap.regs.ncachbe1)); +} + + +void s3c44b0_device::s3c44b0_postload() +{ + m_lcd.frame_period = HZ_TO_ATTOSECONDS(m_lcd.framerate); + m_lcd.scantime = m_lcd.frame_period / m_lcd.vpos_end; + m_lcd.pixeltime = m_lcd.frame_period / (m_lcd.vpos_end * m_lcd.hpos_end); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void s3c44b0_device::device_reset() +{ + m_iis.fifo_index = 0; + // m_iic.data_index = 0; +#if defined(DEVICE_S3C2410) || defined(DEVICE_S3C2440) + m_gpio.regs.gstatus2 = 0x00000001; // Boot is caused by power on reset +#endif + m_irq.line_irq = m_irq.line_fiq = CLEAR_LINE; +} + + +/******************************************************************************* + MACROS & CONSTANTS +*******************************************************************************/ + +#define UART_PRINTF + +#define CLOCK_MULTIPLIER 1 + +#define BIT(x,n) (((x)>>(n))&1) +#define BITS(x,m,n) (((x)>>(n))&(((UINT32)1<<((m)-(n)+1))-1)) +#define CLR_BITS(x,m,n) ((x) & ~((((UINT32)1 << ((m) - (n) + 1)) - 1) << n)) + + +/*************************************************************************** + IMPLEMENTATION +***************************************************************************/ + +/* LCD Controller */ + +rgb_t s3c44b0_device::lcd_get_color_stn_04(UINT8 data) +{ + UINT8 r, g, b; + r = g = b = BITS(data, 3, 0) << 4; + return rgb_t(r, g, b); +} + +UINT8 s3c44b0_device::lcd_get_color_stn_08_r(UINT8 data) +{ + return ((m_lcd.regs.redlut >> (BITS(data, 7, 5) << 2)) & 0xf) << 4; +} + +UINT8 s3c44b0_device::lcd_get_color_stn_08_g(UINT8 data) +{ + return ((m_lcd.regs.greenlut >> (BITS(data, 4, 2) << 2)) & 0xf) << 4; +} + +UINT8 s3c44b0_device::lcd_get_color_stn_08_b(UINT8 data) +{ + return ((m_lcd.regs.bluelut >> (BITS(data, 1, 0) << 2)) & 0xf) << 4; +} + +void s3c44b0_device::lcd_dma_reload() +{ + int lcdbank, lcdbaseu, lcdbasel; + lcdbank = BITS(m_lcd.regs.lcdsaddr1, 26, 21); + lcdbaseu = BITS(m_lcd.regs.lcdsaddr1, 20, 0); + lcdbasel = BITS(m_lcd.regs.lcdsaddr2, 20, 0); + + m_lcd.vramaddr_cur = (lcdbank << 22) | (lcdbaseu << 1); + m_lcd.vramaddr_max = (lcdbank << 22) | (lcdbasel << 1); + if (lcdbasel == 0) m_lcd.vramaddr_max += 1 << 22; + m_lcd.offsize = BITS(m_lcd.regs.lcdsaddr3, 19, 9); + m_lcd.pagewidth_cur = 0; + m_lcd.pagewidth_max = BITS(m_lcd.regs.lcdsaddr3, 8, 0); + m_lcd.bswp = BIT(m_lcd.regs.lcdsaddr2, 29); // note: juicebox changes bswp when video playback starts +// verboselog(machine(), 3, "LCD - vramaddr %08X %08X offsize %08X pagewidth %08X\n", m_lcd.vramaddr_cur, m_lcd.vramaddr_max, m_lcd.offsize, m_lcd.pagewidth_max); +} + +void s3c44b0_device::lcd_dma_init() +{ + m_lcd.modesel = BITS(m_lcd.regs.lcdsaddr1, 28, 27); +// verboselog(machine(), 3, "LCD - modesel %d bswp %d\n", m_lcd.modesel, m_lcd.bswp); + lcd_dma_reload(); +} + +void s3c44b0_device::lcd_dma_read(int count, UINT8 *data) +{ + address_space &space = m_cpu->space(AS_PROGRAM); + UINT8 *vram = (UINT8 *)space.get_read_ptr(m_lcd.vramaddr_cur); + for (int i = 0; i < count / 2; i++) + { + if (m_lcd.bswp == 0) + { + if ((m_lcd.vramaddr_cur & 2) == 0) + { + data[0] = *(vram + 3); + data[1] = *(vram + 2); + } + else + { + data[0] = *(vram - 1); + data[1] = *(vram - 2); + } + } + else + { + data[0] = *(vram + 0); + data[1] = *(vram + 1); + } + m_lcd.vramaddr_cur += 2; + m_lcd.pagewidth_cur++; + if (m_lcd.pagewidth_cur >= m_lcd.pagewidth_max) + { + m_lcd.vramaddr_cur += m_lcd.offsize << 1; + if (m_lcd.vramaddr_cur >= m_lcd.vramaddr_max) + { + lcd_dma_reload(); + } + m_lcd.pagewidth_cur = 0; + vram = (UINT8 *)space.get_read_ptr(m_lcd.vramaddr_cur); + } + else + { + vram += 2; + } + data += 2; + } +} + +void s3c44b0_device::lcd_render_stn_04() +{ + UINT8 *bitmap = m_lcd.bitmap + ((m_lcd.vpos - m_lcd.vpos_min) * (m_lcd.hpos_max - m_lcd.hpos_min + 1)) + (m_lcd.hpos - m_lcd.hpos_min); + UINT8 data[16]; + lcd_dma_read(16, data); + for (int i = 0; i < 16; i++) + { + for (int j = 0; j < 2; j++) + { + *bitmap++ = lcd_get_color_stn_04((data[i] >> 4) & 0x0F); + data[i] = data[i] << 4; + m_lcd.hpos++; + if (m_lcd.hpos >= m_lcd.hpos_min + (m_lcd.pagewidth_max << 2)) + { + m_lcd.vpos++; + if (m_lcd.vpos > m_lcd.vpos_max) + { + m_lcd.vpos = m_lcd.vpos_min; + bitmap = m_lcd.bitmap; + } + m_lcd.hpos = m_lcd.hpos_min; + } + } + } +} + +void s3c44b0_device::lcd_render_stn_08() +{ + UINT8 *bitmap = m_lcd.bitmap + ((m_lcd.vpos - m_lcd.vpos_min) * (m_lcd.hpos_max - m_lcd.hpos_min + 1)) + (m_lcd.hpos - m_lcd.hpos_min); + UINT8 data[16]; + lcd_dma_read(16, data); + for (int i = 0; i < 16; i++) + { + UINT8 xxx[3]; + xxx[0] = lcd_get_color_stn_08_r(data[i]); + xxx[1] = lcd_get_color_stn_08_g(data[i]); + xxx[2] = lcd_get_color_stn_08_b(data[i]); + for (int j = 0; j < 3; j++) + { + *bitmap++ = xxx[j]; + m_lcd.hpos++; + if (m_lcd.hpos >= m_lcd.hpos_min + (m_lcd.pagewidth_max * 6)) + { + m_lcd.vpos++; + if (m_lcd.vpos > m_lcd.vpos_max) + { + m_lcd.vpos = m_lcd.vpos_min; + bitmap = m_lcd.bitmap; + } + m_lcd.hpos = m_lcd.hpos_min; + } + } + } +} + +attotime s3c44b0_device::time_until_pos(int vpos, int hpos) +{ + attoseconds_t time1, time2; + attotime retval; + verboselog(machine(), 3, "s3c44b0_time_until_pos - vpos %d hpos %d\n", vpos, hpos); + time1 = (attoseconds_t)vpos * m_lcd.scantime + (attoseconds_t)hpos * m_lcd.pixeltime; + time2 = (machine().time() - m_lcd.frame_time).as_attoseconds(); + verboselog(machine(), 3, "machine %f frametime %f time1 %f time2 %f\n", machine().time().as_double(), m_lcd.frame_time.as_double(), attotime(0, time1).as_double(), attotime(0, time2).as_double()); + while (time1 <= time2) time1 += m_lcd.frame_period; + retval = attotime( 0, time1 - time2); + verboselog(machine(), 3, "result %f\n", retval.as_double()); + return retval; +} + +int s3c44b0_device::lcd_get_vpos() +{ + attoseconds_t delta; + int vpos; + delta = (machine().time() - m_lcd.frame_time).as_attoseconds(); + delta = delta + (m_lcd.pixeltime / 2); + vpos = delta / m_lcd.scantime; + return (m_lcd.vpos_min + vpos) % m_lcd.vpos_end; +} + +int s3c44b0_device::lcd_get_hpos() +{ + attoseconds_t delta; + int vpos; + delta = (machine().time() - m_lcd.frame_time).as_attoseconds(); + delta = delta + (m_lcd.pixeltime / 2); + vpos = delta / m_lcd.scantime; + delta = delta - (vpos * m_lcd.scantime); + return delta / m_lcd.pixeltime; +} + +TIMER_CALLBACK_MEMBER( s3c44b0_device::lcd_timer_exp ) +{ + int vpos = m_lcd.vpos; + verboselog(machine(), 2, "LCD timer callback (%f)\n", machine().time().as_double()); + verboselog(machine(), 3, "LCD - (1) vramaddr %08X vpos %d hpos %d\n", m_lcd.vramaddr_cur, m_lcd.vpos, m_lcd.hpos); + switch (m_lcd.modesel) + { + case S3C44B0_MODESEL_04 : lcd_render_stn_04(); break; + case S3C44B0_MODESEL_08 : lcd_render_stn_08(); break; + default : verboselog(machine(), 0, "s3c44b0_lcd_timer_exp: modesel %d not supported\n", m_lcd.modesel); break; + } + verboselog(machine(), 3, "LCD - (2) vramaddr %08X vpos %d hpos %d\n", m_lcd.vramaddr_cur, m_lcd.vpos, m_lcd.hpos); + if (m_lcd.vpos < vpos) + { +// verboselog(machine(), 3, "LCD - (1) frame_time %f\n", attotime_to_double(m_lcd.frame_time)); + m_lcd.frame_time = machine().time() + time_until_pos(m_lcd.vpos_min, m_lcd.hpos_min); +// verboselog(machine(), 3, "LCD - (2) frame_time %f\n", attotime_to_double(m_lcd.frame_time)); + } + m_lcd.timer->adjust(time_until_pos(m_lcd.vpos, m_lcd.hpos), 0); +} + +void s3c44b0_device::video_start() +{ + // do nothing +} + +UINT32 s3c44b0_device::video_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + if (m_lcd.regs.lcdcon1 & (1 << 0)) + { + if (m_lcd.bitmap) + { + for (int y = 0; y < screen.height(); y++) + { + UINT32 *scanline = &bitmap.pix32(y); + UINT8 *vram = m_lcd.bitmap + y * (m_lcd.hpos_max - m_lcd.hpos_min + 1); + for (int x = 0; x < screen.width(); x++) + { + *scanline++ = rgb_t(vram[0], vram[1], vram[2]); + vram += 3; + } + } + } + } + else + { + for (int y = 0; y < screen.height(); y++) + { + UINT32 *scanline = &bitmap.pix32(y); + memset(scanline, 0, screen.width() * 4); + } + } + return 0; +} + +READ32_MEMBER( s3c44b0_device::lcd_r ) +{ + UINT32 data = ((UINT32*)&m_lcd.regs)[offset]; + switch (offset) + { + case S3C44B0_LCDCON1 : + { + int vpos = 0; + // make sure line counter is going + if (m_lcd.regs.lcdcon1 & (1 << 0)) + { + vpos = lcd_get_vpos(); + int hpos = lcd_get_hpos(); + if (hpos < m_lcd.hpos_min) vpos = vpos - 1; + if ((vpos < m_lcd.vpos_min) || (vpos > m_lcd.vpos_max)) vpos = m_lcd.vpos_max; + vpos = m_lcd.vpos_max - vpos; + } + data = (data & ~0xFFC00000) | (vpos << 22); + } + break; + } +// verboselog(machine(), 9, "(LCD) %08X -> %08X\n", S3C44B0_BASE_LCD + (offset << 2), data); + return data; +} + +void s3c44b0_device::lcd_configure() +{ + screen_device *screen = machine().first_screen(); + int dismode, clkval, lineval, wdly, hozval, lineblank, wlh, mclk; + double vclk, framerate; + int width, height; + verboselog(machine(), 5, "s3c44b0_lcd_configure\n"); + dismode = BITS(m_lcd.regs.lcdcon1, 6, 5); + clkval = BITS(m_lcd.regs.lcdcon1, 21, 12); + lineval = BITS(m_lcd.regs.lcdcon2, 9, 0); + wdly = BITS(m_lcd.regs.lcdcon1, 9, 8); + hozval = BITS(m_lcd.regs.lcdcon2, 20, 10); + lineblank = BITS(m_lcd.regs.lcdcon2, 31, 21); + wlh = BITS(m_lcd.regs.lcdcon1, 11, 10); + mclk = get_mclk(); + verboselog(machine(), 3, "LCD - dismode %d clkval %d lineval %d wdly %d hozval %d lineblank %d wlh %d mclk %d\n", dismode, clkval, lineval, wdly, hozval, lineblank, wlh, mclk); + vclk = (double)(mclk / (clkval * 2)); + verboselog(machine(), 3, "LCD - vclk %f\n", vclk); + framerate = 1 / (((1 / vclk) * (hozval + 1) + (1 / mclk) * (wlh + wdly + lineblank)) * (lineval + 1)); + framerate = framerate / 3; // ??? + verboselog(machine(), 3, "LCD - framerate %f\n", framerate); + switch (dismode) + { + case S3C44B0_PNRMODE_STN_04_SS : width = ((hozval + 1) * 4); break; + case S3C44B0_PNRMODE_STN_04_DS : width = ((hozval + 1) * 4); break; + case S3C44B0_PNRMODE_STN_08_SS : width = ((hozval + 1) * 8); break; + default : fatalerror("invalid display mode (%d)\n", dismode); + } + height = lineval + 1; + m_lcd.framerate = framerate; + verboselog(machine(), 3, "video_screen_configure %d %d %f\n", width, height, m_lcd.framerate); + screen->configure(screen->width(), screen->height(), screen->visible_area(), HZ_TO_ATTOSECONDS(m_lcd.framerate)); + m_lcd.hpos_min = 25; + m_lcd.hpos_max = 25 + width - 1; + m_lcd.hpos_end = 25 + width - 1 + 25; + m_lcd.vpos_min = 25; + m_lcd.vpos_max = 25 + height - 1; + m_lcd.vpos_end = 25 + height - 1 + 25; + verboselog(machine(), 3, "LCD - min_x %d min_y %d max_x %d max_y %d\n", m_lcd.hpos_min, m_lcd.vpos_min, m_lcd.hpos_max, m_lcd.vpos_max); + if (m_lcd.bitmap) + { + auto_free(machine(), m_lcd.bitmap); + } + m_lcd.bitmap = auto_alloc_array(machine(), UINT8, (m_lcd.hpos_max - m_lcd.hpos_min + 1) * (m_lcd.vpos_max - m_lcd.vpos_min + 1) * 3); + m_lcd.frame_period = HZ_TO_ATTOSECONDS(m_lcd.framerate); + m_lcd.scantime = m_lcd.frame_period / m_lcd.vpos_end; + m_lcd.pixeltime = m_lcd.frame_period / (m_lcd.vpos_end * m_lcd.hpos_end); +// printf("frame_period %f\n", attotime( 0, m_lcd.frame_period).as_double()); +// printf("scantime %f\n", attotime( 0, m_lcd.scantime).as_double()); +// printf("pixeltime %f\n", attotime( 0, m_lcd.pixeltime).as_double()); +} + + +void s3c44b0_device::lcd_start() +{ + screen_device *screen = machine().first_screen(); + verboselog(machine(), 1, "LCD start\n"); + lcd_configure(); + lcd_dma_init(); + m_lcd.vpos = m_lcd.vpos_min; + m_lcd.hpos = m_lcd.hpos_min; + m_lcd.frame_time = screen->time_until_pos( 0, 0); + m_lcd.timer->adjust(m_lcd.frame_time, 0); + m_lcd.frame_time = machine().time() + m_lcd.frame_time; +} + +void s3c44b0_device::lcd_stop() +{ + verboselog(machine(), 1, "LCD stop\n"); + m_lcd.timer->adjust(attotime::never, 0); +} + +void s3c44b0_device::lcd_recalc() +{ + if (m_lcd.regs.lcdcon1 & (1 << 0)) + lcd_start(); + else + lcd_stop(); +} + +WRITE32_MEMBER( s3c44b0_device::lcd_w ) +{ + UINT32 old_value = ((UINT32*)&m_lcd.regs)[offset]; +// verboselog(machine(), 9, "(LCD) %08X <- %08X\n", S3C44B0_BASE_LCD + (offset << 2), data); + COMBINE_DATA(&((UINT32*)&m_lcd.regs)[offset]); + switch (offset) + { + case S3C44B0_LCDCON1 : + { + if ((old_value & (1 << 0)) != (data & (1 << 0))) + { + lcd_recalc(); + } + } + break; + } +} + + +/* Clock & Power Management */ + +UINT32 s3c44b0_device::get_mclk() +{ + UINT32 data, mdiv, pdiv, sdiv; + data = m_clkpow.regs.pllcon; + mdiv = BITS(data, 19, 12); + pdiv = BITS(data, 9, 4); + sdiv = BITS(data, 1, 0); + return (UINT32)((double)((mdiv + 8) * clock()) / (double)((pdiv + 2) * (1 << sdiv))); +} + +READ32_MEMBER( s3c44b0_device::clkpow_r ) +{ + UINT32 data = ((UINT32*)&m_clkpow.regs)[offset]; + verboselog(machine(), 9, "(CLKPOW) %08X -> %08X\n", S3C44B0_BASE_CLKPOW + (offset << 2), data); + return data; +} + +WRITE32_MEMBER( s3c44b0_device::clkpow_w ) +{ + verboselog(machine(), 9, "(CLKPOW) %08X <- %08X\n", S3C44B0_BASE_CLKPOW + (offset << 2), data); + COMBINE_DATA(&((UINT32*)&m_clkpow.regs)[offset]); + switch (offset) + { + case S3C44B0_PLLCON : + { + verboselog(machine(), 5, "CLKPOW - mclk %d\n", get_mclk()); + m_cpu->set_unscaled_clock(get_mclk() * CLOCK_MULTIPLIER); + } + break; + case S3C44B0_CLKCON : + { + if (data & (1 << 2)) + { + m_cpu->spin_until_interrupt(); + } + } + break; + } +} + +/* Interrupt Controller */ + +void s3c44b0_device::check_pending_irq() +{ + // normal irq + UINT32 temp = (m_irq.regs.intpnd & ~m_irq.regs.intmsk) & ~m_irq.regs.intmod; + + if (temp != 0) + { + UINT32 int_type = 0; + while ((temp & 1) == 0) + { + int_type++; + temp = temp >> 1; + } + m_irq.regs.i_ispr |= (1 << int_type); + if (m_irq.line_irq != ASSERT_LINE) + { + m_cpu->set_input_line(ARM7_IRQ_LINE, ASSERT_LINE); + m_irq.line_irq = ASSERT_LINE; + } + } + else + { + if (m_irq.line_irq != CLEAR_LINE) + { + m_cpu->set_input_line(ARM7_IRQ_LINE, CLEAR_LINE); + m_irq.line_irq = CLEAR_LINE; + } + } + // fast irq + temp = (m_irq.regs.intpnd & ~m_irq.regs.intmsk) & m_irq.regs.intmod; + if (temp != 0) + { + UINT32 int_type = 0; + while ((temp & 1) == 0) + { + int_type++; + temp = temp >> 1; + } + if (m_irq.line_fiq != ASSERT_LINE) + { + m_cpu->set_input_line(ARM7_FIRQ_LINE, ASSERT_LINE); + m_irq.line_fiq = ASSERT_LINE; + } + } + else + { + if (m_irq.line_fiq != CLEAR_LINE) + { + m_cpu->set_input_line(ARM7_FIRQ_LINE, CLEAR_LINE); + m_irq.line_fiq = CLEAR_LINE; + } + } +} + +void s3c44b0_device::request_irq(UINT32 int_type) +{ + verboselog(machine(), 5, "request irq %d\n", int_type); + m_irq.regs.intpnd |= (1 << int_type); + check_pending_irq(); +} + +void s3c44b0_device::check_pending_eint() +{ + UINT32 temp = m_gpio.regs.extintpnd; + if (temp != 0) + { + UINT32 int_type = 0; + while ((temp & 1) == 0) + { + int_type++; + temp = temp >> 1; + } + request_irq(S3C44B0_INT_EINT4_7); + } +} + +void s3c44b0_device::request_eint(UINT32 number) +{ + verboselog(machine(), 5, "request external interrupt %d\n", number); + if (number < 4) + { + request_irq(S3C44B0_INT_EINT0 + number); + } + else + { + m_gpio.regs.extintpnd |= (1 << (number - 4)); + check_pending_eint(); + } +} + +READ32_MEMBER( s3c44b0_device::irq_r ) +{ + UINT32 data = ((UINT32*)&m_irq.regs)[offset]; + verboselog(machine(), 9, "(IRQ) %08X -> %08X\n", S3C44B0_BASE_INT + (offset << 2), data); + return data; +} + +WRITE32_MEMBER( s3c44b0_device::irq_w ) +{ + verboselog(machine(), 9, "(IRQ) %08X <- %08X\n", S3C44B0_BASE_INT + (offset << 2), data); + COMBINE_DATA(&((UINT32*)&m_irq.regs)[offset]); + switch (offset) + { + case S3C44B0_INTMSK : + { + check_pending_irq(); + } + break; + case S3C44B0_I_ISPC : + { + m_irq.regs.intpnd = (m_irq.regs.intpnd & ~data); // The bit of INTPND bit is cleared to zero by writing '1' on I_ISPC/F_ISPC + m_irq.regs.i_ispr = (m_irq.regs.i_ispr & ~data); // The pending bit in I_ISPR register should be cleared by writing I_ISPC register. + check_pending_irq(); + } + break; + case S3C44B0_F_ISPC : + { + m_irq.regs.intpnd = (m_irq.regs.intpnd & ~data); // The bit of INTPND bit is cleared to zero by writing '1' on I_ISPC/F_ISPC + check_pending_irq(); + } + break; + } +} + +/* PWM Timer */ + +UINT16 s3c44b0_device::pwm_calc_observation(int ch) +{ + double timeleft, x1, x2; + UINT32 cnto; + timeleft = (m_pwm.timer[ch]->remaining()).as_double(); +// printf( "timeleft %f freq %d cntb %d cmpb %d\n", timeleft, m_pwm.freq[ch], m_pwm.cnt[ch], m_pwm.cmp[ch]); + x1 = 1 / ((double)m_pwm.freq[ch] / (m_pwm.cnt[ch]- m_pwm.cmp[ch] + 1)); + x2 = x1 / timeleft; +// printf( "x1 %f\n", x1); + cnto = m_pwm.cmp[ch] + ((m_pwm.cnt[ch]- m_pwm.cmp[ch]) / x2); +// printf( "cnto %d\n", cnto); + return cnto; +} + +READ32_MEMBER( s3c44b0_device::pwm_r ) +{ + UINT32 data = ((UINT32*)&m_pwm.regs)[offset]; + switch (offset) + { + case S3C44B0_TCNTO0 : + { + data = (data & ~0x0000FFFF) | pwm_calc_observation(0); + } + break; + case S3C44B0_TCNTO1 : + { + data = (data & ~0x0000FFFF) | pwm_calc_observation(1); + } + break; + case S3C44B0_TCNTO2 : + { + data = (data & ~0x0000FFFF) | pwm_calc_observation(2); + } + break; + case S3C44B0_TCNTO3 : + { + data = (data & ~0x0000FFFF) | pwm_calc_observation(3); + } + break; + case S3C44B0_TCNTO4 : + { + data = (data & ~0x0000FFFF) | pwm_calc_observation(4); + } + break; + case S3C44B0_TCNTO5 : + { + data = (data & ~0x0000FFFF) | pwm_calc_observation(5); + } + break; + } + verboselog(machine(), 9, "(PWM) %08X -> %08X\n", S3C44B0_BASE_PWM + (offset << 2), data); + return data; +} + +void s3c44b0_device::pwm_start(int timer) +{ + const int mux_table[] = { 2, 4, 8, 16}; + const int prescaler_shift[] = { 0, 0, 8, 8, 16, 16}; + const int mux_shift[] = { 0, 4, 8, 12, 16, 20}; + UINT32 mclk, prescaler, mux, cnt, cmp, auto_reload; + double freq, hz; + verboselog(machine(), 1, "PWM %d start\n", timer); + mclk = get_mclk(); + prescaler = (m_pwm.regs.tcfg0 >> prescaler_shift[timer]) & 0xFF; + mux = (m_pwm.regs.tcfg1 >> mux_shift[timer]) & 0x0F; + if (mux < 4) + { + freq = (double)mclk / (prescaler + 1) / mux_table[mux]; + } + else + { + // todo + freq = (double)mclk / (prescaler + 1) / 1; + } + switch (timer) + { + case 0 : + { + cnt = BITS(m_pwm.regs.tcntb0, 15, 0); + cmp = BITS(m_pwm.regs.tcmpb0, 15, 0); + auto_reload = BIT(m_pwm.regs.tcon, 3); + } + break; + case 1 : + { + cnt = BITS(m_pwm.regs.tcntb1, 15, 0); + cmp = BITS(m_pwm.regs.tcmpb1, 15, 0); + auto_reload = BIT(m_pwm.regs.tcon, 11); + } + break; + case 2 : + { + cnt = BITS(m_pwm.regs.tcntb2, 15, 0); + cmp = BITS(m_pwm.regs.tcmpb2, 15, 0); + auto_reload = BIT(m_pwm.regs.tcon, 15); + } + break; + case 3 : + { + cnt = BITS(m_pwm.regs.tcntb3, 15, 0); + cmp = BITS(m_pwm.regs.tcmpb3, 15, 0); + auto_reload = BIT(m_pwm.regs.tcon, 19); + } + break; + case 4 : + { + cnt = BITS(m_pwm.regs.tcntb4, 15, 0); + cmp = BITS(m_pwm.regs.tcmpb4, 15, 0); + auto_reload = BIT(m_pwm.regs.tcon, 23); + } + break; + case 5 : + { + cnt = BITS(m_pwm.regs.tcntb5, 15, 0); + cmp = 0; + auto_reload = BIT(m_pwm.regs.tcon, 26); + } + break; + default : + { + cnt = cmp = auto_reload = 0; + } + break; + } +// hz = freq / (cnt - cmp + 1); + if (cnt < 2) + { + hz = freq; + } + else + { + hz = freq / cnt; + } + verboselog(machine(), 5, "PWM %d - mclk=%d prescaler=%d div=%d freq=%f cnt=%d cmp=%d auto_reload=%d hz=%f\n", timer, mclk, prescaler, mux_table[mux], freq, cnt, cmp, auto_reload, hz); + m_pwm.cnt[timer] = cnt; + m_pwm.cmp[timer] = cmp; + m_pwm.freq[timer] = freq; + if (cnt == 0) + { + m_pwm.timer[timer]->adjust(attotime::never, 0); + } + else + { + if (auto_reload) + { + m_pwm.timer[timer]->adjust(attotime::from_hz(hz), timer, attotime::from_hz(hz)); + } + else + { + m_pwm.timer[timer]->adjust(attotime::from_hz(hz), timer); + } + } +} + +void s3c44b0_device::pwm_stop(int timer) +{ + verboselog(machine(), 1, "PWM %d stop\n", timer); + m_pwm.timer[timer]->adjust(attotime::never, 0); +} + +void s3c44b0_device::pwm_recalc(int timer) +{ + const int tcon_shift[] = { 0, 8, 12, 16, 20, 24}; + if (m_pwm.regs.tcon & (1 << tcon_shift[timer])) + pwm_start(timer); + else + pwm_stop(timer); +} + +WRITE32_MEMBER( s3c44b0_device::pwm_w ) +{ + UINT32 old_value = ((UINT32*)&m_pwm.regs)[offset]; + verboselog(machine(), 9, "(PWM) %08X <- %08X\n", S3C44B0_BASE_PWM + (offset << 2), data); + COMBINE_DATA(&((UINT32*)&m_pwm.regs)[offset]); + switch (offset) + { + case S3C44B0_TCON : + { + if ((data & (1 << 0)) != (old_value & (1 << 0))) + { + pwm_recalc(0); + } + if ((data & (1 << 8)) != (old_value & (1 << 8))) + { + pwm_recalc(1); + } + if ((data & (1 << 12)) != (old_value & (1 << 12))) + { + pwm_recalc(2); + } + if ((data & (1 << 16)) != (old_value & (1 << 16))) + { + pwm_recalc(3); + } + if ((data & (1 << 20)) != (old_value & (1 << 20))) + { + pwm_recalc(4); + } + if ((data & (1 << 24)) != (old_value & (1 << 24))) + { + pwm_recalc(5); + } + } + break; + } +} + +TIMER_CALLBACK_MEMBER( s3c44b0_device::pwm_timer_exp ) +{ + int ch = param; + const int ch_int[] = { S3C44B0_INT_TIMER0, S3C44B0_INT_TIMER1, S3C44B0_INT_TIMER2, S3C44B0_INT_TIMER3, S3C44B0_INT_TIMER4, S3C44B0_INT_TIMER5 }; + verboselog(machine(), 2, "PWM %d timer callback\n", ch); + if (BITS(m_pwm.regs.tcfg1, 27, 24) == (ch + 1)) + { + fatalerror("s3c44b0_dma_request_pwm( device)\n"); + } + else + { + request_irq(ch_int[ch]); + } +} + +/* IIC */ + +inline void s3c44b0_device::iface_i2c_scl_w(int state) +{ + if (!m_scl_w_cb.isnull()) + (m_scl_w_cb)( state); +} + +inline void s3c44b0_device::iface_i2c_sda_w(int state) +{ + if (!m_sda_w_cb.isnull()) + (m_sda_w_cb)( state); +} + +inline int s3c44b0_device::iface_i2c_sda_r() +{ + if (!m_sda_r_cb.isnull()) + return (m_sda_r_cb)(); + else + return 0; +} + +void s3c44b0_device::i2c_send_start() +{ + verboselog(machine(), 5, "i2c_send_start\n"); + iface_i2c_sda_w(1); + iface_i2c_scl_w(1); + iface_i2c_sda_w(0); + iface_i2c_scl_w(0); +} + +void s3c44b0_device::i2c_send_stop() +{ + verboselog(machine(), 5, "i2c_send_stop\n"); + iface_i2c_sda_w(0); + iface_i2c_scl_w(1); + iface_i2c_sda_w(1); + iface_i2c_scl_w(0); +} + +UINT8 s3c44b0_device::i2c_receive_byte(int ack) +{ + UINT8 data = 0; + verboselog(machine(), 5, "i2c_receive_byte ...\n"); + iface_i2c_sda_w(1); + for (int i = 0; i < 8; i++) + { + iface_i2c_scl_w(1); + data = (data << 1) + (iface_i2c_sda_r() ? 1 : 0); + iface_i2c_scl_w(0); + } + verboselog(machine(), 5, "recv data %02X\n", data); + verboselog(machine(), 5, "send ack %d\n", ack); + iface_i2c_sda_w(ack ? 0 : 1); + iface_i2c_scl_w(1); + iface_i2c_scl_w(0); + return data; +} + +int s3c44b0_device::i2c_send_byte(UINT8 data) +{ + int ack; + verboselog(machine(), 5, "i2c_send_byte ...\n"); + verboselog(machine(), 5, "send data %02X\n", data); + for (int i = 0; i < 8; i++) + { + iface_i2c_sda_w((data & 0x80) ? 1 : 0); + data = data << 1; + iface_i2c_scl_w(1); + iface_i2c_scl_w(0); + } + iface_i2c_sda_w(1); // ack bit + iface_i2c_scl_w(1); + ack = iface_i2c_sda_r(); + verboselog(machine(), 5, "recv ack %d\n", ack); + iface_i2c_scl_w(0); + return ack; +} + +void s3c44b0_device::iic_start() +{ + int mode_selection; + verboselog(machine(), 1, "IIC start\n"); + i2c_send_start(); + mode_selection = BITS(m_iic.regs.iicstat, 7, 6); + switch (mode_selection) + { + case 2 : i2c_send_byte(m_iic.regs.iicds | 0x01); break; + case 3 : i2c_send_byte(m_iic.regs.iicds & 0xFE); break; + } + m_iic.timer->adjust(attotime::from_usec( 1), 0); +} + +void s3c44b0_device::iic_stop() +{ + verboselog(machine(), 1, "IIC stop\n"); + i2c_send_stop(); + m_iic.timer->adjust(attotime::never, 0); +} + +void s3c44b0_device::iic_resume() +{ + int mode_selection; + verboselog(machine(), 1, "IIC resume\n"); + mode_selection = BITS(m_iic.regs.iicstat, 7, 6); + switch (mode_selection) + { + case 2 : m_iic.regs.iicds = i2c_receive_byte(BIT(m_iic.regs.iiccon, 7)); break; + case 3 : i2c_send_byte(m_iic.regs.iicds & 0xFF); break; + } + m_iic.timer->adjust(attotime::from_usec( 1), 0); +} + +READ32_MEMBER( s3c44b0_device::iic_r ) +{ + UINT32 data = ((UINT32*)&m_iic.regs)[offset]; + switch (offset) + { + case S3C44B0_IICSTAT : + { + data = data & ~0x0000000F; + } + break; + } + verboselog(machine(), 9, "(IIC) %08X -> %08X\n", S3C44B0_BASE_IIC + (offset << 2), data); + return data; +} + +WRITE32_MEMBER( s3c44b0_device::iic_w ) +{ + UINT32 old_value = ((UINT32*)&m_iic.regs)[offset]; + verboselog(machine(), 9, "(IIC) %08X <- %08X\n", S3C44B0_BASE_IIC + (offset << 2), data); + COMBINE_DATA(&((UINT32*)&m_iic.regs)[offset]); + switch (offset) + { + case S3C44B0_IICCON : + { + int interrupt_pending_flag; +#if 0 + const int div_table[] = { 16, 512}; + int enable_interrupt, transmit_clock_value, tx_clock_source_selection + double clock; + transmit_clock_value = (data >> 0) & 0xF; + tx_clock_source_selection = (data >> 6) & 1; + enable_interrupt = (data >> 5) & 1; + clock = (double)get_pclk() / div_table[tx_clock_source_selection] / (transmit_clock_value + 1); +#endif + interrupt_pending_flag = BIT(old_value, 4); + if (interrupt_pending_flag != 0) + { + interrupt_pending_flag = BIT(data, 4); + if (interrupt_pending_flag == 0) + { + int start_stop_condition; + start_stop_condition = BIT(m_iic.regs.iicstat, 5); + if (start_stop_condition != 0) + { + if (m_iic.count == 0) + { + iic_start(); + + } + else + { + iic_resume(); + } + } + else + { + iic_stop(); + } + } + } + } + break; + case S3C44B0_IICSTAT : + { + int interrupt_pending_flag; + m_iic.count = 0; + interrupt_pending_flag = BIT(m_iic.regs.iiccon, 4); + if (interrupt_pending_flag == 0) + { + int start_stop_condition; + start_stop_condition = BIT(data, 5); + if (start_stop_condition != 0) + { + if (m_iic.count == 0) + { + iic_start(); + + } + else + { + iic_resume(); + } + } + else + { + iic_stop(); + } + } + } + break; + } +} + +TIMER_CALLBACK_MEMBER( s3c44b0_device::iic_timer_exp ) +{ + int enable_interrupt; + verboselog(machine(), 2, "IIC timer callback\n"); + m_iic.count++; + enable_interrupt = BIT(m_iic.regs.iiccon, 5); + + m_iic.regs.iicds = 0xFF; // TEST + + if (enable_interrupt) + { + m_iic.regs.iiccon |= (1 << 4); // [bit 4] interrupt is pending + request_irq(S3C44B0_INT_IIC); + } +} + +/* I/O Port */ + +inline UINT32 s3c44b0_device::iface_gpio_port_r(int port) +{ + if (!m_port_r_cb.isnull()) + return (m_port_r_cb)(port); + else + return 0; +} + +inline void s3c44b0_device::iface_gpio_port_w(int port, UINT32 data) +{ + if (!m_port_w_cb.isnull()) + (m_port_w_cb)(port, data, 0xffff); +} + +READ32_MEMBER( s3c44b0_device::gpio_r ) +{ + UINT32 data = ((UINT32*)&m_gpio.regs)[offset]; + switch (offset) + { + case S3C44B0_GPADAT : + { + data = iface_gpio_port_r(S3C44B0_GPIO_PORT_A) & S3C44B0_GPADAT_MASK; + } + break; + case S3C44B0_GPBDAT : + { + data = iface_gpio_port_r(S3C44B0_GPIO_PORT_B) & S3C44B0_GPBDAT_MASK; + } + break; + case S3C44B0_GPCDAT : + { + data = iface_gpio_port_r(S3C44B0_GPIO_PORT_C) & S3C44B0_GPCDAT_MASK; + } + break; + case S3C44B0_GPDDAT : + { + data = iface_gpio_port_r(S3C44B0_GPIO_PORT_D) & S3C44B0_GPDDAT_MASK; + } + break; + case S3C44B0_GPEDAT : + { + data = iface_gpio_port_r(S3C44B0_GPIO_PORT_E) & S3C44B0_GPEDAT_MASK; + } + break; + case S3C44B0_GPFDAT : + { + data = iface_gpio_port_r(S3C44B0_GPIO_PORT_F) & S3C44B0_GPFDAT_MASK; + } + break; + case S3C44B0_GPGDAT : + { + data = iface_gpio_port_r(S3C44B0_GPIO_PORT_G) & S3C44B0_GPGDAT_MASK; + } + break; + } + verboselog(machine(), 9, "(GPIO) %08X -> %08X\n", S3C44B0_BASE_GPIO + (offset << 2), data); + return data; +} + +WRITE32_MEMBER( s3c44b0_device::gpio_w ) +{ + UINT32 old_value = ((UINT32*)&m_gpio.regs)[offset]; + verboselog(machine(), 9, "(GPIO) %08X <- %08X\n", S3C44B0_BASE_GPIO + (offset << 2), data); + COMBINE_DATA(&((UINT32*)&m_gpio.regs)[offset]); + switch (offset) + { + case S3C44B0_GPADAT : + { + iface_gpio_port_w(S3C44B0_GPIO_PORT_A, data & S3C44B0_GPADAT_MASK); + } + break; + case S3C44B0_GPBDAT : + { + iface_gpio_port_w(S3C44B0_GPIO_PORT_B, data & S3C44B0_GPBDAT_MASK); + } + break; + case S3C44B0_GPCDAT : + { + iface_gpio_port_w(S3C44B0_GPIO_PORT_C, data & S3C44B0_GPCDAT_MASK); + } + break; + case S3C44B0_GPDDAT : + { + iface_gpio_port_w(S3C44B0_GPIO_PORT_D, data & S3C44B0_GPDDAT_MASK); + } + break; + case S3C44B0_GPEDAT : + { + iface_gpio_port_w(S3C44B0_GPIO_PORT_E, data & S3C44B0_GPEDAT_MASK); + } + break; + case S3C44B0_GPFDAT : + { + iface_gpio_port_w(S3C44B0_GPIO_PORT_F, data & S3C44B0_GPFDAT_MASK); + } + break; + case S3C44B0_GPGDAT : + { + iface_gpio_port_w(S3C44B0_GPIO_PORT_G, data & S3C44B0_GPGDAT_MASK); + } + break; + case S3C44B0_EXTINTPND : + { + m_gpio.regs.extintpnd = (old_value & ~data); + check_pending_eint(); + } + break; + } +} + +/* UART */ + +UINT32 s3c44b0_device::uart_r(int ch, UINT32 offset) +{ + UINT32 data = ((UINT32*)&m_uart[ch].regs)[offset]; + switch (offset) + { + case S3C44B0_UTRSTAT : + { + data = (data & ~0x00000006) | 0x00000004 | 0x00000002; // [bit 2] Transmitter empty / [bit 1] Transmit buffer empty + } + break; + case S3C44B0_URXH : + { + UINT8 rxdata = data & 0xFF; + verboselog(machine(), 5, "UART %d read %02X (%c)\n", ch, rxdata, ((rxdata >= 32) && (rxdata < 128)) ? (char)rxdata : '?'); + m_uart[ch].regs.utrstat &= ~1; // [bit 0] Receive buffer data ready + } + break; + } + return data; +} + +void s3c44b0_device::uart_w(int ch, UINT32 offset, UINT32 data, UINT32 mem_mask) +{ + COMBINE_DATA(&((UINT32*)&m_uart[ch].regs)[offset]); + switch (offset) + { + case S3C44B0_UTXH : + { + UINT8 txdata = data & 0xFF; + verboselog(machine(), 5, "UART %d write %02X (%c)\n", ch, txdata, ((txdata >= 32) && (txdata < 128)) ? (char)txdata : '?'); +#ifdef UART_PRINTF + printf( "%c", ((txdata >= 32) && (txdata < 128)) ? (char)txdata : '?'); +#endif + } + break; + case S3C44B0_UBRDIV : + { + UINT32 mclk, hz; + mclk = get_mclk(); + hz = (mclk / (m_uart->regs.ubrdiv + 1)) / 16; + verboselog(machine(), 5, "UART %d - mclk %08X hz %08X\n", ch, mclk, hz); + m_uart->timer->adjust(attotime::from_hz(hz), ch, attotime::from_hz(hz)); + } + break; + } +} + +READ32_MEMBER( s3c44b0_device::uart_0_r ) +{ + UINT32 data = uart_r(0, offset); +// verboselog(machine(), 9, "(UART 0) %08X -> %08X\n", S3C44B0_BASE_UART_0 + (offset << 2), data); + return data; +} + +READ32_MEMBER( s3c44b0_device::uart_1_r ) +{ + UINT32 data = uart_r(1, offset); +// verboselog(machine(), 9, "(UART 1) %08X -> %08X\n", S3C44B0_BASE_UART_1 + (offset << 2), data); + return data; +} + +WRITE32_MEMBER( s3c44b0_device::uart_0_w ) +{ + verboselog(machine(), 9, "(UART 0) %08X <- %08X (%08X)\n", S3C44B0_BASE_UART_0 + (offset << 2), data, mem_mask); + uart_w(0, offset, data, mem_mask); +} + +WRITE32_MEMBER( s3c44b0_device::uart_1_w ) +{ + verboselog(machine(), 9, "(UART 1) %08X <- %08X (%08X)\n", S3C44B0_BASE_UART_1 + (offset << 2), data, mem_mask); + uart_w(1, offset, data, mem_mask); +} + +void s3c44b0_device::uart_fifo_w(int uart, UINT8 data) +{ +// printf("s3c44b0_uart_fifo_w (%c)\n", data); + m_uart[uart].regs.urxh = data; + m_uart[uart].regs.utrstat |= 1; // [bit 0] Receive buffer data ready +} + +TIMER_CALLBACK_MEMBER( s3c44b0_device::uart_timer_exp ) +{ + int ch = param; + verboselog(machine(), 2, "UART %d timer callback\n", ch); + if ((m_uart->regs.ucon & (1 << 9)) != 0) + { + const int ch_int[] = { S3C44B0_INT_UTXD0, S3C44B0_INT_UTXD1 }; + request_irq(ch_int[ch]); + } +} + +/* Watchdog Timer */ + +UINT16 s3c44b0_device::wdt_calc_current_count() +{ + return 0; +} + +READ32_MEMBER( s3c44b0_device::wdt_r ) +{ + UINT32 data = ((UINT32*)&m_wdt.regs)[offset]; + switch (offset) + { + case S3C44B0_WTCNT : + { + // is wdt active? + if ((m_wdt.regs.wtcon & (1 << 5)) != 0) + { + data = wdt_calc_current_count(); + } + } + break; + } + verboselog(machine(), 9, "(WDT) %08X -> %08X\n", S3C44B0_BASE_WDT + (offset << 2), data); + return data; +} + +void s3c44b0_device::wdt_start() +{ + UINT32 mclk, prescaler, clock; + double freq, hz; + verboselog(machine(), 1, "WDT start\n"); + mclk = get_mclk(); + prescaler = BITS(m_wdt.regs.wtcon, 15, 8); + clock = 16 << BITS(m_wdt.regs.wtcon, 4, 3); + freq = (double)mclk / (prescaler + 1) / clock; + hz = freq / m_wdt.regs.wtcnt; + verboselog(machine(), 5, "WDT mclk %d prescaler %d clock %d freq %f hz %f\n", mclk, prescaler, clock, freq, hz); + m_wdt.timer->adjust(attotime::from_hz(hz), 0, attotime::from_hz(hz)); +} + +void s3c44b0_device::wdt_stop() +{ + verboselog(machine(), 1, "WDT stop\n"); + m_wdt.regs.wtcnt = wdt_calc_current_count(); + m_wdt.timer->adjust(attotime::never, 0); +} + +void s3c44b0_device::wdt_recalc() +{ + if ((m_wdt.regs.wtcon & (1 << 5)) != 0) + wdt_start(); + else + wdt_stop(); +} + +WRITE32_MEMBER( s3c44b0_device::wdt_w ) +{ + UINT32 old_value = ((UINT32*)&m_wdt.regs)[offset]; + verboselog(machine(), 9, "(WDT) %08X <- %08X\n", S3C44B0_BASE_WDT + (offset << 2), data); + COMBINE_DATA(&((UINT32*)&m_wdt.regs)[offset]); + switch (offset) + { + case S3C44B0_WTCON : + { + if ((data & (1 << 5)) != (old_value & (1 << 5))) + { + wdt_recalc(); + } + } + break; + } +} + +TIMER_CALLBACK_MEMBER( s3c44b0_device::wdt_timer_exp ) +{ + verboselog(machine(), 2, "WDT timer callback\n"); + if ((m_wdt.regs.wtcon & (1 << 2)) != 0) + { + request_irq(S3C44B0_INT_WDT); + } + if ((m_wdt.regs.wtcon & (1 << 0)) != 0) + { + //s3c44b0_reset(); + fatalerror("s3c44b0_reset\n"); + } +} + +/* CPU Wrapper */ + +READ32_MEMBER( s3c44b0_device::cpuwrap_r ) +{ + UINT32 data = ((UINT32*)&m_cpuwrap.regs)[offset]; + verboselog(machine(), 9, "(CPUWRAP) %08X -> %08X\n", S3C44B0_BASE_CPU_WRAPPER + (offset << 2), data); + return data; +} + +WRITE32_MEMBER( s3c44b0_device::cpuwrap_w ) +{ + verboselog(machine(), 9, "(CPUWRAP) %08X <- %08X\n", S3C44B0_BASE_CPU_WRAPPER + (offset << 2), data); + COMBINE_DATA(&((UINT32*)&m_cpuwrap.regs)[offset]); +} + +/* A/D Converter */ + +READ32_MEMBER( s3c44b0_device::adc_r ) +{ + UINT32 data = ((UINT32*)&m_adc.regs)[offset]; + verboselog(machine(), 9, "(ADC) %08X -> %08X\n", S3C44B0_BASE_ADC + (offset << 2), data); + return data; +} + +void s3c44b0_device::adc_start() +{ + UINT32 mclk, prescaler; + double freq, hz; + verboselog(machine(), 1, "ADC start\n"); + mclk = get_mclk(); + prescaler = BITS(m_adc.regs.adcpsr, 7, 0); + freq = (double)mclk / (2 * (prescaler + 1)) / 16; + hz = freq / 1; //m_wdt.regs.wtcnt; + verboselog(machine(), 5, "ADC mclk %d prescaler %d freq %f hz %f\n", mclk, prescaler, freq, hz); + m_adc.timer->adjust(attotime::from_hz(hz), 0); +} + +void s3c44b0_device::adc_stop() +{ + verboselog(machine(), 1, "ADC stop\n"); + m_adc.timer->adjust(attotime::never, 0); +} + +void s3c44b0_device::adc_recalc() +{ + if ((m_adc.regs.adccon & (1 << 0)) != 0) + adc_start(); + else + adc_stop(); +} + +WRITE32_MEMBER( s3c44b0_device::adc_w ) +{ + UINT32 old_value = ((UINT32*)&m_wdt.regs)[offset]; + verboselog(machine(), 9, "(ADC) %08X <- %08X\n", S3C44B0_BASE_ADC + (offset << 2), data); + COMBINE_DATA(&((UINT32*)&m_adc.regs)[offset]); + switch (offset) + { + case S3C44B0_ADCCON : + { + if ((data & (1 << 0)) != (old_value & (1 << 0))) + { + adc_recalc(); + } + m_adc.regs.adccon &= ~(1 << 0); // "this bit is cleared after the start-up" + } + break; + } +} + +TIMER_CALLBACK_MEMBER( s3c44b0_device::adc_timer_exp ) +{ + verboselog(machine(), 2, "ADC timer callback\n"); + m_adc.regs.adccon |= (1 << 6); + request_irq(S3C44B0_INT_ADC); +} + +/* SIO */ + +READ32_MEMBER( s3c44b0_device::sio_r ) +{ + UINT32 data = ((UINT32*)&m_sio.regs)[offset]; + verboselog(machine(), 9, "(SIO) %08X -> %08X\n", S3C44B0_BASE_SIO + (offset << 2), data); + return data; +} + +void s3c44b0_device::sio_start() +{ + UINT32 mclk, prescaler; + double freq, hz; + verboselog(machine(), 1, "SIO start\n"); + mclk = get_mclk(); + prescaler = BITS(m_sio.regs.sbrdr, 11, 0); + freq = (double)mclk / 2 / (prescaler + 1); + hz = freq / 1; //m_wdt.regs.wtcnt; + verboselog(machine(), 5, "SIO mclk %d prescaler %d freq %f hz %f\n", mclk, prescaler, freq, hz); + m_sio.timer->adjust(attotime::from_hz(hz), 0); +// printf("SIO transmit %02X (%c)\n", m_sio.regs.siodat, ((m_sio.regs.siodat >= 32) && (m_sio.regs.siodat < 128)) ? (char)m_sio.regs.siodat : '?'); +} + +void s3c44b0_device::sio_stop() +{ + verboselog(machine(), 1, "SIO stop\n"); +// m_wdt.regs.wtcnt = s3c44b0_wdt_calc_current_count( device); + m_sio.timer->adjust(attotime::never, 0); +} + +void s3c44b0_device::sio_recalc() +{ + if ((m_sio.regs.siocon & (1 << 3)) != 0) + sio_start(); + else + sio_stop(); +} + +WRITE32_MEMBER( s3c44b0_device::sio_w ) +{ + UINT32 old_value = ((UINT32*)&m_sio.regs)[offset]; + verboselog(machine(), 9, "(SIO) %08X <- %08X\n", S3C44B0_BASE_SIO + (offset << 2), data); + COMBINE_DATA(&((UINT32*)&m_sio.regs)[offset]); + switch (offset) + { + case S3C44B0_SIOCON : + { + if ((old_value & (1 << 3)) != (data & (1 << 3))) + { + sio_recalc(); + } + m_sio.regs.siocon &= ~(1 << 3); // "This bit is cleared just after writing this bit as 1." + } + break; + } +} + +TIMER_CALLBACK_MEMBER( s3c44b0_device::sio_timer_exp ) +{ + verboselog(machine(), 2, "SIO timer callback\n"); + + m_sio.regs.siodat = 0x00; // TEST + + if ((m_sio.regs.siocon & (1 << 0)) != 0) + { + request_irq(S3C44B0_INT_SIO); + } +} + +/* IIS */ + +inline void s3c44b0_device::iface_i2s_data_w(address_space &space, int ch, UINT16 data) +{ + if (!m_data_w_cb.isnull()) + (m_data_w_cb)(ch, data, 0); +} + +void s3c44b0_device::iis_start() +{ + UINT32 mclk; + int prescaler; + double freq, hz; + const int div[] = { 2, 4, 6, 8, 10, 12, 14, 16, 1, 0, 3, 0, 5, 0, 7, 0 }; + verboselog(machine(), 1, "IIS start\n"); + mclk = get_mclk(); + prescaler = BITS(m_iis.regs.iispsr, 3, 0); + freq = (double)mclk / div[prescaler]; + hz = freq / 256 * 2; + verboselog(machine(), 5, "IIS mclk %d prescaler %d freq %f hz %f\n", mclk, prescaler, freq, hz); + m_iis.timer->adjust(attotime::from_hz(hz), 0, attotime::from_hz(hz)); +} + +void s3c44b0_device::iis_stop() +{ + verboselog(machine(), 1, "IIS stop\n"); + m_iis.timer->adjust(attotime::never, 0); +} + +READ32_MEMBER( s3c44b0_device::iis_r ) +{ + UINT32 data = ((UINT32*)&m_iis.regs)[offset]; + verboselog(machine(), 9, "(IIS) %08X -> %08X\n", S3C44B0_BASE_IIS + (offset << 2), data); + return data; +} + +WRITE32_MEMBER( s3c44b0_device::iis_w ) +{ + UINT32 old_value = ((UINT32*)&m_iis.regs)[offset]; + verboselog(machine(), 9, "(IIS) %08X <- %08X\n", S3C44B0_BASE_IIS + (offset << 2), data); + COMBINE_DATA(&((UINT32*)&m_iis.regs)[offset]); + switch (offset) + { + case S3C44B0_IISCON : + { + if ((old_value & (1 << 0)) != (data & (1 << 0))) + { + if ((data & (1 << 0)) != 0) + { + iis_start(); + } + else + { + iis_stop(); + } + } + } + break; + case S3C44B0_IISFIFO : + { + if (ACCESSING_BITS_16_31) + { + m_iis.fifo[m_iis.fifo_index++] = BITS(data, 31, 16); + } + if (ACCESSING_BITS_0_15) + { + m_iis.fifo[m_iis.fifo_index++] = BITS(data, 15, 0); + } + if (m_iis.fifo_index == 2) + { + m_iis.fifo_index = 0; + iface_i2s_data_w(space, 0, m_iis.fifo[0]); + iface_i2s_data_w(space, 1, m_iis.fifo[1]); + } + } + break; + } +} + +TIMER_CALLBACK_MEMBER( s3c44b0_device::iis_timer_exp ) +{ + verboselog(machine(), 2, "IIS timer callback\n"); + if ((m_iis.regs.iiscon & (1 << 5)) != 0) + { + bdma_request_iis(); + } +} + +/* ZDMA */ + +void s3c44b0_device::zdma_trigger(int ch) +{ + address_space &space = m_cpu->space(AS_PROGRAM); + UINT32 saddr, daddr; + int dal, dst, opt, das, cnt; + verboselog(machine(), 5, "s3c44b0_zdma_trigger %d\n", ch); + dst = BITS(m_zdma->regs.dcsrc, 31, 30); + dal = BITS(m_zdma->regs.dcsrc, 29, 28); + saddr = BITS(m_zdma->regs.dcsrc, 27, 0); + verboselog(machine(), 5, "dst %d dal %d saddr %08X\n", dst, dal, saddr); + opt = BITS(m_zdma->regs.dcdst, 31, 30); + das = BITS(m_zdma->regs.dcdst, 29, 28); + daddr = BITS(m_zdma->regs.dcdst, 27, 0); + verboselog(machine(), 5, "opt %d das %d daddr %08X\n", opt, das, daddr); + cnt = BITS(m_zdma->regs.dccnt, 19, 0); + verboselog(machine(), 5, "icnt %08X\n", cnt); + while (cnt > 0) + { + verboselog(machine(), 9, "[%08X] -> [%08X]\n", saddr, daddr); + switch (dst) + { + case 0 : space.write_byte(daddr, space.read_byte(saddr)); break; + case 1 : space.write_word(daddr, space.read_word(saddr)); break; + case 2 : space.write_dword(daddr, space.read_dword(saddr)); break; + } + switch (dal) + { + case 1 : saddr += (1 << dst); break; + case 2 : saddr -= (1 << dst); break; + } + switch (das) + { + case 1 : daddr += (1 << dst); break; + case 2 : daddr -= (1 << dst); break; + } + cnt -= (1 << dst); + } + m_zdma->regs.dcsrc = CLR_BITS(m_zdma->regs.dcsrc, 27, 0) | saddr; + m_zdma->regs.dcdst = CLR_BITS(m_zdma->regs.dcdst, 27, 0) | daddr; + m_zdma->regs.dccnt = CLR_BITS(m_zdma->regs.dcdst, 19, 0) | cnt; + if (cnt == 0) + { + if ((m_zdma->regs.dccnt & (1 << 23)) != 0) + { + const int ch_int[] = { S3C44B0_INT_ZDMA0, S3C44B0_INT_ZDMA1 }; + request_irq(ch_int[ch]); + } + } +} + +void s3c44b0_device::zdma_start(int ch) +{ + verboselog(machine(), 5, "ZDMA %d start\n", ch); + m_zdma->regs.dcsrc = m_zdma->regs.disrc; + m_zdma->regs.dcdst = m_zdma->regs.didst; + m_zdma->regs.dccnt = m_zdma->regs.dicnt; + zdma_trigger(ch); +} + +UINT32 s3c44b0_device::zdma_r(int ch, UINT32 offset) +{ + UINT32 data = ((UINT32*)&m_zdma[ch].regs)[offset]; + return data; +} + +void s3c44b0_device::zdma_w(int ch, UINT32 offset, UINT32 data, UINT32 mem_mask) +{ + UINT32 old_value = ((UINT32*)&m_zdma[ch].regs)[offset]; + COMBINE_DATA(&((UINT32*)&m_zdma[ch].regs)[offset]); + switch (offset) + { + case S3C44B0_DCON : + { + if ((old_value & 3) != (data & 3)) + { + switch (data & 3) + { + case 1 : zdma_start(ch); break; + } + } + m_zdma[ch].regs.dcon &= ~3; // "After writing 01,10,11, CMD bit is cleared automatically" + } + break; + } +} + +READ32_MEMBER( s3c44b0_device::zdma_0_r ) +{ + UINT32 data = zdma_r(0, offset); + verboselog(machine(), 9, "(ZDMA 0) %08X -> %08X\n", S3C44B0_BASE_ZDMA_0 + (offset << 2), data); + return data; +} + +READ32_MEMBER( s3c44b0_device::zdma_1_r ) +{ + UINT32 data = zdma_r(1, offset); + verboselog(machine(), 9, "(ZDMA 1) %08X -> %08X\n", S3C44B0_BASE_ZDMA_1 + (offset << 2), data); + return data; +} + +WRITE32_MEMBER( s3c44b0_device::zdma_0_w ) +{ + verboselog(machine(), 9, "(ZDMA 0) %08X <- %08X (%08X)\n", S3C44B0_BASE_ZDMA_0 + (offset << 2), data, mem_mask); + zdma_w(0, offset, data, mem_mask); +} + +WRITE32_MEMBER( s3c44b0_device::zdma_1_w ) +{ + verboselog(machine(), 9, "(ZDMA 1) %08X <- %08X (%08X)\n", S3C44B0_BASE_ZDMA_1 + (offset << 2), data, mem_mask); + zdma_w(1, offset, data, mem_mask); +} + +TIMER_CALLBACK_MEMBER( s3c44b0_device::zdma_timer_exp ) +{ + int ch = param; + verboselog(machine(), 2, "ZDMA %d timer callback\n", ch); +} + +/* BDMA */ + +void s3c44b0_device::bdma_trigger(int ch) +{ + address_space &space = m_cpu->space(AS_PROGRAM); + UINT32 saddr, daddr; + int dal, dst, tdm, das, cnt; + verboselog(machine(), 5, "s3c44b0_bdma_trigger %d\n", ch); + dst = BITS(m_bdma->regs.dcsrc, 31, 30); + dal = BITS(m_bdma->regs.dcsrc, 29, 28); + saddr = BITS(m_bdma->regs.dcsrc, 27, 0); + verboselog(machine(), 5, "dst %d dal %d saddr %08X\n", dst, dal, saddr); + tdm = BITS(m_bdma->regs.dcdst, 31, 30); + das = BITS(m_bdma->regs.dcdst, 29, 28); + daddr = BITS(m_bdma->regs.dcdst, 27, 0); + verboselog(machine(), 5, "tdm %d das %d daddr %08X\n", tdm, das, daddr); + cnt = BITS(m_bdma->regs.dccnt, 19, 0); + verboselog(machine(), 5, "icnt %08X\n", cnt); + verboselog(machine(), 9, "[%08X] -> [%08X]\n", saddr, daddr); + switch (dst) + { + case 0 : space.write_byte(daddr, space.read_byte(saddr)); break; + case 1 : space.write_word(daddr, space.read_word(saddr)); break; + case 2 : space.write_dword(daddr, space.read_dword(saddr)); break; + } + switch (dal) + { + case 1 : saddr += (1 << dst); break; + case 2 : saddr -= (1 << dst); break; + } + switch (das) + { + case 1 : daddr += (1 << dst); break; + case 2 : daddr -= (1 << dst); break; + } + cnt -= (1 << dst); + m_bdma->regs.dcsrc = CLR_BITS(m_bdma->regs.dcsrc, 27, 0) | saddr; + m_bdma->regs.dcdst = CLR_BITS(m_bdma->regs.dcdst, 27, 0) | daddr; + m_bdma->regs.dccnt = CLR_BITS(m_bdma->regs.dcdst, 19, 0) | cnt; + if (cnt == 0) + { + if ((m_bdma->regs.dccnt & (1 << 23)) != 0) + { + const int ch_int[] = { S3C44B0_INT_BDMA0, S3C44B0_INT_BDMA1 }; + request_irq(ch_int[ch]); + } + } +} + +void s3c44b0_device::bdma_request_iis() +{ + verboselog(machine(), 5, "s3c44b0_bdma_request_iis\n"); + bdma_trigger(0); +} + +UINT32 s3c44b0_device::bdma_r(int ch, UINT32 offset) +{ + UINT32 data = ((UINT32*)&m_bdma[ch].regs)[offset]; + return data; +} + +void s3c44b0_device::bdma_start(int ch) +{ + verboselog(machine(), 5, "BDMA %d start\n", ch); + int qsc = BITS(m_bdma->regs.dicnt, 31, 30); + if ((ch == 0) && (qsc == 1)) + { + // IIS + } + else + { + printf( "s3c44b0_bdma_start - todo\n"); + } + m_bdma->regs.dcsrc = m_bdma->regs.disrc; + m_bdma->regs.dcdst = m_bdma->regs.didst; + m_bdma->regs.dccnt = m_bdma->regs.dicnt; +} + +void s3c44b0_device::bdma_stop(int ch) +{ + verboselog(machine(), 5, "BDMA %d stop\n", ch); + m_bdma[ch].timer->adjust(attotime::never, ch); +} + +void s3c44b0_device::bdma_w(int ch, UINT32 offset, UINT32 data, UINT32 mem_mask) +{ + UINT32 old_value = ((UINT32*)&m_bdma[ch].regs)[offset]; + COMBINE_DATA(&((UINT32*)&m_bdma[ch].regs)[offset]); + switch (offset) + { + case S3C44B0_DICNT : + { + if ((old_value & (1 << 20)) != (data & (1 << 20))) + { + if ((data & (1 << 20)) != 0) + { + bdma_start(ch); + } + else + { + bdma_stop(ch); + } + } + } + break; + } +} + +READ32_MEMBER( s3c44b0_device::bdma_0_r ) +{ + UINT32 data = bdma_r(0, offset); + verboselog(machine(), 9, "(BDMA 0) %08X -> %08X\n", S3C44B0_BASE_BDMA_0 + (offset << 2), data); + return data; +} + +READ32_MEMBER( s3c44b0_device::bdma_1_r ) +{ + UINT32 data = bdma_r(1, offset); + verboselog(machine(), 9, "(BDMA 1) %08X -> %08X\n", S3C44B0_BASE_BDMA_1 + (offset << 2), data); + return data; +} + +WRITE32_MEMBER( s3c44b0_device::bdma_0_w ) +{ + verboselog(machine(), 9, "(BDMA 0) %08X <- %08X (%08X)\n", S3C44B0_BASE_BDMA_0 + (offset << 2), data, mem_mask); + bdma_w(0, offset, data, mem_mask); +} + +WRITE32_MEMBER( s3c44b0_device::bdma_1_w ) +{ + verboselog(machine(), 9, "(BDMA 1) %08X <- %08X (%08X)\n", S3C44B0_BASE_BDMA_1 + (offset << 2), data, mem_mask); + bdma_w(1, offset, data, mem_mask); +} + +TIMER_CALLBACK_MEMBER( s3c44b0_device::bdma_timer_exp ) +{ + int ch = param; + verboselog(machine(), 2, "BDMA %d timer callback\n", ch); +} diff --git a/src/devices/machine/s3c44b0.h b/src/devices/machine/s3c44b0.h new file mode 100644 index 00000000000..462bda280d2 --- /dev/null +++ b/src/devices/machine/s3c44b0.h @@ -0,0 +1,814 @@ +// license:BSD-3-Clause +// copyright-holders:Tim Schuerewegen +/******************************************************************************* + + Samsung S3C44B0 + + (c) 2011 Tim Schuerewegen + +*******************************************************************************/ + +#ifndef __S3C44B0_H__ +#define __S3C44B0_H__ + + +/******************************************************************************* + MACROS & CONSTANTS +*******************************************************************************/ + +/* Memory Controller */ + +#define S3C44B0_BASE_MEMCON 0x01C80000 + +/* Interrupt Controller */ + +#define S3C44B0_BASE_INT 0x01E00000 + +#define S3C44B0_INTCON (0x00 / 4) // Interrupt Control +#define S3C44B0_INTPND (0x04 / 4) // Interrupt Request Status +#define S3C44B0_INTMOD (0x08 / 4) // Interrupt Mode Control +#define S3C44B0_INTMSK (0x0C / 4) // Interrupt Mask Control +#define S3C44B0_I_PSLV (0x10 / 4) +#define S3C44B0_I_PMST (0x14 / 4) +#define S3C44B0_I_CSLV (0x18 / 4) +#define S3C44B0_I_CMST (0x1C / 4) +#define S3C44B0_I_ISPR (0x20 / 4) +#define S3C44B0_I_ISPC (0x24 / 4) +#define S3C44B0_F_ISPR (0x38 / 4) +#define S3C44B0_F_ISPC (0x3C / 4) + +/* ZDMA & BDMA */ + +#define S3C44B0_BASE_ZDMA_0 0x01E80000 +#define S3C44B0_BASE_ZDMA_1 0x01E80020 +#define S3C44B0_BASE_BDMA_0 0x01F80000 +#define S3C44B0_BASE_BDMA_1 0x01F80020 + +#define S3C44B0_DCON (0x00 / 4) // DMA Control +#define S3C44B0_DISRC (0x04 / 4) // DMA Initial Source +#define S3C44B0_DIDST (0x08 / 4) // DMA Initial Destination +#define S3C44B0_DICNT (0x0C / 4) // DMA Initial Transfer Count +#define S3C44B0_DCSRC (0x10 / 4) // DMA Current Source Address +#define S3C44B0_DCDST (0x14 / 4) // DMA Current Destination Address +#define S3C44B0_DCCNT (0x18 / 4) // DMA Current Transfer Count + +/* Clock & Power Management */ + +#define S3C44B0_BASE_CLKPOW 0x01D80000 + +#define S3C44B0_PLLCON (0x00 / 4) // PLL Control +#define S3C44B0_CLKCON (0x04 / 4) // Clock Generator Control +#define S3C44B0_CLKSLOW (0x08 / 4) // Slow Clock Control +#define S3C44B0_LOCKTIME (0x0C / 4) // PLL lock time Counter + +/* LCD Controller */ + +#define S3C44B0_BASE_LCD 0x01F00000 + +#define S3C44B0_LCDCON1 (0x00 / 4) // LCD Control 1 +#define S3C44B0_LCDCON2 (0x04 / 4) // LCD Control 2 +#define S3C44B0_LCDSADDR1 (0x08 / 4) // Frame Buffer Start Address 1 +#define S3C44B0_LCDSADDR2 (0x0C / 4) // Frame Buffer Start Address 2 +#define S3C44B0_LCDSADDR3 (0x10 / 4) // Virtual Screen Address Set +#define S3C44B0_REDLUT (0x14 / 4) // STN: Red Lookup Table +#define S3C44B0_GREENLUT (0x18 / 4) // STN: Green Lookup Table +#define S3C44B0_BLUELUT (0x1C / 4) // STN: Blue Lookup Table +#define S3C44B0_LCDCON3 (0x40 / 4) // LCD Control 3 +#define S3C44B0_DITHMODE (0x44 / 4) // STN: Dithering Mode + +/* UART */ + +#define S3C44B0_BASE_UART_0 0x01D00000 +#define S3C44B0_BASE_UART_1 0x01D04000 + +#define S3C44B0_ULCON (0x00 / 4) // UART Line Control +#define S3C44B0_UCON (0x04 / 4) // UART Control +#define S3C44B0_UFCON (0x08 / 4) // UART FIFO Control +#define S3C44B0_UMCON (0x0C / 4) // UART Modem Control +#define S3C44B0_UTRSTAT (0x10 / 4) // UART Tx/Rx Status +#define S3C44B0_UERSTAT (0x14 / 4) // UART Rx Error Status +#define S3C44B0_UFSTAT (0x18 / 4) // UART FIFO Status +#define S3C44B0_UMSTAT (0x1C / 4) // UART Modem Status +#define S3C44B0_UTXH (0x20 / 4) // UART Transmission Hold +#define S3C44B0_URXH (0x24 / 4) // UART Receive Buffer +#define S3C44B0_UBRDIV (0x28 / 4) // UART Baud Rate Divisor + +/* SIO */ + +#define S3C44B0_BASE_SIO 0x01D14000 + +#define S3C44B0_SIOCON (0x00 / 4) // SIO Control +#define S3C44B0_SIODAT (0x04 / 4) // SIO Data +#define S3C44B0_SBRDR (0x08 / 4) // SIO Baud Rate Prescaler +#define S3C44B0_ITVCNT (0x0C / 4) // SIO Interval Counter +#define S3C44B0_DCNTZ (0x10 / 4) // SIO DMA Count Zero + +/* PWM Timer */ + +#define S3C44B0_BASE_PWM 0x01D50000 + +#define S3C44B0_TCFG0 (0x00 / 4) // Timer Configuration +#define S3C44B0_TCFG1 (0x04 / 4) // Timer Configuration +#define S3C44B0_TCON (0x08 / 4) // Timer Control +#define S3C44B0_TCNTB0 (0x0C / 4) // Timer Count Buffer 0 +#define S3C44B0_TCMPB0 (0x10 / 4) // Timer Compare Buffer 0 +#define S3C44B0_TCNTO0 (0x14 / 4) // Timer Count Observation 0 +#define S3C44B0_TCNTB1 (0x18 / 4) // Timer Count Buffer 1 +#define S3C44B0_TCMPB1 (0x1C / 4) // Timer Compare Buffer 1 +#define S3C44B0_TCNTO1 (0x20 / 4) // Timer Count Observation 1 +#define S3C44B0_TCNTB2 (0x24 / 4) // Timer Count Buffer 2 +#define S3C44B0_TCMPB2 (0x28 / 4) // Timer Compare Buffer 2 +#define S3C44B0_TCNTO2 (0x2C / 4) // Timer Count Observation 2 +#define S3C44B0_TCNTB3 (0x30 / 4) // Timer Count Buffer 3 +#define S3C44B0_TCMPB3 (0x34 / 4) // Timer Compare Buffer 3 +#define S3C44B0_TCNTO3 (0x38 / 4) // Timer Count Observation 3 +#define S3C44B0_TCNTB4 (0x3C / 4) // Timer Count Buffer 4 +#define S3C44B0_TCMPB4 (0x40 / 4) // Timer Compare Buffer 4 +#define S3C44B0_TCNTO4 (0x44 / 4) // Timer Count Observation 4 +#define S3C44B0_TCNTB5 (0x48 / 4) // Timer Count Buffer 5 +#define S3C44B0_TCNTO5 (0x4C / 4) // Timer Count Observation 5 + +/* USB Device */ + +#define S3C44B0_BASE_USBDEV 0x15200140 + +/* Watchdog Timer */ + +#define S3C44B0_BASE_WDT 0x01D30000 + +#define S3C44B0_WTCON (0x00 / 4) // Watchdog Timer Mode +#define S3C44B0_WTDAT (0x04 / 4) // Watchdog Timer Data +#define S3C44B0_WTCNT (0x08 / 4) // Watchdog Timer Count + +/* IIC */ + +#define S3C44B0_BASE_IIC 0x01D60000 + +#define S3C44B0_IICCON (0x00 / 4) // IIC Control +#define S3C44B0_IICSTAT (0x04 / 4) // IIC Status +#define S3C44B0_IICADD (0x08 / 4) // IIC Address +#define S3C44B0_IICDS (0x0C / 4) // IIC Data Shift + +/* IIS */ + +#define S3C44B0_BASE_IIS 0x01D18000 + +#define S3C44B0_IISCON (0x00 / 4) // IIS Control +#define S3C44B0_IISMOD (0x04 / 4) // IIS Mode +#define S3C44B0_IISPSR (0x08 / 4) // IIS Prescaler +#define S3C44B0_IISFCON (0x0C / 4) // IIS FIFO Control +#define S3C44B0_IISFIFO (0x10 / 4) // IIS FIFO Entry + +/* I/O Port */ + +#define S3C44B0_BASE_GPIO 0x01D20000 + +#define S3C44B0_GPACON (0x00 / 4) // Port A Control +#define S3C44B0_GPADAT (0x04 / 4) // Port A Data +#define S3C44B0_GPBCON (0x08 / 4) // Port B Control +#define S3C44B0_GPBDAT (0x0C / 4) // Port B Data +#define S3C44B0_GPCCON (0x10 / 4) // Port C Control +#define S3C44B0_GPCDAT (0x14 / 4) // Port C Data +#define S3C44B0_GPCUP (0x18 / 4) // Pull-up Control C +#define S3C44B0_GPDCON (0x1C / 4) // Port D Control +#define S3C44B0_GPDDAT (0x20 / 4) // Port D Data +#define S3C44B0_GPDUP (0x24 / 4) // Pull-up Control D +#define S3C44B0_GPECON (0x28 / 4) // Port E Control +#define S3C44B0_GPEDAT (0x2C / 4) // Port E Data +#define S3C44B0_GPEUP (0x30 / 4) // Pull-up Control E +#define S3C44B0_GPFCON (0x34 / 4) // Port F Control +#define S3C44B0_GPFDAT (0x38 / 4) // Port F Data +#define S3C44B0_GPFUP (0x3C / 4) // Pull-up Control F +#define S3C44B0_GPGCON (0x40 / 4) // Port G Control +#define S3C44B0_GPGDAT (0x44 / 4) // Port G Data +#define S3C44B0_GPGUP (0x48 / 4) // Pull-up Control G +#define S3C44B0_SPUCR (0x4C / 4) // Special Pull-up +#define S3C44B0_EXTINT (0x50 / 4) // External Interrupt Control +#define S3C44B0_EXTINTPND (0x54 / 4) // External Interrupt Pending + +#define S3C44B0_GPADAT_MASK 0x000003FF +#define S3C44B0_GPBDAT_MASK 0x000007FF +#define S3C44B0_GPCDAT_MASK 0x0000FFFF +#define S3C44B0_GPDDAT_MASK 0x000000FF +#define S3C44B0_GPEDAT_MASK 0x000001FF +#define S3C44B0_GPFDAT_MASK 0x000001FF +#define S3C44B0_GPGDAT_MASK 0x000000FF + +/* RTC */ + +#define S3C44B0_BASE_RTC 0x01D70040 + +#define S3C44B0_RTCCON (0x00 / 4) // RTC Control +#define S3C44B0_RTCALM (0x10 / 4) // RTC Alarm Control +#define S3C44B0_ALMSEC (0x14 / 4) // Alarm Second +#define S3C44B0_ALMMIN (0x18 / 4) // Alarm Minute +#define S3C44B0_ALMHOUR (0x1C / 4) // Alarm Hour +#define S3C44B0_ALMDAY (0x20 / 4) // Alarm Day +#define S3C44B0_ALMMON (0x24 / 4) // Alarm Month +#define S3C44B0_ALMYEAR (0x28 / 4) // Alarm Year +#define S3C44B0_RTCRST (0x2C / 4) // RTC Round Reset +#define S3C44B0_BCDSEC (0x30 / 4) // BCD Second +#define S3C44B0_BCDMIN (0x34 / 4) // BCD Minute +#define S3C44B0_BCDHOUR (0x38 / 4) // BCD Hour +#define S3C44B0_BCDDAY (0x3C / 4) // BCD Day +#define S3C44B0_BCDDOW (0x40 / 4) // BCD Day of Week +#define S3C44B0_BCDMON (0x44 / 4) // BCD Month +#define S3C44B0_BCDYEAR (0x48 / 4) // BCD Year +#define S3C44B0_TICNT (0x4C / 4) // Tick Time count + +/* A/D Converter */ + +#define S3C44B0_BASE_ADC 0x01D40000 + +#define S3C44B0_ADCCON (0x00 / 4) // ADC Control +#define S3C44B0_ADCPSR (0x04 / 4) // ADC Prescaler +#define S3C44B0_ADCDAT (0x08 / 4) // ADC Data + +/* CPU Wrapper */ + +#define S3C44B0_BASE_CPU_WRAPPER 0x01C00000 + +#define S3C44B0_SYSCFG (0x00 / 4) // System Configuration +#define S3C44B0_NCACHBE0 (0x04 / 4) // Non Cacheable Area 0 +#define S3C44B0_NCACHBE1 (0x08 / 4) // Non Cacheable Area 1 + +/* ... */ + +#define S3C44B0_INT_ADC 0 +#define S3C44B0_INT_RTC 1 +#define S3C44B0_INT_UTXD1 2 +#define S3C44B0_INT_UTXD0 3 +#define S3C44B0_INT_SIO 4 +#define S3C44B0_INT_IIC 5 +#define S3C44B0_INT_URXD1 6 +#define S3C44B0_INT_URXD0 7 +#define S3C44B0_INT_TIMER5 8 +#define S3C44B0_INT_TIMER4 9 +#define S3C44B0_INT_TIMER3 10 +#define S3C44B0_INT_TIMER2 11 +#define S3C44B0_INT_TIMER1 12 +#define S3C44B0_INT_TIMER0 13 +#define S3C44B0_INT_UERR 14 +#define S3C44B0_INT_WDT 15 +#define S3C44B0_INT_BDMA1 16 +#define S3C44B0_INT_BDMA0 17 +#define S3C44B0_INT_ZDMA1 18 +#define S3C44B0_INT_ZDMA0 19 +#define S3C44B0_INT_TICK 20 +#define S3C44B0_INT_EINT4_7 21 +#define S3C44B0_INT_EINT3 22 +#define S3C44B0_INT_EINT2 23 +#define S3C44B0_INT_EINT1 24 +#define S3C44B0_INT_EINT0 25 + +#define S3C44B0_MODESEL_01 0 +#define S3C44B0_MODESEL_02 1 +#define S3C44B0_MODESEL_04 2 +#define S3C44B0_MODESEL_08 3 + +#define S3C44B0_PNRMODE_STN_04_DS 0 +#define S3C44B0_PNRMODE_STN_04_SS 1 +#define S3C44B0_PNRMODE_STN_08_SS 2 + +#define S3C44B0_GPIO_PORT_A S3C44B0_GPIO_PORT_A +#define S3C44B0_GPIO_PORT_B S3C44B0_GPIO_PORT_B +#define S3C44B0_GPIO_PORT_C S3C44B0_GPIO_PORT_C +#define S3C44B0_GPIO_PORT_D S3C44B0_GPIO_PORT_D +#define S3C44B0_GPIO_PORT_E S3C44B0_GPIO_PORT_E +#define S3C44B0_GPIO_PORT_F S3C44B0_GPIO_PORT_F +#define S3C44B0_GPIO_PORT_G S3C44B0_GPIO_PORT_G + + +/******************************************************************************* + MACROS / CONSTANTS + *******************************************************************************/ + + +struct s3c44b0_memcon_regs_t +{ + UINT32 data[0x34/4]; +}; + +struct s3c44b0_irq_regs_t +{ + UINT32 intcon; + UINT32 intpnd; + UINT32 intmod; + UINT32 intmsk; + UINT32 i_pslv; + UINT32 i_pmst; + UINT32 i_cslv; + UINT32 i_cmst; + UINT32 i_ispr; + UINT32 i_ispc; + UINT32 reserved[4]; + UINT32 f_ispr; + UINT32 f_ispc; +}; + +struct s3c44b0_dma_regs_t +{ + UINT32 dcon; + UINT32 disrc; + UINT32 didst; + UINT32 dicnt; + UINT32 dcsrc; + UINT32 dcdst; + UINT32 dccnt; +}; + +struct s3c44b0_clkpow_regs_t +{ + UINT32 pllcon; + UINT32 clkcon; + UINT32 clkslow; + UINT32 locktime; +}; + +struct s3c44b0_lcd_regs_t +{ + UINT32 lcdcon1; + UINT32 lcdcon2; + UINT32 lcdsaddr1; + UINT32 lcdsaddr2; + UINT32 lcdsaddr3; + UINT32 redlut; + UINT32 greenlut; + UINT32 bluelut; + UINT32 reserved[8]; + UINT32 lcdcon3; + UINT32 dithmode; +}; + +struct s3c44b0_uart_regs_t +{ + UINT32 ulcon; + UINT32 ucon; + UINT32 ufcon; + UINT32 umcon; + UINT32 utrstat; + UINT32 uerstat; + UINT32 ufstat; + UINT32 umstat; + UINT32 utxh; + UINT32 urxh; + UINT32 ubrdiv; +}; + +struct s3c44b0_sio_regs_t +{ + UINT32 siocon; + UINT32 siodat; + UINT32 sbrdr; + UINT32 itvcnt; + UINT32 dcntz; +}; + +struct s3c44b0_pwm_regs_t +{ + UINT32 tcfg0; + UINT32 tcfg1; + UINT32 tcon; + UINT32 tcntb0; + UINT32 tcmpb0; + UINT32 tcnto0; + UINT32 tcntb1; + UINT32 tcmpb1; + UINT32 tcnto1; + UINT32 tcntb2; + UINT32 tcmpb2; + UINT32 tcnto2; + UINT32 tcntb3; + UINT32 tcmpb3; + UINT32 tcnto3; + UINT32 tcntb4; + UINT32 tcmpb4; + UINT32 tcnto4; + UINT32 tcntb5; + UINT32 tcnto5; +}; + +struct s3c44b0_wdt_regs_t +{ + UINT32 wtcon; + UINT32 wtdat; + UINT32 wtcnt; +}; + +struct s3c44b0_iic_regs_t +{ + UINT32 iiccon; + UINT32 iicstat; + UINT32 iicadd; + UINT32 iicds; +}; + +struct s3c44b0_iis_regs_t +{ + UINT32 iiscon; + UINT32 iismod; + UINT32 iispsr; + UINT32 iisfcon; + UINT32 iisfifo; +}; + +struct s3c44b0_gpio_regs_t +{ + UINT32 gpacon; + UINT32 gpadat; + UINT32 gpbcon; + UINT32 gpbdat; + UINT32 gpccon; + UINT32 gpcdat; + UINT32 gpcup; + UINT32 gpdcon; + UINT32 gpddat; + UINT32 gpdup; + UINT32 gpecon; + UINT32 gpedat; + UINT32 gpeup; + UINT32 gpfcon; + UINT32 gpfdat; + UINT32 gpfup; + UINT32 gpgcon; + UINT32 gpgdat; + UINT32 gpgup; + UINT32 spucr; + UINT32 extint; + UINT32 extintpnd; +}; + +struct s3c44b0_rtc_regs_t +{ + UINT32 rtccon; + UINT32 reserved[3]; + UINT32 rtcalm; + UINT32 almsec; + UINT32 almmin; + UINT32 almhour; + UINT32 almday; + UINT32 almmon; + UINT32 almyear; + UINT32 rtcrst; + UINT32 bcdsec; + UINT32 bcdmin; + UINT32 bcdhour; + UINT32 bcdday; + UINT32 bcddow; + UINT32 bcdmon; + UINT32 bcdyear; + UINT32 ticnt; +}; + +struct s3c44b0_adc_regs_t +{ + UINT32 adccon; + UINT32 adcpsr; + UINT32 adcdat; +}; + +struct s3c44b0_cpuwrap_regs_t +{ + UINT32 syscfg; + UINT32 ncachbe0; + UINT32 ncachbe1; +}; + +struct s3c44b0_memcon_t +{ + s3c44b0_memcon_regs_t regs; +}; + +struct s3c44b0_irq_t +{ + s3c44b0_irq_regs_t regs; + int line_irq, line_fiq; +}; + +struct s3c44b0_dma_t +{ + s3c44b0_dma_regs_t regs; + emu_timer *timer; +}; + +struct s3c44b0_clkpow_t +{ + s3c44b0_clkpow_regs_t regs; +}; + +struct rectangle_t +{ + int x1, y1, x2, y2; +}; + +struct s3c44b0_lcd_t +{ + s3c44b0_lcd_regs_t regs; + emu_timer *timer; + UINT8 *bitmap; + UINT32 vramaddr_cur; + UINT32 vramaddr_max; + UINT32 offsize; + UINT32 pagewidth_cur; + UINT32 pagewidth_max; + UINT32 modesel; + UINT32 bswp; + int vpos, hpos; + double framerate; + UINT32 hpos_min, hpos_max, hpos_end, vpos_min, vpos_max, vpos_end; + attotime frame_time; + attoseconds_t frame_period, pixeltime, scantime; +}; + +struct s3c44b0_uart_t +{ + s3c44b0_uart_regs_t regs; + emu_timer *timer; +}; + +struct s3c44b0_sio_t +{ + s3c44b0_sio_regs_t regs; + emu_timer *timer; +}; + +struct s3c44b0_pwm_t +{ + s3c44b0_pwm_regs_t regs; + emu_timer *timer[6]; + UINT32 cnt[6]; + UINT32 cmp[6]; + UINT32 freq[6]; +}; + +struct s3c44b0_wdt_t +{ + s3c44b0_wdt_regs_t regs; + emu_timer *timer; +}; + +struct s3c44b0_iic_t +{ + s3c44b0_iic_regs_t regs; + emu_timer *timer; + int count; +}; + +struct s3c44b0_iis_t +{ + s3c44b0_iis_regs_t regs; + emu_timer *timer; + UINT16 fifo[16/2]; + int fifo_index; +}; + +struct s3c44b0_gpio_t +{ + s3c44b0_gpio_regs_t regs; +}; + +struct s3c44b0_rtc_t +{ + s3c44b0_rtc_regs_t regs; + emu_timer *timer_tick_count; + emu_timer *timer_update; +}; + +struct s3c44b0_adc_t +{ + s3c44b0_adc_regs_t regs; + emu_timer *timer; +}; + +struct s3c44b0_cpuwrap_t +{ + s3c44b0_cpuwrap_regs_t regs; +}; + + +enum +{ + S3C44B0_GPIO_PORT_A = 0, + S3C44B0_GPIO_PORT_B, + S3C44B0_GPIO_PORT_C, + S3C44B0_GPIO_PORT_D, + S3C44B0_GPIO_PORT_E, + S3C44B0_GPIO_PORT_F, + S3C44B0_GPIO_PORT_G +}; + +class s3c44b0_device : public device_t +{ +public: + s3c44b0_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + ~s3c44b0_device() {} + + template static devcb_base &set_gpio_port_r_callback(device_t &device, _Object object) { return downcast(device).m_port_r_cb.set_callback(object); } + template static devcb_base &set_gpio_port_w_callback(device_t &device, _Object object) { return downcast(device).m_port_w_cb.set_callback(object); } + template static devcb_base &set_i2c_scl_w_callback(device_t &device, _Object object) { return downcast(device).m_scl_w_cb.set_callback(object); } + template static devcb_base &set_i2c_sda_r_callback(device_t &device, _Object object) { return downcast(device).m_sda_r_cb.set_callback(object); } + template static devcb_base &set_i2c_sda_w_callback(device_t &device, _Object object) { return downcast(device).m_sda_w_cb.set_callback(object); } + template static devcb_base &set_adc_data_r_callback(device_t &device, _Object object) { return downcast(device).m_data_r_cb.set_callback(object); } + template static devcb_base &set_i2s_data_w_callback(device_t &device, _Object object) { return downcast(device).m_data_w_cb.set_callback(object); } + + DECLARE_READ32_MEMBER(lcd_r); + DECLARE_READ32_MEMBER(clkpow_r); + DECLARE_READ32_MEMBER(irq_r); + DECLARE_READ32_MEMBER(pwm_r); + DECLARE_READ32_MEMBER(iic_r); + DECLARE_READ32_MEMBER(gpio_r); + DECLARE_READ32_MEMBER(uart_0_r); + DECLARE_READ32_MEMBER(uart_1_r); + DECLARE_READ32_MEMBER(wdt_r); + DECLARE_READ32_MEMBER(cpuwrap_r); + DECLARE_READ32_MEMBER(adc_r); + DECLARE_READ32_MEMBER(sio_r); + DECLARE_READ32_MEMBER(iis_r); + DECLARE_READ32_MEMBER(zdma_0_r); + DECLARE_READ32_MEMBER(zdma_1_r); + DECLARE_READ32_MEMBER(bdma_0_r); + DECLARE_READ32_MEMBER(bdma_1_r); + + DECLARE_WRITE32_MEMBER(lcd_w); + DECLARE_WRITE32_MEMBER(clkpow_w); + DECLARE_WRITE32_MEMBER(irq_w); + DECLARE_WRITE32_MEMBER(pwm_w); + DECLARE_WRITE32_MEMBER(iic_w); + DECLARE_WRITE32_MEMBER(gpio_w); + DECLARE_WRITE32_MEMBER(uart_0_w); + DECLARE_WRITE32_MEMBER(uart_1_w); + DECLARE_WRITE32_MEMBER(wdt_w); + DECLARE_WRITE32_MEMBER(cpuwrap_w); + DECLARE_WRITE32_MEMBER(adc_w); + DECLARE_WRITE32_MEMBER(sio_w); + DECLARE_WRITE32_MEMBER(iis_w); + DECLARE_WRITE32_MEMBER(zdma_0_w); + DECLARE_WRITE32_MEMBER(zdma_1_w); + DECLARE_WRITE32_MEMBER(bdma_0_w); + DECLARE_WRITE32_MEMBER(bdma_1_w); + + void request_eint(UINT32 number); + UINT32 video_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + +private: + // internal state + // LCD Controller + rgb_t lcd_get_color_stn_04(UINT8 data); + UINT8 lcd_get_color_stn_08_r(UINT8 data); + UINT8 lcd_get_color_stn_08_g(UINT8 data); + UINT8 lcd_get_color_stn_08_b(UINT8 data); + void lcd_dma_reload(); + void lcd_dma_init(); + void lcd_dma_read(int count, UINT8 *data); + void lcd_render_stn_04(); + void lcd_render_stn_08(); + attotime time_until_pos(int vpos, int hpos); + int lcd_get_vpos(); + int lcd_get_hpos(); + void video_start(); + void lcd_configure(); + void lcd_start(); + void lcd_stop(); + void lcd_recalc(); + TIMER_CALLBACK_MEMBER(lcd_timer_exp); + + // Clock & Power Management + UINT32 get_mclk(); + + // Interrupt Controller + void check_pending_irq(); + void request_irq(UINT32 int_type); + void check_pending_eint(); + + // PWM Timer + UINT16 pwm_calc_observation(int ch); + void pwm_start(int timer); + void pwm_stop(int timer); + void pwm_recalc(int timer); + TIMER_CALLBACK_MEMBER(pwm_timer_exp); + //void dma_request_pwm(); + + // IIC + inline void iface_i2c_scl_w(int state); + inline void iface_i2c_sda_w(int state); + inline int iface_i2c_sda_r(); + void i2c_send_start(); + void i2c_send_stop(); + UINT8 i2c_receive_byte(int ack); + int i2c_send_byte(UINT8 data); + void iic_start(); + void iic_stop(); + void iic_resume(); + TIMER_CALLBACK_MEMBER(iic_timer_exp); + + // I/O Port + inline UINT32 iface_gpio_port_r(int port); + inline void iface_gpio_port_w(int port, UINT32 data); + + // UART + UINT32 uart_r(int ch, UINT32 offset); + void uart_w(int ch, UINT32 offset, UINT32 data, UINT32 mem_mask); + void uart_fifo_w(int uart, UINT8 data); + TIMER_CALLBACK_MEMBER(uart_timer_exp); + + // Watchdog Timer + UINT16 wdt_calc_current_count(); + void wdt_start(); + void wdt_stop(); + void wdt_recalc(); + TIMER_CALLBACK_MEMBER(wdt_timer_exp); + + // A/D Converter + void adc_start(); + void adc_stop(); + void adc_recalc(); + TIMER_CALLBACK_MEMBER(adc_timer_exp); + + // SIO + void sio_start(); + void sio_stop(); + void sio_recalc(); + TIMER_CALLBACK_MEMBER(sio_timer_exp); + + // IIS + inline void iface_i2s_data_w(address_space &space, int ch, UINT16 data); + void iis_start(); + void iis_stop(); + TIMER_CALLBACK_MEMBER(iis_timer_exp); + + // ZDMA + void zdma_trigger(int ch); + void zdma_start(int ch); + UINT32 zdma_r(int ch, UINT32 offset); + void zdma_w(int ch, UINT32 offset, UINT32 data, UINT32 mem_mask); + TIMER_CALLBACK_MEMBER(zdma_timer_exp); + + // BDMA + void bdma_trigger(int ch); + void bdma_request_iis(); + UINT32 bdma_r(int ch, UINT32 offset); + void bdma_start(int ch); + void bdma_stop(int ch); + void bdma_w(int ch, UINT32 offset, UINT32 data, UINT32 mem_mask); + TIMER_CALLBACK_MEMBER(bdma_timer_exp); + + cpu_device *m_cpu; + //s3c44b0_memcon_t m_memcon; + s3c44b0_irq_t m_irq; + s3c44b0_dma_t m_zdma[2]; + s3c44b0_dma_t m_bdma[2]; + s3c44b0_clkpow_t m_clkpow; + s3c44b0_lcd_t m_lcd; + s3c44b0_uart_t m_uart[2]; + s3c44b0_sio_t m_sio; + s3c44b0_pwm_t m_pwm; + s3c44b0_wdt_t m_wdt; + s3c44b0_iic_t m_iic; + s3c44b0_iis_t m_iis; + s3c44b0_gpio_t m_gpio; + //s3c44b0_rtc_t m_rtc; + s3c44b0_adc_t m_adc; + s3c44b0_cpuwrap_t m_cpuwrap; + + devcb_read32 m_port_r_cb; + devcb_write32 m_port_w_cb; + devcb_write_line m_scl_w_cb; + devcb_read_line m_sda_r_cb; + devcb_write_line m_sda_w_cb; + devcb_read32 m_data_r_cb; + devcb_write16 m_data_w_cb; + + void s3c44b0_postload(); +}; + +extern const device_type S3C44B0; + + +#define MCFG_S3C44B0_GPIO_PORT_R_CB(_devcb) \ + devcb = &s3c44b0_device::set_gpio_port_r_callback(*device, DEVCB_##_devcb); + +#define MCFG_S3C44B0_GPIO_PORT_W_CB(_devcb) \ + devcb = &s3c44b0_device::set_gpio_port_w_callback(*device, DEVCB_##_devcb); + +#define MCFG_S3C44B0_I2C_SCL_W_CB(_devcb) \ + devcb = &s3c44b0_device::set_i2c_scl_w_callback(*device, DEVCB_##_devcb); + +#define MCFG_S3C44B0_I2C_SDA_R_CB(_devcb) \ + devcb = &s3c44b0_device::set_i2c_sda_r_callback(*device, DEVCB_##_devcb); + +#define MCFG_S3C44B0_I2C_SDA_W_CB(_devcb) \ + devcb = &s3c44b0_device::set_i2c_sda_w_callback(*device, DEVCB_##_devcb); + +#define MCFG_S3C44B0_ADC_DATA_R_CB(_devcb) \ + devcb = &s3c44b0_device::set_adc_data_r_callback(*device, DEVCB_##_devcb); + +#define MCFG_S3C44B0_I2S_DATA_W_CB(_devcb) \ + devcb = &s3c44b0_device::set_i2s_data_w_callback(*device, DEVCB_##_devcb); + + +#endif diff --git a/src/devices/machine/saturn.c b/src/devices/machine/saturn.c new file mode 100644 index 00000000000..cf79fdc26a2 --- /dev/null +++ b/src/devices/machine/saturn.c @@ -0,0 +1,1003 @@ +// license:LGPL-2.1+ +// copyright-holders:David Haywood, Angelo Salese, Olivier Galibert, Mariusz Wojcieszek, R. Belmont +/************************************************************************************** + + Sega Saturn (c) 1994 Sega + + @todo List of things that needs to be implemented: + - There's definitely an ack mechanism in SCU irqs. This is almost surely done via + the ISM register (i.e. going 0->1 to the given bit acks it). + - There might be a delay to exactly when SCU irqs happens. This is due to the basic + fact that SCU runs at 14-ish MHz, so it needs some time before actually firing the + irq. + - Vblank-Out actually happens at the last screen line, not at 0. + - VDP2 V counter has a similar roll-back as MD correspondent register: + vpos line 0 == 0x1ff (Vblank-Out happens here) + vpos line 1 == 0 + ... + vpos line 241 == 0xf0 (Vblank-In happens here) + vpos line 246 == 0xf5 + vpos line 247 == 0x1ef (rolls back here) + vpos line 263 == 0x1ff again + - HBlank bit seems to follow a normal logic instead. + - Timer 0 doesn't work if the TENB bit isn't enabled (documentation is a bit fussy + over this). + - Timer 0 fires at the HBlank-In signal, not before. + - VDP2 H Counter actually counts x2 in non Hi-Res mode. + - Timer 1 is definitely annoying. Starts from H-Blank signal and starts counting from + that position. + H counter value 0x282 (642) -> timer 1 fires at setting 1 + H counter value 0x284 (644) -> 2 + H counter value 0x2a0 (672) -> 0x10 + H counter value 0x2c0 (704) -> 0x20 + H counter value 0x300 (768) -> 0x40 + H counter value 0x340 (832) -> 0x60 + H counter value 0x352 (850) -> 0x69 + H counter value 0x000 (0) -> 0x6a, V counter goes +1 here (max range?) + H counter value 0x02c (44) -> 0x80 + H counter value 0x0ec (236) -> 0xe0 + H counter value 0x12c (300) -> 0x100 + - Timer 1 seems to count backwards compared to Timer 0 from setting 0x6b onward. + - Yabause claims that if VDP2 DISP bit isn't enabled then vblank irqs (hblank too?) + doesn't happen. + +**************************************************************************************/ + +#include "emu.h" +#include "includes/stv.h" +#include "cpu/sh2/sh2.h" +#include "cpu/scudsp/scudsp.h" + +/* TODO: do this in a verboselog style */ +#define LOG_CDB 0 +#define LOG_SCU 1 +#define LOG_IRQ 0 +#define LOG_IOGA 0 + +int saturn_state::DectoBCD(int num) +{ + int i, cnt = 0, tmp, res = 0; + + while (num > 0) { + tmp = num; + while (tmp >= 10) tmp %= 10; + for (i=0; i +29 0074 +30 0078 +31 007c DMA Status Register +32 0080 DSP Program Control Port +33 0084 DSP Program RAM Data Port +34 0088 DSP Data RAM Address Port +35 008c DSP Data RAM Data Port +36 0090 Timer 0 Compare Register +37 0094 Timer 1 Set Data Register +38 0098 Timer 1 Mode Register +39 009c +40 00a0 Interrupt Mask Register +41 00a4 Interrupt Status Register +42 00a8 A-Bus Interrupt Acknowledge +43 00ac +44 00b0 A-Bus Set Register +45 00b4 +46 00b8 A-Bus Refresh Register +47 00bc +48 00c0 +49 00c4 SCU SDRAM Select Register +50 00c8 SCU Version Register +51 00cc +52 00cf +=================================================================================== +DMA Status Register(32-bit): +xxxx xxxx x--- xx-- xx-- xx-- xx-- xx-- UNUSED +---- ---- -x-- ---- ---- ---- ---- ---- DMA DSP-Bus access +---- ---- --x- ---- ---- ---- ---- ---- DMA B-Bus access +---- ---- ---x ---- ---- ---- ---- ---- DMA A-Bus access +---- ---- ---- --x- ---- ---- ---- ---- DMA lv 1 interrupt +---- ---- ---- ---x ---- ---- ---- ---- DMA lv 0 interrupt +---- ---- ---- ---- --x- ---- ---- ---- DMA lv 2 in stand-by +---- ---- ---- ---- ---x ---- ---- ---- DMA lv 2 in operation +---- ---- ---- ---- ---- --x- ---- ---- DMA lv 1 in stand-by +---- ---- ---- ---- ---- ---x ---- ---- DMA lv 1 in operation +---- ---- ---- ---- ---- ---- --x- ---- DMA lv 0 in stand-by +---- ---- ---- ---- ---- ---- ---x ---- DMA lv 0 in operation +---- ---- ---- ---- ---- ---- ---- --x- DSP side DMA in stand-by +---- ---- ---- ---- ---- ---- ---- ---x DSP side DMA in operation + +**********************************************************************************/ +/* +DMA TODO: +-Remove CD transfer DMA hack (tied with CD block bug(s)?) +-Add timings(but how fast are each DMA?). +-Add level priority & DMA status register. +*/ + +#define DIRECT_MODE(_lv_) (!(m_scu_regs[5+(_lv_*8)] & 0x01000000)) +#define INDIRECT_MODE(_lv_) (m_scu_regs[5+(_lv_*8)] & 0x01000000) +#define DRUP(_lv_) (m_scu_regs[5+(_lv_*8)] & 0x00010000) +#define DWUP(_lv_) (m_scu_regs[5+(_lv_*8)] & 0x00000100) + +/*These macros sets the various DMA status flags.*/ +#define DnMV_1(_ch_) m_scu.status|=(0x10 << 4 * _ch_) +#define DnMV_0(_ch_) m_scu.status&=~(0x10 << 4 * _ch_) + +/*For area checking*/ +#define BIOS_BUS(var) (var & 0x07f00000) == 0 +#define ABUS(_lv_) ((m_scu.src[_lv_] & 0x07000000) >= 0x02000000) && ((m_scu.src[_lv_] & 0x07000000) <= 0x04000000) +#define BBUS(_lv_) ((scu_##_lv_ & 0x07ffffff) >= 0x05a00000) && ((scu_##_lv_ & 0x07ffffff) <= 0x05ffffff) +#define VDP1_REGS(_lv_) ((scu_##_lv_ & 0x07ffffff) >= 0x05d00000) && ((scu_##_lv_ & 0x07ffffff) <= 0x05dfffff) +#define VDP2(_lv_) ((scu_##_lv_ & 0x07ffffff) >= 0x05e00000) && ((scu_##_lv_ & 0x07ffffff) <= 0x05fdffff) +#define WORK_RAM_L(_lv_) ((scu_##_lv_ & 0x07ffffff) >= 0x00200000) && ((scu_##_lv_ & 0x07ffffff) <= 0x002fffff) +#define WORK_RAM_H(var) (var & 0x07000000) == 0x06000000 +#define SOUND_RAM(_lv_) ((scu_##_lv_ & 0x07ffffff) >= 0x05a00000) && ((scu_##_lv_ & 0x07ffffff) <= 0x05afffff) + +void saturn_state::scu_do_transfer(UINT8 event) +{ + address_space &space = machine().device("maincpu")->memory().space(AS_PROGRAM); + int i; + + for(i=0;i<3;i++) + { + if(m_scu.enable_mask[i] && m_scu.start_factor[i] == event) + { + if(DIRECT_MODE(i)) { scu_dma_direct(space,i); } + else { scu_dma_indirect(space,i); } + } + } +} + +/* test pending irqs */ +void saturn_state::scu_test_pending_irq() +{ + int i; + const int irq_level[32] = { 0xf, 0xe, 0xd, 0xc, + 0xb, 0xa, 0x9, 0x8, + 0x8, 0x6, 0x6, 0x5, + 0x3, 0x2, -1, -1, + 0x7, 0x7, 0x7, 0x7, + 0x4, 0x4, 0x4, 0x4, + 0x1, 0x1, 0x1, 0x1, + 0x1, 0x1, 0x1, 0x1 }; + + for(i=0;i<32;i++) + { + if((!(m_scu.ism & 1 << i)) && (m_scu.ist & 1 << i)) + { + if(irq_level[i] != -1) /* TODO: cheap check for undefined irqs */ + { + m_maincpu->set_input_line_and_vector(irq_level[i], HOLD_LINE, 0x40 + i); + m_scu.ist &= ~(1 << i); + return; /* avoid spurious irqs, correct? */ + } + } + } +} + +READ32_MEMBER(saturn_state::saturn_scu_r) +{ + UINT32 res; + + /*TODO: write only registers must return 0 or open bus */ + switch(offset) + { + case 0x5c/4: + // Super Major League and Shin Megami Tensei - Akuma Zensho reads from there (undocumented), DMA status mirror? + if(LOG_SCU && !space.debugger_access()) logerror("(PC=%08x) DMA status reg read\n",space.device().safe_pc()); + res = m_scu.status; + break; + case 0x7c/4: + if(LOG_SCU && !space.debugger_access()) logerror("(PC=%08x) DMA status reg read\n",space.device().safe_pc()); + res = m_scu.status; + break; + case 0x80/4: + res = m_scudsp->program_control_r(space, 0, mem_mask); + break; + case 0x8c/4: + if(LOG_SCU && !space.debugger_access()) logerror( "DSP mem read at %08X\n", m_scu_regs[34]); + res = m_scudsp->ram_address_r(space, 0, mem_mask); + break; + case 0xa0/4: + if(LOG_SCU && !space.debugger_access()) logerror("(PC=%08x) IRQ mask reg read %08x MASK=%08x\n",space.device().safe_pc(),mem_mask,m_scu_regs[0xa0/4]); + res = m_scu.ism; + break; + case 0xa4/4: + if(LOG_SCU && !space.debugger_access()) logerror("(PC=%08x) IRQ status reg read MASK=%08x IST=%08x | ISM=%08x\n",space.device().safe_pc(),mem_mask,m_scu.ist,m_scu.ism); + /* TODO: Bug! trips an HW fault. Basically, it tries to read the IST bit 1 with that irq enabled. + Densetsu no Ogre Battle doesn't like this, so it needs investigation ... + */ +// res = m_scu.ist | ~m_scu.ism; + res = m_scu.ist; + break; + case 0xc8/4: + if(LOG_SCU && !space.debugger_access()) logerror("(PC=%08x) SCU version reg read\n",space.device().safe_pc()); + res = 0x00000004;/*SCU Version 4, OK? */ + break; + default: + if(LOG_SCU && !space.debugger_access()) logerror("(PC=%08x) SCU reg read at %d = %08x\n",space.device().safe_pc(),offset,m_scu_regs[offset]); + res = m_scu_regs[offset]; + break; + } + + return res; +} + +#define DMA_CH ((offset & 0x18) / 8) + +WRITE32_MEMBER(saturn_state::saturn_scu_w) +{ + COMBINE_DATA(&m_scu_regs[offset]); + + switch(offset) + { + /*LV 0 DMA*/ + case 0x00/4: case 0x20/4: case 0x40/4: m_scu.src[DMA_CH] = ((m_scu_regs[offset] & 0x07ffffff) >> 0); break; + case 0x04/4: case 0x24/4: case 0x44/4: m_scu.dst[DMA_CH] = ((m_scu_regs[offset] & 0x07ffffff) >> 0); break; + case 0x08/4: case 0x28/4: case 0x48/4: m_scu.size[DMA_CH] = ((m_scu_regs[offset] & ((offset == 2) ? 0x000fffff : 0xfff)) >> 0); break; + case 0x0c/4: case 0x2c/4: case 0x4c/4: + m_scu.src_add[DMA_CH] = (m_scu_regs[offset] & 0x100) ? 4 : 0; + m_scu.dst_add[DMA_CH] = 1 << (m_scu_regs[offset] & 7); + if(m_scu.dst_add[DMA_CH] == 1) { m_scu.dst_add[DMA_CH] = 0; } + break; + case 0x10/4: case 0x30/4: case 0x50/4: + m_scu.enable_mask[DMA_CH] = (data & 0x100) >> 8; + if(m_scu.enable_mask[DMA_CH] && m_scu.start_factor[DMA_CH] == 7 && m_scu_regs[offset] & 1) + { + if(DIRECT_MODE(DMA_CH)) { scu_dma_direct(space,DMA_CH); } + else { scu_dma_indirect(space,DMA_CH); } + m_scu_regs[offset]&=~1;//disable starting bit. + } + break; + case 0x14/4: case 0x34/4: case 0x54/4: + if(INDIRECT_MODE(DMA_CH)) + { + //if(LOG_SCU) logerror("Indirect Mode DMA lv %d set\n",DMA_CH); + if(!DWUP(DMA_CH)) m_scu.index[DMA_CH] = m_scu.dst[DMA_CH]; + } + + m_scu.start_factor[DMA_CH] = m_scu_regs[offset] & 7; + break; + + case 0x60/4: + if(LOG_SCU) logerror("DMA Forced Stop Register set = %02x\n",m_scu_regs[24]); + break; + case 0x7c/4: if(LOG_SCU) logerror("Warning: DMA status WRITE! Offset %02x(%d)\n",offset*4,offset); break; + /*DSP section*/ + case 0x80/4: + m_scudsp->program_control_w(space, 0, m_scu_regs[offset], mem_mask); + if(LOG_SCU) logerror("SCU DSP: Program Control Port Access %08x\n",data); + break; + case 0x84/4: + m_scudsp->program_w(space, 0, m_scu_regs[offset], mem_mask); + if(LOG_SCU) logerror("SCU DSP: Program RAM Data Port Access %08x\n",data); + break; + case 0x88/4: + m_scudsp->ram_address_control_w(space, 0,m_scu_regs[offset], mem_mask); + if(LOG_SCU) logerror("SCU DSP: Data RAM Address Port Access %08x\n",data); + break; + case 0x8c/4: + m_scudsp->ram_address_w(space, 0, m_scu_regs[offset], mem_mask); + if(LOG_SCU) logerror("SCU DSP: Data RAM Data Port Access %08x\n",data); + break; + case 0x90/4: /*if(LOG_SCU) logerror("timer 0 compare data = %03x\n",m_scu_regs[36]);*/ break; + case 0x94/4: /*if(LOG_SCU) logerror("timer 1 set data = %08x\n",m_scu_regs[37]);*/ break; + case 0x98/4: /*if(LOG_SCU) logerror("timer 1 mode data = %08x\n",m_scu_regs[38]);*/ break; + case 0xa0/4: /* IRQ mask */ + m_scu.ism = m_scu_regs[0xa0/4]; + scu_test_pending_irq(); + break; + case 0xa4/4: /* IRQ control */ + if(LOG_SCU) logerror("PC=%08x IRQ status reg set:%08x %08x\n",space.device().safe_pc(),m_scu_regs[41],mem_mask); + m_scu.ist &= m_scu_regs[offset]; + scu_test_pending_irq(); + break; + case 0xa8/4: + /* This sends an irq signal to the extra devices connected to the A-Bus, not really needed for now. */ + //if(LOG_SCU) logerror("A-Bus IRQ ACK %08x\n",m_scu_regs[42]); + break; + case 0xc4/4: if(LOG_SCU) logerror("SCU SDRAM set: %02x\n",m_scu_regs[49]); break; + default: if(LOG_SCU) logerror("Warning: unused SCU reg set %d = %08x\n",offset,data); + } +} + +/*Lv 0 DMA end irq*/ +TIMER_CALLBACK_MEMBER(saturn_state::dma_lv0_ended ) +{ + if(!(m_scu.ism & IRQ_DMALV0)) + m_maincpu->set_input_line_and_vector(5, HOLD_LINE, 0x4b); + else + m_scu.ist |= (IRQ_DMALV0); + + DnMV_0(0); +} + +/*Lv 1 DMA end irq*/ +TIMER_CALLBACK_MEMBER(saturn_state::dma_lv1_ended) +{ + if(!(m_scu.ism & IRQ_DMALV1)) + m_maincpu->set_input_line_and_vector(6, HOLD_LINE, 0x4a); + else + m_scu.ist |= (IRQ_DMALV1); + + DnMV_0(1); +} + +/*Lv 2 DMA end irq*/ +TIMER_CALLBACK_MEMBER(saturn_state::dma_lv2_ended) +{ + if(!(m_scu.ism & IRQ_DMALV2)) + m_maincpu->set_input_line_and_vector(6, HOLD_LINE, 0x49); + else + m_scu.ist |= (IRQ_DMALV2); + + DnMV_0(2); +} + +void saturn_state::scu_single_transfer(address_space &space, UINT32 src, UINT32 dst,UINT8 *src_shift) +{ + UINT32 src_data; + + if(src & 1) + { + /* Road Blaster does a work ram h to color ram with offsetted source address, do some data rotation */ + src_data = ((space.read_dword(src & 0x07fffffc) & 0x00ffffff)<<8); + src_data |= ((space.read_dword((src & 0x07fffffc)+4) & 0xff000000) >> 24); + src_data >>= (*src_shift)*16; + } + else + src_data = space.read_dword(src & 0x07fffffc) >> (*src_shift)*16; + + space.write_word(dst,src_data); + + *src_shift ^= 1; +} + +void saturn_state::scu_dma_direct(address_space &space, UINT8 dma_ch) +{ + UINT32 tmp_src,tmp_dst,total_size; + UINT8 cd_transfer_flag; + + if(m_scu.src_add[dma_ch] == 0 || (m_scu.dst_add[dma_ch] != 2 && m_scu.dst_add[dma_ch] != 4)) + { + if(LOG_SCU) printf("DMA lv %d transfer START\n" + "Start %08x End %08x Size %04x\n",dma_ch,m_scu.src[dma_ch],m_scu.dst[dma_ch],m_scu.size[dma_ch]); + if(LOG_SCU) printf("Start Add %04x Destination Add %04x\n",m_scu.src_add[dma_ch],m_scu.dst_add[dma_ch]); + } + + /* Game Basic and World Cup 98 trips this, according to the docs the SCU can't transfer from BIOS area (can't communicate from/to that bus) */ + if(BIOS_BUS(m_scu.src[dma_ch])) + { + popmessage("Warning: SCU transfer from BIOS area, contact MAMEdev"); + if(!(m_scu.ism & IRQ_DMAILL)) + m_maincpu->set_input_line_and_vector(3, HOLD_LINE, 0x4c); + else + m_scu.ist |= (IRQ_DMAILL); + return; + } + + DnMV_1(dma_ch); + + /* max size */ + if(m_scu.size[dma_ch] == 0) { m_scu.size[dma_ch] = (dma_ch == 0) ? 0x00100000 : 0x1000; } + + tmp_src = tmp_dst = 0; + + total_size = m_scu.size[dma_ch]; + if(!(DRUP(dma_ch))) tmp_src = m_scu.src[dma_ch]; + if(!(DWUP(dma_ch))) tmp_dst = m_scu.dst[dma_ch]; + + cd_transfer_flag = m_scu.src_add[dma_ch] == 0 && m_scu.src[dma_ch] == 0x05818000; + + /* TODO: Many games directly accesses CD-ROM register 0x05818000, it must be a dword access with current implementation otherwise it won't work */ + if(cd_transfer_flag) + { + int i; + if(WORK_RAM_H(m_scu.dst[dma_ch])) + m_scu.dst_add[dma_ch] = 4; + else + m_scu.dst_add[dma_ch] <<= 1; + + for (i = 0; i < m_scu.size[dma_ch];i+=m_scu.dst_add[dma_ch]) + { + space.write_dword(m_scu.dst[dma_ch],space.read_dword(m_scu.src[dma_ch])); + if(m_scu.dst_add[dma_ch] == 8) + space.write_dword(m_scu.dst[dma_ch]+4,space.read_dword(m_scu.src[dma_ch])); + + m_scu.src[dma_ch]+=m_scu.src_add[dma_ch]; + m_scu.dst[dma_ch]+=m_scu.dst_add[dma_ch]; + } + } + else + { + int i; + UINT8 src_shift; + + src_shift = ((m_scu.src[dma_ch] & 2) >> 1) ^ 1; + + for (i = 0; i < m_scu.size[dma_ch];i+=2) + { + scu_single_transfer(space,m_scu.src[dma_ch],m_scu.dst[dma_ch],&src_shift); + + if(src_shift) + m_scu.src[dma_ch]+=m_scu.src_add[dma_ch]; + + /* if target is Work RAM H, the add value is fixed, behaviour confirmed by Final Romance 2, Virtual Mahjong and Burning Rangers */ + m_scu.dst[dma_ch]+=(WORK_RAM_H(m_scu.dst[dma_ch])) ? 2 : m_scu.dst_add[dma_ch]; + } + } + + /* Burning Rangers doesn't agree with this. */ +// m_scu.size[dma_ch] = 0; + if(!(DRUP(dma_ch))) m_scu.src[dma_ch] = tmp_src; + if(!(DWUP(dma_ch))) m_scu.dst[dma_ch] = tmp_dst; + + { + /*TODO: Timing is a guess. */ + switch(dma_ch) + { + case 0: machine().scheduler().timer_set(m_maincpu->cycles_to_attotime(total_size/4), timer_expired_delegate(FUNC(saturn_state::dma_lv0_ended),this)); break; + case 1: machine().scheduler().timer_set(m_maincpu->cycles_to_attotime(total_size/4), timer_expired_delegate(FUNC(saturn_state::dma_lv1_ended),this)); break; + case 2: machine().scheduler().timer_set(m_maincpu->cycles_to_attotime(total_size/4), timer_expired_delegate(FUNC(saturn_state::dma_lv2_ended),this)); break; + } + } +} + +void saturn_state::scu_dma_indirect(address_space &space,UINT8 dma_ch) +{ + /*Helper to get out of the cycle*/ + UINT8 job_done = 0; + /*temporary storage for the transfer data*/ + UINT32 tmp_src; + UINT32 indirect_src,indirect_dst; + INT32 indirect_size; + UINT32 total_size = 0; + + DnMV_1(dma_ch); + + m_scu.index[dma_ch] = m_scu.dst[dma_ch]; + + do{ + tmp_src = m_scu.index[dma_ch]; + + indirect_size = space.read_dword(m_scu.index[dma_ch]); + indirect_src = space.read_dword(m_scu.index[dma_ch]+8); + indirect_dst = space.read_dword(m_scu.index[dma_ch]+4); + + /*Indirect Mode end factor*/ + if(indirect_src & 0x80000000) + job_done = 1; + + if(m_scu.src_add[dma_ch] == 0 || (m_scu.dst_add[dma_ch] != 2)) + { + if(LOG_SCU) printf("DMA lv %d indirect mode transfer START\n" + "Index %08x Start %08x End %08x Size %04x\n",dma_ch,tmp_src,indirect_src,indirect_dst,indirect_size); + if(LOG_SCU) printf("Start Add %04x Destination Add %04x\n",m_scu.src_add[dma_ch],m_scu.dst_add[dma_ch]); + } + + indirect_src &=0x07ffffff; + indirect_dst &=0x07ffffff; + indirect_size &= ((dma_ch == 0) ? 0xfffff : 0x3ffff); //TODO: Guardian Heroes sets up a 0x23000 transfer for the FMV? + + if(indirect_size == 0) { indirect_size = (dma_ch == 0) ? 0x00100000 : 0x2000; } + + { + int i; + UINT8 src_shift; + + src_shift = ((indirect_src & 2) >> 1) ^ 1; + + for (i = 0; i < indirect_size;i+=2) + { + scu_single_transfer(space,indirect_src,indirect_dst,&src_shift); + + if(src_shift) + indirect_src+=m_scu.src_add[dma_ch]; + + indirect_dst+= (WORK_RAM_H(indirect_dst)) ? 2 : m_scu.dst_add[dma_ch]; + } + } + + /* Guess: Size + data acquire (1 cycle for src/dst/size) */ + total_size += indirect_size + 3*4; + + //if(DRUP(0)) space.write_dword(tmp_src+8,m_scu.src[0]|job_done ? 0x80000000 : 0); + //if(DWUP(0)) space.write_dword(tmp_src+4,m_scu.dst[0]); + + m_scu.index[dma_ch] = tmp_src+0xc; + + }while(job_done == 0); + + { + /*TODO: change DMA into DRQ model. Timing is a guess. */ + switch(dma_ch) + { + case 0: machine().scheduler().timer_set(m_maincpu->cycles_to_attotime(total_size/4), timer_expired_delegate(FUNC(saturn_state::dma_lv0_ended),this)); break; + case 1: machine().scheduler().timer_set(m_maincpu->cycles_to_attotime(total_size/4), timer_expired_delegate(FUNC(saturn_state::dma_lv1_ended),this)); break; + case 2: machine().scheduler().timer_set(m_maincpu->cycles_to_attotime(total_size/4), timer_expired_delegate(FUNC(saturn_state::dma_lv2_ended),this)); break; + } + } +} + + +/**************************************************************************************/ + +WRITE16_MEMBER(saturn_state::saturn_soundram_w) +{ + //machine().scheduler().synchronize(); // force resync + + COMBINE_DATA(&m_sound_ram[offset]); +} + +READ16_MEMBER(saturn_state::saturn_soundram_r) +{ + //machine().scheduler().synchronize(); // force resync + + return m_sound_ram[offset]; +} + +/* communication,SLAVE CPU acquires data from the MASTER CPU and triggers an irq. */ +WRITE32_MEMBER(saturn_state::minit_w) +{ + //logerror("cpu %s (PC=%08X) MINIT write = %08x\n", space.device().tag(), space.device().safe_pc(),data); + machine().scheduler().boost_interleave(m_minit_boost_timeslice, attotime::from_usec(m_minit_boost)); + machine().scheduler().trigger(1000); + machine().scheduler().synchronize(); // force resync + m_slave->sh2_set_frt_input(PULSE_LINE); +} + +WRITE32_MEMBER(saturn_state::sinit_w) +{ + //logerror("cpu %s (PC=%08X) SINIT write = %08x\n", space.device().tag(), space.device().safe_pc(),data); + machine().scheduler().boost_interleave(m_sinit_boost_timeslice, attotime::from_usec(m_sinit_boost)); + machine().scheduler().synchronize(); // force resync + m_maincpu->sh2_set_frt_input(PULSE_LINE); +} + +/* +TODO: +Some games seems to not like either MAME's interleave system and/or SH-2 DRC, causing an hard crash. +Reported games are: +Blast Wind (before FMV) +Choro Q Park (car selection) +060311E4: MOV.L R14,@-SP ;R14 = 0x60ffba0 / R15 = 0x60ffba0 +060311E6: MOV SP,R14 ;R14 = 0x60ffba0 / R15 = 0x60ffb9c / [0x60ffb9c] <- 0x60ffba0 +060311E8: MOV.L @SP+,R14 ;R14 = 0x60ffb9c / R15 = 0x60ffb9c / [0x60ffb9c] -> R14 +060311EA: RTS ;R14 = 0x60ffba0 / R15 = 0x60ffba0 +060311EC: NOP +06031734: MULS.W R9, R8 ;R14 = 0x60ffba0 / R15 = 0x60ffba0 / EA = 0x60311E4 +on DRC this becomes: +R14 0x6031b78 (cause of the crash later on), R15 = 0x60ffba4 and EA = 0 + +Shinrei Jusatsushi Taromaru (options menu) + +*/ + +WRITE32_MEMBER(saturn_state::saturn_minit_w) +{ + //logerror("cpu %s (PC=%08X) MINIT write = %08x\n", space.device().tag(), space.device().safe_pc(),data); + if(m_fake_comms->read() & 1) + machine().scheduler().synchronize(); // force resync + else + { + machine().scheduler().boost_interleave(m_minit_boost_timeslice, attotime::from_usec(m_minit_boost)); + machine().scheduler().trigger(1000); + } + + m_slave->sh2_set_frt_input(PULSE_LINE); +} + +WRITE32_MEMBER(saturn_state::saturn_sinit_w) +{ + //logerror("cpu %s (PC=%08X) SINIT write = %08x\n", space.device().tag(), space.device().safe_pc(),data); + if(m_fake_comms->read() & 1) + machine().scheduler().synchronize(); // force resync + else + machine().scheduler().boost_interleave(m_sinit_boost_timeslice, attotime::from_usec(m_sinit_boost)); + + m_maincpu->sh2_set_frt_input(PULSE_LINE); +} + + +READ8_MEMBER(saturn_state::saturn_backupram_r) +{ + if(!(offset & 1)) + return 0; // yes, it makes sure the "holes" are there. + + return m_backupram[offset >> 1] & 0xff; +} + +WRITE8_MEMBER(saturn_state::saturn_backupram_w) +{ + if(!(offset & 1)) + return; + + m_backupram[offset >> 1] = data; +} + +void saturn_state::scu_reset(void) +{ + m_scu.ism = 0xbfff; + m_scu.ist = 0; + m_scu.start_factor[0] = 7; + m_scu.start_factor[1] = 7; + m_scu.start_factor[2] = 7; + m_scu.status = 0; +} + +TIMER_CALLBACK_MEMBER(saturn_state::stv_rtc_increment) +{ + static const UINT8 dpm[12] = { 0x31, 0x28, 0x31, 0x30, 0x31, 0x30, 0x31, 0x31, 0x30, 0x31, 0x30, 0x31 }; + static int year_num, year_count; + + /* + m_smpc.rtc_data[0] = DectoBCD(systime.local_time.year /100); + m_smpc.rtc_data[1] = DectoBCD(systime.local_time.year %100); + m_smpc.rtc_data[2] = (systime.local_time.weekday << 4) | (systime.local_time.month+1); + m_smpc.rtc_data[3] = DectoBCD(systime.local_time.mday); + m_smpc.rtc_data[4] = DectoBCD(systime.local_time.hour); + m_smpc.rtc_data[5] = DectoBCD(systime.local_time.minute); + m_smpc.rtc_data[6] = DectoBCD(systime.local_time.second); + */ + + m_smpc.rtc_data[6]++; + + /* seconds from 9 -> 10*/ + if((m_smpc.rtc_data[6] & 0x0f) >= 0x0a) { m_smpc.rtc_data[6]+=0x10; m_smpc.rtc_data[6]&=0xf0; } + /* seconds from 59 -> 0 */ + if((m_smpc.rtc_data[6] & 0xf0) >= 0x60) { m_smpc.rtc_data[5]++; m_smpc.rtc_data[6] = 0; } + /* minutes from 9 -> 10 */ + if((m_smpc.rtc_data[5] & 0x0f) >= 0x0a) { m_smpc.rtc_data[5]+=0x10; m_smpc.rtc_data[5]&=0xf0; } + /* minutes from 59 -> 0 */ + if((m_smpc.rtc_data[5] & 0xf0) >= 0x60) { m_smpc.rtc_data[4]++; m_smpc.rtc_data[5] = 0; } + /* hours from 9 -> 10 */ + if((m_smpc.rtc_data[4] & 0x0f) >= 0x0a) { m_smpc.rtc_data[4]+=0x10; m_smpc.rtc_data[4]&=0xf0; } + /* hours from 23 -> 0 */ + if((m_smpc.rtc_data[4] & 0xff) >= 0x24) { m_smpc.rtc_data[3]++; m_smpc.rtc_data[2]+=0x10; m_smpc.rtc_data[4] = 0; } + /* week day name sunday -> monday */ + if((m_smpc.rtc_data[2] & 0xf0) >= 0x70) { m_smpc.rtc_data[2]&=0x0f; } + /* day number 9 -> 10 */ + if((m_smpc.rtc_data[3] & 0x0f) >= 0x0a) { m_smpc.rtc_data[3]+=0x10; m_smpc.rtc_data[3]&=0xf0; } + + // year BCD to dec conversion (for the leap year stuff) + { + year_num = (m_smpc.rtc_data[1] & 0xf); + + for(year_count = 0; year_count < (m_smpc.rtc_data[1] & 0xf0); year_count += 0x10) + year_num += 0xa; + + year_num += (m_smpc.rtc_data[0] & 0xf)*0x64; + + for(year_count = 0; year_count < (m_smpc.rtc_data[0] & 0xf0); year_count += 0x10) + year_num += 0x3e8; + } + + /* month +1 check */ + /* the RTC have a range of 1980 - 2100, so we don't actually need to support the leap year special conditions */ + if(((year_num % 4) == 0) && (m_smpc.rtc_data[2] & 0xf) == 2) + { + if((m_smpc.rtc_data[3] & 0xff) >= dpm[(m_smpc.rtc_data[2] & 0xf)-1]+1+1) + { m_smpc.rtc_data[2]++; m_smpc.rtc_data[3] = 0x01; } + } + else if((m_smpc.rtc_data[3] & 0xff) >= dpm[(m_smpc.rtc_data[2] & 0xf)-1]+1){ m_smpc.rtc_data[2]++; m_smpc.rtc_data[3] = 0x01; } + /* year +1 check */ + if((m_smpc.rtc_data[2] & 0x0f) > 12) { m_smpc.rtc_data[1]++; m_smpc.rtc_data[2] = (m_smpc.rtc_data[2] & 0xf0) | 0x01; } + /* year from 9 -> 10 */ + if((m_smpc.rtc_data[1] & 0x0f) >= 0x0a) { m_smpc.rtc_data[1]+=0x10; m_smpc.rtc_data[1]&=0xf0; } + /* year from 99 -> 100 */ + if((m_smpc.rtc_data[1] & 0xf0) >= 0xa0) { m_smpc.rtc_data[0]++; m_smpc.rtc_data[1] = 0; } + + // probably not SO precise, here just for reference ... + /* year from 999 -> 1000 */ + //if((m_smpc.rtc_data[0] & 0x0f) >= 0x0a) { m_smpc.rtc_data[0]+=0x10; m_smpc.rtc_data[0]&=0xf0; } + /* year from 9999 -> 0 */ + //if((m_smpc.rtc_data[0] & 0xf0) >= 0xa0) { m_smpc.rtc_data[0] = 0; } //roll over +} + +/* Official documentation says that the "RESET/TAS opcodes aren't supported", but Out Run definitely contradicts with it. + Since that m68k can't reset itself via the RESET opcode I suppose that the SMPC actually do it by reading an i/o + connected to this opcode. */ +WRITE_LINE_MEMBER(saturn_state::m68k_reset_callback) +{ + machine().scheduler().timer_set(attotime::from_usec(100), timer_expired_delegate(FUNC(saturn_state::smpc_audio_reset_line_pulse), this)); + + printf("m68k RESET opcode triggered\n"); +} + +WRITE8_MEMBER(saturn_state::scsp_irq) +{ + // don't bother the 68k if it's off + if (!m_en_68k) + { + return; + } + + if (offset != 0) + { + if (data == ASSERT_LINE) m_scsp_last_line = offset; + m_audiocpu->set_input_line(offset, data); + } + else + { + m_audiocpu->set_input_line(m_scsp_last_line, data); + } +} + +WRITE_LINE_MEMBER(saturn_state::scsp_to_main_irq) +{ + if(state) + { + if(!(m_scu.ism & IRQ_SOUND_REQ)) + { + m_maincpu->set_input_line_and_vector(9, HOLD_LINE, 0x46); + scu_do_transfer(5); + } + else + m_scu.ist |= (IRQ_SOUND_REQ); + } +} + + + +/* +(Preliminary) explanation about this: +VBLANK-OUT is used at the start of the vblank period.It also sets the timer zero +variable to 0. +If the Timer Compare register is zero too,the Timer 0 irq is triggered. + +HBLANK-IN is used at the end of each scanline except when in VBLANK-IN/OUT periods. + +The timer 0 is also incremented by one at each HBLANK and checked with the value +of the Timer Compare register;if equal,the timer 0 irq is triggered here too. +Notice that the timer 0 compare register can be more than the VBLANK maximum range,in +this case the timer 0 irq is simply never triggered.This is a known Sega Saturn/ST-V "bug". + +VBLANK-IN is used at the end of the vblank period. + +SCU register[36] is the timer zero compare register. +SCU register[40] is for IRQ masking. + +TODO: +- VDP1 timing and CEF emulation isn't accurate at all. +*/ + + +TIMER_DEVICE_CALLBACK_MEMBER(saturn_state::saturn_scanline) +{ + int scanline = param; + int y_step,vblank_line; + + vblank_line = get_vblank_start_position(); + y_step = get_ystep_count(); + + //popmessage("%08x %d T0 %d T1 %d %08x",m_scu.ism ^ 0xffffffff,max_y,m_scu_regs[36],m_scu_regs[37],m_scu_regs[38]); + + if(scanline == 0*y_step) + { + if(!(m_scu.ism & IRQ_VBLANK_OUT)) + { + m_maincpu->set_input_line_and_vector(0xe, HOLD_LINE, 0x41); + scu_do_transfer(1); + } + else + m_scu.ist |= (IRQ_VBLANK_OUT); + + } + else if(scanline == vblank_line*y_step) + { + if(!(m_scu.ism & IRQ_VBLANK_IN)) + { + m_maincpu->set_input_line_and_vector(0xf, HOLD_LINE ,0x40); + scu_do_transfer(0); + } + else + m_scu.ist |= (IRQ_VBLANK_IN); + + /* TODO: when Automatic Draw actually happens? Night Striker S is very fussy on this, and it looks like that VDP1 starts at more or less vblank-in time ... */ + video_update_vdp1(); + } + else if((scanline % y_step) == 0 && scanline < vblank_line*y_step) + { + if(!(m_scu.ism & IRQ_HBLANK_IN)) + { + m_maincpu->set_input_line_and_vector(0xd, HOLD_LINE, 0x42); + scu_do_transfer(2); + } + else + m_scu.ist |= (IRQ_HBLANK_IN); + } + + if(scanline == (vblank_line+1)*y_step) + { + /* docs mentions that VBE happens one line after vblank-in. */ + if(STV_VDP1_VBE) + m_vdp1.framebuffer_clear_on_next_frame = 1; + } + + + if(scanline == (m_scu_regs[36] & 0x3ff)*y_step) + { + if(!(m_scu.ism & IRQ_TIMER_0)) + { + m_maincpu->set_input_line_and_vector(0xc, HOLD_LINE, 0x43 ); + scu_do_transfer(3); + } + else + m_scu.ist |= (IRQ_TIMER_0); + } + + /* TODO: this isn't completely correct */ + if(m_scu_regs[38] & 0x1) + { + if((!(m_scu_regs[38] & 0x100) && (scanline % y_step) == 0) || + ((m_scu_regs[38] & 0x100) && (scanline == (m_scu_regs[36] & 0x3ff)*y_step))) + { + if(!(m_scu.ism & IRQ_TIMER_1)) + { + m_maincpu->set_input_line_and_vector(0xb, HOLD_LINE, 0x44 ); + scu_do_transfer(4); + } + else + m_scu.ist |= (IRQ_TIMER_1); + } + } +} + +TIMER_DEVICE_CALLBACK_MEMBER(saturn_state::saturn_slave_scanline ) +{ + int scanline = param; + int y_step,vblank_line; + + vblank_line = get_vblank_start_position(); + y_step = get_ystep_count(); + + if(scanline == vblank_line*y_step) + m_slave->set_input_line_and_vector(0x6, HOLD_LINE, 0x43); + else if((scanline % y_step) == 0 && scanline < vblank_line*y_step) + m_slave->set_input_line_and_vector(0x2, HOLD_LINE, 0x41); +} + +static const gfx_layout tiles8x8x4_layout = +{ + 8,8, + 0x100000/(32*8/8), + 4, + { 0, 1, 2, 3 }, + { 0, 4, 8, 12, 16, 20, 24, 28 }, + { 0*32, 1*32, 2*32, 3*32, 4*32, 5*32, 6*32, 7*32 }, + 32*8 +}; + +static const gfx_layout tiles16x16x4_layout = +{ + 16,16, + 0x100000/(32*32/8), + 4, + { 0, 1, 2, 3 }, + { 0, 4, 8, 12, 16, 20, 24, 28, + 32*8+0, 32*8+4, 32*8+8, 32*8+12, 32*8+16, 32*8+20, 32*8+24, 32*8+28, + + }, + { 0*32, 1*32, 2*32, 3*32, 4*32, 5*32, 6*32, 7*32, + 32*16, 32*17,32*18, 32*19,32*20,32*21,32*22,32*23 + + }, + 32*32 +}; + +static const gfx_layout tiles8x8x8_layout = +{ + 8,8, + 0x100000/(32*8/8), + 8, + { 0, 1, 2, 3, 4, 5, 6, 7 }, + { 0, 8, 16, 24, 32, 40, 48, 56 }, + { 0*64, 1*64, 2*64, 3*64, 4*64, 5*64, 6*64, 7*64 }, + 32*8 /* really 64*8, but granularity is 32 bytes */ +}; + +static const gfx_layout tiles16x16x8_layout = +{ + 16,16, + 0x100000/(64*16/8), + 8, + { 0, 1, 2, 3, 4, 5, 6, 7 }, + { 0, 8, 16, 24, 32, 40, 48, 56, + 64*8+0, 65*8, 66*8, 67*8, 68*8, 69*8, 70*8, 71*8 + + }, + { 0*64, 1*64, 2*64, 3*64, 4*64, 5*64, 6*64, 7*64, + 64*16, 64*17, 64*18, 64*19, 64*20, 64*21, 64*22, 64*23 + }, + 64*16 /* really 128*16, but granularity is 32 bytes */ +}; + + + + +GFXDECODE_START( stv ) + GFXDECODE_ENTRY( NULL, 0, tiles8x8x4_layout, 0x00, (0x80*(2+1)) ) + GFXDECODE_ENTRY( NULL, 0, tiles16x16x4_layout, 0x00, (0x80*(2+1)) ) + GFXDECODE_ENTRY( NULL, 0, tiles8x8x8_layout, 0x00, (0x08*(2+1)) ) + GFXDECODE_ENTRY( NULL, 0, tiles16x16x8_layout, 0x00, (0x08*(2+1)) ) +GFXDECODE_END + +WRITE_LINE_MEMBER(saturn_state::scudsp_end_w) +{ + if(state) + { + if(!(m_scu.ism & IRQ_DSP_END)) + m_maincpu->set_input_line_and_vector(0xa, HOLD_LINE, 0x45); + else + m_scu.ist |= (IRQ_DSP_END); + } +} + +READ16_MEMBER(saturn_state::scudsp_dma_r) +{ + address_space &program = m_maincpu->space(AS_PROGRAM); + offs_t addr = offset; + +// printf("%08x\n",addr); + + return program.read_word(addr,mem_mask); +} + + +WRITE16_MEMBER(saturn_state::scudsp_dma_w) +{ + address_space &program = m_maincpu->space(AS_PROGRAM); + offs_t addr = offset; + +// printf("%08x %02x\n",addr,data); + + program.write_word(addr, data,mem_mask); +} diff --git a/src/devices/machine/serflash.c b/src/devices/machine/serflash.c new file mode 100644 index 00000000000..60ff6712a2b --- /dev/null +++ b/src/devices/machine/serflash.c @@ -0,0 +1,411 @@ +// license:BSD-3-Clause +// copyright-holders:David Haywood, Luca Elia +/* Serial Flash Device */ + +/* todo: cleanup, refactor etc. */ +/* ghosteo.c is similar? */ + +#include "emu.h" +#include "machine/serflash.h" + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +// device type definition +const device_type SERFLASH = &device_creator; + +//------------------------------------------------- +// serflash_device - constructor +//------------------------------------------------- + +serflash_device::serflash_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, SERFLASH, "Serial Flash", tag, owner, clock, "serflash", __FILE__), + device_nvram_interface(mconfig, *this), + m_length(0) +{ +} + + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void serflash_device::device_start() +{ + m_length = machine().root_device().memregion( tag() )->bytes(); + m_region = machine().root_device().memregion( tag() )->base(); + + m_flashwritemap.resize(m_length / FLASH_PAGE_SIZE); + memset(&m_flashwritemap[0], 0, m_length / FLASH_PAGE_SIZE); +} + +void serflash_device::device_reset() +{ + m_flash_enab = 0; + flash_hard_reset(machine()); + + m_last_flash_cmd = 0x00; + m_flash_addr_seq = 0; + m_flash_addr = 0; + + m_flash_page_addr = 0; +} + +//------------------------------------------------- +// serflash_default - called to initialize SERFLASH to +// its default state +//------------------------------------------------- + +void serflash_device::nvram_default() +{ +} + + +//------------------------------------------------- +// nvram_read - called to read SERFLASH from the +// .nv file +//------------------------------------------------- + +void serflash_device::nvram_read(emu_file &file) +{ + if (m_length % FLASH_PAGE_SIZE) return; // region size must be multiple of flash page size + int size = m_length / FLASH_PAGE_SIZE; + + + if (file) + { + UINT32 page; + file.read(&page, 4); + while (page < size) + { + m_flashwritemap[page] = 1; + file.read(m_region + page * FLASH_PAGE_SIZE, FLASH_PAGE_SIZE); + file.read(&page, 4); + } + } + +} + + +//------------------------------------------------- +// nvram_write - called to write SERFLASH to the +// .nv file +//------------------------------------------------- + +void serflash_device::nvram_write(emu_file &file) +{ + if (m_length % FLASH_PAGE_SIZE) return; // region size must be multiple of flash page size + int size = m_length / FLASH_PAGE_SIZE; + + UINT32 page = 0; + while (page < size) + { + if (m_flashwritemap[page]) + { + file.write(&page, 4); + file.write(m_region + page * FLASH_PAGE_SIZE, FLASH_PAGE_SIZE); + } + page++; + } + file.write(&page, 4); +} + +void serflash_device::flash_hard_reset(running_machine &machine) +{ +// logerror("%08x FLASH: RESET\n", cpuexec_describe_context(machine)); + + m_flash_state = STATE_READ; + + m_flash_cmd_prev = -1; + m_flash_cmd_seq = 0; + + m_flash_addr_seq = 0; + m_flash_read_seq = 0; + + m_flash_row = 0; + m_flash_col = 0; + + memset(m_flash_page_data, 0, FLASH_PAGE_SIZE); + m_flash_page_addr = 0; + m_flash_page_index = 0; +} + +WRITE8_MEMBER( serflash_device::flash_enab_w ) +{ + //logerror("%08x FLASH: enab = %02X\n", m_maincpu->pc(), data); + m_flash_enab = data; +} + +void serflash_device::flash_change_state(running_machine &machine, flash_state_t state) +{ + m_flash_state = state; + + m_flash_cmd_prev = -1; + m_flash_cmd_seq = 0; + + m_flash_read_seq = 0; + m_flash_addr_seq = 0; + + //logerror("flash_change_state - FLASH: state = %s\n", m_flash_state_name[state]); +} + +WRITE8_MEMBER( serflash_device::flash_cmd_w ) +{ + if (!m_flash_enab) + return; + + //logerror("%08x FLASH: cmd = %02X (prev = %02X)\n", m_maincpu->pc(), data, m_flash_cmd_prev); + + if (m_flash_cmd_prev == -1) + { + m_flash_cmd_prev = data; + + switch (data) + { + case 0x00: // READ + m_flash_addr_seq = 0; + break; + + case 0x60: // BLOCK ERASE + m_flash_addr_seq = 0; + break; + + case 0x70: // READ STATUS + flash_change_state( space.machine(), STATE_READ_STATUS ); + break; + + case 0x80: // PAGE / CACHE PROGRAM + m_flash_addr_seq = 0; + // this actually seems to be set with the next 2 writes? + m_flash_page_addr = 0; + break; + + case 0x90: // READ ID + flash_change_state( space.machine(), STATE_READ_ID ); + break; + + case 0xff: // RESET + flash_change_state( space.machine(), STATE_IDLE ); + break; + + default: + { + //logerror("%08x FLASH: unknown cmd1 = %02X\n", cpu_get_pc(space.device()), data); + } + } + } + else + { + switch (m_flash_cmd_prev) + { + case 0x00: // READ + if (data == 0x30) + { + memcpy(m_flash_page_data, m_region + m_flash_row * FLASH_PAGE_SIZE, FLASH_PAGE_SIZE); + m_flash_page_addr = m_flash_col; + m_flash_page_index = m_flash_row; + + flash_change_state( space.machine(), STATE_READ ); + + //logerror("%08x FLASH: caching page = %04X\n", m_maincpu->pc(), m_flash_row); + } + break; + + case 0x60: // BLOCK ERASE + if (data==0xd0) + { + flash_change_state( space.machine(), STATE_BLOCK_ERASE ); + m_flashwritemap[m_flash_col] |= 1; + memset(m_region + m_flash_col * FLASH_PAGE_SIZE, 0xff, FLASH_PAGE_SIZE); + //logerror("erased block %04x (%08x - %08x)\n", m_flash_col, m_flash_col * FLASH_PAGE_SIZE, ((m_flash_col+1) * FLASH_PAGE_SIZE)-1); + } + else + { + //logerror("unexpected 2nd command after BLOCK ERASE\n"); + } + break; + case 0x80: + if (data==0x10) + { + flash_change_state( space.machine(), STATE_PAGE_PROGRAM ); + m_flashwritemap[m_flash_row] |= (memcmp(m_region + m_flash_row * FLASH_PAGE_SIZE, m_flash_page_data, FLASH_PAGE_SIZE) != 0); + memcpy(m_region + m_flash_row * FLASH_PAGE_SIZE, m_flash_page_data, FLASH_PAGE_SIZE); + //logerror("re-written block %04x (%08x - %08x)\n", m_flash_row, m_flash_row * FLASH_PAGE_SIZE, ((m_flash_row+1) * FLASH_PAGE_SIZE)-1); + + } + else + { + //logerror("unexpected 2nd command after SPAGE PROGRAM\n"); + } + break; + + + default: + { + //logerror("%08x FLASH: unknown cmd2 = %02X (cmd1 = %02X)\n", m_maincpu->pc(), data, m_flash_cmd_prev); + } + } + } +} + +WRITE8_MEMBER( serflash_device::flash_data_w ) +{ + if (!m_flash_enab) + return; + + //logerror("flash data write %04x\n", m_flash_page_addr); + m_flash_page_data[m_flash_page_addr] = data; + m_flash_page_addr++; +} + +WRITE8_MEMBER( serflash_device::flash_addr_w ) +{ + if (!m_flash_enab) + return; + + //logerror("%08x FLASH: addr = %02X (seq = %02X)\n", m_maincpu->pc(), data, m_flash_addr_seq); + + switch( m_flash_addr_seq++ ) + { + case 0: + m_flash_col = (m_flash_col & 0xff00) | data; + break; + case 1: + m_flash_col = (m_flash_col & 0x00ff) | (data << 8); + break; + case 2: + m_flash_row = (m_flash_row & 0xff00) | data; + break; + case 3: + m_flash_row = (m_flash_row & 0x00ff) | (data << 8); + m_flash_addr_seq = 0; + break; + } +} + +READ8_MEMBER( serflash_device::flash_io_r ) +{ + UINT8 data = 0x00; +// UINT32 old; + + if (!m_flash_enab) + return 0xff; + + switch (m_flash_state) + { + case STATE_READ_ID: + //old = m_flash_read_seq; + + switch( m_flash_read_seq++ ) + { + case 0: + data = 0xEC; // Manufacturer + break; + case 1: + data = 0xF1; // Device + break; + case 2: + data = 0x00; // XX + break; + case 3: + data = 0x15; // Flags + m_flash_read_seq = 0; + break; + } + + //logerror("%08x FLASH: read %02X from id(%02X)\n", m_maincpu->pc(), data, old); + break; + + case STATE_READ: + if (m_flash_page_addr > FLASH_PAGE_SIZE-1) + m_flash_page_addr = FLASH_PAGE_SIZE-1; + + //old = m_flash_page_addr; + + data = m_flash_page_data[m_flash_page_addr++]; + + //logerror("%08x FLASH: read data %02X from addr %03X (page %04X)\n", m_maincpu->pc(), data, old, m_flash_page_index); + break; + + case STATE_READ_STATUS: + // bit 7 = writeable, bit 6 = ready, bit 5 = ready/true ready, bit 1 = fail(N-1), bit 0 = fail + data = 0xe0; + //logerror("%08x FLASH: read status %02X\n", m_maincpu->pc(), data); + break; + + default: + { + // logerror("%08x FLASH: unknown read in state %s\n",0x00/*m_maincpu->pc()*/, m_flash_state_name[m_flash_state]); + } + } + + return data; +} + +READ8_MEMBER( serflash_device::flash_ready_r ) +{ + return 1; +} + + + +READ8_MEMBER(serflash_device::n3d_flash_r) +{ + if (m_last_flash_cmd==0x70) return 0xe0; + + if (m_last_flash_cmd==0x00) + { + UINT8 retdat = m_flash_page_data[m_flash_page_addr]; + + //logerror("n3d_flash_r %02x %04x\n", offset, m_flash_page_addr); + + m_flash_page_addr++; + return retdat; + } + + + logerror("n3d_flash_r %02x\n", offset); + return 0x00; + +} + + +WRITE8_MEMBER(serflash_device::n3d_flash_cmd_w) +{ + logerror("n3d_flash_cmd_w %02x %02x\n", offset, data); + m_last_flash_cmd = data; + + if (data==0x00) + { + memcpy(m_flash_page_data, m_region + m_flash_addr * FLASH_PAGE_SIZE, FLASH_PAGE_SIZE); + + } + +} + +WRITE8_MEMBER(serflash_device::n3d_flash_addr_w) +{ +// logerror("n3d_flash_addr_w %02x %02x\n", offset, data); + + m_flash_addr_seq++; + + if (m_flash_addr_seq==3) + m_flash_addr = (m_flash_addr & 0xffff00) | data; + + if (m_flash_addr_seq==4) + m_flash_addr = (m_flash_addr & 0xff00ff) | data << 8; + + if (m_flash_addr_seq==5) + m_flash_addr = (m_flash_addr & 0x00ffff) | data << 16; + + if (m_flash_addr_seq==5) + { + m_flash_addr_seq = 0; + m_flash_page_addr = 0; + logerror("set flash block to %08x\n", m_flash_addr); + } +} diff --git a/src/devices/machine/serflash.h b/src/devices/machine/serflash.h new file mode 100644 index 00000000000..fdda31e3912 --- /dev/null +++ b/src/devices/machine/serflash.h @@ -0,0 +1,108 @@ +// license:BSD-3-Clause +// copyright-holders:David Haywood, Luca Elia +/* Serial Flash */ + +#pragma once + +#ifndef __SERFLASH_H__ +#define __SERFLASH_H__ + + +#define FLASH_PAGE_SIZE (2048+64) + + + + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_SERFLASH_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, SERFLASH, 0) +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class serflash_device; + +typedef enum { STATE_IDLE = 0, STATE_READ, STATE_READ_ID, STATE_READ_STATUS, STATE_BLOCK_ERASE, STATE_PAGE_PROGRAM } flash_state_t; +//const char *m_flash_state_name[] = { "IDLE", "READ", "READ_ID", "READ_STATUS", "BLOCK ERASE", "PAGE PROGRAM" }; + +// custom initialization for default state +typedef device_delegate serflash_init_delegate; + + +// ======================> serflash_device + +class serflash_device : public device_t, + public device_nvram_interface +{ +public: + + // construction/destruction + serflash_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + DECLARE_READ8_MEMBER( flash_ready_r ); + DECLARE_READ8_MEMBER( flash_io_r ); + DECLARE_WRITE8_MEMBER( flash_addr_w ); + DECLARE_WRITE8_MEMBER( flash_data_w ); + DECLARE_WRITE8_MEMBER( flash_cmd_w ); + DECLARE_WRITE8_MEMBER( flash_enab_w ); + void flash_hard_reset(running_machine &machine); + + DECLARE_READ8_MEMBER(n3d_flash_r); + DECLARE_WRITE8_MEMBER(n3d_flash_cmd_w); + DECLARE_WRITE8_MEMBER(n3d_flash_addr_w); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_nvram_interface overrides + virtual void nvram_default(); + virtual void nvram_read(emu_file &file); + virtual void nvram_write(emu_file &file); + + void flash_change_state(running_machine &machine, flash_state_t state); + + // runtime state + size_t m_length; + UINT8* m_region; + + + flash_state_t m_flash_state; + + UINT8 m_flash_enab; + + UINT8 m_flash_cmd_seq; + UINT32 m_flash_cmd_prev; + + UINT8 m_flash_addr_seq; + UINT8 m_flash_read_seq; + + UINT16 m_flash_row, m_flash_col; + int m_flash_page_addr; + UINT16 m_flash_page_index; + + + dynamic_buffer m_flashwritemap; + + UINT8 m_last_flash_cmd; + + UINT32 m_flash_addr; + + UINT8 m_flash_page_data[FLASH_PAGE_SIZE]; + + + +}; + + +// device type definition +extern const device_type SERFLASH; + + +#endif diff --git a/src/devices/machine/smc91c9x.c b/src/devices/machine/smc91c9x.c new file mode 100644 index 00000000000..c075f03fb76 --- /dev/null +++ b/src/devices/machine/smc91c9x.c @@ -0,0 +1,531 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/************************************************************************* + + SMC91C9X ethernet controller implementation + + by Aaron Giles + +*************************************************************************** + + Notes: + * only loopback mode really works + +**************************************************************************/ + +#include "emu.h" +#include "smc91c9x.h" + + + +/*************************************************************************** + DEBUGGING +***************************************************************************/ + +#define LOG_ETHERNET (0) +#define DISPLAY_STATS (0) + + + +/*************************************************************************** + CONSTANTS +***************************************************************************/ + +/* Ethernet registers - bank 0 */ +#define EREG_TCR (0*8 + 0) +#define EREG_EPH_STATUS (0*8 + 1) +#define EREG_RCR (0*8 + 2) +#define EREG_COUNTER (0*8 + 3) +#define EREG_MIR (0*8 + 4) +#define EREG_MCR (0*8 + 5) +#define EREG_BANK (0*8 + 7) + +/* Ethernet registers - bank 1 */ +#define EREG_CONFIG (1*8 + 0) +#define EREG_BASE (1*8 + 1) +#define EREG_IA0_1 (1*8 + 2) +#define EREG_IA2_3 (1*8 + 3) +#define EREG_IA4_5 (1*8 + 4) +#define EREG_GENERAL_PURP (1*8 + 5) +#define EREG_CONTROL (1*8 + 6) + +/* Ethernet registers - bank 2 */ +#define EREG_MMU_COMMAND (2*8 + 0) +#define EREG_PNR_ARR (2*8 + 1) +#define EREG_FIFO_PORTS (2*8 + 2) +#define EREG_POINTER (2*8 + 3) +#define EREG_DATA_0 (2*8 + 4) +#define EREG_DATA_1 (2*8 + 5) +#define EREG_INTERRUPT (2*8 + 6) + +/* Ethernet registers - bank 3 */ +#define EREG_MT0_1 (3*8 + 0) +#define EREG_MT2_3 (3*8 + 1) +#define EREG_MT4_5 (3*8 + 2) +#define EREG_MT6_7 (3*8 + 3) +#define EREG_MGMT (3*8 + 4) +#define EREG_REVISION (3*8 + 5) +#define EREG_ERCV (3*8 + 6) + +/* Ethernet MMU commands */ +#define ECMD_NOP 0 +#define ECMD_ALLOCATE 1 +#define ECMD_RESET_MMU 2 +#define ECMD_REMOVE 3 +#define ECMD_REMOVE_RELEASE 4 +#define ECMD_RELEASE_PACKET 5 +#define ECMD_ENQUEUE_PACKET 6 +#define ECMD_RESET_FIFOS 7 + +/* Ethernet interrupt bits */ +#define EINT_RCV 0x01 +#define EINT_TX 0x02 +#define EINT_TX_EMPTY 0x04 +#define EINT_ALLOC 0x08 +#define EINT_RX_OVRN 0x10 +#define EINT_EPH 0x20 +#define EINT_ERCV 0x40 + +/* Ethernet register names */ +static const char *const ethernet_regname[64] = +{ + "TCR", "EPH STATUS", "RCR", "COUNTER", "MIR", "MCR", "(0.6)", "BANK", + "CONFIG", "BASE", "IA0-1", "IA2-3", "IA4-5", "GENERAL PURPOSE", "CONTROL", "BANK", + "MMU COMMAND", "PNR ARR", "FIFO PORTS", "POINTER", "DATA", "DATA", "INTERRUPT", "BANK", + "MT0-1", "MT2-3", "MT4-5", "MT6-7", "MGMT", "REVISION", "ERCV", "BANK", + "(4.0)", "(4.1)", "(4.2)", "(4.3)", "(4.4)", "(4.5)", "(4.6)", "BANK", + "(5.0)", "(5.1)", "(5.2)", "(5.3)", "(5.4)", "(5.5)", "(5.6)", "BANK", + "(6.0)", "(6.1)", "(6.2)", "(6.3)", "(6.4)", "(6.5)", "(6.6)", "BANK", + "(7.0)", "(7.1)", "(7.2)", "(7.3)", "(7.4)", "(7.5)", "(7.6)", "BANK" +}; + + + +/*************************************************************************** + DEVICE INTERFACE +***************************************************************************/ + +smc91c9x_device::smc91c9x_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + m_irq_handler(*this) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void smc91c9x_device::device_start() +{ + m_irq_handler.resolve_safe(); + + /* register ide states */ + save_item(NAME(m_reg)); + save_item(NAME(m_regmask)); + save_item(NAME(m_irq_state)); + save_item(NAME(m_alloc_count)); + save_item(NAME(m_fifo_count)); + save_item(NAME(m_rx)); + save_item(NAME(m_tx)); + save_item(NAME(m_sent)); + save_item(NAME(m_recd)); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void smc91c9x_device::device_reset() +{ + memset(m_reg, 0, sizeof(m_reg)); + memset(m_regmask, 0, sizeof(m_regmask)); + m_irq_state = 0; + m_alloc_count = 0; + m_fifo_count = 0; + m_sent = 0; + m_recd = 0; + + m_reg[EREG_TCR] = 0x0000; m_regmask[EREG_TCR] = 0x3d87; + m_reg[EREG_EPH_STATUS] = 0x0000; m_regmask[EREG_EPH_STATUS] = 0x0000; + m_reg[EREG_RCR] = 0x0000; m_regmask[EREG_RCR] = 0xc307; + m_reg[EREG_COUNTER] = 0x0000; m_regmask[EREG_COUNTER] = 0x0000; + m_reg[EREG_MIR] = 0x1212; m_regmask[EREG_MIR] = 0x0000; + m_reg[EREG_MCR] = 0x3300; m_regmask[EREG_MCR] = 0x00ff; + m_reg[EREG_BANK] = 0x3300; m_regmask[EREG_BANK] = 0x0007; + + m_reg[EREG_CONFIG] = 0x0030; m_regmask[EREG_CONFIG] = 0x17c6; + m_reg[EREG_BASE] = 0x1866; m_regmask[EREG_BASE] = 0xfffe; + m_reg[EREG_IA0_1] = 0x0000; m_regmask[EREG_IA0_1] = 0xffff; + m_reg[EREG_IA2_3] = 0x0000; m_regmask[EREG_IA2_3] = 0xffff; + m_reg[EREG_IA4_5] = 0x0000; m_regmask[EREG_IA4_5] = 0xffff; + m_reg[EREG_GENERAL_PURP] = 0x0000; m_regmask[EREG_GENERAL_PURP] = 0xffff; + m_reg[EREG_CONTROL] = 0x0100; m_regmask[EREG_CONTROL] = 0x68e7; + + m_reg[EREG_MMU_COMMAND] = 0x0000; m_regmask[EREG_MMU_COMMAND] = 0x00e7; + m_reg[EREG_PNR_ARR] = 0x8000; m_regmask[EREG_PNR_ARR] = 0x00ff; + m_reg[EREG_FIFO_PORTS] = 0x8080; m_regmask[EREG_FIFO_PORTS] = 0x0000; + m_reg[EREG_POINTER] = 0x0000; m_regmask[EREG_POINTER] = 0xf7ff; + m_reg[EREG_DATA_0] = 0x0000; m_regmask[EREG_DATA_0] = 0xffff; + m_reg[EREG_DATA_1] = 0x0000; m_regmask[EREG_DATA_1] = 0xffff; + m_reg[EREG_INTERRUPT] = 0x0004; m_regmask[EREG_INTERRUPT] = 0x7f00; + + m_reg[EREG_MT0_1] = 0x0000; m_regmask[EREG_MT0_1] = 0xffff; + m_reg[EREG_MT2_3] = 0x0000; m_regmask[EREG_MT2_3] = 0xffff; + m_reg[EREG_MT4_5] = 0x0000; m_regmask[EREG_MT4_5] = 0xffff; + m_reg[EREG_MT6_7] = 0x0000; m_regmask[EREG_MT6_7] = 0xffff; + m_reg[EREG_MGMT] = 0x3030; m_regmask[EREG_MGMT] = 0x0f0f; + m_reg[EREG_REVISION] = 0x3340; m_regmask[EREG_REVISION] = 0x0000; + m_reg[EREG_ERCV] = 0x331f; m_regmask[EREG_ERCV] = 0x009f; + + update_ethernet_irq(); +} + + +const device_type SMC91C94 = &device_creator; + +smc91c94_device::smc91c94_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : smc91c9x_device(mconfig, SMC91C94, "SMC91C94 Ethernet Controller", tag, owner, clock, "smc91c94", __FILE__) +{ +} + + +const device_type SMC91C96 = &device_creator; + +smc91c96_device::smc91c96_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : smc91c9x_device(mconfig, SMC91C96, "SMC91C96", tag, owner, clock, "smc91c96", __FILE__) +{ +} + +/*************************************************************************** + INTERNAL HELPERS +***************************************************************************/ + +/*------------------------------------------------- + update_ethernet_irq - update the IRQ state +-------------------------------------------------*/ + +void smc91c9x_device::update_ethernet_irq() +{ + UINT8 mask = m_reg[EREG_INTERRUPT] >> 8; + UINT8 state = m_reg[EREG_INTERRUPT] & 0xff; + + /* update the IRQ state */ + m_irq_state = ((mask & state) != 0); + if (!m_irq_handler.isnull()) + m_irq_handler(m_irq_state ? ASSERT_LINE : CLEAR_LINE); +} + + +/*------------------------------------------------- + update_stats - draw statistics +-------------------------------------------------*/ + +void smc91c9x_device::update_stats() +{ + if (DISPLAY_STATS) + popmessage("Sent:%d Rec'd:%d", m_sent, m_recd); +} + + +/*------------------------------------------------- + finish_enqueue - complete an enqueued packet +-------------------------------------------------*/ + +void smc91c9x_device::finish_enqueue(int param) +{ + int is_broadcast = (m_tx[4] == 0xff && m_tx[5] == 0xff && m_tx[6] == 0xff && + m_tx[7] == 0xff && m_tx[8] == 0xff && m_tx[9] == 0xff); + + /* update the EPH register and stuff it in the first transmit word */ + m_reg[EREG_EPH_STATUS] = 0x0001; + if (is_broadcast) + m_reg[EREG_EPH_STATUS] |= 0x0040; + m_tx[0] = m_reg[EREG_EPH_STATUS]; + m_tx[1] = m_reg[EREG_EPH_STATUS] >> 8; + + /* signal a transmit interrupt and mark the transmit buffer empty */ + m_reg[EREG_INTERRUPT] |= EINT_TX; + m_reg[EREG_INTERRUPT] |= EINT_TX_EMPTY; + m_reg[EREG_FIFO_PORTS] |= 0x0080; + m_sent++; + update_stats(); + + /* loopback? */ + if (m_reg[EREG_TCR] & 0x2002) + if (m_fifo_count < ETHER_RX_BUFFERS) + { + int buffer_len = ((m_tx[3] << 8) | m_tx[2]) & 0x7ff; + UINT8 *packet = &m_rx[m_fifo_count++ * ETHER_BUFFER_SIZE]; + int packet_len; + + /* compute the packet length */ + packet_len = buffer_len - 6; + if (packet[buffer_len - 1] & 0x20) + packet_len++; + + /* build up the packet */ + packet[0] = 0x0000; + packet[1] = 0x0000; + packet[2] = buffer_len; + packet[3] = buffer_len >> 8; + memcpy(&packet[4], &m_tx[4], 6); + memcpy(&packet[10], &m_tx[10], 6); + memcpy(&packet[16], &m_tx[16], buffer_len - 16); + + /* set the broadcast flag */ + if (is_broadcast) + packet[1] |= 0x40; + + /* pad? */ + if (m_reg[EREG_TCR & 0x0080]) + if (packet_len < 64) + { + memset(&packet[buffer_len], 0, 64+6 - buffer_len); + packet[buffer_len - 1] = 0; + buffer_len = 64+6; + packet[2] = buffer_len; + packet[3] = buffer_len >> 8; + } + + /* signal a receive */ + m_reg[EREG_INTERRUPT] |= EINT_RCV; + m_reg[EREG_FIFO_PORTS] &= ~0x8000; + } + update_ethernet_irq(); +} + + +/*------------------------------------------------- + process_command - handle MMU commands +-------------------------------------------------*/ + +void smc91c9x_device::process_command(UINT16 data) +{ + switch ((data >> 5) & 7) + { + case ECMD_NOP: + if (LOG_ETHERNET) + logerror(" NOP\n"); + break; + + case ECMD_ALLOCATE: + if (LOG_ETHERNET) + logerror(" ALLOCATE MEMORY FOR TX (%d)\n", (data & 7)); + m_reg[EREG_PNR_ARR] &= ~0xff00; + m_reg[EREG_PNR_ARR] |= m_alloc_count++ << 8; + m_reg[EREG_INTERRUPT] |= 0x0008; + update_ethernet_irq(); + break; + + case ECMD_RESET_MMU: + if (LOG_ETHERNET) + logerror(" RESET MMU\n"); + break; + + case ECMD_REMOVE: + if (LOG_ETHERNET) + logerror(" REMOVE FRAME FROM RX FIFO\n"); + break; + + case ECMD_REMOVE_RELEASE: + if (LOG_ETHERNET) + logerror(" REMOVE AND RELEASE FRAME FROM RX FIFO\n"); + m_reg[EREG_INTERRUPT] &= ~EINT_RCV; + if (m_fifo_count > 0) + m_fifo_count--; + if (m_fifo_count > 0) + { + memmove(&m_rx[0], &m_rx[ETHER_BUFFER_SIZE], m_fifo_count * ETHER_BUFFER_SIZE); + m_reg[EREG_INTERRUPT] |= EINT_RCV; + m_reg[EREG_FIFO_PORTS] &= ~0x8000; + } + else + m_reg[EREG_FIFO_PORTS] |= 0x8000; + update_ethernet_irq(); + m_recd++; + update_stats(); + break; + + case ECMD_RELEASE_PACKET: + if (LOG_ETHERNET) + logerror(" RELEASE SPECIFIC PACKET\n"); + break; + + case ECMD_ENQUEUE_PACKET: + if (LOG_ETHERNET) + logerror(" ENQUEUE TX PACKET\n"); + finish_enqueue(0); + break; + + case ECMD_RESET_FIFOS: + if (LOG_ETHERNET) + logerror(" RESET TX FIFOS\n"); + break; + } + m_reg[EREG_MMU_COMMAND] &= ~0x0001; +} + + + +/*************************************************************************** + CORE READ/WRITE HANDLERS +***************************************************************************/ + +/*------------------------------------------------- + smc91c9x_r - handle a read from the device +-------------------------------------------------*/ + +READ16_MEMBER( smc91c9x_device::read ) +{ + UINT32 result = ~0; + + /* determine the effective register */ + offset %= 8; + if (offset != EREG_BANK) + offset += 8 * (m_reg[EREG_BANK] & 7); + result = m_reg[offset]; + + switch (offset) + { + case EREG_PNR_ARR: + if (ACCESSING_BITS_8_15) + { + m_reg[EREG_INTERRUPT] &= ~0x0008; + update_ethernet_irq(); + } + break; + + case EREG_DATA_0: /* data register */ + case EREG_DATA_1: /* data register */ + { + UINT8 *buffer = (m_reg[EREG_POINTER] & 0x8000) ? m_rx : m_tx; + int addr = m_reg[EREG_POINTER] & 0x7ff; + result = buffer[addr++]; + if (ACCESSING_BITS_8_15) + result |= buffer[addr++] << 8; + if (m_reg[EREG_POINTER] & 0x4000) + m_reg[EREG_POINTER] = (m_reg[EREG_POINTER] & ~0x7ff) | (addr & 0x7ff); + break; + } + } + + if (LOG_ETHERNET && offset != EREG_BANK) + logerror("%s:smc91c9x_r(%s) = %04X & %04X\n", machine().describe_context(), ethernet_regname[offset], result, mem_mask); + return result; +} + + +/*------------------------------------------------- + smc91c9x_w - handle a write to the device +-------------------------------------------------*/ + +WRITE16_MEMBER( smc91c9x_device::write ) +{ + // UINT16 olddata; + + /* determine the effective register */ + offset %= 8; + if (offset != EREG_BANK) + offset += 8 * (m_reg[EREG_BANK] & 7); + + /* update the data generically */ + // olddata = m_reg[offset]; + mem_mask &= m_regmask[offset]; + COMBINE_DATA(&m_reg[offset]); + + if (LOG_ETHERNET && offset != 7) + logerror("%s:smc91c9x_w(%s) = %04X & %04X\n", machine().describe_context(), ethernet_regname[offset], data, mem_mask); + + /* handle it */ + switch (offset) + { + case EREG_TCR: /* transmit control register */ + if (LOG_ETHERNET) + { + if (data & 0x2000) logerror(" EPH LOOP\n"); + if (data & 0x1000) logerror(" STP SQET\n"); + if (data & 0x0800) logerror(" FDUPLX\n"); + if (data & 0x0400) logerror(" MON_CSN\n"); + if (data & 0x0100) logerror(" NOCRC\n"); + if (data & 0x0080) logerror(" PAD_EN\n"); + if (data & 0x0004) logerror(" FORCOL\n"); + if (data & 0x0002) logerror(" LOOP\n"); + if (data & 0x0001) logerror(" TXENA\n"); + } + break; + + case EREG_RCR: /* receive control register */ + if (LOG_ETHERNET) + { + if (data & 0x8000) reset(); + if (data & 0x8000) logerror(" SOFT RST\n"); + if (data & 0x4000) logerror(" FILT_CAR\n"); + if (data & 0x0200) logerror(" STRIP CRC\n"); + if (data & 0x0100) logerror(" RXEN\n"); + if (data & 0x0004) logerror(" ALMUL\n"); + if (data & 0x0002) logerror(" PRMS\n"); + if (data & 0x0001) logerror(" RX_ABORT\n"); + } + break; + + case EREG_CONFIG: /* configuration register */ + if (LOG_ETHERNET) + { + if (data & 0x1000) logerror(" NO WAIT\n"); + if (data & 0x0400) logerror(" FULL STEP\n"); + if (data & 0x0200) logerror(" SET SQLCH\n"); + if (data & 0x0100) logerror(" AUI SELECT\n"); + if (data & 0x0080) logerror(" 16 BIT\n"); + if (data & 0x0040) logerror(" DIS LINK\n"); + if (data & 0x0004) logerror(" INT SEL1\n"); + if (data & 0x0002) logerror(" INT SEL0\n"); + } + break; + + case EREG_BASE: /* base address register */ + if (LOG_ETHERNET) + { + logerror(" base = $%04X\n", (data & 0xe000) | ((data & 0x1f00) >> 3)); + logerror(" romsize = %d\n", ((data & 0xc0) >> 6)); + logerror(" romaddr = $%05X\n", ((data & 0x3e) << 13)); + } + break; + + case EREG_CONTROL: /* control register */ + if (LOG_ETHERNET) + { + if (data & 0x4000) logerror(" RCV_BAD\n"); + if (data & 0x2000) logerror(" PWRDN\n"); + if (data & 0x0800) logerror(" AUTO RELEASE\n"); + if (data & 0x0080) logerror(" LE ENABLE\n"); + if (data & 0x0040) logerror(" CR ENABLE\n"); + if (data & 0x0020) logerror(" TE ENABLE\n"); + if (data & 0x0004) logerror(" EEPROM SELECT\n"); + if (data & 0x0002) logerror(" RELOAD\n"); + if (data & 0x0001) logerror(" STORE\n"); + } + break; + + case EREG_MMU_COMMAND: /* command register */ + process_command(data); + break; + + case EREG_DATA_0: /* data register */ + case EREG_DATA_1: /* data register */ + { + UINT8 *buffer = (m_reg[EREG_POINTER] & 0x8000) ? m_rx : m_tx; + int addr = m_reg[EREG_POINTER] & 0x7ff; + buffer[addr++] = data; + if (ACCESSING_BITS_8_15) + buffer[addr++] = data >> 8; + if (m_reg[EREG_POINTER] & 0x4000) + m_reg[EREG_POINTER] = (m_reg[EREG_POINTER] & ~0x7ff) | (addr & 0x7ff); + break; + } + + case EREG_INTERRUPT: + m_reg[EREG_INTERRUPT] &= ~(data & 0x56); + update_ethernet_irq(); + break; + } +} diff --git a/src/devices/machine/smc91c9x.h b/src/devices/machine/smc91c9x.h new file mode 100644 index 00000000000..799af951928 --- /dev/null +++ b/src/devices/machine/smc91c9x.h @@ -0,0 +1,100 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/************************************************************************* + + SMC91C9X ethernet controller implementation + + by Aaron Giles + +**************************************************************************/ + +#ifndef __SMC91C9X__ +#define __SMC91C9X__ + +#define ETHER_BUFFER_SIZE (2048) +#define ETHER_RX_BUFFERS (4) + +/*************************************************************************** + TYPE DEFINITIONS +***************************************************************************/ + +class smc91c9x_device : public device_t +{ +public: + smc91c9x_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + ~smc91c9x_device() {} + + template static devcb_base &set_irq_callback(device_t &device, _Object object) { return downcast(device).m_irq_handler.set_callback(object); } + + DECLARE_READ16_MEMBER( read ); + DECLARE_WRITE16_MEMBER( write ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + +private: + // internal state + devcb_write_line m_irq_handler; + + /* raw register data and masks */ + UINT16 m_reg[64]; + UINT16 m_regmask[64]; + + /* IRQ information */ + UINT8 m_irq_state; + + /* allocate information */ + UINT8 m_alloc_count; + + /* transmit/receive FIFOs */ + UINT8 m_fifo_count; + UINT8 m_rx[ETHER_BUFFER_SIZE * ETHER_RX_BUFFERS]; + UINT8 m_tx[ETHER_BUFFER_SIZE]; + + /* counters */ + UINT32 m_sent; + UINT32 m_recd; + + void update_ethernet_irq(); + void update_stats(); + void finish_enqueue(int param); + void process_command(UINT16 data); +}; + + +class smc91c94_device : public smc91c9x_device +{ +public: + smc91c94_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +extern const device_type SMC91C94; + +class smc91c96_device : public smc91c9x_device +{ +public: + smc91c96_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +extern const device_type SMC91C96; + +/*************************************************************************** + DEVICE CONFIGURATION MACROS +***************************************************************************/ + +#define MCFG_SMC91C94_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, SMC91C94, 0) + +#define MCFG_SMC91C94_IRQ_CALLBACK(_write) \ + devcb = &smc91c94_device::set_irq_callback(*device, DEVCB_##_write); + +#define MCFG_SMC91C96_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, SMC91C96, 0) + +#define MCFG_SMC91C96_IRQ_CALLBACK(_write) \ + devcb = &smc91c96_device::set_irq_callback(*device, DEVCB_##_write); + + +#endif diff --git a/src/devices/machine/smpc.c b/src/devices/machine/smpc.c new file mode 100644 index 00000000000..caf0834da5a --- /dev/null +++ b/src/devices/machine/smpc.c @@ -0,0 +1,1084 @@ +// license:LGPL-2.1+ +// copyright-holders:Angelo Salese, R. Belmont +/************************************************************************************ + +Sega Saturn SMPC - System Manager and Peripheral Control MCU simulation + +The SMPC is actually a 4-bit Hitachi HD404920FS MCU, labeled with a Sega custom +315-5744 (that needs decapping) + +MCU simulation by Angelo Salese & R. Belmont + +TODO: +- timings; +- fix intback issue with inputs (according to the docs, it should fall in between + VBLANK-IN and OUT, for obvious reasons); +- clean-ups; + +*************************************************************************************/ +/* SMPC Addresses + +00 +01 -w Input Register 0 (IREG) +02 +03 -w Input Register 1 +04 +05 -w Input Register 2 +06 +07 -w Input Register 3 +08 +09 -w Input Register 4 +0a +0b -w Input Register 5 +0c +0d -w Input Register 6 +0e +0f +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +1a +1b +1c +1d +1e +1f -w Command Register (COMREG) +20 +21 r- Output Register 0 (OREG) +22 +23 r- Output Register 1 +24 +25 r- Output Register 2 +26 +27 r- Output Register 3 +28 +29 r- Output Register 4 +2a +2b r- Output Register 5 +2c +2d r- Output Register 6 +2e +2f r- Output Register 7 +30 +31 r- Output Register 8 +32 +33 r- Output Register 9 +34 +35 r- Output Register 10 +36 +37 r- Output Register 11 +38 +39 r- Output Register 12 +3a +3b r- Output Register 13 +3c +3d r- Output Register 14 +3e +3f r- Output Register 15 +40 +41 r- Output Register 16 +42 +43 r- Output Register 17 +44 +45 r- Output Register 18 +46 +47 r- Output Register 19 +48 +49 r- Output Register 20 +4a +4b r- Output Register 21 +4c +4d r- Output Register 22 +4e +4f r- Output Register 23 +50 +51 r- Output Register 24 +52 +53 r- Output Register 25 +54 +55 r- Output Register 26 +56 +57 r- Output Register 27 +58 +59 r- Output Register 28 +5a +5b r- Output Register 29 +5c +5d r- Output Register 30 +5e +5f r- Output Register 31 +60 +61 r- SR +62 +63 rw SF +64 +65 +66 +67 +68 +69 +6a +6b +6c +6d +6e +6f +70 +71 +72 +73 +74 +75 rw PDR1 +76 +77 rw PDR2 +78 +79 -w DDR1 +7a +7b -w DDR2 +7c +7d -w IOSEL2/1 +7e +7f -w EXLE2/1 +*/ + +#include "emu.h" +#include "coreutil.h" +#include "includes/stv.h" +#include "machine/smpc.h" +#include "machine/eepromser.h" + +#define LOG_SMPC 0 +#define LOG_PAD_CMD 0 + + +/******************************************** + * + * Bankswitch code for ST-V Multi Cart mode + * + *******************************************/ + +void saturn_state::stv_select_game(int gameno) +{ + if (m_prev_bankswitch != gameno) + { + if (m_cart_reg[gameno] && m_cart_reg[gameno]->base()) + memcpy(memregion("abus")->base(), m_cart_reg[gameno]->base(), 0x3000000); + else + memset(memregion("abus")->base(), 0x00, 0x3000000); // TODO: 1-filled? + + m_prev_bankswitch = gameno; + } +} + +/******************************************** + * + * Command functions + * + *******************************************/ + +void saturn_state::smpc_master_on() +{ + m_maincpu->set_input_line(INPUT_LINE_RESET, CLEAR_LINE); +} + +TIMER_CALLBACK_MEMBER( saturn_state::smpc_slave_enable ) +{ + m_slave->set_input_line(INPUT_LINE_RESET, param ? ASSERT_LINE : CLEAR_LINE); + m_smpc.OREG[31] = param + 0x02; //read-back for last command issued + m_smpc.SF = 0x00; //clear hand-shake flag + m_smpc.slave_on = param; +// printf("%d %d\n",machine().first_screen()->hpos(),machine().first_screen()->vpos()); +} + +TIMER_CALLBACK_MEMBER( saturn_state::smpc_sound_enable ) +{ + m_audiocpu->set_input_line(INPUT_LINE_RESET, param ? ASSERT_LINE : CLEAR_LINE); + m_en_68k = param ^ 1; + m_smpc.OREG[31] = param + 0x06; //read-back for last command issued + m_smpc.SF = 0x00; //clear hand-shake flag +} + +TIMER_CALLBACK_MEMBER( saturn_state::smpc_cd_enable ) +{ + m_smpc.OREG[31] = param + 0x08; //read-back for last command issued + m_smpc.SF = 0x08; //clear hand-shake flag (TODO: diagnostic wants this to have bit 3 high) +} + +void saturn_state::smpc_system_reset() +{ + /*Only backup ram and SMPC ram are retained after that this command is issued.*/ + memset(m_scu_regs ,0x00,0x000100); + memset(m_scsp_regs,0x00,0x001000); + memset(m_sound_ram,0x00,0x080000); + memset(m_workram_h,0x00,0x100000); + memset(m_workram_l,0x00,0x100000); + memset(m_vdp2_regs,0x00,0x040000); + memset(m_vdp2_vram,0x00,0x100000); + memset(m_vdp2_cram,0x00,0x080000); + memset(m_vdp1_vram,0x00,0x100000); + //A-Bus + + m_maincpu->set_input_line(INPUT_LINE_RESET, PULSE_LINE); +} + +TIMER_CALLBACK_MEMBER( saturn_state::smpc_change_clock ) +{ + UINT32 xtal; + + if(LOG_SMPC) printf ("Clock change execute at (%d %d)\n",machine().first_screen()->hpos(),machine().first_screen()->vpos()); + + xtal = param ? MASTER_CLOCK_320 : MASTER_CLOCK_352; + + machine().device("maincpu")->set_unscaled_clock(xtal/2); + machine().device("slave")->set_unscaled_clock(xtal/2); + + m_vdp2.dotsel = param ^ 1; + stv_vdp2_dynamic_res_change(); + + m_maincpu->set_input_line(INPUT_LINE_HALT, CLEAR_LINE); + if(!m_NMI_reset) + m_maincpu->set_input_line(INPUT_LINE_NMI, PULSE_LINE); + m_slave->set_input_line(INPUT_LINE_HALT, CLEAR_LINE); + m_slave->set_input_line(INPUT_LINE_RESET, ASSERT_LINE); + m_audiocpu->set_input_line(INPUT_LINE_HALT, CLEAR_LINE); + + /* put issued command in OREG31 */ + m_smpc.OREG[31] = 0x0e + param; + /* clear hand-shake flag */ + m_smpc.SF = 0x00; + + /* TODO: VDP1 / VDP2 / SCU / SCSP default power ON values? */ +} + +TIMER_CALLBACK_MEMBER( saturn_state::stv_intback_peripheral ) +{ + if (m_smpc.intback_stage == 2) + { + m_smpc.SR = (0x80 | m_smpc.pmode); // pad 2, no more data, echo back pad mode set by intback + m_smpc.intback_stage = 0; + } + else + { + m_smpc.SR = (0xc0 | m_smpc.pmode); // pad 1, more data, echo back pad mode set by intback + m_smpc.intback_stage ++; + } + + if(!(m_scu.ism & IRQ_SMPC)) + m_maincpu->set_input_line_and_vector(8, HOLD_LINE, 0x47); + else + m_scu.ist |= (IRQ_SMPC); + + m_smpc.OREG[31] = 0x10; /* callback for last command issued */ + m_smpc.SF = 0x00; /* clear hand-shake flag */ +} + + +TIMER_CALLBACK_MEMBER( saturn_state::stv_smpc_intback ) +{ + int i; + +// printf("%02x %02x %02x\n",m_smpc.intback_buf[0],m_smpc.intback_buf[1],m_smpc.intback_buf[2]); + + if(m_smpc.intback_buf[0] != 0) + { + m_smpc.OREG[0] = (0x80) | ((m_NMI_reset & 1) << 6); + + for(i=0;i<7;i++) + m_smpc.OREG[1+i] = m_smpc.rtc_data[i]; + + m_smpc.OREG[8]=0x00; // CTG0 / CTG1? + + m_smpc.OREG[9]=0x00; // TODO: system region on Saturn + + m_smpc.OREG[10]= 0 << 7 | + m_vdp2.dotsel << 6 | + 1 << 5 | + 1 << 4 | + 0 << 3 | //MSHNMI + 1 << 2 | + 0 << 1 | //SYSRES + 0 << 0; //SOUNDRES + m_smpc.OREG[11]= 0 << 6; //CDRES + + for(i=0;i<4;i++) + m_smpc.OREG[12+i]=m_smpc.SMEM[i]; + + for(i=0;i<15;i++) + m_smpc.OREG[16+i]=0xff; // undefined + + m_smpc.intback_stage = (m_smpc.intback_buf[1] & 8) >> 3; // first peripheral + m_smpc.SR = 0x40 | m_smpc.intback_stage << 5; + m_smpc.pmode = m_smpc.intback_buf[0]>>4; + + // /*This is for RTC,cartridge code and similar stuff...*/ + //if(LOG_SMPC) printf ("Interrupt: System Manager (SMPC) at scanline %04x, Vector 0x47 Level 0x08\n",scanline); + if(!(m_scu.ism & IRQ_SMPC)) + m_maincpu->set_input_line_and_vector(8, HOLD_LINE, 0x47); + else + m_scu.ist |= (IRQ_SMPC); + + /* put issued command in OREG31 */ + m_smpc.OREG[31] = 0x10; // TODO: doc says 0? + /* clear hand-shake flag */ + m_smpc.SF = 0x00; + } + else if(m_smpc.intback_buf[1] & 8) + { + m_smpc.intback_stage = (m_smpc.intback_buf[1] & 8) >> 3; // first peripheral + m_smpc.SR = 0x40; + m_smpc.OREG[31] = 0x10; + machine().scheduler().timer_set(attotime::from_usec(0), timer_expired_delegate(FUNC(saturn_state::stv_intback_peripheral),this),0); + } + else + { + /* Shienryu calls this, it would be plainly illegal on Saturn, I'll just return the command and clear the hs flag for now. */ + m_smpc.OREG[31] = 0x10; + m_smpc.SF = 0x00; + } +} + + +/* + [0] port status: + 0x04 Sega-tap + 0x16 Multi-tap + 0x2x clock serial peripheral + 0xf0 peripheral isn't connected + 0xf1 peripheral is connected + [1] Peripheral ID (note: lowest four bits determines the size of the input packet) + 0x02 digital pad + 0x25 (tested by Game Basic?) + 0x34 keyboard +*/ + +void saturn_state::smpc_digital_pad(UINT8 pad_num, UINT8 offset) +{ + static const char *const padnames[] = { "JOY1", "JOY2" }; + UINT16 pad_data; + + pad_data = ioport(padnames[pad_num])->read(); + m_smpc.OREG[0+pad_num*offset] = 0xf1; + m_smpc.OREG[1+pad_num*offset] = 0x02; + m_smpc.OREG[2+pad_num*offset] = pad_data>>8; + m_smpc.OREG[3+pad_num*offset] = pad_data & 0xff; +} + +void saturn_state::smpc_analog_pad( UINT8 pad_num, UINT8 offset, UINT8 id) +{ + static const char *const padnames[] = { "AN_JOY1", "AN_JOY2" }; + static const char *const annames[2][3] = { { "AN_X1", "AN_Y1", "AN_Z1" }, + { "AN_X2", "AN_Y2", "AN_Z2" }}; + UINT16 pad_data; + + pad_data = ioport(padnames[pad_num])->read(); + m_smpc.OREG[0+pad_num*offset] = 0xf1; + m_smpc.OREG[1+pad_num*offset] = id; + m_smpc.OREG[2+pad_num*offset] = pad_data>>8; + m_smpc.OREG[3+pad_num*offset] = pad_data & 0xff; + m_smpc.OREG[4+pad_num*offset] = ioport(annames[pad_num][0])->read(); + if(id == 0x15) + { + m_smpc.OREG[5+pad_num*offset] = ioport(annames[pad_num][1])->read(); + m_smpc.OREG[6+pad_num*offset] = ioport(annames[pad_num][2])->read(); + } +} + +void saturn_state::smpc_keyboard(UINT8 pad_num, UINT8 offset) +{ + UINT16 game_key; + + game_key = 0xffff; + + game_key ^= ((ioport("KEYS_1")->read() & 0x80) << 8); // right + game_key ^= ((ioport("KEYS_1")->read() & 0x40) << 8); // left + game_key ^= ((ioport("KEYS_1")->read() & 0x20) << 8); // down + game_key ^= ((ioport("KEYS_1")->read() & 0x10) << 8); // up + game_key ^= ((ioport("KEYF")->read() & 0x80) << 4); // ESC -> START + game_key ^= ((ioport("KEY3")->read() & 0x04) << 8); // Z / A trigger + game_key ^= ((ioport("KEY4")->read() & 0x02) << 8); // C / C trigger + game_key ^= ((ioport("KEY6")->read() & 0x04) << 6); // X / B trigger + game_key ^= ((ioport("KEY2")->read() & 0x20) << 2); // Q / R trigger + game_key ^= ((ioport("KEY3")->read() & 0x10) << 2); // A / X trigger + game_key ^= ((ioport("KEY3")->read() & 0x08) << 2); // S / Y trigger + game_key ^= ((ioport("KEY4")->read() & 0x08) << 1); // D / Z trigger + game_key ^= ((ioport("KEY4")->read() & 0x10) >> 1); // E / L trigger + + m_smpc.OREG[0+pad_num*offset] = 0xf1; + m_smpc.OREG[1+pad_num*offset] = 0x34; + m_smpc.OREG[2+pad_num*offset] = game_key>>8; // game buttons, TODO + m_smpc.OREG[3+pad_num*offset] = game_key & 0xff; + /* + Keyboard Status hook-up + TODO: how shift key actually works? EGWord uses it in order to switch between hiragana and katakana modes. + x--- ---- 0 + -x-- ---- caps lock + --x- ---- num lock + ---x ---- scroll lock + ---- x--- data ok + ---- -x-- 1 + ---- --x- 1 + ---- ---x Break key + */ + m_smpc.OREG[4+pad_num*offset] = m_keyb.status | 6; + if(m_keyb.prev_data != m_keyb.data) + { + m_smpc.OREG[5+pad_num*offset] = m_keyb.data; + m_keyb.repeat_count = 0; + m_keyb.prev_data = m_keyb.data; + } + else + { + /* Very crude repeat support */ + m_keyb.repeat_count ++; + m_keyb.repeat_count = m_keyb.repeat_count > 32 ? 32 : m_keyb.repeat_count; + m_smpc.OREG[5+pad_num*offset] = (m_keyb.repeat_count == 32) ? m_keyb.data : 0; + } +} + +void saturn_state::smpc_mouse(UINT8 pad_num, UINT8 offset, UINT8 id) +{ + static const char *const mousenames[2][3] = { { "MOUSEB1", "MOUSEX1", "MOUSEY1" }, + { "MOUSEB2", "MOUSEX2", "MOUSEY2" }}; + UINT8 mouse_ctrl; + INT16 mouse_x, mouse_y; + + mouse_ctrl = ioport(mousenames[pad_num][0])->read(); + mouse_x = ioport(mousenames[pad_num][1])->read(); + mouse_y = ioport(mousenames[pad_num][2])->read(); + + if(mouse_x < 0) + mouse_ctrl |= 0x10; + + if(mouse_y < 0) + mouse_ctrl |= 0x20; + + if((mouse_x & 0xff00) != 0xff00 && (mouse_x & 0xff00) != 0x0000) + mouse_ctrl |= 0x40; + + if((mouse_y & 0xff00) != 0xff00 && (mouse_y & 0xff00) != 0x0000) + mouse_ctrl |= 0x80; + + m_smpc.OREG[0+pad_num*offset] = 0xf1; + m_smpc.OREG[1+pad_num*offset] = id; // 0x23 / 0xe3 + m_smpc.OREG[2+pad_num*offset] = mouse_ctrl; + m_smpc.OREG[3+pad_num*offset] = mouse_x & 0xff; + m_smpc.OREG[4+pad_num*offset] = mouse_y & 0xff; +} + +/* TODO: is there ANY game on which the MD pad works? */ +void saturn_state::smpc_md_pad(UINT8 pad_num, UINT8 offset, UINT8 id) +{ + static const char *const padnames[] = { "MD_JOY1", "MD_JOY2" }; + UINT16 pad_data; + + pad_data = ioport(padnames[pad_num])->read(); + m_smpc.OREG[0+pad_num*offset] = 0xf1; + m_smpc.OREG[1+pad_num*offset] = id; + m_smpc.OREG[2+pad_num*offset] = pad_data>>8; + if(id == 0xe2) // MD 6 Button PAD + m_smpc.OREG[3+pad_num*offset] = pad_data & 0xff; +} + +void saturn_state::smpc_unconnected(UINT8 pad_num, UINT8 offset) +{ + m_smpc.OREG[0+pad_num*offset] = 0xf0; +} + +TIMER_CALLBACK_MEMBER( saturn_state::intback_peripheral ) +{ + int pad_num; + static const UINT8 peri_id[10] = { 0x02, 0x13, 0x15, 0x23, 0x23, 0x34, 0xe1, 0xe2, 0xe3, 0xff }; + UINT8 read_id[2]; + UINT8 offset; + +// if (LOG_SMPC) logerror("SMPC: providing PAD data for intback, pad %d\n", intback_stage-2); + + read_id[0] = (ioport("INPUT_TYPE")->read()) & 0x0f; + read_id[1] = (ioport("INPUT_TYPE")->read()) >> 4; + + /* doesn't work? */ + //pad_num = m_smpc.intback_stage - 1; + + if(LOG_PAD_CMD) printf("%d %d %d\n",m_smpc.intback_stage - 1,machine().first_screen()->vpos(),(int)machine().first_screen()->frame_number()); + + offset = 0; + + for(pad_num=0;pad_num<2;pad_num++) + { + switch(read_id[pad_num]) + { + case 0: smpc_digital_pad(pad_num,offset); break; + case 1: smpc_analog_pad(pad_num,offset,peri_id[read_id[pad_num]]); break; /* Steering Wheel */ + case 2: smpc_analog_pad(pad_num,offset,peri_id[read_id[pad_num]]); break; /* Analog Pad */ + case 4: smpc_mouse(pad_num,offset,peri_id[read_id[pad_num]]); break; /* Pointing Device */ + case 5: smpc_keyboard(pad_num,offset); break; + case 6: smpc_md_pad(pad_num,offset,peri_id[read_id[pad_num]]); break; /* MD 3B PAD */ + case 7: smpc_md_pad(pad_num,offset,peri_id[read_id[pad_num]]); break; /* MD 6B PAD */ + case 8: smpc_mouse(pad_num,offset,peri_id[read_id[pad_num]]); break; /* Saturn Mouse */ + case 9: smpc_unconnected(pad_num,offset); break; + } + + offset += (peri_id[read_id[pad_num]] & 0xf) + 2; /* offset for port 2 */ + } + + if (m_smpc.intback_stage == 2) + { + m_smpc.SR = (0x80 | m_smpc.pmode); // pad 2, no more data, echo back pad mode set by intback + m_smpc.intback_stage = 0; + } + else + { + m_smpc.SR = (0xc0 | m_smpc.pmode); // pad 1, more data, echo back pad mode set by intback + m_smpc.intback_stage ++; + } + + if(!(m_scu.ism & IRQ_SMPC)) + m_maincpu->set_input_line_and_vector(8, HOLD_LINE, 0x47); + else + m_scu.ist |= (IRQ_SMPC); + + m_smpc.OREG[31] = 0x10; /* callback for last command issued */ + m_smpc.SF = 0x00; /* clear hand-shake flag */ +} + +TIMER_CALLBACK_MEMBER( saturn_state::saturn_smpc_intback ) +{ + if(m_smpc.intback_buf[0] != 0) + { + { + int i; + + m_smpc.OREG[0] = (0x80) | ((m_NMI_reset & 1) << 6); // bit 7: SETTIME (RTC isn't setted up properly) + + for(i=0;i<7;i++) + m_smpc.OREG[1+i] = m_smpc.rtc_data[i]; + + m_smpc.OREG[8]=0x00; //Cartridge code? + + m_smpc.OREG[9] = m_saturn_region; + + m_smpc.OREG[10]= 0 << 7 | + m_vdp2.dotsel << 6 | + 1 << 5 | + 1 << 4 | + 0 << 3 | //MSHNMI + 1 << 2 | + 0 << 1 | //SYSRES + 0 << 0; //SOUNDRES + m_smpc.OREG[11]= 0 << 6; //CDRES + + for(i=0;i<4;i++) + m_smpc.OREG[12+i]=m_smpc.SMEM[i]; + + for(i=0;i<15;i++) + m_smpc.OREG[16+i]=0xff; // undefined + } + + m_smpc.intback_stage = (m_smpc.intback_buf[1] & 8) >> 3; // first peripheral + m_smpc.SR = 0x40 | m_smpc.intback_stage << 5; + m_smpc.pmode = m_smpc.intback_buf[0]>>4; + + if(!(m_scu.ism & IRQ_SMPC)) + m_maincpu->set_input_line_and_vector(8, HOLD_LINE, 0x47); + else + m_scu.ist |= (IRQ_SMPC); + + /* put issued command in OREG31 */ + m_smpc.OREG[31] = 0x10; + /* clear hand-shake flag */ + m_smpc.SF = 0x00; + } + else if(m_smpc.intback_buf[1] & 8) + { + m_smpc.intback_stage = (m_smpc.intback_buf[1] & 8) >> 3; // first peripheral + m_smpc.SR = 0x40; + m_smpc.OREG[31] = 0x10; + machine().scheduler().timer_set(attotime::from_usec(0), timer_expired_delegate(FUNC(saturn_state::intback_peripheral),this),0); + } + else + { + printf("SMPC intback bogus behaviour called %02x %02x\n",m_smpc.IREG[0],m_smpc.IREG[1]); + } + +} + +void saturn_state::smpc_rtc_write() +{ + int i; + + for(i=0;i<7;i++) + m_smpc.rtc_data[i] = m_smpc.IREG[i]; +} + +void saturn_state::smpc_memory_setting() +{ + int i; + + for(i=0;i<4;i++) + m_smpc.SMEM[i] = m_smpc.IREG[i]; +} + +void saturn_state::smpc_nmi_req() +{ + /*NMI is unconditionally requested */ + m_maincpu->set_input_line(INPUT_LINE_NMI, PULSE_LINE); +} + +TIMER_CALLBACK_MEMBER( saturn_state::smpc_nmi_set ) +{ +// printf("%d %d\n",machine().first_screen()->hpos(),machine().first_screen()->vpos()); + + m_NMI_reset = param; + /* put issued command in OREG31 */ + m_smpc.OREG[31] = 0x19 + param; + /* clear hand-shake flag */ + m_smpc.SF = 0x00; + + //m_smpc.OREG[0] = (0x80) | ((m_NMI_reset & 1) << 6); +} + + +TIMER_CALLBACK_MEMBER( saturn_state::smpc_audio_reset_line_pulse ) +{ + m_audiocpu->set_input_line(INPUT_LINE_RESET, PULSE_LINE); +} + +/******************************************** + * + * COMREG sub-routine + * + *******************************************/ + +void saturn_state::smpc_comreg_exec(address_space &space, UINT8 data, UINT8 is_stv) +{ + switch (data) + { + case 0x00: + if(LOG_SMPC) printf ("SMPC: Master ON\n"); + smpc_master_on(); + break; + //case 0x01: Master OFF? + case 0x02: + case 0x03: + if(LOG_SMPC) printf ("SMPC: Slave %s %d %d\n",(data & 1) ? "off" : "on",machine().first_screen()->hpos(),machine().first_screen()->vpos()); + machine().scheduler().timer_set(attotime::from_usec(15), timer_expired_delegate(FUNC(saturn_state::smpc_slave_enable),this),data & 1); + break; + case 0x06: + case 0x07: + if(LOG_SMPC) printf ("SMPC: Sound %s\n",(data & 1) ? "off" : "on"); + + if(!is_stv) + machine().scheduler().timer_set(attotime::from_usec(15), timer_expired_delegate(FUNC(saturn_state::smpc_sound_enable),this),data & 1); + break; + /*CD (SH-1) ON/OFF */ + case 0x08: + case 0x09: + printf ("SMPC: CD %s\n",(data & 1) ? "off" : "on"); + machine().scheduler().timer_set(attotime::from_usec(20), timer_expired_delegate(FUNC(saturn_state::smpc_cd_enable),this),data & 1); + break; + case 0x0a: + case 0x0b: + popmessage ("SMPC: NETLINK %s, contact MAMEdev",(data & 1) ? "off" : "on"); + break; case 0x0d: + if(LOG_SMPC) printf ("SMPC: System Reset\n"); + smpc_system_reset(); + break; + case 0x0e: + case 0x0f: + if(LOG_SMPC) printf ("SMPC: Change Clock to %s (%d %d)\n",data & 1 ? "320" : "352",machine().first_screen()->hpos(),machine().first_screen()->vpos()); + + /* on ST-V timing of this is pretty fussy, you get 2 credits at start-up otherwise + My current theory is that SMPC first stops all CPUs until it executes the whole snippet for this, + and restarts them when the screen is again ready for use. I really don't think that the system + can do an usable mid-frame clock switching anyway. + */ + + m_maincpu->set_input_line(INPUT_LINE_HALT, ASSERT_LINE); + m_slave->set_input_line(INPUT_LINE_HALT, ASSERT_LINE); + m_audiocpu->set_input_line(INPUT_LINE_HALT, ASSERT_LINE); + + machine().scheduler().timer_set(machine().first_screen()->time_until_pos(get_vblank_start_position()*get_ystep_count(), 0), timer_expired_delegate(FUNC(saturn_state::smpc_change_clock),this),data & 1); + break; + /*"Interrupt Back"*/ + case 0x10: + if(0) + { + printf ("SMPC: Status Acquire %02x %02x %02x %d\n",m_smpc.IREG[0],m_smpc.IREG[1],m_smpc.IREG[2],machine().first_screen()->vpos()); + } + + int timing; + + timing = 8; + + if(m_smpc.IREG[0] != 0) // non-peripheral data + timing += 8; + + /* TODO: At vblank-out actually ... */ + if(m_smpc.IREG[1] & 8) // peripheral data + timing += 700; + + /* TODO: check if IREG[2] is setted to 0xf0 */ + { + int i; + + for(i=0;i<3;i++) + m_smpc.intback_buf[i] = m_smpc.IREG[i]; + } + + if(is_stv) + { + machine().scheduler().timer_set(attotime::from_usec(timing), timer_expired_delegate(FUNC(saturn_state::stv_smpc_intback),this),0); //TODO: variable time + } + else + { + if(LOG_PAD_CMD) printf("INTBACK %02x %02x %d %d\n",m_smpc.IREG[0],m_smpc.IREG[1],machine().first_screen()->vpos(),(int)machine().first_screen()->frame_number()); + machine().scheduler().timer_set(attotime::from_usec(timing), timer_expired_delegate(FUNC(saturn_state::saturn_smpc_intback),this),0); //TODO: is variable time correct? + } + break; + /* RTC write*/ + case 0x16: + if(LOG_SMPC) printf("SMPC: RTC write\n"); + smpc_rtc_write(); + break; + /* SMPC memory setting*/ + case 0x17: + if(LOG_SMPC) printf ("SMPC: memory setting\n"); + smpc_memory_setting(); + break; + case 0x18: + if(LOG_SMPC) printf ("SMPC: NMI request\n"); + smpc_nmi_req(); + break; + case 0x19: + case 0x1a: + /* TODO: timing */ + if(LOG_SMPC) printf ("SMPC: NMI %sable %d %d\n",data & 1 ? "Dis" : "En",machine().first_screen()->hpos(),machine().first_screen()->vpos()); + machine().scheduler().timer_set(attotime::from_usec(100), timer_expired_delegate(FUNC(saturn_state::smpc_nmi_set),this),data & 1); + break; + default: + printf ("cpu '%s' (PC=%08X) SMPC: undocumented Command %02x\n", space.device().tag(), space.device().safe_pc(), data); + } +} + +/******************************************** + * + * ST-V handlers + * + *******************************************/ + +READ8_MEMBER( saturn_state::stv_SMPC_r ) +{ + int return_data = 0; + + if(!(offset & 1)) + return 0; + + if(offset >= 0x21 && offset <= 0x5f) + return_data = m_smpc.OREG[(offset-0x21) >> 1]; + + if (offset == 0x61) // TODO: SR + return_data = m_smpc.SR; + + if (offset == 0x63) + return_data = m_smpc.SF; + + if (offset == 0x75)//PDR1 read + return_data = ioport("DSW1")->read(); + + if (offset == 0x77)//PDR2 read + return_data = (0xfe | m_eeprom->do_read()); + + return return_data; +} + +WRITE8_MEMBER( saturn_state::stv_SMPC_w ) +{ + if (!(offset & 1)) // avoid writing to even bytes + return; + +// if(LOG_SMPC) printf ("8-bit SMPC Write to Offset %02x with Data %02x\n", offset, data); + + if(offset >= 1 && offset <= 0xd) + m_smpc.IREG[offset >> 1] = data; + + if(offset == 1) //IREG0, check if a BREAK / CONTINUE request for INTBACK command + { + if(m_smpc.intback_stage) + { + if(data & 0x40) + { + if(LOG_PAD_CMD) printf("SMPC: BREAK request\n"); + m_smpc.SR &= 0x0f; + m_smpc.intback_stage = 0; + } + else if(data & 0x80) + { + if(LOG_PAD_CMD) printf("SMPC: CONTINUE request\n"); + machine().scheduler().timer_set(attotime::from_usec(700), timer_expired_delegate(FUNC(saturn_state::stv_intback_peripheral),this),0); /* TODO: is timing correct? */ + m_smpc.OREG[31] = 0x10; + m_smpc.SF = 0x01; //TODO: set hand-shake flag? + } + } + } + + if (offset == 0x1f) // COMREG + { + smpc_comreg_exec(space,data,1); + + // we've processed the command, clear status flag + if(data != 0x10 && data != 0x02 && data != 0x03 && data != 0x08 && data != 0x09 && data != 0xe && data != 0xf && data != 0x19 && data != 0x1a) + { + m_smpc.OREG[31] = data; //read-back command + m_smpc.SF = 0x00; + } + /*TODO:emulate the timing of each command...*/ + } + + if(offset == 0x63) + m_smpc.SF = data & 1; + + if(offset == 0x75) + { + /* + -xx- ---- PDR1 + ---x ---- EEPROM write bit + ---- x--- EEPROM CLOCK line + ---- -x-- EEPROM CS line + ---- --xx A-Bus bank bits + */ + m_eeprom->clk_write((data & 0x08) ? ASSERT_LINE : CLEAR_LINE); + m_eeprom->di_write((data >> 4) & 1); + m_eeprom->cs_write((data & 0x04) ? ASSERT_LINE : CLEAR_LINE); + m_stv_multi_bank = data & 3; + + stv_select_game(m_stv_multi_bank); + + m_smpc.PDR1 = (data & 0x60); + } + + if(offset == 0x77) + { + /* + -xx- ---- PDR2 + ---x ---- Enable Sound System (ACTIVE LOW) + */ + //popmessage("PDR2 = %02x",m_smpc_ram[0x77]); + + if(LOG_SMPC) printf("SMPC: M68k %s\n",(data & 0x10) ? "off" : "on"); + //machine().scheduler().timer_set(attotime::from_usec(100), timer_expired_delegate(FUNC(saturn_state::smpc_sound_enable),this),(m_smpc_ram[0x77] & 0x10) >> 4); + m_audiocpu->set_input_line(INPUT_LINE_RESET, (data & 0x10) ? ASSERT_LINE : CLEAR_LINE); + m_en_68k = ((data & 0x10) >> 4) ^ 1; + + //if(LOG_SMPC) printf("SMPC: ram [0x77] = %02x\n",data); + m_smpc.PDR2 = (data & 0x60); + } + + if(offset == 0x7d) + { + /* + ---- --x- IOSEL2 direct (1) / control mode (0) port select + ---- ---x IOSEL1 direct (1) / control mode (0) port select + */ + m_smpc.IOSEL1 = (data & 1) >> 0; + m_smpc.IOSEL2 = (data & 2) >> 1; + } + + if(offset == 0x7f) + { + //enable PAD irq & VDP2 external latch for port 1/2 + m_smpc.EXLE1 = (data & 1) >> 0; + m_smpc.EXLE2 = (data & 2) >> 1; + } +} + +/******************************************** + * + * Saturn handlers + * + *******************************************/ + +UINT8 saturn_state::smpc_th_control_mode(UINT8 pad_n) +{ + int th; + const char *const padnames[] = { "JOY1", "JOY2" }; + UINT8 res = 0; + + th = (pad_n == 0) ? ((m_smpc.PDR1>>5) & 3) : ((m_smpc.PDR2>>5) & 3); + + if (LOG_SMPC) printf("SMPC: SH-2 TH control mode, returning pad data %d for phase %d\n",pad_n+1, th); + + switch(th) + { + /* TODO: 3D Lemmings bogusly enables TH Control mode, wants this to return the ID, needs HW tests. */ + case 3: + res = th<<6; + res |= 0x14; + res |= machine().root_device().ioport(padnames[pad_n])->read() & 8; // L + break; + case 2: + res = th<<6; + // 1 C B Right Left Down Up + // WHP actually has a very specific code at 0x6015f30, doesn't like bits 0-1 active here ... + res|= (((machine().root_device().ioport(padnames[pad_n])->read()>>4)) & 0x30); // C & B + res|= (((machine().root_device().ioport(padnames[pad_n])->read()>>12)) & 0xc); + break; + case 1: + res = th<<6; + res |= 0x10; + res |= (machine().root_device().ioport(padnames[pad_n])->read()>>4) & 0xf; // R, X, Y, Z + break; + case 0: + res = th<<6; + // 0 Start A 0 0 Down Up + res|= (((machine().root_device().ioport(padnames[pad_n])->read()>>6)) & 0x30); // Start & A + res|= (((machine().root_device().ioport(padnames[pad_n])->read()>>12)) & 0x3); + // ... and actually wants bits 2 - 3 active here. + res|= 0xc; + break; + } + + return res; +} + +UINT8 saturn_state::smpc_direct_mode(UINT8 pad_n) +{ + int hshake; + const int shift_bit[4] = { 4, 12, 8, 0 }; + const char *const padnames[] = { "JOY1", "JOY2" }; + + hshake = (pad_n == 0) ? ((m_smpc.PDR1>>5) & 3) : ((m_smpc.PDR2>>5) & 3); + + if (LOG_SMPC) logerror("SMPC: SH-2 direct mode, returning data for phase %d\n", hshake); + + return 0x80 | 0x10 | ((machine().root_device().ioport(padnames[pad_n])->read()>>shift_bit[hshake]) & 0xf); +} + +READ8_MEMBER( saturn_state::saturn_SMPC_r ) +{ + UINT8 return_data = 0; + + if (!(offset & 1)) // avoid reading to even bytes (TODO: is it 0s or 1s?) + return 0x00; + + if(offset >= 0x21 && offset <= 0x5f) + return_data = m_smpc.OREG[(offset-0x21) >> 1]; + + if (offset == 0x61) + return_data = m_smpc.SR; + + if (offset == 0x63) + { + //printf("SF %d %d\n",machine().first_screen()->hpos(),machine().first_screen()->vpos()); + return_data = m_smpc.SF; + } + + if (offset == 0x75 || offset == 0x77)//PDR1/2 read + { + if ((m_smpc.IOSEL1 && offset == 0x75) || (m_smpc.IOSEL2 && offset == 0x77)) + { + UINT8 cur_ddr; + + if(machine().root_device().ioport("INPUT_TYPE")->read() && !(space.debugger_access())) + { + popmessage("Warning: read with SH-2 direct mode with a non-pad device"); + return 0; + } + + cur_ddr = (offset == 0x75) ? m_smpc.DDR1 : m_smpc.DDR2; + + switch(cur_ddr & 0x60) + { + case 0x00: break; // in diag test + case 0x40: return_data = smpc_th_control_mode(offset == 0x77); break; + case 0x60: return_data = smpc_direct_mode(offset == 0x77); break; + default: + popmessage("SMPC: unemulated control method %02x, contact MAMEdev",cur_ddr & 0x60); + return_data = 0; + break; + } + } + } + + if (LOG_SMPC) logerror ("cpu %s (PC=%08X) SMPC: Read from Byte Offset %02x (%d) Returns %02x\n", space.device().tag(), space.device().safe_pc(), offset, offset>>1, return_data); + + return return_data; +} + +WRITE8_MEMBER( saturn_state::saturn_SMPC_w ) +{ + if (LOG_SMPC) logerror ("8-bit SMPC Write to Offset %02x (reg %d) with Data %02x\n", offset, offset>>1, data); + + if (!(offset & 1)) // avoid writing to even bytes + return; + + if(offset >= 1 && offset <= 0xd) + m_smpc.IREG[offset >> 1] = data; + + if(offset == 1) //IREG0, check if a BREAK / CONTINUE request for INTBACK command + { + if(m_smpc.intback_stage) + { + if(data & 0x40) + { + if(LOG_PAD_CMD) printf("SMPC: BREAK request %02x\n",data); + m_smpc.SR &= 0x0f; + m_smpc.intback_stage = 0; + } + else if(data & 0x80) + { + if(LOG_PAD_CMD) printf("SMPC: CONTINUE request %02x\n",data); + machine().scheduler().timer_set(attotime::from_usec(700), timer_expired_delegate(FUNC(saturn_state::intback_peripheral),this),0); /* TODO: is timing correct? */ + m_smpc.OREG[31] = 0x10; + m_smpc.SF = 0x01; //TODO: set hand-shake flag? + } + } + } + + if (offset == 0x1f) + { + smpc_comreg_exec(space,data,0); + + // we've processed the command, clear status flag + if(data != 0x10 && data != 2 && data != 3 && data != 6 && data != 7 && data != 0x08 && data != 0x09 && data != 0x0e && data != 0x0f && data != 0x19 && data != 0x1a) + { + m_smpc.OREG[31] = data; //read-back for last command issued + m_smpc.SF = 0x00; //clear hand-shake flag + } + /*TODO:emulate the timing of each command...*/ + } + + if (offset == 0x63) + m_smpc.SF = data & 1; // hand-shake flag + + if(offset == 0x75) // PDR1 + m_smpc.PDR1 = data & 0x7f; + + if(offset == 0x77) // PDR2 + m_smpc.PDR2 = data & 0x7f; + + if(offset == 0x79) + m_smpc.DDR1 = data & 0x7f; + + if(offset == 0x7b) + m_smpc.DDR2 = data & 0x7f; + + if(offset == 0x7d) + { + m_smpc.IOSEL1 = data & 1; + m_smpc.IOSEL2 = (data & 2) >> 1; + } + + if(offset == 0x7f) + { + //enable PAD irq & VDP2 external latch for port 1/2 + m_smpc.EXLE1 = (data & 1) >> 0; + m_smpc.EXLE2 = (data & 2) >> 1; + } +} diff --git a/src/devices/machine/smpc.h b/src/devices/machine/smpc.h new file mode 100644 index 00000000000..7bb17fe337d --- /dev/null +++ b/src/devices/machine/smpc.h @@ -0,0 +1,7 @@ +// license:LGPL-2.1+ +// copyright-holders:Angelo Salese, R. Belmont +// TODO: make separate device when code is decoupled better +//DECLARE_WRITE8_MEMBER( stv_SMPC_w ); +//DECLARE_READ8_MEMBER( stv_SMPC_r ); +//DECLARE_WRITE8_MEMBER( saturn_SMPC_w ); +//DECLARE_READ8_MEMBER( saturn_SMPC_r ); diff --git a/src/devices/machine/spchrom.c b/src/devices/machine/spchrom.c new file mode 100644 index 00000000000..a49590e9e00 --- /dev/null +++ b/src/devices/machine/spchrom.c @@ -0,0 +1,139 @@ +// license:BSD-3-Clause +// copyright-holders:Frank Palazzolo, Aaron Giles, Jonathan Gevaryahu, Raphael Nabet, Couriersud, Michael Zapf +/* + spchroms.c - This is an emulator for "typical" speech ROMs from TI, as used by TI99/4(a). + + In order to support its speech processor, TI designed some ROMs with a 1-bit data bus + and 4-bit address bus (multiplexed 5 times to provide a 18-bit address). + A fairly complete description of such a ROM (tms6100) is found in the tms5220 datasheet. + + One notable thing is that the address is a byte address (*NOT* a bit address). + + This file is designed to be interfaced with the tms5220 core. + Interfacing it with the tms5110 would make sense, too. + + TODO: + Create separate devices for TMS6100 & TMS6125 + Implement the serial protocol +*/ + +#include "emu.h" +#include "spchrom.h" + +#define TMS5220_ADDRESS_MASK 0x3FFFFUL /* 18-bit mask for tms5220 address */ + +// device type definition +const device_type SPEECHROM = &device_creator; + +speechrom_device::speechrom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, SPEECHROM, "SPEECHROM", tag, owner, clock, "speechrom", __FILE__), + m_speechROMaddr(0), + m_load_pointer(0), + m_ROM_bits_count(0), + m_reverse(false) +{ +} + +/* + Read 'count' bits serially from speech ROM + + Actually, the ROM is expected to have reversed bit order, but there are + many dumps with normal bit order. + + compatibility mode: 01234567 01234567 01234567 ... + correct mode: 76543210 76543210 76543210 ... +*/ +int speechrom_device::read(int count) +{ + int val; + int spchbyte; + int pos; + + if (m_load_pointer) + { /* first read after load address is ignored */ + m_load_pointer = 0; + count--; + } + + if (m_speechROMaddr < m_speechROMlen) + { + val = 0; + pos = 8 - m_ROM_bits_count; + + spchbyte = (m_reverse? (m_speechrom_data[m_speechROMaddr] >> pos) : (m_speechrom_data[m_speechROMaddr] << pos)) & 0xff; + + while (count > 0) + { + val = val << 1; + if ((spchbyte & (m_reverse? 0x01:0x80))!=0) val |= 1; + spchbyte = m_reverse? (spchbyte >> 1) : (spchbyte << 1); + count--; + if (pos == 7) + { + pos = 0; + m_speechROMaddr = (m_speechROMaddr + 1) & TMS5220_ADDRESS_MASK; + if (m_speechROMaddr >= m_speechROMlen) + count = 0; + else + spchbyte = m_speechrom_data[m_speechROMaddr]; + } + else pos++; + } + m_ROM_bits_count = 8 - pos; + } + else + { + val = 0; + } + + return val; +} + +/* + Write an address nibble to speech ROM +*/ +void speechrom_device::load_address(int data) +{ + /* tms5220 data sheet says that if we load only one 4-bit nibble, it won't work. + This code does not care about this. */ + m_speechROMaddr = ( (m_speechROMaddr & ~(0xf << m_load_pointer)) + | (((unsigned long) (data & 0xf)) << m_load_pointer) ) & TMS5220_ADDRESS_MASK; + m_load_pointer += 4; + m_ROM_bits_count = 8; +} + +/* + Perform a read and branch command +*/ +void speechrom_device::read_and_branch() +{ + /* tms5220 data sheet says that if more than one speech ROM (tms6100) is present, + there is a bus contention. This code does not care about this. */ + if (m_speechROMaddr < m_speechROMlen-1) + m_speechROMaddr = (m_speechROMaddr & 0x3c000UL) + | (((((unsigned long) m_speechrom_data[m_speechROMaddr]) << 8) + | m_speechrom_data[m_speechROMaddr+1]) & 0x3fffUL); + else if (m_speechROMaddr == m_speechROMlen-1) + m_speechROMaddr = (m_speechROMaddr & 0x3c000UL) + | ((((unsigned long) m_speechrom_data[m_speechROMaddr]) << 8) & 0x3fffUL); + else + m_speechROMaddr = (m_speechROMaddr & 0x3c000UL); + + m_ROM_bits_count = 8; +} + +void speechrom_device::device_start() +{ + memory_region *region = memregion(tag()); + if (region == NULL) + { + throw emu_fatalerror("No region for device '%s'\n", tag()); + } + + m_speechrom_data = region->base(); + m_speechROMlen = region->bytes(); + + save_item(NAME(m_speechROMaddr)); + save_item(NAME(m_load_pointer)); + save_item(NAME(m_ROM_bits_count)); +} diff --git a/src/devices/machine/spchrom.h b/src/devices/machine/spchrom.h new file mode 100644 index 00000000000..520c7fc967b --- /dev/null +++ b/src/devices/machine/spchrom.h @@ -0,0 +1,41 @@ +// license:BSD-3-Clause +// copyright-holders:Frank Palazzolo, Aaron Giles, Jonathan Gevaryahu, Raphael Nabet, Couriersud, Michael Zapf +/* + * Voice Synthesis Memory + * + */ + +#ifndef __SPCHROMS_H +#define __SPCHROMS_H + +#include "emu.h" + +class speechrom_device : public device_t +{ +public: + // construction/destruction + speechrom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + /// TODO: implement bus behaviour + int read(int count); + void load_address(int data); + void read_and_branch(); + void set_reverse_bit_order(bool reverse) { m_reverse = reverse; } + + // device-level overrides + virtual void device_start(); + +private: + UINT8 *m_speechrom_data; /* pointer to speech ROM data */ + unsigned int m_speechROMlen; /* length of data pointed by speechrom_data, from 0 to 2^18 */ + unsigned int m_speechROMaddr; /* 18 bit pointer in ROM */ + int m_load_pointer; /* which 4-bit nibble will be affected by load address */ + int m_ROM_bits_count; /* current bit position in ROM */ + bool m_reverse; +}; + + +// device type definition +extern const device_type SPEECHROM; + +#endif diff --git a/src/devices/machine/steppers.c b/src/devices/machine/steppers.c new file mode 100644 index 00000000000..e1eea4d648e --- /dev/null +++ b/src/devices/machine/steppers.c @@ -0,0 +1,450 @@ +// license:BSD-3-Clause +// copyright-holders:James Wallace +/////////////////////////////////////////////////////////////////////////// +// // +// steppers.c steppermotor emulation // +// // +// Emulates : Stepper motors driven with full step or half step // +// also emulates the index optic // +// // +// 26-05-2012: J. Wallace - Implemented proper phase alignment, we no // +// longer need reverse interfaces here, the // +// layout will suffice. Added belt reel handler.// +// 09-04-2012: J. Wallace - Studied some old reel motors and added a // +// number of new stepper types. I am yet to // +// add them to drivers, but barring some init // +// stuff, they should work. // +// 15-01-2012: J. Wallace - Total internal rewrite to remove the table // +// hoodoo that stops anyone but me actually // +// updating this. In theory, we should be able // +// to adapt the phase code to any reel type by // +// studying a game's startup // +// Documentation is much better now. // +// 04-04-2011: J. Wallace - Added reverse spin (this is necessary for // +// accuracy), and improved wraparound logic // +// 03-2011: New 2D array to remove reel bounce and // +// make more realistic // +// 26-01-2007: J. Wallace - Rewritten to make it more flexible // +// and to allow indices to be set in drivers // +// 29-12-2006: J. Wallace - Added state save support // +// 05-03-2004: Re-Animator // +// // +// TODO: add further types of stepper motors if needed (Konami/IGT?) // +// 200 Step reels can alter their relative opto tab position, // +// may be worth adding the phase setting to the interface // +// There are reports that some games use a pulse that is too short// +// to give a 'judder' effect for holds, etc. We'll need to time // +// the pulses to keep tack of this without going out of sync. // +// Check 20RM and Starpoint 200 step // +/////////////////////////////////////////////////////////////////////////// + +#include "emu.h" +#include "steppers.h" + +const device_type STEPPER = &device_creator; + +stepper_device::stepper_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, STEPPER, "Stepper Motor", tag, owner, clock, "stepper", __FILE__), + m_optic_cb(*this) + { + m_max_steps=(48*2); + } +/////////////////////////////////////////////////////////////////////////// + +void stepper_device::update_optic() +{ + int pos = m_step_pos, + start = m_index_start, + end = m_index_end; + + if (start > end) // cope with index patterns that wrap around + { + if ( (( pos > start ) || ( pos < end )) && + ( ( m_pattern == m_index_patt || m_index_patt==0) || + ( m_pattern == 0 && + (m_old_pattern == m_index_patt || m_index_patt==0) + ) ) ) + { + m_optic = 1; + } + else m_optic = 0; + } + else + { + if ( (( pos > start ) && ( pos < end )) && + ( ( m_pattern == m_index_patt || m_index_patt==0) || + ( m_pattern == 0 && + (m_old_pattern == m_index_patt || m_index_patt==0) + ) ) ) + { + m_optic = 1; + } + else m_optic = 0; + } + + m_optic_cb(m_optic); +} +/////////////////////////////////////////////////////////////////////////// + +void stepper_device::device_start() +{ + /* resolve callbacks */ + m_optic_cb.resolve_safe(); + + /* register for state saving */ + save_item(NAME(m_index_start)); + save_item(NAME(m_index_end)); + save_item(NAME(m_index_patt)); + save_item(NAME(m_initphase)); + save_item(NAME(m_phase)); + save_item(NAME(m_old_phase)); + save_item(NAME(m_pattern)); + save_item(NAME(m_old_pattern)); + save_item(NAME(m_step_pos)); + save_item(NAME(m_abs_step_pos)); + save_item(NAME(m_max_steps)); + save_item(NAME(m_type)); +} + +/////////////////////////////////////////////////////////////////////////// + +void stepper_device::device_reset() +{ + m_step_pos = 0x00; + m_abs_step_pos = 0x00; + m_pattern = 0x00; + m_old_pattern = 0x00; + m_phase = m_initphase; + m_old_phase = m_initphase; + update_optic(); +} + +/////////////////////////////////////////////////////////////////////////// + +int stepper_device::update(UINT8 pattern) +{ + int changed = 0; + + /* This code probably makes more sense if you visualise what is being emulated, namely + a spinning drum with two electromagnets inside. Essentially, the CPU + activates a pair of windings on these magnets leads as necessary to attract and repel the drum to pull it round and + display as appropriate. To attempt to visualise the rotation effect, take a look at the compass rose below, representing a side on view of the reel, + the numbers indicate the phase information as used + + 7 + N + 1 W E 5 + S + 3 + + For sake of accuracy, we're representing all possible phases of the motor, effectively moving the motor one half step at a time, so a 48 step motor becomes + 96 half steps. This is necessary because of some programs running the wiring in series with a distinct delay between the pair being completed. This causes + a small movement that may trigger the optic tab. + */ + + int pos,steps=0; + m_pattern = pattern; + switch ( m_type ) + { + default: + logerror("No reel type specified!\n"); + break; + case NOT_A_REEL : + case STARPOINT_48STEP_REEL : /* STARPOINT RMxxx */ + case GAMESMAN_200STEP_REEL : /* Gamesman GMxxxx */ + case STARPOINT_144STEP_DICE :/* STARPOINT 1DCU DICE mechanism */ + case STARPOINT_200STEP_REEL :/* STARPOINT 1DCU DICE mechanism */ + //Standard drive table is 2,6,4,5,1,9,8,a + //NOTE: This runs through the stator patterns in such a way as to drive the reel forward (downwards from the player's view, clockwise on our rose) + //The Heber 'Pluto' controller runs this in reverse + switch (pattern) + { //Black Blue Red Yellow + case 0x02:// 0 0 1 0 + m_phase = 7; + break; + case 0x06:// 0 1 1 0 + m_phase = 6; + break; + case 0x04:// 0 1 0 0 + m_phase = 5; + break; + case 0x05:// 0 1 0 1 + m_phase = 4; + break; + case 0x01:// 0 0 0 1 + m_phase = 3; + break; + case 0x09:// 1 0 0 1 + m_phase = 2; + break; + case 0x08:// 1 0 0 0 + m_phase = 1; + break; + case 0x0A:// 1 0 1 0 + m_phase = 0; + break; + // Black Blue Red Yellow + case 0x03:// 0 0 1 1 + { + if ((m_old_phase ==6)||(m_old_phase == 0)) // if the previous pattern had the drum in the northern quadrant, it will point north now + { + m_phase = 7; + } + else //otherwise it will line up due south + { + m_phase = 3; + } + } + break; + case 0x0C:// 1 1 0 0 + { + if ((m_old_phase ==6)||(m_old_phase == 4)) // if the previous pattern had the drum in the eastern quadrant, it will point east now + { + m_phase = 5; + } + else //otherwise it will line up due west + { + m_phase = 1; + } + } + break; + } + break; + + case BARCREST_48STEP_REEL : + case GAMESMAN_48STEP_REEL : + case GAMESMAN_100STEP_REEL : + //Standard drive table is 1,3,2,6,4,C,8,9 + //Gamesman 48 step uses this pattern shifted one place forward, though this shouldn't matter + switch (pattern) + { + // Yellow Brown Orange Black + case 0x01:// 0 0 0 1 + m_phase = 7; + break; + case 0x03:// 0 0 1 1 + m_phase = 6; + break; + case 0x02:// 0 0 1 0 + m_phase = 5; + break; + case 0x06:// 0 1 1 0 + m_phase = 4; + break; + case 0x04:// 0 1 0 0 + m_phase = 3; + break; + case 0x0C:// 1 1 0 0 + m_phase = 2; + break; + case 0x08:// 1 0 0 0 + m_phase = 1; + break;//YOLB + case 0x09:// 1 0 0 1 + m_phase = 0; + break; + + // The below values should not be used by anything sane, as they effectively ignore one stator side entirely + // Yellow Brown Orange Black + case 0x05:// 0 1 0 1 + { + if ((m_old_phase ==6)||(m_old_phase == 0)) // if the previous pattern had the drum in the northern quadrant, it will point north now + { + m_phase = 7; + } + else //otherwise it will line up due south + { + m_phase = 3; + } + } + break; + + case 0x0A:// 1 0 1 0 + { + if ((m_old_phase ==6)||(m_old_phase == 4)) // if the previous pattern had the drum in the eastern quadrant, it will point east now + { + m_phase = 5; + } + else //otherwise it will line up due west + { + m_phase = 1; + } + } + break; + } + break; + + case MPU3_48STEP_REEL : + /* The MPU3 interface is actually the same as the MPU4 setup, but with two active lines instead of four + Inverters are used so if a pin is low, the higher bit of the pair is activated, and if high the lower bit is activated. + TODO:Check this, 2 and 1 could be switched over. + */ + switch (pattern) + { + // Yellow(2) Brown(1) Orange(!2) Black(!1) + case 0x00 :// 0 0 1 1 + m_phase = 6; + break; + case 0x01 :// 0 1 1 0 + m_phase = 4; + break; + case 0x03 :// 1 1 0 0 + m_phase = 2; + break; + case 0x02 :// 1 0 0 1 + m_phase = 0; + break; + } + break; + + case ECOIN_200STEP_REEL : + //While the 48 and 100 step models appear to be reverse driven Starpoint reels, the 200 step model seems bespoke, certainly in terms of wiring. + //On a Proconn machine this same pattern is seen but running in reverse + //Standard drive table is 8,c,4,6,2,3,1,9 + switch (pattern) + { + case 0x08:// 0 0 1 0 + m_phase = 7; + break; + case 0x0c:// 0 1 1 0 + m_phase = 6; + break; + case 0x04:// 0 1 0 0 + m_phase = 5; + break; + case 0x06:// 0 1 0 1 + m_phase = 4; + break; + case 0x02:// 0 0 0 1 + m_phase = 3; + break; + case 0x03:// 1 0 0 1 + m_phase = 2; + break; + case 0x01:// 1 0 0 0 + m_phase = 1; + break; + case 0x09:// 1 0 1 0 + m_phase = 0; + break; + case 0x0a:// 0 0 1 1 + { + if ((m_old_phase ==6)||(m_old_phase == 0)) // if the previous pattern had the drum in the northern quadrant, it will point north now + { + m_phase = 7; + } + else //otherwise it will line up due south + { + m_phase = 3; + } + } + break; + case 0x07:// 1 1 0 0 + { + if ((m_old_phase ==6)||(m_old_phase == 4)) // if the previous pattern had the drum in the eastern quadrant, it will point east now + { + m_phase = 5; + } + else //otherwise it will line up due west + { + m_phase = 1; + } + } + break; + } + break; + + case PROJECT_48STEP_REEL : + //Standard drive table is 8,c,4,5,1,3,2,a + //This appears to be basically a rewired Gamesman (the reel PCB looks like it does some shuffling) + //TODO: Not sure if this should be represented as a type here, or by defining it as a Gamesman in the driver and bitswapping. + switch (pattern) + { + case 0x08:// 0 0 1 0 + m_phase = 7; + break; + case 0x0c:// 0 1 1 0 + m_phase = 6; + break; + case 0x04:// 0 1 0 0 + m_phase = 5; + break; + case 0x05:// 0 1 0 1 + m_phase = 4; + break; + case 0x01:// 0 0 0 1 + m_phase = 3; + break; + case 0x03:// 1 0 0 1 + m_phase = 2; + break; + case 0x02:// 1 0 0 0 + m_phase = 1; + break; + case 0x0a:// 1 0 1 0 + m_phase = 0; + break; + case 0x09:// 0 0 1 1 + { + if ((m_old_phase ==6)||(m_old_phase == 0)) // if the previous pattern had the drum in the northern quadrant, it will point north now + { + m_phase = 7; + } + else //otherwise it will line up due south + { + m_phase = 3; + } + } + break; + case 0x06:// 1 1 0 0 + { + if ((m_old_phase ==6)||(m_old_phase == 4)) // if the previous pattern had the drum in the eastern quadrant, it will point east now + { + m_phase = 5; + } + else //otherwise it will line up due west + { + m_phase = 1; + } + } + break; + } + break; + + + + } + + steps = m_old_phase - m_phase; + + if (steps < -4) + { + steps = steps +8; + } + if (steps > 4) + { + steps = steps -8; + } + + m_old_phase = m_phase; + m_old_pattern = m_pattern; + + int max = m_max_steps; + pos = 0; + + if (max!=0) + { + m_abs_step_pos += steps; + pos = (m_step_pos + steps + max) % max; + } + + if (pos != m_step_pos) + { + changed++; + } + + m_step_pos = pos; + update_optic(); + + return changed; +} diff --git a/src/devices/machine/steppers.h b/src/devices/machine/steppers.h new file mode 100644 index 00000000000..1ed62da6885 --- /dev/null +++ b/src/devices/machine/steppers.h @@ -0,0 +1,179 @@ +// license:BSD-3-Clause +// copyright-holders:James Wallace +/////////////////////////////////////////////////////////////////////////// +// // +// steppers.c steppermotor emulation // +// // +// Emulates : stepper motors driven with full step or half step // +// also emulates the index optic // +// // +// // +// TODO: add further types of stepper motors if needed (Konami/IGT?) // +/////////////////////////////////////////////////////////////////////////// + + +#ifndef INC_STEPPERS +#define INC_STEPPERS + +#define NOT_A_REEL 0 +#define STARPOINT_48STEP_REEL 1 /* STARPOINT RMXXX reel unit */ +#define STARPOINT_144STEP_DICE 2 /* STARPOINT 1DCU DICE mechanism */ +#define STARPOINT_200STEP_REEL 3 + +#define BARCREST_48STEP_REEL 4 /* Barcrest bespoke reel unit */ +#define MPU3_48STEP_REEL 5 + +#define ECOIN_200STEP_REEL 6 /* Probably not bespoke, but can't find a part number */ + +#define GAMESMAN_48STEP_REEL 7 +#define GAMESMAN_100STEP_REEL 8 +#define GAMESMAN_200STEP_REEL 9 + +#define PROJECT_48STEP_REEL 10 + +#define MCFG_STEPPER_ADD(_tag)\ + MCFG_DEVICE_ADD(_tag, STEPPER, 0) + +#define MCFG_STEPPER_REEL_TYPE(_data) \ + stepper_device::set_reel_type(*device, _data); + +/* total size of reel (in half steps) */ +#define MCFG_STEPPER_MAX_STEPS(_write) \ + stepper_device::set_max_steps(*device, _write); + +/* start position of index (in half steps) */ +#define MCFG_STEPPER_START_INDEX(_write) \ + stepper_device::set_start_index(*device, _write); + +/* end position of index (in half steps) */ +#define MCFG_STEPPER_END_INDEX(_write) \ + stepper_device::set_end_index(*device, _write); + +/* end position of index (in half steps) */ +#define MCFG_STEPPER_INDEX_PATTERN(_write) \ + stepper_device::set_index_pattern(*device, _write); + +/* Phase at 0, for opto linkage */ +#define MCFG_STEPPER_INIT_PHASE(_write) \ + stepper_device::set_init_phase(*device, _write); + +#define MCFG_STARPOINT_48STEP_ADD(_tag)\ + MCFG_STEPPER_ADD(_tag)\ + MCFG_STEPPER_REEL_TYPE(STARPOINT_48STEP_REEL)\ + MCFG_STEPPER_START_INDEX(1)\ + MCFG_STEPPER_END_INDEX(3)\ + MCFG_STEPPER_INDEX_PATTERN(0x09)\ + MCFG_STEPPER_INIT_PHASE(4) + +#define MCFG_STARPOINT_RM20_48STEP_ADD(_tag)\ + MCFG_DEVICE_ADD(_tag, STEPPER, 0)\ + MCFG_STEPPER_REEL_TYPE(STARPOINT_48STEP_REEL)\ + MCFG_STEPPER_START_INDEX(16)\ + MCFG_STEPPER_END_INDEX(24)\ + MCFG_STEPPER_INDEX_PATTERN(0x09)\ + MCFG_STEPPER_INIT_PHASE(7) + +#define MCFG_STARPOINT_200STEP_ADD(_tag)\ + MCFG_DEVICE_ADD(_tag, STEPPER, 0)\ + MCFG_STEPPER_REEL_TYPE(STARPOINT_200STEP_REEL)\ + MCFG_STEPPER_MAX_STEPS(200*2)\ + MCFG_STEPPER_START_INDEX(12)\ + MCFG_STEPPER_END_INDEX(24)\ + MCFG_STEPPER_INDEX_PATTERN(0x09)\ + MCFG_STEPPER_INIT_PHASE(7) + +//guess +#define MCFG_ECOIN_200STEP_ADD(_tag)\ + MCFG_DEVICE_ADD(_tag, STEPPER, 0)\ + MCFG_STEPPER_REEL_TYPE(ECOIN_200STEP_REEL)\ + MCFG_STEPPER_MAX_STEPS(200*2)\ + MCFG_STEPPER_START_INDEX(12)\ + MCFG_STEPPER_END_INDEX(24)\ + MCFG_STEPPER_INDEX_PATTERN(0x09)\ + MCFG_STEPPER_INIT_PHASE(7) + +#define MCFG_STEPPER_OPTIC_CALLBACK(_write) \ + devcb = &stepper_device::set_optic_handler(*device, DEVCB_##_write); + +class stepper_device; +extern const device_type STEPPER; + +class stepper_device : public device_t +{ +public: + stepper_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + template static devcb_base &set_optic_handler(device_t &device, _Object object) { return downcast(device).m_optic_cb.set_callback(object); } + + static void set_reel_type(device_t &device, UINT8 type) + { + downcast(device).m_type = type; + switch ( type ) + { default: + case STARPOINT_48STEP_REEL: /* STARPOINT RMxxx */ + case BARCREST_48STEP_REEL : /* Barcrest Reel unit */ + case MPU3_48STEP_REEL : + case GAMESMAN_48STEP_REEL : /* Gamesman GMxxxx */ + case PROJECT_48STEP_REEL : + downcast(device).m_max_steps = (48*2); + break; + case GAMESMAN_100STEP_REEL : + downcast(device).m_max_steps = (100*2); + break; + case STARPOINT_144STEP_DICE :/* STARPOINT 1DCU DICE mechanism */ + //Dice reels are 48 step motors, but complete three full cycles between opto updates + downcast(device).m_max_steps = ((48*3)*2); + break; + case STARPOINT_200STEP_REEL : + case GAMESMAN_200STEP_REEL : + case ECOIN_200STEP_REEL : + downcast(device).m_max_steps = (200*2); + break; + } + } + static void set_max_steps(device_t &device, INT16 steps) { downcast(device).m_max_steps = steps; } + static void set_start_index(device_t &device, INT16 index) { downcast(device).m_index_start = index; } + static void set_end_index(device_t &device, INT16 index) { downcast(device).m_index_end = index; } + static void set_index_pattern(device_t &device, INT16 index) { downcast(device).m_index_patt = index; } + static void set_init_phase(device_t &device, UINT8 phase) + { + downcast(device).m_initphase = phase; + downcast(device).m_phase = phase; + downcast(device).m_old_phase = phase; + } + + /* update a motor */ + int update(UINT8 pattern); + + /* get current position in half steps */ + int get_position() { return m_step_pos; } + /* get current absolute position in half steps */ + int get_absolute_position() { return m_abs_step_pos; } + /* get maximum position in half steps */ + int get_max() { return m_max_steps; } + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + +private: + UINT8 m_pattern; /* coil pattern */ + UINT8 m_old_pattern; /* old coil pattern */ + UINT8 m_initphase; + UINT8 m_phase; /* motor phase */ + UINT8 m_old_phase; /* old phase */ + UINT8 m_type; /* reel type */ + INT16 m_step_pos; /* step position 0 - max_steps */ + INT16 m_max_steps; /* maximum step position */ + INT32 m_abs_step_pos; /* absolute step position */ + INT16 m_index_start; /* start position of index (in half steps) */ + INT16 m_index_end; /* end position of index (in half steps) */ + INT16 m_index_patt; /* pattern needed on coils (0=don't care) */ + UINT8 m_optic; + + void update_optic(); + devcb_write_line m_optic_cb; +}; + +#endif diff --git a/src/devices/machine/strata.c b/src/devices/machine/strata.c new file mode 100644 index 00000000000..01651eb90bd --- /dev/null +++ b/src/devices/machine/strata.c @@ -0,0 +1,675 @@ +// license:BSD-3-Clause +// copyright-holders:Raphael Nabet, Michael Zapf +/* + Intel 28F640J5 Flash ROM emulation (could also handle 28F320J5 with minor + changes, and possibly 28F256J3, 28F128J3, 28F640J3 and 28F320J3) + + The 28F640J5 is a 64Mbit FEEPROM that can be accessed either on an 8-bit or + a 16-bit bus. + + References: + Datasheets were found on Intel's site (www.intel.com) + + Raphael Nabet 2004, based on MAME's intelfsh.c core + + Device is currently only used in ti99/tn_usbsm + + Rewritten as class + Michael Zapf, 2014 + + TODO: Make it work +*/ + +#include "emu.h" +#include "strata.h" + +#define MAX_STRATA 1 + +#define FEEPROM_SIZE 0x800000 // 64Mbit +#define BLOCK_SIZE 0x020000 + +#define BLOCKLOCK_SIZE ((FEEPROM_SIZE/BLOCK_SIZE+7)/8) +#define WRBUF_SIZE 32 +#define PROT_REGS_SIZE 18 + +#define COMPLETE_SIZE FEEPROM_SIZE + WRBUF_SIZE + PROT_REGS_SIZE + BLOCKLOCK_SIZE + +#define ADDRESS_MASK 0x7fffff +#define BLOCK_ADDRESS_MASK 0x7e0000 +#define BLOCK_ADDRESS_SHIFT 17 +#define BYTE_ADDRESS_MASK 0x01ffff + +/* accessors for individual block lock flags */ +#define READ_BLOCKLOCK(block) ((m_blocklock[(block) >> 3] >> ((block) & 7)) & 1) +#define SET_BLOCKLOCK(block) (m_blocklock[(block) >> 3] |= 1 << ((block) & 7)) +#define CLEAR_BLOCKLOCK(block) (m_blocklock[(block) >> 3] &= ~(1 << ((block) & 7))) + +const device_type STRATAFLASH = &device_creator; + +strataflash_device::strataflash_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, STRATAFLASH, "Intel 28F640J5", tag, owner, clock, "strataflash", __FILE__), + device_nvram_interface(mconfig, *this) +{ +} + +//------------------------------------------------- +// nvram_default - called to initialize NVRAM to +// its default state +//------------------------------------------------- + +void strataflash_device::nvram_default() +{ + memset(m_flashmemory, 0, COMPLETE_SIZE); +} + +//------------------------------------------------- +// nvram_read - called to read NVRAM from the +// .nv file +//------------------------------------------------- + +void strataflash_device::nvram_read(emu_file &file) +{ + file.read(m_flashmemory, COMPLETE_SIZE); + + // TODO + + /* + UINT8 buf; + int i; + + // version flag + if (file->read(& buf, 1) != 1) + return 1; + if (buf != 0) + return 1; + + // chip state: master lock + if (file->read(& buf, 1) != 1) + return 1; + m_master_lock = buf & 1; + + // main FEEPROM area + if (file->read(m_flashmemory, FEEPROM_SIZE) != FEEPROM_SIZE) + return 1; + for (i = 0; i < FEEPROM_SIZE; i += 2) + { + UINT16 *ptr = (UINT16 *) (&m_flashmemory[i]); + *ptr = LITTLE_ENDIANIZE_INT16(*ptr); + } + + // protection registers + if (file->read(m_prot_regs, PROT_REGS_SIZE) != PROT_REGS_SIZE) + return 1; + for (i = 0; i < PROT_REGS_SIZE; i += 2) + { + UINT16 *ptr = (UINT16 *) (&m_prot_regs[i]); + *ptr = LITTLE_ENDIANIZE_INT16(*ptr); + } + + // block lock flags + if (file->read(m_blocklock, BLOCKLOCK_SIZE) != BLOCKLOCK_SIZE) + return 1; + + return 0; + */ +} + +//------------------------------------------------- +// nvram_write - called to write NVRAM to the +// .nv file +//------------------------------------------------- + +void strataflash_device::nvram_write(emu_file &file) +{ + // TODO + + /* + UINT8 buf; + int i; + + // version flag + buf = 0; + if (file->write(& buf, 1) != 1) + return 1; + + // chip state: lower boot block lockout, higher boot block lockout, + software data protect + buf = m_master_lock; + if (file->write(& buf, 1) != 1) + return 1; + + // main FEEPROM area + for (i = 0; i < FEEPROM_SIZE; i += 2) + { + UINT16 *ptr = (UINT16 *) (&m_flashmemory[i]); + *ptr = LITTLE_ENDIANIZE_INT16(*ptr); + } + if (file->write(m_flashmemory, FEEPROM_SIZE) != FEEPROM_SIZE) + return 1; + for (i = 0; i < FEEPROM_SIZE; i += 2) + { + UINT16 *ptr = (UINT16 *) (&m_flashmemory[i]); + *ptr = LITTLE_ENDIANIZE_INT16(*ptr); + } + + // protection registers + for (i = 0; i < PROT_REGS_SIZE; i += 2) + { + UINT16 *ptr = (UINT16 *) (&m_prot_regs[i]); + *ptr = LITTLE_ENDIANIZE_INT16(*ptr); + } + if (file->write(m_prot_regs, PROT_REGS_SIZE) != PROT_REGS_SIZE) + return 1; + for (i = 0; i < PROT_REGS_SIZE; i += 2) + { + UINT16 *ptr = (UINT16 *) (&m_prot_regs[i]); + *ptr = LITTLE_ENDIANIZE_INT16(*ptr); + } + + // block lock flags + if (file->write(m_blocklock, BLOCKLOCK_SIZE) != BLOCKLOCK_SIZE) + return 1; + + return 0; + */ + + file.write(m_flashmemory, COMPLETE_SIZE); +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- +void strataflash_device::device_start(void) +{ + m_mode = FM_NORMAL; + m_status = 0x80; + m_master_lock = 0; + m_flashmemory = auto_alloc_array(machine(), UINT8, COMPLETE_SIZE); + + m_wrbuf = m_flashmemory + FEEPROM_SIZE; + m_prot_regs = m_wrbuf + WRBUF_SIZE; + m_blocklock = m_prot_regs + PROT_REGS_SIZE; + + // clear various FEEPROM areas + memset(m_prot_regs, 0xff, 18); + memset(m_flashmemory, 0xff, FEEPROM_SIZE); + memset(m_blocklock, 0x00, BLOCKLOCK_SIZE); + + // set-up factory-programmed protection register segment + m_prot_regs[BYTE_XOR_LE(0)] &= 0xfe; + for (int i=2; i<10; i++) + m_prot_regs[i] = machine().rand(); +} + +//------------------------------------------------- +// device_config_complete - perform any +// operations now that the configuration is +// complete +//------------------------------------------------- + +void strataflash_device::device_config_complete() +{ +} + +/* + read a 8/16-bit word from FEEPROM +*/ +UINT16 strataflash_device::read8_16(address_space& space, offs_t offset, bus_width_t bus_width) +{ + switch (bus_width) + { + case bw_8: + offset &= ADDRESS_MASK; + break; + case bw_16: + offset &= ADDRESS_MASK & ~1; + } + + switch (m_mode) + { + default: + case FM_NORMAL: + switch (bus_width) + { + case bw_8: + return m_flashmemory[BYTE_XOR_LE(offset)]; + case bw_16: + return *(UINT16*)(m_flashmemory+offset); + } + break; + case FM_READSTATUS: + return m_status; + case FM_WRBUFPART1: + return 0x80; + case FM_READID: + if ((offset >= 0x100) && (offset < 0x112)) + { /* protection registers */ + switch (bus_width) + { + case bw_8: + return m_prot_regs[BYTE_XOR_LE(offset)]; + case bw_16: + return *(UINT16*)(m_prot_regs+offset); + } + } + else + switch (offset >> 1) + { + case 0: // maker ID + return 0x89; // Intel + case 1: // chip ID + return 0x15; // 64 Mbit + default: + if (((offset & BYTE_ADDRESS_MASK) >> 1) == 2) + { // block lock config + return READ_BLOCKLOCK(offset >> BLOCK_ADDRESS_SHIFT); + } + return 0; // default case + case 3: // master lock config + if (m_master_lock) + return 1; + else + return 0; + } + break; + case FM_READQUERY: + switch (offset >> 1) + { + case 0x00: // maker ID + return 0x89; // Intel + case 0x01: // chip ID + return 0x15; // 64 Mbit + default: + if (((offset & BYTE_ADDRESS_MASK) >> 1) == 2) + { // block lock config + return READ_BLOCKLOCK(offset >> BLOCK_ADDRESS_SHIFT); + } + return 0; // default case +#if 0 + case 0x03: // master lock config + if (m_flash_master_lock) + return 1; + else + return 0; +#endif + + /* CFI query identification string */ + case 0x10: + return 'Q'; + case 0x11: + return 'R'; + case 0x12: + return 'Y'; + case 0x13: + return 0x01; + case 0x14: + return 0x00; + case 0x15: + return 0x31; + case 0x16: + return 0x00; + case 0x17: + case 0x18: + case 0x19: + case 0x1a: + return 0x00; + + /* system interface information: voltage */ + case 0x1b: + return 0x45; + case 0x1c: + return 0x55; + case 0x1d: + return 0x00; + case 0x1e: + return 0x00; + + /* system interface information: timings */ + case 0x1f: + return /*0x07*/0x00; + case 0x20: + return /*0x07*/0x00; + case 0x21: + return /*0x0a*/0x00; + case 0x22: + return 0x00; + case 0x23: + return /*0x04*/0x00; + case 0x24: + return /*0x04*/0x00; + case 0x25: + return /*0x04*/0x00; + case 0x26: + return 0x00; + + /* device geometry definition */ + case 0x27: + return 0x17; + case 0x28: + return 0x02; + case 0x29: + return 0x00; + case 0x2a: + return 0x05; + case 0x2b: + return 0x00; + case 0x2c: + return 0x01; + case 0x2d: + return 0x3f; + case 0x2e: + return 0x00; + case 0x2f: + return 0x00; + case 0x30: + return 0x02; + + /* primary vendor-specific extended query */ + case 0x31: + return 'P'; + case 0x32: + return 'R'; + case 0x33: + return 'I'; + case 0x34: + return '1'; + case 0x35: + return '1'; + case 0x36: + return 0x0a; + case 0x37: + return 0x00; + case 0x38: + return 0x00; + case 0x39: + return 0x00; + case 0x3a: + return 0x01; + case 0x3b: + return 0x01; + case 0x3c: + return 0x00; + case 0x3d: + return 0x50; + case 0x3e: + return 0x00; + case 0x3f: + return 0x00; + } + } + + return 0; +} + +/* + write a 8/16-bit word to FEEPROM +*/ +void strataflash_device::write8_16(address_space& space, offs_t offset, UINT16 data, bus_width_t bus_width) +{ + switch (bus_width) + { + case bw_8: + offset &= ADDRESS_MASK; + break; + case bw_16: + offset &= ADDRESS_MASK & ~1; + break; + } + + switch (m_mode) + { + case FM_NORMAL: + case FM_READID: + case FM_READQUERY: + case FM_READSTATUS: + switch (data) + { + case 0xff: // read array + m_mode = FM_NORMAL; + break; + case 0x90: // read identifier codes + m_mode = FM_READID; + break; + case 0x98: // read query + m_mode = FM_READQUERY; + break; + case 0x70: // read status register + m_mode = FM_READSTATUS; + break; + case 0x50: // clear status register + m_mode = FM_READSTATUS; + m_status &= 0xC5; + break; + case 0xe8: // write to buffer + m_mode = FM_WRBUFPART1; + m_wrbuf_base = offset & BLOCK_ADDRESS_MASK; + /*m_status &= 0xC5;*/ + break; + case 0x40: + case 0x10: // program + m_mode = FM_WRITEPART1; + m_status &= 0xC5; + break; + case 0x20: // block erase + m_mode = FM_CLEARPART1; + m_status &= 0xC5; + break; + case 0xb0: // block erase, program suspend + /* not emulated (erase is instantaneous) */ + break; + case 0xd0: // block erase, program resume + /* not emulated (erase is instantaneous) */ + break; + case 0xb8: // configuration + m_mode = FM_CONFPART1; + m_status &= 0xC5; + break; + case 0x60: // set master lock + m_mode = FM_SETLOCK; + m_status &= 0xC5; + break; + case 0xc0: // protection program + m_mode = FM_WRPROTPART1; + m_status &= 0xC5; + break; + default: + logerror("Unknown flash mode byte %x\n", data); + break; + } + break; + case FM_WRBUFPART1: + m_mode = FM_WRBUFPART2; + if (((offset & BLOCK_ADDRESS_MASK) != m_wrbuf_base) || (data >= 0x20)) + { + m_status |= 0x30; + m_wrbuf_len = 0; + m_wrbuf_count = data; + } + else + { + switch (bus_width) + { + case bw_8: + m_wrbuf_len = data+1; + break; + case bw_16: + m_wrbuf_len = (data+1) << 1; + break; + } + m_wrbuf_count = data; + } + break; + case FM_WRBUFPART2: + m_mode = FM_WRBUFPART3; + if (((offset & BLOCK_ADDRESS_MASK) != m_wrbuf_base) + || (((offset & BYTE_ADDRESS_MASK) + m_wrbuf_len) > BLOCK_SIZE)) + { + m_status |= 0x30; + m_wrbuf_len = 0; + m_wrbuf_base = 0; + } + else + m_wrbuf_base = offset; + memset(m_wrbuf, 0xff, m_wrbuf_len); /* right??? */ + case FM_WRBUFPART3: + if ((offset < m_wrbuf_base) || (offset >= (m_wrbuf_base + m_wrbuf_len))) + m_status |= 0x30; + else + { + switch (bus_width) + { + case bw_8: + m_wrbuf[offset-m_wrbuf_base] = data; + break; + case bw_16: + m_wrbuf[offset-m_wrbuf_base] = data & 0xff; + m_wrbuf[offset-m_wrbuf_base+1] = data >> 8; + break; + } + } + if (m_wrbuf_count == 0) + m_mode = FM_WRBUFPART4; + else + m_wrbuf_count--; + break; + case FM_WRBUFPART4: + if (((offset & BLOCK_ADDRESS_MASK) != (m_wrbuf_base & BLOCK_ADDRESS_MASK)) || (data != 0xd0)) + { + m_status |= 0x30; + } + else if (READ_BLOCKLOCK(offset >> BLOCK_ADDRESS_SHIFT) && !m_hard_unlock) + { + m_status |= 0x12; + } + else if (!(m_status & 0x30)) + { + int i; + for (i=0; i> BLOCK_ADDRESS_SHIFT) && !m_hard_unlock) + { + m_status |= 0x12; + } + else + { + switch (bus_width) + { + case bw_8: + m_flashmemory[BYTE_XOR_LE(offset)] &= data; + break; + case bw_16: + *(UINT16*)(m_flashmemory+offset) &= data; + break; + } + } + m_mode = FM_READSTATUS; + break; + case FM_CLEARPART1: + if (data == 0xd0) + { + // clear the 128k block containing the current address + // to all 0xffs + if (READ_BLOCKLOCK(offset >> BLOCK_ADDRESS_SHIFT) && !m_hard_unlock) + { + m_status |= 0x22; + } + else + { + offset &= BLOCK_ADDRESS_MASK; + memset(&m_flashmemory[offset], 0xff, BLOCK_SIZE); + } + m_mode = FM_READSTATUS; + } + break; + case FM_SETLOCK: + switch (data) + { + case 0xf1: + if (!m_hard_unlock) + m_status |= 0x12; + else + m_master_lock = 1; + break; + case 0x01: + if (m_master_lock && !m_hard_unlock) + m_status |= 0x12; + else + SET_BLOCKLOCK(offset >> BLOCK_ADDRESS_SHIFT); + break; + case 0xd0: + if (m_master_lock && !m_hard_unlock) + m_status |= 0x22; + else + CLEAR_BLOCKLOCK(offset >> BLOCK_ADDRESS_SHIFT); + break; + case 0x03: // Set Read configuration + /* ignore command */ + break; + default: + m_status |= 0x30; + break; + } + m_mode = FM_READSTATUS; + break; + case FM_CONFPART1: + /* configuration register is not emulated because the sts pin is not */ + //m_configuration = data; + m_mode = FM_READSTATUS; /* right??? */ + break; + case FM_WRPROTPART1: + if ((offset < 0x100) || (offset >= 0x112)) + m_status |= 0x10; + else if ((offset >= 0x102) && !((m_prot_regs[BYTE_XOR_LE(0)] >> ((offset - 0x102) >> 3)) & 1)) + m_status |= 0x12; + else + { + switch (bus_width) + { + case bw_8: + m_prot_regs[BYTE_XOR_LE(offset-0x100)] &= data; + break; + case bw_16: + *(UINT16*)(m_prot_regs+(offset-0x100)) &= data; + break; + } + } + m_mode = FM_READSTATUS; /* right??? */ + break; + } +} + +/* + read a byte from FEEPROM +*/ +READ8_MEMBER( strataflash_device::read8 ) +{ + return read8_16(space, offset, bw_8); +} + +/* + Write a byte to FEEPROM +*/ +WRITE8_MEMBER( strataflash_device::write8 ) +{ + write8_16(space, offset, data, bw_8); +} + +/* + read a 16-bit word from FEEPROM +*/ +READ16_MEMBER( strataflash_device::read16 ) +{ + return read8_16(space, offset, bw_16); +} + +/* + Write a byte to FEEPROM +*/ +WRITE16_MEMBER( strataflash_device::write16 ) +{ + write8_16(space, offset, data, bw_16); +} diff --git a/src/devices/machine/strata.h b/src/devices/machine/strata.h new file mode 100644 index 00000000000..c037a24396b --- /dev/null +++ b/src/devices/machine/strata.h @@ -0,0 +1,75 @@ +// license:BSD-3-Clause +// copyright-holders:Raphael Nabet, Michael Zapf +/* + strata.h: header file for strata.c +*/ + +class strataflash_device : public device_t, public device_nvram_interface +{ +public: + strataflash_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // 8-bit access + DECLARE_READ8_MEMBER( read8 ); + DECLARE_WRITE8_MEMBER( write8 ); + + // 16-bit access + DECLARE_READ16_MEMBER( read16 ); + DECLARE_WRITE16_MEMBER( write16 ); + +protected: + // device-level overrides + void device_config_complete(); + + void device_start(); + + void nvram_default(); + void nvram_read(emu_file &file); + void nvram_write(emu_file &file); + +private: + + // bus width for 8/16-bit handlers + enum bus_width_t + { + bw_8, + bw_16 + }; + + UINT16 read8_16(address_space& space, offs_t offset, bus_width_t bus_width); + void write8_16(address_space& space, offs_t offset, UINT16 data, bus_width_t bus_width); + + enum fm_mode_t + { + FM_NORMAL, // normal read/write + FM_READID, // read ID + FM_READQUERY, // read query + FM_READSTATUS, // read status + FM_WRITEPART1, // first half of programming, awaiting second + FM_WRBUFPART1, // first part of write to buffer, awaiting second + FM_WRBUFPART2, // second part of write to buffer, awaiting third + FM_WRBUFPART3, // third part of write to buffer, awaiting fourth + FM_WRBUFPART4, // fourth part of write to buffer + FM_CLEARPART1, // first half of clear, awaiting second + FM_SETLOCK, // first half of set master lock/set block lock + FM_CONFPART1, // first half of configuration, awaiting second + FM_WRPROTPART1 // first half of protection program, awaiting second + }; + + fm_mode_t m_mode; // current operation mode + int m_hard_unlock; // 1 if RP* pin is at Vhh (not fully implemented) + int m_status; // current status + int m_master_lock; // master lock flag + offs_t m_wrbuf_base; // start address in write buffer command + int m_wrbuf_len; // count converted into byte length in write buffer command + int m_wrbuf_count; // current count in write buffer command + UINT8* m_wrbuf; // write buffer used by write buffer command + UINT8* m_flashmemory; // main FEEPROM area + UINT8* m_blocklock; // block lock flags + UINT8* m_prot_regs; // protection registers +}; + +extern const device_type STRATAFLASH; + +#define MCFG_STRATAFLASH_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, STRATAFLASH, 0) diff --git a/src/devices/machine/stvcd.c b/src/devices/machine/stvcd.c new file mode 100644 index 00000000000..eebb8d11cb4 --- /dev/null +++ b/src/devices/machine/stvcd.c @@ -0,0 +1,2702 @@ +// license:LGPL-2.1+ +// copyright-holders:Angelo Salese, R. Belmont +/*************************************************************************** + + machine/stvcd.c - Sega Saturn and ST-V CD-ROM handling + + Another tilt at the windmill in 2011 by R. Belmont. + + Status: All known discs at least load their executable, and many load + some data files successfully, but there are other problems. + + Information sources: + - Tyranid's document + - A commented disassembly I made of the Saturn BIOS's CD code + - Yabuse's cs2.c + - The ISO/IEC "Yellow Book" CD-ROM standard, 1995 version + + Address is mostly in terms of FAD (Frame ADdress). + FAD is absolute number of frames from the start of the disc. + In other words, FAD = LBA + 150; FAD is the same units as + LBA except it counts starting at absolute zero instead of + the first sector (00:02:00 in MSF format). + +***************************************************************************/ + +#include "emu.h" +#include "imagedev/chd_cd.h" +#include "includes/stv.h" +#include "cdrom.h" +#include "sound/cdda.h" +#include "debugger.h" +#include "coreutil.h" + +// super-verbose +#if 0 +#define CDROM_LOG(x) printf x; +#else +#define CDROM_LOG(x) +#endif + +// HIRQ definitions +#define CMOK 0x0001 // command dispatch possible +#define DRDY 0x0002 // data transfer preparations complete +#define CSCT 0x0004 // finished reading 1 sector +#define BFUL 0x0008 // CD buffer full +#define PEND 0x0010 // CD playback completed +#define DCHG 0x0020 // disc change / tray open +#define ESEL 0x0040 // selector settings processing complete +#define EHST 0x0080 // host input/output processing complete +#define ECPY 0x0100 // duplication/move processing complete +#define EFLS 0x0200 // file system processing complete +#define SCDQ 0x0400 // subcode Q update completed +#define MPED 0x0800 // MPEG-related processing complete +#define MPCM 0x1000 // MPEG action uncertain +#define MPST 0x2000 // MPEG interrupt status report + +// CD status (hi byte of CR1) definitions: +// (these defines are shifted up 8) +#define CD_STAT_BUSY 0x0000 // status change in progress +#define CD_STAT_PAUSE 0x0100 // CD block paused (temporary stop) +#define CD_STAT_STANDBY 0x0200 // CD drive stopped +#define CD_STAT_PLAY 0x0300 // CD play in progress +#define CD_STAT_SEEK 0x0400 // drive seeking +#define CD_STAT_SCAN 0x0500 // drive scanning +#define CD_STAT_OPEN 0x0600 // tray is open +#define CD_STAT_NODISC 0x0700 // no disc present +#define CD_STAT_RETRY 0x0800 // read retry in progress +#define CD_STAT_ERROR 0x0900 // read data error occurred +#define CD_STAT_FATAL 0x0a00 // fatal error (hard reset required) +#define CD_STAT_PERI 0x2000 // periodic response if set, else command response +#define CD_STAT_TRANS 0x4000 // data transfer request if set +#define CD_STAT_WAIT 0x8000 // waiting for command if set, else executed immediately +#define CD_STAT_REJECT 0xff00 // ultra-fatal error. + +int saturn_state::get_timing_command(void) +{ + /* TODO: calculate timings based off command params */ + return 16667; +} + +/* FIXME: assume Saturn CD-ROMs to have a 2 secs pre-gap for now. */ +int saturn_state::get_track_index(UINT32 fad) +{ + UINT32 rel_fad; + UINT8 track; + + if(cdrom_get_track_type(cdrom, cdrom_get_track(cdrom, fad)) != CD_TRACK_AUDIO) + return 1; + + track = cdrom_get_track( cdrom, fad ); + + rel_fad = fad - cdrom_get_track_start( cdrom, track ); + + if(rel_fad < 150) + return 0; + + return 1; +} + +int saturn_state::sega_cdrom_get_adr_control(cdrom_file *file, int track) +{ + return BITSWAP8(cdrom_get_adr_control(file, cur_track),3,2,1,0,7,6,5,4); +} + +void saturn_state::cr_standard_return(UINT16 cur_status) +{ + if ((cd_stat & 0x0f00) == CD_STAT_SEEK) + { + /* During seek state, values returned are from the target position */ + UINT8 seek_track = cdrom_get_track(cdrom, cd_fad_seek-150); + + cr1 = cur_status | (playtype << 7) | 0x00 | (cdda_repeat_count & 0xf); + cr2 = (seek_track == 0xff) ? 0xffff : ((sega_cdrom_get_adr_control(cdrom, seek_track)<<8) | seek_track); + cr3 = (get_track_index(cd_fad_seek)<<8) | (cd_fad_seek>>16); //index & 0xff00 + cr4 = cd_fad_seek; + } + else + { + /* + TODO: + - Whizz: wpset 0x608f030,4,w,wpdata==0x100&&pc!=0x6040006 + */ + cr1 = cur_status | (playtype << 7) | 0x00 | (cdda_repeat_count & 0xf); //options << 4 | repeat & 0xf + cr2 = (cur_track == 0xff) ? 0xffff : ((sega_cdrom_get_adr_control(cdrom, cur_track)<<8) | (cdrom_get_track(cdrom, cd_curfad-150)+1)); + cr3 = (get_track_index(cd_curfad)<<8) | (cd_curfad>>16); //index & 0xff00 + cr4 = cd_curfad; + } +} + +void saturn_state::cd_exec_command( void ) +{ + UINT32 temp; + + if(cr1 != 0 && + ((cr1 & 0xff00) != 0x5100) && + ((cr1 & 0xff00) != 0x5200) && + ((cr1 & 0xff00) != 0x5300) && + 1) + printf("CD: command exec %04x %04x %04x %04x %04x (stat %04x)\n", hirqreg, cr1, cr2, cr3, cr4, cd_stat); + + switch ((cr1 >> 8) & 0xff) + { + case 0x00: + //CDROM_LOG(("%s:CD: Get Status\n", machine().describe_context())) + hirqreg |= CMOK; + if(status_type == 0) + cr_standard_return(cd_stat); + else + { + cr1 = (cd_stat) | (prev_cr1 & 0xff); + cr2 = prev_cr2; + cr3 = prev_cr3; + cr4 = prev_cr4; + status_type = 0; /* Road Blaster and friends needs this otherwise they won't boot. */ + } + //CDROM_LOG((" = %04x %04x %04x %04x %04x\n", hirqreg, cr1, cr2, cr3, cr4)) + break; + + case 0x01: + CDROM_LOG(("%s:CD: Get Hardware Info\n", machine().describe_context())) + hirqreg |= CMOK; + cr1 = cd_stat; + cr2 = 0x0201; + cr3 = 0x0000; + cr4 = 0x0400; + status_type = 0; + break; + + case 0x02: // Get TOC + CDROM_LOG(("%s:CD: Get TOC\n", machine().describe_context())) + cd_readTOC(); + cd_stat = CD_STAT_TRANS|CD_STAT_PAUSE; + cr1 = cd_stat; + cr2 = 102*2; // TOC length in words (102 entries @ 2 words/4bytes each) + cr3 = 0; + cr4 = 0; + xferdnum = 0; + hirqreg |= (CMOK|DRDY); + status_type = 0; + break; + + case 0x03: // get session info (lower byte = session # to get?) + // bios is interested in returns in cr3 and cr4 + // cr3 should be data track # + // cr4 must be > 1 and < 100 or bios gets angry. + CDROM_LOG(("%s:CD: Get Session Info\n", machine().describe_context())) + cd_readTOC(); + switch (cr1 & 0xff) + { + case 0: // get total session info / disc end + cd_stat = CD_STAT_PAUSE; + cr1 = cd_stat; + cr2 = 0; + cr3 = 0x0100 | tocbuf[(101*4)+1]; + cr4 = tocbuf[(101*4)+2]<<8 | tocbuf[(101*4)+3]; + break; + + case 1: // get total session info / disc start + cd_stat = CD_STAT_PAUSE; + cr1 = cd_stat; + cr2 = 0; + cr3 = 0x0100; // sessions in high byte, session start in lower + cr4 = 0; + break; + + default: + osd_printf_error("CD: Unknown request to Get Session Info %x\n", cr1 & 0xff); + cr1 = cd_stat; + cr2 = 0; + cr3 = 0; + cr4 = 0; + break; + } + + hirqreg |= (CMOK); + status_type = 0; + break; + + /* TODO: double check this */ + case 0x04: // initialize CD system + // CR1 & 1 = reset software + // CR1 & 2 = decode RW subcode + // CR1 & 4 = don't confirm mode 2 subheader + // CR1 & 8 = retry reading mode 2 sectors + // CR1 & 10 = force single-speed + // CR1 & 80 = no change flag (done by Assault Suit Leynos 2) + CDROM_LOG(("%s:CD: Initialize CD system\n", machine().describe_context())) + //if((cr1 & 0x81) == 0x00) //guess TODO: nope, Choice Cuts doesn't like it, it crashes if you try to skip the FMV otherwise. + { + if(((cd_stat & 0x0f00) != CD_STAT_NODISC) && ((cd_stat & 0x0f00) != CD_STAT_OPEN)) + { + cd_stat = CD_STAT_PAUSE; + cd_curfad = 150; + //cur_track = 1; + fadstoplay = 0; + } + in_buffer = 0; + buffull = 0; + hirqreg &= 0xffe5; + cd_speed = (cr1 & 0x10) ? 1 : 2; + + /* reset filter connections */ + /* Guess: X-Men COTA sequence is 0x48->0x48->0x04(01)->0x04(00)->0x30 then 0x10, without this game throws a FAD reject error */ + /* X-Men vs. SF is even fussier, sequence is 0x04 (1) 0x04 (0) 0x03 (0) 0x03 (1) 0x30 */ + #if 0 + for(int i=0;i>17) & 0xff); + cr2 = (xferdnum>>1)&0xffff; + cr3 = 0; + cr4 = 0; + } + else + { + printf("No xferdnum error\n"); + cr1 = (cd_stat) | (0xff); // is this right? + cr2 = 0xffff; + cr3 = 0; + cr4 = 0; + } + + // try to clean up any transfers still in progress + switch (xfertype32) + { + case XFERTYPE32_GETSECTOR: + case XFERTYPE32_PUTSECTOR: + hirqreg |= EHST; + break; + + case XFERTYPE32_GETDELETESECTOR: + if (transpart->size > 0) + { + INT32 i; + + xfertype32 = XFERTYPE32_INVALID; + + // deallocate the blocks + for (i = xfersectpos; i < xfersectpos+xfersectnum; i++) + { + cd_free_block(transpart->blocks[i]); + transpart->blocks[i] = (blockT *)NULL; + transpart->bnum[i] = 0xff; + } + + // defrag what's left + cd_defragblocks(transpart); + + // clean up our state + transpart->size -= xferdnum; + transpart->numblks -= xfersectnum; + + if (freeblocks == 200) + { + sectorstore = 0; + } + + hirqreg |= EHST; + } + break; + + default: + break; + } + + + xferdnum = 0; + hirqreg |= CMOK; + + CDROM_LOG((" = %04x %04x %04x %04x %04x\n", hirqreg, cr1, cr2, cr3, cr4)) + status_type = 1; + break; + + case 0x10: // Play Disc. FAD is in lowest 7 bits of cr1 and all of cr2. + UINT32 start_pos,end_pos; + UINT8 play_mode; + + CDROM_LOG(("%s:CD: Play Disc\n", machine().describe_context())) + cd_stat = CD_STAT_PLAY; + + play_mode = (cr3 >> 8) & 0x7f; + + if (!(cr3 & 0x8000)) // preserve current position if bit 7 set + { + start_pos = ((cr1&0xff)<<16) | cr2; + end_pos = ((cr3&0xff)<<16) | cr4; + + if (start_pos & 0x800000) + { + if (start_pos != 0xffffff) + cd_curfad = start_pos & 0xfffff; + + printf("fad mode\n"); + cur_track = cdrom_get_track(cdrom, cd_curfad-150); + } + else + { + // track mode + if(((start_pos)>>8) != 0) + { + cur_track = (start_pos)>>8; + cd_fad_seek = cdrom_get_track_start(cdrom, cur_track-1); + cd_stat = CD_STAT_SEEK; + machine().device("cdda")->pause_audio(0); + } + else + { + /* TODO: Waku Waku 7 sets up track 0, that basically doesn't make any sense. Just skip it for now. */ + popmessage("Warning: track mode == 0, contact MAMEdev"); + cr_standard_return(cd_stat); + hirqreg |= (CMOK); + return; + } + + printf("track mode %d\n",cur_track); + } + + if (end_pos & 0x800000) + { + if (end_pos != 0xffffff) + fadstoplay = end_pos & 0xfffff; + } + else + { + UINT8 end_track; + + end_track = (end_pos)>>8; + fadstoplay = cdrom_get_track_start(cdrom, end_track) - cd_fad_seek; + } + } + else // play until the end of the disc + { + start_pos = ((cr1&0xff)<<16) | cr2; + end_pos = ((cr3&0xff)<<16) | cr4; + + if(start_pos != 0xffffff) + { + /* Madou Monogatari sets 0xff80xxxx as end position, needs investigation ... */ + if(end_pos & 0x800000) + fadstoplay = end_pos & 0xfffff; + else + { + if(end_pos == 0) + fadstoplay = (cdrom_get_track_start(cdrom, 0xaa)) - cd_curfad; + else + fadstoplay = (cdrom_get_track_start(cdrom, (end_pos & 0xff00) >> 8)) - cd_curfad; + } + printf("track mode %08x %08x\n",cd_curfad,fadstoplay); + } + else + { + /* resume from a pause state */ + /* TODO: Galaxy Fight calls 10ff ffff ffff ffff, but then it calls 0x04->0x02->0x06->0x11->0x04->0x02->0x06 command sequence + (and current implementation nukes start/end FAD addresses at 0x04). I'm sure that this doesn't work like this, but there could + be countless possible combinations ... */ + if(fadstoplay == 0) + { + cd_curfad = cdrom_get_track_start(cdrom, cur_track-1); + fadstoplay = cdrom_get_track_start(cdrom, cur_track) - cd_curfad; + } + printf("track resume %08x %08x\n",cd_curfad,fadstoplay); + } + } + + CDROM_LOG(("CD: Play Disc: start %x length %x\n", cd_curfad, fadstoplay)) + + cr_standard_return(cd_stat); + hirqreg |= (CMOK); + oddframe = 0; + in_buffer = 0; + + playtype = 0; + + // cdda + if(cdrom_get_track_type(cdrom, cdrom_get_track(cdrom, cd_curfad)) == CD_TRACK_AUDIO) + { + machine().device("cdda")->pause_audio(0); + //machine().device("cdda")->start_audio(cd_curfad, fadstoplay); + //cdda_repeat_count = 0; + } + + if(play_mode != 0x7f) + cdda_maxrepeat = play_mode & 0xf; + else + cdda_maxrepeat = 0; + + cdda_repeat_count = 0; + status_type = 0; + break; + + case 0x11: // disc seek + CDROM_LOG(("%s:CD: Disc seek\n", machine().describe_context())) + //printf("%08x %08x %08x %08x\n",cr1,cr2,cr3,cr4); + if (cr1 & 0x80) + { + temp = (cr1&0xff)<<16; // get FAD to seek to + temp |= cr2; + + //cd_curfad = temp; + + if (temp == 0xffffff) + { + cd_stat = CD_STAT_PAUSE; + machine().device("cdda")->pause_audio(1); + } + else + { + cd_curfad = ((cr1&0x7f)<<16) | cr2; + printf("disc seek with params %04x %04x\n",cr1,cr2); //Area 51 sets this up + } + } + else + { + // is it a valid track? + if (cr2 >> 8) + { + cd_stat = CD_STAT_PAUSE; + cur_track = cr2>>8;; + cd_curfad = cdrom_get_track_start(cdrom, cur_track-1); + machine().device("cdda")->pause_audio(1); + // (index is cr2 low byte) + } + else // error! + { + cd_stat = CD_STAT_STANDBY; + cd_curfad = 0xffffffff; + cur_track = 0xff; + machine().device("cdda")->stop_audio(); //stop any pending CD-DA + } + } + + + hirqreg |= CMOK; + cr_standard_return(cd_stat); + status_type = 0; + break; + + case 0x12: // FFWD / REW + //cr1 bit 0 determines if this is a Fast Forward (0) or a Rewind (1) command + // ... + break; + + case 0x20: // Get SubCode Q / RW Channel + switch(cr1 & 0xff) + { + case 0: // Get Q + { + UINT32 msf_abs,msf_rel; + UINT8 track; + cr1 = cd_stat | 0; + cr2 = 10/2; + cr3 = 0; + cr4 = 0; + + /* + Subcode Q info should be: + ---- --x- S0 + ---- ---x S1 + xxxx ---- [0] Control (bit 7 Pre-emphasis, bit 6: copy permitted, bit 5 undefined, bit 4 number of channels) + ---- xxxx [0] address (0x0001 Mode 1) + xxxx xxxx [1] track number (1-99, AA lead-out), BCD format + xxxx xxxx [2] index (01 lead-out), BCD format + xxxx xxxx [3] Time within' track M + xxxx xxxx [4] Time within' track S + xxxx xxxx [5] Time within' track F + xxxx xxxx [6] Zero + xxxx xxxx [7] Absolute M + xxxx xxxx [8] Absolute S + xxxx xxxx [9] Absolute F + xxxx xxxx [10] CRCC + xxxx xxxx [11] CRCC + */ + + msf_abs = lba_to_msf_alt( cd_curfad - 150 ); + track = cdrom_get_track( cdrom, cd_curfad ); + msf_rel = lba_to_msf_alt( cd_curfad - 150 - cdrom_get_track_start( cdrom, track ) ); + + xfertype = XFERTYPE_SUBQ; + xfercount = 0; + subqbuf[0] = 0x01 | ((cdrom_get_track_type(cdrom, cdrom_get_track(cdrom, track+1)) == CD_TRACK_AUDIO) ? 0x00 : 0x40); + subqbuf[1] = dec_2_bcd(track+1); + subqbuf[2] = dec_2_bcd(get_track_index(cd_curfad)); + subqbuf[3] = dec_2_bcd((msf_rel >> 16) & 0xff); + subqbuf[4] = dec_2_bcd((msf_rel >> 8) & 0xff); + subqbuf[5] = dec_2_bcd((msf_rel >> 0) & 0xff); + subqbuf[6] = 0; + subqbuf[7] = dec_2_bcd((msf_abs >> 16) & 0xff); + subqbuf[8] = dec_2_bcd((msf_abs >> 8) & 0xff); + subqbuf[9] = dec_2_bcd((msf_abs >> 0) & 0xff); + } + break; + + case 1: // Get RW + cr1 = cd_stat | 0; + cr2 = 12; + cr3 = 0; + cr4 = 0; + + xfertype = XFERTYPE_SUBRW; + xfercount = 0; + + /* return null data for now */ + { + int i; + + for(i=0;i<12*2;i++) + subrwbuf[i] = 0; + } + break; + } + hirqreg |= CMOK|DRDY; + status_type = 0; + break; + + case 0x30: // Set CD Device connection + { + UINT8 parm; + + // get operation + parm = cr3>>8; + + CDROM_LOG(("%s:CD: Set CD Device Connection filter # %x\n", machine().describe_context(), parm)) + + cddevicenum = parm; + + if (parm == 0xff) + { + cddevice = (filterT *)NULL; + } + else + { + if (parm < 0x24) + { + cddevice = &filters[(cr3>>8)]; + } + } + + + hirqreg |= (CMOK|ESEL); + cr_standard_return(cd_stat); + status_type = 0; + } + break; + + case 0x31: + popmessage("Get CD Device Connection, contact MAMEdev"); + hirqreg |= CMOK; + break; + + case 0x32: // Last Buffer Destination + cr1 = cd_stat | 0; + cr2 = 0; + cr3 = lastbuf << 8; + cr4 = 0; + hirqreg |= (CMOK); + status_type = 0; + break; + + case 0x40: // Set Filter Range + // cr1 low + cr2 = FAD0, cr3 low + cr4 = FAD1 + // cr3 hi = filter num. + { + UINT8 fnum = (cr3>>8)&0xff; + + CDROM_LOG(("%s:CD: Set Filter Range\n", machine().describe_context())) + + filters[fnum].fad = ((cr1 & 0xff)<<16) | cr2; + filters[fnum].range = ((cr3 & 0xff)<<16) | cr4; + + printf("%08x %08x %d\n",filters[fnum].fad,filters[fnum].range,fnum); + + hirqreg |= (CMOK|ESEL); + cr_standard_return(cd_stat); + status_type = 0; + } + break; + + case 0x41: + popmessage("Get Filter Range, contact MAMEdev"); + hirqreg |= CMOK; + break; + + case 0x42: // Set Filter Subheader conditions + { + UINT8 fnum = (cr3>>8)&0xff; + + CDROM_LOG(("%s:CD: Set Filter Subheader conditions %x => chan %x masks %x fid %x vals %x\n", machine().describe_context(), fnum, cr1&0xff, cr2, cr3&0xff, cr4)) + + filters[fnum].chan = cr1 & 0xff; + filters[fnum].smmask = (cr2>>8)&0xff; + filters[fnum].cimask = cr2&0xff; + filters[fnum].fid = cr3&0xff; + filters[fnum].smval = (cr4>>8)&0xff; + filters[fnum].cival = cr4&0xff; + + hirqreg |= (CMOK|ESEL); + cr_standard_return(cd_stat); + status_type = 0; + } + break; + + case 0x43: // Get Filter Subheader conditions + { + UINT8 fnum = (cr3>>8)&0xff; + + CDROM_LOG(("%s:CD: Set Filter Subheader conditions %x => chan %x masks %x fid %x vals %x\n", machine().describe_context(), fnum, cr1&0xff, cr2, cr3&0xff, cr4)) + + cr1 = cd_stat | (filters[fnum].chan & 0xff); + cr2 = (filters[fnum].smmask << 8) | (filters[fnum].cimask & 0xff); + cr3 = filters[fnum].fid; + cr4 = (filters[fnum].smval << 8) | (filters[fnum].cival & 0xff); + + hirqreg |= (CMOK|ESEL); + status_type = 0; + } + break; + + case 0x44: // Set Filter Mode + { + UINT8 fnum = (cr3>>8)&0xff; + UINT8 mode = (cr1 & 0xff); + + // initialize filter? + if (mode & 0x80) + { + memset(&filters[fnum], 0, sizeof(filterT)); + } + else + { + filters[fnum].mode = mode; + } + + CDROM_LOG(("%s:CD: Set Filter Mode filt %x mode %x\n", machine().describe_context(), fnum, mode)) + hirqreg |= (CMOK|ESEL); + cr_standard_return(cd_stat); + status_type = 0; + } + break; + + case 0x45: // Get Filter Mode + { + UINT8 fnum = (cr3>>8)&0xff; + + cr1 = cd_stat | (filters[fnum].mode & 0xff); + cr2 = 0; + cr3 = 0; + cr4 = 0; + + hirqreg |= (CMOK|ESEL); + status_type = 0; + } + break; + + case 0x46: // Set Filter Connection + { + /* TODO: maybe condition false is cr3 low? */ + UINT8 fnum = (cr3>>8)&0xff; + + CDROM_LOG(("%s:CD: Set Filter Connection %x => mode %x parm %04x\n", machine().describe_context(), fnum, cr1 & 0xf, cr2)) + + if (cr1 & 1) // set true condition + filters[fnum].condtrue = (cr2>>8)&0xff; + + if (cr1 & 2) // set false condition + filters[fnum].condfalse = cr2&0xff; + + hirqreg |= (CMOK|ESEL); + cr_standard_return(cd_stat); + status_type = 0; + } + break; + + case 0x48: // Reset Selector + { + int i,j; + + CDROM_LOG(("%s:CD: Reset Selector\n", machine().describe_context())) + + if((cr1 & 0xff) == 0x00) + { + UINT8 bufnum = cr3>>8; + + if(bufnum < MAX_FILTERS) + { + for (i = 0; i < MAX_BLOCKS; i++) + { + cd_free_block(partitions[bufnum].blocks[i]); + partitions[bufnum].blocks[i] = (blockT *)NULL; + partitions[bufnum].bnum[i] = 0xff; + } + + partitions[bufnum].size = -1; + partitions[bufnum].numblks = 0; + } + + // TODO: buffer full flag + + if (freeblocks == 200) { sectorstore = 0; } + + hirqreg |= (CMOK|ESEL); + cr_standard_return(cd_stat); + status_type = 0; + return; + } + + /* reset false filter output conditions */ + /* TODO: check these two. */ + if(cr1 & 0x80) + { + for(i=0;i 200) ? 200 : freeblocks; + cr3 = 0x1800; + cr4 = 200; + CDROM_LOG(("CD: Get Buffer Size = %d\n", cr2)) + hirqreg |= (CMOK); + status_type = 0; + break; + + case 0x51: // get # sectors used in a buffer + { + UINT32 bufnum = cr3>>8; + + CDROM_LOG(("%s:CD: Get Sector Number (bufno %d) = %d blocks\n", machine().describe_context(), bufnum, cr4)) + cr1 = cd_stat; + cr2 = 0; + cr3 = 0; + if(cr1 & 0xff || cr2 || cr3 & 0xff || cr4) + printf("Get # sectors used with params %04x %04x %04x %04x\n",cr1,cr2,cr3,cr4); + + // is the partition empty? + if (partitions[bufnum].size == -1) + { + cr4 = 0; + } + else + { + cr4 = partitions[bufnum].numblks; + //printf("Partition %08x %04x\n",bufnum,cr4); + } + + //printf("%04x\n",cr4); + if(cr4 == 0) + hirqreg |= (CMOK); + else + hirqreg |= (CMOK|DRDY); + status_type = 1; + } + break; + + case 0x52: // calculate actual size + { + UINT32 bufnum = cr3>>8; + UINT32 sectoffs = cr2; + UINT32 numsect = cr4; + + CDROM_LOG(("%s:CD: Calculate actual size: buf %x offs %x numsect %x\n", machine().describe_context(), bufnum, sectoffs, numsect)) + + calcsize = 0; + if (partitions[bufnum].size != -1) + { + INT32 i; + + for (i = 0; i < numsect; i++) + { + if (partitions[bufnum].blocks[sectoffs+i]) + { + calcsize += (partitions[bufnum].blocks[sectoffs+i]->size / 2); + } + } + } + + hirqreg |= (CMOK|ESEL); + cr_standard_return(cd_stat); + status_type = 0; + } + break; + + case 0x53: // get actual block size + CDROM_LOG(("%s:CD: Get actual block size\n", machine().describe_context())) + cr1 = cd_stat | ((calcsize>>16)&0xff); + cr2 = (calcsize & 0xffff); + cr3 = 0; + cr4 = 0; + hirqreg |= (CMOK|ESEL); + status_type = 1; + break; + + case 0x54: // get sector info + { + UINT32 sectoffs = cr2 & 0xff; + UINT32 bufnum = cr3>>8; + + if (bufnum >= MAX_FILTERS || !partitions[bufnum].blocks[sectoffs]) + { + cr1 |= CD_STAT_REJECT & 0xff00; + hirqreg |= (CMOK|ESEL); + printf("Get sector info reject\n"); + } + else + { + cr1 = cd_stat | ((partitions[bufnum].blocks[sectoffs]->FAD >> 16) & 0xff); + cr2 = partitions[bufnum].blocks[sectoffs]->FAD & 0xffff; + cr3 = ((partitions[bufnum].blocks[sectoffs]->fnum & 0xff) << 8) | (partitions[bufnum].blocks[sectoffs]->chan & 0xff); + cr4 = ((partitions[bufnum].blocks[sectoffs]->subm & 0xff) << 8) | (partitions[bufnum].blocks[sectoffs]->cinf & 0xff); + hirqreg |= (CMOK|ESEL); + } + + status_type = 0; + } + break; + + case 0x60: // set sector length + CDROM_LOG(("%s:CD: Set sector length\n", machine().describe_context())) + + switch (cr1 & 0xff) + { + case 0: + sectlenin = 2048; + break; + case 1: + sectlenin = 2336; + break; + case 2: + sectlenin = 2340; + break; + case 3: + sectlenin = 2352; + break; + } + + switch ((cr2>>8) & 0xff) + { + case 0: + sectlenout = 2048; + break; + case 1: + sectlenout = 2336; + break; + case 2: + sectlenout = 2340; + break; + case 3: + sectlenout = 2352; + break; + } + hirqreg |= (CMOK|ESEL); + cr_standard_return(cd_stat); + status_type = 0; + break; + + case 0x61: // get sector data + { + UINT32 sectnum = cr4; + UINT32 sectofs = cr2; + UINT32 bufnum = cr3>>8; + + CDROM_LOG(("%s:CD: Get sector data (SN %d SO %d BN %d)\n", machine().describe_context(), sectnum, sectofs, bufnum)) + + if (bufnum >= MAX_FILTERS) + { + printf("CD: invalid buffer number\n"); + /* TODO: why this is happening? */ + cr_standard_return(CD_STAT_REJECT); + hirqreg |= (CMOK|EHST); + return; + } + + if (partitions[bufnum].numblks < sectnum) + { + printf("CD: buffer is not full %08x %08x\n",partitions[bufnum].numblks,sectnum); + cr_standard_return(CD_STAT_REJECT); + hirqreg |= (CMOK|EHST); + return; + } + + cd_getsectoroffsetnum(bufnum, §ofs, §num); + + xfertype32 = XFERTYPE32_GETSECTOR; + xferoffs = 0; + xfersect = 0; + xferdnum = 0; + xfersectpos = sectofs; + xfersectnum = sectnum; + transpart = &partitions[bufnum]; + + cd_stat |= CD_STAT_TRANS; + cr_standard_return(cd_stat); + hirqreg |= (CMOK|EHST|DRDY); + status_type = 0; + } + break; + + case 0x62: // delete sector data + { + UINT32 sectnum = cr4; + UINT32 sectofs = cr2; + UINT32 bufnum = cr3>>8; + INT32 i; + + CDROM_LOG(("%s:CD: Delete sector data (SN %d SO %d BN %d)\n", machine().describe_context(), sectnum, sectofs, bufnum)) + + if (bufnum >= MAX_FILTERS) + { + printf("CD: invalid buffer number\n"); + /* TODO: why this is happening? */ + cr_standard_return(CD_STAT_REJECT); + hirqreg |= (CMOK|EHST); + return; + } + + /* TODO: Phantasy Star 2 throws this one. */ + if (partitions[bufnum].numblks == 0) + { + printf("CD: buffer is already empty\n"); + cr_standard_return(CD_STAT_REJECT); + hirqreg |= (CMOK|EHST); + return; + } + + cd_getsectoroffsetnum(bufnum, §ofs, §num); + + for (i = sectofs; i < (sectofs + sectnum); i++) + { + partitions[bufnum].size -= partitions[bufnum].blocks[i]->size; + cd_free_block(partitions[bufnum].blocks[i]); + partitions[bufnum].blocks[i] = (blockT *)NULL; + partitions[bufnum].bnum[i] = 0xff; + } + + cd_defragblocks(&partitions[bufnum]); + + partitions[bufnum].numblks -= sectnum; + + if (freeblocks == 200) + { + sectorstore = 0; + } + + cd_stat &= ~CD_STAT_TRANS; + cr_standard_return(cd_stat); + hirqreg |= (CMOK|EHST); + status_type = 0; + } + break; + + case 0x63: // get then delete sector data + { + UINT32 sectnum = cr4; + UINT32 sectofs = cr2; + UINT32 bufnum = cr3>>8; + + CDROM_LOG(("%s:CD: Get and delete sector data (SN %d SO %d BN %d)\n", machine().describe_context(), sectnum, sectofs, bufnum)) + + if (bufnum >= MAX_FILTERS) + { + printf("CD: invalid buffer number\n"); + /* TODO: why this is happening? */ + cr_standard_return(CD_STAT_REJECT); + hirqreg |= (CMOK|EHST); + return; + } + + /* Yoshimoto Mahjong uses the REJECT status to verify when the data is ready. */ + if (partitions[bufnum].numblks < sectnum) + { + printf("CD: buffer is not full %08x %08x\n",partitions[bufnum].numblks,sectnum); + cr_standard_return(CD_STAT_REJECT); + hirqreg |= (CMOK|EHST); + return; + } + + cd_getsectoroffsetnum(bufnum, §ofs, §num); + + xfertype32 = XFERTYPE32_GETDELETESECTOR; + xferoffs = 0; + xfersect = 0; + xferdnum = 0; + xfersectpos = sectofs; + xfersectnum = sectnum; + transpart = &partitions[bufnum]; + + cd_stat |= CD_STAT_TRANS; + cr_standard_return(cd_stat); + hirqreg |= (CMOK|EHST|DRDY); + status_type = 0; + } + break; + + case 0x64: // put sector data + /* After Burner 2, Out Run, Fantasy Zone and Dungeon Master Nexus trips this */ + { + UINT32 sectnum = cr4 & 0xff; + UINT32 sectofs = cr2; + UINT32 bufnum = cr3>>8; + + xfertype32 = XFERTYPE32_PUTSECTOR; + + /*TODO: eventual errors? */ + + cd_getsectoroffsetnum(bufnum, §ofs, §num); + + cd_stat |= CD_STAT_TRANS; + + xferoffs = 0; + xfersect = 0; + xferdnum = 0; + xfersectpos = sectofs; + xfersectnum = sectnum; + transpart = &partitions[bufnum]; + + // allocate the blocks + for (int i = xfersectpos; i < xfersectpos+xfersectnum; i++) + { + transpart->blocks[i] = cd_alloc_block(&transpart->bnum[i]); + if(transpart->size == -1) + transpart->size = 0; + transpart->size += transpart->blocks[i]->size; + transpart->numblks++; + } + } + + hirqreg |= (CMOK|DRDY); + cr_standard_return(cd_stat); + status_type = 0; + break; + + case 0x65: + popmessage("Move Sector data, contact MAMEdev"); + hirqreg |= (CMOK); + break; + + case 0x66: // copy sector data + /* TODO: Sword & Sorcery / Riglord Saga 2 */ + { + UINT32 src_filter = (cr3>>8)&0xff; + UINT32 dst_filter = cr1&0xff; + UINT32 sectnum = cr4 & 0xff; + + //cd_stat |= CD_STAT_TRANS; + //transpart = &partitions[dst_filter]; + + for (int i = 0; i < sectnum; i++) + { + // allocate the dst blocks + partitions[dst_filter].blocks[i] = cd_alloc_block(&partitions[dst_filter].bnum[i]); + if(partitions[dst_filter].size == -1) + partitions[dst_filter].size = 0; + partitions[dst_filter].size += partitions[dst_filter].blocks[i]->size; + partitions[dst_filter].numblks++; + + //copy data + for(int j = 0; j < sectlenin; j++) + partitions[dst_filter].blocks[i]->data[j] = partitions[src_filter].blocks[i]->data[j]; + + //deallocate the src blocks + //partitions[src_filter].size -= partitions[src_filter].blocks[i]->size; + //cd_free_block(partitions[src_filter].blocks[i]); + //partitions[src_filter].blocks[i] = (blockT *)NULL; + //partitions[src_filter].bnum[i] = 0xff; + } + + } + + hirqreg |= (CMOK|ECPY); + cr_standard_return(cd_stat); + status_type = 0; + break; + + + case 0x67: // get copy error + CDROM_LOG(("%s:CD: Get copy error\n", machine().describe_context())) + printf("Get copy error\n"); + cr1 = cd_stat; + cr2 = 0; + cr3 = 0; + cr4 = 0; + hirqreg |= (CMOK); + status_type = 0; + break; + + case 0x70: // change directory + CDROM_LOG(("%s:CD: Change Directory\n", machine().describe_context())) + hirqreg |= (CMOK|EFLS); + + temp = (cr3&0xff)<<16; + temp |= cr4; + + read_new_dir(temp); + cr_standard_return(cd_stat); + status_type = 0; + break; + + case 0x71: // Read directory entry + CDROM_LOG(("%s:CD: Read Directory Entry\n", machine().describe_context())) +// UINT32 read_dir; + +// read_dir = ((cr3&0xff)<<16)|cr4; + + if((cr3 >> 8) < 0x24) + cddevice = &filters[cr3 >> 8]; + else + cddevice = (filterT *)NULL; + + /* TODO: */ + //read_new_dir(read_dir - 2); + + cr_standard_return(cd_stat); + hirqreg |= (CMOK|EFLS); + status_type = 0; + break; + + case 0x72: // Get file system scope + CDROM_LOG(("CD: Get file system scope\n")) + hirqreg |= (CMOK|EFLS); + cr1 = cd_stat; + cr2 = numfiles; // # of files in directory + cr3 = 0x0100; // report directory held + cr4 = firstfile; // first file id + printf("%04x %04x %04x %04x\n",cr1,cr2,cr3,cr4); + status_type = 0; + break; + + case 0x73: // Get File Info + CDROM_LOG(("%s:CD: Get File Info\n", machine().describe_context())) + cd_stat |= CD_STAT_TRANS; + cd_stat &= 0xff00; // clear top byte of return value + playtype = 0; + cdda_repeat_count = 0; + hirqreg |= (CMOK|DRDY); + + temp = (cr3&0xff)<<16; + temp |= cr4; + + if (temp == 0xffffff) // special + { + xfertype = XFERTYPE_FILEINFO_254; + xfercount = 0; + + cr1 = cd_stat; + cr2 = 0x5f4; + cr3 = 0; + cr4 = 0; + } + else + { + cr1 = cd_stat; + cr2 = 6; // 6 words for single file + // first 4 bytes = FAD address + // second 4 bytes = length + // last 4 bytes: + // - unit size + // - gap size + // - file # + // attributes flags + + cr3 = 0; + cr4 = 0; + + printf("%08x %08x\n",curdir[temp].firstfad,curdir[temp].length); + // first 4 bytes = FAD + finfbuf[0] = (curdir[temp].firstfad>>24)&0xff; + finfbuf[1] = (curdir[temp].firstfad>>16)&0xff; + finfbuf[2] = (curdir[temp].firstfad>>8)&0xff; + finfbuf[3] = (curdir[temp].firstfad&0xff); + // second 4 bytes = length of file + finfbuf[4] = (curdir[temp].length>>24)&0xff; + finfbuf[5] = (curdir[temp].length>>16)&0xff; + finfbuf[6] = (curdir[temp].length>>8)&0xff; + finfbuf[7] = (curdir[temp].length&0xff); + finfbuf[8] = curdir[temp].interleave_gap_size; + finfbuf[9] = curdir[temp].file_unit_size; + finfbuf[10] = temp; + finfbuf[11] = curdir[temp].flags; + + xfertype = XFERTYPE_FILEINFO_1; + xfercount = 0; + } + CDROM_LOG((" = %04x %04x %04x %04x %04x\n", hirqreg, cr1, cr2, cr3, cr4)) + status_type = 0; + break; + + case 0x74: // Read File + CDROM_LOG(("%s:CD: Read File\n", machine().describe_context())) + UINT16 file_offset,file_filter,file_id,file_size; + + file_offset = ((cr1 & 0xff)<<8)|(cr2 & 0xff); /* correct? */ + file_filter = cr3 >> 8; + file_id = ((cr3 & 0xff) << 16)|(cr4); + file_size = ((curdir[file_id].length + sectlenin - 1) / sectlenin) - file_offset; + + cd_stat = CD_STAT_PLAY|0x80; // set "cd-rom" bit + cd_curfad = (curdir[file_id].firstfad + file_offset); + fadstoplay = file_size; + if(file_filter < 0x24) + cddevice = &filters[file_filter]; + else + cddevice = (filterT *)NULL; + + printf("Read file %08x (%08x %08x) %02x %d\n",curdir[file_id].firstfad,cd_curfad,fadstoplay,file_filter,sectlenin); + + cr_standard_return(cd_stat); + + oddframe = 0; + in_buffer = 0; + + playtype = 1; + + hirqreg |= (CMOK|EHST); + status_type = 0; + break; + + case 0x75: + CDROM_LOG(("%s:CD: Abort File\n", machine().describe_context())) + // bios expects "2bc" mask to work against this + hirqreg |= (CMOK|EFLS); + sectorstore = 0; + xfertype32 = XFERTYPE32_INVALID; + xferdnum = 0; + if(((cd_stat & 0x0f00) != CD_STAT_NODISC) && ((cd_stat & 0x0f00) != CD_STAT_OPEN)) + cd_stat = CD_STAT_PAUSE; // force to pause + cr_standard_return(cd_stat); + status_type = 0; + break; + + case 0xe0: // appears to be copy protection check. needs only to return OK. + CDROM_LOG(("%s:CD: Verify copy protection\n", machine().describe_context())) + if(((cd_stat & 0x0f00) != CD_STAT_NODISC) && ((cd_stat & 0x0f00) != CD_STAT_OPEN)) + cd_stat = CD_STAT_PAUSE; +// cr1 = cd_stat; // necessary to pass +// cr2 = 0x4; +// hirqreg |= (CMOK|EFLS|CSCT); + sectorstore = 1; + hirqreg = 0xfc5; + cr_standard_return(cd_stat); + status_type = 0; + break; + + case 0xe1: // get disc region + CDROM_LOG(("%s:CD: Get disc region\n", machine().describe_context())) + if(cd_stat != CD_STAT_NODISC && cd_stat != CD_STAT_OPEN) + cd_stat = CD_STAT_PAUSE; + cr1 = cd_stat; // necessary to pass + cr2 = 0x4; // (must return this value to pass bios checks) + cr3 = 0; + cr4 = 0; + hirqreg |= (CMOK); +// cr_standard_return(cd_stat); + status_type = 0; + break; + + default: + CDROM_LOG(("CD: Unknown command %04x\n", cr1>>8)) + popmessage("CD Block unknown command %02x, contact MAMEdev",cr1>>8); + hirqreg |= (CMOK); + break; + } + + if(status_type == 1) + { + prev_cr1 = cr1; + prev_cr2 = cr2; + prev_cr3 = cr3; + prev_cr4 = cr4; + } +} + +TIMER_DEVICE_CALLBACK_MEMBER( saturn_state::stv_sh1_sim ) +{ + if((cmd_pending == 0xf) && (!(hirqreg & CMOK))) + cd_exec_command(); +} + +TIMER_DEVICE_CALLBACK_MEMBER( saturn_state::stv_sector_cb ) +{ + //sector_timer->reset(); + + //popmessage("%08x %08x %d %d",cd_curfad,fadstoplay,cmd_pending,cd_speed); + + cd_playdata(); + + if(cdrom_get_track_type(cdrom, cdrom_get_track(cdrom, cd_curfad)) == CD_TRACK_AUDIO) + sector_timer->adjust(attotime::from_hz(75)); // 75 sectors / second = 150kBytes/second (cdda track ignores cd_speed setting) + else + sector_timer->adjust(attotime::from_hz(75*cd_speed)); // 75 / 150 sectors / second = 150 / 300kBytes/second + + /* TODO: doesn't boot if a disk isn't in? */ + /* TODO: Check out when this really happens. (Daytona USA original version definitely wants it to be on).*/ + //if(((cd_stat & 0x0f00) != CD_STAT_NODISC) && ((cd_stat & 0x0f00) != CD_STAT_OPEN)) + hirqreg |= SCDQ; + + if(cd_stat & CD_STAT_PERI) + { + cr_standard_return(cd_stat); + } +} + +// global functions +void saturn_state::stvcd_reset( void ) +{ + INT32 i, j; + + hirqmask = 0xffff; + hirqreg = 0xffff; + cr1 = 'C'; + cr2 = ('D'<<8) | 'B'; + cr3 = ('L'<<8) | 'O'; + cr4 = ('C'<<8) | 'K'; + cd_stat = CD_STAT_PAUSE; + cd_stat |= CD_STAT_PERI; + cur_track = 0xff; + + curdir.clear(); + + xfertype = XFERTYPE_INVALID; + xfertype32 = XFERTYPE32_INVALID; + + // reset flag vars + buffull = sectorstore = 0; + + freeblocks = 200; + + sectlenin = sectlenout = 2048; + + lastbuf = 0xff; + + // reset buffer partitions + for (i = 0; i < MAX_FILTERS; i++) + { + partitions[i].size = -1; + partitions[i].numblks = 0; + + for (j = 0; j < MAX_BLOCKS; j++) + { + partitions[i].blocks[j] = (blockT *)NULL; + partitions[i].bnum[j] = 0xff; + } + } + + // reset blocks + for (i = 0; i < MAX_BLOCKS; i++) + { + blocks[i].size = -1; + memset(&blocks[i].data, 0, CD_MAX_SECTOR_DATA); + } + + // open device + if (cdrom) + { + cdrom_close(cdrom); + cdrom = (cdrom_file *)NULL; + } + + cdrom_image_device *cddevice = machine().device("cdrom"); + if (cddevice!=NULL) + { + // MESS case + cdrom = cddevice->get_cdrom_file(); + } + else + { + // MAME case + cdrom = cdrom_open(get_disk_handle(machine(), "cdrom")); + } + + machine().device("cdda")->set_cdrom(cdrom); + + if (cdrom) + { + CDROM_LOG(("Opened CD-ROM successfully, reading root directory\n")) + read_new_dir(0xffffff); // read root directory + } + else + { + cd_stat = CD_STAT_NODISC; + } + + cd_speed = 2; + cdda_repeat_count = 0; + tray_is_closed = 1; + + sector_timer = machine().device("sector_timer"); + sector_timer->adjust(attotime::from_hz(150)); // 150 sectors / second = 300kBytes/second + sh1_timer = machine().device("sh1_cmd"); +} + +saturn_state::blockT *saturn_state::cd_alloc_block(UINT8 *blknum) +{ + INT32 i; + + // search the 200 available blocks for a free one + for (i = 0; i < 200; i++) + { + if (blocks[i].size == -1) + { + freeblocks--; + if (freeblocks <= 0) + { + buffull = 1; + printf("buffull in cd_alloc_block\n"); + } + + blocks[i].size = sectlenin; + *blknum = i; + + CDROM_LOG(("CD: allocating block %d, size %x\n", i, sectlenin)) + + return &blocks[i]; + } + } + + buffull = 1; + return (blockT *)NULL; +} + +void saturn_state::cd_free_block(blockT *blktofree) +{ + INT32 i; + + CDROM_LOG(("cd_free_block: %x\n", (UINT32)(FPTR)blktofree)) + + if(blktofree == NULL) + { + return; + } + + for (i = 0; i < 200; i++) + { + if (&blocks[i] == blktofree) + { + CDROM_LOG(("CD: freeing block %d\n", i)) + } + } + + blktofree->size = -1; + freeblocks++; + buffull = 0; + hirqreg &= ~BFUL; +} + +void saturn_state::cd_getsectoroffsetnum(UINT32 bufnum, UINT32 *sectoffs, UINT32 *sectnum) +{ + if (*sectoffs == 0xffff) + { + // last sector + printf("CD: Don't know how to handle offset ffff\n"); + } + else if (*sectnum == 0xffff) + { + *sectnum = partitions[bufnum].numblks - *sectoffs; + } +} + +void saturn_state::cd_defragblocks(partitionT *part) +{ + UINT32 i, j; + blockT *temp; + UINT8 temp2; + + for (i = 0; i < (MAX_BLOCKS-1); i++) + { + for (j = i+1; j < MAX_BLOCKS; j++) + { + if ((part->blocks[i] == (blockT *)NULL) && (part->blocks[j] != (blockT *)NULL)) + { + temp = part->blocks[i]; + part->blocks[i] = part->blocks[j]; + part->blocks[j] = temp; + + temp2 = part->bnum[i]; + part->bnum[i] = part->bnum[j]; + part->bnum[j] = temp2; + } + } + } +} + +UINT16 saturn_state::cd_readWord(UINT32 addr) +{ + UINT16 rv; + + switch (addr & 0xffff) + { + case 0x0008: // read HIRQ register + case 0x000a: + case 0x8008: + case 0x800a: + rv = hirqreg; + + rv &= ~DCHG; // always clear bit 6 (tray open) + + if (buffull) rv |= BFUL; else rv &= ~BFUL; + if (sectorstore) rv |= CSCT; else rv &= ~CSCT; + + hirqreg = rv; + +// CDROM_LOG(("RW HIRQ: %04x\n", rv)) + + return rv; + + case 0x000c: + case 0x000e: + case 0x800c: + case 0x800e: +// CDROM_LOG(("RW HIRM: %04x\n", hirqmask)) + printf("RW HIRM: %04x\n", hirqmask); + return hirqmask; + + case 0x0018: + case 0x001a: + case 0x8018: + case 0x801a: +// CDROM_LOG(("RW CR1: %04x\n", cr1)) + return cr1; + + case 0x001c: + case 0x001e: + case 0x801c: + case 0x801e: +// CDROM_LOG(("RW CR2: %04x\n", cr2)) + return cr2; + + case 0x0020: + case 0x0022: + case 0x8020: + case 0x8022: +// CDROM_LOG(("RW CR3: %04x\n", cr3)) + return cr3; + + case 0x0024: + case 0x0026: + case 0x8024: + case 0x8026: +// CDROM_LOG(("RW CR4: %04x\n", cr4)) + //popmessage("%04x %04x %04x %04x",cr1,cr2,cr3,cr4); + cmd_pending = 0; + cd_stat |= CD_STAT_PERI; + return cr4; + + case 0x8000: + rv = 0xffff; + switch (xfertype) + { + case XFERTYPE_TOC: + rv = tocbuf[xfercount]<<8 | tocbuf[xfercount+1]; + + xfercount += 2; + xferdnum += 2; + + if (xfercount > 102*4) + { + xfercount = 0; + xfertype = XFERTYPE_INVALID; + } + break; + + case XFERTYPE_FILEINFO_1: + rv = finfbuf[xfercount]<<8 | finfbuf[xfercount+1]; + xfercount += 2; + xferdnum += 2; + + if (xfercount > 6*2) + { + xfercount = 0; + xfertype = XFERTYPE_INVALID; + } + break; + + case XFERTYPE_FILEINFO_254: // Lunar 2 + if((xfercount % (6 * 2)) == 0) + { + UINT32 temp = 2 + (xfercount / (0x6 * 2)); + + // first 4 bytes = FAD + finfbuf[0] = (curdir[temp].firstfad>>24)&0xff; + finfbuf[1] = (curdir[temp].firstfad>>16)&0xff; + finfbuf[2] = (curdir[temp].firstfad>>8)&0xff; + finfbuf[3] = (curdir[temp].firstfad&0xff); + // second 4 bytes = length of file + finfbuf[4] = (curdir[temp].length>>24)&0xff; + finfbuf[5] = (curdir[temp].length>>16)&0xff; + finfbuf[6] = (curdir[temp].length>>8)&0xff; + finfbuf[7] = (curdir[temp].length&0xff); + finfbuf[8] = curdir[temp].interleave_gap_size; + finfbuf[9] = curdir[temp].file_unit_size; + finfbuf[10] = temp; + finfbuf[11] = curdir[temp].flags; + } + + rv = finfbuf[xfercount % (6 * 2)]<<8 | finfbuf[(xfercount % (6 * 2)) +1]; + + xfercount += 2; + xferdnum += 2; + + if (xfercount > (254 * 6 * 2)) + { + xfercount = 0; + xfertype = XFERTYPE_INVALID; + } + break; + + case XFERTYPE_SUBQ: + rv = subqbuf[xfercount]<<8 | subqbuf[xfercount+1]; + + xfercount += 2; + xferdnum += 2; + + if (xfercount > 5*2) + { + xfercount = 0; + xfertype = XFERTYPE_INVALID; + } + break; + + + case XFERTYPE_SUBRW: + rv = subrwbuf[xfercount]<<8 | subrwbuf[xfercount+1]; + + xfercount += 2; + xferdnum += 2; + + if (xfercount > 12*2) + { + xfercount = 0; + xfertype = XFERTYPE_INVALID; + } + break; + + default: + printf("STVCD: Unhandled xfer type %d\n", (int)xfertype); + rv = 0; + break; + } + + return rv; + + default: + CDROM_LOG(("CD: RW %08x\n", addr)) + return 0xffff; + } + +} + +UINT32 saturn_state::cd_readLong(UINT32 addr) +{ + UINT32 rv = 0; + + switch (addr & 0xffff) + { + case 0x8000: + switch (xfertype32) + { + case XFERTYPE32_GETSECTOR: + case XFERTYPE32_GETDELETESECTOR: + // make sure we have sectors left + if (xfersect < xfersectnum) + { + // get next longword + rv = (transpart->blocks[xfersectpos+xfersect]->data[xferoffs + 0]<<24) | + (transpart->blocks[xfersectpos+xfersect]->data[xferoffs + 1]<<16) | + (transpart->blocks[xfersectpos+xfersect]->data[xferoffs + 2]<<8) | + (transpart->blocks[xfersectpos+xfersect]->data[xferoffs + 3]<<0); + + xferdnum += 4; + xferoffs += 4; + + // did we run out of sector? + if (xferoffs >= transpart->blocks[xfersect]->size) + { + CDROM_LOG(("CD: finished xfer of block %d of %d\n", xfersect+1, xfersectnum)) + + xferoffs = 0; + xfersect++; + } + } + else // sectors are done, kill 'em all if we can + { + if (xfertype32 == XFERTYPE32_GETDELETESECTOR) + { + INT32 i; + + CDROM_LOG(("Killing sectors in done\n")) + + // deallocate the blocks + for (i = xfersectpos; i < xfersectpos+xfersectnum; i++) + { + cd_free_block(transpart->blocks[i]); + transpart->blocks[i] = (blockT *)NULL; + transpart->bnum[i] = 0xff; + } + + // defrag what's left + cd_defragblocks(transpart); + + // clean up our state + transpart->size -= xferdnum; + transpart->numblks -= xfersectnum; + + /* TODO: is this correct? */ + xfertype32 = XFERTYPE32_INVALID; + } + } + break; + + default: + printf("CD: unhandled 32-bit transfer type\n"); + break; + } + + return rv; + + default: + CDROM_LOG(("CD: RL %08x\n", addr)) + return 0xffff; + } +} + +void saturn_state::cd_writeLong(UINT32 addr, UINT32 data) +{ + switch (addr & 0xffff) + { + case 0x8000: + switch (xfertype32) + { + case XFERTYPE32_PUTSECTOR: + // make sure we have sectors left + if (xfersect < xfersectnum) + { + // get next longword + transpart->blocks[xfersectpos+xfersect]->data[xferoffs + 0] = (data >> 24) & 0xff; + transpart->blocks[xfersectpos+xfersect]->data[xferoffs + 1] = (data >> 16) & 0xff; + transpart->blocks[xfersectpos+xfersect]->data[xferoffs + 2] = (data >> 8) & 0xff; + transpart->blocks[xfersectpos+xfersect]->data[xferoffs + 3] = (data >> 0) & 0xff; + + xferdnum += 4; + xferoffs += 4; + + // did we run out of sector? + if (xferoffs >= transpart->blocks[xfersectpos+xfersect]->size) + { + CDROM_LOG(("CD: finished xfer of block %d of %d\n", xfersect+1, xfersectnum)) + + xferoffs = 0; + xfersect++; + } + } + else // sectors are done + { + /* Virtual On doesnt want this to be resetted. */ + //xfertype32 = XFERTYPE32_INVALID; + } + break; + + default: + printf("CD: unhandled 32-bit transfer type write\n"); + break; + } + break; + + default: + break; + } +} + +void saturn_state::cd_writeWord(UINT32 addr, UINT16 data) +{ + switch(addr & 0xffff) + { + case 0x0008: + case 0x000a: + case 0x8008: + case 0x800a: +// CDROM_LOG(("%s:WW HIRQ: %04x & %04x => %04x\n", machine().describe_context(), hirqreg, data, hirqreg & data)) + hirqreg &= data; + return; + case 0x000c: + case 0x000e: + case 0x800c: + case 0x800e: +// CDROM_LOG(("WW HIRM: %04x => %04x\n", hirqmask, data)) + printf("WW HIRM: %04x => %04x\n", hirqmask, data); + hirqmask = data; + return; + case 0x0018: + case 0x001a: + case 0x8018: + case 0x801a: +// CDROM_LOG(("WW CR1: %04x\n", data)) + cr1 = data; + cd_stat &= ~CD_STAT_PERI; + cmd_pending |= 1; + sh1_timer->adjust(attotime::never); + break; + case 0x001c: + case 0x001e: + case 0x801c: + case 0x801e: +// CDROM_LOG(("WW CR2: %04x\n", data)) + cr2 = data; + cmd_pending |= 2; + break; + case 0x0020: + case 0x0022: + case 0x8020: + case 0x8022: +// CDROM_LOG(("WW CR3: %04x\n", data)) + cr3 = data; + cmd_pending |= 4; + break; + case 0x0024: + case 0x0026: + case 0x8024: + case 0x8026: +// CDROM_LOG(("WW CR4: %04x\n", data)) + cr4 = data; + cmd_pending |= 8; + sh1_timer->adjust(attotime::from_hz(get_timing_command())); + break; + default: + CDROM_LOG(("CD: WW %08x %04x\n", addr, data)) + break; + } +} + +READ32_MEMBER( saturn_state::stvcd_r ) +{ + UINT32 rv = 0; + + offset <<= 2; + + switch (offset) + { + case 0x88008: + case 0x8800a: + case 0x8800c: + case 0x8800e: + case 0x88018: + case 0x8801a: + case 0x8801c: + case 0x8801e: + case 0x88020: + case 0x88022: + case 0x88024: + case 0x88026: + case 0x90008: + case 0x9000a: + case 0x9000c: + case 0x9000e: + case 0x90018: + case 0x9001a: + case 0x9001c: + case 0x9001e: + case 0x90020: + case 0x90022: + case 0x90024: + case 0x90026: + rv = cd_readWord(offset); + return rv<<16; + + case 0x98000: + case 0x18000: + if (mem_mask == 0xffffffff) + { + rv = cd_readLong(offset); + } + else if (mem_mask == 0xffff0000) + { + rv = cd_readWord(offset)<<16; + } + else if (mem_mask == 0x0000ffff) + { + rv = cd_readWord(offset); + } + else + { + osd_printf_error("CD: Unknown data buffer read @ mask = %08x\n", mem_mask); + } + + break; + + default: + printf("Unknown CD read %x\n", offset); + break; + } + + return rv; +} + +WRITE32_MEMBER( saturn_state::stvcd_w ) +{ + offset <<= 2; + + switch (offset) + { + case 0x18000: + if (mem_mask == 0xffffffff) + cd_writeLong(offset, data); + else + printf("CD: Unknown data buffer write @ mask = %08x\n", mem_mask); + break; + + case 0x88008: + case 0x8800a: + case 0x8800c: + case 0x8800e: + case 0x88018: + case 0x8801a: + case 0x8801c: + case 0x8801e: + case 0x88020: + case 0x88022: + case 0x88024: + case 0x88026: + case 0x90008: + case 0x9000a: + case 0x9000c: + case 0x9000e: + case 0x90018: + case 0x9001a: + case 0x9001c: + case 0x9001e: + case 0x90020: + case 0x90022: + case 0x90024: + case 0x90026: + cd_writeWord(offset, data>>16); + break; + + default: + printf("Unknown CD write %x @ %x\n", data, offset); + //xferdnum = 0x8c00; + break; + } +} + +// iso9660 parsing +void saturn_state::read_new_dir(UINT32 fileno) +{ + int foundpd, i; + UINT32 cfad;//, dirfad; + UINT8 sect[2048]; + + if (fileno == 0xffffff) + { + cfad = 166; // first sector of directory as per iso9660 specs + + foundpd = 0; // search for primary vol. desc + while ((!foundpd) && (cfad < 200)) + { + if(sectlenin != 2048) + popmessage("Sector Length %d, contact MAMEdev (0)",sectlenin); + + memset(sect, 0, 2048); + cd_readblock(cfad++, sect); + + if ((sect[1] == 'C') && (sect[2] == 'D') && (sect[3] == '0') && (sect[4] == '0') && (sect[5] == '1')) + { + switch (sect[0]) + { + case 0: // boot record + break; + + case 1: // primary vol. desc + foundpd = 1; + break; + + case 2: // secondary vol desc + break; + + case 3: // vol. section descriptor + break; + + case 0xff: + cfad = 200; + break; + } + } + } + + // got primary vol. desc. + if (foundpd) + { + //dirfad = sect[140] | (sect[141]<<8) | (sect[142]<<16) | (sect[143]<<24); + //dirfad += 150; + + // parse root entry + curroot.firstfad = sect[158] | (sect[159]<<8) | (sect[160]<<16) | (sect[161]<<24); + curroot.firstfad += 150; + curroot.length = sect[166] | (sect[167]<<8) | (sect[168]<<16) | (sect[169]<<24); + curroot.flags = sect[181]; + for (i = 0; i < sect[188]; i++) + { + curroot.name[i] = sect[189+i]; + } + curroot.name[i] = '\0'; // terminate + + // easy to fix, but make sure we *need* to first + if (curroot.length > MAX_DIR_SIZE) + { + osd_printf_error("ERROR: root directory too big (%d)\n", curroot.length); + } + + // done with all that, read the root directory now + make_dir_current(curroot.firstfad); + } + } + else + { + if (curdir[fileno].length > MAX_DIR_SIZE) + { + osd_printf_error("ERROR: new directory too big (%d)!\n", curdir[fileno].length); + } + make_dir_current(curdir[fileno].firstfad); + } +} + +// makes the directory pointed to by FAD current +void saturn_state::make_dir_current(UINT32 fad) +{ + int i; + UINT32 nextent, numentries; + dynamic_buffer sect(MAX_DIR_SIZE); + direntryT *curentry; + + memset(§[0], 0, MAX_DIR_SIZE); + if(sectlenin != 2048) + popmessage("Sector Length %d, contact MAMEdev (1)",sectlenin); + + for (i = 0; i < (curroot.length/2048); i++) + { + cd_readblock(fad+i, §[2048*i]); + } + + nextent = 0; + numentries = 0; + while (nextent < MAX_DIR_SIZE) + { + if (sect[nextent]) + { + nextent += sect[nextent]; + numentries++; + } + else + { + nextent = MAX_DIR_SIZE; + } + } + + curdir.resize(numentries); + curentry = &curdir[0]; + numfiles = numentries; + + nextent = 0; + while (numentries) + { + // [0] record size + // [1] xa record size + // [2-5] lba + // [6-9] (lba?) + // [10-13] size + // [14-17] (size?) + // [18] year + // [19] month + // [20] day + // [21] hour + // [22] minute + // [23] second + // [24] gmt offset + // [25] flags + // [26] file unit size + // [27] interleave gap size + // [28-29] volume sequencer number + // [30-31] (volume sequencer number?) + // [32] name character size + // [33+ ...] file name + + curentry->record_size = sect[nextent+0]; + curentry->xa_record_size = sect[nextent+1]; + curentry->firstfad = sect[nextent+2] | (sect[nextent+3]<<8) | (sect[nextent+4]<<16) | (sect[nextent+5]<<24); + curentry->firstfad += 150; + curentry->length = sect[nextent+10] | (sect[nextent+11]<<8) | (sect[nextent+12]<<16) | (sect[nextent+13]<<24); + curentry->year = sect[nextent+18]; + curentry->month = sect[nextent+19]; + curentry->day = sect[nextent+20]; + curentry->hour = sect[nextent+21]; + curentry->minute = sect[nextent+22]; + curentry->second = sect[nextent+23]; + curentry->gmt_offset = sect[nextent+24]; + curentry->flags = sect[nextent+25]; + curentry->file_unit_size = sect[nextent+26]; + curentry->interleave_gap_size = sect[nextent+27]; + curentry->volume_sequencer_number = sect[nextent+28] | (sect[nextent+29] << 8); + + for (i = 0; i < sect[nextent+32]; i++) + { + curentry->name[i] = sect[nextent+33+i]; + } + curentry->name[i] = '\0'; // terminate + //printf("%08x %08x %s %d/%d/%d\n",curentry->firstfad,curentry->length,curentry->name,curentry->year,curentry->month,curentry->day); + + nextent += sect[nextent]; + curentry++; + numentries--; + } + + for (i = 0; i < numfiles; i++) + { + if (!(curdir[i].flags & 0x02)) + { + firstfile = i; + i = numfiles; + } + } +} + +void saturn_state::stvcd_exit( void ) +{ + curdir.clear(); + + if (cdrom) + { + cdrom_image_device *cddevice = machine().device("cdrom"); + if (cddevice==NULL) + { + cdrom_close(cdrom); + } + cdrom = (cdrom_file *)NULL; + } +} + +void saturn_state::cd_readTOC(void) +{ + int i, ntrks, tocptr, fad; + + xfertype = XFERTYPE_TOC; + xfercount = 0; + + if (cdrom) + { + ntrks = cdrom_get_last_track(cdrom); + } + else + { + ntrks = 0; + } + + // data format for Saturn TOC: + // no header. + // 4 bytes per track + // top nibble of first byte is CTRL info + // low nibble is ADR + // next 3 bytes are FAD address (LBA + 150) + // there are always 99 track entries (0-98) + // unused tracks are ffffffff. + // entries 99-101 are metadata + + tocptr = 0; // starting point of toc entries + + for (i = 0; i < ntrks; i++) + { + if (cdrom) + { + //tocbuf[tocptr] = sega_cdrom_get_adr_control(cdrom, i); + //HACK: ddsom does not enter ingame with the line above! + tocbuf[tocptr] = cdrom_get_adr_control(cdrom, i)<<4 | 0x01; + } + else + { + tocbuf[tocptr] = 0xff; + } + + if (cdrom) + { + fad = cdrom_get_track_start(cdrom, i) + 150; + + tocbuf[tocptr+1] = (fad>>16)&0xff; + tocbuf[tocptr+2] = (fad>>8)&0xff; + tocbuf[tocptr+3] = fad&0xff; + } + else + { + tocbuf[tocptr+1] = 0xff; + tocbuf[tocptr+2] = 0xff; + tocbuf[tocptr+3] = 0xff; + } + + tocptr += 4; + } + + // fill in the rest + for ( ; i < 99; i++) + { + tocbuf[tocptr] = 0xff; + tocbuf[tocptr+1] = 0xff; + tocbuf[tocptr+2] = 0xff; + tocbuf[tocptr+3] = 0xff; + + tocptr += 4; + } + + // tracks 99-101 are special metadata + // $$$FIXME: what to do with the address info for these? + tocptr = 99 * 4; + tocbuf[tocptr] = tocbuf[0]; // get ctrl/adr from first track + tocbuf[tocptr+1] = 1; // first track's track # + tocbuf[tocptr+2] = 0; + tocbuf[tocptr+3] = 0; + + tocbuf[tocptr+4] = tocbuf[(ntrks-1)*4]; // ditto for last track + tocbuf[tocptr+5] = ntrks; // last track's track # + tocbuf[tocptr+6] = 0; + tocbuf[tocptr+7] = 0; + + // get total disc length (start of lead-out) + fad = cdrom_get_track_start(cdrom, 0xaa) + 150; + + tocbuf[tocptr+8] = tocbuf[0]; + tocbuf[tocptr+9] = (fad>>16)&0xff; + tocbuf[tocptr+10] = (fad>>8)&0xff; + tocbuf[tocptr+11] = fad&0xff; +} + +saturn_state::partitionT *saturn_state::cd_filterdata(filterT *flt, int trktype, UINT8 *p_ok) +{ + int match, keepgoing; + partitionT *filterprt = (partitionT *)NULL; + + CDROM_LOG(("cd_filterdata, trktype %d\n", trktype)) + match = 1; + keepgoing = 2; + lastbuf = flt->condtrue; + + // loop on the filters + do + { + // FAD range check? + /* according to an obscure document note, this switches the filter connector to be false if the range fails ... I think ... */ + if (flt->mode & 0x40) + { + if ((cd_curfad < flt->fad) || (cd_curfad > (flt->fad + flt->range))) + { + printf("curfad reject %08x %08x %08x %08x\n",cd_curfad,fadstoplay,flt->fad,flt->fad+flt->range); + match = 0; + //lastbuf = flt->condfalse; + //flt = &filters[lastbuf]; + } + } + + if ((trktype != CD_TRACK_AUDIO) && (curblock.data[15] == 2)) + { + if (flt->mode & 1) // file number + { + if (curblock.fnum != flt->fid) + { + printf("fnum reject\n"); + match = 0; + } + } + + if (flt->mode & 2) // channel number + { + if (curblock.chan != flt->chan) + { + printf("channel number reject\n"); + match = 0; + } + } + + if (flt->mode & 4) // sub mode + { + if((curblock.subm & flt->smmask) != flt->smval) + { + printf("sub mode reject\n"); + match = 0; + } + } + + if (flt->mode & 8) // coding information + { + if((curblock.cinf & flt->cimask) != flt->cival) + { + printf("coding information reject\n"); + match = 0; + } + } + + if (flt->mode & 0x10) // reverse subheader conditions + { + match ^= 1; + } + } + + if (match) + { + //lastbuf = flt->condtrue; + //filterprt = &partitions[lastbuf]; + // we're done + keepgoing = 0; + } + else + { + lastbuf = flt->condfalse; + + // reject sector if no match on either connector + if ((lastbuf == 0xff) || (keepgoing == 0)) + { + *p_ok = 0; + return (partitionT *)NULL; + } + + // try again using the filter that was on the "false" connector + flt = &filters[lastbuf]; + match = 1; + + // and exit if we fail + keepgoing--; + } + } while (keepgoing); + + filterprt = &partitions[lastbuf]; + + // try to allocate a block + filterprt->blocks[filterprt->numblks] = cd_alloc_block(&filterprt->bnum[filterprt->numblks]); + + // did the allocation succeed? + if (filterprt->blocks[filterprt->numblks] == (blockT *)NULL) + { + *p_ok = 0; + return (partitionT *)NULL; + } + + // copy working block to the newly allocated one + memcpy(filterprt->blocks[filterprt->numblks], &curblock, sizeof(blockT)); + + // and massage the data format a bit + switch (curblock.size) + { + case 2048: // user data + if (curblock.data[15] == 2) + { + // mode 2 + memcpy(&filterprt->blocks[filterprt->numblks]->data[0], &curblock.data[24], curblock.size); + } + else + { + // mode 1 + memcpy(&filterprt->blocks[filterprt->numblks]->data[0], &curblock.data[16], curblock.size); + } + break; + + case 2324: // Mode 2 Form 2 data + memcpy(&filterprt->blocks[filterprt->numblks]->data[0], &curblock.data[24], curblock.size); + break; + + case 2336: // Mode 2 Form 2 skip sync/header + memcpy(&filterprt->blocks[filterprt->numblks]->data[0], &curblock.data[16], curblock.size); + break; + + case 2340: // Mode 2 Form 2 skip sync only + memcpy(&filterprt->blocks[filterprt->numblks]->data[0], &curblock.data[12], curblock.size); + break; + + case 2352: // want all data, it's already done, so don't do it again :) + break; + } + + // update the status of the partition + if (filterprt->size == -1) + filterprt->size = 0; + + filterprt->size += filterprt->blocks[filterprt->numblks]->size; + filterprt->numblks++; + + *p_ok = 1; + return filterprt; +} + +// read a single sector off the CD, applying the current filter(s) as necessary +saturn_state::partitionT *saturn_state::cd_read_filtered_sector(INT32 fad, UINT8 *p_ok) +{ + int trktype; + + if ((cddevice != NULL) && (!buffull)) + { + // find out the track's type + trktype = cdrom_get_track_type(cdrom, cdrom_get_track(cdrom, fad-150)); + + // now get a raw 2352 byte sector - if it's mode 1, get mode1_raw + if ((trktype == CD_TRACK_MODE1) || (trktype == CD_TRACK_MODE1_RAW)) + { + cdrom_read_data(cdrom, fad-150, curblock.data, CD_TRACK_MODE1_RAW); + } + else if (trktype != CD_TRACK_AUDIO) // if not audio it must be mode 2 so get mode2_raw + { + cdrom_read_data(cdrom, fad-150, curblock.data, CD_TRACK_MODE2_RAW); + } + else + { + cdrom_read_data(cdrom, fad-150, curblock.data, CD_TRACK_AUDIO); + } + + curblock.size = sectlenin; + curblock.FAD = fad; + + // if track is Mode 2, get the subheader values + if ((trktype != CD_TRACK_AUDIO) && (curblock.data[15] == 2)) + { + curblock.chan = curblock.data[17]; + curblock.fnum = curblock.data[16]; + curblock.subm = curblock.data[18]; + curblock.cinf = curblock.data[19]; + + // if it's Form 2, the length is actually 2324 bytes + if (curblock.subm & 0x20) + { + curblock.size = 2324; + } + } + + return cd_filterdata(cddevice, trktype, &*p_ok); + } + + *p_ok = 0; + return (partitionT *)NULL; +} + +// loads in data set up by a CD-block PLAY command +void saturn_state::cd_playdata( void ) +{ + if ((cd_stat & 0x0f00) == CD_STAT_SEEK) + { + INT32 fad_diff; + //printf("PRE %08x %08x %08x %d\n",cd_curfad,cd_fad_seek,cd_stat,cd_fad_seek - cd_curfad); + + fad_diff = (cd_fad_seek - cd_curfad); + + /* Zero Divide wants this TODO: timings. */ + if(fad_diff > (750*cd_speed)) + { + //printf("PRE FFWD %08x %08x %08x %d %d\n",cd_curfad,cd_fad_seek,cd_stat,cd_fad_seek - cd_curfad,750*cd_speed); + cd_curfad += (750*cd_speed); + //printf("POST FFWD %08x %08x %08x %d %d\n",cd_curfad,cd_fad_seek,cd_stat,cd_fad_seek - cd_curfad, 750*cd_speed); + } + else if(fad_diff < (-750*cd_speed)) + { + //printf("PRE REW %08x %08x %08x %d %d\n",cd_curfad,cd_fad_seek,cd_stat,cd_fad_seek - cd_curfad, -750*cd_speed); + cd_curfad -= (750*cd_speed); + //printf("POST REW %08x %08x %08x %d %d\n",cd_curfad,cd_fad_seek,cd_stat,cd_fad_seek - cd_curfad, -750*cd_speed); + } + else + { + //printf("Ready\n"); + cd_curfad = cd_fad_seek; + cd_stat = CD_STAT_PLAY; + } + + return; + } + + if ((cd_stat & 0x0f00) == CD_STAT_PLAY) + { + if (fadstoplay) + { + logerror("STVCD: Reading FAD %d\n", cd_curfad); + + if (cdrom) + { + UINT8 p_ok; + + if(cdrom_get_track_type(cdrom, cdrom_get_track(cdrom, cd_curfad)) != CD_TRACK_AUDIO) + { + cd_read_filtered_sector(cd_curfad,&p_ok); + machine().device("cdda")->stop_audio(); //stop any pending CD-DA + } + else + { + p_ok = 1; // TODO + machine().device("cdda")->start_audio(cd_curfad, 1); + } + + if(p_ok) + { + cd_curfad++; + fadstoplay--; + hirqreg |= CSCT; + sectorstore = 1; + + if (!fadstoplay) + { + if(cdda_repeat_count >= cdda_maxrepeat) + { + CDROM_LOG(("cd_playdata: playback ended\n")) + cd_stat = CD_STAT_PAUSE; + + hirqreg |= PEND; + + if (playtype == 1) + { + CDROM_LOG(("cd_playdata: setting EFLS\n")) + hirqreg |= EFLS; + } + } + else + { + if(cdda_repeat_count < 0xe) + cdda_repeat_count++; + + cd_curfad = cdrom_get_track_start(cdrom, cur_track-1) + 150; + fadstoplay = cdrom_get_track_start(cdrom, cur_track) - cd_curfad; + } + } + } + } + } + } +} + +// loads a single sector off the CD, anywhere from FAD 150 on up +void saturn_state::cd_readblock(UINT32 fad, UINT8 *dat) +{ + if (cdrom) + { + cdrom_read_data(cdrom, fad-150, dat, CD_TRACK_MODE1); + } +} + +void saturn_state::stvcd_set_tray_open( void ) +{ + if(!tray_is_closed) + return; + + hirqreg |= DCHG; + cd_stat = CD_STAT_OPEN; + + cdrom = (cdrom_file *)NULL; + tray_is_closed = 0; + + popmessage("Tray Open"); +} + +void saturn_state::stvcd_set_tray_close( void ) +{ + /* avoid user attempts to load a CD-ROM without opening the tray first (emulation asserts anyway with current framework) */ + if(tray_is_closed) + return; + + hirqreg |= DCHG; + + cdrom_image_device *cddevice = machine().device("cdrom"); + if (cddevice!=NULL) + { + // MESS case + cdrom = cddevice->get_cdrom_file(); + } + else + { + // MAME case + cdrom = cdrom_open(get_disk_handle(machine(), "cdrom")); + } + + machine().device("cdda")->set_cdrom(cdrom); + + if (cdrom) + { + CDROM_LOG(("Opened CD-ROM successfully, reading root directory\n")) + //read_new_dir(0xffffff); // read root directory + cd_stat = CD_STAT_PAUSE; + } + else + { + cd_stat = CD_STAT_NODISC; + } + + cd_speed = 2; + cdda_repeat_count = 0; + tray_is_closed = 1; + + popmessage("Tray Close"); +} diff --git a/src/devices/machine/t10mmc.c b/src/devices/machine/t10mmc.c new file mode 100644 index 00000000000..86e3ec696ed --- /dev/null +++ b/src/devices/machine/t10mmc.c @@ -0,0 +1,765 @@ +// license:BSD-3-Clause +// copyright-holders:smf +#include "t10mmc.h" + +static int to_msf(int frame) +{ + int m = frame / (75 * 60); + int s = (frame / 75) % 60; + int f = frame % 75; + + return (m << 16) | (s << 8) | f; +} + +void t10mmc::t10_start(device_t &device) +{ + t10spc::t10_start(device); + + device.save_item(NAME(m_lba)); + device.save_item(NAME(m_blocks)); + device.save_item(NAME(m_last_lba)); + device.save_item(NAME(m_num_subblocks)); + device.save_item(NAME(m_cur_subblock)); + device.save_item(NAME(m_audio_sense)); +} + +void t10mmc::t10_reset() +{ + t10spc::t10_reset(); + + SetDevice( m_image->get_cdrom_file() ); + if( !m_cdrom ) + { + logerror( "T10MMC %s: no CD found!\n", m_image->tag() ); + } + + m_lba = 0; + m_blocks = 0; + m_last_lba = 0; + m_sector_bytes = 2048; + m_num_subblocks = 1; + m_cur_subblock = 0; + m_audio_sense = 0; +} + +// scsicd_exec_command + +void t10mmc::abort_audio() +{ + if (m_cdda->audio_active()) + { + m_cdda->stop_audio(); + m_audio_sense = SCSI_SENSE_ASC_ASCQ_AUDIO_PLAY_OPERATION_STOPPED_DUE_TO_ERROR; + } +} + +t10mmc::toc_format_t t10mmc::toc_format() +{ + int mmc_format = command[2] & 0xf; + if (mmc_format != 0) + { + return (toc_format_t) mmc_format; + } + + /// SFF8020 legacy format field (see T10/1836-D Revision 2g page 643) + return (toc_format_t) ((command[9] >> 6) & 3); +} + +int t10mmc::toc_tracks() +{ + int start_track = command[6]; + int end_track = cdrom_get_last_track(m_cdrom); + + if (start_track == 0) + { + return end_track + 1; + } + else if (start_track <= end_track) + { + return ( end_track - start_track ) + 2; + } + else if (start_track <= 0xaa) + { + return 1; + } + + return 0; +} + +// +// Execute a SCSI command. + +void t10mmc::ExecCommand() +{ + int trk; + + // keep updating the sense data while playing audio. + if (command[0] == T10SPC_CMD_REQUEST_SENSE && m_audio_sense != SCSI_SENSE_ASC_ASCQ_NO_SENSE && m_sense_key == SCSI_SENSE_KEY_NO_SENSE && m_sense_asc == 0 && m_sense_ascq == 0) + { + if (m_audio_sense == SCSI_SENSE_ASC_ASCQ_AUDIO_PLAY_OPERATION_IN_PROGRESS && !m_cdda->audio_active()) + { + m_audio_sense = SCSI_SENSE_ASC_ASCQ_AUDIO_PLAY_OPERATION_SUCCESSFULLY_COMPLETED; + } + + set_sense(SCSI_SENSE_KEY_NO_SENSE, (sense_asc_ascq_t) m_audio_sense); + + if (m_audio_sense != SCSI_SENSE_ASC_ASCQ_AUDIO_PLAY_OPERATION_IN_PROGRESS) + { + m_audio_sense = SCSI_SENSE_ASC_ASCQ_NO_SENSE; + } + } + + switch ( command[0] ) + { + case T10SPC_CMD_INQUIRY: + logerror("T10MMC: INQUIRY\n"); + m_phase = SCSI_PHASE_DATAIN; + m_status_code = SCSI_STATUS_CODE_GOOD; + m_transfer_length = SCSILengthFromUINT8( &command[ 4 ] ); + if (m_transfer_length > 36) + m_transfer_length = 36; + break; + + case T10SPC_CMD_MODE_SELECT_6: + logerror("T10MMC: MODE SELECT(6) length %x control %x\n", command[4], command[5]); + m_phase = SCSI_PHASE_DATAOUT; + m_status_code = SCSI_STATUS_CODE_GOOD; + m_transfer_length = SCSILengthFromUINT8( &command[ 4 ] ); + break; + + case T10SPC_CMD_MODE_SENSE_6: + m_phase = SCSI_PHASE_DATAIN; + m_status_code = SCSI_STATUS_CODE_GOOD; + m_transfer_length = SCSILengthFromUINT8( &command[ 4 ] ); + break; + + case T10SPC_CMD_START_STOP_UNIT: + abort_audio(); + m_phase = SCSI_PHASE_STATUS; + m_status_code = SCSI_STATUS_CODE_GOOD; + m_transfer_length = 0; + break; + + case T10SPC_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL: + m_phase = SCSI_PHASE_STATUS; + m_status_code = SCSI_STATUS_CODE_GOOD; + m_transfer_length = 0; + break; + + case T10SBC_CMD_READ_CAPACITY: + m_phase = SCSI_PHASE_DATAIN; + m_status_code = SCSI_STATUS_CODE_GOOD; + m_transfer_length = 8; + break; + + case T10SBC_CMD_READ_10: + m_lba = command[2]<<24 | command[3]<<16 | command[4]<<8 | command[5]; + m_blocks = SCSILengthFromUINT16( &command[7] ); + + logerror("T10MMC: READ(10) at LBA %x for %d blocks (%d bytes)\n", m_lba, m_blocks, m_blocks * m_sector_bytes); + + if (m_num_subblocks > 1) + { + m_cur_subblock = m_lba % m_num_subblocks; + m_lba /= m_num_subblocks; + } + else + { + m_cur_subblock = 0; + } + + abort_audio(); + + m_phase = SCSI_PHASE_DATAIN; + m_status_code = SCSI_STATUS_CODE_GOOD; + m_transfer_length = m_blocks * m_sector_bytes; + break; + + case T10MMC_CMD_READ_SUB_CHANNEL: + //logerror("T10MMC: READ SUB-CHANNEL type %d\n", command[3]); + m_phase = SCSI_PHASE_DATAIN; + m_status_code = SCSI_STATUS_CODE_GOOD; + m_transfer_length = SCSILengthFromUINT16( &command[ 7 ] ); + break; + + case T10MMC_CMD_READ_TOC_PMA_ATIP: + { + int length; + + switch (toc_format()) + { + case TOC_FORMAT_TRACKS: + length = 4 + (8 * toc_tracks()); + break; + + case TOC_FORMAT_SESSIONS: + length = 4 + (8 * 1); + break; + + default: + logerror("T10MMC: Unhandled READ TOC format %d\n", toc_format()); + length = 0; + break; + } + + int allocation_length = SCSILengthFromUINT16( &command[ 7 ] ); + + if( length > allocation_length ) + { + length = allocation_length; + } + + abort_audio(); + + m_phase = SCSI_PHASE_DATAIN; + m_status_code = SCSI_STATUS_CODE_GOOD; + m_transfer_length = length; + break; + } + case T10MMC_CMD_PLAY_AUDIO_10: + m_lba = command[2]<<24 | command[3]<<16 | command[4]<<8 | command[5]; + m_blocks = SCSILengthFromUINT16( &command[7] ); + + // special cases: lba of 0 means MSF of 00:02:00 + if (m_lba == 0) + { + m_lba = 150; + } + else if (m_lba == 0xffffffff) + { + logerror("T10MMC: play audio from current not implemented!\n"); + } + + logerror("T10MMC: PLAY AUDIO(10) at LBA %x for %x blocks\n", m_lba, m_blocks); + + trk = cdrom_get_track(m_cdrom, m_lba); + + if (cdrom_get_track_type(m_cdrom, trk) == CD_TRACK_AUDIO) + { + m_cdda->start_audio(m_lba, m_blocks); + m_audio_sense = SCSI_SENSE_ASC_ASCQ_AUDIO_PLAY_OPERATION_IN_PROGRESS; + } + else + { + logerror("T10MMC: track is NOT audio!\n"); + set_sense(SCSI_SENSE_KEY_ILLEGAL_REQUEST, SCSI_SENSE_ASC_ASCQ_ILLEGAL_MODE_FOR_THIS_TRACK); + } + + m_phase = SCSI_PHASE_STATUS; + m_status_code = SCSI_STATUS_CODE_GOOD; + m_transfer_length = 0; + break; + + case T10MMC_CMD_PLAY_AUDIO_TRACK_INDEX: + // be careful: tracks here are zero-based, but the SCSI command + // uses the real CD track number which is 1-based! + logerror("T10MMC: PLAY AUDIO T/I: strk %d idx %d etrk %d idx %d frames %d\n", command[4], command[5], command[7], command[8], m_blocks); + m_lba = cdrom_get_track_start(m_cdrom, command[4]-1); + m_blocks = cdrom_get_track_start(m_cdrom, command[7]-1) - m_lba; + if (command[4] > command[7]) + { + m_blocks = 0; + } + + if (command[4] == command[7]) + { + m_blocks = cdrom_get_track_start(m_cdrom, command[4]) - m_lba; + } + + trk = cdrom_get_track(m_cdrom, m_lba); + + if (cdrom_get_track_type(m_cdrom, trk) == CD_TRACK_AUDIO) + { + m_cdda->start_audio(m_lba, m_blocks); + m_audio_sense = SCSI_SENSE_ASC_ASCQ_AUDIO_PLAY_OPERATION_IN_PROGRESS; + } + else + { + logerror("T10MMC: track is NOT audio!\n"); + set_sense(SCSI_SENSE_KEY_ILLEGAL_REQUEST, SCSI_SENSE_ASC_ASCQ_ILLEGAL_MODE_FOR_THIS_TRACK); + } + + m_phase = SCSI_PHASE_STATUS; + m_status_code = SCSI_STATUS_CODE_GOOD; + m_transfer_length = 0; + break; + + case T10MMC_CMD_PAUSE_RESUME: + if (m_cdrom) + { + m_cdda->pause_audio((command[8] & 0x01) ^ 0x01); + } + + logerror("T10MMC: PAUSE/RESUME: %s\n", command[8]&1 ? "RESUME" : "PAUSE"); + m_phase = SCSI_PHASE_STATUS; + m_status_code = SCSI_STATUS_CODE_GOOD; + m_transfer_length = 0; + break; + + case T10MMC_CMD_STOP_PLAY_SCAN: + abort_audio(); + + logerror("T10MMC: STOP_PLAY_SCAN\n"); + m_phase = SCSI_PHASE_STATUS; + m_status_code = SCSI_STATUS_CODE_GOOD; + m_transfer_length = 0; + break; + + case T10SPC_CMD_MODE_SELECT_10: + logerror("T10MMC: MODE SELECT length %x control %x\n", command[7]<<8 | command[8], command[1]); + m_phase = SCSI_PHASE_DATAOUT; + m_status_code = SCSI_STATUS_CODE_GOOD; + m_transfer_length = SCSILengthFromUINT16( &command[ 7 ] ); + break; + + case T10SPC_CMD_MODE_SENSE_10: + m_phase = SCSI_PHASE_DATAIN; + m_status_code = SCSI_STATUS_CODE_GOOD; + m_transfer_length = SCSILengthFromUINT16( &command[ 7 ] ); + break; + + case T10MMC_CMD_PLAY_AUDIO_12: + m_lba = command[2]<<24 | command[3]<<16 | command[4]<<8 | command[5]; + m_blocks = command[6]<<24 | command[7]<<16 | command[8]<<8 | command[9]; + + // special cases: lba of 0 means MSF of 00:02:00 + if (m_lba == 0) + { + m_lba = 150; + } + else if (m_lba == 0xffffffff) + { + logerror("T10MMC: play audio from current not implemented!\n"); + } + + logerror("T10MMC: PLAY AUDIO(12) at LBA %x for %x blocks\n", m_lba, m_blocks); + + trk = cdrom_get_track(m_cdrom, m_lba); + + if (cdrom_get_track_type(m_cdrom, trk) == CD_TRACK_AUDIO) + { + m_cdda->start_audio(m_lba, m_blocks); + m_audio_sense = SCSI_SENSE_ASC_ASCQ_AUDIO_PLAY_OPERATION_IN_PROGRESS; + } + else + { + logerror("T10MMC: track is NOT audio!\n"); + set_sense(SCSI_SENSE_KEY_ILLEGAL_REQUEST, SCSI_SENSE_ASC_ASCQ_ILLEGAL_MODE_FOR_THIS_TRACK); + } + + m_phase = SCSI_PHASE_STATUS; + m_status_code = SCSI_STATUS_CODE_GOOD; + m_transfer_length = 0; + break; + + case T10SBC_CMD_READ_12: + m_lba = command[2]<<24 | command[3]<<16 | command[4]<<8 | command[5]; + m_blocks = command[7]<<16 | command[8]<<8 | command[9]; + + logerror("T10MMC: READ(12) at LBA %x for %x blocks (%x bytes)\n", m_lba, m_blocks, m_blocks * m_sector_bytes); + + if (m_num_subblocks > 1) + { + m_cur_subblock = m_lba % m_num_subblocks; + m_lba /= m_num_subblocks; + } + else + { + m_cur_subblock = 0; + } + + abort_audio(); + + m_phase = SCSI_PHASE_DATAIN; + m_status_code = SCSI_STATUS_CODE_GOOD; + m_transfer_length = m_blocks * m_sector_bytes; + break; + + case T10MMC_CMD_SET_CD_SPEED: + logerror("T10MMC: SET CD SPEED to %d kbytes/sec.\n", command[2]<<8 | command[3]); + m_phase = SCSI_PHASE_STATUS; + m_status_code = SCSI_STATUS_CODE_GOOD; + m_transfer_length = 0; + break; + + default: + t10spc::ExecCommand(); + } +} + +// scsicd_read_data +// +// Read data from the device resulting from the execution of a command + +void t10mmc::ReadData( UINT8 *data, int dataLength ) +{ + UINT32 temp; + UINT8 tmp_buffer[2048]; + + switch ( command[0] ) + { + case T10SPC_CMD_INQUIRY: + data[0] = 0x05; // device is present, device is CD/DVD (MMC-3) + data[1] = 0x80; // media is removable + data[2] = 0x05; // device complies with SPC-3 standard + data[3] = 0x02; // response data format = SPC-3 standard + data[4] = 0x1f; + data[5] = 0; + data[6] = 0; + data[7] = 0; + memset(&data[8], ' ', 28); + memcpy(&data[8], "MAME", 4); + memcpy(&data[16], "Virtual CDROM", 13); + memcpy(&data[32], "1.0", 3); + break; + + case T10SBC_CMD_READ_CAPACITY: + logerror("T10MMC: READ CAPACITY\n"); + + temp = cdrom_get_track_start(m_cdrom, 0xaa); + temp--; // return the last used block on the disc + + data[0] = (temp>>24) & 0xff; + data[1] = (temp>>16) & 0xff; + data[2] = (temp>>8) & 0xff; + data[3] = (temp & 0xff); + data[4] = 0; + data[5] = 0; + data[6] = (m_sector_bytes>>8)&0xff; + data[7] = (m_sector_bytes & 0xff); + break; + + case T10SBC_CMD_READ_10: + case T10SBC_CMD_READ_12: + logerror("T10MMC: read %x dataLength, \n", dataLength); + if ((m_cdrom) && (m_blocks)) + { + while (dataLength > 0) + { + if (!cdrom_read_data(m_cdrom, m_lba, tmp_buffer, CD_TRACK_MODE1)) + { + logerror("T10MMC: CD read error!\n"); + } + + logerror("True LBA: %d, buffer half: %d\n", m_lba, m_cur_subblock * m_sector_bytes); + + memcpy(data, &tmp_buffer[m_cur_subblock * m_sector_bytes], m_sector_bytes); + + m_cur_subblock++; + if (m_cur_subblock >= m_num_subblocks) + { + m_cur_subblock = 0; + + m_lba++; + m_blocks--; + } + + m_last_lba = m_lba; + dataLength -= m_sector_bytes; + data += m_sector_bytes; + } + } + break; + + case T10MMC_CMD_READ_SUB_CHANNEL: + switch (command[3]) + { + case 1: // return current position + { + if (!m_cdrom) + { + return; + } + + logerror("T10MMC: READ SUB-CHANNEL Time = %x, SUBQ = %x\n", command[1], command[2]); + + bool msf = (command[1] & 0x2) != 0; + + data[0]= 0x00; + + int audio_active = m_cdda->audio_active(); + if (audio_active) + { + // if audio is playing, get the latest LBA from the CDROM layer + m_last_lba = m_cdda->get_audio_lba(); + if (m_cdda->audio_paused()) + { + data[1] = 0x12; // audio is paused + } + else + { + data[1] = 0x11; // audio in progress + } + } + else + { + m_last_lba = 0; + if (m_cdda->audio_ended()) + { + data[1] = 0x13; // ended successfully + } + else + { +// data[1] = 0x14; // stopped due to error + data[1] = 0x15; // No current audio status to return + } + } + + if (command[2] & 0x40) + { + data[2] = 0; + data[3] = 12; // data length + data[4] = 0x01; // sub-channel format code + data[5] = 0x10 | (audio_active ? 0 : 4); + data[6] = cdrom_get_track(m_cdrom, m_last_lba) + 1; // track + data[7] = 0; // index + + UINT32 frame = m_last_lba; + + if (msf) + { + frame = to_msf(frame); + } + + data[8] = (frame>>24)&0xff; + data[9] = (frame>>16)&0xff; + data[10] = (frame>>8)&0xff; + data[11] = frame&0xff; + + frame -= cdrom_get_track_start(m_cdrom, data[6] - 1); + + if (msf) + { + frame = to_msf(frame); + } + + data[12] = (frame>>24)&0xff; + data[13] = (frame>>16)&0xff; + data[14] = (frame>>8)&0xff; + data[15] = frame&0xff; + } + else + { + data[2] = 0; + data[3] = 0; + } + break; + } + default: + logerror("T10MMC: Unknown subchannel type %d requested\n", command[3]); + } + break; + + case T10MMC_CMD_READ_TOC_PMA_ATIP: + /* + Track numbers are problematic here: 0 = lead-in, 0xaa = lead-out. + That makes sense in terms of how real-world CDs are referred to, but + our internal routines for tracks use "0" as track 1. That probably + should be fixed... + */ + { + bool msf = (command[1] & 0x2) != 0; + + logerror("T10MMC: READ TOC, format = %d time=%d\n", toc_format(),msf); + switch (toc_format()) + { + case TOC_FORMAT_TRACKS: + { + int tracks = toc_tracks(); + int len = 2 + (tracks * 8); + + // the returned TOC DATA LENGTH must be the full amount, + // regardless of how much we're able to pass back due to in_len + int dptr = 0; + data[dptr++] = (len>>8) & 0xff; + data[dptr++] = (len & 0xff); + data[dptr++] = 1; + data[dptr++] = cdrom_get_last_track(m_cdrom); + + int first_track = command[6]; + if (first_track == 0) + { + first_track = 1; + } + + for (int i = 0; i < tracks; i++) + { + int track = first_track + i; + int cdrom_track = track - 1; + if( i == tracks - 1 ) + { + track = 0xaa; + cdrom_track = 0xaa; + } + + if( dptr >= dataLength ) + { + break; + } + + data[dptr++] = 0; + data[dptr++] = cdrom_get_adr_control(m_cdrom, cdrom_track); + data[dptr++] = track; + data[dptr++] = 0; + + UINT32 tstart = cdrom_get_track_start(m_cdrom, cdrom_track); + + if (msf) + { + tstart = to_msf(tstart+150); + } + + data[dptr++] = (tstart>>24) & 0xff; + data[dptr++] = (tstart>>16) & 0xff; + data[dptr++] = (tstart>>8) & 0xff; + data[dptr++] = (tstart & 0xff); + } + } + break; + + case TOC_FORMAT_SESSIONS: + { + int len = 2 + (8 * 1); + + int dptr = 0; + data[dptr++] = (len>>8) & 0xff; + data[dptr++] = (len & 0xff); + data[dptr++] = 1; + data[dptr++] = 1; + + data[dptr++] = 0; + data[dptr++] = cdrom_get_adr_control(m_cdrom, 0); + data[dptr++] = 1; + data[dptr++] = 0; + + UINT32 tstart = cdrom_get_track_start(m_cdrom, 0); + + if (msf) + { + tstart = to_msf(tstart+150); + } + + data[dptr++] = (tstart>>24) & 0xff; + data[dptr++] = (tstart>>16) & 0xff; + data[dptr++] = (tstart>>8) & 0xff; + data[dptr++] = (tstart & 0xff); + } + break; + + default: + logerror("T10MMC: Unhandled READ TOC format %d\n", toc_format()); + break; + } + } + break; + + case T10SPC_CMD_MODE_SENSE_6: + case T10SPC_CMD_MODE_SENSE_10: + logerror("T10MMC: MODE SENSE page code = %x, PC = %x\n", command[2] & 0x3f, (command[2]&0xc0)>>6); + + memset(data, 0, SCSILengthFromUINT16( &command[ 7 ] )); + + switch (command[2] & 0x3f) + { + case 0xe: // CD Audio control page + data[0] = 0x8e; // page E, parameter is savable + data[1] = 0x0e; // page length + data[2] = 0x04; // IMMED = 1, SOTC = 0 + data[3] = data[4] = data[5] = data[6] = data[7] = 0; // reserved + + // connect each audio channel to 1 output port + data[8] = 1; + data[10] = 2; + data[12] = 4; + data[14] = 8; + + // indicate max volume + data[9] = data[11] = data[13] = data[15] = 0xff; + break; + case 0x2a: // Page capabilities + data[0] = 0x2a; + data[1] = 0x14; // page length + data[2] = 0x00; data[3] = 0x00; // CD-R only + data[4] = 0x01; // can play audio + data[5] = 0; + data[6] = 0; + data[7] = 0; + data[8] = 0x02; data[9] = 0xc0; // 4x speed + data[10] = 0; + data[11] = 2; // two volumen levels + data[12] = 0x00; data[13] = 0x00; // buffer + data[14] = 0x02; data[15] = 0xc0; // 4x read speed + data[16] = 0; + data[17] = 0; + data[18] = 0; + data[19] = 0; + data[20] = 0; + data[21] = 0; + break; + + default: + logerror("T10MMC: MODE SENSE unknown page %x\n", command[2] & 0x3f); + break; + } + break; + + default: + t10spc::ReadData( data, dataLength ); + break; + } +} + +// scsicd_write_data +// +// Write data to the CD-ROM device as part of the execution of a command + +void t10mmc::WriteData( UINT8 *data, int dataLength ) +{ + switch (command[ 0 ]) + { + case T10SPC_CMD_MODE_SELECT_6: + case T10SPC_CMD_MODE_SELECT_10: + logerror("T10MMC: MODE SELECT page %x\n", data[0] & 0x3f); + + switch (data[0] & 0x3f) + { + case 0x0: // vendor-specific + // check for SGI extension to force 512-byte blocks + if ((data[3] == 8) && (data[10] == 2)) + { + logerror("T10MMC: Experimental SGI 512-byte block extension enabled\n"); + + m_sector_bytes = 512; + m_num_subblocks = 4; + } + else + { + logerror("T10MMC: Unknown vendor-specific page!\n"); + } + break; + + case 0xe: // audio page + logerror("Ch 0 route: %x vol: %x\n", data[8], data[9]); + logerror("Ch 1 route: %x vol: %x\n", data[10], data[11]); + logerror("Ch 2 route: %x vol: %x\n", data[12], data[13]); + logerror("Ch 3 route: %x vol: %x\n", data[14], data[15]); + break; + } + break; + + default: + t10spc::WriteData( data, dataLength ); + break; +} +} + +void t10mmc::GetDevice( void **_cdrom ) +{ + *(cdrom_file **)_cdrom = m_cdrom; +} + +void t10mmc::SetDevice( void *_cdrom ) +{ + m_cdrom = (cdrom_file *)_cdrom; + m_cdda->set_cdrom(m_cdrom); +} diff --git a/src/devices/machine/t10mmc.h b/src/devices/machine/t10mmc.h new file mode 100644 index 00000000000..cfebfc1694c --- /dev/null +++ b/src/devices/machine/t10mmc.h @@ -0,0 +1,63 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/*************************************************************************** + +t10mmc.h + +***************************************************************************/ + +#ifndef _T10MMC_H_ +#define _T10MMC_H_ + +#include "t10spc.h" +#include "imagedev/chd_cd.h" +#include "sound/cdda.h" + +class t10mmc : public virtual t10spc +{ +public: + virtual void SetDevice( void *device ); + virtual void GetDevice( void **device ); + virtual void ExecCommand(); + virtual void WriteData( UINT8 *data, int dataLength ); + virtual void ReadData( UINT8 *data, int dataLength ); + +protected: + virtual void t10_start(device_t &device); + virtual void t10_reset(); + + enum + { + T10MMC_CMD_READ_SUB_CHANNEL = 0x42, + T10MMC_CMD_READ_TOC_PMA_ATIP = 0x43, + T10MMC_CMD_PLAY_AUDIO_10 = 0x45, + T10MMC_CMD_PLAY_AUDIO_TRACK_INDEX = 0x48, + T10MMC_CMD_PAUSE_RESUME = 0x4b, + T10MMC_CMD_STOP_PLAY_SCAN = 0x4e, + T10MMC_CMD_PLAY_AUDIO_12 = 0xa5, + T10MMC_CMD_SET_CD_SPEED = 0xbb + }; + + enum toc_format_t + { + TOC_FORMAT_TRACKS = 0, + TOC_FORMAT_SESSIONS = 1 + }; + + void abort_audio(); + toc_format_t toc_format(); + int toc_tracks(); + + cdrom_image_device *m_image; + cdda_device *m_cdda; + cdrom_file *m_cdrom; + + UINT32 m_lba; + UINT32 m_blocks; + UINT32 m_last_lba; + UINT32 m_num_subblocks; + UINT32 m_cur_subblock; + int m_audio_sense; +}; + +#endif diff --git a/src/devices/machine/t10sbc.c b/src/devices/machine/t10sbc.c new file mode 100644 index 00000000000..c5d68be8162 --- /dev/null +++ b/src/devices/machine/t10sbc.c @@ -0,0 +1,268 @@ +// license:BSD-3-Clause +// copyright-holders:smf +#include "t10sbc.h" + +void t10sbc::t10_start(device_t &device) +{ + t10spc::t10_start(device); + + device.save_item( NAME( m_lba ) ); + device.save_item( NAME( m_blocks ) ); +} + +void t10sbc::t10_reset() +{ + t10spc::t10_reset(); + + m_lba = 0; + m_blocks = 0; + m_sector_bytes = 512; + + m_disk = m_image->get_hard_disk_file(); + if (!m_disk) + { + logerror("T10SBC %s: no HD found!\n", m_image->owner()->tag()); + } + else + { + // get hard disk sector size from CHD metadata + const hard_disk_info *hdinfo = hard_disk_get_info(m_disk); + m_sector_bytes = hdinfo->sectorbytes; + } +} + +// scsihd_exec_command +void t10sbc::ExecCommand() +{ + switch ( command[0] ) + { + case T10SBC_CMD_FORMAT_UNIT: + m_phase = SCSI_PHASE_STATUS; + m_status_code = SCSI_STATUS_CODE_GOOD; + m_transfer_length = 0; + break; + + case T10SBC_CMD_SEEK_6: + m_lba = (command[1]&0x1f)<<16 | command[2]<<8 | command[3]; + + logerror("S1410: SEEK to LBA %x\n", m_lba); + + m_phase = SCSI_PHASE_STATUS; + m_transfer_length = 0; + break; + + case T10SBC_CMD_READ_6: + m_lba = (command[1]&0x1f)<<16 | command[2]<<8 | command[3]; + m_blocks = SCSILengthFromUINT8( &command[4] ); + + logerror("T10SBC: READ at LBA %x for %x blocks\n", m_lba, m_blocks); + + m_phase = SCSI_PHASE_DATAIN; + m_status_code = SCSI_STATUS_CODE_GOOD; + m_transfer_length = m_blocks * m_sector_bytes; + break; + + case T10SBC_CMD_WRITE_6: + m_lba = (command[1]&0x1f)<<16 | command[2]<<8 | command[3]; + m_blocks = SCSILengthFromUINT8( &command[4] ); + + logerror("T10SBC: WRITE to LBA %x for %x blocks\n", m_lba, m_blocks); + + m_phase = SCSI_PHASE_DATAOUT; + m_status_code = SCSI_STATUS_CODE_GOOD; + m_transfer_length = m_blocks * m_sector_bytes; + break; + + case T10SPC_CMD_INQUIRY: + m_phase = SCSI_PHASE_DATAIN; + m_status_code = SCSI_STATUS_CODE_GOOD; + m_transfer_length = SCSILengthFromUINT8( &command[ 4 ] ); + break; + + case T10SPC_CMD_MODE_SELECT_6: + logerror("T10SBC: MODE SELECT length %x control %x\n", command[4], command[5]); + m_phase = SCSI_PHASE_DATAOUT; + m_status_code = SCSI_STATUS_CODE_GOOD; + m_transfer_length = SCSILengthFromUINT8( &command[ 4 ] ); + break; + + case T10SPC_CMD_MODE_SENSE_6: + m_phase = SCSI_PHASE_DATAIN; + m_status_code = SCSI_STATUS_CODE_GOOD; + m_transfer_length = SCSILengthFromUINT8( &command[ 4 ] ); + break; + + case T10SBC_CMD_READ_CAPACITY: + m_phase = SCSI_PHASE_DATAIN; + m_status_code = SCSI_STATUS_CODE_GOOD; + m_transfer_length = 8; + break; + + case T10SBC_CMD_READ_10: + m_lba = command[2]<<24 | command[3]<<16 | command[4]<<8 | command[5]; + m_blocks = SCSILengthFromUINT16( &command[7] ); + + logerror("T10SBC: READ at LBA %x for %x blocks\n", m_lba, m_blocks); + + m_phase = SCSI_PHASE_DATAIN; + m_status_code = SCSI_STATUS_CODE_GOOD; + m_transfer_length = m_blocks * m_sector_bytes; + break; + + case T10SBC_CMD_WRITE_10: + m_lba = command[2]<<24 | command[3]<<16 | command[4]<<8 | command[5]; + m_blocks = SCSILengthFromUINT16( &command[7] ); + + logerror("T10SBC: WRITE to LBA %x for %x blocks\n", m_lba, m_blocks); + + m_phase = SCSI_PHASE_DATAOUT; + m_status_code = SCSI_STATUS_CODE_GOOD; + m_transfer_length = m_blocks * m_sector_bytes; + break; + + case T10SBC_CMD_READ_12: + m_lba = command[2]<<24 | command[3]<<16 | command[4]<<8 | command[5]; + m_blocks = command[6]<<24 | command[7]<<16 | command[8]<<8 | command[9]; + + logerror("T10SBC: READ at LBA %x for %x blocks\n", m_lba, m_blocks); + + m_phase = SCSI_PHASE_DATAIN; + m_status_code = SCSI_STATUS_CODE_GOOD; + m_transfer_length = m_blocks * m_sector_bytes; + break; + + default: + t10spc::ExecCommand(); + break; + } +} + +void t10sbc::ReadData( UINT8 *data, int dataLength ) +{ + // if we're a drive without a disk, return all zeroes + if (!m_disk) + { + memset(data, 0, dataLength); + return; + } + + switch ( command[0] ) + { + case T10SPC_CMD_INQUIRY: + memset( data, 0, dataLength ); + data[0] = 0x00; // device is direct-access (e.g. hard disk) + data[1] = 0x00; // media is not removable + data[2] = 0x05; // device complies with SPC-3 standard + data[3] = 0x02; // response data format = SPC-3 standard + // Apple HD SC setup utility needs to see this + strcpy((char *)&data[8], " SEAGATE"); + strcpy((char *)&data[16], " ST225N"); + strcpy((char *)&data[32], "1.0"); + break; + + case T10SPC_CMD_MODE_SENSE_6: + // special Apple ID page. this is a vendor-specific page, + // so unless collisions occur there should be no need + // to change it. + if ((command[2] & 0x3f) == 0x30) + { + memset(data, 0, 40); + data[0] = 0x14; + strcpy((char *)&data[14], "APPLE COMPUTER, INC."); + } + break; + + case T10SBC_CMD_READ_6: + case T10SBC_CMD_READ_10: + case T10SBC_CMD_READ_12: + if ((m_disk) && (m_blocks)) + { + while (dataLength > 0) + { + if (!hard_disk_read(m_disk, m_lba, data)) + { + logerror("T10SBC: HD read error!\n"); + } + m_lba++; + m_blocks--; + dataLength -= m_sector_bytes; + data += m_sector_bytes; + } + } + break; + + case T10SBC_CMD_READ_CAPACITY: // READ CAPACITY + { + hard_disk_info *info; + UINT32 temp; + + info = hard_disk_get_info(m_disk); + + logerror("T10SBC: READ CAPACITY\n"); + + // get # of sectors + temp = info->cylinders * info->heads * info->sectors; + temp--; + + data[0] = (temp>>24) & 0xff; + data[1] = (temp>>16) & 0xff; + data[2] = (temp>>8) & 0xff; + data[3] = (temp & 0xff); + data[4] = (info->sectorbytes>>24)&0xff; + data[5] = (info->sectorbytes>>16)&0xff; + data[6] = (info->sectorbytes>>8)&0xff; + data[7] = (info->sectorbytes & 0xff); + } + break; + + default: + t10spc::ReadData( data, dataLength ); + break; + } +} + +void t10sbc::WriteData( UINT8 *data, int dataLength ) +{ + if (!m_disk) + { + return; + } + + switch ( command[0] ) + { + case T10SPC_CMD_MODE_SELECT_6: + break; + + case T10SBC_CMD_WRITE_6: + case T10SBC_CMD_WRITE_10: + if ((m_disk) && (m_blocks)) + { + while (dataLength > 0) + { + if (!hard_disk_write(m_disk, m_lba, data)) + { + logerror("T10SBC: HD write error!\n"); + } + m_lba++; + m_blocks--; + dataLength -= m_sector_bytes; + data += m_sector_bytes; + } + } + break; + + default: + t10spc::WriteData( data, dataLength ); + break; + } +} + +void t10sbc::GetDevice( void **_disk ) +{ + *(hard_disk_file **)_disk = m_disk; +} + +void t10sbc::SetDevice( void *_disk ) +{ + m_disk = (hard_disk_file *)_disk; +} diff --git a/src/devices/machine/t10sbc.h b/src/devices/machine/t10sbc.h new file mode 100644 index 00000000000..d32c0beee57 --- /dev/null +++ b/src/devices/machine/t10sbc.h @@ -0,0 +1,36 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/*************************************************************************** + +t10sbc.h + +***************************************************************************/ + +#ifndef _T10SBC_H_ +#define _T10SBC_H_ + +#include "t10spc.h" +#include "imagedev/harddriv.h" + +class t10sbc : public virtual t10spc +{ +public: + virtual void SetDevice( void *device ); + virtual void GetDevice( void **device ); + virtual void ExecCommand(); + virtual void WriteData( UINT8 *data, int dataLength ); + virtual void ReadData( UINT8 *data, int dataLength ); + +protected: + virtual void t10_start(device_t &device); + virtual void t10_reset(); + + harddisk_image_device *m_image; + + UINT32 m_lba; + UINT32 m_blocks; + + hard_disk_file *m_disk; +}; + +#endif diff --git a/src/devices/machine/t10spc.c b/src/devices/machine/t10spc.c new file mode 100644 index 00000000000..80b279efb44 --- /dev/null +++ b/src/devices/machine/t10spc.c @@ -0,0 +1,150 @@ +// license:BSD-3-Clause +// copyright-holders:smf +#include "t10spc.h" + +void t10spc::t10_start(device_t &device) +{ + device.save_item(NAME(command)); + device.save_item(NAME(commandLength)); + device.save_item(NAME(m_transfer_length)); + device.save_item(NAME(m_phase)); + device.save_item(NAME(m_sense_key)); + device.save_item(NAME(m_sense_asc)); + device.save_item(NAME(m_sense_ascq)); + device.save_item(NAME(m_sense_information)); +} + +void t10spc::t10_reset() +{ + m_phase = SCSI_PHASE_BUS_FREE; + m_status_code = SCSI_STATUS_CODE_GOOD; + m_sense_key = 0; + m_sense_asc = 0; + m_sense_ascq = 0; + m_sense_information = 0; +} + +void t10spc::set_sense(sense_key_t key, sense_asc_ascq_t asc_ascq) +{ + m_sense_key = key; + m_sense_asc = (asc_ascq >> 8) & 0xff; + m_sense_ascq = asc_ascq & 0xff; + m_sense_information = 0; +} + +void t10spc::ExecCommand() +{ + switch( command[ 0 ] ) + { + case T10SPC_CMD_TEST_UNIT_READY: + m_phase = SCSI_PHASE_STATUS; + m_status_code = SCSI_STATUS_CODE_GOOD; + m_transfer_length = 0; + break; + + case T10SPC_CMD_RECALIBRATE: + m_phase = SCSI_PHASE_STATUS; + m_status_code = SCSI_STATUS_CODE_GOOD; + m_transfer_length = 0; + break; + + case T10SPC_CMD_REQUEST_SENSE: + m_phase = SCSI_PHASE_DATAIN; + m_status_code = SCSI_STATUS_CODE_GOOD; + if (command[4] == 0) + { + m_transfer_length = 4; + } + else if (command[4] > 18) + { + m_transfer_length = 18; + } + else + { + m_transfer_length = command[ 4 ]; + } + break; + + case T10SPC_CMD_SEND_DIAGNOSTIC: + m_phase = SCSI_PHASE_DATAOUT; + m_status_code = SCSI_STATUS_CODE_GOOD; + m_transfer_length = SCSILengthFromUINT16(&command[3]); + break; + + default: + logerror( "SCSIDEV unknown command %02x\n", command[ 0 ] ); + m_status_code = SCSI_STATUS_CODE_GOOD; + m_transfer_length = 0; + break; + } +} + +void t10spc::ReadData( UINT8 *data, int dataLength ) +{ + switch( command[ 0 ] ) + { + case T10SPC_CMD_REQUEST_SENSE: + if (command[4] == 0) + { + data[0] = m_sense_asc & 0x7f; + data[1] = (m_sense_information >> 16) & 0x1f; + data[2] = (m_sense_information >> 8) & 0xff; + data[3] = (m_sense_information >> 0) & 0xff; + } + else + { + data[0] = 0x70; + data[1] = 0; + data[2] = m_sense_key & 0xf; + data[3] = (m_sense_information >> 24) & 0xff; + data[4] = (m_sense_information >> 16) & 0xff; + data[5] = (m_sense_information >> 8) & 0xff; + data[6] = (m_sense_information >> 0) & 0xff; + data[7] = 10; + data[8] = 0; + data[9] = 0; + data[10] = 0; + data[11] = 0; + data[12] = m_sense_asc; + data[13] = m_sense_ascq; + data[14] = 0; + data[15] = 0; + data[16] = 0; + data[17] = 0; + } + + set_sense(SCSI_SENSE_KEY_NO_SENSE, SCSI_SENSE_ASC_ASCQ_NO_SENSE); + break; + + default: + logerror( "SCSIDEV unknown read %02x\n", command[ 0 ] ); + break; + } +} + +void t10spc::WriteData( UINT8 *data, int dataLength ) +{ + switch( command[ 0 ] ) + { + case T10SPC_CMD_SEND_DIAGNOSTIC: + break; + + default: + logerror( "SCSIDEV unknown write %02x\n", command[ 0 ] ); + break; + } +} + +void t10spc::SetCommand( UINT8 *_command, int _commandLength ) +{ + if( _commandLength > sizeof( command ) ) + { + /// TODO: output an error. + return; + } + + memcpy( command, _command, _commandLength ); + commandLength = _commandLength; + + m_phase = SCSI_PHASE_COMMAND; +} diff --git a/src/devices/machine/t10spc.h b/src/devices/machine/t10spc.h new file mode 100644 index 00000000000..778fd40bce1 --- /dev/null +++ b/src/devices/machine/t10spc.h @@ -0,0 +1,136 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/*************************************************************************** + +t10spc.h + +***************************************************************************/ + +#ifndef _T10SPC_H_ +#define _T10SPC_H_ + +#include "emu.h" + +class t10spc +{ +public: + virtual ~t10spc() {}; + virtual void SetDevice( void *device ) = 0; + virtual void GetDevice( void **device ) = 0; + + virtual void SetCommand( UINT8 *command, int commandLength ); + virtual void ExecCommand(); + virtual void WriteData( UINT8 *data, int dataLength ); + virtual void ReadData( UINT8 *data, int dataLength ); + void GetLength( int *transferLength ) { *transferLength = m_transfer_length; } + virtual void GetPhase( int *phase ) { *phase = m_phase; } + +protected: + virtual void t10_start(device_t &device); + virtual void t10_reset(); + + int SCSILengthFromUINT8( UINT8 *length ) { if( *length == 0 ) { return 256; } return *length; } + int SCSILengthFromUINT16( UINT8 *length ) { return ( *(length) << 8 ) | *(length + 1 ); } + + enum sense_key_t + { + SCSI_SENSE_KEY_NO_SENSE = 0, + SCSI_SENSE_KEY_ILLEGAL_REQUEST = 5 + }; + + enum sense_asc_ascq_t + { + SCSI_SENSE_ASC_ASCQ_NO_SENSE = 0x0, + SCSI_SENSE_ASC_ASCQ_AUDIO_PLAY_OPERATION_IN_PROGRESS = 0x0011, + SCSI_SENSE_ASC_ASCQ_AUDIO_PLAY_OPERATION_PAUSED = 0x0012, + SCSI_SENSE_ASC_ASCQ_AUDIO_PLAY_OPERATION_SUCCESSFULLY_COMPLETED = 0x0013, + SCSI_SENSE_ASC_ASCQ_AUDIO_PLAY_OPERATION_STOPPED_DUE_TO_ERROR = 0x0014, + SCSI_SENSE_ASC_ASCQ_ILLEGAL_MODE_FOR_THIS_TRACK = 0x6400 + }; + + enum status_code_t + { + SCSI_STATUS_CODE_GOOD = 0x00, + SCSI_STATUS_CODE_CHECK_CONDITION = 0x02, + SCSI_STATUS_CODE_CONDITION_MET = 0x04, + SCSI_STATUS_CODE_BUSY = 0x08, + SCSI_STATUS_CODE_INTERMEDIATE = 0x14, + SCSI_STATUS_CODE_RESERVATION_CONFLICT = 0x18, + SCSI_STATUS_CODE_COMMAND_TERMINATED = 0x22, + SCSI_STATUS_CODE_TASK_SET_FULL = 0x28, + SCSI_STATUS_CODE_ACA_ACTIVE = 0x30, + SCSI_STATUS_CODE_TASK_ABORTED = 0x40 + }; + + // these are defined here because t10mmc also needs them. + enum + { + T10SBC_CMD_FORMAT_UNIT = 0x04, + T10SBC_CMD_READ_6 = 0x08, + T10SBC_CMD_WRITE_6 = 0x0a, + T10SBC_CMD_SEEK_6 = 0x0b, + T10SBC_CMD_READ_10 = 0x28, + T10SBC_CMD_READ_CAPACITY = 0x25, + T10SBC_CMD_WRITE_10 = 0x2a, + T10SBC_CMD_SEEK_10 = 0x2b, + T10SBC_CMD_READ_12 = 0xa8 + }; + + enum + { + T10SPC_CMD_TEST_UNIT_READY = 0x00, + T10SPC_CMD_RECALIBRATE = 0x01, + T10SPC_CMD_REQUEST_SENSE = 0x03, + T10SPC_CMD_INQUIRY = 0x12, + T10SPC_CMD_MODE_SELECT_6 = 0x15, + T10SPC_CMD_RESERVE_6 = 0x16, + T10SPC_CMD_RELEASE_6 = 0x17, + T10SPC_CMD_MODE_SENSE_6 = 0x1a, + T10SPC_CMD_START_STOP_UNIT = 0x1b, + T10SPC_CMD_RECEIVE_DIAGNOSTIC_RESULTS = 0x1c, + T10SPC_CMD_SEND_DIAGNOSTIC = 0x1d, + T10SPC_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL = 0x1e, + T10SPC_CMD_WRITE_BUFFER = 0x3b, + T10SPC_CMD_READ_BUFFER = 0x3c, + T10SPC_CMD_LOG_SELECT = 0x4c, + T10SPC_CMD_LOG_SENSE = 0x4d, + T10SPC_CMD_MODE_SELECT_10 = 0x55, + T10SPC_CMD_RESERVE_10 = 0x56, + T10SPC_CMD_RELEASE_10 = 0x57, + T10SPC_CMD_MODE_SENSE_10 = 0x5a, + T10SPC_CMD_PERSISTENT_RESERVE_IN = 0x5e, + T10SPC_CMD_PERSISTENT_RESERVE_OUT = 0x5f, + T10SPC_CMD_EXTENDED_COPY = 0x83, + T10SPC_CMD_RECEIVE_COPY_RESULTS = 0x84, + T10SPC_CMD_REPORT_LUNS = 0xa0, + T10SPC_CMD_REPORT_DEVICE_IDENTIFIER = 0xa3, + T10SPC_CMD_SET_DEVICE_IDENTIFIER = 0xa4, + T10SPC_CMD_MOVE_MEDIUM_ATTACHED = 0xa7, + T10SPC_CMD_READ_ELEMENT_STATUS_ATTACHED = 0xb4 + }; + + void set_sense(sense_key_t key, sense_asc_ascq_t asc_ascq); + + UINT8 command[ 32 ]; + int commandLength; + int m_transfer_length; + int m_phase; + status_code_t m_status_code; + UINT8 m_sense_key; + UINT8 m_sense_asc; + UINT8 m_sense_ascq; + UINT32 m_sense_information; + int m_sector_bytes; + device_t *m_device; +}; + +#define SCSI_PHASE_DATAOUT ( 0 ) +#define SCSI_PHASE_DATAIN ( 1 ) +#define SCSI_PHASE_COMMAND ( 2 ) +#define SCSI_PHASE_STATUS ( 3 ) +#define SCSI_PHASE_MESSAGE_OUT ( 6 ) +#define SCSI_PHASE_MESSAGE_IN ( 7 ) +#define SCSI_PHASE_BUS_FREE ( 8 ) +#define SCSI_PHASE_SELECT ( 9 ) + +#endif diff --git a/src/devices/machine/tc009xlvc.c b/src/devices/machine/tc009xlvc.c new file mode 100644 index 00000000000..5897d555d88 --- /dev/null +++ b/src/devices/machine/tc009xlvc.c @@ -0,0 +1,417 @@ +// license:LGPL-2.1+ +// copyright-holders:Angelo Salese +/*************************************************************************** + + TC009xLVC device emulation + + Written by Angelo Salese, based off Taito L implementation + + TODO: + - non-video stuff needs to be ported there as well + +***************************************************************************/ + +#include "emu.h" +#include "machine/tc009xlvc.h" + +const device_type TC0091LVC = &device_creator; + + +READ8_MEMBER(tc0091lvc_device::tc0091lvc_paletteram_r) +{ + return m_palette_ram[offset & 0x1ff]; +} + +WRITE8_MEMBER(tc0091lvc_device::tc0091lvc_paletteram_w) +{ + m_palette_ram[offset & 0x1ff] = data; + + { + UINT8 r,g,b,i; + UINT16 pal; + + pal = (m_palette_ram[offset & ~1]<<0) | (m_palette_ram[offset | 1]<<8); + + i = (pal & 0x7000) >> 12; + b = (pal & 0x0f00) >> 8; + g = (pal & 0x00f0) >> 4; + r = (pal & 0x000f) >> 0; + + r <<= 1; + g <<= 1; + b <<= 1; + + /* TODO: correct? */ + b |= ((i & 4) >> 2); + g |= ((i & 2) >> 1); + r |= (i & 1); + + m_palette->set_pen_color(offset / 2, pal5bit(r), pal5bit(g), pal5bit(b)); + } +} + +READ8_MEMBER(tc0091lvc_device::vregs_r) +{ + return m_vregs[offset]; +} + +WRITE8_MEMBER(tc0091lvc_device::vregs_w) +{ + if((offset & 0xfc) == 0) + { + bg0_tilemap->mark_all_dirty(); + bg1_tilemap->mark_all_dirty(); + } + + m_vregs[offset] = data; +} + +READ8_MEMBER(tc0091lvc_device::tc0091lvc_bitmap_r) +{ + return m_bitmap_ram[offset]; +} + +WRITE8_MEMBER(tc0091lvc_device::tc0091lvc_bitmap_w) +{ + m_bitmap_ram[offset] = data; +} + + +READ8_MEMBER(tc0091lvc_device::tc0091lvc_pcg1_r) +{ + return m_pcg1_ram[offset]; +} + +WRITE8_MEMBER(tc0091lvc_device::tc0091lvc_pcg1_w) +{ + m_pcg1_ram[offset] = data; + m_gfxdecode->gfx(m_gfx_index)->mark_dirty((offset+0x4000) / 32); + tx_tilemap->mark_all_dirty(); +} + +READ8_MEMBER(tc0091lvc_device::tc0091lvc_pcg2_r) +{ + return m_pcg2_ram[offset]; +} + +WRITE8_MEMBER(tc0091lvc_device::tc0091lvc_pcg2_w) +{ + m_pcg2_ram[offset] = data; + m_gfxdecode->gfx(m_gfx_index)->mark_dirty((offset+0xc000) / 32); + tx_tilemap->mark_all_dirty(); +} + +READ8_MEMBER(tc0091lvc_device::tc0091lvc_vram0_r) +{ + return m_vram0[offset]; +} + +WRITE8_MEMBER(tc0091lvc_device::tc0091lvc_vram0_w) +{ + m_vram0[offset] = data; + bg0_tilemap->mark_tile_dirty(offset/2); + m_gfxdecode->gfx(m_gfx_index)->mark_dirty((offset+0x8000) / 32); + tx_tilemap->mark_all_dirty(); + +} + +READ8_MEMBER(tc0091lvc_device::tc0091lvc_vram1_r) +{ + return m_vram1[offset]; +} + +WRITE8_MEMBER(tc0091lvc_device::tc0091lvc_vram1_w) +{ + m_vram1[offset] = data; + bg1_tilemap->mark_tile_dirty(offset/2); + m_gfxdecode->gfx(m_gfx_index)->mark_dirty((offset+0x9000) / 32); + tx_tilemap->mark_all_dirty(); +} + +READ8_MEMBER(tc0091lvc_device::tc0091lvc_tvram_r) +{ + return m_tvram[offset]; +} + +WRITE8_MEMBER(tc0091lvc_device::tc0091lvc_tvram_w) +{ + m_tvram[offset] = data; + tx_tilemap->mark_tile_dirty(offset/2); + m_gfxdecode->gfx(m_gfx_index)->mark_dirty((offset+0xa000) / 32); + tx_tilemap->mark_all_dirty(); +} + +READ8_MEMBER(tc0091lvc_device::tc0091lvc_spr_r) +{ + return m_sprram[offset]; +} + +WRITE8_MEMBER(tc0091lvc_device::tc0091lvc_spr_w) +{ + m_sprram[offset] = data; + m_gfxdecode->gfx(m_gfx_index)->mark_dirty((offset+0xb000) / 32); + tx_tilemap->mark_all_dirty(); +} + +static ADDRESS_MAP_START( tc0091lvc_map8, AS_0, 8, tc0091lvc_device ) + AM_RANGE(0x014000, 0x017fff) AM_READWRITE(tc0091lvc_pcg1_r, tc0091lvc_pcg1_w) + AM_RANGE(0x018000, 0x018fff) AM_READWRITE(tc0091lvc_vram0_r, tc0091lvc_vram0_w) + AM_RANGE(0x019000, 0x019fff) AM_READWRITE(tc0091lvc_vram1_r, tc0091lvc_vram1_w) + AM_RANGE(0x01a000, 0x01afff) AM_READWRITE(tc0091lvc_tvram_r, tc0091lvc_tvram_w) + AM_RANGE(0x01b000, 0x01bfff) AM_READWRITE(tc0091lvc_spr_r, tc0091lvc_spr_w) + AM_RANGE(0x01c000, 0x01ffff) AM_READWRITE(tc0091lvc_pcg2_r, tc0091lvc_pcg2_w) + AM_RANGE(0x040000, 0x05ffff) AM_READWRITE(tc0091lvc_bitmap_r, tc0091lvc_bitmap_w) + AM_RANGE(0x080000, 0x0801ff) AM_READWRITE(tc0091lvc_paletteram_r,tc0091lvc_paletteram_w) +ADDRESS_MAP_END + +tc0091lvc_device::tc0091lvc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, TC0091LVC, "Taito TC0091LVC", tag, owner, clock, "tc0091lvc", __FILE__), + device_memory_interface(mconfig, *this), + m_space_config("tc0091lvc", ENDIANNESS_LITTLE, 8,20, 0, NULL, *ADDRESS_MAP_NAME(tc0091lvc_map8)), + m_gfxdecode(*this), + m_palette(*this) +{ +} + +//------------------------------------------------- +// static_set_gfxdecode_tag: Set the tag of the +// gfx decoder +//------------------------------------------------- + +void tc0091lvc_device::static_set_gfxdecode_tag(device_t &device, const char *tag) +{ + downcast(device).m_gfxdecode.set_tag(tag); +} + + +//------------------------------------------------- +// static_set_palette_tag: Set the tag of the +// palette device +//------------------------------------------------- + +void tc0091lvc_device::static_set_palette_tag(device_t &device, const char *tag) +{ + downcast(device).m_palette.set_tag(tag); +} + + +void tc0091lvc_device::device_config_complete() +{ +// int address_bits = 20; + +// m_space_config = address_space_config("janshi_vdp", ENDIANNESS_LITTLE, 8, address_bits, 0, *ADDRESS_MAP_NAME(tc0091lvc_map8)); +} + +void tc0091lvc_device::device_validity_check(validity_checker &valid) const +{ +} + +TILE_GET_INFO_MEMBER(tc0091lvc_device::get_bg0_tile_info) +{ + int attr = m_vram0[2 * tile_index + 1]; + int code = m_vram0[2 * tile_index] + | ((attr & 0x03) << 8) + | ((m_vregs[(attr & 0xc) >> 2]) << 10); +// | (state->m_horshoes_gfxbank << 12); + + SET_TILE_INFO_MEMBER(0, + code, + (attr & 0xf0) >> 4, + 0); +} + +TILE_GET_INFO_MEMBER(tc0091lvc_device::get_bg1_tile_info) +{ + int attr = m_vram1[2 * tile_index + 1]; + int code = m_vram1[2 * tile_index] + | ((attr & 0x03) << 8) + | ((m_vregs[(attr & 0xc) >> 2]) << 10); +// | (state->m_horshoes_gfxbank << 12); + + SET_TILE_INFO_MEMBER(0, + code, + (attr & 0xf0) >> 4, + 0); +} + +TILE_GET_INFO_MEMBER(tc0091lvc_device::get_tx_tile_info) +{ + int attr = m_tvram[2 * tile_index + 1]; + UINT16 code = m_tvram[2 * tile_index] + | ((attr & 0x07) << 8); + + SET_TILE_INFO_MEMBER(m_gfx_index, + code, + (attr & 0xf0) >> 4, + 0); +} + + +static const gfx_layout char_layout = +{ + 8, 8, + 0x10000 / (8 * 4), // need to specify exact number because we create dynamically + 4, + { 8, 12, 0, 4 }, + { 3, 2, 1, 0, 19, 18, 17, 16}, + { 0*32, 1*32, 2*32, 3*32, 4*32, 5*32, 6*32, 7*32 }, + 8*8*4 +}; + + +void tc0091lvc_device::device_start() +{ + if(!m_gfxdecode->started()) + throw device_missing_dependencies(); + + memset(m_palette_ram, 0, sizeof(m_palette_ram)); + memset(m_vregs, 0, sizeof(m_palette_ram)); + memset(m_bitmap_ram, 0, sizeof(m_palette_ram)); + memset(m_pcg_ram, 0, sizeof(m_pcg_ram)); + memset(m_sprram_buffer, 0, sizeof(m_sprram_buffer)); + + // note, the way tiles are addressed suggests that 0x0000-0x3fff of this might be usable, + // but we don't map it anywhere, so the first tiles are always blank at the moment. + m_pcg1_ram = m_pcg_ram + 0x4000; + m_pcg2_ram = m_pcg_ram + 0xc000; + m_vram0 = m_pcg_ram + 0x8000; + m_vram1 = m_pcg_ram + 0x9000; + m_tvram = m_pcg_ram + 0xa000; + m_sprram = m_pcg_ram + 0xb000; + + tx_tilemap = &machine().tilemap().create(m_gfxdecode, tilemap_get_info_delegate(FUNC(tc0091lvc_device::get_tx_tile_info),this),TILEMAP_SCAN_ROWS,8,8,64,32); + bg0_tilemap = &machine().tilemap().create(m_gfxdecode, tilemap_get_info_delegate(FUNC(tc0091lvc_device::get_bg0_tile_info),this),TILEMAP_SCAN_ROWS,8,8,64,32); + bg1_tilemap = &machine().tilemap().create(m_gfxdecode, tilemap_get_info_delegate(FUNC(tc0091lvc_device::get_bg1_tile_info),this),TILEMAP_SCAN_ROWS,8,8,64,32); + + tx_tilemap->set_transparent_pen(0); + bg0_tilemap->set_transparent_pen(0); + bg1_tilemap->set_transparent_pen(0); + + tx_tilemap->set_scrolldx(-8, -8); + bg0_tilemap->set_scrolldx(28, -11); + bg1_tilemap->set_scrolldx(38, -21); + + for (m_gfx_index = 0; m_gfx_index < MAX_GFX_ELEMENTS; m_gfx_index++) + if (m_gfxdecode->gfx(m_gfx_index) == 0) + break; + + //printf("m_gfx_index %d\n", m_gfx_index); + + m_gfxdecode->set_gfx(m_gfx_index, global_alloc(gfx_element(m_palette, char_layout, (UINT8 *)m_pcg_ram, 0, m_palette->entries() / 16, 0))); +} + +void tc0091lvc_device::device_reset() +{ +} + +const address_space_config *tc0091lvc_device::memory_space_config(address_spacenum spacenum) const +{ + return (spacenum == 0) ? &m_space_config : NULL; +} + + +void tc0091lvc_device::draw_sprites( screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect, UINT8 global_flip ) +{ + gfx_element *gfx = m_gfxdecode->gfx(1); + int count; + + for(count=0;count<0x3e7;count+=8) + { + int x,y,spr_offs,col,fx,fy; + + spr_offs = m_sprram_buffer[count+0]|(m_sprram_buffer[count+1]<<8); + x = m_sprram_buffer[count+4]|(m_sprram_buffer[count+5]<<8); + if (x >= 320) + x -= 512; + y = m_sprram_buffer[count+6]; + col = (m_sprram_buffer[count+2])&0x0f; + fx = m_sprram_buffer[count+3] & 0x1; + fy = m_sprram_buffer[count+3] & 0x2; + + if (global_flip) + { + x = 304 - x; + y = 240 - y; + fx = !fx; + fy = !fy; + } + + gfx->prio_transpen(bitmap,cliprect,spr_offs,col,fx,fy,x,y,screen.priority(),(col & 0x08) ? 0xaa : 0x00,0); + } +} + +UINT32 tc0091lvc_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) +{ + UINT32 count; + int x,y; + UINT8 global_flip; + + bitmap.fill(m_palette->black_pen(), cliprect); + + if((m_vregs[4] & 0x20) == 0) + return 0; + + global_flip = m_vregs[4] & 0x10; + + if((m_vregs[4] & 0x7) == 7) // 8bpp bitmap enabled + { + count = 0; + + for (y=0;y<256;y++) + { + for (x=0;x<512;x++) + { + int res_x, res_y; + + res_x = (global_flip) ? 320-x : x; + res_y = (global_flip) ? 256-y : y; + + if(screen.visible_area().contains(res_x, res_y)) + bitmap.pix16(res_y, res_x) = m_palette->pen(m_bitmap_ram[count]); + + count++; + } + } + } + else + { + int dx, dy; + + machine().tilemap().set_flip_all(global_flip ? (TILEMAP_FLIPY | TILEMAP_FLIPX) : 0); + + dx = m_bg0_scroll[0] | (m_bg0_scroll[1] << 8); + if (global_flip) { dx = ((dx & 0xfffc) | ((dx - 3) & 0x0003)) ^ 0xf; dx += 192; } + dy = m_bg0_scroll[2]; + + bg0_tilemap->set_scrollx(0, -dx); + bg0_tilemap->set_scrolly(0, -dy); + + dx = m_bg1_scroll[0] | (m_bg1_scroll[1] << 8); + if (global_flip) { dx = ((dx & 0xfffc) | ((dx - 3) & 0x0003)) ^ 0xf; dx += 192; } + dy = m_bg1_scroll[2]; + + bg1_tilemap->set_scrollx(0, -dx); + bg1_tilemap->set_scrolly(0, -dy); + + tx_tilemap->set_scrollx(0, (global_flip) ? -192 : 0); + + screen.priority().fill(0, cliprect); + bg1_tilemap->draw(screen, bitmap, cliprect, 0,0); + bg0_tilemap->draw(screen, bitmap, cliprect, 0,(m_vregs[4] & 0x8) ? 0 : 1); + draw_sprites(screen, bitmap, cliprect, global_flip); + tx_tilemap->draw(screen, bitmap, cliprect, 0,0); + } + return 0; +} + +void tc0091lvc_device::screen_eof(void) +{ + memcpy(m_sprram_buffer,m_sprram,0x400); + m_bg0_scroll[0] = m_sprram_buffer[0x3f4]; + m_bg0_scroll[1] = m_sprram_buffer[0x3f5]; + m_bg0_scroll[2] = m_sprram_buffer[0x3f6]; + + m_bg1_scroll[0] = m_sprram_buffer[0x3fc]; + m_bg1_scroll[1] = m_sprram_buffer[0x3fd]; + m_bg1_scroll[2] = m_sprram_buffer[0x3fe]; +} diff --git a/src/devices/machine/tc009xlvc.h b/src/devices/machine/tc009xlvc.h new file mode 100644 index 00000000000..de7e20a5c43 --- /dev/null +++ b/src/devices/machine/tc009xlvc.h @@ -0,0 +1,98 @@ +// license:LGPL-2.1+ +// copyright-holders:Angelo Salese +/*************************************************************************** + + TC0091LVC device + +***************************************************************************/ + +#pragma once + +#ifndef __ramdacDEV_H__ +#define __ramdacDEV_H__ + +#include "emu.h" + +class tc0091lvc_device : public device_t, + public device_memory_interface +{ +public: + tc0091lvc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // static configuration + static void static_set_gfxdecode_tag(device_t &device, const char *tag); + static void static_set_palette_tag(device_t &device, const char *tag); + + DECLARE_READ8_MEMBER( vregs_r ); + DECLARE_WRITE8_MEMBER( vregs_w ); + + DECLARE_READ8_MEMBER( tc0091lvc_paletteram_r ); + DECLARE_WRITE8_MEMBER( tc0091lvc_paletteram_w ); + DECLARE_READ8_MEMBER( tc0091lvc_bitmap_r ); + DECLARE_WRITE8_MEMBER( tc0091lvc_bitmap_w ); + DECLARE_READ8_MEMBER( tc0091lvc_pcg1_r ); + DECLARE_WRITE8_MEMBER( tc0091lvc_pcg1_w ); + DECLARE_READ8_MEMBER( tc0091lvc_pcg2_r ); + DECLARE_WRITE8_MEMBER( tc0091lvc_pcg2_w ); + DECLARE_READ8_MEMBER( tc0091lvc_vram0_r ); + DECLARE_WRITE8_MEMBER( tc0091lvc_vram0_w ); + DECLARE_READ8_MEMBER( tc0091lvc_vram1_r ); + DECLARE_WRITE8_MEMBER( tc0091lvc_vram1_w ); + DECLARE_READ8_MEMBER( tc0091lvc_spr_r ); + DECLARE_WRITE8_MEMBER( tc0091lvc_spr_w ); + DECLARE_READ8_MEMBER( tc0091lvc_tvram_r ); + DECLARE_WRITE8_MEMBER( tc0091lvc_tvram_w ); + + DECLARE_WRITE8_MEMBER( tc0091lvc_bg0_scroll_w ); + DECLARE_WRITE8_MEMBER( tc0091lvc_bg1_scroll_w ); + + TILE_GET_INFO_MEMBER(get_bg0_tile_info); + TILE_GET_INFO_MEMBER(get_bg1_tile_info); + TILE_GET_INFO_MEMBER(get_tx_tile_info); + + UINT8 *m_pcg1_ram; + UINT8 *m_pcg2_ram; + UINT8 *m_vram0; + UINT8 *m_vram1; + UINT8 *m_sprram; + UINT8 *m_tvram; + UINT8 m_bg0_scroll[4]; + UINT8 m_bg1_scroll[4]; + + tilemap_t *bg0_tilemap; + tilemap_t *bg1_tilemap; + tilemap_t *tx_tilemap; + + int m_gfx_index; // for RAM tiles + + UINT8 m_palette_ram[0x200]; + UINT8 m_vregs[0x100]; + UINT8 m_bitmap_ram[0x20000]; + UINT8 m_pcg_ram[0x10000]; + UINT8 m_sprram_buffer[0x400]; + + UINT32 screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); + void draw_sprites( screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect, UINT8 global_flip); + void screen_eof(void); + +protected: + virtual void device_config_complete(); + virtual void device_validity_check(validity_checker &valid) const; + virtual void device_start(); + virtual void device_reset(); + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const; + address_space_config m_space_config; + required_device m_gfxdecode; + required_device m_palette; +}; + +extern const device_type TC0091LVC; + +#define MCFG_TC0091LVC_GFXDECODE(_gfxtag) \ + tc0091lvc_device::static_set_gfxdecode_tag(*device, "^" _gfxtag); + +#define MCFG_TC0091LVC_PALETTE(_palette_tag) \ + tc0091lvc_device::static_set_palette_tag(*device, "^" _palette_tag); + + +#endif diff --git a/src/devices/machine/terminal.c b/src/devices/machine/terminal.c new file mode 100644 index 00000000000..f46bcd3156e --- /dev/null +++ b/src/devices/machine/terminal.c @@ -0,0 +1,411 @@ +// license:BSD-3-Clause +// copyright-holders:Miodrag Milanovic +#include "machine/terminal.h" + +#define KEYBOARD_TAG "keyboard" + +/*************************************************************************** + IMPLEMENTATION +***************************************************************************/ + +static const UINT8 terminal_font[256*16] = +{ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x92, 0x44, 0x92, 0x44, 0x92, 0x44, 0x92, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x88, 0x88, 0xf8, 0x88, 0x88, 0x3e, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xf0, 0x80, 0xe0, 0x80, 0x9e, 0x10, 0x1c, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x78, 0x80, 0x80, 0x78, 0x3c, 0x22, 0x3c, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x80, 0x80, 0xf8, 0x3e, 0x20, 0x3c, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x38, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x10, 0x10, 0xfe, 0x10, 0x10, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x88, 0xc8, 0xa8, 0x98, 0x88, 0x20, 0x20, 0x20, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x88, 0x88, 0x50, 0x20, 0x3e, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x10, 0x10, 0x10, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xf0, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x1f, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x10, 0x10, 0x10, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x10, 0x10, 0x10, 0xff, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x10, 0x10, 0x10, 0x1f, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x10, 0x10, 0x10, 0xf0, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x10, 0x10, 0x10, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x02, 0x08, 0x20, 0x80, 0x20, 0x08, 0x02, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x20, 0x08, 0x02, 0x08, 0x20, 0x80, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xfe, 0x24, 0x24, 0x24, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x02, 0x04, 0xfe, 0x10, 0xfe, 0x40, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x1c, 0x22, 0x20, 0xf8, 0x20, 0x78, 0xa6, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x24, 0x24, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x48, 0x48, 0xfc, 0x48, 0xfc, 0x48, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x7c, 0x90, 0x7c, 0x12, 0x7c, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xc2, 0xc4, 0x08, 0x10, 0x20, 0x46, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x70, 0x88, 0x88, 0x70, 0x8a, 0x84, 0x7a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x18, 0x10, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x08, 0x10, 0x20, 0x20, 0x20, 0x10, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x20, 0x10, 0x08, 0x08, 0x08, 0x10, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x44, 0x28, 0xfe, 0x28, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x10, 0x10, 0xfe, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x20, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x38, 0x44, 0x82, 0x82, 0x82, 0x44, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x30, 0x50, 0x10, 0x10, 0x10, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x78, 0x84, 0x02, 0x1c, 0x60, 0x80, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xfe, 0x04, 0x08, 0x1c, 0x02, 0x82, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x08, 0x18, 0x28, 0x48, 0xfe, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xfe, 0x80, 0xbc, 0xc2, 0x02, 0x82, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x3c, 0x42, 0x80, 0xbc, 0xc2, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xfe, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x7c, 0x82, 0x82, 0x7c, 0x82, 0x82, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x78, 0x84, 0x86, 0x7a, 0x02, 0x84, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x20, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x02, 0x08, 0x20, 0x80, 0x20, 0x08, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xfe, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x20, 0x08, 0x02, 0x08, 0x20, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x7c, 0x82, 0x0c, 0x10, 0x10, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x7c, 0x82, 0x8a, 0x92, 0x9c, 0x80, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x28, 0x44, 0x82, 0xfe, 0x82, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xfc, 0x42, 0x42, 0x7c, 0x42, 0x42, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x3c, 0x42, 0x80, 0x80, 0x80, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xf8, 0x44, 0x42, 0x42, 0x42, 0x44, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xfe, 0x80, 0x80, 0xf8, 0x80, 0x80, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xfe, 0x80, 0x80, 0xf8, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x3c, 0x42, 0x80, 0x80, 0x8e, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x82, 0x82, 0x82, 0xfe, 0x82, 0x82, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x7c, 0x10, 0x10, 0x10, 0x10, 0x10, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x0e, 0x04, 0x04, 0x04, 0x04, 0x84, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x82, 0x8c, 0xb0, 0xc0, 0xb0, 0x8c, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x82, 0xc6, 0xaa, 0x92, 0x82, 0x82, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x82, 0xc2, 0xa2, 0x92, 0x8a, 0x86, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x7c, 0x82, 0x82, 0x82, 0x82, 0x82, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xfc, 0x82, 0x82, 0xfc, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x7c, 0x82, 0x82, 0x82, 0x8a, 0x84, 0x7a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xfc, 0x82, 0x82, 0xfc, 0x88, 0x84, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x7c, 0x82, 0x80, 0x7c, 0x02, 0x82, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xfe, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x82, 0x82, 0x44, 0x44, 0x28, 0x28, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x82, 0x82, 0x82, 0x92, 0x92, 0xaa, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x82, 0x44, 0x28, 0x10, 0x28, 0x44, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x82, 0x44, 0x28, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xfe, 0x04, 0x08, 0x10, 0x20, 0x40, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x3c, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x78, 0x08, 0x08, 0x08, 0x08, 0x08, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x28, 0x44, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x30, 0x10, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x7c, 0x02, 0x7e, 0x82, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x80, 0xbc, 0xc2, 0x82, 0xc2, 0xbc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x3c, 0x42, 0x80, 0x40, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x02, 0x02, 0x7a, 0x86, 0x82, 0x86, 0x7a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x7c, 0x82, 0xfe, 0x80, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x1c, 0x22, 0x20, 0xf8, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x7c, 0x84, 0x84, 0x7c, 0x04, 0x84, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,//g + 0x00, 0x80, 0x80, 0xbc, 0xc2, 0x82, 0x82, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x00, 0x30, 0x10, 0x10, 0x10, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x04, 0x00, 0x04, 0x04, 0x04, 0x04, 0x84, 0x84, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x80, 0x88, 0x90, 0xe0, 0x88, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x30, 0x10, 0x10, 0x10, 0x10, 0x10, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xc4, 0xaa, 0x92, 0x92, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xbc, 0xc2, 0x82, 0x82, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x7c, 0x82, 0x82, 0x82, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xbc, 0xc2, 0xc2, 0xbc, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x7a, 0x86, 0x86, 0x7a, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x9c, 0x62, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x7c, 0x80, 0x7c, 0x02, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x20, 0x20, 0xf8, 0x20, 0x20, 0x24, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x84, 0x84, 0x84, 0x84, 0x7a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x82, 0x82, 0x44, 0x28, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x82, 0x82, 0x92, 0xaa, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x84, 0x48, 0x30, 0x48, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x84, 0x84, 0x8c, 0x74, 0x04, 0x84, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xfe, 0x04, 0x18, 0x20, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x0e, 0x10, 0x10, 0x60, 0x10, 0x10, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x10, 0x10, 0x00, 0x00, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xe0, 0x10, 0x10, 0x0c, 0x10, 0x10, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x62, 0x92, 0x8c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +generic_terminal_device::generic_terminal_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + m_palette(*this, "palette"), + m_io_term_conf(*this, "TERM_CONF"), + m_keyboard_cb(*this) +{ +} + +generic_terminal_device::generic_terminal_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, GENERIC_TERMINAL, "Generic Terminal", tag, owner, clock, "generic_terminal", __FILE__), + m_palette(*this, "palette"), + m_io_term_conf(*this, "TERM_CONF"), + m_keyboard_cb(*this) +{ +} + +void generic_terminal_device::scroll_line() +{ + memmove(m_buffer,m_buffer+TERMINAL_WIDTH,(TERMINAL_HEIGHT-1)*TERMINAL_WIDTH); + memset(m_buffer + TERMINAL_WIDTH*(TERMINAL_HEIGHT-1),0x20,TERMINAL_WIDTH); +} + +void generic_terminal_device::write_char(UINT8 data) +{ + m_buffer[m_y_pos*TERMINAL_WIDTH+m_x_pos] = data; + m_x_pos++; + if (m_x_pos >= TERMINAL_WIDTH) + { + m_x_pos = 0; + m_y_pos++; + if (m_y_pos >= TERMINAL_HEIGHT) + { + scroll_line(); + m_y_pos = TERMINAL_HEIGHT-1; + } + } +} + +void generic_terminal_device::clear() +{ + memset(m_buffer,0x20,TERMINAL_WIDTH*TERMINAL_HEIGHT); + m_x_pos = 0; + m_y_pos = 0; +} + +void generic_terminal_device::term_write(UINT8 data) +{ + if (data > 0x1f) + { + // printable char + if (data!=0x7f) write_char(data); + } + else + { + switch(data) + { + case 0x07 : // bell + break; + + case 0x08: if (m_x_pos) m_x_pos--; + break; + + case 0x09: m_x_pos = (m_x_pos & 0xf8) + 8; + if (m_x_pos >= TERMINAL_WIDTH) + m_x_pos = TERMINAL_WIDTH-1; + break; + + case 0x0a: m_y_pos++; + m_x_pos = 0; + if (m_y_pos >= TERMINAL_HEIGHT) + { + scroll_line(); + m_y_pos = TERMINAL_HEIGHT-1; + } + break; + + case 0x0b: if (m_y_pos) m_y_pos--; + break; + + case 0x0c: clear(); + break; + + case 0x0d: m_x_pos = 0; + break; + + case 0x1e: m_x_pos = 0; + m_y_pos = 0; + break; + } + } +} + +/*************************************************************************** + VIDEO HARDWARE +***************************************************************************/ +UINT32 generic_terminal_device::update(screen_device &device, bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + UINT8 options = m_io_term_conf->read(); + UINT16 cursor = m_y_pos * TERMINAL_WIDTH + m_x_pos; + UINT8 y,ra,chr,gfx; + UINT16 sy=0,ma=0,x; + + switch (options & 0x30) + { + case 0x10: + m_palette->set_pen_color(1, rgb_t(0xf7, 0xaa, 0x00)); + break; + case 0x20: + m_palette->set_pen_color(1, rgb_t::white); + break; + default: + m_palette->set_pen_color(1, rgb_t(0x00, 0xff, 0x00)); + break; + } + pen_t font_color = m_palette->pen(1); + + m_framecnt++; + + for (y = 0; y < TERMINAL_HEIGHT; y++) + { + for (ra = 0; ra < 10; ra++) + { + UINT32 *p = &bitmap.pix32(sy++); + + for (x = ma; x < ma + TERMINAL_WIDTH; x++) + { + chr = m_buffer[x]; + gfx = terminal_font[(chr<<4) | ra ]; + + if ((x == cursor) && (options & 1)) // at cursor position and want a cursor + { + if ((options & 2) || (ra == 9)) // block, or underline & at bottom line + { + if ((options & 4) && (m_framecnt & 8)) // want blink & time to blink + { + } + else + { + if (options & 8) + gfx ^= 0xff; // invert + else + gfx |= 0xff; // overwrite + } + } + } + + /* Display a scanline of a character */ + *p++ = (BIT( gfx, 7 ))?font_color:0; + *p++ = (BIT( gfx, 6 ))?font_color:0; + *p++ = (BIT( gfx, 5 ))?font_color:0; + *p++ = (BIT( gfx, 4 ))?font_color:0; + *p++ = (BIT( gfx, 3 ))?font_color:0; + *p++ = (BIT( gfx, 2 ))?font_color:0; + *p++ = (BIT( gfx, 1 ))?font_color:0; + *p++ = (BIT( gfx, 0 ))?font_color:0; + } + } + ma+=TERMINAL_WIDTH; + } + return 0; +} + +WRITE8_MEMBER( generic_terminal_device::kbd_put ) +{ + if (data) + send_key(data); +} + +/*************************************************************************** + VIDEO HARDWARE +***************************************************************************/ + +static MACHINE_CONFIG_FRAGMENT( generic_terminal ) + MCFG_SCREEN_ADD(TERMINAL_SCREEN_TAG, RASTER) + MCFG_SCREEN_REFRESH_RATE(50) + MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(2500)) /* not accurate */ + MCFG_SCREEN_SIZE(TERMINAL_WIDTH*8, TERMINAL_HEIGHT*10) + MCFG_SCREEN_VISIBLE_AREA(0, TERMINAL_WIDTH*8-1, 0, TERMINAL_HEIGHT*10-1) + MCFG_SCREEN_UPDATE_DEVICE(DEVICE_SELF, generic_terminal_device, update) + + MCFG_PALETTE_ADD_MONOCHROME_GREEN("palette") + + MCFG_DEVICE_ADD(KEYBOARD_TAG, GENERIC_KEYBOARD, 0) + MCFG_GENERIC_KEYBOARD_CB(WRITE8(generic_terminal_device, kbd_put)) +MACHINE_CONFIG_END + +machine_config_constructor generic_terminal_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME(generic_terminal); +} + +void generic_terminal_device::device_start() +{ + m_keyboard_cb.resolve_safe(); + save_item(NAME(m_buffer)); + save_item(NAME(m_x_pos)); + save_item(NAME(m_framecnt)); + save_item(NAME(m_y_pos)); +} + +void generic_terminal_device::device_reset() +{ + clear(); + m_framecnt = 0; +} + +/* +Char Dec Oct Hex | Char Dec Oct Hex | Char Dec Oct Hex | Char Dec Oct Hex +------------------------------------------------------------------------------------- +(nul) 0 0000 0x00 | (sp) 32 0040 0x20 | @ 64 0100 0x40 | ` 96 0140 0x60 +(soh) 1 0001 0x01 | ! 33 0041 0x21 | A 65 0101 0x41 | a 97 0141 0x61 +(stx) 2 0002 0x02 | " 34 0042 0x22 | B 66 0102 0x42 | b 98 0142 0x62 +(etx) 3 0003 0x03 | # 35 0043 0x23 | C 67 0103 0x43 | c 99 0143 0x63 +(eot) 4 0004 0x04 | $ 36 0044 0x24 | D 68 0104 0x44 | d 100 0144 0x64 +(enq) 5 0005 0x05 | % 37 0045 0x25 | E 69 0105 0x45 | e 101 0145 0x65 +(ack) 6 0006 0x06 | & 38 0046 0x26 | F 70 0106 0x46 | f 102 0146 0x66 +(bel) 7 0007 0x07 | ' 39 0047 0x27 | G 71 0107 0x47 | g 103 0147 0x67 +(bs) 8 0010 0x08 | ( 40 0050 0x28 | H 72 0110 0x48 | h 104 0150 0x68 +(ht) 9 0011 0x09 | ) 41 0051 0x29 | I 73 0111 0x49 | i 105 0151 0x69 +(nl) 10 0012 0x0a | * 42 0052 0x2a | J 74 0112 0x4a | j 106 0152 0x6a +(vt) 11 0013 0x0b | + 43 0053 0x2b | K 75 0113 0x4b | k 107 0153 0x6b +(np) 12 0014 0x0c | , 44 0054 0x2c | L 76 0114 0x4c | l 108 0154 0x6c +(cr) 13 0015 0x0d | - 45 0055 0x2d | M 77 0115 0x4d | m 109 0155 0x6d +(so) 14 0016 0x0e | . 46 0056 0x2e | N 78 0116 0x4e | n 110 0156 0x6e +(si) 15 0017 0x0f | / 47 0057 0x2f | O 79 0117 0x4f | o 111 0157 0x6f +(dle) 16 0020 0x10 | 0 48 0060 0x30 | P 80 0120 0x50 | p 112 0160 0x70 +(dc1) 17 0021 0x11 | 1 49 0061 0x31 | Q 81 0121 0x51 | q 113 0161 0x71 +(dc2) 18 0022 0x12 | 2 50 0062 0x32 | R 82 0122 0x52 | r 114 0162 0x72 +(dc3) 19 0023 0x13 | 3 51 0063 0x33 | S 83 0123 0x53 | s 115 0163 0x73 +(dc4) 20 0024 0x14 | 4 52 0064 0x34 | T 84 0124 0x54 | t 116 0164 0x74 +(nak) 21 0025 0x15 | 5 53 0065 0x35 | U 85 0125 0x55 | u 117 0165 0x75 +(syn) 22 0026 0x16 | 6 54 0066 0x36 | V 86 0126 0x56 | v 118 0166 0x76 +(etb) 23 0027 0x17 | 7 55 0067 0x37 | W 87 0127 0x57 | w 119 0167 0x77 +(can) 24 0030 0x18 | 8 56 0070 0x38 | X 88 0130 0x58 | x 120 0170 0x78 +(em) 25 0031 0x19 | 9 57 0071 0x39 | Y 89 0131 0x59 | y 121 0171 0x79 +(sub) 26 0032 0x1a | : 58 0072 0x3a | Z 90 0132 0x5a | z 122 0172 0x7a +(esc) 27 0033 0x1b | ; 59 0073 0x3b | [ 91 0133 0x5b | { 123 0173 0x7b +(fs) 28 0034 0x1c | < 60 0074 0x3c | \ 92 0134 0x5c | | 124 0174 0x7c +(gs) 29 0035 0x1d | = 61 0075 0x3d | ] 93 0135 0x5d | } 125 0175 0x7d +(rs) 30 0036 0x1e | > 62 0076 0x3e | ^ 94 0136 0x5e | ~ 126 0176 0x7e +(us) 31 0037 0x1f | ? 63 0077 0x3f | _ 95 0137 0x5f | (del) 127 0177 0x7f + +*/ +INPUT_PORTS_START( generic_terminal ) + PORT_START("TERM_CONF") + PORT_CONFNAME( 0x01, 0x01, "Cursor") + PORT_CONFSETTING( 0x00, DEF_STR(No)) + PORT_CONFSETTING( 0x01, DEF_STR(Yes)) + PORT_CONFNAME( 0x02, 0x02, "Type") + PORT_CONFSETTING( 0x00, "Underline") + PORT_CONFSETTING( 0x02, "Block") + PORT_CONFNAME( 0x04, 0x04, "Blinking") + PORT_CONFSETTING( 0x00, DEF_STR(No)) + PORT_CONFSETTING( 0x04, DEF_STR(Yes)) + PORT_CONFNAME( 0x08, 0x08, "Invert") + PORT_CONFSETTING( 0x00, DEF_STR(No)) + PORT_CONFSETTING( 0x08, DEF_STR(Yes)) + PORT_CONFNAME( 0x30, 0x00, "Color") + PORT_CONFSETTING( 0x00, "Green") + PORT_CONFSETTING( 0x10, "Amber") + PORT_CONFSETTING( 0x20, "White") +INPUT_PORTS_END + +ioport_constructor generic_terminal_device::device_input_ports() const +{ + return INPUT_PORTS_NAME(generic_terminal); +} + +const device_type GENERIC_TERMINAL = &device_creator; diff --git a/src/devices/machine/terminal.h b/src/devices/machine/terminal.h new file mode 100644 index 00000000000..0a0e2ff9b77 --- /dev/null +++ b/src/devices/machine/terminal.h @@ -0,0 +1,63 @@ +// license:BSD-3-Clause +// copyright-holders:Miodrag Milanovic +#ifndef __TERMINAL_H__ +#define __TERMINAL_H__ + +#include "machine/keyboard.h" + +#define TERMINAL_SCREEN_TAG "terminal_screen" + +/*************************************************************************** + DEVICE CONFIGURATION MACROS +***************************************************************************/ + +#define MCFG_GENERIC_TERMINAL_KEYBOARD_CB(_devcb) \ + devcb = &generic_terminal_device::set_keyboard_callback(*device, DEVCB_##_devcb); + +/*************************************************************************** + FUNCTION PROTOTYPES +***************************************************************************/ + +#define TERMINAL_WIDTH 80 +#define TERMINAL_HEIGHT 24 + +INPUT_PORTS_EXTERN( generic_terminal ); + +class generic_terminal_device : public device_t +{ +public: + generic_terminal_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + generic_terminal_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + template static devcb_base &set_keyboard_callback(device_t &device, _Object object) { return downcast(device).m_keyboard_cb.set_callback(object); } + + DECLARE_WRITE8_MEMBER(write) { term_write(data); } + DECLARE_WRITE8_MEMBER(kbd_put); + UINT32 update(screen_device &device, bitmap_rgb32 &bitmap, const rectangle &cliprect); + + virtual ioport_constructor device_input_ports() const; + virtual machine_config_constructor device_mconfig_additions() const; +protected: + optional_device m_palette; + required_ioport m_io_term_conf; + + virtual void term_write(UINT8 data); + virtual void device_start(); + virtual void device_reset(); + virtual void send_key(UINT8 code) { m_keyboard_cb((offs_t)0, code); } + UINT8 m_buffer[TERMINAL_WIDTH*50]; // make big enough for teleprinter + UINT8 m_x_pos; +private: + void scroll_line(); + void write_char(UINT8 data); + void clear(); + + UINT8 m_framecnt; + UINT8 m_y_pos; + + devcb_write8 m_keyboard_cb; +}; + +extern const device_type GENERIC_TERMINAL; + +#endif /* __TERMINAL_H__ */ diff --git a/src/devices/machine/timekpr.c b/src/devices/machine/timekpr.c new file mode 100644 index 00000000000..940fa84f259 --- /dev/null +++ b/src/devices/machine/timekpr.c @@ -0,0 +1,437 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles,smf +/*************************************************************************** + + timekpr.h + + Various ST Microelectronics timekeeper SRAM implementations: + - M48T02 + - M48T35 + - M48T37 + - M48T58 + - MK48T08 + +***************************************************************************/ + +#include "emu.h" +#include "machine/timekpr.h" + + +// device type definition +const device_type M48T02 = &device_creator; +const device_type M48T35 = &device_creator; +const device_type M48T37 = &device_creator; +const device_type M48T58 = &device_creator; +const device_type MK48T08 = &device_creator; + + +/*************************************************************************** + MACROS +***************************************************************************/ + +#define MASK_SECONDS ( 0x7f ) +#define MASK_MINUTES ( 0x7f ) +#define MASK_HOURS ( 0x3f ) +#define MASK_DAY ( 0x07 ) +#define MASK_DATE ( 0x3f ) +#define MASK_MONTH ( 0x1f ) +#define MASK_YEAR ( 0xff ) +#define MASK_CENTURY ( 0xff ) + +#define CONTROL_W ( 0x80 ) +#define CONTROL_R ( 0x40 ) +#define CONTROL_S ( 0x20 ) /* not emulated */ +#define CONTROL_CALIBRATION ( 0x1f ) /* not emulated */ + +#define SECONDS_ST ( 0x80 ) + +#define DAY_FT ( 0x40 ) /* M48T37 - not emulated */ +#define DAY_CEB ( 0x20 ) /* M48T35/M48T58 */ +#define DAY_CB ( 0x10 ) /* M48T35/M48T58 */ + +#define DATE_BLE ( 0x80 ) /* M48T58: not emulated */ +#define DATE_BL ( 0x40 ) /* M48T58: not emulated */ + +#define FLAGS_BL ( 0x10 ) /* MK48T08/M48T37: not emulated */ +#define FLAGS_AF ( 0x40 ) /* M48T37: not emulated */ +#define FLAGS_WDF ( 0x80 ) /* M48T37: not emulated */ + + +/*************************************************************************** + INLINE FUNCTIONS +***************************************************************************/ + +INLINE UINT8 make_bcd(UINT8 data) +{ + return ( ( ( data / 10 ) % 10 ) << 4 ) + ( data % 10 ); +} + +INLINE UINT8 from_bcd( UINT8 data ) +{ + return ( ( ( data >> 4 ) & 15 ) * 10 ) + ( data & 15 ); +} + +static int inc_bcd( UINT8 *data, int mask, int min, int max ) +{ + int bcd; + int carry; + + bcd = ( *( data ) + 1 ) & mask; + carry = 0; + + if( ( bcd & 0x0f ) > 9 ) + { + bcd &= 0xf0; + bcd += 0x10; + if( bcd > max ) + { + bcd = min; + carry = 1; + } + } + + *( data ) = ( *( data ) & ~mask ) | ( bcd & mask ); + return carry; +} + +static void counter_to_ram( UINT8 *data, int offset, int counter ) +{ + if( offset >= 0 ) + { + data[ offset ] = counter; + } +} + +static int counter_from_ram( UINT8 *data, int offset ) +{ + if( offset >= 0 ) + { + return data[ offset ]; + } + return 0; +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// timekeeper_device_config - constructor +//------------------------------------------------- + +timekeeper_device::timekeeper_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_nvram_interface(mconfig, *this) +{ +} + +m48t02_device::m48t02_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : timekeeper_device(mconfig, M48T02, "M48T02 Timekeeper", tag, owner, clock, "m48t02", __FILE__) +{ + m_offset_control = 0x7f8; + m_offset_seconds = 0x7f9; + m_offset_minutes = 0x7fa; + m_offset_hours = 0x7fb; + m_offset_day = 0x7fc; + m_offset_date = 0x7fd; + m_offset_month = 0x7fe; + m_offset_year = 0x7ff; + m_offset_century = -1; + m_offset_flags = -1; + m_size = 0x800; +} + +m48t35_device::m48t35_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : timekeeper_device(mconfig, M48T35, "M48T35 Timekeeper", tag, owner, clock, "m48t35", __FILE__) +{ + m_offset_control = 0x7ff8; + m_offset_seconds = 0x7ff9; + m_offset_minutes = 0x7ffa; + m_offset_hours = 0x7ffb; + m_offset_day = 0x7ffc; + m_offset_date = 0x7ffd; + m_offset_month = 0x7ffe; + m_offset_year = 0x7fff; + m_offset_century = -1; + m_offset_flags = -1; + m_size = 0x8000; +} + +m48t37_device::m48t37_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : timekeeper_device(mconfig, M48T37, "M48T37 Timekeeper", tag, owner, clock, "m48t37", __FILE__) +{ + m_offset_control = 0x7ff8; + m_offset_seconds = 0x7ff9; + m_offset_minutes = 0x7ffa; + m_offset_hours = 0x7ffb; + m_offset_day = 0x7ffc; + m_offset_date = 0x7ffd; + m_offset_month = 0x7ffe; + m_offset_year = 0x7fff; + m_offset_century = 0x7ff1; + m_offset_flags = 0x7ff0; + m_size = 0x8000; +} + +m48t58_device::m48t58_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : timekeeper_device(mconfig, M48T58, "M48T58 Timekeeper", tag, owner, clock, "m48t58", __FILE__) +{ + m_offset_control = 0x1ff8; + m_offset_seconds = 0x1ff9; + m_offset_minutes = 0x1ffa; + m_offset_hours = 0x1ffb; + m_offset_day = 0x1ffc; + m_offset_date = 0x1ffd; + m_offset_month = 0x1ffe; + m_offset_year = 0x1fff; + m_offset_century = -1; + m_offset_flags = -1; + m_size = 0x2000; +} + +mk48t08_device::mk48t08_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : timekeeper_device(mconfig, MK48T08, "MK48T08 Timekeeper", tag, owner, clock, "m48t08", __FILE__) +{ + m_offset_control = 0x1ff8; + m_offset_seconds = 0x1ff9; + m_offset_minutes = 0x1ffa; + m_offset_hours = 0x1ffb; + m_offset_day = 0x1ffc; + m_offset_date = 0x1ffd; + m_offset_month = 0x1ffe; + m_offset_year = 0x1fff; + m_offset_century = 0x1ff1; + m_offset_flags = 0x1ff0; + m_size = 0x2000; +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void timekeeper_device::device_start() +{ + system_time systime; + + /* validate some basic stuff */ + assert(this != NULL); + + machine().base_datetime(systime); + + m_control = 0; + m_seconds = make_bcd( systime.local_time.second ); + m_minutes = make_bcd( systime.local_time.minute ); + m_hours = make_bcd( systime.local_time.hour ); + m_day = make_bcd( systime.local_time.weekday + 1 ); + m_date = make_bcd( systime.local_time.mday ); + m_month = make_bcd( systime.local_time.month + 1 ); + m_year = make_bcd( systime.local_time.year % 100 ); + m_century = make_bcd( systime.local_time.year / 100 ); + m_data.resize( m_size ); + + m_default_data = region()->base(); + if (m_default_data) + { + assert( region()->bytes() == m_size ); + } + + save_item( NAME(m_control) ); + save_item( NAME(m_seconds) ); + save_item( NAME(m_minutes) ); + save_item( NAME(m_hours) ); + save_item( NAME(m_day) ); + save_item( NAME(m_date) ); + save_item( NAME(m_month) ); + save_item( NAME(m_year) ); + save_item( NAME(m_century) ); + save_item( NAME(m_data) ); + + emu_timer *timer = timer_alloc(); + timer->adjust(attotime::from_seconds(1), 0, attotime::from_seconds(1)); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void timekeeper_device::device_reset() { } + +void timekeeper_device::counters_to_ram() +{ + counter_to_ram( &m_data[0], m_offset_control, m_control ); + counter_to_ram( &m_data[0], m_offset_seconds, m_seconds ); + counter_to_ram( &m_data[0], m_offset_minutes, m_minutes ); + counter_to_ram( &m_data[0], m_offset_hours, m_hours ); + counter_to_ram( &m_data[0], m_offset_day, m_day ); + counter_to_ram( &m_data[0], m_offset_date, m_date ); + counter_to_ram( &m_data[0], m_offset_month, m_month ); + counter_to_ram( &m_data[0], m_offset_year, m_year ); + counter_to_ram( &m_data[0], m_offset_century, m_century ); +} + +void timekeeper_device::counters_from_ram() +{ + m_control = counter_from_ram( &m_data[0], m_offset_control ); + m_seconds = counter_from_ram( &m_data[0], m_offset_seconds ); + m_minutes = counter_from_ram( &m_data[0], m_offset_minutes ); + m_hours = counter_from_ram( &m_data[0], m_offset_hours ); + m_day = counter_from_ram( &m_data[0], m_offset_day ); + m_date = counter_from_ram( &m_data[0], m_offset_date ); + m_month = counter_from_ram( &m_data[0], m_offset_month ); + m_year = counter_from_ram( &m_data[0], m_offset_year ); + m_century = counter_from_ram( &m_data[0], m_offset_century ); +} + +void timekeeper_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + if( ( m_seconds & SECONDS_ST ) != 0 || + ( m_control & CONTROL_W ) != 0 ) + { + return; + } + + int carry = inc_bcd( &m_seconds, MASK_SECONDS, 0x00, 0x59 ); + if( carry ) + { + carry = inc_bcd( &m_minutes, MASK_MINUTES, 0x00, 0x59 ); + } + if( carry ) + { + carry = inc_bcd( &m_hours, MASK_HOURS, 0x00, 0x23 ); + } + + if( carry ) + { + UINT8 maxdays; + static const UINT8 daysinmonth[] = { 0x31, 0x28, 0x31, 0x30, 0x31, 0x30, 0x31, 0x31, 0x30, 0x31, 0x30, 0x31 }; + + inc_bcd( &m_day, MASK_DAY, 0x01, 0x07 ); + + UINT8 month = from_bcd( m_month ); + UINT8 year = from_bcd( m_year ); + + if( month == 2 && ( year % 4 ) == 0 ) + { + maxdays = 0x29; + } + else if( month >= 1 && month <= 12 ) + { + maxdays = daysinmonth[ month - 1 ]; + } + else + { + maxdays = 0x31; + } + + carry = inc_bcd( &m_date, MASK_DATE, 0x01, maxdays ); + } + if( carry ) + { + carry = inc_bcd( &m_month, MASK_MONTH, 0x01, 0x12 ); + } + if( carry ) + { + carry = inc_bcd( &m_year, MASK_YEAR, 0x00, 0x99 ); + } + if( carry ) + { + carry = inc_bcd( &m_century, MASK_CENTURY, 0x00, 0x99 ); + + if( type() == M48T35 || + type() == M48T58 ) + { + if( ( m_day & DAY_CEB ) != 0 ) + { + m_day ^= DAY_CB; + } + } + } + + if( ( m_control & CONTROL_R ) == 0 ) + { + counters_to_ram(); + } +} + +WRITE8_MEMBER( timekeeper_device::write ) +{ + if( offset == m_offset_control ) + { + if( ( m_control & CONTROL_W ) != 0 && + ( data & CONTROL_W ) == 0 ) + { + counters_from_ram(); + } + m_control = data; + } + else if( offset == m_offset_day ) + { + if( type() == M48T35 || + type() == M48T58 ) + { + m_day = ( m_day & ~DAY_CEB ) | ( data & DAY_CEB ); + } + } + + m_data[ offset ] = data; +} + +READ8_MEMBER( timekeeper_device::read ) +{ + UINT8 result = m_data[ offset ]; + if( offset == m_offset_date && type() == M48T58 ) + { + result &= ~DATE_BL; + } + else if( offset == m_offset_flags && (type() == MK48T08 || type() == M48T37) ) + { + result = 0; + } + return result; +} + +//------------------------------------------------- +// nvram_default - called to initialize NVRAM to +// its default state +//------------------------------------------------- + +void timekeeper_device::nvram_default() +{ + if( m_default_data != NULL ) + { + memcpy( &m_data[0], m_default_data, m_size ); + } + else + { + memset( &m_data[0], 0xff, m_data.size()); + } + + if ( m_offset_flags >= 0 ) + m_data[ m_offset_flags ] = 0; + counters_to_ram(); +} + + +//------------------------------------------------- +// nvram_read - called to read NVRAM from the +// .nv file +//------------------------------------------------- + +void timekeeper_device::nvram_read(emu_file &file) +{ + file.read( &m_data[0], m_size ); + + counters_to_ram(); +} + + +//------------------------------------------------- +// nvram_write - called to write NVRAM to the +// .nv file +//------------------------------------------------- + +void timekeeper_device::nvram_write(emu_file &file) +{ + file.write( &m_data[0], m_size ); +} diff --git a/src/devices/machine/timekpr.h b/src/devices/machine/timekpr.h new file mode 100644 index 00000000000..6e72f9add62 --- /dev/null +++ b/src/devices/machine/timekpr.h @@ -0,0 +1,144 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles,smf +/*************************************************************************** + + timekpr.h + + Various ST Microelectronics timekeeper SRAM implementations: + - M48T02 + - M48T35 + - M48T37 + - M48T58 + - MK48T08 + +***************************************************************************/ + +#pragma once + +#ifndef __TIMEKPR_H__ +#define __TIMEKPR_H__ + +#include "emu.h" + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_M48T02_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, M48T02, 0) + +#define MCFG_M48T35_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, M48T35, 0) + +#define MCFG_M48T37_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, M48T37, 0) + +#define MCFG_M48T58_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, M48T58, 0) + +#define MCFG_MK48T08_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, MK48T08, 0) + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + + +// ======================> timekeeper_device + +class timekeeper_device : public device_t, + public device_nvram_interface +{ +protected: + // construction/destruction + timekeeper_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + +public: + DECLARE_WRITE8_MEMBER( write ); + DECLARE_READ8_MEMBER( read ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + // device_nvram_interface overrides + virtual void nvram_default(); + virtual void nvram_read(emu_file &file); + virtual void nvram_write(emu_file &file); + +private: + void counters_to_ram(); + void counters_from_ram(); + + // internal state + UINT8 m_control; + UINT8 m_seconds; + UINT8 m_minutes; + UINT8 m_hours; + UINT8 m_day; + UINT8 m_date; + UINT8 m_month; + UINT8 m_year; + UINT8 m_century; + + dynamic_buffer m_data; + UINT8 *m_default_data; + +protected: + int m_size; + int m_offset_control; + int m_offset_seconds; + int m_offset_minutes; + int m_offset_hours; + int m_offset_day; + int m_offset_date; + int m_offset_month; + int m_offset_year; + int m_offset_century; + int m_offset_flags; +}; + +class m48t02_device : public timekeeper_device +{ +public: + m48t02_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class m48t35_device : public timekeeper_device +{ +public: + m48t35_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class m48t37_device : public timekeeper_device +{ +public: + m48t37_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class m48t58_device : public timekeeper_device +{ +public: + m48t58_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class mk48t08_device : public timekeeper_device +{ +public: + mk48t08_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +// device type definition +extern const device_type M48T02; +extern const device_type M48T35; +extern const device_type M48T37; +extern const device_type M48T58; +extern const device_type MK48T08; + +#endif // __TIMEKPR_H__ diff --git a/src/devices/machine/tmp68301.c b/src/devices/machine/tmp68301.c new file mode 100644 index 00000000000..955a10c463b --- /dev/null +++ b/src/devices/machine/tmp68301.c @@ -0,0 +1,337 @@ +// license:BSD-3-Clause +// copyright-holders:Luca Elia +/*************************************************************************** + + TMP68301 basic emulation + Interrupt Handling + + The Toshiba TMP68301 is a 68HC000 + serial I/O, parallel I/O, + 3 timers, address decoder, wait generator, interrupt controller, + all integrated in a single chip. + + TODO: + - Interrupt generation: handle pending / in-service mechanisms + - Parallel port: handle timing latency + - Serial port: not done at all + - (and many other things) + +***************************************************************************/ + +#include "emu.h" +#include "machine/tmp68301.h" + +const device_type TMP68301 = &device_creator; + +static ADDRESS_MAP_START( tmp68301_regs, AS_0, 16, tmp68301_device ) +// AM_RANGE(0x000,0x3ff) AM_RAM + AM_RANGE(0x094,0x095) AM_READWRITE(imr_r,imr_w) + AM_RANGE(0x098,0x099) AM_READWRITE(iisr_r,iisr_w) + + /* Parallel Port */ + AM_RANGE(0x100,0x101) AM_READWRITE(pdir_r,pdir_w) + AM_RANGE(0x10a,0x10b) AM_READWRITE(pdr_r,pdr_w) + + /* Serial Port */ + AM_RANGE(0x18e,0x18f) AM_READWRITE(scr_r,scr_w) +ADDRESS_MAP_END + +// IRQ Mask register, 0x94 +READ16_MEMBER(tmp68301_device::imr_r) +{ + return m_imr; +} + +WRITE16_MEMBER(tmp68301_device::imr_w) +{ + COMBINE_DATA(&m_imr); +} + +// IRQ In-Service Register +READ16_MEMBER(tmp68301_device::iisr_r) +{ + return m_iisr; +} + +WRITE16_MEMBER(tmp68301_device::iisr_w) +{ + COMBINE_DATA(&m_iisr); +} + +// Serial Control Register (TODO: 8-bit wide) +READ16_MEMBER(tmp68301_device::scr_r) +{ + return m_scr; +} + +WRITE16_MEMBER(tmp68301_device::scr_w) +{ + /* + *--- ---- CKSE + --*- ---- RES + ---- ---* INTM + */ + + COMBINE_DATA(&m_scr); + m_scr &= 0xa1; +} + +/* Parallel direction: 1 = output, 0 = input */ +READ16_MEMBER(tmp68301_device::pdir_r) +{ + return m_pdir; +} + +WRITE16_MEMBER(tmp68301_device::pdir_w) +{ + COMBINE_DATA(&m_pdir); +} + +READ16_MEMBER(tmp68301_device::pdr_r) +{ + return (m_in_parallel_cb(0) & ~m_pdir) | (m_pdr & m_pdir); +} + +WRITE16_MEMBER(tmp68301_device::pdr_w) +{ + UINT16 old = m_pdr; + COMBINE_DATA(&m_pdr); + m_pdr = (old & ~m_pdir) | (m_pdr & m_pdir); + m_out_parallel_cb(0, m_pdr, mem_mask); +} + + +tmp68301_device::tmp68301_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, TMP68301, "TMP68301", tag, owner, clock, "tmp68301", __FILE__), + device_memory_interface(mconfig, *this), + m_in_parallel_cb(*this), + m_out_parallel_cb(*this), + m_imr(0), + m_iisr(0), + m_scr(0), + m_pdir(0), + m_pdr(0), + m_space_config("regs", ENDIANNESS_LITTLE, 16, 10, 0, NULL, *ADDRESS_MAP_NAME(tmp68301_regs)) +{ + memset(m_regs, 0, sizeof(m_regs)); + memset(m_IE, 0, sizeof(m_IE)); + memset(m_irq_vector, 0, sizeof(m_irq_vector)); +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void tmp68301_device::device_start() +{ + int i; + for (i = 0; i < 3; i++) + m_tmp68301_timer[i] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(tmp68301_device::timer_callback), this)); + + m_in_parallel_cb.resolve_safe(0); + m_out_parallel_cb.resolve_safe(); + + save_item(NAME(m_regs)); + save_item(NAME(m_IE)); + save_item(NAME(m_irq_vector)); + save_item(NAME(m_imr)); + save_item(NAME(m_iisr)); + save_item(NAME(m_scr)); + save_item(NAME(m_pdir)); + save_item(NAME(m_pdr)); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void tmp68301_device::device_reset() +{ + int i; + + for (i = 0; i < 3; i++) + m_IE[i] = 0; + + m_imr = 0x7f7; // mask all irqs +} + +//------------------------------------------------- +// memory_space_config - return a description of +// any address spaces owned by this device +//------------------------------------------------- + +const address_space_config *tmp68301_device::memory_space_config(address_spacenum spacenum) const +{ + return (spacenum == AS_0) ? &m_space_config : NULL; +} + +//************************************************************************** +// INLINE HELPERS +//************************************************************************** + +//------------------------------------------------- +// read_byte - read a byte at the given address +//------------------------------------------------- + +inline UINT16 tmp68301_device::read_word(offs_t address) +{ + return space(AS_0).read_word(address << 1); +} + +//------------------------------------------------- +// write_byte - write a byte at the given address +//------------------------------------------------- + +inline void tmp68301_device::write_word(offs_t address, UINT16 data) +{ + space(AS_0).write_word(address << 1, data); +} + +IRQ_CALLBACK_MEMBER(tmp68301_device::irq_callback) +{ + int vector = m_irq_vector[irqline]; +// logerror("%s: irq callback returns %04X for level %x\n",machine.describe_context(),vector,int_level); + return vector; +} + +TIMER_CALLBACK_MEMBER( tmp68301_device::timer_callback ) +{ + int i = param; + UINT16 TCR = m_regs[(0x200 + i * 0x20)/2]; + UINT16 ICR = m_regs[0x8e/2+i]; // Interrupt Controller Register (ICR7..9) + UINT16 IVNR = m_regs[0x9a/2]; // Interrupt Vector Number Register (IVNR) + +// logerror("s: callback timer %04X, j = %d\n",machine.describe_context(),i,tcount); + + if ( (TCR & 0x0004) && // INT + !(m_imr & (0x100<set_input_line(level,HOLD_LINE); + } + + if (TCR & 0x0080) // N/1 + { + // Repeat + update_timer(i); + } + else + { + // One Shot + } +} + +void tmp68301_device::update_timer( int i ) +{ + UINT16 TCR = m_regs[(0x200 + i * 0x20)/2]; + UINT16 MAX1 = m_regs[(0x204 + i * 0x20)/2]; + UINT16 MAX2 = m_regs[(0x206 + i * 0x20)/2]; + + int max = 0; + attotime duration = attotime::zero; + + m_tmp68301_timer[i]->adjust(attotime::never,i); + + // timers 1&2 only + switch( (TCR & 0x0030)>>4 ) // MR2..1 + { + case 1: + max = MAX1; + break; + case 2: + max = MAX2; + break; + } + + switch ( (TCR & 0xc000)>>14 ) // CK2..1 + { + case 0: // System clock (CLK) + if (max) + { + int scale = (TCR & 0x3c00)>>10; // P4..1 + if (scale > 8) scale = 8; + duration = attotime::from_hz(machine().firstcpu->unscaled_clock()) * ((1 << scale) * max); + } + break; + } + +// logerror("%s: TMP68301 Timer %d, duration %lf, max %04X\n",machine().describe_context(),i,duration,max); + + if (!(TCR & 0x0002)) // CS + { + if (duration != attotime::zero) + m_tmp68301_timer[i]->adjust(duration,i); + else + logerror("%s: TMP68301 error, timer %d duration is 0\n",machine().describe_context(),i); + } +} + +/* Update the IRQ state based on all possible causes */ +void tmp68301_device::update_irq_state() +{ + int i; + + /* Take care of external interrupts */ + + UINT16 IVNR = m_regs[0x9a/2]; // Interrupt Vector Number Register (IVNR) + + for (i = 0; i < 3; i++) + { + if ( (m_IE[i]) && + !(m_imr & (1<set_input_line(level,HOLD_LINE); + } + } +} + +READ16_MEMBER( tmp68301_device::regs_r ) +{ + return read_word(offset); +} + +WRITE16_MEMBER( tmp68301_device::regs_w ) +{ + COMBINE_DATA(&m_regs[offset]); + + write_word(offset,m_regs[offset]); + + if (!ACCESSING_BITS_0_7) return; + +// logerror("CPU #0 PC %06X: TMP68301 Reg %04X<-%04X & %04X\n",space.device().safe_pc(),offset*2,data,mem_mask^0xffff); + + switch( offset * 2 ) + { + // Timers + case 0x200: + case 0x220: + case 0x240: + { + int i = ((offset*2) >> 5) & 3; + + update_timer( i ); + } + break; + } +} + +void tmp68301_device::external_interrupt_0() { m_IE[0] = 1; update_irq_state(); } +void tmp68301_device::external_interrupt_1() { m_IE[1] = 1; update_irq_state(); } +void tmp68301_device::external_interrupt_2() { m_IE[2] = 1; update_irq_state(); } diff --git a/src/devices/machine/tmp68301.h b/src/devices/machine/tmp68301.h new file mode 100644 index 00000000000..b96296d31f2 --- /dev/null +++ b/src/devices/machine/tmp68301.h @@ -0,0 +1,90 @@ +// license:BSD-3-Clause +// copyright-holders:Luca Elia +#ifndef TMP68301_H +#define TMP68301_H + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +/* TODO: serial ports, frequency & hook it up with m68k */ +#define MCFG_TMP68301_IN_PARALLEL_CB(_devcb) \ + devcb = &tmp68301_device::set_in_parallel_callback(*device, DEVCB_##_devcb); + +#define MCFG_TMP68301_OUT_PARALLEL_CB(_devcb) \ + devcb = &tmp68301_device::set_out_parallel_callback(*device, DEVCB_##_devcb); + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + + + +class tmp68301_device : public device_t, + public device_memory_interface +{ +public: + tmp68301_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + ~tmp68301_device() {} + + template static devcb_base &set_in_parallel_callback(device_t &device, _Object object) { return downcast(device).m_in_parallel_cb.set_callback(object); } + template static devcb_base &set_out_parallel_callback(device_t &device, _Object object) { return downcast(device).m_out_parallel_cb.set_callback(object); } + + // Hardware Registers + DECLARE_READ16_MEMBER( regs_r ); + DECLARE_WRITE16_MEMBER( regs_w ); + + // Interrupts + void external_interrupt_0(); + void external_interrupt_1(); + void external_interrupt_2(); + + DECLARE_READ16_MEMBER(imr_r); + DECLARE_WRITE16_MEMBER(imr_w); + DECLARE_READ16_MEMBER(iisr_r); + DECLARE_WRITE16_MEMBER(iisr_w); + DECLARE_READ16_MEMBER(scr_r); + DECLARE_WRITE16_MEMBER(scr_w); + DECLARE_READ16_MEMBER(pdr_r); + DECLARE_WRITE16_MEMBER(pdr_w); + DECLARE_READ16_MEMBER(pdir_r); + DECLARE_WRITE16_MEMBER(pdir_w); + + IRQ_CALLBACK_MEMBER(irq_callback); +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const; + +private: + devcb_read16 m_in_parallel_cb; + devcb_write16 m_out_parallel_cb; + + // internal state + UINT16 m_regs[0x400]; + + UINT8 m_IE[3]; // 3 External Interrupt Lines + emu_timer *m_tmp68301_timer[3]; // 3 Timers + + UINT16 m_irq_vector[8]; + + TIMER_CALLBACK_MEMBER( timer_callback ); + void update_timer( int i ); + void update_irq_state(); + + UINT16 m_imr; + UINT16 m_iisr; + UINT16 m_scr; + UINT16 m_pdir; + UINT16 m_pdr; + + inline UINT16 read_word(offs_t address); + inline void write_word(offs_t address, UINT16 data); + const address_space_config m_space_config; +}; + +extern const device_type TMP68301; + +#endif diff --git a/src/devices/machine/tms1024.c b/src/devices/machine/tms1024.c new file mode 100644 index 00000000000..f362349ef16 --- /dev/null +++ b/src/devices/machine/tms1024.c @@ -0,0 +1,111 @@ +// license:BSD-3-Clause +// copyright-holders:hap +/* + + Texas Instruments TMS1024/TMS1025 I/O expander + + No documentation was available, just a pinout. + Other than more port pins, TMS1025 is assumed to be same as TMS1024. + + TODO: + - writes to port 0 + - what's the MS pin? + - strobe is on rising edge? or falling edge? + +*/ + +#include "machine/tms1024.h" + + +const device_type TMS1024 = &device_creator; +const device_type TMS1025 = &device_creator; + +//------------------------------------------------- +// constructor +//------------------------------------------------- + +tms1024_device::tms1024_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, TMS1024, "TMS1024 I/O Expander", tag, owner, clock, "tms1024", __FILE__), + m_write_port1(*this), m_write_port2(*this), m_write_port3(*this), m_write_port4(*this), m_write_port5(*this), m_write_port6(*this), m_write_port7(*this) +{ +} + +tms1024_device::tms1024_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + m_write_port1(*this), m_write_port2(*this), m_write_port3(*this), m_write_port4(*this), m_write_port5(*this), m_write_port6(*this), m_write_port7(*this) +{ +} + +tms1025_device::tms1025_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : tms1024_device(mconfig, TMS1025, "TMS1025 I/O Expander", tag, owner, clock, "tms1025", __FILE__) +{ +} + + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void tms1024_device::device_start() +{ + // resolve callbacks (there is no port 0) + m_write_port1.resolve_safe(); m_write_port[0] = &m_write_port1; + m_write_port2.resolve_safe(); m_write_port[1] = &m_write_port2; + m_write_port3.resolve_safe(); m_write_port[2] = &m_write_port3; + m_write_port4.resolve_safe(); m_write_port[3] = &m_write_port4; + m_write_port5.resolve_safe(); m_write_port[4] = &m_write_port5; + m_write_port6.resolve_safe(); m_write_port[5] = &m_write_port6; + m_write_port7.resolve_safe(); m_write_port[6] = &m_write_port7; + + // zerofill + m_h = 0; + m_s = 0; + m_std = 0; + + // register for savestates + save_item(NAME(m_h)); + save_item(NAME(m_s)); + save_item(NAME(m_std)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void tms1024_device::device_reset() +{ +} + + + +//------------------------------------------------- +// handlers +//------------------------------------------------- + +WRITE8_MEMBER(tms1024_device::write_h) +{ + // H1,2,3,4: data for outputs A,B,C,D + m_h = data & 0xf; +} + +WRITE8_MEMBER(tms1024_device::write_s) +{ + // S0,1,2: select port + m_s = data & 7; +} + +WRITE_LINE_MEMBER(tms1024_device::write_std) +{ + state = (state) ? 1 : 0; + + // output on rising edge + if (state && !m_std) + { + if (m_s != 0) + (*m_write_port[m_s-1])((offs_t)(m_s-1), m_h); + } + + m_std = state; +} diff --git a/src/devices/machine/tms1024.h b/src/devices/machine/tms1024.h new file mode 100644 index 00000000000..a7bdb4539bf --- /dev/null +++ b/src/devices/machine/tms1024.h @@ -0,0 +1,110 @@ +// license:BSD-3-Clause +// copyright-holders:hap +/* + + Texas Instruments TMS1024/TMS1025 I/O expander + +*/ + +#ifndef _TMS1024_H_ +#define _TMS1024_H_ + +#include "emu.h" + + +// ports setup + +// 4-bit ports (3210 = DCBA) +// valid ports: 4-7 for TMS1024, 1-7 for TMS1025 +#define MCFG_TMS1024_WRITE_PORT_CB(X, _devcb) \ + tms1024_device::set_write_port##X##_callback(*device, DEVCB_##_devcb); + +enum +{ + TMS1024_PORT1 = 0, + TMS1024_PORT2, + TMS1024_PORT3, + TMS1024_PORT4, + TMS1024_PORT5, + TMS1024_PORT6, + TMS1024_PORT7 +}; + + +// pinout reference + +/* + + ____ ____ ____ ____ + Vss 1 |* \_/ | 28 H2 Vss 1 |* \_/ | 40 H2 + H3 2 | | 27 H1 H3 2 | | 39 H1 + H4 3 | | 26 Vdd H4 3 | | 38 Vdd + CE 4 | | 25 S2 CE 4 | | 37 S2 + MS 5 | | 24 S1 MS 5 | | 36 S1 + STD 6 | | 23 S0 STD 6 | | 35 S0 + A4 7 | TMS1024 | 22 D7 A1 7 | | 34 D3 + B4 8 | | 21 C7 B1 8 | | 33 C3 + C4 9 | | 20 B7 C1 9 | | 32 B3 + D4 10 | | 19 A7 D1 10 | TMS1025 | 31 A3 + A5 11 | | 18 D6 A4 11 | | 30 D7 + B5 12 | | 17 C6 B4 12 | | 29 C7 + C5 13 | | 16 B6 C4 13 | | 28 B7 + D5 14 |___________| 15 A6 D4 14 | | 27 A7 + A5 15 | | 26 D6 + B5 16 | | 25 C6 + CE: Chip Enable C5 17 | | 24 B6 + MS: Master S.? D5 18 | | 23 A6 + STD: STrobe Data? A2 19 | | 22 D2 + S: Select B2 20 |___________| 21 C2 + H: Hold? + +*/ + + +class tms1024_device : public device_t +{ +public: + tms1024_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + tms1024_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + // static configuration helpers + template static devcb_base &set_write_port1_callback(device_t &device, _Object object) { return downcast(device).m_write_port1.set_callback(object); } + template static devcb_base &set_write_port2_callback(device_t &device, _Object object) { return downcast(device).m_write_port2.set_callback(object); } + template static devcb_base &set_write_port3_callback(device_t &device, _Object object) { return downcast(device).m_write_port3.set_callback(object); } + template static devcb_base &set_write_port4_callback(device_t &device, _Object object) { return downcast(device).m_write_port4.set_callback(object); } + template static devcb_base &set_write_port5_callback(device_t &device, _Object object) { return downcast(device).m_write_port5.set_callback(object); } + template static devcb_base &set_write_port6_callback(device_t &device, _Object object) { return downcast(device).m_write_port6.set_callback(object); } + template static devcb_base &set_write_port7_callback(device_t &device, _Object object) { return downcast(device).m_write_port7.set_callback(object); } + + DECLARE_WRITE8_MEMBER(write_h); + DECLARE_WRITE8_MEMBER(write_s); + DECLARE_WRITE_LINE_MEMBER(write_std); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + UINT8 m_h; // 4-bit data latch + UINT8 m_s; // 3-bit port select + UINT8 m_std; // strobe pin + + // callbacks + devcb_write8 m_write_port1, m_write_port2, m_write_port3, m_write_port4, m_write_port5, m_write_port6, m_write_port7; + devcb_write8 *m_write_port[7]; +}; + + +class tms1025_device : public tms1024_device +{ +public: + tms1025_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + + +extern const device_type TMS1024; +extern const device_type TMS1025; + + +#endif /* _TMS1024_H_ */ diff --git a/src/devices/machine/tms5501.c b/src/devices/machine/tms5501.c new file mode 100644 index 00000000000..71f3f298cde --- /dev/null +++ b/src/devices/machine/tms5501.c @@ -0,0 +1,529 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + TMS5501 Multifunction Input/Output Controller emulation + +**********************************************************************/ + +#include "tms5501.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define LOG 0 + + +const UINT8 tms5501_device::rst_vector[] = { 0xc7, 0xcf, 0xd7, 0xdf, 0xe7, 0xef, 0xf7, 0xff }; + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +// device type definition +const device_type TMS5501 = &device_creator; + + +// I/O address map +DEVICE_ADDRESS_MAP_START( io_map, 8, tms5501_device ) + AM_RANGE(0x00, 0x00) AM_READ(rb_r) + AM_RANGE(0x01, 0x01) AM_READ(xi_r) + AM_RANGE(0x02, 0x02) AM_READ(rst_r) + AM_RANGE(0x03, 0x03) AM_READ(sta_r) + AM_RANGE(0x04, 0x04) AM_WRITE(cmd_w) + AM_RANGE(0x05, 0x05) AM_WRITE(rr_w) + AM_RANGE(0x06, 0x06) AM_WRITE(tb_w) + AM_RANGE(0x07, 0x07) AM_WRITE(xo_w) + AM_RANGE(0x08, 0x08) AM_WRITE(mr_w) + AM_RANGE(0x09, 0x0d) AM_WRITE(tmr_w) +ADDRESS_MAP_END + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// tms5501_device - constructor +//------------------------------------------------- + +tms5501_device::tms5501_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, TMS5501, "TMS5501", tag, owner, clock, "tms5501", __FILE__), + device_serial_interface(mconfig, *this), + m_write_irq(*this), + m_write_xmt(*this), + m_read_xi(*this), + m_write_xo(*this), + m_irq(IRQ_TB), + m_rb(0), + m_sta(STA_XBE | STA_SR), + m_cmd(0), + m_rr(0), + m_tb(0), + m_mr(0), + m_sens(0), + m_xi7(0) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void tms5501_device::device_start() +{ + // resolve callbacks + m_write_irq.resolve_safe(); + m_write_xmt.resolve_safe(); + m_read_xi.resolve_safe(0); + m_write_xo.resolve_safe(); + + // create timers + m_timer[TIMER_1] = timer_alloc(TIMER_1); + m_timer[TIMER_2] = timer_alloc(TIMER_2); + m_timer[TIMER_3] = timer_alloc(TIMER_3); + m_timer[TIMER_4] = timer_alloc(TIMER_4); + m_timer[TIMER_5] = timer_alloc(TIMER_5); + + // state saving + save_item(NAME(m_rb)); + save_item(NAME(m_sta)); + save_item(NAME(m_cmd)); + save_item(NAME(m_rr)); + save_item(NAME(m_tb)); + save_item(NAME(m_mr)); + save_item(NAME(m_sens)); + save_item(NAME(m_xi7)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void tms5501_device::device_reset() +{ + receive_register_reset(); + transmit_register_reset(); + + m_write_xmt(1); + + check_interrupt(); +} + + +//------------------------------------------------- +// device_timer - handle timer events +//------------------------------------------------- + +void tms5501_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch (id) + { + case TIMER_1: + set_interrupt(IRQ_TMR1); + break; + + case TIMER_2: + set_interrupt(IRQ_TMR2); + break; + + case TIMER_3: + set_interrupt(IRQ_TMR3); + break; + + case TIMER_4: + set_interrupt(IRQ_TMR4); + break; + + case TIMER_5: + if (!(m_cmd & CMD_XI7)) + { + set_interrupt(IRQ_TMR5); + } + break; + + default: + device_serial_interface::device_timer(timer, id, param, ptr); + } +} + + +//------------------------------------------------- +// tra_callback - +//------------------------------------------------- + +void tms5501_device::tra_callback() +{ + m_write_xmt(transmit_register_get_data_bit()); +} + + +//------------------------------------------------- +// tra_complete - +//------------------------------------------------- + +void tms5501_device::tra_complete() +{ + if (!(m_sta & STA_XBE)) + { + transmit_register_setup(m_tb); + + m_sta |= STA_XBE; + + set_interrupt(IRQ_TB); + } +} + + +//------------------------------------------------- +// rcv_complete - +//------------------------------------------------- + +void tms5501_device::rcv_complete() +{ + receive_register_extract(); + m_rb = get_received_char(); + + if (is_receive_framing_error()) + { + m_sta |= STA_FE; + } + else + { + m_sta &= ~STA_FE; + } + + if (m_sta & STA_RBL) + { + m_sta |= STA_OE; + } + + m_sta |= (STA_RBL | STA_SR); + m_sta &= ~(STA_SBD | STA_FBD); + + set_interrupt(IRQ_RB); +} + + +//------------------------------------------------- +// rb_r - read receiver buffer +//------------------------------------------------- + +READ8_MEMBER( tms5501_device::rb_r ) +{ + m_sta &= ~STA_RBL; + m_irq &= ~IRQ_RB; + + check_interrupt(); + + return m_rb; +} + + +//------------------------------------------------- +// xi_r - read external inputs +//------------------------------------------------- + +READ8_MEMBER( tms5501_device::xi_r ) +{ + UINT8 data = m_read_xi(0); + + if (m_cmd & CMD_XI7) + { + data = (m_xi7 << 7) | (data & 0x7f); + } + + return data; +} + + +//------------------------------------------------- +// rst_r - read interrupt address +//------------------------------------------------- + +READ8_MEMBER( tms5501_device::rst_r ) +{ + return get_vector(); +} + + +//------------------------------------------------- +// sta_r - read TMS5510 status +//------------------------------------------------- + +READ8_MEMBER( tms5501_device::sta_r ) +{ + UINT8 data = m_sta; + + m_sta &= ~STA_OE; + + return data; +} + + +//------------------------------------------------- +// cmd_w - issue discrete commands +//------------------------------------------------- + +WRITE8_MEMBER( tms5501_device::cmd_w ) +{ + if (LOG) logerror("TMS5501 '%s' Command %02x\n", tag(), data); + + m_cmd = data; + + if (m_cmd & CMD_RST) + { + m_sta &= ~(STA_SBD | STA_FBD | STA_RBL | STA_OE); + m_sta |= (STA_XBE | STA_SR); + + receive_register_reset(); + transmit_register_reset(); + + m_write_xmt(1); + + m_irq = 0; + set_interrupt(IRQ_TB); + + m_timer[TIMER_1]->enable(false); + m_timer[TIMER_2]->enable(false); + m_timer[TIMER_3]->enable(false); + m_timer[TIMER_4]->enable(false); + m_timer[TIMER_5]->enable(false); + } + else if (m_cmd & CMD_BRK) + { + receive_register_reset(); + transmit_register_reset(); + + m_write_xmt(0); + } +} + + +//------------------------------------------------- +// rr_w - load rate register +//------------------------------------------------- + +WRITE8_MEMBER( tms5501_device::rr_w ) +{ + if (LOG) logerror("TMS5501 '%s' Rate Register %02x\n", tag(), data); + + m_rr = data; + + stop_bits_t stop_bits = (m_rr & RR_STOP) ? STOP_BITS_1 : STOP_BITS_2; + + set_data_frame(1, 8, PARITY_NONE, stop_bits); + + int rate = 0; + + if (m_rr & RR_9600) rate = 9600; + else if (m_rr & RR_4800) rate = 4800; + else if (m_rr & RR_2400) rate = 2400; + else if (m_rr & RR_1200) rate = 1200; + else if (m_rr & RR_300) rate = 300; + else if (m_rr & RR_150) rate = 150; + else if (m_rr & RR_110) rate = 110; + + if (m_cmd & CMD_TST1) + { + rate *= 8; + } + + set_rcv_rate(rate); + set_tra_rate(rate); +} + + +//------------------------------------------------- +// tb_w - load transmitter buffer +//------------------------------------------------- + +WRITE8_MEMBER( tms5501_device::tb_w ) +{ + if (LOG) logerror("TMS5501 '%s' Transmitter Buffer %02x\n", tag(), data); + + m_tb = data; + + if (is_transmit_register_empty()) + { + transmit_register_setup(m_tb); + + m_sta |= STA_XBE; + + set_interrupt(IRQ_TB); + } + else + { + m_sta &= ~STA_XBE; + } +} + + +//------------------------------------------------- +// xo_w - load output port +//------------------------------------------------- + +WRITE8_MEMBER( tms5501_device::xo_w ) +{ + if (LOG) logerror("TMS5501 '%s' Output %02x\n", tag(), data); + + m_write_xo(data); +} + + +//------------------------------------------------- +// mr_w - load mask register +//------------------------------------------------- + +WRITE8_MEMBER( tms5501_device::mr_w ) +{ + if (LOG) logerror("TMS5501 '%s' Mask Register %02x\n", tag(), data); + + m_mr = data; + + check_interrupt(); +} + + +//------------------------------------------------- +// tmr_w - load interval timer +//------------------------------------------------- + +WRITE8_MEMBER( tms5501_device::tmr_w ) +{ + if (LOG) logerror("TMS5501 '%s' Timer %u %02x\n", tag(), offset, data); + + m_timer[offset]->adjust(attotime::from_double((double) data / (clock() / 128.0))); +} + + +//------------------------------------------------- +// rcv_w - receive data write +//------------------------------------------------- + +WRITE_LINE_MEMBER( tms5501_device::rcv_w ) +{ + device_serial_interface::rx_w(state); + + if (is_receive_register_synchronized()) + { + m_sta |= STA_SBD; + m_sta &= ~STA_SR; + } + + if (is_receive_register_shifting()) + { + m_sta |= STA_FBD; + } +} + + +//------------------------------------------------- +// xi7_w - +//------------------------------------------------- + +WRITE_LINE_MEMBER( tms5501_device::xi7_w ) +{ + if (m_cmd & CMD_XI7) + { + if (!m_xi7 && state) + { + set_interrupt(IRQ_XI7); + } + } + + m_xi7 = state; +} + + +//------------------------------------------------- +// sens_w - +//------------------------------------------------- + +WRITE_LINE_MEMBER( tms5501_device::sens_w ) +{ + if (!m_sens && state) + { + set_interrupt(IRQ_SENS); + } + + m_sens = state; +} + + +//------------------------------------------------- +// set_interrupt - +//------------------------------------------------- + +void tms5501_device::set_interrupt(UINT8 mask) +{ + m_irq |= mask; + + if (LOG) logerror("TMS5501 '%s' Interrupt %02x\n", tag(), mask); + + check_interrupt(); +} + + +//------------------------------------------------- +// check_interrupt - +//------------------------------------------------- + +void tms5501_device::check_interrupt() +{ + int state = (m_irq & m_mr) ? ASSERT_LINE : CLEAR_LINE; + + if (state == ASSERT_LINE) + { + if (LOG) logerror("TMS5501 '%s' Interrupt Assert\n", tag()); + + m_sta |= STA_IP; + } + else + { + m_sta &= ~STA_IP; + } + + if (m_cmd & CMD_IAE) + { + m_write_irq(state); + } + else + { + m_write_irq(CLEAR_LINE); + } +} + + +//------------------------------------------------- +// get_vector - +//------------------------------------------------- + +UINT8 tms5501_device::get_vector() +{ + UINT8 rst = 0; + + for (int i = 0; i < 8; i++) + { + if (BIT((m_irq & m_mr), i)) + { + rst = rst_vector[i]; + m_irq &= ~(1 << i); + + check_interrupt(); + + if (LOG) logerror("%s: TMS5501 '%s' Interrupt Acknowledge %02x\n", machine().describe_context(), tag(), rst); + break; + } + } + + return rst; +} diff --git a/src/devices/machine/tms5501.h b/src/devices/machine/tms5501.h new file mode 100644 index 00000000000..0a62f751910 --- /dev/null +++ b/src/devices/machine/tms5501.h @@ -0,0 +1,195 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + TMS5501 Multifunction Input/Output Controller emulation + +********************************************************************** + _____ _____ + Vbb 1 |* \_/ | 40 XMT + Vcc 2 | | 39 XI0 + Vdd 3 | | 38 XI1 + VSS 4 | | 37 XI2 + RCV 5 | | 36 XI3 + D7 6 | | 35 XI4 + D6 7 | | 34 XI5 + D5 8 | | 33 XI6 + D4 9 | | 32 XI7 + D3 10 | | 31 _XO7 + D2 11 | TMS5501 | 30 _XO6 + D1 12 | | 29 _XO5 + D0 13 | | 28 _XO4 + A0 14 | | 27 _XO3 + A1 15 | | 26 _XO2 + A2 16 | | 25 _XO1 + A3 17 | | 24 _XO0 + CE 18 | | 23 INT + SYNC 19 | | 22 SENS + phi1 20 |_____________| 21 phi2 + +**********************************************************************/ + +#pragma once + +#ifndef __TMS5501__ +#define __TMS5501__ + +#include "emu.h" + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_TMS5501_IRQ_CALLBACK(_write) \ + devcb = &tms5501_device::set_irq_wr_callback(*device, DEVCB_##_write); + +#define MCFG_TMS5501_XMT_CALLBACK(_write) \ + devcb = &tms5501_device::set_xmt_wr_callback(*device, DEVCB_##_write); + +#define MCFG_TMS5501_XI_CALLBACK(_read) \ + devcb = &tms5501_device::set_xi_rd_callback(*device, DEVCB_##_read); + +#define MCFG_TMS5501_XO_CALLBACK(_write) \ + devcb = &tms5501_device::set_xo_wr_callback(*device, DEVCB_##_write); + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> tms5501_device + +class tms5501_device : public device_t, + public device_serial_interface +{ +public: + // construction/destruction + tms5501_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + template static devcb_base &set_irq_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_irq.set_callback(object); } + template static devcb_base &set_xmt_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_xmt.set_callback(object); } + template static devcb_base &set_xi_rd_callback(device_t &device, _Object object) { return downcast(device).m_read_xi.set_callback(object); } + template static devcb_base &set_xo_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_xo.set_callback(object); } + + virtual DECLARE_ADDRESS_MAP(io_map, 8); + + DECLARE_WRITE_LINE_MEMBER( rcv_w ); + + DECLARE_WRITE_LINE_MEMBER( sens_w ); + DECLARE_WRITE_LINE_MEMBER( xi7_w ); + + UINT8 get_vector(); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + // device_serial_interface overrides + virtual void tra_callback(); + virtual void tra_complete(); + virtual void rcv_complete(); + + DECLARE_READ8_MEMBER( rb_r ); + DECLARE_READ8_MEMBER( xi_r ); + DECLARE_READ8_MEMBER( rst_r ); + DECLARE_READ8_MEMBER( sta_r ); + DECLARE_WRITE8_MEMBER( cmd_w ); + DECLARE_WRITE8_MEMBER( rr_w ); + DECLARE_WRITE8_MEMBER( tb_w ); + DECLARE_WRITE8_MEMBER( xo_w ); + DECLARE_WRITE8_MEMBER( mr_w ); + DECLARE_WRITE8_MEMBER( tmr_w ); + +private: + enum + { + TIMER_1 = 0, + TIMER_2, + TIMER_3, + TIMER_4, + TIMER_5 + }; + + enum + { + IRQ_TMR1 = 0x01, + IRQ_TMR2 = 0x02, + IRQ_SENS = 0x04, + IRQ_TMR3 = 0x08, + IRQ_RB = 0x10, + IRQ_TB = 0x20, + IRQ_TMR4 = 0x40, + IRQ_TMR5 = 0x80, + IRQ_XI7 = 0x80 + }; + + enum + { + STA_FE = 0x01, + STA_OE = 0x02, + STA_SR = 0x04, + STA_RBL = 0x08, + STA_XBE = 0x10, + STA_IP = 0x20, + STA_FBD = 0x40, + STA_SBD = 0x80 + }; + + enum + { + CMD_RST = 0x01, + CMD_BRK = 0x02, + CMD_XI7 = 0x04, + CMD_IAE = 0x08, + CMD_TST1 = 0x10, + CMD_TST2 = 0x20 + }; + + enum + { + RR_110 = 0x01, + RR_150 = 0x02, + RR_300 = 0x04, + RR_1200 = 0x08, + RR_2400 = 0x10, + RR_4800 = 0x20, + RR_9600 = 0x40, + RR_STOP = 0x80 + }; + + static const UINT8 rst_vector[]; + + void set_interrupt(UINT8 mask); + void check_interrupt(); + + devcb_write_line m_write_irq; + devcb_write_line m_write_xmt; + devcb_read8 m_read_xi; + devcb_write8 m_write_xo; + + UINT8 m_irq; + UINT8 m_rb; + UINT8 m_sta; + UINT8 m_cmd; + UINT8 m_rr; + UINT8 m_tb; + UINT8 m_mr; + + int m_sens; + int m_xi7; + + emu_timer *m_timer[5]; +}; + + +// device type definition +extern const device_type TMS5501; + + + +#endif diff --git a/src/devices/machine/tms6100.c b/src/devices/machine/tms6100.c new file mode 100644 index 00000000000..7d0f3226ca5 --- /dev/null +++ b/src/devices/machine/tms6100.c @@ -0,0 +1,264 @@ +// license:BSD-3-Clause +// copyright-holders:Couriersud +/********************************************************************************************** + + TMS6100 simulator + + Written for MAME by Couriersud + + Todo: + - implement CS + - implement 4 bit mode (mask programmed) + - implement chip addressing (0-15 mask programmed) + + TMS6100: + + +-----------------+ + VDD | 1 28 | NC + NC | 2 27 | NC + DATA/ADD1 | 3 26 | NC + DATA/ADD2 | 4 25 | NC + DATA/ADD4 | 5 24 | NC + DATA/ADD8 | 6 23 | NC + CLK | 7 22 | NC + NC | 8 21 | NC + NC | 9 20 | NC + M0 | 10 19 | NC + M1 | 11 18 | NC + NC | 12 17 | NC + /CS | 13 16 | NC + VSS | 14 15 | NC + +-----------------+ + + TMS6125: + + +---------+ + DATA/ADD1 | 1 16 | NC + DATA/ADD2 | 2 15 | NC + DATA/ADD4 | 3 14 | NC + DATA/ADD8 | 4 13 | NC + CLK | 5 12 | VDD + NC | 6 11 | /CS + NC | 7 10 | M1 + M0 | 8 9 | VSS + +---------+ + + M58819 (from radarscope schematics): + + +-----------------+ + AD0 | 1 40 | AD1 + GND | 2 39 | AD2 + -5V | 3 38 | AD3 + A0 | 4 37 | AD4 + NC | 5 36 | AD5 + NC | 6 35 | AD6 + A1 | 7 34 | AD7 + A2 | 8 33 | AD8 + A3 | 9 32 | AD9 + CLK | 10 31 | AD10 + NC | 11 30 | AD11 + -5V | 12 29 | AD12 + C0 | 13 28 | NC + C1 | 14 27 | NC + NC | 15 26 | I7 + NC | 16 25 | NC + +5V | 17 24 | I6 + I0 | 18 23 | I5 + I1 | 19 22 | I4 + I2 | 20 21 | I3 + +-----------------+ + + The M58819 is used as an interface to external speech eproms. + NC pins may have a function, although they are not connected in + radarscope. + +***********************************************************************************************/ + +#include "emu.h" +#include "tms6100.h" + +#define VERBOSE (0) + +#if VERBOSE +#define LOG(x) logerror x +#else +#define LOG(x) +#endif + +#define TMS6100_READ_PENDING 0x01 +#define TMS6100_NEXT_READ_IS_DUMMY 0x02 + +/* Variants */ + +#define TMS6110_IS_TMS6100 (1) +#define TMS6110_IS_M58819 (2) + + +const device_type TMS6100 = &device_creator; + +tms6100_device::tms6100_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + m_rom(*this, DEVICE_SELF) +{ +} + +tms6100_device::tms6100_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, TMS6100, "TMS6100", tag, owner, clock, "tms6100", __FILE__), + m_rom(*this, DEVICE_SELF) +{ +} + +const device_type M58819 = &device_creator; + +m58819_device::m58819_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : tms6100_device(mconfig, M58819, "M58819 Memory Controller", tag, owner, clock, "m58819", __FILE__) +{ +} + +//------------------------------------------------- +// device_config_complete - perform any +// operations now that the configuration is +// complete +//------------------------------------------------- + +void tms6100_device::device_config_complete() +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void tms6100_device::device_start() +{ + // save device variables + save_item(NAME(m_addr_bits)); + save_item(NAME(m_address)); + save_item(NAME(m_address_latch)); + save_item(NAME(m_tms_clock)); + save_item(NAME(m_data)); + save_item(NAME(m_loadptr)); + save_item(NAME(m_m0)); + save_item(NAME(m_m1)); + save_item(NAME(m_state)); + save_item(NAME(m_variant)); + set_variant(TMS6110_IS_TMS6100); + +} + +void m58819_device::device_start() +{ + tms6100_device::device_start(); + set_variant(TMS6110_IS_M58819); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void tms6100_device::device_reset() +{ + /* initialize the chip */ + m_addr_bits = 0; + m_address = 0; + m_address_latch = 0; + m_loadptr = 0; + m_m0 = 0; + m_m1 = 0; + m_state = 0; + m_tms_clock = 0; + m_data = 0; +} + +void tms6100_device::set_variant(int variant) +{ + m_variant = variant; +} + +WRITE_LINE_MEMBER(tms6100_device::tms6100_m0_w) +{ + if (state != m_m0) + m_m0 = state; +} + +WRITE_LINE_MEMBER(tms6100_device::tms6100_m1_w) +{ + if (state != m_m1) + m_m1 = state; +} + +WRITE_LINE_MEMBER(tms6100_device::tms6100_romclock_w) +{ + /* process on falling edge */ + if (m_tms_clock && !state) + { + switch ((m_m1<<1) | m_m0) + { + case 0x00: + /* NOP in datasheet, not really ... */ + if (m_state & TMS6100_READ_PENDING) + { + if (m_state & TMS6100_NEXT_READ_IS_DUMMY) + { + m_address = (m_address_latch << 3); + m_address_latch = 0; + m_loadptr = 0; + m_state &= ~TMS6100_NEXT_READ_IS_DUMMY; + LOG(("loaded address %08x\n", m_address)); + } + else + { + /* read bit at address */ + if (m_variant == TMS6110_IS_M58819) + { + m_data = (m_rom[m_address >> 3] >> (7-(m_address & 0x07))) & 1; + } + else // m_variant == (TMS6110_IS_TMS6100 || TMS6110_IS_TMS6125) + { + m_data = (m_rom[m_address >> 3] >> (m_address & 0x07)) & 1; + } + m_address++; + } + m_state &= ~TMS6100_READ_PENDING; + } + break; + case 0x01: + /* READ */ + m_state |= TMS6100_READ_PENDING; + break; + case 0x02: + /* LOAD ADDRESS */ + m_state |= TMS6100_NEXT_READ_IS_DUMMY; + m_address_latch |= (m_addr_bits << m_loadptr); + LOG(("loaded address latch %08x\n", m_address_latch)); + m_loadptr += 4; + break; + case 0x03: + /* READ AND BRANCH */ + if (m_state & TMS6100_NEXT_READ_IS_DUMMY) + { + m_state &= ~TMS6100_NEXT_READ_IS_DUMMY; // clear - no dummy read according to datasheet + LOG(("loaded address latch %08x\n", m_address_latch)); + m_address = m_rom[m_address_latch] | (m_rom[m_address_latch+1]<<8); + m_address &= 0x3fff; // 14 bits + LOG(("loaded indirect address %04x\n", m_address)); + m_address = (m_address << 3); + m_address_latch = 0; + m_loadptr = 0; + } + break; + } + } + m_tms_clock = state; +} + +WRITE8_MEMBER(tms6100_device::tms6100_addr_w) +{ + if (data != m_addr_bits) + m_addr_bits = data; +} + +READ_LINE_MEMBER(tms6100_device::tms6100_data_r) +{ + return m_data; +} diff --git a/src/devices/machine/tms6100.h b/src/devices/machine/tms6100.h new file mode 100644 index 00000000000..4aed02a846b --- /dev/null +++ b/src/devices/machine/tms6100.h @@ -0,0 +1,60 @@ +// license:BSD-3-Clause +// copyright-holders:Couriersud +#pragma once + +#ifndef __TMS6100_H__ +#define __TMS6100_H__ + +/* TMS 6100 memory controller */ + +class tms6100_device : public device_t +{ +public: + tms6100_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + tms6100_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + DECLARE_WRITE_LINE_MEMBER( tms6100_m0_w ); + DECLARE_WRITE_LINE_MEMBER( tms6100_m1_w ); + DECLARE_WRITE_LINE_MEMBER( tms6100_romclock_w ); + DECLARE_WRITE8_MEMBER( tms6100_addr_w ); + + DECLARE_READ_LINE_MEMBER( tms6100_data_r ); + +protected: + // device-level overrides + virtual void device_config_complete(); + virtual void device_start(); + virtual void device_reset(); + void set_variant(int variant); +private: + // internal state + required_region_ptr m_rom; + UINT32 m_address; + UINT32 m_address_latch; + UINT8 m_loadptr; + UINT8 m_m0; + UINT8 m_m1; + UINT8 m_addr_bits; + UINT8 m_tms_clock; + UINT8 m_data; + UINT8 m_state; + UINT8 m_variant; + +}; + +extern const device_type TMS6100; + +class m58819_device : public tms6100_device +{ +public: + m58819_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // device-level overrides + virtual void device_start(); +}; + +extern const device_type M58819; + + +#endif /* __TMS6100_H__ */ diff --git a/src/devices/machine/tms9901.c b/src/devices/machine/tms9901.c new file mode 100644 index 00000000000..8ca2f4b2bf7 --- /dev/null +++ b/src/devices/machine/tms9901.c @@ -0,0 +1,630 @@ +// license:BSD-3-Clause +// copyright-holders:Michael Zapf +/**************************************************************************** + + TMS9901 Programmable System Interface + + +--------------+ + RST1*| 1 | | 40| Vcc + CRUOUT | 2 +--+ 39| S0 + CRUCLK | 3 38| P0 + CRUIN | 4 37| P1 + CE*| 5 36| S1 + INT6*| 6 35| S2 + INT5*| 7 34| INT7* / P15 + INT4*| 8 33| INT8* / P14 + INT3*| 9 32| INT9* / P13 + Phi*|10 31| INT10* / P12 + INTREQ*|11 30| INT11* / P11 + IC3 |12 29| INT12* / P10 + IC2 |13 28| INT13* / P9 + IC1 |14 27| INT14* / P8 + IC0 |15 26| P2 + Vss |16 25| S3 + INT1*|17 24| S4 + INT2*|18 23| INT15* / P7 + P6 |19 22| P3 + P5 |20 21| P4 + +--------------+ + +Overview: + TMS9901 is a support chip for TMS9900. It handles interrupts, provides + several I/O pins, and a timer (a.k.a. clock: it is merely a register which + decrements regularly and can generate an interrupt when it reaches 0). + + It communicates with the TMS9900 with the CRU bus, and with the rest of the + world with a number of parallel I/O pins. + + I/O and timer functions should work with any other 990/99xx/99xxx CPU. + On the other hand, interrupt handling was primarily designed for tms9900 + and 99000 based systems: other CPUs can support interrupts, but not the 16 + distinct interrupt vectors. + +Pins: + Vcc, Vss: power supply + Phi*: system clock (connected to TMS9900 Phi3* or TMS9980 CLKOUT*) + RST1*: reset input + CRUIN, CRUOUT, CRUCLK, CE*, S0-S4: CRU bus (CPU interface) + INTREQ*, IC0-IC3: interrupt bus (CPU interface) + INT*1-INT*6: used as interrupt/input pins. + P0-P6: used as input/output pins. + INT*7/P15-INT*15/P7: used as either interrupt/input or input/output pins. + Note that a pin cannot be used simultaneously as output and as interrupt. + (This is mostly obvious, but it implies that you cannot trigger an + interrupt by setting the output state of a pin, which is not SO obvious.) + +Interrupt handling: + After each clock cycle, TMS9901 latches the state of INT1*-INT15* (except + pins which are set as output pins). If the clock is enabled, it replaces + INT3* with an internal timer interrupt flag. Then it inverts the value and + performs a bit-wise AND with the interrupt mask. + + If there are some unmasked interrupt bits, INTREQ* is asserted and the code + of the lowest active interrupt is placed on IC0-IC3. If these pins are + duly connected to the tms9900 INTREQ* and IC0-IC3 pins, the result is that + asserting an INTn* on tms9901 will cause a level-n interrupt request on the + tms9900, provided that this interrupt pin is not masked in tms9901, and + that no unmasked higher-priority (i.e. lower-level) interrupt pin is set. + + This interrupt request lasts for as long as the interrupt pin and the + relevant bit in the interrupt mask are set (level-triggered interrupts). + (The request may be shadowed by a higher-priority interrupt request, but + it will resume when the higher-priority request ends.) + + TIMER interrupts are kind of an exception, since they are not associated + with an external interrupt pin. I think there is an internal timer + interrupt flag that is set when the decrementer reaches 0, and is cleared + by a write to the 9901 int*3 enable bit ("SBO 3" in interrupt mode). + +TODO: + * Emulate the RST1* input. Note that RST1* active (low) makes INTREQ* + inactive (high) with IC0-IC3 = 0. + * the clock read register is updated every time the timer decrements when + the TMS9901 is not in clock mode. This probably implies that if the + clock mode is cleared and re-asserted immediately, the tms9901 may fail + to update the clock read register: this is not emulated. + * The clock mode is entered when a 1 is written to the control bit. It is + exited when a 0 is written to the control bit or the a tms9901 select bit + greater than 15 is accessed. According to the data sheet, "when CE* is + inactive (HIGH), the PSI is not disabled from seeing the select lines. + As the CPU is accessing memory, A10-A14 could very easily have a value of + 15 or greater" (this is assuming that S0-S4 are connected to A10-A14, + which makes sense with most tms9900 family members). There is no way + this "feature" (I would call it a hardware bug) can be emulated + efficiently, as we would need to watch every memory access. + +MZ: According to the description in + A. Osborne, G. Kane: Osborne 16-bit microprocessor handbook + page 3-81 + the 9901 only temporarily leaves the timer mode as long as S0 is set to 1. + In the meantime the timer function continues but cannot be queried. This + makes it possible to continue using the chip as a timer while working with + its I/O pins. Thus I believe the above TODO concering the exit of the timer + mode is not applicable. + The problem is that the original 9901 specification is not clear about this. + +MZ: Turned to class (January 2012) + +TODO: Tests on a real machine +- Set an interrupt input (e.g. keyboard for Geneve), trigger RST2*, check whether + interrupt mask has been reset +- Check whether the clock_read_register is updated whenever clock mode is exited + (in particular when S0=1, i.e. A10=1 -> addresses xxxx xxxx xx1x xxxx + requires to write a program that fits into 32 bytes; workspace elsewhere) + + Raphael Nabet, 2000-2004 + Michael Zapf + + February 2012: Rewritten as class + +*****************************************************************************/ + +#include +#include "emu.h" + +#include "tms9901.h" + +/* + Debugging flags. +*/ +#define TRACE_PINS 0 +#define TRACE_CLOCK 0 +#define TRACE_MODE 0 + +/* + Constructor +*/ +tms9901_device::tms9901_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) +: device_t(mconfig, TMS9901, "TMS9901 Programmable System Interface", tag, owner, clock, "tms9901", __FILE__), + m_read_block(*this), + m_write_p0(*this), + m_write_p1(*this), + m_write_p2(*this), + m_write_p3(*this), + m_write_p4(*this), + m_write_p5(*this), + m_write_p6(*this), + m_write_p7(*this), + m_write_p8(*this), + m_write_p9(*this), + m_write_p10(*this), + m_write_p11(*this), + m_write_p12(*this), + m_write_p13(*this), + m_write_p14(*this), + m_write_p15(*this), + m_interrupt(*this) +{ +} + +/* + should be called after any change to int_state or enabled_ints. +*/ +void tms9901_device::field_interrupts(void) +{ + int current_ints; + + // m_int_state: inverted state of lines INT1*-INT15*. Bits are set by set_single_int only. + current_ints = m_int_state; + if (m_clock_register != 0) + { + // if timer is enabled, INT3 pin is overridden by timer + if (m_timer_int_pending) + { + if (TRACE_CLOCK) logerror("%s: timer fires\n", tag()); + current_ints |= TMS9901_INT3; + } + else + { + if (TRACE_CLOCK) logerror("%s: timer clear\n", tag()); + current_ints &= ~TMS9901_INT3; + } + } + + // enabled_ints: enabled interrupts + // Remove all settings from pins that are set as outputs (INT7*-INT15* share the same pins as P15-P7) + current_ints &= m_enabled_ints & (~m_pio_direction_mirror); + + // Check whether we have a new state. For systems that use level-triggered + // interrupts it should not do any harm if the line is re-asserted + // but we may as well avoid this. + if (current_ints == m_old_int_state) + return; + + m_old_int_state = current_ints; + + if (current_ints != 0) + { + // find which interrupt tripped us: + // the number of the first (i.e. least significant) non-zero bit among + // the 16 first bits + // we simply look for the first bit set to 1 in current_ints... + int level = 0; + + while ((current_ints & 1)==0) + { + current_ints >>= 1; /* try next bit */ + level++; + } + m_int_pending = true; + if (!m_interrupt.isnull()) + m_interrupt(level, 1, 0xff); // the offset carries the IC0-3 level + } + else + { + m_int_pending = false; + if (!m_interrupt.isnull()) + m_interrupt(0xf, 0, 0xff); //Spec: INTREQ*=1 <=> IC0,1,2,3 = 1111 + } +} + +/* + function which should be called by the driver when the state of an INTn* + pin changes (only required if the pin is set up as an interrupt pin) + + state == CLEAR_LINE: INTn* is inactive (high) + state == ASSERT_LINE: INTn* is active (low) + + 0<=pin_number<=15 +*/ +void tms9901_device::set_single_int(int pin_number, int state) +{ + /* remember new state of INTn* pin state */ + if (state==ASSERT_LINE) + m_int_state |= 1 << pin_number; + else + m_int_state &= ~(1 << pin_number); + + field_interrupts(); +} + +/* + load the content of m_clock_register into the decrementer +*/ +void tms9901_device::timer_reload(void) +{ + if (m_clock_register != 0) + { /* reset clock interval */ + m_decrementer_value = m_clock_register; + m_decrementer->enable(true); + } + else + { /* clock interval == 0 -> no timer */ + m_decrementer->enable(false); + } +} + +/*---------------------------------------------------------------- + TMS9901 CRU interface. +----------------------------------------------------------------*/ + +/* + Read a 8 bit chunk from tms9901. + + signification: + bit 0: m_clock_mode + if (m_clock_mode == false) + bit 1-15: current status of the INT1*-INT15* pins + else + bit 1-14: current timer value + bit 15: value of the INTREQ* (interrupt request to TMS9900) pin. + + bit 16-31: current status of the P0-P15 pins (quits timer mode, too...) +*/ +READ8_MEMBER( tms9901_device::read ) +{ + int answer = 0; + + offset &= 0x003; + + switch (offset) + { + case 0: + if (m_clock_mode) + { + // Clock mode. The LSB reflects the CB bit which is set to 1 for clock mode. + answer = ((m_clock_read_register & 0x7F) << 1) | 0x01; + } + else + { + // Interrupt mode + // Note that we rely on the read function to deliver the same + // INTx levels that have been signaled via the set_single_int method. + // This may mean that those levels must be latched by the callee. + if (!m_read_block.isnull()) + answer |= m_read_block(TMS9901_CB_INT7); + + // Remove the bits that are set as outputs (can only be INT7*) + answer &= ~m_pio_direction_mirror; + + // Set those bits here + answer |= (m_pio_output_mirror & m_pio_direction_mirror) & 0xFF; + } + if (TRACE_PINS) logerror("%s: input on lines INT7..CB = %02x\n", tag(), answer); + break; + case 1: + if (m_clock_mode) + { + // clock mode + answer = (m_clock_read_register & 0x3F80) >> 7; + if (!m_int_pending) + answer |= 0x80; + } + else + { + // See above concerning the INT levels. + if (!m_read_block.isnull()) + answer |= m_read_block(TMS9901_INT8_INT15); + + // Remove the bits that are set as outputs (can be any line) + answer &= ~(m_pio_direction_mirror >> 8); + answer |= (m_pio_output_mirror & m_pio_direction_mirror) >> 8; + } + if (TRACE_PINS) logerror("%s: input on lines INT15..INT8 = %02x\n", tag(), answer); + break; + case 2: + /* exit timer mode */ + // MZ: See comments at the beginning. I'm sure that we do not quit clock mode. + // m_clock_mode = false; + + if (!m_read_block.isnull()) + answer = m_read_block(TMS9901_P0_P7); + else + answer = 0; + + answer &= ~m_pio_direction; + answer |= (m_pio_output & m_pio_direction) & 0xFF; + if (TRACE_PINS) logerror("%s: input on lines P7..P0 = %02x\n", tag(), answer); + + break; + case 3: + // MZ: see above + // m_clock_mode = false; + if (!m_read_block.isnull()) + answer = m_read_block(TMS9901_P8_P15); + else + answer = 0; + + answer &= ~(m_pio_direction >> 8); + answer |= (m_pio_output & m_pio_direction) >> 8; + if (TRACE_PINS) logerror("%s: input on lines P15..P8 = %02x\n", tag(), answer); + + break; + } + + return answer; +} + +/* + Write 1 bit to tms9901. + + signification: + bit 0: write m_clock_mode + if (!m_clock_mode) + bit 1-15: write interrupt mask register + else + bit 1-14: write timer period + bit 15: if written value == 0, soft reset (just resets all I/O pins as input) + + bit 16-31: set output state of P0-P15 (and set them as output pin) (quit timer mode, too...) +*/ +WRITE8_MEMBER ( tms9901_device::write ) +{ + data &= 1; /* clear extra bits */ + offset &= 0x01F; + + if (offset >= 0x10) + { + int pin = offset & 0x0F; + if (TRACE_PINS) logerror("%s: output on P%d = %d\n", tag(), pin, data); + + int bit = (1 << pin); + + // MZ: see above - I think this is wrong + // m_clock_mode = false; // exit timer mode + + // Once a value is written to a pin, the pin remains in output mode + // until the chip is reset + m_pio_direction |= bit; + + // Latch the value + if (data) + m_pio_output |= bit; + else + m_pio_output &= ~bit; + + if (pin >= 7) + { + // pins P7-P15 are mirrored as INT15*-INT7*, + // also using the same pins in the package + int mirror_bit = (1 << (22 - pin)); + + // See above + m_pio_direction_mirror |= mirror_bit; + + if (data) + m_pio_output_mirror |= mirror_bit; + else + m_pio_output_mirror &= ~mirror_bit; + } + + switch (offset) + { + case 0x10: + if (!m_write_p0.isnull()) m_write_p0(data); break; + case 0x11: + if (!m_write_p1.isnull()) m_write_p1(data); break; + case 0x12: + if (!m_write_p2.isnull()) m_write_p2(data); break; + case 0x13: + if (!m_write_p3.isnull()) m_write_p3(data); break; + case 0x14: + if (!m_write_p4.isnull()) m_write_p4(data); break; + case 0x15: + if (!m_write_p5.isnull()) m_write_p5(data); break; + case 0x16: + if (!m_write_p6.isnull()) m_write_p6(data); break; + case 0x17: + if (!m_write_p7.isnull()) m_write_p7(data); break; + case 0x18: + if (!m_write_p8.isnull()) m_write_p8(data); break; + case 0x19: + if (!m_write_p9.isnull()) m_write_p9(data); break; + case 0x1A: + if (!m_write_p10.isnull()) m_write_p10(data); break; + case 0x1B: + if (!m_write_p11.isnull()) m_write_p11(data); break; + case 0x1C: + if (!m_write_p12.isnull()) m_write_p12(data); break; + case 0x1D: + if (!m_write_p13.isnull()) m_write_p13(data); break; + case 0x1E: + if (!m_write_p14.isnull()) m_write_p14(data); break; + case 0x1F: + if (!m_write_p15.isnull()) m_write_p15(data); break; + + } + return; + } + + if (offset == 0) + { + // Write to control bit (CB) + if (data == 0) + { + // Switch to interrupt mode; quit clock mode + m_clock_mode = false; + if (TRACE_MODE) logerror("%s: int mode\n", tag()); + } + else + { + m_clock_mode = true; + if (TRACE_MODE) logerror("%s: clock mode\n", tag()); + // we are switching to clock mode: latch the current value of + // the decrementer register + if (m_clock_register != 0) + m_clock_read_register = m_decrementer_value; + else + m_clock_read_register = 0; /* timer inactive... */ + } + } + else + { + if (offset == 0x0f) + { + if (m_clock_mode) + { /* in clock mode this is the soft reset bit */ + if (!data) + { // TMS9901 soft reset (RST2*) + // Spec: "Writing a 0 to bit 15 while in the clock mode executes a soft reset on the I/O pins. + // [...] RST2* will program all ports to the input mode" + m_pio_direction = 0; + m_pio_direction_mirror = 0; + + // "RST1* (power-up reset) will reset all mask bits low." + // Spec is not clear on whether the mask bits are also reset by RST2* + // TODO: Check on a real machine. (I'd guess from the text they are not touched) + m_enabled_ints = 0; + if (TRACE_MODE) logerror("%s: Soft reset (RST2*)\n", tag()); + } + } + else + { /* modify interrupt enable mask */ + if (data) + m_enabled_ints |= 0x4000; /* set bit */ + else + m_enabled_ints &= ~0x4000; /* unset bit */ + + if (TRACE_PINS) logerror("%s: interrupts = %04x\n", tag(), m_enabled_ints); + field_interrupts(); /* changed interrupt state */ + } + } + else + { + // write one bit to 9901 (bits 1-14) + // + // m_clock_mode==false ? Disable/Enable an interrupt + // : Bit in clock interval + // + // offset is the index of the modified bit of register (-> interrupt number -1) + if (m_clock_mode) + { /* modify clock interval */ + int bit = 1 << ((offset & 0x0F) - 1); /* corresponding mask */ + + if (data) + m_clock_register |= bit; /* set bit */ + else + m_clock_register &= ~bit; /* clear bit */ + + /* reset clock timer (page 8) */ + if (TRACE_CLOCK) logerror("%s: clock register = %04x\n", tag(), m_clock_register); + timer_reload(); + } + else + { /* modify interrupt enable mask */ + int bit = 1 << (offset & 0x0F); /* corresponding mask */ + + if (data) + m_enabled_ints |= bit; /* set bit */ + else + m_enabled_ints &= ~bit; /* unset bit */ + + if (offset == 3) + m_timer_int_pending = false; /* SBO 3 clears pending timer interrupt (??) */ + + if (TRACE_MODE) logerror("%s: enabled interrupts = %04x\n", tag(), m_enabled_ints); + field_interrupts(); /* changed interrupt state */ + } + } + } +} + +/* + Timer callback + Decrementer counts down the value set in clock mode; when it reaches 0, + raises an interrupt and resets to the start value + The decrementer works as long as the clock_register contains a non-zero value. +*/ +void tms9901_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + if (id==DECREMENTER) // we have only that one + { + m_decrementer_value--; + if (TRACE_CLOCK) logerror("%s: decrementer = %d\n", tag(), m_decrementer_value); + if (m_decrementer_value<=0) + { + m_timer_int_pending = true; // decrementer interrupt requested + field_interrupts(); + m_decrementer_value = m_clock_register; + } + } +} + +/*------------------------------------------------- + device_stop - device-specific stop +-------------------------------------------------*/ + +void tms9901_device::device_stop(void) +{ +} + +/*------------------------------------------------- + device_reset - device-specific reset +-------------------------------------------------*/ + +void tms9901_device::device_reset(void) +{ + m_timer_int_pending = false; + m_enabled_ints = 0; + + m_pio_direction = 0; + m_pio_direction_mirror = 0; + m_pio_output = m_pio_output_mirror = 0; + + // This is an interrupt level latch, positive logic (bit 0 = no int) + // The inputs are negative logic (INTx*) + m_int_state = 0; + + m_old_int_state = -1; + field_interrupts(); + + m_clock_mode = false; + + m_clock_register = 0; + timer_reload(); +} + + +/*------------------------------------------------- + device_start - device-specific startup +-------------------------------------------------*/ + +void tms9901_device::device_start(void) +{ + m_decrementer = timer_alloc(DECREMENTER); + m_decrementer->adjust(attotime::from_hz(clock() / 64.), 0, attotime::from_hz(clock() / 64.)); + m_decrementer->enable(false); + + m_read_block.resolve(); + m_write_p0.resolve(); + m_write_p1.resolve(); + m_write_p2.resolve(); + m_write_p3.resolve(); + m_write_p4.resolve(); + m_write_p5.resolve(); + m_write_p6.resolve(); + m_write_p7.resolve(); + m_write_p8.resolve(); + m_write_p9.resolve(); + m_write_p10.resolve(); + m_write_p11.resolve(); + m_write_p12.resolve(); + m_write_p13.resolve(); + m_write_p14.resolve(); + m_write_p15.resolve(); + m_interrupt.resolve(); + + m_clock_register = 0; +} + +const device_type TMS9901 = &device_creator; diff --git a/src/devices/machine/tms9901.h b/src/devices/machine/tms9901.h new file mode 100644 index 00000000000..d6859bf21c5 --- /dev/null +++ b/src/devices/machine/tms9901.h @@ -0,0 +1,224 @@ +// license:BSD-3-Clause +// copyright-holders:Michael Zapf +/**************************************************************************** + + TMS9901 Programmable System Interface + See tms9901.c for documentation + + Raphael Nabet + Michael Zapf + + February 2012: Rewritten as class + +*****************************************************************************/ + +#ifndef __TMS9901_H__ +#define __TMS9901_H__ + +#include "emu.h" + +extern const device_type TMS9901; + +/*************************************************************************** + MACROS +***************************************************************************/ + +// Masks for the interrupts levels available on TMS9901 + +#define TMS9901_INT1 0x0002 +#define TMS9901_INT2 0x0004 +#define TMS9901_INT3 0x0008 // overridden by the timer interrupt +#define TMS9901_INT4 0x0010 +#define TMS9901_INT5 0x0020 +#define TMS9901_INT6 0x0040 +#define TMS9901_INT7 0x0080 +#define TMS9901_INT8 0x0100 +#define TMS9901_INT9 0x0200 +#define TMS9901_INTA 0x0400 +#define TMS9901_INTB 0x0800 +#define TMS9901_INTC 0x1000 +#define TMS9901_INTD 0x2000 +#define TMS9901_INTE 0x4000 +#define TMS9901_INTF 0x8000 + +enum +{ + TMS9901_CB_INT7 = 0, + TMS9901_INT8_INT15 = 1, + TMS9901_P0_P7 = 2, + TMS9901_P8_P15 = 3 +}; + +/*************************************************************************** + CLASS DEFINITION +***************************************************************************/ + +class tms9901_device : public device_t +{ +public: + tms9901_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + void set_single_int(int pin_number, int state); + + DECLARE_READ8_MEMBER( read ); + DECLARE_WRITE8_MEMBER( write ); + + template static devcb_base &static_set_readblock_callback(device_t &device, _Object object) { return downcast(device).m_read_block.set_callback(object); } + + template static devcb_base &static_set_p0_callback(device_t &device, _Object object) { return downcast(device).m_write_p0.set_callback(object); } + template static devcb_base &static_set_p1_callback(device_t &device, _Object object) { return downcast(device).m_write_p1.set_callback(object); } + template static devcb_base &static_set_p2_callback(device_t &device, _Object object) { return downcast(device).m_write_p2.set_callback(object); } + template static devcb_base &static_set_p3_callback(device_t &device, _Object object) { return downcast(device).m_write_p3.set_callback(object); } + template static devcb_base &static_set_p4_callback(device_t &device, _Object object) { return downcast(device).m_write_p4.set_callback(object); } + template static devcb_base &static_set_p5_callback(device_t &device, _Object object) { return downcast(device).m_write_p5.set_callback(object); } + template static devcb_base &static_set_p6_callback(device_t &device, _Object object) { return downcast(device).m_write_p6.set_callback(object); } + template static devcb_base &static_set_p7_callback(device_t &device, _Object object) { return downcast(device).m_write_p7.set_callback(object); } + template static devcb_base &static_set_p8_callback(device_t &device, _Object object) { return downcast(device).m_write_p8.set_callback(object); } + template static devcb_base &static_set_p9_callback(device_t &device, _Object object) { return downcast(device).m_write_p9.set_callback(object); } + template static devcb_base &static_set_p10_callback(device_t &device, _Object object) { return downcast(device).m_write_p10.set_callback(object); } + template static devcb_base &static_set_p11_callback(device_t &device, _Object object) { return downcast(device).m_write_p11.set_callback(object); } + template static devcb_base &static_set_p12_callback(device_t &device, _Object object) { return downcast(device).m_write_p12.set_callback(object); } + template static devcb_base &static_set_p13_callback(device_t &device, _Object object) { return downcast(device).m_write_p13.set_callback(object); } + template static devcb_base &static_set_p14_callback(device_t &device, _Object object) { return downcast(device).m_write_p14.set_callback(object); } + template static devcb_base &static_set_p15_callback(device_t &device, _Object object) { return downcast(device).m_write_p15.set_callback(object); } + + template static devcb_base &static_set_intlevel_callback(device_t &device, _Object object) { return downcast(device).m_interrupt.set_callback(object); } + +private: + static const device_timer_id DECREMENTER = 0; + + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + void timer_reload(void); + void field_interrupts(void); + + void device_start(void); + void device_stop(void); + void device_reset(void); + + // State of the INT1-INT15 lines (must be inverted when queried) + // Note that the levels must also be delivered when reading the pins, which + // may require to latch the int levels. + int m_int_state; + int m_old_int_state; // stores the previous value to avoid useless INT line assertions + int m_enabled_ints; // interrupt enable mask + + bool m_int_pending; // status of the int* pin (connected to TMS9900) + bool m_timer_int_pending; // timer int pending (overrides int3 pin if timer enabled) + + // PIO registers + int m_pio_direction; // direction register for PIO + + // current PIO output (to be masked with pio_direction) + int m_pio_output; + + // mirrors used for INT7*-INT15* + int m_pio_direction_mirror; + int m_pio_output_mirror; + + // ======================================================================= + + // TMS9901 clock mode + // false = so-called interrupt mode (read interrupt state, write interrupt enable mask) + // true = clock mode (read/write clock interval) + bool m_clock_mode; + + // MESS timer, used to emulate the decrementer register + emu_timer *m_decrementer; + + // clock interval, loaded in decrementer when it reaches 0. + // 0 means decrementer off + int m_clock_register; + + // Current decrementer value + int m_decrementer_value; + + // when we go into timer mode, the decrementer is copied there to allow to read it reliably + int m_clock_read_register; + + // ======================================================================= + + // Read callback. + devcb_read8 m_read_block; + + // I/O lines, used for output. When used as inputs, the levels are delivered via the m_read_block + devcb_write_line m_write_p0; + devcb_write_line m_write_p1; + devcb_write_line m_write_p2; + devcb_write_line m_write_p3; + devcb_write_line m_write_p4; + devcb_write_line m_write_p5; + devcb_write_line m_write_p6; + devcb_write_line m_write_p7; + devcb_write_line m_write_p8; + devcb_write_line m_write_p9; + devcb_write_line m_write_p10; + devcb_write_line m_write_p11; + devcb_write_line m_write_p12; + devcb_write_line m_write_p13; + devcb_write_line m_write_p14; + devcb_write_line m_write_p15; + + // The invocation corresponds to the INTREQ signal (with the level passed as data) + // and the address delivers the interrupt level (0-15) + devcb_write8 m_interrupt; +}; + +/*************************************************************************** + DEVICE CONFIGURATION MACROS +***************************************************************************/ + +#define MCFG_TMS9901_READBLOCK_HANDLER( _read ) \ + devcb = &tms9901_device::static_set_readblock_callback( *device, DEVCB_##_read ); + +#define MCFG_TMS9901_P0_HANDLER( _write ) \ + devcb = &tms9901_device::static_set_p0_callback( *device, DEVCB_##_write ); + +#define MCFG_TMS9901_P1_HANDLER( _write ) \ + devcb = &tms9901_device::static_set_p1_callback( *device, DEVCB_##_write ); + +#define MCFG_TMS9901_P2_HANDLER( _write ) \ + devcb = &tms9901_device::static_set_p2_callback( *device, DEVCB_##_write ); + +#define MCFG_TMS9901_P3_HANDLER( _write ) \ + devcb = &tms9901_device::static_set_p3_callback( *device, DEVCB_##_write ); + +#define MCFG_TMS9901_P4_HANDLER( _write ) \ + devcb = &tms9901_device::static_set_p4_callback( *device, DEVCB_##_write ); + +#define MCFG_TMS9901_P5_HANDLER( _write ) \ + devcb = &tms9901_device::static_set_p5_callback( *device, DEVCB_##_write ); + +#define MCFG_TMS9901_P6_HANDLER( _write ) \ + devcb = &tms9901_device::static_set_p6_callback( *device, DEVCB_##_write ); + +#define MCFG_TMS9901_P7_HANDLER( _write ) \ + devcb = &tms9901_device::static_set_p7_callback( *device, DEVCB_##_write ); + +#define MCFG_TMS9901_P8_HANDLER( _write ) \ + devcb = &tms9901_device::static_set_p8_callback( *device, DEVCB_##_write ); + +#define MCFG_TMS9901_P9_HANDLER( _write ) \ + devcb = &tms9901_device::static_set_p9_callback( *device, DEVCB_##_write ); + +#define MCFG_TMS9901_P10_HANDLER( _write ) \ + devcb = &tms9901_device::static_set_p10_callback( *device, DEVCB_##_write ); + +#define MCFG_TMS9901_P11_HANDLER( _write ) \ + devcb = &tms9901_device::static_set_p11_callback( *device, DEVCB_##_write ); + +#define MCFG_TMS9901_P12_HANDLER( _write ) \ + devcb = &tms9901_device::static_set_p12_callback( *device, DEVCB_##_write ); + +#define MCFG_TMS9901_P13_HANDLER( _write ) \ + devcb = &tms9901_device::static_set_p13_callback( *device, DEVCB_##_write ); + +#define MCFG_TMS9901_P14_HANDLER( _write ) \ + devcb = &tms9901_device::static_set_p14_callback( *device, DEVCB_##_write ); + +#define MCFG_TMS9901_P15_HANDLER( _write ) \ + devcb = &tms9901_device::static_set_p15_callback( *device, DEVCB_##_write ); + +#define MCFG_TMS9901_INTLEVEL_HANDLER( _intlevel ) \ + devcb = &tms9901_device::static_set_intlevel_callback( *device, DEVCB_##_intlevel ); + +#endif /* __TMS9901_H__ */ diff --git a/src/devices/machine/tms9902.c b/src/devices/machine/tms9902.c new file mode 100644 index 00000000000..557da504f96 --- /dev/null +++ b/src/devices/machine/tms9902.c @@ -0,0 +1,847 @@ +// license:BSD-3-Clause +// copyright-holders:Michael Zapf +/**************************************************************************** + + TMS9902 Asynchronous Communication Controller + + TMS9902 is an asynchronous serial controller for use with the TI990 and + TMS9900 family. It provides serial I/O, three extra I/O pins (namely RTS, + DSR and CTS), and a timer. It communicates with the CPU through the CRU + I/O bus, and one interrupt pin. + + +----+--+----+ + <- /INT |1 \--/ 18| VCC + <- XOUT |2 17| /CE <- + -> RIN |3 16| /PHI <- + <- CRUIN |4 15| CRUCLK <- + <- /RTS |5 14| S0 <- + -> /CTS |6 13| S1 <- + -> /DSR |7 12| S2 <- + -> CRUOUT |8 11| S3 <- + VSS |9 10| S4 <- + +------------+ + + The CRUIN line borrows its name from the connector of the connected CPU + where it is an input, so CRUIN is an output of this chip. The same is true + for CRUOUT. + + /PHI is a TTL clock input with 4 MHz maximum rate. + + IMPORTANT NOTE: The previous versions of TMS9902 attempted to write their + output to a file. This implementation is able to communicate with an external + UART via a socket connection and an external bridge. However, the work is + not done yet, and until then the file writing is disabled. + + Raphael Nabet, 2003 + Michael Zapf, 2011 + February 2012: Rewritten as class + +*****************************************************************************/ + +#include +#include "tms9902.h" + +#define VERBOSE 1 +#define LOG logerror + +enum +{ + DECTIMER, + RECVTIMER, + SENDTIMER +}; + +// Polling frequency. We use a much higher value to allow for line state changes +// happening between character transmissions (which happen in parallel in real +// communications but which must be serialized here) +#define POLLING_FREQ 20000 + + +/* + Constructor +*/ +tms9902_device::tms9902_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, TMS9902, "TMS9902 ACC", tag, owner, clock, "tms9902", __FILE__), + m_int_cb(*this), + m_rcv_cb(*this), + m_xmit_cb(*this), + m_ctrl_cb(*this) +{ +} + +/* + should be called after any change to int_state or enabled_ints. +*/ +void tms9902_device::field_interrupts() +{ + bool new_int = (m_DSCH && m_DSCENB) + || (m_RBRL && m_RIENB) + || (m_XBRE && m_XBIENB) + || (m_TIMELP && m_TIMENB); + if (VERBOSE>8) LOG("TMS9902: interrupt flags (DSCH = %02x, DSCENB = %02x), (RBRL = %02x, RIENB = %02x), (XBRE = %02x, XBIENB = %02x), (TIMELP = %02x, TIMENB = %02x)\n", + m_DSCH, m_DSCENB, m_RBRL, m_RIENB, m_XBRE, m_XBIENB, m_TIMELP, m_TIMENB); + + if (new_int != m_INT) + { + // Only consider edges + m_INT = new_int; + if (VERBOSE>3) LOG("TMS9902: /INT = %s\n", (m_INT)? "asserted" : "cleared"); + m_int_cb(m_INT? ASSERT_LINE : CLEAR_LINE); + } +} + +/* + Called whenever the incoming CTS* line changes. This should be called by + the device that contains the UART. +*/ +void tms9902_device::rcv_cts(line_state state) +{ + bool previous = m_CTSin; + + // CTSin is an internal register of the TMS9902 with positive logic + m_CTSin = (state==ASSERT_LINE); + + if (VERBOSE>3) LOG("TMS9902: CTS* = %s\n", (state==ASSERT_LINE)? "asserted" : "cleared"); + + if (m_CTSin != previous) + { + m_DSCH = true; + field_interrupts(); + + // If CTS becomes asserted and we have been sending + if (state==ASSERT_LINE && m_RTSout) + { + // and if the byte buffer is empty + if (m_XBRE) + { + // and we want to have a BRK, send it + if (m_BRKON) send_break(true); + } + else + { + // Buffer is not empty, we can send it + // If the shift register is empty, transfer the data + if (m_XSRE && !m_BRKout) + { + initiate_transmit(); + } + } + } + } + else + { + m_DSCH = false; + if (VERBOSE>4) LOG("TMS9902: no change in CTS line, no interrupt."); + } +} + +void tms9902_device::set_clock(bool state) +{ + if (state) + m_recvtimer->adjust(attotime::from_msec(1), 0, attotime::from_hz(POLLING_FREQ)); + else + m_recvtimer->reset(); +} + +/* + Called whenever the incoming DSR* line changes. This should be called by + the device that contains the UART. +*/ +void tms9902_device::rcv_dsr(line_state state) +{ + bool previous = m_DSRin; + if (VERBOSE>3) LOG("TMS9902: DSR* = %s\n", (state==ASSERT_LINE)? "asserted" : "cleared"); + m_DSRin = (state==ASSERT_LINE); + + if (m_DSRin != previous) + { + m_DSCH = true; + field_interrupts(); + } + else + { + m_DSCH = false; + if (VERBOSE>4) LOG("TMS9902: no change in DSR line, no interrupt."); + } +} + +/* + Called whenever the incoming RIN line changes. This should be called by + the device that contains the UART. Unlike the real thing, we deliver + complete bytes in one go. +*/ +void tms9902_device::rcv_data(UINT8 data) +{ + // Put the received byte into the 1-byte receive buffer + m_RBR = data; + + // Clear last errors + m_RFER = false; + m_RPER = false; + + if (!m_RBRL) + { + // Receive buffer was empty + m_RBRL = true; + m_ROVER = false; + if (VERBOSE>3) LOG("TMS9902: Receive buffer loaded with byte %02x\n", data); + field_interrupts(); + } + else + { + // Receive buffer was full + m_ROVER = true; + if (VERBOSE>1) LOG("TMS9902: Receive buffer still loaded; overflow error\n"); + } +} + +//------------------------------------------------ + +/* + Framing error. This can only be detected by a remotely attached real UART; + if we get a report on a framing error we use it to announce the framing error + as if it occurred here. + The flag is reset by the next correctly received byte. +*/ +void tms9902_device::rcv_framing_error() +{ + if (VERBOSE>2) LOG("TMS9902: Detected framing error\n"); + m_RFER = true; +} + +/* + Parity error. This can only be detected by a remotely attached real UART; + if we get a report on a parity error we use it to announce the parity error + as if it occurred here. + The flag is reset by the next correctly received byte. +*/ +void tms9902_device::rcv_parity_error() +{ + if (VERBOSE>2) LOG("TMS9902: Detected parity error\n"); + m_RPER = true; +} + +/* + Incoming BREAK condition. The TMS9902 does not show any directly visible + reactions on a BREAK (no interrupt, no flag set). A BREAK is a time period + of low level on the RIN pin which makes the chip re-synchronize on the + next rising edge. +*/ +void tms9902_device::rcv_break(bool value) +{ + if (VERBOSE>2) LOG("TMS9902: Receive BREAK=%d (no effect)\n", value? 1:0); +} + +//------------------------------------------------ + +/* + Timer callback +*/ +void tms9902_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch (id) + { + // This call-back is called by the MESS timer system when the decrementer + // reaches 0. + case DECTIMER: + m_TIMERR = m_TIMELP; + break; + + // Callback for the autonomous operations of the chip. This is normally + // controlled by an external clock of 3-4 MHz, internally divided by 3 or 4, + // depending on CLK4M. With this timer, reception of characters becomes + // possible. + case RECVTIMER: + m_rcv_cb(ASSERT_LINE); + break; + + case SENDTIMER: + // Byte has been sent + m_XSRE = true; + + // In the meantime, the CPU may have pushed a new byte into the XBR + // so we loop until all data are transferred + if (!m_XBRE && m_CTSin) + { + initiate_transmit(); + } + break; + } +} + +/* + load the content of clockinvl into the decrementer +*/ +void tms9902_device::reload_interval_timer() +{ + if (m_TMR) + { /* reset clock interval */ + m_dectimer->adjust( + attotime::from_double((double) m_TMR / (m_clock_rate / ((m_CLK4M) ? 4. : 3.) / 64.)), + 0, + attotime::from_double((double) m_TMR / (m_clock_rate / ((m_CLK4M) ? 4. : 3.) / 64.))); + } + else + { /* clock interval == 0 -> no timer */ + m_dectimer->enable(0); + } +} + +void tms9902_device::send_break(bool state) +{ + if (state != m_BRKout) + { + m_BRKout = state; + if (VERBOSE>2) LOG("TMS9902: Sending BREAK=%d\n", state? 1:0); + + // Signal BRK (on/off) to the remote site + m_ctrl_cb((offs_t)(EXCEPT | BRK), state? 1:0); + } +} + +/* + Baudpoll value allows the callback function to know when the next data byte shall be delivered. +*/ +double tms9902_device::get_baudpoll() +{ + return m_baudpoll; +} + +// ========================================================================== + +/* + Sets the data rate for the receiver part. If a remote UART is attached, + propagate this setting. + The TMS9902 calculates the baud rate from the external clock, and the result + does not match the known baud rates precisely (e.g. for 9600 baud the + closest value is 9615). Other UARTs may have a different way to set baud + rates. Thus we transmit the bit pattern and leave it up to the remote UART + to calculate its own baud rate from it. Apart from that, the callback + function should add information about the UART. + + CLK4M RDV8 RDR9 RDR8 | RDR7 RDR6 RDR5 RDR4 | RDR3 RDR2 RDR1 RDR0 +*/ +void tms9902_device::set_receive_data_rate() +{ + int value = (m_CLK4M? 0x800 : 0) | (m_RDV8? 0x400 : 0) | m_RDR; + if (VERBOSE>3) LOG("TMS9902: receive rate = %04x\n", value); + + // Calculate the ratio between receive baud rate and polling frequency + double fint = m_clock_rate / ((m_CLK4M) ? 4.0 : 3.0); + double baud = fint / (2.0 * ((m_RDV8)? 8:1) * m_RDR); + + // We assume 10 bit per character (7 data usually add 1 parity; 1 start, 1 stop) + // This value represents the ratio of data inputs of one poll. + // Thus the callback function should add up this value on each poll + // and deliver a data input not before it sums up to 1. + m_baudpoll = (double)(baud / (10*POLLING_FREQ)); + if (VERBOSE>3) LOG ("TMS9902: baudpoll = %f\n", m_baudpoll); + + m_last_config_value = value; + m_ctrl_cb((offs_t)CONFIG, RATERECV); +} + +/* + Sets the data rate for the sender part. If a remote UART is attached, + propagate this setting. +*/ +void tms9902_device::set_transmit_data_rate() +{ + int value = (m_CLK4M? 0x800 : 0) | (m_XDV8? 0x400 : 0) | m_XDR; + if (VERBOSE>3) LOG("TMS9902: set transmit rate = %04x\n", value); + m_last_config_value = value; + m_ctrl_cb((offs_t)CONFIG, RATEXMIT); +} + +void tms9902_device::set_stop_bits() +{ + int value = m_STOPB; + if (VERBOSE>3) LOG("TMS9902: set stop bits = %02x\n", value); + m_last_config_value = value; + m_ctrl_cb((offs_t)CONFIG, STOPBITS); +} + +void tms9902_device::set_data_bits() +{ + int value = m_RCL; + if (VERBOSE>3) LOG("TMS9902: set data bits = %02x\n", value); + m_last_config_value = value; + m_ctrl_cb((offs_t)CONFIG, DATABITS); +} + +void tms9902_device::set_parity() +{ + int value = (m_PENB? 2:0) | (m_ODDP? 1:0); + if (VERBOSE>3) LOG("TMS9902: set parity = %02x\n", value); + m_last_config_value = value; + m_ctrl_cb((offs_t)CONFIG, PARITY); +} + +void tms9902_device::transmit_line_state() +{ + // 00ab cdef = setting line RTS=a, CTS=b, DSR=c, DCD=d, DTR=e, RI=f + // The 9902 only outputs RTS and BRK + if (VERBOSE>3) LOG("TMS9902: transmitting line state (only RTS) = %02x\n", (m_RTSout)? 1:0); + m_last_config_value = (m_RTSout)? RTS : 0; + m_ctrl_cb((offs_t)LINES, RTS); +} + +void tms9902_device::set_rts(line_state state) +{ + bool lstate = (state==ASSERT_LINE); + + if (lstate != m_RTSout) + { + // Signal RTS to the modem + if (VERBOSE>3) LOG("TMS9902: Set RTS=%d\n", lstate? 1:0); + m_RTSout = lstate; + transmit_line_state(); + } +} + +int tms9902_device::get_config_value() +{ + return m_last_config_value; +} + +// ========================================================================== + +void tms9902_device::initiate_transmit() +{ + if (m_BRKON && m_CTSin) + /* enter break mode */ + send_break(true); + else + { + if (!m_RTSON && (!m_CTSin || (m_XBRE && !m_BRKout))) + /* clear RTS output */ + set_rts(CLEAR_LINE); + else + { + if (VERBOSE>5) LOG("TMS9902: transferring XBR to XSR; XSRE=false, XBRE=true\n"); + m_XSR = m_XBR; + m_XSRE = false; + m_XBRE = true; + + field_interrupts(); + + if (VERBOSE>4) LOG("TMS9902: transmit XSR=%02x, RCL=%02x\n", m_XSR, m_RCL); + + m_xmit_cb((offs_t)0, m_XSR & (0xff >> (3-m_RCL))); + + // Should store that somewhere (but the CPU is fast enough, can afford to recalc :-) ) + double fint = m_clock_rate / ((m_CLK4M) ? 4.0 : 3.0); + double baud = fint / (2.0 * ((m_RDV8)? 8:1) * m_RDR); + + // Time for transmitting 10 bit (8 bit + start + stop) + m_sendtimer->adjust(attotime::from_hz(baud/10.0)); + } + } +} + + + +/*---------------------------------------------------------------- + TMS9902 CRU interface. +----------------------------------------------------------------*/ + +/* + Read a 8 bit chunk from tms9902. + + signification: + bit 0-7: RBR0-7 Receive Buffer register + bit 8: not used (always 0) + bit 9: RCVERR Receive Error (RFER | ROVER | RPER) + bit 10: RPER Receive Parity Error + bit 11: ROVER Receive Overrun Error + bit 12: RFER Receive Framing Error + bit 13-15: not emulated, normally used for diagnostics + bit 16: RBINT (RBRL&RIENB) +*/ +READ8_MEMBER( tms9902_device::cruread ) +{ + UINT8 answer = 0; + + offset &= 0x0003; + + switch (offset) + { + case 3: // Bits 31-24 + if (m_INT) answer |= 0x80; + if (m_LDCTRL || m_LDIR || m_LRDR || m_LXDR || m_BRKON) answer |= 0x40; + if (m_DSCH) answer |= 0x20; + if (m_CTSin) answer |= 0x10; + if (m_DSRin) answer |= 0x08; + if (m_RTSout) answer |= 0x04; + if (m_TIMELP) answer |= 0x02; + if (m_TIMERR) answer |= 0x01; + break; + + case 2: // Bits 23-16 + if (m_XSRE) answer |= 0x80; + if (m_XBRE) answer |= 0x40; + if (m_RBRL) answer |= 0x20; + if (m_DSCH && m_DSCENB) answer |= 0x10; + if (m_TIMELP && m_TIMENB) answer |= 0x08; + if (m_XBRE && m_XBIENB) answer |= 0x02; + if (m_RBRL && m_RIENB) answer |= 0x01; + break; + + case 1: // Bits 15-8 + if (m_RIN) answer |= 0x80; + if (m_RSBD) answer |= 0x40; + if (m_RFBD) answer |= 0x20; + if (m_RFER) answer |= 0x10; + if (m_ROVER) answer |= 0x08; + if (m_RPER) answer |= 0x04; + if (m_RPER || m_RFER || m_ROVER) answer |= 0x02; + break; + + case 0: // Bits 7-0 + answer = m_RBR; + break; + } + if (VERBOSE>7) LOG("TMS9902: Reading flag bits %d - %d = %02x\n", ((offset+1)*8-1), offset*8, answer); + return answer; +} + +static inline void set_bits8(UINT8 *reg, UINT8 bits, bool set) +{ + if (set) + *reg |= bits; + else + *reg &= ~bits; +} + +static inline void set_bits16(UINT16 *reg, UINT16 bits, bool set) +{ + if (set) + *reg |= bits; + else + *reg &= ~bits; +} + +void tms9902_device::reset_uart() +{ + if (VERBOSE>1) LOG("TMS9902: resetting\n"); + + /* disable all interrupts */ + m_DSCENB = false; // Data Set Change Interrupt Enable + m_TIMENB = false; // Timer Interrupt Enable + m_XBIENB = false; // Transmit Buffer Interrupt Enable + m_RIENB = false; // Read Buffer Interrupt Enable + + /* initialize transmitter */ + m_XBRE = true; // Transmit Buffer Register Empty + m_XSRE = true; // Transmit Shift Register Empty + + /* initialize receiver */ + m_RBRL = false; // Read Buffer Register Loaded + + /* clear RTS */ + m_RTSON = false; // Request-to-send on (flag) + m_RTSout = true; // Note we are doing this to ensure the state is sent to the interface + set_rts(CLEAR_LINE); + m_RTSout = false; // what we actually want + + /* set all register load flags to 1 */ + m_LDCTRL = true; + m_LDIR = true; + m_LRDR = true; + m_LXDR = true; + + /* clear break condition */ + m_BRKON = false; + m_BRKout = false; + + m_DSCH = false; + m_TIMELP = false; + m_INT = false; + m_CTSin = false; + + m_TMR = 0; + m_STOPB = 0; + m_RCL = 0; + m_XDR = 0; + m_RDR = 0; + m_RBR = 0; + m_XBR = 0; + m_XSR = 0; + + // m_INT will be cleared in field_interrupts + field_interrupts(); +} + +/* + TMS9902 CRU write +*/ +WRITE8_MEMBER( tms9902_device::cruwrite ) +{ + data &= 1; /* clear extra bits */ + + offset &= 0x1F; + if (VERBOSE>5) LOG("TMS9902: Setting bit %d = %02x\n", offset, data); + + if (offset <= 10) + { + UINT16 mask = (1 << offset); + + if (m_LDCTRL) + { // Control Register mode. Values written to bits 0-7 are copied + // into the control register. + switch (offset) + { + case 0: + set_bits8(&m_RCL, 0x01, (data!=0)); + // we assume that bits are written in increasing order + // so we do not transmit the data bits twice + // (will fail when bit 1 is written first) + break; + case 1: + set_bits8(&m_RCL, 0x02, (data!=0)); + set_data_bits(); + break; + case 2: + break; + case 3: + m_CLK4M = (data!=0); + break; + case 4: + m_ODDP = (data!=0); + // we also assume that the parity type is set before the parity enable + break; + case 5: + m_PENB = (data!=0); + set_parity(); + break; + case 6: + set_bits8(&m_STOPB, 0x01, (data!=0)); + break; + case 7: + set_bits8(&m_STOPB, 0x02, (data!=0)); + // When bit 7 is written the control register mode is automatically terminated. + m_LDCTRL = false; + set_stop_bits(); + break; + default: + if (VERBOSE>1) LOG("tms9902: Invalid control register address %d\n", offset); + } + } + else if (m_LDIR) + { // Interval Register mode. Values written to bits 0-7 are copied + // into the interval register. + if (offset <= 7) + { + set_bits8(&m_TMR, mask, (data!=0)); + + if (offset == 7) + { + reload_interval_timer(); + // When bit 7 is written the interval register mode is automatically terminated. + m_LDIR = false; + } + } + } + else if (m_LRDR || m_LXDR) + { + if (m_LRDR) + { // Receive rate register mode. Values written to bits 0-10 are copied + // into the receive rate register. + if (offset < 10) + { + set_bits16(&m_RDR, mask, (data!=0)); + } + else + { + // When bit 10 is written the receive register mode is automatically terminated. + m_RDV8 = (data!=0); + m_LRDR = false; + set_receive_data_rate(); + } + } + if (m_LXDR) + { + // The transmit rate register can be set together with the receive rate register. + if (offset < 10) + { + set_bits16(&m_XDR, mask, (data!=0)); + } + else + { + // Note that the transmit rate register is NOT terminated when + // writing bit 10. This must be done by unsetting bit 11. + m_XDV8 = (data!=0); + set_transmit_data_rate(); + } + } + } + else + { // LDCTRL=LDIR=LRDR=LXRD=0: Transmit buffer register mode. Values + // written to bits 0-7 are transferred into the transmit buffer register. + if (offset <= 7) + { + set_bits8(&m_XBR, mask, (data!=0)); + + if (offset == 7) + { /* transmit */ + m_XBRE = false; + // Spec: When the transmitter is active, the contents of the Transmit + // Buffer Register are transferred to the Transmit Shift Register + // each time the previous character has been completely transmitted + // We need to check XSRE=true as well, as the implementation + // makes use of a timed transmission, during which XSRE=false + if (m_XSRE && m_RTSout && m_CTSin && !m_BRKout) + { + initiate_transmit(); + } + } + } + } + return; + } + switch (offset) + { + case 11: + m_LXDR = (data!=0); + break; + case 12: + m_LRDR = (data!=0); + break; + case 13: + m_LDIR = (data!=0); + // Spec: Each time LDIR is reset the contents of the Interval + // Register are loaded into the Interval Timer, thus restarting + // the timer. + if (data==0) + reload_interval_timer(); + break; + case 14: + m_LDCTRL = (data!=0); + break; + case 15: + m_TSTMD = (data!=0); // Test mode not implemented + break; + case 16: + if (data!=0) + { + m_RTSON = true; + set_rts(ASSERT_LINE); + if (m_CTSin) + { + if (m_XSRE && !m_XBRE && !m_BRKout) + initiate_transmit(); + else if (m_BRKON) + send_break(true); + } + } + else + { + m_RTSON = false; + if (m_XBRE && m_XSRE && !m_BRKout) + { + set_rts(CLEAR_LINE); + } + } + return; + case 17: + if (VERBOSE>3) LOG("TMS9902: set BRKON=%d; BRK=%d\n", data, m_BRKout? 1:0); + m_BRKON = (data!=0); + if (m_BRKout && data==0) + { + // clear BRK + m_BRKout = false; + if ((!m_XBRE) && m_CTSin) + { + /* transmit next byte */ + initiate_transmit(); + } + else if (!m_RTSON) + { + /* clear RTS */ + set_rts(CLEAR_LINE); + } + } + else if (m_XBRE && m_XSRE && m_RTSout && m_CTSin) + { + send_break(data!=0); + } + return; + case 18: + // Receiver Interrupt Enable + // According to spec, (re)setting this flag clears the RBRL flag + // (the only way to clear the flag!) + m_RIENB = (data!=0); + m_RBRL = false; + if (VERBOSE>4) LOG("TMS9902: set RBRL=0, set RIENB=%d\n", data); + field_interrupts(); + return; + case 19: + /* Transmit Buffer Interrupt Enable */ + m_XBIENB = (data!=0); + if (VERBOSE>4) LOG("TMS9902: set XBIENB=%d\n", data); + field_interrupts(); + return; + case 20: + /* Timer Interrupt Enable */ + m_TIMENB = (data!=0); + m_TIMELP = false; + m_TIMERR = false; + field_interrupts(); + return; + case 21: + /* Data Set Change Interrupt Enable */ + m_DSCENB = (data!=0); + m_DSCH = false; + if (VERBOSE>4) LOG("TMS9902: set DSCH=0, set DSCENB=%d\n", data); + field_interrupts(); + return; + case 31: + /* RESET */ + reset_uart(); + return; + default: + if (VERBOSE>1) LOG("TMS9902: Writing to undefined flag bit position %d = %01x\n", offset, data); + } +} + +/*------------------------------------------------- + device_stop - device-specific stop +-------------------------------------------------*/ + +void tms9902_device::device_stop() +{ + if (m_dectimer) + { + m_dectimer->reset(); + m_dectimer = NULL; + } +} + +/*------------------------------------------------- + device_reset - device-specific reset +-------------------------------------------------*/ + +void tms9902_device::device_reset() +{ + reset_uart(); +} + +/*------------------------------------------------- + device_start - device-specific startup +-------------------------------------------------*/ + +void tms9902_device::device_start() +{ + m_clock_rate = clock(); + + m_int_cb.resolve_safe(); + m_rcv_cb.resolve_safe(); + m_xmit_cb.resolve_safe(); + m_ctrl_cb.resolve_safe(); + + m_dectimer = timer_alloc(DECTIMER); + m_recvtimer = timer_alloc(RECVTIMER); + m_sendtimer = timer_alloc(SENDTIMER); +} + +const device_type TMS9902 = &device_creator; diff --git a/src/devices/machine/tms9902.h b/src/devices/machine/tms9902.h new file mode 100644 index 00000000000..ba775d3caa1 --- /dev/null +++ b/src/devices/machine/tms9902.h @@ -0,0 +1,203 @@ +// license:BSD-3-Clause +// copyright-holders:Michael Zapf +/**************************************************************************** + + TMS9902 Asynchronous Communication Controller + See tms9902.c for documentation + + Michael Zapf + + February 2012: Rewritten as class + +*****************************************************************************/ + +#ifndef __TMS9902_H__ +#define __TMS9902_H__ + +#include "emu.h" + +// Serial control protocol values +#define TYPE_TMS9902 0x01 + +// Configuration (output only) +#define CONFIG 0x80 +#define RATERECV 0x70 +#define RATEXMIT 0x60 +#define DATABITS 0x50 +#define STOPBITS 0x40 +#define PARITY 0x30 + +// Exceptional states (BRK: both directions; FRMERR/PARERR: input only) +#define EXCEPT 0x40 +#define BRK 0x02 +#define FRMERR 0x04 +#define PARERR 0x06 + +// Line states (RTS, DTR: output; CTS, DSR, RI, DCD: input) +#define LINES 0x00 +#define RTS 0x20 +#define CTS 0x10 +#define DSR 0x08 +#define DCD 0x04 +#define DTR 0x02 +#define RI 0x01 + +extern const device_type TMS9902; + +class tms9902_device : public device_t +{ +public: + tms9902_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + template static devcb_base &set_int_callback(device_t &device, _Object object) { return downcast(device).m_int_cb.set_callback(object); } + template static devcb_base &set_rcv_callback(device_t &device, _Object object) { return downcast(device).m_rcv_cb.set_callback(object); } + template static devcb_base &set_xmit_callback(device_t &device, _Object object) { return downcast(device).m_xmit_cb.set_callback(object); } + template static devcb_base &set_ctrl_callback(device_t &device, _Object object) { return downcast(device).m_ctrl_cb.set_callback(object); } + + void set_clock(bool state); + + void rcv_cts(line_state state); + void rcv_dsr(line_state state); + void rcv_data(UINT8 data); + void rcv_break(bool value); + void rcv_framing_error(); + void rcv_parity_error(); + + double get_baudpoll(); + + int get_config_value(); + + DECLARE_READ8_MEMBER( cruread ); + DECLARE_WRITE8_MEMBER( cruwrite ); + +protected: + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + virtual void device_start(); + virtual void device_reset(); + virtual void device_stop(); + +private: + void field_interrupts(); + void reload_interval_timer(); + void send_break(bool state); + void set_receive_data_rate(); + void set_transmit_data_rate(); + void set_stop_bits(); + void set_data_bits(); + void set_parity(); + void transmit_line_state(); + void set_rts(line_state state); + void initiate_transmit(); + void reset_uart(); + + devcb_write_line m_int_cb; + devcb_write_line m_rcv_cb; + devcb_write8 m_xmit_cb; + devcb_write8 m_ctrl_cb; // needs to be used with get_config_value + + // tms9902 clock rate (PHI* pin, normally connected to TMS9900 Phi3*) + // Official range is 2MHz-3.3MHz. Some tms9902s were sold as "MP9214", and + // were tested for speeds up to 4MHz, provided the clk4m control bit is set. + // (warning: 3MHz on a tms9900 is equivalent to 12MHz on a tms9995 or tms99000) + double m_clock_rate; + + /* Modes */ + bool m_LDCTRL; // Load control register + bool m_LDIR; // Load interval register + bool m_LRDR; // Load receive data register + bool m_LXDR; // Load transmit data register + bool m_TSTMD; // Test mode + + /* output pin */ + bool m_RTSON; // RTS-on request + + /* transmitter registers */ + bool m_BRKON; // BRK-on request + bool m_BRKout; // indicates the current BRK state + + UINT8 m_XBR; // transmit buffer register + UINT8 m_XSR; // transmit shift register + + /* receiver registers */ + UINT8 m_RBR; // Receive buffer register + + /* Interrupt enable flags */ + bool m_DSCENB; // Data set change interrupt enable + bool m_RIENB; // Receiver interrupt enable + bool m_XBIENB; // Tansmit buffer interrupt enable + bool m_TIMENB; // Timer interrupt enable + + /* + Rate registers. The receive bit rate calculates as + bitrate = clock1 / (2 * (8 ^ RDV8) * RDR) + (similarly for transmit) + + where clock1 = clock_rate / (CLK4M? 4:3) + */ + UINT16 m_RDR; // Receive data rate + bool m_RDV8; // Receive data rate divider + UINT16 m_XDR; // Transmit data rate + bool m_XDV8; // Transmit data rate divider + + /* Status flags */ + bool m_INT; // mirrors /INT output line, inverted + bool m_DSCH; // Data set status change + + bool m_CTSin; // Inverted /CTS input (i.e. CTS) + bool m_DSRin; // Inverted /DSR input (i.e. DSR) + bool m_RTSout; // Current inverted /RTS line state (i.e. RTS) + + bool m_TIMELP; // Timer elapsed + bool m_TIMERR; // Timer error + + bool m_XSRE; // Transmit shift register empty + bool m_XBRE; // Transmit buffer register empty + bool m_RBRL; // Receive buffer register loaded + + bool m_RIN; // State of the RIN pin + bool m_RSBD; // Receive start bit detect + bool m_RFBD; // Receive full bit detect + bool m_RFER; // Receive framing error + bool m_ROVER; // Receiver overflow + bool m_RPER; // Receive parity error + + UINT8 m_RCL; // Character length + bool m_ODDP; + bool m_PENB; + UINT8 m_STOPB; + bool m_CLK4M; // /PHI input divide select + + UINT8 m_TMR; /* interval timer */ + + /* clock registers */ + emu_timer *m_dectimer; /* MESS timer, used to emulate the decrementer register */ + emu_timer *m_recvtimer; + emu_timer *m_sendtimer; + + // This value is the ratio of data input versus the poll rate. The + // data source should deliver data bytes at every 1/baudpoll call. + // This is to ensure that data is delivered at a rate that is expected + // from the emulated program. + double m_baudpoll; + + // Caches the last configuration setting (used with the ctrl_callback) + int m_last_config_value; +}; + +/*************************************************************************** + DEVICE CONFIGURATION MACROS +***************************************************************************/ + +#define MCFG_TMS9902_INT_CB(_devcb) \ + devcb = &tms9902_device::set_int_callback(*device, DEVCB_##_devcb); + +#define MCFG_TMS9902_RCV_CB(_devcb) \ + devcb = &tms9902_device::set_rcv_callback(*device, DEVCB_##_devcb); + +#define MCFG_TMS9902_XMIT_CB(_devcb) \ + devcb = &tms9902_device::set_xmit_callback(*device, DEVCB_##_devcb); + +#define MCFG_TMS9902_CTRL_CB(_devcb) \ + devcb = &tms9902_device::set_ctrl_callback(*device, DEVCB_##_devcb); + +#endif /* __TMS9902_H__ */ diff --git a/src/devices/machine/upd1990a.c b/src/devices/machine/upd1990a.c new file mode 100644 index 00000000000..f40bb30af48 --- /dev/null +++ b/src/devices/machine/upd1990a.c @@ -0,0 +1,499 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder, hap +/********************************************************************** + + NEC uPD1990AC Serial I/O Calendar & Clock emulation + +**********************************************************************/ + +/* + + TODO: + - test mode is mostly untested + - how does timer-interval differ from timer-pulse? + +*/ + +#include "upd1990a.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define LOG 0 + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +// device type definition +const device_type UPD1990A = &device_creator; +const device_type UPD4990A = &device_creator; + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// upd1990a_device - constructor +//------------------------------------------------- + +upd1990a_device::upd1990a_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, UINT32 variant, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_rtc_interface(mconfig, *this), + m_write_data(*this), + m_write_tp(*this), + m_variant(variant) +{ +} + +upd1990a_device::upd1990a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, UPD1990A, "uPD1990A", tag, owner, clock, "upd1990a", __FILE__), + device_rtc_interface(mconfig, *this), + m_write_data(*this), + m_write_tp(*this), + m_variant(TYPE_1990A) +{ +} + +upd4990a_device::upd4990a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : upd1990a_device(mconfig, UPD4990A, "uPD4990A RTC", tag, owner, clock, TYPE_4990A, "upd4990a", __FILE__) { } + + +bool upd1990a_device::is_serial_mode() +{ + // uPD4990A is in serial mode if c0/1/2 = high/VDD + return (m_variant == TYPE_4990A && m_c_unlatched == 7); +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void upd1990a_device::device_start() +{ + (void)m_variant; + // resolve callbacks + m_write_data.resolve_safe(); + m_write_tp.resolve_safe(); + + // initialize + set_current_time(machine()); + + for (int i = 0; i < 7; i++) + m_shift_reg[i] = 0; + + m_oe = 0; + m_cs = 0; + m_stb = 0; + m_data_in = 0; + m_data_out = 0; + m_c = 0; + m_clk = 0; + m_tp = 0; + m_c_unlatched = 0; + m_testmode = false; + + // allocate timers + m_timer_clock = timer_alloc(TIMER_CLOCK); + m_timer_clock->adjust(attotime::from_hz(clock() / 32768.0), 0, attotime::from_hz(clock() / 32768.0)); // 1 second on XTAL_32_768kHz + m_timer_tp = timer_alloc(TIMER_TP); + m_timer_data_out = timer_alloc(TIMER_DATA_OUT); + m_timer_test_mode = timer_alloc(TIMER_TEST_MODE); + + // state saving + save_item(NAME(m_time_counter)); + save_item(NAME(m_shift_reg)); + save_item(NAME(m_oe)); + save_item(NAME(m_cs)); + save_item(NAME(m_stb)); + save_item(NAME(m_data_in)); + save_item(NAME(m_data_out)); + save_item(NAME(m_c)); + save_item(NAME(m_clk)); + save_item(NAME(m_tp)); + save_item(NAME(m_c_unlatched)); + save_item(NAME(m_testmode)); +} + + +//------------------------------------------------- +// rtc_clock_updated - +//------------------------------------------------- + +void upd1990a_device::rtc_clock_updated(int year, int month, int day, int day_of_week, int hour, int minute, int second) +{ + m_time_counter[0] = convert_to_bcd(second); + m_time_counter[1] = convert_to_bcd(minute); + m_time_counter[2] = convert_to_bcd(hour); + m_time_counter[3] = convert_to_bcd(day); + m_time_counter[4] = (month << 4) | (day_of_week - 1); + m_time_counter[5] = convert_to_bcd(year); +} + + +//------------------------------------------------- +// device_timer - handler timer events +//------------------------------------------------- + +void upd1990a_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch (id) + { + case TIMER_CLOCK: + advance_seconds(); + break; + + case TIMER_TP: + m_tp = !m_tp; + m_write_tp(m_tp); + break; + + case TIMER_DATA_OUT: + m_data_out = !m_data_out; + m_write_data(get_data_out()); + break; + + case TIMER_TEST_MODE: + if (m_oe) + { + /* TODO: completely untested */ + /* time counter is advanced from "Second" counter input */ + int max_shift = is_serial_mode() ? 6 : 5; + m_data_out = (m_time_counter[max_shift - 1] == 0); + m_write_data(get_data_out()); + + for (int i = 0; i < max_shift; i++) + { + m_time_counter[i]++; + if (m_time_counter[i] != 0) + return; + } + } + else + { + /* each counter is advanced in parallel, overflow carry does not affect next counter */ + m_data_out = 0; + + int max_shift = is_serial_mode() ? 6 : 5; + for (int i = 0; i < max_shift; i++) + { + m_time_counter[i]++; + m_data_out |= (m_time_counter[i] == 0); + } + m_write_data(get_data_out()); + } + + break; + } +} + + +//------------------------------------------------- +// stb_w - +//------------------------------------------------- + +WRITE_LINE_MEMBER( upd1990a_device::stb_w ) +{ + if (!m_cs) + return; + + if (LOG) logerror("uPD1990A '%s' STB %u\n", tag(), state); + + // rising edge + if (!m_stb && state) + { + // read command + if (is_serial_mode()) + m_c = m_shift_reg[6]; + else + { + m_c = m_c_unlatched; + if (m_c == 7) + m_c = MODE_TEST; + } + + if (LOG) logerror("uPD1990A '%s' Command %x\n", tag(), m_c); + + // common functions + if (m_c == MODE_REGISTER_HOLD || (m_c >= MODE_TP_64HZ && m_c < MODE_TEST)) + { + // enable time counter + m_timer_clock->enable(1); + + // disable testmode + m_testmode = false; + m_timer_test_mode->enable(0); + } + + switch (m_c) + { + case MODE_REGISTER_HOLD: + // 1Hz data out pulse + m_timer_data_out->adjust(attotime::zero, 0, attotime::from_hz((clock() / 32768.0) * 2.0)); + + // 64Hz time pulse + m_timer_tp->adjust(attotime::zero, 0, attotime::from_hz((clock() / 512.0) * 2.0)); + break; + + case MODE_SHIFT: + // enable time counter + if (!m_testmode) + m_timer_clock->enable(1); + + // data out LSB of shift register + m_timer_data_out->enable(0); + m_data_out = m_shift_reg[0] & 1; + m_write_data(get_data_out()); + + // 32Hz time pulse in testmode + if (m_testmode) + m_timer_tp->adjust(attotime::zero, 0, attotime::from_hz((clock() / 1024.0) * 2.0)); + + break; + + case MODE_TIME_SET: + { + // disable time counter + m_timer_clock->enable(0); + + // data out LSB of shift register + m_timer_data_out->enable(0); + m_data_out = m_shift_reg[0] & 1; + m_write_data(get_data_out()); + + // load shift register data into time counter + int max_shift = is_serial_mode() ? 6 : 5; + for (int i = 0; i < max_shift; i++) + m_time_counter[i] = m_shift_reg[i]; + + set_time(false, + bcd_to_integer(m_time_counter[5]), + m_time_counter[4] >> 4, + bcd_to_integer(m_time_counter[3]), + (m_time_counter[4] & 0xf) + 1, + bcd_to_integer(m_time_counter[2]), + bcd_to_integer(m_time_counter[1]), + bcd_to_integer(m_time_counter[0]) + ); + + // reset stage 10-15 of clock divider + m_timer_clock->adjust(attotime::from_ticks(m_timer_clock->remaining().as_ticks(clock()) % (clock() / 512), clock()), 0, attotime::from_hz(clock() / 32768.0)); + + // disable(low) time pulse in testmode + if (m_testmode) + { + m_timer_tp->enable(0); + m_tp = 0; + m_write_tp(m_tp); + } + + break; + } + + case MODE_TIME_READ: + { + // enable time counter + if (!m_testmode) + m_timer_clock->enable(1); + + // load time counter data into shift register + int max_shift = is_serial_mode() ? 6 : 5; + for (int i = 0; i < max_shift; i++) + m_shift_reg[i] = m_time_counter[i]; + + // data out pulse: uPD4990A: 1Hz, uPD1990A: 512Hz in testmode, 0.5Hz in normal mode + double div; + if (m_variant == TYPE_4990A) + div = 32768.0; + else if (m_testmode) + div = 64.0; + else div = 65536.0; + + m_timer_data_out->adjust(attotime::zero, 0, attotime::from_hz((clock() / div) * 2.0)); + + // 32Hz time pulse in testmode + if (m_testmode) + m_timer_tp->adjust(attotime::zero, 0, attotime::from_hz((clock() / 1024.0) * 2.0)); + + break; + } + + case MODE_TP_64HZ: + case MODE_TP_256HZ: + case MODE_TP_2048HZ: + case MODE_TP_4096HZ: + { + // set timer pulse + const double div[4] = { 512.0, 128.0, 16.0, 8.0 }; + m_timer_tp->adjust(attotime::zero, 0, attotime::from_hz((clock() / div[m_c - MODE_TP_64HZ]) * 2.0)); + + break; + } + + case MODE_TP_1S_INT: + case MODE_TP_10S_INT: + case MODE_TP_30S_INT: + case MODE_TP_60S_INT: + { + // set timer pulse + attotime one_second = attotime::from_hz(clock() / 32768.0); + const double mul[4] = { 1.0, 10.0, 30.0, 60.0 }; + m_timer_tp->adjust(attotime::zero, 0, one_second * mul[m_c - MODE_TP_1S_INT] / 2.0); + + break; + } + + case MODE_INT_RESET_OUTPUT: + case MODE_INT_RUN_CLOCK: + case MODE_INT_STOP_CLOCK: + // TODO + break; + + case MODE_TEST: + { + // disable time counter + m_timer_clock->enable(0); + + // disable data out pulse + m_timer_data_out->enable(0); + + // enable testmode + m_testmode = true; + m_timer_test_mode->enable(1); + const float div = (m_variant == TYPE_4990A) ? 4.0 : 32.0; // uPD4990A: 8192Hz, uPD1990A: 1024Hz + m_timer_test_mode->adjust(attotime::zero, 0, attotime::from_hz(clock() / div)); + break; + } + + default: + break; + } + } + + m_stb = state; +} + + +//------------------------------------------------- +// clk_w - +//------------------------------------------------- + +WRITE_LINE_MEMBER( upd1990a_device::clk_w ) +{ + if (!m_cs) + return; + + if (LOG) logerror("uPD1990A '%s' CLK %u\n", tag(), state); + + // rising edge + if (!m_clk && state) + { + int in = m_data_in; + + if (is_serial_mode()) + { + // always clock serial command register + in = m_shift_reg[6] & 1; + m_shift_reg[6] >>= 1; + m_shift_reg[6] |= (m_data_in << 3); + } + + if (m_c == MODE_SHIFT) + { + // clock shift register + int max_shift = is_serial_mode() ? 6 : 5; + for (int i = 0; i < max_shift; i++) + { + m_shift_reg[i] >>= 1; + if (i == (max_shift - 1)) + m_shift_reg[i] |= (in << 7); // shift in new bit + else + m_shift_reg[i] |= (m_shift_reg[i + 1] << 7 & 0x80); + } + + // data out LSB of shift register + m_data_out = m_shift_reg[0] & 1; + m_write_data(get_data_out()); + } + } + + m_clk = state; +} + + +//------------------------------------------------- +// misc input pins +//------------------------------------------------- + +WRITE_LINE_MEMBER( upd1990a_device::cs_w ) +{ + // chip select + if (LOG) logerror("uPD1990A '%s' CS %u\n", tag(), state); + m_cs = state; +} + +WRITE_LINE_MEMBER( upd1990a_device::oe_w ) +{ + // output enable + if (LOG) logerror("uPD1990A '%s' OE %u\n", tag(), state); + + int prev_oe = m_oe; + m_oe = state; + + if (m_oe != prev_oe && m_c != MODE_TEST) + m_write_data(get_data_out()); +} + +WRITE_LINE_MEMBER( upd1990a_device::c0_w ) +{ + if (LOG) logerror("uPD1990A '%s' C0 %u\n", tag(), state); + m_c_unlatched = (m_c_unlatched & 0x06) | state; +} + +WRITE_LINE_MEMBER( upd1990a_device::c1_w ) +{ + if (LOG) logerror("uPD1990A '%s' C1 %u\n", tag(), state); + m_c_unlatched = (m_c_unlatched & 0x05) | (state << 1); +} + +WRITE_LINE_MEMBER( upd1990a_device::c2_w ) +{ + if (LOG) logerror("uPD1990A '%s' C2 %u\n", tag(), state); + m_c_unlatched = (m_c_unlatched & 0x03) | (state << 2); +} + +WRITE_LINE_MEMBER( upd1990a_device::data_in_w ) +{ + // data input + if (LOG) logerror("uPD1990A '%s' DATA IN %u\n", tag(), state); + m_data_in = state; +} + + +//------------------------------------------------- +// output pins +//------------------------------------------------- + +int upd1990a_device::get_data_out() +{ + // except when in testmode, data_out is high impedance when OE is low + return (m_oe || m_testmode) ? m_data_out : 1; +} + + +READ_LINE_MEMBER( upd1990a_device::data_out_r ) +{ + return get_data_out(); +} + +READ_LINE_MEMBER( upd1990a_device::tp_r ) +{ + return m_tp; +} diff --git a/src/devices/machine/upd1990a.h b/src/devices/machine/upd1990a.h new file mode 100644 index 00000000000..745f6c6e648 --- /dev/null +++ b/src/devices/machine/upd1990a.h @@ -0,0 +1,161 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder, hap +/********************************************************************** + + NEC uPD1990AC Serial I/O Calendar & Clock emulation + +********************************************************************** + _____ _____ + C2 1 |* \_/ | 14 Vdd + C1 2 | | 13 XTAL + C0 3 | | 12 _XTAL + STB 4 | uPD1990AC | 11 OUT ENBL + CS 5 | | 10 TP + DATA IN 6 | | 9 DATA OUT + GND 7 |_____________| 8 CLK + +**********************************************************************/ + +#pragma once + +#ifndef __UPD1990A__ +#define __UPD1990A__ + +#include "emu.h" + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_UPD1990A_ADD(_tag, _clock, _data, _tp) \ + MCFG_DEVICE_ADD((_tag), UPD1990A, _clock) \ + downcast(device)->set_data_callback(DEVCB_##_data); \ + downcast(device)->set_tp_callback(DEVCB_##_tp); + +#define MCFG_UPD4990A_ADD(_tag, _clock, _data, _tp) \ + MCFG_DEVICE_ADD((_tag), UPD4990A, _clock) \ + downcast(device)->set_data_callback(DEVCB_##_data); \ + downcast(device)->set_tp_callback(DEVCB_##_tp); + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> upd1990a_device + +class upd1990a_device : public device_t, + public device_rtc_interface +{ +public: + // construction/destruction + upd1990a_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, UINT32 variant, const char *shortname, const char *source); + upd1990a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + template void set_data_callback(_data data) { m_write_data.set_callback(data); } + template void set_tp_callback(_tp tp) { m_write_tp.set_callback(tp); } + + DECLARE_WRITE_LINE_MEMBER( oe_w ); + DECLARE_WRITE_LINE_MEMBER( cs_w ); + DECLARE_WRITE_LINE_MEMBER( stb_w ); + DECLARE_WRITE_LINE_MEMBER( clk_w ); + DECLARE_WRITE_LINE_MEMBER( c0_w ); + DECLARE_WRITE_LINE_MEMBER( c1_w ); + DECLARE_WRITE_LINE_MEMBER( c2_w ); + DECLARE_WRITE_LINE_MEMBER( data_in_w ); + DECLARE_READ_LINE_MEMBER( data_out_r ); + DECLARE_READ_LINE_MEMBER( tp_r ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + // device_rtc_interface overrides + virtual void rtc_clock_updated(int year, int month, int day, int day_of_week, int hour, int minute, int second); + + enum + { + TYPE_1990A = 0, + TYPE_4990A + }; + +private: + enum + { + TIMER_CLOCK, + TIMER_TP, + TIMER_DATA_OUT, + TIMER_TEST_MODE + }; + + enum + { + MODE_REGISTER_HOLD = 0, + MODE_SHIFT, + MODE_TIME_SET, + MODE_TIME_READ, + MODE_TP_64HZ, + MODE_TP_256HZ, + MODE_TP_2048HZ, + MODE_TP_4096HZ, + MODE_TP_1S_INT, + MODE_TP_10S_INT, + MODE_TP_30S_INT, + MODE_TP_60S_INT, + MODE_INT_RESET_OUTPUT, + MODE_INT_RUN_CLOCK, + MODE_INT_STOP_CLOCK, + MODE_TEST + }; + + devcb_write_line m_write_data; + devcb_write_line m_write_tp; + + UINT8 m_time_counter[6]; // time counter + UINT8 m_shift_reg[7]; // shift register (40 bits, or 48 bits + serial command register) + + int m_oe; // output enable + int m_cs; // chip select + int m_stb; // strobe + int m_data_in; // data in + int m_data_out; // data out + int m_c; // latched command + int m_clk; // shift clock + int m_tp; // time pulse + int m_c_unlatched; // command waiting for STB + + bool m_testmode; // testmode active + + int m_variant; + + // timers + emu_timer *m_timer_clock; + emu_timer *m_timer_tp; + emu_timer *m_timer_data_out; + emu_timer *m_timer_test_mode; + + bool is_serial_mode(); + int get_data_out(); +}; + + +// ======================> upd4990a_device + +class upd4990a_device : public upd1990a_device +{ +public: + upd4990a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +// device type definitions +extern const device_type UPD1990A; +extern const device_type UPD4990A; + + + +#endif diff --git a/src/devices/machine/upd4701.c b/src/devices/machine/upd4701.c new file mode 100644 index 00000000000..4a7adfda291 --- /dev/null +++ b/src/devices/machine/upd4701.c @@ -0,0 +1,259 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/*************************************************************************** + + NEC uPD4701 + + Incremental Encoder Control + + 2009-06 Converted to be a device + +***************************************************************************/ + +#include "emu.h" +#include "upd4701.h" + +#define MASK_SWITCHES ( 7 ) +#define MASK_COUNTER ( 0xfff ) + +const device_type UPD4701 = &device_creator; + +upd4701_device::upd4701_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, UPD4701, "uPD4701 Encoder", tag, owner, clock, "upd4701", __FILE__) +{ +} + +//------------------------------------------------- +// device_config_complete - perform any +// operations now that the configuration is +// complete +//------------------------------------------------- + +void upd4701_device::device_config_complete() +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void upd4701_device::device_start() +{ + save_item(NAME(m_cs)); + save_item(NAME(m_xy)); + save_item(NAME(m_ul)); + save_item(NAME(m_resetx)); + save_item(NAME(m_resety)); + save_item(NAME(m_latchx)); + save_item(NAME(m_latchy)); + save_item(NAME(m_startx)); + save_item(NAME(m_starty)); + save_item(NAME(m_x)); + save_item(NAME(m_y)); + save_item(NAME(m_switches)); + save_item(NAME(m_latchswitches)); + save_item(NAME(m_cf)); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void upd4701_device::device_reset() +{ + m_cs = 1; + m_xy = 0; + m_ul = 0; + m_resetx = 0; + m_resety = 0; + m_latchx = 0; + m_latchy = 0; + m_startx = 0; + m_starty = 0; + m_x = 0; + m_y = 0; + m_switches = 0; + m_latchswitches = 0; + m_cf = 1; +} + +/* x,y increments can be 12bit (see MASK_COUNTER), hence we need a couple of +16bit handlers in the following */ + +/*------------------------------------------------- + ul_w +-------------------------------------------------*/ + +WRITE_LINE_MEMBER( upd4701_device::ul_w ) +{ + m_ul = state; +} + +/*------------------------------------------------- + xy_w +-------------------------------------------------*/ + +WRITE_LINE_MEMBER( upd4701_device::xy_w ) +{ + m_xy = state; +} + +/*------------------------------------------------- + cs_w +-------------------------------------------------*/ + +WRITE_LINE_MEMBER( upd4701_device::cs_w ) +{ + if (m_cs != state) + { + m_cs = state; + + if (!m_cs) + { + m_latchx = (m_x - m_startx) & MASK_COUNTER; + m_latchy = (m_y - m_starty) & MASK_COUNTER; + + m_latchswitches = (~m_switches) & MASK_SWITCHES; + if (m_latchswitches != 0) + { + m_latchswitches |= 8; + } + + m_cf = 1; + } + } +} + +/*------------------------------------------------- + resetx_w +-------------------------------------------------*/ + +WRITE_LINE_MEMBER( upd4701_device::resetx_w ) +{ + if (m_resetx != state) + { + m_resetx = state; + + if (m_resetx) + { + m_startx = m_x; + } + } +} + +/*------------------------------------------------- + resety_w +-------------------------------------------------*/ + +WRITE_LINE_MEMBER( upd4701_device::resety_w ) +{ + if (m_resety != state) + { + m_resety = state; + + if (m_resety) + { + m_starty = m_y; + } + } +} + +/*------------------------------------------------- + x_add +-------------------------------------------------*/ + +void upd4701_device::x_add( INT16 data ) +{ + if (!m_resetx && data != 0) + { + m_x += data; + + if (m_cs) + { + m_cf = 0; + } + } +} + +/*------------------------------------------------- + y_add +-------------------------------------------------*/ + +void upd4701_device::y_add( INT16 data ) +{ + if (!m_resety && data != 0) + { + m_y += data; + + if (m_cs) + { + m_cf = 0; + } + } +} + +/*------------------------------------------------- + switches_set +-------------------------------------------------*/ + +void upd4701_device::switches_set( UINT8 data ) +{ + m_switches = data; +} + +/*------------------------------------------------- + d_r +-------------------------------------------------*/ + +READ16_MEMBER( upd4701_device::d_r ) +{ + int data; + + if (m_cs) + { + return 0xff; + } + + if (m_xy) + { + data = m_latchy; + } + else + { + data = m_latchx; + } + + data |= m_latchswitches << 12; + + if (m_ul) + { + return data >> 8; + } + else + { + return data & 0xff; + } +} + +/*------------------------------------------------- + sf_r +-------------------------------------------------*/ + +READ_LINE_MEMBER( upd4701_device::sf_r ) +{ + if ((m_switches & MASK_SWITCHES) != MASK_SWITCHES) + { + return 0; + } + + return 1; +} + +/*------------------------------------------------- + cf_r +-------------------------------------------------*/ + +READ_LINE_MEMBER( upd4701_device::cf_r ) +{ + return m_cf; +} diff --git a/src/devices/machine/upd4701.h b/src/devices/machine/upd4701.h new file mode 100644 index 00000000000..e8cb0e0243f --- /dev/null +++ b/src/devices/machine/upd4701.h @@ -0,0 +1,66 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/*************************************************************************** + + NEC uPD4701 + + Incremental Encoder Control + +***************************************************************************/ + +#ifndef __UPD4701_H__ +#define __UPD4701_H__ + +/*************************************************************************** + MACROS / CONSTANTS +***************************************************************************/ + +class upd4701_device : public device_t +{ +public: + upd4701_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + void x_add( INT16 data ); + void y_add( INT16 data ); + void switches_set( UINT8 data ); + + DECLARE_WRITE_LINE_MEMBER( cs_w ); + DECLARE_WRITE_LINE_MEMBER( xy_w ); + DECLARE_WRITE_LINE_MEMBER( ul_w ); + DECLARE_WRITE_LINE_MEMBER( resetx_w ); + DECLARE_WRITE_LINE_MEMBER( resety_w ); + + DECLARE_READ16_MEMBER( d_r ); + DECLARE_READ_LINE_MEMBER( cf_r ); + DECLARE_READ_LINE_MEMBER( sf_r ); + +protected: + // device-level overrides + virtual void device_config_complete(); + virtual void device_start(); + virtual void device_reset(); +private: + // internal state + int m_cs; + int m_xy; + int m_ul; + int m_resetx; + int m_resety; + int m_latchx; + int m_latchy; + int m_startx; + int m_starty; + int m_x; + int m_y; + int m_switches; + int m_latchswitches; + int m_cf; +}; + +extern const device_type UPD4701; + + +#define MCFG_UPD4701_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, UPD4701, 0) + +#endif /* __UPD4701_H__ */ diff --git a/src/devices/machine/upd4992.c b/src/devices/machine/upd4992.c new file mode 100644 index 00000000000..3636a7e7d75 --- /dev/null +++ b/src/devices/machine/upd4992.c @@ -0,0 +1,156 @@ +// license:BSD-3-Clause +// copyright-holders: Angelo Salese +/*************************************************************************** + + uPD4992 parallel RTC + + TODO: + - Add timers + - Add leap year count + - Add 12 hours mode + - Add mode/control register + +***************************************************************************/ + +#include "emu.h" +#include "machine/upd4992.h" + + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +// device type definition +const device_type UPD4992 = &device_creator; + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// upd4992_device - constructor +//------------------------------------------------- + +upd4992_device::upd4992_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, UPD4992, "uPD4992 RTC", tag, owner, clock, "upd4992", __FILE__), + device_rtc_interface(mconfig, *this) +{ +} + + +//------------------------------------------------- +// device_validity_check - perform validity checks +// on this device +//------------------------------------------------- + +void upd4992_device::device_validity_check(validity_checker &valid) const +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void upd4992_device::device_start() +{ + m_timer_clock = timer_alloc(TIMER_CLOCK); + m_timer_clock->adjust(attotime::from_hz(clock() / 32768), 0, attotime::from_hz(clock() / 32768)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void upd4992_device::device_reset() +{ + set_current_time(machine()); +} + + +void upd4992_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch (id) + { + case TIMER_CLOCK: + advance_seconds(); + break; + } +} + +//------------------------------------------------- +// rtc_clock_updated - +//------------------------------------------------- + +void upd4992_device::rtc_clock_updated(int year, int month, int day, int day_of_week, int hour, int minute, int second) +{ +/* +[2] +x--- ---- 12/24H flag +-x-- ---- AM/PM flag +--xx ---- 10 hour digit +---- xxxx 1s hour digit +[3] +xx-- ---- Leap year control +--xx ---- Leap year counter +---- xxxx Day of week digit +[4] +xxxx ---- 10s day digit +---- xxxx 1s day digit +[5] +xxxx ---- 10s month digit +---- xxxx 1s month digit +[6] +xxxx ---- 10s year digit +---- xxxx 1s year digit +[7] +xxxx ---- Mode register +---- xxxx Control Register +*/ + m_rtc_regs[0] = convert_to_bcd(second); + m_rtc_regs[1] = convert_to_bcd(minute); + m_rtc_regs[2] = convert_to_bcd(hour); + m_rtc_regs[3] = day_of_week-1; + m_rtc_regs[4] = convert_to_bcd(day); + m_rtc_regs[5] = convert_to_bcd(month); + m_rtc_regs[6] = convert_to_bcd(year); +} + +//************************************************************************** +// READ/WRITE HANDLERS +//************************************************************************** + +READ8_MEMBER( upd4992_device::read ) +{ + return m_rtc_regs[offset]; +} + +WRITE8_MEMBER( upd4992_device::write ) +{ + if(offset == 7) + { + if(data & 8) + { + if(data & 2) // reset + { + // ... + } + + m_timer_clock->enable(data & 1); + } + } + else // TODO: perhaps there's a write inhibit? + { + m_rtc_regs[offset] = data; + set_time(1, bcd_to_integer(m_rtc_regs[6]), + bcd_to_integer(m_rtc_regs[5]), + bcd_to_integer(m_rtc_regs[4]), + m_rtc_regs[3]+1, + bcd_to_integer(m_rtc_regs[2]), + bcd_to_integer(m_rtc_regs[1]), + bcd_to_integer(m_rtc_regs[0])); + } +} diff --git a/src/devices/machine/upd4992.h b/src/devices/machine/upd4992.h new file mode 100644 index 00000000000..90d3f303c83 --- /dev/null +++ b/src/devices/machine/upd4992.h @@ -0,0 +1,73 @@ +// license:BSD-3-Clause +// copyright-holders: Angelo Salese +/*************************************************************************** + + uPD4992 RTC + +***************************************************************************/ + +#pragma once + +#ifndef __UPD4992DEV_H__ +#define __UPD4992DEV_H__ + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_UPD4992_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, UPD4992, XTAL_32_768kHz) + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> upd4992_device + +class upd4992_device : public device_t, + public device_rtc_interface +{ +public: + // construction/destruction + upd4992_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // I/O operations + DECLARE_WRITE8_MEMBER( write ); + DECLARE_READ8_MEMBER( read ); + +protected: + // device-level overrides + virtual void device_validity_check(validity_checker &valid) const; + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + virtual void rtc_clock_updated(int year, int month, int day, int day_of_week, int hour, int minute, int second); + +private: + enum + { + TIMER_CLOCK + //TIMER_TP, + //TIMER_DATA_OUT, + //TIMER_TEST_MODE + }; + + emu_timer *m_timer_clock; + UINT8 m_rtc_regs[8]; +}; + + +// device type definition +extern const device_type UPD4992; + + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + + + +#endif diff --git a/src/devices/machine/upd7002.c b/src/devices/machine/upd7002.c new file mode 100644 index 00000000000..b74d1bbf1d0 --- /dev/null +++ b/src/devices/machine/upd7002.c @@ -0,0 +1,172 @@ +// license:BSD-3-Clause +// copyright-holders:Gordon Jefferyes +/****************************************************************************** + uPD7002 Analogue to Digital Converter + + MESS Driver By: + + Gordon Jefferyes + mess_bbc@gjeffery.dircon.co.uk + +******************************************************************************/ + +#include "emu.h" +#include "upd7002.h" + + +/* Device Interface */ + +const device_type UPD7002 = &device_creator; + +upd7002_device::upd7002_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, UPD7002, "uPD7002", tag, owner, clock, "upd7002", __FILE__) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void upd7002_device::device_start() +{ + m_get_analogue_cb.bind_relative_to(*owner()); + m_eoc_cb.bind_relative_to(*owner()); + + // register for state saving + save_item(NAME(m_status)); + save_item(NAME(m_data1)); + save_item(NAME(m_data0)); + save_item(NAME(m_digitalvalue)); + save_item(NAME(m_conversion_counter)); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void upd7002_device::device_reset() +{ + m_status = 0; + m_data1 = 0; + m_data0 = 0; + m_digitalvalue = 0; + m_conversion_counter = 0; +} + + +/***************************************************************************** + Implementation +*****************************************************************************/ + + +READ8_MEMBER( upd7002_device::eoc_r ) +{ + return (m_status>>7)&0x01; +} + + +void upd7002_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch (id) + { + case TIMER_CONVERSION_COMPLETE: + { + int counter_value = param; + if (counter_value==m_conversion_counter) + { + // this really always does a 12 bit conversion + m_data1 = m_digitalvalue>>8; + m_data0 = m_digitalvalue&0xf0; + + // set the status register with top 2 MSB, not busy and conversion complete + m_status = (m_status & 0x0f)|((m_data1 & 0xc0)>>2)|0x40; + + // call the EOC function with EOC from status + // eoc_r(0) this has just been set to 0 + if (!m_eoc_cb.isnull()) m_eoc_cb(0); + m_conversion_counter=0; + } + break; + } + default: + assert_always(FALSE, "Unknown id in upd7002_device::device_timer"); + } +} + + +READ8_MEMBER( upd7002_device::read ) +{ + switch(offset&0x03) + { + case 0: + return m_status; + + case 1: + return m_data1; + + case 2: case 3: + return m_data0; + } + return 0; +} + + + +WRITE8_MEMBER( upd7002_device::write ) +{ + /* logerror("write to uPD7002 $%02X = $%02X\n",offset,data); */ + + switch(offset&0x03) + { + case 0: + /* + Data Latch/AD start + D0 and D1 together define which one of the four input channels is selected + D2 flag input, normally set to 0???? + D3 defines whether an 8 (0) or 12 (1) bit resolution conversion should occur + D4 to D7 not used. + + an 8 bit conversion typically takes 4ms + an 12 bit conversion typically takes 10ms + + writing to this register will initiate a conversion. + */ + + /* set D6=0 busy ,D7=1 conversion not complete */ + m_status=(data & 0x0f) | 0x80; + + // call the EOC function with EOC from status + // eoc_r(0) this has just been set to 1 + if (!m_eoc_cb.isnull()) m_eoc_cb(1); + + /* the uPD7002 works by sampling the analogue value at the start of the conversion + so it is read hear and stored until the end of the A to D conversion */ + + // this function should return a 16 bit value. + m_digitalvalue = m_get_analogue_cb(m_status & 0x03); + + m_conversion_counter++; + + // call a timer to start the conversion + if (m_status & 0x08) + { + // 12 bit conversion takes 10ms + timer_set(attotime::from_msec(10), TIMER_CONVERSION_COMPLETE, m_conversion_counter); + } else { + // 8 bit conversion takes 4ms + timer_set(attotime::from_msec(4), TIMER_CONVERSION_COMPLETE, m_conversion_counter); + } + break; + + case 1: case 2: + /* Nothing */ + break; + + case 3: + /* Test Mode: Used for inspecting the device, The data input-output terminals assume an input + state and are connected to the A/D counter. Therefore, the A/D conversion data + read out after this is meaningless. + */ + break; + } +} diff --git a/src/devices/machine/upd7002.h b/src/devices/machine/upd7002.h new file mode 100644 index 00000000000..aba6bb8b36f --- /dev/null +++ b/src/devices/machine/upd7002.h @@ -0,0 +1,106 @@ +// license:BSD-3-Clause +// copyright-holders:Gordon Jefferyes +/***************************************************************************** + * + * machine/upd7002.h + * + * uPD7002 Analogue to Digital Converter + * + * Driver by Gordon Jefferyes + * + ****************************************************************************/ + +#ifndef UPD7002_H_ +#define UPD7002_H_ + +/*************************************************************************** + TYPE DEFINITIONS +***************************************************************************/ + +typedef device_delegate upd7002_get_analogue_delegate; +#define UPD7002_GET_ANALOGUE(name) int name(int channel_number) + +typedef device_delegate upd7002_eoc_delegate; +#define UPD7002_EOC(name) void name(int data) + + +/*************************************************************************** + MACROS +***************************************************************************/ + +class upd7002_device : public device_t +{ +public: + upd7002_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + ~upd7002_device() {} + + static void set_get_analogue_callback(device_t &device, upd7002_get_analogue_delegate callback) { downcast(device).m_get_analogue_cb = callback; } + static void set_eoc_callback(device_t &device, upd7002_eoc_delegate callback) { downcast(device).m_eoc_cb = callback; } + + DECLARE_READ8_MEMBER(eoc_r); + DECLARE_READ8_MEMBER(read); + DECLARE_WRITE8_MEMBER(write); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + +private: + // internal state + + /* Status Register + D0 and D1 define the currently selected input channel + D2 flag output + D3 0 = 8 bit mode 1 = 12 bit mode + D4 2nd MSB of conversion + D5 MSB of conversion + D6 0 = busy, 1 = not busy (~busy) + D7 0 = conversion completed, 1 = conversion not completed (~EOC) + */ + int m_status; + + /* High data byte + This byte contains the 8 most significant bits of the analogue to digital conversion. */ + int m_data1; + + /* Low data byte + In 12 bit mode: Bits 7 to 4 define the four low order bits of the conversion. + In 8 bit mode. All bits 7 to 4 are inaccurate. + Bits 3 to 0 are always set to low. */ + int m_data0; + + + /* temporary store of the next A to D conversion */ + int m_digitalvalue; + + /* this counter is used to check a full end of conversion has been reached + if the uPD7002 is half way through one conversion and a new conversion is requested + the counter at the end of the first conversion will not match and not be processed + only then at the end of the second conversion will the conversion complete function run */ + int m_conversion_counter; + + upd7002_get_analogue_delegate m_get_analogue_cb; + upd7002_eoc_delegate m_eoc_cb; + + enum + { + TIMER_CONVERSION_COMPLETE + }; +}; + +extern const device_type UPD7002; + + +/*************************************************************************** + DEVICE CONFIGURATION MACROS +***************************************************************************/ + +#define MCFG_UPD7002_GET_ANALOGUE_CB(_class, _method) \ + upd7002_device::set_get_analogue_callback(*device, upd7002_get_analogue_delegate(&_class::_method, #_class "::" #_method, downcast<_class *>(owner))); + +#define MCFG_UPD7002_EOC_CB(_class, _method) \ + upd7002_device::set_eoc_callback(*device, upd7002_eoc_delegate(&_class::_method, #_class "::" #_method, downcast<_class *>(owner))); + +#endif /* UPD7002_H_ */ diff --git a/src/devices/machine/upd71071.c b/src/devices/machine/upd71071.c new file mode 100644 index 00000000000..59965256bc5 --- /dev/null +++ b/src/devices/machine/upd71071.c @@ -0,0 +1,517 @@ +// license:BSD-3-Clause +// copyright-holders:Barry Rodewald + +/* + + am9517a.c is a more complete implementation of this, the uPD71071 appears to be a clone of it + + NEC uPD71071 DMA Controller + Used on the Fujitsu FM-Towns + + Register description: + + 0x00: Initialise (Write-only) + - bit 0: Reset + - bit 1: 16-bit data bus + + 0x01: Channel Register + On read: + - bits 0-3: Selected channel + - bit 4: Only base registers may be read or written + On write: + - bits 0-1: Select channel for programming count, address, and mode registers + - bit 2: Only base registers can be read or written to + + 0x02: + 0x03: Count Register (16-bit) + DMA Transfer counter + + 0x04: + 0x05: + 0x06: + 0x07: Address Register (32-bit) + Self-explanatory, I hope. :) + NOTE: Datasheet clearly shows this as 24-bit, with register 7 unused. + But the FM-Towns definitely uses reg 7 as bits 24-31. + The documentation on the V53A manual doesn't show these bits either, maybe it's + an external connection on the FMT? might be worth checking overflow behavior etc. + + 0x08: + 0x09: Device Control register (16-bit) + bit 0: Enable memory-to-memory (MTM) transfers + bit 1: Enable fixed address for channel 0 only (MTM only) + bit 2: Disable DMA operation (stops HLDRQ signal to the CPU) + bit 3: Use compressed timing + bit 4: Rotational Priority + bit 5: Extended Writing + bit 6: DMARQ active level (1=active low) + bit 7: DMAAK active level (1=active high) + bit 8: Bus mode (0=bus release, 1=bus hold) + bit 9: Wait Enable during Verify + + 0x0a: Mode Control register + bit 0: Transfer size (1=16-bit, 0=8-bit, 16-bit data bus size only) + bit 2-3: Transfer direction (ignored for MTM transfers) + 00 = Verify + 01 = I/O to memory + 10 = memory to I/O + 11 = invalid + bit 4: Enable auto-initialise + bit 5: Address direction (0=increment, 1=decrement, affects only current Address reg) + bit 6-7: Transfer mode (ignored for MTM transfers) + 00 = Demand + 01 = Single + 10 = Block + 11 = Cascade + + 0x0b: Status register + bit 0-3: Terminal count (per channel) + bit 4-7: DMA request present (external hardware DMA only) + + 0x0c: + 0x0d: Temporary register (16-bit, read-only) + Stores the last data transferred in an MTM transfer + + 0x0e: Request register + bit 0-3: Software DMA request (1=set) + bit 0 only in MTM transfers + + 0x0f: Mask register + bit 0-3: DMARQ mask + bits 1 and 0 only in MTM transfers + + Note, the uPD71071 compatible mode of the V53 CPU differs from a real uPD71071 in the following ways + + + +*/ + +#include "emu.h" +#include "machine/upd71071.h" + + +const device_type UPD71071 = &device_creator; + +upd71071_device::upd71071_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, UPD71071, "NEC uPD71071", tag, owner, clock, "upd71071", __FILE__), + m_upd_clock(0), + m_out_hreq_cb(*this), + m_out_eop_cb(*this), + m_dma_read_0_cb(*this), + m_dma_read_1_cb(*this), + m_dma_read_2_cb(*this), + m_dma_read_3_cb(*this), + m_dma_write_0_cb(*this), + m_dma_write_1_cb(*this), + m_dma_write_2_cb(*this), + m_dma_write_3_cb(*this), + m_out_dack_0_cb(*this), + m_out_dack_1_cb(*this), + m_out_dack_2_cb(*this), + m_out_dack_3_cb(*this), + m_cpu(*this) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void upd71071_device::device_start() +{ + m_out_hreq_cb.resolve_safe(); + m_out_eop_cb.resolve_safe(); + m_dma_read_0_cb.resolve_safe(0); + m_dma_read_1_cb.resolve_safe(0); + m_dma_read_2_cb.resolve_safe(0); + m_dma_read_3_cb.resolve_safe(0); + m_dma_write_0_cb.resolve_safe(); + m_dma_write_1_cb.resolve_safe(); + m_dma_write_2_cb.resolve_safe(); + m_dma_write_3_cb.resolve_safe(); + m_out_dack_0_cb.resolve_safe(); + m_out_dack_1_cb.resolve_safe(); + m_out_dack_2_cb.resolve_safe(); + m_out_dack_3_cb.resolve_safe(); + for (int x = 0; x < 4; x++) + { + m_timer[x] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(upd71071_device::dma_transfer_timer),this)); + } + m_selected_channel = 0; + + m_reg.device_control = 0; + m_reg.mask = 0x0f; // mask all channels + for (int x = 0; x < 4; x++) + m_reg.mode_control[x] = 0; + + save_item(NAME(m_reg.initialise)); + save_item(NAME(m_reg.channel)); + save_item(NAME(m_reg.count_current)); + save_item(NAME(m_reg.count_base)); + save_item(NAME(m_reg.address_current)); + save_item(NAME(m_reg.address_base)); + save_item(NAME(m_reg.device_control)); + save_item(NAME(m_reg.mode_control)); + save_item(NAME(m_reg.status)); + save_item(NAME(m_reg.temp_l)); + save_item(NAME(m_reg.temp_h)); + save_item(NAME(m_reg.request)); + save_item(NAME(m_reg.mask)); + + save_item(NAME(m_selected_channel)); + save_item(NAME(m_buswidth)); + save_item(NAME(m_dmarq)); + save_item(NAME(m_base)); + save_item(NAME(m_hreq)); + save_item(NAME(m_eop)); +} + + + +TIMER_CALLBACK_MEMBER(upd71071_device::dma_transfer_timer) +{ + // single byte or word transfer + int channel = param; + UINT16 data = 0; // data to transfer + + switch (m_reg.mode_control[channel] & 0x0c) + { + case 0x00: // Verify + break; + case 0x04: // I/O -> memory + switch (channel) + { + case 0: + if (!m_dma_read_0_cb.isnull()) + data = m_dma_read_0_cb(0); + break; + case 1: + if (!m_dma_read_1_cb.isnull()) + data = m_dma_read_1_cb(0); + break; + case 2: + if (!m_dma_read_2_cb.isnull()) + data = m_dma_read_2_cb(0); + break; + case 3: + if (!m_dma_read_3_cb.isnull()) + data = m_dma_read_3_cb(0); + break; + } + + if (m_cpu) + { + address_space& space = m_cpu->space(AS_PROGRAM); + space.write_byte(m_reg.address_current[channel], data & 0xff); + } + else + { + printf("upd71071_device: dma_transfer_timer - write to memory, no dest space %02x\n", data & 0xff); + } + + if (m_reg.mode_control[channel] & 0x20) // Address direction + m_reg.address_current[channel]--; + else + m_reg.address_current[channel]++; + m_reg.count_current[channel]--; + if(m_reg.count_current[channel] == 0xffff) + { + if (m_reg.mode_control[channel] & 0x10) // auto-initialise + { + m_reg.address_current[channel] = m_reg.address_base[channel]; + m_reg.count_current[channel] = m_reg.count_base[channel]; + } + // TODO: send terminal count + set_eop(ASSERT_LINE); + } + break; + case 0x08: // memory -> I/O + if (m_cpu) + { + address_space& space = m_cpu->space(AS_PROGRAM); + data = space.read_byte(m_reg.address_current[channel]); + } + else + { + printf("upd71071_device: dma_transfer_timer - read from memory, no src space\n"); + data = 0x00; + } + + switch (channel) + { + case 0: + if (!m_dma_write_0_cb.isnull()) + m_dma_write_0_cb((offs_t)0, data); + break; + case 1: + if (!m_dma_write_1_cb.isnull()) + m_dma_write_1_cb((offs_t)0, data); + break; + case 2: + if (!m_dma_write_2_cb.isnull()) + m_dma_write_2_cb((offs_t)0, data); + break; + case 3: + if (!m_dma_write_3_cb.isnull()) + m_dma_write_3_cb((offs_t)0, data); + break; + } + if (m_reg.mode_control[channel] & 0x20) // Address direction + m_reg.address_current[channel]--; + else + m_reg.address_current[channel]++; + m_reg.count_current[channel]--; + if(m_reg.count_current[channel] == 0xffff) + { + if (m_reg.mode_control[channel] & 0x10) // auto-initialise + { + m_reg.address_current[channel] = m_reg.address_base[channel]; + m_reg.count_current[channel] = m_reg.count_base[channel]; + } + // TODO: send terminal count + set_eop(ASSERT_LINE); + } + break; + case 0x0c: // Invalid + break; + } +} + +void upd71071_device::soft_reset() +{ + // Does not change base/current address, count, or buswidth + m_selected_channel = 0; + m_base = 0; + for (int x = 0; x < 4; x++) + m_reg.mode_control[x] = 0; + m_reg.device_control = 0; + m_reg.temp_h = 0; + m_reg.temp_l = 0; + m_reg.mask = 0x0f; // mask all channels + m_reg.status &= ~0x0f; // clears bits 0-3 only + m_reg.request = 0; +} + +int upd71071_device::dmarq(int state, int channel) +{ + if (state != 0) + { + if (m_reg.device_control & 0x0004) + return 2; + + if (m_reg.mask & (1 << channel)) // is channel masked? + return 1; + + m_dmarq[channel] = 1; // DMARQ line is set + m_reg.status |= (0x10 << channel); + + // start transfer + switch (m_reg.mode_control[channel] & 0xc0) + { + case 0x00: // Demand + // TODO + set_eop(CLEAR_LINE); + m_timer[channel]->adjust(attotime::from_hz(m_upd_clock), channel); + break; + case 0x40: // Single + m_timer[channel]->adjust(attotime::from_hz(m_upd_clock), channel); + break; + case 0x80: // Block + // TODO + break; + case 0xc0: // Cascade + // TODO + break; + + } + } + else + { + m_dmarq[channel] = 0; // clear DMARQ line + m_reg.status &= ~(0x10 << channel); + m_reg.status |= (0x01 << channel); // END or TC + } + return 0; +} + +READ8_MEMBER(upd71071_device::read) +{ + UINT8 ret = 0; + + logerror("DMA: read from register %02x\n",offset); + switch(offset) + { + case 0x01: // Channel + ret = (1 << m_selected_channel); + if (m_base != 0) + ret |= 0x10; + break; + case 0x02: // Count (low) + if (m_base != 0) + ret = m_reg.count_base[m_selected_channel] & 0xff; + else + ret = m_reg.count_current[m_selected_channel] & 0xff; + break; + case 0x03: // Count (high) + if (m_base != 0) + ret = (m_reg.count_base[m_selected_channel] >> 8) & 0xff; + else + ret = (m_reg.count_current[m_selected_channel] >> 8) & 0xff; + break; + case 0x04: // Address (low) + if (m_base != 0) + ret = m_reg.address_base[m_selected_channel] & 0xff; + else + ret = m_reg.address_current[m_selected_channel] & 0xff; + break; + case 0x05: // Address (mid) + if (m_base != 0) + ret = (m_reg.address_base[m_selected_channel] >> 8) & 0xff; + else + ret = (m_reg.address_current[m_selected_channel] >> 8) & 0xff; + break; + case 0x06: // Address (high) + if (m_base != 0) + ret = (m_reg.address_base[m_selected_channel] >> 16) & 0xff; + else + ret = (m_reg.address_current[m_selected_channel] >> 16) & 0xff; + break; + case 0x07: // Address (highest) + if (m_base != 0) + ret = (m_reg.address_base[m_selected_channel] >> 24) & 0xff; + else + ret = (m_reg.address_current[m_selected_channel] >> 24) & 0xff; + break; + case 0x08: // Device control (low) + ret = m_reg.device_control & 0xff; + break; + case 0x09: // Device control (high) + ret = (m_reg.device_control >> 8) & 0xff; + break; + case 0x0a: // Mode control + ret = m_reg.mode_control[m_selected_channel]; + break; + case 0x0b: // Status + ret = m_reg.status; + m_reg.status &= ~0x0f; // resets END/TC? + break; + case 0x0c: // Temporary (low) + ret = m_reg.temp_h; + break; + case 0x0d: // Temporary (high) + ret = m_reg.temp_l; + break; + case 0x0e: // Request + ret = m_reg.request; + break; + case 0x0f: // Mask + ret = m_reg.mask; + break; + } + return ret; +} + +WRITE8_MEMBER(upd71071_device::write) +{ + switch (offset) + { + case 0x00: // Initialise + // TODO: reset (bit 0) + m_buswidth = data & 0x02; + if (data & 0x01) + soft_reset(); + logerror("DMA: Initialise [%02x]\n",data); + break; + case 0x01: // Channel + m_selected_channel = data & 0x03; + m_base = data & 0x04; + logerror("DMA: Channel selected [%02x]\n",data); + break; + case 0x02: // Count (low) + m_reg.count_base[m_selected_channel] = + (m_reg.count_base[m_selected_channel] & 0xff00) | data; + if (m_base == 0) + m_reg.count_current[m_selected_channel] = + (m_reg.count_current[m_selected_channel] & 0xff00) | data; + logerror("DMA: Channel %i Counter set [%04x]\n",m_selected_channel,m_reg.count_base[m_selected_channel]); + break; + case 0x03: // Count (high) + m_reg.count_base[m_selected_channel] = + (m_reg.count_base[m_selected_channel] & 0x00ff) | (data << 8); + if (m_base == 0) + m_reg.count_current[m_selected_channel] = + (m_reg.count_current[m_selected_channel] & 0x00ff) | (data << 8); + logerror("DMA: Channel %i Counter set [%04x]\n",m_selected_channel,m_reg.count_base[m_selected_channel]); + break; + case 0x04: // Address (low) + m_reg.address_base[m_selected_channel] = + (m_reg.address_base[m_selected_channel] & 0xffffff00) | data; + if (m_base == 0) + m_reg.address_current[m_selected_channel] = + (m_reg.address_current[m_selected_channel] & 0xffffff00) | data; + logerror("DMA: Channel %i Address set [%08x]\n",m_selected_channel,m_reg.address_base[m_selected_channel]); + break; + case 0x05: // Address (mid) + m_reg.address_base[m_selected_channel] = + (m_reg.address_base[m_selected_channel] & 0xffff00ff) | (data << 8); + if (m_base == 0) + m_reg.address_current[m_selected_channel] = + (m_reg.address_current[m_selected_channel] & 0xffff00ff) | (data << 8); + logerror("DMA: Channel %i Address set [%08x]\n",m_selected_channel,m_reg.address_base[m_selected_channel]); + break; + case 0x06: // Address (high) + m_reg.address_base[m_selected_channel] = + (m_reg.address_base[m_selected_channel] & 0xff00ffff) | (data << 16); + if (m_base == 0) + m_reg.address_current[m_selected_channel] = + (m_reg.address_current[m_selected_channel] & 0xff00ffff) | (data << 16); + logerror("DMA: Channel %i Address set [%08x]\n",m_selected_channel,m_reg.address_base[m_selected_channel]); + break; + case 0x07: // Address (highest) + m_reg.address_base[m_selected_channel] = + (m_reg.address_base[m_selected_channel] & 0x00ffffff) | (data << 24); + if (m_base == 0) + m_reg.address_current[m_selected_channel] = + (m_reg.address_current[m_selected_channel] & 0x00ffffff) | (data << 24); + logerror("DMA: Channel %i Address set [%08x]\n",m_selected_channel,m_reg.address_base[m_selected_channel]); + break; + case 0x08: // Device control (low) + m_reg.device_control = (m_reg.device_control & 0xff00) | data; + logerror("DMA: Device control set [%04x]\n",m_reg.device_control); + break; + case 0x09: // Device control (high) + m_reg.device_control = (m_reg.device_control & 0x00ff) | (data << 8); + logerror("DMA: Device control set [%04x]\n",m_reg.device_control); + break; + case 0x0a: // Mode control + m_reg.mode_control[m_selected_channel] = data; + logerror("DMA: Channel %i Mode control set [%02x]\n",m_selected_channel,m_reg.mode_control[m_selected_channel]); + break; + case 0x0e: // Request + m_reg.request = data; + logerror("DMA: Request set [%02x]\n",data); + break; + case 0x0f: // Mask + m_reg.mask = data; + logerror("DMA: Mask set [%02x]\n",data); + break; + } +} + +WRITE_LINE_MEMBER(upd71071_device::set_hreq) +{ + if (m_hreq != state) + { + m_out_hreq_cb(state); + m_hreq = state; + } +} + +WRITE_LINE_MEMBER(upd71071_device::set_eop) +{ + if (m_eop != state) + { + m_out_eop_cb(state); + m_eop = state; + } +} diff --git a/src/devices/machine/upd71071.h b/src/devices/machine/upd71071.h new file mode 100644 index 00000000000..99da46f80d6 --- /dev/null +++ b/src/devices/machine/upd71071.h @@ -0,0 +1,146 @@ +// license:BSD-3-Clause +// copyright-holders:Barry Rodewald +#ifndef __UPD71071_H__ +#define __UPD71071_H__ + +#include "emu.h" + + +struct upd71071_reg +{ + UINT8 initialise; + UINT8 channel; + UINT16 count_current[4]; + UINT16 count_base[4]; + UINT32 address_current[4]; + UINT32 address_base[4]; + UINT16 device_control; + UINT8 mode_control[4]; + UINT8 status; + UINT8 temp_l; + UINT8 temp_h; + UINT8 request; + UINT8 mask; +}; + +class upd71071_device : public device_t +{ +public: + upd71071_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + ~upd71071_device() {} + + static void static_set_cpu_tag(device_t &device, const char *tag) { downcast(device).m_cpu.set_tag(tag); } + static void set_clock(device_t &device, int clock) { downcast(device).m_upd_clock = clock; } + template static devcb_base &set_out_hreq_callback(device_t &device, _Object object) { return downcast(device).m_out_hreq_cb.set_callback(object); } + template static devcb_base &set_out_eop_callback(device_t &device, _Object object) { return downcast(device).m_out_eop_cb.set_callback(object); } + + template static devcb_base &set_dma_read_0_callback(device_t &device, _Object object) { return downcast(device).m_dma_read_0_cb.set_callback(object); } + template static devcb_base &set_dma_read_1_callback(device_t &device, _Object object) { return downcast(device).m_dma_read_1_cb.set_callback(object); } + template static devcb_base &set_dma_read_2_callback(device_t &device, _Object object) { return downcast(device).m_dma_read_2_cb.set_callback(object); } + template static devcb_base &set_dma_read_3_callback(device_t &device, _Object object) { return downcast(device).m_dma_read_3_cb.set_callback(object); } + + template static devcb_base &set_dma_write_0_callback(device_t &device, _Object object) { return downcast(device).m_dma_write_0_cb.set_callback(object); } + template static devcb_base &set_dma_write_1_callback(device_t &device, _Object object) { return downcast(device).m_dma_write_1_cb.set_callback(object); } + template static devcb_base &set_dma_write_2_callback(device_t &device, _Object object) { return downcast(device).m_dma_write_2_cb.set_callback(object); } + template static devcb_base &set_dma_write_3_callback(device_t &device, _Object object) { return downcast(device).m_dma_write_3_cb.set_callback(object); } + + template static devcb_base &set_out_dack_0_callback(device_t &device, _Object object) { return downcast(device).m_out_dack_0_cb.set_callback(object); } + template static devcb_base &set_out_dack_1_callback(device_t &device, _Object object) { return downcast(device).m_out_dack_1_cb.set_callback(object); } + template static devcb_base &set_out_dack_2_callback(device_t &device, _Object object) { return downcast(device).m_out_dack_2_cb.set_callback(object); } + template static devcb_base &set_out_dack_3_callback(device_t &device, _Object object) { return downcast(device).m_out_dack_3_cb.set_callback(object); } + + DECLARE_READ8_MEMBER(read); + DECLARE_WRITE8_MEMBER(write); + DECLARE_WRITE_LINE_MEMBER(set_hreq); + DECLARE_WRITE_LINE_MEMBER(set_eop); + + int dmarq(int state, int channel); + +protected: + // device-level overrides + virtual void device_start(); + +private: + // internal state + void soft_reset(); + TIMER_CALLBACK_MEMBER(dma_transfer_timer); + + struct upd71071_reg m_reg; + int m_selected_channel; + int m_buswidth; + int m_dmarq[4]; + emu_timer* m_timer[4]; + //int m_in_progress[4]; + //int m_transfer_size[4]; + int m_base; + int m_upd_clock; + devcb_write_line m_out_hreq_cb; + devcb_write_line m_out_eop_cb; + devcb_read16 m_dma_read_0_cb; + devcb_read16 m_dma_read_1_cb; + devcb_read16 m_dma_read_2_cb; + devcb_read16 m_dma_read_3_cb; + devcb_write16 m_dma_write_0_cb; + devcb_write16 m_dma_write_1_cb; + devcb_write16 m_dma_write_2_cb; + devcb_write16 m_dma_write_3_cb; + devcb_write_line m_out_dack_0_cb; + devcb_write_line m_out_dack_1_cb; + devcb_write_line m_out_dack_2_cb; + devcb_write_line m_out_dack_3_cb; + int m_hreq; + int m_eop; + optional_device m_cpu; +}; + +extern const device_type UPD71071; + +#define MCFG_UPD71071_CPU(_tag) \ + upd71071_device::static_set_cpu_tag(*device, "^" _tag); + +#define MCFG_UPD71071_CLOCK(_clk) \ + upd71071_device::set_clock(*device, _clk); + +#define MCFG_UPD71071_OUT_HREQ_CB(_devcb) \ + devcb = &upd71071_device::set_out_hreq_callback(*device, DEVCB_##_devcb); + +#define MCFG_UPD71071_OUT_EOP_CB(_devcb) \ + devcb = &upd71071_device::set_out_eop_callback(*device, DEVCB_##_devcb); + +#define MCFG_UPD71071_DMA_READ_0_CB(_devcb) \ + devcb = &upd71071_device::set_dma_read_0_callback(*device, DEVCB_##_devcb); + +#define MCFG_UPD71071_DMA_READ_1_CB(_devcb) \ + devcb = &upd71071_device::set_dma_read_1_callback(*device, DEVCB_##_devcb); + +#define MCFG_UPD71071_DMA_READ_2_CB(_devcb) \ + devcb = &upd71071_device::set_dma_read_2_callback(*device, DEVCB_##_devcb); + +#define MCFG_UPD71071_DMA_READ_3_CB(_devcb) \ + devcb = &upd71071_device::set_dma_read_3_callback(*device, DEVCB_##_devcb); + +#define MCFG_UPD71071_DMA_WRITE_0_CB(_devcb) \ + devcb = &upd71071_device::set_dma_write_0_callback(*device, DEVCB_##_devcb); + +#define MCFG_UPD71071_DMA_WRITE_1_CB(_devcb) \ + devcb = &upd71071_device::set_dma_write_1_callback(*device, DEVCB_##_devcb); + +#define MCFG_UPD71071_DMA_WRITE_2_CB(_devcb) \ + devcb = &upd71071_device::set_dma_write_2_callback(*device, DEVCB_##_devcb); + +#define MCFG_UPD71071_DMA_WRITE_3_CB(_devcb) \ + devcb = &upd71071_device::set_dma_write_3_callback(*device, DEVCB_##_devcb); + +#define MCFG_UPD71071_OUT_DACK_0_CB(_devcb) \ + devcb = &upd71071_device::set_out_dack_0_callback(*device, DEVCB_##_devcb); + +#define MCFG_UPD71071_OUT_DACK_1_CB(_devcb) \ + devcb = &upd71071_device::set_out_dack_1_callback(*device, DEVCB_##_devcb); + +#define MCFG_UPD71071_OUT_DACK_2_CB(_devcb) \ + devcb = &upd71071_device::set_out_dack_2_callback(*device, DEVCB_##_devcb); + +#define MCFG_UPD71071_OUT_DACK_3_CB(_devcb) \ + devcb = &upd71071_device::set_out_dack_3_callback(*device, DEVCB_##_devcb); + +#endif /*UPD71071_H_*/ diff --git a/src/devices/machine/upd765.c b/src/devices/machine/upd765.c new file mode 100644 index 00000000000..e1ce769880e --- /dev/null +++ b/src/devices/machine/upd765.c @@ -0,0 +1,2534 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +#include "debugger.h" + +#include "upd765.h" + +const device_type UPD765A = &device_creator; +const device_type UPD765B = &device_creator; +const device_type I8272A = &device_creator; +const device_type UPD72065 = &device_creator; +const device_type SMC37C78 = &device_creator; +const device_type N82077AA = &device_creator; +const device_type PC_FDC_SUPERIO = &device_creator; +const device_type DP8473 = &device_creator; +const device_type PC8477A = &device_creator; +const device_type WD37C65C = &device_creator; +const device_type MCS3201 = &device_creator; +const device_type TC8566AF = &device_creator; + +DEVICE_ADDRESS_MAP_START(map, 8, upd765a_device) + AM_RANGE(0x0, 0x0) AM_READ(msr_r) + AM_RANGE(0x1, 0x1) AM_READWRITE(fifo_r, fifo_w) +ADDRESS_MAP_END + +DEVICE_ADDRESS_MAP_START(map, 8, upd765b_device) + AM_RANGE(0x0, 0x0) AM_READ(msr_r) + AM_RANGE(0x1, 0x1) AM_READWRITE(fifo_r, fifo_w) +ADDRESS_MAP_END + +DEVICE_ADDRESS_MAP_START(map, 8, i8272a_device) + AM_RANGE(0x0, 0x0) AM_READ(msr_r) + AM_RANGE(0x1, 0x1) AM_READWRITE(fifo_r, fifo_w) +ADDRESS_MAP_END + +DEVICE_ADDRESS_MAP_START(map, 8, upd72065_device) + AM_RANGE(0x0, 0x0) AM_READ(msr_r) + AM_RANGE(0x1, 0x1) AM_READWRITE(fifo_r, fifo_w) +ADDRESS_MAP_END + +DEVICE_ADDRESS_MAP_START(map, 8, smc37c78_device) + AM_RANGE(0x2, 0x2) AM_READWRITE(dor_r, dor_w) + AM_RANGE(0x3, 0x3) AM_READWRITE(tdr_r, tdr_w) + AM_RANGE(0x4, 0x4) AM_READWRITE(msr_r, dsr_w) + AM_RANGE(0x5, 0x5) AM_READWRITE(fifo_r, fifo_w) + AM_RANGE(0x7, 0x7) AM_READWRITE(dir_r, ccr_w) +ADDRESS_MAP_END + +DEVICE_ADDRESS_MAP_START(map, 8, n82077aa_device) + AM_RANGE(0x0, 0x0) AM_READ(sra_r) + AM_RANGE(0x1, 0x1) AM_READ(srb_r) + AM_RANGE(0x2, 0x2) AM_READWRITE(dor_r, dor_w) + AM_RANGE(0x3, 0x3) AM_READWRITE(tdr_r, tdr_w) + AM_RANGE(0x4, 0x4) AM_READWRITE(msr_r, dsr_w) + AM_RANGE(0x5, 0x5) AM_READWRITE(fifo_r, fifo_w) + AM_RANGE(0x7, 0x7) AM_READWRITE(dir_r, ccr_w) +ADDRESS_MAP_END + +DEVICE_ADDRESS_MAP_START(map, 8, pc_fdc_superio_device) + AM_RANGE(0x0, 0x0) AM_READ(sra_r) + AM_RANGE(0x1, 0x1) AM_READ(srb_r) + AM_RANGE(0x2, 0x2) AM_READWRITE(dor_r, dor_w) + AM_RANGE(0x3, 0x3) AM_READWRITE(tdr_r, tdr_w) + AM_RANGE(0x4, 0x4) AM_READWRITE(msr_r, dsr_w) + AM_RANGE(0x5, 0x5) AM_READWRITE(fifo_r, fifo_w) + AM_RANGE(0x7, 0x7) AM_READWRITE(dir_r, ccr_w) +ADDRESS_MAP_END + +DEVICE_ADDRESS_MAP_START(map, 8, dp8473_device) + AM_RANGE(0x0, 0x0) AM_READ(sra_r) + AM_RANGE(0x1, 0x1) AM_READ(srb_r) + AM_RANGE(0x2, 0x2) AM_READWRITE(dor_r, dor_w) + AM_RANGE(0x3, 0x3) AM_READWRITE(tdr_r, tdr_w) + AM_RANGE(0x4, 0x4) AM_READWRITE(msr_r, dsr_w) + AM_RANGE(0x5, 0x5) AM_READWRITE(fifo_r, fifo_w) + AM_RANGE(0x7, 0x7) AM_READWRITE(dir_r, ccr_w) +ADDRESS_MAP_END + +DEVICE_ADDRESS_MAP_START(map, 8, pc8477a_device) + AM_RANGE(0x0, 0x0) AM_READ(sra_r) + AM_RANGE(0x1, 0x1) AM_READ(srb_r) + AM_RANGE(0x2, 0x2) AM_READWRITE(dor_r, dor_w) + AM_RANGE(0x3, 0x3) AM_READWRITE(tdr_r, tdr_w) + AM_RANGE(0x4, 0x4) AM_READWRITE(msr_r, dsr_w) + AM_RANGE(0x5, 0x5) AM_READWRITE(fifo_r, fifo_w) + AM_RANGE(0x7, 0x7) AM_READWRITE(dir_r, ccr_w) +ADDRESS_MAP_END + +DEVICE_ADDRESS_MAP_START(map, 8, wd37c65c_device) + AM_RANGE(0x0, 0x0) AM_READ(msr_r) + AM_RANGE(0x1, 0x1) AM_READWRITE(fifo_r, fifo_w) +ADDRESS_MAP_END + +DEVICE_ADDRESS_MAP_START( map, 8, mcs3201_device ) + AM_RANGE(0x0, 0x0) AM_READ(input_r) + AM_RANGE(0x2, 0x2) AM_WRITE(dor_w) + AM_RANGE(0x4, 0x4) AM_READ(msr_r) + AM_RANGE(0x5, 0x5) AM_READWRITE(fifo_r, fifo_w) + AM_RANGE(0x7, 0x7) AM_READWRITE(dir_r, ccr_w) +ADDRESS_MAP_END + +DEVICE_ADDRESS_MAP_START( map, 8, tc8566af_device ) + AM_RANGE(0x2, 0x2) AM_WRITE(dor_w) + AM_RANGE(0x3, 0x3) AM_WRITE(cr1_w) + AM_RANGE(0x4, 0x4) AM_READ(msr_r) + AM_RANGE(0x5, 0x5) AM_READWRITE(fifo_r, fifo_w) +ADDRESS_MAP_END + + +int upd765_family_device::rates[4] = { 500000, 300000, 250000, 1000000 }; + +upd765_family_device::upd765_family_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + pc_fdc_interface(mconfig, type, name, tag, owner, clock, shortname, source), + intrq_cb(*this), + drq_cb(*this), + hdl_cb(*this) +{ + ready_polled = true; + ready_connected = true; + select_connected = true; + external_ready = false; + dor_reset = 0x00; + mode = MODE_AT; +} + +void upd765_family_device::set_ready_line_connected(bool _ready) +{ + ready_connected = _ready; +} + +void upd765_family_device::set_select_lines_connected(bool _select) +{ + select_connected = _select; +} + +void upd765_family_device::set_mode(int _mode) +{ + mode = _mode; +} + +void upd765_family_device::device_start() +{ + intrq_cb.resolve_safe(); + drq_cb.resolve_safe(); + hdl_cb.resolve_safe(); + + for(int i=0; i != 4; i++) { + char name[2]; + flopi[i].tm = timer_alloc(i); + flopi[i].id = i; + if(select_connected) { + name[0] = '0'+i; + name[1] = 0; + floppy_connector *con = subdevice(name); + if(con) { + flopi[i].dev = con->get_device(); + if (flopi[i].dev != NULL) + flopi[i].dev->setup_index_pulse_cb(floppy_image_device::index_pulse_cb(FUNC(upd765_family_device::index_callback), this)); + } else + flopi[i].dev = NULL; + } else + flopi[i].dev = NULL; + + flopi[i].main_state = IDLE; + flopi[i].sub_state = IDLE; + flopi[i].dir = 0; + flopi[i].counter = 0; + flopi[i].pcn = 0; + flopi[i].st0 = 0; + flopi[i].st0_filled = false; + flopi[i].live = false; + flopi[i].index = false; + flopi[i].ready = false; + } + cur_rate = 250000; + tc = false; + + // reset at upper levels may cause a write to tc ending up with + // live_sync, which will crash if the live structure isn't + // initialized enough + + cur_live.tm = attotime::never; + cur_live.state = IDLE; + cur_live.next_state = -1; + cur_live.fi = NULL; + + if(ready_polled) { + poll_timer = timer_alloc(TIMER_DRIVE_READY_POLLING); + poll_timer->adjust(attotime::from_usec(100), 0, attotime::from_usec(1024)); + } else + poll_timer = NULL; + + cur_irq = false; + locked = false; +} + +void upd765_family_device::device_reset() +{ + dor = dor_reset; + locked = false; + soft_reset(); +} + +void upd765_family_device::soft_reset() +{ + main_phase = PHASE_CMD; + for(int i=0; i<4; i++) { + flopi[i].main_state = IDLE; + flopi[i].sub_state = IDLE; + flopi[i].live = false; + flopi[i].ready = !ready_polled; + flopi[i].st0 = i; + flopi[i].st0_filled = false; + } + data_irq = false; + other_irq = false; + internal_drq = false; + fifo_pos = 0; + command_pos = 0; + result_pos = 0; + if(!locked) + fifocfg = FIF_DIS; + cur_live.fi = 0; + drq = false; + cur_live.tm = attotime::never; + cur_live.state = IDLE; + cur_live.next_state = -1; + cur_live.fi = NULL; + tc_done = false; + st1 = st2 = st3 = 0x00; + + check_irq(); + if(ready_polled) + poll_timer->adjust(attotime::from_usec(100), 0, attotime::from_usec(1024)); +} + +void upd765_family_device::tc_w(bool _tc) +{ + logerror("%s: tc=%d\n", tag(), _tc); + if(tc != _tc && _tc) { + live_sync(); + tc_done = true; + tc = _tc; + if(cur_live.fi) + general_continue(*cur_live.fi); + } else + tc = _tc; +} + +void upd765_family_device::ready_w(bool _ready) +{ + external_ready = _ready; +} + +bool upd765_family_device::get_ready(int fid) +{ + if(ready_connected) + return flopi[fid].dev ? !flopi[fid].dev->ready_r() : false; + return !external_ready; +} + +void upd765_family_device::set_floppy(floppy_image_device *flop) +{ + for(int fid=0; fid<4; fid++) { + if(flopi[fid].dev) + flopi[fid].dev->setup_index_pulse_cb(floppy_image_device::index_pulse_cb()); + flopi[fid].dev = flop; + } + if(flop) + flop->setup_index_pulse_cb(floppy_image_device::index_pulse_cb(FUNC(upd765_family_device::index_callback), this)); +} + +READ8_MEMBER(upd765_family_device::sra_r) +{ + UINT8 sra = 0; + int fid = dor & 3; + floppy_info &fi = flopi[fid]; + if(fi.dir) + sra |= 0x01; + if(fi.index) + sra |= 0x04; + if(cur_rate >= 500000) + sra |= 0x08; + if(fi.dev && fi.dev->trk00_r()) + sra |= 0x10; + if(fi.main_state == SEEK_WAIT_STEP_SIGNAL_TIME) + sra |= 0x20; + sra |= 0x40; + if(cur_irq) + sra |= 0x80; + if(mode == MODE_M30) + sra ^= 0x1f; + return sra; +} + +READ8_MEMBER(upd765_family_device::srb_r) +{ + return 0; +} + +READ8_MEMBER(upd765_family_device::dor_r) +{ + return dor; +} + +WRITE8_MEMBER(upd765_family_device::dor_w) +{ + logerror("%s: dor = %02x\n", tag(), data); + UINT8 diff = dor ^ data; + dor = data; + if(diff & 4) + soft_reset(); + + for(int i=0; i<4; i++) { + floppy_info &fi = flopi[i]; + if(fi.dev) + fi.dev->mon_w(!(dor & (0x10 << i))); + } + check_irq(); +} + +READ8_MEMBER(upd765_family_device::tdr_r) +{ + return 0; +} + +WRITE8_MEMBER(upd765_family_device::tdr_w) +{ +} + +READ8_MEMBER(upd765_family_device::msr_r) +{ + UINT32 msr = 0; + switch(main_phase) { + case PHASE_CMD: + msr |= MSR_RQM; + if(command_pos) + msr |= MSR_CB; + break; + case PHASE_EXEC: + msr |= MSR_CB; + if(spec & SPEC_ND) + msr |= MSR_EXM; + if(internal_drq) { + msr |= MSR_RQM; + if(!fifo_write) + msr |= MSR_DIO; + } + break; + + case PHASE_RESULT: + msr |= MSR_RQM|MSR_DIO|MSR_CB; + break; + } + for(int i=0; i<4; i++) + if(flopi[i].main_state == RECALIBRATE || flopi[i].main_state == SEEK) { + msr |= 1<dskchg_r() ? 0x00 : 0x80; + return 0x00; +} + +READ8_MEMBER(upd765_family_device::dir_r) +{ + return do_dir_r(); +} + +WRITE8_MEMBER(upd765_family_device::ccr_w) +{ + dsr = (dsr & 0xfc) | (data & 3); + cur_rate = rates[data & 3]; +} + +void upd765_family_device::set_drq(bool state) +{ + if(state != drq) { + drq = state; + drq_cb(drq); + } +} + +bool upd765_family_device::get_drq() const +{ + return drq; +} + +void upd765_family_device::enable_transfer() +{ + if(spec & SPEC_ND) { + // PIO + if(!internal_drq) { + internal_drq = true; + check_irq(); + } + + } else { + // DMA + if(!drq) + set_drq(true); + } +} + +void upd765_family_device::disable_transfer() +{ + if(spec & SPEC_ND) { + internal_drq = false; + check_irq(); + } else + set_drq(false); +} + +void upd765_family_device::fifo_push(UINT8 data, bool internal) +{ + if(fifo_pos == 16) { + if(internal) { + if(!(st1 & ST1_OR)) + logerror("%s: Fifo overrun\n", tag()); + st1 |= ST1_OR; + } + return; + } + fifo[fifo_pos++] = data; + fifo_expected--; + + int thr = (fifocfg & FIF_THR)+1; + if(!fifo_write && (!fifo_expected || fifo_pos >= thr || (fifocfg & FIF_DIS))) + enable_transfer(); + if(fifo_write && (fifo_pos == 16 || !fifo_expected)) + disable_transfer(); +} + + +UINT8 upd765_family_device::fifo_pop(bool internal) +{ + if(!fifo_pos) { + if(internal) { + if(!(st1 & ST1_OR)) + logerror("%s: Fifo underrun\n", tag()); + st1 |= ST1_OR; + } + return 0; + } + UINT8 r = fifo[0]; + fifo_pos--; + memmove(fifo, fifo+1, fifo_pos); + if(!fifo_write && !fifo_pos) + disable_transfer(); + int thr = fifocfg & 15; + if(fifo_write && fifo_expected && (fifo_pos <= thr || (fifocfg & 0x20))) + enable_transfer(); + return r; +} + +void upd765_family_device::fifo_expect(int size, bool write) +{ + fifo_expected = size; + fifo_write = write; + if(fifo_write) + enable_transfer(); +} + +READ8_MEMBER(upd765_family_device::mdma_r) +{ + return dma_r(); +} + +WRITE8_MEMBER(upd765_family_device::mdma_w) +{ + dma_w(data); +} + +UINT8 upd765_family_device::dma_r() +{ + return fifo_pop(false); +} + +void upd765_family_device::dma_w(UINT8 data) +{ + fifo_push(data, false); +} + +void upd765_family_device::live_start(floppy_info &fi, int state) +{ + cur_live.tm = machine().time(); + cur_live.state = state; + cur_live.next_state = -1; + cur_live.fi = &fi; + cur_live.shift_reg = 0; + cur_live.crc = 0xffff; + cur_live.bit_counter = 0; + cur_live.data_separator_phase = false; + cur_live.data_reg = 0; + cur_live.previous_type = live_info::PT_NONE; + cur_live.data_bit_context = false; + cur_live.byte_counter = 0; + cur_live.pll.reset(cur_live.tm); + cur_live.pll.set_clock(attotime::from_hz(mfm ? 2*cur_rate : cur_rate)); + checkpoint_live = cur_live; + fi.live = true; + + live_run(); +} + +void upd765_family_device::checkpoint() +{ + if(cur_live.fi) + cur_live.pll.commit(cur_live.fi->dev, cur_live.tm); + checkpoint_live = cur_live; +} + +void upd765_family_device::rollback() +{ + cur_live = checkpoint_live; +} + +void upd765_family_device::live_delay(int state) +{ + cur_live.next_state = state; + if(cur_live.tm != machine().time()) + cur_live.fi->tm->adjust(cur_live.tm - machine().time()); + else + live_sync(); +} + +void upd765_family_device::live_sync() +{ + if(!cur_live.tm.is_never()) { + if(cur_live.tm > machine().time()) { + rollback(); + live_run(machine().time()); + cur_live.pll.commit(cur_live.fi->dev, cur_live.tm); + } else { + cur_live.pll.commit(cur_live.fi->dev, cur_live.tm); + if(cur_live.next_state != -1) { + cur_live.state = cur_live.next_state; + cur_live.next_state = -1; + } + if(cur_live.state == IDLE) { + cur_live.pll.stop_writing(cur_live.fi->dev, cur_live.tm); + cur_live.tm = attotime::never; + cur_live.fi->live = false; + cur_live.fi = 0; + } + } + cur_live.next_state = -1; + checkpoint(); + } +} + +void upd765_family_device::live_abort() +{ + if(!cur_live.tm.is_never() && cur_live.tm > machine().time()) { + rollback(); + live_run(machine().time()); + } + + if(cur_live.fi) { + cur_live.pll.stop_writing(cur_live.fi->dev, cur_live.tm); + cur_live.fi->live = false; + cur_live.fi = 0; + } + + cur_live.tm = attotime::never; + cur_live.state = IDLE; + cur_live.next_state = -1; +} + +void upd765_family_device::live_run(attotime limit) +{ + if(cur_live.state == IDLE || cur_live.next_state != -1) + return; + + if(limit == attotime::never) { + if(cur_live.fi->dev) + limit = cur_live.fi->dev->time_next_index(); + if(limit == attotime::never) { + // Happens when there's no disk or if the fdc is not + // connected to a drive, hence no index pulse. Force a + // sync from time to time in that case, so that the main + // cpu timeout isn't too painful. Avoids looping into + // infinity looking for data too. + + limit = machine().time() + attotime::from_msec(1); + cur_live.fi->tm->adjust(attotime::from_msec(1)); + } + } + + for(;;) { + switch(cur_live.state) { + case SEARCH_ADDRESS_MARK_HEADER: + if(read_one_bit(limit)) + return; +#if 0 + fprintf(stderr, "%s: shift = %04x data=%02x c=%d\n", tts(cur_live.tm).c_str(), cur_live.shift_reg, + (cur_live.shift_reg & 0x4000 ? 0x80 : 0x00) | + (cur_live.shift_reg & 0x1000 ? 0x40 : 0x00) | + (cur_live.shift_reg & 0x0400 ? 0x20 : 0x00) | + (cur_live.shift_reg & 0x0100 ? 0x10 : 0x00) | + (cur_live.shift_reg & 0x0040 ? 0x08 : 0x00) | + (cur_live.shift_reg & 0x0010 ? 0x04 : 0x00) | + (cur_live.shift_reg & 0x0004 ? 0x02 : 0x00) | + (cur_live.shift_reg & 0x0001 ? 0x01 : 0x00), + cur_live.bit_counter); +#endif + + if(mfm && cur_live.shift_reg == 0x4489) { + cur_live.crc = 0x443b; + cur_live.data_separator_phase = false; + cur_live.bit_counter = 0; + cur_live.state = READ_HEADER_BLOCK_HEADER; + } + + if(!mfm && cur_live.shift_reg == 0xf57e) { + cur_live.crc = 0xef21; + cur_live.data_separator_phase = false; + cur_live.bit_counter = 0; + cur_live.state = READ_ID_BLOCK; + } + break; + + case READ_HEADER_BLOCK_HEADER: { + if(read_one_bit(limit)) + return; +#if 0 + fprintf(stderr, "%s: shift = %04x data=%02x counter=%d\n", tts(cur_live.tm).c_str(), cur_live.shift_reg, + (cur_live.shift_reg & 0x4000 ? 0x80 : 0x00) | + (cur_live.shift_reg & 0x1000 ? 0x40 : 0x00) | + (cur_live.shift_reg & 0x0400 ? 0x20 : 0x00) | + (cur_live.shift_reg & 0x0100 ? 0x10 : 0x00) | + (cur_live.shift_reg & 0x0040 ? 0x08 : 0x00) | + (cur_live.shift_reg & 0x0010 ? 0x04 : 0x00) | + (cur_live.shift_reg & 0x0004 ? 0x02 : 0x00) | + (cur_live.shift_reg & 0x0001 ? 0x01 : 0x00), + cur_live.bit_counter); +#endif + if(cur_live.bit_counter & 15) + break; + + int slot = cur_live.bit_counter >> 4; + + if(slot < 3) { + if(cur_live.shift_reg != 0x4489) + cur_live.state = SEARCH_ADDRESS_MARK_HEADER; + break; + } + if(cur_live.data_reg != 0xfe) { + cur_live.state = SEARCH_ADDRESS_MARK_HEADER; + break; + } + + cur_live.bit_counter = 0; + cur_live.state = READ_ID_BLOCK; + + break; + } + + case READ_ID_BLOCK: { + if(read_one_bit(limit)) + return; + if(cur_live.bit_counter & 15) + break; + int slot = (cur_live.bit_counter >> 4)-1; + + if(0) + fprintf(stderr, "%s: slot=%d data=%02x crc=%04x\n", tts(cur_live.tm).c_str(), slot, cur_live.data_reg, cur_live.crc); + cur_live.idbuf[slot] = cur_live.data_reg; + if(slot == 5) { + live_delay(IDLE); + return; + } + break; + } + + case SEARCH_ADDRESS_MARK_DATA: + if(read_one_bit(limit)) + return; +#if 0 + fprintf(stderr, "%s: shift = %04x data=%02x c=%d.%x\n", tts(cur_live.tm).c_str(), cur_live.shift_reg, + (cur_live.shift_reg & 0x4000 ? 0x80 : 0x00) | + (cur_live.shift_reg & 0x1000 ? 0x40 : 0x00) | + (cur_live.shift_reg & 0x0400 ? 0x20 : 0x00) | + (cur_live.shift_reg & 0x0100 ? 0x10 : 0x00) | + (cur_live.shift_reg & 0x0040 ? 0x08 : 0x00) | + (cur_live.shift_reg & 0x0010 ? 0x04 : 0x00) | + (cur_live.shift_reg & 0x0004 ? 0x02 : 0x00) | + (cur_live.shift_reg & 0x0001 ? 0x01 : 0x00), + cur_live.bit_counter >> 4, cur_live.bit_counter & 15); +#endif + + if(mfm) { + // Large tolerance due to perpendicular recording at extended density + if(cur_live.bit_counter > 62*16) { + live_delay(SEARCH_ADDRESS_MARK_DATA_FAILED); + return; + } + + if(cur_live.bit_counter >= 28*16 && cur_live.shift_reg == 0x4489) { + cur_live.crc = 0x443b; + cur_live.data_separator_phase = false; + cur_live.bit_counter = 0; + cur_live.state = READ_DATA_BLOCK_HEADER; + } + + } else { + if(cur_live.bit_counter > 23*16) { + live_delay(SEARCH_ADDRESS_MARK_DATA_FAILED); + return; + } + + if(cur_live.bit_counter >= 11*16 && (cur_live.shift_reg == 0xf56a || cur_live.shift_reg == 0xf56f)) { + cur_live.crc = cur_live.shift_reg == 0xf56a ? 0x8fe7 : 0xbf84; + cur_live.data_separator_phase = false; + cur_live.bit_counter = 0; + cur_live.state = READ_SECTOR_DATA; + } + } + + break; + + case READ_DATA_BLOCK_HEADER: { + if(read_one_bit(limit)) + return; +#if 0 + fprintf(stderr, "%s: shift = %04x data=%02x counter=%d\n", tts(cur_live.tm).c_str(), cur_live.shift_reg, + (cur_live.shift_reg & 0x4000 ? 0x80 : 0x00) | + (cur_live.shift_reg & 0x1000 ? 0x40 : 0x00) | + (cur_live.shift_reg & 0x0400 ? 0x20 : 0x00) | + (cur_live.shift_reg & 0x0100 ? 0x10 : 0x00) | + (cur_live.shift_reg & 0x0040 ? 0x08 : 0x00) | + (cur_live.shift_reg & 0x0010 ? 0x04 : 0x00) | + (cur_live.shift_reg & 0x0004 ? 0x02 : 0x00) | + (cur_live.shift_reg & 0x0001 ? 0x01 : 0x00), + cur_live.bit_counter); +#endif + if(cur_live.bit_counter & 15) + break; + + int slot = cur_live.bit_counter >> 4; + + if(slot < 3) { + if(cur_live.shift_reg != 0x4489) { + live_delay(SEARCH_ADDRESS_MARK_DATA_FAILED); + return; + } + break; + } + if(cur_live.data_reg != 0xfb && cur_live.data_reg != 0xf8) { + live_delay(SEARCH_ADDRESS_MARK_DATA_FAILED); + return; + } + + cur_live.bit_counter = 0; + cur_live.state = READ_SECTOR_DATA; + break; + } + + case SEARCH_ADDRESS_MARK_DATA_FAILED: + st1 |= ST1_MA; + st2 |= ST2_MD; + cur_live.state = IDLE; + return; + + case READ_SECTOR_DATA: { + if(read_one_bit(limit)) + return; + if(cur_live.bit_counter & 15) + break; + int slot = (cur_live.bit_counter >> 4)-1; + if(slot < sector_size) { + // Sector data + if(cur_live.fi->main_state == SCAN_DATA) + live_delay(SCAN_SECTOR_DATA_BYTE); + else + live_delay(READ_SECTOR_DATA_BYTE); + return; + + } else if(slot < sector_size+2) { + // CRC + if(slot == sector_size+1) { + live_delay(IDLE); + return; + } + } + break; + } + + case READ_SECTOR_DATA_BYTE: + if(!tc_done) + fifo_push(cur_live.data_reg, true); + cur_live.state = READ_SECTOR_DATA; + checkpoint(); + break; + + case SCAN_SECTOR_DATA_BYTE: + if(!scan_done) // TODO: handle stp, x68000 sets it to 0xff (as it would dtl)? + { + int slot = (cur_live.bit_counter >> 4)-1; + UINT8 data = fifo_pop(true); + if(!slot) + st2 = (st2 & ~(ST2_SN)) | ST2_SH; + + if(data != cur_live.data_reg) + { + st2 = (st2 & ~(ST2_SH)) | ST2_SN; + if((data < cur_live.data_reg) && ((command[0] & 0x1f) == 0x19)) // low + st2 &= ~ST2_SN; + + if((data > cur_live.data_reg) && ((command[0] & 0x1f) == 0x1d)) // high + st2 &= ~ST2_SN; + } + if((slot == sector_size) && !(st2 & ST2_SN)) + { + scan_done = true; + tc_done = true; + } + } + else + { + if(fifo_pos) + fifo_pop(true); + } + cur_live.state = READ_SECTOR_DATA; + checkpoint(); + break; + + case WRITE_SECTOR_SKIP_GAP2: + cur_live.bit_counter = 0; + cur_live.byte_counter = 0; + cur_live.state = WRITE_SECTOR_SKIP_GAP2_BYTE; + checkpoint(); + break; + + case WRITE_SECTOR_SKIP_GAP2_BYTE: + if(read_one_bit(limit)) + return; + if(mfm && cur_live.bit_counter != 22*16) + break; + if(!mfm && cur_live.bit_counter != 11*16) + break; + cur_live.bit_counter = 0; + cur_live.byte_counter = 0; + live_delay(WRITE_SECTOR_DATA); + return; + + case WRITE_SECTOR_DATA: + if(mfm) { + if(cur_live.byte_counter < 12) + live_write_mfm(0x00); + else if(cur_live.byte_counter < 15) + live_write_raw(0x4489); + else if(cur_live.byte_counter < 16) { + cur_live.crc = 0xcdb4; + live_write_mfm(command[0] & 0x08 ? 0xf8 : 0xfb); + } else if(cur_live.byte_counter < 16+sector_size) + live_write_mfm(tc_done && !fifo_pos? 0x00 : fifo_pop(true)); + else if(cur_live.byte_counter < 16+sector_size+2) + live_write_mfm(cur_live.crc >> 8); + else if(cur_live.byte_counter < 16+sector_size+2+command[7]) + live_write_mfm(0x4e); + else { + cur_live.pll.stop_writing(cur_live.fi->dev, cur_live.tm); + cur_live.state = IDLE; + return; + } + + } else { + if(cur_live.byte_counter < 6) + live_write_fm(0x00); + else if(cur_live.byte_counter < 7) { + cur_live.crc = 0xffff; + live_write_raw(command[0] & 0x08 ? 0xf56a : 0xf56f); + } else if(cur_live.byte_counter < 7+sector_size) + live_write_fm(tc_done && !fifo_pos? 0x00 : fifo_pop(true)); + else if(cur_live.byte_counter < 7+sector_size+2) + live_write_fm(cur_live.crc >> 8); + else if(cur_live.byte_counter < 7+sector_size+2+command[7]) + live_write_fm(0xff); + else { + cur_live.pll.stop_writing(cur_live.fi->dev, cur_live.tm); + cur_live.state = IDLE; + return; + } + } + cur_live.state = WRITE_SECTOR_DATA_BYTE; + cur_live.bit_counter = 16; + checkpoint(); + break; + + case WRITE_TRACK_PRE_SECTORS: + if(!cur_live.byte_counter && command[3]) + fifo_expect(4, true); + if(mfm) { + if(cur_live.byte_counter < 80) + live_write_mfm(0x4e); + else if(cur_live.byte_counter < 92) + live_write_mfm(0x00); + else if(cur_live.byte_counter < 95) + live_write_raw(0x5224); + else if(cur_live.byte_counter < 96) + live_write_mfm(0xfc); + else if(cur_live.byte_counter < 146) + live_write_mfm(0x4e); + else { + cur_live.state = WRITE_TRACK_SECTOR; + cur_live.byte_counter = 0; + break; + } + } else { + if(cur_live.byte_counter < 40) + live_write_fm(0xff); + else if(cur_live.byte_counter < 46) + live_write_fm(0x00); + else if(cur_live.byte_counter < 47) + live_write_raw(0xf77a); + else if(cur_live.byte_counter < 73) + live_write_fm(0xff); + else { + cur_live.state = WRITE_TRACK_SECTOR; + cur_live.byte_counter = 0; + break; + } + } + cur_live.state = WRITE_TRACK_PRE_SECTORS_BYTE; + cur_live.bit_counter = 16; + checkpoint(); + break; + + case WRITE_TRACK_SECTOR: + if(!cur_live.byte_counter) { + command[3]--; + if(command[3]) + fifo_expect(4, true); + } + if(mfm) { + if(cur_live.byte_counter < 12) + live_write_mfm(0x00); + else if(cur_live.byte_counter < 15) + live_write_raw(0x4489); + else if(cur_live.byte_counter < 16) { + cur_live.crc = 0xcdb4; + live_write_mfm(0xfe); + } else if(cur_live.byte_counter < 20) { + UINT8 byte = fifo_pop(true); + command[12+cur_live.byte_counter-16] = byte; + live_write_mfm(byte); + if(cur_live.byte_counter == 19) + logerror("%s: formatting sector %02x %02x %02x %02x\n", + tag(), command[12], command[13], command[14], command[15]); + } else if(cur_live.byte_counter < 22) + live_write_mfm(cur_live.crc >> 8); + else if(cur_live.byte_counter < 44) + live_write_mfm(0x4e); + else if(cur_live.byte_counter < 56) + live_write_mfm(0x00); + else if(cur_live.byte_counter < 59) + live_write_raw(0x4489); + else if(cur_live.byte_counter < 60) { + cur_live.crc = 0xcdb4; + live_write_mfm(0xfb); + } else if(cur_live.byte_counter < 60+sector_size) + live_write_mfm(command[5]); + else if(cur_live.byte_counter < 62+sector_size) + live_write_mfm(cur_live.crc >> 8); + else if(cur_live.byte_counter < 62+sector_size+command[4]) + live_write_mfm(0x4e); + else { + cur_live.byte_counter = 0; + cur_live.state = command[3] ? WRITE_TRACK_SECTOR : WRITE_TRACK_POST_SECTORS; + break; + } + + } else { + if(cur_live.byte_counter < 6) + live_write_fm(0x00); + else if(cur_live.byte_counter < 7) { + cur_live.crc = 0xffff; + live_write_raw(0xf57e); + } else if(cur_live.byte_counter < 11) { + UINT8 byte = fifo_pop(true); + command[12+cur_live.byte_counter-7] = byte; + live_write_fm(byte); + if(cur_live.byte_counter == 10) + logerror("%s: formatting sector %02x %02x %02x %02x\n", + tag(), command[12], command[13], command[14], command[15]); + } else if(cur_live.byte_counter < 13) + live_write_fm(cur_live.crc >> 8); + else if(cur_live.byte_counter < 24) + live_write_fm(0xff); + else if(cur_live.byte_counter < 30) + live_write_fm(0x00); + else if(cur_live.byte_counter < 31) { + cur_live.crc = 0xffff; + live_write_raw(0xf56f); + } else if(cur_live.byte_counter < 31+sector_size) + live_write_fm(command[5]); + else if(cur_live.byte_counter < 33+sector_size) + live_write_fm(cur_live.crc >> 8); + else if(cur_live.byte_counter < 33+sector_size+command[4]) + live_write_fm(0xff); + else { + cur_live.byte_counter = 0; + cur_live.state = command[3] ? WRITE_TRACK_SECTOR : WRITE_TRACK_POST_SECTORS; + break; + } + } + cur_live.state = WRITE_TRACK_SECTOR_BYTE; + cur_live.bit_counter = 16; + checkpoint(); + break; + + case WRITE_TRACK_POST_SECTORS: + if(mfm) + live_write_mfm(0x4e); + else + live_write_fm(0xff); + cur_live.state = WRITE_TRACK_POST_SECTORS_BYTE; + cur_live.bit_counter = 16; + checkpoint(); + break; + + case WRITE_TRACK_PRE_SECTORS_BYTE: + case WRITE_TRACK_SECTOR_BYTE: + case WRITE_TRACK_POST_SECTORS_BYTE: + case WRITE_SECTOR_DATA_BYTE: + if(write_one_bit(limit)) + return; + if(cur_live.bit_counter == 0) { + cur_live.byte_counter++; + live_delay(cur_live.state-1); + return; + } + break; + + default: + logerror("%s: Unknown live state %d\n", tts(cur_live.tm).c_str(), cur_live.state); + return; + } + } +} + +int upd765_family_device::check_command() +{ + // 0.000010 read track + // 00000011 specify + // 00000100 sense drive status + // ..000101 write data + // ...00110 read data + // 00000111 recalibrate + // 00001000 sense interrupt status + // ..001001 write deleted data + // 0.001010 read id + // ...01100 read deleted data + // 0.001101 format track + // 00001110 dumpreg + // 00101110 save + // 01001110 restore + // 10001110 drive specification command + // 00001111 seek + // 1.001111 relative seek + // 00010000 version + // ...10001 scan equal + // 00010010 perpendicular mode + // 00010011 configure + // 00110011 option + // .0010100 lock + // ...10110 verify + // 00010111 powerdown mode + // 00011000 part id + // ...11001 scan low or equal + // ...11101 scan high or equal + + // MSDOS 6.22 format uses 0xcd to format a track, which makes one + // think only the bottom 5 bits are decoded. + + switch(command[0] & 0x1f) { + case 0x02: + return command_pos == 9 ? C_READ_TRACK : C_INCOMPLETE; + + case 0x03: + return command_pos == 3 ? C_SPECIFY : C_INCOMPLETE; + + case 0x04: + return command_pos == 2 ? C_SENSE_DRIVE_STATUS : C_INCOMPLETE; + + case 0x05: + case 0x09: + return command_pos == 9 ? C_WRITE_DATA : C_INCOMPLETE; + + case 0x06: + case 0x0c: + return command_pos == 9 ? C_READ_DATA : C_INCOMPLETE; + + case 0x07: + return command_pos == 2 ? C_RECALIBRATE : C_INCOMPLETE; + + case 0x08: + return C_SENSE_INTERRUPT_STATUS; + + case 0x0a: + return command_pos == 2 ? C_READ_ID : C_INCOMPLETE; + + case 0x0d: + return command_pos == 6 ? C_FORMAT_TRACK : C_INCOMPLETE; + + case 0x0e: + return C_DUMP_REG; + + case 0x0f: + return command_pos == 3 ? C_SEEK : C_INCOMPLETE; + + case 0x11: + return command_pos == 9 ? C_SCAN_EQUAL : C_INCOMPLETE; + + case 0x12: + return command_pos == 2 ? C_PERPENDICULAR : C_INCOMPLETE; + + case 0x13: + return command_pos == 4 ? C_CONFIGURE : C_INCOMPLETE; + + case 0x14: + return C_LOCK; + + case 0x19: + return command_pos == 9 ? C_SCAN_LOW : C_INCOMPLETE; + + case 0x1d: + return command_pos == 9 ? C_SCAN_HIGH : C_INCOMPLETE; + + default: + return C_INVALID; + } +} + +void upd765_family_device::start_command(int cmd) +{ + command_pos = 0; + result_pos = 0; + main_phase = PHASE_EXEC; + tc_done = false; + switch(cmd) { + case C_CONFIGURE: + logerror("%s: command configure %02x %02x %02x\n", + tag(), + command[1], command[2], command[3]); + // byte 1 is ignored, byte 3 is precompensation-related + fifocfg = command[2]; + precomp = command[3]; + main_phase = PHASE_CMD; + break; + + case C_DUMP_REG: + logerror("%s: command dump regs\n", tag()); + main_phase = PHASE_RESULT; + result[0] = flopi[0].pcn; + result[1] = flopi[1].pcn; + result[2] = flopi[2].pcn; + result[3] = flopi[3].pcn; + result[4] = (spec & 0xff00) >> 8; + result[5] = (spec & 0x00ff); + result[6] = sector_size; + result[7] = locked ? 0x80 : 0x00; + result[7] |= (perpmode & 0x30); + result[8] = fifocfg; + result[9] = precomp; + result_pos = 10; + break; + + case C_FORMAT_TRACK: + format_track_start(flopi[command[1] & 3]); + break; + + case C_LOCK: + locked = command[0] & 0x80; + main_phase = PHASE_RESULT; + result[0] = locked ? 0x10 : 0x00; + result_pos = 1; + logerror("%s: command lock (%s)\n", tag(), locked ? "on" : "off"); + break; + + case C_PERPENDICULAR: + logerror("%s: command perpendicular\n", tag()); + perpmode = command[1]; + main_phase = PHASE_CMD; + break; + + case C_READ_DATA: + read_data_start(flopi[command[1] & 3]); + break; + + case C_READ_ID: + read_id_start(flopi[command[1] & 3]); + break; + + case C_READ_TRACK: + read_track_start(flopi[command[1] & 3]); + break; + + case C_SCAN_EQUAL: + case C_SCAN_LOW: + case C_SCAN_HIGH: + scan_start(flopi[command[1] & 3]); + break; + + case C_RECALIBRATE: + recalibrate_start(flopi[command[1] & 3]); + main_phase = PHASE_CMD; + break; + + case C_SEEK: + seek_start(flopi[command[1] & 3]); + main_phase = PHASE_CMD; + break; + + case C_SENSE_DRIVE_STATUS: { + floppy_info &fi = flopi[command[1] & 3]; + main_phase = PHASE_RESULT; + result[0] = command[1] & 7; + if(fi.ready) + result[0] |= ST3_RY; + if(fi.dev) + result[0] |= + (fi.dev->wpt_r() ? ST3_WP : 0x00) | + (fi.dev->trk00_r() ? 0x00 : ST3_T0) | + (fi.dev->twosid_r() ? 0x00 : ST3_TS); + logerror("%s: command sense drive status %d (%02x)\n", tag(), fi.id, result[0]); + result_pos = 1; + break; + } + + case C_SENSE_INTERRUPT_STATUS: { + // Documentation is somewhat contradictory w.r.t polling + // and irq. PC bios, especially 5150, requires that only + // one irq happens. That's also wait the ns82077a doc + // says it does. OTOH, a number of docs says you need to + // call SIS 4 times, once per drive... + // + // There's also the interaction with the seek irq. The + // somewhat borderline tf20 code seems to think that + // essentially ignoring the polling irq should work. + // + // And the pc98 expects to be able to accumulate irq reasons + // for different drives and things to work. + // + // Current hypothesis: + // - each drive has its own st0 and irq trigger + // - SIS drops the irq always, but also returns the first full st0 it finds + + main_phase = PHASE_RESULT; + + int fid; + for(fid=0; fid<4 && !flopi[fid].st0_filled; fid++); + if(fid == 4) { + result[0] = ST0_UNK; + result_pos = 1; + logerror("%s: command sense interrupt status (%02x)\n", tag(), result[0]); + break; + } + + floppy_info &fi = flopi[fid]; + fi.st0_filled = false; + + result[0] = fi.st0; + result[1] = fi.pcn; + + logerror("%s: command sense interrupt status (fid=%d %02x %02x)\n", tag(), fid, result[0], result[1]); + result_pos = 2; + + other_irq = false; + check_irq(); + break; + } + + case C_SPECIFY: + logerror("%s: command specify %02x %02x\n", + tag(), + command[1], command[2]); + spec = (command[1] << 8) | command[2]; + main_phase = PHASE_CMD; + break; + + case C_WRITE_DATA: + write_data_start(flopi[command[1] & 3]); + break; + + default: + fprintf(stderr, "start command %d\n", cmd); + exit(1); + } +} + +void upd765_family_device::command_end(floppy_info &fi, bool data_completion) +{ + logerror("%s: command done (%s) -", tag(), data_completion ? "data" : "seek"); + for(int i=0; i != result_pos; i++) + logerror(" %02x", result[i]); + logerror("\n"); + fi.main_state = fi.sub_state = IDLE; + if(data_completion) + data_irq = true; + else + { + other_irq = true; + fi.st0_filled = true; + } + check_irq(); +} + +void upd765_family_device::recalibrate_start(floppy_info &fi) +{ + logerror("%s: command recalibrate\n", tag()); + fi.main_state = RECALIBRATE; + fi.sub_state = SEEK_WAIT_STEP_TIME_DONE; + fi.dir = 1; + fi.counter = 77; + seek_continue(fi); +} + +void upd765_family_device::seek_start(floppy_info &fi) +{ + logerror("%s: command %sseek %d\n", tag(), command[0] & 0x80 ? "relative " : "", command[2]); + fi.main_state = SEEK; + fi.sub_state = SEEK_WAIT_STEP_TIME_DONE; + fi.dir = fi.pcn > command[2] ? 1 : 0; + seek_continue(fi); +} + +void upd765_family_device::delay_cycles(emu_timer *tm, int cycles) +{ + tm->adjust(attotime::from_double(double(cycles)/cur_rate)); +} + +void upd765_family_device::seek_continue(floppy_info &fi) +{ + for(;;) { + switch(fi.sub_state) { + case SEEK_MOVE: + if(fi.dev) { + fi.dev->dir_w(fi.dir); + fi.dev->stp_w(0); + } + fi.sub_state = SEEK_WAIT_STEP_SIGNAL_TIME; + fi.tm->adjust(attotime::from_nsec(2500)); + return; + + case SEEK_WAIT_STEP_SIGNAL_TIME: + return; + + case SEEK_WAIT_STEP_SIGNAL_TIME_DONE: + if(fi.dev) + fi.dev->stp_w(1); + + if(fi.main_state == SEEK) { + if(fi.pcn > command[2]) + fi.pcn--; + else + fi.pcn++; + } + fi.sub_state = SEEK_WAIT_STEP_TIME; + delay_cycles(fi.tm, 500*(16-(spec >> 12))); + return; + + case SEEK_WAIT_STEP_TIME: + return; + + case SEEK_WAIT_STEP_TIME_DONE: { + bool done = false; + switch(fi.main_state) { + case RECALIBRATE: + fi.counter--; + done = fi.dev && !fi.dev->trk00_r(); + if(done) + fi.pcn = 0; + else if(!fi.counter) { + fi.st0 = ST0_FAIL|ST0_SE|ST0_EC | fi.id; + command_end(fi, false); + return; + } + break; + case SEEK: + done = fi.pcn == command[2]; + break; + } + if(done) { + fi.st0 = ST0_SE | fi.id; + command_end(fi, false); + return; + } + fi.sub_state = SEEK_MOVE; + break; + } + } + } +} + +void upd765_family_device::read_data_start(floppy_info &fi) +{ + fi.main_state = READ_DATA; + fi.sub_state = HEAD_LOAD_DONE; + mfm = command[0] & 0x40; + + logerror("%s: command read%s data%s%s%s%s cmd=%02x sel=%x chrn=(%d, %d, %d, %d) eot=%02x gpl=%02x dtl=%02x rate=%d\n", + tag(), + command[0] & 0x08 ? " deleted" : "", + command[0] & 0x80 ? " mt" : "", + command[0] & 0x40 ? " mfm" : "", + command[0] & 0x20 ? " sk" : "", + fifocfg & 0x40 ? " seek" : "", + command[0], + command[1], + command[2], + command[3], + command[4], + 128 << (command[5] & 7), + command[6], + command[7], + command[8], + cur_rate); + + fi.st0 = command[1] & 7; + st1 = ST1_MA; + st2 = 0x00; + hdl_cb(1); + fi.ready = get_ready(command[1] & 3); + + if(!fi.ready) + { + fi.st0 |= ST0_NR | ST0_FAIL; + fi.sub_state = COMMAND_DONE; + st1 = 0; + st2 = 0; + read_data_continue(fi); + return; + } + + if(fi.dev) + fi.dev->ss_w(command[1] & 4 ? 1 : 0); + read_data_continue(fi); +} + +void upd765_family_device::scan_start(floppy_info &fi) +{ + fi.main_state = SCAN_DATA; + fi.sub_state = HEAD_LOAD_DONE; + mfm = command[0] & 0x40; + + logerror("%s: command scan%s data%s%s%s%s cmd=%02x sel=%x chrn=(%d, %d, %d, %d) eot=%02x gpl=%02x stp=%02x rate=%d\n", + tag(), + command[0] & 0x08 ? " deleted" : "", + command[0] & 0x80 ? " mt" : "", + command[0] & 0x40 ? " mfm" : "", + command[0] & 0x20 ? " sk" : "", + fifocfg & 0x40 ? " seek" : "", + command[0], + command[1], + command[2], + command[3], + command[4], + 128 << (command[5] & 7), + command[6], + command[7], + command[8], + cur_rate); + + fi.st0 = command[1] & 7; + st1 = ST1_MA; + st2 = 0x00; + scan_done = false; + hdl_cb(1); + fi.ready = get_ready(command[1] & 3); + + if(!fi.ready) + { + fi.st0 |= ST0_NR | ST0_FAIL; + fi.sub_state = COMMAND_DONE; + st1 = 0; + st2 = 0; + read_data_continue(fi); + return; + } + + if(fi.dev) + fi.dev->ss_w(command[1] & 4 ? 1 : 0); + read_data_continue(fi); +} + +void upd765_family_device::read_data_continue(floppy_info &fi) +{ + for(;;) { + switch(fi.sub_state) { + case HEAD_LOAD_DONE: + if(fi.pcn == command[2] || !(fifocfg & 0x40)) { + fi.sub_state = SEEK_DONE; + break; + } + fi.st0 |= ST0_SE; + if(fi.dev) { + fi.dev->dir_w(fi.pcn > command[2] ? 1 : 0); + fi.dev->stp_w(0); + } + fi.sub_state = SEEK_WAIT_STEP_SIGNAL_TIME; + fi.tm->adjust(attotime::from_nsec(2500)); + return; + + case SEEK_WAIT_STEP_SIGNAL_TIME: + return; + + case SEEK_WAIT_STEP_SIGNAL_TIME_DONE: + if(fi.dev) + fi.dev->stp_w(1); + + fi.sub_state = SEEK_WAIT_STEP_TIME; + delay_cycles(fi.tm, 500*(16-(spec >> 12))); + return; + + case SEEK_WAIT_STEP_TIME: + return; + + case SEEK_WAIT_STEP_TIME_DONE: + if(fi.pcn > command[2]) + fi.pcn--; + else + fi.pcn++; + fi.sub_state = HEAD_LOAD_DONE; + break; + + case SEEK_DONE: + fi.counter = 0; + fi.sub_state = SCAN_ID; + live_start(fi, SEARCH_ADDRESS_MARK_HEADER); + return; + + case SCAN_ID: + if(cur_live.crc) { + fi.st0 |= ST0_FAIL; + st1 |= ST1_DE|ST1_ND; + fi.sub_state = COMMAND_DONE; + break; + } + st1 &= ~ST1_MA; + if(!sector_matches()) { + if(cur_live.idbuf[0] != command[2]) { + if(cur_live.idbuf[0] == 0xff) + st2 |= ST2_WC|ST2_BC; + else + st2 |= ST2_WC; + fi.st0 |= ST0_FAIL; + fi.sub_state = COMMAND_DONE; + break; + } + live_start(fi, SEARCH_ADDRESS_MARK_HEADER); + return; + } + logerror("%s: reading sector %02x %02x %02x %02x\n", + tag(), + cur_live.idbuf[0], + cur_live.idbuf[1], + cur_live.idbuf[2], + cur_live.idbuf[3]); + sector_size = calc_sector_size(cur_live.idbuf[3]); + if(fi.main_state == SCAN_DATA) + fifo_expect(sector_size, true); + else + fifo_expect(sector_size, false); + fi.sub_state = SECTOR_READ; + live_start(fi, SEARCH_ADDRESS_MARK_DATA); + return; + + case SCAN_ID_FAILED: + fi.st0 |= ST0_FAIL; + st1 |= ST1_ND; + fi.sub_state = COMMAND_DONE; + break; + + case SECTOR_READ: { + if(st2 & ST2_MD) { + fi.st0 |= ST0_FAIL; + fi.sub_state = COMMAND_DONE; + break; + } + if(cur_live.crc) { + fi.st0 |= ST0_FAIL; + st1 |= ST1_DE; + st2 |= ST2_CM; + fi.sub_state = COMMAND_DONE; + break; + } + bool done = tc_done; + if(command[4] == command[6]) { + if(command[0] & 0x80) { + command[3] = command[3] ^ 1; + command[4] = 1; + if(fi.dev) + fi.dev->ss_w(command[3] & 1); + } + if(!(command[0] & 0x80) || !(command[3] & 1)) { + if(!tc_done) { + fi.st0 |= ST0_FAIL; + st1 |= ST1_EN; + } else { + command[2]++; + command[4] = 1; + } + done = true; + } + } else + command[4]++; + if(!done) { + fi.sub_state = SEEK_DONE; + break; + } + fi.sub_state = COMMAND_DONE; + break; + } + + case COMMAND_DONE: + main_phase = PHASE_RESULT; + result[0] = fi.st0; + result[1] = st1; + result[2] = st2; + result[3] = command[2]; + result[4] = command[3]; + result[5] = command[4]; + result[6] = command[5]; + result_pos = 7; + command_end(fi, true); + return; + + default: + logerror("%s: read sector unknown sub-state %d\n", ttsn().c_str(), fi.sub_state); + return; + } + } +} + +void upd765_family_device::write_data_start(floppy_info &fi) +{ + fi.main_state = WRITE_DATA; + fi.sub_state = HEAD_LOAD_DONE; + mfm = command[0] & 0x40; + logerror("%s: command write%s data%s%s cmd=%02x sel=%x chrn=(%d, %d, %d, %d) eot=%02x gpl=%02x dtl=%02x rate=%d\n", + tag(), + command[0] & 0x08 ? " deleted" : "", + command[0] & 0x80 ? " mt" : "", + command[0] & 0x40 ? " mfm" : "", + command[0], + command[1], + command[2], + command[3], + command[4], + 128 << (command[5] & 7), + command[6], + command[7], + command[8], + cur_rate); + + if(fi.dev) + fi.dev->ss_w(command[1] & 4 ? 1 : 0); + + fi.st0 = command[1] & 7; + st1 = ST1_MA; + st2 = 0x00; + hdl_cb(1); + fi.ready = get_ready(command[1] & 3); + + if(!fi.ready) + { + fi.st0 |= ST0_NR | ST0_FAIL; + fi.sub_state = COMMAND_DONE; + st1 = 0; + st2 = 0; + write_data_continue(fi); + return; + } + + write_data_continue(fi); +} + +void upd765_family_device::write_data_continue(floppy_info &fi) +{ + for(;;) { + switch(fi.sub_state) { + case HEAD_LOAD_DONE: + fi.counter = 0; + fi.sub_state = SCAN_ID; + live_start(fi, SEARCH_ADDRESS_MARK_HEADER); + return; + + case SCAN_ID: + if(!sector_matches()) { + live_start(fi, SEARCH_ADDRESS_MARK_HEADER); + return; + } + if(cur_live.crc) { + fi.st0 |= ST0_FAIL; + st1 |= ST1_DE|ST1_ND; + fi.sub_state = COMMAND_DONE; + break; + } + st1 &= ~ST1_MA; + sector_size = calc_sector_size(cur_live.idbuf[3]); + fifo_expect(sector_size, true); + fi.sub_state = SECTOR_WRITTEN; + live_start(fi, WRITE_SECTOR_SKIP_GAP2); + return; + + case SCAN_ID_FAILED: + fi.st0 |= ST0_FAIL; + st1 |= ST1_ND; + fi.sub_state = COMMAND_DONE; + break; + + case SECTOR_WRITTEN: { + bool done = tc_done; + if(command[4] == command[6]) { + if(command[0] & 0x80) { + command[3] = command[3] ^ 1; + command[4] = 1; + if(fi.dev) + fi.dev->ss_w(command[3] & 1); + } + if(!(command[0] & 0x80) || !(command[3] & 1)) { + if(!tc_done) { + fi.st0 |= ST0_FAIL; + st1 |= ST1_EN; + } else { + command[2]++; + command[4] = 1; + } + done = true; + } + } else + command[4]++; + if(!done) { + fi.sub_state = HEAD_LOAD_DONE; + break; + } + fi.sub_state = COMMAND_DONE; + break; + } + + case COMMAND_DONE: + main_phase = PHASE_RESULT; + result[0] = fi.st0; + result[1] = st1; + result[2] = st2; + result[3] = command[2]; + result[4] = command[3]; + result[5] = command[4]; + result[6] = command[5]; + result_pos = 7; + command_end(fi, true); + return; + + default: + logerror("%s: write sector unknown sub-state %d\n", ttsn().c_str(), fi.sub_state); + return; + } + } +} + +void upd765_family_device::read_track_start(floppy_info &fi) +{ + fi.main_state = READ_TRACK; + fi.sub_state = HEAD_LOAD_DONE; + mfm = command[0] & 0x40; + sectors_read = 0; + + logerror("%s: command read track%s cmd=%02x sel=%x chrn=(%d, %d, %d, %d) eot=%02x gpl=%02x dtl=%02x rate=%d\n", + tag(), + command[0] & 0x40 ? " mfm" : "", + command[0], + command[1], + command[2], + command[3], + command[4], + 128 << (command[5] & 7), + command[6], + command[7], + command[8], + cur_rate); + fi.st0 = command[1] & 7; + st1 = ST1_MA; + st2 = 0x00; + hdl_cb(1); + fi.ready = get_ready(command[1] & 3); + + if(!fi.ready) + { + fi.st0 |= ST0_NR | ST0_FAIL; + fi.sub_state = COMMAND_DONE; + st1 = 0; + st2 = 0; + read_track_continue(fi); + return; + } + + if(fi.dev) + fi.dev->ss_w(command[1] & 4 ? 1 : 0); + read_track_continue(fi); +} + +void upd765_family_device::read_track_continue(floppy_info &fi) +{ + for(;;) { + switch(fi.sub_state) { + case HEAD_LOAD_DONE: + if(fi.pcn == command[2] || !(fifocfg & 0x40)) { + fi.sub_state = SEEK_DONE; + break; + } + fi.st0 |= ST0_SE; + if(fi.dev) { + fi.dev->dir_w(fi.pcn > command[2] ? 1 : 0); + fi.dev->stp_w(0); + } + fi.sub_state = SEEK_WAIT_STEP_SIGNAL_TIME; + fi.tm->adjust(attotime::from_nsec(2500)); + return; + + case SEEK_WAIT_STEP_SIGNAL_TIME: + return; + + case SEEK_WAIT_STEP_SIGNAL_TIME_DONE: + if(fi.dev) + fi.dev->stp_w(1); + + fi.sub_state = SEEK_WAIT_STEP_TIME; + delay_cycles(fi.tm, 500*(16-(spec >> 12))); + return; + + case SEEK_WAIT_STEP_TIME: + return; + + case SEEK_WAIT_STEP_TIME_DONE: + if(fi.pcn > command[2]) + fi.pcn--; + else + fi.pcn++; + fi.sub_state = HEAD_LOAD_DONE; + break; + + case SEEK_DONE: + fi.counter = 0; + fi.sub_state = WAIT_INDEX; + return; + + case WAIT_INDEX: + return; + + case WAIT_INDEX_DONE: + logerror("%s: index found, reading track\n", tag()); + fi.sub_state = SCAN_ID; + live_start(fi, SEARCH_ADDRESS_MARK_HEADER); + return; + + case SCAN_ID: + if(cur_live.crc) { + st1 |= ST1_DE; + } + st1 &= ~ST1_MA; + logerror("%s: reading sector %02x %02x %02x %02x\n", + tag(), + cur_live.idbuf[0], + cur_live.idbuf[1], + cur_live.idbuf[2], + cur_live.idbuf[3]); + if(!sector_matches()) + st1 |= ST1_ND; + else + st1 &= ~ST1_ND; + + sector_size = calc_sector_size(cur_live.idbuf[3]); + fifo_expect(sector_size, false); + fi.sub_state = SECTOR_READ; + live_start(fi, SEARCH_ADDRESS_MARK_DATA); + return; + + case SCAN_ID_FAILED: + fi.st0 |= ST0_FAIL; + st1 |= ST1_ND; + fi.sub_state = COMMAND_DONE; + break; + + case SECTOR_READ: { + if(st2 & ST2_MD) { + fi.st0 |= ST0_FAIL; + fi.sub_state = COMMAND_DONE; + break; + } + if(cur_live.crc) { + st1 |= ST1_DE; + st2 |= ST2_CM; + } + bool done = tc_done; + sectors_read++; + if(sectors_read == command[6]) { + if(!tc_done) { + fi.st0 |= ST0_FAIL; + st1 |= ST1_EN; + } + done = true; + } + if(!done) { + fi.sub_state = WAIT_INDEX_DONE; + break; + } + fi.sub_state = COMMAND_DONE; + break; + } + + case COMMAND_DONE: + main_phase = PHASE_RESULT; + result[0] = fi.st0; + result[1] = st1; + result[2] = st2; + result[3] = command[2]; + result[4] = command[3]; + result[5] = command[4]; + result[6] = command[5]; + result_pos = 7; + command_end(fi, true); + return; + + default: + logerror("%s: read track unknown sub-state %d\n", ttsn().c_str(), fi.sub_state); + return; + } + } +} + +int upd765_family_device::calc_sector_size(UINT8 size) +{ + return size > 7 ? 16384 : 128 << size; +} + +void upd765_family_device::format_track_start(floppy_info &fi) +{ + fi.main_state = FORMAT_TRACK; + fi.sub_state = HEAD_LOAD_DONE; + mfm = command[0] & 0x40; + + logerror("%s: command format track %s h=%02x n=%02x sc=%02x gpl=%02x d=%02x\n", + tag(), + command[0] & 0x40 ? "mfm" : "fm", + command[1], command[2], command[3], command[4], command[5]); + + hdl_cb(1); + fi.ready = get_ready(command[1] & 3); + + if(!fi.ready) + { + fi.st0 = (command[1] & 7) | ST0_NR | ST0_FAIL; + fi.sub_state = TRACK_DONE; + format_track_continue(fi); + return; + } + fi.st0 = command[1] & 7; + + if(fi.dev) + fi.dev->ss_w(command[1] & 4 ? 1 : 0); + sector_size = calc_sector_size(command[2]); + + format_track_continue(fi); +} + +void upd765_family_device::format_track_continue(floppy_info &fi) +{ + for(;;) { + switch(fi.sub_state) { + case HEAD_LOAD_DONE: + fi.sub_state = WAIT_INDEX; + break; + + case WAIT_INDEX: + return; + + case WAIT_INDEX_DONE: + logerror("%s: index found, writing track\n", tag()); + fi.sub_state = TRACK_DONE; + cur_live.pll.start_writing(machine().time()); + live_start(fi, WRITE_TRACK_PRE_SECTORS); + return; + + case TRACK_DONE: + main_phase = PHASE_RESULT; + result[0] = fi.st0; + result[1] = 0; + result[2] = 0; + result[3] = 0; + result[4] = 0; + result[5] = 0; + result[6] = 0; + result_pos = 7; + command_end(fi, true); + return; + + default: + logerror("%s: format track unknown sub-state %d\n", ttsn().c_str(), fi.sub_state); + return; + } + } +} + +void upd765_family_device::read_id_start(floppy_info &fi) +{ + fi.main_state = READ_ID; + fi.sub_state = HEAD_LOAD_DONE; + mfm = command[0] & 0x40; + + logerror("%s: command read id%s, rate=%d\n", + tag(), + command[0] & 0x40 ? " mfm" : "", + cur_rate); + + if(fi.dev) + fi.dev->ss_w(command[1] & 4 ? 1 : 0); + + fi.st0 = command[1] & 7; + st1 = 0x00; + st2 = 0x00; + + for(int i=0; i<4; i++) + cur_live.idbuf[i] = 0x00; + + hdl_cb(1); + fi.ready = get_ready(command[1] & 3); + + if(!fi.ready) + { + fi.st0 |= ST0_NR | ST0_FAIL; + fi.sub_state = COMMAND_DONE; + read_id_continue(fi); + return; + } + + read_id_continue(fi); +} + +void upd765_family_device::read_id_continue(floppy_info &fi) +{ + for(;;) { + switch(fi.sub_state) { + case HEAD_LOAD_DONE: + fi.counter = 0; + fi.sub_state = SCAN_ID; + live_start(fi, SEARCH_ADDRESS_MARK_HEADER); + return; + + case SCAN_ID: + if(cur_live.crc) { + fi.st0 |= ST0_FAIL; + st1 |= ST1_MA|ST1_DE|ST1_ND; + } + fi.sub_state = COMMAND_DONE; + break; + + case SCAN_ID_FAILED: + fi.st0 |= ST0_FAIL; + st1 |= ST1_ND|ST1_MA; + fi.sub_state = COMMAND_DONE; + break; + + case COMMAND_DONE: + main_phase = PHASE_RESULT; + result[0] = fi.st0; + result[1] = st1; + result[2] = st2; + result[3] = cur_live.idbuf[0]; + result[4] = cur_live.idbuf[1]; + result[5] = cur_live.idbuf[2]; + result[6] = cur_live.idbuf[3]; + result_pos = 7; + command_end(fi, true); + return; + + default: + logerror("%s: read id unknown sub-state %d\n", ttsn().c_str(), fi.sub_state); + return; + } + } +} + +void upd765_family_device::check_irq() +{ + bool old_irq = cur_irq; + cur_irq = data_irq || other_irq || internal_drq; + cur_irq = cur_irq && (dor & 4) && (mode != MODE_AT || (dor & 8)); + if(cur_irq != old_irq) { + logerror("%s: irq = %d\n", tag(), cur_irq); + intrq_cb(cur_irq); + } +} + +bool upd765_family_device::get_irq() const +{ + return cur_irq; +} + +std::string upd765_family_device::tts(attotime t) +{ + char buf[256]; + const char *sign = ""; + if(t.seconds() < 0) { + t = attotime::zero-t; + sign = "-"; + } + int nsec = t.attoseconds() / ATTOSECONDS_PER_NANOSECOND; + sprintf(buf, "%s%04d.%03d,%03d,%03d", sign, int(t.seconds()), nsec/1000000, (nsec/1000)%1000, nsec % 1000); + return buf; +} + +std::string upd765_family_device::ttsn() +{ + return tts(machine().time()); +} + +void upd765_family_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + if(id == TIMER_DRIVE_READY_POLLING) { + run_drive_ready_polling(); + return; + } + + live_sync(); + + floppy_info &fi = flopi[id]; + switch(fi.sub_state) { + case SEEK_WAIT_STEP_SIGNAL_TIME: + fi.sub_state = SEEK_WAIT_STEP_SIGNAL_TIME_DONE; + break; + case SEEK_WAIT_STEP_TIME: + fi.sub_state = SEEK_WAIT_STEP_TIME_DONE; + break; + } + + general_continue(fi); +} + +void upd765_family_device::run_drive_ready_polling() +{ + if(main_phase != PHASE_CMD || (fifocfg & FIF_POLL) || command_pos) + return; + + for(int fid=0; fid<4; fid++) { + bool ready = get_ready(fid); + if(ready != flopi[fid].ready) { + logerror("%s: polled %d : %d -> %d\n", tag(), fid, flopi[fid].ready, ready); + flopi[fid].ready = ready; + if(!flopi[fid].st0_filled) { + flopi[fid].st0 = ST0_ABRT | fid; + flopi[fid].st0_filled = true; + other_irq = true; + } + } + } + + check_irq(); +} + +void upd765_family_device::index_callback(floppy_image_device *floppy, int state) +{ + for(int fid=0; fid<4; fid++) { + floppy_info &fi = flopi[fid]; + if(fi.dev != floppy) + continue; + + if(fi.live) + live_sync(); + fi.index = state; + + if(!state) { + general_continue(fi); + continue; + } + + switch(fi.sub_state) { + case IDLE: + case SEEK_MOVE: + case SEEK_WAIT_STEP_SIGNAL_TIME: + case SEEK_WAIT_STEP_SIGNAL_TIME_DONE: + case SEEK_WAIT_STEP_TIME: + case SEEK_WAIT_STEP_TIME_DONE: + case HEAD_LOAD_DONE: + case SCAN_ID_FAILED: + case SECTOR_READ: + break; + + case WAIT_INDEX: + fi.sub_state = WAIT_INDEX_DONE; + break; + + case SCAN_ID: + fi.counter++; + if(fi.counter == 2) { + fi.sub_state = SCAN_ID_FAILED; + live_abort(); + } + break; + + case TRACK_DONE: + live_abort(); + break; + + default: + logerror("%s: Index pulse on unknown sub-state %d\n", ttsn().c_str(), fi.sub_state); + break; + } + + general_continue(fi); + } +} + + +void upd765_family_device::general_continue(floppy_info &fi) +{ + if(fi.live && cur_live.state != IDLE) { + live_run(); + if(cur_live.state != IDLE) + return; + } + + switch(fi.main_state) { + case IDLE: + break; + + case RECALIBRATE: + case SEEK: + seek_continue(fi); + break; + + case READ_DATA: + case SCAN_DATA: + read_data_continue(fi); + break; + + case WRITE_DATA: + write_data_continue(fi); + break; + + case READ_TRACK: + read_track_continue(fi); + break; + + case FORMAT_TRACK: + format_track_continue(fi); + break; + + case READ_ID: + read_id_continue(fi); + break; + + default: + logerror("%s: general_continue on unknown main-state %d\n", ttsn().c_str(), fi.main_state); + break; + } +} + +bool upd765_family_device::read_one_bit(const attotime &limit) +{ + int bit = cur_live.pll.get_next_bit(cur_live.tm, cur_live.fi->dev, limit); + if(bit < 0) + return true; + cur_live.shift_reg = (cur_live.shift_reg << 1) | bit; + cur_live.bit_counter++; + if(cur_live.data_separator_phase) { + cur_live.data_reg = (cur_live.data_reg << 1) | bit; + if((cur_live.crc ^ (bit ? 0x8000 : 0x0000)) & 0x8000) + cur_live.crc = (cur_live.crc << 1) ^ 0x1021; + else + cur_live.crc = cur_live.crc << 1; + } + cur_live.data_separator_phase = !cur_live.data_separator_phase; + return false; +} + +bool upd765_family_device::write_one_bit(const attotime &limit) +{ + bool bit = cur_live.shift_reg & 0x8000; + if(cur_live.pll.write_next_bit(bit, cur_live.tm, cur_live.fi->dev, limit)) + return true; + if(cur_live.bit_counter & 1) { + if((cur_live.crc ^ (bit ? 0x8000 : 0x0000)) & 0x8000) + cur_live.crc = (cur_live.crc << 1) ^ 0x1021; + else + cur_live.crc = cur_live.crc << 1; + } + cur_live.shift_reg = cur_live.shift_reg << 1; + cur_live.bit_counter--; + return false; +} + +void upd765_family_device::live_write_raw(UINT16 raw) +{ + // logerror("write %04x %04x\n", raw, cur_live.crc); + cur_live.shift_reg = raw; + cur_live.data_bit_context = raw & 1; +} + +void upd765_family_device::live_write_mfm(UINT8 mfm) +{ + bool context = cur_live.data_bit_context; + UINT16 raw = 0; + for(int i=0; i<8; i++) { + bool bit = mfm & (0x80 >> i); + if(!(bit || context)) + raw |= 0x8000 >> (2*i); + if(bit) + raw |= 0x4000 >> (2*i); + context = bit; + } + cur_live.data_reg = mfm; + cur_live.shift_reg = raw; + cur_live.data_bit_context = context; + // logerror("write %02x %04x %04x\n", mfm, cur_live.crc, raw); +} + +void upd765_family_device::live_write_fm(UINT8 fm) +{ + UINT16 raw = 0xaaaa; + for(int i=0; i<8; i++) + if(fm & (0x80 >> i)) + raw |= 0x4000 >> (2*i); + cur_live.data_reg = fm; + cur_live.shift_reg = raw; + cur_live.data_bit_context = fm & 1; + // logerror("write %02x %04x %04x\n", fm, cur_live.crc, raw); +} + +bool upd765_family_device::sector_matches() const +{ + if(0) + logerror("%s: matching %02x %02x %02x %02x - %02x %02x %02x %02x\n", tag(), + cur_live.idbuf[0], cur_live.idbuf[1], cur_live.idbuf[2], cur_live.idbuf[3], + command[2], command[3], command[4], command[5]); + return + cur_live.idbuf[0] == command[2] && + cur_live.idbuf[1] == command[3] && + cur_live.idbuf[2] == command[4] && + cur_live.idbuf[3] == command[5]; +} + +upd765a_device::upd765a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : upd765_family_device(mconfig, UPD765A, "UPD765A", tag, owner, clock, "upd765a", __FILE__) +{ + dor_reset = 0x0c; +} + +upd765b_device::upd765b_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : upd765_family_device(mconfig, UPD765B, "UPD765B", tag, owner, clock, "upd765b", __FILE__) +{ + dor_reset = 0x0c; +} + +i8272a_device::i8272a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : upd765_family_device(mconfig, I8272A, "I8272A", tag, owner, clock, "i8272a", __FILE__) +{ + dor_reset = 0x0c; +} + +upd72065_device::upd72065_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : upd765_family_device(mconfig, UPD72065, "UPD72065", tag, owner, clock, "upd72065", __FILE__) +{ + dor_reset = 0x0c; +} + +smc37c78_device::smc37c78_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : upd765_family_device(mconfig, SMC37C78, "SMC37C78", tag, owner, clock, "smc37c78", __FILE__) +{ + ready_connected = false; + select_connected = true; +} + +n82077aa_device::n82077aa_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : upd765_family_device(mconfig, N82077AA, "N82077AA", tag, owner, clock, "n82077aa", __FILE__) +{ + ready_connected = false; + select_connected = true; +} + +pc_fdc_superio_device::pc_fdc_superio_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : upd765_family_device(mconfig, PC_FDC_SUPERIO, "PC FDC SUPERIO", tag, owner, clock, "pc_fdc_superio", __FILE__) +{ + ready_polled = false; + ready_connected = false; + select_connected = true; +} + +dp8473_device::dp8473_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : upd765_family_device(mconfig, PC_FDC_SUPERIO, "DP8473", tag, owner, clock, "dp8473", __FILE__) +{ + ready_polled = false; + ready_connected = false; + select_connected = true; +} + +pc8477a_device::pc8477a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : upd765_family_device(mconfig, PC_FDC_SUPERIO, "PC8477A", tag, owner, clock, "pc8477a", __FILE__) +{ + ready_polled = true; + ready_connected = false; + select_connected = true; +} + +wd37c65c_device::wd37c65c_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : upd765_family_device(mconfig, PC_FDC_SUPERIO, "WD37C65C", tag, owner, clock, "wd37c65c", __FILE__) +{ + ready_polled = true; + ready_connected = false; + select_connected = true; +} + +mcs3201_device::mcs3201_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + upd765_family_device(mconfig, MCS3201, "Motorola MCS3201", tag, owner, clock, "mcs3201", __FILE__), + m_input_handler(*this) +{ + dor_reset = 0x0c; + ready_polled = false; + ready_connected = false; + select_connected = true; +} + +void mcs3201_device::device_start() +{ + upd765_family_device::device_start(); + m_input_handler.resolve_safe(0); +} + +READ8_MEMBER( mcs3201_device::input_r ) +{ + return m_input_handler(); +} + +tc8566af_device::tc8566af_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : upd765_family_device(mconfig, TC8566AF, "TC8566AF", tag, owner, clock, "tc8566af", __FILE__) + , m_cr1(0) +{ + ready_polled = true; + ready_connected = true; + select_connected = true; +} + +void tc8566af_device::device_start() +{ + upd765_family_device::device_start(); + save_item(NAME(m_cr1)); +} + +WRITE8_MEMBER(tc8566af_device::cr1_w) +{ + m_cr1 = data; + + if (m_cr1 & 0x02) + { + // Not sure if this inverted or not + tc_w((m_cr1 & 0x01) ? true : false); + } +} diff --git a/src/devices/machine/upd765.h b/src/devices/machine/upd765.h new file mode 100644 index 00000000000..a3465887943 --- /dev/null +++ b/src/devices/machine/upd765.h @@ -0,0 +1,533 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +#ifndef __UPD765_F_H__ +#define __UPD765_F_H__ + +#include "emu.h" +#include "imagedev/floppy.h" +#include "fdc_pll.h" + +/* + * ready = true if the ready line is physically connected to the floppy drive + * select = true if the fdc controls the floppy drive selection + * mode = MODE_AT, MODE_PS2 or MODE_M30 for the fdcs that have reset-time selection + */ + +#define MCFG_UPD765A_ADD(_tag, _ready, _select) \ + MCFG_DEVICE_ADD(_tag, UPD765A, 0) \ + downcast(device)->set_ready_line_connected(_ready); \ + downcast(device)->set_select_lines_connected(_select); + +#define MCFG_UPD765B_ADD(_tag, _ready, _select) \ + MCFG_DEVICE_ADD(_tag, UPD765B, 0) \ + downcast(device)->set_ready_line_connected(_ready); \ + downcast(device)->set_select_lines_connected(_select); + +#define MCFG_I8272A_ADD(_tag, _ready) \ + MCFG_DEVICE_ADD(_tag, I8272A, 0) \ + downcast(device)->set_ready_line_connected(_ready); + +#define MCFG_UPD72065_ADD(_tag, _ready, _select) \ + MCFG_DEVICE_ADD(_tag, UPD72065, 0) \ + downcast(device)->set_ready_line_connected(_ready); \ + downcast(device)->set_select_lines_connected(_select); + +#define MCFG_SMC37C78_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, SMC37C78, 0) + +#define MCFG_N82077AA_ADD(_tag, _mode) \ + MCFG_DEVICE_ADD(_tag, N82077AA, 0) \ + downcast(device)->set_mode(_mode); + +#define MCFG_PC_FDC_SUPERIO_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, PC_FDC_SUPERIO, 0) + +#define MCFG_DP8473_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, DP8473, 0) + +#define MCFG_PC8477A_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, PC8477A, 0) + +#define MCFG_WD37C65C_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, WD37C65C, 0) + +#define MCFG_MCS3201_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, MCS3201, 0) + +#define MCFG_TC8566AF_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, TC8566AF, 0) + +#define MCFG_MCS3201_INPUT_HANDLER(_devcb) \ + devcb = &mcs3201_device::set_input_handler(*device, DEVCB_##_devcb); + +#define MCFG_UPD765_INTRQ_CALLBACK(_write) \ + devcb = &upd765_family_device::set_intrq_wr_callback(*device, DEVCB_##_write); + +#define MCFG_UPD765_DRQ_CALLBACK(_write) \ + devcb = &upd765_family_device::set_drq_wr_callback(*device, DEVCB_##_write); + +#define MCFG_UPD765_HDL_CALLBACK(_write) \ + devcb = &upd765_family_device::set_hdl_wr_callback(*device, DEVCB_##_write); + +/* Interface required for PC ISA wrapping */ +class pc_fdc_interface : public device_t { +public: + typedef delegate byte_read_cb; + typedef delegate byte_write_cb; + + pc_fdc_interface(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : device_t(mconfig, type, name, tag, owner, clock, shortname, source) {} + + /* Note that the address map must cover and handle the whole 0-7 + * range. The upd765, while conforming to the rest of the + * interface, is not eligible as a result. + */ + + virtual DECLARE_ADDRESS_MAP(map, 8) = 0; + + virtual UINT8 dma_r() = 0; + virtual void dma_w(UINT8 data) = 0; + + virtual void tc_w(bool val) = 0; + virtual UINT8 do_dir_r() = 0; +}; + +class upd765_family_device : public pc_fdc_interface { +public: + enum { MODE_AT, MODE_PS2, MODE_M30 }; + + upd765_family_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + template static devcb_base &set_intrq_wr_callback(device_t &device, _Object object) { return downcast(device).intrq_cb.set_callback(object); } + template static devcb_base &set_drq_wr_callback(device_t &device, _Object object) { return downcast(device).drq_cb.set_callback(object); } + template static devcb_base &set_hdl_wr_callback(device_t &device, _Object object) { return downcast(device).hdl_cb.set_callback(object); } + + virtual DECLARE_ADDRESS_MAP(map, 8) = 0; + + DECLARE_READ8_MEMBER (sra_r); + DECLARE_READ8_MEMBER (srb_r); + DECLARE_READ8_MEMBER (dor_r); + DECLARE_WRITE8_MEMBER(dor_w); + DECLARE_READ8_MEMBER (tdr_r); + DECLARE_WRITE8_MEMBER(tdr_w); + DECLARE_READ8_MEMBER (msr_r); + DECLARE_WRITE8_MEMBER(dsr_w); + DECLARE_READ8_MEMBER (fifo_r); + DECLARE_WRITE8_MEMBER(fifo_w); + DECLARE_READ8_MEMBER (dir_r); + DECLARE_WRITE8_MEMBER(ccr_w); + + virtual UINT8 do_dir_r(); + + UINT8 dma_r(); + void dma_w(UINT8 data); + + // Same as the previous ones, but as memory-mappable members + DECLARE_READ8_MEMBER(mdma_r); + DECLARE_WRITE8_MEMBER(mdma_w); + + bool get_irq() const; + bool get_drq() const; + void tc_w(bool val); + void ready_w(bool val); + + void set_rate(int rate); // rate in bps, to be used when the fdc is externally frequency-controlled + + void set_mode(int mode); + void set_ready_line_connected(bool ready); + void set_select_lines_connected(bool select); + void set_floppy(floppy_image_device *image); + void soft_reset(); + +protected: + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + enum { + TIMER_DRIVE_READY_POLLING = 4 + }; + + enum { + PHASE_CMD, PHASE_EXEC, PHASE_RESULT + }; + + enum { + MSR_DB = 0x0f, + MSR_CB = 0x10, + MSR_EXM = 0x20, + MSR_DIO = 0x40, + MSR_RQM = 0x80, + + ST0_UNIT = 0x07, + ST0_NR = 0x08, + ST0_EC = 0x10, + ST0_SE = 0x20, + ST0_FAIL = 0x40, + ST0_UNK = 0x80, + ST0_ABRT = 0xc0, + + ST1_MA = 0x01, + ST1_NW = 0x02, + ST1_ND = 0x04, + ST1_OR = 0x10, + ST1_DE = 0x20, + ST1_EN = 0x80, + + ST2_MD = 0x01, + ST2_BC = 0x02, + ST2_SN = 0x04, + ST2_SH = 0x08, + ST2_WC = 0x10, + ST2_DD = 0x20, + ST2_CM = 0x40, + + ST3_UNIT = 0x07, + ST3_TS = 0x08, + ST3_T0 = 0x10, + ST3_RY = 0x20, + ST3_WP = 0x40, + ST3_FT = 0x80, + + FIF_THR = 0x0f, + FIF_POLL = 0x10, + FIF_DIS = 0x20, + FIF_EIS = 0x40, + + SPEC_ND = 0x0001 + }; + + + enum { + // General "doing nothing" state + IDLE, + + // Main states + RECALIBRATE, + SEEK, + READ_DATA, + WRITE_DATA, + READ_TRACK, + FORMAT_TRACK, + READ_ID, + SCAN_DATA, + + // Sub-states + COMMAND_DONE, + + SEEK_MOVE, + SEEK_WAIT_STEP_SIGNAL_TIME, + SEEK_WAIT_STEP_SIGNAL_TIME_DONE, + SEEK_WAIT_STEP_TIME, + SEEK_WAIT_STEP_TIME_DONE, + SEEK_DONE, + + HEAD_LOAD_DONE, + + WAIT_INDEX, + WAIT_INDEX_DONE, + + SCAN_ID, + SCAN_ID_FAILED, + + SECTOR_READ, + SECTOR_WRITTEN, + TC_DONE, + + TRACK_DONE, + + // Live states + SEARCH_ADDRESS_MARK_HEADER, + READ_HEADER_BLOCK_HEADER, + READ_DATA_BLOCK_HEADER, + READ_ID_BLOCK, + SEARCH_ADDRESS_MARK_DATA, + SEARCH_ADDRESS_MARK_DATA_FAILED, + READ_SECTOR_DATA, + READ_SECTOR_DATA_BYTE, + SCAN_SECTOR_DATA_BYTE, + + WRITE_SECTOR_SKIP_GAP2, + WRITE_SECTOR_SKIP_GAP2_BYTE, + WRITE_SECTOR_DATA, + WRITE_SECTOR_DATA_BYTE, + + WRITE_TRACK_PRE_SECTORS, + WRITE_TRACK_PRE_SECTORS_BYTE, + + WRITE_TRACK_SECTOR, + WRITE_TRACK_SECTOR_BYTE, + + WRITE_TRACK_POST_SECTORS, + WRITE_TRACK_POST_SECTORS_BYTE + }; + + struct pll_t { + attotime ctime, period, min_period, max_period, period_adjust_base, phase_adjust; + + attotime write_start_time; + attotime write_buffer[32]; + int write_position; + int freq_hist; + + void set_clock(const attotime &period); + void reset(const attotime &when); + int get_next_bit(attotime &tm, floppy_image_device *floppy, const attotime &limit); + bool write_next_bit(bool bit, attotime &tm, floppy_image_device *floppy, const attotime &limit); + void start_writing(const attotime &tm); + void commit(floppy_image_device *floppy, const attotime &tm); + void stop_writing(floppy_image_device *floppy, const attotime &tm); + }; + + struct floppy_info { + enum { IRQ_NONE, IRQ_POLLED, IRQ_SEEK, IRQ_DONE }; + emu_timer *tm; + floppy_image_device *dev; + int id; + int main_state, sub_state; + int dir, counter; + UINT8 pcn, st0; + bool st0_filled; + bool live, index, ready; + }; + + struct live_info { + enum { PT_NONE, PT_CRC_1, PT_CRC_2 }; + + attotime tm; + int state, next_state; + floppy_info *fi; + UINT16 shift_reg; + UINT16 crc; + int bit_counter, byte_counter, previous_type; + bool data_separator_phase, data_bit_context; + UINT8 data_reg; + UINT8 idbuf[6]; + fdc_pll_t pll; + }; + + static int rates[4]; + + bool ready_connected, ready_polled, select_connected; + + bool external_ready; + + int mode; + int main_phase; + + live_info cur_live, checkpoint_live; + devcb_write_line intrq_cb, drq_cb, hdl_cb; + bool cur_irq, other_irq, data_irq, drq, internal_drq, tc, tc_done, locked, mfm, scan_done; + floppy_info flopi[4]; + + int fifo_pos, fifo_expected, command_pos, result_pos, sectors_read; + bool fifo_write; + UINT8 dor, dsr, msr, fifo[16], command[16], result[16]; + UINT8 st1, st2, st3; + UINT8 fifocfg, dor_reset; + UINT8 precomp, perpmode; + UINT16 spec; + int sector_size; + int cur_rate; + + emu_timer *poll_timer; + + static std::string tts(attotime t); + std::string ttsn(); + + enum { + C_CONFIGURE, + C_DUMP_REG, + C_FORMAT_TRACK, + C_LOCK, + C_PERPENDICULAR, + C_READ_DATA, + C_READ_ID, + C_READ_TRACK, + C_RECALIBRATE, + C_SEEK, + C_SENSE_DRIVE_STATUS, + C_SENSE_INTERRUPT_STATUS, + C_SPECIFY, + C_WRITE_DATA, + C_SCAN_EQUAL, + C_SCAN_LOW, + C_SCAN_HIGH, + + C_INVALID, + C_INCOMPLETE + }; + + void delay_cycles(emu_timer *tm, int cycles); + void check_irq(); + void fifo_expect(int size, bool write); + void fifo_push(UINT8 data, bool internal); + UINT8 fifo_pop(bool internal); + void set_drq(bool state); + bool get_ready(int fid); + + void enable_transfer(); + void disable_transfer(); + int calc_sector_size(UINT8 size); + + void run_drive_ready_polling(); + + int check_command(); + void start_command(int cmd); + void command_end(floppy_info &fi, bool data_completion); + + void recalibrate_start(floppy_info &fi); + void seek_start(floppy_info &fi); + void seek_continue(floppy_info &fi); + + void read_data_start(floppy_info &fi); + void read_data_continue(floppy_info &fi); + + void write_data_start(floppy_info &fi); + void write_data_continue(floppy_info &fi); + + void read_track_start(floppy_info &fi); + void read_track_continue(floppy_info &fi); + + void format_track_start(floppy_info &fi); + void format_track_continue(floppy_info &fi); + + void read_id_start(floppy_info &fi); + void read_id_continue(floppy_info &fi); + + void scan_start(floppy_info &fi); + + void general_continue(floppy_info &fi); + void index_callback(floppy_image_device *floppy, int state); + bool sector_matches() const; + + void live_start(floppy_info &fi, int live_state); + void live_abort(); + void checkpoint(); + void rollback(); + void live_delay(int state); + void live_sync(); + void live_run(attotime limit = attotime::never); + void live_write_raw(UINT16 raw); + void live_write_fm(UINT8 fm); + void live_write_mfm(UINT8 mfm); + + bool read_one_bit(const attotime &limit); + bool write_one_bit(const attotime &limit); +}; + +class upd765a_device : public upd765_family_device { +public: + upd765a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual DECLARE_ADDRESS_MAP(map, 8); +}; + +class upd765b_device : public upd765_family_device { +public: + upd765b_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual DECLARE_ADDRESS_MAP(map, 8); +}; + +class i8272a_device : public upd765_family_device { +public: + i8272a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual DECLARE_ADDRESS_MAP(map, 8); +}; + +class smc37c78_device : public upd765_family_device { +public: + smc37c78_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual DECLARE_ADDRESS_MAP(map, 8); +}; + +class upd72065_device : public upd765_family_device { +public: + upd72065_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual DECLARE_ADDRESS_MAP(map, 8); +}; + +class n82077aa_device : public upd765_family_device { +public: + n82077aa_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual DECLARE_ADDRESS_MAP(map, 8); +}; + +class pc_fdc_superio_device : public upd765_family_device { +public: + pc_fdc_superio_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual DECLARE_ADDRESS_MAP(map, 8); +}; + +class dp8473_device : public upd765_family_device { +public: + dp8473_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual DECLARE_ADDRESS_MAP(map, 8); +}; + +class pc8477a_device : public upd765_family_device { +public: + pc8477a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual DECLARE_ADDRESS_MAP(map, 8); +}; + +class wd37c65c_device : public upd765_family_device { +public: + wd37c65c_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual DECLARE_ADDRESS_MAP(map, 8); +}; + +class mcs3201_device : public upd765_family_device { +public: + mcs3201_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // static configuration helpers + template static devcb_base &set_input_handler(device_t &device, _Object object) { return downcast(device).m_input_handler.set_callback(object); } + + virtual DECLARE_ADDRESS_MAP(map, 8); + DECLARE_READ8_MEMBER( input_r ); + +protected: + virtual void device_start(); + +private: + devcb_read8 m_input_handler; +}; + +class tc8566af_device : public upd765_family_device { +public: + tc8566af_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual DECLARE_ADDRESS_MAP(map, 8); + + DECLARE_WRITE8_MEMBER(cr1_w); + +protected: + virtual void device_start(); + +private: + UINT8 m_cr1; +}; + +extern const device_type UPD765A; +extern const device_type UPD765B; +extern const device_type I8272A; +extern const device_type UPD72065; +extern const device_type SMC37C78; +extern const device_type N82077AA; +extern const device_type PC_FDC_SUPERIO; +extern const device_type DP8473; +extern const device_type PC8477A; +extern const device_type WD37C65C; +extern const device_type MCS3201; +extern const device_type TC8566AF; + +#endif diff --git a/src/devices/machine/v3021.c b/src/devices/machine/v3021.c new file mode 100644 index 00000000000..de8f8526f25 --- /dev/null +++ b/src/devices/machine/v3021.c @@ -0,0 +1,185 @@ +// license:BSD-3-Clause +// copyright-holders:Angelo Salese +/*************************************************************************** + + v3021.c + + EM Microelectronic-Marin SA Ultra Low Power 32kHz CMOS RTC (DIP8) + + Serial Real Time Clock + + - very preliminary, borrowed from hard-coded PGM implementation. + +***************************************************************************/ + +#include "emu.h" +#include "machine/v3021.h" + + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +// device type definition +const device_type v3021 = &device_creator; + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// v3021_device - constructor +//------------------------------------------------- + +v3021_device::v3021_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, v3021, "V3021 RTC", tag, owner, clock, "v3021", __FILE__) +{ +} + +void v3021_device::timer_callback() +{ + static const UINT8 dpm[12] = { 0x31, 0x28, 0x31, 0x30, 0x31, 0x30, 0x31, 0x31, 0x30, 0x31, 0x30, 0x31 }; + int dpm_count; + + m_rtc.sec++; + + if((m_rtc.sec & 0x0f) >= 0x0a) { m_rtc.sec+=0x10; m_rtc.sec&=0xf0; } + if((m_rtc.sec & 0xf0) >= 0x60) { m_rtc.min++; m_rtc.sec = 0; } + if((m_rtc.min & 0x0f) >= 0x0a) { m_rtc.min+=0x10; m_rtc.min&=0xf0; } + if((m_rtc.min & 0xf0) >= 0x60) { m_rtc.hour++; m_rtc.min = 0; } + if((m_rtc.hour & 0x0f) >= 0x0a) { m_rtc.hour+=0x10; m_rtc.hour&=0xf0; } + if((m_rtc.hour & 0xff) >= 0x24) { m_rtc.day++; m_rtc.wday<<=1; m_rtc.hour = 0; } + if(m_rtc.wday & 0x80) { m_rtc.wday = 1; } + if((m_rtc.day & 0x0f) >= 0x0a) { m_rtc.day+=0x10; m_rtc.day&=0xf0; } + + /* TODO: crude leap year support */ + dpm_count = (m_rtc.month & 0xf) + (((m_rtc.month & 0x10) >> 4)*10)-1; + + if(((m_rtc.year % 4) == 0) && m_rtc.month == 2) + { + if((m_rtc.day & 0xff) >= dpm[dpm_count]+1+1) + { m_rtc.month++; m_rtc.day = 0x01; } + } + else if((m_rtc.day & 0xff) >= dpm[dpm_count]+1){ m_rtc.month++; m_rtc.day = 0x01; } + if((m_rtc.month & 0x0f) >= 0x0a) { m_rtc.month = 0x10; } + if(m_rtc.month >= 0x13) { m_rtc.year++; m_rtc.month = 1; } + if((m_rtc.year & 0x0f) >= 0x0a) { m_rtc.year+=0x10; m_rtc.year&=0xf0; } + if((m_rtc.year & 0xf0) >= 0xa0) { m_rtc.year = 0; } //2000-2099 possible timeframe +} + +TIMER_CALLBACK( v3021_device::rtc_inc_callback ) +{ + reinterpret_cast(ptr)->timer_callback(); +} + +//------------------------------------------------- +// device_validity_check - perform validity checks +// on this device +//------------------------------------------------- + +void v3021_device::device_validity_check(validity_checker &valid) const +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void v3021_device::device_start() +{ + /* let's call the timer callback every second */ + machine().scheduler().timer_pulse(attotime::from_hz(clock() / XTAL_32_768kHz), FUNC(rtc_inc_callback), 0, (void *)this); + + system_time systime; + machine().base_datetime(systime); + + m_rtc.day = ((systime.local_time.mday / 10)<<4) | ((systime.local_time.mday % 10) & 0xf); + m_rtc.month = (((systime.local_time.month+1) / 10) << 4) | (((systime.local_time.month+1) % 10) & 0xf); + m_rtc.wday = 1 << systime.local_time.weekday; + m_rtc.year = (((systime.local_time.year % 100)/10)<<4) | ((systime.local_time.year % 10) & 0xf); + m_rtc.hour = ((systime.local_time.hour / 10)<<4) | ((systime.local_time.hour % 10) & 0xf); + m_rtc.min = ((systime.local_time.minute / 10)<<4) | ((systime.local_time.minute % 10) & 0xf); + m_rtc.sec = ((systime.local_time.second / 10)<<4) | ((systime.local_time.second % 10) & 0xf); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void v3021_device::device_reset() +{ + m_cal_cnt = 0; +} + + +//************************************************************************** +// READ/WRITE HANDLERS +//************************************************************************** + +READ8_MEMBER( v3021_device::read ) +{ + UINT8 calr = (m_cal_val & m_cal_mask) ? 1 : 0; + + m_cal_mask <<= 1; + return calr; +} + +WRITE8_MEMBER( v3021_device::write ) +{ + m_cal_com <<= 1; + m_cal_com |= data & 1; + ++m_cal_cnt; + + if (m_cal_cnt == 4) + { + m_cal_mask = 1; + m_cal_val = 1; + m_cal_cnt = 0; + + switch (m_cal_com & 0xf) + { + case 1: case 3: case 5: case 7: case 9: case 0xb: case 0xd: + m_cal_val++; + break; + + case 0: + m_cal_val = (m_rtc.wday); //?? + break; + + case 2: //Hours + m_cal_val = (m_rtc.hour); + break; + + case 4: //Seconds + m_cal_val = (m_rtc.sec); + break; + + case 6: //Month + m_cal_val = (m_rtc.month); //?? not bcd in MVS + break; + + case 8: + m_cal_val = 0; //Controls blinking speed, maybe milliseconds + break; + + case 0xa: //Day + m_cal_val = (m_rtc.day); + break; + + case 0xc: //Minute + m_cal_val = (m_rtc.min); + break; + + case 0xe: //Year + m_cal_val = (m_rtc.year % 100); + break; + + case 0xf: //Load Date + //space.machine().base_datetime(m_systime); + break; + } + } +} diff --git a/src/devices/machine/v3021.h b/src/devices/machine/v3021.h new file mode 100644 index 00000000000..3dd1c709d1e --- /dev/null +++ b/src/devices/machine/v3021.h @@ -0,0 +1,78 @@ +// license:BSD-3-Clause +// copyright-holders:Angelo Salese +/*************************************************************************** + + v3021.h + + EM Microelectronic-Marin SA Ultra Low Power 32kHz CMOS RTC (DIP8) + + Serial Real Time Clock + +***************************************************************************/ + +#pragma once + +#ifndef __v3021DEV_H__ +#define __v3021DEV_H__ + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_V3021_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, v3021, XTAL_32_768kHz) + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +struct rtc_regs_t +{ + UINT8 sec, min, hour, day, wday, month, year; +}; + + +// ======================> v3021_device + +class v3021_device : public device_t +{ +public: + // construction/destruction + v3021_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // I/O operations + DECLARE_WRITE8_MEMBER( write ); + DECLARE_READ8_MEMBER( read ); + void timer_callback(); + +protected: + // device-level overrides + virtual void device_validity_check(validity_checker &valid) const; + virtual void device_start(); + virtual void device_reset(); + + inline UINT8 rtc_read(UINT8 offset); + inline void rtc_write(UINT8 offset,UINT8 data); + + static TIMER_CALLBACK( rtc_inc_callback ); + + UINT8 m_cal_mask,m_cal_com,m_cal_cnt,m_cal_val; + + rtc_regs_t m_rtc; +}; + + +// device type definition +extern const device_type v3021; + + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + + + +#endif diff --git a/src/devices/machine/vrc4373.c b/src/devices/machine/vrc4373.c new file mode 100644 index 00000000000..860b7ff601a --- /dev/null +++ b/src/devices/machine/vrc4373.c @@ -0,0 +1,432 @@ +// license:BSD-3-Clause +// copyright-holders:Ted Green +#include "vrc4373.h" + +#define LOG_NILE (0) +#define LOG_NILE_MASTER (0) +#define LOG_NILE_TARGET (0) + +const device_type VRC4373 = &device_creator; + +DEVICE_ADDRESS_MAP_START(config_map, 32, vrc4373_device) + AM_RANGE(0x40, 0x43) AM_READWRITE (pcictrl_r, pcictrl_w) + AM_INHERIT_FROM(pci_host_device::config_map) +ADDRESS_MAP_END + +// cpu i/f map +DEVICE_ADDRESS_MAP_START(cpu_map, 32, vrc4373_device) + AM_RANGE(0x00000000, 0x0000007b) AM_READWRITE( cpu_if_r, cpu_if_w) +ADDRESS_MAP_END + +// Target Window 1 map +DEVICE_ADDRESS_MAP_START(target1_map, 32, vrc4373_device) + AM_RANGE(0x00000000, 0xFFFFFFFF) AM_READWRITE( target1_r, target1_w) +ADDRESS_MAP_END + +// Target Window 2 map +DEVICE_ADDRESS_MAP_START(target2_map, 32, vrc4373_device) + AM_RANGE(0x00000000, 0xFFFFFFFF) AM_READWRITE( target2_r, target2_w) +ADDRESS_MAP_END + +vrc4373_device::vrc4373_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : pci_host_device(mconfig, VRC4373, "NEC VRC4373 System Controller", tag, owner, clock, "vrc4373", __FILE__), + m_mem_config("memory_space", ENDIANNESS_LITTLE, 32, 32), + m_io_config("io_space", ENDIANNESS_LITTLE, 32, 32) + +{ +} + +const address_space_config *vrc4373_device::memory_space_config(address_spacenum spacenum) const +{ + return (spacenum == AS_PROGRAM) ? pci_bridge_device::memory_space_config(spacenum) : (spacenum == AS_DATA) ? &m_mem_config : (spacenum == AS_IO) ? &m_io_config : NULL; +} + +void vrc4373_device::device_start() +{ + pci_host_device::device_start(); + m_cpu = machine().device(cpu_tag); + m_cpu_space = &m_cpu->space(AS_PROGRAM); + memory_space = &space(AS_DATA); + io_space = &space(AS_IO); + + memset(m_cpu_regs, 0, sizeof(m_cpu_regs)); + + memory_window_start = 0; + memory_window_end = 0xffffffff; + memory_offset = 0; + io_window_start = 0; + io_window_end = 0xffffffff; + io_offset = 0x00000000; + status = 0x0280; + m_ram_size = 1<<22; + m_ram_base = 0; + m_simm_size = 1<<21; + m_simm_base = 0; + + // ROM size = 1 MB + m_cpu_space->install_rom (0x1fc00000, 0x1fcfffff, m_region->base()); + m_cpu_space->install_device(0x0f000000, 0x0f0000ff, *static_cast(this), &vrc4373_device::cpu_map); + // PCI Configuration also mapped at 0x0f000100 + m_cpu_space->install_device(0x0f000100, 0x0f0001ff, *static_cast(this), &vrc4373_device::config_map); + + // MIPS drc + m_cpu->add_fastram(0x1fc00000, 0x1fcfffff, TRUE, m_region->base()); +} + +void vrc4373_device::device_reset() +{ + pci_device::device_reset(); + memset(m_cpu_regs, 0, sizeof(m_cpu_regs)); + regenerate_config_mapping(); +} + +void vrc4373_device::map_cpu_space() +{ + UINT32 winStart, winEnd, winSize; + + // VRC4373 is at 0x0f000000 to 0x0f0001ff + // ROM region starts at 0x1f000000 + m_cpu_space->unmap_readwrite(0x00000000, 0x0effffff); + m_cpu_space->unmap_readwrite(0x0f000200, 0x1effffff); + + // Clear fastram regions in cpu after rom + m_cpu->clear_fastram(1); + + if (m_cpu_regs[NREG_BMCR]&0x8) { + m_cpu_space->install_ram(m_ram_base, m_ram_base+m_ram_size-1, &m_ram[0]); + m_cpu->add_fastram(m_ram_base, m_ram_size-1, FALSE, &m_ram[0]); + if (LOG_NILE) + logerror("%s: map_cpu_space ram_size=%08X ram_base=%08X\n", tag(),m_ram_size,m_ram_base); + } + if (m_cpu_regs[NREG_SIMM1]&0x8) { + m_cpu_space->install_ram(m_simm_base, m_simm_base+m_simm_size-1, &m_simm[0]); + //m_cpu->add_fastram(m_simm_base, m_simm_size-1, FALSE, &m_simm[0]); + if (LOG_NILE) + logerror("%s: map_cpu_space simm_size=%08X simm_base=%08X\n", tag(),m_simm_size,m_simm_base); + } + + // PCI Master Window 1 + if (m_cpu_regs[NREG_PCIMW1]&0x1000) { + winStart = m_cpu_regs[NREG_PCIMW1]&0xff000000; + winEnd = winStart | (~(0x80000000 | (((m_cpu_regs[NREG_PCIMW1]>>13)&0x7f)<<24))); + winSize = winEnd - winStart + 1; + m_cpu_space->install_read_handler(winStart, winEnd, 0, 0, read32_delegate(FUNC(vrc4373_device::master1_r), this)); + m_cpu_space->install_write_handler(winStart, winEnd, 0, 0, write32_delegate(FUNC(vrc4373_device::master1_w), this)); + if (LOG_NILE) + logerror("%s: map_cpu_space Master Window 1 start=%08X end=%08X size=%08X laddr=%08X\n", tag(), winStart, winEnd, winSize, m_pci1_laddr); + } + // PCI Master Window 2 + if (m_cpu_regs[NREG_PCIMW2]&0x1000) { + winStart = m_cpu_regs[NREG_PCIMW2]&0xff000000; + winEnd = winStart | (~(0x80000000 | (((m_cpu_regs[NREG_PCIMW2]>>13)&0x7f)<<24))); + winSize = winEnd - winStart + 1; + m_cpu_space->install_read_handler(winStart, winEnd, 0, 0, read32_delegate(FUNC(vrc4373_device::master2_r), this)); + m_cpu_space->install_write_handler(winStart, winEnd, 0, 0, write32_delegate(FUNC(vrc4373_device::master2_w), this)); + if (LOG_NILE) + logerror("%s: map_cpu_space Master Window 2 start=%08X end=%08X size=%08X laddr=%08X\n", tag(), winStart, winEnd, winSize, m_pci2_laddr); + } + // PCI IO Window + if (m_cpu_regs[NREG_PCIMIOW]&0x1000) { + winStart = m_cpu_regs[NREG_PCIMIOW]&0xff000000; + winEnd = winStart | (~(0x80000000 | (((m_cpu_regs[NREG_PCIMIOW]>>13)&0x7f)<<24))); + winSize = winEnd - winStart + 1; + m_cpu_space->install_read_handler(winStart, winEnd, 0, 0, read32_delegate(FUNC(vrc4373_device::master_io_r), this)); + m_cpu_space->install_write_handler(winStart, winEnd, 0, 0, write32_delegate(FUNC(vrc4373_device::master_io_w), this)); + if (LOG_NILE) + logerror("%s: map_cpu_space IO Window start=%08X end=%08X size=%08X laddr=%08X\n", tag(), winStart, winEnd, winSize, m_pci_io_laddr); + } +} + +void vrc4373_device::map_extra(UINT64 memory_window_start, UINT64 memory_window_end, UINT64 memory_offset, address_space *memory_space, + UINT64 io_window_start, UINT64 io_window_end, UINT64 io_offset, address_space *io_space) +{ + UINT32 winStart, winEnd, winSize; + + // PCI Target Window 1 + if (m_cpu_regs[NREG_PCITW1]&0x1000) { + winStart = m_cpu_regs[NREG_PCITW1]&0xffe00000; + winEnd = winStart | (~(0xf0000000 | (((m_cpu_regs[NREG_PCITW1]>>13)&0x7f)<<21))); + winSize = winEnd - winStart + 1; + memory_space->install_read_handler(winStart, winEnd, 0, 0, read32_delegate(FUNC(vrc4373_device::target1_r), this)); + memory_space->install_write_handler(winStart, winEnd, 0, 0, write32_delegate(FUNC(vrc4373_device::target1_w), this)); + if (LOG_NILE) + logerror("%s: map_extra Target Window 1 start=%08X end=%08X size=%08X laddr=%08X\n", tag(), winStart, winEnd, winSize, m_target1_laddr); + } + // PCI Target Window 2 + if (m_cpu_regs[NREG_PCITW2]&0x1000) { + winStart = m_cpu_regs[NREG_PCITW2]&0xffe00000; + winEnd = winStart | (~(0xf0000000 | (((m_cpu_regs[NREG_PCITW2]>>13)&0x7f)<<21))); + winSize = winEnd - winStart + 1; + memory_space->install_read_handler(winStart, winEnd, 0, 0, read32_delegate(FUNC(vrc4373_device::target2_r), this)); + memory_space->install_write_handler(winStart, winEnd, 0, 0, write32_delegate(FUNC(vrc4373_device::target2_w), this)); + if (LOG_NILE) + logerror("%s: map_extra Target Window 2 start=%08X end=%08X size=%08X laddr=%08X\n", tag(), winStart, winEnd, winSize, m_target2_laddr); + } +} + +void vrc4373_device::reset_all_mappings() +{ + pci_device::reset_all_mappings(); +} + +void vrc4373_device::set_cpu_tag(const char *_cpu_tag) +{ + if (LOG_NILE) + logerror("%s: set_cpu_tag\n", tag()); + cpu_tag = _cpu_tag; +} +// PCI bus control +READ32_MEMBER (vrc4373_device::pcictrl_r) +{ + UINT32 result = 0; + if (LOG_NILE) + logerror("%06X:nile pcictrl_r from offset %02X = %08X & %08X\n", space.device().safe_pc(), offset*4, result, mem_mask); + return result; +} +WRITE32_MEMBER (vrc4373_device::pcictrl_w) +{ + if (LOG_NILE) + logerror("%06X:nile pcictrl_w to offset %02X = %08X & %08X\n", space.device().safe_pc(), offset*4, data, mem_mask); +} +// PCI Master Window 1 +READ32_MEMBER (vrc4373_device::master1_r) +{ + UINT32 result = this->space(AS_DATA).read_dword(m_pci1_laddr | (offset*4), mem_mask); + if (LOG_NILE_MASTER) + logerror("%06X:nile master1 read from offset %02X = %08X & %08X\n", space.device().safe_pc(), offset*4, result, mem_mask); + return result; +} +WRITE32_MEMBER (vrc4373_device::master1_w) +{ + this->space(AS_DATA).write_dword(m_pci1_laddr | (offset*4), data, mem_mask); + if (LOG_NILE_MASTER) + logerror("%06X:nile master1 write to offset %02X = %08X & %08X\n", space.device().safe_pc(), offset*4, data, mem_mask); +} + +// PCI Master Window 2 +READ32_MEMBER (vrc4373_device::master2_r) +{ + UINT32 result = this->space(AS_DATA).read_dword(m_pci2_laddr | (offset*4), mem_mask); + if (LOG_NILE_MASTER) + logerror("%06X:nile master2 read from offset %02X = %08X & %08X\n", space.device().safe_pc(), offset*4, result, mem_mask); + return result; +} +WRITE32_MEMBER (vrc4373_device::master2_w) +{ + this->space(AS_DATA).write_dword(m_pci2_laddr | (offset*4), data, mem_mask); + if (LOG_NILE_MASTER) + logerror("%06X:nile master2 write to offset %02X = %08X & %08X\n", space.device().safe_pc(), offset*4, data, mem_mask); +} + +// PCI Master IO Window +READ32_MEMBER (vrc4373_device::master_io_r) +{ + UINT32 result = this->space(AS_IO).read_dword(m_pci_io_laddr | (offset*4), mem_mask); + if (LOG_NILE_MASTER) + logerror("%06X:nile master io read from offset %02X = %08X & %08X\n", space.device().safe_pc(), offset*4, result, mem_mask); + return result; +} +WRITE32_MEMBER (vrc4373_device::master_io_w) +{ + this->space(AS_IO).write_dword(m_pci_io_laddr | (offset*4), data, mem_mask); + if (LOG_NILE_MASTER) + logerror("%06X:nile master io write to offset %02X = %08X & %08X\n", space.device().safe_pc(), offset*4, data, mem_mask); +} + +// PCI Target Window 1 +READ32_MEMBER (vrc4373_device::target1_r) +{ + UINT32 result = m_cpu->space(AS_PROGRAM).read_dword(m_target1_laddr | (offset*4), mem_mask); + if (LOG_NILE_TARGET) + logerror("%08X:nile target1 read from offset %02X = %08X & %08X\n", m_cpu->device_t::safe_pc(), offset*4, result, mem_mask); + return result; +} +WRITE32_MEMBER (vrc4373_device::target1_w) +{ + m_cpu->space(AS_PROGRAM).write_dword(m_target1_laddr | (offset*4), data, mem_mask); + if (LOG_NILE_TARGET) + logerror("%08X:nile target1 write to offset %02X = %08X & %08X\n", m_cpu->device_t::safe_pc(), offset*4, data, mem_mask); +} + +// PCI Target Window 2 +READ32_MEMBER (vrc4373_device::target2_r) +{ + UINT32 result = m_cpu->space(AS_PROGRAM).read_dword(m_target2_laddr | (offset*4), mem_mask); + if (LOG_NILE_TARGET) + logerror("%08X:nile target2 read from offset %02X = %08X & %08X\n", m_cpu->device_t::safe_pc(), offset*4, result, mem_mask); + return result; +} +WRITE32_MEMBER (vrc4373_device::target2_w) +{ + m_cpu->space(AS_PROGRAM).write_dword(m_target2_laddr | (offset*4), data, mem_mask); + if (LOG_NILE_TARGET) + logerror("%08X:nile target2 write to offset %02X = %08X & %08X\n", m_cpu->device_t::safe_pc(), offset*4, data, mem_mask); +} + +// DMA Transfer +void vrc4373_device::dma_transfer(int which) +{ + if (LOG_NILE) + logerror("%08X:nile Start dma PCI: %08X MEM: %08X Words: %X\n", m_cpu->space(AS_PROGRAM).device().safe_pc(), m_cpu_regs[NREG_DMA_CPAR], m_cpu_regs[NREG_DMA_CMAR], m_cpu_regs[NREG_DMA_REM]); + int pciSel = (m_cpu_regs[NREG_DMACR1+which*0xC] & DMA_MIO) ? AS_DATA : AS_IO; + address_space *src, *dst; + UINT32 srcAddr, dstAddr; + + if (m_cpu_regs[NREG_DMACR1+which*0xC]&DMA_RW) { + // Read data from PCI and write to cpu + src = &this->space(pciSel); + dst = &m_cpu->space(AS_PROGRAM); + srcAddr = m_cpu_regs[NREG_DMA_CPAR]; + dstAddr = m_cpu_regs[NREG_DMA_CMAR]; + } else { + // Read data from cpu and write to PCI + src = &m_cpu->space(AS_PROGRAM); + dst = &this->space(pciSel); + srcAddr = m_cpu_regs[NREG_DMA_CMAR]; + dstAddr = m_cpu_regs[NREG_DMA_CPAR]; + } + int count = m_cpu_regs[NREG_DMA_REM]; + while (count>0) { + dst->write_dword(dstAddr, src->read_dword(srcAddr)); + dstAddr += 0x4; + srcAddr += 0x4; + --count; + } + if (m_cpu_regs[NREG_DMACR1+which*0xC]&DMA_RW) { + m_cpu_regs[NREG_DMA_CPAR] = srcAddr; + m_cpu_regs[NREG_DMA_CMAR] = dstAddr; + } else { + m_cpu_regs[NREG_DMA_CMAR] = srcAddr; + m_cpu_regs[NREG_DMA_CPAR] = dstAddr; + } + m_cpu_regs[NREG_DMA_REM] = 0; +} + +// CPU I/F +READ32_MEMBER (vrc4373_device::cpu_if_r) +{ + UINT32 result = m_cpu_regs[offset]; + switch (offset) { + case NREG_PCICAR: + result = config_address_r(space, offset); + break; + case NREG_PCICDR: + result = config_data_r(space, offset); + break; + case NREG_DMACR1: + case NREG_DMACR2: + // Clear busy and go on read + if (m_cpu_regs[NREG_DMA_REM]==0) { + int which = (offset-NREG_DMACR1)>>3; + m_cpu_regs[NREG_DMACR1+which*0xc] &= ~DMA_BUSY; + m_cpu_regs[NREG_DMACR1+which*0xc] &= ~DMA_GO; + } + break; + default: + break; + } + if (LOG_NILE) + logerror("%06X:nile read from offset %02X = %08X & %08X\n", space.device().safe_pc(), offset*4, result, mem_mask); + return result; +} + +WRITE32_MEMBER(vrc4373_device::cpu_if_w) +{ + if (LOG_NILE) + logerror("%06X:nile write to offset %02X = %08X & %08X\n", space.device().safe_pc(), offset*4, data, mem_mask); + + UINT32 modData, oldData; + oldData = m_cpu_regs[offset]; + COMBINE_DATA(&m_cpu_regs[offset]); + switch (offset) { + case NREG_PCIMW1: + m_pci1_laddr = (data&0xff)<<24; + map_cpu_space(); + break; + case NREG_PCIMW2: + m_pci2_laddr = (data&0xff)<<24; + map_cpu_space(); + break; + case NREG_PCIMIOW: + m_pci_io_laddr = (data&0xff)<<24; + map_cpu_space(); + break; + case NREG_PCITW1: + m_target1_laddr = 0x00000000 | ((data&0x7FF)<<21); + remap_cb(); + break; + case NREG_PCITW2: + m_target2_laddr = 0x00000000 | ((data&0x7FF)<<21); + remap_cb(); + break; + case NREG_PCICAR: + // Bits in reserved area are used for device selection of type 0 config transactions + // Assuming 23:11 get mapped into device number for configuration + if ((data&0x3) == 0x0) { + // Type 0 transaction + modData = 0; + // Select the device based on one hot bit + for (int i=11; i<24; i++) { + if ((data>>i)&0x1) { + // One hot encoding, bit 11 will mean device 1 + modData = i-10; + break; + } + } + // Re-organize into Type 1 transaction for bus 0 (local bus) + modData = (modData<<11) | (data&0x7ff) | (0x80000000); + } else { + // Type 1 transaction, no modification needed + modData = data; + } + pci_host_device::config_address_w(space, offset, modData); + break; + case NREG_PCICDR: + pci_host_device::config_data_w(space, offset, data); + break; + case NREG_DMACR1: + case NREG_DMACR2: + // Start when DMA_GO bit is set + if (!(oldData & DMA_GO) && (data & DMA_GO)) { + int which = (offset-NREG_DMACR1)>>3; + // Check to see DMA is not already started + if (!(data&DMA_BUSY)) { + // Set counts and address + m_cpu_regs[NREG_DMA_CPAR] = m_cpu_regs[NREG_DMAPCI1+which*0xC]; + m_cpu_regs[NREG_DMA_CMAR] = m_cpu_regs[NREG_DMAMAR1+which*0xC]; + m_cpu_regs[NREG_DMA_REM] = (data & DMA_BLK_SIZE)>>2; + m_cpu_regs[NREG_DMACR1+which*0xc] |= DMA_BUSY; + // Start the transfer + dma_transfer(which); + } + } + break; + case NREG_BMCR: + if ((data>>3)&0x1) { + m_ram_size = 1<<22; // 4MB + for (int i=14; i<=15; i++) { + if (!((data>>i)&0x1)) m_ram_size<<=1; + else break; + } + m_ram.resize(m_ram_size/4); + m_ram_base = (data & 0x0fc00000); + } + map_cpu_space(); + break; + case NREG_SIMM1: + if ((data>>3)&0x1) { + m_simm_size = 1<<21; // 2MB + for (int i=13; i<=17; i++) { + if (!((data>>i)&0x1)) m_simm_size<<=1; + else break; + } + m_simm.resize(m_simm_size/4); + m_simm_base = (data & 0x0fe00000); + } + map_cpu_space(); + break; + default: + break; + } + +} diff --git a/src/devices/machine/vrc4373.h b/src/devices/machine/vrc4373.h new file mode 100644 index 00000000000..31439b58537 --- /dev/null +++ b/src/devices/machine/vrc4373.h @@ -0,0 +1,132 @@ +// license:BSD-3-Clause +// copyright-holders:Ted Green +// NEC VRC 4373 System Controller + +#ifndef VRC4373_H +#define VRC4373_H + +#include "pci.h" +#include "cpu/mips/mips3.h" + +#define MCFG_VRC4373_ADD(_tag, _cpu_tag) \ + MCFG_PCI_HOST_ADD(_tag, VRC4373, 0x005B1033, 0x00, 0x00000000) \ + downcast(device)->set_cpu_tag(_cpu_tag); + +#define VRC4373_PAGESHIFT 12 + +/* NILE 3 registers 0x000-0x0ff */ +#define NREG_BMCR (0x000/4) +#define NREG_SIMM1 (0x004/4) +#define NREG_SIMM2 (0x008/4) +#define NREG_SIMM3 (0x00C/4) +#define NREG_SIMM4 (0x010/4) +#define NREG_PCIMW1 (0x014/4) +#define NREG_PCIMW2 (0x018/4) +#define NREG_PCITW1 (0x01C/4) +#define NREG_PCITW2 (0x020/4) +#define NREG_PCIMIOW (0x024/4) +#define NREG_PCICDR (0x028/4) +#define NREG_PCICAR (0x02C/4) +#define NREG_PCIMB1 (0x030/4) +#define NREG_PCIMB2 (0x034/4) +#define NREG_DMACR1 (0x038/4) +#define NREG_DMAMAR1 (0x03C/4) +#define NREG_DMAPCI1 (0x040/4) +#define NREG_DMACR2 (0x044/4) +#define NREG_DMAMAR2 (0x048/4) +#define NREG_DMAPCI2 (0x04C/4) + +#define NREG_BESR (0x050/4) +#define NREG_ICSR (0x054/4) +#define NREG_DRAMRCR (0x058/4) +#define NREG_BOOTWP (0x05C/4) +#define NREG_PCIEAR (0x060/4) +#define NREG_DMA_REM (0x064/4) +#define NREG_DMA_CMAR (0x068/4) +#define NREG_DMA_CPAR (0x06C/4) +#define NREG_PCIRC (0x070/4) +#define NREG_PCIEN (0x074/4) +#define NREG_PMIR (0x078/4) + +#define DMA_BUSY 0x80000000 +#define DMA_INT_EN 0x40000000 +#define DMA_RW 0x20000000 +#define DMA_GO 0x10000000 +#define DMA_SUS 0x08000000 +#define DMA_INC 0x04000000 +#define DMA_MIO 0x02000000 +#define DMA_RST 0x01000000 +#define DMA_BLK_SIZE 0x000fffff + + +class vrc4373_device : public pci_host_device { +public: + vrc4373_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual void reset_all_mappings(); + virtual void map_extra(UINT64 memory_window_start, UINT64 memory_window_end, UINT64 memory_offset, address_space *memory_space, + UINT64 io_window_start, UINT64 io_window_end, UINT64 io_offset, address_space *io_space); + + void set_cpu_tag(const char *tag); + + virtual DECLARE_ADDRESS_MAP(config_map, 32); + + DECLARE_READ32_MEMBER( pcictrl_r); + DECLARE_WRITE32_MEMBER( pcictrl_w); + //cpu bus registers + DECLARE_READ32_MEMBER (cpu_if_r); + DECLARE_WRITE32_MEMBER(cpu_if_w); + + DECLARE_READ32_MEMBER (master1_r); + DECLARE_WRITE32_MEMBER(master1_w); + + DECLARE_READ32_MEMBER (master2_r); + DECLARE_WRITE32_MEMBER(master2_w); + + DECLARE_READ32_MEMBER (master_io_r); + DECLARE_WRITE32_MEMBER(master_io_w); + + virtual DECLARE_ADDRESS_MAP(target1_map, 32); + DECLARE_READ32_MEMBER (target1_r); + DECLARE_WRITE32_MEMBER(target1_w); + + virtual DECLARE_ADDRESS_MAP(target2_map, 32); + DECLARE_READ32_MEMBER (target2_r); + DECLARE_WRITE32_MEMBER(target2_w); + +protected: + address_space *m_cpu_space; + virtual const address_space_config *memory_space_config(address_spacenum spacenum) const; + virtual void device_start(); + virtual void device_reset(); + void dma_transfer(int which); + +private: + mips3_device *m_cpu; + const char *cpu_tag; + + address_space_config m_mem_config, m_io_config; + + DECLARE_ADDRESS_MAP(cpu_map, 32); + + void map_cpu_space(); + + UINT32 m_ram_size; + UINT32 m_ram_base; + std::vector m_ram; + + UINT32 m_simm_size; + UINT32 m_simm_base; + std::vector m_simm; + + UINT32 m_cpu_regs[0x7c]; + + UINT32 m_pci1_laddr, m_pci2_laddr, m_pci_io_laddr; + UINT32 m_target1_laddr, m_target2_laddr; + +}; + + +extern const device_type VRC4373; + +#endif diff --git a/src/devices/machine/vt83c461.c b/src/devices/machine/vt83c461.c new file mode 100644 index 00000000000..1957b848c9b --- /dev/null +++ b/src/devices/machine/vt83c461.c @@ -0,0 +1,105 @@ +// license:BSD-3-Clause +// copyright-holders:smf +#include "vt83c461.h" + +/*************************************************************************** + DEBUGGING +***************************************************************************/ + +#define VERBOSE 0 + +#define LOG(x) do { if (VERBOSE) logerror x; } while (0) + + +#define VT83C461_CONFIG_UNK 1 +#define VT83C461_CONFIG_REGISTER 2 +#define VT83C461_CONFIG_DATA 3 + + +const device_type VT83C461 = &device_creator; + +vt83c461_device::vt83c461_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + ide_controller_32_device(mconfig, VT83C461, "VIA VT83C461", tag, owner, clock, "vt83c461", __FILE__), + m_config_unknown(0), + m_config_register_num(0) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void vt83c461_device::device_start() +{ + ide_controller_32_device::device_start(); + + /* register ide states */ + save_item(NAME(m_config_unknown)); + save_item(NAME(m_config_register)); + save_item(NAME(m_config_register_num)); +} + +READ32_MEMBER( vt83c461_device::read_config ) +{ + UINT32 result = 0; + + /* logit */ + LOG(("%s:IDE via config read at %X, mem_mask=%d\n", machine().describe_context(), offset, mem_mask)); + + switch(offset) + { + /* unknown config register */ + case VT83C461_CONFIG_UNK: + result = m_config_unknown; + break; + + /* active config register */ + case VT83C461_CONFIG_REGISTER: + result = m_config_register_num; + break; + + /* data from active config register */ + case VT83C461_CONFIG_DATA: + if (m_config_register_num < IDE_CONFIG_REGISTERS) + result = m_config_register[m_config_register_num]; + break; + + default: + logerror("%s:unknown IDE via config read at %03X, mem_mask=%d\n", machine().describe_context(), offset, mem_mask); + break; + } + +// printf( "vt83c461 read config %04x %08x %04x\n", offset, result, mem_mask ); + return result; +} + +WRITE32_MEMBER( vt83c461_device::write_config ) +{ +// printf( "vt83c461 write config %04x %08x %04x\n", offset, data, mem_mask ); + + /* logit */ + LOG(("%s:IDE via config write to %X = %08X, mem_mask=%d\n", machine().describe_context(), offset, data, mem_mask)); + + switch (offset) + { + /* unknown config register */ + case VT83C461_CONFIG_UNK: + m_config_unknown = data; + break; + + /* active config register */ + case VT83C461_CONFIG_REGISTER: + m_config_register_num = data; + break; + + /* data from active config register */ + case VT83C461_CONFIG_DATA: + if (m_config_register_num < IDE_CONFIG_REGISTERS) + m_config_register[m_config_register_num] = data; + break; + + default: + logerror("%s:unknown IDE via config write at %03X = %08x, mem_mask=%d\n", machine().describe_context(), offset, data, mem_mask); + break; + } +} diff --git a/src/devices/machine/vt83c461.h b/src/devices/machine/vt83c461.h new file mode 100644 index 00000000000..18e737ed29b --- /dev/null +++ b/src/devices/machine/vt83c461.h @@ -0,0 +1,51 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/*************************************************************************** + + vt83c461.h + + VIA VT83C461 (IDE Hard Drive controller). + +***************************************************************************/ + +#pragma once + +#ifndef __VT83C461_H__ +#define __VT83C461_H__ + +#include "idectrl.h" + +/*************************************************************************** + DEVICE CONFIGURATION MACROS +***************************************************************************/ + +#define MCFG_VT83C461_ADD(_tag, _slot_intf, _master, _slave, _fixed) \ + MCFG_DEVICE_ADD(_tag, VT83C461, 0) \ + MCFG_DEVICE_MODIFY(_tag ":0") \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _master, _fixed) \ + MCFG_DEVICE_MODIFY(_tag ":1") \ + MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _slave, _fixed) \ + MCFG_DEVICE_MODIFY(_tag) + +#define IDE_CONFIG_REGISTERS 0x10 + +class vt83c461_device : public ide_controller_32_device +{ +public: + vt83c461_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + DECLARE_READ32_MEMBER(read_config); + DECLARE_WRITE32_MEMBER(write_config); + +protected: + virtual void device_start(); + +private: + UINT8 m_config_unknown; + UINT8 m_config_register[IDE_CONFIG_REGISTERS]; + UINT8 m_config_register_num; +}; + +extern const device_type VT83C461; + +#endif diff --git a/src/devices/machine/wd11c00_17.c b/src/devices/machine/wd11c00_17.c new file mode 100644 index 00000000000..0f38c32c624 --- /dev/null +++ b/src/devices/machine/wd11c00_17.c @@ -0,0 +1,474 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Western Digital WD11C00-17 PC/XT Host Interface Logic Device + +**********************************************************************/ + +#include "machine/wd11c00_17.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define LOG 1 + + +// status register +#define STATUS_IRQ 0x20 +#define STATUS_DRQ 0x10 +#define STATUS_BUSY 0x08 +#define STATUS_C_D 0x04 +#define STATUS_I_O 0x02 +#define STATUS_REQ 0x01 + + +// mask register +#define MASK_IRQ 0x02 +#define MASK_DMA 0x01 + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type WD11C00_17 = &device_creator; + + +//************************************************************************** +// INLINE HELPERS +//************************************************************************** + +//------------------------------------------------- +// check_interrupt - +//------------------------------------------------- + +inline void wd11c00_17_device::check_interrupt() +{ + if (BIT(m_ra, 10)) + { + m_status &= ~STATUS_DRQ; + } + + int ra3 = BIT(m_ra, 3); + + if (m_ra3 != ra3) + { + m_out_ra3_cb(ra3 ? ASSERT_LINE : CLEAR_LINE); + m_ra3 = ra3; + } + + int irq5 = ((m_status & STATUS_IRQ) && (m_mask & MASK_IRQ)) ? ASSERT_LINE : CLEAR_LINE; + + if (m_irq5 != irq5) + { + m_out_irq5_cb(irq5); + m_irq5 = irq5; + } + + int drq3 = ((m_status & STATUS_DRQ) && (m_mask & MASK_DMA)) ? ASSERT_LINE : CLEAR_LINE; + + if (m_drq3 != drq3) + { + m_out_drq3_cb(drq3); + m_drq3 = drq3; + } + + int busy = (m_status & STATUS_BUSY) ? 0 : 1; + + if (m_busy != busy) + { + m_out_busy_cb(busy); + m_busy = busy; + } + + int req = (m_status & STATUS_REQ) ? 1 : 0; + + if (m_req != req) + { + m_out_req_cb(req); + m_req = req; + } +} + + +//------------------------------------------------- +// increment_address - +//------------------------------------------------- + +inline void wd11c00_17_device::increment_address() +{ + m_ra++; + check_interrupt(); +} + + +//------------------------------------------------- +// read_data - +//------------------------------------------------- + +inline UINT8 wd11c00_17_device::read_data() +{ + UINT8 data = 0; + + if (m_status & STATUS_BUSY) + { + data = m_in_ramcs_cb(m_ra & 0x7ff); + + increment_address(); + } + + return data; +} + + +//------------------------------------------------- +// write_data - +//------------------------------------------------- + +inline void wd11c00_17_device::write_data(UINT8 data) +{ + if (m_status & STATUS_BUSY) + { + m_out_ramwr_cb(m_ra & 0x7ff, data); + + increment_address(); + } +} + + +//------------------------------------------------- +// software_reset - +//------------------------------------------------- + +inline void wd11c00_17_device::software_reset() +{ + m_out_mr_cb(ASSERT_LINE); + m_out_mr_cb(CLEAR_LINE); + + device_reset(); +} + + +//------------------------------------------------- +// select - +//------------------------------------------------- + +inline void wd11c00_17_device::select() +{ + m_status = STATUS_BUSY | STATUS_C_D | STATUS_REQ; + + check_interrupt(); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// wd11c00_17_device - constructor +//------------------------------------------------- + +wd11c00_17_device::wd11c00_17_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, WD11C00_17, "Western Digital WD11C00-17", tag, owner, clock, "wd11c00_17", __FILE__), + m_out_irq5_cb(*this), + m_out_drq3_cb(*this), + m_out_mr_cb(*this), + m_out_busy_cb(*this), + m_out_req_cb(*this), + m_out_ra3_cb(*this), + m_in_rd322_cb(*this), + m_in_ramcs_cb(*this), + m_out_ramwr_cb(*this), + m_in_cs1010_cb(*this), + m_out_cs1010_cb(*this), + m_status(0), + m_ra(0), + m_irq5(CLEAR_LINE), + m_drq3(CLEAR_LINE), + m_busy(1), + m_req(0), + m_ra3(0) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void wd11c00_17_device::device_start() +{ + // resolve callbacks + m_out_irq5_cb.resolve_safe(); + m_out_drq3_cb.resolve_safe(); + m_out_mr_cb.resolve_safe(); + m_out_busy_cb.resolve_safe(); + m_out_req_cb.resolve_safe(); + m_out_ra3_cb.resolve_safe(); + m_in_rd322_cb.resolve_safe(0); + m_in_ramcs_cb.resolve_safe(0); + m_out_ramwr_cb.resolve_safe(); + m_in_cs1010_cb.resolve_safe(0); + m_out_cs1010_cb.resolve_safe(); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void wd11c00_17_device::device_reset() +{ + m_status &= ~(STATUS_IRQ | STATUS_DRQ | STATUS_BUSY); + m_mask = 0; + m_ra = 0; + + check_interrupt(); +} + + +//------------------------------------------------- +// io_r - +//------------------------------------------------- + +READ8_MEMBER( wd11c00_17_device::io_r ) +{ + UINT8 data = 0xff; + + switch (offset) + { + case 0: // Read Data, Board to Host + if (LOG) logerror("%s WD11C00-17 '%s' Read Data %03x:", machine().describe_context(), tag(), m_ra); + data = read_data(); + if (LOG) logerror("%02x\n", data); + break; + + case 1: // Read Board Hardware Status + data = m_status; + check_interrupt(); + break; + + case 2: // Read Drive Configuration Information + data = m_in_rd322_cb(0); + break; + + case 3: // Not Used + break; + } + + return data; +} + + +//------------------------------------------------- +// io_w - +//------------------------------------------------- + +WRITE8_MEMBER( wd11c00_17_device::io_w ) +{ + switch (offset) + { + case 0: // Write Data, Host to Board + if (LOG) logerror("%s WD11C00-17 '%s' Write Data %03x:%02x\n", machine().describe_context(), tag(), m_ra, data); + write_data(data); + break; + + case 1: // Board Software Reset + if (LOG) logerror("%s WD11C00-17 '%s' Software Reset\n", machine().describe_context(), tag()); + software_reset(); + break; + + case 2: // Board Select + if (LOG) logerror("%s WD11C00-17 '%s' Select\n", machine().describe_context(), tag()); + increment_address(); // HACK + select(); + break; + + case 3: // Set/Reset DMA, IRQ Masks + if (LOG) logerror("%s WD11C00-17 '%s' Mask IRQ %u DMA %u\n", machine().describe_context(), tag(), BIT(data, 1), BIT(data, 0)); + m_mask = data; + check_interrupt(); + break; + } +} + + +//------------------------------------------------- +// dack_r - +//------------------------------------------------- + +UINT8 wd11c00_17_device::dack_r() +{ + return read_data(); +} + + +//------------------------------------------------- +// dack_w - +//------------------------------------------------- + +void wd11c00_17_device::dack_w(UINT8 data) +{ + write_data(data); +} + + +//------------------------------------------------- +// read - +//------------------------------------------------- + +READ8_MEMBER( wd11c00_17_device::read ) +{ + UINT8 data = 0; + + switch (offset) + { + case 0x00: + if (LOG) logerror("%s WD11C00-17 '%s' Read RAM %03x:", machine().describe_context(), tag(), m_ra); + data = read_data(); + if (LOG) logerror("%02x\n", data); + break; + + case 0x20: + data = m_in_cs1010_cb(m_ra >> 8); + break; + } + + return data; +} + + +//------------------------------------------------- +// write - +//------------------------------------------------- + +WRITE8_MEMBER( wd11c00_17_device::write ) +{ + switch (offset) + { + case 0x00: + if (LOG) logerror("%s WD11C00-17 '%s' Write RAM %03x:%02x\n", machine().describe_context(), tag(), m_ra, data); + write_data(data); + if (m_ra > 0x400) m_ecc_not_0 = 0; // HACK + break; + + case 0x20: + m_out_cs1010_cb(m_ra >> 8, data); + break; + + case 0x60: + m_ra = (data & 0x07) << 8; + if (LOG) logerror("%s WD11C00-17 '%s' RA %03x\n", machine().describe_context(), tag(), m_ra); + check_interrupt(); + break; + } +} + + +//------------------------------------------------- +// ireq_w - +//------------------------------------------------- + +WRITE_LINE_MEMBER( wd11c00_17_device::ireq_w ) +{ + if (LOG) logerror("%s WD11C00-17 '%s' IREQ %u\n", machine().describe_context(), tag(), state); + + if (state) m_status |= STATUS_REQ; else m_status &= ~STATUS_REQ; + + if (m_status & STATUS_BUSY) + { + if (state) + { + m_status |= STATUS_IRQ | STATUS_I_O; + } + else + { + if (m_status & STATUS_I_O) + { + m_status &= ~(STATUS_BUSY | STATUS_I_O); + } + } + } + + check_interrupt(); +} + + +//------------------------------------------------- +// io_w - +//------------------------------------------------- + +WRITE_LINE_MEMBER( wd11c00_17_device::io_w ) +{ + if (LOG) logerror("%s WD11C00-17 '%s' I/O %u\n", machine().describe_context(), tag(), state); + + if (state) m_status |= STATUS_I_O; else m_status &= ~STATUS_I_O; +} + + +//------------------------------------------------- +// cd_w - +//------------------------------------------------- + +WRITE_LINE_MEMBER( wd11c00_17_device::cd_w ) +{ + if (LOG) logerror("%s WD11C00-17 '%s' C/D %u\n", machine().describe_context(), tag(), state); + + if (state) m_status |= STATUS_C_D; else m_status &= ~STATUS_C_D; +} + + +//------------------------------------------------- +// clct_w - +//------------------------------------------------- + +WRITE_LINE_MEMBER( wd11c00_17_device::clct_w ) +{ + if (LOG) logerror("%s WD11C00-17 '%s' CLCT %u\n", machine().describe_context(), tag(), state); + + if (state) + { + m_ra &= 0xff00; + check_interrupt(); + } +} + + +//------------------------------------------------- +// mode_w - +//------------------------------------------------- + +WRITE_LINE_MEMBER( wd11c00_17_device::mode_w ) +{ + if (LOG) logerror("%s WD11C00-17 '%s' MODE %u\n", machine().describe_context(), tag(), state); + + m_mode = state; + m_ecc_not_0 = state; // HACK +} + + +//------------------------------------------------- +// busy_r - +//------------------------------------------------- + +READ_LINE_MEMBER( wd11c00_17_device::busy_r ) +{ + return (m_status & STATUS_BUSY) ? 0 : 1; +} + + +//------------------------------------------------- +// ecc_not_0_r - +//------------------------------------------------- + +READ_LINE_MEMBER( wd11c00_17_device::ecc_not_0_r ) +{ + return m_ecc_not_0; +} diff --git a/src/devices/machine/wd11c00_17.h b/src/devices/machine/wd11c00_17.h new file mode 100644 index 00000000000..adc8a9f2c64 --- /dev/null +++ b/src/devices/machine/wd11c00_17.h @@ -0,0 +1,142 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Western Digital WD11C00-17 PC/XT Host Interface Logic Device + +**********************************************************************/ + +#pragma once + +#ifndef __WD11C00_17__ +#define __WD11C00_17__ + + +#include "emu.h" + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_WD11C00_17_OUT_IRQ5_CB(_devcb) \ + devcb = &wd11c00_17_device::set_out_irq5_callback(*device, DEVCB_##_devcb); + +#define MCFG_WD11C00_17_OUT_DRQ3_CB(_devcb) \ + devcb = &wd11c00_17_device::set_out_drq3_callback(*device, DEVCB_##_devcb); + +#define MCFG_WD11C00_17_OUT_MR_CB(_devcb) \ + devcb = &wd11c00_17_device::set_out_mr_callback(*device, DEVCB_##_devcb); + +#define MCFG_WD11C00_17_OUT_BUSY_CB(_devcb) \ + devcb = &wd11c00_17_device::set_out_busy_callback(*device, DEVCB_##_devcb); + +#define MCFG_WD11C00_17_OUT_REQ_CB(_devcb) \ + devcb = &wd11c00_17_device::set_out_req_callback(*device, DEVCB_##_devcb); + +#define MCFG_WD11C00_17_OUT_RA3_CB(_devcb) \ + devcb = &wd11c00_17_device::set_out_ra3_callback(*device, DEVCB_##_devcb); + +#define MCFG_WD11C00_17_IN_RD322_CB(_devcb) \ + devcb = &wd11c00_17_device::set_in_rd322_callback(*device, DEVCB_##_devcb); + +#define MCFG_WD11C00_17_IN_RAMCS_CB(_devcb) \ + devcb = &wd11c00_17_device::set_in_ramcs_callback(*device, DEVCB_##_devcb); + +#define MCFG_WD11C00_17_OUT_RAMWR_CB(_devcb) \ + devcb = &wd11c00_17_device::set_out_ramwr_callback(*device, DEVCB_##_devcb); + +#define MCFG_WD11C00_17_IN_CS1010_CB(_devcb) \ + devcb = &wd11c00_17_device::set_in_cs1010_callback(*device, DEVCB_##_devcb); + +#define MCFG_WD11C00_17_OUT_CS1010_CB(_devcb) \ + devcb = &wd11c00_17_device::set_out_cs1010_callback(*device, DEVCB_##_devcb); + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> wd11c00_17_device + +class wd11c00_17_device : public device_t +{ +public: + // construction/destruction + wd11c00_17_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + template static devcb_base &set_out_irq5_callback(device_t &device, _Object object) { return downcast(device).m_out_irq5_cb.set_callback(object); } + template static devcb_base &set_out_drq3_callback(device_t &device, _Object object) { return downcast(device).m_out_drq3_cb.set_callback(object); } + template static devcb_base &set_out_mr_callback(device_t &device, _Object object) { return downcast(device).m_out_mr_cb.set_callback(object); } + template static devcb_base &set_out_busy_callback(device_t &device, _Object object) { return downcast(device).m_out_busy_cb.set_callback(object); } + template static devcb_base &set_out_req_callback(device_t &device, _Object object) { return downcast(device).m_out_req_cb.set_callback(object); } + template static devcb_base &set_out_ra3_callback(device_t &device, _Object object) { return downcast(device).m_out_ra3_cb.set_callback(object); } + template static devcb_base &set_in_rd322_callback(device_t &device, _Object object) { return downcast(device).m_in_rd322_cb.set_callback(object); } + template static devcb_base &set_in_ramcs_callback(device_t &device, _Object object) { return downcast(device).m_in_ramcs_cb.set_callback(object); } + template static devcb_base &set_out_ramwr_callback(device_t &device, _Object object) { return downcast(device).m_out_ramwr_cb.set_callback(object); } + template static devcb_base &set_in_cs1010_callback(device_t &device, _Object object) { return downcast(device).m_in_cs1010_cb.set_callback(object); } + template static devcb_base &set_out_cs1010_callback(device_t &device, _Object object) { return downcast(device).m_out_cs1010_cb.set_callback(object); } + + DECLARE_READ8_MEMBER( io_r ); + DECLARE_WRITE8_MEMBER( io_w ); + + UINT8 dack_r(); + void dack_w(UINT8 data); + + DECLARE_READ8_MEMBER( read ); + DECLARE_WRITE8_MEMBER( write ); + + DECLARE_WRITE_LINE_MEMBER( ireq_w ); + DECLARE_WRITE_LINE_MEMBER( io_w ); + DECLARE_WRITE_LINE_MEMBER( cd_w ); + DECLARE_WRITE_LINE_MEMBER( clct_w ); + DECLARE_WRITE_LINE_MEMBER( mode_w ); + + DECLARE_READ_LINE_MEMBER( busy_r ); + DECLARE_READ_LINE_MEMBER( ecc_not_0_r ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + +private: + inline void check_interrupt(); + inline void increment_address(); + inline UINT8 read_data(); + inline void write_data(UINT8 data); + inline void software_reset(); + inline void select(); + + devcb_write_line m_out_irq5_cb; + devcb_write_line m_out_drq3_cb; + devcb_write_line m_out_mr_cb; + devcb_write_line m_out_busy_cb; + devcb_write_line m_out_req_cb; + devcb_write_line m_out_ra3_cb; + devcb_read8 m_in_rd322_cb; + devcb_read8 m_in_ramcs_cb; + devcb_write8 m_out_ramwr_cb; + devcb_read8 m_in_cs1010_cb; + devcb_write8 m_out_cs1010_cb; + + UINT8 m_status; + UINT8 m_mask; + + offs_t m_ra; + + int m_mode; + int m_ecc_not_0; + + int m_irq5; + int m_drq3; + int m_busy; + int m_req; + int m_ra3; +}; + + +// device type definition +extern const device_type WD11C00_17; + +#endif diff --git a/src/devices/machine/wd2010.c b/src/devices/machine/wd2010.c new file mode 100644 index 00000000000..6f50622ec79 --- /dev/null +++ b/src/devices/machine/wd2010.c @@ -0,0 +1,989 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + +Western Digital WD2010 Winchester Disk Controller + +Portions (2015) : Karl-Ludwig Deisenhofer +********************************************************************** + +Implements WD2010 / WD1010 controller basics. + + Provides IRQ / (B)DRQ signals needed for early MFM cards. + Honors DRIVE_READY and WRITE FAULT (DRDY / WF). + + Single sector read / write (format) confirmed to work with + Rainbow-100 controller (WD1010, largely compatible to WD2010, see **) + + LIST OF UNIMPLEMENTED FEATURES : + - MULTI SECTOR TRANSFERS (M = 1); MULTIPLE DRIVES + - AUTO_SCAN_ID / SEEK + INDEX TIMERS / ID NOT FOUND + - IMPLIED SEEKS / IMPLIED WRITES / RETRIES + - EDGE or LEVEL TRIGGERED SEEK_COMPLETE (SC) + - SET_PARAMETER / COMPUTE_CORRECTION (DWC flag!) + + Pseudo code (from datasheet) left in to illustrate + the intended instruction flow. Some loops were omitted! + + USAGE: tie WF (write fault) to ground if not needed: + MCFG_WD2010_IN_WF_CB(GND) + + Other signals should be set to VCC if not serviced: + MCFG_WD2010_IN_DRDY_CB(VCC) // DRIVE READY = VCC + MCFG_WD2010_IN_SC_CB(VCC) // SEEK COMPLETE = VCC + **********************************************************************/ + +// WD 2010 CONFIGURATION (2048 cylinder limit) +#define STEP_LIMIT 2048 +#define CYLINDER_HIGH_MASK 0x07 + +// DEC RD51 chip; different STEP / CYLINDER LIMIT (**): + +// WD 1010 CONFIGURATION (1024 cylinder limit) +// #define STEP_LIMIT 1024 +// #define CYLINDER_HIGH_MASK 0x03 + +// -------------------------------------------------------- +#define MAX_MFM_SECTORS 17 // STANDARD MFM SECTORS/TRACK +// -------------------------------------------------------- + + +#include "machine/wd2010.h" + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define LOG 1 + +// task file +enum +{ + TASK_FILE_ERROR = 1, + TASK_FILE_WRITE_PRECOMP_CYLINDER = TASK_FILE_ERROR, + TASK_FILE_SECTOR_COUNT, + TASK_FILE_SECTOR_NUMBER, + TASK_FILE_CYLINDER_LOW, + TASK_FILE_CYLINDER_HIGH, + TASK_FILE_SDH_REGISTER, + TASK_FILE_STATUS, + TASK_FILE_COMMAND = TASK_FILE_STATUS +}; + +#define WRITE_PRECOMP_CYLINDER \ + (m_task_file[TASK_FILE_WRITE_PRECOMP_CYLINDER] * 4) + +#define SECTOR_COUNT \ + ((m_task_file[TASK_FILE_SECTOR_COUNT] + 1) * 256) + +#define SECTOR_NUMBER \ + (m_task_file[TASK_FILE_SECTOR_NUMBER]) + +#define CYLINDER \ + (((m_task_file[TASK_FILE_CYLINDER_HIGH] & CYLINDER_HIGH_MASK) << 8) | m_task_file[TASK_FILE_CYLINDER_LOW]) + +#define HEAD \ + (m_task_file[TASK_FILE_SDH_REGISTER] & 0x07) + +#define DRIVE \ + ((m_task_file[TASK_FILE_SDH_REGISTER] >> 3) & 0x03) + +static const int SECTOR_SIZES[4] = { 256, 512, 1024, 128 }; + +#define SECTOR_SIZE \ + SECTOR_SIZES[(m_task_file[TASK_FILE_SDH_REGISTER] >> 5) & 0x03] + +// status register +#define STATUS_BSY 0x80 +#define STATUS_RDY 0x40 +#define STATUS_WF 0x20 +#define STATUS_SC 0x10 +#define STATUS_DRQ 0x08 +#define STATUS_DWC 0x04 +#define STATUS_CIP 0x02 +#define STATUS_ERR 0x01 + + +// error register +#define ERROR_BB 0x80 +#define ERROR_CRC_ECC 0x40 +#define ERROR_ID 0x10 +#define ERROR_AC 0x04 +#define ERROR_TK 0x02 +#define ERROR_DM 0x01 + + +// command register +#define COMMAND_MASK 0xf0 +#define COMMAND_RESTORE 0x10 +#define COMMAND_SEEK 0x70 +#define COMMAND_READ_SECTOR 0x20 +#define COMMAND_WRITE_SECTOR 0x30 +#define COMMAND_SCAN_ID 0x40 +#define COMMAND_WRITE_FORMAT 0x50 +#define COMMAND_COMPUTE_CORRECTION 0x08 +#define COMMAND_SET_PARAMETER_MASK 0xfe +#define COMMAND_SET_PARAMETER 0x00 + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type WD2010 = &device_creator; + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// wd2010_device - constructor +//------------------------------------------------- + +wd2010_device::wd2010_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) +: device_t(mconfig, WD2010, "Western Digital WD2010", tag, owner, clock, "wd2010", __FILE__), +m_out_intrq_cb(*this), +m_out_bdrq_cb(*this), +m_out_bcr_cb(*this), +m_in_bcs_cb(*this), +m_in_brdy_cb(*this), +m_out_bcs_cb(*this), +m_out_dirin_cb(*this), +m_out_step_cb(*this), +m_out_rwc_cb(*this), +m_out_wg_cb(*this), +m_in_drdy_cb(*this), +m_in_index_cb(*this), +m_in_wf_cb(*this), +m_in_tk000_cb(*this), +m_in_sc_cb(*this), +m_status(0), +m_error(0) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void wd2010_device::device_start() +{ + // resolve callbacks + m_out_intrq_cb.resolve_safe(); + m_out_bdrq_cb.resolve_safe(); + m_out_bcr_cb.resolve_safe(); + m_in_bcs_cb.resolve_safe(0); + + m_in_brdy_cb.resolve_safe(0); + + m_out_bcs_cb.resolve_safe(); + m_out_dirin_cb.resolve_safe(); + m_out_step_cb.resolve_safe(); + m_out_rwc_cb.resolve_safe(); + m_out_wg_cb.resolve_safe(); + m_in_drdy_cb.resolve_safe(0); + m_in_index_cb.resolve_safe(0); + m_in_wf_cb.resolve_safe(0); + m_in_tk000_cb.resolve_safe(0); + m_in_sc_cb.resolve_safe(0); + + /* allocate a timer for commands */ + cmd_timer = timer_alloc(0); + complete_write_when_buffer_ready_high = timer_alloc(1); + deassert_write_when_buffer_ready_low = timer_alloc(2); + deassert_read_when_buffer_ready_high = timer_alloc(3); +} + +// timers +#define COMMAND_TIMER 0 +#define COMPLETE_WRITE_SECTOR 1 +#define DE_ASSERT_WRITE 2 +#define DE_ASSERT_READ 3 + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void wd2010_device::device_reset() +{ + m_out_intrq_cb(CLEAR_LINE); + + buffer_ready(false); + + m_present_cylinder = 0; // start somewhere +} + + +//------------------------------------------------- +// read - +//------------------------------------------------- + +READ8_MEMBER(wd2010_device::read) +{ + UINT8 data = 0; + + switch (offset) + { + case TASK_FILE_ERROR: + if (m_status & STATUS_CIP) // "if other registers are read while CIP, the status register contents are returned." + data = (m_in_drdy_cb() ? 0x40 : 0) | (m_in_wf_cb() ? 0x20 : 0) | (m_in_sc_cb() ? 0x10 : 0) | m_status;// see STATUS register + else + data = m_error; + break; + + case TASK_FILE_STATUS: + m_out_intrq_cb(CLEAR_LINE); // "reading the status register clears INTRQ" (-> datasheet) + data = (m_in_drdy_cb() ? 0x40 : 0) | (m_in_wf_cb() ? 0x20 : 0) | (m_in_sc_cb() ? 0x10 : 0) | m_status;// see ERROR register + break; + + default: + data = m_task_file[offset]; + + if (offset == TASK_FILE_SDH_REGISTER) + { + logerror("(READ) %s WD2010 '%s' SDH: %u\n", machine().describe_context(), tag(), data); + logerror("(READ) %s WD2010 '%s' Head: %u\n", machine().describe_context(), tag(), HEAD); + logerror("(READ) %s WD2010 '%s' Drive: %u\n", machine().describe_context(), tag(), DRIVE); + logerror("(READ) %s WD2010 '%s' Sector Size: %u\n", machine().describe_context(), tag(), SECTOR_SIZE); + } + + break; + } + + return data; +} + + +//------------------------------------------------- +// write - +//------------------------------------------------- + +WRITE8_MEMBER(wd2010_device::write) +{ + m_task_file[offset] = data; + + switch (offset) + { + case TASK_FILE_WRITE_PRECOMP_CYLINDER: + if (LOG) logerror("%s WD2010 '%s' Write Precomp Cylinder: %u\n", machine().describe_context(), tag(), WRITE_PRECOMP_CYLINDER); + break; + + case TASK_FILE_SECTOR_COUNT: + if (LOG) logerror("%s WD2010 '%s' Sector Count: %u\n", machine().describe_context(), tag(), SECTOR_COUNT); + break; + + case TASK_FILE_SECTOR_NUMBER: + if (LOG) logerror("%s WD2010 '%s' Sector Number: %u\n", machine().describe_context(), tag(), SECTOR_NUMBER); + break; + + case TASK_FILE_CYLINDER_LOW: + if (LOG) logerror("%s WD2010 '%s' Cylinder (lower bits set): %u\n", machine().describe_context(), tag(), CYLINDER); + break; + + case TASK_FILE_CYLINDER_HIGH: + if (LOG) logerror("%s WD2010 '%s' Cylinder (MSB bits set): %u\n", machine().describe_context(), tag(), CYLINDER); + break; + + case TASK_FILE_SDH_REGISTER: + if (LOG) + { + logerror("(WRITE) %s WD2010 '%s' SDH: %u\n", machine().describe_context(), tag(), data); + logerror("(WRITE) %s WD2010 '%s' Head: %u\n", machine().describe_context(), tag(), HEAD); + logerror("(WRITE) %s WD2010 '%s' Drive: %u\n", machine().describe_context(), tag(), DRIVE); + logerror("(WRITE) %s WD2010 '%s' Sector Size: %u\n", machine().describe_context(), tag(), SECTOR_SIZE); + } + break; + + case TASK_FILE_COMMAND: + m_out_intrq_cb(CLEAR_LINE); // "either reading the status register or writing a new command clears INTRQ" + m_status &= ~(STATUS_ERR | STATUS_BSY | STATUS_CIP); // "Reset ERR bit in STATUS upon new cmd" (see datasheet) + m_error = 0; + + if (data == COMMAND_COMPUTE_CORRECTION) + { + if (LOG) logerror("%s WD2010 '%s' COMPUTE CORRECTION\n", machine().describe_context(), tag()); + compute_correction(data); + } + else if ((data & COMMAND_SET_PARAMETER_MASK) == COMMAND_SET_PARAMETER) + { + if (LOG) logerror("%s WD2010 '%s' SET PARAMETER\n", machine().describe_context(), tag()); + set_parameter(data); + } + else + { + switch (data & COMMAND_MASK) + { + case COMMAND_RESTORE: + if (LOG) logerror("%s WD2010 '%s' RESTORE\n", machine().describe_context(), tag()); + restore(data); + break; + + case COMMAND_SEEK: + if (LOG) logerror("%s WD2010 '%s' SEEK\n", machine().describe_context(), tag()); + seek(data); + break; + + case COMMAND_READ_SECTOR: + if (LOG) logerror("%s WD2010 '%s' READ SECTOR (I = %u) (M = %u)\n", machine().describe_context(), tag(), ((data & 8)>0), ((data & 4)>0)); + read_sector(data); + break; + + case COMMAND_WRITE_SECTOR: + if (LOG) logerror("%s WD2010 '%s' WRITE SECTOR (M = %u)\n", machine().describe_context(), tag(), ((data & 4) > 0)); + write_sector(data); + break; + + case COMMAND_SCAN_ID: + if (LOG) logerror("%s WD2010 '%s' SCAN ID\n", machine().describe_context(), tag()); + scan_id(data); + break; + + case COMMAND_WRITE_FORMAT: + if (LOG) logerror("%s WD2010 '%s' WRITE FORMAT\n", machine().describe_context(), tag()); + format(data); + break; + } + + } + + break; + } // switch +} + + +//------------------------------------------------- +// compute_correction - +//------------------------------------------------- +void wd2010_device::compute_correction(UINT8 data) +{ + UINT8 newstatus = STATUS_RDY | STATUS_SC; + complete_cmd(newstatus); +} + + +//------------------------------------------------- +// set_parameter - +//------------------------------------------------- +void wd2010_device::set_parameter(UINT8 data) +{ + UINT8 newstatus = STATUS_RDY | STATUS_SC; + complete_cmd(newstatus); +} + + +//------------------------------------------------- +// restore - +//------------------------------------------------- +void wd2010_device::restore(UINT8 data) +{ + UINT8 newstatus = STATUS_RDY | STATUS_SC; + + m_out_intrq_cb(CLEAR_LINE); // reset INTRQ, errors, set BUSY, CIP + m_error = 0; + m_status = STATUS_BSY | STATUS_CIP; + + m_out_rwc_cb(0); // reset RWC, set direction = OUT + + // datasheet: DIRIN HIGH = in ; LOW = out + m_out_dirin_cb(0); // 0 = heads move away from the spindle, towards track O. + + // TODO: store step rate + + m_present_cylinder = 0; // (sse WD2010-05 datasheet) + m_task_file[TASK_FILE_CYLINDER_HIGH] = 0; + m_task_file[TASK_FILE_CYLINDER_LOW] = 0; + + int step_pulses = 0; + while (step_pulses < STEP_LIMIT) + { + while (!m_in_sc_cb()) + { + if (!m_in_drdy_cb() || m_in_wf_cb()) // drive not ready or write fault? + { + m_out_bcr_cb(0); // pulse BCR + m_out_bcr_cb(1); + + m_error = ERROR_AC; // ERROR : ABORTED COMMAND + complete_cmd(newstatus | STATUS_ERR); + return; + } + } + + //if (m_in_tk000_cb()) + if (step_pulses == STEP_LIMIT - 2) // Simulate TRACK 00 signal (normally from DRIVE) + { + m_out_bcr_cb(0); // pulse BCR + m_out_bcr_cb(1); + newstatus &= ~(STATUS_BSY | STATUS_CIP); // prepare new status; (INTRQ later) reset BSY, CIP + complete_cmd(newstatus); + return; + } + + if (step_pulses == STEP_LIMIT - 1) // NOTE: STEP_LIMIT - differs - between WD2010 and WD1010 + { + m_error = ERROR_TK; // ERROR: track 0 not reached within limit + newstatus = newstatus | STATUS_ERR; + + m_out_bcr_cb(0); // pulse BCR + m_out_bcr_cb(1); + newstatus &= ~(STATUS_BSY | STATUS_CIP); // prepare new status; (INTRQ later) reset BSY, CIP + complete_cmd(newstatus); + return; + } + + m_out_step_cb(1); // issue a step pulse + m_out_step_cb(0); + step_pulses++; + } + + assert(1); +} + +//------------------------------------------------- +// seek - +//------------------------------------------------- + +// FIXME : step rate, drive change (!) + +// NOT IMPLEMENTED: IMPLIED SEEK ("wait until rising edge of SC signal") +void wd2010_device::seek(UINT8 data) +{ + UINT8 newstatus = STATUS_RDY | STATUS_SC; + + m_out_intrq_cb(CLEAR_LINE); // reset INTRQ, errors, set BUSY, CIP + m_error = 0; + m_status = STATUS_BSY | STATUS_CIP; + + // TODO : store STEP RATE. + + auto_scan_id(data); // has drive number changed? + + int direction = 0; // 0 = towards 0 + int step_pulses = 0; + + // Calculate number of steps by comparing the cylinder registers + // HI/LO with the internally stored position. + UINT32 cylinder_registers = CYLINDER; + if (m_present_cylinder > cylinder_registers) + { + step_pulses = m_present_cylinder - cylinder_registers; + direction = 0; + } + else + { + step_pulses = cylinder_registers - m_present_cylinder; + direction = 1; + } + logerror("SEEK - direction = %u, step_pulses = %u\n", direction, step_pulses); + m_out_dirin_cb(direction); + + if (!m_in_drdy_cb() || m_in_wf_cb()) // DRDY de-asserted or WF asserted? + { + m_error = ERROR_AC; + complete_cmd(newstatus | STATUS_ERR); + return; + } + else + { + while (step_pulses > 0) // issue STEP PULSES + { + if (direction == 0) + { + m_out_step_cb(1); // issue a step pulse + m_out_step_cb(0); + + if (m_present_cylinder > 0) + m_present_cylinder--; + } + else + { + m_out_step_cb(0); + m_out_step_cb(1); + + m_present_cylinder++; + } + step_pulses--; + + // TODO: delay according to rate field + } + + // ALL STEPS ISSUED NOW + + if (!m_in_drdy_cb()) // DRDY not asserted = > ABORTED COMMAND + { + m_error = ERROR_AC; + complete_cmd(newstatus | STATUS_ERR); + return; + } + } + + // AFTER ALL STEPS ARE ISSUED ... + // UPDATE INTERNAL CYLINDER POSITION REGISTER (from WD1010 spec -> "SEEK COMMAND") + m_present_cylinder = cylinder_registers; + + logerror("SEEK (END) - m_present_cylinder = %u\n", m_present_cylinder); + + cmd_timer->adjust(attotime::from_msec(35), newstatus); // 35 msecs makes "SEEK_TIMING" test happy. +} + +//------------------------------------------------- +// read_sector - +//------------------------------------------------- +// FIXME: multiple sector transfers, ID / CYL / HEAD / SIZE match +// + ERROR HANDLING (...) +void wd2010_device::read_sector(UINT8 data) +{ + UINT8 newstatus = STATUS_RDY | STATUS_SC; + int intrq_at_end = 0; // (default) : (I = 1 INTRQ occurs when the command + + m_out_intrq_cb(CLEAR_LINE); // reset INTRQ, errors, set BUSY, CIP + m_error = 0; + m_status = STATUS_BSY | STATUS_CIP; + + // Assume: drive NO # has not changed... (else: SCAN_ID; GET CYL#) + auto_scan_id(data); // has drive number changed? + + // CYL REGISTERS and INTERNAL CYL. SAME ? + // TODO: < NOT SAME? THEN _SEEK_ > + + // DRIVE NOT READY? OR WF? + if ( (!m_in_drdy_cb()) || m_in_wf_cb() ) + { + m_error = ERROR_AC; // ABORTED_COMMAND + complete_cmd(newstatus | STATUS_ERR); + return; + } + else + { + m_out_bcs_cb(1); // activate BCS (!) + + m_out_bcr_cb(0); // strobe BCR + m_out_bcr_cb(1); + + if (!m_in_drdy_cb()) // DRIVE NOT READY? + { + m_error = ERROR_AC; // ABORTED_COMMAND + complete_cmd(newstatus | STATUS_ERR); + return; + } + else + { + // < SEARCH FOR ID FIELD > + // < CYL / HEAD / SEC.SIZE MATCH ? > + + // < ID NOT FOUND > + if (SECTOR_NUMBER > MAX_MFM_SECTORS) + { + // prepare new status; (later IRQ +) reset BSY, CIP + m_error = ERROR_ID; + complete_cmd(newstatus | STATUS_ERR); + return; + } + + // LOOP OVER 10 INDEXES : SCAN_ID / GET CYL.# (not implemented: ID NOT FOUND) + + // CYL / HEAD / SEC.SIZE MATCH ? => (ID FOUND) + // + // NO "BAD BLOCK DETECT" (** NOT IMPLEMENTED **) + // NO "CRC ERROR" (** NOT IMPLEMENTED **) + // AND "DAM FOUND" (** NOT IMPLEMENTED **) + + // ====> THEN "TRANSFER SECTOR TO BUFFER" <==== + + m_out_bcr_cb(0); // strobe BCR + m_out_bcr_cb(1); + + // NO "CRC ERROR" + + // FLAG "M" SET? (MULTIPLE SECTOR TRANSFERS) + if (data & 4) + logerror("WD2010 (READ): MULTIPLE SECTOR READ (M = 1).\n"); + + // Assume: NO "M" (MULTIPLE SECTOR TRANSFERS) + + m_out_bcs_cb(0); // deactivate BCS (!) + + m_out_bcr_cb(0); // strobe BCR + m_out_bcr_cb(1); + + // set BDRQ (NOTE: DRQ status bit 3 reflects state of BDRQ) + m_status |= STATUS_DRQ; + m_out_bdrq_cb(1); + + // reset BUSY (* after * TRANSFER OF SECTOR in READ) + m_status &= ~(STATUS_BSY); + + // FLAG "I" SET? + if (!(data & 8)) // (I = 0 INTRQ occurs with BDRQ/DRQ indicating the Sector Buffer is full...) + { + m_out_intrq_cb(ASSERT_LINE); + if (!(data & 4)) // (...valid only when M = 0) + intrq_at_end = STATUS_DWC; // 'reuse' unused DWC bit! + } + else + { + intrq_at_end = 0; // (default): (I = 1 INTRQ occurs when the command is completed and the Host has read the Sector Buffer) + } + + // (WAIT FOR): BRDY LOW TO HIGH? (see -> TIMER) + + } // DRIVE_READY ? (inner) + + } // DRIVE_READY ? (outer) + + // NOTE : (intrq_at_end = 0) - INTRQ occurs when the command is completed + newstatus |= (m_status & ~(STATUS_CIP | STATUS_DRQ)) | intrq_at_end; // de-assert CIP + DRQ (BSY already reset) + + deassert_read_when_buffer_ready_high->adjust(attotime::from_usec(1), newstatus); // complete command ON *RISING EDGE * OF BUFFER_READY +} + + +//------------------------------------------------- +// write_sector (stage I) +//------------------------------------------------- +// FIXME: SEEK, SEEK_COMPLETE, Drive # change (!) +// as well as CYL.register + internal CYL.register comparisons +void wd2010_device::write_sector(UINT8 data) +{ + m_error = 0; // De-assert ERROR + DRQ + m_status &= ~(STATUS_DRQ); + + m_status = STATUS_BSY | STATUS_CIP; // Assert BUSY + CIP + + m_status |= STATUS_DRQ; // Assert BDRQ + DRQ (= status bit 3) + m_out_bdrq_cb(1); + + // WAIT UNTIL BRDY ASSERTED (-> timer): + complete_write_when_buffer_ready_high->adjust(attotime::from_usec(1), data); // 1 usec +} + + +//------------------------------------------------- +// write_sector (stage II) +//------------------------------------------------- +void wd2010_device::complete_write_sector(UINT8 data) +{ + UINT8 newstatus = STATUS_RDY | STATUS_SC; + + m_out_bdrq_cb(0); // DE-Assert BDRQ (...and DRQ !) + m_status &= ~(STATUS_DRQ); + + // (When drive changed) : SCAN_ID / GET CYL# + auto_scan_id(data); // has drive number changed? (*** UNIMPLEMENTED ***) + + // Assume YES : CYL.register + internal CYL.register SAME? (if NO => SEEK!) + // Assume : SEEK_COMPLETE = YES + + if (!m_in_drdy_cb() || m_in_wf_cb()) // DRIVE IS READY / NO WF? + { + m_error = ERROR_AC; // ABORTED_COMMAND + complete_cmd(newstatus | STATUS_ERR); + return; + } + else + { // -------------------------------------------------------- + // (*** UNIMPLEMENTED ***) Search for ID field... + + // < Correct ID found > + + // (*** UNIMPLEMENTED ***) : 'ID NOT FOUND' - set bit 4 error register + // ........................: => SCAN_ID => RE-SEEK (2-10 INDEX PULSES) / Set ERR bit 0 status register .. + + m_status &= ~(STATUS_SC); // "WRITE_GATE valid when SEEK_COMPLETE = 0" (see Rainbow 100 Addendum!) + + m_out_bcs_cb(1); + m_out_wg_cb(1); // (!) + + m_out_bcr_cb(0); // strobe BCR + m_out_bcr_cb(1); + + // Assume: DRIVE IS READY / NO WF + + if (!m_in_drdy_cb() || m_in_wf_cb()) // DRDY de-asserted or WF asserted? + { + m_error = ERROR_AC; // ABORTED_COMMAND + complete_cmd(newstatus | STATUS_ERR); + return; + } + else + { + // ====> WRITE DATA TO SECTOR <==== + + m_out_wg_cb(0); // (!) + + // Assume: (single sector transfer; M = 0) + + } // (INNER IF): No WF and DRIVE IS READY. + } // -------------------------------------------------------- + + // 'complete_cmd' ON THE FALLING EDGE OF _BUFFER_READY_ ( set by WRITE_SECTOR ) ! + deassert_write_when_buffer_ready_low->adjust(attotime::from_usec(1), newstatus); +} + +// ****************************************************** +// AUTO SCAN-ID (whenever DRIVE # changes): + + // * does nothing right now * +// ****************************************************** +void wd2010_device::auto_scan_id(UINT8 data) +{ + static int last_drive; + + if (DRIVE != last_drive) + { + printf("\n(WD2010) : UNSUPPORTED DRIVE CHANGE !\n"); + logerror("\n(WD2010) : UNSUPPORTED DRIVE CHANGE !\n"); + + //update_sdh(new_sector_size, new_head, new_cylinder, new_sectornr); + } + last_drive = DRIVE; + + return; // AUTO-SCAN CURRENTLY DISABLED (see NOTES) +} +// ****************************************************** + +// What to do here (just update present_cylinder with CYLINDER)...? +void wd2010_device::update_sdh(UINT8 new_sector_size, UINT8 new_head, UINT16 new_cylinder, UINT8 new_sectornr) +{ + // "Update SDH" + /* + // Update SECTOR_SIZE, HEAD in SDH with the ID found - + m_task_file[TASK_FILE_SDH_REGISTER] = ??? + + // ...update CYLINDER registers with cylinder found - + m_task_file[TASK_FILE_CYLINDER_LOW] = (new_cylinder >> 4) & 0x0f; + m_task_file[TASK_FILE_CYLINDER_HIGH] = (new_cylinder - ((new_cylinder >> 4) << 4)) & 0x0f; + + // ...update SECTOR_NUMBER with sector nr. found - + m_task_file[TASK_FILE_SECTOR_NUMBER] = new_sectornr; + */ + + m_present_cylinder = CYLINDER; + logerror("UPDATE_SDH - m_present_cylinder = %u\n", m_present_cylinder); +} + +//------------------------------------------------- +// scan_id - +//------------------------------------------------- + +// Reads the cylinder number from the track on which the heads are PRESENTLY located, +// and writes this into the Present Cylinder Position Register. + +// FIXME: NO ID HANDLING (ID FOUND / NOT FOUND), NO BAD BLOCK; NO CRC +void wd2010_device::scan_id(UINT8 data) +{ + UINT8 newstatus = STATUS_RDY; + + m_out_intrq_cb(CLEAR_LINE); + m_error = 0; + m_status = STATUS_BSY | STATUS_CIP; + + // Assume DRIVE READY. + // < TODO: Search for ANY ID FIELD. > + + // Assume ID FOUND : + update_sdh( 32, 0, 0, 1 ); // (NEW:) SECTOR_SIZE, HEAD, CYLINDER, SECTOR_NR + + // NO BAD BLOCK. + // NO CRC ERROR. + + complete_cmd(newstatus); +} + +//-------------------------------------------------------- +// FORMAT ENTIRE TRACK using the task file + sector buffer + +// On real hardware, data fields are filled with FF. +// Sector buffer is used for track layout (see datasheet). + +// Routine simulates one single write on each track +// - just enough to keep formatter programs happy - + +// < UNIMPLEMENTED: (IMPLIED) SEEKs, INDEX, CRC and GAPs > +//-------------------------------------------------------- +// SECTOR_COUNT REG.= 'total # of sectors to be formatted' +// (raw number; no multiplication) = 16 decimal on RD51 + +// SECTOR NUMBER REG.= number of bytes - 3 (for GAP 1 + 3) +// = 40 decimal on DEC RD51 with WUTIL 3.2 +//-------------------------------------------------------- +void wd2010_device::format(UINT8 data) +{ + UINT8 newstatus = STATUS_RDY; + + m_out_intrq_cb(CLEAR_LINE); + m_error = 0; + m_status = STATUS_BSY | STATUS_CIP; + + m_status |= STATUS_DRQ; + m_out_bdrq_cb(1); + + // < WAIT UNTIL BRDY ASSERTED > + + // Datasheet says [DRQ] must go LOW... + // ...delayed here _until BRDY goes high_ (=> TIMER EVENT <=): + + // m_out_bdrq_cb(0); + // m_status &= ~(STATUS_DRQ); + + auto_scan_id(data); // has drive number changed? + + // TODO: Seek to desired cylinder + // Assume : SEEK COMPLETE. + + m_out_bcr_cb(0); // strobe BCR + m_out_bcr_cb(1); + + m_out_bcs_cb(1); // activate BCS (!) + + if (!m_in_drdy_cb() || m_in_wf_cb()) + { + m_error = ERROR_AC; // ABORTED_COMMAND + complete_cmd(newstatus | STATUS_ERR); + return; + } + + // WAIT FOR INDEX + + m_out_wg_cb(1); // Have Index, activate WRITE GATE + + // Check for WRITE FAULT (WF) + if (m_in_wf_cb()) + { + m_error = ERROR_AC; // ABORTED_COMMAND + complete_cmd(newstatus | STATUS_ERR); + return; + } + + // UINT8 format_sector_count = m_task_file[TASK_FILE_SECTOR_COUNT]; + // do + // { + // < WRITE GAP 1 or GAP 3 > + + // < Wait for SEEK_COMPLETE=1 (extend GAP if SEEK_COMPLETE = 0) > + // < Assume SEEK COMPLETE > + + // format_sector_count--; + // if (format_sector_count != 0) + { + // The Rainbow 100 driver does ignore multiple sector + // transfers so WRITE FORMAT does not actually write - + + m_out_wg_cb(0); // (transition from WG 1 -> 0) + + // NOTE: decrementing TASK_FILE_SECTOR_COUNT does * NOT WORK * + } + // else + // { // < Write 4Es until INDEX (*** UNIMPLEMENTED ****) > + // } + // } while (format_sector_count > 0); + + // ** DELAY INTRQ UNTIL WRITE IS COMPLETE : + complete_write_when_buffer_ready_high->adjust(attotime::from_usec(1), newstatus | STATUS_DRQ); // 1 USECs +} + + +// ************************************* +// INTERNAL +// ************************************* +void wd2010_device::buffer_ready(bool state) +{ + is_buffer_ready = state; +} + + +void wd2010_device::device_timer(emu_timer &timer, device_timer_id tid, int param, void *ptr) +{ + switch (tid) + { + case COMMAND_TIMER: + cmd_timer->adjust(attotime::never); + complete_immediate(param); + break; + + case COMPLETE_WRITE_SECTOR: // when BUFFER_READY -> HIGH + if (is_buffer_ready) + { + complete_write_when_buffer_ready_high->adjust(attotime::never); + complete_write_sector(param); + } + else + { + complete_write_when_buffer_ready_high->reset(); + complete_write_when_buffer_ready_high->adjust(attotime::from_usec(1), param); // DELAY ANOTHER 1 USEC (!) + } + break; + + case DE_ASSERT_WRITE: // waiting for BUFFER_READY -> LOW + if (!(is_buffer_ready)) + { + deassert_write_when_buffer_ready_low->adjust(attotime::never); + complete_immediate(param); + } + else + { + deassert_write_when_buffer_ready_low->reset(); + deassert_write_when_buffer_ready_low->adjust(attotime::from_usec(1), param); // DELAY ANOTHER 1 USEC (!) + } + break; + + case DE_ASSERT_READ: // when BUFFER_READY -> HIGH + if (is_buffer_ready) + { + deassert_read_when_buffer_ready_high->adjust(attotime::never); + + m_error &= ~ERROR_ID; + param &= ~STATUS_ERR; + + m_out_bdrq_cb(0); + complete_immediate(param); + } + else + { + deassert_read_when_buffer_ready_high->reset(); + deassert_read_when_buffer_ready_high->adjust(attotime::from_usec(1), param); // DELAY ANOTHER 1 USEC (!) + } + break; + + default: + break; + } +} + +// Called by 'device_timer' - +void wd2010_device::complete_immediate(UINT8 status) +{ + // re-evaluate external signals at end of command + status &= ~(STATUS_RDY | STATUS_WF | STATUS_SC); // RDY 0x40 / WF 0x20 / SC 0x10 + status |= (m_in_drdy_cb() ? 0x40 : 0) | (m_in_wf_cb() ? 0x20 : 0) | (m_in_sc_cb() ? 0x10 : 0); + + if (status & STATUS_DRQ) // if DRQ was set, reset + { + status &= ~(STATUS_DRQ); + m_out_bdrq_cb(0); + } + + // Set current status (M_STATUS) + m_status = status & (255 - STATUS_DWC); // minus "unused" bit 2 (DWC) + + m_status &= ~(STATUS_BSY | STATUS_CIP); // de-assert BUSY + CIP + + // "IRQ AT END OF COMMAND" when BIT 2 set (DWC 'data was corrected' - unused in this context!) + if (!(status & STATUS_DWC)) // interrupt at END OF COMMAND ? + m_out_intrq_cb(ASSERT_LINE); // Assert INTRQ (callback). + + m_out_bcs_cb(0); // de-assert BCS (needed) + m_out_wg_cb(0); // deactivate WG (required by write / format) + + m_out_bcr_cb(0); // strobe BCR + m_out_bcr_cb(1); +} + +void wd2010_device::complete_cmd(UINT8 status) +{ + cmd_timer->adjust(attotime::from_msec(1), status); +} diff --git a/src/devices/machine/wd2010.h b/src/devices/machine/wd2010.h new file mode 100644 index 00000000000..678844f28d6 --- /dev/null +++ b/src/devices/machine/wd2010.h @@ -0,0 +1,157 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Western Digital WD2010 Winchester Disk Controller + +**********************************************************************/ + +#pragma once + +#ifndef __WD2010__ +#define __WD2010__ + + +#include "emu.h" + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_WD2010_OUT_INTRQ_CB(_devcb) \ + devcb = &wd2010_device::set_out_intrq_callback(*device, DEVCB_##_devcb); + +#define MCFG_WD2010_OUT_BDRQ_CB(_devcb) \ + devcb = &wd2010_device::set_out_bdrq_callback(*device, DEVCB_##_devcb); + +#define MCFG_WD2010_OUT_BCR_CB(_devcb) \ + devcb = &wd2010_device::set_out_bcr_callback(*device, DEVCB_##_devcb); + +#define MCFG_WD2010_IN_BRDY_CB(_devcb) \ + devcb = &wd2010_device::set_in_brdy_callback(*device, DEVCB_##_devcb); + +#define MCFG_WD2010_IN_BCS_CB(_devcb) \ + devcb = &wd2010_device::set_in_bcs_callback(*device, DEVCB_##_devcb); + +#define MCFG_WD2010_OUT_BCS_CB(_devcb) \ + devcb = &wd2010_device::set_out_bcs_callback(*device, DEVCB_##_devcb); + +#define MCFG_WD2010_OUT_DIRIN_CB(_devcb) \ + devcb = &wd2010_device::set_out_dirin_callback(*device, DEVCB_##_devcb); + +#define MCFG_WD2010_OUT_STEP_CB(_devcb) \ + devcb = &wd2010_device::set_out_step_callback(*device, DEVCB_##_devcb); + +#define MCFG_WD2010_OUT_RWC_CB(_devcb) \ + devcb = &wd2010_device::set_out_rwc_callback(*device, DEVCB_##_devcb); + +#define MCFG_WD2010_OUT_WG_CB(_devcb) \ + devcb = &wd2010_device::set_out_wg_callback(*device, DEVCB_##_devcb); + +#define MCFG_WD2010_IN_DRDY_CB(_devcb) \ + devcb = &wd2010_device::set_in_drdy_callback(*device, DEVCB_##_devcb); + +#define MCFG_WD2010_IN_INDEX_CB(_devcb) \ + devcb = &wd2010_device::set_in_index_callback(*device, DEVCB_##_devcb); + +#define MCFG_WD2010_IN_WF_CB(_devcb) \ + devcb = &wd2010_device::set_in_wf_callback(*device, DEVCB_##_devcb); + +#define MCFG_WD2010_IN_TK000_CB(_devcb) \ + devcb = &wd2010_device::set_in_tk000_callback(*device, DEVCB_##_devcb); + +#define MCFG_WD2010_IN_SC_CB(_devcb) \ + devcb = &wd2010_device::set_in_sc_callback(*device, DEVCB_##_devcb); + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> wd2010_device + +class wd2010_device : public device_t +{ +public: + // construction/destruction + wd2010_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + template static devcb_base &set_out_intrq_callback(device_t &device, _Object object) { return downcast(device).m_out_intrq_cb.set_callback(object); } + template static devcb_base &set_out_bdrq_callback(device_t &device, _Object object) { return downcast(device).m_out_bdrq_cb.set_callback(object); } + template static devcb_base &set_out_bcr_callback(device_t &device, _Object object) { return downcast(device).m_out_bcr_cb.set_callback(object); } + template static devcb_base &set_in_brdy_callback(device_t &device, _Object object) { return downcast(device).m_in_brdy_cb.set_callback(object); } + template static devcb_base &set_in_bcs_callback(device_t &device, _Object object) { return downcast(device).m_in_bcs_cb.set_callback(object); } + template static devcb_base &set_out_bcs_callback(device_t &device, _Object object) { return downcast(device).m_out_bcs_cb.set_callback(object); } + template static devcb_base &set_out_dirin_callback(device_t &device, _Object object) { return downcast(device).m_out_dirin_cb.set_callback(object); } + template static devcb_base &set_out_step_callback(device_t &device, _Object object) { return downcast(device).m_out_step_cb.set_callback(object); } + template static devcb_base &set_out_rwc_callback(device_t &device, _Object object) { return downcast(device).m_out_rwc_cb.set_callback(object); } + template static devcb_base &set_out_wg_callback(device_t &device, _Object object) { return downcast(device).m_out_wg_cb.set_callback(object); } + template static devcb_base &set_in_drdy_callback(device_t &device, _Object object) { return downcast(device).m_in_drdy_cb.set_callback(object); } + template static devcb_base &set_in_index_callback(device_t &device, _Object object) { return downcast(device).m_in_index_cb.set_callback(object); } + template static devcb_base &set_in_wf_callback(device_t &device, _Object object) { return downcast(device).m_in_wf_cb.set_callback(object); } + template static devcb_base &set_in_tk000_callback(device_t &device, _Object object) { return downcast(device).m_in_tk000_cb.set_callback(object); } + template static devcb_base &set_in_sc_callback(device_t &device, _Object object) { return downcast(device).m_in_sc_cb.set_callback(object); } + + DECLARE_READ8_MEMBER( read ); + DECLARE_WRITE8_MEMBER( write ); + + void buffer_ready(bool state); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + +private: + void compute_correction(UINT8 data); + void set_parameter(UINT8 data); + void restore(UINT8 data); + void seek(UINT8 data); + void read_sector(UINT8 data); + void write_sector(UINT8 data); + void scan_id(UINT8 data); + void update_sdh(UINT8 new_sector_size, UINT8 new_head, UINT16 new_cylinder, UINT8 new_sectornr); + void auto_scan_id(UINT8 data); + void format(UINT8 data); + + devcb_write_line m_out_intrq_cb; + devcb_write_line m_out_bdrq_cb; + devcb_write_line m_out_bcr_cb; + devcb_read8 m_in_bcs_cb; + devcb_read_line m_in_brdy_cb; + devcb_write8 m_out_bcs_cb; + devcb_write_line m_out_dirin_cb; + devcb_write_line m_out_step_cb; + devcb_write_line m_out_rwc_cb; + devcb_write_line m_out_wg_cb; + devcb_read_line m_in_drdy_cb; + devcb_read_line m_in_index_cb; + devcb_read_line m_in_wf_cb; + devcb_read_line m_in_tk000_cb; + devcb_read_line m_in_sc_cb; + + UINT8 m_status; + UINT8 m_error; + UINT8 m_task_file[8]; + + emu_timer *cmd_timer; + emu_timer *complete_write_when_buffer_ready_high; + emu_timer *deassert_write_when_buffer_ready_low; + emu_timer *deassert_read_when_buffer_ready_high; + + void complete_write_sector(UINT8 status); + void complete_cmd(UINT8 status); + void complete_immediate(UINT8 status); + + bool is_buffer_ready; + + UINT32 m_present_cylinder; // Present Cylinder Position Register +}; + +// device type definition +extern const device_type WD2010; + +#endif diff --git a/src/devices/machine/wd33c93.c b/src/devices/machine/wd33c93.c new file mode 100644 index 00000000000..2ae5f9d370a --- /dev/null +++ b/src/devices/machine/wd33c93.c @@ -0,0 +1,807 @@ +// license:BSD-3-Clause +// copyright-holders:ElSemi, R. Belmont, Ryan Holtz +/* + * wd33c93.c + * + * WD/AMD 33c93 SCSI controller, as seen in + * early PCs, some MSX add-ons, NEC PC-88, and SGI + * Indigo, Indigo2, and Indy systems. + * + * References: + * WD 33c93 manual + * NetBSD 33c93 driver + * + */ + +#include "emu.h" +#include "wd33c93.h" + +#define VERBOSE 0 +#define LOG(x) do { if (VERBOSE) logerror x; } while (0) + +/* WD commands */ +#define WD_CMD_RESET 0x00 +#define WD_CMD_ABORT 0x01 +#define WD_CMD_ASSERT_ATN 0x02 +#define WD_CMD_NEGATE_ACK 0x03 +#define WD_CMD_DISCONNECT 0x04 +#define WD_CMD_RESELECT 0x05 +#define WD_CMD_SEL_ATN 0x06 +#define WD_CMD_SEL 0x07 +#define WD_CMD_SEL_ATN_XFER 0x08 +#define WD_CMD_SEL_XFER 0x09 +#define WD_CMD_RESEL_RECEIVE 0x0a +#define WD_CMD_RESEL_SEND 0x0b +#define WD_CMD_WAIT_SEL_RECEIVE 0x0c +#define WD_CMD_SSCC 0x0d +#define WD_CMD_SND_DISC 0x0e +#define WD_CMD_SET_IDI 0x0f +#define WD_CMD_RCV_CMD 0x10 +#define WD_CMD_RCV_DATA 0x11 +#define WD_CMD_RCV_MSG_OUT 0x12 +#define WD_CMD_RCV 0x13 +#define WD_CMD_SND_STATUS 0x14 +#define WD_CMD_SND_DATA 0x15 +#define WD_CMD_SND_MSG_IN 0x16 +#define WD_CMD_SND 0x17 +#define WD_CMD_TRANS_ADDR 0x18 +#define WD_CMD_XFER_PAD 0x19 +#define WD_CMD_TRANS_INFO 0x20 +#define WD_CMD_TRANSFER_PAD 0x21 +#define WD_CMD_SBT_MODE 0x80 + +/* ASR register */ +#define ASR_INT 0x80 +#define ASR_LCI 0x40 +#define ASR_BSY 0x20 +#define ASR_CIP 0x10 +#define ASR_PE 0x02 +#define ASR_DBR 0x01 + +/* SCSI Bus Phases */ +#define PHS_DATA_OUT 0x00 +#define PHS_DATA_IN 0x01 +#define PHS_COMMAND 0x02 +#define PHS_STATUS 0x03 +#define PHS_MESS_OUT 0x06 +#define PHS_MESS_IN 0x07 + +/* Command Status Register definitions */ + + /* reset state interrupts */ +#define CSR_RESET 0x00 +#define CSR_RESET_AF 0x01 + + /* successful completion interrupts */ +#define CSR_RESELECT 0x10 +#define CSR_SELECT 0x11 +#define CSR_SEL_XFER_DONE 0x16 +#define CSR_XFER_DONE 0x18 + + /* paused or aborted interrupts */ +#define CSR_MSGIN 0x20 +#define CSR_SDP 0x21 +#define CSR_SEL_ABORT 0x22 +#define CSR_RESEL_ABORT 0x25 +#define CSR_RESEL_ABORT_AM 0x27 +#define CSR_ABORT 0x28 + + /* terminated interrupts */ +#define CSR_INVALID 0x40 +#define CSR_UNEXP_DISC 0x41 +#define CSR_TIMEOUT 0x42 +#define CSR_PARITY 0x43 +#define CSR_PARITY_ATN 0x44 +#define CSR_BAD_STATUS 0x45 +#define CSR_UNEXP 0x48 + + /* service required interrupts */ +#define CSR_RESEL 0x80 +#define CSR_RESEL_AM 0x81 +#define CSR_DISC 0x85 +#define CSR_SRV_REQ 0x88 + + /* Own ID/CDB Size register */ +#define OWNID_EAF 0x08 +#define OWNID_EHP 0x10 +#define OWNID_RAF 0x20 +#define OWNID_FS_8 0x00 +#define OWNID_FS_12 0x40 +#define OWNID_FS_16 0x80 + + /* Control register */ +#define CTRL_HSP 0x01 +#define CTRL_HA 0x02 +#define CTRL_IDI 0x04 +#define CTRL_EDI 0x08 +#define CTRL_HHP 0x10 +#define CTRL_POLLED 0x00 +#define CTRL_BURST 0x20 +#define CTRL_BUS 0x40 +#define CTRL_DMA 0x80 + + /* Synchronous Transfer Register */ +#define STR_FSS 0x80 + + /* Destination ID register */ +#define DSTID_DPD 0x40 +#define DATA_OUT_DIR 0 +#define DATA_IN_DIR 1 +#define DSTID_SCC 0x80 + + /* Source ID register */ +#define SRCID_MASK 0x07 +#define SRCID_SIV 0x08 +#define SRCID_DSP 0x20 +#define SRCID_ES 0x40 +#define SRCID_ER 0x80 + +/* convernience functions */ +UINT8 wd33c93_device::getunit( void ) +{ + /* return the destination unit id */ + return regs[WD_DESTINATION_ID] & SRCID_MASK; +} + +void wd33c93_device::set_xfer_count( int count ) +{ + /* set the count */ + regs[ WD_TRANSFER_COUNT_LSB ] = count & 0xff; + regs[ WD_TRANSFER_COUNT ] = ( count >> 8 ) & 0xff; + regs[ WD_TRANSFER_COUNT_MSB ] = ( count >> 16 ) & 0xff; +} + +int wd33c93_device::get_xfer_count( void ) +{ + /* get the count */ + int count = regs[ WD_TRANSFER_COUNT_MSB ]; + + count <<= 8; + count |= regs[ WD_TRANSFER_COUNT ]; + count <<= 8; + count |= regs[ WD_TRANSFER_COUNT_LSB ]; + + return count; +} + +void wd33c93_device::complete_immediate( int status ) +{ + /* reset our timer */ + cmd_timer->reset(); + + /* set the new status */ + regs[WD_SCSI_STATUS] = status & 0xff; + + /* set interrupt pending */ + regs[WD_AUXILIARY_STATUS] |= ASR_INT; + + /* check for error conditions */ + if ( get_xfer_count() > 0 ) + { + /* set data buffer ready */ + regs[WD_AUXILIARY_STATUS] |= ASR_DBR; + } + else + { + /* clear data buffer ready */ + regs[WD_AUXILIARY_STATUS] &= ~ASR_DBR; + } + + /* clear command in progress and bus busy */ + regs[WD_AUXILIARY_STATUS] &= ~(ASR_CIP | ASR_BSY); + + /* if we have a callback, call it */ + if (!m_irq_cb.isnull()) + { + m_irq_cb(1); + } +} + +void wd33c93_device::device_timer(emu_timer &timer, device_timer_id tid, int param, void *ptr) +{ + switch( tid ) + { + case 0: + complete_immediate( param ); + break; + + case 1: + complete_immediate(CSR_SRV_REQ | busphase); + break; + + case 2: + regs[WD_AUXILIARY_STATUS] &= ~ASR_CIP; + break; + } +} + +void wd33c93_device::complete_cmd( UINT8 status ) +{ + /* fire off a timer to complete the command */ + cmd_timer->adjust( attotime::from_usec(1), status ); +} + +/* command handlers */ +void wd33c93_device::unimplemented_cmd() +{ + logerror( "%s:Unimplemented SCSI controller command: %02x\n", machine().describe_context(), regs[WD_COMMAND] ); + + /* complete the command */ + complete_cmd( CSR_INVALID ); +} + +void wd33c93_device::invalid_cmd() +{ + logerror( "%s:Invalid SCSI controller command: %02x\n", machine().describe_context(), regs[WD_COMMAND] ); + + /* complete the command */ + complete_cmd( CSR_INVALID ); +} + +void wd33c93_device::reset_cmd() +{ + int advanced = 0; + + /* see if it wants us to reset with advanced features */ + if ( regs[WD_OWN_ID] & OWNID_EAF ) + { + advanced = 1; + } + + /* clear out all registers */ + memset( regs, 0, sizeof( regs ) ); + + /* complete the command */ + complete_cmd(advanced ? CSR_RESET_AF : CSR_RESET); +} + +void wd33c93_device::abort_cmd() +{ + /* complete the command */ + complete_cmd(CSR_ABORT); +} + +void wd33c93_device::disconnect_cmd() +{ + /* complete the command */ + regs[WD_AUXILIARY_STATUS] &= ~(ASR_CIP | ASR_BSY); +} + +void wd33c93_device::select_cmd() +{ + UINT8 unit = getunit(); + UINT8 newstatus; + + /* see if we can select that device */ + if (select(unit)) + { + /* device is available - signal selection done */ + newstatus = CSR_SELECT; + + /* determine the next bus phase depending on the command */ + if ( (regs[WD_COMMAND] & 0x7f) == WD_CMD_SEL_ATN ) + { + /* /ATN asserted during select: Move to Message Out Phase to read identify */ + busphase = PHS_MESS_OUT; + } + else + { + /* No /ATN asserted: Move to Command Phase */ + busphase = PHS_COMMAND; + } + + /* queue up a service request out in the future */ + service_req_timer->adjust( attotime::from_usec(50) ); + } + else + { + /* device is not available */ + newstatus = CSR_TIMEOUT; + } + + /* complete the command */ + complete_cmd(newstatus); +} + +void wd33c93_device::selectxfer_cmd() +{ + UINT8 unit = getunit(); + UINT8 newstatus; + + /* see if we can select that device */ + if (select(unit)) + { + if ( regs[WD_COMMAND_PHASE] < 0x45 ) + { + /* device is available */ + int phase; + + /* do the request */ + send_command(®s[WD_CDB_1], 12); + phase = get_phase(); + + /* set transfer count */ + if ( get_xfer_count() > TEMP_INPUT_LEN ) + { + logerror( "WD33C93: Transfer count too big. Please increase TEMP_INPUT_LEN (size=%d)\n", get_xfer_count() ); + set_xfer_count( TEMP_INPUT_LEN ); + } + + switch( phase ) + { + case SCSI_PHASE_DATAIN: + read_pending = 1; + break; + } + } + + if ( read_pending ) + { + int len = TEMP_INPUT_LEN; + + if ( get_xfer_count() < len ) len = get_xfer_count(); + + memset( &temp_input[0], 0, TEMP_INPUT_LEN ); + read_data(&temp_input[0], len); + temp_input_pos = 0; + read_pending = 0; + } + + regs[WD_TARGET_LUN] = 0; + regs[WD_CONTROL] |= CTRL_EDI; + regs[WD_COMMAND_PHASE] = 0x60; + + /* signal transfer ready */ + newstatus = CSR_SEL_XFER_DONE; + + /* if allowed disconnect, queue a service request */ + if ( identify & 0x40 ) + { + /* queue disconnect message in */ + busphase = PHS_MESS_IN; + + /* queue up a service request out in the future */ + service_req_timer->adjust( attotime::from_usec(50) ); + } + } + else + { + /* device is not available */ + newstatus = CSR_TIMEOUT; + + set_xfer_count( 0 ); + } + + /* complete the command */ + complete_cmd(newstatus); +} + +void wd33c93_device::negate_ack() +{ + logerror( "WD33C93: ACK Negated\n" ); + + /* complete the command */ + regs[WD_AUXILIARY_STATUS] &= ~(ASR_CIP | ASR_BSY); +} + +void wd33c93_device::xferinfo_cmd() +{ + /* make the buffer available right away */ + regs[WD_AUXILIARY_STATUS] |= ASR_DBR; + regs[WD_AUXILIARY_STATUS] |= ASR_CIP; + + /* the command will be completed once the data is transferred */ + deassert_cip_timer->adjust( attotime::from_msec(1) ); +} + +/* Handle pending commands */ +void wd33c93_device::dispatch_command() +{ + /* get the command */ + UINT8 cmd = regs[WD_COMMAND] & 0x7f; + + switch(cmd) + { + case WD_CMD_RESET: + reset_cmd(); + break; + + case WD_CMD_ABORT: + abort_cmd(); + break; + + case WD_CMD_NEGATE_ACK: + negate_ack(); + break; + + case WD_CMD_DISCONNECT: + disconnect_cmd(); + break; + + case WD_CMD_SEL_ATN: + case WD_CMD_SEL: + select_cmd(); + break; + + case WD_CMD_SEL_ATN_XFER: + case WD_CMD_SEL_XFER: + selectxfer_cmd(); + break; + + case WD_CMD_TRANS_INFO: + xferinfo_cmd(); + break; + + case WD_CMD_ASSERT_ATN: + case WD_CMD_RESELECT: + case WD_CMD_RESEL_RECEIVE: + case WD_CMD_RESEL_SEND: + case WD_CMD_WAIT_SEL_RECEIVE: + case WD_CMD_SSCC: + case WD_CMD_SND_DISC: + case WD_CMD_SET_IDI: + case WD_CMD_RCV_CMD: + case WD_CMD_RCV_DATA: + case WD_CMD_RCV_MSG_OUT: + case WD_CMD_RCV: + case WD_CMD_SND_STATUS: + case WD_CMD_SND_DATA: + case WD_CMD_SND_MSG_IN: + case WD_CMD_SND: + case WD_CMD_TRANS_ADDR: + case WD_CMD_XFER_PAD: + case WD_CMD_TRANSFER_PAD: + unimplemented_cmd(); + break; + + default: + invalid_cmd(); + break; + } +} + +WRITE8_MEMBER(wd33c93_device::write) +{ + switch( offset ) + { + case 0: + { + /* update register select */ + sasr = data & 0x1f; + } + break; + + case 1: + { + LOG(( "WD33C93: PC=%08x - Write REG=%02x, data = %02x\n", space.device().safe_pc(), sasr, data )); + + /* update the register */ + regs[sasr] = data; + + /* if we receive a command, schedule to process it */ + if ( sasr == WD_COMMAND ) + { + LOG(( "WDC33C93: PC=%08x - Executing command %08x - unit %d\n", space.device().safe_pc(), data, getunit() )); + + /* signal we're processing it */ + regs[WD_AUXILIARY_STATUS] |= ASR_CIP; + + /* process the command */ + dispatch_command(); + } + else if ( sasr == WD_CDB_1 ) + { + regs[WD_COMMAND_PHASE] = 0; + } + else if ( sasr == WD_DATA ) + { + /* if data was written, and we have a count, send to device */ + int count = get_xfer_count(); + + if ( regs[WD_COMMAND] & 0x80 ) + count = 1; + + if ( count-- > 0 ) + { + /* write to FIFO */ + if ( fifo_pos < FIFO_SIZE ) + { + fifo[fifo_pos++] = data; + } + + /* update count */ + set_xfer_count( count ); + + /* if we're done with the write, see where we're at */ + if ( count == 0 ) + { + regs[WD_AUXILIARY_STATUS] |= ASR_INT; + regs[WD_AUXILIARY_STATUS] &= ~ASR_DBR; + + switch( busphase ) + { + case PHS_MESS_OUT: + { + /* reset fifo */ + fifo_pos = 0; + + /* Message out phase. Data is probably SCSI Identify. Move to command phase. */ + busphase = PHS_COMMAND; + + identify = fifo[0]; + } + break; + + case PHS_COMMAND: + { + int xfercount; + int phase; + + /* Execute the command. Depending on the command, we'll move to data in or out */ + send_command(&fifo[0], 12); + xfercount = get_length(); + phase = get_phase(); + + /* reset fifo */ + fifo_pos = 0; + + /* set the new count */ + set_xfer_count( xfercount ); + + switch( phase ) + { + case SCSI_PHASE_STATUS: + busphase = PHS_STATUS; + break; + + case SCSI_PHASE_DATAIN: + busphase = PHS_DATA_IN; + read_pending = 1; + break; + + case SCSI_PHASE_DATAOUT: + busphase = PHS_DATA_OUT; + break; + } + } + break; + + case PHS_DATA_OUT: + { + /* write data out to device */ + write_data(fifo, fifo_pos); + + /* reset fifo */ + fifo_pos = 0; + + /* move to status phase */ + busphase = PHS_STATUS; + } + break; + } + + /* complete the command */ + complete_immediate(CSR_XFER_DONE | busphase); + } + } + else + { + logerror( "WD33C93: Sending data to device with transfer count = 0!. Ignoring...\n" ); + } + } + + /* auto-increment register select if not on special registers */ + if ( sasr != WD_COMMAND && sasr != WD_DATA && sasr != WD_AUXILIARY_STATUS ) + { + sasr = ( sasr + 1 ) & 0x1f; + } + } + break; + + default: + { + logerror( "WD33C93: Write to invalid offset %d (data=%02x)\n", offset, data ); + } + break; + } +} + +READ8_MEMBER(wd33c93_device::read) +{ + switch( offset ) + { + case 0: + { + /* read aux status */ + return regs[WD_AUXILIARY_STATUS]; + } + + case 1: + { + UINT8 ret; + + /* if reading status, clear irq flag */ + if ( sasr == WD_SCSI_STATUS ) + { + regs[WD_AUXILIARY_STATUS] &= ~ASR_INT; + + if (!m_irq_cb.isnull()) + { + m_irq_cb(0); + } + + LOG(( "WD33C93: PC=%08x - Status read (%02x)\n", space.device().safe_pc(), regs[WD_SCSI_STATUS] )); + } + else if ( sasr == WD_DATA ) + { + /* we're going to be doing synchronous reads */ + + /* get the transfer count */ + int count = get_xfer_count(); + + /* initialize the return value */ + regs[WD_DATA] = 0; + + if ( count <= 0 && busphase == PHS_MESS_IN ) + { + /* move to disconnect */ + complete_cmd(CSR_DISC); + } + else if ( count == 1 && busphase == PHS_STATUS ) + { + /* update the count */ + set_xfer_count( 0 ); + + /* move to message in phase */ + busphase = PHS_MESS_IN; + + /* complete the command */ + complete_cmd(CSR_XFER_DONE | busphase); + } + else if ( count-- > 0 ) /* make sure we still have data to send */ + { + if ( read_pending ) + { + int len = TEMP_INPUT_LEN; + + if ( (count+1) < len ) len = count+1; + read_data(&temp_input[0], len); + temp_input_pos = 0; + read_pending = 0; + } + + regs[WD_AUXILIARY_STATUS] &= ~ASR_INT; + + /* read in one byte */ + if ( temp_input_pos < TEMP_INPUT_LEN ) + regs[WD_DATA] = temp_input[temp_input_pos++]; + + /* update the count */ + set_xfer_count( count ); + + /* transfer finished, see where we're at */ + if ( count == 0 ) + { + if ( regs[WD_COMMAND_PHASE] != 0x60 ) + { + /* move to status phase */ + busphase = PHS_STATUS; + + /* complete the command */ + complete_cmd(CSR_XFER_DONE | busphase); + } + else + { + regs[WD_AUXILIARY_STATUS] |= ASR_INT; + regs[WD_AUXILIARY_STATUS] &= ~ASR_DBR; + } + } + } + } + + LOG(( "WD33C93: PC=%08x - Data read (%02x)\n", space.device().safe_pc(), regs[WD_DATA] )); + + /* get the register value */ + ret = regs[sasr]; + + /* auto-increment register select if not on special registers */ + if ( sasr != WD_COMMAND && sasr != WD_DATA && sasr != WD_AUXILIARY_STATUS ) + { + sasr = ( sasr + 1 ) & 0x1f; + } + + return ret; + } + + default: + { + logerror( "WD33C93: Read from invalid offset %d\n", offset ); + } + break; + } + + return 0; +} + +wd33c93_device::wd33c93_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + legacy_scsi_host_adapter(mconfig, WD33C93, "33C93 SCSI", tag, owner, clock, "wd33c93", __FILE__), + m_irq_cb(*this) +{ +} + +void wd33c93_device::device_start() +{ + legacy_scsi_host_adapter::device_start(); + + memset(regs, 0, sizeof(regs)); + memset(fifo, 0, sizeof(fifo)); + memset(temp_input, 0, sizeof(temp_input)); + + sasr = 0; + fifo_pos = 0; + temp_input_pos = 0; + busphase = 0; + identify = 0; + read_pending = 0; + + m_irq_cb.resolve(); + + /* allocate a timer for commands */ + cmd_timer = timer_alloc(0); + service_req_timer = timer_alloc(1); + deassert_cip_timer = timer_alloc(2); + + save_item( NAME( sasr ) ); + save_item( NAME( regs ) ); + save_item( NAME( fifo ) ); + save_item( NAME( fifo_pos ) ); + save_item( NAME( temp_input ) ); + save_item( NAME( temp_input_pos ) ); + save_item( NAME( busphase ) ); + save_item( NAME( identify ) ); + save_item( NAME( read_pending ) ); +} + +void wd33c93_device::dma_read_data( int bytes, UINT8 *pData ) +{ + int len = bytes; + + if ( len >= get_xfer_count() ) + len = get_xfer_count(); + + if ( len == 0 ) + return; + + if ( (temp_input_pos+len) >= TEMP_INPUT_LEN ) + { + logerror( "Reading past end of buffer, increase TEMP_INPUT_LEN size\n" ); + len = TEMP_INPUT_LEN - len; + } + + assert(len); + + memcpy( pData, &temp_input[temp_input_pos], len ); + + temp_input_pos += len; + len = get_xfer_count() - len; + set_xfer_count(len); +} + +void wd33c93_device::dma_write_data(int bytes, UINT8 *pData) +{ + write_data(pData, bytes); +} + +void wd33c93_device::clear_dma() +{ + /* indicate DMA completed by clearing the transfer count */ + set_xfer_count(0); + regs[WD_AUXILIARY_STATUS] &= ~ASR_DBR; +} + +int wd33c93_device::get_dma_count() +{ + return get_xfer_count(); +} + +const device_type WD33C93 = &device_creator; diff --git a/src/devices/machine/wd33c93.h b/src/devices/machine/wd33c93.h new file mode 100644 index 00000000000..68ca8acfc58 --- /dev/null +++ b/src/devices/machine/wd33c93.h @@ -0,0 +1,109 @@ +// license:BSD-3-Clause +// copyright-holders:ElSemi, R. Belmont, Ryan Holtz +/* + * wd33c93.h + * + */ + +#ifndef _WD33C93_H_ +#define _WD33C93_H_ + +#include "legscsi.h" + +/* wd register names */ + +enum +{ + WD_OWN_ID = 0x00, + WD_CONTROL = 0x01, + WD_TIMEOUT_PERIOD = 0x02, + WD_CDB_1 = 0x03, + WD_CDB_2 = 0x04, + WD_CDB_3 = 0x05, + WD_CDB_4 = 0x06, + WD_CDB_5 = 0x07, + WD_CDB_6 = 0x08, + WD_CDB_7 = 0x09, + WD_CDB_8 = 0x0a, + WD_CDB_9 = 0x0b, + WD_CDB_10 = 0x0c, + WD_CDB_11 = 0x0d, + WD_CDB_12 = 0x0e, + WD_TARGET_LUN = 0x0f, + WD_COMMAND_PHASE = 0x10, + WD_SYNCHRONOUS_TRANSFER = 0x11, + WD_TRANSFER_COUNT_MSB = 0x12, + WD_TRANSFER_COUNT = 0x13, + WD_TRANSFER_COUNT_LSB = 0x14, + WD_DESTINATION_ID = 0x15, + WD_SOURCE_ID = 0x16, + WD_SCSI_STATUS = 0x17, + WD_COMMAND = 0x18, + WD_DATA = 0x19, + WD_QUEUE_TAG = 0x1a, + WD_AUXILIARY_STATUS = 0x1f +}; + +#define TEMP_INPUT_LEN 262144 +#define FIFO_SIZE 12 + +#define MCFG_WD33C93_IRQ_CB(_devcb) \ + devcb = &wd33c93_device::set_irq_callback(*device, DEVCB_##_devcb); + +class wd33c93_device : public legacy_scsi_host_adapter +{ +public: + // construction/destruction + wd33c93_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + template static devcb_base &set_irq_callback(device_t &device, _Object object) { return downcast(device).m_irq_cb.set_callback(object); } + + DECLARE_READ8_MEMBER(read); + DECLARE_WRITE8_MEMBER(write); + + void dma_read_data( int bytes, UINT8 *pData ); + void dma_write_data(int bytes, UINT8 *pData); + void clear_dma(); + int get_dma_count(); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + +private: + UINT8 getunit( void ); + void set_xfer_count( int count ); + int get_xfer_count( void ); + void complete_immediate( int status ); + void complete_cmd( UINT8 status ); + void unimplemented_cmd(); + void invalid_cmd(); + void reset_cmd(); + void abort_cmd(); + void disconnect_cmd(); + void select_cmd(); + void selectxfer_cmd(); + void negate_ack(); + void xferinfo_cmd(); + void dispatch_command(); + + UINT8 sasr; + UINT8 regs[WD_AUXILIARY_STATUS+1]; + UINT8 fifo[FIFO_SIZE]; + int fifo_pos; + UINT8 temp_input[TEMP_INPUT_LEN]; + int temp_input_pos; + UINT8 busphase; + UINT8 identify; + int read_pending; + emu_timer *cmd_timer; + emu_timer *service_req_timer; + emu_timer *deassert_cip_timer; + devcb_write_line m_irq_cb; /* irq callback */ +}; + +// device type definition +extern const device_type WD33C93; + +#endif diff --git a/src/devices/machine/wd7600.c b/src/devices/machine/wd7600.c new file mode 100644 index 00000000000..26873553e14 --- /dev/null +++ b/src/devices/machine/wd7600.c @@ -0,0 +1,557 @@ +// license:BSD-3-Clause +// copyright-holders:Barry Rodewald +/* + * Western Digital WD7600 PC system chipset + * + * WD76C10 - system control + * WD76C20 - FDC, RTC, Bus interface + * WD76C30 - 1 parallel and 2 serial ports + * + * Created on: 5/05/2014 + * + * TODO: pretty much everything + */ + +#include "machine/wd7600.h" + +const device_type WD7600 = &device_creator; + +#define LOG (1) + +static MACHINE_CONFIG_FRAGMENT( wd7600 ) + MCFG_DEVICE_ADD("dma1", AM9517A, 0) + MCFG_I8237_OUT_HREQ_CB(DEVWRITELINE("dma2", am9517a_device, dreq0_w)) + MCFG_I8237_OUT_EOP_CB(WRITELINE(wd7600_device, dma1_eop_w)) + MCFG_I8237_IN_MEMR_CB(READ8(wd7600_device, dma_read_byte)) + MCFG_I8237_OUT_MEMW_CB(WRITE8(wd7600_device, dma_write_byte)) + MCFG_I8237_IN_IOR_0_CB(READ8(wd7600_device, dma1_ior0_r)) + MCFG_I8237_IN_IOR_1_CB(READ8(wd7600_device, dma1_ior1_r)) + MCFG_I8237_IN_IOR_2_CB(READ8(wd7600_device, dma1_ior2_r)) + MCFG_I8237_IN_IOR_3_CB(READ8(wd7600_device, dma1_ior3_r)) + MCFG_I8237_OUT_IOW_0_CB(WRITE8(wd7600_device, dma1_iow0_w)) + MCFG_I8237_OUT_IOW_1_CB(WRITE8(wd7600_device, dma1_iow1_w)) + MCFG_I8237_OUT_IOW_2_CB(WRITE8(wd7600_device, dma1_iow2_w)) + MCFG_I8237_OUT_IOW_3_CB(WRITE8(wd7600_device, dma1_iow3_w)) + MCFG_I8237_OUT_DACK_0_CB(WRITELINE(wd7600_device, dma1_dack0_w)) + MCFG_I8237_OUT_DACK_1_CB(WRITELINE(wd7600_device, dma1_dack1_w)) + MCFG_I8237_OUT_DACK_2_CB(WRITELINE(wd7600_device, dma1_dack2_w)) + MCFG_I8237_OUT_DACK_3_CB(WRITELINE(wd7600_device, dma1_dack3_w)) + MCFG_DEVICE_ADD("dma2", AM9517A, 0) + MCFG_I8237_OUT_HREQ_CB(WRITELINE(wd7600_device, dma2_hreq_w)) + MCFG_I8237_IN_MEMR_CB(READ8(wd7600_device, dma_read_word)) + MCFG_I8237_OUT_MEMW_CB(WRITE8(wd7600_device, dma_write_word)) + MCFG_I8237_IN_IOR_1_CB(READ8(wd7600_device, dma2_ior1_r)) + MCFG_I8237_IN_IOR_2_CB(READ8(wd7600_device, dma2_ior2_r)) + MCFG_I8237_IN_IOR_3_CB(READ8(wd7600_device, dma2_ior3_r)) + MCFG_I8237_OUT_IOW_1_CB(WRITE8(wd7600_device, dma2_iow1_w)) + MCFG_I8237_OUT_IOW_2_CB(WRITE8(wd7600_device, dma2_iow2_w)) + MCFG_I8237_OUT_IOW_3_CB(WRITE8(wd7600_device, dma2_iow3_w)) + MCFG_I8237_OUT_DACK_0_CB(WRITELINE(wd7600_device, dma2_dack0_w)) + MCFG_I8237_OUT_DACK_1_CB(WRITELINE(wd7600_device, dma2_dack1_w)) + MCFG_I8237_OUT_DACK_2_CB(WRITELINE(wd7600_device, dma2_dack2_w)) + MCFG_I8237_OUT_DACK_3_CB(WRITELINE(wd7600_device, dma2_dack3_w)) + MCFG_PIC8259_ADD("intc1", WRITELINE(wd7600_device, pic1_int_w), VCC, READ8(wd7600_device, pic1_slave_ack_r)) + MCFG_PIC8259_ADD("intc2", DEVWRITELINE("intc1", pic8259_device, ir2_w), GND, NULL) + + MCFG_DEVICE_ADD("ctc", PIT8254, 0) + MCFG_PIT8253_CLK0(XTAL_14_31818MHz / 12) + MCFG_PIT8253_OUT0_HANDLER(DEVWRITELINE("intc1", pic8259_device, ir0_w)) + MCFG_PIT8253_CLK1(XTAL_14_31818MHz / 12) + MCFG_PIT8253_OUT1_HANDLER(WRITELINE(wd7600_device, ctc_out1_w)) + MCFG_PIT8253_CLK2(XTAL_14_31818MHz / 12) + MCFG_PIT8253_OUT2_HANDLER(WRITELINE(wd7600_device, ctc_out2_w)) + + MCFG_DS12885_ADD("rtc") + MCFG_MC146818_IRQ_HANDLER(WRITELINE(wd7600_device, rtc_irq_w)) + MCFG_MC146818_CENTURY_INDEX(0x32) +MACHINE_CONFIG_END + +machine_config_constructor wd7600_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( wd7600 ); +} + +void wd7600_device::static_set_cputag(device_t &device, const char *tag) +{ + wd7600_device &chip = downcast(device); + chip.m_cputag = tag; +} + +void wd7600_device::static_set_isatag(device_t &device, const char *tag) +{ + wd7600_device &chip = downcast(device); + chip.m_isatag = tag; +} + +void wd7600_device::static_set_biostag(device_t &device, const char *tag) +{ + wd7600_device &chip = downcast(device); + chip.m_biostag = tag; +} + +void wd7600_device::static_set_keybctag(device_t &device, const char *tag) +{ + wd7600_device &chip = downcast(device); + chip.m_keybctag = tag; +} + +wd7600_device::wd7600_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, WD7600, "WD 7600 chipset", tag, owner, clock, "wd7600", __FILE__), + m_read_ior(*this), + m_write_iow(*this), + m_write_tc(*this), + m_write_hold(*this), + m_write_nmi(*this), + m_write_intr(*this), + m_write_cpureset(*this), + m_write_a20m(*this), + m_write_spkr(*this), + m_dma1(*this, "dma1"), + m_dma2(*this, "dma2"), + m_pic1(*this, "intc1"), + m_pic2(*this, "intc2"), + m_ctc(*this, "ctc"), + m_rtc(*this, "rtc"), + m_portb(0x0f), + m_iochck(1), + m_nmi_mask(1), + m_alt_a20(0), + m_ext_gatea20(0), + m_kbrst(1), + m_refresh_toggle(0), + m_dma_eop(0), + m_dma_high_byte(0xff), + m_dma_channel(-1) + {} + + +void wd7600_device::device_start() +{ + ram_device *ram_dev = machine().device(RAM_TAG); + + // make sure the ram device is already running + if (!ram_dev->started()) + throw device_missing_dependencies(); + + // resolve callbacks + m_read_ior.resolve_safe(0); + m_write_iow.resolve_safe(); + m_write_tc.resolve_safe(); + m_write_hold.resolve_safe(); + m_write_nmi.resolve_safe(); + m_write_intr.resolve_safe(); + m_write_cpureset.resolve_safe(); + m_write_a20m.resolve_safe(); + m_write_spkr.resolve_safe(); + + device_t *cpu = machine().device(m_cputag); + m_space = &cpu->memory().space(AS_PROGRAM); + m_space_io = &cpu->memory().space(AS_IO); + + m_isa = machine().root_device().memregion(m_isatag)->base(); + m_bios = machine().root_device().memregion(m_biostag)->base(); + m_keybc = downcast(machine().device(m_keybctag)); + + m_ram = ram_dev->pointer(); + UINT32 ram_size = ram_dev->size(); + + // install base memory + m_space->install_ram(0x000000, 0x09ffff, m_ram); + m_space->install_ram(0x0d0000, 0x0effff, m_ram + 0xd0000); + + // install extended memory + if (ram_size > 0x100000) + m_space->install_ram(0x100000, ram_size - 1, m_ram + 0x100000); + + // install video BIOS (we should use the VGA BIOS at the beginning of the system BIOS ROM, but that gives a + // blank display (but still runs)) + //m_space->install_rom(0x000c0000, 0x000cffff, m_bios + 0xe0000); + m_space->install_rom(0x000c0000, 0x000cffff, m_isa); + + // install BIOS ROM at cpu inital pc + m_space->install_rom(0x000f0000, 0x000fffff, m_bios + 0xf0000); + m_space->install_rom(0xffff0000, 0xffffffff, m_bios + 0xf0000); + + // install i/o accesses + m_space_io->install_readwrite_handler(0x0000, 0x000f, read8_delegate(FUNC(am9517a_device::read), &(*m_dma1)), write8_delegate(FUNC(am9517a_device::write), &(*m_dma1)), 0xffffffff); + m_space_io->install_readwrite_handler(0x0020, 0x003f, read8_delegate(FUNC(pic8259_device::read), &(*m_pic1)), write8_delegate(FUNC(pic8259_device::write), &(*m_pic1)), 0x0000ffff); + m_space_io->install_readwrite_handler(0x0040, 0x0043, read8_delegate(FUNC(pit8254_device::read), &(*m_ctc)), write8_delegate(FUNC(pit8254_device::write), &(*m_ctc)), 0xffffffff); + m_space_io->install_readwrite_handler(0x0060, 0x0063, read8_delegate(FUNC(wd7600_device::keyb_data_r), this), write8_delegate(FUNC(wd7600_device::keyb_data_w), this), 0x000000ff); + m_space_io->install_readwrite_handler(0x0060, 0x0063, read8_delegate(FUNC(wd7600_device::portb_r), this), write8_delegate(FUNC(wd7600_device::portb_w), this), 0x0000ff00); + m_space_io->install_readwrite_handler(0x0064, 0x0067, read8_delegate(FUNC(wd7600_device::keyb_status_r), this), write8_delegate(FUNC(wd7600_device::keyb_cmd_w), this), 0x000000ff); + m_space_io->install_readwrite_handler(0x0070, 0x007f, read8_delegate(FUNC(mc146818_device::read), &(*m_rtc)), write8_delegate(FUNC(wd7600_device::rtc_w), this), 0x0000ffff); + m_space_io->install_readwrite_handler(0x0080, 0x009f, read8_delegate(FUNC(wd7600_device::dma_page_r), this), write8_delegate(FUNC(wd7600_device::dma_page_w), this), 0xffffffff); + m_space_io->install_readwrite_handler(0x0090, 0x0093, read8_delegate(FUNC(wd7600_device::a20_reset_r), this), write8_delegate(FUNC(wd7600_device::a20_reset_w), this), 0x00ff0000); + m_space_io->install_readwrite_handler(0x00a0, 0x00a3, read8_delegate(FUNC(pic8259_device::read), &(*m_pic2)), write8_delegate(FUNC(pic8259_device::write), &(*m_pic2)), 0x0000ffff); + m_space_io->install_readwrite_handler(0x00c0, 0x00df, read8_delegate(FUNC(am9517a_device::read), &(*m_dma2)), write8_delegate(FUNC(am9517a_device::write), &(*m_dma2)), 0x00ff00ff); + m_space_io->install_readwrite_handler(0x2070, 0x2073, read16_delegate(FUNC(wd7600_device::refresh_r), this), write16_delegate(FUNC(wd7600_device::refresh_w), this), 0xffff0000); + m_space_io->install_readwrite_handler(0x2870, 0x2873, read16_delegate(FUNC(wd7600_device::chipsel_r), this), write16_delegate(FUNC(wd7600_device::chipsel_w), this), 0xffff0000); + m_space_io->install_readwrite_handler(0x3870, 0x3873, read16_delegate(FUNC(wd7600_device::mem_ctrl_r), this), write16_delegate(FUNC(wd7600_device::mem_ctrl_w), this), 0xffff0000); + m_space_io->install_readwrite_handler(0x4870, 0x4873, read16_delegate(FUNC(wd7600_device::bank_01_start_r), this), write16_delegate(FUNC(wd7600_device::bank_01_start_w), this), 0xffff0000); + m_space_io->install_readwrite_handler(0x5070, 0x5073, read16_delegate(FUNC(wd7600_device::bank_23_start_r), this), write16_delegate(FUNC(wd7600_device::bank_23_start_w), this), 0xffff0000); + m_space_io->install_readwrite_handler(0x5870, 0x5873, read16_delegate(FUNC(wd7600_device::split_addr_r), this), write16_delegate(FUNC(wd7600_device::split_addr_w), this), 0xffff0000); + m_space_io->install_readwrite_handler(0x9870, 0x9873, read16_delegate(FUNC(wd7600_device::diag_r), this), write16_delegate(FUNC(wd7600_device::diag_w), this), 0xffff0000); +} + +void wd7600_device::device_reset() +{ + m_split_start = 0; + m_chip_sel = 0; + m_refresh_ctrl = 0; + m_memory_ctrl = 0; + m_diagnostic = 0xe080; + + for(int x=0;x<4;x++) + m_bank_start[x] = 0; + + // initialize dma controller clocks + m_dma1->set_unscaled_clock(clock()); + m_dma2->set_unscaled_clock(clock()); +} + + +WRITE_LINE_MEMBER( wd7600_device::iochck_w ) +{ + if (BIT(m_portb, 3) == 0) + { + if (m_iochck && state == 0) + { + // set channel check latch + m_portb |= 1 << 6; + nmi(); + } + + m_iochck = state; + } +} + +void wd7600_device::nmi() +{ + if (m_nmi_mask & BIT(m_portb, 6)) + { + m_write_nmi(1); + m_write_nmi(0); + } +} + +void wd7600_device::a20m() +{ + // TODO: ignore keyboard A20 signal if set in Diagnostic register (0x9872) + m_write_a20m(m_alt_a20 | m_ext_gatea20); +} + +void wd7600_device::keyboard_gatea20(int state) +{ + m_ext_gatea20 = state; + a20m(); +} + +WRITE8_MEMBER( wd7600_device::rtc_w ) +{ + if (offset == 0) + { + m_nmi_mask = !BIT(data, 7); + data &= 0x7f; + } + + m_rtc->write(space, offset, data); +} + +WRITE_LINE_MEMBER( wd7600_device::rtc_irq_w ) +{ + m_pic2->ir0_w(state ? 0 : 1); // inverted? +} + +READ8_MEMBER( wd7600_device::pic1_slave_ack_r ) +{ + if (offset == 2) // IRQ 2 + return m_pic2->acknowledge(); + + return 0x00; +} + +// Timer outputs +WRITE_LINE_MEMBER( wd7600_device::ctc_out1_w ) +{ + m_refresh_toggle ^= state; + m_portb = (m_portb & 0xef) | (m_refresh_toggle << 4); +} + +WRITE_LINE_MEMBER( wd7600_device::ctc_out2_w ) +{ + m_write_spkr(!(state)); + m_portb = (m_portb & 0xdf) | (state << 5); +} + +// Keyboard +WRITE8_MEMBER( wd7600_device::keyb_data_w ) +{ +// if(LOG) logerror("WD7600 '%s': keyboard data write %02x\n", tag(), data); + m_keybc->data_w(space,0,data); +} + +READ8_MEMBER( wd7600_device::keyb_data_r ) +{ + UINT8 ret = m_keybc->data_r(space,0); +// if(LOG) logerror("WD7600 '%s': keyboard data read %02x\n", tag(), ret); + return ret; +} + +WRITE8_MEMBER( wd7600_device::keyb_cmd_w ) +{ +// if(LOG) logerror("WD7600 '%s': keyboard command %02x\n", tag(), data); + m_keybc->command_w(space,0,data); +} + +READ8_MEMBER( wd7600_device::keyb_status_r ) +{ + return m_keybc->status_r(space,0); +} + +READ8_MEMBER( wd7600_device::portb_r ) +{ + return m_portb; +} + +WRITE8_MEMBER( wd7600_device::portb_w ) +{ + m_portb = (m_portb & 0xf0) | (data & 0x0f); + + // bit 5 forced to 1 if timer disabled + if (!BIT(m_portb, 0)) + m_portb |= 1 << 5; + + m_ctc->write_gate2(BIT(m_portb, 0)); + + m_write_spkr(!BIT(m_portb, 1)); + + // clear channel check latch? + if (BIT(m_portb, 3)) + m_portb &= 0xbf; +} + +// DMA controllers +offs_t wd7600_device::page_offset() +{ + switch (m_dma_channel) + { + case 0: return (offs_t) m_dma_page[0x07] << 16; + case 1: return (offs_t) m_dma_page[0x03] << 16; + case 2: return (offs_t) m_dma_page[0x01] << 16; + case 3: return (offs_t) m_dma_page[0x02] << 16; + case 5: return (offs_t) m_dma_page[0x0b] << 16; + case 6: return (offs_t) m_dma_page[0x09] << 16; + case 7: return (offs_t) m_dma_page[0x0a] << 16; + } + + // should never get here + return 0xff0000; +} + +READ8_MEMBER( wd7600_device::dma_read_byte ) +{ + if (m_dma_channel == -1) + return 0xff; + + return m_space->read_byte(page_offset() + offset); +} + +WRITE8_MEMBER( wd7600_device::dma_write_byte ) +{ + if (m_dma_channel == -1) + return; + + m_space->write_byte(page_offset() + offset, data); +} + +READ8_MEMBER( wd7600_device::dma_read_word ) +{ + if (m_dma_channel == -1) + return 0xff; + + UINT16 result = m_space->read_word(page_offset() + (offset << 1)); + m_dma_high_byte = result >> 8; + + return result; +} + +WRITE8_MEMBER( wd7600_device::dma_write_word ) +{ + if (m_dma_channel == -1) + return; + + m_space->write_word(page_offset() + (offset << 1), (m_dma_high_byte << 8) | data); +} + +WRITE_LINE_MEMBER( wd7600_device::dma2_dack0_w ) +{ + m_dma1->hack_w(state ? 0 : 1); // inverted? +} + +WRITE_LINE_MEMBER( wd7600_device::dma1_eop_w ) +{ + m_dma_eop = state; + if (m_dma_channel != -1) + m_write_tc(m_dma_channel, state, 0xff); +} + +void wd7600_device::set_dma_channel(int channel, bool state) +{ + if (!state) + { + m_dma_channel = channel; + if (m_dma_eop) + m_write_tc(channel, 1, 0xff); + } + else + { + if (m_dma_channel == channel) + { + m_dma_channel = -1; + if (m_dma_eop) + m_write_tc(channel, 0, 0xff); + } + } +} + +WRITE_LINE_MEMBER( wd7600_device::gatea20_w ) +{ + keyboard_gatea20(state); +} + +WRITE_LINE_MEMBER( wd7600_device::kbrst_w ) +{ + // convert to active low signal (gets inverted in at_keybc.c) + state = (state == ASSERT_LINE ? 0 : 1); + + // detect transition + if (m_kbrst == 1 && state == 0) + { + m_write_cpureset(1); + m_write_cpureset(0); + } + + m_kbrst = state; +} + +WRITE8_MEMBER( wd7600_device::a20_reset_w ) +{ + m_alt_a20 = BIT(data,1); + a20m(); + // TODO: proper timing. Reset occurs 128 cycles after changing to a 1, and lasts for 16 cycles + if(BIT(data,0)) + { + m_write_cpureset(1); + m_write_cpureset(0); + if(LOG) logerror("WD7600 '%s': System reset\n",tag()); + } +} + +READ8_MEMBER( wd7600_device::a20_reset_r ) +{ + UINT8 ret = 0; + if(m_alt_a20) + ret |= 0x02; + return ret; +} + +// port 0x2072 - Refresh Control, and serial/parallel port address select +READ16_MEMBER(wd7600_device::refresh_r) +{ + return m_refresh_ctrl; +} + +WRITE16_MEMBER(wd7600_device::refresh_w) +{ + // TODO: select serial/parallel I/O port location + m_refresh_ctrl = data; + if(LOG) logerror("WD7600 '%s': Refresh Control write %04x\n",tag(),data); +} + +// port 0x2872 - chip select +READ16_MEMBER(wd7600_device::chipsel_r) +{ + return m_chip_sel; +} + +WRITE16_MEMBER(wd7600_device::chipsel_w) +{ + m_chip_sel = data; + if(LOG) logerror("WD7600 '%s': Chip Select write %04x\n",tag(),data); +} + +// port 0x3872 - Memory Control +READ16_MEMBER(wd7600_device::mem_ctrl_r) +{ + return m_memory_ctrl; +} + +WRITE16_MEMBER(wd7600_device::mem_ctrl_w) +{ + m_memory_ctrl = data; + if(LOG) logerror("WD7600 '%s': Memory Control write %04x\n",tag(),data); +} + +// port 0x4872 - Bank 0 and 1 start address +READ16_MEMBER(wd7600_device::bank_01_start_r) +{ + return (m_bank_start[1] << 8) | m_bank_start[0]; +} + +WRITE16_MEMBER(wd7600_device::bank_01_start_w) +{ + if(ACCESSING_BITS_0_7) + { + m_bank_start[0] = data & 0xff; + if(LOG) logerror("WD7600 '%s': Bank 0 start address %08x\n",tag(),m_bank_start[0] << 16); + } + if(ACCESSING_BITS_8_15) + { + m_bank_start[1] = (data & 0xff00) >> 8; + if(LOG) logerror("WD7600 '%s': Bank 1 start address %08x\n",tag(),m_bank_start[1] << 16); + } +} + +// port 0x5072 - Bank 2 and 3 start address +READ16_MEMBER(wd7600_device::bank_23_start_r) +{ + return (m_bank_start[3] << 8) | m_bank_start[2]; +} + +WRITE16_MEMBER(wd7600_device::bank_23_start_w) +{ + if(ACCESSING_BITS_0_7) + { + m_bank_start[2] = data & 0xff; + if(LOG) logerror("WD7600 '%s': Bank 2 start address %08x\n",tag(),m_bank_start[2] << 16); + } + if(ACCESSING_BITS_8_15) + { + m_bank_start[3] = (data & 0xff00) >> 8; + if(LOG) logerror("WD7600 '%s': Bank 3 start address %08x\n",tag(),m_bank_start[3] << 16); + } +} + +// port 0x5872 - split starting address (used for BIOS shadowing) +READ16_MEMBER(wd7600_device::split_addr_r) +{ + return m_split_start; +} + +WRITE16_MEMBER(wd7600_device::split_addr_w) +{ + m_split_start = data; + if(LOG) logerror("WD7600 '%s': Split start address write %04x\n",tag(),data); +} + +// port 0x9872 - Diagnostic +READ16_MEMBER(wd7600_device::diag_r) +{ + return m_diagnostic | 0xe080; +} + +WRITE16_MEMBER(wd7600_device::diag_w) +{ + m_diagnostic = data; + if(LOG) logerror("WD7600 '%s': Diagnostic write %04x\n",tag(),data); +} diff --git a/src/devices/machine/wd7600.h b/src/devices/machine/wd7600.h new file mode 100644 index 00000000000..7cfada03261 --- /dev/null +++ b/src/devices/machine/wd7600.h @@ -0,0 +1,240 @@ +// license:BSD-3-Clause +// copyright-holders:Barry Rodewald +/* + * wd7600.h + * + * Created on: 5/05/2014 + */ + +#ifndef WD7600_H_ +#define WD7600_H_ + +#include "emu.h" +#include "machine/am9517a.h" +#include "machine/pic8259.h" +#include "machine/pit8253.h" +#include "machine/ds128x.h" +#include "machine/at_keybc.h" +#include "machine/ram.h" + + +#define MCFG_WD7600_ADD(_tag, _clock, _cputag, _isatag, _biostag, _keybctag) \ + MCFG_DEVICE_ADD(_tag, WD7600, _clock) \ + wd7600_device::static_set_cputag(*device, _cputag); \ + wd7600_device::static_set_isatag(*device, _isatag); \ + wd7600_device::static_set_biostag(*device, _biostag); \ + wd7600_device::static_set_keybctag(*device, _keybctag); + +#define MCFG_WD7600_IOR(_ior) \ + downcast(device)->set_ior_callback(DEVCB_##_ior); + +#define MCFG_WD7600_IOW(_iow) \ + downcast(device)->set_iow_callback(DEVCB_##_iow); + +#define MCFG_WD7600_TC(_tc) \ + downcast(device)->set_tc_callback(DEVCB_##_tc); + +#define MCFG_WD7600_HOLD(_hold) \ + downcast(device)->set_hold_callback(DEVCB_##_hold); + +#define MCFG_WD7600_NMI(_nmi) \ + downcast(device)->set_nmi_callback(DEVCB_##_nmi); + +#define MCFG_WD7600_INTR(_intr) \ + downcast(device)->set_intr_callback(DEVCB_##_intr); + +#define MCFG_WD7600_CPURESET(_cpureset) \ + downcast(device)->set_cpureset_callback(DEVCB_##_cpureset); + +#define MCFG_WD7600_A20M(_a20m) \ + downcast(device)->set_a20m_callback(DEVCB_##_a20m); + +#define MCFG_WD7600_SPKR(_spkr) \ + downcast(device)->set_spkr_callback(DEVCB_##_spkr); + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> wd7600_device + +class wd7600_device : public device_t +{ +public: + // construction/destruction + wd7600_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + + // callbacks + template void set_ior_callback(_ior ior) { m_read_ior.set_callback(ior); } + template void set_iow_callback(_iow iow) { m_write_iow.set_callback(iow); } + template void set_tc_callback(_tc tc) { m_write_tc.set_callback(tc); } + template void set_hold_callback(_hold hold) { m_write_hold.set_callback(hold); } + template void set_cpureset_callback(_cpureset cpureset) { m_write_cpureset.set_callback(cpureset); } + template void set_nmi_callback(_nmi nmi) { m_write_nmi.set_callback(nmi); } + template void set_intr_callback(_intr intr) { m_write_intr.set_callback(intr); } + template void set_a20m_callback(_a20m a20m) { m_write_a20m.set_callback(a20m); } + template void set_spkr_callback(_spkr spkr) { m_write_spkr.set_callback(spkr); } + + // inline configuration + static void static_set_cputag(device_t &device, const char *tag); + static void static_set_isatag(device_t &device, const char *tag); + static void static_set_biostag(device_t &device, const char *tag); + static void static_set_keybctag(device_t &device, const char *tag); + + DECLARE_WRITE_LINE_MEMBER(rtc_irq_w); + DECLARE_WRITE_LINE_MEMBER( pic1_int_w ) { m_write_intr(state); } + DECLARE_READ8_MEMBER( pic1_slave_ack_r ); + DECLARE_WRITE_LINE_MEMBER( ctc_out1_w ); + DECLARE_WRITE_LINE_MEMBER( ctc_out2_w ); + DECLARE_WRITE8_MEMBER( rtc_w ); + DECLARE_WRITE8_MEMBER( keyb_cmd_w ); + DECLARE_WRITE8_MEMBER( keyb_data_w ); + DECLARE_READ8_MEMBER( keyb_data_r ); + DECLARE_READ8_MEMBER( keyb_status_r ); + DECLARE_WRITE8_MEMBER( a20_reset_w ); + DECLARE_READ8_MEMBER( a20_reset_r ); + DECLARE_READ8_MEMBER( portb_r ); + DECLARE_WRITE8_MEMBER( portb_w ); + DECLARE_WRITE8_MEMBER( dma_page_w ) { m_dma_page[offset & 0x0f] = data; } + DECLARE_READ8_MEMBER( dma_page_r ) { return m_dma_page[offset & 0x0f]; } + DECLARE_READ8_MEMBER( dma_read_byte ); + DECLARE_WRITE8_MEMBER( dma_write_byte ); + DECLARE_READ8_MEMBER( dma_read_word ); + DECLARE_WRITE8_MEMBER( dma_write_word ); + DECLARE_WRITE_LINE_MEMBER( dma1_eop_w ); + DECLARE_READ8_MEMBER( dma1_ior0_r ) { return m_read_ior(0); } + DECLARE_READ8_MEMBER( dma1_ior1_r ) { return m_read_ior(1); } + DECLARE_READ8_MEMBER( dma1_ior2_r ) { return m_read_ior(2); } + DECLARE_READ8_MEMBER( dma1_ior3_r ) { return m_read_ior(3); } + DECLARE_READ8_MEMBER( dma2_ior1_r ) { UINT16 result = m_read_ior(5); m_dma_high_byte = result >> 8; return result; } + DECLARE_READ8_MEMBER( dma2_ior2_r ) { UINT16 result = m_read_ior(6); m_dma_high_byte = result >> 8; return result; } + DECLARE_READ8_MEMBER( dma2_ior3_r ) { UINT16 result = m_read_ior(7); m_dma_high_byte = result >> 8; return result; } + DECLARE_WRITE8_MEMBER( dma1_iow0_w ) { m_write_iow(0, data, 0xffff); } + DECLARE_WRITE8_MEMBER( dma1_iow1_w ) { m_write_iow(1, data, 0xffff); } + DECLARE_WRITE8_MEMBER( dma1_iow2_w ) { m_write_iow(2, data, 0xffff); } + DECLARE_WRITE8_MEMBER( dma1_iow3_w ) { m_write_iow(3, data, 0xffff); } + DECLARE_WRITE8_MEMBER( dma2_iow1_w ) { m_write_iow(5, (m_dma_high_byte << 8) | data, 0xffff); } + DECLARE_WRITE8_MEMBER( dma2_iow2_w ) { m_write_iow(6, (m_dma_high_byte << 8) | data, 0xffff); } + DECLARE_WRITE8_MEMBER( dma2_iow3_w ) { m_write_iow(7, (m_dma_high_byte << 8) | data, 0xffff); } + DECLARE_WRITE_LINE_MEMBER( dma1_dack0_w ) { set_dma_channel(0, state); } + DECLARE_WRITE_LINE_MEMBER( dma1_dack1_w ) { set_dma_channel(1, state); } + DECLARE_WRITE_LINE_MEMBER( dma1_dack2_w ) { set_dma_channel(2, state); } + DECLARE_WRITE_LINE_MEMBER( dma1_dack3_w ) { set_dma_channel(3, state); } + DECLARE_WRITE_LINE_MEMBER( dma2_dack0_w ); + DECLARE_WRITE_LINE_MEMBER( dma2_dack1_w ) { set_dma_channel(5, state); } + DECLARE_WRITE_LINE_MEMBER( dma2_dack2_w ) { set_dma_channel(6, state); } + DECLARE_WRITE_LINE_MEMBER( dma2_dack3_w ) { set_dma_channel(7, state); } + DECLARE_WRITE_LINE_MEMBER( dma2_hreq_w ) { m_write_hold(state); } + + // input lines + DECLARE_WRITE_LINE_MEMBER( irq01_w ) { m_pic1->ir1_w(state); } + DECLARE_WRITE_LINE_MEMBER( irq03_w ) { m_pic1->ir3_w(state); } + DECLARE_WRITE_LINE_MEMBER( irq04_w ) { m_pic1->ir4_w(state); } + DECLARE_WRITE_LINE_MEMBER( irq05_w ) { m_pic1->ir5_w(state); } + DECLARE_WRITE_LINE_MEMBER( irq06_w ) { m_pic1->ir6_w(state); } + DECLARE_WRITE_LINE_MEMBER( irq07_w ) { m_pic1->ir7_w(state); } + DECLARE_WRITE_LINE_MEMBER( irq09_w ) { m_pic2->ir1_w(state); } + DECLARE_WRITE_LINE_MEMBER( irq10_w ) { m_pic2->ir2_w(state); } + DECLARE_WRITE_LINE_MEMBER( irq11_w ) { m_pic2->ir3_w(state); } + DECLARE_WRITE_LINE_MEMBER( irq12_w ) { m_pic2->ir4_w(state); } + DECLARE_WRITE_LINE_MEMBER( irq13_w ) { m_pic2->ir5_w(state); } // also FERR# + DECLARE_WRITE_LINE_MEMBER( irq14_w ) { m_pic2->ir6_w(state); } + DECLARE_WRITE_LINE_MEMBER( irq15_w ) { m_pic2->ir7_w(state); } + DECLARE_WRITE_LINE_MEMBER( dreq0_w ) { m_dma1->dreq0_w(state); } + DECLARE_WRITE_LINE_MEMBER( dreq1_w ) { m_dma1->dreq1_w(state); } + DECLARE_WRITE_LINE_MEMBER( dreq2_w ) { m_dma1->dreq2_w(state); } + DECLARE_WRITE_LINE_MEMBER( dreq3_w ) { m_dma1->dreq3_w(state); } + DECLARE_WRITE_LINE_MEMBER( dreq5_w ) { m_dma2->dreq1_w(state); } + DECLARE_WRITE_LINE_MEMBER( dreq6_w ) { m_dma2->dreq2_w(state); } + DECLARE_WRITE_LINE_MEMBER( dreq7_w ) { m_dma2->dreq3_w(state); } + DECLARE_WRITE_LINE_MEMBER( hlda_w ) { m_dma2->hack_w(state); } + DECLARE_WRITE_LINE_MEMBER( iochck_w ); + DECLARE_WRITE_LINE_MEMBER( gatea20_w ); + DECLARE_WRITE_LINE_MEMBER( kbrst_w ); + + DECLARE_READ16_MEMBER(refresh_r); + DECLARE_WRITE16_MEMBER(refresh_w); + DECLARE_READ16_MEMBER(chipsel_r); + DECLARE_WRITE16_MEMBER(chipsel_w); + DECLARE_READ16_MEMBER(mem_ctrl_r); + DECLARE_WRITE16_MEMBER(mem_ctrl_w); + DECLARE_READ16_MEMBER(bank_01_start_r); + DECLARE_WRITE16_MEMBER(bank_01_start_w); + DECLARE_READ16_MEMBER(bank_23_start_r); + DECLARE_WRITE16_MEMBER(bank_23_start_w); + DECLARE_READ16_MEMBER(split_addr_r); + DECLARE_WRITE16_MEMBER(split_addr_w); + DECLARE_READ16_MEMBER(diag_r); + DECLARE_WRITE16_MEMBER(diag_w); + + IRQ_CALLBACK_MEMBER(intack_cb) { return m_pic1->acknowledge(); } + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + +private: + devcb_read16 m_read_ior; + devcb_write16 m_write_iow; + devcb_write8 m_write_tc; + devcb_write_line m_write_hold; + devcb_write_line m_write_nmi; + devcb_write_line m_write_intr; + devcb_write_line m_write_cpureset; + devcb_write_line m_write_a20m; + devcb_write_line m_write_spkr; + + required_device m_dma1; + required_device m_dma2; + required_device m_pic1; + required_device m_pic2; + required_device m_ctc; + required_device m_rtc; + + offs_t page_offset(); + void set_dma_channel(int channel, bool state); + void keyboard_gatea20(int state); + void nmi(); + void a20m(); + + // internal state + const char *m_cputag; + const char *m_isatag; + const char *m_biostag; + const char *m_keybctag; + UINT8 m_portb; + int m_iochck; + int m_nmi_mask; + int m_alt_a20; + int m_ext_gatea20; + int m_kbrst; + int m_refresh_toggle; + UINT16 m_refresh_ctrl; + UINT16 m_memory_ctrl; + UINT16 m_chip_sel; + UINT16 m_split_start; + UINT8 m_bank_start[4]; + UINT16 m_diagnostic; + + int m_dma_eop; + UINT8 m_dma_page[0x10]; + UINT8 m_dma_high_byte; + int m_dma_channel; + + address_space *m_space; + address_space *m_space_io; + UINT8 *m_isa; + UINT8 *m_bios; + UINT8 *m_ram; + at_keyboard_controller_device *m_keybc; +}; + +// device type definition +extern const device_type WD7600; + +#endif /* WD7600_H_ */ diff --git a/src/devices/machine/wd_fdc.c b/src/devices/machine/wd_fdc.c new file mode 100644 index 00000000000..8b27486c79a --- /dev/null +++ b/src/devices/machine/wd_fdc.c @@ -0,0 +1,2831 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +#include "wd_fdc.h" + +#include "debugger.h" + +const device_type FD1771 = &device_creator; +const device_type FD1781 = &device_creator; +const device_type FD1791 = &device_creator; +const device_type FD1792 = &device_creator; +const device_type FD1793 = &device_creator; +const device_type KR1818VG93 = &device_creator; +const device_type FD1794 = &device_creator; +const device_type FD1795 = &device_creator; +const device_type FD1797 = &device_creator; +const device_type MB8866 = &device_creator; +const device_type MB8876 = &device_creator; +const device_type MB8877 = &device_creator; +const device_type FD1761 = &device_creator; +const device_type FD1763 = &device_creator; +const device_type FD1765 = &device_creator; +const device_type FD1767 = &device_creator; +const device_type WD2791 = &device_creator; +const device_type WD2793 = &device_creator; +const device_type WD2795 = &device_creator; +const device_type WD2797 = &device_creator; +const device_type WD1770 = &device_creator; +const device_type WD1772 = &device_creator; +const device_type WD1773 = &device_creator; + +/* + Debugging flags. Set to 0 or 1. +*/ + +// Shows shift register contents +#define TRACE_SHIFT 0 + +// Shows operations on the CPU side +#define TRACE_COMP 0 + +// Shows command invocation +#define TRACE_COMMAND 0 + +// Shows sync actions +#define TRACE_SYNC 0 + +// Show control lines +#define TRACE_LINES 0 + +// Show events +#define TRACE_EVENT 0 + +// Show sector match operation +#define TRACE_MATCH 0 + +// Show track description +#define TRACE_DESC 0 + +// Show write operation on image +#define TRACE_WRITE 0 + +// Show transitions +#define TRACE_TRANSITION 0 + +// Show state machine +#define TRACE_STATE 0 + +wd_fdc_t::wd_fdc_t(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + intrq_cb(*this), + drq_cb(*this), + hld_cb(*this), + enp_cb(*this), + enmf_cb(*this) +{ + force_ready = false; +} + +void wd_fdc_t::set_force_ready(bool _force_ready) +{ + force_ready = _force_ready; +} + +void wd_fdc_t::device_start() +{ + intrq_cb.resolve(); + drq_cb.resolve(); + hld_cb.resolve(); + enp_cb.resolve(); + enmf_cb.resolve(); + + if (!has_enmf && !enmf_cb.isnull()) + logerror("%s: Warning, this chip doesn't have an ENMF line.\n", tag()); + + t_gen = timer_alloc(TM_GEN); + t_cmd = timer_alloc(TM_CMD); + t_track = timer_alloc(TM_TRACK); + t_sector = timer_alloc(TM_SECTOR); + dden = disable_mfm; + enmf = false; + floppy = 0; + status = 0x00; + + save_item(NAME(status)); + save_item(NAME(command)); + save_item(NAME(main_state)); + save_item(NAME(sub_state)); + save_item(NAME(track)); + save_item(NAME(sector)); + save_item(NAME(intrq_cond)); + save_item(NAME(cmd_buffer)); + save_item(NAME(track_buffer)); + save_item(NAME(sector_buffer)); + save_item(NAME(counter)); + save_item(NAME(status_type_1)); + save_item(NAME(last_dir)); +} + +void wd_fdc_t::device_reset() +{ + soft_reset(); +} + +void wd_fdc_t::soft_reset() +{ + command = 0x00; + main_state = IDLE; + sub_state = IDLE; + cur_live.state = IDLE; + track = 0x00; + sector = 0x01; + status = 0x00; + data = 0x00; + cmd_buffer = track_buffer = sector_buffer = -1; + counter = 0; + status_type_1 = true; + last_dir = 1; + + // gnd == enmf enabled, otherwise disabled (default) + if (!enmf_cb.isnull() && has_enmf) + enmf = enmf_cb() ? false : true; + + intrq = false; + if (!intrq_cb.isnull()) + { + intrq_cb(intrq); + } + drq = false; + if (!drq_cb.isnull()) + { + drq_cb(drq); + } + hld = false; + intrq_cond = 0; + live_abort(); + + // restore + last_dir = 1; + seek_start(RESTORE); +} + +void wd_fdc_t::set_floppy(floppy_image_device *_floppy) +{ + if(floppy == _floppy) + return; + + int prev_ready = floppy ? floppy->ready_r() : 1; + + if(floppy) { + // Warning: deselecting a drive does *not* stop its motor if it was running + floppy->setup_index_pulse_cb(floppy_image_device::index_pulse_cb()); + floppy->setup_ready_cb(floppy_image_device::ready_cb()); + } + + floppy = _floppy; + + int next_ready = floppy ? floppy->ready_r() : 1; + + if(floppy) { + if(motor_control) + floppy->mon_w(status & S_MON ? 0 : 1); + floppy->setup_index_pulse_cb(floppy_image_device::index_pulse_cb(FUNC(wd_fdc_t::index_callback), this)); + floppy->setup_ready_cb(floppy_image_device::ready_cb(FUNC(wd_fdc_t::ready_callback), this)); + } + + if(prev_ready != next_ready) + ready_callback(floppy, next_ready); +} + +void wd_fdc_t::dden_w(bool _dden) +{ + if(disable_mfm) { + logerror("%s: Error, this chip does not have a dden line\n", tag()); + return; + } + + if(dden != _dden) { + dden = _dden; + if (TRACE_LINES) logerror("%s: select %s\n", tag(), dden ? "fm" : "mfm"); + } +} + +std::string wd_fdc_t::tts(const attotime &t) +{ + char buf[256]; + int nsec = t.attoseconds() / ATTOSECONDS_PER_NANOSECOND; + sprintf(buf, "%4d.%03d,%03d,%03d", int(t.seconds()), nsec/1000000, (nsec/1000)%1000, nsec % 1000); + return buf; +} + +std::string wd_fdc_t::ttsn() +{ + return tts(machine().time()); +} + +void wd_fdc_t::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + if (TRACE_EVENT) logerror("%s: Event fired for timer %s\n", tag(), (id==TM_GEN)? "TM_GEN" : (id==TM_CMD)? "TM_CMD" : (id==TM_TRACK)? "TM_TRACK" : "TM_SECTOR"); + live_sync(); + + switch(id) { + case TM_GEN: do_generic(); break; + case TM_CMD: do_cmd_w(); break; + case TM_TRACK: do_track_w(); break; + case TM_SECTOR: do_sector_w(); break; + } + + general_continue(); +} + +void wd_fdc_t::command_end() +{ + main_state = sub_state = IDLE; + motor_timeout = 0; + + if (!drq) { + status &= ~S_BUSY; + intrq = true; + if(!intrq_cb.isnull()) + intrq_cb(intrq); + } +} + +void wd_fdc_t::seek_start(int state) +{ + if (TRACE_COMMAND) logerror("%s: seek %d (track=%d)\n", tag(), data, track); + main_state = state; + status &= ~(S_CRC|S_RNF|S_SPIN); + if(head_control) { + // TODO get value from HLT callback + if(command & 8) + status |= S_HLD; + else + status &= ~S_HLD; + } + sub_state = motor_control ? SPINUP : SPINUP_DONE; + status_type_1 = true; + seek_continue(); +} + +void wd_fdc_t::seek_continue() +{ + for(;;) { + switch(sub_state) { + case SPINUP: + if (TRACE_STATE) logerror("%s: SPINUP\n", tag()); + if(!(status & S_MON)) { + spinup(); + return; + } + if(!(command & 0x08)) + status |= S_SPIN; + sub_state = SPINUP_DONE; + break; + + case SPINUP_WAIT: + if (TRACE_STATE) logerror("%s: SPINUP_WAIT\n", tag()); + return; + + case SPINUP_DONE: + if (TRACE_STATE) logerror("%s: SPINUP_DONE\n", tag()); + if(main_state == RESTORE && floppy && !floppy->trk00_r()) { + sub_state = SEEK_WAIT_STEP_TIME; + delay_cycles(t_gen, step_times[command & 3]); + } + + if(main_state == SEEK && track == data) { + sub_state = SEEK_WAIT_STABILIZATION_TIME; + delay_cycles(t_gen, 30000); + } + + if(sub_state == SPINUP_DONE) { + counter = 0; + sub_state = SEEK_MOVE; + } + break; + + case SEEK_MOVE: + if (TRACE_STATE) logerror("%s: SEEK_MOVE\n", tag()); + if(floppy) { + floppy->dir_w(last_dir); + floppy->stp_w(0); + floppy->stp_w(1); + } + // When stepping with update, the track register is updated before seeking. + // Important for the sam coupe format code. + if(main_state == STEP && (command & 0x10)) + track += last_dir ? -1 : 1; + counter++; + sub_state = SEEK_WAIT_STEP_TIME; + delay_cycles(t_gen, step_times[command & 3]); + return; + + case SEEK_WAIT_STEP_TIME: + if (TRACE_STATE) logerror("%s: SEEK_WAIT_STEP_TIME\n", tag()); + return; + + case SEEK_WAIT_STEP_TIME_DONE: { + if (TRACE_STATE) logerror("%s: SEEK_WAIT_STEP_TIME_DONE\n", tag()); + bool done = false; + switch(main_state) { + case RESTORE: + done = floppy && !floppy->trk00_r(); + break; + case SEEK: + track += last_dir ? -1 : 1; + done = track == data; + break; + case STEP: + done = true; + break; + } + + if(done || counter == 255) { + if(main_state == RESTORE) + track = 0; + + if(command & 0x04) { + sub_state = SEEK_WAIT_STABILIZATION_TIME; + delay_cycles(t_gen, 30000); + return; + } else + sub_state = SEEK_DONE; + + } else + sub_state = SEEK_MOVE; + + break; + } + + case SEEK_WAIT_STABILIZATION_TIME: + if (TRACE_STATE) logerror("%s: SEEK_WAIT_STABILIZATION_TIME\n", tag()); + return; + + case SEEK_WAIT_STABILIZATION_TIME_DONE: + if (TRACE_STATE) logerror("%s: SEEK_WAIT_STABILIZATION_TIME_DONE\n", tag()); + sub_state = SEEK_DONE; + break; + + case SEEK_DONE: + if (TRACE_STATE) logerror("%s: SEEK_DONE\n", tag()); + status |= S_HLD; + if(command & 0x04) { + if(!is_ready()) { + status |= S_RNF; + command_end(); + return; + } + sub_state = SCAN_ID; + counter = 0; + live_start(SEARCH_ADDRESS_MARK_HEADER); + return; + } + command_end(); + return; + + case SCAN_ID: + if (TRACE_STATE) logerror("%s: SCAN_ID\n", tag()); + if(cur_live.idbuf[0] != track) { + live_start(SEARCH_ADDRESS_MARK_HEADER); + return; + } + if(cur_live.crc) { + status |= S_CRC; + live_start(SEARCH_ADDRESS_MARK_HEADER); + return; + } + command_end(); + return; + + case SCAN_ID_FAILED: + if (TRACE_STATE) logerror("%s: SCAN_ID_FAILED\n", tag()); + status |= S_RNF; + command_end(); + return; + + default: + logerror("%s: seek unknown sub-state %d\n", ttsn().c_str(), sub_state); + return; + } + } +} + +bool wd_fdc_t::sector_matches() const +{ + if(TRACE_MATCH) + logerror("%s: matching read T=%02x H=%02x S=%02x L=%02x - searched T=%02x S=%02x\n", tag(), + cur_live.idbuf[0], cur_live.idbuf[1], cur_live.idbuf[2], cur_live.idbuf[3], + track, sector); + + if(cur_live.idbuf[0] != track || cur_live.idbuf[2] != sector) + return false; + if(!side_compare || ((command & 2)==0)) + return true; + if(command & 8) + return cur_live.idbuf[1] & 1; + else + return !(cur_live.idbuf[1] & 1); +} + +bool wd_fdc_t::is_ready() +{ + return !ready_hooked || force_ready || (floppy && !floppy->ready_r()); +} + +void wd_fdc_t::read_sector_start() +{ + if (TRACE_COMMAND) logerror("%s: read sector%s (c=%02x) t=%d, s=%d\n", tag(), command & 0x10 ? " multiple" : "", command, track, sector); + if(!is_ready()) { + command_end(); + return; + } + + main_state = READ_SECTOR; + status &= ~(S_CRC|S_LOST|S_RNF|S_WP|S_DDM); + drop_drq(); + if(side_control && floppy) + floppy->ss_w((command & 0x02) ? 1 : 0); + sub_state = motor_control ? SPINUP : SPINUP_DONE; + status_type_1 = false; + read_sector_continue(); +} + +void wd_fdc_t::read_sector_continue() +{ + for(;;) { + switch(sub_state) { + case SPINUP: + if (TRACE_STATE) logerror("%s: SPINUP\n", tag()); + if(!(status & S_MON)) { + spinup(); + return; + } + sub_state = SPINUP_DONE; + break; + + case SPINUP_WAIT: + if (TRACE_STATE) logerror("%s: SPINUP_WAIT\n", tag()); + return; + + case SPINUP_DONE: + if (TRACE_STATE) logerror("%s: SPINUP_DONE\n", tag()); + if(command & 4) { + sub_state = SETTLE_WAIT; + delay_cycles(t_gen, settle_time()); + return; + } else { + sub_state = SETTLE_DONE; + break; + } + + case SETTLE_WAIT: + if (TRACE_STATE) logerror("%s: SETTLE_WAIT\n", tag()); + return; + + case SETTLE_DONE: + if (TRACE_STATE) logerror("%s: SETTLE_DONE\n", tag()); + sub_state = SCAN_ID; + counter = 0; + live_start(SEARCH_ADDRESS_MARK_HEADER); + return; + + case SCAN_ID: + if (TRACE_STATE) logerror("%s: SCAN_ID\n", tag()); + if(!sector_matches()) { + live_start(SEARCH_ADDRESS_MARK_HEADER); + return; + } + if(cur_live.crc) { + status |= S_CRC; + live_start(SEARCH_ADDRESS_MARK_HEADER); + return; + } + sector_size = calc_sector_size(cur_live.idbuf[3], command); + sub_state = SECTOR_READ; + live_start(SEARCH_ADDRESS_MARK_DATA); + return; + + case SCAN_ID_FAILED: + if (TRACE_STATE) logerror("%s: SCAN_ID_FAILED\n", tag()); + status |= S_RNF; + command_end(); + return; + + case SECTOR_READ: + if (TRACE_STATE) logerror("%s: SECTOR_READ\n", tag()); + if(cur_live.crc) + status |= S_CRC; + + if(command & 0x10 && !(status & S_RNF)) { + sector++; + sub_state = SETTLE_DONE; + } else { + command_end(); + return; + } + break; + + default: + logerror("%s: read sector unknown sub-state %d\n", ttsn().c_str(), sub_state); + return; + } + } +} + +void wd_fdc_t::read_track_start() +{ + if (TRACE_COMMAND) logerror("%s: read track (c=%02x) t=%d\n", tag(), command, track); + + if(!is_ready()) { + command_end(); + return; + } + + main_state = READ_TRACK; + status &= ~(S_LOST|S_RNF); + drop_drq(); + if(side_control && floppy) + floppy->ss_w((command & 0x02) ? 1 : 0); + sub_state = motor_control ? SPINUP : SPINUP_DONE; + status_type_1 = false; + read_track_continue(); +} + +void wd_fdc_t::read_track_continue() +{ + for(;;) { + switch(sub_state) { + case SPINUP: + if (TRACE_STATE) logerror("%s: SPINUP\n", tag()); + if(!(status & S_MON)) { + spinup(); + return; + } + sub_state = SPINUP_DONE; + break; + + case SPINUP_WAIT: + if (TRACE_STATE) logerror("%s: SPINUP_WAIT\n", tag()); + return; + + case SPINUP_DONE: + if (TRACE_STATE) logerror("%s: SPINUP_DONE\n", tag()); + if(command & 4) { + sub_state = SETTLE_WAIT; + delay_cycles(t_gen, settle_time()); + return; + + } else { + sub_state = SETTLE_DONE; + break; + } + + case SETTLE_WAIT: + if (TRACE_STATE) logerror("%s: SETTLE_WAIT\n", tag()); + return; + + case SETTLE_DONE: + if (TRACE_STATE) logerror("%s: SETTLE_DONE\n", tag()); + sub_state = WAIT_INDEX; + return; + + case WAIT_INDEX: + if (TRACE_STATE) logerror("%s: WAIT_INDEX\n", tag()); + return; + + case WAIT_INDEX_DONE: + if (TRACE_STATE) logerror("%s: WAIT_INDEX_DONE\n", tag()); + sub_state = TRACK_DONE; + live_start(READ_TRACK_DATA); + return; + + case TRACK_DONE: + if (TRACE_STATE) logerror("%s: TRACK_DONE\n", tag()); + command_end(); + return; + + default: + logerror("%s: read track unknown sub-state %d\n", ttsn().c_str(), sub_state); + return; + } + } +} + +void wd_fdc_t::read_id_start() +{ + if (TRACE_COMMAND) logerror("%s: read id (c=%02x)\n", tag(), command); + if(!is_ready()) { + command_end(); + return; + } + + main_state = READ_ID; + status &= ~(S_WP|S_DDM|S_LOST|S_RNF); + drop_drq(); + if(side_control && floppy) + floppy->ss_w((command & 0x02) ? 1 : 0); + sub_state = motor_control ? SPINUP : SPINUP_DONE; + status_type_1 = false; + read_id_continue(); +} + +void wd_fdc_t::read_id_continue() +{ + for(;;) { + switch(sub_state) { + case SPINUP: + if (TRACE_STATE) logerror("%s: SPINUP\n", tag()); + if(!(status & S_MON)) { + spinup(); + return; + } + sub_state = SPINUP_DONE; + break; + + case SPINUP_WAIT: + if (TRACE_STATE) logerror("%s: SPINUP_WAIT\n", tag()); + return; + + case SPINUP_DONE: + if (TRACE_STATE) logerror("%s: SPINUP_DONE\n", tag()); + if(command & 4) { + sub_state = SETTLE_WAIT; + delay_cycles(t_gen, settle_time()); + return; + } else { + sub_state = SETTLE_DONE; + break; + } + + case SETTLE_WAIT: + if (TRACE_STATE) logerror("%s: SETTLE_WAIT\n", tag()); + return; + + case SETTLE_DONE: + if (TRACE_STATE) logerror("%s: SETTLE_DONE\n", tag()); + sub_state = SCAN_ID; + counter = 0; + live_start(SEARCH_ADDRESS_MARK_HEADER); + return; + + case SCAN_ID: + if (TRACE_STATE) logerror("%s: SCAN_ID\n", tag()); + command_end(); + return; + + case SCAN_ID_FAILED: + if (TRACE_STATE) logerror("%s: SCAN_ID_FAILED\n", tag()); + status |= S_RNF; + command_end(); + return; + + default: + logerror("%s: read id unknown sub-state %d\n", ttsn().c_str(), sub_state); + return; + } + } +} + +void wd_fdc_t::write_track_start() +{ + if (TRACE_COMMAND) logerror("%s: write track (c=%02x) t=%d\n", tag(), command, track); + + if(!is_ready()) { + command_end(); + return; + } + + main_state = WRITE_TRACK; + status &= ~(S_WP|S_DDM|S_LOST|S_RNF); + drop_drq(); + if(side_control && floppy) + floppy->ss_w((command & 0x02) ? 1 : 0); + sub_state = motor_control ? SPINUP : SPINUP_DONE; + status_type_1 = false; + + format_last_byte = 0; + format_last_byte_count = 0; + format_description_string = ""; + + write_track_continue(); +} + +void wd_fdc_t::write_track_continue() +{ + for(;;) { + switch(sub_state) { + case SPINUP: + if (TRACE_STATE) logerror("%s: SPINUP\n", tag()); + if(!(status & S_MON)) { + spinup(); + return; + } + sub_state = SPINUP_DONE; + break; + + case SPINUP_WAIT: + if (TRACE_STATE) logerror("%s: SPINUP_WAIT\n", tag()); + return; + + case SPINUP_DONE: + if (TRACE_STATE) logerror("%s: SPINUP_DONE\n", tag()); + if(command & 4) { + sub_state = SETTLE_WAIT; + delay_cycles(t_gen, settle_time()); + return; + } else { + sub_state = SETTLE_DONE; + break; + } + + case SETTLE_WAIT: + if (TRACE_STATE) logerror("%s: SETTLE_WAIT\n", tag()); + return; + + case SETTLE_DONE: + if (TRACE_STATE) logerror("%s: SETTLE_DONE\n", tag()); + set_drq(); + sub_state = DATA_LOAD_WAIT; + delay_cycles(t_gen, 192); + return; + + case DATA_LOAD_WAIT: + if (TRACE_STATE) logerror("%s: DATA_LOAD_WAIT\n", tag()); + return; + + case DATA_LOAD_WAIT_DONE: + if (TRACE_STATE) logerror("%s: DATA_LOAD_WAIT_DONE\n", tag()); + if(drq) { + status |= S_LOST; + drop_drq(); + command_end(); + return; + } + sub_state = WAIT_INDEX; + break; + + case WAIT_INDEX: + if (TRACE_STATE) logerror("%s: WAIT_INDEX\n", tag()); + return; + + case WAIT_INDEX_DONE: + if (TRACE_STATE) logerror("%s: WAIT_INDEX_DONE\n", tag()); + sub_state = TRACK_DONE; + live_start(WRITE_TRACK_DATA); + pll_start_writing(machine().time()); + return; + + case TRACK_DONE: + if (TRACE_STATE) logerror("%s: TRACK_DONE\n", tag()); + if(format_last_byte_count) { + char buf[32]; + if(format_last_byte_count > 1) + sprintf(buf, "%dx%02x", format_last_byte_count, format_last_byte); + else + sprintf(buf, "%02x", format_last_byte); + format_description_string += buf; + } + if (TRACE_DESC) logerror("%s: track description %s\n", tag(), format_description_string.c_str()); + command_end(); + return; + + default: + logerror("%s: write track unknown sub-state %d\n", ttsn().c_str(), sub_state); + return; + } + } +} + + +void wd_fdc_t::write_sector_start() +{ + if (TRACE_COMMAND) logerror("%s: write sector%s (c=%02x) t=%d, s=%d\n", tag(), command & 0x10 ? " multiple" : "", command, track, sector); + + if(!is_ready()) { + command_end(); + return; + } + + main_state = WRITE_SECTOR; + status &= ~(S_CRC|S_LOST|S_RNF|S_WP|S_DDM); + drop_drq(); + if(side_control && floppy) + floppy->ss_w((command & 0x02) ? 1 : 0); + sub_state = motor_control ? SPINUP : SPINUP_DONE; + status_type_1 = false; + write_sector_continue(); +} + +void wd_fdc_t::write_sector_continue() +{ + for(;;) { + switch(sub_state) { + case SPINUP: + if (TRACE_STATE) logerror("%s: SPINUP\n", tag()); + if(!(status & S_MON)) { + spinup(); + return; + } + sub_state = SPINUP_DONE; + break; + + case SPINUP_WAIT: + if (TRACE_STATE) logerror("%s: SPINUP_WAIT\n", tag()); + return; + + case SPINUP_DONE: + if (TRACE_STATE) logerror("%s: SPINUP_DONE\n", tag()); + if(command & 4) { + sub_state = SETTLE_WAIT; + delay_cycles(t_gen, settle_time()); + return; + } else { + sub_state = SETTLE_DONE; + break; + } + + case SETTLE_WAIT: + if (TRACE_STATE) logerror("%s: SETTLE_WAIT\n", tag()); + return; + + case SETTLE_DONE: + if (TRACE_STATE) logerror("%s: SETTLE_DONE\n", tag()); + sub_state = SCAN_ID; + counter = 0; + live_start(SEARCH_ADDRESS_MARK_HEADER); + return; + + case SCAN_ID: + if (TRACE_STATE) logerror("%s: SCAN_ID\n", tag()); + if(!sector_matches()) { + live_start(SEARCH_ADDRESS_MARK_HEADER); + return; + } + if(cur_live.crc) { + status |= S_CRC; + live_start(SEARCH_ADDRESS_MARK_HEADER); + return; + } + sector_size = calc_sector_size(cur_live.idbuf[3], command); + sub_state = SECTOR_WRITE; + live_start(WRITE_SECTOR_PRE); + return; + + case SCAN_ID_FAILED: + if (TRACE_STATE) logerror("%s: SCAN_ID_FAILED\n", tag()); + status |= S_RNF; + command_end(); + return; + + case SECTOR_WRITE: + if (TRACE_STATE) logerror("%s: SECTOR_WRITE\n", tag()); + if(command & 0x10) { + sector++; + sub_state = SPINUP_DONE; + } else { + command_end(); + return; + } + break; + + default: + logerror("%s: write sector unknown sub-state %d\n", ttsn().c_str(), sub_state); + return; + } + } +} + +void wd_fdc_t::interrupt_start() +{ + if (TRACE_COMMAND) logerror("%s: Forced interrupt (c=%02x)\n", tag(), command); + + if(status & S_BUSY) { + main_state = sub_state = cur_live.state = IDLE; + cur_live.tm = attotime::never; + status &= ~S_BUSY; + drop_drq(); + motor_timeout = 0; + } + else + { + // when a force interrupt command is issued and there is no + // currently running command, return the status type 1 bits + status_type_1 = true; + } + + int intcond = command & 0x0f; + if (!nonsticky_immint) { + if(intcond == 0) + intrq_cond = 0; + else + intrq_cond = (intrq_cond & I_IMM) | intcond; + } else { + if (intcond < 8) + intrq_cond = intcond; + else + intrq_cond = 0; + } + + if(command & I_IMM) { + intrq = true; + if(!intrq_cb.isnull()) + intrq_cb(intrq); + } + + if(command & 0x03) { + logerror("%s: unhandled interrupt generation (%02x)\n", ttsn().c_str(), command); + } +} + +void wd_fdc_t::general_continue() +{ + if(cur_live.state != IDLE) { + live_run(); + if(cur_live.state != IDLE) + return; + } + + switch(main_state) { + case IDLE: + break; + case RESTORE: case SEEK: case STEP: + seek_continue(); + break; + case READ_SECTOR: + read_sector_continue(); + break; + case READ_TRACK: + read_track_continue(); + break; + case READ_ID: + read_id_continue(); + break; + case WRITE_TRACK: + write_track_continue(); + break; + case WRITE_SECTOR: + write_sector_continue(); + break; + default: + logerror("%s: general_continue on unknown main-state %d\n", ttsn().c_str(), main_state); + break; + } +} + +void wd_fdc_t::do_generic() +{ + switch(sub_state) { + case IDLE: + case SCAN_ID: + case SECTOR_READ: + break; + + case SETTLE_WAIT: + sub_state = SETTLE_DONE; + break; + + case SEEK_WAIT_STEP_TIME: + sub_state = SEEK_WAIT_STEP_TIME_DONE; + break; + + case SEEK_WAIT_STABILIZATION_TIME: + sub_state = SEEK_WAIT_STABILIZATION_TIME_DONE; + break; + + case DATA_LOAD_WAIT: + sub_state = DATA_LOAD_WAIT_DONE; + break; + + default: + if(cur_live.tm.is_never()) + logerror("%s: do_generic on unknown sub-state %d\n", ttsn().c_str(), sub_state); + break; + } +} + +void wd_fdc_t::do_cmd_w() +{ + // Only available command when busy is interrupt + if(main_state != IDLE && (cmd_buffer & 0xf0) != 0xd0) { + cmd_buffer = -1; + return; + } + command = cmd_buffer; + cmd_buffer = -1; + + switch(command & 0xf0) { + case 0x00: + last_dir = 1; + seek_start(RESTORE); + break; + case 0x10: + last_dir = data > track ? 0 : 1; + seek_start(SEEK); + break; + case 0x20: + case 0x30: + seek_start(STEP); + break; + case 0x40: + case 0x50: + last_dir = 0; + seek_start(STEP); + break; + case 0x60: + case 0x70: + last_dir = 1; + seek_start(STEP); + break; + case 0x80: + case 0x90: + read_sector_start(); + break; + case 0xa0: + case 0xb0: + write_sector_start(); + break; + case 0xc0: + read_id_start(); + break; + case 0xd0: + interrupt_start(); + break; + case 0xe0: + read_track_start(); + break; + case 0xf0: + write_track_start(); + break; + } +} + +void wd_fdc_t::cmd_w(UINT8 val) +{ + if (TRACE_COMP) logerror("%s: Initiating command %02x\n", tag(), val); + if (inverted_bus) val ^= 0xff; + + if(intrq && !(intrq_cond & I_IMM)) { + intrq = false; + if(!intrq_cb.isnull()) + intrq_cb(intrq); + } + + // No more than one write in flight, but interrupts take priority + if(cmd_buffer != -1 && ((val & 0xf0) != 0xd0)) + return; + + cmd_buffer = val; + + if ((val & 0xf0) == 0xd0) + { + // force interrupt is executed instantly (?) + delay_cycles(t_cmd, 0); + } + else + { + // set busy, then set a timer to process the command + status |= S_BUSY; + delay_cycles(t_cmd, dden ? delay_command_commit*2 : delay_command_commit); + } +} + +UINT8 wd_fdc_t::status_r() +{ + if(intrq && !(intrq_cond & I_IMM)) { + intrq = false; + if(!intrq_cb.isnull()) + intrq_cb(intrq); + } + + if(status_type_1) { + if(floppy && floppy->idx_r()) + status |= S_IP; + else + status &= ~S_IP; + } else { + if(drq) + status |= S_DRQ; + else + status &= ~S_DRQ; + } + + if(status_type_1) { + status &= ~(S_TR00|S_WP); + if(floppy) { + if(floppy->wpt_r()) + status |= S_WP; + if(!floppy->trk00_r()) + status |= S_TR00; + } + } + + if(ready_hooked) { + if(!is_ready()) + status |= S_NRDY; + else + status &= ~S_NRDY; + } + + UINT8 val = status; + if (inverted_bus) val ^= 0xff; + + return val; +} + +void wd_fdc_t::do_track_w() +{ + track = track_buffer; + track_buffer = -1; +} + +void wd_fdc_t::track_w(UINT8 val) +{ + if (inverted_bus) val ^= 0xff; + + // No more than one write in flight + if(track_buffer != -1) + return; + + track_buffer = val; + delay_cycles(t_track, dden ? delay_register_commit*2 : delay_register_commit); +} + +UINT8 wd_fdc_t::track_r() +{ + UINT8 val = track; + if (inverted_bus) val ^= 0xff; + + return val; +} + +void wd_fdc_t::do_sector_w() +{ + sector = sector_buffer; + sector_buffer = -1; +} + +void wd_fdc_t::sector_w(UINT8 val) +{ + if (inverted_bus) val ^= 0xff; + + // No more than one write in flight + // C1581 accesses this register with an INC opcode, + // i.e. write old value, write new value, and the new value gets ignored by this + //if(sector_buffer != -1) + // return; + + sector_buffer = val; + + // set a timer to write the new value to the register, but only if we aren't in + // the middle of an already occurring update + if (!t_sector->enabled()) + delay_cycles(t_sector, dden ? delay_register_commit*2 : delay_register_commit); +} + +UINT8 wd_fdc_t::sector_r() +{ + UINT8 val = sector; + if (inverted_bus) val ^= 0xff; + + return val; +} + +void wd_fdc_t::data_w(UINT8 val) +{ + if (inverted_bus) val ^= 0xff; + + data = val; + drop_drq(); +} + +UINT8 wd_fdc_t::data_r() +{ + drop_drq(); + + UINT8 val = data; + if (inverted_bus) val ^= 0xff; + + return val; +} + +void wd_fdc_t::gen_w(int reg, UINT8 val) +{ + switch(reg) { + case 0: cmd_w(val); break; + case 1: track_w(val); break; + case 2: sector_w(val); break; + case 3: data_w(val); break; + } +} + +UINT8 wd_fdc_t::gen_r(int reg) +{ + switch(reg) { + case 0: return status_r(); + case 1: return track_r(); + case 2: return sector_r(); + case 3: return data_r(); + } + return 0xff; +} + +void wd_fdc_t::delay_cycles(emu_timer *tm, int cycles) +{ + tm->adjust(clocks_to_attotime(cycles*clock_ratio)); +} + +void wd_fdc_t::spinup() +{ + if(command & 0x08) + sub_state = SPINUP_DONE; + else { + sub_state = SPINUP_WAIT; + counter = 0; + } + + status |= S_MON|S_SPIN; + if(floppy) + floppy->mon_w(0); +} + +void wd_fdc_t::ready_callback(floppy_image_device *floppy, int state) +{ + // why is this even possible? + if (!floppy) + return; + + live_sync(); + if(!ready_hooked) + return; + + if(!intrq && (((intrq_cond & I_RDY) && !state) || ((intrq_cond & I_NRDY) && state))) { + intrq = true; + if(!intrq_cb.isnull()) + intrq_cb(intrq); + } +} + +void wd_fdc_t::index_callback(floppy_image_device *floppy, int state) +{ + live_sync(); + + if(!state) { + general_continue(); + return; + } + + if(!intrq && (intrq_cond & I_IDX)) { + intrq = true; + if(!intrq_cb.isnull()) + intrq_cb(intrq); + } + + switch(sub_state) { + case IDLE: + if(motor_control || head_control) { + motor_timeout ++; + if(motor_control && motor_timeout >= 5) { + status &= ~S_MON; + if(floppy) + floppy->mon_w(1); + } + + if (head_control && motor_timeout >= 3) + { + hld = false; + + // signal drive to unload head + if (!hld_cb.isnull()) + hld_cb(hld); + + status &= ~S_HLD; // todo: should get this value from the drive + } + } + break; + + case SPINUP: + break; + + case SPINUP_WAIT: + counter++; + if(counter == 6) { + sub_state = SPINUP_DONE; + if(status_type_1) + status |= S_SPIN; + } + break; + + case SPINUP_DONE: + case SETTLE_WAIT: + case SETTLE_DONE: + case DATA_LOAD_WAIT: + case DATA_LOAD_WAIT_DONE: + case SEEK_MOVE: + case SEEK_WAIT_STEP_TIME: + case SEEK_WAIT_STEP_TIME_DONE: + case SEEK_WAIT_STABILIZATION_TIME: + case SEEK_WAIT_STABILIZATION_TIME_DONE: + case SEEK_DONE: + case WAIT_INDEX_DONE: + case SCAN_ID_FAILED: + case SECTOR_READ: + case SECTOR_WRITE: + break; + + case SCAN_ID: + counter++; + if(counter == 5) { + sub_state = SCAN_ID_FAILED; + live_abort(); + } + break; + + case WAIT_INDEX: + sub_state = WAIT_INDEX_DONE; + break; + + case TRACK_DONE: + live_abort(); + break; + + default: + logerror("%s: Index pulse on unknown sub-state %d\n", ttsn().c_str(), sub_state); + break; + } + + general_continue(); +} + +bool wd_fdc_t::intrq_r() +{ + return intrq; +} + +bool wd_fdc_t::drq_r() +{ + return drq; +} + +bool wd_fdc_t::hld_r() +{ + return hld; +} + +void wd_fdc_t::hlt_w(bool state) +{ + hlt = state; +} + +bool wd_fdc_t::enp_r() +{ + return enp; +} + +void wd_fdc_t::live_start(int state) +{ + cur_live.tm = machine().time(); + cur_live.state = state; + cur_live.next_state = -1; + cur_live.shift_reg = 0; + cur_live.crc = 0xffff; + cur_live.bit_counter = 0; + cur_live.data_separator_phase = false; + cur_live.data_reg = 0; + cur_live.previous_type = live_info::PT_NONE; + cur_live.data_bit_context = false; + cur_live.byte_counter = 0; + + if (!enmf_cb.isnull() && has_enmf) + enmf = enmf_cb() ? false : true; + + pll_reset(dden, enmf, cur_live.tm); + checkpoint_live = cur_live; + pll_save_checkpoint(); + + live_run(); +} + +void wd_fdc_t::checkpoint() +{ + pll_commit(floppy, cur_live.tm); + checkpoint_live = cur_live; + pll_save_checkpoint(); +} + +void wd_fdc_t::rollback() +{ + cur_live = checkpoint_live; + pll_retrieve_checkpoint(); +} + +void wd_fdc_t::live_delay(int state) +{ + cur_live.next_state = state; + t_gen->adjust(cur_live.tm - machine().time()); +} + +void wd_fdc_t::live_sync() +{ + if(!cur_live.tm.is_never()) { + if(cur_live.tm > machine().time()) { + if (TRACE_SYNC) logerror("%s: Rolling back and replaying (%s)\n", ttsn().c_str(), tts(cur_live.tm).c_str()); + rollback(); + live_run(machine().time()); + pll_commit(floppy, cur_live.tm); + } else { + if (TRACE_SYNC) logerror("%s: Committing (%s)\n", ttsn().c_str(), tts(cur_live.tm).c_str()); + pll_commit(floppy, cur_live.tm); + if(cur_live.next_state != -1) { + cur_live.state = cur_live.next_state; + cur_live.next_state = -1; + } + if(cur_live.state == IDLE) { + pll_stop_writing(floppy, cur_live.tm); + cur_live.tm = attotime::never; + } + } + cur_live.next_state = -1; + checkpoint(); + } +} + +void wd_fdc_t::live_abort() +{ + if(!cur_live.tm.is_never() && cur_live.tm > machine().time()) { + rollback(); + live_run(machine().time()); + } + + pll_stop_writing(floppy, cur_live.tm); + cur_live.tm = attotime::never; + cur_live.state = IDLE; + cur_live.next_state = -1; +} + +bool wd_fdc_t::read_one_bit(const attotime &limit) +{ + int bit = pll_get_next_bit(cur_live.tm, floppy, limit); + if(bit < 0) + return true; + cur_live.shift_reg = (cur_live.shift_reg << 1) | bit; + cur_live.bit_counter++; + if(cur_live.data_separator_phase) { + cur_live.data_reg = (cur_live.data_reg << 1) | bit; + if((cur_live.crc ^ (bit ? 0x8000 : 0x0000)) & 0x8000) + cur_live.crc = (cur_live.crc << 1) ^ 0x1021; + else + cur_live.crc = cur_live.crc << 1; + } + cur_live.data_separator_phase = !cur_live.data_separator_phase; + return false; +} + +bool wd_fdc_t::write_one_bit(const attotime &limit) +{ + bool bit = cur_live.shift_reg & 0x8000; + if(pll_write_next_bit(bit, cur_live.tm, floppy, limit)) + return true; + if(cur_live.bit_counter & 1) { + if((cur_live.crc ^ (bit ? 0x8000 : 0x0000)) & 0x8000) + cur_live.crc = (cur_live.crc << 1) ^ 0x1021; + else + cur_live.crc = cur_live.crc << 1; + } + cur_live.shift_reg = cur_live.shift_reg << 1; + cur_live.bit_counter--; + return false; +} + +void wd_fdc_t::live_write_raw(UINT16 raw) +{ + if (TRACE_WRITE) logerror("%s: write raw %04x, CRC=%04x\n", tag(), raw, cur_live.crc); + cur_live.shift_reg = raw; + cur_live.data_bit_context = raw & 1; +} + +void wd_fdc_t::live_write_mfm(UINT8 mfm) +{ + bool context = cur_live.data_bit_context; + UINT16 raw = 0; + for(int i=0; i<8; i++) { + bool bit = mfm & (0x80 >> i); + if(!(bit || context)) + raw |= 0x8000 >> (2*i); + if(bit) + raw |= 0x4000 >> (2*i); + context = bit; + } + cur_live.shift_reg = raw; + cur_live.data_bit_context = context; + if (TRACE_WRITE) logerror("%s: live_write_mfm byte=%02x, raw=%04x, CRC=%04x\n", tag(), mfm, raw, cur_live.crc); +} + + +void wd_fdc_t::live_write_fm(UINT8 fm) +{ + UINT16 raw = 0xaaaa; + for(int i=0; i<8; i++) + if(fm & (0x80 >> i)) + raw |= 0x4000 >> (2*i); + cur_live.data_reg = fm; + cur_live.shift_reg = raw; + cur_live.data_bit_context = fm & 1; + if (TRACE_WRITE) logerror("%s: live_write_fm byte=%02x, raw=%04x, CRC=%04x\n", tag(), fm, raw, cur_live.crc); +} + +void wd_fdc_t::live_run(attotime limit) +{ + if(cur_live.state == IDLE || cur_live.next_state != -1) + return; + + if(limit == attotime::never) { + if(floppy) + limit = floppy->time_next_index(); + if(limit == attotime::never) { + // Happens when there's no disk or if the wd is not + // connected to a drive, hence no index pulse. Force a + // sync from time to time in that case, so that the main + // cpu timeout isn't too painful. Avoids looping into + // infinity looking for data too. + + limit = machine().time() + attotime::from_msec(1); + t_gen->adjust(attotime::from_msec(1)); + } + } + + // fprintf(stderr, "%s: live_run(%s)\n", ttsn().c_str(), tts(limit).c_str()); + + for(;;) { + switch(cur_live.state) { + case SEARCH_ADDRESS_MARK_HEADER: + if(read_one_bit(limit)) + return; + + if (TRACE_SHIFT) logerror("%s: shift = %04x data=%02x c=%d\n", tts(cur_live.tm).c_str(), cur_live.shift_reg, + (cur_live.shift_reg & 0x4000 ? 0x80 : 0x00) | + (cur_live.shift_reg & 0x1000 ? 0x40 : 0x00) | + (cur_live.shift_reg & 0x0400 ? 0x20 : 0x00) | + (cur_live.shift_reg & 0x0100 ? 0x10 : 0x00) | + (cur_live.shift_reg & 0x0040 ? 0x08 : 0x00) | + (cur_live.shift_reg & 0x0010 ? 0x04 : 0x00) | + (cur_live.shift_reg & 0x0004 ? 0x02 : 0x00) | + (cur_live.shift_reg & 0x0001 ? 0x01 : 0x00), + cur_live.bit_counter); + + if(!dden && cur_live.shift_reg == 0x4489) { + cur_live.crc = 0x443b; + cur_live.data_separator_phase = false; + cur_live.bit_counter = 0; + cur_live.state = READ_HEADER_BLOCK_HEADER; + } + + if(dden && cur_live.shift_reg == 0xf57e) { + cur_live.crc = 0xef21; + cur_live.data_separator_phase = false; + cur_live.bit_counter = 0; + if(main_state == READ_ID) + cur_live.state = READ_ID_BLOCK_TO_DMA; + else + cur_live.state = READ_ID_BLOCK_TO_LOCAL; + } + break; + + case READ_HEADER_BLOCK_HEADER: { + if(read_one_bit(limit)) + return; + + if (TRACE_SHIFT) logerror("%s: shift = %04x data=%02x counter=%d\n", tts(cur_live.tm).c_str(), cur_live.shift_reg, + (cur_live.shift_reg & 0x4000 ? 0x80 : 0x00) | + (cur_live.shift_reg & 0x1000 ? 0x40 : 0x00) | + (cur_live.shift_reg & 0x0400 ? 0x20 : 0x00) | + (cur_live.shift_reg & 0x0100 ? 0x10 : 0x00) | + (cur_live.shift_reg & 0x0040 ? 0x08 : 0x00) | + (cur_live.shift_reg & 0x0010 ? 0x04 : 0x00) | + (cur_live.shift_reg & 0x0004 ? 0x02 : 0x00) | + (cur_live.shift_reg & 0x0001 ? 0x01 : 0x00), + cur_live.bit_counter); + + if(cur_live.bit_counter & 15) + break; + + int slot = cur_live.bit_counter >> 4; + + if(slot < 3) { + if(cur_live.shift_reg != 0x4489) + cur_live.state = SEARCH_ADDRESS_MARK_HEADER; + break; + } + if(cur_live.data_reg != 0xfe && cur_live.data_reg != 0xff) { + cur_live.state = SEARCH_ADDRESS_MARK_HEADER; + break; + } + + cur_live.bit_counter = 0; + + if(main_state == READ_ID) + cur_live.state = READ_ID_BLOCK_TO_DMA; + else + cur_live.state = READ_ID_BLOCK_TO_LOCAL; + + break; + } + + case READ_ID_BLOCK_TO_LOCAL: { + if(read_one_bit(limit)) + return; + if(cur_live.bit_counter & 15) + break; + int slot = (cur_live.bit_counter >> 4)-1; + // fprintf(stderr, "%s: slot[%d] = %02x crc = %04x\n", tts(cur_live.tm).c_str(), slot, cur_live.data_reg, cur_live.crc); + cur_live.idbuf[slot] = cur_live.data_reg; + if(slot == 5) { + live_delay(IDLE); + return; + } + break; + } + + case READ_ID_BLOCK_TO_DMA: + if(read_one_bit(limit)) + return; + if(cur_live.bit_counter & 15) + break; + live_delay(READ_ID_BLOCK_TO_DMA_BYTE); + return; + + case READ_ID_BLOCK_TO_DMA_BYTE: + data = cur_live.data_reg; + if(cur_live.bit_counter == 16) + sector = data; + set_drq(); + + if(cur_live.bit_counter == 16*6) { + if(cur_live.crc) { + status |= S_CRC; + } + + // Already synchronous + cur_live.state = IDLE; + return; + } + + cur_live.state = READ_ID_BLOCK_TO_DMA; + checkpoint(); + break; + + case SEARCH_ADDRESS_MARK_DATA: + if(read_one_bit(limit)) + return; + + if (TRACE_SHIFT) logerror("%s: shift = %04x data=%02x c=%d.%x\n", tts(cur_live.tm).c_str(), cur_live.shift_reg, + (cur_live.shift_reg & 0x4000 ? 0x80 : 0x00) | + (cur_live.shift_reg & 0x1000 ? 0x40 : 0x00) | + (cur_live.shift_reg & 0x0400 ? 0x20 : 0x00) | + (cur_live.shift_reg & 0x0100 ? 0x10 : 0x00) | + (cur_live.shift_reg & 0x0040 ? 0x08 : 0x00) | + (cur_live.shift_reg & 0x0010 ? 0x04 : 0x00) | + (cur_live.shift_reg & 0x0004 ? 0x02 : 0x00) | + (cur_live.shift_reg & 0x0001 ? 0x01 : 0x00), + cur_live.bit_counter >> 4, cur_live.bit_counter & 15); + + if(!dden) { + if(cur_live.bit_counter > 43*16) { + live_delay(SEARCH_ADDRESS_MARK_DATA_FAILED); + return; + } + + if(cur_live.bit_counter >= 28*16 && cur_live.shift_reg == 0x4489) { + cur_live.crc = 0x443b; + cur_live.data_separator_phase = false; + cur_live.bit_counter = 0; + cur_live.state = READ_DATA_BLOCK_HEADER; + } + } else { + if(cur_live.bit_counter > 23*16) { + live_delay(SEARCH_ADDRESS_MARK_DATA_FAILED); + return; + } + + if(cur_live.bit_counter >= 11*16 && (cur_live.shift_reg == 0xf56a || cur_live.shift_reg == 0xf56b || + cur_live.shift_reg == 0xf56e || cur_live.shift_reg == 0xf56f)) { + cur_live.crc = + cur_live.shift_reg == 0xf56a ? 0x8fe7 : + cur_live.shift_reg == 0xf56b ? 0x9fc6 : + cur_live.shift_reg == 0xf56e ? 0xafa5 : + 0xbf84; + + if((cur_live.data_reg & 0xfe) == 0xf8) + status |= S_DDM; + + cur_live.data_separator_phase = false; + cur_live.bit_counter = 0; + cur_live.state = READ_SECTOR_DATA; + } + } + break; + + case READ_DATA_BLOCK_HEADER: { + if(read_one_bit(limit)) + return; + + if (TRACE_SHIFT) logerror("%s: shift = %04x data=%02x counter=%d\n", tts(cur_live.tm).c_str(), cur_live.shift_reg, + (cur_live.shift_reg & 0x4000 ? 0x80 : 0x00) | + (cur_live.shift_reg & 0x1000 ? 0x40 : 0x00) | + (cur_live.shift_reg & 0x0400 ? 0x20 : 0x00) | + (cur_live.shift_reg & 0x0100 ? 0x10 : 0x00) | + (cur_live.shift_reg & 0x0040 ? 0x08 : 0x00) | + (cur_live.shift_reg & 0x0010 ? 0x04 : 0x00) | + (cur_live.shift_reg & 0x0004 ? 0x02 : 0x00) | + (cur_live.shift_reg & 0x0001 ? 0x01 : 0x00), + cur_live.bit_counter); + + if(cur_live.bit_counter & 15) + break; + + int slot = cur_live.bit_counter >> 4; + + if(slot < 3) { + if(cur_live.shift_reg != 0x4489) { + live_delay(SEARCH_ADDRESS_MARK_DATA_FAILED); + return; + } + break; + } + if((cur_live.data_reg & 0xfe) != 0xfa && (cur_live.data_reg & 0xfe) != 0xf8) { + live_delay(SEARCH_ADDRESS_MARK_DATA_FAILED); + return; + } + + cur_live.bit_counter = 0; + if((cur_live.data_reg & 0xfe) == 0xf8) + status |= S_DDM; + live_delay(READ_SECTOR_DATA); + return; + } + + case SEARCH_ADDRESS_MARK_DATA_FAILED: + status |= S_RNF; + cur_live.state = IDLE; + return; + + case READ_SECTOR_DATA: { + if(read_one_bit(limit)) + return; + if(cur_live.bit_counter & 15) + break; + int slot = (cur_live.bit_counter >> 4)-1; + if(slot < sector_size) { + // Sector data + live_delay(READ_SECTOR_DATA_BYTE); + return; + + } else if(slot < sector_size+2) { + // CRC + if(slot == sector_size+1) { + live_delay(IDLE); + return; + } + } + break; + } + + case READ_SECTOR_DATA_BYTE: + data = cur_live.data_reg; + set_drq(); + cur_live.state = READ_SECTOR_DATA; + checkpoint(); + break; + + case READ_TRACK_DATA: { + if(read_one_bit(limit)) + return; + if(cur_live.bit_counter != 16 + && cur_live.shift_reg != 0x4489 + && cur_live.shift_reg != 0x5224) + break; + + // Incorrect, hmmm + // Probably >2 + not just after a sync if <16 + + // Transitions 00..00 -> 4489.4489.4489 at varied syncs: + // 0: 00.00.14.a1 1: ff.fe.c2.a1 2: 00.01.14.a1 3: ff.fc.c2.a1 + // 4: 00.02.14.a1 5: ff.f8.c2.a1 6: 00.05.14.a1 7: ff.f0.c2.a1 + // 8: 00.00.0a.a1 9: ff.ff.e1.a1 10: 00.00.14.a1 11: ff.ff.ce.a1 + // 12: 00.00.14.a1 13: ff.ff.c2.a1 14: 00.00.14.a1 15: ff.ff.c2.a1 + + bool output_byte = cur_live.bit_counter > 5; + + cur_live.data_separator_phase = false; + cur_live.bit_counter = 0; + + if(output_byte) { + live_delay(READ_TRACK_DATA_BYTE); + return; + } + break; + } + + case READ_TRACK_DATA_BYTE: + data = cur_live.data_reg; + set_drq(); + cur_live.state = READ_TRACK_DATA; + checkpoint(); + break; + + case WRITE_TRACK_DATA: + if(drq) { + status |= S_LOST; + data = 0; + } + if(data != format_last_byte) { + if(format_last_byte_count) { + char buf[32]; + if(format_last_byte_count > 1) + sprintf(buf, "%dx%02x ", format_last_byte_count, format_last_byte); + else + sprintf(buf, "%02x ", format_last_byte); + format_description_string += buf; + } + format_last_byte = data; + format_last_byte_count = 1; + } else + format_last_byte_count++; + + if(dden) { + switch(data) { + case 0xf7: + if(cur_live.previous_type == live_info::PT_CRC_2) { + cur_live.previous_type = live_info::PT_NONE; + live_write_fm(0xf7); + } else { + cur_live.previous_type = live_info::PT_CRC_1; + live_write_fm(cur_live.crc >> 8); + } + break; + case 0xf8: + live_write_raw(0xf56a); + cur_live.crc = 0xffff; + cur_live.previous_type = live_info::PT_NONE; + break; + case 0xf9: + live_write_raw(0xf56b); + cur_live.crc = 0xffff; + cur_live.previous_type = live_info::PT_NONE; + break; + case 0xfa: + live_write_raw(0xf56e); + cur_live.crc = 0xffff; + cur_live.previous_type = live_info::PT_NONE; + break; + case 0xfb: + live_write_raw(0xf56f); + cur_live.crc = 0xffff; + cur_live.previous_type = live_info::PT_NONE; + break; + case 0xfc: + live_write_raw(0xf77a); + cur_live.previous_type = live_info::PT_NONE; + break; + case 0xfe: + live_write_raw(0xf57e); + cur_live.crc = 0xffff; + cur_live.previous_type = live_info::PT_NONE; + break; + default: + cur_live.previous_type = live_info::PT_NONE; + live_write_fm(data); + break; + } + + } else { + switch(data) { + case 0xf5: + live_write_raw(0x4489); + cur_live.crc = 0x968b; // Ensures that the crc is cdb4 after writing the byte + cur_live.previous_type = live_info::PT_NONE; + break; + case 0xf6: + cur_live.previous_type = live_info::PT_NONE; + live_write_raw(0x5224); + break; + case 0xf7: + if(cur_live.previous_type == live_info::PT_CRC_2) { + cur_live.previous_type = live_info::PT_NONE; + live_write_mfm(0xf7); + } else { + cur_live.previous_type = live_info::PT_CRC_1; + live_write_mfm(cur_live.crc >> 8); + } + break; + default: + cur_live.previous_type = live_info::PT_NONE; + live_write_mfm(data); + break; + } + } + set_drq(); + cur_live.state = WRITE_BYTE; + cur_live.bit_counter = 16; + checkpoint(); + break; + + case WRITE_BYTE: + if(write_one_bit(limit)) + return; + if(cur_live.bit_counter == 0) { + live_delay(WRITE_BYTE_DONE); + return; + } + break; + + case WRITE_BYTE_DONE: + switch(sub_state) { + case TRACK_DONE: + if(cur_live.previous_type == live_info::PT_CRC_1) { + cur_live.previous_type = live_info::PT_CRC_2; + if(dden) + live_write_fm(cur_live.crc >> 8); + else + live_write_mfm(cur_live.crc >> 8); + cur_live.state = WRITE_BYTE; + cur_live.bit_counter = 16; + checkpoint(); + } else + cur_live.state = WRITE_TRACK_DATA; + break; + + case SECTOR_WRITE: + cur_live.state = WRITE_BYTE; + cur_live.bit_counter = 16; + cur_live.byte_counter++; + + if(dden) { + if(cur_live.byte_counter < 6) + live_write_fm(0x00); + else if(cur_live.byte_counter < 7) { + cur_live.crc = 0xffff; + live_write_raw(command & 1 ? 0xf56a : 0xf56f); + } else if(cur_live.byte_counter < sector_size + 7-1) { + if(drq) { + status |= S_LOST; + data = 0; + } + live_write_fm(data); + set_drq(); + } else if(cur_live.byte_counter < sector_size + 7) { + if(drq) { + status |= S_LOST; + data = 0; + } + live_write_fm(data); + } else if(cur_live.byte_counter < sector_size + 7+2) + live_write_fm(cur_live.crc >> 8); + else if(cur_live.byte_counter < sector_size + 7+3) + live_write_fm(0xff); + else { + pll_stop_writing(floppy, cur_live.tm); + cur_live.state = IDLE; + return; + } + + } else { + if(cur_live.byte_counter < 12) + live_write_mfm(0x00); + else if(cur_live.byte_counter < 15) + live_write_raw(0x4489); + else if(cur_live.byte_counter < 16) { + cur_live.crc = 0xcdb4; + live_write_mfm(command & 1 ? 0xf8 : 0xfb); + + } else if(cur_live.byte_counter < sector_size + 16-1) { + if(drq) { + status |= S_LOST; + data = 0; + } + live_write_mfm(data); + set_drq(); + } else if(cur_live.byte_counter < sector_size + 16) { + if(drq) { + status |= S_LOST; + data = 0; + } + live_write_mfm(data); + } else if(cur_live.byte_counter < sector_size + 16+2) + live_write_mfm(cur_live.crc >> 8); + else if(cur_live.byte_counter < sector_size + 16+3) + live_write_mfm(0xff); + else { + pll_stop_writing(floppy, cur_live.tm); + cur_live.state = IDLE; + return; + } + } + + + checkpoint(); + break; + + default: + logerror("%s: Unknown sub state %d in WRITE_BYTE_DONE\n", tts(cur_live.tm).c_str(), sub_state); + live_abort(); + return; + } + break; + + case WRITE_SECTOR_PRE: + if(read_one_bit(limit)) + return; + if(cur_live.bit_counter != 16) + break; + live_delay(WRITE_SECTOR_PRE_BYTE); + return; + + case WRITE_SECTOR_PRE_BYTE: + cur_live.state = WRITE_SECTOR_PRE; + cur_live.byte_counter++; + cur_live.bit_counter = 0; + switch(cur_live.byte_counter) { + case 2: + set_drq(); + checkpoint(); + break; + + // MZ: There is an inconsistency in the wd177x specs; compare + // the flow chart and the text of the section "Write sector" (1-9) and + // pages 1-17 and 1-18. + // + // I suppose the sum of the delays in the flow chart should be + // 11 and 22, so we shorten the 9-byte delay to 8 bytes. + + // case 11: + case 10: + if(drq) { + status |= S_LOST; + cur_live.state = IDLE; + return; + } + break; + // case 12: + case 11: + if(dden) { + cur_live.state = WRITE_BYTE; + cur_live.bit_counter = 16; + cur_live.byte_counter = 0; + cur_live.data_bit_context = cur_live.data_reg & 1; + pll_start_writing(cur_live.tm); + live_write_fm(0x00); + } + break; + + case 22: + cur_live.state = WRITE_BYTE; + cur_live.bit_counter = 16; + cur_live.byte_counter = 0; + cur_live.data_bit_context = cur_live.data_reg & 1; + pll_start_writing(cur_live.tm); + live_write_mfm(0x00); + break; + } + break; + + default: + logerror("%s: Unknown live state %d\n", tts(cur_live.tm).c_str(), cur_live.state); + return; + } + } +} + +void wd_fdc_t::set_drq() +{ + if(drq) { + status |= S_LOST; + drq = false; + if(!drq_cb.isnull()) + drq_cb(false); + } else if(!(status & S_LOST)) { + drq = true; + if(!drq_cb.isnull()) + drq_cb(true); + } +} + +void wd_fdc_t::drop_drq() +{ + if(drq) { + drq = false; + if(!drq_cb.isnull()) + drq_cb(false); + if (main_state == IDLE) { + status &= ~S_BUSY; + intrq = true; + if(!intrq_cb.isnull()) + intrq_cb(intrq); + } + } +} + +int wd_fdc_t::calc_sector_size(UINT8 size, UINT8 command) const +{ + return 128 << (size & 3); +} + +int wd_fdc_t::settle_time() const +{ + return 60000; +} + +wd_fdc_analog_t::wd_fdc_analog_t(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + wd_fdc_t(mconfig, type, name, tag, owner, clock, shortname, source) +{ + clock_ratio = 1; +} + +void wd_fdc_analog_t::pll_reset(bool fm, bool enmf, const attotime &when) +{ + int clocks = 2; + + if (fm) clocks *= 2; + if (enmf) clocks *= 2; + + cur_pll.reset(when); + cur_pll.set_clock(clocks_to_attotime(clocks)); +} + +void wd_fdc_analog_t::pll_start_writing(const attotime &tm) +{ + cur_pll.start_writing(tm); +} + +void wd_fdc_analog_t::pll_commit(floppy_image_device *floppy, const attotime &tm) +{ + cur_pll.commit(floppy, tm); +} + +void wd_fdc_analog_t::pll_stop_writing(floppy_image_device *floppy, const attotime &tm) +{ + cur_pll.stop_writing(floppy, tm); +} + +void wd_fdc_analog_t::pll_save_checkpoint() +{ + checkpoint_pll = cur_pll; +} + +void wd_fdc_analog_t::pll_retrieve_checkpoint() +{ + cur_pll = checkpoint_pll; +} + +int wd_fdc_analog_t::pll_get_next_bit(attotime &tm, floppy_image_device *floppy, const attotime &limit) +{ + return cur_pll.get_next_bit(tm, floppy, limit); +} + +bool wd_fdc_analog_t::pll_write_next_bit(bool bit, attotime &tm, floppy_image_device *floppy, const attotime &limit) +{ + return cur_pll.write_next_bit(bit, tm, floppy, limit); +} + +wd_fdc_digital_t::wd_fdc_digital_t(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + wd_fdc_t(mconfig, type, name, tag, owner, clock, shortname, source) +{ + clock_ratio = 4; +} + +const int wd_fdc_digital_t::wd_digital_step_times[4] = { 12000, 24000, 40000, 60000 }; + +void wd_fdc_digital_t::pll_reset(bool fm, bool enmf, const attotime &when) +{ + int clocks = 1; + + if (fm) clocks *= 2; + if (enmf) clocks *= 2; + + cur_pll.reset(when); + cur_pll.set_clock(clocks_to_attotime(clocks)); +} + +void wd_fdc_digital_t::pll_start_writing(const attotime &tm) +{ + cur_pll.start_writing(tm); +} + +void wd_fdc_digital_t::pll_commit(floppy_image_device *floppy, const attotime &tm) +{ + cur_pll.commit(floppy, tm); +} + +void wd_fdc_digital_t::pll_stop_writing(floppy_image_device *floppy, const attotime &tm) +{ + cur_pll.stop_writing(floppy, tm); +} + +int wd_fdc_digital_t::pll_get_next_bit(attotime &tm, floppy_image_device *floppy, const attotime &limit) +{ + return cur_pll.get_next_bit(tm, floppy, limit); +} + +bool wd_fdc_digital_t::pll_write_next_bit(bool bit, attotime &tm, floppy_image_device *floppy, const attotime &limit) +{ + return cur_pll.write_next_bit(bit, tm, floppy, limit); +} + +void wd_fdc_digital_t::pll_save_checkpoint() +{ + checkpoint_pll = cur_pll; +} + +void wd_fdc_digital_t::pll_retrieve_checkpoint() +{ + cur_pll = checkpoint_pll; +} + +void wd_fdc_digital_t::digital_pll_t::set_clock(const attotime &period) +{ + for(int i=0; i<42; i++) + delays[i] = period*(i+1); +} + +void wd_fdc_digital_t::digital_pll_t::reset(const attotime &when) +{ + counter = 0; + increment = 128; + transition_time = 0xffff; + history = 0x80; + slot = 0; + ctime = when; + phase_add = 0x00; + phase_sub = 0x00; + freq_add = 0x00; + freq_sub = 0x00; + write_position = 0; + write_start_time = attotime::never; +} + +int wd_fdc_digital_t::digital_pll_t::get_next_bit(attotime &tm, floppy_image_device *floppy, const attotime &limit) +{ + attotime when = floppy ? floppy->get_next_transition(ctime) : attotime::never; + + /* if (TRACE_TRANSITION) + if(!when.is_never()) + logerror("transition_time=%s\n", tts(when).c_str()); + */ + for(;;) { + // if (TRACE_TRANSITION) logerror("slot=%2d, counter=%03x\n", slot, counter); + attotime etime = ctime+delays[slot]; + // if (TRACE_TRANSITION) logerror("etime=%s\n", tts(etime).c_str()); + if(etime > limit) + return -1; + if(transition_time == 0xffff && !when.is_never() && etime >= when) + transition_time = counter; + if(slot < 8) { + UINT8 mask = 1 << slot; + if(phase_add & mask) + counter += 226; + else if(phase_sub & mask) + counter += 30; + else + counter += increment; + + if((freq_add & mask) && increment < 140) + increment++; + else if((freq_sub & mask) && increment > 117) + increment--; + } else + counter += increment; + + slot++; + tm = etime; + if(counter & 0x800) + break; + } + if (TRACE_TRANSITION) logerror("first transition, time=%03x, inc=%3d\n", transition_time, increment); + int bit = transition_time != 0xffff; + + if(transition_time != 0xffff) { + static const UINT8 pha[8] = { 0xf, 0x7, 0x3, 0x1, 0, 0, 0, 0 }; + static const UINT8 phs[8] = { 0, 0, 0, 0, 0x1, 0x3, 0x7, 0xf }; + static const UINT8 freqa[4][8] = { + { 0xf, 0x7, 0x3, 0x1, 0, 0, 0, 0 }, + { 0x7, 0x3, 0x1, 0, 0, 0, 0, 0 }, + { 0x7, 0x3, 0x1, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0 } + }; + static const UINT8 freqs[4][8] = { + { 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0x1, 0x3, 0x7 }, + { 0, 0, 0, 0, 0, 0x1, 0x3, 0x7 }, + { 0, 0, 0, 0, 0x1, 0x3, 0x7, 0xf }, + }; + + int cslot = transition_time >> 8; + phase_add = pha[cslot]; + phase_sub = phs[cslot]; + int way = transition_time & 0x400 ? 1 : 0; + if(history & 0x80) + history = way ? 0x80 : 0x83; + else if(history & 0x40) + history = way ? history & 2 : (history & 2) | 1; + freq_add = freqa[history & 3][cslot]; + freq_sub = freqs[history & 3][cslot]; + history = way ? (history >> 1) | 2 : history >> 1; + + } else + phase_add = phase_sub = freq_add = freq_sub = 0; + + counter &= 0x7ff; + + ctime = tm; + transition_time = 0xffff; + slot = 0; + + return bit; +} + +void wd_fdc_digital_t::digital_pll_t::start_writing(const attotime &tm) +{ + write_start_time = tm; + write_position = 0; +} + +void wd_fdc_digital_t::digital_pll_t::stop_writing(floppy_image_device *floppy, const attotime &tm) +{ + commit(floppy, tm); + write_start_time = attotime::never; +} + +bool wd_fdc_digital_t::digital_pll_t::write_next_bit(bool bit, attotime &tm, floppy_image_device *floppy, const attotime &limit) +{ + if(write_start_time.is_never()) { + write_start_time = ctime; + write_position = 0; + } + + for(;;) { + attotime etime = ctime+delays[slot]; + if(etime > limit) + return true; + UINT16 pre_counter = counter; + counter += increment; + if(bit && !(pre_counter & 0x400) && (counter & 0x400)) + if(write_position < ARRAY_LENGTH(write_buffer)) + write_buffer[write_position++] = etime; + slot++; + tm = etime; + if(counter & 0x800) + break; + } + + counter &= 0x7ff; + + ctime = tm; + slot = 0; + + return false; +} + +void wd_fdc_digital_t::digital_pll_t::commit(floppy_image_device *floppy, const attotime &tm) +{ + if(write_start_time.is_never() || tm == write_start_time) + return; + + if(floppy) + floppy->write_flux(write_start_time, tm, write_position, write_buffer); + write_start_time = tm; + write_position = 0; +} + +fd1771_t::fd1771_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : wd_fdc_analog_t(mconfig, FD1771, "FD1771", tag, owner, clock, "fd1771", __FILE__) +{ + const static int fd1771_step_times[4] = { 12000, 12000, 20000, 40000 }; + + step_times = fd1771_step_times; + delay_register_commit = 16; + delay_command_commit = 20; // x2 due to fm + disable_mfm = true; + inverted_bus = true; + side_control = false; + side_compare = false; + head_control = true; + motor_control = false; + ready_hooked = true; + nonsticky_immint = false; +} + +int fd1771_t::calc_sector_size(UINT8 size, UINT8 command) const +{ + if(command & 0x08) + return 128 << (size & 3); + else + return size ? size << 4 : 4096; +} + +fd1781_t::fd1781_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : wd_fdc_analog_t(mconfig, FD1781, "FD1781", tag, owner, clock, "fd1781", __FILE__) +{ + const static int fd1781_step_times[4] = { 6000, 12000, 20000, 40000 }; + + step_times = fd1781_step_times; + delay_register_commit = 16; + delay_command_commit = 12; + disable_mfm = false; + inverted_bus = true; + side_control = false; + side_compare = false; + head_control = true; + motor_control = false; + ready_hooked = true; + nonsticky_immint = false; +} + +int fd1781_t::calc_sector_size(UINT8 size, UINT8 command) const +{ + if(command & 0x08) + return 128 << (size & 3); + else + return size ? size << 4 : 4096; +} + +const int wd_fdc_t::fd179x_step_times[4] = { 6000, 12000, 20000, 30000 }; +const int wd_fdc_t::fd176x_step_times[4] = { 12000, 24000, 40000, 60000 }; + +fd1791_t::fd1791_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : wd_fdc_analog_t(mconfig, FD1791, "FD1791", tag, owner, clock, "fd1791", __FILE__) +{ + step_times = fd179x_step_times; + delay_register_commit = 4; + delay_command_commit = 12; + disable_mfm = false; + has_enmf = false; + inverted_bus = true; + side_control = false; + side_compare = true; + head_control = true; + motor_control = false; + ready_hooked = true; + nonsticky_immint = false; +} + +fd1792_t::fd1792_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : wd_fdc_analog_t(mconfig, FD1792, "FD1792", tag, owner, clock, "fd1792", __FILE__) +{ + step_times = fd179x_step_times; + delay_register_commit = 4; + delay_command_commit = 12; + disable_mfm = true; + has_enmf = false; + inverted_bus = true; + side_control = false; + side_compare = true; + head_control = true; + motor_control = false; + ready_hooked = true; + nonsticky_immint = false; +} + +fd1793_t::fd1793_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : wd_fdc_analog_t(mconfig, FD1793, "FD1793", tag, owner, clock, "fd1793", __FILE__) +{ + step_times = fd179x_step_times; + delay_register_commit = 4; + delay_command_commit = 12; + disable_mfm = false; + has_enmf = false; + inverted_bus = false; + side_control = false; + side_compare = true; + head_control = true; + motor_control = false; + ready_hooked = true; + nonsticky_immint = false; +} + +kr1818vg93_t::kr1818vg93_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : wd_fdc_analog_t(mconfig, KR1818VG93, "KR1818VG93", tag, owner, clock, "kr1818vg93", __FILE__) +{ + step_times = fd179x_step_times; + delay_register_commit = 4; + delay_command_commit = 12; + disable_mfm = false; + has_enmf = false; + inverted_bus = false; + side_control = false; + side_compare = true; + head_control = true; + motor_control = false; + ready_hooked = true; + nonsticky_immint = true; +} + +fd1794_t::fd1794_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : wd_fdc_analog_t(mconfig, FD1794, "FD1794", tag, owner, clock, "fd1794", __FILE__) +{ + step_times = fd179x_step_times; + delay_register_commit = 4; + delay_command_commit = 12; + disable_mfm = true; + has_enmf = false; + inverted_bus = false; + side_control = false; + side_compare = true; + head_control = true; + motor_control = false; + ready_hooked = true; + nonsticky_immint = false; +} + +fd1795_t::fd1795_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : wd_fdc_analog_t(mconfig, FD1795, "FD1795", tag, owner, clock, "fd1795", __FILE__) +{ + step_times = fd179x_step_times; + delay_register_commit = 4; + delay_command_commit = 12; + disable_mfm = false; + has_enmf = false; + inverted_bus = true; + side_control = true; + side_compare = false; + head_control = true; + motor_control = false; + ready_hooked = true; + nonsticky_immint = false; +} + +int fd1795_t::calc_sector_size(UINT8 size, UINT8 command) const +{ + if(command & 0x08) + return 128 << (size & 3); + else + return 128 << ((size + 1) & 3); +} + +fd1797_t::fd1797_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : wd_fdc_analog_t(mconfig, FD1797, "FD1797", tag, owner, clock, "fd1797", __FILE__) +{ + step_times = fd179x_step_times; + delay_register_commit = 4; + delay_command_commit = 12; + disable_mfm = false; + has_enmf = false; + inverted_bus = false; + side_control = true; + side_compare = false; + head_control = true; + motor_control = false; + ready_hooked = true; + nonsticky_immint = false; +} + +int fd1797_t::calc_sector_size(UINT8 size, UINT8 command) const +{ + if(command & 0x08) + return 128 << (size & 3); + else + return 128 << ((size + 1) & 3); +} + +mb8866_t::mb8866_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : wd_fdc_analog_t(mconfig, MB8866, "MB8866", tag, owner, clock, "mb8866", __FILE__) +{ + step_times = fd179x_step_times; + delay_register_commit = 4; + delay_command_commit = 12; + disable_mfm = false; + has_enmf = false; + inverted_bus = true; + side_control = false; + side_compare = true; + head_control = true; + motor_control = false; + ready_hooked = true; + nonsticky_immint = false; +} + +mb8876_t::mb8876_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : wd_fdc_analog_t(mconfig, MB8876, "MB8876", tag, owner, clock, "mb8876", __FILE__) +{ + step_times = fd179x_step_times; + delay_register_commit = 4; + delay_command_commit = 12; + disable_mfm = false; + has_enmf = false; + inverted_bus = true; + side_control = false; + side_compare = true; + head_control = true; + motor_control = false; + ready_hooked = true; + nonsticky_immint = false; +} + +mb8877_t::mb8877_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : wd_fdc_analog_t(mconfig, MB8877, "MB8877", tag, owner, clock, "mb8877", __FILE__) +{ + step_times = fd179x_step_times; + delay_register_commit = 4; + delay_command_commit = 12; + disable_mfm = false; + has_enmf = false; + inverted_bus = false; + side_control = false; + side_compare = true; + head_control = true; + motor_control = false; + ready_hooked = true; + nonsticky_immint = false; +} + +fd1761_t::fd1761_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : wd_fdc_analog_t(mconfig, FD1761, "FD1761", tag, owner, clock, "fd1761", __FILE__) +{ + step_times = fd176x_step_times; + delay_register_commit = 16; + delay_command_commit = 12; + disable_mfm = false; + has_enmf = false; + inverted_bus = true; + side_control = false; + side_compare = true; + head_control = true; + motor_control = false; + ready_hooked = true; + nonsticky_immint = false; +} + +fd1763_t::fd1763_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : wd_fdc_analog_t(mconfig, FD1763, "FD1763", tag, owner, clock, "fd1763", __FILE__) +{ + step_times = fd176x_step_times; + delay_register_commit = 16; + delay_command_commit = 12; + disable_mfm = false; + has_enmf = false; + inverted_bus = false; + side_control = false; + side_compare = true; + head_control = true; + motor_control = false; + ready_hooked = true; + nonsticky_immint = false; +} + +fd1765_t::fd1765_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : wd_fdc_analog_t(mconfig, FD1765, "FD1765", tag, owner, clock, "fd1765", __FILE__) +{ + step_times = fd176x_step_times; + delay_register_commit = 16; + delay_command_commit = 12; + disable_mfm = false; + has_enmf = false; + inverted_bus = true; + side_control = true; + side_compare = false; + head_control = true; + motor_control = false; + ready_hooked = true; + nonsticky_immint = false; +} + +int fd1765_t::calc_sector_size(UINT8 size, UINT8 command) const +{ + if(command & 0x08) + return 128 << (size & 3); + else + return 128 << ((size + 1) & 3); +} + +fd1767_t::fd1767_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : wd_fdc_analog_t(mconfig, FD1767, "FD1767", tag, owner, clock, "fd1767", __FILE__) +{ + step_times = fd179x_step_times; + delay_register_commit = 16; + delay_command_commit = 12; + disable_mfm = false; + has_enmf = false; + inverted_bus = false; + side_control = true; + side_compare = false; + head_control = true; + motor_control = false; + ready_hooked = true; + nonsticky_immint = false; +} + +int fd1767_t::calc_sector_size(UINT8 size, UINT8 command) const +{ + if(command & 0x08) + return 128 << (size & 3); + else + return 128 << ((size + 1) & 3); +} + +wd2791_t::wd2791_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : wd_fdc_analog_t(mconfig, WD2791, "WD2791", tag, owner, clock, "wd2791", __FILE__) +{ + step_times = fd179x_step_times; + delay_register_commit = 16; + delay_command_commit = 12; + disable_mfm = false; + has_enmf = true; + inverted_bus = true; + side_control = false; + side_compare = true; + head_control = true; + motor_control = false; + ready_hooked = true; + nonsticky_immint = false; +} + +wd2793_t::wd2793_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : wd_fdc_analog_t(mconfig, WD2793, "WD2793", tag, owner, clock, "wd2793", __FILE__) +{ + step_times = fd179x_step_times; + delay_register_commit = 16; + delay_command_commit = 12; + disable_mfm = false; + has_enmf = true; + inverted_bus = false; + side_control = false; + side_compare = true; + head_control = true; + motor_control = false; + ready_hooked = true; + nonsticky_immint = false; +} + +wd2795_t::wd2795_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : wd_fdc_analog_t(mconfig, WD2795, "WD2795", tag, owner, clock, "wd2795", __FILE__) +{ + step_times = fd179x_step_times; + delay_register_commit = 16; + delay_command_commit = 12; + disable_mfm = false; + has_enmf = false; + inverted_bus = true; + side_control = true; + side_compare = false; + head_control = true; + motor_control = false; + ready_hooked = true; + nonsticky_immint = false; +} + +int wd2795_t::calc_sector_size(UINT8 size, UINT8 command) const +{ + if(command & 0x08) + return 128 << (size & 3); + else + return 128 << ((size + 1) & 3); +} + +wd2797_t::wd2797_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : wd_fdc_analog_t(mconfig, WD2797, "WD2797", tag, owner, clock, "wd2797", __FILE__) +{ + step_times = fd179x_step_times; + delay_register_commit = 16; + delay_command_commit = 12; + disable_mfm = false; + has_enmf = false; + inverted_bus = false; + side_control = true; + side_compare = false; + head_control = true; + motor_control = false; + ready_hooked = true; + nonsticky_immint = false; +} + +int wd2797_t::calc_sector_size(UINT8 size, UINT8 command) const +{ + if(command & 0x08) + return 128 << (size & 3); + else + return 128 << ((size + 1) & 3); +} + +wd1770_t::wd1770_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : wd_fdc_digital_t(mconfig, WD1770, "WD1770", tag, owner, clock, "wd1770", __FILE__) +{ + step_times = wd_digital_step_times; + delay_register_commit = 32; + delay_command_commit = 36; // official 48 is too high for oric jasmin boot + disable_mfm = false; + has_enmf = false; + inverted_bus = false; + side_control = false; + side_compare = false; + head_control = false; + motor_control = true; + ready_hooked = false; + nonsticky_immint = false; +} + +wd1772_t::wd1772_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : wd_fdc_digital_t(mconfig, WD1772, "WD1772", tag, owner, clock, "wd1772", __FILE__) +{ + const static int wd1772_step_times[4] = { 12000, 24000, 4000, 6000 }; + + step_times = wd1772_step_times; + delay_register_commit = 32; + delay_command_commit = 48; + disable_mfm = false; + has_enmf = false; + inverted_bus = false; + side_control = false; + side_compare = false; + head_control = false; + motor_control = true; + ready_hooked = false; + nonsticky_immint = false; +} + +int wd1772_t::settle_time() const +{ + return 30000; +} + +wd1773_t::wd1773_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : wd_fdc_digital_t(mconfig, WD1773, "WD1773", tag, owner, clock, "wd1773", __FILE__) +{ + step_times = wd_digital_step_times; + delay_register_commit = 32; + delay_command_commit = 48; + disable_mfm = false; + has_enmf = false; + inverted_bus = false; + side_control = false; + side_compare = true; + head_control = false; + motor_control = false; + ready_hooked = true; + nonsticky_immint = false; +} diff --git a/src/devices/machine/wd_fdc.h b/src/devices/machine/wd_fdc.h new file mode 100644 index 00000000000..7af735a7bef --- /dev/null +++ b/src/devices/machine/wd_fdc.h @@ -0,0 +1,683 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +#ifndef WD_FDC_H +#define WD_FDC_H + +#include "emu.h" +#include "imagedev/floppy.h" +#include "fdc_pll.h" + +/* + * The Western Digital floppy controller family + * + + * Chip Bus SCtrl SCmp Len HLO Motor Rdy MFM clock ENMF 58 pll + + * fd1771 inverted n n y y n y n 2MHz n n analog + + * fd1781 inverted n n y y n y y 1/2MHz n n analog + + * fd1791 inverted n y n y n y y 1/2MHz n n analog + * fd1792 inverted n y n y n y n 1/2MHz n n analog + * fd1793 normal n y n y n y y 1/2MHz n n analog + * fd1794 normal n y n y n y n 1/2MHz n n analog + * fd1795 inverted y n y y n y y 1/2MHz n n analog + * fd1797 normal y n y y n y y 1/2MHz n n analog + + * mb8866 inverted n n n y n y y 1/2MHz n n analog (fd1791 compatible) + * mb8876 inverted n y n y n y y 1/2MHz n n analog (fd1791-01/02 compatible) + * mb8877 normal n y n y n y y 1/2MHz n n analog (fd1793 compatible) + + * fd1761 inverted n y n y n y y 1MHz n n analog + * fd1763 normal n y n y n y y 1MHz n n analog + * fd1765 inverted y n y y n y y 1MHz n n analog + * fd1767 normal y n y y n y y 1MHz n n analog + + * wd2791 inverted n y n y n y y 1/2MHz y y analog + * wd2793 normal n y n y n y y 1/2MHz y y analog + * wd2795 inverted y n y y n y y 1/2MHz n y analog + * wd2797 normal y n y y n y y 1/2MHz n y analog + + * wd1770 normal n n n n y n y 8Mhz n n digital + * wd1772 normal n n n n y n y 8MHz n n digital + * wd1773 normal n y n n n y y 8MHz n n digital + + */ + +#define MCFG_FD1771_ADD(_tag, _clock) \ + MCFG_DEVICE_ADD(_tag, FD1771, _clock) + +#define MCFG_FD1781_ADD(_tag, _clock) \ + MCFG_DEVICE_ADD(_tag, FD1781, _clock) + +#define MCFG_FD1791_ADD(_tag, _clock) \ + MCFG_DEVICE_ADD(_tag, FD1791, _clock) + +#define MCFG_FD1792_ADD(_tag, _clock) \ + MCFG_DEVICE_ADD(_tag, FD1792, _clock) + +#define MCFG_FD1793_ADD(_tag, _clock) \ + MCFG_DEVICE_ADD(_tag, FD1793, _clock) + +#define MCFG_KR1818VG93_ADD(_tag, _clock) \ + MCFG_DEVICE_ADD(_tag, KR1818VG93, _clock) + +#define MCFG_FD1794_ADD(_tag, _clock) \ + MCFG_DEVICE_ADD(_tag, FD1794, _clock) + +#define MCFG_FD1795_ADD(_tag, _clock) \ + MCFG_DEVICE_ADD(_tag, FD1795, _clock) + +#define MCFG_FD1797_ADD(_tag, _clock) \ + MCFG_DEVICE_ADD(_tag, FD1797, _clock) + +#define MCFG_MB8866_ADD(_tag, _clock) \ + MCFG_DEVICE_ADD(_tag, MB8866, _clock) + +#define MCFG_MB8876_ADD(_tag, _clock) \ + MCFG_DEVICE_ADD(_tag, MB8876, _clock) + +#define MCFG_MB8877_ADD(_tag, _clock) \ + MCFG_DEVICE_ADD(_tag, MB8877, _clock) + +#define MCFG_FD1761_ADD(_tag, _clock) \ + MCFG_DEVICE_ADD(_tag, FD1761, _clock) + +#define MCFG_FD1763_ADD(_tag, _clock) \ + MCFG_DEVICE_ADD(_tag, FD1763, _clock) + +#define MCFG_FD1765_ADD(_tag, _clock) \ + MCFG_DEVICE_ADD(_tag, FD1765, _clock) + +#define MCFG_FD1767_ADD(_tag, _clock) \ + MCFG_DEVICE_ADD(_tag, FD1767, _clock) + +#define MCFG_WD2791_ADD(_tag, _clock) \ + MCFG_DEVICE_ADD(_tag, WD2791, _clock) + +#define MCFG_WD2793_ADD(_tag, _clock) \ + MCFG_DEVICE_ADD(_tag, WD2793, _clock) + +#define MCFG_WD2795_ADD(_tag, _clock) \ + MCFG_DEVICE_ADD(_tag, WD2795, _clock) + +#define MCFG_WD2797_ADD(_tag, _clock) \ + MCFG_DEVICE_ADD(_tag, WD2797, _clock) + +#define MCFG_WD1770_ADD(_tag, _clock) \ + MCFG_DEVICE_ADD(_tag, WD1770, _clock) + +#define MCFG_WD1772_ADD(_tag, _clock) \ + MCFG_DEVICE_ADD(_tag, WD1772, _clock) + +#define MCFG_WD1773_ADD(_tag, _clock) \ + MCFG_DEVICE_ADD(_tag, WD1773, _clock) + +#define MCFG_WD_FDC_FORCE_READY \ + downcast(device)->set_force_ready(true); + +#define MCFG_WD_FDC_INTRQ_CALLBACK(_write) \ + devcb = &wd_fdc_t::set_intrq_wr_callback(*device, DEVCB_##_write); + +#define MCFG_WD_FDC_DRQ_CALLBACK(_write) \ + devcb = &wd_fdc_t::set_drq_wr_callback(*device, DEVCB_##_write); + +#define MCFG_WD_FDC_HLD_CALLBACK(_write) \ + devcb = &wd_fdc_t::set_hld_wr_callback(*device, DEVCB_##_write); + +#define MCFG_WD_FDC_ENP_CALLBACK(_write) \ + devcb = &wd_fdc_t::set_enp_wr_callback(*device, DEVCB_##_write); + +#define MCFG_WD_FDC_ENMF_CALLBACK(_read) \ + devcb = &wd_fdc_t::set_enmf_rd_callback(*device, DEVCB_##_read); + +class wd_fdc_t : public device_t { +public: + wd_fdc_t(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + template static devcb_base &set_intrq_wr_callback(device_t &device, _Object object) { return downcast(device).intrq_cb.set_callback(object); } + template static devcb_base &set_drq_wr_callback(device_t &device, _Object object) { return downcast(device).drq_cb.set_callback(object); } + template static devcb_base &set_hld_wr_callback(device_t &device, _Object object) { return downcast(device).hld_cb.set_callback(object); } + template static devcb_base &set_enp_wr_callback(device_t &device, _Object object) { return downcast(device).enp_cb.set_callback(object); } + template static devcb_base &set_enmf_rd_callback(device_t &device, _Object object) { return downcast(device).enmf_cb.set_callback(object); } + + void soft_reset(); + + void dden_w(bool dden); + void set_floppy(floppy_image_device *floppy); + void set_force_ready(bool force_ready); + + void cmd_w(UINT8 val); + UINT8 status_r(); + DECLARE_READ8_MEMBER( status_r ) { return status_r(); } + DECLARE_WRITE8_MEMBER( cmd_w ) { cmd_w(data); } + + void track_w(UINT8 val); + UINT8 track_r(); + DECLARE_READ8_MEMBER( track_r ) { return track_r(); } + DECLARE_WRITE8_MEMBER( track_w ) { track_w(data); } + + void sector_w(UINT8 val); + UINT8 sector_r(); + DECLARE_READ8_MEMBER( sector_r ) { return sector_r(); } + DECLARE_WRITE8_MEMBER( sector_w ) { sector_w(data); } + + void data_w(UINT8 val); + UINT8 data_r(); + DECLARE_READ8_MEMBER( data_r ) { return data_r(); } + DECLARE_WRITE8_MEMBER( data_w ) { data_w(data); } + + void gen_w(int reg, UINT8 val); + UINT8 gen_r(int reg); + DECLARE_READ8_MEMBER( read ) { return gen_r(offset);} + DECLARE_WRITE8_MEMBER( write ) { gen_w(offset,data); } + + bool intrq_r(); + bool drq_r(); + + bool hld_r(); + void hlt_w(bool state); + + bool enp_r(); + + void index_callback(floppy_image_device *floppy, int state); + +protected: + // Chip-specific configuration flags + bool disable_mfm; + bool enmf; + bool has_enmf; + bool inverted_bus; + bool side_control; + bool side_compare; + bool head_control; + bool motor_control; + bool ready_hooked; + bool nonsticky_immint; + int clock_ratio; + const int *step_times; + int delay_register_commit; + int delay_command_commit; + + static const int fd179x_step_times[4]; + static const int fd176x_step_times[4]; + + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + virtual int calc_sector_size(UINT8 size, UINT8 command) const; + virtual int settle_time() const; + + virtual void pll_reset(bool fm, bool enmf, const attotime &when) = 0; + virtual void pll_start_writing(const attotime &tm) = 0; + virtual void pll_commit(floppy_image_device *floppy, const attotime &tm) = 0; + virtual void pll_stop_writing(floppy_image_device *floppy, const attotime &tm) = 0; + virtual int pll_get_next_bit(attotime &tm, floppy_image_device *floppy, const attotime &limit) = 0; + virtual bool pll_write_next_bit(bool bit, attotime &tm, floppy_image_device *floppy, const attotime &limit) = 0; + virtual void pll_save_checkpoint() = 0; + virtual void pll_retrieve_checkpoint() = 0; + +private: + enum { TM_GEN, TM_CMD, TM_TRACK, TM_SECTOR }; + + // State machine general behaviour: + // + // There are three levels of state. + // + // Main state is associated to (groups of) commands. They're set + // by a *_start() function below, and the associated _continue() + // function can then be called at pretty much any time. + // + // Sub state is the state of execution within a command. The + // principle is that the *_start() function selects the initial + // substate, then the *_continue() function decides what to do, + // possibly changing state. Eventually it can: + // - decide to wait for an event (timer, index) + // - end the command with command_end() + // - start a live state (see below) + // + // In the first case, it must first switch to a waiting + // sub-state, then return. The waiting sub-state must just + // return immediatly when *_continue is called. Eventually the + // event handler function will advance the state machine to + // another sub-state, and things will continue synchronously. + // + // On command end it's also supposed to return immediatly. + // + // The last option is to switch to the next sub-state, start a + // live state with live_start() then return. The next sub-state + // will only be called once the live state is finished. + // + // Live states change continually depending on the disk contents + // until the next externally discernable event is found. They + // are checkpointing, run until an event is found, then they wait + // for it. When an event eventually happens, the changes are + // either committed or replayed until the sync event time. + // + // The transition to IDLE is only done on a synced event. Some + // other transitions, such as activating drq, are also done after + // syncing without exiting live mode. Syncing in live mode is + // done by calling live_delay() with the state to change to after + // syncing. + + enum { + // General "doing nothing" state + IDLE, + + // Main states - the commands + RESTORE, + SEEK, + STEP, + READ_SECTOR, + READ_TRACK, + READ_ID, + WRITE_TRACK, + WRITE_SECTOR, + + // Sub states + + SPINUP, + SPINUP_WAIT, + SPINUP_DONE, + + SETTLE_WAIT, + SETTLE_DONE, + + DATA_LOAD_WAIT, + DATA_LOAD_WAIT_DONE, + + SEEK_MOVE, + SEEK_WAIT_STEP_TIME, + SEEK_WAIT_STEP_TIME_DONE, + SEEK_WAIT_STABILIZATION_TIME, + SEEK_WAIT_STABILIZATION_TIME_DONE, + SEEK_DONE, + + WAIT_INDEX, + WAIT_INDEX_DONE, + + SCAN_ID, + SCAN_ID_FAILED, + + SECTOR_READ, + SECTOR_WRITE, + TRACK_DONE, + + // Live states + + SEARCH_ADDRESS_MARK_HEADER, + READ_HEADER_BLOCK_HEADER, + READ_DATA_BLOCK_HEADER, + READ_ID_BLOCK_TO_LOCAL, + READ_ID_BLOCK_TO_DMA, + READ_ID_BLOCK_TO_DMA_BYTE, + SEARCH_ADDRESS_MARK_DATA, + SEARCH_ADDRESS_MARK_DATA_FAILED, + READ_SECTOR_DATA, + READ_SECTOR_DATA_BYTE, + READ_TRACK_DATA, + READ_TRACK_DATA_BYTE, + WRITE_TRACK_DATA, + WRITE_BYTE, + WRITE_BYTE_DONE, + WRITE_SECTOR_PRE, + WRITE_SECTOR_PRE_BYTE + }; + + struct live_info { + enum { PT_NONE, PT_CRC_1, PT_CRC_2 }; + + attotime tm; + int state, next_state; + UINT16 shift_reg; + UINT16 crc; + int bit_counter, byte_counter, previous_type; + bool data_separator_phase, data_bit_context; + UINT8 data_reg; + UINT8 idbuf[6]; + }; + + enum { + S_BUSY = 0x01, + S_DRQ = 0x02, + S_IP = 0x02, + S_TR00 = 0x04, + S_LOST = 0x04, + S_CRC = 0x08, + S_RNF = 0x10, + S_HLD = 0x20, + S_SPIN = 0x20, // WD1770, WD1772 + S_DDM = 0x20, + S_WF = 0x20, // WD1773 + S_WP = 0x40, + S_NRDY = 0x80, + S_MON = 0x80 // WD1770, WD1772 + }; + + enum { + I_RDY = 0x01, + I_NRDY = 0x02, + I_IDX = 0x04, + I_IMM = 0x08 + }; + + + floppy_image_device *floppy; + + emu_timer *t_gen, *t_cmd, *t_track, *t_sector; + + bool dden, status_type_1, intrq, drq, hld, hlt, enp, force_ready; + int main_state, sub_state; + UINT8 command, track, sector, data, status, intrq_cond; + int last_dir; + + int counter, motor_timeout, sector_size; + + int cmd_buffer, track_buffer, sector_buffer; + + live_info cur_live, checkpoint_live; + + devcb_write_line intrq_cb, drq_cb, hld_cb, enp_cb; + devcb_read_line enmf_cb; + + UINT8 format_last_byte; + int format_last_byte_count; + std::string format_description_string; + + static std::string tts(const attotime &t); + std::string ttsn(); + + void delay_cycles(emu_timer *tm, int cycles); + + // Device timer subfunctions + void do_cmd_w(); + void do_track_w(); + void do_sector_w(); + void do_generic(); + + + // Main-state handling functions + void seek_start(int state); + void seek_continue(); + + void read_sector_start(); + void read_sector_continue(); + + void read_track_start(); + void read_track_continue(); + + void read_id_start(); + void read_id_continue(); + + void write_track_start(); + void write_track_continue(); + + void write_sector_start(); + void write_sector_continue(); + + void interrupt_start(); + + void general_continue(); + void command_end(); + + void spinup(); + void ready_callback(floppy_image_device *floppy, int state); + bool sector_matches() const; + bool is_ready(); + + void live_start(int live_state); + void live_abort(); + void checkpoint(); + void rollback(); + void live_delay(int state); + void live_sync(); + void live_run(attotime limit = attotime::never); + bool read_one_bit(const attotime &limit); + bool write_one_bit(const attotime &limit); + + void live_write_raw(UINT16 raw); + void live_write_mfm(UINT8 mfm); + void live_write_fm(UINT8 fm); + + void drop_drq(); + void set_drq(); +}; + +class wd_fdc_analog_t : public wd_fdc_t { +public: + wd_fdc_analog_t(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + +protected: + virtual void pll_reset(bool fm, bool enmf, const attotime &when); + virtual void pll_start_writing(const attotime &tm); + virtual void pll_commit(floppy_image_device *floppy, const attotime &tm); + virtual void pll_stop_writing(floppy_image_device *floppy, const attotime &tm); + virtual int pll_get_next_bit(attotime &tm, floppy_image_device *floppy, const attotime &limit); + virtual bool pll_write_next_bit(bool bit, attotime &tm, floppy_image_device *floppy, const attotime &limit); + virtual void pll_save_checkpoint(); + virtual void pll_retrieve_checkpoint(); + +private: + fdc_pll_t cur_pll, checkpoint_pll; +}; + +class wd_fdc_digital_t : public wd_fdc_t { +public: + wd_fdc_digital_t(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + +protected: + static const int wd_digital_step_times[4]; + + virtual void pll_reset(bool fm, bool enmf, const attotime &when); + virtual void pll_start_writing(const attotime &tm); + virtual void pll_commit(floppy_image_device *floppy, const attotime &tm); + virtual void pll_stop_writing(floppy_image_device *floppy, const attotime &tm); + virtual int pll_get_next_bit(attotime &tm, floppy_image_device *floppy, const attotime &limit); + virtual bool pll_write_next_bit(bool bit, attotime &tm, floppy_image_device *floppy, const attotime &limit); + virtual void pll_save_checkpoint(); + virtual void pll_retrieve_checkpoint(); + +private: + struct digital_pll_t { + UINT16 counter; + UINT16 increment; + UINT16 transition_time; + UINT8 history; + UINT8 slot; + UINT8 phase_add, phase_sub, freq_add, freq_sub; + attotime ctime; + + attotime delays[42]; + + attotime write_start_time; + attotime write_buffer[32]; + int write_position; + + void set_clock(const attotime &period); + void reset(const attotime &when); + int get_next_bit(attotime &tm, floppy_image_device *floppy, const attotime &limit); + bool write_next_bit(bool bit, attotime &tm, floppy_image_device *floppy, const attotime &limit); + void start_writing(const attotime &tm); + void commit(floppy_image_device *floppy, const attotime &tm); + void stop_writing(floppy_image_device *floppy, const attotime &tm); + }; + + digital_pll_t cur_pll, checkpoint_pll; +}; + +class fd1771_t : public wd_fdc_analog_t { +public: + fd1771_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual int calc_sector_size(UINT8 size, UINT8 command) const; +}; + +class fd1781_t : public wd_fdc_analog_t { +public: + fd1781_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual int calc_sector_size(UINT8 size, UINT8 command) const; +}; + +class fd1791_t : public wd_fdc_analog_t { +public: + fd1791_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class fd1792_t : public wd_fdc_analog_t { +public: + fd1792_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class fd1793_t : public wd_fdc_analog_t { +public: + fd1793_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class kr1818vg93_t : public wd_fdc_analog_t { +public: + kr1818vg93_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class fd1794_t : public wd_fdc_analog_t { +public: + fd1794_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class fd1795_t : public wd_fdc_analog_t { +public: + fd1795_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual int calc_sector_size(UINT8 size, UINT8 command) const; +}; + +class fd1797_t : public wd_fdc_analog_t { +public: + fd1797_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual int calc_sector_size(UINT8 size, UINT8 command) const; +}; + +class mb8866_t : public wd_fdc_analog_t { +public: + mb8866_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class mb8876_t : public wd_fdc_analog_t { +public: + mb8876_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class mb8877_t : public wd_fdc_analog_t { +public: + mb8877_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class fd1761_t : public wd_fdc_analog_t { +public: + fd1761_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class fd1763_t : public wd_fdc_analog_t { +public: + fd1763_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class fd1765_t : public wd_fdc_analog_t { +public: + fd1765_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual int calc_sector_size(UINT8 size, UINT8 command) const; +}; + +class fd1767_t : public wd_fdc_analog_t { +public: + fd1767_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual int calc_sector_size(UINT8 size, UINT8 command) const; +}; + +class wd2791_t : public wd_fdc_analog_t { +public: + wd2791_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + DECLARE_WRITE_LINE_MEMBER(enmf_w) { enmf = state ? false : true; } +}; + +class wd2793_t : public wd_fdc_analog_t { +public: + wd2793_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + DECLARE_WRITE_LINE_MEMBER(enmf_w) { enmf = state ? false : true; } +}; + +class wd2795_t : public wd_fdc_analog_t { +public: + wd2795_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual int calc_sector_size(UINT8 size, UINT8 command) const; +}; + +class wd2797_t : public wd_fdc_analog_t { +public: + wd2797_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual int calc_sector_size(UINT8 size, UINT8 command) const; +}; + +class wd1770_t : public wd_fdc_digital_t { +public: + wd1770_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class wd1772_t : public wd_fdc_digital_t { +public: + wd1772_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual int settle_time() const; +}; + +class wd1773_t : public wd_fdc_digital_t { +public: + wd1773_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +extern const device_type FD1771; + +extern const device_type FD1781; + +extern const device_type FD1791; +extern const device_type FD1792; +extern const device_type FD1793; +extern const device_type FD1794; +extern const device_type KR1818VG93; +extern const device_type FD1795; +extern const device_type FD1797; + +extern const device_type MB8866; +extern const device_type MB8876; +extern const device_type MB8877; + +extern const device_type FD1761; +extern const device_type FD1763; +extern const device_type FD1765; +extern const device_type FD1767; + +extern const device_type WD2791; +extern const device_type WD2793; +extern const device_type WD2795; +extern const device_type WD2797; + +extern const device_type WD1770; +extern const device_type WD1772; +extern const device_type WD1773; + +#endif diff --git a/src/devices/machine/wozfdc.c b/src/devices/machine/wozfdc.c new file mode 100644 index 00000000000..dd3f2483c77 --- /dev/null +++ b/src/devices/machine/wozfdc.c @@ -0,0 +1,587 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +/********************************************************************* + + wozfdc.c + + Implementation of the Apple Disk II floppy disk controller + +*********************************************************************/ + +#include "emu.h" +#include "imagedev/floppy.h" +#include "formats/ap2_dsk.h" +#include "wozfdc.h" + +/*************************************************************************** + PARAMETERS +***************************************************************************/ + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const device_type DISKII_FDC = &device_creator; +const device_type APPLEIII_FDC = &device_creator; + +#define DISKII_P6_REGION "diskii_rom_p6" + +ROM_START( diskiing ) + ROM_REGION(0x100, DISKII_P6_REGION, 0) + ROM_LOAD( "341-0028-a.rom", 0x0000, 0x0100, CRC(b72a2c70) SHA1(bc39fbd5b9a8d2287ac5d0a42e639fc4d3c2f9d4)) /* 341-0028: 16-sector disk drive (older version), PROM P6 */ +ROM_END + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *wozfdc_device::device_rom_region() const +{ + return ROM_NAME( diskiing ); +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +wozfdc_device::wozfdc_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source) +{ +} + +diskii_fdc::diskii_fdc(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + wozfdc_device(mconfig, DISKII_FDC, "Apple Disk II floppy controller", tag, owner, clock, "d2fdc", __FILE__) +{ +} + +appleiii_fdc::appleiii_fdc(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + wozfdc_device(mconfig, DISKII_FDC, "Apple III floppy controller", tag, owner, clock, "a3fdc", __FILE__) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void wozfdc_device::device_start() +{ + m_rom_p6 = machine().root_device().memregion(this->subtag(DISKII_P6_REGION).c_str())->base(); + + timer = timer_alloc(0); + delay_timer = timer_alloc(1); + + save_item(NAME(last_6502_write)); + save_item(NAME(mode_write)); + save_item(NAME(mode_load)); + save_item(NAME(active)); + save_item(NAME(phases)); + save_item(NAME(external_io_select)); + save_item(NAME(cur_lss.tm)); + save_item(NAME(cur_lss.cycles)); + save_item(NAME(cur_lss.data_reg)); + save_item(NAME(cur_lss.address)); + save_item(NAME(cur_lss.write_start_time)); +// save_item(NAME(cur_lss.write_buffer)); + save_item(NAME(cur_lss.write_position)); + save_item(NAME(cur_lss.write_line_active)); + save_item(NAME(predicted_lss.tm)); + save_item(NAME(predicted_lss.cycles)); + save_item(NAME(predicted_lss.data_reg)); + save_item(NAME(predicted_lss.address)); + save_item(NAME(predicted_lss.write_start_time)); +// save_item(NAME(predicted_lss.write_buffer)); + save_item(NAME(predicted_lss.write_position)); + save_item(NAME(predicted_lss.write_line_active)); + save_item(NAME(drvsel)); + save_item(NAME(enable1)); +} + +void wozfdc_device::device_reset() +{ + floppy = NULL; + active = MODE_IDLE; + phases = 0x00; + mode_write = false; + mode_load = false; + last_6502_write = 0x00; + cur_lss.tm = machine().time(); + cur_lss.cycles = time_to_cycles(cur_lss.tm); + cur_lss.data_reg = 0x00; + cur_lss.address = 0x00; + cur_lss.write_start_time = attotime::never; + cur_lss.write_position = 0; + cur_lss.write_line_active = false; + predicted_lss.tm = attotime::never; + external_io_select = false; +} + +void wozfdc_device::a3_update_drive_sel() +{ + floppy_image_device *newflop = NULL; + + if (!external_io_select) + { + newflop = floppy0->get_device(); + } + else + { + switch (drvsel & 3) + { + case 0: + newflop = floppy0->get_device(); + break; + + case 1: + newflop = floppy1->get_device(); + break; + + case 2: + newflop = floppy2->get_device(); + break; + + case 3: + newflop = floppy3->get_device(); + break; + } + } + + if (floppy != newflop) + { + if(active) { + lss_sync(); + floppy->mon_w(true); + } + floppy = newflop; + if(active) { + floppy->mon_w(false); + lss_predict(); + } + } +} + +void diskii_fdc::device_reset() +{ + wozfdc_device::device_reset(); + external_drive_select = false; + + if (floppy0 != NULL) + { + floppy = floppy0->get_device(); + } +} + +void appleiii_fdc::device_reset() +{ + wozfdc_device::device_reset(); + external_drive_select = true; + drvsel = 0; + enable1 = 1; +} + +void wozfdc_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + if(active) + lss_sync(); + + if(id == 1 && active == MODE_DELAY) { + if(floppy) + floppy->mon_w(true); + active = MODE_IDLE; + } + + if(active) + lss_predict(); +} + +/*------------------------------------------------- + read - called to read the FDC's registers +-------------------------------------------------*/ + +READ8_MEMBER(wozfdc_device::read) +{ + control(offset); + + if(!(offset & 1)) + return cur_lss.data_reg; + return 0xff; +} + + +/*------------------------------------------------- + write - called to write the FDC's registers +-------------------------------------------------*/ + +WRITE8_MEMBER(wozfdc_device::write) +{ + control(offset); + last_6502_write = data; + lss_predict(); +} + +void wozfdc_device::phase(int ph, bool on) +{ + if(on) + phases |= 1 << ph; + else + phases &= ~(1 << ph); + + if(floppy && active) + floppy->seek_phase_w(phases); +} + +void wozfdc_device::control(int offset) +{ + if(offset < 8) { + if(active) + lss_sync(); + phase(offset >> 1, offset & 1); + if(active) + lss_predict(); + + } else + switch(offset) { + case 0x8: + if(active == MODE_ACTIVE) { + lss_sync(); + delay_timer->adjust(attotime::from_seconds(1)); + active = MODE_DELAY; + } + break; + case 0x9: + switch(active) { + case MODE_IDLE: + if(floppy) + floppy->mon_w(false); + active = MODE_ACTIVE; + if(floppy) + lss_start(); + break; + case MODE_DELAY: + active = MODE_ACTIVE; + delay_timer->adjust(attotime::never); + break; + } + break; + case 0xa: + external_io_select = false; + if(floppy != floppy0->get_device()) { + if(active) { + lss_sync(); + floppy->mon_w(true); + } + floppy = floppy0->get_device(); + if(active) { + floppy->mon_w(false); + lss_predict(); + } + } + break; + case 0xb: + external_io_select = true; + if (!external_drive_select) + { + if (floppy != floppy1->get_device()) + { + if(active) { + lss_sync(); + floppy->mon_w(true); + } + floppy = floppy1->get_device(); + if(active) { + floppy->mon_w(false); + lss_predict(); + } + } + } + else + { + a3_update_drive_sel(); + } + break; + case 0xc: + if(mode_load) { + if(active) { + lss_sync(); + cur_lss.address &= ~0x04; + } + mode_load = false; + if(active) + lss_predict(); + } + break; + case 0xd: + if(!mode_load) { + if(active) { + lss_sync(); + cur_lss.address |= 0x04; + } + mode_load = true; + if(active) + lss_predict(); + } + break; + case 0xe: + if(mode_write) { + if(active) { + lss_sync(); + cur_lss.address &= ~0x08; + } + mode_write = false; + if(active) + lss_predict(); + } + break; + case 0xf: + if(!mode_write) { + if(active) { + lss_sync(); + cur_lss.address |= 0x08; + cur_lss.write_start_time = machine().time(); + if(floppy) + floppy->set_write_splice(cur_lss.write_start_time); + } + mode_write = true; + if(active) + lss_predict(); + } + break; + } +} + +UINT64 wozfdc_device::time_to_cycles(const attotime &tm) +{ + // Clock is falling edges of the ~2Mhz clock + // The 1021800 must be the controlling 6502's speed + + UINT64 cycles = tm.as_ticks(clock()*2); + cycles = (cycles+1) >> 1; + return cycles; +} + +attotime wozfdc_device::cycles_to_time(UINT64 cycles) +{ + return attotime::from_ticks(cycles*2+1, clock()*2); +} + +void wozfdc_device::lss_start() +{ + cur_lss.tm = machine().time(); + cur_lss.cycles = time_to_cycles(cur_lss.tm); + cur_lss.data_reg = 0x00; + cur_lss.address &= ~0x0e; + cur_lss.write_position = 0; + cur_lss.write_start_time = mode_write ? machine().time() : attotime::never; + cur_lss.write_line_active = false; + if(mode_write && floppy) + floppy->set_write_splice(cur_lss.write_start_time); + lss_predict(); +} + +void wozfdc_device::lss_delay(UINT64 cycles, const attotime &tm, UINT8 data_reg, UINT8 address, bool write_line_active) +{ + if(data_reg & 0x80) + address |= 0x02; + else + address &= ~0x02; + predicted_lss.cycles = cycles; + predicted_lss.tm = tm; + predicted_lss.data_reg = data_reg; + predicted_lss.address = address; + predicted_lss.write_line_active = write_line_active; + attotime mtm = machine().time(); + if(predicted_lss.tm > mtm) + timer->adjust(predicted_lss.tm - mtm); +} + +void wozfdc_device::lss_delay(UINT64 cycles, UINT8 data_reg, UINT8 address, bool write_line_active) +{ + lss_delay(cycles, cycles_to_time(cycles), data_reg, address, write_line_active); +} + +void wozfdc_device::commit_predicted() +{ + cur_lss = predicted_lss; + assert(!mode_write || (cur_lss.write_line_active && (cur_lss.address & 0x80)) || ((!cur_lss.write_line_active) && !(cur_lss.address & 0x80))); + if(mode_write) { + if(floppy) + floppy->write_flux(cur_lss.write_start_time, cur_lss.tm, cur_lss.write_position, cur_lss.write_buffer); + cur_lss.write_start_time = cur_lss.tm; + cur_lss.write_position = 0; + } + + predicted_lss.tm = attotime::never; +} + +void wozfdc_device::lss_sync() +{ + attotime tm = machine().time(); + if(!predicted_lss.tm.is_never() && predicted_lss.tm <= tm) + commit_predicted(); + + while(cur_lss.tm < tm) { + lss_predict(tm); + commit_predicted(); + } +} + +void wozfdc_device::lss_predict(attotime limit) +{ + predicted_lss.write_start_time = cur_lss.write_start_time; + predicted_lss.write_position = cur_lss.write_position; + memcpy(predicted_lss.write_buffer, cur_lss.write_buffer, cur_lss.write_position * sizeof(attotime)); + bool write_line_active = cur_lss.write_line_active; + + attotime next_flux = floppy ? floppy->get_next_transition(cur_lss.tm - attotime::from_usec(1)) : attotime::never; + + if(limit == attotime::never) + limit = machine().time() + attotime::from_usec(50); + + UINT64 cycles = cur_lss.cycles; + UINT64 cycles_limit = time_to_cycles(limit); + UINT64 cycles_next_flux = next_flux != attotime::never ? time_to_cycles(next_flux) : UINT64(-1); + UINT64 cycles_next_flux_down = cycles_next_flux != UINT64(-1) ? cycles_next_flux+1 : UINT64(-1); + + UINT8 address = cur_lss.address; + UINT8 data_reg = cur_lss.data_reg; + + if(cycles >= cycles_next_flux && cycles < cycles_next_flux_down) + address &= ~0x10; + else + address |= 0x10; + + while(cycles < cycles_limit) { + UINT64 cycles_next_trans = cycles_limit; + if(cycles_next_trans > cycles_next_flux && cycles < cycles_next_flux) + cycles_next_trans = cycles_next_flux; + if(cycles_next_trans > cycles_next_flux_down && cycles < cycles_next_flux_down) + cycles_next_trans = cycles_next_flux_down; + + while(cycles < cycles_next_trans) { + UINT8 opcode = m_rom_p6[address]; + + if(mode_write) { + if((write_line_active && !(address & 0x80)) || + (!write_line_active && (address & 0x80))) { + write_line_active = !write_line_active; + assert(predicted_lss.write_position != 32); + predicted_lss.write_buffer[predicted_lss.write_position++] = cycles_to_time(cycles); + } + } + + address = (address & 0x1e) | (opcode & 0xc0) | ((opcode & 0x20) >> 5) | ((opcode & 0x10) << 1); + switch(opcode & 0x0f) { + case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: + if(data_reg) { + lss_delay(cycles+1, 0x00, address, write_line_active); + return; + } + break; + case 0x8: case 0xc: + break; + case 0x9: + lss_delay(cycles+1, data_reg << 1, address, write_line_active); + return; + case 0xa: case 0xe: + lss_delay(cycles+1, (data_reg >> 1) | (floppy && floppy->wpt_r() ? 0x80 : 0x00), address, write_line_active); + return; + case 0xb: case 0xf: + lss_delay(cycles+1, last_6502_write, address, write_line_active); + return; + case 0xd: + lss_delay(cycles+1, (data_reg << 1) | 0x01, address, write_line_active); + return; + } + cycles++; + } + + if(cycles == cycles_next_flux) + address &= ~0x10; + else if(cycles == cycles_next_flux_down) { + address |= 0x10; + next_flux = floppy ? floppy->get_next_transition(cycles_to_time(cycles)) : attotime::never; + cycles_next_flux = next_flux != attotime::never ? time_to_cycles(next_flux) : UINT64(-1); + cycles_next_flux_down = cycles_next_flux != UINT64(-1) ? cycles_next_flux+1 : UINT64(-1); + } + } + + lss_delay(cycles, limit, data_reg, address, write_line_active); +} + +// set the two images for the Disk II +void diskii_fdc::set_floppies(floppy_connector *f0, floppy_connector *f1) +{ + floppy0 = f0; + floppy1 = f1; + + if (floppy0) + { + floppy = floppy0->get_device(); + } +} + +void appleiii_fdc::set_floppies_4(floppy_connector *f0, floppy_connector *f1, floppy_connector *f2, floppy_connector *f3) +{ + floppy0 = f0; + floppy1 = f1; + floppy2 = f2; + floppy3 = f3; + + if (floppy0) + { + floppy = floppy0->get_device(); + } +} + +READ8_MEMBER(appleiii_fdc::read_c0dx) +{ + control_dx(offset); + + return 0xff; +} + +WRITE8_MEMBER(appleiii_fdc::write_c0dx) +{ + control_dx(offset); +} + +void appleiii_fdc::control_dx(int offset) +{ + switch (offset) + { + case 0: // clear drive select bit 0 + drvsel &= ~1; + break; + + case 1: // set drive select bit 0 + drvsel |= 1; + break; + + case 2: // clear drive select bit 1 + drvsel &= ~2; + break; + + case 3: // set drive select bit 1 + drvsel |= 2; + break; + + case 4: // clear enable 1 + enable1 = 0; + break; + + case 5: // set enable 1 + enable1 = 1; + break; + + case 6: // clear side 2 + case 7: // set side 2 + break; + + default: // cod8-c0df are not FDC related + break; + } + + if (offset < 8) + { + a3_update_drive_sel(); + } +} diff --git a/src/devices/machine/wozfdc.h b/src/devices/machine/wozfdc.h new file mode 100644 index 00000000000..384f057919d --- /dev/null +++ b/src/devices/machine/wozfdc.h @@ -0,0 +1,122 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +/********************************************************************* + + wozfdc.h + + Apple Disk II floppy disk controller + +*********************************************************************/ + +#pragma once + +#ifndef __WOZFDC_H__ +#define __WOZFDC_H__ + +#include "emu.h" +#include "imagedev/floppy.h" +#include "formats/flopimg.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + + +class wozfdc_device: + public device_t +{ + friend class diskii_fdc; + friend class appleiii_fdc; + +public: + // construction/destruction + wozfdc_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + + DECLARE_READ8_MEMBER(read); + DECLARE_WRITE8_MEMBER(write); + +protected: + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + floppy_connector *floppy0, *floppy1, *floppy2, *floppy3; + floppy_image_device *floppy; + +private: + enum { + MODE_IDLE, MODE_ACTIVE, MODE_DELAY + }; + + struct lss { + attotime tm; + UINT64 cycles; + UINT8 data_reg, address; + attotime write_start_time; + attotime write_buffer[32]; + int write_position; + bool write_line_active; + }; + + const UINT8 *m_rom_p6; + UINT8 last_6502_write; + bool mode_write, mode_load; + int active; + UINT8 phases; + emu_timer *timer, *delay_timer; + bool external_drive_select; + bool external_io_select; + + lss cur_lss, predicted_lss; + + int drvsel; + int enable1; + + void control(int offset); + void phase(int ph, bool on); + UINT64 time_to_cycles(const attotime &tm); + attotime cycles_to_time(UINT64 cycles); + void a3_update_drive_sel(); + + void lss_start(); + void lss_delay(UINT64 cycles, const attotime &tm, UINT8 data_reg, UINT8 address, bool write_line_active); + void lss_delay(UINT64 cycles, UINT8 data_reg, UINT8 address, bool write_line_active); + void lss_sync(); + void lss_predict(attotime limit = attotime::never); + void commit_predicted(); +}; + +class diskii_fdc : public wozfdc_device +{ +public: + diskii_fdc(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual void device_reset(); + + void set_floppies(floppy_connector *f0, floppy_connector *f1); +}; + +class appleiii_fdc : public wozfdc_device +{ +public: + appleiii_fdc(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual void device_reset(); + + void set_floppies_4(floppy_connector *f0, floppy_connector *f1, floppy_connector *f2, floppy_connector *f3); + + DECLARE_READ8_MEMBER(read_c0dx); + DECLARE_WRITE8_MEMBER(write_c0dx); + +private: + void control_dx(int offset); +}; + +// device type definition +extern const device_type DISKII_FDC; +extern const device_type APPLEIII_FDC; + +#endif /* __WOZFDC_H__ */ diff --git a/src/devices/machine/x2212.c b/src/devices/machine/x2212.c new file mode 100644 index 00000000000..01db1709c74 --- /dev/null +++ b/src/devices/machine/x2212.c @@ -0,0 +1,261 @@ +// license:BSD-3-Clause +// copyright-holders:smf,Barry Rodewald +/*************************************************************************** + + x2212.c + + Xicor X2212 256 x 4 bit Nonvolatile Static RAM. + +***************************************************************************/ + +#include "emu.h" +#include "machine/x2212.h" + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +static ADDRESS_MAP_START( x2212_sram_map, AS_0, 8, x2212_device ) + AM_RANGE(0x0000, 0x00ff) AM_RAM +ADDRESS_MAP_END + +static ADDRESS_MAP_START( x2212_e2prom_map, AS_1, 8, x2212_device ) + AM_RANGE(0x0000, 0x00ff) AM_RAM +ADDRESS_MAP_END + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +// device type definition +const device_type X2212 = &device_creator; +const device_type X2210 = &device_creator; + +//------------------------------------------------- +// x2212_device - constructor +//------------------------------------------------- + +x2212_device::x2212_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, X2212, "X2212 NVRAM", tag, owner, clock, "x2212", __FILE__), + device_memory_interface(mconfig, *this), + device_nvram_interface(mconfig, *this), + m_auto_save(false), + m_sram_space_config("SRAM", ENDIANNESS_BIG, 8, 8, 0, *ADDRESS_MAP_NAME(x2212_sram_map)), + m_e2prom_space_config("E2PROM", ENDIANNESS_BIG, 8, 8, 0, *ADDRESS_MAP_NAME(x2212_e2prom_map)), + m_store(false), + m_array_recall(false) +{ +} + +x2212_device::x2212_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_memory_interface(mconfig, *this), + device_nvram_interface(mconfig, *this), + m_auto_save(false), + m_sram_space_config("SRAM", ENDIANNESS_BIG, 8, 8, 0, *ADDRESS_MAP_NAME(x2212_sram_map)), + m_e2prom_space_config("E2PROM", ENDIANNESS_BIG, 8, 8, 0, *ADDRESS_MAP_NAME(x2212_e2prom_map)), + m_store(false), + m_array_recall(false) +{ +} + +//------------------------------------------------- +// static_set_auto_save - configuration helper +// to set the auto-save flag +//------------------------------------------------- + +void x2212_device::static_set_auto_save(device_t &device) +{ + downcast(device).m_auto_save = true; +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void x2212_device::device_start() +{ + save_item(NAME(m_store)); + save_item(NAME(m_array_recall)); + + m_sram = m_addrspace[0]; + m_e2prom = m_addrspace[1]; + + SIZE_DATA = 0x100; +} + +void x2210_device::device_start() +{ + save_item(NAME(m_store)); + save_item(NAME(m_array_recall)); + + m_sram = m_addrspace[0]; + m_e2prom = m_addrspace[1]; + + SIZE_DATA = 0x40; +} + + +//------------------------------------------------- +// memory_space_config - return a description of +// any address spaces owned by this device +//------------------------------------------------- + +const address_space_config *x2212_device::memory_space_config(address_spacenum spacenum) const +{ + return (spacenum == 0) ? &m_sram_space_config : (spacenum == 1) ? &m_e2prom_space_config : NULL; +} + + +//------------------------------------------------- +// nvram_default - called to initialize NVRAM to +// its default state +//------------------------------------------------- + +void x2212_device::nvram_default() +{ + // default to all-0xff + for (int byte = 0; byte < SIZE_DATA; byte++) + { + m_sram->write_byte(byte, 0xff); + m_e2prom->write_byte(byte, 0xff); + } + + // populate from a memory region if present + if (m_region != NULL) + { + if (m_region->bytes() != SIZE_DATA) + fatalerror("x2212 region '%s' wrong size (expected size = 0x100)\n", tag()); + if (m_region->bytewidth() != 1) + fatalerror("x2212 region '%s' needs to be an 8-bit region\n", tag()); + + UINT8 *default_data = m_region->base(); + for (int byte = 0; byte < SIZE_DATA; byte++) + m_e2prom->write_byte(byte, default_data[byte]); + } +} + + +//------------------------------------------------- +// nvram_read - called to read NVRAM from the +// .nv file +//------------------------------------------------- + +void x2212_device::nvram_read(emu_file &file) +{ + UINT8 *buffer = (UINT8 *) alloca(SIZE_DATA); + file.read(buffer, SIZE_DATA); + for (int byte = 0; byte < SIZE_DATA; byte++) + { + m_sram->write_byte(byte, 0xff); + m_e2prom->write_byte(byte, buffer[byte]); + } +} + + +//------------------------------------------------- +// nvram_write - called to write NVRAM to the +// .nv file +//------------------------------------------------- + +void x2212_device::nvram_write(emu_file &file) +{ + // auto-save causes an implicit store prior to exiting (writing) + if (m_auto_save) + store(); + + UINT8 *buffer = (UINT8 *) alloca(SIZE_DATA); + for (int byte = 0; byte < SIZE_DATA; byte++) + buffer[byte] = m_e2prom->read_byte(byte); + file.write(buffer, SIZE_DATA); +} + + + +//************************************************************************** +// INTERNAL HELPERS +//************************************************************************** + +//------------------------------------------------- +// store - store data from live RAM into the +// EEPROM +//------------------------------------------------- + +void x2212_device::store() +{ + for (int byte = 0; byte < SIZE_DATA; byte++) + m_e2prom->write_byte(byte, m_sram->read_byte(byte)); +} + + +//------------------------------------------------- +// recall - fetch data from the EEPROM into live +// RAM +//------------------------------------------------- + +void x2212_device::recall() +{ + for (int byte = 0; byte < SIZE_DATA; byte++) + m_sram->write_byte(byte, m_e2prom->read_byte(byte)); +} + + + +//************************************************************************** +// READ/WRITE HANDLERS +//************************************************************************** + +//------------------------------------------------- +// write - store to the live RAM +//------------------------------------------------- + +WRITE8_MEMBER( x2212_device::write ) +{ + m_sram->write_byte(offset, data & 0x0f); +} + + +//------------------------------------------------- +// read - read from the live RAM +//------------------------------------------------- + +READ8_MEMBER( x2212_device::read ) +{ + return (m_sram->read_byte(offset) & 0x0f) | (space.unmap() & 0xf0); +} + + +//------------------------------------------------- +// store - set the state of the store line +// (active high) +//------------------------------------------------- + +WRITE_LINE_MEMBER( x2212_device::store ) +{ + if (state != 0 && !m_store) + store(); + m_store = (state != 0); +} + + +//------------------------------------------------- +// recall - set the state of the recall line +// (active high) +//------------------------------------------------- + +WRITE_LINE_MEMBER( x2212_device::recall ) +{ + if (state != 0 && !m_array_recall) + recall(); + m_array_recall = (state != 0); +} + + +x2210_device::x2210_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : x2212_device(mconfig, X2210, "X2210", tag, owner, clock, "x2210", __FILE__) +{ +} diff --git a/src/devices/machine/x2212.h b/src/devices/machine/x2212.h new file mode 100644 index 00000000000..4345c8f9a64 --- /dev/null +++ b/src/devices/machine/x2212.h @@ -0,0 +1,113 @@ +// license:BSD-3-Clause +// copyright-holders:smf,Barry Rodewald +/*************************************************************************** + + x2212.h + + Xicor X2212 256 x 4 bit Nonvolatile Static RAM. + +***************************************************************************/ + +#pragma once + +#ifndef __X2212_H__ +#define __X2212_H__ + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_X2212_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, X2212, 0) +// some systems (like many early Atari games) wire up the /STORE signal +// to fire on power-down, effectively creating an "auto-save" functionality +#define MCFG_X2212_ADD_AUTOSAVE(_tag) \ + MCFG_DEVICE_ADD(_tag, X2212, 0) \ + x2212_device::static_set_auto_save(*device); + +#define MCFG_X2210_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, X2210, 0) + +#define MCFG_X2210_ADD_AUTOSAVE(_tag) \ + MCFG_DEVICE_ADD(_tag, X2210, 0) \ + x2212_device::static_set_auto_save(*device); + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + + +// ======================> x2212_device + +class x2212_device : public device_t, + public device_memory_interface, + public device_nvram_interface +{ +public: + // construction/destruction + x2212_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + x2212_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + // inline configuration helpers + static void static_set_auto_save(device_t &device); + + // I/O operations + DECLARE_READ8_MEMBER( read ); + DECLARE_WRITE8_MEMBER( write ); + + DECLARE_WRITE_LINE_MEMBER( store ); + DECLARE_WRITE_LINE_MEMBER( recall ); + +protected: + // internal helpers + void store(); + void recall(); + + // device-level overrides + virtual void device_start(); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const; + + // device_nvram_interface overrides + virtual void nvram_default(); + virtual void nvram_read(emu_file &file); + virtual void nvram_write(emu_file &file); + + int SIZE_DATA; + + // configuration state + bool m_auto_save; + + // device-specific configuration + address_space_config m_sram_space_config; + address_space_config m_e2prom_space_config; + + // internal state + address_space * m_sram; + address_space * m_e2prom; + + bool m_store; + bool m_array_recall; +}; + +class x2210_device : public x2212_device +{ +public: + x2210_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // device-level overrides + virtual void device_start(); +}; + + +// device type definition +extern const device_type X2212; +extern const device_type X2210; + + +#endif diff --git a/src/devices/machine/x76f041.c b/src/devices/machine/x76f041.c new file mode 100644 index 00000000000..21dea0ae141 --- /dev/null +++ b/src/devices/machine/x76f041.c @@ -0,0 +1,540 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/* + * x76f041.c + * + * Secure SerialFlash + * + * The X76F041 is a Password Access Security Supervisor, containing four 128 x 8 bit SecureFlash arrays. + * Access can be controlled by three 64-bit programmable passwords, one for read operations, one for write + * operations and one for device configuration. + * + * The data sheet has an incorrect diagrams for sequential read with password, there shouldn't be an extra address after the 0xc0 command. + * + */ + +#include "emu.h" +#include "machine/x76f041.h" + +#define VERBOSE_LEVEL ( 0 ) + +inline void ATTR_PRINTF( 3, 4 ) x76f041_device::verboselog( int n_level, const char *s_fmt, ... ) +{ + if( VERBOSE_LEVEL >= n_level ) + { + va_list v; + char buf[ 32768 ]; + va_start( v, s_fmt ); + vsprintf( buf, s_fmt, v ); + va_end( v ); + logerror( "%s: x76f041(%s) %s", machine().describe_context(), tag(), buf ); + } +} + +// device type definition +const device_type X76F041 = &device_creator; + +x76f041_device::x76f041_device( const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock ) + : device_t( mconfig, X76F041, "X76F041 Flash", tag, owner, clock, "x76f041", __FILE__ ), + device_nvram_interface(mconfig, *this), + m_cs( 0 ), + m_rst( 0 ), + m_scl( 0 ), + m_sdaw( 0 ), + m_sdar( 0 ), + m_state( STATE_STOP ), + m_shift( 0 ), + m_bit( 0 ), + m_byte( 0 ), + m_command( 0 ), + m_address( 0 ) +{ +} + +void x76f041_device::device_start() +{ + memset( m_write_buffer, 0, sizeof( m_write_buffer ) ); + + save_item( NAME( m_cs ) ); + save_item( NAME( m_rst ) ); + save_item( NAME( m_scl ) ); + save_item( NAME( m_sdaw ) ); + save_item( NAME( m_sdar ) ); + save_item( NAME( m_state ) ); + save_item( NAME( m_shift ) ); + save_item( NAME( m_bit ) ); + save_item( NAME( m_byte ) ); + save_item( NAME( m_command ) ); + save_item( NAME( m_address ) ); + save_item( NAME( m_write_buffer ) ); + save_item( NAME( m_response_to_reset ) ); + save_item( NAME( m_write_password ) ); + save_item( NAME( m_read_password ) ); + save_item( NAME( m_configuration_password ) ); + save_item( NAME( m_configuration_registers ) ); + save_item( NAME( m_data ) ); +} + +WRITE_LINE_MEMBER( x76f041_device::write_cs ) +{ + if( m_cs != state ) + { + verboselog( 2, "cs=%d\n", state ); + } + + if( m_cs != 0 && state == 0 ) + { + /* enable chip */ + m_state = STATE_STOP; + } + + if( m_cs == 0 && state != 0 ) + { + /* disable chip */ + m_state = STATE_STOP; + /* high impendence? */ + m_sdar = 0; + } + + m_cs = state; +} + +WRITE_LINE_MEMBER( x76f041_device::write_rst ) +{ + if( m_rst != state ) + { + verboselog( 2, "rst=%d\n", state ); + } + + if( m_rst == 0 && state != 0 && m_cs == 0 ) + { + verboselog( 1, "goto response to reset\n" ); + m_state = STATE_RESPONSE_TO_RESET; + m_bit = 0; + m_byte = 0; + } + + m_rst = state; +} + +UINT8 *x76f041_device::password() +{ + switch( m_command & 0xe0 ) + { + case COMMAND_WRITE: + return m_write_password; + + case COMMAND_READ: + return m_read_password; + + default: + return m_configuration_password; + } +} + +void x76f041_device::password_ok() +{ + switch( m_command & 0xe0 ) + { + case COMMAND_WRITE: + m_state = STATE_WRITE_DATA; + break; + case COMMAND_READ: + m_state = STATE_READ_DATA; + break; + case COMMAND_WRITE_USE_CONFIGURATION_PASSWORD: + m_state = STATE_WRITE_DATA; + break; + case COMMAND_READ_USE_CONFIGURATION_PASSWORD: + m_state = STATE_READ_DATA; + break; + case COMMAND_CONFIGURATION: + switch( m_address ) + { + case CONFIGURATION_PROGRAM_WRITE_PASSWORD: + break; + case CONFIGURATION_PROGRAM_READ_PASSWORD: + break; + case CONFIGURATION_PROGRAM_CONFIGURATION_PASSWORD: + break; + case CONFIGURATION_RESET_WRITE_PASSWORD: + break; + case CONFIGURATION_RESET_READ_PASSWORD: + break; + case CONFIGURATION_PROGRAM_CONFIGURATION_REGISTERS: + m_state = STATE_WRITE_CONFIGURATION_REGISTERS; + m_byte = 0; + break; + case CONFIGURATION_READ_CONFIGURATION_REGISTERS: + m_state = STATE_READ_CONFIGURATION_REGISTERS; + m_byte = 0; + break; + case CONFIGURATION_MASS_PROGRAM: + break; + case CONFIGURATION_MASS_ERASE: + break; + default: + break; + } + } +} + +void x76f041_device::load_address() +{ + /* todo: handle other bcr bits */ + int bcr; + + m_address = m_shift; + + verboselog( 1, "-> address: %02x\n", m_address ); + + if( ( m_command & 1 ) == 0 ) + { + bcr = m_configuration_registers[ CONFIG_BCR1 ]; + } + else + { + bcr = m_configuration_registers[ CONFIG_BCR2 ]; + } + if( ( m_address & 0x80 ) != 0 ) + { + bcr >>= 4; + } + + if( ( ( m_command & 0xe0 ) == COMMAND_READ && ( bcr & BCR_Z ) != 0 && ( bcr & BCR_T ) != 0 ) || + ( ( m_command & 0xe0 ) == COMMAND_WRITE && ( bcr & BCR_Z ) != 0 ) ) + { + /* todo: find out when this is really checked. */ + verboselog( 1, "command not allowed\n" ); + m_state = STATE_STOP; + m_sdar = 0; + } + else if( ( ( m_command & 0xe0 ) == COMMAND_WRITE && ( bcr & BCR_X ) == 0 ) || + ( ( m_command & 0xe0 ) == COMMAND_READ && ( bcr & BCR_Y ) == 0 ) ) + { + verboselog( 1, "password not required\n" ); + password_ok(); + } + else + { + verboselog( 1, "send password\n" ); + m_state = STATE_LOAD_PASSWORD; + m_byte = 0; + } +} + +int x76f041_device::data_offset() +{ + int block_offset = ( ( m_command & 1 ) << 8 ) + m_address; + + // TODO: confirm block_start doesn't wrap. + + return ( block_offset & 0x180 ) | ( ( block_offset + m_byte ) & 0x7f ); +} + +WRITE_LINE_MEMBER( x76f041_device::write_scl ) +{ + if( m_scl != state ) + { + verboselog( 2, "scl=%d\n", state ); + } + + if( m_cs == 0 ) + { + switch( m_state ) + { + case STATE_STOP: + break; + + case STATE_RESPONSE_TO_RESET: + if( m_scl != 0 && state == 0 ) + { + m_sdar = ( m_response_to_reset[ m_byte ] >> m_bit ) & 1; + verboselog( 2, "in response to reset %d (%d/%d)\n", m_sdar, m_byte, m_bit ); + m_bit++; + + if( m_bit == 8 ) + { + m_bit = 0; + m_byte++; + + if( m_byte == sizeof( m_response_to_reset ) ) + { + m_byte = 0; + } + } + } + break; + + case STATE_LOAD_COMMAND: + case STATE_LOAD_ADDRESS: + case STATE_LOAD_PASSWORD: + case STATE_VERIFY_PASSWORD: + case STATE_WRITE_DATA: + case STATE_WRITE_CONFIGURATION_REGISTERS: + if( m_scl == 0 && state != 0 ) + { + if( m_bit < 8 ) + { + verboselog( 2, "clock\n" ); + m_shift <<= 1; + + if( m_sdaw != 0 ) + { + m_shift |= 1; + } + + m_bit++; + } + else + { + m_sdar = 0; + + switch( m_state ) + { + case STATE_LOAD_COMMAND: + m_command = m_shift; + verboselog( 1, "-> command: %02x\n", m_command ); + /* todo: verify command is valid? */ + m_state = STATE_LOAD_ADDRESS; + break; + + case STATE_LOAD_ADDRESS: + load_address(); + break; + + case STATE_LOAD_PASSWORD: + verboselog( 1, "-> password: %02x\n", m_shift ); + m_write_buffer[ m_byte++ ] = m_shift; + + if( m_byte == sizeof( m_write_buffer ) ) + { + m_state = STATE_VERIFY_PASSWORD; + } + break; + + case STATE_VERIFY_PASSWORD: + verboselog( 1, "-> verify password: %02x\n", m_shift ); + + /* todo: this should probably be handled as a command */ + if( m_shift == 0xc0 ) + { + /* todo: this should take 10ms before it returns ok. */ + if( memcmp( password(), m_write_buffer, sizeof( m_write_buffer ) ) == 0 ) + { + password_ok(); + } + else + { + m_sdar = 1; + } + } + break; + + case STATE_WRITE_DATA: + verboselog( 2, "-> data: %02x\n", m_shift ); + m_write_buffer[ m_byte++ ] = m_shift; + + if( m_byte == sizeof( m_write_buffer ) ) + { + for( m_byte = 0; m_byte < sizeof( m_write_buffer ); m_byte++ ) + { + int offset = data_offset(); + verboselog( 1, "-> data[ %03x ]: %02x\n", offset, m_write_buffer[ m_byte ] ); + m_data[ offset ] = m_write_buffer[ m_byte ]; + } + m_byte = 0; + + verboselog( 1, "data flushed\n" ); + } + break; + + case STATE_WRITE_CONFIGURATION_REGISTERS: + verboselog( 1, "-> configuration register[ %d ]: %02x\n", m_byte, m_shift ); + /* todo: write after all bytes received? */ + m_configuration_registers[ m_byte++ ] = m_shift; + + if( m_byte == sizeof( m_configuration_registers ) ) + { + m_byte = 0; + } + break; + } + + m_bit = 0; + m_shift = 0; + } + } + break; + + case STATE_READ_DATA: + case STATE_READ_CONFIGURATION_REGISTERS: + if( m_scl == 0 && state != 0 ) + { + if( m_bit < 8 ) + { + if( m_bit == 0 ) + { + int offset; + + switch( m_state ) + { + case STATE_READ_DATA: + offset = data_offset(); + m_shift = m_data[ offset ]; + verboselog( 1, "<- data[ %03x ]: %02x\n", offset, m_shift ); + break; + + case STATE_READ_CONFIGURATION_REGISTERS: + offset = m_byte & 7; + m_shift = m_configuration_registers[ offset ]; + verboselog( 1, "<- configuration register[ %d ]: %02x\n", offset, m_shift ); + break; + } + } + + m_sdar = ( m_shift >> 7 ) & 1; + m_shift <<= 1; + m_bit++; + } + else + { + m_bit = 0; + m_sdar = 0; + + if( m_sdaw == 0 ) + { + verboselog( 2, "ack <-\n" ); + m_byte++; + } + else + { + verboselog( 2, "nak <-\n" ); + } + } + } + break; + } + } + + m_scl = state; +} + +WRITE_LINE_MEMBER( x76f041_device::write_sda ) +{ + if( m_sdaw != state ) + { + verboselog( 2, "sdaw=%d\n", state ); + } + + if( m_cs == 0 && m_scl != 0 ) + { + if( m_sdaw == 0 && state != 0 ) + { + verboselog( 1, "goto stop\n" ); + m_state = STATE_STOP; + m_sdar = 0; + } + + if( m_sdaw != 0 && state == 0 ) + { + switch( m_state ) + { + case STATE_STOP: + verboselog( 1, "goto start\n" ); + m_state = STATE_LOAD_COMMAND; + break; + + case STATE_LOAD_PASSWORD: + /* todo: this will be the 0xc0 command, but it's not handled as a command yet. */ + verboselog( 1, "goto start\n" ); + break; + + case STATE_READ_DATA: + verboselog( 1, "goto load address\n" ); + m_state = STATE_LOAD_ADDRESS; + break; + + default: + verboselog( 1, "skipped start (default)\n" ); + break; + } + + m_bit = 0; + m_byte = 0; + m_shift = 0; + m_sdar = 0; + } + } + + m_sdaw = state; +} + +READ_LINE_MEMBER( x76f041_device::read_sda ) +{ + if( m_cs != 0 ) + { + verboselog( 2, "not selected\n" ); + return 1; + } + + verboselog( 2, "sdar=%d\n", m_sdar ); + return m_sdar; +} + +void x76f041_device::nvram_default() +{ + m_response_to_reset[0] = 0x19; + m_response_to_reset[1] = 0x55; + m_response_to_reset[2] = 0xaa; + m_response_to_reset[3] = 0x55, + + memset( m_write_password, 0, sizeof( m_write_password ) ); + memset( m_read_password, 0, sizeof( m_read_password ) ); + memset( m_configuration_password, 0, sizeof( m_configuration_password ) ); + memset( m_configuration_registers, 0, sizeof( m_configuration_registers ) ); + memset( m_data, 0, sizeof( m_data ) ); + + int expected_bytes = sizeof( m_response_to_reset ) + sizeof( m_write_password ) + sizeof( m_read_password ) + + sizeof( m_configuration_password ) + sizeof( m_configuration_registers ) + sizeof( m_data ); + + if( !m_region ) + { + logerror( "x76f041(%s) region not found\n", tag() ); + } + else if( m_region->bytes() != expected_bytes ) + { + logerror( "x76f041(%s) region length 0x%x expected 0x%x\n", tag(), m_region->bytes(), expected_bytes ); + } + else + { + UINT8 *region = m_region->base(); + + memcpy( m_response_to_reset, region, sizeof( m_response_to_reset ) ); region += sizeof( m_response_to_reset ); + memcpy( m_write_password, region, sizeof( m_write_password ) ); region += sizeof( m_write_password ); + memcpy( m_read_password, region, sizeof( m_read_password ) ); region += sizeof( m_read_password ); + memcpy( m_configuration_password, region, sizeof( m_configuration_password ) ); region += sizeof( m_configuration_password ); + memcpy( m_configuration_registers, region, sizeof( m_configuration_registers ) ); region += sizeof( m_configuration_registers ); + memcpy( m_data, region, sizeof( m_data ) ); region += sizeof( m_data ); + } +} + +void x76f041_device::nvram_read( emu_file &file ) +{ + file.read( m_response_to_reset, sizeof( m_response_to_reset ) ); + file.read( m_write_password, sizeof( m_write_password ) ); + file.read( m_read_password, sizeof( m_read_password ) ); + file.read( m_configuration_password, sizeof( m_configuration_password ) ); + file.read( m_configuration_registers, sizeof( m_configuration_registers ) ); + file.read( m_data, sizeof( m_data ) ); +} + +void x76f041_device::nvram_write( emu_file &file ) +{ + file.write( m_response_to_reset, sizeof( m_response_to_reset ) ); + file.write( m_write_password, sizeof( m_write_password ) ); + file.write( m_read_password, sizeof( m_read_password ) ); + file.write( m_configuration_password, sizeof( m_configuration_password ) ); + file.write( m_configuration_registers, sizeof( m_configuration_registers ) ); + file.write( m_data, sizeof( m_data ) ); +} diff --git a/src/devices/machine/x76f041.h b/src/devices/machine/x76f041.h new file mode 100644 index 00000000000..d1f8a8e9e46 --- /dev/null +++ b/src/devices/machine/x76f041.h @@ -0,0 +1,127 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/* + * x76f041.h + * + * Secure SerialFlash + * + */ + +#pragma once + +#ifndef __X76F041_H__ +#define __X76F041_H__ + +#include "emu.h" + +#define MCFG_X76F041_ADD( _tag ) \ + MCFG_DEVICE_ADD( _tag, X76F041, 0 ) + +class x76f041_device : public device_t, + public device_nvram_interface +{ +public: + // construction/destruction + x76f041_device( const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock ); + + DECLARE_WRITE_LINE_MEMBER( write_cs ); + DECLARE_WRITE_LINE_MEMBER( write_rst ); + DECLARE_WRITE_LINE_MEMBER( write_scl ); + DECLARE_WRITE_LINE_MEMBER( write_sda ); + DECLARE_READ_LINE_MEMBER( read_sda ); + +protected: + // device-level overrides + virtual void device_start(); + + // device_nvram_interface overrides + virtual void nvram_default(); + virtual void nvram_read( emu_file &file ); + virtual void nvram_write( emu_file &file ); + +private: + inline void ATTR_PRINTF( 3, 4 ) verboselog( int n_level, const char *s_fmt, ... ); + UINT8 *password(); + void password_ok(); + void load_address(); + int data_offset(); + + enum configuration_register_t + { + CONFIG_BCR1 = 0, + CONFIG_BCR2 = 1, + CONFIG_CR = 2, + CONFIG_RR = 3, + CONFIG_RC = 4 + }; + + enum bcr_t + { + BCR_X = 8, + BCR_Y = 4, + BCR_Z = 2, + BCR_T = 1 + }; + + enum command_t + { + COMMAND_WRITE = 0x00, + COMMAND_READ = 0x20, + COMMAND_WRITE_USE_CONFIGURATION_PASSWORD = 0x40, + COMMAND_READ_USE_CONFIGURATION_PASSWORD = 0x60, + COMMAND_CONFIGURATION = 0x80 + }; + + enum configuration_t + { + CONFIGURATION_PROGRAM_WRITE_PASSWORD = 0x00, + CONFIGURATION_PROGRAM_READ_PASSWORD = 0x10, + CONFIGURATION_PROGRAM_CONFIGURATION_PASSWORD = 0x20, + CONFIGURATION_RESET_WRITE_PASSWORD = 0x30, + CONFIGURATION_RESET_READ_PASSWORD = 0x40, + CONFIGURATION_PROGRAM_CONFIGURATION_REGISTERS = 0x50, + CONFIGURATION_READ_CONFIGURATION_REGISTERS = 0x60, + CONFIGURATION_MASS_PROGRAM = 0x70, + CONFIGURATION_MASS_ERASE = 0x80 + }; + + enum state_t + { + STATE_STOP, + STATE_RESPONSE_TO_RESET, + STATE_LOAD_COMMAND, + STATE_LOAD_ADDRESS, + STATE_LOAD_PASSWORD, + STATE_VERIFY_PASSWORD, + STATE_READ_DATA, + STATE_WRITE_DATA, + STATE_READ_CONFIGURATION_REGISTERS, + STATE_WRITE_CONFIGURATION_REGISTERS + }; + + // internal state + int m_cs; + int m_rst; + int m_scl; + int m_sdaw; + int m_sdar; + int m_state; + int m_shift; + int m_bit; + int m_byte; + int m_command; + int m_address; + UINT8 m_write_buffer[ 8 ]; + UINT8 m_response_to_reset[ 4 ]; + UINT8 m_write_password[ 8 ]; + UINT8 m_read_password[ 8 ]; + UINT8 m_configuration_password[ 8 ]; + UINT8 m_configuration_registers[ 8 ]; + UINT8 m_data[ 512 ]; +}; + + +// device type definition +extern const device_type X76F041; + +#endif diff --git a/src/devices/machine/x76f100.c b/src/devices/machine/x76f100.c new file mode 100644 index 00000000000..830a0e51448 --- /dev/null +++ b/src/devices/machine/x76f100.c @@ -0,0 +1,427 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/* + * x76f100.c + * + * Secure SerialFlash + * + * The X76F100 is a Password Access Security Supervisor, containing one 896-bit Secure SerialFlash array. + * Access to the memory array can be controlled by two 64-bit passwords. These passwords protect read and + * write operations of the memory array. + * + */ + +#include "emu.h" +#include "machine/x76f100.h" + +#define VERBOSE_LEVEL ( 0 ) + +inline void ATTR_PRINTF( 3, 4 ) x76f100_device::verboselog( int n_level, const char *s_fmt, ... ) +{ + if( VERBOSE_LEVEL >= n_level ) + { + va_list v; + char buf[ 32768 ]; + va_start( v, s_fmt ); + vsprintf( buf, s_fmt, v ); + va_end( v ); + logerror( "%s: x76f100(%s) %s", machine().describe_context(), tag(), buf ); + } +} + +// device type definition +const device_type X76F100 = &device_creator; + +x76f100_device::x76f100_device( const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock ) + : device_t( mconfig, X76F100, "X76F100 Flash", tag, owner, clock, "x76f100", __FILE__ ), + device_nvram_interface(mconfig, *this), + m_cs( 0 ), + m_rst( 0 ), + m_scl( 0 ), + m_sdaw( 0 ), + m_sdar( 0 ), + m_state( STATE_STOP ), + m_shift( 0 ), + m_bit( 0 ), + m_byte( 0 ), + m_command( 0 ) +{ +} + +void x76f100_device::device_start() +{ + memset( m_write_buffer, 0, sizeof( m_write_buffer ) ); + + save_item( NAME( m_cs ) ); + save_item( NAME( m_rst ) ); + save_item( NAME( m_scl ) ); + save_item( NAME( m_sdaw ) ); + save_item( NAME( m_sdar ) ); + save_item( NAME( m_state ) ); + save_item( NAME( m_shift ) ); + save_item( NAME( m_bit ) ); + save_item( NAME( m_byte ) ); + save_item( NAME( m_command ) ); + save_item( NAME( m_write_buffer ) ); + save_item( NAME( m_response_to_reset ) ); + save_item( NAME( m_write_password ) ); + save_item( NAME( m_read_password ) ); + save_item( NAME( m_data ) ); +} + +WRITE_LINE_MEMBER( x76f100_device::write_cs ) +{ + if( m_cs != state ) + { + verboselog( 2, "cs=%d\n", state ); + } + + if( m_cs != 0 && state == 0 ) + { + /* enable chip */ + m_state = STATE_STOP; + } + + if( m_cs == 0 && state != 0 ) + { + /* disable chip */ + m_state = STATE_STOP; + /* high impendence? */ + m_sdar = 0; + } + + m_cs = state; +} + +WRITE_LINE_MEMBER( x76f100_device::write_rst ) +{ + if( m_rst != state ) + { + verboselog( 2, "rst=%d\n", state ); + } + + if( m_rst == 0 && state != 0 && m_cs == 0 ) + { + verboselog( 1, "goto response to reset\n" ); + m_state = STATE_RESPONSE_TO_RESET; + m_bit = 0; + m_byte = 0; + } + + m_rst = state; +} + +UINT8 *x76f100_device::password() +{ + if( ( m_command & 0xe1 ) == COMMAND_READ ) + { + return m_read_password; + } + + return m_write_password; +} + +void x76f100_device::password_ok() +{ + if( ( m_command & 0xe1 ) == COMMAND_READ ) + { + m_state = STATE_READ_DATA; + } + else if( ( m_command & 0xe1 ) == COMMAND_WRITE ) + { + m_state = STATE_WRITE_DATA; + } + else + { + /* TODO: */ + } +} + +int x76f100_device::data_offset() +{ + int block_offset = ( m_command >> 1 ) & 0x0f; + + return ( block_offset * sizeof( m_write_buffer ) ) + m_byte; +} + +WRITE_LINE_MEMBER( x76f100_device::write_scl ) +{ + if( m_scl != state ) + { + verboselog( 2, "scl=%d\n", state ); + } + + if( m_cs == 0 ) + { + switch( m_state ) + { + case STATE_STOP: + break; + + case STATE_RESPONSE_TO_RESET: + if( m_scl != 0 && state == 0 ) + { + if( m_bit == 0 ) + { + m_shift = m_response_to_reset[ m_byte ]; + verboselog( 1, "<- response_to_reset[%d]: %02x\n", m_byte, m_shift ); + } + + m_sdar = m_shift & 1; + m_shift >>= 1; + m_bit++; + + if( m_bit == 8 ) + { + m_bit = 0; + m_byte++; + + if( m_byte == sizeof( m_response_to_reset ) ) + { + m_byte = 0; + } + } + } + break; + + case STATE_LOAD_COMMAND: + case STATE_LOAD_PASSWORD: + case STATE_VERIFY_PASSWORD: + case STATE_WRITE_DATA: + if( m_scl == 0 && state != 0 ) + { + if( m_bit < 8 ) + { + verboselog( 2, "clock\n" ); + m_shift <<= 1; + + if( m_sdaw != 0 ) + { + m_shift |= 1; + } + + m_bit++; + } + else + { + m_sdar = 0; + + switch( m_state ) + { + case STATE_LOAD_COMMAND: + m_command = m_shift; + verboselog( 1, "-> command: %02x\n", m_command ); + /* todo: verify command is valid? */ + m_state = STATE_LOAD_PASSWORD; + break; + + case STATE_LOAD_PASSWORD: + verboselog( 1, "-> password: %02x\n", m_shift ); + m_write_buffer[ m_byte++ ] = m_shift; + + if( m_byte == sizeof( m_write_buffer ) ) + { + m_state = STATE_VERIFY_PASSWORD; + } + break; + + case STATE_VERIFY_PASSWORD: + verboselog( 1, "-> verify password: %02x\n", m_shift ); + + /* todo: this should probably be handled as a command */ + if( m_shift == COMMAND_ACK_PASSWORD ) + { + /* todo: this should take 10ms before it returns ok. */ + if( memcmp( password(), m_write_buffer, sizeof( m_write_buffer ) ) == 0 ) + { + password_ok(); + } + else + { + m_sdar = 1; + } + } + break; + + case STATE_WRITE_DATA: + verboselog( 2, "-> data: %02x\n", m_shift ); + m_write_buffer[ m_byte++ ] = m_shift; + + if( m_byte == sizeof( m_write_buffer ) ) + { + for( m_byte = 0; m_byte < sizeof( m_write_buffer ); m_byte++ ) + { + int offset = data_offset(); + verboselog( 1, "-> data[ %03x ]: %02x\n", offset, m_write_buffer[ m_byte ] ); + m_data[ offset ] = m_write_buffer[ m_byte ]; + } + + m_byte = 0; + + verboselog( 1, "data flushed\n" ); + } + break; + } + + m_bit = 0; + m_shift = 0; + } + } + break; + + case STATE_READ_DATA: + if( m_scl == 0 && state != 0 ) + { + if( m_bit < 8 ) + { + if( m_bit == 0 ) + { + int offset; + + switch( m_state ) + { + case STATE_READ_DATA: + offset = data_offset(); + m_shift = m_data[ offset ]; + verboselog( 1, "<- data[ %02x ]: %02x\n", offset, m_shift ); + break; + } + } + + m_sdar = ( m_shift >> 7 ) & 1; + m_shift <<= 1; + m_bit++; + } + else + { + m_bit = 0; + m_sdar = 0; + + if( m_sdaw == 0 ) + { + verboselog( 2, "ack <-\n" ); + m_byte++; + } + else + { + verboselog( 2, "nak <-\n" ); + } + } + } + break; + } + } + + m_scl = state; +} + +WRITE_LINE_MEMBER( x76f100_device::write_sda ) +{ + if( m_sdaw != state ) + { + verboselog( 2, "sdaw=%d\n", state ); + } + + if( m_cs == 0 && m_scl != 0 ) + { + if( m_sdaw == 0 && state != 0 ) + { + verboselog( 1, "goto stop\n" ); + m_state = STATE_STOP; + m_sdar = 0; + } + + if( m_sdaw != 0 && state == 0 ) + { + switch( m_state ) + { + case STATE_STOP: + verboselog( 1, "goto start\n" ); + m_state = STATE_LOAD_COMMAND; + break; + + case STATE_LOAD_PASSWORD: + /* todo: this will be the 0xc0 command, but it's not handled as a command yet. */ + verboselog( 1, "goto start\n" ); + break; + + case STATE_READ_DATA: + verboselog( 1, "continue reading??\n" ); +// verboselog( 1, "goto load address\n" ); +// m_state = STATE_LOAD_ADDRESS; + break; + + default: + verboselog( 1, "skipped start (default)\n" ); + break; + } + + m_bit = 0; + m_byte = 0; + m_shift = 0; + m_sdar = 0; + } + } + + m_sdaw = state; +} + +READ_LINE_MEMBER( x76f100_device::read_sda ) +{ + if( m_cs != 0 ) + { + verboselog( 2, "not selected\n" ); + return 1; + } + + verboselog( 2, "sdar=%d\n", m_sdar ); + return m_sdar; +} + +void x76f100_device::nvram_default() +{ + m_response_to_reset[ 0 ] = 0x19; + m_response_to_reset[ 1 ] = 0x00; + m_response_to_reset[ 2 ] = 0xaa; + m_response_to_reset[ 3 ] = 0x55, + + memset( m_write_password, 0, sizeof( m_write_password ) ); + memset( m_read_password, 0, sizeof( m_read_password ) ); + memset( m_data, 0, sizeof( m_data ) ); + + int expected_size = sizeof( m_response_to_reset ) + sizeof( m_write_password ) + sizeof( m_read_password ) + sizeof( m_data ); + + if( !m_region ) + { + logerror( "x76f100(%s) region not found\n", tag() ); + } + else if( m_region->bytes() != expected_size ) + { + logerror("x76f100(%s) region length 0x%x expected 0x%x\n", tag(), m_region->bytes(), expected_size ); + } + else + { + UINT8 *region = m_region->base(); + + memcpy( m_response_to_reset, region, sizeof( m_response_to_reset )); region += sizeof( m_response_to_reset ); + memcpy( m_write_password, region, sizeof( m_write_password )); region += sizeof( m_write_password ); + memcpy( m_read_password, region, sizeof( m_read_password )); region += sizeof( m_read_password ); + memcpy( m_data, region, sizeof( m_data )); region += sizeof( m_data ); + } +} + +void x76f100_device::nvram_read( emu_file &file ) +{ + file.read( m_response_to_reset, sizeof( m_response_to_reset ) ); + file.read( m_write_password, sizeof( m_write_password ) ); + file.read( m_read_password, sizeof( m_read_password ) ); + file.read( m_data, sizeof( m_data ) ); +} + +void x76f100_device::nvram_write( emu_file &file ) +{ + file.write( m_response_to_reset, sizeof( m_response_to_reset ) ); + file.write( m_write_password, sizeof( m_write_password ) ); + file.write( m_read_password, sizeof( m_read_password ) ); + file.write( m_data, sizeof( m_data ) ); +} diff --git a/src/devices/machine/x76f100.h b/src/devices/machine/x76f100.h new file mode 100644 index 00000000000..dea839c4c5e --- /dev/null +++ b/src/devices/machine/x76f100.h @@ -0,0 +1,90 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/* + * x76f100.h + * + * Secure SerialFlash + * + */ + +#pragma once + +#ifndef __X76F100_H__ +#define __X76F100_H__ + +#include "emu.h" + +#define MCFG_X76F100_ADD( _tag ) \ + MCFG_DEVICE_ADD( _tag, X76F100, 0 ) + +class x76f100_device : public device_t, + public device_nvram_interface +{ +public: + // construction/destruction + x76f100_device( const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock ); + + DECLARE_WRITE_LINE_MEMBER( write_cs ); + DECLARE_WRITE_LINE_MEMBER( write_rst ); + DECLARE_WRITE_LINE_MEMBER( write_scl ); + DECLARE_WRITE_LINE_MEMBER( write_sda ); + DECLARE_READ_LINE_MEMBER( read_sda ); + +protected: + // device-level overrides + virtual void device_start(); + + // device_nvram_interface overrides + virtual void nvram_default(); + virtual void nvram_read( emu_file &file ); + virtual void nvram_write( emu_file &file ); + +private: + inline void verboselog(int n_level, const char *s_fmt, ...) ATTR_PRINTF(3,4); + + UINT8 *password(); + void password_ok(); + int data_offset(); + + enum command_t + { + COMMAND_WRITE = 0x80, + COMMAND_READ = 0x81, + COMMAND_CHANGE_WRITE_PASSWORD = 0xfc, + COMMAND_CHANGE_READ_PASSWORD = 0xfe, + COMMAND_ACK_PASSWORD = 0x55 + }; + + enum state_t + { + STATE_STOP, + STATE_RESPONSE_TO_RESET, + STATE_LOAD_COMMAND, + STATE_LOAD_PASSWORD, + STATE_VERIFY_PASSWORD, + STATE_READ_DATA, + STATE_WRITE_DATA + }; + + // internal state + int m_cs; + int m_rst; + int m_scl; + int m_sdaw; + int m_sdar; + int m_state; + int m_shift; + int m_bit; + int m_byte; + int m_command; + UINT8 m_write_buffer[ 8 ]; + UINT8 m_response_to_reset[ 4 ]; + UINT8 m_write_password[ 8 ]; + UINT8 m_read_password[ 8 ]; + UINT8 m_data[ 112 ]; +}; + +// device type definition +extern const device_type X76F100; + +#endif diff --git a/src/devices/machine/ym2148.c b/src/devices/machine/ym2148.c new file mode 100644 index 00000000000..d0f45fc8844 --- /dev/null +++ b/src/devices/machine/ym2148.c @@ -0,0 +1,209 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +/************************************************************************** + + Yamaha YM-2148 emulation + +TODO: +- Finish implemention of midi out + +**************************************************************************/ + +#include "emu.h" +#include "ym2148.h" + + +const device_type YM2148 = &device_creator; + + +ym2148_device::ym2148_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, YM2148, "YM2148", tag, owner, clock, "ym2148", __FILE__) + , device_serial_interface(mconfig, *this) + , m_txd_handler(*this) + , m_irq_handler(*this) + , m_port_write_handler(*this) + , m_port_read_handler(*this) + , m_irq_state(CLEAR_LINE) + , m_irq_vector(0xff) // guess + , m_external_irq_vector(0xff) // guess + , m_data_out(0) + , m_data_in(0) + , m_control(0) + , m_status(0) + , m_rxd(1) + , m_tx_busy(false) +{ +} + + +void ym2148_device::device_start() +{ + m_txd_handler.resolve_safe(); + m_irq_handler.resolve_safe(); + m_port_write_handler.resolve_safe(); + m_port_read_handler.resolve_safe(0xff); + + // Start a timer to trigger at clock / 8 / 16 + m_timer = timer_alloc(0); + m_timer->adjust(attotime::from_hz(m_clock / 8 / 16), 0, attotime::from_hz(m_clock / 8 / 16)); +} + + +void ym2148_device::device_reset() +{ + set_data_frame(1, 8, PARITY_NONE, STOP_BITS_1); + transmit_register_reset(); + receive_register_reset(); + m_status |= STATUS_TRANSMIT_READY; +} + + +void ym2148_device::receive_clock() +{ + if (m_control & CONTROL_RECEIVE_ENABLE) + { + /* get bit received from other side and update receive register */ + receive_register_update_bit(m_rxd); + + if (is_receive_register_full()) + { + receive_register_extract(); + + m_data_in = get_received_char(); + + if (m_status & STATUS_RECEIVE_BUFFER_FULL) + { + // Overrun error + m_status |= STATUS_OVERRUN_ERROR; + } + m_status |= STATUS_RECEIVE_BUFFER_FULL; + update_irq(); + } + } +} + + +void ym2148_device::transmit_clock() +{ + if (m_control & CONTROL_TRANSMIT_ENABLE) + { + if (!(m_status & STATUS_TRANSMIT_READY)) + { + /* is diserial ready for it? */ + if (is_transmit_register_empty()) + { + /* set it up */ + transmit_register_setup(m_data_out); + /* ready for next transmit */ + m_status |= STATUS_TRANSMIT_READY; + } + } + + /* if diserial has bits to send, make them so */ + if (!is_transmit_register_empty()) + { + UINT8 data = transmit_register_get_data_bit(); + m_tx_busy = true; + m_txd_handler(data); + } + + // is transmitter totally done? + if ((m_status & STATUS_TRANSMIT_READY) && is_transmit_register_empty()) + { + m_tx_busy = false; + } + } +} + + +void ym2148_device::update_irq() +{ + m_irq_state = CLEAR_LINE; + + if ((m_status & STATUS_RECEIVE_BUFFER_FULL) && (m_control & CONTROL_RECEIVE_IRQ_ENABLE)) + { + m_irq_state = ASSERT_LINE; + } + if ((m_status & STATUS_TRANSMIT_READY) && (m_control & CONTROL_TRANSMIT_IRQ_ENABLE)) + { +// m_irq_state = ASSERT_LINE; + } + + m_irq_handler(m_irq_state); +} + + +void ym2148_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + receive_clock(); + transmit_clock(); +} + + +READ8_MEMBER(ym2148_device::read) +{ + switch (offset & 7) + { + case 2: // External port read + return m_port_read_handler(); + + case 5: // Midi data read register + m_status &= ~STATUS_RECEIVE_BUFFER_FULL; + update_irq(); + return m_data_in; + + case 6: // Midi status register + return m_status; + } + return 0xff; +} + + +WRITE8_MEMBER(ym2148_device::write) +{ + switch (offset & 7) + { + case 2: // External port write + m_port_write_handler(data); + break; + + case 3: // IRQ vector + m_irq_vector = data; + break; + + case 4: // External IRQ vector + m_external_irq_vector = data; + break; + + case 5: // Midi data write register + m_data_out = data; + m_status &= ~STATUS_TRANSMIT_READY; + break; + + case 6: // Midi control register + m_control = data; + + if (m_control & 0x80) + { + // Reset + receive_clock(); + transmit_clock(); + m_irq_state = CLEAR_LINE; + m_irq_handler(m_irq_state); + } + update_irq(); + break; + } +} + + +UINT8 ym2148_device::get_irq_vector() +{ + return (m_irq_state == ASSERT_LINE) ? m_irq_vector : m_external_irq_vector; +} + + +WRITE_LINE_MEMBER(ym2148_device::write_rxd) +{ + m_rxd = state; +} diff --git a/src/devices/machine/ym2148.h b/src/devices/machine/ym2148.h new file mode 100644 index 00000000000..58d2d5cb360 --- /dev/null +++ b/src/devices/machine/ym2148.h @@ -0,0 +1,93 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +/********************************************************************* + + ym2148.h + + Yamaha YM2148 Midi and keyboard interface + +*********************************************************************/ + +#ifndef __YM2148_H__ +#define __YM2148_H__ + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_YM2148_TXD_HANDLER(_devcb) \ + devcb = &ym2148_device::set_txd_handler(*device, DEVCB_##_devcb); + +#define MCFG_YM2148_PORT_WRITE_HANDLER(_devcb) \ + devcb = &ym2148_device::set_port_write_handler(*device, DEVCB_##_devcb); + +#define MCFG_YM2148_PORT_READ_HANDLER(_devcb) \ + devcb = &ym2148_device::set_port_read_handler(*device, DEVCB_##_devcb); + +#define MCFG_YM2148_IRQ_HANDLER(_devcb) \ + devcb = &ym2148_device::set_irq_handler(*device, DEVCB_##_devcb); + + +class ym2148_device : public device_t, + public device_serial_interface +{ +public: + // construction/destruction + ym2148_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // static configuration helpers + template static devcb_base &set_txd_handler(device_t &device, _Object object) { return downcast(device).m_txd_handler.set_callback(object); } + template static devcb_base &set_port_write_handler(device_t &device, _Object object) { return downcast(device).m_port_write_handler.set_callback(object); } + template static devcb_base &set_port_read_handler(device_t &device, _Object object) { return downcast(device).m_port_read_handler.set_callback(object); } + template static devcb_base &set_irq_handler(device_t &device, _Object object) { return downcast(device).m_irq_handler.set_callback(object); } + + DECLARE_READ8_MEMBER(read); + DECLARE_WRITE8_MEMBER(write); + + DECLARE_WRITE_LINE_MEMBER(write_rxd); + UINT8 get_irq_vector(); + +protected: + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + +private: + devcb_write_line m_txd_handler; + devcb_write_line m_irq_handler; + devcb_write8 m_port_write_handler; // write ST0-ST7 + devcb_read8 m_port_read_handler; // read SD0-SD7 + int m_irq_state; + UINT8 m_irq_vector; + UINT8 m_external_irq_vector; + // Does this chip have 1 or 2 data registers? + UINT8 m_data_out; + UINT8 m_data_in; + UINT8 m_control; + UINT8 m_status; + emu_timer *m_timer; + int m_rxd; + bool m_tx_busy; + + void receive_clock(); + void transmit_clock(); + void update_irq(); + + enum + { + STATUS_TRANSMIT_READY = 0x01, + STATUS_RECEIVE_BUFFER_FULL = 0x2, + STATUS_OVERRUN_ERROR = 0x20, + CONTROL_TRANSMIT_ENABLE = 0x01, + CONTROL_TRANSMIT_IRQ_ENABLE = 0x02, + CONTROL_RECEIVE_ENABLE = 0x04, + CONTROL_RECEIVE_IRQ_ENABLE = 0x08 + }; +}; + + +extern const device_type YM2148; + + +#endif diff --git a/src/devices/machine/z80ctc.c b/src/devices/machine/z80ctc.c new file mode 100644 index 00000000000..8ab638a5e8d --- /dev/null +++ b/src/devices/machine/z80ctc.c @@ -0,0 +1,525 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +/*************************************************************************** + + Z80 CTC (Z8430) implementation + + based on original version (c) 1997, Tatsuyuki Satoh + +***************************************************************************/ + +#include "emu.h" +#include "z80ctc.h" +#include "cpu/z80/z80.h" +#include "cpu/z80/z80daisy.h" + + + +//************************************************************************** +// DEBUGGING +//************************************************************************** + +#define VERBOSE 0 + +#define VPRINTF(x) do { if (VERBOSE) logerror x; } while (0) + + + +//************************************************************************** +// CONSTANTS +//************************************************************************** + +// these are the bits of the incoming commands to the CTC +const int INTERRUPT = 0x80; +const int INTERRUPT_ON = 0x80; +//const int INTERRUPT_OFF = 0x00; + +const int MODE = 0x40; +const int MODE_TIMER = 0x00; +const int MODE_COUNTER = 0x40; + +const int PRESCALER = 0x20; +//const int PRESCALER_256 = 0x20; +const int PRESCALER_16 = 0x00; + +const int EDGE = 0x10; +const int EDGE_FALLING = 0x00; +const int EDGE_RISING = 0x10; + +const int TRIGGER = 0x08; +const int TRIGGER_AUTO = 0x00; +//const int TRIGGER_CLOCK = 0x08; + +const int CONSTANT = 0x04; +const int CONSTANT_LOAD = 0x04; +//const int CONSTANT_NONE = 0x00; + +const int RESET = 0x02; +//const int RESET_CONTINUE = 0x00; +const int RESET_ACTIVE = 0x02; + +const int CONTROL = 0x01; +const int CONTROL_VECTOR = 0x00; +const int CONTROL_WORD = 0x01; + +// these extra bits help us keep things accurate +const int WAITING_FOR_TRIG = 0x100; + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +// device type definition +const device_type Z80CTC = &device_creator; + +//------------------------------------------------- +// z80ctc_device - constructor +//------------------------------------------------- + +z80ctc_device::z80ctc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, Z80CTC, "Z80 CTC", tag, owner, clock, "z80ctc", __FILE__), + device_z80daisy_interface(mconfig, *this), + m_intr_cb(*this), + m_zc0_cb(*this), + m_zc1_cb(*this), + m_zc2_cb(*this), + m_zc3_cb(*this) +{ +} + + +//------------------------------------------------- +// read - standard handler for reading +//------------------------------------------------- + +READ8_MEMBER( z80ctc_device::read ) +{ + return m_channel[offset & 3].read(); +} + + +//------------------------------------------------- +// write - standard handler for writing +//------------------------------------------------- + +WRITE8_MEMBER( z80ctc_device::write ) +{ + m_channel[offset & 3].write(data); +} + + +//------------------------------------------------- +// trg0-3 - standard write line handlers for each +// trigger +//------------------------------------------------- + +WRITE_LINE_MEMBER( z80ctc_device::trg0 ) { m_channel[0].trigger(state); } +WRITE_LINE_MEMBER( z80ctc_device::trg1 ) { m_channel[1].trigger(state); } +WRITE_LINE_MEMBER( z80ctc_device::trg2 ) { m_channel[2].trigger(state); } +WRITE_LINE_MEMBER( z80ctc_device::trg3 ) { m_channel[3].trigger(state); } + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void z80ctc_device::device_start() +{ + m_period16 = attotime::from_hz(m_clock) * 16; + m_period256 = attotime::from_hz(m_clock) * 256; + + // resolve callbacks + m_intr_cb.resolve_safe(); + m_zc0_cb.resolve_safe(); + m_zc1_cb.resolve_safe(); + m_zc2_cb.resolve_safe(); + m_zc3_cb.resolve_safe(); + + // start each channel + m_channel[0].start(this, 0); + m_channel[1].start(this, 1); + m_channel[2].start(this, 2); + m_channel[3].start(this, 3); + + // register for save states + save_item(NAME(m_vector)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void z80ctc_device::device_reset() +{ + // reset each channel + m_channel[0].reset(); + m_channel[1].reset(); + m_channel[2].reset(); + m_channel[3].reset(); + + // check for interrupts + interrupt_check(); + VPRINTF(("CTC Reset\n")); +} + + + +//************************************************************************** +// DAISY CHAIN INTERFACE +//************************************************************************** + +//------------------------------------------------- +// z80daisy_irq_state - return the overall IRQ +// state for this device +//------------------------------------------------- + +int z80ctc_device::z80daisy_irq_state() +{ + VPRINTF(("CTC IRQ state = %d%d%d%d\n", m_channel[0].m_int_state, m_channel[1].m_int_state, m_channel[2].m_int_state, m_channel[3].m_int_state)); + + // loop over all channels + int state = 0; + for (int ch = 0; ch < 4; ch++) + { + ctc_channel &channel = m_channel[ch]; + + // if we're servicing a request, don't indicate more interrupts + if (channel.m_int_state & Z80_DAISY_IEO) + { + state |= Z80_DAISY_IEO; + break; + } + state |= channel.m_int_state; + } + + return state; +} + + +//------------------------------------------------- +// z80daisy_irq_ack - acknowledge an IRQ and +// return the appropriate vector +//------------------------------------------------- + +int z80ctc_device::z80daisy_irq_ack() +{ + // loop over all channels + for (int ch = 0; ch < 4; ch++) + { + ctc_channel &channel = m_channel[ch]; + + // find the first channel with an interrupt requested + if (channel.m_int_state & Z80_DAISY_INT) + { + VPRINTF(("CTC IRQAck ch%d\n", ch)); + + // clear interrupt, switch to the IEO state, and update the IRQs + channel.m_int_state = Z80_DAISY_IEO; + interrupt_check(); + return m_vector + ch * 2; + } + } + + //logerror("z80ctc_irq_ack: failed to find an interrupt to ack!\n"); + return m_vector; +} + + +//------------------------------------------------- +// z80daisy_irq_reti - clear the interrupt +// pending state to allow other interrupts through +//------------------------------------------------- + +void z80ctc_device::z80daisy_irq_reti() +{ + // loop over all channels + for (int ch = 0; ch < 4; ch++) + { + ctc_channel &channel = m_channel[ch]; + + // find the first channel with an IEO pending + if (channel.m_int_state & Z80_DAISY_IEO) + { + VPRINTF(("CTC IRQReti ch%d\n", ch)); + + // clear the IEO state and update the IRQs + channel.m_int_state &= ~Z80_DAISY_IEO; + interrupt_check(); + return; + } + } + + //logerror("z80ctc_irq_reti: failed to find an interrupt to clear IEO on!\n"); +} + + + +//************************************************************************** +// INTERNAL STATE MANAGEMENT +//************************************************************************** + +//------------------------------------------------- +// interrupt_check - look for pending interrupts +// and update the line +//------------------------------------------------- + +void z80ctc_device::interrupt_check() +{ + int state = (z80daisy_irq_state() & Z80_DAISY_INT) ? ASSERT_LINE : CLEAR_LINE; + m_intr_cb(state); +} + + + +//************************************************************************* +// CTC CHANNELS +//************************************************************************** + +//------------------------------------------------- +// ctc_channel - constructor +//------------------------------------------------- + +z80ctc_device::ctc_channel::ctc_channel() + : m_mode(0), + m_tconst(0), + m_down(0), + m_extclk(0), + m_timer(NULL), + m_int_state(0) +{ +} + + +//------------------------------------------------- +// start - set up at device start time +//------------------------------------------------- + +void z80ctc_device::ctc_channel::start(z80ctc_device *device, int index) +{ + // initialize state + m_device = device; + m_index = index; + m_timer = m_device->machine().scheduler().timer_alloc(FUNC(static_timer_callback), this); + + // register for save states + m_device->save_item(NAME(m_mode), m_index); + m_device->save_item(NAME(m_tconst), m_index); + m_device->save_item(NAME(m_down), m_index); + m_device->save_item(NAME(m_extclk), m_index); + m_device->save_item(NAME(m_int_state), m_index); +} + + +//------------------------------------------------- +// reset - reset the channel +//------------------------------------------------- + +void z80ctc_device::ctc_channel::reset() +{ + m_mode = RESET_ACTIVE; + m_tconst = 0x100; + m_timer->adjust(attotime::never); + m_int_state = 0; +} + + +//------------------------------------------------- +// period - return the current channel's period +//------------------------------------------------- + +attotime z80ctc_device::ctc_channel::period() const +{ + // if reset active, no period + if ((m_mode & RESET) == RESET_ACTIVE) + return attotime::zero; + + // if counter mode, no real period + if ((m_mode & MODE) == MODE_COUNTER) + { + logerror("CTC %d is CounterMode : Can't calculate period\n", m_index); + return attotime::zero; + } + + // compute the period + attotime period = ((m_mode & PRESCALER) == PRESCALER_16) ? m_device->m_period16 : m_device->m_period256; + return period * m_tconst; +} + + +//------------------------------------------------- +// read - read the channel's state +//------------------------------------------------- + +UINT8 z80ctc_device::ctc_channel::read() +{ + // if we're in counter mode, just return the count + if ((m_mode & MODE) == MODE_COUNTER || (m_mode & WAITING_FOR_TRIG)) + return m_down; + + // else compute the down counter value + else + { + attotime period = ((m_mode & PRESCALER) == PRESCALER_16) ? m_device->m_period16 : m_device->m_period256; + + VPRINTF(("CTC clock %f\n",ATTOSECONDS_TO_HZ(period.attoseconds()))); + + if (m_timer != NULL) + return ((int)(m_timer->remaining().as_double() / period.as_double()) + 1) & 0xff; + else + return 0; + } +} + + +//------------------------------------------------- +// write - handle writes to a channel +//------------------------------------------------- + +void z80ctc_device::ctc_channel::write(UINT8 data) +{ + // if we're waiting for a time constant, this is it + if ((m_mode & CONSTANT) == CONSTANT_LOAD) + { + VPRINTF(("CTC ch.%d constant = %02x\n", m_index, data)); + + // set the time constant (0 -> 0x100) + m_tconst = data ? data : 0x100; + + // clear the internal mode -- we're no longer waiting + m_mode &= ~CONSTANT; + + // also clear the reset, since the constant gets it going again + m_mode &= ~RESET; + + // if we're in timer mode.... + if ((m_mode & MODE) == MODE_TIMER) + { + // if we're triggering on the time constant, reset the down counter now + if ((m_mode & TRIGGER) == TRIGGER_AUTO) + { + attotime curperiod = period(); + m_timer->adjust(curperiod, m_index, curperiod); + } + + // else set the bit indicating that we're waiting for the appropriate trigger + else + m_mode |= WAITING_FOR_TRIG; + } + + // also set the down counter in case we're clocking externally + m_down = m_tconst; + } + + // if we're writing the interrupt vector, handle it specially +#if 0 /* Tatsuyuki Satoh changes */ + // The 'Z80family handbook' wrote, + // interrupt vector is able to set for even channel (0 or 2) + else if ((data & CONTROL) == CONTROL_VECTOR && (m_index & 1) == 0) +#else + else if ((data & CONTROL) == CONTROL_VECTOR && m_index == 0) +#endif + { + m_device->m_vector = data & 0xf8; + logerror("CTC Vector = %02x\n", m_device->m_vector); + } + + // this must be a control word + else if ((data & CONTROL) == CONTROL_WORD) + { + // set the new mode + m_mode = data; + VPRINTF(("CTC ch.%d mode = %02x\n", m_index, data)); + + // if we're being reset, clear out any pending timers for this channel + if ((data & RESET) == RESET_ACTIVE) + { + m_timer->adjust(attotime::never); + // note that we don't clear the interrupt state here! + } + } +} + + +//------------------------------------------------- +// trigger - clock this channel and handle any +// side-effects +//------------------------------------------------- + +void z80ctc_device::ctc_channel::trigger(UINT8 data) +{ + // normalize data + data = data ? 1 : 0; + + // see if the trigger value has changed + if (data != m_extclk) + { + m_extclk = data; + + // see if this is the active edge of the trigger + if (((m_mode & EDGE) == EDGE_RISING && data) || ((m_mode & EDGE) == EDGE_FALLING && !data)) + { + // if we're waiting for a trigger, start the timer + if ((m_mode & WAITING_FOR_TRIG) && (m_mode & MODE) == MODE_TIMER) + { + attotime curperiod = period(); + VPRINTF(("CTC period %s\n", curperiod.as_string())); + m_timer->adjust(curperiod, m_index, curperiod); + } + + // we're no longer waiting + m_mode &= ~WAITING_FOR_TRIG; + + // if we're clocking externally, decrement the count + if ((m_mode & MODE) == MODE_COUNTER) + { + // if we hit zero, do the same thing as for a timer interrupt + if (--m_down == 0) + timer_callback(); + } + } + } +} + + +//------------------------------------------------- +// trigger - clock this channel and handle any +// side-effects +//------------------------------------------------- + +void z80ctc_device::ctc_channel::timer_callback() +{ + // down counter has reached zero - see if we should interrupt + if ((m_mode & INTERRUPT) == INTERRUPT_ON) + { + m_int_state |= Z80_DAISY_INT; + VPRINTF(("CTC timer ch%d\n", m_index)); + m_device->interrupt_check(); + } + + // generate the clock pulse + switch (m_index) + { + case 0: + m_device->m_zc0_cb(1); + m_device->m_zc0_cb(0); + break; + case 1: + m_device->m_zc1_cb(1); + m_device->m_zc1_cb(0); + break; + case 2: + m_device->m_zc2_cb(1); + m_device->m_zc2_cb(0); + break; + case 3: + m_device->m_zc3_cb(1); + m_device->m_zc3_cb(0); + break; + } + + // reset the down counter + m_down = m_tconst; +} diff --git a/src/devices/machine/z80ctc.h b/src/devices/machine/z80ctc.h new file mode 100644 index 00000000000..b5191d21104 --- /dev/null +++ b/src/devices/machine/z80ctc.h @@ -0,0 +1,140 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +/*************************************************************************** + + Z80 CTC (Z8430) implementation + +**************************************************************************** + _____ _____ + D4 1 |* \_/ | 28 D3 + D5 2 | | 27 D2 + D6 3 | | 26 D1 + D7 4 | | 25 D0 + GND 5 | | 24 +5V + _RD 6 | | 23 CLK/TRG0 + ZC/TOO 7 | Z80-CTC | 22 CLK/TRG1 + ZC/TO1 8 | | 21 CLK/TRG2 + ZC/TO2 9 | | 20 CLK/TRG3 + _IORQ 10 | | 19 CS1 + IEO 11 | | 18 CS0 + _INT 12 | | 17 _RESET + IEI 13 | | 16 _CE + _M1 14 |_____________| 15 CLK + +***************************************************************************/ + +#ifndef __Z80CTC_H__ +#define __Z80CTC_H__ + +#include "cpu/z80/z80daisy.h" + + +//************************************************************************** +// DEVICE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_Z80CTC_INTR_CB(_devcb) \ + devcb = &z80ctc_device::set_intr_callback(*device, DEVCB_##_devcb); + +#define MCFG_Z80CTC_ZC0_CB(_devcb) \ + devcb = &z80ctc_device::set_zc0_callback(*device, DEVCB_##_devcb); + +#define MCFG_Z80CTC_ZC1_CB(_devcb) \ + devcb = &z80ctc_device::set_zc1_callback(*device, DEVCB_##_devcb); + +#define MCFG_Z80CTC_ZC2_CB(_devcb) \ + devcb = &z80ctc_device::set_zc2_callback(*device, DEVCB_##_devcb); + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + + +// ======================> z80ctc_device + +class z80ctc_device : public device_t, + public device_z80daisy_interface +{ +public: + // construction/destruction + z80ctc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + template static devcb_base &set_intr_callback(device_t &device, _Object object) { return downcast(device).m_intr_cb.set_callback(object); } + template static devcb_base &set_zc0_callback(device_t &device, _Object object) { return downcast(device).m_zc0_cb.set_callback(object); } + template static devcb_base &set_zc1_callback(device_t &device, _Object object) { return downcast(device).m_zc1_cb.set_callback(object); } + template static devcb_base &set_zc2_callback(device_t &device, _Object object) { return downcast(device).m_zc2_cb.set_callback(object); } + + // read/write handlers + DECLARE_READ8_MEMBER( read ); + DECLARE_WRITE8_MEMBER( write ); + DECLARE_WRITE_LINE_MEMBER( trg0 ); + DECLARE_WRITE_LINE_MEMBER( trg1 ); + DECLARE_WRITE_LINE_MEMBER( trg2 ); + DECLARE_WRITE_LINE_MEMBER( trg3 ); + + UINT16 get_channel_constant(UINT8 channel) { return m_channel[channel].m_tconst; } + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // z80daisy_interface overrides + virtual int z80daisy_irq_state(); + virtual int z80daisy_irq_ack(); + virtual void z80daisy_irq_reti(); + +private: + // internal helpers + void interrupt_check(); + void timercallback(int chanindex); + + // a single channel within the CTC + class ctc_channel + { + public: + ctc_channel(); + + void start(z80ctc_device *device, int index); + void reset(); + + UINT8 read(); + void write(UINT8 data); + + attotime period() const; + void trigger(UINT8 data); + void timer_callback(); + + z80ctc_device * m_device; // pointer back to our device + int m_index; // our channel index + UINT16 m_mode; // current mode + UINT16 m_tconst; // time constant + UINT16 m_down; // down counter (clock mode only) + UINT8 m_extclk; // current signal from the external clock + emu_timer * m_timer; // array of active timers + UINT8 m_int_state; // interrupt status (for daisy chain) + + private: + static TIMER_CALLBACK( static_timer_callback ) { reinterpret_cast(ptr)->timer_callback(); } + }; + + // internal state + devcb_write_line m_intr_cb; // interrupt callback + devcb_write_line m_zc0_cb; // channel 0 zero crossing callbacks + devcb_write_line m_zc1_cb; // channel 1 zero crossing callbacks + devcb_write_line m_zc2_cb; // channel 2 zero crossing callbacks + devcb_write_line m_zc3_cb; // channel 3 zero crossing callbacks = NULL ? + + UINT8 m_vector; // interrupt vector + attotime m_period16; // 16/system clock + attotime m_period256; // 256/system clock + ctc_channel m_channel[4]; // data for each channel +}; + + +// device type definition +extern const device_type Z80CTC; + + +#endif diff --git a/src/devices/machine/z80dart.c b/src/devices/machine/z80dart.c new file mode 100644 index 00000000000..6254d1d81f1 --- /dev/null +++ b/src/devices/machine/z80dart.c @@ -0,0 +1,1357 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/*************************************************************************** + + Intel 8274 Multi-Protocol Serial Controller emulation + NEC uPD7201 Multiprotocol Serial Communications Controller emulation + Z80-DART Dual Asynchronous Receiver/Transmitter emulation + Z80-SIO/0/1/2/3/4 Serial Input/Output Controller emulation + + The z80dart/z80sio itself is based on an older intel serial chip, the i8274 MPSC + (see http://doc.chipfind.ru/pdf/intel/8274.pdf), which also has almost identical + behavior, except lacks the interrupt daisy chaining and has its own interrupt/dma + scheme which uses write register 2 on channel A, that register which is unused on + the z80dart and z80sio. + +***************************************************************************/ + +/* + + TODO: + + - i8274 DMA scheme + - break detection + - wr0 reset tx interrupt pending + - wait/ready + - 1.5 stop bits + - synchronous mode (Z80-SIO/1,2) + - SDLC mode (Z80-SIO/1,2) + +*/ + +#include "z80dart.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define VERBOSE 0 + +#define LOG(x) do { if (VERBOSE) logerror x; } while (0) + +#define CHANA_TAG "cha" +#define CHANB_TAG "chb" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +// device type definition +const device_type Z80DART = &device_creator; +const device_type Z80DART_CHANNEL = &device_creator; +const device_type Z80SIO0 = &device_creator; +const device_type Z80SIO1 = &device_creator; +const device_type Z80SIO2 = &device_creator; +const device_type Z80SIO3 = &device_creator; +const device_type Z80SIO4 = &device_creator; +const device_type I8274 = &device_creator; +const device_type UPD7201 = &device_creator; + + +//------------------------------------------------- +// device_mconfig_additions - +//------------------------------------------------- + +MACHINE_CONFIG_FRAGMENT( z80dart ) + MCFG_DEVICE_ADD(CHANA_TAG, Z80DART_CHANNEL, 0) + MCFG_DEVICE_ADD(CHANB_TAG, Z80DART_CHANNEL, 0) +MACHINE_CONFIG_END + +machine_config_constructor z80dart_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( z80dart ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// z80dart_device - constructor +//------------------------------------------------- + +z80dart_device::z80dart_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, UINT32 variant, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_z80daisy_interface(mconfig, *this), + m_chanA(*this, CHANA_TAG), + m_chanB(*this, CHANB_TAG), + m_rxca(0), + m_txca(0), + m_rxcb(0), + m_txcb(0), + m_out_txda_cb(*this), + m_out_dtra_cb(*this), + m_out_rtsa_cb(*this), + m_out_wrdya_cb(*this), + m_out_synca_cb(*this), + m_out_txdb_cb(*this), + m_out_dtrb_cb(*this), + m_out_rtsb_cb(*this), + m_out_wrdyb_cb(*this), + m_out_syncb_cb(*this), + m_out_int_cb(*this), + m_out_rxdrqa_cb(*this), + m_out_txdrqa_cb(*this), + m_out_rxdrqb_cb(*this), + m_out_txdrqb_cb(*this), + m_variant(variant) +{ + for (int i = 0; i < 8; i++) + m_int_state[i] = 0; +} + +z80dart_device::z80dart_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, Z80DART, "Z80 DART", tag, owner, clock, "z80dart", __FILE__), + device_z80daisy_interface(mconfig, *this), + m_chanA(*this, CHANA_TAG), + m_chanB(*this, CHANB_TAG), + m_rxca(0), + m_txca(0), + m_rxcb(0), + m_txcb(0), + m_out_txda_cb(*this), + m_out_dtra_cb(*this), + m_out_rtsa_cb(*this), + m_out_wrdya_cb(*this), + m_out_synca_cb(*this), + m_out_txdb_cb(*this), + m_out_dtrb_cb(*this), + m_out_rtsb_cb(*this), + m_out_wrdyb_cb(*this), + m_out_syncb_cb(*this), + m_out_int_cb(*this), + m_out_rxdrqa_cb(*this), + m_out_txdrqa_cb(*this), + m_out_rxdrqb_cb(*this), + m_out_txdrqb_cb(*this), + m_variant(TYPE_DART) +{ + for (int i = 0; i < 8; i++) + m_int_state[i] = 0; +} + +z80sio0_device::z80sio0_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : z80dart_device(mconfig, Z80SIO0, "Z80 SIO/0", tag, owner, clock, TYPE_SIO0, "z80sio0", __FILE__) +{ +} + +z80sio1_device::z80sio1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : z80dart_device(mconfig, Z80SIO1, "Z80 SIO/1", tag, owner, clock, TYPE_SIO1, "z80sio1", __FILE__) +{ +} + +z80sio2_device::z80sio2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : z80dart_device(mconfig, Z80SIO2, "Z80 SIO/2", tag, owner, clock, TYPE_SIO2, "z80sio2", __FILE__) +{ +} + +z80sio3_device::z80sio3_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : z80dart_device(mconfig, Z80SIO3, "Z80 SIO/3", tag, owner, clock, TYPE_SIO3, "z80sio3", __FILE__) +{ +} + +z80sio4_device::z80sio4_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : z80dart_device(mconfig, Z80SIO4, "Z80 SIO/4", tag, owner, clock, TYPE_SIO4, "z80sio4", __FILE__) +{ +} + +i8274_device::i8274_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : z80dart_device(mconfig, I8274, "I8274", tag, owner, clock, TYPE_I8274, "i8274", __FILE__) +{ +} + +upd7201_device::upd7201_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : z80dart_device(mconfig, UPD7201, "uPD7201", tag, owner, clock, TYPE_UPD7201, "upd7201", __FILE__) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void z80dart_device::device_start() +{ + // resolve callbacks + m_out_txda_cb.resolve_safe(); + m_out_dtra_cb.resolve_safe(); + m_out_rtsa_cb.resolve_safe(); + m_out_wrdya_cb.resolve_safe(); + m_out_synca_cb.resolve_safe(); + m_out_txdb_cb.resolve_safe(); + m_out_dtrb_cb.resolve_safe(); + m_out_rtsb_cb.resolve_safe(); + m_out_wrdyb_cb.resolve_safe(); + m_out_syncb_cb.resolve_safe(); + m_out_int_cb.resolve_safe(); + m_out_rxdrqa_cb.resolve_safe(); + m_out_txdrqa_cb.resolve_safe(); + m_out_rxdrqb_cb.resolve_safe(); + m_out_txdrqb_cb.resolve_safe(); + + // configure channel A + m_chanA->m_rxc = m_rxca; + m_chanA->m_txc = m_txca; + + // configure channel B + m_chanB->m_rxc = m_rxcb; + m_chanB->m_txc = m_txcb; + + // state saving + save_item(NAME(m_int_state)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void z80dart_device::device_reset() +{ + LOG(("Z80DART \"%s\" Reset\n", tag())); + + m_chanA->reset(); + m_chanB->reset(); +} + +//------------------------------------------------- +// z80daisy_irq_state - get interrupt status +//------------------------------------------------- + +int z80dart_device::z80daisy_irq_state() +{ + int state = 0; + int i; + + LOG(("Z80DART \"%s\" : Interrupt State A:%d%d%d%d B:%d%d%d%d\n", tag(), + m_int_state[0], m_int_state[1], m_int_state[2], m_int_state[3], + m_int_state[4], m_int_state[5], m_int_state[6], m_int_state[7])); + + // loop over all interrupt sources + for (i = 0; i < 8; i++) + { + // if we're servicing a request, don't indicate more interrupts + if (m_int_state[i] & Z80_DAISY_IEO) + { + state |= Z80_DAISY_IEO; + break; + } + state |= m_int_state[i]; + } + + LOG(("Z80DART \"%s\" : Interrupt State %u\n", tag(), state)); + + return state; +} + + +//------------------------------------------------- +// z80daisy_irq_ack - interrupt acknowledge +//------------------------------------------------- + +int z80dart_device::z80daisy_irq_ack() +{ + int i; + + LOG(("Z80DART \"%s\" Interrupt Acknowledge\n", tag())); + + // loop over all interrupt sources + for (i = 0; i < 8; i++) + { + // find the first channel with an interrupt requested + if (m_int_state[i] & Z80_DAISY_INT) + { + // clear interrupt, switch to the IEO state, and update the IRQs + m_int_state[i] = Z80_DAISY_IEO; + m_chanA->m_rr[0] &= ~z80dart_channel::RR0_INTERRUPT_PENDING; + check_interrupts(); + + LOG(("Z80DART \"%s\" : Interrupt Acknowledge Vector %02x\n", tag(), m_chanB->m_rr[2])); + + return m_chanB->m_rr[2]; + } + } + + //logerror("z80dart_irq_ack: failed to find an interrupt to ack!\n"); + + return m_chanB->m_rr[2]; +} + + +//------------------------------------------------- +// z80daisy_irq_reti - return from interrupt +//------------------------------------------------- + +void z80dart_device::z80daisy_irq_reti() +{ + int i; + + LOG(("Z80DART \"%s\" Return from Interrupt\n", tag())); + + // loop over all interrupt sources + for (i = 0; i < 8; i++) + { + // find the first channel with an IEO pending + if (m_int_state[i] & Z80_DAISY_IEO) + { + // clear the IEO state and update the IRQs + m_int_state[i] &= ~Z80_DAISY_IEO; + check_interrupts(); + return; + } + } + + //logerror("z80dart_irq_reti: failed to find an interrupt to clear IEO on!\n"); +} + + +//------------------------------------------------- +// check_interrupts - +//------------------------------------------------- + +void z80dart_device::check_interrupts() +{ + int state = (z80daisy_irq_state() & Z80_DAISY_INT) ? ASSERT_LINE : CLEAR_LINE; + m_out_int_cb(state); +} + + +//------------------------------------------------- +// reset_interrupts - +//------------------------------------------------- + +void z80dart_device::reset_interrupts() +{ + for (int i = 0; i < 8; i++) + { + m_int_state[i] = 0; + } + + check_interrupts(); +} + + +//------------------------------------------------- +// trigger_interrupt - +//------------------------------------------------- + +void z80dart_device::trigger_interrupt(int index, int state) +{ + UINT8 vector = m_chanB->m_wr[2]; + int priority; + + if((m_variant == TYPE_I8274) || (m_variant == TYPE_UPD7201)) + { + int prio_level = 0; + switch(state) + { + case z80dart_channel::INT_TRANSMIT: + prio_level = 1; + break; + case z80dart_channel::INT_RECEIVE: + case z80dart_channel::INT_SPECIAL: + prio_level = 0; + break; + case z80dart_channel::INT_EXTERNAL: + prio_level = 2; + break; + } + + if(m_chanA->m_wr[2] & z80dart_channel::WR2_PRIORITY) + { + priority = (prio_level * 2) + index; + } + else + { + priority = (prio_level == 2) ? index + 4 : ((index * 2) + prio_level); + } + if (m_chanB->m_wr[1] & z80dart_channel::WR1_STATUS_VECTOR) + { + vector = (!index << 2) | state; + if((m_chanA->m_wr[1] & 0x18) == z80dart_channel::WR2_MODE_8086_8088) + { + vector = (m_chanB->m_wr[2] & 0xf8) | vector; + } + else + { + vector = (m_chanB->m_wr[2] & 0xe3) | (vector << 2); + } + } + } + else + { + priority = (index << 2) | state; + if (m_chanB->m_wr[1] & z80dart_channel::WR1_STATUS_VECTOR) + { + // status affects vector + vector = (m_chanB->m_wr[2] & 0xf1) | (!index << 3) | (state << 1); + } + } + + LOG(("Z80DART \"%s\" Channel %c : Interrupt Request %u\n", tag(), 'A' + index, state)); + + // update vector register + m_chanB->m_rr[2] = vector; + + // trigger interrupt + m_int_state[priority] |= Z80_DAISY_INT; + m_chanA->m_rr[0] |= z80dart_channel::RR0_INTERRUPT_PENDING; + + // check for interrupt + check_interrupts(); +} + + +//------------------------------------------------- +// m1_r - interrupt acknowledge +//------------------------------------------------- + +int z80dart_device::m1_r() +{ + return z80daisy_irq_ack(); +} + + +//------------------------------------------------- +// cd_ba_r - +//------------------------------------------------- + +READ8_MEMBER( z80dart_device::cd_ba_r ) +{ + int ba = BIT(offset, 0); + int cd = BIT(offset, 1); + z80dart_channel *channel = ba ? m_chanB : m_chanA; + + return cd ? channel->control_read() : channel->data_read(); +} + + +//------------------------------------------------- +// cd_ba_w - +//------------------------------------------------- + +WRITE8_MEMBER( z80dart_device::cd_ba_w ) +{ + int ba = BIT(offset, 0); + int cd = BIT(offset, 1); + z80dart_channel *channel = ba ? m_chanB : m_chanA; + + if (cd) + channel->control_write(data); + else + channel->data_write(data); +} + + +//------------------------------------------------- +// ba_cd_r - +//------------------------------------------------- + +READ8_MEMBER( z80dart_device::ba_cd_r ) +{ + int ba = BIT(offset, 1); + int cd = BIT(offset, 0); + z80dart_channel *channel = ba ? m_chanB : m_chanA; + + return cd ? channel->control_read() : channel->data_read(); +} + + +//------------------------------------------------- +// ba_cd_w - +//------------------------------------------------- + +WRITE8_MEMBER( z80dart_device::ba_cd_w ) +{ + int ba = BIT(offset, 1); + int cd = BIT(offset, 0); + z80dart_channel *channel = ba ? m_chanB : m_chanA; + + if (cd) + channel->control_write(data); + else + channel->data_write(data); +} + + + +//************************************************************************** +// DART CHANNEL +//************************************************************************** + +//------------------------------------------------- +// dart_channel - constructor +//------------------------------------------------- + +z80dart_channel::z80dart_channel(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, Z80DART_CHANNEL, "Z80 DART channel", tag, owner, clock, "z80dart_channel", __FILE__), + device_serial_interface(mconfig, *this), + m_rx_error(0), + m_rx_fifo(-1), + m_rx_clock(0), + m_rx_first(0), + m_rx_break(0), + m_rx_rr0_latch(0), + m_rxd(0), + m_ri(0), + m_cts(0), + m_dcd(0), + m_tx_data(0), + m_tx_clock(0), + m_dtr(0), + m_rts(0), + m_sync(0) +{ + for (int i = 0; i < 3; i++) + m_rr[i] = 0; + + for (int i = 0; i < 6; i++) + m_wr[i] = 0; + + for (int i = 0; i < 3; i++) + { + m_rx_data_fifo[i] = 0; + m_rx_error_fifo[i] = 0; + } +} + + +//------------------------------------------------- +// start - channel startup +//------------------------------------------------- + +void z80dart_channel::device_start() +{ + m_uart = downcast(owner()); + m_index = m_uart->get_channel_index(this); + + // state saving + save_item(NAME(m_rr)); + save_item(NAME(m_wr)); + save_item(NAME(m_rx_data_fifo)); + save_item(NAME(m_rx_error_fifo)); + save_item(NAME(m_rx_error)); + save_item(NAME(m_rx_fifo)); + save_item(NAME(m_rx_clock)); + save_item(NAME(m_rx_first)); + save_item(NAME(m_rx_break)); + save_item(NAME(m_rx_rr0_latch)); + save_item(NAME(m_ri)); + save_item(NAME(m_cts)); + save_item(NAME(m_dcd)); + save_item(NAME(m_tx_data)); + save_item(NAME(m_tx_clock)); + save_item(NAME(m_dtr)); + save_item(NAME(m_rts)); + save_item(NAME(m_sync)); + device_serial_interface::register_save_state(machine().save(), this); +} + + +//------------------------------------------------- +// reset - reset channel status +//------------------------------------------------- + +void z80dart_channel::device_reset() +{ + receive_register_reset(); + transmit_register_reset(); + + // disable receiver + m_wr[3] &= ~WR3_RX_ENABLE; + + // disable transmitter + m_wr[5] &= ~WR5_TX_ENABLE; + m_rr[0] |= RR0_TX_BUFFER_EMPTY; + m_rr[1] |= RR1_ALL_SENT; + + // reset external lines + set_rts(1); + set_dtr(1); + + // reset interrupts + if (m_index == z80dart_device::CHANNEL_A) + { + m_uart->reset_interrupts(); + } +} + +void z80dart_channel::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + device_serial_interface::device_timer(timer, id, param, ptr); +} + + +//------------------------------------------------- +// tra_callback - +//------------------------------------------------- + +void z80dart_channel::tra_callback() +{ + if (!(m_wr[5] & WR5_TX_ENABLE)) + { + // transmit mark + if (m_index == z80dart_device::CHANNEL_A) + m_uart->m_out_txda_cb(1); + else + m_uart->m_out_txdb_cb(1); + } + else if (m_wr[5] & WR5_SEND_BREAK) + { + // transmit break + if (m_index == z80dart_device::CHANNEL_A) + m_uart->m_out_txda_cb(0); + else + m_uart->m_out_txdb_cb(0); + } + else if (!is_transmit_register_empty()) + { + // transmit data + if (m_index == z80dart_device::CHANNEL_A) + m_uart->m_out_txda_cb(transmit_register_get_data_bit()); + else + m_uart->m_out_txdb_cb(transmit_register_get_data_bit()); + } +} + + +//------------------------------------------------- +// tra_complete - +//------------------------------------------------- + +void z80dart_channel::tra_complete() +{ + if ((m_wr[5] & WR5_TX_ENABLE) && !(m_wr[5] & WR5_SEND_BREAK) && !(m_rr[0] & RR0_TX_BUFFER_EMPTY)) + { + LOG(("Z80DART \"%s\" Channel %c : Transmit Data Byte '%02x'\n", m_owner->tag(), 'A' + m_index, m_tx_data)); + + transmit_register_setup(m_tx_data); + + // empty transmit buffer + m_rr[0] |= RR0_TX_BUFFER_EMPTY; + + if (m_wr[1] & WR1_TX_INT_ENABLE) + m_uart->trigger_interrupt(m_index, INT_TRANSMIT); + } + else if (m_wr[5] & WR5_SEND_BREAK) + { + // transmit break + if (m_index == z80dart_device::CHANNEL_A) + m_uart->m_out_txda_cb(0); + else + m_uart->m_out_txdb_cb(0); + } + else + { + // transmit mark + if (m_index == z80dart_device::CHANNEL_A) + m_uart->m_out_txda_cb(1); + else + m_uart->m_out_txdb_cb(1); + } + + // if transmit buffer is empty + if (m_rr[0] & RR0_TX_BUFFER_EMPTY) + { + // then all characters have been sent + m_rr[1] |= RR1_ALL_SENT; + + // when the RTS bit is reset, the _RTS output goes high after the transmitter empties + if (!m_rts) + set_rts(1); + } +} + + +//------------------------------------------------- +// rcv_callback - +//------------------------------------------------- + +void z80dart_channel::rcv_callback() +{ + if (m_wr[3] & WR3_RX_ENABLE) + { + receive_register_update_bit(m_rxd); + } +} + + +//------------------------------------------------- +// rcv_complete - +//------------------------------------------------- + +void z80dart_channel::rcv_complete() +{ + receive_register_extract(); + receive_data(get_received_char()); +} + + +//------------------------------------------------- +// get_clock_mode - get clock divisor +//------------------------------------------------- + +int z80dart_channel::get_clock_mode() +{ + int clocks = 1; + + switch (m_wr[4] & WR4_CLOCK_RATE_MASK) + { + case WR4_CLOCK_RATE_X1: clocks = 1; break; + case WR4_CLOCK_RATE_X16: clocks = 16; break; + case WR4_CLOCK_RATE_X32: clocks = 32; break; + case WR4_CLOCK_RATE_X64: clocks = 64; break; + } + + return clocks; +} + + +//------------------------------------------------- +// get_stop_bits - get number of stop bits +//------------------------------------------------- + +device_serial_interface::stop_bits_t z80dart_channel::get_stop_bits() +{ + switch (m_wr[4] & WR4_STOP_BITS_MASK) + { + case WR4_STOP_BITS_1: return STOP_BITS_1; + case WR4_STOP_BITS_1_5: return STOP_BITS_1_5; + case WR4_STOP_BITS_2: return STOP_BITS_2; + } + + return STOP_BITS_0; +} + + +//------------------------------------------------- +// get_rx_word_length - get receive word length +//------------------------------------------------- + +int z80dart_channel::get_rx_word_length() +{ + int bits = 5; + + switch (m_wr[3] & WR3_RX_WORD_LENGTH_MASK) + { + case WR3_RX_WORD_LENGTH_5: bits = 5; break; + case WR3_RX_WORD_LENGTH_6: bits = 6; break; + case WR3_RX_WORD_LENGTH_7: bits = 7; break; + case WR3_RX_WORD_LENGTH_8: bits = 8; break; + } + + return bits; +} + + +//------------------------------------------------- +// get_tx_word_length - get transmit word length +//------------------------------------------------- + +int z80dart_channel::get_tx_word_length() +{ + int bits = 5; + + switch (m_wr[5] & WR5_TX_WORD_LENGTH_MASK) + { + case WR5_TX_WORD_LENGTH_5: bits = 5; break; + case WR5_TX_WORD_LENGTH_6: bits = 6; break; + case WR5_TX_WORD_LENGTH_7: bits = 7; break; + case WR5_TX_WORD_LENGTH_8: bits = 8; break; + } + + return bits; +} + + +//------------------------------------------------- +// control_read - read control register +//------------------------------------------------- + +UINT8 z80dart_channel::control_read() +{ + UINT8 data = 0; + + int reg = m_wr[0] & WR0_REGISTER_MASK; + + if (reg != 0) + { + // mask out register index + m_wr[0] &= ~WR0_REGISTER_MASK; + } + + switch (reg) + { + case 0: + case 1: + data = m_rr[reg]; + break; + + case 2: + // channel B only + if (m_index == z80dart_device::CHANNEL_B) + data = m_rr[reg]; + break; + } + + //LOG(("Z80DART \"%s\" Channel %c : Control Register Read '%02x'\n", m_owner->tag(), 'A' + m_index, data)); + + return data; +} + + +//------------------------------------------------- +// control_write - write control register +//------------------------------------------------- + +void z80dart_channel::control_write(UINT8 data) +{ + int reg = m_wr[0] & WR0_REGISTER_MASK; + + LOG(("Z80DART \"%s\" Channel %c : Control Register Write '%02x'\n", m_owner->tag(), 'A' + m_index, data)); + + // write data to selected register + if (reg < 6) + m_wr[reg] = data; + + if (reg != 0) + { + // mask out register index + m_wr[0] &= ~WR0_REGISTER_MASK; + } + + switch (reg) + { + case 0: + switch (data & WR0_COMMAND_MASK) + { + case WR0_NULL: + LOG(("Z80DART \"%s\" Channel %c : Null\n", m_owner->tag(), 'A' + m_index)); + break; + + case WR0_SEND_ABORT: + LOG(("Z80DART \"%s\" Channel %c : Send Abort\n", m_owner->tag(), 'A' + m_index)); + logerror("Z80DART \"%s\" Channel %c : unsupported command: Send Abort\n", m_owner->tag(), 'A' + m_index); + break; + + case WR0_RESET_EXT_STATUS: + // reset external/status interrupt + m_rr[0] &= ~(RR0_DCD | RR0_RI | RR0_CTS | RR0_BREAK_ABORT); + + if (!m_dcd) m_rr[0] |= RR0_DCD; + if (m_ri) m_rr[0] |= RR0_RI; + if (m_cts) m_rr[0] |= RR0_CTS; + + m_rx_rr0_latch = 0; + + LOG(("Z80DART \"%s\" Channel %c : Reset External/Status Interrupt\n", m_owner->tag(), 'A' + m_index)); + break; + + case WR0_CHANNEL_RESET: + // channel reset + LOG(("Z80DART \"%s\" Channel %c : Channel Reset\n", m_owner->tag(), 'A' + m_index)); + device_reset(); + break; + + case WR0_ENABLE_INT_NEXT_RX: + // enable interrupt on next receive character + LOG(("Z80DART \"%s\" Channel %c : Enable Interrupt on Next Received Character\n", m_owner->tag(), 'A' + m_index)); + m_rx_first = 1; + break; + + case WR0_RESET_TX_INT: + // reset transmitter interrupt pending + LOG(("Z80DART \"%s\" Channel %c : Reset Transmitter Interrupt Pending\n", m_owner->tag(), 'A' + m_index)); + logerror("Z80DART \"%s\" Channel %c : unsupported command: Reset Transmitter Interrupt Pending\n", m_owner->tag(), 'A' + m_index); + break; + + case WR0_ERROR_RESET: + // error reset + LOG(("Z80DART \"%s\" Channel %c : Error Reset\n", m_owner->tag(), 'A' + m_index)); + m_rr[1] &= ~(RR1_CRC_FRAMING_ERROR | RR1_RX_OVERRUN_ERROR | RR1_PARITY_ERROR); + break; + + case WR0_RETURN_FROM_INT: + // return from interrupt + LOG(("Z80DART \"%s\" Channel %c : Return from Interrupt\n", m_owner->tag(), 'A' + m_index)); + m_uart->z80daisy_irq_reti(); + break; + } + break; + + case 1: + LOG(("Z80DART \"%s\" Channel %c : External Interrupt Enable %u\n", m_owner->tag(), 'A' + m_index, (data & WR1_EXT_INT_ENABLE) ? 1 : 0)); + LOG(("Z80DART \"%s\" Channel %c : Transmit Interrupt Enable %u\n", m_owner->tag(), 'A' + m_index, (data & WR1_TX_INT_ENABLE) ? 1 : 0)); + LOG(("Z80DART \"%s\" Channel %c : Status Affects Vector %u\n", m_owner->tag(), 'A' + m_index, (data & WR1_STATUS_VECTOR) ? 1 : 0)); + LOG(("Z80DART \"%s\" Channel %c : Wait/Ready Enable %u\n", m_owner->tag(), 'A' + m_index, (data & WR1_WRDY_ENABLE) ? 1 : 0)); + LOG(("Z80DART \"%s\" Channel %c : Wait/Ready Function %s\n", m_owner->tag(), 'A' + m_index, (data & WR1_WRDY_FUNCTION) ? "Ready" : "Wait")); + LOG(("Z80DART \"%s\" Channel %c : Wait/Ready on %s\n", m_owner->tag(), 'A' + m_index, (data & WR1_WRDY_ON_RX_TX) ? "Receive" : "Transmit")); + + switch (data & WR1_RX_INT_MODE_MASK) + { + case WR1_RX_INT_DISABLE: + LOG(("Z80DART \"%s\" Channel %c : Receiver Interrupt Disabled\n", m_owner->tag(), 'A' + m_index)); + break; + + case WR1_RX_INT_FIRST: + LOG(("Z80DART \"%s\" Channel %c : Receiver Interrupt on First Character\n", m_owner->tag(), 'A' + m_index)); + break; + + case WR1_RX_INT_ALL_PARITY: + LOG(("Z80DART \"%s\" Channel %c : Receiver Interrupt on All Characters, Parity Affects Vector\n", m_owner->tag(), 'A' + m_index)); + break; + + case WR1_RX_INT_ALL: + LOG(("Z80DART \"%s\" Channel %c : Receiver Interrupt on All Characters\n", m_owner->tag(), 'A' + m_index)); + break; + } + + m_uart->check_interrupts(); + break; + + case 2: + // interrupt vector + if (m_index == z80dart_device::CHANNEL_B) + { + if(m_wr[1] & z80dart_channel::WR1_STATUS_VECTOR) + m_rr[2] = ( m_rr[2] & 0x0e ) | ( m_wr[2] & 0xF1); + else + m_rr[2] = m_wr[2]; + } + m_uart->check_interrupts(); + LOG(("Z80DART \"%s\" Channel %c : Interrupt Vector %02x\n", m_owner->tag(), 'A' + m_index, data)); + break; + + case 3: + LOG(("Z80DART \"%s\" Channel %c : Receiver Enable %u\n", m_owner->tag(), 'A' + m_index, (data & WR3_RX_ENABLE) ? 1 : 0)); + LOG(("Z80DART \"%s\" Channel %c : Auto Enables %u\n", m_owner->tag(), 'A' + m_index, (data & WR3_AUTO_ENABLES) ? 1 : 0)); + LOG(("Z80DART \"%s\" Channel %c : Receiver Bits/Character %u\n", m_owner->tag(), 'A' + m_index, get_rx_word_length())); + + update_serial(); + break; + + case 4: + LOG(("Z80DART \"%s\" Channel %c : Parity Enable %u\n", m_owner->tag(), 'A' + m_index, (data & WR4_PARITY_ENABLE) ? 1 : 0)); + LOG(("Z80DART \"%s\" Channel %c : Parity %s\n", m_owner->tag(), 'A' + m_index, (data & WR4_PARITY_EVEN) ? "Even" : "Odd")); + LOG(("Z80DART \"%s\" Channel %c : Stop Bits %s\n", m_owner->tag(), 'A' + m_index, stop_bits_tostring(get_stop_bits()))); + LOG(("Z80DART \"%s\" Channel %c : Clock Mode %uX\n", m_owner->tag(), 'A' + m_index, get_clock_mode())); + + update_serial(); + break; + + case 5: + LOG(("Z80DART \"%s\" Channel %c : Transmitter Enable %u\n", m_owner->tag(), 'A' + m_index, (data & WR5_TX_ENABLE) ? 1 : 0)); + LOG(("Z80DART \"%s\" Channel %c : Transmitter Bits/Character %u\n", m_owner->tag(), 'A' + m_index, get_tx_word_length())); + LOG(("Z80DART \"%s\" Channel %c : Send Break %u\n", m_owner->tag(), 'A' + m_index, (data & WR5_SEND_BREAK) ? 1 : 0)); + LOG(("Z80DART \"%s\" Channel %c : Request to Send %u\n", m_owner->tag(), 'A' + m_index, (data & WR5_RTS) ? 1 : 0)); + LOG(("Z80DART \"%s\" Channel %c : Data Terminal Ready %u\n", m_owner->tag(), 'A' + m_index, (data & WR5_DTR) ? 1 : 0)); + + update_serial(); + + if (data & WR5_RTS) + { + // when the RTS bit is set, the _RTS output goes low + set_rts(0); + m_rts = 1; + } + else + { + // when the RTS bit is reset, the _RTS output goes high after the transmitter empties + m_rts = 0; + } + + // data terminal ready output follows the state programmed into the DTR bit*/ + set_dtr((data & WR5_DTR) ? 0 : 1); + break; + + case 6: + LOG(("Z80DART \"%s\" Channel %c : Transmit Sync %02x\n", m_owner->tag(), 'A' + m_index, data)); + m_sync = (m_sync & 0xff00) | data; + break; + + case 7: + LOG(("Z80DART \"%s\" Channel %c : Receive Sync %02x\n", m_owner->tag(), 'A' + m_index, data)); + m_sync = (data << 8) | (m_sync & 0xff); + break; + } +} + + +//------------------------------------------------- +// data_read - read data register +//------------------------------------------------- + +UINT8 z80dart_channel::data_read() +{ + UINT8 data = 0; + + if (m_rx_fifo >= 0) + { + // load data from the FIFO + data = m_rx_data_fifo[m_rx_fifo]; + + // load error status from the FIFO + m_rr[1] = (m_rr[1] & ~(RR1_CRC_FRAMING_ERROR | RR1_RX_OVERRUN_ERROR | RR1_PARITY_ERROR)) | m_rx_error_fifo[m_rx_fifo]; + + // decrease FIFO pointer + m_rx_fifo--; + + if (m_rx_fifo < 0) + { + // no more characters available in the FIFO + m_rr[0] &= ~ RR0_RX_CHAR_AVAILABLE; + } + } + + LOG(("Z80DART \"%s\" Channel %c : Data Register Read '%02x'\n", m_owner->tag(), 'A' + m_index, data)); + + return data; +} + + +//------------------------------------------------- +// data_write - write data register +//------------------------------------------------- + +void z80dart_channel::data_write(UINT8 data) +{ + m_tx_data = data; + + if ((m_wr[5] & WR5_TX_ENABLE) && is_transmit_register_empty()) + { + LOG(("Z80DART \"%s\" Channel %c : Transmit Data Byte '%02x'\n", m_owner->tag(), 'A' + m_index, m_tx_data)); + + transmit_register_setup(m_tx_data); + + // empty transmit buffer + m_rr[0] |= RR0_TX_BUFFER_EMPTY; + + if (m_wr[1] & WR1_TX_INT_ENABLE) + m_uart->trigger_interrupt(m_index, INT_TRANSMIT); + } + else + { + m_rr[0] &= ~RR0_TX_BUFFER_EMPTY; + } + + m_rr[1] &= ~RR1_ALL_SENT; + + LOG(("Z80DART \"%s\" Channel %c : Data Register Write '%02x'\n", m_owner->tag(), 'A' + m_index, data)); +} + + +//------------------------------------------------- +// receive_data - receive data word +//------------------------------------------------- + +void z80dart_channel::receive_data(UINT8 data) +{ + LOG(("Z80DART \"%s\" Channel %c : Receive Data Byte '%02x'\n", m_owner->tag(), 'A' + m_index, data)); + + if (m_rx_fifo == 2) + { + // receive overrun error detected + m_rx_error |= RR1_RX_OVERRUN_ERROR; + + switch (m_wr[1] & WR1_RX_INT_MODE_MASK) + { + case WR1_RX_INT_FIRST: + if (!m_rx_first) + { + m_uart->trigger_interrupt(m_index, INT_SPECIAL); + } + break; + + case WR1_RX_INT_ALL_PARITY: + case WR1_RX_INT_ALL: + m_uart->trigger_interrupt(m_index, INT_SPECIAL); + break; + } + } + else + { + m_rx_fifo++; + } + + // store received character and error status into FIFO + m_rx_data_fifo[m_rx_fifo] = data; + m_rx_error_fifo[m_rx_fifo] = m_rx_error; + + m_rr[0] |= RR0_RX_CHAR_AVAILABLE; + + // receive interrupt + switch (m_wr[1] & WR1_RX_INT_MODE_MASK) + { + case WR1_RX_INT_FIRST: + if (m_rx_first) + { + m_uart->trigger_interrupt(m_index, INT_RECEIVE); + + m_rx_first = 0; + } + break; + + case WR1_RX_INT_ALL_PARITY: + case WR1_RX_INT_ALL: + m_uart->trigger_interrupt(m_index, INT_RECEIVE); + break; + } +} + + +//------------------------------------------------- +// cts_w - clear to send handler +//------------------------------------------------- + +WRITE_LINE_MEMBER( z80dart_channel::cts_w ) +{ + LOG(("Z80DART \"%s\" Channel %c : CTS %u\n", m_owner->tag(), 'A' + m_index, state)); + + if (m_cts != state) + { + // enable transmitter if in auto enables mode + if (!state) + if (m_wr[3] & WR3_AUTO_ENABLES) + m_wr[5] |= WR5_TX_ENABLE; + + // set clear to send + m_cts = state; + + if (!m_rx_rr0_latch) + { + if (!m_cts) + m_rr[0] |= RR0_CTS; + else + m_rr[0] &= ~RR0_CTS; + + // trigger interrupt + if (m_wr[1] & WR1_EXT_INT_ENABLE) + { + // trigger interrupt + m_uart->trigger_interrupt(m_index, INT_EXTERNAL); + + // latch read register 0 + m_rx_rr0_latch = 1; + } + } + } +} + + +//------------------------------------------------- +// dcd_w - data carrier detected handler +//------------------------------------------------- + +WRITE_LINE_MEMBER( z80dart_channel::dcd_w ) +{ + LOG(("Z80DART \"%s\" Channel %c : DCD %u\n", m_owner->tag(), 'A' + m_index, state)); + + if (m_dcd != state) + { + // enable receiver if in auto enables mode + if (!state) + if (m_wr[3] & WR3_AUTO_ENABLES) + m_wr[3] |= WR3_RX_ENABLE; + + // set data carrier detect + m_dcd = state; + + if (!m_rx_rr0_latch) + { + if (m_dcd) + m_rr[0] |= RR0_DCD; + else + m_rr[0] &= ~RR0_DCD; + + if (m_wr[1] & WR1_EXT_INT_ENABLE) + { + // trigger interrupt + m_uart->trigger_interrupt(m_index, INT_EXTERNAL); + + // latch read register 0 + m_rx_rr0_latch = 1; + } + } + } +} + + +//------------------------------------------------- +// ri_w - ring indicator handler +//------------------------------------------------- + +WRITE_LINE_MEMBER( z80dart_channel::ri_w ) +{ + LOG(("Z80DART \"%s\" Channel %c : RI %u\n", m_owner->tag(), 'A' + m_index, state)); + + if (m_ri != state) + { + // set ring indicator state + m_ri = state; + + if (!m_rx_rr0_latch) + { + if (m_ri) + m_rr[0] |= RR0_RI; + else + m_rr[0] &= ~RR0_RI; + + if (m_wr[1] & WR1_EXT_INT_ENABLE) + { + // trigger interrupt + m_uart->trigger_interrupt(m_index, INT_EXTERNAL); + + // latch read register 0 + m_rx_rr0_latch = 1; + } + } + } +} + + +//------------------------------------------------- +// sync_w - sync handler +//------------------------------------------------- + +WRITE_LINE_MEMBER( z80dart_channel::sync_w ) +{ + LOG(("Z80DART \"%s\" Channel %c : SYNC %u\n", m_owner->tag(), 'A' + m_index, state)); +} + + +//------------------------------------------------- +// rxc_w - receive clock +//------------------------------------------------- + +WRITE_LINE_MEMBER( z80dart_channel::rxc_w ) +{ + //LOG(("Z80DART \"%s\" Channel %c : Receiver Clock Pulse\n", m_owner->tag(), m_index + 'A')); + int clocks = get_clock_mode(); + if (clocks == 1) + rx_clock_w(state); + else if(state) + { + rx_clock_w(m_rx_clock < clocks/2); + + m_rx_clock++; + if (m_rx_clock == clocks) + m_rx_clock = 0; + + } +} + + +//------------------------------------------------- +// txc_w - transmit clock +//------------------------------------------------- + +WRITE_LINE_MEMBER( z80dart_channel::txc_w ) +{ + //LOG(("Z80DART \"%s\" Channel %c : Transmitter Clock Pulse\n", m_owner->tag(), m_index + 'A')); + int clocks = get_clock_mode(); + if (clocks == 1) + tx_clock_w(state); + else if(state) + { + tx_clock_w(m_tx_clock < clocks/2); + + m_tx_clock++; + if (m_tx_clock == clocks) + m_tx_clock = 0; + + } +} + + +//------------------------------------------------- +// update_serial - +//------------------------------------------------- + +void z80dart_channel::update_serial() +{ + int data_bit_count = get_rx_word_length(); + stop_bits_t stop_bits = get_stop_bits(); + + parity_t parity; + if (m_wr[4] & WR4_PARITY_ENABLE) + { + if (m_wr[4] & WR4_PARITY_EVEN) + parity = PARITY_EVEN; + else + parity = PARITY_ODD; + } + else + parity = PARITY_NONE; + + set_data_frame(1, data_bit_count, parity, stop_bits); + + int clocks = get_clock_mode(); + + if (m_rxc > 0) + { + set_rcv_rate(m_rxc / clocks); + } + + if (m_txc > 0) + { + set_tra_rate(m_txc / clocks); + } + receive_register_reset(); // if stop bits is changed from 0, receive register has to be reset +} + + +//------------------------------------------------- +// set_dtr - +//------------------------------------------------- + +void z80dart_channel::set_dtr(int state) +{ + m_dtr = state; + + if (m_index == z80dart_device::CHANNEL_A) + m_uart->m_out_dtra_cb(m_dtr); + else + m_uart->m_out_dtrb_cb(m_dtr); +} + + +//------------------------------------------------- +// set_rts - +//------------------------------------------------- + +void z80dart_channel::set_rts(int state) +{ + if (m_index == z80dart_device::CHANNEL_A) + m_uart->m_out_rtsa_cb(state); + else + m_uart->m_out_rtsb_cb(state); +} + + +//------------------------------------------------- +// write_rx - +//------------------------------------------------- + +WRITE_LINE_MEMBER(z80dart_channel::write_rx) +{ + m_rxd = state; + //only use rx_w when self-clocked + if(m_rxc) + device_serial_interface::rx_w(state); +} diff --git a/src/devices/machine/z80dart.h b/src/devices/machine/z80dart.h new file mode 100644 index 00000000000..2674f84758a --- /dev/null +++ b/src/devices/machine/z80dart.h @@ -0,0 +1,684 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/*************************************************************************** + + Intel 8274 Multi-Protocol Serial Controller emulation + NEC uPD7201 Multiprotocol Serial Communications Controller emulation + Z80-DART Dual Asynchronous Receiver/Transmitter emulation + Z80-SIO/0/1/2/3/4 Serial Input/Output Controller emulation + +**************************************************************************** + _____ _____ + CLK 1 |* \_/ | 40 Vcc + _RESET 2 | | 39 _CTSA + _CDA 3 | | 38 _RTSA + _RxCB 4 | | 37 TxDA + _CDB 5 | | 36 _TxCA + _CTSB 6 | | 35 _RxCA + _TxCB 7 | | 34 RxDA + TxDB 8 | | 33 _SYNDETA + RxDB 9 | | 32 RDYA/RxDRQA + _RTSB/_SYNDETB 10 | I8274 | 31 _DTRA + RDYB/_TxDRQA 11 | | 30 _IPO/TxDRQB + D7 12 | | 29 _IPI/RxDRQB + D6 13 | | 28 _INT + D5 14 | | 27 _INTA + D4 15 | | 26 _DTRB + D3 16 | | 25 A0 + D2 17 | | 24 A1 + D1 18 | | 23 _CS + D0 19 | | 22 _RD + Vss 20 |_____________| 21 _WR + + _____ _____ + CLK 1 |* \_/ | 40 Vcc + _RESET 2 | | 39 _CTSA + _DCDA 3 | | 38 _RTSA + _RxCB 4 | | 37 TxDA + _DCDB 5 | | 36 _TxCA + _CTSB 6 | | 35 _RxCA + _TxCB 7 | | 34 RxDA + TxDB 8 | | 33 _SYNCA + RxDB 9 | | 32 _WAITA/DRQRxA + _RTSB/_SYNCB 10 | UPD7201 | 31 _DTRA/_HAO + _WAITB/_DRQTxA 11 | | 30 _PRO/DRQTxB + D7 12 | | 29 _PRI/DRQRxB + D6 13 | | 28 _INT + D5 14 | | 27 _INTAK + D4 15 | | 26 _DTRB/_HAI + D3 16 | | 25 B/_A + D2 17 | | 24 C/_D + D1 18 | | 23 _CS + D0 19 | | 22 _RD + Vss 20 |_____________| 21 _WR + + _____ _____ + D1 1 |* \_/ | 40 D0 + D3 2 | | 39 D2 + D5 3 | | 38 D4 + D7 4 | | 37 D6 + _INT 5 | | 36 _IORQ + IEI 6 | | 35 _CE + IEO 7 | | 34 B/_A + _M1 8 | | 33 C/_D + Vdd 9 | | 32 _RD + _W/RDYA 10 | Z80-DART | 31 GND + _RIA 11 | Z8470 | 30 _W/RDYB + RxDA 12 | | 29 _RIB + _RxCA 13 | | 28 RxDB + _TxCA 14 | | 27 _RxTxCB + TxDA 15 | | 26 TxDB + _DTRA 16 | | 25 _DTRB + _RTSA 17 | | 24 _RTSB + _CTSA 18 | | 23 _CTSB + _DCDA 19 | | 22 _DCDB + CLK 20 |_____________| 21 _RESET + + _____ _____ + D1 1 |* \_/ | 40 D0 + D3 2 | | 39 D2 + D5 3 | | 38 D4 + D7 4 | | 37 D6 + _INT 5 | | 36 _IORQ + IEI 6 | | 35 _CE + IEO 7 | | 34 B/_A + _M1 8 | | 33 C/_D + Vdd 9 | | 32 _RD + _W/RDYA 10 | Z80-SIO/0 | 31 GND + _SYNCA 11 | Z8440 | 30 _W/RDYB + RxDA 12 | | 29 _SYNCB + _RxCA 13 | | 28 RxDB + _TxCA 14 | | 27 _RxTxCB + TxDA 15 | | 26 TxDB + _DTRA 16 | | 25 _DTRB + _RTSA 17 | | 24 _RTSB + _CTSA 18 | | 23 _CTSB + _DCDA 19 | | 22 _DCDB + CLK 20 |_____________| 21 _RESET + + _____ _____ + D1 1 |* \_/ | 40 D0 + D3 2 | | 39 D2 + D5 3 | | 38 D4 + D7 4 | | 37 D6 + _INT 5 | | 36 _IORQ + IEI 6 | | 35 _CE + IEO 7 | | 34 B/_A + _M1 8 | | 33 C/_D + Vdd 9 | | 32 _RD + _W/RDYA 10 | Z80-SIO/1 | 31 GND + _SYNCA 11 | Z8441 | 30 _W/RDYB + RxDA 12 | | 29 _SYNCB + _RxCA 13 | | 28 RxDB + _TxCA 14 | | 27 _RxCB + TxDA 15 | | 26 _TxCB + _DTRA 16 | | 25 TxDB + _RTSA 17 | | 24 _RTSB + _CTSA 18 | | 23 _CTSB + _DCDA 19 | | 22 _DCDB + CLK 20 |_____________| 21 _RESET + + _____ _____ + D1 1 |* \_/ | 40 D0 + D3 2 | | 39 D2 + D5 3 | | 38 D4 + D7 4 | | 37 D6 + _INT 5 | | 36 _IORQ + IEI 6 | | 35 _CE + IEO 7 | | 34 B/_A + _M1 8 | | 33 C/_D + Vdd 9 | | 32 _RD + _W/RDYA 10 | Z80-SIO/2 | 31 GND + _SYNCA 11 | Z8442 | 30 _W/RDYB + RxDA 12 | | 29 _RxDB + _RxCA 13 | | 28 _RxCB + _TxCA 14 | | 27 _TxCB + TxDA 15 | | 26 TxDB + _DTRA 16 | | 25 _DTRB + _RTSA 17 | | 24 _RTSB + _CTSA 18 | | 23 _CTSB + _DCDA 19 | | 22 _DCDB + CLK 20 |_____________| 21 _RESET + +***************************************************************************/ + +#ifndef __Z80DART_H__ +#define __Z80DART_H__ + +#include "emu.h" +#include "cpu/z80/z80daisy.h" + + +//************************************************************************** +// DEVICE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_Z80DART_ADD(_tag, _clock, _rxa, _txa, _rxb, _txb) \ + MCFG_DEVICE_ADD(_tag, Z80DART, _clock) \ + MCFG_Z80DART_OFFSETS(_rxa, _txa, _rxb, _txb) + +#define MCFG_Z80SIO0_ADD(_tag, _clock, _rxa, _txa, _rxb, _txb) \ + MCFG_DEVICE_ADD(_tag, Z80SIO0, _clock) \ + MCFG_Z80DART_OFFSETS(_rxa, _txa, _rxb, _txb) + +#define MCFG_Z80SIO1_ADD(_tag, _clock, _rxa, _txa, _rxb, _txb) \ + MCFG_DEVICE_ADD(_tag, Z80SIO1, _clock) \ + MCFG_Z80DART_OFFSETS(_rxa, _txa, _rxb, _txb) + +#define MCFG_Z80SIO2_ADD(_tag, _clock, _rxa, _txa, _rxb, _txb) \ + MCFG_DEVICE_ADD(_tag, Z80SIO2, _clock) \ + MCFG_Z80DART_OFFSETS(_rxa, _txa, _rxb, _txb) + +#define MCFG_Z80SIO3_ADD(_tag, _clock, _rxa, _txa, _rxb, _txb) \ + MCFG_DEVICE_ADD(_tag, Z80SIO3, _clock) \ + MCFG_Z80DART_OFFSETS(_rxa, _txa, _rxb, _txb) + +#define MCFG_Z80SIO4_ADD(_tag, _clock, _rxa, _txa, _rxb, _txb) \ + MCFG_DEVICE_ADD(_tag, Z80SIO4, _clock) \ + MCFG_Z80DART_OFFSETS(_rxa, _txa, _rxb, _txb) + +#define MCFG_I8274_ADD(_tag, _clock, _rxa, _txa, _rxb, _txb) \ + MCFG_DEVICE_ADD(_tag, I8274, _clock) \ + MCFG_Z80DART_OFFSETS(_rxa, _txa, _rxb, _txb) + +#define MCFG_UPD7201_ADD(_tag, _clock, _rxa, _txa, _rxb, _txb) \ + MCFG_DEVICE_ADD(_tag, UPD7201, _clock) \ + MCFG_Z80DART_OFFSETS(_rxa, _txa, _rxb, _txb) + + +#define MCFG_Z80DART_OFFSETS(_rxa, _txa, _rxb, _txb) \ + z80dart_device::configure_channels(*device, _rxa, _txa, _rxb, _txb); + +#define MCFG_Z80DART_OUT_TXDA_CB(_devcb) \ + devcb = &z80dart_device::set_out_txda_callback(*device, DEVCB_##_devcb); + +#define MCFG_Z80DART_OUT_DTRA_CB(_devcb) \ + devcb = &z80dart_device::set_out_dtra_callback(*device, DEVCB_##_devcb); + +#define MCFG_Z80DART_OUT_RTSA_CB(_devcb) \ + devcb = &z80dart_device::set_out_rtsa_callback(*device, DEVCB_##_devcb); + +#define MCFG_Z80DART_OUT_WRDYA_CB(_devcb) \ + devcb = &z80dart_device::set_out_wrdya_callback(*device, DEVCB_##_devcb); + +#define MCFG_Z80DART_OUT_SYNCA_CB(_devcb) \ + devcb = &z80dart_device::set_out_synca_callback(*device, DEVCB_##_devcb); + +#define MCFG_Z80DART_OUT_TXDB_CB(_devcb) \ + devcb = &z80dart_device::set_out_txdb_callback(*device, DEVCB_##_devcb); + +#define MCFG_Z80DART_OUT_DTRB_CB(_devcb) \ + devcb = &z80dart_device::set_out_dtrb_callback(*device, DEVCB_##_devcb); + +#define MCFG_Z80DART_OUT_RTSB_CB(_devcb) \ + devcb = &z80dart_device::set_out_rtsb_callback(*device, DEVCB_##_devcb); + +#define MCFG_Z80DART_OUT_WRDYB_CB(_devcb) \ + devcb = &z80dart_device::set_out_wrdyb_callback(*device, DEVCB_##_devcb); + +#define MCFG_Z80DART_OUT_SYNCB_CB(_devcb) \ + devcb = &z80dart_device::set_out_syncb_callback(*device, DEVCB_##_devcb); + +#define MCFG_Z80DART_OUT_INT_CB(_devcb) \ + devcb = &z80dart_device::set_out_int_callback(*device, DEVCB_##_devcb); + +#define MCFG_Z80DART_OUT_RXDRQA_CB(_devcb) \ + devcb = &z80dart_device::set_out_rxdrqa_callback(*device, DEVCB_##_devcb); + +#define MCFG_Z80DART_OUT_TXDRQA_CB(_devcb) \ + devcb = &z80dart_device::set_out_txdrqa_callback(*device, DEVCB_##_devcb); + +#define MCFG_Z80DART_OUT_RXDRQB_CB(_devcb) \ + devcb = &z80dart_device::set_out_rxdrqb_callback(*device, DEVCB_##_devcb); + +#define MCFG_Z80DART_OUT_TXDRQB_CB(_devcb) \ + devcb = &z80dart_device::set_out_txdrqb_callback(*device, DEVCB_##_devcb); + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> z80dart_channel + +class z80dart_device; + +class z80dart_channel : public device_t, + public device_serial_interface +{ + friend class z80dart_device; + +public: + z80dart_channel(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + // device_serial_interface overrides + virtual void tra_callback(); + virtual void tra_complete(); + virtual void rcv_callback(); + virtual void rcv_complete(); + + UINT8 control_read(); + void control_write(UINT8 data); + + UINT8 data_read(); + void data_write(UINT8 data); + + void receive_data(UINT8 data); + + DECLARE_WRITE_LINE_MEMBER( write_rx ); + DECLARE_WRITE_LINE_MEMBER( cts_w ); + DECLARE_WRITE_LINE_MEMBER( dcd_w ); + DECLARE_WRITE_LINE_MEMBER( ri_w ); + DECLARE_WRITE_LINE_MEMBER( rxc_w ); + DECLARE_WRITE_LINE_MEMBER( txc_w ); + DECLARE_WRITE_LINE_MEMBER( sync_w ); + + int m_rxc; + int m_txc; + + // register state + UINT8 m_rr[3]; // read register + UINT8 m_wr[6]; // write register + +protected: + enum + { + INT_TRANSMIT = 0, + INT_EXTERNAL, + INT_RECEIVE, + INT_SPECIAL + }; + + enum + { + RR0_RX_CHAR_AVAILABLE = 0x01, + RR0_INTERRUPT_PENDING = 0x02, + RR0_TX_BUFFER_EMPTY = 0x04, + RR0_DCD = 0x08, + RR0_RI = 0x10, + RR0_SYNC_HUNT = 0x10, // not supported + RR0_CTS = 0x20, + RR0_TX_UNDERRUN = 0x40, // not supported + RR0_BREAK_ABORT = 0x80 // not supported + }; + + enum + { + RR1_ALL_SENT = 0x01, + RR1_RESIDUE_CODE_MASK = 0x0e, // not supported + RR1_PARITY_ERROR = 0x10, + RR1_RX_OVERRUN_ERROR = 0x20, + RR1_CRC_FRAMING_ERROR = 0x40, + RR1_END_OF_FRAME = 0x80 // not supported + }; + + enum + { + WR0_REGISTER_MASK = 0x07, + WR0_COMMAND_MASK = 0x38, + WR0_NULL = 0x00, + WR0_SEND_ABORT = 0x08, // not supported + WR0_RESET_EXT_STATUS = 0x10, + WR0_CHANNEL_RESET = 0x18, + WR0_ENABLE_INT_NEXT_RX = 0x20, + WR0_RESET_TX_INT = 0x28, // not supported + WR0_ERROR_RESET = 0x30, + WR0_RETURN_FROM_INT = 0x38, // not supported + WR0_CRC_RESET_CODE_MASK = 0xc0, // not supported + WR0_CRC_RESET_NULL = 0x00, // not supported + WR0_CRC_RESET_RX = 0x40, // not supported + WR0_CRC_RESET_TX = 0x80, // not supported + WR0_CRC_RESET_TX_UNDERRUN = 0xc0 // not supported + }; + + enum + { + WR1_EXT_INT_ENABLE = 0x01, + WR1_TX_INT_ENABLE = 0x02, + WR1_STATUS_VECTOR = 0x04, + WR1_RX_INT_MODE_MASK = 0x18, + WR1_RX_INT_DISABLE = 0x00, + WR1_RX_INT_FIRST = 0x08, + WR1_RX_INT_ALL_PARITY = 0x10, // not supported + WR1_RX_INT_ALL = 0x18, + WR1_WRDY_ON_RX_TX = 0x20, // not supported + WR1_WRDY_FUNCTION = 0x40, // not supported + WR1_WRDY_ENABLE = 0x80 // not supported + }; + + enum + { + WR2_DATA_XFER_INT = 0x00, // not supported + WR2_DATA_XFER_DMA_INT = 0x01, // not supported + WR2_DATA_XFER_DMA = 0x02, // not supported + WR2_DATA_XFER_ILLEGAL = 0x03, // not supported + WR2_DATA_XFER_MASK = 0x03, // not supported + WR2_PRIORITY = 0x04, // not supported + WR2_MODE_8085_1 = 0x00, // not supported + WR2_MODE_8085_2 = 0x08, // not supported + WR2_MODE_8086_8088 = 0x10, // not supported + WR2_MODE_ILLEGAL = 0x18, // not supported + WR2_MODE_MASK = 0x18, // not supported + WR2_VECTORED_INT = 0x20, // not supported + WR2_PIN10_SYNDETB_RTSB = 0x80 // not supported + }; + + enum + { + WR3_RX_ENABLE = 0x01, + WR3_SYNC_CHAR_LOAD_INHIBIT= 0x02, // not supported + WR3_ADDRESS_SEARCH_MODE = 0x04, // not supported + WR3_RX_CRC_ENABLE = 0x08, // not supported + WR3_ENTER_HUNT_PHASE = 0x10, // not supported + WR3_AUTO_ENABLES = 0x20, + WR3_RX_WORD_LENGTH_MASK = 0xc0, + WR3_RX_WORD_LENGTH_5 = 0x00, + WR3_RX_WORD_LENGTH_7 = 0x40, + WR3_RX_WORD_LENGTH_6 = 0x80, + WR3_RX_WORD_LENGTH_8 = 0xc0 + }; + + enum + { + WR4_PARITY_ENABLE = 0x01, + WR4_PARITY_EVEN = 0x02, + WR4_STOP_BITS_MASK = 0x0c, + WR4_STOP_BITS_1 = 0x04, + WR4_STOP_BITS_1_5 = 0x08, // not supported + WR4_STOP_BITS_2 = 0x0c, + WR4_SYNC_MODE_MASK = 0x30, // not supported + WR4_SYNC_MODE_8_BIT = 0x00, // not supported + WR4_SYNC_MODE_16_BIT = 0x10, // not supported + WR4_SYNC_MODE_SDLC = 0x20, // not supported + WR4_SYNC_MODE_EXT = 0x30, // not supported + WR4_CLOCK_RATE_MASK = 0xc0, + WR4_CLOCK_RATE_X1 = 0x00, + WR4_CLOCK_RATE_X16 = 0x40, + WR4_CLOCK_RATE_X32 = 0x80, + WR4_CLOCK_RATE_X64 = 0xc0 + }; + + enum + { + WR5_TX_CRC_ENABLE = 0x01, // not supported + WR5_RTS = 0x02, + WR5_CRC16 = 0x04, // not supported + WR5_TX_ENABLE = 0x08, + WR5_SEND_BREAK = 0x10, + WR5_TX_WORD_LENGTH_MASK = 0x60, + WR5_TX_WORD_LENGTH_5 = 0x00, + WR5_TX_WORD_LENGTH_6 = 0x40, + WR5_TX_WORD_LENGTH_7 = 0x20, + WR5_TX_WORD_LENGTH_8 = 0x60, + WR5_DTR = 0x80 + }; + + void update_serial(); + void set_dtr(int state); + void set_rts(int state); + + int get_clock_mode(); + stop_bits_t get_stop_bits(); + int get_rx_word_length(); + int get_tx_word_length(); + + // receiver state + UINT8 m_rx_data_fifo[3]; // receive data FIFO + UINT8 m_rx_error_fifo[3]; // receive error FIFO + UINT8 m_rx_error; // current receive error + int m_rx_fifo; // receive FIFO pointer + + int m_rx_clock; // receive clock pulse count + int m_rx_first; // first character received + int m_rx_break; // receive break condition + UINT8 m_rx_rr0_latch; // read register 0 latched + + int m_rxd; + int m_ri; // ring indicator latch + int m_cts; // clear to send latch + int m_dcd; // data carrier detect latch + + // transmitter state + UINT8 m_tx_data; // transmit data register + int m_tx_clock; // transmit clock pulse count + + int m_dtr; // data terminal ready + int m_rts; // request to send + + // synchronous state + UINT16 m_sync; // sync character + + int m_index; + z80dart_device *m_uart; +}; + + +// ======================> z80dart_device + +class z80dart_device : public device_t, + public device_z80daisy_interface +{ + friend class z80dart_channel; + +public: + // construction/destruction + z80dart_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, UINT32 variant, const char *shortname, const char *source); + z80dart_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + template static devcb_base &set_out_txda_callback(device_t &device, _Object object) { return downcast(device).m_out_txda_cb.set_callback(object); } + template static devcb_base &set_out_dtra_callback(device_t &device, _Object object) { return downcast(device).m_out_dtra_cb.set_callback(object); } + template static devcb_base &set_out_rtsa_callback(device_t &device, _Object object) { return downcast(device).m_out_rtsa_cb.set_callback(object); } + template static devcb_base &set_out_wrdya_callback(device_t &device, _Object object) { return downcast(device).m_out_wrdya_cb.set_callback(object); } + template static devcb_base &set_out_synca_callback(device_t &device, _Object object) { return downcast(device).m_out_synca_cb.set_callback(object); } + template static devcb_base &set_out_txdb_callback(device_t &device, _Object object) { return downcast(device).m_out_txdb_cb.set_callback(object); } + template static devcb_base &set_out_dtrb_callback(device_t &device, _Object object) { return downcast(device).m_out_dtrb_cb.set_callback(object); } + template static devcb_base &set_out_rtsb_callback(device_t &device, _Object object) { return downcast(device).m_out_rtsb_cb.set_callback(object); } + template static devcb_base &set_out_wrdyb_callback(device_t &device, _Object object) { return downcast(device).m_out_wrdyb_cb.set_callback(object); } + template static devcb_base &set_out_syncb_callback(device_t &device, _Object object) { return downcast(device).m_out_syncb_cb.set_callback(object); } + template static devcb_base &set_out_int_callback(device_t &device, _Object object) { return downcast(device).m_out_int_cb.set_callback(object); } + template static devcb_base &set_out_rxdrqa_callback(device_t &device, _Object object) { return downcast(device).m_out_rxdrqa_cb.set_callback(object); } + template static devcb_base &set_out_txdrqa_callback(device_t &device, _Object object) { return downcast(device).m_out_txdrqa_cb.set_callback(object); } + template static devcb_base &set_out_rxdrqb_callback(device_t &device, _Object object) { return downcast(device).m_out_rxdrqb_cb.set_callback(object); } + template static devcb_base &set_out_txdrqb_callback(device_t &device, _Object object) { return downcast(device).m_out_txdrqb_cb.set_callback(object); } + + static void configure_channels(device_t &device, int rxa, int txa, int rxb, int txb) + { + z80dart_device &dev = downcast(device); + dev.m_rxca = rxa; + dev.m_txca = txa; + dev.m_rxcb = rxb; + dev.m_txcb = txb; + } + + DECLARE_READ8_MEMBER( cd_ba_r ); + DECLARE_WRITE8_MEMBER( cd_ba_w ); + DECLARE_READ8_MEMBER( ba_cd_r ); + DECLARE_WRITE8_MEMBER( ba_cd_w ); + + DECLARE_READ8_MEMBER( da_r ) { return m_chanA->data_read(); } + DECLARE_WRITE8_MEMBER( da_w ) { m_chanA->data_write(data); } + DECLARE_READ8_MEMBER( db_r ) { return m_chanB->data_read(); } + DECLARE_WRITE8_MEMBER( db_w ) { m_chanB->data_write(data); } + + DECLARE_READ8_MEMBER( ca_r ) { return m_chanA->control_read(); } + DECLARE_WRITE8_MEMBER( ca_w ) { m_chanA->control_write(data); } + DECLARE_READ8_MEMBER( cb_r ) { return m_chanB->control_read(); } + DECLARE_WRITE8_MEMBER( cb_w ) { m_chanB->control_write(data); } + + // interrupt acknowledge + int m1_r(); + + DECLARE_WRITE_LINE_MEMBER( rxa_w ) { m_chanA->write_rx(state); } + DECLARE_WRITE_LINE_MEMBER( rxb_w ) { m_chanB->write_rx(state); } + DECLARE_WRITE_LINE_MEMBER( ctsa_w ) { m_chanA->cts_w(state); } + DECLARE_WRITE_LINE_MEMBER( ctsb_w ) { m_chanB->cts_w(state); } + DECLARE_WRITE_LINE_MEMBER( dcda_w ) { m_chanA->dcd_w(state); } + DECLARE_WRITE_LINE_MEMBER( dcdb_w ) { m_chanB->dcd_w(state); } + DECLARE_WRITE_LINE_MEMBER( ria_w ) { m_chanA->ri_w(state); } + DECLARE_WRITE_LINE_MEMBER( rib_w ) { m_chanB->ri_w(state); } + DECLARE_WRITE_LINE_MEMBER( rxca_w ) { m_chanA->rxc_w(state); } + DECLARE_WRITE_LINE_MEMBER( rxcb_w ) { m_chanB->rxc_w(state); } + DECLARE_WRITE_LINE_MEMBER( txca_w ) { m_chanA->txc_w(state); } + DECLARE_WRITE_LINE_MEMBER( txcb_w ) { m_chanB->txc_w(state); } + DECLARE_WRITE_LINE_MEMBER( rxtxcb_w ) { m_chanB->rxc_w(state); m_chanB->txc_w(state); } + DECLARE_WRITE_LINE_MEMBER( synca_w ) { m_chanA->sync_w(state); } + DECLARE_WRITE_LINE_MEMBER( syncb_w ) { m_chanB->sync_w(state); } + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual machine_config_constructor device_mconfig_additions() const; + + // device_z80daisy_interface overrides + virtual int z80daisy_irq_state(); + virtual int z80daisy_irq_ack(); + virtual void z80daisy_irq_reti(); + + // internal interrupt management + void check_interrupts(); + void reset_interrupts(); + void trigger_interrupt(int index, int state); + int get_channel_index(z80dart_channel *ch) { return (ch == m_chanA) ? 0 : 1; } + + enum + { + TYPE_DART, + TYPE_SIO0, + TYPE_SIO1, + TYPE_SIO2, + TYPE_SIO3, + TYPE_SIO4, + TYPE_I8274, + TYPE_UPD7201 + }; + + enum + { + CHANNEL_A = 0, + CHANNEL_B + }; + + required_device m_chanA; + required_device m_chanB; + + // internal state + int m_rxca; + int m_txca; + int m_rxcb; + int m_txcb; + + devcb_write_line m_out_txda_cb; + devcb_write_line m_out_dtra_cb; + devcb_write_line m_out_rtsa_cb; + devcb_write_line m_out_wrdya_cb; + devcb_write_line m_out_synca_cb; + + devcb_write_line m_out_txdb_cb; + devcb_write_line m_out_dtrb_cb; + devcb_write_line m_out_rtsb_cb; + devcb_write_line m_out_wrdyb_cb; + devcb_write_line m_out_syncb_cb; + + devcb_write_line m_out_int_cb; + devcb_write_line m_out_rxdrqa_cb; + devcb_write_line m_out_txdrqa_cb; + devcb_write_line m_out_rxdrqb_cb; + devcb_write_line m_out_txdrqb_cb; + + int m_int_state[8]; // interrupt state + + int m_variant; +}; + + +// ======================> z80sio0_device + +class z80sio0_device : public z80dart_device +{ +public: + // construction/destruction + z80sio0_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +// ======================> z80sio1_device + +class z80sio1_device : public z80dart_device +{ +public: + // construction/destruction + z80sio1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +// ======================> z80sio2_device + +class z80sio2_device : public z80dart_device +{ +public: + // construction/destruction + z80sio2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +// ======================> z80sio3_device + +class z80sio3_device : public z80dart_device +{ +public: + // construction/destruction + z80sio3_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +// ======================> z80sio4_device + +class z80sio4_device : public z80dart_device +{ +public: + // construction/destruction + z80sio4_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +// ======================> i8274_device + +class i8274_device : public z80dart_device +{ +public: + // construction/destruction + i8274_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + DECLARE_READ8_MEMBER( inta_r ) { return m1_r(); }; +}; + + +// ======================> upd7201_device + +class upd7201_device : public z80dart_device +{ +public: + // construction/destruction + upd7201_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +// device type definition +extern const device_type Z80DART_CHANNEL; +extern const device_type Z80DART; +extern const device_type Z80SIO0; +extern const device_type Z80SIO1; +extern const device_type Z80SIO2; +extern const device_type Z80SIO3; +extern const device_type Z80SIO4; +extern const device_type I8274; +extern const device_type UPD7201; + + +#endif diff --git a/src/devices/machine/z80dma.c b/src/devices/machine/z80dma.c new file mode 100644 index 00000000000..745d22877f0 --- /dev/null +++ b/src/devices/machine/z80dma.c @@ -0,0 +1,881 @@ +// license:BSD-3-Clause +// copyright-holders:Couriersud +/********************************************************************** + + Z80 DMA interface and emulation + + For datasheet http://www.zilog.com/docs/z80/ps0179.pdf + + 2008/01 couriersud + + - architecture copied from 8257 DMA + - significant changes to implementation + - This is only a minimum implementation to support dkong3 and mario drivers + - Only memory to memory is tested! + + TODO: + - reset command (C3) is handled improperly + - rewrite to match documentation + - implement missing features + - implement more asserts + - implement a INPUT_LINE_BUSREQ for Z80. As a workaround, + HALT is used. This implies burst mode. + +**********************************************************************/ + +#include "emu.h" +#include "z80dma.h" +#include "cpu/z80/z80daisy.h" + + +//************************************************************************** +// CONSTANTS +//************************************************************************** + +enum +{ + INT_RDY = 0, + INT_MATCH, + INT_END_OF_BLOCK, + INT_MATCH_END_OF_BLOCK +}; + +const int COMMAND_RESET = 0xc3; +const int COMMAND_RESET_PORT_A_TIMING = 0xc7; +const int COMMAND_RESET_PORT_B_TIMING = 0xcb; +const int COMMAND_LOAD = 0xcf; +const int COMMAND_CONTINUE = 0xd3; +const int COMMAND_DISABLE_INTERRUPTS = 0xaf; +const int COMMAND_ENABLE_INTERRUPTS = 0xab; +const int COMMAND_RESET_AND_DISABLE_INTERRUPTS = 0xa3; +const int COMMAND_ENABLE_AFTER_RETI = 0xb7; +const int COMMAND_READ_STATUS_BYTE = 0xbf; +const int COMMAND_REINITIALIZE_STATUS_BYTE = 0x8b; +const int COMMAND_INITIATE_READ_SEQUENCE = 0xa7; +const int COMMAND_FORCE_READY = 0xb3; +const int COMMAND_ENABLE_DMA = 0x87; +const int COMMAND_DISABLE_DMA = 0x83; +const int COMMAND_READ_MASK_FOLLOWS = 0xbb; + +const int TM_TRANSFER = 0x01; +const int TM_SEARCH = 0x02; +const int TM_SEARCH_TRANSFER = 0x03; + + + +//************************************************************************** +// MACROS +//************************************************************************** + +#define LOG 0 +#define DMA_LOG 0 + +#define REGNUM(_m, _s) (((_m)<<3) + (_s)) +#define GET_REGNUM(_r) (&(_r) - &(WR0)) +#define REG(_m, _s) m_regs[REGNUM(_m,_s)] +#define WR0 REG(0, 0) +#define WR1 REG(1, 0) +#define WR2 REG(2, 0) +#define WR3 REG(3, 0) +#define WR4 REG(4, 0) +#define WR5 REG(5, 0) +#define WR6 REG(6, 0) + +#define PORTA_ADDRESS_L REG(0,1) +#define PORTA_ADDRESS_H REG(0,2) + +#define BLOCKLEN_L REG(0,3) +#define BLOCKLEN_H REG(0,4) + +#define PORTA_TIMING REG(1,1) +#define PORTB_TIMING REG(2,1) + +#define MASK_BYTE REG(3,1) +#define MATCH_BYTE REG(3,2) + +#define PORTB_ADDRESS_L REG(4,1) +#define PORTB_ADDRESS_H REG(4,2) +#define INTERRUPT_CTRL REG(4,3) +#define INTERRUPT_VECTOR REG(4,4) +#define PULSE_CTRL REG(4,5) + +#define READ_MASK REG(6,1) + +#define PORTA_ADDRESS ((PORTA_ADDRESS_H<<8) | PORTA_ADDRESS_L) +#define PORTB_ADDRESS ((PORTB_ADDRESS_H<<8) | PORTB_ADDRESS_L) +#define BLOCKLEN ((BLOCKLEN_H<<8) | BLOCKLEN_L) + +#define PORTA_INC (WR1 & 0x10) +#define PORTB_INC (WR2 & 0x10) +#define PORTA_FIXED (((WR1 >> 4) & 0x02) == 0x02) +#define PORTB_FIXED (((WR2 >> 4) & 0x02) == 0x02) +#define PORTA_MEMORY (((WR1 >> 3) & 0x01) == 0x00) +#define PORTB_MEMORY (((WR2 >> 3) & 0x01) == 0x00) + +#define PORTA_CYCLE_LEN (4-(PORTA_TIMING & 0x03)) +#define PORTB_CYCLE_LEN (4-(PORTB_TIMING & 0x03)) + +#define PORTA_IS_SOURCE ((WR0 >> 2) & 0x01) +#define PORTB_IS_SOURCE (!PORTA_IS_SOURCE) +#define TRANSFER_MODE (WR0 & 0x03) + +#define MATCH_F_SET (m_status &= ~0x10) +#define MATCH_F_CLEAR (m_status |= 0x10) +#define EOB_F_SET (m_status &= ~0x20) +#define EOB_F_CLEAR (m_status |= 0x20) + +#define READY_ACTIVE_HIGH ((WR5>>3) & 0x01) +#define AUTO_RESTART ((WR5>>5) & 0x01) + +#define INTERRUPT_ENABLE (WR3 & 0x20) +#define INT_ON_MATCH (INTERRUPT_CTRL & 0x01) +#define INT_ON_END_OF_BLOCK (INTERRUPT_CTRL & 0x02) +#define INT_ON_READY (INTERRUPT_CTRL & 0x40) +#define STATUS_AFFECTS_VECTOR (INTERRUPT_CTRL & 0x20) + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +// device type definition +const device_type Z80DMA = &device_creator; + +//------------------------------------------------- +// z80dma_device - constructor +//------------------------------------------------- + +z80dma_device::z80dma_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, Z80DMA, "Z80 DMA", tag, owner, clock, "z80dma", __FILE__), + device_z80daisy_interface(mconfig, *this), + m_out_busreq_cb(*this), + m_out_int_cb(*this), + m_out_bao_cb(*this), + m_in_mreq_cb(*this), + m_out_mreq_cb(*this), + m_in_iorq_cb(*this), + m_out_iorq_cb(*this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void z80dma_device::device_start() +{ + // resolve callbacks + m_out_busreq_cb.resolve_safe(); + m_out_int_cb.resolve_safe(); + m_out_bao_cb.resolve_safe(); + m_in_mreq_cb.resolve_safe(0); + m_out_mreq_cb.resolve_safe(); + m_in_iorq_cb.resolve_safe(0); + m_out_iorq_cb.resolve_safe(); + + // allocate timer + m_timer = machine().scheduler().timer_alloc(FUNC(static_timerproc), (void *)this); + + // register for state saving + save_item(NAME(m_regs)); + save_item(NAME(m_regs_follow)); + save_item(NAME(m_num_follow)); + save_item(NAME(m_cur_follow)); + save_item(NAME(m_status)); + save_item(NAME(m_dma_enabled)); + save_item(NAME(m_vector)); + save_item(NAME(m_ip)); + save_item(NAME(m_ius)); + save_item(NAME(m_addressA)); + save_item(NAME(m_addressB)); + save_item(NAME(m_count)); + save_item(NAME(m_rdy)); + save_item(NAME(m_force_ready)); + save_item(NAME(m_is_read)); + save_item(NAME(m_cur_cycle)); + save_item(NAME(m_latch)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void z80dma_device::device_reset() +{ + m_status = 0; + m_rdy = 0; + m_force_ready = 0; + m_num_follow = 0; + m_dma_enabled = 0; + m_read_num_follow = m_read_cur_follow = 0; + m_reset_pointer = 0; + m_is_read = false; + memset(m_regs, 0, sizeof(m_regs)); + memset(m_regs_follow, 0, sizeof(m_regs_follow)); + + // disable interrupts + WR3 &= ~0x20; + m_ip = 0; + m_ius = 0; + m_vector = 0; + + update_status(); +} + + + +//************************************************************************** +// DAISY CHAIN INTERFACE +//************************************************************************** + +//------------------------------------------------- +// z80daisy_irq_state - return the overall IRQ +// state for this device +//------------------------------------------------- + +int z80dma_device::z80daisy_irq_state() +{ + int state = 0; + + if (m_ip) + { + // interrupt pending + state = Z80_DAISY_INT; + } + else if (m_ius) + { + // interrupt under service + state = Z80_DAISY_IEO; + } + + if (LOG) logerror("Z80DMA '%s' Interrupt State: %u\n", tag(), state); + + return state; +} + + +//------------------------------------------------- +// z80daisy_irq_ack - acknowledge an IRQ and +// return the appropriate vector +//------------------------------------------------- + +int z80dma_device::z80daisy_irq_ack() +{ + if (m_ip) + { + if (LOG) logerror("Z80DMA '%s' Interrupt Acknowledge\n", tag()); + + // clear interrupt pending flag + m_ip = 0; + interrupt_check(); + + // set interrupt under service flag + m_ius = 1; + + return m_vector; + } + + //logerror("z80dma_irq_ack: failed to find an interrupt to ack!\n"); + + return 0; +} + + +//------------------------------------------------- +// z80daisy_irq_reti - clear the interrupt +// pending state to allow other interrupts through +//------------------------------------------------- + +void z80dma_device::z80daisy_irq_reti() +{ + if (m_ius) + { + if (LOG) logerror("Z80DMA '%s' Return from Interrupt\n", tag()); + + // clear interrupt under service flag + m_ius = 0; + interrupt_check(); + + return; + } + + //logerror("z80dma_irq_reti: failed to find an interrupt to clear IEO on!\n"); +} + + + +//************************************************************************** +// INTERNAL STATE MANAGEMENT +//************************************************************************** + +//------------------------------------------------- +// is_ready - ready for DMA transfer? +//------------------------------------------------- + +int z80dma_device::is_ready() +{ + return (m_force_ready) || (m_rdy == READY_ACTIVE_HIGH); +} + + +//------------------------------------------------- +// interrupt_check - update IRQ line state +//------------------------------------------------- + +void z80dma_device::interrupt_check() +{ + m_out_int_cb(m_ip ? ASSERT_LINE : CLEAR_LINE); +} + + +//------------------------------------------------- +// trigger_interrupt - trigger DMA interrupt +//------------------------------------------------- + +void z80dma_device::trigger_interrupt(int level) +{ + if (!m_ius && INTERRUPT_ENABLE) + { + // set interrupt pending flag + m_ip = 1; + + // set interrupt vector + if (STATUS_AFFECTS_VECTOR) + { + m_vector = (INTERRUPT_VECTOR & 0xf9) | (level << 1); + } + else + { + m_vector = INTERRUPT_VECTOR; + } + + m_status &= ~0x08; + + if (LOG) logerror("Z80DMA '%s' Interrupt Pending\n", tag()); + + interrupt_check(); + } +} + + +//------------------------------------------------- +// do_read - perform DMA read +//------------------------------------------------- + +void z80dma_device::do_read() +{ + UINT8 mode; + + mode = TRANSFER_MODE; + switch(mode) { + case TM_TRANSFER: + case TM_SEARCH: + case TM_SEARCH_TRANSFER: + if (PORTA_IS_SOURCE) + { + if (PORTA_MEMORY) + m_latch = m_in_mreq_cb(m_addressA); + else + m_latch = m_in_iorq_cb(m_addressA); + + if (DMA_LOG) logerror("Z80DMA '%s' A src: %04x %s -> data: %02x\n", tag(), m_addressA, PORTA_MEMORY ? "mem" : "i/o", m_latch); + } + else + { + if (PORTB_MEMORY) + m_latch = m_in_mreq_cb(m_addressB); + else + m_latch = m_in_iorq_cb(m_addressB); + + if (DMA_LOG) logerror("Z80DMA '%s' B src: %04x %s -> data: %02x\n", tag(), m_addressB, PORTB_MEMORY ? "mem" : "i/o", m_latch); + } + break; + default: + logerror("z80dma_do_operation: invalid mode %d!\n", mode); + break; + } +} + + +//------------------------------------------------- +// do_write - perform DMA write +//------------------------------------------------- + +void z80dma_device::do_transfer_write() +{ + if (PORTA_IS_SOURCE) + { + if (PORTB_MEMORY) + m_out_mreq_cb((offs_t)m_addressB, m_latch); + else + m_out_iorq_cb((offs_t)m_addressB, m_latch); + + if (DMA_LOG) logerror("Z80DMA '%s' B dst: %04x %s\n", tag(), m_addressB, PORTB_MEMORY ? "mem" : "i/o"); + } + else + { + if (PORTA_MEMORY) + m_out_mreq_cb((offs_t)m_addressA, m_latch); + else + m_out_iorq_cb((offs_t)m_addressA, m_latch); + + if (DMA_LOG) logerror("Z80DMA '%s' A dst: %04x %s\n", tag(), m_addressA, PORTA_MEMORY ? "mem" : "i/o"); + } +} + +void z80dma_device::do_search() +{ + UINT8 load_byte,match_byte; + load_byte = m_latch | MASK_BYTE; + match_byte = MATCH_BYTE | MASK_BYTE; + //if (LOG) logerror("%02x %02x\n",load_byte,match_byte)); + if (load_byte == match_byte) + { + if (INT_ON_MATCH) + { + trigger_interrupt(INT_MATCH); + } + } +} + +int z80dma_device::do_write() +{ + int done = 0; + UINT8 mode; + + mode = TRANSFER_MODE; + if (m_count == 0x0000) + { + //FIXME: Any signal here + } + switch(mode) { + case TM_TRANSFER: + do_transfer_write(); + break; + + case TM_SEARCH: + do_search(); + break; + + case TM_SEARCH_TRANSFER: + do_transfer_write(); + do_search(); + break; + + default: + logerror("z80dma_do_operation: invalid mode %d!\n", mode); + break; + } + + m_addressA += PORTA_FIXED ? 0 : PORTA_INC ? 1 : -1; + m_addressB += PORTB_FIXED ? 0 : PORTB_INC ? 1 : -1; + + m_count--; + done = (m_count == 0xFFFF); //correct? + + if (done) + { + //FIXME: interrupt ? + } + return done; +} + + +//------------------------------------------------- +// timerproc +//------------------------------------------------- + +void z80dma_device::timerproc() +{ + int done; + + if (--m_cur_cycle) + { + return; + } + + if (m_is_read && !is_ready()) return; + + if (m_is_read) + { + /* TODO: there's a nasty recursion bug with Alpha for Sharp X1 Turbo on the transfers with this function! */ + do_read(); + done = 0; + m_is_read = false; + m_cur_cycle = (PORTA_IS_SOURCE ? PORTA_CYCLE_LEN : PORTB_CYCLE_LEN); + } + else + { + done = do_write(); + m_is_read = true; + m_cur_cycle = (PORTB_IS_SOURCE ? PORTA_CYCLE_LEN : PORTB_CYCLE_LEN); + } + + if (done) + { + m_dma_enabled = 0; //FIXME: Correct? + m_status = 0x09; + + m_status |= !is_ready() << 1; // ready line status + + if(TRANSFER_MODE == TM_TRANSFER) m_status |= 0x10; // no match found + + update_status(); + if (LOG) logerror("Z80DMA '%s' End of Block\n", tag()); + + if (INT_ON_END_OF_BLOCK) + { + trigger_interrupt(INT_END_OF_BLOCK); + } + + if (AUTO_RESTART) + { + if (LOG) logerror("Z80DMA '%s' Auto Restart\n", tag()); + + m_dma_enabled = 1; + m_addressA = PORTA_ADDRESS; + m_addressB = PORTB_ADDRESS; + m_count = BLOCKLEN; + m_status |= 0x30; + } + } +} + + +//------------------------------------------------- +// update_status - update DMA status +//------------------------------------------------- + +void z80dma_device::update_status() +{ + UINT16 pending_transfer; + attotime next; + + // no transfer is active right now; is there a transfer pending right now? + pending_transfer = is_ready() & m_dma_enabled; + + if (pending_transfer) + { + m_is_read = true; + m_cur_cycle = (PORTA_IS_SOURCE ? PORTA_CYCLE_LEN : PORTB_CYCLE_LEN); + next = attotime::from_hz(clock()); + m_timer->adjust( + attotime::zero, + 0, + // 1 byte transferred in 4 clock cycles + next); + } + else + { + if (m_is_read) + { + // no transfers active right now + m_timer->reset(); + } + } + + // set the busreq line + m_out_busreq_cb(pending_transfer ? ASSERT_LINE : CLEAR_LINE); +} + + + +//************************************************************************** +// READ/WRITE INTERFACES +//************************************************************************** + +//------------------------------------------------- +// read - register read +//------------------------------------------------- + +UINT8 z80dma_device::read() +{ + UINT8 res; + + if(m_read_num_follow == 0) // special case: Legend of Kage on X1 Turbo + res = m_status; + else { + res = m_read_regs_follow[m_read_cur_follow]; + } + + m_read_cur_follow++; + + if(m_read_cur_follow >= m_read_num_follow) + m_read_cur_follow = 0; + + if (LOG) logerror("Z80DMA '%s' Read %02x\n", tag(), res); + + return res; +} + + +//------------------------------------------------- +// write - register write +//------------------------------------------------- + +void z80dma_device::write(UINT8 data) +{ + if (m_num_follow == 0) + { + m_reset_pointer = 0; + + if ((data & 0x87) == 0) // WR2 + { + if (LOG) logerror("Z80DMA '%s' WR2 %02x\n", tag(), data); + WR2 = data; + if (data & 0x40) + m_regs_follow[m_num_follow++] = GET_REGNUM(PORTB_TIMING); + } + else if ((data & 0x87) == 0x04) // WR1 + { + if (LOG) logerror("Z80DMA '%s' WR1 %02x\n", tag(), data); + WR1 = data; + if (data & 0x40) + m_regs_follow[m_num_follow++] = GET_REGNUM(PORTA_TIMING); + } + else if ((data & 0x80) == 0) // WR0 + { + if (LOG) logerror("Z80DMA '%s' WR0 %02x\n", tag(), data); + WR0 = data; + if (data & 0x08) + m_regs_follow[m_num_follow++] = GET_REGNUM(PORTA_ADDRESS_L); + if (data & 0x10) + m_regs_follow[m_num_follow++] = GET_REGNUM(PORTA_ADDRESS_H); + if (data & 0x20) + m_regs_follow[m_num_follow++] = GET_REGNUM(BLOCKLEN_L); + if (data & 0x40) + m_regs_follow[m_num_follow++] = GET_REGNUM(BLOCKLEN_H); + } + else if ((data & 0x83) == 0x80) // WR3 + { + if (LOG) logerror("Z80DMA '%s' WR3 %02x\n", tag(), data); + WR3 = data; + if (data & 0x08) + m_regs_follow[m_num_follow++] = GET_REGNUM(MASK_BYTE); + if (data & 0x10) + m_regs_follow[m_num_follow++] = GET_REGNUM(MATCH_BYTE); + } + else if ((data & 0x83) == 0x81) // WR4 + { + if (LOG) logerror("Z80DMA '%s' WR4 %02x\n", tag(), data); + WR4 = data; + if (data & 0x04) + m_regs_follow[m_num_follow++] = GET_REGNUM(PORTB_ADDRESS_L); + if (data & 0x08) + m_regs_follow[m_num_follow++] = GET_REGNUM(PORTB_ADDRESS_H); + if (data & 0x10) + m_regs_follow[m_num_follow++] = GET_REGNUM(INTERRUPT_CTRL); + } + else if ((data & 0xC7) == 0x82) // WR5 + { + if (LOG) logerror("Z80DMA '%s' WR5 %02x\n", tag(), data); + WR5 = data; + } + else if ((data & 0x83) == 0x83) // WR6 + { + if (LOG) logerror("Z80DMA '%s' WR6 %02x\n", tag(), data); + m_dma_enabled = 0; + + WR6 = data; + + switch (data) + { + case COMMAND_ENABLE_AFTER_RETI: + fatalerror("Z80DMA '%s' Unimplemented WR6 command %02x\n", tag(), data); + case COMMAND_READ_STATUS_BYTE: + if (LOG) logerror("Z80DMA '%s' CMD Read status Byte\n", tag()); + READ_MASK = 1; + m_read_regs_follow[0] = m_status; + break; + case COMMAND_RESET_AND_DISABLE_INTERRUPTS: + WR3 &= ~0x20; + m_ip = 0; + m_ius = 0; + m_force_ready = 0; + m_status |= 0x08; + break; + case COMMAND_INITIATE_READ_SEQUENCE: + if (LOG) logerror("Z80DMA '%s' Initiate Read Sequence\n", tag()); + m_read_cur_follow = m_read_num_follow = 0; + if(READ_MASK & 0x01) { m_read_regs_follow[m_read_num_follow++] = m_status; } + if(READ_MASK & 0x02) { m_read_regs_follow[m_read_num_follow++] = m_count & 0xff; } //byte counter (low) + if(READ_MASK & 0x04) { m_read_regs_follow[m_read_num_follow++] = m_count >> 8; } //byte counter (high) + if(READ_MASK & 0x08) { m_read_regs_follow[m_read_num_follow++] = m_addressA & 0xff; } //port A address (low) + if(READ_MASK & 0x10) { m_read_regs_follow[m_read_num_follow++] = m_addressA >> 8; } //port A address (high) + if(READ_MASK & 0x20) { m_read_regs_follow[m_read_num_follow++] = m_addressB & 0xff; } //port B address (low) + if(READ_MASK & 0x40) { m_read_regs_follow[m_read_num_follow++] = m_addressB >> 8; } //port B address (high) + break; + case COMMAND_RESET: + if (LOG) logerror("Z80DMA '%s' Reset\n", tag()); + m_dma_enabled = 0; + m_force_ready = 0; + m_ip = 0; + m_ius = 0; + interrupt_check(); + // Needs six reset commands to reset the DMA + { + UINT8 WRi; + + for(WRi=0;WRi<7;WRi++) + REG(WRi,m_reset_pointer) = 0; + + m_reset_pointer++; + if(m_reset_pointer >= 6) { m_reset_pointer = 0; } + } + m_status = 0x38; + break; + case COMMAND_LOAD: + m_force_ready = 0; + m_addressA = PORTA_ADDRESS; + m_addressB = PORTB_ADDRESS; + m_count = BLOCKLEN; + m_status |= 0x30; + + if (LOG) logerror("Z80DMA '%s' Load A: %x B: %x N: %x\n", tag(), m_addressA, m_addressB, m_count); + break; + case COMMAND_DISABLE_DMA: + if (LOG) logerror("Z80DMA '%s' Disable DMA\n", tag()); + m_dma_enabled = 0; + break; + case COMMAND_ENABLE_DMA: + if (LOG) logerror("Z80DMA '%s' Enable DMA\n", tag()); + m_dma_enabled = 1; + update_status(); + break; + case COMMAND_READ_MASK_FOLLOWS: + if (LOG) logerror("Z80DMA '%s' Set Read Mask\n", tag()); + m_regs_follow[m_num_follow++] = GET_REGNUM(READ_MASK); + break; + case COMMAND_CONTINUE: + if (LOG) logerror("Z80DMA '%s' Continue\n", tag()); + m_count = BLOCKLEN; + m_dma_enabled = 1; + //"match not found" & "end of block" status flags zeroed here + m_status |= 0x30; + break; + case COMMAND_RESET_PORT_A_TIMING: + if (LOG) logerror("Z80DMA '%s' Reset Port A Timing\n", tag()); + PORTA_TIMING = 0; + break; + case COMMAND_RESET_PORT_B_TIMING: + if (LOG) logerror("Z80DMA '%s' Reset Port B Timing\n", tag()); + PORTB_TIMING = 0; + break; + case COMMAND_FORCE_READY: + if (LOG) logerror("Z80DMA '%s' Force Ready\n", tag()); + m_force_ready = 1; + update_status(); + break; + case COMMAND_ENABLE_INTERRUPTS: + if (LOG) logerror("Z80DMA '%s' Enable IRQ\n", tag()); + WR3 |= 0x20; + break; + case COMMAND_DISABLE_INTERRUPTS: + if (LOG) logerror("Z80DMA '%s' Disable IRQ\n", tag()); + WR3 &= ~0x20; + break; + case COMMAND_REINITIALIZE_STATUS_BYTE: + if (LOG) logerror("Z80DMA '%s' Reinitialize status byte\n", tag()); + m_status |= 0x30; + m_ip = 0; + break; + case 0xFB: + case 0xFF: // TODO: p8k triggers this, it probably crashed. + if (LOG) logerror("Z80DMA '%s' undocumented command triggered 0x%02X!\n", tag(), data); + break; + default: + printf("Z80DMA '%s' Unknown WR6 command %02x\n", tag(), data); + } + } + else if(data == 0x8e) //newtype on Sharp X1, unknown purpose + printf("Z80DMA '%s' Unknown base register %02x\n", tag(), data); + else + fatalerror("Z80DMA '%s' Unknown base register %02x\n", tag(), data); + m_cur_follow = 0; + } + else + { + if (LOG) logerror("Z80DMA '%s' Write %02x\n", tag(), data); + + int nreg = m_regs_follow[m_cur_follow]; + m_regs[nreg] = data; + m_cur_follow++; + if (m_cur_follow>=m_num_follow) + m_num_follow = 0; + if (nreg == REGNUM(4,3)) + { + m_num_follow=0; + if (data & 0x08) + m_regs_follow[m_num_follow++] = GET_REGNUM(PULSE_CTRL); + if (data & 0x10) + m_regs_follow[m_num_follow++] = GET_REGNUM(INTERRUPT_VECTOR); + m_cur_follow = 0; + } + else if(m_regs_follow[m_num_follow] == GET_REGNUM(READ_MASK)) + { + m_read_cur_follow = m_read_num_follow = 0; + + if(READ_MASK & 0x01) { m_read_regs_follow[m_read_num_follow++] = m_status; } + if(READ_MASK & 0x02) { m_read_regs_follow[m_read_num_follow++] = m_count & 0xff; } //byte counter (low) + if(READ_MASK & 0x04) { m_read_regs_follow[m_read_num_follow++] = m_count >> 8; } //byte counter (high) + if(READ_MASK & 0x08) { m_read_regs_follow[m_read_num_follow++] = m_addressA & 0xff; } //port A address (low) + if(READ_MASK & 0x10) { m_read_regs_follow[m_read_num_follow++] = m_addressA >> 8; } //port A address (high) + if(READ_MASK & 0x20) { m_read_regs_follow[m_read_num_follow++] = m_addressB & 0xff; } //port B address (low) + if(READ_MASK & 0x40) { m_read_regs_follow[m_read_num_follow++] = m_addressB >> 8; } //port B address (high) + } + + m_reset_pointer++; + if(m_reset_pointer >= 6) { m_reset_pointer = 0; } + } +} + + +//------------------------------------------------- +// rdy_write_callback - deferred RDY signal write +//------------------------------------------------- + +void z80dma_device::rdy_write_callback(int state) +{ + // normalize state + m_rdy = state; + m_status = (m_status & 0xFD) | (!is_ready() << 1); + + update_status(); + + if (is_ready() && INT_ON_READY) + { + trigger_interrupt(INT_RDY); + } +} + + +//------------------------------------------------- +// rdy_w - ready input +//------------------------------------------------- + +WRITE_LINE_MEMBER(z80dma_device::rdy_w) +{ + if (LOG) logerror("Z80DMA '%s' RDY: %d Active High: %d\n", tag(), state, READY_ACTIVE_HIGH); + machine().scheduler().synchronize(FUNC(static_rdy_write_callback), state, (void *)this); +} + + +//------------------------------------------------- +// wait_w - wait input +//------------------------------------------------- + +WRITE_LINE_MEMBER(z80dma_device::wait_w) +{ +} + + +//------------------------------------------------- +// bai_w - bus acknowledge input +//------------------------------------------------- + +WRITE_LINE_MEMBER(z80dma_device::bai_w) +{ +} diff --git a/src/devices/machine/z80dma.h b/src/devices/machine/z80dma.h new file mode 100644 index 00000000000..389112e6f19 --- /dev/null +++ b/src/devices/machine/z80dma.h @@ -0,0 +1,165 @@ +// license:BSD-3-Clause +// copyright-holders:Couriersud +/*************************************************************************** + + Zilog Z80 DMA Direct Memory Access Controller emulation + +**************************************************************************** + _____ _____ + A5 1 |* \_/ | 40 A6 + A4 2 | | 39 A7 + A3 3 | | 38 IEI + A2 4 | | 37 _INT/_PULSE + A1 5 | | 36 IEO + A0 6 | | 35 D0 + CLK 7 | | 34 D1 + _WR 8 | | 33 D2 + _RD 9 | | 32 D3 + _IORQ 10 | Z8410 | 31 D4 + +5V 11 | | 30 GND + _MREQ 12 | | 29 D5 + _BAO 13 | | 28 D6 + _BAI 14 | | 27 D7 + _BUSREQ 15 | | 26 _M1 + _CE/_WAIT 16 | | 25 RDY + A15 17 | | 24 A8 + A14 18 | | 23 A9 + A13 19 | | 22 A10 + A12 20 |_____________| 21 A11 + +***************************************************************************/ + +#ifndef __Z80DMA__ +#define __Z80DMA__ + +#include "cpu/z80/z80daisy.h" + + +//************************************************************************** +// DEVICE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_Z80DMA_OUT_BUSREQ_CB(_devcb) \ + devcb = &z80dma_device::set_out_busreq_callback(*device, DEVCB_##_devcb); + +#define MCFG_Z80DMA_OUT_INT_CB(_devcb) \ + devcb = &z80dma_device::set_out_int_callback(*device, DEVCB_##_devcb); + +#define MCFG_Z80DMA_OUT_BAO_CB(_devcb) \ + devcb = &z80dma_device::set_out_bao_callback(*device, DEVCB_##_devcb); + +#define MCFG_Z80DMA_IN_MREQ_CB(_devcb) \ + devcb = &z80dma_device::set_in_mreq_callback(*device, DEVCB_##_devcb); + +#define MCFG_Z80DMA_OUT_MREQ_CB(_devcb) \ + devcb = &z80dma_device::set_out_mreq_callback(*device, DEVCB_##_devcb); + +#define MCFG_Z80DMA_IN_IORQ_CB(_devcb) \ + devcb = &z80dma_device::set_in_iorq_callback(*device, DEVCB_##_devcb); + +#define MCFG_Z80DMA_OUT_IORQ_CB(_devcb) \ + devcb = &z80dma_device::set_out_iorq_callback(*device, DEVCB_##_devcb); + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + + +// ======================> z80dma_device + +class z80dma_device : public device_t, + public device_z80daisy_interface +{ +public: + // construction/destruction + z80dma_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + template static devcb_base &set_out_busreq_callback(device_t &device, _Object object) { return downcast(device).m_out_busreq_cb.set_callback(object); } + template static devcb_base &set_out_int_callback(device_t &device, _Object object) { return downcast(device).m_out_int_cb.set_callback(object); } + template static devcb_base &set_out_bao_callback(device_t &device, _Object object) { return downcast(device).m_out_bao_cb.set_callback(object); } + template static devcb_base &set_in_mreq_callback(device_t &device, _Object object) { return downcast(device).m_in_mreq_cb.set_callback(object); } + template static devcb_base &set_out_mreq_callback(device_t &device, _Object object) { return downcast(device).m_out_mreq_cb.set_callback(object); } + template static devcb_base &set_in_iorq_callback(device_t &device, _Object object) { return downcast(device).m_in_iorq_cb.set_callback(object); } + template static devcb_base &set_out_iorq_callback(device_t &device, _Object object) { return downcast(device).m_out_iorq_cb.set_callback(object); } + + UINT8 read(); + void write(UINT8 data); + DECLARE_READ8_MEMBER( read ) { return read(); } + DECLARE_WRITE8_MEMBER( write ) { write(data); } + + DECLARE_WRITE_LINE_MEMBER(rdy_w); + DECLARE_WRITE_LINE_MEMBER(wait_w); + DECLARE_WRITE_LINE_MEMBER(bai_w); + +private: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_z80daisy_interface overrides + virtual int z80daisy_irq_state(); + virtual int z80daisy_irq_ack(); + virtual void z80daisy_irq_reti(); + + // internal helpers + int is_ready(); + void interrupt_check(); + void trigger_interrupt(int level); + void do_read(); + int do_write(); + void do_transfer_write(); + void do_search(); + + static TIMER_CALLBACK( static_timerproc ) { reinterpret_cast(ptr)->timerproc(); } + void timerproc(); + + void update_status(); + + static TIMER_CALLBACK( static_rdy_write_callback ) { reinterpret_cast(ptr)->rdy_write_callback(param); } + void rdy_write_callback(int state); + + // internal state + devcb_write_line m_out_busreq_cb; + devcb_write_line m_out_int_cb; + devcb_write_line m_out_bao_cb; + devcb_read8 m_in_mreq_cb; + devcb_write8 m_out_mreq_cb; + devcb_read8 m_in_iorq_cb; + devcb_write8 m_out_iorq_cb; + + emu_timer *m_timer; + + UINT16 m_regs[(6<<3)+1+1]; + UINT8 m_num_follow; + UINT8 m_cur_follow; + UINT8 m_regs_follow[5]; + UINT8 m_read_num_follow; + UINT8 m_read_cur_follow; + UINT8 m_read_regs_follow[7]; + UINT8 m_status; + UINT8 m_dma_enabled; + + UINT16 m_addressA; + UINT16 m_addressB; + UINT16 m_count; + + int m_rdy; + int m_force_ready; + UINT8 m_reset_pointer; + + bool m_is_read; + UINT8 m_cur_cycle; + UINT8 m_latch; + + // interrupts + int m_ip; // interrupt pending + int m_ius; // interrupt under service + UINT8 m_vector; // interrupt vector +}; + + +// device type definition +extern const device_type Z80DMA; + +#endif diff --git a/src/devices/machine/z80pio.c b/src/devices/machine/z80pio.c new file mode 100644 index 00000000000..6463adc8fb7 --- /dev/null +++ b/src/devices/machine/z80pio.c @@ -0,0 +1,809 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/*************************************************************************** + + Zilog Z80 Parallel Input/Output Controller implementation + +***************************************************************************/ + +/* + + TODO: + + - if port A is bidirectional, port B does not issue interrupts in bit mode + +*/ + +#include "emu.h" +#include "z80pio.h" +#include "cpu/z80/z80daisy.h" + + +//************************************************************************** +// CONSTANTS +//************************************************************************** + +#define LOG 0 + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +// device type definition +const device_type Z80PIO = &device_creator; + +//------------------------------------------------- +// z80pio_device - constructor +//------------------------------------------------- + +z80pio_device::z80pio_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, Z80PIO, "Z80 PIO", tag, owner, clock, "z80pio", __FILE__), + device_z80daisy_interface(mconfig, *this), + m_out_int_cb(*this), + m_in_pa_cb(*this), + m_out_pa_cb(*this), + m_out_ardy_cb(*this), + m_in_pb_cb(*this), + m_out_pb_cb(*this), + m_out_brdy_cb(*this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void z80pio_device::device_start() +{ + m_port[PORT_A].start(this, PORT_A); + m_port[PORT_B].start(this, PORT_B); + + // resolve callbacks + m_out_int_cb.resolve_safe(); + m_in_pa_cb.resolve_safe(0); + m_out_pa_cb.resolve_safe(); + m_out_ardy_cb.resolve_safe(); + m_in_pb_cb.resolve_safe(0); + m_out_pb_cb.resolve_safe(); + m_out_brdy_cb.resolve_safe(); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void z80pio_device::device_reset() +{ + // loop over ports + for (int index = PORT_A; index < PORT_COUNT; index++) + m_port[index].reset(); +} + + + +//************************************************************************** +// DAISY CHAIN INTERFACE +//************************************************************************** + +//------------------------------------------------- +// z80daisy_irq_state - return the overall IRQ +// state for this device +//------------------------------------------------- + +int z80pio_device::z80daisy_irq_state() +{ + int state = 0; + + for (int index = PORT_A; index < PORT_COUNT; index++) + { + pio_port &port = m_port[index]; + + if (port.m_ius) + { + // interrupt under service + return Z80_DAISY_IEO; + } + else if (port.m_ie && port.m_ip) + { + // interrupt pending + state = Z80_DAISY_INT; + } + } + + return state; +} + + +//------------------------------------------------- +// z80daisy_irq_ack - acknowledge an IRQ and +// return the appropriate vector +//------------------------------------------------- + +int z80pio_device::z80daisy_irq_ack() +{ + for (int index = PORT_A; index < PORT_COUNT; index++) + { + pio_port &port = m_port[index]; + + if (port.m_ip) + { + if (LOG) logerror("Z80PIO '%s' Port %c Interrupt Acknowledge\n", tag(), 'A' + index); + + // clear interrupt pending flag + port.m_ip = false; + + // set interrupt under service flag + port.m_ius = true; + + check_interrupts(); + + return port.m_vector; + } + } + + //logerror("z80pio_irq_ack: failed to find an interrupt to ack!\n"); + + return 0; +} + + +//------------------------------------------------- +// z80daisy_irq_reti - clear the interrupt +// pending state to allow other interrupts through +//------------------------------------------------- + +void z80pio_device::z80daisy_irq_reti() +{ + for (int index = PORT_A; index < PORT_COUNT; index++) + { + pio_port &port = m_port[index]; + + if (port.m_ius) + { + if (LOG) logerror("Z80PIO '%s' Port %c Return from Interrupt\n", tag(), 'A' + index); + + // clear interrupt under service flag + port.m_ius = false; + check_interrupts(); + + return; + } + } + + //logerror("z80pio_irq_reti: failed to find an interrupt to clear IEO on!\n"); +} + + + +//************************************************************************** +// READ/WRITE HANDLERS +//************************************************************************** + +//------------------------------------------------- +// read - register read +//------------------------------------------------- + +READ8_MEMBER( z80pio_device::read ) +{ + int index = BIT(offset, 0); + return BIT(offset, 1) ? control_read() : data_read(index); +} + +//------------------------------------------------- +// write - register write +//------------------------------------------------- + +WRITE8_MEMBER( z80pio_device::write ) +{ + int index = BIT(offset, 0); + BIT(offset, 1) ? control_write(index, data) : data_write(index, data); +} + +//------------------------------------------------- +// read_alt - register read +//------------------------------------------------- + +READ8_MEMBER( z80pio_device::read_alt ) +{ + int index = BIT(offset, 1); + return BIT(offset, 0) ? control_read() : data_read(index); +} + +//------------------------------------------------- +// write_alt - register write +//------------------------------------------------- + +WRITE8_MEMBER( z80pio_device::write_alt ) +{ + int index = BIT(offset, 1); + BIT(offset, 0) ? control_write(index, data) : data_write(index, data); +} + + + +//************************************************************************** +// DEVICE-LEVEL IMPLEMENTATION +//************************************************************************** + +//------------------------------------------------- +// control_read - control register read +//------------------------------------------------- + +UINT8 z80pio_device::control_read() +{ + return (m_port[PORT_A].m_icw & 0xc0) | (m_port[PORT_B].m_icw >> 4); +} + + +//------------------------------------------------- +// check_interrupts - update the interrupt state +// over all ports +//------------------------------------------------- + +void z80pio_device::check_interrupts() +{ + int state = CLEAR_LINE; + bool ius = (m_port[PORT_A].m_ius || m_port[PORT_B].m_ius); + + for (int index = PORT_A; index < PORT_COUNT; index++) + { + if (LOG) logerror("Z80PIO '%s' Port %c IE %s IP %s IUS %s\n", tag(), 'A' + index, m_port[index].m_ie ? "1":"0", m_port[index].m_ip ? "1":"0", m_port[index].m_ius ? "1":"0"); + + if (!ius && m_port[index].m_ie && m_port[index].m_ip) + { + state = ASSERT_LINE; + } + } + + if (LOG) logerror("Z80PIO '%s' INT %u\n", tag(), state); + + m_out_int_cb(state); +} + + + +//************************************************************************** +// PORT-LEVEL IMPLEMENTATION +//************************************************************************** + +//------------------------------------------------- +// pio_port - constructor +//------------------------------------------------- + +z80pio_device::pio_port::pio_port() : + m_device(NULL), + m_index(0), + m_mode(0), + m_next_control_word(0), + m_input(0), + m_output(0), + m_ior(0), + m_rdy(false), + m_stb(false), + m_ie(false), + m_ip(false), + m_ius(false), + m_icw(0), + m_vector(0), + m_mask(0), + m_match(false) +{ +} + + +//------------------------------------------------- +// start - set up a port during device startup +//------------------------------------------------- + +void z80pio_device::pio_port::start(z80pio_device *device, int index) +{ + m_device = device; + m_index = index; + + // register for state saving + m_device->save_item(NAME(m_mode), m_index); + m_device->save_item(NAME(m_next_control_word), m_index); + m_device->save_item(NAME(m_input), m_index); + m_device->save_item(NAME(m_output), m_index); + m_device->save_item(NAME(m_ior), m_index); + m_device->save_item(NAME(m_rdy), m_index); + m_device->save_item(NAME(m_stb), m_index); + m_device->save_item(NAME(m_ie), m_index); + m_device->save_item(NAME(m_ip), m_index); + m_device->save_item(NAME(m_ius), m_index); + m_device->save_item(NAME(m_icw), m_index); + m_device->save_item(NAME(m_vector), m_index); + m_device->save_item(NAME(m_mask), m_index); + m_device->save_item(NAME(m_match), m_index); +} + + +//------------------------------------------------- +// reset - reset a port during device reset +//------------------------------------------------- + +void z80pio_device::pio_port::reset() +{ + // set mode 1 + set_mode(MODE_INPUT); + + // reset interrupt enable flip-flops + m_icw &= ~ICW_ENABLE_INT; + m_ie = false; + m_ip = false; + m_ius = false; + m_match = false; + + // reset all bits of the data I/O register + m_ior = 0; + + // set all bits of the mask control register + m_mask = 0xff; + + // reset output register + m_output = 0; + + // clear ready line + set_rdy(false); +} + + +//------------------------------------------------- +// trigger_interrupt - trigger an interrupt from +// this port +//------------------------------------------------- + +void z80pio_device::pio_port::trigger_interrupt() +{ + m_ip = true; + if (LOG) logerror("Z80PIO '%s' Port %c Transfer Mode Interrupt Pending\n", m_device->tag(), 'A' + m_index); + + check_interrupts(); +} + + +//------------------------------------------------- +// set_rdy - set the port's RDY line +//------------------------------------------------- + +void z80pio_device::pio_port::set_rdy(bool state) +{ + if (m_rdy == state) return; + + if (LOG) logerror("Z80PIO '%s' Port %c Ready: %u\n", m_device->tag(), 'A' + m_index, state); + + m_rdy = state; + if (m_index == PORT_A) + m_device->m_out_ardy_cb(state); + else + m_device->m_out_brdy_cb(state); +} + + +//------------------------------------------------- +// set_mode - set the port's mode +//------------------------------------------------- + +void z80pio_device::pio_port::set_mode(int mode) +{ + if (LOG) logerror("Z80PIO '%s' Port %c Mode: %u\n", m_device->tag(), 'A' + m_index, mode); + + switch (mode) + { + case MODE_OUTPUT: + // enable data output + if (m_index == PORT_A) + m_device->m_out_pa_cb((offs_t)0, m_output); + else + m_device->m_out_pb_cb((offs_t)0, m_output); + + // assert ready line + set_rdy(true); + + // set mode register + m_mode = mode; + break; + + case MODE_INPUT: + // set mode register + m_mode = mode; + break; + + case MODE_BIDIRECTIONAL: + if (m_index == PORT_B) + { + logerror("Z80PIO '%s' Port %c Invalid Mode: %u!\n", m_device->tag(), 'A' + m_index, mode); + } + else + { + // set mode register + m_mode = mode; + } + break; + + case MODE_BIT_CONTROL: + if ((m_index == PORT_A) || (m_device->m_port[PORT_A].m_mode != MODE_BIDIRECTIONAL)) + { + // clear ready line + set_rdy(false); + } + + // disable interrupts until IOR is written + m_ie = false; + check_interrupts(); + + // set logic equation to false + m_match = false; + + // next word is I/O register + m_next_control_word = IOR; + + // set mode register + m_mode = mode; + break; + } +} + + +//------------------------------------------------- +// strobe - strobe data in/out of the port +//------------------------------------------------- + +void z80pio_device::pio_port::strobe(bool state) +{ + if (LOG) logerror("Z80PIO '%s' Port %c Strobe: %u\n", m_device->tag(), 'A' + m_index, state); + + if (m_device->m_port[PORT_A].m_mode == MODE_BIDIRECTIONAL) + { + if (m_rdy) // port ready + { + if (m_stb && !state) // falling edge + { + if (m_index == PORT_A) + m_device->m_out_pa_cb((offs_t)0, m_output); + else + m_device->m_port[PORT_A].m_input = m_device->m_in_pa_cb(0); + } + else if (!m_stb && state) // rising edge + { + trigger_interrupt(); + + // clear ready line + set_rdy(false); + } + } + } + else + { + switch (m_mode) + { + case MODE_OUTPUT: + if (m_rdy) + { + if (!m_stb && state) // rising edge + { + trigger_interrupt(); + + // clear ready line + set_rdy(false); + } + } + break; + + case MODE_INPUT: + if (!state) + { + // input port data + if (m_index == PORT_A) + m_input = m_device->m_in_pa_cb(0); + else + m_input = m_device->m_in_pb_cb(0); + } + else if (!m_stb && state) // rising edge + { + trigger_interrupt(); + + // clear ready line + set_rdy(false); + } + break; + } + } + + m_stb = state; +} + + +//------------------------------------------------- +// read - port I/O read +//------------------------------------------------- + +UINT8 z80pio_device::pio_port::read() +{ + UINT8 data = 0xff; + + switch (m_mode) + { + case MODE_OUTPUT: + data = m_output; + break; + + case MODE_BIDIRECTIONAL: + if (m_index == PORT_A) + data = m_output; + break; + + case MODE_BIT_CONTROL: + data = m_ior | (m_output & (m_ior ^ 0xff)); + break; + } + + return data; +} + + +//------------------------------------------------- +// write - port I/O write +//------------------------------------------------- + +void z80pio_device::pio_port::write(UINT8 data) +{ + if (m_mode == MODE_BIT_CONTROL) + { + // latch data + m_input = data; + + // fetch input data (ignore output lines) + UINT8 data = (m_input & m_ior) | (m_output & ~m_ior); + UINT8 mask = ~m_mask; + bool match = false; + + data &= mask; + + if ((m_icw & 0x60) == 0 && data != mask) match = true; + else if ((m_icw & 0x60) == 0x20 && data != 0) match = true; + else if ((m_icw & 0x60) == 0x40 && data == 0) match = true; + else if ((m_icw & 0x60) == 0x60 && data == mask) match = true; + + if (!m_match && match && !m_ius) + { + // trigger interrupt + m_ip = true; + if (LOG) logerror("Z80PIO '%s' Port %c Bit Control Mode Interrupt Pending\n", m_device->tag(), 'A' + m_index); + } + + m_match = match; + + check_interrupts(); + } +} + + +//------------------------------------------------- +// control_write - control register write +//------------------------------------------------- + +void z80pio_device::pio_port::control_write(UINT8 data) +{ + switch (m_next_control_word) + { + case ANY: + if (!BIT(data, 0)) + { + // load interrupt vector + m_vector = data; + if (LOG) logerror("Z80PIO '%s' Port %c Interrupt Vector: %02x\n", m_device->tag(), 'A' + m_index, data); + + // set interrupt enable + m_icw |= ICW_ENABLE_INT; + m_ie = true; + check_interrupts(); + } + else + { + switch (data & 0x0f) + { + case 0x0f: // select operating mode + set_mode(data >> 6); + break; + + case 0x07: // set interrupt control word + m_icw = data; + + if (LOG) + { + logerror("Z80PIO '%s' Port %c Interrupt Enable: %u\n", m_device->tag(), 'A' + m_index, BIT(data, 7)); + logerror("Z80PIO '%s' Port %c Logic: %s\n", m_device->tag(), 'A' + m_index, BIT(data, 6) ? "AND" : "OR"); + logerror("Z80PIO '%s' Port %c Active %s\n", m_device->tag(), 'A' + m_index, BIT(data, 5) ? "High" : "Low"); + logerror("Z80PIO '%s' Port %c Mask Follows: %u\n", m_device->tag(), 'A' + m_index, BIT(data, 4)); + } + + if (m_icw & ICW_MASK_FOLLOWS) + { + // disable interrupts until mask is written + m_ie = false; + + // reset pending interrupts + m_ip = false; + check_interrupts(); + + // set logic equation to false + m_match = false; + + // next word is mask control + m_next_control_word = MASK; + } + else + { + // set interrupt enable + m_ie = BIT(m_icw, 7) ? true : false; + check_interrupts(); + } + break; + + case 0x03: // set interrupt enable flip-flop + m_icw = (data & 0x80) | (m_icw & 0x7f); + if (LOG) logerror("Z80PIO '%s' Port %c Interrupt Enable: %u\n", m_device->tag(), 'A' + m_index, BIT(data, 7)); + + // set interrupt enable + m_ie = BIT(m_icw, 7) ? true : false; + check_interrupts(); + break; + + default: + logerror("Z80PIO '%s' Port %c Invalid Control Word: %02x!\n", m_device->tag(), 'A' + m_index, data); + } + } + break; + + case IOR: // data direction register + m_ior = data; + if (LOG) logerror("Z80PIO '%s' Port %c IOR: %02x\n", m_device->tag(), 'A' + m_index, data); + + // set interrupt enable + m_ie = BIT(m_icw, 7) ? true : false; + check_interrupts(); + + // next word is any + m_next_control_word = ANY; + break; + + case MASK: // interrupt mask + m_mask = data; + if (LOG) logerror("Z80PIO '%s' Port %c Mask: %02x\n", m_device->tag(), 'A' + m_index, data); + + // set interrupt enable + m_ie = BIT(m_icw, 7) ? true : false; + check_interrupts(); + + // next word is any + m_next_control_word = ANY; + break; + } +} + + +//------------------------------------------------- +// data_read - data register read +//------------------------------------------------- + +UINT8 z80pio_device::pio_port::data_read() +{ + UINT8 data = 0; + + switch (m_mode) + { + case MODE_OUTPUT: + data = m_output; + break; + + case MODE_INPUT: + if (!m_stb) + { + // input port data + if (m_index == PORT_A) + m_input = m_device->m_in_pa_cb(0); + else + m_input = m_device->m_in_pb_cb(0); + } + + data = m_input; + + // clear ready line + set_rdy(false); + + // assert ready line + set_rdy(true); + break; + + case MODE_BIDIRECTIONAL: + data = m_input; + + // clear ready line + m_device->m_port[PORT_B].set_rdy(false); + + // assert ready line + m_device->m_port[PORT_B].set_rdy(true); + break; + + case MODE_BIT_CONTROL: + // input port data + if (m_index == PORT_A) + m_input = m_device->m_in_pa_cb(0); + else + m_input = m_device->m_in_pb_cb(0); + + data = (m_input & m_ior) | (m_output & (m_ior ^ 0xff)); + break; + } + + return data; +} + + +//------------------------------------------------- +// data_write - data register write +//------------------------------------------------- + +void z80pio_device::pio_port::data_write(UINT8 data) +{ + switch (m_mode) + { + case MODE_OUTPUT: + // clear ready line + set_rdy(false); + + // latch output data + m_output = data; + + // output data to port + if (m_index == PORT_A) + m_device->m_out_pa_cb((offs_t)0, m_output); + else + m_device->m_out_pb_cb((offs_t)0, m_output); + + // assert ready line + set_rdy(true); + break; + + case MODE_INPUT: + // latch output data + m_output = data; + break; + + case MODE_BIDIRECTIONAL: + // clear ready line + set_rdy(false); + + // latch output data + m_output = data; + + if (!m_stb) + { + // output data to port + if (m_index == PORT_A) + m_device->m_out_pa_cb((offs_t)0, data); + else + m_device->m_out_pb_cb((offs_t)0, data); + } + + // assert ready line + set_rdy(true); + break; + + case MODE_BIT_CONTROL: + // latch output data + m_output = data; + + // output data to port + if (m_index == PORT_A) + m_device->m_out_pa_cb((offs_t)0, m_ior | (m_output & (m_ior ^ 0xff))); + else + m_device->m_out_pb_cb((offs_t)0, m_ior | (m_output & (m_ior ^ 0xff))); + break; + } +} diff --git a/src/devices/machine/z80pio.h b/src/devices/machine/z80pio.h new file mode 100644 index 00000000000..80a458dd4fd --- /dev/null +++ b/src/devices/machine/z80pio.h @@ -0,0 +1,260 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/*************************************************************************** + + Zilog Z80 Parallel Input/Output Controller implementation + +*************************************************************************** + _____ _____ + D2 1 |* \_/ | 40 D3 + D7 2 | | 39 D4 + D6 3 | | 38 D5 + _CE 4 | | 37 _M1 + C/_D 5 | | 36 _IORQ + B/_A 6 | | 35 RD + PA7 7 | | 34 PB7 + PA6 8 | | 33 PB6 + PA5 9 | | 32 PB5 + PA4 10 | Z8420 | 31 PB4 + GND 11 | | 30 PB3 + PA3 12 | | 29 PB2 + PA2 13 | | 28 PB1 + PA1 14 | | 27 PB0 + PA0 15 | | 26 +5V + _ASTB 16 | | 25 CLK + _BSTB 17 | | 24 IEI + ARDY 18 | | 23 _INT + D0 19 | | 22 IEO + D1 20 |_____________| 21 BRDY + +***************************************************************************/ + +#ifndef __Z80PIO__ +#define __Z80PIO__ + +#include "cpu/z80/z80daisy.h" + + +//************************************************************************** +// DEVICE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_Z80PIO_OUT_INT_CB(_devcb) \ + devcb = &z80pio_device::set_out_int_callback(*device, DEVCB_##_devcb); + +#define MCFG_Z80PIO_IN_PA_CB(_devcb) \ + devcb = &z80pio_device::set_in_pa_callback(*device, DEVCB_##_devcb); + +#define MCFG_Z80PIO_OUT_PA_CB(_devcb) \ + devcb = &z80pio_device::set_out_pa_callback(*device, DEVCB_##_devcb); + +#define MCFG_Z80PIO_OUT_ARDY_CB(_devcb) \ + devcb = &z80pio_device::set_out_ardy_callback(*device, DEVCB_##_devcb); + +#define MCFG_Z80PIO_IN_PB_CB(_devcb) \ + devcb = &z80pio_device::set_in_pb_callback(*device, DEVCB_##_devcb); + +#define MCFG_Z80PIO_OUT_PB_CB(_devcb) \ + devcb = &z80pio_device::set_out_pb_callback(*device, DEVCB_##_devcb); + +#define MCFG_Z80PIO_OUT_BRDY_CB(_devcb) \ + devcb = &z80pio_device::set_out_brdy_callback(*device, DEVCB_##_devcb); + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + + +// ======================> z80pio_device + +class z80pio_device : public device_t, + public device_z80daisy_interface +{ +public: + enum + { + PORT_A = 0, + PORT_B, + PORT_COUNT + }; + + // construction/destruction + z80pio_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + template static devcb_base &set_out_int_callback(device_t &device, _Object object) { return downcast(device).m_out_int_cb.set_callback(object); } + template static devcb_base &set_in_pa_callback(device_t &device, _Object object) { return downcast(device).m_in_pa_cb.set_callback(object); } + template static devcb_base &set_out_pa_callback(device_t &device, _Object object) { return downcast(device).m_out_pa_cb.set_callback(object); } + template static devcb_base &set_out_ardy_callback(device_t &device, _Object object) { return downcast(device).m_out_ardy_cb.set_callback(object); } + template static devcb_base &set_in_pb_callback(device_t &device, _Object object) { return downcast(device).m_in_pb_cb.set_callback(object); } + template static devcb_base &set_out_pb_callback(device_t &device, _Object object) { return downcast(device).m_out_pb_cb.set_callback(object); } + template static devcb_base &set_out_brdy_callback(device_t &device, _Object object) { return downcast(device).m_out_brdy_cb.set_callback(object); } + + // I/O line access + int rdy(int which) { return m_port[which].rdy(); } + void strobe(int which, bool state) { m_port[which].strobe(state); } + DECLARE_READ_LINE_MEMBER( rdy_a ) { return rdy(PORT_A); } + DECLARE_READ_LINE_MEMBER( rdy_b ) { return rdy(PORT_B); } + DECLARE_WRITE_LINE_MEMBER( strobe_a ) { strobe(PORT_A, state); } + DECLARE_WRITE_LINE_MEMBER( strobe_b ) { strobe(PORT_B, state); } + + // control register I/O + UINT8 control_read(); + void control_write(int offset, UINT8 data) { m_port[offset & 1].control_write(data); } + void control_a_write(UINT8 data) { control_write(PORT_A, data); } + void control_b_write(UINT8 data) { control_write(PORT_B, data); } + + // data register I/O + UINT8 data_read(int offset) { return m_port[offset & 1].data_read(); } + void data_write(int offset, UINT8 data) { m_port[offset & 1].data_write(data); } + UINT8 data_a_read() { return data_read(PORT_A); } + UINT8 data_b_read() { return data_read(PORT_B); } + void data_a_write(UINT8 data) { data_write(PORT_A, data); } + void data_b_write(UINT8 data) { data_write(PORT_B, data); } + + // port I/O + UINT8 port_read(int offset) { return m_port[offset & 1].read(); } + void port_write(int offset, UINT8 data) { m_port[offset & 1].write(data); } + void port_write(int offset, int bit, int state) { port_write(offset, (m_port[offset & 1].m_input & ~(1 << bit)) | (state << bit)); } + UINT8 port_a_read() { return port_read(PORT_A); } + UINT8 port_b_read() { return port_read(PORT_B); } + void port_a_write(UINT8 data) { port_write(PORT_A, data); } + void port_b_write(UINT8 data) { port_write(PORT_B, data); } + DECLARE_WRITE8_MEMBER( pa_w ) { port_a_write(data); } + DECLARE_READ8_MEMBER( pa_r ) { return port_a_read(); } + DECLARE_WRITE8_MEMBER( pb_w ) { port_b_write(data); } + DECLARE_READ8_MEMBER( pb_r ) { return port_b_read(); } + DECLARE_WRITE_LINE_MEMBER( pa0_w ) { port_write(PORT_A, 0, state); } + DECLARE_WRITE_LINE_MEMBER( pa1_w ) { port_write(PORT_A, 1, state); } + DECLARE_WRITE_LINE_MEMBER( pa2_w ) { port_write(PORT_A, 2, state); } + DECLARE_WRITE_LINE_MEMBER( pa3_w ) { port_write(PORT_A, 3, state); } + DECLARE_WRITE_LINE_MEMBER( pa4_w ) { port_write(PORT_A, 4, state); } + DECLARE_WRITE_LINE_MEMBER( pa5_w ) { port_write(PORT_A, 5, state); } + DECLARE_WRITE_LINE_MEMBER( pa6_w ) { port_write(PORT_A, 6, state); } + DECLARE_WRITE_LINE_MEMBER( pa7_w ) { port_write(PORT_A, 7, state); } + DECLARE_WRITE_LINE_MEMBER( pb0_w ) { port_write(PORT_B, 0, state); } + DECLARE_WRITE_LINE_MEMBER( pb1_w ) { port_write(PORT_B, 1, state); } + DECLARE_WRITE_LINE_MEMBER( pb2_w ) { port_write(PORT_B, 2, state); } + DECLARE_WRITE_LINE_MEMBER( pb3_w ) { port_write(PORT_B, 3, state); } + DECLARE_WRITE_LINE_MEMBER( pb4_w ) { port_write(PORT_B, 4, state); } + DECLARE_WRITE_LINE_MEMBER( pb5_w ) { port_write(PORT_B, 5, state); } + DECLARE_WRITE_LINE_MEMBER( pb6_w ) { port_write(PORT_B, 6, state); } + DECLARE_WRITE_LINE_MEMBER( pb7_w ) { port_write(PORT_B, 7, state); } + + // standard read/write, with C/D in bit 1, B/A in bit 0 + DECLARE_READ8_MEMBER( read ); + DECLARE_WRITE8_MEMBER( write ); + + // alternate read/write, with C/D in bit 0, B/A in bit 1 + DECLARE_READ8_MEMBER( read_alt ); + DECLARE_WRITE8_MEMBER( write_alt ); + +private: + enum + { + MODE_OUTPUT = 0, + MODE_INPUT, + MODE_BIDIRECTIONAL, + MODE_BIT_CONTROL + }; + + enum + { + ANY = 0, + IOR, + MASK + }; + + enum + { + ICW_ENABLE_INT = 0x80, + ICW_AND_OR = 0x40, + ICW_AND = 0x40, + ICW_OR = 0x00, + ICW_HIGH_LOW = 0x20, + ICW_HIGH = 0x20, + ICW_LOW = 0x00, + ICW_MASK_FOLLOWS = 0x10 + }; + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_z80daisy_interface overrides + virtual int z80daisy_irq_state(); + virtual int z80daisy_irq_ack(); + virtual void z80daisy_irq_reti(); + + // internal helpers + void check_interrupts(); + + // a single PIO port + class pio_port + { + friend class z80pio_device; + + public: + pio_port(); + + void start(z80pio_device *device, int index); + void reset(); + + void trigger_interrupt(); + + int rdy() const { return m_rdy; } + void set_rdy(bool state); + void set_mode(int mode); + void strobe(bool state); + + UINT8 read(); + void write(UINT8 data); + + void control_write(UINT8 data); + + UINT8 data_read(); + void data_write(UINT8 data); + + private: + void check_interrupts() { m_device->check_interrupts(); } + + z80pio_device * m_device; + int m_index; + + int m_mode; // mode register + int m_next_control_word; // next control word + UINT8 m_input; // input latch + UINT8 m_output; // output latch + UINT8 m_ior; // input/output register + bool m_rdy; // ready + bool m_stb; // strobe + + // interrupts + bool m_ie; // interrupt enabled + bool m_ip; // interrupt pending + bool m_ius; // interrupt under service + UINT8 m_icw; // interrupt control word + UINT8 m_vector; // interrupt vector + UINT8 m_mask; // interrupt mask + bool m_match; // logic equation match + }; + + // internal state + pio_port m_port[2]; + devcb_write_line m_out_int_cb; + + devcb_read8 m_in_pa_cb; + devcb_write8 m_out_pa_cb; + devcb_write_line m_out_ardy_cb; + + devcb_read8 m_in_pb_cb; + devcb_write8 m_out_pb_cb; + devcb_write_line m_out_brdy_cb; +}; + + +// device type definition +extern const device_type Z80PIO; + + +#endif diff --git a/src/devices/machine/z80sti.c b/src/devices/machine/z80sti.c new file mode 100644 index 00000000000..a27295f6ff1 --- /dev/null +++ b/src/devices/machine/z80sti.c @@ -0,0 +1,720 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/*************************************************************************** + + Mostek MK3801 Serial Timer Interrupt Controller (Z80-STI) emulation + +***************************************************************************/ + +/* + + TODO: + + - timers (other than delay mode) + - serial I/O + - reset behavior + +*/ + +#include "emu.h" +#include "z80sti.h" +#include "cpu/z80/z80.h" +#include "cpu/z80/z80daisy.h" + + + +// device type definition +const device_type Z80STI = &device_creator; + + + +//************************************************************************** +// DEBUGGING +//************************************************************************** + +#define VERBOSE 0 + +#define LOG(x) do { if (VERBOSE) logerror x; } while (0) + + + +//************************************************************************** +// CONSTANTS +//************************************************************************** + +// timer C/D control register +//const int TCDC_TARS = 0x80; +//const int TCDC_TBRS = 0x08; + +// interrupt vector register +//const int PVR_ISE = 0x08; +//const int PVR_VR4 = 0x10; + +// general purpose I/O interrupt levels +const int z80sti_device::INT_LEVEL_GPIP[] = +{ + IR_P0, IR_P1, IR_P2, IR_P3, IR_P4, IR_P5, IR_P6, IR_P7 +}; + +// timer interrupt levels +const int z80sti_device::INT_LEVEL_TIMER[] = +{ + IR_TA, IR_TB, IR_TC, IR_TD +}; + +// interrupt vectors +const UINT8 z80sti_device::INT_VECTOR[] = +{ + 0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e, + 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e +}; + +// timer prescaler divisors +const int z80sti_device::PRESCALER[] = { 0, 4, 10, 16, 50, 64, 100, 200 }; + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// z80sti_device - constructor +//------------------------------------------------- + +z80sti_device::z80sti_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, Z80STI, "Mostek MK3801", tag, owner, clock, "z80sti", __FILE__), + device_serial_interface(mconfig, *this), + device_z80daisy_interface(mconfig, *this), + m_out_int_cb(*this), + m_in_gpio_cb(*this), + m_out_gpio_cb(*this), + m_out_so_cb(*this), + m_out_tao_cb(*this), + m_out_tbo_cb(*this), + m_out_tco_cb(*this), + m_out_tdo_cb(*this), + m_rx_clock(0), + m_tx_clock(0), + m_gpip(0), + m_aer(0), + m_ier(0), + m_ipr(0), + m_isr(0), + m_imr(0) +{ + for (int i = 0; i < 16; i++) + { + m_int_state[i] = 0; + } +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void z80sti_device::device_start() +{ + // resolve callbacks + m_out_int_cb.resolve_safe(); + m_in_gpio_cb.resolve_safe(0); + m_out_gpio_cb.resolve_safe(); + m_out_so_cb.resolve_safe(); + m_out_tao_cb.resolve_safe(); + m_out_tbo_cb.resolve_safe(); + m_out_tco_cb.resolve_safe(); + m_out_tdo_cb.resolve_safe(); + + // create the counter timers + m_timer[TIMER_A] = timer_alloc(TIMER_A); + m_timer[TIMER_B] = timer_alloc(TIMER_B); + m_timer[TIMER_C] = timer_alloc(TIMER_C); + m_timer[TIMER_D] = timer_alloc(TIMER_D); + + // create serial receive clock timer + if (m_rx_clock > 0) + { + set_rcv_rate(m_rx_clock); + } + + // create serial transmit clock timer + if (m_tx_clock > 0) + { + set_tra_rate(m_tx_clock); + } + + // state saving + save_item(NAME(m_gpip)); + save_item(NAME(m_aer)); + save_item(NAME(m_ddr)); + save_item(NAME(m_ier)); + save_item(NAME(m_ipr)); + save_item(NAME(m_isr)); + save_item(NAME(m_imr)); + save_item(NAME(m_pvr)); + save_item(NAME(m_int_state)); + save_item(NAME(m_tabc)); + save_item(NAME(m_tcdc)); + save_item(NAME(m_tdr)); + save_item(NAME(m_tmc)); + save_item(NAME(m_to)); + save_item(NAME(m_scr)); + save_item(NAME(m_ucr)); + save_item(NAME(m_rsr)); + save_item(NAME(m_tsr)); + save_item(NAME(m_udr)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void z80sti_device::device_reset() +{ + memset(m_tmc, 0, sizeof(m_tmc)); + memset(m_to, 0, sizeof(m_to)); + + transmit_register_reset(); + receive_register_reset(); +} + + +//------------------------------------------------- +// device_timer - handler timer events +//------------------------------------------------- + +void z80sti_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + timer_count(id); +} + + +//------------------------------------------------- +// tra_callback - +//------------------------------------------------- + +void z80sti_device::tra_callback() +{ + m_out_so_cb(transmit_register_get_data_bit()); +} + + +//------------------------------------------------- +// tra_complete - +//------------------------------------------------- + +void z80sti_device::tra_complete() +{ + // TODO +} + + +//------------------------------------------------- +// rcv_complete - +//------------------------------------------------- + +void z80sti_device::rcv_complete() +{ + // TODO +} + + +//************************************************************************** +// DAISY CHAIN INTERFACE +//************************************************************************** + +//------------------------------------------------- +// z80daisy_irq_state - get interrupt status +//------------------------------------------------- + +int z80sti_device::z80daisy_irq_state() +{ + int state = 0, i; + + // loop over all interrupt sources + for (i = 15; i >= 0; i--) + { + // if we're servicing a request, don't indicate more interrupts + if (m_int_state[i] & Z80_DAISY_IEO) + { + state |= Z80_DAISY_IEO; + break; + } + + if (BIT(m_imr, i)) + { + state |= m_int_state[i]; + } + } + + LOG(("Z80STI '%s' Interrupt State: %u\n", tag(), state)); + + return state; +} + + +//------------------------------------------------- +// z80daisy_irq_ack - interrupt acknowledge +//------------------------------------------------- + +int z80sti_device::z80daisy_irq_ack() +{ + int i; + + // loop over all interrupt sources + for (i = 15; i >= 0; i--) + { + // find the first channel with an interrupt requested + if (m_int_state[i] & Z80_DAISY_INT) + { + UINT8 vector = (m_pvr & 0xe0) | INT_VECTOR[i]; + + // clear interrupt, switch to the IEO state, and update the IRQs + m_int_state[i] = Z80_DAISY_IEO; + + // clear interrupt pending register bit + m_ipr &= ~(1 << i); + + // set interrupt in-service register bit + m_isr |= (1 << i); + + check_interrupts(); + + LOG(("Z80STI '%s' Interrupt Acknowledge Vector: %02x\n", tag(), vector)); + + return vector; + } + } + + logerror("z80sti_irq_ack: failed to find an interrupt to ack!\n"); + + return 0; +} + + +//------------------------------------------------- +// z80daisy_irq_reti - return from interrupt +//------------------------------------------------- + +void z80sti_device::z80daisy_irq_reti() +{ + int i; + + LOG(("Z80STI '%s' Return from Interrupt\n", tag())); + + // loop over all interrupt sources + for (i = 15; i >= 0; i--) + { + // find the first channel with an IEO pending + if (m_int_state[i] & Z80_DAISY_IEO) + { + // clear the IEO state and update the IRQs + m_int_state[i] &= ~Z80_DAISY_IEO; + + // clear interrupt in-service register bit + m_isr &= ~(1 << i); + + check_interrupts(); + return; + } + } + + logerror("z80sti_irq_reti: failed to find an interrupt to clear IEO on!\n"); +} + + + +//************************************************************************** +// IMPLEMENTATION +//************************************************************************** + +//------------------------------------------------- +// check_interrupts - set the interrupt request +// line state +//------------------------------------------------- + +void z80sti_device::check_interrupts() +{ + if (m_ipr & m_imr) + { + m_out_int_cb(ASSERT_LINE); + } + else + { + m_out_int_cb(CLEAR_LINE); + } +} + + +//------------------------------------------------- +// take_interrupt - mark an interrupt pending +//------------------------------------------------- + +void z80sti_device::take_interrupt(int level) +{ + // set interrupt pending register bit + m_ipr |= 1 << level; + + // trigger interrupt + m_int_state[level] |= Z80_DAISY_INT; + + check_interrupts(); +} + + +//------------------------------------------------- +// read - register read +//------------------------------------------------- + +READ8_MEMBER( z80sti_device::read ) +{ + UINT8 data = 0; + + switch (offset & 0x0f) + { + case REGISTER_IR: + switch (m_pvr & 0x07) + { + case REGISTER_IR_SCR: data = m_scr; break; + case REGISTER_IR_TDDR: data = m_tmc[TIMER_D]; break; + case REGISTER_IR_TCDR: data = m_tmc[TIMER_C]; break; + case REGISTER_IR_AER: data = m_aer; break; + case REGISTER_IR_IERB: data = m_ier & 0xff; break; + case REGISTER_IR_IERA: data = m_ier >> 8; break; + case REGISTER_IR_DDR: data = m_ddr; break; + case REGISTER_IR_TCDC: data = m_tcdc; break; + } + break; + + case REGISTER_GPIP: m_gpip = (m_in_gpio_cb(0) & ~m_ddr) | (m_gpip & m_ddr); data = m_gpip; break; + case REGISTER_IPRB: data = m_ipr & 0xff; break; + case REGISTER_IPRA: data = m_ipr >> 8; break; + case REGISTER_ISRB: data = m_isr & 0xff; break; + case REGISTER_ISRA: data = m_isr >> 8; break; + case REGISTER_IMRB: data = m_imr & 0xff; break; + case REGISTER_IMRA: data = m_imr >> 8; break; + case REGISTER_PVR: data = m_pvr; break; + case REGISTER_TABC: data = m_tabc; break; + case REGISTER_TBDR: data = m_tmc[TIMER_B]; break; + case REGISTER_TADR: data = m_tmc[TIMER_A]; break; + case REGISTER_UCR: data = m_ucr; break; + case REGISTER_RSR: data = m_rsr; break; + case REGISTER_TSR: data = m_tsr; break; + case REGISTER_UDR: data = m_udr; break; + } + + return data; +} + + +//------------------------------------------------- +// write - register write +//------------------------------------------------- + +WRITE8_MEMBER( z80sti_device::write ) +{ + switch (offset & 0x0f) + { + case REGISTER_IR: + switch (m_pvr & 0x07) + { + case REGISTER_IR_SCR: + LOG(("Z80STI '%s' Sync Character Register: %x\n", tag(), data)); + m_scr = data; + break; + + case REGISTER_IR_TDDR: + LOG(("Z80STI '%s' Timer D Data Register: %x\n", tag(), data)); + m_tdr[TIMER_D] = data; + break; + + case REGISTER_IR_TCDR: + LOG(("Z80STI '%s' Timer C Data Register: %x\n", tag(), data)); + m_tdr[TIMER_C] = data; + break; + + case REGISTER_IR_AER: + LOG(("Z80STI '%s' Active Edge Register: %x\n", tag(), data)); + m_aer = data; + break; + + case REGISTER_IR_IERB: + LOG(("Z80STI '%s' Interrupt Enable Register B: %x\n", tag(), data)); + m_ier = (m_ier & 0xff00) | data; + check_interrupts(); + break; + + case REGISTER_IR_IERA: + LOG(("Z80STI '%s' Interrupt Enable Register A: %x\n", tag(), data)); + m_ier = (data << 8) | (m_ier & 0xff); + check_interrupts(); + break; + + case REGISTER_IR_DDR: + LOG(("Z80STI '%s' Data Direction Register: %x\n", tag(), data)); + m_ddr = data; + break; + + case REGISTER_IR_TCDC: + { + int tcc = PRESCALER[(data >> 4) & 0x07]; + int tdc = PRESCALER[data & 0x07]; + + m_tcdc = data; + + LOG(("Z80STI '%s' Timer C Prescaler: %u\n", tag(), tcc)); + LOG(("Z80STI '%s' Timer D Prescaler: %u\n", tag(), tdc)); + + if (tcc) + m_timer[TIMER_C]->adjust(attotime::from_hz(clock() / tcc), TIMER_C, attotime::from_hz(clock() / tcc)); + else + m_timer[TIMER_C]->enable(false); + + if (tdc) + m_timer[TIMER_D]->adjust(attotime::from_hz(clock() / tdc), TIMER_D, attotime::from_hz(clock() / tdc)); + else + m_timer[TIMER_D]->enable(false); + + if (BIT(data, 7)) + { + LOG(("Z80STI '%s' Timer A Reset\n", tag())); + m_to[TIMER_A] = 0; + + m_out_tao_cb(m_to[TIMER_A]); + } + + if (BIT(data, 3)) + { + LOG(("Z80STI '%s' Timer B Reset\n", tag())); + m_to[TIMER_B] = 0; + + m_out_tbo_cb(m_to[TIMER_B]); + } + } + break; + } + break; + + case REGISTER_GPIP: + LOG(("Z80STI '%s' General Purpose I/O Register: %x\n", tag(), data)); + m_gpip = data & m_ddr; + m_out_gpio_cb((offs_t)0, m_gpip); + break; + + case REGISTER_IPRB: + { + int i; + LOG(("Z80STI '%s' Interrupt Pending Register B: %x\n", tag(), data)); + m_ipr &= (m_ipr & 0xff00) | data; + + for (i = 0; i < 16; i++) + { + if (!BIT(m_ipr, i) && (m_int_state[i] == Z80_DAISY_INT)) m_int_state[i] = 0; + } + + check_interrupts(); + } + break; + + case REGISTER_IPRA: + { + int i; + LOG(("Z80STI '%s' Interrupt Pending Register A: %x\n", tag(), data)); + m_ipr &= (data << 8) | (m_ipr & 0xff); + + for (i = 0; i < 16; i++) + { + if (!BIT(m_ipr, i) && (m_int_state[i] == Z80_DAISY_INT)) m_int_state[i] = 0; + } + + check_interrupts(); + } + break; + + case REGISTER_ISRB: + LOG(("Z80STI '%s' Interrupt In-Service Register B: %x\n", tag(), data)); + m_isr &= (m_isr & 0xff00) | data; + break; + + case REGISTER_ISRA: + LOG(("Z80STI '%s' Interrupt In-Service Register A: %x\n", tag(), data)); + m_isr &= (data << 8) | (m_isr & 0xff); + break; + + case REGISTER_IMRB: + LOG(("Z80STI '%s' Interrupt Mask Register B: %x\n", tag(), data)); + m_imr = (m_imr & 0xff00) | data; + m_isr &= m_imr; + check_interrupts(); + break; + + case REGISTER_IMRA: + LOG(("Z80STI '%s' Interrupt Mask Register A: %x\n", tag(), data)); + m_imr = (data << 8) | (m_imr & 0xff); + m_isr &= m_imr; + check_interrupts(); + break; + + case REGISTER_PVR: + LOG(("Z80STI '%s' Interrupt Vector: %02x\n", tag(), data & 0xe0)); + LOG(("Z80STI '%s' IR Address: %01x\n", tag(), data & 0x07)); + m_pvr = data; + break; + + case REGISTER_TABC: + { + int tac = PRESCALER[(data >> 4) & 0x07]; + int tbc = PRESCALER[data & 0x07]; + + m_tabc = data; + + LOG(("Z80STI '%s' Timer A Prescaler: %u\n", tag(), tac)); + LOG(("Z80STI '%s' Timer B Prescaler: %u\n", tag(), tbc)); + + if (tac) + m_timer[TIMER_A]->adjust(attotime::from_hz(clock() / tac), TIMER_A, attotime::from_hz(clock() / tac)); + else + m_timer[TIMER_A]->enable(false); + + if (tbc) + m_timer[TIMER_B]->adjust(attotime::from_hz(clock() / tbc), TIMER_B, attotime::from_hz(clock() / tbc)); + else + m_timer[TIMER_B]->enable(false); + } + break; + + case REGISTER_TBDR: + LOG(("Z80STI '%s' Timer B Data Register: %x\n", tag(), data)); + m_tdr[TIMER_B] = data; + break; + + case REGISTER_TADR: + LOG(("Z80STI '%s' Timer A Data Register: %x\n", tag(), data)); + m_tdr[TIMER_A] = data; + break; + + case REGISTER_UCR: + LOG(("Z80STI '%s' USART Control Register: %x\n", tag(), data)); + m_ucr = data; + break; + + case REGISTER_RSR: + LOG(("Z80STI '%s' Receiver Status Register: %x\n", tag(), data)); + m_rsr = data; + break; + + case REGISTER_TSR: + LOG(("Z80STI '%s' Transmitter Status Register: %x\n", tag(), data)); + m_tsr = data; + break; + + case REGISTER_UDR: + LOG(("Z80STI '%s' USART Data Register: %x\n", tag(), data)); + m_udr = data; + break; + } +} + + +//------------------------------------------------- +// timer_count - timer count down +//------------------------------------------------- + +void z80sti_device::timer_count(int index) +{ + if (m_tmc[index] == 0x01) + { + //LOG(("Z80STI '%s' Timer %c Expired\n", tag(), 'A' + index)); + + // toggle timer output signal + m_to[index] = !m_to[index]; + + switch (index) + { + case TIMER_A: + m_out_tao_cb(m_to[index]); + break; + case TIMER_B: + m_out_tbo_cb(m_to[index]); + break; + case TIMER_C: + m_out_tco_cb(m_to[index]); + break; + case TIMER_D: + m_out_tdo_cb(m_to[index]); + break; + } + + if (m_ier & (1 << INT_LEVEL_TIMER[index])) + { + LOG(("Z80STI '%s' Interrupt Pending for Timer %c\n", tag(), 'A' + index)); + + // signal timer elapsed interrupt + take_interrupt(INT_LEVEL_TIMER[index]); + } + + // load timer main counter + m_tmc[index] = m_tdr[index]; + } + else + { + // count down + m_tmc[index]--; + } +} + + +//------------------------------------------------- +// gpip_input - GPIP input line write +//------------------------------------------------- + +void z80sti_device::gpip_input(int bit, int state) +{ + int aer = BIT(m_aer, bit); + int old_state = BIT(m_gpip, bit); + + if ((old_state ^ aer) && !(state ^ aer)) + { + LOG(("Z80STI '%s' Edge Transition Detected on Bit: %u\n", tag(), bit)); + + if (m_ier & (1 << INT_LEVEL_GPIP[bit])) + { + LOG(("Z80STI '%s' Interrupt Pending for P%u\n", tag(), bit)); + + take_interrupt(INT_LEVEL_GPIP[bit]); + } + } + + m_gpip = (m_gpip & ~(1 << bit)) | (state << bit); +} + +WRITE_LINE_MEMBER( z80sti_device::i0_w ) { gpip_input(0, state); } +WRITE_LINE_MEMBER( z80sti_device::i1_w ) { gpip_input(1, state); } +WRITE_LINE_MEMBER( z80sti_device::i2_w ) { gpip_input(2, state); } +WRITE_LINE_MEMBER( z80sti_device::i3_w ) { gpip_input(3, state); } +WRITE_LINE_MEMBER( z80sti_device::i4_w ) { gpip_input(4, state); } +WRITE_LINE_MEMBER( z80sti_device::i5_w ) { gpip_input(5, state); } +WRITE_LINE_MEMBER( z80sti_device::i6_w ) { gpip_input(6, state); } +WRITE_LINE_MEMBER( z80sti_device::i7_w ) { gpip_input(7, state); } + + +//------------------------------------------------- +// rc_w - receiver clock +//------------------------------------------------- + +WRITE_LINE_MEMBER( z80sti_device::rc_w ) +{ + rx_clock_w(state); +} + + +//------------------------------------------------- +// tc_w - transmitter clock +//------------------------------------------------- + +WRITE_LINE_MEMBER( z80sti_device::tc_w ) +{ + tx_clock_w(state); +} diff --git a/src/devices/machine/z80sti.h b/src/devices/machine/z80sti.h new file mode 100644 index 00000000000..1691695147c --- /dev/null +++ b/src/devices/machine/z80sti.h @@ -0,0 +1,250 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Mostek MK3801 Serial Timer Interrupt Controller (Z80-STI) emulation + +********************************************************************** + _____ _____ + TAO 1 |* \_/ | 40 Vcc + TBO 2 | | 39 RC + TCO 3 | | 38 SI + TDO 4 | | 37 SO + TCK 5 | | 36 TC + _M1 6 | | 35 A0 + _RES 7 | | 34 A1 + I0 8 | | 33 A2 + I1 9 | | 32 A3 + I2 10 | MK3801 | 31 _WR + I3 11 | Z80-STI | 30 _CE + I4 12 | | 29 _RD + I5 13 | | 28 D7 + I6 14 | | 27 D6 + I7 15 | | 26 D5 + IEI 16 | | 25 D4 + _INT 17 | | 24 D3 + IEO 18 | | 23 D2 + _IORQ 19 | | 22 D1 + Vss 20 |_____________| 21 D0 + +**********************************************************************/ + +#ifndef __Z80STI__ +#define __Z80STI__ + +#include "cpu/z80/z80daisy.h" + + +//************************************************************************** +// DEVICE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_Z80STI_RXCLOCK(_clock) \ + z80sti_device::set_rx_clock(*device, _clock); + +#define MCFG_Z80STI_TXCLOCK(_clock) \ + z80sti_device::set_tx_clock(*device, _clock); + +#define MCFG_Z80STI_OUT_INT_CB(_devcb) \ + devcb = &z80sti_device::set_out_int_callback(*device, DEVCB_##_devcb); + +#define MCFG_Z80STI_IN_GPIO_CB(_devcb) \ + devcb = &z80sti_device::set_in_gpio_callback(*device, DEVCB_##_devcb); + +#define MCFG_Z80STI_OUT_GPIO_CB(_devcb) \ + devcb = &z80sti_device::set_out_gpio_callback(*device, DEVCB_##_devcb); + +#define MCFG_Z80STI_OUT_SO_CB(_devcb) \ + devcb = &z80sti_device::set_out_so_callback(*device, DEVCB_##_devcb); + +#define MCFG_Z80STI_OUT_TAO_CB(_devcb) \ + devcb = &z80sti_device::set_out_tao_callback(*device, DEVCB_##_devcb); + +#define MCFG_Z80STI_OUT_TBO_CB(_devcb) \ + devcb = &z80sti_device::set_out_tbo_callback(*device, DEVCB_##_devcb); + +#define MCFG_Z80STI_OUT_TCO_CB(_devcb) \ + devcb = &z80sti_device::set_out_tco_callback(*device, DEVCB_##_devcb); + +#define MCFG_Z80STI_OUT_TDO_CB(_devcb) \ + devcb = &z80sti_device::set_out_tdo_callback(*device, DEVCB_##_devcb); + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> z80sti_device + +class z80sti_device : public device_t, + public device_serial_interface, + public device_z80daisy_interface +{ +public: + // construction/destruction + z80sti_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + template static devcb_base &set_out_int_callback(device_t &device, _Object object) { return downcast(device).m_out_int_cb.set_callback(object); } + template static devcb_base &set_in_gpio_callback(device_t &device, _Object object) { return downcast(device).m_in_gpio_cb.set_callback(object); } + template static devcb_base &set_out_gpio_callback(device_t &device, _Object object) { return downcast(device).m_out_gpio_cb.set_callback(object); } + template static devcb_base &set_out_so_callback(device_t &device, _Object object) { return downcast(device).m_out_so_cb.set_callback(object); } + template static devcb_base &set_out_tao_callback(device_t &device, _Object object) { return downcast(device).m_out_tao_cb.set_callback(object); } + template static devcb_base &set_out_tbo_callback(device_t &device, _Object object) { return downcast(device).m_out_tbo_cb.set_callback(object); } + template static devcb_base &set_out_tco_callback(device_t &device, _Object object) { return downcast(device).m_out_tco_cb.set_callback(object); } + template static devcb_base &set_out_tdo_callback(device_t &device, _Object object) { return downcast(device).m_out_tdo_cb.set_callback(object); } + + static void set_rx_clock(device_t &device, int clock) { downcast(device).m_rx_clock = clock; } + static void set_tx_clock(device_t &device, int clock) { downcast(device).m_tx_clock = clock; } + + DECLARE_READ8_MEMBER( read ); + DECLARE_WRITE8_MEMBER( write ); + + DECLARE_WRITE_LINE_MEMBER( i0_w ); + DECLARE_WRITE_LINE_MEMBER( i1_w ); + DECLARE_WRITE_LINE_MEMBER( i2_w ); + DECLARE_WRITE_LINE_MEMBER( i3_w ); + DECLARE_WRITE_LINE_MEMBER( i4_w ); + DECLARE_WRITE_LINE_MEMBER( i5_w ); + DECLARE_WRITE_LINE_MEMBER( i6_w ); + DECLARE_WRITE_LINE_MEMBER( i7_w ); + + DECLARE_WRITE_LINE_MEMBER( tc_w ); + DECLARE_WRITE_LINE_MEMBER( rc_w ); + +private: + enum + { + TIMER_A = 0, + TIMER_B, + TIMER_C, + TIMER_D + }; + + enum + { + REGISTER_IR = 0, + REGISTER_GPIP, + REGISTER_IPRB, + REGISTER_IPRA, + REGISTER_ISRB, + REGISTER_ISRA, + REGISTER_IMRB, + REGISTER_IMRA, + REGISTER_PVR, + REGISTER_TABC, + REGISTER_TBDR, + REGISTER_TADR, + REGISTER_UCR, + REGISTER_RSR, + REGISTER_TSR, + REGISTER_UDR + }; + + enum + { + REGISTER_IR_SCR = 0, + REGISTER_IR_TDDR, + REGISTER_IR_TCDR, + REGISTER_IR_AER, + REGISTER_IR_IERB, + REGISTER_IR_IERA, + REGISTER_IR_DDR, + REGISTER_IR_TCDC + }; + + enum + { + IR_P0 = 0, + IR_P1, + IR_P2, + IR_P3, + IR_TD, + IR_TC, + IR_P4, + IR_P5, + IR_TB, + IR_XE, + IR_XB, + IR_RE, + IR_RB, + IR_TA, + IR_P6, + IR_P7 + }; + + static const int INT_LEVEL_GPIP[]; + static const int INT_LEVEL_TIMER[]; + static const UINT8 INT_VECTOR[]; + static const int PRESCALER[]; + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + // device_serial_interface overrides + virtual void tra_callback(); + virtual void tra_complete(); + virtual void rcv_complete(); + + // device_z80daisy_interface overrides + virtual int z80daisy_irq_state(); + virtual int z80daisy_irq_ack(); + virtual void z80daisy_irq_reti(); + + // internal helpers + void check_interrupts(); + void take_interrupt(int level); + void timer_count(int index); + void gpip_input(int bit, int state); + + // device callbacks + devcb_write_line m_out_int_cb; // this gets called on each change of the _INT pin (pin 17) + devcb_read8 m_in_gpio_cb; // this is called on each read of the GPIO pins + devcb_write8 m_out_gpio_cb; // this is called on each write of the GPIO pins + devcb_write_line m_out_so_cb; // this gets called for each change of the SO pin (pin 37) + devcb_write_line m_out_tao_cb; // this gets called for each change of the TAO pin (pin 1) + devcb_write_line m_out_tbo_cb; // this gets called for each change of the TBO pin (pin 2) + devcb_write_line m_out_tco_cb; // this gets called for each change of the TCO pin (pin 3) + devcb_write_line m_out_tdo_cb; // this gets called for each change of the TDO pin (pin 4) + + int m_rx_clock; // serial receive clock + int m_tx_clock; // serial transmit clock + + // I/O state + UINT8 m_gpip; // general purpose I/O register + UINT8 m_aer; // active edge register + UINT8 m_ddr; // data direction register + + // interrupt state + UINT16 m_ier; // interrupt enable register + UINT16 m_ipr; // interrupt pending register + UINT16 m_isr; // interrupt in-service register + UINT16 m_imr; // interrupt mask register + UINT8 m_pvr; // interrupt vector register + int m_int_state[16]; // interrupt state + + // timer state + UINT8 m_tabc; // timer A/B control register + UINT8 m_tcdc; // timer C/D control register + UINT8 m_tdr[4]; // timer data registers + UINT8 m_tmc[4]; // timer main counters + int m_to[4]; // timer out latch + + // serial state + UINT8 m_scr; // synchronous character register + UINT8 m_ucr; // USART control register + UINT8 m_tsr; // transmitter status register + UINT8 m_rsr; // receiver status register + UINT8 m_udr; // USART data register + + // timers + emu_timer *m_timer[4]; // counter timers +}; + + +// device type definition +extern const device_type Z80STI; + + + +#endif diff --git a/src/devices/machine/z8536.c b/src/devices/machine/z8536.c new file mode 100644 index 00000000000..fc5e770b15a --- /dev/null +++ b/src/devices/machine/z8536.c @@ -0,0 +1,1123 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Zilog Z8536 Counter/Timer and Parallel I/O emulation + +**********************************************************************/ + +/* + + TODO: + + - interrupts + - vector + - status affects vector + - IE/IP/IUS + - acknowledge + - daisy chain + - port I/O + - counters/timers + +*/ + +#include "emu.h" +#include "z8536.h" + + +// device type definition +const device_type Z8536 = &device_creator; + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define LOG 0 + + +static const char *PMS_PTS[] = { "Bit", "Input", "Output", "Bidirectional" }; +static const char *PMS_PMS[] = { "Disabled", "AND", "OR", "OR-PEV" }; +static const char *CTMS_DCS[] = { "Pulse", "One-shot", "Square Wave", "Do not use" }; + + +// master interrupt control register +#define MICR_RESET 0x01 // reset +#define MICR_RJA 0x02 // right justified address +#define MICR_CT_VIS 0x04 // counter/timer vector includes status +#define MICR_PB_VIS 0x08 // port B vector includes status +#define MICR_PA_VIS 0x10 // port A vector includes status +#define MICR_NV 0x20 // no vector +#define MICR_DLC 0x40 // disable lower chain +#define MICR_MIE 0x80 // master interrupt enable + + +// master configuration control register +#define MCCR_LC_MASK 0x03 // counter/timer link controls +#define MCCR_PAE 0x04 // port A enable +#define MCCR_PLC 0x08 // port link control +#define MCCR_PCE_CT3E 0x10 // port C and counter/timer 3 enable +#define MCCR_CT2E 0x20 // counter/timer 2 enable +#define MCCR_CT1E 0x40 // counter/timer 1 enable +#define MCCR_PBE 0x80 // port B enable + + +// port mode specification registers +#define PMS_LPM 0x01 // latch on pattern match +#define PMS_DTE 0x01 // deskew timer enable +#define PMS_PMS_MASK 0x06 // pattern mode specification +#define PMS_IMO 0x08 // interrupt on match only +#define PMS_SB 0x10 // single buffer +#define PMS_ITB 0x20 // interrupt on two bytes +#define PMS_PTS_MASK 0xc0 // port type select + + +// port handshake specification registers +#define PHS_DTS_MASK 0x07 // deskew time specification +#define PHS_RWS_MASK 0x38 // request/wait specification +#define PHS_HTS_MASK 0xc0 // handshake type specification + + +// port command and status registers +#define PCS_IOE 0x01 // interrupt on error +#define PCS_PMF 0x02 // pattern match flag (read only) +#define PCS_IRF 0x04 // input register full (read only) +#define PCS_ORE 0x08 // output register empty (read only) +#define PCS_ERR 0x10 // interrupt error (read only) +#define PCS_IP 0x20 // interrupt pending +#define PCS_IE 0x40 // interrupt enable +#define PCS_IUS 0x80 // interrupt under service + + +// counter/timer mode specification registers +#define CTMS_DCS_MASK 0x03 // output duty cycle +#define CTMS_REB 0x04 // retrigger enable bit +#define CTMS_EDE 0x08 // external gate enable +#define CTMS_ETE 0x10 // external trigger enable +#define CTMS_ECE 0x20 // external count enable +#define CTMS_EOE 0x40 // external output enable +#define CTMS_CSC 0x80 // continuous/single cycle + + +// counter/timer command and status registers +#define CTCS_CIP 0x01 // count in progress (read only) +#define CTCS_TCB 0x02 // trigger command bit (write only - read returns 0) +#define CTCS_GCB 0x04 // gate command bit +#define CTCS_RCC 0x08 // read counter control (read/set only - cleared by reading CCR LSB) +#define CTCS_ERR 0x10 // interrupt error (read only) +#define CTCS_IP 0x20 // interrupt pending +#define CTCS_IE 0x40 // interrupt enable +#define CTCS_IUS 0x80 // interrupt under service + + + +//************************************************************************** +// INLINE HELPERS +//************************************************************************** + +//------------------------------------------------- +// get_interrupt_vector - +//------------------------------------------------- + +void z8536_device::get_interrupt_vector() +{ + UINT8 vector = 0xff; + + if (m_register[MASTER_INTERRUPT_CONTROL] & MICR_MIE) + { + if ((m_register[COUNTER_TIMER_3_COMMAND_AND_STATUS] & (CTCS_IP | CTCS_IE | CTCS_IUS)) == (CTCS_IP | CTCS_IE)) + { + vector = m_register[COUNTER_TIMER_INTERRUPT_VECTOR]; + + if (m_register[MASTER_INTERRUPT_CONTROL] & MICR_CT_VIS) + { + vector = (vector & 0xf9) | 0; + } + } + else if ((m_register[PORT_A_COMMAND_AND_STATUS] & (PCS_IP | PCS_IE | PCS_IUS)) == (PCS_IP | PCS_IE)) + { + vector = m_register[PORT_A_INTERRUPT_VECTOR]; + + if (m_register[MASTER_INTERRUPT_CONTROL] & MICR_PA_VIS) + { + vector &= 0xf1; + + if (((m_register[PORT_A_MODE_SPECIFICATION] & PMS_PMS_MASK) >> 1) == PMS_OR_PEV) + { + if (m_match[PORT_A] & 0x80) vector |= 7 << 1; + else if (m_match[PORT_A] & 0x40) vector |= 6 << 1; + else if (m_match[PORT_A] & 0x20) vector |= 5 << 1; + else if (m_match[PORT_A] & 0x10) vector |= 4 << 1; + else if (m_match[PORT_A] & 0x08) vector |= 3 << 1; + else if (m_match[PORT_A] & 0x04) vector |= 2 << 1; + else if (m_match[PORT_A] & 0x02) vector |= 1 << 1; + else if (m_match[PORT_A] & 0x01) vector |= 0 << 1; + } + else + { + vector |= (m_register[PORT_A_COMMAND_AND_STATUS] & 0x0e); + } + } + } + else if ((m_register[COUNTER_TIMER_2_COMMAND_AND_STATUS] & (CTCS_IP | CTCS_IE | CTCS_IUS)) == (CTCS_IP | CTCS_IE)) + { + vector = m_register[COUNTER_TIMER_INTERRUPT_VECTOR]; + + if (m_register[MASTER_INTERRUPT_CONTROL] & MICR_CT_VIS) + { + vector = (vector & 0xf9) | 2; + } + } + else if ((m_register[PORT_B_COMMAND_AND_STATUS] & (PCS_IP | PCS_IE | PCS_IUS)) == (PCS_IP | PCS_IE)) + { + vector = m_register[PORT_B_INTERRUPT_VECTOR]; + + if (m_register[MASTER_INTERRUPT_CONTROL] & MICR_PB_VIS) + { + vector &= 0xf1; + + if (((m_register[PORT_B_MODE_SPECIFICATION] & PMS_PMS_MASK) >> 1) == PMS_OR_PEV) + { + if (m_match[PORT_B] & 0x80) vector |= 7 << 1; + else if (m_match[PORT_B] & 0x40) vector |= 6 << 1; + else if (m_match[PORT_B] & 0x20) vector |= 5 << 1; + else if (m_match[PORT_B] & 0x10) vector |= 4 << 1; + else if (m_match[PORT_B] & 0x08) vector |= 3 << 1; + else if (m_match[PORT_B] & 0x04) vector |= 2 << 1; + else if (m_match[PORT_B] & 0x02) vector |= 1 << 1; + else if (m_match[PORT_B] & 0x01) vector |= 0 << 1; + } + else + { + vector |= (m_register[PORT_B_COMMAND_AND_STATUS] & 0x0e); + } + } + } + else if ((m_register[COUNTER_TIMER_1_COMMAND_AND_STATUS] & (CTCS_IP | CTCS_IE | CTCS_IUS)) == (CTCS_IP | CTCS_IE)) + { + vector = m_register[COUNTER_TIMER_INTERRUPT_VECTOR]; + + if (m_register[MASTER_INTERRUPT_CONTROL] & MICR_CT_VIS) + { + vector = (vector & 0xf9) | 4; + } + } + } + + m_register[CURRENT_VECTOR] = vector; +} + + +//------------------------------------------------- +// check_interrupt - check interrupt status +//------------------------------------------------- + +void z8536_device::check_interrupt() +{ + int state = ASSERT_LINE; + + if (m_register[MASTER_INTERRUPT_CONTROL] & MICR_MIE) + { + if (((m_register[COUNTER_TIMER_3_COMMAND_AND_STATUS] & (CTCS_IP | CTCS_IE | CTCS_IUS)) == (CTCS_IP | CTCS_IE)) || + ((m_register[PORT_A_COMMAND_AND_STATUS] & (PCS_IP | PCS_IE | PCS_IUS)) == (PCS_IP | PCS_IE)) || + ((m_register[COUNTER_TIMER_2_COMMAND_AND_STATUS] & (CTCS_IP | CTCS_IE | CTCS_IUS)) == (CTCS_IP | CTCS_IE)) || + ((m_register[PORT_B_COMMAND_AND_STATUS] & (PCS_IP | PCS_IE | PCS_IUS)) == (PCS_IP | PCS_IE)) || + ((m_register[COUNTER_TIMER_1_COMMAND_AND_STATUS] & (CTCS_IP | CTCS_IE | CTCS_IUS)) == (CTCS_IP | CTCS_IE))) + { + state = ASSERT_LINE; + } + else + { + state = CLEAR_LINE; + } + } + else + { + state = CLEAR_LINE; + } + + if (m_irq != state) + { + if (LOG) logerror("%s Z8536 '%s' Interrupt: %u\n", machine().describe_context(), tag(), state); + m_irq = state; + m_write_irq(state); + } +} + + +//------------------------------------------------- +// read_register - read from register +//------------------------------------------------- + +UINT8 z8536_device::read_register(offs_t offset) +{ + UINT8 data = 0; + + switch (offset) + { + case PORT_A_DATA: + data = m_read_pa(0); + break; + + case PORT_B_DATA: + data = m_read_pb(0); + break; + + case PORT_C_DATA: + data = 0xf0 | (m_read_pc(0) & 0x0f); + break; + + case COUNTER_TIMER_1_CURRENT_COUNT_MS_BYTE: + case COUNTER_TIMER_2_CURRENT_COUNT_MS_BYTE: + case COUNTER_TIMER_3_CURRENT_COUNT_MS_BYTE: + { + int timer = (offset - COUNTER_TIMER_1_CURRENT_COUNT_MS_BYTE) >> 1; + + if (m_register[COUNTER_TIMER_1_COMMAND_AND_STATUS + timer] & CTCS_RCC) + { + // read frozen value + data = m_register[offset]; + } + else + { + // read current count + data = m_counter[timer] >> 8; + } + } + break; + + case COUNTER_TIMER_1_CURRENT_COUNT_LS_BYTE: + case COUNTER_TIMER_2_CURRENT_COUNT_LS_BYTE: + case COUNTER_TIMER_3_CURRENT_COUNT_LS_BYTE: + { + int timer = (offset - COUNTER_TIMER_1_CURRENT_COUNT_MS_BYTE) >> 1; + + if (m_register[COUNTER_TIMER_1_COMMAND_AND_STATUS + timer] & CTCS_RCC) + { + // read frozen value + data = m_register[offset]; + } + else + { + // read current count + data = m_counter[timer] & 0xff; + } + + // clear RCC bit + m_register[COUNTER_TIMER_1_COMMAND_AND_STATUS + timer] &= ~CTCS_RCC; + } + break; + + case CURRENT_VECTOR: + get_interrupt_vector(); + data = m_register[offset]; + break; + + default: + data = m_register[offset]; + break; + } + + return data; +} + + +//------------------------------------------------- +// read_register - masked read from register +//------------------------------------------------- + +UINT8 z8536_device::read_register(offs_t offset, UINT8 mask) +{ + return read_register(offset) & mask; +} + + +//------------------------------------------------- +// write_register - write to register +//------------------------------------------------- + +void z8536_device::write_register(offs_t offset, UINT8 data) +{ + switch (offset) + { + case MASTER_INTERRUPT_CONTROL: + if (data & MICR_RESET) + { + if (LOG) logerror("%s Z8536 '%s' Reset\n", machine().describe_context(), tag()); + device_reset(); + } + else + { + if (m_state == STATE_RESET) + { + m_state = STATE_0; + } + + if (LOG) + { + if (LOG) logerror("%s Z8536 '%s' Master Interrupt Enable: %u\n", machine().describe_context(), tag(), (data & MICR_MIE) ? 1 : 0); + if (LOG) logerror("%s Z8536 '%s' Disable Lower Chain: %u\n", machine().describe_context(), tag(), (data & MICR_DLC) ? 1 : 0); + if (LOG) logerror("%s Z8536 '%s' No Vector: %u\n", machine().describe_context(), tag(), (data & MICR_NV) ? 1 : 0); + if (LOG) logerror("%s Z8536 '%s' Port A Vector Includes Status: %u\n", machine().describe_context(), tag(), (data & MICR_PA_VIS) ? 1 : 0); + if (LOG) logerror("%s Z8536 '%s' Port B Vector Includes Status: %u\n", machine().describe_context(), tag(), (data & MICR_PB_VIS) ? 1 : 0); + if (LOG) logerror("%s Z8536 '%s' Counter/Timer Vector Includes Status: %u\n", machine().describe_context(), tag(), (data & MICR_CT_VIS) ? 1 : 0); + if (LOG) logerror("%s Z8536 '%s' Right Justified Address: %u\n", machine().describe_context(), tag(), (data & MICR_RJA) ? 1 : 0); + } + + m_register[offset] = data; + } + break; + + case MASTER_CONFIGURATION_CONTROL: + if (LOG) + { + if (LOG) logerror("%s Z8536 '%s' Port B Enable: %u\n", machine().describe_context(), tag(), (data & MCCR_PBE) ? 1 : 0); + if (LOG) logerror("%s Z8536 '%s' Counter/Timer 1 Enable: %u\n", machine().describe_context(), tag(), (data & MCCR_CT1E) ? 1 : 0); + if (LOG) logerror("%s Z8536 '%s' Counter/Timer 2 Enable: %u\n", machine().describe_context(), tag(), (data & MCCR_CT2E) ? 1 : 0); + if (LOG) logerror("%s Z8536 '%s' Port C and Counter/Timer 3 Enable: %u\n", machine().describe_context(), tag(), (data & MCCR_PCE_CT3E) ? 1 : 0); + if (LOG) logerror("%s Z8536 '%s' Port A Enable: %u\n", machine().describe_context(), tag(), (data & MCCR_PAE) ? 1 : 0); + if (LOG) logerror("%s Z8536 '%s' Port Link Control: %u\n", machine().describe_context(), tag(), (data & MCCR_PLC) ? 1 : 0); + if (LOG) logerror("%s Z8536 '%s' Counter/Timer Link Controls: %u\n", machine().describe_context(), tag(), data & MCCR_LC_MASK); + } + + m_register[offset] = data; + + for (int counter = 0; counter < 3; counter++) + { + // clear RCC bit if counter disabled + if (!counter_enabled(counter)) m_register[COUNTER_TIMER_1_COMMAND_AND_STATUS + counter] &= ~CTCS_RCC; + } + break; + + case PORT_A_INTERRUPT_VECTOR: + if (LOG) logerror("%s Z8536 '%s' Port A Interrupt Vector: %02x\n", machine().describe_context(), tag(), data); + m_register[offset] = data; + break; + + case PORT_B_INTERRUPT_VECTOR: + if (LOG) logerror("%s Z8536 '%s' Port B Interrupt Vector: %02x\n", machine().describe_context(), tag(), data); + m_register[offset] = data; + break; + + case COUNTER_TIMER_INTERRUPT_VECTOR: + if (LOG) logerror("%s Z8536 '%s' Counter/Timer Interrupt Vector: %02x\n", machine().describe_context(), tag(), data); + m_register[offset] = data; + break; + + case PORT_C_DATA_PATH_POLARITY: + if (LOG) logerror("%s Z8536 '%s' Port C Data Path Polarity: %02x\n", machine().describe_context(), tag(), data); + m_register[offset] = data; + break; + + case PORT_C_DATA_DIRECTION: + if (LOG) logerror("%s Z8536 '%s' Port C Data Direction: %02x\n", machine().describe_context(), tag(), data); + m_register[offset] = data; + break; + + case PORT_C_SPECIAL_IO_CONTROL: + if (LOG) logerror("%s Z8536 '%s' Port C Special I/O Control: %02x\n", machine().describe_context(), tag(), data); + m_register[offset] = data; + break; + + case PORT_A_COMMAND_AND_STATUS: + case PORT_B_COMMAND_AND_STATUS: + { + char port = 'A' + offset - PORT_A_COMMAND_AND_STATUS; + + if (LOG) logerror("%s Z8536 '%s' Port %c Interrupt on Error: %u\n", machine().describe_context(), tag(), port, (data & PCS_IOE) ? 1 : 0); + + switch (data >> 5) + { + case IC_CLEAR_IP_IUS: m_register[offset] &= ~(PCS_IP | PCS_IUS); if (LOG) logerror("%s Z8536 '%s' Port %c Clear IP/IUS\n", machine().describe_context(), tag(), port); break; + case IC_SET_IUS: m_register[offset] |= PCS_IUS; if (LOG) logerror("%s Z8536 '%s' Port %c Set IUS\n", machine().describe_context(), tag(), port); break; + case IC_CLEAR_IUS: m_register[offset] &= ~PCS_IUS; if (LOG) logerror("%s Z8536 '%s' Port %c Clear IUS\n", machine().describe_context(), tag(), port); break; + case IC_SET_IP: m_register[offset] |= PCS_IP; if (LOG) logerror("%s Z8536 '%s' Port %c Set IP\n", machine().describe_context(), tag(), port); break; + case IC_CLEAR_IP: m_register[offset] &= ~PCS_IP; if (LOG) logerror("%s Z8536 '%s' Port %c Clear IP\n", machine().describe_context(), tag(), port); break; + case IC_SET_IE: m_register[offset] |= PCS_IE; if (LOG) logerror("%s Z8536 '%s' Port %c Set IE\n", machine().describe_context(), tag(), port); break; + case IC_CLEAR_IE: m_register[offset] &= ~PCS_IE; if (LOG) logerror("%s Z8536 '%s' Port %c Clear IE\n", machine().describe_context(), tag(), port); break; + } + + m_register[offset] = (m_register[offset] & ~PCS_IOE) | (data & PCS_IOE); + + match_pattern(offset - PORT_A_COMMAND_AND_STATUS); + check_interrupt(); + } + break; + + case COUNTER_TIMER_1_COMMAND_AND_STATUS: + case COUNTER_TIMER_2_COMMAND_AND_STATUS: + case COUNTER_TIMER_3_COMMAND_AND_STATUS: + { + int counter = offset - COUNTER_TIMER_1_COMMAND_AND_STATUS; + + if (LOG) + { + if (LOG) logerror("%s Z8536 '%s' Counter/Timer %u Trigger Command Bit: %u\n", machine().describe_context(), tag(), counter + 1, (data & CTCS_TCB) ? 1 : 0); + if (LOG) logerror("%s Z8536 '%s' Counter/Timer %u Gate Command Bit: %u\n", machine().describe_context(), tag(), counter + 1, (data & CTCS_GCB) ? 1 : 0); + if (LOG) logerror("%s Z8536 '%s' Counter/Timer %u Read Counter Control: %u\n", machine().describe_context(), tag(), counter + 1, (data & CTCS_RCC) ? 1 : 0); + } + + switch (data >> 5) + { + case IC_CLEAR_IP_IUS: m_register[offset] &= ~(CTCS_IP | CTCS_IUS);if (LOG) logerror("%s Z8536 '%s' Counter/Timer %u Clear IP/IUS\n", machine().describe_context(), tag(), counter + 1); break; + case IC_SET_IUS: m_register[offset] |= CTCS_IUS; if (LOG) logerror("%s Z8536 '%s' Counter/Timer %u Set IUS\n", machine().describe_context(), tag(), counter + 1); break; + case IC_CLEAR_IUS: m_register[offset] &= ~CTCS_IUS; if (LOG) logerror("%s Z8536 '%s' Counter/Timer %u Clear IUS\n", machine().describe_context(), tag(), counter + 1); break; + case IC_SET_IP: m_register[offset] |= CTCS_IP; if (LOG) logerror("%s Z8536 '%s' Counter/Timer %u Set IP\n", machine().describe_context(), tag(), counter + 1); break; + case IC_CLEAR_IP: m_register[offset] &= ~CTCS_IP; if (LOG) logerror("%s Z8536 '%s' Counter/Timer %u Clear IP\n", machine().describe_context(), tag(), counter + 1); break; + case IC_SET_IE: m_register[offset] |= CTCS_IE; if (LOG) logerror("%s Z8536 '%s' Counter/Timer %u Set IE\n", machine().describe_context(), tag(), counter + 1); break; + case IC_CLEAR_IE: m_register[offset] &= ~CTCS_IE; if (LOG) logerror("%s Z8536 '%s' Counter/Timer %u Clear IE\n", machine().describe_context(), tag(), counter + 1); break; + } + + // gate command bit + m_register[offset] = (m_register[offset] & ~CTCS_GCB) | (data & CTCS_GCB); + + // trigger command bit + if (data & CTCS_TCB) + { + trigger(counter); + } + + // read counter control + if (counter_enabled(counter) && (data & CTCS_RCC)) + { + // freeze current count register + m_register[offset] |= CTCS_RCC; + m_register[COUNTER_TIMER_1_CURRENT_COUNT_MS_BYTE + (counter << 1)] = m_counter[counter] >> 8; + m_register[COUNTER_TIMER_1_CURRENT_COUNT_LS_BYTE + (counter << 1)] = m_counter[counter] & 0xff; + } + + check_interrupt(); + } + break; + + case PORT_A_DATA: + m_write_pa((offs_t)0, data); + break; + + case PORT_B_DATA: + m_write_pb((offs_t)0, data); + break; + + case PORT_C_DATA: + { + UINT8 mask = (data & 0xf0) | (data >> 4); + + m_output[PORT_C] = (m_output[PORT_C] & mask) | ((data & 0x0f) & (mask ^ 0xff)); + + m_write_pc((offs_t)0, m_output[PORT_C]); + } + break; + + case COUNTER_TIMER_1_TIME_CONSTANT_MS_BYTE: + case COUNTER_TIMER_2_TIME_CONSTANT_MS_BYTE: + case COUNTER_TIMER_3_TIME_CONSTANT_MS_BYTE: + if (LOG) + { + int counter = (offset - COUNTER_TIMER_1_TIME_CONSTANT_MS_BYTE) >> 1; + if (LOG) logerror("%s Z8536 '%s' Counter/Timer %u Time Constant MSB: %02x\n", machine().describe_context(), tag(), counter + 1, data); + } + + m_register[offset] = data; + break; + + case COUNTER_TIMER_1_TIME_CONSTANT_LS_BYTE: + case COUNTER_TIMER_2_TIME_CONSTANT_LS_BYTE: + case COUNTER_TIMER_3_TIME_CONSTANT_LS_BYTE: + if (LOG) + { + int counter = (offset - COUNTER_TIMER_1_TIME_CONSTANT_LS_BYTE) >> 1; + if (LOG) logerror("%s Z8536 '%s' Counter/Timer %u Time Constant LSB: %02x\n", machine().describe_context(), tag(), counter + 1, data); + } + + m_register[offset] = data; + break; + + case COUNTER_TIMER_1_MODE_SPECIFICATION: + case COUNTER_TIMER_2_MODE_SPECIFICATION: + case COUNTER_TIMER_3_MODE_SPECIFICATION: + if (LOG) + { + int counter = offset - COUNTER_TIMER_1_MODE_SPECIFICATION; + int dcs = data & CTMS_DCS_MASK; + + logerror("%s Z8536 '%s' Counter/Timer %u Mode: %s\n", machine().describe_context(), tag(), counter + 1, (data & CTMS_CSC) ? "Continuous" : "Single Cycle"); + logerror("%s Z8536 '%s' Counter/Timer %u External Output Enable: %u\n", machine().describe_context(), tag(), counter + 1, (data & CTMS_EOE) ? 1 : 0); + logerror("%s Z8536 '%s' Counter/Timer %u External Count Enable: %u\n", machine().describe_context(), tag(), counter + 1, (data & CTMS_ECE) ? 1 : 0); + logerror("%s Z8536 '%s' Counter/Timer %u External Trigger Enable: %u\n", machine().describe_context(), tag(), counter + 1, (data & CTMS_ETE) ? 1 : 0); + logerror("%s Z8536 '%s' Counter/Timer %u External Gate Enable: %u\n", machine().describe_context(), tag(), counter + 1, (data & CTMS_EDE) ? 1 : 0); + logerror("%s Z8536 '%s' Counter/Timer %u Retrigger Enable: %u\n", machine().describe_context(), tag(), counter + 1, (data & CTMS_REB) ? 1 : 0); + logerror("%s Z8536 '%s' Counter/Timer %u Output Duty Cycle: %s\n", machine().describe_context(), tag(), counter + 1, CTMS_DCS[dcs]); + } + + m_register[offset] = data; + break; + + case PORT_A_MODE_SPECIFICATION: + case PORT_B_MODE_SPECIFICATION: + if (LOG) + { + char port = BIT(offset, 3) ? 'B' : 'A'; + int pts = (data & PMS_PTS_MASK) >> 6; + int pms = (data & PMS_PMS_MASK) >> 1; + + logerror("%s Z8536 '%s' Port %c Port Type: %s\n", machine().describe_context(), tag(), port, PMS_PTS[pts]); + logerror("%s Z8536 '%s' Port %c Interrupt on 2 Bytes: %u\n", machine().describe_context(), tag(), port, (data & PMS_ITB) ? 1 : 0); + logerror("%s Z8536 '%s' Port %c Single Buffer: %u\n", machine().describe_context(), tag(), port, (data & PMS_SB) ? 1 : 0); + logerror("%s Z8536 '%s' Port %c Interrupt on Match Only: %u\n", machine().describe_context(), tag(), port, (data & PMS_IMO) ? 1 : 0); + logerror("%s Z8536 '%s' Port %c Pattern Mode: %s\n", machine().describe_context(), tag(), port, PMS_PMS[pms]); + + if (pts == PTS_BIT) + logerror("%s Z8536 '%s' Port %c Latch on Pattern Match: %u\n", machine().describe_context(), tag(), port, (data & PMS_LPM) ? 1 : 0); + else + logerror("%s Z8536 '%s' Port %c Deskew Timer Enable: %u\n", machine().describe_context(), tag(), port, (data & PMS_DTE) ? 1 : 0); + } + + m_register[offset] = data; + break; + + case PORT_A_HANDSHAKE_SPECIFICATION: + case PORT_B_HANDSHAKE_SPECIFICATION: + // TODO + break; + + case PORT_A_DATA_PATH_POLARITY: + case PORT_B_DATA_PATH_POLARITY: + if (LOG) logerror("%s Z8536 '%s' Port %c Data Path Polarity: %02x\n", machine().describe_context(), tag(), BIT(offset, 3) ? 'B' : 'A', data); + m_register[offset] = data; + break; + + case PORT_A_DATA_DIRECTION: + case PORT_B_DATA_DIRECTION: + if (LOG) logerror("%s Z8536 '%s' Port %c Data Direction: %02x\n", machine().describe_context(), tag(), BIT(offset, 3) ? 'B' : 'A', data); + m_register[offset] = data; + break; + + case PORT_A_SPECIAL_IO_CONTROL: + case PORT_B_SPECIAL_IO_CONTROL: + if (LOG) logerror("%s Z8536 '%s' Port %c Special I/O Control: %02x\n", machine().describe_context(), tag(), BIT(offset, 3) ? 'B' : 'A', data); + m_register[offset] = data; + break; + + case PORT_A_PATTERN_POLARITY: + case PORT_B_PATTERN_POLARITY: + if (LOG) logerror("%s Z8536 '%s' Port %c Pattern Polarity: %02x\n", machine().describe_context(), tag(), BIT(offset, 3) ? 'B' : 'A', data); + m_register[offset] = data; + break; + + case PORT_A_PATTERN_TRANSITION: + case PORT_B_PATTERN_TRANSITION: + if (LOG) logerror("%s Z8536 '%s' Port %c Pattern Transition: %02x\n", machine().describe_context(), tag(), BIT(offset, 3) ? 'B' : 'A', data); + m_register[offset] = data; + break; + + case PORT_A_PATTERN_MASK: + case PORT_B_PATTERN_MASK: + if (LOG) logerror("%s Z8536 '%s' Port %c Pattern Mask: %02x\n", machine().describe_context(), tag(), BIT(offset, 3) ? 'B' : 'A', data); + m_register[offset] = data; + match_pattern(BIT(offset, 3)); + check_interrupt(); + break; + + default: + logerror("%s: Z8536 '%s' Unimplemented write %02x to register %u\n", machine().describe_context(), tag(), data, offset); + m_register[offset] = data; + } +} + + +//------------------------------------------------- +// write_register - masked write to register +//------------------------------------------------- + +void z8536_device::write_register(offs_t offset, UINT8 data, UINT8 mask) +{ + UINT8 combined_data = (data & mask) | (m_register[offset] & (mask ^ 0xff)); + + write_register(offset, combined_data); +} + + +//------------------------------------------------- +// counter_enabled - is counter enabled? +//------------------------------------------------- + +bool z8536_device::counter_enabled(device_timer_id id) +{ + bool enabled = false; + + switch (id) + { + case TIMER_1: + enabled = (m_register[MASTER_CONFIGURATION_CONTROL] & MCCR_CT1E) ? true : false; + break; + + case TIMER_2: + enabled = (m_register[MASTER_CONFIGURATION_CONTROL] & MCCR_CT2E) ? true : false; + break; + + case TIMER_3: + enabled = (m_register[MASTER_CONFIGURATION_CONTROL] & MCCR_PCE_CT3E) ? true : false; + break; + } + + return enabled; +} + + +//------------------------------------------------- +// counter_external_output - +//------------------------------------------------- + +bool z8536_device::counter_external_output(device_timer_id id) +{ + return (m_register[COUNTER_TIMER_1_MODE_SPECIFICATION + id] & CTMS_EOE) ? true : false; +} + + +//------------------------------------------------- +// counter_external_count - +//------------------------------------------------- + +bool z8536_device::counter_external_count(device_timer_id id) +{ + return (m_register[COUNTER_TIMER_1_MODE_SPECIFICATION + id] & CTMS_ECE) ? true : false; +} + + +//------------------------------------------------- +// counter_external_trigger - +//------------------------------------------------- + +bool z8536_device::counter_external_trigger(device_timer_id id) +{ + return (m_register[COUNTER_TIMER_1_MODE_SPECIFICATION + id] & CTMS_ETE) ? true : false; +} + + +//------------------------------------------------- +// counter_external_gate - +//------------------------------------------------- + +bool z8536_device::counter_external_gate(device_timer_id id) +{ + return (m_register[COUNTER_TIMER_1_MODE_SPECIFICATION + id] & CTMS_EDE) ? true : false; +} + + +//------------------------------------------------- +// counter_gated - +//------------------------------------------------- + +bool z8536_device::counter_gated(device_timer_id id) +{ + return (m_register[COUNTER_TIMER_1_COMMAND_AND_STATUS + id] & CTCS_GCB) ? true : false; +} + + +//------------------------------------------------- +// count - count down +//------------------------------------------------- + +void z8536_device::count(device_timer_id id) +{ + if (!counter_gated(id)) return; + if (!(m_register[COUNTER_TIMER_1_COMMAND_AND_STATUS + id] & CTCS_CIP)) return; + + // count down + m_counter[id]--; + + if (m_counter[id] == 0) + { + if (m_register[COUNTER_TIMER_1_COMMAND_AND_STATUS + id] & CTCS_IP) + { + // set interrupt error bit + m_register[COUNTER_TIMER_1_COMMAND_AND_STATUS + id] |= CTCS_ERR; + } + else + { + if (LOG) logerror("%s Z8536 '%s' Counter/Timer %u Interrupt Pending\n", machine().describe_context(), tag(), id + 1); + + // set interrupt pending bit + m_register[COUNTER_TIMER_1_COMMAND_AND_STATUS + id] |= CTCS_IP; + } + + if (m_register[COUNTER_TIMER_1_MODE_SPECIFICATION + id] & CTMS_CSC) + { + // reload counter with time constant + m_counter[id] = (m_register[COUNTER_TIMER_1_TIME_CONSTANT_MS_BYTE + (id << 1)] << 8) | m_register[COUNTER_TIMER_1_TIME_CONSTANT_LS_BYTE + (id << 1)]; + } + else + { + if (LOG) logerror("%s Z8536 '%s' Counter/Timer %u Terminal Count\n", machine().describe_context(), tag(), id + 1); + + // clear count in progress bit + m_register[COUNTER_TIMER_1_COMMAND_AND_STATUS + id] &= ~CTCS_CIP; + } + + check_interrupt(); + } +} + + +//------------------------------------------------- +// trigger - +//------------------------------------------------- + +void z8536_device::trigger(device_timer_id id) +{ + // ignore triggers during countdown if retrigger is disabled + if (!(m_register[COUNTER_TIMER_1_MODE_SPECIFICATION + id] & CTMS_REB) && (m_register[COUNTER_TIMER_1_COMMAND_AND_STATUS + id] & CTCS_CIP)) return; + + if (LOG) logerror("%s Z8536 '%s' Counter/Timer %u Trigger\n", machine().describe_context(), tag(), id + 1); + + // load counter with time constant + m_counter[id] = (m_register[COUNTER_TIMER_1_TIME_CONSTANT_MS_BYTE + (id << 1)] << 8) | m_register[COUNTER_TIMER_1_TIME_CONSTANT_LS_BYTE + (id << 1)]; + + // set count in progress bit + m_register[COUNTER_TIMER_1_COMMAND_AND_STATUS + id] |= CTCS_CIP; +} + + +//------------------------------------------------- +// gate - +//------------------------------------------------- + +void z8536_device::gate(device_timer_id id, int state) +{ + // TODO +} + + +//------------------------------------------------- +// match_pattern - +//------------------------------------------------- + +void z8536_device::match_pattern(int port) +{ + UINT8 pms = m_register[PORT_A_MODE_SPECIFICATION + (port << 3)]; + UINT8 pm = m_register[PORT_A_PATTERN_MASK + (port << 3)]; + UINT8 ddr = m_register[PORT_A_DATA_DIRECTION + (port << 3)]; + + switch ((pms & PMS_PMS_MASK) >> 1) + { + case PMS_OR_PEV: + m_match[port] = m_input[port] & ddr & pm; + + if (m_match[port]) + { + if (LOG) logerror("%s Z8536 '%s' Port %c Interrupt Pending\n", machine().describe_context(), tag(), 'A' + port); + m_register[PORT_A_COMMAND_AND_STATUS + port] |= PCS_IP; + check_interrupt(); + } + break; + } +} + + +//------------------------------------------------- +// external_port_w - external port write +//------------------------------------------------- + +void z8536_device::external_port_w(int port, int bit, int state) +{ + switch (port) + { + case PORT_A: + case PORT_B: + { + assert((PORT_A_DATA_DIRECTION + (port << 3)) >= 0 && (PORT_A_DATA_DIRECTION + (port << 3)) < ARRAY_LENGTH(m_register)); + UINT8 ddr = m_register[PORT_A_DATA_DIRECTION + (port << 3)]; + + if (!BIT(ddr, bit)) return; + + if (LOG) logerror("%s Z8536 '%s' Port %c Bit %u: %u\n", machine().describe_context(), tag(), 'A' + port, bit, state); + + m_input[port] = (m_input[port] & ~(1 << bit)) | (state << bit); + + match_pattern(port); + } + break; + + case PORT_C: + break; + } +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// z8536_device - constructor +//------------------------------------------------- + +z8536_device::z8536_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, Z8536, "Zilog Z8536", tag, owner, clock, "z8536", __FILE__), + device_z80daisy_interface(mconfig, *this), + m_write_irq(*this), + m_read_pa(*this), + m_write_pa(*this), + m_read_pb(*this), + m_write_pb(*this), + m_read_pc(*this), + m_write_pc(*this), + m_irq(CLEAR_LINE) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void z8536_device::device_start() +{ + for (int i = 0; i < 3; i++) + { + m_input[i] = 0; + m_output[i] = 0; + m_buffer[i] = 0; + m_match[i] = 0; + } + + // allocate timer + m_timer = timer_alloc(); + m_timer->adjust(attotime::from_hz(clock() / 2), 0, attotime::from_hz(clock() / 2)); + + // resolve callbacks + m_write_irq.resolve_safe(); + m_read_pa.resolve_safe(0); + m_write_pa.resolve_safe(); + m_read_pb.resolve_safe(0); + m_write_pb.resolve_safe(); + m_read_pc.resolve_safe(0); + m_write_pc.resolve_safe(); +} + + +//------------------------------------------------- +// device_start - device-specific reset +//------------------------------------------------- + +void z8536_device::device_reset() +{ + m_state = STATE_RESET; + + for (int i = 0; i < 48; i++) + { + m_register[i] = 0; + } + + m_register[MASTER_INTERRUPT_CONTROL] = MICR_RESET; + m_register[PORT_A_COMMAND_AND_STATUS] = PCS_ORE; + m_register[PORT_B_COMMAND_AND_STATUS] = PCS_ORE; + m_register[CURRENT_VECTOR] = 0xff; + + m_pointer = 0; + + check_interrupt(); +} + + +//------------------------------------------------- +// device_timer - handler timer events +//------------------------------------------------- + +void z8536_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + if (counter_enabled(TIMER_1) && !counter_external_count(TIMER_1)) + { + count(TIMER_1); + } + + if (counter_enabled(TIMER_2) && !counter_external_count(TIMER_2)) + { + count(TIMER_2); + } + + if (counter_enabled(TIMER_3) && !counter_external_count(TIMER_3)) + { + count(TIMER_3); + } +} + + + +//************************************************************************** +// DAISY CHAIN INTERFACE +//************************************************************************** + +//------------------------------------------------- +// z80daisy_irq_state - return the overall IRQ +// state for this device +//------------------------------------------------- + +int z8536_device::z80daisy_irq_state() +{ + return 0; +} + + +//------------------------------------------------- +// z80daisy_irq_ack - acknowledge an IRQ and +// return the appropriate vector +//------------------------------------------------- + +int z8536_device::z80daisy_irq_ack() +{ + return intack_r(); +} + + +//------------------------------------------------- +// z80daisy_irq_reti - clear the interrupt +// pending state to allow other interrupts through +//------------------------------------------------- + +void z8536_device::z80daisy_irq_reti() +{ +} + + + +//************************************************************************** +// INTERNAL STATE MANAGEMENT +//************************************************************************** + +//------------------------------------------------- +// read - register read +//------------------------------------------------- + +READ8_MEMBER( z8536_device::read ) +{ + UINT8 data = 0; + + if (m_state == STATE_RESET) + { + // read RESET bit + data = read_register(m_pointer, 0x01); + } + else + { + switch (offset & 0x03) + { + case PORT_C: + data = read_register(PORT_C_DATA); + break; + + case PORT_B: + data = read_register(PORT_B_DATA); + break; + + case PORT_A: + data = read_register(PORT_A_DATA); + break; + + case CONTROL: + switch (m_state) + { + case STATE_1: + m_state = STATE_0; + // fallthru + case STATE_0: + data = read_register(m_pointer); + break; + } + break; + } + } + + return data; +} + + +//------------------------------------------------- +// write - register write +//------------------------------------------------- + +WRITE8_MEMBER( z8536_device::write ) +{ + if (m_state == STATE_RESET) + { + // write RESET bit + write_register(m_pointer, data, 0x01); + } + else + { + switch (offset & 0x03) + { + case PORT_C: + write_register(PORT_C_DATA, data); + break; + + case PORT_B: + write_register(PORT_B_DATA, data); + break; + + case PORT_A: + write_register(PORT_A_DATA, data); + break; + + case CONTROL: + switch (m_state) + { + case STATE_0: + m_pointer = data; + m_state = STATE_1; + break; + + case STATE_1: + write_register(m_pointer, data); + m_state = STATE_0; + } + break; + } + } +} + + +//------------------------------------------------- +// intack_r - interrupt acknowledge +//------------------------------------------------- + +int z8536_device::intack_r() +{ + get_interrupt_vector(); + int data = m_register[CURRENT_VECTOR]; + + if (LOG) logerror("%s Z8536 '%s' Interrupt Acknowledge: %02x\n", machine().describe_context(), tag(), data); + + // set interrupt under service bit + if ((m_register[COUNTER_TIMER_3_COMMAND_AND_STATUS] & (CTCS_IP | CTCS_IE)) == (CTCS_IP | CTCS_IE)) + { + m_register[COUNTER_TIMER_3_COMMAND_AND_STATUS] |= CTCS_IUS; + } + else if ((m_register[PORT_A_COMMAND_AND_STATUS] & (PCS_IP | PCS_IE)) == (PCS_IP | PCS_IE)) + { + m_register[PORT_A_COMMAND_AND_STATUS] |= PCS_IUS; + } + else if ((m_register[COUNTER_TIMER_2_COMMAND_AND_STATUS] & (CTCS_IP | CTCS_IE)) == (CTCS_IP | CTCS_IE)) + { + m_register[COUNTER_TIMER_2_COMMAND_AND_STATUS] |= CTCS_IUS; + } + else if ((m_register[PORT_B_COMMAND_AND_STATUS] & (PCS_IP | PCS_IE)) == (PCS_IP | PCS_IE)) + { + m_register[PORT_B_COMMAND_AND_STATUS] |= PCS_IUS; + } + else if ((m_register[COUNTER_TIMER_1_COMMAND_AND_STATUS] & (CTCS_IP | CTCS_IE)) == (CTCS_IP | CTCS_IE)) + { + m_register[COUNTER_TIMER_1_COMMAND_AND_STATUS] |= CTCS_IUS; + } + + check_interrupt(); + + if (m_register[MASTER_INTERRUPT_CONTROL] & MICR_NV) + { + // no vector + data = -1; + } + + return data; +} diff --git a/src/devices/machine/z8536.h b/src/devices/machine/z8536.h new file mode 100644 index 00000000000..96c39e0123a --- /dev/null +++ b/src/devices/machine/z8536.h @@ -0,0 +1,353 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Zilog Z8536 Counter/Timer and Parallel I/O emulation + +********************************************************************** + _____ _____ + D4 1 |* \_/ | 40 D3 + D5 2 | | 39 D2 + D6 3 | | 38 D1 + D7 4 | | 37 D0 + _RD 5 | | 36 _CE + _WR 6 | | 35 A1 + GND 7 | | 34 A0 + PB0 8 | | 33 PA0 + PB1 9 | | 32 PA1 + PB2 10 | Z8536 | 31 PA2 + PB3 11 | | 30 PA3 + PB4 12 | | 29 PA4 + PB5 13 | | 28 PA5 + PB6 14 | | 27 PA6 + PB7 15 | | 26 PA7 + PCLK 16 | | 25 _INTACK + IEI 17 | | 24 _INT + IEO 18 | | 23 +5 V + PC0 19 | | 22 PC3 + PC1 20 |_____________| 21 PC2 + +**********************************************************************/ + +#pragma once + +#ifndef __Z8536__ +#define __Z8536__ + +#include "emu.h" +#include "cpu/z80/z80daisy.h" + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_Z8536_IRQ_CALLBACK(_write) \ + devcb = &z8536_device::set_irq_wr_callback(*device, DEVCB_##_write); + +#define MCFG_Z8536_PA_IN_CALLBACK(_read) \ + devcb = &z8536_device::set_pa_rd_callback(*device, DEVCB_##_read); + +#define MCFG_Z8536_PA_OUT_CALLBACK(_write) \ + devcb = &z8536_device::set_pa_wr_callback(*device, DEVCB_##_write); + +#define MCFG_Z8536_PB_IN_CALLBACK(_read) \ + devcb = &z8536_device::set_pb_rd_callback(*device, DEVCB_##_read); + +#define MCFG_Z8536_PB_OUT_CALLBACK(_write) \ + devcb = &z8536_device::set_pb_wr_callback(*device, DEVCB_##_write); + +#define MCFG_Z8536_PC_IN_CALLBACK(_read) \ + devcb = &z8536_device::set_pc_rd_callback(*device, DEVCB_##_read); + +#define MCFG_Z8536_PC_OUT_CALLBACK(_write) \ + devcb = &z8536_device::set_pc_wr_callback(*device, DEVCB_##_write); + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> z8536_device + +class z8536_device : public device_t, + public device_z80daisy_interface +{ +public: + // construction/destruction + z8536_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + template static devcb_base &set_irq_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_irq.set_callback(object); } + template static devcb_base &set_pa_rd_callback(device_t &device, _Object object) { return downcast(device).m_read_pa.set_callback(object); } + template static devcb_base &set_pa_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_pa.set_callback(object); } + template static devcb_base &set_pb_rd_callback(device_t &device, _Object object) { return downcast(device).m_read_pb.set_callback(object); } + template static devcb_base &set_pb_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_pb.set_callback(object); } + template static devcb_base &set_pc_rd_callback(device_t &device, _Object object) { return downcast(device).m_read_pc.set_callback(object); } + template static devcb_base &set_pc_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_pc.set_callback(object); } + + DECLARE_READ8_MEMBER( read ); + DECLARE_WRITE8_MEMBER( write ); + + int intack_r(); + + DECLARE_WRITE_LINE_MEMBER( pa0_w ) { external_port_w(PORT_A, 0, state); } + DECLARE_WRITE_LINE_MEMBER( pa1_w ) { external_port_w(PORT_A, 1, state); } + DECLARE_WRITE_LINE_MEMBER( pa2_w ) { external_port_w(PORT_A, 2, state); } + DECLARE_WRITE_LINE_MEMBER( pa3_w ) { external_port_w(PORT_A, 3, state); } + DECLARE_WRITE_LINE_MEMBER( pa4_w ) { external_port_w(PORT_A, 4, state); } + DECLARE_WRITE_LINE_MEMBER( pa5_w ) { external_port_w(PORT_A, 5, state); } + DECLARE_WRITE_LINE_MEMBER( pa6_w ) { external_port_w(PORT_A, 6, state); } + DECLARE_WRITE_LINE_MEMBER( pa7_w ) { external_port_w(PORT_A, 7, state); } + + DECLARE_WRITE_LINE_MEMBER( pb0_w ) { external_port_w(PORT_B, 0, state); } + DECLARE_WRITE_LINE_MEMBER( pb1_w ) { external_port_w(PORT_B, 1, state); } + DECLARE_WRITE_LINE_MEMBER( pb2_w ) { external_port_w(PORT_B, 2, state); } + DECLARE_WRITE_LINE_MEMBER( pb3_w ) { external_port_w(PORT_B, 3, state); } + DECLARE_WRITE_LINE_MEMBER( pb4_w ) { external_port_w(PORT_B, 4, state); } + DECLARE_WRITE_LINE_MEMBER( pb5_w ) { external_port_w(PORT_B, 5, state); } + DECLARE_WRITE_LINE_MEMBER( pb6_w ) { external_port_w(PORT_B, 6, state); } + DECLARE_WRITE_LINE_MEMBER( pb7_w ) { external_port_w(PORT_B, 7, state); } + + DECLARE_WRITE_LINE_MEMBER( pc0_w ) { external_port_w(PORT_C, 0, state); } + DECLARE_WRITE_LINE_MEMBER( pc1_w ) { external_port_w(PORT_C, 1, state); } + DECLARE_WRITE_LINE_MEMBER( pc2_w ) { external_port_w(PORT_C, 2, state); } + DECLARE_WRITE_LINE_MEMBER( pc3_w ) { external_port_w(PORT_C, 3, state); } + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + // device_z80daisy_interface overrides + virtual int z80daisy_irq_state(); + virtual int z80daisy_irq_ack(); + virtual void z80daisy_irq_reti(); + +private: + enum + { + TIMER_1 = 0, + TIMER_2, + TIMER_3 + }; + + // states + enum + { + STATE_RESET = -1, + STATE_0, + STATE_1 + }; + + + // ports + enum + { + PORT_C = 0, + PORT_B, + PORT_A, + CONTROL + }; + + + // registers + enum + { + MASTER_INTERRUPT_CONTROL = 0, + MASTER_CONFIGURATION_CONTROL, + PORT_A_INTERRUPT_VECTOR, + PORT_B_INTERRUPT_VECTOR, + COUNTER_TIMER_INTERRUPT_VECTOR, + PORT_C_DATA_PATH_POLARITY, + PORT_C_DATA_DIRECTION, + PORT_C_SPECIAL_IO_CONTROL, + PORT_A_COMMAND_AND_STATUS, + PORT_B_COMMAND_AND_STATUS, + COUNTER_TIMER_1_COMMAND_AND_STATUS, + COUNTER_TIMER_2_COMMAND_AND_STATUS, + COUNTER_TIMER_3_COMMAND_AND_STATUS, + PORT_A_DATA, + PORT_B_DATA, + PORT_C_DATA, + COUNTER_TIMER_1_CURRENT_COUNT_MS_BYTE, + COUNTER_TIMER_1_CURRENT_COUNT_LS_BYTE, + COUNTER_TIMER_2_CURRENT_COUNT_MS_BYTE, + COUNTER_TIMER_2_CURRENT_COUNT_LS_BYTE, + COUNTER_TIMER_3_CURRENT_COUNT_MS_BYTE, + COUNTER_TIMER_3_CURRENT_COUNT_LS_BYTE, + COUNTER_TIMER_1_TIME_CONSTANT_MS_BYTE, + COUNTER_TIMER_1_TIME_CONSTANT_LS_BYTE, + COUNTER_TIMER_2_TIME_CONSTANT_MS_BYTE, + COUNTER_TIMER_2_TIME_CONSTANT_LS_BYTE, + COUNTER_TIMER_3_TIME_CONSTANT_MS_BYTE, + COUNTER_TIMER_3_TIME_CONSTANT_LS_BYTE, + COUNTER_TIMER_1_MODE_SPECIFICATION, + COUNTER_TIMER_2_MODE_SPECIFICATION, + COUNTER_TIMER_3_MODE_SPECIFICATION, + CURRENT_VECTOR, + PORT_A_MODE_SPECIFICATION, + PORT_A_HANDSHAKE_SPECIFICATION, + PORT_A_DATA_PATH_POLARITY, + PORT_A_DATA_DIRECTION, + PORT_A_SPECIAL_IO_CONTROL, + PORT_A_PATTERN_POLARITY, + PORT_A_PATTERN_TRANSITION, + PORT_A_PATTERN_MASK, + PORT_B_MODE_SPECIFICATION, + PORT_B_HANDSHAKE_SPECIFICATION, + PORT_B_DATA_PATH_POLARITY, + PORT_B_DATA_DIRECTION, + PORT_B_SPECIAL_IO_CONTROL, + PORT_B_PATTERN_POLARITY, + PORT_B_PATTERN_TRANSITION, + PORT_B_PATTERN_MASK + }; + + + // interrupt control + enum + { + IC_NULL = 0, + IC_CLEAR_IP_IUS, + IC_SET_IUS, + IC_CLEAR_IUS, + IC_SET_IP, + IC_CLEAR_IP, + IC_SET_IE, + IC_CLEAR_IE + }; + + + // counter/timer link control + enum + { + LC_INDEPENDENT = 0, + LC_CT1_GATES_CT2, + LC_CT1_TRIGGERS_CT2, + LC_CT1_COUNTS_CT2 + }; + + + // port type select + enum + { + PTS_BIT = 0, + PTS_INPUT, + PTS_OUTPUT, + PTS_BIDIRECTIONAL + }; + + + + // pattern mode specification + enum + { + PMS_DISABLE = 0, + PMS_AND, + PMS_OR, + PMS_OR_PEV + }; + + // handshake specification + enum + { + HTS_INTERLOCKED = 0, + HTS_STROBED, + HTS_PULSED, + HTS_3_WIRE + }; + + + // request/wait specification + enum + { + RWS_DISABLED = 0, + RWS_OUTPUT_WAIT, + RWS_INPUT_WAIT = 3, + RWS_SPECIAL_REQUEST, + RWS_OUTPUT_REQUEST, + RWS_INPUT_REQUEST = 7 + }; + + + // pattern specification + enum + { + BIT_MASKED_OFF = 0, + ANY_TRANSITION, + ZERO = 4, + ONE, + ONE_TO_ZERO, + ZERO_TO_ONE + }; + + + // output duty cycle + enum + { + DCS_PULSE, + DCS_ONE_SHOT, + DCS_SQUARE_WAVE, + DCS_DO_NOT_USE + }; + + void get_interrupt_vector(); + void check_interrupt(); + + UINT8 read_register(offs_t offset); + UINT8 read_register(offs_t offset, UINT8 mask); + void write_register(offs_t offset, UINT8 data); + void write_register(offs_t offset, UINT8 data, UINT8 mask); + + bool counter_enabled(device_timer_id id); + bool counter_external_output(device_timer_id id); + bool counter_external_count(device_timer_id id); + bool counter_external_trigger(device_timer_id id); + bool counter_external_gate(device_timer_id id); + bool counter_gated(device_timer_id id); + void count(device_timer_id id); + void trigger(device_timer_id id); + void gate(device_timer_id id, int state); + void match_pattern(int port); + void external_port_w(int port, int bit, int state); + + devcb_write_line m_write_irq; + + devcb_read8 m_read_pa; + devcb_write8 m_write_pa; + + devcb_read8 m_read_pb; + devcb_write8 m_write_pb; + + devcb_read8 m_read_pc; + devcb_write8 m_write_pc; + + // interrupt state + int m_irq; + + // register state + int m_state; + UINT8 m_register[48]; + UINT8 m_pointer; + + // input/output port state + UINT8 m_input[3]; + UINT8 m_output[3]; + UINT8 m_buffer[3]; + UINT8 m_match[3]; + + // timers + emu_timer *m_timer; + UINT16 m_counter[3]; +}; + + +// device type definition +extern const device_type Z8536; + + + +#endif diff --git a/src/devices/sound/2151intf.c b/src/devices/sound/2151intf.c new file mode 100644 index 00000000000..e4739c758ee --- /dev/null +++ b/src/devices/sound/2151intf.c @@ -0,0 +1,131 @@ +// license:BSD-3-Clause +// copyright-holders:Ernesto Corvi +/*************************************************************************** + + 2151intf.c + + Support interface YM2151(OPM) + +***************************************************************************/ + +#include "emu.h" +#include "fm.h" +#include "2151intf.h" +#include "ym2151.h" + + + +const device_type YM2151 = &device_creator; + + +//------------------------------------------------- +// ym2151_device - constructor +//------------------------------------------------- + +ym2151_device::ym2151_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, YM2151, "YM2151", tag, owner, clock, "ym2151", __FILE__), + device_sound_interface(mconfig, *this), + m_irqhandler(*this), + m_portwritehandler(*this) +{ +} + + +//------------------------------------------------- +// read - read from the device +//------------------------------------------------- + +READ8_MEMBER( ym2151_device::read ) +{ + if (offset & 1) + { + m_stream->update(); + return ym2151_read_status(m_chip); + } + else + return 0xff; /* confirmed on a real YM2151 */ +} + + +//------------------------------------------------- +// write - write from the device +//------------------------------------------------- + +WRITE8_MEMBER( ym2151_device::write ) +{ + if (offset & 1) + { + m_stream->update(); + ym2151_write_reg(m_chip, m_lastreg, data); + } + else + m_lastreg = data; +} + + +READ8_MEMBER( ym2151_device::status_r ) { return read(space, 1); } + +WRITE8_MEMBER( ym2151_device::register_w ) { write(space, 0, data); } +WRITE8_MEMBER( ym2151_device::data_w ) { write(space, 1, data); } + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void ym2151_device::device_start() +{ + m_irqhandler.resolve_safe(); + m_portwritehandler.resolve_safe(); + + // stream setup + int rate = clock() / 64; + m_stream = stream_alloc(0, 2, rate); + + m_chip = ym2151_init(this, clock(), rate); + assert_always(m_chip != NULL, "Error creating YM2151 chip"); + + ym2151_set_irq_handler(m_chip, irq_frontend); + ym2151_set_port_write_handler(m_chip, port_write_frontend); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void ym2151_device::device_reset() +{ + ym2151_reset_chip(m_chip); +} + + +//------------------------------------------------- +// device_stop - device-specific stop +//------------------------------------------------- + +void ym2151_device::device_stop() +{ + ym2151_shutdown(m_chip); +} + + +//------------------------------------------------- +// sound_stream_update - handle a stream update +//------------------------------------------------- + +void ym2151_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + ym2151_update_one(m_chip, outputs, samples); +} + + +void ym2151_device::irq_frontend(device_t *device, int irq) +{ + downcast(device)->m_irqhandler(irq); +} + +void ym2151_device::port_write_frontend(device_t *device, offs_t offset, UINT8 data) +{ + downcast(device)->m_portwritehandler(offset, data); +} diff --git a/src/devices/sound/2151intf.h b/src/devices/sound/2151intf.h new file mode 100644 index 00000000000..79952d76228 --- /dev/null +++ b/src/devices/sound/2151intf.h @@ -0,0 +1,84 @@ +// license:BSD-3-Clause +// copyright-holders:Ernesto Corvi +/*************************************************************************** + + 2151intf.h + + MAME interface to YM2151 emulator. + +***************************************************************************/ + +#pragma once + +#ifndef __2151INTF_H__ +#define __2151INTF_H__ + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_YM2151_ADD(_tag, _clock) \ + MCFG_DEVICE_ADD(_tag, YM2151, _clock) + +#define MCFG_YM2151_IRQ_HANDLER(_devcb) \ + devcb = &ym2151_device::set_irq_handler(*device, DEVCB_##_devcb); +#define MCFG_YM2151_PORT_WRITE_HANDLER(_devcb) \ + devcb = &ym2151_device::set_port_write_handler(*device, DEVCB_##_devcb); + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + + +// ======================> ym2151_device + +class ym2151_device : public device_t, + public device_sound_interface +{ +public: + // construction/destruction + ym2151_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // static configuration helpers + template static devcb_base &set_irq_handler(device_t &device, _Object object) { return downcast(device).m_irqhandler.set_callback(object); } + template static devcb_base &set_port_write_handler(device_t &device, _Object object) { return downcast(device).m_portwritehandler.set_callback(object); } + + // read/write + DECLARE_READ8_MEMBER( read ); + DECLARE_WRITE8_MEMBER( write ); + + DECLARE_READ8_MEMBER( status_r ); + DECLARE_WRITE8_MEMBER( register_w ); + DECLARE_WRITE8_MEMBER( data_w ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_stop(); + virtual void device_reset(); + + // sound stream update overrides + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + +private: + // internal helpers + static void irq_frontend(device_t *device, int irq); + static void port_write_frontend(device_t *device, offs_t offset, UINT8 data); + + // internal state + sound_stream * m_stream; + //emu_timer * m_timer[2]; + void * m_chip; + UINT8 m_lastreg; + devcb_write_line m_irqhandler; + devcb_write8 m_portwritehandler; +}; + + +// device type definition +extern const device_type YM2151; + + +#endif /* __2151INTF_H__ */ diff --git a/src/devices/sound/2203intf.c b/src/devices/sound/2203intf.c new file mode 100644 index 00000000000..279ae52cea4 --- /dev/null +++ b/src/devices/sound/2203intf.c @@ -0,0 +1,195 @@ +// license:BSD-3-Clause +// copyright-holders:Ernesto Corvi +#include "2203intf.h" +#include "fm.h" + +static void psg_set_clock(void *param, int clock) +{ + ym2203_device *ym2203 = (ym2203_device *) param; + ym2203->ay_set_clock(clock); +} + +static void psg_write(void *param, int address, int data) +{ + ym2203_device *ym2203 = (ym2203_device *) param; + ym2203->ay8910_write_ym(address, data); +} + +static int psg_read(void *param) +{ + ym2203_device *ym2203 = (ym2203_device *) param; + return ym2203->ay8910_read_ym(); +} + +static void psg_reset(void *param) +{ + ym2203_device *ym2203 = (ym2203_device *) param; + ym2203->ay8910_reset_ym(); +} + +static const ssg_callbacks psgintf = +{ + psg_set_clock, + psg_write, + psg_read, + psg_reset +}; + +/* IRQ Handler */ +static void IRQHandler(void *param,int irq) +{ + ym2203_device *ym2203 = (ym2203_device *) param; + ym2203->_IRQHandler(irq); +} + +void ym2203_device::_IRQHandler(int irq) +{ + if (!m_irq_handler.isnull()) + m_irq_handler(irq); +} + +/* Timer overflow callback from timer.c */ +void ym2203_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch(id) + { + case 0: + ym2203_timer_over(m_chip,0); + break; + + case 1: + ym2203_timer_over(m_chip,1); + break; + } +} + +static void timer_handler(void *param,int c,int count,int clock) +{ + ym2203_device *ym2203 = (ym2203_device *) param; + ym2203->_timer_handler(c, count, clock); +} + +void ym2203_device::_timer_handler(int c,int count,int clock) +{ + if( count == 0 ) + { /* Reset FM Timer */ + m_timer[c]->enable(false); + } + else + { /* Start FM Timer */ + attotime period = attotime::from_hz(clock) * count; + + if (!m_timer[c]->enable(true)) + m_timer[c]->adjust(period); + } +} + +/* update request from fm.c */ +void ym2203_update_request(void *param) +{ + ym2203_device *ym2203 = (ym2203_device *) param; + ym2203->_ym2203_update_request(); +} + +void ym2203_device::_ym2203_update_request() +{ + m_stream->update(); +} + +//------------------------------------------------- +// sound_stream_update - handle a stream update +//------------------------------------------------- + + +void ym2203_device::stream_generate(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + ym2203_update_one(m_chip, outputs[0], samples); +} + + +void ym2203_device::device_post_load() +{ + ym2203_postload(m_chip); +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void ym2203_device::device_start() +{ + ay8910_device::device_start(); + + int rate = clock()/72; /* ??? */ + + m_irq_handler.resolve(); + + /* Timer Handler set */ + m_timer[0] = timer_alloc(0); + m_timer[1] = timer_alloc(1); + + /* stream system initialize */ + m_stream = machine().sound().stream_alloc(*this,0,1,rate, stream_update_delegate(FUNC(ym2203_device::stream_generate),this)); + + /* Initialize FM emurator */ + m_chip = ym2203_init(this,this,clock(),rate,timer_handler,IRQHandler,&psgintf); + assert_always(m_chip != NULL, "Error creating YM2203 chip"); +} + +//------------------------------------------------- +// device_stop - device-specific stop +//------------------------------------------------- + +void ym2203_device::device_stop() +{ + ym2203_shutdown(m_chip); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void ym2203_device::device_reset() +{ + ym2203_reset_chip(m_chip); +} + + +READ8_MEMBER( ym2203_device::read ) +{ + return ym2203_read(m_chip, offset & 1); +} + +WRITE8_MEMBER( ym2203_device::write ) +{ + ym2203_write(m_chip, offset & 1, data); +} + +READ8_MEMBER( ym2203_device::status_port_r ) +{ + return read(space, 0); +} + +READ8_MEMBER( ym2203_device::read_port_r ) +{ + return read(space, 1); +} + +WRITE8_MEMBER( ym2203_device::control_port_w ) +{ + write(space, 0, data); +} + +WRITE8_MEMBER( ym2203_device::write_port_w ) +{ + write(space, 1, data); +} + +const device_type YM2203 = &device_creator; + +ym2203_device::ym2203_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : ay8910_device(mconfig, YM2203, "YM2203", tag, owner, clock, PSG_TYPE_YM, 3, 2, "ym2203", __FILE__), + m_irq_handler(*this) +{ +} diff --git a/src/devices/sound/2203intf.h b/src/devices/sound/2203intf.h new file mode 100644 index 00000000000..8d81c54282a --- /dev/null +++ b/src/devices/sound/2203intf.h @@ -0,0 +1,56 @@ +// license:BSD-3-Clause +// copyright-holders:Ernesto Corvi +#pragma once + +#ifndef __2203INTF_H__ +#define __2203INTF_H__ + +#include "emu.h" +#include "ay8910.h" + +void ym2203_update_request(void *param); + +#define MCFG_YM2203_IRQ_HANDLER(_devcb) \ + devcb = &ym2203_device::set_irq_handler(*device, DEVCB_##_devcb); + +class ym2203_device : public ay8910_device +{ +public: + ym2203_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // static configuration helpers + template static devcb_base &set_irq_handler(device_t &device, _Object object) { return downcast(device).m_irq_handler.set_callback(object); } + + DECLARE_READ8_MEMBER( read ); + DECLARE_WRITE8_MEMBER( write ); + + DECLARE_READ8_MEMBER( status_port_r ); + DECLARE_READ8_MEMBER( read_port_r ); + DECLARE_WRITE8_MEMBER( control_port_w ); + DECLARE_WRITE8_MEMBER( write_port_w ); + + void _IRQHandler(int irq); + void _timer_handler(int c,int count,int clock); + void _ym2203_update_request(); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_post_load(); + virtual void device_stop(); + virtual void device_reset(); + + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + void stream_generate(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); +private: + // internal state + sound_stream * m_stream; + emu_timer * m_timer[2]; + void * m_chip; + devcb_write_line m_irq_handler; +}; + +extern const device_type YM2203; + + +#endif /* __2203INTF_H__ */ diff --git a/src/devices/sound/2413intf.c b/src/devices/sound/2413intf.c new file mode 100644 index 00000000000..3ecfd061241 --- /dev/null +++ b/src/devices/sound/2413intf.c @@ -0,0 +1,95 @@ +// license:BSD-3-Clause +// copyright-holders:Ernesto Corvi +/**************************************************************** + + MAME / MESS functions + +****************************************************************/ + +#include "emu.h" +#include "ym2413.h" +#include "2413intf.h" + + +static void ym2413_update_request(void *param, int interval) +{ + ym2413_device *ym2413 = (ym2413_device *) param; + ym2413->_ym2413_update_request(); +} + +void ym2413_device::_ym2413_update_request() +{ + m_stream->update(); +} + +//------------------------------------------------- +// sound_stream_update - handle a stream update +//------------------------------------------------- + +void ym2413_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + ym2413_update_one(m_chip, outputs, samples); +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void ym2413_device::device_start() +{ + int rate = clock()/72; + + /* emulator create */ + m_chip = ym2413_init(this, clock(), rate); + assert_always(m_chip != NULL, "Error creating YM2413 chip"); + + /* stream system initialize */ + m_stream = machine().sound().stream_alloc(*this,0,2,rate); + + ym2413_set_update_handler(m_chip, ym2413_update_request, this); +} + +//------------------------------------------------- +// device_stop - device-specific stop +//------------------------------------------------- + +void ym2413_device::device_stop() +{ + ym2413_shutdown(m_chip); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void ym2413_device::device_reset() +{ + ym2413_reset_chip(m_chip); +} + + +WRITE8_MEMBER( ym2413_device::write ) +{ + ym2413_write(m_chip, offset & 1, data); +} + +WRITE8_MEMBER( ym2413_device::register_port_w ) { write(space, 0, data); } +WRITE8_MEMBER( ym2413_device::data_port_w ) { write(space, 1, data); } + +const device_type YM2413 = &device_creator; + +ym2413_device::ym2413_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, YM2413, "YM2413", tag, owner, clock, "ym2413", __FILE__), + device_sound_interface(mconfig, *this) +{ +} + +//------------------------------------------------- +// device_config_complete - perform any +// operations now that the configuration is +// complete +//------------------------------------------------- + +void ym2413_device::device_config_complete() +{ +} diff --git a/src/devices/sound/2413intf.h b/src/devices/sound/2413intf.h new file mode 100644 index 00000000000..0edf7d1a696 --- /dev/null +++ b/src/devices/sound/2413intf.h @@ -0,0 +1,42 @@ +// license:BSD-3-Clause +// copyright-holders:Ernesto Corvi +#pragma once + +#ifndef __2413INTF_H__ +#define __2413INTF_H__ + +#include "emu.h" + +class ym2413_device : public device_t, + public device_sound_interface +{ +public: + ym2413_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + DECLARE_WRITE8_MEMBER( write ); + + DECLARE_WRITE8_MEMBER( register_port_w ); + DECLARE_WRITE8_MEMBER( data_port_w ); + + void _ym2413_update_request(); + +protected: + // device-level overrides + virtual void device_config_complete(); + virtual void device_start(); + virtual void device_stop(); + virtual void device_reset(); + + // sound stream update overrides + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + +private: + // internal state + sound_stream * m_stream; + void * m_chip; +}; + +extern const device_type YM2413; + + +#endif /* __2413INTF_H__ */ diff --git a/src/devices/sound/2608intf.c b/src/devices/sound/2608intf.c new file mode 100644 index 00000000000..4a2c25597bb --- /dev/null +++ b/src/devices/sound/2608intf.c @@ -0,0 +1,231 @@ +// license:BSD-3-Clause +// copyright-holders:Ernesto Corvi +/*************************************************************************** + + 2608intf.c + + The YM2608 emulator supports up to 2 chips. + Each chip has the following connections: + - Status Read / Control Write A + - Port Read / Data Write A + - Control Write B + - Data Write B + +***************************************************************************/ + +#include "2608intf.h" +#include "fm.h" + +static void psg_set_clock(void *param, int clock) +{ + ym2608_device *ym2608 = (ym2608_device *) param; + ym2608->ay_set_clock(clock); +} + +static void psg_write(void *param, int address, int data) +{ + ym2608_device *ym2608 = (ym2608_device *) param; + ym2608->ay8910_write_ym(address, data); +} + +static int psg_read(void *param) +{ + ym2608_device *ym2608 = (ym2608_device *) param; + return ym2608->ay8910_read_ym(); +} + +static void psg_reset(void *param) +{ + ym2608_device *ym2608 = (ym2608_device *) param; + ym2608->ay8910_reset_ym(); +} + +static const ssg_callbacks psgintf = +{ + psg_set_clock, + psg_write, + psg_read, + psg_reset +}; + +/* IRQ Handler */ +static void IRQHandler(void *param,int irq) +{ + ym2608_device *ym2608 = (ym2608_device *) param; + ym2608->_IRQHandler(irq); +} + +void ym2608_device::_IRQHandler(int irq) +{ + if (!m_irq_handler.isnull()) + m_irq_handler(irq); +} + +/* Timer overflow callback from timer.c */ +void ym2608_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch(id) + { + case 0: + ym2608_timer_over(m_chip,0); + break; + + case 1: + ym2608_timer_over(m_chip,1); + break; + } +} + +static void timer_handler(void *param,int c,int count,int clock) +{ + ym2608_device *ym2608 = (ym2608_device *) param; + ym2608->_timer_handler(c, count, clock); +} + +void ym2608_device::_timer_handler(int c,int count,int clock) +{ + if( count == 0 ) + { /* Reset FM Timer */ + m_timer[c]->enable(false); + } + else + { /* Start FM Timer */ + attotime period = attotime::from_hz(clock) * count; + + if (!m_timer[c]->enable(true)) + m_timer[c]->adjust(period); + } +} + +/* update request from fm.c */ +void ym2608_update_request(void *param) +{ + ym2608_device *ym2608 = (ym2608_device *) param; + ym2608->_ym2608_update_request(); +} + +void ym2608_device::_ym2608_update_request() +{ + m_stream->update(); +} + +//------------------------------------------------- +// sound_stream_update - handle a stream update +//------------------------------------------------- + +void ym2608_device::stream_generate(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + ym2608_update_one(m_chip, outputs, samples); +} + +void ym2608_device::device_post_load() +{ + ym2608_postload(m_chip); +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void ym2608_device::device_start() +{ + ay8910_device::device_start(); + + int rate = clock()/72; + void *pcmbufa; + int pcmsizea; + + m_irq_handler.resolve(); + + /* Timer Handler set */ + m_timer[0] = timer_alloc(0); + m_timer[1] = timer_alloc(1); + + /* stream system initialize */ + m_stream = machine().sound().stream_alloc(*this,0,2,rate, stream_update_delegate(FUNC(ym2608_device::stream_generate),this)); + /* setup adpcm buffers */ + pcmbufa = region()->base(); + pcmsizea = region()->bytes(); + + /* initialize YM2608 */ + m_chip = ym2608_init(this,this,clock(),rate, + pcmbufa,pcmsizea, + timer_handler,IRQHandler,&psgintf); + assert_always(m_chip != NULL, "Error creating YM2608 chip"); +} + +//------------------------------------------------- +// device_stop - device-specific stop +//------------------------------------------------- + +void ym2608_device::device_stop() +{ + ym2608_shutdown(m_chip); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void ym2608_device::device_reset() +{ + ym2608_reset_chip(m_chip); +} + + +READ8_MEMBER( ym2608_device::read ) +{ + return ym2608_read(m_chip, offset & 3); +} + +WRITE8_MEMBER( ym2608_device::write ) +{ + ym2608_write(m_chip, offset & 3, data); +} + +const device_type YM2608 = &device_creator; + +ym2608_device::ym2608_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : ay8910_device(mconfig, YM2608, "YM2608", tag, owner, clock, PSG_TYPE_YM, 1, 2, "ym2608", __FILE__), + m_irq_handler(*this) +{ +} + +ROM_START( ym2608 ) + ROM_REGION( 0x2000, "ym2608", 0 ) + /* + This data is derived from the chip's output - internal ROM can't be read. + It was verified, using real YM2608, that this ADPCM stream produces 100% correct output signal. + */ + // see YM2608_ADPCM_ROM_addr table in fm.c for current sample offsets + // original offset comments from Jarek: + // offset 0: + /* Source: 01BD.ROM */ + /* Length: 448 / 0x000001C0 */ + // offset 0x1C0: + /* Source: 02SD.ROM */ + /* Length: 640 / 0x00000280 */ + // offset 0x440: + /* Source: 04TOP.ROM */ + /* Length: 5952 / 0x00001740 */ + // offset 0x1B80: + /* Source: 08HH.ROM */ + /* Length: 384 / 0x00000180 */ + // offset 0x1D00 + /* Source: 10TOM.ROM */ + /* Length: 640 / 0x00000280 */ + // offset 0x1F80 + /* Source: 20RIM.ROM */ + /* Length: 128 / 0x00000080 */ + /* while this rom was dumped by output analysis, not decap, it was tested + by playing it back into the chip as an external adpcm sample and produced + an identical dac result. a decap would be nice to verify things 100%, + but there is currently no reason to think this rom dump is incorrect. */ + ROM_LOAD16_WORD( "ym2608_adpcm_rom.bin", 0x0000, 0x2000, CRC(23c9e0d8) SHA1(50b6c3e288eaa12ad275d4f323267bb72b0445df) ) +ROM_END + + +const rom_entry *ym2608_device::device_rom_region() const +{ + return ROM_NAME( ym2608 ); +} diff --git a/src/devices/sound/2608intf.h b/src/devices/sound/2608intf.h new file mode 100644 index 00000000000..ea610036d88 --- /dev/null +++ b/src/devices/sound/2608intf.h @@ -0,0 +1,53 @@ +// license:BSD-3-Clause +// copyright-holders:Ernesto Corvi +#pragma once + +#ifndef __2608INTF_H__ +#define __2608INTF_H__ + +#include "emu.h" +#include "ay8910.h" + +void ym2608_update_request(void *param); + +#define MCFG_YM2608_IRQ_HANDLER(_devcb) \ + devcb = &ym2608_device::set_irq_handler(*device, DEVCB_##_devcb); + +class ym2608_device : public ay8910_device +{ +public: + ym2608_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // static configuration helpers + template static devcb_base &set_irq_handler(device_t &device, _Object object) { return downcast(device).m_irq_handler.set_callback(object); } + + DECLARE_READ8_MEMBER( read ); + DECLARE_WRITE8_MEMBER( write ); + + void _IRQHandler(int irq); + void _timer_handler(int c,int count,int clock); + void _ym2608_update_request(); + +protected: + // device-level overrides + virtual const rom_entry *device_rom_region() const; + virtual void device_start(); + virtual void device_post_load(); + virtual void device_stop(); + virtual void device_reset(); + + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + void stream_generate(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); +private: + // internal state + sound_stream * m_stream; + emu_timer * m_timer[2]; + void * m_chip; + devcb_write_line m_irq_handler; +}; + +extern const device_type YM2608; + + +#endif /* __2608INTF_H__ */ diff --git a/src/devices/sound/2610intf.c b/src/devices/sound/2610intf.c new file mode 100644 index 00000000000..88f05e354cc --- /dev/null +++ b/src/devices/sound/2610intf.c @@ -0,0 +1,226 @@ +// license:BSD-3-Clause +// copyright-holders:Ernesto Corvi +/*************************************************************************** + + 2610intf.c + + The YM2610 emulator supports up to 2 chips. + Each chip has the following connections: + - Status Read / Control Write A + - Port Read / Data Write A + - Control Write B + - Data Write B + +***************************************************************************/ + +#include "2610intf.h" +#include "fm.h" + +static void psg_set_clock(void *param, int clock) +{ + ym2610_device *ym2610 = (ym2610_device *) param; + ym2610->ay_set_clock(clock); +} + +static void psg_write(void *param, int address, int data) +{ + ym2610_device *ym2610 = (ym2610_device *) param; + ym2610->ay8910_write_ym(address, data); +} + +static int psg_read(void *param) +{ + ym2610_device *ym2610 = (ym2610_device *) param; + return ym2610->ay8910_read_ym(); +} + +static void psg_reset(void *param) +{ + ym2610_device *ym2610 = (ym2610_device *) param; + ym2610->ay8910_reset_ym(); +} + +static const ssg_callbacks psgintf = +{ + psg_set_clock, + psg_write, + psg_read, + psg_reset +}; + +/*------------------------- TM2610 -------------------------------*/ +/* IRQ Handler */ +static void IRQHandler(void *param,int irq) +{ + ym2610_device *ym2610 = (ym2610_device *) param; + ym2610->_IRQHandler(irq); +} + +void ym2610_device::_IRQHandler(int irq) +{ + if (!m_irq_handler.isnull()) + m_irq_handler(irq); +} + +/* Timer overflow callback from timer.c */ +void ym2610_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch(id) + { + case 0: + ym2610_timer_over(m_chip,0); + break; + + case 1: + ym2610_timer_over(m_chip,1); + break; + } +} + +static void timer_handler(void *param,int c,int count,int clock) +{ + ym2610_device *ym2610 = (ym2610_device *) param; + ym2610->_timer_handler(c, count, clock); +} + +void ym2610_device::_timer_handler(int c,int count,int clock) +{ + if( count == 0 ) + { /* Reset FM Timer */ + m_timer[c]->enable(false); + } + else + { /* Start FM Timer */ + attotime period = attotime::from_hz(clock) * count; + + if (!m_timer[c]->enable(true)) + m_timer[c]->adjust(period); + } +} + +/* update request from fm.c */ +void ym2610_update_request(void *param) +{ + ym2610_device *ym2610 = (ym2610_device *) param; + ym2610->_ym2610_update_request(); +} + +void ym2610_device::_ym2610_update_request() +{ + m_stream->update(); +} + +//------------------------------------------------- +// sound_stream_update - handle a stream update +//------------------------------------------------- +void ym2610_device::stream_generate(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + ym2610_update_one(m_chip, outputs, samples); +} + +//------------------------------------------------- +// sound_stream_update - handle a stream update +//------------------------------------------------- + +void ym2610b_device::stream_generate(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + ym2610b_update_one(m_chip, outputs, samples); +} + + +void ym2610_device::device_post_load() +{ + ym2610_postload(m_chip); +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void ym2610_device::device_start() +{ + ay8910_device::device_start(); + + int rate = clock()/72; + void *pcmbufa,*pcmbufb; + int pcmsizea,pcmsizeb; + std::string name(tag()); + + m_irq_handler.resolve(); + + /* Timer Handler set */ + m_timer[0] = timer_alloc(0); + m_timer[1] = timer_alloc(1); + + /* stream system initialize */ + m_stream = machine().sound().stream_alloc(*this,0,2,rate, stream_update_delegate(FUNC(ym2610_device::stream_generate),this)); + /* setup adpcm buffers */ + pcmbufa = region()->base(); + pcmsizea = region()->bytes(); + name.append(".deltat"); + pcmbufb = (void *)(machine().root_device().memregion(name.c_str())->base()); + pcmsizeb = machine().root_device().memregion(name.c_str())->bytes(); + if (pcmbufb == NULL || pcmsizeb == 0) + { + pcmbufb = pcmbufa; + pcmsizeb = pcmsizea; + } + + /**** initialize YM2610 ****/ + m_chip = ym2610_init(this,this,clock(),rate, + pcmbufa,pcmsizea,pcmbufb,pcmsizeb, + timer_handler,IRQHandler,&psgintf); + assert_always(m_chip != NULL, "Error creating YM2610 chip"); +} + +//------------------------------------------------- +// device_stop - device-specific stop +//------------------------------------------------- + +void ym2610_device::device_stop() +{ + ym2610_shutdown(m_chip); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void ym2610_device::device_reset() +{ + ym2610_reset_chip(m_chip); +} + + +READ8_MEMBER( ym2610_device::read ) +{ + return ym2610_read(m_chip, offset & 3); +} + +WRITE8_MEMBER( ym2610_device::write ) +{ + ym2610_write(m_chip, offset & 3, data); +} + + +const device_type YM2610 = &device_creator; + +ym2610_device::ym2610_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : ay8910_device(mconfig, YM2610, "YM2610", tag, owner, clock, PSG_TYPE_YM, 1, 0, "ym2610", __FILE__), + m_irq_handler(*this) +{ +} + +ym2610_device::ym2610_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : ay8910_device(mconfig, type, name, tag, owner, clock, PSG_TYPE_YM, 1, 0, shortname, source), + m_irq_handler(*this) +{ +} + +const device_type YM2610B = &device_creator; + +ym2610b_device::ym2610b_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : ym2610_device(mconfig, YM2610B, "YM2610B", tag, owner, clock, "ym2610b", __FILE__) +{ +} diff --git a/src/devices/sound/2610intf.h b/src/devices/sound/2610intf.h new file mode 100644 index 00000000000..40842f48411 --- /dev/null +++ b/src/devices/sound/2610intf.h @@ -0,0 +1,65 @@ +// license:BSD-3-Clause +// copyright-holders:Ernesto Corvi +#pragma once + +#ifndef __2610INTF_H__ +#define __2610INTF_H__ + +#include "emu.h" +#include "ay8910.h" + +void ym2610_update_request(void *param); + +#define MCFG_YM2610_IRQ_HANDLER(_devcb) \ + devcb = &ym2610_device::set_irq_handler(*device, DEVCB_##_devcb); + +class ym2610_device : public ay8910_device +{ +public: + ym2610_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + ym2610_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + // static configuration helpers + template static devcb_base &set_irq_handler(device_t &device, _Object object) { return downcast(device).m_irq_handler.set_callback(object); } + + DECLARE_READ8_MEMBER( read ); + DECLARE_WRITE8_MEMBER( write ); + + void _IRQHandler(int irq); + void _timer_handler(int c,int count,int clock); + void _ym2610_update_request(); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_post_load(); + virtual void device_stop(); + virtual void device_reset(); + + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + virtual void stream_generate(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + + void * m_chip; + +private: + // internal state + sound_stream * m_stream; + emu_timer * m_timer[2]; + devcb_write_line m_irq_handler; +}; + +extern const device_type YM2610; + +class ym2610b_device : public ym2610_device +{ +public: + ym2610b_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual void stream_generate(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); +}; + +extern const device_type YM2610B; + + +#endif /* __2610INTF_H__ */ diff --git a/src/devices/sound/2612intf.c b/src/devices/sound/2612intf.c new file mode 100644 index 00000000000..b5464d4e824 --- /dev/null +++ b/src/devices/sound/2612intf.c @@ -0,0 +1,183 @@ +// license:BSD-3-Clause +// copyright-holders:Ernesto Corvi +/*************************************************************************** + + 2612intf.c + + The YM2612 emulator supports up to 2 chips. + Each chip has the following connections: + - Status Read / Control Write A + - Port Read / Data Write A + - Control Write B + - Data Write B + +***************************************************************************/ + +#include "2612intf.h" +#include "fm.h" + +/*------------------------- TM2612 -------------------------------*/ +/* IRQ Handler */ +static void IRQHandler(void *param,int irq) +{ + ym2612_device *ym2612 = (ym2612_device *) param; + ym2612->_IRQHandler(irq); +} + +void ym2612_device::_IRQHandler(int irq) +{ + if (!m_irq_handler.isnull()) + m_irq_handler(irq); +} + +/* Timer overflow callback from timer.c */ +void ym2612_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch(id) + { + case 0: + ym2612_timer_over(m_chip,0); + break; + + case 1: + ym2612_timer_over(m_chip,1); + break; + } +} + +static void timer_handler(void *param,int c,int count,int clock) +{ + ym2612_device *ym2612 = (ym2612_device *) param; + ym2612->_timer_handler(c, count, clock); +} + +void ym2612_device::_timer_handler(int c,int count,int clock) +{ + if( count == 0 ) + { /* Reset FM Timer */ + m_timer[c]->enable(false); + } + else + { /* Start FM Timer */ + attotime period = attotime::from_hz(clock) * count; + + if (!m_timer[c]->enable(true)) + m_timer[c]->adjust(period); + } +} + +/* update request from fm.c */ +void ym2612_update_request(void *param) +{ + ym2612_device *ym2612 = (ym2612_device *) param; + ym2612->_ym2612_update_request(); +} + +void ym2612_device::_ym2612_update_request() +{ + m_stream->update(); +} + +//------------------------------------------------- +// sound_stream_update - handle a stream update +//------------------------------------------------- + +void ym2612_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + ym2612_update_one(m_chip, outputs, samples); +} + + +void ym2612_device::device_post_load() +{ + ym2612_postload(m_chip); +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void ym2612_device::device_start() +{ + int rate = clock()/72; + + m_irq_handler.resolve(); + + /* FM init */ + /* Timer Handler set */ + m_timer[0] = timer_alloc(0); + m_timer[1] = timer_alloc(1); + + /* stream system initialize */ + m_stream = machine().sound().stream_alloc(*this,0,2,rate); + + /**** initialize YM2612 ****/ + m_chip = ym2612_init(this,this,clock(),rate,timer_handler,IRQHandler); + assert_always(m_chip != NULL, "Error creating YM2612 chip"); +} + + +//------------------------------------------------- +// device_stop - device-specific stop +//------------------------------------------------- + +void ym2612_device::device_stop() +{ + ym2612_shutdown(m_chip); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void ym2612_device::device_reset() +{ + ym2612_reset_chip(m_chip); +} + + +READ8_MEMBER( ym2612_device::read ) +{ + return ym2612_read(m_chip, offset & 3); +} + +WRITE8_MEMBER( ym2612_device::write ) +{ + ym2612_write(m_chip, offset & 3, data); +} + + +const device_type YM2612 = &device_creator; + +ym2612_device::ym2612_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, YM2612, "YM2612", tag, owner, clock, "ym2612", __FILE__), + device_sound_interface(mconfig, *this), + m_irq_handler(*this) +{ +} + +ym2612_device::ym2612_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_sound_interface(mconfig, *this), + m_irq_handler(*this) +{ +} + +//------------------------------------------------- +// device_config_complete - perform any +// operations now that the configuration is +// complete +//------------------------------------------------- + +void ym2612_device::device_config_complete() +{ +} + + +const device_type YM3438 = &device_creator; + +ym3438_device::ym3438_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : ym2612_device(mconfig, YM3438, "YM3438", tag, owner, clock, "ym3438", __FILE__) +{ +} diff --git a/src/devices/sound/2612intf.h b/src/devices/sound/2612intf.h new file mode 100644 index 00000000000..8199172044d --- /dev/null +++ b/src/devices/sound/2612intf.h @@ -0,0 +1,64 @@ +// license:BSD-3-Clause +// copyright-holders:Ernesto Corvi +#pragma once + +#ifndef __2612INTF_H__ +#define __2612INTF_H__ + +#include "emu.h" + +void ym2612_update_request(void *param); + +#define MCFG_YM2612_IRQ_HANDLER(_devcb) \ + devcb = &ym2612_device::set_irq_handler(*device, DEVCB_##_devcb); + +class ym2612_device : public device_t, + public device_sound_interface +{ +public: + ym2612_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + ym2612_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + // static configuration helpers + template static devcb_base &set_irq_handler(device_t &device, _Object object) { return downcast(device).m_irq_handler.set_callback(object); } + + DECLARE_READ8_MEMBER( read ); + DECLARE_WRITE8_MEMBER( write ); + + void _IRQHandler(int irq); + void _timer_handler(int c,int count,int clock); + void _ym2612_update_request(); + +protected: + // device-level overrides + virtual void device_config_complete(); + virtual void device_start(); + virtual void device_post_load(); + virtual void device_stop(); + virtual void device_reset(); + + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + // sound stream update overrides + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + +private: + sound_stream * m_stream; + emu_timer * m_timer[2]; + void * m_chip; + devcb_write_line m_irq_handler; +}; + +extern const device_type YM2612; + + +class ym3438_device : public ym2612_device +{ +public: + ym3438_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +extern const device_type YM3438; + + +#endif /* __2612INTF_H__ */ diff --git a/src/devices/sound/262intf.c b/src/devices/sound/262intf.c new file mode 100644 index 00000000000..b15b6f4deda --- /dev/null +++ b/src/devices/sound/262intf.c @@ -0,0 +1,155 @@ +// license:BSD-3-Clause +// copyright-holders:Ernesto Corvi +/*************************************************************************** + + 262intf.c + + MAME interface for YMF262 (OPL3) emulator + +***************************************************************************/ +#include "emu.h" +#include "262intf.h" +#include "ymf262.h" + + +/* IRQ Handler */ +static void IRQHandler(void *param,int irq) +{ + ymf262_device *ymf262 = (ymf262_device *) param; + ymf262->_IRQHandler(irq); +} + +void ymf262_device::_IRQHandler(int irq) +{ + if (!m_irq_handler.isnull()) + m_irq_handler(irq); +} + +/* Timer overflow callback from timer.c */ +void ymf262_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch(id) + { + case 0: + ymf262_timer_over(m_chip,0); + break; + + case 1: + ymf262_timer_over(m_chip,1); + break; + } +} + + +static void timer_handler(void *param, int c, const attotime &period) +{ + ymf262_device *ymf262 = (ymf262_device *) param; + ymf262->_timer_handler(c, period); +} + +void ymf262_device::_timer_handler(int c, const attotime &period) +{ + if( period == attotime::zero ) + { /* Reset FM Timer */ + m_timer[c]->enable(false); + } + else + { /* Start FM Timer */ + m_timer[c]->adjust(period); + } +} + +void ymf262_update_request(void *param, int interval) +{ + ymf262_device *ymf262 = (ymf262_device *) param; + ymf262->_ymf262_update_request(); +} + +void ymf262_device::_ymf262_update_request() +{ + m_stream->update(); +} + + + +//------------------------------------------------- +// sound_stream_update - handle a stream update +//------------------------------------------------- + +void ymf262_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + ymf262_update_one(m_chip, outputs, samples); +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void ymf262_device::device_start() +{ + int rate = clock()/288; + + m_irq_handler.resolve(); + + /* stream system initialize */ + m_chip = ymf262_init(this,clock(),rate); + assert_always(m_chip != NULL, "Error creating YMF262 chip"); + + m_stream = machine().sound().stream_alloc(*this,0,4,rate); + + /* YMF262 setup */ + ymf262_set_timer_handler (m_chip, timer_handler, this); + ymf262_set_irq_handler (m_chip, IRQHandler, this); + ymf262_set_update_handler(m_chip, ymf262_update_request, this); + + m_timer[0] = timer_alloc(0); + m_timer[1] = timer_alloc(1); +} + +//------------------------------------------------- +// device_stop - device-specific stop +//------------------------------------------------- + +void ymf262_device::device_stop() +{ + ymf262_shutdown(m_chip); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void ymf262_device::device_reset() +{ + ymf262_reset_chip(m_chip); +} + + +READ8_MEMBER( ymf262_device::read ) +{ + return ymf262_read(m_chip, offset & 3); +} + +WRITE8_MEMBER( ymf262_device::write ) +{ + ymf262_write(m_chip, offset & 3, data); +} + +const device_type YMF262 = &device_creator; + +ymf262_device::ymf262_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, YMF262, "YMF262", tag, owner, clock, "ymf262", __FILE__), + device_sound_interface(mconfig, *this), + m_irq_handler(*this) +{ +} + +//------------------------------------------------- +// device_config_complete - perform any +// operations now that the configuration is +// complete +//------------------------------------------------- + +void ymf262_device::device_config_complete() +{ +} diff --git a/src/devices/sound/262intf.h b/src/devices/sound/262intf.h new file mode 100644 index 00000000000..2ff45f3190c --- /dev/null +++ b/src/devices/sound/262intf.h @@ -0,0 +1,51 @@ +// license:BSD-3-Clause +// copyright-holders:Ernesto Corvi +#pragma once + +#ifndef __262INTF_H__ +#define __262INTF_H__ + +#include "emu.h" + +#define MCFG_YMF262_IRQ_HANDLER(_devcb) \ + devcb = &ymf262_device::set_irq_handler(*device, DEVCB_##_devcb); + +class ymf262_device : public device_t, + public device_sound_interface +{ +public: + ymf262_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // static configuration helpers + template static devcb_base &set_irq_handler(device_t &device, _Object object) { return downcast(device).m_irq_handler.set_callback(object); } + + DECLARE_READ8_MEMBER( read ); + DECLARE_WRITE8_MEMBER( write ); + + void _IRQHandler(int irq); + void _timer_handler(int c, const attotime &period); + void _ymf262_update_request(); + + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + +protected: + // device-level overrides + virtual void device_config_complete(); + virtual void device_start(); + virtual void device_stop(); + virtual void device_reset(); + + // sound stream update overrides + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); +private: + // internal state + sound_stream * m_stream; + emu_timer * m_timer[2]; + void * m_chip; + devcb_write_line m_irq_handler; +}; + +extern const device_type YMF262; + + +#endif /* __262INTF_H__ */ diff --git a/src/devices/sound/315-5641.c b/src/devices/sound/315-5641.c new file mode 100644 index 00000000000..a0de2fce330 --- /dev/null +++ b/src/devices/sound/315-5641.c @@ -0,0 +1,70 @@ +/* Sega 315-5641 / D77591 / 9442CA010 */ + +#include "emu.h" +#include "315-5641.h" + +const device_type SEGA_315_5641_PCM = &device_creator; + +sega_315_5641_pcm_device::sega_315_5641_pcm_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : upd7759_device(mconfig, SEGA_315_5641_PCM, "315-5641 PCM", tag, owner, clock, "315-5641_pcm", __FILE__) +{ +} + +void sega_315_5641_pcm_device::device_start() +{ + save_item(NAME(m_fifo_data), 0x40); + save_item(NAME(m_fifo_read)); + save_item(NAME(m_fifo_write)); + + upd7759_device::device_start(); +} + +void sega_315_5641_pcm_device::advance_state() +{ + switch (m_state) + { + case STATE_DROP_DRQ: + if (m_rombase == NULL) + { + // Slave Mode: get data from FIFO buffer + UINT8 fiforead = (m_fifo_read + 1) & 0x3F; + if (fiforead != m_fifo_write) + { + m_fifo_in = m_fifo_data[fiforead]; + m_fifo_read = fiforead; + } + } + break; + } + + upd775x_device::advance_state(); +} + + +WRITE8_MEMBER( sega_315_5641_pcm_device::port_w ) +{ + if (m_rombase != NULL) + { + /* update the FIFO value */ + m_fifo_in = data; + } + else + { + m_fifo_data[m_fifo_write++] = data; + m_fifo_write &= 0x3F; + } +} + + +UINT8 sega_315_5641_pcm_device::get_fifo_space() +{ + return (m_fifo_read - m_fifo_write) & 0x3F; +} + +void sega_315_5641_pcm_device::device_reset() +{ + m_fifo_read = 0x3F; + m_fifo_write = 0x00; + + upd775x_device::device_reset(); +} \ No newline at end of file diff --git a/src/devices/sound/315-5641.h b/src/devices/sound/315-5641.h new file mode 100644 index 00000000000..c8fb0f6270f --- /dev/null +++ b/src/devices/sound/315-5641.h @@ -0,0 +1,30 @@ +/* Sega 315-5641 / D77591 / 9442CA010 */ + +// this is the PICO sound chip, we are not sure if it's the same as a 7759 or not, it requires FIFO logic +// which the 7759 does _not_ have but it is possible that is handled somewhere else on the PICO hardawre. + +#include "upd7759.h" + + +class sega_315_5641_pcm_device : public upd7759_device +{ +public: + sega_315_5641_pcm_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + UINT8 get_fifo_space(); + void advance_state(); + DECLARE_WRITE8_MEMBER(port_w); + + UINT8 m_fifo_data[0x40]; + UINT8 m_fifo_read; // last read offset (will read in m_fifo_read+1) + UINT8 m_fifo_write; // write offset + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + +}; + +extern const device_type SEGA_315_5641_PCM; \ No newline at end of file diff --git a/src/devices/sound/3526intf.c b/src/devices/sound/3526intf.c new file mode 100644 index 00000000000..d90b053a4d3 --- /dev/null +++ b/src/devices/sound/3526intf.c @@ -0,0 +1,173 @@ +// license:BSD-3-Clause +// copyright-holders:Ernesto Corvi +/****************************************************************************** +* FILE +* Yamaha 3812 emulator interface - MAME VERSION +* +* CREATED BY +* Ernesto Corvi +* +* UPDATE LOG +* JB 28-04-2002 Fixed simultaneous usage of all three different chip types. +* Used real sample rate when resample filter is active. +* AAT 12-28-2001 Protected Y8950 from accessing unmapped port and keyboard handlers. +* CHS 1999-01-09 Fixes new ym3812 emulation interface. +* CHS 1998-10-23 Mame streaming sound chip update +* EC 1998 Created Interface +* +* NOTES +* +******************************************************************************/ +#include "3526intf.h" +#include "fm.h" +#include "fmopl.h" + + +/* IRQ Handler */ +static void IRQHandler(void *param,int irq) +{ + ym3526_device *ym3526 = (ym3526_device *) param; + ym3526->_IRQHandler(irq); +} + +void ym3526_device::_IRQHandler(int irq) +{ + if (!m_irq_handler.isnull()) + m_irq_handler(irq); +} + +/* Timer overflow callback from timer.c */ +void ym3526_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch(id) + { + case 0: + ym3526_timer_over(m_chip,0); + break; + + case 1: + ym3526_timer_over(m_chip,1); + break; + } +} + +static void timer_handler(void *param,int c,const attotime &period) +{ + ym3526_device *ym3526 = (ym3526_device *) param; + ym3526->_timer_handler(c, period); +} + +void ym3526_device::_timer_handler(int c,const attotime &period) +{ + if( period == attotime::zero ) + { /* Reset FM Timer */ + m_timer[c]->enable(false); + } + else + { /* Start FM Timer */ + m_timer[c]->adjust(period); + } +} + +/* update request from fm.c */ +void ym3526_update_request(void *param, int interval) +{ + ym3526_device *ym3526 = (ym3526_device *) param; + ym3526->_ym3526_update_request(); +} + +void ym3526_device::_ym3526_update_request() +{ + m_stream->update(); +} + + + +//------------------------------------------------- +// sound_stream_update - handle a stream update +//------------------------------------------------- + +void ym3526_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + ym3526_update_one(m_chip, outputs[0], samples); +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void ym3526_device::device_start() +{ + int rate = clock()/72; + + // resolve callbacks + m_irq_handler.resolve(); + + /* stream system initialize */ + m_chip = ym3526_init(this,clock(),rate); + assert_always(m_chip != NULL, "Error creating YM3526 chip"); + + m_stream = machine().sound().stream_alloc(*this,0,1,rate); + /* YM3526 setup */ + ym3526_set_timer_handler (m_chip, timer_handler, this); + ym3526_set_irq_handler (m_chip, IRQHandler, this); + ym3526_set_update_handler(m_chip, ym3526_update_request, this); + + m_timer[0] = timer_alloc(0); + m_timer[1] = timer_alloc(1); +} + +//------------------------------------------------- +// device_stop - device-specific stop +//------------------------------------------------- + +void ym3526_device::device_stop() +{ + ym3526_shutdown(m_chip); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void ym3526_device::device_reset() +{ + ym3526_reset_chip(m_chip); +} + + +READ8_MEMBER( ym3526_device::read ) +{ + return ym3526_read(m_chip, offset & 1); +} + +WRITE8_MEMBER( ym3526_device::write ) +{ + ym3526_write(m_chip, offset & 1, data); +} + +READ8_MEMBER( ym3526_device::status_port_r ) { return read(space, 0); } +READ8_MEMBER( ym3526_device::read_port_r ) { return read(space, 1); } +WRITE8_MEMBER( ym3526_device::control_port_w ) { write(space, 0, data); } +WRITE8_MEMBER( ym3526_device::write_port_w ) { write(space, 1, data); } + + +const device_type YM3526 = &device_creator; + +ym3526_device::ym3526_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, YM3526, "YM3526", tag, owner, clock, "ym3526", __FILE__), + device_sound_interface(mconfig, *this), + m_irq_handler(*this) +{ +} + +//------------------------------------------------- +// device_config_complete - perform any +// operations now that the configuration is +// complete +//------------------------------------------------- + +void ym3526_device::device_config_complete() +{ +} diff --git a/src/devices/sound/3526intf.h b/src/devices/sound/3526intf.h new file mode 100644 index 00000000000..4f0d59f1c74 --- /dev/null +++ b/src/devices/sound/3526intf.h @@ -0,0 +1,57 @@ +// license:BSD-3-Clause +// copyright-holders:Ernesto Corvi +#pragma once + +#ifndef __3526INTF_H__ +#define __3526INTF_H__ + +#include "emu.h" + +#define MCFG_YM3526_IRQ_HANDLER(_devcb) \ + devcb = &ym3526_device::set_irq_handler(*device, DEVCB_##_devcb); + +class ym3526_device : public device_t, + public device_sound_interface +{ +public: + ym3526_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // static configuration helpers + template static devcb_base &set_irq_handler(device_t &device, _Object object) { return downcast(device).m_irq_handler.set_callback(object); } + + DECLARE_READ8_MEMBER( read ); + DECLARE_WRITE8_MEMBER( write ); + + DECLARE_READ8_MEMBER( status_port_r ); + DECLARE_READ8_MEMBER( read_port_r ); + DECLARE_WRITE8_MEMBER( control_port_w ); + DECLARE_WRITE8_MEMBER( write_port_w ); + + void _IRQHandler(int irq); + void _timer_handler(int c,const attotime &period); + void _ym3526_update_request(); + +protected: + // device-level overrides + virtual void device_config_complete(); + virtual void device_start(); + virtual void device_stop(); + virtual void device_reset(); + + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + // sound stream update overrides + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + +private: + // internal state + sound_stream * m_stream; + emu_timer * m_timer[2]; + void * m_chip; + devcb_write_line m_irq_handler; +}; + +extern const device_type YM3526; + + +#endif /* __3526INTF_H__ */ diff --git a/src/devices/sound/3812intf.c b/src/devices/sound/3812intf.c new file mode 100644 index 00000000000..ee4a9e3d5af --- /dev/null +++ b/src/devices/sound/3812intf.c @@ -0,0 +1,171 @@ +// license:BSD-3-Clause +// copyright-holders:Ernesto Corvi +/****************************************************************************** +* FILE +* Yamaha 3812 emulator interface - MAME VERSION +* +* CREATED BY +* Ernesto Corvi +* +* UPDATE LOG +* JB 28-04-2002 Fixed simultaneous usage of all three different chip types. +* Used real sample rate when resample filter is active. +* AAT 12-28-2001 Protected Y8950 from accessing unmapped port and keyboard handlers. +* CHS 1999-01-09 Fixes new ym3812 emulation interface. +* CHS 1998-10-23 Mame streaming sound chip update +* EC 1998 Created Interface +* +* NOTES +* +******************************************************************************/ +#include "emu.h" +#include "3812intf.h" +#include "fm.h" +#include "sound/fmopl.h" + + +static void IRQHandler(void *param,int irq) +{ + ym3812_device *ym3812 = (ym3812_device *) param; + ym3812->_IRQHandler(irq); +} + +void ym3812_device::_IRQHandler(int irq) +{ + if (!m_irq_handler.isnull()) + m_irq_handler(irq); +} + +/* Timer overflow callback from timer.c */ +void ym3812_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch(id) + { + case 0: + ym3812_timer_over(m_chip,0); + break; + + case 1: + ym3812_timer_over(m_chip,1); + break; + } +} + +static void timer_handler(void *param,int c,const attotime &period) +{ + ym3812_device *ym3812 = (ym3812_device *) param; + ym3812->_timer_handler(c, period); +} + +void ym3812_device::_timer_handler(int c, const attotime &period) +{ + if( period == attotime::zero ) + { /* Reset FM Timer */ + m_timer[c]->enable(false); + } + else + { /* Start FM Timer */ + m_timer[c]->adjust(period); + } +} + + +static void ym3812_update_request(void * param, int interval) +{ + ym3812_device *ym3812 = (ym3812_device *) param; + ym3812->_ym3812_update_request(); +} + +void ym3812_device::_ym3812_update_request() +{ + m_stream->update(); +} + + +//------------------------------------------------- +// sound_stream_update - handle a stream update +//------------------------------------------------- + +void ym3812_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + ym3812_update_one(m_chip, outputs[0], samples); +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void ym3812_device::device_start() +{ + int rate = clock()/72; + + m_irq_handler.resolve(); + + /* stream system initialize */ + m_chip = ym3812_init(this,clock(),rate); + assert_always(m_chip != NULL, "Error creating YM3812 chip"); + + m_stream = machine().sound().stream_alloc(*this,0,1,rate); + + /* YM3812 setup */ + ym3812_set_timer_handler (m_chip, timer_handler, this); + ym3812_set_irq_handler (m_chip, IRQHandler, this); + ym3812_set_update_handler(m_chip, ym3812_update_request, this); + + m_timer[0] = timer_alloc(0); + m_timer[1] = timer_alloc(1); +} + +//------------------------------------------------- +// device_stop - device-specific stop +//------------------------------------------------- + +void ym3812_device::device_stop() +{ + ym3812_shutdown(m_chip); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void ym3812_device::device_reset() +{ + ym3812_reset_chip(m_chip); +} + + +READ8_MEMBER( ym3812_device::read ) +{ + return ym3812_read(m_chip, offset & 1); +} + +WRITE8_MEMBER( ym3812_device::write ) +{ + ym3812_write(m_chip, offset & 1, data); +} + +READ8_MEMBER( ym3812_device::status_port_r ) { return read(space, 0); } +READ8_MEMBER( ym3812_device::read_port_r ) { return read(space, 1); } +WRITE8_MEMBER( ym3812_device::control_port_w ) { write(space, 0, data); } +WRITE8_MEMBER( ym3812_device::write_port_w ) { write( space, 1, data); } + + +const device_type YM3812 = &device_creator; + +ym3812_device::ym3812_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, YM3812, "YM3812", tag, owner, clock, "ym3812", __FILE__), + device_sound_interface(mconfig, *this), + m_irq_handler(*this) +{ +} + +//------------------------------------------------- +// device_config_complete - perform any +// operations now that the configuration is +// complete +//------------------------------------------------- + +void ym3812_device::device_config_complete() +{ +} diff --git a/src/devices/sound/3812intf.h b/src/devices/sound/3812intf.h new file mode 100644 index 00000000000..ee87e8a43d9 --- /dev/null +++ b/src/devices/sound/3812intf.h @@ -0,0 +1,56 @@ +// license:BSD-3-Clause +// copyright-holders:Ernesto Corvi +#pragma once + +#ifndef __3812INTF_H__ +#define __3812INTF_H__ + +#include "emu.h" + +#define MCFG_YM3812_IRQ_HANDLER(_devcb) \ + devcb = &ym3812_device::set_irq_handler(*device, DEVCB_##_devcb); + +class ym3812_device : public device_t, + public device_sound_interface +{ +public: + ym3812_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // static configuration helpers + template static devcb_base &set_irq_handler(device_t &device, _Object object) { return downcast(device).m_irq_handler.set_callback(object); } + + DECLARE_READ8_MEMBER( read ); + DECLARE_WRITE8_MEMBER( write ); + + DECLARE_READ8_MEMBER( status_port_r ); + DECLARE_READ8_MEMBER( read_port_r ); + DECLARE_WRITE8_MEMBER( control_port_w ); + DECLARE_WRITE8_MEMBER( write_port_w ); + + void _IRQHandler(int irq); + void _timer_handler(int c, const attotime &period); + void _ym3812_update_request(); + +protected: + // device-level overrides + virtual void device_config_complete(); + virtual void device_start(); + virtual void device_stop(); + virtual void device_reset(); + + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + // sound stream update overrides + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + +private: + sound_stream * m_stream; + emu_timer * m_timer[2]; + void * m_chip; + devcb_write_line m_irq_handler; +}; + +extern const device_type YM3812; + + +#endif /* __3812INTF_H__ */ diff --git a/src/devices/sound/8950intf.c b/src/devices/sound/8950intf.c new file mode 100644 index 00000000000..172ee03ef25 --- /dev/null +++ b/src/devices/sound/8950intf.c @@ -0,0 +1,226 @@ +// license:BSD-3-Clause +// copyright-holders:Ernesto Corvi +/****************************************************************************** +* FILE +* Yamaha 3812 emulator interface - MAME VERSION +* +* CREATED BY +* Ernesto Corvi +* +* UPDATE LOG +* JB 28-04-2002 Fixed simultaneous usage of all three different chip types. +* Used real sample rate when resample filter is active. +* AAT 12-28-2001 Protected Y8950 from accessing unmapped port and keyboard handlers. +* CHS 1999-01-09 Fixes new ym3812 emulation interface. +* CHS 1998-10-23 Mame streaming sound chip update +* EC 1998 Created Interface +* +* NOTES +* +******************************************************************************/ +#include "8950intf.h" +#include "fm.h" +#include "fmopl.h" + + +static void IRQHandler(void *param,int irq) +{ + y8950_device *y8950 = (y8950_device *) param; + y8950->_IRQHandler(irq); +} + +void y8950_device::_IRQHandler(int irq) +{ + m_irq_handler(irq); +} + +void y8950_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch(id) + { + case 0: + y8950_timer_over(m_chip,0); + break; + + case 1: + y8950_timer_over(m_chip,1); + break; + } +} + +static void timer_handler(void *param, int c, const attotime &period) +{ + y8950_device *y8950 = (y8950_device *) param; + y8950->_timer_handler(c, period); +} + +void y8950_device::_timer_handler(int c, const attotime &period) +{ + if( period == attotime::zero ) + { /* Reset FM Timer */ + m_timer[c]->enable(false); + } + else + { /* Start FM Timer */ + m_timer[c]->adjust(period); + } +} + + +static unsigned char Y8950PortHandler_r(void *param) +{ + y8950_device *y8950 = (y8950_device *) param; + return y8950->_Y8950PortHandler_r(); +} + +unsigned char y8950_device::_Y8950PortHandler_r() +{ + return m_io_read_handler(0); +} + +static void Y8950PortHandler_w(void *param,unsigned char data) +{ + y8950_device *y8950 = (y8950_device *) param; + y8950->_Y8950PortHandler_w(data); +} + +void y8950_device::_Y8950PortHandler_w(unsigned char data) +{ + m_io_write_handler((offs_t)0,data); +} + +static unsigned char Y8950KeyboardHandler_r(void *param) +{ + y8950_device *y8950 = (y8950_device *) param; + return y8950->_Y8950KeyboardHandler_r(); +} + +unsigned char y8950_device::_Y8950KeyboardHandler_r() +{ + return m_keyboard_read_handler(0); +} + +static void Y8950KeyboardHandler_w(void *param,unsigned char data) +{ + y8950_device *y8950 = (y8950_device *) param; + y8950->_Y8950KeyboardHandler_w(data); +} + +void y8950_device::_Y8950KeyboardHandler_w(unsigned char data) +{ + m_keyboard_write_handler((offs_t)0,data); +} + +//------------------------------------------------- +// sound_stream_update - handle a stream update +//------------------------------------------------- + +void y8950_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + y8950_update_one(m_chip, outputs[0], samples); +} + +static void y8950_update_request(void *param, int interval) +{ + y8950_device *y8950 = (y8950_device *) param; + y8950->_y8950_update_request(); +} + +void y8950_device::_y8950_update_request() +{ + m_stream->update(); +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void y8950_device::device_start() +{ + int rate = clock()/72; + + m_irq_handler.resolve_safe(); + m_keyboard_read_handler.resolve_safe(0); + m_keyboard_write_handler.resolve_safe(); + m_io_read_handler.resolve_safe(0); + m_io_write_handler.resolve_safe(); + + /* stream system initialize */ + m_chip = y8950_init(this,clock(),rate); + assert_always(m_chip != NULL, "Error creating Y8950 chip"); + + /* ADPCM ROM data */ + y8950_set_delta_t_memory(m_chip, region()->base(), region()->bytes()); + + m_stream = machine().sound().stream_alloc(*this,0,1,rate); + /* port and keyboard handler */ + y8950_set_port_handler(m_chip, Y8950PortHandler_w, Y8950PortHandler_r, this); + y8950_set_keyboard_handler(m_chip, Y8950KeyboardHandler_w, Y8950KeyboardHandler_r, this); + + /* Y8950 setup */ + y8950_set_timer_handler (m_chip, timer_handler, this); + y8950_set_irq_handler (m_chip, IRQHandler, this); + y8950_set_update_handler(m_chip, y8950_update_request, this); + + m_timer[0] = timer_alloc(0); + m_timer[1] = timer_alloc(1); +} + +//------------------------------------------------- +// device_stop - device-specific stop +//------------------------------------------------- + +void y8950_device::device_stop() +{ + y8950_shutdown(m_chip); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void y8950_device::device_reset() +{ + y8950_reset_chip(m_chip); +} + + +READ8_MEMBER( y8950_device::read ) +{ + return y8950_read(m_chip, offset & 1); +} + +WRITE8_MEMBER( y8950_device::write ) +{ + y8950_write(m_chip, offset & 1, data); +} + +READ8_MEMBER( y8950_device::status_port_r ) { return read(space, 0); } +READ8_MEMBER( y8950_device::read_port_r ) { return read(space, 1); } +WRITE8_MEMBER( y8950_device::control_port_w ) { write(space, 0, data); } +WRITE8_MEMBER( y8950_device::write_port_w ) { write(space, 1, data); } + + +const device_type Y8950 = &device_creator; + +y8950_device::y8950_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, Y8950, "Y8950", tag, owner, clock, "y8950", __FILE__), + device_sound_interface(mconfig, *this), + m_irq_handler(*this), + m_keyboard_read_handler(*this), + m_keyboard_write_handler(*this), + m_io_read_handler(*this), + m_io_write_handler(*this) +{ +} + +//------------------------------------------------- +// device_config_complete - perform any +// operations now that the configuration is +// complete +//------------------------------------------------- + +void y8950_device::device_config_complete() +{ +} diff --git a/src/devices/sound/8950intf.h b/src/devices/sound/8950intf.h new file mode 100644 index 00000000000..42db5339696 --- /dev/null +++ b/src/devices/sound/8950intf.h @@ -0,0 +1,81 @@ +// license:BSD-3-Clause +// copyright-holders:Ernesto Corvi +#pragma once + +#ifndef __8950INTF_H__ +#define __8950INTF_H__ + +#include "emu.h" + +#define MCFG_Y8950_IRQ_HANDLER(_devcb) \ + devcb = &y8950_device::set_irq_handler(*device, DEVCB_##_devcb); + +#define MCFG_Y8950_KEYBOARD_READ_HANDLER(_devcb) \ + devcb = &y8950_device::set_keyboard_read_handler(*device, DEVCB_##_devcb); + +#define MCFG_Y8950_KEYBOARD_WRITE_HANDLER(_devcb) \ + devcb = &y8950_device::set_keyboard_write_handler(*device, DEVCB_##_devcb); + +#define MCFG_Y8950_IO_READ_HANDLER(_devcb) \ + devcb = &y8950_device::set_io_read_handler(*device, DEVCB_##_devcb); + +#define MCFG_Y8950_IO_WRITE_HANDLER(_devcb) \ + devcb = &y8950_device::set_io_write_handler(*device, DEVCB_##_devcb); + +class y8950_device : public device_t, + public device_sound_interface +{ +public: + y8950_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // static configuration helpers + template static devcb_base &set_irq_handler(device_t &device, _Object object) { return downcast(device).m_irq_handler.set_callback(object); } + template static devcb_base &set_keyboard_read_handler(device_t &device, _Object object) { return downcast(device).m_keyboard_read_handler.set_callback(object); } + template static devcb_base &set_keyboard_write_handler(device_t &device, _Object object) { return downcast(device).m_keyboard_write_handler.set_callback(object); } + template static devcb_base &set_io_read_handler(device_t &device, _Object object) { return downcast(device).m_io_read_handler.set_callback(object); } + template static devcb_base &set_io_write_handler(device_t &device, _Object object) { return downcast(device).m_io_write_handler.set_callback(object); } + + DECLARE_READ8_MEMBER( read ); + DECLARE_WRITE8_MEMBER( write ); + + DECLARE_READ8_MEMBER( status_port_r ); + DECLARE_READ8_MEMBER( read_port_r ); + DECLARE_WRITE8_MEMBER( control_port_w ); + DECLARE_WRITE8_MEMBER( write_port_w ); + + void _IRQHandler(int irq); + void _timer_handler(int c, const attotime &period); + void _y8950_update_request(); + unsigned char _Y8950PortHandler_r(); + void _Y8950PortHandler_w(unsigned char data); + unsigned char _Y8950KeyboardHandler_r(); + void _Y8950KeyboardHandler_w(unsigned char data); + +protected: + // device-level overrides + virtual void device_config_complete(); + virtual void device_start(); + virtual void device_stop(); + virtual void device_reset(); + + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + // sound stream update overrides + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + +private: + // internal state + sound_stream * m_stream; + emu_timer * m_timer[2]; + void * m_chip; + devcb_write_line m_irq_handler; + devcb_read8 m_keyboard_read_handler; + devcb_write8 m_keyboard_write_handler; + devcb_read8 m_io_read_handler; + devcb_write8 m_io_write_handler; +}; + +extern const device_type Y8950; + + +#endif /* __8950INTF_H__ */ diff --git a/src/devices/sound/aica.c b/src/devices/sound/aica.c new file mode 100644 index 00000000000..e788b4fda34 --- /dev/null +++ b/src/devices/sound/aica.c @@ -0,0 +1,1662 @@ +// license:??? +// copyright-holders:ElSemi, kingshriek, Deunan Knute, R. Belmont +/* + Sega/Yamaha AICA emulation + By ElSemi, kingshriek, Deunan Knute, and R. Belmont + + This is effectively a 64-voice SCSP, with the following differences: + - No FM mode + - A third sample format (ADPCM) has been added + - Some minor other tweeks (no EGHOLD, slighly more capable DSP) +*/ + +#include "emu.h" +#include "aica.h" + +#define ICLIP16(x) (x<-32768)?-32768:((x>32767)?32767:x) + +#define SHIFT 12 +#define FIX(v) ((UINT32) ((float) (1<udata.data[0x0]>>0x0)&0x8000) +#define KEYONB(slot) ((slot->udata.data[0x0]>>0x0)&0x4000) +#define SSCTL(slot) ((slot->udata.data[0x0]>>0xA)&0x0001) +#define LPCTL(slot) ((slot->udata.data[0x0]>>0x9)&0x0001) +#define PCMS(slot) ((slot->udata.data[0x0]>>0x7)&0x0003) + +#define SA(slot) (((slot->udata.data[0x0]&0x7F)<<16)|(slot->udata.data[0x4/2])) + +#define LSA(slot) (slot->udata.data[0x8/2]) + +#define LEA(slot) (slot->udata.data[0xc/2]) + +#define D2R(slot) ((slot->udata.data[0x10/2]>>0xB)&0x001F) +#define D1R(slot) ((slot->udata.data[0x10/2]>>0x6)&0x001F) +#define AR(slot) ((slot->udata.data[0x10/2]>>0x0)&0x001F) + +#define LPSLNK(slot) ((slot->udata.data[0x14/2]>>0x0)&0x4000) +#define KRS(slot) ((slot->udata.data[0x14/2]>>0xA)&0x000F) +#define DL(slot) ((slot->udata.data[0x14/2]>>0x5)&0x001F) +#define RR(slot) ((slot->udata.data[0x14/2]>>0x0)&0x001F) + +#define TL(slot) ((slot->udata.data[0x28/2]>>0x8)&0x00FF) + +#define OCT(slot) ((slot->udata.data[0x18/2]>>0xB)&0x000F) +#define FNS(slot) ((slot->udata.data[0x18/2]>>0x0)&0x03FF) + +#define LFORE(slot) ((slot->udata.data[0x1c/2]>>0x0)&0x8000) +#define LFOF(slot) ((slot->udata.data[0x1c/2]>>0xA)&0x001F) +#define PLFOWS(slot) ((slot->udata.data[0x1c/2]>>0x8)&0x0003) +#define PLFOS(slot) ((slot->udata.data[0x1c/2]>>0x5)&0x0007) +#define ALFOWS(slot) ((slot->udata.data[0x1c/2]>>0x3)&0x0003) +#define ALFOS(slot) ((slot->udata.data[0x1c/2]>>0x0)&0x0007) + +#define ISEL(slot) ((slot->udata.data[0x20/2]>>0x0)&0x000F) +#define IMXL(slot) ((slot->udata.data[0x20/2]>>0x4)&0x000F) + +#define DISDL(slot) ((slot->udata.data[0x24/2]>>0x8)&0x000F) +#define DIPAN(slot) ((slot->udata.data[0x24/2]>>0x0)&0x001F) + +#define EFSDL(slot) ((m_EFSPAN[slot*4]>>8)&0x000f) +#define EFPAN(slot) ((m_EFSPAN[slot*4]>>0)&0x001f) + +//Envelope times in ms +static const double ARTimes[64]={100000/*infinity*/,100000/*infinity*/,8100.0,6900.0,6000.0,4800.0,4000.0,3400.0,3000.0,2400.0,2000.0,1700.0,1500.0, + 1200.0,1000.0,860.0,760.0,600.0,500.0,430.0,380.0,300.0,250.0,220.0,190.0,150.0,130.0,110.0,95.0, + 76.0,63.0,55.0,47.0,38.0,31.0,27.0,24.0,19.0,15.0,13.0,12.0,9.4,7.9,6.8,6.0,4.7,3.8,3.4,3.0,2.4, + 2.0,1.8,1.6,1.3,1.1,0.93,0.85,0.65,0.53,0.44,0.40,0.35,0.0,0.0}; +static const double DRTimes[64]={100000/*infinity*/,100000/*infinity*/,118200.0,101300.0,88600.0,70900.0,59100.0,50700.0,44300.0,35500.0,29600.0,25300.0,22200.0,17700.0, + 14800.0,12700.0,11100.0,8900.0,7400.0,6300.0,5500.0,4400.0,3700.0,3200.0,2800.0,2200.0,1800.0,1600.0,1400.0,1100.0, + 920.0,790.0,690.0,550.0,460.0,390.0,340.0,270.0,230.0,200.0,170.0,140.0,110.0,98.0,85.0,68.0,57.0,49.0,43.0,34.0, + 28.0,25.0,22.0,18.0,14.0,12.0,11.0,8.5,7.1,6.1,5.4,4.3,3.6,3.1}; + +#define MEM4B(aica) ((m_udata.data[0]>>0x0)&0x0200) +#define DAC18B(aica) ((m_udata.data[0]>>0x0)&0x0100) +#define MVOL(aica) ((m_udata.data[0]>>0x0)&0x000F) +#define RBL(aica) ((m_udata.data[2]>>0xD)&0x0003) +#define RBP(aica) ((m_udata.data[2]>>0x0)&0x0fff) +#define MOFULL(aica) ((m_udata.data[4]>>0x0)&0x1000) +#define MOEMPTY(aica) ((m_udata.data[4]>>0x0)&0x0800) +#define MIOVF(aica) ((m_udata.data[4]>>0x0)&0x0400) +#define MIFULL(aica) ((m_udata.data[4]>>0x0)&0x0200) +#define MIEMPTY(aica) ((m_udata.data[4]>>0x0)&0x0100) + +#define AFSEL(aica) ((m_udata.data[0xc/2]>>0x0)&0x4000) +#define MSLC(aica) ((m_udata.data[0xc/2]>>0x8)&0x3F) + +#define SCILV0(aica) ((m_udata.data[0xa8/2]>>0x0)&0xff) +#define SCILV1(aica) ((m_udata.data[0xac/2]>>0x0)&0xff) +#define SCILV2(aica) ((m_udata.data[0xb0/2]>>0x0)&0xff) + +#define MCIEB(aica) ((m_udata.data[0xb4/2]>>0x0)&0xff) +#define MCIPD(aica) ((m_udata.data[0xb8/2]>>0x0)&0xff) +#define MCIRE(aica) ((m_udata.data[0xbc/2]>>0x0)&0xff) + +#define SCIEX0 0 +#define SCIEX1 1 +#define SCIEX2 2 +#define SCIMID 3 +#define SCIDMA 4 +#define SCIIRQ 5 +#define SCITMA 6 +#define SCITMB 7 + +static const float SDLT[16]={-1000000.0,-42.0,-39.0,-36.0,-33.0,-30.0,-27.0,-24.0,-21.0,-18.0,-15.0,-12.0,-9.0,-6.0,-3.0,0.0}; + +unsigned char aica_device::DecodeSCI(unsigned char irq) +{ + unsigned char SCI=0; + unsigned char v; + v=(SCILV0((AICA))&(1<>8; + + CheckPendingIRQ(); + CheckPendingIRQ_SH4(); + +} + +TIMER_CALLBACK_MEMBER( aica_device::timerB_cb ) +{ + m_TimCnt[1] = 0xFFFF; + m_udata.data[0xa0/2]|=0x80; + m_mcipd |= 0x80; + m_udata.data[0x94/2]&=0xff00; + m_udata.data[0x94/2]|=m_TimCnt[1]>>8; + + CheckPendingIRQ(); + CheckPendingIRQ_SH4(); +} + +TIMER_CALLBACK_MEMBER( aica_device::timerC_cb ) +{ + m_TimCnt[2] = 0xFFFF; + m_udata.data[0xa0/2]|=0x100; + m_mcipd |= 0x100; + m_udata.data[0x98/2]&=0xff00; + m_udata.data[0x98/2]|=m_TimCnt[2]>>8; + + CheckPendingIRQ(); + CheckPendingIRQ_SH4(); +} + +int aica_device::Get_AR(int base,int R) +{ + int Rate=base+(R<<1); + if(Rate>63) Rate=63; + if(Rate<0) Rate=0; + return m_ARTABLE[Rate]; +} + +int aica_device::Get_DR(int base,int R) +{ + int Rate=base+(R<<1); + if(Rate>63) Rate=63; + if(Rate<0) Rate=0; + return m_DRTABLE[Rate]; +} + +int aica_device::Get_RR(int base,int R) +{ + int Rate=base+(R<<1); + if(Rate>63) Rate=63; + if(Rate<0) Rate=0; + return m_DRTABLE[Rate]; +} + +void aica_device::Compute_EG(AICA_SLOT *slot) +{ + int octave=(OCT(slot)^8)-8; + int rate; + if(KRS(slot)!=0xf) + rate=octave+2*KRS(slot)+((FNS(slot)>>9)&1); + else + rate=0; //rate=((FNS(slot)>>9)&1); + + slot->EG.volume=0x17f<EG.AR=Get_AR(rate,AR(slot)); + slot->EG.D1R=Get_DR(rate,D1R(slot)); + slot->EG.D2R=Get_DR(rate,D2R(slot)); + slot->EG.RR=Get_RR(rate,RR(slot)); + slot->EG.RR=Get_RR(rate,RR(slot)); + slot->EG.DL=0x1f-DL(slot); +} + +int aica_device::EG_Update(AICA_SLOT *slot) +{ + switch(slot->EG.state) + { + case AICA_ATTACK: + slot->EG.volume+=slot->EG.AR; + if(slot->EG.volume>=(0x3ff<EG.D1R) + { + slot->EG.state=AICA_DECAY1; + if(slot->EG.D1R>=(1024<EG.D2R) //Skip DECAY1, go directly to DECAY2 + slot->EG.state=AICA_DECAY2; + } + slot->EG.volume=0x3ff<EG.volume-=slot->EG.D1R; + if(slot->EG.volume<=0) + slot->EG.volume=0; + if(slot->EG.volume>>(EG_SHIFT+5)<=slot->EG.DL) + slot->EG.state=AICA_DECAY2; + break; + case AICA_DECAY2: + if(D2R(slot)==0) + return (slot->EG.volume>>EG_SHIFT)<<(SHIFT-10); + slot->EG.volume-=slot->EG.D2R; + if(slot->EG.volume<=0) + slot->EG.volume=0; + + break; + case AICA_RELEASE: + slot->EG.volume-=slot->EG.RR; + if(slot->EG.volume<=0) + { + slot->EG.volume=0; + StopSlot(slot,0); +// slot->EG.volume=0x17f<EG.state=AICA_ATTACK; + } + break; + default: + return 1<EG.volume>>EG_SHIFT)<<(SHIFT-10); +} + +UINT32 aica_device::Step(AICA_SLOT *slot) +{ + int octave=(OCT(slot)^8)-8+SHIFT-10; + UINT32 Fn=FNS(slot) + (0x400); + if (octave >= 0) + Fn<<=octave; + else + Fn>>=-octave; + return Fn; +} + + +void aica_device::Compute_LFO(AICA_SLOT *slot) +{ + if(PLFOS(slot)!=0) + AICALFO_ComputeStep(&(slot->PLFO),LFOF(slot),PLFOWS(slot),PLFOS(slot),0); + if(ALFOS(slot)!=0) + AICALFO_ComputeStep(&(slot->ALFO),LFOF(slot),ALFOWS(slot),ALFOS(slot),1); +} + +#define ADPCMSHIFT 8 +#define ADFIX(f) (int) ((float) f*(float) (1<> 29)) >> 3); + *PrevSignal=ICLIP16(x); + *PrevQuant=(*PrevQuant*TableQuant[Delta&7])>>ADPCMSHIFT; + *PrevQuant=(*PrevQuant<0x7f)?0x7f:((*PrevQuant>0x6000)?0x6000:*PrevQuant); + return *PrevSignal; +} + +void aica_device::StartSlot(AICA_SLOT *slot) +{ + UINT64 start_offset; + + slot->active=1; + slot->Backwards=0; + slot->cur_addr=0; slot->nxt_addr=1<prv_addr=-1; + start_offset = SA(slot); // AICA can play 16-bit samples from any boundry + slot->base=&m_AICARAM[start_offset]; + slot->step=Step(slot); + Compute_EG(slot); + slot->EG.state=AICA_ATTACK; + slot->EG.volume=0x17f<= 2) + { + slot->curstep = 0; + slot->adbase = (unsigned char *) (m_AICARAM+((SA(slot))&0x7fffff)); + InitADPCM(&(slot->cur_sample), &(slot->cur_quant)); + InitADPCM(&(slot->cur_lpsample), &(slot->cur_lpquant)); + + // on real hardware this creates undefined behavior. + if (LSA(slot) > LEA(slot)) + { + slot->udata.data[0xc/2] = 0xffff; + } + } +} + +void aica_device::StopSlot(AICA_SLOT *slot,int keyoff) +{ + if(keyoff /*&& slot->EG.state!=AICA_RELEASE*/) + { + slot->EG.state=AICA_RELEASE; + } + else + { + slot->active=0; + slot->lpend = 1; + } + slot->udata.data[0]&=~0x4000; +} + +#define log_base_2(n) (log((float) n)/log((float) 2)) + +void aica_device::Init() +{ + int i; + + m_IrqTimA = m_IrqTimBC = m_IrqMidi = 0; + m_MidiR=m_MidiW=0; + m_MidiOutR=m_MidiOutW=0; + + // get AICA RAM + { + m_AICARAM = region()->base(); + if (m_AICARAM) + { + m_AICARAM += m_roffset; + m_AICARAM_LENGTH = region()->bytes(); + m_RAM_MASK = m_AICARAM_LENGTH-1; + m_RAM_MASK16 = m_RAM_MASK & 0x7ffffe; + m_DSP.AICARAM = (UINT16 *)m_AICARAM; + m_DSP.AICARAM_LENGTH = m_AICARAM_LENGTH/2; + } + } + + m_timerA = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(aica_device::timerA_cb), this)); + m_timerB = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(aica_device::timerB_cb), this)); + m_timerC = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(aica_device::timerC_cb), this)); + + for(i=0;i<0x400;++i) + { + float envDB=((float)(3*(i-0x3ff)))/32.0f; + float scale=(float)(1<>0x0)&0xff; + int iPAN=(i>>0x8)&0x1f; + int iSDL=(i>>0xD)&0x0F; + float TL=1.0; + float SegaDB=0; + float fSDL=1.0; + float PAN=1.0; + float LPAN,RPAN; + + if(iTL&0x01) SegaDB-=0.4f; + if(iTL&0x02) SegaDB-=0.8f; + if(iTL&0x04) SegaDB-=1.5f; + if(iTL&0x08) SegaDB-=3.0f; + if(iTL&0x10) SegaDB-=6.0f; + if(iTL&0x20) SegaDB-=12.0f; + if(iTL&0x40) SegaDB-=24.0f; + if(iTL&0x80) SegaDB-=48.0f; + + TL=powf(10.0f,SegaDB/20.0f); + + SegaDB=0; + if(iPAN&0x1) SegaDB-=3.0f; + if(iPAN&0x2) SegaDB-=6.0f; + if(iPAN&0x4) SegaDB-=12.0f; + if(iPAN&0x8) SegaDB-=24.0f; + + if((iPAN&0xf)==0xf) PAN=0.0; + else PAN=powf(10.0f,SegaDB/20.0f); + + if(iPAN<0x10) + { + LPAN=PAN; + RPAN=1.0; + } + else + { + RPAN=PAN; + LPAN=1.0; + } + + if(iSDL) + fSDL=powf(10.0f,(SDLT[iSDL])/20.0f); + else + fSDL=0.0; + + m_LPANTABLE[i]=FIX((4.0f*LPAN*TL*fSDL)); + m_RPANTABLE[i]=FIX((4.0f*RPAN*TL*fSDL)); + } + + m_ARTABLE[0]=m_DRTABLE[0]=0; //Infinite time + m_ARTABLE[1]=m_DRTABLE[1]=0; //Infinite time + for(i=2;i<64;++i) + { + double t,step,scale; + t=ARTimes[i]; //In ms + if(t!=0.0) + { + step=(1023*1000.0)/(44100.0*t); + scale=(double) (1<EG.state==AICA_RELEASE/*&& !s2->active*/) + { + s2->lpend = 0; + StartSlot(s2); + #if 0 + printf("StartSlot[%02X]: SSCTL %01X SA %06X LSA %04X LEA %04X PCMS %01X LPCTL %01X\n",sl,SSCTL(s2),SA(s2),LSA(s2),LEA(s2),PCMS(s2),LPCTL(s2)); + printf(" AR %02X D1R %02X D2R %02X RR %02X DL %02X KRS %01X LPSLNK %01X\n",AR(s2),D1R(s2),D2R(s2),RR(s2),DL(s2),KRS(s2),LPSLNK(s2)>>14); + printf(" TL %02X OCT %01X FNS %03X\n",TL(s2),OCT(s2),FNS(s2)); + printf(" LFORE %01X LFOF %02X ALFOWS %01X ALFOS %01X PLFOWS %01X PLFOS %01X\n",LFORE(s2),LFOF(s2),ALFOWS(s2),ALFOS(s2),PLFOWS(s2),PLFOS(s2)); + printf(" IMXL %01X ISEL %01X DISDL %01X DIPAN %02X\n",IMXL(s2),ISEL(s2),DISDL(s2),DIPAN(s2)); + printf("\n"); + fflush(stdout); + #endif + } + if(!KEYONB(s2) /*&& s2->active*/) + { + StopSlot(s2,1); + } + } + } + slot->udata.data[0]&=~0x8000; + } + break; + case 0x18: + case 0x19: + slot->step=Step(slot); + break; + case 0x14: + case 0x15: + slot->EG.RR=Get_RR(0,RR(slot)); + slot->EG.DL=0x1f-DL(slot); + break; + case 0x1c: + case 0x1d: + Compute_LFO(slot); + break; + case 0x24: +// printf("[%02d]: %x to DISDL/DIPAN (PC=%x)\n", s, slot->udata.data[0x24/2], arm7_get_register(15)); + break; + } +} + +void aica_device::UpdateReg(address_space &space, int reg) +{ + switch(reg&0xff) + { + case 0x4: + case 0x5: + { + unsigned int v=RBL(); + m_DSP.RBP=RBP(); + if(v==0) + m_DSP.RBL=8*1024; + else if(v==1) + m_DSP.RBL=16*1024; + else if(v==2) + m_DSP.RBL=32*1024; + else if(v==3) + m_DSP.RBL=64*1024; + } + break; + case 0x8: + case 0x9: + midi_in(space, 0, m_udata.data[0x8/2]&0xff, 0xffff); + break; + + //case 0x0c: + //case 0x0d: + // printf("%04x\n",m_udata.data[0xc/2]); + // break; + + case 0x12: + case 0x13: + case 0x14: + case 0x15: + case 0x16: + case 0x17: + break; + + case 0x80: + case 0x81: + m_dma.dmea = ((m_udata.data[0x80/2] & 0xfe00) << 7) | (m_dma.dmea & 0xfffc); + /* TODO: $TSCD - MRWINH regs */ + break; + + case 0x84: + case 0x85: + m_dma.dmea = (m_udata.data[0x84/2] & 0xfffc) | (m_dma.dmea & 0x7f0000); + break; + + case 0x88: + case 0x89: + m_dma.drga = (m_udata.data[0x88/2] & 0x7ffc); + m_dma.dgate = (m_udata.data[0x88/2] & 0x8000) >> 15; + break; + + case 0x8c: + case 0x8d: + m_dma.dlg = (m_udata.data[0x8c/2] & 0x7ffc); + m_dma.ddir = (m_udata.data[0x8c/2] & 0x8000) >> 15; + if(m_udata.data[0x8c/2] & 1) // dexe + aica_exec_dma(space); + break; + + case 0x90: + case 0x91: + if(m_master) + { + UINT32 time; + + m_TimPris[0]=1<<((m_udata.data[0x90/2]>>8)&0x7); + m_TimCnt[0]=(m_udata.data[0x90/2]&0xff)<<8; + + if ((m_udata.data[0x90/2]&0xff) != 255) + { + time = (44100 / m_TimPris[0]) / (255-(m_udata.data[0x90/2]&0xff)); + if (time) + { + m_timerA->adjust(attotime::from_hz(time)); + } + } + } + break; + case 0x94: + case 0x95: + if(m_master) + { + UINT32 time; + + m_TimPris[1]=1<<((m_udata.data[0x94/2]>>8)&0x7); + m_TimCnt[1]=(m_udata.data[0x94/2]&0xff)<<8; + + if ((m_udata.data[0x94/2]&0xff) != 255) + { + time = (44100 / m_TimPris[1]) / (255-(m_udata.data[0x94/2]&0xff)); + if (time) + { + m_timerB->adjust(attotime::from_hz(time)); + } + } + } + break; + case 0x98: + case 0x99: + if(m_master) + { + UINT32 time; + + m_TimPris[2]=1<<((m_udata.data[0x98/2]>>8)&0x7); + m_TimCnt[2]=(m_udata.data[0x98/2]&0xff)<<8; + + if ((m_udata.data[0x98/2]&0xff) != 255) + { + time = (44100 / m_TimPris[2]) / (255-(m_udata.data[0x98/2]&0xff)); + if (time) + { + m_timerC->adjust(attotime::from_hz(time)); + } + } + } + break; + + case 0x9c: //SCIEB + case 0x9d: + if(m_udata.data[0x9c/2] & 0x631) + popmessage("AICA: SCIEB enabled %04x, contact MAME/MESSdev",m_udata.data[0x9c/2]); + break; + + case 0xa4: //SCIRE + case 0xa5: + + if(m_master) + { + m_udata.data[0xa0/2] &= ~m_udata.data[0xa4/2]; + ResetInterrupts(); + + // behavior from real hardware (SCSP, assumed to carry over): if you SCIRE a timer that's expired, + // it'll immediately pop up again + if (m_TimCnt[0] >= 0xff00) + { + m_udata.data[0xa0/2] |= 0x40; + } + if (m_TimCnt[1] >= 0xff00) + { + m_udata.data[0xa0/2] |= 0x80; + } + if (m_TimCnt[2] >= 0xff00) + { + m_udata.data[0xa0/2] |= 0x100; + } + } + break; + case 0xa8: + case 0xa9: + case 0xac: + case 0xad: + case 0xb0: + case 0xb1: + if(m_master) + { + m_IrqTimA=DecodeSCI(SCITMA); + m_IrqTimBC=DecodeSCI(SCITMB); + m_IrqMidi=DecodeSCI(SCIMID); + } + break; + + case 0xb4: //MCIEB + case 0xb5: + if(m_udata.data[0xb4/2] & 0x7df) + popmessage("AICA: MCIEB enabled %04x, contact MAME/MESSdev",m_udata.data[0xb4/2]); + m_mcieb = m_udata.data[0xb4/2]; + CheckPendingIRQ_SH4(); + break; + + case 0xb8: + case 0xb9: + if(m_udata.data[0xb8/2] & 0x20) + m_mcipd |= 0x20; + CheckPendingIRQ_SH4(); + break; + + case 0xbc: + case 0xbd: + m_mcipd &= ~m_udata.data[0xbc/2]; + CheckPendingIRQ_SH4(); + break; + } +} + +void aica_device::UpdateSlotRegR(int slot,int reg) +{ +} + +void aica_device::UpdateRegR(address_space &space, int reg) +{ + switch(reg&0xff) + { + case 8: + case 9: + { + unsigned short v=m_udata.data[0x8/2]; + v&=0xff00; + v|=m_MidiStack[m_MidiR]; + m_irq_cb(0); // cancel the IRQ + if(m_MidiR!=m_MidiW) + { + ++m_MidiR; + m_MidiR&=15; + } + m_udata.data[0x8/2]=v; + } + break; + + case 0x10: // LP check + case 0x11: + { + int slotnum = MSLC(); + AICA_SLOT *slot=m_Slots + slotnum; + UINT16 LP = 0; + if (!(AFSEL())) + { + UINT16 SGC; + int EG; + + LP = slot->lpend ? 0x8000 : 0x0000; + slot->lpend = 0; + SGC = (slot->EG.state << 13) & 0x6000; + EG = slot->active ? slot->EG.volume : 0; + EG >>= (EG_SHIFT - 13); + EG = 0x1FFF - EG; + if (EG < 0) EG = 0; + + m_udata.data[0x10/2] = (EG & 0x1FF8) | SGC | LP; + } + else + { + LP = slot->lpend ? 0x8000 : 0x0000; + m_udata.data[0x10/2] = LP; + } + } + break; + + case 0x14: // CA (slot address) + case 0x15: + { + //m_stream->update(); + int slotnum = MSLC(); + AICA_SLOT *slot=m_Slots+slotnum; + unsigned int CA = 0; + + if (PCMS(slot) == 0) // 16-bit samples + { + CA = (slot->cur_addr>>(SHIFT-1))&m_RAM_MASK16; + } + else // 8-bit PCM and 4-bit ADPCM + { + CA = (slot->cur_addr>>SHIFT)&m_RAM_MASK; + } + + //printf("%08x %08x\n",CA,slot->cur_addr&m_RAM_MASK16); + + m_udata.data[0x14/2] = CA; + } + break; + case 0xb8: + case 0xb9: + m_udata.data[0xb8/2] = m_mcipd; + break; + } +} + +void aica_device::w16(address_space &space,unsigned int addr,unsigned short val) +{ + addr&=0xffff; + if(addr<0x2000) + { + int slot=addr/0x80; + addr&=0x7f; +// printf("%x to slot %d offset %x\n", val, slot, addr); + *((unsigned short *) (m_Slots[slot].udata.datab+(addr))) = val; + UpdateSlotReg(slot,addr&0x7f); + } + else if (addr < 0x2800) + { + if (addr <= 0x2044) + { +// printf("%x to EFSxx slot %d (addr %x)\n", val, (addr-0x2000)/4, addr&0x7f); + m_EFSPAN[addr&0x7f] = val; + } + } + else if(addr<0x3000) + { + if (addr < 0x28be) + { +// printf("%x to AICA global @ %x\n", val, addr & 0xff); + *((unsigned short *) (m_udata.datab+((addr&0xff)))) = val; + UpdateReg(space, addr&0xff); + + } + else if (addr == 0x2d00) + { + m_IRQL = val; + popmessage("AICA: write to IRQL?"); + } + else if (addr == 0x2d04) + { + m_IRQR = val; + + if (val & 1) + { + m_irq_cb(0); + } + if (val & 0x100) + popmessage("AICA: SH-4 write protection enabled!"); + + if (val & 0xfefe) + popmessage("AICA: IRQR %04x!",val); + } + } + else + { + //DSP + if(addr<0x3200) //COEF + *((unsigned short *) (m_DSP.COEF+(addr-0x3000)/2))=val; + else if(addr<0x3400) + *((unsigned short *) (m_DSP.MADRS+(addr-0x3200)/2))=val; + else if(addr<0x3c00) + { + *((unsigned short *) (m_DSP.MPRO+(addr-0x3400)/2))=val; + + if (addr == 0x3bfe) + { + aica_dsp_start(&m_DSP); + } + } + else if(addr<0x4000) + { + popmessage("AICADSP write to undocumented reg %04x -> %04x",addr,val); + } + else if(addr<0x4400) + { + if(addr & 4) + m_DSP.TEMP[(addr >> 3) & 0x7f] = (m_DSP.TEMP[(addr >> 3) & 0x7f] & 0xffff0000) | (val & 0xffff); + else + m_DSP.TEMP[(addr >> 3) & 0x7f] = (m_DSP.TEMP[(addr >> 3) & 0x7f] & 0xffff) | (val << 16); + } + else if(addr<0x4500) + { + if(addr & 4) + m_DSP.MEMS[(addr >> 3) & 0x1f] = (m_DSP.MEMS[(addr >> 3) & 0x1f] & 0xffff0000) | (val & 0xffff); + else + m_DSP.MEMS[(addr >> 3) & 0x1f] = (m_DSP.MEMS[(addr >> 3) & 0x1f] & 0xffff) | (val << 16); + } + else if(addr<0x4580) + { + if(addr & 4) + m_DSP.MIXS[(addr >> 3) & 0xf] = (m_DSP.MIXS[(addr >> 3) & 0xf] & 0xffff0000) | (val & 0xffff); + else + m_DSP.MIXS[(addr >> 3) & 0xf] = (m_DSP.MIXS[(addr >> 3) & 0xf] & 0xffff) | (val << 16); + } + else if(addr<0x45c0) + *((unsigned short *) (m_DSP.EFREG+(addr-0x4580)/4))=val; + else if(addr<0x45c8) + *((unsigned short *) (m_DSP.EXTS+(addr-0x45c0)/2))=val; + } +} + +unsigned short aica_device::r16(address_space &space, unsigned int addr) +{ + unsigned short v=0; + addr&=0xffff; + if(addr<0x2000) + { + int slot=addr/0x80; + addr&=0x7f; + UpdateSlotRegR(slot,addr&0x7f); + v=*((unsigned short *) (m_Slots[slot].udata.datab+(addr))); + } + else if(addr<0x3000) + { + if (addr <= 0x2044) + { + v = m_EFSPAN[addr&0x7f]; + } + else if (addr < 0x28be) + { + UpdateRegR(space, addr&0xff); + v= *((unsigned short *) (m_udata.datab+((addr&0xff)))); + if((addr&0xfffe)==0x2810) m_udata.data[0x10/2] &= 0x7FFF; // reset LP on read + } + else if (addr == 0x2d00) + { + return m_IRQL; + } + else if (addr == 0x2d04) + { + //popmessage("AICA: read to IRQR?"); + return m_IRQR; + } + } + else + { + if(addr<0x3200) //COEF + v= *((unsigned short *) (m_DSP.COEF+(addr-0x3000)/2)); + else if(addr<0x3400) + v= *((unsigned short *) (m_DSP.MADRS+(addr-0x3200)/2)); + else if(addr<0x3c00) + v= *((unsigned short *) (m_DSP.MPRO+(addr-0x3400)/2)); + else if(addr<0x4000) + { + v= 0xffff; + popmessage("AICADSP read to undocumented reg %04x",addr); + } + else if(addr<0x4400) + { + if(addr & 4) + v= m_DSP.TEMP[(addr >> 3) & 0x7f] & 0xffff; + else + v= m_DSP.TEMP[(addr >> 3) & 0x7f] >> 16; + } + else if(addr<0x4500) + { + if(addr & 4) + v= m_DSP.MEMS[(addr >> 3) & 0x1f] & 0xffff; + else + v= m_DSP.MEMS[(addr >> 3) & 0x1f] >> 16; + } + else if(addr<0x4580) + { + if(addr & 4) + v= m_DSP.MIXS[(addr >> 3) & 0xf] & 0xffff; + else + v= m_DSP.MIXS[(addr >> 3) & 0xf] >> 16; + } + else if(addr<0x45c0) + v = *((unsigned short *) (m_DSP.EFREG+(addr-0x4580)/4)); + else if(addr<0x45c8) + v = *((unsigned short *) (m_DSP.EXTS+(addr-0x45c0)/2)); + } +// else if (addr<0x700) +// v=m_RINGBUF[(addr-0x600)/2]; + return v; +} + + +#define REVSIGN(v) ((~v)+1) + +#ifdef UNUSED_FUNCTION +void aica_device::TimersAddTicks(int ticks) +{ + if(m_TimCnt[0]<=0xff00) + { + m_TimCnt[0] += ticks << (8-((m_udata.data[0x18/2]>>8)&0x7)); + if (m_TimCnt[0] > 0xFF00) + { + m_TimCnt[0] = 0xFFFF; + m_udata.data[0xa0/2]|=0x40; + } + m_udata.data[0x90/2]&=0xff00; + m_udata.data[0x90/2]|=m_TimCnt[0]>>8; + } + + if(m_TimCnt[1]<=0xff00) + { + m_TimCnt[1] += ticks << (8-((m_udata.data[0x1a/2]>>8)&0x7)); + if (m_TimCnt[1] > 0xFF00) + { + m_TimCnt[1] = 0xFFFF; + m_udata.data[0xa0/2]|=0x80; + } + m_udata.data[0x94/2]&=0xff00; + m_udata.data[0x94/2]|=m_TimCnt[1]>>8; + } + + if(m_TimCnt[2]<=0xff00) + { + m_TimCnt[2] += ticks << (8-((m_udata.data[0x1c/2]>>8)&0x7)); + if (m_TimCnt[2] > 0xFF00) + { + m_TimCnt[2] = 0xFFFF; + m_udata.data[0xa0/2]|=0x100; + } + m_udata.data[0x98/2]&=0xff00; + m_udata.data[0x98/2]|=m_TimCnt[2]>>8; + } +} +#endif + +INT32 aica_device::UpdateSlot(AICA_SLOT *slot) +{ + INT32 sample; + int step=slot->step; + UINT32 addr1,addr2,addr_select; // current and next sample addresses + UINT32 *addr[2] = {&addr1, &addr2}; // used for linear interpolation + UINT32 *slot_addr[2] = {&(slot->cur_addr), &(slot->nxt_addr)}; // + UINT32 chanlea = LEA(slot); + + if(SSCTL(slot)!=0) //no FM or noise yet + return 0; + + if(PCMS(slot) == 3) // Red Dog music relies on this + chanlea = (chanlea + 3) & ~3; + + if(PLFOS(slot)!=0) + { + step=step*AICAPLFO_Step(&(slot->PLFO)); + step>>=SHIFT; + } + + if(PCMS(slot) == 1) + { + addr1=slot->cur_addr>>SHIFT; + addr2=slot->nxt_addr>>SHIFT; + } + else if(PCMS(slot) == 0) + { + addr1=(slot->cur_addr>>(SHIFT-1))&m_RAM_MASK16; + addr2=(slot->nxt_addr>>(SHIFT-1))&m_RAM_MASK16; + } + else + { + addr1=slot->cur_addr>>SHIFT; + addr2=slot->nxt_addr>>SHIFT; + } + + if(PCMS(slot) == 1) // 8-bit signed + { + INT8 *p1=(signed char *) (m_AICARAM+(((SA(slot)+addr1))&m_RAM_MASK)); + INT8 *p2=(signed char *) (m_AICARAM+(((SA(slot)+addr2))&m_RAM_MASK)); + INT32 s; + INT32 fpart=slot->cur_addr&((1<>SHIFT); + } + else if (PCMS(slot) == 0) //16 bit signed + { + UINT8 *p1=(UINT8 *) (m_AICARAM+((SA(slot)+addr1)&m_RAM_MASK)); + UINT8 *p2=(UINT8 *) (m_AICARAM+((SA(slot)+addr2)&m_RAM_MASK)); + INT32 s; + INT32 fpart=slot->cur_addr&((1<>SHIFT); + } + else // 4-bit ADPCM + { + UINT8 *base= slot->adbase; + INT32 s; + int cur_sample; //current ADPCM sample + int nxt_sample; //next ADPCM sample + INT32 fpart=slot->cur_addr&((1< addr2 ? chanlea : addr2, curstep = slot->curstep; + + if (slot->adbase) + { + cur_sample = slot->cur_sample; // may already contains current decoded sample + + // seek to the interpolation sample + while (curstep < steps_to_go) + { + int shift1 = 4 & (curstep << 2); + unsigned char delta1 = (*base>>shift1)&0xf; + DecodeADPCM(&(slot->cur_sample),delta1,&(slot->cur_quant)); + if (!(++curstep & 1)) + base++; + if (curstep == addr1) + cur_sample = slot->cur_sample; + if (curstep == LSA(slot)) + { + slot->cur_lpsample = slot->cur_sample; + slot->cur_lpquant = slot->cur_quant; + } + } + nxt_sample = slot->cur_sample; + + slot->adbase = base; + slot->curstep = curstep; + + s=(int)cur_sample*((1<>SHIFT); + } + + slot->prv_addr=slot->cur_addr; + slot->cur_addr+=step; + slot->nxt_addr=slot->cur_addr+(1<cur_addr>>SHIFT; + addr2=slot->nxt_addr>>SHIFT; + + if(addr1>=LSA(slot)) + { + if(LPSLNK(slot) && slot->EG.state==AICA_ATTACK && slot->EG.D1R) + slot->EG.state = AICA_DECAY1; + } + + for (addr_select=0; addr_select<2; addr_select++) + { + INT32 rem_addr; + switch(LPCTL(slot)) + { + case 0: //no loop + if(*addr[addr_select]>=LSA(slot) && *addr[addr_select]>=chanlea) + { + StopSlot(slot,0); + } + break; + case 1: //normal loop + if(*addr[addr_select]>=chanlea) + { + slot->lpend = 1; + rem_addr = *slot_addr[addr_select] - (chanlea<=2 && addr_select == 0) + { + // restore the state @ LSA - the sampler will naturally walk to (LSA + remainder) + slot->adbase = &m_AICARAM[SA(slot)+(LSA(slot)/2)]; + slot->curstep = LSA(slot); + if (PCMS(slot) == 2) + { + slot->cur_sample = slot->cur_lpsample; + slot->cur_quant = slot->cur_lpquant; + } + +// printf("Looping: slot_addr %x LSA %x LEA %x step %x base %x\n", *slot_addr[addr_select]>>SHIFT, LSA(slot), LEA(slot), slot->curstep, slot->adbase); + } + } + break; + } + } + + if(ALFOS(slot)!=0) + { + sample=sample*AICAALFO_Step(&(slot->ALFO)); + sample>>=SHIFT; + } + + if(slot->EG.state==AICA_ATTACK) + sample=(sample*EG_Update(slot))>>SHIFT; + else + sample=(sample*m_EG_TABLE[EG_Update(slot)>>(SHIFT-10)])>>SHIFT; + + return sample; +} + +void aica_device::DoMasterSamples(int nsamples) +{ + stream_sample_t *bufr,*bufl; + int sl, s, i; + + bufr=m_bufferr; + bufl=m_bufferl; + + for(s=0;s>(SHIFT-2),ISEL(slot),IMXL(slot)); + Enc=((TL(slot))<<0x0)|((DIPAN(slot))<<0x8)|((DISDL(slot))<<0xd); + { + smpl+=(sample*m_LPANTABLE[Enc])>>SHIFT; + smpr+=(sample*m_RPANTABLE[Enc])>>SHIFT; + } + } + + m_BUFPTR&=63; + } + + // process the DSP + aica_dsp_step(&m_DSP); + + // mix DSP output + for(i=0;i<16;++i) + { + if(EFSDL(i)) + { + unsigned int Enc=((EFPAN(i))<<0x8)|((EFSDL(i))<<0xd); + smpl+=(m_DSP.EFREG[i]*m_LPANTABLE[Enc])>>SHIFT; + smpr+=(m_DSP.EFREG[i]*m_RPANTABLE[Enc])>>SHIFT; + } + } + + *bufl++ = ICLIP16(smpl>>3); + *bufr++ = ICLIP16(smpr>>3); + } +} + +/* TODO: this needs to be timer-ized */ +void aica_device::aica_exec_dma(address_space &space) +{ + static UINT16 tmp_dma[4]; + int i; + + printf("AICA: DMA transfer START\n" + "DMEA: %08x DRGA: %08x DLG: %04x\n" + "DGATE: %d DDIR: %d\n",m_dma.dmea,m_dma.drga,m_dma.dlg,m_dma.dgate,m_dma.ddir); + + /* Copy the dma values in a temp storage for resuming later */ + /* (DMA *can't* overwrite its parameters). */ + if(!(m_dma.ddir)) + { + for(i=0;i<4;i++) + tmp_dma[i] = m_udata.data[(0x80+(i*4))/2]; + } + + /* note: we don't use space.read_word / write_word because it can happen that SH-4 enables the DMA instead of ARM like in DCLP tester. */ + /* TODO: don't know if params auto-updates, I guess not ... */ + if(m_dma.ddir) + { + if(m_dma.dgate) + { + for(i=0;i < m_dma.dlg;i+=2) + { + m_AICARAM[m_dma.dmea] = 0; + m_AICARAM[m_dma.dmea+1] = 0; + m_dma.dmea+=2; + } + } + else + { + for(i=0;i < m_dma.dlg;i+=2) + { + UINT16 tmp; + tmp = r16(space, m_dma.drga);; + m_AICARAM[m_dma.dmea] = tmp & 0xff; + m_AICARAM[m_dma.dmea+1] = tmp>>8; + m_dma.dmea+=4; + m_dma.drga+=4; + } + } + } + else + { + if(m_dma.dgate) + { + for(i=0;i < m_dma.dlg;i+=2) + { + w16(space, m_dma.drga, 0); + m_dma.drga+=4; + } + } + else + { + for(i=0;i < m_dma.dlg;i+=2) + { + UINT16 tmp; + tmp = m_AICARAM[m_dma.dmea]; + tmp|= m_AICARAM[m_dma.dmea+1]<<8; + w16(space, m_dma.drga, tmp); + m_dma.dmea+=4; + m_dma.drga+=4; + } + } + } + + /*Resume the values*/ + if(!(m_dma.ddir)) + { + for(i=0;i<4;i++) + m_udata.data[(0x80+(i*4))/2] = tmp_dma[i]; + } + + /* Job done, clear DEXE */ + m_udata.data[0x8c/2] &= ~1; + /* request a dma end irq */ + m_mcipd |= 0x10; + CheckPendingIRQ_SH4(); +} + +#ifdef UNUSED_FUNCTION +int aica_device::IRQCB(void *param) +{ + CheckPendingIRQ(param); + return -1; +} +#endif + +//------------------------------------------------- +// sound_stream_update - handle a stream update +//------------------------------------------------- + +void aica_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + m_bufferl = outputs[0]; + m_bufferr = outputs[1]; + m_length = samples; + DoMasterSamples(samples); +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void aica_device::device_start() +{ + // init the emulation + Init(); + + // set up the IRQ callbacks + m_irq_cb.resolve_safe(); + m_main_irq_cb.resolve_safe(); + + m_stream = machine().sound().stream_alloc(*this, 0, 2, 44100); + + // save state + save_item(NAME(m_IrqTimA)); + save_item(NAME(m_IrqTimBC)); + save_item(NAME(m_IrqMidi)); + save_item(NAME(m_MidiOutW)); + save_item(NAME(m_MidiOutR)); + save_item(NAME(m_MidiStack),16); + save_item(NAME(m_MidiW)); + save_item(NAME(m_MidiR)); + save_item(NAME(m_LPANTABLE),0x20000); + save_item(NAME(m_RPANTABLE),0x20000); + save_item(NAME(m_TimPris),3); + save_item(NAME(m_TimCnt),3); +} + +void aica_device::set_ram_base(void *base, int size) +{ + m_AICARAM = (unsigned char *)base; + m_AICARAM_LENGTH = size; + m_RAM_MASK = m_AICARAM_LENGTH-1; + m_RAM_MASK16 = m_RAM_MASK & 0x7ffffe; + m_DSP.AICARAM = (UINT16 *)base; + m_DSP.AICARAM_LENGTH = size; +} + +READ16_MEMBER( aica_device::read ) +{ + return r16(space,offset*2); +} + +WRITE16_MEMBER( aica_device::write ) +{ + UINT16 tmp; + + tmp = r16(space, offset*2); + COMBINE_DATA(&tmp); + w16(space, offset*2, tmp); +} + +WRITE16_MEMBER( aica_device::midi_in ) +{ + m_MidiStack[m_MidiW++]=data; + m_MidiW &= 15; +} + +READ16_MEMBER( aica_device::midi_out_r ) +{ + unsigned char val; + + val=m_MidiStack[m_MidiR++]; + m_MidiR&=7; + return val; +} + +const device_type AICA = &device_creator; + +aica_device::aica_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, AICA, "AICA", tag, owner, clock, "aica", __FILE__), + device_sound_interface(mconfig, *this), + m_master(false), + m_roffset(0), + m_irq_cb(*this), + m_main_irq_cb(*this), + m_IRQL(0), + m_IRQR(0), + m_BUFPTR(0), + m_AICARAM(NULL), + m_AICARAM_LENGTH(0), + m_RAM_MASK(0), + m_RAM_MASK16(0), + m_buffertmpl(NULL), + m_buffertmpr(NULL), + m_IrqTimA(0), + m_IrqTimBC(0), + m_IrqMidi(0), + m_MidiOutW(0), + m_MidiOutR(0), + m_MidiW(0), + m_MidiR(0), + m_mcieb(0), + m_mcipd(0), + m_bufferl(NULL), + m_bufferr(NULL), + m_length(0), + m_RBUFDST(NULL) + +{ + memset(&m_udata.data, 0, sizeof(m_udata.data)); + memset(m_EFSPAN, 0, sizeof(m_EFSPAN)); + memset(m_Slots, 0, sizeof(m_Slots)); + memset(m_RINGBUF, 0, sizeof(m_RINGBUF)); + memset(m_MidiStack, 0, sizeof(m_MidiStack)); + + memset(m_LPANTABLE, 0, sizeof(m_LPANTABLE)); + memset(m_RPANTABLE, 0, sizeof(m_RPANTABLE)); + + memset(m_TimPris, 0, sizeof(m_TimPris)); + memset(m_TimCnt, 0, sizeof(m_TimCnt)); + + memset(&m_dma, 0, sizeof(m_dma)); + + memset(m_ARTABLE, 0, sizeof(m_ARTABLE)); + memset(m_DRTABLE, 0, sizeof(m_DRTABLE)); + + memset(&m_DSP, 0, sizeof(m_DSP)); + + memset(m_EG_TABLE, 0, sizeof(m_EG_TABLE)); + memset(m_PLFO_TRI, 0, sizeof(m_PLFO_TRI)); + memset(m_PLFO_SQR, 0, sizeof(m_PLFO_SQR)); + memset(m_PLFO_SAW, 0, sizeof(m_PLFO_SAW)); + memset(m_PLFO_NOI, 0, sizeof(m_PLFO_NOI)); + + memset(m_ALFO_TRI, 0, sizeof(m_ALFO_TRI)); + memset(m_ALFO_SQR, 0, sizeof(m_ALFO_SQR)); + memset(m_ALFO_SAW, 0, sizeof(m_ALFO_SAW)); + memset(m_ALFO_NOI, 0, sizeof(m_ALFO_NOI)); + + memset(m_PSCALES, 0, sizeof(m_PSCALES)); + memset(m_ASCALES, 0, sizeof(m_ASCALES)); +} + + +static const float LFOFreq[32]={0.17f,0.19f,0.23f,0.27f,0.34f,0.39f,0.45f,0.55f,0.68f,0.78f,0.92f,1.10f,1.39f,1.60f,1.87f,2.27f, + 2.87f,3.31f,3.92f,4.79f,6.15f,7.18f,8.60f,10.8f,14.4f,17.2f,21.5f,28.7f,43.1f,57.4f,86.1f,172.3f}; +static const float ASCALE[8]={0.0f,0.4f,0.8f,1.5f,3.0f,6.0f,12.0f,24.0f}; +static const float PSCALE[8]={0.0f,7.0f,13.5f,27.0f,55.0f,112.0f,230.0f,494.0f}; + +void aica_device::AICALFO_Init() +{ + int i,s; + for(i=0;i<256;++i) + { + int a,p; +// float TL; + //Saw + a=255-i; + if(i<128) + p=i; + else + p=i-256; + m_ALFO_SAW[i]=a; + m_PLFO_SAW[i]=p; + + //Square + if(i<128) + { + a=255; + p=127; + } + else + { + a=0; + p=-128; + } + m_ALFO_SQR[i]=a; + m_PLFO_SQR[i]=p; + + //Tri + if(i<128) + a=255-(i*2); + else + a=(i*2)-256; + if(i<64) + p=i*2; + else if(i<128) + p=255-i*2; + else if(i<192) + p=256-i*2; + else + p=i*2-511; + m_ALFO_TRI[i]=a; + m_PLFO_TRI[i]=p; + + //noise + //a=lfo_noise[i]; + a=machine().rand()&0xff; + p=128-a; + m_ALFO_NOI[i]=a; + m_PLFO_NOI[i]=p; + } + + for(s=0;s<8;++s) + { + float limit=PSCALE[s]; + for(i=-128;i<128;++i) + { + m_PSCALES[s][i+128]=CENTS(((limit*(float) i)/128.0f)); + } + limit=-ASCALE[s]; + for(i=0;i<256;++i) + { + m_ASCALES[s][i]=DB(((limit*(float) i)/256.0f)); + } + } +} + +signed int aica_device::AICAPLFO_Step(AICA_LFO_t *LFO) +{ + int p; + + LFO->phase+=LFO->phase_step; +#if LFO_SHIFT!=8 + LFO->phase&=(1<<(LFO_SHIFT+8))-1; +#endif + p=LFO->table[LFO->phase>>LFO_SHIFT]; + p=LFO->scale[p+128]; + return p<<(SHIFT-LFO_SHIFT); +} + +signed int aica_device::AICAALFO_Step(AICA_LFO_t *LFO) +{ + int p; + LFO->phase+=LFO->phase_step; +#if LFO_SHIFT!=8 + LFO->phase&=(1<<(LFO_SHIFT+8))-1; +#endif + p=LFO->table[LFO->phase>>LFO_SHIFT]; + p=LFO->scale[p]; + return p<<(SHIFT-LFO_SHIFT); +} + +void aica_device::AICALFO_ComputeStep(AICA_LFO_t *LFO,UINT32 LFOF,UINT32 LFOWS,UINT32 LFOS,int ALFO) +{ + float step=(float) LFOFreq[LFOF]*256.0f/(float)44100.0f; + LFO->phase_step=(unsigned int) ((float) (1<table=m_ALFO_SAW; break; + case 1: LFO->table=m_ALFO_SQR; break; + case 2: LFO->table=m_ALFO_TRI; break; + case 3: LFO->table=m_ALFO_NOI; break; + default: printf("Unknown ALFO %d\n", LFOWS); + } + LFO->scale=m_ASCALES[LFOS]; + } + else + { + switch(LFOWS) + { + case 0: LFO->table=m_PLFO_SAW; break; + case 1: LFO->table=m_PLFO_SQR; break; + case 2: LFO->table=m_PLFO_TRI; break; + case 3: LFO->table=m_PLFO_NOI; break; + default: printf("Unknown PLFO %d\n", LFOWS); + } + LFO->scale=m_PSCALES[LFOS]; + } +} diff --git a/src/devices/sound/aica.h b/src/devices/sound/aica.h new file mode 100644 index 00000000000..0c7d5caf4f4 --- /dev/null +++ b/src/devices/sound/aica.h @@ -0,0 +1,213 @@ +// license:??? +// copyright-holders:ElSemi, kingshriek, Deunan Knute, R. Belmont +/* + + Sega/Yamaha AICA emulation +*/ + +#ifndef __AICA_H__ +#define __AICA_H__ + +#include "aicadsp.h" + +#define MCFG_AICA_MASTER \ + aica_device::set_master(*device); + +#define MCFG_AICA_ROFFSET(_offs) \ + aica_device::set_roffset(*device, _offs); + +#define MCFG_AICA_IRQ_CB(_devcb) \ + devcb = &aica_device::set_irq_callback(*device, DEVCB_##_devcb); + +#define MCFG_AICA_MAIN_IRQ_CB(_devcb) \ + devcb = &aica_device::set_main_irq_callback(*device, DEVCB_##_devcb); + +enum AICA_STATE {AICA_ATTACK,AICA_DECAY1,AICA_DECAY2,AICA_RELEASE}; + +struct AICA_LFO_t +{ + unsigned short phase; + UINT32 phase_step; + int *table; + int *scale; +}; + + +struct AICA_EG_t +{ + int volume; // + AICA_STATE state; + int step; + //step vals + int AR; //Attack + int D1R; //Decay1 + int D2R; //Decay2 + int RR; //Release + + int DL; //Decay level + UINT8 LPLINK; +}; + +struct AICA_SLOT +{ + union + { + UINT16 data[0x40]; //only 0x1a bytes used + UINT8 datab[0x80]; + } udata; + UINT8 active; //this slot is currently playing + UINT8 *base; //samples base address + UINT32 prv_addr; // previous play address (for ADPCM) + UINT32 cur_addr; //current play address (24.8) + UINT32 nxt_addr; //next play address + UINT32 step; //pitch step (24.8) + UINT8 Backwards; //the wave is playing backwards + AICA_EG_t EG; //Envelope + AICA_LFO_t PLFO; //Phase LFO + AICA_LFO_t ALFO; //Amplitude LFO + int slot; + int cur_sample; //current ADPCM sample + int cur_quant; //current ADPCM step + int curstep; + int cur_lpquant, cur_lpsample, cur_lpstep; + UINT8 *adbase, *adlpbase; + UINT8 lpend; +}; + +class aica_device : public device_t, + public device_sound_interface +{ +public: + aica_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + static void set_master(device_t &device) { downcast(device).m_master = true; } + static void set_roffset(device_t &device, int roffset) { downcast(device).m_roffset = roffset; } + template static devcb_base &set_irq_callback(device_t &device, _Object object) { return downcast(device).m_irq_cb.set_callback(object); } + template static devcb_base &set_main_irq_callback(device_t &device, _Object object) { return downcast(device).m_main_irq_cb.set_callback(object); } + + // AICA register access + DECLARE_READ16_MEMBER( read ); + DECLARE_WRITE16_MEMBER( write ); + + // MIDI I/O access + DECLARE_WRITE16_MEMBER( midi_in ); + DECLARE_READ16_MEMBER( midi_out_r ); + + void set_ram_base(void *base, int size); + +protected: + // device-level overrides + virtual void device_start(); + + // sound stream update overrides + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); +private: + unsigned char DecodeSCI(unsigned char irq); + void ResetInterrupts(); + + void CheckPendingIRQ(); + void CheckPendingIRQ_SH4(); + TIMER_CALLBACK_MEMBER( timerA_cb ); + TIMER_CALLBACK_MEMBER( timerB_cb ); + TIMER_CALLBACK_MEMBER( timerC_cb ); + int Get_AR(int base,int R); + int Get_DR(int base,int R); + int Get_RR(int base,int R); + void Compute_EG(AICA_SLOT *slot); + int EG_Update(AICA_SLOT *slot); + UINT32 Step(AICA_SLOT *slot); + void Compute_LFO(AICA_SLOT *slot); + void InitADPCM(int *PrevSignal, int *PrevQuant); + inline signed short DecodeADPCM(int *PrevSignal, unsigned char Delta, int *PrevQuant); + void StartSlot(AICA_SLOT *slot); + void StopSlot(AICA_SLOT *slot,int keyoff); + void Init(); + void UpdateSlotReg(int s,int r); + void UpdateReg(address_space &space, int reg); + void UpdateSlotRegR(int slot,int reg); + void UpdateRegR(address_space &space, int reg); + void w16(address_space &space,unsigned int addr,unsigned short val); + unsigned short r16(address_space &space, unsigned int addr); + inline INT32 UpdateSlot(AICA_SLOT *slot); + void DoMasterSamples(int nsamples); + void aica_exec_dma(address_space &space); + + + void AICALFO_Init(); + inline signed int AICAPLFO_Step(AICA_LFO_t *LFO); + inline signed int AICAALFO_Step(AICA_LFO_t *LFO); + void AICALFO_ComputeStep(AICA_LFO_t *LFO,UINT32 LFOF,UINT32 LFOWS,UINT32 LFOS,int ALFO); + + bool m_master; + int m_roffset; /* offset in the region */ + devcb_write_line m_irq_cb; + devcb_write_line m_main_irq_cb; + + union + { + UINT16 data[0xc0/2]; + UINT8 datab[0xc0]; + } m_udata; + + UINT16 m_IRQL, m_IRQR; + UINT16 m_EFSPAN[0x48]; + AICA_SLOT m_Slots[64]; + signed short m_RINGBUF[64]; + unsigned char m_BUFPTR; + unsigned char *m_AICARAM; + UINT32 m_AICARAM_LENGTH, m_RAM_MASK, m_RAM_MASK16; + sound_stream * m_stream; + + INT32 *m_buffertmpl, *m_buffertmpr; + + UINT32 m_IrqTimA; + UINT32 m_IrqTimBC; + UINT32 m_IrqMidi; + + UINT8 m_MidiOutW,m_MidiOutR; + UINT8 m_MidiStack[16]; + UINT8 m_MidiW,m_MidiR; + + int m_LPANTABLE[0x20000]; + int m_RPANTABLE[0x20000]; + + int m_TimPris[3]; + int m_TimCnt[3]; + + UINT16 m_mcieb, m_mcipd; + + // timers + emu_timer *m_timerA, *m_timerB, *m_timerC; + + // DMA stuff + struct{ + UINT32 dmea; + UINT16 drga; + UINT16 dlg; + UINT8 dgate; + UINT8 ddir; + }m_dma; + + + int m_ARTABLE[64], m_DRTABLE[64]; + + AICADSP m_DSP; + + stream_sample_t *m_bufferl; + stream_sample_t *m_bufferr; + + int m_length; + + signed short *m_RBUFDST; //this points to where the sample will be stored in the RingBuf + INT32 m_EG_TABLE[0x400]; + int m_PLFO_TRI[256],m_PLFO_SQR[256],m_PLFO_SAW[256],m_PLFO_NOI[256]; + int m_ALFO_TRI[256],m_ALFO_SQR[256],m_ALFO_SAW[256],m_ALFO_NOI[256]; + int m_PSCALES[8][256]; + int m_ASCALES[8][256]; + +}; + +extern const device_type AICA; + + +#endif /* __AICA_H__ */ diff --git a/src/devices/sound/aicadsp.c b/src/devices/sound/aicadsp.c new file mode 100644 index 00000000000..4f533125825 --- /dev/null +++ b/src/devices/sound/aicadsp.c @@ -0,0 +1,351 @@ +// license:??? +// copyright-holders:ElSemi, kingshriek, Deunan Knute, R. Belmont +#include "emu.h" +#include "aicadsp.h" + +static UINT16 PACK(INT32 val) +{ + UINT32 temp; + int sign,exponent,k; + + sign = (val >> 23) & 0x1; + temp = (val ^ (val << 1)) & 0xFFFFFF; + exponent = 0; + for (k=0; k<12; k++) + { + if (temp & 0x800000) + break; + temp <<= 1; + exponent += 1; + } + if (exponent < 12) + val = (val << exponent) & 0x3FFFFF; + else + val <<= 11; + val >>= 11; + val &= 0x7FF; + val |= sign << 15; + val |= exponent << 11; + + return (UINT16)val; +} + +static INT32 UNPACK(UINT16 val) +{ + int sign,exponent,mantissa; + INT32 uval; + + sign = (val >> 15) & 0x1; + exponent = (val >> 11) & 0xF; + mantissa = val & 0x7FF; + uval = mantissa << 11; + if (exponent > 11) + { + exponent = 11; + uval |= sign << 22; + } + else + uval |= (sign ^ 1) << 22; + uval |= sign << 23; + uval <<= 8; + uval >>= 8; + uval >>= exponent; + + return uval; +} + +void aica_dsp_init(AICADSP *DSP) +{ + memset(DSP,0,sizeof(AICADSP)); + DSP->RBL=0x8000; + DSP->Stopped=1; +} + +void aica_dsp_step(AICADSP *DSP) +{ + INT32 ACC=0; //26 bit + INT32 SHIFTED=0; //24 bit + INT32 X=0; //24 bit + INT32 Y=0; //13 bit + INT32 B=0; //26 bit + INT32 INPUTS=0; //24 bit + INT32 MEMVAL=0; + INT32 FRC_REG=0; //13 bit + INT32 Y_REG=0; //24 bit + UINT32 ADDR=0; + UINT32 ADRS_REG=0; //13 bit + int step; + + if(DSP->Stopped) + return; + + memset(DSP->EFREG,0,2*16); +#if 0 + int dump=0; + FILE *f=NULL; + if(dump) + f=fopen("dsp.txt","wt"); +#endif + for(step=0;stepLastStep;++step) + { + UINT16 *IPtr=DSP->MPRO+step*8; + +// if(IPtr[0]==0 && IPtr[1]==0 && IPtr[2]==0 && IPtr[3]==0) +// break; + + UINT32 TRA=(IPtr[0]>>9)&0x7F; + UINT32 TWT=(IPtr[0]>>8)&0x01; + UINT32 TWA=(IPtr[0]>>1)&0x7F; + + UINT32 XSEL=(IPtr[2]>>15)&0x01; + UINT32 YSEL=(IPtr[2]>>13)&0x03; + UINT32 IRA=(IPtr[2]>>7)&0x3F; + UINT32 IWT=(IPtr[2]>>6)&0x01; + UINT32 IWA=(IPtr[2]>>1)&0x1F; + + UINT32 TABLE=(IPtr[4]>>15)&0x01; + UINT32 MWT=(IPtr[4]>>14)&0x01; + UINT32 MRD=(IPtr[4]>>13)&0x01; + UINT32 EWT=(IPtr[4]>>12)&0x01; + UINT32 EWA=(IPtr[4]>>8)&0x0F; + UINT32 ADRL=(IPtr[4]>>7)&0x01; + UINT32 FRCL=(IPtr[4]>>6)&0x01; + UINT32 SHIFT=(IPtr[4]>>4)&0x03; + UINT32 YRL=(IPtr[4]>>3)&0x01; + UINT32 NEGB=(IPtr[4]>>2)&0x01; + UINT32 ZERO=(IPtr[4]>>1)&0x01; + UINT32 BSEL=(IPtr[4]>>0)&0x01; + + UINT32 NOFL=(IPtr[6]>>15)&1; //???? + UINT32 COEF=step; + + UINT32 MASA=(IPtr[6]>>9)&0x1f; //??? + UINT32 ADREB=(IPtr[6]>>8)&0x1; + UINT32 NXADR=(IPtr[6]>>7)&0x1; + + INT64 v; + + //operations are done at 24 bit precision +#if 0 + if(MASA) + int a=1; + if(NOFL) + int a=1; + +// int dump=0; + + if(f) + { +#define DUMP(v) fprintf(f," " #v ": %04X",v); + + fprintf(f,"%d: ",step); + DUMP(ACC); + DUMP(SHIFTED); + DUMP(X); + DUMP(Y); + DUMP(B); + DUMP(INPUTS); + DUMP(MEMVAL); + DUMP(FRC_REG); + DUMP(Y_REG); + DUMP(ADDR); + DUMP(ADRS_REG); + fprintf(f,"\n"); + } +#endif + //INPUTS RW + assert(IRA<0x32); + if(IRA<=0x1f) + INPUTS=DSP->MEMS[IRA]; + else if(IRA<=0x2F) + INPUTS=DSP->MIXS[IRA-0x20]<<4; //MIXS is 20 bit + else if(IRA<=0x31) + INPUTS=0; + + INPUTS<<=8; + INPUTS>>=8; + //if(INPUTS&0x00800000) + // INPUTS|=0xFF000000; + + if(IWT) + { + DSP->MEMS[IWA]=MEMVAL; //MEMVAL was selected in previous MRD + if(IRA==IWA) + INPUTS=MEMVAL; + } + + //Operand sel + //B + if(!ZERO) + { + if(BSEL) + B=ACC; + else + { + B=DSP->TEMP[(TRA+DSP->DEC)&0x7F]; + B<<=8; + B>>=8; + //if(B&0x00800000) + // B|=0xFF000000; //Sign extend + } + if(NEGB) + B=0-B; + } + else + B=0; + + //X + if(XSEL) + X=INPUTS; + else + { + X=DSP->TEMP[(TRA+DSP->DEC)&0x7F]; + X<<=8; + X>>=8; + //if(X&0x00800000) + // X|=0xFF000000; + } + + //Y + if(YSEL==0) + Y=FRC_REG; + else if(YSEL==1) + Y=DSP->COEF[COEF<<1]>>3; //COEF is 16 bits + else if(YSEL==2) + Y=(Y_REG>>11)&0x1FFF; + else if(YSEL==3) + Y=(Y_REG>>4)&0x0FFF; + + if(YRL) + Y_REG=INPUTS; + + //Shifter + if(SHIFT==0) + { + SHIFTED=ACC; + if(SHIFTED>0x007FFFFF) + SHIFTED=0x007FFFFF; + if(SHIFTED<(-0x00800000)) + SHIFTED=-0x00800000; + } + else if(SHIFT==1) + { + SHIFTED=ACC*2; + if(SHIFTED>0x007FFFFF) + SHIFTED=0x007FFFFF; + if(SHIFTED<(-0x00800000)) + SHIFTED=-0x00800000; + } + else if(SHIFT==2) + { + SHIFTED=ACC*2; + SHIFTED<<=8; + SHIFTED>>=8; + //SHIFTED&=0x00FFFFFF; + //if(SHIFTED&0x00800000) + // SHIFTED|=0xFF000000; + } + else if(SHIFT==3) + { + SHIFTED=ACC; + SHIFTED<<=8; + SHIFTED>>=8; + //SHIFTED&=0x00FFFFFF; + //if(SHIFTED&0x00800000) + // SHIFTED|=0xFF000000; + } + + //ACCUM + Y<<=19; + Y>>=19; + //if(Y&0x1000) + // Y|=0xFFFFF000; + + v=(((INT64) X*(INT64) Y)>>12); + ACC=(int) v+B; + + if(TWT) + DSP->TEMP[(TWA+DSP->DEC)&0x7F]=SHIFTED; + + if(FRCL) + { + if(SHIFT==3) + FRC_REG=SHIFTED&0x0FFF; + else + FRC_REG=(SHIFTED>>11)&0x1FFF; + } + + if(MRD || MWT) + //if(0) + { + ADDR=DSP->MADRS[MASA<<1]; + if(!TABLE) + ADDR+=DSP->DEC; + if(ADREB) + ADDR+=ADRS_REG&0x0FFF; + if(NXADR) + ADDR++; + if(!TABLE) + ADDR&=DSP->RBL-1; + else + ADDR&=0xFFFF; + //ADDR<<=1; + //ADDR+=DSP->RBP<<13; + //MEMVAL=DSP->AICARAM[ADDR>>1]; + ADDR+=DSP->RBP<<10; + if(MRD && (step&1)) //memory only allowed on odd? DoA inserts NOPs on even + { + if(NOFL) + MEMVAL=DSP->AICARAM[ADDR]<<8; + else + MEMVAL=UNPACK(DSP->AICARAM[ADDR]); + } + if(MWT && (step&1)) + { + if(NOFL) + DSP->AICARAM[ADDR]=SHIFTED>>8; + else + DSP->AICARAM[ADDR]=PACK(SHIFTED); + } + } + + if(ADRL) + { + if(SHIFT==3) + ADRS_REG=(SHIFTED>>12)&0xFFF; + else + ADRS_REG=(INPUTS>>16); + } + + if(EWT) + DSP->EFREG[EWA]+=SHIFTED>>8; + + } + --DSP->DEC; + memset(DSP->MIXS,0,4*16); +// if(f) +// fclose(f); +} + +void aica_dsp_setsample(AICADSP *DSP,INT32 sample,int SEL,int MXL) +{ + //DSP->MIXS[SEL]+=sample<<(MXL+1)/*7*/; + DSP->MIXS[SEL]+=sample; +// if(MXL) +// int a=1; +} + +void aica_dsp_start(AICADSP *DSP) +{ + int i; + DSP->Stopped=0; + for(i=127;i>=0;--i) + { + UINT16 *IPtr=DSP->MPRO+i*8; + + if(IPtr[0]!=0 || IPtr[2]!=0 || IPtr[4]!=0 || IPtr[6]!=0) + break; + } + DSP->LastStep=i+1; + +} diff --git a/src/devices/sound/aicadsp.h b/src/devices/sound/aicadsp.h new file mode 100644 index 00000000000..e28301a6100 --- /dev/null +++ b/src/devices/sound/aicadsp.h @@ -0,0 +1,42 @@ +// license:??? +// copyright-holders:ElSemi, kingshriek, Deunan Knute, R. Belmont +#pragma once + +#ifndef __AICADSP_H__ +#define __AICADSP_H__ + +//the DSP Context +struct AICADSP +{ +//Config + UINT16 *AICARAM; + UINT32 AICARAM_LENGTH; + UINT32 RBP; //Ring buf pointer + UINT32 RBL; //Delay ram (Ring buffer) size in words + +//context + + INT16 COEF[128*2]; //16 bit signed + UINT16 MADRS[64*2]; //offsets (in words), 16 bit + UINT16 MPRO[128*4*2*2]; //128 steps 64 bit + INT32 TEMP[128]; //TEMP regs,24 bit signed + INT32 MEMS[32]; //MEMS regs,24 bit signed + UINT32 DEC; + +//input + INT32 MIXS[16]; //MIXS, 24 bit signed + INT16 EXTS[2]; //External inputs (CDDA) 16 bit signed + +//output + INT16 EFREG[16]; //EFREG, 16 bit signed + + int Stopped; + int LastStep; +}; + +void aica_dsp_init(AICADSP *DSP); +void aica_dsp_setsample(AICADSP *DSP, INT32 sample, INT32 SEL, INT32 MXL); +void aica_dsp_step(AICADSP *DSP); +void aica_dsp_start(AICADSP *DSP); + +#endif /* __AICADSP_H__ */ diff --git a/src/devices/sound/amiga.c b/src/devices/sound/amiga.c new file mode 100644 index 00000000000..84b761e73bd --- /dev/null +++ b/src/devices/sound/amiga.c @@ -0,0 +1,245 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + Amiga audio hardware + +***************************************************************************/ + +#include "amiga.h" +#include "includes/amiga.h" + + +//************************************************************************** +// CONSTANTS / MACROS +//************************************************************************** + +#define VERBOSE 0 +#define LOG(x) do { if (VERBOSE) logerror x; } while (0) + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type AMIGA = &device_creator; + + +//************************************************************************* +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// amiga_sound_device - constructor +//------------------------------------------------- + +amiga_sound_device::amiga_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, AMIGA, "Amiga Paula", tag, owner, clock, "amiga_paula", __FILE__), + device_sound_interface(mconfig, *this), + m_stream(NULL) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void amiga_sound_device::device_start() +{ + // initialize channels + for (int i = 0; i < 4; i++) + { + m_channel[i].index = i; + m_channel[i].curticks = 0; + m_channel[i].manualmode = false; + m_channel[i].curlocation = 0; + m_channel[i].irq_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(amiga_sound_device::signal_irq), this)); + } + + // create the stream + m_stream = machine().sound().stream_alloc(*this, 0, 4, clock() / CLOCK_DIVIDER); +} + + +//************************************************************************* +// IMPLEMENTATION +//************************************************************************** + +//------------------------------------------------- +// signal_irq - irq signaling +//------------------------------------------------- + +TIMER_CALLBACK_MEMBER( amiga_sound_device::signal_irq ) +{ + amiga_state *state = machine().driver_data(); + + state->custom_chip_w(REG_INTREQ, INTENA_SETCLR | (0x80 << param)); +} + +//------------------------------------------------- +// dma_reload +//------------------------------------------------- + +void amiga_sound_device::dma_reload(audio_channel *chan) +{ + amiga_state *state = machine().driver_data(); + + chan->curlocation = CUSTOM_REG_LONG(REG_AUD0LCH + chan->index * 8); + chan->curlength = CUSTOM_REG(REG_AUD0LEN + chan->index * 8); + chan->irq_timer->adjust(attotime::from_hz(15750), chan->index); + + LOG(("dma_reload(%d): offs=%05X len=%04X\n", chan->index, chan->curlocation, chan->curlength)); +} + +//------------------------------------------------- +// data_w - manual mode data writer +//------------------------------------------------- + +void amiga_sound_device::data_w(int which, UINT16 data) +{ + m_channel[which].manualmode = true; +} + +//------------------------------------------------- +// update - stream updater +//------------------------------------------------- + +void amiga_sound_device::update() +{ + m_stream->update(); +} + +//------------------------------------------------- +// sound_stream_update - handle a stream update +//------------------------------------------------- + +void amiga_sound_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + amiga_state *state = machine().driver_data(); + int channum, sampoffs = 0; + + // if all DMA off, disable all channels + if (!(CUSTOM_REG(REG_DMACON) & 0x0200)) + { + m_channel[0].dma_enabled = + m_channel[1].dma_enabled = + m_channel[2].dma_enabled = + m_channel[3].dma_enabled = false; + + // clear the sample data to 0 + for (channum = 0; channum < 4; channum++) + memset(outputs[channum], 0, sizeof(stream_sample_t) * samples); + return; + } + + samples *= CLOCK_DIVIDER; + + // update the DMA states on each channel and reload if fresh + for (channum = 0; channum < 4; channum++) + { + audio_channel *chan = &m_channel[channum]; + if (!chan->dma_enabled && ((CUSTOM_REG(REG_DMACON) >> channum) & 1)) + dma_reload(chan); + chan->dma_enabled = (CUSTOM_REG(REG_DMACON) >> channum) & 1; + } + + // loop until done + while (samples > 0) + { + int nextper, nextvol; + int ticks = samples; + + // determine the number of ticks we can do in this chunk + if (ticks > m_channel[0].curticks) + ticks = m_channel[0].curticks; + if (ticks > m_channel[1].curticks) + ticks = m_channel[1].curticks; + if (ticks > m_channel[2].curticks) + ticks = m_channel[2].curticks; + if (ticks > m_channel[3].curticks) + ticks = m_channel[3].curticks; + + // loop over channels + nextper = nextvol = -1; + for (channum = 0; channum < 4; channum++) + { + int volume = (nextvol == -1) ? CUSTOM_REG(REG_AUD0VOL + channum * 8) : nextvol; + int period = (nextper == -1) ? CUSTOM_REG(REG_AUD0PER + channum * 8) : nextper; + audio_channel *chan = &m_channel[channum]; + stream_sample_t sample; + int i; + + // normalize the volume value + volume = (volume & 0x40) ? 64 : (volume & 0x3f); + volume *= 4; + + // are we modulating the period of the next channel? + if ((CUSTOM_REG(REG_ADKCON) >> channum) & 0x10) + { + nextper = CUSTOM_REG(REG_AUD0DAT + channum * 8); + nextvol = -1; + sample = 0; + } + + // are we modulating the volume of the next channel? + else if ((CUSTOM_REG(REG_ADKCON) >> channum) & 0x01) + { + nextper = -1; + nextvol = CUSTOM_REG(REG_AUD0DAT + channum * 8); + sample = 0; + } + + // otherwise, we are generating data + else + { + nextper = nextvol = -1; + sample = chan->latched * volume; + } + + // fill the buffer with the sample + for (i = 0; i < ticks; i += CLOCK_DIVIDER) + outputs[channum][(sampoffs + i) / CLOCK_DIVIDER] = sample; + + // account for the ticks; if we hit 0, advance + chan->curticks -= ticks; + if (chan->curticks == 0) + { + // reset the clock and ensure we're above the minimum ticks + chan->curticks = period; + if (chan->curticks < 124) + chan->curticks = 124; + + // move forward one byte; if we move to an even byte, fetch new + if (chan->dma_enabled || chan->manualmode) + chan->curlocation++; + if (chan->dma_enabled && !(chan->curlocation & 1)) + { + CUSTOM_REG(REG_AUD0DAT + channum * 8) = state->chip_ram_r(chan->curlocation); + if (chan->curlength != 0) + chan->curlength--; + + // if we run out of data, reload the dma + if (chan->curlength == 0) + dma_reload(chan); + } + + // latch the next byte of the sample + if (!(chan->curlocation & 1)) + chan->latched = CUSTOM_REG(REG_AUD0DAT + channum * 8) >> 8; + else + chan->latched = CUSTOM_REG(REG_AUD0DAT + channum * 8) >> 0; + + // if we're in manual mode, signal an interrupt once we latch the low byte + if (!chan->dma_enabled && chan->manualmode && (chan->curlocation & 1)) + { + signal_irq(NULL, channum); + chan->manualmode = false; + } + } + } + + // bump ourselves forward by the number of ticks + sampoffs += ticks; + samples -= ticks; + } +} diff --git a/src/devices/sound/amiga.h b/src/devices/sound/amiga.h new file mode 100644 index 00000000000..eb8b9ee436d --- /dev/null +++ b/src/devices/sound/amiga.h @@ -0,0 +1,65 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + Amiga audio hardware + +***************************************************************************/ + +#pragma once + +#ifndef __SOUND_AMIGA_H__ +#define __SOUND_AMIGA_H__ + +#include "emu.h" + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> amiga_sound_device + +class amiga_sound_device : public device_t, public device_sound_interface +{ +public: + amiga_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + ~amiga_sound_device() {} + + void update(); + void data_w(int which, UINT16 data); + +protected: + // device-level overrides + virtual void device_start(); + + // sound stream update overrides + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + +private: + static const int CLOCK_DIVIDER = 16; + + struct audio_channel + { + emu_timer *irq_timer; + UINT32 curlocation; + UINT16 curlength; + UINT16 curticks; + UINT8 index; + bool dma_enabled; + bool manualmode; + INT8 latched; + }; + + void dma_reload(audio_channel *chan); + + // internal state + audio_channel m_channel[4]; + sound_stream *m_stream; + + TIMER_CALLBACK_MEMBER( signal_irq ); +}; + +extern const device_type AMIGA; + +#endif // __SOUND_AMIGA_H__ diff --git a/src/devices/sound/asc.c b/src/devices/sound/asc.c new file mode 100644 index 00000000000..ad7559e0d3d --- /dev/null +++ b/src/devices/sound/asc.c @@ -0,0 +1,597 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/*************************************************************************** + + asc.c + + Apple Sound Chip (ASC) 344S0063 + Enhanced Apple Sound Chip (EASC) 343S1063 + + Emulation by R. Belmont + + Registers: + 0x800: VERSION + 0x801: MODE (1=FIFO mode, 2=wavetable mode) + 0x802: CONTROL (bit 0=analog or PWM output, 1=stereo/mono, 7=processing time exceeded) + 0x803: FIFO MODE (bit 7=clear FIFO, bit 1="non-ROM companding", bit 0="ROM companding") + 0x804: FIFO IRQ STATUS (bit 0=ch A 1/2 full, 1=ch A full, 2=ch B 1/2 full, 3=ch B full) + 0x805: WAVETABLE CONTROL (bits 0-3 wavetables 0-3 start) + 0x806: VOLUME (bits 2-4 = 3 bit internal ASC volume, bits 5-7 = volume control sent to Sony sound chip) + 0x807: CLOCK RATE (0 = Mac 22257 Hz, 1 = undefined, 2 = 22050 Hz, 3 = 44100 Hz) + 0x80a: PLAY REC A + 0x80f: TEST (bits 6-7 = digital test, bits 4-5 = analog test) + 0x810: WAVETABLE 0 PHASE (big-endian 9.15 fixed-point, only 24 bits valid) + 0x814: WAVETABLE 0 INCREMENT (big-endian 9.15 fixed-point, only 24 bits valid) + 0x818: WAVETABLE 1 PHASE + 0x81C: WAVETABLE 1 INCREMENT + 0x820: WAVETABLE 2 PHASE + 0x824: WAVETABLE 2 INCREMENT + 0x828: WAVETABLE 3 PHASE + 0x82C: WAVETABLE 3 INCREMENT + +***************************************************************************/ + +#include "emu.h" +#include "asc.h" + +// device type definition +const device_type ASC = &device_creator; + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// asc_device - constructor +//------------------------------------------------- + +asc_device::asc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, ASC, "ASC", tag, owner, clock, "asc", __FILE__), + device_sound_interface(mconfig, *this), + write_irq(*this), + m_chip_type(0) +{ +} + + +//------------------------------------------------- +// static_set_type - configuration helper to set +// the chip type +//------------------------------------------------- + +void asc_device::static_set_type(device_t &device, int type) +{ + asc_device &asc = downcast(device); + asc.m_chip_type = type; +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void asc_device::device_start() +{ + // create the stream + m_stream = machine().sound().stream_alloc(*this, 0, 2, 22257); + + memset(m_regs, 0, sizeof(m_regs)); + + m_timer = timer_alloc(0, NULL); + + save_item(NAME(m_fifo_a_rdptr)); + save_item(NAME(m_fifo_b_rdptr)); + save_item(NAME(m_fifo_a_wrptr)); + save_item(NAME(m_fifo_b_wrptr)); + save_item(NAME(m_fifo_cap_a)); + save_item(NAME(m_fifo_cap_b)); + save_item(NAME(m_fifo_a)); + save_item(NAME(m_fifo_b)); + save_item(NAME(m_regs)); + save_item(NAME(m_phase)); + save_item(NAME(m_incr)); + + write_irq.resolve_safe(); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void asc_device::device_reset() +{ + m_stream->update(); + + memset(m_regs, 0, sizeof(m_regs)); + memset(m_fifo_a, 0, sizeof(m_fifo_a)); + memset(m_fifo_b, 0, sizeof(m_fifo_b)); + memset(m_phase, 0, sizeof(m_phase)); + memset(m_incr, 0, sizeof(m_incr)); + + m_fifo_a_rdptr = m_fifo_b_rdptr = 0; + m_fifo_a_wrptr = m_fifo_b_wrptr = 0; + m_fifo_cap_a = m_fifo_cap_b = 0; +} + +//------------------------------------------------- +// device_timer - called when our device timer expires +//------------------------------------------------- + +void asc_device::device_timer(emu_timer &timer, device_timer_id tid, int param, void *ptr) +{ + m_stream->update(); +} + +//------------------------------------------------- +// sound_stream_update - handle update requests for +// our sound stream +//------------------------------------------------- + +void asc_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + stream_sample_t *outL, *outR; + int i, ch; + static UINT32 wtoffs[2] = { 0, 0x200 }; + + outL = outputs[0]; + outR = outputs[1]; + + switch (m_regs[R_MODE-0x800] & 3) + { + case 0: // chip off + for (i = 0; i < samples; i++) + { + outL[i] = outR[i] = 0; + } + break; + + case 1: // FIFO mode + for (i = 0; i < samples; i++) + { + INT8 smpll, smplr; + + smpll = (INT8)m_fifo_a[m_fifo_a_rdptr]^0x80; + smplr = (INT8)m_fifo_b[m_fifo_b_rdptr]^0x80; + + // don't advance the sample pointer if there are no more samples + if (m_fifo_cap_a) + { + m_fifo_a_rdptr++; + m_fifo_a_rdptr &= 0x3ff; + m_fifo_cap_a--; + } + + if (m_fifo_cap_b) + { + m_fifo_b_rdptr++; + m_fifo_b_rdptr &= 0x3ff; + m_fifo_cap_b--; + } + + switch (m_chip_type) + { + case ASC_TYPE_SONORA: + if (m_fifo_cap_a < 0x200) + { + m_regs[R_FIFOSTAT-0x800] |= 0x4; // fifo less than half full + m_regs[R_FIFOSTAT-0x800] |= 0x8; // just pass the damn test + write_irq(ASSERT_LINE); + } + break; + + default: + if (m_fifo_cap_a == 0x1ff) + { + m_regs[R_FIFOSTAT-0x800] |= 1; // fifo A half-empty + write_irq(ASSERT_LINE); + } + else if (m_fifo_cap_a == 0x1) // fifo A fully empty + { + m_regs[R_FIFOSTAT-0x800] |= 2; // fifo A empty + write_irq(ASSERT_LINE); + } + + if (m_fifo_cap_b == 0x1ff) + { + m_regs[R_FIFOSTAT-0x800] |= 4; // fifo B half-empty + write_irq(ASSERT_LINE); + } + else if (m_fifo_cap_b == 0x1) // fifo B fully empty + { + m_regs[R_FIFOSTAT-0x800] |= 8; // fifo B empty + write_irq(ASSERT_LINE); + } + break; + } + + outL[i] = smpll * 64; + outR[i] = smplr * 64; + } + break; + + case 2: // wavetable mode + for (i = 0; i < samples; i++) + { + INT32 mixL, mixR; + INT8 smpl; + + mixL = mixR = 0; + + // update channel pointers + for (ch = 0; ch < 4; ch++) + { + m_phase[ch] += m_incr[ch]; + + if (ch < 2) + { + smpl = (INT8)m_fifo_a[((m_phase[ch]>>15)&0x1ff) + wtoffs[ch&1]]; + } + else + { + smpl = (INT8)m_fifo_b[((m_phase[ch]>>15)&0x1ff) + wtoffs[ch&1]]; + } + + smpl ^= 0x80; + mixL += smpl*256; + mixR += smpl*256; + } + + outL[i] = mixL>>2; + outR[i] = mixR>>2; + } + break; + } + +// printf("rdA %04x rdB %04x wrA %04x wrB %04x (capA %04x B %04x)\n", m_fifo_a_rdptr, m_fifo_b_rdptr, m_fifo_a_wrptr, m_fifo_b_wrptr, m_fifo_cap_a, m_fifo_cap_b); +} + +//------------------------------------------------- +// read - read from the chip's registers and internal RAM +//------------------------------------------------- + +READ8_MEMBER( asc_device::read ) +{ + UINT8 rv; + +// printf("ASC: read at %x\n", offset); + + // not sure what actually happens when the CPU reads the FIFO... + if (offset < 0x400) + { + return m_fifo_a[offset]; + } + else if (offset < 0x800) + { + return m_fifo_b[offset-0x400]; + } + else + { + m_stream->update(); + switch (offset) + { + case R_VERSION: + switch (m_chip_type) + { + case ASC_TYPE_ASC: + return 0; + + case ASC_TYPE_V8: + case ASC_TYPE_EAGLE: + case ASC_TYPE_SPICE: + case ASC_TYPE_VASP: + return 0xe8; + + case ASC_TYPE_SONORA: + return 0xbc; + + default: // return the actual register value + break; + } + break; + + case R_MODE: + switch (m_chip_type) + { + case ASC_TYPE_V8: + case ASC_TYPE_EAGLE: + case ASC_TYPE_SPICE: + case ASC_TYPE_VASP: + return 1; + + default: + break; + } + break; + + case R_CONTROL: + switch (m_chip_type) + { + case ASC_TYPE_V8: + case ASC_TYPE_EAGLE: + case ASC_TYPE_SPICE: + case ASC_TYPE_VASP: + return 1; + + default: + break; + } + break; + + case R_FIFOSTAT: + if (m_chip_type == ASC_TYPE_V8) + { + rv = 3; + } + else + { + rv = m_regs[R_FIFOSTAT-0x800]; + } + +// printf("Read FIFO stat = %02x\n", rv); + + // reading this register clears all bits + m_regs[R_FIFOSTAT-0x800] = 0; + + // reading this clears interrupts + write_irq(CLEAR_LINE); + + return rv; + + default: + break; + } + } + + // WT inc/phase registers - rebuild from "live" copies" + if ((offset >= 0x810) && (offset <= 0x82f)) + { + m_regs[0x11] = m_phase[0]>>16; + m_regs[0x12] = m_phase[0]>>8; + m_regs[0x13] = m_phase[0]; + m_regs[0x15] = m_incr[0]>>16; + m_regs[0x16] = m_incr[0]>>8; + m_regs[0x17] = m_incr[0]; + + m_regs[0x19] = m_phase[1]>>16; + m_regs[0x1a] = m_phase[1]>>8; + m_regs[0x1b] = m_phase[1]; + m_regs[0x1d] = m_incr[1]>>16; + m_regs[0x1e] = m_incr[1]>>8; + m_regs[0x1f] = m_incr[1]; + + m_regs[0x21] = m_phase[2]>>16; + m_regs[0x22] = m_phase[2]>>8; + m_regs[0x23] = m_phase[2]; + m_regs[0x25] = m_incr[2]>>16; + m_regs[0x26] = m_incr[2]>>8; + m_regs[0x27] = m_incr[2]; + + m_regs[0x29] = m_phase[3]>>16; + m_regs[0x2a] = m_phase[3]>>8; + m_regs[0x2b] = m_phase[3]; + m_regs[0x2d] = m_incr[3]>>16; + m_regs[0x2e] = m_incr[3]>>8; + m_regs[0x2f] = m_incr[3]; + } + + if (offset >= 0x1000) + { + return 0xff; + } + + return m_regs[offset-0x800]; +} + +//------------------------------------------------- +// write - write to the chip's registers and internal RAM +//------------------------------------------------- + +WRITE8_MEMBER( asc_device::write ) +{ +// printf("ASC: write %02x to %x\n", data, offset); + + if (offset < 0x400) + { + if (m_regs[R_MODE-0x800] == 1) + { + m_fifo_a[m_fifo_a_wrptr++] = data; + m_fifo_cap_a++; + + if (m_fifo_cap_a == 0x3ff) + { + m_regs[R_FIFOSTAT-0x800] |= 2; // fifo A full + } + + m_fifo_a_wrptr &= 0x3ff; + } + else + { + m_fifo_a[offset] = data; + } + } + else if (offset < 0x800) + { + if (m_regs[R_MODE-0x800] == 1) + { + m_fifo_b[m_fifo_b_wrptr++] = data; + m_fifo_cap_b++; + + if (m_fifo_cap_b == 0x3ff) + { + m_regs[R_FIFOSTAT-0x800] |= 8; // fifo B full + } + + m_fifo_b_wrptr &= 0x3ff; + } + else + { + m_fifo_b[offset-0x400] = data; + } + } + else + { +// printf("ASC: %02x to %x (was %x)\n", data, offset, m_regs[offset-0x800]); + + m_stream->update(); + switch (offset) + { + case R_MODE: + data &= 3; // only bits 0 and 1 can be written + + if (data != m_regs[R_MODE-0x800]) + { + m_fifo_a_rdptr = m_fifo_b_rdptr = 0; + m_fifo_a_wrptr = m_fifo_b_wrptr = 0; + m_fifo_cap_a = m_fifo_cap_b = 0; + + if (data != 0) + { + m_timer->adjust(attotime::zero, 0, attotime::from_hz(22257/4)); + } + else + { + m_timer->adjust(attotime::never); + } + } + break; + + case R_FIFOMODE: + if (data & 0x80) + { + m_fifo_a_rdptr = m_fifo_b_rdptr = 0; + m_fifo_a_wrptr = m_fifo_b_wrptr = 0; + m_fifo_cap_a = m_fifo_cap_b = 0; + } + break; + + case R_WTCONTROL: +// printf("One-shot wavetable %02x\n", data); + break; + + case 0x811: + m_phase[0] &= 0x00ffff; + m_phase[0] |= data<<16; + break; + + case 0x812: + m_phase[0] &= 0xff00ff; + m_phase[0] |= data<<8; + break; + + case 0x813: + m_phase[0] &= 0xffff00; + m_phase[0] |= data; + break; + + case 0x815: + m_incr[0] &= 0x00ffff; + m_incr[0] |= data<<16; + break; + + case 0x816: + m_incr[0] &= 0xff00ff; + m_incr[0] |= data<<8; + break; + + case 0x817: + m_incr[0] &= 0xffff00; + m_incr[0] |= data; + break; + + case 0x819: + m_phase[1] &= 0x00ffff; + m_phase[1] |= data<<16; + break; + + case 0x81a: + m_phase[1] &= 0xff00ff; + m_phase[1] |= data<<8; + break; + + case 0x81b: + m_phase[1] &= 0xffff00; + m_phase[1] |= data; + break; + + case 0x81d: + m_incr[1] &= 0x00ffff; + m_incr[1] |= data<<16; + break; + + case 0x81e: + m_incr[1] &= 0xff00ff; + m_incr[1] |= data<<8; + break; + + case 0x81f: + m_incr[1] &= 0xffff00; + m_incr[1] |= data; + break; + + case 0x821: + m_phase[2] &= 0x00ffff; + m_phase[2] |= data<<16; + break; + + case 0x822: + m_phase[2] &= 0xff00ff; + m_phase[2] |= data<<8; + break; + + case 0x823: + m_phase[2] &= 0xffff00; + m_phase[2] |= data; + break; + + case 0x825: + m_incr[2] &= 0x00ffff; + m_incr[2] |= data<<16; + break; + + case 0x826: + m_incr[2] &= 0xff00ff; + m_incr[2] |= data<<8; + break; + + case 0x827: + m_incr[2] &= 0xffff00; + m_incr[2] |= data; + break; + + case 0x829: + m_phase[3] &= 0x00ffff; + m_phase[3] |= data<<16; + break; + + case 0x82a: + m_phase[3] &= 0xff00ff; + m_phase[3] |= data<<8; + break; + + case 0x82b: + m_phase[3] &= 0xffff00; + m_phase[3] |= data; + break; + + case 0x82d: + m_incr[3] &= 0x00ffff; + m_incr[3] |= data<<16; + break; + + case 0x82e: + m_incr[3] &= 0xff00ff; + m_incr[3] |= data<<8; + break; + + case 0x82f: + m_incr[3] &= 0xffff00; + m_incr[3] |= data; + break; + } + + if (offset >= 0x800 && offset < 0x1000) + { + m_regs[offset-0x800] = data; + } + } +} diff --git a/src/devices/sound/asc.h b/src/devices/sound/asc.h new file mode 100644 index 00000000000..24f085e50ac --- /dev/null +++ b/src/devices/sound/asc.h @@ -0,0 +1,136 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/*************************************************************************** + + asc.h + + Apple Sound Chip (ASC) 344S0063 + Enhanced Apple Sound Chip (EASC) 343S1063 + +***************************************************************************/ + +#pragma once + +#ifndef __ASC_H__ +#define __ASC_H__ + + + + +//************************************************************************** +// CONSTANTS +//************************************************************************** + +// chip behavior types +enum +{ + ASC_TYPE_ASC = 0, // original discrete Apple Sound Chip + ASC_TYPE_EASC = 1, // discrete Enhanced Apple Sound Chip + ASC_TYPE_V8 = 2, // Subset of ASC included in the V8 ASIC (LC/LCII) + ASC_TYPE_EAGLE = 3, // Subset of ASC included in the Eagle ASIC (Classic II) + ASC_TYPE_SPICE = 4, // Subset of ASC included in the Spice ASIC (Color Classic) + ASC_TYPE_SONORA = 5, // Subset of ASC included in the Sonora ASIC (LCIII) + ASC_TYPE_VASP = 6, // Subset of ASC included in the VASP ASIC (IIvx/IIvi) + ASC_TYPE_ARDBEG = 7 // Subset of ASC included in the Ardbeg ASIC (LC520) +}; + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_ASC_ADD(_tag, _clock, _type, _irqf) \ + MCFG_DEVICE_ADD(_tag, ASC, _clock) \ + MCFG_ASC_TYPE(_type) \ + MCFG_IRQ_FUNC(_irqf) + +#define MCFG_ASC_REPLACE(_tag, _clock, _type, _irqf) \ + MCFG_DEVICE_REPLACE(_tag, ASC, _clock) \ + MCFG_ASC_TYPE(_type) \ + MCFG_IRQ_FUNC(_irqf) + +#define MCFG_ASC_TYPE(_type) \ + asc_device::static_set_type(*device, _type); +#define MCFG_IRQ_FUNC(_irqf) \ + downcast(device)->set_irqf(DEVCB_##_irqf); + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> asc_device + +class asc_device : public device_t, public device_sound_interface +{ +public: + // construction/destruction + asc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // inline configuration helpers + static void static_set_type(device_t &device, int type); + + + template void set_irqf(_write wr) + { + write_irq.set_callback(wr); + } + + devcb_write_line write_irq; + + DECLARE_READ8_MEMBER(read); + DECLARE_WRITE8_MEMBER(write); + + sound_stream *m_stream; + +protected: + enum + { + R_VERSION = 0x800, + R_MODE, + R_CONTROL, + R_FIFOMODE, + R_FIFOSTAT, + R_WTCONTROL, + R_VOLUME, + R_CLOCK, + R_REG8, + R_REG9, + R_PLAYRECA, + R_REGB, + R_REGC, + R_REGD, + R_REGE, + R_TEST + }; + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + + // inline data + UINT8 m_chip_type; + + UINT8 m_fifo_a[0x400]; + UINT8 m_fifo_b[0x400]; + + UINT8 m_regs[0x800]; + + UINT32 m_phase[4], m_incr[4]; + + int m_fifo_a_rdptr, m_fifo_b_rdptr; + int m_fifo_a_wrptr, m_fifo_b_wrptr; + int m_fifo_cap_a, m_fifo_cap_b; + + emu_timer *m_timer; +}; + + +// device type definition +extern const device_type ASC; + + +#endif /* __ASC_H__ */ diff --git a/src/devices/sound/astrocde.c b/src/devices/sound/astrocde.c new file mode 100644 index 00000000000..0870347c6ae --- /dev/null +++ b/src/devices/sound/astrocde.c @@ -0,0 +1,285 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles,Frank Palazzolo +/*********************************************************** + + Astrocade custom 'IO' chip sound chip driver + Aaron Giles + based on original work by Frank Palazzolo + +************************************************************ + + Register Map + ============ + + Register 0: + D7..D0: Master oscillator frequency + + Register 1: + D7..D0: Tone generator A frequency + + Register 2: + D7..D0: Tone generator B frequency + + Register 3: + D7..D0: Tone generator C frequency + + Register 4: + D7..D6: Vibrato speed + D5..D0: Vibrato depth + + Register 5: + D5: Noise AM enable + D4: Mux source (0=vibrato, 1=noise) + D3..D0: Tone generator C volume + + Register 6: + D7..D4: Tone generator B volume + D3..D0: Tone generator A volume + + Register 7: + D7..D0: Noise volume + +***********************************************************/ + +#include "emu.h" +#include "astrocde.h" + + +// device type definition +const device_type ASTROCADE = &device_creator; + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// astrocade_device - constructor +//------------------------------------------------- + +astrocade_device::astrocade_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, ASTROCADE, "Astrocade", tag, owner, clock, "astrocade", __FILE__), + device_sound_interface(mconfig, *this), + m_stream(NULL), + m_master_count(0), + m_vibrato_clock(0), + m_noise_clock(0), + m_noise_state(0), + m_a_count(0), + m_a_state(0), + m_b_count(0), + m_b_state(0), + m_c_count(0), + m_c_state(0) +{ + memset(m_reg, 0, sizeof(UINT8)*8); + memset(m_bitswap, 0, sizeof(UINT8)*256); +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void astrocade_device::device_start() +{ + int i; + + /* generate a bitswap table for the noise */ + for (i = 0; i < 256; i++) + m_bitswap[i] = BITSWAP8(i, 0,1,2,3,4,5,6,7); + + /* allocate a stream for output */ + m_stream = stream_alloc(0, 1, clock()); + + /* reset state */ + device_reset(); + state_save_register(); +} + + +//------------------------------------------------- +// sound_stream_update - handle a stream update +//------------------------------------------------- + +void astrocade_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + stream_sample_t *dest = outputs[0]; + UINT16 noise_state; + UINT8 master_count; + UINT8 noise_clock; + + /* load some locals */ + master_count = m_master_count; + noise_clock = m_noise_clock; + noise_state = m_noise_state; + + /* loop over samples */ + while (samples > 0) + { + stream_sample_t cursample = 0; + int samples_this_time; + int samp; + + /* compute the number of cycles until the next master oscillator reset */ + /* or until the next noise boundary */ + samples_this_time = MIN(samples, 256 - master_count); + samples_this_time = MIN(samples_this_time, 64 - noise_clock); + samples -= samples_this_time; + + /* sum the output of the tone generators */ + if (m_a_state) + cursample += m_reg[6] & 0x0f; + if (m_b_state) + cursample += m_reg[6] >> 4; + if (m_c_state) + cursample += m_reg[5] & 0x0f; + + /* add in the noise if it is enabled, based on the top bit of the LFSR */ + if ((m_reg[5] & 0x20) && (noise_state & 0x4000)) + cursample += m_reg[7] >> 4; + + /* scale to max and output */ + cursample = cursample * 32767 / 60; + for (samp = 0; samp < samples_this_time; samp++) + *dest++ = cursample; + + /* clock the noise; a 2-bit counter clocks a 4-bit counter which clocks the LFSR */ + noise_clock += samples_this_time; + if (noise_clock >= 64) + { + /* update the noise state; this is a 15-bit LFSR with feedback from */ + /* the XOR of the top two bits */ + noise_state = (noise_state << 1) | (~((noise_state >> 14) ^ (noise_state >> 13)) & 1); + noise_clock -= 64; + + /* the same clock also controls the vibrato clock, which is a 13-bit counter */ + m_vibrato_clock++; + } + + /* clock the master oscillator; this is an 8-bit up counter */ + master_count += samples_this_time; + if (master_count == 0) + { + /* reload based on mux value -- the value from the register is negative logic */ + master_count = ~m_reg[0]; + + /* mux value 0 means reload based on the vibrato control */ + if ((m_reg[5] & 0x10) == 0) + { + /* vibrato speed (register 4 bits 6-7) selects one of the top 4 bits */ + /* of the 13-bit vibrato clock to use (0=highest freq, 3=lowest) */ + if (!((m_vibrato_clock >> (m_reg[4] >> 6)) & 0x0200)) + { + /* if the bit is clear, we add the vibrato volume to the counter */ + master_count += m_reg[4] & 0x3f; + } + } + + /* mux value 1 means reload based on the noise control */ + else + { + /* the top 8 bits of the noise LFSR are ANDed with the noise volume */ + /* register and added to the count */ + master_count += m_bitswap[(noise_state >> 7) & 0xff] & m_reg[7]; + } + + /* clock tone A */ + if (++m_a_count == 0) + { + m_a_state ^= 1; + m_a_count = ~m_reg[1]; + } + + /* clock tone B */ + if (++m_b_count == 0) + { + m_b_state ^= 1; + m_b_count = ~m_reg[2]; + } + + /* clock tone C */ + if (++m_c_count == 0) + { + m_c_state ^= 1; + m_c_count = ~m_reg[3]; + } + } + } + + /* put back the locals */ + m_master_count = master_count; + m_noise_clock = noise_clock; + m_noise_state = noise_state; +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void astrocade_device::device_reset() +{ + memset(m_reg, 0, sizeof(m_reg)); + + m_master_count = 0; + m_vibrato_clock = 0; + + m_noise_clock = 0; + m_noise_state = 0; + + m_a_count = 0; + m_a_state = 0; + + m_b_count = 0; + m_b_state = 0; + + m_c_count = 0; + m_c_state = 0; +} + + +//------------------------------------------------- +// Save state registration +//------------------------------------------------- + +void astrocade_device::state_save_register() +{ + save_item(NAME(m_reg)); + + save_item(NAME(m_master_count)); + save_item(NAME(m_vibrato_clock)); + + save_item(NAME(m_noise_clock)); + save_item(NAME(m_noise_state)); + + save_item(NAME(m_a_count)); + save_item(NAME(m_a_state)); + + save_item(NAME(m_b_count)); + save_item(NAME(m_b_state)); + + save_item(NAME(m_c_count)); + save_item(NAME(m_c_state)); +} + + +/************************************* + * + * Sound write accessors + * + *************************************/ + +WRITE8_MEMBER( astrocade_device::astrocade_sound_w ) +{ + if ((offset & 8) != 0) + offset = (offset >> 8) & 7; + else + offset &= 7; + + /* update */ + m_stream->update(); + + /* stash the new register value */ + m_reg[offset & 7] = data; +} diff --git a/src/devices/sound/astrocde.h b/src/devices/sound/astrocde.h new file mode 100644 index 00000000000..23e9a83c733 --- /dev/null +++ b/src/devices/sound/astrocde.h @@ -0,0 +1,73 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles,Frank Palazzolo +#pragma once + +#ifndef __ASTROCDE_H__ +#define __ASTROCDE_H__ + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_ASTROCADE_ADD(_tag, _clock) \ + MCFG_DEVICE_ADD(_tag, ASTROCADE, _clock) +#define MCFG_ASTROCADE_REPLACE(_tag, _clock) \ + MCFG_DEVICE_REPLACE(_tag, ASTROCADE, _clock) + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> astrocade_device + +class astrocade_device : public device_t, + public device_sound_interface +{ +public: + astrocade_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + ~astrocade_device() { } + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // sound stream update overrides + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + +public: + DECLARE_WRITE8_MEMBER( astrocade_sound_w ); + +private: + void state_save_register(); + +private: + sound_stream *m_stream; /* sound stream */ + + UINT8 m_reg[8]; /* 8 control registers */ + + UINT8 m_master_count; /* current master oscillator count */ + UINT16 m_vibrato_clock; /* current vibrato clock */ + + UINT8 m_noise_clock; /* current noise generator clock */ + UINT16 m_noise_state; /* current noise LFSR state */ + + UINT8 m_a_count; /* current tone generator A count */ + UINT8 m_a_state; /* current tone generator A state */ + + UINT8 m_b_count; /* current tone generator B count */ + UINT8 m_b_state; /* current tone generator B state */ + + UINT8 m_c_count; /* current tone generator C count */ + UINT8 m_c_state; /* current tone generator C state */ + + UINT8 m_bitswap[256]; /* bitswap table */ +}; + +extern const device_type ASTROCADE; + + +#endif /* __ASTROCDE_H__ */ diff --git a/src/devices/sound/awacs.c b/src/devices/sound/awacs.c new file mode 100644 index 00000000000..57668acaef5 --- /dev/null +++ b/src/devices/sound/awacs.c @@ -0,0 +1,176 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/*************************************************************************** + + awacs.c + + AWACS/Singer style 16-bit audio I/O for '040 and PowerPC Macs + + Emulation by R. Belmont + +***************************************************************************/ + +#include "emu.h" +#include "awacs.h" + +// device type definition +const device_type AWACS = &device_creator; + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// awacs_device - constructor +//------------------------------------------------- + +awacs_device::awacs_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, AWACS, "AWACS", tag, owner, clock, "awacs", __FILE__), + device_sound_interface(mconfig, *this) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void awacs_device::device_start() +{ + // create the stream + m_stream = machine().sound().stream_alloc(*this, 0, 2, 22050); + + memset(m_regs, 0, sizeof(m_regs)); + + m_timer = timer_alloc(0, NULL); + + save_item(NAME(m_play_ptr)); + save_item(NAME(m_buffer_size)); + save_item(NAME(m_playback_enable)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void awacs_device::device_reset() +{ + m_stream->update(); + + memset(m_regs, 0, sizeof(m_regs)); + + m_play_ptr = 0; + m_buffer_size = 0; + m_playback_enable = false; + m_dma_space = NULL; + m_dma_offset_0 = m_dma_offset_1 = 0; + m_buffer_num = 0; +} + +//------------------------------------------------- +// device_timer - called when our device timer expires +//------------------------------------------------- + +void awacs_device::device_timer(emu_timer &timer, device_timer_id tid, int param, void *ptr) +{ + m_stream->update(); +} + +//------------------------------------------------- +// sound_stream_update - handle update requests for +// our sound stream +//------------------------------------------------- + +void awacs_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + stream_sample_t *outL, *outR; + int offset = (m_buffer_num == 0) ? m_dma_offset_0 : m_dma_offset_1; + + outL = outputs[0]; + outR = outputs[1]; + + if (m_playback_enable) + { + for (int i = 0; i < samples; i++) + { + outL[i] = (INT16)m_dma_space->read_word(offset + m_play_ptr); + outR[i] = (INT16)m_dma_space->read_word(offset + m_play_ptr + 2); + m_play_ptr += 4; + } + + // out of buffer? + if (m_play_ptr >= m_buffer_size) + { + UINT8 bufflag[2] = { 0x40, 0x80 }; + + m_regs[0x18] |= bufflag[m_buffer_num]; + m_buffer_num ^= 1; + m_play_ptr = 0; + } + } + else + { + for (int i = 0; i < samples; i++) + { + outL[i] = 0; + outR[i] = 0; + } + } +} + +//------------------------------------------------- +// read - read from the chip's registers and internal RAM +//------------------------------------------------- + +READ8_MEMBER( awacs_device::read ) +{ + return m_regs[offset]; +} + +//------------------------------------------------- +// write - write to the chip's registers and internal RAM +//------------------------------------------------- + +WRITE8_MEMBER( awacs_device::write ) +{ + switch (offset) + { + case 0x8: + case 0x9: + m_regs[offset] = data; + m_buffer_size = (m_regs[8]<<6) | (m_regs[9]>>2); +// printf("buffer size = %x samples, %x bytes\n", m_buffer_size, m_buffer_size*4); + m_buffer_size *= 4; // samples * 16 bits * stereo + break; + + case 0x10: + { + static const int rates[4] = { 22100, 29400, 44100, 22100 }; + m_stream->set_sample_rate(rates[(data>>1)&3]); +// printf("rate %d, enable: %d\n", rates[(data>>1)&3], data & 1); + m_playback_enable = (data & 1) ? true : false; + + if (m_playback_enable && !(m_regs[0x10]&1)) + { + m_play_ptr = 0; + m_buffer_num = 0; + } + } + break; + + case 0x18: + m_regs[offset] &= 0xf0; + m_regs[offset] |= (data & 0x0f); + m_regs[offset] &= ~(data & 0xf0); + return; + } + + m_regs[offset] = data; +} + +void awacs_device::set_dma_base(address_space &space, int offset0, int offset1) +{ + m_dma_space = &space; + m_dma_offset_0 = offset0; + m_dma_offset_1 = offset1; +} diff --git a/src/devices/sound/awacs.h b/src/devices/sound/awacs.h new file mode 100644 index 00000000000..93b9da2d5d9 --- /dev/null +++ b/src/devices/sound/awacs.h @@ -0,0 +1,77 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/*************************************************************************** + + awacs.h + + AWACS/Singer style 16-bit audio I/O for '040 and PowerPC Macs + +***************************************************************************/ + +#pragma once + +#ifndef __AWACS_H__ +#define __AWACS_H__ + + + + +//************************************************************************** +// CONSTANTS +//************************************************************************** + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_AWACS_ADD(_tag, _clock) \ + MCFG_DEVICE_ADD(_tag, AWACS, _clock) + +#define MCFG_AWACS_REPLACE(_tag, _clock) \ + MCFG_DEVICE_REPLACE(_tag, AWACS, _clock) + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> awacs_device + +class awacs_device : public device_t, public device_sound_interface +{ +public: + // construction/destruction + awacs_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + DECLARE_READ8_MEMBER(read); + DECLARE_WRITE8_MEMBER(write); + + void set_dma_base(address_space &space, int offset0, int offset1); + + sound_stream *m_stream; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + + // inline data + UINT8 m_regs[0x100]; + + int m_play_ptr, m_buffer_size, m_buffer_num; + bool m_playback_enable; + + address_space *m_dma_space; + int m_dma_offset_0, m_dma_offset_1; + + emu_timer *m_timer; +}; + + +// device type definition +extern const device_type AWACS; + + +#endif /* __AWACS_H__ */ diff --git a/src/devices/sound/ay8910.c b/src/devices/sound/ay8910.c new file mode 100644 index 00000000000..9e8d397ff7a --- /dev/null +++ b/src/devices/sound/ay8910.c @@ -0,0 +1,1270 @@ +// license:BSD-3-Clause +// copyright-holders:Couriersud +/* + * Couriersud, July 2014: + * + * This documents recent work on the AY8910. A YM2149 is now on it's way from + * Hong Kong as well. + * + * TODO: + * + * - Create a true sound device nAY8910 driver. + * - implement approach outlined below in this driver. + * + * For years I had a AY8910 in my drawer. Arduinos were around as well. + * Using the approach documented in this blog post + * http://www.986-studio.com/2014/05/18/another-ay-entry/#more-476 + * I measured the output voltages using a Extech 520. + * + * Measurement Setup + * + * Laptop <--> Arduino <---> AY8910 + * + * AY8910 Registers: + * 0x07: 3f + * 0x08: RV + * 0x09: RV + * 0x0A: RV + * + * Output was measured on Analog Output B with a resistor RD to + * ground. + * + * Measurement results: + * + * RD 983 9.830k 99.5k 1.001M open + * + * RV B B B B B + * 0 0.0000 0.0000 0.0001 0.0011 0.0616 + * 1 0.0106 0.0998 0.6680 1.8150 2.7260 + * 2 0.0150 0.1377 0.8320 1.9890 2.8120 + * 3 0.0222 0.1960 1.0260 2.1740 2.9000 + * 4 0.0320 0.2708 1.2320 2.3360 2.9760 + * 5 0.0466 0.3719 1.4530 2.4880 3.0440 + * 6 0.0665 0.4938 1.6680 2.6280 3.1130 + * 7 0.1039 0.6910 1.9500 2.7900 3.1860 + * 8 0.1237 0.7790 2.0500 2.8590 3.2340 + * 9 0.1986 1.0660 2.3320 3.0090 3.3090 + * 10 0.2803 1.3010 2.5050 3.0850 3.3380 + * 11 0.3548 1.4740 2.6170 3.1340 3.3590 + * 12 0.4702 1.6870 2.7340 3.1800 3.3730 + * 13 0.6030 1.8870 2.8410 3.2300 3.4050 + * 14 0.7530 2.0740 2.9280 3.2580 3.4170 + * 15 0.9250 2.2510 3.0040 3.2940 3.4380 + * + * Using an equivalent model approach with two resistors + * + * 5V + * | + * Z + * Z Resistor Value for RV + * Z + * | + * +---> Output signal + * | + * Z + * Z External RD + * Z + * | + * GND + * + * will NOT work out of the box since RV = RV(RD). + * + * The following approach will be used going forward based on die pictures + * of the AY8910 done by Dr. Stack van Hay: + * + * + * 5V + * _| D + * G | NMOS + * Vg ---|| Kn depends on volume selected + * |_ S Vs + * | + * | + * +---> VO Output signal + * | + * Z + * Z External RD + * Z + * | + * GND + * + * Whilst conducting, the FET operates in saturation mode: + * + * Id = Kn * (Vgs - Vth)^2 + * + * Using Id = Vs / RD + * + * Vs = Kn * RD * (Vg - Vs - Vth)^2 + * + * finally using Vg' = Vg - Vth + * + * Vs = Vg' + 1 / (2 * Kn * RD) - sqrt((Vg' + 1 / (2 * Kn * RD))^2 - Vg'^2) + * + * and finally + * + * VO = Vs + * + * and this can be used to re-Thenevin to 5V + * + * RVequiv = RD * ( 5V / VO - 1) + * + * The RV and Kn parameter are derived using least squares to match + * calculation results with measurements. + * + * FIXME: + * There is voltage of 60 mV measured with the EX520 (Ri ~ 10M). This may + * be induced by cutoff currents from the 15 FETs. + * + */ + + +/*************************************************************************** + + ay8910.c + + Emulation of the AY-3-8910 / YM2149 sound chip. + + Based on various code snippets by Ville Hallik, Michael Cuddy, + Tatsuyuki Satoh, Fabrice Frances, Nicola Salmoria. + + Mostly rewritten by couriersud in 2008 + + Public documentation: + + - http://privatfrickler.de/blick-auf-den-chip-soundchip-general-instruments-ay-3-8910/ + Die pictures of the AY8910 + + - US Patent 4933980 + + Games using ADSR: gyruss + + A list with more games using ADSR can be found here: + http://mametesters.org/view.php?id=3043 + + TODO: + * The AY8930 has an extended mode which is currently + not emulated. + * YM2610 & YM2608 will need a separate flag in their config structures + to distinguish between legacy and discrete mode. + + The rewrite also introduces a generic model for the DAC. This model is + not perfect, but allows channel mixing based on a parametrized approach. + This model also allows to factor in different loads on individual channels. + If a better model is developped in the future or better measurements are + available, the driver should be easy to change. The model is described + later. + + In order to not break hundreds of existing drivers by default the flag + AY8910_LEGACY_OUTPUT is used by drivers not changed to take into account the + new model. All outputs are normalized to the old output range (i.e. 0 .. 7ffff). + In the case of channel mixing, output range is 0...3 * 7fff. + + The main difference between the AY-3-8910 and the YM2149 is, that the + AY-3-8910 datasheet mentions, that fixed volume level 0, which is set by + registers 8 to 10 is "channel off". The YM2149 mentions, that the generated + signal has a 2V DC component. This is confirmed by measurements. The approach + taken here is to assume the 2V DC offset for all outputs for the YM2149. + For the AY-3-8910, an offset is used if envelope is active for a channel. + This is backed by oscilloscope pictures from the datasheet. If a fixed volume + is set, i.e. envelope is disabled, the output voltage is set to 0V. Recordings + I found on the web for gyruss indicate, that the AY-3-8910 offset should + be around 0.2V. This will also make sound levels more compatible with + user observations for scramble. + + The Model: + 5V 5V + | | + / | + Volume Level x >---| Z + > Z Pullup Resistor RU + | Z + Z | + Rx Z | + Z | + | | + '-----+--------> >---+----> Output signal + | | + Z Z + Pulldown RD Z Z Load RL + Z Z + | | + GND GND + +Each Volume level x will select a different resistor Rx. Measurements from fpgaarcade.com +where used to calibrate channel mixing for the YM2149. This was done using +a least square approach using a fixed RL of 1K Ohm. + +For the AY measurements cited in e.g. openmsx as "Hacker Kay" for a single +channel were taken. These were normalized to 0 ... 65535 and consequently +adapted to an offset of 0.2V and a VPP of 1.3V. These measurements are in +line e.g. with the formula used by pcmenc for the volume: vol(i) = exp(i/2-7.5). + +The following is documentation from the code moved here and amended to reflect +the changes done: + +Careful studies of the chip output prove that the chip counts up from 0 +until the counter becomes greater or equal to the period. This is an +important difference when the program is rapidly changing the period to +modulate the sound. This is worthwhile noting, since the datasheets +say, that the chip counts down. +Also, note that period = 0 is the same as period = 1. This is mentioned +in the YM2203 data sheets. However, this does NOT apply to the Envelope +period. In that case, period = 0 is half as period = 1. + +Envelope shapes: + C AtAlH + 0 0 x x \___ + 0 1 x x /___ + 1 0 0 0 \\\\ + 1 0 0 1 \___ + 1 0 1 0 \/\/ + 1 0 1 1 \``` + 1 1 0 0 //// + 1 1 0 1 /``` + 1 1 1 0 /\/\ + 1 1 1 1 /___ + +The envelope counter on the AY-3-8910 has 16 steps. On the YM2149 it +has twice the steps, happening twice as fast. + +***************************************************************************/ + +#include "emu.h" +#include "ay8910.h" + +/************************************* + * + * Defines + * + *************************************/ + +#define ENABLE_REGISTER_TEST (0) /* Enable preprogrammed registers */ + +#define MAX_OUTPUT 0x7fff + +/* register id's */ +#define AY_AFINE (0) +#define AY_ACOARSE (1) +#define AY_BFINE (2) +#define AY_BCOARSE (3) +#define AY_CFINE (4) +#define AY_CCOARSE (5) +#define AY_NOISEPER (6) +#define AY_ENABLE (7) +#define AY_AVOL (8) +#define AY_BVOL (9) +#define AY_CVOL (10) +#define AY_EFINE (11) +#define AY_ECOARSE (12) +#define AY_ESHAPE (13) + +#define AY_PORTA (14) +#define AY_PORTB (15) + +#define NOISE_ENABLEQ(_chan) ((m_regs[AY_ENABLE] >> (3 + _chan)) & 1) +#define TONE_ENABLEQ(_chan) ((m_regs[AY_ENABLE] >> (_chan)) & 1) +#define TONE_PERIOD(_chan) ( m_regs[(_chan) << 1] | ((m_regs[((_chan) << 1) | 1] & 0x0f) << 8) ) +#define NOISE_PERIOD() ( m_regs[AY_NOISEPER] & 0x1f) +#define TONE_VOLUME(_chan) ( m_regs[AY_AVOL + (_chan)] & 0x0f) +#define TONE_ENVELOPE(_chan) ((m_regs[AY_AVOL + (_chan)] >> 4) & ((type() == AY8914) ? 3 : 1)) +#define ENVELOPE_PERIOD() ((m_regs[AY_EFINE] | (m_regs[AY_ECOARSE]<<8))) +#define NOISE_OUTPUT() (m_rng & 1) + +/************************************* + * + * Type definitions + * + *************************************/ + + +/************************************* + * + * Static + * + *************************************/ + +static const ay8910_device::ay_ym_param ym2149_param = +{ + 630, 801, + 16, + { 73770, 37586, 27458, 21451, 15864, 12371, 8922, 6796, + 4763, 3521, 2403, 1737, 1123, 762, 438, 251 }, +}; + +static const ay8910_device::ay_ym_param ym2149_param_env = +{ + 630, 801, + 32, + { 103350, 73770, 52657, 37586, 32125, 27458, 24269, 21451, + 18447, 15864, 14009, 12371, 10506, 8922, 7787, 6796, + 5689, 4763, 4095, 3521, 2909, 2403, 2043, 1737, + 1397, 1123, 925, 762, 578, 438, 332, 251 }, +}; + +#if 0 +/* RL = 1000, Hacker Kay normalized, 2.1V to 3.2V */ +static const ay8910_device::ay_ym_param ay8910_param = +{ + 664, 913, + 16, + { 85785, 34227, 26986, 20398, 14886, 10588, 7810, 4856, + 4120, 2512, 1737, 1335, 1005, 747, 586, 451 }, +}; + +/* + * RL = 3000, Hacker Kay normalized pattern, 1.5V to 2.8V + * These values correspond with guesses based on Gyruss schematics + * They work well with scramble as well. + */ +static const ay8910_device::ay_ym_param ay8910_param = +{ + 930, 454, + 16, + { 85066, 34179, 27027, 20603, 15046, 10724, 7922, 4935, + 4189, 2557, 1772, 1363, 1028, 766, 602, 464 }, +}; + +/* + * RL = 1000, Hacker Kay normalized pattern, 0.75V to 2.05V + * These values correspond with guesses based on Gyruss schematics + * They work well with scramble as well. + */ +static const ay8910_device::ay_ym_param ay8910_param = +{ + 1371, 313, + 16, + { 93399, 33289, 25808, 19285, 13940, 9846, 7237, 4493, + 3814, 2337, 1629, 1263, 962, 727, 580, 458 }, +}; + +/* + * RL = 1000, Hacker Kay normalized pattern, 0.2V to 1.5V + */ +static const ay8910_device::ay_ym_param ay8910_param = +{ + 5806, 300, + 16, + { 118996, 42698, 33105, 24770, 17925, 12678, 9331, 5807, + 4936, 3038, 2129, 1658, 1271, 969, 781, 623 } +}; +#endif + +/* + * RL = 2000, Based on Matthew Westcott's measurements from Dec 2001. + * ------------------------------------------------------------------- + * + * http://groups.google.com/group/comp.sys.sinclair/browse_thread/thread/fb3091da4c4caf26/d5959a800cda0b5e?lnk=gst&q=Matthew+Westcott#d5959a800cda0b5e + * After what Russell mentioned a couple of weeks back about the lack of + * publicised measurements of AY chip volumes - I've finally got round to + * making these readings, and I'm placing them in the public domain - so + * anyone's welcome to use them in emulators or anything else. + + * To make the readings, I set up the chip to produce a constant voltage on + * channel C (setting bits 2 and 5 of register 6), and varied the amplitude + * (the low 4 bits of register 10). The voltages were measured between the + * channel C output (pin 1) and ground (pin 6). + * + * Level Voltage + * 0 1.147 + * 1 1.162 + * 2 1.169 + * 3 1.178 + * 4 1.192 + * 5 1.213 + * 6 1.238 + * 7 1.299 + * 8 1.336 + * 9 1.457 + * 10 1.573 + * 11 1.707 + * 12 1.882 + * 13 2.06 + * 14 2.32 + * 15 2.58 + * ------------------------------------------------------------------- + * + * The ZX spectrum output circuit was modelled in SwitcherCAD and + * the resistor values below create the voltage levels above. + * RD was measured on a real chip to be 8m Ohm, RU was 0.8m Ohm. + */ + + +static const ay8910_device::ay_ym_param ay8910_param = +{ + 800000, 8000000, + 16, + { 15950, 15350, 15090, 14760, 14275, 13620, 12890, 11370, + 10600, 8590, 7190, 5985, 4820, 3945, 3017, 2345 } +}; + +static const ay8910_device::mosfet_param ay8910_mosfet_param = +{ + 1.465385778, + 4.9, + 16, + { + 0.00076, + 0.80536, + 1.13106, + 1.65952, + 2.42261, + 3.60536, + 5.34893, + 8.96871, + 10.97202, + 19.32370, + 29.01935, + 38.82026, + 55.50539, + 78.44395, + 109.49257, + 153.72985, + } +}; + + + + +/************************************* + * + * Inline + * + *************************************/ + +INLINE void build_3D_table(double rl, const ay8910_device::ay_ym_param *par, const ay8910_device::ay_ym_param *par_env, int normalize, double factor, int zero_is_off, INT32 *tab) +{ + double min = 10.0, max = 0.0; + + std::vector temp(8*32*32*32, 0); + + for (int e=0; e < 8; e++) + { + const ay8910_device::ay_ym_param *par_ch1 = (e & 0x01) ? par_env : par; + const ay8910_device::ay_ym_param *par_ch2 = (e & 0x02) ? par_env : par; + const ay8910_device::ay_ym_param *par_ch3 = (e & 0x04) ? par_env : par; + + for (int j1=0; j1 < par_ch1->res_count; j1++) + for (int j2=0; j2 < par_ch2->res_count; j2++) + for (int j3=0; j3 < par_ch3->res_count; j3++) + { + double n; + if (zero_is_off) + { + n = (j1 != 0 || (e & 0x01)) ? 1 : 0; + n += (j2 != 0 || (e & 0x02)) ? 1 : 0; + n += (j3 != 0 || (e & 0x04)) ? 1 : 0; + } + else + n = 3.0; + + double rt = n / par->r_up + 3.0 / par->r_down + 1.0 / rl; + double rw = n / par->r_up; + + rw += 1.0 / par_ch1->res[j1]; + rt += 1.0 / par_ch1->res[j1]; + rw += 1.0 / par_ch2->res[j2]; + rt += 1.0 / par_ch2->res[j2]; + rw += 1.0 / par_ch3->res[j3]; + rt += 1.0 / par_ch3->res[j3]; + + int indx = (e << 15) | (j3<<10) | (j2<<5) | j1; + temp[indx] = rw / rt; + if (temp[indx] < min) + min = temp[indx]; + if (temp[indx] > max) + max = temp[indx]; + } + } + + if (normalize) + { + for (int j=0; j < 32*32*32*8; j++) + tab[j] = MAX_OUTPUT * (((temp[j] - min)/(max-min))) * factor; + } + else + { + for (int j=0; j < 32*32*32*8; j++) + tab[j] = MAX_OUTPUT * temp[j]; + } + + /* for (e=0;e<16;e++) printf("%d %d\n",e<<10, tab[e<<10]); */ +} + +INLINE void build_single_table(double rl, const ay8910_device::ay_ym_param *par, int normalize, INT32 *tab, int zero_is_off) +{ + int j; + double rt, rw = 0; + double temp[32], min=10.0, max=0.0; + + for (j=0; j < par->res_count; j++) + { + rt = 1.0 / par->r_down + 1.0 / rl; + + rw = 1.0 / par->res[j]; + rt += 1.0 / par->res[j]; + + if (!(zero_is_off && j == 0)) + { + rw += 1.0 / par->r_up; + rt += 1.0 / par->r_up; + } + + temp[j] = rw / rt; + if (temp[j] < min) + min = temp[j]; + if (temp[j] > max) + max = temp[j]; + } + if (normalize) + { + for (j=0; j < par->res_count; j++) + tab[j] = MAX_OUTPUT * (((temp[j] - min)/(max-min)) - 0.25) * 0.5; + } + else + { + for (j=0; j < par->res_count; j++) + tab[j] = MAX_OUTPUT * temp[j]; + } + +} + +INLINE void build_mosfet_resistor_table(const ay8910_device::mosfet_param &par, const double rd, INT32 *tab) +{ + int j; + + for (j=0; j < par.m_count; j++) + { + const double Vd = 5.0; + const double Vg = par.m_Vg - par.m_Vth; + const double kn = par.m_Kn[j] / 1.0e6; + const double p2 = 1.0 / (2.0 * kn * rd) + Vg; + const double Vs = p2 - sqrt(p2 * p2 - Vg * Vg); + + const double res = rd * ( Vd / Vs - 1.0); + /* That's the biggest value we can stream on to netlist. */ + + if (res > (1 << 28)) + tab[j] = (1 << 28); + else + tab[j] = res; + //printf("%d %f %10d\n", j, rd / (res + rd) * 5.0, tab[j]); + } +} + + +UINT16 ay8910_device::mix_3D() +{ + int indx = 0, chan; + + for (chan = 0; chan < AY8910_NUM_CHANNELS; chan++) + if (TONE_ENVELOPE(chan) != 0) + { + if (type() == AY8914) // AY8914 Has a two bit tone_envelope field + { + indx |= (1 << (chan+15)) | ( m_vol_enabled[chan] ? ((m_env_volume >> (3-TONE_ENVELOPE(chan))) << (chan*5)) : 0); + } + else + { + indx |= (1 << (chan+15)) | ( m_vol_enabled[chan] ? m_env_volume << (chan*5) : 0); + } + } + else + { + indx |= (m_vol_enabled[chan] ? TONE_VOLUME(chan) << (chan*5) : 0); + } + return m_vol3d_table[indx]; +} + +/************************************* + * + * Static functions + * + *************************************/ + +void ay8910_device::ay8910_write_reg(int r, int v) +{ + //if (r >= 11 && r <= 13 ) printf("%d %x %02x\n", PSG->index, r, v); + m_regs[r] = v; + + switch( r ) + { + case AY_AFINE: + case AY_ACOARSE: + case AY_BFINE: + case AY_BCOARSE: + case AY_CFINE: + case AY_CCOARSE: + case AY_NOISEPER: + case AY_AVOL: + case AY_BVOL: + case AY_CVOL: + case AY_EFINE: + /* No action required */ + break; + case AY_ECOARSE: + #ifdef MAME_DEBUG + if ( (v & 0x0f) > 0) + popmessage("ECoarse"); + #endif + /* No action required */ + break; + case AY_ENABLE: + if ((m_last_enable == -1) || + ((m_last_enable & 0x40) != (m_regs[AY_ENABLE] & 0x40))) + { + /* write out 0xff if port set to input */ + if (!m_port_a_write_cb.isnull()) + m_port_a_write_cb((offs_t)0, (m_regs[AY_ENABLE] & 0x40) ? m_regs[AY_PORTA] : 0xff); + } + + if ((m_last_enable == -1) || + ((m_last_enable & 0x80) != (m_regs[AY_ENABLE] & 0x80))) + { + /* write out 0xff if port set to input */ + if (!m_port_b_write_cb.isnull()) + m_port_b_write_cb((offs_t)0, (m_regs[AY_ENABLE] & 0x80) ? m_regs[AY_PORTB] : 0xff); + } + m_last_enable = m_regs[AY_ENABLE]; + break; + case AY_ESHAPE: + #ifdef MAME_DEBUG + if ( (v & 0x0f) > 0) + popmessage("EShape"); + #endif + m_attack = (m_regs[AY_ESHAPE] & 0x04) ? m_env_step_mask : 0x00; + if ((m_regs[AY_ESHAPE] & 0x08) == 0) + { + /* if Continue = 0, map the shape to the equivalent one which has Continue = 1 */ + m_hold = 1; + m_alternate = m_attack; + } + else + { + m_hold = m_regs[AY_ESHAPE] & 0x01; + m_alternate = m_regs[AY_ESHAPE] & 0x02; + } + m_env_step = m_env_step_mask; + m_holding = 0; + m_env_volume = (m_env_step ^ m_attack); + break; + case AY_PORTA: + if (m_regs[AY_ENABLE] & 0x40) + { + if (!m_port_a_write_cb.isnull()) + m_port_a_write_cb((offs_t)0, m_regs[AY_PORTA]); + else + logerror("warning - write %02x to 8910 '%s' Port A\n",m_regs[AY_PORTA],tag()); + } + else + { + logerror("warning: write to 8910 '%s' Port A set as input - ignored\n",tag()); + } + break; + case AY_PORTB: + if (m_regs[AY_ENABLE] & 0x80) + { + if (!m_port_b_write_cb.isnull()) + m_port_b_write_cb((offs_t)0, m_regs[AY_PORTB]); + else + logerror("warning - write %02x to 8910 '%s' Port B\n",m_regs[AY_PORTB],tag()); + } + else + { + logerror("warning: write to 8910 '%s' Port B set as input - ignored\n",tag()); + } + break; + } +} + +//------------------------------------------------- +// sound_stream_update - handle a stream update +//------------------------------------------------- + +void ay8910_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + stream_sample_t *buf[AY8910_NUM_CHANNELS]; + int chan; + + buf[0] = outputs[0]; + buf[1] = NULL; + buf[2] = NULL; + if (m_streams == AY8910_NUM_CHANNELS) + { + buf[1] = outputs[1]; + buf[2] = outputs[2]; + } + + /* hack to prevent us from hanging when starting filtered outputs */ + if (!m_ready) + { + for (chan = 0; chan < AY8910_NUM_CHANNELS; chan++) + if (buf[chan] != NULL) + memset(buf[chan], 0, samples * sizeof(*buf[chan])); + } + + /* The 8910 has three outputs, each output is the mix of one of the three */ + /* tone generators and of the (single) noise generator. The two are mixed */ + /* BEFORE going into the DAC. The formula to mix each channel is: */ + /* (ToneOn | ToneDisable) & (NoiseOn | NoiseDisable). */ + /* Note that this means that if both tone and noise are disabled, the output */ + /* is 1, not 0, and can be modulated changing the volume. */ + + /* buffering loop */ + while (samples) + { + for (chan = 0; chan < AY8910_NUM_CHANNELS; chan++) + { + m_count[chan]++; + if (m_count[chan] >= TONE_PERIOD(chan)) + { + m_output[chan] ^= 1; + m_count[chan] = 0; + } + } + + m_count_noise++; + if (m_count_noise >= NOISE_PERIOD()) + { + /* toggle the prescaler output. Noise is no different to + * channels. + */ + m_count_noise = 0; + m_prescale_noise ^= 1; + + if ( m_prescale_noise) + { + /* The Random Number Generator of the 8910 is a 17-bit shift */ + /* register. The input to the shift register is bit0 XOR bit3 */ + /* (bit0 is the output). This was verified on AY-3-8910 and YM2149 chips. */ + + m_rng ^= (((m_rng & 1) ^ ((m_rng >> 3) & 1)) << 17); + m_rng >>= 1; + } + } + + for (chan = 0; chan < AY8910_NUM_CHANNELS; chan++) + { + m_vol_enabled[chan] = (m_output[chan] | TONE_ENABLEQ(chan)) & (NOISE_OUTPUT() | NOISE_ENABLEQ(chan)); + } + + /* update envelope */ + if (m_holding == 0) + { + m_count_env++; + if (m_count_env >= ENVELOPE_PERIOD() * m_step ) + { + m_count_env = 0; + m_env_step--; + + /* check envelope current position */ + if (m_env_step < 0) + { + if (m_hold) + { + if (m_alternate) + m_attack ^= m_env_step_mask; + m_holding = 1; + m_env_step = 0; + } + else + { + /* if CountEnv has looped an odd number of times (usually 1), */ + /* invert the output. */ + if (m_alternate && (m_env_step & (m_env_step_mask + 1))) + m_attack ^= m_env_step_mask; + + m_env_step &= m_env_step_mask; + } + } + + } + } + m_env_volume = (m_env_step ^ m_attack); + + if (m_streams == 3) + { + for (chan = 0; chan < AY8910_NUM_CHANNELS; chan++) + if (TONE_ENVELOPE(chan) != 0) + { + if (type() == AY8914) // AY8914 Has a two bit tone_envelope field + { + *(buf[chan]++) = m_env_table[chan][m_vol_enabled[chan] ? m_env_volume >> (3-TONE_ENVELOPE(chan)) : 0]; + } + else + { + *(buf[chan]++) = m_env_table[chan][m_vol_enabled[chan] ? m_env_volume : 0]; + } + } + else + { + *(buf[chan]++) = m_vol_table[chan][m_vol_enabled[chan] ? TONE_VOLUME(chan) : 0]; + } + } + else + { + *(buf[0]++) = mix_3D(); + } + samples--; + } +} + +void ay8910_device::build_mixer_table() +{ + int normalize = 0; + int chan; + + if ((m_flags & AY8910_LEGACY_OUTPUT) != 0) + { + logerror("AY-3-8910/YM2149 using legacy output levels!\n"); + normalize = 1; + } + + if ((m_flags & AY8910_RESISTOR_OUTPUT) != 0) + { + if (m_type != PSG_TYPE_AY) + fatalerror("AY8910_RESISTOR_OUTPUT currently only supported for AY8910 devices."); + + for (chan=0; chan < AY8910_NUM_CHANNELS; chan++) + { + build_mosfet_resistor_table(ay8910_mosfet_param, m_res_load[chan], m_vol_table[chan]); + build_mosfet_resistor_table(ay8910_mosfet_param, m_res_load[chan], m_env_table[chan]); + } + } + else if (m_streams == AY8910_NUM_CHANNELS) + { + for (chan=0; chan < AY8910_NUM_CHANNELS; chan++) + { + build_single_table(m_res_load[chan], m_par, normalize, m_vol_table[chan], m_zero_is_off); + build_single_table(m_res_load[chan], m_par_env, normalize, m_env_table[chan], 0); + } + } + /* + * The previous implementation added all three channels up instead of averaging them. + * The factor of 3 will force the same levels if normalizing is used. + */ + else + { + build_3D_table(m_res_load[0], m_par, m_par_env, normalize, 3, m_zero_is_off, m_vol3d_table); + } +} + +void ay8910_device::ay8910_statesave() +{ + save_item(NAME(m_register_latch)); + save_item(NAME(m_regs)); + save_item(NAME(m_last_enable)); + + save_item(NAME(m_count)); + save_item(NAME(m_count_noise)); + save_item(NAME(m_count_env)); + + save_item(NAME(m_env_volume)); + + save_item(NAME(m_output)); + save_item(NAME(m_prescale_noise)); + + save_item(NAME(m_env_step)); + save_item(NAME(m_hold)); + save_item(NAME(m_alternate)); + save_item(NAME(m_attack)); + save_item(NAME(m_holding)); + save_item(NAME(m_rng)); +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void ay8910_device::device_start() +{ + int master_clock = clock(); + + if (m_ioports < 1 && !(m_port_a_read_cb.isnull() && m_port_a_write_cb.isnull())) + fatalerror("Device '%s' is a %s and has no port A!", tag(), name()); + + if (m_ioports < 2 && !(m_port_b_read_cb.isnull() && m_port_b_write_cb.isnull())) + fatalerror("Device '%s' is a %s and has no port B!", tag(), name()); + + m_port_a_read_cb.resolve(); + m_port_b_read_cb.resolve(); + m_port_a_write_cb.resolve(); + m_port_b_write_cb.resolve(); + + if ((m_flags & AY8910_SINGLE_OUTPUT) != 0) + { + logerror("%s device '%s' using single output!\n", name(), tag()); + m_streams = 1; + } + + // FIXME: this doesn't belong here, it should be an input pin exposed via devcb + if (type() == YM2149 && (m_flags & YM2149_PIN26_LOW)) + { + master_clock /= 2; + } + + build_mixer_table(); + + /* The envelope is pacing twice as fast for the YM2149 as for the AY-3-8910, */ + /* This handled by the step parameter. Consequently we use a divider of 8 here. */ + m_channel = machine().sound().stream_alloc(*this, 0, m_streams, master_clock / 8); + + ay_set_clock(master_clock); + ay8910_statesave(); +} + + + +void ay8910_device::ay8910_reset_ym() +{ + int i; + + m_register_latch = 0; + m_rng = 1; + m_output[0] = 0; + m_output[1] = 0; + m_output[2] = 0; + m_count[0] = 0; + m_count[1] = 0; + m_count[2] = 0; + m_count_noise = 0; + m_count_env = 0; + m_prescale_noise = 0; + m_last_enable = -1; /* force a write */ + for (i = 0;i < AY_PORTA;i++) + ay8910_write_reg(i,0); + m_ready = 1; +#if ENABLE_REGISTER_TEST + ay8910_write_reg(AY_AFINE, 0); + ay8910_write_reg(AY_ACOARSE, 1); + ay8910_write_reg(AY_BFINE, 0); + ay8910_write_reg(AY_BCOARSE, 2); + ay8910_write_reg(AY_CFINE, 0); + ay8910_write_reg(AY_CCOARSE, 4); + //#define AY_NOISEPER (6) + ay8910_write_reg(AY_ENABLE, ~7); + ay8910_write_reg(AY_AVOL, 10); + ay8910_write_reg(AY_BVOL, 10); + ay8910_write_reg(AY_CVOL, 10); + //#define AY_EFINE (11) + //#define AY_ECOARSE (12) + //#define AY_ESHAPE (13) +#endif +} + +void ay8910_device::set_volume(int channel,int volume) +{ + int ch; + + for (ch = 0; ch < m_streams; ch++) + if (channel == ch || m_streams == 1 || channel == ALL_8910_CHANNELS) + m_channel->set_output_gain(ch, volume / 100.0); +} + +void ay8910_device::ay_set_clock(int clock) +{ + m_channel->set_sample_rate( clock / 8 ); +} + +void ay8910_device::ay8910_write_ym(int addr, int data) +{ + if (addr & 1) + { /* Data port */ + int r = m_register_latch; + + if (r > 15) return; + if (r == AY_ESHAPE || m_regs[r] != data) + { + /* update the output buffer before changing the register */ + m_channel->update(); + } + + ay8910_write_reg(r,data); + } + else + { /* Register port */ + m_register_latch = data & 0x0f; + } +} + +int ay8910_device::ay8910_read_ym() +{ + device_type chip_type = type(); + int r = m_register_latch; + + if (r > 15) return 0; + + /* There are no state dependent register in the AY8910! */ + /* m_channel->update(); */ + + switch (r) + { + case AY_PORTA: + if ((m_regs[AY_ENABLE] & 0x40) != 0) + logerror("warning: read from 8910 '%s' Port A set as output\n",tag()); + /* + even if the port is set as output, we still need to return the external + data. Some games, like kidniki, need this to work. + + FIXME: The io ports are designed as open collector outputs. Bits 7 and 8 of AY_ENABLE + only enable (low) or disable (high) the pull up resistors. The YM2149 datasheet + specifies those pull up resistors as 60k to 600k (min / max). + We do need a callback for those two flags. Kid Niki (Irem m62) is one such + case were it makes a difference in comparison to a standard TTL output. + */ + if (!m_port_a_read_cb.isnull()) + m_regs[AY_PORTA] = m_port_a_read_cb(0); + else + logerror("%s: warning - read 8910 '%s' Port A\n",machine().describe_context(),tag()); + break; + case AY_PORTB: + if ((m_regs[AY_ENABLE] & 0x80) != 0) + logerror("warning: read from 8910 '%s' Port B set as output\n",tag()); + if (!m_port_b_read_cb.isnull()) + m_regs[AY_PORTB] = m_port_b_read_cb(0); + else + logerror("%s: warning - read 8910 '%s' Port B\n",machine().describe_context(),tag()); + break; + } + + /* Depending on chip type, unused bits in registers may or may not be accessible. + Untested chips are assumed to regard them as 'ram' + Tested and confirmed on hardware: + - AY-3-8910: inaccessible bits (see masks below) read back as 0 + - YM2149: no anomaly + */ + if (chip_type == AY8910) { + const UINT8 mask[0x10]={ + 0xff,0x0f,0xff,0x0f,0xff,0x0f,0x1f,0xff,0x1f,0x1f,0x1f,0xff,0xff,0x0f,0xff,0xff + }; + + return m_regs[r] & mask[r]; + } + else return m_regs[r]; +} + +/************************************* + * + * Sound Interface + * + *************************************/ + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void ay8910_device::device_reset() +{ + ay8910_reset_ym(); +} + +/************************************* + * + * Read/Write Handlers + * + *************************************/ + +READ8_MEMBER( ay8910_device::data_r ) +{ + return ay8910_read_ym(); +} + +WRITE8_MEMBER( ay8910_device::data_address_w ) +{ + /* note that directly connecting BC1 to A0 puts data on 0 and address on 1 */ + ay8910_write_ym(~offset & 1, data); +} + +WRITE8_MEMBER( ay8910_device::address_data_w ) +{ + ay8910_write_ym(offset & 1, data); +} + +WRITE8_MEMBER( ay8910_device::address_w ) +{ +#if ENABLE_REGISTER_TEST + return; +#else + data_address_w(space, 1, data); +#endif +} + +WRITE8_MEMBER( ay8910_device::data_w ) +{ +#if ENABLE_REGISTER_TEST + return; +#else + data_address_w(space, 0, data); +#endif +} + +WRITE8_MEMBER( ay8910_device::reset_w ) +{ + ay8910_reset_ym(); +} + +static const int mapping8914to8910[16] = { 0, 2, 4, 11, 1, 3, 5, 12, 7, 6, 13, 8, 9, 10, 14, 15 }; + +READ8_MEMBER( ay8914_device::read ) +{ + UINT16 rv; + address_w(space, 0, mapping8914to8910[offset & 0xf]); + rv = (UINT16) data_r(space, 0); + return rv; +} + +WRITE8_MEMBER( ay8914_device::write ) +{ + address_w(space, 0, mapping8914to8910[offset & 0xf]); + data_w(space, 0, data & 0xff); +} + + + +const device_type AY8910 = &device_creator; + +ay8910_device::ay8910_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, AY8910, "AY-3-8910A", tag, owner, clock, "ay8910", __FILE__), + device_sound_interface(mconfig, *this), + m_type(PSG_TYPE_AY), + m_streams(3), + m_ioports(2), + m_ready(0), + m_channel(NULL), + m_register_latch(0), + m_last_enable(0), + m_prescale_noise(0), + m_count_noise(0), + m_count_env(0), + m_env_step(0), + m_env_volume(0), + m_hold(0), + m_alternate(0), + m_attack(0), + m_holding(0), + m_rng(0), + m_env_step_mask(0x0f), + m_step(2), + m_zero_is_off(1), + m_par(&ay8910_param), + m_par_env(&ay8910_param), + m_flags(AY8910_LEGACY_OUTPUT), + m_port_a_read_cb(*this), + m_port_b_read_cb(*this), + m_port_a_write_cb(*this), + m_port_b_write_cb(*this) +{ + memset(&m_regs,0,sizeof(m_regs)); + memset(&m_count,0,sizeof(m_count)); + memset(&m_output,0,sizeof(m_output)); + memset(&m_vol_enabled,0,sizeof(m_vol_enabled)); + memset(&m_vol_table,0,sizeof(m_vol_table)); + memset(&m_env_table,0,sizeof(m_env_table)); + memset(&m_vol3d_table,0,sizeof(m_vol3d_table)); + m_res_load[0] = m_res_load[1] = m_res_load[2] = 1000; //Default values for resistor loads +} + +ay8910_device::ay8910_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, + psg_type_t psg_type, int streams, int ioports, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_sound_interface(mconfig, *this), + m_type(psg_type), + m_streams(streams), + m_ioports(ioports), + m_ready(0), + m_channel(NULL), + m_register_latch(0), + m_last_enable(0), + m_prescale_noise(0), + m_count_noise(0), + m_count_env(0), + m_env_step(0), + m_env_volume(0), + m_hold(0), + m_alternate(0), + m_attack(0), + m_holding(0), + m_rng(0), + m_env_step_mask(psg_type == PSG_TYPE_AY ? 0x0f : 0x1f), + m_step( psg_type == PSG_TYPE_AY ? 2 : 1), + m_zero_is_off( psg_type == PSG_TYPE_AY ? 1 : 0), + m_par( psg_type == PSG_TYPE_AY ? &ay8910_param : &ym2149_param), + m_par_env( psg_type == PSG_TYPE_AY ? &ay8910_param : &ym2149_param_env), + m_flags(AY8910_LEGACY_OUTPUT), + m_port_a_read_cb(*this), + m_port_b_read_cb(*this), + m_port_a_write_cb(*this), + m_port_b_write_cb(*this) +{ + memset(&m_regs,0,sizeof(m_regs)); + memset(&m_count,0,sizeof(m_count)); + memset(&m_output,0,sizeof(m_output)); + memset(&m_vol_enabled,0,sizeof(m_vol_enabled)); + memset(&m_vol_table,0,sizeof(m_vol_table)); + memset(&m_env_table,0,sizeof(m_env_table)); + memset(&m_vol3d_table,0,sizeof(m_vol3d_table)); + m_res_load[0] = m_res_load[1] = m_res_load[2] = 1000; //Default values for resistor loads +} + +const device_type AY8912 = &device_creator; + +ay8912_device::ay8912_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : ay8910_device(mconfig, AY8912, "AY-3-8912A", tag, owner, clock, PSG_TYPE_AY, 3, 1, "ay8912", __FILE__) +{ +} + + +const device_type AY8913 = &device_creator; + +ay8913_device::ay8913_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : ay8910_device(mconfig, AY8913, "AY-3-8913A", tag, owner, clock, PSG_TYPE_AY, 3, 0, "ay8913", __FILE__) +{ +} + + +const device_type AY8914 = &device_creator; + +ay8914_device::ay8914_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : ay8910_device(mconfig, AY8914, "AY-3-8914", tag, owner, clock, PSG_TYPE_AY, 3, 2, "ay8914", __FILE__) +{ +} + + +const device_type AY8930 = &device_creator; + +ay8930_device::ay8930_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : ay8910_device(mconfig, AY8930, "AY8930", tag, owner, clock, PSG_TYPE_AY, 3, 2, "ay8930", __FILE__) +{ +} + + +const device_type YM2149 = &device_creator; + +ym2149_device::ym2149_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : ay8910_device(mconfig, YM2149, "YM2149", tag, owner, clock, PSG_TYPE_YM, 3, 2, "ym2149", __FILE__) +{ +} + + +const device_type YM3439 = &device_creator; + +ym3439_device::ym3439_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : ay8910_device(mconfig, YM3439, "YM3439", tag, owner, clock, PSG_TYPE_YM, 3, 2, "ym3429", __FILE__) +{ +} + + +const device_type YMZ284 = &device_creator; + +ymz284_device::ymz284_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : ay8910_device(mconfig, YMZ284, "YMZ284", tag, owner, clock, PSG_TYPE_YM, 1, 0, "ymz284", __FILE__) +{ +} + + +const device_type YMZ294 = &device_creator; + +ymz294_device::ymz294_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : ay8910_device(mconfig, YMZ294, "YMZ294", tag, owner, clock, PSG_TYPE_YM, 1, 0, "ymz294", __FILE__) +{ +} diff --git a/src/devices/sound/ay8910.h b/src/devices/sound/ay8910.h new file mode 100644 index 00000000000..30ef634b766 --- /dev/null +++ b/src/devices/sound/ay8910.h @@ -0,0 +1,273 @@ +// license:BSD-3-Clause +// copyright-holders:Couriersud +#pragma once + +#ifndef __AY8910_H__ +#define __AY8910_H__ + +#include "emu.h" + +/* +AY-3-8910A: 2 I/O ports +AY-3-8912A: 1 I/O port +AY-3-8913A: 0 I/O port +AY-3-8914: same as 8910 except for different register mapping and two bit envelope enable / volume field +AY8930: upper compatible with 8910. +In extended mode, it has higher resolution and duty ratio setting +YM2149: higher resolution, selectable clock divider +YM3439: same as 2149 +YMZ284: 0 I/O port, different clock divider +YMZ294: 0 I/O port +*/ + +#define ALL_8910_CHANNELS -1 + +/* Internal resistance at Volume level 7. */ + +#define AY8910_INTERNAL_RESISTANCE (356) +#define YM2149_INTERNAL_RESISTANCE (353) + +/* + * The following is used by all drivers not reviewed yet. + * This will like the old behaviour, output between + * 0 and 7FFF + */ +#define AY8910_LEGACY_OUTPUT (0x01) + +/* + * Specifing the next define will simulate the special + * cross channel mixing if outputs are tied together. + * The driver will only provide one stream in this case. + */ +#define AY8910_SINGLE_OUTPUT (0x02) + +/* + * The following define is the default behaviour. + * Output level 0 is 0V and 7ffff corresponds to 5V. + * Use this to specify that a discrete mixing stage + * follows. + */ +#define AY8910_DISCRETE_OUTPUT (0x04) + +/* + * The following define causes the driver to output + * resistor values. Intended to be used for + * netlist interfacing. + */ + +#define AY8910_RESISTOR_OUTPUT (0x08) + +/* + * This define specifies the initial state of YM2149 + * pin 26 (SEL pin). By default it is set to high, + * compatible with AY8910. + */ +/* TODO: make it controllable while it's running (used by any hw???) */ +#define YM2149_PIN26_HIGH (0x00) /* or N/C */ +#define YM2149_PIN26_LOW (0x10) + + +#define AY8910_NUM_CHANNELS 3 + + +#define MCFG_AY8910_OUTPUT_TYPE(_flag) \ + ay8910_device::set_flags(*device, _flag); + +#define MCFG_AY8910_RES_LOADS(_res0, _res1, _res2) \ + ay8910_device::set_resistors_load(*device, _res0, _res1, _res2); + +#define MCFG_AY8910_PORT_A_READ_CB(_devcb) \ + devcb = &ay8910_device::set_port_a_read_callback(*device, DEVCB_##_devcb); + +#define MCFG_AY8910_PORT_B_READ_CB(_devcb) \ + devcb = &ay8910_device::set_port_b_read_callback(*device, DEVCB_##_devcb); + +#define MCFG_AY8910_PORT_A_WRITE_CB(_devcb) \ + devcb = &ay8910_device::set_port_a_write_callback(*device, DEVCB_##_devcb); + +#define MCFG_AY8910_PORT_B_WRITE_CB(_devcb) \ + devcb = &ay8910_device::set_port_b_write_callback(*device, DEVCB_##_devcb); + + +class ay8910_device : public device_t, + public device_sound_interface +{ +public: + enum psg_type_t + { + PSG_TYPE_AY, + PSG_TYPE_YM + }; + + // construction/destruction + ay8910_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + ay8910_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, + UINT32 clock, psg_type_t psg_type, int streams, int ioports, const char *shortname, const char *source); + + // static configuration helpers + static void set_flags(device_t &device, int flags) { downcast(device).m_flags = flags; } + static void set_resistors_load(device_t &device, int res_load0, int res_load1, int res_load2) { downcast(device).m_res_load[0] = res_load0; downcast(device).m_res_load[1] = res_load1; downcast(device).m_res_load[2] = res_load2; } + template static devcb_base &set_port_a_read_callback(device_t &device, _Object object) { return downcast(device).m_port_a_read_cb.set_callback(object); } + template static devcb_base &set_port_b_read_callback(device_t &device, _Object object) { return downcast(device).m_port_b_read_cb.set_callback(object); } + template static devcb_base &set_port_a_write_callback(device_t &device, _Object object) { return downcast(device).m_port_a_write_cb.set_callback(object); } + template static devcb_base &set_port_b_write_callback(device_t &device, _Object object) { return downcast(device).m_port_b_write_cb.set_callback(object); } + + DECLARE_READ8_MEMBER( data_r ); + DECLARE_WRITE8_MEMBER( address_w ); + DECLARE_WRITE8_MEMBER( data_w ); + + /* /RES */ + DECLARE_WRITE8_MEMBER( reset_w ); + + /* use this when BC1 == A0; here, BC1=0 selects 'data' and BC1=1 selects 'latch address' */ + DECLARE_WRITE8_MEMBER( data_address_w ); + + /* use this when BC1 == !A0; here, BC1=0 selects 'latch address' and BC1=1 selects 'data' */ + DECLARE_WRITE8_MEMBER( address_data_w ); + + void set_volume(int channel,int volume); + void ay_set_clock(int clock); + + struct ay_ym_param + { + double r_up; + double r_down; + int res_count; + double res[32]; + }; + + struct mosfet_param + { + double m_Vth; + double m_Vg; + int m_count; + double m_Kn[32]; + }; + + void ay8910_write_ym(int addr, int data); + int ay8910_read_ym(); + void ay8910_reset_ym(); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // sound stream update overrides + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + +private: + // internal helpers + inline UINT16 mix_3D(); + void ay8910_write_reg(int r, int v); + void build_mixer_table(); + void ay8910_statesave(); + + // internal state + psg_type_t m_type; + int m_streams; + int m_ioports; + int m_ready; + sound_stream *m_channel; + INT32 m_register_latch; + UINT8 m_regs[16]; + INT32 m_last_enable; + INT32 m_count[AY8910_NUM_CHANNELS]; + UINT8 m_output[AY8910_NUM_CHANNELS]; + UINT8 m_prescale_noise; + INT32 m_count_noise; + INT32 m_count_env; + INT8 m_env_step; + UINT32 m_env_volume; + UINT8 m_hold,m_alternate,m_attack,m_holding; + INT32 m_rng; + UINT8 m_env_step_mask; + /* init parameters ... */ + int m_step; + int m_zero_is_off; + UINT8 m_vol_enabled[AY8910_NUM_CHANNELS]; + const ay_ym_param *m_par; + const ay_ym_param *m_par_env; + INT32 m_vol_table[AY8910_NUM_CHANNELS][16]; + INT32 m_env_table[AY8910_NUM_CHANNELS][32]; + INT32 m_vol3d_table[8*32*32*32]; + int m_flags; /* Flags */ + int m_res_load[3]; /* Load on channel in ohms */ + devcb_read8 m_port_a_read_cb; + devcb_read8 m_port_b_read_cb; + devcb_write8 m_port_a_write_cb; + devcb_write8 m_port_b_write_cb; +}; + +extern const device_type AY8910; + +class ay8912_device : public ay8910_device +{ +public: + ay8912_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +extern const device_type AY8912; + +class ay8913_device : public ay8910_device +{ +public: + ay8913_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +extern const device_type AY8913; + +class ay8914_device : public ay8910_device +{ +public: + ay8914_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + /* AY8914 handlers needed due to different register map */ + DECLARE_READ8_MEMBER( read ); + DECLARE_WRITE8_MEMBER( write ); +}; + +extern const device_type AY8914; + +class ay8930_device : public ay8910_device +{ +public: + ay8930_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +extern const device_type AY8930; + +class ym2149_device : public ay8910_device +{ +public: + ym2149_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +extern const device_type YM2149; + +class ym3439_device : public ay8910_device +{ +public: + ym3439_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +extern const device_type YM3439; + +class ymz284_device : public ay8910_device +{ +public: + ymz284_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +extern const device_type YMZ284; + +class ymz294_device : public ay8910_device +{ +public: + ymz294_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +extern const device_type YMZ294; + + +#endif /* __AY8910_H__ */ diff --git a/src/devices/sound/beep.c b/src/devices/sound/beep.c new file mode 100644 index 00000000000..ce5558f3320 --- /dev/null +++ b/src/devices/sound/beep.c @@ -0,0 +1,147 @@ +// license:BSD-3-Clause +// copyright-holders:Kevin Thacker +/*************************************************************************** + + beep.c + + This is used for computers/systems which can only output a constant tone. + This tone can be turned on and off. + e.g. PCW and PCW16 computer systems + KT - 25-Jun-2000 + + Sound handler + +****************************************************************************/ + +#include "emu.h" +#include "sound/beep.h" + +#define BEEP_RATE (48000) + + +// device type definition +const device_type BEEP = &device_creator; + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// beep_device - constructor +//------------------------------------------------- + +beep_device::beep_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, BEEP, "Beep", tag, owner, clock, "beep", __FILE__), + device_sound_interface(mconfig, *this), + m_stream(NULL), + m_enable(0), + m_frequency(0), + m_incr(0), + m_signal(0) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void beep_device::device_start() +{ + m_stream = stream_alloc(0, 1, BEEP_RATE); + m_enable = 0; + m_frequency = 3250; + m_incr = 0; + m_signal = 0x07fff; +} + + +//------------------------------------------------- +// sound_stream_update - handle a stream update +//------------------------------------------------- + +void beep_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + stream_sample_t *buffer = outputs[0]; + INT16 signal = m_signal; + int clock = 0, rate = BEEP_RATE / 2; + + /* get progress through wave */ + int incr = m_incr; + + if (m_frequency > 0) + clock = m_frequency; + + /* if we're not enabled, just fill with 0 */ + if ( !m_enable || clock == 0 ) + { + memset( buffer, 0, samples * sizeof(*buffer) ); + return; + } + + /* fill in the sample */ + while( samples-- > 0 ) + { + *buffer++ = signal; + incr -= clock; + while( incr < 0 ) + { + incr += rate; + signal = -signal; + } + } + + /* store progress through wave */ + m_incr = incr; + m_signal = signal; +} + + +//------------------------------------------------- +// changing state to on from off will restart tone +//------------------------------------------------- + +void beep_device::set_state(int on) +{ + /* only update if new state is not the same as old state */ + if (m_enable == on) + return; + + m_stream->update(); + m_enable = on; + + /* restart wave from beginning */ + m_incr = 0; + m_signal = 0x07fff; +} + + + +//------------------------------------------------- +// setting new frequency starts from beginning +//------------------------------------------------- + +void beep_device::set_frequency(int frequency) +{ + if (m_frequency == frequency) + return; + + m_stream->update(); + m_frequency = frequency; + m_signal = 0x07fff; + m_incr = 0; +} + + + +//------------------------------------------------- +// change a channel volume +//------------------------------------------------- + +void beep_device::set_volume(int volume) +{ + m_stream->update(); + volume = 100 * volume / 7; + set_output_gain(0, volume); +} diff --git a/src/devices/sound/beep.h b/src/devices/sound/beep.h new file mode 100644 index 00000000000..4b587bd3c89 --- /dev/null +++ b/src/devices/sound/beep.h @@ -0,0 +1,44 @@ +// license:BSD-3-Clause +// copyright-holders:Kevin Thacker +#pragma once + +#ifndef __BEEP_H__ +#define __BEEP_H__ + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> beep_device + +class beep_device : public device_t, + public device_sound_interface +{ +public: + beep_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + ~beep_device() { } + +protected: + // device-level overrides + virtual void device_start(); + + // sound stream update overrides + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + +public: + void set_state(int on); + void set_frequency(int frequency); + void set_volume(int volume); + +private: + sound_stream *m_stream; /* stream number */ + int m_enable; /* enable beep */ + int m_frequency; /* set frequency - this can be changed using the appropiate function */ + int m_incr; /* initial wave state */ + INT16 m_signal; /* current signal */ +}; + +extern const device_type BEEP; + + +#endif /* __BEEP_H__ */ diff --git a/src/devices/sound/bsmt2000.c b/src/devices/sound/bsmt2000.c new file mode 100644 index 00000000000..0b1dea55354 --- /dev/null +++ b/src/devices/sound/bsmt2000.c @@ -0,0 +1,358 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + bsmt2000.c + + BSMT2000 device emulator. + +**************************************************************************** + + Chip is actually a TMS320C15 DSP with embedded mask rom + Trivia: BSMT stands for "Brian Schmidt's Mouse Trap" + +***************************************************************************/ + +#include "emu.h" +#include "bsmt2000.h" + + +// device type definition +const device_type BSMT2000 = &device_creator; + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +// program map for the DSP (points to internal ROM) +static ADDRESS_MAP_START( tms_program_map, AS_PROGRAM, 16, bsmt2000_device) + ADDRESS_MAP_UNMAP_HIGH + AM_RANGE(0x000, 0xfff) AM_ROM +ADDRESS_MAP_END + + +// I/O map for the DSP +static ADDRESS_MAP_START( tms_io_map, AS_IO, 16, bsmt2000_device) + AM_RANGE(0, 0) AM_READWRITE(tms_register_r, tms_rom_addr_w) + AM_RANGE(1, 1) AM_READWRITE(tms_data_r, tms_rom_bank_w) + AM_RANGE(2, 2) AM_READ(tms_rom_r) + AM_RANGE(3, 3) AM_WRITE(tms_left_w) + AM_RANGE(7, 7) AM_WRITE(tms_right_w) + AM_RANGE(TMS32010_BIO, TMS32010_BIO) AM_READ(tms_write_pending_r) +ADDRESS_MAP_END + + +// machine fragment +static MACHINE_CONFIG_FRAGMENT( bsmt2000 ) + MCFG_CPU_ADD("bsmt2000", TMS32015, DERIVED_CLOCK(1,1)) + MCFG_CPU_PROGRAM_MAP(tms_program_map) + // data map is internal to the CPU + MCFG_CPU_IO_MAP(tms_io_map) +MACHINE_CONFIG_END + + +// default address map for the external memory interface +// the BSMT can address a full 32 bits but typically only 24 are used +static ADDRESS_MAP_START( bsmt2000, AS_0, 8, bsmt2000_device) + AM_RANGE(0x00000, 0xffffff) AM_ROM +ADDRESS_MAP_END + + +// ROM definition for the BSMT2000 program ROM +ROM_START( bsmt2000 ) + ROM_REGION( 0x2000, "bsmt2000", 0 ) + ROM_LOAD16_WORD( "bsmt2000.bin", 0x0000, 0x2000, CRC(c2a265af) SHA1(6ec9eb038fb8eb842c5482aebe1d149daf49f2e6) ) +ROM_END + + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// bsmt2000_device - constructor +//------------------------------------------------- + +bsmt2000_device::bsmt2000_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, BSMT2000, "BSMT2000", tag, owner, clock, "bsmt2000", __FILE__), + device_sound_interface(mconfig, *this), + device_memory_interface(mconfig, *this), + m_space_config("samples", ENDIANNESS_LITTLE, 8, 32, 0, NULL), + m_ready_callback(NULL), + m_stream(NULL), + m_direct(NULL), + m_cpu(NULL), + m_register_select(0), + m_write_data(0), + m_rom_address(0), + m_rom_bank(0), + m_left_data(0), + m_right_data(0), + m_write_pending(false) +{ + m_address_map[0] = *ADDRESS_MAP_NAME(bsmt2000); +} + + +//------------------------------------------------- +// static_set_ready_callback - configuration +// helper to set the ready callback +//------------------------------------------------- + +void bsmt2000_device::static_set_ready_callback(device_t &device, ready_callback callback) +{ + bsmt2000_device &bsmt = downcast(device); + bsmt.m_ready_callback = callback; +} + + +//------------------------------------------------- +// rom_region - return a pointer to the device's +// internal ROM region +//------------------------------------------------- + +const rom_entry *bsmt2000_device::device_rom_region() const +{ + return ROM_NAME( bsmt2000 ); +} + + +//------------------------------------------------- +// machine_config_additions - return a pointer to +// the device's machine fragment +//------------------------------------------------- + +machine_config_constructor bsmt2000_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( bsmt2000 ); +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void bsmt2000_device::device_start() +{ + // find our CPU + m_cpu = subdevice("bsmt2000"); + + // find our direct access + m_direct = &space().direct(); + + // create the stream; BSMT typically runs at 24MHz and writes to a DAC, so + // in theory we should generate a 24MHz stream, but that's certainly overkill + // internally at 24MHz the max output sample rate is 32kHz + // divided by 128 gives us 6x the max output rate which is plenty for oversampling + m_stream = stream_alloc(0, 2, clock() / 128); + + // register for save states + save_item(NAME(m_register_select)); + save_item(NAME(m_write_data)); + save_item(NAME(m_rom_address)); + save_item(NAME(m_rom_bank)); + save_item(NAME(m_left_data)); + save_item(NAME(m_right_data)); + save_item(NAME(m_write_pending)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void bsmt2000_device::device_reset() +{ + synchronize(TIMER_ID_RESET); +} + + +//------------------------------------------------- +// memory_space_config - return a description of +// any address spaces owned by this device +//------------------------------------------------- + +const address_space_config *bsmt2000_device::memory_space_config(address_spacenum spacenum) const +{ + return (spacenum == 0) ? &m_space_config : NULL; +} + + +//------------------------------------------------- +// device_timer - handle deferred writes and +// resets as a timer callback +//------------------------------------------------- + +void bsmt2000_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch (id) + { + // deferred reset + case TIMER_ID_RESET: + m_stream->update(); + m_cpu->reset(); + break; + + // deferred register write + case TIMER_ID_REG_WRITE: + m_register_select = param & 0xffff; + break; + + // deferred data write + case TIMER_ID_DATA_WRITE: + m_write_data = param & 0xffff; + if (m_write_pending) logerror("BSMT2000: Missed data\n"); + m_write_pending = true; + break; + } +} + + +//------------------------------------------------- +// sound_stream_update - handle update requests +// for our sound stream +//------------------------------------------------- + +void bsmt2000_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + // just fill with current left/right values + for (int samp = 0; samp < samples; samp++) + { + outputs[0][samp] = m_left_data * 16; + outputs[1][samp] = m_right_data * 16; + } +} + + +//------------------------------------------------- +// read_status - return the write pending status +//------------------------------------------------- + +UINT16 bsmt2000_device::read_status() +{ + return m_write_pending ? 0 : 1; +} + + +//------------------------------------------------- +// write_reg - handle writes to the BSMT2000 +// register select interface +//------------------------------------------------- + +void bsmt2000_device::write_reg(UINT16 data) +{ + synchronize(TIMER_ID_REG_WRITE, data); +} + + +//------------------------------------------------- +// write_data - handle writes to the BSMT2000 +// data port +//------------------------------------------------- + +void bsmt2000_device::write_data(UINT16 data) +{ + synchronize(TIMER_ID_DATA_WRITE, data); + + // boost the interleave on a write so that the caller detects the status more accurately + machine().scheduler().boost_interleave(attotime::from_usec(1), attotime::from_usec(10)); +} + + +//------------------------------------------------- +// tms_register_r - return the value written to +// the register select port +//------------------------------------------------- + +READ16_MEMBER( bsmt2000_device::tms_register_r ) +{ + return m_register_select; +} + + +//------------------------------------------------- +// tms_data_r - return the value written to the +// data port +//------------------------------------------------- + +READ16_MEMBER( bsmt2000_device::tms_data_r ) +{ + // also implicitly clear the write pending flag + m_write_pending = false; + if (m_ready_callback != NULL) + (*m_ready_callback)(*this); + return m_write_data; +} + + +//------------------------------------------------- +// tms_rom_r - read a byte from the currently +// selected ROM bank and address +//------------------------------------------------- + +READ16_MEMBER( bsmt2000_device::tms_rom_r ) +{ + // underlying logic assumes this is a sign-extended value + return (INT8)m_direct->read_byte((m_rom_bank << 16) + m_rom_address); +} + + +//------------------------------------------------- +// tms_rom_addr_w - selects which byte within the +// current ROM bank to access +//------------------------------------------------- + +WRITE16_MEMBER( bsmt2000_device::tms_rom_addr_w ) +{ + m_rom_address = data; +} + + +//------------------------------------------------- +// tms_rom_bank_w - selects which bank of ROM to +// access +//------------------------------------------------- + +WRITE16_MEMBER( bsmt2000_device::tms_rom_bank_w ) +{ + m_rom_bank = data; +} + + +//------------------------------------------------- +// tms_left_w - handle writes to the left channel +// DAC +//------------------------------------------------- + +WRITE16_MEMBER( bsmt2000_device::tms_left_w ) +{ + m_stream->update(); + m_left_data = data; +} + + +//------------------------------------------------- +// tms_right_w - handle writes to the right +// channel DAC +//------------------------------------------------- + +WRITE16_MEMBER( bsmt2000_device::tms_right_w ) +{ + m_stream->update(); + m_right_data = data; +} + + +//------------------------------------------------- +// tms_write_pending_r - return whether a write +// is pending; this data is fed into the BIO line +// on the TMS32015 +//------------------------------------------------- + +READ16_MEMBER( bsmt2000_device::tms_write_pending_r ) +{ + return m_write_pending ? 1 : 0; +} diff --git a/src/devices/sound/bsmt2000.h b/src/devices/sound/bsmt2000.h new file mode 100644 index 00000000000..fb993e982e0 --- /dev/null +++ b/src/devices/sound/bsmt2000.h @@ -0,0 +1,112 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + bsmt2000.h + + BSMT2000 device emulator. + +***************************************************************************/ + +#pragma once + +#ifndef __BSMT2000_H__ +#define __BSMT2000_H__ + +#include "cpu/tms32010/tms32010.h" + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_BSMT2000_ADD(_tag, _clock) \ + MCFG_DEVICE_ADD(_tag, BSMT2000, _clock) +#define MCFG_BSMT2000_REPLACE(_tag, _clock) \ + MCFG_DEVICE_REPLACE(_tag, BSMT2000, _clock) +#define MCFG_BSMT2000_READY_CALLBACK(_callback) \ + bsmt2000_device::static_set_ready_callback(*device, _callback); + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + + +// ======================> bsmt2000_device + +class bsmt2000_device : public device_t, + public device_sound_interface, + public device_memory_interface +{ + typedef void (*ready_callback)(bsmt2000_device &device); + +public: + // construction/destruction + bsmt2000_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // inline configuration helpers + static void static_set_ready_callback(device_t &device, ready_callback callback); + + // public interface + UINT16 read_status(); + void write_reg(UINT16 data); + void write_data(UINT16 data); + +protected: + // device-level overrides + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const; + + // device_sound_interface overrides + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + +public: + // internal TMS I/O callbacks + DECLARE_READ16_MEMBER( tms_register_r ); + DECLARE_READ16_MEMBER( tms_data_r ); + DECLARE_READ16_MEMBER( tms_rom_r ); + DECLARE_WRITE16_MEMBER( tms_rom_addr_w ); + DECLARE_WRITE16_MEMBER( tms_rom_bank_w ); + DECLARE_WRITE16_MEMBER( tms_left_w ); + DECLARE_WRITE16_MEMBER( tms_right_w ); + DECLARE_READ16_MEMBER( tms_write_pending_r ); + +private: + // timers + enum + { + TIMER_ID_RESET, + TIMER_ID_REG_WRITE, + TIMER_ID_DATA_WRITE + }; + + // configuration state + const address_space_config m_space_config; + ready_callback m_ready_callback; + + // internal state + sound_stream * m_stream; + direct_read_data * m_direct; + tms32015_device * m_cpu; + UINT16 m_register_select; + UINT16 m_write_data; + UINT16 m_rom_address; + UINT16 m_rom_bank; + INT16 m_left_data; + INT16 m_right_data; + bool m_write_pending; +}; + + +// device type definition +extern const device_type BSMT2000; + + +#endif /* __BSMT2000_H__ */ diff --git a/src/devices/sound/c140.c b/src/devices/sound/c140.c new file mode 100644 index 00000000000..6649f53616a --- /dev/null +++ b/src/devices/sound/c140.c @@ -0,0 +1,489 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/* +C140.c + +Simulator based on AMUSE sources. +The C140 sound chip is used by Namco System 2 and System 21 +The 219 ASIC (which incorporates a modified C140) is used by Namco NA-1 and NA-2 +This chip controls 24 channels (C140) or 16 (219) of PCM. +16 bytes are associated with each channel. +Channels can be 8 bit signed PCM, or 12 bit signed PCM. + +Timer behavior is not yet handled. + +Unmapped registers: + 0x1f8:timer interval? (Nx0.1 ms) + 0x1fa:irq ack? timer restart? + 0x1fe:timer switch?(0:off 1:on) + +-------------- + + ASIC "219" notes + + On the 219 ASIC used on NA-1 and NA-2, the high registers have the following + meaning instead: + 0x1f7: bank for voices 0-3 + 0x1f1: bank for voices 4-7 + 0x1f3: bank for voices 8-11 + 0x1f5: bank for voices 12-15 + + Some games (bkrtmaq, xday2) write to 0x1fd for voices 12-15 instead. Probably the bank registers + mirror at 1f8, in which case 1ff is also 0-3, 1f9 is also 4-7, 1fb is also 8-11, and 1fd is also 12-15. + + Each bank is 0x20000 (128k), and the voice addresses on the 219 are all multiplied by 2. + Additionally, the 219's base pitch is the same as the C352's (42667). But these changes + are IMO not sufficient to make this a separate file - all the other registers are + fully compatible. + + Finally, the 219 only has 16 voices. +*/ +/* + 2000.06.26 CAB fixed compressed pcm playback + 2002.07.20 R. Belmont added support for multiple banking types + 2006.01.08 R. Belmont added support for NA-1/2 "219" derivative +*/ + + +#include "emu.h" +#include "c140.h" + +struct voice_registers +{ + UINT8 volume_right; + UINT8 volume_left; + UINT8 frequency_msb; + UINT8 frequency_lsb; + UINT8 bank; + UINT8 mode; + UINT8 start_msb; + UINT8 start_lsb; + UINT8 end_msb; + UINT8 end_lsb; + UINT8 loop_msb; + UINT8 loop_lsb; + UINT8 reserved[4]; +}; + + +// device type definition +const device_type C140 = &device_creator; + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +INLINE int limit(INT32 in) +{ + if(in>0x7fff) return 0x7fff; + else if(in<-0x8000) return -0x8000; + return in; +} + + +//------------------------------------------------- +// c140_device - constructor +//------------------------------------------------- + +c140_device::c140_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, C140, "C140", tag, owner, clock, "c140", __FILE__), + device_sound_interface(mconfig, *this), + m_sample_rate(0), + m_stream(NULL), + m_banking_type(0), + m_mixer_buffer_left(NULL), + m_mixer_buffer_right(NULL), + m_baserate(0), + m_pRom(NULL) +{ + memset(m_REG, 0, sizeof(UINT8)*0x200); + memset(m_pcmtbl, 0, sizeof(INT16)*8); +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void c140_device::device_start() +{ + m_sample_rate=m_baserate=clock(); + + m_stream = stream_alloc(0, 2, m_sample_rate); + + m_pRom = (INT8 *)region()->base(); + + /* make decompress pcm table */ //2000.06.26 CAB + { + int i; + INT32 segbase=0; + for(i=0;i<8;i++) + { + m_pcmtbl[i]=segbase; //segment base value + segbase += 16<m_sample_rate) samples=m_sample_rate; + + /* zap the contents of the mixer buffer */ + memset(m_mixer_buffer_left, 0, samples * sizeof(INT16)); + memset(m_mixer_buffer_right, 0, samples * sizeof(INT16)); + + /* get the number of voices to update */ + voicecnt = (m_banking_type == C140_TYPE_ASIC219) ? 16 : 24; + + //--- audio update + for( i=0;ikey ) + { + frequency= vreg->frequency_msb*256 + vreg->frequency_lsb; + + /* Abort voice if no frequency value set */ + if(frequency==0) continue; + + /* Delta = frequency * ((8MHz/374)*2 / sample rate) */ + delta=(long)((float)frequency * pbase); + + /* Calculate left/right channel volumes */ + lvol=(vreg->volume_left*32)/C140_MAX_VOICE; //32ch -> 24ch + rvol=(vreg->volume_right*32)/C140_MAX_VOICE; + + /* Set mixer outputs base pointers */ + lmix = m_mixer_buffer_left; + rmix = m_mixer_buffer_right; + + /* Retrieve sample start/end and calculate size */ + st=v->sample_start; + ed=v->sample_end; + sz=ed-st; + + /* Retrieve base pointer to the sample data */ + pSampleData = m_pRom + find_sample(st, v->bank, i); + + /* Fetch back previous data pointers */ + offset=v->ptoffset; + pos=v->pos; + lastdt=v->lastdt; + prevdt=v->prevdt; + dltdt=v->dltdt; + + /* Switch on data type - compressed PCM is only for C140 */ + if ((v->mode&8) && (m_banking_type != C140_TYPE_ASIC219)) + { + //compressed PCM (maybe correct...) + /* Loop for enough to fill sample buffer as requested */ + for(j=0;j>16)&0x7fff; + offset &= 0xffff; + pos+=cnt; + //for(;cnt>0;cnt--) + { + /* Check for the end of the sample */ + if(pos >= sz) + { + /* Check if its a looping sample, either stop or loop */ + if(v->mode&0x10) + { + pos = (v->sample_loop - st); + } + else + { + v->key=0; + break; + } + } + + /* Read the chosen sample byte */ + dt=pSampleData[pos]; + + /* decompress to 13bit range */ //2000.06.26 CAB + sdt=dt>>3; //signed + if(sdt<0) sdt = (sdt<<(dt&7)) - m_pcmtbl[dt&7]; + else sdt = (sdt<<(dt&7)) + m_pcmtbl[dt&7]; + + prevdt=lastdt; + lastdt=sdt; + dltdt=(lastdt - prevdt); + } + + /* Caclulate the sample value */ + dt=((dltdt*offset)>>16)+prevdt; + + /* Write the data to the sample buffers */ + *lmix++ +=(dt*lvol)>>(5+5); + *rmix++ +=(dt*rvol)>>(5+5); + } + } + else + { + /* linear 8bit signed PCM */ + for(j=0;j>16)&0x7fff; + offset &= 0xffff; + pos += cnt; + /* Check for the end of the sample */ + if(pos >= sz) + { + /* Check if its a looping sample, either stop or loop */ + if( v->mode&0x10 ) + { + pos = (v->sample_loop - st); + } + else + { + v->key=0; + break; + } + } + + if( cnt ) + { + prevdt=lastdt; + + if (m_banking_type == C140_TYPE_ASIC219) + { + lastdt = pSampleData[BYTE_XOR_BE(pos)]; + + // Sign + magnitude format + if ((v->mode & 0x01) && (lastdt & 0x80)) + lastdt = -(lastdt & 0x7f); + + // Sign flip + if (v->mode & 0x40) + lastdt = -lastdt; + } + else + { + lastdt=pSampleData[pos]; + } + + dltdt = (lastdt - prevdt); + } + + /* Caclulate the sample value */ + dt=((dltdt*offset)>>16)+prevdt; + + /* Write the data to the sample buffers */ + *lmix++ +=(dt*lvol)>>5; + *rmix++ +=(dt*rvol)>>5; + } + } + + /* Save positional data for next callback */ + v->ptoffset=offset; + v->pos=pos; + v->lastdt=lastdt; + v->prevdt=prevdt; + v->dltdt=dltdt; + } + } + + /* render to MAME's stream buffer */ + lmix = m_mixer_buffer_left; + rmix = m_mixer_buffer_right; + { + stream_sample_t *dest1 = outputs[0]; + stream_sample_t *dest2 = outputs[1]; + for (i = 0; i < samples; i++) + { + INT32 val; + + val = 8 * (*lmix++); + *dest1++ = limit(val); + val = 8 * (*rmix++); + *dest2++ = limit(val); + } + } +} + + +READ8_MEMBER( c140_device::c140_r ) +{ + offset&=0x1ff; + return m_REG[offset]; +} + + +WRITE8_MEMBER( c140_device::c140_w ) +{ + m_stream->update(); + + offset&=0x1ff; + + // mirror the bank registers on the 219, fixes bkrtmaq (and probably xday2 based on notes in the HLE) + if ((offset >= 0x1f8) && (m_banking_type == C140_TYPE_ASIC219)) + { + offset -= 8; + } + + m_REG[offset]=data; + if( offset<0x180 ) + { + C140_VOICE *v = &m_voi[offset>>4]; + + if( (offset&0xf)==0x5 ) + { + if( data&0x80 ) + { + const struct voice_registers *vreg = (struct voice_registers *) &m_REG[offset&0x1f0]; + v->key=1; + v->ptoffset=0; + v->pos=0; + v->lastdt=0; + v->prevdt=0; + v->dltdt=0; + v->bank = vreg->bank; + v->mode = data; + + // on the 219 asic, addresses are in words + if (m_banking_type == C140_TYPE_ASIC219) + { + v->sample_loop = (vreg->loop_msb*256 + vreg->loop_lsb)*2; + v->sample_start = (vreg->start_msb*256 + vreg->start_lsb)*2; + v->sample_end = (vreg->end_msb*256 + vreg->end_lsb)*2; + + #if 0 + logerror("219: play v %d mode %02x start %x loop %x end %x\n", + offset>>4, v->mode, + find_sample(v->sample_start, v->bank, offset>>4), + find_sample(v->sample_loop, v->bank, offset>>4), + find_sample(v->sample_end, v->bank, offset>>4)); + #endif + } + else + { + v->sample_loop = vreg->loop_msb*256 + vreg->loop_lsb; + v->sample_start = vreg->start_msb*256 + vreg->start_lsb; + v->sample_end = vreg->end_msb*256 + vreg->end_lsb; + } + } + else + { + v->key=0; + } + } + } +} + + +void c140_device::set_base(void *base) +{ + m_pRom = (INT8 *)base; +} + + +void c140_device::init_voice( C140_VOICE *v ) +{ + v->key=0; + v->ptoffset=0; + v->rvol=0; + v->lvol=0; + v->frequency=0; + v->bank=0; + v->mode=0; + v->sample_start=0; + v->sample_end=0; + v->sample_loop=0; +} + + +/* + find_sample: compute the actual address of a sample given it's + address and banking registers, as well as the board type. + + I suspect in "real life" this works like the Sega MultiPCM where the banking + is done by a small PAL or GAL external to the sound chip, which can be switched + per-game or at least per-PCB revision as addressing range needs grow. + */ +long c140_device::find_sample(long adrs, long bank, int voice) +{ + long newadr = 0; + + static const INT16 asic219banks[4] = { 0x1f7, 0x1f1, 0x1f3, 0x1f5 }; + + adrs=(bank<<16)+adrs; + + switch (m_banking_type) + { + case C140_TYPE_SYSTEM2: + // System 2 banking + newadr = ((adrs&0x200000)>>2)|(adrs&0x7ffff); + break; + + case C140_TYPE_SYSTEM21: + // System 21 banking. + // similar to System 2's. + newadr = ((adrs&0x300000)>>1)+(adrs&0x7ffff); + break; + + case C140_TYPE_ASIC219: + // ASIC219's banking is fairly simple + newadr = ((m_REG[asic219banks[voice/4]]&0x3) * 0x20000) + adrs; + break; + } + + return (newadr); +} diff --git a/src/devices/sound/c140.h b/src/devices/sound/c140.h new file mode 100644 index 00000000000..13b6bfbcc7c --- /dev/null +++ b/src/devices/sound/c140.h @@ -0,0 +1,124 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/* C140.h */ + +#pragma once + +#ifndef __C140_H__ +#define __C140_H__ + +#define C140_MAX_VOICE 24 + +enum +{ + C140_TYPE_SYSTEM2, + C140_TYPE_SYSTEM21, + C140_TYPE_ASIC219 +}; + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_C140_ADD(_tag, _clock) \ + MCFG_DEVICE_ADD(_tag, C140, _clock) +#define MCFG_C140_REPLACE(_tag, _clock) \ + MCFG_DEVICE_REPLACE(_tag, C140, _clock) + +#define MCFG_C140_BANK_TYPE(_type) \ + c140_device::set_bank_type(*device, _type); + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +struct C140_VOICE +{ + C140_VOICE() : + ptoffset(0), + pos(0), + key(0), + lastdt(0), + prevdt(0), + dltdt(0), + rvol(0), + lvol(0), + frequency(0), + bank(0), + mode(0), + sample_start(0), + sample_end(0), + sample_loop(0) {} + + INT32 ptoffset; + INT32 pos; + INT32 key; + //--work + INT32 lastdt; + INT32 prevdt; + INT32 dltdt; + //--reg + INT32 rvol; + INT32 lvol; + INT32 frequency; + INT32 bank; + INT32 mode; + + INT32 sample_start; + INT32 sample_end; + INT32 sample_loop; +}; + + +// ======================> c140_device + +class c140_device : public device_t, + public device_sound_interface +{ +public: + c140_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + ~c140_device() { } + + // static configuration + static void set_bank_type(device_t &device, int bank) { downcast(device).m_banking_type = bank; } + +protected: + // device-level overrides + virtual void device_start(); + + // sound stream update overrides + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + +public: + DECLARE_READ8_MEMBER( c140_r ); + DECLARE_WRITE8_MEMBER( c140_w ); + +public: + void set_base(void *base); + +private: + void init_voice( C140_VOICE *v ); + long find_sample(long adrs, long bank, int voice); + +private: + int m_sample_rate; + sound_stream *m_stream; + int m_banking_type; + /* internal buffers */ + INT16 *m_mixer_buffer_left; + INT16 *m_mixer_buffer_right; + + int m_baserate; + INT8 *m_pRom; + UINT8 m_REG[0x200]; + + INT16 m_pcmtbl[8]; //2000.06.26 CAB + + C140_VOICE m_voi[C140_MAX_VOICE]; +}; + +extern const device_type C140; + + +#endif /* __C140_H__ */ diff --git a/src/devices/sound/c352.c b/src/devices/sound/c352.c new file mode 100644 index 00000000000..98f8f3a9fed --- /dev/null +++ b/src/devices/sound/c352.c @@ -0,0 +1,551 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/* + c352.c - Namco C352 custom PCM chip emulation + v1.2 + By R. Belmont + Additional code by cync and the hoot development team + + Thanks to Cap of VivaNonno for info and The_Author for preliminary reverse-engineering + + Chip specs: + 32 voices + Supports 8-bit linear and 8-bit muLaw samples + Output: digital, 16 bit, 4 channels + Output sample rate is the input clock / (288 * 2). + + superctr: The clock divider appears to be configurable for each system. + Below is a list of the divider values followed by the systems that use it. + + * 228: System 11. + * 288: System 22, Super 22, NB-1/2, ND-1, FL. + * 296: System 23, Super 23. + * 332: System 12. + */ + +#include "emu.h" +#include "c352.h" + +#define VERBOSE (0) +#define LOG(x) do { if (VERBOSE) logerror x; } while (0) + +// device type definition +const device_type C352 = &device_creator; + +// default address map +static ADDRESS_MAP_START( c352, AS_0, 8, c352_device ) + AM_RANGE(0x000000, 0xffffff) AM_ROM +ADDRESS_MAP_END + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// c352_device - constructor +//------------------------------------------------- + +c352_device::c352_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, C352, "C352", tag, owner, clock, "c352", __FILE__), + device_sound_interface(mconfig, *this), + device_memory_interface(mconfig, *this), + m_space_config("samples", ENDIANNESS_LITTLE, 8, 24, 0, NULL, *ADDRESS_MAP_NAME(c352)) +{ +} + +//------------------------------------------------- +// static_set_dividder - configuration helper to +// set the divider setting +//------------------------------------------------- + +void c352_device::static_set_divider(device_t &device, int setting) +{ + c352_device &c352 = downcast(device); + c352.m_divider = setting; +} + +//------------------------------------------------- +// memory_space_config - return a description of +// any address spaces owned by this device +//------------------------------------------------- + +const address_space_config *c352_device::memory_space_config(address_spacenum spacenum) const +{ + return (spacenum == 0) ? &m_space_config : NULL; +} + +// noise generator +int c352_device::get_mseq_bit() +{ + unsigned int mask = (1 << (7 - 1)); + unsigned int reg = m_mseq_reg; + unsigned int bit = reg & (1 << (17 - 1)); + + if (bit) + { + reg = ((reg ^ mask) << 1) | 1; + } + else + { + reg = reg << 1; + } + + m_mseq_reg = reg; + + return (reg & 1); +} + +void c352_device::mix_one_channel(unsigned long ch, long sample_count) +{ + int i; + + signed short sample, nextsample; + signed short noisebuf; + UINT16 noisecnt; + INT32 frequency, delta, offset, cnt, flag; + UINT32 bank; + UINT32 pos; + + frequency = m_c352_ch[ch].pitch; + delta=frequency; + + pos = m_c352_ch[ch].current_addr; // sample pointer + offset = m_c352_ch[ch].pos; // 16.16 fixed-point offset into the sample + flag = m_c352_ch[ch].flag; + bank = m_c352_ch[ch].bank << 16; + + noisecnt = m_c352_ch[ch].noisecnt; + noisebuf = m_c352_ch[ch].noisebuf; + + for(i = 0 ; (i < sample_count) && (flag & C352_FLG_BUSY) ; i++) + { + offset += delta; + cnt = (offset>>16)&0x7fff; + if (cnt) // if there is a whole sample part, chop it off now that it's been applied + { + offset &= 0xffff; + } + + if (pos > 0x1000000) + { + m_c352_ch[ch].flag &= ~C352_FLG_BUSY; + return; + } + + sample = (char)m_direct->read_byte(pos); + nextsample = (char)m_direct->read_byte(pos+cnt); + + // sample is muLaw, not 8-bit linear (Fighting Layer uses this extensively) + if (flag & C352_FLG_MULAW) + { + sample = m_mulaw_table[(unsigned char)sample]; + nextsample = m_mulaw_table[(unsigned char)nextsample]; + } + else + { + sample <<= 8; + nextsample <<= 8; + } + + // play noise instead of sample data + if (flag & C352_FLG_NOISE) + { + int noise_level = 0x8000; + sample = m_c352_ch[ch].noise = (m_c352_ch[ch].noise << 1) | get_mseq_bit(); + sample = (sample & (noise_level - 1)) - (noise_level >> 1); + if (sample > 0x7f) + { + sample = 0x7f; + } + else if (sample < 0) + { + sample = 0xff; + } + sample = m_mulaw_table[(unsigned char)sample]; + + if ( (pos+cnt) == pos ) + { + noisebuf += sample; + noisecnt++; + sample = noisebuf / noisecnt; + } + else + { + if ( noisecnt ) + { + sample = noisebuf / noisecnt; + } + else + { + sample = m_mulaw_table[0x7f]; // Nearest sound(s) is here. + } + noisebuf = 0; + noisecnt = ( flag & C352_FLG_FILTER ) ? 0 : 1; + } + } + + // apply linear interpolation + if ( (flag & (C352_FLG_FILTER | C352_FLG_NOISE)) == 0 ) + { + sample = (short)(sample + ((nextsample-sample) * (((double)(0x0000ffff&offset) )/0x10000))); + } + + if ( flag & C352_FLG_PHASEFL ) + { + m_channel_l[i] += ((-sample * m_c352_ch[ch].vol_l)>>8); + } + else + { + m_channel_l[i] += ((sample * m_c352_ch[ch].vol_l)>>8); + } + + if ( flag & C352_FLG_PHASEFR ) + { + m_channel_r[i] += ((-sample * m_c352_ch[ch].vol_r)>>8); + } + else + { + m_channel_r[i] += ((sample * m_c352_ch[ch].vol_r)>>8); + } + + if ( flag & C352_FLG_PHASERL ) + { + m_channel_l2[i] += ((-sample * m_c352_ch[ch].vol_l2)>>8); + } + else + { + m_channel_l2[i] += ((sample * m_c352_ch[ch].vol_l2)>>8); + } + m_channel_r2[i] += ((sample * m_c352_ch[ch].vol_r2)>>8); + + if ( (flag & C352_FLG_REVERSE) && (flag & C352_FLG_LOOP) ) + { + if ( !(flag & C352_FLG_LDIR) ) + { + pos += cnt; + if ( + (((pos&0xFFFF) > m_c352_ch[ch].end_addr) && ((pos&0xFFFF) < m_c352_ch[ch].start) && (m_c352_ch[ch].start > m_c352_ch[ch].end_addr) ) || + (((pos&0xFFFF) > m_c352_ch[ch].end_addr) && ((pos&0xFFFF) > m_c352_ch[ch].start) && (m_c352_ch[ch].start < m_c352_ch[ch].end_addr) ) || + ((pos > (bank|0xFFFF)) && (m_c352_ch[ch].end_addr == 0xFFFF)) + ) + { + m_c352_ch[ch].flag |= C352_FLG_LDIR; + m_c352_ch[ch].flag |= C352_FLG_LOOPHIST; + } + } + else + { + pos -= cnt; + if ( + (((pos&0xFFFF) < m_c352_ch[ch].repeat) && ((pos&0xFFFF) < m_c352_ch[ch].end_addr) && (m_c352_ch[ch].end_addr > m_c352_ch[ch].start) ) || + (((pos&0xFFFF) < m_c352_ch[ch].repeat) && ((pos&0xFFFF) > m_c352_ch[ch].end_addr) && (m_c352_ch[ch].end_addr < m_c352_ch[ch].start) ) || + ((pos < bank) && (m_c352_ch[ch].repeat == 0x0000)) + ) + { + m_c352_ch[ch].flag &= ~C352_FLG_LDIR; + m_c352_ch[ch].flag |= C352_FLG_LOOPHIST; + } + } + } + else if ( flag & C352_FLG_REVERSE ) + { + pos -= cnt; + if ( + (((pos&0xFFFF) < m_c352_ch[ch].end_addr) && ((pos&0xFFFF) < m_c352_ch[ch].start) && (m_c352_ch[ch].start > m_c352_ch[ch].end_addr) ) || + (((pos&0xFFFF) < m_c352_ch[ch].end_addr) && ((pos&0xFFFF) > m_c352_ch[ch].start) && (m_c352_ch[ch].start < m_c352_ch[ch].end_addr) ) || + ((pos < bank) && (m_c352_ch[ch].end_addr == 0x0000)) + ) + { + if ( (flag & C352_FLG_LINK) && (flag & C352_FLG_LOOP) ) + { + m_c352_ch[ch].bank = m_c352_ch[ch].start_addr & 0xFF; + m_c352_ch[ch].start_addr = m_c352_ch[ch].repeat_addr; + m_c352_ch[ch].start = m_c352_ch[ch].start_addr; + m_c352_ch[ch].repeat = m_c352_ch[ch].repeat_addr; + pos = (m_c352_ch[ch].bank<<16) + m_c352_ch[ch].start_addr; + m_c352_ch[ch].flag |= C352_FLG_LOOPHIST; + } + else if (flag & C352_FLG_LOOP) + { + pos = (pos & 0xFF0000) + m_c352_ch[ch].repeat; + m_c352_ch[ch].flag |= C352_FLG_LOOPHIST; + } + else + { + m_c352_ch[ch].flag |= C352_FLG_KEYOFF; + m_c352_ch[ch].flag &= ~C352_FLG_BUSY; + return; + } + } + } else { + pos += cnt; + if ( + (((pos&0xFFFF) > m_c352_ch[ch].end_addr) && ((pos&0xFFFF) < m_c352_ch[ch].start) && (m_c352_ch[ch].start > m_c352_ch[ch].end_addr) ) || + (((pos&0xFFFF) > m_c352_ch[ch].end_addr) && ((pos&0xFFFF) > m_c352_ch[ch].start) && (m_c352_ch[ch].start < m_c352_ch[ch].end_addr) ) || + ((pos > (bank|0xFFFF)) && (m_c352_ch[ch].end_addr == 0xFFFF)) + ) + { + if ( (flag & C352_FLG_LINK) && (flag & C352_FLG_LOOP) ) + { + m_c352_ch[ch].bank = m_c352_ch[ch].start_addr & 0xFF; + m_c352_ch[ch].start_addr = m_c352_ch[ch].repeat_addr; + m_c352_ch[ch].start = m_c352_ch[ch].start_addr; + m_c352_ch[ch].repeat = m_c352_ch[ch].repeat_addr; + pos = (m_c352_ch[ch].bank<<16) + m_c352_ch[ch].start_addr; + m_c352_ch[ch].flag |= C352_FLG_LOOPHIST; + } + else if (flag & C352_FLG_LOOP) + { + pos = (pos & 0xFF0000) + m_c352_ch[ch].repeat; + m_c352_ch[ch].flag |= C352_FLG_LOOPHIST; + } + else + { + m_c352_ch[ch].flag |= C352_FLG_KEYOFF; + m_c352_ch[ch].flag &= ~C352_FLG_BUSY; + return; + } + } + } + } + + m_c352_ch[ch].noisecnt = noisecnt; + m_c352_ch[ch].noisebuf = noisebuf; + m_c352_ch[ch].pos = offset; + m_c352_ch[ch].current_addr = pos; +} + + +void c352_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + int i, j; + stream_sample_t *bufferl = outputs[0]; + stream_sample_t *bufferr = outputs[1]; + stream_sample_t *bufferl2 = outputs[2]; + stream_sample_t *bufferr2 = outputs[3]; + + for(i = 0 ; i < samples ; i++) + { + m_channel_l[i] = m_channel_r[i] = m_channel_l2[i] = m_channel_r2[i] = 0; + } + + for (j = 0 ; j < 32 ; j++) + { + mix_one_channel(j, samples); + } + + for(i = 0 ; i < samples ; i++) + { + *bufferl++ = (short) (m_channel_l[i] >>3); + *bufferr++ = (short) (m_channel_r[i] >>3); + *bufferl2++ = (short) (m_channel_l2[i] >>3); + *bufferr2++ = (short) (m_channel_r2[i] >>3); + } +} + +unsigned short c352_device::read_reg16(unsigned long address) +{ + unsigned long chan; + unsigned short val; + + m_stream->update(); + + chan = (address >> 4) & 0xfff; + if (chan > 31) + { + val = 0; + } + else + { + if ((address & 0xf) == 6) + { + val = m_c352_ch[chan].flag; + } + else + { + val = 0; + } + } + return val; +} + +void c352_device::write_reg16(unsigned long address, unsigned short val) +{ + unsigned long chan; + int i; + + m_stream->update(); + + chan = (address >> 4) & 0xfff; + + if ( address >= 0x400 ) + { + switch(address) + { + case 0x404: // execute key-ons/offs + for ( i = 0 ; i <= 31 ; i++ ) + { + if ( m_c352_ch[i].flag & C352_FLG_KEYON ) + { + if (m_c352_ch[i].start_addr != m_c352_ch[i].end_addr) + { + m_c352_ch[i].current_addr = (m_c352_ch[i].bank << 16) + m_c352_ch[i].start_addr; + m_c352_ch[i].start = m_c352_ch[i].start_addr; + m_c352_ch[i].repeat = m_c352_ch[i].repeat_addr; + m_c352_ch[i].noisebuf = 0; + m_c352_ch[i].noisecnt = 0; + m_c352_ch[i].flag &= ~(C352_FLG_KEYON | C352_FLG_LOOPHIST); + m_c352_ch[i].flag |= C352_FLG_BUSY; + } + } + else if ( m_c352_ch[i].flag & C352_FLG_KEYOFF ) + { + m_c352_ch[i].flag &= ~C352_FLG_BUSY; + m_c352_ch[i].flag &= ~(C352_FLG_KEYOFF); + } + } + break; + default: + break; + } + return; + } + + if (chan > 31) + { + LOG(("C352 CTRL %08lx %04x\n", address, val)); + return; + } + switch(address & 0xf) + { + case 0x0: + // volumes (output 1) + LOG(("CH %02ld LVOL %02x RVOL %02x\n", chan, val & 0xff, val >> 8)); + m_c352_ch[chan].vol_l = val & 0xff; + m_c352_ch[chan].vol_r = val >> 8; + break; + + case 0x2: + // volumes (output 2) + LOG(("CH %02ld RLVOL %02x RRVOL %02x\n", chan, val & 0xff, val >> 8)); + m_c352_ch[chan].vol_l2 = val & 0xff; + m_c352_ch[chan].vol_r2 = val >> 8; + break; + + case 0x4: + // pitch + LOG(("CH %02ld PITCH %04x\n", chan, val)); + m_c352_ch[chan].pitch = val; + break; + + case 0x6: + // flags + LOG(("CH %02ld FLAG %02x\n", chan, val)); + m_c352_ch[chan].flag = val; + break; + + case 0x8: + // bank (bits 16-31 of address); + m_c352_ch[chan].bank = val & 0xff; + LOG(("CH %02ld BANK %02x", chan, m_c352_ch[chan].bank)); + break; + + case 0xa: + // start address + LOG(("CH %02ld SADDR %04x\n", chan, val)); + m_c352_ch[chan].start_addr = val; + break; + + case 0xc: + // end address + LOG(("CH %02ld EADDR %04x\n", chan, val)); + m_c352_ch[chan].end_addr = val; + break; + + case 0xe: + // loop address + LOG(("CH %02ld LADDR %04x\n", chan, val)); + m_c352_ch[chan].repeat_addr = val; + break; + + default: + LOG(("CH %02ld UNKN %01lx %04x", chan, address & 0xf, val)); + break; + } +} + +void c352_device::device_start() +{ + int i; + double x_max = 32752.0; + double y_max = 127.0; + double u = 10.0; + + // find our direct access + m_direct = &space().direct(); + + m_sample_rate_base = clock() / m_divider; + + m_stream = machine().sound().stream_alloc(*this, 0, 4, m_sample_rate_base); + + // generate mulaw table for mulaw format samples + for (i = 0; i < 256; i++) + { + double y = (double) (i & 0x7f); + double x = (exp (y / y_max * log (1.0 + u)) - 1.0) * x_max / u; + + if (i & 0x80) + { + x = -x; + } + m_mulaw_table[i] = (short)x; + } + + // register save state info + for (i = 0; i < 32; i++) + { + save_item(NAME(m_c352_ch[i].vol_l), i); + save_item(NAME(m_c352_ch[i].vol_r), i); + save_item(NAME(m_c352_ch[i].vol_l2), i); + save_item(NAME(m_c352_ch[i].vol_r2), i); + save_item(NAME(m_c352_ch[i].bank), i); + save_item(NAME(m_c352_ch[i].noise), i); + save_item(NAME(m_c352_ch[i].noisebuf), i); + save_item(NAME(m_c352_ch[i].noisecnt), i); + save_item(NAME(m_c352_ch[i].pitch), i); + save_item(NAME(m_c352_ch[i].start_addr), i); + save_item(NAME(m_c352_ch[i].end_addr), i); + save_item(NAME(m_c352_ch[i].repeat_addr), i); + save_item(NAME(m_c352_ch[i].flag), i); + save_item(NAME(m_c352_ch[i].start), i); + save_item(NAME(m_c352_ch[i].repeat), i); + save_item(NAME(m_c352_ch[i].current_addr), i); + save_item(NAME(m_c352_ch[i].pos), i); + } +} + +void c352_device::device_reset() +{ + // clear all channels states + memset(m_c352_ch, 0, sizeof(c352_ch_t)*32); + + // init noise generator + m_mseq_reg = 0x12345678; +} + +READ16_MEMBER( c352_device::read ) +{ + return(read_reg16(offset*2)); +} + +WRITE16_MEMBER( c352_device::write ) +{ + if (mem_mask == 0xffff) + { + write_reg16(offset*2, data); + } + else + { + logerror("C352: byte-wide write unsupported at this time!\n"); + } +} diff --git a/src/devices/sound/c352.h b/src/devices/sound/c352.h new file mode 100644 index 00000000000..24a2a1cbe74 --- /dev/null +++ b/src/devices/sound/c352.h @@ -0,0 +1,121 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +#pragma once + +#ifndef __C352_H__ +#define __C352_H__ + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_C352_ADD(_tag, _clock, _setting) \ + MCFG_DEVICE_ADD(_tag, C352, _clock) \ + MCFG_C352_DIVIDER(_setting) + +#define MCFG_C352_DIVIDER(_setting) \ + c352_device::static_set_divider(*device, _setting); + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> asc_device + +class c352_device : public device_t, + public device_sound_interface, + public device_memory_interface +{ +public: + // construction/destruction + c352_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // inline configuration helpers + static void static_set_divider(device_t &device, int setting); + + DECLARE_READ16_MEMBER(read); + DECLARE_WRITE16_MEMBER(write); + + sound_stream *m_stream; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_sound_interface overrides + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const; + + const address_space_config m_space_config; + +private: + enum { + C352_FLG_BUSY = 0x8000, // channel is busy + C352_FLG_KEYON = 0x4000, // Keyon + C352_FLG_KEYOFF = 0x2000, // Keyoff + C352_FLG_LOOPTRG = 0x1000, // Loop Trigger + C352_FLG_LOOPHIST = 0x0800, // Loop History + C352_FLG_FM = 0x0400, // Frequency Modulation + C352_FLG_PHASERL = 0x0200, // Rear Left invert phase 180 degrees + C352_FLG_PHASEFL = 0x0100, // Front Left invert phase 180 degrees + C352_FLG_PHASEFR = 0x0080, // invert phase 180 degrees (e.g. flip sign of sample) + C352_FLG_LDIR = 0x0040, // loop direction + C352_FLG_LINK = 0x0020, // "long-format" sample (can't loop, not sure what else it means) + C352_FLG_NOISE = 0x0010, // play noise instead of sample + C352_FLG_MULAW = 0x0008, // sample is mulaw instead of linear 8-bit PCM + C352_FLG_FILTER = 0x0004, // don't apply filter + C352_FLG_REVLOOP = 0x0003, // loop backwards + C352_FLG_LOOP = 0x0002, // loop forward + C352_FLG_REVERSE = 0x0001 // play sample backwards + }; + + struct c352_ch_t + { + UINT8 vol_l; + UINT8 vol_r; + UINT8 vol_l2; + UINT8 vol_r2; + UINT8 bank; + INT16 noise; + INT16 noisebuf; + UINT16 noisecnt; + UINT16 pitch; + UINT16 start_addr; + UINT16 end_addr; + UINT16 repeat_addr; + UINT32 flag; + + UINT16 start; + UINT16 repeat; + UINT32 current_addr; + UINT32 pos; + }; + + c352_ch_t m_c352_ch[32]; + int m_sample_rate_base; + int m_divider; + + long m_channel_l[2048*2]; + long m_channel_r[2048*2]; + long m_channel_l2[2048*2]; + long m_channel_r2[2048*2]; + + short m_mulaw_table[256]; + unsigned int m_mseq_reg; + direct_read_data *m_direct; + + // private functions + int get_mseq_bit(void); + void mix_one_channel(unsigned long ch, long sample_count); + unsigned short read_reg16(unsigned long address); + void write_reg16(unsigned long address, unsigned short val); +}; + + +// device type definition +extern const device_type C352; + +#endif /* __C352_H__ */ diff --git a/src/devices/sound/c6280.c b/src/devices/sound/c6280.c new file mode 100644 index 00000000000..d484b8281c0 --- /dev/null +++ b/src/devices/sound/c6280.c @@ -0,0 +1,302 @@ +// license:BSD-3-Clause +// copyright-holders:Charles MacDonald +/* + HuC6280 sound chip emulator + by Charles MacDonald + E-mail: cgfm2@hotmail.com + WWW: http://cgfm2.emuviews.com + + Thanks to: + + - Paul Clifford for his PSG documentation. + - Richard Bannister for the TGEmu-specific sound updating code. + - http://www.uspto.gov for the PSG patents. + - All contributors to the tghack-list. + + Changes: + + (03/30/2003) + - Removed TGEmu specific code and added support functions for MAME. + - Modified setup code to handle multiple chips with different clock and + volume settings. + + Missing features / things to do: + + - Add LFO support. But do any games actually use it? + + - Add shared index for waveform playback and sample writes. Almost every + game will reset the index prior to playback so this isn't an issue. + + - While the noise emulation is complete, the data for the pseudo-random + bitstream is calculated by machine.rand() and is not a representation of what + the actual hardware does. + + For some background on Hudson Soft's C62 chipset: + + - http://www.hudsonsoft.net/ww/about/about.html + - http://www.hudson.co.jp/corp/eng/coinfo/history.html + +*/ + +#include "emu.h" +#include "c6280.h" + +/* only needed for io_buffer */ +#include "cpu/h6280/h6280.h" + + +void c6280_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + static const int scale_tab[] = { + 0x00, 0x03, 0x05, 0x07, 0x09, 0x0B, 0x0D, 0x0F, + 0x10, 0x13, 0x15, 0x17, 0x19, 0x1B, 0x1D, 0x1F + }; + + int lmal = (m_balance >> 4) & 0x0F; + int rmal = (m_balance >> 0) & 0x0F; + + lmal = scale_tab[lmal]; + rmal = scale_tab[rmal]; + + /* Clear buffer */ + for (int i = 0; i < samples; i++) + { + outputs[0][i] = 0; + outputs[1][i] = 0; + } + + for (int ch = 0; ch < 6; ch++) + { + /* Only look at enabled channels */ + if(m_channel[ch].m_control & 0x80) + { + int lal = (m_channel[ch].m_balance >> 4) & 0x0F; + int ral = (m_channel[ch].m_balance >> 0) & 0x0F; + int al = m_channel[ch].m_control & 0x1F; + + lal = scale_tab[lal]; + ral = scale_tab[ral]; + + /* Calculate volume just as the patent says */ + int vll = (0x1F - lal) + (0x1F - al) + (0x1F - lmal); + if(vll > 0x1F) vll = 0x1F; + + int vlr = (0x1F - ral) + (0x1F - al) + (0x1F - rmal); + if(vlr > 0x1F) vlr = 0x1F; + + vll = m_volume_table[vll]; + vlr = m_volume_table[vlr]; + + /* Check channel mode */ + if((ch >= 4) && (m_channel[ch].m_noise_control & 0x80)) + { + /* Noise mode */ + UINT32 step = m_noise_freq_tab[(m_channel[ch].m_noise_control & 0x1F) ^ 0x1F]; + for (int i = 0; i < samples; i += 1) + { + static int data = 0; + m_channel[ch].m_noise_counter += step; + if(m_channel[ch].m_noise_counter >= 0x800) + { + data = (machine().rand() & 1) ? 0x1F : 0; + } + m_channel[ch].m_noise_counter &= 0x7FF; + outputs[0][i] += (INT16)(vll * (data - 16)); + outputs[1][i] += (INT16)(vlr * (data - 16)); + } + } + else + if(m_channel[ch].m_control & 0x40) + { + /* DDA mode */ + for (int i = 0; i < samples; i++) + { + outputs[0][i] += (INT16)(vll * (m_channel[ch].m_dda - 16)); + outputs[1][i] += (INT16)(vlr * (m_channel[ch].m_dda - 16)); + } + } + else + { + /* Waveform mode */ + UINT32 step = m_wave_freq_tab[m_channel[ch].m_frequency]; + for (int i = 0; i < samples; i += 1) + { + int offset; + INT16 data; + offset = (m_channel[ch].m_counter >> 12) & 0x1F; + m_channel[ch].m_counter += step; + m_channel[ch].m_counter &= 0x1FFFF; + data = m_channel[ch].m_waveform[offset]; + outputs[0][i] += (INT16)(vll * (data - 16)); + outputs[1][i] += (INT16)(vlr * (data - 16)); + } + } + } + } +} + + +/*--------------------------------------------------------------------------*/ +/* MAME specific code */ +/*--------------------------------------------------------------------------*/ + +READ8_MEMBER( c6280_device::c6280_r ) +{ + return m_cpudevice->io_get_buffer(); +} + +WRITE8_MEMBER( c6280_device::c6280_w ) +{ + m_cpudevice->io_set_buffer(data); + + channel *chan = &m_channel[m_select]; + + /* Update stream */ + m_stream->update(); + + switch(offset & 0x0F) + { + case 0x00: /* Channel select */ + m_select = data & 0x07; + break; + + case 0x01: /* Global balance */ + m_balance = data; + break; + + case 0x02: /* Channel frequency (LSB) */ + chan->m_frequency = (chan->m_frequency & 0x0F00) | data; + chan->m_frequency &= 0x0FFF; + break; + + case 0x03: /* Channel frequency (MSB) */ + chan->m_frequency = (chan->m_frequency & 0x00FF) | (data << 8); + chan->m_frequency &= 0x0FFF; + break; + + case 0x04: /* Channel control (key-on, DDA mode, volume) */ + + /* 1-to-0 transition of DDA bit resets waveform index */ + if((chan->m_control & 0x40) && ((data & 0x40) == 0)) + { + chan->m_index = 0; + } + chan->m_control = data; + break; + + case 0x05: /* Channel balance */ + chan->m_balance = data; + break; + + case 0x06: /* Channel waveform data */ + + switch(chan->m_control & 0xC0) + { + case 0x00: + chan->m_waveform[chan->m_index & 0x1F] = data & 0x1F; + chan->m_index = (chan->m_index + 1) & 0x1F; + break; + + case 0x40: + break; + + case 0x80: + chan->m_waveform[chan->m_index & 0x1F] = data & 0x1F; + chan->m_index = (chan->m_index + 1) & 0x1F; + break; + + case 0xC0: + chan->m_dda = data & 0x1F; + break; + } + + break; + + case 0x07: /* Noise control (enable, frequency) */ + chan->m_noise_control = data; + break; + + case 0x08: /* LFO frequency */ + m_lfo_frequency = data; + break; + + case 0x09: /* LFO control (enable, mode) */ + m_lfo_control = data; + break; + + default: + break; + } +} + +const device_type C6280 = &device_creator; + +c6280_device::c6280_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, C6280, "HuC6280", tag, owner, clock, "c6280", __FILE__), + device_sound_interface(mconfig, *this), + m_cpudevice(*this) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void c6280_device::device_start() +{ + int rate = clock() / 16; + + /* Create stereo stream */ + m_stream = machine().sound().stream_alloc(*this, 0, 2, rate); + + /* Loudest volume level for table */ + double level = 65535.0 / 6.0 / 32.0; + + /* Clear context */ + m_select = 0; + m_balance = 0; + m_lfo_frequency = 0; + m_lfo_control = 0; + memset(m_channel, 0, sizeof(channel) * 8); + + /* Make waveform frequency table */ + for (int i = 0; i < 4096; i += 1) + { + double step = ((clock() / rate) * 4096) / (i + 1); + m_wave_freq_tab[(1 + i) & 0xFFF] = (UINT32)step; + } + + /* Make noise frequency table */ + for (int i = 0; i < 32; i += 1) + { + double step = ((clock() / rate) * 32) / (i+1); + m_noise_freq_tab[i] = (UINT32)step; + } + + /* Make volume table */ + /* PSG has 48dB volume range spread over 32 steps */ + double step = 48.0 / 32.0; + for (int i = 0; i < 31; i++) + { + m_volume_table[i] = (UINT16)level; + level /= pow(10.0, step / 20.0); + } + m_volume_table[31] = 0; + + save_item(NAME(m_select)); + save_item(NAME(m_balance)); + save_item(NAME(m_lfo_frequency)); + save_item(NAME(m_lfo_control)); + for (int chan = 0; chan < 8; chan++) + { + save_item(NAME(m_channel[chan].m_frequency), chan); + save_item(NAME(m_channel[chan].m_control), chan); + save_item(NAME(m_channel[chan].m_balance), chan); + save_item(NAME(m_channel[chan].m_waveform), chan); + save_item(NAME(m_channel[chan].m_index), chan); + save_item(NAME(m_channel[chan].m_dda), chan); + save_item(NAME(m_channel[chan].m_noise_control), chan); + save_item(NAME(m_channel[chan].m_noise_counter), chan); + save_item(NAME(m_channel[chan].m_counter), chan); + } +} diff --git a/src/devices/sound/c6280.h b/src/devices/sound/c6280.h new file mode 100644 index 00000000000..af53962a83e --- /dev/null +++ b/src/devices/sound/c6280.h @@ -0,0 +1,61 @@ +// license:BSD-3-Clause +// copyright-holders:Charles MacDonald +#pragma once + +#ifndef __C6280_H__ +#define __C6280_H__ + +#include "cpu/h6280/h6280.h" + +class c6280_device : public device_t, + public device_sound_interface +{ +public: + c6280_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + static void set_devicecpu_tag(device_t &device, const char *tag) { downcast(device).m_cpudevice.set_tag(tag); } + + // read/write + DECLARE_READ8_MEMBER( c6280_r ); + DECLARE_WRITE8_MEMBER( c6280_w ); + +protected: + // device-level overrides + virtual void device_start(); + + // sound stream update overrides + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + +private: + struct channel { + UINT16 m_frequency; + UINT8 m_control; + UINT8 m_balance; + UINT8 m_waveform[32]; + UINT8 m_index; + INT16 m_dda; + UINT8 m_noise_control; + UINT32 m_noise_counter; + UINT32 m_counter; + }; + + // internal state + sound_stream *m_stream; + required_device m_cpudevice; + UINT8 m_select; + UINT8 m_balance; + UINT8 m_lfo_frequency; + UINT8 m_lfo_control; + channel m_channel[8]; + INT16 m_volume_table[32]; + UINT32 m_noise_freq_tab[32]; + UINT32 m_wave_freq_tab[4096]; +}; + +extern const device_type C6280; + +#define MCFG_C6280_CPU(_tag) \ + c6280_device::set_devicecpu_tag(*device, "^" _tag); + + +#endif /* __C6280_H__ */ diff --git a/src/devices/sound/cdda.c b/src/devices/sound/cdda.c new file mode 100644 index 00000000000..1b7c81c1172 --- /dev/null +++ b/src/devices/sound/cdda.c @@ -0,0 +1,271 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles,smf +/* + CD-DA "Red Book" audio sound hardware handler + Relies on the actual CD logic and reading in cdrom.c. +*/ + +#include "emu.h" +#include "cdda.h" + +#define MAX_SECTORS ( 4 ) + + +//------------------------------------------------- +// sound_stream_update - handle a stream update +//------------------------------------------------- + +void cdda_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + get_audio_data(&outputs[0][0], &outputs[1][0], samples); + m_audio_volume[0] = (INT16)outputs[0][0]; + m_audio_volume[1] = (INT16)outputs[1][0]; +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void cdda_device::device_start() +{ + /* allocate an audio cache */ + m_audio_cache = auto_alloc_array( machine(), UINT8, CD_MAX_SECTOR_DATA * MAX_SECTORS ); + + m_stream = machine().sound().stream_alloc(*this, 0, 2, 44100); + + m_audio_playing = 0; + m_audio_pause = 0; + m_audio_ended_normally = 0; + m_audio_lba = 0; + m_audio_length = 0; + m_audio_samples = 0; + m_audio_bptr = 0; + m_disc = NULL; + + save_item( NAME(m_audio_playing) ); + save_item( NAME(m_audio_pause) ); + save_item( NAME(m_audio_ended_normally) ); + save_item( NAME(m_audio_lba) ); + save_item( NAME(m_audio_length) ); + save_pointer( NAME(m_audio_cache), CD_MAX_SECTOR_DATA * MAX_SECTORS ); + save_item( NAME(m_audio_samples) ); + save_item( NAME(m_audio_bptr) ); +} + + +/*------------------------------------------------- + cdda_set_cdrom - set the CD-ROM file for the + given CDDA stream +-------------------------------------------------*/ + +void cdda_device::set_cdrom(void *file) +{ + m_disc = (cdrom_file *)file; +} + + +/*------------------------------------------------- + cdda_start_audio - begin playback of a Red + Book audio track +-------------------------------------------------*/ + +void cdda_device::start_audio(UINT32 startlba, UINT32 numblocks) +{ + m_stream->update(); + m_audio_playing = TRUE; + m_audio_pause = FALSE; + m_audio_ended_normally = FALSE; + m_audio_lba = startlba; + m_audio_length = numblocks; + m_audio_samples = 0; +} + + +/*------------------------------------------------- + cdda_stop_audio - stop playback of a Red Book + audio track +-------------------------------------------------*/ + +void cdda_device::stop_audio() +{ + m_stream->update(); + m_audio_playing = FALSE; + m_audio_ended_normally = TRUE; +} + + +/*------------------------------------------------- + cdda_pause_audio - pause/unpause playback of + a Red Book audio track +-------------------------------------------------*/ + +void cdda_device::pause_audio(int pause) +{ + m_stream->update(); + m_audio_pause = pause; +} + + +/*------------------------------------------------- + cdda_get_audio_lba - returns the current LBA + (physical sector) during Red Book playback +-------------------------------------------------*/ + +UINT32 cdda_device::get_audio_lba() +{ + m_stream->update(); + return m_audio_lba; +} + + +/*------------------------------------------------- + cdda_audio_active - returns Red Book audio + playback status +-------------------------------------------------*/ + +int cdda_device::audio_active() +{ + m_stream->update(); + return m_audio_playing; +} + + +/*------------------------------------------------- + cdda_audio_paused - returns if Red Book + playback is paused +-------------------------------------------------*/ + +int cdda_device::audio_paused() +{ + return m_audio_pause; +} + + +/*------------------------------------------------- + cdda_audio_ended - returns if a Red Book + track reached it's natural end +-------------------------------------------------*/ + +int cdda_device::audio_ended() +{ + return m_audio_ended_normally; +} + + +/*------------------------------------------------- + get_audio_data - reads Red Book data off + the disc if playback is in progress and + converts it to 2 16-bit 44.1 kHz streams +-------------------------------------------------*/ + +void cdda_device::get_audio_data(stream_sample_t *bufL, stream_sample_t *bufR, UINT32 samples_wanted) +{ + int i; + INT16 *audio_cache = (INT16 *) m_audio_cache; + + while (samples_wanted > 0) + { + /* if no file, audio not playing, audio paused, or out of disc data, + just zero fill */ + if (!m_disc || !m_audio_playing || m_audio_pause || (!m_audio_length && !m_audio_samples)) + { + if( m_disc && m_audio_playing && !m_audio_pause && !m_audio_length ) + { + m_audio_playing = FALSE; + m_audio_ended_normally = TRUE; + } + + memset(bufL, 0, sizeof(stream_sample_t)*samples_wanted); + memset(bufR, 0, sizeof(stream_sample_t)*samples_wanted); + return; + } + + int samples = samples_wanted; + if (samples > m_audio_samples) + { + samples = m_audio_samples; + } + + for (i = 0; i < samples; i++) + { + /* CD-DA data on the disc is big-endian */ + *bufL++ = (INT16) BIG_ENDIANIZE_INT16( audio_cache[ m_audio_bptr ] ); m_audio_bptr++; + *bufR++ = (INT16) BIG_ENDIANIZE_INT16( audio_cache[ m_audio_bptr ] ); m_audio_bptr++; + } + + samples_wanted -= samples; + m_audio_samples -= samples; + + if (m_audio_samples == 0) + { + int sectors = m_audio_length; + if (sectors > MAX_SECTORS) + { + sectors = MAX_SECTORS; + } + + for (i = 0; i < sectors; i++) + { + cdrom_read_data(m_disc, m_audio_lba, &m_audio_cache[CD_MAX_SECTOR_DATA*i], CD_TRACK_AUDIO); + + m_audio_lba++; + } + + m_audio_samples = (CD_MAX_SECTOR_DATA*sectors)/4; + m_audio_length -= sectors; + + /* reset feedout ptr */ + m_audio_bptr = 0; + } + } +} + +/*------------------------------------------------- + cdda_set_volume - sets CD-DA volume level + for both speakers, used for fade in/out effects +-------------------------------------------------*/ + +void cdda_device::set_volume(int volume) +{ + m_stream->set_output_gain(0,volume / 100.0); + m_stream->set_output_gain(1,volume / 100.0); +} + +/*------------------------------------------------- + cdda_set_channel_volume - sets CD-DA volume level + for either speaker, used for fade in/out effects +-------------------------------------------------*/ + +void cdda_device::set_channel_volume(int channel, int volume) +{ + m_stream->set_output_gain(channel,volume / 100.0); +} + + +/*------------------------------------------------- + cdda_get_channel_volume - sets CD-DA volume level + for either speaker, used for volume control display +-------------------------------------------------*/ + +INT16 cdda_device::get_channel_volume(int channel) +{ + return m_audio_volume[channel]; +} + +const device_type CDDA = &device_creator; + +cdda_device::cdda_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, CDDA, "CD/DA", tag, owner, clock, "cdda", __FILE__), + device_sound_interface(mconfig, *this) +{ +} + +//------------------------------------------------- +// device_config_complete - perform any +// operations now that the configuration is +// complete +//------------------------------------------------- + +void cdda_device::device_config_complete() +{ +} diff --git a/src/devices/sound/cdda.h b/src/devices/sound/cdda.h new file mode 100644 index 00000000000..7650348a099 --- /dev/null +++ b/src/devices/sound/cdda.h @@ -0,0 +1,58 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles,smf +#pragma once + +#ifndef __CDDA_H__ +#define __CDDA_H__ + +#include "cdrom.h" + +class cdda_device : public device_t, + public device_sound_interface +{ +public: + cdda_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + void set_cdrom(void *file); + + void start_audio(UINT32 startlba, UINT32 numblocks); + void stop_audio(); + void pause_audio(int pause); + void set_volume(int volume); + void set_channel_volume(int channel, int volume); + INT16 get_channel_volume(int channel); + + UINT32 get_audio_lba(); + int audio_active(); + int audio_paused(); + int audio_ended(); + + cdrom_file * m_disc; + +protected: + // device-level overrides + virtual void device_config_complete(); + virtual void device_start(); + + // sound stream update overrides + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + +private: + void get_audio_data(stream_sample_t *bufL, stream_sample_t *bufR, UINT32 samples_wanted); + + // internal state + sound_stream * m_stream; + + INT8 m_audio_playing, m_audio_pause, m_audio_ended_normally; + UINT32 m_audio_lba, m_audio_length; + + UINT8 * m_audio_cache; + UINT32 m_audio_samples; + UINT32 m_audio_bptr; + INT16 m_audio_volume[2]; +}; + +extern const device_type CDDA; + + +#endif /* __CDDA_H__ */ diff --git a/src/devices/sound/cdp1863.c b/src/devices/sound/cdp1863.c new file mode 100644 index 00000000000..08a88f914ce --- /dev/null +++ b/src/devices/sound/cdp1863.c @@ -0,0 +1,198 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + RCA CDP1863 CMOS 8-Bit Programmable Frequency Generator emulation + +**********************************************************************/ + +/* + + TODO: + + - what happens if you connect both clocks? + +*/ + +#include "cdp1863.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define LOG 0 + + +#define CDP1863_DEFAULT_LATCH 0x35 + + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +// devices +const device_type CDP1863 = &device_creator; + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// cdp1863_device - constructor +//------------------------------------------------- + +cdp1863_device::cdp1863_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, CDP1863, "CDP1863", tag, owner, clock, "cdp1863", __FILE__), + device_sound_interface(mconfig, *this), + m_stream(NULL), + m_clock1(clock), + m_clock2(0) +{ +} + + +//------------------------------------------------- +// static_set_clock2 - configuration helper +//------------------------------------------------- + +void cdp1863_device::static_set_clock2(device_t &device, int clock2) +{ + cdp1863_device &cdp1863 = downcast(device); + + cdp1863.m_clock2 = clock2; +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void cdp1863_device::device_start() +{ + // create sound stream + m_stream = machine().sound().stream_alloc(*this, 0, 1, machine().sample_rate()); + + // register for state saving + save_item(NAME(m_clock1)); + save_item(NAME(m_clock2)); + save_item(NAME(m_oe)); + save_item(NAME(m_latch)); + save_item(NAME(m_signal)); + save_item(NAME(m_incr)); +} + + +//------------------------------------------------- +// sound_stream_update - handle update requests for +// our sound stream +//------------------------------------------------- + +void cdp1863_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + // reset the output stream + memset(outputs[0], 0, samples * sizeof(*outputs[0])); + + INT16 signal = m_signal; + stream_sample_t *buffer = outputs[0]; + + memset( buffer, 0, samples * sizeof(*buffer) ); + + if (m_oe) + { + double frequency; + int rate = machine().sample_rate() / 2; + + // get progress through wave + int incr = m_incr; + + if (m_clock1 > 0) + { + // CLK1 is pre-divided by 4 + frequency = m_clock1 / 4 / (m_latch + 1) / 2; + } + else + { + // CLK2 is pre-divided by 8 + frequency = m_clock2 / 8 / (m_latch + 1) / 2; + } + + if (signal < 0) + { + signal = -0x7fff; + } + else + { + signal = 0x7fff; + } + + while( samples-- > 0 ) + { + *buffer++ = signal; + incr -= frequency; + while( incr < 0 ) + { + incr += rate; + signal = -signal; + } + } + + // store progress through wave + m_incr = incr; + m_signal = signal; + } +} + + +//------------------------------------------------- +// str_w - latch write +//------------------------------------------------- + +WRITE8_MEMBER( cdp1863_device::str_w ) +{ + m_latch = data; +} + + +//------------------------------------------------- +// str_w - latch write +//------------------------------------------------- + +void cdp1863_device::str_w(UINT8 data) +{ + m_latch = data; +} + + +//------------------------------------------------- +// oe_w - output enable write +//------------------------------------------------- + +WRITE_LINE_MEMBER( cdp1863_device::oe_w ) +{ + m_oe = state; +} + + +//------------------------------------------------- +// set_clk1 - set clock 1 +//------------------------------------------------- + +void cdp1863_device::set_clk1(int clock) +{ + m_clock1 = clock; +} + + +//------------------------------------------------- +// set_clk2 - set clock 2 +//------------------------------------------------- + +void cdp1863_device::set_clk2(int clock) +{ + m_clock2 = clock; +} diff --git a/src/devices/sound/cdp1863.h b/src/devices/sound/cdp1863.h new file mode 100644 index 00000000000..910be5153fd --- /dev/null +++ b/src/devices/sound/cdp1863.h @@ -0,0 +1,89 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + RCA CDP1863 CMOS 8-Bit Programmable Frequency Generator emulation + +********************************************************************** + _____ _____ + _RESET 1 |* \_/ | 16 Vdd + CLK 2 2 | | 15 OE + CLK 1 3 | | 14 OUT + STR 4 | CDP1863 | 13 DO7 + DI0 5 | | 12 DI6 + DI1 6 | | 11 DI5 + DI2 7 | | 10 DI4 + Vss 8 |_____________| 9 DI3 + +**********************************************************************/ + +#pragma once + +#ifndef __CDP1863__ +#define __CDP1863__ + +#include "emu.h" + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_CDP1863_ADD(_tag, _clock, _clock2) \ + MCFG_DEVICE_ADD(_tag, CDP1863, _clock) \ + cdp1863_device::static_set_clock2(*device, _clock2); + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> cdp1863_device + +class cdp1863_device : public device_t, + public device_sound_interface +{ +public: + // construction/destruction + cdp1863_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // inline configuration helpers + static void static_set_clock2(device_t &device, int clock2); + + DECLARE_WRITE8_MEMBER( str_w ); + void str_w(UINT8 data); + + DECLARE_WRITE_LINE_MEMBER( oe_w ); + + void set_clk1(int clock); + void set_clk2(int clock); + +protected: + // device-level overrides + virtual void device_start(); + + // internal callbacks + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + +private: + sound_stream *m_stream; + + int m_clock1; // clock 1 + int m_clock2; // clock 2 + + // sound state + int m_oe; // output enable + int m_latch; // sound latch + INT16 m_signal; // current signal + int m_incr; // initial wave state +}; + + +// device type definition +extern const device_type CDP1863; + + + +#endif diff --git a/src/devices/sound/cdp1864.c b/src/devices/sound/cdp1864.c new file mode 100644 index 00000000000..b4859cee4a3 --- /dev/null +++ b/src/devices/sound/cdp1864.c @@ -0,0 +1,467 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + RCA CDP1864C COS/MOS PAL Compatible Color TV Interface + +**********************************************************************/ + +/* + + TODO: + + - interlace mode + - PAL output, currently using RGB + - cpu synchronization + + SC1 and SC0 are used to provide CDP1864C-to-CPU synchronization for a jitter-free display. + During every horizontal sync the CDP1864C samples SC0 and SC1 for SC0 = 1 and SC1 = 0 + (CDP1800 execute state). Detection of a fetch cycle causes the CDP1864C to skip cycles to + attain synchronization. (i.e. picture moves 8 pixels to the right) + +*/ + +#include "cdp1864.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define CDP1864_DEFAULT_LATCH 0x35 + +#define CDP1864_CYCLES_DMA_START 2*8 +#define CDP1864_CYCLES_DMA_ACTIVE 8*8 +#define CDP1864_CYCLES_DMA_WAIT 6*8 + +const int cdp1864_device::bckgnd[] = { 2, 0, 4, 1 }; + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +// devices +const device_type CDP1864 = &device_creator; + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// cdp1864_device - constructor +//------------------------------------------------- + +cdp1864_device::cdp1864_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, CDP1864, "CDP1864", tag, owner, clock, "cdp1864", __FILE__), + device_sound_interface(mconfig, *this), + device_video_interface(mconfig, *this), + m_read_inlace(*this), + m_read_rdata(*this), + m_read_bdata(*this), + m_read_gdata(*this), + m_write_irq(*this), + m_write_dma_out(*this), + m_write_efx(*this), + m_write_hsync(*this), + m_disp(0), + m_dmaout(0), + m_bgcolor(0), + m_con(0), + m_aoe(0), + m_latch(CDP1864_DEFAULT_LATCH) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void cdp1864_device::device_start() +{ + // resolve callbacks + m_read_inlace.resolve_safe(1); + m_read_rdata.resolve_safe(0); + m_read_bdata.resolve_safe(0); + m_read_gdata.resolve_safe(0); + m_write_irq.resolve_safe(); + m_write_dma_out.resolve_safe(); + m_write_efx.resolve_safe(); + m_write_hsync.resolve_safe(); + + // initialize palette + initialize_palette(); + + // create sound stream + m_stream = machine().sound().stream_alloc(*this, 0, 1, machine().sample_rate()); + + // allocate timers + m_int_timer = timer_alloc(TIMER_INT); + m_efx_timer = timer_alloc(TIMER_EFX); + m_dma_timer = timer_alloc(TIMER_DMA); + m_hsync_timer = timer_alloc(TIMER_HSYNC); + + // find devices + m_screen->register_screen_bitmap(m_bitmap); + + // register for state saving + save_item(NAME(m_disp)); + save_item(NAME(m_dmaout)); + save_item(NAME(m_bgcolor)); + save_item(NAME(m_con)); + save_item(NAME(m_aoe)); + save_item(NAME(m_latch)); + save_item(NAME(m_signal)); + save_item(NAME(m_incr)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void cdp1864_device::device_reset() +{ + m_int_timer->adjust(m_screen->time_until_pos(CDP1864_SCANLINE_INT_START, 0)); + m_efx_timer->adjust(m_screen->time_until_pos(CDP1864_SCANLINE_EFX_TOP_START, 0)); + m_dma_timer->adjust(clocks_to_attotime(CDP1864_CYCLES_DMA_START)); + + m_disp = 0; + m_dmaout = 0; + + m_write_irq(CLEAR_LINE); + m_write_dma_out(CLEAR_LINE); + m_write_efx(CLEAR_LINE); + m_write_hsync(CLEAR_LINE); +} + + +//------------------------------------------------- +// device_timer - handle timer events +//------------------------------------------------- + +void cdp1864_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + int scanline = m_screen->vpos(); + + switch (id) + { + case TIMER_INT: + if (scanline == CDP1864_SCANLINE_INT_START) + { + if (m_disp) + { + m_write_irq(ASSERT_LINE); + } + + m_int_timer->adjust(m_screen->time_until_pos( CDP1864_SCANLINE_INT_END, 0)); + } + else + { + if (m_disp) + { + m_write_irq(CLEAR_LINE); + } + + m_int_timer->adjust(m_screen->time_until_pos(CDP1864_SCANLINE_INT_START, 0)); + } + break; + + case TIMER_EFX: + switch (scanline) + { + case CDP1864_SCANLINE_EFX_TOP_START: + m_write_efx(ASSERT_LINE); + m_efx_timer->adjust(m_screen->time_until_pos(CDP1864_SCANLINE_EFX_TOP_END, 0)); + break; + + case CDP1864_SCANLINE_EFX_TOP_END: + m_write_efx(CLEAR_LINE); + m_efx_timer->adjust(m_screen->time_until_pos(CDP1864_SCANLINE_EFX_BOTTOM_START, 0)); + break; + + case CDP1864_SCANLINE_EFX_BOTTOM_START: + m_write_efx(ASSERT_LINE); + m_efx_timer->adjust(m_screen->time_until_pos(CDP1864_SCANLINE_EFX_BOTTOM_END, 0)); + break; + + case CDP1864_SCANLINE_EFX_BOTTOM_END: + m_write_efx(CLEAR_LINE); + m_efx_timer->adjust(m_screen->time_until_pos(CDP1864_SCANLINE_EFX_TOP_START, 0)); + break; + } + break; + + case TIMER_DMA: + if (m_dmaout) + { + if (m_disp) + { + if (scanline >= CDP1864_SCANLINE_DISPLAY_START && scanline < CDP1864_SCANLINE_DISPLAY_END) + { + m_write_dma_out(CLEAR_LINE); + } + } + + m_dma_timer->adjust(clocks_to_attotime(CDP1864_CYCLES_DMA_WAIT)); + + m_dmaout = 0; + } + else + { + if (m_disp) + { + if (scanline >= CDP1864_SCANLINE_DISPLAY_START && scanline < CDP1864_SCANLINE_DISPLAY_END) + { + m_write_dma_out(ASSERT_LINE); + } + } + + m_dma_timer->adjust(clocks_to_attotime(CDP1864_CYCLES_DMA_ACTIVE)); + + m_dmaout = 1; + } + break; + } +} + + +//------------------------------------------------- +// sound_stream_update - handle update requests for +// our sound stream +//------------------------------------------------- + +void cdp1864_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + // reset the output stream + memset(outputs[0], 0, samples * sizeof(*outputs[0])); + + INT16 signal = m_signal; + stream_sample_t *buffer = outputs[0]; + + memset( buffer, 0, samples * sizeof(*buffer) ); + + if (m_aoe) + { + double frequency = unscaled_clock() / 8 / 4 / (m_latch + 1) / 2; + int rate = machine().sample_rate() / 2; + + /* get progress through wave */ + int incr = m_incr; + + if (signal < 0) + { + signal = -0x7fff; + } + else + { + signal = 0x7fff; + } + + while( samples-- > 0 ) + { + *buffer++ = signal; + incr -= frequency; + while( incr < 0 ) + { + incr += rate; + signal = -signal; + } + } + + /* store progress through wave */ + m_incr = incr; + m_signal = signal; + } +} + + +//------------------------------------------------- +// dispon_r - +//------------------------------------------------- + +READ8_MEMBER( cdp1864_device::dispon_r ) +{ + m_disp = 1; + + return 0xff; +} + + +//------------------------------------------------- +// dispoff_r - +//------------------------------------------------- + +READ8_MEMBER( cdp1864_device::dispoff_r ) +{ + m_disp = 0; + + m_write_irq(CLEAR_LINE); + m_write_dma_out(CLEAR_LINE); + + return 0xff; +} + + +//------------------------------------------------- +// step_bgcolor_w - +//------------------------------------------------- + +WRITE8_MEMBER( cdp1864_device::step_bgcolor_w ) +{ + m_disp = 1; + + m_bgcolor++; + m_bgcolor &= 0x03; +} + + +//------------------------------------------------- +// tone_latch_w - +//------------------------------------------------- + +WRITE8_MEMBER( cdp1864_device::tone_latch_w ) +{ + m_latch = data; +} + + +//------------------------------------------------- +// dma_w - +//------------------------------------------------- + +WRITE8_MEMBER( cdp1864_device::dma_w ) +{ + int rdata = 1, bdata = 1, gdata = 1; + int sx = m_screen->hpos() + 4; + int y = m_screen->vpos(); + + if (!m_con) + { + rdata = m_read_rdata(); + bdata = m_read_bdata(); + gdata = m_read_gdata(); + } + + for (int x = 0; x < 8; x++) + { + int color = bckgnd[m_bgcolor] + 8; + + if (BIT(data, 7)) + { + color = (gdata << 2) | (bdata << 1) | rdata; + } + + m_bitmap.pix32(y, sx + x) = m_palette[color]; + + data <<= 1; + } +} + + +//------------------------------------------------- +// con_w - color on write +//------------------------------------------------- + +WRITE_LINE_MEMBER( cdp1864_device::con_w ) +{ + if (!state) + { + m_con = 0; + } +} + + +//------------------------------------------------- +// aoe_w - audio output enable write +//------------------------------------------------- + +WRITE_LINE_MEMBER( cdp1864_device::aoe_w ) +{ + if (!state) + { + m_latch = CDP1864_DEFAULT_LATCH; + } + + m_aoe = state; +} + + +//------------------------------------------------- +// evs_w - external vertical sync write +//------------------------------------------------- + +WRITE_LINE_MEMBER( cdp1864_device::evs_w ) +{ +} + + +//------------------------------------------------- +// update_screen - +//------------------------------------------------- + +UINT32 cdp1864_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + if (m_disp) + { + copybitmap(bitmap, m_bitmap, 0, 0, 0, 0, cliprect); + m_bitmap.fill(m_palette[bckgnd[m_bgcolor] + 8], cliprect); + } + else + { + bitmap.fill(rgb_t::black, cliprect); + } + + return 0; +} + + +//------------------------------------------------- +// initialize_palette - +//------------------------------------------------- + +void cdp1864_device::initialize_palette() +{ + const int resistances_r[] = { m_chr_r }; + const int resistances_g[] = { m_chr_g }; + const int resistances_b[] = { m_chr_b }; + + double color_weights_r[1], color_weights_g[1], color_weights_b[1]; + double color_weights_bkg_r[1], color_weights_bkg_g[1], color_weights_bkg_b[1]; + + compute_resistor_weights(0, 0xff, -1.0, + 1, resistances_r, color_weights_r, 0, m_chr_bkg, + 1, resistances_g, color_weights_g, 0, m_chr_bkg, + 1, resistances_b, color_weights_b, 0, m_chr_bkg); + + compute_resistor_weights(0, 0xff, -1.0, + 1, resistances_r, color_weights_bkg_r, m_chr_bkg, 0, + 1, resistances_g, color_weights_bkg_g, m_chr_bkg, 0, + 1, resistances_b, color_weights_bkg_b, m_chr_bkg, 0); + + for (int i = 0; i < 8; i++) + { + // foreground colors + UINT8 r = 0, g = 0, b = 0; + + if (m_chr_r != RES_INF) r = combine_1_weights(color_weights_r, BIT(i, 0)); + if (m_chr_b != RES_INF) b = combine_1_weights(color_weights_b, BIT(i, 1)); + if (m_chr_g != RES_INF) g = combine_1_weights(color_weights_g, BIT(i, 2)); + + m_palette[i] = rgb_t(r, g, b); + + // background colors + r = 0, g = 0, b = 0; + + if (m_chr_r != RES_INF) r = combine_1_weights(color_weights_bkg_r, BIT(i, 0)); + if (m_chr_b != RES_INF) b = combine_1_weights(color_weights_bkg_b, BIT(i, 1)); + if (m_chr_g != RES_INF) g = combine_1_weights(color_weights_bkg_g, BIT(i, 2)); + + m_palette[i + 8] = rgb_t(r, g, b); + } +} diff --git a/src/devices/sound/cdp1864.h b/src/devices/sound/cdp1864.h new file mode 100644 index 00000000000..ab9f384dc1a --- /dev/null +++ b/src/devices/sound/cdp1864.h @@ -0,0 +1,208 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + RCA CDP1864C COS/MOS PAL Compatible Color TV Interface + +********************************************************************** + _____ _____ + INLACE 1 |* \_/ | 40 Vdd + CLK IN_ 2 | | 39 AUD + CLR OUT_ 3 | | 38 CLR IN_ + AOE 4 | | 37 DMA0_ + SC1 5 | | 36 INT_ + SC0 6 | | 35 TPA + MRD_ 7 | | 34 TPB + BUS 7 8 | | 33 EVS + BUS 6 9 | | 32 V SYNC + BUS 5 10 | CDP1864 | 31 H SYNC + BUS 4 11 | | 30 C SYNC_ + BUS 3 12 | | 29 RED + BUS 2 13 | | 28 BLUE + BUS 1 14 | | 27 GREEN + BUS 0 15 | | 26 BCK GND_ + CON_ 16 | | 25 BURST + N2 17 | | 24 ALT + EF_ 18 | | 23 R DATA + N0 19 | | 22 G DATA + Vss 20 |_____________| 21 B DATA + + + http://homepage.mac.com/ruske/cosmacelf/cdp1864.pdf + +**********************************************************************/ + +#pragma once + +#ifndef __CDP1864__ +#define __CDP1864__ + +#include "emu.h" +#include "machine/rescap.h" +#include "video/resnet.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define CDP1864_CLOCK XTAL_1_75MHz + +#define CDP1864_VISIBLE_COLUMNS 64 +#define CDP1864_VISIBLE_LINES 192 + +#define CDP1864_HBLANK_END 1 * 8 +#define CDP1864_HBLANK_START 13 * 8 +#define CDP1864_HSYNC_START 0 * 8 +#define CDP1864_HSYNC_END 1 * 8 +#define CDP1864_SCREEN_START 4 * 8 +#define CDP1864_SCREEN_END 12 * 8 +#define CDP1864_SCREEN_WIDTH 14 * 8 + +#define CDP1864_TOTAL_SCANLINES 312 + +#define CDP1864_SCANLINE_VBLANK_START CDP1864_TOTAL_SCANLINES - 4 +#define CDP1864_SCANLINE_VBLANK_END 20 +#define CDP1864_SCANLINE_VSYNC_START 0 +#define CDP1864_SCANLINE_VSYNC_END 4 +#define CDP1864_SCANLINE_DISPLAY_START 60 // ??? +#define CDP1864_SCANLINE_DISPLAY_END CDP1864_SCANLINE_DISPLAY_START + CDP1864_VISIBLE_LINES +#define CDP1864_SCANLINE_INT_START CDP1864_SCANLINE_DISPLAY_START - 2 +#define CDP1864_SCANLINE_INT_END CDP1864_SCANLINE_DISPLAY_START +#define CDP1864_SCANLINE_EFX_TOP_START CDP1864_SCANLINE_DISPLAY_START - 4 +#define CDP1864_SCANLINE_EFX_TOP_END CDP1864_SCANLINE_DISPLAY_START +#define CDP1864_SCANLINE_EFX_BOTTOM_START CDP1864_SCANLINE_DISPLAY_END - 4 +#define CDP1864_SCANLINE_EFX_BOTTOM_END CDP1864_SCANLINE_DISPLAY_END + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_CDP1864_ADD(_tag, _screen_tag, _clock, _inlace, _irq, _dma_out, _efx, _hsync, _rdata, _bdata, _gdata) \ + MCFG_SOUND_ADD(_tag, CDP1864, _clock) \ + MCFG_VIDEO_SET_SCREEN(_screen_tag) \ + downcast(device)->set_inlace_callback(DEVCB_##_inlace); \ + downcast(device)->set_irq_callback(DEVCB_##_irq); \ + downcast(device)->set_dma_out_callback(DEVCB_##_dma_out); \ + downcast(device)->set_efx_callback(DEVCB_##_efx); \ + downcast(device)->set_hsync_callback(DEVCB_##_hsync); \ + downcast(device)->set_rdata_callback(DEVCB_##_rdata); \ + downcast(device)->set_bdata_callback(DEVCB_##_bdata); \ + downcast(device)->set_gdata_callback(DEVCB_##_gdata); + +#define MCFG_CDP1864_CHROMINANCE(_r, _b, _g, _bkg) \ + downcast(device)->set_chrominance_resistors(_r, _b, _g, _bkg); + +#define MCFG_CDP1864_SCREEN_ADD(_tag, _clock) \ + MCFG_SCREEN_ADD(_tag, RASTER) \ + MCFG_SCREEN_RAW_PARAMS(_clock, CDP1864_SCREEN_WIDTH, CDP1864_HBLANK_END, CDP1864_HBLANK_START, CDP1864_TOTAL_SCANLINES, CDP1864_SCANLINE_VBLANK_END, CDP1864_SCANLINE_VBLANK_START) + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> cdp1864_device + +class cdp1864_device : public device_t, + public device_sound_interface, + public device_video_interface +{ +public: + // construction/destruction + cdp1864_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + template void set_inlace_callback(_inlace inlace) { m_read_inlace.set_callback(inlace); } + template void set_irq_callback(_irq irq) { m_write_irq.set_callback(irq); } + template void set_dma_out_callback(_dma_out dma_out) { m_write_dma_out.set_callback(dma_out); } + template void set_efx_callback(_efx efx) { m_write_efx.set_callback(efx); } + template void set_hsync_callback(_hsync hsync) { m_write_hsync.set_callback(hsync); } + template void set_rdata_callback(_rdata rdata) { m_read_rdata.set_callback(rdata); } + template void set_bdata_callback(_bdata bdata) { m_read_bdata.set_callback(bdata); } + template void set_gdata_callback(_gdata gdata) { m_read_gdata.set_callback(gdata); } + void set_chrominance_resistors(double r, double b, double g, double bkg) { m_chr_r = r; m_chr_b = b; m_chr_g = g; m_chr_bkg = bkg; } + + DECLARE_READ8_MEMBER( dispon_r ); + DECLARE_READ8_MEMBER( dispoff_r ); + + DECLARE_WRITE8_MEMBER( step_bgcolor_w ); + DECLARE_WRITE8_MEMBER( tone_latch_w ); + + DECLARE_WRITE8_MEMBER( dma_w ); + + DECLARE_WRITE_LINE_MEMBER( con_w ); + DECLARE_WRITE_LINE_MEMBER( aoe_w ); + DECLARE_WRITE_LINE_MEMBER( evs_w ); + + UINT32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + // internal callbacks + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + +private: + enum + { + TIMER_INT, + TIMER_EFX, + TIMER_DMA, + TIMER_HSYNC + }; + + void initialize_palette(); + + static const int bckgnd[]; + + devcb_read_line m_read_inlace; + devcb_read_line m_read_rdata; + devcb_read_line m_read_bdata; + devcb_read_line m_read_gdata; + devcb_write_line m_write_irq; + devcb_write_line m_write_dma_out; + devcb_write_line m_write_efx; + devcb_write_line m_write_hsync; + + bitmap_rgb32 m_bitmap; // bitmap + sound_stream *m_stream; // sound output + + // video state + double m_chr_r; // red chrominance resistor value + double m_chr_b; // blue chrominance resistor value + double m_chr_g; // green chrominance resistor value + double m_chr_bkg; // background chrominance resistor value + + rgb_t m_palette[16]; + int m_disp; // display on + int m_dmaout; // DMA request active + int m_bgcolor; // background color + int m_con; // color on + + // sound state + int m_aoe; // audio on + int m_latch; // sound latch + INT16 m_signal; // current signal + int m_incr; // initial wave state + + // timers + emu_timer *m_int_timer; + emu_timer *m_efx_timer; + emu_timer *m_dma_timer; + emu_timer *m_hsync_timer; +}; + + +// device type definition +extern const device_type CDP1864; + + + +#endif diff --git a/src/devices/sound/cdp1869.c b/src/devices/sound/cdp1869.c new file mode 100644 index 00000000000..383d7eb5d88 --- /dev/null +++ b/src/devices/sound/cdp1869.c @@ -0,0 +1,1004 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + RCA CDP1869/1870/1876 Video Interface System (VIS) emulation + +**********************************************************************/ + +/* + + TODO: + + - white noise + - scanline based update + - CMSEL output + +*/ + +#include "emu.h" +#include "cdp1869.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define LOG 0 + +#define CDP1869_WEIGHT_RED 30 // % of max luminance +#define CDP1869_WEIGHT_GREEN 59 +#define CDP1869_WEIGHT_BLUE 11 + +#define CDP1869_COLUMNS_HALF 20 +#define CDP1869_COLUMNS_FULL 40 +#define CDP1869_ROWS_HALF 12 +#define CDP1869_ROWS_FULL_PAL 25 +#define CDP1869_ROWS_FULL_NTSC 24 + +enum +{ + CDB0 = 0, + CDB1, + CDB2, + CDB3, + CDB4, + CDB5, + CCB0, + CCB1 +}; + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +// device type definition +const device_type CDP1869 = &device_creator; + +// I/O map +DEVICE_ADDRESS_MAP_START( io_map, 8, cdp1869_device ) + AM_RANGE(0x03, 0x03) AM_WRITE(out3_w) + AM_RANGE(0x04, 0x04) AM_WRITE(out4_w) + AM_RANGE(0x05, 0x05) AM_WRITE(out5_w) + AM_RANGE(0x06, 0x06) AM_WRITE(out6_w) + AM_RANGE(0x07, 0x07) AM_WRITE(out7_w) +ADDRESS_MAP_END + +// character RAM map +DEVICE_ADDRESS_MAP_START( char_map, 8, cdp1869_device ) + AM_RANGE(0x000, 0x3ff) AM_READWRITE(char_ram_r, char_ram_w) +ADDRESS_MAP_END + +// page RAM map +DEVICE_ADDRESS_MAP_START( page_map, 8, cdp1869_device ) + AM_RANGE(0x000, 0x7ff) AM_READWRITE(page_ram_r, page_ram_w) +ADDRESS_MAP_END + +// default address map +static ADDRESS_MAP_START( cdp1869, AS_0, 8, cdp1869_device ) + AM_RANGE(0x000, 0x7ff) AM_RAM +ADDRESS_MAP_END + + + +//************************************************************************** +// INLINE HELPERS +//************************************************************************** + +//------------------------------------------------- +// is_ntsc - is device in NTSC mode +//------------------------------------------------- + +inline bool cdp1869_device::is_ntsc() +{ + return m_read_pal_ntsc() ? false : true; +} + + +//------------------------------------------------- +// read_page_ram_byte - read a page RAM byte at +// the given address +//------------------------------------------------- + +inline UINT8 cdp1869_device::read_page_ram_byte(offs_t pma) +{ + return space().read_byte(pma); +} + + +//------------------------------------------------- +// write_page_ram_byte - write a page RAM byte at +// the given address +//------------------------------------------------- + +inline void cdp1869_device::write_page_ram_byte(offs_t pma, UINT8 data) +{ + space().write_byte(pma, data); +} + + +//------------------------------------------------- +// read_char_ram_byte - read a char RAM byte at +// the given address +//------------------------------------------------- + +inline UINT8 cdp1869_device::read_char_ram_byte(offs_t pma, offs_t cma, UINT8 pmd) +{ + UINT8 data = 0; + + if (!m_in_char_ram_func.isnull()) + { + data = m_in_char_ram_func(pma, cma, pmd); + } + + return data; +} + + +//------------------------------------------------- +// write_char_ram_byte - write a char RAM byte at +// the given address +//------------------------------------------------- + +inline void cdp1869_device::write_char_ram_byte(offs_t pma, offs_t cma, UINT8 pmd, UINT8 data) +{ + if (!m_out_char_ram_func.isnull()) + { + m_out_char_ram_func(pma, cma, pmd, data); + } +} + + +//------------------------------------------------- +// read_pcb - read page control bit +//------------------------------------------------- + +inline int cdp1869_device::read_pcb(offs_t pma, offs_t cma, UINT8 pmd) +{ + int pcb = 0; + + if (!m_in_pcb_func.isnull()) + { + pcb = m_in_pcb_func(pma, cma, pmd); + } + + return pcb; +} + + +//------------------------------------------------- +// update_prd_changed_timer - +//------------------------------------------------- + +inline void cdp1869_device::update_prd_changed_timer() +{ + int start = CDP1869_SCANLINE_PREDISPLAY_START_PAL; + int end = CDP1869_SCANLINE_PREDISPLAY_END_PAL; + int next_state; + int scanline = m_screen->vpos(); + int next_scanline; + + if (is_ntsc()) + { + start = CDP1869_SCANLINE_PREDISPLAY_START_NTSC; + end = CDP1869_SCANLINE_PREDISPLAY_END_NTSC; + } + + if (scanline < start) + { + next_scanline = start; + next_state = ASSERT_LINE; + } + else if (scanline < end) + { + next_scanline = end; + next_state = CLEAR_LINE; + } + else + { + next_scanline = start; + next_state = ASSERT_LINE; + } + + if (m_dispoff) + { + next_state = CLEAR_LINE; + } + + attotime duration = m_screen->time_until_pos(next_scanline); + m_prd_timer->adjust(duration, next_state); +} + + +//------------------------------------------------- +// get_rgb - get RGB value +//------------------------------------------------- + +inline rgb_t cdp1869_device::get_rgb(int i, int c, int l) +{ + int luma = 0, r, g, b; + + luma += (l & 4) ? CDP1869_WEIGHT_RED : 0; + luma += (l & 1) ? CDP1869_WEIGHT_GREEN : 0; + luma += (l & 2) ? CDP1869_WEIGHT_BLUE : 0; + + luma = (luma * 0xff) / 100; + + r = (c & 4) ? luma : 0; + g = (c & 1) ? luma : 0; + b = (c & 2) ? luma : 0; + + return rgb_t(r, g, b); +} + + +//------------------------------------------------- +// get_lines - get number of character lines +//------------------------------------------------- + +inline int cdp1869_device::get_lines() +{ + if (m_line16 && !m_dblpage) + { + return 16; + } + else if (!m_line9) + { + return 9; + } + else + { + return 8; + } +} + + +//------------------------------------------------- +// get_pmemsize - get page memory size +//------------------------------------------------- + +inline UINT16 cdp1869_device::get_pmemsize(int cols, int rows) +{ + int pmemsize = cols * rows; + + if (m_dblpage) pmemsize *= 2; + if (m_line16) pmemsize *= 2; + + return pmemsize; +} + + +//------------------------------------------------- +// get_pma - get page memory address +//------------------------------------------------- + +inline UINT16 cdp1869_device::get_pma() +{ + if (m_dblpage) + { + return m_pma; + } + else + { + return m_pma & 0x3ff; + } +} + + +//------------------------------------------------- +// get_pen - get pen for color bits +//------------------------------------------------- + +inline int cdp1869_device::get_pen(int ccb0, int ccb1, int pcb) +{ + int r = 0, g = 0, b = 0; + + switch (m_col) + { + case 0: + r = ccb0; + b = ccb1; + g = pcb; + break; + + case 1: + r = ccb0; + b = pcb; + g = ccb1; + break; + + case 2: + case 3: + r = pcb; + b = ccb0; + g = ccb1; + break; + } + + int color = (r << 2) + (b << 1) + g; + + if (m_cfc) + { + return color + ((m_bkg + 1) * 8); + } + else + { + return color; + } +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// cdp1869_device - constructor +//------------------------------------------------- + +cdp1869_device::cdp1869_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, CDP1869, "RCA CDP1869", tag, owner, clock, "cdp1869", __FILE__), + device_sound_interface(mconfig, *this), + device_video_interface(mconfig, *this), + device_memory_interface(mconfig, *this), + m_read_pal_ntsc(*this), + m_write_prd(*this), + m_color_clock(0), + m_stream(NULL), + m_palette(*this, "palette"), + m_space_config("pageram", ENDIANNESS_LITTLE, 8, 11, 0, NULL, *ADDRESS_MAP_NAME(cdp1869)) +{ +} + +static MACHINE_CONFIG_FRAGMENT( cdp1869 ) + MCFG_PALETTE_ADD("palette", 8+64) + MCFG_PALETTE_INIT_OWNER(cdp1869_device, cdp1869) +MACHINE_CONFIG_END + +//------------------------------------------------- +// machine_config_additions - return a pointer to +// the device's machine fragment +//------------------------------------------------- + +machine_config_constructor cdp1869_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( cdp1869 ); +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void cdp1869_device::device_start() +{ + // resolve callbacks + m_read_pal_ntsc.resolve_safe(0); + m_write_prd.resolve_safe(); + m_in_pcb_func.bind_relative_to(*owner()); + m_in_char_ram_func.bind_relative_to(*owner()); + m_out_char_ram_func.bind_relative_to(*owner()); + + // allocate timers + m_prd_timer = timer_alloc(); + m_dispoff = 0; + update_prd_changed_timer(); + + // initialize palette + m_bkg = 0; + + // create sound stream + m_stream = machine().sound().stream_alloc(*this, 0, 1, machine().sample_rate()); + + // initialize other + m_tonediv = 0; + m_tonefreq = 0; + m_toneamp = 0; + m_dblpage = 0; + m_line16 = 0; + m_line9 = 0; + m_fresvert = 0; + m_freshorz = 0; + m_hma = 0; + m_col = 0; + m_incr = 0; + m_signal = 0; + m_cfc = 0; + m_toneoff = 0; + m_cmem = 0; + + // register for state saving + save_item(NAME(m_prd)); + save_item(NAME(m_dispoff)); + save_item(NAME(m_fresvert)); + save_item(NAME(m_freshorz)); + save_item(NAME(m_cmem)); + save_item(NAME(m_dblpage)); + save_item(NAME(m_line16)); + save_item(NAME(m_line9)); + save_item(NAME(m_cfc)); + save_item(NAME(m_col)); + save_item(NAME(m_bkg)); + save_item(NAME(m_pma)); + save_item(NAME(m_hma)); + save_item(NAME(m_signal)); + save_item(NAME(m_incr)); + save_item(NAME(m_toneoff)); + save_item(NAME(m_wnoff)); + save_item(NAME(m_tonediv)); + save_item(NAME(m_tonefreq)); + save_item(NAME(m_toneamp)); + save_item(NAME(m_wnfreq)); + save_item(NAME(m_wnamp)); +} + + +//------------------------------------------------- +// device_post_load - device-specific post-load +//------------------------------------------------- + +void cdp1869_device::device_post_load() +{ + update_prd_changed_timer(); +} + + +//------------------------------------------------- +// device_timer - handler timer events +//------------------------------------------------- + +void cdp1869_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + m_write_prd(param); + m_prd = param; + + update_prd_changed_timer(); +} + + +//------------------------------------------------- +// memory_space_config - return a description of +// any address spaces owned by this device +//------------------------------------------------- + +const address_space_config *cdp1869_device::memory_space_config(address_spacenum spacenum) const +{ + return (spacenum == 0) ? &m_space_config : NULL; +} + + +//------------------------------------------------- +// initialize_palette - initialize palette +//------------------------------------------------- + +PALETTE_INIT_MEMBER(cdp1869_device, cdp1869) +{ + // color-on-color display (CFC=0) + int i; + + for (i = 0; i < 8; i++) + { + palette.set_pen_color(i, get_rgb(i, i, 15)); + } + + // tone-on-tone display (CFC=1) + for (int c = 0; c < 8; c++) + { + for (int l = 0; l < 8; l++) + { + palette.set_pen_color(i, get_rgb(i, c, l)); + i++; + } + } +} + + +//------------------------------------------------- +// sound_stream_update - handle update requests for +// our sound stream +//------------------------------------------------- + +void cdp1869_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + // reset the output stream + memset(outputs[0], 0, samples * sizeof(*outputs[0])); + + INT16 signal = m_signal; + stream_sample_t *buffer = outputs[0]; + + if (!m_toneoff && m_toneamp) + { + double frequency = (clock() / 2) / (512 >> m_tonefreq) / (m_tonediv + 1); +// double amplitude = m_toneamp * ((0.78*5) / 15); + + int rate = machine().sample_rate() / 2; + + /* get progress through wave */ + int incr = m_incr; + + if (signal < 0) + { + signal = -(m_toneamp * (0x07fff / 15)); + } + else + { + signal = m_toneamp * (0x07fff / 15); + } + + while( samples-- > 0 ) + { + *buffer++ = signal; + incr -= frequency; + while( incr < 0 ) + { + incr += rate; + signal = -signal; + } + } + + /* store progress through wave */ + m_incr = incr; + m_signal = signal; + } +/* + if (!m_wnoff) + { + double amplitude = m_wnamp * ((0.78*5) / 15); + + for (int wndiv = 0; wndiv < 128; wndiv++) + { + double frequency = (clock() / 2) / (4096 >> m_wnfreq) / (wndiv + 1): + + sum_square_wave(buffer, frequency, amplitude); + } + } +*/ + +} + + +//------------------------------------------------- +// draw_line - draw character line +//------------------------------------------------- + +void cdp1869_device::draw_line(bitmap_rgb32 &bitmap, const rectangle &rect, int x, int y, UINT8 data, int color) +{ + int i; + pen_t fg = m_palette->pen(color); + + data <<= 2; + + for (i = 0; i < CDP1869_CHAR_WIDTH; i++) + { + if (data & 0x80) + { + bitmap.pix32(y, x) = fg; + + if (!m_fresvert) + { + bitmap.pix32(y + 1, x) = fg; + } + + if (!m_freshorz) + { + bitmap.pix32(y, x + 1) = fg; + + if (!m_fresvert) + { + bitmap.pix32(y + 1, x + 1) = fg; + } + } + } + + if (!m_freshorz) + { + x++; + } + + x++; + + data <<= 1; + } +} + + +//------------------------------------------------- +// draw_char - draw character +//------------------------------------------------- + +void cdp1869_device::draw_char(bitmap_rgb32 &bitmap, const rectangle &rect, int x, int y, UINT16 pma) +{ + UINT8 pmd = read_page_ram_byte(pma); + + for (UINT8 cma = 0; cma < get_lines(); cma++) + { + UINT8 data = read_char_ram_byte(pma, cma, pmd); + + int ccb0 = BIT(data, CCB0); + int ccb1 = BIT(data, CCB1); + int pcb = read_pcb(pma, cma, pmd); + + int color = get_pen(ccb0, ccb1, pcb); + + draw_line(bitmap, rect, rect.min_x + x, rect.min_y + y, data, color); + + y++; + + if (!m_fresvert) + { + y++; + } + } +} + + +//------------------------------------------------- +// out3_w - register 3 write +//------------------------------------------------- + +WRITE8_MEMBER( cdp1869_device::out3_w ) +{ + /* + bit description + + 0 bkg green + 1 bkg blue + 2 bkg red + 3 cfc + 4 disp off + 5 colb0 + 6 colb1 + 7 fres horz + */ + + m_bkg = data & 0x07; + m_cfc = BIT(data, 3); + m_dispoff = BIT(data, 4); + m_col = (data & 0x60) >> 5; + m_freshorz = BIT(data, 7); +} + + +//------------------------------------------------- +// out4_w - register 4 write +//------------------------------------------------- + +WRITE8_MEMBER( cdp1869_device::out4_w ) +{ + /* + bit description + + 0 tone amp 2^0 + 1 tone amp 2^1 + 2 tone amp 2^2 + 3 tone amp 2^3 + 4 tone freq sel0 + 5 tone freq sel1 + 6 tone freq sel2 + 7 tone off + 8 tone / 2^0 + 9 tone / 2^1 + 10 tone / 2^2 + 11 tone / 2^3 + 12 tone / 2^4 + 13 tone / 2^5 + 14 tone / 2^6 + 15 always 0 + */ + + m_toneamp = offset & 0x0f; + m_tonefreq = (offset & 0x70) >> 4; + m_toneoff = BIT(offset, 7); + m_tonediv = (offset & 0x7f00) >> 8; + + m_stream->update(); +} + + +//------------------------------------------------- +// out5_w - register 5 write +//------------------------------------------------- + +WRITE8_MEMBER( cdp1869_device::out5_w ) +{ + /* + bit description + + 0 cmem access mode + 1 x + 2 x + 3 9-line + 4 x + 5 16 line hi-res + 6 double page + 7 fres vert + 8 wn amp 2^0 + 9 wn amp 2^1 + 10 wn amp 2^2 + 11 wn amp 2^3 + 12 wn freq sel0 + 13 wn freq sel1 + 14 wn freq sel2 + 15 wn off + */ + + m_cmem = BIT(offset, 0); + m_line9 = BIT(offset, 3); + m_line16 = BIT(offset, 5); + m_dblpage = BIT(offset, 6); + m_fresvert = BIT(offset, 7); + m_wnamp = (offset & 0x0f00) >> 8; + m_wnfreq = (offset & 0x7000) >> 12; + m_wnoff = BIT(offset, 15); + + m_stream->update(); + + if (m_cmem) + { + m_pma = offset; + } + else + { + m_pma = 0; + } +} + + +//------------------------------------------------- +// out6_w - register 6 write +//------------------------------------------------- + +WRITE8_MEMBER( cdp1869_device::out6_w ) +{ + /* + bit description + + 0 pma0 reg + 1 pma1 reg + 2 pma2 reg + 3 pma3 reg + 4 pma4 reg + 5 pma5 reg + 6 pma6 reg + 7 pma7 reg + 8 pma8 reg + 9 pma9 reg + 10 pma10 reg + 11 x + 12 x + 13 x + 14 x + 15 x + */ + + m_pma = offset & 0x7ff; +} + + +//------------------------------------------------- +// out7_w - register 7 write +//------------------------------------------------- + +WRITE8_MEMBER( cdp1869_device::out7_w ) +{ + /* + bit description + + 0 x + 1 x + 2 hma2 reg + 3 hma3 reg + 4 hma4 reg + 5 hma5 reg + 6 hma6 reg + 7 hma7 reg + 8 hma8 reg + 9 hma9 reg + 10 hma10 reg + 11 x + 12 x + 13 x + 14 x + 15 x + */ + + m_hma = offset & 0x7fc; +} + + +//------------------------------------------------- +// char_ram_r - character RAM read +//------------------------------------------------- + +READ8_MEMBER( cdp1869_device::char_ram_r ) +{ + UINT8 cma = offset & 0x0f; + UINT16 pma; + + if (m_cmem) + { + pma = get_pma(); + } + else + { + pma = offset; + } + + if (m_dblpage) + { + cma &= 0x07; + } + + UINT8 pmd = read_page_ram_byte(pma); + + return read_char_ram_byte(pma, cma, pmd); +} + + +//------------------------------------------------- +// char_ram_w - character RAM write +//------------------------------------------------- + +WRITE8_MEMBER( cdp1869_device::char_ram_w ) +{ + UINT8 cma = offset & 0x0f; + UINT16 pma; + + if (m_cmem) + { + pma = get_pma(); + } + else + { + pma = offset; + } + + if (m_dblpage) + { + cma &= 0x07; + } + + UINT8 pmd = read_page_ram_byte(pma); + + write_char_ram_byte(pma, cma, pmd, data); +} + + +//------------------------------------------------- +// page_ram_r - page RAM read +//------------------------------------------------- + +READ8_MEMBER( cdp1869_device::page_ram_r ) +{ + UINT16 pma; + + if (m_cmem) + { + pma = get_pma(); + } + else + { + pma = offset; + } + + return read_page_ram_byte(pma); +} + + +//------------------------------------------------- +// page_ram_w - page RAM write +//------------------------------------------------- + +WRITE8_MEMBER( cdp1869_device::page_ram_w ) +{ + UINT16 pma; + + if (m_cmem) + { + pma = get_pma(); + } + else + { + pma = offset; + } + + write_page_ram_byte(pma, data); +} + + +//------------------------------------------------- +// page_ram_w - predisplay +//------------------------------------------------- + +READ_LINE_MEMBER( cdp1869_device::predisplay_r ) +{ + return m_prd; +} + + +//------------------------------------------------- +// pal_ntsc_r - PAL/NTSC +//------------------------------------------------- + +READ_LINE_MEMBER( cdp1869_device::pal_ntsc_r ) +{ + return m_read_pal_ntsc(); +} + + +//------------------------------------------------- +// update_screen - update screen +//------------------------------------------------- + +UINT32 cdp1869_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + rectangle screen_rect, outer; + + if (is_ntsc()) + { + outer.min_x = CDP1869_HBLANK_END; + outer.max_x = CDP1869_HBLANK_START - 1; + outer.min_y = CDP1869_SCANLINE_VBLANK_END_NTSC; + outer.max_y = CDP1869_SCANLINE_VBLANK_START_NTSC - 1; + screen_rect.min_x = CDP1869_SCREEN_START_NTSC; + screen_rect.max_x = CDP1869_SCREEN_END - 1; + screen_rect.min_y = CDP1869_SCANLINE_DISPLAY_START_NTSC; + screen_rect.max_y = CDP1869_SCANLINE_DISPLAY_END_NTSC - 1; + } + else + { + outer.min_x = CDP1869_HBLANK_END; + outer.max_x = CDP1869_HBLANK_START - 1; + outer.min_y = CDP1869_SCANLINE_VBLANK_END_PAL; + outer.max_y = CDP1869_SCANLINE_VBLANK_START_PAL - 1; + screen_rect.min_x = CDP1869_SCREEN_START_PAL; + screen_rect.max_x = CDP1869_SCREEN_END - 1; + screen_rect.min_y = CDP1869_SCANLINE_DISPLAY_START_PAL; + screen_rect.max_y = CDP1869_SCANLINE_DISPLAY_END_PAL - 1; + } + + outer &= cliprect; + bitmap.fill(m_palette->pen(m_bkg), outer); + + if (!m_dispoff) + { + int width = CDP1869_CHAR_WIDTH; + int height = get_lines(); + + if (!m_freshorz) + { + width *= 2; + } + + if (!m_fresvert) + { + height *= 2; + } + + int cols = m_freshorz ? CDP1869_COLUMNS_FULL : CDP1869_COLUMNS_HALF; + int rows = screen_rect.height() / height; + + UINT16 pmemsize = get_pmemsize(cols, rows); + UINT16 addr = m_hma; + + for (int sy = 0; sy < rows; sy++) + { + for (int sx = 0; sx < cols; sx++) + { + int x = sx * width; + int y = sy * height; + + draw_char(bitmap, screen_rect, x, y, addr); + + addr++; + + if (addr == pmemsize) addr = 0; + } + } + } + return 0; +} diff --git a/src/devices/sound/cdp1869.h b/src/devices/sound/cdp1869.h new file mode 100644 index 00000000000..96185021ac4 --- /dev/null +++ b/src/devices/sound/cdp1869.h @@ -0,0 +1,302 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + RCA CDP1869/1870/1876 Video Interface System (VIS) emulation + +********************************************************************** + _____ _____ + TPA 1 |* \_/ | 40 Vdd + TPB 2 | | 39 PMSEL + _MRD 3 | | 38 _PMWR + _MWR 4 | | 37 CMSEL + MA0/8 5 | | 36 _CMWR + MA1/9 6 | | 35 PMA0 + MA2/10 7 | | 34 PMA1 + MA3/11 8 | | 33 PMA2 + MA4/12 9 | | 32 PMA3 + MA5/13 10 | | 31 PMA4 + MA6/14 11 | CDP1869 | 30 PMA5 + MA7/15 12 | | 29 PMA6 + N0 13 | | 28 PMA7 + N1 14 | | 27 PMA8 + N2 15 | | 26 PMA9 + _H SYNC 16 | | 25 CMA3/PMA10 + _DISPLAY 17 | | 24 CMA2 + _ADDRSTB 18 | | 23 CMA1 + SOUND 19 | | 22 CMA0 + Vss 20 |_____________| 21 _N=3 + + _____ _____ + _PREDISPLAY 1 |* \_/ | 40 Vdd + _DISPLAY 2 | | 39 PAL/_NTSC + PCB 3 | | 38 CPUCLK + CCB1 4 | | 37 XTAL (DOT) + BUS7 5 | | 36 _XTAL (DOT) + CCB0 6 | | 35 _ADDRSTB + BUS6 7 | | 34 _MRD + CDB5 8 | | 33 TPB + BUS5 9 | | 32 CMSEL + CDB4 10 | | 31 BURST + BUS4 11 | CDP1870 | 30 _H SYNC + CDB3 12 | | 29 _COMPSYNC + BUS3 13 | | 28 LUM + CDB2 14 | | 27 PAL CHROM + BUS2 15 | | 26 NTSC CHROM + CDB1 16 | | 25 _XTAL (CHROM) + BUS1 17 | | 24 XTAL (CHROM) + CDB0 18 | | 23 _EMS + BUS0 19 | | 22 _EVS + Vss 20 |_____________| 21 _N=3 + + _____ _____ + _PREDISPLAY 1 |* \_/ | 40 Vdd + _DISPLAY 2 | | 39 PAL/_NTSC + PCB 3 | | 38 CPUCLK + CCB1 4 | | 37 XTAL (DOT) + BUS7 5 | | 36 _XTAL (DOT) + CCB0 6 | | 35 _ADDRSTB + BUS6 7 | | 34 _MRD + CDB5 8 | | 33 TPB + BUS5 9 | | 32 CMSEL + CDB4 10 | | 31 BURST + BUS4 11 | CDP1876 | 30 _H SYNC + CDB3 12 | | 29 _COMPSYNC + BUS3 13 | | 28 RED + CDB2 14 | | 27 BLUE + BUS2 15 | | 26 GREEN + CDB1 16 | | 25 _XTAL (CHROM) + BUS1 17 | | 24 XTAL (CHROM) + CDB0 18 | | 23 _EMS + BUS0 19 | | 22 _EVS + Vss 20 |_____________| 21 _N=3 + +**********************************************************************/ + +#pragma once + +#ifndef __CDP1869__ +#define __CDP1869__ + +#include "emu.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define CDP1869_DOT_CLK_PAL (float)XTAL_5_626MHz +#define CDP1869_DOT_CLK_NTSC (float)XTAL_5_67MHz +#define CDP1869_COLOR_CLK_PAL (float)XTAL_8_867236MHz +#define CDP1869_COLOR_CLK_NTSC (float)XTAL_7_15909MHz + +#define CDP1869_CPU_CLK_PAL (CDP1869_DOT_CLK_PAL / 2) +#define CDP1869_CPU_CLK_NTSC (CDP1869_DOT_CLK_NTSC / 2) + +#define CDP1869_CHAR_WIDTH 6 + +#define CDP1869_HSYNC_START (56 * CDP1869_CHAR_WIDTH) +#define CDP1869_HSYNC_END (60 * CDP1869_CHAR_WIDTH) +#define CDP1869_HBLANK_START (54 * CDP1869_CHAR_WIDTH) +#define CDP1869_HBLANK_END ( 5 * CDP1869_CHAR_WIDTH) +#define CDP1869_SCREEN_START_PAL ( 9 * CDP1869_CHAR_WIDTH) +#define CDP1869_SCREEN_START_NTSC (10 * CDP1869_CHAR_WIDTH) +#define CDP1869_SCREEN_START (10 * CDP1869_CHAR_WIDTH) +#define CDP1869_SCREEN_END (50 * CDP1869_CHAR_WIDTH) +#define CDP1869_SCREEN_WIDTH (60 * CDP1869_CHAR_WIDTH) + +#define CDP1869_TOTAL_SCANLINES_PAL 312 +#define CDP1869_SCANLINE_VBLANK_START_PAL 304 +#define CDP1869_SCANLINE_VBLANK_END_PAL 10 +#define CDP1869_SCANLINE_VSYNC_START_PAL 308 +#define CDP1869_SCANLINE_VSYNC_END_PAL 312 +#define CDP1869_SCANLINE_DISPLAY_START_PAL 44 +#define CDP1869_SCANLINE_DISPLAY_END_PAL 260 +#define CDP1869_SCANLINE_PREDISPLAY_START_PAL 43 +#define CDP1869_SCANLINE_PREDISPLAY_END_PAL 260 +#define CDP1869_VISIBLE_SCANLINES_PAL (CDP1869_SCANLINE_DISPLAY_END_PAL - CDP1869_SCANLINE_DISPLAY_START_PAL) + +#define CDP1869_TOTAL_SCANLINES_NTSC 262 +#define CDP1869_SCANLINE_VBLANK_START_NTSC 252 +#define CDP1869_SCANLINE_VBLANK_END_NTSC 10 +#define CDP1869_SCANLINE_VSYNC_START_NTSC 258 +#define CDP1869_SCANLINE_VSYNC_END_NTSC 262 +#define CDP1869_SCANLINE_DISPLAY_START_NTSC 36 +#define CDP1869_SCANLINE_DISPLAY_END_NTSC 228 +#define CDP1869_SCANLINE_PREDISPLAY_START_NTSC 35 +#define CDP1869_SCANLINE_PREDISPLAY_END_NTSC 228 +#define CDP1869_VISIBLE_SCANLINES_NTSC (CDP1869_SCANLINE_DISPLAY_END_NTSC - CDP1869_SCANLINE_DISPLAY_START_NTSC) + +#define CDP1869_PALETTE_LENGTH 8+64 + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_CDP1869_ADD(_tag, _pixclock, _map) \ + MCFG_DEVICE_ADD(_tag, CDP1869, _pixclock) \ + MCFG_DEVICE_ADDRESS_MAP(AS_0, _map) + +#define MCFG_CDP1869_SCREEN_PAL_ADD(_cdptag, _tag, _clock) \ + MCFG_SCREEN_ADD(_tag, RASTER) \ + MCFG_SCREEN_UPDATE_DEVICE(_cdptag, cdp1869_device, screen_update) \ + MCFG_SCREEN_RAW_PARAMS(_clock, CDP1869_SCREEN_WIDTH, CDP1869_HBLANK_END, CDP1869_HBLANK_START, CDP1869_TOTAL_SCANLINES_PAL, CDP1869_SCANLINE_VBLANK_END_PAL, CDP1869_SCANLINE_VBLANK_START_PAL) + +#define MCFG_CDP1869_SCREEN_NTSC_ADD(_cdptag, _tag, _clock) \ + MCFG_SCREEN_ADD(_tag, RASTER) \ + MCFG_SCREEN_UPDATE_DEVICE(_cdptag, cdp1869_device, screen_update) \ + MCFG_SCREEN_RAW_PARAMS(_clock, CDP1869_SCREEN_WIDTH, CDP1869_HBLANK_END, CDP1869_HBLANK_START, CDP1869_TOTAL_SCANLINES_NTSC, CDP1869_SCANLINE_VBLANK_END_NTSC, CDP1869_SCANLINE_VBLANK_START_NTSC) + +#define MCFG_CDP1869_SET_SCREEN MCFG_VIDEO_SET_SCREEN + +#define CDP1869_CHAR_RAM_READ_MEMBER(name) UINT8 name(UINT16 pma, UINT8 cma, UINT8 pmd) +#define CDP1869_CHAR_RAM_WRITE_MEMBER(name) void name(UINT16 pma, UINT8 cma, UINT8 pmd, UINT8 data) +#define CDP1869_PCB_READ_MEMBER(name) int name(UINT16 pma, UINT8 cma, UINT8 pmd) + +#define MCFG_CDP1869_PAL_NTSC_CALLBACK(_read) \ + devcb = &cdp1869_device::set_pal_ntsc_rd_callback(*device, DEVCB_##_read); + +#define MCFG_CDP1869_PRD_CALLBACK(_write) \ + devcb = &cdp1869_device::set_prd_wr_callback(*device, DEVCB_##_write); + +#define MCFG_CDP1869_COLOR_CLOCK(_clk) \ + cdp1869_device::static_set_color_clock(*device, _clk); + +#define MCFG_CDP1869_CHAR_RAM_READ_OWNER(_class, _method) \ + cdp1869_device::static_set_char_ram_read(*device, cdp1869_char_ram_read_delegate(&_class::_method, #_class "::" #_method, downcast<_class *>(owner))); + +#define MCFG_CDP1869_CHAR_RAM_WRITE_OWNER(_class, _method) \ + cdp1869_device::static_set_char_ram_write(*device, cdp1869_char_ram_write_delegate(&_class::_method, #_class "::" #_method, downcast<_class *>(owner))); + +#define MCFG_CDP1869_CHAR_PCB_READ_OWNER(_class, _method) \ + cdp1869_device::static_set_pcb_read(*device, cdp1869_pcb_read_delegate(&_class::_method, #_class "::" #_method, downcast<_class *>(owner))); + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +typedef device_delegate cdp1869_char_ram_read_delegate; +typedef device_delegate cdp1869_char_ram_write_delegate; +typedef device_delegate cdp1869_pcb_read_delegate; + +// ======================> cdp1869_device + +class cdp1869_device : public device_t, + public device_sound_interface, + public device_video_interface, + public device_memory_interface +{ +public: + // construction/destruction + cdp1869_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + template static devcb_base &set_pal_ntsc_rd_callback(device_t &device, _Object object) { return downcast(device).m_read_pal_ntsc.set_callback(object); } + template static devcb_base &set_prd_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_prd.set_callback(object); } + static void static_set_char_ram_read(device_t &device, cdp1869_char_ram_read_delegate callback) { downcast(device).m_in_char_ram_func = callback; } + static void static_set_char_ram_write(device_t &device, cdp1869_char_ram_write_delegate callback) { downcast(device).m_out_char_ram_func = callback; } + static void static_set_pcb_read(device_t &device, cdp1869_pcb_read_delegate callback) { downcast(device).m_in_pcb_func = callback; } + static void static_set_color_clock(device_t &device, int color_clock) { downcast(device).m_color_clock = color_clock; } + + DECLARE_PALETTE_INIT(cdp1869); + + virtual DECLARE_ADDRESS_MAP(io_map, 8); + virtual DECLARE_ADDRESS_MAP(char_map, 8); + virtual DECLARE_ADDRESS_MAP(page_map, 8); + + DECLARE_WRITE8_MEMBER( out3_w ); + DECLARE_WRITE8_MEMBER( out4_w ); + DECLARE_WRITE8_MEMBER( out5_w ); + DECLARE_WRITE8_MEMBER( out6_w ); + DECLARE_WRITE8_MEMBER( out7_w ); + + DECLARE_READ8_MEMBER( char_ram_r ); + DECLARE_WRITE8_MEMBER( char_ram_w ); + + DECLARE_READ8_MEMBER( page_ram_r ); + DECLARE_WRITE8_MEMBER( page_ram_w ); + + DECLARE_READ_LINE_MEMBER( predisplay_r ); + DECLARE_READ_LINE_MEMBER( pal_ntsc_r ); + + UINT32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); + +protected: + // device-level overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual void device_start(); + virtual void device_post_load(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const; + + // device_sound_interface callbacks + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + + inline bool is_ntsc(); + inline UINT8 read_page_ram_byte(offs_t address); + inline void write_page_ram_byte(offs_t address, UINT8 data); + inline UINT8 read_char_ram_byte(offs_t pma, offs_t cma, UINT8 pmd); + inline void write_char_ram_byte(offs_t pma, offs_t cma, UINT8 pmd, UINT8 data); + inline int read_pcb(offs_t pma, offs_t cma, UINT8 pmd); + inline void update_prd_changed_timer(); + inline rgb_t get_rgb(int i, int c, int l); + inline int get_lines(); + inline UINT16 get_pmemsize(int cols, int rows); + inline UINT16 get_pma(); + inline int get_pen(int ccb0, int ccb1, int pcb); + + void draw_line(bitmap_rgb32 &bitmap, const rectangle &rect, int x, int y, UINT8 data, int color); + void draw_char(bitmap_rgb32 &bitmap, const rectangle &rect, int x, int y, UINT16 pma); + +private: + devcb_read_line m_read_pal_ntsc; + devcb_write_line m_write_prd; + cdp1869_pcb_read_delegate m_in_pcb_func; + cdp1869_char_ram_read_delegate m_in_char_ram_func; + cdp1869_char_ram_write_delegate m_out_char_ram_func; + int m_color_clock; + + //address_space *m_page_ram; + emu_timer *m_prd_timer; + sound_stream *m_stream; + required_device m_palette; + const address_space_config m_space_config; + + // video state + int m_prd; // predisplay + int m_dispoff; // display off + int m_fresvert; // full resolution vertical + int m_freshorz; // full resolution horizontal + int m_cmem; // character memory access mode + int m_dblpage; // double page mode + int m_line16; // 16-line hi-res mode + int m_line9; // 9 line mode + int m_cfc; // color format control + UINT8 m_col; // character color control + UINT8 m_bkg; // background color + UINT16 m_pma; // page memory address + UINT16 m_hma; // home memory address + + // sound state + INT16 m_signal; // current signal + int m_incr; // initial wave state + int m_toneoff; // tone off + int m_wnoff; // white noise off + UINT8 m_tonediv; // tone divisor + UINT8 m_tonefreq; // tone range select + UINT8 m_toneamp; // tone output amplitude + UINT8 m_wnfreq; // white noise range select + UINT8 m_wnamp; // white noise output amplitude +}; + + +// device type definition +extern const device_type CDP1869; + + + +#endif diff --git a/src/devices/sound/cem3394.c b/src/devices/sound/cem3394.c new file mode 100644 index 00000000000..f5af2dd2b86 --- /dev/null +++ b/src/devices/sound/cem3394.c @@ -0,0 +1,552 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + CEM3394 sound driver. + + This driver handles CEM-3394 analog synth chip. Very crudely. + + Still to do: + - adjust the overall volume when multiple waves are being generated + - filter internal sound + - support resonance (don't understand how it works) + +***************************************************************************/ + +#include "emu.h" +#include "cem3394.h" + + + +/* waveform generation parameters */ +#define ENABLE_PULSE 1 +#define ENABLE_TRIANGLE 1 +#define ENABLE_SAWTOOTH 1 +#define ENABLE_EXTERNAL 1 + + +/* pulse shaping parameters */ +/* examples: */ +/* hat trick - skidding ice sounds too loud if minimum width is too big */ +/* snake pit - melody during first level too soft if minimum width is too small */ +/* snake pit - bonus counter at the end of level */ +/* snacks'n jaxson - laugh at end of level is too soft if minimum width is too small */ + +#define LIMIT_WIDTH 1 +#define MINIMUM_WIDTH 0.25 +#define MAXIMUM_WIDTH 0.75 + + +/******************************************************************************** + + From the datasheet: + + CEM3394_VCO_FREQUENCY: + -4.0 ... +4.0 + -0.75 V/octave + f = exp(V) * 431.894 + + CEM3394_MODULATION_AMOUNT + 0.0 ... +3.5 + 0.0 == 0.01 x frequency + 3.5 == 2.00 x frequency + + CEM3394_WAVE_SELECT + -0.5 ... -0.2 == triangle + +0.9 ... +1.5 == triangle + sawtooth + +2.3 ... +3.9 == sawtooth + + CEM3394_PULSE_WIDTH + 0.0 ... +2.0 + 0.0 == 0% duty cycle + +2.0 == 100% duty cycle + + CEM3394_MIXER_BALANCE + -4.0 ... +4.0 + 0.0 both at -6dB + -20 dB/V + + CEM3394_FILTER_RESONANCE + 0.0 ... +2.5 + 0.0 == no resonance + +2.5 == oscillation + + CEM3394_FILTER_FREQENCY + -3.0 ... +4.0 + -0.375 V/octave + 0.0 == 1300Hz + + CEM3394_FINAL_GAIN + 0.0 ... +4.0 + -20 dB/V + 0.0 == -90dB + 4.0 == 0dB + + Square wave output = 160 (average is constant regardless of duty cycle) + Sawtooth output = 200 + Triangle output = 250 + Sawtooth + triangle output = 330 + Maximum output = 400 + +********************************************************************************/ + + +// various waveforms +#define WAVE_TRIANGLE 1 +#define WAVE_SAWTOOTH 2 +#define WAVE_PULSE 4 + +// keep lots of fractional bits +#define FRACTION_BITS 28 +#define FRACTION_ONE (1 << FRACTION_BITS) +#define FRACTION_ONE_D ((double)(1 << FRACTION_BITS)) +#define FRACTION_MASK (FRACTION_ONE - 1) +#define FRACTION_MULT(a,b) (((a) >> (FRACTION_BITS / 2)) * ((b) >> (FRACTION_BITS - FRACTION_BITS / 2))) + + +// device type definition +const device_type CEM3394 = &device_creator; + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// cem3394_device - constructor +//------------------------------------------------- + +cem3394_device::cem3394_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, CEM3394, "CEM3394", tag, owner, clock, "cem3394", __FILE__), + device_sound_interface(mconfig, *this), + m_stream(NULL), + m_vco_zero_freq(0.0), + m_filter_zero_freq(0.0), + m_wave_select(0), + m_volume(0), + m_mixer_internal(0), + m_mixer_external(0), + m_position(0), + m_step(0), + m_filter_position(0), + m_filter_step(0), + m_modulation_depth(0), + m_last_ext(0), + m_pulse_width(0), + m_inv_sample_rate(0.0), + m_sample_rate(0), + m_mixer_buffer(NULL), + m_external_buffer(NULL) +{ + memset(m_values, 0, 8*sizeof(double)); +} + + +//------------------------------------------------- +// sound_stream_update - generate sound to the mix buffer in mono +//------------------------------------------------- + +void cem3394_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + int int_volume = (m_volume * m_mixer_internal) / 256; + int ext_volume = (m_volume * m_mixer_external) / 256; + UINT32 step = m_step, position, end_position = 0; + stream_sample_t *buffer = outputs[0]; + INT16 *mix, *ext; + int i; + + /* external volume is effectively 0 if no external function */ + if (m_ext_cb.isnull() || !ENABLE_EXTERNAL) + ext_volume = 0; + + /* adjust the volume for the filter */ + if (step > m_filter_step) + int_volume /= step - m_filter_step; + + /* bail if nothing's going on */ + if (int_volume == 0 && ext_volume == 0) + { + memset(buffer, 0, sizeof(*buffer) * samples); + return; + } + + /* if there's external stuff, fetch and process it now */ + if (ext_volume != 0) + { + UINT32 fposition = m_filter_position, fstep = m_filter_step, depth; + INT16 last_ext = m_last_ext; + + /* fetch the external data */ + m_ext_cb(samples, m_external_buffer); + + /* compute the modulation depth, and adjust fstep to the maximum frequency */ + /* we lop off 13 bits of depth so that we can multiply by stepadjust, below, */ + /* which has 13 bits of precision */ + depth = FRACTION_MULT(fstep, m_modulation_depth); + fstep += depth; + depth >>= 13; + + /* "apply" the filter: note this is pretty cheesy; it basically just downsamples the + external sample to filter_freq by allowing only 2 transitions for every cycle */ + for (i = 0, ext = m_external_buffer, position = m_position; i < samples; i++, ext++) + { + UINT32 newposition; + INT32 stepadjust; + + /* update the position and compute the adjustment from a triangle wave */ + if (position & (1 << (FRACTION_BITS - 1))) + stepadjust = 0x2000 - ((position >> (FRACTION_BITS - 14)) & 0x1fff); + else + stepadjust = (position >> (FRACTION_BITS - 14)) & 0x1fff; + position += step; + + /* if we cross a half-step boundary, allow the next byte of the external input */ + newposition = fposition + fstep - (stepadjust * depth); + if ((newposition ^ fposition) & ~(FRACTION_MASK >> 1)) + last_ext = *ext; + else + *ext = last_ext; + fposition = newposition & FRACTION_MASK; + } + + /* update the final filter values */ + m_filter_position = fposition; + m_last_ext = last_ext; + } + + /* if there's internal stuff, generate it */ + if (int_volume != 0) + { + if (m_wave_select == 0 && !ext_volume) + logerror("%f V didn't cut it\n", m_values[CEM3394_WAVE_SELECT]); + + /* handle the pulse component; it maxes out at 0x1932, which is 27% smaller than */ + /* the sawtooth (since the value is constant, this is the best place to have an */ + /* odd value for volume) */ + if (ENABLE_PULSE && (m_wave_select & WAVE_PULSE)) + { + UINT32 pulse_width = m_pulse_width; + + /* if the width is wider than the step, we're guaranteed to hit it once per cycle */ + if (pulse_width >= step) + { + for (i = 0, mix = m_mixer_buffer, position = m_position; i < samples; i++, mix++) + { + if (position < pulse_width) + *mix = 0x1932; + else + *mix = 0x0000; + position = (position + step) & FRACTION_MASK; + } + } + + /* otherwise, we compute a volume and watch for cycle boundary crossings */ + else + { + INT16 volume = 0x1932 * pulse_width / step; + for (i = 0, mix = m_mixer_buffer, position = m_position; i < samples; i++, mix++) + { + UINT32 newposition = position + step; + if ((newposition ^ position) & ~FRACTION_MASK) + *mix = volume; + else + *mix = 0x0000; + position = newposition & FRACTION_MASK; + } + } + end_position = position; + } + + /* otherwise, clear the mixing buffer */ + else + memset(m_mixer_buffer, 0, sizeof(INT16) * samples); + + /* handle the sawtooth component; it maxes out at 0x2000, which is 27% larger */ + /* than the pulse */ + if (ENABLE_SAWTOOTH && (m_wave_select & WAVE_SAWTOOTH)) + { + for (i = 0, mix = m_mixer_buffer, position = m_position; i < samples; i++, mix++) + { + *mix += ((position >> (FRACTION_BITS - 14)) & 0x3fff) - 0x2000; + position += step; + } + end_position = position & FRACTION_MASK; + } + + /* handle the triangle component; it maxes out at 0x2800, which is 25% larger */ + /* than the sawtooth (should be 27% according to the specs, but 25% saves us */ + /* a multiplication) */ + if (ENABLE_TRIANGLE && (m_wave_select & WAVE_TRIANGLE)) + { + for (i = 0, mix = m_mixer_buffer, position = m_position; i < samples; i++, mix++) + { + INT16 value; + if (position & (1 << (FRACTION_BITS - 1))) + value = 0x2000 - ((position >> (FRACTION_BITS - 14)) & 0x1fff); + else + value = (position >> (FRACTION_BITS - 14)) & 0x1fff; + *mix += value + (value >> 2); + position += step; + } + end_position = position & FRACTION_MASK; + } + + /* update the final position */ + m_position = end_position; + } + + /* mix it down */ + mix = m_mixer_buffer; + ext = m_external_buffer; + { + /* internal + external */ + if (ext_volume != 0 && int_volume != 0) + { + for (i = 0; i < samples; i++, mix++, ext++) + *buffer++ = (*mix * int_volume + *ext * ext_volume) / 128; + } + /* internal only */ + else if (int_volume != 0) + { + for (i = 0; i < samples; i++, mix++) + *buffer++ = *mix * int_volume / 128; + } + /* external only */ + else + { + for (i = 0; i < samples; i++, ext++) + *buffer++ = *ext * ext_volume / 128; + } + } +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void cem3394_device::device_start() +{ + /* copy global parameters */ + m_sample_rate = CEM3394_SAMPLE_RATE; + m_inv_sample_rate = 1.0 / (double)m_sample_rate; + + /* allocate stream channels, 1 per chip */ + m_stream = stream_alloc(0, 1, m_sample_rate); + + m_ext_cb.bind_relative_to(*owner()); + + /* allocate memory for a mixer buffer and external buffer (1 second should do it!) */ + m_mixer_buffer = auto_alloc_array(machine(), INT16, m_sample_rate); + m_external_buffer = auto_alloc_array(machine(), INT16, m_sample_rate); + + save_item(NAME(m_values)); + save_item(NAME(m_wave_select)); + save_item(NAME(m_volume)); + save_item(NAME(m_mixer_internal)); + save_item(NAME(m_mixer_external)); + save_item(NAME(m_position)); + save_item(NAME(m_step)); + save_item(NAME(m_filter_position)); + save_item(NAME(m_filter_step)); + save_item(NAME(m_modulation_depth)); + save_item(NAME(m_last_ext)); + save_item(NAME(m_pulse_width)); +} + + +double cem3394_device::compute_db(double voltage) +{ + /* assumes 0.0 == full off, 4.0 == full on, with linear taper, as described in the datasheet */ + + /* above 4.0, maximum volume */ + if (voltage >= 4.0) + return 0.0; + + /* below 0.0, minimum volume */ + else if (voltage <= 0.0) + return 90.0; + + /* between 2.5 and 4.0, linear from 20dB to 0dB */ + else if (voltage >= 2.5) + return (4.0 - voltage) * (1.0 / 1.5) * 20.0; + + /* between 0.0 and 2.5, exponential to 20dB */ + else + { + double temp = 20.0 * pow(2.0, 2.5 - voltage); + if (temp < 90.0) return 90.0; + else return temp; + } +} + + +UINT32 cem3394_device::compute_db_volume(double voltage) +{ + double temp; + + /* assumes 0.0 == full off, 4.0 == full on, with linear taper, as described in the datasheet */ + + /* above 4.0, maximum volume */ + if (voltage >= 4.0) + return 256; + + /* below 0.0, minimum volume */ + else if (voltage <= 0.0) + return 0; + + /* between 2.5 and 4.0, linear from 20dB to 0dB */ + else if (voltage >= 2.5) + temp = (4.0 - voltage) * (1.0 / 1.5) * 20.0; + + /* between 0.0 and 2.5, exponential to 20dB */ + else + { + temp = 20.0 * pow(2.0, 2.5 - voltage); + if (temp < 50.0) return 0; + } + + /* convert from dB to volume and return */ + return (UINT32)(256.0 * pow(0.891251, temp)); +} + + +void cem3394_device::set_voltage(int input, double voltage) +{ + double temp; + + /* don't do anything if no change */ + if (voltage == m_values[input]) + return; + m_values[input] = voltage; + + /* update the stream first */ + m_stream->update(); + + /* switch off the input */ + switch (input) + { + /* frequency varies from -4.0 to +4.0, at 0.75V/octave */ + case CEM3394_VCO_FREQUENCY: + temp = m_vco_zero_freq * pow(2.0, -voltage * (1.0 / 0.75)); + m_step = (UINT32)(temp * m_inv_sample_rate * FRACTION_ONE_D); + break; + + /* wave select determines triangle/sawtooth enable */ + case CEM3394_WAVE_SELECT: + m_wave_select &= ~(WAVE_TRIANGLE | WAVE_SAWTOOTH); + if (voltage >= -0.5 && voltage <= -0.2) + m_wave_select |= WAVE_TRIANGLE; + else if (voltage >= 0.9 && voltage <= 1.5) + m_wave_select |= WAVE_TRIANGLE | WAVE_SAWTOOTH; + else if (voltage >= 2.3 && voltage <= 3.9) + m_wave_select |= WAVE_SAWTOOTH; + break; + + /* pulse width determines duty cycle; 0.0 means 0%, 2.0 means 100% */ + case CEM3394_PULSE_WIDTH: + if (voltage < 0.0) + { + m_pulse_width = 0; + m_wave_select &= ~WAVE_PULSE; + } + else + { + temp = voltage * 0.5; + if (LIMIT_WIDTH) + temp = MINIMUM_WIDTH + (MAXIMUM_WIDTH - MINIMUM_WIDTH) * temp; + m_pulse_width = (UINT32)(temp * FRACTION_ONE_D); + m_wave_select |= WAVE_PULSE; + } + break; + + /* final gain is pretty self-explanatory; 0.0 means ~90dB, 4.0 means 0dB */ + case CEM3394_FINAL_GAIN: + m_volume = compute_db_volume(voltage); + break; + + /* mixer balance is a pan between the external input and the internal input */ + /* 0.0 is equal parts of both; positive values favor external, negative favor internal */ + case CEM3394_MIXER_BALANCE: + if (voltage >= 0.0) + { + m_mixer_internal = compute_db_volume(3.55 - voltage); + m_mixer_external = compute_db_volume(3.55 + 0.45 * (voltage * 0.25)); + } + else + { + m_mixer_internal = compute_db_volume(3.55 - 0.45 * (voltage * 0.25)); + m_mixer_external = compute_db_volume(3.55 + voltage); + } + break; + + /* filter frequency varies from -4.0 to +4.0, at 0.375V/octave */ + case CEM3394_FILTER_FREQENCY: + temp = m_filter_zero_freq * pow(2.0, -voltage * (1.0 / 0.375)); + m_filter_step = (UINT32)(temp * m_inv_sample_rate * FRACTION_ONE_D); + break; + + /* modulation depth is 0.01 at 0V and 2.0 at 3.5V; how it grows from one to the other */ + /* is still unclear at this point */ + case CEM3394_MODULATION_AMOUNT: + if (voltage < 0.0) + m_modulation_depth = (UINT32)(0.01 * FRACTION_ONE_D); + else if (voltage > 3.5) + m_modulation_depth = (UINT32)(2.00 * FRACTION_ONE_D); + else + m_modulation_depth = (UINT32)(((voltage * (1.0 / 3.5)) * 1.99 + 0.01) * FRACTION_ONE_D); + break; + + /* this is not yet implemented */ + case CEM3394_FILTER_RESONANCE: + break; + } +} + + +double cem3394_device::get_parameter(int input) +{ + double voltage = m_values[input]; + + switch (input) + { + case CEM3394_VCO_FREQUENCY: + return m_vco_zero_freq * pow(2.0, -voltage * (1.0 / 0.75)); + + case CEM3394_WAVE_SELECT: + return voltage; + + case CEM3394_PULSE_WIDTH: + if (voltage <= 0.0) + return 0.0; + else if (voltage >= 2.0) + return 1.0; + else + return voltage * 0.5; + + case CEM3394_FINAL_GAIN: + return compute_db(voltage); + + case CEM3394_MIXER_BALANCE: + return voltage * 0.25; + + case CEM3394_MODULATION_AMOUNT: + if (voltage < 0.0) + return 0.01; + else if (voltage > 3.5) + return 2.0; + else + return (voltage * (1.0 / 3.5)) * 1.99 + 0.01; + + case CEM3394_FILTER_RESONANCE: + if (voltage < 0.0) + return 0.0; + else if (voltage > 2.5) + return 1.0; + else + return voltage * (1.0 / 2.5); + + case CEM3394_FILTER_FREQENCY: + return m_filter_zero_freq * pow(2.0, -voltage * (1.0 / 0.375)); + } + return 0.0; +} diff --git a/src/devices/sound/cem3394.h b/src/devices/sound/cem3394.h new file mode 100644 index 00000000000..65290aefce9 --- /dev/null +++ b/src/devices/sound/cem3394.h @@ -0,0 +1,117 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +#pragma once + +#ifndef __CEM3394_H__ +#define __CEM3394_H__ + +#define CEM3394_SAMPLE_RATE (44100*4) + +// inputs +enum +{ + CEM3394_VCO_FREQUENCY = 0, + CEM3394_MODULATION_AMOUNT, + CEM3394_WAVE_SELECT, + CEM3394_PULSE_WIDTH, + CEM3394_MIXER_BALANCE, + CEM3394_FILTER_RESONANCE, + CEM3394_FILTER_FREQENCY, + CEM3394_FINAL_GAIN +}; + +typedef device_delegate cem3394_ext_input_delegate; + +#define CEM3394_EXT_INPUT(_name) void _name(int count, short *buffer) + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_CEM3394_ADD(_tag, _clock) \ + MCFG_DEVICE_ADD(_tag, CEM3394, _clock) +#define MCFG_CEM3394_REPLACE(_tag, _clock) \ + MCFG_DEVICE_REPLACE(_tag, CEM3394, _clock) + +#define MCFG_CEM3394_EXT_INPUT_CB(_class, _method) \ + cem3394_device::set_ext_input_callback(*device, cem3394_ext_input_delegate(&_class::_method, #_class "::" #_method, downcast<_class *>(owner))); + +#define MCFG_CEM3394_VCO_ZERO(_freq) \ + cem3394_device::set_vco_zero_freq(*device, _freq); + +#define MCFG_CEM3394_FILTER_ZERO(_freq) \ + cem3394_device::set_filter_zero_freq(*device, _freq); + + +class cem3394_device : public device_t, + public device_sound_interface +{ +public: + cem3394_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + ~cem3394_device() { } + + static void set_ext_input_callback(device_t &device, cem3394_ext_input_delegate callback) { downcast(device).m_ext_cb = callback; } + static void set_vco_zero_freq(device_t &device, double freq) { downcast(device).m_vco_zero_freq = freq; } + static void set_filter_zero_freq(device_t &device, double freq) { downcast(device).m_filter_zero_freq = freq; } + +protected: + // device-level overrides + virtual void device_start(); + + // sound stream update overrides + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + +public: + // Set the voltage going to a particular parameter + void set_voltage(int input, double voltage); + + // Get the translated parameter associated with the given input as follows: + // CEM3394_VCO_FREQUENCY: frequency in Hz + // CEM3394_MODULATION_AMOUNT: scale factor, 0.0 to 2.0 + // CEM3394_WAVE_SELECT: voltage from this line + // CEM3394_PULSE_WIDTH: width fraction, from 0.0 to 1.0 + // CEM3394_MIXER_BALANCE: balance, from -1.0 to 1.0 + // CEM3394_FILTER_RESONANCE: resonance, from 0.0 to 1.0 + // CEM3394_FILTER_FREQENCY: frequency, in Hz + // CEM3394_FINAL_GAIN: gain, in dB + double get_parameter(int input); + +private: + double compute_db(double voltage); + UINT32 compute_db_volume(double voltage); + +private: + cem3394_ext_input_delegate m_ext_cb; /* callback to generate external samples */ + + sound_stream *m_stream; /* our stream */ + double m_vco_zero_freq; /* frequency of VCO at 0.0V */ + double m_filter_zero_freq; /* frequency of filter at 0.0V */ + + double m_values[8]; /* raw values of registers */ + UINT8 m_wave_select; /* flags which waveforms are enabled */ + + UINT32 m_volume; /* linear overall volume (0-256) */ + UINT32 m_mixer_internal; /* linear internal volume (0-256) */ + UINT32 m_mixer_external; /* linear external volume (0-256) */ + + UINT32 m_position; /* current VCO frequency position (0.FRACTION_BITS) */ + UINT32 m_step; /* per-sample VCO step (0.FRACTION_BITS) */ + + UINT32 m_filter_position; /* current filter frequency position (0.FRACTION_BITS) */ + UINT32 m_filter_step; /* per-sample filter step (0.FRACTION_BITS) */ + UINT32 m_modulation_depth; /* fraction of total by which we modulate (0.FRACTION_BITS) */ + INT16 m_last_ext; /* last external sample we read */ + + UINT32 m_pulse_width; /* fractional pulse width (0.FRACTION_BITS) */ + + double m_inv_sample_rate; + int m_sample_rate; + + INT16 *m_mixer_buffer; + INT16 *m_external_buffer; +}; + +extern const device_type CEM3394; + + +#endif /* __CEM3394_H__ */ diff --git a/src/devices/sound/dac.c b/src/devices/sound/dac.c new file mode 100644 index 00000000000..8e4baffe3aa --- /dev/null +++ b/src/devices/sound/dac.c @@ -0,0 +1,92 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + dac.c + + DAC device emulator. + +***************************************************************************/ + +#include "emu.h" +#include "dac.h" + + +// device type definition +const device_type DAC = &device_creator; + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// dac_device - constructor +//------------------------------------------------- + +dac_device::dac_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, DAC, "DAC", tag, owner, clock, "dac", __FILE__), + device_sound_interface(mconfig, *this), + m_stream(NULL), + m_output(0) +{ +} + + +//------------------------------------------------- +// write_unsigned8 - write an 8-bit value, +// keeping the scaled result unsigned +//------------------------------------------------- + +WRITE8_MEMBER( dac_device::write_unsigned8 ) +{ + write_unsigned8(data); +} + + +//------------------------------------------------- +// write_signed8 - write an 8-bit value, +// keeping the scaled result signed +//------------------------------------------------- + +WRITE8_MEMBER( dac_device::write_signed8 ) +{ + write_signed8(data); +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void dac_device::device_start() +{ + // create the stream + m_stream = stream_alloc(0, 1, DEFAULT_SAMPLE_RATE); + + // register for save states + save_item(NAME(m_output)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void dac_device::device_reset() +{ + m_output = 0; +} + + +//------------------------------------------------- +// sound_stream_update - handle update requests +// for our sound stream +//------------------------------------------------- + +void dac_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + // just fill with current value + for (int samp = 0; samp < samples; samp++) + outputs[0][samp] = m_output; +} diff --git a/src/devices/sound/dac.h b/src/devices/sound/dac.h new file mode 100644 index 00000000000..fadc1a7e324 --- /dev/null +++ b/src/devices/sound/dac.h @@ -0,0 +1,70 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + dac.h + + DAC device emulator. + +***************************************************************************/ + +#ifndef __DAC_H__ +#define __DAC_H__ + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_DAC_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, DAC, 0) + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + + +// ======================> dac_device + +class dac_device : public device_t, + public device_sound_interface +{ + // default to 4x oversampling + static const UINT32 DEFAULT_SAMPLE_RATE = 48000 * 4; + +public: + // construction/destruction + dac_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // public interface + INT16 output() const { return m_output; } + void write(INT16 data) { m_stream->update(); m_output = data; } + void write_unsigned8(UINT8 data) { write(data * 32767 / 255); } // 0..255, mapped to 0..32767 + void write_signed8(UINT8 data) { write((data - 0x80) * 32767 / 128); } // 0..255, mapped to -32767..32767 + void write_unsigned16(UINT16 data) { write(data / 2); } // 0..65535, mapped to 0..32767 + void write_signed16(UINT16 data) { write(data - 0x8000); } // 0..65535, mapped to -32768..32767 + + // wrappers + DECLARE_WRITE8_MEMBER( write_unsigned8 ); + DECLARE_WRITE8_MEMBER( write_signed8 ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_sound_interface overrides + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + + // internal state + sound_stream * m_stream; + INT16 m_output; +}; + + +// device type definition +extern const device_type DAC; + + +#endif /* __DAC_H__ */ diff --git a/src/devices/sound/digitalk.c b/src/devices/sound/digitalk.c new file mode 100644 index 00000000000..dcd0a965408 --- /dev/null +++ b/src/devices/sound/digitalk.c @@ -0,0 +1,692 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +#include "emu.h" +#include "digitalk.h" + +/* + National Semiconductor's Digitalker, also known as MM54104. + +This is a sample decompression chip where the codec is very +specialized for speech. + + - Driver history + +The history of this driver is a little strange. The real +reverse-engineering work has been done by Kevin Horton +(single-stepping the chip and everything) with assistance by Lord +Nightmare who had done the work (with help from Mr. Horton) on the tsi +s14001a, a predecessor of the digitalker. Mr. Horton was not +interested in publishing his findings, but provided full-rate +resynthesized samples for the game scorpion. This driver is the +result of analyzing these samples. + + + - The Chip + +Pinout from chipdir, added there by Agustin Yado. Added rompwr. +Package is DIP40. Standard osc is 4MHz, maximum is 5Mhz. + + +--()--+ + osc in | 1 40| vdd + osc out | 2 39| speech out + cs | 3 38| adr 13 + wr | 4 37| adr 12 + rompwr | 5 36| adr 11 + intr | 6 35| adr 10 + cms | 7 34| adr 9 + d0 | 8 33| adr 8 + d1 | 9 32| adr 7 + d2 |10 31| adr 6 + d3 |11 30| adr 5 + d4 |12 29| adr 4 + d5 |13 28| adr 3 + d6 |14 27| adr 2 + d7 |15 26| adr 1 + rdata 0 |16 25| adr 0 + rdata 1 |17 24| rdata 7 + rdata 2 |18 23| rdata 6 + rdata 3 |19 22| rdata 5 + vss |20 21| rdata 4 + +------+ + +Pin functions, excerpt from +http://www.ski.org/Rehab/sktf/vol06no1Winter1985.html, slightly modified +"Smith-Kettlewell Technical File, Vol 6, No 1, winter 1985" + + On the controller chip, pin 40 is VCC, while pin 20 is ground. VCC + for this chip is between 7 and 11 VDC, and pin 40 is bypassed to + pin 20 by 0.1uF. Maximum current is listed at 45mA. + + Pin 3 is called "Chip Select Not," and can be taken high to "open" + the input address and control lines. This is used in cases where + the Digitalker is connected to a computer bus, and the address + lines need to be floated while the bus is doing something else. In + other words, taking pin 3 high makes the Digitalker turn a deaf + ear to all of its inputs. + + Pin 4 is "Write Not," and, as mentioned before, is brought low to + load an address into the controller, then brought high again to + start speech. In other words, this is the pin by which you + "trigger" the Digitalker. + + Pin 5 is "Not ROM-Power Enable," an output which can be used to + control the power to the ROM's. This is used in cases of battery + supply where current drain is important; the ROM's will have their + power controlled by the controller. + + Pin 6 is the "Interrupt Output," (equivalent to the "Busy Line" of + the old TSI Speech Board); this line goes low when an address is + loaded into the chip, then goes high again when speech is + finished. This signal can be used to control the driver circuitry + (or other controlling device), in which case it tells the driver + to "Hold the phone!" while the speech is running. Pin 7 is called + "CMS," and its state controls the action of the "Write Not" + line. With pin 7 low, the operation of pin 4 is as described. If + pin 7 is brought high, raising pin 4 high after loading an address + serves only to reset the interrupt and does not start speech. This + facility is probably intended for use where the interrupt line + really controls the hardware interrupt of a computer, and where + the program taking care of the interrupt may not have another word + to say every time the Digitalker is finished. I have found no + particular use for pin 7, and I simply ground it for normal + operation. + + Pins 8 through 15 are the eight input address lines, with pin 8 + being the most significant BIT and pin 15 being least + significant. These address lines are "active high." They should + never be left open. They are TTL-compatible; this means that logic + low is ground and logic high is plus 5VDC. (Actually, being MOS + inputs, you can take them as high as the VCC on the controller, + but a 5V supply is required for the ROM's anyhow -- it's there if + you want to use 5V.) + + Pins 16 through 24 are the eight data lines which bring data from + the ROMs to the controller, with pin 16 being called "ROM Data + 1," and pin 24 being "ROM Data 8." + + Pins 25 through 38 are the fourteen address lines which select + location in the ROM's to be read by the controller. Pin 25 is + "Address 0," pin 38 is "Address 13." + + + - Codec + +The codec stems from the standard model for voiced speech generation: +a stream of impulses at the pitch frequency followed by an +articulation filter. Both of those are considered slowly varying. + + pitch filter voiced sound + |||||||||| * /\/\ = ~~~~ + +The first compression effect is by forcing the filter to be +zero-phase. That makes the periods perfectly symmetrical around the +pitch pulse. The voiced speech is as a result extracted as a number +of symmetric periods, centered on the pitch pulses. + +Following that, two quantizations are done. First, the pitch +frequency is quantized to one of 32 values (see pitch_vals), going +from ~80 to 200Hz. Then the volume is selected among 8 possible +values in an exponential scale, and the amplitudes are quantized as a +4-bit signed value. The period is time-warped to make it exactly 128 +samples long. + +The next step of the compression is to select which harnomics will be +kept. The choices are to keep only the even ones or only the odd +ones. Dropping half the harmonics allow to encode the period in only +32 samples, using the fact that a period, for a zero-phase-at-center, +half-harmonics signal, looks like: + + even harmonics: /\/\ odd harmonics: _/\_ + +Where / = block of 32 samples + \ = same block reversed + _ = 32 zeroes + +So we're left with 32 4-bit samples to encode, which is done using a +2-bit adpcm. The adaptative part is done by using a fixed 16-deltas +table indexed by the current and the previous encoded value. + +Added to all that is the possibility of repeating such a period while +increasing or decreasing the pitch frequency. + + +For non-voiced speech or non-speech an alternative mode is available +where an equivalent period cutting, frequency and amplitude +quantization is done, but the whole 128 samples are adpcm-encoded. + + +Finally, silent zones are compressed specifically by storing their +lenghts. + + +Decoding is simpler. The 128-samples waveform is decoded using the +adpcm data and mirroring/zeroing as needed in the voiced case. The +pitch is taken into account by modulating a 1MHz (clock/4) signal at +the pitch frequency multiplied by 128. pitch_vals in is practice this +modulation interval, hence its 128us base unit to compute the pitch +period. + + + - Rom organization + +The rom starts with a vector of 16-bits big endian values which are +the addresses of the segments table for the samples. The segments data +is a vector of 24-bits little-endian values organized as such: + + adr+2 adr+1 adr + MMAAAAAA AAAAAAAA ERRRSSSS + + M: Segment base waveforms compression mode (0-3) + A: Segment base waveforms data address (0-16383) + R: Repeat count (1-8) + S: Number of waveforms (1-16) + E: Last segment of the sample (flag) + +Decoding stops after having decoded a segment with the E bit set. A +final 8.192ms silence is systematically added. + +A == 0 means silence. Duration is 5.12ms*(R+1)*(S+1), or in other +terms a full decode of all-zero waveforms at maximal pitch frequency +(pitch code 31). + + +A != 0 means sound. The sound data starts at that offset. The +encoding method is selected with M: + + 0: odd-harmonics voiced mode + 2: even-harmonics voiced mode + 3: unvoiced/non-speech mode + +Mode 1 is not supported because it is not present in the available +samples, hence unknown. + + + Voiced mode (9 bytes/waveform): + + VVVPPPPP AAAAAAAAx8 - First waveform + VVVDCCCC AAAAAAAAx8 - Following waveforms + +V: Volume (first index in pcm_levels) +P: Pitch index +A: adpcm data +D: Pitch index change direction (0=increase, 1=decrease) +C: Pitch index maximum change + +The waveforms are encoded with a 2-bit adpcm, lowest pair of bits +first. Deltas are a size-16 vector, indexed with the previous adpcm +value in bits 0&1 and the current in bits 2&3. Voiced speech modes +use table delta1 and initial "previous" value 2. + +Each waveform is repeated R times at volume V. First waveform has +fixed pitch P. Subsequent waveforms change the pitch index by 1 every +repeat (including the first) up to a change of C. D indicates whether +it's an increment or a decrement. + + + Unvoiced mode (33 bytes/waveform): + + VVVPPPPP AAAAAAAAx32 - All waveforms + +V: Volume (first index in pcm_levels) +P: Pitch index +A: adpcm data + +Adpcm encoding is identical but using delta2 table and an initial +value of 1. Every waveform is played consecutively and the adpcm +previous value or dac level is not reset between waveforms. The +complete set of waveforms is repeated R times. + +*/ + +// Quantized intensity values, first index is the volume, second the +// intensity (positive half only, real value goes -8..7) +static const short pcm_levels[8][8] = { + { 473, 945, 1418, 1890, 2363, 2835, 3308, 3781 }, + { 655, 1310, 1966, 2621, 3276, 3931, 4586, 5242 }, + { 925, 1851, 2776, 3702, 4627, 5553, 6478, 7404 }, + { 1249, 2498, 3747, 4996, 6245, 7494, 8743, 9992 }, + { 1638, 3276, 4914, 6552, 8190, 9828, 11466, 13104 }, + { 2252, 4504, 6757, 9009, 11261, 13514, 15766, 18018 }, + { 2989, 5979, 8968, 11957, 14947, 17936, 20925, 23915 }, + { 4095, 8190, 12285, 16380, 20475, 24570, 28665, 32760 }, +}; + +static const int delta1[16] = { -4, -4, -1, -1, -2, -2, 0, 0, 0, 0, 2, 2, 1, 1, 4, 4 }; +static const int delta2[16] = { 0, -1, -2, -3, 1, 0, -1, -2, 2, 1, 0, -1, 3, 2, 1, 0 }; + +// Frequency quantizations, values are in units of 128us. +static const int pitch_vals[32] = { + 97, 95, 92, 89, 87, 84, 82, 80, 77, 75, 73, 71, 69, 67, 65, 63, + 61, 60, 58, 56, 55, 53, 52, 50, 49, 48, 46, 45, 43, 42, 41, 40 +}; + + +const device_type DIGITALKER = &device_creator; + +digitalker_device::digitalker_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, DIGITALKER, "Digitalker", tag, owner, clock, "digitalker", __FILE__), + device_sound_interface(mconfig, *this), + m_rom(NULL), + m_stream(NULL), + m_data(0), + m_cs(0), + m_cms(0), + m_wr(0), + m_intr(0), + m_bpos(0), + m_apos(0), + m_mode(0), + m_cur_segment(0), + m_cur_repeat(0), + m_segments(0), + m_repeats(0), + m_prev_pitch(0), + m_pitch(0), + m_pitch_pos(0), + m_stop_after(0), + m_cur_dac(0), + m_cur_bits(0), + m_zero_count(0), + m_dac_index(0) +{ +} + + +void digitalker_device::digitalker_write(UINT8 *adr, UINT8 vol, INT8 dac) +{ + INT16 v; + dac &= 15; + if(dac >= 9) + v = -pcm_levels[vol][15-dac]; + else if(dac) + v = pcm_levels[vol][dac-1]; + else + v = 0; + m_dac[(*adr)++] = v; +} + +UINT8 digitalker_device::digitalker_pitch_next(UINT8 val, UINT8 prev, int step) +{ + int delta, nv; + + delta = val & 0xf; + if(delta > step + 1) + delta = step + 1; + if(val & 0x10) + delta = -delta; + + nv = prev + delta; + if(nv < 0) + nv = 0; + else if(nv > 31) + nv = 31; + return nv; +} + +void digitalker_device::digitalker_set_intr(UINT8 intr) +{ + m_intr = intr; +} + +void digitalker_device::digitalker_start_command(UINT8 cmd) +{ + m_bpos = ((m_rom[cmd*2] << 8) | m_rom[cmd*2+1]) & 0x3fff; + m_cur_segment = m_segments = m_cur_repeat = m_repeats = 0; + m_dac_index = 128; + m_zero_count = 0; + digitalker_set_intr(0); +} + +void digitalker_device::digitalker_step_mode_0() +{ + INT8 dac = 0; + int i, k, l; + UINT8 wpos = 0; + UINT8 h = m_rom[m_apos]; + UINT16 bits = 0x80; + UINT8 vol = h >> 5; + UINT8 pitch_id = m_cur_segment ? digitalker_pitch_next(h, m_prev_pitch, m_cur_repeat) : h & 0x1f; + + m_pitch = pitch_vals[pitch_id]; + + for(i=0; i<32; i++) + m_dac[wpos++] = 0; + + for(k=1; k != 9; k++) { + bits |= m_rom[m_apos+k] << 8; + for(l=0; l<4; l++) { + dac += delta1[(bits >> (6+2*l)) & 15]; + digitalker_write(&wpos, vol, dac); + } + bits >>= 8; + } + + digitalker_write(&wpos, vol, dac); + + for(k=7; k >= 0; k--) { + bits = (bits << 8) | (k ? m_rom[m_apos+k] : 0x80); + for(l=3; l>=0; l--) { + dac -= delta1[(bits >> (6+2*l)) & 15]; + digitalker_write(&wpos, vol, dac); + } + } + + for(i=0; i<31; i++) + m_dac[wpos++] = 0; + + m_cur_repeat++; + if(m_cur_repeat == m_repeats) { + m_apos += 9; + m_prev_pitch = pitch_id; + m_cur_repeat = 0; + m_cur_segment++; + } +} + +void digitalker_device::digitalker_step_mode_1() +{ + logerror("Digitalker mode 1 unsupported\n"); + m_zero_count = 1; + m_cur_segment = m_segments; +} + +void digitalker_device::digitalker_step_mode_2() +{ + INT8 dac = 0; + int k, l; + UINT8 wpos=0; + UINT8 h = m_rom[m_apos]; + UINT16 bits = 0x80; + UINT8 vol = h >> 5; + UINT8 pitch_id = m_cur_segment ? digitalker_pitch_next(h, m_prev_pitch, m_cur_repeat) : h & 0x1f; + + m_pitch = pitch_vals[pitch_id]; + + for(k=1; k != 9; k++) { + bits |= m_rom[m_apos+k] << 8; + for(l=0; l<4; l++) { + dac += delta1[(bits >> (6+2*l)) & 15]; + digitalker_write(&wpos, vol, dac); + } + bits >>= 8; + } + + digitalker_write(&wpos, vol, dac); + + for(k=7; k >= 0; k--) { + int limit = k ? 0 : 1; + bits = (bits << 8) | (k ? m_rom[m_apos+k] : 0x80); + for(l=3; l>=limit; l--) { + dac -= delta1[(bits >> (6+2*l)) & 15]; + digitalker_write(&wpos, vol, dac); + } + } + + digitalker_write(&wpos, vol, dac); + + for(k=1; k != 9; k++) { + int start = k == 1 ? 1 : 0; + bits |= m_rom[m_apos+k] << 8; + for(l=start; l<4; l++) { + dac += delta1[(bits >> (6+2*l)) & 15]; + digitalker_write(&wpos, vol, dac); + } + bits >>= 8; + } + + digitalker_write(&wpos, vol, dac); + + for(k=7; k >= 0; k--) { + int limit = k ? 0 : 1; + bits = (bits << 8) | (k ? m_rom[m_apos+k] : 0x80); + for(l=3; l>=limit; l--) { + dac -= delta1[(bits >> (6+2*l)) & 15]; + digitalker_write(&wpos, vol, dac); + } + } + + m_cur_repeat++; + if(m_cur_repeat == m_repeats) { + m_apos += 9; + m_prev_pitch = pitch_id; + m_cur_repeat = 0; + m_cur_segment++; + } +} + +void digitalker_device::digitalker_step_mode_3() +{ + UINT8 h = m_rom[m_apos]; + UINT8 vol = h >> 5; + UINT16 bits; + UINT8 dac, apos, wpos; + int k, l; + + m_pitch = pitch_vals[h & 0x1f]; + if(m_cur_segment == 0 && m_cur_repeat == 0) { + m_cur_bits = 0x40; + m_cur_dac = 0; + } + bits = m_cur_bits; + dac = 0; + + apos = m_apos + 1 + 32*m_cur_segment; + wpos = 0; + for(k=0; k != 32; k++) { + bits |= m_rom[apos++] << 8; + for(l=0; l<4; l++) { + dac += delta2[(bits >> (6+2*l)) & 15]; + digitalker_write(&wpos, vol, dac); + } + bits >>= 8; + } + + m_cur_bits = bits; + m_cur_dac = dac; + + m_cur_segment++; + if(m_cur_segment == m_segments) { + m_cur_segment = 0; + m_cur_repeat++; + } +} + +void digitalker_device::digitalker_step() +{ + if(m_cur_segment == m_segments || m_cur_repeat == m_repeats) { + if(m_stop_after == 0 && m_bpos == 0xffff) + return; + if(m_stop_after == 0) { + UINT8 v1 = m_rom[m_bpos++]; + UINT8 v2 = m_rom[m_bpos++]; + UINT8 v3 = m_rom[m_bpos++]; + m_apos = v2 | ((v3 << 8) & 0x3f00); + m_segments = (v1 & 15) + 1; + m_repeats = ((v1 >> 4) & 7) + 1; + m_mode = (v3 >> 6) & 3; + m_stop_after = (v1 & 0x80) != 0; + + m_cur_segment = 0; + m_cur_repeat = 0; + + if(!m_apos) { + m_zero_count = 40*128*m_segments*m_repeats; + m_segments = 0; + m_repeats = 0; + return; + } + } else if(m_stop_after == 1) { + m_bpos = 0xffff; + m_zero_count = 81920; + m_stop_after = 2; + m_cur_segment = 0; + m_cur_repeat = 0; + m_segments = 0; + m_repeats = 0; + } else { + m_stop_after = 0; + digitalker_set_intr(1); + } + } + + switch(m_mode) { + case 0: digitalker_step_mode_0(); break; + case 1: digitalker_step_mode_1(); break; + case 2: digitalker_step_mode_2(); break; + case 3: digitalker_step_mode_3(); break; + } + if(!m_zero_count) + m_dac_index = 0; +} + + +//------------------------------------------------- +// sound_stream_update - handle a stream update +//------------------------------------------------- + +void digitalker_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + stream_sample_t *sout = outputs[0]; + int cpos = 0; + while(cpos != samples) { + if(m_zero_count == 0 && m_dac_index == 128) + digitalker_step(); + + if(m_zero_count) { + int n = samples - cpos; + int i; + if(n > m_zero_count) + n = m_zero_count; + for(i=0; i != n; i++) + sout[cpos++] = 0; + m_zero_count -= n; + + } else if(m_dac_index != 128) { + while(cpos != samples && m_dac_index != 128) { + short v = m_dac[m_dac_index]; + int pp = m_pitch_pos; + while(cpos != samples && pp != m_pitch) { + sout[cpos++] = v; + pp++; + } + if(pp == m_pitch) { + pp = 0; + m_dac_index++; + } + m_pitch_pos = pp; + } + + } else { + while(cpos != samples) + sout[cpos++] = 0; + } + } +} + +void digitalker_device::digitalker_cs_w(int line) +{ + UINT8 cs = line == ASSERT_LINE ? 1 : 0; + if(cs == m_cs) + return; + m_cs = cs; + if(cs) + return; + if(!m_wr) { + if(m_cms) + digitalker_set_intr(1); + else + digitalker_start_command(m_data); + } +} + +void digitalker_device::digitalker_cms_w(int line) +{ + m_cms = line == ASSERT_LINE ? 1 : 0; +} + +void digitalker_device::digitalker_wr_w(int line) +{ + UINT8 wr = line == ASSERT_LINE ? 1 : 0; + if(wr == m_wr) + return; + m_wr = wr; + if(wr || m_cs) + return; + if(m_cms) + digitalker_set_intr(1); + else + digitalker_start_command(m_data); +} + +int digitalker_device::digitalker_intr_r() +{ + return m_intr ? ASSERT_LINE : CLEAR_LINE; +} + +void digitalker_device::digitalker_register_for_save() +{ + save_item(NAME(m_data)); + save_item(NAME(m_cs)); + save_item(NAME(m_cms)); + save_item(NAME(m_wr)); + save_item(NAME(m_intr)); + save_item(NAME(m_bpos)); + save_item(NAME(m_apos)); + save_item(NAME(m_mode)); + save_item(NAME(m_cur_segment)); + save_item(NAME(m_cur_repeat)); + save_item(NAME(m_segments)); + save_item(NAME(m_repeats)); + save_item(NAME(m_prev_pitch)); + save_item(NAME(m_pitch)); + save_item(NAME(m_pitch_pos)); + save_item(NAME(m_stop_after)); + save_item(NAME(m_cur_dac)); + save_item(NAME(m_cur_bits)); + save_item(NAME(m_zero_count)); + save_item(NAME(m_dac_index)); + save_item(NAME(m_dac)); +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void digitalker_device::device_start() +{ + m_rom = m_region->base(); + m_stream = stream_alloc(0, 1, clock()/4); + m_dac_index = 128; + m_data = 0xff; + m_cs = m_cms = m_wr = 1; + m_bpos = 0xffff; + digitalker_set_intr(1); + + digitalker_register_for_save(); +} + +void digitalker_device::digitalker_0_cs_w(int line) +{ + digitalker_cs_w(line); +} + +void digitalker_device::digitalker_0_cms_w(int line) +{ + digitalker_cms_w(line); +} + +void digitalker_device::digitalker_0_wr_w(int line) +{ + digitalker_wr_w(line); +} + +int digitalker_device::digitalker_0_intr_r() +{ + return digitalker_intr_r(); +} + +WRITE8_MEMBER( digitalker_device::digitalker_data_w ) +{ + m_data = data; +} diff --git a/src/devices/sound/digitalk.h b/src/devices/sound/digitalk.h new file mode 100644 index 00000000000..fc2dd497f09 --- /dev/null +++ b/src/devices/sound/digitalk.h @@ -0,0 +1,101 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +#ifndef _DIGITALKER_H_ +#define _DIGITALKER_H_ + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_DIGITALKER_ADD(_tag, _clock) \ + MCFG_DEVICE_ADD(_tag, DIGITALKER, _clock) +#define MCFG_DIGITALKER_REPLACE(_tag, _clock) \ + MCFG_DEVICE_REPLACE(_tag, DIGITALKER, _clock) + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> digitalker_device + +class digitalker_device : public device_t, + public device_sound_interface +{ +public: + digitalker_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + ~digitalker_device() { } + + void digitalker_0_cs_w(int line); + void digitalker_0_cms_w(int line); + void digitalker_0_wr_w(int line); + int digitalker_0_intr_r(); + +protected: + // device-level overrides + virtual void device_start(); + + // sound stream update overrides + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + +public: + DECLARE_WRITE8_MEMBER(digitalker_data_w); + +private: + void digitalker_write(UINT8 *adr, UINT8 vol, INT8 dac); + UINT8 digitalker_pitch_next(UINT8 val, UINT8 prev, int step); + void digitalker_set_intr(UINT8 intr); + void digitalker_start_command(UINT8 cmd); + void digitalker_step_mode_0(); + void digitalker_step_mode_1(); + void digitalker_step_mode_2(); + void digitalker_step_mode_3(); + void digitalker_step(); + void digitalker_cs_w(int line); + void digitalker_cms_w(int line); + void digitalker_wr_w(int line); + int digitalker_intr_r(); + void digitalker_register_for_save(); + +private: + const UINT8 *m_rom; + sound_stream *m_stream; + + // Port/lines state + UINT8 m_data; + UINT8 m_cs; + UINT8 m_cms; + UINT8 m_wr; + UINT8 m_intr; + + // Current decoding state + UINT16 m_bpos; + UINT16 m_apos; + + UINT8 m_mode; + UINT8 m_cur_segment; + UINT8 m_cur_repeat; + UINT8 m_segments; + UINT8 m_repeats; + + UINT8 m_prev_pitch; + UINT8 m_pitch; + UINT8 m_pitch_pos; + + UINT8 m_stop_after; + UINT8 m_cur_dac; + UINT8 m_cur_bits; + + // Zero-range size + UINT32 m_zero_count; // 0 for done + + // Waveform and current index in it + UINT8 m_dac_index; // 128 for done + INT16 m_dac[128]; +}; + +extern const device_type DIGITALKER; + + +#endif diff --git a/src/devices/sound/disc_cls.h b/src/devices/sound/disc_cls.h new file mode 100644 index 00000000000..255b0958c15 --- /dev/null +++ b/src/devices/sound/disc_cls.h @@ -0,0 +1,258 @@ +// license:??? +// copyright-holders:K.Wilkins, Derrick Renaud, F.Palazzolo, Couriersud +#pragma once + +#ifndef __DISC_CLS_H__ +#define __DISC_CLS_H__ + +/*********************************************************************** + * + * MAME - Discrete sound system emulation library + * + * Written by K.Wilkins (mame@esplexo.co.uk) + * + * (c) K.Wilkins 2000 + * + * Coding started in November 2000 + * + * Additions/bugfix February 2003 - Derrick Renaud, F.Palazzolo, K.Wilkins + * Discrete parallel tasks 2009 - Couriersud + * Discrete classes 2010 - Couriersud + * + ***********************************************************************/ + +#define DISCRETE_CLASS_NAME(_name) discrete_ ## _name ## _node + +#define DISCRETE_CLASS_INPUT(_name, _num) inline double _name (void) { return *(m_input[_num]); } + +#define DISCRETE_CLASS_CONSTRUCTOR(_name, _base) \ + public: \ + DISCRETE_CLASS_NAME(_name)() \ + : DISCRETE_CLASS_NAME(_base)() { } + +#define DISCRETE_CLASS_DESTRUCTOR(_name) \ + public: \ + virtual ~ DISCRETE_CLASS_NAME(_name)(void) { } + +#define DISCRETE_CLASS_STEP_RESET(_name, _maxout, _priv) \ +class DISCRETE_CLASS_NAME(_name): public discrete_base_node, public discrete_step_interface \ +{ \ + DISCRETE_CLASS_CONSTRUCTOR(_name, base) \ + DISCRETE_CLASS_DESTRUCTOR(_name) \ +public: \ + void step(void); \ + void reset(void); \ + int max_output(void) { return _maxout; } \ +private: \ + _priv \ +} + +#define DISCRETE_CLASS_STEP(_name, _maxout, _priv) \ +class DISCRETE_CLASS_NAME(_name): public discrete_base_node, public discrete_step_interface \ +{ \ + DISCRETE_CLASS_CONSTRUCTOR(_name, base) \ + DISCRETE_CLASS_DESTRUCTOR(_name) \ +public: \ + void step(void); \ + void reset(void) { this->step(); } \ + int max_output(void) { return _maxout; } \ +private: \ + _priv \ +} + +#define DISCRETE_CLASS_RESET(_name, _maxout) \ +class DISCRETE_CLASS_NAME(_name): public discrete_base_node \ +{ \ + DISCRETE_CLASS_CONSTRUCTOR(_name, base) \ + DISCRETE_CLASS_DESTRUCTOR(_name) \ +public: \ + void reset(void); \ + int max_output(void) { return _maxout; } \ +} + +#define DISCRETE_CLASS(_name, _maxout, _priv) \ +class DISCRETE_CLASS_NAME(_name): public discrete_base_node, public discrete_step_interface \ +{ \ + DISCRETE_CLASS_DESTRUCTOR(_name) \ + DISCRETE_CLASS_CONSTRUCTOR(_name, base) \ +public: \ + void step(void); \ + void reset(void); \ + void start(void); \ + void stop(void); \ + int max_output(void) { return _maxout; } \ +private: \ + _priv \ +} + +class DISCRETE_CLASS_NAME(special): public discrete_base_node +{ + DISCRETE_CLASS_CONSTRUCTOR(special, base) + DISCRETE_CLASS_DESTRUCTOR(special) +public: + int max_output(void) { return 0; } +}; + +class DISCRETE_CLASS_NAME(unimplemented): public discrete_base_node +{ + DISCRETE_CLASS_CONSTRUCTOR(unimplemented, base) + DISCRETE_CLASS_DESTRUCTOR(unimplemented) +public: + int max_output(void) { return 0; } +}; + +/************************************* + * + * disc_sys.inc + * + *************************************/ + +class DISCRETE_CLASS_NAME(dso_output): public discrete_base_node, + public discrete_sound_output_interface, + public discrete_step_interface +{ + DISCRETE_CLASS_CONSTRUCTOR(dso_output, base) + DISCRETE_CLASS_DESTRUCTOR(dso_output) +public: + void step(void) { + /* Add gain to the output and put into the buffers */ + /* Clipping will be handled by the main sound system */ + double val = DISCRETE_INPUT(0) * DISCRETE_INPUT(1); + *m_ptr++ = val; + } + int max_output(void) { return 0; } + void set_output_ptr(stream_sample_t *ptr) { m_ptr = ptr; } +private: + stream_sample_t *m_ptr; +}; + +DISCRETE_CLASS(dso_csvlog, 0, + FILE *m_csv_file; + INT64 m_sample_num; + char m_name[32]; +); + +DISCRETE_CLASS(dso_wavlog, 0, + wav_file *m_wavfile; + char m_name[32]; +); + +/************************************* + * + * disc_inp.inc + * + *************************************/ + +class DISCRETE_CLASS_NAME(dss_adjustment): public discrete_base_node, public discrete_step_interface +{ + DISCRETE_CLASS_CONSTRUCTOR(dss_adjustment, base) + DISCRETE_CLASS_DESTRUCTOR(dss_adjustment) +public: + void step(void); + void reset(void); +private: + ioport_port *m_port; + INT32 m_lastpval; + INT32 m_pmin; + double m_pscale; + double m_min; + double m_scale; +}; + +DISCRETE_CLASS_RESET(dss_constant, 1); + +class DISCRETE_CLASS_NAME(dss_input_data): public discrete_base_node, public discrete_input_interface +{ + DISCRETE_CLASS_DESTRUCTOR(dss_input_data) + DISCRETE_CLASS_CONSTRUCTOR(dss_input_data, base) +public: + void reset(void); + void input_write(int sub_node, UINT8 data ); +private: + double m_gain; /* node gain */ + double m_offset; /* node offset */ + UINT8 m_data; /* data written */ +}; + +class DISCRETE_CLASS_NAME(dss_input_logic): public discrete_base_node, public discrete_input_interface +{ + DISCRETE_CLASS_CONSTRUCTOR(dss_input_logic, base) + DISCRETE_CLASS_DESTRUCTOR(dss_input_logic) +public: + void reset(void); + void input_write(int sub_node, UINT8 data ); +private: + double m_gain; /* node gain */ + double m_offset; /* node offset */ + UINT8 m_data; /* data written */ +}; + +class DISCRETE_CLASS_NAME(dss_input_not): public discrete_base_node, public discrete_input_interface +{ + DISCRETE_CLASS_CONSTRUCTOR(dss_input_not, base) + DISCRETE_CLASS_DESTRUCTOR(dss_input_not) +public: + void reset(void); + void input_write(int sub_node, UINT8 data ); +private: + double m_gain; /* node gain */ + double m_offset; /* node offset */ + UINT8 m_data; /* data written */ +}; + +class DISCRETE_CLASS_NAME(dss_input_pulse): public discrete_base_node, public discrete_input_interface, public discrete_step_interface +{ + DISCRETE_CLASS_CONSTRUCTOR(dss_input_pulse, base) + DISCRETE_CLASS_DESTRUCTOR(dss_input_pulse) +public: + void step(void); + void reset(void); + void input_write(int sub_node, UINT8 data ); +private: + //double m_gain; /* node gain */ + //double m_offset; /* node offset */ + UINT8 m_data; /* data written */ +}; + +class DISCRETE_CLASS_NAME(dss_input_stream): public discrete_base_node, public discrete_input_interface, public discrete_step_interface +{ + DISCRETE_CLASS_CONSTRUCTOR(dss_input_stream, base) + DISCRETE_CLASS_DESTRUCTOR(dss_input_stream) +public: + void step(void); + void reset(void); + void start(void); + void input_write(int sub_node, UINT8 data ); + virtual bool is_buffered(void) { return false; } + + /* This is called by discrete_sound_device */ + void stream_start(void); + +//protected: + UINT32 m_stream_in_number; + stream_sample_t *m_ptr; /* current in ptr for stream */ +private: + void stream_generate(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + + double m_gain; /* node gain */ + double m_offset; /* node offset */ + UINT8 m_data; /* data written */ + UINT8 m_is_buffered; + /* the buffer stream */ + sound_stream *m_buffer_stream; +}; + +class DISCRETE_CLASS_NAME(dss_input_buffer): public DISCRETE_CLASS_NAME(dss_input_stream) +{ + DISCRETE_CLASS_CONSTRUCTOR(dss_input_buffer, dss_input_stream) + DISCRETE_CLASS_DESTRUCTOR(dss_input_buffer) +public: + bool is_buffered(void) { return true; } +}; + +#include "disc_wav.h" +#include "disc_mth.h" +#include "disc_flt.h" +#include "disc_dev.h" + +#endif /* __DISCRETE_H__ */ diff --git a/src/devices/sound/disc_dev.h b/src/devices/sound/disc_dev.h new file mode 100644 index 00000000000..80af62a3ae3 --- /dev/null +++ b/src/devices/sound/disc_dev.h @@ -0,0 +1,129 @@ +// license:BSD-3-Clause +// copyright-holders:K.Wilkins +#pragma once + +#ifndef __DISC_DEV_H__ +#define __DISC_DEV_H__ + +/*********************************************************************** + * + * MAME - Discrete sound system emulation library + * + * Written by K.Wilkins (mame@esplexo.co.uk) + * + * (c) K.Wilkins 2000 + * + * Coding started in November 2000 + * + * Additions/bugfix February 2003 - Derrick Renaud, F.Palazzolo, K.Wilkins + * Discrete parallel tasks 2009 - Couriersud + * Discrete classes 2010 - Couriersud + * + ***********************************************************************/ + +#include "discrete.h" + +DISCRETE_CLASS_STEP_RESET(dsd_555_astbl, 1, + int m_use_ctrlv; + int m_output_type; + int m_output_is_ac; + double m_ac_shift; /* DC shift needed to make waveform ac */ + int m_flip_flop; /* 555 flip/flop output state */ + double m_cap_voltage; /* voltage on cap */ + double m_threshold; + double m_trigger; + double m_v_out_high; /* Logic 1 voltage level */ + double m_v_charge; + const double * m_v_charge_node; /* point to output of node */ + int m_has_rc_nodes; + double m_exp_bleed; + double m_exp_charge; + double m_exp_discharge; + double m_t_rc_bleed; + double m_t_rc_charge; + double m_t_rc_discharge; + double m_last_r1; + double m_last_r2; + double m_last_c; +); + +DISCRETE_CLASS_STEP_RESET(dsd_555_mstbl, 1, + int m_trig_is_logic; + int m_trig_discharges_cap; + int m_output_type; + double m_ac_shift; /* DC shift needed to make waveform ac */ + int m_flip_flop; /* 555 flip/flop output state */ + int m_has_rc_nodes; + double m_exp_charge; + double m_cap_voltage; /* voltage on cap */ + double m_threshold; + double m_trigger; + double m_v_out_high; /* Logic 1 voltage level */ + double m_v_charge; +); + +DISCRETE_CLASS_STEP_RESET(dsd_555_cc, 1, + unsigned int m_type; /* type of 555cc circuit */ + int m_output_type; + int m_output_is_ac; + double m_ac_shift; /* DC shift needed to make waveform ac */ + int m_flip_flop; /* 555 flip/flop output state */ + double m_cap_voltage; /* voltage on cap */ + double m_threshold; + double m_trigger; + double m_v_out_high; /* Logic 1 voltage level */ + double m_v_cc_source; + int m_has_rc_nodes; + double m_exp_bleed; + double m_exp_charge; + double m_exp_discharge; + double m_exp_discharge_01; + double m_exp_discharge_no_i; + double m_t_rc_charge; + double m_t_rc_discharge; + double m_t_rc_discharge_01; + double m_t_rc_discharge_no_i; +); + +DISCRETE_CLASS_STEP_RESET(dsd_555_vco1, 1, + int m_ctrlv_is_node; + int m_output_type; + int m_output_is_ac; + double m_ac_shift; /* DC shift needed to make waveform ac */ + int m_flip_flop; /* flip/flop output state */ + double m_v_out_high; /* 555 high voltage */ + double m_threshold; /* falling threshold */ + double m_trigger; /* rising threshold */ + double m_i_charge; /* charge current */ + double m_i_discharge; /* discharge current */ + double m_cap_voltage; /* current capacitor voltage */ +); + +DISCRETE_CLASS_STEP_RESET(dsd_566, 1, + //unsigned int m_state[2]; /* keeps track of excess flip_flop changes during the current step */ + int m_flip_flop; /* 566 flip/flop output state */ + double m_cap_voltage; /* voltage on cap */ + double m_v_sqr_low; /* voltage for a squarewave at low */ + double m_v_sqr_high; /* voltage for a squarewave at high */ + double m_v_sqr_diff; + double m_threshold_low; /* falling threshold */ + double m_threshold_high; /* rising threshold */ + double m_ac_shift; /* used to fake AC */ + double m_v_osc_stable; + double m_v_osc_stop; + int m_fake_ac; + int m_out_type; +); + +DISCRETE_CLASS_STEP_RESET(dsd_ls624, 1, + double m_exponent; + double m_t_used; + double m_v_cap_freq_in; + double m_v_freq_scale; + double m_v_rng_scale; + int m_flip_flop; + int m_has_freq_in_cap; + int m_out_type; +); + +#endif /* __DISC_WAV_H__ */ diff --git a/src/devices/sound/disc_dev.inc b/src/devices/sound/disc_dev.inc new file mode 100644 index 00000000000..47026747cd1 --- /dev/null +++ b/src/devices/sound/disc_dev.inc @@ -0,0 +1,1776 @@ +// license:BSD-3-Clause +// copyright-holders:K.Wilkins +/************************************************************************ + * + * MAME - Discrete sound system emulation library + * + * Written by K.Wilkins (mame@esplexo.co.uk) + * + * (c) K.Wilkins 2000 + * (c) Derrick Renaud 2003-2004 + * + ************************************************************************ + * + * DSD_555_ASTBL - NE555 Simulation - Astable mode + * DSD_555_MSTBL - NE555 Simulation - Monostable mode + * DSD_555_CC - NE555 Constant Current VCO + * DSD_555_VCO1 - Op-Amp linear ramp based 555 VCO + * DSD_566 - NE566 Simulation + * DSD_LS624 - 74LS624/629 Simulation + * + ************************************************************************ + * + * You will notice that the code for a lot of these routines are similar. + * I tried to make a common charging routine, but there are too many + * minor differences that affect each module. + * + ************************************************************************/ + +#define DEFAULT_555_BLEED_R RES_M(10) + +/************************************************************************ + * + * DSD_555_ASTBL - - 555 Astable simulation + * + * input[0] - Reset value + * input[1] - R1 value + * input[2] - R2 value + * input[3] - C value + * input[4] - Control Voltage value + * + * also passed discrete_555_desc structure + * + * Jan 2004, D Renaud. + ************************************************************************/ +#define DSD_555_ASTBL__RESET (! DISCRETE_INPUT(0)) +#define DSD_555_ASTBL__R1 DISCRETE_INPUT(1) +#define DSD_555_ASTBL__R2 DISCRETE_INPUT(2) +#define DSD_555_ASTBL__C DISCRETE_INPUT(3) +#define DSD_555_ASTBL__CTRLV DISCRETE_INPUT(4) + +/* bit mask of the above RC inputs */ +#define DSD_555_ASTBL_RC_MASK 0x0e + +/* charge/discharge constants */ +#define DSD_555_ASTBL_T_RC_BLEED (DEFAULT_555_BLEED_R * DSD_555_ASTBL__C) +/* Use quick charge if specified. */ +#define DSD_555_ASTBL_T_RC_CHARGE ((DSD_555_ASTBL__R1 + ((info->options & DISC_555_ASTABLE_HAS_FAST_CHARGE_DIODE) ? 0 : DSD_555_ASTBL__R2)) * DSD_555_ASTBL__C) +#define DSD_555_ASTBL_T_RC_DISCHARGE (DSD_555_ASTBL__R2 * DSD_555_ASTBL__C) + +DISCRETE_STEP(dsd_555_astbl) +{ + DISCRETE_DECLARE_INFO(discrete_555_desc) + + int count_f = 0; + int count_r = 0; + double dt; /* change in time */ + double x_time = 0; /* time since change happened */ + double v_cap = m_cap_voltage; /* Current voltage on capacitor, before dt */ + double v_cap_next = 0; /* Voltage on capacitor, after dt */ + double v_charge, exponent = 0; + UINT8 flip_flop = m_flip_flop; + UINT8 update_exponent = 0; + double v_out = 0.0; + + /* put commonly used stuff in local variables for speed */ + double threshold = m_threshold; + double trigger = m_trigger; + + if(DSD_555_ASTBL__RESET) + { + /* We are in RESET */ + set_output(0, 0); + m_flip_flop = 1; + m_cap_voltage = 0; + return; + } + + /* Check: if the Control Voltage node is connected. */ + if (m_use_ctrlv) + { + /* If CV is less then .25V, the circuit will oscillate way out of range. + * So we will just ignore it when it happens. */ + if (DSD_555_ASTBL__CTRLV < .25) return; + /* If it is a node then calculate thresholds based on Control Voltage */ + threshold = DSD_555_ASTBL__CTRLV; + trigger = DSD_555_ASTBL__CTRLV / 2.0; + /* Since the thresholds may have changed we need to update the FF */ + if (v_cap >= threshold) + { + flip_flop = 0; + count_f++; + } + else + if (v_cap <= trigger) + { + flip_flop = 1; + count_r++; + } + } + + /* get the v_charge and update each step if it is a node */ + if (m_v_charge_node != NULL) + { + v_charge = *m_v_charge_node; + if (info->options & DISC_555_ASTABLE_HAS_FAST_CHARGE_DIODE) v_charge -= 0.5; + } + else + v_charge = m_v_charge; + + + /* Calculate future capacitor voltage. + * ref@ http://www.physics.rutgers.edu/ugrad/205/capacitance.html + * The formulas from the ref pages have been modified to reflect that we are stepping the change. + * dt = time of sample (1/sample frequency) + * VC = Voltage across capacitor + * VC' = Future voltage across capacitor + * Vc = Voltage change + * Vr = is the voltage across the resistor. For charging it is Vcc - VC. Discharging it is VC - 0. + * R = R1+R2 (for charging) R = R2 for discharging. + * Vc = Vr*(1-exp(-dt/(R*C))) + * VC' = VC + Vc (for charging) VC' = VC - Vc for discharging. + * + * We will also need to calculate the amount of time we overshoot the thresholds + * dt = amount of time we overshot + * Vc = voltage change overshoot + * dt = R*C(log(1/(1-(Vc/Vr)))) + */ + + dt = this->sample_time(); + + /* Sometimes a switching network is used to setup the capacitance. + * These may select no capacitor, causing oscillation to stop. + */ + if (DSD_555_ASTBL__C == 0) + { + flip_flop = 1; + /* The voltage goes high because the cap circuit is open. */ + v_cap_next = v_charge; + v_cap = v_charge; + m_cap_voltage = 0; + } + else + { + /* Update charge contstants and exponents if nodes changed */ + if (m_has_rc_nodes && (DSD_555_ASTBL__R1 != m_last_r1 || DSD_555_ASTBL__C != m_last_c || DSD_555_ASTBL__R2 != m_last_r2)) + { + m_t_rc_bleed = DSD_555_ASTBL_T_RC_BLEED; + m_t_rc_charge = DSD_555_ASTBL_T_RC_CHARGE; + m_t_rc_discharge = DSD_555_ASTBL_T_RC_DISCHARGE; + m_exp_bleed = RC_CHARGE_EXP(m_t_rc_bleed); + m_exp_charge = RC_CHARGE_EXP(m_t_rc_charge); + m_exp_discharge = RC_CHARGE_EXP(m_t_rc_discharge); + m_last_r1 = DSD_555_ASTBL__R1; + m_last_r2 = DSD_555_ASTBL__R2; + m_last_c = DSD_555_ASTBL__C; + } + /* Keep looping until all toggling in time sample is used up. */ + do + { + if (flip_flop) + { + if (DSD_555_ASTBL__R1 == 0) + { + /* Oscillation disabled because there is no longer any charge resistor. */ + /* Bleed the cap due to circuit losses. */ + if (update_exponent) + exponent = RC_CHARGE_EXP_DT(m_t_rc_bleed, dt); + else + exponent = m_exp_bleed; + v_cap_next = v_cap - (v_cap * exponent); + dt = 0; + } + else + { + /* Charging */ + if (update_exponent) + exponent = RC_CHARGE_EXP_DT(m_t_rc_charge, dt); + else + exponent = m_exp_charge; + v_cap_next = v_cap + ((v_charge - v_cap) * exponent); + dt = 0; + + /* has it charged past upper limit? */ + if (v_cap_next >= threshold) + { + /* calculate the overshoot time */ + dt = m_t_rc_charge * log(1.0 / (1.0 - ((v_cap_next - threshold) / (v_charge - v_cap)))); + x_time = dt; + v_cap_next = threshold; + flip_flop = 0; + count_f++; + update_exponent = 1; + } + } + } + else + { + /* Discharging */ + if(DSD_555_ASTBL__R2 != 0) + { + if (update_exponent) + exponent = RC_CHARGE_EXP_DT(m_t_rc_discharge, dt); + else + exponent = m_exp_discharge; + v_cap_next = v_cap - (v_cap * exponent); + dt = 0; + } + else + { + /* no discharge resistor so we immediately discharge */ + v_cap_next = trigger; + } + + /* has it discharged past lower limit? */ + if (v_cap_next <= trigger) + { + /* calculate the overshoot time */ + if (v_cap_next < trigger) + dt = m_t_rc_discharge * log(1.0 / (1.0 - ((trigger - v_cap_next) / v_cap))); + x_time = dt; + v_cap_next = trigger; + flip_flop = 1; + count_r++; + update_exponent = 1; + } + } + v_cap = v_cap_next; + } while(dt); + + m_cap_voltage = v_cap; + } + + /* Convert last switch time to a ratio */ + x_time = x_time / this->sample_time(); + + switch (m_output_type) + { + case DISC_555_OUT_SQW: + if (count_f + count_r >= 2) + /* force at least 1 toggle */ + v_out = m_flip_flop ? 0 : m_v_out_high; + else + v_out = flip_flop * m_v_out_high; + v_out += m_ac_shift; + break; + case DISC_555_OUT_CAP: + v_out = v_cap; + /* Fake it to AC if needed */ + if (m_output_is_ac) + v_out -= threshold * 3.0 /4.0; + break; + case DISC_555_OUT_ENERGY: + if (x_time == 0) x_time = 1.0; + v_out = m_v_out_high * (flip_flop ? x_time : (1.0 - x_time)); + v_out += m_ac_shift; + break; + case DISC_555_OUT_LOGIC_X: + v_out = flip_flop + x_time; + break; + case DISC_555_OUT_COUNT_F_X: + v_out = count_f ? count_f + x_time : count_f; + break; + case DISC_555_OUT_COUNT_R_X: + v_out = count_r ? count_r + x_time : count_r; + break; + case DISC_555_OUT_COUNT_F: + v_out = count_f; + break; + case DISC_555_OUT_COUNT_R: + v_out = count_r; + break; + } + set_output(0, v_out); + m_flip_flop = flip_flop; +} + +DISCRETE_RESET(dsd_555_astbl) +{ + DISCRETE_DECLARE_INFO(discrete_555_desc) + + m_use_ctrlv = (this->input_is_node() >> 4) & 1; + m_output_type = info->options & DISC_555_OUT_MASK; + + /* Use the defaults or supplied values. */ + m_v_out_high = (info->v_out_high == DEFAULT_555_HIGH) ? info->v_pos - 1.2 : info->v_out_high; + + /* setup v_charge or node */ + m_v_charge_node = m_device->node_output_ptr(info->v_charge); + if (m_v_charge_node == NULL) + { + m_v_charge = (info->v_charge == DEFAULT_555_CHARGE) ? info->v_pos : info->v_charge; + + if (info->options & DISC_555_ASTABLE_HAS_FAST_CHARGE_DIODE) m_v_charge -= 0.5; + } + + if ((DSD_555_ASTBL__CTRLV != -1) && !m_use_ctrlv) + { + /* Setup based on supplied Control Voltage static value */ + m_threshold = DSD_555_ASTBL__CTRLV; + m_trigger = DSD_555_ASTBL__CTRLV / 2.0; + } + else + { + /* Setup based on v_pos power source */ + m_threshold = info->v_pos * 2.0 / 3.0; + m_trigger = info->v_pos / 3.0; + } + + /* optimization if none of the values are nodes */ + m_has_rc_nodes = 0; + if (this->input_is_node() & DSD_555_ASTBL_RC_MASK) + m_has_rc_nodes = 1; + else + { + m_t_rc_bleed = DSD_555_ASTBL_T_RC_BLEED; + m_exp_bleed = RC_CHARGE_EXP(m_t_rc_bleed); + m_t_rc_charge = DSD_555_ASTBL_T_RC_CHARGE; + m_exp_charge = RC_CHARGE_EXP(m_t_rc_charge); + m_t_rc_discharge = DSD_555_ASTBL_T_RC_DISCHARGE; + m_exp_discharge = RC_CHARGE_EXP(m_t_rc_discharge); + } + + m_output_is_ac = info->options & DISC_555_OUT_AC; + /* Calculate DC shift needed to make squarewave waveform AC */ + m_ac_shift = m_output_is_ac ? -m_v_out_high / 2.0 : 0; + + m_flip_flop = 1; + m_cap_voltage = 0; + + /* Step to set the output */ + this->step(); +} + + +/************************************************************************ + * + * DSD_555_MSTBL - 555 Monostable simulation + * + * input[0] - Reset value + * input[1] - Trigger input + * input[2] - R2 value + * input[3] - C value + * + * also passed discrete_555_desc structure + * + * Oct 2004, D Renaud. + ************************************************************************/ +#define DSD_555_MSTBL__RESET (! DISCRETE_INPUT(0)) +#define DSD_555_MSTBL__TRIGGER DISCRETE_INPUT(1) +#define DSD_555_MSTBL__R DISCRETE_INPUT(2) +#define DSD_555_MSTBL__C DISCRETE_INPUT(3) + +/* bit mask of the above RC inputs */ +#define DSD_555_MSTBL_RC_MASK 0x0c + +DISCRETE_STEP(dsd_555_mstbl) +{ + DISCRETE_DECLARE_INFO(discrete_555_desc) + + double v_cap; /* Current voltage on capacitor, before dt */ + double x_time = 0; /* time since change happened */ + double dt, exponent; + double out = 0; + int trigger = 0; + int trigger_type; + int update_exponent = m_has_rc_nodes; + int flip_flop; + + if(UNEXPECTED(DSD_555_MSTBL__RESET)) + { + /* We are in RESET */ + set_output(0, 0); + m_flip_flop = 0; + m_cap_voltage = 0; + return; + } + + dt = this->sample_time(); + flip_flop = m_flip_flop; + trigger_type = info->options; + v_cap = m_cap_voltage; + + switch (trigger_type & DSD_555_TRIGGER_TYPE_MASK) + { + case DISC_555_TRIGGER_IS_LOGIC: + trigger = ((int)DSD_555_MSTBL__TRIGGER) ? 0 : 1; + if (UNEXPECTED(trigger)) + x_time = 1.0 - DSD_555_MSTBL__TRIGGER; + break; + case DISC_555_TRIGGER_IS_VOLTAGE: + trigger = (int)(DSD_555_MSTBL__TRIGGER < m_trigger); + break; + case DISC_555_TRIGGER_IS_COUNT: + trigger = (int)DSD_555_MSTBL__TRIGGER; + if (UNEXPECTED(trigger)) + x_time = DSD_555_MSTBL__TRIGGER - trigger; + break; + } + + if (UNEXPECTED(trigger && !flip_flop && x_time != 0)) + { + /* adjust sample to after trigger */ + update_exponent = 1; + dt *= x_time; + } + x_time = 0; + + if ((trigger_type & DISC_555_TRIGGER_DISCHARGES_CAP) && trigger) + m_cap_voltage = 0; + + /* Wait for trigger */ + if (UNEXPECTED(!flip_flop && trigger)) + { + flip_flop = 1; + m_flip_flop = 1; + } + + if (flip_flop) + { + /* Sometimes a switching network is used to setup the capacitance. + * These may select 'no' capacitor, causing oscillation to stop. + */ + if (UNEXPECTED(DSD_555_MSTBL__C == 0)) + { + /* The trigger voltage goes high because the cap circuit is open. + * and the cap discharges */ + v_cap = info->v_pos; /* needed for cap output type */ + m_cap_voltage = 0; + + if (!trigger) + { + flip_flop = 0; + m_flip_flop = 0; + } + } + else + { + /* Charging */ + double v_diff = m_v_charge - v_cap; + + if (UNEXPECTED(update_exponent)) + exponent = RC_CHARGE_EXP_DT(DSD_555_MSTBL__R * DSD_555_MSTBL__C, dt); + else + exponent = m_exp_charge; + v_cap += v_diff * exponent; + + /* Has it charged past upper limit? */ + /* If trigger is still enabled, then we keep charging, + * regardless of threshold. */ + if (UNEXPECTED((v_cap >= m_threshold) && !trigger)) + { + dt = DSD_555_MSTBL__R * DSD_555_MSTBL__C * log(1.0 / (1.0 - ((v_cap - m_threshold) / v_diff))); + x_time = 1.0 - dt / this->sample_time(); + v_cap = 0; + flip_flop = 0; + m_flip_flop = 0; + } + m_cap_voltage = v_cap; + } + } + + switch (m_output_type) + { + case DISC_555_OUT_SQW: + out = flip_flop * m_v_out_high - m_ac_shift; + break; + case DISC_555_OUT_CAP: + if (x_time > 0) + out = v_cap * x_time; + else + out = v_cap; + + out -= m_ac_shift; + break; + case DISC_555_OUT_ENERGY: + if (x_time > 0) + out = m_v_out_high * x_time; + else if (flip_flop) + out = m_v_out_high; + else + out = 0; + + out -= m_ac_shift; + break; + } + set_output(0, out); +} + +DISCRETE_RESET(dsd_555_mstbl) +{ + DISCRETE_DECLARE_INFO(discrete_555_desc) + + m_output_type = info->options & DISC_555_OUT_MASK; + if ((m_output_type == DISC_555_OUT_COUNT_F) || (m_output_type == DISC_555_OUT_COUNT_R)) + { + m_device->discrete_log("Invalid Output type in NODE_%d.\n", this->index()); + m_output_type = DISC_555_OUT_SQW; + } + + /* Use the defaults or supplied values. */ + m_v_out_high = (info->v_out_high == DEFAULT_555_HIGH) ? info->v_pos - 1.2 : info->v_out_high; + m_v_charge = (info->v_charge == DEFAULT_555_CHARGE) ? info->v_pos : info->v_charge; + + /* Setup based on v_pos power source */ + m_threshold = info->v_pos * 2.0 / 3.0; + m_trigger = info->v_pos / 3.0; + + /* Calculate DC shift needed to make waveform AC */ + if (info->options & DISC_555_OUT_AC) + { + if (m_output_type == DISC_555_OUT_CAP) + m_ac_shift = m_threshold * 3.0 /4.0; + else + m_ac_shift = m_v_out_high / 2.0; + } + else + m_ac_shift = 0; + + m_trig_is_logic = (info->options & DISC_555_TRIGGER_IS_VOLTAGE) ? 0: 1; + m_trig_discharges_cap = (info->options & DISC_555_TRIGGER_DISCHARGES_CAP) ? 1: 0; + + m_flip_flop = 0; + m_cap_voltage = 0; + + /* optimization if none of the values are nodes */ + m_has_rc_nodes = 0; + if (this->input_is_node() & DSD_555_MSTBL_RC_MASK) + m_has_rc_nodes = 1; + else + m_exp_charge = RC_CHARGE_EXP(DSD_555_MSTBL__R * DSD_555_MSTBL__C); + + set_output(0, 0); +} + + +/************************************************************************ + * + * DSD_555_CC - Usage of node_description values + * + * input[0] - Reset input value + * input[1] - Voltage input for Constant current source. + * input[2] - R value to set CC current. + * input[3] - C value + * input[4] - rBias value + * input[5] - rGnd value + * input[6] - rDischarge value + * + * also passed discrete_555_cc_desc structure + * + * Mar 2004, D Renaud. + ************************************************************************/ +#define DSD_555_CC__RESET (! DISCRETE_INPUT(0)) +#define DSD_555_CC__VIN DISCRETE_INPUT(1) +#define DSD_555_CC__R DISCRETE_INPUT(2) +#define DSD_555_CC__C DISCRETE_INPUT(3) +#define DSD_555_CC__RBIAS DISCRETE_INPUT(4) +#define DSD_555_CC__RGND DISCRETE_INPUT(5) +#define DSD_555_CC__RDIS DISCRETE_INPUT(6) + +/* bit mask of the above RC inputs not including DSD_555_CC__R */ +#define DSD_555_CC_RC_MASK 0x78 + +/* charge/discharge constants */ +#define DSD_555_CC_T_RC_BLEED (DEFAULT_555_BLEED_R * DSD_555_CC__C) +#define DSD_555_CC_T_RC_DISCHARGE_01 (DSD_555_CC__RDIS * DSD_555_CC__C) +#define DSD_555_CC_T_RC_DISCHARGE_NO_I (DSD_555_CC__RGND * DSD_555_CC__C) +#define DSD_555_CC_T_RC_CHARGE (r_charge * DSD_555_CC__C) +#define DSD_555_CC_T_RC_DISCHARGE (r_discharge * DSD_555_CC__C) + + +DISCRETE_STEP(dsd_555_cc) +{ + DISCRETE_DECLARE_INFO(discrete_555_cc_desc) + + int count_f = 0; + int count_r = 0; + double i; /* Charging current created by vIn */ + double r_charge = 0; /* Equivalent charging resistor */ + double r_discharge = 0; /* Equivalent discharging resistor */ + double vi = 0; /* Equivalent voltage from current source */ + double v_bias = 0; /* Equivalent voltage from bias voltage */ + double v = 0; /* Equivalent voltage total from current source and bias circuit if used */ + double dt; /* change in time */ + double x_time = 0; /* time since change happened */ + double t_rc ; /* RC time constant */ + double v_cap; /* Current voltage on capacitor, before dt */ + double v_cap_next = 0; /* Voltage on capacitor, after dt */ + double v_vcharge_limit; /* vIn and the junction voltage limit the max charging voltage from i */ + double r_temp; /* play thing */ + double exponent; + UINT8 update_exponent, update_t_rc; + UINT8 flip_flop = m_flip_flop; + + double v_out = 0; + + + if (UNEXPECTED(DSD_555_CC__RESET)) + { + /* We are in RESET */ + set_output(0, 0); + m_flip_flop = 1; + m_cap_voltage = 0; + return; + } + + dt = this->sample_time(); /* Change in time */ + v_cap = m_cap_voltage; /* Set to voltage before change */ + v_vcharge_limit = DSD_555_CC__VIN + info->v_cc_junction; /* the max v_cap can be and still be charged by i */ + /* Calculate charging current */ + i = (m_v_cc_source - v_vcharge_limit) / DSD_555_CC__R; + if ( i < 0) i = 0; + + if (info->options & DISCRETE_555_CC_TO_CAP) + { + vi = i * DSD_555_CC__RDIS; + } + else + { + switch (m_type) /* see dsd_555_cc_reset for descriptions */ + { + case 1: + r_discharge = DSD_555_CC__RDIS; + case 0: + break; + case 3: + r_discharge = RES_2_PARALLEL(DSD_555_CC__RDIS, DSD_555_CC__RGND); + case 2: + r_charge = DSD_555_CC__RGND; + vi = i * r_charge; + break; + case 4: + r_charge = DSD_555_CC__RBIAS; + vi = i * r_charge; + v_bias = info->v_pos; + break; + case 5: + r_charge = DSD_555_CC__RBIAS + DSD_555_CC__RDIS; + vi = i * DSD_555_CC__RBIAS; + v_bias = info->v_pos; + r_discharge = DSD_555_CC__RDIS; + break; + case 6: + r_charge = RES_2_PARALLEL(DSD_555_CC__RBIAS, DSD_555_CC__RGND); + vi = i * r_charge; + v_bias = info->v_pos * RES_VOLTAGE_DIVIDER(DSD_555_CC__RGND, DSD_555_CC__RBIAS); + break; + case 7: + r_temp = DSD_555_CC__RBIAS + DSD_555_CC__RDIS; + r_charge = RES_2_PARALLEL(r_temp, DSD_555_CC__RGND); + r_temp += DSD_555_CC__RGND; + r_temp = DSD_555_CC__RGND / r_temp; /* now has voltage divider ratio, not resistance */ + vi = i * DSD_555_CC__RBIAS * r_temp; + v_bias = info->v_pos * r_temp; + r_discharge = RES_2_PARALLEL(DSD_555_CC__RGND, DSD_555_CC__RDIS); + break; + } + } + + /* Keep looping until all toggling in time sample is used up. */ + update_t_rc = m_has_rc_nodes; + update_exponent = update_t_rc; + do + { + if (m_type <= 1) + { + /* Standard constant current charge */ + if (flip_flop) + { + if (i == 0) + { + /* No charging current, so we have to discharge the cap + * due to cap and circuit losses. + */ + if (update_exponent) + { + t_rc = DSD_555_CC_T_RC_BLEED; + exponent = RC_CHARGE_EXP_DT(t_rc, dt); + } + else + exponent = m_exp_bleed; + v_cap_next = v_cap - (v_cap * exponent); + dt = 0; + } + else + { + /* Charging */ + /* iC=C*dv/dt works out to dv=iC*dt/C */ + v_cap_next = v_cap + (i * dt / DSD_555_CC__C); + /* Yes, if the cap voltage has reached the max voltage it can, + * and the 555 threshold has not been reached, then oscillation stops. + * This is the way the actual electronics works. + * This is why you never play with the pots after being factory adjusted + * to work in the proper range. */ + if (v_cap_next > v_vcharge_limit) v_cap_next = v_vcharge_limit; + dt = 0; + + /* has it charged past upper limit? */ + if (v_cap_next >= m_threshold) + { + /* calculate the overshoot time */ + dt = DSD_555_CC__C * (v_cap_next - m_threshold) / i; + x_time = dt; + v_cap_next = m_threshold; + flip_flop = 0; + count_f++; + update_exponent = 1; + } + } + } + else if (DSD_555_CC__RDIS != 0) + { + /* Discharging */ + if (update_t_rc) + t_rc = DSD_555_CC_T_RC_DISCHARGE_01; + else + t_rc = m_t_rc_discharge_01; + if (update_exponent) + exponent = RC_CHARGE_EXP_DT(t_rc, dt); + else + exponent = m_exp_discharge_01; + + if (info->options & DISCRETE_555_CC_TO_CAP) + { + /* Asteroids - Special Case */ + /* Charging in discharge mode */ + /* If the cap voltage is past the current source charging limit + * then only the bias voltage will charge the cap. */ + v = (v_cap < v_vcharge_limit) ? vi : v_vcharge_limit; + v_cap_next = v_cap + ((v - v_cap) * exponent); + } + else + { + v_cap_next = v_cap - (v_cap * exponent); + } + + dt = 0; + /* has it discharged past lower limit? */ + if (v_cap_next <= m_trigger) + { + dt = t_rc * log(1.0 / (1.0 - ((m_trigger - v_cap_next) / v_cap))); + x_time = dt; + v_cap_next = m_trigger; + flip_flop = 1; + count_r++; + update_exponent = 1; + } + } + else /* Immediate discharge. No change in dt. */ + { + x_time = dt; + v_cap_next = m_trigger; + flip_flop = 1; + count_r++; + } + } + else + { + /* The constant current gets changed to a voltage due to a load resistor. */ + if (flip_flop) + { + if ((i == 0) && (DSD_555_CC__RBIAS == 0)) + { + /* No charging current, so we have to discharge the cap + * due to rGnd. + */ + if (update_t_rc) + t_rc = DSD_555_CC_T_RC_DISCHARGE_NO_I; + else + t_rc = m_t_rc_discharge_no_i; + if (update_exponent) + exponent = RC_CHARGE_EXP_DT(t_rc, dt); + else + exponent = m_exp_discharge_no_i; + + v_cap_next = v_cap - (v_cap * exponent); + dt = 0; + } + else + { + /* Charging */ + /* If the cap voltage is past the current source charging limit + * then only the bias voltage will charge the cap. */ + v = v_bias; + if (v_cap < v_vcharge_limit) v += vi; + else if (m_type <= 3) v = v_vcharge_limit; + + if (update_t_rc) + t_rc = DSD_555_CC_T_RC_CHARGE; + else + t_rc = m_t_rc_charge; + if (update_exponent) + exponent = RC_CHARGE_EXP_DT(t_rc, dt); + else + exponent = m_exp_charge; + + v_cap_next = v_cap + ((v - v_cap) * exponent); + dt = 0; + + /* has it charged past upper limit? */ + if (v_cap_next >= m_threshold) + { + /* calculate the overshoot time */ + dt = t_rc * log(1.0 / (1.0 - ((v_cap_next - m_threshold) / (v - v_cap)))); + x_time = dt; + v_cap_next = m_threshold; + flip_flop = 0; + count_f++; + update_exponent = 1; + } + } + } + else /* Discharging */ + if (r_discharge) + { + if (update_t_rc) + t_rc = DSD_555_CC_T_RC_DISCHARGE; + else + t_rc = m_t_rc_discharge; + if (update_exponent) + exponent = RC_CHARGE_EXP_DT(t_rc, dt); + else + exponent = m_exp_discharge; + + v_cap_next = v_cap - (v_cap * exponent); + dt = 0; + + /* has it discharged past lower limit? */ + if (v_cap_next <= m_trigger) + { + /* calculate the overshoot time */ + dt = t_rc * log(1.0 / (1.0 - ((m_trigger - v_cap_next) / v_cap))); + x_time = dt; + v_cap_next = m_trigger; + flip_flop = 1; + count_r++; + update_exponent = 1; + } + } + else /* Immediate discharge. No change in dt. */ + { + x_time = dt; + v_cap_next = m_trigger; + flip_flop = 1; + count_r++; + } + } + v_cap = v_cap_next; + } while(dt); + + m_cap_voltage = v_cap; + + /* Convert last switch time to a ratio */ + x_time = x_time / this->sample_time(); + + switch (m_output_type) + { + case DISC_555_OUT_SQW: + if (count_f + count_r >= 2) + /* force at least 1 toggle */ + v_out = m_flip_flop ? 0 : m_v_out_high; + else + v_out = flip_flop * m_v_out_high; + /* Fake it to AC if needed */ + v_out += m_ac_shift; + break; + case DISC_555_OUT_CAP: + v_out = v_cap + m_ac_shift; + break; + case DISC_555_OUT_ENERGY: + if (x_time == 0) x_time = 1.0; + v_out = m_v_out_high * (flip_flop ? x_time : (1.0 - x_time)); + v_out += m_ac_shift; + break; + case DISC_555_OUT_LOGIC_X: + v_out = flip_flop + x_time; + break; + case DISC_555_OUT_COUNT_F_X: + v_out = count_f ? count_f + x_time : count_f; + break; + case DISC_555_OUT_COUNT_R_X: + v_out = count_r ? count_r + x_time : count_r; + break; + case DISC_555_OUT_COUNT_F: + v_out = count_f; + break; + case DISC_555_OUT_COUNT_R: + v_out = count_r; + break; + } + set_output(0, v_out); + m_flip_flop = flip_flop; +} + +DISCRETE_RESET(dsd_555_cc) +{ + DISCRETE_DECLARE_INFO(discrete_555_cc_desc) + + double r_temp, r_discharge = 0, r_charge = 0; + + m_flip_flop = 1; + m_cap_voltage = 0; + + m_output_type = info->options & DISC_555_OUT_MASK; + + /* Use the defaults or supplied values. */ + m_v_out_high = (info->v_out_high == DEFAULT_555_HIGH) ? info->v_pos - 1.2 : info->v_out_high; + m_v_cc_source = (info->v_cc_source == DEFAULT_555_CC_SOURCE) ? info->v_pos : info->v_cc_source; + + /* Setup based on v_pos power source */ + m_threshold = info->v_pos * 2.0 / 3.0; + m_trigger = info->v_pos / 3.0; + + m_output_is_ac = info->options & DISC_555_OUT_AC; + /* Calculate DC shift needed to make squarewave waveform AC */ + m_ac_shift = m_output_is_ac ? -m_v_out_high / 2.0 : 0; + + /* There are 8 different types of basic oscillators + * depending on the resistors used. We will determine + * the type of circuit at reset, because the ciruit type + * is constant. See Below. + */ + m_type = (DSD_555_CC__RDIS > 0) | ((DSD_555_CC__RGND > 0) << 1) | ((DSD_555_CC__RBIAS > 0) << 2); + + /* optimization if none of the values are nodes */ + m_has_rc_nodes = 0; + if (this->input_is_node() & DSD_555_CC_RC_MASK) + m_has_rc_nodes = 1; + else + { + switch (m_type) /* see dsd_555_cc_reset for descriptions */ + { + case 1: + r_discharge = DSD_555_CC__RDIS; + case 0: + break; + case 3: + r_discharge = RES_2_PARALLEL(DSD_555_CC__RDIS, DSD_555_CC__RGND); + case 2: + r_charge = DSD_555_CC__RGND; + break; + case 4: + r_charge = DSD_555_CC__RBIAS; + break; + case 5: + r_charge = DSD_555_CC__RBIAS + DSD_555_CC__RDIS; + r_discharge = DSD_555_CC__RDIS; + break; + case 6: + r_charge = RES_2_PARALLEL(DSD_555_CC__RBIAS, DSD_555_CC__RGND); + break; + case 7: + r_temp = DSD_555_CC__RBIAS + DSD_555_CC__RDIS; + r_charge = RES_2_PARALLEL(r_temp, DSD_555_CC__RGND); + r_discharge = RES_2_PARALLEL(DSD_555_CC__RGND, DSD_555_CC__RDIS); + break; + } + + m_exp_bleed = RC_CHARGE_EXP(DSD_555_CC_T_RC_BLEED); + m_t_rc_discharge_01 = DSD_555_CC_T_RC_DISCHARGE_01; + m_exp_discharge_01 = RC_CHARGE_EXP(m_t_rc_discharge_01); + m_t_rc_discharge_no_i = DSD_555_CC_T_RC_DISCHARGE_NO_I; + m_exp_discharge_no_i = RC_CHARGE_EXP(m_t_rc_discharge_no_i); + m_t_rc_charge = DSD_555_CC_T_RC_CHARGE; + m_exp_charge = RC_CHARGE_EXP(m_t_rc_charge); + m_t_rc_discharge = DSD_555_CC_T_RC_DISCHARGE; + m_exp_discharge = RC_CHARGE_EXP(m_t_rc_discharge); + } + + /* Step to set the output */ + this->step(); + + /* + * TYPES: + * Note: These are equivalent circuits shown without the 555 circuitry. + * See the schematic in src\sound\discrete.h for full hookup info. + * + * DISCRETE_555_CC_TO_DISCHARGE_PIN + * When the CC source is connected to the discharge pin, it allows the + * circuit to charge when the 555 is in charge mode. But when in discharge + * mode, the CC source is grounded, disabling it's effect. + * + * [0] + * No resistors. Straight constant current charge of capacitor. + * When there is not any charge current, the cap will bleed off. + * Once the lower threshold(trigger) is reached, the output will + * go high but the cap will continue to discharge due to losses. + * .------+---> cap_voltage CHARGING: + * | | dv (change in voltage) compared to dt (change in time in seconds). + * .---. --- dv = i * dt / C; where i is current in amps and C is capacitance in farads. + * | i | --- C cap_voltage = cap_voltage + dv + * '---' | + * | | DISCHARGING: + * gnd gnd instantaneous + * + * [1] + * Same as type 1 but with rDischarge. rDischarge has no effect on the charge rate because + * of the constant current source i. + * When there is not any charge current, the cap will bleed off. + * Once the lower threshold(trigger) is reached, the output will + * go high but the cap will continue to discharge due to losses. + * .----ZZZ-----+---> cap_voltage CHARGING: + * | rDischarge | dv (change in voltage) compared to dt (change in time in seconds). + * .---. --- dv = i * dt / C; where i is current in amps and C is capacitance in farads. + * | i | --- C cap_voltage = cap_voltage + dv + * '---' | + * | | DISCHARGING: + * gnd gnd through rDischarge + * + * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + * !!!!! IMPORTANT NOTE ABOUT TYPES 3 - 7 !!!!! + * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + * + * From here on in all the circuits have either an rBias or rGnd resistor. + * This converts the constant current into a voltage source. + * So all the remaining circuit types will be converted to this circuit. + * When discharging, rBias is out of the equation because the 555 is grounding the circuit + * after that point. + * + * .------------. Rc Rc is the equivilent circuit resistance. + * | v |----ZZZZ---+---> cap_voltage v is the equivilent circuit voltage. + * | | | + * '------------' --- Then the standard RC charging formula applies. + * | --- C + * | | NOTE: All the following types are converted to Rc and v values. + * gnd gnd + * + * [2] + * When there is not any charge current, the cap will bleed off. + * Once the lower threshold(trigger) is reached, the output will + * go high but the cap will continue to discharge due to rGnd. + * .-------+------+------> cap_voltage CHARGING: + * | | | v = vi = i * rGnd + * .---. --- Z Rc = rGnd + * | i | --- C Z rGnd + * '---' | | DISCHARGING: + * | | | instantaneous + * gnd gnd gnd + * + * [3] + * When there is not any charge current, the cap will bleed off. + * Once the lower threshold(trigger) is reached, the output will + * go high but the cap will continue to discharge due to rGnd. + * .----ZZZ-----+------+------> cap_voltage CHARGING: + * | rDischarge | | v = vi = i * rGnd + * .---. --- Z Rc = rGnd + * | i | --- C Z rGnd + * '---' | | DISCHARGING: + * | | | through rDischarge || rGnd ( || means in parallel) + * gnd gnd gnd + * + * [4] + * .---ZZZ---+------------+-------------> cap_voltage CHARGING: + * | rBias | | Rc = rBias + * .-------. .---. --- vi = i * rBias + * | vBias | | i | --- C v = vBias + vi + * '-------' '---' | + * | | | DISCHARGING: + * gnd gnd gnd instantaneous + * + * [5] + * .---ZZZ---+----ZZZ-----+-------------> cap_voltage CHARGING: + * | rBias | rDischarge | Rc = rBias + rDischarge + * .-------. .---. --- vi = i * rBias + * | vBias | | i | --- C v = vBias + vi + * '-------' '---' | + * | | | DISCHARGING: + * gnd gnd gnd through rDischarge + * + * [6] + * .---ZZZ---+------------+------+------> cap_voltage CHARGING: + * | rBias | | | Rc = rBias || rGnd + * .-------. .---. --- Z vi = i * Rc + * | vBias | | i | --- C Z rGnd v = vBias * (rGnd / (rBias + rGnd)) + vi + * '-------' '---' | | + * | | | | DISCHARGING: + * gnd gnd gnd gnd instantaneous + * + * [7] + * .---ZZZ---+----ZZZ-----+------+------> cap_voltage CHARGING: + * | rBias | rDischarge | | Rc = (rBias + rDischarge) || rGnd + * .-------. .---. --- Z vi = i * rBias * (rGnd / (rBias + rDischarge + rGnd)) + * | vBias | | i | --- C Z rGnd v = vBias * (rGnd / (rBias + rDischarge + rGnd)) + vi + * '-------' '---' | | + * | | | | DISCHARGING: + * gnd gnd gnd gnd through rDischarge || rGnd + */ + + /* + * DISCRETE_555_CC_TO_CAP + * + * When the CC source is connected to the capacitor, it allows the + * current to charge the cap while it is in discharge mode, slowing the + * discharge. So in charge mode it charges linearly from the constant + * current cource. But when in discharge mode it behaves like circuit + * type 2 above. + * .-------+------+------> cap_voltage CHARGING: + * | | | dv = i * dt / C + * .---. --- Z cap_voltage = cap_voltage + dv + * | i | --- C Z rDischarge + * '---' | | DISCHARGING: + * | | | v = vi = i * rGnd + * gnd gnd discharge Rc = rDischarge + */ +} + + +/************************************************************************ + * + * DSD_555_VCO1 - Usage of node_description values + * + * input[0] - Reset input value + * input[1] - Modulation Voltage (Vin1) + * input[2] - Control Voltage (Vin2) + * + * also passed discrete_5555_vco1_desc structure + * + * Apr 2006, D Renaud. + ************************************************************************/ +#define DSD_555_VCO1__RESET DISCRETE_INPUT(0) /* reset active low */ +#define DSD_555_VCO1__VIN1 DISCRETE_INPUT(1) +#define DSD_555_VCO1__VIN2 DISCRETE_INPUT(2) + +DISCRETE_STEP(dsd_555_vco1) +{ + DISCRETE_DECLARE_INFO(discrete_555_vco1_desc) + + int count_f = 0; + int count_r = 0; + double dt; /* change in time */ + double x_time = 0; /* time since change happened */ + double v_cap; /* Current voltage on capacitor, before dt */ + double v_cap_next = 0; /* Voltage on capacitor, after dt */ + + double v_out = 0; + + dt = this->sample_time(); /* Change in time */ + v_cap = m_cap_voltage; + + /* Check: if the Control Voltage node is connected. */ + if (m_ctrlv_is_node && DSD_555_VCO1__RESET) /* reset active low */ + { + /* If CV is less then .25V, the circuit will oscillate way out of range. + * So we will just ignore it when it happens. */ + if (DSD_555_VCO1__VIN2 < .25) return; + /* If it is a node then calculate thresholds based on Control Voltage */ + m_threshold = DSD_555_VCO1__VIN2; + m_trigger = DSD_555_VCO1__VIN2 / 2.0; + /* Since the thresholds may have changed we need to update the FF */ + if (v_cap >= m_threshold) + { + x_time = dt; + m_flip_flop = 0; + count_f++; + } + else + if (v_cap <= m_trigger) + { + x_time = dt; + m_flip_flop = 1; + count_r++; + } + } + + /* Keep looping until all toggling in time sample is used up. */ + do + { + if (m_flip_flop) + { + /* if we are in reset then toggle f/f and discharge */ + if (!DSD_555_VCO1__RESET) /* reset active low */ + { + m_flip_flop = 0; + count_f++; + } + else + { + /* Charging */ + /* iC=C*dv/dt works out to dv=iC*dt/C */ + v_cap_next = v_cap + (m_i_charge * dt / info->c); + dt = 0; + + /* has it charged past upper limit? */ + if (v_cap_next >= m_threshold) + { + /* calculate the overshoot time */ + dt = info->c * (v_cap_next - m_threshold) / m_i_charge; + v_cap = m_threshold; + x_time = dt; + m_flip_flop = 0; + count_f++; + } + } + } + else + { + /* Discharging */ + /* iC=C*dv/dt works out to dv=iC*dt/C */ + v_cap_next = v_cap - (m_i_discharge * dt / info->c); + + /* if we are in reset, then the cap can discharge to 0 */ + if (!DSD_555_VCO1__RESET) /* reset active low */ + { + if (v_cap_next < 0) v_cap_next = 0; + dt = 0; + } + else + { + /* if we are out of reset and the cap voltage is less then + * the lower threshold, toggle f/f and start charging */ + if (v_cap <= m_trigger) + { + if (m_flip_flop == 0) + { + /* don't need to track x_time here */ + m_flip_flop = 1; + count_r++; + } + } + else + { + dt = 0; + /* has it discharged past lower limit? */ + if (v_cap_next <= m_trigger) + { + /* calculate the overshoot time */ + dt = info->c * (v_cap_next - m_trigger) / m_i_discharge; + v_cap = m_trigger; + x_time = dt; + m_flip_flop = 1; + count_r++; + } + } + } + } + } while(dt); + + m_cap_voltage = v_cap_next; + + /* Convert last switch time to a ratio. No x_time in reset. */ + x_time = x_time / this->sample_time(); + if (!DSD_555_VCO1__RESET) x_time = 0; + + switch (m_output_type) + { + case DISC_555_OUT_SQW: + v_out = m_flip_flop * m_v_out_high + m_ac_shift; + break; + case DISC_555_OUT_CAP: + v_out = v_cap_next; + /* Fake it to AC if needed */ + if (m_output_is_ac) + v_out -= m_threshold * 3.0 /4.0; + break; + case DISC_555_OUT_ENERGY: + if (x_time == 0) x_time = 1.0; + v_out = m_v_out_high * (m_flip_flop ? x_time : (1.0 - x_time)); + v_out += m_ac_shift; + break; + case DISC_555_OUT_LOGIC_X: + v_out = m_flip_flop + x_time; + break; + case DISC_555_OUT_COUNT_F_X: + v_out = count_f ? count_f + x_time : count_f; + break; + case DISC_555_OUT_COUNT_R_X: + v_out = count_r ? count_r + x_time : count_r; + break; + case DISC_555_OUT_COUNT_F: + v_out = count_f; + break; + case DISC_555_OUT_COUNT_R: + v_out = count_r; + break; + } + set_output(0, v_out); +} + +DISCRETE_RESET(dsd_555_vco1) +{ + DISCRETE_DECLARE_INFO(discrete_555_vco1_desc) + + double v_ratio_r3, v_ratio_r4_1, r_in_1; + + m_output_type = info->options & DISC_555_OUT_MASK; + m_output_is_ac = info->options & DISC_555_OUT_AC; + + /* Setup op-amp parameters */ + + /* The voltage at op-amp +in is always a fixed ratio of the modulation voltage. */ + v_ratio_r3 = info->r3 / (info->r2 + info->r3); /* +in voltage */ + /* The voltage at op-amp -in is 1 of 2 fixed ratios of the modulation voltage, + * based on the 555 Flip-Flop state. */ + /* If the FF is 0, then only R1 is connected allowing the full modulation volatge to pass. */ + /* v_ratio_r4_0 = 1 */ + /* If the FF is 1, then R1 & R4 make a voltage divider similar to R2 & R3 */ + v_ratio_r4_1 = info->r4 / (info->r1 + info->r4); /* -in voltage */ + /* the input resistance to the op amp depends on the FF state */ + /* r_in_0 = info->r1 when FF = 0 */ + r_in_1 = 1.0 / (1.0 / info->r1 + 1.0 / info->r4); /* input resistance when r4 switched in */ + + /* Now that we know the voltages entering the op amp and the resistance for the + * FF states, we can predetermine the ratios for the charge/discharge currents. */ + m_i_discharge = (1 - v_ratio_r3) / info->r1; + m_i_charge = (v_ratio_r3 - v_ratio_r4_1) / r_in_1; + + /* the cap starts off discharged */ + m_cap_voltage = 0; + + /* Setup 555 parameters */ + + /* There is no charge on the cap so the 555 goes high at init. */ + m_flip_flop = 1; + m_ctrlv_is_node = (this->input_is_node() >> 2) & 1; + m_v_out_high = (info->v_out_high == DEFAULT_555_HIGH) ? info->v_pos - 1.2 : info->v_out_high; + + /* Calculate 555 thresholds. + * If the Control Voltage is a node, then the thresholds will be calculated each step. + * If the Control Voltage is a fixed voltage, then the thresholds will be calculated + * from that. Otherwise we will use thresholds based on v_pos. */ + if (!m_ctrlv_is_node && (DSD_555_VCO1__VIN2 != -1)) + { + /* Setup based on supplied Control Voltage static value */ + m_threshold = DSD_555_VCO1__VIN2; + m_trigger = DSD_555_VCO1__VIN2 / 2.0; + } + else + { + /* Setup based on v_pos power source */ + m_threshold = info->v_pos * 2.0 / 3.0; + m_trigger = info->v_pos / 3.0; + } + + /* Calculate DC shift needed to make squarewave waveform AC */ + m_ac_shift = m_output_is_ac ? -m_v_out_high / 2.0 : 0; +} + + +/************************************************************************ + * + * DSD_566 - Usage of node_description values + * + * Mar 2004, D Renaud. updated Sept 2009 + * + * The data sheets for this are no where near correct. + * This simulation is based on the internal schematic and testing of + * a real Signetics IC. + * + * The 566 is a constant current based VCO. If you change R, that affects + * the charge/discharge rate. A constant current source will charge the + * cap linearly. Of course due to the transistors there will be some + * non-linear areas at the ends of the Vmod range. As the Vmod voltage + * drops from Vcharge, the frequency generated increases. + * + * The Triangle (pin 4) output is just a buffered version of the cap + * charge. It is about 1.35 higher then the cap voltage. + * The Square (pin 3) output starts low as the cap voltages rises. + * Once a threshold is reached, the cap starts to discharge, and the + * Square output goes high. The Square high output is about 1V less then + * B+. Unloaded it is .75V less. With a 4.7k pull-down resistor, it + * is 1.06V less. So I will simulate at 1V less. The Square low voltage + * is non-linear so I will use a table. The cap toggle thresholds vary + * depending on B+, so they will be simulated with a table. + * + * The data sheets show Vmod should be no less then 3/4*B+. In reality + * you can go to close to 1/2*B+ before you lose linearity. Below 1/2, + * oscillation stops. When Vmod is 0V to 0.1V less then B+, it also + * loses linearity, and stops oscillating when >= B+. This is because + * there is no voltage difference to create a current source. + * + * The current source is dependant on the voltage difference between B+ + * and Vmod. Due to transistor action, it is not 100%, but this formula + * gives a good approximation: + * I = ((B+ - Vmod - 0.1) * 0.95) / R + * You can test the current VS modulation function by using 10k for R + * and replace C with a 10k resistor. Then you can monitor the voltage + * on pin 7 to work out the current. I=V/R. It will start to oscillate + * when in the cap threshold range. + * + * When Vmod drops below the stable range, the current source no longer + * functions properly. Technically this is out of the range specified + * for the IC. Of course old games used this range anyways, so we need + * to know how the real IC behaves. When Vmod drops below the stable range, + * the charge current is stops dropping instead of increasing, while the + * discharge current still functions. This means the frequency generated + * starts to drop as the voltage lowers, instead of the normal increase + * in frequency. + * + ************************************************************************/ +#define DSD_566__VMOD DISCRETE_INPUT(0) +#define DSD_566__R DISCRETE_INPUT(1) +#define DSD_566__C DISCRETE_INPUT(2) +#define DSD_566__VPOS DISCRETE_INPUT(3) +#define DSD_566__VNEG DISCRETE_INPUT(4) +#define DSD_566__VCHARGE DISCRETE_INPUT(5) +#define DSD_566__OPTIONS DISCRETE_INPUT(6) + + +static const struct +{ + double c_high[6]; + double c_low[6]; + double sqr_low[6]; + double osc_stable[6]; + double osc_stop[6]; +} ne566 = +{ + /* 10 10.5 11 11.5 12 13 14 15 B+ */ + {3.364, /*3.784,*/ 4.259, /*4.552,*/ 4.888, 5.384, 5.896, 6.416}, /* c_high */ + {1.940, /*2.100,*/ 2.276, /*2.404,*/ 2.580, 2.880, 3.180, 3.488}, /* c_low */ + {4.352, /*4.144,*/ 4.080, /*4.260,*/ 4.500, 4.960, 5.456, 5.940}, /* sqr_low */ + {4.885, /*5.316,*/ 5.772, /*6.075,*/ 6.335, 6.912, 7.492, 7.945}, /* osc_stable */ + {4.495, /*4.895,*/ 5.343, /*5.703,*/ 5.997, 6.507, 7.016, 7.518} /* osc_stop */ +}; + +DISCRETE_STEP(dsd_566) +{ + double i = 0; /* Charging current created by vIn */ + double i_rise; /* non-linear rise charge current */ + double dt; /* change in time */ + double x_time = 0; + double v_cap; /* Current voltage on capacitor, before dt */ + int count_f = 0, count_r = 0; + + double v_out = 0.0; + + dt = this->sample_time(); /* Change in time */ + v_cap = m_cap_voltage; /* Set to voltage before change */ + + /* Calculate charging current if it is in range */ + if (EXPECTED(DSD_566__VMOD > m_v_osc_stop)) + { + double v_charge = DSD_566__VCHARGE - DSD_566__VMOD - 0.1; + if (v_charge > 0) + { + i = (v_charge * .95) / DSD_566__R; + if (DSD_566__VMOD < m_v_osc_stable) + { + /* no where near correct calculation of non linear range */ + i_rise = ((DSD_566__VCHARGE - m_v_osc_stable - 0.1) * .95) / DSD_566__R; + i_rise *= 1.0 - (m_v_osc_stable - DSD_566__VMOD) / (m_v_osc_stable - m_v_osc_stop); + } + else + i_rise = i; + } + else + return; + } + else return; + + /* Keep looping until all toggling in this time sample is used up. */ + do + { + if (m_flip_flop) + { + /* Discharging */ + v_cap -= i * dt / DSD_566__C; + dt = 0; + + /* has it discharged past lower limit? */ + if (UNEXPECTED(v_cap < m_threshold_low)) + { + /* calculate the overshoot time */ + dt = DSD_566__C * (m_threshold_low - v_cap) / i; + v_cap = m_threshold_low; + m_flip_flop = 0; + count_f++; + x_time = dt; + } + } + else + { + /* Charging */ + /* iC=C*dv/dt works out to dv=iC*dt/C */ + v_cap += i_rise * dt / DSD_566__C; + dt = 0; + /* Yes, if the cap voltage has reached the max voltage it can, + * and the 566 threshold has not been reached, then oscillation stops. + * This is the way the actual electronics works. + * This is why you never play with the pots after being factory adjusted + * to work in the proper range. */ + if (UNEXPECTED(v_cap > DSD_566__VMOD)) v_cap = DSD_566__VMOD; + + /* has it charged past upper limit? */ + if (UNEXPECTED(v_cap > m_threshold_high)) + { + /* calculate the overshoot time */ + dt = DSD_566__C * (v_cap - m_threshold_high) / i; + v_cap = m_threshold_high; + m_flip_flop = 1; + count_r++; + x_time = dt; + } + } + } while(dt); + + m_cap_voltage = v_cap; + + /* Convert last switch time to a ratio */ + x_time /= this->sample_time(); + + switch (m_out_type) + { + case DISC_566_OUT_SQUARE: + v_out = m_flip_flop ? m_v_sqr_high : m_v_sqr_low; + if (m_fake_ac) + v_out += m_ac_shift; + break; + case DISC_566_OUT_ENERGY: + if (x_time == 0) x_time = 1.0; + v_out = m_v_sqr_low + m_v_sqr_diff * (m_flip_flop ? x_time : (1.0 - x_time)); + if (m_fake_ac) + v_out += m_ac_shift; + break; + case DISC_566_OUT_LOGIC: + v_out = m_flip_flop; + break; + case DISC_566_OUT_TRIANGLE: + v_out = v_cap; + if (m_fake_ac) + v_out += m_ac_shift; + break; + case DISC_566_OUT_COUNT_F_X: + v_out = count_f ? count_f + x_time : count_f; + break; + case DISC_566_OUT_COUNT_R_X: + v_out = count_r ? count_r + x_time : count_r; + break; + case DISC_566_OUT_COUNT_F: + v_out = count_f; + break; + case DISC_566_OUT_COUNT_R: + v_out = count_r; + break; + } + set_output(0, v_out); +} + +DISCRETE_RESET(dsd_566) +{ + int v_int; + double v_float; + + m_out_type = (int)DSD_566__OPTIONS & DISC_566_OUT_MASK; + m_fake_ac = (int)DSD_566__OPTIONS & DISC_566_OUT_AC; + + if (DSD_566__VNEG >= DSD_566__VPOS) + fatalerror("[v_neg >= v_pos] in NODE_%d!\n", this->index()); + + v_float = DSD_566__VPOS - DSD_566__VNEG; + v_int = (int)v_float; + if ( v_float < 10 || v_float > 15 ) + fatalerror("v_neg and/or v_pos out of range in NODE_%d\n", this->index()); + if ( v_float != v_int ) + /* fatal for now. */ + fatalerror("Power should be integer in NODE_%d\n", this->index()); + + m_flip_flop = 0; + m_cap_voltage = 0; + + v_int -= 10; + m_threshold_high = ne566.c_high[v_int] + DSD_566__VNEG; + m_threshold_low = ne566.c_low[v_int] + DSD_566__VNEG; + m_v_sqr_high = DSD_566__VPOS - 1; + m_v_sqr_low = ne566.sqr_low[v_int] + DSD_566__VNEG; + m_v_sqr_diff = m_v_sqr_high - m_v_sqr_low; + m_v_osc_stable = ne566.osc_stable[v_int] + DSD_566__VNEG; + m_v_osc_stop = ne566.osc_stop[v_int] + DSD_566__VNEG; + + m_ac_shift = 0; + if (m_fake_ac) + { + if (m_out_type == DISC_566_OUT_TRIANGLE) + m_ac_shift = (m_threshold_high - m_threshold_low) / 2 - m_threshold_high; + else + m_ac_shift = m_v_sqr_diff / 2 - m_v_sqr_high; + } + + /* Step the output */ + this->step(); +} + + +/************************************************************************ + * + * DSD_LS624 - Usage of node_description values + * + * Dec 2007, Couriersud based on data sheet + * Oct 2009, complete re-write based on IC testing + ************************************************************************/ +#define DSD_LS624__ENABLE DISCRETE_INPUT(0) +#define DSD_LS624__VMOD DISCRETE_INPUT(1) +#define DSD_LS624__VRNG DISCRETE_INPUT(2) +#define DSD_LS624__C DISCRETE_INPUT(3) +#define DSD_LS624__R_FREQ_IN DISCRETE_INPUT(4) +#define DSD_LS624__C_FREQ_IN DISCRETE_INPUT(5) +#define DSD_LS624__R_RNG_IN DISCRETE_INPUT(6) +#define DSD_LS624__OUTTYPE DISCRETE_INPUT(7) + +#define LS624_R_EXT 600.0 /* as specified in data sheet */ +#define LS624_OUT_HIGH 4.5 /* measured */ +#define LS624_IN_R RES_K(90) /* measured & 70K + 20k per data sheet */ + +/* + * The 74LS624 series are constant current based VCOs. The Freq Control voltage + * modulates the current source. The current is created from Rext, which is + * internally fixed at 600 ohms for all devices except the 74LS628 which has + * external connections. The current source linearly discharges the cap voltage. + * The cap starts with 0V charge across it. One side is connected to a fixed voltage + * bias circuit. The other side is charged negatively from the current source until + * a certain low threshold is reached. Once this threshold is reached, the output + * toggles state and the pins on the cap reverse in respect to the charge/bias hookup. + * This starts the one side of the cap to be at bias, and the other side of the cap is + * now at bias + the charge on the cap which is bias - threshold. + * Y = 0; CX1 = bias; CX2 = charge + * Y = 1; CX1 = charge; CX2 = bias + * The Range voltage adjusts the threshold voltage. The higher the Range voltage, + * the lower the threshold voltage, the longer the cap can charge, the lower the frequency. + * + * In a perfect world it would work like this: + * The current is based on the mysterious Rext mentioned in the data sheet. + * I = (VfreqControl * 20k/90k) / Rext + * where Rext = 600 ohms or external Rext on a 74LS628 + * The Freq Control has an input impedance of approximately 90k, so any input resistance + * connected to the Freq Control pin works as a voltage divider. + * I = (VfreqControl * 20k/(90k + RfreqControlIn)) / Rext + * That gives us a change in voltage on the cap of + * dV = I / sampleRate / C_inFarads + * + * Unfortunately the chip does not behave linearly do to internal interactions, + * so I have just worked out the formula (using zunzun.com) of FreqControl and + * range to frequency out for a fixed cap value of 0.1uf. Other cap values can just + * scale from that. From the freq, we calculate the time of 1/2 cycle using 1/Freq/2. + * Then just use that to toggle a waveform. + */ + + +DISCRETE_STEP(dsd_ls624) +{ + double x_time = 0; + double freq, t1; + double v_freq_2, v_freq_3, v_freq_4; + double t_used = m_t_used; + double dt = this->sample_time();; + double v_freq = DSD_LS624__VMOD; + double v_rng = DSD_LS624__VRNG; + int count_f = 0, count_r = 0; + + /* coefficients */ + const double k1 = 1.9904769024796283E+03; + const double k2 = 1.2070059213983407E+03; + const double k3 = 1.3266985579561108E+03; + const double k4 = -1.5500979825922698E+02; + const double k5 = 2.8184536266938172E+00; + const double k6 = -2.3503421582744556E+02; + const double k7 = -3.3836786704527788E+02; + const double k8 = -1.3569136703258670E+02; + const double k9 = 2.9914575453819188E+00; + const double k10 = 1.6855569086173170E+00; + + if (UNEXPECTED(DSD_LS624__ENABLE == 0)) + return; + + /* scale due to input resistance */ + v_freq *= m_v_freq_scale; + v_rng *= m_v_rng_scale; + + /* apply cap if needed */ + if (m_has_freq_in_cap) + { + m_v_cap_freq_in += (v_freq - m_v_cap_freq_in) * m_exponent; + v_freq = m_v_cap_freq_in; + } + + /* Polyfunctional3D_model created by zunzun.com using sum of squared absolute error */ + v_freq_2 = v_freq * v_freq; + v_freq_3 = v_freq_2 * v_freq; + v_freq_4 = v_freq_3 * v_freq; + freq = k1; + freq += k2 * v_freq; + freq += k3 * v_freq_2; + freq += k4 * v_freq_3; + freq += k5 * v_freq_4; + freq += k6 * v_rng; + freq += k7 * v_rng * v_freq; + freq += k8 * v_rng * v_freq_2; + freq += k9 * v_rng * v_freq_3; + freq += k10 * v_rng * v_freq_4; + + freq *= CAP_U(0.1) / DSD_LS624__C; + + t1 = 0.5 / freq ; + t_used += this->sample_time(); + do + { + dt = 0; + if (t_used > t1) + { + /* calculate the overshoot time */ + t_used -= t1; + m_flip_flop ^= 1; + if (m_flip_flop) + count_r++; + else + count_f++; + /* fix up any frequency increase change errors */ + while(t_used > this->sample_time()) + t_used -= this->sample_time(); + x_time = t_used; + dt = t_used; + } + }while(dt); + + m_t_used = t_used; + + /* Convert last switch time to a ratio */ + x_time = x_time / this->sample_time(); + + switch (m_out_type) + { + case DISC_LS624_OUT_LOGIC_X: + set_output(0, m_flip_flop + x_time); + break; + case DISC_LS624_OUT_COUNT_F_X: + set_output(0, count_f ? count_f + x_time : count_f); + break; + case DISC_LS624_OUT_COUNT_R_X: + set_output(0, count_r ? count_r + x_time : count_r); + break; + case DISC_LS624_OUT_COUNT_F: + set_output(0, count_f); + break; + case DISC_LS624_OUT_COUNT_R: + set_output(0, count_r); + break; + case DISC_LS624_OUT_ENERGY: + if (x_time == 0) x_time = 1.0; + set_output(0, LS624_OUT_HIGH * (m_flip_flop ? x_time : (1.0 - x_time))); + break; + case DISC_LS624_OUT_LOGIC: + set_output(0, m_flip_flop); + break; + case DISC_LS624_OUT_SQUARE: + set_output(0, m_flip_flop ? LS624_OUT_HIGH : 0); + break; + } +} + +DISCRETE_RESET(dsd_ls624) +{ + m_out_type = (int)DSD_LS624__OUTTYPE; + + m_flip_flop = 0; + m_t_used = 0; + m_v_freq_scale = LS624_IN_R / (DSD_LS624__R_FREQ_IN + LS624_IN_R); + m_v_rng_scale = LS624_IN_R / (DSD_LS624__R_RNG_IN + LS624_IN_R); + if (DSD_LS624__C_FREQ_IN > 0) + { + m_has_freq_in_cap = 1; + m_exponent = RC_CHARGE_EXP(RES_2_PARALLEL(DSD_LS624__R_FREQ_IN, LS624_IN_R) * DSD_LS624__C_FREQ_IN); + m_v_cap_freq_in = 0; + } + else + m_has_freq_in_cap = 0; + + set_output(0, 0); +} diff --git a/src/devices/sound/disc_flt.h b/src/devices/sound/disc_flt.h new file mode 100644 index 00000000000..3c6f2d72607 --- /dev/null +++ b/src/devices/sound/disc_flt.h @@ -0,0 +1,180 @@ +// license:BSD-3-Clause +// copyright-holders:K.Wilkins +#pragma once + +#ifndef __DISC_FLTH__ +#define __DISC_FLT_H__ + +/*********************************************************************** + * + * MAME - Discrete sound system emulation library + * + * Written by K.Wilkins (mame@esplexo.co.uk) + * + * (c) K.Wilkins 2000 + * + * Coding started in November 2000 + * + * Additions/bugfix February 2003 - Derrick Renaud, F.Palazzolo, K.Wilkins + * Discrete parallel tasks 2009 - Couriersud + * Discrete classes 2010 - Couriersud + * + ***********************************************************************/ + +#include "discrete.h" + +struct discrete_filter_coeff +{ + double x1, x2; /* x[k-1], x[k-2], previous 2 input values */ + double y1, y2; /* y[k-1], y[k-2], previous 2 output values */ + double a1, a2; /* digital filter coefficients, denominator */ + double b0, b1, b2; /* digital filter coefficients, numerator */ +}; + + +DISCRETE_CLASS_STEP_RESET(dst_filter1, 1, + /* uses x1, y1, a1, b0, b1 */ + struct discrete_filter_coeff m_fc; +); + +DISCRETE_CLASS_STEP_RESET(dst_filter2, 1, + struct discrete_filter_coeff m_fc; +); + +DISCRETE_CLASS_STEP_RESET(dst_sallen_key, 1, + struct discrete_filter_coeff m_fc; +); + +DISCRETE_CLASS_STEP_RESET(dst_crfilter, 1, + double m_vCap; + double m_rc; + double m_exponent; + UINT8 m_has_rc_nodes; + //UINT8 m_is_fast; +); + +DISCRETE_CLASS_STEP_RESET(dst_op_amp_filt, 1, + int m_type; /* What kind of filter */ + int m_is_norton; /* 1 = Norton op-amps */ + double m_vRef; + double m_vP; + double m_vN; + double m_rTotal; /* All input resistance in parallel. */ + double m_iFixed; /* Current supplied by r3 & r4 if used. */ + double m_exponentC1; + double m_exponentC2; + double m_exponentC3; + double m_rRatio; /* divide ratio of resistance network */ + double m_vC1; /* Charge on C1 */ + double m_vC1b; /* Charge on C1, part of C1 charge if needed */ + double m_vC2; /* Charge on C2 */ + double m_vC3; /* Charge on C2 */ + double m_gain; /* Gain of the filter */ + struct discrete_filter_coeff m_fc; +); + +DISCRETE_CLASS_STEP_RESET(dst_rc_circuit_1, 1, + double m_v_cap; + double m_v_charge_1_2; + double m_v_drop; + double m_exp_1; + double m_exp_1_2; + double m_exp_2; +); + +DISCRETE_CLASS_STEP_RESET(dst_rcdisc, 1, + int m_state; + double m_t; /* time */ + double m_exponent0; +); + +DISCRETE_CLASS_STEP_RESET(dst_rcdisc2, 1, + int m_state; + double m_v_out; + double m_t; /* time */ + double m_exponent0; + double m_exponent1; +); + +DISCRETE_CLASS_STEP_RESET(dst_rcdisc3, 1, + int m_state; + double m_v_out; + double m_t; /* time */ + double m_exponent0; + double m_exponent1; + double m_v_diode; /* rcdisc3 */ +); + +DISCRETE_CLASS_STEP_RESET(dst_rcdisc4, 1, + int m_type; + double m_max_out; + double m_vC1; + double m_v[2]; + double m_exp[2]; +); + +DISCRETE_CLASS_STEP_RESET(dst_rcdisc5, 1, + int m_state; + double m_t; /* time */ + double m_exponent0; + double m_v_cap; /* rcdisc5 */ +); + +DISCRETE_CLASS_STEP_RESET(dst_rcintegrate, 1, + int m_type; + double m_gain_r1_r2; + double m_f; /* r2,r3 gain */ + double m_vCap; + double m_vCE; + double m_exponent0; + double m_exponent1; + double m_exp_exponent0; + double m_exp_exponent1; + double m_c_exp0; + double m_c_exp1; + double m_EM_IC_0_7; +); + +DISCRETE_CLASS_STEP_RESET(dst_rcdisc_mod, 1, + double m_v_cap; + double m_exp_low[2]; + double m_exp_high[4]; + double m_gain[2]; + double m_vd_gain[4]; +); + +DISCRETE_CLASS_STEP_RESET(dst_rcfilter, 1, + double m_v_out; + double m_vCap; + double m_rc; + double m_exponent; + UINT8 m_has_rc_nodes; + UINT8 m_is_fast; +); + +DISCRETE_CLASS_STEP_RESET(dst_rcfilter_sw, 1, + double m_vCap[4]; + double m_exp[4]; + double m_exp0; /* fast case bit 0 */ + double m_exp1; /* fast case bit 1 */ + double m_factor; /* fast case */ + double m_f1[16]; + double m_f2[16]; +); + +DISCRETE_CLASS_STEP_RESET(dst_rcdiscN, 1, + double m_x1; /* x[k-1], previous input value */ + double m_y1; /* y[k-1], previous output value */ + double m_a1; /* digital filter coefficients, denominator */ + //double m_b[2]; /* digital filter coefficients, numerator */ +); + +DISCRETE_CLASS_STEP_RESET(dst_rcdisc2N, 1, + struct discrete_filter_coeff m_fc0; + struct discrete_filter_coeff m_fc1; + double m_x1; + double m_y1; +); + + +#endif /* __DISC_FLT_H__ */ diff --git a/src/devices/sound/disc_flt.inc b/src/devices/sound/disc_flt.inc new file mode 100644 index 00000000000..18cb8f41c1c --- /dev/null +++ b/src/devices/sound/disc_flt.inc @@ -0,0 +1,1438 @@ +// license:BSD-3-Clause +// copyright-holders:K.Wilkins +/************************************************************************ + * + * MAME - Discrete sound system emulation library + * + * Written by K.Wilkins (mame@esplexo.co.uk) + * + * (c) K.Wilkins 2000 + * + *********************************************************************** + * + * DST_CRFILTER - Simple CR filter & also highpass filter + * DST_FILTER1 - Generic 1st order filter + * DST_FILTER2 - Generic 2nd order filter + * DST_OP_AMP_FILT - Op Amp filter circuits + * DST_RC_CIRCUIT_1 - RC charge/discharge circuit + * DST_RCDISC - Simple discharging RC + * DST_RCDISC2 - Simple charge R1/C, discharge R0/C + * DST_RCDISC3 - Simple charge R1/c, discharge R0*R1/(R0+R1)/C + * DST_RCDISC4 - Various charge/discharge circuits + * DST_RCDISC5 - Diode in series with R//C + * DST_RCDISC_MOD - RC triggered by logic and modulated + * DST_RCFILTER - Simple RC filter & also lowpass filter + * DST_RCFILTER_SW - Usage of node_description values for switchable RC filter + * DST_RCINTEGRATE - Two diode inputs, transistor and a R/C charge + * discharge network + * DST_SALLEN_KEY - Sallen-Key filter circuit + * + ************************************************************************/ + + +/************************************************************************ + * + * DST_CRFILTER - Usage of node_description values for CR filter + * + * input[0] - Enable input value + * input[1] - input value + * input[2] - Resistor value (initialization only) + * input[3] - Capacitor Value (initialization only) + * input[4] - Voltage reference. Usually 0V. + * + ************************************************************************/ +#define DST_CRFILTER__IN DISCRETE_INPUT(0) +#define DST_CRFILTER__R DISCRETE_INPUT(1) +#define DST_CRFILTER__C DISCRETE_INPUT(2) +#define DST_CRFILTER__VREF DISCRETE_INPUT(3) + +DISCRETE_STEP(dst_crfilter) +{ + if (UNEXPECTED(m_has_rc_nodes)) + { + double rc = DST_CRFILTER__R * DST_CRFILTER__C; + if (rc != m_rc) + { + m_rc = rc; + m_exponent = RC_CHARGE_EXP(rc); + } + } + + double v_out = DST_CRFILTER__IN - m_vCap; + double v_diff = v_out - DST_CRFILTER__VREF; + set_output(0, v_out); + m_vCap += v_diff * m_exponent; +} + +DISCRETE_RESET(dst_crfilter) +{ + m_has_rc_nodes = this->input_is_node() & 0x6; + m_rc = DST_CRFILTER__R * DST_CRFILTER__C; + m_exponent = RC_CHARGE_EXP(m_rc); + m_vCap = 0; + set_output(0, DST_CRFILTER__IN); +} + + +/************************************************************************ + * + * DST_FILTER1 - Generic 1st order filter + * + * input[0] - Enable input value + * input[1] - input value + * input[2] - Frequency value (initialization only) + * input[3] - Filter type (initialization only) + * + ************************************************************************/ +#define DST_FILTER1__ENABLE DISCRETE_INPUT(0) +#define DST_FILTER1__IN DISCRETE_INPUT(1) +#define DST_FILTER1__FREQ DISCRETE_INPUT(2) +#define DST_FILTER1__TYPE DISCRETE_INPUT(3) + +static void calculate_filter1_coefficients(discrete_base_node *node, double fc, double type, + struct discrete_filter_coeff &coeff) +{ + double den, w, two_over_T; + + /* calculate digital filter coefficents */ + /*w = 2.0*M_PI*fc; no pre-warping */ + w = node->sample_rate()*2.0*tan(M_PI*fc/node->sample_rate()); /* pre-warping */ + two_over_T = 2.0*node->sample_rate(); + + den = w + two_over_T; + coeff.a1 = (w - two_over_T)/den; + if (type == DISC_FILTER_LOWPASS) + { + coeff.b0 = coeff.b1 = w/den; + } + else if (type == DISC_FILTER_HIGHPASS) + { + coeff.b0 = two_over_T/den; + coeff.b1 = -(coeff.b0); + } + else + { + /* FIXME: reenable */ + //node->m_device->discrete_log("calculate_filter1_coefficients() - Invalid filter type for 1st order filter."); + } +} + +DISCRETE_STEP(dst_filter1) +{ + double gain = 1.0; + double v_out; + + if (DST_FILTER1__ENABLE == 0.0) + { + gain = 0.0; + } + + v_out = -m_fc.a1*m_fc.y1 + m_fc.b0*gain*DST_FILTER1__IN + m_fc.b1*m_fc.x1; + + m_fc.x1 = gain*DST_FILTER1__IN; + m_fc.y1 = v_out; + set_output(0, v_out); +} + +DISCRETE_RESET(dst_filter1) +{ + calculate_filter1_coefficients(this, DST_FILTER1__FREQ, DST_FILTER1__TYPE, m_fc); + set_output(0, 0); +} + + +/************************************************************************ + * + * DST_FILTER2 - Generic 2nd order filter + * + * input[0] - Enable input value + * input[1] - input value + * input[2] - Frequency value (initialization only) + * input[3] - Damping value (initialization only) + * input[4] - Filter type (initialization only) + * + ************************************************************************/ +#define DST_FILTER2__ENABLE DISCRETE_INPUT(0) +#define DST_FILTER2__IN DISCRETE_INPUT(1) +#define DST_FILTER2__FREQ DISCRETE_INPUT(2) +#define DST_FILTER2__DAMP DISCRETE_INPUT(3) +#define DST_FILTER2__TYPE DISCRETE_INPUT(4) + +static void calculate_filter2_coefficients(discrete_base_node *node, + double fc, double d, double type, + struct discrete_filter_coeff &coeff) +{ + double w; /* cutoff freq, in radians/sec */ + double w_squared; + double den; /* temp variable */ + double two_over_T = 2 * node->sample_rate(); + double two_over_T_squared = two_over_T * two_over_T; + + /* calculate digital filter coefficents */ + /*w = 2.0*M_PI*fc; no pre-warping */ + w = node->sample_rate() * 2.0 * tan(M_PI * fc / node->sample_rate()); /* pre-warping */ + w_squared = w * w; + + den = two_over_T_squared + d*w*two_over_T + w_squared; + + coeff.a1 = 2.0 * (-two_over_T_squared + w_squared) / den; + coeff.a2 = (two_over_T_squared - d * w * two_over_T + w_squared) / den; + + if (type == DISC_FILTER_LOWPASS) + { + coeff.b0 = coeff.b2 = w_squared/den; + coeff.b1 = 2.0 * (coeff.b0); + } + else if (type == DISC_FILTER_BANDPASS) + { + coeff.b0 = d * w * two_over_T / den; + coeff.b1 = 0.0; + coeff.b2 = -(coeff.b0); + } + else if (type == DISC_FILTER_HIGHPASS) + { + coeff.b0 = coeff.b2 = two_over_T_squared / den; + coeff.b1 = -2.0 * (coeff.b0); + } + else + { + /* FIXME: reenable */ + //node->device->discrete_log("calculate_filter2_coefficients() - Invalid filter type for 2nd order filter."); + } +} + +DISCRETE_STEP(dst_filter2) +{ + double gain = 1.0; + double v_out; + + if (DST_FILTER2__ENABLE == 0.0) + { + gain = 0.0; + } + + v_out = -m_fc.a1 * m_fc.y1 - m_fc.a2 * m_fc.y2 + + m_fc.b0 * gain * DST_FILTER2__IN + m_fc.b1 * m_fc.x1 + m_fc.b2 * m_fc.x2; + + m_fc.x2 = m_fc.x1; + m_fc.x1 = gain * DST_FILTER2__IN; + m_fc.y2 = m_fc.y1; + m_fc.y1 = v_out; + set_output(0, v_out); +} + +DISCRETE_RESET(dst_filter2) +{ + calculate_filter2_coefficients(this, DST_FILTER2__FREQ, DST_FILTER2__DAMP, DST_FILTER2__TYPE, + m_fc); + set_output(0, 0); +} + + +/************************************************************************ + * + * DST_OP_AMP_FILT - Op Amp filter circuit RC filter + * + * input[0] - Enable input value + * input[1] - IN0 node + * input[2] - IN1 node + * input[3] - Filter Type + * + * also passed discrete_op_amp_filt_info structure + * + * Mar 2004, D Renaud. + ************************************************************************/ +#define DST_OP_AMP_FILT__ENABLE DISCRETE_INPUT(0) +#define DST_OP_AMP_FILT__INP1 DISCRETE_INPUT(1) +#define DST_OP_AMP_FILT__INP2 DISCRETE_INPUT(2) +#define DST_OP_AMP_FILT__TYPE DISCRETE_INPUT(3) + +DISCRETE_STEP(dst_op_amp_filt) +{ + DISCRETE_DECLARE_INFO(discrete_op_amp_filt_info) + double v_out = 0; + + double i, v = 0; + + if (DST_OP_AMP_FILT__ENABLE) + { + if (m_is_norton) + { + v = DST_OP_AMP_FILT__INP1 - OP_AMP_NORTON_VBE; + if (v < 0) v = 0; + } + else + { + /* Millman the input voltages. */ + i = m_iFixed; + switch (m_type) + { + case DISC_OP_AMP_FILTER_IS_LOW_PASS_1_A: + i += (DST_OP_AMP_FILT__INP1 - DST_OP_AMP_FILT__INP2) / info->r1; + if (info->r2 != 0) + i += (m_vP - DST_OP_AMP_FILT__INP2) / info->r2; + if (info->r3 != 0) + i += (m_vN - DST_OP_AMP_FILT__INP2) / info->r3; + break; + default: + i += (DST_OP_AMP_FILT__INP1 - m_vRef) / info->r1; + if (info->r2 != 0) + i += (DST_OP_AMP_FILT__INP2 - m_vRef) / info->r2; + break; + } + v = i * m_rTotal; + } + + switch (m_type) + { + case DISC_OP_AMP_FILTER_IS_LOW_PASS_1: + m_vC1 += (v - m_vC1) * m_exponentC1; + v_out = m_vC1 * m_gain + info->vRef; + break; + + case DISC_OP_AMP_FILTER_IS_LOW_PASS_1_A: + m_vC1 += (v - m_vC1) * m_exponentC1; + v_out = m_vC1 * m_gain + DST_OP_AMP_FILT__INP2; + break; + + case DISC_OP_AMP_FILTER_IS_HIGH_PASS_1: + v_out = (v - m_vC1) * m_gain + info->vRef; + m_vC1 += (v - m_vC1) * m_exponentC1; + break; + + case DISC_OP_AMP_FILTER_IS_BAND_PASS_1: + v_out = (v - m_vC2); + m_vC2 += (v - m_vC2) * m_exponentC2; + m_vC1 += (v_out - m_vC1) * m_exponentC1; + v_out = m_vC1 * m_gain + info->vRef; + break; + + case DISC_OP_AMP_FILTER_IS_BAND_PASS_0 | DISC_OP_AMP_IS_NORTON: + m_vC1 += (v - m_vC1) * m_exponentC1; + m_vC2 += (m_vC1 - m_vC2) * m_exponentC2; + v = m_vC2; + v_out = v - m_vC3; + m_vC3 += (v - m_vC3) * m_exponentC3; + i = v_out / m_rTotal; + v_out = (m_iFixed - i) * info->rF; + break; + + case DISC_OP_AMP_FILTER_IS_HIGH_PASS_0 | DISC_OP_AMP_IS_NORTON: + v_out = v - m_vC1; + m_vC1 += (v - m_vC1) * m_exponentC1; + i = v_out / m_rTotal; + v_out = (m_iFixed - i) * info->rF; + break; + + case DISC_OP_AMP_FILTER_IS_BAND_PASS_1M: + case DISC_OP_AMP_FILTER_IS_BAND_PASS_1M | DISC_OP_AMP_IS_NORTON: + v_out = -m_fc.a1 * m_fc.y1 - m_fc.a2 * m_fc.y2 + + m_fc.b0 * v + m_fc.b1 * m_fc.x1 + m_fc.b2 * m_fc.x2 + + m_vRef; + m_fc.x2 = m_fc.x1; + m_fc.x1 = v; + m_fc.y2 = m_fc.y1; + break; + } + + /* Clip the output to the voltage rails. + * This way we get the original distortion in all it's glory. + */ + if (v_out > m_vP) v_out = m_vP; + if (v_out < m_vN) v_out = m_vN; + m_fc.y1 = v_out - m_vRef; + set_output(0, v_out); + } + else + set_output(0, 0); + +} + +DISCRETE_RESET(dst_op_amp_filt) +{ + DISCRETE_DECLARE_INFO(discrete_op_amp_filt_info) + + /* Convert the passed filter type into an int for easy use. */ + m_type = (int)DST_OP_AMP_FILT__TYPE & DISC_OP_AMP_FILTER_TYPE_MASK; + m_is_norton = (int)DST_OP_AMP_FILT__TYPE & DISC_OP_AMP_IS_NORTON; + + if (m_is_norton) + { + m_vRef = 0; + m_rTotal = info->r1; + if (m_type == (DISC_OP_AMP_FILTER_IS_BAND_PASS_0 | DISC_OP_AMP_IS_NORTON)) + m_rTotal += info->r2 + info->r3; + + /* Setup the current to the + input. */ + m_iFixed = (info->vP - OP_AMP_NORTON_VBE) / info->r4; + + /* Set the output max. */ + m_vP = info->vP - OP_AMP_NORTON_VBE; + m_vN = info->vN; + } + else + { + m_vRef = info->vRef; + /* Set the output max. */ + m_vP = info->vP - OP_AMP_VP_RAIL_OFFSET; + m_vN = info->vN; + + /* Work out the input resistance. It is all input and bias resistors in parallel. */ + m_rTotal = 1.0 / info->r1; /* There has to be an R1. Otherwise the table is wrong. */ + if (info->r2 != 0) m_rTotal += 1.0 / info->r2; + if (info->r3 != 0) m_rTotal += 1.0 / info->r3; + m_rTotal = 1.0 / m_rTotal; + + m_iFixed = 0; + + m_rRatio = info->rF / (m_rTotal + info->rF); + m_gain = -info->rF / m_rTotal; + } + + switch (m_type) + { + case DISC_OP_AMP_FILTER_IS_LOW_PASS_1: + case DISC_OP_AMP_FILTER_IS_LOW_PASS_1_A: + m_exponentC1 = RC_CHARGE_EXP(info->rF * info->c1); + m_exponentC2 = 0; + break; + case DISC_OP_AMP_FILTER_IS_HIGH_PASS_1: + m_exponentC1 = RC_CHARGE_EXP(m_rTotal * info->c1); + m_exponentC2 = 0; + break; + case DISC_OP_AMP_FILTER_IS_BAND_PASS_1: + m_exponentC1 = RC_CHARGE_EXP(info->rF * info->c1); + m_exponentC2 = RC_CHARGE_EXP(m_rTotal * info->c2); + break; + case DISC_OP_AMP_FILTER_IS_BAND_PASS_1M | DISC_OP_AMP_IS_NORTON: + if (info->r2 == 0) + m_rTotal = info->r1; + else + m_rTotal = RES_2_PARALLEL(info->r1, info->r2); + case DISC_OP_AMP_FILTER_IS_BAND_PASS_1M: + { + double fc = 1.0 / (2 * M_PI * sqrt(m_rTotal * info->rF * info->c1 * info->c2)); + double d = (info->c1 + info->c2) / sqrt(info->rF / m_rTotal * info->c1 * info->c2); + double gain = -info->rF / m_rTotal * info->c2 / (info->c1 + info->c2); + + calculate_filter2_coefficients(this, fc, d, DISC_FILTER_BANDPASS, m_fc); + m_fc.b0 *= gain; + m_fc.b1 *= gain; + m_fc.b2 *= gain; + + if (m_is_norton) + m_vRef = (info->vP - OP_AMP_NORTON_VBE) / info->r3 * info->rF; + else + m_vRef = info->vRef; + + break; + } + case DISC_OP_AMP_FILTER_IS_BAND_PASS_0 | DISC_OP_AMP_IS_NORTON: + m_exponentC1 = RC_CHARGE_EXP(RES_2_PARALLEL(info->r1, info->r2 + info->r3 + info->r4) * info->c1); + m_exponentC2 = RC_CHARGE_EXP(RES_2_PARALLEL(info->r1 + info->r2, info->r3 + info->r4) * info->c2); + m_exponentC3 = RC_CHARGE_EXP((info->r1 + info->r2 + info->r3 + info->r4) * info->c3); + break; + case DISC_OP_AMP_FILTER_IS_HIGH_PASS_0 | DISC_OP_AMP_IS_NORTON: + m_exponentC1 = RC_CHARGE_EXP(info->r1 * info->c1); + break; + } + + /* At startup there is no charge on the caps and output is 0V in relation to vRef. */ + m_vC1 = 0; + m_vC1b = 0; + m_vC2 = 0; + m_vC3 = 0; + + set_output(0, info->vRef); +} + + +/************************************************************************ + * + * DST_RC_CIRCUIT_1 - RC charge/discharge circuit + * + ************************************************************************/ +#define DST_RC_CIRCUIT_1__IN0 DISCRETE_INPUT(0) +#define DST_RC_CIRCUIT_1__IN1 DISCRETE_INPUT(1) +#define DST_RC_CIRCUIT_1__R DISCRETE_INPUT(2) +#define DST_RC_CIRCUIT_1__C DISCRETE_INPUT(3) + +#define CD4066_R_ON 270 + +DISCRETE_STEP( dst_rc_circuit_1 ) +{ + if (DST_RC_CIRCUIT_1__IN0 == 0) + if (DST_RC_CIRCUIT_1__IN1 == 0) + /* cap is floating and does not change charge */ + /* output is pulled to ground */ + set_output(0, 0); + else + { + /* cap is discharged */ + m_v_cap -= m_v_cap * m_exp_2; + set_output(0, m_v_cap * m_v_drop); + } + else + if (DST_RC_CIRCUIT_1__IN1 == 0) + { + /* cap is charged */ + m_v_cap += (5.0 - m_v_cap) * m_exp_1; + /* output is pulled to ground */ + set_output(0, 0); + } + else + { + /* cap is charged slightly less */ + m_v_cap += (m_v_charge_1_2 - m_v_cap) * m_exp_1_2; + set_output(0, m_v_cap * m_v_drop); + } +} + +DISCRETE_RESET( dst_rc_circuit_1 ) +{ + /* the charging voltage across the cap based on in2*/ + m_v_drop = RES_VOLTAGE_DIVIDER(CD4066_R_ON, CD4066_R_ON + DST_RC_CIRCUIT_1__R); + m_v_charge_1_2 = 5.0 * m_v_drop; + m_v_cap = 0; + + /* precalculate charging exponents */ + /* discharge cap - in1 = 0, in2 = 1*/ + m_exp_2 = RC_CHARGE_EXP((CD4066_R_ON + DST_RC_CIRCUIT_1__R) * DST_RC_CIRCUIT_1__C); + /* charge cap - in1 = 1, in2 = 0 */ + m_exp_1 = RC_CHARGE_EXP(CD4066_R_ON * DST_RC_CIRCUIT_1__C); + /* charge cap - in1 = 1, in2 = 1 */ + m_exp_1_2 = RC_CHARGE_EXP(RES_2_PARALLEL(CD4066_R_ON, CD4066_R_ON + DST_RC_CIRCUIT_1__R) * DST_RC_CIRCUIT_1__C); + + /* starts at 0 until cap starts charging */ + set_output(0, 0); +} + +/************************************************************************ + * + * DST_RCDISC - Usage of node_description values for RC discharge + * (inverse slope of DST_RCFILTER) + * + * input[0] - Enable input value + * input[1] - input value + * input[2] - Resistor value (initialization only) + * input[3] - Capacitor Value (initialization only) + * + ************************************************************************/ +#define DST_RCDISC__ENABLE DISCRETE_INPUT(0) +#define DST_RCDISC__IN DISCRETE_INPUT(1) +#define DST_RCDISC__R DISCRETE_INPUT(2) +#define DST_RCDISC__C DISCRETE_INPUT(3) + +DISCRETE_STEP(dst_rcdisc) +{ + switch (m_state) + { + case 0: /* waiting for trigger */ + if(DST_RCDISC__ENABLE) + { + m_state = 1; + m_t = 0; + } + set_output(0, 0); + break; + + case 1: + if (DST_RCDISC__ENABLE) + { + set_output(0, DST_RCDISC__IN * exp(m_t / m_exponent0)); + m_t += this->sample_time(); + } else + { + m_state = 0; + } + } +} + +DISCRETE_RESET(dst_rcdisc) +{ + set_output(0, 0); + + m_state = 0; + m_t = 0; + m_exponent0=-1.0 * DST_RCDISC__R * DST_RCDISC__C; +} + + +/************************************************************************ + * + * DST_RCDISC2 - Usage of node_description values for RC discharge + * Has switchable charge resistor/input + * + * input[0] - Switch input value + * input[1] - input[0] value + * input[2] - Resistor0 value (initialization only) + * input[3] - input[1] value + * input[4] - Resistor1 value (initialization only) + * input[5] - Capacitor Value (initialization only) + * + ************************************************************************/ +#define DST_RCDISC2__ENABLE DISCRETE_INPUT(0) +#define DST_RCDISC2__IN0 DISCRETE_INPUT(1) +#define DST_RCDISC2__R0 DISCRETE_INPUT(2) +#define DST_RCDISC2__IN1 DISCRETE_INPUT(3) +#define DST_RCDISC2__R1 DISCRETE_INPUT(4) +#define DST_RCDISC2__C DISCRETE_INPUT(5) + +DISCRETE_STEP(dst_rcdisc2) +{ + double diff; + + /* Works differently to other as we are always on, no enable */ + /* exponential based in difference between input/output */ + + diff = ((DST_RCDISC2__ENABLE == 0) ? DST_RCDISC2__IN0 : DST_RCDISC2__IN1) - m_v_out; + diff = diff - (diff * ((DST_RCDISC2__ENABLE == 0) ? m_exponent0 : m_exponent1)); + m_v_out += diff; + set_output(0, m_v_out); +} + +DISCRETE_RESET(dst_rcdisc2) +{ + m_v_out = 0; + + m_state = 0; + m_t = 0; + m_exponent0 = RC_DISCHARGE_EXP(DST_RCDISC2__R0 * DST_RCDISC2__C); + m_exponent1 = RC_DISCHARGE_EXP(DST_RCDISC2__R1 * DST_RCDISC2__C); +} + +/************************************************************************ + * + * DST_RCDISC3 - Usage of node_description values for RC discharge + * + * + * input[0] - Enable + * input[1] - input value + * input[2] - Resistor0 value (initialization only) + * input[4] - Resistor1 value (initialization only) + * input[5] - Capacitor Value (initialization only) + * input[6] - Diode Junction voltage (initialization only) + * + ************************************************************************/ +#define DST_RCDISC3__ENABLE DISCRETE_INPUT(0) +#define DST_RCDISC3__IN DISCRETE_INPUT(1) +#define DST_RCDISC3__R1 DISCRETE_INPUT(2) +#define DST_RCDISC3__R2 DISCRETE_INPUT(3) +#define DST_RCDISC3__C DISCRETE_INPUT(4) +#define DST_RCDISC3__DJV DISCRETE_INPUT(5) + +DISCRETE_STEP(dst_rcdisc3) +{ + double diff; + + /* Exponential based in difference between input/output */ + + if(DST_RCDISC3__ENABLE) + { + diff = DST_RCDISC3__IN - m_v_out; + if (m_v_diode > 0) + { + if (diff > 0) + { + diff = diff * m_exponent0; + } + else if (diff < -m_v_diode) + { + diff = diff * m_exponent1; + } + else + { + diff = diff * m_exponent0; + } + } + else + { + if (diff < 0) + { + diff = diff * m_exponent0; + } + else if (diff > -m_v_diode) + { + diff = diff * m_exponent1; + } + else + { + diff = diff * m_exponent0; + } + } + m_v_out += diff; + set_output(0, m_v_out); + } + else + { + set_output(0, 0); + } +} + +DISCRETE_RESET(dst_rcdisc3) +{ + m_v_out = 0; + + m_state = 0; + m_t = 0; + m_v_diode = DST_RCDISC3__DJV; + m_exponent0 = RC_CHARGE_EXP(DST_RCDISC3__R1 * DST_RCDISC3__C); + m_exponent1 = RC_CHARGE_EXP(RES_2_PARALLEL(DST_RCDISC3__R1, DST_RCDISC3__R2) * DST_RCDISC3__C); +} + + +/************************************************************************ + * + * DST_RCDISC4 - Various charge/discharge circuits + * + * input[0] - Enable input value + * input[1] - input value + * input[2] - R1 Resistor value (initialization only) + * input[2] - R2 Resistor value (initialization only) + * input[4] - C1 Capacitor Value (initialization only) + * input[4] - vP power source (initialization only) + * input[4] - circuit type (initialization only) + * + ************************************************************************/ +#define DST_RCDISC4__ENABLE DISCRETE_INPUT(0) +#define DST_RCDISC4__IN DISCRETE_INPUT(1) +#define DST_RCDISC4__R1 DISCRETE_INPUT(2) +#define DST_RCDISC4__R2 DISCRETE_INPUT(3) +#define DST_RCDISC4__R3 DISCRETE_INPUT(4) +#define DST_RCDISC4__C1 DISCRETE_INPUT(5) +#define DST_RCDISC4__VP DISCRETE_INPUT(6) +#define DST_RCDISC4__TYPE DISCRETE_INPUT(7) + +DISCRETE_STEP(dst_rcdisc4) +{ + int inp1 = (DST_RCDISC4__IN == 0) ? 0 : 1; + double v_out = 0; + + if (DST_RCDISC4__ENABLE == 0) + { + set_output(0, 0); + return; + } + + switch (m_type) + { + case 1: + case 3: + m_vC1 += ((m_v[inp1] - m_vC1) * m_exp[inp1]); + v_out = m_vC1; + break; + } + + /* clip output */ + if (v_out > m_max_out) v_out = m_max_out; + if (v_out < 0) v_out = 0; + set_output(0, v_out); +} + +DISCRETE_RESET( dst_rcdisc4) +{ + double v, i, r, rT; + + m_type = 0; + /* some error checking. */ + if (DST_RCDISC4__R1 <= 0 || DST_RCDISC4__R2 <= 0 || DST_RCDISC4__C1 <= 0 || (DST_RCDISC4__R3 <= 0 && m_type == 1)) + { + m_device->discrete_log("Invalid component values in NODE_%d.\n", this->index()); + return; + } + if (DST_RCDISC4__VP < 3) + { + m_device->discrete_log("vP must be >= 3V in NODE_%d.\n", this->index()); + return; + } + if (DST_RCDISC4__TYPE < 1 || DST_RCDISC4__TYPE > 3) + { + m_device->discrete_log("Invalid circuit type in NODE_%d.\n", this->index()); + return; + } + + m_vC1 = 0; + /* store type as integer */ + m_type = (int)DST_RCDISC4__TYPE; + /* setup the maximum op-amp output. */ + m_max_out = DST_RCDISC4__VP - OP_AMP_VP_RAIL_OFFSET; + + switch (m_type) + { + case 1: + /* We will simulate this as a voltage divider with 2 states depending + * on the input. But we have to take the diodes into account. + */ + v = DST_RCDISC4__VP - .5; /* diode drop */ + + /* When the input is 1, both R1 & R3 are basically in parallel. */ + r = RES_2_PARALLEL(DST_RCDISC4__R1, DST_RCDISC4__R3); + rT = DST_RCDISC4__R2 + r; + i = v / rT; + m_v[1] = i * r + .5; + rT = RES_2_PARALLEL(DST_RCDISC4__R2, r); + m_exp[1] = RC_CHARGE_EXP(rT * DST_RCDISC4__C1); + + /* When the input is 0, R1 is out of circuit. */ + rT = DST_RCDISC4__R2 + DST_RCDISC4__R3; + i = v / rT; + m_v[0] = i * DST_RCDISC4__R3 + .5; + rT = RES_2_PARALLEL(DST_RCDISC4__R2, DST_RCDISC4__R3); + m_exp[0] = RC_CHARGE_EXP(rT * DST_RCDISC4__C1); + break; + + case 3: + /* We will simulate this as a voltage divider with 2 states depending + * on the input. The 1k pullup is in parallel with the internal TTL + * resistance, so we will just use .5k in series with R1. + */ + r = 500.0 + DST_RCDISC4__R1; + m_v[1] = RES_VOLTAGE_DIVIDER(r, DST_RCDISC4__R2) * (5.0 - 0.5); + rT = RES_2_PARALLEL(r, DST_RCDISC4__R2); + m_exp[1] = RC_CHARGE_EXP(rT * DST_RCDISC4__C1); + + /* When the input is 0, R1 is out of circuit. */ + m_v[0] = 0; + m_exp[0] = RC_CHARGE_EXP(DST_RCDISC4__R2 * DST_RCDISC4__C1); + break; + } +} + +/************************************************************************ + * + * DST_RCDISC5 - Diode in series with R//C + * + * input[0] - Enable input value + * input[1] - input value + * input[2] - Resistor value (initialization only) + * input[3] - Capacitor Value (initialization only) + * + ************************************************************************/ +#define DST_RCDISC5__ENABLE DISCRETE_INPUT(0) +#define DST_RCDISC5__IN DISCRETE_INPUT(1) +#define DST_RCDISC5__R DISCRETE_INPUT(2) +#define DST_RCDISC5__C DISCRETE_INPUT(3) + +DISCRETE_STEP( dst_rcdisc5) +{ + double diff,u; + + /* Exponential based in difference between input/output */ + + u = DST_RCDISC5__IN - 0.7; /* Diode drop */ + if( u < 0) + u = 0; + + diff = u - m_v_cap; + + if(DST_RCDISC5__ENABLE) + { + if(diff < 0) + diff = diff * m_exponent0; + + m_v_cap += diff; + set_output(0, m_v_cap); + } + else + { + if(diff > 0) + m_v_cap = u; + + set_output(0, 0); + } +} + +DISCRETE_RESET( dst_rcdisc5) +{ + set_output(0, 0); + + m_state = 0; + m_t = 0; + m_v_cap = 0; + m_exponent0 = RC_CHARGE_EXP(DST_RCDISC5__R * DST_RCDISC5__C); +} + + +/************************************************************************ + * + * DST_RCDISC_MOD - RC triggered by logic and modulated + * + * input[0] - Enable input value + * input[1] - input value 1 + * input[2] - input value 2 + * input[3] - Resistor 1 value (initialization only) + * input[4] - Resistor 2 value (initialization only) + * input[5] - Resistor 3 value (initialization only) + * input[6] - Resistor 4 value (initialization only) + * input[7] - Capacitor Value (initialization only) + * input[8] - Voltage Value (initialization only) + * + ************************************************************************/ +#define DST_RCDISC_MOD__IN1 DISCRETE_INPUT(0) +#define DST_RCDISC_MOD__IN2 DISCRETE_INPUT(1) +#define DST_RCDISC_MOD__R1 DISCRETE_INPUT(2) +#define DST_RCDISC_MOD__R2 DISCRETE_INPUT(3) +#define DST_RCDISC_MOD__R3 DISCRETE_INPUT(4) +#define DST_RCDISC_MOD__R4 DISCRETE_INPUT(5) +#define DST_RCDISC_MOD__C DISCRETE_INPUT(6) +#define DST_RCDISC_MOD__VP DISCRETE_INPUT(7) + +DISCRETE_STEP(dst_rcdisc_mod) +{ + double diff, v_cap, u, vD; + int mod_state, mod1_state, mod2_state; + + /* Exponential based in difference between input/output */ + v_cap = m_v_cap; + + mod1_state = DST_RCDISC_MOD__IN1 > 0.5; + mod2_state = DST_RCDISC_MOD__IN2 > 0.6; + mod_state = (mod2_state << 1) + mod1_state; + + u = mod1_state ? 0 : DST_RCDISC_MOD__VP; + /* Clamp */ + diff = u - v_cap; + vD = diff * m_vd_gain[mod_state]; + if (vD < -0.6) + { + diff = u + 0.6 - v_cap; + diff -= diff * m_exp_low[mod1_state]; + v_cap += diff; + set_output(0, mod2_state ? 0 : -0.6); + } + else + { + diff -= diff * m_exp_high[mod_state]; + v_cap += diff; + /* neglecting current through R3 drawn by next8 node */ + set_output(0, mod2_state ? 0: (u - v_cap) * m_gain[mod1_state]); + } + m_v_cap = v_cap; +} + +DISCRETE_RESET(dst_rcdisc_mod) +{ + double rc[2], rc2[2]; + + /* pre-calculate fixed values */ + /* DST_RCDISC_MOD__IN1 <= 0.5 */ + rc[0] = DST_RCDISC_MOD__R1 + DST_RCDISC_MOD__R2; + if (rc[0] < 1) rc[0] = 1; + m_exp_low[0] = RC_DISCHARGE_EXP(DST_RCDISC_MOD__C * rc[0]); + m_gain[0] = RES_VOLTAGE_DIVIDER(rc[0], DST_RCDISC_MOD__R4); + /* DST_RCDISC_MOD__IN1 > 0.5 */ + rc[1] = DST_RCDISC_MOD__R2; + if (rc[1] < 1) rc[1] = 1; + m_exp_low[1] = RC_DISCHARGE_EXP(DST_RCDISC_MOD__C * rc[1]); + m_gain[1] = RES_VOLTAGE_DIVIDER(rc[1], DST_RCDISC_MOD__R4); + /* DST_RCDISC_MOD__IN2 <= 0.6 */ + rc2[0] = DST_RCDISC_MOD__R4; + /* DST_RCDISC_MOD__IN2 > 0.6 */ + rc2[1] = RES_2_PARALLEL(DST_RCDISC_MOD__R3, DST_RCDISC_MOD__R4); + /* DST_RCDISC_MOD__IN1 <= 0.5 && DST_RCDISC_MOD__IN2 <= 0.6 */ + m_exp_high[0] = RC_DISCHARGE_EXP(DST_RCDISC_MOD__C * (rc[0] + rc2[0])); + m_vd_gain[0] = RES_VOLTAGE_DIVIDER(rc[0], rc2[0]); + /* DST_RCDISC_MOD__IN1 > 0.5 && DST_RCDISC_MOD__IN2 <= 0.6 */ + m_exp_high[1] = RC_DISCHARGE_EXP(DST_RCDISC_MOD__C * (rc[1] + rc2[0])); + m_vd_gain[1] = RES_VOLTAGE_DIVIDER(rc[1], rc2[0]); + /* DST_RCDISC_MOD__IN1 <= 0.5 && DST_RCDISC_MOD__IN2 > 0.6 */ + m_exp_high[2] = RC_DISCHARGE_EXP(DST_RCDISC_MOD__C * (rc[0] + rc2[1])); + m_vd_gain[2] = RES_VOLTAGE_DIVIDER(rc[0], rc2[1]); + /* DST_RCDISC_MOD__IN1 > 0.5 && DST_RCDISC_MOD__IN2 > 0.6 */ + m_exp_high[3] = RC_DISCHARGE_EXP(DST_RCDISC_MOD__C * (rc[1] + rc2[1])); + m_vd_gain[3] = RES_VOLTAGE_DIVIDER(rc[1], rc2[1]); + + m_v_cap = 0; + set_output(0, 0); +} + +/************************************************************************ + * + * DST_RCFILTER - Usage of node_description values for RC filter + * + * input[0] - Enable input value + * input[1] - input value + * input[2] - Resistor value (initialization only) + * input[3] - Capacitor Value (initialization only) + * input[4] - Voltage reference. Usually 0V. + * + ************************************************************************/ +#define DST_RCFILTER__VIN DISCRETE_INPUT(0) +#define DST_RCFILTER__R DISCRETE_INPUT(1) +#define DST_RCFILTER__C DISCRETE_INPUT(2) +#define DST_RCFILTER__VREF DISCRETE_INPUT(3) + +DISCRETE_STEP(dst_rcfilter) +{ + if (EXPECTED(m_is_fast)) + m_v_out += ((DST_RCFILTER__VIN - m_v_out) * m_exponent); + else + { + if (UNEXPECTED(m_has_rc_nodes)) + { + double rc = DST_RCFILTER__R * DST_RCFILTER__C; + if (rc != m_rc) + { + m_rc = rc; + m_exponent = RC_CHARGE_EXP(rc); + } + } + + /************************************************************************/ + /* Next Value = PREV + (INPUT_VALUE - PREV)*(1-(EXP(-TIMEDELTA/RC))) */ + /************************************************************************/ + + m_vCap += ((DST_RCFILTER__VIN - m_v_out) * m_exponent); + m_v_out = m_vCap + DST_RCFILTER__VREF; + } + set_output(0, m_v_out); +} + + +DISCRETE_RESET(dst_rcfilter) +{ + m_has_rc_nodes = this->input_is_node() & 0x6; + m_rc = DST_RCFILTER__R * DST_RCFILTER__C; + m_exponent = RC_CHARGE_EXP(m_rc); + m_vCap = 0; + m_v_out = 0; + /* FIXME --> we really need another class here */ + if (!m_has_rc_nodes && DST_RCFILTER__VREF == 0) + m_is_fast = 1; + else + m_is_fast = 0; +} + +/************************************************************************ + * + * DST_RCFILTER_SW - Usage of node_description values for switchable RC filter + * + * input[0] - Enable input value + * input[1] - input value + * input[2] - Resistor value (initialization only) + * input[3] - Capacitor Value (initialization only) + * input[4] - Voltage reference. Usually 0V. + * + ************************************************************************/ +#define DST_RCFILTER_SW__ENABLE DISCRETE_INPUT(0) +#define DST_RCFILTER_SW__VIN DISCRETE_INPUT(1) +#define DST_RCFILTER_SW__SWITCH DISCRETE_INPUT(2) +#define DST_RCFILTER_SW__R DISCRETE_INPUT(3) +#define DST_RCFILTER_SW__C(x) DISCRETE_INPUT(4+x) + +/* 74HC4066 : 15 + * 74VHC4066 : 15 + * UTC4066 : 270 @ 5VCC, 80 @ 15VCC + * CD4066BC : 270 (Fairchild) + * + * The choice below makes scramble sound about "right". For future error reports, + * we need the exact type of switch and at which voltage (5, 12?) it is operated. + */ +#define CD4066_ON_RES (40) + +// FIXME: This needs optimization ! +DISCRETE_STEP(dst_rcfilter_sw) +{ + int i; + int bits = (int)DST_RCFILTER_SW__SWITCH; + double us = 0; + double vIn = DST_RCFILTER_SW__VIN; + double v_out; + + if (EXPECTED(DST_RCFILTER_SW__ENABLE)) + { + switch (bits) + { + case 0: + v_out = vIn; + break; + case 1: + m_vCap[0] += (vIn - m_vCap[0]) * m_exp0; + v_out = m_vCap[0] + (vIn - m_vCap[0]) * m_factor; + break; + case 2: + m_vCap[1] += (vIn - m_vCap[1]) * m_exp1; + v_out = m_vCap[1] + (vIn - m_vCap[1]) * m_factor; + break; + default: + for (i = 0; i < 4; i++) + { + if (( bits & (1 << i)) != 0) + us += m_vCap[i]; + } + v_out = m_f1[bits] * vIn + m_f2[bits] * us; + for (i = 0; i < 4; i++) + { + if (( bits & (1 << i)) != 0) + m_vCap[i] += (v_out - m_vCap[i]) * m_exp[i]; + } + } + set_output(0, v_out); + } + else + { + set_output(0, 0); + } +} + +DISCRETE_RESET(dst_rcfilter_sw) +{ + int i, bits; + + for (i = 0; i < 4; i++) + { + m_vCap[i] = 0; + m_exp[i] = RC_CHARGE_EXP( CD4066_ON_RES * DST_RCFILTER_SW__C(i)); + } + + for (bits=0; bits < 15; bits++) + { + double rs = 0; + + for (i = 0; i < 4; i++) + { + if (( bits & (1 << i)) != 0) + rs += DST_RCFILTER_SW__R; + } + m_f1[bits] = RES_VOLTAGE_DIVIDER(rs, CD4066_ON_RES); + m_f2[bits] = DST_RCFILTER_SW__R / (CD4066_ON_RES + rs); + } + + + /* fast cases */ + m_exp0 = RC_CHARGE_EXP((CD4066_ON_RES + DST_RCFILTER_SW__R) * DST_RCFILTER_SW__C(0)); + m_exp1 = RC_CHARGE_EXP((CD4066_ON_RES + DST_RCFILTER_SW__R) * DST_RCFILTER_SW__C(1)); + m_factor = RES_VOLTAGE_DIVIDER(DST_RCFILTER_SW__R, CD4066_ON_RES); + + set_output(0, 0); +} + + +/************************************************************************ + * + * DST_RCINTEGRATE - Two diode inputs, transistor and a R/C charge + * discharge network + * + * input[0] - Enable input value + * input[1] - input value 1 + * input[2] - input value 2 + * input[3] - Resistor 1 value (initialization only) + * input[4] - Resistor 2 value (initialization only) + * input[5] - Capacitor Value (initialization only) + * + ************************************************************************/ +#define DST_RCINTEGRATE__IN1 DISCRETE_INPUT(0) +#define DST_RCINTEGRATE__R1 DISCRETE_INPUT(1) +#define DST_RCINTEGRATE__R2 DISCRETE_INPUT(2) +#define DST_RCINTEGRATE__R3 DISCRETE_INPUT(3) +#define DST_RCINTEGRATE__C DISCRETE_INPUT(4) +#define DST_RCINTEGRATE__VP DISCRETE_INPUT(5) +#define DST_RCINTEGRATE__TYPE DISCRETE_INPUT(6) + +/* Ebers-Moll large signal model + * Couriersud: + * The implementation avoids all iterative approaches in order not to burn cycles + * We will calculate Ic from vBE and use this as an indication where to go. + * The implementation may oscillate if you change the weighting factors at the + * end. + * + * This implementation is not perfect, but does it's job in dkong' + */ + +/* reverse saturation current */ +#define IES 7e-15 +#define ALPHAT 0.99 +#define KT 0.026 +#define EM_IC(x) (ALPHAT * IES * exp( (x) / KT - 1.0 )) + +DISCRETE_STEP( dst_rcintegrate) +{ + double diff, u, iQ, iQc, iC, RG, vE; + double vP; + + u = DST_RCINTEGRATE__IN1; + vP = DST_RCINTEGRATE__VP; + + if ( u - 0.7 < m_vCap * m_gain_r1_r2) + { + /* discharge .... */ + diff = 0.0 - m_vCap; + iC = m_c_exp1 * diff; /* iC */ + diff -= diff * m_exp_exponent1; + m_vCap += diff; + iQ = 0; + vE = m_vCap * m_gain_r1_r2; + RG = vE / iC; + } + else + { + /* charging */ + diff = (vP - m_vCE) * m_f - m_vCap; + iC = 0.0 - m_c_exp0 * diff; /* iC */ + diff -= diff * m_exp_exponent0; + m_vCap += diff; + iQ = iC + (iC * DST_RCINTEGRATE__R1 + m_vCap) / DST_RCINTEGRATE__R2; + RG = (vP - m_vCE) / iQ; + vE = (RG - DST_RCINTEGRATE__R3) / RG * (vP - m_vCE); + } + + + u = DST_RCINTEGRATE__IN1; + if (u > 0.7 + vE) + { + vE = u - 0.7; + //iQc = EM_IC(u - vE); + iQc = m_EM_IC_0_7; + } + else + iQc = EM_IC(u - vE); + + m_vCE = MIN(vP - 0.1, vP - RG * iQc); + + /* Avoid oscillations + * The method tends to largely overshoot - no wonder without + * iterative solution approximation + */ + + m_vCE = MAX(m_vCE, 0.1 ); + m_vCE = 0.1 * m_vCE + 0.9 * (vP - vE - iQ * DST_RCINTEGRATE__R3); + + switch (m_type) + { + case DISC_RC_INTEGRATE_TYPE1: + set_output(0, m_vCap); + break; + case DISC_RC_INTEGRATE_TYPE2: + set_output(0, vE); + break; + case DISC_RC_INTEGRATE_TYPE3: + set_output(0, MAX(0, vP - iQ * DST_RCINTEGRATE__R3)); + break; + } +} + +DISCRETE_RESET(dst_rcintegrate) +{ + double r; + double dt = this->sample_time(); + + m_type = DST_RCINTEGRATE__TYPE; + + m_vCap = 0; + m_vCE = 0; + + /* pre-calculate fixed values */ + m_gain_r1_r2 = RES_VOLTAGE_DIVIDER(DST_RCINTEGRATE__R1, DST_RCINTEGRATE__R2); + + r = DST_RCINTEGRATE__R1 / DST_RCINTEGRATE__R2 * DST_RCINTEGRATE__R3 + DST_RCINTEGRATE__R1 + DST_RCINTEGRATE__R3; + + m_f = RES_VOLTAGE_DIVIDER(DST_RCINTEGRATE__R3, DST_RCINTEGRATE__R2); + m_exponent0 = -1.0 * r * m_f * DST_RCINTEGRATE__C; + m_exponent1 = -1.0 * (DST_RCINTEGRATE__R1 + DST_RCINTEGRATE__R2) * DST_RCINTEGRATE__C; + m_exp_exponent0 = exp(dt / m_exponent0); + m_exp_exponent1 = exp(dt / m_exponent1); + m_c_exp0 = DST_RCINTEGRATE__C / m_exponent0 * m_exp_exponent0; + m_c_exp1 = DST_RCINTEGRATE__C / m_exponent1 * m_exp_exponent1; + + m_EM_IC_0_7 = EM_IC(0.7); + + set_output(0, 0); +} + +/************************************************************************ + * + * DST_SALLEN_KEY - Sallen-Key filter circuit + * + * input[0] - Enable input value + * input[1] - IN0 node + * input[3] - Filter Type + * + * also passed discrete_op_amp_filt_info structure + * + * 2008, couriersud + ************************************************************************/ +#define DST_SALLEN_KEY__ENABLE DISCRETE_INPUT(0) +#define DST_SALLEN_KEY__INP0 DISCRETE_INPUT(1) +#define DST_SALLEN_KEY__TYPE DISCRETE_INPUT(2) + +DISCRETE_STEP(dst_sallen_key) +{ + double gain = 1.0; + double v_out; + + if (DST_SALLEN_KEY__ENABLE == 0.0) + { + gain = 0.0; + } + + v_out = -m_fc.a1 * m_fc.y1 - m_fc.a2 * m_fc.y2 + + m_fc.b0 * gain * DST_SALLEN_KEY__INP0 + m_fc.b1 * m_fc.x1 + m_fc.b2 * m_fc.x2; + + m_fc.x2 = m_fc.x1; + m_fc.x1 = gain * DST_SALLEN_KEY__INP0; + m_fc.y2 = m_fc.y1; + m_fc.y1 = v_out; + set_output(0, v_out); +} + +DISCRETE_RESET(dst_sallen_key) +{ + DISCRETE_DECLARE_INFO(discrete_op_amp_filt_info) + + double freq, q; + + switch ((int) DST_SALLEN_KEY__TYPE) + { + case DISC_SALLEN_KEY_LOW_PASS: + freq = 1.0 / ( 2.0 * M_PI * sqrt(info->c1 * info->c2 * info->r1 * info->r2)); + q = sqrt(info->c1 * info->c2 * info->r1 * info->r2) / (info->c2 * (info->r1 + info->r2)); + break; + default: + fatalerror("Unknown sallen key filter type\n"); + } + + calculate_filter2_coefficients(this, freq, 1.0 / q, DISC_FILTER_LOWPASS, m_fc); + set_output(0, 0); +} + + +/* !!!!!!!!!!! NEW FILTERS for testing !!!!!!!!!!!!!!!!!!!!! */ + + +/************************************************************************ + * + * DST_RCFILTERN - Usage of node_description values for RC filter + * + * input[0] - Enable input value + * input[1] - input value + * input[2] - Resistor value (initialization only) + * input[3] - Capacitor Value (initialization only) + * + ************************************************************************/ +#define DST_RCFILTERN__ENABLE DISCRETE_INPUT(0) +#define DST_RCFILTERN__IN DISCRETE_INPUT(1) +#define DST_RCFILTERN__R DISCRETE_INPUT(2) +#define DST_RCFILTERN__C DISCRETE_INPUT(3) + +#if 0 +DISCRETE_RESET(dst_rcfilterN) +{ +#if 0 + double f=1.0/(2*M_PI* DST_RCFILTERN__R * DST_RCFILTERN__C); + +/* !!!!!!!!!!!!!! CAN'T CHEAT LIKE THIS !!!!!!!!!!!!!!!! */ +/* Put this stuff in a context */ + + this->m_input[2] = f; + this->m_input[3] = DISC_FILTER_LOWPASS; + + /* Use first order filter */ + dst_filter1_reset(node); +#endif +} +#endif + +/************************************************************************ + * + * DST_RCDISCN - Usage of node_description values for RC discharge + * (inverse slope of DST_RCFILTER) + * + * input[0] - Enable input value + * input[1] - input value + * input[2] - Resistor value (initialization only) + * input[3] - Capacitor Value (initialization only) + * + ************************************************************************/ +#define DST_RCDISCN__ENABLE DISCRETE_INPUT(0) +#define DST_RCDISCN__IN DISCRETE_INPUT(1) +#define DST_RCDISCN__R DISCRETE_INPUT(2) +#define DST_RCDISCN__C DISCRETE_INPUT(3) + +DISCRETE_RESET(dst_rcdiscN) +{ +#if 0 + double f = 1.0 / (2 * M_PI * DST_RCDISCN__R * DST_RCDISCN__C); + +/* !!!!!!!!!!!!!! CAN'T CHEAT LIKE THIS !!!!!!!!!!!!!!!! */ +/* Put this stuff in a context */ + + this->m_input[2] = f; + this->m_input[3] = DISC_FILTER_LOWPASS; + + /* Use first order filter */ + dst_filter1_reset(node); +#endif +} + +DISCRETE_STEP(dst_rcdiscN) +{ + double gain = 1.0; + double v_out; + + if (DST_RCDISCN__ENABLE == 0.0) + { + gain = 0.0; + } + + /* A rise in the input signal results in an instant charge, */ + /* else discharge through the RC to zero */ + if (gain* DST_RCDISCN__IN > m_x1) + v_out = gain* DST_RCDISCN__IN; + else + v_out = -m_a1*m_y1; + + m_x1 = gain* DST_RCDISCN__IN; + m_y1 = v_out; + set_output(0, v_out); +} + + +/************************************************************************ + * + * DST_RCDISC2N - Usage of node_description values for RC discharge + * Has switchable charge resistor/input + * + * input[0] - Switch input value + * input[1] - input[0] value + * input[2] - Resistor0 value (initialization only) + * input[3] - input[1] value + * input[4] - Resistor1 value (initialization only) + * input[5] - Capacitor Value (initialization only) + * + ************************************************************************/ +#define DST_RCDISC2N__ENABLE DISCRETE_INPUT(0) +#define DST_RCDISC2N__IN0 DISCRETE_INPUT(1) +#define DST_RCDISC2N__R0 DISCRETE_INPUT(2) +#define DST_RCDISC2N__IN1 DISCRETE_INPUT(3) +#define DST_RCDISC2N__R1 DISCRETE_INPUT(4) +#define DST_RCDISC2N__C DISCRETE_INPUT(5) + + +DISCRETE_STEP(dst_rcdisc2N) +{ + double inp = ((DST_RCDISC2N__ENABLE == 0) ? DST_RCDISC2N__IN0 : DST_RCDISC2N__IN1); + double v_out; + + if (DST_RCDISC2N__ENABLE == 0) + v_out = -m_fc0.a1*m_y1 + m_fc0.b0*inp + m_fc0.b1 * m_x1; + else + v_out = -m_fc1.a1*m_y1 + m_fc1.b0*inp + m_fc1.b1*m_x1; + + m_x1 = inp; + m_y1 = v_out; + set_output(0, v_out); +} + +DISCRETE_RESET(dst_rcdisc2N) +{ + double f1,f2; + + f1 = 1.0 / (2 * M_PI * DST_RCDISC2N__R0 * DST_RCDISC2N__C); + f2 = 1.0 / (2 * M_PI * DST_RCDISC2N__R1 * DST_RCDISC2N__C); + + calculate_filter1_coefficients(this, f1, DISC_FILTER_LOWPASS, m_fc0); + calculate_filter1_coefficients(this, f2, DISC_FILTER_LOWPASS, m_fc1); + + /* Initialize the object */ + set_output(0, 0); +} diff --git a/src/devices/sound/disc_inp.inc b/src/devices/sound/disc_inp.inc new file mode 100644 index 00000000000..b9eedb9fdff --- /dev/null +++ b/src/devices/sound/disc_inp.inc @@ -0,0 +1,325 @@ +// license:BSD-3-Clause +// copyright-holders:K.Wilkins +/************************************************************************ + * + * MAME - Discrete sound system emulation library + * + * Written by K.Wilkins (mame@esplexo.co.uk) + * + * (c) K.Wilkins 2000 + * + *********************************************************************** + * + * DSS_ADJUSTMENT - UI Mapped adjustable input + * DSS_CONSTANT - Node based constant - Do we need this ??? + * DSS_INPUT_x - Input devices + * DSS_INPUT_STREAM - Connects external streams to the discrete system + * + ************************************************************************/ + + +#define DSS_INPUT__GAIN DISCRETE_INPUT(0) +#define DSS_INPUT__OFFSET DISCRETE_INPUT(1) +#define DSS_INPUT__INIT DISCRETE_INPUT(2) + +/************************************************************************ + * + * DSS_ADJUSTMENT - UI Adjustable constant node to emulate trimmers + * + * input[0] - Enable + * input[1] - Minimum value + * input[2] - Maximum value + * input[3] - Log/Linear 0=Linear !0=Log + * input[4] - Input Port number + * input[5] - + * input[6] - + * + ************************************************************************/ +#define DSS_ADJUSTMENT__MIN DISCRETE_INPUT(0) +#define DSS_ADJUSTMENT__MAX DISCRETE_INPUT(1) +#define DSS_ADJUSTMENT__LOG DISCRETE_INPUT(2) +#define DSS_ADJUSTMENT__PORT DISCRETE_INPUT(3) +#define DSS_ADJUSTMENT__PMIN DISCRETE_INPUT(4) +#define DSS_ADJUSTMENT__PMAX DISCRETE_INPUT(5) + +DISCRETE_STEP(dss_adjustment) +{ + INT32 rawportval = m_port->read(); + + /* only recompute if the value changed from last time */ + if (UNEXPECTED(rawportval != m_lastpval)) + { + double portval = (double)(rawportval - m_pmin) * m_pscale; + double scaledval = portval * m_scale + m_min; + + m_lastpval = rawportval; + if (DSS_ADJUSTMENT__LOG == 0) + set_output(0, scaledval); + else + set_output(0, pow(10, scaledval)); + } +} + +DISCRETE_RESET(dss_adjustment) +{ + double min, max; + + m_port = m_device->machine().root_device().ioport(m_device->siblingtag((const char *)this->custom_data()).c_str()); + if (m_port == NULL) + fatalerror("DISCRETE_ADJUSTMENT - NODE_%d has invalid tag\n", this->index()); + + m_lastpval = 0x7fffffff; + m_pmin = DSS_ADJUSTMENT__PMIN; + m_pscale = 1.0 / (double)(DSS_ADJUSTMENT__PMAX - DSS_ADJUSTMENT__PMIN); + + /* linear scale */ + if (DSS_ADJUSTMENT__LOG == 0) + { + m_min = DSS_ADJUSTMENT__MIN; + m_scale = DSS_ADJUSTMENT__MAX - DSS_ADJUSTMENT__MIN; + } + + /* logarithmic scale */ + else + { + /* force minimum and maximum to be > 0 */ + min = (DSS_ADJUSTMENT__MIN > 0) ? DSS_ADJUSTMENT__MIN : 1; + max = (DSS_ADJUSTMENT__MAX > 0) ? DSS_ADJUSTMENT__MAX : 1; + m_min = log10(min); + m_scale = log10(max) - log10(min); + } + + this->step(); +} + + +/************************************************************************ + * + * DSS_CONSTANT - This is a constant. + * + * input[0] - Constant value + * + ************************************************************************/ +#define DSS_CONSTANT__INIT DISCRETE_INPUT(0) + +DISCRETE_RESET(dss_constant) +{ + set_output(0, DSS_CONSTANT__INIT); +} + + +/************************************************************************ + * + * DSS_INPUT_x - Receives input from discrete_sound_w + * + * input[0] - Gain value + * input[1] - Offset value + * input[2] - Starting Position + * input[3] - Current data value + * + ************************************************************************/ + +DISCRETE_RESET(dss_input_data) +{ + m_gain = DSS_INPUT__GAIN; + m_offset = DSS_INPUT__OFFSET; + + m_data = DSS_INPUT__INIT; + set_output(0, m_data * m_gain + m_offset); +} + +void DISCRETE_CLASS_FUNC(dss_input_data, input_write)(int sub_node, UINT8 data ) +{ + UINT8 new_data = 0; + + new_data = data; + + if (m_data != new_data) + { + /* Bring the system up to now */ + m_device->update_to_current_time(); + + m_data = new_data; + + /* Update the node output here so we don't have to do it each step */ + set_output(0, m_data * m_gain + m_offset); + } +} + +DISCRETE_RESET(dss_input_logic) +{ + m_gain = DSS_INPUT__GAIN; + m_offset = DSS_INPUT__OFFSET; + + m_data = (DSS_INPUT__INIT == 0) ? 0 : 1; + set_output(0, m_data * m_gain + m_offset); +} + +void DISCRETE_CLASS_FUNC(dss_input_logic, input_write)(int sub_node, UINT8 data ) +{ + UINT8 new_data = 0; + + new_data = data ? 1 : 0; + + if (m_data != new_data) + { + /* Bring the system up to now */ + m_device->update_to_current_time(); + + m_data = new_data; + + /* Update the node output here so we don't have to do it each step */ + set_output(0, m_data * m_gain + m_offset); + } +} + +DISCRETE_RESET(dss_input_not) +{ + m_gain = DSS_INPUT__GAIN; + m_offset = DSS_INPUT__OFFSET; + + m_data = (DSS_INPUT__INIT == 0) ? 1 : 0; + set_output(0, m_data * m_gain + m_offset); +} + +void DISCRETE_CLASS_FUNC(dss_input_not, input_write)(int sub_node, UINT8 data ) +{ + UINT8 new_data = 0; + + new_data = data ? 0 : 1; + + if (m_data != new_data) + { + /* Bring the system up to now */ + m_device->update_to_current_time(); + + m_data = new_data; + + /* Update the node output here so we don't have to do it each step */ + set_output(0, m_data * m_gain + m_offset); + } +} + +DISCRETE_STEP(dss_input_pulse) +{ + /* Set a valid output */ + set_output(0, m_data); + /* Reset the input to default for the next cycle */ + /* node order is now important */ + m_data = DSS_INPUT__INIT; +} + +DISCRETE_RESET(dss_input_pulse) +{ + m_data = (DSS_INPUT__INIT == 0) ? 0 : 1; + set_output(0, m_data); +} + +void DISCRETE_CLASS_FUNC(dss_input_pulse, input_write)(int sub_node, UINT8 data ) +{ + UINT8 new_data = 0; + + new_data = data ? 1 : 0; + + if (m_data != new_data) + { + /* Bring the system up to now */ + m_device->update_to_current_time(); + m_data = new_data; + } +} + +/************************************************************************ + * + * DSS_INPUT_STREAM - Receives input from a routed stream + * + * input[0] - Input stream number + * input[1] - Gain value + * input[2] - Offset value + * + ************************************************************************/ +#define DSS_INPUT_STREAM__STREAM DISCRETE_INPUT(0) +#define DSS_INPUT_STREAM__GAIN DISCRETE_INPUT(1) +#define DSS_INPUT_STREAM__OFFSET DISCRETE_INPUT(2) + +void discrete_dss_input_stream_node::stream_generate(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + stream_sample_t *ptr = outputs[0]; + int samplenum = samples; + + while (samplenum-- > 0) + *(ptr++) = m_data; +} +DISCRETE_STEP(dss_input_stream) +{ + /* the context pointer is set to point to the current input stream data in discrete_stream_update */ + if (EXPECTED(m_ptr)) + { + set_output(0, (*m_ptr) * m_gain + m_offset); + m_ptr++; + } + else + set_output(0, 0); +} + +DISCRETE_RESET(dss_input_stream) +{ + m_ptr = NULL; + m_data = 0; +} + +void DISCRETE_CLASS_FUNC(dss_input_stream, input_write)(int sub_node, UINT8 data ) +{ + UINT8 new_data = 0; + + new_data = data; + + if (m_data != new_data) + { + if (m_is_buffered) + { + /* Bring the system up to now */ + m_buffer_stream->update(); + + m_data = new_data; + } + else + { + /* Bring the system up to now */ + m_device->update_to_current_time(); + + m_data = new_data; + + /* Update the node output here so we don't have to do it each step */ + set_output(0, new_data * m_gain + m_offset); + } + } +} + +DISCRETE_START(dss_input_stream) +{ + discrete_base_node::start(); + + /* Stream out number is set during start */ + m_stream_in_number = DSS_INPUT_STREAM__STREAM; + m_gain = DSS_INPUT_STREAM__GAIN; + m_offset = DSS_INPUT_STREAM__OFFSET; + m_ptr = NULL; + + m_is_buffered = is_buffered(); + m_buffer_stream = NULL; +} + +void DISCRETE_CLASS_NAME(dss_input_stream)::stream_start(void) +{ + if (m_is_buffered) + { + /* stream_buffered input only supported for sound devices */ + discrete_sound_device *snd_device = downcast(m_device); + //assert(DSS_INPUT_STREAM__STREAM < snd_device->m_input_stream_list.count()); + + m_buffer_stream = m_device->machine().sound().stream_alloc(*snd_device, 0, 1, this->sample_rate(), stream_update_delegate(FUNC(discrete_dss_input_stream_node::stream_generate),this)); + + snd_device->get_stream()->set_input(m_stream_in_number, m_buffer_stream); + } +} diff --git a/src/devices/sound/disc_mth.h b/src/devices/sound/disc_mth.h new file mode 100644 index 00000000000..a459440a3b6 --- /dev/null +++ b/src/devices/sound/disc_mth.h @@ -0,0 +1,240 @@ +// license:BSD-3-Clause +// copyright-holders:K.Wilkins +#pragma once + +#ifndef __DISC_MTH_H__ +#define __DISC_MTH_H__ + +/*********************************************************************** + * + * MAME - Discrete sound system emulation library + * + * Written by K.Wilkins (mame@esplexo.co.uk) + * + * (c) K.Wilkins 2000 + * + * Coding started in November 2000 + * + * Additions/bugfix February 2003 - Derrick Renaud, F.Palazzolo, K.Wilkins + * Discrete parallel tasks 2009 - Couriersud + * Discrete classes 2010 - Couriersud + * + ***********************************************************************/ + +#include "discrete.h" + +DISCRETE_CLASS_STEP(dst_adder, 1, /* no context */ ); + +DISCRETE_CLASS_STEP(dst_clamp, 1, /* no context */ ); + +DISCRETE_CLASS_STEP(dst_divide, 1, /* no context */ ); + +DISCRETE_CLASS_STEP(dst_gain, 1, /* no context */ ); + +DISCRETE_CLASS_STEP(dst_logic_inv, 1, /* no context */ ); + +DISCRETE_CLASS_STEP_RESET(dst_bits_decode, 8, + int m_count; + int m_decode_x_time; + int m_from; + int m_last_val; + int m_last_had_x_time; +); + +DISCRETE_CLASS_STEP(dst_logic_and, 1, /* no context */ ); + +DISCRETE_CLASS_STEP(dst_logic_nand, 1, /* no context */ ); + +DISCRETE_CLASS_STEP(dst_logic_or, 1, /* no context */ ); + +DISCRETE_CLASS_STEP(dst_logic_nor, 1, /* no context */ ); + +DISCRETE_CLASS_STEP(dst_logic_xor, 1, /* no context */ ); + +DISCRETE_CLASS_STEP(dst_logic_nxor, 1, /* no context */ ); + +DISCRETE_CLASS_STEP_RESET(dst_logic_dff, 1, + int m_last_clk; +); + +DISCRETE_CLASS_STEP_RESET(dst_logic_jkff, 1, + double m_v_out; + int m_last_clk; +); + +DISCRETE_CLASS_STEP_RESET(dst_logic_shift, 1, + double m_t_left; /* time unused during last sample in seconds */ + UINT32 m_shift_data; + UINT32 m_bit_mask; + UINT8 m_clock_type; + UINT8 m_reset_on_high; + UINT8 m_shift_r; + UINT8 m_last; +); + +DISCRETE_CLASS_STEP(dst_lookup_table, 1, /* no context */ ); + +DISCRETE_CLASS_STEP_RESET(dst_multiplex, 1, + int m_size; +); + +DISCRETE_CLASS_STEP_RESET(dst_oneshot, 1, + double m_countdown; + int m_state; + int m_last_trig; + int m_type; +); + +DISCRETE_CLASS_STEP_RESET(dst_ramp, 1, + double m_v_out; + double m_step; + int m_dir; /* 1 if End is higher then Start */ + int m_last_en; /* Keep track of the last enable value */ +); + +DISCRETE_CLASS_STEP_RESET(dst_samphold, 1, + double m_last_input; + int m_clocktype; +); + +DISCRETE_CLASS_STEP(dst_switch, 1, /* no context */ ); + +DISCRETE_CLASS_STEP(dst_aswitch, 1, /* no context */ ); + +DISCRETE_CLASS_STEP(, 1, /* no context */ ); +class DISCRETE_CLASS_NAME(dst_transform): public discrete_base_node, public discrete_step_interface +{ + DISCRETE_CLASS_CONSTRUCTOR(dst_transform, base) + DISCRETE_CLASS_DESTRUCTOR(dst_transform) +public: + enum token { + TOK_END = 0, + TOK_MULT, + TOK_DIV, + TOK_ADD, + TOK_MINUS, + TOK_0, + TOK_1, + TOK_2, + TOK_3, + TOK_4, + TOK_DUP, + TOK_ABS, /* absolute value */ + TOK_NEG, /* * -1 */ + TOK_NOT, /* Logical NOT of Last Value */ + TOK_EQUAL, /* Logical = */ + TOK_GREATER, /* Logical > */ + TOK_LESS, /* Logical < */ + TOK_AND, /* Bitwise AND */ + TOK_OR, /* Bitwise OR */ + TOK_XOR /* Bitwise XOR */ + }; + void step(void); + void reset(void); +protected: +private: + DISCRETE_CLASS_INPUT(I_IN0, 0); + DISCRETE_CLASS_INPUT(I_IN1, 1); + DISCRETE_CLASS_INPUT(I_IN2, 2); + DISCRETE_CLASS_INPUT(I_IN3, 3); + DISCRETE_CLASS_INPUT(I_IN4, 4); + enum token precomp[32]; +}; + +/* Component specific */ + +DISCRETE_CLASS_STEP_RESET(dst_comp_adder, 1, + double m_total[256]; +); + +DISCRETE_CLASS_STEP_RESET(dst_dac_r1, 1, + double m_v_out; + double m_exponent; + double m_last_v; + double m_v_step[256]; + int m_has_c_filter; +); + +DISCRETE_CLASS_STEP_RESET(dst_diode_mix, 1, + int m_size; + double m_v_junction[8]; +); + +DISCRETE_CLASS_STEP_RESET(dst_integrate, 1, + double m_v_out; + double m_change; + double m_v_max_in; /* v1 - norton VBE */ + double m_v_max_in_d; /* v1 - norton VBE - diode drop */ + double m_v_max_out; +); + +#define DISC_MIXER_MAX_INPS 8 +DISCRETE_CLASS_STEP_RESET(dst_mixer, 1, + int m_type; + int m_size; + int m_r_node_bit_flag; + int m_c_bit_flag; + double m_r_total; + const double * m_r_node[DISC_MIXER_MAX_INPS]; /* Either pointer to resistance node output OR NULL */ + double m_r_last[DISC_MIXER_MAX_INPS]; + double m_exponent_rc[DISC_MIXER_MAX_INPS]; /* For high pass filtering cause by cIn */ + double m_v_cap[DISC_MIXER_MAX_INPS]; /* cap voltage of each input */ + double m_exponent_c_f; /* Low pass on mixed inputs */ + double m_exponent_c_amp; /* Final high pass caused by out cap and amp input impedance */ + double m_v_cap_f; /* cap voltage of cF */ + double m_v_cap_amp; /* cap voltage of cAmp */ + double m_gain; /* used for DISC_MIXER_IS_OP_AMP_WITH_RI */ +); + +DISCRETE_CLASS_STEP_RESET(dst_op_amp, 1, + UINT8 m_has_cap; + UINT8 m_has_r1; + UINT8 m_has_r4; + double m_v_max; + double m_i_fixed; + double m_v_cap; + double m_exponent; +); + +DISCRETE_CLASS_STEP_RESET(dst_op_amp_1sht, 1, + double m_v_out; + double m_i_fixed; + double m_v_max; + double m_r34ratio; + double m_v_cap1; + double m_v_cap2; + double m_exponent1c; + double m_exponent1d; + double m_exponent2; +); + +DISCRETE_CLASS_STEP_RESET(dst_tvca_op_amp, 1, + double m_v_out_max; /* Maximum output voltage */ + double m_v_trig[2]; /* Voltage used to charge cap1 based on function F3 */ + double m_v_trig2; /* Voltage used to charge cap2 */ + double m_v_trig3; /* Voltage used to charge cap3 */ + double m_i_fixed; /* Fixed current going into - input */ + double m_exponent_c[2]; /* Charge exponents based on function F3 */ + double m_exponent_d[2]; /* Discharge exponents based on function F3 */ + double m_exponent2[2]; /* Discharge/charge exponents based on function F4 */ + double m_exponent3[2]; /* Discharge/charge exponents based on function F5 */ + double m_exponent4; /* Discharge/charge exponents for c4 */ + double m_v_cap1; /* charge on cap c1 */ + double m_v_cap2; /* charge on cap c2 */ + double m_v_cap3; /* charge on cap c3 */ + double m_v_cap4; /* charge on cap c4 */ + double m_r67; /* = r6 + r7 (for easy use later) */ + UINT8 m_has_c4; + UINT8 m_has_r4; +); + +DISCRETE_CLASS_STEP(dst_xtime_buffer, 1, /* no context */ ); + +DISCRETE_CLASS_STEP(dst_xtime_and, 1, /* no context */ ); + +DISCRETE_CLASS_STEP(dst_xtime_or, 1, /* no context */ ); + +DISCRETE_CLASS_STEP(dst_xtime_xor, 1, /* no context */ ); + + +#endif /* __DISC_WAV_H__ */ diff --git a/src/devices/sound/disc_mth.inc b/src/devices/sound/disc_mth.inc new file mode 100644 index 00000000000..45e04654445 --- /dev/null +++ b/src/devices/sound/disc_mth.inc @@ -0,0 +1,2773 @@ +// license:BSD-3-Clause +// copyright-holders:K.Wilkins +/************************************************************************ + * + * MAME - Discrete sound system emulation library + * + * Written by K.Wilkins (mame@esplexo.co.uk) + * + * (c) K.Wilkins 2000 + * (c) Derrick Renaud 2003-2004 + * + ************************************************************************ + * + * DST_ADDDER - Multichannel adder + * DST_BITS_DECODE - Decode Bits from input node + * DST_CLAMP - Simple signal clamping circuit + * DST_COMP_ADDER - Selectable parallel component circuit + * DST_DAC_R1 - R1 Ladder DAC with cap filtering + * DST_DIODE_MIX - Diode mixer + * DST_DIVIDE - Division function + * DST_GAIN - Gain Factor + * DST_INTEGRATE - Integration circuits + * DST_LOGIC_INV - Logic level invertor + * DST_LOGIC_AND - Logic AND gate 4 input + * DST_LOGIC_NAND - Logic NAND gate 4 input + * DST_LOGIC_OR - Logic OR gate 4 input + * DST_LOGIC_NOR - Logic NOR gate 4 input + * DST_LOGIC_XOR - Logic XOR gate 2 input + * DST_LOGIC_NXOR - Logic NXOR gate 2 input + * DST_LOGIC_DFF - Logic D-type flip/flop + * DST_LOGIC_JKFF - Logic JK-type flip/flop + * DST_LOGIC_SHIFT - Logic Shift Register + * DST_LOOKUP_TABLE - Return value from lookup table + * DST_MIXER - Final Mixer Stage + * DST_MULTIPLEX - 1 of x Multiplexer/switch + * DST_ONESHOT - One shot pulse generator + * DST_RAMP - Ramp up/down + * DST_SAMPHOLD - Sample & Hold Implementation + * DST_SWITCH - Switch implementation + * DST_ASWITCH - Analog switch + * DST_TRANSFORM - Multiple math functions + * DST_OP_AMP - Op Amp circuits + * DST_OP_AMP_1SHT - Op Amp One Shot + * DST_TVCA_OP_AMP - Triggered op amp voltage controlled amplifier + * DST_XTIME_BUFFER - Buffer/Invertor gate implementation using X_TIME + * DST_XTIME_AND - AND/NAND gate implementation using X_TIME + * DST_XTIME_OR - OR/NOR gate implementation using X_TIME + * DST_XTIME_XOR - XOR/XNOR gate implementation using X_TIME + * + ************************************************************************/ + +#include + + + +/************************************************************************ + * + * DST_ADDER - This is a 4 channel input adder with enable function + * + * input[0] - Enable input value + * input[1] - Channel0 input value + * input[2] - Channel1 input value + * input[3] - Channel2 input value + * input[4] - Channel3 input value + * + ************************************************************************/ +#define DST_ADDER__ENABLE DISCRETE_INPUT(0) +#define DST_ADDER__IN0 DISCRETE_INPUT(1) +#define DST_ADDER__IN1 DISCRETE_INPUT(2) +#define DST_ADDER__IN2 DISCRETE_INPUT(3) +#define DST_ADDER__IN3 DISCRETE_INPUT(4) + +DISCRETE_STEP(dst_adder) +{ + if(DST_ADDER__ENABLE) + { + set_output(0, DST_ADDER__IN0 + DST_ADDER__IN1 + DST_ADDER__IN2 + DST_ADDER__IN3); + } + else + { + set_output(0, 0); + } +} + + +/************************************************************************ + * + * DST_COMP_ADDER - Selectable parallel component adder + * + * input[0] - Bit Select + * + * Also passed discrete_comp_adder_table structure + * + * Mar 2004, D Renaud. + ************************************************************************/ +#define DST_COMP_ADDER__SELECT DISCRETE_INPUT(0) + +DISCRETE_STEP(dst_comp_adder) +{ + int select; + + select = (int)DST_COMP_ADDER__SELECT; + assert(select < 256); + set_output(0, m_total[select]); +} + +DISCRETE_RESET(dst_comp_adder) +{ + DISCRETE_DECLARE_INFO(discrete_comp_adder_table) + + int i, bit; + int bit_length = info->length; + + assert(bit_length <= 8); + + /* pre-calculate all possible values to speed up step routine */ + for(i = 0; i < 256; i++) + { + switch (info->type) + { + case DISC_COMP_P_CAPACITOR: + m_total[i] = info->cDefault; + for(bit = 0; bit < bit_length; bit++) + { + if (i & (1 << bit)) + m_total[i] += info->c[bit]; + } + break; + case DISC_COMP_P_RESISTOR: + m_total[i] = (info->cDefault != 0) ? 1.0 / info->cDefault : 0; + for(bit = 0; bit < bit_length; bit++) + { + if ((i & (1 << bit)) && (info->c[bit] != 0)) + m_total[i] += 1.0 / info->c[bit]; + } + if (m_total[i] != 0) + m_total[i] = 1.0 / m_total[i]; + break; + } + } + set_output(0, m_total[0]); +} + +/************************************************************************ + * + * DST_CLAMP - Simple signal clamping circuit + * + * input[0] - Input value + * input[1] - Minimum value + * input[2] - Maximum value + * + ************************************************************************/ +#define DST_CLAMP__IN DISCRETE_INPUT(0) +#define DST_CLAMP__MIN DISCRETE_INPUT(1) +#define DST_CLAMP__MAX DISCRETE_INPUT(2) + +DISCRETE_STEP(dst_clamp) +{ + if (DST_CLAMP__IN < DST_CLAMP__MIN) + set_output(0, DST_CLAMP__MIN); + else if (DST_CLAMP__IN > DST_CLAMP__MAX) + set_output(0, DST_CLAMP__MAX); + else + set_output(0, DST_CLAMP__IN); +} + + +/************************************************************************ + * + * DST_DAC_R1 - R1 Ladder DAC with cap smoothing + * + * input[0] - Binary Data Input + * input[1] - Data On Voltage (3.4 for TTL) + * + * also passed discrete_dac_r1_ladder structure + * + * Mar 2004, D Renaud. + * Nov 2010, D Renaud. - optimized for speed + ************************************************************************/ +#define DST_DAC_R1__DATA DISCRETE_INPUT(0) +#define DST_DAC_R1__VON DISCRETE_INPUT(1) + +DISCRETE_STEP(dst_dac_r1) +{ + int data = (int)DST_DAC_R1__DATA; + double v = m_v_step[data]; + double x_time = DST_DAC_R1__DATA - data; + double last_v = m_last_v; + + m_last_v = v; + + if (x_time > 0) + v = x_time * (v - last_v) + last_v; + + /* Filter if needed, else just output voltage */ + if (m_has_c_filter) + { + double v_diff = v - m_v_out; + /* optimization - if charged close enough to voltage */ + if (fabs(v_diff) < 0.000001) + m_v_out = v; + else + { + m_v_out += v_diff * m_exponent; + } + } + else + m_v_out = v; + + set_output(0, m_v_out); +} + +DISCRETE_RESET(dst_dac_r1) +{ + DISCRETE_DECLARE_INFO(discrete_dac_r1_ladder) + + int bit; + int ladderLength = info->ladderLength; + int total_steps = 1 << ladderLength; + double r_total = 0; + double i_bias; + double v_on = DST_DAC_R1__VON; + + m_last_v = 0; + + /* Calculate the Millman current of the bias circuit */ + if (info->rBias > 0) + i_bias = info->vBias / info->rBias; + else + i_bias = 0; + + /* + * We will do a small amount of error checking. + * But if you are an idiot and pass a bad ladder table + * then you deserve a crash. + */ + if (ladderLength < 2 && info->rBias == 0 && info->rGnd == 0) + { + /* You need at least 2 resistors for a ladder */ + m_device->discrete_log("dst_dac_r1_reset - Ladder length too small"); + } + if (ladderLength > DISC_LADDER_MAXRES ) + { + m_device->discrete_log("dst_dac_r1_reset - Ladder length exceeds DISC_LADDER_MAXRES"); + } + + /* + * Calculate the total of all resistors in parallel. + * This is the combined resistance of the voltage sources. + * This is used for the charging curve. + */ + for(bit = 0; bit < ladderLength; bit++) + { + if (info->r[bit] > 0) + r_total += 1.0 / info->r[bit]; + } + if (info->rBias > 0) r_total += 1.0 / info->rBias; + if (info->rGnd > 0) r_total += 1.0 / info->rGnd; + r_total = 1.0 / r_total; + + m_v_out = 0; + + if (info->cFilter > 0) + { + m_has_c_filter = 1; + /* Setup filter constant */ + m_exponent = RC_CHARGE_EXP(r_total * info->cFilter); + } + else + m_has_c_filter = 0; + + /* pre-calculate all possible values to speed up step routine */ + for(int i = 0; i < total_steps; i++) + { + double i_total = i_bias; + for (bit = 0; bit < ladderLength; bit++) + { + /* Add up currents of ON circuits per Millman. */ + + /* ignore if no resistor present */ + if (EXPECTED(info->r[bit] > 0)) + { + double i_bit; + int bit_val = (i >> bit) & 0x01; + + if (bit_val != 0) + i_bit = v_on / info->r[bit]; + else + i_bit = 0; + i_total += i_bit; + } + } + m_v_step[i] = i_total * r_total; + } +} + + +/************************************************************************ +* + * DST_DIODE_MIX - Diode Mixer + * + * input[0] - Input 0 + * ..... + * + * Dec 2004, D Renaud. + ************************************************************************/ +#define DST_DIODE_MIX_INP_OFFSET 0 +#define DST_DIODE_MIX__INP(addr) DISCRETE_INPUT(DST_DIODE_MIX_INP_OFFSET + addr) + +DISCRETE_STEP(dst_diode_mix) +{ + double val, max = 0; + int addr; + + for (addr = 0; addr < m_size; addr++) + { + val = DST_DIODE_MIX__INP(addr) - m_v_junction[addr]; + if (val > max) max = val; + } + if (max < 0) max = 0; + set_output(0, max); +} + +DISCRETE_RESET(dst_diode_mix) +{ + DISCRETE_DECLARE_INFO(double) + + int addr; + + m_size = this->active_inputs() - DST_DIODE_MIX_INP_OFFSET; + assert(m_size <= 8); + + for (addr = 0; addr < m_size; addr++) + { + if (info == NULL) + { + /* setup default junction voltage */ + m_v_junction[addr] = 0.5; + } + else + { + /* use supplied junction voltage */ + m_v_junction[addr] = *info++; + } + } + this->step(); +} + + +/************************************************************************ + * + * DST_DIVIDE - Programmable divider with enable + * + * input[0] - Enable input value + * input[1] - Channel0 input value + * input[2] - Divisor + * + ************************************************************************/ +#define DST_DIVIDE__ENABLE DISCRETE_INPUT(0) +#define DST_DIVIDE__IN DISCRETE_INPUT(1) +#define DST_DIVIDE__DIV DISCRETE_INPUT(2) + +DISCRETE_STEP(dst_divide) +{ + if(DST_DIVIDE__ENABLE) + { + if(DST_DIVIDE__DIV == 0) + { + set_output(0, DBL_MAX); /* Max out but don't break */ + m_device->discrete_log("dst_divider_step() - Divide by Zero attempted in NODE_%02d.\n",this->index()); + } + else + { + set_output(0, DST_DIVIDE__IN / DST_DIVIDE__DIV); + } + } + else + { + set_output(0, 0); + } +} + + +/************************************************************************ + * + * DST_GAIN - This is a programmable gain module with enable function + * + * input[0] - Channel0 input value + * input[1] - Gain value + * input[2] - Final addition offset + * + ************************************************************************/ +#define DST_GAIN__IN DISCRETE_INPUT(0) +#define DST_GAIN__GAIN DISCRETE_INPUT(1) +#define DST_GAIN__OFFSET DISCRETE_INPUT(2) + +DISCRETE_STEP(dst_gain) +{ + set_output(0, DST_GAIN__IN * DST_GAIN__GAIN + DST_GAIN__OFFSET); +} + + +/************************************************************************ + * + * DST_INTEGRATE - Integration circuits + * + * input[0] - Trigger 0 + * input[1] - Trigger 1 + * + * also passed discrete_integrate_info structure + * + * Mar 2004, D Renaud. + ************************************************************************/ +#define DST_INTEGRATE__TRG0 DISCRETE_INPUT(0) +#define DST_INTEGRATE__TRG1 DISCRETE_INPUT(1) + +static int dst_trigger_function(int trig0, int trig1, int trig2, int function) +{ + int result = 1; + switch (function) + { + case DISC_OP_AMP_TRIGGER_FUNCTION_TRG0: + result = trig0; + break; + case DISC_OP_AMP_TRIGGER_FUNCTION_TRG0_INV: + result = !trig0; + break; + case DISC_OP_AMP_TRIGGER_FUNCTION_TRG1: + result = trig1; + break; + case DISC_OP_AMP_TRIGGER_FUNCTION_TRG1_INV: + result = !trig1; + break; + case DISC_OP_AMP_TRIGGER_FUNCTION_TRG2: + result = trig2; + break; + case DISC_OP_AMP_TRIGGER_FUNCTION_TRG2_INV: + result = !trig2; + break; + case DISC_OP_AMP_TRIGGER_FUNCTION_TRG01_AND: + result = trig0 && trig1; + break; + case DISC_OP_AMP_TRIGGER_FUNCTION_TRG01_NAND: + result = !(trig0 && trig1); + break; + } + + return (result); +} + +DISCRETE_STEP(dst_integrate) +{ + DISCRETE_DECLARE_INFO(discrete_integrate_info) + + int trig0, trig1; + double i_neg = 0; /* current into - input */ + double i_pos = 0; /* current into + input */ + + switch (info->type) + { + case DISC_INTEGRATE_OP_AMP_1: + if (DST_INTEGRATE__TRG0 != 0) + { + /* This forces the cap to completely charge, + * and the output to go to it's max value. + */ + m_v_out = m_v_max_out; + set_output(0, m_v_out); + return; + } + m_v_out -= m_change; + break; + + case DISC_INTEGRATE_OP_AMP_1 | DISC_OP_AMP_IS_NORTON: + i_neg = m_v_max_in / info->r1; + i_pos = (DST_INTEGRATE__TRG0 - OP_AMP_NORTON_VBE) / info->r2; + if (i_pos < 0) i_pos = 0; + m_v_out += (i_pos - i_neg) / this->sample_rate() / info->c; + break; + + case DISC_INTEGRATE_OP_AMP_2 | DISC_OP_AMP_IS_NORTON: + trig0 = (int)DST_INTEGRATE__TRG0; + trig1 = (int)DST_INTEGRATE__TRG1; + i_neg = dst_trigger_function(trig0, trig1, 0, info->f0) ? m_v_max_in_d / info->r1 : 0; + i_pos = dst_trigger_function(trig0, trig1, 0, info->f1) ? m_v_max_in / info->r2 : 0; + i_pos += dst_trigger_function(trig0, trig1, 0, info->f2) ? m_v_max_in_d / info->r3 : 0; + m_v_out += (i_pos - i_neg) / this->sample_rate() / info->c; + break; + } + + /* Clip the output. */ + if (m_v_out < 0) m_v_out = 0; + if (m_v_out > m_v_max_out) m_v_out = m_v_max_out; + + set_output(0, m_v_out); +} + +DISCRETE_RESET(dst_integrate) +{ + DISCRETE_DECLARE_INFO(discrete_integrate_info) + + double i, v; + + if (info->type & DISC_OP_AMP_IS_NORTON) + { + m_v_max_out = info->vP - OP_AMP_NORTON_VBE; + m_v_max_in = info->v1 - OP_AMP_NORTON_VBE; + m_v_max_in_d = m_v_max_in - OP_AMP_NORTON_VBE; + } + else + { + m_v_max_out = info->vP - OP_AMP_VP_RAIL_OFFSET; + + v = info->v1 * info->r3 / (info->r2 + info->r3); /* vRef */ + v = info->v1 - v; /* actual charging voltage */ + i = v / info->r1; + m_change = i / this->sample_rate() / info->c; + } + m_v_out = 0; + set_output(0, m_v_out); +} + + +/************************************************************************ + * + * DST_LOGIC_INV - Logic invertor gate implementation + * + * input[0] - Enable + * input[1] - input[0] value + * + ************************************************************************/ +#define DST_LOGIC_INV__IN DISCRETE_INPUT(0) + +DISCRETE_STEP(dst_logic_inv) +{ + set_output(0, DST_LOGIC_INV__IN ? 0.0 : 1.0); +} + +/************************************************************************ + * + * DST_BITS_DECODE - Decode Bits from input node + * + ************************************************************************/ +#define DST_BITS_DECODE__IN DISCRETE_INPUT(0) +#define DST_BITS_DECODE__FROM DISCRETE_INPUT(1) +#define DST_BITS_DECODE__TO DISCRETE_INPUT(2) +#define DST_BITS_DECODE__VOUT DISCRETE_INPUT(3) + +DISCRETE_STEP(dst_bits_decode) +{ + int new_val = DST_BITS_DECODE__IN; + int last_val = m_last_val; + int last_had_x_time = m_last_had_x_time; + + if (last_val != new_val || last_had_x_time) + { + int i, new_bit, last_bit, last_bit_had_x_time, bit_changed; + double x_time = DST_BITS_DECODE__IN - new_val; + int from = m_from; + int count = m_count; + int decode_x_time = m_decode_x_time; + int has_x_time = x_time > 0 ? 1 : 0; + double out = 0; + double v_out = DST_BITS_DECODE__VOUT; + + for (i = 0; i < count; i++ ) + { + new_bit = (new_val >> (i + from)) & 1; + last_bit = (last_val >> (i + from)) & 1; + last_bit_had_x_time = (last_had_x_time >> (i + from)) & 1; + bit_changed = last_bit != new_bit ? 1 : 0; + + if (!bit_changed && !last_bit_had_x_time) + continue; + + if (decode_x_time) + { + out = new_bit; + if (bit_changed) + out += x_time; + } + else + { + out = v_out; + if (has_x_time && bit_changed) + { + if (new_bit) + out *= x_time; + else + out *= (1.0 - x_time); + } + else + out *= new_bit; + } + set_output(i, out); + if (has_x_time && bit_changed) + /* set */ + m_last_had_x_time |= 1 << (i + from); + else + /* clear */ + m_last_had_x_time &= ~(1 << (i + from)); + } + m_last_val = new_val; + } +} + +DISCRETE_RESET(dst_bits_decode) +{ + m_from = DST_BITS_DECODE__FROM; + m_count = DST_BITS_DECODE__TO - m_from + 1; + if (DST_BITS_DECODE__VOUT == 0) + m_decode_x_time = 1; + else + m_decode_x_time = 0; + m_last_had_x_time = 0; + + this->step(); +} + + +/************************************************************************ + * + * DST_LOGIC_AND - Logic AND gate implementation + * + * input[0] - input[0] value + * input[1] - input[1] value + * input[2] - input[2] value + * input[3] - input[3] value + * + ************************************************************************/ +#define DST_LOGIC_AND__IN0 DISCRETE_INPUT(0) +#define DST_LOGIC_AND__IN1 DISCRETE_INPUT(1) +#define DST_LOGIC_AND__IN2 DISCRETE_INPUT(2) +#define DST_LOGIC_AND__IN3 DISCRETE_INPUT(3) + +DISCRETE_STEP(dst_logic_and) +{ + set_output(0, (DST_LOGIC_AND__IN0 && DST_LOGIC_AND__IN1 && DST_LOGIC_AND__IN2 && DST_LOGIC_AND__IN3)? 1.0 : 0.0); +} + +/************************************************************************ + * + * DST_LOGIC_NAND - Logic NAND gate implementation + * + * input[0] - input[0] value + * input[1] - input[1] value + * input[2] - input[2] value + * input[3] - input[3] value + * + ************************************************************************/ +#define DST_LOGIC_NAND__IN0 DISCRETE_INPUT(0) +#define DST_LOGIC_NAND__IN1 DISCRETE_INPUT(1) +#define DST_LOGIC_NAND__IN2 DISCRETE_INPUT(2) +#define DST_LOGIC_NAND__IN3 DISCRETE_INPUT(3) + +DISCRETE_STEP(dst_logic_nand) +{ + set_output(0, (DST_LOGIC_NAND__IN0 && DST_LOGIC_NAND__IN1 && DST_LOGIC_NAND__IN2 && DST_LOGIC_NAND__IN3)? 0.0 : 1.0); +} + +/************************************************************************ + * + * DST_LOGIC_OR - Logic OR gate implementation + * + * input[0] - input[0] value + * input[1] - input[1] value + * input[2] - input[2] value + * input[3] - input[3] value + * + ************************************************************************/ +#define DST_LOGIC_OR__IN0 DISCRETE_INPUT(0) +#define DST_LOGIC_OR__IN1 DISCRETE_INPUT(1) +#define DST_LOGIC_OR__IN2 DISCRETE_INPUT(2) +#define DST_LOGIC_OR__IN3 DISCRETE_INPUT(3) + +DISCRETE_STEP(dst_logic_or) +{ + set_output(0, (DST_LOGIC_OR__IN0 || DST_LOGIC_OR__IN1 || DST_LOGIC_OR__IN2 || DST_LOGIC_OR__IN3) ? 1.0 : 0.0); +} + +/************************************************************************ + * + * DST_LOGIC_NOR - Logic NOR gate implementation + * + * input[0] - input[0] value + * input[1] - input[1] value + * input[2] - input[2] value + * input[3] - input[3] value + * + ************************************************************************/ +#define DST_LOGIC_NOR__IN0 DISCRETE_INPUT(0) +#define DST_LOGIC_NOR__IN1 DISCRETE_INPUT(1) +#define DST_LOGIC_NOR__IN2 DISCRETE_INPUT(2) +#define DST_LOGIC_NOR__IN3 DISCRETE_INPUT(3) + +DISCRETE_STEP(dst_logic_nor) +{ + set_output(0, (DST_LOGIC_NOR__IN0 || DST_LOGIC_NOR__IN1 || DST_LOGIC_NOR__IN2 || DST_LOGIC_NOR__IN3) ? 0.0 : 1.0); +} + +/************************************************************************ + * + * DST_LOGIC_XOR - Logic XOR gate implementation + * + * input[0] - input[0] value + * input[1] - input[1] value + * + ************************************************************************/ +#define DST_LOGIC_XOR__IN0 DISCRETE_INPUT(0) +#define DST_LOGIC_XOR__IN1 DISCRETE_INPUT(1) + +DISCRETE_STEP(dst_logic_xor) +{ + set_output(0, ((DST_LOGIC_XOR__IN0 && !DST_LOGIC_XOR__IN1) || (!DST_LOGIC_XOR__IN0 && DST_LOGIC_XOR__IN1)) ? 1.0 : 0.0); +} + +/************************************************************************ + * + * DST_LOGIC_NXOR - Logic NXOR gate implementation + * + * input[0] - input[0] value + * input[1] - input[1] value + * + ************************************************************************/ +#define DST_LOGIC_XNOR__IN0 DISCRETE_INPUT(0) +#define DST_LOGIC_XNOR__IN1 DISCRETE_INPUT(1) + +DISCRETE_STEP(dst_logic_nxor) +{ + set_output(0, ((DST_LOGIC_XNOR__IN0 && !DST_LOGIC_XNOR__IN1) || (!DST_LOGIC_XNOR__IN0 && DST_LOGIC_XNOR__IN1)) ? 0.0 : 1.0); +} + + +/************************************************************************ + * + * DST_LOGIC_DFF - Standard D-type flip-flop implementation + * + * input[0] - /Reset + * input[1] - /Set + * input[2] - clock + * input[3] - data + * + ************************************************************************/ +#define DST_LOGIC_DFF__RESET !DISCRETE_INPUT(0) +#define DST_LOGIC_DFF__SET !DISCRETE_INPUT(1) +#define DST_LOGIC_DFF__CLOCK DISCRETE_INPUT(2) +#define DST_LOGIC_DFF__DATA DISCRETE_INPUT(3) + +DISCRETE_STEP(dst_logic_dff) +{ + int clk = (int)DST_LOGIC_DFF__CLOCK; + + if (DST_LOGIC_DFF__RESET) + set_output(0, 0); + else if (DST_LOGIC_DFF__SET) + set_output(0, 1); + else if (!m_last_clk && clk) /* low to high */ + set_output(0, DST_LOGIC_DFF__DATA); + m_last_clk = clk; +} + +DISCRETE_RESET(dst_logic_dff) +{ + m_last_clk = 0; + set_output(0, 0); +} + + +/************************************************************************ + * + * DST_LOGIC_JKFF - Standard JK-type flip-flop implementation + * + * input[0] - /Reset + * input[1] - /Set + * input[2] - clock + * input[3] - J + * input[4] - K + * + ************************************************************************/ +#define DST_LOGIC_JKFF__RESET !DISCRETE_INPUT(0) +#define DST_LOGIC_JKFF__SET !DISCRETE_INPUT(1) +#define DST_LOGIC_JKFF__CLOCK DISCRETE_INPUT(2) +#define DST_LOGIC_JKFF__J DISCRETE_INPUT(3) +#define DST_LOGIC_JKFF__K DISCRETE_INPUT(4) + +DISCRETE_STEP(dst_logic_jkff) +{ + int clk = (int)DST_LOGIC_JKFF__CLOCK; + int j = (int)DST_LOGIC_JKFF__J; + int k = (int)DST_LOGIC_JKFF__K; + + if (DST_LOGIC_JKFF__RESET) + m_v_out = 0; + else if (DST_LOGIC_JKFF__SET) + m_v_out = 1; + else if (m_last_clk && !clk) /* high to low */ + { + if (!j) + { + /* J=0, K=0 - Hold */ + if (k) + /* J=0, K=1 - Reset */ + m_v_out = 0; + } + else + { + if (!k) + /* J=1, K=0 - Set */ + m_v_out = 1; + else + /* J=1, K=1 - Toggle */ + m_v_out = !(int)m_v_out; + } + } + m_last_clk = clk; + set_output(0, m_v_out); +} + +DISCRETE_RESET(dst_logic_jkff) +{ + m_last_clk = 0; + m_v_out = 0; + set_output(0, m_v_out); +} + +/************************************************************************ + * + * DST_LOGIC_SHIFT - Shift Register implementation + * + ************************************************************************/ +#define DST_LOGIC_SHIFT__IN DISCRETE_INPUT(0) +#define DST_LOGIC_SHIFT__RESET DISCRETE_INPUT(1) +#define DST_LOGIC_SHIFT__CLK DISCRETE_INPUT(2) +#define DST_LOGIC_SHIFT__SIZE DISCRETE_INPUT(3) +#define DST_LOGIC_SHIFT__OPTIONS DISCRETE_INPUT(4) + +DISCRETE_STEP(dst_logic_shift) +{ + double cycles; + double ds_clock; + int clock = 0, inc = 0; + + int input_bit = (DST_LOGIC_SHIFT__IN != 0) ? 1 : 0; + ds_clock = DST_LOGIC_SHIFT__CLK; + if (m_clock_type == DISC_CLK_IS_FREQ) + { + /* We need to keep clocking the internal clock even if in reset. */ + cycles = (m_t_left + this->sample_time()) * ds_clock; + inc = (int)cycles; + m_t_left = (cycles - inc) / ds_clock; + } + else + { + clock = (int)ds_clock; + } + + /* If reset enabled then set output to the reset value. No x_time in reset. */ + if(((DST_LOGIC_SHIFT__RESET == 0) ? 0 : 1) == m_reset_on_high) + { + m_shift_data = 0; + set_output(0, 0); + return; + } + + /* increment clock */ + switch (m_clock_type) + { + case DISC_CLK_ON_F_EDGE: + case DISC_CLK_ON_R_EDGE: + /* See if the clock has toggled to the proper edge */ + clock = (clock != 0); + if (m_last != clock) + { + m_last = clock; + if (m_clock_type == clock) + { + /* Toggled */ + inc = 1; + } + } + break; + + case DISC_CLK_BY_COUNT: + /* Clock number of times specified. */ + inc = clock; + break; + } + + if (inc > 0) + { + if (m_shift_r) + { + m_shift_data >>= 1; + m_shift_data |= input_bit << ((int)DST_LOGIC_SHIFT__SIZE - 1); + inc--; + m_shift_data >>= inc; + } + else + { + m_shift_data <<= 1; + m_shift_data |= input_bit; + inc--; + m_shift_data <<= inc; + } + m_shift_data &= m_bit_mask; + } + + set_output(0, m_shift_data); +} + +DISCRETE_RESET(dst_logic_shift) +{ + m_bit_mask = (1 << (int)DST_LOGIC_SHIFT__SIZE) - 1; + m_clock_type = (int)DST_LOGIC_SHIFT__OPTIONS & DISC_CLK_MASK; + m_reset_on_high = ((int)DST_LOGIC_SHIFT__OPTIONS & DISC_LOGIC_SHIFT__RESET_H) ? 1 : 0; + m_shift_r = ((int)DST_LOGIC_SHIFT__OPTIONS & DISC_LOGIC_SHIFT__RIGHT) ? 1 : 0; + + m_t_left = 0; + m_last = 0; + m_shift_data = 0; + set_output(0, 0); +} + +/************************************************************************ + * + * DST_LOOKUP_TABLE - Return value from lookup table + * + * input[0] - Input 1 + * input[1] - Table size + * + * Also passed address of the lookup table + * + * Feb 2007, D Renaud. + ************************************************************************/ +#define DST_LOOKUP_TABLE__IN DISCRETE_INPUT(0) +#define DST_LOOKUP_TABLE__SIZE DISCRETE_INPUT(1) + +DISCRETE_STEP(dst_lookup_table) +{ + DISCRETE_DECLARE_INFO(double) + + int addr = DST_LOOKUP_TABLE__IN; + + if (addr < 0 || addr >= DST_LOOKUP_TABLE__SIZE) + set_output(0, 0); + else + set_output(0, info[addr]); +} + + +/************************************************************************ + * + * DST_MIXER - Mixer/Gain stage + * + * input[0] - Enable input value + * input[1] - Input 1 + * input[2] - Input 2 + * input[3] - Input 3 + * input[4] - Input 4 + * input[5] - Input 5 + * input[6] - Input 6 + * input[7] - Input 7 + * input[8] - Input 8 + * + * Also passed discrete_mixer_info structure + * + * Mar 2004, D Renaud. + ************************************************************************/ +/* + * The input resistors can be a combination of static values and nodes. + * If a node is used then its value is in series with the static value. + * Also if a node is used and its value is 0, then that means the + * input is disconnected from the circuit. + * + * There are 3 basic types of mixers, defined by the 2 types. The + * op amp mixer is further defined by the prescence of rI. This is a + * brief explanation. + * + * DISC_MIXER_IS_RESISTOR + * The inputs are high pass filtered if needed, using (rX || rF) * cX. + * Then Millman is used for the voltages. + * r = (1/rF + 1/r1 + 1/r2...) + * i = (v1/r1 + v2/r2...) + * v = i * r + * + * DISC_MIXER_IS_OP_AMP - no rI + * This is just a summing circuit. + * The inputs are high pass filtered if needed, using rX * cX. + * Then a modified Millman is used for the voltages. + * i = ((vRef - v1)/r1 + (vRef - v2)/r2...) + * v = i * rF + * + * DISC_MIXER_IS_OP_AMP_WITH_RI + * The inputs are high pass filtered if needed, using (rX + rI) * cX. + * Then Millman is used for the voltages including vRef/rI. + * r = (1/rI + 1/r1 + 1/r2...) + * i = (vRef/rI + v1/r1 + v2/r2...) + * The voltage is then modified by an inverting amp formula. + * v = vRef + (rF/rI) * (vRef - (i * r)) + */ +#define DST_MIXER__ENABLE DISCRETE_INPUT(0) +#define DST_MIXER__IN(bit) DISCRETE_INPUT(bit + 1) + +DISCRETE_STEP(dst_mixer) +{ + DISCRETE_DECLARE_INFO(discrete_mixer_desc) + + double v, vTemp, r_total, rTemp, rTemp2 = 0; + double i = 0; /* total current of inputs */ + int bit, connected; + + /* put commonly used stuff in local variables for speed */ + int r_node_bit_flag = m_r_node_bit_flag; + int c_bit_flag = m_c_bit_flag; + int bit_mask = 1; + int has_rF = (info->rF != 0); + int type = m_type; + double v_ref = info->vRef; + double rI = info->rI; + + if (EXPECTED(DST_MIXER__ENABLE)) + { + r_total = m_r_total; + + if (UNEXPECTED(m_r_node_bit_flag != 0)) + { + /* loop and do any high pass filtering for connected caps */ + /* but first see if there is an r_node for the current path */ + /* if so, then the exponents need to be re-calculated */ + for (bit = 0; bit < m_size; bit++) + { + rTemp = info->r[bit]; + connected = 1; + vTemp = DST_MIXER__IN(bit); + + /* is there a resistor? */ + if (r_node_bit_flag & bit_mask) + { + /* a node has the possibility of being disconnected from the circuit. */ + if (*m_r_node[bit] == 0) + connected = 0; + else + { + /* value currently holds resistance */ + rTemp += *m_r_node[bit]; + r_total += 1.0 / rTemp; + /* is there a capacitor? */ + if (c_bit_flag & bit_mask) + { + switch (type) + { + case DISC_MIXER_IS_RESISTOR: + /* is there an rF? */ + if (has_rF) + { + rTemp2 = RES_2_PARALLEL(rTemp, info->rF); + break; + } + /* else, fall through and just use the resistor value */ + case DISC_MIXER_IS_OP_AMP: + rTemp2 = rTemp; + break; + case DISC_MIXER_IS_OP_AMP_WITH_RI: + rTemp2 = rTemp + rI; + break; + } + /* Re-calculate exponent if resistor is a node and has changed value */ + if (*m_r_node[bit] != m_r_last[bit]) + { + m_exponent_rc[bit] = RC_CHARGE_EXP(rTemp2 * info->c[bit]); + m_r_last[bit] = *m_r_node[bit]; + } + } + } + } + + if (connected) + { + /* is there a capacitor? */ + if (c_bit_flag & bit_mask) + { + /* do input high pass filtering if needed. */ + m_v_cap[bit] += (vTemp - v_ref - m_v_cap[bit]) * m_exponent_rc[bit]; + vTemp -= m_v_cap[bit]; + } + i += ((type == DISC_MIXER_IS_OP_AMP) ? v_ref - vTemp : vTemp) / rTemp; + } + bit_mask = bit_mask << 1; + } + } + else if (UNEXPECTED(c_bit_flag != 0)) + { + /* no r_nodes, so just do high pass filtering */ + for (bit = 0; bit < m_size; bit++) + { + vTemp = DST_MIXER__IN(bit); + + if (c_bit_flag & (1 << bit)) + { + /* do input high pass filtering if needed. */ + m_v_cap[bit] += (vTemp - v_ref - m_v_cap[bit]) * m_exponent_rc[bit]; + vTemp -= m_v_cap[bit]; + } + i += ((type == DISC_MIXER_IS_OP_AMP) ? v_ref - vTemp : vTemp) / info->r[bit]; + } + } + else + { + /* no r_nodes or c_nodes, mixing only */ + if (UNEXPECTED(type == DISC_MIXER_IS_OP_AMP)) + { + for (bit = 0; bit < m_size; bit++) + i += ( v_ref - DST_MIXER__IN(bit) ) / info->r[bit]; + } + else + { + for (bit = 0; bit < m_size; bit++) + i += DST_MIXER__IN(bit) / info->r[bit]; + } + } + + if (UNEXPECTED(type == DISC_MIXER_IS_OP_AMP_WITH_RI)) + i += v_ref / rI; + + r_total = 1.0 / r_total; + + /* If resistor network or has rI then Millman is used. + * If op-amp then summing formula is used. */ + v = i * ((type == DISC_MIXER_IS_OP_AMP) ? info->rF : r_total); + + if (UNEXPECTED(type == DISC_MIXER_IS_OP_AMP_WITH_RI)) + v = v_ref + (m_gain * (v_ref - v)); + + /* Do the low pass filtering for cF */ + if (EXPECTED(info->cF != 0)) + { + if (UNEXPECTED(r_node_bit_flag != 0)) + { + /* Re-calculate exponent if resistor nodes are used */ + m_exponent_c_f = RC_CHARGE_EXP(r_total * info->cF); + } + m_v_cap_f += (v - v_ref - m_v_cap_f) * m_exponent_c_f; + v = m_v_cap_f; + } + + /* Do the high pass filtering for cAmp */ + if (EXPECTED(info->cAmp != 0)) + { + m_v_cap_amp += (v - m_v_cap_amp) * m_exponent_c_amp; + v -= m_v_cap_amp; + } + set_output(0, v * info->gain); + } + else + { + set_output(0, 0); + } +} + + +DISCRETE_RESET(dst_mixer) +{ + DISCRETE_DECLARE_INFO(discrete_mixer_desc) + + int bit; + double rTemp = 0; + + /* link to r_node outputs */ + m_r_node_bit_flag = 0; + for (bit = 0; bit < 8; bit++) + { + m_r_node[bit] = m_device->node_output_ptr(info->r_node[bit]); + if (m_r_node[bit] != NULL) + { + m_r_node_bit_flag |= 1 << bit; + } + + /* flag any caps */ + if (info->c[bit] != 0) + m_c_bit_flag |= 1 << bit; + } + + m_size = this->active_inputs() - 1; + + /* + * THERE IS NO ERROR CHECKING!!!!!!!!! + * If you pass a bad ladder table + * then you deserve a crash. + */ + + m_type = info->type; + if ((info->type == DISC_MIXER_IS_OP_AMP) && (info->rI != 0)) + m_type = DISC_MIXER_IS_OP_AMP_WITH_RI; + + /* + * Calculate the total of all resistors in parallel. + * This is the combined resistance of the voltage sources. + * Also calculate the exponents while we are here. + */ + m_r_total = 0; + for(bit = 0; bit < m_size; bit++) + { + if ((info->r[bit] != 0) && !info->r_node[bit] ) + { + m_r_total += 1.0 / info->r[bit]; + } + + m_v_cap[bit] = 0; + m_exponent_rc[bit] = 0; + if ((info->c[bit] != 0) && !info->r_node[bit]) + { + switch (m_type) + { + case DISC_MIXER_IS_RESISTOR: + /* is there an rF? */ + if (info->rF != 0) + { + rTemp = 1.0 / ((1.0 / info->r[bit]) + (1.0 / info->rF)); + break; + } + /* else, fall through and just use the resistor value */ + case DISC_MIXER_IS_OP_AMP: + rTemp = info->r[bit]; + break; + case DISC_MIXER_IS_OP_AMP_WITH_RI: + rTemp = info->r[bit] + info->rI; + break; + } + /* Setup filter constants */ + m_exponent_rc[bit] = RC_CHARGE_EXP(rTemp * info->c[bit]); + } + } + + if (info->rF != 0) + { + if (m_type == DISC_MIXER_IS_RESISTOR) m_r_total += 1.0 / info->rF; + } + if (m_type == DISC_MIXER_IS_OP_AMP_WITH_RI) m_r_total += 1.0 / info->rI; + + m_v_cap_f = 0; + m_exponent_c_f = 0; + if (info->cF != 0) + { + /* Setup filter constants */ + m_exponent_c_f = RC_CHARGE_EXP(((info->type == DISC_MIXER_IS_OP_AMP) ? info->rF : (1.0 / m_r_total)) * info->cF); + } + + m_v_cap_amp = 0; + m_exponent_c_amp = 0; + if (info->cAmp != 0) + { + /* Setup filter constants */ + /* We will use 100k ohms as an average final stage impedance. */ + /* Your amp/speaker system will have more effect on incorrect filtering then any value used here. */ + m_exponent_c_amp = RC_CHARGE_EXP(RES_K(100) * info->cAmp); + } + + if (m_type == DISC_MIXER_IS_OP_AMP_WITH_RI) m_gain = info->rF / info->rI; + + set_output(0, 0); +} + + +/************************************************************************ + * + * DST_MULTIPLEX - 1 of x multiplexer/switch + * + * input[0] - switch position + * input[1] - input[0] + * input[2] - input[1] + * ..... + * + * Dec 2004, D Renaud. + ************************************************************************/ +#define DST_MULTIPLEX__ADDR DISCRETE_INPUT(0) +#define DST_MULTIPLEX__INP(addr) DISCRETE_INPUT(1 + addr) + +DISCRETE_STEP(dst_multiplex) +{ + int addr; + + addr = DST_MULTIPLEX__ADDR; /* FP to INT */ + if ((addr >= 0) && (addr < m_size)) + { + set_output(0, DST_MULTIPLEX__INP(addr)); + } + else + { + /* Bad address. We will leave the output alone. */ + m_device->discrete_log("NODE_%02d - Address = %d. Out of bounds\n", this->index(), addr); + } +} + +DISCRETE_RESET(dst_multiplex) +{ + m_size = this->active_inputs() - 1; + + this->step(); +} + + +/************************************************************************ + * + * DST_ONESHOT - Usage of node_description values for one shot pulse + * + * input[0] - Reset value + * input[1] - Trigger value + * input[2] - Amplitude value + * input[3] - Width of oneshot pulse + * input[4] - type R/F edge, Retriggerable? + * + * Complete re-write Jan 2004, D Renaud. + ************************************************************************/ +#define DST_ONESHOT__RESET DISCRETE_INPUT(0) +#define DST_ONESHOT__TRIG DISCRETE_INPUT(1) +#define DST_ONESHOT__AMP DISCRETE_INPUT(2) +#define DST_ONESHOT__WIDTH DISCRETE_INPUT(3) +#define DST_ONESHOT__TYPE (int)DISCRETE_INPUT(4) + +DISCRETE_STEP(dst_oneshot) +{ + int trigger = (DST_ONESHOT__TRIG != 0); + + /* If the state is triggered we will need to countdown later */ + int do_count = m_state; + + if (UNEXPECTED(DST_ONESHOT__RESET)) + { + /* Hold in Reset */ + set_output(0, 0); + m_state = 0; + } + else + { + /* are we at an edge? */ + if (UNEXPECTED(trigger != m_last_trig)) + { + /* There has been a trigger edge */ + m_last_trig = trigger; + + /* Is it the proper edge trigger */ + if ((m_type & DISC_ONESHOT_REDGE) ? trigger : !trigger) + { + if (!m_state) + { + /* We have first trigger */ + m_state = 1; + set_output(0, (m_type & DISC_OUT_ACTIVE_LOW) ? 0 : DST_ONESHOT__AMP); + m_countdown = DST_ONESHOT__WIDTH; + } + else + { + /* See if we retrigger */ + if (m_type & DISC_ONESHOT_RETRIG) + { + /* Retrigger */ + m_countdown = DST_ONESHOT__WIDTH; + do_count = 0; + } + } + } + } + + if (UNEXPECTED(do_count)) + { + m_countdown -= this->sample_time(); + if(m_countdown <= 0.0) + { + set_output(0, (m_type & DISC_OUT_ACTIVE_LOW) ? DST_ONESHOT__AMP : 0); + m_countdown = 0; + m_state = 0; + } + } + } +} + + +DISCRETE_RESET(dst_oneshot) +{ + m_countdown = 0; + m_state = 0; + + m_last_trig = 0; + m_type = DST_ONESHOT__TYPE; + + set_output(0, (m_type & DISC_OUT_ACTIVE_LOW) ? DST_ONESHOT__AMP : 0); +} + + +/************************************************************************ + * + * DST_RAMP - Ramp up/down model usage + * + * input[0] - Enable ramp + * input[1] - Ramp Reverse/Forward switch + * input[2] - Gradient, change/sec + * input[3] - Start value + * input[4] - End value + * input[5] - Clamp value when disabled + * + ************************************************************************/ +#define DST_RAMP__ENABLE DISCRETE_INPUT(0) +#define DST_RAMP__DIR DISCRETE_INPUT(1) +#define DST_RAMP__GRAD DISCRETE_INPUT(2) +#define DST_RAMP__START DISCRETE_INPUT(3) +#define DST_RAMP__END DISCRETE_INPUT(4) +#define DST_RAMP__CLAMP DISCRETE_INPUT(5) + +DISCRETE_STEP(dst_ramp) +{ + if(DST_RAMP__ENABLE) + { + if (!m_last_en) + { + m_last_en = 1; + m_v_out = DST_RAMP__START; + } + if(m_dir ? DST_RAMP__DIR : !DST_RAMP__DIR) m_v_out += m_step; + else m_v_out -= m_step; + /* Clamp to min/max */ + if(m_dir ? (m_v_out < DST_RAMP__START) + : (m_v_out > DST_RAMP__START)) m_v_out = DST_RAMP__START; + if(m_dir ? (m_v_out > DST_RAMP__END) + : (m_v_out < DST_RAMP__END)) m_v_out = DST_RAMP__END; + } + else + { + m_last_en = 0; + /* Disabled so clamp to output */ + m_v_out = DST_RAMP__CLAMP; + } + + set_output(0, m_v_out); +} + +DISCRETE_RESET(dst_ramp) +{ + m_v_out = DST_RAMP__CLAMP; + m_step = DST_RAMP__GRAD / this->sample_rate(); + m_dir = ((DST_RAMP__END - DST_RAMP__START) == fabs(DST_RAMP__END - DST_RAMP__START)); + m_last_en = 0; +} + + +/************************************************************************ + * + * DST_SAMPHOLD - Sample & Hold Implementation + * + * input[0] - input[0] value + * input[1] - clock node + * input[2] - clock type + * + ************************************************************************/ +#define DST_SAMPHOLD__IN0 DISCRETE_INPUT(0) +#define DST_SAMPHOLD__CLOCK DISCRETE_INPUT(1) +#define DST_SAMPHOLD__TYPE DISCRETE_INPUT(2) + +DISCRETE_STEP(dst_samphold) +{ + switch(m_clocktype) + { + case DISC_SAMPHOLD_REDGE: + /* Clock the whole time the input is rising */ + if (DST_SAMPHOLD__CLOCK > m_last_input) set_output(0, DST_SAMPHOLD__IN0); + break; + case DISC_SAMPHOLD_FEDGE: + /* Clock the whole time the input is falling */ + if(DST_SAMPHOLD__CLOCK < m_last_input) set_output(0, DST_SAMPHOLD__IN0); + break; + case DISC_SAMPHOLD_HLATCH: + /* Output follows input if clock != 0 */ + if( DST_SAMPHOLD__CLOCK) set_output(0, DST_SAMPHOLD__IN0); + break; + case DISC_SAMPHOLD_LLATCH: + /* Output follows input if clock == 0 */ + if (DST_SAMPHOLD__CLOCK == 0) set_output(0, DST_SAMPHOLD__IN0); + break; + default: + m_device->discrete_log("dst_samphold_step - Invalid clocktype passed"); + break; + } + /* Save the last value */ + m_last_input = DST_SAMPHOLD__CLOCK; +} + +DISCRETE_RESET(dst_samphold) +{ + set_output(0, 0); + m_last_input = -1; + /* Only stored in here to speed up and save casting in the step function */ + m_clocktype = (int)DST_SAMPHOLD__TYPE; + this->step(); +} + + +/************************************************************************ + * + * DST_SWITCH - Programmable 2 pole switch module with enable function + * + * input[0] - Enable input value + * input[1] - switch position + * input[2] - input[0] + * input[3] - input[1] + * + ************************************************************************/ +#define DST_SWITCH__ENABLE DISCRETE_INPUT(0) +#define DST_SWITCH__SWITCH DISCRETE_INPUT(1) +#define DST_SWITCH__IN0 DISCRETE_INPUT(2) +#define DST_SWITCH__IN1 DISCRETE_INPUT(3) + +DISCRETE_STEP(dst_switch) +{ + if(DST_SWITCH__ENABLE) + { + set_output(0, DST_SWITCH__SWITCH ? DST_SWITCH__IN1 : DST_SWITCH__IN0); + } + else + { + set_output(0, 0); + } +} + +/************************************************************************ + * + * DST_ASWITCH - Analog switch + * + * input[1] - Control + * input[2] - Input + * input[3] - Threshold for enable + * + ************************************************************************/ +#define DST_ASWITCH__CTRL DISCRETE_INPUT(0) +#define DST_ASWITCH__IN DISCRETE_INPUT(1) +#define DST_ASWITCH__THRESHOLD DISCRETE_INPUT(2) + + +DISCRETE_STEP(dst_aswitch) +{ + set_output(0, DST_ASWITCH__CTRL > DST_ASWITCH__THRESHOLD ? DST_ASWITCH__IN : 0); +} + +/************************************************************************ + * + * DST_TRANSFORM - Programmable math module + * + * input[0] - Channel0 input value + * input[1] - Channel1 input value + * input[2] - Channel2 input value + * input[3] - Channel3 input value + * input[4] - Channel4 input value + * + ************************************************************************/ +#define MAX_TRANS_STACK 16 + +struct double_stack { +public: + double_stack() : p(&stk[0]) { } + inline void push(double v) + { + //Store THEN increment + assert(p <= &stk[MAX_TRANS_STACK-1]); + *p++ = v; + } + inline double pop(void) + { + //decrement THEN read + assert(p > &stk[0]); + p--; + return *p; + } +private: + double stk[MAX_TRANS_STACK]; + double *p; +}; + +DISCRETE_STEP(dst_transform) +{ + double_stack stack; + double top; + + enum token *fPTR = &precomp[0]; + + top = HUGE_VAL; + + while(*fPTR != TOK_END) + { + switch (*fPTR++) + { + case TOK_MULT: top = stack.pop() * top; break; + case TOK_DIV: top = stack.pop() / top; break; + case TOK_ADD: top = stack.pop() + top; break; + case TOK_MINUS: top = stack.pop() - top; break; + case TOK_0: stack.push(top); top = I_IN0(); break; + case TOK_1: stack.push(top); top = I_IN1(); break; + case TOK_2: stack.push(top); top = I_IN2(); break; + case TOK_3: stack.push(top); top = I_IN3(); break; + case TOK_4: stack.push(top); top = I_IN4(); break; + case TOK_DUP: stack.push(top); break; + case TOK_ABS: top = fabs(top); break; /* absolute value */ + case TOK_NEG: top = -top; break; /* * -1 */ + case TOK_NOT: top = !top; break; /* Logical NOT of Last Value */ + case TOK_EQUAL: top = (int)stack.pop() == (int)top; break; /* Logical = */ + case TOK_GREATER: top = (stack.pop() > top); break; /* Logical > */ + case TOK_LESS: top = (stack.pop() < top); break; /* Logical < */ + case TOK_AND: top = (int)stack.pop() & (int)top; break; /* Bitwise AND */ + case TOK_OR: top = (int)stack.pop() | (int)top; break; /* Bitwise OR */ + case TOK_XOR: top = (int)stack.pop() ^ (int)top; break; /* Bitwise XOR */ + case TOK_END: break; /* please compiler */ + } + } + set_output(0, top); +} + +DISCRETE_RESET(dst_transform) +{ + const char *fPTR = (const char *)this->custom_data(); + enum token *p = &precomp[0]; + + while(*fPTR != 0) + { + switch (*fPTR++) + { + case '*': *p = TOK_MULT; break; + case '/': *p = TOK_DIV; break; + case '+': *p = TOK_ADD; break; + case '-': *p = TOK_MINUS; break; + case '0': *p = TOK_0; break; + case '1': *p = TOK_1; break; + case '2': *p = TOK_2; break; + case '3': *p = TOK_3; break; + case '4': *p = TOK_4; break; + case 'P': *p = TOK_DUP; break; + case 'a': *p = TOK_ABS; break; /* absolute value */ + case 'i': *p = TOK_NEG; break; /* * -1 */ + case '!': *p = TOK_NOT; break; /* Logical NOT of Last Value */ + case '=': *p = TOK_EQUAL; break; /* Logical = */ + case '>': *p = TOK_GREATER; break; /* Logical > */ + case '<': *p = TOK_LESS; break; /* Logical < */ + case '&': *p = TOK_AND; break; /* Bitwise AND */ + case '|': *p = TOK_OR; break; /* Bitwise OR */ + case '^': *p = TOK_XOR; break; /* Bitwise XOR */ + default: + m_device->discrete_log("dst_transform_step - Invalid function type/variable passed: %s",(const char *)this->custom_data()); + /* that is enough to fatalerror */ + fatalerror("dst_transform_step - Invalid function type/variable passed: %s\n", (const char *)this->custom_data()); + break; + } + p++; + } + *p = TOK_END; +} + +/************************************************************************ + * + * DST_OP_AMP - op amp circuits + * + * input[0] - Enable + * input[1] - Input 0 + * input[2] - Input 1 + * + * also passed discrete_op_amp_info structure + * + * Mar 2007, D Renaud. + ************************************************************************/ +#define DST_OP_AMP__ENABLE DISCRETE_INPUT(0) +#define DST_OP_AMP__INP0 DISCRETE_INPUT(1) +#define DST_OP_AMP__INP1 DISCRETE_INPUT(2) + +DISCRETE_STEP(dst_op_amp) +{ + DISCRETE_DECLARE_INFO(discrete_op_amp_info) + + double i_pos = 0; + double i_neg = 0; + double i = 0; + double v_out; + + if (DST_OP_AMP__ENABLE) + { + switch (info->type) + { + case DISC_OP_AMP_IS_NORTON: + /* work out neg pin current */ + if (m_has_r1) + { + i_neg = (DST_OP_AMP__INP0 - OP_AMP_NORTON_VBE) / info->r1; + if (i_neg < 0) i_neg = 0; + } + i_neg += m_i_fixed; + + /* work out neg pin current */ + i_pos = (DST_OP_AMP__INP1 - OP_AMP_NORTON_VBE) / info->r2; + if (i_pos < 0) i_pos = 0; + + /* work out current across r4 */ + i = i_pos - i_neg; + + if (m_has_cap) + { + if (m_has_r4) + { + /* voltage across r4 charging cap */ + i *= info->r4; + /* exponential charge */ + m_v_cap += (i - m_v_cap) * m_exponent; + } + else + /* linear charge */ + m_v_cap += i / m_exponent; + v_out = m_v_cap; + } + else + if (m_has_r4) + v_out = i * info->r4; + else + /* output just swings to rail when there is no r4 */ + if (i > 0) + v_out = m_v_max; + else + v_out = 0; + + /* clamp output */ + if (v_out > m_v_max) v_out = m_v_max; + else if (v_out < info->vN) v_out = info->vN; + m_v_cap = v_out; + + set_output(0, v_out); + break; + + default: + set_output(0, 0); + } + } + else + set_output(0, 0); +} + +DISCRETE_RESET(dst_op_amp) +{ + DISCRETE_DECLARE_INFO(discrete_op_amp_info) + + m_has_r1 = info->r1 > 0; + m_has_r4 = info->r4 > 0; + + m_v_max = info->vP - OP_AMP_NORTON_VBE; + + m_v_cap = 0; + if (info->c > 0) + { + m_has_cap = 1; + /* Setup filter constants */ + if (m_has_r4) + { + /* exponential charge */ + m_exponent = RC_CHARGE_EXP(info->r4 * info->c); + } + else + /* linear charge */ + m_exponent = this->sample_rate() * info->c; + } + + if (info->r3 > 0) + m_i_fixed = (info->vP - OP_AMP_NORTON_VBE) / info->r3; + else + m_i_fixed = 0; +} + + +/************************************************************************ + * + * DST_OP_AMP_1SHT - op amp one shot circuits + * + * input[0] - Trigger + * + * also passed discrete_op_amp_1sht_info structure + * + * Mar 2007, D Renaud. + ************************************************************************/ +#define DST_OP_AMP_1SHT__TRIGGER DISCRETE_INPUT(0) + +DISCRETE_STEP(dst_op_amp_1sht) +{ + DISCRETE_DECLARE_INFO(discrete_op_amp_1sht_info) + + double i_pos; + double i_neg; + double v; + + /* update trigger circuit */ + i_pos = (DST_OP_AMP_1SHT__TRIGGER - m_v_cap2) / info->r2; + i_pos += m_v_out / info->r5; + m_v_cap2 += (DST_OP_AMP_1SHT__TRIGGER - m_v_cap2) * m_exponent2; + + /* calculate currents and output */ + i_neg = (m_v_cap1 - OP_AMP_NORTON_VBE) / info->r3; + if (i_neg < 0) i_neg = 0; + i_neg += m_i_fixed; + + if (i_pos > i_neg) m_v_out = m_v_max; + else m_v_out = info->vN; + + /* update c1 */ + /* rough value of voltage at anode of diode if discharging */ + v = m_v_out + 0.6; + if (m_v_cap1 > m_v_out) + { + /* discharge */ + if (m_v_cap1 > v) + /* immediate discharge through diode */ + m_v_cap1 = v; + else + /* discharge through r4 */ + m_v_cap1 += (m_v_out - m_v_cap1) * m_exponent1d; + } + else + /* charge */ + m_v_cap1 += ((m_v_out - OP_AMP_NORTON_VBE) * m_r34ratio + OP_AMP_NORTON_VBE - m_v_cap1) * m_exponent1c; + + set_output(0, m_v_out); +} + +DISCRETE_RESET(dst_op_amp_1sht) +{ + DISCRETE_DECLARE_INFO(discrete_op_amp_1sht_info) + + m_exponent1c = RC_CHARGE_EXP(RES_2_PARALLEL(info->r3, info->r4) * info->c1); + m_exponent1d = RC_CHARGE_EXP(info->r4 * info->c1); + m_exponent2 = RC_CHARGE_EXP(info->r2 * info->c2); + m_i_fixed = (info->vP - OP_AMP_NORTON_VBE) / info->r1; + m_v_cap1 = m_v_cap2 = 0; + m_v_max = info->vP - OP_AMP_NORTON_VBE; + m_r34ratio = info->r3 / (info->r3 + info->r4); +} + + +/************************************************************************ + * + * DST_TVCA_OP_AMP - trigged op-amp VCA + * + * input[0] - Trigger 0 + * input[1] - Trigger 1 + * input[2] - Trigger 2 + * input[3] - Input 0 + * input[4] - Input 1 + * + * also passed discrete_op_amp_tvca_info structure + * + * Mar 2004, D Renaud. + ************************************************************************/ +#define DST_TVCA_OP_AMP__TRG0 DISCRETE_INPUT(0) +#define DST_TVCA_OP_AMP__TRG1 DISCRETE_INPUT(1) +#define DST_TVCA_OP_AMP__TRG2 DISCRETE_INPUT(2) +#define DST_TVCA_OP_AMP__INP0 DISCRETE_INPUT(3) +#define DST_TVCA_OP_AMP__INP1 DISCRETE_INPUT(4) + +DISCRETE_STEP(dst_tvca_op_amp) +{ + DISCRETE_DECLARE_INFO(discrete_op_amp_tvca_info) + + int trig0, trig1, trig2, f3; + double i2 = 0; /* current through r2 */ + double i3 = 0; /* current through r3 */ + double i_neg = 0; /* current into - input */ + double i_pos = 0; /* current into + input */ + double i_out = 0; /* current at output */ + + double v_out; + + trig0 = (int)DST_TVCA_OP_AMP__TRG0; + trig1 = (int)DST_TVCA_OP_AMP__TRG1; + trig2 = (int)DST_TVCA_OP_AMP__TRG2; + f3 = dst_trigger_function(trig0, trig1, trig2, info->f3); + + if ((info->r2 != 0) && dst_trigger_function(trig0, trig1, trig2, info->f0)) + { + /* r2 is present, so we assume Input 0 is connected and valid. */ + i2 = (DST_TVCA_OP_AMP__INP0 - OP_AMP_NORTON_VBE) / info->r2; + if ( i2 < 0) i2 = 0; + } + + if ((info->r3 != 0) && dst_trigger_function(trig0, trig1, trig2, info->f1)) + { + /* r2 is present, so we assume Input 1 is connected and valid. */ + /* Function F1 is not grounding the circuit. */ + i3 = (DST_TVCA_OP_AMP__INP1 - OP_AMP_NORTON_VBE) / info->r3; + if ( i3 < 0) i3 = 0; + } + + /* Calculate current going in to - input. */ + i_neg = m_i_fixed + i2 + i3; + + /* Update the c1 cap voltage. */ + if (dst_trigger_function(trig0, trig1, trig2, info->f2)) + { + /* F2 is not grounding the circuit so we charge the cap. */ + m_v_cap1 += (m_v_trig[f3] - m_v_cap1) * m_exponent_c[f3]; + } + else + { + /* F2 is at ground. The diode blocks this so F2 and r5 are out of circuit. + * So now the discharge rate is dependent upon F3. + * If F3 is at ground then we discharge to 0V through r6. + * If F3 is out of circuit then we discharge to OP_AMP_NORTON_VBE through r6+r7. */ + m_v_cap1 += ((f3 ? OP_AMP_NORTON_VBE : 0.0) - m_v_cap1) * m_exponent_d[f3]; + } + + /* Calculate c1 current going in to + input. */ + i_pos = (m_v_cap1 - OP_AMP_NORTON_VBE) / m_r67; + if ((i_pos < 0) || !f3) i_pos = 0; + + /* Update the c2 cap voltage and current. */ + if (info->r9 != 0) + { + f3 = dst_trigger_function(trig0, trig1, trig2, info->f4); + m_v_cap2 += ((f3 ? m_v_trig2 : 0) - m_v_cap2) * m_exponent2[f3]; + i_pos += m_v_cap2 / info->r9; + } + + /* Update the c3 cap voltage and current. */ + if (info->r11 != 0) + { + f3 = dst_trigger_function(trig0, trig1, trig2, info->f5); + m_v_cap3 += ((f3 ? m_v_trig3 : 0) - m_v_cap3) * m_exponent3[f3]; + i_pos += m_v_cap3 / info->r11; + } + + /* Calculate output current. */ + i_out = i_pos - i_neg; + if (i_out < 0) i_out = 0; + + /* Convert to voltage for final output. */ + if (m_has_c4) + { + if (m_has_r4) + { + /* voltage across r4 charging cap */ + i_out *= info->r4; + /* exponential charge */ + m_v_cap4 += (i_out - m_v_cap4) * m_exponent4; + } + else + /* linear charge */ + m_v_cap4 += i_out / m_exponent4; + if (m_v_cap4 < 0) + m_v_cap4 = 0; + v_out = m_v_cap4; + } + else + v_out = i_out * info->r4; + + + + /* Clip the output if needed. */ + if (v_out > m_v_out_max) v_out = m_v_out_max; + + set_output(0, v_out); +} + +DISCRETE_RESET(dst_tvca_op_amp) +{ + DISCRETE_DECLARE_INFO(discrete_op_amp_tvca_info) + + m_r67 = info->r6 + info->r7; + + m_v_out_max = info->vP - OP_AMP_NORTON_VBE; + /* This is probably overkill because R5 is usually much lower then r6 or r7, + * but it is better to play it safe. */ + m_v_trig[0] = (info->v1 - 0.6) * RES_VOLTAGE_DIVIDER(info->r5, info->r6); + m_v_trig[1] = (info->v1 - 0.6 - OP_AMP_NORTON_VBE) * RES_VOLTAGE_DIVIDER(info->r5, m_r67) + OP_AMP_NORTON_VBE; + m_i_fixed = m_v_out_max / info->r1; + + m_v_cap1 = 0; + /* Charge rate through r5 */ + /* There can be a different charge rates depending on function F3. */ + m_exponent_c[0] = RC_CHARGE_EXP(RES_2_PARALLEL(info->r5, info->r6) * info->c1); + m_exponent_c[1] = RC_CHARGE_EXP(RES_2_PARALLEL(info->r5, m_r67) * info->c1); + /* Discharge rate through r6 + r7 */ + m_exponent_d[1] = RC_CHARGE_EXP(m_r67 * info->c1); + /* Discharge rate through r6 */ + if (info->r6 != 0) + { + m_exponent_d[0] = RC_CHARGE_EXP(info->r6 * info->c1); + } + m_v_cap2 = 0; + m_v_trig2 = (info->v2 - 0.6 - OP_AMP_NORTON_VBE) * RES_VOLTAGE_DIVIDER(info->r8, info->r9); + m_exponent2[0] = RC_CHARGE_EXP(info->r9 * info->c2); + m_exponent2[1] = RC_CHARGE_EXP(RES_2_PARALLEL(info->r8, info->r9) * info->c2); + m_v_cap3 = 0; + m_v_trig3 = (info->v3 - 0.6 - OP_AMP_NORTON_VBE) * RES_VOLTAGE_DIVIDER(info->r10, info->r11); + m_exponent3[0] = RC_CHARGE_EXP(info->r11 * info->c3); + m_exponent3[1] = RC_CHARGE_EXP(RES_2_PARALLEL(info->r10, info->r11) * info->c3); + m_v_cap4 = 0; + if (info->r4 != 0) m_has_r4 = 1; + if (info->c4 != 0) m_has_c4 = 1; + if (m_has_r4 && m_has_c4) + m_exponent4 = RC_CHARGE_EXP(info->r4 * info->c4); + + this->step(); +} + + +/* the different logic and xtime states */ +enum +{ + XTIME__IN0_0__IN1_0__IN0_NOX__IN1_NOX = 0, + XTIME__IN0_0__IN1_0__IN0_NOX__IN1_X, + XTIME__IN0_0__IN1_0__IN0_X__IN1_NOX, + XTIME__IN0_0__IN1_0__IN0_X__IN1_X, + XTIME__IN0_0__IN1_1__IN0_NOX__IN1_NOX, + XTIME__IN0_0__IN1_1__IN0_NOX__IN1_X, + XTIME__IN0_0__IN1_1__IN0_X__IN1_NOX, + XTIME__IN0_0__IN1_1__IN0_X__IN1_X, + XTIME__IN0_1__IN1_0__IN0_NOX__IN1_NOX, + XTIME__IN0_1__IN1_0__IN0_NOX__IN1_X, + XTIME__IN0_1__IN1_0__IN0_X__IN1_NOX, + XTIME__IN0_1__IN1_0__IN0_X__IN1_X, + XTIME__IN0_1__IN1_1__IN0_NOX__IN1_NOX, + XTIME__IN0_1__IN1_1__IN0_NOX__IN1_X, + XTIME__IN0_1__IN1_1__IN0_X__IN1_NOX, + XTIME__IN0_1__IN1_1__IN0_X__IN1_X +}; + + +/************************************************************************ + * + * DST_XTIME_BUFFER - Buffer/Invertor gate implementation using X_TIME + * + * If OUT_LOW and OUT_HIGH are defined then the output will be energy. + * If they are both 0, then the output will be X_TIME logic. + * + ************************************************************************/ +#define DST_XTIME_BUFFER__IN DISCRETE_INPUT(0) +#define DST_XTIME_BUFFER_OUT_LOW DISCRETE_INPUT(1) +#define DST_XTIME_BUFFER_OUT_HIGH DISCRETE_INPUT(2) +#define DST_XTIME_BUFFER_INVERT DISCRETE_INPUT(3) + +DISCRETE_STEP(dst_xtime_buffer) +{ + int in0 = (int)DST_XTIME_BUFFER__IN; + int out = in0; + int out_is_energy = 1; + + double x_time = DST_XTIME_BUFFER__IN - in0; + + double out_low = DST_XTIME_BUFFER_OUT_LOW; + double out_high = DST_XTIME_BUFFER_OUT_HIGH; + + if (out_low ==0 && out_high == 0) + out_is_energy = 0; + + if (DST_XTIME_BUFFER_INVERT != 0) + out ^= 1; + + if (out_is_energy) + { + if (x_time > 0) + { + double diff = out_high - out_low; + diff = out ? diff * x_time : diff * (1.0 - x_time); + set_output(0, out_low + diff); + } + else + set_output(0, out ? out_high : out_low); + } + else + set_output(0, out + x_time); +} + + +/************************************************************************ + * + * DST_XTIME_AND - AND/NAND gate implementation using X_TIME + * + * If OUT_LOW and OUT_HIGH are defined then the output will be energy. + * If they are both 0, then the output will be X_TIME logic. + * + ************************************************************************/ +#define DST_XTIME_AND__IN0 DISCRETE_INPUT(0) +#define DST_XTIME_AND__IN1 DISCRETE_INPUT(1) +#define DST_XTIME_AND_OUT_LOW DISCRETE_INPUT(2) +#define DST_XTIME_AND_OUT_HIGH DISCRETE_INPUT(3) +#define DST_XTIME_AND_INVERT DISCRETE_INPUT(4) + +DISCRETE_STEP(dst_xtime_and) +{ + int in0 = (int)DST_XTIME_AND__IN0; + int in1 = (int)DST_XTIME_AND__IN1; + int out = 0; + int out_is_energy = 1; + + double x_time = 0; + double x_time0 = DST_XTIME_AND__IN0 - in0; + double x_time1 = DST_XTIME_AND__IN1 - in1; + + int in0_has_xtime = x_time0 > 0 ? 1 : 0; + int in1_has_xtime = x_time1 > 0 ? 1 : 0; + + double out_low = DST_XTIME_AND_OUT_LOW; + double out_high = DST_XTIME_AND_OUT_HIGH; + + if (out_low ==0 && out_high == 0) + out_is_energy = 0; + + switch ((in0 << 3) | (in1 << 2) | (in0_has_xtime < 1) | in1_has_xtime) + { + // these are all 0 + //case XTIME__IN0_0__IN1_0__IN0_NOX__IN1_NOX: + //case XTIME__IN0_0__IN1_1__IN0_NOX__IN1_NOX: + //case XTIME__IN0_1__IN1_0__IN0_NOX__IN1_NOX: + //case XTIME__IN0_0__IN1_0__IN0_NOX__IN1_X: + //case XTIME__IN0_0__IN1_0__IN0_X__IN1_NOX: + //case XTIME__IN0_0__IN1_1__IN0_NOX__IN1_X: + //case XTIME__IN0_1__IN1_0__IN0_X__IN1_NOX: + // break; + + case XTIME__IN0_1__IN1_1__IN0_NOX__IN1_NOX: + out = 1; + break; + + case XTIME__IN0_0__IN1_1__IN0_X__IN1_NOX: + /* + * in0 1 ------ + * 0 ------- + * ...^....^... + * + * in1 1 ------------- + * 0 + * ...^....^... + * + * out 1 ------ + * 0 ------ + * ...^....^... + */ + x_time = x_time0; + break; + + case XTIME__IN0_1__IN1_0__IN0_NOX__IN1_X: + /* + * in0 1 ------------- + * 0 + * ...^....^... + * + * in1 1 ------ + * 0 ------- + * ...^....^... + * + * out 1 ------ + * 0 ------ + * ...^....^... + */ + x_time = x_time1; + break; + + case XTIME__IN0_0__IN1_0__IN0_X__IN1_X: + /* + * in0 1 ----- ------- + * 0 -------- ------ + * ...^....^... ...^....^... + * + * in1 1 ------- ----- + * 0 ------ -------- + * ...^....^... ...^....^... + * + * out 1 ----- ----- + * 0 ------- ------- + * ...^....^... ...^....^... + */ + // use x_time of input that went to 0 first/longer + if (x_time0 >= x_time1) + x_time = x_time0; + else + x_time = x_time1; + break; + + case XTIME__IN0_0__IN1_1__IN0_X__IN1_X: + /* + * in0 1 ------- ----- + * 0 ----- ------- + * ...^....^... ...^....^... + * + * in1 1 ------- ----- + * 0 ----- ------- + * ...^....^... ...^....^... + * + * out 1 -- + * 0 ----- ----- ------------ + * ...^....^... ...^....^... + */ + // may have went high for a bit in this cycle + //if (x_time0 < x_time1) + // x_time = time1 - x_time0; + break; + + case XTIME__IN0_1__IN1_0__IN0_X__IN1_X: + /* + * in0 1 ------- ----- + * 0 ----- ------- + * ...^....^... ...^....^... + * + * in1 1 ------- ----- + * 0 ----- ------- + * ...^....^... ...^....^... + * + * out 1 -- + * 0 ----- ----- ------------ + * ...^....^... ...^....^... + */ + // may have went high for a bit in this cycle + //if (x_time0 > x_time1) + // x_time = x_time0 - x_time1; + break; + + case XTIME__IN0_1__IN1_1__IN0_NOX__IN1_X: + /* + * in0 1 ------------ + * 0 + * ...^....^... + * + * in1 1 ------ + * 0 ------ + * ...^....^... + * + * out 1 ------ + * 0 ------ + * ...^....^... + */ + out = 1; + x_time = x_time1; + break; + + case XTIME__IN0_1__IN1_1__IN0_X__IN1_NOX: + /* + * in1 0 ------ + * 0 ------ + * ...^....^... + * + * in1 1 ------------ + * 0 + * ...^....^... + * + * out 1 ------ + * 0 ------ + * ...^....^... + */ + out = 1; + x_time = x_time0; + break; + + case XTIME__IN0_1__IN1_1__IN0_X__IN1_X: + /* + * in0 1 ------ -------- + * 0 ------ ---- + * ...^....^... ...^....^... + * + * in1 1 -------- ------ + * 0 ---- ------ + * ...^....^... ...^....^... + * + * out 1 ------ ------ + * 0 ------ ------ + * ...^....^... ...^....^... + */ + out = 1; + if (x_time0 < x_time1) + x_time = x_time0; + else + x_time = x_time1; + break; + } + + if (DST_XTIME_AND_INVERT != 0) + out ^= 1; + + if (out_is_energy) + { + if (x_time > 0) + { + double diff = out_high - out_low; + diff = out ? diff * x_time : diff * (1.0 - x_time); + set_output(0, out_low + diff); + } + else + set_output(0, out ? out_high : out_low); + } + else + set_output(0, out + x_time); +} + + +/************************************************************************ + * + * DST_XTIME_OR - OR/NOR gate implementation using X_TIME + * + * If OUT_LOW and OUT_HIGH are defined then the output will be energy. + * If they are both 0, then the output will be X_TIME logic. + * + ************************************************************************/ +#define DST_XTIME_OR__IN0 DISCRETE_INPUT(0) +#define DST_XTIME_OR__IN1 DISCRETE_INPUT(1) +#define DST_XTIME_OR_OUT_LOW DISCRETE_INPUT(2) +#define DST_XTIME_OR_OUT_HIGH DISCRETE_INPUT(3) +#define DST_XTIME_OR_INVERT DISCRETE_INPUT(4) + +DISCRETE_STEP(dst_xtime_or) +{ + int in0 = (int)DST_XTIME_OR__IN0; + int in1 = (int)DST_XTIME_OR__IN1; + int out = 1; + int out_is_energy = 1; + + double x_time = 0; + double x_time0 = DST_XTIME_OR__IN0 - in0; + double x_time1 = DST_XTIME_OR__IN1 - in1; + + int in0_has_xtime = x_time0 > 0 ? 1 : 0; + int in1_has_xtime = x_time1 > 0 ? 1 : 0; + + double out_low = DST_XTIME_OR_OUT_LOW; + double out_high = DST_XTIME_OR_OUT_HIGH; + + if (out_low ==0 && out_high == 0) + out_is_energy = 0; + + switch ((in0 << 3) | (in1 << 2) | (in0_has_xtime < 1) | in1_has_xtime) + { + // these are all 1 + //case XTIME__IN0_1__IN1_1__IN0_NOX__IN1_NOX: + //case XTIME__IN0_0__IN1_1__IN0_NOX__IN1_NOX: + //case XTIME__IN0_1__IN1_0__IN0_NOX__IN1_NOX: + //case XTIME__IN0_1__IN1_0__IN0_NOX__IN1_X: + //case XTIME__IN0_0__IN1_1__IN0_X__IN1_NOX: + //case XTIME__IN0_1__IN1_1__IN0_NOX__IN1_X: + //case XTIME__IN0_1__IN1_1__IN0_X__IN1_NOX: + // break; + + case XTIME__IN0_0__IN1_0__IN0_NOX__IN1_NOX: + out = 0; + break; + + case XTIME__IN0_0__IN1_0__IN0_NOX__IN1_X: + /* + * in0 1 + * 0 ------------- + * ...^....^... + * + * in1 1 ------ + * 0 ------- + * ...^....^... + * + * out 1 ------ + * 0 ------ + * ...^....^... + */ + out = 0; + x_time = x_time1; + break; + + case XTIME__IN0_0__IN1_0__IN0_X__IN1_NOX: + /* + * in0 1 ------ + * 0 ------- + * ...^....^... + * + * in1 1 + * 0 ------------- + * ...^....^... + * + * out 1 ------ + * 0 ------ + * ...^....^... + */ + out = 0; + x_time = x_time0; + break; + + case XTIME__IN0_0__IN1_0__IN0_X__IN1_X: + /* + * in0 1 ----- ------- + * 0 -------- ------ + * ...^....^... ...^....^... + * + * in1 1 ------- ----- + * 0 ------ -------- + * ...^....^... ...^....^... + * + * out 1 ------- ------- + * 0 ----- ----- + * ...^....^... ...^....^... + */ + out = 0; + // use x_time of input that was 1 last/longer + // this means at 0 for less x_time + if (x_time0 > x_time1) + x_time = x_time1; + else + x_time = x_time0; + break; + + case XTIME__IN0_0__IN1_1__IN0_NOX__IN1_X: + /* + * in0 1 + * 0 ------------ + * ...^....^... + * + * in1 1 ------ + * 0 ------ + * ...^....^... + * + * out 1 ------ + * 0 ------ + * ...^....^... + */ + x_time = x_time1; + break; + + case XTIME__IN0_1__IN1_0__IN0_X__IN1_NOX: + /* + * in0 1 ------ + * 0 ------ + * ...^....^... + * + * in1 1 + * 0 ------------ + * ...^....^... + * + * out 1 ------ + * 0 ------ + * ...^....^... + */ + x_time = x_time0; + break; + + case XTIME__IN0_0__IN1_1__IN0_X__IN1_X: + /* + * in0 1 ------- ----- + * 0 ----- ------- + * ...^....^... ...^....^... + * + * in1 1 ------- ----- + * 0 ----- ------- + * ...^....^... ...^....^... + * + * out 1 ------------ ----- ----- + * 0 -- + * ...^....^... ...^....^... + */ + // if (x_time0 > x_time1) + /* Not sure if it is better to use 1 + * or the total energy which would smear the switch points together. + * Let's try just using 1 */ + //x_time = xtime_0 - xtime_1; + break; + + case XTIME__IN0_1__IN1_0__IN0_X__IN1_X: + /* + * in0 1 ------- ----- + * 0 ----- ------- + * ...^....^... ...^....^... + * + * in1 1 ------- ----- + * 0 ----- ------- + * ...^....^... ...^....^... + * + * out 1 ------------ ----- ----- + * 0 -- + * ...^....^... ...^....^... + */ + //if (x_time0 < x_time1) + /* Not sure if it is better to use 1 + * or the total energy which would smear the switch points together. + * Let's try just using 1 */ + //x_time = xtime_1 - xtime_0; + break; + + case XTIME__IN0_1__IN1_1__IN0_X__IN1_X: + /* + * in0 1 ------ -------- + * 0 ------ ---- + * ...^....^... ...^....^... + * + * in1 1 -------- ------ + * 0 ---- ------ + * ...^....^... ...^....^... + * + * out 1 -------- -------- + * 0 ---- ---- + * ...^....^... ...^....^... + */ + if (x_time0 > x_time1) + x_time = x_time0; + else + x_time = x_time1; + break; + } + + if (DST_XTIME_OR_INVERT != 0) + out ^= 1; + + if (out_is_energy) + { + if (x_time > 0) + { + double diff = out_high - out_low; + diff = out ? diff * x_time : diff * (1.0 - x_time); + set_output(0, out_low + diff); + } + else + set_output(0, out ? out_high : out_low); + } + else + set_output(0, out + x_time); +} + + +/************************************************************************ + * + * DST_XTIME_XOR - XOR/XNOR gate implementation using X_TIME + * + * If OUT_LOW and OUT_HIGH are defined then the output will be energy. + * If they are both 0, then the output will be X_TIME logic. + * + ************************************************************************/ +#define DST_XTIME_XOR__IN0 DISCRETE_INPUT(0) +#define DST_XTIME_XOR__IN1 DISCRETE_INPUT(1) +#define DST_XTIME_XOR_OUT_LOW DISCRETE_INPUT(2) +#define DST_XTIME_XOR_OUT_HIGH DISCRETE_INPUT(3) +#define DST_XTIME_XOR_INVERT DISCRETE_INPUT(4) + +DISCRETE_STEP(dst_xtime_xor) +{ + int in0 = (int)DST_XTIME_XOR__IN0; + int in1 = (int)DST_XTIME_XOR__IN1; + int out = 1; + int out_is_energy = 1; + + double x_time = 0; + double x_time0 = DST_XTIME_XOR__IN0 - in0; + double x_time1 = DST_XTIME_XOR__IN1 - in1; + + int in0_has_xtime = x_time0 > 0 ? 1 : 0; + int in1_has_xtime = x_time1 > 0 ? 1 : 0; + + double out_low = DST_XTIME_XOR_OUT_LOW; + double out_high = DST_XTIME_XOR_OUT_HIGH; + + if (out_low ==0 && out_high == 0) + out_is_energy = 0; + + switch ((in0 << 3) | (in1 << 2) | (in0_has_xtime < 1) | in1_has_xtime) + { + // these are all 1 + //case XTIME__IN0_0__IN1_1__IN0_NOX__IN1_NOX: + //case XTIME__IN0_1__IN1_0__IN0_NOX__IN1_NOX: + // break; + + case XTIME__IN0_1__IN1_1__IN0_NOX__IN1_NOX: + case XTIME__IN0_0__IN1_0__IN0_NOX__IN1_NOX: + out = 0; + break; + + case XTIME__IN0_1__IN1_0__IN0_X__IN1_NOX: + /* + * in0 1 ------ + * 0 ------ + * ...^....^... + * + * in1 1 + * 0 ------------ + * ...^....^... + * + * out 1 ------ + * 0 ------ + * ...^....^... + */ + case XTIME__IN0_0__IN1_1__IN0_X__IN1_NOX: + /* + * in0 1 ------ + * 0 ------- + * ...^....^... + * + * in1 1 ------------- + * 0 + * ...^....^... + * + * out 1 ------ + * 0 ------ + * ...^....^... + */ + x_time = x_time0; + break; + + case XTIME__IN0_0__IN1_1__IN0_NOX__IN1_X: + /* + * in0 1 + * 0 ------------ + * ...^....^... + * + * in1 1 ------ + * 0 ------ + * ...^....^... + * + * out 1 ------ + * 0 ------ + * ...^....^... + */ + case XTIME__IN0_1__IN1_0__IN0_NOX__IN1_X: + /* + * in0 1 ------------- + * 0 + * ...^....^... + * + * in1 1 ------ + * 0 ------- + * ...^....^... + * + * out 1 ------ + * 0 ------ + * ...^....^... + */ + x_time = x_time1; + break; + + case XTIME__IN0_0__IN1_0__IN0_X__IN1_NOX: + /* + * in0 1 ------ + * 0 ------ + * ...^....^... + * + * in1 1 + * 0 ------------ + * ...^....^... + * + * out 1 ------ + * 0 ------ + * ...^....^... + */ + case XTIME__IN0_1__IN1_1__IN0_X__IN1_NOX: + /* + * in1 0 ------ + * 0 ------ + * ...^....^... + * + * in1 1 ------------ + * 0 + * ...^....^... + * + * out 1 ------ + * 0 ------ + * ...^....^... + */ + out = 0; + x_time = x_time0; + break; + + case XTIME__IN0_0__IN1_0__IN0_NOX__IN1_X: + /* + * in0 1 + * 0 ------------ + * ...^....^... + * + * in1 1 ------ + * 0 ------ + * ...^....^... + * + * out 1 ------ + * 0 ------ + * ...^....^... + */ + case XTIME__IN0_1__IN1_1__IN0_NOX__IN1_X: + /* + * in0 1 ------------ + * 0 + * ...^....^... + * + * in1 1 ------ + * 0 ------ + * ...^....^... + * + * out 1 ------ + * 0 ------ + * ...^....^... + */ + out = 0; + x_time = x_time1; + break; + + case XTIME__IN0_0__IN1_0__IN0_X__IN1_X: + /* + * in0 1 ----- ------- + * 0 ------- ----- + * ...^....^... ...^....^... + * + * in1 1 ------- ----- + * 0 ----- ------- + * ...^....^... ...^....^... + * + * out 1 -- -- + * 0 ----- ----- ----- ----- + * ...^....^... ...^....^... + */ + case XTIME__IN0_1__IN1_1__IN0_X__IN1_X: + /* + * in0 1 ------ -------- + * 0 ------ ---- + * ...^....^... ...^....^... + * + * in1 1 -------- ------ + * 0 ---- ------ + * ...^....^... ...^....^... + * + * out 1 -- -- + * 0 ---- ------ ---- ------ + * ...^....^... ...^....^... + */ + out = 0; + /* Not sure if it is better to use 0 + * or the total energy which would smear the switch points together. + * Let's try just using 0 */ + // x_time = abs(x_time0 - x_time1); + break; + + case XTIME__IN0_0__IN1_1__IN0_X__IN1_X: + /* + * in0 1 ------- ----- + * 0 ----- ------- + * ...^....^... ...^....^... + * + * in1 1 ------- ----- + * 0 ----- ------- + * ...^....^... ...^....^... + * + * out 1 ----- ----- ----- ----- + * 0 -- -- + * ...^....^... ...^....^... + */ + case XTIME__IN0_1__IN1_0__IN0_X__IN1_X: + /* + * in0 1 ------- ----- + * 0 ----- ------- + * ...^....^... ...^....^... + * + * in1 1 ------- ----- + * 0 ----- ------- + * ...^....^... ...^....^... + * + * out 1 ----- ----- ----- ----- + * 0 -- -- + * ...^....^... ...^....^... + */ + /* Not sure if it is better to use 1 + * or the total energy which would smear the switch points together. + * Let's try just using 1 */ + // x_time = 1.0 - abs(x_time0 - x_time1); + break; +} + + if (DST_XTIME_XOR_INVERT != 0) + out ^= 1; + + if (out_is_energy) + { + if (x_time > 0) + { + double diff = out_high - out_low; + diff = out ? diff * x_time : diff * (1.0 - x_time); + set_output(0, out_low + diff); + } + else + set_output(0, out ? out_high : out_low); + } + else + set_output(0, out + x_time); +} diff --git a/src/devices/sound/disc_sys.inc b/src/devices/sound/disc_sys.inc new file mode 100644 index 00000000000..4192e832d93 --- /dev/null +++ b/src/devices/sound/disc_sys.inc @@ -0,0 +1,123 @@ +// license:BSD-3-Clause +// copyright-holders:K.Wilkins +/************************************************************************ + * + * MAME - Discrete sound system emulation library + * + * Written by K.Wilkins (mame@esplexo.co.uk) + * + * (c) K.Wilkins 2000 + * (c) Derrick Renaud 2003-2004 + * + ************************************************************************ + * + * DSO_OUTPUT - Output node + * DSO_TASK - Task node + * + * Task and list routines + * + ************************************************************************/ + + + + +/************************************* + * + * Task node (main task execution) + * + *************************************/ + +DISCRETE_START( dso_csvlog ) +{ + int log_num, node_num; + + log_num = m_device->same_module_index(*this); + m_sample_num = 0; + + sprintf(m_name, "discrete_%s_%d.csv", m_device->tag(), log_num); + m_csv_file = fopen(m_name, "w"); + /* Output some header info */ + fprintf(m_csv_file, "\"MAME Discrete System Node Log\"\n"); + fprintf(m_csv_file, "\"Log Version\", 1.0\n"); + fprintf(m_csv_file, "\"Sample Rate\", %d\n", this->sample_rate()); + fprintf(m_csv_file, "\n"); + fprintf(m_csv_file, "\"Sample\""); + for (node_num = 0; node_num < this->active_inputs(); node_num++) + { + fprintf(m_csv_file, ", \"NODE_%2d\"", NODE_INDEX(this->input_node(node_num))); + } + fprintf(m_csv_file, "\n"); +} + +DISCRETE_STOP( dso_csvlog ) +{ + /* close any csv files */ + if (m_csv_file) + fclose(m_csv_file); +} + +DISCRETE_STEP( dso_csvlog ) +{ + int nodenum; + + /* Dump any csv logs */ + fprintf(m_csv_file, "%" I64FMT "d", ++m_sample_num); + for (nodenum = 0; nodenum < this->active_inputs(); nodenum++) + { + fprintf(m_csv_file, ", %f", *this->m_input[nodenum]); + } + fprintf(m_csv_file, "\n"); +} + +DISCRETE_RESET( dso_csvlog ) +{ + this->step(); +} + + +DISCRETE_START( dso_wavlog ) +{ + int log_num; + + log_num = m_device->same_module_index(*this); + sprintf(m_name, "discrete_%s_%d.wav", m_device->tag(), log_num); + m_wavfile = wav_open(m_name, sample_rate(), active_inputs()/2); +} + +DISCRETE_STOP( dso_wavlog ) +{ + /* close any wave files */ + if (m_wavfile) + wav_close(m_wavfile); +} + +DISCRETE_STEP( dso_wavlog ) +{ + double val; + INT16 wave_data_l, wave_data_r; + + /* Dump any wave logs */ + /* get nodes to be logged and apply gain, then clip to 16 bit */ + val = DISCRETE_INPUT(0) * DISCRETE_INPUT(1); + val = (val < -32768) ? -32768 : (val > 32767) ? 32767 : val; + wave_data_l = (INT16)val; + if (this->active_inputs() == 2) + { + /* DISCRETE_WAVLOG1 */ + wav_add_data_16(m_wavfile, &wave_data_l, 1); + } + else + { + /* DISCRETE_WAVLOG2 */ + val = DISCRETE_INPUT(2) * DISCRETE_INPUT(3); + val = (val < -32768) ? -32768 : (val > 32767) ? 32767 : val; + wave_data_r = (INT16)val; + + wav_add_data_16lr(m_wavfile, &wave_data_l, &wave_data_r, 1); + } +} + +DISCRETE_RESET( dso_wavlog ) +{ + this->step(); +} diff --git a/src/devices/sound/disc_wav.h b/src/devices/sound/disc_wav.h new file mode 100644 index 00000000000..4775dd8fe68 --- /dev/null +++ b/src/devices/sound/disc_wav.h @@ -0,0 +1,193 @@ +// license:BSD-3-Clause +// copyright-holders:K.Wilkins +#pragma once + +#ifndef __DISC_WAV_H__ +#define __DISC_WAV_H__ + +/*********************************************************************** + * + * MAME - Discrete sound system emulation library + * + * Written by K.Wilkins (mame@esplexo.co.uk) + * + * (c) K.Wilkins 2000 + * + * Coding started in November 2000 + * + * Additions/bugfix February 2003 - Derrick Renaud, F.Palazzolo, K.Wilkins + * Discrete parallel tasks 2009 - Couriersud + * Discrete classes 2010 - Couriersud + * + ***********************************************************************/ + +#include "discrete.h" + +DISCRETE_CLASS_STEP_RESET(dss_counter, 1, + int m_clock_type; + int m_out_type; + int m_is_7492; + int m_last_clock; + UINT32 m_last_count; + //UINT32 m_last; /* Last clock state */ + UINT32 m_min; + UINT32 m_max; + UINT32 m_diff; + double m_t_left; /* time unused during last sample in seconds */ +); + +DISCRETE_CLASS_STEP_RESET(dss_lfsr_noise, 2, + unsigned int m_lfsr_reg; + int m_last; /* Last clock state */ + double m_t_clock; /* fixed counter clock in seconds */ + double m_t_left; /* time unused during last sample in seconds */ + //double m_sample_step; + //double m_t; + UINT8 m_reset_on_high; + UINT8 m_invert_output; + UINT8 m_out_is_f0; + UINT8 m_out_lfsr_reg; +); + +DISCRETE_CLASS_STEP_RESET(dss_noise, 2, + double m_phase; +); + +DISCRETE_CLASS_STEP_RESET(dss_note, 1, + int m_clock_type; + int m_out_type; + int m_last; /* Last clock state */ + double m_t_clock; /* fixed counter clock in seconds */ + double m_t_left; /* time unused during last sample in seconds */ + int m_max1; /* Max 1 Count stored as int for easy use. */ + int m_max2; /* Max 2 Count stored as int for easy use. */ + int m_count1; /* current count1 */ + int m_count2; /* current count2 */ +); + +DISCRETE_CLASS_STEP_RESET(dss_sawtoothwave, 1, + double m_phase; + int m_type; +); + +DISCRETE_CLASS_STEP_RESET(dss_sinewave, 1, + double m_phase; +); + +DISCRETE_CLASS_STEP_RESET(dss_squarewave, 1, + double m_phase; + double m_trigger; +); +DISCRETE_CLASS_STEP_RESET(dss_squarewfix, 1, + int m_flip_flop; + double m_sample_step; + double m_t_left; + double m_t_off; + double m_t_on; +); + +DISCRETE_CLASS_STEP_RESET(dss_squarewave2, 1, + double m_phase; + double m_trigger; +); + +DISCRETE_CLASS_STEP_RESET(dss_trianglewave, 1, + double m_phase; +); + +/* Component specific modules */ + +#define DSS_INV_TAB_SIZE 500 +#define DEFAULT_CD40XX_VALUES(_vB) (_vB),(_vB)*0.02,(_vB)*0.98,(_vB)/5.0*1.5,(_vB)/5.0*3.5, 0.1 + +class DISCRETE_CLASS_NAME(dss_inverter_osc): public discrete_base_node, public discrete_step_interface +{ + DISCRETE_CLASS_CONSTRUCTOR(dss_inverter_osc, base) + DISCRETE_CLASS_DESTRUCTOR(dss_inverter_osc) +public: + struct description + { + double vB; + double vOutLow; + double vOutHigh; + double vInFall; // voltage that triggers the gate input to go low (0V) on fall + double vInRise; // voltage that triggers the gate input to go high (vGate) on rise + double clamp; // voltage is clamped to -clamp ... vb+clamp if clamp>= 0; + int options; // bitmaped options + }; + enum { + IS_TYPE1 = 0x00, + IS_TYPE2 = 0x01, + IS_TYPE3 = 0x02, + IS_TYPE4 = 0x03, + IS_TYPE5 = 0x04, + TYPE_MASK = 0x0f, + OUT_IS_LOGIC = 0x10 + }; + void step(void); + void reset(void); +protected: + inline double tftab(double x); + inline double tf(double x); +private: + DISCRETE_CLASS_INPUT(I_ENABLE, 0); + DISCRETE_CLASS_INPUT(I_MOD, 1); + DISCRETE_CLASS_INPUT(I_RC, 2); + DISCRETE_CLASS_INPUT(I_RP, 3); + DISCRETE_CLASS_INPUT(I_C, 4); + DISCRETE_CLASS_INPUT(I_R2, 5); + + double mc_v_cap; + double mc_v_g2_old; + double mc_w; + double mc_wc; + double mc_rp; + double mc_r1; + double mc_r2; + double mc_c; + double mc_tf_a; + double mc_tf_b; + double mc_tf_tab[DSS_INV_TAB_SIZE]; +}; + +DISCRETE_CLASS_STEP_RESET(dss_op_amp_osc, 1, + const double * m_r[8]; /* pointers to resistor values */ + int m_type; + UINT8 m_flip_flop; /* flip/flop output state */ + UINT8 m_flip_flop_xor; /* flip_flop ^ flip_flop_xor, 0 = discharge, 1 = charge */ + UINT8 m_output_type; + UINT8 m_has_enable; + double m_v_out_high; + double m_threshold_low; /* falling threshold */ + double m_threshold_high; /* rising threshold */ + double m_v_cap; /* current capacitor voltage */ + double m_r_total; /* all input resistors in parallel */ + double m_i_fixed; /* fixed current at the input */ + double m_i_enable; /* fixed current at the input if enabled */ + double m_temp1; /* Multi purpose */ + double m_temp2; /* Multi purpose */ + double m_temp3; /* Multi purpose */ + double m_is_linear_charge; + double m_charge_rc[2]; + double m_charge_exp[2]; + double m_charge_v[2]; +); + +DISCRETE_CLASS_STEP_RESET(dss_schmitt_osc, 1, + double m_ration_in; /* ratio of total charging voltage that comes from the input */ + double m_ratio_feedback; /* ratio of total charging voltage that comes from the feedback */ + double m_v_cap; /* current capacitor voltage */ + double m_rc; /* r*c */ + double m_exponent; + int m_state; /* state of the output */ + int m_enable_type; + UINT8 m_input_is_voltage; +); + +/* Not yet implemented */ +DISCRETE_CLASS_STEP_RESET(dss_adsrenv, 1, + //double m_phase; +); + + +#endif /* __DISC_WAV_H__ */ diff --git a/src/devices/sound/disc_wav.inc b/src/devices/sound/disc_wav.inc new file mode 100644 index 00000000000..57a90ae5a5b --- /dev/null +++ b/src/devices/sound/disc_wav.inc @@ -0,0 +1,1787 @@ +// license:BSD-3-Clause +// copyright-holders:K.Wilkins +/************************************************************************ + * + * MAME - Discrete sound system emulation library + * Written by K.Wilkins (mame@esplexo.co.uk) + * + * (c) K.Wilkins 2000 + * + ************************************************************************ + * + * DSS_COUNTER - External clock Binary Counter + * DSS_LFSR_NOISE - Linear Feedback Shift Register Noise + * DSS_NOISE - Noise Source - Random source + * DSS_NOTE - Note/tone generator + * DSS_OP_AMP_OSC - Op Amp oscillator circuits + * DSS_SAWTOOTHWAVE - Sawtooth waveform generator + * DSS_SCHMITT_OSC - Schmitt Feedback Oscillator + * DSS_SINEWAVE - Sinewave generator source code + * DSS_SQUAREWAVE - Squarewave generator source code + * DSS_SQUAREWFIX - Squarewave generator - fixed frequency + * DSS_SQUAREWAVE2 - Squarewave generator - by t_on/t_off + * DSS_TRIANGLEWAVE - Triangle waveform generator + * + ************************************************************************/ + + + + + + + +/************************************************************************ + * + * DSS_COUNTER - External clock Binary Counter + * + * input0 - Enable input value + * input1 - Reset input (active high) + * input2 - Clock Input + * input3 - Max count + * input4 - Direction - 0=down, 1=up + * input5 - Reset Value + * input6 - Clock type + * + * Jan 2004, D Renaud. + ************************************************************************/ +#define DSS_COUNTER__ENABLE DISCRETE_INPUT(0) +#define DSS_COUNTER__RESET DISCRETE_INPUT(1) +#define DSS_COUNTER__CLOCK DISCRETE_INPUT(2) +#define DSS_COUNTER__MIN DISCRETE_INPUT(3) +#define DSS_COUNTER__MAX DISCRETE_INPUT(4) +#define DSS_COUNTER__DIR DISCRETE_INPUT(5) +#define DSS_COUNTER__INIT DISCRETE_INPUT(6) +#define DSS_COUNTER__CLOCK_TYPE DISCRETE_INPUT(7) +#define DSS_7492__CLOCK_TYPE DSS_COUNTER__MIN + +static const int disc_7492_count[6] = {0x00, 0x01, 0x02, 0x04, 0x05, 0x06}; + +DISCRETE_STEP(dss_counter) +{ + double cycles; + double ds_clock; + int clock = 0, inc = 0; + UINT32 last_count = m_last_count; /* it is different then output in 7492 */ + double x_time = 0; + UINT32 count = last_count; + + ds_clock = DSS_COUNTER__CLOCK; + if (UNEXPECTED(m_clock_type == DISC_CLK_IS_FREQ)) + { + /* We need to keep clocking the internal clock even if disabled. */ + cycles = (m_t_left + this->sample_time()) * ds_clock; + inc = (int)cycles; + m_t_left = (cycles - inc) / ds_clock; + if (inc) x_time = m_t_left / this->sample_time(); + } + else + { + clock = (int)ds_clock; + /* x_time from input clock */ + x_time = ds_clock - clock; + } + + + /* If reset enabled then set output to the reset value. No x_time in reset. */ + if (UNEXPECTED(DSS_COUNTER__RESET)) + { + m_last_count = (int)DSS_COUNTER__INIT; + set_output(0, (int)DSS_COUNTER__INIT); + return; + } + + /* + * Only count if module is enabled. + * This has the effect of holding the output at it's current value. + */ + if (EXPECTED(DSS_COUNTER__ENABLE)) + { + double v_out; + + switch (m_clock_type) + { + case DISC_CLK_ON_F_EDGE: + case DISC_CLK_ON_R_EDGE: + /* See if the clock has toggled to the proper edge */ + clock = (clock != 0); + if (m_last_clock != clock) + { + m_last_clock = clock; + if (m_clock_type == clock) + { + /* Toggled */ + inc = 1; + } + } + break; + + case DISC_CLK_BY_COUNT: + /* Clock number of times specified. */ + inc = clock; + break; + } + + /* use loops because init is not always min or max */ + if (DSS_COUNTER__DIR) + { + count += inc; + while (count > m_max) + { + count -= m_diff; + } + } + else + { + count -= inc; + while (count < m_min || count > (0xffffffff - inc)) + { + count += m_diff; + } + } + + m_last_count = count; + v_out = m_is_7492 ? disc_7492_count[count] : count; + + if (UNEXPECTED(count != last_count)) + { + /* the x_time is only output if the output changed. */ + switch (m_out_type) + { + case DISC_OUT_HAS_XTIME: + v_out += x_time; + break; + case DISC_OUT_IS_ENERGY: + if (x_time == 0) x_time = 1.0; + v_out = last_count; + if (count > last_count) + v_out += (count - last_count) * x_time; + else + v_out -= (last_count - count) * x_time; + break; + } + } + set_output(0, v_out); + } +} + +DISCRETE_RESET(dss_counter) +{ + if ((int)DSS_COUNTER__CLOCK_TYPE & DISC_COUNTER_IS_7492) + { + m_is_7492 = 1; + m_clock_type = DSS_7492__CLOCK_TYPE; + m_max = 5; + m_min = 0; + m_diff = 6; + } + else + { + m_is_7492 = 0; + m_clock_type = DSS_COUNTER__CLOCK_TYPE; + m_max = DSS_COUNTER__MAX; + m_min = DSS_COUNTER__MIN; + m_diff = m_max - m_min + 1; + } + + + if (!m_is_7492 && (DSS_COUNTER__MAX < DSS_COUNTER__MIN)) + fatalerror("MAX < MIN in NODE_%02d\n", this->index()); + + m_out_type = m_clock_type & DISC_OUT_MASK; + m_clock_type &= DISC_CLK_MASK; + + m_t_left = 0; + m_last_count = 0; + m_last_clock = 0; + set_output(0, DSS_COUNTER__INIT); /* count starts at reset value */ +} + + +/************************************************************************ + * + * DSS_LFSR_NOISE - Usage of node_description values for LFSR noise gen + * + * input0 - Enable input value + * input1 - Register reset + * input2 - Clock Input + * input3 - Amplitude input value + * input4 - Input feed bit + * input5 - Bias + * + * also passed dss_lfsr_context structure + * + ************************************************************************/ +#define DSS_LFSR_NOISE__ENABLE DISCRETE_INPUT(0) +#define DSS_LFSR_NOISE__RESET DISCRETE_INPUT(1) +#define DSS_LFSR_NOISE__CLOCK DISCRETE_INPUT(2) +#define DSS_LFSR_NOISE__AMP DISCRETE_INPUT(3) +#define DSS_LFSR_NOISE__FEED DISCRETE_INPUT(4) +#define DSS_LFSR_NOISE__BIAS DISCRETE_INPUT(5) + +INLINE int dss_lfsr_function(discrete_device *dev, int myfunc, int in0, int in1, int bitmask) +{ + int retval; + + in0 &= bitmask; + in1 &= bitmask; + + switch(myfunc) + { + case DISC_LFSR_XOR: + retval = in0 ^ in1; + break; + case DISC_LFSR_OR: + retval = in0 | in1; + break; + case DISC_LFSR_AND: + retval = in0 & in1; + break; + case DISC_LFSR_XNOR: + retval = in0 ^ in1; + retval = retval ^ bitmask; /* Invert output */ + break; + case DISC_LFSR_NOR: + retval = in0 | in1; + retval = retval ^ bitmask; /* Invert output */ + break; + case DISC_LFSR_NAND: + retval = in0 & in1; + retval = retval ^ bitmask; /* Invert output */ + break; + case DISC_LFSR_IN0: + retval = in0; + break; + case DISC_LFSR_IN1: + retval = in1; + break; + case DISC_LFSR_NOT_IN0: + retval = in0 ^ bitmask; + break; + case DISC_LFSR_NOT_IN1: + retval = in1 ^ bitmask; + break; + case DISC_LFSR_REPLACE: + retval = in0 & ~in1; + retval = retval | in1; + break; + case DISC_LFSR_XOR_INV_IN0: + retval = in0 ^ bitmask; /* invert in0 */ + retval = retval ^ in1; /* xor in1 */ + break; + case DISC_LFSR_XOR_INV_IN1: + retval = in1 ^ bitmask; /* invert in1 */ + retval = retval ^ in0; /* xor in0 */ + break; + default: + dev->discrete_log("dss_lfsr_function - Invalid function type passed"); + retval=0; + break; + } + return retval; +} + + +DISCRETE_STEP(dss_lfsr_noise) +{ + DISCRETE_DECLARE_INFO(discrete_lfsr_desc) + + double cycles; + int clock, inc = 0; + int fb0, fb1, fbresult = 0, noise_feed; + + if (info->clock_type == DISC_CLK_IS_FREQ) + { + /* We need to keep clocking the internal clock even if disabled. */ + cycles = (m_t_left + this->sample_time()) / m_t_clock; + inc = (int)cycles; + m_t_left = (cycles - inc) * m_t_clock; + } + + /* Reset everything if necessary */ + if(((DSS_LFSR_NOISE__RESET == 0) ? 0 : 1) == m_reset_on_high) + { + this->reset(); + return; + } + + switch (info->clock_type) + { + case DISC_CLK_ON_F_EDGE: + case DISC_CLK_ON_R_EDGE: + /* See if the clock has toggled to the proper edge */ + clock = (DSS_LFSR_NOISE__CLOCK != 0); + if (m_last != clock) + { + m_last = clock; + if (info->clock_type == clock) + { + /* Toggled */ + inc = 1; + } + } + break; + + case DISC_CLK_BY_COUNT: + /* Clock number of times specified. */ + inc = (int)DSS_LFSR_NOISE__CLOCK; + break; + } + + if (inc > 0) + { + double v_out; + + noise_feed = (DSS_LFSR_NOISE__FEED ? 0x01 : 0x00); + for (clock = 0; clock < inc; clock++) + { + /* Fetch the last feedback result */ + fbresult = (m_lfsr_reg >> info->bitlength) & 0x01; + + /* Stage 2 feedback combine fbresultNew with infeed bit */ + fbresult = dss_lfsr_function(m_device, info->feedback_function1, fbresult, noise_feed, 0x01); + + /* Stage 3 first we setup where the bit is going to be shifted into */ + fbresult = fbresult * info->feedback_function2_mask; + /* Then we left shift the register, */ + m_lfsr_reg = m_lfsr_reg << 1; + /* Now move the fbresult into the shift register and mask it to the bitlength */ + m_lfsr_reg = dss_lfsr_function(m_device, info->feedback_function2, fbresult, m_lfsr_reg, (1 << info->bitlength) - 1 ); + + /* Now get and store the new feedback result */ + /* Fetch the feedback bits */ + fb0 = (m_lfsr_reg >> info->feedback_bitsel0) & 0x01; + fb1 = (m_lfsr_reg >> info->feedback_bitsel1) & 0x01; + /* Now do the combo on them */ + fbresult = dss_lfsr_function(m_device, info->feedback_function0, fb0, fb1, 0x01); + m_lfsr_reg = dss_lfsr_function(m_device, DISC_LFSR_REPLACE, m_lfsr_reg, fbresult << info->bitlength, (2 << info->bitlength) - 1); + + } + /* Now select the output bit */ + if (m_out_is_f0) + v_out = fbresult & 0x01; + else + v_out = (m_lfsr_reg >> info->output_bit) & 0x01; + + /* Final inversion if required */ + if (m_invert_output) v_out = v_out ? 0 : 1; + + /* Gain stage */ + v_out = v_out ? DSS_LFSR_NOISE__AMP / 2 : -DSS_LFSR_NOISE__AMP / 2; + /* Bias input as required */ + v_out = v_out + DSS_LFSR_NOISE__BIAS; + + set_output(0, v_out); + + /* output the lfsr reg ?*/ + if (m_out_lfsr_reg) + set_output(1, (double) m_lfsr_reg); + + } + if(!DSS_LFSR_NOISE__ENABLE) + { + set_output(0, 0); + } +} + +DISCRETE_RESET(dss_lfsr_noise) +{ + DISCRETE_DECLARE_INFO(discrete_lfsr_desc) + + int fb0 , fb1, fbresult; + double v_out; + + m_reset_on_high = (info->flags & DISC_LFSR_FLAG_RESET_TYPE_H) ? 1 : 0; + m_invert_output = info->flags & DISC_LFSR_FLAG_OUT_INVERT; + m_out_is_f0 = (info->flags & DISC_LFSR_FLAG_OUTPUT_F0) ? 1 : 0; + m_out_lfsr_reg = (info->flags & DISC_LFSR_FLAG_OUTPUT_SR_SN1) ? 1 : 0; + + if ((info->clock_type < DISC_CLK_ON_F_EDGE) || (info->clock_type > DISC_CLK_IS_FREQ)) + m_device->discrete_log("Invalid clock type passed in NODE_%d\n", this->index()); + + m_last = (DSS_COUNTER__CLOCK != 0); + if (info->clock_type == DISC_CLK_IS_FREQ) m_t_clock = 1.0 / DSS_LFSR_NOISE__CLOCK; + m_t_left = 0; + + m_lfsr_reg = info->reset_value; + + /* Now get and store the new feedback result */ + /* Fetch the feedback bits */ + fb0 = (m_lfsr_reg >> info->feedback_bitsel0) & 0x01; + fb1=(m_lfsr_reg >> info->feedback_bitsel1) & 0x01; + /* Now do the combo on them */ + fbresult = dss_lfsr_function(m_device, info->feedback_function0, fb0, fb1, 0x01); + m_lfsr_reg=dss_lfsr_function(m_device, DISC_LFSR_REPLACE, m_lfsr_reg, fbresult << info->bitlength, (2<< info->bitlength ) - 1); + + /* Now select and setup the output bit */ + v_out = (m_lfsr_reg >> info->output_bit) & 0x01; + + /* Final inversion if required */ + if(info->flags & DISC_LFSR_FLAG_OUT_INVERT) v_out = v_out ? 0 : 1; + + /* Gain stage */ + v_out = v_out ? DSS_LFSR_NOISE__AMP / 2 : -DSS_LFSR_NOISE__AMP / 2; + /* Bias input as required */ + v_out += DSS_LFSR_NOISE__BIAS; + + set_output(0, v_out); + set_output(1, 0); +} + + +/************************************************************************ + * + * DSS_NOISE - Usage of node_description values for white nose generator + * + * input0 - Enable input value + * input1 - Noise sample frequency + * input2 - Amplitude input value + * input3 - DC Bias value + * + ************************************************************************/ +#define DSS_NOISE__ENABLE DISCRETE_INPUT(0) +#define DSS_NOISE__FREQ DISCRETE_INPUT(1) +#define DSS_NOISE__AMP DISCRETE_INPUT(2) +#define DSS_NOISE__BIAS DISCRETE_INPUT(3) + +DISCRETE_STEP(dss_noise) +{ + double v_out; + + if(DSS_NOISE__ENABLE) + { + /* Only sample noise on rollover to next cycle */ + if(m_phase > (2.0 * M_PI)) + { + /* GCC's rand returns a RAND_MAX value of 0x7fff */ + int newval = (m_device->machine().rand() & 0x7fff) - 16384; + + /* make sure the peak to peak values are the amplitude */ + v_out = DSS_NOISE__AMP / 2; + if (newval > 0) + v_out *= ((double)newval / 16383); + else + v_out *= ((double)newval / 16384); + + /* Add DC Bias component */ + v_out += DSS_NOISE__BIAS; + set_output(0, v_out); + } + } + else + { + set_output(0, 0); + } + + /* Keep the new phasor in the 2Pi range.*/ + m_phase = fmod(m_phase, 2.0 * M_PI); + + /* The enable input only curtails output, phase rotation still occurs. */ + /* We allow the phase to exceed 2Pi here, so we can tell when to sample the noise. */ + m_phase += ((2.0 * M_PI * DSS_NOISE__FREQ) / this->sample_rate()); +} + + +DISCRETE_RESET(dss_noise) +{ + m_phase=0; + this->step(); +} + + +/************************************************************************ + * + * DSS_NOTE - Note/tone generator + * + * input0 - Enable input value + * input1 - Clock Input + * input2 - data value + * input3 - Max count 1 + * input4 - Max count 2 + * input5 - Clock type + * + * Mar 2004, D Renaud. + ************************************************************************/ + #define DSS_NOTE__ENABLE DISCRETE_INPUT(0) + #define DSS_NOTE__CLOCK DISCRETE_INPUT(1) + #define DSS_NOTE__DATA DISCRETE_INPUT(2) + #define DSS_NOTE__MAX1 DISCRETE_INPUT(3) + #define DSS_NOTE__MAX2 DISCRETE_INPUT(4) + #define DSS_NOTE__CLOCK_TYPE DISCRETE_INPUT(5) + +DISCRETE_STEP(dss_note) +{ + double cycles; + int clock = 0, last_count2, inc = 0; + double x_time = 0; + double v_out; + + if (m_clock_type == DISC_CLK_IS_FREQ) + { + /* We need to keep clocking the internal clock even if disabled. */ + cycles = (m_t_left + this->sample_time()) / m_t_clock; + inc = (int)cycles; + m_t_left = (cycles - inc) * m_t_clock; + if (inc) x_time = m_t_left / this->sample_time(); + } + else + { + /* separate clock info from x_time info. */ + clock = (int)DSS_NOTE__CLOCK; + x_time = DSS_NOTE__CLOCK - clock; + } + + if (DSS_NOTE__ENABLE) + { + last_count2 = m_count2; + + switch (m_clock_type) + { + case DISC_CLK_ON_F_EDGE: + case DISC_CLK_ON_R_EDGE: + /* See if the clock has toggled to the proper edge */ + clock = (clock != 0); + if (m_last != clock) + { + m_last = clock; + if (m_clock_type == clock) + { + /* Toggled */ + inc = 1; + } + } + break; + + case DISC_CLK_BY_COUNT: + /* Clock number of times specified. */ + inc = clock; + break; + } + + /* Count output as long as the data loaded is not already equal to max 1 count. */ + if (DSS_NOTE__DATA != DSS_NOTE__MAX1) + { + for (clock = 0; clock < inc; clock++) + { + m_count1++; + if (m_count1 > m_max1) + { + /* Max 1 count reached. Load Data into counter. */ + m_count1 = (int)DSS_NOTE__DATA; + m_count2 += 1; + if (m_count2 > m_max2) m_count2 = 0; + } + } + } + + v_out = m_count2; + if (m_count2 != last_count2) + { + /* the x_time is only output if the output changed. */ + switch (m_out_type) + { + case DISC_OUT_IS_ENERGY: + if (x_time == 0) x_time = 1.0; + v_out = last_count2; + if (m_count2 > last_count2) + v_out += (m_count2 - last_count2) * x_time; + else + v_out -= (last_count2 - m_count2) * x_time; + break; + case DISC_OUT_HAS_XTIME: + v_out += x_time; + break; + } + } + set_output(0, v_out); + } + else + set_output(0, 0); +} + +DISCRETE_RESET(dss_note) +{ + m_clock_type = (int)DSS_NOTE__CLOCK_TYPE & DISC_CLK_MASK; + m_out_type = (int)DSS_NOTE__CLOCK_TYPE & DISC_OUT_MASK; + + m_last = (DSS_NOTE__CLOCK != 0); + m_t_left = 0; + m_t_clock = 1.0 / DSS_NOTE__CLOCK; + + m_count1 = (int)DSS_NOTE__DATA; + m_count2 = 0; + m_max1 = (int)DSS_NOTE__MAX1; + m_max2 = (int)DSS_NOTE__MAX2; + set_output(0, 0); +} + +/************************************************************************ + * + * DSS_OP_AMP_OSC - Op Amp Oscillators + * + * input0 - Enable input value + * input1 - vMod1 (if needed) + * input2 - vMod2 (if needed) + * + * also passed discrete_op_amp_osc_info structure + * + * Mar 2004, D Renaud. + ************************************************************************/ +#define DSS_OP_AMP_OSC__ENABLE DISCRETE_INPUT(0) +#define DSS_OP_AMP_OSC__VMOD1 DISCRETE_INPUT(1) +#define DSS_OP_AMP_OSC__VMOD2 DISCRETE_INPUT(2) + +/* The inputs on a norton op-amp are (info->vP - OP_AMP_NORTON_VBE) */ +/* which is the same as the output high voltage. We will define them */ +/* the same to save a calculation step */ +#define DSS_OP_AMP_OSC_NORTON_VP_IN m_v_out_high + +DISCRETE_STEP(dss_op_amp_osc) +{ + DISCRETE_DECLARE_INFO(discrete_op_amp_osc_info) + + double i = 0; /* Charging current created by vIn */ + double v = 0; /* all input voltages mixed */ + double dt; /* change in time */ + double v_cap; /* Current voltage on capacitor, before dt */ + double v_cap_next = 0; /* Voltage on capacitor, after dt */ + double charge[2] = {0}; + double x_time = 0; /* time since change happened */ + double exponent; + UINT8 force_charge = 0; + UINT8 enable = DSS_OP_AMP_OSC__ENABLE; + UINT8 update_exponent = 0; + UINT8 flip_flop = m_flip_flop; + int count_f = 0; + int count_r = 0; + + double v_out = 0; + + dt = this->sample_time(); /* Change in time */ + v_cap = m_v_cap; /* Set to voltage before change */ + + /* work out the charge currents/voltages. */ + switch (m_type) + { + case DISC_OP_AMP_OSCILLATOR_VCO_1: + /* Work out the charge rates. */ + /* i is not a current. It is being used as a temp variable. */ + i = DSS_OP_AMP_OSC__VMOD1 * m_temp1; + charge[0] = (DSS_OP_AMP_OSC__VMOD1 - i) / info->r1; + charge[1] = (i - (DSS_OP_AMP_OSC__VMOD1 * m_temp2)) / m_temp3; + break; + + case DISC_OP_AMP_OSCILLATOR_1 | DISC_OP_AMP_IS_NORTON: + { + /* resistors can be nodes, so everything needs updating */ + double i1, i2; + /* add in enable current if using real enable */ + if (m_has_enable) + { + if (enable) + i = m_i_enable; + enable = 1; + } + /* Work out the charge rates. */ + charge[0] = DSS_OP_AMP_OSC_NORTON_VP_IN / *m_r[1-1] - i; + charge[1] = (m_v_out_high - OP_AMP_NORTON_VBE) / *m_r[2-1] - charge[0]; + /* Work out the Inverting Schmitt thresholds. */ + i1 = DSS_OP_AMP_OSC_NORTON_VP_IN / *m_r[5-1]; + i2 = (0.0 - OP_AMP_NORTON_VBE) / *m_r[4-1]; + m_threshold_low = (i1 + i2) * *m_r[3-1] + OP_AMP_NORTON_VBE; + i2 = (m_v_out_high - OP_AMP_NORTON_VBE) / *m_r[4-1]; + m_threshold_high = (i1 + i2) * *m_r[3-1] + OP_AMP_NORTON_VBE; + break; + } + + case DISC_OP_AMP_OSCILLATOR_VCO_1 | DISC_OP_AMP_IS_NORTON: + /* Millman the input voltages. */ + if (info->r7 == 0) + { + /* No r7 means that the modulation circuit is fed directly into the circuit. */ + v = DSS_OP_AMP_OSC__VMOD1; + } + else + { + /* we need to mix any bias and all modulation voltages together. */ + i = m_i_fixed; + i += DSS_OP_AMP_OSC__VMOD1 / info->r7; + if (info->r8 != 0) + i += DSS_OP_AMP_OSC__VMOD2 / info->r8; + v = i * m_r_total; + } + + /* Work out the charge rates. */ + v -= OP_AMP_NORTON_VBE; + charge[0] = v / info->r1; + charge[1] = v / info->r2 - charge[0]; + + /* use the real enable circuit */ + force_charge = !enable; + enable = 1; + break; + + case DISC_OP_AMP_OSCILLATOR_VCO_2 | DISC_OP_AMP_IS_NORTON: + /* Work out the charge rates. */ + i = DSS_OP_AMP_OSC__VMOD1 / info->r1; + charge[0] = i - m_temp1; + charge[1] = m_temp2 - i; + /* if the negative pin current is less then the positive pin current, */ + /* then the osc is disabled and the cap keeps charging */ + if (charge[0] < 0) + { + force_charge = 1; + charge[0] *= -1; + } + break; + + case DISC_OP_AMP_OSCILLATOR_VCO_3 | DISC_OP_AMP_IS_NORTON: + /* start with fixed bias */ + charge[0] = m_i_fixed; + /* add in enable current if using real enable */ + if (m_has_enable) + { + if (enable) + charge[0] -= m_i_enable; + enable = 1; + } + /* we need to mix any bias and all modulation voltages together. */ + v = DSS_OP_AMP_OSC__VMOD1 - OP_AMP_NORTON_VBE; + if (v < 0) v = 0; + charge[0] += v / info->r1; + if (info->r6 != 0) + { + v = DSS_OP_AMP_OSC__VMOD2 - OP_AMP_NORTON_VBE; + charge[0] += v / info->r6; + } + charge[1] = m_temp1 - charge[0]; + break; + } + + if (!enable) + { + /* we will just output 0 for oscillators that have no real enable. */ + set_output(0, 0); + return; + } + + /* Keep looping until all toggling in time sample is used up. */ + do + { + if (m_is_linear_charge) + { + if ((flip_flop ^ m_flip_flop_xor) || force_charge) + { + /* Charging */ + /* iC=C*dv/dt works out to dv=iC*dt/C */ + v_cap_next = v_cap + (charge[1] * dt / info->c); + dt = 0; + + /* has it charged past upper limit? */ + if (v_cap_next > m_threshold_high) + { + flip_flop = m_flip_flop_xor; + if (flip_flop) + count_r++; + else + count_f++; + if (force_charge) + { + /* we need to keep charging the cap to the max thereby disabling the circuit */ + if (v_cap_next > m_v_out_high) + v_cap_next = m_v_out_high; + } + else + { + /* calculate the overshoot time */ + dt = info->c * (v_cap_next - m_threshold_high) / charge[1]; + x_time = dt; + v_cap_next = m_threshold_high; + } + } + } + else + { + /* Discharging */ + v_cap_next = v_cap - (charge[0] * dt / info->c); + dt = 0; + + /* has it discharged past lower limit? */ + if (v_cap_next < m_threshold_low) + { + flip_flop = !m_flip_flop_xor; + if (flip_flop) + count_r++; + else + count_f++; + /* calculate the overshoot time */ + dt = info->c * (m_threshold_low - v_cap_next) / charge[0]; + x_time = dt; + v_cap_next = m_threshold_low; + } + } + } + else /* non-linear charge */ + { + if (update_exponent) + exponent = RC_CHARGE_EXP_DT(m_charge_rc[flip_flop], dt); + else + exponent = m_charge_exp[flip_flop]; + + v_cap_next = v_cap + ((m_charge_v[flip_flop] - v_cap) * exponent); + dt = 0; + + if (flip_flop) + { + /* Has it charged past upper limit? */ + if (v_cap_next > m_threshold_high) + { + dt = m_charge_rc[1] * log(1.0 / (1.0 - ((v_cap_next - m_threshold_high) / (m_v_out_high - v_cap)))); + x_time = dt; + v_cap_next = m_threshold_high; + flip_flop = 0; + count_f++; + update_exponent = 1; + } + } + else + { + /* has it discharged past lower limit? */ + if (v_cap_next < m_threshold_low) + { + dt = m_charge_rc[0] * log(1.0 / (1.0 - ((m_threshold_low - v_cap_next) / v_cap))); + x_time = dt; + v_cap_next = m_threshold_low; + flip_flop = 1; + count_r++; + update_exponent = 1; + } + } + } + v_cap = v_cap_next; + } while(dt); + if (v_cap > m_v_out_high) + v_cap = m_v_out_high; + if (v_cap < 0) + v_cap = 0; + m_v_cap = v_cap; + + x_time = dt / this->sample_time(); + + switch (m_output_type) + { + case DISC_OP_AMP_OSCILLATOR_OUT_CAP: + v_out = v_cap; + break; + case DISC_OP_AMP_OSCILLATOR_OUT_ENERGY: + if (x_time == 0) x_time = 1.0; + v_out = m_v_out_high * (flip_flop ? x_time : (1.0 - x_time)); + break; + case DISC_OP_AMP_OSCILLATOR_OUT_SQW: + if (count_f + count_r >= 2) + /* force at least 1 toggle */ + v_out = m_flip_flop ? 0 : m_v_out_high; + else + v_out = flip_flop * m_v_out_high; + break; + case DISC_OP_AMP_OSCILLATOR_OUT_COUNT_F_X: + v_out = count_f ? count_f + x_time : count_f; + break; + case DISC_OP_AMP_OSCILLATOR_OUT_COUNT_R_X: + v_out = count_r ? count_r + x_time : count_r; + break; + case DISC_OP_AMP_OSCILLATOR_OUT_LOGIC_X: + v_out = m_flip_flop + x_time; + break; + } + set_output(0, v_out); + m_flip_flop = flip_flop; +} + +#define DIODE_DROP 0.7 + +DISCRETE_RESET(dss_op_amp_osc) +{ + DISCRETE_DECLARE_INFO(discrete_op_amp_osc_info) + + const double *r_info_ptr; + int loop; + + double i1 = 0; /* inverting input current */ + double i2 = 0; /* non-inverting input current */ + + /* link to resistor static or node values */ + r_info_ptr = &info->r1; + for (loop = 0; loop < 8; loop ++) + { + m_r[loop] = m_device->node_output_ptr(*r_info_ptr); + if (m_r[loop] == NULL) + m_r[loop] = r_info_ptr; + r_info_ptr++; + } + + m_is_linear_charge = 1; + m_output_type = info->type & DISC_OP_AMP_OSCILLATOR_OUT_MASK; + m_type = info->type & DISC_OP_AMP_OSCILLATOR_TYPE_MASK; + m_charge_rc[0] = 0; + m_charge_rc[1] = 0; + m_charge_v[0] = 0; + m_charge_v[1] = 0; + m_i_fixed = 0; + m_has_enable = 0; + + switch (m_type) + { + case DISC_OP_AMP_OSCILLATOR_VCO_1: + /* The charge rates vary depending on vMod so they are not precalculated. */ + /* Charges while FlipFlop High */ + m_flip_flop_xor = 0; + /* Work out the Non-inverting Schmitt thresholds. */ + m_temp1 = (info->vP / 2) / info->r4; + m_temp2 = (info->vP - OP_AMP_VP_RAIL_OFFSET) / info->r3; + m_temp3 = 1.0 / (1.0 / info->r3 + 1.0 / info->r4); + m_threshold_low = m_temp1 * m_temp3; + m_threshold_high = (m_temp1 + m_temp2) * m_temp3; + /* There is no charge on the cap so the schmitt goes high at init. */ + m_flip_flop = 1; + /* Setup some commonly used stuff */ + m_temp1 = info->r5 / (info->r2 + info->r5); /* voltage ratio across r5 */ + m_temp2 = info->r6 / (info->r1 + info->r6); /* voltage ratio across r6 */ + m_temp3 = 1.0 / (1.0 / info->r1 + 1.0 / info->r6); /* input resistance when r6 switched in */ + break; + + case DISC_OP_AMP_OSCILLATOR_1 | DISC_OP_AMP_IS_NORTON: + /* Charges while FlipFlop High */ + m_flip_flop_xor = 0; + /* There is no charge on the cap so the schmitt inverter goes high at init. */ + m_flip_flop = 1; + /* setup current if using real enable */ + if (info->r6 > 0) + { + m_has_enable = 1; + m_i_enable = (info->vP - OP_AMP_NORTON_VBE) / (info->r6 + RES_K(1)); + } + break; + + case DISC_OP_AMP_OSCILLATOR_2 | DISC_OP_AMP_IS_NORTON: + m_is_linear_charge = 0; + /* First calculate the parallel charge resistors and volatges. */ + /* We can cheat and just calcuate the charges in the working area. */ + /* The thresholds are well past the effect of the voltage drop */ + /* and the component tolerances far exceed the .5V charge difference */ + if (info->r1 != 0) + { + m_charge_rc[0] = 1.0 / info->r1; + m_charge_rc[1] = 1.0 / info->r1; + m_charge_v[1] = (info->vP - OP_AMP_NORTON_VBE) / info->r1; + } + if (info->r5 != 0) + { + m_charge_rc[0] += 1.0 / info->r5; + m_charge_v[0] = DIODE_DROP / info->r5; + } + if (info->r6 != 0) + { + m_charge_rc[1] += 1.0 / info->r6; + m_charge_v[1] += (info->vP - OP_AMP_NORTON_VBE - DIODE_DROP) / info->r6; + } + m_charge_rc[0] += 1.0 / info->r2; + m_charge_rc[0] = 1.0 / m_charge_rc[0]; + m_charge_v[0] += OP_AMP_NORTON_VBE / info->r2; + m_charge_v[0] *= m_charge_rc[0]; + m_charge_rc[1] += 1.0 / info->r2; + m_charge_rc[1] = 1.0 / m_charge_rc[1]; + m_charge_v[1] += OP_AMP_NORTON_VBE / info->r2; + m_charge_v[1] *= m_charge_rc[1]; + + m_charge_rc[0] *= info->c; + m_charge_rc[1] *= info->c; + m_charge_exp[0] = RC_CHARGE_EXP(m_charge_rc[0]); + m_charge_exp[1] = RC_CHARGE_EXP(m_charge_rc[1]); + m_threshold_low = (info->vP - OP_AMP_NORTON_VBE) / info->r4; + m_threshold_high = m_threshold_low + (info->vP - 2 * OP_AMP_NORTON_VBE) / info->r3;; + m_threshold_low = m_threshold_low * info->r2 + OP_AMP_NORTON_VBE; + m_threshold_high = m_threshold_high * info->r2 + OP_AMP_NORTON_VBE; + + /* There is no charge on the cap so the schmitt inverter goes high at init. */ + m_flip_flop = 1; + break; + + case DISC_OP_AMP_OSCILLATOR_VCO_1 | DISC_OP_AMP_IS_NORTON: + /* Charges while FlipFlop Low */ + m_flip_flop_xor = 1; + /* There is no charge on the cap so the schmitt goes low at init. */ + m_flip_flop = 0; + /* The charge rates vary depending on vMod so they are not precalculated. */ + /* But we can precalculate the fixed currents. */ + if (info->r6 != 0) m_i_fixed += info->vP / info->r6; + m_i_fixed += OP_AMP_NORTON_VBE / info->r1; + m_i_fixed += OP_AMP_NORTON_VBE / info->r2; + /* Work out the input resistance to be used later to calculate the Millman voltage. */ + m_r_total = 1.0 / info->r1 + 1.0 / info->r2 + 1.0 / info->r7; + if (info->r6) m_r_total += 1.0 / info->r6; + if (info->r8) m_r_total += 1.0 / info->r8; + m_r_total = 1.0 / m_r_total; + /* Work out the Non-inverting Schmitt thresholds. */ + i1 = (info->vP - OP_AMP_NORTON_VBE) / info->r5; + i2 = (info->vP - OP_AMP_NORTON_VBE - OP_AMP_NORTON_VBE) / info->r4; + m_threshold_low = (i1 - i2) * info->r3 + OP_AMP_NORTON_VBE; + i2 = (0.0 - OP_AMP_NORTON_VBE) / info->r4; + m_threshold_high = (i1 - i2) * info->r3 + OP_AMP_NORTON_VBE; + break; + + case DISC_OP_AMP_OSCILLATOR_VCO_2 | DISC_OP_AMP_IS_NORTON: + /* Charges while FlipFlop High */ + m_flip_flop_xor = 0; + /* There is no charge on the cap so the schmitt inverter goes high at init. */ + m_flip_flop = 1; + /* Work out the charge rates. */ + m_temp1 = (info->vP - OP_AMP_NORTON_VBE) / info->r2; + m_temp2 = (info->vP - OP_AMP_NORTON_VBE) * (1.0 / info->r2 + 1.0 / info->r6); + /* Work out the Inverting Schmitt thresholds. */ + i1 = (info->vP - OP_AMP_NORTON_VBE) / info->r5; + i2 = (0.0 - OP_AMP_NORTON_VBE) / info->r4; + m_threshold_low = (i1 + i2) * info->r3 + OP_AMP_NORTON_VBE; + i2 = (info->vP - OP_AMP_NORTON_VBE - OP_AMP_NORTON_VBE) / info->r4; + m_threshold_high = (i1 + i2) * info->r3 + OP_AMP_NORTON_VBE; + break; + + case DISC_OP_AMP_OSCILLATOR_VCO_3 | DISC_OP_AMP_IS_NORTON: + /* Charges while FlipFlop High */ + m_flip_flop_xor = 0; + /* There is no charge on the cap so the schmitt inverter goes high at init. */ + m_flip_flop = 1; + /* setup current if using real enable */ + if (info->r8 > 0) + { + m_has_enable = 1; + m_i_enable = (info->vP - OP_AMP_NORTON_VBE) / (info->r8 + RES_K(1)); + } + /* Work out the charge rates. */ + /* The charge rates vary depending on vMod so they are not precalculated. */ + /* But we can precalculate the fixed currents. */ + if (info->r7 != 0) m_i_fixed = (info->vP - OP_AMP_NORTON_VBE) / info->r7; + m_temp1 = (info->vP - OP_AMP_NORTON_VBE - OP_AMP_NORTON_VBE) / info->r2; + /* Work out the Inverting Schmitt thresholds. */ + i1 = (info->vP - OP_AMP_NORTON_VBE) / info->r5; + i2 = (0.0 - OP_AMP_NORTON_VBE) / info->r4; + m_threshold_low = (i1 + i2) * info->r3 + OP_AMP_NORTON_VBE; + i2 = (info->vP - OP_AMP_NORTON_VBE - OP_AMP_NORTON_VBE) / info->r4; + m_threshold_high = (i1 + i2) * info->r3 + OP_AMP_NORTON_VBE; + break; + } + + m_v_out_high = info->vP - ((m_type & DISC_OP_AMP_IS_NORTON) ? OP_AMP_NORTON_VBE : OP_AMP_VP_RAIL_OFFSET); + m_v_cap = 0; + + this->step(); +} + + +/************************************************************************ + * + * DSS_SAWTOOTHWAVE - Usage of node_description values for step function + * + * input0 - Enable input value + * input1 - Frequency input value + * input2 - Amplitde input value + * input3 - DC Bias Value + * input4 - Gradient + * input5 - Initial Phase + * + ************************************************************************/ +#define DSS_SAWTOOTHWAVE__ENABLE DISCRETE_INPUT(0) +#define DSS_SAWTOOTHWAVE__FREQ DISCRETE_INPUT(1) +#define DSS_SAWTOOTHWAVE__AMP DISCRETE_INPUT(2) +#define DSS_SAWTOOTHWAVE__BIAS DISCRETE_INPUT(3) +#define DSS_SAWTOOTHWAVE__GRAD DISCRETE_INPUT(4) +#define DSS_SAWTOOTHWAVE__PHASE DISCRETE_INPUT(5) + +DISCRETE_STEP(dss_sawtoothwave) +{ + double v_out; + + if(DSS_SAWTOOTHWAVE__ENABLE) + { + v_out = (m_type == 0) ? m_phase * (DSS_SAWTOOTHWAVE__AMP / (2.0 * M_PI)) : DSS_SAWTOOTHWAVE__AMP - (m_phase * (DSS_SAWTOOTHWAVE__AMP / (2.0 * M_PI))); + v_out -= DSS_SAWTOOTHWAVE__AMP / 2.0; + /* Add DC Bias component */ + v_out = v_out + DSS_SAWTOOTHWAVE__BIAS; + } + else + { + v_out = 0; + } + set_output(0, v_out); + + /* Work out the phase step based on phase/freq & sample rate */ + /* The enable input only curtails output, phase rotation */ + /* still occurs */ + /* phase step = 2Pi/(output period/sample period) */ + /* boils out to */ + /* phase step = (2Pi*output freq)/sample freq) */ + /* Also keep the new phasor in the 2Pi range. */ + m_phase = fmod((m_phase + ((2.0 * M_PI * DSS_SAWTOOTHWAVE__FREQ) / this->sample_rate())), 2.0 * M_PI); +} + +DISCRETE_RESET(dss_sawtoothwave) +{ + double start; + + /* Establish starting phase, convert from degrees to radians */ + start = (DSS_SAWTOOTHWAVE__PHASE / 360.0) * (2.0 * M_PI); + /* Make sure its always mod 2Pi */ + m_phase = fmod(start, 2.0 * M_PI); + + /* Invert gradient depending on sawtooth type /|/|/|/|/| or |\|\|\|\|\ */ + m_type = (DSS_SAWTOOTHWAVE__GRAD) ? 1 : 0; + + /* Step the node to set the output */ + this->step(); +} + + +/************************************************************************ + * + * DSS_SCHMITT_OSC - Schmitt feedback oscillator + * + * input0 - Enable input value + * input1 - Vin + * input2 - Amplitude + * + * also passed discrete_schmitt_osc_disc structure + * + * Mar 2004, D Renaud. + ************************************************************************/ +#define DSS_SCHMITT_OSC__ENABLE (int)DISCRETE_INPUT(0) +#define DSS_SCHMITT_OSC__VIN DISCRETE_INPUT(1) +#define DSS_SCHMITT_OSC__AMP DISCRETE_INPUT(2) + +DISCRETE_STEP(dss_schmitt_osc) +{ + DISCRETE_DECLARE_INFO(discrete_schmitt_osc_desc) + + double supply, v_cap, new_vCap, t, exponent; + double v_out = 0; + + /* We will always oscillate. The enable just affects the output. */ + v_cap = m_v_cap; + exponent = m_exponent; + + /* Keep looping until all toggling in time sample is used up. */ + do + { + t = 0; + /* The charging voltage to the cap is the sum of the input voltage and the gate + * output voltage in the ratios determined by their resistors in a divider network. + * The input voltage is selectable as straight voltage in or logic level that will + * use vGate as its voltage. Note that ration_in is just the ratio of the total + * voltage and needs to be multipled by the input voltage. ratio_feedback has + * already been multiplied by vGate to save time because that voltage never changes. */ + supply = m_input_is_voltage ? m_ration_in * DSS_SCHMITT_OSC__VIN : (DSS_SCHMITT_OSC__VIN ? m_ration_in * info->vGate : 0); + supply += (m_state ? m_ratio_feedback : 0); + new_vCap = v_cap + ((supply - v_cap) * exponent); + if (m_state) + { + /* Charging */ + /* has it charged past upper limit? */ + if (new_vCap > info->trshRise) + { + /* calculate the overshoot time */ + t = m_rc * log(1.0 / (1.0 - ((new_vCap - info->trshRise) / (info->vGate - v_cap)))); + /* calculate new exponent because of reduced time */ + exponent = RC_CHARGE_EXP_DT(m_rc, t); + v_cap = new_vCap = info->trshRise; + m_state = 0; + } + } + else + { + /* Discharging */ + /* has it discharged past lower limit? */ + if (new_vCap < info->trshFall) + { + /* calculate the overshoot time */ + t = m_rc * log(1.0 / (1.0 - ((info->trshFall - new_vCap) / v_cap))); + /* calculate new exponent because of reduced time */ + exponent = RC_CHARGE_EXP_DT(m_rc, t); + v_cap = new_vCap = info->trshFall; + m_state = 1; + } + } + } while(t); + + m_v_cap = new_vCap; + + switch (m_enable_type) + { + case DISC_SCHMITT_OSC_ENAB_IS_AND: + v_out = DSS_SCHMITT_OSC__ENABLE && m_state; + break; + case DISC_SCHMITT_OSC_ENAB_IS_NAND: + v_out = !(DSS_SCHMITT_OSC__ENABLE && m_state); + break; + case DISC_SCHMITT_OSC_ENAB_IS_OR: + v_out = DSS_SCHMITT_OSC__ENABLE || m_state; + break; + case DISC_SCHMITT_OSC_ENAB_IS_NOR: + v_out = !(DSS_SCHMITT_OSC__ENABLE || m_state); + break; + } + v_out *= DSS_SCHMITT_OSC__AMP; + set_output(0, v_out); +} + +DISCRETE_RESET(dss_schmitt_osc) +{ + DISCRETE_DECLARE_INFO(discrete_schmitt_osc_desc) + + double rSource; + + m_enable_type = info->options & DISC_SCHMITT_OSC_ENAB_MASK; + m_input_is_voltage = (info->options & DISC_SCHMITT_OSC_IN_IS_VOLTAGE) ? 1 : 0; + + /* The 2 resistors make a voltage divider, so their ratios add together + * to make the charging voltage. */ + m_ration_in = info->rFeedback / (info->rIn + info->rFeedback); + m_ratio_feedback = info->rIn / (info->rIn + info->rFeedback) * info->vGate; + + /* The voltage source resistance works out to the 2 resistors in parallel. + * So use this for the RC charge constant. */ + rSource = 1.0 / ((1.0 / info->rIn) + (1.0 / info->rFeedback)); + m_rc = rSource * info->c; + m_exponent = RC_CHARGE_EXP(m_rc); + + /* Cap is at 0V on power up. Causing output to be high. */ + m_v_cap = 0; + m_state = 1; + + set_output(0, info->options ? 0 : DSS_SCHMITT_OSC__AMP); +} + + +/************************************************************************ + * + * DSS_SINEWAVE - Usage of node_description values for step function + * + * input0 - Enable input value + * input1 - Frequency input value + * input2 - Amplitude input value + * input3 - DC Bias + * input4 - Starting phase + * + ************************************************************************/ +#define DSS_SINEWAVE__ENABLE DISCRETE_INPUT(0) +#define DSS_SINEWAVE__FREQ DISCRETE_INPUT(1) +#define DSS_SINEWAVE__AMPL DISCRETE_INPUT(2) +#define DSS_SINEWAVE__BIAS DISCRETE_INPUT(3) +#define DSS_SINEWAVE__PHASE DISCRETE_INPUT(4) + +DISCRETE_STEP(dss_sinewave) +{ + /* Set the output */ + if(DSS_SINEWAVE__ENABLE) + { + set_output(0, (DSS_SINEWAVE__AMPL / 2.0) * sin(m_phase) + DSS_SINEWAVE__BIAS); + /* Add DC Bias component */ + } + else + { + set_output(0, 0); + } + + /* Work out the phase step based on phase/freq & sample rate */ + /* The enable input only curtails output, phase rotation */ + /* still occurs */ + /* phase step = 2Pi/(output period/sample period) */ + /* boils out to */ + /* phase step = (2Pi*output freq)/sample freq) */ + /* Also keep the new phasor in the 2Pi range. */ + m_phase=fmod((m_phase + ((2.0 * M_PI * DSS_SINEWAVE__FREQ) / this->sample_rate())), 2.0 * M_PI); +} + +DISCRETE_RESET(dss_sinewave) +{ + double start; + + /* Establish starting phase, convert from degrees to radians */ + start = (DSS_SINEWAVE__PHASE / 360.0) * (2.0 * M_PI); + /* Make sure its always mod 2Pi */ + m_phase = fmod(start, 2.0 * M_PI); + /* Step the output to make it correct */ + this->step(); +} + + +/************************************************************************ + * + * DSS_SQUAREWAVE - Usage of node_description values for step function + * + * input0 - Enable input value + * input1 - Frequency input value + * input2 - Amplitude input value + * input3 - Duty Cycle + * input4 - DC Bias level + * input5 - Start Phase + * + ************************************************************************/ +#define DSS_SQUAREWAVE__ENABLE DISCRETE_INPUT(0) +#define DSS_SQUAREWAVE__FREQ DISCRETE_INPUT(1) +#define DSS_SQUAREWAVE__AMP DISCRETE_INPUT(2) +#define DSS_SQUAREWAVE__DUTY DISCRETE_INPUT(3) +#define DSS_SQUAREWAVE__BIAS DISCRETE_INPUT(4) +#define DSS_SQUAREWAVE__PHASE DISCRETE_INPUT(5) + +DISCRETE_STEP(dss_squarewave) +{ + /* Establish trigger phase from duty */ + m_trigger=((100-DSS_SQUAREWAVE__DUTY)/100)*(2.0*M_PI); + + /* Set the output */ + if(DSS_SQUAREWAVE__ENABLE) + { + if(m_phase>m_trigger) + set_output(0, DSS_SQUAREWAVE__AMP / 2.0 + DSS_SQUAREWAVE__BIAS); + else + set_output(0, - DSS_SQUAREWAVE__AMP / 2.0 + DSS_SQUAREWAVE__BIAS); + /* Add DC Bias component */ + } + else + { + set_output(0, 0); + } + + /* Work out the phase step based on phase/freq & sample rate */ + /* The enable input only curtails output, phase rotation */ + /* still occurs */ + /* phase step = 2Pi/(output period/sample period) */ + /* boils out to */ + /* phase step = (2Pi*output freq)/sample freq) */ + /* Also keep the new phasor in the 2Pi range. */ + m_phase=fmod(m_phase + ((2.0 * M_PI * DSS_SQUAREWAVE__FREQ) / this->sample_rate()), 2.0 * M_PI); +} + +DISCRETE_RESET(dss_squarewave) +{ + double start; + + /* Establish starting phase, convert from degrees to radians */ + start = (DSS_SQUAREWAVE__PHASE / 360.0) * (2.0 * M_PI); + /* Make sure its always mod 2Pi */ + m_phase = fmod(start, 2.0 * M_PI); + + /* Step the output */ + this->step(); +} + +/************************************************************************ + * + * DSS_SQUAREWFIX - Usage of node_description values for step function + * + * input0 - Enable input value + * input1 - Frequency input value + * input2 - Amplitude input value + * input3 - Duty Cycle + * input4 - DC Bias level + * input5 - Start Phase + * + ************************************************************************/ +#define DSS_SQUAREWFIX__ENABLE DISCRETE_INPUT(0) +#define DSS_SQUAREWFIX__FREQ DISCRETE_INPUT(1) +#define DSS_SQUAREWFIX__AMP DISCRETE_INPUT(2) +#define DSS_SQUAREWFIX__DUTY DISCRETE_INPUT(3) +#define DSS_SQUAREWFIX__BIAS DISCRETE_INPUT(4) +#define DSS_SQUAREWFIX__PHASE DISCRETE_INPUT(5) + +DISCRETE_STEP(dss_squarewfix) +{ + m_t_left -= m_sample_step; + + /* The enable input only curtails output, phase rotation still occurs */ + while (m_t_left <= 0) + { + m_flip_flop = m_flip_flop ? 0 : 1; + m_t_left += m_flip_flop ? m_t_on : m_t_off; + } + + if(DSS_SQUAREWFIX__ENABLE) + { + /* Add gain and DC Bias component */ + + m_t_off = 1.0 / DSS_SQUAREWFIX__FREQ; /* cycle time */ + m_t_on = m_t_off * (DSS_SQUAREWFIX__DUTY / 100.0); + m_t_off -= m_t_on; + + set_output(0, (m_flip_flop ? DSS_SQUAREWFIX__AMP / 2.0 : -(DSS_SQUAREWFIX__AMP / 2.0)) + DSS_SQUAREWFIX__BIAS); + } + else + { + set_output(0, 0); + } +} + +DISCRETE_RESET(dss_squarewfix) +{ + m_sample_step = 1.0 / this->sample_rate(); + m_flip_flop = 1; + + /* Do the intial time shift and convert freq to off/on times */ + m_t_off = 1.0 / DSS_SQUAREWFIX__FREQ; /* cycle time */ + m_t_left = DSS_SQUAREWFIX__PHASE / 360.0; /* convert start phase to % */ + m_t_left = m_t_left - (int)m_t_left; /* keep % between 0 & 1 */ + m_t_left = (m_t_left < 0) ? 1.0 + m_t_left : m_t_left; /* if - then flip to + phase */ + m_t_left *= m_t_off; + m_t_on = m_t_off * (DSS_SQUAREWFIX__DUTY / 100.0); + m_t_off -= m_t_on; + + m_t_left = -m_t_left; + + /* toggle output and work out intial time shift */ + while (m_t_left <= 0) + { + m_flip_flop = m_flip_flop ? 0 : 1; + m_t_left += m_flip_flop ? m_t_on : m_t_off; + } + + /* Step the output */ + this->step(); +} + + +/************************************************************************ + * + * DSS_SQUAREWAVE2 - Usage of node_description values + * + * input0 - Enable input value + * input1 - Amplitude input value + * input2 - OFF Time + * input3 - ON Time + * input4 - DC Bias level + * input5 - Initial Time Shift + * + ************************************************************************/ +#define DSS_SQUAREWAVE2__ENABLE DISCRETE_INPUT(0) +#define DSS_SQUAREWAVE2__AMP DISCRETE_INPUT(1) +#define DSS_SQUAREWAVE2__T_OFF DISCRETE_INPUT(2) +#define DSS_SQUAREWAVE2__T_ON DISCRETE_INPUT(3) +#define DSS_SQUAREWAVE2__BIAS DISCRETE_INPUT(4) +#define DSS_SQUAREWAVE2__SHIFT DISCRETE_INPUT(5) + +DISCRETE_STEP(dss_squarewave2) +{ + double newphase; + + if(DSS_SQUAREWAVE2__ENABLE) + { + /* Establish trigger phase from time periods */ + m_trigger = (DSS_SQUAREWAVE2__T_OFF / (DSS_SQUAREWAVE2__T_OFF + DSS_SQUAREWAVE2__T_ON)) * (2.0 * M_PI); + + /* Work out the phase step based on phase/freq & sample rate */ + /* The enable input only curtails output, phase rotation */ + /* still occurs */ + + /* phase step = 2Pi/(output period/sample period) */ + /* boils out to */ + /* phase step = 2Pi/(output period*sample freq) */ + newphase = m_phase + ((2.0 * M_PI) / ((DSS_SQUAREWAVE2__T_OFF + DSS_SQUAREWAVE2__T_ON) * this->sample_rate())); + /* Keep the new phasor in the 2Pi range.*/ + m_phase = fmod(newphase, 2.0 * M_PI); + + /* Add DC Bias component */ + if(m_phase>m_trigger) + set_output(0, DSS_SQUAREWAVE2__AMP / 2.0 + DSS_SQUAREWAVE2__BIAS); + else + set_output(0, -DSS_SQUAREWAVE2__AMP / 2.0 + DSS_SQUAREWAVE2__BIAS); + } + else + { + set_output(0, 0); + } +} + +DISCRETE_RESET(dss_squarewave2) +{ + double start; + + /* Establish starting phase, convert from degrees to radians */ + /* Only valid if we have set the on/off time */ + if((DSS_SQUAREWAVE2__T_OFF + DSS_SQUAREWAVE2__T_ON) != 0.0) + start = (DSS_SQUAREWAVE2__SHIFT / (DSS_SQUAREWAVE2__T_OFF + DSS_SQUAREWAVE2__T_ON)) * (2.0 * M_PI); + else + start = 0.0; + /* Make sure its always mod 2Pi */ + m_phase = fmod(start, 2.0 * M_PI); + + /* Step the output */ + this->step(); +} + +/************************************************************************ + * + * DSS_INVERTER_OSC - Usage of node_description values + * + * input0 - Enable input value + * input1 - RC Resistor + * input2 - RP Resistor + * input3 - C Capacitor + * input4 - Desc + * + ************************************************************************/ + +/* + * Taken from the transfer characteristerics diagram in CD4049UB datasheet (TI) + * There is no default trigger point and vI-vO is a continuous function + */ + +inline double DISCRETE_CLASS_FUNC(dss_inverter_osc, tftab)(double x) +{ + DISCRETE_DECLARE_INFO(description) + + x = x / info->vB; + if (x > 0) + return info->vB * exp(-mc_tf_a * pow(x, mc_tf_b)); + else + return info->vB; +} + +inline double DISCRETE_CLASS_FUNC(dss_inverter_osc, tf)(double x) +{ + DISCRETE_DECLARE_INFO(description) + + if (x < 0.0) + return info->vB; + else if (x <= info->vB) + return mc_tf_tab[(int)((double)(DSS_INV_TAB_SIZE - 1) * x / info->vB)]; + else + return mc_tf_tab[DSS_INV_TAB_SIZE - 1]; +} + +DISCRETE_STEP(dss_inverter_osc) +{ + DISCRETE_DECLARE_INFO(description) + double diff, vG1, vG2, vG3, vI; + double vMix, rMix; + int clamped; + double v_out; + + /* Get new state */ + vI = mc_v_cap + mc_v_g2_old; + switch (info->options & TYPE_MASK) + { + case IS_TYPE1: + case IS_TYPE3: + vG1 = this->tf(vI); + vG2 = this->tf(vG1); + vG3 = this->tf(vG2); + break; + case IS_TYPE2: + vG1 = 0; + vG3 = this->tf(vI); + vG2 = this->tf(vG3); + break; + case IS_TYPE4: + vI = MIN(I_ENABLE(), vI + 0.7); + vG1 = 0; + vG3 = this->tf(vI); + vG2 = this->tf(vG3); + break; + case IS_TYPE5: + vI = MAX(I_ENABLE(), vI - 0.7); + vG1 = 0; + vG3 = this->tf(vI); + vG2 = this->tf(vG3); + break; + default: + fatalerror("DISCRETE_INVERTER_OSC - Wrong type on NODE_%02d\n", this->index()); + } + + clamped = 0; + if (info->clamp >= 0.0) + { + if (vI < -info->clamp) + { + vI = -info->clamp; + clamped = 1; + } + else if (vI > info->vB+info->clamp) + { + vI = info->vB + info->clamp; + clamped = 1; + } + } + + switch (info->options & TYPE_MASK) + { + case IS_TYPE1: + case IS_TYPE2: + case IS_TYPE3: + if (clamped) + { + double ratio = mc_rp / (mc_rp + mc_r1); + diff = vG3 * (ratio) + - (mc_v_cap + vG2) + + vI * (1.0 - ratio); + diff = diff - diff * mc_wc; + } + else + { + diff = vG3 - (mc_v_cap + vG2); + diff = diff - diff * mc_w; + } + break; + case IS_TYPE4: + /* FIXME handle r2 = 0 */ + rMix = (mc_r1 * mc_r2) / (mc_r1 + mc_r2); + vMix = rMix* ((vG3 - vG2) / mc_r1 + (I_MOD() -vG2) / mc_r2); + if (vMix < (vI-vG2-0.7)) + { + rMix = 1.0 / rMix + 1.0 / mc_rp; + rMix = 1.0 / rMix; + vMix = rMix* ( (vG3-vG2) / mc_r1 + (I_MOD() - vG2) / mc_r2 + + (vI - 0.7 - vG2) / mc_rp); + } + diff = vMix - mc_v_cap; + diff = diff - diff * exp(-this->sample_time() / (mc_c * rMix)); + break; + case IS_TYPE5: + /* FIXME handle r2 = 0 */ + rMix = (mc_r1 * mc_r2) / (mc_r1 + mc_r2); + vMix = rMix* ((vG3 - vG2) / mc_r1 + (I_MOD() - vG2) / mc_r2); + if (vMix > (vI -vG2 + 0.7)) + { + rMix = 1.0 / rMix + 1.0 / mc_rp; + rMix = 1.0 / rMix; + vMix = rMix * ( (vG3 - vG2) / mc_r1 + (I_MOD() - vG2) / mc_r2 + + (vI + 0.7 - vG2) / mc_rp); + } + diff = vMix - mc_v_cap; + diff = diff - diff * exp(-this->sample_time()/(mc_c * rMix)); + break; + default: + fatalerror("DISCRETE_INVERTER_OSC - Wrong type on NODE_%02d\n", this->index()); + } + + mc_v_cap += diff; + mc_v_g2_old = vG2; + + if ((info->options & TYPE_MASK) == IS_TYPE3) + v_out = vG1; + else + v_out = vG3; + + if (info->options & OUT_IS_LOGIC) + v_out = (v_out > info->vInFall); + + set_output(0, v_out); +} + +DISCRETE_RESET(dss_inverter_osc) +{ + DISCRETE_DECLARE_INFO(description) + + int i; + + /* exponent */ + mc_w = exp(-this->sample_time() / (I_RC() * I_C())); + mc_wc = exp(-this->sample_time() / ((I_RC() * I_RP()) / (I_RP() + I_RC()) * I_C())); + set_output(0, 0); + mc_v_cap = 0; + mc_v_g2_old = 0; + mc_rp = I_RP(); + mc_r1 = I_RC(); + mc_r2 = I_R2(); + mc_c = I_C(); + mc_tf_b = (log(0.0 - log(info->vOutLow/info->vB)) - log(0.0 - log((info->vOutHigh/info->vB))) ) / log(info->vInRise / info->vInFall); + mc_tf_a = log(0.0 - log(info->vOutLow/info->vB)) - mc_tf_b * log(info->vInRise/info->vB); + mc_tf_a = exp(mc_tf_a); + + for (i = 0; i < DSS_INV_TAB_SIZE; i++) + { + mc_tf_tab[i] = this->tftab((double)i / (double)(DSS_INV_TAB_SIZE - 1) * info->vB); + } +} + +/************************************************************************ + * + * DSS_TRIANGLEWAVE - Usage of node_description values for step function + * + * input0 - Enable input value + * input1 - Frequency input value + * input2 - Amplitde input value + * input3 - DC Bias value + * input4 - Initial Phase + * + ************************************************************************/ +#define DSS_TRIANGLEWAVE__ENABLE DISCRETE_INPUT(0) +#define DSS_TRIANGLEWAVE__FREQ DISCRETE_INPUT(1) +#define DSS_TRIANGLEWAVE__AMP DISCRETE_INPUT(2) +#define DSS_TRIANGLEWAVE__BIAS DISCRETE_INPUT(3) +#define DSS_TRIANGLEWAVE__PHASE DISCRETE_INPUT(4) + +DISCRETE_STEP(dss_trianglewave) +{ + if(DSS_TRIANGLEWAVE__ENABLE) + { + double v_out = m_phase < M_PI ? (DSS_TRIANGLEWAVE__AMP * (m_phase / (M_PI / 2.0) - 1.0)) / 2.0 : + (DSS_TRIANGLEWAVE__AMP * (3.0 - m_phase / (M_PI / 2.0))) / 2.0 ; + + /* Add DC Bias component */ + v_out += DSS_TRIANGLEWAVE__BIAS; + set_output(0, v_out); + } + else + { + set_output(0, 0); + } + + /* Work out the phase step based on phase/freq & sample rate */ + /* The enable input only curtails output, phase rotation */ + /* still occurs */ + /* phase step = 2Pi/(output period/sample period) */ + /* boils out to */ + /* phase step = (2Pi*output freq)/sample freq) */ + /* Also keep the new phasor in the 2Pi range. */ + m_phase=fmod((m_phase + ((2.0 * M_PI * DSS_TRIANGLEWAVE__FREQ) / this->sample_rate())), 2.0 * M_PI); +} + +DISCRETE_RESET(dss_trianglewave) +{ + double start; + + /* Establish starting phase, convert from degrees to radians */ + start = (DSS_TRIANGLEWAVE__PHASE / 360.0) * (2.0 * M_PI); + /* Make sure its always mod 2Pi */ + m_phase=fmod(start, 2.0 * M_PI); + + /* Step to set the output */ + this->step(); +} + + +/************************************************************************ + * + * DSS_ADSR - Attack Decay Sustain Release + * + * input0 - Enable input value + * input1 - Trigger value + * input2 - gain scaling factor + * + ************************************************************************/ +#define DSS_ADSR__ENABLE DISCRETE_INPUT(0) + +DISCRETE_STEP(dss_adsrenv) +{ + if(DSS_ADSR__ENABLE) + { + set_output(0, 0); + } + else + { + set_output(0, 0); + } +} + + +DISCRETE_RESET(dss_adsrenv) +{ + this->step(); +} diff --git a/src/devices/sound/discrete.c b/src/devices/sound/discrete.c new file mode 100644 index 00000000000..ae278d503db --- /dev/null +++ b/src/devices/sound/discrete.c @@ -0,0 +1,1148 @@ +// license:??? +// copyright-holders:K.Wilkins, Derrick Renaud, Frank Palazzolo, Couriersud +/************************************************************************ + * + * MAME - Discrete sound system emulation library + * + * Written by K.Wilkins (mame@esplexo.co.uk) + * + * (c) K.Wilkins 2000 + * + * Coding started in November 2000 + * KW - Added Sawtooth waveforms Feb2003 + * + *********************************************************************** + * + * SEE DISCRETE.H for documentation on usage + * + *********************************************************************** + * + * Each sound primative DSS_xxxx or DST_xxxx has its own implementation + * file. All discrete sound primatives MUST implement the following + * API: + * + * dsX_NAME_step(inputs, context, float timestep) - Perform time step + * return output value + * dsX_NAME_reset(context) - Reset to initial state + * + * Core software takes care of traversing the netlist in the correct + * order + * + * device_start - Read Node list, initialise & reset + * device_stop - Shutdown discrete sound system + * device_reset - Put sound system back to time 0 + * discrete_stream_update() - This does the real update to the sim + * + ************************************************************************/ + +#include "emu.h" +#include "wavwrite.h" +#include "discrete.h" + +// for now, make buggy GCC/Mingw STFU about I64FMT +#if (defined(__MINGW32__) && (__GNUC__ >= 5)) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wformat" +#pragma GCC diagnostic ignored "-Wformat-extra-args" +#endif + + +/* for_each collides with c++ standard libraries - include it here */ +#define for_each(_T, _e, _l) for (_T _e = (_l)->begin_ptr() ; _e <= (_l)->end_ptr(); _e++) + +// device type definition +const device_type DISCRETE = &device_creator; + +/************************************* + * + * Performance + * + *************************************/ + +/* + * Normally, the discrete core processes 960 samples per update. + * With the various buffers involved, this on a Core2 is not as + * performant as processing 240 samples 4 times. + * The setting most probably depends on CPU and which modules are + * run and how many tasks are defined. + * + * Values < 32 exhibit poor performance (too much overhead) while + * Values > 500 have a slightly worse performace (too much cache misses?). + */ + +#define MAX_SAMPLES_PER_TASK_SLICE (960/4) + +/************************************* + * + * Debugging + * + *************************************/ + +#define DISCRETE_DEBUGLOG (0) + +/************************************* + * + * Use tasks ? + * + *************************************/ + +#define USE_DISCRETE_TASKS (1) + +/************************************* + * + * Internal classes + * + *************************************/ + +struct output_buffer +{ + double *node_buf; + const double *source; + volatile double *ptr; + int node_num; +}; + +struct input_buffer +{ + volatile const double *ptr; /* pointer into linked_outbuf.nodebuf */ + output_buffer * linked_outbuf; /* what output are we connected to ? */ + double buffer; /* input[] will point here */ +}; + +class discrete_task +{ + friend class discrete_device; +public: + virtual ~discrete_task(void) { } + + inline void step_nodes(void); + inline bool lock_threadid(INT32 threadid) + { + INT32 prev_id; + prev_id = compare_exchange32(&m_threadid, -1, threadid); + return (prev_id == -1 && m_threadid == threadid); + } + inline void unlock(void) { m_threadid = -1; } + + //const linked_list_entry *list; + node_step_list_t step_list; + + /* list of source nodes */ + vector_t source_list; /* discrete_source_node */ + + int task_group; + + +protected: + discrete_task(discrete_device &pdev) + : task_group(0), m_device(pdev), m_threadid(-1) + { + source_list.clear(); + step_list.clear(); + m_buffers.clear(); + } + + static void *task_callback(void *param, int threadid); + inline bool process(void); + + void check(discrete_task *dest_task); + void prepare_for_queue(int samples); + + vector_t m_buffers; + discrete_device & m_device; + +private: + volatile INT32 m_threadid; + volatile int m_samples; + +}; + + +/************************************* + * + * Included simulation objects + * + *************************************/ + +#include "disc_sys.inc" /* discrete core modules and support functions */ +#include "disc_wav.inc" /* Wave sources - SINE/SQUARE/NOISE/etc */ +#include "disc_mth.inc" /* Math Devices - ADD/GAIN/etc */ +#include "disc_inp.inc" /* Input Devices - INPUT/CONST/etc */ +#include "disc_flt.inc" /* Filter Devices - RCF/HPF/LPF */ +#include "disc_dev.inc" /* Popular Devices - NE555/etc */ + +/************************************* + * + * INLINEs + * + *************************************/ + + + +/************************************* + * + * Task implementation + * + *************************************/ + +inline void discrete_task::step_nodes(void) +{ + for_each(input_buffer *, sn, &source_list) + { + sn->buffer = *sn->ptr++; + } + + if (EXPECTED(!m_device.profiling())) + { + for_each(discrete_step_interface **, entry, &step_list) + { + /* Now step the node */ + (*entry)->step(); + } + } + else + { + osd_ticks_t last = get_profile_ticks(); + + for_each(discrete_step_interface **, entry, &step_list) + { + discrete_step_interface *node = *entry; + + node->run_time -= last; + node->step(); + last = get_profile_ticks(); + node->run_time += last; + } + } + + /* buffer the outputs */ + for_each(output_buffer *, outbuf, &m_buffers) + *(outbuf->ptr++) = *outbuf->source; +} + +void *discrete_task::task_callback(void *param, int threadid) +{ + task_list_t *list = (task_list_t *) param; + do + { + for_each(discrete_task **, task, list) + { + /* try to lock */ + if ((*task)->lock_threadid(threadid)) + { + if (!(*task)->process()) + return NULL; + (*task)->unlock(); + } + } + } while (1); + + return NULL; +} + +bool discrete_task::process(void) +{ + int samples = MIN(m_samples, MAX_SAMPLES_PER_TASK_SLICE); + + /* check dependencies */ + for_each(input_buffer *, sn, &source_list) + { + int avail; + + avail = sn->linked_outbuf->ptr - sn->ptr; + assert_always(avail >= 0, "task_callback: available samples are negative"); + if (avail < samples) + samples = avail; + } + + m_samples -= samples; + assert_always(m_samples >=0, "task_callback: task_samples got negative"); + while (samples > 0) + { + /* step */ + step_nodes(); + samples--; + } + if (m_samples == 0) + { + /* return and keep the task locked so it is not picked up by other worker threads */ + return false; + } + return true; +} + +void discrete_task::prepare_for_queue(int samples) +{ + m_samples = samples; + /* set up task buffers */ + for_each(output_buffer *, ob, &m_buffers) + ob->ptr = ob->node_buf; + + /* initialize sources */ + for_each(input_buffer *, sn, &source_list) + { + sn->ptr = sn->linked_outbuf->node_buf; + } +} + +void discrete_task::check(discrete_task *dest_task) +{ + int inputnum; + + /* Determine, which nodes in the task are referenced by nodes in dest_task + * and add them to the list of nodes to be buffered for further processing + */ + for_each(discrete_step_interface **, node_entry, &step_list) + { + discrete_base_node *task_node = (*node_entry)->self; + + for_each(discrete_step_interface **, step_entry, &dest_task->step_list) + { + discrete_base_node *dest_node = (*step_entry)->self; + + /* loop over all active inputs */ + for (inputnum = 0; inputnum < dest_node->active_inputs(); inputnum++) + { + int inputnode_num = dest_node->input_node(inputnum); + if IS_VALUE_A_NODE(inputnode_num) + { + /* Fixme: sub nodes ! */ + if (NODE_DEFAULT_NODE(task_node->block_node()) == NODE_DEFAULT_NODE(inputnode_num)) + { + input_buffer source; + int i, found = -1; + output_buffer *pbuf = NULL; + + for (i = 0; i < m_buffers.count(); i++) +// if (m_buffers[i].node->block_node() == inputnode_num) + if (m_buffers[i].node_num == inputnode_num) + { + found = i; + pbuf = &m_buffers[i]; + break; + } + + if (found<0) + { + output_buffer buf; + + buf.node_buf = auto_alloc_array(m_device.machine(), double, + ((task_node->sample_rate() + sound_manager::STREAMS_UPDATE_FREQUENCY) / sound_manager::STREAMS_UPDATE_FREQUENCY)); + buf.ptr = buf.node_buf; + buf.source = dest_node->m_input[inputnum]; + buf.node_num = inputnode_num; + //buf.node = device->discrete_find_node(inputnode); + i = m_buffers.count(); + pbuf = m_buffers.add(buf); + } + m_device.discrete_log("dso_task_start - buffering %d(%d) in task %p group %d referenced by %d group %d", NODE_INDEX(inputnode_num), NODE_CHILD_NODE_NUM(inputnode_num), this, task_group, dest_node->index(), dest_task->task_group); + + /* register into source list */ + //source = auto_alloc(device->machine(), discrete_source_node); + //source.task = this; + //source.output_node = i; + source.linked_outbuf = pbuf; + source.buffer = 0.0; /* please compiler */ + source.ptr = NULL; + dest_task->source_list.add(source); + + /* point the input to a buffered location */ + dest_node->m_input[inputnum] = &dest_task->source_list[dest_task->source_list.count()-1].buffer; // was copied! &source.buffer; + + } + } + } + } + } +} + +/************************************* + * + * Base node implementation + * + *************************************/ + +discrete_base_node::discrete_base_node() : + m_step_intf(NULL), + m_input_intf(NULL) +{ + m_output[0] = 0.0; +} + + +discrete_base_node::~discrete_base_node(void) +{ + /* currently noting */ +} + +void discrete_base_node::init(discrete_device *pdev, const discrete_block *xblock) +{ + m_device = pdev; + m_block = xblock; + + m_custom = m_block->custom; + m_active_inputs = m_block->active_inputs; + + m_step_intf = dynamic_cast(this); + m_input_intf = dynamic_cast(this); + m_output_intf = dynamic_cast(this); + + if (m_step_intf) + { + m_step_intf->run_time = 0; + m_step_intf->self = this; + } +} + +void discrete_base_node::save_state(void) +{ + if (m_block->node != NODE_SPECIAL) + m_device->save_item(NAME(m_output), m_block->node); +} + +discrete_base_node *discrete_device::discrete_find_node(int node) +{ + if (node < NODE_START || node > NODE_END) return NULL; + return m_indexed_node[NODE_INDEX(node)]; +} + +void discrete_base_node::resolve_input_nodes(void) +{ + int inputnum; + + /* loop over all active inputs */ + for (inputnum = 0; inputnum < m_active_inputs; inputnum++) + { + int inputnode = m_block->input_node[inputnum]; + + /* if this input is node-based, find the node in the indexed list */ + if IS_VALUE_A_NODE(inputnode) + { + //discrete_base_node *node_ref = m_device->m_indexed_node[NODE_INDEX(inputnode)]; + discrete_base_node *node_ref = m_device->discrete_find_node(inputnode); + if (!node_ref) + fatalerror("discrete_start - NODE_%02d referenced a non existent node NODE_%02d\n", index(), NODE_INDEX(inputnode)); + + if ((NODE_CHILD_NODE_NUM(inputnode) >= node_ref->max_output()) /*&& (node_ref->module_type() != DST_CUSTOM)*/) + fatalerror("discrete_start - NODE_%02d referenced non existent output %d on node NODE_%02d\n", index(), NODE_CHILD_NODE_NUM(inputnode), NODE_INDEX(inputnode)); + + m_input[inputnum] = &(node_ref->m_output[NODE_CHILD_NODE_NUM(inputnode)]); /* Link referenced node out to input */ + m_input_is_node |= 1 << inputnum; /* Bit flag if input is node */ + } + else + { + /* warn if trying to use a node for an input that can only be static */ + if IS_VALUE_A_NODE(m_block->initial[inputnum]) + { + m_device->discrete_log("Warning - discrete_start - NODE_%02d trying to use a node on static input %d", index(), inputnum); + /* also report it in the error log so it is not missed */ + logerror("Warning - discrete_start - NODE_%02d trying to use a node on static input %d", index(), inputnum); + } + else + { + m_input[inputnum] = &(m_block->initial[inputnum]); + } + } + } + for (inputnum = m_active_inputs; inputnum < DISCRETE_MAX_INPUTS; inputnum++) + { + /* FIXME: Check that no nodes follow ! */ + m_input[inputnum] = &(m_block->initial[inputnum]); + } +} + +const double *discrete_device::node_output_ptr(int onode) +{ + const discrete_base_node *node; + node = discrete_find_node(onode); + + if (node != NULL) + { + return &(node->m_output[NODE_CHILD_NODE_NUM(onode)]); + } + else + return NULL; +} + +/************************************* + * + * Device implementation + * + *************************************/ + + +//------------------------------------------------- +// discrete_log: Debug logging +//------------------------------------------------- + +void CLIB_DECL discrete_device::discrete_log(const char *text, ...) const +{ + if (DISCRETE_DEBUGLOG) + { + va_list arg; + va_start(arg, text); + + if(m_disclogfile) + { + vfprintf(m_disclogfile, text, arg); + fprintf(m_disclogfile, "\n"); + fflush(m_disclogfile); + } + + va_end(arg); + } +} + +//------------------------------------------------- +// discrete_build_list: Build import list +//------------------------------------------------- + +void discrete_device::discrete_build_list(const discrete_block *intf, sound_block_list_t &block_list) +{ + int node_count = 0; + + for (; intf[node_count].type != DSS_NULL; ) + { + /* scan imported */ + if (intf[node_count].type == DSO_IMPORT) + { + discrete_log("discrete_build_list() - DISCRETE_IMPORT @ NODE_%02d", NODE_INDEX(intf[node_count].node) ); + discrete_build_list((discrete_block *) intf[node_count].custom, block_list); + } + else if (intf[node_count].type == DSO_REPLACE) + { + bool found = false; + node_count++; + if (intf[node_count].type == DSS_NULL) + fatalerror("discrete_build_list: DISCRETE_REPLACE at end of node_list\n"); + + for (int i=0; i < block_list.count(); i++) + { + const discrete_block *block = block_list[i]; + + if (block->type != NODE_SPECIAL ) + if (block->node == intf[node_count].node) + { + block_list[i] = &intf[node_count]; + discrete_log("discrete_build_list() - DISCRETE_REPLACE @ NODE_%02d", NODE_INDEX(intf[node_count].node) ); + found = true; + break; + } + } + + if (!found) + fatalerror("discrete_build_list: DISCRETE_REPLACE did not found node %d\n", NODE_INDEX(intf[node_count].node)); + + } + else if (intf[node_count].type == DSO_DELETE) + { + vector_t deletethem; + + for (int i=0; inode >= intf[node_count].input_node[0]) && + (block->node <= intf[node_count].input_node[1])) + { + discrete_log("discrete_build_list() - DISCRETE_DELETE deleted NODE_%02d", NODE_INDEX(block->node) ); + deletethem.add(i); + } + } + for_each (int *, i, &deletethem) + block_list.remove(*i); + } + else + { + discrete_log("discrete_build_list() - adding node %d\n", node_count); + block_list.add(&intf[node_count]); + } + + node_count++; + } +} + +//------------------------------------------------- +// discrete_sanity_check: Sanity check list +//------------------------------------------------- + +void discrete_device::discrete_sanity_check(const sound_block_list_t &block_list) +{ + int node_count = 0; + + discrete_log("discrete_start() - Doing node list sanity check"); + for (int i=0; i < block_list.count(); i++) + { + const discrete_block *block = block_list[i]; + + /* make sure we don't have too many nodes overall */ + if (node_count > DISCRETE_MAX_NODES) + fatalerror("discrete_start() - Upper limit of %d nodes exceeded, have you terminated the interface block?\n", DISCRETE_MAX_NODES); + + /* make sure the node number is in range */ + if (block->node < NODE_START || block->node > NODE_END) + fatalerror("discrete_start() - Invalid node number on node %02d descriptor\n", block->node); + + /* make sure the node type is valid */ + if (block->type > DSO_OUTPUT) + fatalerror("discrete_start() - Invalid function type on NODE_%02d\n", NODE_INDEX(block->node) ); + + /* make sure this is a main node */ + if (NODE_CHILD_NODE_NUM(block->node) > 0) + fatalerror("discrete_start() - Child node number on NODE_%02d\n", NODE_INDEX(block->node) ); + + node_count++; + } + discrete_log("discrete_start() - Sanity check counted %d nodes", node_count); + +} + +//------------------------------------------------- +// discrete_sanity_check: Sanity check list +//------------------------------------------------- + +/************************************* + * + * Master discrete system start + * + *************************************/ + + +/************************************* + * + * Master discrete system stop + * + *************************************/ + +static UINT64 list_run_time(const node_list_t &list) +{ + UINT64 total = 0; + + for_each(discrete_base_node **, node, &list) + { + discrete_step_interface *step; + if ((*node)->interface(step)) + total += step->run_time; + } + return total; +} + +static UINT64 step_list_run_time(const node_step_list_t &list) +{ + UINT64 total = 0; + + for_each(discrete_step_interface **, node, &list) + { + total += (*node)->run_time; + } + return total; +} + +void discrete_device::display_profiling(void) +{ + int count; + UINT64 total; + UINT64 tresh; + double tt; + + /* calculate total time */ + total = list_run_time(m_node_list); + count = m_node_list.count(); + /* print statistics */ + printf("Total Samples : %16" I64FMT "d\n", m_total_samples); + tresh = total / count; + printf("Threshold (mean): %16" I64FMT "d\n", tresh / m_total_samples ); + for_each(discrete_base_node **, node, &m_node_list) + { + discrete_step_interface *step; + if ((*node)->interface(step)) + if (step->run_time > tresh) + printf("%3d: %20s %8.2f %10.2f\n", (*node)->index(), (*node)->module_name(), (double) step->run_time / (double) total * 100.0, ((double) step->run_time) / (double) m_total_samples); + } + + /* Task information */ + for_each(discrete_task **, task, &task_list) + { + tt = step_list_run_time((*task)->step_list); + + printf("Task(%d): %8.2f %15.2f\n", (*task)->task_group, tt / (double) total * 100.0, tt / (double) m_total_samples); + } + + printf("Average samples/double->update: %8.2f\n", (double) m_total_samples / (double) m_total_stream_updates); +} + + +/************************************* + * + * First pass init of nodes + * + *************************************/ + + +void discrete_device::init_nodes(const sound_block_list_t &block_list) +{ + discrete_task *task = NULL; + /* list tail pointers */ + int has_tasks = 0; + + /* check whether we have tasks ... */ + if (USE_DISCRETE_TASKS) + { + for (int i = 0; i < block_list.count(); i++) + { + if (block_list[i]->type == DSO_TASK_START) + has_tasks = 1; + } + } + + if (!has_tasks) + { + /* make sure we have one simple task + * No need to create a node since there are no dependencies. + */ + task = auto_alloc_clear(machine(), discrete_task(*this)); + task_list.add(task); + } + + /* loop over all nodes */ + for (int i = 0; i < block_list.count(); i++) + { + const discrete_block *block = block_list[i]; + + //discrete_base_node *node = block->factory->Create(this, block); + discrete_base_node *node = block->factory(this, block); + /* keep track of special nodes */ + if (block->node == NODE_SPECIAL) + { + switch(block->type) + { + /* Output Node */ + case DSO_OUTPUT: + /* nothing -> handled later */ + break; + + /* CSVlog Node for debugging */ + case DSO_CSVLOG: + break; + + /* Wavelog Node for debugging */ + case DSO_WAVLOG: + break; + + /* Task processing */ + case DSO_TASK_START: + if (USE_DISCRETE_TASKS) + { + if (task != NULL) + fatalerror("init_nodes() - Nested DISCRETE_START_TASK.\n"); + task = auto_alloc_clear(machine(), discrete_task(*this)); + task->task_group = block->initial[0]; + if (task->task_group < 0 || task->task_group >= DISCRETE_MAX_TASK_GROUPS) + fatalerror("discrete_dso_task: illegal task_group %d\n", task->task_group); + //printf("task group %d\n", task->task_group); + task_list.add(task); + } + break; + + case DSO_TASK_END: + if (USE_DISCRETE_TASKS) + { + if (task == NULL) + fatalerror("init_nodes() - NO DISCRETE_START_TASK.\n"); + } + break; + + default: + fatalerror("init_nodes() - Failed, trying to create unknown special discrete node.\n"); + } + } + + /* otherwise, make sure we are not a duplicate, and put ourselves into the indexed list */ + else + { + if (m_indexed_node[NODE_INDEX(block->node)]) + fatalerror("init_nodes() - Duplicate entries for NODE_%02d\n", NODE_INDEX(block->node)); + m_indexed_node[NODE_INDEX(block->node)] = node; + } + + /* add to node list */ + m_node_list.add(node); + + /* our running order just follows the order specified */ + /* does the node step ? */ + discrete_step_interface *step; + if (node->interface(step)) + { + /* do we belong to a task? */ + if (task == NULL) + fatalerror("init_nodes() - found node outside of task: %s\n", node->module_name() ); + else + task->step_list.add(step); + } + + if (USE_DISCRETE_TASKS && block->type == DSO_TASK_END) + { + task = NULL; + } + + /* and register save state */ + node->save_state(); + } + + if (!has_tasks) + { + } +} + + +/************************************* + * + * node_description implementation + * + *************************************/ + + +int discrete_device::same_module_index(const discrete_base_node &node) +{ + int index = 0; + + for_each(discrete_base_node **, n, &m_node_list) + { + if (*n == &node) + return index; + if ((*n)->module_type() == node.module_type()) + index++; + } + return -1; +} + + +//************************************************************************** +// DEVICE CONFIGURATION +//************************************************************************** + +//------------------------------------------------- +// static_set_intf - configuration helper to set +// the interface +//------------------------------------------------- + +void discrete_device::static_set_intf(device_t &device, const discrete_block *intf) +{ + discrete_device &disc = downcast(device); + disc.m_intf = intf; +} + +//------------------------------------------------- +// discrete_device - constructor +//------------------------------------------------- + +discrete_device::discrete_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, type, name, tag, owner, clock, "discrete", __FILE__), + m_intf(NULL), + m_sample_rate(0), + m_sample_time(0), + m_neg_sample_time(0), + m_indexed_node(NULL), + m_disclogfile(NULL), + m_queue(NULL), + m_profiling(0), + m_total_samples(0), + m_total_stream_updates(0) +{ +} + +discrete_sound_device::discrete_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : discrete_device(mconfig, DISCRETE, "DISCRETE", tag, owner, clock), + device_sound_interface(mconfig, *this) +{ +} + +discrete_device::~discrete_device(void) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void discrete_device::device_start() +{ + // create the stream + //m_stream = machine().sound().stream_alloc(*this, 0, 2, 22257); + + const discrete_block *intf_start = m_intf; + char name[128]; + + /* If a clock is specified we will use it, otherwise run at the audio sample rate. */ + if (this->clock()) + m_sample_rate = this->clock(); + else + m_sample_rate = this->machine().sample_rate(); + m_sample_time = 1.0 / m_sample_rate; + m_neg_sample_time = - m_sample_time; + + m_total_samples = 0; + m_total_stream_updates = 0; + + /* create the logfile */ + sprintf(name, "discrete%s.log", this->tag()); + if (DISCRETE_DEBUGLOG) + m_disclogfile = fopen(name, "w"); + + /* enable profiling */ + m_profiling = 0; + if (getenv("DISCRETE_PROFILING")) + m_profiling = atoi(getenv("DISCRETE_PROFILING")); + + /* Build the final block list */ + sound_block_list_t block_list; + discrete_build_list(intf_start, block_list); + + /* first pass through the nodes: sanity check, fill in the indexed_nodes, and make a total count */ + discrete_sanity_check(block_list); + + /* Start with empty lists */ + m_node_list.clear(); + + /* allocate memory to hold pointers to nodes by index */ + m_indexed_node = auto_alloc_array_clear(this->machine(), discrete_base_node *, DISCRETE_MAX_NODES); + + /* initialize the node data */ + init_nodes(block_list); + + /* now go back and find pointers to all input nodes */ + for_each(discrete_base_node **, node, &m_node_list) + { + (*node)->resolve_input_nodes(); + } + + /* allocate a queue */ + m_queue = osd_work_queue_alloc(WORK_QUEUE_FLAG_MULTI | WORK_QUEUE_FLAG_HIGH_FREQ); + + /* Process nodes which have a start func */ + for_each(discrete_base_node **, node, &m_node_list) + { + (*node)->start(); + } + + /* Now set up tasks */ + for_each(discrete_task **, task, &task_list) + { + for_each(discrete_task **, dest_task, &task_list) + { + if ((*task)->task_group > (*dest_task)->task_group) + (*dest_task)->check((*task)); + } + } +} + +void discrete_device::device_stop() +{ + if (m_queue) + { + osd_work_queue_free(m_queue); + } + + if (m_profiling) + { + display_profiling(); + } + + /* Process nodes which have a stop func */ + + for_each(discrete_base_node **, node, &m_node_list) + { + (*node)->stop(); + } + + if (DISCRETE_DEBUGLOG) + { + /* close the debug log */ + if (m_disclogfile) + fclose(m_disclogfile); + m_disclogfile = NULL; + } +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void discrete_sound_device::device_start() +{ + m_input_stream_list.clear(); + m_output_list.clear(); + + /* call the parent */ + discrete_device::device_start(); + + /* look for input stream nodes */ + for_each(discrete_base_node **, node, &m_node_list) + { + /* if we are an stream input node, track that */ + discrete_dss_input_stream_node *input_stream = dynamic_cast(*node); + if (input_stream != NULL) + { + m_input_stream_list.add(input_stream); + } + /* if this is an output interface, add it the output list */ + discrete_sound_output_interface *out; + if ((*node)->interface(out)) + m_output_list.add(out); + } + + /* if no outputs, give an error */ + if (m_output_list.count() == 0) + fatalerror("init_nodes() - Couldn't find an output node\n"); + + /* initialize the stream(s) */ + m_stream = machine().sound().stream_alloc(*this,m_input_stream_list.count(), m_output_list.count(), m_sample_rate); + + /* Finalize stream_input_nodes */ + for_each(discrete_dss_input_stream_node **, node, &m_input_stream_list) + { + (*node)->stream_start(); + } + + +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void discrete_device::device_reset() +{ + update_to_current_time(); + + /* loop over all nodes */ + for_each (discrete_base_node **, node, &m_node_list) + { + /* Fimxe : node_level */ + (*node)->m_output[0] = 0; + + (*node)->reset(); + } +} + +void discrete_sound_device::device_reset() +{ + discrete_device::device_reset(); +} + +//------------------------------------------------- +// discrete_device_process - process a number of +// samples. +// +// input / output buffers are stream_sample_t +// to not to have to convert the buffers. +// a "discrete cpu" device will pass NULL here +//------------------------------------------------- + +void discrete_device::process(int samples) +{ + if (samples == 0) + return; + + /* Setup tasks */ + for_each(discrete_task **, task, &task_list) + { + /* unlock the thread */ + (*task)->unlock(); + + (*task)->prepare_for_queue(samples); + } + + for_each(discrete_task **, task, &task_list) + { + /* Fire a work item for each task */ + osd_work_item_queue(m_queue, discrete_task::task_callback, (void *) &task_list, WORK_ITEM_FLAG_AUTO_RELEASE); + } + osd_work_queue_wait(m_queue, osd_ticks_per_second()*10); + + if (m_profiling) + { + m_total_samples += samples; + m_total_stream_updates++; + } +} + +//------------------------------------------------- +// sound_stream_update - handle update requests for +// our sound stream +//------------------------------------------------- + +void discrete_sound_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + int outputnum = 0; + + if (samples == 0) + return; + + /* Setup any output streams */ + for_each(discrete_sound_output_interface **, node, &m_output_list) + { + (*node)->set_output_ptr(outputs[outputnum]); + outputnum++; + } + + /* Setup any input streams */ + for_each(discrete_dss_input_stream_node **, node, &m_input_stream_list) + { + (*node)->m_ptr = (stream_sample_t *) inputs[(*node)->m_stream_in_number]; + } + + /* just process it */ + process(samples); +} + +//------------------------------------------------- +// read - read from the chip's registers and internal RAM +//------------------------------------------------- + +READ8_MEMBER( discrete_device::read ) +{ + const discrete_base_node *node = discrete_find_node(offset); + + UINT8 data = 0; + + /* Read the node input value if allowed */ + if (node) + { + /* Bring the system up to now */ + update_to_current_time(); + + data = (UINT8) node->m_output[NODE_CHILD_NODE_NUM(offset)]; + } + else + fatalerror("discrete_sound_r read from non-existent NODE_%02d\n", offset-NODE_00); + + return data; +} + +//------------------------------------------------- +// write - write to the chip's registers and internal RAM +//------------------------------------------------- + +WRITE8_MEMBER( discrete_device::write ) +{ + const discrete_base_node *node = discrete_find_node(offset); + + /* Update the node input value if it's a proper input node */ + if (node) + { + discrete_input_interface *intf; + if (node->interface(intf)) + intf->input_write(0, data); + else + discrete_log("discrete_sound_w write to non-input NODE_%02d\n", offset-NODE_00); + } + else + { + discrete_log("discrete_sound_w write to non-existent NODE_%02d\n", offset-NODE_00); + } +} + +#if (defined(__MINGW32__) && (__GNUC__ >= 5)) +#pragma GCC diagnostic pop +#endif diff --git a/src/devices/sound/discrete.h b/src/devices/sound/discrete.h new file mode 100644 index 00000000000..d3dfd2c4e85 --- /dev/null +++ b/src/devices/sound/discrete.h @@ -0,0 +1,4728 @@ +// license:??? +// copyright-holders:K.Wilkins, Derrick Renaud, Frank Palazzolo, Couriersud +#pragma once + +#ifndef __DISCRETE_H__ +#define __DISCRETE_H__ + +#include "machine/rescap.h" + +/*********************************************************************** + * + * MAME - Discrete sound system emulation library + * + * Written by K.Wilkins (mame@esplexo.co.uk) + * + * (c) K.Wilkins 2000 + * + * Coding started in November 2000 + * + * Additions/bugfix February 2003 - Derrick Renaud, F.Palazzolo, K.Wilkins + * Discrete parallel tasks 2009 - Couriersud + * + *********************************************************************** + * + * For free text books on electronic theory check out: + * http://www.ibiblio.org/obp/electricCircuits/ + * For a free circuit simulator: + * http://qucs.sourceforge.net/index.html + * For a free waveform editor to view DISCRETE_WAVLOG dumps: + * http://audacity.sourceforge.net/ + * http://www.sonicvisualiser.org/ + * + *********************************************************************** + * + * Currently only one instance of a discrete sound system is supported. + * If more then one instance is required in the future, then a chip # + * will have to be added to the read/writes and the discrete inputs + * modified to match. This functionality should never be needed. + * There is no real need to run more then 1 discrete system. + * + * If a clock is specified in the machine driver setup, then this is + * used for the simulation sample rate. Otherwise it will default to + * run at the audio sample rate. + * + * Unused/Unconnected input nodes should be set to NODE_NC (No Connect) + * + * Each node can have many inputs from either constants or other + * nodes within the system. + * + * It should be remembered that the discrete sound system emulation + * does not do individual device emulation, but instead does a function + * emulation. So you will need to convert the schematic design into + * a logic block representation. + * + * There is the possibility to support multiple outputs per module. + * In this case, NODE_XXX is the default output. Alternative outputs may + * be accessed by using NODE_XXX_YY where 00<=Y<08. + * + * You may also access nodes with a macros: + * + * NODE_XXX = NODE_SUB(NODE_XXX, 0) + * NODE_XXX = NODE_XXX_00 + * NODE_XXX = NODE(XXX) + * NODE_XXX_YY = NODE_SUB(NODE_XXX, YY) + * + * One node point may feed a number of inputs, for example you could + * connect the output of a DISCRETE_SINEWAVE to the AMPLITUDE input + * of another DISCRETE_SINEWAVE to amplitude modulate its output and + * also connect it to the frequency input of another to frequency + * modulate its output, the combinations are endless.... + * + * Consider the circuit below: + * + * .--------. .----------. .-------. + * | | | | | | + * | SQUARE | Enable| SINEWAVE | | | + * | WAVE |-+---------->| 2000Hz |---------------->| | + * | | | | | | ADDER |-->OUT + * | NODE11 | | | NODE12 | | | + * '--------' | '----------' .->| | + * | | |NODE20 | + * | .------. .---------. | '-------' + * | |Logic | | | | ^ + * | | INV | Enable | SINEWVE | | | + * '->| ERT |------------->| 4000Hz |--' .-------. + * | | | | | | + * |NODE13| | NODE14 | | INPUT | + * '------' '---------' | | + * |NODE01 | + * '-------' + * + * This should give you an alternating two tone sound switching + * between the 2000Hz and 4000Hz sine waves at the frequency of the + * square wave, with the memory mapped enable signal mapped onto NODE07 + * so discrete_sound_w(NODE_01,1) will enable the sound, and + * discrete_sound_w(NODE_01,0) will disable the sound. + * + * DISCRETE_SOUND_START(test_interface) + * DISCRETE_INPUT_LOGIC(NODE_01) + * DISCRETE_SQUAREWFIX(NODE_11, 1, 0.5, 1, 50, 1.0/2, 0) // Output 0:1 + * DISCRETE_SINEWAVE(NODE_12, NODE_11, 2000, 10000, 0, 0) + * DISCRETE_LOGIC_INVERT(NODE_13, NODE_11) + * DISCRETE_SINEWAVE(NODE_14, NODE_13, 4000, 10000, 0, 0) + * DISCRETE_ADDER2(NODE_20, NODE_01, NODE_12, NODE_14) + * DISCRETE_OUTPUT(NODE_20, 1) + * DISCRETE_SOUND_END + * + * To aid simulation speed it is preferable to use the enable/disable + * inputs to a block rather than setting the output amplitude to zero + * + * Feedback loops are allowed BUT they will always feedback one time + * step later, the loop over the netlist is only performed once per + * deltaT so feedback occurs in the next deltaT step. This is not + * the perfect solution but saves repeatedly traversing the netlist + * until all nodes have settled. + * + * The best way to work out your system is generally to use a pen and + * paper to draw a logical block diagram like the one above, it helps + * to understand the system ,map the inputs and outputs and to work + * out your node numbering scheme. + * + * Node numbers NODE_01 to NODE_299 are defined at present. + * + * It is recommended to put all Inputs at the start of the interface. + * That way they are updated first. + * + * Each sound effects final node should come after all nodes that + * create it. The final mixing of all sound effects should come + * at the end of the interface. + * + *********************************************************************** + * + * x_time - ANTI-ALIASING features. + * + * Certain modules make use of x_time. This is a feature that passes + * information between modules about how long in the current sample, the + * switch in state happened. This is a decimal value of the % of the + * full sample period that it has been in the new state. + * 0 means it has been at the same state the whole sample. + * + * Example: Here is the output of a clock source with x_time on the + * output. The square wave is the real world waveform we + * want. The ^'s are the sample point. The numbers under + * the ^'s are the node output with the logic state left of + * the decimal and the x_time to the right. Under that is + * what the node's anti-aliased output energy would be. + * Note: the example is not 4x sampling so the energy + * does not provide an accurate representation of the + * original waveform. This is intentional so it fits + * in this header file. + * 1 ____ ____ ____ ____ ____ ____ ____ ____ + * 0 ___ ____ ____ ____ ____ ____ ____ ____ __ + * ^....^....^....^....^....^....^....^....^....^....^....^....^ + * x_time 0.2 1.4 0.6 1.8 1.2 0.4 1.6 0.8 0.2 1.4 0.6 + * energy 0.8 0.4 0.4 0.8 0.2 0.6 0.6 0.2 0.8 0.4 0.4 + * + * Some modules will just pass the x_time onto another module. + * + * Modules that process x_time will keep track of the node's previous + * state so they can calculate the actual energy at the sample time. + * + * Example: Say we have a 555 module that outputs a clock with x_time + * that is connected to a counter. The output of the counter + * is connected to DAC_R1. + * In this case the counter module continues counting dependant + * on the integer portion of the 555 output. But it also + * passes the decimal portion as the x_time. + * The DAC_R1 then uses this info to anti-alias its output. + * Consider the following counter outputs vs DAC_R1 + * calculations. The count changes from 9 to 10. It has + * been at the new state for 75% of the sample. + * + * counter binary x_time -- DAC_R1 bit energy -- + * out count D3 D2 D1 D0 + * 9.0 1001 0.0 1.0 0.0 0.0 1.0 + * 10.75 1010 0.75 1.0 0.0 0.75 0.25 + * 10.0 1010 0.0 1.0 0.0 1.0 0.0 + * + * The DAC_R1 uses these energy calculations to scale the + * voltages created on each of its resistors. This + * anti-aliases the waveform no mater what the resistor + * weighting is. + * + *********************************************************************** + * + * LIST OF CURRENTLY IMPLEMENTED DISCRETE BLOCKS + * --------------------------------------------- + * + * DISCRETE_SOUND_START(STRUCTURENAME) + * DISCRETE_SOUND_END + * + * DISCRETE_ADJUSTMENT(NODE,MIN,MAX,LOGLIN,TAG) + * DISCRETE_ADJUSTMENTX(NODE,MIN,MAX,LOGLIN,TAG,PMIN,PMAX) + * DISCRETE_CONSTANT(NODE,CONST0) + * DISCRETE_INPUT_DATA(NODE) + * DISCRETE_INPUTX_DATA(NODE,GAIN,OFFSET,INIT) + * DISCRETE_INPUT_LOGIC(NODE) + * DISCRETE_INPUTX_LOGIC(NODE,GAIN,OFFSET,INIT) + * DISCRETE_INPUT_NOT(NODE) + * DISCRETE_INPUTX_NOT(NODE,GAIN,OFFSET,INIT) + * DISCRETE_INPUT_PULSE(NODE,INIT) + * DISCRETE_INPUT_STREAM(NODE, NUM) + * DISCRETE_INPUTX_STREAM(NODE,NUM, GAIN,OFFSET) + * + * DISCRETE_COUNTER(NODE,ENAB,RESET,CLK,MIN,MAX,DIR,INIT0,CLKTYPE) + * DISCRETE_COUNTER_7492(NODE,ENAB,RESET,CLK,CLKTYPE) + * DISCRETE_LFSR_NOISE(NODE,ENAB,RESET,CLK,AMPL,FEED,BIAS,LFSRTB) + * DISCRETE_NOISE(NODE,ENAB,FREQ,AMP,BIAS) + * DISCRETE_NOTE(NODE,ENAB,CLK,DATA,MAX1,MAX2,CLKTYPE) + * DISCRETE_SAWTOOTHWAVE(NODE,ENAB,FREQ,AMP,BIAS,GRADIENT,PHASE) + * DISCRETE_SINEWAVE(NODE,ENAB,FREQ,AMP,BIAS,PHASE) + * DISCRETE_SQUAREWAVE(NODE,ENAB,FREQ,AMP,DUTY,BIAS,PHASE) + * DISCRETE_SQUAREWFIX(NODE,ENAB,FREQ,AMP,DUTY,BIAS,PHASE) + * DISCRETE_SQUAREWAVE2(NODE,ENAB,AMPL,T_OFF,T_ON,BIAS,TSHIFT) + * DISCRETE_TRIANGLEWAVE(NODE,ENAB,FREQ,AMP,BIAS,PHASE) + * + * DISCRETE_INVERTER_OSC(NODE,ENAB,MOD,RCHARGE,RP,C,R2,INFO) + * DISCRETE_OP_AMP_OSCILLATOR(NODE,ENAB,INFO) + * DISCRETE_OP_AMP_VCO1(NODE,ENAB,VMOD1,INFO) + * DISCRETE_OP_AMP_VCO2(NODE,ENAB,VMOD1,VMOD2,INFO) + * DISCRETE_SCHMITT_OSCILLATOR(NODE,ENAB,INP0,AMPL,TABLE) + * + * DISCRETE_ADDER2(NODE,ENAB,IN0,IN1) + * DISCRETE_ADDER3(NODE,ENAB,IN0,IN1,IN2) + * DISCRETE_ADDER4(NODE,ENAB,IN0,IN1,IN2,IN3) + * DISCRETE_CLAMP(NODE,IN0,MIN,MAX) + * DISCRETE_DIVIDE(NODE,ENAB,IN0,IN1) + * DISCRETE_GAIN(NODE,IN0,GAIN) + * DISCRETE_INVERT(NODE,IN0) + * DISCRETE_LOOKUP_TABLE(NODE,ADDR,SIZE,TABLE) + * DISCRETE_MULTIPLY(NODE,ENAB,IN0,IN1) + * DISCRETE_MULTADD(NODE,INP0,INP1,INP2) + * DISCRETE_ONESHOT(NODE,TRIG,AMPL,WIDTH,TYPE) + * DISCRETE_ONESHOTR(NODE,RESET,TRIG,AMPL,WIDTH,TYPE) + * DISCRETE_ONOFF(NODE,ENAB,INP0) + * DISCRETE_RAMP(NODE,ENAB,RAMP,GRAD,MIN,MAX,CLAMP) + * DISCRETE_SAMPLHOLD(NODE,INP0,CLOCK,CLKTYPE) + * DISCRETE_SWITCH(NODE,ENAB,SWITCH,INP0,INP1) + * DISCRETE_ASWITCH(NODE,CTRL,INP,THRESHOLD) + * DISCRETE_TRANSFORM2(NODE,INP0,INP1,FUNCT) + * DISCRETE_TRANSFORM3(NODE,INP0,INP1,INP2,FUNCT) + * DISCRETE_TRANSFORM4(NODE,INP0,INP1,INP2,INP3,FUNCT) + * DISCRETE_TRANSFORM5(NODE,INP0,INP1,INP2,INP3,INP4,FUNCT) + * + * DISCRETE_COMP_ADDER(NODE,DATA,TABLE) + * DISCRETE_DAC_R1(NODE,DATA,VDATA,LADDER) + * DISCRETE_DIODE_MIXER2(NODE,IN0,IN1,TABLE) + * DISCRETE_DIODE_MIXER3(NODE,IN0,IN1,IN2,TABLE) + * DISCRETE_DIODE_MIXER4(NODE,IN0,IN1,IN2,IN3,TABLE) + * DISCRETE_INTEGRATE(NODE,TRG0,TRG1,INFO) + * DISCRETE_MIXER2(NODE,ENAB,IN0,IN1,INFO) + * DISCRETE_MIXER3(NODE,ENAB,IN0,IN1,IN2,INFO) + * DISCRETE_MIXER4(NODE,ENAB,IN0,IN1,IN2,IN3,INFO) + * DISCRETE_MIXER5(NODE,ENAB,IN0,IN1,IN2,IN3,IN4,INFO) + * DISCRETE_MIXER6(NODE,ENAB,IN0,IN1,IN2,IN3,IN4,IN5,INFO) + * DISCRETE_MIXER7(NODE,ENAB,IN0,IN1,IN2,IN3,IN4,IN5,IN6,INFO) + * DISCRETE_MIXER8(NODE,ENAB,IN0,IN1,IN2,IN3,IN4,IN5,IN6,IN7,INFO) + * DISCRETE_OP_AMP(NODE,ENAB,IN0,IN1,INFO) + * DISCRETE_OP_AMP_ONESHOT(NODE,TRIG,INFO) + * DISCRETE_OP_AMP_TRIG_VCA(NODE,TRG0,TRG1,TRG2,IN0,IN1,INFO) + * + * DISCRETE_BIT_DECODE(NODE,INP,BIT_N,VOUT) + * DISCRETE_BITS_DECODE(NODE,INP,BIT_FROM,BIT_TO,VOUT) + * + * DISCRETE_LOGIC_INVERT(NODE,INP0) + * DISCRETE_LOGIC_AND(NODE,INP0,INP1) + * DISCRETE_LOGIC_AND3(NODE,INP0,INP1,INP2) + * DISCRETE_LOGIC_AND4(NODE,INP0,INP1,INP2,INP3) + * DISCRETE_LOGIC_NAND(NODE,INP0,INP1) + * DISCRETE_LOGIC_NAND3(NODE,INP0,INP1,INP2) + * DISCRETE_LOGIC_NAND4(NODE,INP0,INP1,INP2,INP3) + * DISCRETE_LOGIC_OR(NODE,INP0,INP1) + * DISCRETE_LOGIC_OR3(NODE,INP0,INP1,INP2) + * DISCRETE_LOGIC_OR4(NODE,INP0,INP1,INP2,INP3) + * DISCRETE_LOGIC_NOR(NODE,INP0,INP1) + * DISCRETE_LOGIC_NOR3(NODE,INP0,INP1,INP2) + * DISCRETE_LOGIC_NOR4(NODE,INP0,INP1,INP2,INP3) + * DISCRETE_LOGIC_XOR(NODE,INP0,INP1) + * DISCRETE_LOGIC_XNOR(NODE,INP0,INP1) + * DISCRETE_LOGIC_DFLIPFLOP(NODE,RESET,SET,CLK,INP) + * DISCRETE_LOGIC_JKFLIPFLOP(NODE,RESET,SET,CLK,J,K) + * DISCRETE_LOGIC_SHIFT(NODE,INP0,RESET,CLK,SIZE,OPTIONS) + * DISCRETE_MULTIPLEX2(NODE,ADDR,INP0,INP1) + * DISCRETE_MULTIPLEX4(NODE,ADDR,INP0,INP1,INP2,INP3) + * DISCRETE_MULTIPLEX8(NODE,ADDR,INP0,INP1,INP2,INP3,INP4,INP5,INP6,INP7) + * DISCRETE_XTIME_BUFFER(NODE,IN0,LOW,HIGH) + * DISCRETE_XTIME_INVERTER(NODE,IN0,LOW,HIGH) + * DISCRETE_XTIME_AND(NODE,IN0,IN1,LOW,HIGH) + * DISCRETE_XTIME_NAND(NODE,IN0,IN1,LOW,HIGH) + * DISCRETE_XTIME_OR(NODE,IN0,IN1,LOW,HIGH) + * DISCRETE_XTIME_NOR(NODE,IN0,IN1,LOW,HIGH) + * DISCRETE_XTIME_XOR(NODE,IN0,IN1,LOW,HIGH) + * DISCRETE_XTIME_XNOR(NODE,IN0,IN1,LOW,HIGH) + * + * DISCRETE_FILTER1(NODE,ENAB,INP0,FREQ,TYPE) + * DISCRETE_FILTER2(NODE,ENAB,INP0,FREQ,DAMP,TYPE) + * + * DISCRETE_CRFILTER(NODE,IN0,RVAL,CVAL) + * DISCRETE_CRFILTER_VREF(NODE,IN0,RVAL,CVAL,VREF) + * DISCRETE_OP_AMP_FILTER(NODE,ENAB,INP0,INP1,TYPE,INFO) + * DISCRETE_RC_CIRCUIT_1(NODE,INP0,INP1,RVAL,CVAL) + * DISCRETE_RCDISC(NODE,ENAB,IN0,RVAL,CVAL) + * DISCRETE_RCDISC2(NODE,SWITCH,INP0,RVAL0,INP1,RVAL1,CVAL) + * DISCRETE_RCDISC3(NODE,ENAB,INP0,RVAL0,RVAL1,CVAL, DJV) + * DISCRETE_RCDISC4(NODE,ENAB,INP0,RVAL0,RVAL1,RVAL2,CVAL,VP,TYPE) + * DISCRETE_RCDISC5(NODE,ENAB,IN0,RVAL,CVAL) + * DISCRETE_RCINTEGRATE(NODE,INP0,RVAL0,RVAL1,RVAL2,CVAL,vP,TYPE) + * DISCRETE_RCDISC_MODULATED(NODE,INP0,INP1,RVAL0,RVAL1,RVAL2,RVAL3,CVAL,VP) + * DISCRETE_RCFILTER(NODE,IN0,RVAL,CVAL) + * DISCRETE_RCFILTER_VREF(NODE,IN0,RVAL,CVAL,VREF) + * + * DISCRETE_555_ASTABLE(NODE,RESET,R1,R2,C,OPTIONS) + * DISCRETE_555_ASTABLE_CV(NODE,RESET,R1,R2,C,CTRLV,OPTIONS) + * DISCRETE_555_MSTABLE(NODE,RESET,TRIG,R,C,OPTIONS) + * DISCRETE_555_CC(NODE,RESET,VIN,R,C,RBIAS,RGND,RDIS,OPTIONS) + * DISCRETE_555_VCO1(NODE,RESET,VIN,OPTIONS) + * DISCRETE_555_VCO1_CV(NODE,RESET,VIN,CTRLV,OPTIONS) + * DISCRETE_566(NODE,VMOD,R,C,VPOS,VNEG,VCHARGE,OPTIONS) + * DISCRETE_74LS624(NODE,ENAB,VMOD,VRNG,C,R_FREQ_IN,C_FREQ_IN,R_RNG_IN,OUTTYPE) + * + * DISCRETE_CUSTOM1(NODE,IN0,INFO) + * DISCRETE_CUSTOM2(NODE,IN0,IN1,INFO) + * DISCRETE_CUSTOM3(NODE,IN0,IN1,IN2,INFO) + * DISCRETE_CUSTOM4(NODE,IN0,IN1,IN2,IN3,INFO) + * DISCRETE_CUSTOM5(NODE,IN0,IN1,IN2,IN3,IN4,INFO) + * DISCRETE_CUSTOM6(NODE,IN0,IN1,IN2,IN3,IN4,IN5,INFO) + * DISCRETE_CUSTOM7(NODE,IN0,IN1,IN2,IN3,IN4,IN5,IN6,INFO) + * DISCRETE_CUSTOM8(NODE,IN0,IN1,IN2,IN3,IN4,IN5,IN6,IN7,INFO) + * DISCRETE_CUSTOM9(NODE,IN0,IN1,IN2,IN3,IN4,IN5,IN6,IN7,IN8,INFO) + * + * DISCRETE_CSVLOG1(NODE1) + * DISCRETE_CSVLOG2(NODE1,NODE2) + * DISCRETE_CSVLOG3(NODE1,NODE2,NODE3) + * DISCRETE_CSVLOG4(NODE1,NODE2,NODE3,NODE4) + * DISCRETE_CSVLOG5(NODE1,NODE2,NODE3,NODE4,NODE5) + * DISCRETE_WAVLOG1(NODE1,GAIN1) + * DISCRETE_WAVLOG2(NODE1,GAIN1,NODE2,GAIN2) + * DISCRETE_OUTPUT(OPNODE,GAIN) + * + *********************************************************************** + ======================================================================= + * from from disc_inp.inc + ======================================================================= + *********************************************************************** + * + * DISCRETE_ADJUSTMENT - Adjustable constant set by the UI [~] menu. + * + * .----------. + * | | + * | ADJUST.. |--------> Netlist node + * | | + * '----------' + * Declaration syntax + * + * DISCRETE_ADJUSTMENT(name of node, + * static minimum value the node can take, + * static maximum value the node can take, + * log/linear scale 0=Linear !0=Logarithmic, + * port tag name of the adjuster) + * + * Note: When using DISC_LOGADJ, the min/max values must be > 0. + * If they are <=0, they will be forced to 1. + * Min can be a higher value then max. + * Min/max is just how the slider is displayed. + * + * Example config line + * + * DISCRETE_ADJUSTMENT(NODE_01,0.0,5.0,DISC_LINADJ,0,"pot") + * + * Define an adjustment slider that takes a 0-100 input from input + * port "pot", scaling between 0.0 and 5.0. Adjustment scaling is Linear. + * + * DISC_LOGADJ 1.0 + * DISC_LINADJ 0.0 + * + * EXAMPLES: see Hit Me, Fire Truck + * + *********************************************************************** + * + * DISCRETE_CONSTANT - Single output, fixed at compile time. + * This is usefull as a placeholder for + * incomplete circuits. + * + * .----------. + * | | + * | CONSTANT |--------> Netlist node + * | | + * '----------' + * Declaration syntax + * + * DISCRETE_CONSTANT(name of node, constant value) + * + * Example config line + * + * DISCRETE_CONSTANT(NODE_01, 100) + * + * Define a node that has a constant value of 100 + * + *********************************************************************** + * + * DISCRETE_INPUT_DATA - accepts 8-bit data. Value at reset is 0. + * DISCRETE_INPUT_LOGIC - 0 if data=0; 1 if data=1. Value at reset is 0. + * DISCRETE_INPUT_NOT - 0 if data=1; 1 if data=0. Value at reset is 1. + * + * DISCRETE_INPUTX_xx - same as above, but will modify the value by the + * given GAIN and OFFSET. At reset the value will + * be INIT modified by GAIN and OFFSET. + * + * DISCRETE_INPUT_PULSE - Same as normal input node but the netlist + * node output returns to INIT after a single + * cycle of sound output. To allow for scenarios + * whereby the register write pulse is used as + * a reset to a system. + * + * .----------. + * -----\| | + * discrete_sound_w data | INPUT(A) |----> Netlist node + * Write -----/| | + * '----------' + * + * Declaration syntax + * + * DISCRETE_INPUT_DATA (name of node) + * DISCRETE_INPUT_LOGIC (name of node) + * DISCRETE_INPUT_NOT (name of node) + * DISCRETE_INPUTX_DATA (name of node, gain, offset, initial value) + * DISCRETE_INPUTX_LOGIC(name of node, gain, offset, initial value) + * DISCRETE_INPUTX_NOT (name of node, gain, offset, initial value) + * DISCRETE_INPUT_PULSE (name of node, default value) + * + * Can be written to with: discrete_sound_w(NODE_xx, data); + * + *********************************************************************** + * + * DISCRETE_INPUT_STREAM(NODE,NUM) - Accepts stream input NUM + * DISCRETE_INPUTX_STREAM(NODE,NUM,GAIN,OFFSET) - Accepts a stream input and + * applies a gain and offset. + * + * Declaration syntax + * + * DISCRETE_INPUT_STREAM (name of node, stream number, ) + * DISCRETE_INPUTX_STREAM(name of node, stream nubmer, gain, offset) + * + * Note: The discrete system is floating point based. So when routing a stream + * set it's gain to 100% and then use DISCRETE_INPUTX_STREAM to adjust + * it if needed. + * If you need to access a stream from a discrete task, the stream node + * must be part of that task. If a given stream is used in two tasks or + * a task and the main task, you must declare two stream nodes acccessing the + * same stream input NUM. + * + * EXAMPLES: see scramble, frogger + * + *********************************************************************** + ======================================================================= + * from from disc_wav.inc + * Generic modules + ======================================================================= + *********************************************************************** + * + * DISCRETE_COUNTER - up/down counter. + * + * This counter counts up/down from MIN to MAX. When the enable is low, the output + * is held at it's last value. When reset is high, the reset value is loaded + * into the output. The counter can be clocked internally or externally. It also + * supports x_time used by the clock modules to pass on anti-aliasing info. + * + * Declaration syntax + * + * where: direction: DISC_COUNT_DOWN = 0 = down + * DISC_COUNT_UP = 1 = up + * + * clock type: DISC_CLK_ON_F_EDGE - toggle on falling edge. + * DISC_CLK_ON_R_EDGE - toggle on rising edge. + * DISC_CLK_BY_COUNT - toggle specified number of times. + * DISC_CLK_IS_FREQ - internally clock at this frequency. + * + * x_time options: you can also | these x_time features to the basic + * types above if needed, or use separately with 7492. + * DISC_OUT_IS_ENERGY - This will uses the x_time to + * anti-alias the count. Might be + * usefull if not connected to other + * modules. + * DISC_OUT_HAS_XTIME - This will generate x_time if + * being used with DISC_CLK_IS_FREQ. + * It will pass x_time for the + * other clock types. + * + * DISCRETE_COUNTER(name of node, + * enable node or static value, + * reset node or static value, (reset when TRUE) + * clock node or static value, + * min count static value, + * max count static value, + * direction node or static value, + * reset value node or static value, + * clock type static value) + * + * DISCRETE_COUNTER_7492(name of node, + * enable node or static value, + * reset node or static value, + * clock node or static value, + * clock type static value) + * + * Note: A 7492 counter outputs a special bit pattern on its /6 stage. + * A 7492 clocks on the falling edge, + * so it is not recommended to use DISC_CLK_ON_R_EDGE for a 7492. + * This module emulates the /6 stage only. + * Use another DISCRETE_COUNTER for the /2 stage. + * + * EXAMPLES: see Fire Truck, Monte Carlo, Super Bug, Polaris + * + *********************************************************************** + * + * DISCRETE_LFSR_NOISE - Noise waveform generator node, generates + * psuedo random digital stream at the requested + * clock frequency. + * + * Declaration syntax + * + * DISCRETE_LFSR_NOISE(name of node, + * enable node or static value, + * reset node or static value, + * clock node or static value, + * amplitude node or static value, + * forced infeed bit to shift reg, + * bias node or static value, + * LFSR noise descriptor structure) + * + * discrete_lfsr_desc = {clock type, (see DISCRETE_COUNTER), + * bitlength, reset_value, + * feedback_bitsel0, feedback_bitsel1, + * feedback_function0, feedback_function1, feedback_function2, + * feedback_function2_mask, flags, output_bit} + * + * flags: DISC_LFSR_FLAG_OUT_INVERT - invert output + * DISC_LFSR_FLAG_RESET_TYPE_L - reset when LOW (Defalut) + * DISC_LFSR_FLAG_RESET_TYPE_H - reset when HIGH + * DISC_LFSR_FLAG_OUTPUT_F0 - output is result of F0 + * DISC_LFSR_FLAG_OUTPUT_SR_SN1 - output shift register to sub-node output #1 + * + * The diagram below outlines the structure of the LFSR model. + * + * .-------. + * FEED | | + * ----->| F1 |<--------------------------------------------. + * | | | + * '-------' BS - Bit Select | + * | Fx - Programmable Function | + * | .-------. PI - Programmable Inversion | + * | | | | + * | .---- | SR>>1 |<--------. | + * | | | | | | + * V V '-------' | .---- | + * .------. +->| BS |--. .------. | + * BITMASK | | .-------------. | '----' '-| | | + * ------->| F2 |-+->| Shift Reg |--+ | F0 |--' + * | | | '-------------' | .----. .-| | + * '------' | ^ '->| BS |--' '------' + * | | '----' + * CLOCK | RESET VAL + * ----> | .----. .----. + * '----------------------| BS |--| PI |--->OUTPUT + * '----' '----' + * + * EXAMPLES: see Fire Truck, Monte Carlo, Super Bug, Polaris + * + *********************************************************************** + * + * DISCRETE_NOISE - Noise waveform generator node, generates + * random noise of the chosen frequency. + * + * .------------. + * | | + * ENABLE -0------>| | + * | | + * FREQUENCY -1------>| NOISE |----> Netlist node + * | | + * AMPLITUDE -2------>| | + * | | + * BIAS -3------>| | + * | | + * '------------' + * + * Declaration syntax + * + * DISCRETE_NOISE(name of node, + * enable node or static value, + * frequency node or static value, + * amplitude node or static value) + * + * Example config line + * + * DISCRETE_NOISE(NODE_03,1,5000,NODE_01,0) + * + *********************************************************************** + * + * DISCRETE_NOTE - Note generator. This takes a chosen clock, and + * clocks an up counter that is preloaded with the data + * value at every max 1 count. Every time max 1 count + * is reached, the output counts up one and rolls over + * to 0 at max 2 count. + * When the data value is the same as max count 1, the + * counter no longer counts. + * + * Declaration syntax + * + * DISCRETE_NOTE(name of node, + * enable node or static value, + * clock node or static value, + * data node or static value, + * max 1 count static value, + * max 2 count static value, + * clock type (see DISCRETE_COUNTER)) + * + * EXAMPLES: see Polaris, Blockade + * + *********************************************************************** + * + * DISCRETE_SAWTOOTHWAVE - Saw tooth shape waveform generator, rapid + * rise and then graduated fall + * + * .------------. + * | | + * ENABLE -0------>| | + * | | + * FREQUENCY -1------>| | + * | | + * AMPLITUDE -2------>| SAWTOOTH |----> Netlist Node + * | WAVE | + * BIAS -3------>| | + * | | + * GRADIENT -4------>| | + * | | + * PHASE -5------>| | + * | | + * '------------' + * + * Declaration syntax + * + * DISCRETE_SAWTOOTHWAVE(name of node, + * enable node or static value, + * frequency node or static value, + * amplitude node or static value, + * dc bias value for waveform, + * gradient of wave ==0 //// !=0 \\\\, + * starting phase value in degrees) + * + * Example config line + * + * DISCRETE_SAWTOOTHWAVE(NODE_03,1,5000,NODE_01,0,0,90) + * + *********************************************************************** + * + * DISCRETE_SINEWAVE - Sinewave waveform generator node, has four + * input nodes FREQUENCY, AMPLITUDE, ENABLE and + * PHASE, if a node is not connected it will + * default to the initialised value in the macro + * + * .------------. + * | | + * ENABLE -0------>| | + * | | + * FREQUENCY -1------>| | + * | SINEWAVE |----> Netlist node + * AMPLITUDE -2------>| | + * | | + * BIAS -3------>| | + * | | + * PHASE -4------>| | + * | | + * '------------' + * + * Declaration syntax + * + * DISCRETE_SINEWAVE (name of node, + * enable node or static value, + * frequency node or static value, + * amplitude node or static value, + * dc bias value for waveform, + * starting phase value in degrees) + * + * Example config line + * + * DISCRETE_SINEWAVE(NODE_03,NODE_01,NODE_02,10000,5000.0,90) + * + *********************************************************************** + * + * DISCRETE_SQUAREWAVE - Squarewave waveform generator node. + * DISCRETE_SQUAREWFIX Waveform is defined by frequency and duty + * cycle. + * + * .------------. + * | | + * ENABLE -0------>| | + * | | + * FREQUENCY -1------>| | + * | | + * AMPLITUDE -2------>| SQUAREWAVE |----> Netlist node + * | | + * DUTY CYCLE -3------>| | + * | | + * BIAS -4------>| | + * | | + * PHASE -5------>| | + * | | + * '------------' + * + * Declaration syntax + * + * DISCRETE_SQUAREWAVE(name of node, + * enable node or static value, + * frequency node or static value, + * amplitude node or static value, + * duty cycle node or static value, + * dc bias value for waveform, + * starting phase value in degrees) + * + * Example config line + * + * DISCRETE_SQUAREWAVE(NODE_03,NODE_01,NODE_02,100,50,0,90) + * + * NOTE: DISCRETE_SQUAREWFIX is used the same as DISCRETE_SQUAREWAVE. + * BUT... It does not stay in sync when you change the freq or + * duty values while enabled. This should be used only + * when these values are stable while the wave is enabled. + * It takes up less CPU time then DISCRETE_SQUAREWAVE and + * should be used whenever possible. + * + * EXAMPLES: see Polaris + * + *********************************************************************** + * + * DISCRETE_SQUAREWAVE2 - Squarewave waveform generator node. + * Waveform is defined by it's off/on time + * periods. + * + * .------------. + * | | + * ENABLE -0------>| | + * | | + * AMPLITUDE -1------>| | + * | | + * OFF TIME -2------>| SQUAREWAVE |----> Netlist node + * | | + * ON TIME -3------>| | + * | | + * BIAS -4------>| | + * | | + * TIME SHIFT -5------>| | + * | | + * '------------' + * + * Declaration syntax + * + * DISCRETE_SQUAREWAVE2(name of node, + * enable node or static value, + * amplitude node or static value, + * off time node or static value in seconds, + * on time node or static value in seconds, + * dc bias value for waveform, + * starting phase value in seconds) + * + * Example config line + * + * DISCRETE_SQUAREWAVE2(NODE_03,NODE_01,NODE_02,0.01,0.001,0.0,0.001) + * + *********************************************************************** + * + * DISCRETE_TRIANGLEW - Triagular waveform generator, generates + * equal ramp up/down at chosen frequency + * + * .------------. + * | | + * ENABLE -0------>| | + * | | + * FREQUENCY -1------>| TRIANGLE |----> Netlist node + * | WAVE | + * AMPLITUDE -2------>| | + * | | + * BIAS -3------>| | + * | | + * PHASE -4------>| | + * | | + * '------------' + * + * Declaration syntax + * + * DISCRETE_TRIANGLEWAVE(name of node, + * enable node or static value, + * frequency node or static value, + * amplitude node or static value, + * dc bias value for waveform, + * starting phase value in degrees) + * + * Example config line + * + * DISCRETE_TRIANGLEWAVE(NODE_03,1,5000,NODE_01,0.0,0.0) + * + *********************************************************************** + ======================================================================= + * from from disc_wav.inc + * Component specific modules + ======================================================================= + *********************************************************************** + * + * DISCRETE_OP_AMP_OSCILLATOR - Various single power supply op-amp oscillator circuits + * + * Declaration syntax + * + * DISCRETE_OP_AMP_OSCILLATOR(name of node, + * enable node or static value, + * address of dss_op_amp_osc_context structure) + * + * discrete_op_amp_osc_info = {type, r1, r2, r3, r4, r5, r6, r7, r8, c, vP} + * + * Note: Set all unused components to 0. + * _OUT_SQW can also be replaced with + * _OUT_ENERGY, _OUT_LOGIC_X, _OUT_COUNT_F_X, _OUT_COUNT_R_X + * + * Types: + * + * DISC_OP_AMP_OSCILLATOR_1 | DISC_OP_AMP_IS_NORTON + * Basic Norton Op Amp Oscillator circuit. + * + * vP >-. + * | c + * Z .---||----+-------------------------> DISC_OP_AMP_OSCILLATOR_OUT_CAP + * Z r1 | | + * Z | |\ | + * | | | \ | |\ + * '-----+---|- \ | r3 | \ + * | >-+----ZZZZ----|- \ + * |+ / | >--+-----> DISC_OP_AMP_OSCILLATOR_OUT_SQW + * .---| / .--|+ / | + * | |/ r5 | | / | + * vP >-. | vP >--ZZZZ---+ |/ | + * | Z | | + * Z Z r2 | r4 | + * Z 1k Z '--ZZZZ---+ + * Z | | + * |\ | r6 | | + * Enable >---| >-+-ZZZZ---+-----------------------------' + * |/ O.C. + * + * Note: R1 - R5 can be nodes. + * + * EXAMPLES: see Polaris, Amazing Maze + * + * -------------------------------------------------- + * + * DISC_OP_AMP_OSCILLATOR_2 | DISC_OP_AMP_IS_NORTON + * Basic Norton Op Amp Oscillator circuit. + * + * .-------------------------------------------> DISC_OP_AMP_OSCILLATOR_OUT_CAP + * | + * | r1 + * +------ZZZZ-----. + * | | + * | r5 | + * +--ZZZZ---|>|---. + * | | + * | r6 | + * +--ZZZZ---|<|---. + * | | + * | |\ | + * | r2 | \ | + * +---ZZZZ--|- \ | + * | | >-+-------> DISC_OP_AMP_OSCILLATOR_OUT_SQW + * --- c |+ / | + * --- .---| / | + * | | |/ | + * gnd | | + * | r3 | + * +--ZZZZ---' + * | + * Z + * Z r4 + * Z + * | + * ^ + * vP + * + * Note: All values are static. + * + * EXAMPLES: see Space Walk, Blue Shark + * + *********************************************************************** + * + * DISCRETE_OP_AMP_VCOn - Various single power supply op-amp VCO circuits + * (n = 1 or 2) + * + * Declaration syntax + * + * DISCRETE_OP_AMP_VCOn(name of node, + * enable node or static value, + * modulation voltage 1 node or static value, + * modulation voltage 2 node or static value, [optional] + * address of dss_op_amp_osc_context structure) + * + * discrete_op_amp_osc_info = {type, r1, r2, r3, r4, r5, r6, r7, r8, c, vP} + * + * Note: Set all unused components to 0. + * _OUT_SQW can also be replaced with + * _OUT_ENERGY, _OUT_LOGIC_X, _OUT_COUNT_F_X, _OUT_COUNT_R_X + * + * Types: + * + * DISC_OP_AMP_OSCILLATOR_VCO_1 + * Basic Op Amp Voltage Controlled Oscillator circuit. + * Note that this circuit has only 1 modulation voltage. + * So it is used only with DISCRETE_OP_AMP_VCO1. + * + * c + * .------------------------+---||----+---------------------------> DISC_OP_AMP_OSCILLATOR_OUT_CAP + * | | | + * | | |\ | + * | r1 | | \ | |\ + * | vMod1 >--+--ZZZZ-------+---|- \ | | \ + * | | | >-+------------|- \ + * | | r2 |+ / | >--+-------> DISC_OP_AMP_OSCILLATOR_OUT_SQW + * Z '--ZZZZ--+--------| / .--|+ / | + * Z r6 | |/ r4 | | / | + * Z Z vP/2 >--ZZZZ---+ |/ | + * | Z r5 | | + * .----. Z | r3 | + * | sw |<--------. | '--ZZZZ---+ + * '----' | gnd | + * | | | + * gnd '----------------------------------------' + * + * Notes: The 'sw' block can be a transistor or 4066 switch. It connects + * r6 to ground when 'sw' is high. + * + * -------------------------------------------------- + * + * DISC_OP_AMP_OSCILLATOR_VCO_1 | DISC_OP_AMP_IS_NORTON + * Basic Norton Op Amp Voltage Controlled Oscillator circuit. + * When disabled, c discharges and sqw out goes high. + * + * .---------------------------> DISC_OP_AMP_OSCILLATOR_OUT_CAP + * c | + * r6 .---||----+ + * vP >--ZZZZ---. | | r5 |\ + * | | |\ | vP >--ZZZZ-. | \ + * r7 | r1 | | \ | '-|- \ + * vMod1 >--ZZZZ---+--ZZZZ-------+---|- \ | r3 | >--+-------> DISC_OP_AMP_OSCILLATOR_OUT_SQW + * | | >-+----ZZZZ----+--|+ / | + * r8 | r2 .----. |+ / | | / | + * vMod2 >--ZZZZ---+--ZZZZ---| sw |--| / | |/ | + * '----' |/ | | + * ^ ^ | r4 | + * | | '--ZZZZ---+ + * | | | + * Enable >---------' | | + * '--------------------------------' + * + * EXAMPLES: see Polaris + * + * -------------------------------------------------- + * + * DISC_OP_AMP_OSCILLATOR_VCO_2 | DISC_OP_AMP_IS_NORTON + * Basic Norton Op Amp Voltage Controlled Oscillator circuit. + * Note that this circuit has only 1 modulation voltage. + * So it is used only with DISCRETE_OP_AMP_VCO1. + * When vMod1 goes to 0V, the oscillator is disabled. + * c fully charges and the sqw out goes low. + * + * .---------------------------> DISC_OP_AMP_OSCILLATOR_OUT_CAP + * | + * | r4 + * c | .--ZZZZ--. + * .---||----+ | | + * | | r5 | |\ | + * | |\ | vP >--ZZZZ-+ | \ | + * r1 | | \ | '-|+ \ | + * vMod1 >--ZZZZ-----------------+---|- \ | r3 | >--+-------> DISC_OP_AMP_OSCILLATOR_OUT_SQW + * | >-+----ZZZZ-------|- / | + * r2 |+ / | / | + * vP >--ZZZZ-----------------+---| / |/ | + * | |/ | + * r6 .----. | | + * vP >--ZZZZ-----|-sw-|------' | + * '----' | + * ^ | + * | | + * '-----------------------------------------' + * + * EXAMPLES: see Double Play + * + * -------------------------------------------------- + * + * DISC_OP_AMP_OSCILLATOR_VCO_3 | DISC_OP_AMP_IS_NORTON + * Basic Norton Op Amp Voltage Controlled Oscillator circuit. + * + * + * c + * r7 .---||----+---------------------------> DISC_OP_AMP_OSCILLATOR_OUT_CAP + * vP >--ZZZZ---. | | + * | | |\ | + * r1 | | | \ | |\ + * vMod1 >--ZZZZ---+---------+---|- \ | r3 | \ + * | | >-+----ZZZZ----|- \ + * r6 | |+ / | >--+-------> DISC_OP_AMP_OSCILLATOR_OUT_SQW + * vMod2 >--ZZZZ---' .---| / .--|+ / | + * | |/ r5 | | / | + * vP >-. | vP >--ZZZZ---+ |/ | + * | Z | | + * Z Z r2 | r4 | + * Z 1k Z '--ZZZZ---+ + * Z | | + * |\ | r8 | | + * Enable >---| >-+-ZZZZ---+-----------------------------' + * |/ O.C. + * + * EXAMPLES: see Space Encounter, Blue Shark + * + *********************************************************************** + * + * DISCRETE_SCHMITT_OSCILLATOR - Schmitt Inverter gate oscillator + * + * rFeedback + * .---ZZZ----. .--< Amplitude + * | | | + * | |\ | .------. | + * rIn | | \ | 0/1 | AND/ | .-. + * INP0 >---ZZZ--+--|S >o---+----->|NAND/ |--->|*|-----> Netlist Node + * | | / | OR/ | '-' + * | |/ .->| NOR | + * --- | '------' + * --- C | + * | ^ + * gnd Enable + * + * Declaration syntax + * + * DISCRETE_SCHMITT_OSCILLATOR(name of node, + * enable node or static value, + * Input 0 node or static value, + * Amplitude node or static value, + * address of discrete_schmitt_osc_desc structure) + * + * discrete_schmitt_osc_desc = {rIn, rFeedback, c, trshRise, trshFall, vGate, options} + * + * Note: trshRise, trshFall, vGate can be replaced with one of these common types: + * DEFAULT_7414_VALUES or DEFAULT_74LS14_VALUES (the LS makes a difference) + * eg: {rIn, rFeedback, c, DEFAULT_7414_VALUES, options} + * + * Where: + * trshRise is the voltage level that triggers the gate input to go high (vGate) on rise. + * trshFall is the voltage level that triggers the gate input to go low (0V) on fall. + * vGate is the output high voltage of the gate that gets fedback through rFeedback. + * + * Input Options: + * DISC_SCHMITT_OSC_IN_IS_LOGIC (DEFAULT) + * DISC_SCHMITT_OSC_IN_IS_VOLTAGE + * + * Enable Options: (ORed with input options) + * DISC_SCHMITT_OSC_ENAB_IS_AND (DEFAULT) + * DISC_SCHMITT_OSC_ENAB_IS_NAND + * DISC_SCHMITT_OSC_ENAB_IS_OR + * DISC_SCHMITT_OSC_ENAB_IS_NOR + * + * EXAMPLES: see Fire Truck, Monte Carlo, Super Bug + * + *********************************************************************** + * + * DISCRETE_INVERTER_OSC - Inverter gate oscillator circuits + * + * TYPE 1/3 + * .----------------------------> Netlist Node (Type 3) + * | + * |\ | |\ |\ + * | \ | | \ | \ + * +--| >o--+--|-->o--+--| >o--+--------> Netlist Node (Type 1) + * | | / | / | | / | + * | |/ |/ | |/ | + * Z | | + * Z RP --- | + * Z --- C | + * | | R1 | + * '-------------------+----ZZZ--' + * + * TYPE 2 + * + * |\ |\ + * | \ | \ + * +--| >o--+--|-->o--+-------> Netlist Node + * | | / | | / | + * | |/ | |/ | + * Z Z | + * Z RP Z R1 --- + * Z Z --- C + * | | | + * '---------+---------' + * + * + * TYPE 4 / see vicdual + * + * |\ |\ + * | \ | \ + * Enable >-+-----+--|>o-+--|-->o--+-------> Netlist Node + * | | / | | / | + * | |/ | |/ | + * Z Z | + * Z RP Z R1 --- + * Z Z --- C + * | D | | + * '------|>|---+---------' + * | + * Mod >-----ZZZ------' + * R2 + * + * TYPE 5 / see vicdual + * Diode will cause inverted input behaviour and inverted output + * + * |\ |\ + * | \ | \ + * Enable >-+-----+--|>o-+--|-->o--+-------> Netlist Node + * | | / | | / | + * | |/ | |/ | + * Z Z | + * Z RP Z R1 --- + * Z Z --- C + * | D | | + * '------|<|---+---------' + * | + * Mod >-----ZZZ------' + * R2 + * + * Declaration syntax + * + * DISCRETE_INVERTER_OSC( name of node, + * enable node or static value, + * modulation node or static value (0 when not used), + * R1 static value, + * RP static value + * C static value, + * R2 static value (0 when not used), + * address of discrete_inverter_osc_desc structure) + * + * discrete_inverter_osc_desc = {vB, vOutLow, vOutHigh, vInRise, vInFall, clamp, options} + * + * Where + * vB Supply Voltage + * vOutLow Low Output voltage + * vOutHigh High Output voltage + * vInRise voltage that triggers the gate input to go high (vGate) on rise + * vInFall voltage that triggers the gate input to go low (0V) on fall + * clamp internal diode clamp: [-clamp ... vb+clamp] if clamp>= 0 + * options bitmaped options + * + * There is a macro DEFAULT_CD40XX_VALUES(_vB) which may be used to initialize the + * structure with .... = { 5, DEFAULT_CD40XX_VALUES(5), DISC_OSC_INVERTER_IS_TYPE1} + * + * The parameters are used to construct a input/output transfer function. + * + * Option Values + * + * DISC_OSC_INVERTER_IS_TYPE1 + * DISC_OSC_INVERTER_IS_TYPE2 + * DISC_OSC_INVERTER_IS_TYPE3 + * DISC_OSC_INVERTER_IS_TYPE4 + * DISC_OSC_INVERTER_OUT_IS_LOGIC + * + * EXAMPLES: see dkong + * + *********************************************************************** + ======================================================================= + * from from disc_wav.inc + * Not yet implemented + ======================================================================= + *********************************************************************** + * + * DISCRETE_ADSR_ENV - Attack Decay Sustain Release envelope generator + * + * Note: Not yet implemented. + * + * .------------. + * | | + * ENABLE -0------>| | + * | /\__ | + * TRIGGER -1------>| / \ |----> Netlist node + * | ADSR | + * GAIN -2------>| Env | + * | | + * '------------' + * + * Declaration syntax + * + * DISCRETE_ADSR_ENV (name of node, + * enable node or static value, + * envelope gain node or static value, + * envelope descriptor struct) + * + * Example config line + * + * DISCRETE_ADSR_ENV(NODE_3,1,NODE_21,1.0,&adsrdesc) + * + *********************************************************************** + ======================================================================= + * from from disc_mth.inc + * Generic modules + ======================================================================= + *********************************************************************** + * + * DISCRETE_ADDER - Node addition function, available in three + * lovely flavours, ADDER2,ADDER3,ADDER4 + * that perform a summation of incoming nodes + * + * .------------. + * | | + * INPUT0 -0------>| | + * | | + * INPUT1 -1------>| | | + * | -+- |----> Netlist node + * INPUT2 -2------>| | | + * | | + * INPUT3 -3------>| | + * | | + * '------------' + * + * Declaration syntax + * + * DISCRETE_ADDERx (name of node, + * (x=2/3/4) enable node or static value, + * input0 node or static value, + * input1 node or static value, + * input2 node or static value, [optional] + * input3 node or static value) [optional] + * + * Example config line + * + * DISCRETE_ADDER2(NODE_03,1,NODE_12,-2000) + * + * Always enabled, subtracts 2000 from the output of NODE_12 + * + *********************************************************************** + * + * DISCRETE_CLAMP - Force a signal to stay within bounds MIN/MAX + * + * .------------. + * | | + * INP0 -0------>| | + * | | + * MIN -1------>| CLAMP |----> Netlist node + * | | + * MAX -2------>| | + * | | + * '------------' + * + * Declaration syntax + * + * DISCRETE_CLAMP(name of node, + * input node, + * minimum node or static value, + * maximum node or static value), + * + * Example config line + * + * DISCRETE_CLAMP(NODE_9,NODE_10,2.0,10.0) + * + * Force the value on the node output, to be within the MIN/MAX + * boundary. In this example the output is clamped to the range + * of 2.0 to 10.0 inclusive. + * + * EXAMPLES: Sprint 8 + * + *********************************************************************** + * + * DISCRETE_DIVIDE - Node division function + * + * .------------. + * | | + * ENAB -0------>| | + * | o | + * INPUT1 -1------>| --- |----> Netlist node + * | o | + * INPUT2 -2------>| | + * | | + * '------------' + * + * Declaration syntax + * + * DISCRETE_DIVIDE (name of node, + * enable node or static value, + * input0 node or static value, + * input1 node or static value) + * + * Example config line + * + * DISCRETE_DIVIDE(NODE_03,1.0,NODE_12,50.0) + * + * Always enabled, divides the input NODE_12 by 50.0. Note that a + * divide by zero condition will give a LARGE number output, it + * will not stall the machine or simulation. It will also attempt + * to write a divide by zero error to the Mame log if enabled. + * + *********************************************************************** + * + * DISCRETE_BIT_DECODE - Decode a bit from value + * DISCRETE_BITS_DECODE - Decode a range of bits from value + * + * Declaration syntax + * + * DISCRETE_BIT_DECODE(name of node, + * input0 node or static value, + * bit number static value, + * output voltage (logic high) static value) + * + * Note: This module can decode x_time from counters, etc. + * If you set the output voltage to 0, then 0/1 with x_time will be output. + * Otherwise it will be used as energy based on the output voltage. + * + * Example config lines + * + * DISCRETE_BIT_DECODE(NODE_03,7,0,5) + * + * Node output is 5 + * + * DISCRETE_BIT_DECODE(NODE_03,7,3,5) + * + * Node output is 0 + * + * if the range variant is used, you may access the bits (up to 8) + * by using NODE_SUB, i.e. + * + * DISCRETE_BITS_DECODE(NODE_03,5,0,4,5) + * + * NODE_SUB(NODE_03, 0) = 5 + * NODE_SUB(NODE_03, 1) = 0 + * NODE_SUB(NODE_03, 2) = 5 + * NODE_SUB(NODE_03, 3) = 0 + * NODE_SUB(NODE_03, 4) = 0 + * + * EXAMPLES: galaxian, dkong, mario + * + *********************************************************************** + * + * DISCRETE_LOGIC_INVERT - Logic invertor + * DISCRETE_LOGIC_AND - Logic AND gate (3 & 4 input also available) + * DISCRETE_LOGIC_NAND - Logic NAND gate (3 & 4 input also available) + * DISCRETE_LOGIC_OR - Logic OR gate (3 & 4 input also available) + * DISCRETE_LOGIC_NOR - Logic NOR gate (3 & 4 input also available) + * DISCRETE_LOGIC_XOR - Logic XOR gate + * DISCRETE_LOGIC_XNOR - Logic NXOR gate + * + * .------------. + * | | + * INPUT0 -0------>| | + * | LOGIC | + * [INPUT1] -1------>| FUNCTION |----> Netlist node + * | !&|^ | + * [INPUT2] -2------>| | + * | | + * [INPUT3] -3------>| | + * | | + * [] - Optional '------------' + * + * Declaration syntax + * + * DISCRETE_LOGIC_XXXn(name of node, + * (X=INV/AND/etc) + * (n=Blank/2/3) input0 node or static value, + * [input1 node or static value], + * [input2 node or static value], + * [input3 node or static value]) + * + * Example config lines + * + * DISCRETE_LOGIC_INVERT(NODE_03,NODE_12) + * DISCRETE_LOGIC_AND(NODE_03,NODE_12,NODE_13) + * DISCRETE_LOGIC_NOR4(NODE_03,NODE_12,NODE_13,NODE_14,NODE_15) + * + * Node output is always either 0.0 or 1.0 any input value !=0.0 is + * taken as a logic 1. + * + *********************************************************************** + * + * DISCRETE_XTIME_BUFFER + * DISCRETE_XTIME_INVERTER + * DISCRETE_XTIME_AND + * DISCRETE_XTIME_NAND + * DISCRETE_XTIME_OR + * DISCRETE_XTIME_NOR + * DISCRETE_XTIME_XOR + * DISCRETE_XTIME_XNOR + * + * Declaration syntax + * + * DISCRETE_XTIME_xxx(name of node, + * (xxx=INV/AND/etc) + * input0 node or static value, + * [input1 node or static value], + * logic Low voltage (static value), + * logic High voltage (static value)) + * + * These modules all take 0/1 with x_time data and perform the logic + * while keeping and using the x_time anti-alaising data. + * If both logic Low and High are set to 0, the 0/1 + x_time data + * will be output. Otherwise the Low/High voltages will be used + * to convert the x_time to energy. + * + * EXAMPLES: see Mario Bros.; Donkey Kong Jr + * + *********************************************************************** + * + * DISCRETE_LOGIC_DFLIPFLOP - Standard D-type flip-flop. + * Changes on rising edge of clock. + * + * /SET -2 ------------. + * v + * .-----o------. + * | | + * DATA -4 ----->| | + * | FLIPFLOP | + * | Q|----> Netlist node + * | | + * CLOCK -3 ----->| | + * | | + * '-----o------' + * ^ + * /RESET -1 ------------' + * + * Declaration syntax + * + * DISCRETE_LOGIC_DFLIPFLOP(name of node, + * reset node or static value, + * set node or static value, + * clock node, + * data node or static value) + * + * Example config line + * + * DISCRETE_LOGIC_DFLIPFLOP(NODE_7,NODE_17,0,NODE_13,1) + * + * A flip-flop that clocks a logic 1 through on the rising edge of + * NODE_13. A logic 1 on NODE_17 resets the output to 0. + * + * EXAMPLES: see Hit Me, Polaris + * + *********************************************************************** + * + * DISCRETE_LOGIC_JKFLIPFLOP - Standard JK-type flip-flop. + * Changes on falling edge of clock. + * + * /SET -2 ------------. + * v + * .-----o------. + * | | + * J -4 ----->| | + * | FLIPFLOP | + * CLOCK -3 ----->| Q|----> Netlist node + * | | + * K -5 ----->| | + * | | + * '-----o------' + * ^ + * /RESET -1 ------------' + * + * Declaration syntax + * + * DISCRETE_LOGIC_JKFLIPFLOP(name of node, + * reset node or static value, + * set node or static value, + * clock node, + * J node or static value, + * K node or static value) + * + * EXAMPLES: see Amazing Maze + * + *********************************************************************** + * + * DISCRETE_LOOKUP_TABLE - returns the value in a table + * + * Declaration syntax + * + * DISCRETE_LOOKUP_TABLE(name of node, + * address node, + * size of table static value, + * address of table of double values) + * + *********************************************************************** + * + * DISCRETE_MULTIPLEX - 1 of 2/4/8 multiplexer + * + * .-------------. + * Input 0 >-----|>-<. | + * | \ | + * Input 1 >-----|>- \ | + * | \ | + * Input 2 >-----|>- |\ | + * | | \ | + * Input 3 >-----|>- | o-->|------> Netlist Node + * | | | + * Input 4 >-----|>- | | + * | | | + * Input 5 >-----|>- '------|----< Address + * | | (0 shown) + * Input 6 >-----|>- | + * | | + * Input 7 >-----|>- | + * '-------------' + * + * Declaration syntax + * + * DISCRETE_MULTIPLEXx(name of node, + * (x=2/4/8) address node, + * input 0 node or static value, + * input 1 node or static value, ...) + * + *********************************************************************** + * + * DISCRETE_LOGIC_SHIFT - shift register + * + * Declaration syntax + * + * DISCRETE_LOGIC_SHIFT(name of node, + * input node, + * reset node or static value, + * clock node or static value, + * size static value, + * options static value) + * + * Options: + * reset type: DISC_LOGIC_SHIFT__RESET_L + * DISC_LOGIC_SHIFT__RESET_H + * shift type: DISC_LOGIC_SHIFT__LEFT + * DISC_LOGIC_SHIFT__RIGHT + * clock type: DISC_CLK_ON_F_EDGE - toggle on falling edge. + * DISC_CLK_ON_R_EDGE - toggle on rising edge. + * DISC_CLK_BY_COUNT - toggle specified number of times. + * DISC_CLK_IS_FREQ - internally clock at this frequency. + * + * EXAMPLES: see Sky Raider + * + *********************************************************************** + * + * DISCRETE_GAIN - Node multiplication function output is equal + * DISCRETE_MULTIPLY to INPUT0 * INPUT1 + * DISCRETE_MULTADD to (INPUT0 * INPUT1) + INPUT 2 + * + * .------------. + * | | + * INPUT0 -1------>| \|/ | + * | -+- |----> Netlist node + * INPUT1 -2------>| /|\ | + * | | + * INPUT2 -3------>| | + * | | + * '------------' + * + * Declaration syntax + * + * DISCRETE_MULTIPLY (name of node, + * input0 node or static value, + * input1 node or static value) + * + * DISCRETE_MULTADD (name of node, + * input0 node or static value, + * input1 node or static value, + * input2 node or static value) + * + * DISCRETE_GAIN (name of node, + * input0 node or static value, + * static value for gain) + * Example config line + * + * DISCRETE_GAIN(NODE_03,NODE_12,112.0) + * + * Always enabled, multiplies the input NODE_12 by 112.0 + * + *********************************************************************** + * + * DISCRETE_ONESHOT - Monostable multivibrator, no reset + * DISCRETE_ONESHOTR - Monostable multivibrator, with reset + * + * Declaration syntax + * + * DISCRETE_ONESHOT (name of node, + * trigger node, + * amplitude node or static value, + * width (in seconds) node or static value, + * type of oneshot static value) + * + * DISCRETE_ONESHOTR (name of node, + * reset node or static value, + * trigger node, + * amplitude node or static value, + * width (in seconds) node or static value, + * type of oneshot static value) + * + * Types: + * + * DISC_ONESHOT_FEDGE 0x00 - trigger on falling edge (DEFAULT) + * DISC_ONESHOT_REDGE 0x01 - trigger on rising edge + * + * DISC_ONESHOT_NORETRIG 0x00 - non-retriggerable (DEFAULT) + * DISC_ONESHOT_RETRIG 0x02 - retriggerable + * + * DISC_OUT_ACTIVE_LOW 0x04 - output active low + * DISC_OUT_ACTIVE_HIGH 0x00 - output active high (DEFAULT) + * + * NOTE: A width of 0 seconds will output a pulse of 1 sample. + * This is useful for a guaranteed minimun pulse, regardless + * of the sample rate. + * + * EXAMPLES: see Polaris + * + *********************************************************************** + * + * DISCRETE_RAMP - Ramp up/down circuit with clamps & reset + * + * .------------. + * | | + * ENAB -0------>| FREE/CLAMP | + * | | + * RAMP -1------>| FW/REV | + * | | + * GRAD -2------>| Grad/sec | + * | |----> Netlist node + * START -3------>| Start clamp| + * | | + * END -4------>| End clamp | + * | | + * CLAMP -5------>| off clamp | + * | | + * '------------' + * + * Declaration syntax + * + * DISCRETE_RAMP(name of node, + * enable, + * ramp forward/reverse node (or value), + * gradient node (or static value), + * start node or static value, + * end node or static value, + * clamp node or static value when disabled) + * + * Example config line + * + * DISCRETE_RAMP(NODE_9,NODE_10,NODE_11,10.0,-10.0,10.0,0) + * + * Node10 when not zero will allow ramp to operate, when 0 then output + * is clamped to clamp value specified. Node11 ramp when 0 change + * gradient from start to end. 1 is reverse. Output is clamped to max- + * min values. Gradient is specified in change/second. + * + *********************************************************************** + * + * DISCRETE_SAMPHOLD - Sample & Hold circuit + * + * .------------. + * | | + * ENAB -0------>| | + * | | + * INP0 -1------>| SAMPLE | + * | & |----> Netlist node + * CLOCK -2------>| HOLD | + * | | + * CLKTYPE -3------>| | + * | | + * '------------' + * + * Declaration syntax + * + * DISCRETE_SAMPHOLD(name of node, + * enable, + * input node, + * clock node or static value, + * input clock type) + * + * Example config line + * + * DISCRETE_SAMPHOLD(NODE_9,1,NODE_11,NODE_12,DISC_SAMPHOLD_REDGE) + * + * Node9 will sample the input node 11 on the rising edge (REDGE) of + * the input clock signal of node 12. + * + * DISC_SAMPHOLD_REDGE - Rising edge clock + * DISC_SAMPHOLD_FEDGE - Falling edge clock + * DISC_SAMPHOLD_HLATCH - Output is latched whilst clock is high + * DISC_SAMPHOLD_LLATCH - Output is latched whilst clock is low + * + *********************************************************************** + * + * DISCRETE_SWITCH - Node switch function, output node is switched + * by switch input to take one node/contst or + * other. Can be nodes or constants. + * + * SWITCH -0--------------. + * V + * .------------. + * | | | + * INPUT0 -1------}|----o | + * | .--- |----> Netlist node + * INPUT1 -2------>|----o / | + * | | + * '------------' + * + * Declaration syntax + * + * DISCRETE_SWITCH (name of node, + * enable node or static value, + * switch node or static value, + * input0 node or static value, + * input1 node or static value) + * + * Example config line + * + * DISCRETE_SWITCH(NODE_03,1,NODE_10,NODE_90,5.0) + * + * Always enabled, NODE_10 switches output to be either NODE_90 or + * constant value 5.0. Switch==0 inp0=output else inp1=output + * + *********************************************************************** + * + * DISCRETE_ASWITCH - Node switch function, output node is same + * as input when CTRL is above threshold. + * + * CTRL -0--------------. + * V + * .------------. + * | | | + * INPUT0 -1------ |----- . --- |----> Netlist node + * | | + * | | + * '------------' + * + * Declaration syntax + * + * DISCRETE_ASWITCH (name of node, + * ctrl node or static value, + * input node or static value, + * threshold satic value ) + * + * Example config line + * + * DISCRETE_ASWITCH(NODE_03,NODE_10,NODE_90, 2.73) + * + * Always enabled, NODE_10 switches output to be either NODE_90 or + * constant value 0.0. Ctrl>2.73 output=NODE_90 else output=0 + * + *********************************************************************** + * + * DISCRETE_TRANSFORMn - Node arithmatic logic (postfix arithmatic) + * (n=2,3,4,5) + * .------------. + * | | + * INPUT0 -0------>| | + * | | + * INPUT1 -1------>| Postfix | + * | stack |----> Netlist node + * INPUT2 -2------>| maths | + * | | + * INPUT3 -3------>| | + * | | + * INPUT4 -4------>| | + * | | + * '------------' + * + * Declaration syntax + * + * DISCRETE_TRANSFORMn(name of node, + * input0 node or static value, + * input1 node or static value, + * input2 node or static value, [optional] + * input3 node or static value, [optional] + * input4 node or static value, [optional] + * maths string) + * + * Example config line + * + * DISCRETE_TRANSFORM4(NODE_12,NODE_22,50.0,120.0,33.33,"01*2+3/") + * + * Arithmetic uses stack based arithmetic similar to Forth, the maths + * has 5 registers 0-4 and various arithmetic operations. The math + * string is processed from left to right in the following manner: + * 0 - Push input 0 to stack + * 1 - Push input 1 to stack + * 2 - Push input 2 to stack + * 3 - Push input 3 to stack + * 4 - Push input 4 to stack + * - - Pop two values from stack, subtract and push result to stack + * + - Pop two values from stack, add and push result to stack + * / - Pop two values from stack, divide and push result to stack + * * - Pop two values from stack, multiply and push result to stack + * a - Pop one value from stack, multiply -1 if less than 0 and push result to stack + * i - Pop one value from stack, multiply -1 and push result to stack + * ! - Pop one value from stack, logical invert, push result to stack + * = - Pop two values from stack, logical = and push result to stack + * > - Pop two values from stack, logical > and push result to stack + * < - Pop two values from stack, logical < and push result to stack + * & - Pop two values from stack, binary AND and push result to stack + * | - Pop two values from stack, binary OR and push result to stack + * ^ - Pop two values from stack, binary XOR and push result to stack + * P - Push a duplicate of the last stack value back on the stack + * + * EXAMPLES: see Polaris + * + *********************************************************************** + ======================================================================= + * from from disc_mth.inc + * Component specific modules + ======================================================================= + *********************************************************************** + * + * DISCRETE_COMP_ADDER - Selecatable parallel component adder. + * The total netlist out will be the parallel sum of all + * components with their corresponding data bit = 1. + * Set cDefault to 0 if not used. + * + * common >---cDefault---. + * data&0x01 >-----c[0]-----+ + * data&0x02 >-----c[1]-----+ + * data&0x04 >-----c[2]-----+ + * data&0x08 >-----c[3]-----+-----> netlist node + * data&0x10 >-----c[4]-----+ + * data&0x20 >-----c[5]-----+ + * data&0x40 >-----c[6]-----+ + * data&0x80 >-----c[7]-----' + * + * Declaration syntax + * + * DISCRETE_COMP_ADDER(name of node, + * data node (static value is useless), + * address of discrete_comp_adder_table structure) + * + * discrete_comp_adder_table = {type, cDefault, length, c{}} + * note: length can be a maximum of 8 + * + * Circuit Types: + * DISC_COMP_P_CAPACITOR - parallel capacitors + * DISC_COMP_P_RESISTOR - parallel resistors + * + * EXAMPLES: see Hit Me + * + *********************************************************************** + * + * DISCRETE_DAC_R1 - R1 ladder DAC with cap smoothing and external bias + * + * rBias + * data&0x01 >--/\R[0]/\--+-----/\/\----< vBias + * data&0x02 >--/\R[1]/\--| + * data&0x04 >--/\R[2]/\--| + * data&0x08 >--/\R[3]/\--| + * data&0x10 >--/\R[4]/\--| + * data&0x20 >--/\R[5]/\--| + * data&0x40 >--/\R[6]/\--| + * data&0x80 >--/\R[7]/\--+-------------+-----> Netlist node + * | | + * Z --- + * Z rGnd --- cFilter + * | | + * gnd gnd + * + * NOTES: rBias and vBias are used together. If not needed they should + * be set to 0. If used, they should both have valid values. + * rGnd and cFilter should be 0 if not needed. + * A resistor value should be properly set for each resistor + * up to the ladder length. Remember 0 is a short circuit. + * The data node is bit mapped to the ladder. valid int 0-255. + * TTL logic 0 is actually 0.2V but 0V is used. The other parts + * have a tolerance that more then makes up for this. + * + * Declaration syntax + * + * DISCRETE_DAC_R1(name of node, + * data node (static value is useless), + * vData static value (voltage when a bit is on ), + * address of discrete_dac_r1_ladder structure) + * + * discrete_dac_r1_ladder = {ladderLength, r{}, vBias, rBias, rGnd, cFilter} + * + * Note: Resistors in the ladder that are set to 0, will be handled like they + * are out of circuit. So the bit selecting them will have no effect + * on the DAC output voltage. + * + * x_time - this modules automatically handles any non-integer value + * on the data input as x_time. + * + * EXAMPLES: see Fire Truck, Monte Carlo, Super Bug, Polaris + * + *********************************************************************** + * + * DISCRETE_DIODE_MIXER - mixes inputs through diodes + * + * + * input 0 >----|>|---. + * | + * input 1 >----|>|---+----------> Netlist Node + * | + * input 2 >----|>|---+ + * | + * input 3 >----|>|---+--/\/\/\--. + * | + * gnd + * + * Declaration syntax + * + * DISCRETE_DIODE_MIXERx(name of node, + * (x = 2/3/4) input 0 node, + * input 1 node, + * ..., + * address of v_junction table) + * + * v_junction table can be set to NULL if you want all diodes to + * default to a 0.5V drop. Otherwise use a + * table of doubles to specify juntion voltages. + * + * EXAMPLES: see dkong + * + *********************************************************************** + * + * DISCRETE_INTEGRATE - Various Integration circuits + * + * Declaration syntax + * + * DISCRETE_INTEGRATE(name of node, + * trigger 0 node or static value, + * trigger 1 node or static value, + * address of discrete_integrate_info) + * + * discrete_integrate_info = {type, r1, r2, r3, c, v1, vP, f0, f1, f2} + * + * Note: Set all unused components to 0. + * These are all single supply circuits going from gnd(0V) to vP(B+), + * so be sure to specify the vP power source. + * + * Types: + * + * DISC_INTEGRATE_OP_AMP_1 + * + * v1 >----+-------. + * | | c + * Z Z .---||----. + * Z r1 Z r2 | | + * Z Z | |\ | + * | | | | \ | + * +--------------+--|- \ | + * | | | >--+----> Netlist Node + * / +---------|+ / + * |/ | | / + * Trig0 >--| NPN Z |/ + * |\ Z r3 + * > Z + * | | + * gnd gnd + * + * + * EXAMPLES: see Tank8 + * + * -------------------------------------------------- + * + * DISC_INTEGRATE_OP_AMP_1 | DISC_OP_AMP_IS_NORTON + * + * c + * .---||----. + * | | + * | |\ | + * r1 | | \ | + * v1 >----ZZZZ--------+--|- \ | + * | >--+----> Netlist Node + * r2 .--|+ / + * Trig0 >----ZZZZ--------' | / + * |/ + * + * Note: Trig0 is voltage level, not logic. + * No functions are used so set them to 0, or DISC_OP_AMP_TRIGGER_FUNCTION_NONE. + * You can also use DISCRETE_OP_AMP with type DISC_OP_AMP_IS_NORTON to emulate this. + * + * EXAMPLES: see Double Play + * + * -------------------------------------------------- + * + * DISC_INTEGRATE_OP_AMP_2 | DISC_OP_AMP_IS_NORTON + * + * c + * .---||----. + * r1a | | + * v1 >----ZZZZ---. | |\ | + * .----. | r1b Diode | | \ | + * | F0 |--+--ZZZZ----|>|--+--|- \ | + * '----' | >--+----> Netlist Node + * r2a r2b .--|+ / + * v1 >----ZZZZ---+--ZZZZ---------+ | / + * .----. | | |/ + * | F1 |--' | + * '----' | + * r3a r3b Diode | + * v1 >----ZZZZ---+--ZZZZ----|>|--' + * .----. | + * | F2 |--' + * '----' + * + * Note: For an explanation of the functions and trigger inputs, + * see DISCRETE_OP_AMP_TRIG_VCA below. + * + * EXAMPLES: see Polaris + * + *********************************************************************** + * + * DISCRETE_MIXER - Mixes multiple input signals. + * + * Declaration syntax + * + * DISCRETE_MIXERx(name of node, + * (x = 2 to 8) enable node or static value, + * input 0 node, + * input 1 node, + * input 2 node, (if used) + * input 3 node, (if used) + * input 4 node, (if used) + * input 5 node, (if used) + * input 6 node, (if used) + * input 7 node, (if used) + * address of discrete_mixer_info structure) + * + * discrete_mixer_desc = {type, r{}, r_node{}, c{}, rI, rF, cF, cAmp, vRef, gain} + * + * Note: Set all unused components to 0. + * If an rNode is not used it should also be set to 0. + * + * Types: + * + * DISC_MIXER_IS_RESISTOR + * + * rNode[0] r[0] c[0] + * IN0 >--zzzz-----zzzz----||---. + * | + * rNode[1] r[1] c[1] | + * IN1 >--zzzz-----zzzz----||---+--------. + * . . . . | | cAmp + * . . . . | Z<------||---------> Netlist Node + * . . . . | Z + * . rNode[7] r[7] c[7] | Z rF + * IN7 >--zzzz-----zzzz----||---+ | + * | | + * --- | + * cF --- | + * | | + * gnd gnd + * + * Note: The variable resistor is used in it's full volume position. + * MAME's built in volume is used for adjustment. + * + * EXAMPLES: see Polaris, Super Bug + * + * -------------------------------------------------- + * + * DISC_MIXER_IS_OP_AMP + * + * cF + * .----||---. + * | | + * rNode[0] r[0] c[0] | rF | + * IN0 >--zzzz------zzzz----||---. +---ZZZZ--+ + * | | | + * rNode[1] r[1] c[1] | rI | |\ | + * IN1 >--zzzz------zzzz----||---+--zzzz--+ | \ | + * . . . . | '--|- \ | cAmp + * . . . . | | >--+---||-----> Netlist Node + * . . . . | .--|+ / + * . rNode[7] r[7] c[7] | | | / + * IN7 >--zzzz------zzzz----||---' | |/ + * | + * vRef >----------------------------------' + * + * Note: rI is not always used and should then be 0. + * + * EXAMPLES: see Fire Truck, Monte Carlo + * + *********************************************************************** + * + * DISCRETE_OP_AMP - Various op-amp circuits + * + * Declaration syntax + * + * DISCRETE_OP_AMP(name of node, + * enable node or static value, + * input 0 node or static value, + * input 1 node or static value, + * address of discrete_op_amp_info structure) + * + * discrete_op_amp_info = {type, r1, r2, r3, r4, c, vN, vP} + * + * Note: Set all unused components to 0. + * + * Types: + * + * DISC_OP_AMP_IS_NORTON + * + * c + * .----||---. + * | | + * r3 | r4 | vP = B+ + * vP >---ZZZZ------+---ZZZZ--+ vN = B- + * | | + * r1 | |\ | Note: r2 must always be used + * IN0 >---ZZZZ------+ | \ | + * '--|- \ | + * r2 | >--+-----> Netlist Node + * IN1 >---ZZZZ---------|+ / + * | / + * |/ + * + * EXAMPLES: see Space Encounter + * + *********************************************************************** + * + * DISCRETE_OP_AMP_ONESHOT - Various op-amp one shot circuits + * + * Declaration syntax + * + * DISCRETE_OP_AMP_ONESHOT(name of node, + * trigger node (voltage level), + * address of discrete_op_amp_1sht_info structure) + * + * discrete_op_amp_1sht_info = {type, r1, r2, r3, r4, r5, c1, c2, vN, vP} + * + * Types: + * + * DISC_OP_AMP_1SHT_1 | DISC_OP_AMP_IS_NORTON + * + * c1 .---|>|---. + * gnd >----||---+---+ | + * | | r4 | vP = B+ + * Z '---ZZZZ--+ vN = B- + * Z r3 | + * Z |\ | Note: all components must be used + * r1 | | \ | The oneshot is cancelled when TRIG goes low + * vP >---ZZZZ--+------|- \ | + * | >--+-----> Netlist Node + * c2 r2 .--|+ / | + * TRIG >--||---ZZZZ--+ | / | + * | |/ | + * | r5 | + * '---ZZZZ--' + * + * + * EXAMPLES: see Space Encounter + * + *********************************************************************** + * + * DISCRETE_OP_AMP_TRIG_VCA - Triggered Norton op amp voltage controlled amplifier. + * This means the cap is rapidly charged through r5 when F2=1. + * Then it discharges through r6+r7 when F2=0. + * This voltage controls the amplitude. + * While the diagram looks complex, usually only parts of it are used. + * + * Declaration syntax + * + * DISCRETE_OP_AMP_TRIG_VCA(name of node, + * trigger 0 node or static value, + * trigger 1 node or static value, + * trigger 2 node or static value, + * input 0 node or static value, + * input 1 node or static value, + * address of discrete_op_amp_tvca_info structure) + * + * discrete_op_amp_tvca_info = { r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, c1, c2, c3, c4, v1, v2, v3, vP, f0, f1, f2, f3, f4, f5} + * + * Note: Set all unused components to 0. + * Set all unused functions to DISC_OP_AMP_TRIGGER_FUNCTION_NONE + * Set all unused nodes to NODE_NC. + * If function F3 is not used then set r6=0 and use only r7. + * r2 = r2a + r2b. r3 = r3a + r3b. + * vP is the op-amp B+. + * + * r2a + * IN0 >----ZZZZ-----. r1 c4 + * .----. | vP >------ZZZZ---+---||----. + * | F0 |----+ | | + * '----' | r2b | r4 | + * r3a '---------------ZZZZ---+---ZZZZ--+ + * IN1 >----ZZZZ---. | | + * .----. | r3b | |\ | + * | F1 |--+-----------------ZZZZ---+ | \ | + * '----' '--|- \ | + * .----. diode r6 r7 | >--+----> Netlist Node + * | F2 |--+--|>|--+--ZZZZ---+--ZZZZ-+-|+ / + * '----' | | | | | / + * | --- .----. | |/ + * r5 | --- c1 | F3 | | + * v1 >----ZZZZ---' | '----' | + * gnd | + * | + * .----. diode r9 | + * | F4 |--+--|>|-----------+---ZZZZ-+ + * '----' | c2 | | + * r8 | gnd >---||---' | + * v2 >----ZZZZ---' | + * .----. diode r11 | + * | F5 |--+--|>|-----------+---ZZZZ-' + * '----' | c3 | + * r10 | gnd >---||---' + * v3 >----ZZZZ---' + * + * Function types: + * + * Trigger 0, 1 and 2 are used for the functions F0 - F5. + * When the output of the function is 0, then the connection is held at 0V or gnd. + * When the output of the function is 1, then the function is an open circuit. + * + * DISC_OP_AMP_TRIGGER_FUNCTION_NONE - Not used, cicuit open. + * DISC_OP_AMP_TRIGGER_FUNCTION_TRG0 - Gnd when trigger 0 is 0. + * DISC_OP_AMP_TRIGGER_FUNCTION_TRG0_INV - Gnd when trigger 0 is 1. + * DISC_OP_AMP_TRIGGER_FUNCTION_TRG1 - Gnd when trigger 1 is 0. + * DISC_OP_AMP_TRIGGER_FUNCTION_TRG1_INV - Gnd when trigger 1 is 1. + * DISC_OP_AMP_TRIGGER_FUNCTION_TRG2 - Gnd when trigger 2 is 0. + * DISC_OP_AMP_TRIGGER_FUNCTION_TRG2_INV - Gnd when trigger 2 is 1. + * DISC_OP_AMP_TRIGGER_FUNCTION_TRG01_AND - Gnd when trigger 0 or 1 are 0. + * DISC_OP_AMP_TRIGGER_FUNCTION_TRG01_NAND - Gnd when trigger 0 and 1 are 1. + * + * EXAMPLES: see Polaris + * + *********************************************************************** + ======================================================================= + * from from disc_flt.inc + * Generic modules + ======================================================================= + *********************************************************************** + * + * DISCRETE_FILTER1 + * + * Declaration syntax + * + * DISCRETE_FILTER1(name of node, + * enable node or static value, + * input node, + * filter center frequency static value, + * filter type static value) + * + * Filter types: DISC_FILTER_LOWPASS, + * DISC_FILTER_HIGHPASS + * DISC_FILTER_BANDPASS + * + *********************************************************************** + * + * DISCRETE_FILTER2 + * + * Declaration syntax + * + * DISCRETE_FILTER2(name of node, + * enable node or static value, + * input node, + * filter center frequency static value, + * damp static value, + * filter type static value) + * + * Filter types: DISC_FILTER_LOWPASS, + * DISC_FILTER_HIGHPASS + * DISC_FILTER_BANDPASS + * + * Note: Damp = 1/Q + * + *********************************************************************** + ======================================================================= + * from from disc_flt.inc + * Component specific modules + ======================================================================= + *********************************************************************** + * + * DISCRETE_CRFILTER - Simple single pole CR filter network (vRef = 0) + * DISCRETE_CRFILTER_VREF - Same but referenced to vRef not 0V + * + * .------------. + * | | + * | CR FILTER | + * | | + * INPUT1 -0------}| --| |-+-- | + * | C | |----} Netlist node + * RVAL -1------}| Z | + * | Z R | + * CVAL -2------}| | | + * | vRef | + * '------------' + * + * Declaration syntax + * + * DISCRETE_CRFILTER(name of node, + * input node (or value) + * resistor node or static value in OHMS + * capacitor node or static value in FARADS) + * + * DISCRETE_CRFILTER_VREF(name of node, + * input node (or value) + * resistor value in OHMS + * capacitor value in FARADS, + * vRef node or static value) + * + * Example config line + * + * DISCRETE_CRFILTER(NODE_11,NODE_10,100,CAP_U(1)) + * + * Defines a CR filter with a 100R & 1uF network + * the input is fed from NODE_10. + * + * This can be also thought of as a high pass filter with a 3dB cutoff + * at: + * 1 + * Fcuttoff = -------------- + * 2*Pi*RVAL*CVAL + * + * (3dB cutoff is where the output power has dropped by 3dB ie Half) + * + *********************************************************************** + * + * DISCRETE_OP_AMP_FILTER - Various Op Amp Filters. + * + * Declaration syntax + * + * DISCRETE_OP_AMP_FILTER(name of node, + * enable node or static value, + * input 1 node or static value, + * input 2 node or static value, + * type static value, + * address of discrete_op_amp_filt_info) + * + * discrete_op_amp_filt_info = {r1, r2, r3, r4, rF, c1, c2, c3, vRef, vP, vN} + * + * Note: Set all unused components to 0. + * vP and vN are the +/- op-amp power supplies. + * vRef is 0 if Gnd. + * + * Types: + * + * DISC_OP_AMP_FILTER_IS_LOW_PASS_1 + * First Order Low Pass Filter + * + * c1 + * .-------||---------. + * | | + * r1 | rF | + * IN0 >--ZZZZ--. +------ZZZZ--------+ + * | | | + * r2 | | |\ | + * IN1 >--ZZZZ--+------+--------+ | \ | + * | '--|- \ | + * r3 | | >--+----------> Netlist Node + * vRef >--ZZZZ--' .--|+ / + * | | / + * vRef >-----------------------' |/ + * + * -------------------------------------------------- + * + * DISC_OP_AMP_FILTER_IS_LOW_PASS_1_A + * First Order Low Pass Filter + * + * c1 + * .-------||---------. + * | | + * r1 | rF | + * IN0 >--ZZZZ--. +------ZZZZ--------+ + * | | | + * r2 | | |\ | + * VP >--ZZZZ--+------+--------+ | \ | + * | '--|- \ | + * r3 | | >--+----------> Netlist Node + * VN >--ZZZZ--' .--|+ / + * | | / + * IN1 >------------------------' |/ + * + * -------------------------------------------------- + * + * DISC_OP_AMP_FILTER_IS_HIGH_PASS_1 + * First Order High Pass Filter + * + * r1 rF + * IN0 >--ZZZZ--. .------ZZZZ--------. + * | | | + * r2 | c1 | |\ | + * IN1 >--ZZZZ--+--||--+--------+ | \ | + * | '--|- \ | + * r3 | | >--+----------> Netlist Node + * vRef >--ZZZZ--' .--|+ / + * | | / + * vRef >-----------------------' |/ + * + * -------------------------------------------------- + * + * DISC_OP_AMP_FILTER_IS_BAND_PASS_1 + * First Order Band Pass Filter + * + * c1 + * .-------||---------. + * | | + * r1 | rF | + * IN0 >--ZZZZ--. +------ZZZZ--------+ + * | | | + * r2 | c2 | |\ | + * IN1 >--ZZZZ--+--||--+--------+ | \ | + * | '--|- \ | + * r3 | | >--+----------> Netlist Node + * vRef >--ZZZZ--' .--|+ / + * | | / + * vRef >-----------------------' |/ + * + * -------------------------------------------------- + * + * DISC_OP_AMP_FILTER_IS_BAND_PASS_1M + * Single Pole Multiple Feedback Band Pass Filter + * + * c1 + * .--||----+---------. + * | | | + * r1 | Z | + * IN0 >--ZZZZ--. | Z rF | + * | | Z | + * r2 | | c2 | |\ | + * IN1 >--ZZZZ--+------+--||----+ | \ | + * | '--|- \ | + * r3 | | >--+----------> Netlist Node + * vRef >--ZZZZ--' .--|+ / + * | | / + * vRef >-----------------------' |/ + * + * EXAMPLES: see Tank 8, Atari Baseball, Monte Carlo + * + * -------------------------------------------------- + * + * DISC_OP_AMP_FILTER_IS_BAND_PASS_1M | DISC_OP_AMP_IS_NORTON + * Single Pole Multiple Feedback Band Pass Filter + * + * c1 + * .--||----+---------. + * | | | + * | Z | + * | Z rF | + * | Z | + * r1 | c2 | |\ | + * IN0 >--ZZZZ--+------+--||----+ | \ | + * | '--|- \ | + * r2 | | >--+----------> Netlist Node + * vRef >--ZZZZ--' .--|+ / + * r3 | | / + * vP >-----------ZZZZ--------' |/ + * + * EXAMPLES: see Space Encounter + * + * -------------------------------------------------- + * + * DISC_OP_AMP_FILTER_IS_HIGH_PASS_0 | DISC_OP_AMP_IS_NORTON + * Basic Norton High Pass Filter + * + * rF + * r1 = r1a + r1b .--ZZZZ---. + * | | + * r1a c1 r1b | |\ | + * IN1 >--ZZZZ---||---ZZZZ------+ | \ | + * '--|- \ | + * | >--+----------> Netlist Node + * .--|+ / + * r4 | | / + * vRef >------------ZZZZ-------' |/ + * + * EXAMPLES: see Polaris + * + * -------------------------------------------------- + * + * DISC_OP_AMP_FILTER_IS_BAND_PASS_0 | DISC_OP_AMP_IS_NORTON + * Basic Norton Band Pass Filter + * + * rF + * r3 = r3a + r3b .--ZZZZ---. + * | | + * r1 r2 r3a c3 r3b | |\ | + * IN1 >---ZZZZ--+--ZZZZ--+--ZZZZ---||----ZZZZ---+ | \ | + * | | '--|- \ | + * --- --- | >--+---> Netlist Node + * --- c1 --- c2 .--|+ / + * | | | | / + * gnd gnd | |/ + * r4 | + * vRef >--------------------------------ZZZZ----' + * + * EXAMPLES: see Polaris + * + *********************************************************************** + * + * DISCRETE_SALLEN_KEY_FILTER - Sallen key low pass filter + * + * Declaration syntax + * + * DISCRETE_SALLEN_KEY_FILTER(name of node, + * enable node or static value, + * input node or static value, + * type static value, + * address of discrete_op_amp_filt_info) + * + * discrete_op_amp_filt_info = {r1, r2, r3, r4, rF, c1, c2, c3, vRef, vP, vN} + * + * Note: Set all unused components to 0. + * + * Types: + * + * DISC_SALLEN_KEY_LOWPASS + * + * .---------. + * | | + * | |\ | + * | | \ | + * `--|- \ | + * R1 R2 | >--+----> Netlist Node + * IN >---ZZZZ--+--ZZZZ--+------|+ / | + * | | | / | + * --- --- |/ | + * --- C1 --- C2 | + * | | | + * | gnd | + * | | + * `----------------------' + * + * EXAMPLES: see moon patrol, dkong + * + * References: + * http://www.t-linespeakers.org/tech/filters/Sallen-Key.html + * http://en.wikipedia.org/wiki/Sallen_Key_filter + *********************************************************************** + * + * DISCRETE_RC_CIRCUIT_1 - RC charge/discharge circuit + * + * Declaration syntax + * + * DISCRETE_RC_CIRCUIT_1(name of node, + * In0 (Logic) node, + * In1 (Logic) node, + * R static value, + * C static value) + * + * 5V + * v + * | + * .-------. + * | 4066 | + * In0 >---|c | + * '-------' + * | + * +------------. + * | | + * .-------. --- C + * | 4066 | --- + * In1 >---|c | | + * '-------' gnd + * | + * +----> Node Output + * | + * Z + * Z R + * Z + * | + * gnd + * + * EXAMPLES: see Sky Raider, Battlezone + * + ************************************************************************ + * + * DISCRETE_RCDISC - Simple single pole RC discharge network + * + * .------------. + * | | + * | RC | + * | | + * INPUT1 -0------>| -ZZZZ-+-- | + * | R | |----> Netlist node + * RVAL -1------>| --- | + * | ---C | + * CVAL -2------>| | | + * | vref | + * '------------' + * + * Declaration syntax + * + * DISCRETE_RCFILTER(name of node, + * input node (or value), + * resistor value in OHMS, + * capacitor value in FARADS) + * + * Example config line + * + * DISCRETE_RCDISC(NODE_11,10,100,CAP_U(1)) + * + * C discharges from 10v as indicated by RC of 100R & 1uF. + * + *********************************************************************** + * + * DISCRETE_RCDISC2 - Switched input RC discharge network + * + * .------------. + * | | + * SWITCH -0------>| IP0 | IP1 | + * | | + * INPUT0 -1------>| -ZZZZ-. | + * | R0 | | + * RVAL0 -2------>| | | + * | | | + * INPUT1 -3------>| -ZZZZ-+-- | + * | R1 | |----> Netlist node + * RVAL1 -4------>| --- | + * | ---C | + * CVAL -5------>| | | + * | | + * '------------' + * + * Declaration syntax + * + * DISCRETE_RCDISC2(name of node, + * switch, + * input0 node (or value), + * resistor0 value in OHMS, + * input1 node (or value), + * resistor1 value in OHMS, + * capacitor value in FARADS) + * + * Example config line + * + * DISCRETE_RCDISC2(NODE_9,NODE_10,10.0,100,0.0,100,CAP_U(1)) + * + * When switched by NODE_10, C charges/discharges from 10v/0v + * as dictated by R0/C & R1/C combos respectively + * of 100R & 1uF. + * + *********************************************************************** + * + * DISCRETE_RCDISC3 - RC discharge network + * + * FIXME: Diode direction (for bzone) + * + * .-----------------. + * | | + * ENAB -0------>| | + * | diode R2 | + * JV -5------>| -+-|>|--ZZZZ-+- |----> Netlist node (JV < 0) + * | | + * | diode R2 | + * INPUT1 -1------>| -+-|<|--ZZZZ-+- |----> Netlist node (JV > 0) + * | | | | + * RVAL1 -2------>| '-ZZZZ-+----' | + * | R1 | | + * RVAL2 -3------>| --- | + * | ---C | + * CVAL -4------>| | | + * | gnd | + * '-----------------' + * + * Declaration syntax + * + * DISCRETE_RCDISC3(name of node, + * enable, + * input node (or value), + * R1 resistor value in OHMS, + * R2 resistor value in OHMS, + * capacitor value in FARADS, + * diode junction voltage) + * + * The polarity of the diode junction voltage determines the polarity of the diode. + * + * Example config line + * + * DISCRETE_RCDISC3(NODE_11,NODE_10,10,100,220,CAP_U(1), 0.5) + * + * When enabled by NODE_10, C charges from 10v as indicated by RC + * of 100R & 1uF. + * + * EXAMPLES: see Tank8, bzone + * + *********************************************************************** + * + * DISCRETE_RCDISC4 - RC discharge networks triggered by logic levels + * + * Declaration syntax + * + * DISCRETE_RCDISC4(name of node, + * enable, + * logic input node, + * R1 resistor static value in OHMS, + * R2 resistor static value in OHMS, + * R3 resistor static value in OHMS, + * C1 capacitor static value in FARADS, + * vP static value in VOLTS, + * circuit type static value) + * + * Type: 1 + * + * vP >---. + * | .------. + * Z | | + * Z R2 | |\ | + * O.C. Z '-|-\ | + * |\ Diode R1 | | >-+---> node + * Input >---| o----|<|------ZZZZ---+--------+-------|+/ + * |/ | | |/ + * --- ----- + * C1 --- \ / Diode + * | V + * gnd --- + * | + * Z + * Z R3 + * Z + * | + * gnd + * + * EXAMPLES: see Phoenix + * + * -------------------------------------------------- + * + * Type: 2 + * + * 5V >---. .------. + * Z | | + * Z 1k | |\ | + * Z '-|-\ | + * | R1 C1 Diode | >-+---> node + * Input >---+--ZZZZ----||----+-----|>|----+--------|+/ + * | | |/ + * ----- Z + * ^ Z R2 + * / \ Diode Z + * ----- | + * | gnd + * gnd + * + * EXAMPLES: see + * + * -------------------------------------------------- + * + * Type: 3 + * + * 5V >---. .------. + * Z | | + * Z 1k | |\ | + * Z '-|-\ | + * | R1 Diode | >-+---> node + * Input >---+--ZZZZ-----|>|------+---------+--------|+/ + * | | |/ + * --- C1 Z + * --- Z R2 + * | Z + * gnd | + * gnd + * + * + * EXAMPLES: see + * + *********************************************************************** + * + * DISCRETE_RCDISC5 - Diode in series with R//C + * + * .---------------------. + * | | + * ENAB -0------>| -----------. | + * | -- | + * INPUT1 -1------>| -|>|--+--|SW|---+- |----> Netlist node + * | | -- | | + * RVAL -2------>| --- Z | + * | C--- Z R | + * CVAL -3------>| | Z | + * | -----+----- | + * | |gnd | + * '---------------------' + * + * Declaration syntax + * + * DISCRETE_RCDISC5(name of node, + * enable, + * input node (or value), + * resistor value in OHMS, + * capacitor value in FARADS) + * + * Example config line + * + * DISCRETE_RCDISC5(NODE_11,NODE_10,10,100,CAP_U(1)) + * + * When enabled by NODE_10, C discharges from 10v as indicated by RC + * of 100R & 1uF. If not enabled, the capcitors keeps it load and may + * still be charged through input1. The switch is assumed to be a CD4066, + * thus if not enabled the output will be drawn by R to GND since + * the switch is in high impedance mode. + * + * EXAMPLES: see Spiders, Galaxian + * + *********************************************************************** + * + * DISCRETE_RCDISC_MODULATED - RC triggered by logic and modulated + * + * vP >---. + * | + * Z + * Z R1 + * O.C. Z + * |\ | R2 C1 R3 + * INPUT1 >---| o---+--ZZZ---||------+----+---ZZZ------+---> node + * |/ | | / + * / \ Z |/ + * Diode ----- Z R4 .---| NPN + * | Z | |\ + * | | | > + * gnd gnd | | + * | gnd + * INPUT2 >----------ZZZ------------------------. + * + * Declaration syntax + * + * DISCRETE_RCDISC_MODULATED(name of node, + * INPUT1 node (or value), + * INPUT2 node (or value), + * R1 value in OHMS (static value), + * R2 value in OHMS (static value), + * R3 value in OHMS (static value), + * R4 value in OHMS (static value), + * C1 value in FARADS (static value), + * vP value in VOLTS) + * + * EXAMPLES: dkong + * + *********************************************************************** + * + * DISCRETE_RCFILTER - Simple single pole RC filter network (vRef = 0) + * DISCRETE_RCFILTER_VREF - Same but referenced to vRef not 0V + * + * .------------. + * | | + * ENAB -0------}| RC FILTER | + * | | + * INPUT1 -1------}| -ZZZZ-+-- | + * | R | |----} Netlist node + * RVAL -2------}| --- | + * | ---C | + * CVAL -3------}| | | + * | vRef | + * '------------' + * + * Declaration syntax + * + * DISCRETE_RCFILTER(name of node, + * enable + * input node (or value) + * resistor value in OHMS + * capacitor value in FARADS) + * + * DISCRETE_RCFILTER_VREF(name of node, + * enable + * input node (or value) + * resistor value in OHMS + * capacitor value in FARADS, + * vRef static value) + * + * Example config line + * + * DISCRETE_RCFILTER(NODE_11,1,NODE_10,100,CAP_U(1)) + * + * Defines an always enabled RC filter with a 100R & 1uF network + * the input is fed from NODE_10. + * + * This can be also thought of as a low pass filter with a 3dB cutoff + * at: + * 1 + * Fcuttoff = -------------- + * 2*Pi*RVAL*CVAL + * + * (3dB cutoff is where the output power has dropped by 3dB ie Half) + * + * EXAMPLES: see Polaris + * + *********************************************************************** + * + * DISCRETE_RCFILTER_SW - Multiple switchable RC filters + * + * R + * INPUT >-----------ZZZZ-+-------+----......-----> Output + * | | + * +-+ +-+ + * SWITCH > Bit 0 ---->F1 | | F2 | | + * '-' ^ '-' + * Bit 1 ---------|----' | + * | | + * Bit ... --- --- + * --- C1 --- C2 + * | | + * GND GND + * + * + * Declaration syntax + * + * DISCRETE_RCFILTER_SW(name of node, + * enable, + * input node (or value), + * switch node (or value), + * R in Ohms (static value), + * C1 in Farads (static value), + * C2 in Farads (static value), + * C3 in Farads (static value), + * C4 in Farads (static value)) + * + * This is a typical filter circuit in circusc or scramble. + * Switches are usually CD4066 with a "open" resistance of + * typical 470 Ohms at 5V. + * This circuit supports up to 4 filters. + * + * EXAMPLES: see circusc + * + *********************************************************************** + * + * DISCRETE_RCINTEGRATE - RC integration circuit/amplifier + * + * + * vP >-------------------+ + * | + * Z + * Z R3 + * Z + * | + * +-----------------> node (Type 3) + * / + * |/ + * INPUT >---------------| NPN + * \ .--------------> node (Type 2) + * > | R1 + * +--+--ZZZ-+-------> node (Type 1) + * | | + * Z --- + * Z R2 C--- + * Z | + * | | + * gnd gnd + * + * Declaration syntax + * + * DISCRETE_RCINTEGRATE(name of node, + * INPUT node (or value), + * R1 value in OHMS, + * R2 value in OHMS, + * R3 value in OHMS, + * C value in FARADS, + * vP node (or value in VOLTS) + * TYPE) + * + * TYPE: RC_INTEGRATE_TYPE1, RC_INTEGRATE_TYPE2, RC_INTEGRATE_TYPE3 + * + * Actually an amplifier as well. Primary reason for implementation was integration. + * The integration configuration (TYPE3, R3=0) works quite well, the amplifying + * configuration is missing a good, yet simple ( :-) ) transistor model. Around the + * defined working point the amplifier delivers results. + * + * EXAMPLES: dkong + * + * + *********************************************************************** + ======================================================================= + * from from disc_dev.inc + * Component specific modules + ======================================================================= + *********************************************************************** + * + * DISCRETE_555_ASTABLE - NE555 Chip simulation (astable mode). + * DISCRETE_555_ASTABLE_CV - NE555 Chip simulation (astable mode) with CV control. + * + * v_charge v_pos + * V V + * | | + * | | + * | | + * Z |8 + * _FAST_CHARGE_DIODE R1 Z .---------. + * (optional) | 7| Vcc | + * +---------> +-----|Discharge| + * | | | | + * --- Z | 555 |3 + * \ / R2 Z | Out|---> Netlist Node + * V | 6| | + * --- +-----|Threshold| + * | | | | + * +---------> +-----|Trigger | + * | 2| |---< Control Voltage + * | | Reset |5 + * | '---------' + * --- 4| + * C --- | + * | ^ + * gnd Reset + * + * Declaration syntax + * + * DISCRETE_555_ASTABLE(name of node, + * reset node (or value), + * R1 node (or value) in ohms, + * R2 node (or value) in ohms, + * C node (or value) in farads, + * address of discrete_555_desc structure) + * + * DISCRETE_555_ASTABLE_CV(name of node, + * reset node (or value), + * R1 node (or value) in ohms, + * R2 node (or value) in ohms, + * C node (or value) in farads, + * Control Voltage node (or value), + * address of discrete_555_desc structure) + * + * discrete_555_desc = + * { + * options, - bit mapped options + * v_pos, - B+ voltage of 555 + * v_charge, - voltage (or node) to charge circuit (Defaults to v_pos) + * v_out_high - High output voltage of 555 (Defaults to v_pos - 1.2V) + * } + * + * The last 2 options of discrete_555_desc can use the following defaults: + * DEFAULT_555_CHARGE - to connect v_charge to v_pos + * DEFAULT_555_HIGH - to use the normal output voltage based on v_pos + * or combine both as: + * DEFAULT_555_VALUES + * + * eg. {DISC_555_OUT_SQW | DISC_555_OUT_DC, 12, DEFAULT_555_VALUES} + * + * Output Types: (only needed with DISC_555_OUT_SQW, DISC_555_OUT_CAP + * and DISC_555_OUT_ENERGY) + * DISC_555_OUT_DC - Output is actual DC. (DEFAULT) + * DISC_555_OUT_AC - A cheat to make the waveform AC. + * + * Waveform Types: (ORed with output types) + * DISC_555_OUT_SQW - Output is Squarewave. 0 or v_out_high. (DEFAULT) + * When the state changes from low to high (or high to low) + * during a sample, the output will high (or low) for that + * sample. This can cause alaising effects. + * DISC_555_OUT_CAP - Output is Timing Capacitor 'C' voltage. + * DISC_555_OUT_COUNT_F - If the 555 frequency is greater then half the sample + * rate, then the output may change state more then once + * during the sample. Using this flag will cause + * the output to be the number of falling edges that + * happened during the sample. This is usefull to feed + * to counter circuits. The Output Type flag is ingnored + * when this flag is used. + * DISC_555_OUT_COUNT_R - Same as DISC_555_OUT_COUNT_F but with rising edges. + * DISC_555_OUT_ENERGY - Same SQW, but will help reduce aliasing effects. + * This should be used when the 555 squarewave output is used + * as a final output and not as a clock source. + * If the state changes from low to high 1/4 of the way + * through the sample, then the output will be 75% of the + * normal high value. + * DISC_555_OUT_LOGIC_X - This will output the 0/1 level of the flip-flop with + * some eXtra info. This x_time is in decimal remainder. + * It lets you know the percent of sample time where the + * flip-flop changed state. If 0, the change did not happen + * during the sample. 1.75 means the flip-flop is 1 and + * switched over 1/4 of the way through the sample. + * 0.2 means the flip-flop is 0 and switched over 4/5 of + * the way through the sample. + * X modules can be used with counters to reduce alaising. + * DISC_555_OUT_COUNT_F_X - Same as DISC_555_OUT_COUNT_F but with x_time. + * DISC_555_OUT_COUNT_R_X - Same as DISC_555_OUT_COUNT_R but with x_time. + * + * other options - DISCRETE_555_ASTABLE only: + * DISC_555_ASTABLE_HAS_FAST_CHARGE_DIODE - diode used to bypass rDischarge + * when charging for quicker charge. + * + * EXAMPLES: see Hit Me, Canyon Bomber, Sky Diver + * + *********************************************************************** + * + * DISCRETE_555_MSTABLE - NE555 Chip simulation (monostable mode) + * - Triggered on falling edge. + * + * v_charge v_pos + * V V + * | | + * | | + * | | + * Z | + * R Z .---------. + * | | Vcc | + * +-----|Discharge| + * | | | + * | | 555 | + * | | Out|---> Netlist Node + * | | | + * +-----|Threshold| + * | | | + * | | Trigger|--------< Trigger + * | | CV|---. + * | | Reset | | + * | '---------' --- not + * --- | --- needed + * C --- | | + * | ^ gnd + * gnd Reset + * + * Declaration syntax + * + * DISCRETE_555_MSTABLE(name of node, + * reset node (or value), + * Trigger node, + * R node (or value) in ohms, + * C node (or value) in farads, + * address of discrete_555_desc structure) + * + * discrete_555_desc = See DISCRETE_555_ASTABLE for description. + * Note: v_charge can not be a node for this circuit. + * + * Trigger Types + * DISC_555_TRIGGER_IS_LOGIC - Input is (0 or !0) logic (DEFAULT) + * DISC_555_TRIGGER_IS_VOLTAGE - Input is actual voltage. + * Voltage must drop below + * trigger to activate. + * DISC_555_TRIGGER_IS_COUNT - 1 when trigger, allows passing of x_time. + * Mainly connected with other module using + * a xxx_COUNT_F_X type. + * DISC_555_TRIGGER_DISCHARGES_CAP - some circuits connect an external + * device (transistor) to the cap to + * discharge it when the trigger is + * enabled. Thereby allowing the one-shot + * to retrigger. + * + * Output Types: (ORed with trigger types) + * DISC_555_OUT_DC - Output is actual DC. (DEFAULT) + * DISC_555_OUT_AC - A cheat to make the waveform AC. + * + * Waveform Types: (ORed with trigger types) + * DISC_555_OUT_SQW - Output is Squarewave. 0 or v_out_high. (DEFAULT) + * DISC_555_OUT_CAP - Output is Timing Capacitor 'C' voltage. + * DISC_555_OUT_ENERGY - see DISCRETE_555_MSTABLE. + * + * EXAMPLES: see Frogs, Sprint 8 + * + *********************************************************************** + * + * DISCRETE_555_CC - Constant Current Controlled 555 Oscillator + * Which works out to a VCO when R is fixed. + * + * v_cc_source v_pos + * V V + * | .----------------------+ + * | | | + * | | .---------. + * | | rDischarge | Vcc | + * Z Z .---+-----|Discharge| + * Z R Z rBias | | | | + * | | | Z | 555 | + * | | | Z | Out|---> Netlist Node + * .----. | >-' | | | + * Vin >--| CC |--+--> option +-----|Threshold| + * '----' >-----+ | | + * +-----|Trigger | + * | | | + * .------+-----' | Reset | + * | | '---------' + * --- Z | + * --- C Z rGnd | + * | | ^ + * gnd gnd Reset + * + * Notes: R sets the current and should NEVER be 0 (short). + * The current follows the voltage I=Vin/R and charges C. + * rBias, rDischarge and rGnd should be 0 if not used. + * Reset is active low for the module. + * + * Note that the CC source can be connected two different ways. + * See the option flags below for more info. + * + * DISC_555_OUT_SQW mode only: + * When there is no rDischarge there is a very short discharge + * cycle (almost 0s), so the module triggers the output for 1 + * sample. This does not effect the timing, just the duty cycle. + * But frequencies more the half the sample frequency will be + * limited to a max of half the sample frequency. + * This mode should be used to drive a counter for any real use. + * Just like the real thing. + * + * Declaration syntax + * + * DISCRETE_555_CC(name of node, + * reset node or static value, + * Vin node or static value, + * R node or static value, + * C node or static value, + * rBias node or static value, + * rGnd node or static value, + * rDischarge node or static value, + * address of discrete_555_cc_desc structure) + * + * discrete_555_cc_desc = + * { + * options; - bit mapped options + * v_pos; - B+ voltage of 555 + * v_cc_source; - Voltage of the Constant Current source + * v_out_high; - High output voltage of 555 (Defaults to v_pos - 1.2V) + * v_cc_junction; - The voltage drop of the Constant Current source transitor + * (0 if Op Amp) + * } + * + * The last 2 options of discrete_555_desc can use the following defaults: + * DEFAULT_555_CC_SOURCE - to connect v_cc_source to v_pos + * DEFAULT_555_HIGH - to use the normal output voltage based on v_pos + * or combine both as: + * DEFAULT_555_VALUES + * + * Output Types: + * See DISCRETE_555_ASTABLE for description. + * + * Waveform Types: (ORed with output types) + * See DISCRETE_555_ASTABLE for description. + * + * Other Flags: + * DISCRETE_555_CC_TO_DISCHARGE_PIN - The CC source connects to the + * discharge pin. (Default) + * DISCRETE_555_CC_TO_CAP - The CC source connects to the + * threshold pin. This is not fully + * implemented yet. It only works properly + * when only rDischarge is defined. + * + * EXAMPLES: see Fire Truck, Monte Carlo, Super Bug + * + *********************************************************************** + * + * DISCRETE_555_VCO1 - Op-Amp based 555 VCO circuit. + * DISCRETE_555_VCO1_CV - Op-Amp based 555 VCO circuit with CV control. + * + * c + * .------------------------+---||----+---------------------------> DISC_555_OUT_CAP + * | | | + * | | |\ | + * | r1 | | \ | .------------. + * | vIn1 >--+--ZZZZ-------+---|- \ | | | + * | | | >-+---+--|Threshold | + * | | r2 |+ / | | Out|------> DISC_555_OUT_xx + * Z '--ZZZZ--+--------| / '--|Trigger | + * Z r4 | |/ | | + * Z Z | Reset|------< Reset + * | Z r3 vIn2 >--|CV | + * .----. Z | | + * | En|<--------. | .---|Discharge | + * '----' | gnd | '------------' + * | | | + * gnd '-----------------------+---ZZZZ------> v_charge (ignored) + * rX + * + * Declaration syntax + * + * DISCRETE_555_VCO1(name of node, + * reset node or static value, + * Vin1 node or static value, + * address of discrete_555_vco1_desc structure) + * + * DISCRETE_555_VCO1_CV(name of node, + * reset node or static value, + * Vin1 node or static value, + * Vin2 (CV) node or static value, + * address of discrete_555_vco1_desc structure) + * + * discrete_555_vco1_desc = + * { + * options, - bit mapped options + * r1, r2, r3, r4, c, + * v_pos, - B+ voltage of 555 + * v_out_high, - High output voltage of 555 (Defaults to v_pos - 1.2V) + * } + * + * The last option of discrete_555_vco1_desc can use the following default: + * DEFAULT_555_HIGH - to use the normal output voltage based on v_pos + * + * Notes: The value of resistor rX is not needed. It is just a pull-up + * for the discharge output. + * The 'En' block can be a transistor or 4066 switch. It connects + * r4 to ground when En is high. + * + *********************************************************************** + * + * DISCRETE_566 - NE566 VCO simulation. + * + * v_charge v_pos + * V V + * | | + * | | + * | R .-------. + * '---/\/\--|6 8 | + * | | + * vMod >------------|5 3/4|---------> Netlist Node + * | | + * .---|7 1 | + * | '-------' + * --- | + * --- C | + * | | + * v_neg v_neg + * + * Note: There is usually a 0.001uF cap between pins 5 & 6. + * This is for circuit stability and can be ignored for simulation purposes. + * + * Declaration syntax + * + * DISCRETE_566(name of node, + * vMod node or static value, + * R node or static value in ohms, + * C node or static value in Farads, + * v_pos static value + * v_neg static value + * v_charge node or static value + * options) + * + * Output Types: + * DISC_566_OUT_DC - Output is actual DC. (DEFAULT) + * DISC_566_OUT_AC - A cheat to make the waveform AC. + * + * Waveform Types: + * DISC_566_OUT_SQUARE - Pin 3 Square Wave Output (DEFAULT) + * DISC_566_OUT_ENERGY - Pin 3 anti-alaised Square Wave Output + * DISC_566_OUT_TRIANGLE - Pin 4 Triangle Wave Output + * DISC_566_OUT_LOGIC - Internal Flip/Flop Output + * DISC_566_COUNT_F - # of falling edges + * DISC_566_COUNT_R - # of rising edges + * DISC_566_COUNT_F_X - # of falling edges with x-time + * DISC_566_COUNT_R_X - # of rising edges with x-time + * + * EXAMPLES: see Starship 1 + * + *********************************************************************** + * + * DISCRETE_74LS624 - VCO. 1/2 of 74LS629. + * + * The datasheet gives no formulae. The implementation is based on + * testing a 74LS629. + * + * For a LS628, use VRng = 3.2 + * + * V+ + * | + * R_rng_in .---------. + * vRng >-----------ZZZZ-------|Rng V+ | + * R_freq_in | | + * vMod >---ZZZZ-+-------------|Freq Z |---------> Netlist Node + * | | | + * C_freq_in --- .---|CX1 | + * --- | | | + * | --- | | + * | C --- | | + * Gnd | | | + * '---|CX2 | + * '---------' + * | + * GND + * + * Declaration syntax + * + * DISCRETE_74LS624(name of node,(NODE,ENAB,VMOD,VRNG,C,R_FREQ_IN,C_FREQ_IN,R_RNG_IN,OUTTYPE) + * enable node or static value, + * vMod node or static value, + * vRng static value, + * C static value in Farads, + * R_freq_in static value in Ohms, + * C_freq_in static value in Farads, + * R_rng_in static value in Ohms, + * Type of output static value) + * + * Type of Output + * DISC_LS624_OUT_SQUARE - 4.4V square wave + * DISC_LS624_OUT_ENERGY - 4.4V anti-aliased square wave + * DISC_LS624_OUT_LOGIC - Logic ( 0 or 1) + * DISC_LS624_OUT_LOGIC_X - Logic ( 0 or 1) with x_time + * DISC_LS624_OUT_COUNT_F - Number of Falling edges + * DISC_LS624_OUT_COUNT_F_X - Number of Falling edges with x_time + * DISC_LS624_OUT_COUNT_R - Number of Rising edges + * DISC_LS624_OUT_COUNT_R_X - Number of Rising edges with x_time + * + * + * EXAMPLES: see Donkey Kong Jr.; Mario Bros. + * + *********************************************************************** + * + * DISCRETE_CUSTOMx - Link to custom code + * where x = 1 to 9 + * + * Declaration syntax + * + * DISCRETE_CUSTOMx(name of node, + * input 0 node or static value, ...) + * + * discrete_custom_info = {discrete_module, custom} + * discrete_module = discrete module definition + * custom = address of specific initialization data + * + * In most case, you should be able to use + * + * discrete_custom_info = {DISCRETE_CUSTOM_MODULE(basename, context type), custom} + * + * if you have used DISCRETE_STEP(basename) and DISCRETE_RESET(basename) to define + * the step/reset procedures. + * + * EXAMPLES: see Sky Raider, Donkey Kong + * + *********************************************************************** + ======================================================================= + * Debugging modules. + ======================================================================= + *********************************************************************** + * + * DISCRETE_CSVLOGx - Dump n nodes into a csv (comma separated value) file + * + * Declaration syntax + * + * DISCRETE_CSVLOGx(node 1, ...) + * where x = 1 to 5 + * + * WARNING: This can rapidally use up a lot of hard drive space. + * 48kHz sampling of 5 nodes used 217M after 80 seconds. + * + * Use this to monitor nodes while debugging the driver. You should + * remove these nodes from the final driver. You can use up to a maximum + * DISCRETE_MAX_CSVLOGS. Each file will be called discreteX_Y.csv, + * where X is the sound tag. Y is 0-9, in the order the file is + * created in the driver. + * + * This can be used to monitor how multiple nodes relate to each other. + * The resulting file can be imported to a spreadsheet. + * + ************************************************************************ + * + * DISCRETE_WAVLOG - Dump nodes into a wav file + * + * Declaration syntax + * + * DISCRETE_WAVLOG1(node, + * static gain for node) + * + * DISCRETE_WAVLOG2(left node, + * static gain for left node, + * right node, + * static gain for right node) + * + * Use this to monitor nodes while debugging the driver. You should + * remove these nodes from the final driver. You can use up to a maximum + * of DISCRETE_MAX_WAVLOGS. Each file will be called discreteX_Y.wav, + * where X is the sound tag. Y is 0-9, in the order the file is + * created in the driver. + * + * This can be used to monitor how a node's input affects it's output. + * Monitor the input trigger against the final effect, etc. The resulting + * file can be played/viewed etc. by music player/editor software. + * + * When logging nodes that are voltage levels, you may want to use a + * gain of 1000. This will make the wav sample level reflect milli-volts. + * + ************************************************************************ + ======================================================================= + * Must be last module. + ======================================================================= + *********************************************************************** + * + * DISCRETE_OUTPUT - Single output node to Mame mixer and output + * + * .----------. . + * | | .-/| + * Netlist node -------->| OUTPUT |----| | Sound Output + * | | '-\| + * '----------' ' + * + * Declaration syntax + * + * DISCRETE_OUTPUT(name of output node, gain) + * + * Example config line + * + * DISCRETE_OUTPUT(NODE_02, 1000) + * + * Output stream will be generated from the NODE_02 output stream * 1000. + * + * Multiple outputs can be used up to DISCRETE_MAX_OUTPUTS. + * + ************************************************************************/ + +#include "wavwrite.h" + +/************************************* + * + * macros + * see also: emu\machine\rescap.h + * + *************************************/ + +/* calculate charge exponent using discrete sample time */ +#define RC_CHARGE_EXP(rc) (1.0 - exp(-this->sample_time() / (rc))) +/* calculate charge exponent using given sample time */ +#define RC_CHARGE_EXP_DT(rc, dt) (1.0 - exp(-(dt) / (rc))) +#define RC_CHARGE_NEG_EXP_DT(rc, dt) (1.0 - exp((dt) / (rc))) + +/* calculate discharge exponent using discrete sample time */ +#define RC_DISCHARGE_EXP(rc) (exp(-this->sample_time() / (rc))) +/* calculate discharge exponent using given sample time */ +#define RC_DISCHARGE_EXP_DT(rc, dt) (exp(-(dt) / (rc))) +#define RC_DISCHARGE_NEG_EXP_DT(rc, dt) (exp((dt) / (rc))) + +#define FREQ_OF_555(_r1, _r2, _c) (1.49 / ((_r1 + 2 * _r2) * _c)) + +/************************************* + * + * Interface & Naming + * + *************************************/ + +#define DISCRETE_CLASS_FUNC(_class, _func) DISCRETE_CLASS_NAME(_class) :: _func + +#define DISCRETE_STEP(_class) void DISCRETE_CLASS_FUNC(_class, step)(void) +#define DISCRETE_RESET(_class) void DISCRETE_CLASS_FUNC(_class, reset)(void) +#define DISCRETE_START(_class) void DISCRETE_CLASS_FUNC(_class, start)(void) +#define DISCRETE_STOP(_class) void DISCRETE_CLASS_FUNC(_class, stop)(void) +#define DISCRETE_DECLARE_INFO(_name) const _name *info = (const _name *)this->custom_data(); + +//#define DISCRETE_INPUT(_num) (*(this->m_input[_num])) +#define DISCRETE_INPUT(_num) (input(_num)) + +/************************************* + * + * Core constants + * + *************************************/ + +#define DISCRETE_MAX_NODES 300 +#define DISCRETE_MAX_INPUTS 10 +#define DISCRETE_MAX_OUTPUTS 8 + +#define DISCRETE_MAX_TASK_GROUPS 10 + + +/************************************* + * + * Node-specific constants + * + *************************************/ + +#define DEFAULT_TTL_V_LOGIC_1 3.4 + +#define DISC_LOGADJ 1.0 +#define DISC_LINADJ 0.0 + +/* DISCRETE_COMP_ADDER types */ +#define DISC_COMP_P_CAPACITOR 0x00 +#define DISC_COMP_P_RESISTOR 0x01 + +/* clk types */ +#define DISC_CLK_MASK 0x03 +#define DISC_CLK_ON_F_EDGE 0x00 +#define DISC_CLK_ON_R_EDGE 0x01 +#define DISC_CLK_BY_COUNT 0x02 +#define DISC_CLK_IS_FREQ 0x03 + +#define DISC_COUNT_DOWN 0 +#define DISC_COUNT_UP 1 + +#define DISC_COUNTER_IS_7492 0x08 + +#define DISC_OUT_MASK 0x30 +#define DISC_OUT_DEFAULT 0x00 +#define DISC_OUT_IS_ENERGY 0x10 +#define DISC_OUT_HAS_XTIME 0x20 + +/* Function possibilities for the LFSR feedback nodes */ +/* 2 inputs, one output */ +#define DISC_LFSR_XOR 0 +#define DISC_LFSR_OR 1 +#define DISC_LFSR_AND 2 +#define DISC_LFSR_XNOR 3 +#define DISC_LFSR_NOR 4 +#define DISC_LFSR_NAND 5 +#define DISC_LFSR_IN0 6 +#define DISC_LFSR_IN1 7 +#define DISC_LFSR_NOT_IN0 8 +#define DISC_LFSR_NOT_IN1 9 +#define DISC_LFSR_REPLACE 10 +#define DISC_LFSR_XOR_INV_IN0 11 +#define DISC_LFSR_XOR_INV_IN1 12 + +/* LFSR Flag Bits */ +#define DISC_LFSR_FLAG_OUT_INVERT 0x01 +#define DISC_LFSR_FLAG_RESET_TYPE_L 0x00 +#define DISC_LFSR_FLAG_RESET_TYPE_H 0x02 +#define DISC_LFSR_FLAG_OUTPUT_F0 0x04 +#define DISC_LFSR_FLAG_OUTPUT_SR_SN1 0x08 + +/* Sample & Hold supported clock types */ +#define DISC_SAMPHOLD_REDGE 0 +#define DISC_SAMPHOLD_FEDGE 1 +#define DISC_SAMPHOLD_HLATCH 2 +#define DISC_SAMPHOLD_LLATCH 3 + +/* Shift options */ +#define DISC_LOGIC_SHIFT__RESET_L 0x00 +#define DISC_LOGIC_SHIFT__RESET_H 0x10 +#define DISC_LOGIC_SHIFT__LEFT 0x00 +#define DISC_LOGIC_SHIFT__RIGHT 0x20 + +/* Maximum number of resistors in ladder chain */ +#define DISC_LADDER_MAXRES 8 + +/* Filter types */ +#define DISC_FILTER_LOWPASS 0 +#define DISC_FILTER_HIGHPASS 1 +#define DISC_FILTER_BANDPASS 2 + +/* Mixer types */ +#define DISC_MIXER_IS_RESISTOR 0 +#define DISC_MIXER_IS_OP_AMP 1 +#define DISC_MIXER_IS_OP_AMP_WITH_RI 2 /* Used only internally. Use DISC_MIXER_IS_OP_AMP */ + +/* Triggered Op Amp Functions */ +enum +{ + DISC_OP_AMP_TRIGGER_FUNCTION_NONE, + DISC_OP_AMP_TRIGGER_FUNCTION_TRG0, + DISC_OP_AMP_TRIGGER_FUNCTION_TRG0_INV, + DISC_OP_AMP_TRIGGER_FUNCTION_TRG1, + DISC_OP_AMP_TRIGGER_FUNCTION_TRG1_INV, + DISC_OP_AMP_TRIGGER_FUNCTION_TRG2, + DISC_OP_AMP_TRIGGER_FUNCTION_TRG2_INV, + DISC_OP_AMP_TRIGGER_FUNCTION_TRG01_AND, + DISC_OP_AMP_TRIGGER_FUNCTION_TRG01_NAND +}; + + +/* Common Op Amp Flags and values */ +#define DISC_OP_AMP_IS_NORTON 0x100 +#define OP_AMP_NORTON_VBE 0.5 // This is the norton junction voltage. Used only internally. +#define OP_AMP_VP_RAIL_OFFSET 1.5 // This is how close an op-amp can get to the vP rail. Used only internally. + +/* Integrate options */ +#define DISC_INTEGRATE_OP_AMP_1 0x00 +#define DISC_INTEGRATE_OP_AMP_2 0x10 + +/* op amp 1 shot types */ +#define DISC_OP_AMP_1SHT_1 0x00 + +/* Op Amp Filter Options */ +#define DISC_OP_AMP_FILTER_IS_LOW_PASS_1 0x00 +#define DISC_OP_AMP_FILTER_IS_HIGH_PASS_1 0x10 +#define DISC_OP_AMP_FILTER_IS_BAND_PASS_1 0x20 +#define DISC_OP_AMP_FILTER_IS_BAND_PASS_1M 0x30 +#define DISC_OP_AMP_FILTER_IS_HIGH_PASS_0 0x40 +#define DISC_OP_AMP_FILTER_IS_BAND_PASS_0 0x50 +#define DISC_OP_AMP_FILTER_IS_LOW_PASS_1_A 0x60 + +#define DISC_OP_AMP_FILTER_TYPE_MASK (0xf0 | DISC_OP_AMP_IS_NORTON) // Used only internally. + +/* Sallen-Key filter Opions */ +#define DISC_SALLEN_KEY_LOW_PASS 0x01 +#define DISC_SALLEN_KEY_HIGH_PASS 0x02 + + +/* Op Amp Oscillator Flags */ +#define DISC_OP_AMP_OSCILLATOR_TYPE_MASK (0xf0 | DISC_OP_AMP_IS_NORTON) // Used only internally. +#define DISC_OP_AMP_OSCILLATOR_1 0x00 +#define DISC_OP_AMP_OSCILLATOR_2 0x10 +#define DISC_OP_AMP_OSCILLATOR_VCO_1 0x20 +#define DISC_OP_AMP_OSCILLATOR_VCO_2 0x30 +#define DISC_OP_AMP_OSCILLATOR_VCO_3 0x40 + +#define DISC_OP_AMP_OSCILLATOR_OUT_MASK 0x07 +#define DISC_OP_AMP_OSCILLATOR_OUT_CAP 0x00 +#define DISC_OP_AMP_OSCILLATOR_OUT_SQW 0x01 +#define DISC_OP_AMP_OSCILLATOR_OUT_ENERGY 0x02 +#define DISC_OP_AMP_OSCILLATOR_OUT_LOGIC_X 0x03 +#define DISC_OP_AMP_OSCILLATOR_OUT_COUNT_F_X 0x04 +#define DISC_OP_AMP_OSCILLATOR_OUT_COUNT_R_X 0x05 + +/* Schmitt Oscillator Options */ +#define DISC_SCHMITT_OSC_IN_IS_LOGIC 0x00 +#define DISC_SCHMITT_OSC_IN_IS_VOLTAGE 0x01 + +#define DISC_SCHMITT_OSC_ENAB_IS_AND 0x00 +#define DISC_SCHMITT_OSC_ENAB_IS_NAND 0x02 +#define DISC_SCHMITT_OSC_ENAB_IS_OR 0x04 +#define DISC_SCHMITT_OSC_ENAB_IS_NOR 0x06 + +#define DISC_SCHMITT_OSC_ENAB_MASK 0x06 /* Bits that define output enable type. + * Used only internally in module. */ + +/* 555 Common output flags */ +#define DISC_555_OUT_DC 0x00 +#define DISC_555_OUT_AC 0x10 + +#define DISC_555_TRIGGER_IS_LOGIC 0x00 +#define DISC_555_TRIGGER_IS_VOLTAGE 0x20 +#define DISC_555_TRIGGER_IS_COUNT 0x40 +#define DSD_555_TRIGGER_TYPE_MASK 0x60 +#define DISC_555_TRIGGER_DISCHARGES_CAP 0x80 + +#define DISC_555_OUT_SQW 0x00 /* Squarewave */ +#define DISC_555_OUT_CAP 0x01 /* Cap charge waveform */ +#define DISC_555_OUT_COUNT_F 0x02 /* Falling count */ +#define DISC_555_OUT_COUNT_R 0x03 /* Rising count */ +#define DISC_555_OUT_ENERGY 0x04 +#define DISC_555_OUT_LOGIC_X 0x05 +#define DISC_555_OUT_COUNT_F_X 0x06 +#define DISC_555_OUT_COUNT_R_X 0x07 + +#define DISC_555_OUT_MASK 0x07 /* Bits that define output type. + * Used only internally in module. */ + +#define DISC_555_ASTABLE_HAS_FAST_CHARGE_DIODE 0x80 +#define DISCRETE_555_CC_TO_DISCHARGE_PIN 0x00 +#define DISCRETE_555_CC_TO_CAP 0x80 + +/* 566 output flags */ +#define DISC_566_OUT_DC 0x00 +#define DISC_566_OUT_AC 0x10 + +#define DISC_566_OUT_SQUARE 0x00 /* Squarewave */ +#define DISC_566_OUT_ENERGY 0x01 /* anti-alaised Squarewave */ +#define DISC_566_OUT_TRIANGLE 0x02 /* Triangle waveform */ +#define DISC_566_OUT_LOGIC 0x03 /* 0/1 logic output */ +#define DISC_566_OUT_COUNT_F 0x04 +#define DISC_566_OUT_COUNT_R 0x05 +#define DISC_566_OUT_COUNT_F_X 0x06 +#define DISC_566_OUT_COUNT_R_X 0x07 +#define DISC_566_OUT_MASK 0x07 /* Bits that define output type. + * Used only internally in module. */ + +/* LS624 output flags */ +#define DISC_LS624_OUT_SQUARE 0x01 +#define DISC_LS624_OUT_ENERGY 0x02 +#define DISC_LS624_OUT_LOGIC 0x03 +#define DISC_LS624_OUT_LOGIC_X 0x04 +#define DISC_LS624_OUT_COUNT_F 0x05 +#define DISC_LS624_OUT_COUNT_R 0x06 +#define DISC_LS624_OUT_COUNT_F_X 0x07 +#define DISC_LS624_OUT_COUNT_R_X 0x08 + +/* Oneshot types */ +#define DISC_ONESHOT_FEDGE 0x00 +#define DISC_ONESHOT_REDGE 0x01 + +#define DISC_ONESHOT_NORETRIG 0x00 +#define DISC_ONESHOT_RETRIG 0x02 + +#define DISC_OUT_ACTIVE_LOW 0x04 +#define DISC_OUT_ACTIVE_HIGH 0x00 + +#define DISC_CD4066_THRESHOLD 2.75 + +/* Integrate */ + +#define DISC_RC_INTEGRATE_TYPE1 0x00 +#define DISC_RC_INTEGRATE_TYPE2 0x01 +#define DISC_RC_INTEGRATE_TYPE3 0x02 + +/************************************* + * + * Classes and structs to handle + * linked lists. + * + *************************************/ + +/* + * add and delete may be slow - the focus is on access! + */ + + // TODO: replace with vector from utils +template struct vector_t +{ +public: + vector_t(int initial) { + m_count = 0; + m_allocated = initial; + m_arr = global_alloc_array_clear(_ElementType, m_allocated); + } + vector_t() { + m_count = 0; + m_allocated = 16; + m_arr = global_alloc_array_clear(_ElementType, m_allocated); + } + ~vector_t() { + global_free_array(m_arr); + } + _ElementType& operator [] (unsigned int index) const // get array item + { + return m_arr[index]; + } + + vector_t(const vector_t &a) // copy constructor + { + m_allocated = a.count(); + if (m_allocated < 16) + m_allocated = 16; + m_count = a.count(); + m_arr = global_alloc_array_clear(_ElementType, m_allocated); + for (int i=0; i < m_count; i++) + m_arr[i] = a[i]; + } + vector_t& operator = (const vector_t &a) // assignment operator + { + if (this == &a) return *this; + m_allocated = a.count(); + if (m_allocated < 16) + m_allocated = 16; + m_count = a.count(); + m_arr = global_alloc_array_clear(_ElementType, m_allocated); + for (int i=0; i < m_count; i++) + m_arr[i] = a[i]; + return *this; + } + + inline _ElementType* add(_ElementType object) + { + if (m_count >= m_allocated) + { + m_allocated *= 2; + _ElementType *newarr = global_alloc_array_clear(_ElementType, m_allocated); + for (int i=0; i < m_count; i++) + newarr[i] = m_arr[i]; + global_free_array(m_arr); + m_arr = newarr; + } + m_arr[m_count] = object; + m_count++; + return &m_arr[m_count-1]; + } + inline void remove(int index) + { + for (int i=index+1; i < m_count; i++) + m_arr[i-1] = m_arr[i]; + m_count--; + } + inline void clear(void) { m_count = 0; } + inline int count(void) const { return m_count; } + inline _ElementType *begin_ptr(void) const { return m_arr; } + inline _ElementType *end_ptr(void) const { return m_arr + (m_count - 1); } +private: + _ElementType *m_arr; + int m_count; + int m_allocated; +}; + +/************************************* + * + * Node-specific struct types + * + *************************************/ + +struct discrete_lfsr_desc +{ + int clock_type; + int bitlength; + int reset_value; + + int feedback_bitsel0; + int feedback_bitsel1; + int feedback_function0; /* Combines bitsel0 & bitsel1 */ + + int feedback_function1; /* Combines funct0 & infeed bit */ + + int feedback_function2; /* Combines funct1 & shifted register */ + int feedback_function2_mask; /* Which bits are affected by function 2 */ + + int flags; + + int output_bit; +}; + + +struct discrete_op_amp_osc_info +{ + UINT32 type; + double r1; + double r2; + double r3; + double r4; + double r5; + double r6; + double r7; + double r8; + double c; + double vP; // Op amp B+ +}; + + +#define DEFAULT_7414_VALUES 1.7, 0.9, 3.4 + +#define DEFAULT_74LS14_VALUES 1.6, 0.8, 3.4 + +struct discrete_schmitt_osc_desc +{ + double rIn; + double rFeedback; + double c; + double trshRise; // voltage that triggers the gate input to go high (vGate) on rise + double trshFall; // voltage that triggers the gate input to go low (0V) on fall + double vGate; // the output high voltage of the gate that gets fedback through rFeedback + int options; // bitmaped options +}; + + +struct discrete_comp_adder_table +{ + int type; + double cDefault; // Default componet. 0 if not used. + int length; + double c[DISC_LADDER_MAXRES]; // Componet table +}; + + +struct discrete_dac_r1_ladder +{ + int ladderLength; // 2 to DISC_LADDER_MAXRES. 1 would be useless. + double r[DISC_LADDER_MAXRES]; // Don't use 0 for valid resistors. That is a short. + double vBias; // Voltage Bias resistor is tied to (0 = not used) + double rBias; // Additional resistor tied to vBias (0 = not used) + double rGnd; // Resistor tied to ground (0 = not used) + double cFilter; // Filtering cap (0 = not used) +}; + + +struct discrete_integrate_info +{ + UINT32 type; + double r1; // r1a + r1b + double r2; // r2a + r2b + double r3; // r3a + r3b + double c; + double v1; + double vP; + double f0; + double f1; + double f2; +}; + + +#define DISC_MAX_MIXER_INPUTS 8 +struct discrete_mixer_desc +{ + int type; + double r[DISC_MAX_MIXER_INPUTS]; /* static input resistance values. These are in series with rNode, if used. */ + int r_node[DISC_MAX_MIXER_INPUTS]; /* variable resistance nodes, if needed. 0 if not used. */ + double c[DISC_MAX_MIXER_INPUTS]; + double rI; + double rF; + double cF; + double cAmp; + double vRef; + double gain; /* Scale value to get output close to +/- 32767 */ +}; + + +struct discrete_op_amp_info +{ + UINT32 type; + double r1; + double r2; + double r3; + double r4; + double c; + double vN; // Op amp B- + double vP; // Op amp B+ +}; + + +struct discrete_op_amp_1sht_info +{ + UINT32 type; + double r1; + double r2; + double r3; + double r4; + double r5; + double c1; + double c2; + double vN; // Op amp B- + double vP; // Op amp B+ +}; + + +struct discrete_op_amp_tvca_info +{ + double r1; + double r2; // r2a + r2b + double r3; // r3a + r3b + double r4; + double r5; + double r6; + double r7; + double r8; + double r9; + double r10; + double r11; + double c1; + double c2; + double c3; + double c4; + double v1; + double v2; + double v3; + double vP; + int f0; + int f1; + int f2; + int f3; + int f4; + int f5; +}; + + +struct discrete_op_amp_filt_info +{ + double r1; + double r2; + double r3; + double r4; + double rF; + double c1; + double c2; + double c3; + double vRef; + double vP; + double vN; +}; + + +#define DEFAULT_555_CHARGE -1 +#define DEFAULT_555_HIGH -1 +#define DEFAULT_555_VALUES DEFAULT_555_CHARGE, DEFAULT_555_HIGH + +struct discrete_555_desc +{ + int options; /* bit mapped options */ + double v_pos; /* B+ voltage of 555 */ + double v_charge; /* voltage to charge circuit (Defaults to v_pos) */ + double v_out_high; /* High output voltage of 555 (Defaults to v_pos - 1.2V) */ +}; + +#define DEFAULT_555_CC_SOURCE DEFAULT_555_CHARGE + +struct discrete_555_cc_desc +{ + int options; /* bit mapped options */ + double v_pos; /* B+ voltage of 555 */ + double v_cc_source; /* Voltage of the Constant Current source */ + double v_out_high; /* High output voltage of 555 (Defaults to v_pos - 1.2V) */ + double v_cc_junction; /* The voltage drop of the Constant Current source transitor (0 if Op Amp) */ +}; + + +struct discrete_555_vco1_desc +{ + int options; /* bit mapped options */ + double r1, r2, r3, r4, c; + double v_pos; /* B+ voltage of 555 */ + double v_charge; /* (ignored) */ + double v_out_high; /* High output voltage of 555 (Defaults to v_pos - 1.2V) */ +}; + + +struct discrete_adsr +{ + double attack_time; /* All times are in seconds */ + double attack_value; + double decay_time; + double decay_value; + double sustain_time; + double sustain_value; + double release_time; + double release_value; +}; + + +/************************************* + * + * The node numbers themselves + * + *************************************/ + +#define NODE0_DEF(_x) NODE_ ## 0 ## _x = (0x40000000 + (_x) * DISCRETE_MAX_OUTPUTS), \ + NODE_ ## 0 ## _x ## _00 = NODE_ ## 0 ## _x, NODE_ ## 0 ## _x ## _01, NODE_ ## 0 ## _x ## _02, NODE_ ## 0 ## _x ## _03, \ + NODE_ ## 0 ## _x ## _04, NODE_ ## 0 ## _x ## _05, NODE_ ## 0 ## _x ## _06, NODE_ ## 0 ## _x ## _07 +#define NODE_DEF(_x) NODE_ ## _x = (0x40000000 + (_x) * DISCRETE_MAX_OUTPUTS), \ + NODE_ ## _x ## _00 = NODE_ ## _x, NODE_ ## _x ## _01, NODE_ ## _x ## _02, NODE_ ## _x ## _03, \ + NODE_ ## _x ## _04, NODE_ ## _x ## _05, NODE_ ## _x ## _06, NODE_ ## _x ## _07 + +enum { + NODE0_DEF(0), NODE0_DEF(1), NODE0_DEF(2), NODE0_DEF(3), NODE0_DEF(4), NODE0_DEF(5), NODE0_DEF(6), NODE0_DEF(7), NODE0_DEF(8), NODE0_DEF(9), + NODE_DEF(10), NODE_DEF(11), NODE_DEF(12), NODE_DEF(13), NODE_DEF(14), NODE_DEF(15), NODE_DEF(16), NODE_DEF(17), NODE_DEF(18), NODE_DEF(19), + NODE_DEF(20), NODE_DEF(21), NODE_DEF(22), NODE_DEF(23), NODE_DEF(24), NODE_DEF(25), NODE_DEF(26), NODE_DEF(27), NODE_DEF(28), NODE_DEF(29), + NODE_DEF(30), NODE_DEF(31), NODE_DEF(32), NODE_DEF(33), NODE_DEF(34), NODE_DEF(35), NODE_DEF(36), NODE_DEF(37), NODE_DEF(38), NODE_DEF(39), + NODE_DEF(40), NODE_DEF(41), NODE_DEF(42), NODE_DEF(43), NODE_DEF(44), NODE_DEF(45), NODE_DEF(46), NODE_DEF(47), NODE_DEF(48), NODE_DEF(49), + NODE_DEF(50), NODE_DEF(51), NODE_DEF(52), NODE_DEF(53), NODE_DEF(54), NODE_DEF(55), NODE_DEF(56), NODE_DEF(57), NODE_DEF(58), NODE_DEF(59), + NODE_DEF(60), NODE_DEF(61), NODE_DEF(62), NODE_DEF(63), NODE_DEF(64), NODE_DEF(65), NODE_DEF(66), NODE_DEF(67), NODE_DEF(68), NODE_DEF(69), + NODE_DEF(70), NODE_DEF(71), NODE_DEF(72), NODE_DEF(73), NODE_DEF(74), NODE_DEF(75), NODE_DEF(76), NODE_DEF(77), NODE_DEF(78), NODE_DEF(79), + NODE_DEF(80), NODE_DEF(81), NODE_DEF(82), NODE_DEF(83), NODE_DEF(84), NODE_DEF(85), NODE_DEF(86), NODE_DEF(87), NODE_DEF(88), NODE_DEF(89), + NODE_DEF(90), NODE_DEF(91), NODE_DEF(92), NODE_DEF(93), NODE_DEF(94), NODE_DEF(95), NODE_DEF(96), NODE_DEF(97), NODE_DEF(98), NODE_DEF(99), + NODE_DEF(100),NODE_DEF(101),NODE_DEF(102),NODE_DEF(103),NODE_DEF(104),NODE_DEF(105),NODE_DEF(106),NODE_DEF(107),NODE_DEF(108),NODE_DEF(109), + NODE_DEF(110),NODE_DEF(111),NODE_DEF(112),NODE_DEF(113),NODE_DEF(114),NODE_DEF(115),NODE_DEF(116),NODE_DEF(117),NODE_DEF(118),NODE_DEF(119), + NODE_DEF(120),NODE_DEF(121),NODE_DEF(122),NODE_DEF(123),NODE_DEF(124),NODE_DEF(125),NODE_DEF(126),NODE_DEF(127),NODE_DEF(128),NODE_DEF(129), + NODE_DEF(130),NODE_DEF(131),NODE_DEF(132),NODE_DEF(133),NODE_DEF(134),NODE_DEF(135),NODE_DEF(136),NODE_DEF(137),NODE_DEF(138),NODE_DEF(139), + NODE_DEF(140),NODE_DEF(141),NODE_DEF(142),NODE_DEF(143),NODE_DEF(144),NODE_DEF(145),NODE_DEF(146),NODE_DEF(147),NODE_DEF(148),NODE_DEF(149), + NODE_DEF(150),NODE_DEF(151),NODE_DEF(152),NODE_DEF(153),NODE_DEF(154),NODE_DEF(155),NODE_DEF(156),NODE_DEF(157),NODE_DEF(158),NODE_DEF(159), + NODE_DEF(160),NODE_DEF(161),NODE_DEF(162),NODE_DEF(163),NODE_DEF(164),NODE_DEF(165),NODE_DEF(166),NODE_DEF(167),NODE_DEF(168),NODE_DEF(169), + NODE_DEF(170),NODE_DEF(171),NODE_DEF(172),NODE_DEF(173),NODE_DEF(174),NODE_DEF(175),NODE_DEF(176),NODE_DEF(177),NODE_DEF(178),NODE_DEF(179), + NODE_DEF(180),NODE_DEF(181),NODE_DEF(182),NODE_DEF(183),NODE_DEF(184),NODE_DEF(185),NODE_DEF(186),NODE_DEF(187),NODE_DEF(188),NODE_DEF(189), + NODE_DEF(190),NODE_DEF(191),NODE_DEF(192),NODE_DEF(193),NODE_DEF(194),NODE_DEF(195),NODE_DEF(196),NODE_DEF(197),NODE_DEF(198),NODE_DEF(199), + NODE_DEF(200),NODE_DEF(201),NODE_DEF(202),NODE_DEF(203),NODE_DEF(204),NODE_DEF(205),NODE_DEF(206),NODE_DEF(207),NODE_DEF(208),NODE_DEF(209), + NODE_DEF(210),NODE_DEF(211),NODE_DEF(212),NODE_DEF(213),NODE_DEF(214),NODE_DEF(215),NODE_DEF(216),NODE_DEF(217),NODE_DEF(218),NODE_DEF(219), + NODE_DEF(220),NODE_DEF(221),NODE_DEF(222),NODE_DEF(223),NODE_DEF(224),NODE_DEF(225),NODE_DEF(226),NODE_DEF(227),NODE_DEF(228),NODE_DEF(229), + NODE_DEF(230),NODE_DEF(231),NODE_DEF(232),NODE_DEF(233),NODE_DEF(234),NODE_DEF(235),NODE_DEF(236),NODE_DEF(237),NODE_DEF(238),NODE_DEF(239), + NODE_DEF(240),NODE_DEF(241),NODE_DEF(242),NODE_DEF(243),NODE_DEF(244),NODE_DEF(245),NODE_DEF(246),NODE_DEF(247),NODE_DEF(248),NODE_DEF(249), + NODE_DEF(250),NODE_DEF(251),NODE_DEF(252),NODE_DEF(253),NODE_DEF(254),NODE_DEF(255),NODE_DEF(256),NODE_DEF(257),NODE_DEF(258),NODE_DEF(259), + NODE_DEF(260),NODE_DEF(261),NODE_DEF(262),NODE_DEF(263),NODE_DEF(264),NODE_DEF(265),NODE_DEF(266),NODE_DEF(267),NODE_DEF(268),NODE_DEF(269), + NODE_DEF(270),NODE_DEF(271),NODE_DEF(272),NODE_DEF(273),NODE_DEF(274),NODE_DEF(275),NODE_DEF(276),NODE_DEF(277),NODE_DEF(278),NODE_DEF(279), + NODE_DEF(280),NODE_DEF(281),NODE_DEF(282),NODE_DEF(283),NODE_DEF(284),NODE_DEF(285),NODE_DEF(286),NODE_DEF(287),NODE_DEF(288),NODE_DEF(289), + NODE_DEF(290),NODE_DEF(291),NODE_DEF(292),NODE_DEF(293),NODE_DEF(294),NODE_DEF(295),NODE_DEF(296),NODE_DEF(297),NODE_DEF(298),NODE_DEF(299) +}; + +/* Some Pre-defined nodes for convenience */ + +#define NODE(_x) (NODE_00 + (_x) * DISCRETE_MAX_OUTPUTS) +#define NODE_SUB(_x, _y) ((_x) + (_y)) + +#if DISCRETE_MAX_OUTPUTS == 8 +#define NODE_CHILD_NODE_NUM(_x) ((int)(_x) & 7) +#define NODE_DEFAULT_NODE(_x) ((int)(_x) & ~7) +#define NODE_INDEX(_x) (((int)(_x) - NODE_START)>>3) +#else +#error "DISCRETE_MAX_OUTPUTS != 8" +#endif + +#define NODE_RELATIVE(_x, _y) (NODE(NODE_INDEX(_x) + (_y))) + +#define NODE_NC NODE_00 +#define NODE_SPECIAL NODE(DISCRETE_MAX_NODES) + +#define NODE_START NODE_00 +#define NODE_END NODE_SPECIAL + +#define IS_VALUE_A_NODE(val) (((val) > NODE_START) && ((val) <= NODE_END)) + +// Optional node such as used in CR_FILTER +#define OPT_NODE(val) (int) val +/************************************* + * + * Enumerated values for Node types + * in the simulation + * + * DSS - Discrete Sound Source + * DST - Discrete Sound Transform + * DSD - Discrete Sound Device + * DSO - Discrete Sound Output + * + *************************************/ + +enum discrete_node_type +{ + DSS_NULL, /* Nothing, nill, zippo, only to be used as terminating node */ + DSS_NOP, /* just do nothing, placeholder for potential DISCRETE_REPLACE in parent block */ + + /* standard node */ + + DSS_NODE, /* a standard node */ + + /* Custom */ + DST_CUSTOM, /* whatever you want */ + + /* Debugging */ + DSO_CSVLOG, /* Dump nodes as csv file */ + DSO_WAVLOG, /* Dump nodes as wav file */ + + /* Parallel execution */ + DSO_TASK_START, /* start of parallel task */ + DSO_TASK_END, /* end of parallel task */ + + /* Output Node -- this must be the last entry in this enum! */ + DSO_OUTPUT, /* The final output node */ + + /* Import another blocklist */ + DSO_IMPORT, /* import from another discrete block */ + DSO_REPLACE, /* replace next node */ + DSO_DELETE, /* delete nodes */ + + /* Marks end of this enum -- must be last entry ! */ + DSO_LAST +}; + +/************************************* + * + * Forward declarations + * + *************************************/ + +struct discrete_block; +class discrete_node_base_factory; +class discrete_task; +class discrete_base_node; +class discrete_dss_input_stream_node; +class discrete_device; +typedef vector_t node_list_t; +typedef vector_t istream_node_list_t; +typedef vector_t task_list_t; + + +/************************************* + * + * Discrete module definition + * + *************************************/ + + +/************************************* + * + * The discrete sound blocks as + * defined in the drivers + * + *************************************/ + +struct discrete_block +{ + int node; /* Output node number */ + discrete_base_node *(*factory)(discrete_device * pdev, const discrete_block *block); + int type; /* see defines below */ + int active_inputs; /* Number of active inputs on this node type */ + int input_node[DISCRETE_MAX_INPUTS];/* input/control nodes */ + double initial[DISCRETE_MAX_INPUTS]; /* Initial values */ + const void * custom; /* Custom function specific initialisation data */ + const char * name; /* Node Name */ + const char * mod_name; /* Module / class name */ +}; +typedef vector_t sound_block_list_t; + +/************************************* + * + * Node interfaces + * + *************************************/ + +class discrete_step_interface +{ +public: + virtual ~discrete_step_interface() { } + + virtual void step(void) = 0; + osd_ticks_t run_time; + discrete_base_node * self; +}; +typedef vector_t node_step_list_t; + +class discrete_input_interface +{ +public: + virtual ~discrete_input_interface() { } + + virtual void input_write(int sub_node, UINT8 data ) = 0; +}; + +class discrete_sound_output_interface +{ +public: + virtual ~discrete_sound_output_interface() { } + + virtual void set_output_ptr(stream_sample_t *ptr) = 0; +}; + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_DISCRETE_ADD(_tag, _clock, _intf) \ + MCFG_DEVICE_ADD(_tag, DISCRETE, _clock) \ + MCFG_DISCRETE_INTF(_intf) + +#define MCFG_DISCRETE_REPLACE(_tag, _clock, _intf) \ + MCFG_DEVICE_REPLACE(_tag, DISCRETE, _clock) \ + MCFG_DISCRETE_INTF(_intf) + +#define MCFG_DISCRETE_INTF(_intf) \ + discrete_device::static_set_intf(*device, (const discrete_block *)&(_intf##_discrete_interface)); + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class discrete_sound_output_interface; +typedef vector_t node_output_list_t; + + +// ======================> discrete_device + +class discrete_device : public device_t +{ + //friend class discrete_base_node; + +protected: + // construction/destruction + discrete_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock); + +public: + // inline configuration helpers + static void static_set_intf(device_t &device, const discrete_block *intf); + + DECLARE_READ8_MEMBER(read); + DECLARE_WRITE8_MEMBER(write); + virtual ~discrete_device(void); + + /* --------------------------------- */ + + virtual void update_to_current_time(void) const { } + + /* process a number of samples */ + void process(int samples); + + /* access to the discrete_logging facility */ + void CLIB_DECL discrete_log(const char *text, ...) const ATTR_PRINTF(2,3); + + /* get pointer to a info struct node ref */ + const double *node_output_ptr(int onode); + + /* FIXME: this is used by csv and wav logs - going forward, identifiers should be explicitly passed */ + int same_module_index(const discrete_base_node &node); + + /* get node */ + discrete_base_node *discrete_find_node(int node); + + /* are we profiling */ + inline int profiling(void) { return m_profiling; } + + inline int sample_rate(void) { return m_sample_rate; } + inline double sample_time(void) { return m_sample_time; } + + +protected: + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_stop(); + + // configuration state + const discrete_block *m_intf; + + // internal state + + /* --------------------------------- */ + + /* emulation info */ + int m_sample_rate; + double m_sample_time; + double m_neg_sample_time; + + /* list of all nodes */ + node_list_t m_node_list; /* node_description * */ + +private: + void discrete_build_list(const discrete_block *intf, sound_block_list_t &block_list); + void discrete_sanity_check(const sound_block_list_t &block_list); + void display_profiling(void); + void init_nodes(const sound_block_list_t &block_list); + + /* internal node tracking */ + discrete_base_node ** m_indexed_node; + + /* tasks */ + task_list_t task_list; /* discrete_task_context * */ + + /* debugging statistics */ + FILE * m_disclogfile; + + /* parallel tasks */ + osd_work_queue * m_queue; + + /* profiling */ + int m_profiling; + UINT64 m_total_samples; + UINT64 m_total_stream_updates; +}; + +// ======================> discrete_sound_device + +class discrete_sound_device : public discrete_device, + public device_sound_interface +{ +public: + // construction/destruction + discrete_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual ~discrete_sound_device(void) { }; + + /* --------------------------------- */ + + virtual void update_to_current_time(void) const { m_stream->update(); } + + sound_stream *get_stream(void) { return m_stream; } +protected: + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_sound_interface overrides + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + +private: + /* the output stream */ + sound_stream *m_stream; + + /* the input streams */ + istream_node_list_t m_input_stream_list; + /* output node tracking */ + node_output_list_t m_output_list; +}; + +// device type definition +extern const device_type DISCRETE; + +/************************************* + * + * Node class + * + *************************************/ + +class discrete_base_node +{ + friend class discrete_device; + template friend class discrete_node_factory; + friend class discrete_task; + +public: + + virtual void reset(void) { } + virtual void start(void) { } + virtual void stop(void) { } + virtual void save_state(void); + + virtual int max_output(void) { return 1; }; + + inline bool interface(discrete_step_interface *&intf) const { intf = m_step_intf; return (intf != NULL); } + inline bool interface(discrete_input_interface *&intf) const { intf = m_input_intf; return (intf != NULL); } + inline bool interface(discrete_sound_output_interface *&intf) const { intf = m_output_intf; return (intf != NULL); } + + /* get the input value from node #n */ + inline double input(int n) { return *(m_input[n]); } + + /* set an output */ + inline void set_output(int n, double val) { m_output[n] = val; } + + /* Return the node index, i.e. X from NODE(X) */ + inline int index(void) { return NODE_INDEX(m_block->node); } + + /* Return the node number, i.e. NODE(X) */ + inline int block_node(void) const { return m_block->node; } + + /* Custom function specific initialisation data */ + inline const void *custom_data(void) { return m_custom; } + + inline int input_node(int inputnum) { return m_block->input_node[inputnum]; } + + /* Number of active inputs on this node type */ + inline int active_inputs(void) { return m_active_inputs; } + /* Bit Flags. 1 in bit location means input_is_node */ + inline int input_is_node(void) { return m_input_is_node; } + + inline double sample_time(void) { return m_device->sample_time(); } + inline int sample_rate(void) { return m_device->sample_rate(); } + + const char * module_name(void) { return m_block->mod_name; } + inline int module_type(void) const { return m_block->type; } + +protected: + + discrete_base_node(); + virtual ~discrete_base_node(); + + /* finish node setup after allocation is complete */ + void init(discrete_device * pdev, const discrete_block *block); + + void resolve_input_nodes(void); + + double m_output[DISCRETE_MAX_OUTPUTS]; /* The node's last output value */ + const double * m_input[DISCRETE_MAX_INPUTS]; /* Addresses of Input values */ + discrete_device * m_device; /* Points to the parent */ + +private: + + const discrete_block * m_block; /* Points to the node's setup block. */ + int m_active_inputs; /* Number of active inputs on this node type */ + + const void * m_custom; /* Custom function specific initialisation data */ + int m_input_is_node; + + discrete_step_interface * m_step_intf; + discrete_input_interface * m_input_intf; + discrete_sound_output_interface * m_output_intf; +}; + +class discrete_node_base_factory +{ +public: + virtual discrete_base_node *Create(discrete_device * pdev, const discrete_block *block) = 0; + virtual ~discrete_node_base_factory() {} +}; + +template +class discrete_node_factory : public discrete_node_base_factory +{ +public: + discrete_base_node *Create(discrete_device * pdev, const discrete_block *block); +}; + +template +discrete_base_node * discrete_node_factory::Create(discrete_device * pdev, const discrete_block *block) +{ + discrete_base_node *r = auto_alloc_clear(pdev->machine(), C); + + r->init(pdev, block); + return r; +} + +/************************************* + * + * Class definitions for nodes + * + *************************************/ + +#include "disc_cls.h" + +/************************************* + * + * Encapsulation macros for defining + * your simulation + * + *************************************/ + +template +discrete_base_node *discrete_create_node(discrete_device * pdev, const discrete_block *block) +{ + return discrete_node_factory< C >().Create(pdev, block); +} + +#define DISCRETE_SOUND_EXTERN(name) extern const discrete_block name##_discrete_interface[] +#define DISCRETE_SOUND_START(name) const discrete_block name##_discrete_interface[] = { +//#define DSC_SND_ENTRY(_nod, _class, _dss, _num, _iact, _iinit, _custom, _name) { _nod, new discrete_node_factory< DISCRETE_CLASS_NAME(_class) >, _dss, _num, _iact, _iinit, _custom, _name, # _class } +#define DSC_SND_ENTRY(_nod, _class, _dss, _num, _iact, _iinit, _custom, _name) { _nod, &discrete_create_node< DISCRETE_CLASS_NAME(_class) >, _dss, _num, _iact, _iinit, _custom, _name, # _class } + + +#define DISCRETE_SOUND_END DSC_SND_ENTRY( NODE_00, special, DSS_NULL , 0, DSE( NODE_NC ), DSE( 0 ) ,NULL ,"DISCRETE_SOUND_END" ) }; +#define DSE( ... ) { __VA_ARGS__ } + +/* Module Name out, enum value, #in, {variable inputs}, {static inputs}, data pointer, "name" */ + +/* from disc_inp.inc */ +#define DISCRETE_ADJUSTMENT(NODE,MIN,MAX,LOGLIN,TAG) DSC_SND_ENTRY( NODE, dss_adjustment , DSS_NODE , 6, DSE( NODE_NC,NODE_NC,NODE_NC,NODE_NC,NODE_NC,NODE_NC ), DSE( MIN,MAX,LOGLIN,0 ,0 ,100 ), TAG , "DISCRETE_ADJUSTMENT" ), +#define DISCRETE_ADJUSTMENTX(NODE,MIN,MAX,LOGLIN,TAG,PMIN,PMAX) DSC_SND_ENTRY( NODE, dss_adjustment , DSS_NODE , 6, DSE( NODE_NC,NODE_NC,NODE_NC,NODE_NC,NODE_NC,NODE_NC ), DSE( MIN,MAX,LOGLIN,0 ,PMIN,PMAX ), TAG , "DISCRETE_ADJUSTMENTX" ), +#define DISCRETE_CONSTANT(NODE,CONST) DSC_SND_ENTRY( NODE, dss_constant , DSS_NODE , 1, DSE( NODE_NC ), DSE( CONST ) ,NULL ,"DISCRETE_CONSTANT" ), +#define DISCRETE_INPUT_DATA(NODE) DSC_SND_ENTRY( NODE, dss_input_data , DSS_NODE , 3, DSE( NODE_NC,NODE_NC,NODE_NC ), DSE( 1,0,0 ), NULL, "DISCRETE_INPUT_DATA" ), +#define DISCRETE_INPUTX_DATA(NODE,GAIN,OFFSET,INIT) DSC_SND_ENTRY( NODE, dss_input_data , DSS_NODE , 3, DSE( NODE_NC,NODE_NC,NODE_NC ), DSE( GAIN,OFFSET,INIT ), NULL, "DISCRETE_INPUTX_DATA" ), +#define DISCRETE_INPUT_LOGIC(NODE) DSC_SND_ENTRY( NODE, dss_input_logic , DSS_NODE , 3, DSE( NODE_NC,NODE_NC,NODE_NC ), DSE( 1,0,0 ), NULL, "DISCRETE_INPUT_LOGIC" ), +#define DISCRETE_INPUTX_LOGIC(NODE,GAIN,OFFSET,INIT) DSC_SND_ENTRY( NODE, dss_input_logic , DSS_NODE , 3, DSE( NODE_NC,NODE_NC,NODE_NC ), DSE( GAIN,OFFSET,INIT ), NULL, "DISCRETE_INPUTX_LOGIC" ), +#define DISCRETE_INPUT_NOT(NODE) DSC_SND_ENTRY( NODE, dss_input_not , DSS_NODE , 3, DSE( NODE_NC,NODE_NC,NODE_NC ), DSE( 1,0,0 ), NULL, "DISCRETE_INPUT_NOT" ), +#define DISCRETE_INPUTX_NOT(NODE,GAIN,OFFSET,INIT) DSC_SND_ENTRY( NODE, dss_input_not , DSS_NODE , 3, DSE( NODE_NC,NODE_NC,NODE_NC ), DSE( GAIN,OFFSET,INIT ), NULL, "DISCRETE_INPUTX_NOT" ), +#define DISCRETE_INPUT_PULSE(NODE,INIT) DSC_SND_ENTRY( NODE, dss_input_pulse , DSS_NODE , 3, DSE( NODE_NC,NODE_NC,NODE_NC ), DSE( 1,0,INIT ), NULL, "DISCRETE_INPUT_PULSE" ), + +#define DISCRETE_INPUT_STREAM(NODE, NUM) DSC_SND_ENTRY( NODE, dss_input_stream, DSS_NODE , 3, DSE( NUM,NODE_NC,NODE_NC ), DSE( NUM,1,0 ), NULL, "DISCRETE_INPUT_STREAM" ), +#define DISCRETE_INPUTX_STREAM(NODE, NUM, GAIN,OFFSET) DSC_SND_ENTRY( NODE, dss_input_stream, DSS_NODE , 3, DSE( NUM,NODE_NC,NODE_NC ), DSE( NUM,GAIN,OFFSET ), NULL, "DISCRETE_INPUTX_STREAM" ), + +#define DISCRETE_INPUT_BUFFER(NODE, NUM) DSC_SND_ENTRY( NODE, dss_input_buffer, DSS_NODE , 3, DSE( NUM,NODE_NC,NODE_NC ), DSE( NUM,1,0 ), NULL, "DISCRETE_INPUT_BUFFER" ), + +/* from disc_wav.inc */ +/* generic modules */ +#define DISCRETE_COUNTER(NODE,ENAB,RESET,CLK,MIN,MAX,DIR,INIT0,CLKTYPE) DSC_SND_ENTRY( NODE, dss_counter , DSS_NODE , 8, DSE( ENAB,RESET,CLK,NODE_NC,NODE_NC,DIR,INIT0,NODE_NC ), DSE( ENAB,RESET,CLK,MIN,MAX,DIR,INIT0,CLKTYPE ), NULL, "DISCRETE_COUNTER" ), +#define DISCRETE_COUNTER_7492(NODE,ENAB,RESET,CLK,CLKTYPE) DSC_SND_ENTRY( NODE, dss_counter , DSS_NODE , 8, DSE( ENAB,RESET,CLK,NODE_NC,NODE_NC,NODE_NC,NODE_NC,NODE_NC ), DSE( ENAB,RESET,CLK,CLKTYPE,0,1,0,DISC_COUNTER_IS_7492 ), NULL, "DISCRETE_COUNTER_7492" ), +#define DISCRETE_LFSR_NOISE(NODE,ENAB,RESET,CLK,AMPL,FEED,BIAS,LFSRTB) DSC_SND_ENTRY( NODE, dss_lfsr_noise , DSS_NODE , 6, DSE( ENAB,RESET,CLK,AMPL,FEED,BIAS ), DSE( ENAB,RESET,CLK,AMPL,FEED,BIAS ), LFSRTB, "DISCRETE_LFSR_NOISE" ), +#define DISCRETE_NOISE(NODE,ENAB,FREQ,AMPL,BIAS) DSC_SND_ENTRY( NODE, dss_noise , DSS_NODE , 4, DSE( ENAB,FREQ,AMPL,BIAS ), DSE( ENAB,FREQ,AMPL,BIAS ), NULL, "DISCRETE_NOISE" ), +#define DISCRETE_NOTE(NODE,ENAB,CLK,DATA,MAX1,MAX2,CLKTYPE) DSC_SND_ENTRY( NODE, dss_note , DSS_NODE , 6, DSE( ENAB,CLK,DATA,NODE_NC,NODE_NC,NODE_NC ), DSE( ENAB,CLK,DATA,MAX1,MAX2,CLKTYPE ), NULL, "DISCRETE_NOTE" ), +#define DISCRETE_SAWTOOTHWAVE(NODE,ENAB,FREQ,AMPL,BIAS,GRAD,PHASE) DSC_SND_ENTRY( NODE, dss_sawtoothwave, DSS_NODE , 6, DSE( ENAB,FREQ,AMPL,BIAS,NODE_NC,NODE_NC ), DSE( ENAB,FREQ,AMPL,BIAS,GRAD,PHASE ), NULL, "DISCRETE_SAWTOOTHWAVE" ), +#define DISCRETE_SINEWAVE(NODE,ENAB,FREQ,AMPL,BIAS,PHASE) DSC_SND_ENTRY( NODE, dss_sinewave , DSS_NODE , 5, DSE( ENAB,FREQ,AMPL,BIAS,NODE_NC ), DSE( ENAB,FREQ,AMPL,BIAS,PHASE ), NULL, "DISCRETE_SINEWAVE" ), +#define DISCRETE_SQUAREWAVE(NODE,ENAB,FREQ,AMPL,DUTY,BIAS,PHASE) DSC_SND_ENTRY( NODE, dss_squarewave , DSS_NODE , 6, DSE( ENAB,FREQ,AMPL,DUTY,BIAS,NODE_NC ), DSE( ENAB,FREQ,AMPL,DUTY,BIAS,PHASE ), NULL, "DISCRETE_SQUAREWAVE" ), +#define DISCRETE_SQUAREWFIX(NODE,ENAB,FREQ,AMPL,DUTY,BIAS,PHASE) DSC_SND_ENTRY( NODE, dss_squarewfix , DSS_NODE , 6, DSE( ENAB,FREQ,AMPL,DUTY,BIAS,NODE_NC ), DSE( ENAB,FREQ,AMPL,DUTY,BIAS,PHASE ), NULL, "DISCRETE_SQUAREWFIX" ), +#define DISCRETE_SQUAREWAVE2(NODE,ENAB,AMPL,T_OFF,T_ON,BIAS,TSHIFT) DSC_SND_ENTRY( NODE, dss_squarewave2 , DSS_NODE , 6, DSE( ENAB,AMPL,T_OFF,T_ON,BIAS,NODE_NC ), DSE( ENAB,AMPL,T_OFF,T_ON,BIAS,TSHIFT ), NULL, "DISCRETE_SQUAREWAVE2" ), +#define DISCRETE_TRIANGLEWAVE(NODE,ENAB,FREQ,AMPL,BIAS,PHASE) DSC_SND_ENTRY( NODE, dss_trianglewave, DSS_NODE , 5, DSE( ENAB,FREQ,AMPL,BIAS,NODE_NC ), DSE( ENAB,FREQ,AMPL,BIAS,PHASE ), NULL, "DISCRETE_TRIANGLEWAVE" ), +/* Component specific */ +#define DISCRETE_INVERTER_OSC(NODE,ENAB,MOD,RCHARGE,RP,C,R2,INFO) DSC_SND_ENTRY( NODE, dss_inverter_osc, DSS_NODE , 6, DSE( ENAB,MOD,NODE_NC,NODE_NC,NODE_NC,NODE_NC ), DSE( ENAB,MOD,RCHARGE,RP,C,R2 ), INFO, "DISCRETE_INVERTER_OSC" ), +#define DISCRETE_OP_AMP_OSCILLATOR(NODE,ENAB,INFO) DSC_SND_ENTRY( NODE, dss_op_amp_osc , DSS_NODE , 1, DSE( ENAB ), DSE( ENAB ), INFO, "DISCRETE_OP_AMP_OSCILLATOR" ), +#define DISCRETE_OP_AMP_VCO1(NODE,ENAB,VMOD1,INFO) DSC_SND_ENTRY( NODE, dss_op_amp_osc , DSS_NODE , 2, DSE( ENAB,VMOD1 ), DSE( ENAB,VMOD1 ), INFO, "DISCRETE_OP_AMP_VCO1" ), +#define DISCRETE_OP_AMP_VCO2(NODE,ENAB,VMOD1,VMOD2,INFO) DSC_SND_ENTRY( NODE, dss_op_amp_osc , DSS_NODE , 3, DSE( ENAB,VMOD1,VMOD2 ), DSE( ENAB,VMOD1,VMOD2 ), INFO, "DISCRETE_OP_AMP_VCO2" ), +#define DISCRETE_SCHMITT_OSCILLATOR(NODE,ENAB,INP0,AMPL,TABLE) DSC_SND_ENTRY( NODE, dss_schmitt_osc , DSS_NODE , 3, DSE( ENAB,INP0,AMPL ), DSE( ENAB,INP0,AMPL ), TABLE, "DISCRETE_SCHMITT_OSCILLATOR" ), +/* Not yet implemented */ +#define DISCRETE_ADSR_ENV(NODE,ENAB,TRIGGER,GAIN,ADSRTB) DSC_SND_ENTRY( NODE, dss_adsr , DSS_NODE , 3, DSE( ENAB,TRIGGER,GAIN ), DSE( ENAB,TRIGGER,GAIN ), ADSRTB, "DISCRETE_ADSR_ENV" ), + +/* from disc_mth.inc */ +/* generic modules */ +#define DISCRETE_ADDER2(NODE,ENAB,INP0,INP1) DSC_SND_ENTRY( NODE, dst_adder , DSS_NODE , 3, DSE( ENAB,INP0,INP1 ), DSE( ENAB,INP0,INP1 ), NULL, "DISCRETE_ADDER2" ), +#define DISCRETE_ADDER3(NODE,ENAB,INP0,INP1,INP2) DSC_SND_ENTRY( NODE, dst_adder , DSS_NODE , 4, DSE( ENAB,INP0,INP1,INP2 ), DSE( ENAB,INP0,INP1,INP2 ), NULL, "DISCRETE_ADDER3" ), +#define DISCRETE_ADDER4(NODE,ENAB,INP0,INP1,INP2,INP3) DSC_SND_ENTRY( NODE, dst_adder , DSS_NODE , 5, DSE( ENAB,INP0,INP1,INP2,INP3 ), DSE( ENAB,INP0,INP1,INP2,INP3 ), NULL, "DISCRETE_ADDER4" ), +#define DISCRETE_CLAMP(NODE,INP0,MIN,MAX) DSC_SND_ENTRY( NODE, dst_clamp , DSS_NODE , 3, DSE( INP0,MIN,MAX ), DSE( INP0,MIN,MAX ), NULL, "DISCRETE_CLAMP" ), +#define DISCRETE_DIVIDE(NODE,ENAB,INP0,INP1) DSC_SND_ENTRY( NODE, dst_divide , DSS_NODE , 3, DSE( ENAB,INP0,INP1 ), DSE( ENAB,INP0,INP1 ), NULL, "DISCRETE_DIVIDE" ), +#define DISCRETE_GAIN(NODE,INP0,GAIN) DSC_SND_ENTRY( NODE, dst_gain , DSS_NODE , 3, DSE( INP0,NODE_NC,NODE_NC ), DSE( INP0,GAIN,0 ), NULL, "DISCRETE_GAIN" ), +#define DISCRETE_INVERT(NODE,INP0) DSC_SND_ENTRY( NODE, dst_gain , DSS_NODE , 3, DSE( INP0,NODE_NC,NODE_NC ), DSE( INP0,-1,0 ), NULL, "DISCRETE_INVERT" ), +#define DISCRETE_LOGIC_INVERT(NODE,INP0) DSC_SND_ENTRY( NODE, dst_logic_inv , DSS_NODE , 1, DSE( INP0 ), DSE( INP0 ), NULL, "DISCRETE_LOGIC_INVERT" ), + +#define DISCRETE_BIT_DECODE(NODE, INP, BIT_N, VOUT) DSC_SND_ENTRY( NODE, dst_bits_decode , DSS_NODE , 4, DSE( INP,NODE_NC,NODE_NC,NODE_NC ), DSE( INP,BIT_N,BIT_N,VOUT ), NULL, "DISCRETE_BIT_DECODE" ), +#define DISCRETE_BITS_DECODE(NODE, INP, BIT_FROM, BIT_TO, VOUT) DSC_SND_ENTRY( NODE, dst_bits_decode , DSS_NODE , 4, DSE( INP,NODE_NC,NODE_NC,NODE_NC ), DSE( INP,BIT_FROM,BIT_TO,VOUT ), NULL, "DISCRETE_BITS_DECODE" ), + +#define DISCRETE_LOGIC_AND(NODE,INP0,INP1) DSC_SND_ENTRY( NODE, dst_logic_and , DSS_NODE , 4, DSE( INP0,INP1,NODE_NC,NODE_NC ), DSE( INP0,INP1,1.0,1.0 ), NULL, "DISCRETE_LOGIC_AND" ), +#define DISCRETE_LOGIC_AND3(NODE,INP0,INP1,INP2) DSC_SND_ENTRY( NODE, dst_logic_and , DSS_NODE , 4, DSE( INP0,INP1,INP2,NODE_NC ), DSE( INP0,INP1,INP2,1.0 ), NULL, "DISCRETE_LOGIC_AND3" ), +#define DISCRETE_LOGIC_AND4(NODE,INP0,INP1,INP2,INP3) DSC_SND_ENTRY( NODE, dst_logic_and , DSS_NODE , 4, DSE( INP0,INP1,INP2,INP3 ), DSE( INP0,INP1,INP2,INP3 ) ,NULL, "DISCRETE_LOGIC_AND4" ), +#define DISCRETE_LOGIC_NAND(NODE,INP0,INP1) DSC_SND_ENTRY( NODE, dst_logic_nand , DSS_NODE , 4, DSE( INP0,INP1,NODE_NC,NODE_NC ), DSE( INP0,INP1,1.0,1.0 ), NULL, "DISCRETE_LOGIC_NAND" ), +#define DISCRETE_LOGIC_NAND3(NODE,INP0,INP1,INP2) DSC_SND_ENTRY( NODE, dst_logic_nand , DSS_NODE , 4, DSE( INP0,INP1,INP2,NODE_NC ), DSE( INP0,INP1,INP2,1.0 ), NULL, "DISCRETE_LOGIC_NAND3" ), +#define DISCRETE_LOGIC_NAND4(NODE,INP0,INP1,INP2,INP3) DSC_SND_ENTRY( NODE, dst_logic_nand , DSS_NODE , 4, DSE( INP0,INP1,INP2,INP3 ), DSE( INP0,INP1,INP2,INP3 ), NULL, ")DISCRETE_LOGIC_NAND4" ), +#define DISCRETE_LOGIC_OR(NODE,INP0,INP1) DSC_SND_ENTRY( NODE, dst_logic_or , DSS_NODE , 4, DSE( INP0,INP1,NODE_NC,NODE_NC ), DSE( INP0,INP1,0.0,0.0 ), NULL, "DISCRETE_LOGIC_OR" ), +#define DISCRETE_LOGIC_OR3(NODE,INP0,INP1,INP2) DSC_SND_ENTRY( NODE, dst_logic_or , DSS_NODE , 4, DSE( INP0,INP1,INP2,NODE_NC ), DSE( INP0,INP1,INP2,0.0 ), NULL, "DISCRETE_LOGIC_OR3" ), +#define DISCRETE_LOGIC_OR4(NODE,INP0,INP1,INP2,INP3) DSC_SND_ENTRY( NODE, dst_logic_or , DSS_NODE , 4, DSE( INP0,INP1,INP2,INP3 ), DSE( INP0,INP1,INP2,INP3 ), NULL, "DISCRETE_LOGIC_OR4" ), +#define DISCRETE_LOGIC_NOR(NODE,INP0,INP1) DSC_SND_ENTRY( NODE, dst_logic_nor , DSS_NODE , 4, DSE( INP0,INP1,NODE_NC,NODE_NC ), DSE( INP0,INP1,0.0,0.0 ), NULL, "DISCRETE_LOGIC_NOR" ), +#define DISCRETE_LOGIC_NOR3(NODE,INP0,INP1,INP2) DSC_SND_ENTRY( NODE, dst_logic_nor , DSS_NODE , 4, DSE( INP0,INP1,INP2,NODE_NC ), DSE( INP0,INP1,INP2,0.0 ), NULL, "DISCRETE_LOGIC_NOR3" ), +#define DISCRETE_LOGIC_NOR4(NODE,INP0,INP1,INP2,INP3) DSC_SND_ENTRY( NODE, dst_logic_nor , DSS_NODE , 4, DSE( INP0,INP1,INP2,INP3 ), DSE( INP0,INP1,INP2,INP3 ), NULL, "DISCRETE_LOGIC_NOR4" ), +#define DISCRETE_LOGIC_XOR(NODE,INP0,INP1) DSC_SND_ENTRY( NODE, dst_logic_xor , DSS_NODE , 2, DSE( INP0,INP1 ), DSE( INP0,INP1 ), NULL, "DISCRETE_LOGIC_XOR" ), +#define DISCRETE_LOGIC_XNOR(NODE,INP0,INP1) DSC_SND_ENTRY( NODE, dst_logic_nxor , DSS_NODE , 2, DSE( INP0,INP1 ), DSE( INP0,INP1 ), NULL, "DISCRETE_LOGIC_XNOR" ), +#define DISCRETE_LOGIC_DFLIPFLOP(NODE,RESET,SET,CLK,INP) DSC_SND_ENTRY( NODE, dst_logic_dff , DSS_NODE , 4, DSE( RESET,SET,CLK,INP ), DSE( RESET,SET,CLK,INP ), NULL, "DISCRETE_LOGIC_DFLIPFLOP" ), +#define DISCRETE_LOGIC_JKFLIPFLOP(NODE,RESET,SET,CLK,J,K) DSC_SND_ENTRY( NODE, dst_logic_jkff , DSS_NODE , 5, DSE( RESET,SET,CLK,J,K ), DSE( RESET,SET,CLK,J,K ), NULL, "DISCRETE_LOGIC_JKFLIPFLOP" ), +#define DISCRETE_LOGIC_SHIFT(NODE,INP0,RESET,CLK,SIZE,OPTIONS) DSC_SND_ENTRY( NODE, dst_logic_shift , DSS_NODE , 5, DSE( INP0,RESET,CLK,NODE_NC,NODE_NC ), DSE( INP0,RESET,CLK,SIZE,OPTIONS ), NULL, "DISCRETE_LOGIC_SHIFT" ), +#define DISCRETE_LOOKUP_TABLE(NODE,ADDR,SIZE,TABLE) DSC_SND_ENTRY( NODE, dst_lookup_table, DSS_NODE , 2, DSE( ADDR,NODE_NC ), DSE( ADDR,SIZE ), TABLE, "DISCRETE_LOOKUP_TABLE" ), +#define DISCRETE_MULTIPLEX2(NODE,ADDR,INP0,INP1) DSC_SND_ENTRY( NODE, dst_multiplex , DSS_NODE , 3, DSE( ADDR,INP0,INP1 ), DSE( ADDR,INP0,INP1 ), NULL, "DISCRETE_MULTIPLEX2" ), +#define DISCRETE_MULTIPLEX4(NODE,ADDR,INP0,INP1,INP2,INP3) DSC_SND_ENTRY( NODE, dst_multiplex , DSS_NODE , 5, DSE( ADDR,INP0,INP1,INP2,INP3 ), DSE( ADDR,INP0,INP1,INP2,INP3 ), NULL, "DISCRETE_MULTIPLEX4" ), +#define DISCRETE_MULTIPLEX8(NODE,ADDR,INP0,INP1,INP2,INP3,INP4,INP5,INP6,INP7) DSC_SND_ENTRY( NODE, dst_multiplex, DSS_NODE , 9, DSE( ADDR,INP0,INP1,INP2,INP3,INP4,INP5,INP6,INP7 ), DSE( ADDR,INP0,INP1,INP2,INP3,INP4,INP5,INP6,INP7 ), NULL, "DISCRETE_MULTIPLEX8" ), +#define DISCRETE_MULTIPLY(NODE,INP0,INP1) DSC_SND_ENTRY( NODE, dst_gain , DSS_NODE , 3, DSE( INP0,INP1,NODE_NC ), DSE( INP0,INP1,0 ), NULL, "DISCRETE_MULTIPLY" ), +#define DISCRETE_MULTADD(NODE,INP0,INP1,INP2) DSC_SND_ENTRY( NODE, dst_gain , DSS_NODE , 3, DSE( INP0,INP1,INP2 ), DSE( INP0,INP1,INP2 ), NULL, "DISCRETE_MULTADD" ), +#define DISCRETE_ONESHOT(NODE,TRIG,AMPL,WIDTH,TYPE) DSC_SND_ENTRY( NODE, dst_oneshot , DSS_NODE , 5, DSE( 0,TRIG,AMPL,WIDTH,NODE_NC ), DSE( 0,TRIG,AMPL,WIDTH,TYPE ), NULL, "DISCRETE_ONESHOT" ), +#define DISCRETE_ONESHOTR(NODE,RESET,TRIG,AMPL,WIDTH,TYPE) DSC_SND_ENTRY( NODE, dst_oneshot , DSS_NODE , 5, DSE( RESET,TRIG,AMPL,WIDTH,NODE_NC ), DSE( RESET,TRIG,AMPL,WIDTH,TYPE ), NULL, "One Shot Resetable" ), +#define DISCRETE_ONOFF(NODE,ENAB,INP0) DSC_SND_ENTRY( NODE, dst_gain , DSS_NODE , 3, DSE( ENAB,INP0,NODE_NC ), DSE( 0,1,0 ), NULL, "DISCRETE_ONOFF" ), +#define DISCRETE_RAMP(NODE,ENAB,RAMP,GRAD,START,END,CLAMP) DSC_SND_ENTRY( NODE, dst_ramp , DSS_NODE , 6, DSE( ENAB,RAMP,GRAD,START,END,CLAMP ), DSE( ENAB,RAMP,GRAD,START,END,CLAMP ), NULL, "DISCRETE_RAMP" ), +#define DISCRETE_SAMPLHOLD(NODE,INP0,CLOCK,CLKTYPE) DSC_SND_ENTRY( NODE, dst_samphold , DSS_NODE , 3, DSE( INP0,CLOCK,NODE_NC ), DSE( INP0,CLOCK,CLKTYPE ), NULL, "DISCRETE_SAMPLHOLD" ), +#define DISCRETE_SWITCH(NODE,ENAB,SWITCH,INP0,INP1) DSC_SND_ENTRY( NODE, dst_switch , DSS_NODE , 4, DSE( ENAB,SWITCH,INP0,INP1 ), DSE( ENAB,SWITCH,INP0,INP1 ), NULL, "DISCRETE_SWITCH" ), +#define DISCRETE_ASWITCH(NODE,CTRL,INP,THRESHOLD) DSC_SND_ENTRY( NODE, dst_aswitch , DSS_NODE , 3, DSE( CTRL,INP,THRESHOLD ), DSE( CTRL,INP, THRESHOLD), NULL, "Analog Switch" ), +#define DISCRETE_TRANSFORM2(NODE,INP0,INP1,FUNCT) DSC_SND_ENTRY( NODE, dst_transform , DSS_NODE , 2, DSE( INP0,INP1 ), DSE( INP0,INP1 ), FUNCT, "DISCRETE_TRANSFORM2" ), +#define DISCRETE_TRANSFORM3(NODE,INP0,INP1,INP2,FUNCT) DSC_SND_ENTRY( NODE, dst_transform , DSS_NODE , 3, DSE( INP0,INP1,INP2 ), DSE( INP0,INP1,INP2 ), FUNCT, "DISCRETE_TRANSFORM3" ), +#define DISCRETE_TRANSFORM4(NODE,INP0,INP1,INP2,INP3,FUNCT) DSC_SND_ENTRY( NODE, dst_transform , DSS_NODE , 4, DSE( INP0,INP1,INP2,INP3 ), DSE( INP0,INP1,INP2,INP3 ), FUNCT, "DISCRETE_TRANSFORM4" ), +#define DISCRETE_TRANSFORM5(NODE,INP0,INP1,INP2,INP3,INP4,FUNCT) DSC_SND_ENTRY( NODE, dst_transform , DSS_NODE , 5, DSE( INP0,INP1,INP2,INP3,INP4 ), DSE( INP0,INP1,INP2,INP3,INP4 ), FUNCT, "DISCRETE_TRANSFORM5" ), +/* Component specific */ +#define DISCRETE_COMP_ADDER(NODE,DATA,TABLE) DSC_SND_ENTRY( NODE, dst_comp_adder , DSS_NODE , 1, DSE( DATA ), DSE( DATA ), TABLE, "DISCRETE_COMP_ADDER" ), +#define DISCRETE_DAC_R1(NODE,DATA,VDATA,LADDER) DSC_SND_ENTRY( NODE, dst_dac_r1 , DSS_NODE , 2, DSE( DATA,NODE_NC ), DSE( DATA,VDATA ), LADDER, "DISCRETE_DAC_R1" ), +#define DISCRETE_DIODE_MIXER2(NODE,IN0,IN1,TABLE) DSC_SND_ENTRY( NODE, dst_diode_mix , DSS_NODE , 2, DSE( IN0,IN1 ), DSE( IN0,IN1 ), TABLE, "DISCRETE_DIODE_MIXER2" ), +#define DISCRETE_DIODE_MIXER3(NODE,IN0,IN1,IN2,TABLE) DSC_SND_ENTRY( NODE, dst_diode_mix , DSS_NODE , 3, DSE( IN0,IN1,IN2 ), DSE( IN0,IN1,IN2 ), TABLE, "DISCRETE_DIODE_MIXER3" ), +#define DISCRETE_DIODE_MIXER4(NODE,IN0,IN1,IN2,IN3,TABLE) DSC_SND_ENTRY( NODE, dst_diode_mix , DSS_NODE , 4, DSE( IN0,IN1,IN2,IN3 ), DSE( IN0,IN1,IN2,IN3 ), TABLE, "DISCRETE_DIODE_MIXER4" ), +#define DISCRETE_INTEGRATE(NODE,TRG0,TRG1,INFO) DSC_SND_ENTRY( NODE, dst_integrate , DSS_NODE , 2, DSE( TRG0,TRG1 ), DSE( TRG0,TRG1 ), INFO, "DISCRETE_INTEGRATE" ), +#define DISCRETE_MIXER2(NODE,ENAB,IN0,IN1,INFO) DSC_SND_ENTRY( NODE, dst_mixer , DSS_NODE , 3, DSE( ENAB,IN0,IN1 ), DSE( ENAB,IN0,IN1 ), INFO, "DISCRETE_MIXER2" ), +#define DISCRETE_MIXER3(NODE,ENAB,IN0,IN1,IN2,INFO) DSC_SND_ENTRY( NODE, dst_mixer , DSS_NODE , 4, DSE( ENAB,IN0,IN1,IN2 ), DSE( ENAB,IN0,IN1,IN2 ), INFO, "DISCRETE_MIXER3" ), +#define DISCRETE_MIXER4(NODE,ENAB,IN0,IN1,IN2,IN3,INFO) DSC_SND_ENTRY( NODE, dst_mixer , DSS_NODE , 5, DSE( ENAB,IN0,IN1,IN2,IN3 ), DSE( ENAB,IN0,IN1,IN2,IN3 ), INFO, "DISCRETE_MIXER4" ), +#define DISCRETE_MIXER5(NODE,ENAB,IN0,IN1,IN2,IN3,IN4,INFO) DSC_SND_ENTRY( NODE, dst_mixer , DSS_NODE , 6, DSE( ENAB,IN0,IN1,IN2,IN3,IN4 ), DSE( ENAB,IN0,IN1,IN2,IN3,IN4 ), INFO, "DISCRETE_MIXER5" ), +#define DISCRETE_MIXER6(NODE,ENAB,IN0,IN1,IN2,IN3,IN4,IN5,INFO) DSC_SND_ENTRY( NODE, dst_mixer , DSS_NODE , 7, DSE( ENAB,IN0,IN1,IN2,IN3,IN4,IN5 ), DSE( ENAB,IN0,IN1,IN2,IN3,IN4,IN5 ), INFO, "DISCRETE_MIXER6" ), +#define DISCRETE_MIXER7(NODE,ENAB,IN0,IN1,IN2,IN3,IN4,IN5,IN6,INFO) DSC_SND_ENTRY( NODE, dst_mixer , DSS_NODE , 8, DSE( ENAB,IN0,IN1,IN2,IN3,IN4,IN5,IN6 ), DSE( ENAB,IN0,IN1,IN2,IN3,IN4,IN5,IN6 ), INFO, "DISCRETE_MIXER7" ), +#define DISCRETE_MIXER8(NODE,ENAB,IN0,IN1,IN2,IN3,IN4,IN5,IN6,IN7,INFO) DSC_SND_ENTRY( NODE, dst_mixer , DSS_NODE , 9, DSE( ENAB,IN0,IN1,IN2,IN3,IN4,IN5,IN6,IN7 ), DSE( ENAB,IN0,IN1,IN2,IN3,IN4,IN5,IN6,IN7 ), INFO, "DISCRETE_MIXER8" ), +#define DISCRETE_OP_AMP(NODE,ENAB,IN0,IN1,INFO) DSC_SND_ENTRY( NODE, dst_op_amp , DSS_NODE , 3, DSE( ENAB,IN0,IN1 ), DSE( ENAB,IN0,IN1 ), INFO, "DISCRETE_OP_AMP" ), +#define DISCRETE_OP_AMP_ONESHOT(NODE,TRIG,INFO) DSC_SND_ENTRY( NODE, dst_op_amp_1sht , DSS_NODE , 1, DSE( TRIG ), DSE( TRIG ), INFO, "DISCRETE_OP_AMP_ONESHOT" ), +#define DISCRETE_OP_AMP_TRIG_VCA(NODE,TRG0,TRG1,TRG2,IN0,IN1,INFO) DSC_SND_ENTRY( NODE, dst_tvca_op_amp , DSS_NODE , 5, DSE( TRG0,TRG1,TRG2,IN0,IN1 ), DSE( TRG0,TRG1,TRG2,IN0,IN1 ), INFO, "DISCRETE_OP_AMP_TRIG_VCA" ), +#define DISCRETE_VCA(NODE,ENAB,IN0,CTRL,TYPE) DSC_SND_ENTRY( NODE, dst_vca , DSS_NODE , 4, DSE( ENAB,IN0,CTRL,NODE_NC ), DSE( ENAB,IN0,CTRL,TYPE ), NULL, "DISCRETE_VCA" ), +#define DISCRETE_XTIME_BUFFER(NODE,IN0,LOW,HIGH) DSC_SND_ENTRY( NODE, dst_xtime_buffer, DSS_NODE , 4, DSE( IN0,LOW,HIGH,NODE_NC ), DSE( IN0,LOW,HIGH,0 ), NULL, "DISCRETE_XTIME_BUFFER" ), +#define DISCRETE_XTIME_INVERTER(NODE,IN0,LOW,HIGH) DSC_SND_ENTRY( NODE, dst_xtime_buffer, DSS_NODE , 4, DSE( IN0,LOW,HIGH,NODE_NC ), DSE( IN0,LOW,HIGH,1 ), NULL, "DISCRETE_XTIME_INVERTER" ), +#define DISCRETE_XTIME_AND(NODE,IN0,IN1,LOW,HIGH) DSC_SND_ENTRY( NODE, dst_xtime_and , DSS_NODE , 5, DSE( IN0,IN1,LOW,HIGH,NODE_NC ), DSE( IN0,IN1,LOW,HIGH,0 ), NULL, "DISCRETE_XTIME_AND" ), +#define DISCRETE_XTIME_NAND(NODE,IN0,IN1,LOW,HIGH) DSC_SND_ENTRY( NODE, dst_xtime_and , DSS_NODE , 5, DSE( IN0,IN1,LOW,HIGH,NODE_NC ), DSE( IN0,IN1,LOW,HIGH,1 ), NULL, "DISCRETE_XTIME_NAND" ), +#define DISCRETE_XTIME_OR(NODE,IN0,IN1,LOW,HIGH) DSC_SND_ENTRY( NODE, dst_xtime_or , DSS_NODE , 5, DSE( IN0,IN1,LOW,HIGH,NODE_NC ), DSE( IN0,IN1,LOW,HIGH,0 ), NULL, "DISCRETE_XTIME_OR" ), +#define DISCRETE_XTIME_NOR(NODE,IN0,IN1,LOW,HIGH) DSC_SND_ENTRY( NODE, dst_xtime_or , DSS_NODE , 5, DSE( IN0,IN1,LOW,HIGH,NODE_NC ), DSE( IN0,IN1,LOW,HIGH,1 ), NULL, "DISCRETE_XTIME_NOR" ), +#define DISCRETE_XTIME_XOR(NODE,IN0,IN1,LOW,HIGH) DSC_SND_ENTRY( NODE, dst_xtime_xor , DSS_NODE , 5, DSE( IN0,IN1,LOW,HIGH,NODE_NC ), DSE( IN0,IN1,LOW,HIGH,0 ), NULL, "DISCRETE_XTIME_XOR" ), +#define DISCRETE_XTIME_XNOR(NODE,IN0,IN1,LOW,HIGH) DSC_SND_ENTRY( NODE, dst_xtime_xnor , DSS_NODE , 5, DSE( IN0,IN1,LOW,HIGH,NODE_NC ), DSE( IN0,IN1,LOW,HIGH,1 ), NULL, "DISCRETE_XTIME_XNOR" ), + +/* from disc_flt.inc */ +/* generic modules */ +#define DISCRETE_FILTER1(NODE,ENAB,INP0,FREQ,TYPE) DSC_SND_ENTRY( NODE, dst_filter1 , DSS_NODE , 4, DSE( ENAB,INP0,NODE_NC,NODE_NC ), DSE( ENAB,INP0,FREQ,TYPE ), NULL, "DISCRETE_FILTER1" ), +#define DISCRETE_FILTER2(NODE,ENAB,INP0,FREQ,DAMP,TYPE) DSC_SND_ENTRY( NODE, dst_filter2 , DSS_NODE , 5, DSE( ENAB,INP0,NODE_NC,NODE_NC,NODE_NC ), DSE( ENAB,INP0,FREQ,DAMP,TYPE ), NULL, "DISCRETE_FILTER2" ), +/* Component specific */ +#define DISCRETE_SALLEN_KEY_FILTER(NODE,ENAB,INP0,TYPE,INFO) DSC_SND_ENTRY( NODE, dst_sallen_key , DSS_NODE , 3, DSE( ENAB,INP0,NODE_NC ), DSE( ENAB,INP0,TYPE ), INFO, "DISCRETE_SALLEN_KEY_FILTER" ), +#define DISCRETE_CRFILTER(NODE,INP0,RVAL,CVAL) DSC_SND_ENTRY( NODE, dst_crfilter , DSS_NODE , 3, DSE( INP0,OPT_NODE(RVAL),OPT_NODE(CVAL) ), DSE( INP0,RVAL,CVAL ), NULL, "DISCRETE_CRFILTER" ), +#define DISCRETE_CRFILTER_VREF(NODE,INP0,RVAL,CVAL,VREF) DSC_SND_ENTRY( NODE, dst_crfilter , DSS_NODE , 4, DSE( INP0,OPT_NODE(RVAL),OPT_NODE(CVAL),VREF ), DSE( INP0,RVAL,CVAL,VREF ), NULL, "DISCRETE_CRFILTER_VREF" ), +#define DISCRETE_OP_AMP_FILTER(NODE,ENAB,INP0,INP1,TYPE,INFO) DSC_SND_ENTRY( NODE, dst_op_amp_filt , DSS_NODE , 4, DSE( ENAB,INP0,INP1,NODE_NC ), DSE( ENAB,INP0,INP1,TYPE ), INFO, "DISCRETE_OP_AMP_FILTER" ), +#define DISCRETE_RC_CIRCUIT_1(NODE,INP0,INP1,RVAL,CVAL) DSC_SND_ENTRY( NODE, dst_rc_circuit_1, DSS_NODE , 4, DSE( INP0,INP1,NODE_NC,NODE_NC ), DSE( INP0,INP1,RVAL,CVAL ), NULL, "DISCRETE_RC_CIRCUIT_1" ), +#define DISCRETE_RCDISC(NODE,ENAB,INP0,RVAL,CVAL) DSC_SND_ENTRY( NODE, dst_rcdisc , DSS_NODE , 4, DSE( ENAB,INP0,NODE_NC,NODE_NC ), DSE( ENAB,INP0,RVAL,CVAL ), NULL, "DISCRETE_RCDISC" ), +#define DISCRETE_RCDISC2(NODE,SWITCH,INP0,RVAL0,INP1,RVAL1,CVAL) DSC_SND_ENTRY( NODE, dst_rcdisc2 , DSS_NODE , 6, DSE( SWITCH,INP0,NODE_NC,INP1,NODE_NC,NODE_NC ), DSE( SWITCH,INP0,RVAL0,INP1,RVAL1,CVAL ), NULL, "DISCRETE_RCDISC2" ), +#define DISCRETE_RCDISC3(NODE,ENAB,INP0,RVAL0,RVAL1,CVAL,DJV) DSC_SND_ENTRY( NODE, dst_rcdisc3 , DSS_NODE , 6, DSE( ENAB,INP0,NODE_NC,NODE_NC,NODE_NC,NODE_NC ), DSE( ENAB,INP0,RVAL0,RVAL1,CVAL,DJV ), NULL, "DISCRETE_RCDISC3" ), +#define DISCRETE_RCDISC4(NODE,ENAB,INP0,RVAL0,RVAL1,RVAL2,CVAL,VP,TYPE) DSC_SND_ENTRY( NODE, dst_rcdisc4 , DSS_NODE , 8, DSE( ENAB,INP0,NODE_NC,NODE_NC,NODE_NC,NODE_NC,NODE_NC,NODE_NC ), DSE( ENAB,INP0,RVAL0,RVAL1,RVAL2,CVAL,VP,TYPE ), NULL, "DISCRETE_RCDISC4" ), +#define DISCRETE_RCDISC5(NODE,ENAB,INP0,RVAL,CVAL) DSC_SND_ENTRY( NODE, dst_rcdisc5 , DSS_NODE , 4, DSE( ENAB,INP0,NODE_NC,NODE_NC ), DSE( ENAB,INP0,RVAL,CVAL ), NULL, "DISCRETE_RCDISC5" ), +#define DISCRETE_RCDISC_MODULATED(NODE,INP0,INP1,RVAL0,RVAL1,RVAL2,RVAL3,CVAL,VP) DSC_SND_ENTRY( NODE, dst_rcdisc_mod, DSS_NODE , 8, DSE( INP0,INP1,NODE_NC,NODE_NC,NODE_NC,NODE_NC,NODE_NC,NODE_NC ), DSE( INP0,INP1,RVAL0,RVAL1,RVAL2,RVAL3,CVAL,VP ), NULL, "DISCRETE_RCDISC_MODULATED" ), +#define DISCRETE_RCFILTER(NODE,INP0,RVAL,CVAL) DSC_SND_ENTRY( NODE, dst_rcfilter , DSS_NODE , 3, DSE( INP0,OPT_NODE(RVAL),OPT_NODE(CVAL) ), DSE( INP0,RVAL,CVAL ), NULL, "DISCRETE_RCFILTER" ), +#define DISCRETE_RCFILTER_VREF(NODE,INP0,RVAL,CVAL,VREF) DSC_SND_ENTRY( NODE, dst_rcfilter , DSS_NODE , 4, DSE( INP0,OPT_NODE(RVAL),OPT_NODE(CVAL),VREF ), DSE( INP0,RVAL,CVAL,VREF ), NULL, "DISCRETE_RCFILTER_VREF" ), +#define DISCRETE_RCFILTER_SW(NODE,ENAB,INP0,SW,RVAL,CVAL1,CVAL2,CVAL3,CVAL4) DSC_SND_ENTRY( NODE, dst_rcfilter_sw, DSS_NODE , 8, DSE( ENAB,INP0,SW,NODE_NC,NODE_NC,NODE_NC,NODE_NC,NODE_NC ), DSE( ENAB,INP0,SW,RVAL,CVAL1,CVAL2,CVAL3,CVAL4 ), NULL, "DISCRETE_RCFILTER_SW" ), +#define DISCRETE_RCINTEGRATE(NODE,INP0,RVAL0,RVAL1,RVAL2,CVAL,vP,TYPE) DSC_SND_ENTRY( NODE, dst_rcintegrate , DSS_NODE , 7, DSE( INP0,NODE_NC,NODE_NC,NODE_NC,NODE_NC,NODE_NC,NODE_NC ), DSE( INP0,RVAL0,RVAL1,RVAL2,CVAL,vP,TYPE ), NULL, "DISCRETE_RCINTEGRATE" ), +/* For testing - seem to be buggered. Use versions not ending in N. */ +#define DISCRETE_RCDISCN(NODE,ENAB,INP0,RVAL,CVAL) DSC_SND_ENTRY( NODE, dst_rcdiscn , DSS_NODE , 4, DSE( ENAB,INP0,NODE_NC,NODE_NC ), DSE( ENAB,INP0,RVAL,CVAL ), NULL, "DISCRETE_RCDISCN" ), +#define DISCRETE_RCDISC2N(NODE,SWITCH,INP0,RVAL0,INP1,RVAL1,CVAL) DSC_SND_ENTRY( NODE, dst_rcdisc2n , DSS_NODE , 6, DSE( SWITCH,INP0,NODE_NC,INP1,NODE_NC,NODE_NC ), DSE( SWITCH,INP0,RVAL0,INP1,RVAL1,CVAL ), NULL, "DISCRETE_RCDISC2N" ), +#define DISCRETE_RCFILTERN(NODE,ENAB,INP0,RVAL,CVAL) DSC_SND_ENTRY( NODE, dst_rcfiltern , DSS_NODE , 4, DSE( ENAB,INP0,NODE_NC,NODE_NC ), DSE( ENAB,INP0,RVAL,CVAL ), NULL, "DISCRETE_RCFILTERN" ), + +/* from disc_dev.inc */ +/* generic modules */ +#define DISCRETE_CUSTOM1(NODE,CLASS,IN0,INFO) DSC_SND_ENTRY( NODE, CLASS, DST_CUSTOM , 1, DSE( IN0 ), DSE( IN0 ), INFO, "DISCRETE_CUSTOM1" ), +#define DISCRETE_CUSTOM2(NODE,CLASS,IN0,IN1,INFO) DSC_SND_ENTRY( NODE, CLASS, DST_CUSTOM , 2, DSE( IN0,IN1 ), DSE( IN0,IN1 ), INFO, "DISCRETE_CUSTOM2" ), +#define DISCRETE_CUSTOM3(NODE,CLASS,IN0,IN1,IN2,INFO) DSC_SND_ENTRY( NODE, CLASS, DST_CUSTOM , 3, DSE( IN0,IN1,IN2 ), DSE( IN0,IN1,IN2 ), INFO, "DISCRETE_CUSTOM3" ), +#define DISCRETE_CUSTOM4(NODE,CLASS,IN0,IN1,IN2,IN3,INFO) DSC_SND_ENTRY( NODE, CLASS, DST_CUSTOM , 4, DSE( IN0,IN1,IN2,IN3 ), DSE( IN0,IN1,IN2,IN3 ), INFO, "DISCRETE_CUSTOM4" ), +#define DISCRETE_CUSTOM5(NODE,CLASS,IN0,IN1,IN2,IN3,IN4,INFO) DSC_SND_ENTRY( NODE, CLASS, DST_CUSTOM , 5, DSE( IN0,IN1,IN2,IN3,IN4 ), DSE( IN0,IN1,IN2,IN3,IN4 ), INFO, "DISCRETE_CUSTOM5" ), +#define DISCRETE_CUSTOM6(NODE,CLASS,IN0,IN1,IN2,IN3,IN4,IN5,INFO) DSC_SND_ENTRY( NODE, CLASS, DST_CUSTOM , 6, DSE( IN0,IN1,IN2,IN3,IN4,IN5 ), DSE( IN0,IN1,IN2,IN3,IN4,IN5 ), INFO, "DISCRETE_CUSTOM6" ), +#define DISCRETE_CUSTOM7(NODE,CLASS,IN0,IN1,IN2,IN3,IN4,IN5,IN6,INFO) DSC_SND_ENTRY( NODE, CLASS, DST_CUSTOM , 7, DSE( IN0,IN1,IN2,IN3,IN4,IN5,IN6 ), DSE( IN0,IN1,IN2,IN3,IN4,IN5,IN6 ), INFO, "DISCRETE_CUSTOM7" ), +#define DISCRETE_CUSTOM8(NODE,CLASS,IN0,IN1,IN2,IN3,IN4,IN5,IN6,IN7,INFO) DSC_SND_ENTRY( NODE, CLASS, DST_CUSTOM , 8, DSE( IN0,IN1,IN2,IN3,IN4,IN5,IN6,IN7 ), DSE( IN0,IN1,IN2,IN3,IN4,IN5,IN6,IN7 ), INFO, "DISCRETE_CUSTOM8" ), +#define DISCRETE_CUSTOM9(NODE,CLASS,IN0,IN1,IN2,IN3,IN4,IN5,IN6,IN7,IN8,INFO) DSC_SND_ENTRY( NODE, CLASS, DST_CUSTOM , 9, DSE( IN0,IN1,IN2,IN3,IN4,IN5,IN6,IN7,IN8 ), DSE( IN0,IN1,IN2,IN3,IN4,IN5,IN6,IN7,IN8 ), INFO, "DISCRETE_CUSTOM9" ), + +/* Component specific */ +#define DISCRETE_555_ASTABLE(NODE,RESET,R1,R2,C,OPTIONS) DSC_SND_ENTRY( NODE, dsd_555_astbl , DSS_NODE , 5, DSE( RESET,R1,R2,C,NODE_NC ), DSE( RESET,R1,R2,C,-1 ), OPTIONS, "DISCRETE_555_ASTABLE" ), +#define DISCRETE_555_ASTABLE_CV(NODE,RESET,R1,R2,C,CTRLV,OPTIONS) DSC_SND_ENTRY( NODE, dsd_555_astbl , DSS_NODE , 5, DSE( RESET,R1,R2,C,CTRLV ), DSE( RESET,R1,R2,C,CTRLV ), OPTIONS, "DISCRETE_555_ASTABLE_CV" ), +#define DISCRETE_555_MSTABLE(NODE,RESET,TRIG,R,C,OPTIONS) DSC_SND_ENTRY( NODE, dsd_555_mstbl , DSS_NODE , 4, DSE( RESET,TRIG,R,C ), DSE( RESET,TRIG,R,C ), OPTIONS, "DISCRETE_555_MSTABLE" ), +#define DISCRETE_555_CC(NODE,RESET,VIN,R,C,RBIAS,RGND,RDIS,OPTIONS) DSC_SND_ENTRY( NODE, dsd_555_cc , DSS_NODE , 7, DSE( RESET,VIN,R,C,RBIAS,RGND,RDIS ), DSE( RESET,VIN,R,C,RBIAS,RGND,RDIS ), OPTIONS, "DISCRETE_555_CC" ), +#define DISCRETE_555_VCO1(NODE,RESET,VIN,OPTIONS) DSC_SND_ENTRY( NODE, dsd_555_vco1 , DSS_NODE , 3, DSE( RESET,VIN,NODE_NC ), DSE( RESET,VIN,-1 ), OPTIONS, "DISCRETE_555_VCO1" ), +#define DISCRETE_555_VCO1_CV(NODE,RESET,VIN,CTRLV,OPTIONS) DSC_SND_ENTRY( NODE, dsd_555_vco1 , DSS_NODE , 3, DSE( RESET,VIN,CTRLV ), DSE( RESET,VIN,CTRLV ), OPTIONS, "DISCRETE_555_VCO1_CV" ), +#define DISCRETE_566(NODE,VMOD,R,C,VPOS,VNEG,VCHARGE,OPTIONS) DSC_SND_ENTRY( NODE, dsd_566 , DSS_NODE , 7, DSE( VMOD,R,C,NODE_NC,NODE_NC,VCHARGE,NODE_NC ), DSE( VMOD,R,C,VPOS,VNEG,VCHARGE,OPTIONS ), NULL, "DISCRETE_566" ), +#define DISCRETE_74LS624(NODE,ENAB,VMOD,VRNG,C,R_FREQ_IN,C_FREQ_IN,R_RNG_IN,OUTTYPE) DSC_SND_ENTRY( NODE, dsd_ls624 , DSS_NODE , 8, DSE( ENAB,VMOD,NODE_NC,NODE_NC,NODE_NC,NODE_NC,NODE_NC,NODE_NC ), DSE( ENAB,VMOD,VRNG,C,R_FREQ_IN,C_FREQ_IN,R_RNG_IN,OUTTYPE ), NULL, "DISCRETE_74LS624" ), + +/* NOP */ +#define DISCRETE_NOP(NODE) DSC_SND_ENTRY( NODE, dss_nop , DSS_NOP , 0, DSE( 0 ), DSE( 0 ), NULL, "DISCRETE_NOP" ), + +/* logging */ +#define DISCRETE_CSVLOG1(NODE1) DSC_SND_ENTRY( NODE_SPECIAL, dso_csvlog , DSO_CSVLOG , 1, DSE( NODE1 ), DSE( NODE1 ), NULL, "DISCRETE_CSVLOG1" ), +#define DISCRETE_CSVLOG2(NODE1,NODE2) DSC_SND_ENTRY( NODE_SPECIAL, dso_csvlog , DSO_CSVLOG , 2, DSE( NODE1,NODE2 ), DSE( NODE1,NODE2 ), NULL, "DISCRETE_CSVLOG2" ), +#define DISCRETE_CSVLOG3(NODE1,NODE2,NODE3) DSC_SND_ENTRY( NODE_SPECIAL, dso_csvlog , DSO_CSVLOG , 3, DSE( NODE1,NODE2,NODE3 ), DSE( NODE1,NODE2,NODE3 ), NULL, "DISCRETE_CSVLOG3" ), +#define DISCRETE_CSVLOG4(NODE1,NODE2,NODE3,NODE4) DSC_SND_ENTRY( NODE_SPECIAL, dso_csvlog , DSO_CSVLOG , 4, DSE( NODE1,NODE2,NODE3,NODE4 ), DSE( NODE1,NODE2,NODE3,NODE4 ), NULL, "DISCRETE_CSVLOG4" ), +#define DISCRETE_CSVLOG5(NODE1,NODE2,NODE3,NODE4,NODE5) DSC_SND_ENTRY( NODE_SPECIAL, dso_csvlog , DSO_CSVLOG , 5, DSE( NODE1,NODE2,NODE3,NODE4,NODE5 ), DSE( NODE1,NODE2,NODE3,NODE4,NODE5 ), NULL, "DISCRETE_CSVLOG5" ), +#define DISCRETE_WAVLOG1(NODE1,GAIN1) DSC_SND_ENTRY( NODE_SPECIAL, dso_wavlog , DSO_WAVLOG , 2, DSE( NODE1,NODE_NC ), DSE( NODE1,GAIN1 ), NULL, "DISCRETE_WAVLOG1" ), +#define DISCRETE_WAVLOG2(NODE1,GAIN1,NODE2,GAIN2) DSC_SND_ENTRY( NODE_SPECIAL, dso_wavlog , DSO_WAVLOG , 4, DSE( NODE1,NODE_NC,NODE2,NODE_NC ), DSE( NODE1,GAIN1,NODE2,GAIN2 ), NULL, "DISCRETE_WAVLOG2" ), + +/* import */ +#define DISCRETE_IMPORT(INFO) DSC_SND_ENTRY( NODE_SPECIAL, special , DSO_IMPORT , 0, DSE( 0 ), DSE( 0 ), &(INFO##_discrete_interface), "DISCRETE_IMPORT" ), +#define DISCRETE_DELETE(NODE_FROM, NODE_TO) DSC_SND_ENTRY( NODE_SPECIAL, special , DSO_DELETE , 2, DSE( NODE_FROM, NODE_TO ), DSE( NODE_FROM, NODE_TO ), NULL, "DISCRETE_DELETE" ), +#define DISCRETE_REPLACE DSC_SND_ENTRY( NODE_SPECIAL, special , DSO_REPLACE , 0, DSE( 0 ), DSE( 0 ), NULL, "DISCRETE_REPLACE" ), + +/* parallel tasks */ + +#define DISCRETE_TASK_START(TASK_GROUP) DSC_SND_ENTRY( NODE_SPECIAL, special , DSO_TASK_START, 2, DSE( NODE_NC, NODE_NC ), DSE( TASK_GROUP, 0 ), NULL, "DISCRETE_TASK_START" ), +#define DISCRETE_TASK_END() DSC_SND_ENTRY( NODE_SPECIAL, special , DSO_TASK_END , 0, DSE( 0 ), DSE( 0 ), NULL, "DISCRETE_TASK_END" ), +//#define DISCRETE_TASK_SYNC() DSC_SND_ENTRY( NODE_SPECIAL, special , DSO_TASK_SYNC , 0, DSE( 0 ), DSE( 0 ), NULL, "DISCRETE_TASK_SYNC" ), + +/* output */ +#define DISCRETE_OUTPUT(OPNODE,GAIN) DSC_SND_ENTRY( NODE_SPECIAL, dso_output , DSO_OUTPUT ,2, DSE( OPNODE,NODE_NC ), DSE( 0,GAIN ), NULL, "DISCRETE_OUTPUT" ), + + + +#endif /* __DISCRETE_H__ */ diff --git a/src/devices/sound/dmadac.c b/src/devices/sound/dmadac.c new file mode 100644 index 00000000000..622b566f1ee --- /dev/null +++ b/src/devices/sound/dmadac.c @@ -0,0 +1,238 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + DMA-driven DAC driver + by Aaron Giles + +***************************************************************************/ + +#include "emu.h" +#include "dmadac.h" + + + +/************************************* + * + * Debugging + * + *************************************/ + +#define VERBOSE 0 + +#define LOG(x) do { if (VERBOSE) logerror x; } while (0) + + +/************************************* + * + * Constants + * + *************************************/ + +#define DEFAULT_SAMPLE_RATE (44100) + +#define BUFFER_SIZE 32768 + + +/************************************* + * + * Sound hardware init + * + *************************************/ + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void dmadac_sound_device::device_start() +{ + /* allocate a clear a buffer */ + m_buffer = auto_alloc_array_clear(machine(), INT16, BUFFER_SIZE); + + /* reset the state */ + m_volume = 0x100; + + /* allocate a stream channel */ + m_channel = machine().sound().stream_alloc(*this, 0, 1, DEFAULT_SAMPLE_RATE); + + /* register with the save state system */ + save_item(NAME(m_bufin)); + save_item(NAME(m_bufout)); + save_item(NAME(m_volume)); + save_item(NAME(m_enabled)); + save_item(NAME(m_frequency)); + save_pointer(NAME(m_buffer), BUFFER_SIZE); +} + + + +/************************************* + * + * Primary transfer routine + * + *************************************/ + +void dmadac_transfer(dmadac_sound_device **devlist, UINT8 num_channels, offs_t channel_spacing, offs_t frame_spacing, offs_t total_frames, INT16 *data) +{ + int i; + + /* flush out as much data as we can */ + for (i = 0; i < num_channels; i++) + { + devlist[i]->flush(); + } + + /* loop over all channels and accumulate the data */ + for (i = 0; i < num_channels; i++) + { + devlist[i]->transfer(i, channel_spacing, frame_spacing, total_frames, data); + } +} + +void dmadac_sound_device::flush() +{ + m_channel->update(); +} + +void dmadac_sound_device::transfer(int channel, offs_t channel_spacing, offs_t frame_spacing, offs_t total_frames, INT16 *data) +{ + int j; + + /* loop over all channels and accumulate the data */ + if (m_enabled) + { + int maxin = (m_bufout + BUFFER_SIZE - 1) % BUFFER_SIZE; + INT16 *src = data + channel * channel_spacing; + int curin = m_bufin; + + /* copy the data */ + for (j = 0; j < total_frames && curin != maxin; j++) + { + m_buffer[curin] = *src; + curin = (curin + 1) % BUFFER_SIZE; + src += frame_spacing; + } + m_bufin = curin; + + /* log overruns */ + if (j != total_frames) + logerror("dmadac_transfer: buffer overrun (short %d frames)\n", total_frames - j); + } + + //LOG(("dmadac_transfer - %d samples, %d effective, %d in buffer\n", total_frames, (int)(total_frames * (double)DEFAULT_SAMPLE_RATE / dmadac[first_channel].frequency), dmadac[first_channel].curinpos - dmadac[first_channel].curoutpos)); +} + + + +/************************************* + * + * Enable/disable DMA channel(s) + * + *************************************/ + +void dmadac_enable(dmadac_sound_device **devlist, UINT8 num_channels, UINT8 enable) +{ + int i; + + /* flush out as much data as we can */ + for (i = 0; i < num_channels; i++) + { + devlist[i]->enable(enable); + } +} + + +void dmadac_sound_device::enable(UINT8 enable) +{ + m_channel->update(); + m_enabled = enable; + if (!enable) + m_bufin = m_bufout = 0; +} + +/************************************* + * + * Set the frequency on DMA channel(s) + * + *************************************/ + +void dmadac_set_frequency(dmadac_sound_device **devlist, UINT8 num_channels, double frequency) +{ + int i; + + /* set the sample rate on each channel */ + for (i = 0; i < num_channels; i++) + { + devlist[i]->set_frequency(frequency); + } +} + + +void dmadac_sound_device::set_frequency(double frequency) +{ + m_channel->set_sample_rate(frequency); +} + +/************************************* + * + * Set the volume on DMA channel(s) + * + *************************************/ + +void dmadac_set_volume(dmadac_sound_device **devlist, UINT8 num_channels, UINT16 volume) +{ + int i; + + /* flush out as much data as we can */ + for (i = 0; i < num_channels; i++) + { + devlist[i]->set_volume(volume); + } +} + +void dmadac_sound_device::set_volume(UINT16 volume) +{ + m_channel->update(); + m_volume = volume; +} + +const device_type DMADAC = &device_creator; + +dmadac_sound_device::dmadac_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, DMADAC, "DMA-driven DAC", tag, owner, clock, "dmadac", __FILE__), + device_sound_interface(mconfig, *this), + m_buffer(NULL), + m_bufin(0), + m_bufout(0), + m_volume(0), + m_enabled(0), + m_frequency(0) +{ +} + +//------------------------------------------------- +// sound_stream_update - handle a stream update +//------------------------------------------------- + +void dmadac_sound_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + stream_sample_t *output = outputs[0]; + INT16 *source = m_buffer; + UINT32 curout = m_bufout; + UINT32 curin = m_bufin; + int volume = m_volume; + + /* feed as much as we can */ + while (curout != curin && samples-- > 0) + { + *output++ = (source[curout] * volume) >> 8; + curout = (curout + 1) % BUFFER_SIZE; + } + + /* fill the rest with silence */ + while (samples-- > 0) + *output++ = 0; + + /* save the new output pointer */ + m_bufout = curout; +} diff --git a/src/devices/sound/dmadac.h b/src/devices/sound/dmadac.h new file mode 100644 index 00000000000..65bfe16b3ff --- /dev/null +++ b/src/devices/sound/dmadac.h @@ -0,0 +1,56 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/********************************************************************************************** + * + * DMA-driven DAC driver + * by Aaron Giles + * + **********************************************************************************************/ + +#pragma once + +#ifndef __DMADAC_H__ +#define __DMADAC_H__ + + +class dmadac_sound_device : public device_t, + public device_sound_interface +{ +public: + dmadac_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + void flush(); + void transfer(int channel, offs_t channel_spacing, offs_t frame_spacing, offs_t total_frames, INT16 *data); + void enable(UINT8 enable); + void set_frequency(double frequency); + void set_volume(UINT16 volume); + +protected: + // device-level overrides + virtual void device_start(); + + // sound stream update overrides + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); +private: + // internal state + /* sound stream and buffers */ + sound_stream * m_channel; + INT16 * m_buffer; + UINT32 m_bufin; + UINT32 m_bufout; + + /* per-channel parameters */ + INT16 m_volume; + UINT8 m_enabled; + double m_frequency; +}; + +extern const device_type DMADAC; + + +void dmadac_transfer(dmadac_sound_device **devlist, UINT8 num_channels, offs_t channel_spacing, offs_t frame_spacing, offs_t total_frames, INT16 *data); +void dmadac_enable(dmadac_sound_device **devlist, UINT8 num_channels, UINT8 enable); +void dmadac_set_frequency(dmadac_sound_device **devlist, UINT8 num_channels, double frequency); +void dmadac_set_volume(dmadac_sound_device **devlist, UINT8 num_channels, UINT16 volume); + +#endif /* __DMADAC_H__ */ diff --git a/src/devices/sound/es1373.c b/src/devices/sound/es1373.c new file mode 100644 index 00000000000..509b4a873d2 --- /dev/null +++ b/src/devices/sound/es1373.c @@ -0,0 +1,499 @@ +// license:BSD-3-Clause +// copyright-holders:Ted Green +#include "es1373.h" + +#define LOG_ES (0) +#define LOG_ES_REG (0) +#define LOG_ES_FILE (0) + + +static MACHINE_CONFIG_FRAGMENT( es1373 ) + MCFG_SPEAKER_STANDARD_STEREO("lspeaker", "rspeaker") +MACHINE_CONFIG_END + +machine_config_constructor es1373_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( es1373 ); +} + +const device_type ES1373 = &device_creator; + +DEVICE_ADDRESS_MAP_START(map, 32, es1373_device) + AM_RANGE(0x00, 0x3f) AM_READWRITE (reg_r, reg_w) +ADDRESS_MAP_END + +es1373_device::es1373_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : pci_device(mconfig, ES1373, "Creative Labs Ensoniq AudioPCI97 ES1373", tag, owner, clock, "es1373", __FILE__), + device_sound_interface(mconfig, *this), + m_eslog(NULL), + m_irq_num(-1) +{ +} + +void es1373_device::set_irq_info(const char *tag, const int irq_num) +{ + m_cpu_tag = tag; + m_irq_num = irq_num; +} + +//------------------------------------------------- +// device_stop - device-specific stop +//------------------------------------------------- +void es1373_device::device_stop() +{ + /* debugging */ + if (LOG_ES_FILE && m_eslog) + { + fclose(m_eslog); + m_eslog = NULL; + } +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- +void es1373_device::device_start() +{ + m_cpu = machine().device(m_cpu_tag); + pci_device::device_start(); + add_map(0x40, M_IO, FUNC(es1373_device::map)); + + // create the stream + m_stream = machine().sound().stream_alloc(*this, 0, 2, 44100/2); + + m_timer = timer_alloc(0, NULL); + m_timer->adjust(attotime::zero, 0, attotime::from_hz(44100/2/16)); + +} + +void es1373_device::device_reset() +{ + // debugging + m_tempCount = 0; + if (LOG_ES_FILE && m_eslog) + { + fclose(m_eslog); + m_eslog = NULL; + } + if (LOG_ES_FILE && !m_eslog) + m_eslog = fopen("es.log", "w"); + + pci_device::device_reset(); + memset(m_es_regs, 0, sizeof(m_es_regs)); + memset(m_ac97_regs, 0, sizeof(m_ac97_regs)); + m_ac97_regs[0] = 0x0800; + // Reset ADC channel info + m_adc.number = 0; + m_adc.enable = false; + m_adc.initialized = false; + m_adc.buf_rptr = 0x20; + m_adc.buf_wptr = 0x20; + // Reset DAC1 channel info + m_dac1.number = 1; + m_dac1.enable = false; + m_dac1.initialized = false; + m_dac1.buf_rptr = 0x0; + m_dac1.buf_wptr = 0x0; + // Reset DAC2 channel info + m_dac2.number = 2; + m_dac2.enable = false; + m_dac2.initialized = false; + m_dac2.buf_rptr = 0x10; + m_dac2.buf_wptr = 0x10; // Start PCI writing to bottom half of buffer + + m_stream->update(); +} + +void es1373_device::map_extra(UINT64 memory_window_start, UINT64 memory_window_end, UINT64 memory_offset, address_space *memory_space, + UINT64 io_window_start, UINT64 io_window_end, UINT64 io_offset, address_space *io_space) +{ + m_memory_space = memory_space; +} + +//------------------------------------------------- +// device_timer - called when our device timer expires +//------------------------------------------------- +void es1373_device::device_timer(emu_timer &timer, device_timer_id tid, int param, void *ptr) +{ + m_stream->update(); +} + +//------------------------------------------------- +// sound_stream_update - handle update requests for +// our sound stream +//------------------------------------------------- +void es1373_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + if (m_dac1.enable) { + logerror("%s: sound_stream_update DAC1 not implemented yet\n", tag()); + } + + if (m_dac2.enable) { + send_audio_out(m_dac2, ICSTATUS_DAC2_INT_MASK, outputs[0], outputs[1], samples); + } + + if (m_adc.enable) { + if (m_adc.format!=SCTRL_16BIT_MONO) { + logerror("%s: sound_stream_update Only SCTRL_16BIT_MONO recorded supported\n", tag()); + } else { + for (int i=0; im_adc.buf_size) { + if (m_adc.loop_en) { + // Keep playing + m_adc.buf_count = 0; + if (LOG_ES) + logerror("%X: send_audio_out ADC clearing buf_count\n", machine().device("maincpu")->safe_pc()); + } + if (m_adc.int_en) { + m_es_regs[ES_INT_CS_STATUS] |= ICSTATUS_ADC_INT_MASK; + if (LOG_ES) + logerror("%X: send_audio_out Setting ADC interrupt\n", machine().device("maincpu")->safe_pc()); + } + } + if (!(m_adc.buf_count&1) && !(m_adc.buf_wptr&0xf)) { + m_adc.buf_wptr -= 0x10; + } + // PCI Write Transfer + if (command & 0x4) { + if ((m_adc.buf_rptr&8)^(m_adc.buf_wptr&8)) { + transfer_pci_audio(m_adc, ES_PCI_WRITE); + } + } + } + } + } + } + if (m_es_regs[ES_INT_CS_STATUS]&(ICSTATUS_DAC1_INT_MASK|ICSTATUS_DAC2_INT_MASK|ICSTATUS_ADC_INT_MASK)) { + m_es_regs[ES_INT_CS_STATUS] |= ICSTATUS_INTR_MASK; + // Assert interrupt + //m_cpu->set_input_line(ES_IRQ_NUM, ASSERT_LINE); + if (m_irq_num!=-1) { + m_cpu->set_input_line(m_irq_num, ASSERT_LINE); + } + } +} + +//------------------------------------------------- +// send_audio_out - Sends channel audio output data +//------------------------------------------------- +void es1373_device::send_audio_out(chan_info& chan, UINT32 intr_mask, stream_sample_t *outL, stream_sample_t *outR, int samples) +{ + // Only transfer PCI data if bus mastering is enabled + // Fill initial half buffer + if (1 && (command & 0x4) && (!chan.initialized)) { + chan.initialized = true; + transfer_pci_audio(chan, ES_PCI_READ); + } + //UINT32 sample_size = calc_size(chan.format); + // Send data to sound stream + bool buf_row_done; + for (int i=0; isafe_pc(), chan.number, samples, chan.buf_count, chan.buf_size, chan.buf_rptr, chan.buf_wptr); + // Buffer is 4 bytes per location, need to switch on sample mode + switch (chan.format) { + case SCTRL_8BIT_MONO: + logerror("es1373_device::send_audio_out SCTRL_8BIT_MONO not implemented yet\n"); + break; + case SCTRL_8BIT_STEREO: + logerror("es1373_device::send_audio_out SCTRL_8BIT_STEREO not implemented yet\n"); + break; + case SCTRL_16BIT_MONO: + // The sound cache is 32 bit wide fifo, so each entry is two mono 16 bit samples + if ((chan.buf_count&0x1)) { + // Read high 16 bits + outL[i] = outR[i] = (INT16)(m_sound_cache[chan.buf_rptr]>>16); + chan.buf_rptr++; + buf_row_done = true; + } else { + // Read low 16 bits + outL[i] = outR[i] = (INT16)(m_sound_cache[chan.buf_rptr]&0xffff); + } + break; + case SCTRL_16BIT_STEREO: + // The sound cache is 32 bit wide fifo, so each entry is one stereo 16 bit sample + outL[i] = (INT16) m_sound_cache[chan.buf_rptr]&0xffff; + outR[i] = (INT16) m_sound_cache[chan.buf_rptr]>>16; + chan.buf_rptr++; + buf_row_done = true; + break; + } + if (LOG_ES_FILE && m_tempCount<1000000) { + m_tempCount++; + //logerror("es1373_device::sound_stream_update count: %i samp16: %X\n", i, samp16); + //if (LOG_ES_FILE && m_eslog) + //fprintf(m_eslog, "%i\n", samp16); + } + chan.buf_count++; + if (chan.buf_count > chan.buf_size) { + if (chan.loop_en) { + // Keep playing + //chan.buf_count -= 1; // Should check SCTRL_P2_END_MASK + chan.buf_count = 0; + //chan.buf_rptr -= 1; + if (LOG_ES) + logerror("%X: send_audio_out DAC2 clearing buf_count\n", machine().device("maincpu")->safe_pc()); + } + if (chan.int_en) { + m_es_regs[ES_INT_CS_STATUS] |= intr_mask; + if (LOG_ES) + logerror("%X: send_audio_out Setting DAC2 interrupt\n", machine().device("maincpu")->safe_pc()); + } + } + if (buf_row_done && !(chan.buf_rptr&0xf)) { + chan.buf_rptr -= 0x10; + } + } else { + // Send zeros? + outL[i] = outR[i] = 0; + } + } +} + +void es1373_device::transfer_pci_audio(chan_info& chan, int type) +{ + UINT32 pci_addr, data; + pci_addr = chan.pci_addr + (chan.pci_count<<2); + if (LOG_ES) + logerror("%s: transfer_pci_audio start chan: %X pci_addr: %08X pci_count: %X pci_size: %X buf_rptr: %X buf_wptr: %X\n", + machine().describe_context(), chan.number, pci_addr, chan.pci_count, chan.pci_size, chan.buf_rptr, chan.buf_wptr); + // Always transfer 8 longwords + for (int i=0; i<8; i++) { + pci_addr = chan.pci_addr + (chan.pci_count<<2); + if (type==ES_PCI_READ) { + data = m_memory_space->read_dword(pci_addr, 0xffffffff); + m_sound_cache[chan.buf_wptr++] = data; + if (!(chan.buf_wptr&0xf)) { + chan.buf_wptr -= 0x10; + } + } else { + data = m_sound_cache[chan.buf_rptr++]; + m_memory_space->write_dword(pci_addr, data); + if (!(chan.buf_rptr&0xf)) { + chan.buf_rptr -= 0x10; + } + } + if (chan.pci_count==chan.pci_size) { + chan.pci_count = 0; + } else { + chan.pci_count++; + } + } +} + +UINT32 es1373_device::calc_size(const UINT8 &format) +{ + switch (format) { + case SCTRL_8BIT_MONO: + return 1; + break; + case SCTRL_8BIT_STEREO: + return 2; + break; + case SCTRL_16BIT_MONO: + return 2; + break; + case SCTRL_16BIT_STEREO: + return 4; + break; + } + logerror("%s: calc_size Invalid format = %X specified\n", tag(), format); + return 0; +} + +READ32_MEMBER (es1373_device::reg_r) +{ + UINT32 result = m_es_regs[offset]; + switch (offset) { + case ES_CODEC: + break; + case ES_DAC2_CNT: + result = ((m_dac2.buf_size-m_dac2.buf_count)<<16) | m_dac2.buf_size; + break; + case ES_HOST_IF0: // 0x30 + result = m_sound_cache[(m_es_regs[ES_MEM_PAGE]<<2) | 0x0]; + switch (m_es_regs[ES_MEM_PAGE]&0xf) { + case 0xc: + result = m_dac1.pci_addr; + break; + case 0xd: + result = m_adc.pci_addr; + break; + default: + break; + } + break; + case ES_HOST_IF1: // 0x34 + result = m_sound_cache[(m_es_regs[ES_MEM_PAGE]<<2) | 0x1]; + switch (m_es_regs[ES_MEM_PAGE]&0xf) { + case 0xc: + result = (m_dac1.pci_count<<16) | m_dac1.pci_size; + break; + case 0xd: + result = (m_adc.pci_count<<16) | m_adc.pci_size; + break; + default: + break; + } + break; + case ES_HOST_IF2: // 0x38 + result = m_sound_cache[(m_es_regs[ES_MEM_PAGE]<<2) | 0x2]; + switch (m_es_regs[ES_MEM_PAGE]&0xf) { + case 0xc: + result = m_dac2.pci_addr; + break; + default: + break; + } + break; + case ES_HOST_IF3: // 0x3C + result = m_sound_cache[(m_es_regs[ES_MEM_PAGE]<<2) | 0x3]; + switch (m_es_regs[ES_MEM_PAGE]&0xf) { + case 0xc: + result = ((m_dac2.pci_count)<<16) | m_dac2.pci_size; + break; + default: + break; + } + break; + default: + break; + } + if (LOG_ES_REG) + logerror("%08X:ES1373 read from offset %02X = %08X & %08X\n", machine().device("maincpu")->safe_pc(), offset*4, result, mem_mask); + return result; +} + +WRITE32_MEMBER(es1373_device::reg_w) +{ + COMBINE_DATA(&m_es_regs[offset]); + switch (offset) { + case ES_INT_CS_CTRL: + m_dac1.enable = (m_es_regs[ES_INT_CS_CTRL] & ICCTRL_DAC1_EN_MASK); + m_dac2.enable = (m_es_regs[ES_INT_CS_CTRL] & ICCTRL_DAC2_EN_MASK); + m_adc.enable = (m_es_regs[ES_INT_CS_CTRL] & ICCTRL_ADC_EN_MASK); + break; + case ES_SRC_IF: + if (data&(1<<24)) { + // Write to Sample Rate Converter Ram + m_src_ram[(data>>25)&0x7F] = data&0xFFFF; + } else { + // Read From Sample Rate Converter Ram + m_es_regs[offset] = (data&0xFFFF0000) | m_src_ram[(data>>25)&0x7F]; + } + break; + case ES_CODEC: + if (data&(1<<23)) { + // Read from AC97 codec registers + m_es_regs[offset] = (data&0xFFFF0000) | m_ac97_regs[(data>>16)&0x7f] | 0x80000000; + } else { + // Write to AC97 codec registers + m_ac97_regs[(data>>16)&0x7f] = data&0xFFFF; + } + break; + case ES_SERIAL_CTRL: + m_adc.loop_en = !(m_es_regs[ES_SERIAL_CTRL] & SCTRL_R1_LOOP_MASK); + m_dac2.loop_en = !(m_es_regs[ES_SERIAL_CTRL] & SCTRL_P2_LOOP_MASK); + m_dac1.loop_en = !(m_es_regs[ES_SERIAL_CTRL] & SCTRL_P1_LOOP_MASK); + m_adc.int_en = m_es_regs[ES_SERIAL_CTRL] & SCTRL_R1_INT_EN_MASK; + m_dac2.int_en = m_es_regs[ES_SERIAL_CTRL] & SCTRL_P2_INT_EN_MASK; + m_dac1.int_en = m_es_regs[ES_SERIAL_CTRL] & SCTRL_P1_INT_EN_MASK; + m_adc.format = (m_es_regs[ES_SERIAL_CTRL] & SCTRL_R1_S_MASK)>>4; + m_dac2.format = (m_es_regs[ES_SERIAL_CTRL] & SCTRL_P2_S_MASK)>>2; + m_dac1.format = (m_es_regs[ES_SERIAL_CTRL] & SCTRL_P1_S_MASK)>>0; + if (!m_adc.int_en) m_es_regs[ES_INT_CS_STATUS] &= ~ICSTATUS_ADC_INT_MASK; + if (!m_dac1.int_en) m_es_regs[ES_INT_CS_STATUS] &= ~ICSTATUS_DAC1_INT_MASK; + if (!m_dac2.int_en) m_es_regs[ES_INT_CS_STATUS] &= ~ICSTATUS_DAC2_INT_MASK; + // Clear the summary interrupt and irq line + if (!(m_es_regs[ES_INT_CS_STATUS]&(ICSTATUS_DAC1_INT_MASK|ICSTATUS_DAC2_INT_MASK|ICSTATUS_ADC_INT_MASK))) { + // Deassert interrupt + if (m_es_regs[ES_INT_CS_STATUS]&ICSTATUS_INTR_MASK && m_irq_num!=-1) { + m_cpu->set_input_line(m_irq_num, CLEAR_LINE); + m_es_regs[ES_INT_CS_STATUS] &= ~ICSTATUS_INTR_MASK; + if (0 && LOG_ES_REG) + logerror("%X: es1373_device::reg_w Clearing interrupt\n", machine().device("maincpu")->safe_pc()); + } + } + if (0 && LOG_ES_REG) + logerror("%s: es1373_device::reg_w adc_int_en: %i dac1_int_en: %i dac2_int_en: %i\n", tag(), m_adc.int_en, m_dac1.int_en, m_dac2.int_en); + break; + case ES_DAC2_CNT: + m_dac2.buf_count = 0; + m_dac2.buf_size = data&0xffff; + break; + case ES_HOST_IF0: // 0x30 + m_sound_cache[(m_es_regs[ES_MEM_PAGE]<<2) | 0x0] = data; + switch (m_es_regs[ES_MEM_PAGE]&0xf) { + case 0xc: + m_dac1.pci_addr = data; + break; + case 0xd: + m_adc.pci_addr = data; + break; + default: + break; + } + break; + case ES_HOST_IF1: // 0x34 + m_sound_cache[(m_es_regs[ES_MEM_PAGE]<<2) | 0x1] = data; + switch (m_es_regs[ES_MEM_PAGE]&0xf) { + case 0xc: + m_dac1.pci_count = (data>>16)&0xffff; + m_dac1.pci_size = data&0xffff; + break; + case 0xd: + m_adc.pci_count = (data>>16)&0xffff; + m_adc.pci_size = data&0xffff; + break; + default: + break; + } + break; + case ES_HOST_IF2: // 0x38 + m_sound_cache[(m_es_regs[ES_MEM_PAGE]<<2) | 0x2] = data; + switch (m_es_regs[ES_MEM_PAGE]&0xf) { + case 0xc: + m_dac2.pci_addr = data; + break; + default: + break; + } + break; + case ES_HOST_IF3: // 0x3C + m_sound_cache[(m_es_regs[ES_MEM_PAGE]<<2) | 0x3] = data; + switch (m_es_regs[ES_MEM_PAGE]&0xf) { + case 0xc: + m_dac2.pci_count = (data>>16)&0xffff; + m_dac2.pci_size = data&0xffff; + if (LOG_ES_REG) + logerror("%08X:ES1373 write to offset %02X = %08X & %08X\n", machine().device("maincpu")->safe_pc(), offset*4, data, mem_mask); + break; + default: + break; + } + break; + default: + break; + } + + if (LOG_ES_REG) + logerror("%08X:ES1373 write to offset %02X = %08X & %08X\n", machine().device("maincpu")->safe_pc(), offset*4, data, mem_mask); + +} diff --git a/src/devices/sound/es1373.h b/src/devices/sound/es1373.h new file mode 100644 index 00000000000..a5c7e974204 --- /dev/null +++ b/src/devices/sound/es1373.h @@ -0,0 +1,145 @@ +// license:BSD-3-Clause +// copyright-holders:Ted Green +// Creative Labs Ensonic AudioPCI97 ES1373 + +#pragma once + +#ifndef ES1373_H +#define ES1373_H + +#include "machine/pci.h" + +// No interrupts +#define MCFG_ES1373_ADD(_tag) \ + MCFG_PCI_DEVICE_ADD(_tag, ES1373, 0x12741371, 0x04, 0x040100, 0x12741371) + +#define MCFG_ES1373_IRQ_ADD(_cpu_tag, _irq_num) \ + downcast(device)->set_irq_info(_cpu_tag, _irq_num); + +/* Ensonic ES1373 registers 0x00-0x3f */ +#define ES_INT_CS_CTRL (0x00/4) +#define ES_INT_CS_STATUS (0x04/4) +#define ES_UART_DATA (0x08/4) +#define ES_UART_STATUS (0x09/4) +#define ES_UART_CTRL (0x09/4) +#define ES_UART_RSVD (0x0A/4) +#define ES_MEM_PAGE (0x0C/4) +#define ES_SRC_IF (0x10/4) +#define ES_CODEC (0x14/4) +#define ES_LEGACY (0x18/4) +#define ES_CHAN_CTRL (0x1C/4) +#define ES_SERIAL_CTRL (0x20/4) +#define ES_DAC1_CNT (0x24/4) +#define ES_DAC2_CNT (0x28/4) +#define ES_ADC_CNT (0x2C/4) +#define ES_HOST_IF0 (0x30/4) +#define ES_HOST_IF1 (0x34/4) +#define ES_HOST_IF2 (0x38/4) +#define ES_HOST_IF3 (0x3C/4) + +// Interrupt/Chip Select Control Register (ES_INT_CS_CTRL) bits +#define ICCTRL_ADC_STOP_MASK 0x00002000 +#define ICCTRL_DAC1_EN_MASK 0x00000040 +#define ICCTRL_DAC2_EN_MASK 0x00000020 +#define ICCTRL_ADC_EN_MASK 0x00000010 +#define ICCTRL_UART_EN_MASK 0x00000008 +#define ICCTRL_JYSTK_EN_MASK 0x00000004 + +// Interrupt/Chip Select Status Register (ES_INT_CS_STATUS) bits +#define ICSTATUS_INTR_MASK 0x80000000 +#define ICSTATUS_DAC1_INT_MASK 0x00000004 +#define ICSTATUS_DAC2_INT_MASK 0x00000002 +#define ICSTATUS_ADC_INT_MASK 0x00000001 + +// Serial Interface Control Register (ES_SERIAL_CTRL) bits +#define SCTRL_P2_END_MASK 0x00380000 +#define SCTRL_P2_START_MASK 0x00070000 +#define SCTRL_R1_LOOP_MASK 0x00008000 +#define SCTRL_P2_LOOP_MASK 0x00004000 +#define SCTRL_P1_LOOP_MASK 0x00002000 +#define SCTRL_P2_PAUSE_MASK 0x00001000 +#define SCTRL_P1_PAUSE_MASK 0x00000800 +#define SCTRL_R1_INT_EN_MASK 0x00000400 +#define SCTRL_P2_INT_EN_MASK 0x00000200 +#define SCTRL_P1_INT_EN_MASK 0x00000100 +#define SCTRL_P1_RELOAD_MASK 0x00000080 +#define SCTRL_P2_STOP_MASK 0x00000040 +#define SCTRL_R1_S_MASK 0x00000030 +#define SCTRL_P2_S_MASK 0x0000000C +#define SCTRL_P1_S_MASK 0x00000003 + +#define SCTRL_8BIT_MONO 0x0 +#define SCTRL_8BIT_STEREO 0x1 +#define SCTRL_16BIT_MONO 0x2 +#define SCTRL_16BIT_STEREO 0x3 + +#define ES_PCI_READ 0 +#define ES_PCI_WRITE 1 + +struct chan_info { + int number; + bool enable; + bool int_en; + bool loop_en; + bool initialized; + UINT8 format; // Format of channel + UINT32 buf_wptr; // Address to sample cache memory + UINT32 buf_rptr; // Address to sample cache memory + UINT16 buf_count; // Number of samples that have been played + UINT16 buf_size; // Number of samples minus one to play + UINT32 pci_addr; // PCI Addresss for system memory accesses + UINT16 pci_count; // Number of 32 bits transfered + UINT16 pci_size; // Total number of words (32 bits) minus one in system memory +}; + +class es1373_device : public pci_device, public device_sound_interface +{ +public: + es1373_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual void map_extra(UINT64 memory_window_start, UINT64 memory_window_end, UINT64 memory_offset, address_space *memory_space, + UINT64 io_window_start, UINT64 io_window_end, UINT64 io_offset, address_space *io_space); + + void set_irq_info(const char *tag, const int irq_num); + + DECLARE_READ32_MEMBER (reg_r); + DECLARE_WRITE32_MEMBER(reg_w); + + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + + // Sound stream + sound_stream *m_stream; + +protected: + virtual void device_start(); + virtual void device_stop(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + + FILE *m_eslog; + +private: + UINT32 m_tempCount; + emu_timer *m_timer; + address_space *m_memory_space; + const char *m_cpu_tag; + cpu_device *m_cpu; + int m_irq_num; + DECLARE_ADDRESS_MAP(map, 32); + UINT16 m_ac97_regs[0x80]; + UINT32 m_es_regs[0x10]; + UINT32 m_sound_cache[0x40]; + UINT16 m_src_ram[0x80]; + chan_info m_dac1; + chan_info m_dac2; + chan_info m_adc; + void transfer_pci_audio(chan_info& chan, int type); + UINT32 calc_size(const UINT8 &format); + void send_audio_out(chan_info& chan, UINT32 intr_mask, stream_sample_t *outL, stream_sample_t *outR, int samples); + +}; + +extern const device_type ES1373; + +#endif diff --git a/src/devices/sound/es5503.c b/src/devices/sound/es5503.c new file mode 100644 index 00000000000..b1881412da2 --- /dev/null +++ b/src/devices/sound/es5503.c @@ -0,0 +1,451 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/* + + ES5503 - Ensoniq ES5503 "DOC" emulator v2.1.1 + By R. Belmont. + + Copyright R. Belmont. + + History: the ES5503 was the next design after the famous C64 "SID" by Bob Yannes. + It powered the legendary Mirage sampler (the first affordable pro sampler) as well + as the ESQ-1 synth/sequencer. The ES5505 (used in Taito's F3 System) and 5506 + (used in the "Soundscape" series of ISA PC sound cards) followed on a fundamentally + similar architecture. + + Bugs: On the real silicon, oscillators 30 and 31 have random volume fluctuations and are + unusable for playback. We don't attempt to emulate that. :-) + + Additionally, in "swap" mode, there's one cycle when the switch takes place where the + oscillator's output is 0x80 (centerline) regardless of the sample data. This can + cause audible clicks and a general degradation of audio quality if the correct sample + data at that point isn't 0x80 or very near it. + + Changes: + 0.2 (RB) - improved behavior for volumes > 127, fixes missing notes in Nucleus & missing voices in Thexder + 0.3 (RB) - fixed extraneous clicking, improved timing behavior for e.g. Music Construction Set & Music Studio + 0.4 (RB) - major fixes to IRQ semantics and end-of-sample handling. + 0.5 (RB) - more flexible wave memory hookup (incl. banking) and save state support. + 1.0 (RB) - properly respects the input clock + 2.0 (RB) - C++ conversion, more accurate oscillator IRQ timing + 2.1 (RB) - Corrected phase when looping; synthLAB, Arkanoid, and Arkanoid II no longer go out of tune + 2.1.1 (RB) - Fixed issue introduced in 2.0 where IRQs were delayed +*/ + +#include "emu.h" +#include "es5503.h" + +// device type definition +const device_type ES5503 = &device_creator; + +// useful constants +static const UINT16 wavesizes[8] = { 256, 512, 1024, 2048, 4096, 8192, 16384, 32768 }; +static const UINT32 wavemasks[8] = { 0x1ff00, 0x1fe00, 0x1fc00, 0x1f800, 0x1f000, 0x1e000, 0x1c000, 0x18000 }; +static const UINT32 accmasks[8] = { 0xff, 0x1ff, 0x3ff, 0x7ff, 0xfff, 0x1fff, 0x3fff, 0x7fff }; +static const int resshifts[8] = { 9, 10, 11, 12, 13, 14, 15, 16 }; + +// default address map +static ADDRESS_MAP_START( es5503, AS_0, 8, es5503_device ) + AM_RANGE(0x000000, 0x1ffff) AM_ROM +ADDRESS_MAP_END + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// es5503_device - constructor +//------------------------------------------------- + +es5503_device::es5503_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, ES5503, "Ensoniq ES5503", tag, owner, clock, "es5503", __FILE__), + device_sound_interface(mconfig, *this), + device_memory_interface(mconfig, *this), + m_space_config("es5503_samples", ENDIANNESS_LITTLE, 8, 17, 0, NULL, *ADDRESS_MAP_NAME(es5503)), + m_irq_func(*this), + m_adc_func(*this) +{ +} + +//------------------------------------------------- +// memory_space_config - return a description of +// any address spaces owned by this device +//------------------------------------------------- + +const address_space_config *es5503_device::memory_space_config(address_spacenum spacenum) const +{ + return (spacenum == 0) ? &m_space_config : NULL; +} + +//------------------------------------------------- +// static_set_type - configuration helper to set +// the IRQ callback +//------------------------------------------------- + +void es5503_device::static_set_channels(device_t &device, int channels) +{ + es5503_device &es5503 = downcast(device); + es5503.output_channels = channels; +} + +//------------------------------------------------- +// device_timer - called when our device timer expires +//------------------------------------------------- + +void es5503_device::device_timer(emu_timer &timer, device_timer_id tid, int param, void *ptr) +{ + m_stream->update(); +} + +// halt_osc: handle halting an oscillator +// chip = chip ptr +// onum = oscillator # +// type = 1 for 0 found in sample data, 0 for hit end of table size +void es5503_device::halt_osc(int onum, int type, UINT32 *accumulator, int resshift) +{ + ES5503Osc *pOsc = &oscillators[onum]; + ES5503Osc *pPartner = &oscillators[onum^1]; + int mode = (pOsc->control>>1) & 3; + + // if 0 found in sample data or mode is not free-run, halt this oscillator + if ((mode != MODE_FREE) || (type != 0)) + { + pOsc->control |= 1; + } + else // preserve the relative phase of the oscillator when looping + { + UINT16 wtsize = pOsc->wtsize - 1; + UINT32 altram = (*accumulator) >> resshift; + + if (altram > wtsize) + { + altram -= wtsize; + } + else + { + altram = 0; + } + + *accumulator = altram << resshift; + } + int omode = (pPartner->control>>1) & 3; + + // if swap mode, start the partner + if ((mode == MODE_SWAP) || (omode == MODE_SWAP)) + { + pPartner->control &= ~1; // clear the halt bit + pPartner->accumulator = 0; // and make sure it starts from the top (does this also need phase preservation?) + } + + // IRQ enabled for this voice? + if (pOsc->control & 0x08) + { + pOsc->irqpend = 1; + + m_irq_func(1); + } +} + +void es5503_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + static INT32 mix[(44100/60)*2*8]; + INT32 *mixp; + int osc, snum, i; + UINT32 ramptr; + + assert(samples < (44100/60)*2); + memset(mix, 0, sizeof(mix)); + + for (int chan = 0; chan < output_channels; chan++) + { + for (osc = 0; osc < (oscsenabled+1); osc++) + { + ES5503Osc *pOsc = &oscillators[osc]; + + if (!(pOsc->control & 1) && ((pOsc->control >> 4) & (output_channels - 1)) == chan) + { + UINT32 wtptr = pOsc->wavetblpointer & wavemasks[pOsc->wavetblsize], altram; + UINT32 acc = pOsc->accumulator; + UINT16 wtsize = pOsc->wtsize - 1; + UINT8 ctrl = pOsc->control; + UINT16 freq = pOsc->freq; + INT16 vol = pOsc->vol; + INT8 data = -128; + int resshift = resshifts[pOsc->resolution] - pOsc->wavetblsize; + UINT32 sizemask = accmasks[pOsc->wavetblsize]; + mixp = &mix[0] + chan; + + for (snum = 0; snum < samples; snum++) + { + altram = acc >> resshift; + ramptr = altram & sizemask; + + acc += freq; + + // channel strobe is always valid when reading; this allows potentially banking per voice + m_channel_strobe = (ctrl>>4) & 0xf; + data = (INT32)m_direct->read_byte(ramptr + wtptr) ^ 0x80; + + if (m_direct->read_byte(ramptr + wtptr) == 0x00) + { + halt_osc(osc, 1, &acc, resshift); + } + else + { + *mixp += data * vol; + mixp += output_channels; + + if (altram >= wtsize) + { + halt_osc(osc, 0, &acc, resshift); + } + } + + // if oscillator halted, we've got no more samples to generate + if (pOsc->control & 1) + { + ctrl |= 1; + break; + } + } + + pOsc->control = ctrl; + pOsc->accumulator = acc; + pOsc->data = data ^ 0x80; + } + } + } + + mixp = &mix[0]; + for (i = 0; i < samples; i++) + for (int chan = 0; chan < output_channels; chan++) + outputs[chan][i] = (*mixp++)>>1; +} + + +void es5503_device::device_start() +{ + int osc; + + // find our direct access + m_direct = &space().direct(); + + m_irq_func.resolve_safe(); + m_adc_func.resolve_safe(0); + + rege0 = 0xff; + + for (osc = 0; osc < 32; osc++) + { + save_item(NAME(oscillators[osc].freq), osc); + save_item(NAME(oscillators[osc].wtsize), osc); + save_item(NAME(oscillators[osc].control), osc); + save_item(NAME(oscillators[osc].vol), osc); + save_item(NAME(oscillators[osc].data), osc); + save_item(NAME(oscillators[osc].wavetblpointer), osc); + save_item(NAME(oscillators[osc].wavetblsize), osc); + save_item(NAME(oscillators[osc].resolution), osc); + save_item(NAME(oscillators[osc].accumulator), osc); + save_item(NAME(oscillators[osc].irqpend), osc); + } + + output_rate = (clock()/8)/34; // (input clock / 8) / # of oscs. enabled + 2 + m_stream = machine().sound().stream_alloc(*this, 0, output_channels, output_rate); + + m_timer = timer_alloc(0, NULL); + m_timer->adjust(attotime::from_hz(output_rate), 0, attotime::from_hz(output_rate)); +} + +void es5503_device::device_reset() +{ + rege0 = 0xff; + + for (int osc = 0; osc < 32; osc++) + { + oscillators[osc].freq = 0; + oscillators[osc].wtsize = 0; + oscillators[osc].control = 0; + oscillators[osc].vol = 0; + oscillators[osc].data = 0x80; + oscillators[osc].wavetblpointer = 0; + oscillators[osc].wavetblsize = 0; + oscillators[osc].resolution = 0; + oscillators[osc].accumulator = 0; + oscillators[osc].irqpend = 0; + } + + oscsenabled = 1; + + m_channel_strobe = 0; + + output_rate = (clock()/8)/34; // (input clock / 8) / # of oscs. enabled + 2 +} + +READ8_MEMBER( es5503_device::read ) +{ + UINT8 retval; + int i; + + m_stream->update(); + + if (offset < 0xe0) + { + int osc = offset & 0x1f; + + switch(offset & 0xe0) + { + case 0: // freq lo + return (oscillators[osc].freq & 0xff); + + case 0x20: // freq hi + return (oscillators[osc].freq >> 8); + + case 0x40: // volume + return oscillators[osc].vol; + + case 0x60: // data + return oscillators[osc].data; + + case 0x80: // wavetable pointer + return (oscillators[osc].wavetblpointer>>8) & 0xff; + + case 0xa0: // oscillator control + return oscillators[osc].control; + + case 0xc0: // bank select / wavetable size / resolution + retval = 0; + if (oscillators[osc].wavetblpointer & 0x10000) + { + retval |= 0x40; + } + + retval |= (oscillators[osc].wavetblsize<<3); + retval |= oscillators[osc].resolution; + return retval; + } + } + else // global registers + { + switch (offset) + { + case 0xe0: // interrupt status + retval = rege0; + + m_irq_func(0); + + // scan all oscillators + for (i = 0; i < oscsenabled+1; i++) + { + if (oscillators[i].irqpend) + { + // signal this oscillator has an interrupt + retval = i<<1; + + rege0 = retval | 0x80; + + // and clear its flag + oscillators[i].irqpend = 0; + break; + } + } + + // if any oscillators still need to be serviced, assert IRQ again immediately + for (i = 0; i < oscsenabled+1; i++) + { + if (oscillators[i].irqpend) + { + m_irq_func(1); + break; + } + } + + return retval; + + case 0xe1: // oscillator enable + return oscsenabled<<1; + + case 0xe2: // A/D converter + return m_adc_func(); + } + } + + return 0; +} + +WRITE8_MEMBER( es5503_device::write ) +{ + m_stream->update(); + + if (offset < 0xe0) + { + int osc = offset & 0x1f; + + switch(offset & 0xe0) + { + case 0: // freq lo + oscillators[osc].freq &= 0xff00; + oscillators[osc].freq |= data; + break; + + case 0x20: // freq hi + oscillators[osc].freq &= 0x00ff; + oscillators[osc].freq |= (data<<8); + break; + + case 0x40: // volume + oscillators[osc].vol = data; + break; + + case 0x60: // data - ignore writes + break; + + case 0x80: // wavetable pointer + oscillators[osc].wavetblpointer = (data<<8); + break; + + case 0xa0: // oscillator control + // if a fresh key-on, reset the ccumulator + if ((oscillators[osc].control & 1) && (!(data&1))) + { + oscillators[osc].accumulator = 0; + } + + oscillators[osc].control = data; + break; + + case 0xc0: // bank select / wavetable size / resolution + if (data & 0x40) // bank select - not used on the Apple IIgs + { + oscillators[osc].wavetblpointer |= 0x10000; + } + else + { + oscillators[osc].wavetblpointer &= 0xffff; + } + + oscillators[osc].wavetblsize = ((data>>3) & 7); + oscillators[osc].wtsize = wavesizes[oscillators[osc].wavetblsize]; + oscillators[osc].resolution = (data & 7); + break; + } + } + else // global registers + { + switch (offset) + { + case 0xe0: // interrupt status + break; + + case 0xe1: // oscillator enable + oscsenabled = (data>>1) & 0x1f; + + output_rate = (clock()/8)/(2+oscsenabled); + m_stream->set_sample_rate(output_rate); + m_timer->adjust(attotime::from_hz(output_rate), 0, attotime::from_hz(output_rate)); + break; + + case 0xe2: // A/D converter + break; + } + } +} diff --git a/src/devices/sound/es5503.h b/src/devices/sound/es5503.h new file mode 100644 index 00000000000..582456e830b --- /dev/null +++ b/src/devices/sound/es5503.h @@ -0,0 +1,108 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +#pragma once + +#ifndef __ES5503_H__ +#define __ES5503_H__ + +// channels must be a power of two + +#define MCFG_ES5503_ADD(_tag, _clock) \ + MCFG_DEVICE_ADD(_tag, ES5503, _clock) + +#define MCFG_ES5503_OUTPUT_CHANNELS(_channels) \ + es5503_device::static_set_channels(*device, _channels); + +#define MCFG_ES5503_IRQ_FUNC(_write) \ + devcb = &es5503_device::static_set_irqf(*device, DEVCB_##_write); + +#define MCFG_ES5503_ADC_FUNC(_read) \ + devcb = &es5503_device::static_set_adcf(*device, DEVCB_##_read); + +// ======================> es5503_device + +class es5503_device : public device_t, + public device_sound_interface, + public device_memory_interface +{ +public: + // construction/destruction + es5503_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + static void static_set_channels(device_t &device, int channels); + + template static devcb_base &static_set_irqf(device_t &device, _Object object) { return downcast(device).m_irq_func.set_callback(object); } + template static devcb_base &static_set_adcf(device_t &device, _Object object) { return downcast(device).m_adc_func.set_callback(object); } + + DECLARE_READ8_MEMBER(read); + DECLARE_WRITE8_MEMBER(write); + + UINT8 get_channel_strobe() { return m_channel_strobe; } + + sound_stream *m_stream; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id tid, int param, void *ptr); + + // device_sound_interface overrides + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const; + + const address_space_config m_space_config; + + devcb_write_line m_irq_func; + devcb_read8 m_adc_func; + + emu_timer *m_sync_timer; + +private: + enum + { + MODE_FREE = 0, + MODE_ONESHOT = 1, + MODE_SYNCAM = 2, + MODE_SWAP = 3 + }; + + struct ES5503Osc + { + UINT16 freq; + UINT16 wtsize; + UINT8 control; + UINT8 vol; + UINT8 data; + UINT32 wavetblpointer; + UINT8 wavetblsize; + UINT8 resolution; + + UINT32 accumulator; + UINT8 irqpend; + }; + + ES5503Osc oscillators[32]; + + INT8 oscsenabled; // # of oscillators enabled + int rege0; // contents of register 0xe0 + + UINT8 m_channel_strobe; + + int output_channels; + UINT32 output_rate; + + emu_timer *m_timer; + + direct_read_data *m_direct; + + void halt_osc(int onum, int type, UINT32 *accumulator, int resshift); +}; + + +// device type definition +extern const device_type ES5503; + +#endif /* __ES5503_H__ */ diff --git a/src/devices/sound/es5506.c b/src/devices/sound/es5506.c new file mode 100644 index 00000000000..2c46b7560d6 --- /dev/null +++ b/src/devices/sound/es5506.c @@ -0,0 +1,2274 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/********************************************************************************************** + + Ensoniq ES5505/6 driver + by Aaron Giles + +Ensoniq OTIS - ES5505 Ensoniq OTTO - ES5506 + + OTIS is a VLSI device designed in a 2 micron double metal OTTO is a VLSI device designed in a 1.5 micron double metal + CMOS process. The device is the next generation of audio CMOS process. The device is the next generation of audio + technology from ENSONIQ. This new chip achieves a new technology from ENSONIQ. All calculations in the device are + level of audio fidelity performance. These improvements made with at least 18-bit accuracy. + are achieved through the use of frequency interpolation + and on board real time digital filters. All calculations The major features of OTTO are: + in the device are made with at least 16 bit accuracy. - 68 pin PLCC package + - On chip real time digital filters + The major features of OTIS are: - Frequency interpolation + - 48 Pin dual in line package - 32 independent voices + - On chip real time digital filters - Loop start and stop posistions for each voice + - Frequency interpolation - Bidirectional and reverse looping + - 32 independent voices (up from 25 in DOCII) - 68000 compatibility for asynchronous bus communication + - Loop start and stop positions for each voice - separate host and sound memory interface + - Bidirectional and reverse looping - 6 channel stereo serial communication port + - 68000 compatibility for asynchronous bus communication - Programmable clocks for defining serial protocol + - On board pulse width modulation D to A - Internal volume multiplication and stereo panning + - 4 channel stereo serial communication port - A to D input for pots and wheels + - Internal volume multiplication and stereo panning - Hardware support for envelopes + - A to D input for pots and wheels - Support for dual OTTO systems + - Up to 10MHz operation - Optional compressed data format for sample data + - Up to 16MHz operation + ______ ______ + _|o \__/ |_ + A17/D13 - |_|1 48|_| - VSS A A A A A A + _| |_ 2 1 1 1 1 1 A + A18/D14 - |_|2 47|_| - A16/D12 0 9 8 7 6 5 1 + _| |_ / / / / / / 4 + A19/D15 - |_|3 46|_| - A15/D11 H H H H H H H V V H D D D D D D / + _| |_ D D D D D D D S D D 1 1 1 1 1 1 D + BS - |_|4 45|_| - A14/D10 0 1 2 3 4 5 6 S D 7 5 4 3 2 1 0 9 + _| |_ ------------------------------------+ + PWZERO - |_|5 44|_| - A13/D9 / 9 8 7 6 5 4 3 2 1 6 6 6 6 6 6 6 6 | + _| |_ / 8 7 6 5 4 3 2 1 | + SER0 - |_|6 43|_| - A12/D8 | | + _| E |_ SER0|10 60|A13/D8 + SER1 - |_|7 N 42|_| - A11/D7 SER1|11 59|A12/D7 + _| S |_ SER2|12 58|A11/D6 + SER2 - |_|8 O 41|_| - A10/D6 SER3|13 ENSONIQ 57|A10/D5 + _| N |_ SER4|14 56|A9/D4 + SER3 - |_|9 I 40|_| - A9/D5 SER5|15 55|A8/D3 + _| Q |_ WCLK|16 54|A7/D2 + SERWCLK - |_|10 39|_| - A8/D4 LRCLK|17 ES5506 53|A6/D1 + _| |_ BCLK|18 52|A5/D0 + SERLR - |_|11 38|_| - A7/D3 RESB|19 51|A4 + _| |_ HA5|20 50|A3 + SERBCLK - |_|12 E 37|_| - A6/D2 HA4|21 OTTO 49|A2 + _| S |_ HA3|22 48|A1 + RLO - |_|13 5 36|_| - A5/D1 HA2|23 47|A0 + _| 5 |_ HA1|24 46|BS1 + RHI - |_|14 0 35|_| - A4/D0 HA0|25 45|BS0 + _| 5 |_ POT_IN|26 44|DTACKB + LLO - |_|15 34|_| - CLKIN | 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 | + _| |_ | 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 | + LHI - |_|16 33|_| - CAS +--------------------------------------+ + _| |_ B E E B E B B D S B B B E K B W W + POT - |_|17 O 32|_| - AMUX S B L N L S S D S S X S L Q / / + _| T |_ E E R E H M C V V A U A C R R R + DTACK - |_|18 I 31|_| - RAS R R D H R M C I M + _| S |_ _ D A + R/W - |_|19 30|_| - E T + _| |_ O + MS - |_|20 29|_| - IRQ P + _| |_ + CS - |_|21 28|_| - A3 + _| |_ + RES - |_|22 27|_| - A2 + _| |_ + VSS - |_|23 26|_| - A1 + _| |_ + VDD - |_|24 25|_| - A0 + |________________| + +***********************************************************************************************/ + +#include "emu.h" +#include "es5506.h" + + +/********************************************************************************************** + + CONSTANTS + +***********************************************************************************************/ + +#define LOG_COMMANDS 0 +#define RAINE_CHECK 0 + +#if MAKE_WAVS +#include "wavwrite.h" +#endif + + +#define MAX_SAMPLE_CHUNK 10000 +#define ULAW_MAXBITS 8 + +#define CONTROL_BS1 0x8000 +#define CONTROL_BS0 0x4000 +#define CONTROL_CMPD 0x2000 +#define CONTROL_CA2 0x1000 +#define CONTROL_CA1 0x0800 +#define CONTROL_CA0 0x0400 +#define CONTROL_LP4 0x0200 +#define CONTROL_LP3 0x0100 +#define CONTROL_IRQ 0x0080 +#define CONTROL_DIR 0x0040 +#define CONTROL_IRQE 0x0020 +#define CONTROL_BLE 0x0010 +#define CONTROL_LPE 0x0008 +#define CONTROL_LEI 0x0004 +#define CONTROL_STOP1 0x0002 +#define CONTROL_STOP0 0x0001 + +#define CONTROL_BSMASK (CONTROL_BS1 | CONTROL_BS0) +#define CONTROL_CAMASK (CONTROL_CA2 | CONTROL_CA1 | CONTROL_CA0) +#define CONTROL_LPMASK (CONTROL_LP4 | CONTROL_LP3) +#define CONTROL_LOOPMASK (CONTROL_BLE | CONTROL_LPE) +#define CONTROL_STOPMASK (CONTROL_STOP1 | CONTROL_STOP0) + + +es550x_device::es550x_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_sound_interface(mconfig, *this), + m_stream(NULL), + m_sample_rate(0), + m_write_latch(0), + m_read_latch(0), + m_master_clock(0), + m_current_page(0), + m_active_voices(0), + m_mode(0), + m_wst(0), + m_wend(0), + m_lrend(0), + m_irqv(0), + m_scratch(NULL), + m_ulaw_lookup(NULL), + m_volume_lookup(NULL), + #if MAKE_WAVS + m_wavraw(NULL), + #endif + m_eslog(NULL), + m_region0(NULL), + m_region1(NULL), + m_region2(NULL), + m_region3(NULL), + m_channels(0), + m_irq_cb(*this), + m_read_port_cb(*this) +{ + for (int i = 0; i < 4; i++) + { + m_region_base[i] = NULL; + } +} + +const device_type ES5506 = &device_creator; + +es5506_device::es5506_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : es550x_device(mconfig, ES5506, "ES5506", tag, owner, clock, "es5506", __FILE__) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- +void es550x_device::device_start() +{ +} + +void es5506_device::device_start() +{ + int j; + UINT32 accum_mask; + int channels = 1; /* 1 channel by default, for backward compatibility */ + + /* only override the number of channels if the value is in the valid range 1 .. 6 */ + if (1 <= m_channels && m_channels <= 6) + channels = m_channels; + + /* debugging */ + if (LOG_COMMANDS && !m_eslog) + m_eslog = fopen("es.log", "w"); + + /* create the stream */ + m_stream = machine().sound().stream_alloc(*this, 0, 2 * channels, clock() / (16*32)); + + /* initialize the regions */ + m_region_base[0] = m_region0 ? (UINT16 *)machine().root_device().memregion(m_region0)->base() : NULL; + m_region_base[1] = m_region1 ? (UINT16 *)machine().root_device().memregion(m_region1)->base() : NULL; + m_region_base[2] = m_region2 ? (UINT16 *)machine().root_device().memregion(m_region2)->base() : NULL; + m_region_base[3] = m_region3 ? (UINT16 *)machine().root_device().memregion(m_region3)->base() : NULL; + + /* initialize the rest of the structure */ + m_master_clock = clock(); + m_irq_cb.resolve(); + m_read_port_cb.resolve(); + m_irqv = 0x80; + m_channels = channels; + + /* KT-76 assumes all voices are active on an ES5506 without setting them! */ + m_active_voices = 31; + m_sample_rate = m_master_clock / (16 * (m_active_voices + 1)); + m_stream->set_sample_rate(m_sample_rate); + + /* compute the tables */ + compute_tables(); + + /* init the voices */ + accum_mask = 0xffffffff; + for (j = 0; j < 32; j++) + { + m_voice[j].index = j; + m_voice[j].control = CONTROL_STOPMASK; + m_voice[j].lvol = 0xffff; + m_voice[j].rvol = 0xffff; + m_voice[j].exbank = 0; + m_voice[j].accum_mask = accum_mask; + } + + /* allocate memory */ + m_scratch = auto_alloc_array_clear(machine(), INT32, 2 * MAX_SAMPLE_CHUNK); + + /* register save */ + save_item(NAME(m_sample_rate)); + save_item(NAME(m_write_latch)); + save_item(NAME(m_read_latch)); + + save_item(NAME(m_current_page)); + save_item(NAME(m_active_voices)); + save_item(NAME(m_mode)); + save_item(NAME(m_wst)); + save_item(NAME(m_wend)); + save_item(NAME(m_lrend)); + save_item(NAME(m_irqv)); + + save_pointer(NAME(m_scratch), 2 * MAX_SAMPLE_CHUNK); + + for (j = 0; j < 32; j++) + { + save_item(NAME(m_voice[j].control), j); + save_item(NAME(m_voice[j].freqcount), j); + save_item(NAME(m_voice[j].start), j); + save_item(NAME(m_voice[j].lvol), j); + save_item(NAME(m_voice[j].end), j); + save_item(NAME(m_voice[j].lvramp), j); + save_item(NAME(m_voice[j].accum), j); + save_item(NAME(m_voice[j].rvol), j); + save_item(NAME(m_voice[j].rvramp), j); + save_item(NAME(m_voice[j].ecount), j); + save_item(NAME(m_voice[j].k2), j); + save_item(NAME(m_voice[j].k2ramp), j); + save_item(NAME(m_voice[j].k1), j); + save_item(NAME(m_voice[j].k1ramp), j); + save_item(NAME(m_voice[j].o4n1), j); + save_item(NAME(m_voice[j].o3n1), j); + save_item(NAME(m_voice[j].o3n2), j); + save_item(NAME(m_voice[j].o2n1), j); + save_item(NAME(m_voice[j].o2n2), j); + save_item(NAME(m_voice[j].o1n1), j); + save_item(NAME(m_voice[j].exbank), j); + save_item(NAME(m_voice[j].filtcount), j); + } + + /* success */ +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void es550x_device::device_reset() +{ +} + +//------------------------------------------------- +// device_stop - device-specific stop +//------------------------------------------------- + +void es550x_device::device_stop() +{ + /* debugging */ + if (LOG_COMMANDS && m_eslog) + { + fclose(m_eslog); + m_eslog = NULL; + } + + #if MAKE_WAVS + { + int i; + + for (i = 0; i < MAX_ES5506; i++) + { + if (es5506[i].m_wavraw) + wav_close(es5506[i].m_wavraw); + } + } + #endif +} + +const device_type ES5505 = &device_creator; + +es5505_device::es5505_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : es550x_device(mconfig, ES5505, "ES5505", tag, owner, clock, "es5505", __FILE__) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void es5505_device::device_start() +{ + int j; + UINT32 accum_mask; + int channels = 1; /* 1 channel by default, for backward compatibility */ + + /* only override the number of channels if the value is in the valid range 1 .. 4 */ + if (1 <= m_channels && m_channels <= 4) + channels = m_channels; + + /* debugging */ + if (LOG_COMMANDS && !m_eslog) + m_eslog = fopen("es.log", "w"); + + /* create the stream */ + m_stream = machine().sound().stream_alloc(*this, 0, 2 * channels, clock() / (16*32)); + + /* initialize the regions */ + m_region_base[0] = m_region0 ? (UINT16 *)machine().root_device().memregion(m_region0)->base() : NULL; + m_region_base[1] = m_region1 ? (UINT16 *)machine().root_device().memregion(m_region1)->base() : NULL; + + /* initialize the rest of the structure */ + m_master_clock = clock(); + m_irq_cb.resolve(); + m_read_port_cb.resolve(); + m_irqv = 0x80; + m_channels = channels; + + /* compute the tables */ + compute_tables(); + + /* init the voices */ + accum_mask = 0x7fffffff; + for (j = 0; j < 32; j++) + { + m_voice[j].index = j; + m_voice[j].control = CONTROL_STOPMASK; + m_voice[j].lvol = 0xffff; + m_voice[j].rvol = 0xffff; + m_voice[j].exbank = 0; + m_voice[j].accum_mask = accum_mask; + } + + /* allocate memory */ + m_scratch = auto_alloc_array_clear(machine(), INT32, 2 * MAX_SAMPLE_CHUNK); + + /* register save */ + save_item(NAME(m_sample_rate)); + save_item(NAME(m_write_latch)); + save_item(NAME(m_read_latch)); + + save_item(NAME(m_current_page)); + save_item(NAME(m_active_voices)); + save_item(NAME(m_mode)); + save_item(NAME(m_wst)); + save_item(NAME(m_wend)); + save_item(NAME(m_lrend)); + save_item(NAME(m_irqv)); + + save_pointer(NAME(m_scratch), 2 * MAX_SAMPLE_CHUNK); + + for (j = 0; j < 32; j++) + { + save_item(NAME(m_voice[j].control), j); + save_item(NAME(m_voice[j].freqcount), j); + save_item(NAME(m_voice[j].start), j); + save_item(NAME(m_voice[j].lvol), j); + save_item(NAME(m_voice[j].end), j); + save_item(NAME(m_voice[j].lvramp), j); + save_item(NAME(m_voice[j].accum), j); + save_item(NAME(m_voice[j].rvol), j); + save_item(NAME(m_voice[j].rvramp), j); + save_item(NAME(m_voice[j].ecount), j); + save_item(NAME(m_voice[j].k2), j); + save_item(NAME(m_voice[j].k2ramp), j); + save_item(NAME(m_voice[j].k1), j); + save_item(NAME(m_voice[j].k1ramp), j); + save_item(NAME(m_voice[j].o4n1), j); + save_item(NAME(m_voice[j].o3n1), j); + save_item(NAME(m_voice[j].o3n2), j); + save_item(NAME(m_voice[j].o2n1), j); + save_item(NAME(m_voice[j].o2n2), j); + save_item(NAME(m_voice[j].o1n1), j); + save_item(NAME(m_voice[j].exbank), j); + save_item(NAME(m_voice[j].filtcount), j); + } + + /* success */ +} + + +/********************************************************************************************** + + update_irq_state -- update the IRQ state + +***********************************************************************************************/ + + +void es550x_device::update_irq_state() +{ + /* ES5505/6 irq line has been set high - inform the host */ + if (!m_irq_cb.isnull()) + m_irq_cb(1); /* IRQB set high */ +} + +void es550x_device::update_internal_irq_state() +{ + /* Host (cpu) has just read the voice interrupt vector (voice IRQ ack). + + Reset the voice vector to show the IRQB line is low (top bit set). + If we have any stacked interrupts (other voices waiting to be + processed - with their IRQ bit set) then they will be moved into + the vector next time the voice is processed. In emulation + terms they get updated next time generate_samples() is called. + */ + + m_irqv=0x80; + + if (!m_irq_cb.isnull()) + m_irq_cb(0); /* IRQB set low */ +} + +/********************************************************************************************** + + compute_tables -- compute static tables + +***********************************************************************************************/ + +void es550x_device::compute_tables() +{ + int i; + + /* allocate ulaw lookup table */ + m_ulaw_lookup = auto_alloc_array_clear(machine(), INT16, 1 << ULAW_MAXBITS); + + /* generate ulaw lookup table */ + for (i = 0; i < (1 << ULAW_MAXBITS); i++) + { + UINT16 rawval = (i << (16 - ULAW_MAXBITS)) | (1 << (15 - ULAW_MAXBITS)); + UINT8 exponent = rawval >> 13; + UINT32 mantissa = (rawval << 3) & 0xffff; + + if (exponent == 0) + m_ulaw_lookup[i] = (INT16)mantissa >> 7; + else + { + mantissa = (mantissa >> 1) | (~mantissa & 0x8000); + m_ulaw_lookup[i] = (INT16)mantissa >> (7 - exponent); + } + } + + /* allocate volume lookup table */ + m_volume_lookup = auto_alloc_array_clear(machine(), UINT16, 4096); + + /* generate volume lookup table */ + for (i = 0; i < 4096; i++) + { + UINT8 exponent = i >> 8; + UINT32 mantissa = (i & 0xff) | 0x100; + + m_volume_lookup[i] = (mantissa << 11) >> (20 - exponent); + } +} + + + +/********************************************************************************************** + + interpolate -- interpolate between two samples + +***********************************************************************************************/ + +#define interpolate(sample1, sample2, accum) \ + (sample1 * (INT32)(0x800 - (accum & 0x7ff)) + \ + sample2 * (INT32)(accum & 0x7ff)) >> 11; + + + +/********************************************************************************************** + + apply_filters -- apply the 4-pole digital filter to the sample + +***********************************************************************************************/ + +#define apply_filters(voice, sample) \ +do \ +{ \ + /* pole 1 is always low-pass using K1 */ \ + sample = ((INT32)(voice->k1 >> 2) * (sample - voice->o1n1) / 16384) + voice->o1n1; \ + voice->o1n1 = sample; \ + \ + /* pole 2 is always low-pass using K1 */ \ + sample = ((INT32)(voice->k1 >> 2) * (sample - voice->o2n1) / 16384) + voice->o2n1; \ + voice->o2n2 = voice->o2n1; \ + voice->o2n1 = sample; \ + \ + /* remaining poles depend on the current filter setting */ \ + switch (voice->control & CONTROL_LPMASK) \ + { \ + case 0: \ + /* pole 3 is high-pass using K2 */ \ + sample = sample - voice->o2n2 + ((INT32)(voice->k2 >> 2) * voice->o3n1) / 32768 + voice->o3n1 / 2; \ + voice->o3n2 = voice->o3n1; \ + voice->o3n1 = sample; \ + \ + /* pole 4 is high-pass using K2 */ \ + sample = sample - voice->o3n2 + ((INT32)(voice->k2 >> 2) * voice->o4n1) / 32768 + voice->o4n1 / 2; \ + voice->o4n1 = sample; \ + break; \ + \ + case CONTROL_LP3: \ + /* pole 3 is low-pass using K1 */ \ + sample = ((INT32)(voice->k1 >> 2) * (sample - voice->o3n1) / 16384) + voice->o3n1; \ + voice->o3n2 = voice->o3n1; \ + voice->o3n1 = sample; \ + \ + /* pole 4 is high-pass using K2 */ \ + sample = sample - voice->o3n2 + ((INT32)(voice->k2 >> 2) * voice->o4n1) / 32768 + voice->o4n1 / 2; \ + voice->o4n1 = sample; \ + break; \ + \ + case CONTROL_LP4: \ + /* pole 3 is low-pass using K2 */ \ + sample = ((INT32)(voice->k2 >> 2) * (sample - voice->o3n1) / 16384) + voice->o3n1; \ + voice->o3n2 = voice->o3n1; \ + voice->o3n1 = sample; \ + \ + /* pole 4 is low-pass using K2 */ \ + sample = ((INT32)(voice->k2 >> 2) * (sample - voice->o4n1) / 16384) + voice->o4n1; \ + voice->o4n1 = sample; \ + break; \ + \ + case CONTROL_LP4 | CONTROL_LP3: \ + /* pole 3 is low-pass using K1 */ \ + sample = ((INT32)(voice->k1 >> 2) * (sample - voice->o3n1) / 16384) + voice->o3n1; \ + voice->o3n2 = voice->o3n1; \ + voice->o3n1 = sample; \ + \ + /* pole 4 is low-pass using K2 */ \ + sample = ((INT32)(voice->k2 >> 2) * (sample - voice->o4n1) / 16384) + voice->o4n1; \ + voice->o4n1 = sample; \ + break; \ + } \ +} while (0) + + + +/********************************************************************************************** + + update_envelopes -- update the envelopes + +***********************************************************************************************/ + +#define update_envelopes(voice, samples) \ +do \ +{ \ + int count = (samples > 1 && samples > voice->ecount) ? voice->ecount : samples; \ + \ + /* decrement the envelope counter */ \ + voice->ecount -= count; \ + \ + /* ramp left volume */ \ + if (voice->lvramp) \ + { \ + voice->lvol += (INT8)voice->lvramp * count; \ + if ((INT32)voice->lvol < 0) voice->lvol = 0; \ + else if (voice->lvol > 0xffff) voice->lvol = 0xffff; \ + } \ + \ + /* ramp right volume */ \ + if (voice->rvramp) \ + { \ + voice->rvol += (INT8)voice->rvramp * count; \ + if ((INT32)voice->rvol < 0) voice->rvol = 0; \ + else if (voice->rvol > 0xffff) voice->rvol = 0xffff; \ + } \ + \ + /* ramp k1 filter constant */ \ + if (voice->k1ramp && ((INT32)voice->k1ramp >= 0 || !(voice->filtcount & 7))) \ + { \ + voice->k1 += (INT8)voice->k1ramp * count; \ + if ((INT32)voice->k1 < 0) voice->k1 = 0; \ + else if (voice->k1 > 0xffff) voice->k1 = 0xffff; \ + } \ + \ + /* ramp k2 filter constant */ \ + if (voice->k2ramp && ((INT32)voice->k2ramp >= 0 || !(voice->filtcount & 7))) \ + { \ + voice->k2 += (INT8)voice->k2ramp * count; \ + if ((INT32)voice->k2 < 0) voice->k2 = 0; \ + else if (voice->k2 > 0xffff) voice->k2 = 0xffff; \ + } \ + \ + /* update the filter constant counter */ \ + voice->filtcount += count; \ + \ +} while (0) + + + +/********************************************************************************************** + + check_for_end_forward + check_for_end_reverse -- check for loop end and loop appropriately + +***********************************************************************************************/ + +#define check_for_end_forward(voice, accum) \ +do \ +{ \ + /* are we past the end? */ \ + if (accum > voice->end && !(voice->control & CONTROL_LEI)) \ + { \ + /* generate interrupt if required */ \ + if (voice->control&CONTROL_IRQE) \ + voice->control |= CONTROL_IRQ; \ + \ + /* handle the different types of looping */ \ + switch (voice->control & CONTROL_LOOPMASK) \ + { \ + /* non-looping */ \ + case 0: \ + voice->control |= CONTROL_STOP0; \ + goto alldone; \ + \ + /* uni-directional looping */ \ + case CONTROL_LPE: \ + accum = (voice->start + (accum - voice->end)) & voice->accum_mask; \ + break; \ + \ + /* trans-wave looping */ \ + case CONTROL_BLE: \ + accum = (voice->start + (accum - voice->end)) & voice->accum_mask; \ + voice->control = (voice->control & ~CONTROL_LOOPMASK) | CONTROL_LEI;\ + break; \ + \ + /* bi-directional looping */ \ + case CONTROL_LPE | CONTROL_BLE: \ + accum = (voice->end - (accum - voice->end)) & voice->accum_mask; \ + voice->control ^= CONTROL_DIR; \ + goto reverse; \ + } \ + } \ +} while (0) + + +#define check_for_end_reverse(voice, accum) \ +do \ +{ \ + /* are we past the end? */ \ + if (accum < voice->start && !(voice->control & CONTROL_LEI)) \ + { \ + /* generate interrupt if required */ \ + if (voice->control&CONTROL_IRQE) \ + voice->control |= CONTROL_IRQ; \ + \ + /* handle the different types of looping */ \ + switch (voice->control & CONTROL_LOOPMASK) \ + { \ + /* non-looping */ \ + case 0: \ + voice->control |= CONTROL_STOP0; \ + goto alldone; \ + \ + /* uni-directional looping */ \ + case CONTROL_LPE: \ + accum = (voice->end - (voice->start - accum)) & voice->accum_mask; \ + break; \ + \ + /* trans-wave looping */ \ + case CONTROL_BLE: \ + accum = (voice->end - (voice->start - accum)) & voice->accum_mask; \ + voice->control = (voice->control & ~CONTROL_LOOPMASK) | CONTROL_LEI;\ + break; \ + \ + /* bi-directional looping */ \ + case CONTROL_LPE | CONTROL_BLE: \ + accum = (voice->start + (voice->start - accum)) & voice->accum_mask;\ + voice->control ^= CONTROL_DIR; \ + goto reverse; \ + } \ + } \ +} while (0) + + + +/********************************************************************************************** + + generate_dummy -- generate nothing, just apply envelopes + +***********************************************************************************************/ + +void es550x_device::generate_dummy(es550x_voice *voice, UINT16 *base, INT32 *lbuffer, INT32 *rbuffer, int samples) +{ + UINT32 freqcount = voice->freqcount; + UINT32 accum = voice->accum & voice->accum_mask; + + /* outer loop, in case we switch directions */ + while (samples > 0 && !(voice->control & CONTROL_STOPMASK)) + { +reverse: + /* two cases: first case is forward direction */ + if (!(voice->control & CONTROL_DIR)) + { + /* loop while we still have samples to generate */ + while (samples--) + { + /* fetch two samples */ + accum = (accum + freqcount) & voice->accum_mask; + + /* update filters/volumes */ + if (voice->ecount != 0) + update_envelopes(voice, 1); + + /* check for loop end */ + check_for_end_forward(voice, accum); + } + } + + /* two cases: second case is backward direction */ + else + { + /* loop while we still have samples to generate */ + while (samples--) + { + /* fetch two samples */ + accum = (accum - freqcount) & voice->accum_mask; + + /* update filters/volumes */ + if (voice->ecount != 0) + update_envelopes(voice, 1); + + /* check for loop end */ + check_for_end_reverse(voice, accum); + } + } + } + + /* if we stopped, process any additional envelope */ +alldone: + voice->accum = accum; + if (samples > 0) + update_envelopes(voice, samples); +} + + + +/********************************************************************************************** + + generate_ulaw -- general u-law decoding routine + +***********************************************************************************************/ + +void es550x_device::generate_ulaw(es550x_voice *voice, UINT16 *base, INT32 *lbuffer, INT32 *rbuffer, int samples) +{ + UINT32 freqcount = voice->freqcount; + UINT32 accum = voice->accum & voice->accum_mask; + INT32 lvol = m_volume_lookup[voice->lvol >> 4]; + INT32 rvol = m_volume_lookup[voice->rvol >> 4]; + + /* pre-add the bank offset */ + base += voice->exbank; + + /* outer loop, in case we switch directions */ + while (samples > 0 && !(voice->control & CONTROL_STOPMASK)) + { +reverse: + /* two cases: first case is forward direction */ + if (!(voice->control & CONTROL_DIR)) + { + /* loop while we still have samples to generate */ + while (samples--) + { + /* fetch two samples */ + INT32 val1 = base[accum >> 11]; + INT32 val2 = base[((accum + (1 << 11)) & voice->accum_mask) >> 11]; + + /* decompress u-law */ + val1 = m_ulaw_lookup[val1 >> (16 - ULAW_MAXBITS)]; + val2 = m_ulaw_lookup[val2 >> (16 - ULAW_MAXBITS)]; + + /* interpolate */ + val1 = interpolate(val1, val2, accum); + accum = (accum + freqcount) & voice->accum_mask; + + /* apply filters */ + apply_filters(voice, val1); + + /* update filters/volumes */ + if (voice->ecount != 0) + { + update_envelopes(voice, 1); + lvol = m_volume_lookup[voice->lvol >> 4]; + rvol = m_volume_lookup[voice->rvol >> 4]; + } + + /* apply volumes and add */ + *lbuffer++ += (val1 * lvol) >> 11; + *rbuffer++ += (val1 * rvol) >> 11; + + /* check for loop end */ + check_for_end_forward(voice, accum); + } + } + + /* two cases: second case is backward direction */ + else + { + /* loop while we still have samples to generate */ + while (samples--) + { + /* fetch two samples */ + INT32 val1 = base[accum >> 11]; + INT32 val2 = base[((accum + (1 << 11)) & voice->accum_mask) >> 11]; + + /* decompress u-law */ + val1 = m_ulaw_lookup[val1 >> (16 - ULAW_MAXBITS)]; + val2 = m_ulaw_lookup[val2 >> (16 - ULAW_MAXBITS)]; + + /* interpolate */ + val1 = interpolate(val1, val2, accum); + accum = (accum - freqcount) & voice->accum_mask; + + /* apply filters */ + apply_filters(voice, val1); + + /* update filters/volumes */ + if (voice->ecount != 0) + { + update_envelopes(voice, 1); + lvol = m_volume_lookup[voice->lvol >> 4]; + rvol = m_volume_lookup[voice->rvol >> 4]; + } + + /* apply volumes and add */ + *lbuffer++ += (val1 * lvol) >> 11; + *rbuffer++ += (val1 * rvol) >> 11; + + /* check for loop end */ + check_for_end_reverse(voice, accum); + } + } + } + + /* if we stopped, process any additional envelope */ +alldone: + voice->accum = accum; + if (samples > 0) + update_envelopes(voice, samples); +} + + + +/********************************************************************************************** + + generate_pcm -- general PCM decoding routine + +***********************************************************************************************/ + +void es550x_device::generate_pcm(es550x_voice *voice, UINT16 *base, INT32 *lbuffer, INT32 *rbuffer, int samples) +{ + UINT32 freqcount = voice->freqcount; + UINT32 accum = voice->accum & voice->accum_mask; + INT32 lvol = m_volume_lookup[voice->lvol >> 4]; + INT32 rvol = m_volume_lookup[voice->rvol >> 4]; + + /* pre-add the bank offset */ + base += voice->exbank; + + /* outer loop, in case we switch directions */ + while (samples > 0 && !(voice->control & CONTROL_STOPMASK)) + { +reverse: + /* two cases: first case is forward direction */ + if (!(voice->control & CONTROL_DIR)) + { + /* loop while we still have samples to generate */ + while (samples--) + { + /* fetch two samples */ + INT32 val1 = (INT16)base[accum >> 11]; + INT32 val2 = (INT16)base[((accum + (1 << 11)) & voice->accum_mask) >> 11]; + + /* interpolate */ + val1 = interpolate(val1, val2, accum); + accum = (accum + freqcount) & voice->accum_mask; + + /* apply filters */ + apply_filters(voice, val1); + + /* update filters/volumes */ + if (voice->ecount != 0) + { + update_envelopes(voice, 1); + lvol = m_volume_lookup[voice->lvol >> 4]; + rvol = m_volume_lookup[voice->rvol >> 4]; + } + + /* apply volumes and add */ + *lbuffer++ += (val1 * lvol) >> 11; + *rbuffer++ += (val1 * rvol) >> 11; + + /* check for loop end */ + check_for_end_forward(voice, accum); + } + } + + /* two cases: second case is backward direction */ + else + { + /* loop while we still have samples to generate */ + while (samples--) + { + /* fetch two samples */ + INT32 val1 = (INT16)base[accum >> 11]; + INT32 val2 = (INT16)base[((accum + (1 << 11)) & voice->accum_mask) >> 11]; + + /* interpolate */ + val1 = interpolate(val1, val2, accum); + accum = (accum - freqcount) & voice->accum_mask; + + /* apply filters */ + apply_filters(voice, val1); + + /* update filters/volumes */ + if (voice->ecount != 0) + { + update_envelopes(voice, 1); + lvol = m_volume_lookup[voice->lvol >> 4]; + rvol = m_volume_lookup[voice->rvol >> 4]; + } + + /* apply volumes and add */ + *lbuffer++ += (val1 * lvol) >> 11; + *rbuffer++ += (val1 * rvol) >> 11; + + /* check for loop end */ + check_for_end_reverse(voice, accum); + } + } + } + + /* if we stopped, process any additional envelope */ +alldone: + voice->accum = accum; + if (samples > 0) + update_envelopes(voice, samples); +} + + + +/********************************************************************************************** + + generate_samples -- tell each voice to generate samples + +***********************************************************************************************/ + +void es5506_device::generate_samples(INT32 **outputs, int offset, int samples) +{ + int v; + + /* skip if nothing to do */ + if (!samples) + return; + + /* clear out the accumulators */ + for (int i = 0; i < m_channels << 1; i++) + { + memset(outputs[i] + offset, 0, sizeof(INT32) * samples); + } + + /* loop over voices */ + for (v = 0; v <= m_active_voices; v++) + { + es550x_voice *voice = &m_voice[v]; + UINT16 *base = m_region_base[voice->control >> 14]; + + /* special case: if end == start, stop the voice */ + if (voice->start == voice->end) + voice->control |= CONTROL_STOP0; + + int voice_channel = (voice->control & CONTROL_CAMASK) >> 10; + int channel = voice_channel % m_channels; + int l = channel << 1; + int r = l + 1; + INT32 *left = outputs[l] + offset; + INT32 *right = outputs[r] + offset; + + /* generate from the appropriate source */ + if (!base) + { + logerror("es5506: NULL region base %d\n",voice->control >> 14); + generate_dummy(voice, base, left, right, samples); + } + else if (voice->control & 0x2000) + generate_ulaw(voice, base, left, right, samples); + else + generate_pcm(voice, base, left, right, samples); + + /* does this voice have it's IRQ bit raised? */ + if (voice->control&CONTROL_IRQ) + { + logerror("es5506: IRQ raised on voice %d!!\n",v); + + /* only update voice vector if existing IRQ is acked by host */ + if (m_irqv&0x80) + { + /* latch voice number into vector, and set high bit low */ + m_irqv=v&0x7f; + + /* take down IRQ bit on voice */ + voice->control&=~CONTROL_IRQ; + + /* inform host of irq */ + update_irq_state(); + } + } + } +} + +void es5505_device::generate_samples(INT32 **outputs, int offset, int samples) +{ + int v; + + /* skip if nothing to do */ + if (!samples) + return; + + /* clear out the accumulators */ + for (int i = 0; i < m_channels << 1; i++) + { + memset(outputs[i] + offset, 0, sizeof(INT32) * samples); + } + + /* loop over voices */ + for (v = 0; v <= m_active_voices; v++) + { + es550x_voice *voice = &m_voice[v]; + UINT16 *base = m_region_base[voice->control >> 14]; + + /* special case: if end == start, stop the voice */ + if (voice->start == voice->end) + voice->control |= CONTROL_STOP0; + + int voice_channel = (voice->control & CONTROL_CAMASK) >> 10; + int channel = voice_channel % m_channels; + int l = channel << 1; + int r = l + 1; + INT32 *left = outputs[l] + offset; + INT32 *right = outputs[r] + offset; + + /* generate from the appropriate source */ + if (!base) + { + logerror("es5506: NULL region base %d\n",voice->control >> 14); + generate_dummy(voice, base, left, right, samples); + } + else if (voice->control & 0x2000) + generate_ulaw(voice, base, left, right, samples); + else + generate_pcm(voice, base, left, right, samples); + + /* does this voice have it's IRQ bit raised? */ + if (voice->control&CONTROL_IRQ) + { + logerror("es5506: IRQ raised on voice %d!!\n",v); + + /* only update voice vector if existing IRQ is acked by host */ + if (m_irqv&0x80) + { + /* latch voice number into vector, and set high bit low */ + m_irqv=v&0x7f; + + /* take down IRQ bit on voice */ + voice->control&=~CONTROL_IRQ; + + /* inform host of irq */ + update_irq_state(); + } + } + } +} + + + +/********************************************************************************************** + + reg_write -- handle a write to the selected ES5506 register + +***********************************************************************************************/ + +inline void es5506_device::reg_write_low(es550x_voice *voice, offs_t offset, UINT32 data) +{ + switch (offset) + { + case 0x00/8: /* CR */ + voice->control = data & 0xffff; + if (LOG_COMMANDS && m_eslog) + fprintf(m_eslog, "voice %d, control=%04x\n", m_current_page & 0x1f, voice->control); + break; + + case 0x08/8: /* FC */ + voice->freqcount = data & 0x1ffff; + if (LOG_COMMANDS && m_eslog) + fprintf(m_eslog, "voice %d, freq count=%08x\n", m_current_page & 0x1f, voice->freqcount); + break; + + case 0x10/8: /* LVOL */ + voice->lvol = data & 0xffff; + if (LOG_COMMANDS && m_eslog) + fprintf(m_eslog, "voice %d, left vol=%04x\n", m_current_page & 0x1f, voice->lvol); + break; + + case 0x18/8: /* LVRAMP */ + voice->lvramp = (data & 0xff00) >> 8; + if (LOG_COMMANDS && m_eslog) + fprintf(m_eslog, "voice %d, left vol ramp=%04x\n", m_current_page & 0x1f, voice->lvramp); + break; + + case 0x20/8: /* RVOL */ + voice->rvol = data & 0xffff; + if (LOG_COMMANDS && m_eslog) + fprintf(m_eslog, "voice %d, right vol=%04x\n", m_current_page & 0x1f, voice->rvol); + break; + + case 0x28/8: /* RVRAMP */ + voice->rvramp = (data & 0xff00) >> 8; + if (LOG_COMMANDS && m_eslog) + fprintf(m_eslog, "voice %d, right vol ramp=%04x\n", m_current_page & 0x1f, voice->rvramp); + break; + + case 0x30/8: /* ECOUNT */ + voice->ecount = data & 0x1ff; + voice->filtcount = 0; + if (LOG_COMMANDS && m_eslog) + fprintf(m_eslog, "voice %d, envelope count=%04x\n", m_current_page & 0x1f, voice->ecount); + break; + + case 0x38/8: /* K2 */ + voice->k2 = data & 0xffff; + if (LOG_COMMANDS && m_eslog) + fprintf(m_eslog, "voice %d, K2=%04x\n", m_current_page & 0x1f, voice->k2); + break; + + case 0x40/8: /* K2RAMP */ + voice->k2ramp = ((data & 0xff00) >> 8) | ((data & 0x0001) << 31); + if (LOG_COMMANDS && m_eslog) + fprintf(m_eslog, "voice %d, K2 ramp=%04x\n", m_current_page & 0x1f, voice->k2ramp); + break; + + case 0x48/8: /* K1 */ + voice->k1 = data & 0xffff; + if (LOG_COMMANDS && m_eslog) + fprintf(m_eslog, "voice %d, K1=%04x\n", m_current_page & 0x1f, voice->k1); + break; + + case 0x50/8: /* K1RAMP */ + voice->k1ramp = ((data & 0xff00) >> 8) | ((data & 0x0001) << 31); + if (LOG_COMMANDS && m_eslog) + fprintf(m_eslog, "voice %d, K1 ramp=%04x\n", m_current_page & 0x1f, voice->k1ramp); + break; + + case 0x58/8: /* ACTV */ + { + m_active_voices = data & 0x1f; + m_sample_rate = m_master_clock / (16 * (m_active_voices + 1)); + m_stream->set_sample_rate(m_sample_rate); + + if (LOG_COMMANDS && m_eslog) + fprintf(m_eslog, "active voices=%d, sample_rate=%d\n", m_active_voices, m_sample_rate); + break; + } + + case 0x60/8: /* MODE */ + m_mode = data & 0x1f; + break; + + case 0x68/8: /* PAR - read only */ + case 0x70/8: /* IRQV - read only */ + break; + + case 0x78/8: /* PAGE */ + m_current_page = data & 0x7f; + break; + } +} + +inline void es5506_device::reg_write_high(es550x_voice *voice, offs_t offset, UINT32 data) +{ + switch (offset) + { + case 0x00/8: /* CR */ + voice->control = data & 0xffff; + if (LOG_COMMANDS && m_eslog) + fprintf(m_eslog, "voice %d, control=%04x\n", m_current_page & 0x1f, voice->control); + break; + + case 0x08/8: /* START */ + voice->start = data & 0xfffff800; + if (LOG_COMMANDS && m_eslog) + fprintf(m_eslog, "voice %d, loop start=%08x\n", m_current_page & 0x1f, voice->start); + break; + + case 0x10/8: /* END */ + voice->end = data & 0xffffff80; + if (LOG_COMMANDS && m_eslog) + fprintf(m_eslog, "voice %d, loop end=%08x\n", m_current_page & 0x1f, voice->end); + break; + + case 0x18/8: /* ACCUM */ + voice->accum = data; + if (LOG_COMMANDS && m_eslog) + fprintf(m_eslog, "voice %d, accum=%08x\n", m_current_page & 0x1f, voice->accum); + break; + + case 0x20/8: /* O4(n-1) */ + voice->o4n1 = (INT32)(data << 14) >> 14; + if (LOG_COMMANDS && m_eslog) + fprintf(m_eslog, "voice %d, O4(n-1)=%05x\n", m_current_page & 0x1f, voice->o4n1 & 0x3ffff); + break; + + case 0x28/8: /* O3(n-1) */ + voice->o3n1 = (INT32)(data << 14) >> 14; + if (LOG_COMMANDS && m_eslog) + fprintf(m_eslog, "voice %d, O3(n-1)=%05x\n", m_current_page & 0x1f, voice->o3n1 & 0x3ffff); + break; + + case 0x30/8: /* O3(n-2) */ + voice->o3n2 = (INT32)(data << 14) >> 14; + if (LOG_COMMANDS && m_eslog) + fprintf(m_eslog, "voice %d, O3(n-2)=%05x\n", m_current_page & 0x1f, voice->o3n2 & 0x3ffff); + break; + + case 0x38/8: /* O2(n-1) */ + voice->o2n1 = (INT32)(data << 14) >> 14; + if (LOG_COMMANDS && m_eslog) + fprintf(m_eslog, "voice %d, O2(n-1)=%05x\n", m_current_page & 0x1f, voice->o2n1 & 0x3ffff); + break; + + case 0x40/8: /* O2(n-2) */ + voice->o2n2 = (INT32)(data << 14) >> 14; + if (LOG_COMMANDS && m_eslog) + fprintf(m_eslog, "voice %d, O2(n-2)=%05x\n", m_current_page & 0x1f, voice->o2n2 & 0x3ffff); + break; + + case 0x48/8: /* O1(n-1) */ + voice->o1n1 = (INT32)(data << 14) >> 14; + if (LOG_COMMANDS && m_eslog) + fprintf(m_eslog, "voice %d, O1(n-1)=%05x\n", m_current_page & 0x1f, voice->o1n1 & 0x3ffff); + break; + + case 0x50/8: /* W_ST */ + m_wst = data & 0x7f; + break; + + case 0x58/8: /* W_END */ + m_wend = data & 0x7f; + break; + + case 0x60/8: /* LR_END */ + m_lrend = data & 0x7f; + break; + + case 0x68/8: /* PAR - read only */ + case 0x70/8: /* IRQV - read only */ + break; + + case 0x78/8: /* PAGE */ + m_current_page = data & 0x7f; + break; + } +} + +inline void es5506_device::reg_write_test(es550x_voice *voice, offs_t offset, UINT32 data) +{ + switch (offset) + { + case 0x00/8: /* CHANNEL 0 LEFT */ + if (LOG_COMMANDS && m_eslog) + fprintf(m_eslog, "Channel 0 left test write %08x\n", data); + break; + + case 0x08/8: /* CHANNEL 0 RIGHT */ + if (LOG_COMMANDS && m_eslog) + fprintf(m_eslog, "Channel 0 right test write %08x\n", data); + break; + + case 0x10/8: /* CHANNEL 1 LEFT */ + if (LOG_COMMANDS && m_eslog) + fprintf(m_eslog, "Channel 1 left test write %08x\n", data); + break; + + case 0x18/8: /* CHANNEL 1 RIGHT */ + if (LOG_COMMANDS && m_eslog) + fprintf(m_eslog, "Channel 1 right test write %08x\n", data); + break; + + case 0x20/8: /* CHANNEL 2 LEFT */ + if (LOG_COMMANDS && m_eslog) + fprintf(m_eslog, "Channel 2 left test write %08x\n", data); + break; + + case 0x28/8: /* CHANNEL 2 RIGHT */ + if (LOG_COMMANDS && m_eslog) + fprintf(m_eslog, "Channel 2 right test write %08x\n", data); + break; + + case 0x30/8: /* CHANNEL 3 LEFT */ + if (LOG_COMMANDS && m_eslog) + fprintf(m_eslog, "Channel 3 left test write %08x\n", data); + break; + + case 0x38/8: /* CHANNEL 3 RIGHT */ + if (LOG_COMMANDS && m_eslog) + fprintf(m_eslog, "Channel 3 right test write %08x\n", data); + break; + + case 0x40/8: /* CHANNEL 4 LEFT */ + if (LOG_COMMANDS && m_eslog) + fprintf(m_eslog, "Channel 4 left test write %08x\n", data); + break; + + case 0x48/8: /* CHANNEL 4 RIGHT */ + if (LOG_COMMANDS && m_eslog) + fprintf(m_eslog, "Channel 4 right test write %08x\n", data); + break; + + case 0x50/8: /* CHANNEL 5 LEFT */ + if (LOG_COMMANDS && m_eslog) + fprintf(m_eslog, "Channel 5 left test write %08x\n", data); + break; + + case 0x58/8: /* CHANNEL 6 RIGHT */ + if (LOG_COMMANDS && m_eslog) + fprintf(m_eslog, "Channel 5 right test write %08x\n", data); + break; + + case 0x60/8: /* EMPTY */ + if (LOG_COMMANDS && m_eslog) + fprintf(m_eslog, "Test write EMPTY %08x\n", data); + break; + + case 0x68/8: /* PAR - read only */ + case 0x70/8: /* IRQV - read only */ + break; + + case 0x78/8: /* PAGE */ + m_current_page = data & 0x7f; + break; + } +} + +WRITE8_MEMBER( es5506_device::write ) +{ + es550x_voice *voice = &m_voice[m_current_page & 0x1f]; + int shift = 8 * (offset & 3); + + /* accumulate the data */ + m_write_latch = (m_write_latch & ~(0xff000000 >> shift)) | (data << (24 - shift)); + + /* wait for a write to complete */ + if (shift != 24) + return; + + /* force an update */ + m_stream->update(); + + /* switch off the page and register */ + if (m_current_page < 0x20) + reg_write_low(voice, offset / 4, m_write_latch); + else if (m_current_page < 0x40) + reg_write_high(voice, offset / 4, m_write_latch); + else + reg_write_test(voice, offset / 4, m_write_latch); + + /* clear the write latch when done */ + m_write_latch = 0; +} + + + +/********************************************************************************************** + + reg_read -- read from the specified ES5506 register + +***********************************************************************************************/ + +inline UINT32 es5506_device::reg_read_low(es550x_voice *voice, offs_t offset) +{ + UINT32 result = 0; + + switch (offset) + { + case 0x00/8: /* CR */ + result = voice->control; + break; + + case 0x08/8: /* FC */ + result = voice->freqcount; + break; + + case 0x10/8: /* LVOL */ + result = voice->lvol; + break; + + case 0x18/8: /* LVRAMP */ + result = voice->lvramp << 8; + break; + + case 0x20/8: /* RVOL */ + result = voice->rvol; + break; + + case 0x28/8: /* RVRAMP */ + result = voice->rvramp << 8; + break; + + case 0x30/8: /* ECOUNT */ + result = voice->ecount; + break; + + case 0x38/8: /* K2 */ + result = voice->k2; + break; + + case 0x40/8: /* K2RAMP */ + result = (voice->k2ramp << 8) | (voice->k2ramp >> 31); + break; + + case 0x48/8: /* K1 */ + result = voice->k1; + break; + + case 0x50/8: /* K1RAMP */ + result = (voice->k1ramp << 8) | (voice->k1ramp >> 31); + break; + + case 0x58/8: /* ACTV */ + result = m_active_voices; + break; + + case 0x60/8: /* MODE */ + result = m_mode; + break; + + case 0x68/8: /* PAR */ + if (!m_read_port_cb.isnull()) + result = m_read_port_cb(0); + break; + + case 0x70/8: /* IRQV */ + result = m_irqv; + update_internal_irq_state(); + break; + + case 0x78/8: /* PAGE */ + result = m_current_page; + break; + } + return result; +} + + +inline UINT32 es5506_device::reg_read_high(es550x_voice *voice, offs_t offset) +{ + UINT32 result = 0; + + switch (offset) + { + case 0x00/8: /* CR */ + result = voice->control; + break; + + case 0x08/8: /* START */ + result = voice->start; + break; + + case 0x10/8: /* END */ + result = voice->end; + break; + + case 0x18/8: /* ACCUM */ + result = voice->accum; + break; + + case 0x20/8: /* O4(n-1) */ + result = voice->o4n1 & 0x3ffff; + break; + + case 0x28/8: /* O3(n-1) */ + result = voice->o3n1 & 0x3ffff; + break; + + case 0x30/8: /* O3(n-2) */ + result = voice->o3n2 & 0x3ffff; + break; + + case 0x38/8: /* O2(n-1) */ + result = voice->o2n1 & 0x3ffff; + break; + + case 0x40/8: /* O2(n-2) */ + result = voice->o2n2 & 0x3ffff; + break; + + case 0x48/8: /* O1(n-1) */ + result = voice->o1n1 & 0x3ffff; + break; + + case 0x50/8: /* W_ST */ + result = m_wst; + break; + + case 0x58/8: /* W_END */ + result = m_wend; + break; + + case 0x60/8: /* LR_END */ + result = m_lrend; + break; + + case 0x68/8: /* PAR */ + if (!m_read_port_cb.isnull()) + result = m_read_port_cb(0); + break; + + case 0x70/8: /* IRQV */ + result = m_irqv; + update_internal_irq_state(); + break; + + case 0x78/8: /* PAGE */ + result = m_current_page; + break; + } + return result; +} +inline UINT32 es5506_device::reg_read_test(es550x_voice *voice, offs_t offset) +{ + UINT32 result = 0; + + switch (offset) + { + case 0x68/8: /* PAR */ + if (!m_read_port_cb.isnull()) + result = m_read_port_cb(0); + break; + + case 0x70/8: /* IRQV */ + result = m_irqv; + break; + + case 0x78/8: /* PAGE */ + result = m_current_page; + break; + } + return result; +} + +READ8_MEMBER( es5506_device::read ) +{ + es550x_voice *voice = &m_voice[m_current_page & 0x1f]; + int shift = 8 * (offset & 3); + + /* only read on offset 0 */ + if (shift != 0) + return m_read_latch >> (24 - shift); + + if (LOG_COMMANDS && m_eslog) + fprintf(m_eslog, "read from %02x/%02x -> ", m_current_page, offset / 4 * 8); + + /* force an update */ + m_stream->update(); + + /* switch off the page and register */ + if (m_current_page < 0x20) + m_read_latch = reg_read_low(voice, offset / 4); + else if (m_current_page < 0x40) + m_read_latch = reg_read_high(voice, offset / 4); + else + m_read_latch = reg_read_test(voice, offset / 4); + + if (LOG_COMMANDS && m_eslog) + fprintf(m_eslog, "%08x\n", m_read_latch); + + /* return the high byte */ + return m_read_latch >> 24; +} + + + +void es5506_device::voice_bank_w(int voice, int bank) +{ + m_voice[voice].exbank=bank; +} + + +/********************************************************************************************** + + reg_write -- handle a write to the selected ES5505 register + +***********************************************************************************************/ + +inline void es5505_device::reg_write_low(es550x_voice *voice, offs_t offset, UINT16 data, UINT16 mem_mask) +{ + switch (offset) + { + case 0x00: /* CR */ + if (ACCESSING_BITS_0_7) + { +#if RAINE_CHECK + voice->control &= ~(CONTROL_STOPMASK | CONTROL_LOOPMASK | CONTROL_DIR); +#else + voice->control &= ~(CONTROL_STOPMASK | CONTROL_BS0 | CONTROL_LOOPMASK | CONTROL_IRQE | CONTROL_DIR | CONTROL_IRQ); +#endif + voice->control |= (data & (CONTROL_STOPMASK | CONTROL_LOOPMASK | CONTROL_IRQE | CONTROL_DIR | CONTROL_IRQ)) | + ((data << 12) & CONTROL_BS0); + } + if (ACCESSING_BITS_8_15) + { + voice->control &= ~(CONTROL_CA0 | CONTROL_CA1 | CONTROL_LPMASK); + voice->control |= ((data >> 2) & CONTROL_LPMASK) | + ((data << 2) & (CONTROL_CA0 | CONTROL_CA1)); + } + + if (LOG_COMMANDS && m_eslog) + fprintf(m_eslog, "%s:voice %d, control=%04x (raw=%04x & %04x)\n", machine().describe_context(), m_current_page & 0x1f, voice->control, data, mem_mask ^ 0xffff); + break; + + case 0x01: /* FC */ + if (ACCESSING_BITS_0_7) + voice->freqcount = (voice->freqcount & ~0x001fe) | ((data & 0x00ff) << 1); + if (ACCESSING_BITS_8_15) + voice->freqcount = (voice->freqcount & ~0x1fe00) | ((data & 0xff00) << 1); + if (LOG_COMMANDS && m_eslog) + fprintf(m_eslog, "%s:voice %d, freq count=%08x\n", machine().describe_context(), m_current_page & 0x1f, voice->freqcount); + break; + + case 0x02: /* STRT (hi) */ + if (ACCESSING_BITS_0_7) + voice->start = (voice->start & ~0x03fc0000) | ((data & 0x00ff) << 18); + if (ACCESSING_BITS_8_15) + voice->start = (voice->start & ~0x7c000000) | ((data & 0x1f00) << 18); + if (LOG_COMMANDS && m_eslog) + fprintf(m_eslog, "%s:voice %d, loop start=%08x\n", machine().describe_context(), m_current_page & 0x1f, voice->start); + break; + + case 0x03: /* STRT (lo) */ + if (ACCESSING_BITS_0_7) + voice->start = (voice->start & ~0x00000380) | ((data & 0x00e0) << 2); + if (ACCESSING_BITS_8_15) + voice->start = (voice->start & ~0x0003fc00) | ((data & 0xff00) << 2); + if (LOG_COMMANDS && m_eslog) + fprintf(m_eslog, "%s:voice %d, loop start=%08x\n", machine().describe_context(), m_current_page & 0x1f, voice->start); + break; + + case 0x04: /* END (hi) */ + if (ACCESSING_BITS_0_7) + voice->end = (voice->end & ~0x03fc0000) | ((data & 0x00ff) << 18); + if (ACCESSING_BITS_8_15) + voice->end = (voice->end & ~0x7c000000) | ((data & 0x1f00) << 18); +#if RAINE_CHECK + voice->control |= CONTROL_STOP0; +#endif + if (LOG_COMMANDS && m_eslog) + fprintf(m_eslog, "%s:voice %d, loop end=%08x\n", machine().describe_context(), m_current_page & 0x1f, voice->end); + break; + + case 0x05: /* END (lo) */ + if (ACCESSING_BITS_0_7) + voice->end = (voice->end & ~0x00000380) | ((data & 0x00e0) << 2); + if (ACCESSING_BITS_8_15) + voice->end = (voice->end & ~0x0003fc00) | ((data & 0xff00) << 2); +#if RAINE_CHECK + voice->control |= CONTROL_STOP0; +#endif + if (LOG_COMMANDS && m_eslog) + fprintf(m_eslog, "%s:voice %d, loop end=%08x\n", machine().describe_context(), m_current_page & 0x1f, voice->end); + break; + + case 0x06: /* K2 */ + if (ACCESSING_BITS_0_7) + voice->k2 = (voice->k2 & ~0x00f0) | (data & 0x00f0); + if (ACCESSING_BITS_8_15) + voice->k2 = (voice->k2 & ~0xff00) | (data & 0xff00); + if (LOG_COMMANDS && m_eslog) + fprintf(m_eslog, "%s:voice %d, K2=%04x\n", machine().describe_context(), m_current_page & 0x1f, voice->k2); + break; + + case 0x07: /* K1 */ + if (ACCESSING_BITS_0_7) + voice->k1 = (voice->k1 & ~0x00f0) | (data & 0x00f0); + if (ACCESSING_BITS_8_15) + voice->k1 = (voice->k1 & ~0xff00) | (data & 0xff00); + if (LOG_COMMANDS && m_eslog) + fprintf(m_eslog, "%s:voice %d, K1=%04x\n", machine().describe_context(), m_current_page & 0x1f, voice->k1); + break; + + case 0x08: /* LVOL */ + if (ACCESSING_BITS_8_15) + voice->lvol = (voice->lvol & ~0xff00) | (data & 0xff00); + if (LOG_COMMANDS && m_eslog) + fprintf(m_eslog, "%s:voice %d, left vol=%04x\n", machine().describe_context(), m_current_page & 0x1f, voice->lvol); + break; + + case 0x09: /* RVOL */ + if (ACCESSING_BITS_8_15) + voice->rvol = (voice->rvol & ~0xff00) | (data & 0xff00); + if (LOG_COMMANDS && m_eslog) + fprintf(m_eslog, "%s:voice %d, right vol=%04x\n", machine().describe_context(), m_current_page & 0x1f, voice->rvol); + break; + + case 0x0a: /* ACC (hi) */ + if (ACCESSING_BITS_0_7) + voice->accum = (voice->accum & ~0x03fc0000) | ((data & 0x00ff) << 18); + if (ACCESSING_BITS_8_15) + voice->accum = (voice->accum & ~0x7c000000) | ((data & 0x1f00) << 18); + if (LOG_COMMANDS && m_eslog) + fprintf(m_eslog, "%s:voice %d, accum=%08x\n", machine().describe_context(), m_current_page & 0x1f, voice->accum); + break; + + case 0x0b: /* ACC (lo) */ + if (ACCESSING_BITS_0_7) + voice->accum = (voice->accum & ~0x000003fc) | ((data & 0x00ff) << 2); + if (ACCESSING_BITS_8_15) + voice->accum = (voice->accum & ~0x0003fc00) | ((data & 0xff00) << 2); + if (LOG_COMMANDS && m_eslog) + fprintf(m_eslog, "%s:voice %d, accum=%08x\n", machine().describe_context(), m_current_page & 0x1f, voice->accum); + break; + + case 0x0c: /* unused */ + break; + + case 0x0d: /* ACT */ + if (ACCESSING_BITS_0_7) + { + m_active_voices = data & 0x1f; + m_sample_rate = m_master_clock / (16 * (m_active_voices + 1)); + m_stream->set_sample_rate(m_sample_rate); + + if (LOG_COMMANDS && m_eslog) + fprintf(m_eslog, "active voices=%d, sample_rate=%d\n", m_active_voices, m_sample_rate); + } + break; + + case 0x0e: /* IRQV - read only */ + break; + + case 0x0f: /* PAGE */ + if (ACCESSING_BITS_0_7) + m_current_page = data & 0x7f; + break; + } +} + + +inline void es5505_device::reg_write_high(es550x_voice *voice, offs_t offset, UINT16 data, UINT16 mem_mask) +{ + switch (offset) + { + case 0x00: /* CR */ + if (ACCESSING_BITS_0_7) + { + voice->control &= ~(CONTROL_STOPMASK | CONTROL_BS0 | CONTROL_LOOPMASK | CONTROL_IRQE | CONTROL_DIR | CONTROL_IRQ); + voice->control |= (data & (CONTROL_STOPMASK | CONTROL_LOOPMASK | CONTROL_IRQE | CONTROL_DIR | CONTROL_IRQ)) | + ((data << 12) & CONTROL_BS0); + } + if (ACCESSING_BITS_8_15) + { + voice->control &= ~(CONTROL_CA0 | CONTROL_CA1 | CONTROL_LPMASK); + voice->control |= ((data >> 2) & CONTROL_LPMASK) | + ((data << 2) & (CONTROL_CA0 | CONTROL_CA1)); + } + if (LOG_COMMANDS && m_eslog) + fprintf(m_eslog, "%s:voice %d, control=%04x (raw=%04x & %04x)\n", machine().describe_context(), m_current_page & 0x1f, voice->control, data, mem_mask); + break; + + case 0x01: /* O4(n-1) */ + if (ACCESSING_BITS_0_7) + voice->o4n1 = (voice->o4n1 & ~0x00ff) | (data & 0x00ff); + if (ACCESSING_BITS_8_15) + voice->o4n1 = (INT16)((voice->o4n1 & ~0xff00) | (data & 0xff00)); + if (LOG_COMMANDS && m_eslog) + fprintf(m_eslog, "%s:voice %d, O4(n-1)=%05x\n", machine().describe_context(), m_current_page & 0x1f, voice->o4n1 & 0x3ffff); + break; + + case 0x02: /* O3(n-1) */ + if (ACCESSING_BITS_0_7) + voice->o3n1 = (voice->o3n1 & ~0x00ff) | (data & 0x00ff); + if (ACCESSING_BITS_8_15) + voice->o3n1 = (INT16)((voice->o3n1 & ~0xff00) | (data & 0xff00)); + if (LOG_COMMANDS && m_eslog) + fprintf(m_eslog, "%s:voice %d, O3(n-1)=%05x\n", machine().describe_context(), m_current_page & 0x1f, voice->o3n1 & 0x3ffff); + break; + + case 0x03: /* O3(n-2) */ + if (ACCESSING_BITS_0_7) + voice->o3n2 = (voice->o3n2 & ~0x00ff) | (data & 0x00ff); + if (ACCESSING_BITS_8_15) + voice->o3n2 = (INT16)((voice->o3n2 & ~0xff00) | (data & 0xff00)); + if (LOG_COMMANDS && m_eslog) + fprintf(m_eslog, "%s:voice %d, O3(n-2)=%05x\n", machine().describe_context(), m_current_page & 0x1f, voice->o3n2 & 0x3ffff); + break; + + case 0x04: /* O2(n-1) */ + if (ACCESSING_BITS_0_7) + voice->o2n1 = (voice->o2n1 & ~0x00ff) | (data & 0x00ff); + if (ACCESSING_BITS_8_15) + voice->o2n1 = (INT16)((voice->o2n1 & ~0xff00) | (data & 0xff00)); + if (LOG_COMMANDS && m_eslog) + fprintf(m_eslog, "%s:voice %d, O2(n-1)=%05x\n", machine().describe_context(), m_current_page & 0x1f, voice->o2n1 & 0x3ffff); + break; + + case 0x05: /* O2(n-2) */ + if (ACCESSING_BITS_0_7) + voice->o2n2 = (voice->o2n2 & ~0x00ff) | (data & 0x00ff); + if (ACCESSING_BITS_8_15) + voice->o2n2 = (INT16)((voice->o2n2 & ~0xff00) | (data & 0xff00)); + if (LOG_COMMANDS && m_eslog) + fprintf(m_eslog, "%s:voice %d, O2(n-2)=%05x\n", machine().describe_context(), m_current_page & 0x1f, voice->o2n2 & 0x3ffff); + break; + + case 0x06: /* O1(n-1) */ + if (ACCESSING_BITS_0_7) + voice->o1n1 = (voice->o1n1 & ~0x00ff) | (data & 0x00ff); + if (ACCESSING_BITS_8_15) + voice->o1n1 = (INT16)((voice->o1n1 & ~0xff00) | (data & 0xff00)); + if (LOG_COMMANDS && m_eslog) + fprintf(m_eslog, "%s:voice %d, O1(n-1)=%05x (accum=%08x)\n", machine().describe_context(), m_current_page & 0x1f, voice->o2n1 & 0x3ffff, voice->accum); + break; + + case 0x07: + case 0x08: + case 0x09: + case 0x0a: + case 0x0b: + case 0x0c: /* unused */ + break; + + case 0x0d: /* ACT */ + if (ACCESSING_BITS_0_7) + { + m_active_voices = data & 0x1f; + m_sample_rate = m_master_clock / (16 * (m_active_voices + 1)); + m_stream->set_sample_rate(m_sample_rate); + + if (LOG_COMMANDS && m_eslog) + fprintf(m_eslog, "active voices=%d, sample_rate=%d\n", m_active_voices, m_sample_rate); + } + break; + + case 0x0e: /* IRQV - read only */ + break; + + case 0x0f: /* PAGE */ + if (ACCESSING_BITS_0_7) + m_current_page = data & 0x7f; + break; + } +} + + +inline void es5505_device::reg_write_test(es550x_voice *voice, offs_t offset, UINT16 data, UINT16 mem_mask) +{ + switch (offset) + { + case 0x00: /* CH0L */ + case 0x01: /* CH0R */ + case 0x02: /* CH1L */ + case 0x03: /* CH1R */ + case 0x04: /* CH2L */ + case 0x05: /* CH2R */ + case 0x06: /* CH3L */ + case 0x07: /* CH3R */ + break; + + case 0x08: /* SERMODE */ + m_mode = data & 0x0007; + break; + + case 0x09: /* PAR */ + break; + + case 0x0d: /* ACT */ + if (ACCESSING_BITS_0_7) + { + m_active_voices = data & 0x1f; + m_sample_rate = m_master_clock / (16 * (m_active_voices + 1)); + m_stream->set_sample_rate(m_sample_rate); + + if (LOG_COMMANDS && m_eslog) + fprintf(m_eslog, "active voices=%d, sample_rate=%d\n", m_active_voices, m_sample_rate); + } + break; + + case 0x0e: /* IRQV - read only */ + break; + + case 0x0f: /* PAGE */ + if (ACCESSING_BITS_0_7) + m_current_page = data & 0x7f; + break; + } +} + + +WRITE16_MEMBER( es5505_device::write ) +{ + es550x_voice *voice = &m_voice[m_current_page & 0x1f]; + +// logerror("%s:ES5505 write %02x/%02x = %04x & %04x\n", machine().describe_context(), m_current_page, offset, data, mem_mask); + + /* force an update */ + m_stream->update(); + + /* switch off the page and register */ + if (m_current_page < 0x20) + reg_write_low(voice, offset, data, mem_mask); + else if (m_current_page < 0x40) + reg_write_high(voice, offset, data, mem_mask); + else + reg_write_test(voice, offset, data, mem_mask); +} + + + +/********************************************************************************************** + + reg_read -- read from the specified ES5505 register + +***********************************************************************************************/ + +inline UINT16 es5505_device::reg_read_low(es550x_voice *voice, offs_t offset) +{ + UINT16 result = 0; + + switch (offset) + { + case 0x00: /* CR */ + result = (voice->control & (CONTROL_STOPMASK | CONTROL_LOOPMASK | CONTROL_IRQE | CONTROL_DIR | CONTROL_IRQ)) | + ((voice->control & CONTROL_BS0) >> 12) | + ((voice->control & CONTROL_LPMASK) << 2) | + ((voice->control & (CONTROL_CA0 | CONTROL_CA1)) >> 2) | + 0xf000; + break; + + case 0x01: /* FC */ + result = voice->freqcount >> 1; + break; + + case 0x02: /* STRT (hi) */ + result = voice->start >> 18; + break; + + case 0x03: /* STRT (lo) */ + result = voice->start >> 2; + break; + + case 0x04: /* END (hi) */ + result = voice->end >> 18; + break; + + case 0x05: /* END (lo) */ + result = voice->end >> 2; + break; + + case 0x06: /* K2 */ + result = voice->k2; + break; + + case 0x07: /* K1 */ + result = voice->k1; + break; + + case 0x08: /* LVOL */ + result = voice->lvol; + break; + + case 0x09: /* RVOL */ + result = voice->rvol; + break; + + case 0x0a: /* ACC (hi) */ + result = voice->accum >> 18; + break; + + case 0x0b: /* ACC (lo) */ + result = voice->accum >> 2; + break; + + case 0x0c: /* unused */ + break; + + case 0x0d: /* ACT */ + result = m_active_voices; + break; + + case 0x0e: /* IRQV */ + result = m_irqv; + update_internal_irq_state(); + break; + + case 0x0f: /* PAGE */ + result = m_current_page; + break; + } + return result; +} + + +inline UINT16 es5505_device::reg_read_high(es550x_voice *voice, offs_t offset) +{ + UINT16 result = 0; + + switch (offset) + { + case 0x00: /* CR */ + result = (voice->control & (CONTROL_STOPMASK | CONTROL_LOOPMASK | CONTROL_IRQE | CONTROL_DIR | CONTROL_IRQ)) | + ((voice->control & CONTROL_BS0) >> 12) | + ((voice->control & CONTROL_LPMASK) << 2) | + ((voice->control & (CONTROL_CA0 | CONTROL_CA1)) >> 2) | + 0xf000; + break; + + case 0x01: /* O4(n-1) */ + result = voice->o4n1; + break; + + case 0x02: /* O3(n-1) */ + result = voice->o3n1; + break; + + case 0x03: /* O3(n-2) */ + result = voice->o3n2; + break; + + case 0x04: /* O2(n-1) */ + result = voice->o2n1; + break; + + case 0x05: /* O2(n-2) */ + result = voice->o2n2; + break; + + case 0x06: /* O1(n-1) */ + /* special case for the Taito F3 games: they set the accumulator on a stopped */ + /* voice and assume the filters continue to process the data. They then read */ + /* the O1(n-1) in order to extract raw data from the sound ROMs. Since we don't */ + /* want to waste time filtering stopped channels, we just look for a read from */ + /* this register on a stopped voice, and return the raw sample data at the */ + /* accumulator */ + if ((voice->control & CONTROL_STOPMASK) && m_region_base[voice->control >> 14]) + { + voice->o1n1 = m_region_base[voice->control >> 14][voice->exbank + (voice->accum >> 11)]; + // logerror("%02x %08x ==> %08x\n",voice->o1n1,voice->control >> 14,voice->exbank + (voice->accum >> 11)); + } + result = voice->o1n1; + break; + + case 0x07: + case 0x08: + case 0x09: + case 0x0a: + case 0x0b: + case 0x0c: /* unused */ + break; + + case 0x0d: /* ACT */ + result = m_active_voices; + break; + + case 0x0e: /* IRQV */ + result = m_irqv; + update_internal_irq_state(); + break; + + case 0x0f: /* PAGE */ + result = m_current_page; + break; + } + return result; +} + + +inline UINT16 es5505_device::reg_read_test(es550x_voice *voice, offs_t offset) +{ + UINT16 result = 0; + + switch (offset) + { + case 0x00: /* CH0L */ + case 0x01: /* CH0R */ + case 0x02: /* CH1L */ + case 0x03: /* CH1R */ + case 0x04: /* CH2L */ + case 0x05: /* CH2R */ + case 0x06: /* CH3L */ + case 0x07: /* CH3R */ + break; + + case 0x08: /* SERMODE */ + result = m_mode; + break; + + case 0x09: /* PAR */ + if (!m_read_port_cb.isnull()) + result = m_read_port_cb(0); + break; + + case 0x0f: /* PAGE */ + result = m_current_page; + break; + } + return result; +} + + +READ16_MEMBER( es5505_device::read ) +{ + es550x_voice *voice = &m_voice[m_current_page & 0x1f]; + UINT16 result = 0; + + if (LOG_COMMANDS && m_eslog) + fprintf(m_eslog, "read from %02x/%02x -> ", m_current_page, offset); + + /* force an update */ + m_stream->update(); + + /* switch off the page and register */ + if (m_current_page < 0x20) + result = reg_read_low(voice, offset); + else if (m_current_page < 0x40) + result = reg_read_high(voice, offset); + else + result = reg_read_test(voice, offset); + + if (LOG_COMMANDS && m_eslog) + fprintf(m_eslog, "%04x (accum=%08x)\n", result, voice->accum); + + /* return the high byte */ + return result; +} + + + +void es5505_device::voice_bank_w(int voice, int bank) +{ +#if RAINE_CHECK + m_voice[voice].control = CONTROL_STOPMASK; +#endif + m_voice[voice].exbank=bank; +} + + +//------------------------------------------------- +// sound_stream_update - handle a stream update +//------------------------------------------------- + +void es550x_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ +} + +void es5506_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ +#if MAKE_WAVS + /* start the logging once we have a sample rate */ + if (m_sample_rate) + { + if (!m_wavraw) + m_wavraw = wav_open("raw.wav", m_sample_rate, 2); + } +#endif + + /* loop until all samples are output */ + int offset = 0; + while (samples) + { + int length = (samples > MAX_SAMPLE_CHUNK) ? MAX_SAMPLE_CHUNK : samples; + + generate_samples(outputs, offset, length); + +#if MAKE_WAVS + /* log the raw data */ + if (m_wavraw) { + /* determine left/right source data */ + INT32 *lsrc = m_scratch, *rsrc = m_scratch + length; + int channel; + memset(lsrc, 0, sizeof(INT32) * length * 2); + /* loop over the output channels */ + for (channel = 0; channel < m_channels; channel++) { + INT32 *l = outputs[(channel << 1)] + offset; + INT32 *r = outputs[(channel << 1) + 1] + offset; + /* add the current channel's samples to the WAV data */ + for (samp = 0; samp < length; samp++) { + lsrc[samp] += l[samp]; + rsrc[samp] += r[samp]; + } + } + wav_add_data_32lr(m_wavraw, lsrc, rsrc, length, 4); + } +#endif + + /* account for these samples */ + offset += length; + samples -= length; + } +} + +void es5505_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ +#if MAKE_WAVS + /* start the logging once we have a sample rate */ + if (m_sample_rate) + { + if (!m_wavraw) + m_wavraw = wav_open("raw.wav", m_sample_rate, 2); + } +#endif + + /* loop until all samples are output */ + int offset = 0; + while (samples) + { + int length = (samples > MAX_SAMPLE_CHUNK) ? MAX_SAMPLE_CHUNK : samples; + + generate_samples(outputs, offset, length); + +#if MAKE_WAVS + /* log the raw data */ + if (m_wavraw) { + /* determine left/right source data */ + INT32 *lsrc = m_scratch, *rsrc = m_scratch + length; + int channel; + memset(lsrc, 0, sizeof(INT32) * length * 2); + /* loop over the output channels */ + for (channel = 0; channel < m_channels; channel++) { + INT32 *l = outputs[(channel << 1)] + offset; + INT32 *r = outputs[(channel << 1) + 1] + offset; + /* add the current channel's samples to the WAV data */ + for (samp = 0; samp < length; samp++) { + lsrc[samp] += l[samp]; + rsrc[samp] += r[samp]; + } + } + wav_add_data_32lr(m_wavraw, lsrc, rsrc, length, 4); + } +#endif + + /* account for these samples */ + offset += length; + samples -= length; + } +} diff --git a/src/devices/sound/es5506.h b/src/devices/sound/es5506.h new file mode 100644 index 00000000000..c434ec8b12e --- /dev/null +++ b/src/devices/sound/es5506.h @@ -0,0 +1,248 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/********************************************************************************************** + * + * Ensoniq ES5505/6 driver + * by Aaron Giles + * + **********************************************************************************************/ + +#pragma once + +#ifndef __ES5506_H__ +#define __ES5506_H__ + +#define MAKE_WAVS 0 + +#define MCFG_ES5506_REGION0(_region) \ + es5506_device::set_region0(*device, _region); + +#define MCFG_ES5506_REGION1(_region) \ + es5506_device::set_region1(*device, _region); + +#define MCFG_ES5506_REGION2(_region) \ + es5506_device::set_region2(*device, _region); + +#define MCFG_ES5506_REGION3(_region) \ + es5506_device::set_region3(*device, _region); + +#define MCFG_ES5506_CHANNELS(_chan) \ + es5506_device::set_channels(*device, _chan); + +#define MCFG_ES5506_IRQ_CB(_devcb) \ + devcb = &es5506_device::set_irq_callback(*device, DEVCB_##_devcb); + +#define MCFG_ES5506_READ_PORT_CB(_devcb) \ + devcb = &es5506_device::set_read_port_callback(*device, DEVCB_##_devcb); + + +#define MCFG_ES5505_REGION0(_region) \ + es5505_device::set_region0(*device, _region); + +#define MCFG_ES5505_REGION1(_region) \ + es5505_device::set_region1(*device, _region); + +#define MCFG_ES5505_CHANNELS(_chan) \ + es5505_device::set_channels(*device, _chan); + +#define MCFG_ES5505_IRQ_CB(_devcb) \ + devcb = &es5505_device::set_irq_callback(*device, DEVCB_##_devcb); + +#define MCFG_ES5505_READ_PORT_CB(_devcb) \ + devcb = &es5505_device::set_read_port_callback(*device, DEVCB_##_devcb); + + +/* struct describing a single playing voice */ + +struct es550x_voice +{ + es550x_voice(): + control(0), + freqcount(0), + start(0), + lvol(0), + end(0), + lvramp(0), + accum(0), + rvol(0), + rvramp(0), + ecount(0), + k2(0), + k2ramp(0), + k1(0), + k1ramp(0), + o4n1(0), + o3n1(0), + o3n2(0), + o2n1(0), + o2n2(0), + o1n1(0), + exbank(0), + index(0), + filtcount(0), + accum_mask(0) {} + + /* external state */ + UINT32 control; /* control register */ + UINT32 freqcount; /* frequency count register */ + UINT32 start; /* start register */ + UINT32 lvol; /* left volume register */ + UINT32 end; /* end register */ + UINT32 lvramp; /* left volume ramp register */ + UINT32 accum; /* accumulator register */ + UINT32 rvol; /* right volume register */ + UINT32 rvramp; /* right volume ramp register */ + UINT32 ecount; /* envelope count register */ + UINT32 k2; /* k2 register */ + UINT32 k2ramp; /* k2 ramp register */ + UINT32 k1; /* k1 register */ + UINT32 k1ramp; /* k1 ramp register */ + INT32 o4n1; /* filter storage O4(n-1) */ + INT32 o3n1; /* filter storage O3(n-1) */ + INT32 o3n2; /* filter storage O3(n-2) */ + INT32 o2n1; /* filter storage O2(n-1) */ + INT32 o2n2; /* filter storage O2(n-2) */ + INT32 o1n1; /* filter storage O1(n-1) */ + UINT32 exbank; /* external address bank */ + + /* internal state */ + UINT8 index; /* index of this voice */ + UINT8 filtcount; /* filter count */ + UINT32 accum_mask; +}; + +class es550x_device : public device_t, + public device_sound_interface +{ +public: + es550x_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + ~es550x_device() {} + + static void set_region0(device_t &device, const char *region0) { downcast(device).m_region0 = region0; } + static void set_region1(device_t &device, const char *region1) { downcast(device).m_region1 = region1; } + static void set_region2(device_t &device, const char *region2) { downcast(device).m_region2 = region2; } + static void set_region3(device_t &device, const char *region3) { downcast(device).m_region3 = region3; } + static void set_channels(device_t &device, int channels) { downcast(device).m_channels = channels; } + template static devcb_base &set_irq_callback(device_t &device, _Object object) { return downcast(device).m_irq_cb.set_callback(object); } + template static devcb_base &set_read_port_callback(device_t &device, _Object object) { return downcast(device).m_read_port_cb.set_callback(object); } + + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_stop(); + virtual void device_reset(); + + // sound stream update overrides + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + + // internal state + sound_stream *m_stream; /* which stream are we using */ + int m_sample_rate; /* current sample rate */ + UINT16 * m_region_base[4]; /* pointer to the base of the region */ + UINT32 m_write_latch; /* currently accumulated data for write */ + UINT32 m_read_latch; /* currently accumulated data for read */ + UINT32 m_master_clock; /* master clock frequency */ + + UINT8 m_current_page; /* current register page */ + UINT8 m_active_voices; /* number of active voices */ + UINT8 m_mode; /* MODE register */ + UINT8 m_wst; /* W_ST register */ + UINT8 m_wend; /* W_END register */ + UINT8 m_lrend; /* LR_END register */ + UINT8 m_irqv; /* IRQV register */ + + es550x_voice m_voice[32]; /* the 32 voices */ + + INT32 * m_scratch; + + INT16 * m_ulaw_lookup; + UINT16 * m_volume_lookup; + + #if MAKE_WAVS + void * m_wavraw; /* raw waveform */ + #endif + + FILE *m_eslog; + + const char * m_region0; /* memory region where the sample ROM lives */ + const char * m_region1; /* memory region where the sample ROM lives */ + const char * m_region2; /* memory region where the sample ROM lives */ + const char * m_region3; /* memory region where the sample ROM lives */ + int m_channels; /* number of output channels: 1 .. 6 */ + devcb_write_line m_irq_cb; /* irq callback */ + devcb_read16 m_read_port_cb; /* input port read */ + + void update_irq_state(); + void update_internal_irq_state(); + void compute_tables(); + + void generate_dummy(es550x_voice *voice, UINT16 *base, INT32 *lbuffer, INT32 *rbuffer, int samples); + void generate_ulaw(es550x_voice *voice, UINT16 *base, INT32 *lbuffer, INT32 *rbuffer, int samples); + void generate_pcm(es550x_voice *voice, UINT16 *base, INT32 *lbuffer, INT32 *rbuffer, int samples); +}; + + +class es5506_device : public es550x_device +{ +public: + es5506_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + ~es5506_device() {} + + DECLARE_READ8_MEMBER( read ); + DECLARE_WRITE8_MEMBER( write ); + void voice_bank_w(int voice, int bank); + +protected: + // device-level overrides + virtual void device_start(); + + // sound stream update overrides + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + + + void generate_samples(INT32 **outputs, int offset, int samples); + +private: + inline void reg_write_low(es550x_voice *voice, offs_t offset, UINT32 data); + inline void reg_write_high(es550x_voice *voice, offs_t offset, UINT32 data); + inline void reg_write_test(es550x_voice *voice, offs_t offset, UINT32 data); + inline UINT32 reg_read_low(es550x_voice *voice, offs_t offset); + inline UINT32 reg_read_high(es550x_voice *voice, offs_t offset); + inline UINT32 reg_read_test(es550x_voice *voice, offs_t offset); +}; + +extern const device_type ES5506; + + +class es5505_device : public es550x_device +{ +public: + es5505_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + DECLARE_READ16_MEMBER( read ); + DECLARE_WRITE16_MEMBER( write ); + void voice_bank_w(int voice, int bank); + +protected: + // device-level overrides + virtual void device_start(); + + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + + void generate_samples(INT32 **outputs, int offset, int samples); + +private: + // internal state + inline void reg_write_low(es550x_voice *voice, offs_t offset, UINT16 data, UINT16 mem_mask); + inline void reg_write_high(es550x_voice *voice, offs_t offset, UINT16 data, UINT16 mem_mask); + inline void reg_write_test(es550x_voice *voice, offs_t offset, UINT16 data, UINT16 mem_mask); + inline UINT16 reg_read_low(es550x_voice *voice, offs_t offset); + inline UINT16 reg_read_high(es550x_voice *voice, offs_t offset); + inline UINT16 reg_read_test(es550x_voice *voice, offs_t offset); +}; + +extern const device_type ES5505; + + +#endif /* __ES5506_H__ */ diff --git a/src/devices/sound/es8712.c b/src/devices/sound/es8712.c new file mode 100644 index 00000000000..f6087f83dc1 --- /dev/null +++ b/src/devices/sound/es8712.c @@ -0,0 +1,349 @@ +// license:BSD-3-Clause +// copyright-holders:Quench +/********************************************************************************************** + * + * Streaming single channel ADPCM core for the ES8712 chip + * Chip is branded by Excellent Systems, probably OEM'd. + * + * Samples are currently looped, but whether they should and how, is unknown. + * Interface to the chip is also not 100% clear. + * Should there be any status signals signifying busy, end of sample - etc? + * + * Heavily borrowed from the OKI M6295 source + * + **********************************************************************************************/ + + +#include "emu.h" +#include "es8712.h" + +#define MAX_SAMPLE_CHUNK 10000 + + +/* step size index shift table */ +static const int index_shift[8] = { -1, -1, -1, -1, 2, 4, 6, 8 }; + +/* lookup table for the precomputed difference */ +static int diff_lookup[49*16]; + + +// device type definition +const device_type ES8712 = &device_creator; + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// es8712_device - constructor +//------------------------------------------------- + +es8712_device::es8712_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, ES8712, "ES8712", tag, owner, clock, "es8712", __FILE__), + device_sound_interface(mconfig, *this), + m_rom(*this, DEVICE_SELF), + m_playing(0), + m_base_offset(0), + m_sample(0), + m_count(0), + m_signal(0), + m_step(0), + m_start(0), + m_end(0), + m_repeat(0), + m_bank_offset(0), + m_stream(NULL) +{ +} + + +//------------------------------------------------- +// device_start - start emulation of an ES8712 chip +//------------------------------------------------- + +void es8712_device::device_start() +{ + compute_tables(); + + m_start = 0; + m_end = 0; + m_repeat = 0; + + m_bank_offset = 0; + + /* generate the name and create the stream */ + m_stream = stream_alloc(0, 1, clock()); + + /* initialize the rest of the structure */ + m_signal = -2; + + es8712_state_save_register(); +} + + +//------------------------------------------------- +// device_reset - stop emulation of an ES8712-compatible chip +//------------------------------------------------- + +void es8712_device::device_reset() +{ + if (m_playing) + { + /* update the stream, then turn it off */ + m_stream->update(); + m_playing = 0; + m_repeat = 0; + } +} + + +//------------------------------------------------- +// sound_stream_update - update the sound chip so that it is in sync with CPU execution +//------------------------------------------------- + +void es8712_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + stream_sample_t *buffer = outputs[0]; + + /* generate them into our buffer */ + generate_adpcm(buffer, samples); +} + + +//------------------------------------------------- +// compute_tables -- compute the difference tables +//------------------------------------------------- + +void es8712_device::compute_tables() +{ + /* nibble to bit map */ + static const int nbl2bit[16][4] = + { + { 1, 0, 0, 0}, { 1, 0, 0, 1}, { 1, 0, 1, 0}, { 1, 0, 1, 1}, + { 1, 1, 0, 0}, { 1, 1, 0, 1}, { 1, 1, 1, 0}, { 1, 1, 1, 1}, + {-1, 0, 0, 0}, {-1, 0, 0, 1}, {-1, 0, 1, 0}, {-1, 0, 1, 1}, + {-1, 1, 0, 0}, {-1, 1, 0, 1}, {-1, 1, 1, 0}, {-1, 1, 1, 1} + }; + + int step, nib; + + /* loop over all possible steps */ + for (step = 0; step <= 48; step++) + { + /* compute the step value */ + int stepval = floor(16.0 * pow(11.0 / 10.0, (double)step)); + + /* loop over all nibbles and compute the difference */ + for (nib = 0; nib < 16; nib++) + { + diff_lookup[step*16 + nib] = nbl2bit[nib][0] * + (stepval * nbl2bit[nib][1] + + stepval/2 * nbl2bit[nib][2] + + stepval/4 * nbl2bit[nib][3] + + stepval/8); + } + } +} + + +//------------------------------------------------- +// generate_adpcm -- general ADPCM decoding routine +//------------------------------------------------- + +void es8712_device::generate_adpcm(stream_sample_t *buffer, int samples) +{ + /* if this chip is active */ + if (m_playing) + { + UINT8 *base = &m_rom[m_bank_offset + m_base_offset]; + int sample = m_sample; + int signal = m_signal; + int count = m_count; + int step = m_step; + int val; + + /* loop while we still have samples to generate */ + while (samples) + { + /* compute the new amplitude and update the current step */ + val = base[sample / 2] >> (((sample & 1) << 2) ^ 4); + signal += diff_lookup[step * 16 + (val & 15)]; + + /* clamp to the maximum */ + if (signal > 2047) + signal = 2047; + else if (signal < -2048) + signal = -2048; + + /* adjust the step size and clamp */ + step += index_shift[val & 7]; + if (step > 48) + step = 48; + else if (step < 0) + step = 0; + + /* output to the buffer */ + *buffer++ = signal * 16; + samples--; + + /* next! */ + if (++sample >= count) + { + if (m_repeat) + { + sample = 0; + signal = -2; + step = 0; + } + else + { + m_playing = 0; + break; + } + } + } + + /* update the parameters */ + m_sample = sample; + m_signal = signal; + m_step = step; + } + + /* fill the rest with silence */ + while (samples--) + *buffer++ = 0; +} + + + +//------------------------------------------------- +// state save support for MAME +//------------------------------------------------- + +void es8712_device::es8712_state_save_register() +{ + save_item(NAME(m_bank_offset)); + + save_item(NAME(m_playing)); + save_item(NAME(m_sample)); + save_item(NAME(m_count)); + save_item(NAME(m_signal)); + save_item(NAME(m_step)); + + save_item(NAME(m_base_offset)); + + save_item(NAME(m_start)); + save_item(NAME(m_end)); + save_item(NAME(m_repeat)); +} + + + + +//------------------------------------------------- +// es8712_set_bank_base -- set the base of the bank on a given chip +//------------------------------------------------- + +void es8712_device::set_bank_base(int base) +{ + m_stream->update(); + m_bank_offset = base; +} + + +//------------------------------------------------- +// es8712_set_frequency -- dynamically adjusts the frequency of a given ADPCM chip +//------------------------------------------------- + +void es8712_device::set_frequency(int frequency) +{ + /* update the stream and set the new base */ + m_stream->update(); + m_stream->set_sample_rate(frequency); +} + + +//------------------------------------------------- +// play -- Begin playing the addressed sample +//------------------------------------------------- + +void es8712_device::play() +{ + if (m_start < m_end) + { + if (!m_playing) + { + m_playing = 1; + m_base_offset = m_start; + m_sample = 0; + m_count = 2 * (m_end - m_start + 1); + m_repeat = 0;//1; + + /* also reset the ADPCM parameters */ + m_signal = -2; + m_step = 0; + } + } + /* invalid samples go here */ + else + { + logerror("ES871295:'%s' requested to play invalid sample range %06x-%06x\n", tag(), m_start, m_end); + + if (m_playing) + { + /* update the stream */ + m_stream->update(); + m_playing = 0; + } + } +} + + + +/********************************************************************************************** + + es8712_data_0_w -- generic data write functions + es8712_data_1_w + +***********************************************************************************************/ + +/********************************************************************************************** + * + * offset Start End + * 0hmmll - 0HMMLL + * 00 ----ll + * 01 --mm-- + * 02 0h---- + * 03 ----LL + * 04 --MM-- + * 05 0H---- + * 06 Go! + * + * Offsets are written in the order -> 00, 02, 01, 03, 05, 04, 06 + * Offset 06 is written with the same value as offset 04. + * +***********************************************************************************************/ + +WRITE8_MEMBER( es8712_device::es8712_w ) +{ + switch (offset) + { + case 00: m_start &= 0x000fff00; + m_start |= ((data & 0xff) << 0); break; + case 01: m_start &= 0x000f00ff; + m_start |= ((data & 0xff) << 8); break; + case 02: m_start &= 0x0000ffff; + m_start |= ((data & 0x0f) << 16); break; + case 03: m_end &= 0x000fff00; + m_end |= ((data & 0xff) << 0); break; + case 04: m_end &= 0x000f00ff; + m_end |= ((data & 0xff) << 8); break; + case 05: m_end &= 0x0000ffff; + m_end |= ((data & 0x0f) << 16); break; + case 06: + play(); break; + default: break; + } + m_start &= 0xfffff; m_end &= 0xfffff; +} diff --git a/src/devices/sound/es8712.h b/src/devices/sound/es8712.h new file mode 100644 index 00000000000..ed05a4b3497 --- /dev/null +++ b/src/devices/sound/es8712.h @@ -0,0 +1,78 @@ +// license:BSD-3-Clause +// copyright-holders:Quench +/* An interface for the ES8712 ADPCM chip */ + +#pragma once + +#ifndef __ES8712_H__ +#define __ES8712_H__ + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_ES8712_ADD(_tag, _clock) \ + MCFG_DEVICE_ADD(_tag, ES8712, _clock) +#define MCFG_ES8712_REPLACE(_tag, _clock) \ + MCFG_DEVICE_REPLACE(_tag, ES8712, _clock) + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + + +// ======================> es8712_device + +class es8712_device : public device_t, + public device_sound_interface +{ +public: + es8712_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + ~es8712_device() { } + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // sound stream update overrides + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + +public: + DECLARE_WRITE8_MEMBER( es8712_w ); + +public: + void play(); + void set_bank_base(int base); + void set_frequency(int frequency); + +private: + void compute_tables(); + void generate_adpcm(stream_sample_t *buffer, int samples); + void es8712_state_save_register(); + +private: + required_region_ptr m_rom; + + UINT8 m_playing; /* 1 if we're actively playing */ + + UINT32 m_base_offset; /* pointer to the base memory location */ + UINT32 m_sample; /* current sample number */ + UINT32 m_count; /* total samples to play */ + + UINT32 m_signal; /* current ADPCM signal */ + UINT32 m_step; /* current ADPCM step */ + + UINT32 m_start; /* starting address for the next loop */ + UINT32 m_end; /* ending address for the next loop */ + UINT8 m_repeat; /* Repeat current sample when 1 */ + + INT32 m_bank_offset; + sound_stream *m_stream; /* which stream are we playing on? */ +}; + +extern const device_type ES8712; + + +#endif /* __ES8712_H__ */ diff --git a/src/devices/sound/esqpump.c b/src/devices/sound/esqpump.c new file mode 100644 index 00000000000..147f97786ca --- /dev/null +++ b/src/devices/sound/esqpump.c @@ -0,0 +1,170 @@ +// license:BSD-3-Clause +// copyright-holders:Christian Brunschen +/*************************************************************************** + + esqpump.c - Ensoniq 5505/5506 to 5510 interface. + + By Christian Brunschen + +***************************************************************************/ + +#include "sound/esqpump.h" + +const device_type ESQ_5505_5510_PUMP = &device_creator; + +esq_5505_5510_pump::esq_5505_5510_pump(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, ESQ_5505_5510_PUMP, "ESQ_5505_5510_PUMP", tag, owner, clock, "esq_5505_5510_pump", __FILE__), + device_sound_interface(mconfig, *this), + m_esp_halted(true) +{ +} + +void esq_5505_5510_pump::device_start() +{ + logerror("Clock = %d\n", clock()); + + m_stream = machine().sound().stream_alloc(*this, 8, 2, clock()); + m_timer = timer_alloc(0); + m_timer->enable(false); + +#if PUMP_DETECT_SILENCE + silent_for = 500; + was_silence = 1; +#endif +#if !PUMP_FAKE_ESP_PROCESSING + ticks_spent_processing = 0; + samples_processed = 0; +#endif +#if PUMP_TRACK_SAMPLES + last_samples = 0; + last_ticks = osd_ticks(); + next_report_ticks = last_ticks + osd_ticks_per_second(); +#endif + +#if !PUMP_FAKE_ESP_PROCESSING && PUMP_REPLACE_ESP_PROGRAM + memset(e, 0, 0x4000 * sizeof(e[0])); + ei = 0; +#endif +} + +void esq_5505_5510_pump::device_stop() +{ + m_timer->enable(false); +} + +void esq_5505_5510_pump::device_reset() +{ + INT64 nsec_per_sample = 100 * 16 * 21; + attotime sample_time(0, 1000000000 * nsec_per_sample); + attotime initial_delay(0, 0); + + m_timer->adjust(initial_delay, 0, sample_time); + m_timer->enable(true); +} + +void esq_5505_5510_pump::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + if (samples != 1) { + logerror("Pump: request for %d samples\n", samples); + } + + stream_sample_t *left = outputs[0], *right = outputs[1]; + for (int i = 0; i < samples; i++) + { +#define SAMPLE_SHIFT 4 + // anything for the 'aux' output? + INT16 l = inputs[0][i] >> SAMPLE_SHIFT; + INT16 r = inputs[1][i] >> SAMPLE_SHIFT; + + // push the samples into the ESP + m_esp->ser_w(0, inputs[2][i] >> SAMPLE_SHIFT); + m_esp->ser_w(1, inputs[3][i] >> SAMPLE_SHIFT); + m_esp->ser_w(2, inputs[4][i] >> SAMPLE_SHIFT); + m_esp->ser_w(3, inputs[5][i] >> SAMPLE_SHIFT); + m_esp->ser_w(4, inputs[6][i] >> SAMPLE_SHIFT); + m_esp->ser_w(5, inputs[7][i] >> SAMPLE_SHIFT); + +#if PUMP_FAKE_ESP_PROCESSING + m_esp->ser_w(6, m_esp->ser_r(0) + m_esp->ser_r(2) + m_esp->ser_r(4)); + m_esp->ser_w(7, m_esp->ser_r(1) + m_esp->ser_r(3) + m_esp->ser_r(5)); +#else + if (!m_esp_halted) { + logerror("passing one sample through ESP\n"); + osd_ticks_t a = osd_ticks(); + m_esp->run_once(); + osd_ticks_t b = osd_ticks(); + ticks_spent_processing += (b - a); + samples_processed++; + } +#endif + + // read the processed result from the ESP and add to the saved AUX data + INT16 ll = m_esp->ser_r(6); + INT16 rr = m_esp->ser_r(7); + l += ll; + r += rr; + +#if !PUMP_FAKE_ESP_PROCESSING && PUMP_REPLACE_ESP_PROGRAM + // if we're processing the fake program through the ESP, the result should just be that of adding the inputs + INT32 el = (inputs[2][i]) + (inputs[4][i]) + (inputs[6][i]); + INT32 er = (inputs[3][i]) + (inputs[5][i]) + (inputs[7][i]); + INT32 e_next = el + er; + e[(ei + 0x1d0f) % 0x4000] = e_next; + + if (l != e[ei]) { + fprintf(stderr, "expected (%d) but have (%d)\n", e[ei], l); + } + ei = (ei + 1) % 0x4000; +#endif + + // write the combined data to the output + *left++ = l; + *right++ = r; + } + +#if PUMP_DETECT_SILENCE + for (int i = 0; i < samples; i++) { + if (outputs[0][i] == 0 && outputs[1][i] == 0) { + silent_for++; + } else { + silent_for = 0; + } + } + bool silence = silent_for >= 500; + if (was_silence != silence) { + if (!silence) { + fprintf(stderr, ".-*\n"); + } else { + fprintf(stderr, "*-.\n"); + } + was_silence = silence; + } +#endif + +#if PUMP_TRACK_SAMPLES + last_samples += samples; + osd_ticks_t now = osd_ticks(); + if (now >= next_report_ticks) + { + osd_ticks_t elapsed = now - last_ticks; + osd_ticks_t tps = osd_ticks_per_second(); + fprintf(stderr, "Pump: %d samples in %" I64FMT "d ticks for %f Hz\n", last_samples, elapsed, last_samples * (double)tps / (double)elapsed); + last_ticks = now; + while (next_report_ticks <= now) { + next_report_ticks += tps; + } + last_samples = 0; + +#if !PUMP_FAKE_ESP_PROCESSING + fprintf(stderr, " ESP spent %" I64FMT "d ticks on %d samples, %f ticks per sample\n", ticks_spent_processing, samples_processed, (double)ticks_spent_processing / (double)samples_processed); + ticks_spent_processing = 0; + samples_processed = 0; +#endif + } +#endif +} + +void esq_5505_5510_pump::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) { + // ecery time there's a new sample period, update the stream! + m_stream->update(); +} diff --git a/src/devices/sound/esqpump.h b/src/devices/sound/esqpump.h new file mode 100644 index 00000000000..bc2c72f8a72 --- /dev/null +++ b/src/devices/sound/esqpump.h @@ -0,0 +1,124 @@ +// license:BSD-3-Clause +// copyright-holders:Christian Brunschen +#pragma once + +#ifndef _ESQPUMP_H_ +#define _ESQPUMP_H_ + +#include "emu.h" +#include "sound/es5506.h" +#include "cpu/es5510/es5510.h" + +#define PUMP_DETECT_SILENCE 0 +#define PUMP_TRACK_SAMPLES 0 +#define PUMP_FAKE_ESP_PROCESSING 0 +#define PUMP_REPLACE_ESP_PROGRAM 0 + +class esq_5505_5510_pump : public device_t, + public device_sound_interface +{ +public: + esq_5505_5510_pump(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + void set_otis(es5505_device *otis) { m_otis = otis; } + void set_esp(es5510_device *esp) { m_esp = esp; } + void set_esp_halted(bool esp_halted) { + m_esp_halted = esp_halted; + logerror("ESP-halted -> %d\n", m_esp_halted); + if (!esp_halted) { +#if PUMP_REPLACE_ESP_PROGRAM + m_esp->write_reg(245, 0x1d0f << 8); // dlength = 0x3fff, 16-sample delay + + int pc = 0; + for (pc = 0; pc < 0xc0; pc++) { + m_esp->write_reg(pc, 0); + } + pc = 0; + // replace the ESP program with a simple summing & single-sample delay + m_esp->_instr(pc++) = 0xffffeaa09000; // MOV SER0R > grp_a0 + m_esp->_instr(pc++) = 0xffffeba00000; // ADD SER0L, gpr_a0 > gpr_a0 + m_esp->_instr(pc++) = 0xffffeca00000; // ADD SER1R, gpr_a0 > gpr_a0 + m_esp->_instr(pc++) = 0xffffeda00000; // ADD SER1L, gpr_a0 > gpr_a0 + m_esp->_instr(pc++) = 0xffffeea00000; // ADD SER2R, gpr_a0 > gpr_a0 + + m_esp->_instr(pc ) = 0xffffefa00000; // ADD SER2L, gpr_a0 > gpr_a0; prepare to read from delay 2 instructions from now, offset = 0 + m_esp->write_reg(pc++, 0); //offset into delay + + m_esp->_instr(pc ) = 0xffffa0a09508; // MOV gpr_a0 > delay + offset + m_esp->write_reg(pc++, 1 << 8); // offset into delay - -1 samples + + m_esp->_instr(pc++) = 0xffff00a19928; // MOV DIL > gpr_a1; read Delay and dump FIFO (so that the value gets written) + + m_esp->_instr(pc++) = 0xffffa1f09000; // MOV gpr_a1 > SER3R + m_esp->_instr(pc++) = 0xffffa1f19000; // MOV gpr_a1 > SER3L + + m_esp->_instr(pc++) = 0xffffffff0000; // NO-OP + m_esp->_instr(pc++) = 0xffffffff0000; // NO-OP + m_esp->_instr(pc++) = 0xfffffffff000; // END + + while (pc < 160) { + m_esp->_instr(pc++) = 0xffffffffffff; // no-op + } +#endif + + // m_esp->list_program(print_to_stderr); + } + } + bool get_esp_halted() { + return m_esp_halted; + } + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_stop(); + virtual void device_reset(); + + // sound stream update overrides + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + + // timer callback overrides + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + +private: + // internal state: + // sound stream + sound_stream *m_stream; + + // per-sample timer + emu_timer *m_timer; + + // OTIS sound generator + es5505_device *m_otis; + + // ESP signal processor + es5510_device *m_esp; + + // Is the ESP halted by the CPU? + bool m_esp_halted; + +#if !PUMP_FAKE_ESP_PROCESSING + osd_ticks_t ticks_spent_processing; + int samples_processed; +#endif + +#if PUMP_DETECT_SILENCE + int silent_for; + bool was_silence; +#endif + +#if PUMP_TRACK_SAMPLES + int last_samples; + osd_ticks_t last_ticks; + osd_ticks_t next_report_ticks; +#endif + +#if !PUMP_FAKE_ESP_PROCESSING && PUMP_REPLACE_ESP_PROGRAM + INT16 e[0x4000]; + int ei; +#endif +}; + +extern const device_type ESQ_5505_5510_PUMP; + +#endif diff --git a/src/devices/sound/filter.c b/src/devices/sound/filter.c new file mode 100644 index 00000000000..3d80966d029 --- /dev/null +++ b/src/devices/sound/filter.c @@ -0,0 +1,234 @@ +// license:??? +// copyright-holders:Derrick Renaud, Couriersud +#include "emu.h" +#include "filter.h" + +static filter* filter_alloc(void) { + filter* f = global_alloc(filter); + return f; +} + +void filter_free(filter* f) { + global_free(f); +} + +void filter_state_reset(filter* f, filter_state* s) { + int i; + s->prev_mac = 0; + for(i=0;iorder;++i) { + s->xprev[i] = 0; + } +} + +filter_state* filter_state_alloc(void) { + int i; + filter_state* s = global_alloc(filter_state); + s->prev_mac = 0; + for(i=0;ixprev[i] = 0; + return s; +} + +void filter_state_free(filter_state* s) { + global_free(s); +} + +/****************************************************************************/ +/* FIR */ + +filter_real filter_compute(filter* f, filter_state* s) { + unsigned order = f->order; + unsigned midorder = f->order / 2; + filter_real y = 0; + unsigned i,j,k; + + /* i == [0] */ + /* j == [-2*midorder] */ + i = s->prev_mac; + j = i + 1; + if (j == order) + j = 0; + + /* x */ + for(k=0;kxcoeffs[midorder-k] * (s->xprev[i] + s->xprev[j]); + ++j; + if (j == order) + j = 0; + if (i == 0) + i = order - 1; + else + --i; + } + y += f->xcoeffs[0] * s->xprev[i]; + +#ifdef FILTER_USE_INT + return y >> FILTER_INT_FRACT; +#else + return y; +#endif +} + +filter* filter_lp_fir_alloc(double freq, int order) { + filter* f = filter_alloc(); + unsigned midorder = (order - 1) / 2; + unsigned i; + double gain; + + assert( order <= FILTER_ORDER_MAX ); + assert( order % 2 == 1 ); + assert( 0 < freq && freq <= 0.5 ); + + /* Compute the antitrasform of the perfect low pass filter */ + gain = 2*freq; +#ifdef FILTER_USE_INT + f->xcoeffs[0] = gain * (1 << FILTER_INT_FRACT); +#else + f->xcoeffs[0] = gain; +#endif + for(i=1;i<=midorder;++i) { + /* number of the sample starting from 0 to (order-1) included */ + unsigned n = i + midorder; + + /* sample value */ + double c = sin(2*M_PI*freq*i) / (M_PI*i); + + /* apply only one window or none */ + /* double w = 2 - 2*n/(order-1); */ /* Bartlett (triangular) */ + /* double w = 0.5 * (1 - cos(2*M_PI*n/(order-1))); */ /* Hanning */ + double w = 0.54 - 0.46 * cos(2*M_PI*n/(order-1)); /* Hamming */ + /* double w = 0.42 - 0.5 * cos(2*M_PI*n/(order-1)) + 0.08 * cos(4*M_PI*n/(order-1)); */ /* Blackman */ + + /* apply the window */ + c *= w; + + /* update the gain */ + gain += 2*c; + + /* insert the coeff */ +#ifdef FILTER_USE_INT + f->xcoeffs[i] = c * (1 << FILTER_INT_FRACT); +#else + f->xcoeffs[i] = c; +#endif + } + + /* adjust the gain to be exact 1.0 */ + for(i=0;i<=midorder;++i) { +#ifdef FILTER_USE_INT + f->xcoeffs[i] /= gain; +#else + f->xcoeffs[i] = f->xcoeffs[i] * (double)(1 << FILTER_INT_FRAC) / gain; +#endif + } + + /* decrease the order if the last coeffs are 0 */ + i = midorder; + while (i > 0 && f->xcoeffs[i] == 0.0) + --i; + + f->order = i * 2 + 1; + + return f; +} + + +void filter2_setup(device_t *device, int type, double fc, double d, double gain, + filter2_context *filter2) +{ + int sample_rate = device->machine().sample_rate(); + double w; /* cutoff freq, in radians/sec */ + double w_squared; + double den; /* temp variable */ + double two_over_T = 2*sample_rate; + double two_over_T_squared = two_over_T * two_over_T; + + /* calculate digital filter coefficents */ + /*w = 2.0*M_PI*fc; no pre-warping */ + w = sample_rate*2.0*tan(M_PI*fc/sample_rate); /* pre-warping */ + w_squared = w*w; + + den = two_over_T_squared + d*w*two_over_T + w_squared; + + filter2->a1 = 2.0*(-two_over_T_squared + w_squared)/den; + filter2->a2 = (two_over_T_squared - d*w*two_over_T + w_squared)/den; + + switch (type) + { + case FILTER_LOWPASS: + filter2->b0 = filter2->b2 = w_squared/den; + filter2->b1 = 2.0*(filter2->b0); + break; + case FILTER_BANDPASS: + filter2->b0 = d*w*two_over_T/den; + filter2->b1 = 0.0; + filter2->b2 = -(filter2->b0); + break; + case FILTER_HIGHPASS: + filter2->b0 = filter2->b2 = two_over_T_squared/den; + filter2->b1 = -2.0*(filter2->b0); + break; + default: + logerror("filter2_setup() - Invalid filter type for 2nd order filter."); + break; + } + + filter2->b0 *= gain; + filter2->b1 *= gain; + filter2->b2 *= gain; +} + + +/* Reset the input/output voltages to 0. */ +void filter2_reset(filter2_context *filter2) +{ + filter2->x0 = 0; + filter2->x1 = 0; + filter2->x2 = 0; + filter2->y0 = 0; + filter2->y1 = 0; + filter2->y2 = 0; +} + + +/* Step the filter. */ +void filter2_step(filter2_context *filter2) +{ + filter2->y0 = -filter2->a1 * filter2->y1 - filter2->a2 * filter2->y2 + + filter2->b0 * filter2->x0 + filter2->b1 * filter2->x1 + filter2->b2 * filter2->x2; + filter2->x2 = filter2->x1; + filter2->x1 = filter2->x0; + filter2->y2 = filter2->y1; + filter2->y1 = filter2->y0; +} + + +/* Setup a filter2 structure based on an op-amp multipole bandpass circuit. */ +void filter_opamp_m_bandpass_setup(device_t *device, double r1, double r2, double r3, double c1, double c2, + filter2_context *filter2) +{ + double r_in, fc, d, gain; + + if (r1 == 0) + { + logerror("filter_opamp_m_bandpass_setup() - r1 can not be 0"); + return; /* Filter can not be setup. Undefined results. */ + } + + if (r2 == 0) + { + gain = 1; + r_in = r1; + } + else + { + gain = r2 / (r1 + r2); + r_in = 1.0 / (1.0/r1 + 1.0/r2); + } + + fc = 1.0 / (2 * M_PI * sqrt(r_in * r3 * c1 * c2)); + d = (c1 + c2) / sqrt(r3 / r_in * c1 * c2); + gain *= -r3 / r_in * c2 / (c1 + c2); + + filter2_setup(device, FILTER_BANDPASS, fc, d, gain, filter2); +} diff --git a/src/devices/sound/filter.h b/src/devices/sound/filter.h new file mode 100644 index 00000000000..5e671e85545 --- /dev/null +++ b/src/devices/sound/filter.h @@ -0,0 +1,133 @@ +// license:??? +// copyright-holders:Derrick Renaud, Couriersud +#pragma once + +#ifndef __FILTER_H__ +#define __FILTER_H__ + +/* Max filter order */ +#define FILTER_ORDER_MAX 51 + +/* Define to use integer calculation */ +#define FILTER_USE_INT + +#ifdef FILTER_USE_INT +typedef int filter_real; +#define FILTER_INT_FRACT 15 /* fractional bits */ +#else +typedef double filter_real; +#endif + +struct filter +{ + filter_real xcoeffs[(FILTER_ORDER_MAX+1)/2]; + unsigned order; +}; + +struct filter_state +{ + unsigned prev_mac; + filter_real xprev[FILTER_ORDER_MAX]; +}; + +/* Allocate a FIR Low Pass filter */ +filter* filter_lp_fir_alloc(double freq, int order); +void filter_free(filter* f); + +/* Allocate a filter state */ +filter_state* filter_state_alloc(void); + +/* Free the filter state */ +void filter_state_free(filter_state* s); + +/* Clear the filter state */ +void filter_state_reset(filter* f, filter_state* s); + +/* Insert a value in the filter state */ +INLINE void filter_insert(filter* f, filter_state* s, filter_real x) { + /* next state */ + ++s->prev_mac; + if (s->prev_mac >= f->order) + s->prev_mac = 0; + + /* set x[0] */ + s->xprev[s->prev_mac] = x; +} + +/* Compute the filter output */ +filter_real filter_compute(filter* f, filter_state* s); + + +/* Filter types */ +#define FILTER_LOWPASS 0 +#define FILTER_HIGHPASS 1 +#define FILTER_BANDPASS 2 + +#define Q_TO_DAMP(q) (1.0/q) + +struct filter2_context +{ + filter2_context() : + x0(0.0), + x1(0.0), + x2(0.0), + y0(0.0), + y1(0.0), + y2(0.0), + a1(0.0), + a2(0.0), + b0(0.0), + b1(0.0), + b2(0.0) + {} + + double x0, x1, x2; /* x[k], x[k-1], x[k-2], current and previous 2 input values */ + double y0, y1, y2; /* y[k], y[k-1], y[k-2], current and previous 2 output values */ + double a1, a2; /* digital filter coefficients, denominator */ + double b0, b1, b2; /* digital filter coefficients, numerator */ +}; + + +/* Setup the filter context based on the passed filter type info. + * type - 1 of the 3 defined filter types + * fc - center frequency + * d - damp = 1/Q + * gain - overall filter gain. Set to 1 if not needed. + */ +void filter2_setup(device_t *device, int type, double fc, double d, double gain, + filter2_context *filter2); + + +/* Reset the input/output voltages to 0. */ +void filter2_reset(filter2_context *filter2); + + +/* Step the filter. + * x0 is the new input, which needs to be set before stepping. + * y0 is the new filter output. + */ +void filter2_step(filter2_context *filter2); + + +/* Setup a filter2 structure based on an op-amp multipole bandpass circuit. + * NOTE: If r2 is not used then set to 0. + * vRef is not needed to setup filter. + * + * .--------+---------. + * | | | + * --- c1 Z | + * --- Z r3 | + * | Z | + * r1 | c2 | |\ | + * In >----ZZZZ----+---------+--||----+ | \ | + * Z '--|- \ | + * Z r2 | >--+------> out + * Z .--|+ / + * | | | / + * gnd vRef >---' |/ + * + */ +void filter_opamp_m_bandpass_setup(device_t *device, double r1, double r2, double r3, double c1, double c2, + filter2_context *filter2); + +#endif /* __FILTER_H__ */ diff --git a/src/devices/sound/flt_rc.c b/src/devices/sound/flt_rc.c new file mode 100644 index 00000000000..5fc0a7df882 --- /dev/null +++ b/src/devices/sound/flt_rc.c @@ -0,0 +1,139 @@ +// license:??? +// copyright-holders:Derrick Renaud, Couriersud +#include "emu.h" +#include "flt_rc.h" + + +// device type definition +const device_type FILTER_RC = &device_creator; + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// filter_rc_device - constructor +//------------------------------------------------- + +filter_rc_device::filter_rc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, FILTER_RC, "RC Filter", tag, owner, clock, "filter_rc", __FILE__), + device_sound_interface(mconfig, *this), + m_stream(NULL), + m_k(0), + m_memory(0), + m_type(FLT_RC_LOWPASS), + m_R1(1), + m_R2(1), + m_R3(1), + m_C(0) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void filter_rc_device::device_start() +{ + m_stream = stream_alloc(1, 1, machine().sample_rate()); + recalc(); + + save_item(NAME(m_k)); + save_item(NAME(m_memory)); + save_item(NAME(m_type)); + save_item(NAME(m_R1)); + save_item(NAME(m_R2)); + save_item(NAME(m_R3)); + save_item(NAME(m_C)); +} + + +//------------------------------------------------- +// sound_stream_update - handle a stream update +//------------------------------------------------- + +void filter_rc_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + stream_sample_t *src = inputs[0]; + stream_sample_t *dst = outputs[0]; + int memory = m_memory; + + switch (m_type) + { + case FLT_RC_LOWPASS: + while (samples--) + { + memory += ((*src++ - memory) * m_k) / 0x10000; + *dst++ = memory; + } + break; + case FLT_RC_HIGHPASS: + case FLT_RC_AC: + while (samples--) + { + *dst++ = *src - memory; + memory += ((*src++ - memory) * m_k) / 0x10000; + } + break; + } + m_memory = memory; +} + + +void filter_rc_device::recalc() +{ + double Req; + + switch (m_type) + { + case FLT_RC_LOWPASS: + if (m_C == 0.0) + { + /* filter disabled */ + m_k = 0x10000; + return; + } + Req = (m_R1 * (m_R2 + m_R3)) / (m_R1 + m_R2 + m_R3); + break; + case FLT_RC_HIGHPASS: + case FLT_RC_AC: + if (m_C == 0.0) + { + /* filter disabled */ + m_k = 0x0; + m_memory = 0x0; + return; + } + Req = m_R1; + break; + default: + fatalerror("filter_rc_setRC: Wrong filter type %d\n", m_type); + } + + /* Cut Frequency = 1/(2*Pi*Req*C) */ + /* k = (1-(EXP(-TIMEDELTA/RC))) */ + m_k = 0x10000 - 0x10000 * (exp(-1 / (Req * m_C) / machine().sample_rate())); +} + + +void filter_rc_device::filter_rc_set_RC(int type, double R1, double R2, double R3, double C) +{ + m_stream->update(); + m_type = type; + m_R1 = R1; + m_R2 = R2; + m_R3 = R3; + m_C = C; + recalc(); +} + +void filter_rc_device::static_set_rc(device_t &device, int type, double R1, double R2, double R3, double C) +{ + downcast(device).m_type = type; + downcast(device).m_R1 = R1; + downcast(device).m_R2 = R2; + downcast(device).m_R3 = R3; + downcast(device).m_C = C; +} diff --git a/src/devices/sound/flt_rc.h b/src/devices/sound/flt_rc.h new file mode 100644 index 00000000000..0ea52c6972a --- /dev/null +++ b/src/devices/sound/flt_rc.h @@ -0,0 +1,104 @@ +// license:??? +// copyright-holders:Derrick Renaud, Couriersud +#pragma once + +#ifndef __FLT_RC_H__ +#define __FLT_RC_H__ + +#include "machine/rescap.h" + +/* + * FLT_RC_LOWPASS: + * + * signal >--R1--+--R2--+ + * | | + * C R3---> amp + * | | + * GND GND + * + * Set C=0 to disable filter + * + * FLT_RC_HIGHPASS: + * + * signal >--C---+----> amp + * | + * R1 + * | + * GND + * + * Set C = 0 to disable filter + * + * FLT_RC_AC: + * + * Same as FLT_RC_HIGHPASS, but with standard frequency of 16 HZ + * This filter may be setup just with + * + * MCFG_FILTER_RC_ADD("tag", 0) + * MCFG_FILTER_RC_AC(&flt_rc_ac_default) + * + * Default behaviour: + * + * Without MCFG_SOUND_CONFIG, a disabled FLT_RC_LOWPASS is created + * + */ + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_FILTER_RC_ADD(_tag, _clock) \ + MCFG_DEVICE_ADD(_tag, FILTER_RC, _clock) + +#define MCFG_FILTER_RC_REPLACE(_tag, _clock) \ + MCFG_DEVICE_REPLACE(_tag, FILTER_RC, _clock) + +#define MCFG_FILTER_RC_AC() \ + filter_rc_device::static_set_rc(*device, FLT_RC_AC, 10000, 0, 0, CAP_U(1)); + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +#define FLT_RC_LOWPASS 0 +#define FLT_RC_HIGHPASS 1 +#define FLT_RC_AC 2 + +// ======================> filter_rc_device + +class filter_rc_device : public device_t, + public device_sound_interface +{ +public: + filter_rc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + ~filter_rc_device() { } + + // static configuration + static void static_set_rc(device_t &device, int type, double R1, double R2, double R3, double C); + + void filter_rc_set_RC(int type, double R1, double R2, double R3, double C); + +protected: + // device-level overrides + virtual void device_start(); + + // sound stream update overrides + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + +private: + void recalc(); + +private: + sound_stream* m_stream; + int m_k; + int m_memory; + int m_type; + double m_R1; + double m_R2; + double m_R3; + double m_C; +}; + +extern const device_type FILTER_RC; + +#endif /* __FLT_RC_H__ */ diff --git a/src/devices/sound/flt_vol.c b/src/devices/sound/flt_vol.c new file mode 100644 index 00000000000..0012f3fc4db --- /dev/null +++ b/src/devices/sound/flt_vol.c @@ -0,0 +1,52 @@ +// license:??? +// copyright-holders:Derrick Renaud, Couriersud +#include "emu.h" +#include "flt_vol.h" + + +// device type definition +const device_type FILTER_VOLUME = &device_creator; + +//------------------------------------------------- +// filter_volume_device - constructor +//------------------------------------------------- + +filter_volume_device::filter_volume_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, FILTER_VOLUME, "Volume Filter", tag, owner, clock, "filter_volume", __FILE__), + device_sound_interface(mconfig, *this), + m_stream(NULL), + m_gain(0) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void filter_volume_device::device_start() +{ + m_gain = 0x100; + m_stream = stream_alloc(1, 1, machine().sample_rate()); +} + + +//------------------------------------------------- +// sound_stream_update - handle a stream update +//------------------------------------------------- + +void filter_volume_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + stream_sample_t *src = inputs[0]; + stream_sample_t *dst = outputs[0]; + + while (samples--) + *dst++ = (*src++ * m_gain) >> 8; +} + + + +void filter_volume_device::flt_volume_set_volume(float volume) +{ + m_gain = (int)(volume * 256); +} diff --git a/src/devices/sound/flt_vol.h b/src/devices/sound/flt_vol.h new file mode 100644 index 00000000000..20ce17a58e9 --- /dev/null +++ b/src/devices/sound/flt_vol.h @@ -0,0 +1,50 @@ +// license:??? +// copyright-holders:Derrick Renaud, Couriersud +#pragma once + +#ifndef __FLT_VOL_H__ +#define __FLT_VOL_H__ + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_FILTER_VOLUME_ADD(_tag, _clock) \ + MCFG_DEVICE_ADD(_tag, FILTER_VOLUME, _clock) +#define MCFG_FILTER_VOLUME_REPLACE(_tag, _clock) \ + MCFG_DEVICE_REPLACE(_tag, FILTER_VOLUME, _clock) + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> filter_volume_device + +class filter_volume_device : public device_t, + public device_sound_interface +{ +public: + filter_volume_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + ~filter_volume_device() { } + + void flt_volume_set_volume(float volume); + +protected: + // device-level overrides + virtual void device_start(); + + // sound stream update overrides + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + +private: + sound_stream* m_stream; + int m_gain; +}; + +extern const device_type FILTER_VOLUME; + + +#endif /* __FLT_VOL_H__ */ diff --git a/src/devices/sound/fm.c b/src/devices/sound/fm.c new file mode 100644 index 00000000000..3782790409f --- /dev/null +++ b/src/devices/sound/fm.c @@ -0,0 +1,3908 @@ +// license:??? +// copyright-holders:Jarek Burczynski,Tatsuyuki Satoh +#define YM2610B_WARNING + +/* +** +** File: fm.c -- software implementation of Yamaha FM sound generator +** +** Copyright Jarek Burczynski (bujar at mame dot net) +** Copyright Tatsuyuki Satoh , MultiArcadeMachineEmulator development +** +** Version 1.4.2 (final beta) +** +*/ + +/* +** History: +** +** 2006-2008 Eke-Eke (Genesis Plus GX), MAME backport by R. Belmont. +** - implemented PG overflow, aka "detune bug" (Ariel, Comix Zone, Shaq Fu, Spiderman,...), credits to Nemesis +** - fixed SSG-EG support, credits to Nemesis and additional fixes from Alone Coder +** - modified EG rates and frequency, tested by Nemesis on real hardware +** - implemented LFO phase update for CH3 special mode (Warlock birds, Alladin bug sound) +** - fixed Attack Rate update (Batman & Robin intro) +** - fixed attenuation level at the start of Substain (Gynoug explosions) +** - fixed EG decay->substain transition to handle special cases, like SL=0 and Decay rate is very slow (Mega Turrican tracks 03,09...) +** +** 06-23-2007 Zsolt Vasvari: +** - changed the timing not to require the use of floating point calculations +** +** 03-08-2003 Jarek Burczynski: +** - fixed YM2608 initial values (after the reset) +** - fixed flag and irqmask handling (YM2608) +** - fixed BUFRDY flag handling (YM2608) +** +** 14-06-2003 Jarek Burczynski: +** - implemented all of the YM2608 status register flags +** - implemented support for external memory read/write via YM2608 +** - implemented support for deltat memory limit register in YM2608 emulation +** +** 22-05-2003 Jarek Burczynski: +** - fixed LFO PM calculations (copy&paste bugfix) +** +** 08-05-2003 Jarek Burczynski: +** - fixed SSG support +** +** 22-04-2003 Jarek Burczynski: +** - implemented 100% correct LFO generator (verified on real YM2610 and YM2608) +** +** 15-04-2003 Jarek Burczynski: +** - added support for YM2608's register 0x110 - status mask +** +** 01-12-2002 Jarek Burczynski: +** - fixed register addressing in YM2608, YM2610, YM2610B chips. (verified on real YM2608) +** The addressing patch used for early Neo-Geo games can be removed now. +** +** 26-11-2002 Jarek Burczynski, Nicola Salmoria: +** - recreated YM2608 ADPCM ROM using data from real YM2608's output which leads to: +** - added emulation of YM2608 drums. +** - output of YM2608 is two times lower now - same as YM2610 (verified on real YM2608) +** +** 16-08-2002 Jarek Burczynski: +** - binary exact Envelope Generator (verified on real YM2203); +** identical to YM2151 +** - corrected 'off by one' error in feedback calculations (when feedback is off) +** - corrected connection (algorithm) calculation (verified on real YM2203 and YM2610) +** +** 18-12-2001 Jarek Burczynski: +** - added SSG-EG support (verified on real YM2203) +** +** 12-08-2001 Jarek Burczynski: +** - corrected sin_tab and tl_tab data (verified on real chip) +** - corrected feedback calculations (verified on real chip) +** - corrected phase generator calculations (verified on real chip) +** - corrected envelope generator calculations (verified on real chip) +** - corrected FM volume level (YM2610 and YM2610B). +** - changed YMxxxUpdateOne() functions (YM2203, YM2608, YM2610, YM2610B, YM2612) : +** this was needed to calculate YM2610 FM channels output correctly. +** (Each FM channel is calculated as in other chips, but the output of the channel +** gets shifted right by one *before* sending to accumulator. That was impossible to do +** with previous implementation). +** +** 23-07-2001 Jarek Burczynski, Nicola Salmoria: +** - corrected YM2610 ADPCM type A algorithm and tables (verified on real chip) +** +** 11-06-2001 Jarek Burczynski: +** - corrected end of sample bug in ADPCMA_calc_cha(). +** Real YM2610 checks for equality between current and end addresses (only 20 LSB bits). +** +** 08-12-98 hiro-shi: +** rename ADPCMA -> ADPCMB, ADPCMB -> ADPCMA +** move ROM limit check.(CALC_CH? -> 2610Write1/2) +** test program (ADPCMB_TEST) +** move ADPCM A/B end check. +** ADPCMB repeat flag(no check) +** change ADPCM volume rate (8->16) (32->48). +** +** 09-12-98 hiro-shi: +** change ADPCM volume. (8->16, 48->64) +** replace ym2610 ch0/3 (YM-2610B) +** change ADPCM_SHIFT (10->8) missing bank change 0x4000-0xffff. +** add ADPCM_SHIFT_MASK +** change ADPCMA_DECODE_MIN/MAX. +*/ + + + + +/************************************************************************/ +/* comment of hiro-shi(Hiromitsu Shioya) */ +/* YM2610(B) = OPN-B */ +/* YM2610 : PSG:3ch FM:4ch ADPCM(18.5KHz):6ch DeltaT ADPCM:1ch */ +/* YM2610B : PSG:3ch FM:6ch ADPCM(18.5KHz):6ch DeltaT ADPCM:1ch */ +/************************************************************************/ + +#include "emu.h" +#include "fm.h" + + +/* include external DELTA-T unit (when needed) */ +#if (BUILD_YM2608||BUILD_YM2610||BUILD_YM2610B) + #include "ymdeltat.h" +#endif + +/* shared function building option */ +#define BUILD_OPN (BUILD_YM2203||BUILD_YM2608||BUILD_YM2610||BUILD_YM2610B) +#define BUILD_OPN_PRESCALER (BUILD_YM2203||BUILD_YM2608) + + +/* globals */ +#define TYPE_SSG 0x01 /* SSG support */ +#define TYPE_LFOPAN 0x02 /* OPN type LFO and PAN */ +#define TYPE_6CH 0x04 /* FM 6CH / 3CH */ +#define TYPE_DAC 0x08 /* YM2612's DAC device */ +#define TYPE_ADPCM 0x10 /* two ADPCM units */ +#define TYPE_2610 0x20 /* bogus flag to differentiate 2608 from 2610 */ + + +#define TYPE_YM2203 (TYPE_SSG) +#define TYPE_YM2608 (TYPE_SSG |TYPE_LFOPAN |TYPE_6CH |TYPE_ADPCM) +#define TYPE_YM2610 (TYPE_SSG |TYPE_LFOPAN |TYPE_6CH |TYPE_ADPCM |TYPE_2610) + + + +#define FREQ_SH 16 /* 16.16 fixed point (frequency calculations) */ +#define EG_SH 16 /* 16.16 fixed point (envelope generator timing) */ +#define LFO_SH 24 /* 8.24 fixed point (LFO calculations) */ +#define TIMER_SH 16 /* 16.16 fixed point (timers calculations) */ + +#define FREQ_MASK ((1<>3) + +/* sin waveform table in 'decibel' scale */ +static unsigned int sin_tab[SIN_LEN]; + +/* sustain level table (3dB per step) */ +/* bit0, bit1, bit2, bit3, bit4, bit5, bit6 */ +/* 1, 2, 4, 8, 16, 32, 64 (value)*/ +/* 0.75, 1.5, 3, 6, 12, 24, 48 (dB)*/ + +/* 0 - 15: 0, 3, 6, 9,12,15,18,21,24,27,30,33,36,39,42,93 (dB)*/ +#define SC(db) (UINT32) ( db * (4.0/ENV_STEP) ) +static const UINT32 sl_table[16]={ + SC( 0),SC( 1),SC( 2),SC(3 ),SC(4 ),SC(5 ),SC(6 ),SC( 7), + SC( 8),SC( 9),SC(10),SC(11),SC(12),SC(13),SC(14),SC(31) +}; +#undef SC + + +#define RATE_STEPS (8) +static const UINT8 eg_inc[19*RATE_STEPS]={ +/*cycle:0 1 2 3 4 5 6 7*/ + +/* 0 */ 0,1, 0,1, 0,1, 0,1, /* rates 00..11 0 (increment by 0 or 1) */ +/* 1 */ 0,1, 0,1, 1,1, 0,1, /* rates 00..11 1 */ +/* 2 */ 0,1, 1,1, 0,1, 1,1, /* rates 00..11 2 */ +/* 3 */ 0,1, 1,1, 1,1, 1,1, /* rates 00..11 3 */ + +/* 4 */ 1,1, 1,1, 1,1, 1,1, /* rate 12 0 (increment by 1) */ +/* 5 */ 1,1, 1,2, 1,1, 1,2, /* rate 12 1 */ +/* 6 */ 1,2, 1,2, 1,2, 1,2, /* rate 12 2 */ +/* 7 */ 1,2, 2,2, 1,2, 2,2, /* rate 12 3 */ + +/* 8 */ 2,2, 2,2, 2,2, 2,2, /* rate 13 0 (increment by 2) */ +/* 9 */ 2,2, 2,4, 2,2, 2,4, /* rate 13 1 */ +/*10 */ 2,4, 2,4, 2,4, 2,4, /* rate 13 2 */ +/*11 */ 2,4, 4,4, 2,4, 4,4, /* rate 13 3 */ + +/*12 */ 4,4, 4,4, 4,4, 4,4, /* rate 14 0 (increment by 4) */ +/*13 */ 4,4, 4,8, 4,4, 4,8, /* rate 14 1 */ +/*14 */ 4,8, 4,8, 4,8, 4,8, /* rate 14 2 */ +/*15 */ 4,8, 8,8, 4,8, 8,8, /* rate 14 3 */ + +/*16 */ 8,8, 8,8, 8,8, 8,8, /* rates 15 0, 15 1, 15 2, 15 3 (increment by 8) */ +/*17 */ 16,16,16,16,16,16,16,16, /* rates 15 2, 15 3 for attack */ +/*18 */ 0,0, 0,0, 0,0, 0,0, /* infinity rates for attack and decay(s) */ +}; + + +#define O(a) (a*RATE_STEPS) + +/*note that there is no O(17) in this table - it's directly in the code */ +static const UINT8 eg_rate_select[32+64+32]={ /* Envelope Generator rates (32 + 64 rates + 32 RKS) */ +/* 32 infinite time rates */ +O(18),O(18),O(18),O(18),O(18),O(18),O(18),O(18), +O(18),O(18),O(18),O(18),O(18),O(18),O(18),O(18), +O(18),O(18),O(18),O(18),O(18),O(18),O(18),O(18), +O(18),O(18),O(18),O(18),O(18),O(18),O(18),O(18), + +/* rates 00-11 */ +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), + +/* rate 12 */ +O( 4),O( 5),O( 6),O( 7), + +/* rate 13 */ +O( 8),O( 9),O(10),O(11), + +/* rate 14 */ +O(12),O(13),O(14),O(15), + +/* rate 15 */ +O(16),O(16),O(16),O(16), + +/* 32 dummy rates (same as 15 3) */ +O(16),O(16),O(16),O(16),O(16),O(16),O(16),O(16), +O(16),O(16),O(16),O(16),O(16),O(16),O(16),O(16), +O(16),O(16),O(16),O(16),O(16),O(16),O(16),O(16), +O(16),O(16),O(16),O(16),O(16),O(16),O(16),O(16) + +}; + +#undef O + +/*rate 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15*/ +/*shift 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0, 0, 0, 0 */ +/*mask 2047, 1023, 511, 255, 127, 63, 31, 15, 7, 3, 1, 0, 0, 0, 0, 0 */ + +#define O(a) (a*1) +static const UINT8 eg_rate_shift[32+64+32]={ /* Envelope Generator counter shifts (32 + 64 rates + 32 RKS) */ +/* 32 infinite time rates */ +O(0),O(0),O(0),O(0),O(0),O(0),O(0),O(0), +O(0),O(0),O(0),O(0),O(0),O(0),O(0),O(0), +O(0),O(0),O(0),O(0),O(0),O(0),O(0),O(0), +O(0),O(0),O(0),O(0),O(0),O(0),O(0),O(0), + +/* rates 00-11 */ +O(11),O(11),O(11),O(11), +O(10),O(10),O(10),O(10), +O( 9),O( 9),O( 9),O( 9), +O( 8),O( 8),O( 8),O( 8), +O( 7),O( 7),O( 7),O( 7), +O( 6),O( 6),O( 6),O( 6), +O( 5),O( 5),O( 5),O( 5), +O( 4),O( 4),O( 4),O( 4), +O( 3),O( 3),O( 3),O( 3), +O( 2),O( 2),O( 2),O( 2), +O( 1),O( 1),O( 1),O( 1), +O( 0),O( 0),O( 0),O( 0), + +/* rate 12 */ +O( 0),O( 0),O( 0),O( 0), + +/* rate 13 */ +O( 0),O( 0),O( 0),O( 0), + +/* rate 14 */ +O( 0),O( 0),O( 0),O( 0), + +/* rate 15 */ +O( 0),O( 0),O( 0),O( 0), + +/* 32 dummy rates (same as 15 3) */ +O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0), +O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0), +O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0), +O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0) + +}; +#undef O + +static const UINT8 dt_tab[4 * 32]={ +/* this is YM2151 and YM2612 phase increment data (in 10.10 fixed point format)*/ +/* FD=0 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/* FD=1 */ + 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, + 2, 3, 3, 3, 4, 4, 4, 5, 5, 6, 6, 7, 8, 8, 8, 8, +/* FD=2 */ + 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, + 5, 6, 6, 7, 8, 8, 9,10,11,12,13,14,16,16,16,16, +/* FD=3 */ + 2, 2, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 6, 6, 7, + 8 , 8, 9,10,11,12,13,14,16,17,19,20,22,22,22,22 +}; + + +/* OPN key frequency number -> key code follow table */ +/* fnum higher 4bit -> keycode lower 2bit */ +static const UINT8 opn_fktable[16] = {0,0,0,0,0,0,0,1,2,3,3,3,3,3,3,3}; + + +/* 8 LFO speed parameters */ +/* each value represents number of samples that one LFO level will last for */ +static const UINT32 lfo_samples_per_step[8] = {108, 77, 71, 67, 62, 44, 8, 5}; + + + +/*There are 4 different LFO AM depths available, they are: + 0 dB, 1.4 dB, 5.9 dB, 11.8 dB + Here is how it is generated (in EG steps): + + 11.8 dB = 0, 2, 4, 6, 8, 10,12,14,16...126,126,124,122,120,118,....4,2,0 + 5.9 dB = 0, 1, 2, 3, 4, 5, 6, 7, 8....63, 63, 62, 61, 60, 59,.....2,1,0 + 1.4 dB = 0, 0, 0, 0, 1, 1, 1, 1, 2,...15, 15, 15, 15, 14, 14,.....0,0,0 + + (1.4 dB is losing precision as you can see) + + It's implemented as generator from 0..126 with step 2 then a shift + right N times, where N is: + 8 for 0 dB + 3 for 1.4 dB + 1 for 5.9 dB + 0 for 11.8 dB +*/ +static const UINT8 lfo_ams_depth_shift[4] = {8, 3, 1, 0}; + + + +/*There are 8 different LFO PM depths available, they are: + 0, 3.4, 6.7, 10, 14, 20, 40, 80 (cents) + + Modulation level at each depth depends on F-NUMBER bits: 4,5,6,7,8,9,10 + (bits 8,9,10 = FNUM MSB from OCT/FNUM register) + + Here we store only first quarter (positive one) of full waveform. + Full table (lfo_pm_table) containing all 128 waveforms is build + at run (init) time. + + One value in table below represents 4 (four) basic LFO steps + (1 PM step = 4 AM steps). + + For example: + at LFO SPEED=0 (which is 108 samples per basic LFO step) + one value from "lfo_pm_output" table lasts for 432 consecutive + samples (4*108=432) and one full LFO waveform cycle lasts for 13824 + samples (32*432=13824; 32 because we store only a quarter of whole + waveform in the table below) +*/ +static const UINT8 lfo_pm_output[7*8][8]={ /* 7 bits meaningful (of F-NUMBER), 8 LFO output levels per one depth (out of 32), 8 LFO depths */ +/* FNUM BIT 4: 000 0001xxxx */ +/* DEPTH 0 */ {0, 0, 0, 0, 0, 0, 0, 0}, +/* DEPTH 1 */ {0, 0, 0, 0, 0, 0, 0, 0}, +/* DEPTH 2 */ {0, 0, 0, 0, 0, 0, 0, 0}, +/* DEPTH 3 */ {0, 0, 0, 0, 0, 0, 0, 0}, +/* DEPTH 4 */ {0, 0, 0, 0, 0, 0, 0, 0}, +/* DEPTH 5 */ {0, 0, 0, 0, 0, 0, 0, 0}, +/* DEPTH 6 */ {0, 0, 0, 0, 0, 0, 0, 0}, +/* DEPTH 7 */ {0, 0, 0, 0, 1, 1, 1, 1}, + +/* FNUM BIT 5: 000 0010xxxx */ +/* DEPTH 0 */ {0, 0, 0, 0, 0, 0, 0, 0}, +/* DEPTH 1 */ {0, 0, 0, 0, 0, 0, 0, 0}, +/* DEPTH 2 */ {0, 0, 0, 0, 0, 0, 0, 0}, +/* DEPTH 3 */ {0, 0, 0, 0, 0, 0, 0, 0}, +/* DEPTH 4 */ {0, 0, 0, 0, 0, 0, 0, 0}, +/* DEPTH 5 */ {0, 0, 0, 0, 0, 0, 0, 0}, +/* DEPTH 6 */ {0, 0, 0, 0, 1, 1, 1, 1}, +/* DEPTH 7 */ {0, 0, 1, 1, 2, 2, 2, 3}, + +/* FNUM BIT 6: 000 0100xxxx */ +/* DEPTH 0 */ {0, 0, 0, 0, 0, 0, 0, 0}, +/* DEPTH 1 */ {0, 0, 0, 0, 0, 0, 0, 0}, +/* DEPTH 2 */ {0, 0, 0, 0, 0, 0, 0, 0}, +/* DEPTH 3 */ {0, 0, 0, 0, 0, 0, 0, 0}, +/* DEPTH 4 */ {0, 0, 0, 0, 0, 0, 0, 1}, +/* DEPTH 5 */ {0, 0, 0, 0, 1, 1, 1, 1}, +/* DEPTH 6 */ {0, 0, 1, 1, 2, 2, 2, 3}, +/* DEPTH 7 */ {0, 0, 2, 3, 4, 4, 5, 6}, + +/* FNUM BIT 7: 000 1000xxxx */ +/* DEPTH 0 */ {0, 0, 0, 0, 0, 0, 0, 0}, +/* DEPTH 1 */ {0, 0, 0, 0, 0, 0, 0, 0}, +/* DEPTH 2 */ {0, 0, 0, 0, 0, 0, 1, 1}, +/* DEPTH 3 */ {0, 0, 0, 0, 1, 1, 1, 1}, +/* DEPTH 4 */ {0, 0, 0, 1, 1, 1, 1, 2}, +/* DEPTH 5 */ {0, 0, 1, 1, 2, 2, 2, 3}, +/* DEPTH 6 */ {0, 0, 2, 3, 4, 4, 5, 6}, +/* DEPTH 7 */ {0, 0, 4, 6, 8, 8, 0xa, 0xc}, + +/* FNUM BIT 8: 001 0000xxxx */ +/* DEPTH 0 */ {0, 0, 0, 0, 0, 0, 0, 0}, +/* DEPTH 1 */ {0, 0, 0, 0, 1, 1, 1, 1}, +/* DEPTH 2 */ {0, 0, 0, 1, 1, 1, 2, 2}, +/* DEPTH 3 */ {0, 0, 1, 1, 2, 2, 3, 3}, +/* DEPTH 4 */ {0, 0, 1, 2, 2, 2, 3, 4}, +/* DEPTH 5 */ {0, 0, 2, 3, 4, 4, 5, 6}, +/* DEPTH 6 */ {0, 0, 4, 6, 8, 8, 0xa, 0xc}, +/* DEPTH 7 */ {0, 0, 8, 0xc,0x10,0x10,0x14,0x18}, + +/* FNUM BIT 9: 010 0000xxxx */ +/* DEPTH 0 */ {0, 0, 0, 0, 0, 0, 0, 0}, +/* DEPTH 1 */ {0, 0, 0, 0, 2, 2, 2, 2}, +/* DEPTH 2 */ {0, 0, 0, 2, 2, 2, 4, 4}, +/* DEPTH 3 */ {0, 0, 2, 2, 4, 4, 6, 6}, +/* DEPTH 4 */ {0, 0, 2, 4, 4, 4, 6, 8}, +/* DEPTH 5 */ {0, 0, 4, 6, 8, 8, 0xa, 0xc}, +/* DEPTH 6 */ {0, 0, 8, 0xc,0x10,0x10,0x14,0x18}, +/* DEPTH 7 */ {0, 0,0x10,0x18,0x20,0x20,0x28,0x30}, + +/* FNUM BIT10: 100 0000xxxx */ +/* DEPTH 0 */ {0, 0, 0, 0, 0, 0, 0, 0}, +/* DEPTH 1 */ {0, 0, 0, 0, 4, 4, 4, 4}, +/* DEPTH 2 */ {0, 0, 0, 4, 4, 4, 8, 8}, +/* DEPTH 3 */ {0, 0, 4, 4, 8, 8, 0xc, 0xc}, +/* DEPTH 4 */ {0, 0, 4, 8, 8, 8, 0xc,0x10}, +/* DEPTH 5 */ {0, 0, 8, 0xc,0x10,0x10,0x14,0x18}, +/* DEPTH 6 */ {0, 0,0x10,0x18,0x20,0x20,0x28,0x30}, +/* DEPTH 7 */ {0, 0,0x20,0x30,0x40,0x40,0x50,0x60}, + +}; + +/* all 128 LFO PM waveforms */ +static INT32 lfo_pm_table[128*8*32]; /* 128 combinations of 7 bits meaningful (of F-NUMBER), 8 LFO depths, 32 LFO output levels per one depth */ + + + + + +/* register number to channel number , slot offset */ +#define OPN_CHAN(N) (N&3) +#define OPN_SLOT(N) ((N>>2)&3) + +/* slot number */ +#define SLOT1 0 +#define SLOT2 2 +#define SLOT3 1 +#define SLOT4 3 + +/* bit0 = Right enable , bit1 = Left enable */ +#define OUTD_RIGHT 1 +#define OUTD_LEFT 2 +#define OUTD_CENTER 3 + + +/* save output as raw 16-bit sample */ +/* #define SAVE_SAMPLE */ + +#ifdef SAVE_SAMPLE +static FILE *sample[1]; + #if 1 /*save to MONO file */ + #define SAVE_ALL_CHANNELS \ + { signed int pom = lt; \ + fputc((unsigned short)pom&0xff,sample[0]); \ + fputc(((unsigned short)pom>>8)&0xff,sample[0]); \ + } + #else /*save to STEREO file */ + #define SAVE_ALL_CHANNELS \ + { signed int pom = lt; \ + fputc((unsigned short)pom&0xff,sample[0]); \ + fputc(((unsigned short)pom>>8)&0xff,sample[0]); \ + pom = rt; \ + fputc((unsigned short)pom&0xff,sample[0]); \ + fputc(((unsigned short)pom>>8)&0xff,sample[0]); \ + } + #endif +#endif + + +/* struct describing a single operator (SLOT) */ +struct FM_SLOT +{ + INT32 *DT; /* detune :dt_tab[DT] */ + UINT8 KSR; /* key scale rate :3-KSR */ + UINT32 ar; /* attack rate */ + UINT32 d1r; /* decay rate */ + UINT32 d2r; /* sustain rate */ + UINT32 rr; /* release rate */ + UINT8 ksr; /* key scale rate :kcode>>(3-KSR) */ + UINT32 mul; /* multiple :ML_TABLE[ML] */ + + /* Phase Generator */ + UINT32 phase; /* phase counter */ + INT32 Incr; /* phase step */ + + /* Envelope Generator */ + UINT8 state; /* phase type */ + UINT32 tl; /* total level: TL << 3 */ + INT32 volume; /* envelope counter */ + UINT32 sl; /* sustain level:sl_table[SL] */ + UINT32 vol_out; /* current output from EG circuit (without AM from LFO) */ + + UINT8 eg_sh_ar; /* (attack state) */ + UINT8 eg_sel_ar; /* (attack state) */ + UINT8 eg_sh_d1r; /* (decay state) */ + UINT8 eg_sel_d1r; /* (decay state) */ + UINT8 eg_sh_d2r; /* (sustain state) */ + UINT8 eg_sel_d2r; /* (sustain state) */ + UINT8 eg_sh_rr; /* (release state) */ + UINT8 eg_sel_rr; /* (release state) */ + + UINT8 ssg; /* SSG-EG waveform */ + UINT8 ssgn; /* SSG-EG negated output */ + + UINT32 key; /* 0=last key was KEY OFF, 1=KEY ON */ + + /* LFO */ + UINT32 AMmask; /* AM enable flag */ + +}; + +struct FM_CH +{ + FM_SLOT SLOT[4]; /* four SLOTs (operators) */ + + UINT8 ALGO; /* algorithm */ + UINT8 FB; /* feedback shift */ + INT32 op1_out[2]; /* op1 output for feedback */ + + INT32 *connect1; /* SLOT1 output pointer */ + INT32 *connect3; /* SLOT3 output pointer */ + INT32 *connect2; /* SLOT2 output pointer */ + INT32 *connect4; /* SLOT4 output pointer */ + + INT32 *mem_connect;/* where to put the delayed sample (MEM) */ + INT32 mem_value; /* delayed sample (MEM) value */ + + INT32 pms; /* channel PMS */ + UINT8 ams; /* channel AMS */ + + UINT32 fc; /* fnum,blk:adjusted to sample rate */ + UINT8 kcode; /* key code: */ + UINT32 block_fnum; /* current blk/fnum value for this slot (can be different betweeen slots of one channel in 3slot mode) */ +}; + + +struct FM_ST +{ + device_t *device; + void * param; /* this chip parameter */ + int clock; /* master clock (Hz) */ + int rate; /* sampling rate (Hz) */ + double freqbase; /* frequency base */ + int timer_prescaler; /* timer prescaler */ +#if FM_BUSY_FLAG_SUPPORT + TIME_TYPE busy_expiry_time; /* expiry time of the busy status */ +#endif + UINT8 address; /* address register */ + UINT8 irq; /* interrupt level */ + UINT8 irqmask; /* irq mask */ + UINT8 status; /* status flag */ + UINT32 mode; /* mode CSM / 3SLOT */ + UINT8 prescaler_sel; /* prescaler selector */ + UINT8 fn_h; /* freq latch */ + INT32 TA; /* timer a */ + INT32 TAC; /* timer a counter */ + UINT8 TB; /* timer b */ + INT32 TBC; /* timer b counter */ + /* local time tables */ + INT32 dt_tab[8][32]; /* DeTune table */ + /* Extention Timer and IRQ handler */ + FM_TIMERHANDLER timer_handler; + FM_IRQHANDLER IRQ_Handler; + const ssg_callbacks *SSG; +}; + + + +/***********************************************************/ +/* OPN unit */ +/***********************************************************/ + +/* OPN 3slot struct */ +struct FM_3SLOT +{ + UINT32 fc[3]; /* fnum3,blk3: calculated */ + UINT8 fn_h; /* freq3 latch */ + UINT8 kcode[3]; /* key code */ + UINT32 block_fnum[3]; /* current fnum value for this slot (can be different betweeen slots of one channel in 3slot mode) */ +}; + +/* OPN/A/B common state */ +struct FM_OPN +{ + UINT8 type; /* chip type */ + FM_ST ST; /* general state */ + FM_3SLOT SL3; /* 3 slot mode state */ + FM_CH *P_CH; /* pointer of CH */ + unsigned int pan[6*2]; /* fm channels output masks (0xffffffff = enable) */ + + UINT32 eg_cnt; /* global envelope generator counter */ + UINT32 eg_timer; /* global envelope generator counter works at frequency = chipclock/64/3 */ + UINT32 eg_timer_add; /* step of eg_timer */ + UINT32 eg_timer_overflow;/* envelope generator timer overlfows every 3 samples (on real chip) */ + + + /* there are 2048 FNUMs that can be generated using FNUM/BLK registers + but LFO works with one more bit of a precision so we really need 4096 elements */ + + UINT32 fn_table[4096]; /* fnumber->increment counter */ + UINT32 fn_max; /* maximal phase increment (used for phase overflow) */ + + /* LFO */ + UINT32 LFO_AM; /* runtime LFO calculations helper */ + INT32 LFO_PM; /* runtime LFO calculations helper */ + + UINT32 lfo_cnt; + UINT32 lfo_inc; + + UINT32 lfo_freq[8]; /* LFO FREQ table */ + + INT32 m2,c1,c2; /* Phase Modulation input for operators 2,3,4 */ + INT32 mem; /* one sample delay memory */ + + INT32 out_fm[8]; /* outputs of working channels */ + +#if (BUILD_YM2608||BUILD_YM2610||BUILD_YM2610B) + INT32 out_adpcm[4]; /* channel output NONE,LEFT,RIGHT or CENTER for YM2608/YM2610 ADPCM */ + INT32 out_delta[4]; /* channel output NONE,LEFT,RIGHT or CENTER for YM2608/YM2610 DELTAT*/ +#endif +}; + + + +/* current chip state */ + +/* log output level */ +#define LOG_ERR 3 /* ERROR */ +#define LOG_WAR 2 /* WARNING */ +#define LOG_INF 1 /* INFORMATION */ +#define LOG_LEVEL LOG_INF + +#ifndef __RAINE__ +#define LOG(n,x) do { if( (n)>=LOG_LEVEL ) logerror x; } while (0) +#endif + +/* limitter */ +#define Limit(val, max,min) { \ + if ( val > max ) val = max; \ + else if ( val < min ) val = min; \ +} + + +/* status set and IRQ handling */ +INLINE void FM_STATUS_SET(FM_ST *ST,int flag) +{ + /* set status flag */ + ST->status |= flag; + if ( !(ST->irq) && (ST->status & ST->irqmask) ) + { + ST->irq = 1; + /* callback user interrupt handler (IRQ is OFF to ON) */ + if(ST->IRQ_Handler) (ST->IRQ_Handler)(ST->param,1); + } +} + +/* status reset and IRQ handling */ +INLINE void FM_STATUS_RESET(FM_ST *ST,int flag) +{ + /* reset status flag */ + ST->status &=~flag; + if ( (ST->irq) && !(ST->status & ST->irqmask) ) + { + ST->irq = 0; + /* callback user interrupt handler (IRQ is ON to OFF) */ + if(ST->IRQ_Handler) (ST->IRQ_Handler)(ST->param,0); + } +} + +/* IRQ mask set */ +INLINE void FM_IRQMASK_SET(FM_ST *ST,int flag) +{ + ST->irqmask = flag; + /* IRQ handling check */ + FM_STATUS_SET(ST,0); + FM_STATUS_RESET(ST,0); +} + +/* OPN Mode Register Write */ +INLINE void set_timers( FM_ST *ST, void *n, int v ) +{ + /* b7 = CSM MODE */ + /* b6 = 3 slot mode */ + /* b5 = reset b */ + /* b4 = reset a */ + /* b3 = timer enable b */ + /* b2 = timer enable a */ + /* b1 = load b */ + /* b0 = load a */ + ST->mode = v; + + /* reset Timer b flag */ + if( v & 0x20 ) + FM_STATUS_RESET(ST,0x02); + /* reset Timer a flag */ + if( v & 0x10 ) + FM_STATUS_RESET(ST,0x01); + /* load b */ + if( v & 0x02 ) + { + if( ST->TBC == 0 ) + { + ST->TBC = ( 256-ST->TB)<<4; + /* External timer handler */ + if (ST->timer_handler) (ST->timer_handler)(n,1,ST->TBC * ST->timer_prescaler,ST->clock); + } + } + else + { /* stop timer b */ + if( ST->TBC != 0 ) + { + ST->TBC = 0; + if (ST->timer_handler) (ST->timer_handler)(n,1,0,ST->clock); + } + } + /* load a */ + if( v & 0x01 ) + { + if( ST->TAC == 0 ) + { + ST->TAC = (1024-ST->TA); + /* External timer handler */ + if (ST->timer_handler) (ST->timer_handler)(n,0,ST->TAC * ST->timer_prescaler,ST->clock); + } + } + else + { /* stop timer a */ + if( ST->TAC != 0 ) + { + ST->TAC = 0; + if (ST->timer_handler) (ST->timer_handler)(n,0,0,ST->clock); + } + } +} + + +/* Timer A Overflow */ +INLINE void TimerAOver(FM_ST *ST) +{ + /* set status (if enabled) */ + if(ST->mode & 0x04) FM_STATUS_SET(ST,0x01); + /* clear or reload the counter */ + ST->TAC = (1024-ST->TA); + if (ST->timer_handler) (ST->timer_handler)(ST->param,0,ST->TAC * ST->timer_prescaler,ST->clock); +} +/* Timer B Overflow */ +INLINE void TimerBOver(FM_ST *ST) +{ + /* set status (if enabled) */ + if(ST->mode & 0x08) FM_STATUS_SET(ST,0x02); + /* clear or reload the counter */ + ST->TBC = ( 256-ST->TB)<<4; + if (ST->timer_handler) (ST->timer_handler)(ST->param,1,ST->TBC * ST->timer_prescaler,ST->clock); +} + + +#if FM_INTERNAL_TIMER +/* ----- internal timer mode , update timer */ + +/* ---------- calculate timer A ---------- */ + #define INTERNAL_TIMER_A(ST,CSM_CH) \ + { \ + if( ST->TAC && (ST->timer_handler==0) ) \ + if( (ST->TAC -= (int)(ST->freqbase*4096)) <= 0 ) \ + { \ + TimerAOver( ST ); \ + /* CSM mode total level latch and auto key on */ \ + if( ST->mode & 0x80 ) \ + CSMKeyControll( CSM_CH ); \ + } \ + } +/* ---------- calculate timer B ---------- */ + #define INTERNAL_TIMER_B(ST,step) \ + { \ + if( ST->TBC && (ST->timer_handler==0) ) \ + if( (ST->TBC -= (int)(ST->freqbase*4096*step)) <= 0 ) \ + TimerBOver( ST ); \ + } +#else /* FM_INTERNAL_TIMER */ +/* external timer mode */ +#define INTERNAL_TIMER_A(ST,CSM_CH) +#define INTERNAL_TIMER_B(ST,step) +#endif /* FM_INTERNAL_TIMER */ + + + +#if FM_BUSY_FLAG_SUPPORT +#define FM_BUSY_CLEAR(ST) ((ST)->busy_expiry_time = UNDEFINED_TIME) +INLINE UINT8 FM_STATUS_FLAG(FM_ST *ST) +{ + if( COMPARE_TIMES(ST->busy_expiry_time, UNDEFINED_TIME) != 0 ) + { + if (COMPARE_TIMES(ST->busy_expiry_time, FM_GET_TIME_NOW(&ST->device->machine())) > 0) + return ST->status | 0x80; /* with busy */ + /* expire */ + FM_BUSY_CLEAR(ST); + } + return ST->status; +} +INLINE void FM_BUSY_SET(FM_ST *ST,int busyclock ) +{ + TIME_TYPE expiry_period = MULTIPLY_TIME_BY_INT(attotime::from_hz(ST->clock), busyclock * ST->timer_prescaler); + ST->busy_expiry_time = ADD_TIMES(FM_GET_TIME_NOW(&ST->device->machine()), expiry_period); +} +#else +#define FM_STATUS_FLAG(ST) ((ST)->status) +#define FM_BUSY_SET(ST,bclock) {} +#define FM_BUSY_CLEAR(ST) {} +#endif + + + + +INLINE void FM_KEYON(UINT8 type, FM_CH *CH , int s ) +{ + FM_SLOT *SLOT = &CH->SLOT[s]; + if( !SLOT->key ) + { + SLOT->key = 1; + SLOT->phase = 0; /* restart Phase Generator */ + SLOT->ssgn = (SLOT->ssg & 0x04) >> 1; + SLOT->state = EG_ATT; + } +} + +INLINE void FM_KEYOFF(FM_CH *CH , int s ) +{ + FM_SLOT *SLOT = &CH->SLOT[s]; + if( SLOT->key ) + { + SLOT->key = 0; + if (SLOT->state>EG_REL) + SLOT->state = EG_REL;/* phase -> Release */ + } +} + +/* set algorithm connection */ +static void setup_connection( FM_OPN *OPN, FM_CH *CH, int ch ) +{ + INT32 *carrier = &OPN->out_fm[ch]; + + INT32 **om1 = &CH->connect1; + INT32 **om2 = &CH->connect3; + INT32 **oc1 = &CH->connect2; + + INT32 **memc = &CH->mem_connect; + + switch( CH->ALGO ) + { + case 0: + /* M1---C1---MEM---M2---C2---OUT */ + *om1 = &OPN->c1; + *oc1 = &OPN->mem; + *om2 = &OPN->c2; + *memc= &OPN->m2; + break; + case 1: + /* M1------+-MEM---M2---C2---OUT */ + /* C1-+ */ + *om1 = &OPN->mem; + *oc1 = &OPN->mem; + *om2 = &OPN->c2; + *memc= &OPN->m2; + break; + case 2: + /* M1-----------------+-C2---OUT */ + /* C1---MEM---M2-+ */ + *om1 = &OPN->c2; + *oc1 = &OPN->mem; + *om2 = &OPN->c2; + *memc= &OPN->m2; + break; + case 3: + /* M1---C1---MEM------+-C2---OUT */ + /* M2-+ */ + *om1 = &OPN->c1; + *oc1 = &OPN->mem; + *om2 = &OPN->c2; + *memc= &OPN->c2; + break; + case 4: + /* M1---C1-+-OUT */ + /* M2---C2-+ */ + /* MEM: not used */ + *om1 = &OPN->c1; + *oc1 = carrier; + *om2 = &OPN->c2; + *memc= &OPN->mem; /* store it anywhere where it will not be used */ + break; + case 5: + /* +----C1----+ */ + /* M1-+-MEM---M2-+-OUT */ + /* +----C2----+ */ + *om1 = 0; /* special mark */ + *oc1 = carrier; + *om2 = carrier; + *memc= &OPN->m2; + break; + case 6: + /* M1---C1-+ */ + /* M2-+-OUT */ + /* C2-+ */ + /* MEM: not used */ + *om1 = &OPN->c1; + *oc1 = carrier; + *om2 = carrier; + *memc= &OPN->mem; /* store it anywhere where it will not be used */ + break; + case 7: + /* M1-+ */ + /* C1-+-OUT */ + /* M2-+ */ + /* C2-+ */ + /* MEM: not used*/ + *om1 = carrier; + *oc1 = carrier; + *om2 = carrier; + *memc= &OPN->mem; /* store it anywhere where it will not be used */ + break; + } + + CH->connect4 = carrier; +} + +/* set detune & multiple */ +INLINE void set_det_mul(FM_ST *ST,FM_CH *CH,FM_SLOT *SLOT,int v) +{ + SLOT->mul = (v&0x0f)? (v&0x0f)*2 : 1; + SLOT->DT = ST->dt_tab[(v>>4)&7]; + CH->SLOT[SLOT1].Incr=-1; +} + +/* set total level */ +INLINE void set_tl(FM_CH *CH,FM_SLOT *SLOT , int v) +{ + SLOT->tl = (v&0x7f)<<(ENV_BITS-7); /* 7bit TL */ +} + +/* set attack rate & key scale */ +INLINE void set_ar_ksr(UINT8 type, FM_CH *CH,FM_SLOT *SLOT,int v) +{ + UINT8 old_KSR = SLOT->KSR; + + SLOT->ar = (v&0x1f) ? 32 + ((v&0x1f)<<1) : 0; + + SLOT->KSR = 3-(v>>6); + if (SLOT->KSR != old_KSR) + { + CH->SLOT[SLOT1].Incr=-1; + } + + /* refresh Attack rate */ + if ((SLOT->ar + SLOT->ksr) < 32+62) + { + SLOT->eg_sh_ar = eg_rate_shift [SLOT->ar + SLOT->ksr ]; + SLOT->eg_sel_ar = eg_rate_select[SLOT->ar + SLOT->ksr ]; + } + else + { + SLOT->eg_sh_ar = 0; + SLOT->eg_sel_ar = 17*RATE_STEPS; + } +} + +/* set decay rate */ +INLINE void set_dr(UINT8 type, FM_SLOT *SLOT,int v) +{ + SLOT->d1r = (v&0x1f) ? 32 + ((v&0x1f)<<1) : 0; + + SLOT->eg_sh_d1r = eg_rate_shift [SLOT->d1r + SLOT->ksr]; + SLOT->eg_sel_d1r= eg_rate_select[SLOT->d1r + SLOT->ksr]; +} + +/* set sustain rate */ +INLINE void set_sr(UINT8 type, FM_SLOT *SLOT,int v) +{ + SLOT->d2r = (v&0x1f) ? 32 + ((v&0x1f)<<1) : 0; + + SLOT->eg_sh_d2r = eg_rate_shift [SLOT->d2r + SLOT->ksr]; + SLOT->eg_sel_d2r= eg_rate_select[SLOT->d2r + SLOT->ksr]; +} + +/* set release rate */ +INLINE void set_sl_rr(UINT8 type, FM_SLOT *SLOT,int v) +{ + SLOT->sl = sl_table[ v>>4 ]; + + SLOT->rr = 34 + ((v&0x0f)<<2); + + SLOT->eg_sh_rr = eg_rate_shift [SLOT->rr + SLOT->ksr]; + SLOT->eg_sel_rr = eg_rate_select[SLOT->rr + SLOT->ksr]; +} + + + +INLINE signed int op_calc(UINT32 phase, unsigned int env, signed int pm) +{ + UINT32 p; + + p = (env<<3) + sin_tab[ ( ((signed int)((phase & ~FREQ_MASK) + (pm<<15))) >> FREQ_SH ) & SIN_MASK ]; + + if (p >= TL_TAB_LEN) + return 0; + return tl_tab[p]; +} + +INLINE signed int op_calc1(UINT32 phase, unsigned int env, signed int pm) +{ + UINT32 p; + + p = (env<<3) + sin_tab[ ( ((signed int)((phase & ~FREQ_MASK) + pm )) >> FREQ_SH ) & SIN_MASK ]; + + if (p >= TL_TAB_LEN) + return 0; + return tl_tab[p]; +} + +/* advance LFO to next sample */ +INLINE void advance_lfo(FM_OPN *OPN) +{ + UINT8 pos; + + if (OPN->lfo_inc) /* LFO enabled ? */ + { + OPN->lfo_cnt += OPN->lfo_inc; + + pos = (OPN->lfo_cnt >> LFO_SH) & 127; + + + /* update AM when LFO output changes */ + + /* actually I can't optimize is this way without rewriting chan_calc() + to use chip->lfo_am instead of global lfo_am */ + { + /* triangle */ + /* AM: 0 to 126 step +2, 126 to 0 step -2 */ + if (pos<64) + OPN->LFO_AM = (pos&63) * 2; + else + OPN->LFO_AM = 126 - ((pos&63) * 2); + } + + /* PM works with 4 times slower clock */ + pos >>= 2; + /* update PM when LFO output changes */ + /*if (prev_pos != pos)*/ /* can't use global lfo_pm for this optimization, must be chip->lfo_pm instead*/ + { + OPN->LFO_PM = pos; + } + + } + else + { + OPN->LFO_AM = 0; + OPN->LFO_PM = 0; + } +} + +/* changed from INLINE to static here to work around gcc 4.2.1 codegen bug */ +static void advance_eg_channel(FM_OPN *OPN, FM_SLOT *SLOT) +{ + unsigned int out; + unsigned int swap_flag = 0; + unsigned int i; + + + i = 4; /* four operators per channel */ + do + { + /* reset SSG-EG swap flag */ + swap_flag = 0; + + switch(SLOT->state) + { + case EG_ATT: /* attack phase */ + if ( !(OPN->eg_cnt & ((1<eg_sh_ar)-1) ) ) + { + SLOT->volume += (~SLOT->volume * + (eg_inc[SLOT->eg_sel_ar + ((OPN->eg_cnt>>SLOT->eg_sh_ar)&7)]) + ) >>4; + + if (SLOT->volume <= MIN_ATT_INDEX) + { + SLOT->volume = MIN_ATT_INDEX; + SLOT->state = EG_DEC; + } + } + break; + + case EG_DEC: /* decay phase */ + { + if (SLOT->ssg&0x08) /* SSG EG type envelope selected */ + { + if ( !(OPN->eg_cnt & ((1<eg_sh_d1r)-1) ) ) + { + SLOT->volume += 4 * eg_inc[SLOT->eg_sel_d1r + ((OPN->eg_cnt>>SLOT->eg_sh_d1r)&7)]; + + if ( SLOT->volume >= (INT32)(SLOT->sl) ) + SLOT->state = EG_SUS; + } + } + else + { + if ( !(OPN->eg_cnt & ((1<eg_sh_d1r)-1) ) ) + { + SLOT->volume += eg_inc[SLOT->eg_sel_d1r + ((OPN->eg_cnt>>SLOT->eg_sh_d1r)&7)]; + + if ( SLOT->volume >= (INT32)(SLOT->sl) ) + SLOT->state = EG_SUS; + } + } + } + break; + + case EG_SUS: /* sustain phase */ + if (SLOT->ssg&0x08) /* SSG EG type envelope selected */ + { + if ( !(OPN->eg_cnt & ((1<eg_sh_d2r)-1) ) ) + { + SLOT->volume += 4 * eg_inc[SLOT->eg_sel_d2r + ((OPN->eg_cnt>>SLOT->eg_sh_d2r)&7)]; + + if ( SLOT->volume >= ENV_QUIET ) + { + SLOT->volume = MAX_ATT_INDEX; + + if (SLOT->ssg&0x01) /* bit 0 = hold */ + { + if (SLOT->ssgn&1) /* have we swapped once ??? */ + { + /* yes, so do nothing, just hold current level */ + } + else + swap_flag = (SLOT->ssg&0x02) | 1 ; /* bit 1 = alternate */ + + } + else + { + /* same as KEY-ON operation */ + + /* restart of the Phase Generator should be here */ + SLOT->phase = 0; + + { + /* phase -> Attack */ + SLOT->volume = 511; + SLOT->state = EG_ATT; + } + + swap_flag = (SLOT->ssg&0x02); /* bit 1 = alternate */ + } + } + } + } + else + { + if ( !(OPN->eg_cnt & ((1<eg_sh_d2r)-1) ) ) + { + SLOT->volume += eg_inc[SLOT->eg_sel_d2r + ((OPN->eg_cnt>>SLOT->eg_sh_d2r)&7)]; + + if ( SLOT->volume >= MAX_ATT_INDEX ) + { + SLOT->volume = MAX_ATT_INDEX; + /* do not change SLOT->state (verified on real chip) */ + } + } + + } + break; + + case EG_REL: /* release phase */ + if ( !(OPN->eg_cnt & ((1<eg_sh_rr)-1) ) ) + { + /* SSG-EG affects Release phase also (Nemesis) */ + SLOT->volume += eg_inc[SLOT->eg_sel_rr + ((OPN->eg_cnt>>SLOT->eg_sh_rr)&7)]; + + if ( SLOT->volume >= MAX_ATT_INDEX ) + { + SLOT->volume = MAX_ATT_INDEX; + SLOT->state = EG_OFF; + } + } + break; + + } + + + out = ((UINT32)SLOT->volume); + + /* negate output (changes come from alternate bit, init comes from attack bit) */ + if ((SLOT->ssg&0x08) && (SLOT->ssgn&2) && (SLOT->state > EG_REL)) + out ^= MAX_ATT_INDEX; + + /* we need to store the result here because we are going to change ssgn + in next instruction */ + SLOT->vol_out = out + SLOT->tl; + + /* reverse SLOT inversion flag */ + SLOT->ssgn ^= swap_flag; + + SLOT++; + i--; + }while (i); + +} + + + +#define volume_calc(OP) ((OP)->vol_out + (AM & (OP)->AMmask)) + +INLINE void update_phase_lfo_slot(FM_OPN *OPN, FM_SLOT *SLOT, INT32 pms, UINT32 block_fnum) +{ + UINT32 fnum_lfo = ((block_fnum & 0x7f0) >> 4) * 32 * 8; + INT32 lfo_fn_table_index_offset = lfo_pm_table[ fnum_lfo + pms + OPN->LFO_PM ]; + + if (lfo_fn_table_index_offset) /* LFO phase modulation active */ + { + UINT8 blk; + UINT32 fn; + int kc, fc; + + block_fnum = block_fnum*2 + lfo_fn_table_index_offset; + + blk = (block_fnum&0x7000) >> 12; + fn = block_fnum & 0xfff; + + /* keyscale code */ + kc = (blk<<2) | opn_fktable[fn >> 8]; + + /* phase increment counter */ + fc = (OPN->fn_table[fn]>>(7-blk)) + SLOT->DT[kc]; + + /* detects frequency overflow (credits to Nemesis) */ + if (fc < 0) fc += OPN->fn_max; + + /* update phase */ + SLOT->phase += (fc * SLOT->mul) >> 1; + } + else /* LFO phase modulation = zero */ + { + SLOT->phase += SLOT->Incr; + } +} + +INLINE void update_phase_lfo_channel(FM_OPN *OPN, FM_CH *CH) +{ + UINT32 block_fnum = CH->block_fnum; + + UINT32 fnum_lfo = ((block_fnum & 0x7f0) >> 4) * 32 * 8; + INT32 lfo_fn_table_index_offset = lfo_pm_table[ fnum_lfo + CH->pms + OPN->LFO_PM ]; + + if (lfo_fn_table_index_offset) /* LFO phase modulation active */ + { + UINT8 blk; + UINT32 fn; + int kc, fc, finc; + + block_fnum = block_fnum*2 + lfo_fn_table_index_offset; + + blk = (block_fnum&0x7000) >> 12; + fn = block_fnum & 0xfff; + + /* keyscale code */ + kc = (blk<<2) | opn_fktable[fn >> 8]; + + /* phase increment counter */ + fc = (OPN->fn_table[fn]>>(7-blk)); + + /* detects frequency overflow (credits to Nemesis) */ + finc = fc + CH->SLOT[SLOT1].DT[kc]; + + if (finc < 0) finc += OPN->fn_max; + CH->SLOT[SLOT1].phase += (finc*CH->SLOT[SLOT1].mul) >> 1; + + finc = fc + CH->SLOT[SLOT2].DT[kc]; + if (finc < 0) finc += OPN->fn_max; + CH->SLOT[SLOT2].phase += (finc*CH->SLOT[SLOT2].mul) >> 1; + + finc = fc + CH->SLOT[SLOT3].DT[kc]; + if (finc < 0) finc += OPN->fn_max; + CH->SLOT[SLOT3].phase += (finc*CH->SLOT[SLOT3].mul) >> 1; + + finc = fc + CH->SLOT[SLOT4].DT[kc]; + if (finc < 0) finc += OPN->fn_max; + CH->SLOT[SLOT4].phase += (finc*CH->SLOT[SLOT4].mul) >> 1; + } + else /* LFO phase modulation = zero */ + { + CH->SLOT[SLOT1].phase += CH->SLOT[SLOT1].Incr; + CH->SLOT[SLOT2].phase += CH->SLOT[SLOT2].Incr; + CH->SLOT[SLOT3].phase += CH->SLOT[SLOT3].Incr; + CH->SLOT[SLOT4].phase += CH->SLOT[SLOT4].Incr; + } +} + +INLINE void chan_calc(FM_OPN *OPN, FM_CH *CH, int chnum) +{ + unsigned int eg_out; + + UINT32 AM = OPN->LFO_AM >> CH->ams; + + + OPN->m2 = OPN->c1 = OPN->c2 = OPN->mem = 0; + + *CH->mem_connect = CH->mem_value; /* restore delayed sample (MEM) value to m2 or c2 */ + + eg_out = volume_calc(&CH->SLOT[SLOT1]); + { + INT32 out = CH->op1_out[0] + CH->op1_out[1]; + CH->op1_out[0] = CH->op1_out[1]; + + if( !CH->connect1 ) + { + /* algorithm 5 */ + OPN->mem = OPN->c1 = OPN->c2 = CH->op1_out[0]; + } + else + { + /* other algorithms */ + *CH->connect1 += CH->op1_out[0]; + } + + CH->op1_out[1] = 0; + if( eg_out < ENV_QUIET ) /* SLOT 1 */ + { + if (!CH->FB) + out=0; + + CH->op1_out[1] = op_calc1(CH->SLOT[SLOT1].phase, eg_out, (out<FB) ); + } + } + + eg_out = volume_calc(&CH->SLOT[SLOT3]); + if( eg_out < ENV_QUIET ) /* SLOT 3 */ + *CH->connect3 += op_calc(CH->SLOT[SLOT3].phase, eg_out, OPN->m2); + + eg_out = volume_calc(&CH->SLOT[SLOT2]); + if( eg_out < ENV_QUIET ) /* SLOT 2 */ + *CH->connect2 += op_calc(CH->SLOT[SLOT2].phase, eg_out, OPN->c1); + + eg_out = volume_calc(&CH->SLOT[SLOT4]); + if( eg_out < ENV_QUIET ) /* SLOT 4 */ + *CH->connect4 += op_calc(CH->SLOT[SLOT4].phase, eg_out, OPN->c2); + + + /* store current MEM */ + CH->mem_value = OPN->mem; + + /* update phase counters AFTER output calculations */ + if(CH->pms) + { + /* add support for 3 slot mode */ + if ((OPN->ST.mode & 0xC0) && (chnum == 2)) + { + update_phase_lfo_slot(OPN, &CH->SLOT[SLOT1], CH->pms, OPN->SL3.block_fnum[1]); + update_phase_lfo_slot(OPN, &CH->SLOT[SLOT2], CH->pms, OPN->SL3.block_fnum[2]); + update_phase_lfo_slot(OPN, &CH->SLOT[SLOT3], CH->pms, OPN->SL3.block_fnum[0]); + update_phase_lfo_slot(OPN, &CH->SLOT[SLOT4], CH->pms, CH->block_fnum); + } + else update_phase_lfo_channel(OPN, CH); + } + else /* no LFO phase modulation */ + { + CH->SLOT[SLOT1].phase += CH->SLOT[SLOT1].Incr; + CH->SLOT[SLOT2].phase += CH->SLOT[SLOT2].Incr; + CH->SLOT[SLOT3].phase += CH->SLOT[SLOT3].Incr; + CH->SLOT[SLOT4].phase += CH->SLOT[SLOT4].Incr; + } +} + +/* update phase increment and envelope generator */ +INLINE void refresh_fc_eg_slot(FM_OPN *OPN, FM_SLOT *SLOT , int fc , int kc ) +{ + int ksr = kc >> SLOT->KSR; + + fc += SLOT->DT[kc]; + + /* detects frequency overflow (credits to Nemesis) */ + if (fc < 0) fc += OPN->fn_max; + + /* (frequency) phase increment counter */ + SLOT->Incr = (fc * SLOT->mul) >> 1; + + if( SLOT->ksr != ksr ) + { + SLOT->ksr = ksr; + + /* calculate envelope generator rates */ + if ((SLOT->ar + SLOT->ksr) < 32+62) + { + SLOT->eg_sh_ar = eg_rate_shift [SLOT->ar + SLOT->ksr ]; + SLOT->eg_sel_ar = eg_rate_select[SLOT->ar + SLOT->ksr ]; + } + else + { + SLOT->eg_sh_ar = 0; + SLOT->eg_sel_ar = 17*RATE_STEPS; + } + + SLOT->eg_sh_d1r = eg_rate_shift [SLOT->d1r + SLOT->ksr]; + SLOT->eg_sh_d2r = eg_rate_shift [SLOT->d2r + SLOT->ksr]; + SLOT->eg_sh_rr = eg_rate_shift [SLOT->rr + SLOT->ksr]; + + SLOT->eg_sel_d1r= eg_rate_select[SLOT->d1r + SLOT->ksr]; + SLOT->eg_sel_d2r= eg_rate_select[SLOT->d2r + SLOT->ksr]; + SLOT->eg_sel_rr = eg_rate_select[SLOT->rr + SLOT->ksr]; + } +} + +/* update phase increment counters */ +/* Changed from INLINE to static to work around gcc 4.2.1 codegen bug */ +static void refresh_fc_eg_chan(FM_OPN *OPN, FM_CH *CH ) +{ + if( CH->SLOT[SLOT1].Incr==-1) + { + int fc = CH->fc; + int kc = CH->kcode; + refresh_fc_eg_slot(OPN, &CH->SLOT[SLOT1] , fc , kc ); + refresh_fc_eg_slot(OPN, &CH->SLOT[SLOT2] , fc , kc ); + refresh_fc_eg_slot(OPN, &CH->SLOT[SLOT3] , fc , kc ); + refresh_fc_eg_slot(OPN, &CH->SLOT[SLOT4] , fc , kc ); + } +} + +/* initialize time tables */ +static void init_timetables( FM_ST *ST , const UINT8 *dttable ) +{ + int i,d; + double rate; + +#if 0 + logerror("FM.C: samplerate=%8i chip clock=%8i freqbase=%f \n", + ST->rate, ST->clock, ST->freqbase ); +#endif + + /* DeTune table */ + for (d = 0;d <= 3;d++) + { + for (i = 0;i <= 31;i++) + { + rate = ((double)dttable[d*32 + i]) * SIN_LEN * ST->freqbase * (1<dt_tab[d][i] = (INT32) rate; + ST->dt_tab[d+4][i] = -ST->dt_tab[d][i]; +#if 0 + logerror("FM.C: DT [%2i %2i] = %8x \n", d, i, ST->dt_tab[d][i] ); +#endif + } + } + +} + + +static void reset_channels( FM_ST *ST , FM_CH *CH , int num ) +{ + int c,s; + + ST->mode = 0; /* normal mode */ + ST->TA = 0; + ST->TAC = 0; + ST->TB = 0; + ST->TBC = 0; + + for( c = 0 ; c < num ; c++ ) + { + CH[c].fc = 0; + for(s = 0 ; s < 4 ; s++ ) + { + CH[c].SLOT[s].ssg = 0; + CH[c].SLOT[s].ssgn = 0; + CH[c].SLOT[s].state= EG_OFF; + CH[c].SLOT[s].volume = MAX_ATT_INDEX; + CH[c].SLOT[s].vol_out= MAX_ATT_INDEX; + } + } +} + +/* initialize generic tables */ +static int init_tables(void) +{ + signed int i,x; + signed int n; + double o,m; + + for (x=0; x>= 4; /* 12 bits here */ + if (n&1) /* round to nearest */ + n = (n>>1)+1; + else + n = n>>1; + /* 11 bits here (rounded) */ + n <<= 2; /* 13 bits here (as in real chip) */ + tl_tab[ x*2 + 0 ] = n; + tl_tab[ x*2 + 1 ] = -tl_tab[ x*2 + 0 ]; + + for (i=1; i<13; i++) + { + tl_tab[ x*2+0 + i*2*TL_RES_LEN ] = tl_tab[ x*2+0 ]>>i; + tl_tab[ x*2+1 + i*2*TL_RES_LEN ] = -tl_tab[ x*2+0 + i*2*TL_RES_LEN ]; + } + #if 0 + logerror("tl %04i", x); + for (i=0; i<13; i++) + logerror(", [%02i] %4x", i*2, tl_tab[ x*2 /*+1*/ + i*2*TL_RES_LEN ]); + logerror("\n"); + #endif + } + /*logerror("FM.C: TL_TAB_LEN = %i elements (%i bytes)\n",TL_TAB_LEN, (int)sizeof(tl_tab));*/ + + + for (i=0; i0.0) + o = 8*log(1.0/m)/log(2.0); /* convert to 'decibels' */ + else + o = 8*log(-1.0/m)/log(2.0); /* convert to 'decibels' */ + + o = o / (ENV_STEP/4); + + n = (int)(2.0*o); + if (n&1) /* round to nearest */ + n = (n>>1)+1; + else + n = n>>1; + + sin_tab[ i ] = n*2 + (m>=0.0? 0: 1 ); + /*logerror("FM.C: sin [%4i]= %4i (tl_tab value=%5i)\n", i, sin_tab[i],tl_tab[sin_tab[i]]);*/ + } + + /*logerror("FM.C: ENV_QUIET= %08x\n",ENV_QUIET );*/ + + + /* build LFO PM modulation table */ + for(i = 0; i < 8; i++) /* 8 PM depths */ + { + UINT8 fnum; + for (fnum=0; fnum<128; fnum++) /* 7 bits meaningful of F-NUMBER */ + { + UINT8 value; + UINT8 step; + UINT32 offset_depth = i; + UINT32 offset_fnum_bit; + UINT32 bit_tmp; + + for (step=0; step<8; step++) + { + value = 0; + for (bit_tmp=0; bit_tmp<7; bit_tmp++) /* 7 bits */ + { + if (fnum & (1<SLOT[SLOT1].key) + { + FM_KEYON(type, CH,SLOT1); + FM_KEYOFF(CH, SLOT1); + } + if (!CH->SLOT[SLOT2].key) + { + FM_KEYON(type, CH,SLOT2); + FM_KEYOFF(CH, SLOT2); + } + if (!CH->SLOT[SLOT3].key) + { + FM_KEYON(type, CH,SLOT3); + FM_KEYOFF(CH, SLOT3); + } + if (!CH->SLOT[SLOT4].key) + { + FM_KEYON(type, CH,SLOT4); + FM_KEYOFF(CH, SLOT4); + } +} + +#ifdef __SAVE_H__ +/* FM channel save , internal state only */ +static void FMsave_state_channel(device_t *device,FM_CH *CH,int num_ch) +{ + int slot , ch; + + for(ch=0;chsave_item(NAME(CH->op1_out), ch); + device->save_item(NAME(CH->fc), ch); + /* slots */ + for(slot=0;slot<4;slot++) + { + FM_SLOT *SLOT = &CH->SLOT[slot]; + device->save_item(NAME(SLOT->phase), ch * 4 + slot); + device->save_item(NAME(SLOT->state), ch * 4 + slot); + device->save_item(NAME(SLOT->volume), ch * 4 + slot); + } + } +} + +static void FMsave_state_st(device_t *device,FM_ST *ST) +{ +#if FM_BUSY_FLAG_SUPPORT + device->save_item(NAME(ST->busy_expiry_time) ); +#endif + device->save_item(NAME(ST->address) ); + device->save_item(NAME(ST->irq) ); + device->save_item(NAME(ST->irqmask) ); + device->save_item(NAME(ST->status) ); + device->save_item(NAME(ST->mode) ); + device->save_item(NAME(ST->prescaler_sel) ); + device->save_item(NAME(ST->fn_h) ); + device->save_item(NAME(ST->TA) ); + device->save_item(NAME(ST->TAC) ); + device->save_item(NAME(ST->TB) ); + device->save_item(NAME(ST->TBC) ); +} +#endif /* _STATE_H */ + +#if BUILD_OPN + + + +/* prescaler set (and make time tables) */ +static void OPNSetPres(FM_OPN *OPN, int pres, int timer_prescaler, int SSGpres) +{ + int i; + + /* frequency base */ + OPN->ST.freqbase = (OPN->ST.rate) ? ((double)OPN->ST.clock / OPN->ST.rate) / pres : 0; + +#if 0 + OPN->ST.rate = (double)OPN->ST.clock / pres; + OPN->ST.freqbase = 1.0; +#endif + + OPN->eg_timer_add = (1<ST.freqbase; + OPN->eg_timer_overflow = ( 3 ) * (1<ST.timer_prescaler = timer_prescaler; + + /* SSG part prescaler set */ + if( SSGpres ) (*OPN->ST.SSG->set_clock)( OPN->ST.param, OPN->ST.clock * 2 / SSGpres ); + + /* make time tables */ + init_timetables( &OPN->ST, dt_tab ); + + /* there are 2048 FNUMs that can be generated using FNUM/BLK registers + but LFO works with one more bit of a precision so we really need 4096 elements */ + /* calculate fnumber -> increment counter table */ + for(i = 0; i < 4096; i++) + { + /* freq table for octave 7 */ + /* OPN phase increment counter = 20bit */ + OPN->fn_table[i] = (UINT32)( (double)i * 32 * OPN->ST.freqbase * (1<<(FREQ_SH-10)) ); /* -10 because chip works with 10.10 fixed point, while we use 16.16 */ +#if 0 + logerror("FM.C: fn_table[%4i] = %08x (dec=%8i)\n", + i, OPN->fn_table[i]>>6,OPN->fn_table[i]>>6 ); +#endif + } + + /* maximal frequency is required for Phase overflow calculation, register size is 17 bits (Nemesis) */ + OPN->fn_max = (UINT32)( (double)0x20000 * OPN->ST.freqbase * (1<<(FREQ_SH-10)) ); + + /* LFO freq. table */ + for(i = 0; i < 8; i++) + { + /* Amplitude modulation: 64 output levels (triangle waveform); 1 level lasts for one of "lfo_samples_per_step" samples */ + /* Phase modulation: one entry from lfo_pm_output lasts for one of 4 * "lfo_samples_per_step" samples */ + OPN->lfo_freq[i] = (1.0 / lfo_samples_per_step[i]) * (1<ST.freqbase; +#if 0 + logerror("FM.C: lfo_freq[%i] = %08x (dec=%8i)\n", + i, OPN->lfo_freq[i],OPN->lfo_freq[i] ); +#endif + } +} + + + +/* write a OPN mode register 0x20-0x2f */ +static void OPNWriteMode(FM_OPN *OPN, int r, int v) +{ + UINT8 c; + FM_CH *CH; + + switch(r) + { + case 0x21: /* Test */ + break; + case 0x22: /* LFO FREQ (YM2608/YM2610/YM2610B/YM2612) */ + if( OPN->type & TYPE_LFOPAN ) + { + if (v&0x08) /* LFO enabled ? */ + { + OPN->lfo_inc = OPN->lfo_freq[v&7]; + } + else + { + OPN->lfo_inc = 0; + } + } + break; + case 0x24: /* timer A High 8*/ + OPN->ST.TA = (OPN->ST.TA & 0x03)|(((int)v)<<2); + break; + case 0x25: /* timer A Low 2*/ + OPN->ST.TA = (OPN->ST.TA & 0x3fc)|(v&3); + break; + case 0x26: /* timer B */ + OPN->ST.TB = v; + break; + case 0x27: /* mode, timer control */ + set_timers( &(OPN->ST),OPN->ST.param,v ); + break; + case 0x28: /* key on / off */ + c = v & 0x03; + if( c == 3 ) break; + if( (v&0x04) && (OPN->type & TYPE_6CH) ) c+=3; + CH = OPN->P_CH; + CH = &CH[c]; + if(v&0x10) FM_KEYON(OPN->type,CH,SLOT1); else FM_KEYOFF(CH,SLOT1); + if(v&0x20) FM_KEYON(OPN->type,CH,SLOT2); else FM_KEYOFF(CH,SLOT2); + if(v&0x40) FM_KEYON(OPN->type,CH,SLOT3); else FM_KEYOFF(CH,SLOT3); + if(v&0x80) FM_KEYON(OPN->type,CH,SLOT4); else FM_KEYOFF(CH,SLOT4); + break; + } +} + +/* write a OPN register (0x30-0xff) */ +static void OPNWriteReg(FM_OPN *OPN, int r, int v) +{ + FM_CH *CH; + FM_SLOT *SLOT; + + UINT8 c = OPN_CHAN(r); + + if (c == 3) return; /* 0xX3,0xX7,0xXB,0xXF */ + + if (r >= 0x100) c+=3; + + CH = OPN->P_CH; + CH = &CH[c]; + + SLOT = &(CH->SLOT[OPN_SLOT(r)]); + + switch( r & 0xf0 ) + { + case 0x30: /* DET , MUL */ + set_det_mul(&OPN->ST,CH,SLOT,v); + break; + + case 0x40: /* TL */ + set_tl(CH,SLOT,v); + break; + + case 0x50: /* KS, AR */ + set_ar_ksr(OPN->type,CH,SLOT,v); + break; + + case 0x60: /* bit7 = AM ENABLE, DR */ + set_dr(OPN->type, SLOT,v); + + if(OPN->type & TYPE_LFOPAN) /* YM2608/2610/2610B/2612 */ + { + SLOT->AMmask = (v&0x80) ? ~0 : 0; + } + break; + + case 0x70: /* SR */ + set_sr(OPN->type,SLOT,v); + break; + + case 0x80: /* SL, RR */ + set_sl_rr(OPN->type,SLOT,v); + break; + + case 0x90: /* SSG-EG */ + SLOT->ssg = v&0x0f; + SLOT->ssgn = (v&0x04)>>1; /* bit 1 in ssgn = attack */ + + /* SSG-EG envelope shapes : + + E AtAlH + 1 0 0 0 \\\\ + + 1 0 0 1 \___ + + 1 0 1 0 \/\/ + ___ + 1 0 1 1 \ + + 1 1 0 0 //// + ___ + 1 1 0 1 / + + 1 1 1 0 /\/\ + + 1 1 1 1 /___ + + + E = SSG-EG enable + + + The shapes are generated using Attack, Decay and Sustain phases. + + Each single character in the diagrams above represents this whole + sequence: + + - when KEY-ON = 1, normal Attack phase is generated (*without* any + difference when compared to normal mode), + + - later, when envelope level reaches minimum level (max volume), + the EG switches to Decay phase (which works with bigger steps + when compared to normal mode - see below), + + - later when envelope level passes the SL level, + the EG swithes to Sustain phase (which works with bigger steps + when compared to normal mode - see below), + + - finally when envelope level reaches maximum level (min volume), + the EG switches to Attack phase again (depends on actual waveform). + + Important is that when switch to Attack phase occurs, the phase counter + of that operator will be zeroed-out (as in normal KEY-ON) but not always. + (I havent found the rule for that - perhaps only when the output level is low) + + The difference (when compared to normal Envelope Generator mode) is + that the resolution in Decay and Sustain phases is 4 times lower; + this results in only 256 steps instead of normal 1024. + In other words: + when SSG-EG is disabled, the step inside of the EG is one, + when SSG-EG is enabled, the step is four (in Decay and Sustain phases). + + Times between the level changes are the same in both modes. + + + Important: + Decay 1 Level (so called SL) is compared to actual SSG-EG output, so + it is the same in both SSG and no-SSG modes, with this exception: + + when the SSG-EG is enabled and is generating raising levels + (when the EG output is inverted) the SL will be found at wrong level !!! + For example, when SL=02: + 0 -6 = -6dB in non-inverted EG output + 96-6 = -90dB in inverted EG output + Which means that EG compares its level to SL as usual, and that the + output is simply inverted afterall. + + + The Yamaha's manuals say that AR should be set to 0x1f (max speed). + That is not necessary, but then EG will be generating Attack phase. + + */ + + + break; + + case 0xa0: + switch( OPN_SLOT(r) ) + { + case 0: /* 0xa0-0xa2 : FNUM1 */ + { + UINT32 fn = (((UINT32)( (OPN->ST.fn_h)&7))<<8) + v; + UINT8 blk = OPN->ST.fn_h>>3; + /* keyscale code */ + CH->kcode = (blk<<2) | opn_fktable[fn >> 7]; + /* phase increment counter */ + CH->fc = OPN->fn_table[fn*2]>>(7-blk); + + /* store fnum in clear form for LFO PM calculations */ + CH->block_fnum = (blk<<11) | fn; + + CH->SLOT[SLOT1].Incr=-1; + } + break; + case 1: /* 0xa4-0xa6 : FNUM2,BLK */ + OPN->ST.fn_h = v&0x3f; + break; + case 2: /* 0xa8-0xaa : 3CH FNUM1 */ + if(r < 0x100) + { + UINT32 fn = (((UINT32)(OPN->SL3.fn_h&7))<<8) + v; + UINT8 blk = OPN->SL3.fn_h>>3; + /* keyscale code */ + OPN->SL3.kcode[c]= (blk<<2) | opn_fktable[fn >> 7]; + /* phase increment counter */ + OPN->SL3.fc[c] = OPN->fn_table[fn*2]>>(7-blk); + OPN->SL3.block_fnum[c] = (blk<<11) | fn; + (OPN->P_CH)[2].SLOT[SLOT1].Incr=-1; + } + break; + case 3: /* 0xac-0xae : 3CH FNUM2,BLK */ + if(r < 0x100) + OPN->SL3.fn_h = v&0x3f; + break; + } + break; + + case 0xb0: + switch( OPN_SLOT(r) ) + { + case 0: /* 0xb0-0xb2 : FB,ALGO */ + { + int feedback = (v>>3)&7; + CH->ALGO = v&7; + CH->FB = feedback ? feedback+6 : 0; + setup_connection( OPN, CH, c ); + } + break; + case 1: /* 0xb4-0xb6 : L , R , AMS , PMS (YM2612/YM2610B/YM2610/YM2608) */ + if( OPN->type & TYPE_LFOPAN) + { + /* b0-2 PMS */ + CH->pms = (v & 7) * 32; /* CH->pms = PM depth * 32 (index in lfo_pm_table) */ + + /* b4-5 AMS */ + CH->ams = lfo_ams_depth_shift[(v>>4) & 0x03]; + + /* PAN : b7 = L, b6 = R */ + OPN->pan[ c*2 ] = (v & 0x80) ? ~0 : 0; + OPN->pan[ c*2+1 ] = (v & 0x40) ? ~0 : 0; + + } + break; + } + break; + } +} + +#endif /* BUILD_OPN */ + +#if BUILD_OPN_PRESCALER +/* + prescaler circuit (best guess to verified chip behaviour) + + +--------------+ +-sel2-+ + | +--|in20 | + +---+ | +-sel1-+ | | +M-CLK -+-|1/2|-+--|in10 | +---+ | out|--INT_CLOCK + | +---+ | out|-|1/3|-|in21 | + +----------|in11 | +---+ +------+ + +------+ + +reg.2d : sel2 = in21 (select sel2) +reg.2e : sel1 = in11 (select sel1) +reg.2f : sel1 = in10 , sel2 = in20 (clear selector) +reset : sel1 = in11 , sel2 = in21 (clear both) + +*/ +static void OPNPrescaler_w(FM_OPN *OPN , int addr, int pre_divider) +{ + static const int opn_pres[4] = { 2*12 , 2*12 , 6*12 , 3*12 }; + static const int ssg_pres[4] = { 1 , 1 , 4 , 2 }; + int sel; + + switch(addr) + { + case 0: /* when reset */ + OPN->ST.prescaler_sel = 2; + break; + case 1: /* when postload */ + break; + case 0x2d: /* divider sel : select 1/1 for 1/3line */ + OPN->ST.prescaler_sel |= 0x02; + break; + case 0x2e: /* divider sel , select 1/3line for output */ + OPN->ST.prescaler_sel |= 0x01; + break; + case 0x2f: /* divider sel , clear both selector to 1/2,1/2 */ + OPN->ST.prescaler_sel = 0; + break; + } + sel = OPN->ST.prescaler_sel & 3; + /* update prescaler */ + OPNSetPres( OPN, opn_pres[sel]*pre_divider, + opn_pres[sel]*pre_divider, + ssg_pres[sel]*pre_divider ); +} +#endif /* BUILD_OPN_PRESCALER */ + +#if BUILD_YM2203 +/*****************************************************************************/ +/* YM2203 local section */ +/*****************************************************************************/ + +/* here's the virtual YM2203(OPN) */ +struct YM2203 +{ + UINT8 REGS[256]; /* registers */ + FM_OPN OPN; /* OPN state */ + FM_CH CH[3]; /* channel state */ +}; + +/* Generate samples for one of the YM2203s */ +void ym2203_update_one(void *chip, FMSAMPLE *buffer, int length) +{ + YM2203 *F2203 = (YM2203 *)chip; + FM_OPN *OPN = &F2203->OPN; + int i; + FMSAMPLE *buf = buffer; + FM_CH *cch[3]; + + cch[0] = &F2203->CH[0]; + cch[1] = &F2203->CH[1]; + cch[2] = &F2203->CH[2]; + + + /* refresh PG and EG */ + refresh_fc_eg_chan( OPN, cch[0] ); + refresh_fc_eg_chan( OPN, cch[1] ); + if( (F2203->OPN.ST.mode & 0xc0) ) + { + /* 3SLOT MODE */ + if( cch[2]->SLOT[SLOT1].Incr==-1) + { + refresh_fc_eg_slot(OPN, &cch[2]->SLOT[SLOT1] , OPN->SL3.fc[1] , OPN->SL3.kcode[1] ); + refresh_fc_eg_slot(OPN, &cch[2]->SLOT[SLOT2] , OPN->SL3.fc[2] , OPN->SL3.kcode[2] ); + refresh_fc_eg_slot(OPN, &cch[2]->SLOT[SLOT3] , OPN->SL3.fc[0] , OPN->SL3.kcode[0] ); + refresh_fc_eg_slot(OPN, &cch[2]->SLOT[SLOT4] , cch[2]->fc , cch[2]->kcode ); + } + } + else + refresh_fc_eg_chan( OPN, cch[2] ); + + + /* YM2203 doesn't have LFO so we must keep these globals at 0 level */ + OPN->LFO_AM = 0; + OPN->LFO_PM = 0; + + /* buffering */ + for (i=0; i < length ; i++) + { + /* clear outputs */ + OPN->out_fm[0] = 0; + OPN->out_fm[1] = 0; + OPN->out_fm[2] = 0; + + /* advance envelope generator */ + OPN->eg_timer += OPN->eg_timer_add; + while (OPN->eg_timer >= OPN->eg_timer_overflow) + { + OPN->eg_timer -= OPN->eg_timer_overflow; + OPN->eg_cnt++; + + advance_eg_channel(OPN, &cch[0]->SLOT[SLOT1]); + advance_eg_channel(OPN, &cch[1]->SLOT[SLOT1]); + advance_eg_channel(OPN, &cch[2]->SLOT[SLOT1]); + } + + /* calculate FM */ + chan_calc(OPN, cch[0], 0 ); + chan_calc(OPN, cch[1], 1 ); + chan_calc(OPN, cch[2], 2 ); + + /* buffering */ + { + int lt; + + lt = OPN->out_fm[0] + OPN->out_fm[1] + OPN->out_fm[2]; + + lt >>= FINAL_SH; + + Limit( lt , MAXOUT, MINOUT ); + + #ifdef SAVE_SAMPLE + SAVE_ALL_CHANNELS + #endif + + /* buffering */ + buf[i] = lt; + } + + /* timer A control */ + INTERNAL_TIMER_A( &F2203->OPN.ST , cch[2] ) + } + INTERNAL_TIMER_B(&F2203->OPN.ST,length) +} + +/* ---------- reset one of chip ---------- */ +void ym2203_reset_chip(void *chip) +{ + int i; + YM2203 *F2203 = (YM2203 *)chip; + FM_OPN *OPN = &F2203->OPN; + + /* Reset Prescaler */ + OPNPrescaler_w(OPN, 0 , 1 ); + /* reset SSG section */ + (*OPN->ST.SSG->reset)(OPN->ST.param); + /* status clear */ + FM_IRQMASK_SET(&OPN->ST,0x03); + FM_BUSY_CLEAR(&OPN->ST); + OPNWriteMode(OPN,0x27,0x30); /* mode 0 , timer reset */ + + OPN->eg_timer = 0; + OPN->eg_cnt = 0; + + FM_STATUS_RESET(&OPN->ST, 0xff); + + reset_channels( &OPN->ST , F2203->CH , 3 ); + /* reset OPerator paramater */ + for(i = 0xb2 ; i >= 0x30 ; i-- ) OPNWriteReg(OPN,i,0); + for(i = 0x26 ; i >= 0x20 ; i-- ) OPNWriteReg(OPN,i,0); +} + +#ifdef __SAVE_H__ +void ym2203_postload(void *chip) +{ + if (chip) + { + YM2203 *F2203 = (YM2203 *)chip; + int r; + + /* prescaler */ + OPNPrescaler_w(&F2203->OPN,1,1); + + /* SSG registers */ + for(r=0;r<16;r++) + { + (*F2203->OPN.ST.SSG->write)(F2203->OPN.ST.param,0,r); + (*F2203->OPN.ST.SSG->write)(F2203->OPN.ST.param,1,F2203->REGS[r]); + } + + /* OPN registers */ + /* DT / MULTI , TL , KS / AR , AMON / DR , SR , SL / RR , SSG-EG */ + for(r=0x30;r<0x9e;r++) + if((r&3) != 3) + OPNWriteReg(&F2203->OPN,r,F2203->REGS[r]); + /* FB / CONNECT , L / R / AMS / PMS */ + for(r=0xb0;r<0xb6;r++) + if((r&3) != 3) + OPNWriteReg(&F2203->OPN,r,F2203->REGS[r]); + + /* channels */ + /*FM_channel_postload(F2203->CH,3);*/ + } +} + +static void YM2203_save_state(YM2203 *F2203, device_t *device) +{ + device->save_item(NAME(F2203->REGS)); + FMsave_state_st(device,&F2203->OPN.ST); + FMsave_state_channel(device,F2203->CH,3); + /* 3slots */ + device->save_item (NAME(F2203->OPN.SL3.fc)); + device->save_item (NAME(F2203->OPN.SL3.fn_h)); + device->save_item (NAME(F2203->OPN.SL3.kcode)); +} +#endif /* _STATE_H */ + +/* ---------- Initialize YM2203 emulator(s) ---------- + 'num' is the number of virtual YM2203s to allocate + 'clock' is the chip clock in Hz + 'rate' is sampling rate +*/ +void * ym2203_init(void *param, device_t *device, int clock, int rate, + FM_TIMERHANDLER timer_handler,FM_IRQHANDLER IRQHandler, const ssg_callbacks *ssg) +{ + YM2203 *F2203; + + /* allocate ym2203 state space */ + F2203 = auto_alloc_clear(device->machine(), YM2203); + + if( !init_tables() ) + { + auto_free( device->machine(), F2203 ); + return NULL; + } + + F2203->OPN.ST.param = param; + F2203->OPN.type = TYPE_YM2203; + F2203->OPN.P_CH = F2203->CH; + F2203->OPN.ST.device = device; + F2203->OPN.ST.clock = clock; + F2203->OPN.ST.rate = rate; + + F2203->OPN.ST.timer_handler = timer_handler; + F2203->OPN.ST.IRQ_Handler = IRQHandler; + F2203->OPN.ST.SSG = ssg; + +#ifdef __SAVE_H__ + YM2203_save_state(F2203, device); +#endif + return F2203; +} + +/* shut down emulator */ +void ym2203_shutdown(void *chip) +{ + YM2203 *FM2203 = (YM2203 *)chip; + + FMCloseTable(); + auto_free(FM2203->OPN.ST.device->machine(), FM2203); +} + +/* YM2203 I/O interface */ +int ym2203_write(void *chip,int a,UINT8 v) +{ + YM2203 *F2203 = (YM2203 *)chip; + FM_OPN *OPN = &F2203->OPN; + + if( !(a&1) ) + { /* address port */ + OPN->ST.address = (v &= 0xff); + + /* Write register to SSG emulator */ + if( v < 16 ) (*OPN->ST.SSG->write)(OPN->ST.param,0,v); + + /* prescaler select : 2d,2e,2f */ + if( v >= 0x2d && v <= 0x2f ) + OPNPrescaler_w(OPN , v , 1); + } + else + { /* data port */ + int addr = OPN->ST.address; + F2203->REGS[addr] = v; + switch( addr & 0xf0 ) + { + case 0x00: /* 0x00-0x0f : SSG section */ + /* Write data to SSG emulator */ + (*OPN->ST.SSG->write)(OPN->ST.param,a,v); + break; + case 0x20: /* 0x20-0x2f : Mode section */ + ym2203_update_req(OPN->ST.param); + /* write register */ + OPNWriteMode(OPN,addr,v); + break; + default: /* 0x30-0xff : OPN section */ + ym2203_update_req(OPN->ST.param); + /* write register */ + OPNWriteReg(OPN,addr,v); + } + FM_BUSY_SET(&OPN->ST,1); + } + return OPN->ST.irq; +} + +UINT8 ym2203_read(void *chip,int a) +{ + YM2203 *F2203 = (YM2203 *)chip; + int addr = F2203->OPN.ST.address; + UINT8 ret = 0; + + if( !(a&1) ) + { /* status port */ + ret = FM_STATUS_FLAG(&F2203->OPN.ST); + } + else + { /* data port (only SSG) */ + if( addr < 16 ) ret = (*F2203->OPN.ST.SSG->read)(F2203->OPN.ST.param); + } + return ret; +} + +int ym2203_timer_over(void *chip,int c) +{ + YM2203 *F2203 = (YM2203 *)chip; + + if( c ) + { /* Timer B */ + TimerBOver( &(F2203->OPN.ST) ); + } + else + { /* Timer A */ + ym2203_update_req(F2203->OPN.ST.param); + /* timer update */ + TimerAOver( &(F2203->OPN.ST) ); + /* CSM mode key,TL control */ + if( F2203->OPN.ST.mode & 0x80 ) + { /* CSM mode auto key on */ + CSMKeyControll( F2203->OPN.type, &(F2203->CH[2]) ); + } + } + return F2203->OPN.ST.irq; +} +#endif /* BUILD_YM2203 */ + + + +#if (BUILD_YM2608||BUILD_YM2610||BUILD_YM2610B) + +/* ADPCM type A channel struct */ +struct ADPCM_CH +{ + UINT8 flag; /* port state */ + UINT8 flagMask; /* arrived flag mask */ + UINT8 now_data; /* current ROM data */ + UINT32 now_addr; /* current ROM address */ + UINT32 now_step; + UINT32 step; + UINT32 start; /* sample data start address*/ + UINT32 end; /* sample data end address */ + UINT8 IL; /* Instrument Level */ + INT32 adpcm_acc; /* accumulator */ + INT32 adpcm_step; /* step */ + INT32 adpcm_out; /* (speedup) hiro-shi!! */ + INT8 vol_mul; /* volume in "0.75dB" steps */ + UINT8 vol_shift; /* volume in "-6dB" steps */ + INT32 *pan; /* &out_adpcm[OPN_xxxx] */ +}; + +/* here's the virtual YM2610 */ +struct YM2610 +{ + UINT8 REGS[512]; /* registers */ + FM_OPN OPN; /* OPN state */ + FM_CH CH[6]; /* channel state */ + UINT8 addr_A1; /* address line A1 */ + + /* ADPCM-A unit */ + const UINT8 *pcmbuf; /* pcm rom buffer */ + UINT32 pcm_size; /* size of pcm rom */ + UINT8 adpcmTL; /* adpcmA total level */ + ADPCM_CH adpcm[6]; /* adpcm channels */ + UINT32 adpcmreg[0x30]; /* registers */ + UINT8 adpcm_arrivedEndAddress; + YM_DELTAT deltaT; /* Delta-T ADPCM unit */ + + UINT8 flagmask; /* YM2608 only */ + UINT8 irqmask; /* YM2608 only */ +}; + +/* here is the virtual YM2608 */ +typedef YM2610 YM2608; + + +/**** YM2610 ADPCM defines ****/ +#define ADPCM_SHIFT (16) /* frequency step rate */ +#define ADPCMA_ADDRESS_SHIFT 8 /* adpcm A address shift */ + +/* Algorithm and tables verified on real YM2608 and YM2610 */ + +/* usual ADPCM table (16 * 1.1^N) */ +static const int steps[49] = +{ + 16, 17, 19, 21, 23, 25, 28, + 31, 34, 37, 41, 45, 50, 55, + 60, 66, 73, 80, 88, 97, 107, + 118, 130, 143, 157, 173, 190, 209, + 230, 253, 279, 307, 337, 371, 408, + 449, 494, 544, 598, 658, 724, 796, + 876, 963, 1060, 1166, 1282, 1411, 1552 +}; + +/* different from the usual ADPCM table */ +static const int step_inc[8] = { -1*16, -1*16, -1*16, -1*16, 2*16, 5*16, 7*16, 9*16 }; + +/* speedup purposes only */ +static int jedi_table[ 49*16 ]; + + +static void Init_ADPCMATable(void) +{ + int step, nib; + + for (step = 0; step < 49; step++) + { + /* loop over all nibbles and compute the difference */ + for (nib = 0; nib < 16; nib++) + { + int value = (2*(nib & 0x07) + 1) * steps[step] / 8; + jedi_table[step*16 + nib] = (nib&0x08) ? -value : value; + } + } +} + +/* ADPCM A (Non control type) : calculate one channel output */ +INLINE void ADPCMA_calc_chan( YM2610 *F2610, ADPCM_CH *ch ) +{ + UINT32 step; + UINT8 data; + + + ch->now_step += ch->step; + if ( ch->now_step >= (1<now_step >> ADPCM_SHIFT; + ch->now_step &= (1< instead of == */ + /* YM2610 checks lower 20 bits only, the 4 MSB bits are sample bank */ + /* Here we use 1<<21 to compensate for nibble calculations */ + + if ( (ch->now_addr & ((1<<21)-1)) == ((ch->end<<1) & ((1<<21)-1)) ) + { + ch->flag = 0; + F2610->adpcm_arrivedEndAddress |= ch->flagMask; + return; + } +#if 0 + if ( ch->now_addr > (F2610->pcmsizeA<<1) ) + { + LOG(LOG_WAR,("YM2610: Attempting to play past adpcm rom size!\n" )); + return; + } +#endif + if ( ch->now_addr&1 ) + data = ch->now_data & 0x0f; + else + { + ch->now_data = *(F2610->pcmbuf+(ch->now_addr>>1)); + data = (ch->now_data >> 4) & 0x0f; + } + + ch->now_addr++; + + ch->adpcm_acc += jedi_table[ch->adpcm_step + data]; + + /* extend 12-bit signed int */ + if (ch->adpcm_acc & ~0x7ff) + ch->adpcm_acc |= ~0xfff; + else + ch->adpcm_acc &= 0xfff; + + ch->adpcm_step += step_inc[data & 7]; + Limit( ch->adpcm_step, 48*16, 0*16 ); + + }while(--step); + + /* calc pcm * volume data */ + ch->adpcm_out = ((ch->adpcm_acc * ch->vol_mul) >> ch->vol_shift) & ~3; /* multiply, shift and mask out 2 LSB bits */ + } + + /* output for work of output channels (out_adpcm[OPNxxxx])*/ + *(ch->pan) += ch->adpcm_out; +} + +/* ADPCM type A Write */ +static void FM_ADPCMAWrite(YM2610 *F2610,int r,int v) +{ + ADPCM_CH *adpcm = F2610->adpcm; + UINT8 c = r&0x07; + + F2610->adpcmreg[r] = v&0xff; /* stock data */ + switch( r ) + { + case 0x00: /* DM,--,C5,C4,C3,C2,C1,C0 */ + if( !(v&0x80) ) + { + /* KEY ON */ + for( c = 0; c < 6; c++ ) + { + if( (v>>c)&1 ) + { + /**** start adpcm ****/ + adpcm[c].step = (UINT32)((float)(1<OPN.ST.freqbase)/3.0f); + adpcm[c].now_addr = adpcm[c].start<<1; + adpcm[c].now_step = 0; + adpcm[c].adpcm_acc = 0; + adpcm[c].adpcm_step= 0; + adpcm[c].adpcm_out = 0; + adpcm[c].flag = 1; + + if(F2610->pcmbuf==NULL) + { /* Check ROM Mapped */ + logerror("YM2608-YM2610: ADPCM-A rom not mapped\n"); + adpcm[c].flag = 0; + } + else + { + if(adpcm[c].end >= F2610->pcm_size) + { /* Check End in Range */ + logerror("YM2610: ADPCM-A end out of range: $%08x\n",adpcm[c].end); + /*adpcm[c].end = F2610->pcm_size-1;*/ /* JB: DO NOT uncomment this, otherwise you will break the comparison in the ADPCM_CALC_CHA() */ + } + if(adpcm[c].start >= F2610->pcm_size) /* Check Start in Range */ + { + logerror("YM2608-YM2610: ADPCM-A start out of range: $%08x\n",adpcm[c].start); + adpcm[c].flag = 0; + } + } + } + } + } + else + { + /* KEY OFF */ + for( c = 0; c < 6; c++ ) + if( (v>>c)&1 ) + adpcm[c].flag = 0; + } + break; + case 0x01: /* B0-5 = TL */ + F2610->adpcmTL = (v & 0x3f) ^ 0x3f; + for( c = 0; c < 6; c++ ) + { + int volume = F2610->adpcmTL + adpcm[c].IL; + + if ( volume >= 63 ) /* This is correct, 63 = quiet */ + { + adpcm[c].vol_mul = 0; + adpcm[c].vol_shift = 0; + } + else + { + adpcm[c].vol_mul = 15 - (volume & 7); /* so called 0.75 dB */ + adpcm[c].vol_shift = 1 + (volume >> 3); /* Yamaha engineers used the approximation: each -6 dB is close to divide by two (shift right) */ + } + + /* calc pcm * volume data */ + adpcm[c].adpcm_out = ((adpcm[c].adpcm_acc * adpcm[c].vol_mul) >> adpcm[c].vol_shift) & ~3; /* multiply, shift and mask out low 2 bits */ + } + break; + default: + c = r&0x07; + if( c >= 0x06 ) return; + switch( r&0x38 ) + { + case 0x08: /* B7=L,B6=R, B4-0=IL */ + { + int volume; + + adpcm[c].IL = (v & 0x1f) ^ 0x1f; + + volume = F2610->adpcmTL + adpcm[c].IL; + + if ( volume >= 63 ) /* This is correct, 63 = quiet */ + { + adpcm[c].vol_mul = 0; + adpcm[c].vol_shift = 0; + } + else + { + adpcm[c].vol_mul = 15 - (volume & 7); /* so called 0.75 dB */ + adpcm[c].vol_shift = 1 + (volume >> 3); /* Yamaha engineers used the approximation: each -6 dB is close to divide by two (shift right) */ + } + + adpcm[c].pan = &F2610->OPN.out_adpcm[(v>>6)&0x03]; + + /* calc pcm * volume data */ + adpcm[c].adpcm_out = ((adpcm[c].adpcm_acc * adpcm[c].vol_mul) >> adpcm[c].vol_shift) & ~3; /* multiply, shift and mask out low 2 bits */ + } + break; + case 0x10: + case 0x18: + adpcm[c].start = ( (F2610->adpcmreg[0x18 + c]*0x0100 | F2610->adpcmreg[0x10 + c]) << ADPCMA_ADDRESS_SHIFT); + break; + case 0x20: + case 0x28: + adpcm[c].end = ( (F2610->adpcmreg[0x28 + c]*0x0100 | F2610->adpcmreg[0x20 + c]) << ADPCMA_ADDRESS_SHIFT); + adpcm[c].end += (1<save_item(NAME(adpcm->flag), ch); + device->save_item(NAME(adpcm->now_data), ch); + device->save_item(NAME(adpcm->now_addr), ch); + device->save_item(NAME(adpcm->now_step), ch); + device->save_item(NAME(adpcm->adpcm_acc), ch); + device->save_item(NAME(adpcm->adpcm_step), ch); + device->save_item(NAME(adpcm->adpcm_out), ch); + } +} +#endif /* _STATE_H */ + +#endif /* (BUILD_YM2608||BUILD_YM2610||BUILD_YM2610B) */ + + +#if BUILD_YM2608 +/*****************************************************************************/ +/* YM2608 local section */ +/*****************************************************************************/ + + + +static const unsigned int YM2608_ADPCM_ROM_addr[2*6] = { +0x0000, 0x01bf, /* bass drum */ +0x01c0, 0x043f, /* snare drum */ +0x0440, 0x1b7f, /* top cymbal */ +0x1b80, 0x1cff, /* high hat */ +0x1d00, 0x1f7f, /* tom tom */ +0x1f80, 0x1fff /* rim shot */ +}; + + +/* flag enable control 0x110 */ +INLINE void YM2608IRQFlagWrite(FM_OPN *OPN, YM2608 *F2608, int v) +{ + if( v & 0x80 ) + { /* Reset IRQ flag */ + FM_STATUS_RESET(&OPN->ST, 0xf7); /* don't touch BUFRDY flag otherwise we'd have to call ymdeltat module to set the flag back */ + } + else + { /* Set status flag mask */ + F2608->flagmask = (~(v&0x1f)); + FM_IRQMASK_SET(&OPN->ST, (F2608->irqmask & F2608->flagmask) ); + } +} + +/* compatible mode & IRQ enable control 0x29 */ +INLINE void YM2608IRQMaskWrite(FM_OPN *OPN, YM2608 *F2608, int v) +{ + /* SCH,xx,xxx,EN_ZERO,EN_BRDY,EN_EOS,EN_TB,EN_TA */ + + /* extend 3ch. enable/disable */ + if(v&0x80) + OPN->type |= TYPE_6CH; /* OPNA mode - 6 FM channels */ + else + OPN->type &= ~TYPE_6CH; /* OPN mode - 3 FM channels */ + + /* IRQ MASK store and set */ + F2608->irqmask = v&0x1f; + FM_IRQMASK_SET(&OPN->ST, (F2608->irqmask & F2608->flagmask) ); +} + +/* Generate samples for one of the YM2608s */ +void ym2608_update_one(void *chip, FMSAMPLE **buffer, int length) +{ + YM2608 *F2608 = (YM2608 *)chip; + FM_OPN *OPN = &F2608->OPN; + YM_DELTAT *DELTAT = &F2608->deltaT; + int i,j; + FMSAMPLE *bufL,*bufR; + FM_CH *cch[6]; + INT32 *out_fm = OPN->out_fm; + + /* set bufer */ + bufL = buffer[0]; + bufR = buffer[1]; + + cch[0] = &F2608->CH[0]; + cch[1] = &F2608->CH[1]; + cch[2] = &F2608->CH[2]; + cch[3] = &F2608->CH[3]; + cch[4] = &F2608->CH[4]; + cch[5] = &F2608->CH[5]; + + /* refresh PG and EG */ + refresh_fc_eg_chan( OPN, cch[0] ); + refresh_fc_eg_chan( OPN, cch[1] ); + if( (OPN->ST.mode & 0xc0) ) + { + /* 3SLOT MODE */ + if( cch[2]->SLOT[SLOT1].Incr==-1) + { + refresh_fc_eg_slot(OPN, &cch[2]->SLOT[SLOT1] , OPN->SL3.fc[1] , OPN->SL3.kcode[1] ); + refresh_fc_eg_slot(OPN, &cch[2]->SLOT[SLOT2] , OPN->SL3.fc[2] , OPN->SL3.kcode[2] ); + refresh_fc_eg_slot(OPN, &cch[2]->SLOT[SLOT3] , OPN->SL3.fc[0] , OPN->SL3.kcode[0] ); + refresh_fc_eg_slot(OPN, &cch[2]->SLOT[SLOT4] , cch[2]->fc , cch[2]->kcode ); + } + } + else + refresh_fc_eg_chan( OPN, cch[2] ); + refresh_fc_eg_chan( OPN, cch[3] ); + refresh_fc_eg_chan( OPN, cch[4] ); + refresh_fc_eg_chan( OPN, cch[5] ); + + + /* buffering */ + for(i=0; i < length ; i++) + { + advance_lfo(OPN); + + /* clear output acc. */ + OPN->out_adpcm[OUTD_LEFT] = OPN->out_adpcm[OUTD_RIGHT] = OPN->out_adpcm[OUTD_CENTER] = 0; + OPN->out_delta[OUTD_LEFT] = OPN->out_delta[OUTD_RIGHT] = OPN->out_delta[OUTD_CENTER] = 0; + /* clear outputs */ + out_fm[0] = 0; + out_fm[1] = 0; + out_fm[2] = 0; + out_fm[3] = 0; + out_fm[4] = 0; + out_fm[5] = 0; + + /* calculate FM */ + chan_calc(OPN, cch[0], 0 ); + chan_calc(OPN, cch[1], 1 ); + chan_calc(OPN, cch[2], 2 ); + chan_calc(OPN, cch[3], 3 ); + chan_calc(OPN, cch[4], 4 ); + chan_calc(OPN, cch[5], 5 ); + + /* deltaT ADPCM */ + if( DELTAT->portstate&0x80 ) + YM_DELTAT_ADPCM_CALC(DELTAT); + + /* ADPCMA */ + for( j = 0; j < 6; j++ ) + { + if( F2608->adpcm[j].flag ) + ADPCMA_calc_chan( F2608, &F2608->adpcm[j]); + } + + /* advance envelope generator */ + OPN->eg_timer += OPN->eg_timer_add; + while (OPN->eg_timer >= OPN->eg_timer_overflow) + { + OPN->eg_timer -= OPN->eg_timer_overflow; + OPN->eg_cnt++; + + advance_eg_channel(OPN, &cch[0]->SLOT[SLOT1]); + advance_eg_channel(OPN, &cch[1]->SLOT[SLOT1]); + advance_eg_channel(OPN, &cch[2]->SLOT[SLOT1]); + advance_eg_channel(OPN, &cch[3]->SLOT[SLOT1]); + advance_eg_channel(OPN, &cch[4]->SLOT[SLOT1]); + advance_eg_channel(OPN, &cch[5]->SLOT[SLOT1]); + } + + /* buffering */ + { + int lt,rt; + + lt = OPN->out_adpcm[OUTD_LEFT] + OPN->out_adpcm[OUTD_CENTER]; + rt = OPN->out_adpcm[OUTD_RIGHT] + OPN->out_adpcm[OUTD_CENTER]; + lt += (OPN->out_delta[OUTD_LEFT] + OPN->out_delta[OUTD_CENTER])>>9; + rt += (OPN->out_delta[OUTD_RIGHT] + OPN->out_delta[OUTD_CENTER])>>9; + lt += ((out_fm[0]>>1) & OPN->pan[0]); /* shift right verified on real YM2608 */ + rt += ((out_fm[0]>>1) & OPN->pan[1]); + lt += ((out_fm[1]>>1) & OPN->pan[2]); + rt += ((out_fm[1]>>1) & OPN->pan[3]); + lt += ((out_fm[2]>>1) & OPN->pan[4]); + rt += ((out_fm[2]>>1) & OPN->pan[5]); + lt += ((out_fm[3]>>1) & OPN->pan[6]); + rt += ((out_fm[3]>>1) & OPN->pan[7]); + lt += ((out_fm[4]>>1) & OPN->pan[8]); + rt += ((out_fm[4]>>1) & OPN->pan[9]); + lt += ((out_fm[5]>>1) & OPN->pan[10]); + rt += ((out_fm[5]>>1) & OPN->pan[11]); + + lt >>= FINAL_SH; + rt >>= FINAL_SH; + + Limit( lt, MAXOUT, MINOUT ); + Limit( rt, MAXOUT, MINOUT ); + /* buffering */ + bufL[i] = lt; + bufR[i] = rt; + + #ifdef SAVE_SAMPLE + SAVE_ALL_CHANNELS + #endif + + } + + /* timer A control */ + INTERNAL_TIMER_A( &OPN->ST , cch[2] ) + } + INTERNAL_TIMER_B(&OPN->ST,length) + + + /* check IRQ for DELTA-T EOS */ + FM_STATUS_SET(&OPN->ST, 0); + +} +#ifdef __SAVE_H__ +void ym2608_postload(void *chip) +{ + if (chip) + { + YM2608 *F2608 = (YM2608 *)chip; + int r; + + /* prescaler */ + OPNPrescaler_w(&F2608->OPN,1,2); + F2608->deltaT.freqbase = F2608->OPN.ST.freqbase; + /* IRQ mask / mode */ + YM2608IRQMaskWrite(&F2608->OPN, F2608, F2608->REGS[0x29]); + /* SSG registers */ + for(r=0;r<16;r++) + { + (*F2608->OPN.ST.SSG->write)(F2608->OPN.ST.param,0,r); + (*F2608->OPN.ST.SSG->write)(F2608->OPN.ST.param,1,F2608->REGS[r]); + } + + /* OPN registers */ + /* DT / MULTI , TL , KS / AR , AMON / DR , SR , SL / RR , SSG-EG */ + for(r=0x30;r<0x9e;r++) + if((r&3) != 3) + { + OPNWriteReg(&F2608->OPN,r,F2608->REGS[r]); + OPNWriteReg(&F2608->OPN,r|0x100,F2608->REGS[r|0x100]); + } + /* FB / CONNECT , L / R / AMS / PMS */ + for(r=0xb0;r<0xb6;r++) + if((r&3) != 3) + { + OPNWriteReg(&F2608->OPN,r,F2608->REGS[r]); + OPNWriteReg(&F2608->OPN,r|0x100,F2608->REGS[r|0x100]); + } + /* FM channels */ + /*FM_channel_postload(F2608->CH,6);*/ + /* rhythm(ADPCMA) */ + FM_ADPCMAWrite(F2608,1,F2608->REGS[0x111]); + for( r=0x08 ; r<0x0c ; r++) + FM_ADPCMAWrite(F2608,r,F2608->REGS[r+0x110]); + /* Delta-T ADPCM unit */ + YM_DELTAT_postload(&F2608->deltaT , &F2608->REGS[0x100] ); + } +} + +static void YM2608_save_state(YM2608 *F2608, device_t *device) +{ + device->save_item(NAME(F2608->REGS)); + FMsave_state_st(device,&F2608->OPN.ST); + FMsave_state_channel(device,F2608->CH,6); + /* 3slots */ + device->save_item(NAME(F2608->OPN.SL3.fc)); + device->save_item(NAME(F2608->OPN.SL3.fn_h)); + device->save_item(NAME(F2608->OPN.SL3.kcode)); + /* address register1 */ + device->save_item(NAME(F2608->addr_A1)); + /* rhythm(ADPCMA) */ + FMsave_state_adpcma(device,F2608->adpcm); + /* Delta-T ADPCM unit */ + YM_DELTAT_savestate(device,&F2608->deltaT); +} +#endif /* _STATE_H */ + +static void YM2608_deltat_status_set(void *chip, UINT8 changebits) +{ + YM2608 *F2608 = (YM2608 *)chip; + FM_STATUS_SET(&(F2608->OPN.ST), changebits); +} +static void YM2608_deltat_status_reset(void *chip, UINT8 changebits) +{ + YM2608 *F2608 = (YM2608 *)chip; + FM_STATUS_RESET(&(F2608->OPN.ST), changebits); +} +/* YM2608(OPNA) */ +void * ym2608_init(void *param, device_t *device, int clock, int rate, + void *pcmrom,int pcmsize, + FM_TIMERHANDLER timer_handler,FM_IRQHANDLER IRQHandler, const ssg_callbacks *ssg) +{ + YM2608 *F2608; + + /* allocate extend state space */ + F2608 = auto_alloc_clear(device->machine(), YM2608); + /* allocate total level table (128kb space) */ + if( !init_tables() ) + { + auto_free( device->machine(), F2608 ); + return NULL; + } + + F2608->OPN.ST.param = param; + F2608->OPN.type = TYPE_YM2608; + F2608->OPN.P_CH = F2608->CH; + F2608->OPN.ST.device = device; + F2608->OPN.ST.clock = clock; + F2608->OPN.ST.rate = rate; + + /* External handlers */ + F2608->OPN.ST.timer_handler = timer_handler; + F2608->OPN.ST.IRQ_Handler = IRQHandler; + F2608->OPN.ST.SSG = ssg; + + /* DELTA-T */ + F2608->deltaT.memory = (UINT8 *)pcmrom; + F2608->deltaT.memory_size = pcmsize; + + /*F2608->deltaT.write_time = 20.0 / clock;*/ /* a single byte write takes 20 cycles of main clock */ + /*F2608->deltaT.read_time = 18.0 / clock;*/ /* a single byte read takes 18 cycles of main clock */ + + F2608->deltaT.status_set_handler = YM2608_deltat_status_set; + F2608->deltaT.status_reset_handler = YM2608_deltat_status_reset; + F2608->deltaT.status_change_which_chip = F2608; + F2608->deltaT.status_change_EOS_bit = 0x04; /* status flag: set bit2 on End Of Sample */ + F2608->deltaT.status_change_BRDY_bit = 0x08; /* status flag: set bit3 on BRDY */ + F2608->deltaT.status_change_ZERO_bit = 0x10; /* status flag: set bit4 if silence continues for more than 290 miliseconds while recording the ADPCM */ + + /* ADPCM Rhythm */ + F2608->pcmbuf = device->memregion("ym2608")->base(); + F2608->pcm_size = 0x2000; + + Init_ADPCMATable(); + +#ifdef __SAVE_H__ + YM2608_save_state(F2608, device); +#endif + return F2608; +} + +/* shut down emulator */ +void ym2608_shutdown(void *chip) +{ + YM2608 *F2608 = (YM2608 *)chip; + + FMCloseTable(); + auto_free(F2608->OPN.ST.device->machine(), F2608); +} + +/* reset one of chips */ +void ym2608_reset_chip(void *chip) +{ + int i; + YM2608 *F2608 = (YM2608 *)chip; + FM_OPN *OPN = &F2608->OPN; + YM_DELTAT *DELTAT = &F2608->deltaT; + + /* Reset Prescaler */ + OPNPrescaler_w(OPN , 0 , 2); + F2608->deltaT.freqbase = OPN->ST.freqbase; + /* reset SSG section */ + (*OPN->ST.SSG->reset)(OPN->ST.param); + + /* status clear */ + FM_BUSY_CLEAR(&OPN->ST); + + /* register 0x29 - default value after reset is: + enable only 3 FM channels and enable all the status flags */ + YM2608IRQMaskWrite(OPN, F2608, 0x1f ); /* default value for D4-D0 is 1 */ + + /* register 0x10, A1=1 - default value is 1 for D4, D3, D2, 0 for the rest */ + YM2608IRQFlagWrite(OPN, F2608, 0x1c ); /* default: enable timer A and B, disable EOS, BRDY and ZERO */ + + OPNWriteMode(OPN,0x27,0x30); /* mode 0 , timer reset */ + + OPN->eg_timer = 0; + OPN->eg_cnt = 0; + + FM_STATUS_RESET(&OPN->ST, 0xff); + + reset_channels( &OPN->ST , F2608->CH , 6 ); + /* reset OPerator paramater */ + for(i = 0xb6 ; i >= 0xb4 ; i-- ) + { + OPNWriteReg(OPN,i ,0xc0); + OPNWriteReg(OPN,i|0x100,0xc0); + } + for(i = 0xb2 ; i >= 0x30 ; i-- ) + { + OPNWriteReg(OPN,i ,0); + OPNWriteReg(OPN,i|0x100,0); + } + for(i = 0x26 ; i >= 0x20 ; i-- ) OPNWriteReg(OPN,i,0); + + /* ADPCM - percussion sounds */ + for( i = 0; i < 6; i++ ) + { + if (i<=3) /* channels 0,1,2,3 */ + F2608->adpcm[i].step = (UINT32)((float)(1<OPN.ST.freqbase)/3.0f); + else /* channels 4 and 5 work with slower clock */ + F2608->adpcm[i].step = (UINT32)((float)(1<OPN.ST.freqbase)/6.0f); + + F2608->adpcm[i].start = YM2608_ADPCM_ROM_addr[i*2]; + F2608->adpcm[i].end = YM2608_ADPCM_ROM_addr[i*2+1]; + + F2608->adpcm[i].now_addr = 0; + F2608->adpcm[i].now_step = 0; + /* F2608->adpcm[i].delta = 21866; */ + F2608->adpcm[i].vol_mul = 0; + F2608->adpcm[i].pan = &OPN->out_adpcm[OUTD_CENTER]; /* default center */ + F2608->adpcm[i].flagMask = 0; + F2608->adpcm[i].flag = 0; + F2608->adpcm[i].adpcm_acc = 0; + F2608->adpcm[i].adpcm_step= 0; + F2608->adpcm[i].adpcm_out = 0; + } + F2608->adpcmTL = 0x3f; + + F2608->adpcm_arrivedEndAddress = 0; /* not used */ + + /* DELTA-T unit */ + DELTAT->freqbase = OPN->ST.freqbase; + DELTAT->output_pointer = OPN->out_delta; + DELTAT->portshift = 5; /* always 5bits shift */ /* ASG */ + DELTAT->output_range = 1<<23; + YM_DELTAT_ADPCM_Reset(DELTAT,OUTD_CENTER,YM_DELTAT_EMULATION_MODE_NORMAL); +} + +/* YM2608 write */ +/* n = number */ +/* a = address */ +/* v = value */ +int ym2608_write(void *chip, int a,UINT8 v) +{ + YM2608 *F2608 = (YM2608 *)chip; + FM_OPN *OPN = &F2608->OPN; + int addr; + + v &= 0xff; /*adjust to 8 bit bus */ + + + switch(a&3) + { + case 0: /* address port 0 */ + OPN->ST.address = v; + F2608->addr_A1 = 0; + + /* Write register to SSG emulator */ + if( v < 16 ) (*OPN->ST.SSG->write)(OPN->ST.param,0,v); + /* prescaler selecter : 2d,2e,2f */ + if( v >= 0x2d && v <= 0x2f ) + { + OPNPrescaler_w(OPN , v , 2); + F2608->deltaT.freqbase = OPN->ST.freqbase; + } + break; + + case 1: /* data port 0 */ + if (F2608->addr_A1 != 0) + break; /* verified on real YM2608 */ + + addr = OPN->ST.address; + F2608->REGS[addr] = v; + switch(addr & 0xf0) + { + case 0x00: /* SSG section */ + /* Write data to SSG emulator */ + (*OPN->ST.SSG->write)(OPN->ST.param,a,v); + break; + case 0x10: /* 0x10-0x1f : Rhythm section */ + ym2608_update_req(OPN->ST.param); + FM_ADPCMAWrite(F2608,addr-0x10,v); + break; + case 0x20: /* Mode Register */ + switch(addr) + { + case 0x29: /* SCH,xx,xxx,EN_ZERO,EN_BRDY,EN_EOS,EN_TB,EN_TA */ + YM2608IRQMaskWrite(OPN, F2608, v); + break; + default: + ym2608_update_req(OPN->ST.param); + OPNWriteMode(OPN,addr,v); + } + break; + default: /* OPN section */ + ym2608_update_req(OPN->ST.param); + OPNWriteReg(OPN,addr,v); + } + break; + + case 2: /* address port 1 */ + OPN->ST.address = v; + F2608->addr_A1 = 1; + break; + + case 3: /* data port 1 */ + if (F2608->addr_A1 != 1) + break; /* verified on real YM2608 */ + + addr = OPN->ST.address; + F2608->REGS[addr | 0x100] = v; + ym2608_update_req(OPN->ST.param); + switch( addr & 0xf0 ) + { + case 0x00: /* DELTAT PORT */ + switch( addr ) + { + case 0x0e: /* DAC data */ + logerror("YM2608: write to DAC data (unimplemented) value=%02x\n",v); + break; + default: + /* 0x00-0x0d */ + YM_DELTAT_ADPCM_Write(&F2608->deltaT,addr,v); + } + break; + case 0x10: /* IRQ Flag control */ + if( addr == 0x10 ) + { + YM2608IRQFlagWrite(OPN, F2608, v); + } + break; + default: + OPNWriteReg(OPN,addr | 0x100,v); + } + } + return OPN->ST.irq; +} + +UINT8 ym2608_read(void *chip,int a) +{ + YM2608 *F2608 = (YM2608 *)chip; + int addr = F2608->OPN.ST.address; + UINT8 ret = 0; + + switch( a&3 ) + { + case 0: /* status 0 : YM2203 compatible */ + /* BUSY:x:x:x:x:x:FLAGB:FLAGA */ + ret = FM_STATUS_FLAG(&F2608->OPN.ST) & 0x83; + break; + + case 1: /* status 0, ID */ + if( addr < 16 ) ret = (*F2608->OPN.ST.SSG->read)(F2608->OPN.ST.param); + else if(addr == 0xff) ret = 0x01; /* ID code */ + break; + + case 2: /* status 1 : status 0 + ADPCM status */ + /* BUSY : x : PCMBUSY : ZERO : BRDY : EOS : FLAGB : FLAGA */ + ret = (FM_STATUS_FLAG(&F2608->OPN.ST) & (F2608->flagmask|0x80)) | ((F2608->deltaT.PCM_BSY & 1)<<5) ; + break; + + case 3: + if(addr == 0x08) + { + ret = YM_DELTAT_ADPCM_Read(&F2608->deltaT); + } + else + { + if(addr == 0x0f) + { + logerror("YM2608 A/D convertion is accessed but not implemented !\n"); + ret = 0x80; /* 2's complement PCM data - result from A/D convertion */ + } + } + break; + } + return ret; +} + +int ym2608_timer_over(void *chip,int c) +{ + YM2608 *F2608 = (YM2608 *)chip; + + switch(c) + { +#if 0 + case 2: + { /* BUFRDY flag */ + YM_DELTAT_BRDY_callback( &F2608->deltaT ); + } + break; +#endif + case 1: + { /* Timer B */ + TimerBOver( &(F2608->OPN.ST) ); + } + break; + case 0: + { /* Timer A */ + ym2608_update_req(F2608->OPN.ST.param); + /* timer update */ + TimerAOver( &(F2608->OPN.ST) ); + /* CSM mode key,TL controll */ + if( F2608->OPN.ST.mode & 0x80 ) + { /* CSM mode total level latch and auto key on */ + CSMKeyControll( F2608->OPN.type, &(F2608->CH[2]) ); + } + } + break; + default: + break; + } + + return F2608->OPN.ST.irq; +} + +#endif /* BUILD_YM2608 */ + + + +#if (BUILD_YM2610||BUILD_YM2610B) +/* YM2610(OPNB) */ + +/* Generate samples for one of the YM2610s */ +void ym2610_update_one(void *chip, FMSAMPLE **buffer, int length) +{ + YM2610 *F2610 = (YM2610 *)chip; + FM_OPN *OPN = &F2610->OPN; + YM_DELTAT *DELTAT = &F2610->deltaT; + int i,j; + FMSAMPLE *bufL,*bufR; + FM_CH *cch[4]; + INT32 *out_fm = OPN->out_fm; + + /* buffer setup */ + bufL = buffer[0]; + bufR = buffer[1]; + + cch[0] = &F2610->CH[1]; + cch[1] = &F2610->CH[2]; + cch[2] = &F2610->CH[4]; + cch[3] = &F2610->CH[5]; + +#ifdef YM2610B_WARNING +#define FM_KEY_IS(SLOT) ((SLOT)->key) +#define FM_MSG_YM2610B "YM2610-%p.CH%d is playing,Check whether the type of the chip is YM2610B\n" + /* Check YM2610B warning message */ + if( FM_KEY_IS(&F2610->CH[0].SLOT[3]) ) + LOG(LOG_WAR,(FM_MSG_YM2610B,F2610->OPN.ST.param,0)); + if( FM_KEY_IS(&F2610->CH[3].SLOT[3]) ) + LOG(LOG_WAR,(FM_MSG_YM2610B,F2610->OPN.ST.param,3)); +#endif + + /* refresh PG and EG */ + refresh_fc_eg_chan( OPN, cch[0] ); + if( (OPN->ST.mode & 0xc0) ) + { + /* 3SLOT MODE */ + if( cch[1]->SLOT[SLOT1].Incr==-1) + { + refresh_fc_eg_slot(OPN, &cch[1]->SLOT[SLOT1] , OPN->SL3.fc[1] , OPN->SL3.kcode[1] ); + refresh_fc_eg_slot(OPN, &cch[1]->SLOT[SLOT2] , OPN->SL3.fc[2] , OPN->SL3.kcode[2] ); + refresh_fc_eg_slot(OPN, &cch[1]->SLOT[SLOT3] , OPN->SL3.fc[0] , OPN->SL3.kcode[0] ); + refresh_fc_eg_slot(OPN, &cch[1]->SLOT[SLOT4] , cch[1]->fc , cch[1]->kcode ); + } + } + else + refresh_fc_eg_chan( OPN, cch[1] ); + refresh_fc_eg_chan( OPN, cch[2] ); + refresh_fc_eg_chan( OPN, cch[3] ); + + /* buffering */ + for(i=0; i < length ; i++) + { + advance_lfo(OPN); + + /* clear output acc. */ + OPN->out_adpcm[OUTD_LEFT] = OPN->out_adpcm[OUTD_RIGHT] = OPN->out_adpcm[OUTD_CENTER] = 0; + OPN->out_delta[OUTD_LEFT] = OPN->out_delta[OUTD_RIGHT] = OPN->out_delta[OUTD_CENTER] = 0; + /* clear outputs */ + out_fm[1] = 0; + out_fm[2] = 0; + out_fm[4] = 0; + out_fm[5] = 0; + + /* advance envelope generator */ + OPN->eg_timer += OPN->eg_timer_add; + while (OPN->eg_timer >= OPN->eg_timer_overflow) + { + OPN->eg_timer -= OPN->eg_timer_overflow; + OPN->eg_cnt++; + + advance_eg_channel(OPN, &cch[0]->SLOT[SLOT1]); + advance_eg_channel(OPN, &cch[1]->SLOT[SLOT1]); + advance_eg_channel(OPN, &cch[2]->SLOT[SLOT1]); + advance_eg_channel(OPN, &cch[3]->SLOT[SLOT1]); + } + + /* calculate FM */ + chan_calc(OPN, cch[0], 1 ); /*remapped to 1*/ + chan_calc(OPN, cch[1], 2 ); /*remapped to 2*/ + chan_calc(OPN, cch[2], 4 ); /*remapped to 4*/ + chan_calc(OPN, cch[3], 5 ); /*remapped to 5*/ + + /* deltaT ADPCM */ + if( DELTAT->portstate&0x80 ) + YM_DELTAT_ADPCM_CALC(DELTAT); + + /* ADPCMA */ + for( j = 0; j < 6; j++ ) + { + if( F2610->adpcm[j].flag ) + ADPCMA_calc_chan( F2610, &F2610->adpcm[j]); + } + + /* buffering */ + { + int lt,rt; + + lt = OPN->out_adpcm[OUTD_LEFT] + OPN->out_adpcm[OUTD_CENTER]; + rt = OPN->out_adpcm[OUTD_RIGHT] + OPN->out_adpcm[OUTD_CENTER]; + lt += (OPN->out_delta[OUTD_LEFT] + OPN->out_delta[OUTD_CENTER])>>9; + rt += (OPN->out_delta[OUTD_RIGHT] + OPN->out_delta[OUTD_CENTER])>>9; + + + lt += ((out_fm[1]>>1) & OPN->pan[2]); /* the shift right was verified on real chip */ + rt += ((out_fm[1]>>1) & OPN->pan[3]); + lt += ((out_fm[2]>>1) & OPN->pan[4]); + rt += ((out_fm[2]>>1) & OPN->pan[5]); + + lt += ((out_fm[4]>>1) & OPN->pan[8]); + rt += ((out_fm[4]>>1) & OPN->pan[9]); + lt += ((out_fm[5]>>1) & OPN->pan[10]); + rt += ((out_fm[5]>>1) & OPN->pan[11]); + + + lt >>= FINAL_SH; + rt >>= FINAL_SH; + + Limit( lt, MAXOUT, MINOUT ); + Limit( rt, MAXOUT, MINOUT ); + + #ifdef SAVE_SAMPLE + SAVE_ALL_CHANNELS + #endif + + /* buffering */ + bufL[i] = lt; + bufR[i] = rt; + } + + /* timer A control */ + INTERNAL_TIMER_A( &OPN->ST , cch[1] ) + } + INTERNAL_TIMER_B(&OPN->ST,length) + +} + +#if BUILD_YM2610B +/* Generate samples for one of the YM2610Bs */ +void ym2610b_update_one(void *chip, FMSAMPLE **buffer, int length) +{ + YM2610 *F2610 = (YM2610 *)chip; + FM_OPN *OPN = &F2610->OPN; + YM_DELTAT *DELTAT = &F2610->deltaT; + int i,j; + FMSAMPLE *bufL,*bufR; + FM_CH *cch[6]; + INT32 *out_fm = OPN->out_fm; + + /* buffer setup */ + bufL = buffer[0]; + bufR = buffer[1]; + + cch[0] = &F2610->CH[0]; + cch[1] = &F2610->CH[1]; + cch[2] = &F2610->CH[2]; + cch[3] = &F2610->CH[3]; + cch[4] = &F2610->CH[4]; + cch[5] = &F2610->CH[5]; + + /* refresh PG and EG */ + refresh_fc_eg_chan( OPN, cch[0] ); + refresh_fc_eg_chan( OPN, cch[1] ); + if( (OPN->ST.mode & 0xc0) ) + { + /* 3SLOT MODE */ + if( cch[2]->SLOT[SLOT1].Incr==-1) + { + refresh_fc_eg_slot(OPN, &cch[2]->SLOT[SLOT1] , OPN->SL3.fc[1] , OPN->SL3.kcode[1] ); + refresh_fc_eg_slot(OPN, &cch[2]->SLOT[SLOT2] , OPN->SL3.fc[2] , OPN->SL3.kcode[2] ); + refresh_fc_eg_slot(OPN, &cch[2]->SLOT[SLOT3] , OPN->SL3.fc[0] , OPN->SL3.kcode[0] ); + refresh_fc_eg_slot(OPN, &cch[2]->SLOT[SLOT4] , cch[2]->fc , cch[2]->kcode ); + } + } + else + refresh_fc_eg_chan( OPN, cch[2] ); + refresh_fc_eg_chan( OPN, cch[3] ); + refresh_fc_eg_chan( OPN, cch[4] ); + refresh_fc_eg_chan( OPN, cch[5] ); + + /* buffering */ + for(i=0; i < length ; i++) + { + advance_lfo(OPN); + + /* clear output acc. */ + OPN->out_adpcm[OUTD_LEFT] = OPN->out_adpcm[OUTD_RIGHT] = OPN->out_adpcm[OUTD_CENTER] = 0; + OPN->out_delta[OUTD_LEFT] = OPN->out_delta[OUTD_RIGHT] = OPN->out_delta[OUTD_CENTER] = 0; + /* clear outputs */ + out_fm[0] = 0; + out_fm[1] = 0; + out_fm[2] = 0; + out_fm[3] = 0; + out_fm[4] = 0; + out_fm[5] = 0; + + /* advance envelope generator */ + OPN->eg_timer += OPN->eg_timer_add; + while (OPN->eg_timer >= OPN->eg_timer_overflow) + { + OPN->eg_timer -= OPN->eg_timer_overflow; + OPN->eg_cnt++; + + advance_eg_channel(OPN, &cch[0]->SLOT[SLOT1]); + advance_eg_channel(OPN, &cch[1]->SLOT[SLOT1]); + advance_eg_channel(OPN, &cch[2]->SLOT[SLOT1]); + advance_eg_channel(OPN, &cch[3]->SLOT[SLOT1]); + advance_eg_channel(OPN, &cch[4]->SLOT[SLOT1]); + advance_eg_channel(OPN, &cch[5]->SLOT[SLOT1]); + } + + /* calculate FM */ + chan_calc(OPN, cch[0], 0 ); + chan_calc(OPN, cch[1], 1 ); + chan_calc(OPN, cch[2], 2 ); + chan_calc(OPN, cch[3], 3 ); + chan_calc(OPN, cch[4], 4 ); + chan_calc(OPN, cch[5], 5 ); + + /* deltaT ADPCM */ + if( DELTAT->portstate&0x80 ) + YM_DELTAT_ADPCM_CALC(DELTAT); + + /* ADPCMA */ + for( j = 0; j < 6; j++ ) + { + if( F2610->adpcm[j].flag ) + ADPCMA_calc_chan( F2610, &F2610->adpcm[j]); + } + + /* buffering */ + { + int lt,rt; + + lt = OPN->out_adpcm[OUTD_LEFT] + OPN->out_adpcm[OUTD_CENTER]; + rt = OPN->out_adpcm[OUTD_RIGHT] + OPN->out_adpcm[OUTD_CENTER]; + lt += (OPN->out_delta[OUTD_LEFT] + OPN->out_delta[OUTD_CENTER])>>9; + rt += (OPN->out_delta[OUTD_RIGHT] + OPN->out_delta[OUTD_CENTER])>>9; + + lt += ((out_fm[0]>>1) & OPN->pan[0]); /* the shift right is verified on YM2610 */ + rt += ((out_fm[0]>>1) & OPN->pan[1]); + lt += ((out_fm[1]>>1) & OPN->pan[2]); + rt += ((out_fm[1]>>1) & OPN->pan[3]); + lt += ((out_fm[2]>>1) & OPN->pan[4]); + rt += ((out_fm[2]>>1) & OPN->pan[5]); + lt += ((out_fm[3]>>1) & OPN->pan[6]); + rt += ((out_fm[3]>>1) & OPN->pan[7]); + lt += ((out_fm[4]>>1) & OPN->pan[8]); + rt += ((out_fm[4]>>1) & OPN->pan[9]); + lt += ((out_fm[5]>>1) & OPN->pan[10]); + rt += ((out_fm[5]>>1) & OPN->pan[11]); + + + lt >>= FINAL_SH; + rt >>= FINAL_SH; + + Limit( lt, MAXOUT, MINOUT ); + Limit( rt, MAXOUT, MINOUT ); + + #ifdef SAVE_SAMPLE + SAVE_ALL_CHANNELS + #endif + + /* buffering */ + bufL[i] = lt; + bufR[i] = rt; + } + + /* timer A control */ + INTERNAL_TIMER_A( &OPN->ST , cch[2] ) + } + INTERNAL_TIMER_B(&OPN->ST,length) + +} +#endif /* BUILD_YM2610B */ + + +#ifdef __SAVE_H__ +void ym2610_postload(void *chip) +{ + if (chip) + { + YM2610 *F2610 = (YM2610 *)chip; + int r; + + /* SSG registers */ + for(r=0;r<16;r++) + { + (*F2610->OPN.ST.SSG->write)(F2610->OPN.ST.param,0,r); + (*F2610->OPN.ST.SSG->write)(F2610->OPN.ST.param,1,F2610->REGS[r]); + } + + /* OPN registers */ + /* DT / MULTI , TL , KS / AR , AMON / DR , SR , SL / RR , SSG-EG */ + for(r=0x30;r<0x9e;r++) + if((r&3) != 3) + { + OPNWriteReg(&F2610->OPN,r,F2610->REGS[r]); + OPNWriteReg(&F2610->OPN,r|0x100,F2610->REGS[r|0x100]); + } + /* FB / CONNECT , L / R / AMS / PMS */ + for(r=0xb0;r<0xb6;r++) + if((r&3) != 3) + { + OPNWriteReg(&F2610->OPN,r,F2610->REGS[r]); + OPNWriteReg(&F2610->OPN,r|0x100,F2610->REGS[r|0x100]); + } + /* FM channels */ + /*FM_channel_postload(F2610->CH,6);*/ + + /* rhythm(ADPCMA) */ + FM_ADPCMAWrite(F2610,1,F2610->REGS[0x101]); + for( r=0 ; r<6 ; r++) + { + FM_ADPCMAWrite(F2610,r+0x08,F2610->REGS[r+0x108]); + FM_ADPCMAWrite(F2610,r+0x10,F2610->REGS[r+0x110]); + FM_ADPCMAWrite(F2610,r+0x18,F2610->REGS[r+0x118]); + FM_ADPCMAWrite(F2610,r+0x20,F2610->REGS[r+0x120]); + FM_ADPCMAWrite(F2610,r+0x28,F2610->REGS[r+0x128]); + } + /* Delta-T ADPCM unit */ + YM_DELTAT_postload(&F2610->deltaT , &F2610->REGS[0x010] ); + } +} + +static void YM2610_save_state(YM2610 *F2610, device_t *device) +{ + device->save_item(NAME(F2610->REGS)); + FMsave_state_st(device,&F2610->OPN.ST); + FMsave_state_channel(device,F2610->CH,6); + /* 3slots */ + device->save_item(NAME(F2610->OPN.SL3.fc)); + device->save_item(NAME(F2610->OPN.SL3.fn_h)); + device->save_item(NAME(F2610->OPN.SL3.kcode)); + /* address register1 */ + device->save_item(NAME(F2610->addr_A1)); + + device->save_item(NAME(F2610->adpcm_arrivedEndAddress)); + /* rhythm(ADPCMA) */ + FMsave_state_adpcma(device,F2610->adpcm); + /* Delta-T ADPCM unit */ + YM_DELTAT_savestate(device,&F2610->deltaT); +} +#endif /* _STATE_H */ + +static void YM2610_deltat_status_set(void *chip, UINT8 changebits) +{ + YM2610 *F2610 = (YM2610 *)chip; + F2610->adpcm_arrivedEndAddress |= changebits; +} +static void YM2610_deltat_status_reset(void *chip, UINT8 changebits) +{ + YM2610 *F2610 = (YM2610 *)chip; + F2610->adpcm_arrivedEndAddress &= (~changebits); +} + +void *ym2610_init(void *param, device_t *device, int clock, int rate, + void *pcmroma,int pcmsizea,void *pcmromb,int pcmsizeb, + FM_TIMERHANDLER timer_handler,FM_IRQHANDLER IRQHandler, const ssg_callbacks *ssg) + +{ + YM2610 *F2610; + + /* allocate extend state space */ + F2610 = auto_alloc_clear(device->machine(), YM2610); + /* allocate total level table (128kb space) */ + if( !init_tables() ) + { + auto_free( device->machine(), F2610 ); + return NULL; + } + + /* FM */ + F2610->OPN.ST.param = param; + F2610->OPN.type = TYPE_YM2610; + F2610->OPN.P_CH = F2610->CH; + F2610->OPN.ST.device = device; + F2610->OPN.ST.clock = clock; + F2610->OPN.ST.rate = rate; + /* Extend handler */ + F2610->OPN.ST.timer_handler = timer_handler; + F2610->OPN.ST.IRQ_Handler = IRQHandler; + F2610->OPN.ST.SSG = ssg; + /* ADPCM */ + F2610->pcmbuf = (const UINT8 *)pcmroma; + F2610->pcm_size = pcmsizea; + /* DELTA-T */ + F2610->deltaT.memory = (UINT8 *)pcmromb; + F2610->deltaT.memory_size = pcmsizeb; + + F2610->deltaT.status_set_handler = YM2610_deltat_status_set; + F2610->deltaT.status_reset_handler = YM2610_deltat_status_reset; + F2610->deltaT.status_change_which_chip = F2610; + F2610->deltaT.status_change_EOS_bit = 0x80; /* status flag: set bit7 on End Of Sample */ + + Init_ADPCMATable(); +#ifdef __SAVE_H__ + YM2610_save_state(F2610, device); +#endif + return F2610; +} + +/* shut down emulator */ +void ym2610_shutdown(void *chip) +{ + YM2610 *F2610 = (YM2610 *)chip; + + FMCloseTable(); + auto_free(F2610->OPN.ST.device->machine(), F2610); +} + +/* reset one of chip */ +void ym2610_reset_chip(void *chip) +{ + int i; + YM2610 *F2610 = (YM2610 *)chip; + FM_OPN *OPN = &F2610->OPN; + YM_DELTAT *DELTAT = &F2610->deltaT; + + device_t* dev = F2610->OPN.ST.device; + std::string name(dev->tag()); + + /* setup PCM buffers again */ + F2610->pcmbuf = (const UINT8 *)dev->machine().root_device().memregion(name.c_str())->base(); + F2610->pcm_size = dev->machine().root_device().memregion(name.c_str())->bytes(); + name.append(".deltat"); + F2610->deltaT.memory = (UINT8 *)dev->machine().root_device().memregion(name.c_str())->base(); + if(F2610->deltaT.memory == NULL) + { + F2610->deltaT.memory = (UINT8*)F2610->pcmbuf; + F2610->deltaT.memory_size = F2610->pcm_size; + } + else + F2610->deltaT.memory_size = dev->machine().root_device().memregion(name.c_str())->bytes(); + + /* Reset Prescaler */ + OPNSetPres( OPN, 6*24, 6*24, 4*2); /* OPN 1/6 , SSG 1/4 */ + /* reset SSG section */ + (*OPN->ST.SSG->reset)(OPN->ST.param); + /* status clear */ + FM_IRQMASK_SET(&OPN->ST,0x03); + FM_BUSY_CLEAR(&OPN->ST); + OPNWriteMode(OPN,0x27,0x30); /* mode 0 , timer reset */ + + OPN->eg_timer = 0; + OPN->eg_cnt = 0; + + FM_STATUS_RESET(&OPN->ST, 0xff); + + reset_channels( &OPN->ST , F2610->CH , 6 ); + /* reset OPerator paramater */ + for(i = 0xb6 ; i >= 0xb4 ; i-- ) + { + OPNWriteReg(OPN,i ,0xc0); + OPNWriteReg(OPN,i|0x100,0xc0); + } + for(i = 0xb2 ; i >= 0x30 ; i-- ) + { + OPNWriteReg(OPN,i ,0); + OPNWriteReg(OPN,i|0x100,0); + } + for(i = 0x26 ; i >= 0x20 ; i-- ) OPNWriteReg(OPN,i,0); + /**** ADPCM work initial ****/ + for( i = 0; i < 6 ; i++ ) + { + F2610->adpcm[i].step = (UINT32)((float)(1<OPN.ST.freqbase)/3.0f); + F2610->adpcm[i].now_addr = 0; + F2610->adpcm[i].now_step = 0; + F2610->adpcm[i].start = 0; + F2610->adpcm[i].end = 0; + /* F2610->adpcm[i].delta = 21866; */ + F2610->adpcm[i].vol_mul = 0; + F2610->adpcm[i].pan = &OPN->out_adpcm[OUTD_CENTER]; /* default center */ + F2610->adpcm[i].flagMask = 1<adpcm[i].flag = 0; + F2610->adpcm[i].adpcm_acc = 0; + F2610->adpcm[i].adpcm_step= 0; + F2610->adpcm[i].adpcm_out = 0; + } + F2610->adpcmTL = 0x3f; + + F2610->adpcm_arrivedEndAddress = 0; + + /* DELTA-T unit */ + DELTAT->freqbase = OPN->ST.freqbase; + DELTAT->output_pointer = OPN->out_delta; + DELTAT->portshift = 8; /* allways 8bits shift */ + DELTAT->output_range = 1<<23; + YM_DELTAT_ADPCM_Reset(DELTAT,OUTD_CENTER,YM_DELTAT_EMULATION_MODE_YM2610); +} + +/* YM2610 write */ +/* n = number */ +/* a = address */ +/* v = value */ +int ym2610_write(void *chip, int a, UINT8 v) +{ + YM2610 *F2610 = (YM2610 *)chip; + FM_OPN *OPN = &F2610->OPN; + int addr; + int ch; + + v &= 0xff; /* adjust to 8 bit bus */ + + switch( a&3 ) + { + case 0: /* address port 0 */ + OPN->ST.address = v; + F2610->addr_A1 = 0; + + /* Write register to SSG emulator */ + if( v < 16 ) (*OPN->ST.SSG->write)(OPN->ST.param,0,v); + break; + + case 1: /* data port 0 */ + if (F2610->addr_A1 != 0) + break; /* verified on real YM2608 */ + + addr = OPN->ST.address; + F2610->REGS[addr] = v; + switch(addr & 0xf0) + { + case 0x00: /* SSG section */ + /* Write data to SSG emulator */ + (*OPN->ST.SSG->write)(OPN->ST.param,a,v); + break; + case 0x10: /* DeltaT ADPCM */ + ym2610_update_req(OPN->ST.param); + + switch(addr) + { + case 0x10: /* control 1 */ + case 0x11: /* control 2 */ + case 0x12: /* start address L */ + case 0x13: /* start address H */ + case 0x14: /* stop address L */ + case 0x15: /* stop address H */ + + case 0x19: /* delta-n L */ + case 0x1a: /* delta-n H */ + case 0x1b: /* volume */ + { + YM_DELTAT_ADPCM_Write(&F2610->deltaT,addr-0x10,v); + } + break; + + case 0x1c: /* FLAG CONTROL : Extend Status Clear/Mask */ + { + UINT8 statusmask = ~v; + /* set arrived flag mask */ + for(ch=0;ch<6;ch++) + F2610->adpcm[ch].flagMask = statusmask&(1<deltaT.status_change_EOS_bit = statusmask & 0x80; /* status flag: set bit7 on End Of Sample */ + + /* clear arrived flag */ + F2610->adpcm_arrivedEndAddress &= statusmask; + } + break; + + default: + logerror("YM2610: write to unknown deltat register %02x val=%02x\n",addr,v); + break; + } + + break; + case 0x20: /* Mode Register */ + ym2610_update_req(OPN->ST.param); + OPNWriteMode(OPN,addr,v); + break; + default: /* OPN section */ + ym2610_update_req(OPN->ST.param); + /* write register */ + OPNWriteReg(OPN,addr,v); + } + break; + + case 2: /* address port 1 */ + OPN->ST.address = v; + F2610->addr_A1 = 1; + break; + + case 3: /* data port 1 */ + if (F2610->addr_A1 != 1) + break; /* verified on real YM2608 */ + + ym2610_update_req(OPN->ST.param); + addr = OPN->ST.address; + F2610->REGS[addr | 0x100] = v; + if( addr < 0x30 ) + /* 100-12f : ADPCM A section */ + FM_ADPCMAWrite(F2610,addr,v); + else + OPNWriteReg(OPN,addr | 0x100,v); + } + return OPN->ST.irq; +} + +UINT8 ym2610_read(void *chip,int a) +{ + YM2610 *F2610 = (YM2610 *)chip; + int addr = F2610->OPN.ST.address; + UINT8 ret = 0; + + switch( a&3) + { + case 0: /* status 0 : YM2203 compatible */ + ret = FM_STATUS_FLAG(&F2610->OPN.ST) & 0x83; + break; + case 1: /* data 0 */ + if( addr < 16 ) ret = (*F2610->OPN.ST.SSG->read)(F2610->OPN.ST.param); + if( addr == 0xff ) ret = 0x01; + break; + case 2: /* status 1 : ADPCM status */ + /* ADPCM STATUS (arrived End Address) */ + /* B,--,A5,A4,A3,A2,A1,A0 */ + /* B = ADPCM-B(DELTA-T) arrived end address */ + /* A0-A5 = ADPCM-A arrived end address */ + ret = F2610->adpcm_arrivedEndAddress; + break; + case 3: + ret = 0; + break; + } + return ret; +} + +int ym2610_timer_over(void *chip,int c) +{ + YM2610 *F2610 = (YM2610 *)chip; + + if( c ) + { /* Timer B */ + TimerBOver( &(F2610->OPN.ST) ); + } + else + { /* Timer A */ + ym2610_update_req(F2610->OPN.ST.param); + /* timer update */ + TimerAOver( &(F2610->OPN.ST) ); + /* CSM mode key,TL controll */ + if( F2610->OPN.ST.mode & 0x80 ) + { /* CSM mode total level latch and auto key on */ + CSMKeyControll( F2610->OPN.type, &(F2610->CH[2]) ); + } + } + return F2610->OPN.ST.irq; +} + +#endif /* (BUILD_YM2610||BUILD_YM2610B) */ diff --git a/src/devices/sound/fm.h b/src/devices/sound/fm.h new file mode 100644 index 00000000000..878f753b599 --- /dev/null +++ b/src/devices/sound/fm.h @@ -0,0 +1,201 @@ +// license:??? +// copyright-holders:Jarek Burczynski +/* + File: fm.h -- header file for software emulation for FM sound generator + +*/ + +#pragma once + +#ifndef __FM_H__ +#define __FM_H__ + +/* --- select emulation chips --- */ +#define BUILD_YM2203 (1) /* build YM2203(OPN) emulator */ +#define BUILD_YM2608 (1) /* build YM2608(OPNA) emulator */ +#define BUILD_YM2610 (1) /* build YM2610(OPNB) emulator */ +#define BUILD_YM2610B (1) /* build YM2610B(OPNB?)emulator */ +#define BUILD_YM2612 (1) /* build YM2612(OPN2) emulator */ +#define BUILD_YM3438 (1) /* build YM3438(OPN) emulator */ + +/* select bit size of output : 8 or 16 */ +#define FM_SAMPLE_BITS 16 + +/* select timer system internal or external */ +#define FM_INTERNAL_TIMER 0 + +/* --- speedup optimize --- */ +/* busy flag enulation , The definition of FM_GET_TIME_NOW() is necessary. */ +#define FM_BUSY_FLAG_SUPPORT 1 + +/* --- external SSG(YM2149/AY-3-8910)emulator interface port */ +/* used by YM2203,YM2608,and YM2610 */ +struct ssg_callbacks +{ + void (*set_clock)(void *param, int clock); + void (*write)(void *param, int address, int data); + int (*read)(void *param); + void (*reset)(void *param); +}; + +/* --- external callback funstions for realtime update --- */ + +#if FM_BUSY_FLAG_SUPPORT +#define TIME_TYPE attotime +#define UNDEFINED_TIME attotime::zero +#define FM_GET_TIME_NOW(machine) (machine)->time() +#define ADD_TIMES(t1, t2) ((t1) + (t2)) +#define COMPARE_TIMES(t1, t2) (((t1) == (t2)) ? 0 : ((t1) < (t2)) ? -1 : 1) +#define MULTIPLY_TIME_BY_INT(t,i) ((t) * (i)) +#endif + +#if BUILD_YM2203 + /* in 2203intf.c */ + void ym2203_update_request(void *param); + #define ym2203_update_req(chip) ym2203_update_request(chip) +#endif /* BUILD_YM2203 */ + +#if BUILD_YM2608 + /* in 2608intf.c */ + void ym2608_update_request(void *param); + #define ym2608_update_req(chip) ym2608_update_request(chip); +#endif /* BUILD_YM2608 */ + +#if (BUILD_YM2610||BUILD_YM2610B) + /* in 2610intf.c */ + void ym2610_update_request(void *param); + #define ym2610_update_req(chip) ym2610_update_request(chip); +#endif /* (BUILD_YM2610||BUILD_YM2610B) */ + +#if (BUILD_YM2612||BUILD_YM3438) + /* in 2612intf.c */ + void ym2612_update_request(void *param); + #define ym2612_update_req(chip) ym2612_update_request(chip); +#endif /* (BUILD_YM2612||BUILD_YM3438) */ + + +typedef stream_sample_t FMSAMPLE; +/* +#if (FM_SAMPLE_BITS==16) +typedef INT16 FMSAMPLE; +#endif +#if (FM_SAMPLE_BITS==8) +typedef unsigned char FMSAMPLE; +#endif +*/ + +typedef void (*FM_TIMERHANDLER)(void *param,int c,int cnt,int clock); +typedef void (*FM_IRQHANDLER)(void *param,int irq); +/* FM_TIMERHANDLER : Stop or Start timer */ +/* int n = chip number */ +/* int c = Channel 0=TimerA,1=TimerB */ +/* int count = timer count (0=stop) */ +/* doube stepTime = step time of one count (sec.)*/ + +/* FM_IRQHHANDLER : IRQ level changing sense */ +/* int n = chip number */ +/* int irq = IRQ level 0=OFF,1=ON */ + +#if BUILD_YM2203 +/* -------------------- YM2203(OPN) Interface -------------------- */ + +/* +** Initialize YM2203 emulator(s). +** +** 'num' is the number of virtual YM2203's to allocate +** 'baseclock' +** 'rate' is sampling rate +** 'TimerHandler' timer callback handler when timer start and clear +** 'IRQHandler' IRQ callback handler when changed IRQ level +** return 0 = success +*/ +void * ym2203_init(void *param, device_t *device, int baseclock, int rate, + FM_TIMERHANDLER TimerHandler,FM_IRQHANDLER IRQHandler, const ssg_callbacks *ssg); + +/* +** shutdown the YM2203 emulators +*/ +void ym2203_shutdown(void *chip); + +/* +** reset all chip registers for YM2203 number 'num' +*/ +void ym2203_reset_chip(void *chip); + +/* +** update one of chip +*/ +void ym2203_update_one(void *chip, FMSAMPLE *buffer, int length); + +/* +** Write +** return : InterruptLevel +*/ +int ym2203_write(void *chip,int a,unsigned char v); + +/* +** Read +** return : InterruptLevel +*/ +unsigned char ym2203_read(void *chip,int a); + +/* +** Timer OverFlow +*/ +int ym2203_timer_over(void *chip, int c); + +/* +** State Save +*/ +void ym2203_postload(void *chip); +#endif /* BUILD_YM2203 */ + +#if BUILD_YM2608 +/* -------------------- YM2608(OPNA) Interface -------------------- */ +void * ym2608_init(void *param, device_t *device, int baseclock, int rate, + void *pcmroma,int pcmsizea, + FM_TIMERHANDLER TimerHandler,FM_IRQHANDLER IRQHandler, const ssg_callbacks *ssg); +void ym2608_shutdown(void *chip); +void ym2608_reset_chip(void *chip); +void ym2608_update_one(void *chip, FMSAMPLE **buffer, int length); + +int ym2608_write(void *chip, int a,unsigned char v); +unsigned char ym2608_read(void *chip,int a); +int ym2608_timer_over(void *chip, int c ); +void ym2608_postload(void *chip); +#endif /* BUILD_YM2608 */ + +#if (BUILD_YM2610||BUILD_YM2610B) +/* -------------------- YM2610(OPNB) Interface -------------------- */ +void * ym2610_init(void *param, device_t *device, int baseclock, int rate, + void *pcmroma,int pcmasize,void *pcmromb,int pcmbsize, + FM_TIMERHANDLER TimerHandler,FM_IRQHANDLER IRQHandler, const ssg_callbacks *ssg); +void ym2610_shutdown(void *chip); +void ym2610_reset_chip(void *chip); +void ym2610_update_one(void *chip, FMSAMPLE **buffer, int length); + +#if BUILD_YM2610B +void ym2610b_update_one(void *chip, FMSAMPLE **buffer, int length); +#endif /* BUILD_YM2610B */ + +int ym2610_write(void *chip, int a,unsigned char v); +unsigned char ym2610_read(void *chip,int a); +int ym2610_timer_over(void *chip, int c ); +void ym2610_postload(void *chip); +#endif /* (BUILD_YM2610||BUILD_YM2610B) */ + +#if (BUILD_YM2612||BUILD_YM3438) +void * ym2612_init(void *param, device_t *device, int baseclock, int rate, + FM_TIMERHANDLER TimerHandler,FM_IRQHANDLER IRQHandler); +void ym2612_shutdown(void *chip); +void ym2612_reset_chip(void *chip); +void ym2612_update_one(void *chip, FMSAMPLE **buffer, int length); + +int ym2612_write(void *chip, int a,unsigned char v); +unsigned char ym2612_read(void *chip,int a); +int ym2612_timer_over(void *chip, int c ); +void ym2612_postload(void *chip); +#endif /* (BUILD_YM2612||BUILD_YM3438) */ + + +#endif /* __FM_H__ */ diff --git a/src/devices/sound/fm2612.c b/src/devices/sound/fm2612.c new file mode 100644 index 00000000000..034b07a8595 --- /dev/null +++ b/src/devices/sound/fm2612.c @@ -0,0 +1,2559 @@ +// license:??? +// copyright-holders:Jarek Burczynski,Tatsuyuki Satoh +/* +** +** File: fm2612.c -- software implementation of Yamaha YM2612 FM sound generator +** Split from fm.c to keep 2612 fixes from infecting other OPN chips +** +** Copyright Jarek Burczynski (bujar at mame dot net) +** Copyright Tatsuyuki Satoh , MultiArcadeMachineEmulator development +** +** Version 1.5.1 (Genesis Plus GX ym2612.c rev. 368) +** +*/ + +/* +** History: +** +** 2006~2009 Eke-Eke (Genesis Plus GX): +** Huge thanks to Nemesis, lot of those fixes came from his tests on Sega Genesis hardware +** More informations at http://gendev.spritesmind.net/forum/viewtopic.php?t=386 +** +** TODO: +** +** - core documentation +** - BUSY flag support +** +** CHANGELOG: +** +** 07-30-2014 dink (FB Alpha project): +** - fixed missing dac channel on savestate load +** +** xx-xx-xxxx +** - fixed LFO implementation: +** .added support for CH3 special mode: fixes various sound effects (birds in Warlock, bug sound in Aladdin...) +** .inverted LFO AM waveform: fixes Spider-Man & Venom : Separation Anxiety (intro), California Games (surfing event) +** .improved LFO timing accuracy: now updated AFTER sample output, like EG/PG updates, and without any precision loss anymore. +** - improved internal timers emulation +** - adjusted lowest EG rates increment values +** - fixed Attack Rate not being updated in some specific cases (Batman & Robin intro) +** - fixed EG behavior when Attack Rate is maximal +** - fixed EG behavior when SL=0 (Mega Turrican tracks 03,09...) or/and Key ON occurs at minimal attenuation +** - implemented EG output immediate changes on register writes +** - fixed YM2612 initial values (after the reset): fixes missing intro in B.O.B +** - implemented Detune overflow (Ariel, Comix Zone, Shaq Fu, Spiderman & many other games using GEMS sound engine) +** - implemented accurate CSM mode emulation +** - implemented accurate SSG-EG emulation (Asterix, Beavis&Butthead, Bubba'n Stix & many other games) +** - implemented accurate address/data ports behavior +** +** 06-23-2007 Zsolt Vasvari: +** - changed the timing not to require the use of floating point calculations +** +** 03-08-2003 Jarek Burczynski: +** - fixed YM2608 initial values (after the reset) +** - fixed flag and irqmask handling (YM2608) +** - fixed BUFRDY flag handling (YM2608) +** +** 14-06-2003 Jarek Burczynski: +** - implemented all of the YM2608 status register flags +** - implemented support for external memory read/write via YM2608 +** - implemented support for deltat memory limit register in YM2608 emulation +** +** 22-05-2003 Jarek Burczynski: +** - fixed LFO PM calculations (copy&paste bugfix) +** +** 08-05-2003 Jarek Burczynski: +** - fixed SSG support +** +** 22-04-2003 Jarek Burczynski: +** - implemented 100% correct LFO generator (verified on real YM2610 and YM2608) +** +** 15-04-2003 Jarek Burczynski: +** - added support for YM2608's register 0x110 - status mask +** +** 01-12-2002 Jarek Burczynski: +** - fixed register addressing in YM2608, YM2610, YM2610B chips. (verified on real YM2608) +** The addressing patch used for early Neo-Geo games can be removed now. +** +** 26-11-2002 Jarek Burczynski, Nicola Salmoria: +** - recreated YM2608 ADPCM ROM using data from real YM2608's output which leads to: +** - added emulation of YM2608 drums. +** - output of YM2608 is two times lower now - same as YM2610 (verified on real YM2608) +** +** 16-08-2002 Jarek Burczynski: +** - binary exact Envelope Generator (verified on real YM2203); +** identical to YM2151 +** - corrected 'off by one' error in feedback calculations (when feedback is off) +** - corrected connection (algorithm) calculation (verified on real YM2203 and YM2610) +** +** 18-12-2001 Jarek Burczynski: +** - added SSG-EG support (verified on real YM2203) +** +** 12-08-2001 Jarek Burczynski: +** - corrected sin_tab and tl_tab data (verified on real chip) +** - corrected feedback calculations (verified on real chip) +** - corrected phase generator calculations (verified on real chip) +** - corrected envelope generator calculations (verified on real chip) +** - corrected FM volume level (YM2610 and YM2610B). +** - changed YMxxxUpdateOne() functions (YM2203, YM2608, YM2610, YM2610B, YM2612) : +** this was needed to calculate YM2610 FM channels output correctly. +** (Each FM channel is calculated as in other chips, but the output of the channel +** gets shifted right by one *before* sending to accumulator. That was impossible to do +** with previous implementation). +** +** 23-07-2001 Jarek Burczynski, Nicola Salmoria: +** - corrected YM2610 ADPCM type A algorithm and tables (verified on real chip) +** +** 11-06-2001 Jarek Burczynski: +** - corrected end of sample bug in ADPCMA_calc_cha(). +** Real YM2610 checks for equality between current and end addresses (only 20 LSB bits). +** +** 08-12-98 hiro-shi: +** rename ADPCMA -> ADPCMB, ADPCMB -> ADPCMA +** move ROM limit check.(CALC_CH? -> 2610Write1/2) +** test program (ADPCMB_TEST) +** move ADPCM A/B end check. +** ADPCMB repeat flag(no check) +** change ADPCM volume rate (8->16) (32->48). +** +** 09-12-98 hiro-shi: +** change ADPCM volume. (8->16, 48->64) +** replace ym2610 ch0/3 (YM-2610B) +** change ADPCM_SHIFT (10->8) missing bank change 0x4000-0xffff. +** add ADPCM_SHIFT_MASK +** change ADPCMA_DECODE_MIN/MAX. +*/ + + + + +/************************************************************************/ +/* comment of hiro-shi(Hiromitsu Shioya) */ +/* YM2610(B) = OPN-B */ +/* YM2610 : PSG:3ch FM:4ch ADPCM(18.5KHz):6ch DeltaT ADPCM:1ch */ +/* YM2610B : PSG:3ch FM:6ch ADPCM(18.5KHz):6ch DeltaT ADPCM:1ch */ +/************************************************************************/ + +#include "emu.h" +#include "fm.h" + +/* shared function building option */ +#define BUILD_OPN (BUILD_YM2203||BUILD_YM2608||BUILD_YM2610||BUILD_YM2610B||BUILD_YM2612||BUILD_YM3438) +#define BUILD_OPN_PRESCALER (BUILD_YM2203||BUILD_YM2608) + + +/* globals */ +#define TYPE_SSG 0x01 /* SSG support */ +#define TYPE_LFOPAN 0x02 /* OPN type LFO and PAN */ +#define TYPE_6CH 0x04 /* FM 6CH / 3CH */ +#define TYPE_DAC 0x08 /* YM2612's DAC device */ +#define TYPE_ADPCM 0x10 /* two ADPCM units */ +#define TYPE_2610 0x20 /* bogus flag to differentiate 2608 from 2610 */ + + +#define TYPE_YM2203 (TYPE_SSG) +#define TYPE_YM2608 (TYPE_SSG |TYPE_LFOPAN |TYPE_6CH |TYPE_ADPCM) +#define TYPE_YM2610 (TYPE_SSG |TYPE_LFOPAN |TYPE_6CH |TYPE_ADPCM |TYPE_2610) +#define TYPE_YM2612 (TYPE_DAC |TYPE_LFOPAN |TYPE_6CH) + + +/* globals */ +#define FREQ_SH 16 /* 16.16 fixed point (frequency calculations) */ +#define EG_SH 16 /* 16.16 fixed point (envelope generator timing) */ +#define LFO_SH 24 /* 8.24 fixed point (LFO calculations) */ +#define TIMER_SH 16 /* 16.16 fixed point (timers calculations) */ + +#define FREQ_MASK ((1<>3) + +/* sin waveform table in 'decibel' scale */ +static unsigned int sin_tab[SIN_LEN]; + +/* sustain level table (3dB per step) */ +/* bit0, bit1, bit2, bit3, bit4, bit5, bit6 */ +/* 1, 2, 4, 8, 16, 32, 64 (value)*/ +/* 0.75, 1.5, 3, 6, 12, 24, 48 (dB)*/ + +/* 0 - 15: 0, 3, 6, 9,12,15,18,21,24,27,30,33,36,39,42,93 (dB)*/ +/* attenuation value (10 bits) = (SL << 2) << 3 */ +#define SC(db) (UINT32) ( db * (4.0/ENV_STEP) ) +static const UINT32 sl_table[16]={ + SC( 0),SC( 1),SC( 2),SC(3 ),SC(4 ),SC(5 ),SC(6 ),SC( 7), + SC( 8),SC( 9),SC(10),SC(11),SC(12),SC(13),SC(14),SC(31) +}; +#undef SC + + +#define RATE_STEPS (8) +static const UINT8 eg_inc[19*RATE_STEPS]={ +/*cycle:0 1 2 3 4 5 6 7*/ + +/* 0 */ 0,1, 0,1, 0,1, 0,1, /* rates 00..11 0 (increment by 0 or 1) */ +/* 1 */ 0,1, 0,1, 1,1, 0,1, /* rates 00..11 1 */ +/* 2 */ 0,1, 1,1, 0,1, 1,1, /* rates 00..11 2 */ +/* 3 */ 0,1, 1,1, 1,1, 1,1, /* rates 00..11 3 */ + +/* 4 */ 1,1, 1,1, 1,1, 1,1, /* rate 12 0 (increment by 1) */ +/* 5 */ 1,1, 1,2, 1,1, 1,2, /* rate 12 1 */ +/* 6 */ 1,2, 1,2, 1,2, 1,2, /* rate 12 2 */ +/* 7 */ 1,2, 2,2, 1,2, 2,2, /* rate 12 3 */ + +/* 8 */ 2,2, 2,2, 2,2, 2,2, /* rate 13 0 (increment by 2) */ +/* 9 */ 2,2, 2,4, 2,2, 2,4, /* rate 13 1 */ +/*10 */ 2,4, 2,4, 2,4, 2,4, /* rate 13 2 */ +/*11 */ 2,4, 4,4, 2,4, 4,4, /* rate 13 3 */ + +/*12 */ 4,4, 4,4, 4,4, 4,4, /* rate 14 0 (increment by 4) */ +/*13 */ 4,4, 4,8, 4,4, 4,8, /* rate 14 1 */ +/*14 */ 4,8, 4,8, 4,8, 4,8, /* rate 14 2 */ +/*15 */ 4,8, 8,8, 4,8, 8,8, /* rate 14 3 */ + +/*16 */ 8,8, 8,8, 8,8, 8,8, /* rates 15 0, 15 1, 15 2, 15 3 (increment by 8) */ +/*17 */ 16,16,16,16,16,16,16,16, /* rates 15 2, 15 3 for attack */ +/*18 */ 0,0, 0,0, 0,0, 0,0, /* infinity rates for attack and decay(s) */ +}; + + +#define O(a) (a*RATE_STEPS) + +/*note that there is no O(17) in this table - it's directly in the code */ +static const UINT8 eg_rate_select2612[32+64+32]={ /* Envelope Generator rates (32 + 64 rates + 32 RKS) */ +/* 32 infinite time rates (same as Rate 0) */ +O(18),O(18),O(18),O(18),O(18),O(18),O(18),O(18), +O(18),O(18),O(18),O(18),O(18),O(18),O(18),O(18), +O(18),O(18),O(18),O(18),O(18),O(18),O(18),O(18), +O(18),O(18),O(18),O(18),O(18),O(18),O(18),O(18), + +/* rates 00-11 */ +/* +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +*/ +O(18),O(18),O( 0),O( 0), +O( 0),O( 0),O( 2),O( 2), // Nemesis's tests + +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), + +/* rate 12 */ +O( 4),O( 5),O( 6),O( 7), + +/* rate 13 */ +O( 8),O( 9),O(10),O(11), + +/* rate 14 */ +O(12),O(13),O(14),O(15), + +/* rate 15 */ +O(16),O(16),O(16),O(16), + +/* 32 dummy rates (same as 15 3) */ +O(16),O(16),O(16),O(16),O(16),O(16),O(16),O(16), +O(16),O(16),O(16),O(16),O(16),O(16),O(16),O(16), +O(16),O(16),O(16),O(16),O(16),O(16),O(16),O(16), +O(16),O(16),O(16),O(16),O(16),O(16),O(16),O(16) + +}; +#undef O + +/*rate 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15*/ +/*shift 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0, 0, 0, 0 */ +/*mask 2047, 1023, 511, 255, 127, 63, 31, 15, 7, 3, 1, 0, 0, 0, 0, 0 */ + +#define O(a) (a*1) +static const UINT8 eg_rate_shift[32+64+32]={ /* Envelope Generator counter shifts (32 + 64 rates + 32 RKS) */ +/* 32 infinite time rates */ +/* O(0),O(0),O(0),O(0),O(0),O(0),O(0),O(0), +O(0),O(0),O(0),O(0),O(0),O(0),O(0),O(0), +O(0),O(0),O(0),O(0),O(0),O(0),O(0),O(0), +O(0),O(0),O(0),O(0),O(0),O(0),O(0),O(0), */ + +/* fixed (should be the same as rate 0, even if it makes no difference since increment value is 0 for these rates) */ +O(11),O(11),O(11),O(11),O(11),O(11),O(11),O(11), +O(11),O(11),O(11),O(11),O(11),O(11),O(11),O(11), +O(11),O(11),O(11),O(11),O(11),O(11),O(11),O(11), +O(11),O(11),O(11),O(11),O(11),O(11),O(11),O(11), + +/* rates 00-11 */ +O(11),O(11),O(11),O(11), +O(10),O(10),O(10),O(10), +O( 9),O( 9),O( 9),O( 9), +O( 8),O( 8),O( 8),O( 8), +O( 7),O( 7),O( 7),O( 7), +O( 6),O( 6),O( 6),O( 6), +O( 5),O( 5),O( 5),O( 5), +O( 4),O( 4),O( 4),O( 4), +O( 3),O( 3),O( 3),O( 3), +O( 2),O( 2),O( 2),O( 2), +O( 1),O( 1),O( 1),O( 1), +O( 0),O( 0),O( 0),O( 0), + +/* rate 12 */ +O( 0),O( 0),O( 0),O( 0), + +/* rate 13 */ +O( 0),O( 0),O( 0),O( 0), + +/* rate 14 */ +O( 0),O( 0),O( 0),O( 0), + +/* rate 15 */ +O( 0),O( 0),O( 0),O( 0), + +/* 32 dummy rates (same as 15 3) */ +O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0), +O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0), +O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0), +O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0) + +}; +#undef O + +static const UINT8 dt_tab[4 * 32]={ +/* this is YM2151 and YM2612 phase increment data (in 10.10 fixed point format)*/ +/* FD=0 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/* FD=1 */ + 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, + 2, 3, 3, 3, 4, 4, 4, 5, 5, 6, 6, 7, 8, 8, 8, 8, +/* FD=2 */ + 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, + 5, 6, 6, 7, 8, 8, 9,10,11,12,13,14,16,16,16,16, +/* FD=3 */ + 2, 2, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 6, 6, 7, + 8 , 8, 9,10,11,12,13,14,16,17,19,20,22,22,22,22 +}; + + +/* OPN key frequency number -> key code follow table */ +/* fnum higher 4bit -> keycode lower 2bit */ +static const UINT8 opn_fktable[16] = {0,0,0,0,0,0,0,1,2,3,3,3,3,3,3,3}; + + +/* 8 LFO speed parameters */ +/* each value represents number of samples that one LFO level will last for */ +static const UINT32 lfo_samples_per_step[8] = {108, 77, 71, 67, 62, 44, 8, 5}; + + + +/*There are 4 different LFO AM depths available, they are: + 0 dB, 1.4 dB, 5.9 dB, 11.8 dB + Here is how it is generated (in EG steps): + + 11.8 dB = 0, 2, 4, 6, 8, 10,12,14,16...126,126,124,122,120,118,....4,2,0 + 5.9 dB = 0, 1, 2, 3, 4, 5, 6, 7, 8....63, 63, 62, 61, 60, 59,.....2,1,0 + 1.4 dB = 0, 0, 0, 0, 1, 1, 1, 1, 2,...15, 15, 15, 15, 14, 14,.....0,0,0 + + (1.4 dB is losing precision as you can see) + + It's implemented as generator from 0..126 with step 2 then a shift + right N times, where N is: + 8 for 0 dB + 3 for 1.4 dB + 1 for 5.9 dB + 0 for 11.8 dB +*/ +static const UINT8 lfo_ams_depth_shift[4] = {8, 3, 1, 0}; + + + +/*There are 8 different LFO PM depths available, they are: + 0, 3.4, 6.7, 10, 14, 20, 40, 80 (cents) + + Modulation level at each depth depends on F-NUMBER bits: 4,5,6,7,8,9,10 + (bits 8,9,10 = FNUM MSB from OCT/FNUM register) + + Here we store only first quarter (positive one) of full waveform. + Full table (lfo_pm_table) containing all 128 waveforms is build + at run (init) time. + + One value in table below represents 4 (four) basic LFO steps + (1 PM step = 4 AM steps). + + For example: + at LFO SPEED=0 (which is 108 samples per basic LFO step) + one value from "lfo_pm_output" table lasts for 432 consecutive + samples (4*108=432) and one full LFO waveform cycle lasts for 13824 + samples (32*432=13824; 32 because we store only a quarter of whole + waveform in the table below) +*/ +static const UINT8 lfo_pm_output[7*8][8]={ /* 7 bits meaningful (of F-NUMBER), 8 LFO output levels per one depth (out of 32), 8 LFO depths */ +/* FNUM BIT 4: 000 0001xxxx */ +/* DEPTH 0 */ {0, 0, 0, 0, 0, 0, 0, 0}, +/* DEPTH 1 */ {0, 0, 0, 0, 0, 0, 0, 0}, +/* DEPTH 2 */ {0, 0, 0, 0, 0, 0, 0, 0}, +/* DEPTH 3 */ {0, 0, 0, 0, 0, 0, 0, 0}, +/* DEPTH 4 */ {0, 0, 0, 0, 0, 0, 0, 0}, +/* DEPTH 5 */ {0, 0, 0, 0, 0, 0, 0, 0}, +/* DEPTH 6 */ {0, 0, 0, 0, 0, 0, 0, 0}, +/* DEPTH 7 */ {0, 0, 0, 0, 1, 1, 1, 1}, + +/* FNUM BIT 5: 000 0010xxxx */ +/* DEPTH 0 */ {0, 0, 0, 0, 0, 0, 0, 0}, +/* DEPTH 1 */ {0, 0, 0, 0, 0, 0, 0, 0}, +/* DEPTH 2 */ {0, 0, 0, 0, 0, 0, 0, 0}, +/* DEPTH 3 */ {0, 0, 0, 0, 0, 0, 0, 0}, +/* DEPTH 4 */ {0, 0, 0, 0, 0, 0, 0, 0}, +/* DEPTH 5 */ {0, 0, 0, 0, 0, 0, 0, 0}, +/* DEPTH 6 */ {0, 0, 0, 0, 1, 1, 1, 1}, +/* DEPTH 7 */ {0, 0, 1, 1, 2, 2, 2, 3}, + +/* FNUM BIT 6: 000 0100xxxx */ +/* DEPTH 0 */ {0, 0, 0, 0, 0, 0, 0, 0}, +/* DEPTH 1 */ {0, 0, 0, 0, 0, 0, 0, 0}, +/* DEPTH 2 */ {0, 0, 0, 0, 0, 0, 0, 0}, +/* DEPTH 3 */ {0, 0, 0, 0, 0, 0, 0, 0}, +/* DEPTH 4 */ {0, 0, 0, 0, 0, 0, 0, 1}, +/* DEPTH 5 */ {0, 0, 0, 0, 1, 1, 1, 1}, +/* DEPTH 6 */ {0, 0, 1, 1, 2, 2, 2, 3}, +/* DEPTH 7 */ {0, 0, 2, 3, 4, 4, 5, 6}, + +/* FNUM BIT 7: 000 1000xxxx */ +/* DEPTH 0 */ {0, 0, 0, 0, 0, 0, 0, 0}, +/* DEPTH 1 */ {0, 0, 0, 0, 0, 0, 0, 0}, +/* DEPTH 2 */ {0, 0, 0, 0, 0, 0, 1, 1}, +/* DEPTH 3 */ {0, 0, 0, 0, 1, 1, 1, 1}, +/* DEPTH 4 */ {0, 0, 0, 1, 1, 1, 1, 2}, +/* DEPTH 5 */ {0, 0, 1, 1, 2, 2, 2, 3}, +/* DEPTH 6 */ {0, 0, 2, 3, 4, 4, 5, 6}, +/* DEPTH 7 */ {0, 0, 4, 6, 8, 8, 0xa, 0xc}, + +/* FNUM BIT 8: 001 0000xxxx */ +/* DEPTH 0 */ {0, 0, 0, 0, 0, 0, 0, 0}, +/* DEPTH 1 */ {0, 0, 0, 0, 1, 1, 1, 1}, +/* DEPTH 2 */ {0, 0, 0, 1, 1, 1, 2, 2}, +/* DEPTH 3 */ {0, 0, 1, 1, 2, 2, 3, 3}, +/* DEPTH 4 */ {0, 0, 1, 2, 2, 2, 3, 4}, +/* DEPTH 5 */ {0, 0, 2, 3, 4, 4, 5, 6}, +/* DEPTH 6 */ {0, 0, 4, 6, 8, 8, 0xa, 0xc}, +/* DEPTH 7 */ {0, 0, 8, 0xc,0x10,0x10,0x14,0x18}, + +/* FNUM BIT 9: 010 0000xxxx */ +/* DEPTH 0 */ {0, 0, 0, 0, 0, 0, 0, 0}, +/* DEPTH 1 */ {0, 0, 0, 0, 2, 2, 2, 2}, +/* DEPTH 2 */ {0, 0, 0, 2, 2, 2, 4, 4}, +/* DEPTH 3 */ {0, 0, 2, 2, 4, 4, 6, 6}, +/* DEPTH 4 */ {0, 0, 2, 4, 4, 4, 6, 8}, +/* DEPTH 5 */ {0, 0, 4, 6, 8, 8, 0xa, 0xc}, +/* DEPTH 6 */ {0, 0, 8, 0xc,0x10,0x10,0x14,0x18}, +/* DEPTH 7 */ {0, 0,0x10,0x18,0x20,0x20,0x28,0x30}, + +/* FNUM BIT10: 100 0000xxxx */ +/* DEPTH 0 */ {0, 0, 0, 0, 0, 0, 0, 0}, +/* DEPTH 1 */ {0, 0, 0, 0, 4, 4, 4, 4}, +/* DEPTH 2 */ {0, 0, 0, 4, 4, 4, 8, 8}, +/* DEPTH 3 */ {0, 0, 4, 4, 8, 8, 0xc, 0xc}, +/* DEPTH 4 */ {0, 0, 4, 8, 8, 8, 0xc,0x10}, +/* DEPTH 5 */ {0, 0, 8, 0xc,0x10,0x10,0x14,0x18}, +/* DEPTH 6 */ {0, 0,0x10,0x18,0x20,0x20,0x28,0x30}, +/* DEPTH 7 */ {0, 0,0x20,0x30,0x40,0x40,0x50,0x60}, + +}; + +/* all 128 LFO PM waveforms */ +static INT32 lfo_pm_table[128*8*32]; /* 128 combinations of 7 bits meaningful (of F-NUMBER), 8 LFO depths, 32 LFO output levels per one depth */ + +/* register number to channel number , slot offset */ +#define OPN_CHAN(N) (N&3) +#define OPN_SLOT(N) ((N>>2)&3) + +/* slot number */ +#define SLOT1 0 +#define SLOT2 2 +#define SLOT3 1 +#define SLOT4 3 + +/* bit0 = Right enable , bit1 = Left enable */ +#define OUTD_RIGHT 1 +#define OUTD_LEFT 2 +#define OUTD_CENTER 3 + + +/* save output as raw 16-bit sample */ +/* #define SAVE_SAMPLE */ + +#ifdef SAVE_SAMPLE +static FILE *sample[1]; + #if 1 /*save to MONO file */ + #define SAVE_ALL_CHANNELS \ + { signed int pom = lt; \ + fputc((unsigned short)pom&0xff,sample[0]); \ + fputc(((unsigned short)pom>>8)&0xff,sample[0]); \ + } + #else /*save to STEREO file */ + #define SAVE_ALL_CHANNELS \ + { signed int pom = lt; \ + fputc((unsigned short)pom&0xff,sample[0]); \ + fputc(((unsigned short)pom>>8)&0xff,sample[0]); \ + pom = rt; \ + fputc((unsigned short)pom&0xff,sample[0]); \ + fputc(((unsigned short)pom>>8)&0xff,sample[0]); \ + } + #endif +#endif + + +/* struct describing a single operator (SLOT) */ +struct fm2612_FM_SLOT +{ + INT32 *DT; /* detune :dt_tab[DT] */ + UINT8 KSR; /* key scale rate :3-KSR */ + UINT32 ar; /* attack rate */ + UINT32 d1r; /* decay rate */ + UINT32 d2r; /* sustain rate */ + UINT32 rr; /* release rate */ + UINT8 ksr; /* key scale rate :kcode>>(3-KSR) */ + UINT32 mul; /* multiple :ML_TABLE[ML] */ + + /* Phase Generator */ + UINT32 phase; /* phase counter */ + INT32 Incr; /* phase step */ + + /* Envelope Generator */ + UINT8 state; /* phase type */ + UINT32 tl; /* total level: TL << 3 */ + INT32 volume; /* envelope counter */ + UINT32 sl; /* sustain level:sl_table[SL] */ + UINT32 vol_out; /* current output from EG circuit (without AM from LFO) */ + + UINT8 eg_sh_ar; /* (attack state) */ + UINT8 eg_sel_ar; /* (attack state) */ + UINT8 eg_sh_d1r; /* (decay state) */ + UINT8 eg_sel_d1r; /* (decay state) */ + UINT8 eg_sh_d2r; /* (sustain state) */ + UINT8 eg_sel_d2r; /* (sustain state) */ + UINT8 eg_sh_rr; /* (release state) */ + UINT8 eg_sel_rr; /* (release state) */ + + UINT8 ssg; /* SSG-EG waveform */ + UINT8 ssgn; /* SSG-EG negated output */ + + UINT8 key; /* 0=last key was KEY OFF, 1=KEY ON */ + + /* LFO */ + UINT32 AMmask; /* AM enable flag */ + +}; + +struct fm2612_FM_CH +{ + fm2612_FM_SLOT SLOT[4]; /* four SLOTs (operators) */ + + UINT8 ALGO; /* algorithm */ + UINT8 FB; /* feedback shift */ + INT32 op1_out[2]; /* op1 output for feedback */ + + INT32 *connect1; /* SLOT1 output pointer */ + INT32 *connect3; /* SLOT3 output pointer */ + INT32 *connect2; /* SLOT2 output pointer */ + INT32 *connect4; /* SLOT4 output pointer */ + + INT32 *mem_connect;/* where to put the delayed sample (MEM) */ + INT32 mem_value; /* delayed sample (MEM) value */ + + INT32 pms; /* channel PMS */ + UINT8 ams; /* channel AMS */ + + UINT32 fc; /* fnum,blk:adjusted to sample rate */ + UINT8 kcode; /* key code: */ + UINT32 block_fnum; /* current blk/fnum value for this slot (can be different betweeen slots of one channel in 3slot mode) */ +}; + + +struct fm2612_FM_ST +{ + device_t *device; + void * param; /* this chip parameter */ + double freqbase; /* frequency base */ + int timer_prescaler; /* timer prescaler */ + UINT8 irq; /* interrupt level */ + UINT8 irqmask; /* irq mask */ +#if FM_BUSY_FLAG_SUPPORT + TIME_TYPE busy_expiry_time; /* expiry time of the busy status */ +#endif + UINT32 clock; /* master clock (Hz) */ + UINT32 rate; /* sampling rate (Hz) */ + UINT16 address; /* address register */ + UINT8 status; /* status flag */ + UINT32 mode; /* mode CSM / 3SLOT */ + UINT8 fn_h; /* freq latch */ + UINT8 prescaler_sel; /* prescaler selector */ + INT32 TA; /* timer a */ + INT32 TAC; /* timer a counter */ + UINT8 TB; /* timer b */ + INT32 TBC; /* timer b counter */ + /* local time tables */ + INT32 dt_tab[8][32]; /* DeTune table */ + /* Extention Timer and IRQ handler */ + FM_TIMERHANDLER timer_handler; + FM_IRQHANDLER IRQ_Handler; + const ssg_callbacks *SSG; +}; + + + +/***********************************************************/ +/* OPN unit */ +/***********************************************************/ + +/* OPN 3slot struct */ +struct fm2612_FM_3SLOT +{ + UINT32 fc[3]; /* fnum3,blk3: calculated */ + UINT8 fn_h; /* freq3 latch */ + UINT8 kcode[3]; /* key code */ + UINT32 block_fnum[3]; /* current fnum value for this slot (can be different betweeen slots of one channel in 3slot mode) */ + UINT8 key_csm; /* CSM mode Key-ON flag */ +}; + +/* OPN/A/B common state */ +struct fm2612_FM_OPN +{ + UINT8 type; /* chip type */ + fm2612_FM_ST ST; /* general state */ + fm2612_FM_3SLOT SL3; /* 3 slot mode state */ + fm2612_FM_CH *P_CH; /* pointer of CH */ + unsigned int pan[6*2]; /* fm channels output masks (0xffffffff = enable) */ + + UINT32 eg_cnt; /* global envelope generator counter */ + UINT32 eg_timer; /* global envelope generator counter works at frequency = chipclock/144/3 */ + UINT32 eg_timer_add; /* step of eg_timer */ + UINT32 eg_timer_overflow;/* envelope generator timer overlfows every 3 samples (on real chip) */ + + + /* there are 2048 FNUMs that can be generated using FNUM/BLK registers + but LFO works with one more bit of a precision so we really need 4096 elements */ + UINT32 fn_table[4096]; /* fnumber->increment counter */ + UINT32 fn_max; /* maximal phase increment (used for phase overflow) */ + + /* LFO */ + UINT8 lfo_cnt; /* current LFO phase (out of 128) */ + UINT32 lfo_timer; /* current LFO phase runs at LFO frequency */ + UINT32 lfo_timer_add; /* step of lfo_timer */ + UINT32 lfo_timer_overflow; /* LFO timer overflows every N samples (depends on LFO frequency) */ + UINT32 LFO_AM; /* current LFO AM step */ + UINT32 LFO_PM; /* current LFO PM step */ + + INT32 m2,c1,c2; /* Phase Modulation input for operators 2,3,4 */ + INT32 mem; /* one sample delay memory */ + INT32 out_fm[8]; /* outputs of working channels */ + +}; + +/* here's the virtual YM2612 */ +struct YM2612 +{ + UINT8 REGS[512]; /* registers */ + fm2612_FM_OPN OPN; /* OPN state */ + fm2612_FM_CH CH[6]; /* channel state */ + UINT8 addr_A1; /* address line A1 */ + + /* dac output (YM2612) */ + int dacen; + INT32 dacout; +}; + +/* log output level */ +#define LOG_ERR 3 /* ERROR */ +#define LOG_WAR 2 /* WARNING */ +#define LOG_INF 1 /* INFORMATION */ +#define LOG_LEVEL LOG_INF + +#ifndef __RAINE__ +#define LOG(n,x) do { if( (n)>=LOG_LEVEL ) logerror x; } while (0) +#endif + +/* limitter */ +#define Limit(val, max,min) { \ + if ( val > max ) val = max; \ + else if ( val < min ) val = min; \ +} + + +/* status set and IRQ handling */ +INLINE void FM_STATUS_SET(fm2612_FM_ST *ST,int flag) +{ + /* set status flag */ + ST->status |= flag; + if ( !(ST->irq) && (ST->status & ST->irqmask) ) + { + ST->irq = 1; + /* callback user interrupt handler (IRQ is OFF to ON) */ + if(ST->IRQ_Handler) (ST->IRQ_Handler)(ST->param,1); + } +} + +/* status reset and IRQ handling */ +INLINE void FM_STATUS_RESET(fm2612_FM_ST *ST,int flag) +{ + /* reset status flag */ + ST->status &=~flag; + if ( (ST->irq) && !(ST->status & ST->irqmask) ) + { + ST->irq = 0; + /* callback user interrupt handler (IRQ is ON to OFF) */ + if(ST->IRQ_Handler) (ST->IRQ_Handler)(ST->param,0); + } +} + +/* IRQ mask set */ +INLINE void FM_IRQMASK_SET(fm2612_FM_ST *ST,int flag) +{ + ST->irqmask = flag; + /* IRQ handling check */ + FM_STATUS_SET(ST,0); + FM_STATUS_RESET(ST,0); +} + +INLINE void FM_KEYON(fm2612_FM_OPN *OPN, fm2612_FM_CH *CH , int s ) +{ + fm2612_FM_SLOT *SLOT = &CH->SLOT[s]; + + if( !SLOT->key && !OPN->SL3.key_csm) + { + /* restart Phase Generator */ + SLOT->phase = 0; + + /* reset SSG-EG inversion flag */ + SLOT->ssgn = 0; + + if ((SLOT->ar + SLOT->ksr) < 94 /*32+62*/) + { + SLOT->state = (SLOT->volume <= MIN_ATT_INDEX) ? ((SLOT->sl == MIN_ATT_INDEX) ? EG_SUS : EG_DEC) : EG_ATT; + } + else + { + /* force attenuation level to 0 */ + SLOT->volume = MIN_ATT_INDEX; + + /* directly switch to Decay (or Sustain) */ + SLOT->state = (SLOT->sl == MIN_ATT_INDEX) ? EG_SUS : EG_DEC; + } + + /* recalculate EG output */ + if ((SLOT->ssg&0x08) && (SLOT->ssgn ^ (SLOT->ssg&0x04))) + SLOT->vol_out = ((UINT32)(0x200 - SLOT->volume) & MAX_ATT_INDEX) + SLOT->tl; + else + SLOT->vol_out = (UINT32)SLOT->volume + SLOT->tl; + } + + SLOT->key = 1; +} + +INLINE void FM_KEYOFF(fm2612_FM_OPN *OPN, fm2612_FM_CH *CH , int s ) +{ + fm2612_FM_SLOT *SLOT = &CH->SLOT[s]; + + if (SLOT->key && !OPN->SL3.key_csm) + { + if (SLOT->state>EG_REL) + { + SLOT->state = EG_REL; /* phase -> Release */ + + /* SSG-EG specific update */ + if (SLOT->ssg&0x08) + { + /* convert EG attenuation level */ + if (SLOT->ssgn ^ (SLOT->ssg&0x04)) + SLOT->volume = (0x200 - SLOT->volume); + + /* force EG attenuation level */ + if (SLOT->volume >= 0x200) + { + SLOT->volume = MAX_ATT_INDEX; + SLOT->state = EG_OFF; + } + + /* recalculate EG output */ + SLOT->vol_out = (UINT32)SLOT->volume + SLOT->tl; + } + } + } + + SLOT->key = 0; +} + +INLINE void FM_KEYON_CSM(fm2612_FM_OPN *OPN, fm2612_FM_CH *CH , int s ) +{ + fm2612_FM_SLOT *SLOT = &CH->SLOT[s]; + + if( !SLOT->key && !OPN->SL3.key_csm) + { + /* restart Phase Generator */ + SLOT->phase = 0; + + /* reset SSG-EG inversion flag */ + SLOT->ssgn = 0; + + if ((SLOT->ar + SLOT->ksr) < 94 /*32+62*/) + { + SLOT->state = (SLOT->volume <= MIN_ATT_INDEX) ? ((SLOT->sl == MIN_ATT_INDEX) ? EG_SUS : EG_DEC) : EG_ATT; + } + else + { + /* force attenuation level to 0 */ + SLOT->volume = MIN_ATT_INDEX; + + /* directly switch to Decay (or Sustain) */ + SLOT->state = (SLOT->sl == MIN_ATT_INDEX) ? EG_SUS : EG_DEC; + } + + /* recalculate EG output */ + if ((SLOT->ssg&0x08) && (SLOT->ssgn ^ (SLOT->ssg&0x04))) + SLOT->vol_out = ((UINT32)(0x200 - SLOT->volume) & MAX_ATT_INDEX) + SLOT->tl; + else + SLOT->vol_out = (UINT32)SLOT->volume + SLOT->tl; + } +} + +INLINE void FM_KEYOFF_CSM(fm2612_FM_CH *CH , int s ) +{ + fm2612_FM_SLOT *SLOT = &CH->SLOT[s]; + if (!SLOT->key) + { + if (SLOT->state>EG_REL) + { + SLOT->state = EG_REL; /* phase -> Release */ + + /* SSG-EG specific update */ + if (SLOT->ssg&0x08) + { + /* convert EG attenuation level */ + if (SLOT->ssgn ^ (SLOT->ssg&0x04)) + SLOT->volume = (0x200 - SLOT->volume); + + /* force EG attenuation level */ + if (SLOT->volume >= 0x200) + { + SLOT->volume = MAX_ATT_INDEX; + SLOT->state = EG_OFF; + } + + /* recalculate EG output */ + SLOT->vol_out = (UINT32)SLOT->volume + SLOT->tl; + } + } + } +} + +/* OPN Mode Register Write */ +INLINE void set_timers(fm2612_FM_OPN *OPN, fm2612_FM_ST *ST, void *n, int v) +{ + /* b7 = CSM MODE */ + /* b6 = 3 slot mode */ + /* b5 = reset b */ + /* b4 = reset a */ + /* b3 = timer enable b */ + /* b2 = timer enable a */ + /* b1 = load b */ + /* b0 = load a */ + + if ((OPN->ST.mode ^ v) & 0xC0) + { + /* phase increment need to be recalculated */ + OPN->P_CH[2].SLOT[SLOT1].Incr=-1; + + /* CSM mode disabled and CSM key ON active*/ + if (((v & 0xC0) != 0x80) && OPN->SL3.key_csm) + { + /* CSM Mode Key OFF (verified by Nemesis on real hardware) */ + FM_KEYOFF_CSM(&OPN->P_CH[2],SLOT1); + FM_KEYOFF_CSM(&OPN->P_CH[2],SLOT2); + FM_KEYOFF_CSM(&OPN->P_CH[2],SLOT3); + FM_KEYOFF_CSM(&OPN->P_CH[2],SLOT4); + OPN->SL3.key_csm = 0; + } + } + + /* reload Timers */ + if ((v&1) && !(ST->mode&1)) + { + ST->TAC = (1024-ST->TA); + /* External timer handler */ + if (ST->timer_handler) (ST->timer_handler)(n,0,ST->TAC * ST->timer_prescaler,ST->clock); + } + else if (!(v & 1)) + { + if( ST->TAC != 0 ) + { + ST->TAC = 0; + if (ST->timer_handler) (ST->timer_handler)(n,0,0,ST->clock); + } + } + + if ((v&2) && !(ST->mode&2)) + { + ST->TBC = ( 256-ST->TB)<<4; + /* External timer handler */ + if (ST->timer_handler) (ST->timer_handler)(n,1,ST->TBC * ST->timer_prescaler,ST->clock); + } + else if (!(v & 2)) + { + if( ST->TBC != 0 ) + { + ST->TBC = 0; + if (ST->timer_handler) (ST->timer_handler)(n,1,0,ST->clock); + } + } + + /* reset Timers flags */ + ST->status &= (~v >> 4); + + /* if IRQ should be lowered now, do so */ + if ( (ST->irq) && !(ST->status & ST->irqmask) ) + { + ST->irq = 0; + /* callback user interrupt handler (IRQ is ON to OFF) */ + if(ST->IRQ_Handler) (ST->IRQ_Handler)(ST->param, 0); + } + ST->mode = v; +} + + +/* Timer A Overflow */ +INLINE void TimerAOver(fm2612_FM_ST *ST) +{ + /* set status (if enabled) */ + if(ST->mode & 0x04) FM_STATUS_SET(ST,0x01); + /* clear or reload the counter */ + ST->TAC = (1024-ST->TA); + if (ST->timer_handler) (ST->timer_handler)(ST->param,0,ST->TAC * ST->timer_prescaler,ST->clock); +} +/* Timer B Overflow */ +INLINE void TimerBOver(fm2612_FM_ST *ST) +{ + /* set status (if enabled) */ + if(ST->mode & 0x08) FM_STATUS_SET(ST,0x02); + /* clear or reload the counter */ + ST->TBC = ( 256-ST->TB)<<4; + if (ST->timer_handler) (ST->timer_handler)(ST->param,1,ST->TBC * ST->timer_prescaler,ST->clock); +} + + +#if FM_INTERNAL_TIMER +/* ----- internal timer mode , update timer */ + +/* ---------- calculate timer A ---------- */ + #define INTERNAL_TIMER_A(ST,CSM_CH) \ + { \ + if( ST->TAC && (ST->timer_handler==0) ) \ + if( (ST->TAC -= (int)(ST->freqbase*4096)) <= 0 ) \ + { \ + TimerAOver( ST ); \ + /* CSM mode total level latch and auto key on */ \ + if( ST->mode & 0x80 ) \ + CSMKeyControll( CSM_CH ); \ + } \ + } +/* ---------- calculate timer B ---------- */ + #define INTERNAL_TIMER_B(ST,step) \ + { \ + if( ST->TBC && (ST->timer_handler==0) ) \ + if( (ST->TBC -= (int)(ST->freqbase*4096*step)) <= 0 ) \ + TimerBOver( ST ); \ + } +#else /* FM_INTERNAL_TIMER */ +/* external timer mode */ +#define INTERNAL_TIMER_A(ST,CSM_CH) +#define INTERNAL_TIMER_B(ST,step) +#endif /* FM_INTERNAL_TIMER */ + + + +#if FM_BUSY_FLAG_SUPPORT +#define FM_BUSY_CLEAR(ST) ((ST)->busy_expiry_time = UNDEFINED_TIME) +INLINE UINT8 FM_STATUS_FLAG(fm2612_FM_ST *ST) +{ + if( COMPARE_TIMES(ST->busy_expiry_time, UNDEFINED_TIME) != 0 ) + { + if (COMPARE_TIMES(ST->busy_expiry_time, FM_GET_TIME_NOW(&ST->device->machine())) > 0) + return ST->status | 0x80; /* with busy */ + /* expire */ + FM_BUSY_CLEAR(ST); + } + return ST->status; +} +#if 0 +INLINE void FM_BUSY_SET(fm2612_FM_ST *ST,int busyclock ) +{ + TIME_TYPE expiry_period = MULTIPLY_TIME_BY_INT(attotime::from_hz(ST->clock), busyclock * ST->timer_prescaler); + ST->busy_expiry_time = ADD_TIMES(FM_GET_TIME_NOW(&ST->device->machine()), expiry_period); +} +#endif +#else +#define FM_STATUS_FLAG(ST) ((ST)->status) +#define FM_BUSY_SET(ST,bclock) {} +#define FM_BUSY_CLEAR(ST) {} +#endif + + +/* set algorithm connection */ +static void setup_connection(fm2612_FM_OPN *OPN, fm2612_FM_CH *CH, int ch) +{ + INT32 *carrier = &OPN->out_fm[ch]; + + INT32 **om1 = &CH->connect1; + INT32 **om2 = &CH->connect3; + INT32 **oc1 = &CH->connect2; + + INT32 **memc = &CH->mem_connect; + + switch( CH->ALGO ) + { + case 0: + /* M1---C1---MEM---M2---C2---OUT */ + *om1 = &OPN->c1; + *oc1 = &OPN->mem; + *om2 = &OPN->c2; + *memc= &OPN->m2; + break; + case 1: + /* M1------+-MEM---M2---C2---OUT */ + /* C1-+ */ + *om1 = &OPN->mem; + *oc1 = &OPN->mem; + *om2 = &OPN->c2; + *memc= &OPN->m2; + break; + case 2: + /* M1-----------------+-C2---OUT */ + /* C1---MEM---M2-+ */ + *om1 = &OPN->c2; + *oc1 = &OPN->mem; + *om2 = &OPN->c2; + *memc= &OPN->m2; + break; + case 3: + /* M1---C1---MEM------+-C2---OUT */ + /* M2-+ */ + *om1 = &OPN->c1; + *oc1 = &OPN->mem; + *om2 = &OPN->c2; + *memc= &OPN->c2; + break; + case 4: + /* M1---C1-+-OUT */ + /* M2---C2-+ */ + /* MEM: not used */ + *om1 = &OPN->c1; + *oc1 = carrier; + *om2 = &OPN->c2; + *memc= &OPN->mem; /* store it anywhere where it will not be used */ + break; + case 5: + /* +----C1----+ */ + /* M1-+-MEM---M2-+-OUT */ + /* +----C2----+ */ + *om1 = 0; /* special mark */ + *oc1 = carrier; + *om2 = carrier; + *memc= &OPN->m2; + break; + case 6: + /* M1---C1-+ */ + /* M2-+-OUT */ + /* C2-+ */ + /* MEM: not used */ + *om1 = &OPN->c1; + *oc1 = carrier; + *om2 = carrier; + *memc= &OPN->mem; /* store it anywhere where it will not be used */ + break; + case 7: + /* M1-+ */ + /* C1-+-OUT */ + /* M2-+ */ + /* C2-+ */ + /* MEM: not used*/ + *om1 = carrier; + *oc1 = carrier; + *om2 = carrier; + *memc= &OPN->mem; /* store it anywhere where it will not be used */ + break; + } + + CH->connect4 = carrier; +} + +/* set detune & multiple */ +INLINE void set_det_mul(fm2612_FM_ST *ST,fm2612_FM_CH *CH,fm2612_FM_SLOT *SLOT,int v) +{ + SLOT->mul = (v&0x0f)? (v&0x0f)*2 : 1; + SLOT->DT = ST->dt_tab[(v>>4)&7]; + CH->SLOT[SLOT1].Incr=-1; +} + +/* set total level */ +INLINE void set_tl(fm2612_FM_CH *CH,fm2612_FM_SLOT *SLOT , int v) +{ + SLOT->tl = (v&0x7f)<<(ENV_BITS-7); /* 7bit TL */ + + /* recalculate EG output */ + if ((SLOT->ssg&0x08) && (SLOT->ssgn ^ (SLOT->ssg&0x04)) && (SLOT->state > EG_REL)) + SLOT->vol_out = ((UINT32)(0x200 - SLOT->volume) & MAX_ATT_INDEX) + SLOT->tl; + else + SLOT->vol_out = (UINT32)SLOT->volume + SLOT->tl; +} + +/* set attack rate & key scale */ +INLINE void set_ar_ksr(UINT8 type, fm2612_FM_CH *CH,fm2612_FM_SLOT *SLOT,int v) +{ + UINT8 old_KSR = SLOT->KSR; + + SLOT->ar = (v&0x1f) ? 32 + ((v&0x1f)<<1) : 0; + + SLOT->KSR = 3-(v>>6); + if (SLOT->KSR != old_KSR) + { + CH->SLOT[SLOT1].Incr=-1; + } + + /* Even if it seems unnecessary, in some odd case, KSR and KC are modified */ + /* and could result in SLOT->kc remaining unchanged. */ + /* In such case, AR values would not be recalculated despite SLOT->ar has changed */ + /* This actually fixes the intro of "The Adventures of Batman & Robin" (Eke-Eke) */ + if ((SLOT->ar + SLOT->ksr) < 94 /*32+62*/) + { + SLOT->eg_sh_ar = eg_rate_shift [SLOT->ar + SLOT->ksr ]; + SLOT->eg_sel_ar = eg_rate_select2612[SLOT->ar + SLOT->ksr ]; + } + else + { + SLOT->eg_sh_ar = 0; + SLOT->eg_sel_ar = 18*RATE_STEPS; /* verified by Nemesis on real hardware */ + } +} + +/* set decay rate */ +INLINE void set_dr(UINT8 type, fm2612_FM_SLOT *SLOT,int v) +{ + SLOT->d1r = (v&0x1f) ? 32 + ((v&0x1f)<<1) : 0; + + SLOT->eg_sh_d1r = eg_rate_shift [SLOT->d1r + SLOT->ksr]; + SLOT->eg_sel_d1r= eg_rate_select2612[SLOT->d1r + SLOT->ksr]; +} + +/* set sustain rate */ +INLINE void set_sr(UINT8 type, fm2612_FM_SLOT *SLOT,int v) +{ + SLOT->d2r = (v&0x1f) ? 32 + ((v&0x1f)<<1) : 0; + + SLOT->eg_sh_d2r = eg_rate_shift [SLOT->d2r + SLOT->ksr]; + SLOT->eg_sel_d2r= eg_rate_select2612[SLOT->d2r + SLOT->ksr]; +} + +/* set release rate */ +INLINE void set_sl_rr(UINT8 type, fm2612_FM_SLOT *SLOT,int v) +{ + SLOT->sl = sl_table[ v>>4 ]; + + /* check EG state changes */ + if ((SLOT->state == EG_DEC) && (SLOT->volume >= (INT32)(SLOT->sl))) + SLOT->state = EG_SUS; + + SLOT->rr = 34 + ((v&0x0f)<<2); + + SLOT->eg_sh_rr = eg_rate_shift [SLOT->rr + SLOT->ksr]; + SLOT->eg_sel_rr = eg_rate_select2612[SLOT->rr + SLOT->ksr]; +} + +/* advance LFO to next sample */ +INLINE void advance_lfo(fm2612_FM_OPN *OPN) +{ + if (OPN->lfo_timer_overflow) /* LFO enabled ? */ + { + /* increment LFO timer */ + OPN->lfo_timer += OPN->lfo_timer_add; + + /* when LFO is enabled, one level will last for 108, 77, 71, 67, 62, 44, 8 or 5 samples */ + while (OPN->lfo_timer >= OPN->lfo_timer_overflow) + { + OPN->lfo_timer -= OPN->lfo_timer_overflow; + + /* There are 128 LFO steps */ + OPN->lfo_cnt = ( OPN->lfo_cnt + 1 ) & 127; + + /* triangle (inverted) */ + /* AM: from 126 to 0 step -2, 0 to 126 step +2 */ + if (OPN->lfo_cnt<64) + OPN->LFO_AM = (OPN->lfo_cnt ^ 63) << 1; + else + OPN->LFO_AM = (OPN->lfo_cnt & 63) << 1; + + /* PM works with 4 times slower clock */ + OPN->LFO_PM = OPN->lfo_cnt >> 2; + } + } +} + +/* changed from INLINE to static here to work around gcc 4.2.1 codegen bug */ +static void advance_eg_channel(fm2612_FM_OPN *OPN, fm2612_FM_SLOT *SLOT) +{ + unsigned int out; + unsigned int i = 4; /* four operators per channel */ + + do + { + switch(SLOT->state) + { + case EG_ATT: /* attack phase */ + if (!(OPN->eg_cnt & ((1<eg_sh_ar)-1))) + { + /* update attenuation level */ + SLOT->volume += (~SLOT->volume * (eg_inc[SLOT->eg_sel_ar + ((OPN->eg_cnt>>SLOT->eg_sh_ar)&7)]))>>4; + + /* check phase transition*/ + if (SLOT->volume <= MIN_ATT_INDEX) + { + SLOT->volume = MIN_ATT_INDEX; + SLOT->state = (SLOT->sl == MIN_ATT_INDEX) ? EG_SUS : EG_DEC; /* special case where SL=0 */ + } + + /* recalculate EG output */ + if ((SLOT->ssg&0x08) && (SLOT->ssgn ^ (SLOT->ssg&0x04))) /* SSG-EG Output Inversion */ + SLOT->vol_out = ((UINT32)(0x200 - SLOT->volume) & MAX_ATT_INDEX) + SLOT->tl; + else + SLOT->vol_out = (UINT32)SLOT->volume + SLOT->tl; + } + break; + + case EG_DEC: /* decay phase */ + if (!(OPN->eg_cnt & ((1<eg_sh_d1r)-1))) + { + /* SSG EG type */ + if (SLOT->ssg&0x08) + { + /* update attenuation level */ + if (SLOT->volume < 0x200) + { + SLOT->volume += 4 * eg_inc[SLOT->eg_sel_d1r + ((OPN->eg_cnt>>SLOT->eg_sh_d1r)&7)]; + + /* recalculate EG output */ + if (SLOT->ssgn ^ (SLOT->ssg&0x04)) /* SSG-EG Output Inversion */ + SLOT->vol_out = ((UINT32)(0x200 - SLOT->volume) & MAX_ATT_INDEX) + SLOT->tl; + else + SLOT->vol_out = (UINT32)SLOT->volume + SLOT->tl; + } + + } + else + { + /* update attenuation level */ + SLOT->volume += eg_inc[SLOT->eg_sel_d1r + ((OPN->eg_cnt>>SLOT->eg_sh_d1r)&7)]; + + /* recalculate EG output */ + SLOT->vol_out = (UINT32)SLOT->volume + SLOT->tl; + } + + /* check phase transition*/ + if (SLOT->volume >= (INT32)(SLOT->sl)) + SLOT->state = EG_SUS; + } + break; + + case EG_SUS: /* sustain phase */ + if (!(OPN->eg_cnt & ((1<eg_sh_d2r)-1))) + { + /* SSG EG type */ + if (SLOT->ssg&0x08) + { + /* update attenuation level */ + if (SLOT->volume < 0x200) + { + SLOT->volume += 4 * eg_inc[SLOT->eg_sel_d2r + ((OPN->eg_cnt>>SLOT->eg_sh_d2r)&7)]; + + /* recalculate EG output */ + if (SLOT->ssgn ^ (SLOT->ssg&0x04)) /* SSG-EG Output Inversion */ + SLOT->vol_out = ((UINT32)(0x200 - SLOT->volume) & MAX_ATT_INDEX) + SLOT->tl; + else + SLOT->vol_out = (UINT32)SLOT->volume + SLOT->tl; + } + } + else + { + /* update attenuation level */ + SLOT->volume += eg_inc[SLOT->eg_sel_d2r + ((OPN->eg_cnt>>SLOT->eg_sh_d2r)&7)]; + + /* check phase transition*/ + if ( SLOT->volume >= MAX_ATT_INDEX ) + SLOT->volume = MAX_ATT_INDEX; + /* do not change SLOT->state (verified on real chip) */ + + /* recalculate EG output */ + SLOT->vol_out = (UINT32)SLOT->volume + SLOT->tl; + } + } + break; + + case EG_REL: /* release phase */ + if (!(OPN->eg_cnt & ((1<eg_sh_rr)-1))) + { + /* SSG EG type */ + if (SLOT->ssg&0x08) + { + /* update attenuation level */ + if (SLOT->volume < 0x200) + SLOT->volume += 4 * eg_inc[SLOT->eg_sel_rr + ((OPN->eg_cnt>>SLOT->eg_sh_rr)&7)]; + /* check phase transition */ + if (SLOT->volume >= 0x200) + { + SLOT->volume = MAX_ATT_INDEX; + SLOT->state = EG_OFF; + } + } + else + { + /* update attenuation level */ + SLOT->volume += eg_inc[SLOT->eg_sel_rr + ((OPN->eg_cnt>>SLOT->eg_sh_rr)&7)]; + + /* check phase transition*/ + if (SLOT->volume >= MAX_ATT_INDEX) + { + SLOT->volume = MAX_ATT_INDEX; + SLOT->state = EG_OFF; + } + } + + /* recalculate EG output */ + SLOT->vol_out = (UINT32)SLOT->volume + SLOT->tl; + + } + break; + } + + out = ((UINT32)SLOT->volume); + + /* negate output (changes come from alternate bit, init comes from attack bit) */ + if ((SLOT->ssg&0x08) && (SLOT->ssgn&2) && (SLOT->state > EG_REL)) + out ^= MAX_ATT_INDEX; + + /* we need to store the result here because we are going to change ssgn + in next instruction */ + SLOT->vol_out = out + SLOT->tl; + + SLOT++; + i--; + }while (i); + +} + +/* SSG-EG update process */ +/* The behavior is based upon Nemesis tests on real hardware */ +/* This is actually executed before each samples */ +static void update_ssg_eg_channel(fm2612_FM_SLOT *SLOT) +{ + unsigned int i = 4; /* four operators per channel */ + + do + { + /* detect SSG-EG transition */ + /* this is not required during release phase as the attenuation has been forced to MAX and output invert flag is not used */ + /* if an Attack Phase is programmed, inversion can occur on each sample */ + if ((SLOT->ssg & 0x08) && (SLOT->volume >= 0x200) && (SLOT->state > EG_REL)) + { + if (SLOT->ssg & 0x01) /* bit 0 = hold SSG-EG */ + { + /* set inversion flag */ + if (SLOT->ssg & 0x02) + SLOT->ssgn = 4; + + /* force attenuation level during decay phases */ + if ((SLOT->state != EG_ATT) && !(SLOT->ssgn ^ (SLOT->ssg & 0x04))) + SLOT->volume = MAX_ATT_INDEX; + } + else /* loop SSG-EG */ + { + /* toggle output inversion flag or reset Phase Generator */ + if (SLOT->ssg & 0x02) + SLOT->ssgn ^= 4; + else + SLOT->phase = 0; + + /* same as Key ON */ + if (SLOT->state != EG_ATT) + { + if ((SLOT->ar + SLOT->ksr) < 94 /*32+62*/) + { + SLOT->state = (SLOT->volume <= MIN_ATT_INDEX) ? ((SLOT->sl == MIN_ATT_INDEX) ? EG_SUS : EG_DEC) : EG_ATT; + } + else + { + /* Attack Rate is maximal: directly switch to Decay or Substain */ + SLOT->volume = MIN_ATT_INDEX; + SLOT->state = (SLOT->sl == MIN_ATT_INDEX) ? EG_SUS : EG_DEC; + } + } + } + + /* recalculate EG output */ + if (SLOT->ssgn ^ (SLOT->ssg&0x04)) + SLOT->vol_out = ((UINT32)(0x200 - SLOT->volume) & MAX_ATT_INDEX) + SLOT->tl; + else + SLOT->vol_out = (UINT32)SLOT->volume + SLOT->tl; + } + + /* next slot */ + SLOT++; + i--; + } while (i); +} + + +INLINE void update_phase_lfo_slot(fm2612_FM_OPN *OPN, fm2612_FM_SLOT *SLOT, INT32 pms, UINT32 block_fnum) +{ + UINT32 fnum_lfo = ((block_fnum & 0x7f0) >> 4) * 32 * 8; + INT32 lfo_fn_table_index_offset = lfo_pm_table[ fnum_lfo + pms + OPN->LFO_PM ]; + + block_fnum = block_fnum*2 + lfo_fn_table_index_offset; + + if (lfo_fn_table_index_offset) /* LFO phase modulation active */ + { + UINT8 blk = (block_fnum&0x7000) >> 12; + UINT32 fn = block_fnum & 0xfff; + + /* recalculate keyscale code */ + int kc = (blk<<2) | opn_fktable[(fn >> 7) & 0xf]; + + /* recalculate (frequency) phase increment counter */ + int fc = (OPN->fn_table[fn]>>(7-blk)) + SLOT->DT[kc]; + + /* (frequency) phase overflow (credits to Nemesis) */ + if (fc < 0) fc += OPN->fn_max; + + /* update phase */ + SLOT->phase += (fc * SLOT->mul) >> 1; + } + else /* LFO phase modulation = zero */ + { + SLOT->phase += SLOT->Incr; + } +} + +INLINE void update_phase_lfo_channel(fm2612_FM_OPN *OPN, fm2612_FM_CH *CH) +{ + UINT32 block_fnum = CH->block_fnum; + + UINT32 fnum_lfo = ((block_fnum & 0x7f0) >> 4) * 32 * 8; + INT32 lfo_fn_table_index_offset = lfo_pm_table[ fnum_lfo + CH->pms + OPN->LFO_PM ]; + + block_fnum = block_fnum*2 + lfo_fn_table_index_offset; + + if (lfo_fn_table_index_offset) /* LFO phase modulation active */ + { + UINT8 blk = (block_fnum&0x7000) >> 12; + UINT32 fn = block_fnum & 0xfff; + + /* recalculate keyscale code */ + int kc = (blk<<2) | opn_fktable[(fn >> 7) & 0xf]; + + /* recalculate (frequency) phase increment counter */ + int fc = (OPN->fn_table[fn]>>(7-blk)); + + /* (frequency) phase overflow (credits to Nemesis) */ + int finc = fc + CH->SLOT[SLOT1].DT[kc]; + if (finc < 0) finc += OPN->fn_max; + CH->SLOT[SLOT1].phase += (finc*CH->SLOT[SLOT1].mul) >> 1; + + finc = fc + CH->SLOT[SLOT2].DT[kc]; + if (finc < 0) finc += OPN->fn_max; + CH->SLOT[SLOT2].phase += (finc*CH->SLOT[SLOT2].mul) >> 1; + + finc = fc + CH->SLOT[SLOT3].DT[kc]; + if (finc < 0) finc += OPN->fn_max; + CH->SLOT[SLOT3].phase += (finc*CH->SLOT[SLOT3].mul) >> 1; + + finc = fc + CH->SLOT[SLOT4].DT[kc]; + if (finc < 0) finc += OPN->fn_max; + CH->SLOT[SLOT4].phase += (finc*CH->SLOT[SLOT4].mul) >> 1; + } + else /* LFO phase modulation = zero */ + { + CH->SLOT[SLOT1].phase += CH->SLOT[SLOT1].Incr; + CH->SLOT[SLOT2].phase += CH->SLOT[SLOT2].Incr; + CH->SLOT[SLOT3].phase += CH->SLOT[SLOT3].Incr; + CH->SLOT[SLOT4].phase += CH->SLOT[SLOT4].Incr; + } +} + +/* update phase increment and envelope generator */ +INLINE void refresh_fc_eg_slot(fm2612_FM_OPN *OPN, fm2612_FM_SLOT *SLOT , int fc , int kc ) +{ + int ksr = kc >> SLOT->KSR; + + fc += SLOT->DT[kc]; + + /* detects frequency overflow (credits to Nemesis) */ + if (fc < 0) fc += OPN->fn_max; + + /* (frequency) phase increment counter */ + SLOT->Incr = (fc * SLOT->mul) >> 1; + + if( SLOT->ksr != ksr ) + { + SLOT->ksr = ksr; + + /* calculate envelope generator rates */ + if ((SLOT->ar + SLOT->ksr) < 32+62) + { + SLOT->eg_sh_ar = eg_rate_shift [SLOT->ar + SLOT->ksr ]; + SLOT->eg_sel_ar = eg_rate_select2612[SLOT->ar + SLOT->ksr ]; + } + else + { + SLOT->eg_sh_ar = 0; + SLOT->eg_sel_ar = 18*RATE_STEPS; /* verified by Nemesis on real hardware (Attack phase is blocked) */ + } + + SLOT->eg_sh_d1r = eg_rate_shift [SLOT->d1r + SLOT->ksr]; + SLOT->eg_sh_d2r = eg_rate_shift [SLOT->d2r + SLOT->ksr]; + SLOT->eg_sh_rr = eg_rate_shift [SLOT->rr + SLOT->ksr]; + + SLOT->eg_sel_d1r= eg_rate_select2612[SLOT->d1r + SLOT->ksr]; + SLOT->eg_sel_d2r= eg_rate_select2612[SLOT->d2r + SLOT->ksr]; + SLOT->eg_sel_rr = eg_rate_select2612[SLOT->rr + SLOT->ksr]; + } +} + +/* update phase increment counters */ +/* Changed from INLINE to static to work around gcc 4.2.1 codegen bug */ +static void refresh_fc_eg_chan(fm2612_FM_OPN *OPN, fm2612_FM_CH *CH ) +{ + if( CH->SLOT[SLOT1].Incr==-1) + { + int fc = CH->fc; + int kc = CH->kcode; + refresh_fc_eg_slot(OPN, &CH->SLOT[SLOT1] , fc , kc ); + refresh_fc_eg_slot(OPN, &CH->SLOT[SLOT2] , fc , kc ); + refresh_fc_eg_slot(OPN, &CH->SLOT[SLOT3] , fc , kc ); + refresh_fc_eg_slot(OPN, &CH->SLOT[SLOT4] , fc , kc ); + } +} + +#define volume_calc(OP) ((OP)->vol_out + (AM & (OP)->AMmask)) + +INLINE signed int op_calc(UINT32 phase, unsigned int env, signed int pm) +{ + UINT32 p; + + p = (env<<3) + sin_tab[ ( ((signed int)((phase & ~FREQ_MASK) + (pm<<15))) >> FREQ_SH ) & SIN_MASK ]; + + if (p >= TL_TAB_LEN) + return 0; + return tl_tab[p]; +} + +INLINE signed int op_calc1(UINT32 phase, unsigned int env, signed int pm) +{ + UINT32 p; + + p = (env<<3) + sin_tab[ ( ((signed int)((phase & ~FREQ_MASK) + pm )) >> FREQ_SH ) & SIN_MASK ]; + + if (p >= TL_TAB_LEN) + return 0; + return tl_tab[p]; +} + +INLINE void chan_calc(YM2612 *F2612, fm2612_FM_OPN *OPN, fm2612_FM_CH *CH) +{ + UINT32 AM = OPN->LFO_AM >> CH->ams; + unsigned int eg_out = volume_calc(&CH->SLOT[SLOT1]); + + OPN->m2 = OPN->c1 = OPN->c2 = OPN->mem = 0; + + *CH->mem_connect = CH->mem_value; /* restore delayed sample (MEM) value to m2 or c2 */ + + { + INT32 out = CH->op1_out[0] + CH->op1_out[1]; + CH->op1_out[0] = CH->op1_out[1]; + + if( !CH->connect1 ) + { + /* algorithm 5 */ + OPN->mem = OPN->c1 = OPN->c2 = CH->op1_out[0]; + } + else + { + /* other algorithms */ + *CH->connect1 += CH->op1_out[0]; + } + + + CH->op1_out[1] = 0; + if( eg_out < ENV_QUIET ) /* SLOT 1 */ + { + if (!CH->FB) + out=0; + + CH->op1_out[1] = op_calc1(CH->SLOT[SLOT1].phase, eg_out, (out<FB) ); + } + } + + eg_out = volume_calc(&CH->SLOT[SLOT3]); + if( eg_out < ENV_QUIET ) /* SLOT 3 */ + *CH->connect3 += op_calc(CH->SLOT[SLOT3].phase, eg_out, OPN->m2); + + eg_out = volume_calc(&CH->SLOT[SLOT2]); + if( eg_out < ENV_QUIET ) /* SLOT 2 */ + *CH->connect2 += op_calc(CH->SLOT[SLOT2].phase, eg_out, OPN->c1); + + eg_out = volume_calc(&CH->SLOT[SLOT4]); + if( eg_out < ENV_QUIET ) /* SLOT 4 */ + *CH->connect4 += op_calc(CH->SLOT[SLOT4].phase, eg_out, OPN->c2); + + + /* store current MEM */ + CH->mem_value = OPN->mem; + + /* update phase counters AFTER output calculations */ + if(CH->pms) + { + /* add support for 3 slot mode */ + if ((OPN->ST.mode & 0xC0) && (CH == &F2612->CH[2])) + { + update_phase_lfo_slot(OPN, &CH->SLOT[SLOT1], CH->pms, OPN->SL3.block_fnum[1]); + update_phase_lfo_slot(OPN, &CH->SLOT[SLOT2], CH->pms, OPN->SL3.block_fnum[2]); + update_phase_lfo_slot(OPN, &CH->SLOT[SLOT3], CH->pms, OPN->SL3.block_fnum[0]); + update_phase_lfo_slot(OPN, &CH->SLOT[SLOT4], CH->pms, CH->block_fnum); + } + else update_phase_lfo_channel(OPN, CH); + } + else /* no LFO phase modulation */ + { + CH->SLOT[SLOT1].phase += CH->SLOT[SLOT1].Incr; + CH->SLOT[SLOT2].phase += CH->SLOT[SLOT2].Incr; + CH->SLOT[SLOT3].phase += CH->SLOT[SLOT3].Incr; + CH->SLOT[SLOT4].phase += CH->SLOT[SLOT4].Incr; + } +} + +static void FMCloseTable( void ) +{ +#ifdef SAVE_SAMPLE + fclose(sample[0]); +#endif + return; +} + + +/* CSM Key Controll */ +INLINE void CSMKeyControll(fm2612_FM_OPN *OPN, fm2612_FM_CH *CH) +{ + /* all key ON (verified by Nemesis on real hardware) */ + FM_KEYON_CSM(OPN,CH,SLOT1); + FM_KEYON_CSM(OPN,CH,SLOT2); + FM_KEYON_CSM(OPN,CH,SLOT3); + FM_KEYON_CSM(OPN,CH,SLOT4); + OPN->SL3.key_csm = 1; +} + +#ifdef __SAVE_H__ +/* FM channel save , internal state only */ +static void FMsave_state_channel(device_t *device,fm2612_FM_CH *CH,int num_ch) +{ + int slot , ch; + + for(ch=0;chsave_item(NAME(CH->op1_out), ch); + device->save_item(NAME(CH->fc), ch); + /* slots */ + for(slot=0;slot<4;slot++) + { + fm2612_FM_SLOT *SLOT = &CH->SLOT[slot]; + device->save_item(NAME(SLOT->phase), ch * 4 + slot); + device->save_item(NAME(SLOT->state), ch * 4 + slot); + device->save_item(NAME(SLOT->volume), ch * 4 + slot); + } + } +} + +static void FMsave_state_st(device_t *device,fm2612_FM_ST *ST) +{ +#if FM_BUSY_FLAG_SUPPORT + device->save_item(NAME(ST->busy_expiry_time) ); +#endif + device->save_item(NAME(ST->address) ); + device->save_item(NAME(ST->irq) ); + device->save_item(NAME(ST->irqmask) ); + device->save_item(NAME(ST->status) ); + device->save_item(NAME(ST->mode) ); + device->save_item(NAME(ST->prescaler_sel) ); + device->save_item(NAME(ST->fn_h) ); + device->save_item(NAME(ST->TA) ); + device->save_item(NAME(ST->TAC) ); + device->save_item(NAME(ST->TB) ); + device->save_item(NAME(ST->TBC) ); +} +#endif /* _STATE_H */ + +#if BUILD_OPN +/* write a OPN mode register 0x20-0x2f */ +static void OPNWriteMode(fm2612_FM_OPN *OPN, int r, int v) +{ + UINT8 c; + fm2612_FM_CH *CH; + + switch(r) + { + case 0x21: /* Test */ + break; + case 0x22: /* LFO FREQ (YM2608/YM2610/YM2610B/YM2612) */ + if (v&8) /* LFO enabled ? */ + { + OPN->lfo_timer_overflow = lfo_samples_per_step[v&7] << LFO_SH; + } + else + { + /* hold LFO waveform in reset state */ + OPN->lfo_timer_overflow = 0; + OPN->lfo_timer = 0; + OPN->lfo_cnt = 0; + OPN->LFO_PM = 0; + OPN->LFO_AM = 126; + } + break; + case 0x24: /* timer A High 8*/ + OPN->ST.TA = (OPN->ST.TA & 0x03)|(((int)v)<<2); + break; + case 0x25: /* timer A Low 2*/ + OPN->ST.TA = (OPN->ST.TA & 0x3fc)|(v&3); + break; + case 0x26: /* timer B */ + OPN->ST.TB = v; + break; + case 0x27: /* mode, timer control */ + set_timers( OPN, &(OPN->ST),OPN->ST.param,v ); + break; + case 0x28: /* key on / off */ + c = v & 0x03; + if( c == 3 ) break; + if( (v&0x04) && (OPN->type & TYPE_6CH) ) c+=3; + CH = OPN->P_CH; + CH = &CH[c]; + if(v&0x10) FM_KEYON(OPN,CH,SLOT1); else FM_KEYOFF(OPN,CH,SLOT1); + if(v&0x20) FM_KEYON(OPN,CH,SLOT2); else FM_KEYOFF(OPN,CH,SLOT2); + if(v&0x40) FM_KEYON(OPN,CH,SLOT3); else FM_KEYOFF(OPN,CH,SLOT3); + if(v&0x80) FM_KEYON(OPN,CH,SLOT4); else FM_KEYOFF(OPN,CH,SLOT4); + break; + } +} + +/* write a OPN register (0x30-0xff) */ +static void OPNWriteReg(fm2612_FM_OPN *OPN, int r, int v) +{ + fm2612_FM_CH *CH; + fm2612_FM_SLOT *SLOT; + + UINT8 c = OPN_CHAN(r); + + if (c == 3) return; /* 0xX3,0xX7,0xXB,0xXF */ + + if (r >= 0x100) c+=3; + + CH = OPN->P_CH; + CH = &CH[c]; + + SLOT = &(CH->SLOT[OPN_SLOT(r)]); + + switch( r & 0xf0 ) { + case 0x30: /* DET , MUL */ + set_det_mul(&OPN->ST,CH,SLOT,v); + break; + + case 0x40: /* TL */ + set_tl(CH,SLOT,v); + break; + + case 0x50: /* KS, AR */ + set_ar_ksr(OPN->type,CH,SLOT,v); + break; + + case 0x60: /* bit7 = AM ENABLE, DR */ + set_dr(OPN->type, SLOT,v); + + if(OPN->type & TYPE_LFOPAN) /* YM2608/2610/2610B/2612 */ + { + SLOT->AMmask = (v&0x80) ? ~0 : 0; + } + break; + + case 0x70: /* SR */ + set_sr(OPN->type,SLOT,v); + break; + + case 0x80: /* SL, RR */ + set_sl_rr(OPN->type,SLOT,v); + break; + + case 0x90: /* SSG-EG */ + SLOT->ssg = v&0x0f; + + /* recalculate EG output */ + if ((SLOT->ssg&0x08) && (SLOT->ssgn ^ (SLOT->ssg&0x04)) && (SLOT->state > EG_REL)) + SLOT->vol_out = ((UINT32)(0x200 - SLOT->volume) & MAX_ATT_INDEX) + SLOT->tl; + else + SLOT->vol_out = (UINT32)SLOT->volume + SLOT->tl; + + /* SSG-EG envelope shapes : + + E AtAlH + 1 0 0 0 \\\\ + + 1 0 0 1 \___ + + 1 0 1 0 \/\/ + ___ + 1 0 1 1 \ + + 1 1 0 0 //// + ___ + 1 1 0 1 / + + 1 1 1 0 /\/\ + + 1 1 1 1 /___ + + + E = SSG-EG enable + + + The shapes are generated using Attack, Decay and Sustain phases. + + Each single character in the diagrams above represents this whole + sequence: + + - when KEY-ON = 1, normal Attack phase is generated (*without* any + difference when compared to normal mode), + + - later, when envelope level reaches minimum level (max volume), + the EG switches to Decay phase (which works with bigger steps + when compared to normal mode - see below), + + - later when envelope level passes the SL level, + the EG swithes to Sustain phase (which works with bigger steps + when compared to normal mode - see below), + + - finally when envelope level reaches maximum level (min volume), + the EG switches to Attack phase again (depends on actual waveform). + + Important is that when switch to Attack phase occurs, the phase counter + of that operator will be zeroed-out (as in normal KEY-ON) but not always. + (I havent found the rule for that - perhaps only when the output level is low) + + The difference (when compared to normal Envelope Generator mode) is + that the resolution in Decay and Sustain phases is 4 times lower; + this results in only 256 steps instead of normal 1024. + In other words: + when SSG-EG is disabled, the step inside of the EG is one, + when SSG-EG is enabled, the step is four (in Decay and Sustain phases). + + Times between the level changes are the same in both modes. + + + Important: + Decay 1 Level (so called SL) is compared to actual SSG-EG output, so + it is the same in both SSG and no-SSG modes, with this exception: + + when the SSG-EG is enabled and is generating raising levels + (when the EG output is inverted) the SL will be found at wrong level !!! + For example, when SL=02: + 0 -6 = -6dB in non-inverted EG output + 96-6 = -90dB in inverted EG output + Which means that EG compares its level to SL as usual, and that the + output is simply inverted afterall. + + + The Yamaha's manuals say that AR should be set to 0x1f (max speed). + That is not necessary, but then EG will be generating Attack phase. + + */ + + + break; + + case 0xa0: + switch( OPN_SLOT(r) ) + { + case 0: /* 0xa0-0xa2 : FNUM1 */ + { + UINT32 fn = (((UINT32)( (OPN->ST.fn_h)&7))<<8) + v; + UINT8 blk = OPN->ST.fn_h>>3; + /* keyscale code */ + CH->kcode = (blk<<2) | opn_fktable[(fn >> 7) & 0xf]; + /* phase increment counter */ + CH->fc = OPN->fn_table[fn*2]>>(7-blk); + + /* store fnum in clear form for LFO PM calculations */ + CH->block_fnum = (blk<<11) | fn; + + CH->SLOT[SLOT1].Incr=-1; + } + break; + case 1: /* 0xa4-0xa6 : FNUM2,BLK */ + OPN->ST.fn_h = v&0x3f; + break; + case 2: /* 0xa8-0xaa : 3CH FNUM1 */ + if(r < 0x100) + { + UINT32 fn = (((UINT32)(OPN->SL3.fn_h&7))<<8) + v; + UINT8 blk = OPN->SL3.fn_h>>3; + /* keyscale code */ + OPN->SL3.kcode[c]= (blk<<2) | opn_fktable[(fn >> 7) & 0xf]; + /* phase increment counter */ + OPN->SL3.fc[c] = OPN->fn_table[fn*2]>>(7-blk); + OPN->SL3.block_fnum[c] = (blk<<11) | fn; + (OPN->P_CH)[2].SLOT[SLOT1].Incr=-1; + } + break; + case 3: /* 0xac-0xae : 3CH FNUM2,BLK */ + if(r < 0x100) + OPN->SL3.fn_h = v&0x3f; + break; + } + break; + + case 0xb0: + switch( OPN_SLOT(r) ) + { + case 0: /* 0xb0-0xb2 : FB,ALGO */ + { + int feedback = (v>>3)&7; + CH->ALGO = v&7; + CH->FB = feedback ? feedback+6 : 0; + setup_connection( OPN, CH, c ); + } + break; + case 1: /* 0xb4-0xb6 : L , R , AMS , PMS (YM2612/YM2610B/YM2610/YM2608) */ + if( OPN->type & TYPE_LFOPAN) + { + /* b0-2 PMS */ + CH->pms = (v & 7) * 32; /* CH->pms = PM depth * 32 (index in lfo_pm_table) */ + + /* b4-5 AMS */ + CH->ams = lfo_ams_depth_shift[(v>>4) & 0x03]; + + /* PAN : b7 = L, b6 = R */ + OPN->pan[ c*2 ] = (v & 0x80) ? ~0 : 0; + OPN->pan[ c*2+1 ] = (v & 0x40) ? ~0 : 0; + + } + break; + } + break; + } +} + +/* initialize time tables */ +static void init_timetables(fm2612_FM_OPN *OPN, double freqbase) +{ + int i,d; + double rate; + + /* DeTune table */ + for (d = 0;d <= 3;d++) + { + for (i = 0;i <= 31;i++) + { + rate = ((double)dt_tab[d*32 + i]) * freqbase * (1<<(FREQ_SH-10)); /* -10 because chip works with 10.10 fixed point, while we use 16.16 */ + OPN->ST.dt_tab[d][i] = (INT32) rate; + OPN->ST.dt_tab[d+4][i] = -OPN->ST.dt_tab[d][i]; + } + } + + /* there are 2048 FNUMs that can be generated using FNUM/BLK registers + but LFO works with one more bit of a precision so we really need 4096 elements */ + /* calculate fnumber -> increment counter table */ + for(i = 0; i < 4096; i++) + { + /* freq table for octave 7 */ + /* OPN phase increment counter = 20bit */ + /* the correct formula is : F-Number = (144 * fnote * 2^20 / M) / 2^(B-1) */ + /* where sample clock is M/144 */ + /* this means the increment value for one clock sample is FNUM * 2^(B-1) = FNUM * 64 for octave 7 */ + /* we also need to handle the ratio between the chip frequency and the emulated frequency (can be 1.0) */ + OPN->fn_table[i] = (UINT32)( (double)i * 32 * freqbase * (1<<(FREQ_SH-10)) ); /* -10 because chip works with 10.10 fixed point, while we use 16.16 */ + } + + /* maximal frequency is required for Phase overflow calculation, register size is 17 bits (Nemesis) */ + OPN->fn_max = (UINT32)( (double)0x20000 * freqbase * (1<<(FREQ_SH-10)) ); +} + +/* prescaler set (and make time tables) */ +static void OPNSetPres(fm2612_FM_OPN *OPN, int pres, int timer_prescaler, int SSGpres) +{ + /* frequency base */ + OPN->ST.freqbase = (OPN->ST.rate) ? ((double)OPN->ST.clock / OPN->ST.rate) / pres : 0; + + /* EG is updated every 3 samples */ + OPN->eg_timer_add = (UINT32)((1<ST.freqbase); + OPN->eg_timer_overflow = ( 3 ) * (1<lfo_timer_add = (UINT32)((1<ST.freqbase); + + /* Timer base time */ + OPN->ST.timer_prescaler = timer_prescaler; + + /* SSG part prescaler set */ + if( SSGpres ) (*OPN->ST.SSG->set_clock)( OPN->ST.param, OPN->ST.clock * 2 / SSGpres ); + + /* make time tables */ + init_timetables(OPN, OPN->ST.freqbase); +} + +static void reset_channels(fm2612_FM_ST *ST , fm2612_FM_CH *CH , int num) +{ + int c,s; + + for( c = 0 ; c < num ; c++ ) + { + CH[c].fc = 0; + for(s = 0 ; s < 4 ; s++ ) + { + CH[c].SLOT[s].ssg = 0; + CH[c].SLOT[s].ssgn = 0; + CH[c].SLOT[s].state= EG_OFF; + CH[c].SLOT[s].volume = MAX_ATT_INDEX; + CH[c].SLOT[s].vol_out= MAX_ATT_INDEX; + } + } +} + +/* initialize generic tables */ +static void init_tables(void) +{ + signed int i,x; + signed int n; + double o,m; + + /* build Linear Power Table */ + for (x=0; x>= 4; /* 12 bits here */ + if (n&1) /* round to nearest */ + n = (n>>1)+1; + else + n = n>>1; + /* 11 bits here (rounded) */ + n <<= 2; /* 13 bits here (as in real chip) */ + + + /* 14 bits (with sign bit) */ + tl_tab[ x*2 + 0 ] = n; + tl_tab[ x*2 + 1 ] = -tl_tab[ x*2 + 0 ]; + + /* one entry in the 'Power' table use the following format, xxxxxyyyyyyyys with: */ + /* s = sign bit */ + /* yyyyyyyy = 8-bits decimal part (0-TL_RES_LEN) */ + /* xxxxx = 5-bits integer 'shift' value (0-31) but, since Power table output is 13 bits, */ + /* any value above 13 (included) would be discarded. */ + for (i=1; i<13; i++) + { + tl_tab[ x*2+0 + i*2*TL_RES_LEN ] = tl_tab[ x*2+0 ]>>i; + tl_tab[ x*2+1 + i*2*TL_RES_LEN ] = -tl_tab[ x*2+0 + i*2*TL_RES_LEN ]; + } + } + + /* build Logarithmic Sinus table */ + for (i=0; i0.0) + o = 8*log(1.0/m)/log(2.0); /* convert to 'decibels' */ + else + o = 8*log(-1.0/m)/log(2.0); /* convert to 'decibels' */ + + o = o / (ENV_STEP/4); + + n = (int)(2.0*o); + if (n&1) /* round to nearest */ + n = (n>>1)+1; + else + n = n>>1; + + /* 13-bits (8.5) value is formatted for above 'Power' table */ + sin_tab[ i ] = n*2 + (m>=0.0? 0: 1 ); + } + + /* build LFO PM modulation table */ + for(i = 0; i < 8; i++) /* 8 PM depths */ + { + UINT8 fnum; + for (fnum=0; fnum<128; fnum++) /* 7 bits meaningful of F-NUMBER */ + { + UINT8 value; + UINT8 step; + UINT32 offset_depth = i; + UINT32 offset_fnum_bit; + UINT32 bit_tmp; + + for (step=0; step<8; step++) + { + value = 0; + for (bit_tmp=0; bit_tmp<7; bit_tmp++) /* 7 bits */ + { + if (fnum & (1<OPN; + INT32 *out_fm = OPN->out_fm; + int i; + FMSAMPLE *bufL,*bufR; + fm2612_FM_CH *cch[6]; + int lt,rt; + + /* set bufer */ + bufL = buffer[0]; + bufR = buffer[1]; + + cch[0] = &F2612->CH[0]; + cch[1] = &F2612->CH[1]; + cch[2] = &F2612->CH[2]; + cch[3] = &F2612->CH[3]; + cch[4] = &F2612->CH[4]; + cch[5] = &F2612->CH[5]; + + /* refresh PG and EG */ + refresh_fc_eg_chan( OPN, cch[0] ); + refresh_fc_eg_chan( OPN, cch[1] ); + if( (OPN->ST.mode & 0xc0) ) + { + /* 3SLOT MODE */ + if( cch[2]->SLOT[SLOT1].Incr==-1) + { + refresh_fc_eg_slot(OPN, &cch[2]->SLOT[SLOT1] , OPN->SL3.fc[1] , OPN->SL3.kcode[1] ); + refresh_fc_eg_slot(OPN, &cch[2]->SLOT[SLOT2] , OPN->SL3.fc[2] , OPN->SL3.kcode[2] ); + refresh_fc_eg_slot(OPN, &cch[2]->SLOT[SLOT3] , OPN->SL3.fc[0] , OPN->SL3.kcode[0] ); + refresh_fc_eg_slot(OPN, &cch[2]->SLOT[SLOT4] , cch[2]->fc , cch[2]->kcode ); + } + }else refresh_fc_eg_chan( OPN, cch[2] ); + refresh_fc_eg_chan( OPN, cch[3] ); + refresh_fc_eg_chan( OPN, cch[4] ); + refresh_fc_eg_chan( OPN, cch[5] ); + + /* buffering */ + for(i=0; i < length ; i++) + { + /* clear outputs */ + out_fm[0] = 0; + out_fm[1] = 0; + out_fm[2] = 0; + out_fm[3] = 0; + out_fm[4] = 0; + out_fm[5] = 0; + + /* update SSG-EG output */ + update_ssg_eg_channel(&cch[0]->SLOT[SLOT1]); + update_ssg_eg_channel(&cch[1]->SLOT[SLOT1]); + update_ssg_eg_channel(&cch[2]->SLOT[SLOT1]); + update_ssg_eg_channel(&cch[3]->SLOT[SLOT1]); + update_ssg_eg_channel(&cch[4]->SLOT[SLOT1]); + update_ssg_eg_channel(&cch[5]->SLOT[SLOT1]); + + /* calculate FM */ + chan_calc(F2612, OPN, cch[0]); + chan_calc(F2612, OPN, cch[1]); + chan_calc(F2612, OPN, cch[2]); + chan_calc(F2612, OPN, cch[3]); + chan_calc(F2612, OPN, cch[4]); + if( F2612->dacen ) + *cch[5]->connect4 += F2612->dacout; + else + chan_calc(F2612, OPN, cch[5]); + + /* advance LFO */ + advance_lfo(OPN); + + /* advance envelope generator */ + OPN->eg_timer += OPN->eg_timer_add; + while (OPN->eg_timer >= OPN->eg_timer_overflow) + { + OPN->eg_timer -= OPN->eg_timer_overflow; + OPN->eg_cnt++; + + advance_eg_channel(OPN, &cch[0]->SLOT[SLOT1]); + advance_eg_channel(OPN, &cch[1]->SLOT[SLOT1]); + advance_eg_channel(OPN, &cch[2]->SLOT[SLOT1]); + advance_eg_channel(OPN, &cch[3]->SLOT[SLOT1]); + advance_eg_channel(OPN, &cch[4]->SLOT[SLOT1]); + advance_eg_channel(OPN, &cch[5]->SLOT[SLOT1]); + } + + if (out_fm[0] > 8191) out_fm[0] = 8191; + else if (out_fm[0] < -8192) out_fm[0] = -8192; + if (out_fm[1] > 8191) out_fm[1] = 8191; + else if (out_fm[1] < -8192) out_fm[1] = -8192; + if (out_fm[2] > 8191) out_fm[2] = 8191; + else if (out_fm[2] < -8192) out_fm[2] = -8192; + if (out_fm[3] > 8191) out_fm[3] = 8191; + else if (out_fm[3] < -8192) out_fm[3] = -8192; + if (out_fm[4] > 8191) out_fm[4] = 8191; + else if (out_fm[4] < -8192) out_fm[4] = -8192; + if (out_fm[5] > 8191) out_fm[5] = 8191; + else if (out_fm[5] < -8192) out_fm[5] = -8192; + + /* 6-channels mixing */ + lt = ((out_fm[0]>>0) & OPN->pan[0]); + rt = ((out_fm[0]>>0) & OPN->pan[1]); + lt += ((out_fm[1]>>0) & OPN->pan[2]); + rt += ((out_fm[1]>>0) & OPN->pan[3]); + lt += ((out_fm[2]>>0) & OPN->pan[4]); + rt += ((out_fm[2]>>0) & OPN->pan[5]); + lt += ((out_fm[3]>>0) & OPN->pan[6]); + rt += ((out_fm[3]>>0) & OPN->pan[7]); + lt += ((out_fm[4]>>0) & OPN->pan[8]); + rt += ((out_fm[4]>>0) & OPN->pan[9]); + lt += ((out_fm[5]>>0) & OPN->pan[10]); + rt += ((out_fm[5]>>0) & OPN->pan[11]); + +// Limit( lt, MAXOUT, MINOUT ); +// Limit( rt, MAXOUT, MINOUT ); + + #ifdef SAVE_SAMPLE + SAVE_ALL_CHANNELS + #endif + + /* buffering */ + bufL[i] = lt; + bufR[i] = rt; + + /* CSM mode: if CSM Key ON has occurred, CSM Key OFF need to be sent */ + /* only if Timer A does not overflow again (i.e CSM Key ON not set again) */ + OPN->SL3.key_csm <<= 1; + + /* timer A control */ + INTERNAL_TIMER_A( &OPN->ST , cch[2] ) + + /* CSM Mode Key ON still disabled */ + /* CSM Mode Key OFF (verified by Nemesis on real hardware) */ + FM_KEYOFF_CSM(cch[2],SLOT1); + FM_KEYOFF_CSM(cch[2],SLOT2); + FM_KEYOFF_CSM(cch[2],SLOT3); + FM_KEYOFF_CSM(cch[2],SLOT4); + OPN->SL3.key_csm = 0; + } + + /* timer B control */ + INTERNAL_TIMER_B(&OPN->ST,length) +} + +#ifdef __SAVE_H__ +void ym2612_postload(void *chip) +{ + if (chip) + { + YM2612 *F2612 = (YM2612 *)chip; + int r; + + /* DAC data & port */ + F2612->dacout = ((int)F2612->REGS[0x2a] - 0x80) << 6; /* level unknown */ + F2612->dacen = F2612->REGS[0x2b] & 0x80; + /* OPN registers */ + /* DT / MULTI , TL , KS / AR , AMON / DR , SR , SL / RR , SSG-EG */ + for(r=0x30;r<0x9e;r++) + if((r&3) != 3) + { + OPNWriteReg(&F2612->OPN,r,F2612->REGS[r]); + OPNWriteReg(&F2612->OPN,r|0x100,F2612->REGS[r|0x100]); + } + /* FB / CONNECT , L / R / AMS / PMS */ + for(r=0xb0;r<0xb6;r++) + if((r&3) != 3) + { + OPNWriteReg(&F2612->OPN,r,F2612->REGS[r]); + OPNWriteReg(&F2612->OPN,r|0x100,F2612->REGS[r|0x100]); + } + /* channels */ + /*FM_channel_postload(F2612->CH,6);*/ + } +} + +static void YM2612_save_state(YM2612 *F2612, device_t *device) +{ + device->save_item(NAME(F2612->REGS)); + FMsave_state_st(device,&F2612->OPN.ST); + FMsave_state_channel(device,F2612->CH,6); + /* 3slots */ + device->save_item(NAME(F2612->OPN.SL3.fc)); + device->save_item(NAME(F2612->OPN.SL3.fn_h)); + device->save_item(NAME(F2612->OPN.SL3.kcode)); + /* address register1 */ + device->save_item(NAME(F2612->addr_A1)); +} +#endif /* _STATE_H */ + +/* initialize YM2612 emulator(s) */ +void * ym2612_init(void *param, device_t *device, int clock, int rate, + FM_TIMERHANDLER timer_handler,FM_IRQHANDLER IRQHandler) +{ + YM2612 *F2612; + + /* allocate extend state space */ + F2612 = auto_alloc_clear(device->machine(), YM2612); + /* allocate total level table (128kb space) */ + init_tables(); + + F2612->OPN.ST.param = param; + F2612->OPN.type = TYPE_YM2612; + F2612->OPN.P_CH = F2612->CH; + F2612->OPN.ST.device = device; + F2612->OPN.ST.clock = clock; + F2612->OPN.ST.rate = rate; + /* F2612->OPN.ST.irq = 0; */ + /* F2612->OPN.ST.status = 0; */ + /* Extend handler */ + F2612->OPN.ST.timer_handler = timer_handler; + F2612->OPN.ST.IRQ_Handler = IRQHandler; + +#ifdef __SAVE_H__ + YM2612_save_state(F2612, device); +#endif + return F2612; +} + +/* shut down emulator */ +void ym2612_shutdown(void *chip) +{ + YM2612 *F2612 = (YM2612 *)chip; + + FMCloseTable(); + auto_free(F2612->OPN.ST.device->machine(), F2612); +} + +/* reset one of chip */ +void ym2612_reset_chip(void *chip) +{ + int i; + YM2612 *F2612 = (YM2612 *)chip; + fm2612_FM_OPN *OPN = &F2612->OPN; + + OPNSetPres( OPN, 6*24, 6*24, 0); + /* status clear */ + FM_IRQMASK_SET(&OPN->ST,0x03); + FM_BUSY_CLEAR(&OPN->ST); + OPNWriteMode(OPN,0x27,0x30); /* mode 0 , timer reset */ + + OPN->eg_timer = 0; + OPN->eg_cnt = 0; + + OPN->lfo_timer = 0; + OPN->lfo_cnt = 0; + OPN->LFO_AM = 126; + OPN->LFO_PM = 0; + + OPN->ST.status = 0; + OPN->ST.mode = 0; + + OPNWriteMode(OPN,0x27,0x30); + OPNWriteMode(OPN,0x26,0x00); + OPNWriteMode(OPN,0x25,0x00); + OPNWriteMode(OPN,0x24,0x00); + + reset_channels( &OPN->ST , &F2612->CH[0] , 6 ); + + for(i = 0xb6 ; i >= 0xb4 ; i-- ) + { + OPNWriteReg(OPN,i ,0xc0); + OPNWriteReg(OPN,i|0x100,0xc0); + } + for(i = 0xb2 ; i >= 0x30 ; i-- ) + { + OPNWriteReg(OPN,i ,0); + OPNWriteReg(OPN,i|0x100,0); + } + + /* DAC mode clear */ + F2612->dacen = 0; + F2612->dacout = 0; +} + +/* YM2612 write */ +/* n = number */ +/* a = address */ +/* v = value */ +int ym2612_write(void *chip, int a, UINT8 v) +{ + YM2612 *F2612 = (YM2612 *)chip; + int addr; + + v &= 0xff; /* adjust to 8 bit bus */ + + switch( a&3) + { + case 0: /* address port 0 */ + F2612->OPN.ST.address = v; + F2612->addr_A1 = 0; + break; + + case 1: /* data port 0 */ + if (F2612->addr_A1 != 0) + break; /* verified on real YM2608 */ + + addr = F2612->OPN.ST.address; + F2612->REGS[addr] = v; + switch( addr & 0xf0 ) + { + case 0x20: /* 0x20-0x2f Mode */ + switch( addr ) + { + case 0x2a: /* DAC data (YM2612) */ + ym2612_update_req(F2612->OPN.ST.param); + F2612->dacout = ((int)v - 0x80) << 6; /* level unknown */ + break; + case 0x2b: /* DAC Sel (YM2612) */ + /* b7 = dac enable */ + F2612->dacen = v & 0x80; + break; + default: /* OPN section */ + ym2612_update_req(F2612->OPN.ST.param); + /* write register */ + OPNWriteMode(&(F2612->OPN),addr,v); + } + break; + default: /* 0x30-0xff OPN section */ + ym2612_update_req(F2612->OPN.ST.param); + /* write register */ + OPNWriteReg(&(F2612->OPN),addr,v); + } + break; + + case 2: /* address port 1 */ + F2612->OPN.ST.address = v; + F2612->addr_A1 = 1; + break; + + case 3: /* data port 1 */ + if (F2612->addr_A1 != 1) + break; /* verified on real YM2608 */ + + addr = F2612->OPN.ST.address; + F2612->REGS[addr | 0x100] = v; + ym2612_update_req(F2612->OPN.ST.param); + OPNWriteReg(&(F2612->OPN),addr | 0x100,v); + break; + } + return F2612->OPN.ST.irq; +} + +UINT8 ym2612_read(void *chip,int a) +{ + YM2612 *F2612 = (YM2612 *)chip; + + switch( a&3) + { + case 0: /* status 0 */ + return FM_STATUS_FLAG(&F2612->OPN.ST); + case 1: + case 2: + case 3: + LOG(LOG_WAR,("YM2612 #%p:A=%d read unmapped area\n",F2612->OPN.ST.param,a)); + return FM_STATUS_FLAG(&F2612->OPN.ST); + } + return 0; +} + +int ym2612_timer_over(void *chip,int c) +{ + YM2612 *F2612 = (YM2612 *)chip; + + if( c ) + { /* Timer B */ + TimerBOver( &(F2612->OPN.ST) ); + } + else + { /* Timer A */ + ym2612_update_req(F2612->OPN.ST.param); + /* timer update */ + TimerAOver( &(F2612->OPN.ST) ); + /* CSM mode key,TL controll */ + if ((F2612->OPN.ST.mode & 0xc0) == 0x80) + { /* CSM mode total level latch and auto key on */ + CSMKeyControll( &F2612->OPN, &(F2612->CH[2]) ); + } + } + return F2612->OPN.ST.irq; +} + +#endif /* (BUILD_YM2612||BUILD_YM3238) */ diff --git a/src/devices/sound/fmopl.c b/src/devices/sound/fmopl.c new file mode 100644 index 00000000000..4932cde31fa --- /dev/null +++ b/src/devices/sound/fmopl.c @@ -0,0 +1,2582 @@ +// license:??? +// copyright-holders:Jarek Burczynski +/* +** +** File: fmopl.c - software implementation of FM sound generator +** types OPL and OPL2 +** +** Copyright Jarek Burczynski (bujar at mame dot net) +** Copyright Tatsuyuki Satoh , MultiArcadeMachineEmulator development +** +** Version 0.72 +** + +Revision History: + +04-08-2003 Jarek Burczynski: + - removed BFRDY hack. BFRDY is busy flag, and it should be 0 only when the chip + handles memory read/write or during the adpcm synthesis when the chip + requests another byte of ADPCM data. + +24-07-2003 Jarek Burczynski: + - added a small hack for Y8950 status BFRDY flag (bit 3 should be set after + some (unknown) delay). Right now it's always set. + +14-06-2003 Jarek Burczynski: + - implemented all of the status register flags in Y8950 emulation + - renamed y8950_set_delta_t_memory() parameters from _rom_ to _mem_ since + they can be either RAM or ROM + +08-10-2002 Jarek Burczynski (thanks to Dox for the YM3526 chip) + - corrected ym3526_read() to always set bit 2 and bit 1 + to HIGH state - identical to ym3812_read (verified on real YM3526) + +04-28-2002 Jarek Burczynski: + - binary exact Envelope Generator (verified on real YM3812); + compared to YM2151: the EG clock is equal to internal_clock, + rates are 2 times slower and volume resolution is one bit less + - modified interface functions (they no longer return pointer - + that's internal to the emulator now): + - new wrapper functions for OPLCreate: ym3526_init(), ym3812_init() and y8950_init() + - corrected 'off by one' error in feedback calculations (when feedback is off) + - enabled waveform usage (credit goes to Vlad Romascanu and zazzal22) + - speeded up noise generator calculations (Nicola Salmoria) + +03-24-2002 Jarek Burczynski (thanks to Dox for the YM3812 chip) + Complete rewrite (all verified on real YM3812): + - corrected sin_tab and tl_tab data + - corrected operator output calculations + - corrected waveform_select_enable register; + simply: ignore all writes to waveform_select register when + waveform_select_enable == 0 and do not change the waveform previously selected. + - corrected KSR handling + - corrected Envelope Generator: attack shape, Sustain mode and + Percussive/Non-percussive modes handling + - Envelope Generator rates are two times slower now + - LFO amplitude (tremolo) and phase modulation (vibrato) + - rhythm sounds phase generation + - white noise generator (big thanks to Olivier Galibert for mentioning Berlekamp-Massey algorithm) + - corrected key on/off handling (the 'key' signal is ORed from three sources: FM, rhythm and CSM) + - funky details (like ignoring output of operator 1 in BD rhythm sound when connect == 1) + +12-28-2001 Acho A. Tang + - reflected Delta-T EOS status on Y8950 status port. + - fixed subscription range of attack/decay tables + + + To do: + add delay before key off in CSM mode (see CSMKeyControll) + verify volume of the FM part on the Y8950 +*/ + +#include "emu.h" +#include "ymdeltat.h" +#include "fmopl.h" + + + +/* output final shift */ +#if (OPL_SAMPLE_BITS==16) + #define FINAL_SH (0) + #define MAXOUT (+32767) + #define MINOUT (-32768) +#else + #define FINAL_SH (8) + #define MAXOUT (+127) + #define MINOUT (-128) +#endif + + +#define FREQ_SH 16 /* 16.16 fixed point (frequency calculations) */ +#define EG_SH 16 /* 16.16 fixed point (EG timing) */ +#define LFO_SH 24 /* 8.24 fixed point (LFO calculations) */ +#define TIMER_SH 16 /* 16.16 fixed point (timers calculations) */ + +#define FREQ_MASK ((1<=0) + { + if (value < 0x0200) + return (value & ~0); + if (value < 0x0400) + return (value & ~1); + if (value < 0x0800) + return (value & ~3); + if (value < 0x1000) + return (value & ~7); + if (value < 0x2000) + return (value & ~15); + if (value < 0x4000) + return (value & ~31); + return (value & ~63); + } + /*else value < 0*/ + if (value > -0x0200) + return (~abs(value) & ~0); + if (value > -0x0400) + return (~abs(value) & ~1); + if (value > -0x0800) + return (~abs(value) & ~3); + if (value > -0x1000) + return (~abs(value) & ~7); + if (value > -0x2000) + return (~abs(value) & ~15); + if (value > -0x4000) + return (~abs(value) & ~31); + return (~abs(value) & ~63); +} + + +static FILE *sample[1]; + #if 1 /*save to MONO file */ + #define SAVE_ALL_CHANNELS \ + { signed int pom = acc_calc(lt); \ + fputc((unsigned short)pom&0xff,sample[0]); \ + fputc(((unsigned short)pom>>8)&0xff,sample[0]); \ + } + #else /*save to STEREO file */ + #define SAVE_ALL_CHANNELS \ + { signed int pom = lt; \ + fputc((unsigned short)pom&0xff,sample[0]); \ + fputc(((unsigned short)pom>>8)&0xff,sample[0]); \ + pom = rt; \ + fputc((unsigned short)pom&0xff,sample[0]); \ + fputc(((unsigned short)pom>>8)&0xff,sample[0]); \ + } + #endif +#endif + +#define LOG_CYM_FILE 0 +static FILE * cymfile = NULL; + + + +#define OPL_TYPE_WAVESEL 0x01 /* waveform select */ +#define OPL_TYPE_ADPCM 0x02 /* DELTA-T ADPCM unit */ +#define OPL_TYPE_KEYBOARD 0x04 /* keyboard interface */ +#define OPL_TYPE_IO 0x08 /* I/O port */ + +/* ---------- Generic interface section ---------- */ +#define OPL_TYPE_YM3526 (0) +#define OPL_TYPE_YM3812 (OPL_TYPE_WAVESEL) +#define OPL_TYPE_Y8950 (OPL_TYPE_ADPCM|OPL_TYPE_KEYBOARD|OPL_TYPE_IO) + + + +struct OPL_SLOT +{ + UINT32 ar; /* attack rate: AR<<2 */ + UINT32 dr; /* decay rate: DR<<2 */ + UINT32 rr; /* release rate:RR<<2 */ + UINT8 KSR; /* key scale rate */ + UINT8 ksl; /* keyscale level */ + UINT8 ksr; /* key scale rate: kcode>>KSR */ + UINT8 mul; /* multiple: mul_tab[ML] */ + + /* Phase Generator */ + UINT32 Cnt; /* frequency counter */ + UINT32 Incr; /* frequency counter step */ + UINT8 FB; /* feedback shift value */ + INT32 *connect1; /* slot1 output pointer */ + INT32 op1_out[2]; /* slot1 output for feedback */ + UINT8 CON; /* connection (algorithm) type */ + + /* Envelope Generator */ + UINT8 eg_type; /* percussive/non-percussive mode */ + UINT8 state; /* phase type */ + UINT32 TL; /* total level: TL << 2 */ + INT32 TLL; /* adjusted now TL */ + INT32 volume; /* envelope counter */ + UINT32 sl; /* sustain level: sl_tab[SL] */ + UINT8 eg_sh_ar; /* (attack state) */ + UINT8 eg_sel_ar; /* (attack state) */ + UINT8 eg_sh_dr; /* (decay state) */ + UINT8 eg_sel_dr; /* (decay state) */ + UINT8 eg_sh_rr; /* (release state) */ + UINT8 eg_sel_rr; /* (release state) */ + UINT32 key; /* 0 = KEY OFF, >0 = KEY ON */ + + /* LFO */ + UINT32 AMmask; /* LFO Amplitude Modulation enable mask */ + UINT8 vib; /* LFO Phase Modulation enable flag (active high)*/ + + /* waveform select */ + UINT16 wavetable; +}; + +struct OPL_CH +{ + OPL_SLOT SLOT[2]; + /* phase generator state */ + UINT32 block_fnum; /* block+fnum */ + UINT32 fc; /* Freq. Increment base */ + UINT32 ksl_base; /* KeyScaleLevel Base step */ + UINT8 kcode; /* key code (for key scaling) */ +}; + +/* OPL state */ +struct FM_OPL +{ + /* FM channel slots */ + OPL_CH P_CH[9]; /* OPL/OPL2 chips have 9 channels*/ + + UINT32 eg_cnt; /* global envelope generator counter */ + UINT32 eg_timer; /* global envelope generator counter works at frequency = chipclock/72 */ + UINT32 eg_timer_add; /* step of eg_timer */ + UINT32 eg_timer_overflow; /* envelope generator timer overlfows every 1 sample (on real chip) */ + + UINT8 rhythm; /* Rhythm mode */ + + UINT32 fn_tab[1024]; /* fnumber->increment counter */ + + /* LFO */ + UINT32 LFO_AM; + INT32 LFO_PM; + + UINT8 lfo_am_depth; + UINT8 lfo_pm_depth_range; + UINT32 lfo_am_cnt; + UINT32 lfo_am_inc; + UINT32 lfo_pm_cnt; + UINT32 lfo_pm_inc; + + UINT32 noise_rng; /* 23 bit noise shift register */ + UINT32 noise_p; /* current noise 'phase' */ + UINT32 noise_f; /* current noise period */ + + UINT8 wavesel; /* waveform select enable flag */ + + UINT32 T[2]; /* timer counters */ + UINT8 st[2]; /* timer enable */ + +#if BUILD_Y8950 + /* Delta-T ADPCM unit (Y8950) */ + + YM_DELTAT *deltat; + + /* Keyboard and I/O ports interface */ + UINT8 portDirection; + UINT8 portLatch; + OPL_PORTHANDLER_R porthandler_r; + OPL_PORTHANDLER_W porthandler_w; + void * port_param; + OPL_PORTHANDLER_R keyboardhandler_r; + OPL_PORTHANDLER_W keyboardhandler_w; + void * keyboard_param; +#endif + + /* external event callback handlers */ + OPL_TIMERHANDLER timer_handler; /* TIMER handler */ + void *TimerParam; /* TIMER parameter */ + OPL_IRQHANDLER IRQHandler; /* IRQ handler */ + void *IRQParam; /* IRQ parameter */ + OPL_UPDATEHANDLER UpdateHandler;/* stream update handler */ + void *UpdateParam; /* stream update parameter */ + + UINT8 type; /* chip type */ + UINT8 address; /* address register */ + UINT8 status; /* status flag */ + UINT8 statusmask; /* status mask */ + UINT8 mode; /* Reg.08 : CSM,notesel,etc. */ + + UINT32 clock; /* master clock (Hz) */ + UINT32 rate; /* sampling rate (Hz) */ + double freqbase; /* frequency base */ + attotime TimerBase; /* Timer base time (==sampling time)*/ + device_t *device; + + signed int phase_modulation; /* phase modulation input (SLOT 2) */ + signed int output[1]; +#if BUILD_Y8950 + INT32 output_deltat[4]; /* for Y8950 DELTA-T, chip is mono, that 4 here is just for safety */ +#endif +}; + + + +/* mapping of register number (offset) to slot number used by the emulator */ +static const int slot_array[32]= +{ + 0, 2, 4, 1, 3, 5,-1,-1, + 6, 8,10, 7, 9,11,-1,-1, + 12,14,16,13,15,17,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1 +}; + +/* key scale level */ +/* table is 3dB/octave , DV converts this into 6dB/octave */ +/* 0.1875 is bit 0 weight of the envelope counter (volume) expressed in the 'decibel' scale */ +#define DV (0.1875/2.0) +static const UINT32 ksl_tab[8*16]= +{ + /* OCT 0 */ + 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV, + 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV, + 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV, + 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV, + /* OCT 1 */ + 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV, + 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV, + 0.000/DV, 0.750/DV, 1.125/DV, 1.500/DV, + 1.875/DV, 2.250/DV, 2.625/DV, 3.000/DV, + /* OCT 2 */ + 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV, + 0.000/DV, 1.125/DV, 1.875/DV, 2.625/DV, + 3.000/DV, 3.750/DV, 4.125/DV, 4.500/DV, + 4.875/DV, 5.250/DV, 5.625/DV, 6.000/DV, + /* OCT 3 */ + 0.000/DV, 0.000/DV, 0.000/DV, 1.875/DV, + 3.000/DV, 4.125/DV, 4.875/DV, 5.625/DV, + 6.000/DV, 6.750/DV, 7.125/DV, 7.500/DV, + 7.875/DV, 8.250/DV, 8.625/DV, 9.000/DV, + /* OCT 4 */ + 0.000/DV, 0.000/DV, 3.000/DV, 4.875/DV, + 6.000/DV, 7.125/DV, 7.875/DV, 8.625/DV, + 9.000/DV, 9.750/DV,10.125/DV,10.500/DV, + 10.875/DV,11.250/DV,11.625/DV,12.000/DV, + /* OCT 5 */ + 0.000/DV, 3.000/DV, 6.000/DV, 7.875/DV, + 9.000/DV,10.125/DV,10.875/DV,11.625/DV, + 12.000/DV,12.750/DV,13.125/DV,13.500/DV, + 13.875/DV,14.250/DV,14.625/DV,15.000/DV, + /* OCT 6 */ + 0.000/DV, 6.000/DV, 9.000/DV,10.875/DV, + 12.000/DV,13.125/DV,13.875/DV,14.625/DV, + 15.000/DV,15.750/DV,16.125/DV,16.500/DV, + 16.875/DV,17.250/DV,17.625/DV,18.000/DV, + /* OCT 7 */ + 0.000/DV, 9.000/DV,12.000/DV,13.875/DV, + 15.000/DV,16.125/DV,16.875/DV,17.625/DV, + 18.000/DV,18.750/DV,19.125/DV,19.500/DV, + 19.875/DV,20.250/DV,20.625/DV,21.000/DV +}; +#undef DV + +/* 0 / 3.0 / 1.5 / 6.0 dB/OCT */ +static const UINT32 ksl_shift[4] = { 31, 1, 2, 0 }; + + +/* sustain level table (3dB per step) */ +/* 0 - 15: 0, 3, 6, 9,12,15,18,21,24,27,30,33,36,39,42,93 (dB)*/ +#define SC(db) (UINT32) ( db * (2.0/ENV_STEP) ) +static const UINT32 sl_tab[16]={ + SC( 0),SC( 1),SC( 2),SC(3 ),SC(4 ),SC(5 ),SC(6 ),SC( 7), + SC( 8),SC( 9),SC(10),SC(11),SC(12),SC(13),SC(14),SC(31) +}; +#undef SC + + +#define RATE_STEPS (8) +static const unsigned char eg_inc[15*RATE_STEPS]={ +/*cycle:0 1 2 3 4 5 6 7*/ + +/* 0 */ 0,1, 0,1, 0,1, 0,1, /* rates 00..12 0 (increment by 0 or 1) */ +/* 1 */ 0,1, 0,1, 1,1, 0,1, /* rates 00..12 1 */ +/* 2 */ 0,1, 1,1, 0,1, 1,1, /* rates 00..12 2 */ +/* 3 */ 0,1, 1,1, 1,1, 1,1, /* rates 00..12 3 */ + +/* 4 */ 1,1, 1,1, 1,1, 1,1, /* rate 13 0 (increment by 1) */ +/* 5 */ 1,1, 1,2, 1,1, 1,2, /* rate 13 1 */ +/* 6 */ 1,2, 1,2, 1,2, 1,2, /* rate 13 2 */ +/* 7 */ 1,2, 2,2, 1,2, 2,2, /* rate 13 3 */ + +/* 8 */ 2,2, 2,2, 2,2, 2,2, /* rate 14 0 (increment by 2) */ +/* 9 */ 2,2, 2,4, 2,2, 2,4, /* rate 14 1 */ +/*10 */ 2,4, 2,4, 2,4, 2,4, /* rate 14 2 */ +/*11 */ 2,4, 4,4, 2,4, 4,4, /* rate 14 3 */ + +/*12 */ 4,4, 4,4, 4,4, 4,4, /* rates 15 0, 15 1, 15 2, 15 3 (increment by 4) */ +/*13 */ 8,8, 8,8, 8,8, 8,8, /* rates 15 2, 15 3 for attack */ +/*14 */ 0,0, 0,0, 0,0, 0,0, /* infinity rates for attack and decay(s) */ +}; + + +#define O(a) (a*RATE_STEPS) + +/*note that there is no O(13) in this table - it's directly in the code */ +static const unsigned char eg_rate_select[16+64+16]={ /* Envelope Generator rates (16 + 64 rates + 16 RKS) */ +/* 16 infinite time rates */ +O(14),O(14),O(14),O(14),O(14),O(14),O(14),O(14), +O(14),O(14),O(14),O(14),O(14),O(14),O(14),O(14), + +/* rates 00-12 */ +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), + +/* rate 13 */ +O( 4),O( 5),O( 6),O( 7), + +/* rate 14 */ +O( 8),O( 9),O(10),O(11), + +/* rate 15 */ +O(12),O(12),O(12),O(12), + +/* 16 dummy rates (same as 15 3) */ +O(12),O(12),O(12),O(12),O(12),O(12),O(12),O(12), +O(12),O(12),O(12),O(12),O(12),O(12),O(12),O(12), + +}; +#undef O + +/*rate 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 */ +/*shift 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0, 0, 0 */ +/*mask 4095, 2047, 1023, 511, 255, 127, 63, 31, 15, 7, 3, 1, 0, 0, 0, 0 */ + +#define O(a) (a*1) +static const unsigned char eg_rate_shift[16+64+16]={ /* Envelope Generator counter shifts (16 + 64 rates + 16 RKS) */ +/* 16 infinite time rates */ +O(0),O(0),O(0),O(0),O(0),O(0),O(0),O(0), +O(0),O(0),O(0),O(0),O(0),O(0),O(0),O(0), + +/* rates 00-12 */ +O(12),O(12),O(12),O(12), +O(11),O(11),O(11),O(11), +O(10),O(10),O(10),O(10), +O( 9),O( 9),O( 9),O( 9), +O( 8),O( 8),O( 8),O( 8), +O( 7),O( 7),O( 7),O( 7), +O( 6),O( 6),O( 6),O( 6), +O( 5),O( 5),O( 5),O( 5), +O( 4),O( 4),O( 4),O( 4), +O( 3),O( 3),O( 3),O( 3), +O( 2),O( 2),O( 2),O( 2), +O( 1),O( 1),O( 1),O( 1), +O( 0),O( 0),O( 0),O( 0), + +/* rate 13 */ +O( 0),O( 0),O( 0),O( 0), + +/* rate 14 */ +O( 0),O( 0),O( 0),O( 0), + +/* rate 15 */ +O( 0),O( 0),O( 0),O( 0), + +/* 16 dummy rates (same as 15 3) */ +O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0), +O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0), + +}; +#undef O + + +/* multiple table */ +#define ML 2 +static const UINT8 mul_tab[16]= { +/* 1/2, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,10,12,12,15,15 */ + ML/2, 1*ML, 2*ML, 3*ML, 4*ML, 5*ML, 6*ML, 7*ML, + 8*ML, 9*ML,10*ML,10*ML,12*ML,12*ML,15*ML,15*ML +}; +#undef ML + +/* TL_TAB_LEN is calculated as: +* 12 - sinus amplitude bits (Y axis) +* 2 - sinus sign bit (Y axis) +* TL_RES_LEN - sinus resolution (X axis) +*/ +#define TL_TAB_LEN (12*2*TL_RES_LEN) +static signed int tl_tab[TL_TAB_LEN]; + +#define ENV_QUIET (TL_TAB_LEN>>4) + +/* sin waveform table in 'decibel' scale */ +/* four waveforms on OPL2 type chips */ +static unsigned int sin_tab[SIN_LEN * 4]; + + +/* LFO Amplitude Modulation table (verified on real YM3812) + 27 output levels (triangle waveform); 1 level takes one of: 192, 256 or 448 samples + + Length: 210 elements. + + Each of the elements has to be repeated + exactly 64 times (on 64 consecutive samples). + The whole table takes: 64 * 210 = 13440 samples. + + When AM = 1 data is used directly + When AM = 0 data is divided by 4 before being used (losing precision is important) +*/ + +#define LFO_AM_TAB_ELEMENTS 210 + +static const UINT8 lfo_am_table[LFO_AM_TAB_ELEMENTS] = { +0,0,0,0,0,0,0, +1,1,1,1, +2,2,2,2, +3,3,3,3, +4,4,4,4, +5,5,5,5, +6,6,6,6, +7,7,7,7, +8,8,8,8, +9,9,9,9, +10,10,10,10, +11,11,11,11, +12,12,12,12, +13,13,13,13, +14,14,14,14, +15,15,15,15, +16,16,16,16, +17,17,17,17, +18,18,18,18, +19,19,19,19, +20,20,20,20, +21,21,21,21, +22,22,22,22, +23,23,23,23, +24,24,24,24, +25,25,25,25, +26,26,26, +25,25,25,25, +24,24,24,24, +23,23,23,23, +22,22,22,22, +21,21,21,21, +20,20,20,20, +19,19,19,19, +18,18,18,18, +17,17,17,17, +16,16,16,16, +15,15,15,15, +14,14,14,14, +13,13,13,13, +12,12,12,12, +11,11,11,11, +10,10,10,10, +9,9,9,9, +8,8,8,8, +7,7,7,7, +6,6,6,6, +5,5,5,5, +4,4,4,4, +3,3,3,3, +2,2,2,2, +1,1,1,1 +}; + +/* LFO Phase Modulation table (verified on real YM3812) */ +static const INT8 lfo_pm_table[8*8*2] = { +/* FNUM2/FNUM = 00 0xxxxxxx (0x0000) */ +0, 0, 0, 0, 0, 0, 0, 0, /*LFO PM depth = 0*/ +0, 0, 0, 0, 0, 0, 0, 0, /*LFO PM depth = 1*/ + +/* FNUM2/FNUM = 00 1xxxxxxx (0x0080) */ +0, 0, 0, 0, 0, 0, 0, 0, /*LFO PM depth = 0*/ +1, 0, 0, 0,-1, 0, 0, 0, /*LFO PM depth = 1*/ + +/* FNUM2/FNUM = 01 0xxxxxxx (0x0100) */ +1, 0, 0, 0,-1, 0, 0, 0, /*LFO PM depth = 0*/ +2, 1, 0,-1,-2,-1, 0, 1, /*LFO PM depth = 1*/ + +/* FNUM2/FNUM = 01 1xxxxxxx (0x0180) */ +1, 0, 0, 0,-1, 0, 0, 0, /*LFO PM depth = 0*/ +3, 1, 0,-1,-3,-1, 0, 1, /*LFO PM depth = 1*/ + +/* FNUM2/FNUM = 10 0xxxxxxx (0x0200) */ +2, 1, 0,-1,-2,-1, 0, 1, /*LFO PM depth = 0*/ +4, 2, 0,-2,-4,-2, 0, 2, /*LFO PM depth = 1*/ + +/* FNUM2/FNUM = 10 1xxxxxxx (0x0280) */ +2, 1, 0,-1,-2,-1, 0, 1, /*LFO PM depth = 0*/ +5, 2, 0,-2,-5,-2, 0, 2, /*LFO PM depth = 1*/ + +/* FNUM2/FNUM = 11 0xxxxxxx (0x0300) */ +3, 1, 0,-1,-3,-1, 0, 1, /*LFO PM depth = 0*/ +6, 3, 0,-3,-6,-3, 0, 3, /*LFO PM depth = 1*/ + +/* FNUM2/FNUM = 11 1xxxxxxx (0x0380) */ +3, 1, 0,-1,-3,-1, 0, 1, /*LFO PM depth = 0*/ +7, 3, 0,-3,-7,-3, 0, 3 /*LFO PM depth = 1*/ +}; + + +/* lock level of common table */ +static int num_lock = 0; + + +#define SLOT7_1 (&OPL->P_CH[7].SLOT[SLOT1]) +#define SLOT7_2 (&OPL->P_CH[7].SLOT[SLOT2]) +#define SLOT8_1 (&OPL->P_CH[8].SLOT[SLOT1]) +#define SLOT8_2 (&OPL->P_CH[8].SLOT[SLOT2]) + + + + +INLINE int limit( int val, int max, int min ) { + if ( val > max ) + val = max; + else if ( val < min ) + val = min; + + return val; +} + + +/* status set and IRQ handling */ +INLINE void OPL_STATUS_SET(FM_OPL *OPL,int flag) +{ + /* set status flag */ + OPL->status |= flag; + if(!(OPL->status & 0x80)) + { + if(OPL->status & OPL->statusmask) + { /* IRQ on */ + OPL->status |= 0x80; + /* callback user interrupt handler (IRQ is OFF to ON) */ + if(OPL->IRQHandler) (OPL->IRQHandler)(OPL->IRQParam,1); + } + } +} + +/* status reset and IRQ handling */ +INLINE void OPL_STATUS_RESET(FM_OPL *OPL,int flag) +{ + /* reset status flag */ + OPL->status &=~flag; + if((OPL->status & 0x80)) + { + if (!(OPL->status & OPL->statusmask) ) + { + OPL->status &= 0x7f; + /* callback user interrupt handler (IRQ is ON to OFF) */ + if(OPL->IRQHandler) (OPL->IRQHandler)(OPL->IRQParam,0); + } + } +} + +/* IRQ mask set */ +INLINE void OPL_STATUSMASK_SET(FM_OPL *OPL,int flag) +{ + OPL->statusmask = flag; + /* IRQ handling check */ + OPL_STATUS_SET(OPL,0); + OPL_STATUS_RESET(OPL,0); +} + + +/* advance LFO to next sample */ +INLINE void advance_lfo(FM_OPL *OPL) +{ + UINT8 tmp; + + /* LFO */ + OPL->lfo_am_cnt += OPL->lfo_am_inc; + if (OPL->lfo_am_cnt >= ((UINT32)LFO_AM_TAB_ELEMENTS<lfo_am_cnt -= ((UINT32)LFO_AM_TAB_ELEMENTS<lfo_am_cnt >> LFO_SH ]; + + if (OPL->lfo_am_depth) + OPL->LFO_AM = tmp; + else + OPL->LFO_AM = tmp>>2; + + OPL->lfo_pm_cnt += OPL->lfo_pm_inc; + OPL->LFO_PM = ((OPL->lfo_pm_cnt>>LFO_SH) & 7) | OPL->lfo_pm_depth_range; +} + +/* advance to next sample */ +INLINE void advance(FM_OPL *OPL) +{ + OPL_CH *CH; + OPL_SLOT *op; + int i; + + OPL->eg_timer += OPL->eg_timer_add; + + while (OPL->eg_timer >= OPL->eg_timer_overflow) + { + OPL->eg_timer -= OPL->eg_timer_overflow; + + OPL->eg_cnt++; + + for (i=0; i<9*2; i++) + { + CH = &OPL->P_CH[i/2]; + op = &CH->SLOT[i&1]; + + /* Envelope Generator */ + switch(op->state) + { + case EG_ATT: /* attack phase */ + if ( !(OPL->eg_cnt & ((1<eg_sh_ar)-1) ) ) + { + op->volume += (~op->volume * + (eg_inc[op->eg_sel_ar + ((OPL->eg_cnt>>op->eg_sh_ar)&7)]) + ) >>3; + + if (op->volume <= MIN_ATT_INDEX) + { + op->volume = MIN_ATT_INDEX; + op->state = EG_DEC; + } + + } + break; + + case EG_DEC: /* decay phase */ + if ( !(OPL->eg_cnt & ((1<eg_sh_dr)-1) ) ) + { + op->volume += eg_inc[op->eg_sel_dr + ((OPL->eg_cnt>>op->eg_sh_dr)&7)]; + + if ( op->volume >= op->sl ) + op->state = EG_SUS; + + } + break; + + case EG_SUS: /* sustain phase */ + + /* this is important behaviour: + one can change percusive/non-percussive modes on the fly and + the chip will remain in sustain phase - verified on real YM3812 */ + + if(op->eg_type) /* non-percussive mode */ + { + /* do nothing */ + } + else /* percussive mode */ + { + /* during sustain phase chip adds Release Rate (in percussive mode) */ + if ( !(OPL->eg_cnt & ((1<eg_sh_rr)-1) ) ) + { + op->volume += eg_inc[op->eg_sel_rr + ((OPL->eg_cnt>>op->eg_sh_rr)&7)]; + + if ( op->volume >= MAX_ATT_INDEX ) + op->volume = MAX_ATT_INDEX; + } + /* else do nothing in sustain phase */ + } + break; + + case EG_REL: /* release phase */ + if ( !(OPL->eg_cnt & ((1<eg_sh_rr)-1) ) ) + { + op->volume += eg_inc[op->eg_sel_rr + ((OPL->eg_cnt>>op->eg_sh_rr)&7)]; + + if ( op->volume >= MAX_ATT_INDEX ) + { + op->volume = MAX_ATT_INDEX; + op->state = EG_OFF; + } + + } + break; + + default: + break; + } + } + } + + for (i=0; i<9*2; i++) + { + CH = &OPL->P_CH[i/2]; + op = &CH->SLOT[i&1]; + + /* Phase Generator */ + if(op->vib) + { + UINT8 block; + unsigned int block_fnum = CH->block_fnum; + + unsigned int fnum_lfo = (block_fnum&0x0380) >> 7; + + signed int lfo_fn_table_index_offset = lfo_pm_table[OPL->LFO_PM + 16*fnum_lfo ]; + + if (lfo_fn_table_index_offset) /* LFO phase modulation active */ + { + block_fnum += lfo_fn_table_index_offset; + block = (block_fnum&0x1c00) >> 10; + op->Cnt += (OPL->fn_tab[block_fnum&0x03ff] >> (7-block)) * op->mul; + } + else /* LFO phase modulation = zero */ + { + op->Cnt += op->Incr; + } + } + else /* LFO phase modulation disabled for this operator */ + { + op->Cnt += op->Incr; + } + } + + /* The Noise Generator of the YM3812 is 23-bit shift register. + * Period is equal to 2^23-2 samples. + * Register works at sampling frequency of the chip, so output + * can change on every sample. + * + * Output of the register and input to the bit 22 is: + * bit0 XOR bit14 XOR bit15 XOR bit22 + * + * Simply use bit 22 as the noise output. + */ + + OPL->noise_p += OPL->noise_f; + i = OPL->noise_p >> FREQ_SH; /* number of events (shifts of the shift register) */ + OPL->noise_p &= FREQ_MASK; + while (i) + { + /* + UINT32 j; + j = ( (OPL->noise_rng) ^ (OPL->noise_rng>>14) ^ (OPL->noise_rng>>15) ^ (OPL->noise_rng>>22) ) & 1; + OPL->noise_rng = (j<<22) | (OPL->noise_rng>>1); + */ + + /* + Instead of doing all the logic operations above, we + use a trick here (and use bit 0 as the noise output). + The difference is only that the noise bit changes one + step ahead. This doesn't matter since we don't know + what is real state of the noise_rng after the reset. + */ + + if (OPL->noise_rng & 1) OPL->noise_rng ^= 0x800302; + OPL->noise_rng >>= 1; + + i--; + } +} + + +INLINE signed int op_calc(UINT32 phase, unsigned int env, signed int pm, unsigned int wave_tab) +{ + UINT32 p; + + p = (env<<4) + sin_tab[wave_tab + ((((signed int)((phase & ~FREQ_MASK) + (pm<<16))) >> FREQ_SH ) & SIN_MASK) ]; + + if (p >= TL_TAB_LEN) + return 0; + return tl_tab[p]; +} + +INLINE signed int op_calc1(UINT32 phase, unsigned int env, signed int pm, unsigned int wave_tab) +{ + UINT32 p; + + p = (env<<4) + sin_tab[wave_tab + ((((signed int)((phase & ~FREQ_MASK) + pm )) >> FREQ_SH ) & SIN_MASK) ]; + + if (p >= TL_TAB_LEN) + return 0; + return tl_tab[p]; +} + + +#define volume_calc(OP) ((OP)->TLL + ((UINT32)(OP)->volume) + (OPL->LFO_AM & (OP)->AMmask)) + +/* calculate output */ +INLINE void OPL_CALC_CH( FM_OPL *OPL, OPL_CH *CH ) +{ + OPL_SLOT *SLOT; + unsigned int env; + signed int out; + + OPL->phase_modulation = 0; + + /* SLOT 1 */ + SLOT = &CH->SLOT[SLOT1]; + env = volume_calc(SLOT); + out = SLOT->op1_out[0] + SLOT->op1_out[1]; + SLOT->op1_out[0] = SLOT->op1_out[1]; + *SLOT->connect1 += SLOT->op1_out[0]; + SLOT->op1_out[1] = 0; + if( env < ENV_QUIET ) + { + if (!SLOT->FB) + out = 0; + SLOT->op1_out[1] = op_calc1(SLOT->Cnt, env, (out<FB), SLOT->wavetable ); + } + + /* SLOT 2 */ + SLOT++; + env = volume_calc(SLOT); + if( env < ENV_QUIET ) + OPL->output[0] += op_calc(SLOT->Cnt, env, OPL->phase_modulation, SLOT->wavetable); +} + +/* + operators used in the rhythm sounds generation process: + + Envelope Generator: + +channel operator register number Bass High Snare Tom Top +/ slot number TL ARDR SLRR Wave Drum Hat Drum Tom Cymbal + 6 / 0 12 50 70 90 f0 + + 6 / 1 15 53 73 93 f3 + + 7 / 0 13 51 71 91 f1 + + 7 / 1 16 54 74 94 f4 + + 8 / 0 14 52 72 92 f2 + + 8 / 1 17 55 75 95 f5 + + + Phase Generator: + +channel operator register number Bass High Snare Tom Top +/ slot number MULTIPLE Drum Hat Drum Tom Cymbal + 6 / 0 12 30 + + 6 / 1 15 33 + + 7 / 0 13 31 + + + + 7 / 1 16 34 ----- n o t u s e d ----- + 8 / 0 14 32 + + 8 / 1 17 35 + + + +channel operator register number Bass High Snare Tom Top +number number BLK/FNUM2 FNUM Drum Hat Drum Tom Cymbal + 6 12,15 B6 A6 + + + 7 13,16 B7 A7 + + + + + 8 14,17 B8 A8 + + + + +*/ + +/* calculate rhythm */ + +INLINE void OPL_CALC_RH( FM_OPL *OPL, OPL_CH *CH, unsigned int noise ) +{ + OPL_SLOT *SLOT; + signed int out; + unsigned int env; + + + /* Bass Drum (verified on real YM3812): + - depends on the channel 6 'connect' register: + when connect = 0 it works the same as in normal (non-rhythm) mode (op1->op2->out) + when connect = 1 _only_ operator 2 is present on output (op2->out), operator 1 is ignored + - output sample always is multiplied by 2 + */ + + OPL->phase_modulation = 0; + /* SLOT 1 */ + SLOT = &CH[6].SLOT[SLOT1]; + env = volume_calc(SLOT); + + out = SLOT->op1_out[0] + SLOT->op1_out[1]; + SLOT->op1_out[0] = SLOT->op1_out[1]; + + if (!SLOT->CON) + OPL->phase_modulation = SLOT->op1_out[0]; + /* else ignore output of operator 1 */ + + SLOT->op1_out[1] = 0; + if( env < ENV_QUIET ) + { + if (!SLOT->FB) + out = 0; + SLOT->op1_out[1] = op_calc1(SLOT->Cnt, env, (out<FB), SLOT->wavetable ); + } + + /* SLOT 2 */ + SLOT++; + env = volume_calc(SLOT); + if( env < ENV_QUIET ) + OPL->output[0] += op_calc(SLOT->Cnt, env, OPL->phase_modulation, SLOT->wavetable) * 2; + + + /* Phase generation is based on: */ + /* HH (13) channel 7->slot 1 combined with channel 8->slot 2 (same combination as TOP CYMBAL but different output phases) */ + /* SD (16) channel 7->slot 1 */ + /* TOM (14) channel 8->slot 1 */ + /* TOP (17) channel 7->slot 1 combined with channel 8->slot 2 (same combination as HIGH HAT but different output phases) */ + + /* Envelope generation based on: */ + /* HH channel 7->slot1 */ + /* SD channel 7->slot2 */ + /* TOM channel 8->slot1 */ + /* TOP channel 8->slot2 */ + + + /* The following formulas can be well optimized. + I leave them in direct form for now (in case I've missed something). + */ + + /* High Hat (verified on real YM3812) */ + env = volume_calc(SLOT7_1); + if( env < ENV_QUIET ) + { + /* high hat phase generation: + phase = d0 or 234 (based on frequency only) + phase = 34 or 2d0 (based on noise) + */ + + /* base frequency derived from operator 1 in channel 7 */ + unsigned char bit7 = ((SLOT7_1->Cnt>>FREQ_SH)>>7)&1; + unsigned char bit3 = ((SLOT7_1->Cnt>>FREQ_SH)>>3)&1; + unsigned char bit2 = ((SLOT7_1->Cnt>>FREQ_SH)>>2)&1; + + unsigned char res1 = (bit2 ^ bit7) | bit3; + + /* when res1 = 0 phase = 0x000 | 0xd0; */ + /* when res1 = 1 phase = 0x200 | (0xd0>>2); */ + UINT32 phase = res1 ? (0x200|(0xd0>>2)) : 0xd0; + + /* enable gate based on frequency of operator 2 in channel 8 */ + unsigned char bit5e= ((SLOT8_2->Cnt>>FREQ_SH)>>5)&1; + unsigned char bit3e= ((SLOT8_2->Cnt>>FREQ_SH)>>3)&1; + + unsigned char res2 = (bit3e ^ bit5e); + + /* when res2 = 0 pass the phase from calculation above (res1); */ + /* when res2 = 1 phase = 0x200 | (0xd0>>2); */ + if (res2) + phase = (0x200|(0xd0>>2)); + + + /* when phase & 0x200 is set and noise=1 then phase = 0x200|0xd0 */ + /* when phase & 0x200 is set and noise=0 then phase = 0x200|(0xd0>>2), ie no change */ + if (phase&0x200) + { + if (noise) + phase = 0x200|0xd0; + } + else + /* when phase & 0x200 is clear and noise=1 then phase = 0xd0>>2 */ + /* when phase & 0x200 is clear and noise=0 then phase = 0xd0, ie no change */ + { + if (noise) + phase = 0xd0>>2; + } + + OPL->output[0] += op_calc(phase<wavetable) * 2; + } + + /* Snare Drum (verified on real YM3812) */ + env = volume_calc(SLOT7_2); + if( env < ENV_QUIET ) + { + /* base frequency derived from operator 1 in channel 7 */ + unsigned char bit8 = ((SLOT7_1->Cnt>>FREQ_SH)>>8)&1; + + /* when bit8 = 0 phase = 0x100; */ + /* when bit8 = 1 phase = 0x200; */ + UINT32 phase = bit8 ? 0x200 : 0x100; + + /* Noise bit XOR'es phase by 0x100 */ + /* when noisebit = 0 pass the phase from calculation above */ + /* when noisebit = 1 phase ^= 0x100; */ + /* in other words: phase ^= (noisebit<<8); */ + if (noise) + phase ^= 0x100; + + OPL->output[0] += op_calc(phase<wavetable) * 2; + } + + /* Tom Tom (verified on real YM3812) */ + env = volume_calc(SLOT8_1); + if( env < ENV_QUIET ) + OPL->output[0] += op_calc(SLOT8_1->Cnt, env, 0, SLOT8_1->wavetable) * 2; + + /* Top Cymbal (verified on real YM3812) */ + env = volume_calc(SLOT8_2); + if( env < ENV_QUIET ) + { + /* base frequency derived from operator 1 in channel 7 */ + unsigned char bit7 = ((SLOT7_1->Cnt>>FREQ_SH)>>7)&1; + unsigned char bit3 = ((SLOT7_1->Cnt>>FREQ_SH)>>3)&1; + unsigned char bit2 = ((SLOT7_1->Cnt>>FREQ_SH)>>2)&1; + + unsigned char res1 = (bit2 ^ bit7) | bit3; + + /* when res1 = 0 phase = 0x000 | 0x100; */ + /* when res1 = 1 phase = 0x200 | 0x100; */ + UINT32 phase = res1 ? 0x300 : 0x100; + + /* enable gate based on frequency of operator 2 in channel 8 */ + unsigned char bit5e= ((SLOT8_2->Cnt>>FREQ_SH)>>5)&1; + unsigned char bit3e= ((SLOT8_2->Cnt>>FREQ_SH)>>3)&1; + + unsigned char res2 = (bit3e ^ bit5e); + /* when res2 = 0 pass the phase from calculation above (res1); */ + /* when res2 = 1 phase = 0x200 | 0x100; */ + if (res2) + phase = 0x300; + + OPL->output[0] += op_calc(phase<wavetable) * 2; + } +} + + +/* generic table initialize */ +static int init_tables(void) +{ + signed int i,x; + signed int n; + double o,m; + + + for (x=0; x>= 4; /* 12 bits here */ + if (n&1) /* round to nearest */ + n = (n>>1)+1; + else + n = n>>1; + /* 11 bits here (rounded) */ + n <<= 1; /* 12 bits here (as in real chip) */ + tl_tab[ x*2 + 0 ] = n; + tl_tab[ x*2 + 1 ] = -tl_tab[ x*2 + 0 ]; + + for (i=1; i<12; i++) + { + tl_tab[ x*2+0 + i*2*TL_RES_LEN ] = tl_tab[ x*2+0 ]>>i; + tl_tab[ x*2+1 + i*2*TL_RES_LEN ] = -tl_tab[ x*2+0 + i*2*TL_RES_LEN ]; + } + #if 0 + logerror("tl %04i", x*2); + for (i=0; i<12; i++) + logerror(", [%02i] %5i", i*2, tl_tab[ x*2 /*+1*/ + i*2*TL_RES_LEN ] ); + logerror("\n"); + #endif + } + /*logerror("FMOPL.C: TL_TAB_LEN = %i elements (%i bytes)\n",TL_TAB_LEN, (int)sizeof(tl_tab));*/ + + + for (i=0; i0.0) + o = 8*log(1.0/m)/log(2.0); /* convert to 'decibels' */ + else + o = 8*log(-1.0/m)/log(2.0); /* convert to 'decibels' */ + + o = o / (ENV_STEP/4); + + n = (int)(2.0*o); + if (n&1) /* round to nearest */ + n = (n>>1)+1; + else + n = n>>1; + + sin_tab[ i ] = n*2 + (m>=0.0? 0: 1 ); + + /*logerror("FMOPL.C: sin [%4i (hex=%03x)]= %4i (tl_tab value=%5i)\n", i, i, sin_tab[i], tl_tab[sin_tab[i]] );*/ + } + + for (i=0; i>1) ]; + + /* waveform 3: _ _ _ _ */ + /* / |_/ |_/ |_/ |_*/ + /* abs(output only first quarter of the sinus waveform) */ + + if (i & (1<<(SIN_BITS-2)) ) + sin_tab[3*SIN_LEN+i] = TL_TAB_LEN; + else + sin_tab[3*SIN_LEN+i] = sin_tab[i & (SIN_MASK>>2)]; + + /*logerror("FMOPL.C: sin1[%4i]= %4i (tl_tab value=%5i)\n", i, sin_tab[1*SIN_LEN+i], tl_tab[sin_tab[1*SIN_LEN+i]] ); + logerror("FMOPL.C: sin2[%4i]= %4i (tl_tab value=%5i)\n", i, sin_tab[2*SIN_LEN+i], tl_tab[sin_tab[2*SIN_LEN+i]] ); + logerror("FMOPL.C: sin3[%4i]= %4i (tl_tab value=%5i)\n", i, sin_tab[3*SIN_LEN+i], tl_tab[sin_tab[3*SIN_LEN+i]] );*/ + } + /*logerror("FMOPL.C: ENV_QUIET= %08x (dec*8=%i)\n", ENV_QUIET, ENV_QUIET*8 );*/ + + +#ifdef SAVE_SAMPLE + sample[0]=fopen("sampsum.pcm","wb"); +#endif + + return 1; +} + +static void OPLCloseTable( void ) +{ +#ifdef SAVE_SAMPLE + fclose(sample[0]); +#endif +} + + + +static void OPL_initalize(FM_OPL *OPL) +{ + int i; + + /* frequency base */ + OPL->freqbase = (OPL->rate) ? ((double)OPL->clock / 72.0) / OPL->rate : 0; +#if 0 + OPL->rate = (double)OPL->clock / 72.0; + OPL->freqbase = 1.0; +#endif + + /*logerror("freqbase=%f\n", OPL->freqbase);*/ + + /* Timer base time */ + OPL->TimerBase = attotime::from_hz(OPL->clock) * 72; + + /* make fnumber -> increment counter table */ + for( i=0 ; i < 1024 ; i++ ) + { + /* opn phase increment counter = 20bit */ + OPL->fn_tab[i] = (UINT32)( (double)i * 64 * OPL->freqbase * (1<<(FREQ_SH-10)) ); /* -10 because chip works with 10.10 fixed point, while we use 16.16 */ +#if 0 + logerror("FMOPL.C: fn_tab[%4i] = %08x (dec=%8i)\n", + i, OPL->fn_tab[i]>>6, OPL->fn_tab[i]>>6 ); +#endif + } + +#if 0 + for( i=0 ; i < 16 ; i++ ) + { + logerror("FMOPL.C: sl_tab[%i] = %08x\n", + i, sl_tab[i] ); + } + for( i=0 ; i < 8 ; i++ ) + { + int j; + logerror("FMOPL.C: ksl_tab[oct=%2i] =",i); + for (j=0; j<16; j++) + { + logerror("%08x ", ksl_tab[i*16+j] ); + } + logerror("\n"); + } +#endif + + + /* Amplitude modulation: 27 output levels (triangle waveform); 1 level takes one of: 192, 256 or 448 samples */ + /* One entry from LFO_AM_TABLE lasts for 64 samples */ + OPL->lfo_am_inc = (1.0 / 64.0 ) * (1<freqbase; + + /* Vibrato: 8 output levels (triangle waveform); 1 level takes 1024 samples */ + OPL->lfo_pm_inc = (1.0 / 1024.0) * (1<freqbase; + + /*logerror ("OPL->lfo_am_inc = %8x ; OPL->lfo_pm_inc = %8x\n", OPL->lfo_am_inc, OPL->lfo_pm_inc);*/ + + /* Noise generator: a step takes 1 sample */ + OPL->noise_f = (1.0 / 1.0) * (1<freqbase; + + OPL->eg_timer_add = (1<freqbase; + OPL->eg_timer_overflow = ( 1 ) * (1<eg_timer_add, OPL->eg_timer_overflow);*/ + +} + +INLINE void FM_KEYON(OPL_SLOT *SLOT, UINT32 key_set) +{ + if( !SLOT->key ) + { + /* restart Phase Generator */ + SLOT->Cnt = 0; + /* phase -> Attack */ + SLOT->state = EG_ATT; + } + SLOT->key |= key_set; +} + +INLINE void FM_KEYOFF(OPL_SLOT *SLOT, UINT32 key_clr) +{ + if( SLOT->key ) + { + SLOT->key &= key_clr; + + if( !SLOT->key ) + { + /* phase -> Release */ + if (SLOT->state>EG_REL) + SLOT->state = EG_REL; + } + } +} + +/* update phase increment counter of operator (also update the EG rates if necessary) */ +INLINE void CALC_FCSLOT(OPL_CH *CH,OPL_SLOT *SLOT) +{ + int ksr; + + /* (frequency) phase increment counter */ + SLOT->Incr = CH->fc * SLOT->mul; + ksr = CH->kcode >> SLOT->KSR; + + if( SLOT->ksr != ksr ) + { + SLOT->ksr = ksr; + + /* calculate envelope generator rates */ + if ((SLOT->ar + SLOT->ksr) < 16+62) + { + SLOT->eg_sh_ar = eg_rate_shift [SLOT->ar + SLOT->ksr ]; + SLOT->eg_sel_ar = eg_rate_select[SLOT->ar + SLOT->ksr ]; + } + else + { + SLOT->eg_sh_ar = 0; + SLOT->eg_sel_ar = 13*RATE_STEPS; + } + SLOT->eg_sh_dr = eg_rate_shift [SLOT->dr + SLOT->ksr ]; + SLOT->eg_sel_dr = eg_rate_select[SLOT->dr + SLOT->ksr ]; + SLOT->eg_sh_rr = eg_rate_shift [SLOT->rr + SLOT->ksr ]; + SLOT->eg_sel_rr = eg_rate_select[SLOT->rr + SLOT->ksr ]; + } +} + +/* set multi,am,vib,EG-TYP,KSR,mul */ +INLINE void set_mul(FM_OPL *OPL,int slot,int v) +{ + OPL_CH *CH = &OPL->P_CH[slot/2]; + OPL_SLOT *SLOT = &CH->SLOT[slot&1]; + + SLOT->mul = mul_tab[v&0x0f]; + SLOT->KSR = (v&0x10) ? 0 : 2; + SLOT->eg_type = (v&0x20); + SLOT->vib = (v&0x40); + SLOT->AMmask = (v&0x80) ? ~0 : 0; + CALC_FCSLOT(CH,SLOT); +} + +/* set ksl & tl */ +INLINE void set_ksl_tl(FM_OPL *OPL,int slot,int v) +{ + OPL_CH *CH = &OPL->P_CH[slot/2]; + OPL_SLOT *SLOT = &CH->SLOT[slot&1]; + + SLOT->ksl = ksl_shift[v >> 6]; + SLOT->TL = (v&0x3f)<<(ENV_BITS-1-7); /* 7 bits TL (bit 6 = always 0) */ + + SLOT->TLL = SLOT->TL + (CH->ksl_base>>SLOT->ksl); +} + +/* set attack rate & decay rate */ +INLINE void set_ar_dr(FM_OPL *OPL,int slot,int v) +{ + OPL_CH *CH = &OPL->P_CH[slot/2]; + OPL_SLOT *SLOT = &CH->SLOT[slot&1]; + + SLOT->ar = (v>>4) ? 16 + ((v>>4) <<2) : 0; + + if ((SLOT->ar + SLOT->ksr) < 16+62) + { + SLOT->eg_sh_ar = eg_rate_shift [SLOT->ar + SLOT->ksr ]; + SLOT->eg_sel_ar = eg_rate_select[SLOT->ar + SLOT->ksr ]; + } + else + { + SLOT->eg_sh_ar = 0; + SLOT->eg_sel_ar = 13*RATE_STEPS; + } + + SLOT->dr = (v&0x0f)? 16 + ((v&0x0f)<<2) : 0; + SLOT->eg_sh_dr = eg_rate_shift [SLOT->dr + SLOT->ksr ]; + SLOT->eg_sel_dr = eg_rate_select[SLOT->dr + SLOT->ksr ]; +} + +/* set sustain level & release rate */ +INLINE void set_sl_rr(FM_OPL *OPL,int slot,int v) +{ + OPL_CH *CH = &OPL->P_CH[slot/2]; + OPL_SLOT *SLOT = &CH->SLOT[slot&1]; + + SLOT->sl = sl_tab[ v>>4 ]; + + SLOT->rr = (v&0x0f)? 16 + ((v&0x0f)<<2) : 0; + SLOT->eg_sh_rr = eg_rate_shift [SLOT->rr + SLOT->ksr ]; + SLOT->eg_sel_rr = eg_rate_select[SLOT->rr + SLOT->ksr ]; +} + + +/* write a value v to register r on OPL chip */ +static void OPLWriteReg(FM_OPL *OPL, int r, int v) +{ + OPL_CH *CH; + int slot; + int block_fnum; + + + /* adjust bus to 8 bits */ + r &= 0xff; + v &= 0xff; + + if (LOG_CYM_FILE && (cymfile) && (r!=0) ) + { + fputc( (unsigned char)r, cymfile ); + fputc( (unsigned char)v, cymfile ); + } + + + switch(r&0xe0) + { + case 0x00: /* 00-1f:control */ + switch(r&0x1f) + { + case 0x01: /* waveform select enable */ + if(OPL->type&OPL_TYPE_WAVESEL) + { + OPL->wavesel = v&0x20; + /* do not change the waveform previously selected */ + } + break; + case 0x02: /* Timer 1 */ + OPL->T[0] = (256-v)*4; + break; + case 0x03: /* Timer 2 */ + OPL->T[1] = (256-v)*16; + break; + case 0x04: /* IRQ clear / mask and Timer enable */ + if(v&0x80) + { /* IRQ flag clear */ + OPL_STATUS_RESET(OPL,0x7f-0x08); /* don't reset BFRDY flag or we will have to call deltat module to set the flag */ + } + else + { /* set IRQ mask ,timer enable*/ + UINT8 st1 = v&1; + UINT8 st2 = (v>>1)&1; + + /* IRQRST,T1MSK,t2MSK,EOSMSK,BRMSK,x,ST2,ST1 */ + OPL_STATUS_RESET(OPL, v & (0x78-0x08) ); + OPL_STATUSMASK_SET(OPL, (~v) & 0x78 ); + + /* timer 2 */ + if(OPL->st[1] != st2) + { + attotime period = st2 ? (OPL->TimerBase * OPL->T[1]) : attotime::zero; + OPL->st[1] = st2; + if (OPL->timer_handler) (OPL->timer_handler)(OPL->TimerParam,1,period); + } + /* timer 1 */ + if(OPL->st[0] != st1) + { + attotime period = st1 ? (OPL->TimerBase * OPL->T[0]) : attotime::zero; + OPL->st[0] = st1; + if (OPL->timer_handler) (OPL->timer_handler)(OPL->TimerParam,0,period); + } + } + break; +#if BUILD_Y8950 + case 0x06: /* Key Board OUT */ + if(OPL->type&OPL_TYPE_KEYBOARD) + { + if(OPL->keyboardhandler_w) + OPL->keyboardhandler_w(OPL->keyboard_param,v); + else + logerror("Y8950: write unmapped KEYBOARD port\n"); + } + break; + case 0x07: /* DELTA-T control 1 : START,REC,MEMDATA,REPT,SPOFF,x,x,RST */ + if(OPL->type&OPL_TYPE_ADPCM) + YM_DELTAT_ADPCM_Write(OPL->deltat,r-0x07,v); + break; +#endif + case 0x08: /* MODE,DELTA-T control 2 : CSM,NOTESEL,x,x,smpl,da/ad,64k,rom */ + OPL->mode = v; +#if BUILD_Y8950 + if(OPL->type&OPL_TYPE_ADPCM) + YM_DELTAT_ADPCM_Write(OPL->deltat,r-0x07,v&0x0f); /* mask 4 LSBs in register 08 for DELTA-T unit */ +#endif + break; + +#if BUILD_Y8950 + case 0x09: /* START ADD */ + case 0x0a: + case 0x0b: /* STOP ADD */ + case 0x0c: + case 0x0d: /* PRESCALE */ + case 0x0e: + case 0x0f: /* ADPCM data write */ + case 0x10: /* DELTA-N */ + case 0x11: /* DELTA-N */ + case 0x12: /* ADPCM volume */ + if(OPL->type&OPL_TYPE_ADPCM) + YM_DELTAT_ADPCM_Write(OPL->deltat,r-0x07,v); + break; + + case 0x15: /* DAC data high 8 bits (F7,F6...F2) */ + case 0x16: /* DAC data low 2 bits (F1, F0 in bits 7,6) */ + case 0x17: /* DAC data shift (S2,S1,S0 in bits 2,1,0) */ + logerror("FMOPL.C: DAC data register written, but not implemented reg=%02x val=%02x\n",r,v); + break; + + case 0x18: /* I/O CTRL (Direction) */ + if(OPL->type&OPL_TYPE_IO) + OPL->portDirection = v&0x0f; + break; + case 0x19: /* I/O DATA */ + if(OPL->type&OPL_TYPE_IO) + { + OPL->portLatch = v; + if(OPL->porthandler_w) + OPL->porthandler_w(OPL->port_param,v&OPL->portDirection); + } + break; +#endif + default: + logerror("FMOPL.C: write to unknown register: %02x\n",r); + break; + } + break; + case 0x20: /* am ON, vib ON, ksr, eg_type, mul */ + slot = slot_array[r&0x1f]; + if(slot < 0) return; + set_mul(OPL,slot,v); + break; + case 0x40: + slot = slot_array[r&0x1f]; + if(slot < 0) return; + set_ksl_tl(OPL,slot,v); + break; + case 0x60: + slot = slot_array[r&0x1f]; + if(slot < 0) return; + set_ar_dr(OPL,slot,v); + break; + case 0x80: + slot = slot_array[r&0x1f]; + if(slot < 0) return; + set_sl_rr(OPL,slot,v); + break; + case 0xa0: + if (r == 0xbd) /* am depth, vibrato depth, r,bd,sd,tom,tc,hh */ + { + OPL->lfo_am_depth = v & 0x80; + OPL->lfo_pm_depth_range = (v&0x40) ? 8 : 0; + + OPL->rhythm = v&0x3f; + + if(OPL->rhythm&0x20) + { + /* BD key on/off */ + if(v&0x10) + { + FM_KEYON (&OPL->P_CH[6].SLOT[SLOT1], 2); + FM_KEYON (&OPL->P_CH[6].SLOT[SLOT2], 2); + } + else + { + FM_KEYOFF(&OPL->P_CH[6].SLOT[SLOT1],~2); + FM_KEYOFF(&OPL->P_CH[6].SLOT[SLOT2],~2); + } + /* HH key on/off */ + if(v&0x01) FM_KEYON (&OPL->P_CH[7].SLOT[SLOT1], 2); + else FM_KEYOFF(&OPL->P_CH[7].SLOT[SLOT1],~2); + /* SD key on/off */ + if(v&0x08) FM_KEYON (&OPL->P_CH[7].SLOT[SLOT2], 2); + else FM_KEYOFF(&OPL->P_CH[7].SLOT[SLOT2],~2); + /* TOM key on/off */ + if(v&0x04) FM_KEYON (&OPL->P_CH[8].SLOT[SLOT1], 2); + else FM_KEYOFF(&OPL->P_CH[8].SLOT[SLOT1],~2); + /* TOP-CY key on/off */ + if(v&0x02) FM_KEYON (&OPL->P_CH[8].SLOT[SLOT2], 2); + else FM_KEYOFF(&OPL->P_CH[8].SLOT[SLOT2],~2); + } + else + { + /* BD key off */ + FM_KEYOFF(&OPL->P_CH[6].SLOT[SLOT1],~2); + FM_KEYOFF(&OPL->P_CH[6].SLOT[SLOT2],~2); + /* HH key off */ + FM_KEYOFF(&OPL->P_CH[7].SLOT[SLOT1],~2); + /* SD key off */ + FM_KEYOFF(&OPL->P_CH[7].SLOT[SLOT2],~2); + /* TOM key off */ + FM_KEYOFF(&OPL->P_CH[8].SLOT[SLOT1],~2); + /* TOP-CY off */ + FM_KEYOFF(&OPL->P_CH[8].SLOT[SLOT2],~2); + } + return; + } + /* keyon,block,fnum */ + if( (r&0x0f) > 8) return; + CH = &OPL->P_CH[r&0x0f]; + if(!(r&0x10)) + { /* a0-a8 */ + block_fnum = (CH->block_fnum&0x1f00) | v; + } + else + { /* b0-b8 */ + block_fnum = ((v&0x1f)<<8) | (CH->block_fnum&0xff); + + if(v&0x20) + { + FM_KEYON (&CH->SLOT[SLOT1], 1); + FM_KEYON (&CH->SLOT[SLOT2], 1); + } + else + { + FM_KEYOFF(&CH->SLOT[SLOT1],~1); + FM_KEYOFF(&CH->SLOT[SLOT2],~1); + } + } + /* update */ + if(CH->block_fnum != block_fnum) + { + UINT8 block = block_fnum >> 10; + + CH->block_fnum = block_fnum; + + CH->ksl_base = ksl_tab[block_fnum>>6]; + CH->fc = OPL->fn_tab[block_fnum&0x03ff] >> (7-block); + + /* BLK 2,1,0 bits -> bits 3,2,1 of kcode */ + CH->kcode = (CH->block_fnum&0x1c00)>>9; + + /* the info below is actually opposite to what is stated in the Manuals (verifed on real YM3812) */ + /* if notesel == 0 -> lsb of kcode is bit 10 (MSB) of fnum */ + /* if notesel == 1 -> lsb of kcode is bit 9 (MSB-1) of fnum */ + if (OPL->mode&0x40) + CH->kcode |= (CH->block_fnum&0x100)>>8; /* notesel == 1 */ + else + CH->kcode |= (CH->block_fnum&0x200)>>9; /* notesel == 0 */ + + /* refresh Total Level in both SLOTs of this channel */ + CH->SLOT[SLOT1].TLL = CH->SLOT[SLOT1].TL + (CH->ksl_base>>CH->SLOT[SLOT1].ksl); + CH->SLOT[SLOT2].TLL = CH->SLOT[SLOT2].TL + (CH->ksl_base>>CH->SLOT[SLOT2].ksl); + + /* refresh frequency counter in both SLOTs of this channel */ + CALC_FCSLOT(CH,&CH->SLOT[SLOT1]); + CALC_FCSLOT(CH,&CH->SLOT[SLOT2]); + } + break; + case 0xc0: + /* FB,C */ + if( (r&0x0f) > 8) return; + CH = &OPL->P_CH[r&0x0f]; + CH->SLOT[SLOT1].FB = (v>>1)&7 ? ((v>>1)&7) + 7 : 0; + CH->SLOT[SLOT1].CON = v&1; + CH->SLOT[SLOT1].connect1 = CH->SLOT[SLOT1].CON ? &OPL->output[0] : &OPL->phase_modulation; + break; + case 0xe0: /* waveform select */ + /* simply ignore write to the waveform select register if selecting not enabled in test register */ + if(OPL->wavesel) + { + slot = slot_array[r&0x1f]; + if(slot < 0) return; + CH = &OPL->P_CH[slot/2]; + + CH->SLOT[slot&1].wavetable = (v&0x03)*SIN_LEN; + } + break; + } +} + +static TIMER_CALLBACK( cymfile_callback ) +{ + if (cymfile) + { + fputc( (unsigned char)0, cymfile ); + } +} + +/* lock/unlock for common table */ +static int OPL_LockTable(device_t *device) +{ + num_lock++; + if(num_lock>1) return 0; + + /* first time */ + + /* allocate total level table (128kb space) */ + if( !init_tables() ) + { + num_lock--; + return -1; + } + + if (LOG_CYM_FILE) + { + cymfile = fopen("3812_.cym","wb"); + if (cymfile) + device->machine().scheduler().timer_pulse ( attotime::from_hz(110), FUNC(cymfile_callback)); /*110 Hz pulse timer*/ + else + logerror("Could not create file 3812_.cym\n"); + } + + return 0; +} + +static void OPL_UnLockTable(void) +{ + if(num_lock) num_lock--; + if(num_lock) return; + + /* last time */ + + OPLCloseTable(); + + if (cymfile) + fclose (cymfile); + cymfile = NULL; +} + +static void OPLResetChip(FM_OPL *OPL) +{ + int c,s; + int i; + + OPL->eg_timer = 0; + OPL->eg_cnt = 0; + + OPL->noise_rng = 1; /* noise shift register */ + OPL->mode = 0; /* normal mode */ + OPL_STATUS_RESET(OPL,0x7f); + + /* reset with register write */ + OPLWriteReg(OPL,0x01,0); /* wavesel disable */ + OPLWriteReg(OPL,0x02,0); /* Timer1 */ + OPLWriteReg(OPL,0x03,0); /* Timer2 */ + OPLWriteReg(OPL,0x04,0); /* IRQ mask clear */ + for(i = 0xff ; i >= 0x20 ; i-- ) OPLWriteReg(OPL,i,0); + + /* reset operator parameters */ + for( c = 0 ; c < 9 ; c++ ) + { + OPL_CH *CH = &OPL->P_CH[c]; + for(s = 0 ; s < 2 ; s++ ) + { + /* wave table */ + CH->SLOT[s].wavetable = 0; + CH->SLOT[s].state = EG_OFF; + CH->SLOT[s].volume = MAX_ATT_INDEX; + } + } +#if BUILD_Y8950 + if(OPL->type&OPL_TYPE_ADPCM) + { + YM_DELTAT *DELTAT = OPL->deltat; + + DELTAT->freqbase = OPL->freqbase; + DELTAT->output_pointer = &OPL->output_deltat[0]; + DELTAT->portshift = 5; + DELTAT->output_range = 1<<23; + YM_DELTAT_ADPCM_Reset(DELTAT,0,YM_DELTAT_EMULATION_MODE_NORMAL); + } +#endif +} + + +static void OPL_postload(FM_OPL *OPL) +{ + int slot, ch; + + for( ch=0 ; ch < 9 ; ch++ ) + { + OPL_CH *CH = &OPL->P_CH[ch]; + + /* Look up key scale level */ + UINT32 block_fnum = CH->block_fnum; + CH->ksl_base = ksl_tab[block_fnum >> 6]; + CH->fc = OPL->fn_tab[block_fnum & 0x03ff] >> (7 - (block_fnum >> 10)); + + for( slot=0 ; slot < 2 ; slot++ ) + { + OPL_SLOT *SLOT = &CH->SLOT[slot]; + + /* Calculate key scale rate */ + SLOT->ksr = CH->kcode >> SLOT->KSR; + + /* Calculate attack, decay and release rates */ + if ((SLOT->ar + SLOT->ksr) < 16+62) + { + SLOT->eg_sh_ar = eg_rate_shift [SLOT->ar + SLOT->ksr ]; + SLOT->eg_sel_ar = eg_rate_select[SLOT->ar + SLOT->ksr ]; + } + else + { + SLOT->eg_sh_ar = 0; + SLOT->eg_sel_ar = 13*RATE_STEPS; + } + SLOT->eg_sh_dr = eg_rate_shift [SLOT->dr + SLOT->ksr ]; + SLOT->eg_sel_dr = eg_rate_select[SLOT->dr + SLOT->ksr ]; + SLOT->eg_sh_rr = eg_rate_shift [SLOT->rr + SLOT->ksr ]; + SLOT->eg_sel_rr = eg_rate_select[SLOT->rr + SLOT->ksr ]; + + /* Calculate phase increment */ + SLOT->Incr = CH->fc * SLOT->mul; + + /* Total level */ + SLOT->TLL = SLOT->TL + (CH->ksl_base >> SLOT->ksl); + + /* Connect output */ + SLOT->connect1 = SLOT->CON ? &OPL->output[0] : &OPL->phase_modulation; + } + } +#if BUILD_Y8950 + if ( (OPL->type & OPL_TYPE_ADPCM) && (OPL->deltat) ) + { + // We really should call the postlod function for the YM_DELTAT, but it's hard without registers + // (see the way the YM2610 does it) + //YM_DELTAT_postload(OPL->deltat, REGS); + } +#endif +} + + +static void OPLsave_state_channel(device_t *device, OPL_CH *CH) +{ + int slot, ch; + + for( ch=0 ; ch < 9 ; ch++, CH++ ) + { + /* channel */ + device->save_item(NAME(CH->block_fnum), ch); + device->save_item(NAME(CH->kcode), ch); + /* slots */ + for( slot=0 ; slot < 2 ; slot++ ) + { + OPL_SLOT *SLOT = &CH->SLOT[slot]; + + device->save_item(NAME(SLOT->ar), ch * 2 + slot); + device->save_item(NAME(SLOT->dr), ch * 2 + slot); + device->save_item(NAME(SLOT->rr), ch * 2 + slot); + device->save_item(NAME(SLOT->KSR), ch * 2 + slot); + device->save_item(NAME(SLOT->ksl), ch * 2 + slot); + device->save_item(NAME(SLOT->mul), ch * 2 + slot); + + device->save_item(NAME(SLOT->Cnt), ch * 2 + slot); + device->save_item(NAME(SLOT->FB), ch * 2 + slot); + device->save_item(NAME(SLOT->op1_out), ch * 2 + slot); + device->save_item(NAME(SLOT->CON), ch * 2 + slot); + + device->save_item(NAME(SLOT->eg_type), ch * 2 + slot); + device->save_item(NAME(SLOT->state), ch * 2 + slot); + device->save_item(NAME(SLOT->TL), ch * 2 + slot); + device->save_item(NAME(SLOT->volume), ch * 2 + slot); + device->save_item(NAME(SLOT->sl), ch * 2 + slot); + device->save_item(NAME(SLOT->key), ch * 2 + slot); + + device->save_item(NAME(SLOT->AMmask), ch * 2 + slot); + device->save_item(NAME(SLOT->vib), ch * 2 + slot); + + device->save_item(NAME(SLOT->wavetable), ch * 2 + slot); + } + } +} + + +/* Register savestate for a virtual YM3812/YM3526Y8950 */ + +static void OPL_save_state(FM_OPL *OPL, device_t *device) +{ + OPLsave_state_channel(device, OPL->P_CH); + + device->save_item(NAME(OPL->eg_cnt)); + device->save_item(NAME(OPL->eg_timer)); + + device->save_item(NAME(OPL->rhythm)); + + device->save_item(NAME(OPL->lfo_am_depth)); + device->save_item(NAME(OPL->lfo_pm_depth_range)); + device->save_item(NAME(OPL->lfo_am_cnt)); + device->save_item(NAME(OPL->lfo_pm_cnt)); + + device->save_item(NAME(OPL->noise_rng)); + device->save_item(NAME(OPL->noise_p)); + + if( OPL->type & OPL_TYPE_WAVESEL ) + { + device->save_item(NAME(OPL->wavesel)); + } + + device->save_item(NAME(OPL->T)); + device->save_item(NAME(OPL->st)); + +#if BUILD_Y8950 + if ( (OPL->type & OPL_TYPE_ADPCM) && (OPL->deltat) ) + { + YM_DELTAT_savestate(device, OPL->deltat); + } + + if ( OPL->type & OPL_TYPE_IO ) + { + device->save_item(NAME(OPL->portDirection)); + device->save_item(NAME(OPL->portLatch)); + } +#endif + + device->save_item(NAME(OPL->address)); + device->save_item(NAME(OPL->status)); + device->save_item(NAME(OPL->statusmask)); + device->save_item(NAME(OPL->mode)); + + device->machine().save().register_postload(save_prepost_delegate(FUNC(OPL_postload), OPL)); +} + + +/* Create one of virtual YM3812/YM3526/Y8950 */ +/* 'clock' is chip clock in Hz */ +/* 'rate' is sampling rate */ +static FM_OPL *OPLCreate(device_t *device, UINT32 clock, UINT32 rate, int type) +{ + char *ptr; + FM_OPL *OPL; + int state_size; + + if (OPL_LockTable(device) == -1) return NULL; + + /* calculate OPL state size */ + state_size = sizeof(FM_OPL); + +#if BUILD_Y8950 + if (type&OPL_TYPE_ADPCM) state_size+= sizeof(YM_DELTAT); +#endif + + /* allocate memory block */ + ptr = (char *)auto_alloc_array_clear(device->machine(), UINT8, state_size); + + OPL = (FM_OPL *)ptr; + + ptr += sizeof(FM_OPL); + +#if BUILD_Y8950 + if (type&OPL_TYPE_ADPCM) + { + OPL->deltat = (YM_DELTAT *)ptr; + } + ptr += sizeof(YM_DELTAT); +#endif + + OPL->device = device; + OPL->type = type; + OPL->clock = clock; + OPL->rate = rate; + + /* init global tables */ + OPL_initalize(OPL); + + return OPL; +} + +/* Destroy one of virtual YM3812 */ +static void OPLDestroy(FM_OPL *OPL) +{ + OPL_UnLockTable(); + auto_free(OPL->device->machine(), OPL); +} + +/* Optional handlers */ + +static void OPLSetTimerHandler(FM_OPL *OPL,OPL_TIMERHANDLER timer_handler,void *param) +{ + OPL->timer_handler = timer_handler; + OPL->TimerParam = param; +} +static void OPLSetIRQHandler(FM_OPL *OPL,OPL_IRQHANDLER IRQHandler,void *param) +{ + OPL->IRQHandler = IRQHandler; + OPL->IRQParam = param; +} +static void OPLSetUpdateHandler(FM_OPL *OPL,OPL_UPDATEHANDLER UpdateHandler,void *param) +{ + OPL->UpdateHandler = UpdateHandler; + OPL->UpdateParam = param; +} + +static int OPLWrite(FM_OPL *OPL,int a,int v) +{ + if( !(a&1) ) + { /* address port */ + OPL->address = v & 0xff; + } + else + { /* data port */ + if(OPL->UpdateHandler) OPL->UpdateHandler(OPL->UpdateParam,0); + OPLWriteReg(OPL,OPL->address,v); + } + return OPL->status>>7; +} + +static unsigned char OPLRead(FM_OPL *OPL,int a) +{ + if( !(a&1) ) + { + /* status port */ + + #if BUILD_Y8950 + + if(OPL->type&OPL_TYPE_ADPCM) /* Y8950 */ + { + return (OPL->status & (OPL->statusmask|0x80)) | (OPL->deltat->PCM_BSY&1); + } + + #endif + + /* OPL and OPL2 */ + return OPL->status & (OPL->statusmask|0x80); + } + +#if BUILD_Y8950 + /* data port */ + switch(OPL->address) + { + case 0x05: /* KeyBoard IN */ + if(OPL->type&OPL_TYPE_KEYBOARD) + { + if(OPL->keyboardhandler_r) + return OPL->keyboardhandler_r(OPL->keyboard_param); + else + logerror("Y8950: read unmapped KEYBOARD port\n"); + } + return 0; + + case 0x0f: /* ADPCM-DATA */ + if(OPL->type&OPL_TYPE_ADPCM) + { + UINT8 val; + + val = YM_DELTAT_ADPCM_Read(OPL->deltat); + /*logerror("Y8950: read ADPCM value read=%02x\n",val);*/ + return val; + } + return 0; + + case 0x19: /* I/O DATA */ + if(OPL->type&OPL_TYPE_IO) + { + if(OPL->porthandler_r) + return OPL->porthandler_r(OPL->port_param); + else + logerror("Y8950:read unmapped I/O port\n"); + } + return 0; + case 0x1a: /* PCM-DATA */ + if(OPL->type&OPL_TYPE_ADPCM) + { + logerror("Y8950 A/D convertion is accessed but not implemented !\n"); + return 0x80; /* 2's complement PCM data - result from A/D convertion */ + } + return 0; + } +#endif + + return 0xff; +} + +/* CSM Key Controll */ +INLINE void CSMKeyControll(OPL_CH *CH) +{ + FM_KEYON (&CH->SLOT[SLOT1], 4); + FM_KEYON (&CH->SLOT[SLOT2], 4); + + /* The key off should happen exactly one sample later - not implemented correctly yet */ + + FM_KEYOFF(&CH->SLOT[SLOT1], ~4); + FM_KEYOFF(&CH->SLOT[SLOT2], ~4); +} + + +static int OPLTimerOver(FM_OPL *OPL,int c) +{ + if( c ) + { /* Timer B */ + OPL_STATUS_SET(OPL,0x20); + } + else + { /* Timer A */ + OPL_STATUS_SET(OPL,0x40); + /* CSM mode key,TL controll */ + if( OPL->mode & 0x80 ) + { /* CSM mode total level latch and auto key on */ + int ch; + if(OPL->UpdateHandler) OPL->UpdateHandler(OPL->UpdateParam,0); + for(ch=0; ch<9; ch++) + CSMKeyControll( &OPL->P_CH[ch] ); + } + } + /* reload timer */ + if (OPL->timer_handler) (OPL->timer_handler)(OPL->TimerParam,c,OPL->TimerBase * OPL->T[c]); + return OPL->status>>7; +} + + +#define MAX_OPL_CHIPS 2 + + +#if (BUILD_YM3812) + +void * ym3812_init(device_t *device, UINT32 clock, UINT32 rate) +{ + /* emulator create */ + FM_OPL *YM3812 = OPLCreate(device,clock,rate,OPL_TYPE_YM3812); + if (YM3812) + { + OPL_save_state(YM3812, device); + ym3812_reset_chip(YM3812); + } + return YM3812; +} + +void ym3812_shutdown(void *chip) +{ + FM_OPL *YM3812 = (FM_OPL *)chip; + + /* emulator shutdown */ + OPLDestroy(YM3812); +} +void ym3812_reset_chip(void *chip) +{ + FM_OPL *YM3812 = (FM_OPL *)chip; + OPLResetChip(YM3812); +} + +int ym3812_write(void *chip, int a, int v) +{ + FM_OPL *YM3812 = (FM_OPL *)chip; + return OPLWrite(YM3812, a, v); +} + +unsigned char ym3812_read(void *chip, int a) +{ + FM_OPL *YM3812 = (FM_OPL *)chip; + /* YM3812 always returns bit2 and bit1 in HIGH state */ + return OPLRead(YM3812, a) | 0x06 ; +} +int ym3812_timer_over(void *chip, int c) +{ + FM_OPL *YM3812 = (FM_OPL *)chip; + return OPLTimerOver(YM3812, c); +} + +void ym3812_set_timer_handler(void *chip, OPL_TIMERHANDLER timer_handler, void *param) +{ + FM_OPL *YM3812 = (FM_OPL *)chip; + OPLSetTimerHandler(YM3812, timer_handler, param); +} +void ym3812_set_irq_handler(void *chip,OPL_IRQHANDLER IRQHandler,void *param) +{ + FM_OPL *YM3812 = (FM_OPL *)chip; + OPLSetIRQHandler(YM3812, IRQHandler, param); +} +void ym3812_set_update_handler(void *chip,OPL_UPDATEHANDLER UpdateHandler,void *param) +{ + FM_OPL *YM3812 = (FM_OPL *)chip; + OPLSetUpdateHandler(YM3812, UpdateHandler, param); +} + + +/* +** Generate samples for one of the YM3812's +** +** 'which' is the virtual YM3812 number +** '*buffer' is the output buffer pointer +** 'length' is the number of samples that should be generated +*/ +void ym3812_update_one(void *chip, OPLSAMPLE *buffer, int length) +{ + FM_OPL *OPL = (FM_OPL *)chip; + UINT8 rhythm = OPL->rhythm&0x20; + OPLSAMPLE *buf = buffer; + int i; + + for( i=0; i < length ; i++ ) + { + int lt; + + OPL->output[0] = 0; + + advance_lfo(OPL); + + /* FM part */ + OPL_CALC_CH(OPL, &OPL->P_CH[0]); + OPL_CALC_CH(OPL, &OPL->P_CH[1]); + OPL_CALC_CH(OPL, &OPL->P_CH[2]); + OPL_CALC_CH(OPL, &OPL->P_CH[3]); + OPL_CALC_CH(OPL, &OPL->P_CH[4]); + OPL_CALC_CH(OPL, &OPL->P_CH[5]); + + if(!rhythm) + { + OPL_CALC_CH(OPL, &OPL->P_CH[6]); + OPL_CALC_CH(OPL, &OPL->P_CH[7]); + OPL_CALC_CH(OPL, &OPL->P_CH[8]); + } + else /* Rhythm part */ + { + OPL_CALC_RH(OPL, &OPL->P_CH[0], (OPL->noise_rng>>0)&1 ); + } + + lt = OPL->output[0]; + + lt >>= FINAL_SH; + + /* limit check */ + lt = limit( lt , MAXOUT, MINOUT ); + + #ifdef SAVE_SAMPLE + if (which==0) + { + SAVE_ALL_CHANNELS + } + #endif + + /* store to sound buffer */ + buf[i] = lt; + + advance(OPL); + } + +} +#endif /* BUILD_YM3812 */ + + + +#if (BUILD_YM3526) + +void *ym3526_init(device_t *device, UINT32 clock, UINT32 rate) +{ + /* emulator create */ + FM_OPL *YM3526 = OPLCreate(device,clock,rate,OPL_TYPE_YM3526); + if (YM3526) + { + OPL_save_state(YM3526, device); + ym3526_reset_chip(YM3526); + } + return YM3526; +} + +void ym3526_shutdown(void *chip) +{ + FM_OPL *YM3526 = (FM_OPL *)chip; + /* emulator shutdown */ + OPLDestroy(YM3526); +} +void ym3526_reset_chip(void *chip) +{ + FM_OPL *YM3526 = (FM_OPL *)chip; + OPLResetChip(YM3526); +} + +int ym3526_write(void *chip, int a, int v) +{ + FM_OPL *YM3526 = (FM_OPL *)chip; + return OPLWrite(YM3526, a, v); +} + +unsigned char ym3526_read(void *chip, int a) +{ + FM_OPL *YM3526 = (FM_OPL *)chip; + /* YM3526 always returns bit2 and bit1 in HIGH state */ + return OPLRead(YM3526, a) | 0x06 ; +} +int ym3526_timer_over(void *chip, int c) +{ + FM_OPL *YM3526 = (FM_OPL *)chip; + return OPLTimerOver(YM3526, c); +} + +void ym3526_set_timer_handler(void *chip, OPL_TIMERHANDLER timer_handler, void *param) +{ + FM_OPL *YM3526 = (FM_OPL *)chip; + OPLSetTimerHandler(YM3526, timer_handler, param); +} +void ym3526_set_irq_handler(void *chip,OPL_IRQHANDLER IRQHandler,void *param) +{ + FM_OPL *YM3526 = (FM_OPL *)chip; + OPLSetIRQHandler(YM3526, IRQHandler, param); +} +void ym3526_set_update_handler(void *chip,OPL_UPDATEHANDLER UpdateHandler,void *param) +{ + FM_OPL *YM3526 = (FM_OPL *)chip; + OPLSetUpdateHandler(YM3526, UpdateHandler, param); +} + + +/* +** Generate samples for one of the YM3526's +** +** 'which' is the virtual YM3526 number +** '*buffer' is the output buffer pointer +** 'length' is the number of samples that should be generated +*/ +void ym3526_update_one(void *chip, OPLSAMPLE *buffer, int length) +{ + FM_OPL *OPL = (FM_OPL *)chip; + UINT8 rhythm = OPL->rhythm&0x20; + OPLSAMPLE *buf = buffer; + int i; + + for( i=0; i < length ; i++ ) + { + int lt; + + OPL->output[0] = 0; + + advance_lfo(OPL); + + /* FM part */ + OPL_CALC_CH(OPL, &OPL->P_CH[0]); + OPL_CALC_CH(OPL, &OPL->P_CH[1]); + OPL_CALC_CH(OPL, &OPL->P_CH[2]); + OPL_CALC_CH(OPL, &OPL->P_CH[3]); + OPL_CALC_CH(OPL, &OPL->P_CH[4]); + OPL_CALC_CH(OPL, &OPL->P_CH[5]); + + if(!rhythm) + { + OPL_CALC_CH(OPL, &OPL->P_CH[6]); + OPL_CALC_CH(OPL, &OPL->P_CH[7]); + OPL_CALC_CH(OPL, &OPL->P_CH[8]); + } + else /* Rhythm part */ + { + OPL_CALC_RH(OPL, &OPL->P_CH[0], (OPL->noise_rng>>0)&1 ); + } + + lt = OPL->output[0]; + + lt >>= FINAL_SH; + + /* limit check */ + lt = limit( lt , MAXOUT, MINOUT ); + + #ifdef SAVE_SAMPLE + if (which==0) + { + SAVE_ALL_CHANNELS + } + #endif + + /* store to sound buffer */ + buf[i] = lt; + + advance(OPL); + } + +} +#endif /* BUILD_YM3526 */ + + + + +#if BUILD_Y8950 + +static void Y8950_deltat_status_set(void *chip, UINT8 changebits) +{ + FM_OPL *Y8950 = (FM_OPL *)chip; + OPL_STATUS_SET(Y8950, changebits); +} +static void Y8950_deltat_status_reset(void *chip, UINT8 changebits) +{ + FM_OPL *Y8950 = (FM_OPL *)chip; + OPL_STATUS_RESET(Y8950, changebits); +} + +void *y8950_init(device_t *device, UINT32 clock, UINT32 rate) +{ + /* emulator create */ + FM_OPL *Y8950 = OPLCreate(device,clock,rate,OPL_TYPE_Y8950); + if (Y8950) + { + Y8950->deltat->status_set_handler = Y8950_deltat_status_set; + Y8950->deltat->status_reset_handler = Y8950_deltat_status_reset; + Y8950->deltat->status_change_which_chip = Y8950; + Y8950->deltat->status_change_EOS_bit = 0x10; /* status flag: set bit4 on End Of Sample */ + Y8950->deltat->status_change_BRDY_bit = 0x08; /* status flag: set bit3 on BRDY (End Of: ADPCM analysis/synthesis, memory reading/writing) */ + + /*Y8950->deltat->write_time = 10.0 / clock;*/ /* a single byte write takes 10 cycles of main clock */ + /*Y8950->deltat->read_time = 8.0 / clock;*/ /* a single byte read takes 8 cycles of main clock */ + /* reset */ + OPL_save_state(Y8950, device); + y8950_reset_chip(Y8950); + } + + return Y8950; +} + +void y8950_shutdown(void *chip) +{ + FM_OPL *Y8950 = (FM_OPL *)chip; + /* emulator shutdown */ + OPLDestroy(Y8950); +} +void y8950_reset_chip(void *chip) +{ + FM_OPL *Y8950 = (FM_OPL *)chip; + OPLResetChip(Y8950); +} + +int y8950_write(void *chip, int a, int v) +{ + FM_OPL *Y8950 = (FM_OPL *)chip; + return OPLWrite(Y8950, a, v); +} + +unsigned char y8950_read(void *chip, int a) +{ + FM_OPL *Y8950 = (FM_OPL *)chip; + return OPLRead(Y8950, a); +} +int y8950_timer_over(void *chip, int c) +{ + FM_OPL *Y8950 = (FM_OPL *)chip; + return OPLTimerOver(Y8950, c); +} + +void y8950_set_timer_handler(void *chip, OPL_TIMERHANDLER timer_handler, void *param) +{ + FM_OPL *Y8950 = (FM_OPL *)chip; + OPLSetTimerHandler(Y8950, timer_handler, param); +} +void y8950_set_irq_handler(void *chip,OPL_IRQHANDLER IRQHandler,void *param) +{ + FM_OPL *Y8950 = (FM_OPL *)chip; + OPLSetIRQHandler(Y8950, IRQHandler, param); +} +void y8950_set_update_handler(void *chip,OPL_UPDATEHANDLER UpdateHandler,void *param) +{ + FM_OPL *Y8950 = (FM_OPL *)chip; + OPLSetUpdateHandler(Y8950, UpdateHandler, param); +} + +void y8950_set_delta_t_memory(void *chip, void * deltat_mem_ptr, int deltat_mem_size ) +{ + FM_OPL *OPL = (FM_OPL *)chip; + OPL->deltat->memory = (UINT8 *)(deltat_mem_ptr); + OPL->deltat->memory_size = deltat_mem_size; +} + +/* +** Generate samples for one of the Y8950's +** +** 'which' is the virtual Y8950 number +** '*buffer' is the output buffer pointer +** 'length' is the number of samples that should be generated +*/ +void y8950_update_one(void *chip, OPLSAMPLE *buffer, int length) +{ + int i; + FM_OPL *OPL = (FM_OPL *)chip; + UINT8 rhythm = OPL->rhythm&0x20; + YM_DELTAT *DELTAT = OPL->deltat; + OPLSAMPLE *buf = buffer; + + for( i=0; i < length ; i++ ) + { + int lt; + + OPL->output[0] = 0; + OPL->output_deltat[0] = 0; + + advance_lfo(OPL); + + /* deltaT ADPCM */ + if( DELTAT->portstate&0x80 ) + YM_DELTAT_ADPCM_CALC(DELTAT); + + /* FM part */ + OPL_CALC_CH(OPL, &OPL->P_CH[0]); + OPL_CALC_CH(OPL, &OPL->P_CH[1]); + OPL_CALC_CH(OPL, &OPL->P_CH[2]); + OPL_CALC_CH(OPL, &OPL->P_CH[3]); + OPL_CALC_CH(OPL, &OPL->P_CH[4]); + OPL_CALC_CH(OPL, &OPL->P_CH[5]); + + if(!rhythm) + { + OPL_CALC_CH(OPL, &OPL->P_CH[6]); + OPL_CALC_CH(OPL, &OPL->P_CH[7]); + OPL_CALC_CH(OPL, &OPL->P_CH[8]); + } + else /* Rhythm part */ + { + OPL_CALC_RH(OPL, &OPL->P_CH[0], (OPL->noise_rng>>0)&1 ); + } + + lt = OPL->output[0] + (OPL->output_deltat[0]>>11); + + lt >>= FINAL_SH; + + /* limit check */ + lt = limit( lt , MAXOUT, MINOUT ); + + #ifdef SAVE_SAMPLE + if (which==0) + { + SAVE_ALL_CHANNELS + } + #endif + + /* store to sound buffer */ + buf[i] = lt; + + advance(OPL); + } + +} + +void y8950_set_port_handler(void *chip,OPL_PORTHANDLER_W PortHandler_w,OPL_PORTHANDLER_R PortHandler_r,void * param) +{ + FM_OPL *OPL = (FM_OPL *)chip; + OPL->porthandler_w = PortHandler_w; + OPL->porthandler_r = PortHandler_r; + OPL->port_param = param; +} + +void y8950_set_keyboard_handler(void *chip,OPL_PORTHANDLER_W KeyboardHandler_w,OPL_PORTHANDLER_R KeyboardHandler_r,void * param) +{ + FM_OPL *OPL = (FM_OPL *)chip; + OPL->keyboardhandler_w = KeyboardHandler_w; + OPL->keyboardhandler_r = KeyboardHandler_r; + OPL->keyboard_param = param; +} + +#endif diff --git a/src/devices/sound/fmopl.h b/src/devices/sound/fmopl.h new file mode 100644 index 00000000000..3b0cda28c9f --- /dev/null +++ b/src/devices/sound/fmopl.h @@ -0,0 +1,115 @@ +// license:??? +// copyright-holders:Jarek Burczynski +#pragma once + +#ifndef __FMOPL_H__ +#define __FMOPL_H__ + +/* --- select emulation chips --- */ +#define BUILD_YM3812 (1) +#define BUILD_YM3526 (1) +#define BUILD_Y8950 (1) + +/* select output bits size of output : 8 or 16 */ +#define OPL_SAMPLE_BITS 16 + +/* compiler dependence */ +#ifndef __OSDCOMM_H__ +#define __OSDCOMM_H__ +typedef unsigned char UINT8; /* unsigned 8bit */ +typedef unsigned short UINT16; /* unsigned 16bit */ +typedef unsigned int UINT32; /* unsigned 32bit */ +typedef signed char INT8; /* signed 8bit */ +typedef signed short INT16; /* signed 16bit */ +typedef signed int INT32; /* signed 32bit */ +#endif /* __OSDCOMM_H__ */ + +typedef stream_sample_t OPLSAMPLE; +/* +#if (OPL_SAMPLE_BITS==16) +typedef INT16 OPLSAMPLE; +#endif +#if (OPL_SAMPLE_BITS==8) +typedef INT8 OPLSAMPLE; +#endif +*/ + +typedef void (*OPL_TIMERHANDLER)(void *param,int timer,const attotime &period); +typedef void (*OPL_IRQHANDLER)(void *param,int irq); +typedef void (*OPL_UPDATEHANDLER)(void *param,int min_interval_us); +typedef void (*OPL_PORTHANDLER_W)(void *param,unsigned char data); +typedef unsigned char (*OPL_PORTHANDLER_R)(void *param); + + +#if BUILD_YM3812 + +void *ym3812_init(device_t *device, UINT32 clock, UINT32 rate); +void ym3812_shutdown(void *chip); +void ym3812_reset_chip(void *chip); +int ym3812_write(void *chip, int a, int v); +unsigned char ym3812_read(void *chip, int a); +int ym3812_timer_over(void *chip, int c); +void ym3812_update_one(void *chip, OPLSAMPLE *buffer, int length); + +void ym3812_set_timer_handler(void *chip, OPL_TIMERHANDLER TimerHandler, void *param); +void ym3812_set_irq_handler(void *chip, OPL_IRQHANDLER IRQHandler, void *param); +void ym3812_set_update_handler(void *chip, OPL_UPDATEHANDLER UpdateHandler, void *param); + +#endif /* BUILD_YM3812 */ + + +#if BUILD_YM3526 + +/* +** Initialize YM3526 emulator(s). +** +** 'num' is the number of virtual YM3526's to allocate +** 'clock' is the chip clock in Hz +** 'rate' is sampling rate +*/ +void *ym3526_init(device_t *device, UINT32 clock, UINT32 rate); +/* shutdown the YM3526 emulators*/ +void ym3526_shutdown(void *chip); +void ym3526_reset_chip(void *chip); +int ym3526_write(void *chip, int a, int v); +unsigned char ym3526_read(void *chip, int a); +int ym3526_timer_over(void *chip, int c); +/* +** Generate samples for one of the YM3526's +** +** 'which' is the virtual YM3526 number +** '*buffer' is the output buffer pointer +** 'length' is the number of samples that should be generated +*/ +void ym3526_update_one(void *chip, OPLSAMPLE *buffer, int length); + +void ym3526_set_timer_handler(void *chip, OPL_TIMERHANDLER TimerHandler, void *param); +void ym3526_set_irq_handler(void *chip, OPL_IRQHANDLER IRQHandler, void *param); +void ym3526_set_update_handler(void *chip, OPL_UPDATEHANDLER UpdateHandler, void *param); + +#endif /* BUILD_YM3526 */ + + +#if BUILD_Y8950 + +/* Y8950 port handlers */ +void y8950_set_port_handler(void *chip, OPL_PORTHANDLER_W PortHandler_w, OPL_PORTHANDLER_R PortHandler_r, void *param); +void y8950_set_keyboard_handler(void *chip, OPL_PORTHANDLER_W KeyboardHandler_w, OPL_PORTHANDLER_R KeyboardHandler_r, void *param); +void y8950_set_delta_t_memory(void *chip, void * deltat_mem_ptr, int deltat_mem_size ); + +void * y8950_init(device_t *device, UINT32 clock, UINT32 rate); +void y8950_shutdown(void *chip); +void y8950_reset_chip(void *chip); +int y8950_write(void *chip, int a, int v); +unsigned char y8950_read (void *chip, int a); +int y8950_timer_over(void *chip, int c); +void y8950_update_one(void *chip, OPLSAMPLE *buffer, int length); + +void y8950_set_timer_handler(void *chip, OPL_TIMERHANDLER TimerHandler, void *param); +void y8950_set_irq_handler(void *chip, OPL_IRQHANDLER IRQHandler, void *param); +void y8950_set_update_handler(void *chip, OPL_UPDATEHANDLER UpdateHandler, void *param); + +#endif /* BUILD_Y8950 */ + + +#endif /* __FMOPL_H__ */ diff --git a/src/devices/sound/gaelco.c b/src/devices/sound/gaelco.c new file mode 100644 index 00000000000..9a40796a1ac --- /dev/null +++ b/src/devices/sound/gaelco.c @@ -0,0 +1,276 @@ +// license:BSD-3-Clause +// copyright-holders:Manuel Abadia +/*************************************************************************** + Gaelco Sound Hardware + + By Manuel Abadia + +CG-1V/GAE1 (Gaelco custom GFX & Sound chip): + The CG-1V/GAE1 can handle up to 7 stereo channels. + The chip output is connected to a TDA1543 (16 bit DAC). + +Registers per channel: +====================== + Word | Bit(s) | Description + -----+-FEDCBA98-76543210-+-------------------------- + 0 | xxxxxxxx xxxxxxxx | not used? + 1 | xxxx---- -------- | left channel volume (0x00..0x0f) + 1 | ----xxxx -------- | right channel volume (0x00..0x0f) + 1 | -------- xxxx---- | sample type (0x0c = PCM 8 bits mono, 0x08 = PCM 8 bits stereo) + 1 | -------- ----xxxx | ROM Bank + 2 | xxxxxxxx xxxxxxxx | sample end position + 3 | xxxxxxxx xxxxxxxx | remaining bytes to play + + the following are used only when looping (usually used for music) + + 4 | xxxxxxxx xxxxxxxx | not used? + 5 | xxxx---- -------- | left channel volume (0x00..0x0f) + 5 | ----xxxx -------- | right channel volume (0x00..0x0f) + 5 | -------- xxxx---- | sample type (0x0c = PCM 8 bits mono, 0x08 = PCM 8 bits stereo) + 5 | -------- ----xxxx | ROM Bank + 6 | xxxxxxxx xxxxxxxx | sample end position + 7 | xxxxxxxx xxxxxxxx | remaining bytes to play + + The samples are played from (end position + length) to (end position)! + +***************************************************************************/ + +#include "emu.h" +#include "gaelco.h" +#include "wavwrite.h" + +#define VERBOSE_SOUND 0 +#define VERBOSE_READ_WRITES 0 +#define LOG_SOUND(x) do { if (VERBOSE_SOUND) logerror x; } while (0) +#define LOG_READ_WRITES(x) do { if (VERBOSE_READ_WRITES) logerror x; } while (0) + +//#define ALT_MIX + +#define LOG_WAVE 0 +static wav_file* wavraw; // Raw waveform + + +/*============================================================================ + Gaelco GAE1 sound device + ============================================================================*/ + +const device_type GAELCO_GAE1 = &device_creator; + +gaelco_gae1_device::gaelco_gae1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, GAELCO_GAE1, "Gaelco GAE1", tag, owner, clock, "gaelco_gae1", __FILE__), + device_sound_interface(mconfig, *this), + m_stream(NULL), + m_snd_data(NULL), + m_data_tag(NULL) +{ +} + +gaelco_gae1_device::gaelco_gae1_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_sound_interface(mconfig, *this), + m_stream(NULL), + m_snd_data(NULL), + m_data_tag(NULL) +{ +} + + +/*============================================================================ + CG-1V/GAE1 Sound Update + + Writes length bytes to the sound buffer + ============================================================================*/ + +void gaelco_gae1_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + int j, ch; + + /* fill all data needed */ + for(j = 0; j < samples; j++){ + int output_l = 0, output_r = 0; + + /* for each channel */ + for (ch = 0; ch < GAELCO_NUM_CHANNELS; ch ++){ + int ch_data_l = 0, ch_data_r = 0; + gaelco_sound_channel *channel = &m_channel[ch]; + + /* if the channel is playing */ + if (channel->active == 1){ + int data, chunkNum = 0; + int base_offset, type, bank, vol_r, vol_l, end_pos; + + /* if the channel is looping, get current chunk to play */ + if (channel->loop == 1){ + chunkNum = channel->chunkNum; + } + + base_offset = ch*8 + chunkNum*4; + + /* get channel parameters */ + type = ((m_sndregs[base_offset + 1] >> 4) & 0x0f); + bank = m_banks[((m_sndregs[base_offset + 1] >> 0) & 0x03)]; + vol_l = ((m_sndregs[base_offset + 1] >> 12) & 0x0f); + vol_r = ((m_sndregs[base_offset + 1] >> 8) & 0x0f); + end_pos = m_sndregs[base_offset + 2] << 8; + + /* generates output data (range 0x00000..0xffff) */ + if (type == 0x08){ + /* PCM, 8 bits mono */ + data = m_snd_data[bank + end_pos + m_sndregs[base_offset + 3]]; + ch_data_l = m_volume_table[vol_l][data]; + ch_data_r = m_volume_table[vol_r][data]; + + m_sndregs[base_offset + 3]--; + } else if (type == 0x0c){ + /* PCM, 8 bits stereo */ + data = m_snd_data[bank + end_pos + m_sndregs[base_offset + 3]]; + ch_data_l = m_volume_table[vol_l][data]; + + m_sndregs[base_offset + 3]--; + + if (m_sndregs[base_offset + 3] > 0){ + data = m_snd_data[bank + end_pos + m_sndregs[base_offset + 3]]; + ch_data_r = m_volume_table[vol_r][data]; + + m_sndregs[base_offset + 3]--; + } + } else { + LOG_SOUND(("(GAE1) Playing unknown sample format in channel: %02d, type: %02x, bank: %02x, end: %08x, Length: %04x\n", ch, type, bank, end_pos, m_sndregs[base_offset + 3])); + channel->active = 0; + } + + /* check if the current sample has finished playing */ + if (m_sndregs[base_offset + 3] == 0){ + if (channel->loop == 0){ /* if no looping, we're done */ + channel->active = 0; + } else { /* if we're looping, swap chunks */ + channel->chunkNum = (channel->chunkNum + 1) & 0x01; + + /* if the length of the next chunk is 0, we're done */ + if (m_sndregs[ch*8 + channel->chunkNum*4 + 3] == 0){ + channel->active = 0; + } + } + } + } + + /* add the contribution of this channel to the current data output */ + output_l += ch_data_l; + output_r += ch_data_r; + } + +#ifndef ALT_MIX + /* clip to max or min value */ + if (output_l > 32767) output_l = 32767; + if (output_r > 32767) output_r = 32767; + if (output_l < -32768) output_l = -32768; + if (output_r < -32768) output_r = -32768; +#else + /* ponderate channels */ + output_l /= GAELCO_NUM_CHANNELS; + output_r /= GAELCO_NUM_CHANNELS; +#endif + + /* now that we have computed all channels, save current data to the output buffer */ + outputs[0][j] = output_l; + outputs[1][j] = output_r; + } + + if (wavraw) + wav_add_data_32lr(wavraw, outputs[0], outputs[1], samples, 0); +} + +/*============================================================================ + CG-1V/GAE1 Read Handler + ============================================================================*/ + +READ16_MEMBER( gaelco_gae1_device::gaelcosnd_r ) +{ + LOG_READ_WRITES(("%s: (GAE1): read from %04x\n", machine().describe_context(), offset)); + + return m_sndregs[offset]; +} + +/*============================================================================ + CG-1V/GAE1 Write Handler + ============================================================================*/ + +WRITE16_MEMBER( gaelco_gae1_device::gaelcosnd_w ) +{ + gaelco_sound_channel *channel = &m_channel[offset >> 3]; + + LOG_READ_WRITES(("%s: (GAE1): write %04x to %04x\n", machine().describe_context(), data, offset)); + + /* first update the stream to this point in time */ + m_stream->update(); + + COMBINE_DATA(&m_sndregs[offset]); + + switch(offset & 0x07){ + case 0x03: + /* trigger sound */ + if ((m_sndregs[offset - 1] != 0) && (data != 0)){ + if (!channel->active){ + channel->active = 1; + channel->chunkNum = 0; + channel->loop = 0; + LOG_SOUND(("(GAE1) Playing sample channel: %02d, type: %02x, bank: %02x, end: %08x, Length: %04x\n", offset >> 3, (m_sndregs[offset - 2] >> 4) & 0x0f, m_sndregs[offset - 2] & 0x03, m_sndregs[offset - 1] << 8, data)); + } + } else { + channel->active = 0; + } + + break; + + case 0x07: /* enable/disable looping */ + if ((m_sndregs[offset - 1] != 0) && (data != 0)){ + LOG_SOUND(("(GAE1) Looping in channel: %02d, type: %02x, bank: %02x, end: %08x, Length: %04x\n", offset >> 3, (m_sndregs[offset - 2] >> 4) & 0x0f, m_sndregs[offset - 2] & 0x03, m_sndregs[offset - 1] << 8, data)); + channel->loop = 1; + } else { + channel->loop = 0; + } + + break; + } +} + +/*============================================================================ + CG-1V/GAE1 Init / Close + ============================================================================*/ + +void gaelco_gae1_device::device_start() +{ + m_stream = stream_alloc(0, 2, 8000); + + m_snd_data = owner()->memregion(m_data_tag)->base(); + + /* init volume table */ + for (int vol = 0; vol < GAELCO_VOLUME_LEVELS; vol++){ + for (int j = -128; j <= 127; j++){ + m_volume_table[vol][(j ^ 0x80) & 0xff] = (vol*j*256)/(GAELCO_VOLUME_LEVELS - 1); + } + } + + if (LOG_WAVE) + wavraw = wav_open("gae1_snd.wav", 8000, 2); +} + + +void gaelco_gae1_device::device_stop() +{ + if (wavraw) + wav_close(wavraw); + wavraw = NULL; +} + + +/*============================================================================ + Gaelco CG-1V sound device + ============================================================================*/ + +const device_type GAELCO_CG1V = &device_creator; + +gaelco_cg1v_device::gaelco_cg1v_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : gaelco_gae1_device(mconfig, GAELCO_CG1V, "Gaelco CG1V", tag, owner, clock, "gaelco_cg1v", __FILE__) +{ +} diff --git a/src/devices/sound/gaelco.h b/src/devices/sound/gaelco.h new file mode 100644 index 00000000000..25b8cb129d2 --- /dev/null +++ b/src/devices/sound/gaelco.h @@ -0,0 +1,98 @@ +// license:BSD-3-Clause +// copyright-holders:Manuel Abadia +#pragma once + +#ifndef __GAELCO_SND_H__ +#define __GAELCO_SND_H__ + +#define GAELCO_NUM_CHANNELS 0x07 +#define GAELCO_VOLUME_LEVELS 0x10 + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_GAELCO_SND_DATA(_tag) \ + gaelco_gae1_device::set_snd_data_tag(*device, _tag); + +#define MCFG_GAELCO_BANKS(_offs1, _offs2, _offs3, _offs4) \ + gaelco_gae1_device::set_bank_offsets(*device, _offs1, _offs2, _offs3, _offs4); + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> Sound Channel + +struct gaelco_sound_channel +{ + int active; // is it playing? + int loop; // = 0 no looping, = 1 looping + int chunkNum; // current chunk if looping +}; + + +// ======================> gaelco_gae1_device + +class gaelco_gae1_device : public device_t, + public device_sound_interface +{ +public: + gaelco_gae1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + gaelco_gae1_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + ~gaelco_gae1_device() { } + + static void set_snd_data_tag(device_t &device, const char *tag) { downcast(device).m_data_tag = tag; } + static void set_bank_offsets(device_t &device, int offs1, int offs2, int offs3, int offs4) + { + gaelco_gae1_device &dev = downcast(device); + dev.m_banks[0] = offs1; + dev.m_banks[1] = offs2; + dev.m_banks[2] = offs3; + dev.m_banks[3] = offs4; + } + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_stop(); + + // sound stream update overrides + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + +public: + DECLARE_WRITE16_MEMBER( gaelcosnd_w ); + DECLARE_READ16_MEMBER( gaelcosnd_r ); + +private: + sound_stream *m_stream; /* our stream */ + UINT8 *m_snd_data; /* PCM data */ + int m_banks[4]; /* start of each ROM bank */ + gaelco_sound_channel m_channel[GAELCO_NUM_CHANNELS]; /* 7 stereo channels */ + + const char *m_data_tag; + + UINT16 m_sndregs[0x38]; + + // Table for converting from 8 to 16 bits with volume control + INT16 m_volume_table[GAELCO_VOLUME_LEVELS][256]; +}; + +extern const device_type GAELCO_GAE1; + + + +// ======================> gaelco_cg1v_device + +class gaelco_cg1v_device : public gaelco_gae1_device +{ +public: + gaelco_cg1v_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +extern const device_type GAELCO_CG1V; + + +#endif /* __GAELCO_SND_H__ */ diff --git a/src/devices/sound/hc55516.c b/src/devices/sound/hc55516.c new file mode 100644 index 00000000000..9d8a191bdba --- /dev/null +++ b/src/devices/sound/hc55516.c @@ -0,0 +1,337 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/***************************************************************************** + + Harris HC-55516 (and related) emulator + +*****************************************************************************/ + +#include "emu.h" +#include "hc55516.h" + + +/* 4x oversampling */ +#define SAMPLE_RATE (48000 * 4) + +#define INTEGRATOR_LEAK_TC 0.001 +#define FILTER_DECAY_TC 0.004 +#define FILTER_CHARGE_TC 0.004 +#define FILTER_MIN 0.0416 +#define FILTER_MAX 1.0954 +#define SAMPLE_GAIN 10000.0 + + + + +const device_type HC55516 = &device_creator; + +hc55516_device::hc55516_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, HC55516, "HC-55516", tag, owner, clock, "hc55516", __FILE__), + device_sound_interface(mconfig, *this), + m_channel(NULL), + m_active_clock_hi(0), + m_shiftreg_mask(0), + m_last_clock_state(0), + m_digit(0), + m_new_digit(0), + m_shiftreg(0), + m_curr_sample(0), + m_next_sample(0), + m_update_count(0), + m_filter(0), + m_integrator(0), + m_charge(0), + m_decay(0), + m_leak(0) +{ +} +hc55516_device::hc55516_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_sound_interface(mconfig, *this), + m_channel(NULL), + m_active_clock_hi(0), + m_shiftreg_mask(0), + m_last_clock_state(0), + m_digit(0), + m_new_digit(0), + m_shiftreg(0), + m_curr_sample(0), + m_next_sample(0), + m_update_count(0), + m_filter(0), + m_integrator(0), + m_charge(0), + m_decay(0), + m_leak(0) +{ +} + +//------------------------------------------------- +// device_config_complete - perform any +// operations now that the configuration is +// complete +//------------------------------------------------- + +void hc55516_device::device_config_complete() +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void hc55516_device::device_start() +{ + start_common(0x07, TRUE); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void hc55516_device::device_reset() +{ + m_last_clock_state = 0; +} + +const device_type MC3417 = &device_creator; + +mc3417_device::mc3417_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : hc55516_device(mconfig, MC3417, "MC3417", tag, owner, clock, "mc3417", __FILE__) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void mc3417_device::device_start() +{ + start_common(0x07, FALSE); +} + + +const device_type MC3418 = &device_creator; + +mc3418_device::mc3418_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : hc55516_device(mconfig, MC3418, "MC3418", tag, owner, clock, "mc3418", __FILE__) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void mc3418_device::device_start() +{ + start_common(0x0f, FALSE); +} + + +void hc55516_device::start_common(UINT8 _shiftreg_mask, int _active_clock_hi) +{ + /* compute the fixed charge, decay, and leak time constants */ + m_charge = pow(exp(-1.0), 1.0 / (FILTER_CHARGE_TC * 16000.0)); + m_decay = pow(exp(-1.0), 1.0 / (FILTER_DECAY_TC * 16000.0)); + m_leak = pow(exp(-1.0), 1.0 / (INTEGRATOR_LEAK_TC * 16000.0)); + + m_shiftreg_mask = _shiftreg_mask; + m_active_clock_hi = _active_clock_hi; + m_last_clock_state = 0; + + /* create the stream */ + m_channel = machine().sound().stream_alloc(*this, 0, 1, SAMPLE_RATE); + + save_item(NAME(m_last_clock_state)); + save_item(NAME(m_digit)); + save_item(NAME(m_new_digit)); + save_item(NAME(m_shiftreg)); + save_item(NAME(m_curr_sample)); + save_item(NAME(m_next_sample)); + save_item(NAME(m_update_count)); + save_item(NAME(m_filter)); + save_item(NAME(m_integrator)); +} + +inline int hc55516_device::is_external_oscillator() +{ + return clock() != 0; +} + + +inline int hc55516_device::is_active_clock_transition(int clock_state) +{ + return (( m_active_clock_hi && !m_last_clock_state && clock_state) || + (!m_active_clock_hi && m_last_clock_state && !clock_state)); +} + + +inline int hc55516_device::current_clock_state() +{ + return ((UINT64)m_update_count * clock() * 2 / SAMPLE_RATE) & 0x01; +} + + +void hc55516_device::process_digit() +{ + double integrator = m_integrator, temp; + + /* shift the bit into the shift register */ + m_shiftreg = (m_shiftreg << 1) | m_digit; + + /* move the estimator up or down a step based on the bit */ + if (m_digit) + integrator += m_filter; + else + integrator -= m_filter; + + /* simulate leakage */ + integrator *= m_leak; + + /* if we got all 0's or all 1's in the last n bits, bump the step up */ + if (((m_shiftreg & m_shiftreg_mask) == 0) || + ((m_shiftreg & m_shiftreg_mask) == m_shiftreg_mask)) + { + m_filter = FILTER_MAX - ((FILTER_MAX - m_filter) * m_charge); + + if (m_filter > FILTER_MAX) + m_filter = FILTER_MAX; + } + + /* simulate decay */ + else + { + m_filter *= m_decay; + + if (m_filter < FILTER_MIN) + m_filter = FILTER_MIN; + } + + /* compute the sample as a 32-bit word */ + temp = integrator * SAMPLE_GAIN; + m_integrator = integrator; + + /* compress the sample range to fit better in a 16-bit word */ + if (temp < 0) + m_next_sample = (int)(temp / (-temp * (1.0 / 32768.0) + 1.0)); + else + m_next_sample = (int)(temp / (temp * (1.0 / 32768.0) + 1.0)); +} + +void hc55516_device::clock_w(int state) +{ + UINT8 clock_state = state ? TRUE : FALSE; + + /* only makes sense for setups with a software driven clock */ + assert(!is_external_oscillator()); + + /* speech clock changing? */ + if (is_active_clock_transition(clock_state)) + { + /* update the output buffer before changing the registers */ + m_channel->update(); + + /* clear the update count */ + m_update_count = 0; + + process_digit(); + } + + /* update the clock */ + m_last_clock_state = clock_state; +} + + +void hc55516_device::digit_w(int digit) +{ + if (is_external_oscillator()) + { + m_channel->update(); + m_new_digit = digit & 1; + } + else + m_digit = digit & 1; +} + + +int hc55516_device::clock_state_r() +{ + /* only makes sense for setups with an external oscillator */ + assert(is_external_oscillator()); + + m_channel->update(); + + return current_clock_state(); +} + + +//------------------------------------------------- +// sound_stream_update - handle a stream update +//------------------------------------------------- + +void hc55516_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + stream_sample_t *buffer = outputs[0]; + int i; + INT32 sample, slope; + + /* zero-length? bail */ + if (samples == 0) + return; + + if (!is_external_oscillator()) + { + /* track how many samples we've updated without a clock */ + m_update_count += samples; + if (m_update_count > SAMPLE_RATE / 32) + { + m_update_count = SAMPLE_RATE; + m_next_sample = 0; + } + } + + /* compute the interpolation slope */ + sample = m_curr_sample; + slope = ((INT32)m_next_sample - sample) / samples; + m_curr_sample = m_next_sample; + + if (is_external_oscillator()) + { + /* external oscillator */ + for (i = 0; i < samples; i++, sample += slope) + { + UINT8 clock_state; + + *buffer++ = sample; + + m_update_count++; + + clock_state = current_clock_state(); + + /* pull in next digit on the appropriate edge of the clock */ + if (is_active_clock_transition(clock_state)) + { + m_digit = m_new_digit; + + process_digit(); + } + + m_last_clock_state = clock_state; + } + } + + /* software driven clock */ + else + for (i = 0; i < samples; i++, sample += slope) + *buffer++ = sample; +} + +void mc3417_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + hc55516_device::sound_stream_update(stream, inputs, outputs, samples); +} + +void mc3418_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + hc55516_device::sound_stream_update(stream, inputs, outputs, samples); +} diff --git a/src/devices/sound/hc55516.h b/src/devices/sound/hc55516.h new file mode 100644 index 00000000000..a6323f8ee4f --- /dev/null +++ b/src/devices/sound/hc55516.h @@ -0,0 +1,95 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +#pragma once + +#ifndef __HC55516_H__ +#define __HC55516_H__ + +class hc55516_device : public device_t, + public device_sound_interface +{ +public: + hc55516_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + hc55516_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + ~hc55516_device() {} + + /* sets the digit (0 or 1) */ + void digit_w(int digit); + + /* sets the clock state (0 or 1, clocked on the rising edge) */ + void clock_w(int state); + + /* returns whether the clock is currently LO or HI */ + int clock_state_r(); + +protected: + // device-level overrides + virtual void device_config_complete(); + virtual void device_start(); + virtual void device_reset(); + + // sound stream update overrides + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + + void start_common(UINT8 _shiftreg_mask, int _active_clock_hi); + + // internal state + sound_stream *m_channel; + int m_active_clock_hi; + UINT8 m_shiftreg_mask; + + UINT8 m_last_clock_state; + UINT8 m_digit; + UINT8 m_new_digit; + UINT8 m_shiftreg; + + INT16 m_curr_sample; + INT16 m_next_sample; + + UINT32 m_update_count; + + double m_filter; + double m_integrator; + + double m_charge; + double m_decay; + double m_leak; + + inline int is_external_oscillator(); + inline int is_active_clock_transition(int clock_state); + inline int current_clock_state(); + void process_digit(); +}; + +extern const device_type HC55516; + +class mc3417_device : public hc55516_device +{ +public: + mc3417_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +protected: + // device-level overrides + virtual void device_start(); + + // sound stream update overrides + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); +}; + +extern const device_type MC3417; + +class mc3418_device : public hc55516_device +{ +public: + mc3418_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +protected: + // device-level overrides + virtual void device_start(); + + // sound stream update overrides + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); +}; + +extern const device_type MC3418; + + +#endif /* __HC55516_H__ */ diff --git a/src/devices/sound/i5000.c b/src/devices/sound/i5000.c new file mode 100644 index 00000000000..df86311904e --- /dev/null +++ b/src/devices/sound/i5000.c @@ -0,0 +1,303 @@ +// license:BSD-3-Clause +// copyright-holders:hap +/*************************************************************************** + + i5000.c - Imagetek I5000 sound emulator + + Imagetek I5000 is a multi-purpose chip, this covers the sound part. + No official documentation is known to exist. It seems to be a simple + 16-channel ADPCM player. + + TODO: + - verify that ADPCM is the same as standard OKI ADPCM + - verify volume balance + - sample command 0x0007 + - any more sound formats than 3-bit and 4-bit ADPCM? + +***************************************************************************/ + +#include "emu.h" +#include "i5000.h" + + +// device type definition +const device_type I5000_SND = &device_creator; + +i5000snd_device::i5000snd_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, I5000_SND, "I5000", tag, owner, clock, "i5000snd", __FILE__), + device_sound_interface(mconfig, *this) +{ +} + + +void i5000snd_device::device_start() +{ + // fill volume table + double div = 1.032; + double vol = 2047.0; + for (int i = 0; i < 0x100; i++) + { + m_lut_volume[i] = vol + 0.5; + vol /= div; + } + m_lut_volume[0xff] = 0; + + // create the stream + m_stream = machine().sound().stream_alloc(*this, 0, 2, clock() / 0x400); + + m_rom_base = (UINT16 *)device().machine().root_device().memregion(":i5000snd")->base(); + m_rom_mask = device().machine().root_device().memregion(":i5000snd")->bytes() / 2 - 1; + + // register for savestates + for (int ch = 0; ch < 16; ch++) + { + save_item(NAME(m_channels[ch].is_playing), ch); + save_item(NAME(m_channels[ch].m_adpcm.m_signal), ch); + save_item(NAME(m_channels[ch].m_adpcm.m_step), ch); + + save_item(NAME(m_channels[ch].address), ch); + save_item(NAME(m_channels[ch].freq_timer), ch); + save_item(NAME(m_channels[ch].freq_base), ch); + save_item(NAME(m_channels[ch].freq_min), ch); + save_item(NAME(m_channels[ch].sample), ch); + save_item(NAME(m_channels[ch].shift_pos), ch); + save_item(NAME(m_channels[ch].shift_amount), ch); + save_item(NAME(m_channels[ch].shift_mask), ch); + save_item(NAME(m_channels[ch].vol_r), ch); + save_item(NAME(m_channels[ch].vol_l), ch); + save_item(NAME(m_channels[ch].output_r), ch); + save_item(NAME(m_channels[ch].output_l), ch); + } + + save_item(NAME(m_regs)); +} + + +void i5000snd_device::device_reset() +{ + // stop playing + write_reg16(0x43, 0xffff); + + // reset channel regs + for (int i = 0; i < 0x40; i++) + write_reg16(i, 0); +} + + +bool i5000snd_device::read_sample(int ch) +{ + m_channels[ch].shift_pos &= 0xf; + m_channels[ch].sample = m_rom_base[m_channels[ch].address]; + m_channels[ch].address = (m_channels[ch].address + 1) & m_rom_mask; + + // handle command + if (m_channels[ch].sample == 0x7f7f) + { + UINT16 cmd = m_rom_base[m_channels[ch].address]; + m_channels[ch].address = (m_channels[ch].address + 1) & m_rom_mask; + + // volume envelope? or loop sample? + if ((cmd & 0x00ff) == 0x0007) + { + // TODO + return false; + } + + // cmd 0x0000 = end sample + // other values: unused + else return false; + + } + + return true; +} + + +void i5000snd_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + for (int i = 0; i < samples; i++) + { + INT32 mix_l = 0; + INT32 mix_r = 0; + + // loop over all channels + for (int ch = 0; ch < 16; ch++) + { + if (!m_channels[ch].is_playing) + continue; + + m_channels[ch].freq_timer -= m_channels[ch].freq_min; + if (m_channels[ch].freq_timer > 0) + { + mix_r += m_channels[ch].output_r; + mix_l += m_channels[ch].output_l; + continue; + } + m_channels[ch].freq_timer += m_channels[ch].freq_base; + + int adpcm_data = m_channels[ch].sample >> m_channels[ch].shift_pos; + m_channels[ch].shift_pos += m_channels[ch].shift_amount; + if (m_channels[ch].shift_pos & 0x10) + { + if (!read_sample(ch)) + { + m_channels[ch].is_playing = false; + continue; + } + + adpcm_data |= (m_channels[ch].sample << (m_channels[ch].shift_amount - m_channels[ch].shift_pos)); + } + + adpcm_data = m_channels[ch].m_adpcm.clock(adpcm_data & m_channels[ch].shift_mask); + + m_channels[ch].output_r = adpcm_data * m_channels[ch].vol_r / 128; + m_channels[ch].output_l = adpcm_data * m_channels[ch].vol_l / 128; + mix_r += m_channels[ch].output_r; + mix_l += m_channels[ch].output_l; + } + + outputs[0][i] = mix_r / 16; + outputs[1][i] = mix_l / 16; + } +} + + +void i5000snd_device::write_reg16(UINT8 reg, UINT16 data) +{ + // channel regs + if (reg < 0x40) + { + int ch = reg >> 2; + switch (reg & 3) + { + // 0, 1: address + + // 2: frequency + case 2: + m_channels[ch].freq_base = (0x1ff - (data & 0xff)) << (~data >> 8 & 3); + break; + + // 3: left/right volume + case 3: + m_channels[ch].vol_r = m_lut_volume[data & 0xff]; + m_channels[ch].vol_l = m_lut_volume[data >> 8 & 0xff]; + break; + + default: + break; + } + } + + // global regs + else + { + switch (reg) + { + // channel key on (0 has no effect) + case 0x42: + for (int ch = 0; ch < 16; ch++) + { + if (data & (1 << ch) && !m_channels[ch].is_playing) + { + UINT32 address = m_regs[ch << 2 | 1] << 16 | m_regs[ch << 2]; + UINT16 start = m_rom_base[(address + 0) & m_rom_mask]; + UINT16 param = m_rom_base[(address + 1) & m_rom_mask]; + + // check sample start ID + if (start != 0x7f7f) + { + logerror("i5000snd: channel %d wrong sample start ID %04X!\n", ch, start); + continue; + } + + switch (param) + { + // 3-bit ADPCM + case 0x0104: + case 0x0304: // same? + m_channels[ch].freq_min = 0x140; + m_channels[ch].shift_amount = 3; + m_channels[ch].shift_mask = 0xe; + break; + + default: + logerror("i5000snd: channel %d unknown sample param %04X!\n", ch, param); + // fall through (take settings from 0x0184) + // 4-bit ADPCM + case 0x0184: + m_channels[ch].freq_min = 0x100; + m_channels[ch].shift_amount = 4; + m_channels[ch].shift_mask = 0xf; + break; + } + + m_channels[ch].address = (address + 4) & m_rom_mask; + + m_channels[ch].freq_timer = 0; + m_channels[ch].shift_pos = 0; + + m_channels[ch].m_adpcm.reset(); + m_channels[ch].is_playing = read_sample(ch); + } + } + break; + + // channel key off (0 has no effect) + case 0x43: + for (int ch = 0; ch < 16; ch++) + { + if (data & (1 << ch)) + m_channels[ch].is_playing = false; + } + break; + + default: + // not accessed often, assume that these are chip init registers + // 0x40: ? + // 0x41: ? + // 0x45: ? + // 0x46: ? + break; + } + } + + m_regs[reg] = data; +} + + +READ16_MEMBER( i5000snd_device::read ) +{ + UINT16 ret = 0; + m_stream->update(); + + switch (offset) + { + // channel active state + case 0x42: + for (int ch = 0; ch < 16; ch++) + { + if (m_channels[ch].is_playing) + ret |= (1 << ch); + } + break; + + default: + // 0x41: ? + break; + } + + return ret; +} + + +WRITE16_MEMBER( i5000snd_device::write ) +{ + if (mem_mask != 0xffff) + { + logerror("i5000snd: wrong mask %04X!\n", mem_mask); + return; + } + m_stream->update(); + + write_reg16(offset, data); +} diff --git a/src/devices/sound/i5000.h b/src/devices/sound/i5000.h new file mode 100644 index 00000000000..cdf8b33430e --- /dev/null +++ b/src/devices/sound/i5000.h @@ -0,0 +1,89 @@ +// license:BSD-3-Clause +// copyright-holders:hap +/*************************************************************************** + + i5000.h - Imagetek I5000 sound emulator + +***************************************************************************/ + +#pragma once + +#ifndef __I5000_H__ +#define __I5000_H__ + +#include "sound/okiadpcm.h" + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_I5000_SND_ADD(_tag, _clock) \ + MCFG_DEVICE_ADD(_tag, I5000_SND, _clock) + +#define MCFG_I5000_SND_REPLACE(_tag, _clock) \ + MCFG_DEVICE_REPLACE(_tag, I5000_SND, _clock) + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class i5000snd_device : public device_t, + public device_sound_interface +{ +public: + // construction/destruction + i5000snd_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + DECLARE_READ16_MEMBER(read); + DECLARE_WRITE16_MEMBER(write); + + sound_stream *m_stream; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + +private: + struct channel_t + { + bool is_playing; + oki_adpcm_state m_adpcm; + + UINT32 address; + int freq_timer; + int freq_base; + int freq_min; + UINT16 sample; + UINT8 shift_pos; + UINT8 shift_amount; + UINT8 shift_mask; + int vol_r; + int vol_l; + int output_r; + int output_l; + + }; + + channel_t m_channels[16]; + + UINT16 m_regs[0x80]; + + UINT16 *m_rom_base; + UINT32 m_rom_mask; + + int m_lut_volume[0x100]; + + bool read_sample(int ch); + void write_reg16(UINT8 reg, UINT16 data); +}; + + +// device type definition +extern const device_type I5000_SND; + +#endif /* __I5000_H__ */ diff --git a/src/devices/sound/ics2115.c b/src/devices/sound/ics2115.c new file mode 100644 index 00000000000..af3557c28c3 --- /dev/null +++ b/src/devices/sound/ics2115.c @@ -0,0 +1,890 @@ +// license:??? +// copyright-holders:Alex Marshall,nimitz,austere +//ICS2115 by Raiden II team (c) 2010 +//members: austere, nimitz, Alex Marshal +// +//Original driver by O. Galibert, ElSemi +// +//Use tab size = 4 for your viewing pleasure. + +#include "emu.h" +#include "ics2115.h" +#include + +//#define ICS2115_DEBUG +//#define ICS2115_ISOLATE 6 + +// device type definition +const device_type ICS2115 = &device_creator; + +ics2115_device::ics2115_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, ICS2115, "ICS2115", tag, owner, clock, "ics2115", __FILE__), + device_sound_interface(mconfig, *this), + m_rom(*this, DEVICE_SELF), + m_irq_cb(*this) +{ +} + +void ics2115_device::device_start() +{ + m_timer[0].timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(ics2115_device::timer_cb_0),this), this); + m_timer[1].timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(ics2115_device::timer_cb_1),this), this); + m_stream = machine().sound().stream_alloc(*this, 0, 2, 33075); + + m_irq_cb.resolve_safe(); + + //Exact formula as per patent 5809466 + //This seems to give the ok fit but it is not good enough. + /*double maxvol = ((1 << volume_bits) - 1) * pow(2., (double)1/0x100); + for (int i = 0; i < 0x1000; i++) { + m_volume[i] = floor(maxvol * pow(2.,(double)i/256 - 16) + 0.5); + }*/ + + //austere's table, derived from patent 5809466: + //See section V starting from page 195 + //Subsection F (column 124, page 198) onwards + for (int i = 0; i<4096; i++) { + m_volume[i] = ((0x100 | (i & 0xff)) << (volume_bits-9)) >> (15 - (i>>8)); + } + + //u-Law table as per MIL-STD-188-113 + UINT16 lut[8]; + UINT16 lut_initial = 33 << 2; //shift up 2-bits for 16-bit range. + for(int i = 0; i < 8; i++) + lut[i] = (lut_initial << i) - lut_initial; + for(int i = 0; i < 256; i++) { + UINT8 exponent = (~i >> 4) & 0x07; + UINT8 mantissa = ~i & 0x0f; + INT16 value = lut[exponent] + (mantissa << (exponent + 3)); + m_ulaw[i] = (i & 0x80) ? -value : value; + } + + save_item(NAME(m_timer[0].period)); + save_item(NAME(m_timer[0].scale)); + save_item(NAME(m_timer[0].preset)); + save_item(NAME(m_timer[1].period)); + save_item(NAME(m_timer[1].scale)); + save_item(NAME(m_timer[1].preset)); + save_item(NAME(m_reg_select)); + save_item(NAME(m_osc_select)); + save_item(NAME(m_irq_enabled)); + save_item(NAME(m_irq_pending)); + save_item(NAME(m_irq_on)); + save_item(NAME(m_active_osc)); + save_item(NAME(m_vmode)); + + for(int i = 0; i < 32; i++) { + save_item(NAME(m_voice[i].osc_conf.value), i); + save_item(NAME(m_voice[i].state.value), i); + save_item(NAME(m_voice[i].vol_ctrl.value), i); + save_item(NAME(m_voice[i].osc.left), i); + save_item(NAME(m_voice[i].osc.acc), i); + save_item(NAME(m_voice[i].osc.start), i); + save_item(NAME(m_voice[i].osc.end), i); + save_item(NAME(m_voice[i].osc.fc), i); + save_item(NAME(m_voice[i].osc.ctl), i); + save_item(NAME(m_voice[i].osc.saddr), i); + save_item(NAME(m_voice[i].vol.left), i); + save_item(NAME(m_voice[i].vol.add), i); + save_item(NAME(m_voice[i].vol.start), i); + save_item(NAME(m_voice[i].vol.end), i); + save_item(NAME(m_voice[i].vol.acc), i); + save_item(NAME(m_voice[i].vol.regacc), i); + save_item(NAME(m_voice[i].vol.incr), i); + save_item(NAME(m_voice[i].vol.pan), i); + save_item(NAME(m_voice[i].vol.mode), i); + } +} + + +void ics2115_device::device_reset() +{ + m_irq_enabled = 0; + m_irq_pending = 0; + //possible re-suss + m_active_osc = 31; + m_osc_select = 0; + m_reg_select = 0; + m_vmode = 0; + m_irq_on = false; + memset(m_voice, 0, sizeof(m_voice)); + for(int i = 0; i < 2; ++i) + { + m_timer[i].timer->adjust(attotime::never); + m_timer[i].period = 0; + m_timer[i].scale = 0; + m_timer[i].preset = 0; + } + for(int i = 0; i < 32; i++) { + m_voice[i].osc_conf.value = 2; + m_voice[i].osc.fc = 0; + m_voice[i].osc.acc = 0; + m_voice[i].osc.start = 0; + m_voice[i].osc.end = 0; + m_voice[i].osc.ctl = 0; + m_voice[i].osc.saddr = 0; + m_voice[i].vol.acc = 0; + m_voice[i].vol.incr = 0; + m_voice[i].vol.start = 0; + m_voice[i].vol.end = 0; + m_voice[i].vol.pan = 0x7F; + m_voice[i].vol_ctrl.value = 1; + m_voice[i].vol.mode = 0; + m_voice[i].state.value = 0; + } +} + +//TODO: improve using next-state logic from column 126 of patent 5809466 +int ics2115_voice::update_volume_envelope() +{ + int ret = 0; + if(vol_ctrl.bitflags.done || vol_ctrl.bitflags.stop) + return ret; + + if(vol_ctrl.bitflags.invert) { + vol.acc -= vol.add; + vol.left = vol.acc - vol.start; + } else { + vol.acc += vol.add; + vol.left = vol.end - vol.acc; + } + + if(vol.left > 0) + return ret; + + if(vol_ctrl.bitflags.irq) { + vol_ctrl.bitflags.irq_pending = true; + ret = 1; + } + + if(osc_conf.bitflags.eightbit) + return ret; + + if(vol_ctrl.bitflags.loop) { + if(vol_ctrl.bitflags.loop_bidir) + vol_ctrl.bitflags.invert = !vol_ctrl.bitflags.invert; + + if(vol_ctrl.bitflags.invert) + vol.acc = vol.end + vol.left; + else + vol.acc = vol.start - vol.left; + } else { + state.bitflags.on = false; + vol_ctrl.bitflags.done = true; + if(vol_ctrl.bitflags.invert) + vol.acc = vol.end; + else + vol.acc = vol.start; + } + + return ret; +} + +/*UINT32 ics2115_voice::next_address() +{ + //Patent 6,246,774 B1, Column 111, Row 25 + //LEN BLEN DIR BC NextAddress + //x x 0 0 add+fc + //x x 1 0 add-fc + //0 x x 1 add + //1 0 0 1 start-(end-(add+fc)) + //1 0 1 1 end+((add+fc)-start) + //1 1 0 1 end+(end-(add+fc)) + //1 1 1 1 start-((add-fc)-start) + +}*/ + + +int ics2115_voice::update_oscillator() +{ + int ret = 0; + if(osc_conf.bitflags.stop) + return ret; + if(osc_conf.bitflags.invert) { + osc.acc -= osc.fc << 2; + osc.left = osc.acc - osc.start; + } else { + osc.acc += osc.fc << 2; + osc.left = osc.end - osc.acc; + } + // > instead of >= to stop crackling? + if(osc.left > 0) + return ret; + if(osc_conf.bitflags.irq) { + osc_conf.bitflags.irq_pending = true; + ret = 1; + } + if(osc_conf.bitflags.loop) { + if(osc_conf.bitflags.loop_bidir) + osc_conf.bitflags.invert = !osc_conf.bitflags.invert; + //else + // printf("click!\n"); + + if(osc_conf.bitflags.invert) { + osc.acc = osc.end + osc.left; + osc.left = osc.acc - osc.start; + } + else { + osc.acc = osc.start - osc.left; + osc.left = osc.end - osc.acc; + } + } else { + state.bitflags.on = false; + osc_conf.bitflags.stop = true; + if(!osc_conf.bitflags.invert) + osc.acc = osc.end; + else + osc.acc = osc.start; + } + return ret; +} + +//TODO: proper interpolation for uLaw (fill_output doesn't use this) and 8-bit samples (looping) +stream_sample_t ics2115_device::get_sample(ics2115_voice& voice) +{ + UINT32 curaddr = ((voice.osc.saddr << 20) & 0xffffff) | (voice.osc.acc >> 12); + UINT32 nextaddr; + + if (voice.state.bitflags.on && voice.osc_conf.bitflags.loop && !voice.osc_conf.bitflags.loop_bidir && + (voice.osc.left < (voice.osc.fc <<2))) { + //printf("C?[%x:%x]", voice.osc.left, voice.osc.acc); + nextaddr = ((voice.osc.saddr << 20) & 0xffffff) | (voice.osc.start >> 12); + } + else + nextaddr = curaddr + 2; + + + INT16 sample1, sample2; + if (voice.osc_conf.bitflags.eightbit) { + sample1 = ((INT8)m_rom[curaddr]) << 8; + sample2 = ((INT8)m_rom[curaddr + 1]) << 8; + } + else { + sample1 = m_rom[curaddr + 0] | (((INT8)m_rom[curaddr + 1]) << 8); + sample2 = m_rom[nextaddr+ 0] | (((INT8)m_rom[nextaddr+ 1]) << 8); + //sample2 = m_rom[curaddr + 2] | (((INT8)m_rom[curaddr + 3]) << 8); + } + + //no need for interpolation since it's around 1 note a cycle? + //if(voice.osc.fc >> 10) + // return sample1; + + //linear interpolation as in US patent 6,246,774 B1, column 2 row 59 + //LEN=1, BLEN=0, DIR=0, start+end interpolation + INT32 sample, diff; + UINT16 fract; + diff = sample2 - sample1; + fract = (voice.osc.acc >> 3) & 0x1ff; + + sample = (((INT32)sample1 << 9) + diff * fract) >> 9; + //sample = sample1; + return sample; +} + +bool ics2115_voice::playing() +{ + return state.bitflags.on && !((vol_ctrl.bitflags.done || vol_ctrl.bitflags.stop) && osc_conf.bitflags.stop); +} + +void ics2115_voice::update_ramp() { + //slow attack + if (state.bitflags.on && !osc_conf.bitflags.stop) { + if (state.bitflags.ramp < 0x40) + state.bitflags.ramp += 0x1; + else + state.bitflags.ramp = 0x40; + } + //slow release + else { + if (state.bitflags.ramp) + state.bitflags.ramp -= 0x1; + } +} + +int ics2115_device::fill_output(ics2115_voice& voice, stream_sample_t *outputs[2], int samples) +{ + bool irq_invalid = false; + UINT16 fine = 1 << (3*(voice.vol.incr >> 6)); + voice.vol.add = (voice.vol.incr & 0x3F)<< (10 - fine); + + for (int i = 0; i < samples; i++) { + UINT32 volacc = (voice.vol.acc >> 10) & 0xffff; + UINT32 volume = (m_volume[volacc >> 4] * voice.state.bitflags.ramp) >> 6; + UINT16 vleft = volume; //* (255 - voice.vol.pan) / 0x80]; + UINT16 vright = volume; //* (voice.vol.pan + 1) / 0x80]; + + //From GUS doc: + //In general, it is necessary to remember that all voices are being summed in to the + //final output, even if they are not running. This means that whatever data value + //that the voice is pointing at is contributing to the summation. + //(austere note: this will of course fix some of the glitches due to multiple transition) + stream_sample_t sample; + if(voice.osc_conf.bitflags.ulaw) { + UINT32 curaddr = ((voice.osc.saddr << 20) & 0xffffff) | (voice.osc.acc >> 12); + sample = m_ulaw[m_rom[curaddr]]; + } + else + sample = get_sample(voice); + + //15-bit volume + (5-bit worth of 32 channel sum) + 16-bit samples = 4-bit extra + if (!m_vmode || voice.playing()) { + //if (voice.playing()) { + outputs[0][i] += (sample * vleft) >> (5 + volume_bits - 16); + outputs[1][i] += (sample * vright) >> (5 + volume_bits - 16); + } + + voice.update_ramp(); + if (voice.playing()) { + if (voice.update_oscillator()) + irq_invalid = true; + if (voice.update_volume_envelope()) + irq_invalid = true; + } + } + return irq_invalid; +} + +void ics2115_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + memset(outputs[0], 0, samples * sizeof(stream_sample_t)); + memset(outputs[1], 0, samples * sizeof(stream_sample_t)); + + bool irq_invalid = false; + for(int osc = 0; osc <= m_active_osc; osc++) { + ics2115_voice& voice = m_voice[osc]; + +#ifdef ICS2115_ISOLATE + if(osc != ICS2115_ISOLATE) + continue; +#endif +/* +#ifdef ICS2115_DEBUG + UINT32 curaddr = ((voice.osc.saddr << 20) & 0xffffff) | (voice.osc.acc >> 12); + stream_sample_t sample; + if(voice.osc_conf.bitflags.ulaw) + sample = m_ulaw[m_rom[curaddr]]; + else + sample = get_sample(voice); + printf("[%06x=%04x]", curaddr, (INT16)sample); +#endif +*/ + if(fill_output(voice, outputs, samples)) + irq_invalid = true; + +#ifdef ICS2115_DEBUG + if(voice.playing()) { + printf("%d", osc); + if (voice.osc_conf.bitflags.invert) + printf("+"); + else if ((voice.osc.fc >> 1) > 0x1ff) + printf("*"); + printf(" "); + + /*int min = 0x7fffffff, max = 0x80000000; + double average = 0; + for (int i = 0; i < samples; i++) { + if (outputs[0][i] > max) max = outputs[0][i]; + if (outputs[0][i] < min) min = outputs[0][i]; + average += fabs(outputs[0][i]); + } + average /= samples; + average /= 1 << 16; + printf("", min >> 16, max >> 16, average);*/ + } +#endif + } + +#ifdef ICS2115_DEBUG + printf("|"); +#endif + + //rescale + for (int i = 0; i < samples; i++) { + outputs[0][i] >>= 16; + outputs[1][i] >>= 16; + } + + if(irq_invalid) + recalc_irq(); + +} + +//Helper Function (Reads off current register) +UINT16 ics2115_device::reg_read() { + UINT16 ret; + ics2115_voice& voice = m_voice[m_osc_select]; + + switch(m_reg_select) { + case 0x00: // [osc] Oscillator Configuration + ret = voice.osc_conf.value; + ret <<= 8; + break; + + case 0x01: // [osc] Wavesample frequency + // freq = fc*33075/1024 in 32 voices mode, fc*44100/1024 in 24 voices mode + //ret = v->Osc.FC; + ret = voice.osc.fc; + break; + + case 0x02: // [osc] Wavesample loop start high + //TODO: are these returns valid? might be 0x00ff for this one... + ret = (voice.osc.start >> 16) & 0xffff; + break; + + case 0x03: // [osc] Wavesample loop start low + ret = (voice.osc.start >> 0) & 0xff00; + break; + + case 0x04: // [osc] Wavesample loop end high + ret = (voice.osc.end >> 16) & 0xffff; + break; + + case 0x05: // [osc] Wavesample loop end low + ret = (voice.osc.end >> 0) & 0xff00; + break; + + case 0x06: // [osc] Volume Increment + ret = voice.vol.incr; + break; + + case 0x07: // [osc] Volume Start + ret = voice.vol.start >> (10+8); + break; + + case 0x08: // [osc] Volume End + ret = voice.vol.end >> (10+8); + break; + + case 0x09: // [osc] Volume accumulator + //ret = v->Vol.Acc; + ret = voice.vol.acc >> (10); + break; + + case 0x0A: // [osc] Wavesample address + ret = (voice.osc.acc >> 16) & 0xffff; + break; + + case 0x0B: // [osc] Wavesample address + ret = (voice.osc.acc >> 0) & 0xfff8; + break; + + + case 0x0C: // [osc] Pan + ret = voice.vol.pan << 8; + break; + + /* DDP3 code (trap15's reversal) */ + /* 0xA13's work: + res = read() & 0xC3; + if(!(res & 2)) res |= 1; + e = d = res; + */ + /* 0xA4F's work: + while(!(read() & 1)) + */ + case 0x0D: // [osc] Volume Envelope Control + //ret = v->Vol.Ctl | ((v->state & FLAG_STATE_VOLIRQ) ? 0x81 : 1); + // may expect |8 on voice irq with &40 == 0 + // may expect |8 on reg 0 on voice irq with &80 == 0 + // ret = 0xFF; + if (!m_vmode) + ret = voice.vol_ctrl.bitflags.irq ? 0x81 : 0x01; + else + ret = 0x01; + //ret = voice.vol_ctrl.bitflags.value | 0x1; + ret <<= 8; + break; + + case 0x0E: // Active Voices + ret = m_active_osc; + break; + + case 0x0F:{// [osc] Interrupt source/oscillator + ret = 0xff; + for (int i = 0; i <= m_active_osc; i++) { + ics2115_voice& v = m_voice[i]; + if (v.osc_conf.bitflags.irq_pending || v.vol_ctrl.bitflags.irq_pending) { + ret = i | 0xe0; + ret &= v.vol_ctrl.bitflags.irq_pending ? (~0x40) : 0xff; + ret &= v.osc_conf.bitflags.irq_pending ? (~0x80) : 0xff; + recalc_irq(); + if (v.osc_conf.bitflags.irq_pending) { + v.osc_conf.bitflags.irq_pending = 0; + ret &= ~0x80; + } + if (v.vol_ctrl.bitflags.irq_pending) { + v.vol_ctrl.bitflags.irq_pending = 0; + ret &= ~0x40; + } + break; + } + } + ret <<= 8; + break;} + + case 0x10: // [osc] Oscillator Control + ret = voice.osc.ctl << 8; + break; + + case 0x11: // [osc] Wavesample static address 27-20 + ret = voice.osc.saddr << 8; + break; + + case 0x40: // Timer 0 clear irq + case 0x41: // Timer 1 clear irq + //TODO: examine this suspect code + ret = m_timer[m_reg_select & 0x1].preset; + m_irq_pending &= ~(1 << (m_reg_select & 0x1)); + recalc_irq(); + break; + + case 0x43: // Timer status + ret = m_irq_pending & 3; + break; + + case 0x4A: // IRQ Pending + ret = m_irq_pending; + break; + + case 0x4B: // Address of Interrupting Oscillator + ret = 0x80; + break; + + case 0x4C: // Chip Revision + ret = revision; + break; + + default: +#ifdef ICS2115_DEBUG + printf("ICS2115: Unhandled read %x\n", m_reg_select); +#endif + ret = 0; + break; + } + return ret; +} + +void ics2115_device::reg_write(UINT8 data, bool msb) { + ics2115_voice& voice = m_voice[m_osc_select]; + + switch(m_reg_select) { + case 0x00: // [osc] Oscillator Configuration + if(msb) { + voice.osc_conf.value &= 0x80; + voice.osc_conf.value |= data & 0x7f; + } + break; + + case 0x01: // [osc] Wavesample frequency + // freq = fc*33075/1024 in 32 voices mode, fc*44100/1024 in 24 voices mode + if(msb) + voice.osc.fc = (voice.osc.fc & 0x00ff) | (data << 8); + else + //last bit not used! + voice.osc.fc = (voice.osc.fc & 0xff00) | (data & 0xfe); + break; + + case 0x02: // [osc] Wavesample loop start high + if(msb) + voice.osc.start = (voice.osc.start & 0x00ffffff) | (data << 24); + else + voice.osc.start = (voice.osc.start & 0xff00ffff) | (data << 16); + break; + + case 0x03: // [osc] Wavesample loop start low + if(msb) + voice.osc.start = (voice.osc.start & 0xffff00ff) | (data << 8); + // This is unused? + //else + //voice.osc.start = (voice.osc.start & 0xffffff00) | (data & 0); + break; + + case 0x04: // [osc] Wavesample loop end high + if(msb) + voice.osc.end = (voice.osc.end & 0x00ffffff) | (data << 24); + else + voice.osc.end = (voice.osc.end & 0xff00ffff) | (data << 16); + break; + + case 0x05: // [osc] Wavesample loop end low + if(msb) + voice.osc.end = (voice.osc.end & 0xffff00ff) | (data << 8); + // lsb is unused? + break; + + case 0x06: // [osc] Volume Increment + if(msb) + voice.vol.incr = data; + break; + + case 0x07: // [osc] Volume Start + if (!msb) + voice.vol.start = data << (10+8); + break; + + case 0x08: // [osc] Volume End + if (!msb) + voice.vol.end = data << (10+8); + break; + + case 0x09: // [osc] Volume accumulator + if(msb) + voice.vol.regacc = (voice.vol.regacc & 0x00ff) | (data << 8); + else + voice.vol.regacc = (voice.vol.regacc & 0xff00) | data; + voice.vol.acc = voice.vol.regacc << 10; + break; + + case 0x0A: // [osc] Wavesample address high +#ifdef ICS2115_DEBUG +#ifdef ICS2115_ISOLATE + if(m_osc_select == ICS2115_ISOLATE) +#endif + printf("<%d:oa:H[%d]=%x>", m_osc_select, msb, data); +#endif + if(msb) + voice.osc.acc = (voice.osc.acc & 0x00ffffff) | (data << 24); + else + voice.osc.acc = (voice.osc.acc & 0xff00ffff) | (data << 16); + break; + + case 0x0B: // [osc] Wavesample address low +#ifdef ICS2115_DEBUG +#ifdef ICS2115_ISOLATE + if(m_osc_select == ICS2115_ISOLATE) +#endif + printf("<%d:oa:L[%d]=%x>", m_osc_select, msb, data); +#endif + if(msb) + voice.osc.acc = (voice.osc.acc & 0xffff00ff) | (data << 8); + else + voice.osc.acc = (voice.osc.acc & 0xffffff00) | (data & 0xF8); + break; + + case 0x0C: // [osc] Pan + if(msb) + voice.vol.pan = data; + break; + + case 0x0D: // [osc] Volume Envelope Control + if(msb) { + voice.vol_ctrl.value &= 0x80; + voice.vol_ctrl.value |= data & 0x7F; + } + break; + + case 0x0E: // Active Voices + //Does this value get added to 1? Not sure. Could trace for writes of 32. + if(msb) { + m_active_osc = data & 0x1F; // & 0x1F ? (Guessing) + } + break; + //2X8 ? + case 0x10: // [osc] Oscillator Control + //Could this be 2X9? + //[7 R | 6 M2 | 5 M1 | 4-2 Reserve | 1 - Timer 2 Strt | 0 - Timer 1 Strt] + + if (msb) { + voice.osc.ctl = data; + if (!data) + keyon(); + //guessing here + else if(data == 0xf) { +#ifdef ICS2115_DEBUG +#ifdef ICS2115_ISOLATE + if (m_osc_select == ICS2115_ISOLATE) +#endif + if (!voice.osc_conf.bitflags.stop || !voice.vol_ctrl.bitflags.stop) + printf("[%02d STOP]\n", m_osc_select); +#endif + if (!m_vmode) { + voice.osc_conf.bitflags.stop = true; + voice.vol_ctrl.bitflags.stop = true; + //try to key it off as well! + voice.state.bitflags.on = false; + } + } +#ifdef ICS2115_DEBUG + else + printf("ICS2115: Unhandled* data write %d onto 0x10.\n", data); +#endif + } + break; + + case 0x11: // [osc] Wavesample static address 27-20 + if(msb) + //v->Osc.SAddr = data; + voice.osc.saddr = data; + break; + case 0x12: + //Could be per voice! -- investigate. + if (msb) + m_vmode = data; + break; + case 0x40: // Timer 1 Preset + case 0x41: // Timer 2 Preset + if(!msb) { + m_timer[m_reg_select & 0x1].preset = data; + recalc_timer(m_reg_select & 0x1); + } + break; + + case 0x42: // Timer 1 Prescale + case 0x43: // Timer 2 Prescale + if(!msb) { + m_timer[m_reg_select & 0x1].scale = data; + recalc_timer(m_reg_select & 0x1); + } + break; + + case 0x4A: // IRQ Enable + if(!msb) { + m_irq_enabled = data; + recalc_irq(); + } + break; + + case 0x4F: // Oscillator Address being Programmed + if(!msb) { + m_osc_select = data % (1+m_active_osc); + } + break; + default: +#ifdef ICS2115_DEBUG + printf("ICS2115: Unhandled write %x onto %x(%d) [voice = %d]\n", data, m_reg_select, msb, m_osc_select); +#endif + break; + } +} + +READ8_MEMBER(ics2115_device::read) +{ + UINT8 ret = 0; + + switch(offset) { + case 0: + //TODO: check this suspect code + if (m_irq_on) { + ret |= 0x80; + if (m_irq_enabled && (m_irq_pending & 3)) + ret |= 1; + for (int i = 0; i <= m_active_osc; i++) { + if (//m_voice[i].vol_ctrl.bitflags.irq_pending || + m_voice[i].osc_conf.bitflags.irq_pending) { + ret |= 2; + break; + } + } + } + + break; + case 1: + ret = m_reg_select; + break; + case 2: + ret = (UINT8)(reg_read()); + break; + case 3: + ret = reg_read() >> 8; + break; + default: +#ifdef ICS2115_DEBUG + printf("ICS2115: Unhandled memory read at %x\n", offset); +#endif + break; + } + return ret; +} + +WRITE8_MEMBER(ics2115_device::write) +{ + switch(offset) { + case 1: + m_reg_select = data; + break; + case 2: + reg_write(data,0); + break; + case 3: + reg_write(data,1); + break; + default: +#ifdef ICS2115_DEBUG + printf("ICS2115: Unhandled memory write %02x to %x\n", data, offset); +#endif + break; + } +} + +void ics2115_device::keyon() +{ +#ifdef ICS2115_ISOLATE + if (m_osc_select != ICS2115_ISOLATE) + return; +#endif + //set initial condition (may need to invert?) -- does NOT work since these are set to zero even + m_voice[m_osc_select].state.bitflags.on = true; + //no ramp up... + m_voice[m_osc_select].state.bitflags.ramp = 0x40; + +#ifdef ICS2115_DEBUG + printf("[%02d vs:%04x ve:%04x va:%04x vi:%02x vc:%02x os:%06x oe:%06x oa:%06x of:%04x SA:%02x oc:%02x][%04x]\n", m_osc_select, + m_voice[m_osc_select].vol.start >> 10, + m_voice[m_osc_select].vol.end >> 10, + m_voice[m_osc_select].vol.acc >> 10, + m_voice[m_osc_select].vol.incr, + m_voice[m_osc_select].vol_ctrl.value, + m_voice[m_osc_select].osc.start >> 12, + m_voice[m_osc_select].osc.end >> 12, + m_voice[m_osc_select].osc.acc >> 12, + m_voice[m_osc_select].osc.fc, + m_voice[m_osc_select].osc.saddr, + m_voice[m_osc_select].osc_conf.value, + m_volume[(m_voice[m_osc_select].vol.acc >> 14)] + ); +#endif + //testing memory corruption issue with mame stream + //printf("m_volume[0x%x]=0x%x\n", mastervolume, m_volume[mastervolume]); +} + +void ics2115_device::recalc_irq() +{ + //Suspect + bool irq = (m_irq_pending & m_irq_enabled); + for(int i = 0; (!irq) && (i < 32); i++) + irq |= m_voice[i].vol_ctrl.bitflags.irq_pending && m_voice[i].osc_conf.bitflags.irq_pending; + m_irq_on = irq; + if(!m_irq_cb.isnull()) + m_irq_cb(irq ? ASSERT_LINE : CLEAR_LINE); +} + +TIMER_CALLBACK_MEMBER( ics2115_device::timer_cb_0 ) +{ + m_irq_pending |= 1 << 0; + recalc_irq(); +} + +TIMER_CALLBACK_MEMBER( ics2115_device::timer_cb_1 ) +{ + m_irq_pending |= 1 << 1; + recalc_irq(); +} + +void ics2115_device::recalc_timer(int timer) +{ + //Old regression-based formula (minus constant) + //UINT64 period = m_timer[timer].preset * (m_timer[timer].scale << 16) / 60; + + //New formula based on O.Galibert's reverse engineering of ICS2115 card firmware + UINT64 period = ((m_timer[timer].scale & 0x1f) + 1) * (m_timer[timer].preset + 1); + period = (period << (4 + (m_timer[timer].scale >> 5)))*78125/2646; + + if(m_timer[timer].period != period) { + m_timer[timer].period = period; + // Adjust the timer lengths + if(period) // Reset the length + m_timer[timer].timer->adjust(attotime::from_nsec(period), 0, attotime::from_nsec(period)); + else // Kill the timer if length == 0 + m_timer[timer].timer->adjust(attotime::never); + } +} diff --git a/src/devices/sound/ics2115.h b/src/devices/sound/ics2115.h new file mode 100644 index 00000000000..fbfeb64e24a --- /dev/null +++ b/src/devices/sound/ics2115.h @@ -0,0 +1,158 @@ +// license:??? +// copyright-holders:Alex Marshall,nimitz,austere +#pragma once + +#ifndef __ICS2115_H__ +#define __ICS2115_H__ + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_ICS2115_ADD(_tag, _clock) \ + MCFG_DEVICE_ADD(_tag, ICS2115, _clock) + +#define MCFG_ICS2115_IRQ_CB(_devcb) \ + devcb = &ics2115_device::set_irq_callback(*device, DEVCB_##_devcb); + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +struct ics2115_voice { + struct { + INT32 left; + UINT32 acc, start, end; + UINT16 fc; + UINT8 ctl, saddr; + } osc; + + struct { + INT32 left; + UINT32 add; + UINT32 start, end; + UINT32 acc; + UINT16 regacc; + UINT8 incr; + UINT8 pan, mode; + } vol; + + union { + struct { + UINT8 ulaw : 1; + UINT8 stop : 1; //stops wave + vol envelope + UINT8 eightbit : 1; + UINT8 loop : 1; + UINT8 loop_bidir : 1; + UINT8 irq : 1; + UINT8 invert : 1; + UINT8 irq_pending: 1; + //IRQ on variable? + } bitflags; + UINT8 value; + } osc_conf; + + union { + struct { + UINT8 done : 1; //indicates ramp has stopped + UINT8 stop : 1; //stops the ramp + UINT8 rollover : 1; //rollover (TODO) + UINT8 loop : 1; + UINT8 loop_bidir : 1; + UINT8 irq : 1; //enable IRQ generation + UINT8 invert : 1; //invert direction + UINT8 irq_pending: 1; //(read only) IRQ pending + //noenvelope == (done | disable) + } bitflags; + UINT8 value; + } vol_ctrl; + + //Possibly redundant state. => improvements of wavetable logic + //may lead to its elimination. + union { + struct { + UINT8 on : 1; + UINT8 ramp : 7; // 100 0000 = 0x40 maximum + } bitflags; + UINT8 value; + } state; + + bool playing(); + int update_volume_envelope(); + int update_oscillator(); + void update_ramp(); +}; + +// ======================> ics2115_device + +class ics2115_device : public device_t, public device_sound_interface +{ +public: + // construction/destruction + ics2115_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + template static devcb_base &set_irq_callback(device_t &device, _Object object) { return downcast(device).m_irq_cb.set_callback(object); } + + DECLARE_READ8_MEMBER(read); + DECLARE_WRITE8_MEMBER(write); + //UINT8 read(offs_t offset); + //void write(offs_t offset, UINT8 data); + TIMER_CALLBACK_MEMBER(timer_cb_0); + TIMER_CALLBACK_MEMBER(timer_cb_1); + + sound_stream *m_stream; + + static const UINT16 revision = 0x1; + +protected: + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // internal callbacks + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + + // internal state + required_region_ptr m_rom; + devcb_write_line m_irq_cb; + + INT16 m_ulaw[256]; + UINT16 m_volume[4096]; + static const int volume_bits = 15; + + ics2115_voice m_voice[32]; + struct { + UINT8 scale, preset; + emu_timer *timer; + UINT64 period; /* in nsec */ + } m_timer[2]; + + UINT8 m_active_osc; + UINT8 m_osc_select; + UINT8 m_reg_select; + UINT8 m_irq_enabled, m_irq_pending; + bool m_irq_on; + + //Unknown variable, seems to be effected by 0x12. Further investigation + //Required. + UINT8 m_vmode; + + //internal register helper functions + UINT16 reg_read(); + void reg_write(UINT8 data, bool msb); + void recalc_timer(int timer); + void keyon(); + void recalc_irq(); + + //stream helper functions + int fill_output(ics2115_voice& voice, stream_sample_t *outputs[2], int samples); + stream_sample_t get_sample(ics2115_voice& voice); +}; + + +// device type definition +extern const device_type ICS2115; + +#endif /* __ICS2115_H__ */ diff --git a/src/devices/sound/iremga20.c b/src/devices/sound/iremga20.c new file mode 100644 index 00000000000..925814945fe --- /dev/null +++ b/src/devices/sound/iremga20.c @@ -0,0 +1,268 @@ +// license:BSD-3-Clause +// copyright-holders:Acho A. Tang,R. Belmont +/********************************************************* + +Irem GA20 PCM Sound Chip + +It's not currently known whether this chip is stereo. + + +Revisions: + +04-15-2002 Acho A. Tang +- rewrote channel mixing +- added prelimenary volume and sample rate emulation + +05-30-2002 Acho A. Tang +- applied hyperbolic gain control to volume and used + a musical-note style progression in sample rate + calculation(still very inaccurate) + +02-18-2004 R. Belmont +- sample rate calculation reverse-engineered. + Thanks to Fujix, Yasuhiro Ogawa, the Guru, and Tormod + for real PCB samples that made this possible. + +02-03-2007 R. Belmont +- Cleaned up faux x86 assembly. + +*********************************************************/ + +#include "emu.h" +#include "iremga20.h" + +#define MAX_VOL 256 + + +// device type definition +const device_type IREMGA20 = &device_creator; + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// iremga20_device - constructor +//------------------------------------------------- + +iremga20_device::iremga20_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, IREMGA20, "Irem GA20", tag, owner, clock, "iremga20", __FILE__), + device_sound_interface(mconfig, *this), + m_rom(NULL), + m_rom_size(0), + m_stream(NULL) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void iremga20_device::device_start() +{ + int i; + + /* Initialize our chip structure */ + m_rom = m_region->base(); + m_rom_size = m_region->bytes(); + + iremga20_reset(); + + for ( i = 0; i < 0x40; i++ ) + m_regs[i] = 0; + + m_stream = stream_alloc(0, 2, clock()/4); + + save_item(NAME(m_regs)); + for (i = 0; i < 4; i++) + { + save_item(NAME(m_channel[i].rate), i); + save_item(NAME(m_channel[i].size), i); + save_item(NAME(m_channel[i].start), i); + save_item(NAME(m_channel[i].pos), i); + save_item(NAME(m_channel[i].frac), i); + save_item(NAME(m_channel[i].end), i); + save_item(NAME(m_channel[i].volume), i); + save_item(NAME(m_channel[i].pan), i); + save_item(NAME(m_channel[i].effect), i); + save_item(NAME(m_channel[i].play), i); + } +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void iremga20_device::device_reset() +{ + iremga20_reset(); +} + + +//------------------------------------------------- +// sound_stream_update - handle a stream update +//------------------------------------------------- + +void iremga20_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + UINT32 rate[4], pos[4], frac[4], end[4], vol[4], play[4]; + UINT8 *pSamples; + stream_sample_t *outL, *outR; + int i, sampleout; + + /* precache some values */ + for (i=0; i < 4; i++) + { + rate[i] = m_channel[i].rate; + pos[i] = m_channel[i].pos; + frac[i] = m_channel[i].frac; + end[i] = m_channel[i].end - 0x20; + vol[i] = m_channel[i].volume; + play[i] = m_channel[i].play; + } + + i = samples; + pSamples = m_rom; + outL = outputs[0]; + outR = outputs[1]; + + for (i = 0; i < samples; i++) + { + sampleout = 0; + + // update the 4 channels inline + if (play[0]) + { + sampleout += (pSamples[pos[0]] - 0x80) * vol[0]; + frac[0] += rate[0]; + pos[0] += frac[0] >> 24; + frac[0] &= 0xffffff; + play[0] = (pos[0] < end[0]); + } + if (play[1]) + { + sampleout += (pSamples[pos[1]] - 0x80) * vol[1]; + frac[1] += rate[1]; + pos[1] += frac[1] >> 24; + frac[1] &= 0xffffff; + play[1] = (pos[1] < end[1]); + } + if (play[2]) + { + sampleout += (pSamples[pos[2]] - 0x80) * vol[2]; + frac[2] += rate[2]; + pos[2] += frac[2] >> 24; + frac[2] &= 0xffffff; + play[2] = (pos[2] < end[2]); + } + if (play[3]) + { + sampleout += (pSamples[pos[3]] - 0x80) * vol[3]; + frac[3] += rate[3]; + pos[3] += frac[3] >> 24; + frac[3] &= 0xffffff; + play[3] = (pos[3] < end[3]); + } + + sampleout >>= 2; + outL[i] = sampleout; + outR[i] = sampleout; + } + + /* update the regs now */ + for (i=0; i < 4; i++) + { + m_channel[i].pos = pos[i]; + m_channel[i].frac = frac[i]; + m_channel[i].play = play[i]; + } +} + +WRITE8_MEMBER( iremga20_device::irem_ga20_w ) +{ + int channel; + + //logerror("GA20: Offset %02x, data %04x\n",offset,data); + + m_stream->update(); + + channel = offset >> 3; + + m_regs[offset] = data; + + switch (offset & 0x7) + { + case 0: /* start address low */ + m_channel[channel].start = ((m_channel[channel].start)&0xff000) | (data<<4); + break; + + case 1: /* start address high */ + m_channel[channel].start = ((m_channel[channel].start)&0x00ff0) | (data<<12); + break; + + case 2: /* end address low */ + m_channel[channel].end = ((m_channel[channel].end)&0xff000) | (data<<4); + break; + + case 3: /* end address high */ + m_channel[channel].end = ((m_channel[channel].end)&0x00ff0) | (data<<12); + break; + + case 4: + m_channel[channel].rate = 0x1000000 / (256 - data); + break; + + case 5: //AT: gain control + m_channel[channel].volume = (data * MAX_VOL) / (data + 10); + break; + + case 6: //AT: this is always written 2(enabling both channels?) + m_channel[channel].play = data; + m_channel[channel].pos = m_channel[channel].start; + m_channel[channel].frac = 0; + break; + } +} + +READ8_MEMBER( iremga20_device::irem_ga20_r ) +{ + int channel; + + m_stream->update(); + + channel = offset >> 3; + + switch (offset & 0x7) + { + case 7: // voice status. bit 0 is 1 if active. (routine around 0xccc in rtypeleo) + return m_channel[channel].play ? 1 : 0; + + default: + logerror("GA20: read unk. register %d, channel %d\n", offset & 0xf, channel); + break; + } + + return 0; +} + + +void iremga20_device::iremga20_reset() +{ + int i; + + for( i = 0; i < 4; i++ ) { + m_channel[i].rate = 0; + m_channel[i].size = 0; + m_channel[i].start = 0; + m_channel[i].pos = 0; + m_channel[i].frac = 0; + m_channel[i].end = 0; + m_channel[i].volume = 0; + m_channel[i].pan = 0; + m_channel[i].effect = 0; + m_channel[i].play = 0; + } +} diff --git a/src/devices/sound/iremga20.h b/src/devices/sound/iremga20.h new file mode 100644 index 00000000000..13bc8c0ef64 --- /dev/null +++ b/src/devices/sound/iremga20.h @@ -0,0 +1,78 @@ +// license:BSD-3-Clause +// copyright-holders:Acho A. Tang,R. Belmont +/********************************************************* + + Irem GA20 PCM Sound Chip + +*********************************************************/ +#pragma once + +#ifndef __IREMGA20_H__ +#define __IREMGA20_H__ + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_IREMGA20_ADD(_tag, _clock) \ + MCFG_DEVICE_ADD(_tag, IREMGA20, _clock) +#define MCFG_IREMGA20_REPLACE(_tag, _clock) \ + MCFG_DEVICE_REPLACE(_tag, IREMGA20, _clock) + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +struct IremGA20_channel_def +{ + UINT32 rate; + UINT32 size; + UINT32 start; + UINT32 pos; + UINT32 frac; + UINT32 end; + UINT32 volume; + UINT32 pan; + UINT32 effect; + UINT32 play; +}; + + +// ======================> iremga20_device + +class iremga20_device : public device_t, + public device_sound_interface +{ +public: + iremga20_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + ~iremga20_device() { } + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // sound stream update overrides + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + +public: + DECLARE_WRITE8_MEMBER( irem_ga20_w ); + DECLARE_READ8_MEMBER( irem_ga20_r ); + +private: + void iremga20_reset(); + +private: + UINT8 *m_rom; + INT32 m_rom_size; + sound_stream *m_stream; + UINT16 m_regs[0x40]; + IremGA20_channel_def m_channel[4]; +}; + +extern const device_type IREMGA20; + + +#endif /* __IREMGA20_H__ */ diff --git a/src/devices/sound/k005289.c b/src/devices/sound/k005289.c new file mode 100644 index 00000000000..746cf04413f --- /dev/null +++ b/src/devices/sound/k005289.c @@ -0,0 +1,242 @@ +// license:BSD-3-Clause +// copyright-holders:Bryan McPhail +/*************************************************************************** + + Konami 005289 - SCC sound as used in Bubblesystem + + This file is pieced together by Bryan McPhail from a combination of + Namco Sound, Amuse by Cab, Nemesis schematics and whoever first + figured out SCC! + + The 005289 is a 2 channel sound generator. Each channel gets its + waveform from a prom (4 bits wide). + + (From Nemesis schematics) + + Address lines A0-A4 of the prom run to the 005289, giving 32 bytes + per waveform. Address lines A5-A7 of the prom run to PA5-PA7 of + the AY8910 control port A, giving 8 different waveforms. PA0-PA3 + of the AY8910 control volume. + + The second channel is the same as above except port B is used. + + The 005289 has 12 address inputs and 4 control inputs: LD1, LD2, TG1, TG2. + It has no data bus, so data values written don't matter. + When LD1 or LD2 is asserted, the 12 bit value on the address bus is + latched. Each of the two channels has its own latch. + When TG1 or TG2 is asserted, the frequency of the respective channel is + set to the previously latched value. + + The 005289 itself is nothing but an address generator. Digital to analog + conversion, volume control and mixing of the channels is all done + externally via resistor networks and 4066 switches and is only implemented + here for convenience. + +***************************************************************************/ + +#include "emu.h" +#include "k005289.h" + +// is this an actual hardware limit? or just an arbitrary divider +// to bring the output frequency down to a reasonable value for MAME? +#define CLOCK_DIVIDER 32 + +// device type definition +const device_type K005289 = &device_creator; + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// k005289_device - constructor +//------------------------------------------------- + +k005289_device::k005289_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, K005289, "K005289 SCC", tag, owner, clock, "k005289", __FILE__), + device_sound_interface(mconfig, *this), + m_sound_prom(NULL), + m_stream(NULL), + m_rate(0), + m_mixer_table(NULL), + m_mixer_lookup(NULL), + m_mixer_buffer(NULL) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void k005289_device::device_start() +{ + /* get stream channels */ + m_rate = clock() / CLOCK_DIVIDER; + m_stream = stream_alloc(0, 1, m_rate); + + /* allocate a pair of buffers to mix into - 1 second's worth should be more than enough */ + m_mixer_buffer = auto_alloc_array(machine(), short, 2 * m_rate); + + /* build the mixer table */ + make_mixer_table(2); + + m_sound_prom = m_region->base(); + + /* reset all the voices */ + for (int i = 0; i < 2; i++) + { + m_counter[i] = 0; + m_frequency[i] = 0; + m_freq_latch[i] = 0; + m_waveform[i] = i * 0x100; + m_volume[i] = 0; + } + + save_item(NAME(m_counter)); + save_item(NAME(m_frequency)); + save_item(NAME(m_freq_latch)); + save_item(NAME(m_waveform)); + save_item(NAME(m_volume)); +} + + +//------------------------------------------------- +// sound_stream_update - handle a stream update +//------------------------------------------------- + +void k005289_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + stream_sample_t *buffer = outputs[0]; + short *mix; + int i,v,f; + + /* zap the contents of the mixer buffer */ + memset(m_mixer_buffer, 0, samples * sizeof(INT16)); + + v=m_volume[0]; + f=m_frequency[0]; + if (v && f) + { + const unsigned char *w = m_sound_prom + m_waveform[0]; + int c = m_counter[0]; + + mix = m_mixer_buffer; + + /* add our contribution */ + for (i = 0; i < samples; i++) + { + int offs; + + c += CLOCK_DIVIDER; + offs = (c / f) & 0x1f; + *mix++ += ((w[offs] & 0x0f) - 8) * v; + } + + /* update the counter for this voice */ + m_counter[0] = c % (f * 0x20); + } + + v=m_volume[1]; + f=m_frequency[1]; + if (v && f) + { + const unsigned char *w = m_sound_prom + m_waveform[1]; + int c = m_counter[1]; + + mix = m_mixer_buffer; + + /* add our contribution */ + for (i = 0; i < samples; i++) + { + int offs; + + c += CLOCK_DIVIDER; + offs = (c / f) & 0x1f; + *mix++ += ((w[offs] & 0x0f) - 8) * v; + } + + /* update the counter for this voice */ + m_counter[1] = c % (f * 0x20); + } + + /* mix it down */ + mix = m_mixer_buffer; + for (i = 0; i < samples; i++) + *buffer++ = m_mixer_lookup[*mix++]; +} + + + + +/********************************************************************************/ + +/* build a table to divide by the number of voices */ +void k005289_device::make_mixer_table(int voices) +{ + int count = voices * 128; + int i; + int gain = 16; + + /* allocate memory */ + m_mixer_table = auto_alloc_array(machine(), INT16, 256 * voices); + + /* find the middle of the table */ + m_mixer_lookup = m_mixer_table + (128 * voices); + + /* fill in the table - 16 bit case */ + for (i = 0; i < count; i++) + { + int val = i * gain * 16 / voices; + if (val > 32767) val = 32767; + m_mixer_lookup[ i] = val; + m_mixer_lookup[-i] = -val; + } +} + + +WRITE8_MEMBER( k005289_device::k005289_control_A_w ) +{ + m_stream->update(); + + m_volume[0] = data & 0xf; + m_waveform[0] = data & 0xe0; +} + + +WRITE8_MEMBER( k005289_device::k005289_control_B_w ) +{ + m_stream->update(); + + m_volume[1] = data & 0xf; + m_waveform[1] = (data & 0xe0) + 0x100; +} + + +WRITE8_MEMBER( k005289_device::ld1_w ) +{ + m_freq_latch[0] = 0xfff - offset; +} + + +WRITE8_MEMBER( k005289_device::ld2_w ) +{ + m_freq_latch[1] = 0xfff - offset; +} + + +WRITE8_MEMBER( k005289_device::tg1_w ) +{ + m_stream->update(); + + m_frequency[0] = m_freq_latch[0]; +} + + +WRITE8_MEMBER( k005289_device::tg2_w ) +{ + m_stream->update(); + + m_frequency[1] = m_freq_latch[1]; +} diff --git a/src/devices/sound/k005289.h b/src/devices/sound/k005289.h new file mode 100644 index 00000000000..8bee1534390 --- /dev/null +++ b/src/devices/sound/k005289.h @@ -0,0 +1,65 @@ +// license:BSD-3-Clause +// copyright-holders:Bryan McPhail +#pragma once + +#ifndef __K005289_H__ +#define __K005289_H__ + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_K005289_ADD(_tag, _clock) \ + MCFG_DEVICE_ADD(_tag, K005289, _clock) +#define MCFG_K005289_REPLACE(_tag, _clock) \ + MCFG_DEVICE_REPLACE(_tag, K005289, _clock) + + +// ======================> k005289_device + +class k005289_device : public device_t, + public device_sound_interface +{ +public: + k005289_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + ~k005289_device() { } + +protected: + // device-level overrides + virtual void device_start(); + + // sound stream update overrides + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + +public: + DECLARE_WRITE8_MEMBER( k005289_control_A_w ); + DECLARE_WRITE8_MEMBER( k005289_control_B_w ); + DECLARE_WRITE8_MEMBER( ld1_w ); + DECLARE_WRITE8_MEMBER( ld2_w ); + DECLARE_WRITE8_MEMBER( tg1_w ); + DECLARE_WRITE8_MEMBER( tg2_w ); + +private: + void make_mixer_table(int voices); + + const unsigned char *m_sound_prom; + sound_stream *m_stream; + int m_rate; + + /* mixer tables and internal buffers */ + INT16 *m_mixer_table; + INT16 *m_mixer_lookup; + short *m_mixer_buffer; + + UINT32 m_counter[2]; + UINT16 m_frequency[2]; + UINT16 m_freq_latch[2]; + UINT16 m_waveform[2]; + UINT8 m_volume[2]; +}; + +extern const device_type K005289; + + +#endif /* __K005289_H__ */ diff --git a/src/devices/sound/k007232.c b/src/devices/sound/k007232.c new file mode 100644 index 00000000000..6f5286b951f --- /dev/null +++ b/src/devices/sound/k007232.c @@ -0,0 +1,424 @@ +// license:BSD-3-Clause +// copyright-holders:Nicola Salmoria,Hiromitsu Shioya +/*********************************************************/ +/* Konami PCM controller */ +/*********************************************************/ + +/* + Changelog, Hiromitsu Shioya 02/05/2002 + fix start address decode timing. (sample loop bug.) + + Changelog, Mish, August 1999: + Removed interface support for different memory regions per channel. + Removed interface support for differing channel volume. + + Added bankswitching. + Added support for multiple chips. + + (Nb: Should different memory regions per channel be needed + the bankswitching function can set this up). + +NS990821 +support for the k007232_VOL() macro. +added external port callback, and functions to set the volume of the channels + +*/ + + +#include "emu.h" +#include "k007232.h" + +#define BASE_SHIFT (12) + + +#if 0 +static const int kdac_note[] = { + 261.63/8, 277.18/8, + 293.67/8, 311.13/8, + 329.63/8, + 349.23/8, 369.99/8, + 392.00/8, 415.31/8, + 440.00/8, 466.16/8, + 493.88/8, + + 523.25/8, +}; + +static const float kdaca_fn[][2] = { + /* B */ + { 0x03f, 493.88/8 }, /* ?? */ + { 0x11f, 493.88/4 }, /* ?? */ + { 0x18f, 493.88/2 }, /* ?? */ + { 0x1c7, 493.88 }, + { 0x1e3, 493.88*2 }, + { 0x1f1, 493.88*4 }, /* ?? */ + { 0x1f8, 493.88*8 }, /* ?? */ + /* A+ */ + { 0x020, 466.16/8 }, /* ?? */ + { 0x110, 466.16/4 }, /* ?? */ + { 0x188, 466.16/2 }, + { 0x1c4, 466.16 }, + { 0x1e2, 466.16*2 }, + { 0x1f1, 466.16*4 }, /* ?? */ + { 0x1f8, 466.16*8 }, /* ?? */ + /* A */ + { 0x000, 440.00/8 }, /* ?? */ + { 0x100, 440.00/4 }, /* ?? */ + { 0x180, 440.00/2 }, + { 0x1c0, 440.00 }, + { 0x1e0, 440.00*2 }, + { 0x1f0, 440.00*4 }, /* ?? */ + { 0x1f8, 440.00*8 }, /* ?? */ + { 0x1fc, 440.00*16}, /* ?? */ + { 0x1fe, 440.00*32}, /* ?? */ + { 0x1ff, 440.00*64}, /* ?? */ + /* G+ */ + { 0x0f2, 415.31/4 }, + { 0x179, 415.31/2 }, + { 0x1bc, 415.31 }, + { 0x1de, 415.31*2 }, + { 0x1ef, 415.31*4 }, /* ?? */ + { 0x1f7, 415.31*8 }, /* ?? */ + /* G */ + { 0x0e2, 392.00/4 }, + { 0x171, 392.00/2 }, + { 0x1b8, 392.00 }, + { 0x1dc, 392.00*2 }, + { 0x1ee, 392.00*4 }, /* ?? */ + { 0x1f7, 392.00*8 }, /* ?? */ + /* F+ */ + { 0x0d0, 369.99/4 }, /* ?? */ + { 0x168, 369.99/2 }, + { 0x1b4, 369.99 }, + { 0x1da, 369.99*2 }, + { 0x1ed, 369.99*4 }, /* ?? */ + { 0x1f6, 369.99*8 }, /* ?? */ + /* F */ + { 0x0bf, 349.23/4 }, /* ?? */ + { 0x15f, 349.23/2 }, + { 0x1af, 349.23 }, + { 0x1d7, 349.23*2 }, + { 0x1eb, 349.23*4 }, /* ?? */ + { 0x1f5, 349.23*8 }, /* ?? */ + /* E */ + { 0x0ac, 329.63/4 }, + { 0x155, 329.63/2 }, /* ?? */ + { 0x1ab, 329.63 }, + { 0x1d5, 329.63*2 }, + { 0x1ea, 329.63*4 }, /* ?? */ + { 0x1f4, 329.63*8 }, /* ?? */ + /* D+ */ + { 0x098, 311.13/4 }, /* ?? */ + { 0x14c, 311.13/2 }, + { 0x1a6, 311.13 }, + { 0x1d3, 311.13*2 }, + { 0x1e9, 311.13*4 }, /* ?? */ + { 0x1f4, 311.13*8 }, /* ?? */ + /* D */ + { 0x080, 293.67/4 }, /* ?? */ + { 0x140, 293.67/2 }, /* ?? */ + { 0x1a0, 293.67 }, + { 0x1d0, 293.67*2 }, + { 0x1e8, 293.67*4 }, /* ?? */ + { 0x1f4, 293.67*8 }, /* ?? */ + { 0x1fa, 293.67*16}, /* ?? */ + { 0x1fd, 293.67*32}, /* ?? */ + /* C+ */ + { 0x06d, 277.18/4 }, /* ?? */ + { 0x135, 277.18/2 }, /* ?? */ + { 0x19b, 277.18 }, + { 0x1cd, 277.18*2 }, + { 0x1e6, 277.18*4 }, /* ?? */ + { 0x1f2, 277.18*8 }, /* ?? */ + /* C */ + { 0x054, 261.63/4 }, + { 0x12a, 261.63/2 }, + { 0x195, 261.63 }, + { 0x1ca, 261.63*2 }, + { 0x1e5, 261.63*4 }, + { 0x1f2, 261.63*8 }, /* ?? */ + + { -1, -1 }, +}; +#endif + +/*************************************************************/ + + +const device_type K007232 = &device_creator; + +k007232_device::k007232_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, K007232, "K007232 PCM Controller", tag, owner, clock, "k007232", __FILE__), + device_sound_interface(mconfig, *this), + m_rom(*this, DEVICE_SELF), + m_port_write_handler(*this) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void k007232_device::device_start() +{ + /* Set up the chips */ + m_pcmlimit = region()->bytes(); + + m_port_write_handler.resolve(); + + for (int i = 0; i < KDAC_A_PCM_MAX; i++) + { + m_addr[i] = 0; + m_start[i] = 0; + m_step[i] = 0; + m_play[i] = 0; + m_bank[i] = 0; + } + m_vol[0][0] = 255; /* channel A output to output A */ + m_vol[0][1] = 0; + m_vol[1][0] = 0; + m_vol[1][1] = 255; /* channel B output to output B */ + + for (int i = 0; i < 0x10; i++) + m_wreg[i] = 0; + + m_stream = machine().sound().stream_alloc(*this, 0 , 2, clock()/128); + + KDAC_A_make_fncode(); + + save_item(NAME(m_vol)); + save_item(NAME(m_addr)); + save_item(NAME(m_start)); + save_item(NAME(m_step)); + save_item(NAME(m_bank)); + save_item(NAME(m_play)); + save_item(NAME(m_wreg)); +} + +void k007232_device::KDAC_A_make_fncode() +{ +#if 0 + int i, j, k; + float fn; + for( i = 0; i < 0x200; i++ ) fncode[i] = 0; + + i = 0; + while( (int)kdaca_fn[i][0] != -1 ){ + fncode[(int)kdaca_fn[i][0]] = kdaca_fn[i][1]; + i++; + } + + i = j = 0; + while( i < 0x200 ){ + if( fncode[i] != 0 ){ + if( i != j ){ + fn = (fncode[i] - fncode[j]) / (i - j); + for( k = 1; k < (i-j); k++ ) + fncode[k+j] = fncode[j] + fn*k; + j = i; + } + } + i++; + } +#if 0 + for( i = 0; i < 0x200; i++ ) + logerror("fncode[%04x] = %.2f\n", i, fncode[i] ); +#endif + +#else + int i; + for( i = 0; i < 0x200; i++ ) + { + //fncode[i] = (0x200 * 55) / (0x200 - i); + m_fncode[i] = (32 << BASE_SHIFT) / (0x200 - i); +// m_fncode[i] = ((0x200 * 55.2 / 880) / (0x200 - i)); + // = 512 * 55.2 / 220 / (512 - i) = 128 / (512 - i) + // logerror("2 : fncode[%04x] = %.2f\n", i, fncode[i] ); + } + +#endif +} + + +/************************************************/ +/* Konami PCM write register */ +/************************************************/ +WRITE8_MEMBER( k007232_device::write ) +{ + int r = offset; + int v = data; + + m_stream->update(); + + m_wreg[r] = v; /* stock write data */ + + if (r == 0x0c){ + /* external port, usually volume control */ + if (!m_port_write_handler.isnull()) m_port_write_handler(0, v, mem_mask); + return; + } + else if( r == 0x0d ){ + /* loopflag. */ + return; + } + else{ + int reg_port; + + reg_port = 0; + if (r >= 0x06){ + reg_port = 1; + r -= 0x06; + } + + switch (r){ + case 0x00: + case 0x01: + { + /**** address step ****/ + int idx = (((((unsigned int)m_wreg[reg_port*0x06 + 0x01])<<8)&0x0100) | (((unsigned int)m_wreg[reg_port*0x06 + 0x00])&0x00ff)); +#if 0 + if( !reg_port && r == 1 ) + logerror("%04x\n" ,idx ); +#endif + + m_step[reg_port] = m_fncode[idx]; + break; + } + case 0x02: + case 0x03: + case 0x04: + break; + case 0x05: + /**** start address ****/ + m_start[reg_port] = + ((((unsigned int)m_wreg[reg_port*0x06 + 0x04]<<16)&0x00010000) | + (((unsigned int)m_wreg[reg_port*0x06 + 0x03]<< 8)&0x0000ff00) | + (((unsigned int)m_wreg[reg_port*0x06 + 0x02] )&0x000000ff) | + m_bank[reg_port]); + if (m_start[reg_port] < m_pcmlimit ){ + m_play[reg_port] = 1; + m_addr[reg_port] = 0; + } + break; + } + } +} + +/************************************************/ +/* Konami PCM read register */ +/************************************************/ +READ8_MEMBER( k007232_device::read ) +{ + int r = offset; + int ch = 0; + + if( r == 0x0005 || r == 0x000b ){ + ch = r/0x0006; + r = ch * 0x0006; + + m_start[ch] = + ((((unsigned int)m_wreg[r + 0x04]<<16)&0x00010000) | + (((unsigned int)m_wreg[r + 0x03]<< 8)&0x0000ff00) | + (((unsigned int)m_wreg[r + 0x02] )&0x000000ff) | + m_bank[ch]); + + if (m_start[ch] < m_pcmlimit ){ + m_play[ch] = 1; + m_addr[ch] = 0; + } + } + return 0; +} + +/*****************************************************************************/ + +void k007232_device::set_volume(int channel,int volumeA,int volumeB) +{ + m_vol[channel][0] = volumeA; + m_vol[channel][1] = volumeB; +} + +void k007232_device::set_bank(int chABank, int chBBank ) +{ + m_bank[0] = chABank<<17; + m_bank[1] = chBBank<<17; +} + +/*****************************************************************************/ + + +//------------------------------------------------- +// sound_stream_update - handle a stream update +//------------------------------------------------- + +void k007232_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + int i; + + memset(outputs[0],0,samples * sizeof(*outputs[0])); + memset(outputs[1],0,samples * sizeof(*outputs[1])); + + for( i = 0; i < KDAC_A_PCM_MAX; i++ ) + { + if (m_play[i]) + { + int volA,volB,j,out; + unsigned int addr, old_addr; + //int cen; + + /**** PCM setup ****/ + addr = m_start[i] + ((m_addr[i]>>BASE_SHIFT)&0x000fffff); + volA = m_vol[i][0] * 2; + volB = m_vol[i][1] * 2; +#if 0 + cen = (volA + volB) / 2; + volA = (volA + cen) < 0x1fe ? (volA + cen) : 0x1fe; + volB = (volB + cen) < 0x1fe ? (volB + cen) : 0x1fe; +#endif + + for( j = 0; j < samples; j++ ) + { + old_addr = addr; + addr = m_start[i] + ((m_addr[i]>>BASE_SHIFT)&0x000fffff); + while (old_addr <= addr) + { + if( (m_rom[old_addr] & 0x80) || old_addr >= m_pcmlimit ) + { + /* end of sample */ + + if( m_wreg[0x0d]&(1< static devcb_base &set_port_write_handler(device_t &device, _Object object) { return downcast(device).m_port_write_handler.set_callback(object); } + + DECLARE_WRITE8_MEMBER( write ); + DECLARE_READ8_MEMBER( read ); + + /* + The 007232 has two channels and produces two outputs. The volume control + is external, however to make it easier to use we handle that inside the + emulation. You can control volume and panning: for each of the two channels + you can set the volume of the two outputs. If panning is not required, + then volumeB will be 0 for channel 0, and volumeA will be 0 for channel 1. + Volume is in the range 0-255. + */ + void set_volume(int channel,int volumeA,int volumeB); + + void set_bank( int chABank, int chBBank ); + +protected: + // device-level overrides + virtual void device_start(); + + // sound stream update overrides + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + + void KDAC_A_make_fncode(); + +private: + // internal state + required_region_ptr m_rom; + + UINT8 m_vol[KDAC_A_PCM_MAX][2]; /* volume for the left and right channel */ + UINT32 m_addr[KDAC_A_PCM_MAX]; + UINT32 m_start[KDAC_A_PCM_MAX]; + UINT32 m_step[KDAC_A_PCM_MAX]; + UINT32 m_bank[KDAC_A_PCM_MAX]; + int m_play[KDAC_A_PCM_MAX]; + + UINT8 m_wreg[0x10]; /* write data */ + + UINT32 m_pcmlimit; + + sound_stream * m_stream; + UINT32 m_fncode[0x200]; + devcb_write8 m_port_write_handler; +}; + +extern const device_type K007232; + + +#endif /* __K007232_H__ */ diff --git a/src/devices/sound/k051649.c b/src/devices/sound/k051649.c new file mode 100644 index 00000000000..d69b9f25445 --- /dev/null +++ b/src/devices/sound/k051649.c @@ -0,0 +1,288 @@ +// license:BSD-3-Clause +// copyright-holders:Bryan McPhail +/*************************************************************************** + + Konami 051649 - SCC1 sound as used in Haunted Castle, City Bomber + + This file is pieced together by Bryan McPhail from a combination of + Namco Sound, Amuse by Cab, Haunted Castle schematics and whoever first + figured out SCC! + + The 051649 is a 5 channel sound generator, each channel gets its + waveform from RAM (32 bytes per waveform, 8 bit signed data). + + This sound chip is the same as the sound chip in some Konami + megaROM cartridges for the MSX. It is actually well researched + and documented: + + http://bifi.msxnet.org/msxnet/tech/scc.html + + Thanks to Sean Young (sean@mess.org) for some bugfixes. + + K052539 is more or less equivalent to this chip except channel 5 + does not share waveram with channel 4. + +***************************************************************************/ + +#include "emu.h" +#include "k051649.h" + +#define FREQ_BITS 16 +#define DEF_GAIN 8 + + +// device type definition +const device_type K051649 = &device_creator; + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// k051649_device - constructor +//------------------------------------------------- + +k051649_device::k051649_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, K051649, "K051649 SCC1", tag, owner, clock, "k051649", __FILE__), + device_sound_interface(mconfig, *this), + m_stream(NULL), + m_mclock(0), + m_rate(0), + m_mixer_table(NULL), + m_mixer_lookup(NULL), + m_mixer_buffer(NULL), + m_test(0) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void k051649_device::device_start() +{ + // get stream channels + m_rate = clock()/16; + m_stream = stream_alloc(0, 1, m_rate); + m_mclock = clock(); + + // allocate a buffer to mix into - 1 second's worth should be more than enough + m_mixer_buffer = auto_alloc_array(machine(), short, 2 * m_rate); + + // build the mixer table + make_mixer_table(5); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void k051649_device::device_reset() +{ + k051649_sound_channel *voice = m_channel_list; + int i; + + // reset all the voices + for (i = 0; i < 5; i++) + { + voice[i].frequency = 0; + voice[i].volume = 0xf; + voice[i].counter = 0; + voice[i].key = 0; + } + + // other parameters + m_test = 0; +} + + +//------------------------------------------------- +// sound_stream_update - handle a stream update +//------------------------------------------------- + +void k051649_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + k051649_sound_channel *voice=m_channel_list; + stream_sample_t *buffer = outputs[0]; + short *mix; + int i,j; + + // zap the contents of the mixer buffer + memset(m_mixer_buffer, 0, samples * sizeof(short)); + + for (j = 0; j < 5; j++) + { + // channel is halted for freq < 9 + if (voice[j].frequency > 8) + { + const signed char *w = voice[j].waveram; + int v=voice[j].volume * voice[j].key; + int c=voice[j].counter; + int step = ((INT64)m_mclock * (1 << FREQ_BITS)) / (float)((voice[j].frequency + 1) * 16 * (m_rate / 32)) + 0.5f; + + mix = m_mixer_buffer; + + // add our contribution + for (i = 0; i < samples; i++) + { + int offs; + + c += step; + offs = (c >> FREQ_BITS) & 0x1f; + *mix++ += (w[offs] * v)>>3; + } + + // update the counter for this voice + voice[j].counter = c; + } + } + + // mix it down + mix = m_mixer_buffer; + for (i = 0; i < samples; i++) + *buffer++ = m_mixer_lookup[*mix++]; +} + + +/********************************************************************************/ + + +WRITE8_MEMBER( k051649_device::k051649_waveform_w ) +{ + // waveram is read-only? + if (m_test & 0x40 || (m_test & 0x80 && offset >= 0x60)) + return; + + m_stream->update(); + + if (offset >= 0x60) + { + // channel 5 shares waveram with channel 4 + m_channel_list[3].waveram[offset&0x1f]=data; + m_channel_list[4].waveram[offset&0x1f]=data; + } + else + m_channel_list[offset>>5].waveram[offset&0x1f]=data; +} + + +READ8_MEMBER ( k051649_device::k051649_waveform_r ) +{ + // test-register bits 6/7 expose the internal counter + if (m_test & 0xc0) + { + m_stream->update(); + + if (offset >= 0x60) + offset += (m_channel_list[3 + (m_test >> 6 & 1)].counter >> FREQ_BITS); + else if (m_test & 0x40) + offset += (m_channel_list[offset>>5].counter >> FREQ_BITS); + } + return m_channel_list[offset>>5].waveram[offset&0x1f]; +} + + +WRITE8_MEMBER( k051649_device::k052539_waveform_w ) +{ + // waveram is read-only? + if (m_test & 0x40) + return; + + m_stream->update(); + m_channel_list[offset>>5].waveram[offset&0x1f]=data; +} + + +READ8_MEMBER ( k051649_device::k052539_waveform_r ) +{ + // test-register bit 6 exposes the internal counter + if (m_test & 0x40) + { + m_stream->update(); + offset += (m_channel_list[offset>>5].counter >> FREQ_BITS); + } + return m_channel_list[offset>>5].waveram[offset&0x1f]; +} + + +WRITE8_MEMBER( k051649_device::k051649_volume_w ) +{ + m_stream->update(); + m_channel_list[offset&0x7].volume=data&0xf; +} + + +WRITE8_MEMBER( k051649_device::k051649_frequency_w ) +{ + int freq_hi = offset & 1; + offset >>= 1; + + m_stream->update(); + + // test-register bit 5 resets the internal counter + if (m_test & 0x20) + m_channel_list[offset].counter = ~0; + else if (m_channel_list[offset].frequency < 9) + m_channel_list[offset].counter |= ((1 << FREQ_BITS) - 1); + + // update frequency + if (freq_hi) + m_channel_list[offset].frequency = (m_channel_list[offset].frequency & 0x0ff) | (data << 8 & 0xf00); + else + m_channel_list[offset].frequency = (m_channel_list[offset].frequency & 0xf00) | data; +} + + +WRITE8_MEMBER( k051649_device::k051649_keyonoff_w ) +{ + int i; + m_stream->update(); + + for (i = 0; i < 5; i++) + { + m_channel_list[i].key=data&1; + data >>= 1; + } +} + + +WRITE8_MEMBER( k051649_device::k051649_test_w ) +{ + m_test = data; +} + + +READ8_MEMBER ( k051649_device::k051649_test_r ) +{ + // reading the test register sets it to $ff! + k051649_test_w(space, offset, 0xff); + return 0xff; +} + + +//------------------------------------------------- +// build a table to divide by the number of voices +//------------------------------------------------- + +void k051649_device::make_mixer_table(int voices) +{ + int i; + + // allocate memory + m_mixer_table = auto_alloc_array(machine(), INT16, 512 * voices); + + // find the middle of the table + m_mixer_lookup = m_mixer_table + (256 * voices); + + // fill in the table - 16 bit case + for (i = 0; i < (voices * 256); i++) + { + int val = i * DEF_GAIN * 16 / voices; + if (val > 32767) val = 32767; + m_mixer_lookup[ i] = val; + m_mixer_lookup[-i] = -val; + } +} diff --git a/src/devices/sound/k051649.h b/src/devices/sound/k051649.h new file mode 100644 index 00000000000..ee4ffcbfb8e --- /dev/null +++ b/src/devices/sound/k051649.h @@ -0,0 +1,95 @@ +// license:BSD-3-Clause +// copyright-holders:Bryan McPhail +#pragma once + +#ifndef __K051649_H__ +#define __K051649_H__ + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_K051649_ADD(_tag, _clock) \ + MCFG_DEVICE_ADD(_tag, K051649, _clock) +#define MCFG_K051649_REPLACE(_tag, _clock) \ + MCFG_DEVICE_REPLACE(_tag, K051649, _clock) + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// Parameters for a channel +struct k051649_sound_channel +{ + k051649_sound_channel() : + counter(0), + frequency(0), + volume(0), + key(0) + { + memset(waveram, 0, sizeof(signed char)*32); + } + + unsigned long counter; + int frequency; + int volume; + int key; + signed char waveram[32]; +}; + + +// ======================> k051649_device + +class k051649_device : public device_t, + public device_sound_interface +{ +public: + k051649_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + ~k051649_device() { } + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // sound stream update overrides + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + +public: + DECLARE_WRITE8_MEMBER( k051649_waveform_w ); + DECLARE_READ8_MEMBER ( k051649_waveform_r ); + DECLARE_WRITE8_MEMBER( k051649_volume_w ); + DECLARE_WRITE8_MEMBER( k051649_frequency_w ); + DECLARE_WRITE8_MEMBER( k051649_keyonoff_w ); + DECLARE_WRITE8_MEMBER( k051649_test_w ); + DECLARE_READ8_MEMBER ( k051649_test_r ); + + DECLARE_WRITE8_MEMBER( k052539_waveform_w ); + DECLARE_READ8_MEMBER ( k052539_waveform_r ); + +private: + void make_mixer_table(int voices); + +private: + k051649_sound_channel m_channel_list[5]; + + /* global sound parameters */ + sound_stream *m_stream; + int m_mclock; + int m_rate; + + /* mixer tables and internal buffers */ + INT16 *m_mixer_table; + INT16 *m_mixer_lookup; + short *m_mixer_buffer; + + /* chip registers */ + UINT8 m_test; +}; + +extern const device_type K051649; + + +#endif /* __K051649_H__ */ diff --git a/src/devices/sound/k053260.c b/src/devices/sound/k053260.c new file mode 100644 index 00000000000..86054000829 --- /dev/null +++ b/src/devices/sound/k053260.c @@ -0,0 +1,474 @@ +// license:BSD-3-Clause +// copyright-holders:Ernesto Corvi, Alex W. Jackson +/********************************************************* + + Konami 053260 KDSC + + The 053260 is a four voice PCM/ADPCM sound chip that + also incorporates four 8-bit ports for communication + between a main CPU and audio CPU. The chip's output + is compatible with a YM3012 DAC, and it has a digital + auxiliary input compatible with the output of a YM2151. + Some games (e.g. Simpsons) only connect one channel of + the YM2151, but others (e.g. Thunder Cross II) connect + both channels for stereo mixing. + + The 053260 has a 21-bit address bus and 8-bit data bus + to ROM, allowing it to access up to 2 megabytes of + sample data. Sample data can be either signed 8-bit + PCM or a custom 4-bit ADPCM format. It is possible for + two 053260 chips to share access to the same ROMs + (used by Over Drive) + + The 053260 has separate address and data buses to the + audio CPU controlling it and to the main CPU. Both data + buses are 8 bit. The audio CPU address bus has 6 lines + (64 addressable registers, but fewer than 48 are + actually used) while the main CPU "bus" has only 1 line + (2 addressable registers). All registers on the audio + CPU side seem to be either read-only or write-only, + although some games write 0 to all the registers in a + loop at startup (including otherwise read-only or + entirely unused registers). + On the main CPU side, reads and writes to the same + address access different communication ports. + + The sound data ROMs of Simpsons and Vendetta have + "headers" listing all the samples in the ROM, their + formats ("PCM" or "KADPCM"), start and end addresses. + The header data doesn't seem to be used by the hardware + (none of the other games have headers) but provides + useful information about the chip. + + 2004-02-28 (Oliver Achten) + Fixed ADPCM decoding. Games sound much better now. + + 2014-10-06 (Alex W. Jackson) + Rewrote from scratch in C++; implemented communication + ports properly; used the actual up counters instead of + converting to fractional sample position; fixed ADPCM + decoding bugs; added documentation. + + +*********************************************************/ + +#include "emu.h" +#include "k053260.h" + +#define LOG 0 + +#define CLOCKS_PER_SAMPLE 32 + + + +// device type definition +const device_type K053260 = &device_creator; + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// k053260_device - constructor +//------------------------------------------------- + +k053260_device::k053260_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, K053260, "K053260 KDSC", tag, owner, clock, "k053260", __FILE__), + device_sound_interface(mconfig, *this), + m_rgnoverride(NULL), + m_stream(NULL), + m_rom(NULL), + m_rom_size(0), + m_keyon(0), + m_mode(0) +{ + memset(m_portdata, 0, sizeof(m_portdata)); +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void k053260_device::device_start() +{ + memory_region *ROM = (m_rgnoverride) ? owner()->memregion(m_rgnoverride) : region(); + m_rom = ROM->base(); + m_rom_size = ROM->bytes(); + + m_stream = stream_alloc( 0, 2, clock() / CLOCKS_PER_SAMPLE ); + + /* register with the save state system */ + save_item(NAME(m_portdata)); + save_item(NAME(m_keyon)); + save_item(NAME(m_mode)); + + for (int i = 0; i < 4; i++) + m_voice[i].voice_start(*this, i); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void k053260_device::device_reset() +{ + for (int i = 0; i < 4; i++) + m_voice[i].voice_reset(); +} + + +READ8_MEMBER( k053260_device::main_read ) +{ + // sub-to-main ports + return m_portdata[2 + (offset & 1)]; +} + + +WRITE8_MEMBER( k053260_device::main_write ) +{ + // main-to-sub ports + m_portdata[offset & 1] = data; +} + + +READ8_MEMBER( k053260_device::read ) +{ + offset &= 0x3f; + UINT8 ret = 0; + + switch (offset) + { + case 0x00: // main-to-sub ports + case 0x01: + ret = m_portdata[offset]; + break; + + case 0x29: // voice status + m_stream->update(); + for (int i = 0; i < 4; i++) + ret |= m_voice[i].playing() << i; + break; + + case 0x2e: // read ROM + if (m_mode & 1) + ret = m_voice[0].read_rom(); + else + logerror("%s: Attempting to read K053260 ROM without mode bit set\n", machine().describe_context()); + break; + + default: + logerror("%s: Read from unknown K053260 register %02x\n", machine().describe_context(), offset); + } + return ret; +} + + +WRITE8_MEMBER( k053260_device::write ) +{ + offset &= 0x3f; + + m_stream->update(); + + // per voice registers + if ((offset >= 0x08) && (offset <= 0x27)) + { + m_voice[(offset - 8) / 8].set_register(offset, data); + return; + } + + switch (offset) + { + // 0x00 and 0x01 are read registers + + case 0x02: // sub-to-main ports + case 0x03: + m_portdata[offset] = data; + break; + + // 0x04 through 0x07 seem to be unused + + case 0x28: // key on/off + { + UINT8 rising_edge = data & ~m_keyon; + + for (int i = 0; i < 4; i++) + { + if (rising_edge & (1 << i)) + m_voice[i].key_on(); + else if (!(data & (1 << i))) + m_voice[i].key_off(); + } + m_keyon = data; + break; + } + + // 0x29 is a read register + + case 0x2a: // loop and pcm/adpcm select + for (int i = 0; i < 4; i++) + { + m_voice[i].set_loop_kadpcm(data); + data >>= 1; + } + break; + + // 0x2b seems to be unused + + case 0x2c: // pan, voices 0 and 1 + m_voice[0].set_pan(data); + m_voice[1].set_pan(data >> 3); + break; + + case 0x2d: // pan, voices 2 and 3 + m_voice[2].set_pan(data); + m_voice[3].set_pan(data >> 3); + break; + + // 0x2e is a read register + + case 0x2f: // control + m_mode = data; + // bit 0 = enable ROM read from register 0x2e + // bit 1 = enable sound output + // bit 2 = enable aux input? + // (set by all games except Golfing Greats and Rollergames, both of which + // don't have a YM2151. Over Drive only sets it on one of the two chips) + // bit 3 = aux input or ROM sharing related? + // (only set by Over Drive, and only on the same chip that bit 2 is set on) + break; + + default: + logerror("%s: Write to unknown K053260 register %02x (data = %02x)\n", + machine().describe_context(), offset, data); + } +} + + +INLINE int limit( int val, int max, int min ) +{ + if ( val > max ) + val = max; + else if ( val < min ) + val = min; + + return val; +} + +#define MAXOUT 0x7fff +#define MINOUT -0x8000 + +//------------------------------------------------- +// sound_stream_update - handle a stream update +//------------------------------------------------- + +void k053260_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + if (m_mode & 2) + { + for ( int j = 0; j < samples; j++ ) + { + stream_sample_t buffer[2] = {0, 0}; + + for (int i = 0; i < 4; i++) + { + KDSC_Voice &voice = m_voice[i]; + if (voice.playing()) + voice.play(buffer); + } + + outputs[0][j] = limit( buffer[0] >> 1, MAXOUT, MINOUT ); + outputs[1][j] = limit( buffer[1] >> 1, MAXOUT, MINOUT ); + } + } + else + { + memset( outputs[0], 0, samples * sizeof(*outputs[0])); + memset( outputs[1], 0, samples * sizeof(*outputs[1])); + } +} + + +//************************************************************************** +// KDSC_Voice - one of the four voices +//************************************************************************** + +void k053260_device::KDSC_Voice::voice_start(k053260_device &device, int index) +{ + m_device = &device; + + voice_reset(); + + device.save_item(NAME(m_position), index); + device.save_item(NAME(m_pan_volume), index); + device.save_item(NAME(m_counter), index); + device.save_item(NAME(m_output), index); + device.save_item(NAME(m_playing), index); + device.save_item(NAME(m_start), index); + device.save_item(NAME(m_length), index); + device.save_item(NAME(m_pitch), index); + device.save_item(NAME(m_volume), index); + device.save_item(NAME(m_pan), index); + device.save_item(NAME(m_loop), index); + device.save_item(NAME(m_kadpcm), index); +} + +void k053260_device::KDSC_Voice::voice_reset() +{ + m_position = 0; + m_counter = 0; + m_output = 0; + m_playing = false; + m_start = 0; + m_length = 0; + m_pitch = 0; + m_volume = 0; + m_pan = 0; + m_loop = false; + m_kadpcm = false; + update_pan_volume(); +} + +void k053260_device::KDSC_Voice::set_register(offs_t offset, UINT8 data) +{ + switch (offset & 0x7) + { + case 0: // pitch, lower 8 bits + m_pitch = (m_pitch & 0x0f00) | data; + break; + case 1: // pitch, upper 4 bits + m_pitch = (m_pitch & 0x00ff) | ((data << 8) & 0x0f00); + break; + case 2: // length, lower 8 bits + m_length = (m_length & 0xff00) | data; + break; + case 3: // length, upper 8 bits + m_length = (m_length & 0x00ff) | (data << 8); + break; + case 4: // start, lower 8 bits + m_start = (m_start & 0x1fff00) | data; + break; + case 5: // start, middle 8 bits + m_start = (m_start & 0x1f00ff) | (data << 8); + break; + case 6: // start, upper 5 bits + m_start = (m_start & 0x00ffff) | ((data << 16) & 0x1f0000); + break; + case 7: // volume, 7 bits + m_volume = data & 0x7f; + update_pan_volume(); + } +} + +void k053260_device::KDSC_Voice::set_loop_kadpcm(UINT8 data) +{ + m_loop = BIT(data, 0); + m_kadpcm = BIT(data, 4); +} + +void k053260_device::KDSC_Voice::set_pan(UINT8 data) +{ + m_pan = data & 0x7; + update_pan_volume(); +} + +void k053260_device::KDSC_Voice::update_pan_volume() +{ + m_pan_volume[0] = m_volume * (8 - m_pan); + m_pan_volume[1] = m_volume * m_pan; +} + +void k053260_device::KDSC_Voice::key_on() +{ + if (m_start >= m_device->m_rom_size) + logerror("K053260: Attempting to start playing past the end of the ROM ( start = %06x, length = %06x )\n", m_start, m_length); + + else if (m_start + m_length >= m_device->m_rom_size) + logerror("K053260: Attempting to play past the end of the ROM ( start = %06x, length = %06x )\n", + m_start, m_length); + + else + { + m_position = m_kadpcm ? 1 : 0; // for kadpcm low bit is nybble offset, so must start at 1 due to preincrement + m_counter = 0x1000 - CLOCKS_PER_SAMPLE; // force update on next sound_stream_update + m_output = 0; + m_playing = true; + if (LOG) logerror("K053260: start = %06x, length = %06x, pitch = %04x, vol = %02x, loop = %s, %s\n", + m_start, m_length, m_pitch, m_volume, m_loop ? "yes" : "no", m_kadpcm ? "KADPCM" : "PCM" ); + } +} + +void k053260_device::KDSC_Voice::key_off() +{ + m_position = 0; + m_output = 0; + m_playing = false; +} + +void k053260_device::KDSC_Voice::play(stream_sample_t *outputs) +{ + m_counter += CLOCKS_PER_SAMPLE; + + while (m_counter >= 0x1000) + { + m_counter = m_counter - 0x1000 + m_pitch; + + UINT32 bytepos = ++m_position >> ( m_kadpcm ? 1 : 0 ); + /* + Yes, _pre_increment. Playback must start 1 byte position after the + start address written to the register, or else ADPCM sounds will + have DC offsets (e.g. TMNT2 theme song) or will overflow and be + distorted (e.g. various Vendetta sound effects) + The "headers" in the Simpsons and Vendetta sound ROMs provide + further evidence of this quirk (the start addresses listed in the + ROM header are all 1 greater than the addresses the CPU writes + into the register) + */ + if (bytepos > m_length) + { + if (m_loop) + { + m_position = m_output = bytepos = 0; + } + else + { + m_playing = false; + return; + } + } + + UINT8 romdata = m_device->m_rom[m_start + bytepos]; + + if (m_kadpcm) + { + if (m_position & 1) romdata >>= 4; // decode low nybble, then high nybble + static const INT8 kadpcm_table[] = {0,1,2,4,8,16,32,64,-128,-64,-32,-16,-8,-4,-2,-1}; + m_output += kadpcm_table[romdata & 0xf]; + } + else + { + m_output = romdata; + } + } + + outputs[0] += m_output * m_pan_volume[0]; + outputs[1] += m_output * m_pan_volume[1]; +} + +UINT8 k053260_device::KDSC_Voice::read_rom() +{ + UINT32 offs = m_start + m_position; + + m_position = (m_position + 1) & 0xffff; + + if (offs >= m_device->m_rom_size) + { + logerror("%s: K053260: Attempting to read past the end of the ROM (offs = %06x, size = %06x)\n", + m_device->machine().describe_context(), offs, m_device->m_rom_size); + return 0; + } + + return m_device->m_rom[offs]; +} diff --git a/src/devices/sound/k053260.h b/src/devices/sound/k053260.h new file mode 100644 index 00000000000..4a6e6353d08 --- /dev/null +++ b/src/devices/sound/k053260.h @@ -0,0 +1,113 @@ +// license:BSD-3-Clause +// copyright-holders:Ernesto Corvi, Alex W. Jackson +/********************************************************* + + Konami 053260 KDSC + +*********************************************************/ + +#pragma once + +#ifndef __K053260_H__ +#define __K053260_H__ + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_K053260_ADD(_tag, _clock) \ + MCFG_DEVICE_ADD(_tag, K053260, _clock) +#define MCFG_K053260_REPLACE(_tag, _clock) \ + MCFG_DEVICE_REPLACE(_tag, K053260, _clock) + +#define MCFG_K053260_REGION(_tag) \ + k053260_device::set_region_tag(*device, _tag); + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> k053260_device + +class k053260_device : public device_t, + public device_sound_interface +{ +public: + k053260_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + ~k053260_device() { } + + static void set_region_tag(device_t &device, const char *tag) { downcast(device).m_rgnoverride = tag; } + + DECLARE_READ8_MEMBER( main_read ); + DECLARE_WRITE8_MEMBER( main_write ); + DECLARE_READ8_MEMBER( read ); + DECLARE_WRITE8_MEMBER( write ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // sound stream update overrides + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + +private: + // configuration + const char * m_rgnoverride; + + sound_stream * m_stream; + UINT8 * m_rom; + UINT32 m_rom_size; + + // live state + UINT8 m_portdata[4]; + UINT8 m_keyon; + UINT8 m_mode; + + // per voice state + class KDSC_Voice + { + public: + inline void voice_start(k053260_device &device, int index); + inline void voice_reset(); + inline void set_register(offs_t offset, UINT8 data); + inline void set_loop_kadpcm(UINT8 data); + inline void set_pan(UINT8 data); + inline void update_pan_volume(); + inline void key_on(); + inline void key_off(); + inline void play(stream_sample_t *outputs); + inline bool playing() { return m_playing; } + inline UINT8 read_rom(); + + private: + // pointer to owning device + k053260_device *m_device; + + // live state + UINT32 m_position; + UINT16 m_pan_volume[2]; + UINT16 m_counter; + INT8 m_output; + bool m_playing; + + // per voice registers + UINT32 m_start; + UINT16 m_length; + UINT16 m_pitch; + UINT8 m_volume; + + // bit packed registers + UINT8 m_pan; + bool m_loop; + bool m_kadpcm; + } m_voice[4]; + + friend class k053260_device::KDSC_Voice; +}; + +extern const device_type K053260; + +#endif /* __K053260_H__ */ diff --git a/src/devices/sound/k054539.c b/src/devices/sound/k054539.c new file mode 100644 index 00000000000..965ed5b9b58 --- /dev/null +++ b/src/devices/sound/k054539.c @@ -0,0 +1,534 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/********************************************************* + + Konami 054539 (TOP) PCM Sound Chip + + A lot of information comes from Amuse. + Big thanks to them. + +*********************************************************/ + +#include "emu.h" +#include "k054539.h" + +const device_type K054539 = &device_creator; + +#define VERBOSE 0 +#define LOG(x) do { if (VERBOSE) logerror x; } while (0) + +k054539_device::k054539_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, K054539, "K054539 ADPCM", tag, owner, clock, "k054539", __FILE__), + device_sound_interface(mconfig, *this), + m_timer_handler(*this), + m_rgnoverride(NULL) +{ +} + + +/* Registers: + 00..ff: 20 bytes/channel, 8 channels + 00..02: pitch (lsb, mid, msb) + 03: volume (0=max, 0x40=-36dB) + 04: reverb volume (idem) + 05: pan (1-f right, 10 middle, 11-1f left) + 06..07: reverb delay (0=max, current computation non-trusted) + 08..0a: loop (lsb, mid, msb) + 0c..0e: start (lsb, mid, msb) (and current position ?) + + 100.1ff: effects? + 13f: pan of the analog input (1-1f) + + 200..20f: 2 bytes/channel, 8 channels + 00: type (b2-3), reverse (b5) + 01: loop (b0) + + 214: Key on (b0-7 = channel 0-7) + 215: Key off "" + 225: ? + 227: Timer frequency + 228: ? + 229: ? + 22a: ? + 22b: ? + 22c: Channel active? (b0-7 = channel 0-7) + 22d: Data read/write port + 22e: ROM/RAM select (00..7f == ROM banks, 80 = Reverb RAM) + 22f: Global control: + .......x - Enable PCM + ......x. - Timer related? + ...x.... - Enable ROM/RAM readback from 0x22d + ..x..... - Timer output enable? + x....... - Disable register RAM updates + + The chip has an optional 0x8000 byte reverb buffer. + The reverb delay is actually an offset in this buffer. +*/ + +void k054539_device::init_flags(int _flags) +{ + flags = _flags; +} + +void k054539_device::set_gain(int channel, double _gain) +{ + if(_gain >= 0) + gain[channel] = _gain; +} +//* + +bool k054539_device::regupdate() +{ + return !(regs[0x22f] & 0x80); +} + +void k054539_device::keyon(int channel) +{ + if(regupdate()) + regs[0x22c] |= 1 << channel; +} + +void k054539_device::keyoff(int channel) +{ + if(regupdate()) + regs[0x22c] &= ~(1 << channel); +} + +void k054539_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ +#define VOL_CAP 1.80 + + static const INT16 dpcm[16] = { + 0<<8, 1<<8, 4<<8, 9<<8, 16<<8, 25<<8, 36<<8, 49<<8, + -64<<8, -49<<8, -36<<8, -25<<8, -16<<8, -9<<8, -4<<8, -1<<8 + }; + + + INT16 *rbase = (INT16 *)ram; + + if(!(regs[0x22f] & 1)) + return; + + for(int sample = 0; sample != samples; sample++) { + double lval, rval; + if(!(flags & DISABLE_REVERB)) + lval = rval = rbase[reverb_pos]; + else + lval = rval = 0; + rbase[reverb_pos] = 0; + + for(int ch=0; ch<8; ch++) + if(regs[0x22c] & (1< 255) + bval = 255; + + int pan = base1[0x05]; + // DJ Main: 81-87 right, 88 middle, 89-8f left + if (pan >= 0x81 && pan <= 0x8f) + pan -= 0x81; + else if (pan >= 0x11 && pan <= 0x1f) + pan -= 0x11; + else + pan = 0x18 - 0x11; + + double cur_gain = gain[ch]; + + double lvol = voltab[vol] * pantab[pan] * cur_gain; + if (lvol > VOL_CAP) + lvol = VOL_CAP; + + double rvol = voltab[vol] * pantab[0xe - pan] * cur_gain; + if (rvol > VOL_CAP) + rvol = VOL_CAP; + + double rbvol= voltab[bval] * cur_gain / 2; + if (rbvol > VOL_CAP) + rbvol = VOL_CAP; + + int rdelta = (base1[6] | (base1[7] << 8)) >> 3; + rdelta = (rdelta + reverb_pos) & 0x3fff; + + int cur_pos = (base1[0x0c] | (base1[0x0d] << 8) | (base1[0x0e] << 16)) & rom_mask; + + int fdelta, pdelta; + if(base2[0] & 0x20) { + delta = -delta; + fdelta = +0x10000; + pdelta = -1; + } else { + fdelta = -0x10000; + pdelta = +1; + } + + int cur_pfrac, cur_val, cur_pval; + if(cur_pos != chan->pos) { + chan->pos = cur_pos; + cur_pfrac = 0; + cur_val = 0; + cur_pval = 0; + } else { + cur_pfrac = chan->pfrac; + cur_val = chan->val; + cur_pval = chan->pval; + } + + switch(base2[0] & 0xc) { + case 0x0: { // 8bit pcm + cur_pfrac += delta; + while(cur_pfrac & ~0xffff) { + cur_pfrac += fdelta; + cur_pos += pdelta; + + cur_pval = cur_val; + cur_val = (INT16)(rom[cur_pos] << 8); + if(cur_val == (INT16)0x8000 && (base2[1] & 1)) { + cur_pos = (base1[0x08] | (base1[0x09] << 8) | (base1[0x0a] << 16)) & rom_mask; + cur_val = (INT16)(rom[cur_pos] << 8); + } + if(cur_val == (INT16)0x8000) { + keyoff(ch); + cur_val = 0; + break; + } + } + break; + } + + case 0x4: { // 16bit pcm lsb first + pdelta <<= 1; + + cur_pfrac += delta; + while(cur_pfrac & ~0xffff) { + cur_pfrac += fdelta; + cur_pos += pdelta; + + cur_pval = cur_val; + cur_val = (INT16)(rom[cur_pos] | rom[cur_pos+1]<<8); + if(cur_val == (INT16)0x8000 && (base2[1] & 1)) { + cur_pos = (base1[0x08] | (base1[0x09] << 8) | (base1[0x0a] << 16)) & rom_mask; + cur_val = (INT16)(rom[cur_pos] | rom[cur_pos+1]<<8); + } + if(cur_val == (INT16)0x8000) { + keyoff(ch); + cur_val = 0; + break; + } + } + break; + } + + case 0x8: { // 4bit dpcm + cur_pos <<= 1; + cur_pfrac <<= 1; + if(cur_pfrac & 0x10000) { + cur_pfrac &= 0xffff; + cur_pos |= 1; + } + + cur_pfrac += delta; + while(cur_pfrac & ~0xffff) { + cur_pfrac += fdelta; + cur_pos += pdelta; + + cur_pval = cur_val; + cur_val = rom[cur_pos>>1]; + if(cur_val == 0x88 && (base2[1] & 1)) { + cur_pos = ((base1[0x08] | (base1[0x09] << 8) | (base1[0x0a] << 16)) & rom_mask) << 1; + cur_val = rom[cur_pos>>1]; + } + if(cur_val == 0x88) { + keyoff(ch); + cur_val = 0; + break; + } + if(cur_pos & 1) + cur_val >>= 4; + else + cur_val &= 15; + cur_val = cur_pval + dpcm[cur_val]; + if(cur_val < -32768) + cur_val = -32768; + else if(cur_val > 32767) + cur_val = 32767; + } + + cur_pfrac >>= 1; + if(cur_pos & 1) + cur_pfrac |= 0x8000; + cur_pos >>= 1; + break; + } + default: + LOG(("Unknown sample type %x for channel %d\n", base2[0] & 0xc, ch)); + break; + } + lval += cur_val * lvol; + rval += cur_val * rvol; + rbase[(rdelta + reverb_pos) & 0x1fff] += INT16(cur_val*rbvol); + + chan->pos = cur_pos; + chan->pfrac = cur_pfrac; + chan->pval = cur_pval; + chan->val = cur_val; + + if(regupdate()) { + base1[0x0c] = cur_pos & 0xff; + base1[0x0d] = cur_pos>> 8 & 0xff; + base1[0x0e] = cur_pos>>16 & 0xff; + } + } + reverb_pos = (reverb_pos + 1) & 0x1fff; + outputs[0][sample] = INT16(lval); + outputs[1][sample] = INT16(rval); + } +} + + +void k054539_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + if (regs[0x22f] & 0x20) + m_timer_handler(m_timer_state ^= 1); +} + +void k054539_device::init_chip() +{ + memset(regs, 0, sizeof(regs)); + memset(posreg_latch, 0, sizeof(posreg_latch)); //* + flags |= UPDATE_AT_KEYON; //* make it default until proven otherwise + + ram = auto_alloc_array(machine(), unsigned char, 0x4000); + reverb_pos = 0; + cur_ptr = 0; + memset(ram, 0, 0x4000); + + memory_region *reg = (m_rgnoverride != NULL) ? owner()->memregion(m_rgnoverride) : region(); + rom = reg->base(); + rom_size = reg->bytes(); + rom_mask = 0xffffffffU; + for(int i=0; i<32; i++) + if((1U<= rom_size) { + rom_mask = (1U<= 0xc && reg <= 0xe) + return; + } + } + + bool latch = (flags & UPDATE_AT_KEYON) && (regs[0x22f] & 1); + + if (latch && offset < 0x100) + { + int offs = (offset & 0x1f) - 0xc; + int ch = offset >> 5; + + if (offs >= 0 && offs <= 2) + { + // latch writes to the position index registers + posreg_latch[ch][offs] = data; + return; + } + } + + else + switch(offset) { + case 0x13f: { + int pan = data >= 0x11 && data <= 0x1f ? data - 0x11 : 0x18 - 0x11; + if (!m_apan_cb.isnull()) + m_apan_cb(pantab[pan], pantab[0xe - pan]); + break; + } + + case 0x214: + if (latch) + { + for(int ch=0; ch<8; ch++) + { + if(data & (1<adjust(period, 0, period); + + m_timer_state = 0; + m_timer_handler(m_timer_state); + } + break; + + case 0x22d: + if(regs[0x22e] == 0x80) + cur_zone[cur_ptr] = data; + cur_ptr++; + if(cur_ptr == cur_limit) + cur_ptr = 0; + break; + + case 0x22e: + cur_zone = + data == 0x80 ? ram : + rom + 0x20000*data; + cur_limit = data == 0x80 ? 0x4000 : 0x20000; + cur_ptr = 0; + break; + + case 0x22f: + if (!(data & 0x20)) // Disable timer output? + { + m_timer_state = 0; + m_timer_handler(m_timer_state); + } + break; + + default: +#if 0 + if(regs[offset] != data) { + if((offset & 0xff00) == 0) { + chanoff = offset & 0x1f; + if(chanoff < 4 || chanoff == 5 || + (chanoff >=8 && chanoff <= 0xa) || + (chanoff >= 0xc && chanoff <= 0xe)) + break; + } + if(1 || ((offset >= 0x200) && (offset <= 0x210))) + break; + logerror("K054539 %03x = %02x\n", offset, data); + } +#endif + break; + } + + regs[offset] = data; +} + +void k054539_device::device_post_load() +{ + int data = regs[0x22e]; + cur_zone = data == 0x80 ? ram : rom + 0x20000*data; + cur_limit = data == 0x80 ? 0x4000 : 0x20000; +} + +READ8_MEMBER(k054539_device::read) +{ + switch(offset) { + case 0x22d: + if(regs[0x22f] & 0x10) { + UINT8 res = cur_zone[cur_ptr]; + cur_ptr++; + if(cur_ptr == cur_limit) + cur_ptr = 0; + return res; + } else + return 0; + case 0x22c: + break; + default: + LOG(("K054539 read %03x\n", offset)); + break; + } + return regs[offset]; +} + +void k054539_device::device_start() +{ + m_timer = timer_alloc(0); + + // resolve / bind callbacks + m_timer_handler.resolve_safe(); + m_apan_cb.bind_relative_to(*owner()); + + for (int i = 0; i < 8; i++) + gain[i] = 1.0; + + flags = RESET_FLAGS; + + /* + I've tried various equations on volume control but none worked consistently. + The upper four channels in most MW/GX games simply need a significant boost + to sound right. For example, the bass and smash sound volumes in Violent Storm + have roughly the same values and the voices in Tokimeki Puzzledama are given + values smaller than those of the hihats. Needless to say the two K054539 chips + in Mystic Warriors are completely out of balance. Rather than forcing a + "one size fits all" function to the voltab the current invert exponential + appraoch seems most appropriate. + */ + // Factor the 1/4 for the number of channels in the volume (1/8 is too harsh, 1/2 gives clipping) + // vol=0 -> no attenuation, vol=0x40 -> -36dB + for(int i=0; i<256; i++) + voltab[i] = pow(10.0, (-36.0 * (double)i / (double)0x40) / 20.0) / 4.0; + + // Pan table for the left channel + // Right channel is identical with inverted index + // Formula is such that pan[i]**2+pan[0xe-i]**2 = 1 (constant output power) + // and pan[0xe] = 1 (full panning) + for(int i=0; i<0xf; i++) + pantab[i] = sqrt((double)i) / sqrt((double)0xe); + + init_chip(); +} + +void k054539_device::device_reset() +{ + m_timer->enable(false); +} diff --git a/src/devices/sound/k054539.h b/src/devices/sound/k054539.h new file mode 100644 index 00000000000..d6fa2dc73a1 --- /dev/null +++ b/src/devices/sound/k054539.h @@ -0,0 +1,124 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/********************************************************* + + Konami 054539 PCM Sound Chip + +*********************************************************/ + +#pragma once + +#ifndef __K054539_H__ +#define __K054539_H__ + +typedef device_delegate k054539_cb_delegate; +#define K054539_CB_MEMBER(_name) void _name(double left, double right) + +#define MCFG_K054539_APAN_CB(_class, _method) \ + k054539_device::set_analog_callback(*device, k054539_cb_delegate(&_class::_method, #_class "::" #_method, downcast<_class *>(owner))); + +#define MCFG_K054539_REGION_OVERRRIDE(_region) \ + k054539_device::set_override(*device, _region); + +#define MCFG_K054539_TIMER_HANDLER(_devcb) \ + devcb = &k054539_device::set_timer_handler(*device, DEVCB_##_devcb); + + +//* control flags, may be set at DRIVER_INIT(). +#define K054539_RESET_FLAGS 0 +#define K054539_REVERSE_STEREO 1 +#define K054539_DISABLE_REVERB 2 +#define K054539_UPDATE_AT_KEYON 4 + +class k054539_device : public device_t, + public device_sound_interface +{ +public: + enum { + RESET_FLAGS = 0, + REVERSE_STEREO = 1, + DISABLE_REVERB = 2, + UPDATE_AT_KEYON = 4 + }; + + // construction/destruction + k054539_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // static configuration helpers + static void set_analog_callback(device_t &device, k054539_cb_delegate callback) { downcast(device).m_apan_cb = callback; } + static void set_override(device_t &device, const char *rgnoverride) { downcast(device).m_rgnoverride = rgnoverride; } + template static devcb_base &set_timer_handler(device_t &device, _Object object) { return downcast(device).m_timer_handler.set_callback(object); } + + + DECLARE_WRITE8_MEMBER(write); + DECLARE_READ8_MEMBER(read); + + void init_flags(int flags); + + /* + Note that the eight PCM channels of a K054539 do not have separate + volume controls. Considering the global attenuation equation may not + be entirely accurate, k054539_set_gain() provides means to control + channel gain. It can be called anywhere but preferrably from + DRIVER_INIT(). + + Parameters: + channel : 0 - 7 + gain : 0.0=silent, 1.0=no gain, 2.0=twice as loud, etc. + */ + void set_gain(int channel, double gain); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_post_load(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + // device_sound_interface overrides + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + +private: + struct channel { + UINT32 pos; + UINT32 pfrac; + INT32 val; + INT32 pval; + }; + + double voltab[256]; + double pantab[0xf]; + + double gain[8]; + UINT8 posreg_latch[8][3]; + int flags; + + unsigned char regs[0x230]; + unsigned char *ram; + int reverb_pos; + + INT32 cur_ptr; + int cur_limit; + unsigned char *cur_zone; + unsigned char *rom; + UINT32 rom_size; + UINT32 rom_mask; + + channel channels[8]; + sound_stream *stream; + + emu_timer *m_timer; + UINT32 m_timer_state; + devcb_write_line m_timer_handler; + const char *m_rgnoverride; + k054539_cb_delegate m_apan_cb; + + bool regupdate(); + void keyon(int channel); + void keyoff(int channel); + void init_chip(); +}; + +extern const device_type K054539; + +#endif /* __K054539_H__ */ diff --git a/src/devices/sound/k056800.c b/src/devices/sound/k056800.c new file mode 100644 index 00000000000..1534783f8de --- /dev/null +++ b/src/devices/sound/k056800.c @@ -0,0 +1,178 @@ +// license:BSD-3-Clause +// copyright-holders:Ville Linde +/*********************************************************************** + + Konami K056800 (MIRAC) + Sound interface and audio control + +***********************************************************************/ + +#include "emu.h" +#include "sound/k056800.h" + + + +const device_type K056800 = &device_creator; + + + +//------------------------------------------------- +// k056800_device - constructor +//------------------------------------------------- + +k056800_device::k056800_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, K056800, "K056800 MIRAC", tag, owner, clock, "k056800", __FILE__), + m_int_handler(*this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void k056800_device::device_start() +{ + m_int_handler.resolve_safe(); + + save_item(NAME(m_int_pending)); + save_item(NAME(m_host_to_snd_regs)); + save_item(NAME(m_snd_to_host_regs)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void k056800_device::device_reset() +{ + m_int_pending = false; + m_int_enabled = false; + memset(m_host_to_snd_regs, 0, sizeof(m_host_to_snd_regs)); + memset(m_snd_to_host_regs, 0, sizeof(m_snd_to_host_regs)); +} + + +/***************************************************************************** + DEVICE HANDLERS +*****************************************************************************/ + +READ8_MEMBER( k056800_device::host_r ) +{ + UINT32 r = offset & 7; + UINT8 data = 0; + + switch (r) + { + case 0: + case 1: + data = m_snd_to_host_regs[r]; + break; + + case 2: + // .... ...x - Front volume busy + // .... ..x. - Rear volume busy + break; + } + + return data; +} + + +WRITE8_MEMBER( k056800_device::host_w ) +{ + UINT32 r = offset & 7; + + switch (r) + { + case 0: + case 1: + case 2: + case 3: + m_host_to_snd_regs[r] = data; + break; + + case 4: + // xxxx xxxx - Front volume (CAh increments, 35h decrements) + break; + + case 5: + // xxxx xxxx - Rear volume (as above) + break; + + case 6: + // .... ...x - Mute front + // .... ..x. - Mute rear + break; + + case 7: + // Sound interrupt + m_int_pending = true; + + if (m_int_enabled) + m_int_handler(ASSERT_LINE); + + break; + } +} + + +READ8_MEMBER( k056800_device::sound_r ) +{ + UINT32 r = offset & 7; + UINT8 data = 0; + + switch (r) + { + case 0: + case 1: + case 2: + case 3: + data = m_host_to_snd_regs[r]; + break; + } + + return data; +} + + +WRITE8_MEMBER( k056800_device::sound_w ) +{ + UINT32 r = offset & 7; + + switch (r) + { + case 0: + case 1: + m_snd_to_host_regs[r] = data; + break; + + case 2: + case 3: + // TODO: Unknown + break; + + case 4: + // Sound CPU interrupt control + m_int_enabled = (data & 1) != 0; + + if (m_int_enabled) + { + // Enable interrupt + if (m_int_pending) + m_int_handler(ASSERT_LINE); + } + else + { + // Disable/acknowledge interrupt + m_int_pending = false; + m_int_handler(CLEAR_LINE); + } + break; + + case 5: + // TODO: Unknown + break; + } +} diff --git a/src/devices/sound/k056800.h b/src/devices/sound/k056800.h new file mode 100644 index 00000000000..7a14647b3f1 --- /dev/null +++ b/src/devices/sound/k056800.h @@ -0,0 +1,61 @@ +// license:BSD-3-Clause +// copyright-holders:Ville Linde +/********************************************************* + + Konami 056800 MIRAC sound interface + +*********************************************************/ + +#ifndef __K056800_H__ +#define __K056800_H__ + + +/*************************************************************************** + DEVICE CONFIGURATION MACROS +***************************************************************************/ + +#define MCFG_K056800_ADD(_tag, _clock) \ + MCFG_DEVICE_ADD(_tag, K056800, _clock) +#define MCFG_K056800_INT_HANDLER(_devcb) \ + devcb = &k056800_device::set_int_handler(*device, DEVCB_##_devcb); + + + +/*************************************************************************** + TYPE DEFINITIONS +***************************************************************************/ + +class k056800_device : public device_t +{ +public: + // construction/destruction + k056800_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // static configuration helpers + template static devcb_base &set_int_handler(device_t &device, _Object object) { return downcast(device).m_int_handler.set_callback(object); } + + DECLARE_READ8_MEMBER( host_r ); + DECLARE_WRITE8_MEMBER( host_w ); + DECLARE_READ8_MEMBER( sound_r ); + DECLARE_WRITE8_MEMBER( sound_w ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + +private: + // internal state + bool m_int_pending; + bool m_int_enabled; + UINT8 m_host_to_snd_regs[4]; + UINT8 m_snd_to_host_regs[2]; + + devcb_write_line m_int_handler; +}; + +extern const device_type K056800; + + + +#endif /* __K056800_H__ */ diff --git a/src/devices/sound/l7a1045_l6028_dsp_a.c b/src/devices/sound/l7a1045_l6028_dsp_a.c new file mode 100644 index 00000000000..baf277b55e2 --- /dev/null +++ b/src/devices/sound/l7a1045_l6028_dsp_a.c @@ -0,0 +1,348 @@ +// license:LGPL-2.1+ +// copyright-holders:David Haywood, Angelo Salese, ElSemi +/*************************************************************************** + + L7A1045 L6028 DSP-A + (QFP120 package) + + this is the audio chip used on the following + SNK Hyper NeoGeo 64 (arcade platform) + AKAI MPC3000 (synth) + + both are driven by a V53, the MPC3000 isn't dumped. + + appears to write a register number and channel/voice using + l7a1045_sound_select_w (offset 0) + format: + + ---- rrrr ---c cccc + r = register, c = channel + + the channel select appears to address 32 different voices (5-bits) + the register select appears to use 4-bits with 0x0 to 0xa being valid + + the registers data is written / read using offsets 1,2,3 after + setting the register + channel, this gives 3 16-bit values for + each register. + + register format: + + offset 3 offset 2 offset 1 + fedcba9876543210 | fedcba9876543210 | fedcba9876543210 + + 0 ---------------- ---------------- ---------------- + + 1 ---------------- ---------------- ---------------- + + 2 ---------------- ---------------- ---------------- + + 3 ---------------- ---------------- ---------------- + + 4 ---------------- ---------------- ---------------- + + 5 ---------------- ---------------- ---------------- + + 6 ---------------- ---------------- ---------------- + + 7 ---------------- ---------------- llllllllrrrrrrrr left/right volume + + 8 ---------------- ---------------- ---------------- (read only?) + + 9 ---------------- ---------------- ---------------- (read only?) + + a ---------------- ---------------- ---------------- + + Registers are not yet understood. + + probably sample start, end, loop positions, panning etc. + like CPS3, Qsound etc. + + case 0x00: + case 0x01: + case 0x02: + case 0x03: // 00003fffffff (startup only?) + case 0x04: // doesn't use 6 + case 0x05: // 00003fffffff (mostly, often) + case 0x06: // 00007ff0ffff mostly + case 0x07: // 0000000f0708 etc. (low values) + case 0x08: // doesn't write to 2/4/6 with this set?? + case 0x09: // doesn't write to 2/4/6 with this set?? + case 0x0a: // random looking values + + Some of the other ports on the HNG64 sound CPU may also be tied + to this chip, this isn't yet clear. + Port $8 bit 8 is keyon, low byte is sound status related (masked with 0x7f) + + Sample data format TBA + + TODO: + - Sample format needs to be double checked; + - Octave Control/BPM/Pitch, right now XRally Network BGM wants 66150 Hz which is definitely too fast for Terry Bogard speech; + - Key Off; + - ADSR (registers 2 & 4?); + +***************************************************************************/ + +#include "emu.h" +#include "l7a1045_l6028_dsp_a.h" +#include "debugger.h" + + +// device type definition +const device_type L7A1045 = &device_creator; + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// l7a1045_sound_device - constructor +//------------------------------------------------- + +l7a1045_sound_device::l7a1045_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, L7A1045, "L7A1045 L6028 DSP-A", tag, owner, clock, "l7a1045_custom", __FILE__), + device_sound_interface(mconfig, *this), + m_stream(NULL), + m_key(0), + m_rom(NULL), + m_rom_size(0) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void l7a1045_sound_device::device_start() +{ + /* Allocate the stream */ + m_stream = stream_alloc(0, 2, 66150); //clock() / 384); + + m_rom = m_region->base(); + m_rom_size = m_region->bytes(); +} + + +//------------------------------------------------- +// sound_stream_update - handle a stream update +//------------------------------------------------- + +void l7a1045_sound_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + /* Clear the buffers */ + memset(outputs[0], 0, samples*sizeof(*outputs[0])); + memset(outputs[1], 0, samples*sizeof(*outputs[1])); + + for (int i = 0; i < 32; i++) + { + if (m_key & (1 << i)) + { + l7a1045_voice *vptr = &m_voice[i]; + + UINT32 start = vptr->start; + UINT32 end = vptr->end; + UINT32 step = 0x400; + + UINT32 pos = vptr->pos; + UINT32 frac = vptr->frac; + + for (int j = 0; j < samples; j++) + { + INT32 sample; + UINT8 data; + + pos += (frac >> 12); + frac &= 0xfff; + + if ((start + pos) >= end) + { + if(vptr->mode == true) // loop + { + pos = vptr->pos = 0; + frac = vptr->frac = 0; + } + else // no loop, keyoff + { + m_key &= ~(1 << i); + break; + } + } + + + data = m_rom[(start + pos) & (m_rom_size-1)]; + sample = ((INT8)(data & 0xfc)) << (3 - (data & 3)); + frac += step; + + outputs[0][j] += ((sample * vptr->l_volume) >> 9); + outputs[1][j] += ((sample * vptr->r_volume) >> 9); + } + + vptr->pos = pos; + vptr->frac = frac; + } + } +} + +// TODO: needs proper memory map +WRITE16_MEMBER( l7a1045_sound_device::l7a1045_sound_w ) +{ + m_stream->update(); // TODO + + if(offset == 0) + sound_select_w(space, offset, data, mem_mask); + else if(offset == 8/2) + sound_status_w(space, offset, data, mem_mask); + else + sound_data_w(space,offset - 1,data,mem_mask); +} + + +READ16_MEMBER( l7a1045_sound_device::l7a1045_sound_r ) +{ + m_stream->update(); + + if(offset == 0) + printf("sound_select_r?\n"); + else + return sound_data_r(space,offset -1,mem_mask); + + return 0xffff; +} + + +WRITE16_MEMBER(l7a1045_sound_device::sound_select_w) +{ + // I'm guessing these addresses are the sound chip / DSP? + + // ---- ---- 000c cccc + // c = channel + + if (ACCESSING_BITS_0_7) + { + m_audiochannel = data; + if (m_audiochannel & 0xe0) printf("%08x: l7a1045_sound_select_w unknown channel %01x\n", space.device().safe_pc(), m_audiochannel & 0xff); + m_audiochannel &= 0x1f; + } + + if (ACCESSING_BITS_8_15) + { + m_audioregister = (data >> 8); + if (m_audioregister >0x0a) printf("%08x: l7a1045_sound_select_w unknown register %01x\n", space.device().safe_pc(), m_audioregister & 0xff); + m_audioregister &= 0x0f; + } + +} + +WRITE16_MEMBER(l7a1045_sound_device::sound_data_w) +{ + l7a1045_voice *vptr = &m_voice[m_audiochannel]; + + //if(m_audioregister != 0 && m_audioregister != 1 && m_audioregister != 7) + // printf("%04x %04x (%04x %04x)\n",offset,data,m_audioregister,m_audiochannel); + + m_audiodat[m_audioregister][m_audiochannel].dat[offset] = data; + + switch (m_audioregister) + { + case 0x00: + + vptr->start = (m_audiodat[m_audioregister][m_audiochannel].dat[2] & 0x000f) << (16 + 4); + vptr->start |= (m_audiodat[m_audioregister][m_audiochannel].dat[1] & 0xffff) << (4); + vptr->start |= (m_audiodat[m_audioregister][m_audiochannel].dat[0] & 0xf000) >> (12); + + vptr->start &= m_rom_size - 1; + + break; + case 0x01: + // relative to start + //printf("%04x\n",m_audiodat[m_audioregister][m_audiochannel].dat[0]); + //printf("%04x\n",m_audiodat[m_audioregister][m_audiochannel].dat[1]); + //printf("%04x\n",m_audiodat[m_audioregister][m_audiochannel].dat[2]); + + if(m_audiodat[m_audioregister][m_audiochannel].dat[2] & 0x100) + { + vptr->end = (m_audiodat[m_audioregister][m_audiochannel].dat[0] & 0xffff) << 2; + vptr->end += vptr->start; + vptr->mode = false; + // hopefully it'll never happen? Maybe assert here? + vptr->end &= m_rom_size - 1; + + } + else // absolute + { + vptr->end = (m_audiodat[m_audioregister][m_audiochannel].dat[2] & 0x000f) << (16 + 4); + vptr->end |= (m_audiodat[m_audioregister][m_audiochannel].dat[1] & 0xffff) << (4); + vptr->end |= (m_audiodat[m_audioregister][m_audiochannel].dat[0] & 0xf000) >> (12); + vptr->mode = true; + + vptr->end &= m_rom_size - 1; + } + + break; + + case 0x07: + + vptr->r_volume = (m_audiodat[m_audioregister][m_audiochannel].dat[0] & 0xff); + /* TODO: volume tables, linear? */ + vptr->r_volume = (vptr->r_volume) | (vptr->r_volume << 8); + vptr->l_volume = (m_audiodat[m_audioregister][m_audiochannel].dat[0] >> 8) & 0xff; + vptr->l_volume = (vptr->l_volume) | (vptr->l_volume << 8); + //printf("%04x %02x %02x\n",m_audiodat[m_audioregister][m_audiochannel].dat[0],vptr->l_volume,vptr->r_volume); + + break; + } +} + + +READ16_MEMBER(l7a1045_sound_device::sound_data_r) +{ + //printf("%04x (%04x %04x)\n",offset,m_audioregister,m_audiochannel); + //debugger_break(machine()); + l7a1045_voice *vptr = &m_voice[m_audiochannel]; + + switch(m_audioregister) + { + case 0x00: + { + UINT32 current_addr; + UINT16 res; + + current_addr = vptr->start + vptr->pos; + if(offset == 0) + res = (current_addr & 0xf) << 12; // TODO: frac + else if(offset == 1) + res = (current_addr & 0xffff0) >> 4; + else + res = (current_addr & 0xf00000) >> 20; + + return res; + } + } + + return 0; +} + +WRITE16_MEMBER(l7a1045_sound_device::sound_status_w) +{ + if(data & 0x100) // keyin + { + l7a1045_voice *vptr = &m_voice[m_audiochannel]; + + #if 0 + if(vptr->start != 0) + { + printf("%08x START\n",vptr->start); + printf("%08x END\n",vptr->end); + + for(int i=0;i<0x10;i++) + printf("%02x (%02x) = %04x%04x%04x\n",m_audiochannel,i,m_audiodat[i][m_audiochannel].dat[2],m_audiodat[i][m_audiochannel].dat[1],m_audiodat[i][m_audiochannel].dat[0]); + } + #endif + + vptr->frac = 0; + vptr->pos = 0; + m_key |= 1 << m_audiochannel; + } +} diff --git a/src/devices/sound/l7a1045_l6028_dsp_a.h b/src/devices/sound/l7a1045_l6028_dsp_a.h new file mode 100644 index 00000000000..c0283f36836 --- /dev/null +++ b/src/devices/sound/l7a1045_l6028_dsp_a.h @@ -0,0 +1,69 @@ +// license:LGPL-2.1+ +// copyright-holders:David Haywood, Angelo Salese, ElSemi +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +struct l7a1045_voice +{ + l7a1045_voice() : + pos(0), + frac(0) + { + //memset(regs, 0, sizeof(UINT32)*8); + start = 0; + } + + UINT32 start; + UINT32 end; + bool mode; + UINT32 pos; + UINT32 frac; + UINT16 l_volume; + UINT16 r_volume; +}; + +// ======================> l7a1045_sound_device + +class l7a1045_sound_device : public device_t, + public device_sound_interface +{ +public: + l7a1045_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + ~l7a1045_sound_device() { } + +// void set_base(INT8* base) { m_base = base; } + + DECLARE_WRITE16_MEMBER( l7a1045_sound_w ); + DECLARE_READ16_MEMBER( l7a1045_sound_r ); + +protected: + // device-level overrides + virtual void device_start(); + + // sound stream update overrides + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + +private: + sound_stream *m_stream; + l7a1045_voice m_voice[32]; + UINT32 m_key; + UINT8 *m_rom; + INT32 m_rom_size; + + UINT8 m_audiochannel; + UINT8 m_audioregister; + + struct l7a1045_48bit_data { + UINT16 dat[3]; + }; + + l7a1045_48bit_data m_audiodat[0x10][0x20]; + + DECLARE_WRITE16_MEMBER(sound_select_w); + DECLARE_WRITE16_MEMBER(sound_data_w); + DECLARE_READ16_MEMBER(sound_data_r); + DECLARE_WRITE16_MEMBER(sound_status_w); +}; + +extern const device_type L7A1045; diff --git a/src/devices/sound/lmc1992.c b/src/devices/sound/lmc1992.c new file mode 100644 index 00000000000..f4007ea875d --- /dev/null +++ b/src/devices/sound/lmc1992.c @@ -0,0 +1,232 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + LMC1992 Digitally-Controlled Stereo Tone and Volume Circuit with + Four-Channel Input-Selector emulation + +**********************************************************************/ + +/* + + TODO: + + - inputs + - outputs + - bass + - treble + - volume + - balance + +*/ + +#include "lmc1992.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define LOG 0 + + +#define MICROWIRE_DEVICE_ADDRESS 2 + + +enum +{ + FUNCTION_INPUT_SELECT = 0, + FUNCTION_BASS, + FUNCTION_TREBLE, + FUNCTION_VOLUME, + FUNCTION_RIGHT_FRONT_FADER, + FUNCTION_LEFT_FRONT_FADER, + FUNCTION_RIGHT_REAR_FADER, + FUNCTION_LEFT_REAR_FADER +}; + + +enum +{ + INPUT_SELECT_OPEN = 0, + INPUT_SELECT_INPUT1, + INPUT_SELECT_INPUT2, + INPUT_SELECT_INPUT3, + INPUT_SELECT_INPUT4 +}; + + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +// devices +const device_type LMC1992 = &device_creator; + + + +//************************************************************************** +// INLINE HELPERS +//************************************************************************** + +//------------------------------------------------- +// execute_command - +//------------------------------------------------- + +inline void lmc1992_device::execute_command(int addr, int data) +{ + switch (addr) + { + case FUNCTION_INPUT_SELECT: + if (data == INPUT_SELECT_OPEN) + { + if (LOG) logerror("LMC1992 '%s' Input Select : OPEN\n", tag()); + } + else + { + if (LOG) logerror("LMC1992 '%s' Input Select : INPUT%u\n", tag(), data); + } + m_input = data; + break; + + case FUNCTION_BASS: + if (LOG) logerror("LMC1992 '%s' Bass : %i dB\n", tag(), -40 + (data * 2)); + m_bass = data; + break; + + case FUNCTION_TREBLE: + if (LOG) logerror("LMC1992 '%s' Treble : %i dB\n", tag(), -40 + (data * 2)); + m_treble = data; + break; + + case FUNCTION_VOLUME: + if (LOG) logerror("LMC1992 '%s' Volume : %i dB\n", tag(), -80 + (data * 2)); + m_volume = data; + break; + + case FUNCTION_RIGHT_FRONT_FADER: + if (LOG) logerror("LMC1992 '%s' Right Front Fader : %i dB\n", tag(), -40 + (data * 2)); + m_fader_rf = data; + break; + + case FUNCTION_LEFT_FRONT_FADER: + if (LOG) logerror("LMC1992 '%s' Left Front Fader : %i dB\n", tag(), -40 + (data * 2)); + m_fader_lf = data; + break; + + case FUNCTION_RIGHT_REAR_FADER: + if (LOG) logerror("LMC1992 '%s' Right Rear Fader : %i dB\n", tag(), -40 + (data * 2)); + m_fader_rr = data; + break; + + case FUNCTION_LEFT_REAR_FADER: + if (LOG) logerror("LMC1992 '%s' Left Rear Fader : %i dB\n", tag(), -40 + (data * 2)); + m_fader_lr = data; + break; + } +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// lmc1992_device - constructor +//------------------------------------------------- + +lmc1992_device::lmc1992_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, LMC1992, "LMC1992", tag, owner, clock, "lmc1992", __FILE__), + device_sound_interface(mconfig, *this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void lmc1992_device::device_start() +{ + // create sound streams + + // register for state saving + save_item(NAME(m_enable)); + save_item(NAME(m_data)); + save_item(NAME(m_clk)); + save_item(NAME(m_si)); + save_item(NAME(m_input)); + save_item(NAME(m_bass)); + save_item(NAME(m_treble)); + save_item(NAME(m_volume)); + save_item(NAME(m_fader_rf)); + save_item(NAME(m_fader_lf)); + save_item(NAME(m_fader_rr)); + save_item(NAME(m_fader_lr)); +} + + +//------------------------------------------------- +// sound_stream_update - handle update requests for +// our sound stream +//------------------------------------------------- + +void lmc1992_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ +} + + +//------------------------------------------------- +// clock_w - +//------------------------------------------------- + +WRITE_LINE_MEMBER( lmc1992_device::clock_w ) +{ + if ((m_enable == 0) && ((m_clk == 0) && (state == 1))) + { + m_si >>= 1; + m_si = m_si & 0x7fff; + + if (m_data) + { + m_si &= 0x8000; + } + } + + m_clk = state; +} + + +//------------------------------------------------- +// data_w - +//------------------------------------------------- + +WRITE_LINE_MEMBER( lmc1992_device::data_w ) +{ + m_data = state; +} + + +//------------------------------------------------- +// enable_w - +//------------------------------------------------- + +WRITE_LINE_MEMBER( lmc1992_device::enable_w ) +{ + if ((m_enable == 0) && (state == 1)) + { + UINT8 device_addr = (m_si & 0xc000) >> 14; + UINT8 addr = (m_si & 0x3800) >> 11; + UINT8 data = (m_si & 0x07e0) >> 5; + + if (device_addr == MICROWIRE_DEVICE_ADDRESS) + { + execute_command(addr, data); + } + } + + m_enable = state; +} diff --git a/src/devices/sound/lmc1992.h b/src/devices/sound/lmc1992.h new file mode 100644 index 00000000000..0f76e38544e --- /dev/null +++ b/src/devices/sound/lmc1992.h @@ -0,0 +1,113 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + LMC1992 Digitally-Controlled Stereo Tone and Volume Circuit with + Four-Channel Input-Selector emulation + +********************************************************************** + _____ _____ + Data 1 |* \_/ | 28 V+ + Clock 2 | | 27 Bypass + Enable 3 | | 26 Right Input 1 + Left Input 1 4 | | 25 Right Input 2 + Left Input 2 5 | | 24 Right Input 3 + Left Input 3 6 | | 23 Right Input 4 + Left Input 4 7 | LMC1992 | 22 Right Select Out + Left Select Out 8 | | 21 Right Select In + Left Select In 9 | | 20 Right Tone In + Left Tone In 10 | | 19 Right Tone Out + Left Tone Out 11 | | 18 Right Op Amp Out + Left Op Amp Out 12 | | 17 Right Rear Out + Left Rear Out 13 | | 16 Right Front Out + Left Front Out 14 |_____________| 15 Ground + +**********************************************************************/ + +#pragma once + +#ifndef __LMC1992__ +#define __LMC1992__ + +#include "emu.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +enum +{ + LMC1992_LEFT_INPUT_1 = 0, + LMC1992_LEFT_INPUT_2, + LMC1992_LEFT_INPUT_3, + LMC1992_LEFT_INPUT_4, + LMC1992_RIGHT_INPUT_1, + LMC1992_RIGHT_INPUT_2, + LMC1992_RIGHT_INPUT_3, + LMC1992_RIGHT_INPUT_4 +}; + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_LMC1992_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, LMC1992, 0) + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> lmc1992_device + +class lmc1992_device : public device_t, + public device_sound_interface +{ +public: + // construction/destruction + lmc1992_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + DECLARE_WRITE_LINE_MEMBER( clock_w ); + DECLARE_WRITE_LINE_MEMBER( data_w ); + DECLARE_WRITE_LINE_MEMBER( enable_w ); + +protected: + // device-level overrides + virtual void device_start(); + + // internal callbacks + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + +private: + inline void execute_command(int addr, int data); + + //sound_stream *m_stream[4]; + + int m_enable; // enable latch + int m_data; // data latch + int m_clk; // clock latch + UINT16 m_si; // serial in shift register + + int m_input; // input select + int m_bass; // bass + int m_treble; // treble + int m_volume; // volume + int m_fader_rf; // right front fader + int m_fader_lf; // left front fader + int m_fader_rr; // right rear fader + int m_fader_lr; // left rear fader +}; + + +// device type definition +extern const device_type LMC1992; + + + +#endif diff --git a/src/devices/sound/mas3507d.c b/src/devices/sound/mas3507d.c new file mode 100644 index 00000000000..a7be9bb4ba1 --- /dev/null +++ b/src/devices/sound/mas3507d.c @@ -0,0 +1,262 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +// +// MAS 3507D MPEG audio decoder +// + +#include "emu.h" +#include "mas3507d.h" + +// device type definition +const device_type MAS3507D = &device_creator; + +mas3507d_device::mas3507d_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, MAS3507D, "MAS3507D", tag, owner, clock, "mas3507d", __FILE__), + device_sound_interface(mconfig, *this) +{ +} + +void mas3507d_device::device_start() +{ +} + +void mas3507d_device::device_reset() +{ + i2c_scli = i2c_sdai = true; + i2c_sclo = i2c_sdao = true; + i2c_bus_state = IDLE; + i2c_bus_address = UNKNOWN; + i2c_bus_curbit = -1; + i2c_bus_curval = 0; +} + +void mas3507d_device::i2c_scl_w(bool line) +{ + if(line == i2c_scli) + return; + i2c_scli = line; + + if(i2c_scli) { + if(i2c_bus_state == STARTED) { + if(i2c_sdai) + i2c_bus_curval |= 1 << i2c_bus_curbit; + i2c_bus_curbit --; + if(i2c_bus_curbit == -1) { + if(i2c_bus_address == UNKNOWN) { + if(i2c_device_got_address(i2c_bus_curval)) { + i2c_bus_state = ACK; + i2c_bus_address = VALIDATED; + } else { + i2c_bus_state = NAK; + i2c_bus_address = WRONG; + } + } else if(i2c_bus_address == VALIDATED) { + i2c_bus_state = ACK; + i2c_device_got_byte(i2c_bus_curval); + } + } + } else if(i2c_bus_state == ACK) { + i2c_bus_state = ACK2; + i2c_sdao = false; + } + } else { + if(i2c_bus_state == ACK2) { + i2c_bus_state = STARTED; + i2c_bus_curbit = 7; + i2c_bus_curval = 0; + i2c_sdao = true; + } + } +} + +void mas3507d_device::i2c_nak() +{ + assert(i2c_bus_state == ACK); + i2c_bus_state = NAK; +} + +void mas3507d_device::i2c_sda_w(bool line) +{ + if(line == i2c_sdai) + return; + i2c_sdai = line; + + if(i2c_scli) { + if(!i2c_sdai) { + i2c_bus_state = STARTED; + i2c_bus_address = UNKNOWN; + i2c_bus_curbit = 7; + i2c_bus_curval = 0; + } else { + i2c_device_got_stop(); + i2c_bus_state = IDLE; + i2c_bus_address = UNKNOWN; + i2c_bus_curbit = 7; + i2c_bus_curval = 0; + } + } +} + +int mas3507d_device::i2c_scl_r() +{ + return i2c_scli && i2c_sclo; +} + +int mas3507d_device::i2c_sda_r() +{ + return i2c_sdai && i2c_sdao; +} + +bool mas3507d_device::i2c_device_got_address(UINT8 address) +{ + i2c_subdest = UNDEFINED; + return (address & 0xfe) == 0x3a; +} + +void mas3507d_device::i2c_device_got_byte(UINT8 byte) +{ + switch(i2c_subdest) { + case UNDEFINED: + if(byte == 0x68) + i2c_subdest = DATA; + else if(byte == 0x69) + i2c_subdest = DATA; + else if(byte == 0x6a) + i2c_subdest = CONTROL; + else + i2c_subdest = BAD; + i2c_bytecount = 0; + break; + case BAD: + logerror("MAS I2C: Dropping byte %02x\n", byte); + break; + case DATA: + if(!i2c_bytecount) { + switch(byte >> 4) { + case 0: case 1: + i2c_command = CMD_RUN; + i2c_io_adr = byte << 8; + break; + case 3: + i2c_command = CMD_READ_CTRL; + logerror("MAS I2C: READ_CTRL\n"); + break; + case 9: + i2c_io_adr = (byte & 15) << 4; + i2c_command = CMD_WRITE_REG; + break; + case 0xa: case 0xb: + i2c_io_bank = (byte >> 4) & 1; + i2c_command = CMD_WRITE_MEM; + break; + case 0xd: + i2c_command = CMD_READ_REG; + logerror("MAS I2C: READ_REG\n"); + break; + case 0xe: case 0xf: + i2c_io_bank = (byte >> 4) & 1; + i2c_command = CMD_READ_MEM; + logerror("MAS I2C: READ_MEM\n"); + break; + default: + i2c_command = CMD_BAD; + logerror("MAS I2C: BAD\n"); + break; + } + } else { + switch(i2c_command) { + default: + logerror("MAS I2C: Ignoring byte %02x\n", byte); + break; + + case CMD_WRITE_REG: + switch(i2c_bytecount) { + case 1: i2c_io_adr |= byte >> 4; i2c_io_val = byte & 15; break; + case 2: i2c_io_val |= byte << 12; break; + case 3: i2c_io_val |= byte << 4; reg_write(i2c_io_adr, i2c_io_val); break; + case 4: i2c_nak(); return; + } + break; + + case CMD_RUN: + if(i2c_bytecount > 1) { + i2c_nak(); + return; + } + i2c_io_adr |= byte; + run_program(i2c_io_adr); + break; + + case CMD_WRITE_MEM: + switch(i2c_bytecount) { + case 2: i2c_io_count = byte << 8; break; + case 3: i2c_io_count |= byte; break; + case 4: i2c_io_adr = byte << 8; break; + case 5: i2c_io_adr |= byte; break; + } + if(i2c_bytecount >= 6) { + UINT32 i2c_wordid = (i2c_bytecount - 6) >> 2; + UINT32 i2c_offset = (i2c_bytecount - 6) & 3; + if(i2c_wordid >= i2c_io_count) { + i2c_nak(); + return; + } + switch(i2c_offset) { + case 0: i2c_io_val = byte << 8; break; + case 1: i2c_io_val |= byte; break; + case 3: i2c_io_val |= (byte & 15) << 16; mem_write(i2c_io_bank, i2c_io_adr + i2c_wordid, i2c_io_val); break; + } + } + break; + } + } + + i2c_bytecount++; + break; + case CONTROL: + logerror("MAS I2C: Control byte %02x\n", byte); + break; + } +} + +void mas3507d_device::i2c_device_got_stop() +{ + logerror("MAS I2C: got stop\n"); +} + +void mas3507d_device::mem_write(int bank, UINT32 adr, UINT32 val) +{ + switch(adr | (bank ? 0x10000 : 0)) { + case 0x0032f: logerror("MAS3507D: OutputConfig = %05x\n", val); break; + case 0x107f8: logerror("MAS3507D: left->left gain = %05x\n", val); break; + case 0x107f9: logerror("MAS3507D: left->right gain = %05x\n", val); break; + case 0x107fa: logerror("MAS3507D: right->left gain = %05x\n", val); break; + case 0x107fb: logerror("MAS3507D: right->right gain = %05x\n", val); break; + default: logerror("MAS3507D: %d:%04x = %05x\n", bank, adr, val); break; + } +} + +void mas3507d_device::reg_write(UINT32 adr, UINT32 val) +{ + switch(adr) { + case 0x8e: logerror("MAS3507D: DCCF = %05x\n", val); break; + case 0xaa: logerror("MAS3507D: Mute/bypass = %05x\n", val); break; + case 0xe6: logerror("MAS3507D: StartupConfig = %05x\n", val); break; + case 0xe7: logerror("MAS3507D: Kprescale = %05x\n", val); break; + case 0x6b: logerror("MAS3507D: Kbass = %05x\n", val); break; + case 0x6f: logerror("MAS3507D: Ktreble = %05x\n", val); break; + default: logerror("MAS3507D: reg %02x = %05x\n", adr, val); break; + } +} + +void mas3507d_device::run_program(UINT32 adr) +{ + switch(adr) { + case 0xfcb: logerror("MAS3507D: validate OutputConfig\n"); break; + default: logerror("MAS3507D: run %04x\n", adr); break; + } +} + +void mas3507d_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ +} diff --git a/src/devices/sound/mas3507d.h b/src/devices/sound/mas3507d.h new file mode 100644 index 00000000000..0dad34bfe61 --- /dev/null +++ b/src/devices/sound/mas3507d.h @@ -0,0 +1,68 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +#pragma once + +#ifndef __MAS3507D_H__ +#define __MAS3507D_H__ + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_MAS3507D_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, MAS3507D, 0) + +#define MCFG_MAS3507D_REPLACE(_tag) \ + MCFG_DEVICE_REPLACE(_tag, MAS3507D, 0) + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class mas3507d_device : public device_t, public device_sound_interface +{ +public: + // construction/destruction + mas3507d_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + int i2c_scl_r(); + int i2c_sda_r(); + void i2c_scl_w(bool line); + void i2c_sda_w(bool line); + +protected: + virtual void device_start(); + virtual void device_reset(); + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + +private: + enum { IDLE, STARTED, NAK, ACK, ACK2 } i2c_bus_state; + enum { UNKNOWN, VALIDATED, WRONG } i2c_bus_address; + + bool i2c_scli, i2c_sclo, i2c_sdai, i2c_sdao; + int i2c_bus_curbit; + UINT8 i2c_bus_curval; + + void i2c_nak(); + bool i2c_device_got_address(UINT8 address); + void i2c_device_got_byte(UINT8 byte); + void i2c_device_got_stop(); + + + enum { UNDEFINED, CONTROL, DATA, BAD } i2c_subdest; + enum { CMD_BAD, CMD_RUN, CMD_READ_CTRL, CMD_WRITE_REG, CMD_WRITE_MEM, CMD_READ_REG, CMD_READ_MEM } i2c_command; + int i2c_bytecount; + UINT32 i2c_io_bank, i2c_io_adr, i2c_io_count, i2c_io_val; + + + void mem_write(int bank, UINT32 adr, UINT32 val); + void run_program(UINT32 adr); + void reg_write(UINT32 adr, UINT32 val); +}; + + +// device type definition +extern const device_type MAS3507D; + +#endif /* __MAS3507D_H__ */ diff --git a/src/devices/sound/mos6560.c b/src/devices/sound/mos6560.c new file mode 100644 index 00000000000..eb4ee0a5c30 --- /dev/null +++ b/src/devices/sound/mos6560.c @@ -0,0 +1,969 @@ +// license:BSD-3-Clause +// copyright-holders:Peter Trauner +/*************************************************************************** + + MOS 6560 / 6561 Video Interface Chip + + + Original code by PeT (mess@utanet.at), 1999 + + + 2010 FP: converted to a device and merged the video & sound components + + TODO: + - plenty of cleanups! + - investigate attckufo chip features (no invert mode, no multicolor, 16 col chars) + - investigate why some vic20 carts crash emulation + +**************************************************************************** + + Original notes: + + 2 Versions + 6560 NTSC + 6561 PAL + 14 bit addr bus + 12 bit data bus + (16 8 bit registers) + alternates with MOS 6502 on the address bus + fetch 8 bit characternumber and 4 bit color + high bit of 4 bit color value determines: + 0: 2 color mode + 1: 4 color mode + than fetch characterbitmap for characternumber + 2 color mode: + set bit in characterbitmap gives pixel in color of the lower 3 color bits + cleared bit gives pixel in backgroundcolor + 4 color mode: + 2 bits in the characterbitmap are viewed together + 00: backgroundcolor + 11: colorram + 01: helpercolor + 10: framecolor + advance to next character in videorram until line is full + repeat this 8 or 16 lines, before moving to next line in videoram + screen ratio ntsc, pal 4/3 + + pal version: + can contain greater visible areas + expects other sync position (so ntsc modules may be displayed at + the upper left corner of the tv screen) + pixel ratio seems to be different on pal and ntsc + + commodore vic20 notes + 6560 address line 13 is connected inverted to address line 15 of the board + 1 K 4 bit ram at 0x9400 is additional connected as 4 higher bits + of the 6560 (colorram) without decoding the 6560 address line a8..a13 + +*****************************************************************************/ + + +#include "emu.h" +#include "sound/mos6560.h" + + +/***************************************************************************** + PARAMETERS +*****************************************************************************/ + +#define VERBOSE_LEVEL 0 +#define DBG_LOG(N,M,A) \ + do { \ + if(VERBOSE_LEVEL >= N) \ + { \ + if( M ) \ + logerror("%11.6f: %-24s", machine().time().as_double(), (char*) M ); \ + logerror A; \ + } \ + } while (0) + + +/* 2008-05 FP: lightpen code needs to read input port from vc20.c */ + +#define LIGHTPEN_BUTTON ((!m_lightpen_button_cb.isnull()) ? m_lightpen_button_cb(0) : 0) +#define LIGHTPEN_X_VALUE ((!m_lightpen_x_cb.isnull()) ? m_lightpen_x_cb(0) : 0) +#define LIGHTPEN_Y_VALUE ((!m_lightpen_y_cb.isnull()) ? m_lightpen_y_cb(0) : 0) + +/* lightpen delivers values from internal counters + * they do not start with the visual area or frame area */ +#define MOS6560_X_BEGIN 38 +#define MOS6560_Y_BEGIN -6 /* first 6 lines after retrace not for lightpen! */ +#define MOS6561_X_BEGIN 38 +#define MOS6561_Y_BEGIN -6 +#define MOS656X_X_BEGIN ((m_variant == TYPE_6561) ? MOS6561_X_BEGIN : MOS6560_X_BEGIN) +#define MOS656X_Y_BEGIN ((m_variant == TYPE_6561) ? MOS6561_Y_BEGIN : MOS6560_Y_BEGIN) + +#define MOS656X_MAME_XPOS ((m_variant == TYPE_6561) ? MOS6561_MAME_XPOS : MOS6560_MAME_XPOS) +#define MOS656X_MAME_YPOS ((m_variant == TYPE_6561) ? MOS6561_MAME_YPOS : MOS6560_MAME_YPOS) + +/* lightpen behaviour in pal or mono multicolor not tested */ +#define MOS656X_X_VALUE ((LIGHTPEN_X_VALUE + MOS656X_X_BEGIN + MOS656X_MAME_XPOS)/2) +#define MOS656X_Y_VALUE ((LIGHTPEN_Y_VALUE + MOS656X_Y_BEGIN + MOS656X_MAME_YPOS)/2) + +#define MOS656X_VRETRACERATE ((m_variant == TYPE_6561) ? MOS6561_VRETRACERATE : MOS6560_VRETRACERATE) + +/* ntsc 1 - 8 */ +/* pal 5 - 19 */ +#define XPOS (((int)m_reg[0] & 0x7f) * 4) +#define YPOS ((int)m_reg[1] * 2) + +/* ntsc values >= 31 behave like 31 */ +/* pal value >= 32 behave like 32 */ +#define CHARS_X ((int)m_reg[2] & 0x7f) +#define CHARS_Y (((int)m_reg[3] & 0x7e) >> 1) + +/* colorram and backgroundcolor are changed */ +#define INVERTED (!(m_reg[0x0f] & 8)) + +#define CHARGENADDR (((int)m_reg[5] & 0x0f) << 10) +#define VIDEOADDR ((((int)m_reg[5] & 0xf0) << (10 - 4)) | (((int)m_reg[2] & 0x80) << (9-7))) +#define VIDEORAMSIZE (YSIZE * XSIZE) +#define CHARGENSIZE (256 * HEIGHTPIXEL) + +#define HELPERCOLOR (m_reg[0x0e] >> 4) +#define BACKGROUNDCOLOR (m_reg[0x0f] >> 4) +#define FRAMECOLOR (m_reg[0x0f] & 0x07) + + +// VICE palette +static const rgb_t PALETTE_MOS[] = +{ + rgb_t(0x00, 0x00, 0x00), + rgb_t(0xff, 0xff, 0xff), + rgb_t(0xf0, 0x00, 0x00), + rgb_t(0x00, 0xf0, 0xf0), + + rgb_t(0x60, 0x00, 0x60), + rgb_t(0x00, 0xa0, 0x00), + rgb_t(0x00, 0x00, 0xf0), + rgb_t(0xd0, 0xd0, 0x00), + + rgb_t(0xc0, 0xa0, 0x00), + rgb_t(0xff, 0xa0, 0x00), + rgb_t(0xf0, 0x80, 0x80), + rgb_t(0x00, 0xff, 0xff), + + rgb_t(0xff, 0x00, 0xff), + rgb_t(0x00, 0xff, 0x00), + rgb_t(0x00, 0xa0, 0xff), + rgb_t(0xff, 0xff, 0x00) +}; + + + +/***************************************************************************** + IMPLEMENTATION +*****************************************************************************/ + +inline UINT8 mos6560_device::read_videoram(offs_t offset) +{ + m_last_data = space(AS_0).read_byte(offset & 0x3fff); + + return m_last_data; +} + +inline UINT8 mos6560_device::read_colorram(offs_t offset) +{ + return space(AS_1).read_byte(offset & 0x3ff); +} + +/*------------------------------------------------- + draw_character +-------------------------------------------------*/ + +void mos6560_device::draw_character( int ybegin, int yend, int ch, int yoff, int xoff, UINT16 *color ) +{ + int y, code; + + for (y = ybegin; y <= yend; y++) + { + code = read_videoram((m_chargenaddr + ch * m_charheight + y) & 0x3fff); + + m_bitmap.pix32(y + yoff, xoff + 0) = PALETTE_MOS[color[code >> 7]]; + m_bitmap.pix32(y + yoff, xoff + 1) = PALETTE_MOS[color[(code >> 6) & 1]]; + m_bitmap.pix32(y + yoff, xoff + 2) = PALETTE_MOS[color[(code >> 5) & 1]]; + m_bitmap.pix32(y + yoff, xoff + 3) = PALETTE_MOS[color[(code >> 4) & 1]]; + m_bitmap.pix32(y + yoff, xoff + 4) = PALETTE_MOS[color[(code >> 3) & 1]]; + m_bitmap.pix32(y + yoff, xoff + 5) = PALETTE_MOS[color[(code >> 2) & 1]]; + m_bitmap.pix32(y + yoff, xoff + 6) = PALETTE_MOS[color[(code >> 1) & 1]]; + m_bitmap.pix32(y + yoff, xoff + 7) = PALETTE_MOS[color[code & 1]]; + } +} + + +/*------------------------------------------------- + draw_character_multi +-------------------------------------------------*/ + +void mos6560_device::draw_character_multi( int ybegin, int yend, int ch, int yoff, int xoff, UINT16 *color ) +{ + int y, code; + + for (y = ybegin; y <= yend; y++) + { + code = read_videoram((m_chargenaddr + ch * m_charheight + y) & 0x3fff); + + m_bitmap.pix32(y + yoff, xoff + 0) = + m_bitmap.pix32(y + yoff, xoff + 1) = PALETTE_MOS[color[code >> 6]]; + m_bitmap.pix32(y + yoff, xoff + 2) = + m_bitmap.pix32(y + yoff, xoff + 3) = PALETTE_MOS[color[(code >> 4) & 3]]; + m_bitmap.pix32(y + yoff, xoff + 4) = + m_bitmap.pix32(y + yoff, xoff + 5) = PALETTE_MOS[color[(code >> 2) & 3]]; + m_bitmap.pix32(y + yoff, xoff + 6) = + m_bitmap.pix32(y + yoff, xoff + 7) = PALETTE_MOS[color[code & 3]]; + } +} + + +/*------------------------------------------------- + drawlines - draw a certain numer of lines +-------------------------------------------------*/ + +void mos6560_device::drawlines( int first, int last ) +{ + int line, vline; + int offs, yoff, xoff, ybegin, yend, i, j; + int attr, ch; + + m_lastline = last; + if (first >= last) + return; + + for (line = first; (line < m_ypos) && (line < last); line++) + { + for (j = 0; j < m_total_xsize; j++) + m_bitmap.pix32(line, j) = PALETTE_MOS[m_framecolor]; + } + + for (vline = line - m_ypos; (line < last) && (line < m_ypos + m_ysize);) + { + if (m_matrix8x16) + { + offs = (vline >> 4) * m_chars_x; + yoff = (vline & ~0xf) + m_ypos; + ybegin = vline & 0xf; + yend = (vline + 0xf < last - m_ypos) ? 0xf : ((last - line) & 0xf) + ybegin; + } + else + { + offs = (vline >> 3) * m_chars_x; + yoff = (vline & ~7) + m_ypos; + ybegin = vline & 7; + yend = (vline + 7 < last - m_ypos) ? 7 : ((last - line) & 7) + ybegin; + } + + if (m_xpos > 0) + { + for (i = ybegin; i <= yend; i++) + for (j = 0; j < m_xpos; j++) + m_bitmap.pix32(yoff + i, j) = PALETTE_MOS[m_framecolor]; + } + + for (xoff = m_xpos; (xoff < m_xpos + m_xsize) && (xoff < m_total_xsize); xoff += 8, offs++) + { + ch = read_videoram((m_videoaddr + offs) & 0x3fff); + + attr = (read_colorram((m_videoaddr + offs) & 0x3fff)) & 0xf; + + if (m_variant == TYPE_ATTACK_UFO) + { + /* the mos6560 variant used in attckufo only has only one draw mode */ + m_mono[1] = attr; + draw_character(ybegin, yend, ch, yoff, xoff, m_mono); + } + else if (m_inverted) + { + if (attr & 8) + { + m_multiinverted[0] = attr & 7; + draw_character_multi(ybegin, yend, ch, yoff, xoff, m_multiinverted); + } + else + { + m_monoinverted[0] = attr; + draw_character(ybegin, yend, ch, yoff, xoff, m_monoinverted); + } + } + else + { + if (attr & 8) + { + m_multi[2] = attr & 7; + draw_character_multi(ybegin, yend, ch, yoff, xoff, m_multi); + } + else + { + m_mono[1] = attr; + draw_character(ybegin, yend, ch, yoff, xoff, m_mono); + } + } + } + + if (xoff < m_total_xsize) + { + for (i = ybegin; i <= yend; i++) + for (j = xoff; j < m_total_xsize; j++) + m_bitmap.pix32(yoff + i, j) = PALETTE_MOS[m_framecolor]; + } + + if (m_matrix8x16) + { + vline = (vline + 16) & ~0xf; + line = vline + m_ypos; + } + else + { + vline = (vline + 8) & ~7; + line = vline + m_ypos; + } + } + + for (; line < last; line++) + for (j = 0; j < m_total_xsize; j++) + m_bitmap.pix32(line, j) = PALETTE_MOS[m_framecolor]; +} + + +/*------------------------------------------------- + mos6560_port_w - write to regs +-------------------------------------------------*/ + +WRITE8_MEMBER( mos6560_device::write ) +{ + DBG_LOG(1, "mos6560_port_w", ("%.4x:%.2x\n", offset, data)); + + switch (offset) + { + case 0xa: + case 0xb: + case 0xc: + case 0xd: + case 0xe: + soundport_w(offset, data); + break; + } + + if (m_reg[offset] != data) + { + switch (offset) + { + case 0: + case 1: + case 2: + case 3: + case 5: + case 0xe: + case 0xf: + drawlines(m_lastline, m_rasterline); + break; + } + m_reg[offset] = data; + + switch (offset) + { + case 0: + if ((m_variant != TYPE_ATTACK_UFO)) + m_xpos = XPOS; + break; + case 1: + if ((m_variant != TYPE_ATTACK_UFO)) + m_ypos = YPOS; + break; + case 2: + /* ntsc values >= 31 behave like 31 */ + /* pal value >= 32 behave like 32 */ + m_chars_x = CHARS_X; + m_videoaddr = VIDEOADDR; + m_xsize = CHARS_X * 8; + break; + case 3: + if ((m_variant != TYPE_ATTACK_UFO)) + { + m_matrix8x16 = data & 0x01; + m_charheight = m_matrix8x16 ? 16 : 8; + } + m_chars_y = CHARS_Y; + m_ysize = CHARS_Y * m_charheight; + break; + case 5: + m_chargenaddr = CHARGENADDR; + m_videoaddr = VIDEOADDR; + break; + case 0xe: + m_multi[3] = m_multiinverted[3] = m_helpercolor = HELPERCOLOR; + break; + case 0xf: + if ((m_variant != TYPE_ATTACK_UFO)) + m_inverted = INVERTED; + m_multi[1] = m_multiinverted[1] = m_framecolor = FRAMECOLOR; + m_mono[0] = m_monoinverted[1] = m_multi[0] = m_multiinverted[2] = m_backgroundcolor = BACKGROUNDCOLOR; + break; + } + } +} + +/*------------------------------------------------- + mos6560_port_r - read from regs +-------------------------------------------------*/ + +READ8_MEMBER( mos6560_device::read ) +{ + int val; + + switch (offset) + { + case 3: + val = ((m_rasterline & 1) << 7) | (m_reg[offset] & 0x7f); + break; + case 4: /*rasterline */ + drawlines(m_lastline, m_rasterline); + val = (m_rasterline / 2) & 0xff; + break; + case 6: /*lightpen horizontal */ + case 7: /*lightpen vertical */ +#ifdef UNUSED_FUNCTION + if (LIGHTPEN_BUTTON && ((machine().time().as_double() - m_lightpenreadtime) * MOS656X_VRETRACERATE >= 1)) + { + /* only 1 update each frame */ + /* and diode must recognize light */ + if (1) + { + m_reg[6] = MOS656X_X_VALUE; + m_reg[7] = MOS656X_Y_VALUE; + } + m_lightpenreadtime = machine().time().as_double(); + } +#endif + val = m_reg[offset]; + break; + case 8: /* poti 1 */ + val = m_read_potx(0); + break; + case 9: /* poti 2 */ + val = m_read_poty(0); + break; + default: + val = m_reg[offset]; + break; + } + DBG_LOG(3, "mos6560_port_r", ("%.4x:%.2x\n", offset, val)); + return val; +} + +WRITE_LINE_MEMBER( mos6560_device::lp_w ) +{ + // TODO +} + +UINT8 mos6560_device::bus_r() +{ + return m_last_data; +} + +/*------------------------------------------------- + mos6560_raster_interrupt_gen +-------------------------------------------------*/ + +void mos6560_device::raster_interrupt_gen() +{ + m_rasterline++; + if (m_rasterline >= m_total_lines) + { + m_rasterline = 0; + drawlines(m_lastline, m_total_lines); + m_lastline = 0; + } +} + + +/*------------------------------------------------- + mos6560_video_update - copy the VIC bitmap to + main screen bitmap +-------------------------------------------------*/ + +UINT32 mos6560_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + copybitmap(bitmap, m_bitmap, 0, 0, 0, 0, cliprect); + + return 0; +} + +/***************************************************************************** + SOUND IMPLEMENTATION +*****************************************************************************/ + +/* + * assumed model: + * each write to a ton/noise generated starts it new + * each generator behaves like an timer + * when it reaches 0, the next samplevalue is given out + */ + +/* + * noise channel + * based on a document by diku0748@diku.dk (Asger Alstrup Nielsen) + * + * 23 bit shift register + * initial value (0x7ffff8) + * after shift bit 0 is set to bit 22 xor bit 17 + * dac sample bit22 bit20 bit16 bit13 bit11 bit7 bit4 bit2(lsb) + * + * emulation: + * allocate buffer for 5 sec sampledata (fastest played frequency) + * and fill this buffer in init with the required sample + * fast turning off channel, immediate change of frequency + */ + +#define NOISE_BUFFER_SIZE_SEC 5 + +#define TONE1_ON (m_reg[0x0a] & 0x80) +#define TONE2_ON (m_reg[0x0b] & 0x80) +#define TONE3_ON (m_reg[0x0c] & 0x80) +#define NOISE_ON (m_reg[0x0d] & 0x80) +#define VOLUME (m_reg[0x0e] & 0x0f) + +#define TONE_FREQUENCY_MIN (clock()/256/128) + +#define TONE1_VALUE (8 * (128 - ((m_reg[0x0a] + 1) & 0x7f))) +#define TONE1_FREQUENCY (clock()/32/TONE1_VALUE) + +#define TONE2_VALUE (4 * (128 - ((m_reg[0x0b] + 1) & 0x7f))) +#define TONE2_FREQUENCY (clock()/32/TONE2_VALUE) + +#define TONE3_VALUE (2 * (128 - ((m_reg[0x0c] + 1) & 0x7f))) +#define TONE3_FREQUENCY (clock()/32/TONE3_VALUE) + +#define NOISE_VALUE (32 * (128 - ((m_reg[0x0d] + 1) & 0x7f))) +#define NOISE_FREQUENCY (clock()/NOISE_VALUE) + +#define NOISE_FREQUENCY_MAX (clock()/32/1) + + +/*------------------------------------------------- + mos6560_soundport_w - write to regs +-------------------------------------------------*/ + +void mos6560_device::soundport_w( int offset, int data ) +{ + int old = m_reg[offset]; + m_channel->update(); + + switch (offset) + { + case 0x0a: + m_reg[offset] = data; + if (!(old & 0x80) && TONE1_ON) + { + m_tone1pos = 0; + m_tone1samples = machine().sample_rate() / TONE1_FREQUENCY; + if (m_tone1samples == 0) + m_tone1samples = 1; + } + DBG_LOG(1, "mos6560", ("tone1 %.2x %d\n", data, TONE1_FREQUENCY)); + break; + case 0x0b: + m_reg[offset] = data; + if (!(old & 0x80) && TONE2_ON) + { + m_tone2pos = 0; + m_tone2samples = machine().sample_rate() / TONE2_FREQUENCY; + if (m_tone2samples == 0) + m_tone2samples = 1; + } + DBG_LOG(1, "mos6560", ("tone2 %.2x %d\n", data, TONE2_FREQUENCY)); + break; + case 0x0c: + m_reg[offset] = data; + if (!(old & 0x80) && TONE3_ON) + { + m_tone3pos = 0; + m_tone3samples = machine().sample_rate() / TONE3_FREQUENCY; + if (m_tone3samples == 0) + m_tone3samples = 1; + } + DBG_LOG(1, "mos6560", ("tone3 %.2x %d\n", data, TONE3_FREQUENCY)); + break; + case 0x0d: + m_reg[offset] = data; + if (NOISE_ON) + { + m_noisesamples = (int) ((double) NOISE_FREQUENCY_MAX * machine().sample_rate() + * NOISE_BUFFER_SIZE_SEC / NOISE_FREQUENCY); + DBG_LOG (1, "mos6560", ("noise %.2x %d sample:%d\n", + data, NOISE_FREQUENCY, m_noisesamples)); + if ((double) m_noisepos / m_noisesamples >= 1.0) + { + m_noisepos = 0; + } + } + else + { + m_noisepos = 0; + } + break; + case 0x0e: + m_reg[offset] = (old & ~0x0f) | (data & 0x0f); + DBG_LOG (3, "mos6560", ("volume %d\n", data & 0x0f)); + break; + } +} + + +/***************************************************************************** + DEVICE INTERFACE +*****************************************************************************/ + +/*------------------------------------------------- + mos6560_sound_start - start audio emulation + (to be called at device start) +-------------------------------------------------*/ + +void mos6560_device::sound_start() +{ + int i; + + m_channel = machine().sound().stream_alloc(*this, 0, 1, machine().sample_rate()); + + /* buffer for fastest played sample for 5 second so we have enough data for min 5 second */ + m_noisesize = NOISE_FREQUENCY_MAX * NOISE_BUFFER_SIZE_SEC; + m_noise = auto_alloc_array(machine(), INT8, m_noisesize); + { + int noiseshift = 0x7ffff8; + char data; + + for (i = 0; i < m_noisesize; i++) + { + data = 0; + if (noiseshift & 0x400000) + data |= 0x80; + if (noiseshift & 0x100000) + data |= 0x40; + if (noiseshift & 0x010000) + data |= 0x20; + if (noiseshift & 0x002000) + data |= 0x10; + if (noiseshift & 0x000800) + data |= 0x08; + if (noiseshift & 0x000080) + data |= 0x04; + if (noiseshift & 0x000010) + data |= 0x02; + if (noiseshift & 0x000004) + data |= 0x01; + m_noise[i] = data; + if (((noiseshift & 0x400000) == 0) != ((noiseshift & 0x002000) == 0)) + noiseshift = (noiseshift << 1) | 1; + else + noiseshift <<= 1; + } + } + m_tonesize = machine().sample_rate() / TONE_FREQUENCY_MIN; + + if (m_tonesize > 0) + { + m_tone = auto_alloc_array(machine(), INT16, m_tonesize); + + for (i = 0; i < m_tonesize; i++) + { + m_tone[i] = (INT16)(sin (2 * M_PI * i / m_tonesize) * 127 + 0.5); + } + } + else + { + m_tone = NULL; + } +} + + +const device_type MOS6560 = &device_creator; +const device_type MOS6561 = &device_creator; +const device_type MOS656X_ATTACK_UFO = &device_creator; + +// default address maps +static ADDRESS_MAP_START( mos6560_videoram_map, AS_0, 8, mos6560_device ) + AM_RANGE(0x0000, 0x3fff) AM_RAM +ADDRESS_MAP_END + +static ADDRESS_MAP_START( mos6560_colorram_map, AS_1, 8, mos6560_device ) + AM_RANGE(0x000, 0x3ff) AM_RAM +ADDRESS_MAP_END + +mos6560_device::mos6560_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, UINT32 variant, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_memory_interface(mconfig, *this), + device_sound_interface(mconfig, *this), + device_video_interface(mconfig, *this), + m_variant(variant), + m_videoram_space_config("videoram", ENDIANNESS_LITTLE, 8, 14, 0, NULL, *ADDRESS_MAP_NAME(mos6560_videoram_map)), + m_colorram_space_config("colorram", ENDIANNESS_LITTLE, 8, 10, 0, NULL, *ADDRESS_MAP_NAME(mos6560_colorram_map)), + m_read_potx(*this), + m_read_poty(*this) +{ +} + +mos6560_device::mos6560_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, MOS6560, "MOS6560", tag, owner, clock, "mos6560", __FILE__), + device_memory_interface(mconfig, *this), + device_sound_interface(mconfig, *this), + device_video_interface(mconfig, *this), + m_variant(TYPE_6560), + m_videoram_space_config("videoram", ENDIANNESS_LITTLE, 8, 14, 0, NULL, *ADDRESS_MAP_NAME(mos6560_videoram_map)), + m_colorram_space_config("colorram", ENDIANNESS_LITTLE, 8, 10, 0, NULL, *ADDRESS_MAP_NAME(mos6560_colorram_map)), + m_read_potx(*this), + m_read_poty(*this) +{ +} + +mos6561_device::mos6561_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + :mos6560_device(mconfig, MOS6561, "MOS6561", tag, owner, clock, TYPE_6561, "mos6561", __FILE__) { } + +mos656x_attack_ufo_device::mos656x_attack_ufo_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + :mos6560_device(mconfig, MOS656X_ATTACK_UFO, "MOS656X", tag, owner, clock, TYPE_ATTACK_UFO, "mos656x_attack_ufo", __FILE__) { } + + +//------------------------------------------------- +// memory_space_config - return a description of +// any address spaces owned by this device +//------------------------------------------------- + +const address_space_config *mos6560_device::memory_space_config(address_spacenum spacenum) const +{ + switch (spacenum) + { + case AS_0: return &m_videoram_space_config; + case AS_1: return &m_colorram_space_config; + default: return NULL; + } +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void mos6560_device::device_start() +{ + m_screen->register_screen_bitmap(m_bitmap); + + // resolve callbacks + m_read_potx.resolve_safe(0xff); + m_read_poty.resolve_safe(0xff); + + switch (m_variant) + { + case TYPE_6560: + m_total_xsize = MOS6560_XSIZE; + m_total_ysize = MOS6560_YSIZE; + m_total_lines = MOS6560_LINES; + m_total_vretracerate = MOS6560_VRETRACERATE; + break; + + case TYPE_ATTACK_UFO: + m_total_xsize = 23 * 8; + m_total_ysize = 22 * 8; + m_total_lines = MOS6560_LINES; + m_total_vretracerate = MOS6560_VRETRACERATE; + break; + + case TYPE_6561: + m_total_xsize = MOS6561_XSIZE; + m_total_ysize = MOS6561_YSIZE; + m_total_lines = MOS6561_LINES; + m_total_vretracerate = MOS6561_VRETRACERATE; + break; + } + + // allocate timers + m_line_timer = timer_alloc(TIMER_LINE); + m_line_timer->adjust(m_screen->scan_period(), 0, m_screen->scan_period()); + + // initialize sound + sound_start(); + + // state saving + save_item(NAME(m_lightpenreadtime)); + save_item(NAME(m_rasterline)); + save_item(NAME(m_lastline)); + + save_item(NAME(m_charheight)); + save_item(NAME(m_matrix8x16)); + save_item(NAME(m_inverted)); + save_item(NAME(m_chars_x)); + save_item(NAME(m_chars_y)); + save_item(NAME(m_xsize)); + save_item(NAME(m_ysize)); + save_item(NAME(m_xpos)); + save_item(NAME(m_ypos)); + save_item(NAME(m_chargenaddr)); + save_item(NAME(m_videoaddr)); + + save_item(NAME(m_backgroundcolor)); + save_item(NAME(m_framecolor)); + save_item(NAME(m_helpercolor)); + + save_item(NAME(m_reg)); + + save_item(NAME(m_mono)); + save_item(NAME(m_monoinverted)); + save_item(NAME(m_multi)); + save_item(NAME(m_multiinverted)); + + save_item(NAME(m_last_data)); + + save_item(NAME(m_tone1pos)); + save_item(NAME(m_tone2pos)); + save_item(NAME(m_tone3pos)); + save_item(NAME(m_tone1samples)); + save_item(NAME(m_tone2samples)); + save_item(NAME(m_tone3samples)); + save_item(NAME(m_noisepos)); + save_item(NAME(m_noisesamples)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void mos6560_device::device_reset() +{ + m_lightpenreadtime = 0.0; + m_rasterline = 0; + m_lastline = 0; + + memset(m_reg, 0, 16); + + m_charheight = 8; + m_matrix8x16 = 0; + m_inverted = 0; + m_chars_x = 0; + m_chars_y = 0; + m_xsize = 0; + m_ysize = 0; + m_xpos = 0; + m_ypos = 0; + m_chargenaddr = 0; + m_videoaddr = 0; + + m_backgroundcolor = 0; + m_framecolor = 0; + m_helpercolor = 0; + + m_mono[0] = 0; + m_mono[1] = 0; + m_monoinverted[0] = 0; + m_monoinverted[1] = 0; + m_multi[0] = 0; + m_multi[1] = 0; + m_multi[2] = 0; + m_multi[3] = 0; + m_multiinverted[0] = 0; + m_multiinverted[1] = 0; + m_multiinverted[2] = 0; + m_multiinverted[3] = 0; + + m_last_data = 0; + + m_tone1pos = 0; + m_tone2pos = 0; + m_tone3pos = 0; + m_tone1samples = 1; + m_tone2samples = 1; + m_tone3samples = 1; + m_noisepos = 0; + m_noisesamples = 1; +} + + +//------------------------------------------------- +// device_timer - handler timer events +//------------------------------------------------- + +void mos6560_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch (id) + { + case TIMER_LINE: + raster_interrupt_gen(); + break; + } +} + +//------------------------------------------------- +// sound_stream_update - handle a stream update +//------------------------------------------------- + +void mos6560_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + int i, v; + stream_sample_t *buffer = outputs[0]; + + for (i = 0; i < samples; i++) + { + v = 0; + if (TONE1_ON /*||(m_tone1pos != 0) */ ) + { + v += m_tone[m_tone1pos * m_tonesize / m_tone1samples]; + m_tone1pos++; +#if 0 + m_tone1pos %= m_tone1samples; +#else + if (m_tone1pos >= m_tone1samples) + { + m_tone1pos = 0; + m_tone1samples = machine().sample_rate() / TONE1_FREQUENCY; + if (m_tone1samples == 0) + m_tone1samples = 1; + } +#endif + } + if (TONE2_ON /*||(m_tone2pos != 0) */ ) + { + v += m_tone[m_tone2pos * m_tonesize / m_tone2samples]; + m_tone2pos++; +#if 0 + m_tone2pos %= m_tone2samples; +#else + if (m_tone2pos >= m_tone2samples) + { + m_tone2pos = 0; + m_tone2samples = machine().sample_rate() / TONE2_FREQUENCY; + if (m_tone2samples == 0) + m_tone2samples = 1; + } +#endif + } + if (TONE3_ON /*||(m_tone3pos != 0) */ ) + { + v += m_tone[m_tone3pos * m_tonesize / m_tone3samples]; + m_tone3pos++; +#if 0 + m_tone3pos %= m_tone3samples; +#else + if (m_tone3pos >= m_tone3samples) + { + m_tone3pos = 0; + m_tone3samples = machine().sample_rate() / TONE3_FREQUENCY; + if (m_tone3samples == 0) + m_tone3samples = 1; + } +#endif + } + if (NOISE_ON) + { + v += m_noise[(int) ((double) m_noisepos * m_noisesize / m_noisesamples)]; + m_noisepos++; + if ((double) m_noisepos / m_noisesamples >= 1.0) + { + m_noisepos = 0; + } + } + v = (v * VOLUME) << 2; + if (v > 32767) + buffer[i] = 32767; + else if (v < -32767) + buffer[i] = -32767; + else + buffer[i] = v; + } +} diff --git a/src/devices/sound/mos6560.h b/src/devices/sound/mos6560.h new file mode 100644 index 00000000000..05768815bf0 --- /dev/null +++ b/src/devices/sound/mos6560.h @@ -0,0 +1,260 @@ +// license:BSD-3-Clause +// copyright-holders:Peter Trauner +/*************************************************************************** + + MOS 6560/6561 Video Interface Chip (VIC) emulation + +**************************************************************************** + _____ _____ + N/C 1 |* \_/ | 40 Vdd + CHROMA 2 | | 39 phi1 + LUMA/SYNC 3 | | 38 phi2 + R/W 4 | | 37 OPTION + D11 5 | | 36 Pphi2 + D10 6 | | 35 Pphi1 + D9 7 | | 34 A13 + D8 8 | | 33 A12 + D7 9 | | 32 A11 + D6 10 | MOS6560 | 31 A10 + D5 11 | MOS6561 | 30 A9 + D4 12 | | 29 A8 + D3 13 | | 28 A7 + D2 14 | | 27 A6 + D1 15 | | 26 A5 + D0 16 | | 25 A4 + POT X 17 | | 24 A3 + POT Y 18 | | 23 A2 + AUDIO 19 | | 22 A1 + Vss 20 |_____________| 21 A0 + +***************************************************************************/ + +#pragma once + +#ifndef __MOS6560__ +#define __MOS6560__ + +#include "emu.h" + + + +//*************************************************************************** +// DEVICE CONFIGURATION MACROS +//*************************************************************************** + +#define MCFG_MOS6560_ADD(_tag, _screen_tag, _clock, _videoram_map, _colorram_map) \ + MCFG_SCREEN_ADD(_screen_tag, RASTER) \ + MCFG_SCREEN_REFRESH_RATE(MOS6560_VRETRACERATE) \ + MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(2500)) \ + MCFG_SCREEN_SIZE((MOS6560_XSIZE + 7) & ~7, MOS6560_YSIZE) \ + MCFG_SCREEN_VISIBLE_AREA(MOS6560_MAME_XPOS, MOS6560_MAME_XPOS + MOS6560_MAME_XSIZE - 1, MOS6560_MAME_YPOS, MOS6560_MAME_YPOS + MOS6560_MAME_YSIZE - 1) \ + MCFG_SCREEN_UPDATE_DEVICE(_tag, mos6560_device, screen_update) \ + MCFG_SOUND_ADD(_tag, MOS6560, _clock) \ + MCFG_VIDEO_SET_SCREEN(_screen_tag) \ + MCFG_DEVICE_ADDRESS_MAP(AS_0, _videoram_map) \ + MCFG_DEVICE_ADDRESS_MAP(AS_1, _colorram_map) + +#define MCFG_MOS6561_ADD(_tag, _screen_tag, _clock, _videoram_map, _colorram_map) \ + MCFG_SCREEN_ADD(_screen_tag, RASTER) \ + MCFG_SCREEN_REFRESH_RATE(MOS6561_VRETRACERATE) \ + MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(2500)) \ + MCFG_SCREEN_SIZE((MOS6561_XSIZE + 7) & ~7, MOS6561_YSIZE) \ + MCFG_SCREEN_VISIBLE_AREA(MOS6561_MAME_XPOS, MOS6561_MAME_XPOS + MOS6561_MAME_XSIZE - 1, MOS6561_MAME_YPOS, MOS6561_MAME_YPOS + MOS6561_MAME_YSIZE - 1) \ + MCFG_SCREEN_UPDATE_DEVICE(_tag, mos6560_device, screen_update) \ + MCFG_SOUND_ADD(_tag, MOS6561, _clock) \ + MCFG_VIDEO_SET_SCREEN(_screen_tag) \ + MCFG_DEVICE_ADDRESS_MAP(AS_0, _videoram_map) \ + MCFG_DEVICE_ADDRESS_MAP(AS_1, _colorram_map) + +#define MCFG_MOS656X_ATTACK_UFO_ADD(_tag, _screen_tag, _clock, _videoram_map, _colorram_map) \ + MCFG_SCREEN_ADD(_screen_tag, RASTER) \ + MCFG_SCREEN_REFRESH_RATE(MOS6560_VRETRACERATE) \ + MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(2500)) \ + MCFG_SCREEN_SIZE((MOS6560_XSIZE + 7) & ~7, MOS6560_YSIZE) \ + MCFG_SCREEN_VISIBLE_AREA(0, 23*8 - 1, 0, 22*8 - 1) \ + MCFG_SCREEN_UPDATE_DEVICE(_tag, mos6560_device, screen_update) \ + MCFG_SOUND_ADD(_tag, MOS656X_ATTACK_UFO, _clock) \ + MCFG_VIDEO_SET_SCREEN(_screen_tag) \ + MCFG_DEVICE_ADDRESS_MAP(AS_0, _videoram_map) \ + MCFG_DEVICE_ADDRESS_MAP(AS_1, _colorram_map) + + +#define MCFG_MOS6560_POTX_CALLBACK(_read) \ + devcb = &mos6560_device::set_potx_rd_callback(*device, DEVCB_##_read); + +#define MCFG_MOS6560_POTY_CALLBACK(_read) \ + devcb = &mos6560_device::set_poty_rd_callback(*device, DEVCB_##_read); + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define MOS6560_VRETRACERATE 60 +#define MOS6561_VRETRACERATE 50 + +#define MOS6560_MAME_XPOS 4 /* xleft not displayed */ +#define MOS6560_MAME_YPOS 10 /* y up not displayed */ +#define MOS6561_MAME_XPOS 20 +#define MOS6561_MAME_YPOS 10 +#define MOS6560_MAME_XSIZE 200 +#define MOS6560_MAME_YSIZE 248 +#define MOS6561_MAME_XSIZE 224 +#define MOS6561_MAME_YSIZE 296 +/* real values */ + +#define MOS6560_LINES 261 +#define MOS6561_LINES 312 + +#define MOS6560_XSIZE (4+201) /* 4 left not visible */ +#define MOS6560_YSIZE (10+251) /* 10 not visible */ +/* cycles 65 */ + +#define MOS6561_XSIZE (20+229) /* 20 left not visible */ +#define MOS6561_YSIZE (10+302) /* 10 not visible */ +/* cycles 71 */ + + +/* the following values depend on the VIC clock, + * but to achieve TV-frequency the clock must have a fix frequency */ +#define MOS6560_CLOCK (14318181/14) +#define MOS6561_CLOCK (4433618/4) + + + +//*************************************************************************** +// TYPE DEFINITIONS +//*************************************************************************** + +// ======================> mos6560_device + +class mos6560_device : public device_t, + public device_memory_interface, + public device_sound_interface, + public device_video_interface +{ +public: + mos6560_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, UINT32 variant, const char *shortname, const char *source); + mos6560_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + template static devcb_base &set_potx_rd_callback(device_t &device, _Object object) { return downcast(device).m_read_potx.set_callback(object); } + template static devcb_base &set_poty_rd_callback(device_t &device, _Object object) { return downcast(device).m_read_poty.set_callback(object); } + + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const; + + DECLARE_READ8_MEMBER( read ); + DECLARE_WRITE8_MEMBER( write ); + + UINT8 bus_r(); + + DECLARE_WRITE_LINE_MEMBER( lp_w ); + + UINT32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); + +protected: + enum + { + TYPE_6560, // NTSC-M + TYPE_6561, // PAL-B + TYPE_ATTACK_UFO // NTSC-M, less features + }; + + enum + { + TIMER_LINE + }; + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + // sound stream update overrides + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + + inline UINT8 read_videoram(offs_t offset); + inline UINT8 read_colorram(offs_t offset); + + void draw_character( int ybegin, int yend, int ch, int yoff, int xoff, UINT16 *color ); + void draw_character_multi( int ybegin, int yend, int ch, int yoff, int xoff, UINT16 *color ); + void drawlines( int first, int last ); + void soundport_w( int offset, int data ); + void sound_start(); + void raster_interrupt_gen(); + + int m_variant; + + const address_space_config m_videoram_space_config; + const address_space_config m_colorram_space_config; + + devcb_read8 m_read_potx; + devcb_read8 m_read_poty; + + UINT8 m_reg[16]; + + bitmap_rgb32 m_bitmap; + + int m_rasterline, m_lastline; + double m_lightpenreadtime; + + int m_charheight, m_matrix8x16, m_inverted; + int m_chars_x, m_chars_y; + int m_xsize, m_ysize, m_xpos, m_ypos; + int m_chargenaddr, m_videoaddr; + + /* values in videoformat */ + UINT16 m_backgroundcolor, m_framecolor, m_helpercolor; + + /* arrays for bit to color conversion without condition checking */ + UINT16 m_mono[2], m_monoinverted[2], m_multi[4], m_multiinverted[4]; + + /* video chip settings */ + int m_total_xsize, m_total_ysize, m_total_lines, m_total_vretracerate; + + /* DMA */ + UINT8 m_last_data; + + /* sound part */ + int m_tone1pos, m_tone2pos, m_tone3pos, + m_tonesize, m_tone1samples, m_tone2samples, m_tone3samples, + m_noisesize, /* number of samples */ + m_noisepos, /* pos of tone */ + m_noisesamples; /* count of samples to give out per tone */ + + sound_stream *m_channel; + INT16 *m_tone; + INT8 *m_noise; + + emu_timer *m_line_timer; +}; + + +// ======================> mos6561_device + +class mos6561_device : public mos6560_device +{ +public: + // construction/destruction + mos6561_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +// ======================> mos656x_attack_ufo_device + +class mos656x_attack_ufo_device : public mos6560_device +{ +public: + // construction/destruction + mos656x_attack_ufo_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +// device type definitions +extern const device_type MOS6560; +extern const device_type MOS6561; +extern const device_type MOS656X_ATTACK_UFO; + + + +#endif diff --git a/src/devices/sound/mos6581.c b/src/devices/sound/mos6581.c new file mode 100644 index 00000000000..73115c79f83 --- /dev/null +++ b/src/devices/sound/mos6581.c @@ -0,0 +1,157 @@ +// license:BSD-3-Clause +// copyright-holders:Nathan Woods, Curt Coder +/********************************************************************** + + MOS 6581/8580 Sound Interface Device emulation + +**********************************************************************/ + +#include "mos6581.h" +#include "sid.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define LOG 0 + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +// device type definition +const device_type MOS6581 = &device_creator; +const device_type MOS8580 = &device_creator; + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// mos6581_device - constructor +//------------------------------------------------- + +mos6581_device::mos6581_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, UINT32 variant, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_sound_interface(mconfig, *this), + m_read_potx(*this), + m_read_poty(*this), + m_stream(NULL), + m_variant(variant) +{ + m_token = global_alloc_clear(SID6581_t); +} + +mos6581_device::mos6581_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, MOS6581, "MOS6581", tag, owner, clock, "mos6581", __FILE__), + device_sound_interface(mconfig, *this), + m_read_potx(*this), + m_read_poty(*this), + m_stream(NULL), + m_variant(TYPE_6581) +{ + m_token = global_alloc_clear(SID6581_t); +} + +mos6581_device::~mos6581_device() +{ + global_free(m_token); +} + +//------------------------------------------------- +// mos8580_device - constructor +//------------------------------------------------- + +mos8580_device::mos8580_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : mos6581_device(mconfig, MOS8580, "MOS8580", tag, owner, clock, TYPE_8580, "mos8580", __FILE__) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void mos6581_device::device_start() +{ + // resolve callbacks + m_read_potx.resolve_safe(0xff); + m_read_poty.resolve_safe(0xff); + + // create sound stream + m_stream = machine().sound().stream_alloc(*this, 0, 1, machine().sample_rate()); + + // initialize SID engine + m_token->device = this; + m_token->mixer_channel = m_stream; + m_token->PCMfreq = machine().sample_rate(); + m_token->clock = clock(); + m_token->type = m_variant; + + sid6581_init(m_token); + sidInitWaveformTables(m_variant); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void mos6581_device::device_reset() +{ + sidEmuReset(m_token); +} + + +//------------------------------------------------- +// sound_stream_update - handle update requests for +// our sound stream +//------------------------------------------------- + +void mos6581_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + sidEmuFillBuffer(m_token, outputs[0], samples); +} + + +//------------------------------------------------- +// read - +//------------------------------------------------- + +READ8_MEMBER( mos6581_device::read ) +{ + UINT8 data = 0; + + switch (offset & 0x1f) + { + case 0x19: + data = m_read_potx(0); + break; + + case 0x1a: + data = m_read_poty(0); + break; + + default: + data = sid6581_port_r(machine(), m_token, offset); + break; + } + + return data; +} + + +//------------------------------------------------- +// write - +//------------------------------------------------- + +WRITE8_MEMBER( mos6581_device::write ) +{ + sid6581_port_w(m_token, offset, data); +} diff --git a/src/devices/sound/mos6581.h b/src/devices/sound/mos6581.h new file mode 100644 index 00000000000..4699bdc51d7 --- /dev/null +++ b/src/devices/sound/mos6581.h @@ -0,0 +1,109 @@ +// license:BSD-3-Clause +// copyright-holders:Nathan Woods, Curt Coder +/********************************************************************** + + MOS 6581/8580 Sound Interface Device emulation + +********************************************************************** + _____ _____ + CAP1A 1 |* \_/ | 28 Vdd + CAP1B 2 | | 27 AUDIO OUT + CAP2A 3 | | 26 EXT IN + CAP2B 4 | | 25 Vcc + _RES 5 | | 24 POTX + phi2 6 | | 23 POTY + R/_W 7 | MOS6581 | 22 D7 + _CS 8 | MOS8580 | 21 D6 + A0 9 | | 20 D5 + A1 10 | | 19 D4 + A2 11 | | 18 D3 + A3 12 | | 17 D2 + A4 13 | | 16 D1 + GND 14 |_____________| 15 D0 + +**********************************************************************/ + +#pragma once + +#ifndef __MOS6581__ +#define __MOS6581__ + +#include "emu.h" + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_MOS6581_POTX_CALLBACK(_read) \ + devcb = &mos6581_device::set_potx_rd_callback(*device, DEVCB_##_read); + +#define MCFG_MOS6581_POTY_CALLBACK(_read) \ + devcb = &mos6581_device::set_poty_rd_callback(*device, DEVCB_##_read); + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> mos6581_device + +struct SID6581_t; + +class mos6581_device : public device_t, + public device_sound_interface +{ +public: + mos6581_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, UINT32 variant, const char *shortname, const char *source); + mos6581_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + ~mos6581_device(); + + template static devcb_base &set_potx_rd_callback(device_t &device, _Object object) { return downcast(device).m_read_potx.set_callback(object); } + template static devcb_base &set_poty_rd_callback(device_t &device, _Object object) { return downcast(device).m_read_poty.set_callback(object); } + + DECLARE_READ8_MEMBER( read ); + DECLARE_WRITE8_MEMBER( write ); + + enum + { + TYPE_6581, + TYPE_8580 + }; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_sound_interface overrides + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + +private: + devcb_read8 m_read_potx; + devcb_read8 m_read_poty; + + sound_stream *m_stream; + + int m_variant; + + SID6581_t *m_token; +}; + + +// ======================> mos8580_device + +class mos8580_device : public mos6581_device +{ +public: + mos8580_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +// device type definition +extern const device_type MOS6581; +extern const device_type MOS8580; + + +#endif diff --git a/src/devices/sound/mos7360.c b/src/devices/sound/mos7360.c new file mode 100644 index 00000000000..fe8631cfee2 --- /dev/null +++ b/src/devices/sound/mos7360.c @@ -0,0 +1,1206 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + MOS 7360/8360 Text Edit Device (TED) emulation + +**********************************************************************/ + +#include "emu.h" +#include "mos7360.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define LOG 0 + + +#define VERBOSE_LEVEL 0 +#define DBG_LOG(N,M,A) \ + do { \ + if(VERBOSE_LEVEL >= N) \ + { \ + if( M ) \ + logerror("%11.6f: %-24s", machine().time().as_double(), (char*) M ); \ + logerror A; \ + } \ + } while(0) + + +#define VREFRESHINLINES 28 + +#define TIMER1HELPER (m_reg[0] | (m_reg[1] << 8)) +#define TIMER2HELPER (m_reg[2] | (m_reg[3] << 8)) +#define TIMER3HELPER (m_reg[4] | (m_reg[5] << 8)) +#define TIMER1 (TIMER1HELPER ? TIMER1HELPER : 0x10000) +#define TIMER2 (TIMER2HELPER ? TIMER2HELPER : 0x10000) +#define TIMER3 (TIMER3HELPER ? TIMER3HELPER : 0x10000) + +#define TED7360_YPOS 40 +#define RASTERLINE_2_C16(a) ((a + m_lines - TED7360_YPOS - 5) % m_lines) +#define C16_2_RASTERLINE(a) ((a + TED7360_YPOS + 5) % m_lines) +#define XPOS 8 +#define YPOS 8 + +#define SCREENON (m_reg[6] & 0x10) +#define TEST (m_reg[6] & 0x80) +#define VERTICALPOS (m_reg[6] & 0x07) +#define HORICONTALPOS (m_reg[7] & 0x07) +#define ECMON (m_reg[6] & 0x40) +#define HIRESON (m_reg[6] & 0x20) +#define MULTICOLORON (m_reg[7] & 0x10) +#define REVERSEON (!(m_reg[7] & 0x80)) + +/* hardware inverts character when bit 7 set (character taken &0x7f) */ +/* instead of fetching character with higher number! */ +#define LINES25 (m_reg[6] & 0x08) /* else 24 Lines */ +#define LINES (LINES25 ? 25 : 24) +#define YSIZE (LINES * 8) +#define COLUMNS40 (m_reg[7] & 0x08) /* else 38 Columns */ +#define COLUMNS (COLUMNS40 ? 40 : 38) +#define XSIZE (COLUMNS * 8) + +#define INROM (m_reg[0x12] & 0x04) +#define CHARGENADDR (REVERSEON && !HIRESON && !MULTICOLORON ? ((m_reg[0x13] & 0xfc) << 8) : ((m_reg[0x13] & 0xf8) << 8)) +#define BITMAPADDR ((m_reg[0x12] & 0x38) << 10) +#define VIDEOADDR ((m_reg[0x14] & 0xf8) << 8) + +#define RASTERLINE (((m_reg[0xa] & 0x01) << 8) | m_reg[0xb]) +#define CURSOR1POS (m_reg[0xd] | ((m_reg[0xc] & 0x03) << 8)) +#define CURSOR2POS (m_reg[0x1b] | ((m_reg[0x1a] & 0x03) << 8)) +#define CURSORRATE ((m_reg[0x1f] & 0x7c) >> 2) + +#define BACKGROUNDCOLOR (m_reg[0x15] & 0x7f) +#define FOREGROUNDCOLOR (m_reg[0x16] & 0x7f) +#define MULTICOLOR1 (m_reg[0x17] & 0x7f) +#define MULTICOLOR2 (m_reg[0x18] & 0x7f) +#define FRAMECOLOR (m_reg[0x19] & 0x7f) + +#define TED7360_CLOCK (m_clock / 4) +#define TED7360_VRETRACERATE ((m_clock == TED7360PAL_CLOCK) ? TED7360PAL_VRETRACERATE : TED7360NTSC_VRETRACERATE) +#define TED7360_LINES ((m_clock == TED7360PAL_CLOCK) ? TED7360PAL_LINES : TED7360NTSC_LINES) + +static const rgb_t PALETTE_MOS[] = +{ +/* black, white, red, cyan */ +/* purple, green, blue, yellow */ +/* orange, light orange, pink, light cyan, */ +/* light violett, light green, light blue, light yellow */ +/* these 16 colors are 8 times here in different luminance (dark..light) */ +/* taken from digitized tv screenshot */ + rgb_t(0x06, 0x01, 0x03), rgb_t(0x2b, 0x2b, 0x2b), rgb_t(0x67, 0x0e, 0x0f), rgb_t(0x00, 0x3f, 0x42), + rgb_t(0x57, 0x00, 0x6d), rgb_t(0x00, 0x4e, 0x00), rgb_t(0x19, 0x1c, 0x94), rgb_t(0x38, 0x38, 0x00), + rgb_t(0x56, 0x20, 0x00), rgb_t(0x4b, 0x28, 0x00), rgb_t(0x16, 0x48, 0x00), rgb_t(0x69, 0x07, 0x2f), + rgb_t(0x00, 0x46, 0x26), rgb_t(0x06, 0x2a, 0x80), rgb_t(0x2a, 0x14, 0x9b), rgb_t(0x0b, 0x49, 0x00), + + rgb_t(0x00, 0x03, 0x02), rgb_t(0x3d, 0x3d, 0x3d), rgb_t(0x75, 0x1e, 0x20), rgb_t(0x00, 0x50, 0x4f), + rgb_t(0x6a, 0x10, 0x78), rgb_t(0x04, 0x5c, 0x00), rgb_t(0x2a, 0x2a, 0xa3), rgb_t(0x4c, 0x47, 0x00), + rgb_t(0x69, 0x2f, 0x00), rgb_t(0x59, 0x38, 0x00), rgb_t(0x26, 0x56, 0x00), rgb_t(0x75, 0x15, 0x41), + rgb_t(0x00, 0x58, 0x3d), rgb_t(0x15, 0x3d, 0x8f), rgb_t(0x39, 0x22, 0xae), rgb_t(0x19, 0x59, 0x00), + + rgb_t(0x00, 0x03, 0x04), rgb_t(0x42, 0x42, 0x42), rgb_t(0x7b, 0x28, 0x20), rgb_t(0x02, 0x56, 0x59), + rgb_t(0x6f, 0x1a, 0x82), rgb_t(0x0a, 0x65, 0x09), rgb_t(0x30, 0x34, 0xa7), rgb_t(0x50, 0x51, 0x00), + rgb_t(0x6e, 0x36, 0x00), rgb_t(0x65, 0x40, 0x00), rgb_t(0x2c, 0x5c, 0x00), rgb_t(0x7d, 0x1e, 0x45), + rgb_t(0x01, 0x61, 0x45), rgb_t(0x1c, 0x45, 0x99), rgb_t(0x42, 0x2d, 0xad), rgb_t(0x1d, 0x62, 0x00), + + rgb_t(0x05, 0x00, 0x02), rgb_t(0x56, 0x55, 0x5a), rgb_t(0x90, 0x3c, 0x3b), rgb_t(0x17, 0x6d, 0x72), + rgb_t(0x87, 0x2d, 0x99), rgb_t(0x1f, 0x7b, 0x15), rgb_t(0x46, 0x49, 0xc1), rgb_t(0x66, 0x63, 0x00), + rgb_t(0x84, 0x4c, 0x0d), rgb_t(0x73, 0x55, 0x00), rgb_t(0x40, 0x72, 0x00), rgb_t(0x91, 0x33, 0x5e), + rgb_t(0x19, 0x74, 0x5c), rgb_t(0x32, 0x59, 0xae), rgb_t(0x59, 0x3f, 0xc3), rgb_t(0x32, 0x76, 0x00), + + rgb_t(0x02, 0x01, 0x06), rgb_t(0x84, 0x7e, 0x85), rgb_t(0xbb, 0x67, 0x68), rgb_t(0x45, 0x96, 0x96), + rgb_t(0xaf, 0x58, 0xc3), rgb_t(0x4a, 0xa7, 0x3e), rgb_t(0x73, 0x73, 0xec), rgb_t(0x92, 0x8d, 0x11), + rgb_t(0xaf, 0x78, 0x32), rgb_t(0xa1, 0x80, 0x20), rgb_t(0x6c, 0x9e, 0x12), rgb_t(0xba, 0x5f, 0x89), + rgb_t(0x46, 0x9f, 0x83), rgb_t(0x61, 0x85, 0xdd), rgb_t(0x84, 0x6c, 0xef), rgb_t(0x5d, 0xa3, 0x29), + + rgb_t(0x02, 0x00, 0x0a), rgb_t(0xb2, 0xac, 0xb3), rgb_t(0xe9, 0x92, 0x92), rgb_t(0x6c, 0xc3, 0xc1), + rgb_t(0xd9, 0x86, 0xf0), rgb_t(0x79, 0xd1, 0x76), rgb_t(0x9d, 0xa1, 0xff), rgb_t(0xbd, 0xbe, 0x40), + rgb_t(0xdc, 0xa2, 0x61), rgb_t(0xd1, 0xa9, 0x4c), rgb_t(0x93, 0xc8, 0x3d), rgb_t(0xe9, 0x8a, 0xb1), + rgb_t(0x6f, 0xcd, 0xab), rgb_t(0x8a, 0xb4, 0xff), rgb_t(0xb2, 0x9a, 0xff), rgb_t(0x88, 0xcb, 0x59), + + rgb_t(0x02, 0x00, 0x0a), rgb_t(0xc7, 0xca, 0xc9), rgb_t(0xff, 0xac, 0xac), rgb_t(0x85, 0xd8, 0xe0), + rgb_t(0xf3, 0x9c, 0xff), rgb_t(0x92, 0xea, 0x8a), rgb_t(0xb7, 0xba, 0xff), rgb_t(0xd6, 0xd3, 0x5b), + rgb_t(0xf3, 0xbe, 0x79), rgb_t(0xe6, 0xc5, 0x65), rgb_t(0xb0, 0xe0, 0x57), rgb_t(0xff, 0xa4, 0xcf), + rgb_t(0x89, 0xe5, 0xc8), rgb_t(0xa4, 0xca, 0xff), rgb_t(0xca, 0xb3, 0xff), rgb_t(0xa2, 0xe5, 0x7a), + + rgb_t(0x01, 0x01, 0x01), rgb_t(0xff, 0xff, 0xff), rgb_t(0xff, 0xf6, 0xf2), rgb_t(0xd1, 0xff, 0xff), + rgb_t(0xff, 0xe9, 0xff), rgb_t(0xdb, 0xff, 0xd3), rgb_t(0xfd, 0xff, 0xff), rgb_t(0xff, 0xff, 0xa3), + rgb_t(0xff, 0xff, 0xc1), rgb_t(0xff, 0xff, 0xb2), rgb_t(0xfc, 0xff, 0xa2), rgb_t(0xff, 0xee, 0xff), + rgb_t(0xd1, 0xff, 0xff), rgb_t(0xeb, 0xff, 0xff), rgb_t(0xff, 0xf8, 0xff), rgb_t(0xed, 0xff, 0xbc) +}; + + +#define NOISE_BUFFER_SIZE_SEC 5 + +#define TONE_ON (!(m_reg[0x11] & 0x80)) /* or tone update!? */ +#define TONE1_ON ((m_reg[0x11] & 0x10)) +#define TONE1_VALUE (m_reg[0x0e] | ((m_reg[0x12] & 3) << 8)) +#define TONE2_ON ((m_reg[0x11] & 0x20)) +#define TONE2_VALUE (m_reg[0x0f] | ((m_reg[0x10] & 3) << 8)) +#define VOLUME (m_reg[0x11] & 0x0f) +#define NOISE_ON (m_reg[0x11] & 0x40) + +/* + * pal 111860.781 + * ntsc 111840.45 + */ +#define TONE_FREQUENCY(reg) ((TED7360_CLOCK >> 3) / (1024 - reg)) +#define TONE_FREQUENCY_MIN (TONE_FREQUENCY(0)) +#define NOISE_FREQUENCY (TED7360_CLOCK / 8 / (1024 - TONE2_VALUE)) +#define NOISE_FREQUENCY_MAX (TED7360_CLOCK / 8) + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +// device type definition +const device_type MOS7360 = &device_creator; + + +// default address maps +static ADDRESS_MAP_START( mos7360_videoram_map, AS_0, 8, mos7360_device ) + AM_RANGE(0x0000, 0xffff) AM_RAM +ADDRESS_MAP_END + + +//------------------------------------------------- +// memory_space_config - return a description of +// any address spaces owned by this device +//------------------------------------------------- + +const address_space_config *mos7360_device::memory_space_config(address_spacenum spacenum) const +{ + switch (spacenum) + { + case AS_0: return &m_videoram_space_config; + default: return NULL; + } +} + + + +//************************************************************************** +// INLINE HELPERS +//************************************************************************** + +inline void mos7360_device::set_interrupt(int mask) +{ + /* kernel itself polls for timer 2 shot (interrupt disabled!) when cassette loading */ + m_reg[9] |= mask; + if ((m_reg[0xa] & m_reg[9] & 0x5e)) + { + if (!(m_reg[9] & 0x80)) + { + //DBG_LOG(1, "ted7360", ("irq start %.2x\n", mask)); + m_reg[9] |= 0x80; + m_write_irq(ASSERT_LINE); + } + } + m_reg[9] |= mask; +} + +inline void mos7360_device::clear_interrupt(int mask) +{ + m_reg[9] &= ~mask; + if ((m_reg[9] & 0x80) && !(m_reg[9] & m_reg[0xa] & 0x5e)) + { + DBG_LOG(1, "ted7360", ("irq end %.2x\n", mask)); + m_reg[9] &= ~0x80; + m_write_irq(CLEAR_LINE); + } +} + +inline int mos7360_device::rastercolumn() +{ + return (int) ((machine().time().as_double() - m_rastertime) * TED7360_VRETRACERATE * m_lines * 57 * 8 + 0.5); +} + +inline UINT8 mos7360_device::read_ram(offs_t offset) +{ + int rom = m_rom; + m_rom = 0; + + m_last_data = space(AS_0).read_byte(offset); + + m_rom = rom; + + return m_last_data; +} + +inline UINT8 mos7360_device::read_rom(offs_t offset) +{ + int rom = m_rom; + m_rom = 1; + + m_last_data = space(AS_0).read_byte(offset); + + m_rom = rom; + + return m_last_data; +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// mos7360_device - constructor +//------------------------------------------------- + +mos7360_device::mos7360_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, MOS7360, "MOS7360", tag, owner, clock, "mos7360", __FILE__), + device_memory_interface(mconfig, *this), + device_sound_interface(mconfig, *this), + device_video_interface(mconfig, *this), + m_videoram_space_config("videoram", ENDIANNESS_LITTLE, 8, 16, 0, NULL, *ADDRESS_MAP_NAME(mos7360_videoram_map)), + m_write_irq(*this), + m_read_k(*this), + m_stream(NULL) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void mos7360_device::device_start() +{ + // get the CPU device + m_cpu = machine().device(m_cpu_tag); + assert(m_cpu != NULL); + + // resolve callbacks + m_write_irq.resolve_safe(); + m_read_k.resolve_safe(0xff); + + // allocate timers + m_timer1 = timer_alloc(TIMER_ID_1); + m_timer2 = timer_alloc(TIMER_ID_2); + m_timer3 = timer_alloc(TIMER_ID_3); + m_line_timer = timer_alloc(TIMER_LINE); + m_line_timer->adjust(m_screen->scan_period(), 0, m_screen->scan_period()); + m_frame_timer = timer_alloc(TIMER_FRAME); + m_frame_timer->adjust(m_screen->frame_period(), 0, m_screen->frame_period()); + + // allocate screen bitmap + m_screen->register_screen_bitmap(m_bitmap); + + // create sound stream + m_stream = machine().sound().stream_alloc(*this, 0, 1, machine().sample_rate()); + + // buffer for fastest played sample for 5 second so we have enough data for min 5 second + m_noisesize = NOISE_FREQUENCY_MAX * NOISE_BUFFER_SIZE_SEC; + m_noise = auto_alloc_array(machine(), UINT8, m_noisesize); + + { + int noiseshift = 0x7ffff8; + UINT8 data; + + for (int i = 0; i < m_noisesize; i++) + { + data = 0; + if (noiseshift & 0x400000) + data |= 0x80; + if (noiseshift & 0x100000) + data |= 0x40; + if (noiseshift & 0x010000) + data |= 0x20; + if (noiseshift & 0x002000) + data |= 0x10; + if (noiseshift & 0x000800) + data |= 0x08; + if (noiseshift & 0x000080) + data |= 0x04; + if (noiseshift & 0x000010) + data |= 0x02; + if (noiseshift & 0x000004) + data |= 0x01; + m_noise[i] = data; + if (((noiseshift & 0x400000) == 0) != ((noiseshift & 0x002000) == 0)) + noiseshift = (noiseshift << 1) | 1; + else + noiseshift <<= 1; + } + } + + // register for state saving + save_item(NAME(m_reg)); + save_item(NAME(m_last_data)); + save_item(NAME(m_rom)); + save_item(NAME(m_frame_count)); + save_item(NAME(m_lines)); + save_item(NAME(m_timer1_active)); + save_item(NAME(m_timer2_active)); + save_item(NAME(m_timer3_active)); + save_item(NAME(m_cursor1)); + save_item(NAME(m_chargenaddr)); + save_item(NAME(m_bitmapaddr)); + save_item(NAME(m_videoaddr)); + save_item(NAME(m_x_begin)); + save_item(NAME(m_x_end)); + save_item(NAME(m_y_begin)); + save_item(NAME(m_y_end)); + save_item(NAME(m_c16_bitmap)); + save_item(NAME(m_bitmapmulti)); + save_item(NAME(m_mono)); + save_item(NAME(m_monoinversed)); + save_item(NAME(m_multi)); + save_item(NAME(m_ecmcolor)); + save_item(NAME(m_colors)); + save_item(NAME(m_rasterline)); + save_item(NAME(m_lastline)); + save_item(NAME(m_rastertime)); + save_item(NAME(m_tone1pos)); + save_item(NAME(m_tone2pos)); + save_item(NAME(m_tone1samples)); + save_item(NAME(m_tone2samples)); + save_item(NAME(m_noisepos)); + save_item(NAME(m_noisesamples)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void mos7360_device::device_reset() +{ + memset(m_reg, 0, sizeof(m_reg)); + m_last_data = 0; + + m_rom = 1; // FIXME: at start should be RAM or ROM? old c16 code set it to ROM at init: is it correct? + + m_lines = TED7360_LINES; + m_chargenaddr = m_bitmapaddr = m_videoaddr = 0; + m_timer1_active = m_timer2_active = m_timer3_active = 0; + m_cursor1 = 0; + + m_rasterline = 0; + m_lastline = 0; + + m_rastertime = 0.0; + + m_frame_count = 0; + + m_x_begin = 0; + m_x_end = 0; + m_y_begin = 0; + m_y_end = 0; + + memset(m_c16_bitmap, 0, sizeof(m_c16_bitmap)); + memset(m_bitmapmulti, 0, sizeof(m_bitmapmulti)); + memset(m_mono, 0, sizeof(m_mono)); + memset(m_monoinversed, 0, sizeof(m_monoinversed)); + memset(m_multi, 0, sizeof(m_multi)); + memset(m_ecmcolor, 0, sizeof(m_ecmcolor)); + memset(m_colors, 0, sizeof(m_colors)); + + m_tone1pos = 0; + m_tone2pos = 0; + m_tone1samples = 1; + m_tone2samples = 1; + m_noisepos = 0; + m_noisesamples = 1; +} + + +//------------------------------------------------- +// device_timer - handler timer events +//------------------------------------------------- + +void mos7360_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch (id) + { + case TIMER_ID_1: + // proved by digisound of several intros like eoroidpro + m_timer1->adjust(clocks_to_attotime(TIMER1), 1); + m_timer1_active = 1; + set_interrupt(0x08); + break; + + case TIMER_ID_2: + m_timer2->adjust(clocks_to_attotime(0x10000), 2); + m_timer2_active = 1; + set_interrupt(0x10); + break; + + case TIMER_ID_3: + m_timer3->adjust(clocks_to_attotime(0x10000), 3); + m_timer3_active = 1; + set_interrupt(0x40); + break; + + case TIMER_LINE: + raster_interrupt_gen(); + break; + + case TIMER_FRAME: + frame_interrupt_gen(); + break; + } +} + + +//------------------------------------------------- +// sound_stream_update - handle update requests for +// our sound stream +//------------------------------------------------- + +void mos7360_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + int i, v, a; + stream_sample_t *buffer = outputs[0]; + + for (i = 0; i < samples; i++) + { + v = 0; + + if (TONE1_ON) + { + if (m_tone1pos <= m_tone1samples / 2 || !TONE_ON) + v += 0x2ff; // depends on the volume between sound and noise + + m_tone1pos++; + + if (m_tone1pos > m_tone1samples) + m_tone1pos = 0; + } + + if (TONE2_ON || NOISE_ON ) + { + if (TONE2_ON) + { /*higher priority ?! */ + if (m_tone2pos <= m_tone2samples / 2 || !TONE_ON) + v += 0x2ff; + + m_tone2pos++; + + if (m_tone2pos > m_tone2samples) + m_tone2pos = 0; + } + else + { + v += m_noise[(int) ((double) m_noisepos * m_noisesize / m_noisesamples)]; + m_noisepos++; + + if ((double) m_noisepos / m_noisesamples >= 1.0) + m_noisepos = 0; + } + } + + a = VOLUME; + if (a > 8) + a = 8; + + v = v * a; + + buffer[i] = v; + } +} + + +void mos7360_device::draw_character(int ybegin, int yend, int ch, int yoff, int xoff, UINT16 *color) +{ + int y, code; + + for (y = ybegin; y <= yend; y++) + { + if (INROM) + code = read_rom(m_chargenaddr + ch * 8 + y); + else + code = read_ram(m_chargenaddr + ch * 8 + y); + + m_bitmap.pix32(y + yoff, 0 + xoff) = PALETTE_MOS[color[code >> 7]]; + m_bitmap.pix32(y + yoff, 1 + xoff) = PALETTE_MOS[color[(code >> 6) & 1]]; + m_bitmap.pix32(y + yoff, 2 + xoff) = PALETTE_MOS[color[(code >> 5) & 1]]; + m_bitmap.pix32(y + yoff, 3 + xoff) = PALETTE_MOS[color[(code >> 4) & 1]]; + m_bitmap.pix32(y + yoff, 4 + xoff) = PALETTE_MOS[color[(code >> 3) & 1]]; + m_bitmap.pix32(y + yoff, 5 + xoff) = PALETTE_MOS[color[(code >> 2) & 1]]; + m_bitmap.pix32(y + yoff, 6 + xoff) = PALETTE_MOS[color[(code >> 1) & 1]]; + m_bitmap.pix32(y + yoff, 7 + xoff) = PALETTE_MOS[color[code & 1]]; + } +} + +void mos7360_device::draw_character_multi(int ybegin, int yend, int ch, int yoff, int xoff) +{ + int y, code; + + for (y = ybegin; y <= yend; y++) + { + if (INROM) + code = read_rom(m_chargenaddr + ch * 8 + y); + else + code = read_ram(m_chargenaddr + ch * 8 + y); + + m_bitmap.pix32(y + yoff, 0 + xoff) = + m_bitmap.pix32(y + yoff, 1 + xoff) = PALETTE_MOS[m_multi[code >> 6]]; + m_bitmap.pix32(y + yoff, 2 + xoff) = + m_bitmap.pix32(y + yoff, 3 + xoff) = PALETTE_MOS[m_multi[(code >> 4) & 3]]; + m_bitmap.pix32(y + yoff, 4 + xoff) = + m_bitmap.pix32(y + yoff, 5 + xoff) = PALETTE_MOS[m_multi[(code >> 2) & 3]]; + m_bitmap.pix32(y + yoff, 6 + xoff) = + m_bitmap.pix32(y + yoff, 7 + xoff) = PALETTE_MOS[m_multi[code & 3]]; + } +} + +void mos7360_device::draw_bitmap(int ybegin, int yend, int ch, int yoff, int xoff) +{ + int y, code; + + for (y = ybegin; y <= yend; y++) + { + code = read_ram(m_bitmapaddr + ch * 8 + y); + + m_bitmap.pix32(y + yoff, 0 + xoff) = PALETTE_MOS[m_c16_bitmap[code >> 7]]; + m_bitmap.pix32(y + yoff, 1 + xoff) = PALETTE_MOS[m_c16_bitmap[(code >> 6) & 1]]; + m_bitmap.pix32(y + yoff, 2 + xoff) = PALETTE_MOS[m_c16_bitmap[(code >> 5) & 1]]; + m_bitmap.pix32(y + yoff, 3 + xoff) = PALETTE_MOS[m_c16_bitmap[(code >> 4) & 1]]; + m_bitmap.pix32(y + yoff, 4 + xoff) = PALETTE_MOS[m_c16_bitmap[(code >> 3) & 1]]; + m_bitmap.pix32(y + yoff, 5 + xoff) = PALETTE_MOS[m_c16_bitmap[(code >> 2) & 1]]; + m_bitmap.pix32(y + yoff, 6 + xoff) = PALETTE_MOS[m_c16_bitmap[(code >> 1) & 1]]; + m_bitmap.pix32(y + yoff, 7 + xoff) = PALETTE_MOS[m_c16_bitmap[code & 1]]; + } +} + +void mos7360_device::draw_bitmap_multi(int ybegin, int yend, int ch, int yoff, int xoff) +{ + int y, code; + + for (y = ybegin; y <= yend; y++) + { + code = read_ram(m_bitmapaddr + ch * 8 + y); + + m_bitmap.pix32(y + yoff, 0 + xoff) = + m_bitmap.pix32(y + yoff, 1 + xoff) = PALETTE_MOS[m_bitmapmulti[code >> 6]]; + m_bitmap.pix32(y + yoff, 2 + xoff) = + m_bitmap.pix32(y + yoff, 3 + xoff) = PALETTE_MOS[m_bitmapmulti[(code >> 4) & 3]]; + m_bitmap.pix32(y + yoff, 4 + xoff) = + m_bitmap.pix32(y + yoff, 5 + xoff) = PALETTE_MOS[m_bitmapmulti[(code >> 2) & 3]]; + m_bitmap.pix32(y + yoff, 6 + xoff) = + m_bitmap.pix32(y + yoff, 7 + xoff) = PALETTE_MOS[m_bitmapmulti[code & 3]]; + } +} + +void mos7360_device::draw_cursor(int ybegin, int yend, int yoff, int xoff, int color) +{ + int y; + + for (y = ybegin; y <= yend; y++) + { + for (int x = 0; x < 8; x++) + { + m_bitmap.pix32(y + yoff, x + xoff) = PALETTE_MOS[color]; + } + } +} + +void mos7360_device::drawlines(int first, int last) +{ + int line, vline, end; + int attr, ch, c1, c2, ecm; + int offs, yoff, xoff, ybegin, yend, xbegin, xend; + int i; + + m_lastline = last; + + /* top part of display not rastered */ + first -= TED7360_YPOS; + last -= TED7360_YPOS; + if ((first >= last) || (last <= 0)) + return; + if (first < 0) + first = 0; + + if (!SCREENON) + { + for (line = first; (line < last) && (line < m_bitmap.height()); line++) + { + for (int x = 0; x < m_bitmap.width(); x++) + { + m_bitmap.pix32(line, x) = PALETTE_MOS[0]; + } + } + return; + } + + if (COLUMNS40) + xbegin = XPOS, xend = xbegin + 320; + else + xbegin = XPOS + 7, xend = xbegin + 304; + + if (last < m_y_begin) + end = last; + else + end = m_y_begin + YPOS; + { + for (line = first; line < end; line++) + { + for (int x = 0; x < m_bitmap.width(); x++) + { + m_bitmap.pix32(line, x) = PALETTE_MOS[FRAMECOLOR]; + } + } + } + if (LINES25) + vline = line - m_y_begin - YPOS; + else + vline = line - m_y_begin - YPOS + 8 - VERTICALPOS; + + if (last < m_y_end + YPOS) + end = last; + else + end = m_y_end + YPOS; + + for (; line < end; vline = (vline + 8) & ~7, line = line + 1 + yend - ybegin) + { + offs = (vline >> 3) * 40; + ybegin = vline & 7; + yoff = line - ybegin; + yend = (yoff + 7 < end) ? 7 : (end - yoff - 1); + /* rendering 39 characters */ + /* left and right borders are overwritten later */ + + for (xoff = m_x_begin + XPOS; xoff < m_x_end + XPOS; xoff += 8, offs++) + { + if (HIRESON) + { + ch = read_ram((m_videoaddr | 0x400) + offs); + attr = read_ram(m_videoaddr + offs); + c1 = ((ch >> 4) & 0xf) | (attr << 4); + c2 = (ch & 0xf) | (attr & 0x70); + m_bitmapmulti[1] = m_c16_bitmap[1] = c1 & 0x7f; + m_bitmapmulti[2] = m_c16_bitmap[0] = c2 & 0x7f; + if (MULTICOLORON) + { + draw_bitmap_multi(ybegin, yend, offs, yoff, xoff); + } + else + { + draw_bitmap(ybegin, yend, offs, yoff, xoff); + } + } + else + { + ch = read_ram((m_videoaddr | 0x400) + offs); + attr = read_ram(m_videoaddr + offs); + // levente harsfalvi's docu says cursor off in ecm and multicolor + if (ECMON) + { + // hardware reverse off + ecm = ch >> 6; + m_ecmcolor[0] = m_colors[ecm]; + m_ecmcolor[1] = attr & 0x7f; + draw_character(ybegin, yend, ch & ~0xc0, yoff, xoff, m_ecmcolor); + } + else if (MULTICOLORON) + { + // hardware reverse off + if (attr & 8) + { + m_multi[3] = attr & 0x77; + draw_character_multi(ybegin, yend, ch, yoff, xoff); + } + else + { + m_mono[1] = attr & 0x7f; + draw_character(ybegin, yend, ch, yoff, xoff, m_mono); + } + } + else if (m_cursor1 && (offs == CURSOR1POS)) + { + draw_cursor(ybegin, yend, yoff, xoff, attr & 0x7f); + } + else if (REVERSEON && (ch & 0x80)) + { + m_monoinversed[0] = attr & 0x7f; + if (m_cursor1 && (attr & 0x80)) + draw_cursor(ybegin, yend, yoff, xoff, m_monoinversed[0]); + else + draw_character(ybegin, yend, ch & ~0x80, yoff, xoff, m_monoinversed); + } + else + { + m_mono[1] = attr & 0x7f; + if (m_cursor1 && (attr & 0x80)) + draw_cursor(ybegin, yend, yoff, xoff, m_mono[0]); + else + draw_character(ybegin, yend, ch, yoff, xoff, m_mono); + } + } + } + + for (i = ybegin; i <= yend; i++) + { + for (int x = 0; x < xbegin; x++) + { + m_bitmap.pix32(yoff + i, x) = PALETTE_MOS[FRAMECOLOR]; + } + + for (int x = xend; x < m_bitmap.width(); x++) + { + m_bitmap.pix32(yoff + i, x) = PALETTE_MOS[FRAMECOLOR]; + } + } + } + + if (last < m_bitmap.height()) + end = last; + else + end = m_bitmap.height(); + + for (; line < end; line++) + { + for (int x = 0; x < m_bitmap.width(); x++) + { + m_bitmap.pix32(line, x) = PALETTE_MOS[FRAMECOLOR]; + } + } +} + +void mos7360_device::soundport_w(int offset, int data) +{ + // int old = m_reg[offset & 0x1f]; + m_stream->update(); + + switch (offset) + { + case 0x0e: + case 0x12: + if (offset == 0x12) + m_reg[offset & 0x1f] = (m_reg[offset & 0x1f] & ~3) | (data & 3); + else + m_reg[offset & 0x1f] = data; + + m_tone1samples = machine().sample_rate() / TONE_FREQUENCY (TONE1_VALUE); + DBG_LOG(1, "ted7360", ("tone1 %d %d sample:%d\n", TONE1_VALUE, TONE_FREQUENCY(TONE1_VALUE), m_tone1samples)); + break; + + case 0xf: + case 0x10: + m_reg[offset & 0x1f] = data; + + m_tone2samples = machine().sample_rate() / TONE_FREQUENCY (TONE2_VALUE); + DBG_LOG (1, "ted7360", ("tone2 %d %d sample:%d\n", TONE2_VALUE, TONE_FREQUENCY(TONE2_VALUE), m_tone2samples)); + + m_noisesamples = (int) ((double) NOISE_FREQUENCY_MAX * machine().sample_rate() * NOISE_BUFFER_SIZE_SEC / NOISE_FREQUENCY); + DBG_LOG (1, "ted7360", ("noise %d sample:%d\n", NOISE_FREQUENCY, m_noisesamples)); + + if (!NOISE_ON || ((double) m_noisepos / m_noisesamples >= 1.0)) + m_noisepos = 0; + break; + + case 0x11: + m_reg[offset & 0x1f] = data; + DBG_LOG(1, "ted7360", ("%s volume %d, %s %s %s\n", TONE_ON?"on":"off", + VOLUME, TONE1_ON?"tone1":"", TONE2_ON?"tone2":"", NOISE_ON?"noise":"")); + + if (!TONE_ON||!TONE1_ON) m_tone1pos = 0; + if (!TONE_ON||!TONE2_ON) m_tone2pos = 0; + if (!TONE_ON||!NOISE_ON) m_noisepos = 0; + break; + } +} + + +//------------------------------------------------- +// read - register read +//------------------------------------------------- + +UINT8 mos7360_device::read(address_space &space, offs_t offset, int &cs0, int &cs1) +{ + UINT8 val = m_last_data; + + cs0 = cs0_r(offset); + cs1 = cs1_r(offset); + + switch (offset) + { + case 0xff00: + val = attotime_to_clocks(m_timer1->remaining()) & 0xff; + break; + case 0xff01: + val = attotime_to_clocks(m_timer1->remaining()) >> 8; + break; + case 0xff02: + val = attotime_to_clocks(m_timer2->remaining()) & 0xff; + break; + case 0xff03: + val = attotime_to_clocks(m_timer2->remaining()) >> 8; + break; + case 0xff04: + val = attotime_to_clocks(m_timer3->remaining()) & 0xff; + break; + case 0xff05: + val = attotime_to_clocks(m_timer3->remaining()) >> 8; + break; + case 0xff07: + val = (m_reg[offset & 0x1f] & ~0x40); + if (m_clock == TED7360NTSC_CLOCK) + val |= 0x40; + break; + case 0xff13: + val = m_reg[offset & 0x1f] & ~1; + if (m_rom) + val |= 1; + break; + case 0xff1c: /*rasterline */ + drawlines(m_lastline, m_rasterline); + val = ((RASTERLINE_2_C16(m_rasterline) & 0x100) >> 8) | 0xfe; /* expected by matrix */ + break; + case 0xff1d: /*rasterline */ + drawlines(m_lastline, m_rasterline); + val = RASTERLINE_2_C16(m_rasterline) & 0xff; + break; + case 0xff1e: /*rastercolumn */ + val = rastercolumn() / 2; /* pengo >=0x99 */ + break; + case 0xff1f: + val = ((m_rasterline & 7) << 4) | (m_reg[offset & 0x1f] & 0x0f); + DBG_LOG(1, "port_w", ("read from cursorblink %.2x\n", val)); + break; + case 0xff06: + case 0xff08: + case 0xff09: + case 0xff0a: + case 0xff0b: + case 0xff0c: + case 0xff0d: + case 0xff0e: + case 0xff0f: + case 0xff10: + case 0xff11: + case 0xff12: + case 0xff14: + case 0xff15: + case 0xff16: + case 0xff17: + case 0xff18: + case 0xff19: + case 0xff1a: + case 0xff1b: + val = m_reg[offset & 0x1f]; + break; + } + + return val; +} + + +//------------------------------------------------- +// write - register write +//------------------------------------------------- + +void mos7360_device::write(address_space &space, offs_t offset, UINT8 data, int &cs0, int &cs1) +{ + int old; + + cs0 = cs0_r(offset); + cs1 = cs1_r(offset); + + switch (offset) + { + case 0xff0e: + case 0xff0f: + case 0xff10: + case 0xff11: + case 0xff12: + soundport_w(offset & 0x1f, data); + break; + } + + switch (offset) + { + case 0xff00: /* stop timer 1 */ + m_reg[offset & 0x1f] = data; + + if (m_timer1_active) + { + m_reg[1] = attotime_to_clocks(m_timer1->remaining()) >> 8; + m_timer1->reset(); + m_timer1_active = 0; + } + break; + case 0xff01: /* start timer 1 */ + m_reg[offset & 0x1f] = data; + m_timer1->adjust(clocks_to_attotime(TIMER1), 1); + m_timer1_active = 1; + break; + case 0xff02: /* stop timer 2 */ + m_reg[offset & 0x1f] = data; + if (m_timer2_active) + { + m_reg[3] = attotime_to_clocks(m_timer2->remaining()) >> 8; + m_timer2->reset(); + m_timer2_active = 0; + } + break; + case 0xff03: /* start timer 2 */ + m_reg[offset & 0x1f] = data; + m_timer2->adjust(clocks_to_attotime(TIMER2), 2); + m_timer2_active = 1; + break; + case 0xff04: /* stop timer 3 */ + m_reg[offset & 0x1f] = data; + if (m_timer3_active) + { + m_reg[5] = attotime_to_clocks(m_timer3->remaining()) >> 8; + m_timer3->reset(); + m_timer3_active = 0; + } + break; + case 0xff05: /* start timer 3 */ + m_reg[offset & 0x1f] = data; + m_timer3->adjust(clocks_to_attotime(TIMER3), 3); + m_timer3_active = 1; + break; + case 0xff06: + if (m_reg[offset & 0x1f] != data) + { + drawlines(m_lastline, m_rasterline); + m_reg[offset & 0x1f] = data; + if (LINES25) + { + m_y_begin = 0; + m_y_end = m_y_begin + 200; + } + else + { + m_y_begin = 4; + m_y_end = m_y_begin + 192; + } + m_chargenaddr = CHARGENADDR; + } + break; + case 0xff07: + if (m_reg[offset & 0x1f] != data) + { + drawlines(m_lastline, m_rasterline); + m_reg[offset & 0x1f] = data; + if (COLUMNS40) + { + m_x_begin = 0; + m_x_end = m_x_begin + 320; + } + else + { + m_x_begin = HORICONTALPOS; + m_x_end = m_x_begin + 320; + } + DBG_LOG(3, "port_w", ("%s %s\n", data & 0x40 ? "ntsc" : "pal", data & 0x20 ? "hori freeze" : "")); + m_chargenaddr = CHARGENADDR; + } + break; + case 0xff08: + m_reg[offset & 0x1f] = m_read_k(data); + break; + case 0xff09: + if (data & 0x08) + clear_interrupt(8); + if (data & 0x10) + clear_interrupt(0x10); + if (data & 0x40) + clear_interrupt(0x40); + if (data & 0x02) + clear_interrupt(2); + break; + case 0xff0a: + old = data; + m_reg[offset & 0x1f] = data | 0xa0; +#if 0 + m_reg[9] = (m_reg[9] & 0xa1) | (m_reg[9] & data & 0x5e); + if (m_reg[9] & 0x80) + clear_interrupt(0); +#endif + if ((data ^ old) & 1) + { + /* DBG_LOG(1,"set rasterline hi",("soll:%d\n",RASTERLINE)); */ + } + break; + case 0xff0b: + if (data != m_reg[offset & 0x1f]) + { + drawlines(m_lastline, m_rasterline); + m_reg[offset & 0x1f] = data; + /* DBG_LOG(1,"set rasterline lo",("soll:%d\n",RASTERLINE)); */ + } + break; + case 0xff0c: + case 0xff0d: + if (m_reg[offset & 0x1f] != data) + { + drawlines(m_lastline, m_rasterline); + m_reg[offset & 0x1f] = data; + } + break; + case 0xff12: + if (m_reg[offset & 0x1f] != data) + { + drawlines(m_lastline, m_rasterline); + m_reg[offset & 0x1f] = data; + m_bitmapaddr = BITMAPADDR; + m_chargenaddr = CHARGENADDR; + DBG_LOG(3, "port_w", ("bitmap %.4x %s\n", BITMAPADDR, INROM ? "rom" : "ram")); + } + break; + case 0xff13: + if (m_reg[offset & 0x1f] != data) + { + drawlines(m_lastline, m_rasterline); + m_reg[offset & 0x1f] = data; + m_chargenaddr = CHARGENADDR; + DBG_LOG(3, "port_w", ("chargen %.4x %s %d\n", CHARGENADDR, data & 2 ? "" : "doubleclock", data & 1)); + } + break; + case 0xff14: + if (m_reg[offset & 0x1f] != data) + { + drawlines(m_lastline, m_rasterline); + m_reg[offset & 0x1f] = data; + m_videoaddr = VIDEOADDR; + DBG_LOG(3, "port_w", ("videoram %.4x\n", VIDEOADDR)); + } + break; + case 0xff15: /* backgroundcolor */ + if (m_reg[offset & 0x1f] != data) + { + drawlines(m_lastline, m_rasterline); + m_reg[offset & 0x1f] = data; + m_monoinversed[1] = m_mono[0] = m_bitmapmulti[0] = m_multi[0] = m_colors[0] = BACKGROUNDCOLOR; + } + break; + case 0xff16: /* foregroundcolor */ + if (m_reg[offset & 0x1f] != data) + { + drawlines(m_lastline, m_rasterline); + m_reg[offset & 0x1f] = data; + m_bitmapmulti[3] = m_multi[1] = m_colors[1] = FOREGROUNDCOLOR; + } + break; + case 0xff17: /* multicolor 1 */ + if (m_reg[offset & 0x1f] != data) + { + drawlines(m_lastline, m_rasterline); + m_reg[offset & 0x1f] = data; + m_multi[2] = m_colors[2] = MULTICOLOR1; + } + break; + case 0xff18: /* multicolor 2 */ + if (m_reg[offset & 0x1f] != data) + { + drawlines(m_lastline, m_rasterline); + m_reg[offset & 0x1f] = data; + m_colors[3] = MULTICOLOR2; + } + break; + case 0xff19: /* framecolor */ + if (m_reg[offset & 0x1f] != data) + { + drawlines(m_lastline, m_rasterline); + m_reg[offset & 0x1f] = data; + m_colors[4] = FRAMECOLOR; + } + break; + case 0xff1c: + m_reg[offset & 0x1f] = data; /*? */ + DBG_LOG(1, "port_w", ("write to rasterline high %.2x\n", + data)); + break; + case 0xff1f: + m_reg[offset & 0x1f] = data; + DBG_LOG(1, "port_w", ("write to cursorblink %.2x\n", data)); + break; + case 0xff3e: + m_rom = 1; + break; + case 0xff3f: + m_rom = 0; + break; + case 0xff1a: + case 0xff1b: + case 0xff1d: + case 0xff1e: + m_reg[offset & 0x1f] = data; + break; + } +} + + +//------------------------------------------------- +// update_screen - update screen +//------------------------------------------------- + +UINT32 mos7360_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + copybitmap(bitmap, m_bitmap, 0, 0, 0, 0, cliprect); + + return 0; +} + +void mos7360_device::frame_interrupt_gen() +{ + if ((m_reg[0x1f] & 0xf) >= 0x0f) + { + /* if (m_frame_count >= CURSORRATE) */ + m_cursor1 ^= 1; + m_reg[0x1f] &= ~0xf; + m_frame_count = 0; + } + else + m_reg[0x1f]++; +} + +void mos7360_device::raster_interrupt_gen() +{ + m_rasterline++; + m_rastertime = machine().time().as_double(); + if (m_rasterline >= m_lines) + { + m_rasterline = 0; + drawlines(m_lastline, TED7360_LINES); + m_lastline = 0; + } + + if (m_rasterline == C16_2_RASTERLINE(RASTERLINE)) + { + drawlines(m_lastline, m_rasterline); + set_interrupt(2); + } +} + + +//------------------------------------------------- +// cs0_r - chip select 0 read +//------------------------------------------------- + +int mos7360_device::cs0_r(offs_t offset) +{ + if (m_rom && offset >= 0x8000 && offset < 0xc000) + { + return 0; + } + + return 1; +} + + +//------------------------------------------------- +// cs1_r - chip select 1 read +//------------------------------------------------- + +int mos7360_device::cs1_r(offs_t offset) +{ + if (m_rom && ((offset >= 0xc000 && offset < 0xfd00) || (offset >= 0xff20))) + { + return 0; + } + + return 1; +} diff --git a/src/devices/sound/mos7360.h b/src/devices/sound/mos7360.h new file mode 100644 index 00000000000..aea96b42bd9 --- /dev/null +++ b/src/devices/sound/mos7360.h @@ -0,0 +1,205 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/*************************************************************************** + + MOS 7360/8360 Text Edit Device (TED) emulation + +**************************************************************************** + _____ _____ + DB6 1 |* \_/ | 40 Vcc + DB5 2 | | 39 DB7 + DB4 3 | | 38 DB8 + DB3 4 | | 37 DB9 + DB2 5 | | 36 DB10 + DB1 6 | | 35 DB11 + DB0 7 | | 34 A13 + _IRQ 8 | | 33 A12 + LP 9 | | 32 A11 + _CS 10 | MOS7360 | 31 A10 + R/W 11 | | 30 A9 + BA 12 | | 29 A8 + Vdd 13 | | 28 A7 + COLOR 14 | | 27 A6 + S/LUM 15 | | 26 A5 + AEC 16 | | 25 A4 + PH0 17 | | 24 A3 + PHIN 18 | | 23 A2 + PHCOL 19 | | 22 A1 + Vss 20 |_____________| 21 A0 + +***************************************************************************/ + +#pragma once + +#ifndef __MOS7360__ +#define __MOS7360__ + +#include "emu.h" + + + +/*************************************************************************** + DEVICE CONFIGURATION MACROS +***************************************************************************/ + +#define MCFG_MOS7360_ADD(_tag, _screen_tag, _cpu_tag, _clock, _videoram_map, _irq, _k) \ + MCFG_SCREEN_ADD(_screen_tag, RASTER) \ + MCFG_SCREEN_REFRESH_RATE(TED7360PAL_VRETRACERATE) \ + MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(2500)) \ + MCFG_SCREEN_SIZE(336, 216) \ + MCFG_SCREEN_VISIBLE_AREA(0, 336 - 1, 0, 216 - 1) \ + MCFG_SCREEN_UPDATE_DEVICE(_tag, mos7360_device, screen_update) \ + MCFG_DEVICE_ADD(_tag, MOS7360, _clock) \ + MCFG_DEVICE_ADDRESS_MAP(AS_0, _videoram_map) \ + MCFG_VIDEO_SET_SCREEN(_screen_tag) \ + downcast(device)->set_callbacks(_cpu_tag, DEVCB_##_irq, DEVCB_##_k); + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define TED7360NTSC_VRETRACERATE 60 +#define TED7360PAL_VRETRACERATE 50 +#define TED7360_HRETRACERATE 15625 + +/* the following values depend on the VIC clock, + * but to achieve TV-frequency the clock must have a fix frequency */ +#define TED7360_HSIZE 320 +#define TED7360_VSIZE 200 + +/* of course you clock select an other clock, but for accurate */ +/* video timing (these are used in c16/c116/plus4) */ +#define TED7360NTSC_CLOCK (14318180/4) +#define TED7360PAL_CLOCK (17734470/5) + +/* pal 50 Hz vertical screen refresh, screen consists of 312 lines + * ntsc 60 Hz vertical screen refresh, screen consists of 262 lines */ +#define TED7360NTSC_LINES 261 +#define TED7360PAL_LINES 312 + + + +/*************************************************************************** + TYPE DEFINITIONS +***************************************************************************/ + +// ======================> mos7360_device + +class mos7360_device : public device_t, + public device_memory_interface, + public device_sound_interface, + public device_video_interface +{ +public: + // construction/destruction + //mos7360_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock); + mos7360_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + template void set_callbacks(const char *cpu_tag, _irq irq, _k k) { + m_cpu_tag = cpu_tag; + m_write_irq.set_callback(irq); + m_read_k.set_callback(k); + } + + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const; + + UINT8 read(address_space &space, offs_t offset, int &cs0, int &cs1); + void write(address_space &space, offs_t offset, UINT8 data, int &cs0, int &cs1); + + UINT32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); + +protected: + enum + { + TYPE_7360 + }; + + enum + { + TIMER_ID_1, + TIMER_ID_2, + TIMER_ID_3, + TIMER_LINE, + TIMER_FRAME + }; + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + // device_sound_interface callbacks + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + + inline void set_interrupt(int mask); + inline void clear_interrupt(int mask); + inline int rastercolumn(); + inline UINT8 read_ram(offs_t offset); + inline UINT8 read_rom(offs_t offset); + + void draw_character(int ybegin, int yend, int ch, int yoff, int xoff, UINT16 *color); + void draw_character_multi(int ybegin, int yend, int ch, int yoff, int xoff); + void draw_bitmap(int ybegin, int yend, int ch, int yoff, int xoff); + void draw_bitmap_multi(int ybegin, int yend, int ch, int yoff, int xoff); + void draw_cursor(int ybegin, int yend, int yoff, int xoff, int color); + void drawlines(int first, int last); + void soundport_w(int offset, int data); + void frame_interrupt_gen(); + void raster_interrupt_gen(); + int cs0_r(offs_t offset); + int cs1_r(offs_t offset); + + const address_space_config m_videoram_space_config; + + devcb_write_line m_write_irq; + devcb_read8 m_read_k; + + const char *m_cpu_tag; + cpu_device *m_cpu; + sound_stream *m_stream; + + UINT8 m_reg[0x20]; + UINT8 m_last_data; + + bitmap_rgb32 m_bitmap; + + int m_rom; + + int m_frame_count; + + int m_lines; + int m_timer1_active, m_timer2_active, m_timer3_active; + emu_timer *m_timer1, *m_timer2, *m_timer3; + int m_cursor1; + + int m_chargenaddr, m_bitmapaddr, m_videoaddr; + + int m_x_begin, m_x_end; + int m_y_begin, m_y_end; + + UINT16 m_c16_bitmap[2], m_bitmapmulti[4], m_mono[2], m_monoinversed[2], m_multi[4], m_ecmcolor[2], m_colors[5]; + + int m_rasterline, m_lastline; + double m_rastertime; + + /* sound part */ + UINT8 *m_noise; + int m_tone1pos, m_tone2pos, + m_tone1samples, m_tone2samples, + m_noisesize, /* number of samples */ + m_noisepos, /* pos of tone */ + m_noisesamples; /* count of samples to give out per tone */ + + emu_timer *m_line_timer; + emu_timer *m_frame_timer; +}; + + +// device type definition +extern const device_type MOS7360; + + + +#endif diff --git a/src/devices/sound/mpeg_audio.c b/src/devices/sound/mpeg_audio.c new file mode 100644 index 00000000000..bf024383a06 --- /dev/null +++ b/src/devices/sound/mpeg_audio.c @@ -0,0 +1,759 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +/*************************************************************************** + + MPEG audio support. Only layer2 and variants for now. + +***************************************************************************/ + +#include "emu.h" +#include "mpeg_audio.h" + +mpeg_audio::mpeg_audio(const void *_base, unsigned int _accepted, bool lsb_first, int _position_align) +{ + base = (const UINT8 *)_base; + accepted = _accepted; + do_gb = lsb_first ? do_gb_lsb : do_gb_msb; + position_align = _position_align ? _position_align - 1 : 0; + + clear(); +} + +void mpeg_audio::clear() +{ + memset(audio_buffer, 0, sizeof(audio_buffer)); + audio_buffer_pos[0] = 16*32; + audio_buffer_pos[1] = 16*32; +} + +bool mpeg_audio::decode_buffer(int &pos, int limit, short *output, + int &output_samples, int &sample_rate, int &channels) +{ + if(limit - pos < 16) + return false; + + // Scan for the sync mark + // + // Avoid the exception dance at the point where going out of bound + // is the most probable and easily avoidable + + current_pos = pos; + current_limit = limit; + unsigned short sync = do_gb(base, current_pos, 12); + + retry_sync: + while(sync != 0xfff && current_pos < limit) + sync = ((sync << 1) | do_gb(base, current_pos, 1)) & 0xfff; + + if(limit - current_pos < 4) + return false; + + int layer = 0; + int variant = do_gb(base, current_pos, 3); + switch(variant) { + case 2: + if(accepted & L2_5) + layer = 2; + else if(accepted & AMM) + layer = 4; + break; + + case 5: + if(accepted & L3) + layer = 3; + break; + + case 6: + if(accepted & (L2|L2_5)) + layer = 2; + else if(accepted & AMM) + layer = 4; + break; + + case 7: + if(accepted & L1) + layer = 1; + break; + } + + if(!layer) { + current_pos -= 3; + sync = ((sync << 1) | do_gb(base, current_pos, 1)) & 0xfff; + goto retry_sync; + } + + switch(layer) { + case 1: + abort(); + case 2: + try { + read_header_mpeg2(variant == 2); + read_data_mpeg2(); + decode_mpeg2(output, output_samples); + } catch(limit_hit) { + return false; + } + break; + case 3: + abort(); + case 4: + try { + read_header_amm(variant == 2); + read_data_mpeg2(); + if(last_frame_number) + decode_mpeg2(output, output_samples); + } catch(limit_hit) { + return false; + } + break; + } + + if(position_align) + current_pos = (current_pos + position_align) & ~position_align; + + pos = current_pos; + sample_rate = sample_rates[sampling_rate]; + channels = channel_count; + return true; +} + +void mpeg_audio::read_header_amm(bool layer25) +{ + gb(1); // unused + int full_packets_count = gb(4); // max 12 + int srate_index = gb(2); // max 2 + sampling_rate = srate_index + 4 * layer25; + int last_packet_frame_id = gb(2); // max 2 + last_frame_number = 3*full_packets_count + last_packet_frame_id; + int stereo_mode = gb(2); + int stereo_mode_ext = gb(2); + param_index = gb(3); + gb(1); // must be zero + + channel_count = stereo_mode != 3 ? 2 : 1; + + total_bands = total_band_counts[param_index]; + joint_bands = total_bands; + if(stereo_mode == 1) // joint stereo + joint_bands = joint_band_counts[stereo_mode_ext]; + if(joint_bands > total_bands ) + joint_bands = total_bands; +} + +void mpeg_audio::read_header_mpeg2(bool layer25) +{ + int prot = gb(1); + int bitrate_index = gb(4); + sampling_rate = gb(2); + gb(1); // padding + gb(1); + last_frame_number = 36; + int stereo_mode = gb(2); + int stereo_mode_ext = gb(2); + gb(2); // copyright, original + gb(2); // emphasis + if(!prot) + gb(16); // crc + + channel_count = stereo_mode != 3 ? 2 : 1; + + param_index = layer2_param_index[channel_count-1][sampling_rate][bitrate_index]; + assert(param_index != -1); + + total_bands = total_band_counts[param_index]; + joint_bands = total_bands; + if(stereo_mode == 1) // joint stereo + joint_bands = joint_band_counts[stereo_mode_ext]; + if(joint_bands > total_bands ) + joint_bands = total_bands; +} + +void mpeg_audio::read_data_mpeg2() +{ + read_band_params(); + read_scfci(); + read_band_amplitude_params(); +} + +void mpeg_audio::decode_mpeg2(short *output, int &output_samples) +{ + output_samples = 0; + build_amplitudes(); + + // Supposed to stop at last_frame_number when it's not 12*3+2 = 38 + int frame_number = 0; + for(int upper_step = 0; upper_step<3; upper_step++) + for(int middle_step = 0; middle_step < 4; middle_step++) { + build_next_segments(upper_step); + for(int lower_step = 0; lower_step < 3; lower_step++) { + retrieve_subbuffer(lower_step); + + for(int chan=0; chan> 3] & (0x80 >> (pos & 7))) + v |= 1; + pos++; + } + return v; +} + +int mpeg_audio::do_gb_lsb(const unsigned char *data, int &pos, int count) +{ + int v = 0; + for(int i=0; i != count; i++) { + v <<= 1; + if(data[pos >> 3] & (0x01 << (pos & 7))) + v |= 1; + pos++; + } + return v; +} + +int mpeg_audio::get_band_param(int band) +{ + int bit_count = band_parameter_index_bits_count[param_index][band]; + int index = gb(bit_count); + return band_parameter_indexed_values[param_index][band][index]; +} + +void mpeg_audio::read_band_params() +{ + int band = 0; + + while(band < joint_bands) { + for(int chan=0; chan < channel_count; chan++) + band_param[chan][band] = get_band_param(band); + band++; + } + + while(band < total_bands) { + int val = get_band_param(band); + band_param[0][band] = val; + band_param[1][band] = val; + band++; + } + + while(band < 32) { + band_param[0][band] = 0; + band_param[1][band] = 0; + band++; + } +} + +void mpeg_audio::read_scfci() +{ + memset(scfsi, 0, sizeof(scfsi)); + for(int band=0; band < total_bands; band++) + for(int chan=0; chan < channel_count; chan++) + if(band_param[chan][band]) + scfsi[chan][band] = gb(2); +} + +void mpeg_audio::read_band_amplitude_params() +{ + memset(scf, 0, sizeof(scf)); + for(int band=0; band < total_bands; band++) + for(int chan=0; chan= 32767) + cval = 32767; + else + cval = int(val); + *output = cval; + output += step; + } +} diff --git a/src/devices/sound/mpeg_audio.h b/src/devices/sound/mpeg_audio.h new file mode 100644 index 00000000000..615116b6021 --- /dev/null +++ b/src/devices/sound/mpeg_audio.h @@ -0,0 +1,134 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +/*************************************************************************** + + MPEG audio support. Only layer2 and variants for now. + +***************************************************************************/ + +#ifndef __MPEG_AUDIO_H__ +#define __MPEG_AUDIO_H__ + +class mpeg_audio { +public: + // Accepted layers. Beware that AMM is incompatible with L2 (and + // not automatically recognizable) and that 2.5 implies 2. + + enum { + L1 = 1, + L2 = 2, + L2_5 = 4, + L3 = 8, + AMM = 16 + }; + + // base = Start of the mpeg data block + // accepted = Binary or of accepted layers + // lsb_first = Read bits out of bytes lsb-first rather than msb first + // position_align = Position alignment after reading a block (0 = pure bitstream, must be a power of 2 otherwise) + + mpeg_audio(const void *base, unsigned int accepted, bool lsb_first, int position_align); + + // Decode one mpeg buffer. + // pos = position in *bits* relative to base + // limit = maximum accepted position in bits + // output = output samples, interleaved + // output_samples = number of samples written to output per channel + // sample_rate = output sample rate + // channels = number of channels written to output (total sample count is output_samples*channels) + // + // returns true if the buffer was complete and the new position in pos, false otherwise + // + // Sample rate and channels can change every buffer. That's mpeg + // for you. Channels rarely changes, sample rate sometimes do, + // especially in amm samples (drops to half at the end). + // + // One call to output buffer will generate 0 or 1 frame, which is + // 384 samples per channel in layer I and 1152 otherwise (up to + // 1152 in the amm case, <1152 indicating end of stream). + + bool decode_buffer(int &pos, int limit, short *output, + int &output_samples, int &sample_rate, int &channels); + + + // Clear audio buffer + void clear(); + + // Change the base pointer + void set_base(const void *base); + +private: + struct limit_hit {}; + + struct band_info { + int modulo; + double s1; + int bits, cube_bits; + int s4, s5; + double range, s7, scale, offset; + }; + + static const double scalefactors[64]; + static const int sample_rates[8]; + static const int layer2_param_index[2][4][16]; + static const int band_parameter_indexed_values[5][32][17]; + static const int band_parameter_index_bits_count[5][32]; + static const int joint_band_counts[4], total_band_counts[5]; + static const band_info band_infos[18]; + static const double synthesis_filter[512]; + + const UINT8 *base; + int accepted, position_align; + + int sampling_rate, last_frame_number; + int param_index; + + int channel_count, total_bands, joint_bands; + + int band_param[2][32]; + int scfsi[2][32]; + int scf[2][3][32]; + double amp_values[2][3][32]; + double bdata[2][3][32]; + double subbuffer[2][32]; + double audio_buffer[2][32*32]; + int audio_buffer_pos[2]; + + int master_pos; + + int current_pos, current_limit; + + void read_header_amm(bool layer25); + void read_header_mpeg2(bool layer25); + void read_data_mpeg2(); + void decode_mpeg2(short *output, int &output_samples); + + int get_band_param(int band); + void read_band_params(); + void read_scfci(); + void read_band_amplitude_params(); + void read_band_value_triplet(int chan, int band); + void build_amplitudes(); + void build_next_segments(int step); + void retrieve_subbuffer(int step); + void handle_block(int &pos); + void idct32(const double *input, double *output); + void resynthesis(const double *input, double *output); + void scale_and_clamp(const double *input, short *output, int step); + + + static int do_gb_msb(const unsigned char *data, int &pos, int count); + static int do_gb_lsb(const unsigned char *data, int &pos, int count); + + int (*do_gb)(const unsigned char *data, int &pos, int count); + + inline int gb(int count) + { + if(current_pos + count > current_limit) + throw limit_hit(); + + return do_gb(base, current_pos, count); + } +}; + +#endif diff --git a/src/devices/sound/msm5205.c b/src/devices/sound/msm5205.c new file mode 100644 index 00000000000..ae925a513b8 --- /dev/null +++ b/src/devices/sound/msm5205.c @@ -0,0 +1,340 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/* + * streaming ADPCM driver + * by Aaron Giles + * + * Library to transcode from an ADPCM source to raw PCM. + * Written by Buffoni Mirko in 08/06/97 + * References: various sources and documents. + * + * HJB 08/31/98 + * modified to use an automatically selected oversampling factor + * for the current sample rate + * + * 01/06/99 + * separate MSM5205 emulator form adpcm.c and some fix + * + * 07/29/12 + * added basic support for the MSM6585 + */ + +#include "emu.h" +#include "msm5205.h" + +/* + + MSM 5205 ADPCM chip: + + Data is streamed from a CPU by means of a clock generated on the chip. + + A reset signal is set high or low to determine whether playback (and interrupts) are occurring. + + MSM6585: is an upgraded MSM5205 voice synth IC. + Improvements: + More precise internal DA converter + Built in low-pass filter + Expanded sampling frequency + + Differences between MSM6585 & MSM5205: + + MSM6586 MSM5205 + Master clock frequency 640kHz 384kHz + Sampling frequency 4k/8k/16k/32kHz 4k/6k/8kHz + ADPCM bit length 4-bit 3-bit/4-bit + DA converter 12-bit 10-bit + Low-pass filter -40dB/oct N/A + Overflow prevent circuit Included N/A + + Timer callback at VCLK low edge on MSM5205 (at rising edge on MSM6585) + + TODO: + - lowpass filter for MSM6585 + + */ + +const device_type MSM5205 = &device_creator; +const device_type MSM6585 = &device_creator; + + +msm5205_device::msm5205_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, MSM5205, "MSM5205", tag, owner, clock, "msm5205", __FILE__), + device_sound_interface(mconfig, *this), + m_prescaler(0), + m_bitwidth(0), + m_select(0), + m_vclk_cb(*this) +{ +} + +msm5205_device::msm5205_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_sound_interface(mconfig, *this), + m_prescaler(0), + m_bitwidth(0), + m_select(0), + m_vclk_cb(*this) +{ +} + + +msm6585_device::msm6585_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : msm5205_device(mconfig, MSM6585, "MSM6585", tag, owner, clock, "msm6585", __FILE__) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void msm5205_device::device_start() +{ + m_mod_clock = clock(); + m_vclk_cb.resolve(); + + /* compute the difference tables */ + compute_tables(); + + /* stream system initialize */ + m_stream = machine().sound().stream_alloc(*this, 0, 1, clock()); + m_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(msm5205_device::vclk_callback), this)); + + /* register for save states */ + save_item(NAME(m_mod_clock)); + save_item(NAME(m_data)); + save_item(NAME(m_vclk)); + save_item(NAME(m_reset)); + save_item(NAME(m_prescaler)); + save_item(NAME(m_bitwidth)); + save_item(NAME(m_signal)); + save_item(NAME(m_step)); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void msm5205_device::device_reset() +{ + /* initialize work */ + m_data = 0; + m_vclk = 0; + m_reset = 0; + m_signal = 0; + m_step = 0; + + /* timer and bitwidth set */ + playmode_w(m_select); +} + + +/* + * ADPCM lookup table + */ + +/* step size index shift table */ +static const int index_shift[8] = { -1, -1, -1, -1, 2, 4, 6, 8 }; + +/* + * Compute the difference table + */ + +void msm5205_device::compute_tables() +{ + /* nibble to bit map */ + static const int nbl2bit[16][4] = + { + { 1, 0, 0, 0}, { 1, 0, 0, 1}, { 1, 0, 1, 0}, { 1, 0, 1, 1}, + { 1, 1, 0, 0}, { 1, 1, 0, 1}, { 1, 1, 1, 0}, { 1, 1, 1, 1}, + {-1, 0, 0, 0}, {-1, 0, 0, 1}, {-1, 0, 1, 0}, {-1, 0, 1, 1}, + {-1, 1, 0, 0}, {-1, 1, 0, 1}, {-1, 1, 1, 0}, {-1, 1, 1, 1} + }; + + int step, nib; + + /* loop over all possible steps */ + for (step = 0; step <= 48; step++) + { + /* compute the step value */ + int stepval = floor (16.0 * pow (11.0 / 10.0, (double)step)); + + /* loop over all nibbles and compute the difference */ + for (nib = 0; nib < 16; nib++) + { + m_diff_lookup[step*16 + nib] = nbl2bit[nib][0] * + (stepval * nbl2bit[nib][1] + + stepval/2 * nbl2bit[nib][2] + + stepval/4 * nbl2bit[nib][3] + + stepval/8); + } + } +} + +/* timer callback at VCLK low edge on MSM5205 (at rising edge on MSM6585) */ +TIMER_CALLBACK_MEMBER( msm5205_device::vclk_callback ) +{ + int val; + int new_signal; + + /* callback user handler and latch next data */ + if (!m_vclk_cb.isnull()) + m_vclk_cb(1); + + /* reset check at last hiedge of VCLK */ + if (m_reset) + { + new_signal = 0; + m_step = 0; + } + else + { + /* update signal */ + /* !! MSM5205 has internal 12bit decoding, signal width is 0 to 8191 !! */ + val = m_data; + new_signal = m_signal + m_diff_lookup[m_step * 16 + (val & 15)]; + + if (new_signal > 2047) new_signal = 2047; + else if (new_signal < -2048) new_signal = -2048; + + m_step += index_shift[val & 7]; + + if (m_step > 48) m_step = 48; + else if (m_step < 0) m_step = 0; + } + + /* update when signal changed */ + if( m_signal != new_signal) + { + m_stream->update(); + m_signal = new_signal; + } +} + + + +/* + * Handle an update of the vclk status of a chip (1 is reset ON, 0 is reset OFF) + * This function can use selector = MSM5205_SEX only + */ +void msm5205_device::vclk_w(int vclk) +{ + if (m_prescaler != 0) + logerror("error: msm5205_vclk_w() called with chip = '%s', but VCLK selected master mode\n", this->device().tag()); + else + { + if (m_vclk != vclk) + { + m_vclk = vclk; + if (!vclk) + vclk_callback(this, 0); + } + } +} + +/* + * Handle an update of the reset status of a chip (1 is reset ON, 0 is reset OFF) + */ + +void msm5205_device::reset_w(int reset) +{ + m_reset = reset; +} + +/* + * Handle an update of the data to the chip + */ + +void msm5205_device::data_w(int data) +{ + if (m_bitwidth == 4) + m_data = data & 0x0f; + else + m_data = (data & 0x07) << 1; /* unknown */ +} + +/* + * Handle a change of the selector + */ + +void msm5205_device::playmode_w(int select) +{ + static const int prescaler_table[2][4] = + { + { 96, 48, 64, 0}, + {160, 40, 80, 20} + }; + int prescaler = prescaler_table[select >> 3 & 1][select & 3]; + int bitwidth = (select & 4) ? 4 : 3; + + if (m_prescaler != prescaler) + { + m_stream->update(); + + m_prescaler = prescaler; + + /* timer set */ + if (prescaler) + { + attotime period = attotime::from_hz(m_mod_clock) * prescaler; + m_timer->adjust(period, 0, period); + } + else + m_timer->adjust(attotime::never); + } + + if (m_bitwidth != bitwidth) + { + m_stream->update(); + m_bitwidth = bitwidth; + } +} + + +void msm5205_device::set_volume(int volume) +{ + m_stream->set_output_gain(0,volume / 100.0); +} + +void msm5205_device::change_clock_w(INT32 clock) +{ + attotime period; + + m_mod_clock = clock; + + period = attotime::from_hz(m_mod_clock) * m_prescaler; + m_timer->adjust(period, 0, period); +} + + +//------------------------------------------------- +// sound_stream_update - handle a stream update +//------------------------------------------------- + +void msm5205_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + stream_sample_t *buffer = outputs[0]; + + /* if this voice is active */ + if(m_signal) + { + short val = m_signal * 16; + while (samples) + { + *buffer++ = val; + samples--; + } + } + else + memset(buffer, 0, samples * sizeof(*buffer)); +} + + +//------------------------------------------------- +// sound_stream_update - handle a stream update +//------------------------------------------------- + +void msm6585_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + // should this be different? + msm5205_device::sound_stream_update(stream, inputs, outputs,samples); +} diff --git a/src/devices/sound/msm5205.h b/src/devices/sound/msm5205.h new file mode 100644 index 00000000000..ab3b4219df2 --- /dev/null +++ b/src/devices/sound/msm5205.h @@ -0,0 +1,109 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +#pragma once + +#ifndef __MSM5205_H__ +#define __MSM5205_H__ + +/* an interface for the MSM5205 and similar chips */ + +/* prescaler selector defines */ +/* MSM5205 default master clock is 384KHz */ +#define MSM5205_S96_3B 0 /* prescaler 1/96(4KHz) , data 3bit */ +#define MSM5205_S48_3B 1 /* prescaler 1/48(8KHz) , data 3bit */ +#define MSM5205_S64_3B 2 /* prescaler 1/64(6KHz) , data 3bit */ +#define MSM5205_SEX_3B 3 /* VCLK slave mode , data 3bit */ +#define MSM5205_S96_4B 4 /* prescaler 1/96(4KHz) , data 4bit */ +#define MSM5205_S48_4B 5 /* prescaler 1/48(8KHz) , data 4bit */ +#define MSM5205_S64_4B 6 /* prescaler 1/64(6KHz) , data 4bit */ +#define MSM5205_SEX_4B 7 /* VCLK slave mode , data 4bit */ + +/* MSM6585 default master clock is 640KHz */ +#define MSM6585_S160 (4+8) /* prescaler 1/160(4KHz), data 4bit */ +#define MSM6585_S40 (5+8) /* prescaler 1/40(16KHz), data 4bit */ +#define MSM6585_S80 (6+8) /* prescaler 1/80 (8KHz), data 4bit */ +#define MSM6585_S20 (7+8) /* prescaler 1/20(32KHz), data 4bit */ + + +#define MCFG_MSM5205_PRESCALER_SELECTOR(_select) \ + msm5205_device::set_prescaler_selector(*device, _select); + +#define MCFG_MSM5205_VCLK_CB(_devcb) \ + devcb = &msm5205_device::set_vclk_callback(*device, DEVCB_##_devcb); + + +#define MCFG_MSM6585_PRESCALER_SELECTOR(_select) \ + msm6585_device::set_prescaler_selector(*device, _select); + +#define MCFG_MSM6585_VCLK_CB(_devcb) \ + devcb = &msm6585_device::set_vclk_callback(*device, DEVCB_##_devcb); + + +class msm5205_device : public device_t, + public device_sound_interface +{ +public: + msm5205_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + msm5205_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + ~msm5205_device() {} + + static void set_prescaler_selector(device_t &device, int select) { downcast(device).m_select = select; } + template static devcb_base &set_vclk_callback(device_t &device, _Object object) { return downcast(device).m_vclk_cb.set_callback(object); } + + // reset signal should keep for 2cycle of VCLK + void reset_w(int reset); + // adpcmata is latched after vclk_interrupt callback + void data_w(int data); + // VCLK slave mode option + // if VCLK and reset or data is changed at the same time, + // call vclk_w after data_w and reset_w. + void vclk_w(int vclk); + // option , selected pin seletor + void playmode_w(int select); + + void set_volume(int volume); + void change_clock_w(INT32 clock); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + TIMER_CALLBACK_MEMBER(vclk_callback); + + // sound stream update overrides + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + + void compute_tables(); + + // internal state + sound_stream * m_stream; /* number of stream system */ + INT32 m_mod_clock; /* clock rate */ + emu_timer *m_timer; /* VCLK callback timer */ + INT32 m_data; /* next adpcm data */ + INT32 m_vclk; /* vclk signal (external mode) */ + INT32 m_reset; /* reset pin signal */ + INT32 m_prescaler; /* prescaler selector S1 and S2 */ + INT32 m_bitwidth; /* bit width selector -3B/4B */ + INT32 m_signal; /* current ADPCM signal */ + INT32 m_step; /* current ADPCM step */ + int m_diff_lookup[49*16]; + int m_select; + devcb_write_line m_vclk_cb; +}; + +extern const device_type MSM5205; + +class msm6585_device : public msm5205_device +{ +public: + msm6585_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // sound stream update overrides + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); +}; + +extern const device_type MSM6585; + + +#endif /* __MSM5205_H__ */ diff --git a/src/devices/sound/msm5232.c b/src/devices/sound/msm5232.c new file mode 100644 index 00000000000..6bd36aac09e --- /dev/null +++ b/src/devices/sound/msm5232.c @@ -0,0 +1,802 @@ +// license:??? +// copyright-holders:Jarek Burczynski, Hiromitsu Shioya +#include "emu.h" + +#include "msm5232.h" + +#define CLOCK_RATE_DIVIDER 16 + +/* + OKI MSM5232RS + 8 channel tone generator +*/ + +const device_type MSM5232 = &device_creator; + +msm5232_device::msm5232_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, MSM5232, "MSM5232", tag, owner, clock, "msm5232", __FILE__), + device_sound_interface(mconfig, *this), + m_gate_handler_cb(*this) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void msm5232_device::device_start() +{ + int rate = clock()/CLOCK_RATE_DIVIDER; + int voicenum; + + m_gate_handler_cb.resolve(); + + init(clock(), rate); + + m_stream = machine().sound().stream_alloc(*this, 0, 11, rate); + + /* register with the save state system */ + machine().save().register_postload(save_prepost_delegate(FUNC(msm5232_device::postload), this)); + save_item(NAME(m_EN_out16)); + save_item(NAME(m_EN_out8)); + save_item(NAME(m_EN_out4)); + save_item(NAME(m_EN_out2)); + save_item(NAME(m_noise_cnt)); + save_item(NAME(m_noise_rng)); + save_item(NAME(m_noise_clocks)); + save_item(NAME(m_control1)); + save_item(NAME(m_control2)); + save_item(NAME(m_gate)); + save_item(NAME(m_chip_clock)); + save_item(NAME(m_rate)); + + /* register voice-specific data for save states */ + for (voicenum = 0; voicenum < 8; voicenum++) + { + VOICE *voice = &m_voi[voicenum]; + + save_item(NAME(voice->mode), voicenum); + save_item(NAME(voice->TG_count_period), voicenum); + save_item(NAME(voice->TG_cnt), voicenum); + save_item(NAME(voice->TG_out16), voicenum); + save_item(NAME(voice->TG_out8), voicenum); + save_item(NAME(voice->TG_out4), voicenum); + save_item(NAME(voice->TG_out2), voicenum); + save_item(NAME(voice->egvol), voicenum); + save_item(NAME(voice->eg_sect), voicenum); + save_item(NAME(voice->counter), voicenum); + save_item(NAME(voice->eg), voicenum); + save_item(NAME(voice->eg_arm), voicenum); + save_item(NAME(voice->ar_rate), voicenum); + save_item(NAME(voice->dr_rate), voicenum); + save_item(NAME(voice->pitch), voicenum); + save_item(NAME(voice->GF), voicenum); + } +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void msm5232_device::device_reset() +{ + int i; + + for (i=0; i<8; i++) + { + write(machine().driver_data()->generic_space(),i,0x80); + write(machine().driver_data()->generic_space(),i,0x00); + } + m_noise_cnt = 0; + m_noise_rng = 1; + m_noise_clocks = 0; + + m_control1 = 0; + m_EN_out16[0] = 0; + m_EN_out8[0] = 0; + m_EN_out4[0] = 0; + m_EN_out2[0] = 0; + + m_control2 = 0; + m_EN_out16[1] = 0; + m_EN_out8[1] = 0; + m_EN_out4[1] = 0; + m_EN_out2[1] = 0; + + gate_update(); +} + +//------------------------------------------------- +// device_stop - device-specific stop +//------------------------------------------------- + +void msm5232_device::device_stop() +{ + #ifdef SAVE_SAMPLE + fclose(sample[8]); +#endif +#ifdef SAVE_SEPARATE_CHANNELS + fclose(sample[0]); + fclose(sample[1]); + fclose(sample[2]); + fclose(sample[3]); + fclose(sample[4]); + fclose(sample[5]); + fclose(sample[6]); + fclose(sample[7]); +#endif +} + +void msm5232_device::static_set_capacitors(device_t &device, double cap1, double cap2, double cap3, double cap4, double cap5, double cap6, double cap7, double cap8) +{ + msm5232_device &msm = downcast(device); + msm.m_external_capacity[0] = cap1; + msm.m_external_capacity[1] = cap2; + msm.m_external_capacity[2] = cap3; + msm.m_external_capacity[3] = cap4; + msm.m_external_capacity[4] = cap5; + msm.m_external_capacity[5] = cap6; + msm.m_external_capacity[6] = cap7; + msm.m_external_capacity[7] = cap8; +} + +/* Default chip clock is 2119040 Hz */ +/* At this clock chip generates exactly 440.0 Hz signal on 8' output when pitch data=0x21 */ + + +/* ROM table to convert from pitch data into data for programmable counter and binary counter */ +/* Chip has 88x12bits ROM (addressing (in hex) from 0x00 to 0x57) */ +#define ROM(counter,bindiv) (counter|(bindiv<<9)) + +static const UINT16 MSM5232_ROM[88]={ +/* higher values are Programmable Counter data (9 bits) */ +/* lesser values are Binary Counter shift data (3 bits) */ + +/* 0 */ ROM (506, 7), + +/* 1 */ ROM (478, 7),/* 2 */ ROM (451, 7),/* 3 */ ROM (426, 7),/* 4 */ ROM (402, 7), +/* 5 */ ROM (379, 7),/* 6 */ ROM (358, 7),/* 7 */ ROM (338, 7),/* 8 */ ROM (319, 7), +/* 9 */ ROM (301, 7),/* A */ ROM (284, 7),/* B */ ROM (268, 7),/* C */ ROM (253, 7), + +/* D */ ROM (478, 6),/* E */ ROM (451, 6),/* F */ ROM (426, 6),/*10 */ ROM (402, 6), +/*11 */ ROM (379, 6),/*12 */ ROM (358, 6),/*13 */ ROM (338, 6),/*14 */ ROM (319, 6), +/*15 */ ROM (301, 6),/*16 */ ROM (284, 6),/*17 */ ROM (268, 6),/*18 */ ROM (253, 6), + +/*19 */ ROM (478, 5),/*1A */ ROM (451, 5),/*1B */ ROM (426, 5),/*1C */ ROM (402, 5), +/*1D */ ROM (379, 5),/*1E */ ROM (358, 5),/*1F */ ROM (338, 5),/*20 */ ROM (319, 5), +/*21 */ ROM (301, 5),/*22 */ ROM (284, 5),/*23 */ ROM (268, 5),/*24 */ ROM (253, 5), + +/*25 */ ROM (478, 4),/*26 */ ROM (451, 4),/*27 */ ROM (426, 4),/*28 */ ROM (402, 4), +/*29 */ ROM (379, 4),/*2A */ ROM (358, 4),/*2B */ ROM (338, 4),/*2C */ ROM (319, 4), +/*2D */ ROM (301, 4),/*2E */ ROM (284, 4),/*2F */ ROM (268, 4),/*30 */ ROM (253, 4), + +/*31 */ ROM (478, 3),/*32 */ ROM (451, 3),/*33 */ ROM (426, 3),/*34 */ ROM (402, 3), +/*35 */ ROM (379, 3),/*36 */ ROM (358, 3),/*37 */ ROM (338, 3),/*38 */ ROM (319, 3), +/*39 */ ROM (301, 3),/*3A */ ROM (284, 3),/*3B */ ROM (268, 3),/*3C */ ROM (253, 3), + +/*3D */ ROM (478, 2),/*3E */ ROM (451, 2),/*3F */ ROM (426, 2),/*40 */ ROM (402, 2), +/*41 */ ROM (379, 2),/*42 */ ROM (358, 2),/*43 */ ROM (338, 2),/*44 */ ROM (319, 2), +/*45 */ ROM (301, 2),/*46 */ ROM (284, 2),/*47 */ ROM (268, 2),/*48 */ ROM (253, 2), + +/*49 */ ROM (478, 1),/*4A */ ROM (451, 1),/*4B */ ROM (426, 1),/*4C */ ROM (402, 1), +/*4D */ ROM (379, 1),/*4E */ ROM (358, 1),/*4F */ ROM (338, 1),/*50 */ ROM (319, 1), +/*51 */ ROM (301, 1),/*52 */ ROM (284, 1),/*53 */ ROM (268, 1),/*54 */ ROM (253, 1), + +/*55 */ ROM (253, 1),/*56 */ ROM (253, 1), + +/*57 */ ROM (13, 7) +}; +#undef ROM + + +#define STEP_SH (16) /* step calculations accuracy */ + + +/* save output as raw 16-bit sample */ +/* #define SAVE_SAMPLE */ +/* #define SAVE_SEPARATE_CHANNELS */ +#if defined SAVE_SAMPLE || defined SAVE_SEPARATE_CHANNELS +static FILE *sample[9]; +#endif + + + +/* + * resistance values are guesswork, default capacity is mentioned in the datasheets + * + * charges external capacitor (default is 0.39uF) via R51 + * in approx. 5*1400 * 0.39e-6 + * + * external capacitor is discharged through R52 + * in approx. 5*28750 * 0.39e-6 + */ + + +#define R51 1400 /* charge resistance */ +#define R52 28750 /* discharge resistance */ + +#if 0 +/* + C24 = external capacity + + osd_printf_debug("Time constant T=R*C =%f sec.\n",R51*C24); + osd_printf_debug("Cap fully charged after 5T=%f sec (sample=%f). Level=%f\n",(R51*C24)*5,(R51*C24)*5*sample_rate , VMAX*0.99326 ); + osd_printf_debug("Cap charged after 5T=%f sec (sample=%f). Level=%20.16f\n",(R51*C24)*5,(R51*C24)*5*sample_rate , + VMAX*(1.0-pow(2.718,-0.0748/(R51*C24))) ); +*/ +#endif + + + + +void msm5232_device::init_tables() +{ + int i; + double scale; + + /* sample rate = chip clock !!! But : */ + /* highest possible frequency is chipclock/13/16 (pitch data=0x57) */ + /* at 2MHz : 2000000/13/16 = 9615 Hz */ + + i = ((double)(1< 0x0d) + return; + + m_stream->update (); + + if (offset < 0x08) /* pitch */ + { + int ch = offset&7; + + m_voi[ch].GF = ((data&0x80)>>7); + if (ch == 7) + gate_update(); + + if(data&0x80) + { + if(data >= 0xd8) + { + /*if ((data&0x7f) != 0x5f) logerror("MSM5232: WRONG PITCH CODE = %2x\n",data&0x7f);*/ + m_voi[ch].mode = 1; /* noise mode */ + m_voi[ch].eg_sect = 0; /* Key On */ + } + else + { + if ( m_voi[ch].pitch != (data&0x7f) ) + { + int n; + UINT16 pg; + + m_voi[ch].pitch = data&0x7f; + + pg = MSM5232_ROM[ data&0x7f ]; + + m_voi[ch].TG_count_period = (pg & 0x1ff) * m_UpdateStep / 2; + + n = (pg>>9) & 7; /* n = bit number for 16' output */ + m_voi[ch].TG_out16 = 1<0)? n-1: 0; + m_voi[ch].TG_out8 = 1<0)? n-1: 0; + m_voi[ch].TG_out4 = 1<0)? n-1: 0; + m_voi[ch].TG_out2 = 1< go to release */ + else /* arm = 1 */ + m_voi[ch].eg_sect = 1; /* Key Off -> go to decay */ + } + } + else + { + int i; + switch(offset) + { + case 0x08: /* group1 attack */ + for (i=0; i<4; i++) + m_voi[i].ar_rate = m_ar_tbl[data&0x7] * m_external_capacity[i]; + break; + + case 0x09: /* group2 attack */ + for (i=0; i<4; i++) + m_voi[i+4].ar_rate = m_ar_tbl[data&0x7] * m_external_capacity[i+4]; + break; + + case 0x0a: /* group1 decay */ + for (i=0; i<4; i++) + m_voi[i].dr_rate = m_dr_tbl[data&0xf] * m_external_capacity[i]; + break; + + case 0x0b: /* group2 decay */ + for (i=0; i<4; i++) + m_voi[i+4].dr_rate = m_dr_tbl[data&0xf] * m_external_capacity[i+4]; + break; + + case 0x0c: /* group1 control */ + + /*if (m_control1 != data) + logerror("msm5232: control1 ctrl=%x OE=%x\n", data&0xf0, data&0x0f);*/ + + /*if (data & 0x10) + popmessage("msm5232: control1 ctrl=%2x\n", data);*/ + + m_control1 = data; + + for (i=0; i<4; i++) + m_voi[i].eg_arm = data&0x10; + + m_EN_out16[0] = (data&1) ? ~0:0; + m_EN_out8[0] = (data&2) ? ~0:0; + m_EN_out4[0] = (data&4) ? ~0:0; + m_EN_out2[0] = (data&8) ? ~0:0; + + break; + + case 0x0d: /* group2 control */ + + /*if (m_control2 != data) + logerror("msm5232: control2 ctrl=%x OE=%x\n", data&0xf0, data&0x0f);*/ + + /*if (data & 0x10) + popmessage("msm5232: control2 ctrl=%2x\n", data);*/ + + m_control2 = data; + gate_update(); + + for (i=0; i<4; i++) + m_voi[i+4].eg_arm = data&0x10; + + m_EN_out16[1] = (data&1) ? ~0:0; + m_EN_out8[1] = (data&2) ? ~0:0; + m_EN_out4[1] = (data&4) ? ~0:0; + m_EN_out2[1] = (data&8) ? ~0:0; + + break; + } + } +} + + + +#define VMIN 0 +#define VMAX 32768 + + +void msm5232_device::EG_voices_advance() +{ + VOICE *voi = &m_voi[0]; + int samplerate = m_rate; + int i; + + i = 8; + do + { + switch(voi->eg_sect) + { + case 0: /* attack */ + + /* capacitor charge */ + if (voi->eg < VMAX) + { + voi->counter -= (int)((VMAX - voi->eg) / voi->ar_rate); + if ( voi->counter <= 0 ) + { + int n = -voi->counter / samplerate + 1; + voi->counter += n * samplerate; + if ( (voi->eg += n) > VMAX ) + voi->eg = VMAX; + } + } + + /* when ARM=0, EG switches to decay as soon as cap is charged to VT (EG inversion voltage; about 80% of MAX) */ + if (!voi->eg_arm) + { + if(voi->eg >= VMAX * 80/100 ) + { + voi->eg_sect = 1; + } + } + else + /* ARM=1 */ + { + /* when ARM=1, EG stays at maximum until key off */ + } + + voi->egvol = voi->eg / 16; /*32768/16 = 2048 max*/ + + break; + + case 1: /* decay */ + + /* capacitor discharge */ + if (voi->eg > VMIN) + { + voi->counter -= (int)((voi->eg - VMIN) / voi->dr_rate); + if ( voi->counter <= 0 ) + { + int n = -voi->counter / samplerate + 1; + voi->counter += n * samplerate; + if ( (voi->eg -= n) < VMIN ) + voi->eg = VMIN; + } + } + else /* voi->eg <= VMIN */ + { + voi->eg_sect =-1; + } + + voi->egvol = voi->eg / 16; /*32768/16 = 2048 max*/ + + break; + + case 2: /* release */ + + /* capacitor discharge */ + if (voi->eg > VMIN) + { + voi->counter -= (int)((voi->eg - VMIN) / voi->rr_rate); + if ( voi->counter <= 0 ) + { + int n = -voi->counter / samplerate + 1; + voi->counter += n * samplerate; + if ( (voi->eg -= n) < VMIN ) + voi->eg = VMIN; + } + } + else /* voi->eg <= VMIN */ + { + voi->eg_sect =-1; + } + + voi->egvol = voi->eg / 16; /*32768/16 = 2048 max*/ + + break; + + default: + break; + } + + voi++; + i--; + } while (i>0); + +} + +static int o2,o4,o8,o16,solo8,solo16; + +void msm5232_device::TG_group_advance(int groupidx) +{ + VOICE *voi = &m_voi[groupidx*4]; + int i; + + o2 = o4 = o8 = o16 = solo8 = solo16 = 0; + + i=4; + do + { + int out2, out4, out8, out16; + + out2 = out4 = out8 = out16 = 0; + + if (voi->mode==0) /* generate square tone */ + { + int left = 1<TG_cnt&voi->TG_out16) out16+=voi->TG_count; + if (voi->TG_cnt&voi->TG_out8) out8 +=voi->TG_count; + if (voi->TG_cnt&voi->TG_out4) out4 +=voi->TG_count; + if (voi->TG_cnt&voi->TG_out2) out2 +=voi->TG_count; + + voi->TG_count -= nextevent; + + while (voi->TG_count <= 0) + { + voi->TG_count += voi->TG_count_period; + voi->TG_cnt++; + if (voi->TG_cnt&voi->TG_out16) out16+=voi->TG_count_period; + if (voi->TG_cnt&voi->TG_out8 ) out8 +=voi->TG_count_period; + if (voi->TG_cnt&voi->TG_out4 ) out4 +=voi->TG_count_period; + if (voi->TG_cnt&voi->TG_out2 ) out2 +=voi->TG_count_period; + + if (voi->TG_count > 0) + break; + + voi->TG_count += voi->TG_count_period; + voi->TG_cnt++; + if (voi->TG_cnt&voi->TG_out16) out16+=voi->TG_count_period; + if (voi->TG_cnt&voi->TG_out8 ) out8 +=voi->TG_count_period; + if (voi->TG_cnt&voi->TG_out4 ) out4 +=voi->TG_count_period; + if (voi->TG_cnt&voi->TG_out2 ) out2 +=voi->TG_count_period; + } + if (voi->TG_cnt&voi->TG_out16) out16-=voi->TG_count; + if (voi->TG_cnt&voi->TG_out8 ) out8 -=voi->TG_count; + if (voi->TG_cnt&voi->TG_out4 ) out4 -=voi->TG_count; + if (voi->TG_cnt&voi->TG_out2 ) out2 -=voi->TG_count; + + left -=nextevent; + + }while (left>0); + } + else /* generate noise */ + { + if (m_noise_clocks&8) out16+=(1<egvol) >> STEP_SH; + o8 += ( (out8 -(1<<(STEP_SH-1))) * voi->egvol) >> STEP_SH; + o4 += ( (out4 -(1<<(STEP_SH-1))) * voi->egvol) >> STEP_SH; + o2 += ( (out2 -(1<<(STEP_SH-1))) * voi->egvol) >> STEP_SH; + + if (i == 1 && groupidx == 1) + { + solo16 += ( (out16-(1<<(STEP_SH-1))) << 11) >> STEP_SH; + solo8 += ( (out8 -(1<<(STEP_SH-1))) << 11) >> STEP_SH; + } + + voi++; + i--; + }while (i>0); + + /* cut off disabled output lines */ + o16 &= m_EN_out16[groupidx]; + o8 &= m_EN_out8 [groupidx]; + o4 &= m_EN_out4 [groupidx]; + o2 &= m_EN_out2 [groupidx]; +} + + +/* macro saves feet data to mono file */ +#ifdef SAVE_SEPARATE_CHANNELS + #define SAVE_SINGLE_CHANNEL(j,val) \ + { signed int pom= val; \ + if (pom > 32767) pom = 32767; else if (pom < -32768) pom = -32768; \ + fputc((unsigned short)pom&0xff,sample[j]); \ + fputc(((unsigned short)pom>>8)&0xff,sample[j]); } +#else + #define SAVE_SINGLE_CHANNEL(j,val) +#endif + +/* first macro saves all 8 feet outputs to mixed (mono) file */ +/* second macro saves one group into left and the other in right channel */ +#if 1 /*MONO*/ + #ifdef SAVE_SAMPLE + #define SAVE_ALL_CHANNELS \ + { signed int pom = buf1[i] + buf2[i]; \ + fputc((unsigned short)pom&0xff,sample[8]); \ + fputc(((unsigned short)pom>>8)&0xff,sample[8]); \ + } + #else + #define SAVE_ALL_CHANNELS + #endif +#else /*STEREO*/ + #ifdef SAVE_SAMPLE + #define SAVE_ALL_CHANNELS \ + { signed int pom = buf1[i]; \ + fputc((unsigned short)pom&0xff,sample[8]); \ + fputc(((unsigned short)pom>>8)&0xff,sample[8]); \ + pom = buf2[i]; \ + fputc((unsigned short)pom&0xff,sample[8]); \ + fputc(((unsigned short)pom>>8)&0xff,sample[8]); \ + } + #else + #define SAVE_ALL_CHANNELS + #endif +#endif + + +/* MAME Interface */ +void msm5232_device::postload() +{ + init_tables(); +} + +void msm5232_device::set_clock(int clock) +{ + if (m_chip_clock != clock) + { + m_stream->update (); + m_chip_clock = clock; + m_rate = clock/CLOCK_RATE_DIVIDER; + init_tables(); + m_stream->set_sample_rate(m_rate); + } +} + + +//------------------------------------------------- +// sound_stream_update - handle a stream update +//------------------------------------------------- + +void msm5232_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + stream_sample_t *buf1 = outputs[0]; + stream_sample_t *buf2 = outputs[1]; + stream_sample_t *buf3 = outputs[2]; + stream_sample_t *buf4 = outputs[3]; + stream_sample_t *buf5 = outputs[4]; + stream_sample_t *buf6 = outputs[5]; + stream_sample_t *buf7 = outputs[6]; + stream_sample_t *buf8 = outputs[7]; + stream_sample_t *bufsolo1 = outputs[8]; + stream_sample_t *bufsolo2 = outputs[9]; + stream_sample_t *bufnoise = outputs[10]; + int i; + + for (i=0; i> STEP_SH; + m_noise_cnt &= ((1< 0) + { + int tmp = m_noise_rng & (1<<16); /* store current level */ + + if (m_noise_rng&1) + m_noise_rng ^= 0x24000; + m_noise_rng>>=1; + + if ( (m_noise_rng & (1<<16)) != tmp ) /* level change detect */ + m_noise_clocks++; + + cnt--; + } + } + + bufnoise[i] = (m_noise_rng & (1<<16)) ? 32767 : 0; + } +} diff --git a/src/devices/sound/msm5232.h b/src/devices/sound/msm5232.h new file mode 100644 index 00000000000..a7e30e72a57 --- /dev/null +++ b/src/devices/sound/msm5232.h @@ -0,0 +1,111 @@ +// license:??? +// copyright-holders:Jarek Burczynski, Hiromitsu Shioya +#pragma once + +#ifndef __MSM5232_H__ +#define __MSM5232_H__ + + +#define MCFG_MSM5232_SET_CAPACITORS(_a, _b, _c, _d, _e, _f, _g, _h) \ + msm5232_device::static_set_capacitors(*device, _a, _b, _c, _d, _e, _f, _g, _h); + +#define MCFG_MSM5232_GATE_HANDLER_CB(_devcb) \ + devcb = &msm5232_device::set_gate_handler_callback(*device, DEVCB_##_devcb); + +struct VOICE { + UINT8 mode; + + int TG_count_period; + int TG_count; + + UINT8 TG_cnt; /* 7 bits binary counter (frequency output) */ + UINT8 TG_out16; /* bit number (of TG_cnt) for 16' output */ + UINT8 TG_out8; /* bit number (of TG_cnt) for 8' output */ + UINT8 TG_out4; /* bit number (of TG_cnt) for 4' output */ + UINT8 TG_out2; /* bit number (of TG_cnt) for 2' output */ + + int egvol; + int eg_sect; + int counter; + int eg; + + UINT8 eg_arm; /* attack/release mode */ + + double ar_rate; + double dr_rate; + double rr_rate; + + int pitch; /* current pitch data */ + + int GF; +}; + + +class msm5232_device : public device_t, + public device_sound_interface +{ +public: + msm5232_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + ~msm5232_device() {} + + static void static_set_capacitors(device_t &device, double cap1, double cap2, double cap3, double cap4, double cap5, double cap6, double cap7, double cap8); + template static devcb_base &set_gate_handler_callback(device_t &device, _Object object) { return downcast(device).m_gate_handler_cb.set_callback(object); } + + DECLARE_WRITE8_MEMBER( write ); + void set_clock(int clock); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_stop(); + virtual void device_reset(); + + // sound stream update overrides + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + + private: + // internal state + sound_stream *m_stream; + + VOICE m_voi[8]; + + UINT32 m_EN_out16[2]; /* enable 16' output masks for both groups (0-disabled ; ~0 -enabled) */ + UINT32 m_EN_out8[2]; /* enable 8' output masks */ + UINT32 m_EN_out4[2]; /* enable 4' output masks */ + UINT32 m_EN_out2[2]; /* enable 2' output masks */ + + int m_noise_cnt; + int m_noise_step; + int m_noise_rng; + int m_noise_clocks; /* number of the noise_rng (output) level changes */ + + unsigned int m_UpdateStep; + + /* rate tables */ + double m_ar_tbl[8]; + double m_dr_tbl[16]; + + UINT8 m_control1; + UINT8 m_control2; + + int m_gate; /* current state of the GATE output */ + + int m_chip_clock; /* chip clock in Hz */ + int m_rate; /* sample rate in Hz */ + + double m_external_capacity[8]; /* in Farads, eg 0.39e-6 = 0.36 uF (microFarads) */ + devcb_write_line m_gate_handler_cb;/* callback called when the GATE output pin changes state */ + + void init_tables(); + void init_voice(int i); + void gate_update(); + void init(int clock, int rate); + void EG_voices_advance(); + void TG_group_advance(int groupidx); + void postload(); +}; + +extern const device_type MSM5232; + + +#endif /* __MSM5232_H__ */ diff --git a/src/devices/sound/multipcm.c b/src/devices/sound/multipcm.c new file mode 100644 index 00000000000..69c164bad2c --- /dev/null +++ b/src/devices/sound/multipcm.c @@ -0,0 +1,658 @@ +// license:BSD-3-Clause +// copyright-holders:Miguel Angel Horna +/* + * Sega System 32 Multi/Model 1/Model 2 custom PCM chip (315-5560) emulation. + * + * by Miguel Angel Horna (ElSemi) for Model 2 Emulator and MAME. + * Information by R. Belmont and the YMF278B (OPL4) manual. + * + * voice registers: + * 0: Pan + * 1: Index of sample + * 2: LSB of pitch (low 2 bits seem unused so) + * 3: MSB of pitch (ooooppppppppppxx) (o=octave (4 bit signed), p=pitch (10 bits), x=unused? + * 4: voice control: top bit = 1 for key on, 0 for key off + * 5: bit 0: 0: interpolate volume changes, 1: direct set volume, + bits 1-7 = volume attenuate (0=max, 7f=min) + * 6: LFO frequency + Phase LFO depth + * 7: Amplitude LFO size + * + * The first sample ROM contains a variable length table with 12 + * bytes per instrument/sample. This is very similar to the YMF278B. + * + * The first 3 bytes are the offset into the file (big endian). + * The next 2 are the loop start offset into the file (big endian) + * The next 2 are the 2's complement of the total sample size (big endian) + * The next byte is LFO freq + depth (copied to reg 6 ?) + * The next 3 are envelope params (Attack, Decay1 and 2, sustain level, release, Key Rate Scaling) + * The next byte is Amplitude LFO size (copied to reg 7 ?) + * + * TODO + * - The YM278B manual states that the chip supports 512 instruments. The MultiPCM probably supports them + * too but the high bit position is unknown (probably reg 2 low bit). Any game use more than 256? + * + */ + +#include "emu.h" +#include "multipcm.h" + +//???? +#define MULTIPCM_CLOCKDIV (180.0f) + +ALLOW_SAVE_TYPE(STATE); // allow save_item on a non-fundamental type + +static signed int LPANTABLE[0x800],RPANTABLE[0x800]; + +#define FIX(v) ((UINT32) ((float) (1<EG.state) + { + case ATTACK: + slot->EG.volume+=slot->EG.AR; + if(slot->EG.volume>=(0x3ff<EG.state=DECAY1; + if(slot->EG.D1R>=(0x400<EG.state=DECAY2; + slot->EG.volume=0x3ff<EG.volume-=slot->EG.D1R; + if(slot->EG.volume<=0) + slot->EG.volume=0; + if(slot->EG.volume>>EG_SHIFT<=(slot->EG.DL<<(10-4))) + slot->EG.state=DECAY2; + break; + case DECAY2: + slot->EG.volume-=slot->EG.D2R; + if(slot->EG.volume<=0) + slot->EG.volume=0; + break; + case RELEASE: + slot->EG.volume-=slot->EG.RR; + if(slot->EG.volume<=0) + { + slot->EG.volume=0; + slot->Playing=0; + } + break; + default: + return 1<EG.volume>>EG_SHIFT]; +} + +static unsigned int Get_RATE(unsigned int *Steps,unsigned int rate,unsigned int val) +{ + int r=4*val+rate; + if(val==0) + return Steps[0]; + if(val==0xf) + return Steps[0x3f]; + if(r>0x3f) + r=0x3f; + return Steps[r]; +} + +void multipcm_device::EG_Calc(SLOT *slot) +{ + int octave=((slot->Regs[3]>>4)-1)&0xf; + int rate; + if(octave&8) octave=octave-16; + if(slot->Sample->KRS!=0xf) + rate=(octave+slot->Sample->KRS)*2+((slot->Regs[3]>>3)&1); + else + rate=0; + + slot->EG.AR=Get_RATE(m_ARStep,rate,slot->Sample->AR); + slot->EG.D1R=Get_RATE(m_DRStep,rate,slot->Sample->DR1); + slot->EG.D2R=Get_RATE(m_DRStep,rate,slot->Sample->DR2); + slot->EG.RR=Get_RATE(m_DRStep,rate,slot->Sample->RR); + slot->EG.DL=0xf-slot->Sample->DL; + +} + +/***************************** + LFO SECTION +*****************************/ + +#define LFO_SHIFT 8 + + +#define LFIX(v) ((unsigned int) ((float) (1<phase+=LFO->phase_step; + p=LFO->table[(LFO->phase>>LFO_SHIFT)&0xff]; + p=LFO->scale[p+128]; + return p<<(SHIFT-LFO_SHIFT); +} + +INLINE signed int ALFO_Step(LFO_t *LFO) +{ + int p; + LFO->phase+=LFO->phase_step; + p=LFO->table[(LFO->phase>>LFO_SHIFT)&0xff]; + p=LFO->scale[p]; + return p<<(SHIFT-LFO_SHIFT); +} + +void multipcm_device::LFO_ComputeStep(LFO_t *LFO,UINT32 LFOF,UINT32 LFOS,int ALFO) +{ + float step=(float) LFOFreq[LFOF]*256.0f/(float) m_Rate; + LFO->phase_step=(unsigned int) ((float) (1<table=ALFO_TRI; + LFO->scale=ASCALES[LFOS]; + } + else + { + LFO->table=PLFO_TRI; + LFO->scale=PSCALES[LFOS]; + } +} + + + +void multipcm_device::WriteSlot(SLOT *slot,int reg,unsigned char data) +{ + slot->Regs[reg]=data; + + switch(reg) + { + case 0: //PANPOT + slot->Pan=(data>>4)&0xf; + break; + case 1: //Sample + //according to YMF278 sample write causes some base params written to the regs (envelope+lfos) + //the game should never change the sample while playing. + { + Sample_t *Sample=m_Samples+slot->Regs[1]; + WriteSlot(slot,6,Sample->LFOVIB); + WriteSlot(slot,7,Sample->AM); + } + break; + case 2: //Pitch + case 3: + { + unsigned int oct=((slot->Regs[3]>>4)-1)&0xf; + unsigned int pitch=((slot->Regs[3]&0xf)<<6)|(slot->Regs[2]>>2); + pitch=m_FNS_Table[pitch]; + if(oct&0x8) + pitch>>=(16-oct); + else + pitch<<=oct; + slot->step=pitch/m_Rate; + } + break; + case 4: //KeyOn/Off (and more?) + { + if(data&0x80) //KeyOn + { + slot->Sample=m_Samples+slot->Regs[1]; + slot->Playing=1; + slot->Base=slot->Sample->Start; + slot->offset=0; + slot->Prev=0; + slot->TL=slot->DstTL<EG.state=ATTACK; + slot->EG.volume=0; + + if(slot->Base>=0x100000) + { + if(slot->Pan&8) + slot->Base=(slot->Base&0xfffff)|(m_BankL); + else + slot->Base=(slot->Base&0xfffff)|(m_BankR); + } + + } + else + { + if(slot->Playing) + { + if(slot->Sample->RR!=0xf) + slot->EG.state=RELEASE; + else + slot->Playing=0; + } + } + } + break; + case 5: //TL+Interpolation + { + slot->DstTL=(data>>1)&0x7f; + if(!(data&1)) //Interpolate TL + { + if((slot->TL>>SHIFT)>slot->DstTL) + slot->TLStep=TLSteps[0]; //decrease + else + slot->TLStep=TLSteps[1]; //increase + } + else + slot->TL=slot->DstTL<PLFO),(slot->Regs[6]>>3)&7,slot->Regs[6]&7,0); + LFO_ComputeStep(&(slot->ALFO),(slot->Regs[6]>>3)&7,slot->Regs[7]&7,1); + } + } + break; + case 7: //ALFO + { + if(data) + { + LFO_ComputeStep(&(slot->PLFO),(slot->Regs[6]>>3)&7,slot->Regs[6]&7,0); + LFO_ComputeStep(&(slot->ALFO),(slot->Regs[6]>>3)&7,slot->Regs[7]&7,1); + } + } + break; + } +} + +READ8_MEMBER( multipcm_device::read ) +{ + return 0; +} + + +WRITE8_MEMBER( multipcm_device::write ) +{ + switch(offset) + { + case 0: //Data write + WriteSlot(m_Slots+m_CurSlot,m_Address,data); + break; + case 1: + m_CurSlot=val2chan[data&0x1f]; + break; + + case 2: + m_Address=(data>7)?7:data; + break; + } +} + +/* MAME/M1 access functions */ + +void multipcm_device::set_bank(UINT32 leftoffs, UINT32 rightoffs) +{ + m_BankL = leftoffs; + m_BankR = rightoffs; +} + +const device_type MULTIPCM = &device_creator; + +// default address map +static ADDRESS_MAP_START( multipcm, AS_0, 8, multipcm_device ) + AM_RANGE(0x000000, 0x3fffff) AM_ROM +ADDRESS_MAP_END + +multipcm_device::multipcm_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, MULTIPCM, "Sega/Yamaha 315-5560", tag, owner, clock, "multipcm", __FILE__), + device_sound_interface(mconfig, *this), + device_memory_interface(mconfig, *this), + m_space_config("mpcm_samples", ENDIANNESS_LITTLE, 8, 24, 0, NULL), + m_stream(NULL), + //m_Samples(0x200), + //m_Slots[28], + m_CurSlot(0), + m_Address(0), + m_BankR(0), + m_BankL(0), + m_Rate(0) + //m_ARStep(0), + //m_DRStep(0), + //m_FNS_Table(0) +{ + m_address_map[0] = *ADDRESS_MAP_NAME(multipcm); +} + +//------------------------------------------------- +// memory_space_config - return a description of +// any address spaces owned by this device +//------------------------------------------------- + +const address_space_config *multipcm_device::memory_space_config(address_spacenum spacenum) const +{ + return (spacenum == 0) ? &m_space_config : NULL; +} + +//------------------------------------------------- +// device_config_complete - perform any +// operations now that the configuration is +// complete +//------------------------------------------------- + +void multipcm_device::device_config_complete() +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void multipcm_device::device_start() +{ + int i; + + // find our direct access + m_direct = &space().direct(); + + m_Rate=(float) clock() / MULTIPCM_CLOCKDIV; + + m_stream = machine().sound().stream_alloc(*this, 0, 2, m_Rate); + + //Volume+pan table + for(i=0;i<0x800;++i) + { + float SegaDB=0; + float TL; + float LPAN,RPAN; + + unsigned char iTL=i&0x7f; + unsigned char iPAN=(i>>7)&0xf; + + SegaDB=(float) iTL*(-24.0f)/(float) 0x40; + + TL=powf(10.0f,SegaDB/20.0f); + + + if(iPAN==0x8) + { + LPAN=RPAN=0.0; + } + else if(iPAN==0x0) + { + LPAN=RPAN=1.0; + } + else if(iPAN&0x8) + { + LPAN=1.0; + + iPAN=0x10-iPAN; + + SegaDB=(float) iPAN*(-12.0f)/(float) 0x4; + + RPAN=pow(10.0f,SegaDB/20.0f); + + if((iPAN&0x7)==7) + RPAN=0.0; + } + else + { + RPAN=1.0; + + SegaDB=(float) iPAN*(-12.0f)/(float) 0x4; + + LPAN=pow(10.0f,SegaDB/20.0f); + if((iPAN&0x7)==7) + LPAN=0.0; + } + + TL/=4.0f; + + LPANTABLE[i]=FIX((LPAN*TL)); + RPANTABLE[i]=FIX((RPAN*TL)); + } + + //Pitch steps + for(i=0;i<0x400;++i) + { + float fcent=m_Rate*(1024.0f+(float) i)/1024.0f; + m_FNS_Table[i]=(unsigned int ) ((float) (1<exponential ramps + for(i=0;i<0x400;++i) + { + float db=-(96.0f-(96.0f*(float) i/(float) 0x400)); + lin2expvol[i]=powf(10.0f,db/20.0f)*(float) (1<read_byte((i*12) + j); + } + + m_Samples[i].Start=(ptSample[0]<<16)|(ptSample[1]<<8)|(ptSample[2]<<0); + m_Samples[i].Loop=(ptSample[3]<<8)|(ptSample[4]<<0); + m_Samples[i].End=0xffff-((ptSample[5]<<8)|(ptSample[6]<<0)); + m_Samples[i].LFOVIB=ptSample[7]; + m_Samples[i].DR1=ptSample[8]&0xf; + m_Samples[i].AR=(ptSample[8]>>4)&0xf; + m_Samples[i].DR2=ptSample[9]&0xf; + m_Samples[i].DL=(ptSample[9]>>4)&0xf; + m_Samples[i].RR=ptSample[10]&0xf; + m_Samples[i].KRS=(ptSample[10]>>4)&0xf; + m_Samples[i].AM=ptSample[11]; + } + + save_item(NAME(m_CurSlot)); + save_item(NAME(m_Address)); + save_item(NAME(m_BankL)); + save_item(NAME(m_BankR)); + + for(i=0;i<28;++i) + { + m_Slots[i].Num=i; + m_Slots[i].Playing=0; + + save_item(NAME(m_Slots[i].Num), i); + save_item(NAME(m_Slots[i].Regs), i); + save_item(NAME(m_Slots[i].Playing), i); + save_item(NAME(m_Slots[i].Base), i); + save_item(NAME(m_Slots[i].offset), i); + save_item(NAME(m_Slots[i].step), i); + save_item(NAME(m_Slots[i].Pan), i); + save_item(NAME(m_Slots[i].TL), i); + save_item(NAME(m_Slots[i].DstTL), i); + save_item(NAME(m_Slots[i].TLStep), i); + save_item(NAME(m_Slots[i].Prev), i); + save_item(NAME(m_Slots[i].EG.volume), i); + save_item(NAME(m_Slots[i].EG.state), i); + save_item(NAME(m_Slots[i].EG.step), i); + save_item(NAME(m_Slots[i].EG.AR), i); + save_item(NAME(m_Slots[i].EG.D1R), i); + save_item(NAME(m_Slots[i].EG.D2R), i); + save_item(NAME(m_Slots[i].EG.RR), i); + save_item(NAME(m_Slots[i].EG.DL), i); + save_item(NAME(m_Slots[i].PLFO.phase), i); + save_item(NAME(m_Slots[i].PLFO.phase_step), i); + save_item(NAME(m_Slots[i].ALFO.phase), i); + save_item(NAME(m_Slots[i].ALFO.phase_step), i); + } + + LFO_Init(); +} + +//------------------------------------------------- +// sound_stream_update - handle a stream update +//------------------------------------------------- + +void multipcm_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + stream_sample_t *datap[2]; + int i,sl; + + datap[0] = outputs[0]; + datap[1] = outputs[1]; + + memset(datap[0], 0, sizeof(*datap[0])*samples); + memset(datap[1], 0, sizeof(*datap[1])*samples); + + for(i=0;iPlaying) + { + unsigned int vol=(slot->TL>>SHIFT)|(slot->Pan<<7); + unsigned int adr=slot->offset>>SHIFT; + signed int sample; + unsigned int step=slot->step; + signed int csample=(signed short) (m_direct->read_byte(slot->Base+adr)<<8); + signed int fpart=slot->offset&((1<Prev*((1<>SHIFT; + + if(slot->Regs[6]&7) //Vibrato enabled + { + step=step*PLFO_Step(&(slot->PLFO)); + step>>=SHIFT; + } + + slot->offset+=step; + if(slot->offset>=(slot->Sample->End<offset=slot->Sample->Loop<offset>>SHIFT)) + { + slot->Prev=csample; + } + + if((slot->TL>>SHIFT)!=slot->DstTL) + slot->TL+=slot->TLStep; + + if(slot->Regs[7]&7) //Tremolo enabled + { + sample=sample*ALFO_Step(&(slot->ALFO)); + sample>>=SHIFT; + } + + sample=(sample*EG_Update(slot))>>10; + + smpl+=(LPANTABLE[vol]*sample)>>SHIFT; + smpr+=(RPANTABLE[vol]*sample)>>SHIFT; + } + } +#define ICLIP16(x) (x<-32768)?-32768:((x>32767)?32767:x) + datap[0][i]=ICLIP16(smpl); + datap[1][i]=ICLIP16(smpr); + } +} diff --git a/src/devices/sound/multipcm.h b/src/devices/sound/multipcm.h new file mode 100644 index 00000000000..18854902ef1 --- /dev/null +++ b/src/devices/sound/multipcm.h @@ -0,0 +1,110 @@ +// license:BSD-3-Clause +// copyright-holders:Miguel Angel Horna +#pragma once + +#ifndef __MULTIPCM_H__ +#define __MULTIPCM_H__ + +struct Sample_t +{ + unsigned int Start; + unsigned int Loop; + unsigned int End; + unsigned char AR,DR1,DR2,DL,RR; + unsigned char KRS; + unsigned char LFOVIB; + unsigned char AM; +}; + +enum STATE {ATTACK,DECAY1,DECAY2,RELEASE}; + +struct EG_t +{ + int volume; // + STATE state; + int step; + //step vals + int AR; //Attack + int D1R; //Decay1 + int D2R; //Decay2 + int RR; //Release + int DL; //Decay level +}; + +struct LFO_t +{ + unsigned short phase; + UINT32 phase_step; + int *table; + int *scale; +}; + + +struct SLOT +{ + unsigned char Num; + unsigned char Regs[8]; + int Playing; + Sample_t *Sample; + unsigned int Base; + unsigned int offset; + unsigned int step; + unsigned int Pan,TL; + unsigned int DstTL; + int TLStep; + signed int Prev; + EG_t EG; + LFO_t PLFO; //Phase lfo + LFO_t ALFO; //AM lfo +}; + +class multipcm_device : public device_t, + public device_sound_interface, + public device_memory_interface +{ +public: + multipcm_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + ~multipcm_device() {} + + DECLARE_WRITE8_MEMBER( write ); + DECLARE_READ8_MEMBER( read ); + + void set_bank(UINT32 leftoffs, UINT32 rightoffs); + +protected: + // device-level overrides + virtual void device_config_complete(); + virtual void device_start(); + + // sound stream update overrides + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const; + + const address_space_config m_space_config; + +private: + // internal state + sound_stream * m_stream; + Sample_t m_Samples[0x200]; //Max 512 samples + SLOT m_Slots[28]; + unsigned int m_CurSlot; + unsigned int m_Address; + unsigned int m_BankR, m_BankL; + float m_Rate; + //I include these in the chip because they depend on the chip clock + unsigned int m_ARStep[0x40], m_DRStep[0x40]; //Envelope step table + unsigned int m_FNS_Table[0x400]; //Frequency step table + + void EG_Calc(SLOT *slot); + void LFO_ComputeStep(LFO_t *LFO,UINT32 LFOF,UINT32 LFOS,int ALFO); + void WriteSlot(SLOT *slot,int reg,unsigned char data); + + direct_read_data *m_direct; +}; + +extern const device_type MULTIPCM; + + +#endif /* __MULTIPCM_H__ */ diff --git a/src/devices/sound/n63701x.c b/src/devices/sound/n63701x.c new file mode 100644 index 00000000000..a1308c36713 --- /dev/null +++ b/src/devices/sound/n63701x.c @@ -0,0 +1,153 @@ +// license:BSD-3-Clause +// copyright-holders:Nicola Salmoria +/*************************************************************************** + +An Hitachi HD637A01X0 MCU programmed to act as a sample player. +Used by some Namco System 86 games. + +The MCU has internal ROM which hasn't been dumped, so here we simulate its +simple functions. + +The chip can address ROM space up to 8 block of 0x10000 bytes. At the beginning +of each block there's a table listing the start offset of each sample. +Samples are 8 bit unsigned, 0xff marks the end of the sample. 0x00 is used for +silence compression: '00 nn' must be replaced by nn+1 times '80'. + +***************************************************************************/ + +#include "emu.h" +#include "n63701x.h" + + +/* volume control has three resistors: 22000, 10000 and 3300 Ohm. + 22000 is always enabled, the other two can be turned off. + Since 0x00 and 0xff samples have special meaning, the available range is + 0x01 to 0xfe, therefore 258 * (0x01 - 0x80) = 0x8002 just keeps us + inside 16 bits without overflowing. + */ +static const int vol_table[4] = { 26, 84, 200, 258 }; + + +// device type definition +const device_type NAMCO_63701X = &device_creator; + +namco_63701x_device::namco_63701x_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, NAMCO_63701X, "Namco 63701X", tag, owner, clock, "namco_63701x", __FILE__), + device_sound_interface(mconfig, *this), + m_rom(*this, DEVICE_SELF), + m_stream(NULL) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void namco_63701x_device::device_start() +{ + m_stream = stream_alloc(0, 2, clock()/1000); + + for (int i = 0; i < 2; i++) + { + save_item(NAME(m_voices[i].select), i); + save_item(NAME(m_voices[i].playing), i); + save_item(NAME(m_voices[i].base_addr), i); + save_item(NAME(m_voices[i].position), i); + save_item(NAME(m_voices[i].volume), i); + save_item(NAME(m_voices[i].silence_counter), i); + } +} + + +//------------------------------------------------- +// sound_stream_update - handle a stream update +//------------------------------------------------- + +void namco_63701x_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + int ch; + + for (ch = 0;ch < 2;ch++) + { + stream_sample_t *buf = outputs[ch]; + voice_63701x *v = &m_voices[ch]; + + if (v->playing) + { + UINT8 *base = m_rom + v->base_addr; + int pos = v->position; + int vol = vol_table[v->volume]; + int p; + + for (p = 0;p < samples;p++) + { + if (v->silence_counter) + { + v->silence_counter--; + *(buf++) = 0; + } + else + { + int data = base[(pos++) & 0xffff]; + + if (data == 0xff) /* end of sample */ + { + v->playing = 0; + break; + } + else if (data == 0x00) /* silence compression */ + { + data = base[(pos++) & 0xffff]; + v->silence_counter = data; + *(buf++) = 0; + } + else + { + *(buf++) = vol * (data - 0x80); + } + } + } + + v->position = pos; + } + else + memset(buf, 0, samples * sizeof(*buf)); + } +} + + + +WRITE8_MEMBER( namco_63701x_device::namco_63701x_w ) +{ + int ch = offset / 2; + + if (offset & 1) + m_voices[ch].select = data; + else + { + /* + should we stop the playing sample if voice_select[ch] == 0 ? + originally we were, but this makes us lose a sample in genpeitd, + after the continue counter reaches 0. Either we shouldn't stop + the sample, or genpeitd is returning to the title screen too soon. + */ + if (m_voices[ch].select & 0x1f) + { + int rom_offs; + + /* update the streams */ + m_stream->update(); + + m_voices[ch].playing = 1; + m_voices[ch].base_addr = 0x10000 * ((m_voices[ch].select & 0xe0) >> 5); + rom_offs = m_voices[ch].base_addr + 2 * ((m_voices[ch].select & 0x1f) - 1); + m_voices[ch].position = (m_rom[rom_offs] << 8) + m_rom[rom_offs+1]; + /* bits 6-7 = volume */ + m_voices[ch].volume = data >> 6; + /* bits 0-5 = counter to indicate new sample start? we don't use them */ + + m_voices[ch].silence_counter = 0; + } + } +} diff --git a/src/devices/sound/n63701x.h b/src/devices/sound/n63701x.h new file mode 100644 index 00000000000..9af9bfc62ab --- /dev/null +++ b/src/devices/sound/n63701x.h @@ -0,0 +1,69 @@ +// license:BSD-3-Clause +// copyright-holders:Nicola Salmoria +#pragma once + +#ifndef __N63701X_H__ +#define __N63701X_H__ + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_NAMCO_63701X_ADD(_tag, _clock) \ + MCFG_DEVICE_ADD(_tag, NAMCO_63701X, _clock) +#define MCFG_NAMCO_63701X_REPLACE(_tag, _clock) \ + MCFG_DEVICE_REPLACE(_tag, NAMCO_63701X, _clock) + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +struct voice_63701x +{ + voice_63701x() + : select(0), + playing(0), + base_addr(0), + position(0), + volume(0), + silence_counter(0) {} + + int select; + int playing; + int base_addr; + int position; + int volume; + int silence_counter; +}; + + +// ======================> namco_63701x_device + +class namco_63701x_device : public device_t, + public device_sound_interface +{ +public: + namco_63701x_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + ~namco_63701x_device() { } + +protected: + // device-level overrides + virtual void device_start(); + + // sound stream update overrides + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + +public: + DECLARE_WRITE8_MEMBER(namco_63701x_w); + +private: + required_region_ptr m_rom; + voice_63701x m_voices[2]; + sound_stream *m_stream; /* channel assigned by the mixer */ +}; + +extern const device_type NAMCO_63701X; + + +#endif /* __N63701X_H__ */ diff --git a/src/devices/sound/namco.c b/src/devices/sound/namco.c new file mode 100644 index 00000000000..ea59b5c6393 --- /dev/null +++ b/src/devices/sound/namco.c @@ -0,0 +1,850 @@ +// license:BSD-3-Clause +// copyright-holders:Nicola Salmoria,Aaron Giles +/*************************************************************************** + + NAMCO sound driver. + + This driver handles the four known types of NAMCO wavetable sounds: + + - 3-voice mono (PROM-based design: Pac-Man, Pengo, Dig Dug, etc) + - 8-voice quadrophonic (Pole Position 1, Pole Position 2) + - 8-voice mono (custom 15XX: Mappy, Dig Dug 2, etc) + - 8-voice stereo (System 1) + +***************************************************************************/ + +#include "emu.h" +#include "namco.h" + + +/* quality parameter: internal sample rate is 192 KHz, output is 48 KHz */ +#define INTERNAL_RATE 192000 + +/* 16 bits: sample bits of the stream buffer */ +/* 4 bits: volume */ +/* 4 bits: prom sample bits */ +#define MIXLEVEL (1 << (16 - 4 - 4)) + +/* stream output level */ +#define OUTPUT_LEVEL(n) ((n) * MIXLEVEL / m_voices) + +/* a position of waveform sample */ +#define WAVEFORM_POSITION(n) (((n) >> m_f_fracbits) & 0x1f) + +const device_type NAMCO = &device_creator; +const device_type NAMCO_15XX = &device_creator; +const device_type NAMCO_CUS30 = &device_creator; + +namco_audio_device::namco_audio_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, __FILE__), + device_sound_interface(mconfig, *this), + m_last_channel(NULL), + m_soundregs(NULL), + m_wavedata(NULL), + m_wave_size(0), + m_sound_enable(0), + m_stream(NULL), + m_namco_clock(0), + m_sample_rate(0), + m_f_fracbits(0), + m_voices(0), + m_stereo(0) +{ +} + +namco_device::namco_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : namco_audio_device(mconfig, NAMCO, "Namco", tag, owner, clock, "namco", __FILE__) +{ +} + +namco_15xx_device::namco_15xx_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + :namco_audio_device(mconfig, NAMCO_15XX, "Namco 15XX", tag, owner, clock, "namco_15xx", __FILE__) +{ +} + +namco_cus30_device::namco_cus30_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : namco_audio_device(mconfig, NAMCO_CUS30, "Namco CUS30", tag, owner, clock, "namco_cus30", __FILE__) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void namco_audio_device::device_start() +{ + sound_channel *voice; + int clock_multiple; + + /* extract globals from the interface */ + m_last_channel = m_channel_list + m_voices; + + m_soundregs = auto_alloc_array_clear(machine(), UINT8, 0x400); + + /* adjust internal clock */ + m_namco_clock = clock(); + for (clock_multiple = 0; m_namco_clock < INTERNAL_RATE; clock_multiple++) + m_namco_clock *= 2; + + m_f_fracbits = clock_multiple + 15; + + /* adjust output clock */ + m_sample_rate = m_namco_clock; + + logerror("Namco: freq fractional bits = %d: internal freq = %d, output freq = %d\n", m_f_fracbits, m_namco_clock, m_sample_rate); + + /* build the waveform table */ + build_decoded_waveform(region()->base()); + + /* get stream channels */ + if (m_stereo) + m_stream = machine().sound().stream_alloc(*this, 0, 2, m_sample_rate); + else + m_stream = machine().sound().stream_alloc(*this, 0, 1, m_sample_rate); + + /* start with sound enabled, many games don't have a sound enable register */ + m_sound_enable = 1; + + /* register with the save state system */ + save_pointer(NAME(m_soundregs), 0x400); + + if (region() == NULL) + save_pointer(NAME(m_wavedata), 0x400); + + save_item(NAME(m_voices)); + save_item(NAME(m_sound_enable)); + save_pointer(NAME(m_waveform[0]), MAX_VOLUME * 32 * 8 * (1+m_wave_size)); + + /* reset all the voices */ + for (voice = m_channel_list; voice < m_last_channel; voice++) + { + int voicenum = voice - m_channel_list; + + voice->frequency = 0; + voice->volume[0] = voice->volume[1] = 0; + voice->waveform_select = 0; + voice->counter = 0; + voice->noise_sw = 0; + voice->noise_state = 0; + voice->noise_seed = 1; + voice->noise_counter = 0; + voice->noise_hold = 0; + + /* register with the save state system */ + save_item(NAME(voice->frequency), voicenum); + save_item(NAME(voice->counter), voicenum); + save_item(NAME(voice->volume), voicenum); + save_item(NAME(voice->noise_sw), voicenum); + save_item(NAME(voice->noise_state), voicenum); + save_item(NAME(voice->noise_seed), voicenum); + save_item(NAME(voice->noise_hold), voicenum); + save_item(NAME(voice->noise_counter), voicenum); + save_item(NAME(voice->waveform_select), voicenum); + } +} + + + +/* update the decoded waveform data */ +void namco_audio_device::update_namco_waveform(int offset, UINT8 data) +{ + if (m_wave_size == 1) + { + INT16 wdata; + int v; + + /* use full byte, first 4 high bits, then low 4 bits */ + for (v = 0; v < MAX_VOLUME; v++) + { + wdata = ((data >> 4) & 0x0f) - 8; + m_waveform[v][offset * 2] = OUTPUT_LEVEL(wdata * v); + wdata = (data & 0x0f) - 8; + m_waveform[v][offset * 2 + 1] = OUTPUT_LEVEL(wdata * v); + } + } + else + { + int v; + + /* use only low 4 bits */ + for (v = 0; v < MAX_VOLUME; v++) + m_waveform[v][offset] = OUTPUT_LEVEL(((data & 0x0f) - 8) * v); + } +} + + +/* build the decoded waveform table */ +void namco_audio_device::build_decoded_waveform(UINT8 *rgnbase) +{ + INT16 *p; + int size; + int offset; + int v; + + m_wavedata = (rgnbase != NULL) ? rgnbase : auto_alloc_array_clear(machine(), UINT8, 0x400); + + /* 20pacgal has waves in RAM but old sound system */ + if (rgnbase == NULL && m_voices != 3) + { + m_wave_size = 1; + size = 32 * 16; /* 32 samples, 16 waveforms */ + } + else + { + m_wave_size = 0; + size = 32 * 8; /* 32 samples, 8 waveforms */ + } + + p = auto_alloc_array(machine(), INT16, size * MAX_VOLUME); + + for (v = 0; v < MAX_VOLUME; v++) + { + m_waveform[v] = p; + p += size; + } + + /* We need waveform data. It fails if region is not specified. */ + if (m_wavedata) + { + for (offset = 0; offset < 256; offset++) + update_namco_waveform(offset, m_wavedata[offset]); + } +} + + +/* generate sound by oversampling */ +UINT32 namco_audio_device::namco_update_one(stream_sample_t *buffer, int length, const INT16 *wave, UINT32 counter, UINT32 freq) +{ + while (length-- > 0) + { + *buffer++ += wave[WAVEFORM_POSITION(counter)]; + counter += freq; + } + + return counter; +} + + +/********************************************************************************/ + +/* pacman register map + 0x05: ch 0 waveform select + 0x0a: ch 1 waveform select + 0x0f: ch 2 waveform select + + 0x10: ch 0 the first voice has extra frequency bits + 0x11-0x14: ch 0 frequency + 0x15: ch 0 volume + + 0x16-0x19: ch 1 frequency + 0x1a: ch 1 volume + + 0x1b-0x1e: ch 2 frequency + 0x1f: ch 2 volume +*/ + +WRITE8_MEMBER( namco_device::pacman_sound_enable_w ) +{ + m_sound_enable = data; +} + +WRITE8_MEMBER( namco_device::pacman_sound_w ) +{ + sound_channel *voice; + int ch; + + data &= 0x0f; + if (m_soundregs[offset] == data) + return; + + /* update the streams */ + m_stream->update(); + + /* set the register */ + m_soundregs[offset] = data; + + if (offset < 0x10) + ch = (offset - 5) / 5; + else if (offset == 0x10) + ch = 0; + else + ch = (offset - 0x11) / 5; + + if (ch >= m_voices) + return; + + /* recompute the voice parameters */ + voice = m_channel_list + ch; + switch (offset - ch * 5) + { + case 0x05: + voice->waveform_select = data & 7; + break; + + case 0x10: + case 0x11: + case 0x12: + case 0x13: + case 0x14: + /* the frequency has 20 bits */ + /* the first voice has extra frequency bits */ + voice->frequency = (ch == 0) ? m_soundregs[0x10] : 0; + voice->frequency += (m_soundregs[ch * 5 + 0x11] << 4); + voice->frequency += (m_soundregs[ch * 5 + 0x12] << 8); + voice->frequency += (m_soundregs[ch * 5 + 0x13] << 12); + voice->frequency += (m_soundregs[ch * 5 + 0x14] << 16); /* always 0 */ + break; + + case 0x15: + voice->volume[0] = data; + break; + } +} + +WRITE8_MEMBER( namco_cus30_device::pacman_sound_w ) +{ + sound_channel *voice; + int ch; + + data &= 0x0f; + if (m_soundregs[offset] == data) + return; + + /* update the streams */ + m_stream->update(); + + /* set the register */ + m_soundregs[offset] = data; + + if (offset < 0x10) + ch = (offset - 5) / 5; + else if (offset == 0x10) + ch = 0; + else + ch = (offset - 0x11) / 5; + + if (ch >= m_voices) + return; + + /* recompute the voice parameters */ + voice = m_channel_list + ch; + switch (offset - ch * 5) + { + case 0x05: + voice->waveform_select = data & 7; + break; + + case 0x10: + case 0x11: + case 0x12: + case 0x13: + case 0x14: + /* the frequency has 20 bits */ + /* the first voice has extra frequency bits */ + voice->frequency = (ch == 0) ? m_soundregs[0x10] : 0; + voice->frequency += (m_soundregs[ch * 5 + 0x11] << 4); + voice->frequency += (m_soundregs[ch * 5 + 0x12] << 8); + voice->frequency += (m_soundregs[ch * 5 + 0x13] << 12); + voice->frequency += (m_soundregs[ch * 5 + 0x14] << 16); /* always 0 */ + break; + + case 0x15: + voice->volume[0] = data; + break; + } +} + +/********************************************************************************/ + +/* polepos register map +Note: even if there are 8 voices, the game doesn't use the first 2 because +it select the 54XX/52XX outputs on those channels + + 0x00-0x01 ch 0 frequency + 0x02 ch 0 xxxx---- GAIN 2 volume + 0x03 ch 0 xxxx---- GAIN 3 volume + ----xxxx GAIN 4 volume + + 0x04-0x07 ch 1 + + . + . + . + + 0x1c-0x1f ch 7 + + 0x23 ch 0 xxxx---- GAIN 1 volume + -----xxx waveform select + ----x-xx channel output select + 0-7 (all the same, shared with waveform select) = wave + 8 = CHANL1 (54XX pins 17-20) + 9 = CHANL2 (54XX pins 8-11) + A = CHANL3 (54XX pins 4-7) + B = CHANL4 (52XX) + 0x27 ch 1 + 0x2b ch 2 + 0x2f ch 3 + 0x33 ch 4 + 0x37 ch 5 + 0x3b ch 6 + 0x3f ch 7 +*/ + +void namco_device::polepos_sound_enable(int enable) +{ + m_sound_enable = enable; +} + +READ8_MEMBER( namco_device::polepos_sound_r ) +{ + return m_soundregs[offset]; +} + +WRITE8_MEMBER( namco_device::polepos_sound_w ) +{ + sound_channel *voice; + int ch; + + if (m_soundregs[offset] == data) + return; + + /* update the streams */ + m_stream->update(); + + /* set the register */ + m_soundregs[offset] = data; + + ch = (offset & 0x1f) / 4; + + /* recompute the voice parameters */ + voice = m_channel_list + ch; + switch (offset & 0x23) + { + case 0x00: + case 0x01: + /* the frequency has 16 bits */ + voice->frequency = m_soundregs[ch * 4 + 0x00]; + voice->frequency += m_soundregs[ch * 4 + 0x01] << 8; + break; + + case 0x23: + voice->waveform_select = data & 7; + /* fall through */ + case 0x02: + case 0x03: + voice->volume[0] = voice->volume[1] = 0; + // front speakers ? + voice->volume[0] += m_soundregs[ch * 4 + 0x03] >> 4; + voice->volume[1] += m_soundregs[ch * 4 + 0x03] & 0x0f; + // rear speakers ? + voice->volume[0] += m_soundregs[ch * 4 + 0x23] >> 4; + voice->volume[1] += m_soundregs[ch * 4 + 0x02] >> 4; + + voice->volume[0] /= 2; + voice->volume[1] /= 2; + + /* if 54XX or 52XX selected, silence this voice */ + if (m_soundregs[ch * 4 + 0x23] & 8) + voice->volume[0] = voice->volume[1] = 0; + break; + } +} + + +/********************************************************************************/ + +/* 15XX register map + 0x03 ch 0 volume + 0x04-0x05 ch 0 frequency + 0x06 ch 0 waveform select & frequency + + 0x0b ch 1 volume + 0x0c-0x0d ch 1 frequency + 0x0e ch 1 waveform select & frequency + + . + . + . + + 0x3b ch 7 volume + 0x3c-0x3d ch 7 frequency + 0x3e ch 7 waveform select & frequency +*/ + +void namco_15xx_device::mappy_sound_enable(int enable) +{ + m_sound_enable = enable; +} + +WRITE8_MEMBER(namco_15xx_device::namco_15xx_w) +{ + sound_channel *voice; + int ch; + + if (m_soundregs[offset] == data) + return; + + /* update the streams */ + m_stream->update(); + + /* set the register */ + m_soundregs[offset] = data; + + ch = offset / 8; + if (ch >= m_voices) + return; + + /* recompute the voice parameters */ + voice = m_channel_list + ch; + switch (offset - ch * 8) + { + case 0x03: + voice->volume[0] = data & 0x0f; + break; + + case 0x06: + voice->waveform_select = (data >> 4) & 7; + case 0x04: + case 0x05: + /* the frequency has 20 bits */ + voice->frequency = m_soundregs[ch * 8 + 0x04]; + voice->frequency += m_soundregs[ch * 8 + 0x05] << 8; + voice->frequency += (m_soundregs[ch * 8 + 0x06] & 15) << 16; /* high bits are from here */ + break; + } +} + + +/********************************************************************************/ + +/* namcos1 register map + 0x00 ch 0 left volume + 0x01 ch 0 waveform select & frequency + 0x02-0x03 ch 0 frequency + 0x04 ch 0 right volume AND + 0x04 ch 1 noise sw + + 0x08 ch 1 left volume + 0x09 ch 1 waveform select & frequency + 0x0a-0x0b ch 1 frequency + 0x0c ch 1 right volume AND + 0x0c ch 2 noise sw + + . + . + . + + 0x38 ch 7 left volume + 0x39 ch 7 waveform select & frequency + 0x3a-0x3b ch 7 frequency + 0x3c ch 7 right volume AND + 0x3c ch 0 noise sw +*/ + + WRITE8_MEMBER(namco_cus30_device::namcos1_sound_w) +{ + sound_channel *voice; + int ch; + int nssw; + + + /* verify the offset */ + if (offset > 63) + { + logerror("NAMCOS1 sound: Attempting to write past the 64 registers segment\n"); + return; + } + + m_soundregs = m_wavedata + 0x100; + + if (m_soundregs[offset] == data) + return; + + /* update the streams */ + m_stream->update(); + + /* set the register */ + m_soundregs[offset] = data; + + ch = offset / 8; + if (ch >= m_voices) + return; + + /* recompute the voice parameters */ + voice = m_channel_list + ch; + switch (offset - ch * 8) + { + case 0x00: + voice->volume[0] = data & 0x0f; + break; + + case 0x01: + voice->waveform_select = (data >> 4) & 15; + case 0x02: + case 0x03: + /* the frequency has 20 bits */ + voice->frequency = (m_soundregs[ch * 8 + 0x01] & 15) << 16; /* high bits are from here */ + voice->frequency += m_soundregs[ch * 8 + 0x02] << 8; + voice->frequency += m_soundregs[ch * 8 + 0x03]; + break; + + case 0x04: + voice->volume[1] = data & 0x0f; + + nssw = ((data & 0x80) >> 7); + if (++voice == m_last_channel) + voice = m_channel_list; + voice->noise_sw = nssw; + break; + } +} + +WRITE8_MEMBER( namco_cus30_device::namcos1_cus30_w ) +{ + if (offset < 0x100) + { + if (m_wavedata[offset] != data) + { + /* update the streams */ + m_stream->update(); + + m_wavedata[offset] = data; + + /* update the decoded waveform table */ + update_namco_waveform(offset, data); + } + } + else if (offset < 0x140) + namcos1_sound_w(space, offset - 0x100,data); + else + m_wavedata[offset] = data; +} + +READ8_MEMBER( namco_cus30_device::namcos1_cus30_r ) +{ + return m_wavedata[offset]; +} + +READ8_MEMBER( namco_15xx_device::sharedram_r ) +{ + return m_soundregs[offset]; +} + +WRITE8_MEMBER( namco_15xx_device::sharedram_w ) +{ + if (offset < 0x40) + namco_15xx_w(space, offset, data); + else + { + m_soundregs[offset] = data; + } +} + +//------------------------------------------------- +// sound_stream_update - handle a stream update +//------------------------------------------------- + +void namco_audio_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + if (m_stereo) + { + sound_channel *voice; + + /* zap the contents of the buffers */ + memset(outputs[0], 0, samples * sizeof(*outputs[0])); + memset(outputs[1], 0, samples * sizeof(*outputs[1])); + + /* if no sound, we're done */ + if (m_sound_enable == 0) + return; + + /* loop over each voice and add its contribution */ + for (voice = m_channel_list; voice < m_last_channel; voice++) + { + stream_sample_t *lmix = outputs[0]; + stream_sample_t *rmix = outputs[1]; + int lv = voice->volume[0]; + int rv = voice->volume[1]; + + if (voice->noise_sw) + { + int f = voice->frequency & 0xff; + + /* only update if we have non-zero volume and frequency */ + if ((lv || rv) && f) + { + int hold_time = 1 << (m_f_fracbits - 16); + int hold = voice->noise_hold; + UINT32 delta = f << 4; + UINT32 c = voice->noise_counter; + INT16 l_noise_data = OUTPUT_LEVEL(0x07 * (lv >> 1)); + INT16 r_noise_data = OUTPUT_LEVEL(0x07 * (rv >> 1)); + int i; + + /* add our contribution */ + for (i = 0; i < samples; i++) + { + int cnt; + + if (voice->noise_state) + { + *lmix++ += l_noise_data; + *rmix++ += r_noise_data; + } + else + { + *lmix++ -= l_noise_data; + *rmix++ -= r_noise_data; + } + + if (hold) + { + hold--; + continue; + } + + hold = hold_time; + + c += delta; + cnt = (c >> 12); + c &= (1 << 12) - 1; + for( ;cnt > 0; cnt--) + { + if ((voice->noise_seed + 1) & 2) voice->noise_state ^= 1; + if (voice->noise_seed & 1) voice->noise_seed ^= 0x28000; + voice->noise_seed >>= 1; + } + } + + /* update the counter and hold time for this voice */ + voice->noise_counter = c; + voice->noise_hold = hold; + } + } + else + { + /* only update if we have non-zero frequency */ + if (voice->frequency) + { + /* save the counter for this voice */ + UINT32 c = voice->counter; + + /* only update if we have non-zero left volume */ + if (lv) + { + const INT16 *lw = &m_waveform[lv][voice->waveform_select * 32]; + + /* generate sound into the buffer */ + c = namco_update_one(lmix, samples, lw, voice->counter, voice->frequency); + } + + /* only update if we have non-zero right volume */ + if (rv) + { + const INT16 *rw = &m_waveform[rv][voice->waveform_select * 32]; + + /* generate sound into the buffer */ + c = namco_update_one(rmix, samples, rw, voice->counter, voice->frequency); + } + + /* update the counter for this voice */ + voice->counter = c; + } + } + } + } + else + { + sound_channel *voice; + + stream_sample_t *buffer = outputs[0]; + /* zap the contents of the buffer */ + memset(buffer, 0, samples * sizeof(*buffer)); + + /* if no sound, we're done */ + + if (m_sound_enable == 0) + return; + + /* loop over each voice and add its contribution */ + for (voice = m_channel_list; voice < m_last_channel; voice++) + { + stream_sample_t *mix = buffer; + int v = voice->volume[0]; + if (voice->noise_sw) + { + int f = voice->frequency & 0xff; + /* only update if we have non-zero volume and frequency */ + if (v && f) + { + int hold_time = 1 << (m_f_fracbits - 16); + int hold = voice->noise_hold; + UINT32 delta = f << 4; + UINT32 c = voice->noise_counter; + INT16 noise_data = OUTPUT_LEVEL(0x07 * (v >> 1)); + int i; + + /* add our contribution */ + for (i = 0; i < samples; i++) + { + int cnt; + + if (voice->noise_state) + *mix++ += noise_data; + else + *mix++ -= noise_data; + + if (hold) + { + hold--; + continue; + } + + hold = hold_time; + + c += delta; + cnt = (c >> 12); + c &= (1 << 12) - 1; + for( ;cnt > 0; cnt--) + { + if ((voice->noise_seed + 1) & 2) voice->noise_state ^= 1; + if (voice->noise_seed & 1) voice->noise_seed ^= 0x28000; + voice->noise_seed >>= 1; + } + } + + /* update the counter and hold time for this voice */ + voice->noise_counter = c; + voice->noise_hold = hold; + } + } + else + { + /* only update if we have non-zero volume and frequency */ + if (v && voice->frequency) + { + const INT16 *w = &m_waveform[v][voice->waveform_select * 32]; + + /* generate sound into buffer and update the counter for this voice */ + voice->counter = namco_update_one(mix, samples, w, voice->counter, voice->frequency); + } + } + } + } +} + +void namco_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + namco_audio_device::sound_stream_update(stream, inputs, outputs, samples); +} + +void namco_15xx_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + namco_audio_device::sound_stream_update(stream, inputs, outputs, samples); +} + +void namco_cus30_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + namco_audio_device::sound_stream_update(stream, inputs, outputs, samples); +} diff --git a/src/devices/sound/namco.h b/src/devices/sound/namco.h new file mode 100644 index 00000000000..56be828b046 --- /dev/null +++ b/src/devices/sound/namco.h @@ -0,0 +1,132 @@ +// license:BSD-3-Clause +// copyright-holders:Nicola Salmoria,Aaron Giles +#pragma once + +#ifndef __NAMCO_H__ +#define __NAMCO_H__ + +/* 8 voices max */ +#define MAX_VOICES 8 + +#define MAX_VOLUME 16 + + +#define MCFG_NAMCO_AUDIO_VOICES(_voices) \ + namco_audio_device::set_voices(*device, _voices); + +#define MCFG_NAMCO_AUDIO_STEREO(_stereo) \ + namco_audio_device::set_stereo(*device, _stereo); + + +/* this structure defines the parameters for a channel */ +struct sound_channel +{ + UINT32 frequency; + UINT32 counter; + INT32 volume[2]; + INT32 noise_sw; + INT32 noise_state; + INT32 noise_seed; + UINT32 noise_counter; + INT32 noise_hold; + INT32 waveform_select; +}; + +class namco_audio_device : public device_t, + public device_sound_interface +{ +public: + namco_audio_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + ~namco_audio_device() {} + + // static configuration + static void set_voices(device_t &device, int voices) { downcast(device).m_voices = voices; } + static void set_stereo(device_t &device, int stereo) { downcast(device).m_stereo = stereo; } + +protected: + // device-level overrides + virtual void device_start(); + + // internal state + + void build_decoded_waveform( UINT8 *rgnbase ); + void update_namco_waveform(int offset, UINT8 data); + UINT32 namco_update_one(stream_sample_t *buffer, int length, const INT16 *wave, UINT32 counter, UINT32 freq); + + /* data about the sound system */ + sound_channel m_channel_list[MAX_VOICES]; + sound_channel *m_last_channel; + UINT8 *m_soundregs; + UINT8 *m_wavedata; + + /* global sound parameters */ + int m_wave_size; + INT32 m_sound_enable; + sound_stream *m_stream; + int m_namco_clock; + int m_sample_rate; + int m_f_fracbits; + + int m_voices; /* number of voices */ + int m_stereo; /* set to 1 to indicate stereo (e.g., System 1) */ + + /* decoded waveform table */ + INT16 *m_waveform[MAX_VOLUME]; + + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); +}; + +class namco_device : public namco_audio_device +{ +public: + namco_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + DECLARE_WRITE8_MEMBER( pacman_sound_enable_w ); + DECLARE_WRITE8_MEMBER( pacman_sound_w ); + + void polepos_sound_enable(int enable); + + DECLARE_READ8_MEMBER( polepos_sound_r ); + DECLARE_WRITE8_MEMBER( polepos_sound_w ); + +protected: + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); +}; + +extern const device_type NAMCO; + +class namco_15xx_device : public namco_audio_device +{ +public: + namco_15xx_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + DECLARE_WRITE8_MEMBER( namco_15xx_w ); + DECLARE_READ8_MEMBER( sharedram_r ); + DECLARE_WRITE8_MEMBER( sharedram_w ); + + void mappy_sound_enable(int enable); + +protected: + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); +}; + +extern const device_type NAMCO_15XX; + +class namco_cus30_device : public namco_audio_device +{ +public: + namco_cus30_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + DECLARE_WRITE8_MEMBER( namcos1_cus30_w ); /* wavedata + sound registers + RAM */ + DECLARE_READ8_MEMBER( namcos1_cus30_r ); + DECLARE_WRITE8_MEMBER( namcos1_sound_w ); + + DECLARE_WRITE8_MEMBER( pacman_sound_w ); + +protected: + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); +}; + +extern const device_type NAMCO_CUS30; + +#endif /* __NAMCO_H__ */ diff --git a/src/devices/sound/nes_apu.c b/src/devices/sound/nes_apu.c new file mode 100644 index 00000000000..cd2dfa8e4cb --- /dev/null +++ b/src/devices/sound/nes_apu.c @@ -0,0 +1,774 @@ +// license:GPL-2.0+ +// copyright-holders:Matthew Conte +/***************************************************************************** + + MAME/MESS NES APU CORE + + Based on the Nofrendo/Nosefart NES N2A03 sound emulation core written by + Matthew Conte (matt@conte.com) and redesigned for use in MAME/MESS by + Who Wants to Know? (wwtk@mail.com) + + This core is written with the advise and consent of Matthew Conte and is + released under the GNU Public License. This core is freely avaiable for + use in any freeware project, subject to the following terms: + + Any modifications to this code must be duly noted in the source and + approved by Matthew Conte and myself prior to public submission. + + timing notes: + master = 21477270 + 2A03 clock = master/12 + sequencer = master/89490 or CPU/7457 + + ***************************************************************************** + + NES_APU.C + + Actual NES APU interface. + + LAST MODIFIED 02/29/2004 + + - Based on Matthew Conte's Nofrendo/Nosefart core and redesigned to + use MAME system calls and to enable multiple APUs. Sound at this + point should be just about 100% accurate, though I cannot tell for + certain as yet. + + A queue interface is also available for additional speed. However, + the implementation is not yet 100% (DPCM sounds are inaccurate), + so it is disabled by default. + + ***************************************************************************** + + BUGFIXES: + + - Various bugs concerning the DPCM channel fixed. (Oliver Achten) + - Fixed $4015 read behaviour. (Oliver Achten) + + *****************************************************************************/ + +#include "emu.h" +#include "nes_apu.h" +#include "cpu/m6502/n2a03.h" + + + +/* INTERNAL FUNCTIONS */ + +/* INITIALIZE WAVE TIMES RELATIVE TO SAMPLE RATE */ +static void create_vbltimes(uint32 * table,const uint8 *vbl,unsigned int rate) +{ + int i; + + for (i = 0; i < 0x20; i++) + table[i] = vbl[i] * rate; +} + +/* INITIALIZE SAMPLE TIMES IN TERMS OF VSYNCS */ +void nesapu_device::create_syncs(unsigned long sps) +{ + int i; + unsigned long val = sps; + + for (i = 0; i < SYNCS_MAX1; i++) + { + m_sync_times1[i] = val; + val += sps; + } + + val = 0; + for (i = 0; i < SYNCS_MAX2; i++) + { + m_sync_times2[i] = val; + m_sync_times2[i] >>= 2; + val += sps; + } +} + +/* INITIALIZE NOISE LOOKUP TABLE */ +static void create_noise(uint8 *buf, const int bits, int size) +{ + int m = 0x0011; + int xor_val, i; + + for (i = 0; i < size; i++) + { + xor_val = m & 1; + m >>= 1; + xor_val ^= (m & 1); + m |= xor_val << (bits - 1); + + buf[i] = m; + } +} + +const device_type NES_APU = &device_creator; + +nesapu_device::nesapu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, NES_APU, "N2A03 APU", tag, owner, clock, "nesapu", __FILE__), + device_sound_interface(mconfig, *this), + m_apu_incsize(0.0), + m_samps_per_sync(0), + m_buffer_size(0), + m_real_rate(0), + m_stream(NULL), + m_cpu_tag("") +{ + for (int i = 0; i < NOISE_LONG; i++) + { + m_noise_lut[i] = 0; + } + + for (int i = 0; i < 0X20; i++) + { + m_vbl_times[i] = 0; + } + + for (int i = 0; i < SYNCS_MAX1; i++) + { + m_sync_times1[i] = 0; + } + + for (int i = 0; i < SYNCS_MAX2; i++) + { + m_sync_times2[i] = 0; + } +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void nesapu_device::device_start() +{ + int rate = clock() / 4; + + /* Initialize global variables */ + m_samps_per_sync = rate / ATTOSECONDS_TO_HZ(machine().first_screen()->frame_period().attoseconds()); + m_buffer_size = m_samps_per_sync; + m_real_rate = m_samps_per_sync * ATTOSECONDS_TO_HZ(machine().first_screen()->frame_period().attoseconds()); + m_apu_incsize = (float) (clock() / (float) m_real_rate); + + /* Use initializer calls */ + create_noise(m_noise_lut, 13, NOISE_LONG); + create_vbltimes(m_vbl_times,vbl_length,m_samps_per_sync); + create_syncs(m_samps_per_sync); + + /* Adjust buffer size if 16 bits */ + m_buffer_size+=m_samps_per_sync; + + /* Initialize individual chips */ + (m_APU.dpcm).memory = &machine().device(m_cpu_tag)->memory().space(AS_PROGRAM); + + m_stream = machine().sound().stream_alloc(*this, 0, 1, rate); + + /* register for save */ + for (int i = 0; i < 2; i++) + { + save_item(NAME(m_APU.squ[i].regs), i); + save_item(NAME(m_APU.squ[i].vbl_length), i); + save_item(NAME(m_APU.squ[i].freq), i); + save_item(NAME(m_APU.squ[i].phaseacc), i); + save_item(NAME(m_APU.squ[i].output_vol), i); + save_item(NAME(m_APU.squ[i].env_phase), i); + save_item(NAME(m_APU.squ[i].sweep_phase), i); + save_item(NAME(m_APU.squ[i].adder), i); + save_item(NAME(m_APU.squ[i].env_vol), i); + save_item(NAME(m_APU.squ[i].enabled), i); + } + + save_item(NAME(m_APU.tri.regs)); + save_item(NAME(m_APU.tri.linear_length)); + save_item(NAME(m_APU.tri.vbl_length)); + save_item(NAME(m_APU.tri.write_latency)); + save_item(NAME(m_APU.tri.phaseacc)); + save_item(NAME(m_APU.tri.output_vol)); + save_item(NAME(m_APU.tri.adder)); + save_item(NAME(m_APU.tri.counter_started)); + save_item(NAME(m_APU.tri.enabled)); + + save_item(NAME(m_APU.noi.regs)); + save_item(NAME(m_APU.noi.cur_pos)); + save_item(NAME(m_APU.noi.vbl_length)); + save_item(NAME(m_APU.noi.phaseacc)); + save_item(NAME(m_APU.noi.output_vol)); + save_item(NAME(m_APU.noi.env_phase)); + save_item(NAME(m_APU.noi.env_vol)); + save_item(NAME(m_APU.noi.enabled)); + + save_item(NAME(m_APU.dpcm.regs)); + save_item(NAME(m_APU.dpcm.address)); + save_item(NAME(m_APU.dpcm.length)); + save_item(NAME(m_APU.dpcm.bits_left)); + save_item(NAME(m_APU.dpcm.phaseacc)); + save_item(NAME(m_APU.dpcm.output_vol)); + save_item(NAME(m_APU.dpcm.cur_byte)); + save_item(NAME(m_APU.dpcm.enabled)); + save_item(NAME(m_APU.dpcm.irq_occurred)); + save_item(NAME(m_APU.dpcm.vol)); + + save_item(NAME(m_APU.regs)); + + #ifdef USE_QUEUE + save_item(NAME(m_APU.queue)); + save_item(NAME(m_APU.head)); + save_item(NAME(m_APU.tail)); + #else + save_item(NAME(m_APU.buf_pos)); + save_item(NAME(m_APU.step_mode)); + #endif +} + +/* TODO: sound channels should *ALL* have DC volume decay */ + +/* OUTPUT SQUARE WAVE SAMPLE (VALUES FROM -16 to +15) */ +int8 nesapu_device::apu_square(square_t *chan) +{ + int env_delay; + int sweep_delay; + int8 output; + + /* reg0: 0-3=volume, 4=envelope, 5=hold, 6-7=duty cycle + ** reg1: 0-2=sweep shifts, 3=sweep inc/dec, 4-6=sweep length, 7=sweep on + ** reg2: 8 bits of freq + ** reg3: 0-2=high freq, 7-4=vbl length counter + */ + + if (FALSE == chan->enabled) + return 0; + + /* enveloping */ + env_delay = m_sync_times1[chan->regs[0] & 0x0F]; + + /* decay is at a rate of (env_regs + 1) / 240 secs */ + chan->env_phase -= 4; + while (chan->env_phase < 0) + { + chan->env_phase += env_delay; + if (chan->regs[0] & 0x20) + chan->env_vol = (chan->env_vol + 1) & 15; + else if (chan->env_vol < 15) + chan->env_vol++; + } + + /* vbl length counter */ + if (chan->vbl_length > 0 && 0 == (chan->regs [0] & 0x20)) + chan->vbl_length--; + + if (0 == chan->vbl_length) + return 0; + + /* freqsweeps */ + if ((chan->regs[1] & 0x80) && (chan->regs[1] & 7)) + { + sweep_delay = m_sync_times1[(chan->regs[1] >> 4) & 7]; + chan->sweep_phase -= 2; + while (chan->sweep_phase < 0) + { + chan->sweep_phase += sweep_delay; + if (chan->regs[1] & 8) + chan->freq -= chan->freq >> (chan->regs[1] & 7); + else + chan->freq += chan->freq >> (chan->regs[1] & 7); + } + } + + if ((0 == (chan->regs[1] & 8) && (chan->freq >> 16) > freq_limit[chan->regs[1] & 7]) + || (chan->freq >> 16) < 4) + return 0; + + chan->phaseacc -= (float) m_apu_incsize; /* # of cycles per sample */ + + while (chan->phaseacc < 0) + { + chan->phaseacc += (chan->freq >> 16); + chan->adder = (chan->adder + 1) & 0x0F; + } + + if (chan->regs[0] & 0x10) /* fixed volume */ + output = chan->regs[0] & 0x0F; + else + output = 0x0F - chan->env_vol; + + if (chan->adder < (duty_lut[chan->regs[0] >> 6])) + output = -output; + + return (int8) output; +} + +/* OUTPUT TRIANGLE WAVE SAMPLE (VALUES FROM -16 to +15) */ +int8 nesapu_device::apu_triangle(triangle_t *chan) +{ + int freq; + int8 output; + /* reg0: 7=holdnote, 6-0=linear length counter + ** reg2: low 8 bits of frequency + ** reg3: 7-3=length counter, 2-0=high 3 bits of frequency + */ + + if (FALSE == chan->enabled) + return 0; + + if (FALSE == chan->counter_started && 0 == (chan->regs[0] & 0x80)) + { + if (chan->write_latency) + chan->write_latency--; + if (0 == chan->write_latency) + chan->counter_started = TRUE; + } + + if (chan->counter_started) + { + if (chan->linear_length > 0) + chan->linear_length--; + if (chan->vbl_length && 0 == (chan->regs[0] & 0x80)) + chan->vbl_length--; + + if (0 == chan->vbl_length) + return 0; + } + + if (0 == chan->linear_length) + return 0; + + freq = (((chan->regs[3] & 7) << 8) + chan->regs[2]) + 1; + + if (freq < 4) /* inaudible */ + return 0; + + chan->phaseacc -= (float) m_apu_incsize; /* # of cycles per sample */ + while (chan->phaseacc < 0) + { + chan->phaseacc += freq; + chan->adder = (chan->adder + 1) & 0x1F; + + output = (chan->adder & 7) << 1; + if (chan->adder & 8) + output = 0x10 - output; + if (chan->adder & 0x10) + output = -output; + + chan->output_vol = output; + } + + return (int8) chan->output_vol; +} + +/* OUTPUT NOISE WAVE SAMPLE (VALUES FROM -16 to +15) */ +int8 nesapu_device::apu_noise(noise_t *chan) +{ + int freq, env_delay; + uint8 outvol; + uint8 output; + + /* reg0: 0-3=volume, 4=envelope, 5=hold + ** reg2: 7=small(93 byte) sample,3-0=freq lookup + ** reg3: 7-4=vbl length counter + */ + + if (FALSE == chan->enabled) + return 0; + + /* enveloping */ + env_delay = m_sync_times1[chan->regs[0] & 0x0F]; + + /* decay is at a rate of (env_regs + 1) / 240 secs */ + chan->env_phase -= 4; + while (chan->env_phase < 0) + { + chan->env_phase += env_delay; + if (chan->regs[0] & 0x20) + chan->env_vol = (chan->env_vol + 1) & 15; + else if (chan->env_vol < 15) + chan->env_vol++; + } + + /* length counter */ + if (0 == (chan->regs[0] & 0x20)) + { + if (chan->vbl_length > 0) + chan->vbl_length--; + } + + if (0 == chan->vbl_length) + return 0; + + freq = noise_freq[chan->regs[2] & 0x0F]; + chan->phaseacc -= (float) m_apu_incsize; /* # of cycles per sample */ + while (chan->phaseacc < 0) + { + chan->phaseacc += freq; + + chan->cur_pos++; + if (NOISE_SHORT == chan->cur_pos && (chan->regs[2] & 0x80)) + chan->cur_pos = 0; + else if (NOISE_LONG == chan->cur_pos) + chan->cur_pos = 0; + } + + if (chan->regs[0] & 0x10) /* fixed volume */ + outvol = chan->regs[0] & 0x0F; + else + outvol = 0x0F - chan->env_vol; + + output = m_noise_lut[chan->cur_pos]; + if (output > outvol) + output = outvol; + + if (m_noise_lut[chan->cur_pos] & 0x80) /* make it negative */ + output = -output; + + return (int8) output; +} + +/* RESET DPCM PARAMETERS */ +INLINE void apu_dpcmreset(dpcm_t *chan) +{ + chan->address = 0xC000 + (uint16) (chan->regs[2] << 6); + chan->length = (uint16) (chan->regs[3] << 4) + 1; + chan->bits_left = chan->length << 3; + chan->irq_occurred = FALSE; + chan->enabled = TRUE; /* Fixed * Proper DPCM channel ENABLE/DISABLE flag behaviour*/ + chan->vol = 0; /* Fixed * DPCM DAC resets itself when restarted */ +} + +/* OUTPUT DPCM WAVE SAMPLE (VALUES FROM -64 to +63) */ +/* TODO: centerline naughtiness */ +int8 nesapu_device::apu_dpcm(dpcm_t *chan) +{ + int freq, bit_pos; + + /* reg0: 7=irq gen, 6=looping, 3-0=pointer to clock table + ** reg1: output dc level, 7 bits unsigned + ** reg2: 8 bits of 64-byte aligned address offset : $C000 + (value * 64) + ** reg3: length, (value * 16) + 1 + */ + + if (chan->enabled) + { + freq = dpcm_clocks[chan->regs[0] & 0x0F]; + chan->phaseacc -= (float) m_apu_incsize; /* # of cycles per sample */ + + while (chan->phaseacc < 0) + { + chan->phaseacc += freq; + + if (0 == chan->length) + { + chan->enabled = FALSE; /* Fixed * Proper DPCM channel ENABLE/DISABLE flag behaviour*/ + chan->vol=0; /* Fixed * DPCM DAC resets itself when restarted */ + if (chan->regs[0] & 0x40) + apu_dpcmreset(chan); + else + { + if (chan->regs[0] & 0x80) /* IRQ Generator */ + { + chan->irq_occurred = TRUE; + downcast(m_APU.dpcm.memory->device()).set_input_line(N2A03_APU_IRQ_LINE, ASSERT_LINE); + } + break; + } + } + + + chan->bits_left--; + bit_pos = 7 - (chan->bits_left & 7); + if (7 == bit_pos) + { + chan->cur_byte = m_APU.dpcm.memory->read_byte(chan->address); + chan->address++; + chan->length--; + } + + if (chan->cur_byte & (1 << bit_pos)) +// chan->regs[1]++; + chan->vol+=2; /* FIXED * DPCM channel only uses the upper 6 bits of the DAC */ + else +// chan->regs[1]--; + chan->vol-=2; + } + } + + if (chan->vol > 63) + chan->vol = 63; + else if (chan->vol < -64) + chan->vol = -64; + + return (int8) (chan->vol); +} + +/* WRITE REGISTER VALUE */ +inline void nesapu_device::apu_regwrite(int address, uint8 value) +{ + int chan = (address & 4) ? 1 : 0; + + switch (address) + { + /* squares */ + case APU_WRA0: + case APU_WRB0: + m_APU.squ[chan].regs[0] = value; + break; + + case APU_WRA1: + case APU_WRB1: + m_APU.squ[chan].regs[1] = value; + break; + + case APU_WRA2: + case APU_WRB2: + m_APU.squ[chan].regs[2] = value; + if (m_APU.squ[chan].enabled) + m_APU.squ[chan].freq = ((((m_APU.squ[chan].regs[3] & 7) << 8) + value) + 1) << 16; + break; + + case APU_WRA3: + case APU_WRB3: + m_APU.squ[chan].regs[3] = value; + + if (m_APU.squ[chan].enabled) + { + m_APU.squ[chan].vbl_length = m_vbl_times[value >> 3]; + m_APU.squ[chan].env_vol = 0; + m_APU.squ[chan].freq = ((((value & 7) << 8) + m_APU.squ[chan].regs[2]) + 1) << 16; + } + + break; + + /* triangle */ + case APU_WRC0: + m_APU.tri.regs[0] = value; + + if (m_APU.tri.enabled) + { /* ??? */ + if (FALSE == m_APU.tri.counter_started) + m_APU.tri.linear_length = m_sync_times2[value & 0x7F]; + } + + break; + + case 0x4009: + /* unused */ + m_APU.tri.regs[1] = value; + break; + + case APU_WRC2: + m_APU.tri.regs[2] = value; + break; + + case APU_WRC3: + m_APU.tri.regs[3] = value; + + /* this is somewhat of a hack. there is some latency on the Real + ** Thing between when trireg0 is written to and when the linear + ** length counter actually begins its countdown. we want to prevent + ** the case where the program writes to the freq regs first, then + ** to reg 0, and the counter accidentally starts running because of + ** the sound queue's timestamp processing. + ** + ** set to a few NES sample -- should be sufficient + ** + ** 3 * (1789772.727 / 44100) = ~122 cycles, just around one scanline + ** + ** should be plenty of time for the 6502 code to do a couple of table + ** dereferences and load up the other triregs + */ + + /* used to be 3, but now we run the clock faster, so base it on samples/sync */ + m_APU.tri.write_latency = (m_samps_per_sync + 239) / 240; + + if (m_APU.tri.enabled) + { + m_APU.tri.counter_started = FALSE; + m_APU.tri.vbl_length = m_vbl_times[value >> 3]; + m_APU.tri.linear_length = m_sync_times2[m_APU.tri.regs[0] & 0x7F]; + } + + break; + + /* noise */ + case APU_WRD0: + m_APU.noi.regs[0] = value; + break; + + case 0x400D: + /* unused */ + m_APU.noi.regs[1] = value; + break; + + case APU_WRD2: + m_APU.noi.regs[2] = value; + break; + + case APU_WRD3: + m_APU.noi.regs[3] = value; + + if (m_APU.noi.enabled) + { + m_APU.noi.vbl_length = m_vbl_times[value >> 3]; + m_APU.noi.env_vol = 0; /* reset envelope */ + } + break; + + /* DMC */ + case APU_WRE0: + m_APU.dpcm.regs[0] = value; + if (0 == (value & 0x80)) { + downcast(m_APU.dpcm.memory->device()).set_input_line(N2A03_APU_IRQ_LINE, CLEAR_LINE); + m_APU.dpcm.irq_occurred = FALSE; + } + break; + + case APU_WRE1: /* 7-bit DAC */ + //m_APU.dpcm.regs[1] = value - 0x40; + m_APU.dpcm.regs[1] = value & 0x7F; + m_APU.dpcm.vol = (m_APU.dpcm.regs[1]-64); + break; + + case APU_WRE2: + m_APU.dpcm.regs[2] = value; + //apu_dpcmreset(m_APU.dpcm); + break; + + case APU_WRE3: + m_APU.dpcm.regs[3] = value; + break; + + case APU_IRQCTRL: + if(value & 0x80) + m_APU.step_mode = 5; + else + m_APU.step_mode = 4; + break; + + case APU_SMASK: + if (value & 0x01) + m_APU.squ[0].enabled = TRUE; + else + { + m_APU.squ[0].enabled = FALSE; + m_APU.squ[0].vbl_length = 0; + } + + if (value & 0x02) + m_APU.squ[1].enabled = TRUE; + else + { + m_APU.squ[1].enabled = FALSE; + m_APU.squ[1].vbl_length = 0; + } + + if (value & 0x04) + m_APU.tri.enabled = TRUE; + else + { + m_APU.tri.enabled = FALSE; + m_APU.tri.vbl_length = 0; + m_APU.tri.linear_length = 0; + m_APU.tri.counter_started = FALSE; + m_APU.tri.write_latency = 0; + } + + if (value & 0x08) + m_APU.noi.enabled = TRUE; + else + { + m_APU.noi.enabled = FALSE; + m_APU.noi.vbl_length = 0; + } + + if (value & 0x10) + { + /* only reset dpcm values if DMA is finished */ + if (FALSE == m_APU.dpcm.enabled) + { + m_APU.dpcm.enabled = TRUE; + apu_dpcmreset(&m_APU.dpcm); + } + } + else + m_APU.dpcm.enabled = FALSE; + + m_APU.dpcm.irq_occurred = FALSE; + + break; + default: +#ifdef MAME_DEBUG +logerror("invalid apu write: $%02X at $%04X\n", value, address); +#endif + break; + } +} + + + +/* READ VALUES FROM REGISTERS */ +inline uint8 nesapu_device::apu_read(int address) +{ + if (address == 0x15) /*FIXED* Address $4015 has different behaviour*/ + { + int readval = 0; + if (m_APU.squ[0].vbl_length > 0) + readval |= 0x01; + + if (m_APU.squ[1].vbl_length > 0) + readval |= 0x02; + + if (m_APU.tri.vbl_length > 0) + readval |= 0x04; + + if (m_APU.noi.vbl_length > 0) + readval |= 0x08; + + if (m_APU.dpcm.enabled == TRUE) + readval |= 0x10; + + if (m_APU.dpcm.irq_occurred == TRUE) + readval |= 0x80; + + return readval; + } + else + return m_APU.regs[address]; +} + +/* WRITE VALUE TO TEMP REGISTRY AND QUEUE EVENT */ +inline void nesapu_device::apu_write(int address, uint8 value) +{ + m_APU.regs[address]=value; + m_stream->update(); + apu_regwrite(address,value); +} + +/* EXTERNAL INTERFACE FUNCTIONS */ + +/* REGISTER READ/WRITE FUNCTIONS */ +READ8_MEMBER( nesapu_device::read ) {return apu_read(offset);} +WRITE8_MEMBER( nesapu_device::write ) {apu_write(offset,data);} + + +//------------------------------------------------- +// sound_stream_update - handle a stream update +//------------------------------------------------- + +void nesapu_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + int accum; + memset( outputs[0], 0, samples*sizeof(*outputs[0]) ); + + while (samples--) + { + accum = apu_square(&m_APU.squ[0]); + accum += apu_square(&m_APU.squ[1]); + accum += apu_triangle(&m_APU.tri); + accum += apu_noise(&m_APU.noi); + accum += apu_dpcm(&m_APU.dpcm); + + /* 8-bit clamps */ + if (accum > 127) + accum = 127; + else if (accum < -128) + accum = -128; + + *(outputs[0]++)=accum<<8; + } +} diff --git a/src/devices/sound/nes_apu.h b/src/devices/sound/nes_apu.h new file mode 100644 index 00000000000..48823246e39 --- /dev/null +++ b/src/devices/sound/nes_apu.h @@ -0,0 +1,96 @@ +// license:GPL-2.0+ +// copyright-holders:Matthew Conte +/***************************************************************************** + + MAME/MESS NES APU CORE + + Based on the Nofrendo/Nosefart NES N2A03 sound emulation core written by + Matthew Conte (matt@conte.com) and redesigned for use in MAME/MESS by + Who Wants to Know? (wwtk@mail.com) + + This core is written with the advise and consent of Matthew Conte and is + released under the GNU Public License. This core is freely avaiable for + use in any freeware project, subject to the following terms: + + Any modifications to this code must be duly noted in the source and + approved by Matthew Conte and myself prior to public submission. + + ***************************************************************************** + + NES_APU.H + + NES APU external interface. + + *****************************************************************************/ + +#pragma once + +#ifndef __NES_APU_H__ +#define __NES_APU_H__ + + +/* AN EXPLANATION + * + * The NES APU is actually integrated into the Nintendo processor. + * You must supply the same number of APUs as you do processors. + * Also make sure to correspond the memory regions to those used in the + * processor, as each is shared. + */ + +#include "nes_defs.h" + +/* GLOBAL CONSTANTS */ +#define SYNCS_MAX1 0x20 +#define SYNCS_MAX2 0x80 + +class nesapu_device : public device_t, + public device_sound_interface +{ +public: + nesapu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + ~nesapu_device() {} + + static void set_cpu_tag(device_t &device, const char *tag) { downcast(device).m_cpu_tag = tag; } + + DECLARE_READ8_MEMBER( read ); + DECLARE_WRITE8_MEMBER( write ); + +protected: + // device-level overrides + virtual void device_start(); + + // sound stream update overrides + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + +private: + // internal state + apu_t m_APU; /* Actual APUs */ + float m_apu_incsize; /* Adjustment increment */ + uint32 m_samps_per_sync; /* Number of samples per vsync */ + uint32 m_buffer_size; /* Actual buffer size in bytes */ + uint32 m_real_rate; /* Actual playback rate */ + uint8 m_noise_lut[NOISE_LONG]; /* Noise sample lookup table */ + uint32 m_vbl_times[0x20]; /* VBL durations in samples */ + uint32 m_sync_times1[SYNCS_MAX1]; /* Samples per sync table */ + uint32 m_sync_times2[SYNCS_MAX2]; /* Samples per sync table */ + sound_stream *m_stream; + + const char *m_cpu_tag; + + void create_syncs(unsigned long sps); + int8 apu_square(square_t *chan); + int8 apu_triangle(triangle_t *chan); + int8 apu_noise(noise_t *chan); + int8 apu_dpcm(dpcm_t *chan); + inline void apu_regwrite(int address, uint8 value); + inline uint8 apu_read(int address); + inline void apu_write(int address, uint8 value); +}; + +extern const device_type NES_APU; + +#define MCFG_NES_APU_CPU(_tag) \ + nesapu_device::set_cpu_tag(*device, _tag); + + +#endif /* __NES_APU_H__ */ diff --git a/src/devices/sound/nes_defs.h b/src/devices/sound/nes_defs.h new file mode 100644 index 00000000000..0215a6a1208 --- /dev/null +++ b/src/devices/sound/nes_defs.h @@ -0,0 +1,290 @@ +// license:GPL-2.0+ +// copyright-holders:Matthew Conte +/***************************************************************************** + + MAME/MESS NES APU CORE + + Based on the Nofrendo/Nosefart NES N2A03 sound emulation core written by + Matthew Conte (matt@conte.com) and redesigned for use in MAME/MESS by + Who Wants to Know? (wwtk@mail.com) + + This core is written with the advise and consent of Matthew Conte and is + released under the GNU Public License. This core is freely avaiable for + use in any freeware project, subject to the following terms: + + Any modifications to this code must be duly noted in the source and + approved by Matthew Conte and myself prior to public submission. + + ***************************************************************************** + + NES_DEFS.H + + NES APU internal type definitions and constants. + + *****************************************************************************/ + +#pragma once + +#ifndef __NES_DEFS_H__ +#define __NES_DEFS_H__ + +#include "nes_defs.h" + +/* BOOLEAN CONSTANTS */ +#ifndef TRUE +#define TRUE 1 +#define FALSE 0 +#endif + +/* REGULAR TYPE DEFINITIONS */ +typedef INT8 int8; +typedef INT16 int16; +typedef INT32 int32; +typedef UINT8 uint8; +typedef UINT16 uint16; +typedef UINT32 uint32; +typedef UINT8 boolean; + + +/* QUEUE TYPES */ +#ifdef USE_QUEUE + +#define QUEUE_SIZE 0x2000 +#define QUEUE_MAX (QUEUE_SIZE-1) + +struct queue_t +{ + queue_t(): + pos(0), + reg(""),val("") {} + + int pos; + unsigned char reg, val; +}; + +#endif + +/* REGISTER DEFINITIONS */ +#define APU_WRA0 0x00 +#define APU_WRA1 0x01 +#define APU_WRA2 0x02 +#define APU_WRA3 0x03 +#define APU_WRB0 0x04 +#define APU_WRB1 0x05 +#define APU_WRB2 0x06 +#define APU_WRB3 0x07 +#define APU_WRC0 0x08 +#define APU_WRC2 0x0A +#define APU_WRC3 0x0B +#define APU_WRD0 0x0C +#define APU_WRD2 0x0E +#define APU_WRD3 0x0F +#define APU_WRE0 0x10 +#define APU_WRE1 0x11 +#define APU_WRE2 0x12 +#define APU_WRE3 0x13 +#define APU_SMASK 0x15 +#define APU_IRQCTRL 0x17 + +#define NOISE_LONG 0x4000 +#define NOISE_SHORT 93 + +/* CHANNEL TYPE DEFINITIONS */ + +/* Square Wave */ +struct square_t +{ + square_t() + { + for (int i = 0; i < 4; i++) + { + regs[i] = 0; + } + vbl_length =0; + freq = 0; + phaseacc = 0.0; + output_vol = 0.0; + env_phase = 0.0; + sweep_phase = 0.0; + adder = 0; + env_vol = 0; + enabled = false; + } + + uint8 regs[4]; + int vbl_length; + int freq; + float phaseacc; + float output_vol; + float env_phase; + float sweep_phase; + uint8 adder; + uint8 env_vol; + boolean enabled; +}; + +/* Triangle Wave */ +struct triangle_t +{ + triangle_t() + { + for (int i = 0; i < 4; i++) + { + regs[i] = 0; + } + linear_length =0; + vbl_length =0; + write_latency = 0; + phaseacc = 0.0; + output_vol = 0.0; + adder = 0; + counter_started = false; + enabled = false; + } + + uint8 regs[4]; /* regs[1] unused */ + int linear_length; + int vbl_length; + int write_latency; + float phaseacc; + float output_vol; + uint8 adder; + boolean counter_started; + boolean enabled; +}; + +/* Noise Wave */ +struct noise_t +{ + noise_t() + { + for (int i = 0; i < 4; i++) + { + regs[i] = 0; + } + cur_pos =0; + vbl_length =0; + phaseacc = 0.0; + output_vol = 0.0; + env_phase = 0.0; + env_vol = 0; + enabled = false; + } + + uint8 regs[4]; /* regs[1] unused */ + int cur_pos; + int vbl_length; + float phaseacc; + float output_vol; + float env_phase; + uint8 env_vol; + boolean enabled; +}; + +/* DPCM Wave */ +struct dpcm_t +{ + dpcm_t() + { + for (int i = 0; i < 4; i++) + { + regs[i] = 0; + } + address = 0; + length = 0; + bits_left = 0; + phaseacc = 0.0; + output_vol = 0.0; + cur_byte = 0; + enabled = false; + irq_occurred = false; + memory = NULL; + vol = 0; + } + + uint8 regs[4]; + uint32 address; + uint32 length; + int bits_left; + float phaseacc; + float output_vol; + uint8 cur_byte; + boolean enabled; + boolean irq_occurred; + address_space *memory; + signed char vol; +}; + +/* APU type */ +struct apu_t +{ + apu_t() + { + memset(regs, 0, sizeof(regs)); + buffer = NULL; + buf_pos = 0; + step_mode = 0; + } + + /* Sound channels */ + square_t squ[2]; + triangle_t tri; + noise_t noi; + dpcm_t dpcm; + + /* APU registers */ + unsigned char regs[0x18]; + + /* Sound pointers */ + void *buffer; + +#ifdef USE_QUEUE + + /* Event queue */ + queue_t queue[QUEUE_SIZE]; + int head, tail; + +#else + + int buf_pos; + +#endif + + int step_mode; +}; + +/* CONSTANTS */ + +/* vblank length table used for squares, triangle, noise */ +static const uint8 vbl_length[32] = +{ + 5, 127, 10, 1, 19, 2, 40, 3, 80, 4, 30, 5, 7, 6, 13, 7, + 6, 8, 12, 9, 24, 10, 48, 11, 96, 12, 36, 13, 8, 14, 16, 15 +}; + +/* frequency limit of square channels */ +static const int freq_limit[8] = +{ + 0x3FF, 0x555, 0x666, 0x71C, 0x787, 0x7C1, 0x7E0, 0x7F0, +}; + +/* table of noise frequencies */ +static const int noise_freq[16] = +{ + 4, 8, 16, 32, 64, 96, 128, 160, 202, 254, 380, 508, 762, 1016, 2034, 2046 +}; + +/* dpcm transfer freqs */ +static const int dpcm_clocks[16] = +{ + 428, 380, 340, 320, 286, 254, 226, 214, 190, 160, 142, 128, 106, 85, 72, 54 +}; + +/* ratios of pos/neg pulse for square waves */ +/* 2/16 = 12.5%, 4/16 = 25%, 8/16 = 50%, 12/16 = 75% */ +static const int duty_lut[4] = +{ + 2, 4, 8, 12 +}; + +#endif /* __NES_DEFS_H__ */ diff --git a/src/devices/sound/nile.c b/src/devices/sound/nile.c new file mode 100644 index 00000000000..a0fd9d8b5a5 --- /dev/null +++ b/src/devices/sound/nile.c @@ -0,0 +1,228 @@ +// license:BSD-3-Clause +// copyright-holders:Tomasz Slanina +/************************************ + Seta custom Nile ST-0026 chip + sound emulation by Tomasz Slanina + based on ST-0016 emulation + +8 voices, 16 words of config data for each: + + 00 + 01 - sptr ?? (always 0) + 02 - sptr LO + 03 - sptr HI + 04 + 05 - flags? 00000000 0000?L0? - bit 0 loops, other bits appear to be not used by the chip + 06 - freq + 07 - lsptr LO + 08 + 09 - lsptr HI + 0a - leptr LO + 0b - leptr HI + 0c - eptr LO + 0d - eptr HI + 0e - vol R + 0f - vol L + +************************************/ + +#include "emu.h" +#include "nile.h" + +enum +{ + NILE_REG_UNK0=0, + NILE_REG_SPTR_TOP, + NILE_REG_SPTR_LO, + NILE_REG_SPTR_HI, + NILE_REG_UNK_4, + NILE_REG_FLAGS, + NILE_REG_FREQ, + NILE_REG_LSPTR_LO, + MILE_REG_UNK_8, + NILE_REG_LSPTR_HI, + NILE_REG_LEPTR_LO, + NILE_REG_LEPTR_HI, + NILE_REG_EPTR_LO, + NILE_REG_EPTR_HI, + NILE_REG_VOL_R, + NILE_REG_VOL_L +}; + + +const device_type NILE = &device_creator; + +nile_device::nile_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, NILE, "NiLe", tag, owner, clock, "nile", __FILE__), + device_sound_interface(mconfig, *this), + m_stream(NULL), + m_sound_ram(NULL), + m_ctrl(0) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void nile_device::device_start() +{ + m_sound_ram = region()->base(); + m_stream = stream_alloc(0, 2, 44100); +} + + +//------------------------------------------------- +// sound_stream_update - handle update requests +// for our sound stream +//------------------------------------------------- + +void nile_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + UINT8 *sound_ram = m_sound_ram; + int v, i, snum; + UINT16 *slot; + INT32 mix[48000*2]; + INT32 *mixp; + INT16 sample; + int sptr, eptr, freq, lsptr, leptr; + + lsptr=leptr=0; + + memset(mix, 0, sizeof(mix[0])*samples*2); + + for (v = 0; v < NILE_VOICES; v++) + { + slot = &m_sound_regs[v * 16]; + + if (m_ctrl&(1<> 16; + *mixp++ += (sample * (INT32)slot[NILE_REG_VOL_L]) >> 16; + + m_frac[v] += freq; + m_vpos[v] += m_frac[v]>>16; + m_frac[v] &= 0xffff; + + // stop if we're at the end + if (m_lponce[v]) + { + // we've looped once, check loop end rather than sample end + if ((m_vpos[v] + sptr) >= leptr) + { + m_vpos[v] = (lsptr - sptr); + } + } + else + { + // not looped yet, check sample end + if ((m_vpos[v] + sptr) >= eptr) + { + // code at 11d8c: + // if bit 2 (0x4) is set, check if loop start = loop end. + // if they are equal, clear bit 0 and don't set the loop start/end + // registers in the NiLe. if they aren't, set bit 0 and set + // the loop start/end registers in the NiLe. + if ((slot[NILE_REG_FLAGS] & 0x5) == 0x5) + { + m_vpos[v] = (lsptr - sptr); + m_lponce[v] = 1; + } + else + { + m_ctrl &= ~(1<>4; + outputs[1][i] = (*mixp++)>>4; + } +} + + +WRITE16_MEMBER( nile_device::nile_sndctrl_w ) +{ + UINT16 ctrl=m_ctrl; + + m_stream->update(); + + COMBINE_DATA(&m_ctrl); + +// printf("CTRL: %04x -> %04x (PC=%x)\n", ctrl, m_ctrl, space.device().safe_pc()); + + ctrl^=m_ctrl; +} + + +READ16_MEMBER( nile_device::nile_sndctrl_r ) +{ + m_stream->update(); + return m_ctrl; +} + + +READ16_MEMBER( nile_device::nile_snd_r ) +{ + int reg=offset&0xf; + + m_stream->update(); + + if(reg==2 || reg==3) + { + int slot=offset/16; + int sptr = ((m_sound_regs[slot*16+3]<<16)|m_sound_regs[slot*16+2])+m_vpos[slot]; + + if(reg==2) + { + return sptr&0xffff; + } + else + { + return sptr>>16; + } + } + return m_sound_regs[offset]; +} + + +WRITE16_MEMBER( nile_device::nile_snd_w ) +{ + int v, r; + + m_stream->update(); + + COMBINE_DATA(&m_sound_regs[offset]); + + v = offset / 16; + r = offset % 16; + + if ((r == 2) || (r == 3)) + { + m_vpos[v] = m_frac[v] = m_lponce[v] = 0; + } + + //printf("v%02d: %04x to reg %02d (PC=%x)\n", v, m_sound_regs[offset], r, space.device().safe_pc()); +} diff --git a/src/devices/sound/nile.h b/src/devices/sound/nile.h new file mode 100644 index 00000000000..9aa05d79511 --- /dev/null +++ b/src/devices/sound/nile.h @@ -0,0 +1,60 @@ +// license:BSD-3-Clause +// copyright-holders:Tomasz Slanina +#pragma once + +#ifndef __NILE_H__ +#define __NILE_H__ + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_NILE_ADD(_tag, _clock) \ + MCFG_DEVICE_ADD(_tag, NILE, _clock) +#define MCFG_NILE_REPLACE(_tag, _clock) \ + MCFG_DEVICE_REPLACE(_tag, NILE, _clock) + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +#define NILE_VOICES 8 + +// ======================> nile_device + +class nile_device : public device_t, + public device_sound_interface +{ +public: + nile_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + ~nile_device() { } + +protected: + // device-level overrides + virtual void device_start(); + + // sound stream update overrides + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + +public: + DECLARE_WRITE16_MEMBER( nile_snd_w ); + DECLARE_READ16_MEMBER( nile_snd_r ); + DECLARE_WRITE16_MEMBER( nile_sndctrl_w ); + DECLARE_READ16_MEMBER( nile_sndctrl_r ); + +private: + sound_stream *m_stream; + UINT8 *m_sound_ram; + UINT16 m_sound_regs[0x80]; + int m_vpos[NILE_VOICES]; + int m_frac[NILE_VOICES]; + int m_lponce[NILE_VOICES]; + UINT16 m_ctrl; +}; + +extern const device_type NILE; + + +#endif /* __NILE_H__ */ diff --git a/src/devices/sound/okiadpcm.c b/src/devices/sound/okiadpcm.c new file mode 100644 index 00000000000..611f7e2f13f --- /dev/null +++ b/src/devices/sound/okiadpcm.c @@ -0,0 +1,192 @@ +// license:BSD-3-Clause +// copyright-holders:Andrew Gardner,Aaron Giles +/*************************************************************************** + + okiadpcm.h + + OKI ADCPM emulation. + +***************************************************************************/ + +#include "emu.h" +#include "okiadpcm.h" + + +//************************************************************************** +// ADPCM STATE HELPER +//************************************************************************** + +// ADPCM state and tables +bool oki_adpcm_state::s_tables_computed = false; +const INT8 oki_adpcm_state::s_index_shift[8] = { -1, -1, -1, -1, 2, 4, 6, 8 }; +int oki_adpcm_state::s_diff_lookup[49*16]; + +//------------------------------------------------- +// reset - reset the ADPCM state +//------------------------------------------------- + +void oki_adpcm_state::reset() +{ + // reset the signal/step + m_signal = -2; + m_step = 0; +} + + +//------------------------------------------------- +// device_clock_changed - called if the clock +// changes +//------------------------------------------------- + +INT16 oki_adpcm_state::clock(UINT8 nibble) +{ + // update the signal + m_signal += s_diff_lookup[m_step * 16 + (nibble & 15)]; + + // clamp to the maximum + if (m_signal > 2047) + m_signal = 2047; + else if (m_signal < -2048) + m_signal = -2048; + + // adjust the step size and clamp + m_step += s_index_shift[nibble & 7]; + if (m_step > 48) + m_step = 48; + else if (m_step < 0) + m_step = 0; + + // return the signal + return m_signal; +} + + +//------------------------------------------------- +// compute_tables - precompute tables for faster +// sound generation +//------------------------------------------------- + +void oki_adpcm_state::compute_tables() +{ + // skip if we already did it + if (s_tables_computed) + return; + s_tables_computed = true; + + // nibble to bit map + static const INT8 nbl2bit[16][4] = + { + { 1, 0, 0, 0}, { 1, 0, 0, 1}, { 1, 0, 1, 0}, { 1, 0, 1, 1}, + { 1, 1, 0, 0}, { 1, 1, 0, 1}, { 1, 1, 1, 0}, { 1, 1, 1, 1}, + {-1, 0, 0, 0}, {-1, 0, 0, 1}, {-1, 0, 1, 0}, {-1, 0, 1, 1}, + {-1, 1, 0, 0}, {-1, 1, 0, 1}, {-1, 1, 1, 0}, {-1, 1, 1, 1} + }; + + // loop over all possible steps + for (int step = 0; step <= 48; step++) + { + // compute the step value + int stepval = floor(16.0 * pow(11.0 / 10.0, (double)step)); + + // loop over all nibbles and compute the difference + for (int nib = 0; nib < 16; nib++) + { + s_diff_lookup[step*16 + nib] = nbl2bit[nib][0] * + (stepval * nbl2bit[nib][1] + + stepval/2 * nbl2bit[nib][2] + + stepval/4 * nbl2bit[nib][3] + + stepval/8); + } + } +} + + +//************************************************************************** +// ADPCM2 STATE HELPER +//************************************************************************** + +// ADPCM state and tables +bool oki_adpcm2_state::s_tables_computed = false; +const INT8 oki_adpcm2_state::s_index_shift[8] = { -2, -2, -2, -2, 2, 6, 9, 11 }; +int oki_adpcm2_state::s_diff_lookup[49*16]; + +//------------------------------------------------- +// reset - reset the ADPCM state +//------------------------------------------------- + +void oki_adpcm2_state::reset() +{ + // reset the signal/step + m_signal = -2; + m_step = 0; +} + + +//------------------------------------------------- +// device_clock_changed - called if the clock +// changes +//------------------------------------------------- + +INT16 oki_adpcm2_state::clock(UINT8 nibble) +{ + // update the signal + m_signal += s_diff_lookup[m_step * 16 + (nibble & 15)]; + + // clamp to the maximum + if (m_signal > 2047) + m_signal = 2047; + else if (m_signal < -2048) + m_signal = -2048; + + // adjust the step size and clamp + m_step += s_index_shift[nibble & 7]; + if (m_step > 48) + m_step = 48; + else if (m_step < 0) + m_step = 0; + + // return the signal + return m_signal; +} + + +//------------------------------------------------- +// compute_tables - precompute tables for faster +// sound generation +//------------------------------------------------- + +void oki_adpcm2_state::compute_tables() +{ + // skip if we already did it + if (s_tables_computed) + return; + s_tables_computed = true; + + // nibble to bit map + static const INT8 nbl2bit[16][4] = + { + { 1, 0, 0, 0}, { 1, 0, 0, 1}, { 1, 0, 1, 0}, { 1, 0, 1, 1}, + { 1, 1, 0, 0}, { 1, 1, 0, 1}, { 1, 1, 1, 0}, { 1, 1, 1, 1}, + {-1, 0, 0, 0}, {-1, 0, 0, 1}, {-1, 0, 1, 0}, {-1, 0, 1, 1}, + {-1, 1, 0, 0}, {-1, 1, 0, 1}, {-1, 1, 1, 0}, {-1, 1, 1, 1} + }; + + // loop over all possible steps + float floatstep = 64; + for (int step = 0; step <= 48; step++) + { + // compute the step value + int stepval = floor(floatstep * 1.08f); + floatstep = floatstep * 1.08f; + + // loop over all nibbles and compute the difference + for (int nib = 0; nib < 16; nib++) + { + s_diff_lookup[step*16 + nib] = nbl2bit[nib][0] * + (stepval * nbl2bit[nib][1] + + stepval/2 * nbl2bit[nib][2] + + stepval/4 * nbl2bit[nib][3] + + stepval/8); + } + } +} diff --git a/src/devices/sound/okiadpcm.h b/src/devices/sound/okiadpcm.h new file mode 100644 index 00000000000..311ee9d404f --- /dev/null +++ b/src/devices/sound/okiadpcm.h @@ -0,0 +1,64 @@ +// license:BSD-3-Clause +// copyright-holders:Andrew Gardner,Aaron Giles +/*************************************************************************** + + okiadpcm.h + + OKI ADCPM emulation. + +***************************************************************************/ + +#pragma once + +#ifndef __OKIADPCM_H__ +#define __OKIADPCM_H__ + + +// ======================> oki_adpcm_state + +// Internal ADPCM state, used by external ADPCM generators with compatible specs to the OKIM 6295. +class oki_adpcm_state +{ +public: + oki_adpcm_state() { compute_tables(); reset(); } + + void reset(); + INT16 clock(UINT8 nibble); + + INT32 m_signal; + INT32 m_step; + +private: + static const INT8 s_index_shift[8]; + static int s_diff_lookup[49*16]; + + static void compute_tables(); + static bool s_tables_computed; +}; + + +// ======================> oki_adpcm2_state + +// Internal ADPCM2 state, used by external ADPCM generators with compatible specs to the OKI MSM9810. +// TODO: not thoroughly tested: is the output 15 bit? +class oki_adpcm2_state +{ +public: + oki_adpcm2_state() { compute_tables(); reset(); } + + void reset(); + INT16 clock(UINT8 nibble); + + INT32 m_signal; + INT32 m_step; + +private: + static const INT8 s_index_shift[8]; + static int s_diff_lookup[49*16]; + + static void compute_tables(); + static bool s_tables_computed; +}; + + +#endif // __OKIADPCM_H__ diff --git a/src/devices/sound/okim6258.c b/src/devices/sound/okim6258.c new file mode 100644 index 00000000000..d26810e33d5 --- /dev/null +++ b/src/devices/sound/okim6258.c @@ -0,0 +1,337 @@ +// license:BSD-3-Clause +// copyright-holders:Barry Rodewald +/********************************************************************************************** + * + * OKI MSM6258 ADPCM + * + * TODO: + * 3-bit ADPCM support + * Recording? + * + **********************************************************************************************/ + + +#include "emu.h" +#include "okim6258.h" + +#define COMMAND_STOP (1 << 0) +#define COMMAND_PLAY (1 << 1) +#define COMMAND_RECORD (1 << 2) + +#define STATUS_PLAYING (1 << 1) +#define STATUS_RECORDING (1 << 2) + +static const int dividers[4] = { 1024, 768, 512, 512 }; + +/* step size index shift table */ +static const int index_shift[8] = { -1, -1, -1, -1, 2, 4, 6, 8 }; + +/* lookup table for the precomputed difference */ +static int diff_lookup[49*16]; + +/* tables computed? */ +static int tables_computed = 0; + + + +// device type definition +const device_type OKIM6258 = &device_creator; + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// okim6258_device - constructor +//------------------------------------------------- + +okim6258_device::okim6258_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, OKIM6258, "OKI6258", tag, owner, clock, "okim6258", __FILE__), + device_sound_interface(mconfig, *this), + m_status(0), + m_master_clock(0), + m_divider(0), + m_adpcm_type(0), + m_data_in(0), + m_nibble_shift(0), + m_stream(NULL), + m_output_bits(0), + m_signal(0), + m_step(0) +{ +} + + + +/********************************************************************************************** + + compute_tables -- compute the difference tables + +***********************************************************************************************/ + +static void compute_tables(void) +{ + /* nibble to bit map */ + static const int nbl2bit[16][4] = + { + { 1, 0, 0, 0}, { 1, 0, 0, 1}, { 1, 0, 1, 0}, { 1, 0, 1, 1}, + { 1, 1, 0, 0}, { 1, 1, 0, 1}, { 1, 1, 1, 0}, { 1, 1, 1, 1}, + {-1, 0, 0, 0}, {-1, 0, 0, 1}, {-1, 0, 1, 0}, {-1, 0, 1, 1}, + {-1, 1, 0, 0}, {-1, 1, 0, 1}, {-1, 1, 1, 0}, {-1, 1, 1, 1} + }; + + int step, nib; + + /* loop over all possible steps */ + for (step = 0; step <= 48; step++) + { + /* compute the step value */ + int stepval = floor(16.0 * pow(11.0 / 10.0, (double)step)); + + /* loop over all nibbles and compute the difference */ + for (nib = 0; nib < 16; nib++) + { + diff_lookup[step*16 + nib] = nbl2bit[nib][0] * + (stepval * nbl2bit[nib][1] + + stepval/2 * nbl2bit[nib][2] + + stepval/4 * nbl2bit[nib][3] + + stepval/8); + } + } + + tables_computed = 1; +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void okim6258_device::device_start() +{ + compute_tables(); + + m_master_clock = clock(); + + m_divider = dividers[m_start_divider]; + + m_stream = stream_alloc(0, 1, clock()/m_divider); + + m_signal = -2; + m_step = 0; + + okim6258_state_save_register(); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void okim6258_device::device_reset() +{ + m_stream->update(); + + m_signal = -2; + m_step = 0; + m_status = 0; +} + + +//------------------------------------------------- +// sound_stream_update - handle a stream update +//------------------------------------------------- + +void okim6258_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + stream_sample_t *buffer = outputs[0]; + + memset(outputs[0], 0, samples * sizeof(*outputs[0])); + + if (m_status & STATUS_PLAYING) + { + int nibble_shift = m_nibble_shift; + + while (samples) + { + /* Compute the new amplitude and update the current step */ + int nibble = (m_data_in >> nibble_shift) & 0xf; + + /* Output to the buffer */ + INT16 sample = clock_adpcm(nibble); + + nibble_shift ^= 4; + + *buffer++ = sample; + samples--; + } + + /* Update the parameters */ + m_nibble_shift = nibble_shift; + } + else + { + /* Fill with 0 */ + while (samples--) + *buffer++ = 0; + } +} + + + +/********************************************************************************************** + + state save support for MAME + +***********************************************************************************************/ + +void okim6258_device::okim6258_state_save_register() +{ + save_item(NAME(m_status)); + save_item(NAME(m_master_clock)); + save_item(NAME(m_divider)); + save_item(NAME(m_data_in)); + save_item(NAME(m_nibble_shift)); + save_item(NAME(m_signal)); + save_item(NAME(m_step)); +} + + +INT16 okim6258_device::clock_adpcm(UINT8 nibble) +{ + INT32 max = (1 << (m_output_bits - 1)) - 1; + INT32 min = -(1 << (m_output_bits - 1)); + + m_signal += diff_lookup[m_step * 16 + (nibble & 15)]; + + /* clamp to the maximum */ + if (m_signal > max) + m_signal = max; + else if (m_signal < min) + m_signal = min; + + /* adjust the step size and clamp */ + m_step += index_shift[nibble & 7]; + if (m_step > 48) + m_step = 48; + else if (m_step < 0) + m_step = 0; + + /* return the signal scaled up to 32767 */ + return m_signal << 4; +} + + +/********************************************************************************************** + + okim6258::set_divider -- set the master clock divider + +***********************************************************************************************/ + +void okim6258_device::set_divider(int val) +{ + int divider = dividers[val]; + + m_divider = dividers[val]; + m_stream->set_sample_rate(m_master_clock / divider); +} + + +/********************************************************************************************** + + okim6258::set_clock -- set the master clock + +***********************************************************************************************/ + +void okim6258_device::set_clock(int val) +{ + m_master_clock = val; + m_stream->set_sample_rate(m_master_clock / m_divider); +} + + +/********************************************************************************************** + + okim6258::get_vclk -- get the VCLK/sampling frequency + +***********************************************************************************************/ + +int okim6258_device::get_vclk() +{ + return (m_master_clock / m_divider); +} + + +/********************************************************************************************** + + okim6258_status_r -- read the status port of an OKIM6258-compatible chip + +***********************************************************************************************/ + +READ8_MEMBER( okim6258_device::okim6258_status_r ) +{ + m_stream->update(); + + return (m_status & STATUS_PLAYING) ? 0x00 : 0x80; +} + + +/********************************************************************************************** + + okim6258_data_w -- write to the control port of an OKIM6258-compatible chip + +***********************************************************************************************/ +WRITE8_MEMBER( okim6258_device::okim6258_data_w ) +{ + /* update the stream */ + m_stream->update(); + + m_data_in = data; + m_nibble_shift = 0; +} + + +/********************************************************************************************** + + okim6258_ctrl_w -- write to the control port of an OKIM6258-compatible chip + +***********************************************************************************************/ + +WRITE8_MEMBER( okim6258_device::okim6258_ctrl_w ) +{ + m_stream->update(); + + if (data & COMMAND_STOP) + { + m_status &= ~(STATUS_PLAYING | STATUS_RECORDING); + return; + } + + if (data & COMMAND_PLAY) + { + if (!(m_status & STATUS_PLAYING)) + { + m_status |= STATUS_PLAYING; + + /* Also reset the ADPCM parameters */ + m_signal = -2; + m_step = 0; + m_nibble_shift = 0; + } + } + else + { + m_status &= ~STATUS_PLAYING; + } + + if (data & COMMAND_RECORD) + { + logerror("M6258: Record enabled\n"); + m_status |= STATUS_RECORDING; + } + else + { + m_status &= ~STATUS_RECORDING; + } +} diff --git a/src/devices/sound/okim6258.h b/src/devices/sound/okim6258.h new file mode 100644 index 00000000000..c4cfed1c82c --- /dev/null +++ b/src/devices/sound/okim6258.h @@ -0,0 +1,99 @@ +// license:BSD-3-Clause +// copyright-holders:Barry Rodewald +#pragma once + +#ifndef __OKIM6258_H__ +#define __OKIM6258_H__ + +#define FOSC_DIV_BY_1024 0 +#define FOSC_DIV_BY_768 1 +#define FOSC_DIV_BY_512 2 + +#define TYPE_3BITS 0 +#define TYPE_4BITS 1 + +#define OUTPUT_10BITS 10 +#define OUTPUT_12BITS 12 + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_OKIM6258_ADD(_tag, _clock) \ + MCFG_DEVICE_ADD(_tag, OKIM6258, _clock) +#define MCFG_OKIM6258_REPLACE(_tag, _clock) \ + MCFG_DEVICE_REPLACE(_tag, OKIM6258, _clock) + +#define MCFG_OKIM6258_DIVIDER(_div) \ + okim6258_device::set_start_div(*device, _div); + +#define MCFG_OKIM6258_ADPCM_TYPE(_type) \ + okim6258_device::set_type(*device, _type); + +#define MCFG_OKIM6258_OUT_BITS(_bits) \ + okim6258_device::set_outbits(*device, _bits); + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> okim6258_device + +class okim6258_device : public device_t, + public device_sound_interface +{ +public: + okim6258_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + ~okim6258_device() { } + + // static configuration + static void set_start_div(device_t &device, int div) { downcast(device).m_start_divider = div; } + static void set_type(device_t &device, int type) { downcast(device).m_adpcm_type = type; } + static void set_outbits(device_t &device, int outbit) { downcast(device).m_output_bits = outbit; } + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // sound stream update overrides + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + +public: + DECLARE_READ8_MEMBER( okim6258_status_r ); + DECLARE_WRITE8_MEMBER( okim6258_data_w ); + DECLARE_WRITE8_MEMBER( okim6258_ctrl_w ); + +public: + void set_divider(int val); + void set_clock(int val); + int get_vclk(); + +private: + void okim6258_state_save_register(); + INT16 clock_adpcm(UINT8 nibble); + +private: + UINT8 m_status; + + UINT32 m_master_clock; /* master clock frequency */ + UINT32 m_start_divider; + UINT32 m_divider; /* master clock divider */ + UINT8 m_adpcm_type; /* 3/4 bit ADPCM select */ + UINT8 m_data_in; /* ADPCM data-in register */ + UINT8 m_nibble_shift; /* nibble select */ + sound_stream *m_stream; /* which stream are we playing on? */ + + UINT8 m_output_bits; /* D/A precision is 10-bits but 12-bit data can be + output serially to an external DAC */ + + INT32 m_signal; + INT32 m_step; +}; + +extern const device_type OKIM6258; + + +#endif /* __OKIM6258_H__ */ diff --git a/src/devices/sound/okim6295.c b/src/devices/sound/okim6295.c new file mode 100644 index 00000000000..fc9f35e3a58 --- /dev/null +++ b/src/devices/sound/okim6295.c @@ -0,0 +1,421 @@ +// license:BSD-3-Clause +// copyright-holders:Mirko Buffoni,Aaron Giles +/*************************************************************************** + + okim6295.h + + OKIM 6295 ADCPM sound chip. + +**************************************************************************** + + Library to transcode from an ADPCM source to raw PCM. + Written by Buffoni Mirko in 08/06/97 + References: various sources and documents. + + R. Belmont 31/10/2003 + Updated to allow a driver to use both MSM6295s and "raw" ADPCM voices + (gcpinbal). Also added some error trapping for MAME_DEBUG builds + +**************************************************************************** + + OKIM 6295 ADPCM chip: + + Command bytes are sent: + + 1xxx xxxx = start of 2-byte command sequence, xxxxxxx is the sample + number to trigger + abcd vvvv = second half of command; one of the abcd bits is set to + indicate which voice the v bits seem to be volumed + + 0abc d000 = stop playing; one or more of the abcd bits is set to + indicate which voice(s) + + Status is read: + + ???? abcd = one bit per voice, set to 0 if nothing is playing, or + 1 if it is active + +***************************************************************************/ + +#include "emu.h" +#include "okim6295.h" + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +// device type definition +const device_type OKIM6295 = &device_creator; + +// volume lookup table. The manual lists only 9 steps, ~3dB per step. Given the dB values, +// that seems to map to a 5-bit volume control. Any volume parameter beyond the 9th index +// results in silent playback. +const UINT8 okim6295_device::s_volume_table[16] = +{ + 0x20, // 0 dB + 0x16, // -3.2 dB + 0x10, // -6.0 dB + 0x0b, // -9.2 dB + 0x08, // -12.0 dB + 0x06, // -14.5 dB + 0x04, // -18.0 dB + 0x03, // -20.5 dB + 0x02, // -24.0 dB + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, +}; + +// default address map +static ADDRESS_MAP_START( okim6295, AS_0, 8, okim6295_device ) + AM_RANGE(0x00000, 0x3ffff) AM_ROM +ADDRESS_MAP_END + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// okim6295_device - constructor +//------------------------------------------------- + +okim6295_device::okim6295_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, OKIM6295, "OKI6295", tag, owner, clock, "okim6295", __FILE__), + device_sound_interface(mconfig, *this), + device_memory_interface(mconfig, *this), + m_space_config("samples", ENDIANNESS_LITTLE, 8, 18, 0, NULL, *ADDRESS_MAP_NAME(okim6295)), + m_command(-1), + m_bank_installed(false), + m_bank_offs(0), + m_stream(NULL), + m_pin7_state(0), + m_direct(NULL) +{ +} + + +//------------------------------------------------- +// static_set_pin7 - configuration helper to set +// the pin 7 state +//------------------------------------------------- + +void okim6295_device::static_set_pin7(device_t &device, int pin7) +{ + okim6295_device &okim6295 = downcast(device); + okim6295.m_pin7_state = pin7; +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void okim6295_device::device_start() +{ + // find our direct access + m_direct = &space().direct(); + + // create the stream + int divisor = m_pin7_state ? 132 : 165; + m_stream = machine().sound().stream_alloc(*this, 0, 1, clock() / divisor); + + save_item(NAME(m_command)); + save_item(NAME(m_bank_offs)); + save_item(NAME(m_pin7_state)); + + for (int voicenum = 0; voicenum < OKIM6295_VOICES; voicenum++) + { + save_item(NAME(m_voice[voicenum].m_playing), voicenum); + save_item(NAME(m_voice[voicenum].m_sample), voicenum); + save_item(NAME(m_voice[voicenum].m_count), voicenum); + save_item(NAME(m_voice[voicenum].m_adpcm.m_signal), voicenum); + save_item(NAME(m_voice[voicenum].m_adpcm.m_step), voicenum); + save_item(NAME(m_voice[voicenum].m_volume), voicenum); + save_item(NAME(m_voice[voicenum].m_base_offset), voicenum); + } +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void okim6295_device::device_reset() +{ + m_stream->update(); + for (int voicenum = 0; voicenum < OKIM6295_VOICES; voicenum++) + m_voice[voicenum].m_playing = false; +} + + +//------------------------------------------------- +// device_post_load - device-specific post-load +//------------------------------------------------- + +void okim6295_device::device_post_load() +{ + set_bank_base(m_bank_offs, true); + device_clock_changed(); +} + + +//------------------------------------------------- +// device_clock_changed - called if the clock +// changes +//------------------------------------------------- + +void okim6295_device::device_clock_changed() +{ + int divisor = m_pin7_state ? 132 : 165; + m_stream->set_sample_rate(clock() / divisor); +} + + +//------------------------------------------------- +// memory_space_config - return a description of +// any address spaces owned by this device +//------------------------------------------------- + +const address_space_config *okim6295_device::memory_space_config(address_spacenum spacenum) const +{ + return (spacenum == 0) ? &m_space_config : NULL; +} + + +//------------------------------------------------- +// stream_generate - handle update requests for +// our sound stream +//------------------------------------------------- + +void okim6295_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + // reset the output stream + memset(outputs[0], 0, samples * sizeof(*outputs[0])); + + // iterate over voices and accumulate sample data + for (int voicenum = 0; voicenum < OKIM6295_VOICES; voicenum++) + m_voice[voicenum].generate_adpcm(*m_direct, outputs[0], samples); +} + + +//------------------------------------------------- +// set_bank_base - old-style bank management; +// assumes multiple 256k banks +//------------------------------------------------- + +void okim6295_device::set_bank_base(offs_t base, bool bDontUpdateStream) +{ + // flush out anything pending (but not on e.g. a state load) + if (!bDontUpdateStream) + { + m_stream->update(); + } + + // if we are setting a non-zero base, and we have no bank, allocate one + if (!m_bank_installed && base != 0) + { + // override our memory map with a bank + space().install_read_bank(0x00000, 0x3ffff, tag()); + m_bank_installed = true; + } + + // if we have a bank number, set the base pointer + if (m_bank_installed) + { + m_bank_offs = base; + membank(tag())->set_base(m_region->base() + base); + } +} + + +//------------------------------------------------- +// set_pin7 - change the state of pin 7, which +// alters the frequency we output +//------------------------------------------------- + +void okim6295_device::set_pin7(int pin7) +{ + m_pin7_state = pin7; + device_clock_changed(); +} + + +//------------------------------------------------- +// read_status - read the status register +//------------------------------------------------- + +UINT8 okim6295_device::read_status() +{ + UINT8 result = 0xf0; // naname expects bits 4-7 to be 1 + + // set the bit to 1 if something is playing on a given channel + m_stream->update(); + for (int voicenum = 0; voicenum < OKIM6295_VOICES; voicenum++) + if (m_voice[voicenum].m_playing) + result |= 1 << voicenum; + + return result; +} + + +//------------------------------------------------- +// read - memory interface for read +//------------------------------------------------- + +READ8_MEMBER( okim6295_device::read ) +{ + return read_status(); +} + + +//------------------------------------------------- +// write_command - write to the command register +//------------------------------------------------- + +void okim6295_device::write_command(UINT8 command) +{ + // if a command is pending, process the second half + if (m_command != -1) + { + // the manual explicitly says that it's not possible to start multiple voices at the same time + int voicemask = command >> 4; + //if (voicemask != 0 && voicemask != 1 && voicemask != 2 && voicemask != 4 && voicemask != 8) + // popmessage("OKI6295 start %x contact MAMEDEV", voicemask); + + // update the stream + m_stream->update(); + + // determine which voice(s) (voice is set by a 1 bit in the upper 4 bits of the second byte) + for (int voicenum = 0; voicenum < OKIM6295_VOICES; voicenum++, voicemask >>= 1) + if (voicemask & 1) + { + okim_voice &voice = m_voice[voicenum]; + + if (!voice.m_playing) // fixes Got-cha and Steel Force + { + // determine the start/stop positions + offs_t base = m_command * 8; + + offs_t start = m_direct->read_byte(base + 0) << 16; + start |= m_direct->read_byte(base + 1) << 8; + start |= m_direct->read_byte(base + 2) << 0; + start &= 0x3ffff; + + offs_t stop = m_direct->read_byte(base + 3) << 16; + stop |= m_direct->read_byte(base + 4) << 8; + stop |= m_direct->read_byte(base + 5) << 0; + stop &= 0x3ffff; + + if (start < stop) + { + // set up the voice to play this sample + voice.m_playing = true; + voice.m_base_offset = start; + voice.m_sample = 0; + voice.m_count = 2 * (stop - start + 1); + + // also reset the ADPCM parameters + voice.m_adpcm.reset(); + voice.m_volume = s_volume_table[command & 0x0f]; + } + + // invalid samples go here + else + { + logerror("OKIM6295:'%s' requested to play invalid sample %02x\n",tag(),m_command); + } + } + else + { + logerror("OKIM6295:'%s' requested to play sample %02x on non-stopped voice\n",tag(),m_command); + } + } + + // reset the command + m_command = -1; + } + + // if this is the start of a command, remember the sample number for next time + else if (command & 0x80) + m_command = command & 0x7f; + + // otherwise, see if this is a silence command + else + { + // update the stream, then turn it off + m_stream->update(); + + // determine which voice(s) (voice is set by a 1 bit in bits 3-6 of the command + int voicemask = command >> 3; + for (int voicenum = 0; voicenum < OKIM6295_VOICES; voicenum++, voicemask >>= 1) + if (voicemask & 1) + m_voice[voicenum].m_playing = false; + } +} + + +//------------------------------------------------- +// write - memory interface for write +//------------------------------------------------- + +WRITE8_MEMBER( okim6295_device::write ) +{ + write_command(data); +} + + + +//************************************************************************** +// OKIM VOICE +//************************************************************************** + +//------------------------------------------------- +// okim_voice - constructor +//------------------------------------------------- + +okim6295_device::okim_voice::okim_voice() + : m_playing(false), + m_base_offset(0), + m_sample(0), + m_count(0), + m_volume(0) +{ +} + + +//------------------------------------------------- +// generate_adpcm - generate ADPCM samples and +// add them to an output stream +//------------------------------------------------- + +void okim6295_device::okim_voice::generate_adpcm(direct_read_data &direct, stream_sample_t *buffer, int samples) +{ + // skip if not active + if (!m_playing) + return; + + // loop while we still have samples to generate + while (samples-- != 0) + { + // fetch the next sample byte + int nibble = direct.read_byte(m_base_offset + m_sample / 2) >> (((m_sample & 1) << 2) ^ 4); + + // output to the buffer, scaling by the volume + // signal in range -2048..2047, volume in range 2..32 => signal * volume / 2 in range -32768..32767 + *buffer++ += m_adpcm.clock(nibble) * m_volume / 2; + + // next! + if (++m_sample >= m_count) + { + m_playing = false; + break; + } + } +} diff --git a/src/devices/sound/okim6295.h b/src/devices/sound/okim6295.h new file mode 100644 index 00000000000..33c8962767a --- /dev/null +++ b/src/devices/sound/okim6295.h @@ -0,0 +1,126 @@ +// license:BSD-3-Clause +// copyright-holders:Mirko Buffoni,Aaron Giles +/*************************************************************************** + + okim6295.h + + OKIM 6295 ADCPM sound chip. + +***************************************************************************/ + +#pragma once + +#ifndef __OKIM6295_H__ +#define __OKIM6295_H__ + +#include "sound/okiadpcm.h" + + + +//************************************************************************** +// CONSTANTS +//************************************************************************** + +enum +{ + OKIM6295_PIN7_LOW = 0, + OKIM6295_PIN7_HIGH = 1 +}; + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_OKIM6295_ADD(_tag, _clock, _pin7) \ + MCFG_DEVICE_ADD(_tag, OKIM6295, _clock) \ + MCFG_OKIM6295_PIN7(_pin7) + +#define MCFG_OKIM6295_REPLACE(_tag, _clock, _pin7) \ + MCFG_DEVICE_REPLACE(_tag, OKIM6295, _clock) \ + MCFG_OKIM6295_PIN7(_pin7) + +#define MCFG_OKIM6295_PIN7(_pin7) \ + okim6295_device::static_set_pin7(*device, _pin7); + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + + +// ======================> okim6295_device + +class okim6295_device : public device_t, + public device_sound_interface, + public device_memory_interface +{ +public: + // construction/destruction + okim6295_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // inline configuration helpers + static void static_set_pin7(device_t &device, int pin7); + + // runtime configuration + void set_bank_base(offs_t base, bool bDontUpdateStream = false); + void set_pin7(int pin7); + + UINT8 read_status(); + void write_command(UINT8 command); + + DECLARE_READ8_MEMBER( read ); + DECLARE_WRITE8_MEMBER( write ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_post_load(); + virtual void device_clock_changed(); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const; + + // device_sound_interface overrides + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + + // a single voice + class okim_voice + { + public: + okim_voice(); + void generate_adpcm(direct_read_data &direct, stream_sample_t *buffer, int samples); + + oki_adpcm_state m_adpcm; // current ADPCM state + bool m_playing; + offs_t m_base_offset; // pointer to the base memory location + UINT32 m_sample; // current sample number + UINT32 m_count; // total samples to play + INT8 m_volume; // output volume + }; + + // configuration state + const address_space_config m_space_config; + + // internal state + static const int OKIM6295_VOICES = 4; + + okim_voice m_voice[OKIM6295_VOICES]; + INT32 m_command; + bool m_bank_installed; + offs_t m_bank_offs; + sound_stream * m_stream; + UINT8 m_pin7_state; + direct_read_data * m_direct; + + static const UINT8 s_volume_table[16]; +}; + + +// device type definition +extern const device_type OKIM6295; + + +#endif /* __OKIM6295_H__ */ diff --git a/src/devices/sound/okim6376.c b/src/devices/sound/okim6376.c new file mode 100644 index 00000000000..2db0a475b04 --- /dev/null +++ b/src/devices/sound/okim6376.c @@ -0,0 +1,581 @@ +// license:BSD-3-Clause +// copyright-holders:Mirko Buffoni, James Wallace +/********************************************************************************************** + * + * OKI MSM6376 ADPCM + * by Mirko Buffoni, J. Wallace + * + * TODO: + * add BEEP tone generator + * confirm echo + * sample divisor in ROM table not implemented (no documentation) + * modernise + **********************************************************************************************/ + + +#include "emu.h" +#include "okim6376.h" + +#define MAX_SAMPLE_CHUNK 10000 +//#define MAX_WORDS 111 + +#define OKIVERBOSE 0 +#define MSM6376LOG(x) do { if (OKIVERBOSE) logerror x; } while (0) + +/* step size index shift table */ +static const int index_shift[8] = { -1, -1, -1, -1, 2, 4, 6, 8 }; + +/* lookup table for the precomputed difference */ +static int diff_lookup[49*16]; + +/* volume lookup table. Upon configuration, the number of ST pulses determine how much + attenuation to apply to the sound signal. However, this only applies to the second + channel*/ +static const int volume_table[3] = +{ + 0x20, // 0 dB + 0x10, // -6.0 dB + 0x08, // -12.0 dB +}; + +/* divisor lookup table. When an individual word is selected, it can be assigned one of three different 'rates'. + These are implemented as clock divisors, and are looked up in the ROM header. More often than not, this value is 0, + relating to a division by 8, or nominally 8KHz sampling (based on the datasheet example of a 64KHz clock).*/ +static const int divisor_table[3] = +{ + 8, + 10, + 16, +}; + +/* tables computed? */ +static int tables_computed = 0; + +/********************************************************************************************** + + compute_tables -- compute the difference tables + +***********************************************************************************************/ + +static void compute_tables(void) +{ + /* nibble to bit map */ + static const int nbl2bit[16][4] = + { + { 1, 0, 0, 0}, { 1, 0, 0, 1}, { 1, 0, 1, 0}, { 1, 0, 1, 1}, + { 1, 1, 0, 0}, { 1, 1, 0, 1}, { 1, 1, 1, 0}, { 1, 1, 1, 1}, + {-1, 0, 0, 0}, {-1, 0, 0, 1}, {-1, 0, 1, 0}, {-1, 0, 1, 1}, + {-1, 1, 0, 0}, {-1, 1, 0, 1}, {-1, 1, 1, 0}, {-1, 1, 1, 1} + }; + + int step, nib; + + /* loop over all possible steps */ + for (step = 0; step <= 48; step++) + { + /* compute the step value */ + int stepval = floor(16.0 * pow(11.0 / 10.0, (double)step)); + + /* loop over all nibbles and compute the difference */ + for (nib = 0; nib < 16; nib++) + { + diff_lookup[step*16 + nib] = nbl2bit[nib][0] * + (stepval * nbl2bit[nib][1] + + stepval/2 * nbl2bit[nib][2] + + stepval/4 * nbl2bit[nib][3] + + stepval/8); + } + } + + tables_computed = 1; +} + + + +/********************************************************************************************** + + reset_adpcm -- reset the ADPCM stream + +***********************************************************************************************/ + +static void reset_adpcm(struct ADPCMVoice *voice) +{ + /* make sure we have our tables */ + if (!tables_computed) + compute_tables(); + + /* reset the signal/step */ + voice->signal = -2; + voice->step = 0; +} + + +const device_type OKIM6376 = &device_creator; + +okim6376_device::okim6376_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, OKIM6376, "OKI6376", tag, owner, clock, "okim6376", __FILE__), + device_sound_interface(mconfig, *this), + m_region_base(*this, DEVICE_SELF), + //m_command[OKIM6376_VOICES], + m_latch(0), + //m_stage[OKIM6376_VOICES], + m_stream(NULL), + m_master_clock(0), + m_divisor(0), + m_channel(0), + m_nar(0), + m_nartimer(0), + m_busy(0), + m_ch2(0), + m_st(0), + m_st_pulses(0), + m_ch2_update(0), + m_st_update(0) +{ +} + +//------------------------------------------------- +// device_config_complete - perform any +// operations now that the configuration is +// complete +//------------------------------------------------- + +void okim6376_device::device_config_complete() +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void okim6376_device::device_start() +{ + int voice; + compute_tables(); + + m_command[0] = -1; + m_command[1] = -1; + m_stage[0] = 0; + m_stage[1] = 0; + m_latch = 0; + m_master_clock = clock(); + m_divisor = divisor_table[0]; + m_nar = 1; + m_nartimer = 0; + m_busy = 1; + m_st = 1; + m_ch2 = 1; + m_st_update = 0; + m_ch2_update = 0; + m_st_pulses = 0; + /* generate the name and create the stream */ + m_stream = machine().sound().stream_alloc(*this, 0, 1, clock() / m_divisor); + + /* initialize the voices */ + for (voice = 0; voice < OKIM6376_VOICES; voice++) + { + /* initialize the rest of the structure */ + m_voice[voice].volume = 0; + reset_adpcm(&m_voice[voice]); + } + + okim6376_state_save_register(); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void okim6376_device::device_reset() +{ + int i; + + m_stream->update(); + for (i = 0; i < OKIM6376_VOICES; i++) + m_voice[i].playing = 0; +} + + +/********************************************************************************************** + + clock_adpcm -- clock the next ADPCM byte + +***********************************************************************************************/ + +static INT16 clock_adpcm(struct ADPCMVoice *voice, UINT8 nibble) +{ + voice->signal += diff_lookup[voice->step * 16 + (nibble & 15)]; + + /* clamp to the maximum 12bit */ + if (voice->signal > 2047) + voice->signal = 2047; + else if (voice->signal < -2048) + voice->signal = -2048; + + /* adjust the step size and clamp */ + voice->step += index_shift[nibble & 7]; + if (voice->step > 48) + voice->step = 48; + else if (voice->step < 0) + voice->step = 0; + + /* return the signal */ + return voice->signal; +} + + +void okim6376_device::oki_process(int channel, int command) +{ + /* if a command is pending, process the second half */ + if ((command != -1) && (command != 0)) //process silence separately + { + int start; + unsigned char *base/*, *base_end*/; + /* update the stream */ + m_stream->update(); + + /* determine which voice(s) (voice is set by the state of 2CH) */ + { + struct ADPCMVoice *voice = &m_voice[channel]; + + /* determine the start position, max address space is 16Mbit */ + base = &m_region_base[m_command[channel] * 4]; + //base_end = &m_region_base[(MAX_WORDS+1) * 4]; + start = ((base[0] << 16) + (base[1] << 8) + base[2]) & 0x1fffff; + + if (start == 0) + { + voice->playing = 0; + } + else + { + /* set up the voice to play this sample */ + if (!voice->playing) + { + voice->playing = 1; + voice->base_offset = start; + voice->sample = 0; + voice->count = 0; + + /* also reset the ADPCM parameters */ + reset_adpcm(voice); + if (channel == 0) + { + /* We set channel 2's audio separately */ + voice->volume = volume_table[0]; + } + } + else + { + if (((m_nar)&&(channel == 0))||(channel == 1))//Store the request, for later processing (channel 2 ignores NAR) + { + m_stage[channel] = 1; + } + } + } + } + } + /* otherwise, see if this is a silence command */ + else + { + /* update the stream, then turn it off */ + m_stream->update(); + + if (command ==0) + { + int i; + for (i = 0; i < OKIM6376_VOICES; i++) + { + struct ADPCMVoice *voice = &m_voice[i]; + voice->playing = 0; + } + } + } +} + + +/********************************************************************************************** + + generate_adpcm -- general ADPCM decoding routine + +***********************************************************************************************/ + +void okim6376_device::generate_adpcm(struct ADPCMVoice *voice, INT16 *buffer, int samples,int channel) +{ + /* if this voice is active */ + if (voice->playing) + { + UINT8 *base = m_region_base + voice->base_offset; + int sample = voice->sample; + int count = voice->count; + + /* loop while we still have samples to generate */ + while (samples) + { + int nibble; + + if (count == 0) + { + /* get the number of samples to play */ + count = (base[sample / 2] & 0x7f) << 1; + + /* end of voice marker */ + if (count == 0) + { + voice->playing = 0; + break; + } + else + { + /* step past the count byte */ + sample += 2; + } + } + + /* compute the new amplitude and update the current step */ + nibble = base[sample / 2] >> (((sample & 1) << 2) ^ 4); + + /* output to the buffer, scaling by the volume */ + /* signal in range -4096..4095, volume in range 2..16 => signal * volume / 2 in range -32768..32767 */ + *buffer++ = clock_adpcm(voice, nibble) * voice->volume / 2; + + ++sample; + --count; + --samples; + } + + /* update the parameters */ + voice->sample = sample; + voice->count = count; + } + + /* fill the rest with silence */ + while (samples--) + *buffer++ = 0; + + if ((!voice->playing)&&(m_stage[channel]))//end of samples, load anything staged in + { + m_stage[channel] = 0; + oki_process(channel,m_command[channel]); + } +} + + +/********************************************************************************************** + + state save support for MAME + +***********************************************************************************************/ + +void okim6376_device::postload() +{ + set_frequency(m_master_clock); +} + +void okim6376_device::adpcm_state_save_register(struct ADPCMVoice *voice, int index) +{ + save_item(NAME(voice->playing), index); + save_item(NAME(voice->sample), index); + save_item(NAME(voice->count), index); + save_item(NAME(voice->signal), index); + save_item(NAME(voice->step), index); + save_item(NAME(voice->volume), index); + save_item(NAME(voice->base_offset), index); +} + +void okim6376_device::okim6376_state_save_register() +{ + int j; + for (j = 0; j < OKIM6376_VOICES; j++) + { + adpcm_state_save_register(&m_voice[j], j); + } + machine().save().register_postload(save_prepost_delegate(FUNC(okim6376_device::postload), this)); + save_item(NAME(m_command[0])); + save_item(NAME(m_command[1])); + save_item(NAME(m_stage[0])); + save_item(NAME(m_stage[1])); + save_item(NAME(m_latch)); + save_item(NAME(m_divisor)); + save_item(NAME(m_nar)); + save_item(NAME(m_nartimer)); + save_item(NAME(m_busy)); + save_item(NAME(m_st)); + save_item(NAME(m_st_pulses)); + save_item(NAME(m_st_update)); + save_item(NAME(m_ch2)); + save_item(NAME(m_ch2_update)); + save_item(NAME(m_master_clock)); +} + +void okim6376_device::set_frequency(int frequency) +{ + m_master_clock = frequency; + m_stream->set_sample_rate(m_master_clock / m_divisor); +} + + +/********************************************************************************************** + + okim6376_status_r -- read the status port of an OKIM6376-compatible chip + +***********************************************************************************************/ + +READ_LINE_MEMBER( okim6376_device::busy_r ) +{ + struct ADPCMVoice *voice0 = &m_voice[0]; + struct ADPCMVoice *voice1 = &m_voice[1]; + + /* set the bit low if it's playing */ + if ((voice0->playing)||(voice1->playing)) + { + return 0; + } + else + { + return 1; + } +} + +READ_LINE_MEMBER( okim6376_device::nar_r ) +{ + MSM6376LOG(("OKIM6376:'%s' NAR %x\n",tag(),m_nar)); + return m_nar; +} + +WRITE_LINE_MEMBER( okim6376_device::ch2_w ) +{ + m_ch2_update = 0;//Clear flag + MSM6376LOG(("OKIM6376:'%s' CH2 %x\n",tag(),state)); + + if (m_ch2 != state) + { + m_ch2 = state; + m_ch2_update = 1; + } + if((!m_ch2)&&(m_ch2_update)) + { + m_st_pulses = 0; + struct ADPCMVoice *voice0 = &m_voice[0]; + struct ADPCMVoice *voice1 = &m_voice[1]; + // We set to channel 2 + MSM6376LOG(("OKIM6376:'%s' Channel 1\n",tag())); + m_channel = 1; + + if ((voice0->playing)&&(m_st)) + { + //Echo functions when Channel 1 is playing, and ST is still high + m_command[1] = m_command[0];//copy sample over + voice1->volume = volume_table[1]; //echo is 6dB attenuated + } + } + + if((m_ch2)&&(m_ch2_update)) + { + m_stage[1]=0; + oki_process(1, m_command[1]); + MSM6376LOG(("OKIM6376:'%s' Channel 0\n",tag())); + m_channel = 0; + } +} + + +WRITE_LINE_MEMBER( okim6376_device::st_w ) +{ + //As in STart, presumably, this triggers everything + + m_st_update = 0;//Clear flag + MSM6376LOG(("OKIM6376:'%s' ST %x\n",tag(),state)); + + if (m_st != state) + { + m_st = state; + m_st_update = 1; + + if ((m_channel == 1) & !m_st)//ST acts as attenuation for Channel 2 when low, and stays at that level until the channel is reset + { + struct ADPCMVoice *voice = &m_voice[m_channel]; + { + m_st_pulses ++; + MSM6376LOG(("OKIM6376:'%s' ST pulses %x\n",tag(),m_st_pulses)); + if (m_st_pulses > 3) + { + m_st_pulses = 3; //undocumented behaviour beyond 3 pulses + } + + voice->volume = volume_table[m_st_pulses - 1]; + } + } + if (m_st && m_st_update) + { + m_command[m_channel] = m_latch; + if (m_channel ==0 && m_nar) + { + m_stage[m_channel]=0; + oki_process(0, m_command[0]); + m_nar = 0; + m_nartimer = 4; + /*According to datasheet, NAR timing is ~375 us at 8KHz, and is inversely proportional to sample rate, effectively 6 stream updates. */ + } + } + } +} + +/********************************************************************************************** + + okim6376_data_w -- write to the data port of an OKIM6376-compatible chip + +***********************************************************************************************/ + +WRITE8_MEMBER( okim6376_device::write ) +{ + // The data port is purely used to set the latch, everything else is started by an ST pulse + + m_latch = data & 0x7f; + // FIX: maximum adpcm words are 111, there are other 8 commands to generate BEEP tone (0x70 to 0x77), + // and others for internal testing, that manual explicitly says not to use (0x78 to 0x7f) + // We aren't doing anything with the BEEP at the moment, as we'd need to mix the ADPCM stream with beep.c +} + +//------------------------------------------------- +// sound_stream_update - handle a stream update +//------------------------------------------------- + +void okim6376_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + int i; + + memset(outputs[0], 0, samples * sizeof(*outputs[0])); + + for (i = 0; i < OKIM6376_VOICES; i++) + { + struct ADPCMVoice *voice = &m_voice[i]; + stream_sample_t *buffer = outputs[0]; + INT16 sample_data[MAX_SAMPLE_CHUNK]; + int remaining = samples; + if (i == 0) //channel 1 is the only channel to affect NAR + { + if (m_nartimer > 0) + { + m_nartimer--; + if (!m_nartimer) + { + m_nar =1; + } + } + } + + /* loop while we have samples remaining */ + while (remaining) + { + int samples = (remaining > MAX_SAMPLE_CHUNK) ? MAX_SAMPLE_CHUNK : remaining; + int samp; + + generate_adpcm(voice, sample_data, samples,i); + for (samp = 0; samp < samples; samp++) + *buffer++ += sample_data[samp]; + + remaining -= samples; + } + } +} diff --git a/src/devices/sound/okim6376.h b/src/devices/sound/okim6376.h new file mode 100644 index 00000000000..df87344eb50 --- /dev/null +++ b/src/devices/sound/okim6376.h @@ -0,0 +1,82 @@ +// license:BSD-3-Clause +// copyright-holders:Mirko Buffoni, James Wallace +#pragma once + +#ifndef __OKIM6376_H__ +#define __OKIM6376_H__ + +/* an interface for the OKIM6376 and similar chips (CPU interface only) */ + +/* struct describing a single playing ADPCM voice */ +struct ADPCMVoice +{ + UINT8 playing; /* 1 if we are actively playing */ + + UINT32 base_offset; /* pointer to the base memory location */ + UINT32 sample; /* current sample number */ + UINT32 count; /* total samples to play */ + + UINT32 volume; /* output volume */ + INT32 signal; + INT32 step; +}; + +class okim6376_device : public device_t, + public device_sound_interface +{ +public: + okim6376_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + ~okim6376_device() {} + + DECLARE_WRITE8_MEMBER( write ); + + DECLARE_WRITE_LINE_MEMBER( st_w ); + DECLARE_WRITE_LINE_MEMBER( ch2_w ); + + DECLARE_READ_LINE_MEMBER( busy_r ); + DECLARE_READ_LINE_MEMBER( nar_r ); + + void set_frequency(int frequency); + + +protected: + // device-level overrides + virtual void device_config_complete(); + virtual void device_start(); + virtual void device_reset(); + + // sound stream update overrides + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + +private: + // internal state + required_region_ptr m_region_base; /* pointer to the base of the region */ + + #define OKIM6376_VOICES 2 + struct ADPCMVoice m_voice[OKIM6376_VOICES]; + INT32 m_command[OKIM6376_VOICES]; + INT32 m_latch; /* Command data is held before transferring to either channel */ + UINT8 m_stage[OKIM6376_VOICES];/* If a sample is playing, flag that we have a command staged */ + sound_stream *m_stream; /* which stream are we playing on? */ + UINT32 m_master_clock; /* master clock frequency */ + UINT8 m_divisor; /* can be 8,10,16, and is read out of ROM data */ + UINT8 m_channel; + UINT8 m_nar; /* Next Address Ready */ + UINT8 m_nartimer; + UINT8 m_busy; + UINT8 m_ch2; /* 2CH pin - enables Channel 2 operation */ + UINT8 m_st; /* STart */ + UINT8 m_st_pulses; /* Keep track of attenuation */ + UINT8 m_ch2_update; /* Pulse shape */ + UINT8 m_st_update; + + void oki_process(int channel, int command); + void generate_adpcm(struct ADPCMVoice *voice, INT16 *buffer, int samples,int channel); + void postload(); + void okim6376_state_save_register(); + void adpcm_state_save_register(struct ADPCMVoice *voice, int index); +}; + +extern const device_type OKIM6376; + +#endif /* __OKIM6376_H__ */ diff --git a/src/devices/sound/okim9810.c b/src/devices/sound/okim9810.c new file mode 100644 index 00000000000..e134e646ddb --- /dev/null +++ b/src/devices/sound/okim9810.c @@ -0,0 +1,585 @@ +// license:BSD-3-Clause +// copyright-holders:Andrew Gardner +/*************************************************************************** + + okim9810.h + + OKI MSM9810 ADPCM(2) sound chip. + +***************************************************************************/ + +#include "emu.h" +#include "okim9810.h" + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +// device type definition +const device_type OKIM9810 = &device_creator; + +// volume lookup table. The manual lists a full 16 steps, 2dB per step. +// Given the dB values, that seems to map to a 7-bit volume control. +const UINT8 okim9810_device::okim_voice::s_volume_table[16] = +{ + 0x80, // 0 dB + 0x65, // -2 dB + 0x50, // -4 dB + 0x40, // -6 dB + 0x32, // -8.0 dB + 0x28, // -10.5 dB + 0x20, // -12.0 dB + 0x19, // -14.5 dB + 0x14, // -16.0 dB + 0x10, // -18.0 dB + 0x0c, // -20.0 dB + 0x0a, // -22.0 dB + 0x08, // -24.0 dB + 0x06, // -26.0 dB + 0x05, // -28.0 dB + 0x04, // -30.0 dB +}; + +// sampling frequency lookup table. +const UINT32 okim9810_device::s_sampling_freq_table[16] = +{ + 4000, + 8000, + 16000, + 32000, + 0, + 6400, + 12800, + 25600, + 0, + 5300, + 10600, + 21200, + 0, + 0, + 0, + 0 +}; + +// default address map +static ADDRESS_MAP_START( okim9810, AS_0, 8, okim9810_device ) + AM_RANGE(0x000000, 0xffffff) AM_ROM +ADDRESS_MAP_END + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// okim9810_device - constructor +//------------------------------------------------- + +okim9810_device::okim9810_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, OKIM9810, "OKI9810", tag, owner, clock, "okim9810", __FILE__), + device_sound_interface(mconfig, *this), + device_memory_interface(mconfig, *this), + m_space_config("samples", ENDIANNESS_BIG, 8, 24, 0, NULL, *ADDRESS_MAP_NAME(okim9810)), + m_stream(NULL), + m_TMP_register(0x00), + m_global_volume(0x00), + m_filter_type(OKIM9810_SECONDARY_FILTER), + m_output_level(OKIM9810_OUTPUT_TO_DIRECT_DAC) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void okim9810_device::device_start() +{ + // find our direct access + m_direct = &space().direct(); + + // create the stream + //int divisor = m_pin7 ? 132 : 165; + m_stream = machine().sound().stream_alloc(*this, 0, 2, clock()); + + // save state stuff + save_item(NAME(m_TMP_register)); + save_item(NAME(m_global_volume)); + save_item(NAME(m_filter_type)); + save_item(NAME(m_output_level)); + + for (int i = 0; i < OKIM9810_VOICES; i++) + { + okim_voice *voice = &m_voice[i]; + + save_item(NAME(voice->m_adpcm.m_signal), i); + save_item(NAME(voice->m_adpcm.m_step), i); + save_item(NAME(voice->m_adpcm2.m_signal), i); + save_item(NAME(voice->m_adpcm2.m_step), i); + save_item(NAME(voice->m_playbackAlgo), i); + save_item(NAME(voice->m_looping), i); + save_item(NAME(voice->m_startFlags), i); + save_item(NAME(voice->m_endFlags), i); + save_item(NAME(voice->m_base_offset), i); + save_item(NAME(voice->m_count), i); + save_item(NAME(voice->m_samplingFreq), i); + save_item(NAME(voice->m_playing), i); + save_item(NAME(voice->m_sample), i); + save_item(NAME(voice->m_channel_volume), i); + save_item(NAME(voice->m_pan_volume_left), i); + save_item(NAME(voice->m_pan_volume_right), i); + save_item(NAME(voice->m_startSample), i); + save_item(NAME(voice->m_endSample), i); + save_item(NAME(voice->m_interpSampleNum), i); + } +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void okim9810_device::device_reset() +{ + m_stream->update(); + for (int voicenum = 0; voicenum < OKIM9810_VOICES; voicenum++) + m_voice[voicenum].m_playing = false; +} + + +//------------------------------------------------- +// device_post_load - device-specific post-load +//------------------------------------------------- + +void okim9810_device::device_post_load() +{ +} + + +//------------------------------------------------- +// device_clock_changed - called if the clock +// changes +//------------------------------------------------- + +void okim9810_device::device_clock_changed() +{ +} + + +//------------------------------------------------- +// memory_space_config - return a description of +// any address spaces owned by this device +//------------------------------------------------- + +const address_space_config *okim9810_device::memory_space_config(address_spacenum spacenum) const +{ + return (spacenum == 0) ? &m_space_config : NULL; +} + + +//------------------------------------------------- +// stream_generate - handle update requests for +// our sound stream +//------------------------------------------------- + +void okim9810_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + // reset the output streams + memset(outputs[0], 0, samples * sizeof(*outputs[0])); + memset(outputs[1], 0, samples * sizeof(*outputs[1])); + + // iterate over voices and accumulate sample data + for (int voicenum = 0; voicenum < OKIM9810_VOICES; voicenum++) + m_voice[voicenum].generate_audio(*m_direct, outputs, samples, m_global_volume, clock(), m_filter_type); +} + + +//------------------------------------------------- +// read_status - read the status register +//------------------------------------------------- + +UINT8 okim9810_device::read_status() +{ + UINT8 result = 0x00; + UINT8 channelMask = 0x01; + for (int i = 0; i < OKIM9810_VOICES; i++, channelMask <<= 1) + { + if (!m_voice[i].m_playing) + result |= channelMask; + } + return result; +} + + +//------------------------------------------------- +// read - memory interface for reading the active status +//------------------------------------------------- + +READ8_MEMBER( okim9810_device::read ) +{ + return read_status(); +} + + +//------------------------------------------------- +// write - memory interface for write +//------------------------------------------------- + +// The command is written when the CMD pin is low +void okim9810_device::write_command(UINT8 data) +{ + const UINT8 cmd = (data & 0xf8) >> 3; + const UINT8 channel = (data & 0x07); + + switch(cmd) + { + case 0x00: // START + { + osd_printf_debug("START channel mask %02x\n", m_TMP_register); + UINT8 channelMask = 0x01; + for (int i = 0; i < OKIM9810_VOICES; i++, channelMask <<= 1) + { + if (channelMask & m_TMP_register) + { + m_voice[i].m_playing = true; + osd_printf_debug("\t\tPlaying channel %d: encoder type %d @ %dhz (volume = %d %d). From %08x for %d samples (looping=%d).\n", + i, + m_voice[i].m_playbackAlgo, + m_voice[i].m_samplingFreq, + m_voice[i].volume_scale(m_global_volume, m_voice[i].m_channel_volume, m_voice[i].m_pan_volume_left), + m_voice[i].volume_scale(m_global_volume, m_voice[i].m_channel_volume, m_voice[i].m_pan_volume_right), + m_voice[i].m_base_offset, + m_voice[i].m_count, + m_voice[i].m_looping); + } + } + break; + } + case 0x01: // STOP + { + osd_printf_debug("STOP channel mask %02x\n", m_TMP_register); + UINT8 channelMask = 0x01; + for (int i = 0; i < OKIM9810_VOICES; i++, channelMask <<= 1) + { + if (channelMask & m_TMP_register) + { + m_voice[i].m_playing = false; + osd_printf_debug("\tChannel %d stopping.\n", i); + } + } + break; + } + case 0x02: // LOOP + { + osd_printf_debug("LOOP channel mask %02x\n", m_TMP_register); + UINT8 channelMask = 0x01; + for (int i = 0; i < OKIM9810_VOICES; i++, channelMask <<= 1) + { + if (channelMask & m_TMP_register) + { + m_voice[i].m_looping = true; + osd_printf_debug("\tChannel %d looping.\n", i); + } + else + { + m_voice[i].m_looping = false; + osd_printf_debug("\tChannel %d done looping.\n", i); + } + } + break; + } + case 0x03: // OPT (options) + { + osd_printf_debug("OPT complex data %02x\n", m_TMP_register); + m_global_volume = (m_TMP_register & 0x18) >> 3; + m_filter_type = (m_TMP_register & 0x06) >> 1; + m_output_level = (m_TMP_register & 0x01); + osd_printf_debug("\tOPT setting main volume scale to Vdd/%d\n", m_global_volume+1); + osd_printf_debug("\tOPT setting output filter type to %d\n", m_filter_type); + osd_printf_debug("\tOPT setting output amp level to %d\n", m_output_level); + break; + } + case 0x04: // MUON (silence) + { + osd_printf_warning("MUON channel %d length %02x\n", channel, m_TMP_register); + osd_printf_warning("MSM9810: UNIMPLEMENTED COMMAND!\n"); + break; + } + + case 0x05: // FADR (phrase address) + { + const offs_t base = m_TMP_register * 8; + + offs_t startAddr; + UINT8 startFlags = m_direct->read_byte(base + 0); + startAddr = m_direct->read_byte(base + 1) << 16; + startAddr |= m_direct->read_byte(base + 2) << 8; + startAddr |= m_direct->read_byte(base + 3) << 0; + + offs_t endAddr; + UINT8 endFlags = m_direct->read_byte(base + 4); + endAddr = m_direct->read_byte(base + 5) << 16; + endAddr |= m_direct->read_byte(base + 6) << 8; + endAddr |= m_direct->read_byte(base + 7) << 0; + + // Sub-table + if (startFlags & 0x80) + { + offs_t subTable = startAddr; + // TODO: New startFlags &= 0x80. Are there further subtables? + startFlags = m_direct->read_byte(subTable + 0); + startAddr = m_direct->read_byte(subTable + 1) << 16; + startAddr |= m_direct->read_byte(subTable + 2) << 8; + startAddr |= m_direct->read_byte(subTable + 3) << 0; + + // TODO: What does byte (subTable + 4) refer to? + endAddr = m_direct->read_byte(subTable + 5) << 16; + endAddr |= m_direct->read_byte(subTable + 6) << 8; + endAddr |= m_direct->read_byte(subTable + 7) << 0; + } + + m_voice[channel].m_sample = 0; + m_voice[channel].m_interpSampleNum = 0; + m_voice[channel].m_startFlags = startFlags; + m_voice[channel].m_base_offset = startAddr; + m_voice[channel].m_endFlags = endFlags; + m_voice[channel].m_count = (endAddr-startAddr) + 1; // Is there yet another extra byte at the end? + + m_voice[channel].m_playbackAlgo = (startFlags & 0x30) >> 4; + m_voice[channel].m_samplingFreq = s_sampling_freq_table[startFlags & 0x0f]; + if (m_voice[channel].m_playbackAlgo == OKIM9810_ADPCM_PLAYBACK || + m_voice[channel].m_playbackAlgo == OKIM9810_ADPCM2_PLAYBACK) + m_voice[channel].m_count *= 2; + else + osd_printf_warning("MSM9810: UNIMPLEMENTED PLAYBACK METHOD %d\n", m_voice[channel].m_playbackAlgo); + + osd_printf_debug("FADR channel %d phrase offset %02x => ", channel, m_TMP_register); + osd_printf_debug("startFlags(%02x) startAddr(%06x) endFlags(%02x) endAddr(%06x) bytes(%d)\n", startFlags, startAddr, endFlags, endAddr, endAddr-startAddr); + break; + } + + case 0x06: // DADR (direct address playback) + { + osd_printf_warning("DADR channel %d complex data %02x\n", channel, m_TMP_register); + osd_printf_warning("MSM9810: UNIMPLEMENTED COMMAND!\n"); + break; + } + case 0x07: // CVOL (channel volume) + { + osd_printf_debug("CVOL channel %d data %02x\n", channel, m_TMP_register); + osd_printf_debug("\tChannel %d -> volume index %d.\n", channel, m_TMP_register & 0x0f); + + m_voice[channel].m_channel_volume = m_TMP_register & 0x0f; + break; + } + case 0x08: // PAN + { + const UINT8 leftVolIndex = (m_TMP_register & 0xf0) >> 4; + const UINT8 rightVolIndex = m_TMP_register & 0x0f; + osd_printf_debug("PAN channel %d left index: %02x right index: %02x (%02x)\n", channel, leftVolIndex, rightVolIndex, m_TMP_register); + osd_printf_debug("\tChannel %d left -> %d right -> %d\n", channel, leftVolIndex, rightVolIndex); + m_voice[channel].m_pan_volume_left = leftVolIndex; + m_voice[channel].m_pan_volume_right = rightVolIndex; + break; + } + default: + { + osd_printf_warning("MSM9810: UNKNOWN COMMAND!\n"); + break; + } + } +} + +WRITE8_MEMBER( okim9810_device::write ) +{ + write_command(data); +} + + +//----------------------------------------------------------- +// writeTMP - memory interface for writing the TMP register +//----------------------------------------------------------- + +// TMP is written when the CMD pin is high +void okim9810_device::write_TMP_register(UINT8 data) +{ + m_TMP_register = data; +} + +WRITE8_MEMBER( okim9810_device::write_TMP_register ) +{ + write_TMP_register(data); +} + + +//************************************************************************** +// OKIM VOICE +//************************************************************************** + +//------------------------------------------------- +// okim_voice - constructor +//------------------------------------------------- + +okim9810_device::okim_voice::okim_voice() + : m_playbackAlgo(OKIM9810_ADPCM2_PLAYBACK), + m_looping(false), + m_startFlags(0), + m_endFlags(0), + m_base_offset(0), + m_count(0), + m_samplingFreq(s_sampling_freq_table[2]), + m_playing(false), + m_sample(0), + m_channel_volume(0x00), + m_pan_volume_left(0x00), + m_pan_volume_right(0x00), + m_startSample(0), + m_endSample(0), + m_interpSampleNum(0) +{ +} + +//------------------------------------------------- +// generate_audio - generate audio samples and +// add them to an output stream +//------------------------------------------------- + +void okim9810_device::okim_voice::generate_audio(direct_read_data &direct, + stream_sample_t **buffers, + int samples, + const UINT8 global_volume, + const UINT32 clock, + const UINT8 filter_type) +{ + // skip if not active + if (!m_playing) + return; + + // separate out left and right channels + stream_sample_t *outL = buffers[0]; + stream_sample_t *outR = buffers[1]; + + // get left and right volumes + UINT8 volume_scale_left = volume_scale(global_volume, m_channel_volume, m_pan_volume_left); + UINT8 volume_scale_right = volume_scale(global_volume, m_channel_volume, m_pan_volume_right); + + // total samples per byte + UINT32 totalInterpSamples = clock / m_samplingFreq; + + // loop while we still have samples to generate + while (samples-- != 0) + { + // If interpSampleNum == 0, we are at the beginning of a new interp chunk, gather data + if (m_interpSampleNum == 0) + { + // If m_sample == 0, we have begun to play a new voice. Get both the first nibble & the second. + if (m_sample == 0) + { + // fetch the first sample nibble + int nibble0 = direct.read_byte(m_base_offset + m_sample / 2) >> (((m_sample & 1) << 2) ^ 4); + switch (m_playbackAlgo) + { + case OKIM9810_ADPCM_PLAYBACK: + { + m_adpcm.reset(); + m_startSample = (INT32)m_adpcm.clock(nibble0); + break; + } + case OKIM9810_ADPCM2_PLAYBACK: + { + m_adpcm2.reset(); + m_startSample = (INT32)m_adpcm2.clock(nibble0); + break; + } + default: + break; + } + } + else + { + // Otherwise just move the second nibble back to the first spot. + m_startSample = m_endSample; + } + + // And fetch the second sample nibble + int nibble1 = direct.read_byte(m_base_offset + (m_sample+1) / 2) >> ((((m_sample+1) & 1) << 2) ^ 4); + switch (m_playbackAlgo) + { + case OKIM9810_ADPCM_PLAYBACK: + { + m_endSample = (INT32)m_adpcm.clock(nibble1); + break; + } + case OKIM9810_ADPCM2_PLAYBACK: + { + m_endSample = (INT32)m_adpcm2.clock(nibble1); + break; + } + default: + break; + } + } + + // TODO: Interpolate using proper numeric types. + float progress = (float)m_interpSampleNum / (float)totalInterpSamples; + INT32 interpValue = (INT32)((float)m_startSample + (((float)m_endSample-(float)m_startSample) * progress)); + + // if filtering is unwanted + if (filter_type != OKIM9810_SECONDARY_FILTER && filter_type != OKIM9810_PRIMARY_FILTER) + interpValue = m_startSample; + + // output to the stereo buffers, scaling by the volume + // signal in range -2048..2047, volume in range 2..128 => signal * volume / 8 in range -32768..32767 + INT32 interpValueL = (interpValue * (INT32)volume_scale_left) / 8; + *outL++ += interpValueL; + + INT32 interpValueR = (interpValue * (INT32)volume_scale_right) / 8; + *outR++ += interpValueR; + + // if the interpsample has reached its end, move on to the next sample + m_interpSampleNum++; + if (m_interpSampleNum >= totalInterpSamples) + { + m_interpSampleNum = 0; + m_sample++; + } + + // the end of the stream has been reached + if (m_sample >= m_count) + { + if (!m_looping) + { + m_playing = false; + break; + } + else + { + m_sample = 0; + } + } + } +} + + +//------------------------------------------------- +// volume_scale - computes the volume equation as +// seen on page 29 of the docs. +// Returns a value from the volume lookup table. +//------------------------------------------------- + +UINT8 okim9810_device::okim_voice::volume_scale(const UINT8 global_volume_index, + const UINT8 channel_volume_index, + const UINT8 pan_volume_index) const +{ + const UINT8& V = channel_volume_index; + const UINT8& L = pan_volume_index; + const UINT8& O = global_volume_index; + UINT32 index = (V+L) + (O*3); + + if (index > 15) + index = 15; + + return s_volume_table[index]; +} diff --git a/src/devices/sound/okim9810.h b/src/devices/sound/okim9810.h new file mode 100644 index 00000000000..6d3595c59b2 --- /dev/null +++ b/src/devices/sound/okim9810.h @@ -0,0 +1,163 @@ +// license:BSD-3-Clause +// copyright-holders:Andrew Gardner +/*************************************************************************** + + okim9810.h + + OKI MSM9810 ADPCM(2) sound chip. + + Notes: + The master clock frequency for this chip can range from 3.5MHz to 4.5Mhz. + The typical oscillator is a 4.096Mhz crystal. + +***************************************************************************/ + +#pragma once + +#ifndef __OKIM9810_H__ +#define __OKIM9810_H__ + +#include "okiadpcm.h" + + +//************************************************************************** +// CONSTANTS +//************************************************************************** + +enum +{ + OKIM9810_ADPCM_PLAYBACK = 0, + OKIM9810_ADPCM2_PLAYBACK = 1, + OKIM9810_STRAIGHT8_PLAYBACK = 2, + OKIM9810_NONLINEAR8_PLAYBACK = 3 +}; + +enum +{ + OKIM9810_SECONDARY_FILTER = 0, + OKIM9810_PRIMARY_FILTER = 1, + OKIM9810_NO_FILTER = 2, + OKIM9810_NO_FILTER2 = 3 +}; + +enum +{ + OKIM9810_OUTPUT_TO_DIRECT_DAC = 0, + OKIM9810_OUTPUT_TO_VOLTAGE_FOLLOWER = 1 +}; + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_OKIM9810_ADD(_tag, _clock) \ + MCFG_DEVICE_ADD(_tag, OKIM9810, _clock) + +#define MCFG_OKIM9810_REPLACE(_tag, _clock) \ + MCFG_DEVICE_REPLACE(_tag, OKIM9810, _clock) + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + + +// ======================> okim9810_device + +class okim9810_device : public device_t, + public device_sound_interface, + public device_memory_interface +{ +public: + // construction/destruction + okim9810_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + UINT8 read_status(); + void write_TMP_register(UINT8 command); + void write_command(UINT8 command); + + DECLARE_READ8_MEMBER( read ); + DECLARE_WRITE8_MEMBER( write ); + DECLARE_WRITE8_MEMBER( write_TMP_register ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_post_load(); + virtual void device_clock_changed(); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const; + + // device_sound_interface overrides + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + + // a single voice + class okim_voice + { + public: + okim_voice(); + void generate_audio(direct_read_data &direct, + stream_sample_t **buffers, + int samples, + const UINT8 global_volume, + const UINT32 clock, + const UINT8 filter_type); + + // computes volume scale from 3 volume numbers + UINT8 volume_scale(const UINT8 global_volume, + const UINT8 channel_volume, + const UINT8 pan_volume) const; + + oki_adpcm_state m_adpcm; // current ADPCM state + oki_adpcm2_state m_adpcm2; // current ADPCM2 state + UINT8 m_playbackAlgo; // current playback method + bool m_looping; + UINT8 m_startFlags; + UINT8 m_endFlags; + offs_t m_base_offset; // pointer to the base memory location + UINT32 m_count; // total samples to play + UINT32 m_samplingFreq; // voice sampling frequency + + bool m_playing; // playback state + UINT32 m_sample; // current sample number + + UINT8 m_channel_volume; // volume index set with the CVOL command + UINT8 m_pan_volume_left; // volume index set with the PAN command + UINT8 m_pan_volume_right; // volume index set with the PAN command + + INT32 m_startSample; // interpolation state - sample to interpolate from + INT32 m_endSample; // interpolation state - sample to interpolate to + UINT32 m_interpSampleNum; // interpolation state - fraction between start & end + + static const UINT8 s_volume_table[16]; + }; + + // internal state + const address_space_config m_space_config; + + sound_stream* m_stream; + direct_read_data* m_direct; + + UINT8 m_TMP_register; + + UINT8 m_global_volume; // volume index set with the OPT command + UINT8 m_filter_type; // interpolation filter type set with the OPT command + UINT8 m_output_level; // flag stating if a voltage follower is connected + + static const int OKIM9810_VOICES = 8; + okim_voice m_voice[OKIM9810_VOICES]; + + static const UINT32 s_sampling_freq_table[16]; +}; + + +// device type definition +extern const device_type OKIM9810; + + + +#endif // __OKIM9810_H__ diff --git a/src/devices/sound/pci-ac97.c b/src/devices/sound/pci-ac97.c new file mode 100644 index 00000000000..84018534e46 --- /dev/null +++ b/src/devices/sound/pci-ac97.c @@ -0,0 +1,36 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +#include "pci-ac97.h" + +const device_type AC97 = &device_creator; + +DEVICE_ADDRESS_MAP_START(native_audio_mixer_map, 32, ac97_device) +ADDRESS_MAP_END + +DEVICE_ADDRESS_MAP_START(native_audio_bus_mastering_map, 32, ac97_device) +ADDRESS_MAP_END + +DEVICE_ADDRESS_MAP_START(mixer_map, 32, ac97_device) +ADDRESS_MAP_END + +DEVICE_ADDRESS_MAP_START(bus_mastering_map, 32, ac97_device) +ADDRESS_MAP_END + +ac97_device::ac97_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : pci_device(mconfig, AC97, "AC97 audio", tag, owner, clock, "ac97", __FILE__) +{ +} + +void ac97_device::device_start() +{ + pci_device::device_start(); + add_map(256, M_IO, FUNC(ac97_device::native_audio_mixer_map)); + add_map(64, M_IO, FUNC(ac97_device::native_audio_bus_mastering_map)); + add_map(512, M_MEM, FUNC(ac97_device::mixer_map)); + add_map(256, M_MEM, FUNC(ac97_device::bus_mastering_map)); +} + +void ac97_device::device_reset() +{ + pci_device::device_reset(); +} diff --git a/src/devices/sound/pci-ac97.h b/src/devices/sound/pci-ac97.h new file mode 100644 index 00000000000..56a3e4c3ace --- /dev/null +++ b/src/devices/sound/pci-ac97.h @@ -0,0 +1,28 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +#ifndef PCI_AC97_H +#define PCI_AC97_H + +#include "machine/pci.h" + +#define MCFG_AC97_ADD(_tag, _main_id, _revision, _subdevice_id) \ + MCFG_PCI_DEVICE_ADD(_tag, AC97, _main_id, _revision, 0x040300, _subdevice_id) + +class ac97_device : public pci_device { +public: + ac97_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual void device_start(); + virtual void device_reset(); + +private: + DECLARE_ADDRESS_MAP(native_audio_mixer_map, 32); + DECLARE_ADDRESS_MAP(native_audio_bus_mastering_map, 32); + DECLARE_ADDRESS_MAP(mixer_map, 32); + DECLARE_ADDRESS_MAP(bus_mastering_map, 32); +}; + +extern const device_type AC97; + +#endif diff --git a/src/devices/sound/pokey.c b/src/devices/sound/pokey.c new file mode 100644 index 00000000000..89279c16184 --- /dev/null +++ b/src/devices/sound/pokey.c @@ -0,0 +1,1453 @@ +// license:BSD-3-Clause +// copyright-holders:Brad Oliver, Eric Smith, Juergen Buchmueller +/***************************************************************************** + * + * POKEY chip emulator 4.6 + * + * Based on original info found in Ron Fries' Pokey emulator, + * with additions by Brad Oliver, Eric Smith and Juergen Buchmueller, + * paddle (a/d conversion) details from the Atari 400/800 Hardware Manual. + * Polynome algorithms according to info supplied by Perry McFarlane. + * + * 4.6: + * [1] http://ploguechipsounds.blogspot.de/2009/10/how-i-recorded-and-decoded-pokeys.html + * - changed audio emulation to emulate borrow 3 clock delay and + * proper channel reset. New frequency only becomes effective + * after the counter hits 0. Emulation also treats counters + * as 8 bit counters which are linked now instead of monolytic + * 16 bit counters. + * + * 4.51: + * - changed to use the attotime datatype + * 4.5: + * - changed the 9/17 bit polynomial formulas such that the values + * required for the Tempest Pokey protection will be found. + * Tempest expects the upper 4 bits of the RNG to appear in the + * lower 4 bits after four cycles, so there has to be a shift + * of 1 per cycle (which was not the case before). Bits #6-#13 of the + * new RNG give this expected result now, bits #0-7 of the 9 bit poly. + * - reading the RNG returns the shift register contents ^ 0xff. + * That way resetting the Pokey with SKCTL (which resets the + * polynome shifters to 0) returns the expected 0xff value. + * 4.4: + * - reversed sample values to make OFF channels produce a zero signal. + * actually de-reversed them; don't remember that I reversed them ;-/ + * 4.3: + * - for POT inputs returning zero, immediately assert the ALLPOT + * bit after POTGO is written, otherwise start trigger timer + * depending on SK_PADDLE mode, either 1-228 scanlines or 1-2 + * scanlines, depending on the SK_PADDLE bit of SKCTL. + * 4.2: + * - half volume for channels which are inaudible (this should be + * close to the real thing). + * 4.1: + * - default gain increased to closely match the old code. + * - random numbers repeat rate depends on POLY9 flag too! + * - verified sound output with many, many Atari 800 games, + * including the SUPPRESS_INAUDIBLE optimizations. + * 4.0: + * - rewritten from scratch. + * - 16bit stream interface. + * - serout ready/complete delayed interrupts. + * - reworked pot analog/digital conversion timing. + * - optional non-indexing pokey update functions. + * + * TODO: liberatr clipping + * + * + *****************************************************************************/ + +#include "emu.h" +#include "pokey.h" + +#include "debugger.h" + +/* Four channels with a range of 0..32767 and volume 0..15 */ +//#define POKEY_DEFAULT_GAIN (32767/15/4) + +/* + * But we raise the gain and risk clipping, the old Pokey did + * this too. It defined POKEY_DEFAULT_GAIN 6 and this was + * 6 * 15 * 4 = 360, 360/256 = 1.40625 + * I use 15/11 = 1.3636, so this is a little lower. + */ + +#define POKEY_DEFAULT_GAIN (32767/11/4) + +#define VERBOSE 0 +#define VERBOSE_SOUND 0 +#define VERBOSE_TIMER 0 +#define VERBOSE_POLY 0 +#define VERBOSE_RAND 0 + +#define LOG(x) do { if (VERBOSE) logerror x; } while (0) + +#define LOG_SOUND(x) do { if (VERBOSE_SOUND) logerror x; } while (0) + +#define LOG_TIMER(x) do { if (VERBOSE_TIMER) logerror x; } while (0) + +#define LOG_POLY(x) do { if (VERBOSE_POLY) logerror x; } while (0) + +#define LOG_RAND(x) do { if (VERBOSE_RAND) logerror x; } while (0) + +#define CHAN1 0 +#define CHAN2 1 +#define CHAN3 2 +#define CHAN4 3 + +#define TIMER1 0 +#define TIMER2 1 +#define TIMER4 2 + +/* values to add to the divisors for the different modes */ +#define DIVADD_LOCLK 1 +#define DIVADD_HICLK 4 +#define DIVADD_HICLK_JOINED 7 + +/* AUDCx */ +#define NOTPOLY5 0x80 /* selects POLY5 or direct CLOCK */ +#define POLY4 0x40 /* selects POLY4 or POLY17 */ +#define PURE 0x20 /* selects POLY4/17 or PURE tone */ +#define VOLUME_ONLY 0x10 /* selects VOLUME OUTPUT ONLY */ +#define VOLUME_MASK 0x0f /* volume mask */ + +/* AUDCTL */ +#define POLY9 0x80 /* selects POLY9 or POLY17 */ +#define CH1_HICLK 0x40 /* selects 1.78979 MHz for Ch 1 */ +#define CH3_HICLK 0x20 /* selects 1.78979 MHz for Ch 3 */ +#define CH12_JOINED 0x10 /* clocks channel 1 w/channel 2 */ +#define CH34_JOINED 0x08 /* clocks channel 3 w/channel 4 */ +#define CH1_FILTER 0x04 /* selects channel 1 high pass filter */ +#define CH2_FILTER 0x02 /* selects channel 2 high pass filter */ +#define CLK_15KHZ 0x01 /* selects 15.6999 kHz or 63.9211 kHz */ + +/* IRQEN (D20E) */ +#define IRQ_BREAK 0x80 /* BREAK key pressed interrupt */ +#define IRQ_KEYBD 0x40 /* keyboard data ready interrupt */ +#define IRQ_SERIN 0x20 /* serial input data ready interrupt */ +#define IRQ_SEROR 0x10 /* serial output register ready interrupt */ +#define IRQ_SEROC 0x08 /* serial output complete interrupt */ +#define IRQ_TIMR4 0x04 /* timer channel #4 interrupt */ +#define IRQ_TIMR2 0x02 /* timer channel #2 interrupt */ +#define IRQ_TIMR1 0x01 /* timer channel #1 interrupt */ + +/* SKSTAT (R/D20F) */ +#define SK_FRAME 0x80 /* serial framing error */ +#define SK_KBERR 0x40 /* keyboard overrun error - pokey documentation states *some bit as IRQST */ +#define SK_OVERRUN 0x20 /* serial overrun error - pokey documentation states *some bit as IRQST */ +#define SK_SERIN 0x10 /* serial input high */ +#define SK_SHIFT 0x08 /* shift key pressed */ +#define SK_KEYBD 0x04 /* keyboard key pressed */ +#define SK_SEROUT 0x02 /* serial output active */ + +/* SKCTL (W/D20F) */ +#define SK_BREAK 0x80 /* serial out break signal */ +#define SK_BPS 0x70 /* bits per second */ +#define SK_FM 0x08 /* FM mode */ +#define SK_PADDLE 0x04 /* fast paddle a/d conversion */ +#define SK_RESET 0x03 /* reset serial/keyboard interface */ +#define SK_KEYSCAN 0x02 /* key scanning enabled ? */ +#define SK_DEBOUNCE 0x01 /* Debouncing ?*/ + +#define DIV_64 28 /* divisor for 1.78979 MHz clock to 63.9211 kHz */ +#define DIV_15 114 /* divisor for 1.78979 MHz clock to 15.6999 kHz */ + +#define P4(chip) chip->poly4[chip->p4] +#define P5(chip) chip->poly5[chip->p5] +#define P9(chip) chip->poly9[chip->p9] +#define P17(chip) chip->poly17[chip->p17] + +#define CLK_1 0 +#define CLK_28 1 +#define CLK_114 2 + +static const int clock_divisors[3] = {1, DIV_64, DIV_15}; + + + + +// device type definition +const device_type POKEY = &device_creator; + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// okim9810_device - constructor +//------------------------------------------------- + +pokey_device::pokey_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, POKEY, "POKEY", tag, owner, clock, "pokey", __FILE__), + device_sound_interface(mconfig, *this), + device_execute_interface(mconfig, *this), + device_state_interface(mconfig, *this), + m_output_type(LEGACY_LINEAR), + m_icount(0), + m_stream(NULL), + m_pot0_r_cb(*this), + m_pot1_r_cb(*this), + m_pot2_r_cb(*this), + m_pot3_r_cb(*this), + m_pot4_r_cb(*this), + m_pot5_r_cb(*this), + m_pot6_r_cb(*this), + m_pot7_r_cb(*this), + m_allpot_r_cb(*this), + m_serin_r_cb(*this), + m_serout_w_cb(*this) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void pokey_device::device_start() +{ + //int sample_rate = clock(); + int i; + + m_clock_period = attotime::from_hz(clock()); + + /* Setup channels */ + for (i=0; iupdate(); +} + + +//------------------------------------------------- +// device_post_load - device-specific post-load +//------------------------------------------------- + +void pokey_device::device_post_load() +{ +} + + +//------------------------------------------------- +// device_clock_changed - called if the clock +// changes +//------------------------------------------------- + +void pokey_device::device_clock_changed() +{ +} + +//------------------------------------------------- +// stream_generate - handle update requests for +// our sound stream +//------------------------------------------------- + +void pokey_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch (id) + { + case 3: + /* serout_ready_cb */ + if (m_IRQEN & IRQ_SEROR) + { + m_IRQST |= IRQ_SEROR; + if (!m_irq_f.isnull()) + m_irq_f(IRQ_SEROR); + } + break; + case 4: + /* serout_complete */ + if (m_IRQEN & IRQ_SEROC) + { + m_IRQST |= IRQ_SEROC; + if (!m_irq_f.isnull()) + m_irq_f(IRQ_SEROC); + } + break; + case 5: + /* serin_ready */ + if (m_IRQEN & IRQ_SERIN) + { + m_IRQST |= IRQ_SERIN; + if (!m_irq_f.isnull()) + m_irq_f(IRQ_SERIN); + } + break; + case SYNC_WRITE: + { + offs_t offset = (param >> 8) & 0xff; + UINT8 data = param & 0xff; + write_internal(offset, data); + } + break; + case SYNC_NOOP: + /* do nothing, caused by a forced resync */ + break; + case SYNC_POT: + //logerror("x %02x \n", (param & 0x20)); + m_ALLPOT |= (param & 0xff); + break; + case SYNC_SET_IRQST: + m_IRQST |= (param & 0xff); + break; + default: + assert_always(FALSE, "Unknown id in pokey_device::device_timer"); + } +} + +void pokey_device::execute_run() +{ + bool check_debugger = ((device_t::machine().debug_flags & DEBUG_FLAG_ENABLED) != 0); + + do + { + // debugging + //m_ppc = m_pc; // copy PC to previous PC + if (check_debugger) + debugger_instruction_hook(this, 0); //m_pc); + + // instruction fetch + //UINT16 op = opcode_read(); + + UINT32 new_out = step_one_clock(); + if (m_output != new_out) + { + //printf("forced update %08d %08x\n", m_icount, m_output); + m_stream->update(); + m_output = new_out; + } + + m_icount--; + } while (m_icount > 0); + +} + + +//------------------------------------------------- +// step_one_clock - step the whole chip one +// clock cycle. +//------------------------------------------------- + +void pokey_device::step_keyboard() +{ + if (++m_kbd_cnt > 63) + m_kbd_cnt = 0; + if (!m_keyboard_r.isnull()) + { + UINT8 ret = m_keyboard_r(m_kbd_cnt); + + switch (m_kbd_cnt) + { + case POK_KEY_BREAK: + if (ret & 2) + { + /* check if the break IRQ is enabled */ + if (m_IRQEN & IRQ_BREAK) + { + m_IRQST |= IRQ_BREAK; + if (!m_irq_f.isnull()) + m_irq_f(IRQ_BREAK); + } + } + break; + case POK_KEY_SHIFT: + m_kbd_latch = (m_kbd_latch & 0xbf) | ((ret & 2) << 5); + if (m_kbd_latch & 0x40) + m_SKSTAT |= SK_SHIFT; + else + m_SKSTAT &= ~SK_SHIFT; + /* FIXME: sync ? */ + break; + case POK_KEY_CTRL: + m_kbd_latch = (m_kbd_latch & 0x7f) | ((ret & 2) << 6); + break; + } + switch (m_kbd_state) + { + case 0: /* waiting for key */ + if (ret & 1) + { + m_kbd_latch = (m_kbd_latch & 0xc0) | m_kbd_cnt; + m_kbd_state++; + } + break; + case 1: /* waiting for key confirmation */ + if ((m_kbd_latch & 0x3f) == m_kbd_cnt) + { + if (ret & 1) + { + m_KBCODE = m_kbd_latch; + m_SKSTAT |= SK_KEYBD; + if (m_IRQEN & IRQ_KEYBD) + { + /* last interrupt not acknowledged ? */ + if(m_IRQST & IRQ_KEYBD) + m_SKSTAT |= SK_KBERR; + m_IRQST |= IRQ_KEYBD; + if (!m_irq_f.isnull()) + m_irq_f(IRQ_KEYBD); + } + m_kbd_state++; + } + else + m_kbd_state = 0; + } + break; + case 2: /* waiting for release */ + if ((m_kbd_latch & 0x3f) == m_kbd_cnt) + { + if ((ret & 1)==0) + m_kbd_state++; + else + m_SKSTAT |= SK_KEYBD; + } + break; + case 3: + if ((m_kbd_latch & 0x3f) == m_kbd_cnt) + { + if (ret & 1) + m_kbd_state = 2; + else + { + m_SKSTAT &= ~SK_KEYBD; + m_kbd_state = 0; + } + } + break; + } + } +} + +void pokey_device::step_pot() +{ + int pot; + UINT8 upd = 0; + m_pot_counter++; + for (pot = 0; pot < 8; pot++) + { + if ((m_POTx[pot]= clock_divisors[clk]) + { + m_clock_cnt[clk] = 0; + clock_triggered[clk] = 1; + } + } + + m_p4 = (m_p4 + 1) % 0x0000f; + m_p5 = (m_p5 + 1) % 0x0001f; + m_p9 = (m_p9 + 1) % 0x001ff; + m_p17 = (m_p17 + 1 ) % 0x1ffff; + + clk = (m_AUDCTL & CH1_HICLK) ? CLK_1 : base_clock; + if (clock_triggered[clk]) + m_channel[CHAN1].inc_chan(); + + clk = (m_AUDCTL & CH3_HICLK) ? CLK_1 : base_clock; + if (clock_triggered[clk]) + m_channel[CHAN3].inc_chan(); + + if (clock_triggered[base_clock]) + { + if (!(m_AUDCTL & CH12_JOINED)) + m_channel[CHAN2].inc_chan(); + if (!(m_AUDCTL & CH34_JOINED)) + m_channel[CHAN4].inc_chan(); + } + + /* Potentiometer handling */ + if ((clock_triggered[CLK_114] || (m_SKCTL & SK_PADDLE)) && (m_pot_counter < 228)) + step_pot(); + + /* Keyboard */ + if (clock_triggered[CLK_114] && (m_SKCTL & SK_KEYSCAN)) + step_keyboard(); + } + + /* do CHAN2 before CHAN1 because CHAN1 may set borrow! */ + if (m_channel[CHAN2].check_borrow()) + { + int isJoined = (m_AUDCTL & CH12_JOINED); + if (isJoined) + m_channel[CHAN1].reset_channel(); + m_channel[CHAN2].reset_channel(); + process_channel(CHAN2); + + /* check if some of the requested timer interrupts are enabled */ + if ((m_IRQST & IRQ_TIMR2) && !m_irq_f.isnull()) + m_irq_f(IRQ_TIMR2); + } + + if (m_channel[CHAN1].check_borrow()) + { + int isJoined = (m_AUDCTL & CH12_JOINED); + if (isJoined) + m_channel[CHAN2].inc_chan(); + else + m_channel[CHAN1].reset_channel(); + process_channel(CHAN1); + /* check if some of the requested timer interrupts are enabled */ + if ((m_IRQST & IRQ_TIMR1) && !m_irq_f.isnull()) + m_irq_f(IRQ_TIMR1); + } + + /* do CHAN4 before CHAN3 because CHAN3 may set borrow! */ + if (m_channel[CHAN4].check_borrow()) + { + int isJoined = (m_AUDCTL & CH34_JOINED); + if (isJoined) + m_channel[CHAN3].reset_channel(); + m_channel[CHAN4].reset_channel(); + process_channel(CHAN4); + /* is this a filtering channel (3/4) and is the filter active? */ + if (m_AUDCTL & CH2_FILTER) + m_channel[CHAN2].sample(); + else + m_channel[CHAN2].m_filter_sample = 1; + if ((m_IRQST & IRQ_TIMR4) && !m_irq_f.isnull()) + m_irq_f(IRQ_TIMR4); + } + + if (m_channel[CHAN3].check_borrow()) + { + int isJoined = (m_AUDCTL & CH34_JOINED); + if (isJoined) + m_channel[CHAN4].inc_chan(); + else + m_channel[CHAN3].reset_channel(); + process_channel(CHAN3); + /* is this a filtering channel (3/4) and is the filter active? */ + if (m_AUDCTL & CH1_FILTER) + m_channel[CHAN1].sample(); + else + m_channel[CHAN1].m_filter_sample = 1; + } + + for (ch = 0; ch < 4; ch++) + { + sum |= (((((m_channel[ch].m_output ^ m_channel[ch].m_filter_sample) || (m_channel[ch].m_AUDC & VOLUME_ONLY)) ? (m_channel[ch].m_AUDC & VOLUME_MASK) : 0 )) << (ch * 4)); + } + return sum; +} + +//------------------------------------------------- +// stream_generate - handle update requests for +// our sound stream +//------------------------------------------------- + + +void pokey_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + stream_sample_t *buffer = outputs[0]; + + if (m_output_type == LEGACY_LINEAR) + { + INT32 out = 0; + for (int i = 0; i < 4; i++) + out += ((m_output >> (4*i)) & 0x0f); + out *= POKEY_DEFAULT_GAIN; + out = (out > 0x7fff) ? 0x7fff : out; + while( samples > 0 ) + { + *buffer++ = out; + samples--; + } + } + else if (m_output_type == RC_LOWPASS) + { + double rTot = m_voltab[m_output]; + + double V0 = rTot / (rTot+m_r_pullup) * m_v_ref / 5.0 * 32767.0; + double mult = (m_cap == 0.0) ? 1.0 : 1.0 - exp(-(rTot + m_r_pullup) / (m_cap * m_r_pullup * rTot) * m_clock_period.as_double()); + + while( samples > 0 ) + { + /* store sum of output signals into the buffer */ + m_out_filter += (V0 - m_out_filter) * mult; + *buffer++ = m_out_filter; + samples--; + + } + } + else if (m_output_type == OPAMP_C_TO_GROUND) + { + double rTot = m_voltab[m_output]; + /* In this configuration there is a capacitor in parallel to the pokey output to ground. + * With a LM324 in LTSpice this causes the opamp circuit to oscillate at around 100 kHz. + * We are ignoring the capacitor here, since this oscillation would not be audible. + */ + + /* This post-pokey stage usually has a high-pass filter behind it + * It is approximated by eliminating m_v_ref ( -1.0 term) + */ + + double V0 = ((rTot+m_r_pullup) / rTot - 1.0) * m_v_ref / 5.0 * 32767.0; + + while( samples > 0 ) + { + /* store sum of output signals into the buffer */ + *buffer++ = V0; + samples--; + + } + } + else if (m_output_type == OPAMP_LOW_PASS) + { + double rTot = m_voltab[m_output]; + /* This post-pokey stage usually has a low-pass filter behind it + * It is approximated by not adding in VRef below. + */ + + double V0 = (m_r_pullup / rTot) * m_v_ref / 5.0 * 32767.0; + double mult = (m_cap == 0.0) ? 1.0 : 1.0 - exp(-1.0 / (m_cap * m_r_pullup) * m_clock_period.as_double()); + + while( samples > 0 ) + { + /* store sum of output signals into the buffer */ + m_out_filter += (V0 - m_out_filter) * mult; + *buffer++ = m_out_filter /* + m_v_ref */; // see above + samples--; + } + } + else if (m_output_type == DISCRETE_VAR_R) + { + INT32 out = m_voltab[m_output]; + while( samples > 0 ) + { + *buffer++ = out; + samples--; + } + } +} + +//------------------------------------------------- +// read - memory interface for reading the active status +//------------------------------------------------- + +READ8_MEMBER( pokey_device::read ) +{ + return read(offset); +} + +UINT8 pokey_device::read(offs_t offset) +{ + int data = 0, pot; + + synchronize(SYNC_NOOP); /* force resync */ + + switch (offset & 15) + { + case POT0_C: case POT1_C: case POT2_C: case POT3_C: + case POT4_C: case POT5_C: case POT6_C: case POT7_C: + pot = offset & 7; + if( m_ALLPOT & (1 << pot) ) + { + /* we have a value measured */ + data = m_POTx[pot]; + LOG(("POKEY '%s' read POT%d (final value) $%02x\n", tag(), pot, data)); + } + else + { + data = m_pot_counter; + LOG(("POKEY '%s' read POT%d (interpolated) $%02x\n", tag(), pot, data)); + } + break; + + case ALLPOT_C: + /**************************************************************** + * If the 2 least significant bits of SKCTL are 0, the ALLPOTs + * are disabled (SKRESET). Thanks to MikeJ for pointing this out. + ****************************************************************/ + if( (m_SKCTL & SK_RESET) == 0) + { + data = 0; + LOG(("POKEY '%s' ALLPOT internal $%02x (reset)\n", tag(), data)); + } + else if( !m_allpot_r_cb.isnull() ) + { + data = m_allpot_r_cb(offset); + LOG(("%s: POKEY '%s' ALLPOT callback $%02x\n", machine().describe_context(), tag(), data)); + } + else + { + data = m_ALLPOT ^ 0xff; + LOG(("POKEY '%s' ALLPOT internal $%02x\n", tag(), data)); + } + break; + + case KBCODE_C: + data = m_KBCODE; + break; + + case RANDOM_C: + if( m_AUDCTL & POLY9 ) + { + data = m_poly9[m_p9] & 0xff; + LOG_RAND(("POKEY '%s' rand9[$%05x]: $%02x\n", tag(), m_p9, data)); + } + else + { + data = (m_poly17[m_p17] >> 8) & 0xff; + LOG_RAND(("POKEY '%s' rand17[$%05x]: $%02x\n", tag(), m_p17, data)); + } + break; + + case SERIN_C: + if( !m_serin_r_cb.isnull() ) + m_SERIN = m_serin_r_cb(offset); + data = m_SERIN; + LOG(("POKEY '%s' SERIN $%02x\n", tag(), data)); + break; + + case IRQST_C: + /* IRQST is an active low input port; we keep it active high */ + /* internally to ease the (un-)masking of bits */ + data = m_IRQST ^ 0xff; + LOG(("POKEY '%s' IRQST $%02x\n", tag(), data)); + break; + + case SKSTAT_C: + /* SKSTAT is also an active low input port */ + data = m_SKSTAT ^ 0xff; + LOG(("POKEY '%s' SKSTAT $%02x\n", tag(), data)); + break; + + default: + LOG(("POKEY '%s' register $%02x\n", tag(), offset)); + data = 0xff; + break; + } + return data; + +} + + +//------------------------------------------------- +// write - memory interface for write +//------------------------------------------------- + +void pokey_device::write(offs_t offset, UINT8 data) +{ + synchronize(SYNC_WRITE, (offset<<8) | data); +} + +WRITE8_MEMBER( pokey_device::write ) +{ + write(offset, data); +} + +void pokey_device::write_internal(offs_t offset, UINT8 data) +{ + /* determine which address was changed */ + switch (offset & 15) + { + case AUDF1_C: + LOG_SOUND(("POKEY '%s' AUDF1 $%02x\n", tag(), data)); + m_channel[CHAN1].m_AUDF = data; + break; + + case AUDC1_C: + LOG_SOUND(("POKEY '%s' AUDC1 $%02x (%s)\n", tag(), data, audc2str(data))); + m_channel[CHAN1].m_AUDC = data; + break; + + case AUDF2_C: + LOG_SOUND(("POKEY '%s' AUDF2 $%02x\n", tag(), data)); + m_channel[CHAN2].m_AUDF = data; + break; + + case AUDC2_C: + LOG_SOUND(("POKEY '%s' AUDC2 $%02x (%s)\n", tag(), data, audc2str(data))); + m_channel[CHAN2].m_AUDC = data; + break; + + case AUDF3_C: + LOG_SOUND(("POKEY '%s' AUDF3 $%02x\n", tag(), data)); + m_channel[CHAN3].m_AUDF = data; + break; + + case AUDC3_C: + LOG_SOUND(("POKEY '%s' AUDC3 $%02x (%s)\n", tag(), data, audc2str(data))); + m_channel[CHAN3].m_AUDC = data; + break; + + case AUDF4_C: + LOG_SOUND(("POKEY '%s' AUDF4 $%02x\n", tag(), data)); + m_channel[CHAN4].m_AUDF = data; + break; + + case AUDC4_C: + LOG_SOUND(("POKEY '%s' AUDC4 $%02x (%s)\n", tag(), data, audc2str(data))); + m_channel[CHAN4].m_AUDC = data; + break; + + case AUDCTL_C: + if( data == m_AUDCTL ) + return; + LOG_SOUND(("POKEY '%s' AUDCTL $%02x (%s)\n", tag(), data, audctl2str(data))); + m_AUDCTL = data; + + break; + + case STIMER_C: + LOG_TIMER(("POKEY '%s' STIMER $%02x\n", tag(), data)); + + /* From the pokey documentation: + * reset all counters to zero (side effect) + * Actually this takes 4 cycles to actually happen. + * FIXME: Use timer for delayed reset ! + */ + for (int i = 0; i < POKEY_CHANNELS; i++) + { + m_channel[i].reset_channel(); + m_channel[i].m_output = 0; + m_channel[i].m_filter_sample = (i<2 ? 1 : 0); + } + + break; + + case SKREST_C: + /* reset SKSTAT */ + LOG(("POKEY '%s' SKREST $%02x\n", tag(), data)); + m_SKSTAT &= ~(SK_FRAME|SK_OVERRUN|SK_KBERR); + break; + + case POTGO_C: + LOG(("POKEY '%s' POTGO $%02x\n", tag(), data)); + pokey_potgo(); + break; + + case SEROUT_C: + LOG(("POKEY '%s' SEROUT $%02x\n", tag(), data)); + m_serout_w_cb(offset, data); + m_SKSTAT |= SK_SEROUT; + /* + * These are arbitrary values, tested with some custom boot + * loaders from Ballblazer and Escape from Fractalus + * The real times are unknown + */ + timer_set(attotime::from_usec(200), 3); + /* 10 bits (assumption 1 start, 8 data and 1 stop bit) take how long? */ + timer_set(attotime::from_usec(2000), 4);// FUNC(pokey_serout_complete), 0, p); + break; + + case IRQEN_C: + LOG(("POKEY '%s' IRQEN $%02x\n", tag(), data)); + + /* acknowledge one or more IRQST bits ? */ + if( m_IRQST & ~data ) + { + /* reset IRQST bits that are masked now, except the SEROC bit (acid5200 pokey_seroc test) */ + m_IRQST &= (IRQ_SEROC | data); + } + /* store irq enable */ + m_IRQEN = data; + /* if SEROC irq is enabled trigger an irq (acid5200 pokey_seroc test) */ + if (m_IRQEN & m_IRQST & IRQ_SEROC) + { + if (!m_irq_f.isnull()) + m_irq_f(IRQ_SEROC); + } + break; + + case SKCTL_C: + if( data == m_SKCTL ) + return; + LOG(("POKEY '%s' SKCTL $%02x\n", tag(), data)); + m_SKCTL = data; + if( !(data & SK_RESET) ) + { + write_internal(IRQEN_C, 0); + write_internal(SKREST_C, 0); + /**************************************************************** + * If the 2 least significant bits of SKCTL are 0, the random + * number generator is disabled (SKRESET). Thanks to Eric Smith + * for pointing out this critical bit of info! + * Couriersud: Actually, the 17bit poly is reset and kept in a + * reset state. + ****************************************************************/ + m_p9 = 0; + m_p17 = 0; + m_p4 = 0; + m_p5 = 0; + m_clock_cnt[0] = 0; + m_clock_cnt[1] = 0; + m_clock_cnt[2] = 0; + /* FIXME: Serial port reset ! */ + } + break; + } + + /************************************************************ + * As defined in the manual, the exact counter values are + * different depending on the frequency and resolution: + * 64 kHz or 15 kHz - AUDF + 1 + * 1.79 MHz, 8-bit - AUDF + 4 + * 1.79 MHz, 16-bit - AUDF[CHAN1]+256*AUDF[CHAN2] + 7 + ************************************************************/ + +} + +WRITE_LINE_MEMBER( pokey_device::sid_w ) +{ + if (state) + { + m_SKSTAT |= SK_SERIN; + } + else + { + m_SKSTAT &= ~SK_SERIN; + } +} + +void pokey_device::serin_ready(int after) +{ + timer_set(m_clock_period * after, 5, 0); +} + +//------------------------------------------------- +// private stuff +//------------------------------------------------- + +inline void pokey_device::process_channel(int ch) +{ + if ((m_channel[ch].m_AUDC & NOTPOLY5) || (m_poly5[m_p5] & 1)) + { + if (m_channel[ch].m_AUDC & PURE) + m_channel[ch].m_output ^= 1; + else if (m_channel[ch].m_AUDC & POLY4) + m_channel[ch].m_output = (m_poly4[m_p4] & 1); + else if (m_AUDCTL & POLY9) + m_channel[ch].m_output = (m_poly9[m_p9] & 1); + else + m_channel[ch].m_output = (m_poly17[m_p17] & 1); + } +} + + +void pokey_device::pokey_potgo(void) +{ + int pot; + + LOG(("POKEY #%p pokey_potgo\n", (void *) this)); + + m_ALLPOT = 0x00; + m_pot_counter = 0; + + for( pot = 0; pot < 8; pot++ ) + { + m_POTx[pot] = 228; + switch (pot) + { + case 0: + if( !m_pot0_r_cb.isnull() ) + { + int r = m_pot0_r_cb(pot); + + LOG(("POKEY %s pot_r(%d) returned $%02x\n", tag(), pot, r)); + if (r >= 228) + { + r = 228; + } + if (r == 0) + { + /* immediately set the ready - bit of m_ALLPOT + * In this case, most likely no capacitor is connected + */ + m_ALLPOT |= (1<= 228) + { + r = 228; + } + if (r == 0) + { + /* immediately set the ready - bit of m_ALLPOT + * In this case, most likely no capacitor is connected + */ + m_ALLPOT |= (1<= 228) + { + r = 228; + } + if (r == 0) + { + /* immediately set the ready - bit of m_ALLPOT + * In this case, most likely no capacitor is connected + */ + m_ALLPOT |= (1<= 228) + { + r = 228; + } + if (r == 0) + { + /* immediately set the ready - bit of m_ALLPOT + * In this case, most likely no capacitor is connected + */ + m_ALLPOT |= (1<= 228) + { + r = 228; + } + if (r == 0) + { + /* immediately set the ready - bit of m_ALLPOT + * In this case, most likely no capacitor is connected + */ + m_ALLPOT |= (1<= 228) + { + r = 228; + } + if (r == 0) + { + /* immediately set the ready - bit of m_ALLPOT + * In this case, most likely no capacitor is connected + */ + m_ALLPOT |= (1<= 228) + { + r = 228; + } + if (r == 0) + { + /* immediately set the ready - bit of m_ALLPOT + * In this case, most likely no capacitor is connected + */ + m_ALLPOT |= (1<= 228) + { + r = 228; + } + if (r == 0) + { + /* immediately set the ready - bit of m_ALLPOT + * In this case, most likely no capacitor is connected + */ + m_ALLPOT |= (1<>(i*4)) & 0x0f]; + } + rTot = 1.0 / rTot; + m_voltab[j] = rTot; + } + +} + +void pokey_device::poly_init_4_5(UINT32 *poly, int size, int xorbit, int invert) +{ + int mask = (1 << size) - 1; + int i; + UINT32 lfsr = 0; + + LOG_POLY(("poly %d\n", size)); + for( i = 0; i < mask; i++ ) + { + /* calculate next bit */ + int in = !((lfsr >> 0) & 1) ^ ((lfsr >> xorbit) & 1); + lfsr = lfsr >> 1; + lfsr = (in << (size-1)) | lfsr; + *poly = lfsr ^ invert; + LOG_POLY(("%05x: %02x\n", i, *poly)); + poly++; + } +} + +void pokey_device::poly_init_9_17(UINT32 *poly, int size) +{ + int mask = (1 << size) - 1; + int i; + UINT32 lfsr =mask; + + LOG_RAND(("rand %d\n", size)); + + if (size == 17) + { + for( i = 0; i < mask; i++ ) + { + /* calculate next bit @ 7 */ + int in8 = ((lfsr >> 8) & 1) ^ ((lfsr >> 13) & 1); + int in = (lfsr & 1); + lfsr = lfsr >> 1; + lfsr = (lfsr & 0xff7f) | (in8 << 7); + lfsr = (in << 16) | lfsr; + *poly = lfsr; + LOG_RAND(("%05x: %02x\n", i, *poly)); + poly++; + } + } + else + { + for( i = 0; i < mask; i++ ) + { + /* calculate next bit */ + int in = ((lfsr >> 0) & 1) ^ ((lfsr >> 5) & 1); + lfsr = lfsr >> 1; + lfsr = (in << 8) | lfsr; + *poly = lfsr; + LOG_RAND(("%05x: %02x\n", i, *poly)); + poly++; + } + } + +} + +char *pokey_device::audc2str(int val) +{ + static char buff[80]; + if( val & NOTPOLY5 ) + { + if( val & PURE ) + strcpy(buff,"pure"); + else + if( val & POLY4 ) + strcpy(buff,"poly4"); + else + strcpy(buff,"poly9/17"); + } + else + { + if( val & PURE ) + strcpy(buff,"poly5"); + else + if( val & POLY4 ) + strcpy(buff,"poly4+poly5"); + else + strcpy(buff,"poly9/17+poly5"); + } + return buff; +} + +char *pokey_device::audctl2str(int val) +{ + static char buff[80]; + if( val & POLY9 ) + strcpy(buff,"poly9"); + else + strcpy(buff,"poly17"); + if( val & CH1_HICLK ) + strcat(buff,"+ch1hi"); + if( val & CH3_HICLK ) + strcat(buff,"+ch3hi"); + if( val & CH12_JOINED ) + strcat(buff,"+ch1/2"); + if( val & CH34_JOINED ) + strcat(buff,"+ch3/4"); + if( val & CH1_FILTER ) + strcat(buff,"+ch1filter"); + if( val & CH2_FILTER ) + strcat(buff,"+ch2filter"); + if( val & CLK_15KHZ ) + strcat(buff,"+clk15"); + return buff; +} + +pokey_device::pokey_channel::pokey_channel() + : m_AUDF(0), + m_AUDC(0), + m_borrow_cnt(0), + m_counter(0), + m_output(0), + m_filter_sample(0), + m_div2(0) +{ +} diff --git a/src/devices/sound/pokey.h b/src/devices/sound/pokey.h new file mode 100644 index 00000000000..96c9f672246 --- /dev/null +++ b/src/devices/sound/pokey.h @@ -0,0 +1,381 @@ +// license:BSD-3-Clause +// copyright-holders:Brad Oliver, Eric Smith, Juergen Buchmueller +/***************************************************************************** + * + * POKEY chip emulator 4.6 + * + * Based on original info found in Ron Fries' Pokey emulator, + * with additions by Brad Oliver, Eric Smith and Juergen Buchmueller. + * paddle (a/d conversion) details from the Atari 400/800 Hardware Manual. + * Polynome algorithms according to info supplied by Perry McFarlane. + * + *****************************************************************************/ + +#pragma once + +#ifndef __POKEY_H__ +#define __POKEY_H__ + +#include "machine/rescap.h" + +/* + * ATARI Pokey (CO12294) pin-out + * + +-----------------+ + VSS | 1 40 | D2 + D3 | 2 39 | D1 + D4 | 3 38 | D0 + D5 | 4 37 | AUD + D6 | 5 36 | A0 + D7 | 6 35 | A1 + PHI2 | 7 34 | A2 + P6 | 8 33 | A3 + P7 | 9 32 | R / /W + P4 | 10 31 | CS1 + P5 | 11 30 | /CS0 + P2 | 12 29 | IRQ + P3 | 13 28 | SOD + P0 | 14 27 | ACLK + P1 | 15 26 | BCLK + /KR2 | 16 25 | /KR1 + VCC | 17 24 | SID + /K5 | 18 23 | /K0 + /K4 | 19 22 | /K1 + /K3 | 20 21 | /K2 + +-----------------+ + * + */ + +/* CONSTANT DEFINITIONS */ + +/* exact 1.79 MHz clock freq (of the Atari 800 that is) */ +#define FREQ_17_EXACT 1789790 + +//************************************************************************** +// CALLBACK HANDLERS +//************************************************************************** + +typedef device_delegate pokey_kb_cb_delegate; +typedef device_delegate pokey_int_cb_delegate; + +#define POKEY_KEYBOARD_CB_MEMBER(_name) UINT8 _name(UINT8 k543210) +#define POKEY_INTERRUPT_CB_MEMBER(_name) void _name(int mask) + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_POKEY_POT0_R_CB(_devcb) \ + devcb = &pokey_device::set_pot0_r_callback(*device, DEVCB_##_devcb); + +#define MCFG_POKEY_POT1_R_CB(_devcb) \ + devcb = &pokey_device::set_pot1_r_callback(*device, DEVCB_##_devcb); + +#define MCFG_POKEY_POT2_R_CB(_devcb) \ + devcb = &pokey_device::set_pot2_r_callback(*device, DEVCB_##_devcb); + +#define MCFG_POKEY_POT3_R_CB(_devcb) \ + devcb = &pokey_device::set_pot3_r_callback(*device, DEVCB_##_devcb); + +#define MCFG_POKEY_POT4_R_CB(_devcb) \ + devcb = &pokey_device::set_pot4_r_callback(*device, DEVCB_##_devcb); + +#define MCFG_POKEY_POT5_R_CB(_devcb) \ + devcb = &pokey_device::set_pot5_r_callback(*device, DEVCB_##_devcb); + +#define MCFG_POKEY_POT6_R_CB(_devcb) \ + devcb = &pokey_device::set_pot6_r_callback(*device, DEVCB_##_devcb); + +#define MCFG_POKEY_POT7_R_CB(_devcb) \ + devcb = &pokey_device::set_pot7_r_callback(*device, DEVCB_##_devcb); + +#define MCFG_POKEY_ALLPOT_R_CB(_devcb) \ + devcb = &pokey_device::set_allpot_r_callback(*device, DEVCB_##_devcb); + +#define MCFG_POKEY_SERIN_R_CB(_devcb) \ + devcb = &pokey_device::set_serin_r_callback(*device, DEVCB_##_devcb); + +#define MCFG_POKEY_SEROUT_W_CB(_devcb) \ + devcb = &pokey_device::set_serout_w_callback(*device, DEVCB_##_devcb); + +/* k543210 = k5 ... k0 returns bit0: kr1, bit1: kr2 */ +/* all are, in contrast to actual hardware, ACTIVE_HIGH */ +#define MCFG_POKEY_KEYBOARD_CB(_class, _method) \ + pokey_device::set_keyboard_callback(*device, pokey_kb_cb_delegate(&_class::_method, #_class "::" #_method, downcast<_class *>(owner))); + +#define MCFG_POKEY_INTERRUPT_CB(_class, _method) \ + pokey_device::set_interrupt_callback(*device, pokey_int_cb_delegate(&_class::_method, #_class "::" #_method, downcast<_class *>(owner))); + + +#define MCFG_POKEY_OUTPUT_RC(_R, _C, _V) \ + (downcast(device))->m_output_type = pokey_device::RC_LOWPASS; \ + (downcast(device))->m_r_pullup = (_R); \ + (downcast(device))->m_cap = (_C); \ + (downcast(device))->m_v_ref = (_V); + +/* C ignored, please see pokey.c */ + +#define MCFG_POKEY_OUTPUT_OPAMP(_R, _C, _V) \ + (downcast(device))->m_output_type = pokey_device::OPAMP_C_TO_GROUND; \ + (downcast(device))->m_r_pullup = (_R); \ + (downcast(device))->m_cap = (_C); \ + (downcast(device))->m_v_ref = (_V); + +#define MCFG_POKEY_OUTPUT_OPAMP_LOW_PASS(_R, _C, _V) \ + (downcast(device))->m_output_type = pokey_device::OPAMP_LOW_PASS; \ + (downcast(device))->m_r_pullup = (_R); \ + (downcast(device))->m_cap = (_C); \ + (downcast(device))->m_v_ref = (_V); + +#define MCFG_POKEY_OUTPUT_DISCRETE() \ + (downcast(device))->m_output_type = pokey_device::DISCRETE_VAR_R; + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> pokey_device + +class pokey_device : public device_t, + public device_sound_interface, + public device_execute_interface, + public device_state_interface +{ +public: + + enum + { + POK_KEY_BREAK = 0x30, + POK_KEY_SHIFT = 0x20, + POK_KEY_CTRL = 0x00 + }; + + enum + { + /* POKEY WRITE LOGICALS */ + AUDF1_C = 0x00, + AUDC1_C = 0x01, + AUDF2_C = 0x02, + AUDC2_C = 0x03, + AUDF3_C = 0x04, + AUDC3_C = 0x05, + AUDF4_C = 0x06, + AUDC4_C = 0x07, + AUDCTL_C = 0x08, + STIMER_C = 0x09, + SKREST_C = 0x0A, + POTGO_C = 0x0B, + SEROUT_C = 0x0D, + IRQEN_C = 0x0E, + SKCTL_C = 0x0F + }; + + enum + { + /* POKEY READ LOGICALS */ + POT0_C = 0x00, + POT1_C = 0x01, + POT2_C = 0x02, + POT3_C = 0x03, + POT4_C = 0x04, + POT5_C = 0x05, + POT6_C = 0x06, + POT7_C = 0x07, + ALLPOT_C = 0x08, + KBCODE_C = 0x09, + RANDOM_C = 0x0A, + SERIN_C = 0x0D, + IRQST_C = 0x0E, + SKSTAT_C = 0x0F + }; + + enum /* sync-operations */ + { + SYNC_NOOP = 11, + SYNC_SET_IRQST = 12, + SYNC_POT = 13, + SYNC_WRITE = 14 + }; + + enum output_type + { + LEGACY_LINEAR = 0, + RC_LOWPASS, + OPAMP_C_TO_GROUND, + OPAMP_LOW_PASS, + DISCRETE_VAR_R + }; + + // construction/destruction + pokey_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + template static devcb_base &set_pot0_r_callback(device_t &device, _Object object) { return downcast(device).m_pot0_r_cb.set_callback(object); } + template static devcb_base &set_pot1_r_callback(device_t &device, _Object object) { return downcast(device).m_pot1_r_cb.set_callback(object); } + template static devcb_base &set_pot2_r_callback(device_t &device, _Object object) { return downcast(device).m_pot2_r_cb.set_callback(object); } + template static devcb_base &set_pot3_r_callback(device_t &device, _Object object) { return downcast(device).m_pot3_r_cb.set_callback(object); } + template static devcb_base &set_pot4_r_callback(device_t &device, _Object object) { return downcast(device).m_pot4_r_cb.set_callback(object); } + template static devcb_base &set_pot5_r_callback(device_t &device, _Object object) { return downcast(device).m_pot5_r_cb.set_callback(object); } + template static devcb_base &set_pot6_r_callback(device_t &device, _Object object) { return downcast(device).m_pot6_r_cb.set_callback(object); } + template static devcb_base &set_pot7_r_callback(device_t &device, _Object object) { return downcast(device).m_pot7_r_cb.set_callback(object); } + template static devcb_base &set_allpot_r_callback(device_t &device, _Object object) { return downcast(device).m_allpot_r_cb.set_callback(object); } + template static devcb_base &set_serin_r_callback(device_t &device, _Object object) { return downcast(device).m_serin_r_cb.set_callback(object); } + template static devcb_base &set_serout_w_callback(device_t &device, _Object object) { return downcast(device).m_serout_w_cb.set_callback(object); } + + static void set_keyboard_callback(device_t &device, pokey_kb_cb_delegate callback) { downcast(device).m_keyboard_r = callback; } + static void set_interrupt_callback(device_t &device, pokey_int_cb_delegate callback) { downcast(device).m_irq_f = callback; } + + DECLARE_READ8_MEMBER( read ); + DECLARE_WRITE8_MEMBER( write ); + + UINT8 read(offs_t offset); + void write(offs_t offset, UINT8 data); + + DECLARE_WRITE_LINE_MEMBER( sid_w ); // pin 24 + void serin_ready(int after); + + // analog output configuration + + output_type m_output_type; + double m_r_pullup; + double m_cap; + double m_v_ref; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_post_load(); + virtual void device_clock_changed(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + // device_sound_interface overrides + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + + virtual void execute_run(); + + //virtual UINT32 execute_min_cycles() const { return 114; } + // other internal states + int m_icount; + +private: + + + class pokey_channel + { + public: + pokey_channel(); + pokey_device *m_parent; + UINT8 m_INTMask; + UINT8 m_AUDF; /* AUDFx (D200, D202, D204, D206) */ + UINT8 m_AUDC; /* AUDCx (D201, D203, D205, D207) */ + INT32 m_borrow_cnt; /* borrow counter */ + INT32 m_counter; /* channel counter */ + UINT8 m_output; /* channel output signal (1 active, 0 inactive) */ + UINT8 m_filter_sample; /* high-pass filter sample */ + UINT8 m_div2; /* division by 2 */ + + inline void sample(void) { m_filter_sample = m_output; } + inline void reset_channel(void) { m_counter = m_AUDF ^ 0xff; } + + inline void inc_chan() + { + m_counter = (m_counter + 1) & 0xff; + if (m_counter == 0 && m_borrow_cnt == 0) + { + m_borrow_cnt = 3; + if (m_parent->m_IRQEN & m_INTMask) + { + /* Exposed state has changed: This should only be updated after a resync ... */ + m_parent->synchronize(SYNC_SET_IRQST, m_INTMask); + } + } + } + + inline int check_borrow() + { + if (m_borrow_cnt > 0) + { + m_borrow_cnt--; + return (m_borrow_cnt == 0); + } + return 0; + } + }; + + static const int POKEY_CHANNELS = 4; + + UINT32 step_one_clock(); + void step_keyboard(); + void step_pot(); + + void poly_init_4_5(UINT32 *poly, int size, int xorbit, int invert); + void poly_init_9_17(UINT32 *poly, int size); + void vol_init(); + + inline void process_channel(int ch); + void pokey_potgo(void); + char *audc2str(int val); + char *audctl2str(int val); + + void write_internal(offs_t offset, UINT8 data); + + // internal state + sound_stream* m_stream; + + pokey_channel m_channel[POKEY_CHANNELS]; + + UINT32 m_output; /* raw output */ + double m_out_filter; /* filtered output */ + + INT32 m_clock_cnt[3]; /* clock counters */ + UINT32 m_p4; /* poly4 index */ + UINT32 m_p5; /* poly5 index */ + UINT32 m_p9; /* poly9 index */ + UINT32 m_p17; /* poly17 index */ + + devcb_read8 m_pot0_r_cb; + devcb_read8 m_pot1_r_cb; + devcb_read8 m_pot2_r_cb; + devcb_read8 m_pot3_r_cb; + devcb_read8 m_pot4_r_cb; + devcb_read8 m_pot5_r_cb; + devcb_read8 m_pot6_r_cb; + devcb_read8 m_pot7_r_cb; + devcb_read8 m_allpot_r_cb; + devcb_read8 m_serin_r_cb; + devcb_write8 m_serout_w_cb; + + pokey_kb_cb_delegate m_keyboard_r; + pokey_int_cb_delegate m_irq_f; + + UINT8 m_POTx[8]; /* POTx (R/D200-D207) */ + UINT8 m_AUDCTL; /* AUDCTL (W/D208) */ + UINT8 m_ALLPOT; /* ALLPOT (R/D208) */ + UINT8 m_KBCODE; /* KBCODE (R/D209) */ + UINT8 m_SERIN; /* SERIN (R/D20D) */ + UINT8 m_SEROUT; /* SEROUT (W/D20D) */ + UINT8 m_IRQST; /* IRQST (R/D20E) */ + UINT8 m_IRQEN; /* IRQEN (W/D20E) */ + UINT8 m_SKSTAT; /* SKSTAT (R/D20F) */ + UINT8 m_SKCTL; /* SKCTL (W/D20F) */ + + UINT8 m_pot_counter; + UINT8 m_kbd_cnt; + UINT8 m_kbd_latch; + UINT8 m_kbd_state; + + attotime m_clock_period; + + UINT32 m_poly4[0x0f]; + UINT32 m_poly5[0x1f]; + UINT32 m_poly9[0x1ff]; + UINT32 m_poly17[0x1ffff]; + UINT32 m_voltab[0x10000]; +}; + + +// device type definition +extern const device_type POKEY; + +#endif /* __POKEY_H__ */ diff --git a/src/devices/sound/pokey.txt b/src/devices/sound/pokey.txt new file mode 100644 index 00000000000..e0a30094893 --- /dev/null +++ b/src/devices/sound/pokey.txt @@ -0,0 +1,319 @@ + Atari POKEY Chip Emulator V2.0 + ============================== + by Ron Fries + 31 Jan 97 + +The PokeySound Chip Emulator is designed to emulate the functionality of the +Atari POKEY Chip Hardware through 'C' Sourcecode. The emulator is able to +produce sounds which are essentially identical to the original POKEY chip, +including the exact distortions and pitches. + +The emulator is designed to run in a 32-bit environment. Though it can be +compiled and run in a 16-bit environment, it is slow. + +I would like to give special thanks to Neil Bradley. He provided excellent +testing support and was also the driving force behind the multiple POKEY +emulation. + +New Features: +------------- + +Version 2.0 of the 'PokeySound' adds the following features: + +1) Support for multiple POKEY chips. The maximum supported is configured + at compile time. + +2) An adjustable gain. The previous releases had a built-in gain of 64. + +3) A clipping option. Depending on the number of chips emulated and the + configured gain, it is possible for the output to exceed 8-bits. + Clipping can be enabled to prevent this, though it does increase the + processing time. + + +Standard Features: +------------------ + +The 'PokeySound' emulator supports the following functions: + +1) All polynomial sound generators: + a) 4-bit poly - actual bit pattern determined from sampled sound + b) 5-bit poly - actual bit pattern determined from sampled sound + c) 17-bit poly - simulated random bit pattern + d) 9-bit poly - derived from simulated 17-bit poly + +2) Full support of all 'Divide by N' counter clocks: + a) 1.79 MHz (high limited to playback sample rate) + b) 64 KHz (high limited to playback sample rate) + c) 15 KHz + +3) Full support of all 'Divide by N' resolutions: + a) 8-bit - single channel + b) 16-bit - double channel + +4) Full support of all distortions + a) 5-bit poly, then 17-bit poly + b) 5-bit poly only + c) 5-bit poly, then 4-bit poly + d) 17-bit poly only + e) no poly counters (pure tone) + f) 5-bit poly only + +5) Full support of volume control + +6) Full support of all pitches - distortions will vary exactly as the + original Atari based on different pitches + +7) Accurate pitch generation + +8) Support of any playback sample rate (e.g. 22050) + + +The 'PokeySound' emulator does not currently support the following functions: + +1) High pass filters + + +Though I don't believe adding support for the High-Pass filters is very +complicated, I decided not to add support right now because I don't +believe this feature is used much. I'm also not sure how much impact it +would have on performance. Let me know if you find an application that +uses it. + +In the 2.0 release, I've removed the non-optimized vrersion. It was only +left in for reference. If you would still like to see the non-optimized +version, it's available in the 1.2 release. + +One of the unique features of the emulator is that the processing time varies +based on the frequency. Since the routine only calculates new output values +when a change is sensed, the lower frequencies (which change less frequently) +will require less processing time. + + +Differences Between the Emulator and the Actual POKEY Chip: +----------------------------------------------------------- + +The biggest difference between the emulator and the original hardware is +that the emulator emulates an 'ideal' POKEY chip. All output from the +emulator is a based on a precise square wave, whereas the output from the +original chip has decay. Though the output is slightly different, I +don't believe this difference is easily discernible. + +Another slight difference is the 17-bit/9-bit poly. Since the polynomial +is large (2^17 bits), I choose to create the sample using a random number +generator rather than a table. I don't believe this difference is +significant. + +There are also a few differences which are introduced by aliasing. This is +a direct result of using an output sampling rate which is not identical to +the original sound rate. It is most evident with high frequencies. + +A final difference is the lack of support for the High-Pass Filter +functionality. I plan to add this in a future release if necessary. + + +Sample/Test Application: +------------------------ + +The test program I've distributed is a 16-bit DOS application created with +the Borland 'C' compiler. The only reason I used 16-bit was because I +already had a set of working SB drivers in 16-bit. Since the test system +is dedicated to generating sounds, the performance in 16-bit is more than +adequate. + + +POKEY.C +======= + +The POKEY.C file is the heart of the PokeySound Emulation program. +Although the routines in the file must work together, no other files are +modules are required for operation. A header file, 'POKEY.H', has +been included for use in other modules, and provides the necessary +function prototypes. I've attempted to make the routines as portable as +possible, so the file should compile on almost any compiler with little +or no modification. + +I have made some attempts at optimizing the routines, though I am sure +more optimization can be done. They are currently only available in 'C'. +I'll be happy to convert them to assembly language if desired. Please feel +free to send me e-mail at rfries@tcmail.frco.com. + +The routines are easy to use. Detailed descriptions on the function calls +are listed below. + +The POKEY.C module can be compiled in a 32-bit or 16-bit environment. +Since these routines are optimized for 32-bit use, the code will default +to 32-bit. To compile in 16-bits, use a command line option to define +the variable COMP16. + + +GENERAL OVERVIEW +---------------- + +On start-up of the system, a single call should be made to Pokey_sound_init. +This routine will prepare the structures for sound output. This routine +can be called again if necessary during warm-start or other reset. + +Once in the main loop, there are two other functions that will be used. +Whenever the system needs to write to either the AUDC or AUDF values, +a call should be made to the Update_pokey_sound routine. This routine will +take care of updating the internal registers. It will pre-calculate several +values to help with optimization. + +The only other routine that is called is the Pokey_process function. This +function will fill a audio buffer with a specified number of bytes. This +function should be called whenever a new audio buffer is required. + +For best results, I recommend using at least two output buffers. Using this +scheme, the sound card can be playing one buffer while the system is filling +the other. + + +DETAILED FUNCTION DESCRIPTIONS +------------------------------ + +Pokey_sound_init(uint32 freq17, uint16 playback_freq, uint8 num_pokeys) +----------------------------------------------------------------------- + +This function initializes the structures used by the PokeySound routines. +This function takes three parameters: the main clock frequency, the +playback frequency and the number of POKEY chips to emulate. + +The maximum number of POKEY chips emulated is configured at compile time. +Though the maximum number of chips can be configured as one, the PokeySound +1.2 routines are recommended if only a single chip is to be emulated since +they have will provide better performance. + +The main clock frequency is the frequency of the 1.79MHz source clock. +To provide exact results, freq17 should be set equal to 1789790 Hz. As an +alternative, freq17 can be set to an approximate frequency of 1787520 Hz. +Using this approximate frequency will reduce aliasing and thus produce a +clearer output signal. + +A constant has been defined for both of these values for your convenience. +The names are FREQ_17_EXACT and FREQ_17_APPROX. + +The playback frequency is the frequency of the sound playback (the frequency +used by the sound card). For best results, the playback frequency should +be an even division of the main clock frequency. Since most of the sounds +will be generated using the 64kHz clock, I also recommend making the +playback frequency an even division of the 64kHz clock. + +The 64kHz clock is exactly equal to the main clock divided by 28. For +the playback frequency, I recommend one of the following values: + +1) FREQ_17_APPROX / (28*1), which is equal to 63840. Of course, most sound + cards can't reproduce this frequency. + +2) FREQ_17_APPROX / (28*2), which is equal to 31920. All of the newer cards + will support this frequency. + +3) FREQ_17_APPROX / (28*3), which is equal to 21280. All of the SB + compatibles should support this frequency. + +4) FREQ_17_APPROX / (28*4), which is equal to 15960. This may be the + best choice, as it offers good sound reproduction with good performance. + +Of course, these options also assume you are using the approximate +frequency for the main clock as well. Any of these choices will offer the +best results when the main 64kHz clock is used, reasonable results when the +15kHz clock is selected, and marginal results when the 1.79MHz clock is +selected (the only way to produce good results in all cases is to set the +playback frequency to 1.79MHz!) + +Feel free to experiment to find other alternatives as well. + +This function has no return value (void). + + +Update_pokey_sound (uint16 addr, uint8 val, uint8 chip, uint8 gain) +------------------------------------------------------------------- + +This function should be called each time an AUDC, AUDF or AUDCTL value +changes. This function takes four parameters: the address to change, +the new value, the chip to be updated, and the gain to be used. +The lower four bits of the address should be one of the following values: + + Addr Description + ------ ----------- + 0x00 AUDF1 + 0x01 AUDC1 + 0x02 AUDF2 + 0x03 AUDC2 + 0x04 AUDF3 + 0x05 AUDC3 + 0x06 AUDF4 + 0x07 AUDC4 + 0x08 AUDCTL + +In order to support multiple POKEY chips, only the lower four bits of +the address are used. Note that this routine can no longer be called with +any address as it will affect the operation of the specified chip. + +The routine pre-calculates several values that are needed by the +processing function. This is done to optimize performance. + +The output will be amplified (multiplied) by gain/16 (previous releases had +a built in multiplier of 4, which calculates to a gain value of 64). If the +output exceeds the maximum value after then gain and clipping is enabled, +the output will be limited to reduce distortion. + +The best value for the gain depends on the number of POKEYs emulated and +the maximum volume used. The maximum possible output for each channel is 15, +making the maximum possible output for a single chip to be 60. Assuming all +four channels on the chip are used at full volume, a gain of 64 can be used +without distortion. If 4 POKEY chips are emulated and all 16 channels are +used at full volume, the gain must be no more than 16 to prevent distortion. +Of course, if only a few of the 16 channels are used or not all channels are +used at full volume, a larger gain can be used. + +To enable clipping, define the logical CLIP before compiling. This is the +default mode of operation as it has already been included in the POKEY.H file. +Note that this is only recommended if clipping is necessary since it will +impact the performance. + +This function has no return value (void). + + +Pokey_process (uint8 *buffer, uint16 n) +--------------------------------------- + +This function calculates and fills a buffer with unsigned 8-bit mono audio. +This function takes two parameters: a pointer to the buffer to fill and +the size of the buffer (limited to 65535). This function fills the +buffer based on the requested size and returns. It automatically +updates the pointers for the next call, so subsequent calls to this function +will provide a continuous stream of data. + +The size of the buffer that is needed depends on the playback frequency. +It is best to keep the buffer as small as possible to maximize response time +to changes in the sound. Of course, the minimum size is dependent on +system and emulator performance. + +Selecting the correct buffer size is a careful balance. Selecting a buffer +size that is too small will produce noticeable clicks in the output, though +selecting a size that is too large will cause a poor response time and +possible delays in the system when the new buffer is filled. + +This function has no return value (void). + + +License Information and Copyright Notice +======================================== + +PokeySound is Copyright(c) 1996-1997 by Ron Fries + +This library is free software; you can redistribute it and/or modify it under +the terms of version 2 of the GNU Library General Public License as published +by the Free Software Foundation. + +This library is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more +details. + +To obtain a copy of the GNU Library General Public License, write to the Free +Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +Any permitted reproduction of these routines, in whole or in part, must bear +this legend. diff --git a/src/devices/sound/qs1000.c b/src/devices/sound/qs1000.c new file mode 100644 index 00000000000..3100800acbc --- /dev/null +++ b/src/devices/sound/qs1000.c @@ -0,0 +1,646 @@ +// license:BSD-3-Clause +// copyright-holders:Philip Bennett +/*************************************************************************** + + qs1000.c + + QS1000 device emulator. + +**************************************************************************** + + The QS1000 is a 32-voice wavetable synthesizer, believed to be based on + the OPTi 82C941. It contains an 8051 core, 256b of RAM and an (undumped) + internal program ROM. The internal ROM can be bypassed in favour of an + external ROM. Commands are issued to the chip via the 8051 serial port. + + The QS1000 can access 24Mb of sample ROM. To reduce demand on the CPU, + instrument parameters such as playback rate, envelope and filter values + are encoded in ROM and directly accessed by the wavetable engine. + There are table entries for every note of every instrument. + + Registers + ========= + + [200] = Key on/off + 0 = Key on + 1 = ? + 2 = key off + [201] = Address byte 0 (LSB) + [202] = Address byte 1 + [203] = Address byte 2 + [204] = Pitch + [205] = Pitch high byte? (Usually 0) + [206] = Left volume + [207] = Right volume + [208] = Volume + [209] = ? + [20a] = ? + [20b] = ? + [20c] = ? + [20d] = Velocity + [20e] = Channel select + [20f] = Modulation + [210] = Modulation + [211] = 0 - Select global registers? + 3 - Select channel registers? + + Velocity register values for MIDI range 0-127: + + 01 01 01 01 01 01 01 02 02 03 03 04 04 05 05 06 + 06 07 07 08 08 09 09 0A 0A 0B 0B 0C 0C 0D 0D 0E + 0E 0F 10 11 11 12 13 14 14 15 16 17 17 18 19 1A + 1A 1B 1C 1D 1D 1E 1F 20 20 21 22 23 23 24 25 26 + 26 27 28 29 29 2A 2B 2C 2C 2D 2E 2F 2F 30 31 32 + 35 38 3B 3E 41 44 47 4A 4D 50 4F 51 52 53 54 56 + 57 58 59 5B 5C 5D 5E 60 61 62 63 65 66 67 6A 6B + 6C 6E 6F 70 71 73 74 75 76 78 79 7A 7B 7D 7E 7F + + (TODO: Other register values) + + This is the sequence of register writes used to play the Iron Fortress credit sound: + + [211] 0 Select global registers? + [200] 1 ? + [203] d6 Address byte 2 + [202] a9 Address byte 1 + [201] 1 Address byte 0 + [204] 80 Pitch + [205] 0 ? + [206] 80 Left volume + [207] 80 Right volume + [208] b3 Volume + [209] 0 ? + [20a] ff ? + [20b] 0 ? + [20c] 0 ? + [20d] 78 Velocity + [211] 3 Select channel registers + [20e] 0 Select channel + [200] 0 Key on + + + Sound Headers + ============= + + The address registers point to a 6 byte entry in the sound ROM: + + [019be0] + 097b 397f 1510 + ^ ^ ^ + | | | + | | +----- Sound descriptor pointer + | +---------- ? + +--------------- Playback frequency (fixed point value representing 24MHz clock periods) + + This in turn points to a 24 byte descriptor: + + [1510]: + 0 4502D 4508E 45F91 D0 7F 0F 2A 1F 90 00 FF + ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ + | | | | | | | | | | | | + | | | | | | | | | | | +-- ? + | | | | | | | | | | +----- ? + | | | | | | | | | +-------- ? + | | | | | | | | +----------- ? + | | | | | | | +-------------- ? + | | | | | | +----------------- Bit 7: Format (0:PCM 1:ADPCM) + | | | | | +-------------------- ? + | | | | +----------------------- ? + | | | +----------------------------- Loop end address + | | +----------------------------------- Loop start address + | +----------------------------------------- Start address + +------------------------------------------- Address most-significant nibble (shared with loop addresses) + + * The unknown parameters are most likely envelope and filter parameters. + * Is there a loop flag or do sounds loop indefinitely until stopped? + + + TODO: + * Looping is currently disabled + * Figure out unknown sound header parameters + * Figure out and implement envelopes and filters + * Pitch bending + * Dump the internal ROM + +***************************************************************************/ +#include "emu.h" +#include "qs1000.h" + + +#define LOGGING_ENABLED 0 + + +// device type definition +const device_type QS1000 = &device_creator; + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +static ADDRESS_MAP_START( qs1000_prg_map, AS_PROGRAM, 8, qs1000_device ) + AM_RANGE(0x0000, 0x7fff) AM_ROM +ADDRESS_MAP_END + + +static ADDRESS_MAP_START( qs1000_io_map, AS_IO, 8, qs1000_device ) + AM_RANGE(0x0000, 0x00ff) AM_RAM + AM_RANGE(0x0200, 0x0211) AM_WRITE(wave_w) + AM_RANGE(MCS51_PORT_P1, MCS51_PORT_P1) AM_READWRITE(p1_r, p1_w) + AM_RANGE(MCS51_PORT_P2, MCS51_PORT_P2) AM_READWRITE(p2_r, p2_w) + AM_RANGE(MCS51_PORT_P3, MCS51_PORT_P3) AM_READWRITE(p3_r, p3_w) +ADDRESS_MAP_END + + +// Machine fragment +static MACHINE_CONFIG_FRAGMENT( qs1000 ) + MCFG_CPU_ADD("cpu", I8052, DERIVED_CLOCK(1, 1)) + MCFG_CPU_PROGRAM_MAP(qs1000_prg_map) + MCFG_CPU_IO_MAP(qs1000_io_map) +MACHINE_CONFIG_END + + +// ROM definition for the QS1000 internal program ROM +ROM_START( qs1000 ) + ROM_REGION( 0x10000, "cpu", 0 ) + ROM_LOAD_OPTIONAL( "qs1000.bin", 0x0000, 0x10000, NO_DUMP ) +ROM_END + + +// Wavetable ROM address map +static ADDRESS_MAP_START( qs1000, AS_0, 8, qs1000_device ) + AM_RANGE(0x000000, 0xffffff) AM_ROM AM_REGION("qs1000", 0) +ADDRESS_MAP_END + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// qs1000_device - constructor +//------------------------------------------------- +qs1000_device::qs1000_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, QS1000, "QS1000", tag, owner, clock, "qs1000", __FILE__), + device_sound_interface(mconfig, *this), + device_memory_interface(mconfig, *this), + m_external_rom(false), + m_in_p1_cb(*this), + m_in_p2_cb(*this), + m_in_p3_cb(*this), + m_out_p1_cb(*this), + m_out_p2_cb(*this), + m_out_p3_cb(*this), + //m_serial_w_cb(*this), + m_space_config("samples", ENDIANNESS_LITTLE, 8, 24, 0, NULL), + m_stream(NULL), + m_direct(NULL), + m_cpu(*this, "cpu") +{ + m_address_map[0] = *ADDRESS_MAP_NAME(qs1000); +} + + +//------------------------------------------------- +// rom_region - return a pointer to the device's +// internal ROM region +//------------------------------------------------- +const rom_entry *qs1000_device::device_rom_region() const +{ + return m_external_rom ? NULL : ROM_NAME( qs1000 ); +} + + +//------------------------------------------------- +// machine_config_additions - return a pointer to +// the device's machine fragment +//------------------------------------------------- +machine_config_constructor qs1000_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( qs1000 ); +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- +void qs1000_device::device_start() +{ + // Find our direct access + m_direct = &space().direct(); + + // The QS1000 operates at 24MHz. Creating a stream at that rate + // would be overkill so we opt for a fraction of that rate which + // gives reasonable results + m_stream = stream_alloc(0, 2, clock() / 32); + + // Resolve CPU port callbacks + m_in_p1_cb.resolve_safe(0); + m_in_p2_cb.resolve_safe(0); + m_in_p3_cb.resolve_safe(0); + + m_out_p1_cb.resolve_safe(); + m_out_p2_cb.resolve_safe(); + m_out_p3_cb.resolve_safe(); + + //m_serial_w_cb.resolve_safe(); + + m_cpu->i8051_set_serial_rx_callback(read8_delegate(FUNC(qs1000_device::data_to_i8052),this)); + + save_item(NAME(m_serial_data_in)); + save_item(NAME(m_wave_regs)); + + for (int i = 0; i < QS1000_CHANNELS; i++) + { + save_item(NAME(m_channels[i].m_acc), i); + save_item(NAME(m_channels[i].m_adpcm_signal), i); + save_item(NAME(m_channels[i].m_start), i); + save_item(NAME(m_channels[i].m_addr), i); + save_item(NAME(m_channels[i].m_adpcm_addr), i); + save_item(NAME(m_channels[i].m_loop_start), i); + save_item(NAME(m_channels[i].m_loop_end), i); + save_item(NAME(m_channels[i].m_freq), i); + save_item(NAME(m_channels[i].m_flags), i); + save_item(NAME(m_channels[i].m_regs), i); + save_item(NAME(m_channels[i].m_adpcm.m_signal), i); + save_item(NAME(m_channels[i].m_adpcm.m_step), i); + } +} + + +//------------------------------------------------- +// serial_in - send data to the chip +//------------------------------------------------- +void qs1000_device::serial_in(UINT8 data) +{ + m_serial_data_in = data; + + // Signal to the CPU that data is available + m_cpu->set_input_line(MCS51_RX_LINE, ASSERT_LINE); + m_cpu->set_input_line(MCS51_RX_LINE, CLEAR_LINE); +} + + +//------------------------------------------------- +// set_irq - interrupt the internal CPU +//------------------------------------------------- +void qs1000_device::set_irq(int state) +{ + // Signal to the CPU that data is available + m_cpu->set_input_line(MCS51_INT1_LINE, state ? ASSERT_LINE : CLEAR_LINE); +} + + +//------------------------------------------------- +// data_to_i8052 - called by the 8052 core to +// receive serial data +//------------------------------------------------- +READ8_MEMBER(qs1000_device::data_to_i8052) +{ + return m_serial_data_in; +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- +void qs1000_device::device_reset() +{ + for (int ch = 0; ch < QS1000_CHANNELS; ++ch) + { + m_channels[ch].m_flags = 0; + } +} + + +//------------------------------------------------- +// memory_space_config - return a description of +// any address spaces owned by this device +//------------------------------------------------- +const address_space_config *qs1000_device::memory_space_config(address_spacenum spacenum) const +{ + return (spacenum == 0) ? &m_space_config : NULL; +} + + +//------------------------------------------------- +// device_timer - handle deferred writes and +// resets as a timer callback +//------------------------------------------------- +void qs1000_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ +} + + +//------------------------------------------------- +// p0_r +//------------------------------------------------- +READ8_MEMBER( qs1000_device::p0_r ) +{ + return 0xff; +} + + +//------------------------------------------------- +// p1_r +//------------------------------------------------- +READ8_MEMBER( qs1000_device::p1_r ) +{ + return m_in_p1_cb(0); +} + + +//------------------------------------------------- +// p2_r +//------------------------------------------------- +READ8_MEMBER( qs1000_device::p2_r ) +{ + return m_in_p2_cb(0); +} + + +//------------------------------------------------- +// p3_r +//------------------------------------------------- +READ8_MEMBER( qs1000_device::p3_r ) +{ + return m_in_p3_cb(0); +} + + +//------------------------------------------------- +// p0_w +//------------------------------------------------- +WRITE8_MEMBER( qs1000_device::p0_w ) +{ +} + + +//------------------------------------------------- +// p1_w +//------------------------------------------------- + +WRITE8_MEMBER( qs1000_device::p1_w ) +{ + m_out_p1_cb((offs_t)0, data); +} + + +//------------------------------------------------- +// p2_w +//------------------------------------------------- + +WRITE8_MEMBER( qs1000_device::p2_w ) +{ + m_out_p2_cb((offs_t)0, data); +} + + +//------------------------------------------------- +// p3_w +//------------------------------------------------- + +WRITE8_MEMBER( qs1000_device::p3_w ) +{ + m_out_p3_cb((offs_t)0, data); +} + + +//------------------------------------------------- +// wave_w - process writes to wavetable engine +//------------------------------------------------- + +WRITE8_MEMBER( qs1000_device::wave_w ) +{ + m_stream->update(); + + if (LOGGING_ENABLED) + printf("QS1000 W[%x] %x\n", 0x200 + offset, data); + + switch (offset) + { + case 0x00: + { + int ch = m_wave_regs[0xe]; + + if (data == 0) + { + // TODO + for (int i = 0; i < 16; ++i) + m_channels[ch].m_regs[i] = m_wave_regs[i]; + + // Key on + start_voice(ch); + } + if (data == 1) + { + // ? + } + else if (data == 2) + { + // Key off + m_channels[ch].m_flags &= ~QS1000_KEYON; + } + break; + } + + case 0x01: + case 0x02: + case 0x03: + case 0x04: + case 0x05: + case 0x06: + case 0x07: + case 0x08: + case 0x09: + case 0x0a: + case 0x0b: + case 0x0c: + case 0x0d: + { + if (m_wave_regs[0x11] == 3) + { + // Channel-specific write? + m_channels[m_wave_regs[0xe]].m_regs[offset] = data; + } + else + { + // Global write? + m_wave_regs[offset] = data; + } + break; + } + + default: + m_wave_regs[offset] = data; + } +} + + +//------------------------------------------------- +// sound_stream_update - +//------------------------------------------------- +void qs1000_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + // Rset the output stream + memset(outputs[0], 0x0, samples * sizeof(*outputs[0])); + memset(outputs[1], 0x0, samples * sizeof(*outputs[1])); + + // Iterate over voices and accumulate sample data + for (int ch = 0; ch < QS1000_CHANNELS; ch++) + { + qs1000_channel &chan = m_channels[ch]; + + UINT8 lvol = chan.m_regs[6]; + UINT8 rvol = chan.m_regs[7]; + UINT8 vol = chan.m_regs[8]; + + if (chan.m_flags & QS1000_PLAYING) + { + if (chan.m_flags & QS1000_ADPCM) + { + for (int samp = 0; samp < samples; samp++) + { + if (chan.m_addr >= chan.m_loop_end) + { +#if 0 // Looping disabled until envelopes work + if (chan.m_flags & QS1000_KEYON) + { + chan.m_addr = chan.m_loop_start; + } + else +#endif + { + chan.m_flags &= ~QS1000_PLAYING; + break; + } + } + + // Not too keen on this but it'll do for now + while (chan.m_start + chan.m_adpcm_addr != chan.m_addr) + { + chan.m_adpcm_addr++; + + if (chan.m_start + chan.m_adpcm_addr >= chan.m_loop_end) + chan.m_adpcm_addr = chan.m_loop_start - chan.m_start; + + UINT8 data = m_direct->read_byte(chan.m_start + (chan.m_adpcm_addr >> 1)); + UINT8 nibble = (chan.m_adpcm_addr & 1 ? data : data >> 4) & 0xf; + chan.m_adpcm_signal = chan.m_adpcm.clock(nibble); + } + + INT8 result = (chan.m_adpcm_signal >> 4); + chan.m_acc += chan.m_freq; + chan.m_addr = (chan.m_addr + (chan.m_acc >> 18)) & QS1000_ADDRESS_MASK; + chan.m_acc &= ((1 << 18) - 1); + + outputs[0][samp] += (result * 4 * lvol * vol) >> 12; + outputs[1][samp] += (result * 4 * rvol * vol) >> 12; + } + } + else + { + for (int samp = 0; samp < samples; samp++) + { + if (chan.m_addr >= chan.m_loop_end) + { +#if 0 // Looping disabled until envelopes work + if (chan.m_flags & QS1000_KEYON) + { + chan.m_addr = chan.m_loop_start; + } + else +#endif + { + chan.m_flags &= ~QS1000_PLAYING; + break; + } + } + + INT8 result = m_direct->read_byte(chan.m_addr) - 128; + + chan.m_acc += chan.m_freq; + chan.m_addr = (chan.m_addr + (chan.m_acc >> 18)) & QS1000_ADDRESS_MASK; + chan.m_acc &= ((1 << 18) - 1); + + outputs[0][samp] += (result * lvol * vol) >> 12; + outputs[1][samp] += (result * rvol * vol) >> 12; + } + } + } + } +} + + +void qs1000_device::start_voice(int ch) +{ + UINT32 table_addr = (m_channels[ch].m_regs[0x01] << 16) | (m_channels[ch].m_regs[0x02] << 8) | m_channels[ch].m_regs[0x03]; + + // Fetch the sound information + UINT16 freq = (m_direct->read_byte(table_addr + 0) << 8) | m_direct->read_byte(table_addr + 1); + UINT16 word1 = (m_direct->read_byte(table_addr + 2) << 8) | m_direct->read_byte(table_addr + 3); + UINT16 base = (m_direct->read_byte(table_addr + 4) << 8) | m_direct->read_byte(table_addr + 5); + + if (LOGGING_ENABLED) + printf("[%.6x] Freq:%.4x ????:%.4x Addr:%.4x\n", table_addr, freq, word1, base); + + // See Raccoon World and Wyvern Wings NULL sound + if (freq == 0) + return; + + // Fetch the sample pointers and flags + UINT8 byte0 = m_direct->read_byte(base); + + UINT32 start_addr; + + start_addr = byte0 << 16; + start_addr |= m_direct->read_byte(base + 1) << 8; + start_addr |= m_direct->read_byte(base + 2) << 0; + start_addr &= QS1000_ADDRESS_MASK; + + UINT32 loop_start; + + loop_start = (byte0 & 0xf0) << 16; + loop_start |= m_direct->read_byte(base + 3) << 12; + loop_start |= m_direct->read_byte(base + 4) << 4; + loop_start |= m_direct->read_byte(base + 5) >> 4; + loop_start &= QS1000_ADDRESS_MASK; + + UINT32 loop_end; + + loop_end = (byte0 & 0xf0) << 16; + loop_end |= (m_direct->read_byte(base + 5) & 0xf) << 16; + loop_end |= m_direct->read_byte(base + 6) << 8; + loop_end |= m_direct->read_byte(base + 7); + loop_end &= QS1000_ADDRESS_MASK; + + UINT8 byte8 = m_direct->read_byte(base + 8); + + if (LOGGING_ENABLED) + { + UINT8 byte9 = m_direct->read_byte(base + 9); + UINT8 byte10 = m_direct->read_byte(base + 10); + UINT8 byte11 = m_direct->read_byte(base + 11); + UINT8 byte12 = m_direct->read_byte(base + 12); + UINT8 byte13 = m_direct->read_byte(base + 13); + UINT8 byte14 = m_direct->read_byte(base + 14); + UINT8 byte15 = m_direct->read_byte(base + 15); + + printf("[%.6x] Sample Start:%.6x Loop Start:%.6x Loop End:%.6x Params: %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x\n", base, start_addr, loop_start, loop_end, byte8, byte9, byte10, byte11, byte12, byte13, byte14, byte15); + } + + m_channels[ch].m_acc = 0; + m_channels[ch].m_start = start_addr; + m_channels[ch].m_addr = start_addr; + m_channels[ch].m_loop_start = loop_start; + m_channels[ch].m_loop_end = loop_end; + m_channels[ch].m_freq = freq; + m_channels[ch].m_flags = QS1000_PLAYING | QS1000_KEYON; + + if (byte8 & 0x08) + { + m_channels[ch].m_adpcm.reset(); + m_channels[ch].m_adpcm_addr = -1; +// m_channels[ch].m_adpcm_signal = -2; + m_channels[ch].m_flags |= QS1000_ADPCM; + } +} diff --git a/src/devices/sound/qs1000.h b/src/devices/sound/qs1000.h new file mode 100644 index 00000000000..24b843184b4 --- /dev/null +++ b/src/devices/sound/qs1000.h @@ -0,0 +1,165 @@ +// license:BSD-3-Clause +// copyright-holders:Philip Bennett +/*************************************************************************** + + qs1000.h + + QS1000 device emulator. + +***************************************************************************/ + +#pragma once + +#ifndef __QS1000_H__ +#define __QS1000_H__ + +#include "cpu/mcs51/mcs51.h" +#include "sound/okiadpcm.h" + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_QS1000_EXTERNAL_ROM(_bool) \ + qs1000_device::set_external_rom(*device, _bool); + +#define MCFG_QS1000_IN_P1_CB(_devcb) \ + devcb = &qs1000_device::set_in_p1_callback(*device, DEVCB_##_devcb); + +#define MCFG_QS1000_IN_P2_CB(_devcb) \ + devcb = &qs1000_device::set_in_p2_callback(*device, DEVCB_##_devcb); + +#define MCFG_QS1000_IN_P3_CB(_devcb) \ + devcb = &qs1000_device::set_in_p3_callback(*device, DEVCB_##_devcb); + +#define MCFG_QS1000_OUT_P1_CB(_devcb) \ + devcb = &qs1000_device::set_out_p1_callback(*device, DEVCB_##_devcb); + +#define MCFG_QS1000_OUT_P2_CB(_devcb) \ + devcb = &qs1000_device::set_out_p2_callback(*device, DEVCB_##_devcb); + +#define MCFG_QS1000_OUT_P3_CB(_devcb) \ + devcb = &qs1000_device::set_out_p3_callback(*device, DEVCB_##_devcb); + +/*#define MCFG_QS1000_SERIAL_W_CB(_devcb) \ + devcb = &qs1000_device::set_serial_w_callback(*device, DEVCB_##_devcb);*/ + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +#define QS1000_CHANNELS 32 +#define QS1000_ADDRESS_MASK 0xffffff + +// ======================> qs1000_device + +class qs1000_device : public device_t, + public device_sound_interface, + public device_memory_interface +{ +public: + // construction/destruction + qs1000_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + static void set_external_rom(device_t &device, bool external_rom) { downcast(device).m_external_rom = external_rom; } + template static devcb_base &set_in_p1_callback(device_t &device, _Object object) { return downcast(device).m_in_p1_cb.set_callback(object); } + template static devcb_base &set_in_p2_callback(device_t &device, _Object object) { return downcast(device).m_in_p2_cb.set_callback(object); } + template static devcb_base &set_in_p3_callback(device_t &device, _Object object) { return downcast(device).m_in_p3_cb.set_callback(object); } + template static devcb_base &set_out_p1_callback(device_t &device, _Object object) { return downcast(device).m_out_p1_cb.set_callback(object); } + template static devcb_base &set_out_p2_callback(device_t &device, _Object object) { return downcast(device).m_out_p2_cb.set_callback(object); } + template static devcb_base &set_out_p3_callback(device_t &device, _Object object) { return downcast(device).m_out_p3_cb.set_callback(object); } + //template static devcb_base &set_serial_w_callback(device_t &device, _Object object) { return downcast(device).m_serial_w_cb.set_callback(object); } + + // external + void serial_in(UINT8 data); + void set_irq(int state); + +protected: + // device-level overrides + virtual const rom_entry *device_rom_region() const; + virtual machine_config_constructor device_mconfig_additions() const; + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const; + + // device_sound_interface overrides + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + + DECLARE_READ8_MEMBER( data_to_i8052 ); +public: + DECLARE_WRITE8_MEMBER( wave_w ); + + DECLARE_READ8_MEMBER( p0_r ); + DECLARE_WRITE8_MEMBER( p0_w ); + + DECLARE_READ8_MEMBER( p1_r ); + DECLARE_WRITE8_MEMBER( p1_w ); + + DECLARE_READ8_MEMBER( p2_r ); + DECLARE_WRITE8_MEMBER( p2_w ); + + DECLARE_READ8_MEMBER( p3_r ); + DECLARE_WRITE8_MEMBER( p3_w ); + + enum + { + QS1000_KEYON = 1, + QS1000_PLAYING = 2, + QS1000_ADPCM = 4 + }; + + void start_voice(int ch); + void set_voice_regs(int ch); + + bool m_external_rom; + + // Callbacks + devcb_read8 m_in_p1_cb; + devcb_read8 m_in_p2_cb; + devcb_read8 m_in_p3_cb; + + devcb_write8 m_out_p1_cb; + devcb_write8 m_out_p2_cb; + devcb_write8 m_out_p3_cb; + + //devcb_write8 m_serial_w_cb; + + // Internal state + const address_space_config m_space_config; + sound_stream * m_stream; + direct_read_data * m_direct; + required_device m_cpu; + + // Wavetable engine + UINT8 m_serial_data_in; + UINT8 m_wave_regs[18]; + + struct qs1000_channel + { + UINT32 m_acc; + INT32 m_adpcm_signal; + UINT32 m_start; + UINT32 m_addr; + UINT32 m_adpcm_addr; + UINT32 m_loop_start; + UINT32 m_loop_end; + UINT16 m_freq; + UINT16 m_flags; + + UINT8 m_regs[16]; // FIXME + + oki_adpcm_state m_adpcm; + }; + + qs1000_channel m_channels[QS1000_CHANNELS]; +}; + + +// device type definition +extern const device_type QS1000; + + +#endif /* __QS1000_H__ */ diff --git a/src/devices/sound/qsound.c b/src/devices/sound/qsound.c new file mode 100644 index 00000000000..c519da454a5 --- /dev/null +++ b/src/devices/sound/qsound.c @@ -0,0 +1,324 @@ +// license:??? +// copyright-holders:Paul Leaman, Miguel Angel Horna +/*************************************************************************** + + Capcom System QSound(tm) + ======================== + + Driver by Paul Leaman and Miguel Angel Horna + + A 16 channel stereo sample player. + + QSpace position is simulated by panning the sound in the stereo space. + + Many thanks to CAB (the author of Amuse), without whom this probably would + never have been finished. + + TODO: + - hook up the DSP! + - is master volume really linear? + - understand higher bits of reg 0 + - understand reg 9 + - understand other writes to $90-$ff area + +***************************************************************************/ + +#include "emu.h" +#include "qsound.h" + +// device type definition +const device_type QSOUND = &device_creator; + + +// program map for the DSP (points to internal 4096 words of internal ROM) +static ADDRESS_MAP_START( dsp16_program_map, AS_PROGRAM, 16, qsound_device ) + AM_RANGE(0x0000, 0x0fff) AM_ROM +ADDRESS_MAP_END + + +// data map for the DSP (the dsp16 appears to use 2048 words of internal RAM) +static ADDRESS_MAP_START( dsp16_data_map, AS_DATA, 16, qsound_device ) + ADDRESS_MAP_UNMAP_HIGH + AM_RANGE(0x0000, 0x07ff) AM_RAM +ADDRESS_MAP_END + + +// machine fragment +static MACHINE_CONFIG_FRAGMENT( qsound ) + MCFG_CPU_ADD("qsound", DSP16, QSOUND_CLOCK) + MCFG_CPU_PROGRAM_MAP(dsp16_program_map) + MCFG_CPU_DATA_MAP(dsp16_data_map) +MACHINE_CONFIG_END + + +// ROM definition for the Qsound program ROM +// NOTE: ROM is marked as bad since a handful of questionable bits haven't been fully examined. +ROM_START( qsound ) + ROM_REGION( 0x2000, "qsound", 0 ) + ROM_LOAD16_WORD( "qsound.bin", 0x0000, 0x2000, BAD_DUMP CRC(059c847d) SHA1(229cead1be2f86733dd80573d4983ba482355ece) ) +ROM_END + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// qsound_device - constructor +//------------------------------------------------- + +qsound_device::qsound_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, QSOUND, "Q-Sound", tag, owner, clock, "qsound", __FILE__), + device_sound_interface(mconfig, *this), + m_cpu(*this, "qsound"), + m_sample_rom(*this, DEVICE_SELF), + m_data(0), + m_stream(NULL) +{ +} + + +//------------------------------------------------- +// rom_region - return a pointer to the device's +// internal ROM region +//------------------------------------------------- + +const rom_entry *qsound_device::device_rom_region() const +{ + return ROM_NAME( qsound ); +} + + +//------------------------------------------------- +// machine_config_additions - return a pointer to +// the device's machine fragment +//------------------------------------------------- + +machine_config_constructor qsound_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( qsound ); +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void qsound_device::device_start() +{ + m_stream = stream_alloc(0, 2, clock() / 166); // /166 clock divider? + + // create pan table + for (int i = 0; i < 33; i++) + m_pan_table[i] = (int)((256 / sqrt(32.0)) * sqrt((double)i)); + + // init sound regs + memset(m_channel, 0, sizeof(m_channel)); + + for (int adr = 0x7f; adr >= 0; adr--) + write_data(adr, 0); + for (int adr = 0x80; adr < 0x90; adr++) + write_data(adr, 0x120); + + // state save + for (int i = 0; i < 16; i++) + { + save_item(NAME(m_channel[i].bank), i); + save_item(NAME(m_channel[i].address), i); + save_item(NAME(m_channel[i].freq), i); + save_item(NAME(m_channel[i].loop), i); + save_item(NAME(m_channel[i].end), i); + save_item(NAME(m_channel[i].vol), i); + save_item(NAME(m_channel[i].enabled), i); + save_item(NAME(m_channel[i].lvol), i); + save_item(NAME(m_channel[i].rvol), i); + save_item(NAME(m_channel[i].step_ptr), i); + } +} + + +//------------------------------------------------- +// sound_stream_update - handle a stream update +//------------------------------------------------- + +void qsound_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + // Clear the buffers + memset(outputs[0], 0, samples * sizeof(*outputs[0])); + memset(outputs[1], 0, samples * sizeof(*outputs[1])); + + for (int ch = 0; ch < 16; ch++) + { + if (m_channel[ch].enabled) + { + stream_sample_t *lmix=outputs[0]; + stream_sample_t *rmix=outputs[1]; + + // Go through the buffer and add voice contributions + for (int i = 0; i < samples; i++) + { + m_channel[ch].address += (m_channel[ch].step_ptr >> 12); + m_channel[ch].step_ptr &= 0xfff; + m_channel[ch].step_ptr += m_channel[ch].freq; + + if (m_channel[ch].address >= m_channel[ch].end) + { + if (m_channel[ch].loop) + { + // Reached the end, restart the loop + m_channel[ch].address -= m_channel[ch].loop; + + // Make sure we don't overflow (what does the real chip do in this case?) + if (m_channel[ch].address >= m_channel[ch].end) + m_channel[ch].address = m_channel[ch].end - m_channel[ch].loop; + + m_channel[ch].address &= 0xffff; + } + else + { + // Reached the end of a non-looped sample + m_channel[ch].enabled = false; + break; + } + } + + INT8 sample = read_sample(m_channel[ch].bank | m_channel[ch].address); + *lmix++ += ((sample * m_channel[ch].lvol * m_channel[ch].vol) >> 14); + *rmix++ += ((sample * m_channel[ch].rvol * m_channel[ch].vol) >> 14); + } + } + } +} + + +WRITE8_MEMBER(qsound_device::qsound_w) +{ + switch (offset) + { + case 0: + m_data = (m_data & 0x00ff) | (data << 8); + break; + + case 1: + m_data = (m_data & 0xff00) | data; + break; + + case 2: + m_stream->update(); + write_data(data, m_data); + break; + + default: + logerror("%s: qsound_w %d = %02x\n", machine().describe_context(), offset, data); + break; + } +} + + +READ8_MEMBER(qsound_device::qsound_r) +{ + /* Port ready bit (0x80 if ready) */ + return 0x80; +} + + +void qsound_device::write_data(UINT8 address, UINT16 data) +{ + int ch = 0, reg = 0; + + // direct sound reg + if (address < 0x80) + { + ch = address >> 3; + reg = address & 7; + } + + // >= 0x80 is probably for the dsp? + else if (address < 0x90) + { + ch = address & 0xf; + reg = 8; + } + else if (address >= 0xba && address < 0xca) + { + ch = address - 0xba; + reg = 9; + } + else + { + // unknown + reg = address; + } + + switch (reg) + { + case 0: + // bank, high bits unknown + ch = (ch + 1) & 0xf; // strange ... + m_channel[ch].bank = data << 16; + break; + + case 1: + // start/cur address + m_channel[ch].address = data; + break; + + case 2: + // frequency + m_channel[ch].freq = data; + if (data == 0) + { + // key off + m_channel[ch].enabled = false; + } + break; + + case 3: + // key on (does the value matter? it always writes 0x8000) + m_channel[ch].enabled = true; + m_channel[ch].step_ptr = 0; + break; + + case 4: + // loop address + m_channel[ch].loop = data; + break; + + case 5: + // end address + m_channel[ch].end = data; + break; + + case 6: + // master volume + m_channel[ch].vol = data; + break; + + case 7: + // unused? + break; + + case 8: + { + // panning (left=0x0110, centre=0x0120, right=0x0130) + // looks like it doesn't write other values than that + int pan = (data & 0x3f) - 0x10; + if (pan > 0x20) + pan = 0x20; + if (pan < 0) + pan = 0; + + m_channel[ch].rvol = m_pan_table[pan]; + m_channel[ch].lvol = m_pan_table[0x20 - pan]; + break; + } + + case 9: + // unknown + break; + + default: + //logerror("%s: write_data %02x = %04x\n", machine().describe_context(), address, data); + break; + } +} diff --git a/src/devices/sound/qsound.h b/src/devices/sound/qsound.h new file mode 100644 index 00000000000..208fdac41e9 --- /dev/null +++ b/src/devices/sound/qsound.h @@ -0,0 +1,81 @@ +// license:??? +// copyright-holders:Paul Leaman, Miguel Angel Horna +/********************************************************* + + Capcom Q-Sound system + +*********************************************************/ + +#pragma once + +#ifndef __QSOUND_H__ +#define __QSOUND_H__ + +#include "cpu/dsp16/dsp16.h" + +#define QSOUND_CLOCK 4000000 /* default 4MHz clock (60MHz/15?) */ + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_QSOUND_ADD(_tag, _clock) \ + MCFG_DEVICE_ADD(_tag, QSOUND, _clock) +#define MCFG_QSOUND_REPLACE(_tag, _clock) \ + MCFG_DEVICE_REPLACE(_tag, QSOUND, _clock) + + +// ======================> qsound_device + +class qsound_device : public device_t, + public device_sound_interface +{ +public: + qsound_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + ~qsound_device() { } + + DECLARE_WRITE8_MEMBER(qsound_w); + DECLARE_READ8_MEMBER(qsound_r); + +protected: + // device-level overrides + const rom_entry *device_rom_region() const; + machine_config_constructor device_mconfig_additions() const; + virtual void device_start(); + + // sound stream update overrides + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + +private: + struct qsound_channel + { + UINT32 bank; // bank + UINT32 address; // start/cur address + UINT16 loop; // loop address + UINT16 end; // end address + UINT32 freq; // frequency + UINT16 vol; // master volume + + // work variables + bool enabled; // key on / key off + int lvol; // left volume + int rvol; // right volume + UINT32 step_ptr; // current offset counter + } m_channel[16]; + + required_device m_cpu; + required_region_ptr m_sample_rom; + + int m_pan_table[33]; // pan volume table + UINT16 m_data; // register latch data + sound_stream *m_stream; // audio stream + + inline INT8 read_sample(UINT32 offset) { return m_sample_rom[offset & m_sample_rom.mask()]; } + void write_data(UINT8 address, UINT16 data); +}; + +extern const device_type QSOUND; + + +#endif /* __QSOUND_H__ */ diff --git a/src/devices/sound/rf5c400.c b/src/devices/sound/rf5c400.c new file mode 100644 index 00000000000..2e3b823c013 --- /dev/null +++ b/src/devices/sound/rf5c400.c @@ -0,0 +1,551 @@ +// license:BSD-3-Clause +// copyright-holders:Ville Linde +/* + Ricoh RF5C400 emulator + + Written by Ville Linde + Improvements by the hoot development team + + history - + 2007-02-08 hoot development team + looping + stereo panning + 8-bit sample support + + 2007-02-16 hoot development team + envelope + fixed volume table +*/ + +#include "emu.h" +#include "rf5c400.h" + +static int volume_table[256]; +static double pan_table[0x64]; + +/* envelope parameter (experimental) */ +#define ENV_AR_SPEED 0.1 +#define ENV_MIN_AR 0x02 +#define ENV_MAX_AR 0x80 +#define ENV_DR_SPEED 2.0 +#define ENV_MIN_DR 0x20 +#define ENV_MAX_DR 0x73 +#define ENV_RR_SPEED 0.7 +#define ENV_MIN_RR 0x20 +#define ENV_MAX_RR 0x54 + +/* PCM type */ +enum +{ + TYPE_MASK = 0x00C0, + TYPE_16 = 0x0000, + TYPE_8LOW = 0x0040, + TYPE_8HIGH = 0x0080 +}; + +/* envelope phase */ +enum +{ + PHASE_NONE = 0, + PHASE_ATTACK, + PHASE_DECAY, + PHASE_RELEASE +}; + + +// device type definition +const device_type RF5C400 = &device_creator; + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// rf5c400_device - constructor +//------------------------------------------------- + +rf5c400_device::rf5c400_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, RF5C400, "RF5C400", tag, owner, clock, "rf5c400", __FILE__), + device_sound_interface(mconfig, *this), + m_rom(*this, DEVICE_SELF), + m_stream(NULL) +{ + memset(m_env_ar_table, 0, sizeof(double)*0x9f); + memset(m_env_dr_table, 0, sizeof(double)*0x9f); + memset(m_env_rr_table, 0, sizeof(double)*0x9f); +} + + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void rf5c400_device::device_start() +{ + rf5c400_init_chip(); +} + +//------------------------------------------------- +// sound_stream_update - handle a stream update +//------------------------------------------------- + +void rf5c400_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + int i, ch; + INT16 *rom = m_rom; + UINT32 end, loop; + UINT64 pos; + UINT8 vol, lvol, rvol, type; + UINT8 env_phase; + double env_level, env_step, env_rstep; + + memset(outputs[0], 0, samples * sizeof(*outputs[0])); + memset(outputs[1], 0, samples * sizeof(*outputs[1])); + + for (ch=0; ch < 32; ch++) + { + rf5c400_channel *channel = &m_channels[ch]; + stream_sample_t *buf0 = outputs[0]; + stream_sample_t *buf1 = outputs[1]; + +// start = ((channel->startH & 0xFF00) << 8) | channel->startL; + end = ((channel->endHloopH & 0xFF) << 16) | channel->endL; + loop = ((channel->endHloopH & 0xFF00) << 8) | channel->loopL; + pos = channel->pos; + vol = channel->volume & 0xFF; + lvol = channel->pan & 0xFF; + rvol = channel->pan >> 8; + type = (channel->volume >> 8) & TYPE_MASK; + + env_phase = channel->env_phase; + env_level = channel->env_level; + env_step = channel->env_step; + env_rstep = env_step * channel->env_scale; + + for (i=0; i < samples; i++) + { + INT16 tmp; + INT32 sample; + + if (env_phase == PHASE_NONE) break; + + tmp = rom[(pos>>16) & m_rommask]; + switch ( type ) + { + case TYPE_16: + sample = tmp; + break; + case TYPE_8LOW: + sample = (INT16)(tmp << 8); + break; + case TYPE_8HIGH: + sample = (INT16)(tmp & 0xFF00); + break; + default: + sample = 0; + break; + } + + if ( sample & 0x8000 ) + { + sample ^= 0x7FFF; + } + + env_level += env_rstep; + switch (env_phase) + { + case PHASE_ATTACK: + if (env_level >= 1.0) + { + env_phase = PHASE_DECAY; + env_level = 1.0; + if (channel->decay & 0x0080) + { + env_step = 0.0; + } + else + { + env_step = + m_env_dr_table[decode80(channel->decay >> 8)]; + } + env_rstep = env_step * channel->env_scale; + } + break; + case PHASE_DECAY: + if (env_level <= 0.0) + { + env_phase = PHASE_NONE; + env_level = 0.0; + env_step = 0.0; + env_rstep = 0.0; + } + break; + case PHASE_RELEASE: + if (env_level <= 0.0) + { + env_phase = PHASE_NONE; + env_level = 0.0; + env_step = 0.0; + env_rstep = 0.0; + } + break; + } + + sample *= volume_table[vol]; + sample = (sample >> 9) * env_level; + *buf0++ += sample * pan_table[lvol]; + *buf1++ += sample * pan_table[rvol]; + + pos += channel->step; + if ( (pos>>16) > m_rom.length() || (pos>>16) > end) + { + pos -= loop<<16; + pos &= U64(0xFFFFFF0000); + } + + } + channel->pos = pos; + + channel->env_phase = env_phase; + channel->env_level = env_level; + channel->env_step = env_step; + } +} + + +/*****************************************************************************/ + +UINT8 rf5c400_device::decode80(UINT8 val) +{ + if (val & 0x80) + { + val = (val & 0x7f) + 0x1f; + } + + return val; +} + +void rf5c400_device::rf5c400_init_chip() +{ + int i; + + // init volume table + { + double max=255.0; + for (i = 0; i < 256; i++) { + volume_table[i]=(UINT16)max; + max /= pow(10.0,(double)((4.5/(256.0/16.0))/20)); + } + for(i = 0; i < 0x48; i++) { + pan_table[i] = sqrt( (double)(0x47 - i) ) / sqrt( (double)0x47 ); + } + for(i = 0x48; i < 0x64; i++) { + pan_table[i] = 0.0; + } + } + + // init envelope table + { + double r; + + // attack + r = 1.0 / (ENV_AR_SPEED * (clock() / 384)); + for (i = 0; i < ENV_MIN_AR; i++) + { + m_env_ar_table[i] = 1.0; + } + for (i = ENV_MIN_AR; i < ENV_MAX_AR; i++) + { + m_env_ar_table[i] = + r * (ENV_MAX_AR - i) / (ENV_MAX_AR - ENV_MIN_AR); + } + for (i = ENV_MAX_AR; i < 0x9f; i++) + { + m_env_ar_table[i] = 0.0; + } + + // decay + r = -5.0 / (ENV_DR_SPEED * (clock() / 384)); + for (i = 0; i < ENV_MIN_DR; i++) + { + m_env_dr_table[i] = r; + } + for (i = ENV_MIN_DR; i < ENV_MAX_DR; i++) + { + m_env_dr_table[i] = + r * (ENV_MAX_DR - i) / (ENV_MAX_DR - ENV_MIN_DR); + } + for (i = ENV_MAX_DR; i < 0x9f; i++) + { + m_env_dr_table[i] = 0.0; + } + + // release + r = -5.0 / (ENV_RR_SPEED * (clock() / 384)); + for (i = 0; i < ENV_MIN_RR; i++) + { + m_env_rr_table[i] = r; + } + for (i = ENV_MIN_RR; i < ENV_MAX_RR; i++) + { + m_env_rr_table[i] = + r * (ENV_MAX_RR - i) / (ENV_MAX_RR - ENV_MIN_RR); + } + for (i = ENV_MAX_RR; i < 0x9f; i++) + { + m_env_rr_table[i] = 0.0; + } + } + + // init channel info + for (i = 0; i < 32; i++) + { + m_channels[i].env_phase = PHASE_NONE; + m_channels[i].env_level = 0.0; + m_channels[i].env_step = 0.0; + m_channels[i].env_scale = 1.0; + } + + for (i = 0; i < ARRAY_LENGTH(m_channels); i++) + { + save_item(NAME(m_channels[i].startH), i); + save_item(NAME(m_channels[i].startL), i); + save_item(NAME(m_channels[i].freq), i); + save_item(NAME(m_channels[i].endL), i); + save_item(NAME(m_channels[i].endHloopH), i); + save_item(NAME(m_channels[i].loopL), i); + save_item(NAME(m_channels[i].pan), i); + save_item(NAME(m_channels[i].effect), i); + save_item(NAME(m_channels[i].volume), i); + save_item(NAME(m_channels[i].attack), i); + save_item(NAME(m_channels[i].decay), i); + save_item(NAME(m_channels[i].release), i); + save_item(NAME(m_channels[i].cutoff), i); + save_item(NAME(m_channels[i].pos), i); + save_item(NAME(m_channels[i].step), i); + save_item(NAME(m_channels[i].keyon), i); + save_item(NAME(m_channels[i].env_phase), i); + save_item(NAME(m_channels[i].env_level), i); + save_item(NAME(m_channels[i].env_step), i); + save_item(NAME(m_channels[i].env_scale), i); + } + + m_stream = stream_alloc(0, 2, clock()/384); + + m_rommask = m_rom.length() - 1; +} + + +/*****************************************************************************/ + +static UINT16 rf5c400_status = 0; +READ16_MEMBER( rf5c400_device::rf5c400_r ) +{ + switch(offset) + { + case 0x00: + { + return rf5c400_status; + } + + case 0x04: + { + return 0; + } + } + + return 0; +} + +WRITE16_MEMBER( rf5c400_device::rf5c400_w ) +{ + if (offset < 0x400) + { + switch(offset) + { + case 0x00: + { + rf5c400_status = data; + break; + } + + case 0x01: // channel control + { + int ch = data & 0x1f; + switch ( data & 0x60 ) + { + case 0x60: + m_channels[ch].pos = + ((m_channels[ch].startH & 0xFF00) << 8) | m_channels[ch].startL; + m_channels[ch].pos <<= 16; + + m_channels[ch].env_phase = PHASE_ATTACK; + m_channels[ch].env_level = 0.0; + m_channels[ch].env_step = + m_env_ar_table[decode80(m_channels[ch].attack >> 8)]; + break; + case 0x40: + if (m_channels[ch].env_phase != PHASE_NONE) + { + m_channels[ch].env_phase = PHASE_RELEASE; + if (m_channels[ch].release & 0x0080) + { + m_channels[ch].env_step = 0.0; + } + else + { + m_channels[ch].env_step = + m_env_rr_table[decode80(m_channels[ch].release >> 8)]; + } + } + break; + default: + m_channels[ch].env_phase = PHASE_NONE; + m_channels[ch].env_level = 0.0; + m_channels[ch].env_step = 0.0; + break; + } + break; + } + + case 0x08: // relative to env attack (channel no) + case 0x09: // relative to env attack (0x0c00/ 0x1c00) + + case 0x11: // ? counter for 0x13? + { + break; + } + case 0x13: // ? bujutsu writes sample data here + { + break; + } + + case 0x14: // ? related to 0x11/0x13 ? + break; + + case 0x21: // reverb(character).w + case 0x32: // reverb(pre-lpf).w + case 0x2B: // reverb(level).w + case 0x20: // ???.b : reverb(time).b + + case 0x2C: // chorus(level).w + case 0x30: // chorus(rate).w + case 0x22: // chorus(macro).w + case 0x23: // chorus(depth).w + case 0x24: // chorus(macro).w + case 0x2F: // chorus(depth).w + case 0x27: // chorus(send level to reverb).w + + default: + { + //osd_printf_debug("%s:rf5c400_w: %08X, %08X, %08X\n", machine().describe_context(), data, offset, mem_mask); + break; + } + } + //osd_printf_debug("%s:rf5c400_w: %08X, %08X, %08X at %08X\n", machine().describe_context(), data, offset, mem_mask); + } + else + { + // channel registers + int ch = (offset >> 5) & 0x1f; + int reg = (offset & 0x1f); + + rf5c400_channel *channel = &m_channels[ch]; + + switch (reg) + { + case 0x00: // sample start address, bits 23 - 16 + { + channel->startH = data; + break; + } + case 0x01: // sample start address, bits 15 - 0 + { + channel->startL = data; + break; + } + case 0x02: // sample playing frequency + { + channel->step = ((data & 0x1fff) << (data >> 13)) * 4; + channel->freq = data; + break; + } + case 0x03: // sample end address, bits 15 - 0 + { + channel->endL = data; + break; + } + case 0x04: // sample end address, bits 23 - 16 , sample loop 23 - 16 + { + channel->endHloopH = data; + break; + } + case 0x05: // sample loop offset, bits 15 - 0 + { + channel->loopL = data; + break; + } + case 0x06: // channel volume + { + channel->pan = data; + break; + } + case 0x07: // effect depth + { + // 0xCCRR: CC = chorus send depth, RR = reverb send depth + channel->effect = data; + break; + } + case 0x08: // volume, flag + { + channel->volume = data; + break; + } + case 0x09: // env attack + { + // 0x0100: max speed (in case of attack <= 0x40) + // 0xXX40: XX = attack-0x3f (encoded) (in case of attack > 0x40) + // + channel->attack = data; + break; + } + case 0x0A: // relative to env attack ? + { + // always 0x0100 + break; + } + case 0x0B: // relative to env decay ? + { + // always 0x0100 + break; + } + case 0x0C: // env decay + { + // 0xXX70: XX = decay (encoded) (in case of decay > 0x71) + // 0xXX80: XX = decay (encoded) (in case of decay <= 0x71) + channel->decay = data; + break; + } + case 0x0D: // relative to env release ? + { + // always 0x0100 + break; + } + case 0x0E: // env release + { + // 0xXX70: XX = release-0x1f (encoded) (0x01 if release <= 0x20) + channel->release = data; + break; + } + case 0x10: // resonance, cutoff freq. + { + // bit 15-12: resonance + // bit 11-0 : cutoff frequency + channel->cutoff = data; + break; + } + } + } +} diff --git a/src/devices/sound/rf5c400.h b/src/devices/sound/rf5c400.h new file mode 100644 index 00000000000..4781f8893d9 --- /dev/null +++ b/src/devices/sound/rf5c400.h @@ -0,0 +1,117 @@ +// license:BSD-3-Clause +// copyright-holders:Ville Linde +/* Ricoh RF5C400 emulator */ + +#pragma once + +#ifndef __RF5C400_H__ +#define __RF5C400_H__ + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_RF5C400_ADD(_tag, _clock) \ + MCFG_DEVICE_ADD(_tag, RF5C400, _clock) +#define MCFG_RF5C400_REPLACE(_tag, _clock) \ + MCFG_DEVICE_REPLACE(_tag, RF5C400, _clock) + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +struct rf5c400_channel +{ + rf5c400_channel() : + startH(0), + startL(0), + freq(0), + endL(0), + endHloopH(0), + loopL(0), + pan(0), + effect(0), + volume(0), + attack(0), + decay(0), + release(0), + cutoff(0), + pos(0), + step(0), + keyon(0), + env_phase(0), + env_level(0.0), + env_step(0.0), + env_scale(0.0) + { } + + UINT16 startH; + UINT16 startL; + UINT16 freq; + UINT16 endL; + UINT16 endHloopH; + UINT16 loopL; + UINT16 pan; + UINT16 effect; + UINT16 volume; + + UINT16 attack; + UINT16 decay; + UINT16 release; + + UINT16 cutoff; + + UINT64 pos; + UINT64 step; + UINT16 keyon; + + UINT8 env_phase; + double env_level; + double env_step; + double env_scale; +}; + + +// ======================> rf5c400_device + +class rf5c400_device : public device_t, + public device_sound_interface +{ +public: + rf5c400_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + ~rf5c400_device() { } + +protected: + // device-level overrides + virtual void device_start(); + + // sound stream update overrides + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + +public: + DECLARE_READ16_MEMBER( rf5c400_r ); + DECLARE_WRITE16_MEMBER( rf5c400_w ); + +private: + void rf5c400_init_chip(); + UINT8 decode80(UINT8 val); + +private: + required_region_ptr m_rom; + + UINT32 m_rommask; + + sound_stream *m_stream; + + double m_env_ar_table[0x9f]; + double m_env_dr_table[0x9f]; + double m_env_rr_table[0x9f]; + + rf5c400_channel m_channels[32]; +}; + +extern const device_type RF5C400; + + +#endif /* __RF5C400_H__ */ diff --git a/src/devices/sound/rf5c68.c b/src/devices/sound/rf5c68.c new file mode 100644 index 00000000000..af99edd197a --- /dev/null +++ b/src/devices/sound/rf5c68.c @@ -0,0 +1,233 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert,Aaron Giles +/*********************************************************/ +/* ricoh RF5C68(or clone) PCM controller */ +/*********************************************************/ + +#include "emu.h" +#include "rf5c68.h" + + +// device type definition +const device_type RF5C68 = &device_creator; + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// rf5c68_device - constructor +//------------------------------------------------- + +rf5c68_device::rf5c68_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, RF5C68, "RF5C68", tag, owner, clock, "rf5c68", __FILE__), + device_sound_interface(mconfig, *this), + m_stream(NULL), + m_cbank(0), + m_wbank(0), + m_enable(0) +{ + memset(m_data, 0, sizeof(UINT8)*0x10000); +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void rf5c68_device::device_start() +{ + m_sample_end_cb.bind_relative_to(*owner()); + + /* allocate memory for the chip */ + memset(m_data, 0xff, sizeof(m_data)); + + /* allocate the stream */ + m_stream = stream_alloc(0, 2, clock() / 384); +} + + +//------------------------------------------------- +// sound_stream_update - handle a stream update +//------------------------------------------------- + +void rf5c68_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + stream_sample_t *left = outputs[0]; + stream_sample_t *right = outputs[1]; + int i, j; + + /* start with clean buffers */ + memset(left, 0, samples * sizeof(*left)); + memset(right, 0, samples * sizeof(*right)); + + /* bail if not enabled */ + if (!m_enable) + return; + + /* loop over channels */ + for (i = 0; i < RF5C68_NUM_CHANNELS; i++) + { + rf5c68_pcm_channel *chan = &m_chan[i]; + + /* if this channel is active, accumulate samples */ + if (chan->enable) + { + int lv = (chan->pan & 0x0f) * chan->env; + int rv = ((chan->pan >> 4) & 0x0f) * chan->env; + + /* loop over the sample buffer */ + for (j = 0; j < samples; j++) + { + int sample; + + /* trigger sample callback */ + if(!m_sample_end_cb.isnull()) + { + if(((chan->addr >> 11) & 0xfff) == 0xfff) + m_sample_end_cb((chan->addr >> 11)/0x2000); + } + + /* fetch the sample and handle looping */ + sample = m_data[(chan->addr >> 11) & 0xffff]; + if (sample == 0xff) + { + chan->addr = chan->loopst << 11; + sample = m_data[(chan->addr >> 11) & 0xffff]; + + /* if we loop to a loop point, we're effectively dead */ + if (sample == 0xff) + break; + } + chan->addr += chan->step; + + /* add to the buffer */ + if (sample & 0x80) + { + sample &= 0x7f; + left[j] += (sample * lv) >> 5; + right[j] += (sample * rv) >> 5; + } + else + { + left[j] -= (sample * lv) >> 5; + right[j] -= (sample * rv) >> 5; + } + } + } + } + + /* now clamp and shift the result (output is only 10 bits) */ + for (j = 0; j < samples; j++) + { + stream_sample_t temp; + + temp = left[j]; + if (temp > 32767) temp = 32767; + else if (temp < -32768) temp = -32768; + left[j] = temp & ~0x3f; + + temp = right[j]; + if (temp > 32767) temp = 32767; + else if (temp < -32768) temp = -32768; + right[j] = temp & ~0x3f; + } +} + + +//------------------------------------------------- +// RF5C68 write register +//------------------------------------------------- + +READ8_MEMBER( rf5c68_device::rf5c68_r ) +{ + UINT8 shift; + + m_stream->update(); + shift = (offset & 1) ? 11 + 8 : 11; + +// printf("%08x\n",(m_chan[(offset & 0x0e) >> 1].addr)); + + return (m_chan[(offset & 0x0e) >> 1].addr) >> (shift); +} + +WRITE8_MEMBER( rf5c68_device::rf5c68_w ) +{ + rf5c68_pcm_channel *chan = &m_chan[m_cbank]; + int i; + + /* force the stream to update first */ + m_stream->update(); + + /* switch off the address */ + switch (offset) + { + case 0x00: /* envelope */ + chan->env = data; + break; + + case 0x01: /* pan */ + chan->pan = data; + break; + + case 0x02: /* FDL */ + chan->step = (chan->step & 0xff00) | (data & 0x00ff); + break; + + case 0x03: /* FDH */ + chan->step = (chan->step & 0x00ff) | ((data << 8) & 0xff00); + break; + + case 0x04: /* LSL */ + chan->loopst = (chan->loopst & 0xff00) | (data & 0x00ff); + break; + + case 0x05: /* LSH */ + chan->loopst = (chan->loopst & 0x00ff) | ((data << 8) & 0xff00); + break; + + case 0x06: /* ST */ + chan->start = data; + if (!chan->enable) + chan->addr = chan->start << (8 + 11); + break; + + case 0x07: /* control reg */ + m_enable = (data >> 7) & 1; + if (data & 0x40) + m_cbank = data & 7; + else + m_wbank = data & 15; + break; + + case 0x08: /* channel on/off reg */ + for (i = 0; i < 8; i++) + { + m_chan[i].enable = (~data >> i) & 1; + if (!m_chan[i].enable) + m_chan[i].addr = m_chan[i].start << (8 + 11); + } + break; + } +} + + +//------------------------------------------------- +// RF5C68 read memory +//------------------------------------------------- + +READ8_MEMBER( rf5c68_device::rf5c68_mem_r ) +{ + return m_data[m_wbank * 0x1000 + offset]; +} + + +//------------------------------------------------- +// RF5C68 write memory +//------------------------------------------------- + +WRITE8_MEMBER( rf5c68_device::rf5c68_mem_w ) +{ + m_data[m_wbank * 0x1000 + offset] = data; +} diff --git a/src/devices/sound/rf5c68.h b/src/devices/sound/rf5c68.h new file mode 100644 index 00000000000..8dafb114f21 --- /dev/null +++ b/src/devices/sound/rf5c68.h @@ -0,0 +1,96 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert,Aaron Giles +/*********************************************************/ +/* ricoh RF5C68(or clone) PCM controller */ +/*********************************************************/ + +#pragma once + +#ifndef __RF5C68_H__ +#define __RF5C68_H__ + +#define RF5C68_NUM_CHANNELS (8) + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_RF5C68_ADD(_tag, _clock) \ + MCFG_DEVICE_ADD(_tag, RF5C68, _clock) +#define MCFG_RF5C68_REPLACE(_tag, _clock) \ + MCFG_DEVICE_REPLACE(_tag, RF5C68, _clock) + +#define MCFG_RF5C68_SAMPLE_END_CB(_class, _method) \ + rf5c68_device::set_end_callback(*device, rf5c68_sample_end_cb_delegate(&_class::_method, #_class "::" #_method, downcast<_class *>(owner))); + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +typedef device_delegate rf5c68_sample_end_cb_delegate; + +#define RF5C68_SAMPLE_END_CB_MEMBER(_name) void _name(int channel) + + +struct rf5c68_pcm_channel +{ + rf5c68_pcm_channel() : + enable(0), + env(0), + pan(0), + start(0), + addr(0), + step(0), + loopst(0) {} + + UINT8 enable; + UINT8 env; + UINT8 pan; + UINT8 start; + UINT32 addr; + UINT16 step; + UINT16 loopst; +}; + + +// ======================> rf5c68_device + +class rf5c68_device : public device_t, + public device_sound_interface +{ +public: + rf5c68_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + ~rf5c68_device() { } + + static void set_end_callback(device_t &device, rf5c68_sample_end_cb_delegate callback) { downcast(device).m_sample_end_cb = callback; } + +protected: + // device-level overrides + virtual void device_start(); + + // sound stream update overrides + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + +public: + DECLARE_READ8_MEMBER( rf5c68_r ); + DECLARE_WRITE8_MEMBER( rf5c68_w ); + + DECLARE_READ8_MEMBER( rf5c68_mem_r ); + DECLARE_WRITE8_MEMBER( rf5c68_mem_w ); + +private: + sound_stream* m_stream; + rf5c68_pcm_channel m_chan[RF5C68_NUM_CHANNELS]; + UINT8 m_cbank; + UINT8 m_wbank; + UINT8 m_enable; + UINT8 m_data[0x10000]; + + rf5c68_sample_end_cb_delegate m_sample_end_cb; +}; + +extern const device_type RF5C68; + + +#endif /* __RF5C68_H__ */ diff --git a/src/devices/sound/s14001a.c b/src/devices/sound/s14001a.c new file mode 100644 index 00000000000..50cca284241 --- /dev/null +++ b/src/devices/sound/s14001a.c @@ -0,0 +1,651 @@ +// license:BSD-3-Clause +// copyright-holders:Jonathan Gevaryahu,R. Belmont,Zsolt Vasvari +/* + + TSI S14001A emulator v1.32 + By Jonathan Gevaryahu ("Lord Nightmare") with help from Kevin Horton ("kevtris") + MAME conversion and integration by R. Belmont + Clock Frequency control updated by Zsolt Vasvari + Other fixes by AtariAce + + Copyright (C) 2006-2013 Jonathan Gevaryahu aka Lord Nightmare + + Version history: + 0.8 initial version - LN + 0.9 MAME conversion, glue code added - R. Belmont + 1.0 partly fixed stream update - LN (0.111u4) + 1.01 fixed clipping problem - LN (0.111u5) + 1.1 add VSU-1000 features, fully fixed stream update by fixing word latching - LN (0.111u6) + 1.11 fix signedness of output, pre-multiply, fixes clicking on VSU-1000 volume change - LN (0.111u7) + 1.20 supports setting the clock freq directly - reset is done by external hardware, + the chip has no reset line ZV (0.122) + 1.30 move main dac to 4 bits only with no extension (4->16 bit range extension is now done by output). + Added a somewhat better, but still not perfect, filtering system - LN + 1.31 fix a minor bug with the dac range. wolfpack clips again, and I'm almost sure its an encoding error on the original speech - LN (0.125u9) + 1.31a Add chip pinout and other notes - LN (0.128u4) + 1.31b slight update to notes to clarify input bus stuff, mostly finish the state map in the comments - LN + 1.31c remove usage of deprecat lib - AtariAce (0.128u5) + 1.32 fix the squealing noise using a define; it isn't accurate to the chip exactly, but there are other issues which need to be fixed too. see TODO. - LN (0.136u2) + + TODO: + * increase accuracy of internal S14001A 'filter' for both driven and undriven cycles (its not terribly inaccurate for undriven cycles, but the dc sliding of driven cycles is not emulated) + * add option for and attach Frank P.'s emulation of the Analog external filter from the vsu-1000 using the discrete core. (with the direction of independent sound core and analog stuff, this should actually be attached in the main berzerk/frenzy driver and not here) + * fix the local and global silence stuff to not force the dac to a specific level, but cease doing deltas (i.e. force all deltas to 0) after the last sample; this should fix the clipping in wolfpack and in the fidelity games in mess. +*/ + +/* Chip Pinout: +The original datasheet (which is lost as far as I know) clearly called the +s14001a chip the 'CRC chip', or 'Custom Rom Controller', as it appears with +this name on the Stern and Canon schematics, as well as on some TSI speech +print advertisements. +Labels are not based on the labels used by the Atari wolf pack and Stern +schematics, as these are inconsistent. Atari calls the word select/speech address +input pins SAx while Stern calls them Cx. Also Atari and Canon both have the bit +ordering for the word select/speech address bus backwards, which may indicate it +was so on the original datasheet. Stern has it correct, and I've used their Cx +labeling. + + ______ ______ + _|o \__/ |_ + +5V -- |_|1 40|_| -> /BUSY* + _| |_ + ?TEST ?? |_|2 39|_| <- ROM D7 + _| |_ + XTAL CLOCK/CKC -> |_|3 38|_| -> ROM A11 + _| |_ + ROM CLOCK/CKR <- |_|4 37|_| <- ROM D6 + _| |_ + DIGITAL OUT 0 <- |_|5 36|_| -> ROM A10 + _| |_ + DIGITAL OUT 1 <- |_|6 35|_| -> ROM A9 + _| |_ + DIGITAL OUT 2 <- |_|7 34|_| <- ROM D5 + _| |_ + DIGITAL OUT 3 <- |_|8 33|_| -> ROM A8 + _| |_ + ROM /EN <- |_|9 32|_| <- ROM D4 + _| S |_ + START -> |_|10 7 1 T 31|_| -> ROM A7 + _| 7 4 S |_ + AUDIO OUT <- |_|11 3 0 I 30|_| <- ROM D3 + _| 7 0 |_ + ROM A0 <- |_|12 1 29|_| -> ROM A6 + _| A |_ +SPCH ADR BUS C0 -> |_|13 28|_| <- SPCH ADR BUS C5 + _| |_ + ROM A1 <- |_|14 27|_| <- ROM D2 + _| |_ +SPCH ADR BUS C1 -> |_|15 26|_| <- SPCH ADR BUS C4 + _| |_ + ROM A2 <- |_|16 25|_| <- ROM D1 + _| |_ +SPCH ADR BUS C2 -> |_|17 24|_| <- SPCH ADR BUS C3 + _| |_ + ROM A3 <- |_|18 23|_| <- ROM D0 + _| |_ + ROM A4 <- |_|19 22|_| -> ROM A5 + _| |_ + GND -- |_|20 21|_| -- -10V + |________________| + +*Note from Kevin Horton when testing the hookup of the S14001A: the /BUSY line +is not a standard voltage line: when it is in its HIGH state (i.e. not busy) it +puts out a voltage of -10 volts, so it needs to be dropped back to a sane +voltage level before it can be passed to any sort of modern IC. The address +lines for the speech rom (A0-A11) do not have this problem, they output at a +TTL/CMOS compatible voltage. The AUDIO OUT pin also outputs a voltage below GND, +and the TEST pins may do so too. + +START is pulled high when a word is to be said and the word number is on the +word select/speech address input lines. The Canon 'Canola' uses a separate 'rom +strobe' signal independent of the chip to either enable or clock the speech rom. +Its likely that they did this to be able to force the speech chip to stop talking, +which is normally impossible. The later 'version 3' TSI speech board as featured in +an advertisement in the John Cater book probably also has this feature, in addition +to external speech rom banking. + +The Digital out pins supply a copy of the 4-bit waveform which also goes to the +internal DAC. They are only valid every other clock cycle. It is possible that +on 'invalid' cycles they act as a 4 bit input to drive the dac. + +Because it requires -10V to operate, the chip manufacturing process must be PMOS. + +/-----------\ +> Operation < +\-----------/ +Put the 6-bit address of the word to be said onto the C0-C5 word select/speech +address bus lines. Next, clock the START line low-high-low. As long as the START +line is held high, the first address byte of the first word will be read repeatedly +every clock, with the rom enable line enabled constantly (i.e. it doesn't toggle on +and off as it normally does during speech). Once START has gone low-high-low, the +/BUSY line will go low until 3 clocks after the chip is done speaking. +*/ + + +/* state map: + + * state machine 1: odd/even clock state + * on even clocks, audio output is floating, /romen is low so rom data bus is driven, input is latched? + * on odd clocks, audio output is driven, /romen is high, state machine 2 is clocked + * ***** + * state machine 2: decoder state + * NOTE: holding the start line high forces the state machine 2 state to go to or remain in state 1! + * state 0(Idle): Idle (no sample rom bus activity, output at 0), next state is 0(Idle) + + * state 1(GetHiWord): + * grab byte at (wordinput<<1) -> register_WH + * reset output DAC accumulator to 0x8 <- ??? + * reset OldValHi to 1 + * reset OldValLo to 0 + * next state is 2(GetLoWord) UNLESS the PLAY line is still high, in which case the state remains at 1 + + * state 2(GetLoWord): + * grab byte at (wordinput<<1)+1 -> register_WL + * next state is 3(GetHiPhon) + + * state 3(GetHiPhon): + * grab byte at ((register_WH<<8) + (register_WL))>>4 -> phoneaddress + * next state is 4(GetLoPhon) + + * state 4(GetLoPhon): + * grab byte at (((register_WH<<8) + (register_WL))>>4)+1 -> playparams + * set phonepos register to 0 + * set oddphone register to 0 + * next state is 5(PlayForward1) + * playparams: + * 7 6 5 4 3 2 1 0 + * G G = LastPhone + * B B = PlayMode + * Y Y = Silenceflag + * S S S S = Length count load value + * R R R = Repeat count reload value (upon carry/overflow of 3 bits) + * load the repeat counter with the bits 'R R 0' + * load the length counter with the bits 'S S S 0' + * NOTE: though only three bits of the length counter load value are controllable, there is a fourth lower bit which is assumed 0 on start and controls the direction of playback, i.e. forwards or backwards within a phone. + * NOTE: though only two bits of the repeat counter reload value are controllable, there is a third bit which is loaded to 0 on phoneme start, and this hidden low-order bit of the counter itself is what controls whether the output is forced to silence in mirrored mode. the 'carry' from the highest bit of the 3 bit counter is what increments the address pointer for pointing to the next phoneme in mirrored mode + + + * shift register diagram: + * F E D C B A 9 8 7 6 5 4 3 2 1 0 + * + * C C C = Current delta sample read point + * O O O = Old delta sample read point + * I *OPTIMIZED OUT* the shift register by making use of the fact that the device reads each rom byte 4 times + + * state 5(PlayForward1): + * grab byte at (((phoneaddress<<8)+(oddphone*8))+(phonepos>>2)) -> PlayRegister high end, bits F to 8 + * if Playmode is mirrored, set OldValHi and OldValLo to 1 and 0 respectively, otherwise leave them with whatever was in them before. + * Put OldValHi in bit 7 of PlayRegister + * Put OldValLo in bit 6 of PlayRegister + * Get new OldValHi from bit 9 + * Get new OldValLo from bit 8 + * feed current delta (bits 9 and 8) and olddelta (bits 7 and 6) to delta demodulator table, delta demodulator table applies a delta to the accumulator, accumulator goes to enable/disable latch which Silenceflag enables or disables (forces output to 0x8 on disable), then to DAC to output. + * next state: state 6(PlayForward2) + + * state 6(PlayForward2): + * grab byte at (((phoneaddress<<8)+oddphone)+(phonepos>>2)) -> PlayRegister bits D to 6. + * Put OldValHi in bit 7 of PlayRegister\____already done by above operation + * Put OldValLo in bit 6 of PlayRegister/ + * Get new OldValHi from bit 9 + * Get new OldValLo from bit 8 + * feed current delta (bits 9 and 8) and olddelta (bits 7 and 6) to delta demodulator table, delta demodulator table applies a delta to the accumulator, accumulator goes to enable/disable latch which Silenceflag enables or disables (forces output to 0x8 on disable), then to DAC to output. + * next state: state 7(PlayForward3) + + * state 7(PlayForward3): + * grab byte at (((phoneaddress<<8)+oddphone)+(phonepos>>2)) -> PlayRegister bits B to 4. + * Put OldValHi in bit 7 of PlayRegister\____already done by above operation + * Put OldValLo in bit 6 of PlayRegister/ + * Get new OldValHi from bit 9 + * Get new OldValLo from bit 8 + * feed current delta (bits 9 and 8) and olddelta (bits 7 and 6) to delta demodulator table, delta demodulator table applies a delta to the accumulator, accumulator goes to enable/disable latch which Silenceflag enables or disables (forces output to 0x8 on disable), then to DAC to output. + * next state: state 8(PlayForward4) + + * state 8(PlayForward4): + * grab byte at (((phoneaddress<<8)+oddphone)+(phonepos>>2)) -> PlayRegister bits 9 to 2. + * Put OldValHi in bit 7 of PlayRegister\____already done by above operation + * Put OldValLo in bit 6 of PlayRegister/ + * Get new OldValHi from bit 9 + * Get new OldValLo from bit 8 + * feed current delta (bits 9 and 8) and olddelta (bits 7 and 6) to delta demodulator table, delta demodulator table applies a delta to the accumulator, accumulator goes to enable/disable latch which Silenceflag enables or disables (forces output to 0x8 on disable), then to DAC to output. + * if offset < 8, increment offset within 8-byte phone + * if offset = 8: (see PostPhoneme code to understand how this part works, its a bit complicated) + + * next state: depends on playparams: + * if we're in mirrored mode, next will be LoadAndPlayBackward1 + * if we're in nonmirrored mode, next will be PlayForward1 + + * state 9(LoadAndPlayBackward1) + * grab byte at (((phoneaddress<<8)+(oddphone*8))+(phonepos>>2)) -> PlayRegister high end, bits F to 8 <- check code on this, I think its backwards here but its correct in the code + * see code for this, its basically the same as state 8 but with the byte grab mentioned above, and the values fed to the delta demod table are switched + * state 10(PlayBackward2) + * see code for this, its basically the same as state 7 but the values fed to the delta demod table are switched + * state 11(PlayBackward3) + * see code for this, its basically the same as state 6 but the values fed to the delta demod table are switched + * state 12(PlayBackward4) + * see code for this, its basically the same as state 5 but with no byte grab, and the values fed to the delta demod table are switched, and a bit below similar to state 5 + * if offset > -1, decrement offset within 8-byte phone + * if offset = -1: (see PostPhoneme code to understand how this part works, its a bit complicated) +*/ + +/* increment address function: + * increment repeat counter + if repeat counter produces a carry, do two things: + 1. if mirrored mode is ON, increment oddphone. if oddphone carries out (i.e. if it was 1), increment phoneaddress and zero oddphone + 2. increment lengthcounter. if lengthcounter carries out, we're done this phone. + * increment output counter + * if mirrored mode is on, output direction is + * if mirrored mode is OFF, increment oddphone. if not, don't touch it here. if oddphone was 1 before the increment, increment phoneaddress and set oddphone to 0 + * + */ + +#undef ACCURATE_SQUEAL + +#include "emu.h" +#include "s14001a.h" + + +//#define DEBUGSTATE + +#define SILENCE 0x7 // value output when silent +#define ALTFLAG 0xFF // value to tell renderer that this frame's output is the average of the 8 prior frames and not directly used. + +#define LASTSYLLABLE ((m_PlayParams & 0x80)>>7) +#define MIRRORMODE ((m_PlayParams & 0x40)>>6) +#define SILENCEFLAG ((m_PlayParams & 0x20)>>5) +#define LENGTHCOUNT ((m_PlayParams & 0x1C)>>1) // remember: its 4 bits and the bottom bit is always zero! +#define REPEATCOUNT ((m_PlayParams<<1)&0x6) // remember: its 3 bits and the bottom bit is always zero! +#define LOCALSILENCESTATE ((m_OutputCounter & 0x2) && (MIRRORMODE)) // 1 when silent output, 0 when DAC output. + +static const INT8 DeltaTable[4][4] = +{ + { -3, -3, -1, -1, }, + { -1, -1, 0, 0, }, + { 0, 0, 1, 1, }, + { 1, 1, 3, 3 }, +}; + +#ifdef ACCURATE_SQUEAL +INT16 s14001a_device::audiofilter() /* rewrite me to better match the real filter! */ +{ + UINT8 temp1; + INT16 temp2 = 0; + /* mean averaging filter! 1/n exponential *would* be somewhat better, but I'm lazy... */ + for (temp1 = 0; temp1 < 8; temp1++) { temp2 += m_filtervals[temp1]; } + temp2 >>= 3; + return temp2; +} + +void s14001a_device::shiftIntoFilter(INT16 inputvalue) +{ + UINT8 temp1; + for (temp1 = 7; temp1 > 0; temp1--) + { + m_filtervals[temp1] = m_filtervals[(temp1 - 1)]; + } + m_filtervals[0] = inputvalue; +} +#endif + +void s14001a_device::PostPhoneme() /* figure out what the heck to do after playing a phoneme */ +{ +#ifdef DEBUGSTATE + fprintf(stderr,"0: entered PostPhoneme\n"); +#endif + m_RepeatCounter++; // increment the repeat counter + m_OutputCounter++; // increment the output counter + if (MIRRORMODE) // if mirroring is enabled + { +#ifdef DEBUGSTATE + fprintf(stderr,"1: MIRRORMODE was on\n"); +#endif + if (m_RepeatCounter == 0x8) // exceeded 3 bits? + { +#ifdef DEBUGSTATE + fprintf(stderr,"2: RepeatCounter was == 8\n"); +#endif + // reset repeat counter, increment length counter + // but first check if lowest bit is set + m_RepeatCounter = REPEATCOUNT; // reload repeat counter with reload value + if (m_LengthCounter & 0x1) // if low bit is 1 (will carry after increment) + { +#ifdef DEBUGSTATE + fprintf(stderr,"3: LengthCounter's low bit was 1\n"); +#endif + m_PhoneAddress+=8; // go to next phone in this syllable + } + m_LengthCounter++; + if (m_LengthCounter == 0x10) // if Length counter carried out of 4 bits + { +#ifdef DEBUGSTATE + fprintf(stderr,"3: LengthCounter overflowed\n"); +#endif + m_SyllableAddress += 2; // go to next syllable + m_nextstate = LASTSYLLABLE ? 13 : 3; // if we're on the last syllable, go to end state, otherwise go and load the next syllable. + } + else + { +#ifdef DEBUGSTATE + fprintf(stderr,"3: LengthCounter's low bit wasn't 1 and it didn't overflow\n"); +#endif + m_PhoneOffset = (m_OutputCounter&1) ? 7 : 0; + m_nextstate = (m_OutputCounter&1) ? 9 : 5; + } + } + else // repeatcounter did NOT carry out of 3 bits so leave length counter alone + { +#ifdef DEBUGSTATE + fprintf(stderr,"2: RepeatCounter is less than 8 (its actually %d)\n", m_RepeatCounter); +#endif + m_PhoneOffset = (m_OutputCounter&1) ? 7 : 0; + m_nextstate = (m_OutputCounter&1) ? 9 : 5; + } + } + else // if mirroring is NOT enabled + { +#ifdef DEBUGSTATE + fprintf(stderr,"1: MIRRORMODE was off\n"); +#endif + if (m_RepeatCounter == 0x8) // exceeded 3 bits? + { +#ifdef DEBUGSTATE + fprintf(stderr,"2: RepeatCounter was == 8\n"); +#endif + // reset repeat counter, increment length counter + m_RepeatCounter = REPEATCOUNT; // reload repeat counter with reload value + m_LengthCounter++; + if (m_LengthCounter == 0x10) // if Length counter carried out of 4 bits + { +#ifdef DEBUGSTATE + fprintf(stderr,"3: LengthCounter overflowed\n"); +#endif + m_SyllableAddress += 2; // go to next syllable + m_nextstate = LASTSYLLABLE ? 13 : 3; // if we're on the last syllable, go to end state, otherwise go and load the next syllable. +#ifdef DEBUGSTATE + fprintf(stderr,"nextstate is now %d\n", m_nextstate); // see line below, same reason. +#endif + return; // need a return here so we don't hit the 'nextstate = 5' line below + } + } + m_PhoneAddress += 8; // regardless of counters, the phone address always increments in non-mirrored mode + m_PhoneOffset = 0; + m_nextstate = 5; + } +#ifdef DEBUGSTATE + fprintf(stderr,"nextstate is now %d\n", m_nextstate); +#endif +} + +void s14001a_device::s14001a_clock() /* called once per clock */ +{ + UINT8 CurDelta; // Current delta + + /* on even clocks, audio output is floating, /romen is low so rom data bus is driven + * on odd clocks, audio output is driven, /romen is high, state machine 2 is clocked + */ + m_oddeven = !(m_oddeven); // invert the clock + if (m_oddeven == 0) // even clock + { +#ifdef ACCURATE_SQUEAL + m_audioout = ALTFLAG; // flag to the renderer that this output should be the average of the last 8 +#endif + // DIGITAL INPUT *MIGHT* occur on the test pins occurs on this cycle? + } + else // odd clock + { + // fix dac output between samples. theoretically this might be unnecessary but it would require some messy logic in state 5 on the first sample load. + // Note: this behavior is NOT accurate, and needs to be fixed. see TODO. + if (m_GlobalSilenceState || LOCALSILENCESTATE) + { + m_DACOutput = SILENCE; + m_OldDelta = 2; + } + m_audioout = (m_GlobalSilenceState || LOCALSILENCESTATE) ? SILENCE : m_DACOutput; // when either silence state is 1, output silence. + // DIGITAL OUTPUT *might* be driven onto the test pins on this cycle? + switch(m_machineState) // HUUUUUGE switch statement + { + case 0: // idle state + m_nextstate = 0; + break; + case 1: // read starting syllable high byte from word table + m_SyllableAddress = 0; // clear syllable address + m_SyllableAddress |= m_SpeechRom[(m_LatchedWord<<1)]<<4; + m_nextstate = m_resetState ? 1 : 2; + break; + case 2: // read starting syllable low byte from word table + m_SyllableAddress |= m_SpeechRom[(m_LatchedWord<<1)+1]>>4; + m_nextstate = 3; + break; + case 3: // read starting phone address + m_PhoneAddress = m_SpeechRom[m_SyllableAddress]<<4; + m_nextstate = 4; + break; + case 4: // read playback parameters and prepare for play + m_PlayParams = m_SpeechRom[m_SyllableAddress+1]; + m_GlobalSilenceState = SILENCEFLAG; // load phone silence flag + m_LengthCounter = LENGTHCOUNT; // load length counter + m_RepeatCounter = REPEATCOUNT; // load repeat counter + m_OutputCounter = 0; // clear output counter and disable mirrored phoneme silence indirectly via LOCALSILENCESTATE + m_PhoneOffset = 0; // set offset within phone to zero + m_OldDelta = 0x2; // set old delta to 2 <- is this right? + m_DACOutput = SILENCE ; // set DAC output to center/silence position + m_nextstate = 5; + break; + case 5: // Play phone forward, shift = 0 (also load) + CurDelta = (m_SpeechRom[(m_PhoneAddress)+m_PhoneOffset]&0xc0)>>6; // grab current delta from high 2 bits of high nybble + m_DACOutput += DeltaTable[CurDelta][m_OldDelta]; // send data to forward delta table and add result to accumulator + m_OldDelta = CurDelta; // Move current delta to old + m_nextstate = 6; + break; + case 6: // Play phone forward, shift = 2 + CurDelta = (m_SpeechRom[(m_PhoneAddress)+m_PhoneOffset]&0x30)>>4; // grab current delta from low 2 bits of high nybble + m_DACOutput += DeltaTable[CurDelta][m_OldDelta]; // send data to forward delta table and add result to accumulator + m_OldDelta = CurDelta; // Move current delta to old + m_nextstate = 7; + break; + case 7: // Play phone forward, shift = 4 + CurDelta = (m_SpeechRom[(m_PhoneAddress)+m_PhoneOffset]&0xc)>>2; // grab current delta from high 2 bits of low nybble + m_DACOutput += DeltaTable[CurDelta][m_OldDelta]; // send data to forward delta table and add result to accumulator + m_OldDelta = CurDelta; // Move current delta to old + m_nextstate = 8; + break; + case 8: // Play phone forward, shift = 6 (increment address if needed) + CurDelta = m_SpeechRom[(m_PhoneAddress)+m_PhoneOffset]&0x3; // grab current delta from low 2 bits of low nybble + m_DACOutput += DeltaTable[CurDelta][m_OldDelta]; // send data to forward delta table and add result to accumulator + m_OldDelta = CurDelta; // Move current delta to old + m_PhoneOffset++; // increment phone offset + if (m_PhoneOffset == 0x8) // if we're now done this phone + { + /* call the PostPhoneme Function */ + PostPhoneme(); + } + else + { + m_nextstate = 5; + } + break; + case 9: // Play phone backward, shift = 6 (also load) + CurDelta = (m_SpeechRom[(m_PhoneAddress)+m_PhoneOffset]&0x3); // grab current delta from low 2 bits of low nybble + if (m_laststate != 8) // ignore first (bogus) dac change in mirrored backwards mode. observations and the patent show this. + { + m_DACOutput -= DeltaTable[m_OldDelta][CurDelta]; // send data to forward delta table and subtract result from accumulator + } + m_OldDelta = CurDelta; // Move current delta to old + m_nextstate = 10; + break; + case 10: // Play phone backward, shift = 4 + CurDelta = (m_SpeechRom[(m_PhoneAddress)+m_PhoneOffset]&0xc)>>2; // grab current delta from high 2 bits of low nybble + m_DACOutput -= DeltaTable[m_OldDelta][CurDelta]; // send data to forward delta table and subtract result from accumulator + m_OldDelta = CurDelta; // Move current delta to old + m_nextstate = 11; + break; + case 11: // Play phone backward, shift = 2 + CurDelta = (m_SpeechRom[(m_PhoneAddress)+m_PhoneOffset]&0x30)>>4; // grab current delta from low 2 bits of high nybble + m_DACOutput -= DeltaTable[m_OldDelta][CurDelta]; // send data to forward delta table and subtract result from accumulator + m_OldDelta = CurDelta; // Move current delta to old + m_nextstate = 12; + break; + case 12: // Play phone backward, shift = 0 (increment address if needed) + CurDelta = (m_SpeechRom[(m_PhoneAddress)+m_PhoneOffset]&0xc0)>>6; // grab current delta from high 2 bits of high nybble + m_DACOutput -= DeltaTable[m_OldDelta][CurDelta]; // send data to forward delta table and subtract result from accumulator + m_OldDelta = CurDelta; // Move current delta to old + m_PhoneOffset--; // decrement phone offset + if (m_PhoneOffset == 0xFF) // if we're now done this phone + { + /* call the PostPhoneme() function */ + PostPhoneme(); + } + else + { + m_nextstate = 9; + } + break; + case 13: // For those pedantic among us, consume an extra two clocks like the real chip does. + m_nextstate = 0; + break; + } +#ifdef DEBUGSTATE + fprintf(stderr, "Machine state is now %d, was %d, PhoneOffset is %d\n", m_nextstate, m_machineState, m_PhoneOffset); +#endif + m_laststate = m_machineState; + m_machineState = m_nextstate; + + /* the dac is 4 bits wide. if a delta step forced it outside of 4 bits, mask it back over here */ + m_DACOutput &= 0xF; + } +} + +/************************************************************************** + MAME glue code + **************************************************************************/ + +int s14001a_device::bsy_r() +{ + m_stream->update(); +#ifdef DEBUGSTATE + fprintf(stderr,"busy state checked: %d\n",(m_machineState != 0) ); +#endif + return (m_machineState != 0); +} + +void s14001a_device::reg_w(int data) +{ + m_stream->update(); + m_WordInput = data; +} + +void s14001a_device::rst_w(int data) +{ + m_stream->update(); + m_LatchedWord = m_WordInput; + m_resetState = (data==1); + m_machineState = m_resetState ? 1 : m_machineState; +} + +void s14001a_device::set_clock(int clock) +{ + m_stream->set_sample_rate(clock); +} + +void s14001a_device::set_volume(int volume) +{ + m_stream->update(); + m_VSU1000_amp = volume; +} + +const device_type S14001A = &device_creator; + +s14001a_device::s14001a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, S14001A, "S14001A", tag, owner, clock, "s14001a", __FILE__), + device_sound_interface(mconfig, *this), + m_SpeechRom(*this, DEVICE_SELF), + m_stream(NULL), + m_WordInput(0), + m_LatchedWord(0), + m_SyllableAddress(0), + m_PhoneAddress(0), + m_PlayParams(0), + m_PhoneOffset(0), + m_LengthCounter(0), + m_RepeatCounter(0), + m_OutputCounter(0), + m_machineState(0), + m_nextstate(0), + m_laststate(0), + m_resetState(0), + m_oddeven(0), + m_GlobalSilenceState(1), + m_OldDelta(0x02), + m_DACOutput(SILENCE), + m_audioout(0), + m_VSU1000_amp(0) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void s14001a_device::device_start() +{ + int i; + + m_GlobalSilenceState = 1; + m_OldDelta = 0x02; + m_DACOutput = SILENCE; + + for (i = 0; i < 8; i++) + { + m_filtervals[i] = SILENCE; + } + + m_stream = machine().sound().stream_alloc(*this, 0, 1, clock() ? clock() : machine().sample_rate()); + + save_item(NAME(m_WordInput)); + save_item(NAME(m_LatchedWord)); + save_item(NAME(m_SyllableAddress)); + save_item(NAME(m_PhoneAddress)); + save_item(NAME(m_PlayParams)); + save_item(NAME(m_PhoneOffset)); + save_item(NAME(m_LengthCounter)); + save_item(NAME(m_RepeatCounter)); + save_item(NAME(m_OutputCounter)); + save_item(NAME(m_machineState)); + save_item(NAME(m_nextstate)); + save_item(NAME(m_laststate)); + save_item(NAME(m_resetState)); + save_item(NAME(m_oddeven)); + save_item(NAME(m_GlobalSilenceState)); + save_item(NAME(m_OldDelta)); + save_item(NAME(m_DACOutput)); + save_item(NAME(m_audioout)); + save_item(NAME(m_filtervals)); + save_item(NAME(m_VSU1000_amp)); +} + +//------------------------------------------------- +// sound_stream_update - handle a stream update +//------------------------------------------------- + +void s14001a_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + int i; + + for (i = 0; i < samples; i++) + { + s14001a_clock(); + #ifdef ACCURATE_SQUEAL + if (m_audioout == ALTFLAG) // input from test pins -> output + { + shiftIntoFilter(chip, audiofilter(chip)); // shift over the previous outputs and stick in audioout. + outputs[0][i] = audiofilter(chip)*m_VSU1000_amp; + } + else // normal, dac-driven output + { + shiftIntoFilter(chip, ((((INT16)m_audioout)-8)<<9)); // shift over the previous outputs and stick in audioout 4 times. note <<9 instead of <<10, to prevent clipping, and to simulate that the filtered output normally has a somewhat lower amplitude than the driven one. + #endif + outputs[0][i] = ((((INT16)m_audioout)-8)<<10)*m_VSU1000_amp; + #ifdef ACCURATE_SQUEAL + } + #endif + } +} diff --git a/src/devices/sound/s14001a.h b/src/devices/sound/s14001a.h new file mode 100644 index 00000000000..4427a59f8b7 --- /dev/null +++ b/src/devices/sound/s14001a.h @@ -0,0 +1,67 @@ +// license:LGPL-2.1+ +// copyright-holders:Jonathan Gevaryahu,R. Belmont,Zsolt Vasvari +#pragma once +/* + Copyright (C) 2006-2013 Jonathan Gevaryahu AKA Lord Nightmare + +*/ +#ifndef __S14001A_H__ +#define __S14001A_H__ + + +class s14001a_device : public device_t, + public device_sound_interface +{ +public: + s14001a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + ~s14001a_device() {} + + int bsy_r(); /* read BUSY pin */ + void reg_w(int data); /* write to input latch */ + void rst_w(int data); /* write to RESET pin */ + void set_clock(int clock); /* set VSU-1000 clock */ + void set_volume(int volume); /* set VSU-1000 volume control */ + +protected: + // device-level overrides + virtual void device_start(); + + // sound stream update overrides + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + +private: + // internal state + required_region_ptr m_SpeechRom; + sound_stream * m_stream; + + UINT8 m_WordInput; // value on word input bus + UINT8 m_LatchedWord; // value latched from input bus + UINT16 m_SyllableAddress; // address read from word table + UINT16 m_PhoneAddress; // starting/current phone address from syllable table + UINT8 m_PlayParams; // playback parameters from syllable table + UINT8 m_PhoneOffset; // offset within phone + UINT8 m_LengthCounter; // 4-bit counter which holds the inverted length of the word in phones, leftshifted by 1 + UINT8 m_RepeatCounter; // 3-bit counter which holds the inverted number of repeats per phone, leftshifted by 1 + UINT8 m_OutputCounter; // 2-bit counter to determine forward/backward and output/silence state. + UINT8 m_machineState; // chip state machine state + UINT8 m_nextstate; // chip state machine's new state + UINT8 m_laststate; // chip state machine's previous state, needed for mirror increment masking + UINT8 m_resetState; // reset line state + UINT8 m_oddeven; // odd versus even cycle toggle + UINT8 m_GlobalSilenceState; // same as above but for silent syllables instead of silent portions of mirrored syllables + UINT8 m_OldDelta; // 2-bit old delta value + UINT8 m_DACOutput; // 4-bit DAC Accumulator/output + UINT8 m_audioout; // filtered audio output + INT16 m_filtervals[8]; + UINT8 m_VSU1000_amp; // amplitude setting on VSU-1000 board + + INT16 audiofilter(); + void shiftIntoFilter(INT16 inputvalue); + void PostPhoneme(); + void s14001a_clock(); +}; + +extern const device_type S14001A; + + +#endif /* __S14001A_H__ */ diff --git a/src/devices/sound/saa1099.c b/src/devices/sound/saa1099.c new file mode 100644 index 00000000000..a915fa6ed38 --- /dev/null +++ b/src/devices/sound/saa1099.c @@ -0,0 +1,452 @@ +// license:BSD-3-Clause +// copyright-holders:Juergen Buchmueller, Manuel Abadia +/*************************************************************************** + + Philips SAA1099 Sound driver + + By Juergen Buchmueller and Manuel Abadia + + SAA1099 register layout: + ======================== + + offs | 7654 3210 | description + -----+-----------+--------------------------- + 0x00 | ---- xxxx | Amplitude channel 0 (left) + 0x00 | xxxx ---- | Amplitude channel 0 (right) + 0x01 | ---- xxxx | Amplitude channel 1 (left) + 0x01 | xxxx ---- | Amplitude channel 1 (right) + 0x02 | ---- xxxx | Amplitude channel 2 (left) + 0x02 | xxxx ---- | Amplitude channel 2 (right) + 0x03 | ---- xxxx | Amplitude channel 3 (left) + 0x03 | xxxx ---- | Amplitude channel 3 (right) + 0x04 | ---- xxxx | Amplitude channel 4 (left) + 0x04 | xxxx ---- | Amplitude channel 4 (right) + 0x05 | ---- xxxx | Amplitude channel 5 (left) + 0x05 | xxxx ---- | Amplitude channel 5 (right) + | | + 0x08 | xxxx xxxx | Frequency channel 0 + 0x09 | xxxx xxxx | Frequency channel 1 + 0x0a | xxxx xxxx | Frequency channel 2 + 0x0b | xxxx xxxx | Frequency channel 3 + 0x0c | xxxx xxxx | Frequency channel 4 + 0x0d | xxxx xxxx | Frequency channel 5 + | | + 0x10 | ---- -xxx | Channel 0 octave select + 0x10 | -xxx ---- | Channel 1 octave select + 0x11 | ---- -xxx | Channel 2 octave select + 0x11 | -xxx ---- | Channel 3 octave select + 0x12 | ---- -xxx | Channel 4 octave select + 0x12 | -xxx ---- | Channel 5 octave select + | | + 0x14 | ---- ---x | Channel 0 frequency enable (0 = off, 1 = on) + 0x14 | ---- --x- | Channel 1 frequency enable (0 = off, 1 = on) + 0x14 | ---- -x-- | Channel 2 frequency enable (0 = off, 1 = on) + 0x14 | ---- x--- | Channel 3 frequency enable (0 = off, 1 = on) + 0x14 | ---x ---- | Channel 4 frequency enable (0 = off, 1 = on) + 0x14 | --x- ---- | Channel 5 frequency enable (0 = off, 1 = on) + | | + 0x15 | ---- ---x | Channel 0 noise enable (0 = off, 1 = on) + 0x15 | ---- --x- | Channel 1 noise enable (0 = off, 1 = on) + 0x15 | ---- -x-- | Channel 2 noise enable (0 = off, 1 = on) + 0x15 | ---- x--- | Channel 3 noise enable (0 = off, 1 = on) + 0x15 | ---x ---- | Channel 4 noise enable (0 = off, 1 = on) + 0x15 | --x- ---- | Channel 5 noise enable (0 = off, 1 = on) + | | + 0x16 | ---- --xx | Noise generator parameters 0 + 0x16 | --xx ---- | Noise generator parameters 1 + | | + 0x18 | --xx xxxx | Envelope generator 0 parameters + 0x18 | x--- ---- | Envelope generator 0 control enable (0 = off, 1 = on) + 0x19 | --xx xxxx | Envelope generator 1 parameters + 0x19 | x--- ---- | Envelope generator 1 control enable (0 = off, 1 = on) + | | + 0x1c | ---- ---x | All channels enable (0 = off, 1 = on) + 0x1c | ---- --x- | Synch & Reset generators + + Version History: + ================ + ??-??-200? - First version of the driver submitted for MESS (GPL/MESS license) + ??-??-200? - Submitted to DOSBOX for Creative Music System/Game Blaster emulation + ??-??-201? - Driver relicensed to BSD 3 Clause (GPL+ compatible) + 06-27-2015 - Applied clock divisor fix from DOSBOX SVN, http://www.vogons.org/viewtopic.php?p=344227#p344227 + +***************************************************************************/ + +#include "emu.h" +#include "saa1099.h" + +#define LEFT 0x00 +#define RIGHT 0x01 + +static const int amplitude_lookup[16] = { + 0*32767/16, 1*32767/16, 2*32767/16, 3*32767/16, + 4*32767/16, 5*32767/16, 6*32767/16, 7*32767/16, + 8*32767/16, 9*32767/16, 10*32767/16, 11*32767/16, + 12*32767/16, 13*32767/16, 14*32767/16, 15*32767/16 +}; + +static const UINT8 envelope[8][64] = { + /* zero amplitude */ + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + /* maximum amplitude */ + {15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15, + 15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15, + 15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15, + 15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15, }, + /* single decay */ + {15,14,13,12,11,10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + /* repetitive decay */ + {15,14,13,12,11,10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, + 15,14,13,12,11,10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, + 15,14,13,12,11,10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, + 15,14,13,12,11,10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 }, + /* single triangular */ + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15, + 15,14,13,12,11,10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + /* repetitive triangular */ + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15, + 15,14,13,12,11,10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15, + 15,14,13,12,11,10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 }, + /* single attack */ + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + /* repetitive attack */ + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15 } +}; + + +// device type definition +const device_type SAA1099 = &device_creator; + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// saa1099_device - constructor +//------------------------------------------------- + +saa1099_device::saa1099_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, SAA1099, "SAA1099", tag, owner, clock, "saa1099", __FILE__), + device_sound_interface(mconfig, *this), + m_stream(NULL), + m_all_ch_enable(0), + m_sync_state(0), + m_selected_reg(0), + m_sample_rate(0.0) +{ + memset(m_noise_params, 0, sizeof(int)*2); + memset(m_env_enable, 0, sizeof(int)*2); + memset(m_env_reverse_right, 0, sizeof(int)*2); + memset(m_env_mode, 0, sizeof(int)*2); + memset(m_env_bits, 0, sizeof(int)*2); + memset(m_env_clock, 0, sizeof(int)*2); + memset(m_env_step, 0, sizeof(int)*2); +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void saa1099_device::device_start() +{ + /* copy global parameters */ + m_master_clock = clock(); + m_sample_rate = clock() / 256; + + /* for each chip allocate one stream */ + m_stream = stream_alloc(0, 2, m_sample_rate); + + save_item(NAME(m_noise_params)); + save_item(NAME(m_env_enable)); + save_item(NAME(m_env_reverse_right)); + save_item(NAME(m_env_mode)); + save_item(NAME(m_env_bits)); + save_item(NAME(m_env_clock)); + save_item(NAME(m_env_step)); + save_item(NAME(m_all_ch_enable)); + save_item(NAME(m_sync_state)); + save_item(NAME(m_selected_reg)); + + for (int i = 0; i < 6; i++) + { + save_item(NAME(m_channels[i].frequency), i); + save_item(NAME(m_channels[i].freq_enable), i); + save_item(NAME(m_channels[i].noise_enable), i); + save_item(NAME(m_channels[i].octave), i); + save_item(NAME(m_channels[i].amplitude), i); + save_item(NAME(m_channels[i].envelope), i); + save_item(NAME(m_channels[i].counter), i); + save_item(NAME(m_channels[i].freq), i); + save_item(NAME(m_channels[i].level), i); + } + + for (int i = 0; i < 2; i++) + { + save_item(NAME(m_noise[i].counter), i); + save_item(NAME(m_noise[i].freq), i); + save_item(NAME(m_noise[i].level), i); + } +} + + +//------------------------------------------------- +// sound_stream_update - handle a stream update +//------------------------------------------------- + +void saa1099_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + int j, ch; + /* if the channels are disabled we're done */ + if (!m_all_ch_enable) + { + /* init output data */ + memset(outputs[LEFT],0,samples*sizeof(*outputs[LEFT])); + memset(outputs[RIGHT],0,samples*sizeof(*outputs[RIGHT])); + return; + } + + for (ch = 0; ch < 2; ch++) + { + switch (m_noise_params[ch]) + { + case 0: m_noise[ch].freq = m_master_clock/256.0 * 2; break; + case 1: m_noise[ch].freq = m_master_clock/512.0 * 2; break; + case 2: m_noise[ch].freq = m_master_clock/1024.0 * 2; break; + case 3: m_noise[ch].freq = m_channels[ch * 3].freq; break; + } + } + + /* fill all data needed */ + for( j = 0; j < samples; j++ ) + { + int output_l = 0, output_r = 0; + + /* for each channel */ + for (ch = 0; ch < 6; ch++) + { + if (m_channels[ch].freq == 0.0) + m_channels[ch].freq = (double)((2 * m_master_clock / 512) << m_channels[ch].octave) / + (511.0 - (double)m_channels[ch].frequency); + + /* check the actual position in the square wave */ + m_channels[ch].counter -= m_channels[ch].freq; + while (m_channels[ch].counter < 0) + { + /* calculate new frequency now after the half wave is updated */ + m_channels[ch].freq = (double)((2 * m_master_clock / 512) << m_channels[ch].octave) / + (511.0 - (double)m_channels[ch].frequency); + + m_channels[ch].counter += m_sample_rate; + m_channels[ch].level ^= 1; + + /* eventually clock the envelope counters */ + if (ch == 1 && m_env_clock[0] == 0) + envelope_w(0); + if (ch == 4 && m_env_clock[1] == 0) + envelope_w(1); + } + + // if the noise is enabled + if (m_channels[ch].noise_enable) + { + // if the noise level is high (noise 0: chan 0-2, noise 1: chan 3-5) + if (m_noise[ch/3].level & 1) + { + // subtract to avoid overflows, also use only half amplitude + output_l -= m_channels[ch].amplitude[ LEFT] * m_channels[ch].envelope[ LEFT] / 16 / 2; + output_r -= m_channels[ch].amplitude[RIGHT] * m_channels[ch].envelope[RIGHT] / 16 / 2; + } + } + // if the square wave is enabled + if (m_channels[ch].freq_enable) + { + // if the channel level is high + if (m_channels[ch].level & 1) + { + output_l += m_channels[ch].amplitude[ LEFT] * m_channels[ch].envelope[ LEFT] / 16; + output_r += m_channels[ch].amplitude[RIGHT] * m_channels[ch].envelope[RIGHT] / 16; + } + } + } + + for (ch = 0; ch < 2; ch++) + { + /* check the actual position in noise generator */ + m_noise[ch].counter -= m_noise[ch].freq; + while (m_noise[ch].counter < 0) + { + m_noise[ch].counter += m_sample_rate; + if( ((m_noise[ch].level & 0x4000) == 0) == ((m_noise[ch].level & 0x0040) == 0) ) + m_noise[ch].level = (m_noise[ch].level << 1) | 1; + else + m_noise[ch].level <<= 1; + } + } + /* write sound data to the buffer */ + outputs[LEFT][j] = output_l / 6; + outputs[RIGHT][j] = output_r / 6; + } +} + + +void saa1099_device::envelope_w(int ch) +{ + if (m_env_enable[ch]) + { + int step, mode, mask; + mode = m_env_mode[ch]; + /* step from 0..63 and then loop in steps 32..63 */ + step = m_env_step[ch] = + ((m_env_step[ch] + 1) & 0x3f) | (m_env_step[ch] & 0x20); + + mask = 15; + if (m_env_bits[ch]) + mask &= ~1; /* 3 bit resolution, mask LSB */ + + m_channels[ch*3+0].envelope[ LEFT] = + m_channels[ch*3+1].envelope[ LEFT] = + m_channels[ch*3+2].envelope[ LEFT] = envelope[mode][step] & mask; + if (m_env_reverse_right[ch] & 0x01) + { + m_channels[ch*3+0].envelope[RIGHT] = + m_channels[ch*3+1].envelope[RIGHT] = + m_channels[ch*3+2].envelope[RIGHT] = (15 - envelope[mode][step]) & mask; + } + else + { + m_channels[ch*3+0].envelope[RIGHT] = + m_channels[ch*3+1].envelope[RIGHT] = + m_channels[ch*3+2].envelope[RIGHT] = envelope[mode][step] & mask; + } + } + else + { + /* envelope mode off, set all envelope factors to 16 */ + m_channels[ch*3+0].envelope[ LEFT] = + m_channels[ch*3+1].envelope[ LEFT] = + m_channels[ch*3+2].envelope[ LEFT] = + m_channels[ch*3+0].envelope[RIGHT] = + m_channels[ch*3+1].envelope[RIGHT] = + m_channels[ch*3+2].envelope[RIGHT] = 16; + } +} + + +WRITE8_MEMBER( saa1099_device::control_w ) +{ + if ((data & 0xff) > 0x1c) + { + /* Error! */ + logerror("%s: (SAA1099 '%s') Unknown register selected\n", machine().describe_context(), tag()); + } + + m_selected_reg = data & 0x1f; + if (m_selected_reg == 0x18 || m_selected_reg == 0x19) + { + /* clock the envelope channels */ + if (m_env_clock[0]) + envelope_w(0); + if (m_env_clock[1]) + envelope_w(1); + } +} + + +WRITE8_MEMBER( saa1099_device::data_w ) +{ + int reg = m_selected_reg; + int ch; + + /* first update the stream to this point in time */ + m_stream->update(); + + switch (reg) + { + /* channel i amplitude */ + case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: + ch = reg & 7; + m_channels[ch].amplitude[LEFT] = amplitude_lookup[data & 0x0f]; + m_channels[ch].amplitude[RIGHT] = amplitude_lookup[(data >> 4) & 0x0f]; + break; + /* channel i frequency */ + case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: + ch = reg & 7; + m_channels[ch].frequency = data & 0xff; + break; + /* channel i octave */ + case 0x10: case 0x11: case 0x12: + ch = (reg - 0x10) << 1; + m_channels[ch + 0].octave = data & 0x07; + m_channels[ch + 1].octave = (data >> 4) & 0x07; + break; + /* channel i frequency enable */ + case 0x14: + m_channels[0].freq_enable = data & 0x01; + m_channels[1].freq_enable = data & 0x02; + m_channels[2].freq_enable = data & 0x04; + m_channels[3].freq_enable = data & 0x08; + m_channels[4].freq_enable = data & 0x10; + m_channels[5].freq_enable = data & 0x20; + break; + /* channel i noise enable */ + case 0x15: + m_channels[0].noise_enable = data & 0x01; + m_channels[1].noise_enable = data & 0x02; + m_channels[2].noise_enable = data & 0x04; + m_channels[3].noise_enable = data & 0x08; + m_channels[4].noise_enable = data & 0x10; + m_channels[5].noise_enable = data & 0x20; + break; + /* noise generators parameters */ + case 0x16: + m_noise_params[0] = data & 0x03; + m_noise_params[1] = (data >> 4) & 0x03; + break; + /* envelope generators parameters */ + case 0x18: case 0x19: + ch = reg - 0x18; + m_env_reverse_right[ch] = data & 0x01; + m_env_mode[ch] = (data >> 1) & 0x07; + m_env_bits[ch] = data & 0x10; + m_env_clock[ch] = data & 0x20; + m_env_enable[ch] = data & 0x80; + /* reset the envelope */ + m_env_step[ch] = 0; + break; + /* channels enable & reset generators */ + case 0x1c: + m_all_ch_enable = data & 0x01; + m_sync_state = data & 0x02; + if (data & 0x02) + { + int i; + + /* Synch & Reset generators */ + logerror("%s: (SAA1099 '%s') -reg 0x1c- Chip reset\n", machine().describe_context(), tag()); + for (i = 0; i < 6; i++) + { + m_channels[i].level = 0; + m_channels[i].counter = 0.0; + } + } + break; + default: /* Error! */ + logerror("%s: (SAA1099 '%s') Unknown operation (reg:%02x, data:%02x)\n", machine().describe_context(), tag(), reg, data); + } +} diff --git a/src/devices/sound/saa1099.h b/src/devices/sound/saa1099.h new file mode 100644 index 00000000000..1909efa1c52 --- /dev/null +++ b/src/devices/sound/saa1099.h @@ -0,0 +1,112 @@ +// license:BSD-3-Clause +// copyright-holders:Juergen Buchmueller, Manuel Abadia +/********************************************** + Philips SAA1099 Sound driver +**********************************************/ + +#pragma once + +#ifndef __SAA1099_H__ +#define __SAA1099_H__ + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_SAA1099_ADD(_tag, _clock) \ + MCFG_DEVICE_ADD(_tag, SAA1099, _clock) +#define MCFG_SAA1099_REPLACE(_tag, _clock) \ + MCFG_DEVICE_REPLACE(_tag, SAA1099, _clock) + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +struct saa1099_channel +{ + saa1099_channel() : + frequency(0), + freq_enable(0), + noise_enable(0), + octave(0), + counter(0.0), + freq(0.0), + level(0) + { + memset(amplitude, 0, sizeof(int)*2); + memset(envelope, 0, sizeof(int)*2); + } + + int frequency; /* frequency (0x00..0xff) */ + int freq_enable; /* frequency enable */ + int noise_enable; /* noise enable */ + int octave; /* octave (0x00..0x07) */ + int amplitude[2]; /* amplitude (0x00..0x0f) */ + int envelope[2]; /* envelope (0x00..0x0f or 0x10 == off) */ + + /* vars to simulate the square wave */ + double counter; + double freq; + int level; +}; + +struct saa1099_noise +{ + saa1099_noise() : + counter(0.0), + freq(0.0), + level(0) {} + + /* vars to simulate the noise generator output */ + double counter; + double freq; + int level; /* noise polynomal shifter */ +}; + + +// ======================> saa1099_device + +class saa1099_device : public device_t, + public device_sound_interface +{ +public: + saa1099_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + ~saa1099_device() { } + +protected: + // device-level overrides + virtual void device_start(); + + // sound stream update overrides + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + +public: + DECLARE_WRITE8_MEMBER( control_w ); + DECLARE_WRITE8_MEMBER( data_w ); + +private: + void envelope_w(int ch); + +private: + sound_stream *m_stream; /* our stream */ + int m_noise_params[2]; /* noise generators parameters */ + int m_env_enable[2]; /* envelope generators enable */ + int m_env_reverse_right[2]; /* envelope reversed for right channel */ + int m_env_mode[2]; /* envelope generators mode */ + int m_env_bits[2]; /* non zero = 3 bits resolution */ + int m_env_clock[2]; /* envelope clock mode (non-zero external) */ + int m_env_step[2]; /* current envelope step */ + int m_all_ch_enable; /* all channels enable */ + int m_sync_state; /* sync all channels */ + int m_selected_reg; /* selected register */ + saa1099_channel m_channels[6]; /* channels */ + saa1099_noise m_noise[2]; /* noise generators */ + double m_sample_rate; + int m_master_clock; +}; + +extern const device_type SAA1099; + + +#endif /* __SAA1099_H__ */ diff --git a/src/devices/sound/samples.c b/src/devices/sound/samples.c new file mode 100644 index 00000000000..863e30f0832 --- /dev/null +++ b/src/devices/sound/samples.c @@ -0,0 +1,642 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + samples.c + + Sound device for sample playback. + +**************************************************************************** + + Playback of pre-recorded samples. Used for high-level simulation of + discrete sound circuits where proper low-level simulation isn't + available. Also used for tape loops and similar. + + Current limitations + - Only supports single channel samples! + + Considerations + - Maybe this should be part of the presentation layer + (artwork etc.) with samples specified in .lay files instead of + in drivers? + +***************************************************************************/ + +#include "emu.h" +#include "emuopts.h" +#include "samples.h" +#include "flac.h" + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +// device type definition +const device_type SAMPLES = &device_creator; + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// samples_device - constructors +//------------------------------------------------- + +samples_device::samples_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, SAMPLES, "Samples", tag, owner, clock, "samples", __FILE__), + device_sound_interface(mconfig, *this), + m_channels(0), + m_names(NULL) +{ +} + +samples_device::samples_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_sound_interface(mconfig, *this), + m_channels(0), + m_names(NULL) +{ +} + + +//************************************************************************** +// PUBLIC INTERFACE +//************************************************************************** + +//------------------------------------------------- +// start - start playing a loaded sample +//------------------------------------------------- + +void samples_device::start(UINT8 channel, UINT32 samplenum, bool loop) +{ + // if samples are disabled, just return quietly + if (m_sample.empty()) + return; + + assert(samplenum < m_sample.size()); + assert(channel < m_channels); + + // force an update before we start + channel_t &chan = m_channel[channel]; + chan.stream->update(); + + // update the parameters + sample_t &sample = m_sample[samplenum]; + chan.source = &sample.data[0]; + chan.source_length = sample.data.size(); + chan.source_num = (chan.source_length > 0) ? samplenum : -1; + chan.pos = 0; + chan.frac = 0; + chan.basefreq = sample.frequency; + chan.step = (INT64(chan.basefreq) << FRAC_BITS) / machine().sample_rate(); + chan.loop = loop; +} + + +//------------------------------------------------- +// start_raw - start playing an externally +// provided sample +//------------------------------------------------- + +void samples_device::start_raw(UINT8 channel, const INT16 *sampledata, UINT32 samples, UINT32 frequency, bool loop) +{ + assert(channel < m_channels); + + // force an update before we start + channel_t &chan = m_channel[channel]; + chan.stream->update(); + + // update the parameters + chan.source = sampledata; + chan.source_length = samples; + chan.source_num = -1; + chan.pos = 0; + chan.frac = 0; + chan.basefreq = frequency; + chan.step = (INT64(chan.basefreq) << FRAC_BITS) / machine().sample_rate(); + chan.loop = loop; +} + + +//------------------------------------------------- +// set_frequency - set the playback frequency of +// a sample +//------------------------------------------------- + +void samples_device::set_frequency(UINT8 channel, UINT32 freq) +{ + assert(channel < m_channels); + + // force an update before we start + channel_t &chan = m_channel[channel]; + chan.stream->update(); + chan.step = (INT64(freq) << FRAC_BITS) / machine().sample_rate(); +} + + +//------------------------------------------------- +// set_volume - set the playback volume of a +// sample +//------------------------------------------------- + +void samples_device::set_volume(UINT8 channel, float volume) +{ + assert(channel < m_channels); + + // force an update before we start + channel_t &chan = m_channel[channel]; + chan.stream->set_output_gain(0, volume); +} + + +//------------------------------------------------- +// pause - pause playback on a channel +//------------------------------------------------- + +void samples_device::pause(UINT8 channel, bool pause) +{ + assert(channel < m_channels); + + // force an update before we start + channel_t &chan = m_channel[channel]; + chan.paused = pause; +} + + +//------------------------------------------------- +// stop - stop playback on a channel +//------------------------------------------------- + +void samples_device::stop(UINT8 channel) +{ + assert(channel < m_channels); + + // force an update before we start + channel_t &chan = m_channel[channel]; + chan.source = NULL; + chan.source_num = -1; +} + + +//------------------------------------------------- +// stop_all - stop playback on all channels +//------------------------------------------------- + +void samples_device::stop_all() +{ + // just iterate over channels and stop them + for (UINT8 channel = 0; channel < m_channels; channel++) + stop(channel); +} + + +//------------------------------------------------- +// base_frequency - return the base frequency of +// a channel being played +//------------------------------------------------- + +UINT32 samples_device::base_frequency(UINT8 channel) const +{ + assert(channel < m_channels); + + // force an update before we start + const channel_t &chan = m_channel[channel]; + chan.stream->update(); + return chan.basefreq; +} + + +//------------------------------------------------- +// playing - return true if a sample is still +// playing on the given channel +//------------------------------------------------- + +bool samples_device::playing(UINT8 channel) const +{ + assert(channel < m_channels); + + // force an update before we start + const channel_t &chan = m_channel[channel]; + chan.stream->update(); + return (chan.source != NULL); +} + + + +//************************************************************************** +// DEVICE INTERFACE +//************************************************************************** + +//------------------------------------------------- +// device_start - handle device startup +//------------------------------------------------- + +void samples_device::device_start() +{ + // read audio samples + load_samples(); + + // allocate channels + m_channel.resize(m_channels); + for (int channel = 0; channel < m_channels; channel++) + { + // initialize channel + channel_t &chan = m_channel[channel]; + chan.stream = stream_alloc(0, 1, machine().sample_rate()); + chan.source = NULL; + chan.source_num = -1; + chan.step = 0; + chan.loop = 0; + chan.paused = 0; + + // register with the save state system + save_item(NAME(chan.source_length), channel); + save_item(NAME(chan.source_num), channel); + save_item(NAME(chan.pos), channel); + save_item(NAME(chan.frac), channel); + save_item(NAME(chan.step), channel); + save_item(NAME(chan.loop), channel); + save_item(NAME(chan.paused), channel); + } + + // initialize any custom handlers + m_samples_start_cb.bind_relative_to(*owner()); + + if (!m_samples_start_cb.isnull()) + m_samples_start_cb(); +} + + +//------------------------------------------------- +// device_reset - handle device reset +//------------------------------------------------- + +void samples_device::device_reset() +{ + stop_all(); +} + + +//------------------------------------------------- +// device_post_load - handle updating after a +// restore +//------------------------------------------------- + +void samples_device::device_post_load() +{ + // loop over channels + for (int channel = 0; channel < m_channels; channel++) + { + // attach any samples that were loaded and playing + channel_t &chan = m_channel[channel]; + if (chan.source_num >= 0 && chan.source_num < m_sample.size()) + { + sample_t &sample = m_sample[chan.source_num]; + chan.source = &sample.data[0]; + chan.source_length = sample.data.size(); + if (sample.data.empty()) + chan.source_num = -1; + } + + // validate the position against the length in case the sample is smaller + if (chan.source != NULL && chan.pos >= chan.source_length) + { + if (chan.loop) + chan.pos %= chan.source_length; + else + { + chan.source = NULL; + chan.source_num = -1; + } + } + } +} + + +//------------------------------------------------- +// sound_stream_update - update a sound stream +//------------------------------------------------- + +void samples_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + // find the channel with this stream + for (int channel = 0; channel < m_channels; channel++) + if (&stream == m_channel[channel].stream) + { + channel_t &chan = m_channel[channel]; + stream_sample_t *buffer = outputs[0]; + + // process if we still have a source and we're not paused + if (chan.source != NULL && !chan.paused) + { + // load some info locally + UINT32 pos = chan.pos; + UINT32 frac = chan.frac; + UINT32 step = chan.step; + const INT16 *sample = chan.source; + UINT32 sample_length = chan.source_length; + + while (samples--) + { + // do a linear interp on the sample + INT32 sample1 = sample[pos]; + INT32 sample2 = sample[(pos + 1) % sample_length]; + INT32 fracmult = frac >> (FRAC_BITS - 14); + *buffer++ = ((0x4000 - fracmult) * sample1 + fracmult * sample2) >> 14; + + // advance + frac += step; + pos += frac >> FRAC_BITS; + frac = frac & ((1 << FRAC_BITS) - 1); + + // handle looping/ending + if (pos >= sample_length) + { + if (chan.loop) + pos %= sample_length; + else + { + chan.source = NULL; + chan.source_num = -1; + if (samples > 0) + memset(buffer, 0, samples * sizeof(*buffer)); + samples = 0; + break; + } + } + } + + // push position back out + chan.pos = pos; + chan.frac = frac; + } + else + memset(buffer, 0, samples * sizeof(*buffer)); + break; + } +} + + + +//************************************************************************** +// INTERNAL HELPERS +//************************************************************************** + +//------------------------------------------------- +// read_sample - read a WAV or FLAC file as a +// sample +//------------------------------------------------- + +bool samples_device::read_sample(emu_file &file, sample_t &sample) +{ + // read the core header and make sure it's a proper file + UINT8 buf[4]; + UINT32 offset = file.read(buf, 4); + if (offset < 4) + { + osd_printf_warning("Unable to read %s, 0-byte file?\n", file.filename()); + return false; + } + + // look for the appropriate RIFF tag + if (memcmp(&buf[0], "RIFF", 4) == 0) + return read_wav_sample(file, sample); + else if (memcmp(&buf[0], "fLaC", 4) == 0) + return read_flac_sample(file, sample); + + // if nothing appropriate, emit a warning + osd_printf_warning("Unable to read %s, corrupt file?\n", file.filename()); + return false; +} + + +//------------------------------------------------- +// read_wav_sample - read a WAV file as a sample +//------------------------------------------------- + +bool samples_device::read_wav_sample(emu_file &file, sample_t &sample) +{ + // we already read the opening 'RIFF' tag + UINT32 offset = 4; + + // get the total size + UINT32 filesize; + offset += file.read(&filesize, 4); + if (offset < 8) + { + osd_printf_warning("Unexpected size offset %u (%s)\n", offset, file.filename()); + return false; + } + filesize = LITTLE_ENDIANIZE_INT32(filesize); + + // read the RIFF file type and make sure it's a WAVE file + char buf[32]; + offset += file.read(buf, 4); + if (offset < 12) + { + osd_printf_warning("Unexpected WAVE offset %u (%s)\n", offset, file.filename()); + return false; + } + if (memcmp(&buf[0], "WAVE", 4) != 0) + { + osd_printf_warning("Could not find WAVE header (%s)\n", file.filename()); + return false; + } + + // seek until we find a format tag + UINT32 length; + while (1) + { + offset += file.read(buf, 4); + offset += file.read(&length, 4); + length = LITTLE_ENDIANIZE_INT32(length); + if (memcmp(&buf[0], "fmt ", 4) == 0) + break; + + // seek to the next block + file.seek(length, SEEK_CUR); + offset += length; + if (offset >= filesize) + { + osd_printf_warning("Could not find fmt tag (%s)\n", file.filename()); + return false; + } + } + + // read the format -- make sure it is PCM + UINT16 temp16; + offset += file.read(&temp16, 2); + temp16 = LITTLE_ENDIANIZE_INT16(temp16); + if (temp16 != 1) + { + osd_printf_warning("unsupported format %u - only PCM is supported (%s)\n", temp16, file.filename()); + return false; + } + + // number of channels -- only mono is supported + offset += file.read(&temp16, 2); + temp16 = LITTLE_ENDIANIZE_INT16(temp16); + if (temp16 != 1) + { + osd_printf_warning("unsupported number of channels %u - only mono is supported (%s)\n", temp16, file.filename()); + return false; + } + + // sample rate + UINT32 rate; + offset += file.read(&rate, 4); + rate = LITTLE_ENDIANIZE_INT32(rate); + + // bytes/second and block alignment are ignored + offset += file.read(buf, 6); + + // bits/sample + UINT16 bits; + offset += file.read(&bits, 2); + bits = LITTLE_ENDIANIZE_INT16(bits); + if (bits != 8 && bits != 16) + { + osd_printf_warning("unsupported bits/sample %u - only 8 and 16 are supported (%s)\n", bits, file.filename()); + return false; + } + + // seek past any extra data + file.seek(length - 16, SEEK_CUR); + offset += length - 16; + + // seek until we find a data tag + while (1) + { + offset += file.read(buf, 4); + offset += file.read(&length, 4); + length = LITTLE_ENDIANIZE_INT32(length); + if (memcmp(&buf[0], "data", 4) == 0) + break; + + // seek to the next block + file.seek(length, SEEK_CUR); + offset += length; + if (offset >= filesize) + { + osd_printf_warning("Could not find data tag (%s)\n", file.filename()); + return false; + } + } + + // if there was a 0 length data block, we're done + if (length == 0) + { + osd_printf_warning("empty data block (%s)\n", file.filename()); + return false; + } + + // fill in the sample data + sample.frequency = rate; + + // read the data in + if (bits == 8) + { + sample.data.resize(length); + file.read(&sample.data[0], length); + + // convert 8-bit data to signed samples + UINT8 *tempptr = reinterpret_cast(&sample.data[0]); + for (INT32 sindex = length - 1; sindex >= 0; sindex--) + sample.data[sindex] = INT8(tempptr[sindex] ^ 0x80) * 256; + } + else + { + // 16-bit data is fine as-is + sample.data.resize(length / 2); + file.read(&sample.data[0], length); + + // swap high/low on big-endian systems + if (ENDIANNESS_NATIVE != ENDIANNESS_LITTLE) + for (UINT32 sindex = 0; sindex < length / 2; sindex++) + sample.data[sindex] = LITTLE_ENDIANIZE_INT16(sample.data[sindex]); + } + return true; +} + + +//------------------------------------------------- +// read_flac_sample - read a FLAC file as a sample +//------------------------------------------------- + +bool samples_device::read_flac_sample(emu_file &file, sample_t &sample) +{ + // seek back to the start of the file + file.seek(0, SEEK_SET); + + // create the FLAC decoder and fill in the sample data + flac_decoder decoder(file); + sample.frequency = decoder.sample_rate(); + + // error if more than 1 channel or not 16bpp + if (decoder.channels() != 1) + return false; + if (decoder.bits_per_sample() != 16) + return false; + + // resize the array and read + sample.data.resize(decoder.total_samples()); + if (!decoder.decode_interleaved(&sample.data[0], sample.data.size())) + return false; + + // finish up and clean up + decoder.finish(); + return true; +} + + +//------------------------------------------------- +// load_samples - load all the samples in our +// attached interface +// Returns true when all samples were successfully read, else false +//------------------------------------------------- + +bool samples_device::load_samples() +{ + bool ok = true; + // if the user doesn't want to use samples, bail + if (!machine().options().samples()) + return false; + + // iterate over ourself + const char *basename = machine().basename(); + samples_iterator iter(*this); + const char *altbasename = iter.altbasename(); + + // pre-size the array + m_sample.resize(iter.count()); + + // load the samples + int index = 0; + for (const char *samplename = iter.first(); samplename != NULL; index++, samplename = iter.next()) + { + // attempt to open as FLAC first + emu_file file(machine().options().sample_path(), OPEN_FLAG_READ); + file_error filerr = file.open(basename, PATH_SEPARATOR, samplename, ".flac"); + if (filerr != FILERR_NONE && altbasename != NULL) + filerr = file.open(altbasename, PATH_SEPARATOR, samplename, ".flac"); + + // if not, try as WAV + if (filerr != FILERR_NONE) + filerr = file.open(basename, PATH_SEPARATOR, samplename, ".wav"); + if (filerr != FILERR_NONE && altbasename != NULL) + filerr = file.open(altbasename, PATH_SEPARATOR, samplename, ".wav"); + + // if opened, read it + if (filerr == FILERR_NONE) + read_sample(file, m_sample[index]); + else if (filerr == FILERR_NOT_FOUND) + { + logerror("%s: Sample '%s' NOT FOUND\n", tag(), samplename); + ok = false; + } + } + return ok; +} diff --git a/src/devices/sound/samples.h b/src/devices/sound/samples.h new file mode 100644 index 00000000000..24bb4541766 --- /dev/null +++ b/src/devices/sound/samples.h @@ -0,0 +1,187 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + samples.h + + Sound device for sample playback. + +***************************************************************************/ + +#pragma once + +#ifndef __SAMPLES_H__ +#define __SAMPLES_H__ + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_SAMPLES_CHANNELS(_channels) \ + samples_device::static_set_channels(*device, _channels); + +#define MCFG_SAMPLES_NAMES(_names) \ + samples_device::static_set_samples_names(*device, _names); + +typedef device_delegate samples_start_cb_delegate; + +#define SAMPLES_START_CB_MEMBER(_name) void _name() + +#define MCFG_SAMPLES_START_CB(_class, _method) \ + samples_device::set_samples_start_callback(*device, samples_start_cb_delegate(&_class::_method, #_class "::" #_method, downcast<_class *>(owner))); + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> samples_device + +class samples_device : public device_t, + public device_sound_interface +{ +public: + // construction/destruction + samples_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // static configuration helpers + static void static_set_channels(device_t &device, UINT8 channels) { downcast(device).m_channels = channels; } + static void static_set_samples_names(device_t &device, const char *const *names) { downcast(device).m_names = names; } + static void set_samples_start_callback(device_t &device, samples_start_cb_delegate callback) { downcast(device).m_samples_start_cb = callback; } + + // getters + bool playing(UINT8 channel) const; + UINT32 base_frequency(UINT8 channel) const; + + // start/stop helpers + void start(UINT8 channel, UINT32 samplenum, bool loop = false); + void start_raw(UINT8 channel, const INT16 *sampledata, UINT32 samples, UINT32 frequency, bool loop = false); + void pause(UINT8 channel, bool pause = true); + void stop(UINT8 channel); + void stop_all(); + + // dynamic control + void set_frequency(UINT8 channel, UINT32 frequency); + void set_volume(UINT8 channel, float volume); + + // helpers + struct sample_t + { + // shouldn't need a copy, but in case it happens, catch it here + sample_t &operator=(const sample_t &rhs) { assert(false); return *this; } + + UINT32 frequency; // frequency of the sample + std::vector data; // 16-bit signed data + }; + static bool read_sample(emu_file &file, sample_t &sample); + + // interface + UINT8 m_channels; // number of discrete audio channels needed + const char *const *m_names; // array of sample names + samples_start_cb_delegate m_samples_start_cb; // optional callback + +protected: + // subclasses can do it this way + samples_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_post_load(); + + // device_sound_interface overrides + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + + // internal classes + struct channel_t + { + sound_stream * stream; + const INT16 * source; + INT32 source_length; + INT32 source_num; + UINT32 pos; + UINT32 frac; + UINT32 step; + UINT32 basefreq; + bool loop; + bool paused; + }; + + // internal helpers + static bool read_wav_sample(emu_file &file, sample_t &sample); + static bool read_flac_sample(emu_file &file, sample_t &sample); + bool load_samples(); + + // internal state + std::vector m_channel; + std::vector m_sample; + + // internal constants + static const UINT8 FRAC_BITS = 24; + static const UINT32 FRAC_ONE = 1 << FRAC_BITS; + static const UINT32 FRAC_MASK = FRAC_ONE - 1; +}; + +// iterator, since lots of people are interested in these devices +typedef device_type_iterator<&device_creator, samples_device> samples_device_iterator; + + +// ======================> samples_iterator + +class samples_iterator +{ +public: + // construction/destruction + samples_iterator(samples_device &device) + : m_samples(device), + m_current(-1) { } + + // getters + const char *altbasename() const { return (m_samples.m_names != NULL && m_samples.m_names[0] != NULL && m_samples.m_names[0][0] == '*') ? &m_samples.m_names[0][1] : NULL; } + + // iteration + const char *first() + { + if (m_samples.m_names == NULL || m_samples.m_names[0] == NULL) + return NULL; + m_current = 0; + if (m_samples.m_names[0][0] == '*') + m_current++; + return m_samples.m_names[m_current++]; + } + + const char *next() + { + if (m_current == -1 || m_samples.m_names[m_current] == NULL) + return NULL; + return m_samples.m_names[m_current++]; + } + + // counting + int count() + { + int save = m_current; + int result = 0; + for (const char *scan = first(); scan != NULL; scan = next()) + result++; + m_current = save; + return result; + } + +private: + // internal state + samples_device &m_samples; + int m_current; +}; + + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +// device type definition +extern const device_type SAMPLES; + + +#endif diff --git a/src/devices/sound/sb0400.c b/src/devices/sound/sb0400.c new file mode 100644 index 00000000000..343cb6aecaa --- /dev/null +++ b/src/devices/sound/sb0400.c @@ -0,0 +1,24 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +#include "sb0400.h" + +const device_type SB0400 = &device_creator; + +DEVICE_ADDRESS_MAP_START(map, 32, sb0400_device) +ADDRESS_MAP_END + +sb0400_device::sb0400_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : pci_device(mconfig, SB0400, "Creative Labs SB0400 Audigy2 Value", tag, owner, clock, "sb0400", __FILE__) +{ +} + +void sb0400_device::device_start() +{ + pci_device::device_start(); + add_map(64, M_IO, FUNC(sb0400_device::map)); +} + +void sb0400_device::device_reset() +{ + pci_device::device_reset(); +} diff --git a/src/devices/sound/sb0400.h b/src/devices/sound/sb0400.h new file mode 100644 index 00000000000..aeb1ec43e61 --- /dev/null +++ b/src/devices/sound/sb0400.h @@ -0,0 +1,27 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +// Creative labs SB0400 Audigy2 Value + +#ifndef SB0400_H +#define SB0400_H + +#include "machine/pci.h" + +#define MCFG_SB0400_ADD(_tag, _subdevice_id) \ + MCFG_PCI_DEVICE_ADD(_tag, SB0400, 0x11020008, 0x00, 0x040100, _subdevice_id) + +class sb0400_device : public pci_device { +public: + sb0400_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual void device_start(); + virtual void device_reset(); + +private: + DECLARE_ADDRESS_MAP(map, 32); +}; + +extern const device_type SB0400; + +#endif diff --git a/src/devices/sound/scsp.c b/src/devices/sound/scsp.c new file mode 100644 index 00000000000..df2a5ef0143 --- /dev/null +++ b/src/devices/sound/scsp.c @@ -0,0 +1,1574 @@ +// license:BSD-3-Clause +// copyright-holders:ElSemi, R. Belmont +/* + Sega/Yamaha YMF292-F (SCSP = Saturn Custom Sound Processor) emulation + By ElSemi + MAME/M1 conversion and cleanup by R. Belmont + Additional code and bugfixes by kingshriek + + This chip has 32 voices. Each voice can play a sample or be part of + an FM construct. Unlike traditional Yamaha FM chips, the base waveform + for the FM still comes from the wavetable RAM. + + ChangeLog: + * November 25, 2003 (ES) Fixed buggy timers and envelope overflows. + (RB) Improved sample rates other than 44100, multiple + chips now works properly. + * December 02, 2003 (ES) Added DISDL register support, improves mix. + * April 28, 2004 (ES) Corrected envelope rates, added key-rate scaling, + added ringbuffer support. + * January 8, 2005 (RB) Added ability to specify region offset for RAM. + * January 26, 2007 (ES) Added on-board DSP capability + * September 24, 2007 (RB+ES) Removed fake reverb. Rewrote timers and IRQ handling. + Fixed case where voice frequency is updated while looping. + Enabled DSP again. + * December 16, 2007 (kingshriek) Many EG bug fixes, implemented effects mixer, + implemented FM. + * January 5, 2008 (kingshriek+RB) Working, good-sounding FM, removed obsolete non-USEDSP code. + * April 22, 2009 ("PluginNinja") Improved slot monitor, misc cleanups + * June 6, 2011 (AS) Rewrote DMA from scratch, Darius 2 relies on it. +*/ + +#include "emu.h" +#include "sound/cdda.h" +#include "scsp.h" + + +#define ICLIP16(x) (x<-32768)?-32768:((x>32767)?32767:x) + +#define SHIFT 12 +#define LFO_SHIFT 8 +#define FIX(v) ((UINT32) ((float) (1<udata.data[0x0]>>0x0)&0x1000) +#define KEYONB(slot) ((slot->udata.data[0x0]>>0x0)&0x0800) +#define SBCTL(slot) ((slot->udata.data[0x0]>>0x9)&0x0003) +#define SSCTL(slot) ((slot->udata.data[0x0]>>0x7)&0x0003) +#define LPCTL(slot) ((slot->udata.data[0x0]>>0x5)&0x0003) +#define PCM8B(slot) ((slot->udata.data[0x0]>>0x0)&0x0010) + +#define SA(slot) (((slot->udata.data[0x0]&0xF)<<16)|(slot->udata.data[0x1])) + +#define LSA(slot) (slot->udata.data[0x2]) + +#define LEA(slot) (slot->udata.data[0x3]) + +#define D2R(slot) ((slot->udata.data[0x4]>>0xB)&0x001F) +#define D1R(slot) ((slot->udata.data[0x4]>>0x6)&0x001F) +#define EGHOLD(slot) ((slot->udata.data[0x4]>>0x0)&0x0020) +#define AR(slot) ((slot->udata.data[0x4]>>0x0)&0x001F) + +#define LPSLNK(slot) ((slot->udata.data[0x5]>>0x0)&0x4000) +#define KRS(slot) ((slot->udata.data[0x5]>>0xA)&0x000F) +#define DL(slot) ((slot->udata.data[0x5]>>0x5)&0x001F) +#define RR(slot) ((slot->udata.data[0x5]>>0x0)&0x001F) + +#define STWINH(slot) ((slot->udata.data[0x6]>>0x0)&0x0200) +#define SDIR(slot) ((slot->udata.data[0x6]>>0x0)&0x0100) +#define TL(slot) ((slot->udata.data[0x6]>>0x0)&0x00FF) + +#define MDL(slot) ((slot->udata.data[0x7]>>0xC)&0x000F) +#define MDXSL(slot) ((slot->udata.data[0x7]>>0x6)&0x003F) +#define MDYSL(slot) ((slot->udata.data[0x7]>>0x0)&0x003F) + +#define OCT(slot) ((slot->udata.data[0x8]>>0xB)&0x000F) +#define FNS(slot) ((slot->udata.data[0x8]>>0x0)&0x03FF) + +#define LFORE(slot) ((slot->udata.data[0x9]>>0x0)&0x8000) +#define LFOF(slot) ((slot->udata.data[0x9]>>0xA)&0x001F) +#define PLFOWS(slot) ((slot->udata.data[0x9]>>0x8)&0x0003) +#define PLFOS(slot) ((slot->udata.data[0x9]>>0x5)&0x0007) +#define ALFOWS(slot) ((slot->udata.data[0x9]>>0x3)&0x0003) +#define ALFOS(slot) ((slot->udata.data[0x9]>>0x0)&0x0007) + +#define ISEL(slot) ((slot->udata.data[0xA]>>0x3)&0x000F) +#define IMXL(slot) ((slot->udata.data[0xA]>>0x0)&0x0007) + +#define DISDL(slot) ((slot->udata.data[0xB]>>0xD)&0x0007) +#define DIPAN(slot) ((slot->udata.data[0xB]>>0x8)&0x001F) +#define EFSDL(slot) ((slot->udata.data[0xB]>>0x5)&0x0007) +#define EFPAN(slot) ((slot->udata.data[0xB]>>0x0)&0x001F) + +//Envelope times in ms +static const double ARTimes[64]={100000/*infinity*/,100000/*infinity*/,8100.0,6900.0,6000.0,4800.0,4000.0,3400.0,3000.0,2400.0,2000.0,1700.0,1500.0, + 1200.0,1000.0,860.0,760.0,600.0,500.0,430.0,380.0,300.0,250.0,220.0,190.0,150.0,130.0,110.0,95.0, + 76.0,63.0,55.0,47.0,38.0,31.0,27.0,24.0,19.0,15.0,13.0,12.0,9.4,7.9,6.8,6.0,4.7,3.8,3.4,3.0,2.4, + 2.0,1.8,1.6,1.3,1.1,0.93,0.85,0.65,0.53,0.44,0.40,0.35,0.0,0.0}; +static const double DRTimes[64]={100000/*infinity*/,100000/*infinity*/,118200.0,101300.0,88600.0,70900.0,59100.0,50700.0,44300.0,35500.0,29600.0,25300.0,22200.0,17700.0, + 14800.0,12700.0,11100.0,8900.0,7400.0,6300.0,5500.0,4400.0,3700.0,3200.0,2800.0,2200.0,1800.0,1600.0,1400.0,1100.0, + 920.0,790.0,690.0,550.0,460.0,390.0,340.0,270.0,230.0,200.0,170.0,140.0,110.0,98.0,85.0,68.0,57.0,49.0,43.0,34.0, + 28.0,25.0,22.0,18.0,14.0,12.0,11.0,8.5,7.1,6.1,5.4,4.3,3.6,3.1}; + +#define MEM4B() ((m_udata.data[0]>>0x0)&0x0200) +#define DAC18B() ((m_udata.data[0]>>0x0)&0x0100) +#define MVOL() ((m_udata.data[0]>>0x0)&0x000F) +#define RBL() ((m_udata.data[1]>>0x7)&0x0003) +#define RBP() ((m_udata.data[1]>>0x0)&0x003F) +#define MOFULL() ((m_udata.data[2]>>0x0)&0x1000) +#define MOEMPTY() ((m_udata.data[2]>>0x0)&0x0800) +#define MIOVF() ((m_udata.data[2]>>0x0)&0x0400) +#define MIFULL() ((m_udata.data[2]>>0x0)&0x0200) +#define MIEMPTY() ((m_udata.data[2]>>0x0)&0x0100) + +#define SCILV0() ((m_udata.data[0x24/2]>>0x0)&0xff) +#define SCILV1() ((m_udata.data[0x26/2]>>0x0)&0xff) +#define SCILV2() ((m_udata.data[0x28/2]>>0x0)&0xff) + +#define SCIEX0 0 +#define SCIEX1 1 +#define SCIEX2 2 +#define SCIMID 3 +#define SCIDMA 4 +#define SCIIRQ 5 +#define SCITMA 6 +#define SCITMB 7 + +#define USEDSP + +/* TODO */ +//#define dma_transfer_end ((scsp_regs[0x24/2] & 0x10)>>4)|(((scsp_regs[0x26/2] & 0x10)>>4)<<1)|(((scsp_regs[0x28/2] & 0x10)>>4)<<2) + +static const float SDLT[8]={-1000000.0f,-36.0f,-30.0f,-24.0f,-18.0f,-12.0f,-6.0f,0.0f}; + +const device_type SCSP = &device_creator; + +scsp_device::scsp_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, SCSP, "SCSP", tag, owner, clock, "scsp", __FILE__), + device_sound_interface(mconfig, *this), + m_roffset(0), + m_irq_cb(*this), + m_main_irq_cb(*this), + m_BUFPTR(0), + m_SCSPRAM(NULL), + m_SCSPRAM_LENGTH(0), + m_Master(0), + m_stream(NULL), + m_buffertmpl(NULL), + m_buffertmpr(NULL), + m_IrqTimA(0), + m_IrqTimBC(0), + m_IrqMidi(0), + m_MidiOutW(0), + m_MidiOutR(0), + m_MidiW(0), + m_MidiR(0), + m_timerA(NULL), + m_timerB(NULL), + m_timerC(NULL), + m_mcieb(0), + m_mcipd(0), + m_bufferl(NULL), + m_bufferr(NULL), + m_length(0), + m_RBUFDST(NULL) +{ + memset(m_RINGBUF, 0, sizeof(m_RINGBUF)); + memset(m_MidiStack, 0, sizeof(m_MidiStack)); + memset(m_LPANTABLE, 0, sizeof(m_LPANTABLE)); + memset(m_RPANTABLE, 0, sizeof(m_RPANTABLE)); + memset(m_TimPris, 0, sizeof(m_TimPris)); + memset(m_ARTABLE, 0, sizeof(m_ARTABLE)); + memset(m_DRTABLE, 0, sizeof(m_DRTABLE)); + memset(m_EG_TABLE, 0, sizeof(m_EG_TABLE)); + memset(m_PLFO_TRI, 0, sizeof(m_PLFO_TRI)); + memset(m_PLFO_SQR, 0, sizeof(m_PLFO_SQR)); + memset(m_PLFO_SAW, 0, sizeof(m_PLFO_SAW)); + memset(m_PLFO_NOI, 0, sizeof(m_PLFO_NOI)); + memset(m_ALFO_TRI, 0, sizeof(m_ALFO_TRI)); + memset(m_ALFO_SQR, 0, sizeof(m_ALFO_SQR)); + memset(m_ALFO_SAW, 0, sizeof(m_ALFO_SAW)); + memset(m_ALFO_NOI, 0, sizeof(m_ALFO_NOI)); + memset(m_PSCALES, 0, sizeof(m_PSCALES)); + memset(m_ASCALES, 0, sizeof(m_ASCALES)); + memset(&m_Slots, 0, sizeof(m_Slots)); + memset(&m_udata.data, 0, sizeof(m_udata.data)); + m_TimCnt[0] = 0; + m_TimCnt[1] = 0; + m_TimCnt[2] = 0; +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void scsp_device::device_start() +{ + // init the emulation + init(); + + // set up the IRQ callbacks + m_irq_cb.resolve_safe(); + m_main_irq_cb.resolve_safe(); + + m_stream = machine().sound().stream_alloc(*this, 0, 2, 44100); +} + +//------------------------------------------------- +// sound_stream_update - handle a stream update +//------------------------------------------------- + +void scsp_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + m_bufferl = outputs[0]; + m_bufferr = outputs[1]; + m_length = samples; + DoMasterSamples(samples); +} + +unsigned char scsp_device::DecodeSCI(unsigned char irq) +{ + unsigned char SCI=0; + unsigned char v; + v=(SCILV0()&(1<>8; + + CheckPendingIRQ(); + MainCheckPendingIRQ(0x40); +} + +TIMER_CALLBACK_MEMBER( scsp_device::timerB_cb ) +{ + m_TimCnt[1] = 0xFFFF; + m_udata.data[0x20/2]|=0x80; + m_udata.data[0x1a/2]&=0xff00; + m_udata.data[0x1a/2]|=m_TimCnt[1]>>8; + + CheckPendingIRQ(); +} + +TIMER_CALLBACK_MEMBER( scsp_device::timerC_cb ) +{ + m_TimCnt[2] = 0xFFFF; + m_udata.data[0x20/2]|=0x100; + m_udata.data[0x1c/2]&=0xff00; + m_udata.data[0x1c/2]|=m_TimCnt[2]>>8; + + CheckPendingIRQ(); +} + +int scsp_device::Get_AR(int base, int R) +{ + int Rate=base+(R<<1); + if(Rate>63) Rate=63; + if(Rate<0) Rate=0; + return m_ARTABLE[Rate]; +} + +int scsp_device::Get_DR(int base, int R) +{ + int Rate=base+(R<<1); + if(Rate>63) Rate=63; + if(Rate<0) Rate=0; + return m_DRTABLE[Rate]; +} + +int scsp_device::Get_RR(int base, int R) +{ + int Rate=base+(R<<1); + if(Rate>63) Rate=63; + if(Rate<0) Rate=0; + return m_DRTABLE[Rate]; +} + +void scsp_device::Compute_EG(SCSP_SLOT *slot) +{ + int octave=(OCT(slot)^8)-8; + int rate; + if(KRS(slot)!=0xf) + rate=octave+2*KRS(slot)+((FNS(slot)>>9)&1); + else + rate=0; //rate=((FNS(slot)>>9)&1); + + slot->EG.volume=0x17F<EG.AR=Get_AR(rate,AR(slot)); + slot->EG.D1R=Get_DR(rate,D1R(slot)); + slot->EG.D2R=Get_DR(rate,D2R(slot)); + slot->EG.RR=Get_RR(rate,RR(slot)); + slot->EG.DL=0x1f-DL(slot); + slot->EG.EGHOLD=EGHOLD(slot); +} + +int scsp_device::EG_Update(SCSP_SLOT *slot) +{ + switch(slot->EG.state) + { + case SCSP_ATTACK: + slot->EG.volume+=slot->EG.AR; + if(slot->EG.volume>=(0x3ff<EG.state=SCSP_DECAY1; + if(slot->EG.D1R>=(1024<EG.state=SCSP_DECAY2; + } + slot->EG.volume=0x3ff<EG.EGHOLD) + return 0x3ff<<(SHIFT-10); + break; + case SCSP_DECAY1: + slot->EG.volume-=slot->EG.D1R; + if(slot->EG.volume<=0) + slot->EG.volume=0; + if(slot->EG.volume>>(EG_SHIFT+5)<=slot->EG.DL) + slot->EG.state=SCSP_DECAY2; + break; + case SCSP_DECAY2: + if(D2R(slot)==0) + return (slot->EG.volume>>EG_SHIFT)<<(SHIFT-10); + slot->EG.volume-=slot->EG.D2R; + if(slot->EG.volume<=0) + slot->EG.volume=0; + + break; + case SCSP_RELEASE: + slot->EG.volume-=slot->EG.RR; + if(slot->EG.volume<=0) + { + slot->EG.volume=0; + StopSlot(slot,0); + //slot->EG.volume=0x17F<EG.state=SCSP_ATTACK; + } + break; + default: + return 1<EG.volume>>EG_SHIFT)<<(SHIFT-10); +} + +UINT32 scsp_device::Step(SCSP_SLOT *slot) +{ + int octave=(OCT(slot)^8)-8+SHIFT-10; + UINT32 Fn=FNS(slot)+(1 << 10); + if (octave >= 0) + { + Fn<<=octave; + } + else + { + Fn>>=-octave; + } + + return Fn; +} + + +void scsp_device::Compute_LFO(SCSP_SLOT *slot) +{ + if(PLFOS(slot)!=0) + LFO_ComputeStep(&(slot->PLFO),LFOF(slot),PLFOWS(slot),PLFOS(slot),0); + if(ALFOS(slot)!=0) + LFO_ComputeStep(&(slot->ALFO),LFOF(slot),ALFOWS(slot),ALFOS(slot),1); +} + +void scsp_device::StartSlot(SCSP_SLOT *slot) +{ + UINT32 start_offset; + + slot->active=1; + start_offset = PCM8B(slot) ? SA(slot) : SA(slot) & 0x7FFFE; + slot->base=m_SCSPRAM + start_offset; + slot->cur_addr=0; + slot->nxt_addr=1<step=Step(slot); + Compute_EG(slot); + slot->EG.state=SCSP_ATTACK; + slot->EG.volume=0x17F<Prev=0; + slot->Backwards=0; + + Compute_LFO(slot); + +// printf("StartSlot[%p]: SA %x PCM8B %x LPCTL %x ALFOS %x STWINH %x TL %x EFSDL %x\n", slot, SA(slot), PCM8B(slot), LPCTL(slot), ALFOS(slot), STWINH(slot), TL(slot), EFSDL(slot)); +} + +void scsp_device::StopSlot(SCSP_SLOT *slot,int keyoff) +{ + if(keyoff /*&& slot->EG.state!=SCSP_RELEASE*/) + { + slot->EG.state=SCSP_RELEASE; + } + else + { + slot->active=0; + } + slot->udata.data[0]&=~0x800; +} + +#define log_base_2(n) (log((double)(n))/log(2.0)) + +void scsp_device::init() +{ + int i; + + SCSPDSP_Init(&m_DSP); + + m_IrqTimA = m_IrqTimBC = m_IrqMidi = 0; + m_MidiR=m_MidiW=0; + m_MidiOutR=m_MidiOutW=0; + + // get SCSP RAM + if (strcmp(tag(), ":scsp") == 0 || strcmp(tag(), ":scsp1") == 0) + { + m_Master=1; + } + else + { + m_Master=0; + } + + m_SCSPRAM = region()->base(); + if (m_SCSPRAM) + { + m_SCSPRAM_LENGTH = region()->bytes(); + m_DSP.SCSPRAM = (UINT16 *)m_SCSPRAM; + m_DSP.SCSPRAM_LENGTH = m_SCSPRAM_LENGTH/2; + m_SCSPRAM += m_roffset; + } + + m_timerA = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(scsp_device::timerA_cb), this)); + m_timerB = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(scsp_device::timerB_cb), this)); + m_timerC = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(scsp_device::timerC_cb), this)); + + for(i=0;i<0x400;++i) + { + float envDB=((float)(3*(i-0x3ff)))/32.0f; + float scale=(float)(1<>0x0)&0xff; + int iPAN=(i>>0x8)&0x1f; + int iSDL=(i>>0xD)&0x07; + float TL=1.0f; + float SegaDB=0.0f; + float fSDL=1.0f; + float PAN=1.0f; + float LPAN,RPAN; + + if(iTL&0x01) SegaDB-=0.4f; + if(iTL&0x02) SegaDB-=0.8f; + if(iTL&0x04) SegaDB-=1.5f; + if(iTL&0x08) SegaDB-=3.0f; + if(iTL&0x10) SegaDB-=6.0f; + if(iTL&0x20) SegaDB-=12.0f; + if(iTL&0x40) SegaDB-=24.0f; + if(iTL&0x80) SegaDB-=48.0f; + + TL=powf(10.0f,SegaDB/20.0f); + + SegaDB=0; + if(iPAN&0x1) SegaDB-=3.0f; + if(iPAN&0x2) SegaDB-=6.0f; + if(iPAN&0x4) SegaDB-=12.0f; + if(iPAN&0x8) SegaDB-=24.0f; + + if((iPAN&0xf)==0xf) PAN=0.0; + else PAN=powf(10.0f,SegaDB/20.0f); + + if(iPAN<0x10) + { + LPAN=PAN; + RPAN=1.0; + } + else + { + RPAN=PAN; + LPAN=1.0; + } + + if(iSDL) + fSDL=powf(10.0f,(SDLT[iSDL])/20.0f); + else + fSDL=0.0; + + m_LPANTABLE[i]=FIX((4.0f*LPAN*TL*fSDL)); + m_RPANTABLE[i]=FIX((4.0f*RPAN*TL*fSDL)); + } + + m_ARTABLE[0]=m_DRTABLE[0]=0; //Infinite time + m_ARTABLE[1]=m_DRTABLE[1]=0; //Infinite time + for(i=2;i<64;++i) + { + double t,step,scale; + t=ARTimes[i]; //In ms + if(t!=0.0) + { + step=(1023*1000.0)/( 44100.0*t); + scale=(double) (1<EG.state==SCSP_RELEASE/*&& !s2->active*/) + { + StartSlot(s2); + } + if(!KEYONB(s2) /*&& s2->active*/) + { + StopSlot(s2,1); + } + } + } + slot->udata.data[0]&=~0x1000; + } + break; + case 0x10: + case 0x11: + slot->step=Step(slot); + break; + case 0xA: + case 0xB: + slot->EG.RR=Get_RR(0,RR(slot)); + slot->EG.DL=0x1f-DL(slot); + break; + case 0x12: + case 0x13: + Compute_LFO(slot); + break; + } +} + +void scsp_device::UpdateReg(address_space &space, int reg) +{ + switch(reg&0x3f) + { + case 0x0: + m_stream->set_output_gain(0,MVOL() / 15.0); + m_stream->set_output_gain(1,MVOL() / 15.0); + break; + case 0x2: + case 0x3: + { + unsigned int v=RBL(); + m_DSP.RBP=RBP(); + if(v==0) + m_DSP.RBL=8*1024; + else if(v==1) + m_DSP.RBL=16*1024; + if(v==2) + m_DSP.RBL=32*1024; + if(v==3) + m_DSP.RBL=64*1024; + } + break; + case 0x6: + case 0x7: + midi_in(space, 0, m_udata.data[0x6/2]&0xff, 0); + break; + case 8: + case 9: + /* Only MSLC could be written. */ + m_udata.data[0x8/2] &= 0xf800; /**< @todo Docs claims MSLC to be 0x7800, but Jikkyou Parodius doesn't agree. */ + break; + case 0x12: + case 0x13: + m_dma.dmea = (m_udata.data[0x12/2] & 0xfffe) | (m_dma.dmea & 0xf0000); + break; + case 0x14: + case 0x15: + m_dma.dmea = ((m_udata.data[0x14/2] & 0xf000) << 4) | (m_dma.dmea & 0xfffe); + m_dma.drga = (m_udata.data[0x14/2] & 0x0ffe); + break; + case 0x16: + case 0x17: + m_dma.dtlg = (m_udata.data[0x16/2] & 0x0ffe); + m_dma.ddir = (m_udata.data[0x16/2] & 0x2000) >> 13; + m_dma.dgate = (m_udata.data[0x16/2] & 0x4000) >> 14; + if(m_udata.data[0x16/2] & 0x1000) // dexe + exec_dma(space); + break; + case 0x18: + case 0x19: + if(m_Master) + { + UINT32 time; + + m_TimPris[0]=1<<((m_udata.data[0x18/2]>>8)&0x7); + m_TimCnt[0]=(m_udata.data[0x18/2]&0xff)<<8; + + if ((m_udata.data[0x18/2]&0xff) != 255) + { + time = (44100 / m_TimPris[0]) / (255-(m_udata.data[0x18/2]&0xff)); + if (time) + { + m_timerA->adjust(attotime::from_hz(time)); + } + } + } + break; + case 0x1a: + case 0x1b: + if(m_Master) + { + UINT32 time; + + m_TimPris[1]=1<<((m_udata.data[0x1A/2]>>8)&0x7); + m_TimCnt[1]=(m_udata.data[0x1A/2]&0xff)<<8; + + if ((m_udata.data[0x1A/2]&0xff) != 255) + { + time = (44100 / m_TimPris[1]) / (255-(m_udata.data[0x1A/2]&0xff)); + if (time) + { + m_timerB->adjust(attotime::from_hz(time)); + } + } + } + break; + case 0x1C: + case 0x1D: + if(m_Master) + { + UINT32 time; + + m_TimPris[2]=1<<((m_udata.data[0x1C/2]>>8)&0x7); + m_TimCnt[2]=(m_udata.data[0x1C/2]&0xff)<<8; + + if ((m_udata.data[0x1C/2]&0xff) != 255) + { + time = (44100 / m_TimPris[2]) / (255-(m_udata.data[0x1C/2]&0xff)); + if (time) + { + m_timerC->adjust(attotime::from_hz(time)); + } + } + } + break; + case 0x1e: // SCIEB + case 0x1f: + if(m_Master) + { + CheckPendingIRQ(); + + if(m_udata.data[0x1e/2] & 0x610) + popmessage("SCSP SCIEB enabled %04x, contact MAMEdev",m_udata.data[0x1e/2]); + } + break; + case 0x20: // SCIPD + case 0x21: + if(m_Master) + { + if(m_udata.data[0x1e/2] & m_udata.data[0x20/2] & 0x20) + popmessage("SCSP SCIPD write %04x, contact MAMEdev",m_udata.data[0x20/2]); + } + break; + case 0x22: //SCIRE + case 0x23: + + if(m_Master) + { + m_udata.data[0x20/2]&=~m_udata.data[0x22/2]; + ResetInterrupts(); + + // behavior from real hardware: if you SCIRE a timer that's expired, + // it'll immediately pop up again in SCIPD. ask Sakura Taisen on the Saturn... + if (m_TimCnt[0] == 0xffff) + { + m_udata.data[0x20/2] |= 0x40; + } + if (m_TimCnt[1] == 0xffff) + { + m_udata.data[0x20/2] |= 0x80; + } + if (m_TimCnt[2] == 0xffff) + { + m_udata.data[0x20/2] |= 0x100; + } + } + break; + case 0x24: + case 0x25: + case 0x26: + case 0x27: + case 0x28: + case 0x29: + if(m_Master) + { + m_IrqTimA=DecodeSCI(SCITMA); + m_IrqTimBC=DecodeSCI(SCITMB); + m_IrqMidi=DecodeSCI(SCIMID); + } + break; + case 0x2a: + case 0x2b: + m_mcieb = m_udata.data[0x2a/2]; + + MainCheckPendingIRQ(0); + if(m_mcieb & ~0x60) + popmessage("SCSP MCIEB enabled %04x, contact MAMEdev",m_mcieb); + break; + case 0x2c: + case 0x2d: + if(m_udata.data[0x2c/2] & 0x20) + MainCheckPendingIRQ(0x20); + break; + case 0x2e: + case 0x2f: + m_mcipd &= ~m_udata.data[0x2e/2]; + MainCheckPendingIRQ(0); + break; + + } +} + +void scsp_device::UpdateSlotRegR(int slot,int reg) +{ +} + +void scsp_device::UpdateRegR(address_space &space, int reg) +{ + switch(reg&0x3f) + { + case 4: + case 5: + { + unsigned short v=m_udata.data[0x5/2]; + v&=0xff00; + v|=m_MidiStack[m_MidiR]; + m_irq_cb(m_IrqMidi, CLEAR_LINE); // cancel the IRQ + logerror("Read %x from SCSP MIDI\n", v); + if(m_MidiR!=m_MidiW) + { + ++m_MidiR; + m_MidiR&=31; + } + m_udata.data[0x5/2]=v; + } + break; + case 8: + case 9: + { + // MSLC | CA |SGC|EG + // f e d c b a 9 8 7 6 5 4 3 2 1 0 + unsigned char MSLC=(m_udata.data[0x8/2]>>11)&0x1f; + SCSP_SLOT *slot=m_Slots + MSLC; + unsigned int SGC = (slot->EG.state) & 3; + unsigned int CA = (slot->cur_addr>>(SHIFT+12)) & 0xf; + unsigned int EG = (0x1f - (slot->EG.volume>>(EG_SHIFT+5))) & 0x1f; + /* note: according to the manual MSLC is write only, CA, SGC and EG read only. */ + m_udata.data[0x8/2] = /*(MSLC << 11) |*/ (CA << 7) | (SGC << 5) | EG; + } + break; + + case 0x18: + case 0x19: + break; + + case 0x1a: + case 0x1b: + break; + + case 0x1c: + case 0x1d: + break; + + case 0x2a: + case 0x2b: + m_udata.data[0x2a/2] = m_mcieb; + break; + + case 0x2c: + case 0x2d: + m_udata.data[0x2c/2] = m_mcipd; + break; + } +} + +void scsp_device::w16(address_space &space,unsigned int addr,unsigned short val) +{ + addr&=0xffff; + if(addr<0x400) + { + int slot=addr/0x20; + addr&=0x1f; + *((unsigned short *) (m_Slots[slot].udata.datab+(addr))) = val; + UpdateSlotReg(slot,addr&0x1f); + } + else if(addr<0x600) + { + if (addr < 0x430) + { + *((unsigned short *) (m_udata.datab+((addr&0x3f)))) = val; + UpdateReg(space, addr&0x3f); + } + } + else if(addr<0x700) + m_RINGBUF[(addr-0x600)/2]=val; + else + { + //DSP + if(addr<0x780) //COEF + *((unsigned short *) (m_DSP.COEF+(addr-0x700)/2))=val; + else if(addr<0x7c0) + *((unsigned short *) (m_DSP.MADRS+(addr-0x780)/2))=val; + else if(addr<0x800) // MADRS is mirrored twice + *((unsigned short *) (m_DSP.MADRS+(addr-0x7c0)/2))=val; + else if(addr<0xC00) + { + *((unsigned short *) (m_DSP.MPRO+(addr-0x800)/2))=val; + + if(addr==0xBF0) + { + SCSPDSP_Start(&m_DSP); + } + } + } +} + +unsigned short scsp_device::r16(address_space &space, unsigned int addr) +{ + unsigned short v=0; + addr&=0xffff; + if(addr<0x400) + { + int slot=addr/0x20; + addr&=0x1f; + UpdateSlotRegR(slot,addr&0x1f); + v=*((unsigned short *) (m_Slots[slot].udata.datab+(addr))); + } + else if(addr<0x600) + { + if (addr < 0x430) + { + UpdateRegR(space, addr&0x3f); + v= *((unsigned short *) (m_udata.datab+((addr&0x3f)))); + } + } + else if(addr<0x700) + v=m_RINGBUF[(addr-0x600)/2]; + else + { + //DSP + if(addr<0x780) //COEF + v= *((unsigned short *) (m_DSP.COEF+(addr-0x700)/2)); + else if(addr<0x7c0) + v= *((unsigned short *) (m_DSP.MADRS+(addr-0x780)/2)); + else if(addr<0x800) + v= *((unsigned short *) (m_DSP.MADRS+(addr-0x7c0)/2)); + else if(addr<0xC00) + v= *((unsigned short *) (m_DSP.MPRO+(addr-0x800)/2)); + else if(addr<0xE00) + { + if(addr & 2) + v= m_DSP.TEMP[(addr >> 2) & 0x7f] & 0xffff; + else + v= m_DSP.TEMP[(addr >> 2) & 0x7f] >> 16; + } + else if(addr<0xE80) + { + if(addr & 2) + v= m_DSP.MEMS[(addr >> 2) & 0x1f] & 0xffff; + else + v= m_DSP.MEMS[(addr >> 2) & 0x1f] >> 16; + } + else if(addr<0xEC0) + { + if(addr & 2) + v= m_DSP.MIXS[(addr >> 2) & 0xf] & 0xffff; + else + v= m_DSP.MIXS[(addr >> 2) & 0xf] >> 16; + } + else if(addr<0xEE0) + v= *((unsigned short *) (m_DSP.EFREG+(addr-0xec0)/2)); + else + { + /**! + @todo Kyuutenkai reads from 0xee0/0xee2, it's tied with EXTS register(s) also used for CD-Rom Player equalizer. + This port is actually an external parallel port, directly connected from the CD Block device, hence code is a bit of an hack. + Kyuutenkai code snippet for reference: + 004A3A: 207C 0010 0EE0 movea.l #$100ee0, A0 + 004A40: 43EA 0090 lea ($90,A2), A1 ;A2=0x700 + 004A44: 6100 0254 bsr $4c9a + 004A48: 207C 0010 0EE2 movea.l #$100ee2, A0 + 004A4E: 43EA 0092 lea ($92,A2), A1 + 004A52: 6100 0246 bsr $4c9a + 004A56: 207C 0010 0ED2 movea.l #$100ed2, A0 + 004A5C: 43EA 0094 lea ($94,A2), A1 + 004A60: 6100 0238 bsr $4c9a + 004A64: 3540 0096 move.w D0, ($96,A2) + 004A68: 207C 0010 0ED4 movea.l #$100ed4, A0 + 004A6E: 43EA 0098 lea ($98,A2), A1 + 004A72: 6100 0226 bsr $4c9a + 004A76: 3540 009A move.w D0, ($9a,A2) + 004A7A: 207C 0010 0ED6 movea.l #$100ed6, A0 + 004A80: 43EA 009C lea ($9c,A2), A1 + 004A84: 6100 0214 bsr $4c9a + 004A88: 3540 009E move.w D0, ($9e,A2) + 004A8C: 4E75 rts + + 004C9A: 48E7 4000 movem.l D1, -(A7) + 004C9E: 3010 move.w (A0), D0 ;reads from 0x100ee0/ee2 + 004CA0: 4A40 tst.w D0 + 004CA2: 6A00 0004 bpl $4ca8 + 004CA6: 4440 neg.w D0 + 004CA8: 3211 move.w (A1), D1 + 004CAA: D041 add.w D1, D0 + 004CAC: E248 lsr.w #1, D0 + 004CAE: 3280 move.w D0, (A1) ;writes to RAM buffer 0x790/0x792 + 004CB0: 4CDF 0002 movem.l (A7)+, D1 + 004CB4: 4E75 rts + */ + logerror("SCSP: Reading from EXTS register %08x\n",addr); + if(addr == 0xee0) + v = space.machine().device("cdda")->get_channel_volume(0); + if(addr == 0xee2) + v = space.machine().device("cdda")->get_channel_volume(1); + } + } + return v; +} + + +#define REVSIGN(v) ((~v)+1) + +inline INT32 scsp_device::UpdateSlot(SCSP_SLOT *slot) +{ + INT32 sample; + int step=slot->step; + UINT32 addr1,addr2,addr_select; // current and next sample addresses + UINT32 *addr[2] = {&addr1, &addr2}; // used for linear interpolation + UINT32 *slot_addr[2] = {&(slot->cur_addr), &(slot->nxt_addr)}; // + + if(SSCTL(slot)!=0) //no FM or noise yet + return 0; + + if(PLFOS(slot)!=0) + { + step=step*PLFO_Step(&(slot->PLFO)); + step>>=SHIFT; + } + + if(PCM8B(slot)) + { + addr1=slot->cur_addr>>SHIFT; + addr2=slot->nxt_addr>>SHIFT; + } + else + { + addr1=(slot->cur_addr>>(SHIFT-1))&0x7fffe; + addr2=(slot->nxt_addr>>(SHIFT-1))&0x7fffe; + } + + if(MDL(slot)!=0 || MDXSL(slot)!=0 || MDYSL(slot)!=0) + { + INT32 smp=(m_RINGBUF[(m_BUFPTR+MDXSL(slot))&63]+m_RINGBUF[(m_BUFPTR+MDYSL(slot))&63])/2; + + smp<<=0xA; // associate cycle with 1024 + smp>>=0x1A-MDL(slot); // ex. for MDL=0xF, sample range corresponds to +/- 64 pi (32=2^5 cycles) so shift by 11 (16-5 == 0x1A-0xF) + if(!PCM8B(slot)) smp<<=1; + + addr1+=smp; addr2+=smp; + } + + if(PCM8B(slot)) //8 bit signed + { + INT8 *p1=(signed char *) (m_SCSPRAM+BYTE_XOR_BE(((SA(slot)+addr1))&0x7FFFF)); + INT8 *p2=(signed char *) (m_SCSPRAM+BYTE_XOR_BE(((SA(slot)+addr2))&0x7FFFF)); + //sample=(p[0])<<8; + INT32 s; + INT32 fpart=slot->cur_addr&((1<>SHIFT); + } + else //16 bit signed (endianness?) + { + INT16 *p1=(signed short *) (m_SCSPRAM+((SA(slot)+addr1)&0x7FFFE)); + INT16 *p2=(signed short *) (m_SCSPRAM+((SA(slot)+addr2)&0x7FFFE)); + INT32 s; + INT32 fpart=slot->cur_addr&((1<>SHIFT); + } + + if(SBCTL(slot)&0x1) + sample ^= 0x7FFF; + if(SBCTL(slot)&0x2) + sample = (INT16)(sample^0x8000); + + if(slot->Backwards) + slot->cur_addr-=step; + else + slot->cur_addr+=step; + slot->nxt_addr=slot->cur_addr+(1<cur_addr>>SHIFT; + addr2=slot->nxt_addr>>SHIFT; + + if(addr1>=LSA(slot) && !(slot->Backwards)) + { + if(LPSLNK(slot) && slot->EG.state==SCSP_ATTACK) + slot->EG.state = SCSP_DECAY1; + } + + for (addr_select=0;addr_select<2;addr_select++) + { + INT32 rem_addr; + switch(LPCTL(slot)) + { + case 0: //no loop + if(*addr[addr_select]>=LSA(slot) && *addr[addr_select]>=LEA(slot)) + { + //slot->active=0; + StopSlot(slot,0); + } + break; + case 1: //normal loop + if(*addr[addr_select]>=LEA(slot)) + { + rem_addr = *slot_addr[addr_select] - (LEA(slot)<=LSA(slot)) && !(slot->Backwards)) + { + rem_addr = *slot_addr[addr_select] - (LSA(slot)<Backwards=1; + } + else if((*addr[addr_select]Backwards) + { + rem_addr = (LSA(slot)<=LEA(slot)) //reached end, reverse till start + { + rem_addr = *slot_addr[addr_select] - (LEA(slot)<Backwards=1; + } + else if((*addr[addr_select]Backwards)//reached start or negative + { + rem_addr = (LSA(slot)<Backwards=0; + } + break; + } + } + + if(!SDIR(slot)) + { + if(ALFOS(slot)!=0) + { + sample=sample*ALFO_Step(&(slot->ALFO)); + sample>>=SHIFT; + } + + if(slot->EG.state==SCSP_ATTACK) + sample=(sample*EG_Update(slot))>>SHIFT; + else + sample=(sample*m_EG_TABLE[EG_Update(slot)>>(SHIFT-10)])>>SHIFT; + } + + if(!STWINH(slot)) + { + if(!SDIR(slot)) + { + unsigned short Enc=((TL(slot))<<0x0)|(0x7<<0xd); + *m_RBUFDST=(sample*m_LPANTABLE[Enc])>>(SHIFT+1); + } + else + { + unsigned short Enc=(0<<0x0)|(0x7<<0xd); + *m_RBUFDST=(sample*m_LPANTABLE[Enc])>>(SHIFT+1); + } + } + + return sample; +} + +void scsp_device::DoMasterSamples(int nsamples) +{ + stream_sample_t *bufr,*bufl; + int sl, s, i; + + bufr=m_bufferr; + bufl=m_bufferl; + + for(s=0;s>(SHIFT-2),ISEL(slot),IMXL(slot)); + Enc=((TL(slot))<<0x0)|((DIPAN(slot))<<0x8)|((DISDL(slot))<<0xd); + { + smpl+=(sample*m_LPANTABLE[Enc])>>SHIFT; + smpr+=(sample*m_RPANTABLE[Enc])>>SHIFT; + } + } + +#if FM_DELAY + m_RINGBUF[(m_BUFPTR+64-(FM_DELAY-1))&63] = m_DELAYBUF[(m_DELAYPTR+FM_DELAY-(FM_DELAY-1))%FM_DELAY]; +#endif + ++m_BUFPTR; + m_BUFPTR&=63; +#if FM_DELAY + ++m_DELAYPTR; + if(m_DELAYPTR>FM_DELAY-1) m_DELAYPTR=0; +#endif + } + + SCSPDSP_Step(&m_DSP); + + for(i=0;i<16;++i) + { + SCSP_SLOT *slot=m_Slots+i; + if(EFSDL(slot)) + { + unsigned short Enc=((EFPAN(slot))<<0x8)|((EFSDL(slot))<<0xd); + smpl+=(m_DSP.EFREG[i]*m_LPANTABLE[Enc])>>SHIFT; + smpr+=(m_DSP.EFREG[i]*m_RPANTABLE[Enc])>>SHIFT; + } + } + + *bufl++ = ICLIP16(smpl>>2); + *bufr++ = ICLIP16(smpr>>2); + } +} + +/* TODO: this needs to be timer-ized */ +void scsp_device::exec_dma(address_space &space) +{ + static UINT16 tmp_dma[3]; + int i; + + logerror("SCSP: DMA transfer START\n" + "DMEA: %04x DRGA: %04x DTLG: %04x\n" + "DGATE: %d DDIR: %d\n",m_dma.dmea,m_dma.drga,m_dma.dtlg,m_dma.dgate ? 1 : 0,m_dma.ddir ? 1 : 0); + + /* Copy the dma values in a temp storage for resuming later */ + /* (DMA *can't* overwrite its parameters). */ + if(!(m_dma.ddir)) + { + for(i=0;i<3;i++) + tmp_dma[i] = m_udata.data[(0x12+(i*2))/2]; + } + + /* note: we don't use space.read_word / write_word because it can happen that SH-2 enables the DMA instead of m68k. */ + /* TODO: don't know if params auto-updates, I guess not ... */ + if(m_dma.ddir) + { + if(m_dma.dgate) + { + popmessage("Check: SCSP DMA DGATE enabled, contact MAME/MESSdev"); + for(i=0;i < m_dma.dtlg;i+=2) + { + m_SCSPRAM[m_dma.dmea] = 0; + m_SCSPRAM[m_dma.dmea+1] = 0; + m_dma.dmea+=2; + } + } + else + { + for(i=0;i < m_dma.dtlg;i+=2) + { + UINT16 tmp; + tmp = r16(space, m_dma.drga); + m_SCSPRAM[m_dma.dmea] = tmp & 0xff; + m_SCSPRAM[m_dma.dmea+1] = tmp>>8; + m_dma.dmea+=2; + m_dma.drga+=2; + } + } + } + else + { + if(m_dma.dgate) + { + popmessage("Check: SCSP DMA DGATE enabled, contact MAME/MESSdev"); + for(i=0;i < m_dma.dtlg;i+=2) + { + w16(space, m_dma.drga, 0); + m_dma.drga+=2; + } + } + else + { + for(i=0;i < m_dma.dtlg;i+=2) + { + UINT16 tmp; + tmp = m_SCSPRAM[m_dma.dmea]; + tmp|= m_SCSPRAM[m_dma.dmea+1]<<8; + w16(space, m_dma.drga, tmp); + m_dma.dmea+=2; + m_dma.drga+=2; + } + } + } + + /*Resume the values*/ + if(!(m_dma.ddir)) + { + for(i=0;i<3;i++) + m_udata.data[(0x12+(i*2))/2] = tmp_dma[i]; + } + + /* Job done */ + m_udata.data[0x16/2] &= ~0x1000; + /* request a dma end irq (TODO: make it inside the interface) */ + if(m_udata.data[0x1e/2] & 0x10) + { + popmessage("SCSP DMA IRQ triggered, contact MAMEdev"); + space.machine().device("audiocpu")->execute().set_input_line(DecodeSCI(SCIDMA),HOLD_LINE); + } +} + +#ifdef UNUSED_FUNCTION +int IRQCB(void *param) +{ + CheckPendingIRQ(param); + return -1; +} +#endif + + +void scsp_device::set_ram_base(void *base) +{ + if (this) + { + m_SCSPRAM = (unsigned char *)base; + m_DSP.SCSPRAM = (UINT16 *)base; + m_SCSPRAM_LENGTH = 0x80000; + m_DSP.SCSPRAM_LENGTH = 0x80000/2; + } +} + + +READ16_MEMBER( scsp_device::read ) +{ + m_stream->update(); + return r16(space, offset*2); +} + +WRITE16_MEMBER( scsp_device::write ) +{ + UINT16 tmp; + + m_stream->update(); + + tmp = r16(space, offset*2); + COMBINE_DATA(&tmp); + w16(space,offset*2, tmp); +} + +WRITE16_MEMBER( scsp_device::midi_in ) +{ + // printf("scsp_midi_in: %02x\n", data); + + m_MidiStack[m_MidiW++]=data; + m_MidiW &= 31; + + CheckPendingIRQ(); +} + +READ16_MEMBER( scsp_device::midi_out_r ) +{ + unsigned char val; + + val=m_MidiStack[m_MidiR++]; + m_MidiR&=31; + return val; +} + +//LFO handling + +#define LFIX(v) ((unsigned int) ((float) (1<phase+=LFO->phase_step; +#if LFO_SHIFT!=8 + LFO->phase&=(1<<(LFO_SHIFT+8))-1; +#endif + p=LFO->table[LFO->phase>>LFO_SHIFT]; + p=LFO->scale[p+128]; + return p<<(SHIFT-LFO_SHIFT); +} + +signed int scsp_device::ALFO_Step(SCSP_LFO_t *LFO) +{ + int p; + LFO->phase+=LFO->phase_step; +#if LFO_SHIFT!=8 + LFO->phase&=(1<<(LFO_SHIFT+8))-1; +#endif + p=LFO->table[LFO->phase>>LFO_SHIFT]; + p=LFO->scale[p]; + return p<<(SHIFT-LFO_SHIFT); +} + +void scsp_device::LFO_ComputeStep(SCSP_LFO_t *LFO,UINT32 LFOF,UINT32 LFOWS,UINT32 LFOS,int ALFO) +{ + float step=(float) LFOFreq[LFOF]*256.0f/(float)44100; + LFO->phase_step=(unsigned int) ((float) (1<table=m_ALFO_SAW; break; + case 1: LFO->table=m_ALFO_SQR; break; + case 2: LFO->table=m_ALFO_TRI; break; + case 3: LFO->table=m_ALFO_NOI; break; + } + LFO->scale=m_ASCALES[LFOS]; + } + else + { + switch(LFOWS) + { + case 0: LFO->table=m_PLFO_SAW; break; + case 1: LFO->table=m_PLFO_SQR; break; + case 2: LFO->table=m_PLFO_TRI; break; + case 3: LFO->table=m_PLFO_NOI; break; + } + LFO->scale=m_PSCALES[LFOS]; + } +} diff --git a/src/devices/sound/scsp.h b/src/devices/sound/scsp.h new file mode 100644 index 00000000000..bc104a85b68 --- /dev/null +++ b/src/devices/sound/scsp.h @@ -0,0 +1,214 @@ +// license:BSD-3-Clause +// copyright-holders:ElSemi, R. Belmont +/* + SCSP (YMF292-F) header +*/ + +#pragma once + +#ifndef __SCSP_H__ +#define __SCSP_H__ + +#include "scspdsp.h" + +#define FM_DELAY 0 // delay in number of slots processed before samples are written to the FM ring buffer + // driver code indicates should be 4, but sounds distorted then + + +#define MCFG_SCSP_ROFFSET(_offs) \ + scsp_device::set_roffset(*device, _offs); + +#define MCFG_SCSP_IRQ_CB(_devcb) \ + devcb = &scsp_device::set_irq_callback(*device, DEVCB_##_devcb); + +#define MCFG_SCSP_MAIN_IRQ_CB(_devcb) \ + devcb = &scsp_device::set_main_irq_callback(*device, DEVCB_##_devcb); + + +enum SCSP_STATE {SCSP_ATTACK,SCSP_DECAY1,SCSP_DECAY2,SCSP_RELEASE}; + +struct SCSP_EG_t +{ + int volume; // + SCSP_STATE state; + int step; + //step vals + int AR; //Attack + int D1R; //Decay1 + int D2R; //Decay2 + int RR; //Release + + int DL; //Decay level + UINT8 EGHOLD; + UINT8 LPLINK; +}; + +struct SCSP_LFO_t +{ + unsigned short phase; + UINT32 phase_step; + int *table; + int *scale; +}; + +struct SCSP_SLOT +{ + union + { + UINT16 data[0x10]; //only 0x1a bytes used + UINT8 datab[0x20]; + } udata; + + UINT8 Backwards; //the wave is playing backwards + UINT8 active; //this slot is currently playing + UINT8 *base; //samples base address + UINT32 cur_addr; //current play address (24.8) + UINT32 nxt_addr; //next play address + UINT32 step; //pitch step (24.8) + SCSP_EG_t EG; //Envelope + SCSP_LFO_t PLFO; //Phase LFO + SCSP_LFO_t ALFO; //Amplitude LFO + int slot; + signed short Prev; //Previous sample (for interpolation) +}; + + +class scsp_device : public device_t, + public device_sound_interface +{ +public: + scsp_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + static void set_roffset(device_t &device, int roffset) { downcast(device).m_roffset = roffset; } + template static devcb_base &set_irq_callback(device_t &device, _Object object) { return downcast(device).m_irq_cb.set_callback(object); } + template static devcb_base &set_main_irq_callback(device_t &device, _Object object) { return downcast(device).m_main_irq_cb.set_callback(object); } + + // SCSP register access + DECLARE_READ16_MEMBER( read ); + DECLARE_WRITE16_MEMBER( write ); + + // MIDI I/O access (used for comms on Model 2/3) + DECLARE_WRITE16_MEMBER( midi_in ); + DECLARE_READ16_MEMBER( midi_out_r ); + + void set_ram_base(void *base); + +protected: + // device-level overrides + virtual void device_start(); + + // sound stream update overrides + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + +private: + int m_roffset; /* offset in the region */ + devcb_write8 m_irq_cb; /* irq callback */ + devcb_write_line m_main_irq_cb; + + union + { + UINT16 data[0x30/2]; + UINT8 datab[0x30]; + } m_udata; + + SCSP_SLOT m_Slots[32]; + signed short m_RINGBUF[128]; + unsigned char m_BUFPTR; +#if FM_DELAY + signed short m_DELAYBUF[FM_DELAY]; + unsigned char m_DELAYPTR; +#endif + unsigned char *m_SCSPRAM; + UINT32 m_SCSPRAM_LENGTH; + char m_Master; + sound_stream * m_stream; + + INT32 *m_buffertmpl,*m_buffertmpr; + + UINT32 m_IrqTimA; + UINT32 m_IrqTimBC; + UINT32 m_IrqMidi; + + UINT8 m_MidiOutW, m_MidiOutR; + UINT8 m_MidiStack[32]; + UINT8 m_MidiW, m_MidiR; + + INT32 m_EG_TABLE[0x400]; + + int m_LPANTABLE[0x10000]; + int m_RPANTABLE[0x10000]; + + int m_TimPris[3]; + int m_TimCnt[3]; + + // timers + emu_timer *m_timerA, *m_timerB, *m_timerC; + + // DMA stuff + struct + { + UINT32 dmea; + UINT16 drga; + UINT16 dtlg; + UINT8 dgate; + UINT8 ddir; + } m_dma; + + UINT16 m_mcieb; + UINT16 m_mcipd; + + int m_ARTABLE[64], m_DRTABLE[64]; + + SCSPDSP m_DSP; + + stream_sample_t *m_bufferl; + stream_sample_t *m_bufferr; + + int m_length; + + signed short *m_RBUFDST; //this points to where the sample will be stored in the RingBuf + + //LFO + int m_PLFO_TRI[256], m_PLFO_SQR[256], m_PLFO_SAW[256], m_PLFO_NOI[256]; + int m_ALFO_TRI[256], m_ALFO_SQR[256], m_ALFO_SAW[256], m_ALFO_NOI[256]; + int m_PSCALES[8][256]; + int m_ASCALES[8][256]; + + void exec_dma(address_space &space); /*state DMA transfer function*/ + unsigned char DecodeSCI(unsigned char irq); + void CheckPendingIRQ(); + void MainCheckPendingIRQ(UINT16 irq_type); + void ResetInterrupts(); + TIMER_CALLBACK_MEMBER( timerA_cb ); + TIMER_CALLBACK_MEMBER( timerB_cb ); + TIMER_CALLBACK_MEMBER( timerC_cb ); + int Get_AR(int base, int R); + int Get_DR(int base, int R); + int Get_RR(int base, int R); + void Compute_EG(SCSP_SLOT *slot); + int EG_Update(SCSP_SLOT *slot); + UINT32 Step(SCSP_SLOT *slot); + void Compute_LFO(SCSP_SLOT *slot); + void StartSlot(SCSP_SLOT *slot); + void StopSlot(SCSP_SLOT *slot,int keyoff); + void init(); + void UpdateSlotReg(int s,int r); + void UpdateReg(address_space &space, int reg); + void UpdateSlotRegR(int slot,int reg); + void UpdateRegR(address_space &space, int reg); + void w16(address_space &space,unsigned int addr,unsigned short val); + unsigned short r16(address_space &space, unsigned int addr); + inline INT32 UpdateSlot(SCSP_SLOT *slot); + void DoMasterSamples(int nsamples); + + //LFO + void LFO_Init(); + signed int PLFO_Step(SCSP_LFO_t *LFO); + signed int ALFO_Step(SCSP_LFO_t *LFO); + void LFO_ComputeStep(SCSP_LFO_t *LFO,UINT32 LFOF,UINT32 LFOWS,UINT32 LFOS,int ALFO); +}; + +extern const device_type SCSP; + + +#endif /* __SCSP_H__ */ diff --git a/src/devices/sound/scspdsp.c b/src/devices/sound/scspdsp.c new file mode 100644 index 00000000000..75b30cfe85a --- /dev/null +++ b/src/devices/sound/scspdsp.c @@ -0,0 +1,355 @@ +// license:BSD-3-Clause +// copyright-holders:ElSemi, R. Belmont +#include "emu.h" +#include "scspdsp.h" + +static UINT16 PACK(INT32 val) +{ + UINT32 temp; + int sign,exponent,k; + + sign = (val >> 23) & 0x1; + temp = (val ^ (val << 1)) & 0xFFFFFF; + exponent = 0; + for (k=0; k<12; k++) + { + if (temp & 0x800000) + break; + temp <<= 1; + exponent += 1; + } + if (exponent < 12) + val = (val << exponent) & 0x3FFFFF; + else + val <<= 11; + val >>= 11; + val &= 0x7FF; + val |= sign << 15; + val |= exponent << 11; + + return (UINT16)val; +} + +static INT32 UNPACK(UINT16 val) +{ + int sign,exponent,mantissa; + INT32 uval; + + sign = (val >> 15) & 0x1; + exponent = (val >> 11) & 0xF; + mantissa = val & 0x7FF; + uval = mantissa << 11; + if (exponent > 11) + { + exponent = 11; + uval |= sign << 22; + } + else + uval |= (sign ^ 1) << 22; + uval |= sign << 23; + uval <<= 8; + uval >>= 8; + uval >>= exponent; + + return uval; +} + +void SCSPDSP_Init(SCSPDSP *DSP) +{ + memset(DSP,0,sizeof(SCSPDSP)); + DSP->RBL=0x8000; + DSP->Stopped=1; +} + +void SCSPDSP_Step(SCSPDSP *DSP) +{ + INT32 ACC=0; //26 bit + INT32 SHIFTED=0; //24 bit + INT32 X=0; //24 bit + INT32 Y=0; //13 bit + INT32 B=0; //26 bit + INT32 INPUTS=0; //24 bit + INT32 MEMVAL=0; + INT32 FRC_REG=0; //13 bit + INT32 Y_REG=0; //24 bit + UINT32 ADDR=0; + UINT32 ADRS_REG=0; //13 bit + int step; + + if(DSP->Stopped) + return; + + memset(DSP->EFREG,0,2*16); +#if 0 + int dump=0; + FILE *f=NULL; + if(dump) + f=fopen("dsp.txt","wt"); +#endif + for(step=0;stepLastStep;++step) + { + UINT16 *IPtr=DSP->MPRO+step*4; + +// if(IPtr[0]==0 && IPtr[1]==0 && IPtr[2]==0 && IPtr[3]==0) +// break; + + UINT32 TRA=(IPtr[0]>>8)&0x7F; + UINT32 TWT=(IPtr[0]>>7)&0x01; + UINT32 TWA=(IPtr[0]>>0)&0x7F; + + UINT32 XSEL=(IPtr[1]>>15)&0x01; + UINT32 YSEL=(IPtr[1]>>13)&0x03; + UINT32 IRA=(IPtr[1]>>6)&0x3F; + UINT32 IWT=(IPtr[1]>>5)&0x01; + UINT32 IWA=(IPtr[1]>>0)&0x1F; + + UINT32 TABLE=(IPtr[2]>>15)&0x01; + UINT32 MWT=(IPtr[2]>>14)&0x01; + UINT32 MRD=(IPtr[2]>>13)&0x01; + UINT32 EWT=(IPtr[2]>>12)&0x01; + UINT32 EWA=(IPtr[2]>>8)&0x0F; + UINT32 ADRL=(IPtr[2]>>7)&0x01; + UINT32 FRCL=(IPtr[2]>>6)&0x01; + UINT32 SHIFT=(IPtr[2]>>4)&0x03; + UINT32 YRL=(IPtr[2]>>3)&0x01; + UINT32 NEGB=(IPtr[2]>>2)&0x01; + UINT32 ZERO=(IPtr[2]>>1)&0x01; + UINT32 BSEL=(IPtr[2]>>0)&0x01; + + UINT32 NOFL=(IPtr[3]>>15)&1; //???? + UINT32 COEF=(IPtr[3]>>9)&0x3f; + + UINT32 MASA=(IPtr[3]>>2)&0x1f; //??? + UINT32 ADREB=(IPtr[3]>>1)&0x1; + UINT32 NXADR=(IPtr[3]>>0)&0x1; + + INT64 v; + + //operations are done at 24 bit precision +#if 0 + if(MASA) + int a=1; + if(NOFL) + int a=1; + +// int dump=0; + + if(f) + { +#define DUMP(v) fprintf(f," " #v ": %04X",v); + + fprintf(f,"%d: ",step); + DUMP(ACC); + DUMP(SHIFTED); + DUMP(X); + DUMP(Y); + DUMP(B); + DUMP(INPUTS); + DUMP(MEMVAL); + DUMP(FRC_REG); + DUMP(Y_REG); + DUMP(ADDR); + DUMP(ADRS_REG); + fprintf(f,"\n"); + } +#endif + //INPUTS RW +// colmns97 hits this +// assert(IRA<0x32); + if(IRA<=0x1f) + INPUTS=DSP->MEMS[IRA]; + else if(IRA<=0x2F) + INPUTS=DSP->MIXS[IRA-0x20]<<4; //MIXS is 20 bit + else if(IRA<=0x31) + INPUTS=0; + else + return; + + INPUTS<<=8; + INPUTS>>=8; + //if(INPUTS&0x00800000) + // INPUTS|=0xFF000000; + + if(IWT) + { + DSP->MEMS[IWA]=MEMVAL; //MEMVAL was selected in previous MRD + if(IRA==IWA) + INPUTS=MEMVAL; + } + + //Operand sel + //B + if(!ZERO) + { + if(BSEL) + B=ACC; + else + { + B=DSP->TEMP[(TRA+DSP->DEC)&0x7F]; + B<<=8; + B>>=8; + //if(B&0x00800000) + // B|=0xFF000000; //Sign extend + } + if(NEGB) + B=0-B; + } + else + B=0; + + //X + if(XSEL) + X=INPUTS; + else + { + X=DSP->TEMP[(TRA+DSP->DEC)&0x7F]; + X<<=8; + X>>=8; + //if(X&0x00800000) + // X|=0xFF000000; + } + + //Y + if(YSEL==0) + Y=FRC_REG; + else if(YSEL==1) + Y=DSP->COEF[COEF]>>3; //COEF is 16 bits + else if(YSEL==2) + Y=(Y_REG>>11)&0x1FFF; + else if(YSEL==3) + Y=(Y_REG>>4)&0x0FFF; + + if(YRL) + Y_REG=INPUTS; + + //Shifter + if(SHIFT==0) + { + SHIFTED=ACC; + if(SHIFTED>0x007FFFFF) + SHIFTED=0x007FFFFF; + if(SHIFTED<(-0x00800000)) + SHIFTED=-0x00800000; + } + else if(SHIFT==1) + { + SHIFTED=ACC*2; + if(SHIFTED>0x007FFFFF) + SHIFTED=0x007FFFFF; + if(SHIFTED<(-0x00800000)) + SHIFTED=-0x00800000; + } + else if(SHIFT==2) + { + SHIFTED=ACC*2; + SHIFTED<<=8; + SHIFTED>>=8; + //SHIFTED&=0x00FFFFFF; + //if(SHIFTED&0x00800000) + // SHIFTED|=0xFF000000; + } + else if(SHIFT==3) + { + SHIFTED=ACC; + SHIFTED<<=8; + SHIFTED>>=8; + //SHIFTED&=0x00FFFFFF; + //if(SHIFTED&0x00800000) + // SHIFTED|=0xFF000000; + } + + //ACCUM + Y<<=19; + Y>>=19; + //if(Y&0x1000) + // Y|=0xFFFFF000; + + v=(((INT64) X*(INT64) Y)>>12); + ACC=(int) v+B; + + if(TWT) + DSP->TEMP[(TWA+DSP->DEC)&0x7F]=SHIFTED; + + if(FRCL) + { + if(SHIFT==3) + FRC_REG=SHIFTED&0x0FFF; + else + FRC_REG=(SHIFTED>>11)&0x1FFF; + } + + if(MRD || MWT) + //if(0) + { + ADDR=DSP->MADRS[MASA]; + if(!TABLE) + ADDR+=DSP->DEC; + if(ADREB) + ADDR+=ADRS_REG&0x0FFF; + if(NXADR) + ADDR++; + if(!TABLE) + ADDR&=DSP->RBL-1; + else + ADDR&=0xFFFF; + //ADDR<<=1; + //ADDR+=DSP->RBP<<13; + //MEMVAL=DSP->SCSPRAM[ADDR>>1]; + ADDR+=DSP->RBP<<12; + if (ADDR > 0x7ffff) ADDR = 0; + if(MRD && (step&1)) //memory only allowed on odd? DoA inserts NOPs on even + { + if(NOFL) + MEMVAL=DSP->SCSPRAM[ADDR]<<8; + else + MEMVAL=UNPACK(DSP->SCSPRAM[ADDR]); + } + if(MWT && (step&1)) + { + if(NOFL) + DSP->SCSPRAM[ADDR]=SHIFTED>>8; + else + DSP->SCSPRAM[ADDR]=PACK(SHIFTED); + } + } + + if(ADRL) + { + if(SHIFT==3) + ADRS_REG=(SHIFTED>>12)&0xFFF; + else + ADRS_REG=(INPUTS>>16); + } + + if(EWT) + DSP->EFREG[EWA]+=SHIFTED>>8; + + } + --DSP->DEC; + memset(DSP->MIXS,0,4*16); +// if(f) +// fclose(f); +} + +void SCSPDSP_SetSample(SCSPDSP *DSP,INT32 sample,int SEL,int MXL) +{ + //DSP->MIXS[SEL]+=sample<<(MXL+1)/*7*/; + DSP->MIXS[SEL]+=sample; +// if(MXL) +// int a=1; +} + +void SCSPDSP_Start(SCSPDSP *DSP) +{ + int i; + DSP->Stopped=0; + for(i=127;i>=0;--i) + { + UINT16 *IPtr=DSP->MPRO+i*4; + + if(IPtr[0]!=0 || IPtr[1]!=0 || IPtr[2]!=0 || IPtr[3]!=0) + break; + } + DSP->LastStep=i+1; + +} diff --git a/src/devices/sound/scspdsp.h b/src/devices/sound/scspdsp.h new file mode 100644 index 00000000000..319b3ebe099 --- /dev/null +++ b/src/devices/sound/scspdsp.h @@ -0,0 +1,42 @@ +// license:BSD-3-Clause +// copyright-holders:ElSemi, R. Belmont +#pragma once + +#ifndef __SCSPDSP_H__ +#define __SCSPDSP_H__ + +//the DSP Context +struct SCSPDSP +{ +//Config + UINT16 *SCSPRAM; + UINT32 SCSPRAM_LENGTH; + UINT32 RBP; //Ring buf pointer + UINT32 RBL; //Delay ram (Ring buffer) size in words + +//context + + INT16 COEF[64]; //16 bit signed + UINT16 MADRS[32]; //offsets (in words), 16 bit + UINT16 MPRO[128*4]; //128 steps 64 bit + INT32 TEMP[128]; //TEMP regs,24 bit signed + INT32 MEMS[32]; //MEMS regs,24 bit signed + UINT32 DEC; + +//input + INT32 MIXS[16]; //MIXS, 24 bit signed + INT16 EXTS[2]; //External inputs (CDDA) 16 bit signed + +//output + INT16 EFREG[16]; //EFREG, 16 bit signed + + int Stopped; + int LastStep; +}; + +void SCSPDSP_Init(SCSPDSP *DSP); +void SCSPDSP_SetSample(SCSPDSP *DSP, INT32 sample, INT32 SEL, INT32 MXL); +void SCSPDSP_Step(SCSPDSP *DSP); +void SCSPDSP_Start(SCSPDSP *DSP); + +#endif /* __SCSPDSP_H__ */ diff --git a/src/devices/sound/segapcm.c b/src/devices/sound/segapcm.c new file mode 100644 index 00000000000..50e875bc474 --- /dev/null +++ b/src/devices/sound/segapcm.c @@ -0,0 +1,151 @@ +// license:BSD-3-Clause +// copyright-holders:Hiromitsu Shioya, Olivier Galibert +/*********************************************************/ +/* SEGA 16ch 8bit PCM */ +/*********************************************************/ + +#include "emu.h" +#include "segapcm.h" + + +// device type definition +const device_type SEGAPCM = &device_creator; + + +//------------------------------------------------- +// segapcm_device - constructor +//------------------------------------------------- + +segapcm_device::segapcm_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, SEGAPCM, "Sega PCM", tag, owner, clock, "segapcm", __FILE__), + device_sound_interface(mconfig, *this), + m_rom(*this, DEVICE_SELF), + m_ram(NULL), + m_bank(0), + m_bankshift(0), + m_bankmask(0), + m_stream(NULL) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void segapcm_device::device_start() +{ + int mask, rom_mask; + + m_ram = auto_alloc_array(machine(), UINT8, 0x800); + + memset(m_ram, 0xff, 0x800); + + m_bankshift = (UINT8) m_bank; + mask = m_bank >> 16; + if (!mask) + mask = BANK_MASK7 >> 16; + + for(rom_mask = 1; rom_mask < m_rom.length(); rom_mask *= 2); + rom_mask--; + + m_bankmask = mask & (rom_mask >> m_bankshift); + + m_stream = stream_alloc(0, 2, clock() / 128); + + save_item(NAME(m_low)); + save_pointer(NAME(m_ram), 0x800); +} + + +//------------------------------------------------- +// sound_stream_update - handle a stream update +//------------------------------------------------- + +void segapcm_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + /* clear the buffers */ + memset(outputs[0], 0, samples*sizeof(*outputs[0])); + memset(outputs[1], 0, samples*sizeof(*outputs[1])); + + // reg function + // ------------------------------------------------ + // 0x00 ? + // 0x01 ? + // 0x02 volume left + // 0x03 volume right + // 0x04 loop address (08-15) + // 0x05 loop address (16-23) + // 0x06 end address + // 0x07 address delta + // 0x80 ? + // 0x81 ? + // 0x82 ? + // 0x83 ? + // 0x84 current address (08-15), 00-07 is internal? + // 0x85 current address (16-23) + // 0x86 bit 0: channel disable? + // bit 1: loop disable + // other bits: bank + // 0x87 ? + + /* loop over channels */ + for (int ch = 0; ch < 16; ch++) + { + UINT8 *regs = m_ram+8*ch; + + /* only process active channels */ + if (!(regs[0x86]&1)) + { + const UINT8 *rom = m_rom + ((regs[0x86] & m_bankmask) << m_bankshift); + UINT32 addr = (regs[0x85] << 16) | (regs[0x84] << 8) | m_low[ch]; + UINT32 loop = (regs[0x05] << 16) | (regs[0x04] << 8); + UINT8 end = regs[6] + 1; + int i; + + /* loop over samples on this channel */ + for (i = 0; i < samples; i++) + { + INT8 v = 0; + + /* handle looping if we've hit the end */ + if ((addr >> 16) == end) + { + if (regs[0x86] & 2) + { + regs[0x86] |= 1; + break; + } + else addr = loop; + } + + /* fetch the sample */ + v = rom[(addr >> 8) & m_rom.mask()] - 0x80; + + /* apply panning and advance */ + outputs[0][i] += v * (regs[2] & 0x7f); + outputs[1][i] += v * (regs[3] & 0x7f); + addr = (addr + regs[7]) & 0xffffff; + } + + /* store back the updated address */ + regs[0x84] = addr >> 8; + regs[0x85] = addr >> 16; + m_low[ch] = regs[0x86] & 1 ? 0 : addr; + } + } +} + + +WRITE8_MEMBER( segapcm_device::sega_pcm_w ) +{ + m_stream->update(); + m_ram[offset & 0x07ff] = data; +} + + +READ8_MEMBER( segapcm_device::sega_pcm_r ) +{ + m_stream->update(); + return m_ram[offset & 0x07ff]; +} diff --git a/src/devices/sound/segapcm.h b/src/devices/sound/segapcm.h new file mode 100644 index 00000000000..df7110bb7b2 --- /dev/null +++ b/src/devices/sound/segapcm.h @@ -0,0 +1,70 @@ +// license:BSD-3-Clause +// copyright-holders:Hiromitsu Shioya, Olivier Galibert +/*********************************************************/ +/* SEGA 8bit PCM */ +/*********************************************************/ + +#pragma once + +#ifndef __SEGAPCM_H__ +#define __SEGAPCM_H__ + +#define BANK_256 (11) +#define BANK_512 (12) +#define BANK_12M (13) +#define BANK_MASK7 (0x70<<16) +#define BANK_MASKF (0xf0<<16) +#define BANK_MASKF8 (0xf8<<16) + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_SEGAPCM_ADD(_tag, _clock) \ + MCFG_DEVICE_ADD(_tag, SEGAPCM, _clock) +#define MCFG_SEGAPCM_REPLACE(_tag, _clock) \ + MCFG_DEVICE_REPLACE(_tag, SEGAPCM, _clock) + +#define MCFG_SEGAPCM_BANK(_bank) \ + segapcm_device::set_bank(*device, _bank); + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class segapcm_device : public device_t, + public device_sound_interface +{ +public: + segapcm_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + ~segapcm_device() { } + + // static configuration + static void set_bank(device_t &device, int bank) { downcast(device).m_bank = bank; } + + DECLARE_WRITE8_MEMBER( sega_pcm_w ); + DECLARE_READ8_MEMBER( sega_pcm_r ); + +protected: + // device-level overrides + virtual void device_start(); + + // sound stream update overrides + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + +private: + required_region_ptr m_rom; + UINT8* m_ram; + UINT8 m_low[16]; + int m_bank; + int m_bankshift; + int m_bankmask; + sound_stream* m_stream; +}; + +extern const device_type SEGAPCM; + + +#endif /* __SEGAPCM_H__ */ diff --git a/src/devices/sound/sid.c b/src/devices/sound/sid.c new file mode 100644 index 00000000000..375095e7401 --- /dev/null +++ b/src/devices/sound/sid.c @@ -0,0 +1,352 @@ +// license:BSD-3-Clause +// copyright-holders:Peter Trauner +/* + copyright peter trauner + + based on michael schwend's sid play + + Noise generation algorithm is used courtesy of Asger Alstrup Nielsen. + His original publication can be found on the SID home page. + + Noise table optimization proposed by Phillip Wooller. The output of + each table does not differ. + + MOS-8580 R5 combined waveforms recorded by Dennis "Deadman" Lindroos. +*/ + +#include "emu.h" +#include "sidvoice.h" +#include "sidenvel.h" +#include "sid.h" + +static float *filterTable; +static float *bandPassParam; +#define lowPassParam filterTable +static float filterResTable[16]; + +#define maxLogicalVoices 4 + +static const int mix16monoMiddleIndex = 256*maxLogicalVoices/2; +static UINT16 mix16mono[256*maxLogicalVoices]; + +static UINT16 zero16bit=0; /* either signed or unsigned */ +//UINT32 splitBufferLen; + +static void MixerInit(int threeVoiceAmplify) +{ + long si; + UINT16 ui; + long ampDiv = maxLogicalVoices; + + if (threeVoiceAmplify) + { + ampDiv = (maxLogicalVoices-1); + } + + /* Mixing formulas are optimized by sample input value. */ + + si = (-128*maxLogicalVoices) * 256; + for (ui = 0; ui < sizeof(mix16mono)/sizeof(UINT16); ui++ ) + { + mix16mono[ui] = (UINT16)(si/ampDiv) + zero16bit; + si+=256; + } + +} + + +INLINE void syncEm(SID6581_t *This) +{ + int sync1 = (This->optr1.modulator->cycleLenCount <= 0); + int sync2 = (This->optr2.modulator->cycleLenCount <= 0); + int sync3 = (This->optr3.modulator->cycleLenCount <= 0); + + This->optr1.cycleLenCount--; + This->optr2.cycleLenCount--; + This->optr3.cycleLenCount--; + + if (This->optr1.sync && sync1) + { + This->optr1.cycleLenCount = 0; + This->optr1.outProc = &sidWaveCalcNormal; +#if defined(DIRECT_FIXPOINT) + optr1.waveStep.l = 0; +#else + This->optr1.waveStep = (This->optr1.waveStepPnt = 0); +#endif + } + if (This->optr2.sync && sync2) + { + This->optr2.cycleLenCount = 0; + This->optr2.outProc = &sidWaveCalcNormal; +#if defined(DIRECT_FIXPOINT) + This->optr2.waveStep.l = 0; +#else + This->optr2.waveStep = (This->optr2.waveStepPnt = 0); +#endif + } + if (This->optr3.sync && sync3) + { + This->optr3.cycleLenCount = 0; + This->optr3.outProc = &sidWaveCalcNormal; +#if defined(DIRECT_FIXPOINT) + optr3.waveStep.l = 0; +#else + This->optr3.waveStep = (This->optr3.waveStepPnt = 0); +#endif + } +} + + +void sidEmuFillBuffer(SID6581_t *This, stream_sample_t *buffer, UINT32 bufferLen ) +{ +//void* fill16bitMono( SID6581_t *This, void* buffer, UINT32 numberOfSamples ) + + for ( ; bufferLen > 0; bufferLen-- ) + { + *buffer++ = (INT16) mix16mono[(unsigned)(mix16monoMiddleIndex + +(*This->optr1.outProc)(&This->optr1) + +(*This->optr2.outProc)(&This->optr2) + +(This->optr3.outProc(&This->optr3)&This->optr3_outputmask) +/* hack for digi sounds + does n't seam to come from a tone operator + ghostbusters and goldrunner everything except volume zeroed */ + +(This->masterVolume<<2) +// +(*sampleEmuRout)() + )]; + syncEm(This); + } +} + +/* --------------------------------------------------------------------- Init */ + + +/* Reset. */ + +int sidEmuReset(SID6581_t *This) +{ + sidClearOperator( &This->optr1 ); + enveEmuResetOperator( &This->optr1 ); + sidClearOperator( &This->optr2 ); + enveEmuResetOperator( &This->optr2 ); + sidClearOperator( &This->optr3 ); + enveEmuResetOperator( &This->optr3 ); + This->optr3_outputmask = ~0; /* on */ + +// sampleEmuReset(); + + This->filter.Type = (This->filter.CurType = 0); + This->filter.Value = 0; + This->filter.Dy = (This->filter.ResDy = 0); + + sidEmuSet( &This->optr1 ); + sidEmuSet( &This->optr2 ); + sidEmuSet( &This->optr3 ); + + sidEmuSet2( &This->optr1 ); + sidEmuSet2( &This->optr2 ); + sidEmuSet2( &This->optr3 ); + + return TRUE; +} + + +static void filterTableInit(running_machine &machine) +{ + int sample_rate = machine.sample_rate(); + UINT16 uk; + /* Parameter calculation has not been moved to a separate function */ + /* by purpose. */ + const float filterRefFreq = 44100.0f; + + float yMax = 1.0f; + float yMin = 0.01f; + float yAdd; + float yTmp, rk, rk2; + + float resDyMax; + float resDyMin; + float resDy; + + filterTable = auto_alloc_array(machine, float, 0x800); + bandPassParam = auto_alloc_array(machine, float, 0x800); + + uk = 0; + for ( rk = 0; rk < 0x800; rk++ ) + { + filterTable[uk] = (((expf(rk/0x800*logf(400.0f))/60.0f)+0.05f) + *filterRefFreq) / sample_rate; + if ( filterTable[uk] < yMin ) + filterTable[uk] = yMin; + if ( filterTable[uk] > yMax ) + filterTable[uk] = yMax; + uk++; + } + + /*extern float bandPassParam[0x800]; */ + yMax = 0.22f; + yMin = 0.05f; /* less for some R1/R4 chips */ + yAdd = (yMax-yMin)/2048.0f; + yTmp = yMin; + uk = 0; + /* Some C++ compilers still have non-local scope! */ + for ( rk2 = 0; rk2 < 0x800; rk2++ ) + { + bandPassParam[uk] = (yTmp*filterRefFreq) / sample_rate; + yTmp += yAdd; + uk++; + } + + /*extern float filterResTable[16]; */ + resDyMax = 1.0f; + resDyMin = 2.0f; + resDy = resDyMin; + for ( uk = 0; uk < 16; uk++ ) + { + filterResTable[uk] = resDy; + resDy -= (( resDyMin - resDyMax ) / 15 ); + } + filterResTable[0] = resDyMin; + filterResTable[15] = resDyMax; +} + +void sid6581_init (SID6581_t *This) +{ + This->optr1.sid=This; + This->optr2.sid=This; + This->optr3.sid=This; + + This->optr1.modulator = &This->optr3; + This->optr3.carrier = &This->optr1; + This->optr1.filtVoiceMask = 1; + + This->optr2.modulator = &This->optr1; + This->optr1.carrier = &This->optr2; + This->optr2.filtVoiceMask = 2; + + This->optr3.modulator = &This->optr2; + This->optr2.carrier = &This->optr3; + This->optr3.filtVoiceMask = 4; + + + + This->PCMsid = (UINT32)(This->PCMfreq * (16777216.0 / This->clock)); + This->PCMsidNoise = (UINT32)((This->clock*256.0)/This->PCMfreq); + + This->filter.Enabled = TRUE; + + sidInitMixerEngine(This->device->machine()); + filterTableInit(This->device->machine()); + + sidInitWaveformTables(This->type); + + enveEmuInit(This->PCMfreq, TRUE); + + MixerInit(0); + + sidEmuReset(This); +} + +void sid6581_port_w (SID6581_t *This, int offset, int data) +{ + offset &= 0x1f; + + switch (offset) + { + case 0x19: case 0x1a: case 0x1b: case 0x1c: + case 0x1d: + case 0x1e: + case 0x1f: + break; + case 0x15: case 0x16: case 0x17: + case 0x18: + This->mixer_channel->update(); + This->reg[offset] = data; + This->masterVolume = ( This->reg[0x18] & 15 ); + This->masterVolumeAmplIndex = This->masterVolume << 8; + + if ((This->reg[0x18]&0x80) && + ((This->reg[0x17]&This->optr3.filtVoiceMask)==0)) + This->optr3_outputmask = 0; /* off */ + else + This->optr3_outputmask = ~0; /* on */ + + This->filter.Type = This->reg[0x18] & 0x70; + if (This->filter.Type != This->filter.CurType) + { + This->filter.CurType = This->filter.Type; + This->optr1.filtLow = (This->optr1.filtRef = 0); + This->optr2.filtLow = (This->optr2.filtRef = 0); + This->optr3.filtLow = (This->optr3.filtRef = 0); + } + if ( This->filter.Enabled ) + { + This->filter.Value = 0x7ff & ( (This->reg[0x15]&7) | ( (UINT16)This->reg[0x16] << 3 )); + if (This->filter.Type == 0x20) + This->filter.Dy = bandPassParam ? bandPassParam[This->filter.Value] : 0.0f; + else + This->filter.Dy = lowPassParam ? lowPassParam[This->filter.Value] : 0.0f; + This->filter.ResDy = filterResTable[This->reg[0x17] >> 4] - This->filter.Dy; + if ( This->filter.ResDy < 1.0f ) + This->filter.ResDy = 1.0f; + } + + sidEmuSet( &This->optr1 ); + sidEmuSet( &This->optr3 ); + sidEmuSet( &This->optr2 ); + + // relies on sidEmuSet also for other channels! + sidEmuSet2( &This->optr1 ); + sidEmuSet2( &This->optr2 ); + sidEmuSet2( &This->optr3 ); + break; + + default: + This->mixer_channel->update(); + This->reg[offset] = data; + + if (offset<7) { + This->optr1.reg[offset] = data; + } else if (offset<14) { + This->optr2.reg[offset-7] = data; + } else if (offset<21) { + This->optr3.reg[offset-14] = data; + } + + sidEmuSet( &This->optr1 ); + sidEmuSet( &This->optr3 ); + sidEmuSet( &This->optr2 ); + + // relies on sidEmuSet also for other channels! + sidEmuSet2( &This->optr1 ); + sidEmuSet2( &This->optr2 ); + sidEmuSet2( &This->optr3 ); + break; + } +} + +int sid6581_port_r (running_machine &machine, SID6581_t *This, int offset) +{ + int data; +/* SIDPLAY reads last written at a sid address value */ + offset &= 0x1f; + switch (offset) + { + case 0x1d: + case 0x1e: + case 0x1f: + data=0xff; + break; + case 0x1b: + This->mixer_channel->update(); + data = This->optr3.output; + break; + case 0x1c: + This->mixer_channel->update(); + data = This->optr3.enveVol; + break; + default: + data=This->reg[offset]; + } + return data; +} diff --git a/src/devices/sound/sid.h b/src/devices/sound/sid.h new file mode 100644 index 00000000000..9fb8a6dc5bb --- /dev/null +++ b/src/devices/sound/sid.h @@ -0,0 +1,66 @@ +// license:BSD-3-Clause +// copyright-holders:Peter Trauner +#pragma once + +#ifndef __SID_H__ +#define __SID_H__ + +/* + approximation of the sid6581 chip + this part is for one chip, +*/ + +#include "sidvoice.h" + +/* private area */ +struct SID6581_t +{ + device_t *device; + sound_stream *mixer_channel; // mame stream/ mixer channel + + int type; + UINT32 clock; + + UINT16 PCMfreq; // samplerate of the current systems soundcard/DAC + UINT32 PCMsid, PCMsidNoise; + +#if 0 + /* following depends on type */ + ptr2sidVoidFunc ModeNormalTable[16]; + ptr2sidVoidFunc ModeRingTable[16]; + // for speed reason it could be better to make them global! + UINT8* waveform30; + UINT8* waveform50; + UINT8* waveform60; + UINT8* waveform70; +#endif + int reg[0x20]; + +// bool sidKeysOn[0x20], sidKeysOff[0x20]; + + UINT8 masterVolume; + UINT16 masterVolumeAmplIndex; + + + struct + { + int Enabled; + UINT8 Type, CurType; + float Dy, ResDy; + UINT16 Value; + } filter; + + sidOperator optr1, optr2, optr3; + int optr3_outputmask; +}; + +void sid6581_init (SID6581_t *This); + +int sidEmuReset(SID6581_t *This); + +int sid6581_port_r (running_machine &machine, SID6581_t *This, int offset); +void sid6581_port_w (SID6581_t *This, int offset, int data); + +void sidEmuFillBuffer(SID6581_t *This, stream_sample_t *buffer, UINT32 bufferLen ); + +#endif /* __SID_H__ */ diff --git a/src/devices/sound/side6581.h b/src/devices/sound/side6581.h new file mode 100644 index 00000000000..9fb28ffd6d0 --- /dev/null +++ b/src/devices/sound/side6581.h @@ -0,0 +1,128 @@ +// license:BSD-3-Clause +// copyright-holders:Peter Trauner +// +// /home/ms/source/sidplay/libsidplay/emu/RCS/enve_dl.h,v +// + +#pragma once + +#ifndef __SIDE6581_H__ +#define __SIDE6581_H__ + + +// +// Hardware: +// C64 C PAL, MOS 6581R4 1686 S +// + +static const UINT8 releaseTab[] = +{ + 255, 255, 254, 254, 253, 253, 252, 252, 251, 251, 250, 250, 249, 249, 248, + 248, 247, 247, 246, 246, 245, 245, 244, 244, 243, 243, 242, 242, 241, 241, + 240, 240, 239, 239, 238, 238, 237, 237, 236, 236, 235, 235, 234, 234, 233, + 233, 232, 232, 231, 231, 230, 230, 229, 229, 228, 228, 227, 227, 226, 226, + 225, 225, 224, 224, 223, 223, 222, 222, 221, 221, 220, 220, 219, 219, 218, + 218, 217, 217, 216, 216, 215, 215, 214, 214, 213, 213, 212, 212, 211, 211, + 210, 210, 209, 209, 208, 208, 207, 207, 206, 206, 205, 205, 204, 204, 203, + 203, 202, 202, 201, 201, 200, 200, 199, 199, 198, 198, 197, 197, 196, 196, + 195, 195, 194, 194, 193, 193, 192, 192, 191, 191, 190, 190, 189, 189, 188, + 188, 187, 187, 186, 186, 185, 185, 184, 184, 183, 183, 182, 182, 181, 181, + 180, 180, 179, 179, 178, 178, 177, 177, 176, 176, 175, 175, 174, 174, 173, + 173, 172, 172, 171, 171, 170, 170, 169, 169, 168, 168, 167, 167, 166, 166, + 165, 165, 164, 164, 163, 163, 162, 162, 161, 161, 160, 160, 159, 159, 158, + 158, 157, 157, 156, 156, 155, 155, 154, 154, 153, 153, 152, 152, 151, 151, + 150, 150, 149, 149, 148, 148, 147, 147, 146, 146, 145, 145, 144, 144, 143, + 143, 142, 142, 141, 141, 140, 140, 139, 139, 138, 138, 137, 137, 136, 136, + 135, 135, 134, 134, 133, 133, 132, 132, 131, 131, 130, 130, 129, 129, 128, + 128, 127, 127, 126, 126, 125, 125, 124, 124, 123, 123, 122, 122, 121, 121, + 120, 120, 119, 119, 118, 118, 117, 117, 116, 116, 115, 115, 114, 114, 113, + 113, 112, 112, 111, 111, 110, 110, 109, 109, 108, 108, 107, 107, 106, 106, + 105, 105, 104, 104, 103, 103, 102, 102, 101, 101, 100, 100, 99, 99, 98, + 98, 97, 97, 96, 96, 95, 95, 94, 94, 94, 94, 93, 93, 93, 93, + 92, 92, 92, 92, 91, 91, 91, 91, 90, 90, 90, 90, 89, 89, 89, + 89, 88, 88, 88, 88, 87, 87, 87, 87, 86, 86, 86, 86, 85, 85, + 85, 85, 84, 84, 84, 84, 83, 83, 83, 83, 82, 82, 82, 82, 81, + 81, 81, 81, 80, 80, 80, 80, 79, 79, 79, 79, 78, 78, 78, 78, + 77, 77, 77, 77, 76, 76, 76, 76, 75, 75, 75, 75, 74, 74, 74, + 74, 73, 73, 73, 73, 72, 72, 72, 72, 71, 71, 71, 71, 70, 70, + 70, 70, 69, 69, 69, 69, 68, 68, 68, 68, 67, 67, 67, 67, 66, + 66, 66, 66, 65, 65, 65, 65, 64, 64, 64, 64, 63, 63, 63, 63, + 62, 62, 62, 62, 61, 61, 61, 61, 60, 60, 60, 60, 59, 59, 59, + 59, 58, 58, 58, 58, 57, 57, 57, 57, 56, 56, 56, 56, 55, 55, + 55, 55, 55, 55, 55, 55, 54, 54, 54, 54, 54, 54, 54, 54, 53, + 53, 53, 53, 53, 53, 53, 53, 52, 52, 52, 52, 52, 52, 52, 52, + 51, 51, 51, 51, 51, 51, 51, 51, 50, 50, 50, 50, 50, 50, 50, + 50, 49, 49, 49, 49, 49, 49, 49, 49, 48, 48, 48, 48, 48, 48, + 48, 48, 47, 47, 47, 47, 47, 47, 47, 47, 46, 46, 46, 46, 46, + 46, 46, 46, 45, 45, 45, 45, 45, 45, 45, 45, 44, 44, 44, 44, + 44, 44, 44, 44, 43, 43, 43, 43, 43, 43, 43, 43, 42, 42, 42, + 42, 42, 42, 42, 42, 41, 41, 41, 41, 41, 41, 41, 41, 40, 40, + 40, 40, 40, 40, 40, 40, 39, 39, 39, 39, 39, 39, 39, 39, 38, + 38, 38, 38, 38, 38, 38, 38, 37, 37, 37, 37, 37, 37, 37, 37, + 36, 36, 36, 36, 36, 36, 36, 36, 35, 35, 35, 35, 35, 35, 35, + 35, 34, 34, 34, 34, 34, 34, 34, 34, 33, 33, 33, 33, 33, 33, + 33, 33, 32, 32, 32, 32, 32, 32, 32, 32, 31, 31, 31, 31, 31, + 31, 31, 31, 30, 30, 30, 30, 30, 30, 30, 30, 29, 29, 29, 29, + 29, 29, 29, 29, 28, 28, 28, 28, 28, 28, 28, 28, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, + 23, 23, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, + 22, 22, 22, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 18, 18, 18, 18, 18, 18, 18, 18, 18, + 18, 18, 18, 18, 18, 18, 18, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 +}; + + +#endif /* __SIDE6581_H__ */ diff --git a/src/devices/sound/sidenvel.c b/src/devices/sound/sidenvel.c new file mode 100644 index 00000000000..9b375c37b1f --- /dev/null +++ b/src/devices/sound/sidenvel.c @@ -0,0 +1,588 @@ +// license:BSD-3-Clause +// copyright-holders:Peter Trauner +/*========================================================================= */ +/* This source implements the ADSR volume envelope of the SID-chip. */ +/* Two different envelope shapes are implemented, an exponential */ +/* approximation and the linear shape, which can easily be determined */ +/* by reading the registers of the third SID operator. */ +/* */ +/* Accurate volume envelope times as of November 1994 are used */ +/* courtesy of George W. Taylor , */ +/* They are slightly modified. */ +/* */ +/* To use the rounded envelope times from the C64 Programmers Reference */ +/* Book define SID_REFTIMES at the Makefile level. */ +/* */ +/* To perform realtime calculations with floating point precision define */ +/* SID_FPUENVE at the Makefile level. On high-end FPUs (not Pentium !), */ +/* this can result in speed improvement. Default is integer fixpoint. */ +/* */ +/* Global Makefile definables: */ +/* */ +/* DIRECT_FIXPOINT - use a union to access integer fixpoint operands */ +/* in memory. This makes an assumption about the */ +/* hardware and software architecture and therefore */ +/* is considered a hack ! */ +/* */ +/* Local (or Makefile) definables: */ +/* */ +/* SID_REFTIMES - use rounded envelope times */ +/* SID_FPUENVE - use floating point precision for calculations */ +/* (will override the global DIRECT_FIXPOINT setting !) */ +/* */ +/*========================================================================= */ + +#include "emu.h" +#include "sidvoice.h" +#include "sid.h" + +#include "side6581.h" +#include "sidenvel.h" + +const UINT8 masterVolumeLevels[16] = +{ + 0, 17, 34, 51, 68, 85, 102, 119, + 136, 153, 170, 187, 204, 221, 238, 255 +}; + +static UINT16 masterAmplModTable[16*256]; + +static const float attackTimes[16] = +{ + /* milliseconds */ +#if defined(SID_REFTIMES) + 2.0f, 8.0f, 16.0f, 24.0f, 38.0f, 56.0f, 68.0f, 80.0f, + 100.0f, 250.0f, 500.0f, 800.0f, 1000.0f, 3000.0f, 5000.0f, 8000.0f +#else + 2.2528606f, 8.0099577f, 15.7696042f, 23.7795619f, 37.2963655f, 55.0684591f, + 66.8330845f, 78.3473987f, + 98.1219818f, 244.554021f, 489.108042f, 782.472742f, 977.715461f, 2933.64701f, + 4889.07793f, 7822.72493f +#endif +}; + +static const float decayReleaseTimes[16] = +{ + /* milliseconds */ +#if defined(SID_REFTIMES) + 8.0f, 24.0f, 48.0f, 72.0f, 114.0f, 168.0f, 204.0f, 240.0f, + 300.0f, 750.0f, 1500.0f, 2400.0f, 3000.0f, 9000.0f, 15000.0f, 24000.0f +#else + 8.91777693f, 24.594051f, 48.4185907f, 73.0116639f, 114.512475f, 169.078356f, + 205.199432f, 240.551975f, + 301.266125f, 750.858245f, 1501.71551f, 2402.43682f, 3001.89298f, 9007.21405f, + 15010.998f, 24018.2111f +#endif +}; + +#ifdef SID_FPUENVE + static float attackRates[16]; + static float decayReleaseRates[16]; +#elif defined(DIRECT_FIXPOINT) + static UINT32 attackRates[16]; + static UINT32 decayReleaseRates[16]; +#else + static UINT32 attackRates[16]; + static UINT32 attackRatesP[16]; + static UINT32 decayReleaseRates[16]; + static UINT32 decayReleaseRatesP[16]; +#endif + +static const UINT32 attackTabLen = 255; +static UINT32 releaseTabLen; +static UINT32 releasePos[256]; + + +void enveEmuInit( UINT32 updateFreq, int measuredValues ) +{ + UINT32 i, j, k; + + releaseTabLen = sizeof(releaseTab); + for ( i = 0; i < 256; i++ ) + { + j = 0; + while (( j < releaseTabLen ) && (releaseTab[j] > i) ) + { + j++; + } + if ( j < releaseTabLen ) + { + releasePos[i] = j; + } + else + { + releasePos[i] = releaseTabLen -1; + } + } + + k = 0; + for ( i = 0; i < 16; i++ ) + { + for ( j = 0; j < 256; j++ ) + { + UINT16 tmpVol = j; + if (measuredValues) + { + tmpVol = (UINT16) ((293.0*(1-exp(j/-130.0)))+4.0); + if (j == 0) + tmpVol = 0; + if (tmpVol > 255) + tmpVol = 255; + } + /* Want the modulated volume value in the high byte. */ + masterAmplModTable[k++] = ((tmpVol * masterVolumeLevels[i]) / 255) << 8; + } + } + + for ( i = 0; i < 16; i++ ) + { +#ifdef SID_FPUENVE + double scaledenvelen = floor(( attackTimes[i] * updateFreq ) / 1000UL ); + if (scaledenvelen == 0) + scaledenvelen = 1; + attackRates[i] = attackTabLen / scaledenvelen; + + scaledenvelen = floor(( decayReleaseTimes[i] * updateFreq ) / 1000UL ); + if (scaledenvelen == 0) + scaledenvelen = 1; + decayReleaseRates[i] = releaseTabLen / scaledenvelen; +#elif defined(DIRECT_FIXPOINT) + UINT32 scaledenvelen = (UINT32)floor(( attackTimes[i] * updateFreq ) / 1000UL ); + if (scaledenvelen == 0) + scaledenvelen = 1; + attackRates[i] = (attackTabLen << 16) / scaledenvelen; + + scaledenvelen = (UINT32)floor(( decayReleaseTimes[i] * updateFreq ) / 1000UL ); + if (scaledenvelen == 0) + scaledenvelen = 1; + decayReleaseRates[i] = (releaseTabLen << 16) / scaledenvelen; +#else + UINT32 scaledenvelen = (UINT32)(/*floor*/(( attackTimes[i] * updateFreq ) / 1000UL )); + + if (scaledenvelen == 0) + scaledenvelen = 1; + attackRates[i] = attackTabLen / scaledenvelen; + attackRatesP[i] = (( attackTabLen % scaledenvelen ) * 65536UL ) / scaledenvelen; + + scaledenvelen = (UINT32)(/*floor*/(( decayReleaseTimes[i] * updateFreq ) / 1000UL )); + if (scaledenvelen == 0) + scaledenvelen = 1; + decayReleaseRates[i] = releaseTabLen / scaledenvelen; + decayReleaseRatesP[i] = (( releaseTabLen % scaledenvelen ) * 65536UL ) / scaledenvelen; +#endif + } +} + +/* Reset op. */ + +void enveEmuResetOperator(sidOperator* pVoice) +{ + /* mute, end of R-phase */ + pVoice->ADSRctrl = ENVE_MUTE; +// pVoice->gateOnCtrl = (pVoice->gateOffCtrl = false); + +#ifdef SID_FPUENVE + pVoice->fenveStep = (pVoice->fenveStepAdd = 0); + pVoice->enveStep = 0; +#elif defined(DIRECT_FIXPOINT) + pVoice->enveStep.l = (pVoice->enveStepAdd.l = 0); +#else + pVoice->enveStep = (pVoice->enveStepPnt = 0); + pVoice->enveStepAdd = (pVoice->enveStepAddPnt = 0); +#endif + pVoice->enveSusVol = 0; + pVoice->enveVol = 0; + pVoice->enveShortAttackCount = 0; +} + +INLINE UINT16 enveEmuStartAttack(sidOperator*); +INLINE UINT16 enveEmuStartDecay(sidOperator*); +INLINE UINT16 enveEmuStartRelease(sidOperator*); +INLINE UINT16 enveEmuAlterAttack(sidOperator*); +INLINE UINT16 enveEmuAlterDecay(sidOperator*); +INLINE UINT16 enveEmuAlterSustain(sidOperator*); +INLINE UINT16 enveEmuAlterSustainDecay(sidOperator*); +INLINE UINT16 enveEmuAlterRelease(sidOperator*); +INLINE UINT16 enveEmuAttack(sidOperator*); +INLINE UINT16 enveEmuDecay(sidOperator*); +INLINE UINT16 enveEmuSustain(sidOperator*); +INLINE UINT16 enveEmuSustainDecay(sidOperator*); +INLINE UINT16 enveEmuRelease(sidOperator*); +INLINE UINT16 enveEmuMute(sidOperator*); + +INLINE UINT16 enveEmuStartShortAttack(sidOperator*); +INLINE UINT16 enveEmuAlterShortAttack(sidOperator*); +INLINE UINT16 enveEmuShortAttack(sidOperator*); + + +const ptr2sidUwordFunc enveModeTable[] = +{ + /* 0 */ + &enveEmuStartAttack, &enveEmuStartRelease, + &enveEmuAttack, &enveEmuDecay, &enveEmuSustain, &enveEmuRelease, + &enveEmuSustainDecay, &enveEmuMute, + /* 16 */ + &enveEmuStartShortAttack, + &enveEmuMute, &enveEmuMute, &enveEmuMute, + &enveEmuMute, &enveEmuMute, &enveEmuMute, &enveEmuMute, + /* 32 */ + &enveEmuStartAttack, &enveEmuStartRelease, + &enveEmuAlterAttack, &enveEmuAlterDecay, &enveEmuAlterSustain, &enveEmuAlterRelease, + &enveEmuAlterSustainDecay, &enveEmuMute, + /* 48 */ + &enveEmuStartShortAttack, + &enveEmuMute, &enveEmuMute, &enveEmuMute, + &enveEmuMute, &enveEmuMute, &enveEmuMute, &enveEmuMute +}; + +/* Real-time functions. */ +/* Order is important because of inline optimizations. */ +/* */ +/* ADSRctrl is (index*2) to enveModeTable[], because of KEY-bit. */ + +INLINE void enveEmuEnveAdvance(sidOperator* pVoice) +{ +#ifdef SID_FPUENVE + pVoice->fenveStep += pVoice->fenveStepAdd; +#elif defined(DIRECT_FIXPOINT) + pVoice->enveStep.l += pVoice->enveStepAdd.l; +#else + pVoice->enveStepPnt += pVoice->enveStepAddPnt; + pVoice->enveStep += pVoice->enveStepAdd + ( pVoice->enveStepPnt > 65535 ); + pVoice->enveStepPnt &= 0xFFFF; +#endif +} + +/* */ +/* Mute/Idle. */ +/* */ + +/* Only used in the beginning. */ +INLINE UINT16 enveEmuMute(sidOperator* pVoice) +{ + return 0; +} + +/* */ +/* Release */ +/* */ + +INLINE UINT16 enveEmuRelease(sidOperator* pVoice) +{ +#ifdef SID_FPUENVE + pVoice->enveStep = (UINT16)pVoice->fenveStep; +#endif +#if defined(DIRECT_FIXPOINT) && !defined(SID_FPUENVE) + if ( pVoice->enveStep.w[HI] >= releaseTabLen ) +#else + if ( pVoice->enveStep >= releaseTabLen ) +#endif + { + pVoice->enveVol = releaseTab[releaseTabLen -1]; + return masterAmplModTable[ pVoice->sid->masterVolumeAmplIndex + pVoice->enveVol ]; + } + else + { +#if defined(DIRECT_FIXPOINT) && !defined(SID_FPUENVE) + pVoice->enveVol = releaseTab[pVoice->enveStep.w[HI]]; +#else + pVoice->enveVol = releaseTab[pVoice->enveStep]; +#endif + enveEmuEnveAdvance(pVoice); + return masterAmplModTable[ pVoice->sid->masterVolumeAmplIndex + pVoice->enveVol ]; + } +} + +INLINE UINT16 enveEmuAlterRelease(sidOperator* pVoice) +{ + UINT8 release = pVoice->SIDSR & 0x0F; +#ifdef SID_FPUENVE + pVoice->fenveStepAdd = decayReleaseRates[release]; +#elif defined(DIRECT_FIXPOINT) + pVoice->enveStepAdd.l = decayReleaseRates[release]; +#else + pVoice->enveStepAdd = decayReleaseRates[release]; + pVoice->enveStepAddPnt = decayReleaseRatesP[release]; +#endif + pVoice->ADSRproc = &enveEmuRelease; + return enveEmuRelease(pVoice); +} + +INLINE UINT16 enveEmuStartRelease(sidOperator* pVoice) +{ + pVoice->ADSRctrl = ENVE_RELEASE; +#ifdef SID_FPUENVE + pVoice->fenveStep = releasePos[pVoice->enveVol]; +#elif defined(DIRECT_FIXPOINT) + pVoice->enveStep.w[HI] = releasePos[pVoice->enveVol]; + pVoice->enveStep.w[LO] = 0; +#else + pVoice->enveStep = releasePos[pVoice->enveVol]; + pVoice->enveStepPnt = 0; +#endif + return enveEmuAlterRelease(pVoice); +} + +/* */ +/* Sustain */ +/* */ + +INLINE UINT16 enveEmuSustain(sidOperator* pVoice) +{ + return masterAmplModTable[pVoice->sid->masterVolumeAmplIndex+pVoice->enveVol]; +} + +INLINE UINT16 enveEmuSustainDecay(sidOperator* pVoice) +{ +#ifdef SID_FPUENVE + pVoice->enveStep = (UINT16)pVoice->fenveStep; +#endif +#if defined(DIRECT_FIXPOINT) && !defined(SID_FPUENVE) + if ( pVoice->enveStep.w[HI] >= releaseTabLen ) +#else + if ( pVoice->enveStep >= releaseTabLen ) +#endif + { + pVoice->enveVol = releaseTab[releaseTabLen-1]; + return enveEmuAlterSustain(pVoice); + } + else + { +#if defined(DIRECT_FIXPOINT) && !defined(SID_FPUENVE) + pVoice->enveVol = releaseTab[pVoice->enveStep.w[HI]]; +#else + pVoice->enveVol = releaseTab[pVoice->enveStep]; +#endif + /* Will be controlled from sidEmuSet2(). */ + if ( pVoice->enveVol <= pVoice->enveSusVol ) + { + pVoice->enveVol = pVoice->enveSusVol; + return enveEmuAlterSustain(pVoice); + } + else + { + enveEmuEnveAdvance(pVoice); + return masterAmplModTable[ pVoice->sid->masterVolumeAmplIndex + pVoice->enveVol ]; + } + } +} + +/* This is the same as enveEmuStartSustainDecay(). */ +INLINE UINT16 enveEmuAlterSustainDecay(sidOperator* pVoice) +{ + UINT8 decay = pVoice->SIDAD & 0x0F ; +#ifdef SID_FPUENVE + pVoice->fenveStepAdd = decayReleaseRates[decay]; +#elif defined(DIRECT_FIXPOINT) + pVoice->enveStepAdd.l = decayReleaseRates[decay]; +#else + pVoice->enveStepAdd = decayReleaseRates[decay]; + pVoice->enveStepAddPnt = decayReleaseRatesP[decay]; +#endif + pVoice->ADSRproc = &enveEmuSustainDecay; + return enveEmuSustainDecay(pVoice); +} + +/* This is the same as enveEmuStartSustain(). */ +INLINE UINT16 enveEmuAlterSustain(sidOperator* pVoice) +{ + if ( pVoice->enveVol > pVoice->enveSusVol ) + { + pVoice->ADSRctrl = ENVE_SUSTAINDECAY; + pVoice->ADSRproc = &enveEmuSustainDecay; + return enveEmuAlterSustainDecay(pVoice); + } + else + { + pVoice->ADSRctrl = ENVE_SUSTAIN; + pVoice->ADSRproc = &enveEmuSustain; + return enveEmuSustain(pVoice); + } +} + +/* */ +/* Decay */ +/* */ + +INLINE UINT16 enveEmuDecay(sidOperator* pVoice) +{ +#ifdef SID_FPUENVE + pVoice->enveStep = (UINT16)pVoice->fenveStep; +#endif +#if defined(DIRECT_FIXPOINT) && !defined(SID_FPUENVE) + if ( pVoice->enveStep.w[HI] >= releaseTabLen ) +#else + if ( pVoice->enveStep >= releaseTabLen ) +#endif + { + pVoice->enveVol = pVoice->enveSusVol; + return enveEmuAlterSustain(pVoice); /* start sustain */ + } + else + { +#if defined(DIRECT_FIXPOINT) && !defined(SID_FPUENVE) + pVoice->enveVol = releaseTab[pVoice->enveStep.w[HI]]; +#else + pVoice->enveVol = releaseTab[pVoice->enveStep]; +#endif + /* Will be controlled from sidEmuSet2(). */ + if ( pVoice->enveVol <= pVoice->enveSusVol ) + { + pVoice->enveVol = pVoice->enveSusVol; + return enveEmuAlterSustain(pVoice); /* start sustain */ + } + else + { + enveEmuEnveAdvance(pVoice); + return masterAmplModTable[ pVoice->sid->masterVolumeAmplIndex + pVoice->enveVol ]; + } + } +} + +INLINE UINT16 enveEmuAlterDecay(sidOperator* pVoice) +{ + UINT8 decay = pVoice->SIDAD & 0x0F ; +#ifdef SID_FPUENVE + pVoice->fenveStepAdd = decayReleaseRates[decay]; +#elif defined(DIRECT_FIXPOINT) + pVoice->enveStepAdd.l = decayReleaseRates[decay]; +#else + pVoice->enveStepAdd = decayReleaseRates[decay]; + pVoice->enveStepAddPnt = decayReleaseRatesP[decay]; +#endif + pVoice->ADSRproc = &enveEmuDecay; + return enveEmuDecay(pVoice); +} + +INLINE UINT16 enveEmuStartDecay(sidOperator* pVoice) +{ + pVoice->ADSRctrl = ENVE_DECAY; +#ifdef SID_FPUENVE + pVoice->fenveStep = 0; +#elif defined(DIRECT_FIXPOINT) + pVoice->enveStep.l = 0; +#else + pVoice->enveStep = (pVoice->enveStepPnt = 0); +#endif + return enveEmuAlterDecay(pVoice); +} + +/* */ +/* Attack */ +/* */ + +INLINE UINT16 enveEmuAttack(sidOperator* pVoice) +{ +#ifdef SID_FPUENVE + pVoice->enveStep = (UINT16)pVoice->fenveStep; +#endif +#if defined(DIRECT_FIXPOINT) && !defined(SID_FPUENVE) + if ( pVoice->enveStep.w[HI] > attackTabLen ) +#else + if ( pVoice->enveStep >= attackTabLen ) +#endif + return enveEmuStartDecay(pVoice); + else + { +#if defined(DIRECT_FIXPOINT) && !defined(SID_FPUENVE) + pVoice->enveVol = pVoice->enveStep.w[HI]; +#else + pVoice->enveVol = pVoice->enveStep; +#endif + enveEmuEnveAdvance(pVoice); + return masterAmplModTable[ pVoice->sid->masterVolumeAmplIndex + pVoice->enveVol ]; + } +} + +INLINE UINT16 enveEmuAlterAttack(sidOperator* pVoice) +{ + UINT8 attack = pVoice->SIDAD >> 4; +#ifdef SID_FPUENVE + pVoice->fenveStepAdd = attackRates[attack]; +#elif defined(DIRECT_FIXPOINT) + pVoice->enveStepAdd.l = attackRates[attack]; +#else + pVoice->enveStepAdd = attackRates[attack]; + pVoice->enveStepAddPnt = attackRatesP[attack]; +#endif + pVoice->ADSRproc = &enveEmuAttack; + return enveEmuAttack(pVoice); +} + +INLINE UINT16 enveEmuStartAttack(sidOperator* pVoice) +{ + pVoice->ADSRctrl = ENVE_ATTACK; +#ifdef SID_FPUENVE + pVoice->fenveStep = (float)pVoice->enveVol; +#elif defined(DIRECT_FIXPOINT) + pVoice->enveStep.w[HI] = pVoice->enveVol; + pVoice->enveStep.w[LO] = 0; +#else + pVoice->enveStep = pVoice->enveVol; + pVoice->enveStepPnt = 0; +#endif + return enveEmuAlterAttack(pVoice); +} + +/* */ +/* Experimental. */ +/* */ + +/*#include */ +/*#include */ + +INLINE UINT16 enveEmuShortAttack(sidOperator* pVoice) +{ +#ifdef SID_FPUENVE + pVoice->enveStep = (UINT16)pVoice->fenveStep; +#endif +#if defined(DIRECT_FIXPOINT) && !defined(SID_FPUENVE) + if ((pVoice->enveStep.w[HI] > attackTabLen) || + (pVoice->enveShortAttackCount == 0)) +#else + if ((pVoice->enveStep >= attackTabLen) || + (pVoice->enveShortAttackCount == 0)) +#endif +/* return enveEmuStartRelease(pVoice); */ + return enveEmuStartDecay(pVoice); +#if defined(DIRECT_FIXPOINT) && !defined(SID_FPUENVE) + pVoice->enveVol = pVoice->enveStep.w[HI]; +#else + pVoice->enveVol = pVoice->enveStep; +#endif + pVoice->enveShortAttackCount--; +/* cout << hex << pVoice->enveShortAttackCount << " / " << pVoice->enveVol << endl; */ + enveEmuEnveAdvance(pVoice); + return masterAmplModTable[ pVoice->sid->masterVolumeAmplIndex + pVoice->enveVol ]; +} + +INLINE UINT16 enveEmuAlterShortAttack(sidOperator* pVoice) +{ + UINT8 attack = pVoice->SIDAD >> 4; +#ifdef SID_FPUENVE + pVoice->fenveStepAdd = attackRates[attack]; +#elif defined(DIRECT_FIXPOINT) + pVoice->enveStepAdd.l = attackRates[attack]; +#else + pVoice->enveStepAdd = attackRates[attack]; + pVoice->enveStepAddPnt = attackRatesP[attack]; +#endif + pVoice->ADSRproc = &enveEmuShortAttack; + return enveEmuShortAttack(pVoice); +} + +INLINE UINT16 enveEmuStartShortAttack(sidOperator* pVoice) +{ + pVoice->ADSRctrl = ENVE_SHORTATTACK; +#ifdef SID_FPUENVE + pVoice->fenveStep = (float)pVoice->enveVol; +#elif defined(DIRECT_FIXPOINT) + pVoice->enveStep.w[HI] = pVoice->enveVol; + pVoice->enveStep.w[LO] = 0; +#else + pVoice->enveStep = pVoice->enveVol; + pVoice->enveStepPnt = 0; +#endif + pVoice->enveShortAttackCount = 65535; /* unused */ + return enveEmuAlterShortAttack(pVoice); +} diff --git a/src/devices/sound/sidenvel.h b/src/devices/sound/sidenvel.h new file mode 100644 index 00000000000..72f303b8110 --- /dev/null +++ b/src/devices/sound/sidenvel.h @@ -0,0 +1,39 @@ +// license:BSD-3-Clause +// copyright-holders:Peter Trauner +// +// /home/ms/source/sidplay/libsidplay/emu/RCS/envelope.h,v +// + +#pragma once + +#ifndef __SIDENVEL_H__ +#define __SIDENVEL_H__ + + +extern void enveEmuInit(UINT32 updateFreq, int measuredValues); +void enveEmuResetOperator(sidOperator* pVoice); + + +extern const ptr2sidUwordFunc enveModeTable[]; // -> envelope.cpp +extern const UINT8 masterVolumeLevels[16]; // -> envelope.cpp + +enum +{ + ENVE_STARTATTACK = 0, + ENVE_STARTRELEASE = 2, + + ENVE_ATTACK = 4, + ENVE_DECAY = 6, + ENVE_SUSTAIN = 8, + ENVE_RELEASE = 10, + ENVE_SUSTAINDECAY = 12, + ENVE_MUTE = 14, + + ENVE_STARTSHORTATTACK = 16, + ENVE_SHORTATTACK = 16, + + ENVE_ALTER = 32 +}; + + +#endif /* __SIDENVEL_H__ */ diff --git a/src/devices/sound/sidvoice.c b/src/devices/sound/sidvoice.c new file mode 100644 index 00000000000..2dd42bcf3c4 --- /dev/null +++ b/src/devices/sound/sidvoice.c @@ -0,0 +1,810 @@ +// license:BSD-3-Clause +// copyright-holders:Peter Trauner +#include "emu.h" +#include "sidvoice.h" +#include "sid.h" +#include "sidenvel.h" +#include "sidw6581.h" +#include "sidw8580.h" + +static UINT8 triangleTable[4096]; +static UINT8 sawtoothTable[4096]; +static UINT8 squareTable[2*4096]; +static const UINT8* waveform30; +static const UINT8* waveform50; +static const UINT8* waveform60; +static const UINT8* waveform70; +#if defined(LARGE_NOISE_TABLE) + static UINT8 noiseTableMSB[1<<8]; + static UINT8 noiseTableLSB[1L<<16]; +#else + static UINT8 noiseTableMSB[1<<8]; + static UINT8 noiseTableMID[1<<8]; + static UINT8 noiseTableLSB[1<<8]; +#endif + +static INT8* ampMod1x8; + +static const UINT32 noiseSeed = 0x7ffff8; + +void sidInitMixerEngine(running_machine &machine) +{ + UINT16 uk; + INT32 si, sj ; + + /* 8-bit volume modulation tables. */ + float filterAmpl = 0.7f; + + ampMod1x8=auto_alloc_array(machine, INT8, 256*256); + + uk = 0; + for ( si = 0; si < 256; si++ ) + { + for ( sj = -128; sj < 128; sj++, uk++ ) + { + ampMod1x8[uk] = (INT8)(((si*sj)/255)*filterAmpl); + } + } + +} + +INLINE void waveAdvance(sidOperator* pVoice) +{ +#if defined(DIRECT_FIXPOINT) + pVoice->waveStep.l += pVoice->waveStepAdd.l; + pVoice->waveStep.w[HI] &= 4095; +#else + pVoice->waveStepPnt += pVoice->waveStepAddPnt; + pVoice->waveStep += pVoice->waveStepAdd; + if (pVoice->waveStepPnt > 65535 ) pVoice->waveStep++; + pVoice->waveStepPnt &= 0xFFFF; + pVoice->waveStep &= 4095; +#endif +} + +INLINE void noiseAdvance(sidOperator* pVoice) +{ + pVoice->noiseStep += pVoice->noiseStepAdd; + if (pVoice->noiseStep >= (1L<<20)) + { + pVoice->noiseStep -= (1L<<20); +#if defined(DIRECT_FIXPOINT) + pVoice->noiseReg.l = (pVoice->noiseReg.l << 1) | + (((pVoice->noiseReg.l >> 22) ^ (pVoice->noiseReg.l >> 17)) & 1); +#else + pVoice->noiseReg = (pVoice->noiseReg << 1) | + (((pVoice->noiseReg >> 22) ^ (pVoice->noiseReg >> 17)) & 1); +#endif +#if defined(DIRECT_FIXPOINT) && defined(LARGE_NOISE_TABLE) + pVoice->noiseOutput = (noiseTableLSB[pVoice->noiseReg.w[LO]] + |noiseTableMSB[pVoice->noiseReg.w[HI]&0xff]); +#elif defined(DIRECT_FIXPOINT) + pVoice->noiseOutput = (noiseTableLSB[pVoice->noiseReg.b[LOLO]] + |noiseTableMID[pVoice->noiseReg.b[LOHI]] + |noiseTableMSB[pVoice->noiseReg.b[HILO]]); +#else + pVoice->noiseOutput = (noiseTableLSB[pVoice->noiseReg&0xff] + |noiseTableMID[pVoice->noiseReg>>8&0xff] + |noiseTableMSB[pVoice->noiseReg>>16&0xff]); +#endif + } +} + +INLINE void noiseAdvanceHp(sidOperator* pVoice) +{ + UINT32 tmp = pVoice->noiseStepAdd; + while (tmp >= (1L<<20)) + { + tmp -= (1L<<20); +#if defined(DIRECT_FIXPOINT) + pVoice->noiseReg.l = (pVoice->noiseReg.l << 1) | + (((pVoice->noiseReg.l >> 22) ^ (pVoice->noiseReg.l >> 17)) & 1); +#else + pVoice->noiseReg = (pVoice->noiseReg << 1) | + (((pVoice->noiseReg >> 22) ^ (pVoice->noiseReg >> 17)) & 1); +#endif + } + pVoice->noiseStep += tmp; + if (pVoice->noiseStep >= (1L<<20)) + { + pVoice->noiseStep -= (1L<<20); +#if defined(DIRECT_FIXPOINT) + pVoice->noiseReg.l = (pVoice->noiseReg.l << 1) | + (((pVoice->noiseReg.l >> 22) ^ (pVoice->noiseReg.l >> 17)) & 1); +#else + pVoice->noiseReg = (pVoice->noiseReg << 1) | + (((pVoice->noiseReg >> 22) ^ (pVoice->noiseReg >> 17)) & 1); +#endif + } +#if defined(DIRECT_FIXPOINT) && defined(LARGE_NOISE_TABLE) + pVoice->noiseOutput = (noiseTableLSB[pVoice->noiseReg.w[LO]] + |noiseTableMSB[pVoice->noiseReg.w[HI]&0xff]); +#elif defined(DIRECT_FIXPOINT) + pVoice->noiseOutput = (noiseTableLSB[pVoice->noiseReg.b[LOLO]] + |noiseTableMID[pVoice->noiseReg.b[LOHI]] + |noiseTableMSB[pVoice->noiseReg.b[HILO]]); +#else + pVoice->noiseOutput = (noiseTableLSB[pVoice->noiseReg&0xff] + |noiseTableMID[pVoice->noiseReg>>8&0xff] + |noiseTableMSB[pVoice->noiseReg>>16&0xff]); +#endif +} + + +#if defined(DIRECT_FIXPOINT) + #define triangle triangleTable[pVoice->waveStep.w[HI]] + #define sawtooth sawtoothTable[pVoice->waveStep.w[HI]] + #define square squareTable[pVoice->waveStep.w[HI] + pVoice->pulseIndex] + #define triSaw waveform30[pVoice->waveStep.w[HI]] + #define triSquare waveform50[pVoice->waveStep.w[HI] + pVoice->SIDpulseWidth] + #define sawSquare waveform60[pVoice->waveStep.w[HI] + pVoice->SIDpulseWidth] + #define triSawSquare waveform70[pVoice->waveStep.w[HI] + pVoice->SIDpulseWidth] +#else + #define triangle triangleTable[pVoice->waveStep] + #define sawtooth sawtoothTable[pVoice->waveStep] + #define square squareTable[pVoice->waveStep + pVoice->pulseIndex] + #define triSaw waveform30[pVoice->waveStep] + #define triSquare waveform50[pVoice->waveStep + pVoice->SIDpulseWidth] + #define sawSquare waveform60[pVoice->waveStep + pVoice->SIDpulseWidth] + #define triSawSquare waveform70[pVoice->waveStep + pVoice->SIDpulseWidth] +#endif + + +static void sidMode00(sidOperator* pVoice) { + pVoice->output = (pVoice->filtIO-0x80); + waveAdvance(pVoice); +} + +#if 0 +/* not used */ +static void sidModeReal00(sidOperator* pVoice) { + pVoice->output = 0; + waveAdvance(pVoice); +} +#endif + +static void sidMode10(sidOperator* pVoice) { + pVoice->output = triangle; + waveAdvance(pVoice); +} + +static void sidMode20(sidOperator* pVoice) { + pVoice->output = sawtooth; + waveAdvance(pVoice); +} + +static void sidMode30(sidOperator* pVoice) { + pVoice->output = triSaw; + waveAdvance(pVoice); +} + +static void sidMode40(sidOperator* pVoice) { + pVoice->output = square; + waveAdvance(pVoice); +} + +static void sidMode50(sidOperator* pVoice) { + pVoice->output = triSquare; + waveAdvance(pVoice); +} + +static void sidMode60(sidOperator* pVoice) { + pVoice->output = sawSquare; + waveAdvance(pVoice); +} + +static void sidMode70(sidOperator* pVoice) { + pVoice->output = triSawSquare; + waveAdvance(pVoice); +} + +static void sidMode80(sidOperator* pVoice) { + pVoice->output = pVoice->noiseOutput; + waveAdvance(pVoice); + noiseAdvance(pVoice); +} + +static void sidMode80hp(sidOperator* pVoice) { + pVoice->output = pVoice->noiseOutput; + waveAdvance(pVoice); + noiseAdvanceHp(pVoice); +} + +static void sidModeLock(sidOperator* pVoice) +{ + pVoice->noiseIsLocked = TRUE; + pVoice->output = (pVoice->filtIO-0x80); + waveAdvance(pVoice); +} + +/* */ +/* */ +/* */ + +static void sidMode14(sidOperator* pVoice) +{ +#if defined(DIRECT_FIXPOINT) + if ( pVoice->modulator->waveStep.w[HI] < 2048 ) +#else + if ( pVoice->modulator->waveStep < 2048 ) +#endif + pVoice->output = triangle; + else + pVoice->output = 0xFF ^ triangle; + waveAdvance(pVoice); +} + +static void sidMode34(sidOperator* pVoice) { +#if defined(DIRECT_FIXPOINT) + if ( pVoice->modulator->waveStep.w[HI] < 2048 ) +#else + if ( pVoice->modulator->waveStep < 2048 ) +#endif + pVoice->output = triSaw; + else + pVoice->output = 0xFF ^ triSaw; + waveAdvance(pVoice); +} + +static void sidMode54(sidOperator* pVoice) { +#if defined(DIRECT_FIXPOINT) + if ( pVoice->modulator->waveStep.w[HI] < 2048 ) +#else + if ( pVoice->modulator->waveStep < 2048 ) +#endif + pVoice->output = triSquare; + else + pVoice->output = 0xFF ^ triSquare; + waveAdvance(pVoice); +} + +static void sidMode74(sidOperator* pVoice) { +#if defined(DIRECT_FIXPOINT) + if ( pVoice->modulator->waveStep.w[HI] < 2048 ) +#else + if ( pVoice->modulator->waveStep < 2048 ) +#endif + pVoice->output = triSawSquare; + else + pVoice->output = 0xFF ^ triSawSquare; + waveAdvance(pVoice); +} + +/* */ +/* */ +/* */ + +INLINE void waveCalcCycleLen(sidOperator* pVoice) +{ +#if defined(DIRECT_FIXPOINT) + pVoice->cycleAddLen.w[HI] = 0; + pVoice->cycleAddLen.l += pVoice->cycleLen.l; + pVoice->cycleLenCount = pVoice->cycleAddLen.w[HI]; +#else + pVoice->cycleAddLenPnt += pVoice->cycleLenPnt; + pVoice->cycleLenCount = pVoice->cycleLen; + if ( pVoice->cycleAddLenPnt > 65535 ) pVoice->cycleLenCount++; + pVoice->cycleAddLenPnt &= 0xFFFF; +#endif + /* If we keep the value cycleLen between 1 <= x <= 65535, */ + /* the following check is not required. */ +/* if ( pVoice->cycleLenCount == 0 ) */ +/* { */ +/*#if defined(DIRECT_FIXPOINT) */ +/* pVoice->waveStep.l = 0; */ +/*#else */ +/* pVoice->waveStep = (pVoice->waveStepPnt = 0); */ +/*#endif */ +/* pVoice->cycleLenCount = 0; */ +/* } */ +/* else */ + { +#if defined(DIRECT_FIXPOINT) + register UINT16 diff = pVoice->cycleLenCount - pVoice->cycleLen.w[HI]; +#else + register UINT16 diff = pVoice->cycleLenCount - pVoice->cycleLen; +#endif + if ( pVoice->wavePre[diff].len != pVoice->cycleLenCount ) + { + pVoice->wavePre[diff].len = pVoice->cycleLenCount; +#if defined(DIRECT_FIXPOINT) + pVoice->wavePre[diff].stp = (pVoice->waveStepAdd.l = (4096UL*65536UL) / pVoice->cycleLenCount); +#else + pVoice->wavePre[diff].stp = (pVoice->waveStepAdd = 4096UL / pVoice->cycleLenCount); + pVoice->wavePre[diff].pnt = (pVoice->waveStepAddPnt = ((4096UL % pVoice->cycleLenCount) * 65536UL) / pVoice->cycleLenCount); +#endif + } + else + { +#if defined(DIRECT_FIXPOINT) + pVoice->waveStepAdd.l = pVoice->wavePre[diff].stp; +#else + pVoice->waveStepAdd = pVoice->wavePre[diff].stp; + pVoice->waveStepAddPnt = pVoice->wavePre[diff].pnt; +#endif + } + } /* see above (opening bracket) */ +} + +INLINE void waveCalcFilter(sidOperator* pVoice) +{ + if ( pVoice->filtEnabled ) + { + if ( pVoice->sid->filter.Type != 0 ) + { + if ( pVoice->sid->filter.Type == 0x20 ) + { + float tmp; + pVoice->filtLow += ( pVoice->filtRef * pVoice->sid->filter.Dy ); + tmp = (float)pVoice->filtIO - pVoice->filtLow; + tmp -= pVoice->filtRef * pVoice->sid->filter.ResDy; + pVoice->filtRef += ( tmp * (pVoice->sid->filter.Dy) ); + pVoice->filtIO = (INT8)(pVoice->filtRef-pVoice->filtLow/4); + } + else if (pVoice->sid->filter.Type == 0x40) + { + float tmp, tmp2; + pVoice->filtLow += ( pVoice->filtRef * pVoice->sid->filter.Dy * 0.1f ); + tmp = (float)pVoice->filtIO - pVoice->filtLow; + tmp -= pVoice->filtRef * pVoice->sid->filter.ResDy; + pVoice->filtRef += ( tmp * (pVoice->sid->filter.Dy) ); + tmp2 = pVoice->filtRef - pVoice->filtIO/8; + if (tmp2 < -128) + tmp2 = -128; + if (tmp2 > 127) + tmp2 = 127; + pVoice->filtIO = (INT8)tmp2; + } + else + { + float sample, sample2; + int tmp; + pVoice->filtLow += ( pVoice->filtRef * pVoice->sid->filter.Dy ); + sample = pVoice->filtIO; + sample2 = sample - pVoice->filtLow; + tmp = (int)sample2; + sample2 -= pVoice->filtRef * pVoice->sid->filter.ResDy; + pVoice->filtRef += ( sample2 * pVoice->sid->filter.Dy ); + + if ( pVoice->sid->filter.Type == 0x10 ) + { + pVoice->filtIO = (INT8)pVoice->filtLow; + } + else if ( pVoice->sid->filter.Type == 0x30 ) + { + pVoice->filtIO = (INT8)pVoice->filtLow; + } + else if ( pVoice->sid->filter.Type == 0x50 ) + { + pVoice->filtIO = (INT8)(sample - (tmp >> 1)); + } + else if ( pVoice->sid->filter.Type == 0x60 ) + { + pVoice->filtIO = (INT8)tmp; + } + else if ( pVoice->sid->filter.Type == 0x70 ) + { + pVoice->filtIO = (INT8)(sample - (tmp >> 1)); + } + } + } + else /* pVoice->sid->filter.Type == 0x00 */ + { + pVoice->filtIO = 0; + } + } +} + +static INT8 waveCalcMute(sidOperator* pVoice) +{ + (*pVoice->ADSRproc)(pVoice); /* just process envelope */ + return pVoice->filtIO;//&pVoice->outputMask; +} + + +INT8 sidWaveCalcNormal(sidOperator* pVoice) +{ + if ( pVoice->cycleLenCount <= 0 ) + { + waveCalcCycleLen(pVoice); + if (( pVoice->SIDctrl & 0x40 ) == 0x40 ) + { + pVoice->pulseIndex = pVoice->newPulseIndex; + if ( pVoice->pulseIndex > 2048 ) + { +#if defined(DIRECT_FIXPOINT) + pVoice->waveStep.w[HI] = 0; +#else + pVoice->waveStep = 0; +#endif + } + } + } + (*pVoice->waveProc)(pVoice); + pVoice->filtIO = ampMod1x8[(*pVoice->ADSRproc)(pVoice)|pVoice->output]; +// pVoice->filtIO = pVoice->sid->masterVolume; // test for digi sound + waveCalcFilter(pVoice); + return pVoice->filtIO;//&pVoice->outputMask; +} + + +static INT8 waveCalcRangeCheck(sidOperator* pVoice) +{ +#if defined(DIRECT_FIXPOINT) + pVoice->waveStepOld = pVoice->waveStep.w[HI]; + (*pVoice->waveProc)(pVoice); + if (pVoice->waveStep.w[HI] < pVoice->waveStepOld) +#else + pVoice->waveStepOld = pVoice->waveStep; + (*pVoice->waveProc)(pVoice); + if (pVoice->waveStep < pVoice->waveStepOld) +#endif + { + /* Next step switch back to normal calculation. */ + pVoice->cycleLenCount = 0; + pVoice->outProc = &sidWaveCalcNormal; +#if defined(DIRECT_FIXPOINT) + pVoice->waveStep.w[HI] = 4095; +#else + pVoice->waveStep = 4095; +#endif + } + pVoice->filtIO = ampMod1x8[(*pVoice->ADSRproc)(pVoice)|pVoice->output]; + waveCalcFilter(pVoice); + return pVoice->filtIO;//&pVoice->outputMask; +} + +/* -------------------------------------------------- Operator frame set-up 1 */ + +void sidEmuSet(sidOperator* pVoice) +{ + UINT8 enveTemp, newWave, oldWave; + UINT8 ADtemp; + UINT8 SRtemp; + UINT8 tmpSusVol; + + pVoice->SIDfreq = pVoice->reg[0]|(pVoice->reg[1]<<8); + + pVoice->SIDpulseWidth = (pVoice->reg[2]|(pVoice->reg[3]<<8)) & 0x0FFF; + pVoice->newPulseIndex = 4096 - pVoice->SIDpulseWidth; +#if defined(DIRECT_FIXPOINT) + if ( ((pVoice->waveStep.w[HI] + pVoice->pulseIndex) >= 0x1000) + && ((pVoice->waveStep.w[HI] + pVoice->newPulseIndex) >= 0x1000) ) + { + pVoice->pulseIndex = pVoice->newPulseIndex; + } + else if ( ((pVoice->waveStep.w[HI] + pVoice->pulseIndex) < 0x1000) + && ((pVoice->waveStep.w[HI] + pVoice->newPulseIndex) < 0x1000) ) + { + pVoice->pulseIndex = pVoice->newPulseIndex; + } +#else + if ( ((pVoice->waveStep + pVoice->pulseIndex) >= 0x1000) + && ((pVoice->waveStep + pVoice->newPulseIndex) >= 0x1000) ) + { + pVoice->pulseIndex = pVoice->newPulseIndex; + } + else if ( ((pVoice->waveStep + pVoice->pulseIndex) < 0x1000) + && ((pVoice->waveStep + pVoice->newPulseIndex) < 0x1000) ) + { + pVoice->pulseIndex = pVoice->newPulseIndex; + } +#endif + + + oldWave = pVoice->SIDctrl; + enveTemp = pVoice->ADSRctrl; + pVoice->SIDctrl = (newWave = pVoice->reg[4]|(pVoice->reg[5]<<8)); + + if (( newWave & 1 ) ==0 ) + { + if (( oldWave & 1 ) !=0 ) + enveTemp = ENVE_STARTRELEASE; +/* else if ( pVoice->gateOnCtrl ) */ +/* { */ +/* enveTemp = ENVE_STARTSHORTATTACK; */ +/* } */ + } + else if ( /*pVoice->gateOffCtrl || */((oldWave&1)==0) ) + { + enveTemp = ENVE_STARTATTACK; + } + + if ((( oldWave ^ newWave ) & 0xF0 ) != 0 ) + { + pVoice->cycleLenCount = 0; + } + + ADtemp = pVoice->reg[5]; + SRtemp = pVoice->reg[6]; + if ( pVoice->SIDAD != ADtemp ) + { + enveTemp |= ENVE_ALTER; + } + else if ( pVoice->SIDSR != SRtemp ) + { + enveTemp |= ENVE_ALTER; + } + pVoice->SIDAD = ADtemp; + pVoice->SIDSR = SRtemp; + tmpSusVol = masterVolumeLevels[SRtemp >> 4]; + if (pVoice->ADSRctrl != ENVE_SUSTAIN) /* !!! */ + { + pVoice->enveSusVol = tmpSusVol; + } + else + { + if ( pVoice->enveSusVol > pVoice->enveVol ) + pVoice->enveSusVol = 0; + else + pVoice->enveSusVol = tmpSusVol; + } + + pVoice->ADSRproc = enveModeTable[enveTemp>>1]; /* shifting out the KEY-bit */ + pVoice->ADSRctrl = enveTemp & (255-ENVE_ALTER-1); + + pVoice->filtEnabled = pVoice->sid->filter.Enabled && + ((pVoice->sid->reg[0x17] & pVoice->filtVoiceMask)!=0); +} + +/* -------------------------------------------------- Operator frame set-up 2 */ + +/* MOS-8580, MOS-6581 (no 70) */ +static ptr2sidVoidFunc sidModeNormalTable[16] = +{ + sidMode00, sidMode10, sidMode20, sidMode30, sidMode40, sidMode50, sidMode60, sidMode70, + sidMode80, sidModeLock, sidModeLock, sidModeLock, sidModeLock, sidModeLock, sidModeLock, sidModeLock +}; + +/* MOS-8580, MOS-6581 (no 74) */ +static ptr2sidVoidFunc sidModeRingTable[16] = +{ + sidMode00, sidMode14, sidMode00, sidMode34, sidMode00, sidMode54, sidMode00, sidMode74, + sidModeLock, sidModeLock, sidModeLock, sidModeLock, sidModeLock, sidModeLock, sidModeLock, sidModeLock +}; + +void sidClearOperator( sidOperator* pVoice ) +{ + pVoice->SIDfreq = 0; + pVoice->SIDctrl = 0; + pVoice->SIDAD = 0; + pVoice->SIDSR = 0; + + pVoice->sync = FALSE; + + pVoice->pulseIndex = (pVoice->newPulseIndex = (pVoice->SIDpulseWidth = 0)); + pVoice->curSIDfreq = (pVoice->curNoiseFreq = 0); + + pVoice->output = (pVoice->noiseOutput = 0); + pVoice->filtIO = 0; + + pVoice->filtEnabled = FALSE; + pVoice->filtLow = (pVoice->filtRef = 0); + + pVoice->cycleLenCount = 0; +#if defined(DIRECT_FIXPOINT) + pVoice->cycleLen.l = (pVoice->cycleAddLen.l = 0); +#else + pVoice->cycleLen = (pVoice->cycleLenPnt = 0); + pVoice->cycleAddLenPnt = 0; +#endif + + pVoice->outProc = waveCalcMute; + +#if defined(DIRECT_FIXPOINT) + pVoice->waveStepAdd.l = (pVoice->waveStep.l = 0); + pVoice->wavePre[0].len = (pVoice->wavePre[0].stp = 0); + pVoice->wavePre[1].len = (pVoice->wavePre[1].stp = 0); +#else + pVoice->waveStepAdd = (pVoice->waveStepAddPnt = 0); + pVoice->waveStep = (pVoice->waveStepPnt = 0); + pVoice->wavePre[0].len = 0; + pVoice->wavePre[0].stp = (pVoice->wavePre[0].pnt = 0); + pVoice->wavePre[1].len = 0; + pVoice->wavePre[1].stp = (pVoice->wavePre[1].pnt = 0); +#endif + pVoice->waveStepOld = 0; + +#if defined(DIRECT_FIXPOINT) + pVoice->noiseReg.l = noiseSeed; +#else + pVoice->noiseReg = noiseSeed; +#endif + pVoice->noiseStepAdd = (pVoice->noiseStep = 0); + pVoice->noiseIsLocked = FALSE; +} + +void sidEmuSet2(sidOperator* pVoice) +{ + pVoice->outProc = &sidWaveCalcNormal; + pVoice->sync = FALSE; + + if ( (pVoice->SIDfreq < 16) || ((pVoice->SIDctrl & 8) != 0) ) +// if ( /*(pVoice->SIDfreq < 16) || */((pVoice->SIDctrl & 8) != 0) ) + { + pVoice->outProc = waveCalcMute; + if (pVoice->SIDfreq == 0) + { +#if defined(DIRECT_FIXPOINT) + pVoice->cycleLen.l = (pVoice->cycleAddLen.l = 0); + pVoice->waveStep.l = 0; +#else + pVoice->cycleLen = (pVoice->cycleLenPnt = 0); + pVoice->cycleAddLenPnt = 0; + pVoice->waveStep = 0; + pVoice->waveStepPnt = 0; +#endif + pVoice->curSIDfreq = (pVoice->curNoiseFreq = 0); + pVoice->noiseStepAdd = 0; + pVoice->cycleLenCount = 0; + } + if ((pVoice->SIDctrl & 8) != 0) + { + if (pVoice->noiseIsLocked) + { + pVoice->noiseIsLocked = FALSE; +#if defined(DIRECT_FIXPOINT) + pVoice->noiseReg.l = noiseSeed; +#else + pVoice->noiseReg = noiseSeed; +#endif + } + } + } + else + { + if ( pVoice->curSIDfreq != pVoice->SIDfreq ) + { + pVoice->curSIDfreq = pVoice->SIDfreq; + /* We keep the value cycleLen between 1 <= x <= 65535. */ + /* This makes a range-check in waveCalcCycleLen() unrequired. */ +#if defined(DIRECT_FIXPOINT) + pVoice->cycleLen.l = ((pVoice->sid->PCMsid << 12) / pVoice->SIDfreq) << 4; + if (pVoice->cycleLenCount > 0) + { + waveCalcCycleLen(pVoice); + pVoice->outProc = &waveCalcRangeCheck; + } +#else + pVoice->cycleLen = pVoice->sid->PCMsid / pVoice->SIDfreq; + pVoice->cycleLenPnt = (( pVoice->sid->PCMsid % pVoice->SIDfreq ) * 65536UL ) / pVoice->SIDfreq; + if (pVoice->cycleLenCount > 0) + { + waveCalcCycleLen(pVoice); + pVoice->outProc = &waveCalcRangeCheck; + } +#endif + } + + if ((( pVoice->SIDctrl & 0x80 ) == 0x80 ) && ( pVoice->curNoiseFreq != pVoice->SIDfreq )) + { + pVoice->curNoiseFreq = pVoice->SIDfreq; + pVoice->noiseStepAdd = (pVoice->sid->PCMsidNoise * pVoice->SIDfreq) >> 8; + if (pVoice->noiseStepAdd >= (1L<<21)) + sidModeNormalTable[8] = sidMode80hp; + else + sidModeNormalTable[8] = sidMode80; + } + + if (( pVoice->SIDctrl & 2 ) != 0 ) + { + if ( ( pVoice->modulator->SIDfreq == 0 ) || (( pVoice->modulator->SIDctrl & 8 ) != 0 ) ) + { + ; + } + else if ( (( pVoice->carrier->SIDctrl & 2 ) != 0 ) && + ( pVoice->modulator->SIDfreq >= ( pVoice->SIDfreq << 1 )) ) + { + ; + } + else + { + pVoice->sync = TRUE; + } + } + + if ((( pVoice->SIDctrl & 0x14 ) == 0x14 ) && ( pVoice->modulator->SIDfreq != 0 )) + pVoice->waveProc = sidModeRingTable[pVoice->SIDctrl >> 4]; + else + pVoice->waveProc = sidModeNormalTable[pVoice->SIDctrl >> 4]; + } +} + +void sidInitWaveformTables(int type) +{ + int i,j; + UINT16 k; + + k = 0; + for ( i = 0; i < 256; i++ ) + for ( j = 0; j < 8; j++ ) + triangleTable[k++] = i; + for ( i = 255; i >= 0; i-- ) + for ( j = 0; j < 8; j++ ) + triangleTable[k++] = i; + + k = 0; + for ( i = 0; i < 256; i++ ) + for ( j = 0; j < 16; j++ ) + sawtoothTable[k++] = i; + + k = 0; + for ( i = 0; i < 4096; i++ ) + squareTable[k++] = 255; //0; my estimation; especial for digi sound + for ( i = 0; i < 4096; i++ ) + squareTable[k++] = 0; //255; + + if ( type==mos6581_device::TYPE_8580 ) + { + waveform30 = waveform30_8580; + waveform50 = waveform50_8580; + waveform60 = waveform60_8580; + waveform70 = waveform70_8580; + } + else + { + waveform30 = waveform30_6581; + waveform50 = waveform50_6581; + waveform60 = waveform60_6581; + waveform70 = waveform70_6581; /* really audible? */ + } + + if ( type==mos6581_device::TYPE_8580 ) + { + sidModeNormalTable[3] = sidMode30; + sidModeNormalTable[6] = sidMode60; + sidModeNormalTable[7] = sidMode70; + sidModeRingTable[7] = sidMode74; + } + else + { + sidModeNormalTable[3] = sidMode30; + sidModeNormalTable[6] = sidMode60; + sidModeNormalTable[7] = sidMode00; /* really audible? */ + sidModeRingTable[7] = sidMode00; /* */ + } + + { +#if defined(LARGE_NOISE_TABLE) + UINT32 ni; + for (ni = 0; ni < sizeof(noiseTableLSB); ni++) + { + noiseTableLSB[ni] = (UINT8) + (((ni >> (13-4)) & 0x10) | + ((ni >> (11-3)) & 0x08) | + ((ni >> (7-2)) & 0x04) | + ((ni >> (4-1)) & 0x02) | + ((ni >> (2-0)) & 0x01)); + } + for (ni = 0; ni < sizeof(noiseTableMSB); ni++) + { + noiseTableMSB[ni] = (UINT8) + (((ni << (7-(22-16))) & 0x80) | + ((ni << (6-(20-16))) & 0x40) | + ((ni << (5-(16-16))) & 0x20)); + } +#else + UINT32 ni; + for (ni = 0; ni < sizeof(noiseTableLSB); ni++) + { + noiseTableLSB[ni] = (UINT8) + (((ni >> (7-2)) & 0x04) | + ((ni >> (4-1)) & 0x02) | + ((ni >> (2-0)) & 0x01)); + } + for (ni = 0; ni < sizeof(noiseTableMID); ni++) + { + noiseTableMID[ni] = (UINT8) + (((ni >> (13-8-4)) & 0x10) | + ((ni << (3-(11-8))) & 0x08)); + } + for (ni = 0; ni < sizeof(noiseTableMSB); ni++) + { + noiseTableMSB[ni] = (UINT8) + (((ni << (7-(22-16))) & 0x80) | + ((ni << (6-(20-16))) & 0x40) | + ((ni << (5-(16-16))) & 0x20)); + } +#endif + } +} diff --git a/src/devices/sound/sidvoice.h b/src/devices/sound/sidvoice.h new file mode 100644 index 00000000000..f0aebf50f08 --- /dev/null +++ b/src/devices/sound/sidvoice.h @@ -0,0 +1,120 @@ +// license:BSD-3-Clause +// copyright-holders:Peter Trauner +#pragma once + +#ifndef __SIDVOICE_H__ +#define __SIDVOICE_H__ + + +/* + approximation of the sid6581 chip + this part is for 1 (of the 3) voices of a chip +*/ +#include "sound/mos6581.h" + +struct sw_storage +{ + UINT16 len; +#if defined(DIRECT_FIXPOINT) + UINT32 stp; +#else + UINT32 pnt; + INT16 stp; +#endif +}; + +struct SID6581_t; + +struct sidOperator +{ + SID6581_t *sid; + UINT8 reg[7]; + UINT32 SIDfreq; + UINT16 SIDpulseWidth; + UINT8 SIDctrl; + UINT8 SIDAD, SIDSR; + + sidOperator* carrier; + sidOperator* modulator; + int sync; + + UINT16 pulseIndex, newPulseIndex; + UINT16 curSIDfreq; + UINT16 curNoiseFreq; + + UINT8 output;//, outputMask; + + char filtVoiceMask; + int filtEnabled; + float filtLow, filtRef; + INT8 filtIO; + + INT32 cycleLenCount; +#if defined(DIRECT_FIXPOINT) + cpuLword cycleLen, cycleAddLen; +#else + UINT32 cycleAddLenPnt; + UINT16 cycleLen, cycleLenPnt; +#endif + + INT8(*outProc)(sidOperator *); + void(*waveProc)(sidOperator *); + +#if defined(DIRECT_FIXPOINT) + cpuLword waveStep, waveStepAdd; +#else + UINT16 waveStep, waveStepAdd; + UINT32 waveStepPnt, waveStepAddPnt; +#endif + UINT16 waveStepOld; + struct sw_storage wavePre[2]; + +#if defined(DIRECT_FIXPOINT) && defined(LARGE_NOISE_TABLE) + cpuLword noiseReg; +#elif defined(DIRECT_FIXPOINT) + cpuLBword noiseReg; +#else + UINT32 noiseReg; +#endif + UINT32 noiseStep, noiseStepAdd; + UINT8 noiseOutput; + int noiseIsLocked; + + UINT8 ADSRctrl; +// int gateOnCtrl, gateOffCtrl; + UINT16 (*ADSRproc)(sidOperator *); + +#ifdef SID_FPUENVE + float fenveStep, fenveStepAdd; + UINT32 enveStep; +#elif defined(DIRECT_FIXPOINT) + cpuLword enveStep, enveStepAdd; +#else + UINT16 enveStep, enveStepAdd; + UINT32 enveStepPnt, enveStepAddPnt; +#endif + UINT8 enveVol, enveSusVol; + UINT16 enveShortAttackCount; +}; + +typedef INT8 (*ptr2sidFunc)(sidOperator *); +typedef UINT16 (*ptr2sidUwordFunc)(sidOperator *); +typedef void (*ptr2sidVoidFunc)(sidOperator *); + +void sidClearOperator( sidOperator* pVoice ); + +void sidEmuSet(sidOperator* pVoice); +void sidEmuSet2(sidOperator* pVoice); +INT8 sidWaveCalcNormal(sidOperator* pVoice); + +void sidInitWaveformTables(int type); +void sidInitMixerEngine(running_machine &machine); + +#if 0 +extern ptr2sidVoidFunc sid6581ModeNormalTable[16]; +extern ptr2sidVoidFunc sid6581ModeRingTable[16]; +extern ptr2sidVoidFunc sid8580ModeNormalTable[16]; +extern ptr2sidVoidFunc sid8580ModeRingTable[16]; +#endif + +#endif /* __SIDVOICE_H__ */ diff --git a/src/devices/sound/sidw6581.h b/src/devices/sound/sidw6581.h new file mode 100644 index 00000000000..b37f7693c54 --- /dev/null +++ b/src/devices/sound/sidw6581.h @@ -0,0 +1,1053 @@ +// license:GPL-2.0+ +// copyright-holders:Dag Lem +#ifndef WAVE6581_h +#define WAVE6581_h + +/* + * MOS-6581 R1, R3, R4 + * + * Read-out combined waveforms taken from reSID 0.5. + * Copyright Dag Lem + */ + +static const UINT8 waveform30_6581[4096] = +{ + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0x3, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0x7, 0x7, 0x7, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0x3, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe, 0xe, 0xe, 0xe, 0xf, 0xf, 0xf, 0xf, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0x3, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0x7, 0x7, 0x7, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0x3, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1e,0x1e,0x1e,0x1e,0x1f,0x1f,0x3f,0x3f, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0x3, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0x7, 0x7, 0x7, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0x3, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe, 0xe, 0xe, 0xe, 0xf, 0xf, 0xf,0x1f, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0x3, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0x7, 0x7, 0x7, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0x3, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38, + 0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3e,0x3e,0x3f,0x3f,0x7f,0x7f,0x7f,0x7f, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0x3, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0x7, 0x7, 0x7, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0x3, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe, 0xe, 0xe, 0xe, 0xf, 0xf, 0xf, 0xf, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0x3, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0x7, 0x7, 0x7, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0x3, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1e,0x1e,0x1e,0x1e,0x1f,0x1f,0x3f,0x3f, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0x3, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0x7, 0x7, 0x7, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0x3, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe, 0xe, 0xe, 0xe, 0xf, 0xf, 0xf,0x1f, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0x3, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0x7, 0x7, 0x7, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0x3, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38, + 0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3e,0x3e,0x3f,0x3f,0x7f,0x7f,0x7f,0x7f +}; + +static const UINT8 waveform50_6581[4096+4096] = +{ + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x20,0x38,0x3f, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x40, 0x0,0x40,0x40,0x5f, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x40, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x40, 0x0, 0x0, 0x0,0x60, 0x0,0x60,0x60,0x6f, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x40, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x60, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x60, 0x0, 0x0, 0x0,0x60, 0x0,0x60,0x70,0x77, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x60, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x60, 0x0, 0x0, 0x0,0x70,0x40,0x70,0x70,0x7b, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x40,0x70, 0x0,0x40,0x40,0x70,0x60,0x70,0x78,0x7d, + 0x0,0x40,0x60,0x78,0x60,0x78,0x78,0x7e,0x70,0x7c,0x7c,0x7f,0x7e,0x7f,0x7f,0x7f, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x80, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x80, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x80, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x80, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x80, 0x0, 0x0, 0x0,0x80,0x80,0x80,0x80,0x9f, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x80, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x80, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x80, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x80, 0x0,0x80,0x80,0x80,0x80,0xa0,0xa0,0xaf, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x80, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x80,0x80,0x80, + 0x0, 0x0, 0x0,0x80, 0x0,0x80,0x80,0xa0, 0x0,0x80,0x80,0xa0,0x80,0xa0,0xb0,0xb7, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x80, 0x0, 0x0, 0x0,0x80, 0x0,0x80,0x80,0xa0, + 0x0, 0x0, 0x0,0x80, 0x0,0x80,0x80,0xa0, 0x0,0x80,0x80,0xa0,0x80,0xb0,0xb0,0xbb, + 0x0, 0x0, 0x0,0x80,0x80,0x80,0x80,0xb0,0x80,0x80,0x80,0xb0,0x80,0xb0,0xb8,0xbd, + 0x80,0x80,0x80,0xb8,0xa0,0xb8,0xb8,0xbe,0xa0,0xb8,0xbc,0xbf,0xbe,0xbf,0xbf,0xbf, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0xc0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x80,0x80,0xc0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x80, 0x0,0x80,0x80,0xc0, + 0x0, 0x0, 0x0,0x80, 0x0,0x80,0x80,0xc0, 0x0,0x80,0x80,0xc0,0xc0,0xc0,0xc0,0xcf, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x80, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x80, 0x0, 0x0, 0x0,0x80, 0x0,0x80,0x80,0xc0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x80, 0x0, 0x0, 0x0,0x80, 0x0,0x80,0x80,0xc0, + 0x0, 0x0, 0x0,0x80, 0x0,0x80,0xc0,0xc0,0x80,0xc0,0xc0,0xc0,0xc0,0xc0,0xd0,0xd7, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x80, 0x0, 0x0, 0x0,0x80,0x80,0x80,0xc0,0xc0, + 0x0,0x80,0x80,0xc0,0x80,0xc0,0xc0,0xc0,0x80,0xc0,0xc0,0xc0,0xc0,0xd0,0xd0,0xdb, + 0x0,0x80,0x80,0xc0,0x80,0xc0,0xc0,0xd0,0x80,0xc0,0xc0,0xd0,0xc0,0xd0,0xd8,0xdd, + 0xc0,0xc0,0xc0,0xd0,0xc0,0xd8,0xd8,0xde,0xc0,0xd8,0xdc,0xdf,0xdc,0xdf,0xdf,0xdf, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x80, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x80, 0x0, 0x0, 0x0,0x80,0x80,0xc0,0xc0,0xe0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x80, 0x0,0x80,0x80,0xc0,0x80,0xc0,0xc0,0xe0, + 0x0,0x80,0x80,0xc0,0x80,0xc0,0xc0,0xe0,0x80,0xc0,0xc0,0xe0,0xc0,0xe0,0xe0,0xe7, + 0x0, 0x0, 0x0,0x80, 0x0,0x80,0x80,0xc0, 0x0,0x80,0x80,0xc0,0x80,0xc0,0xc0,0xe0, + 0x0,0x80,0x80,0xc0,0x80,0xc0,0xc0,0xe0,0xc0,0xc0,0xc0,0xe0,0xe0,0xe0,0xe0,0xeb, + 0x80,0x80,0xc0,0xc0,0xc0,0xc0,0xc0,0xe0,0xc0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xed, + 0xc0,0xe0,0xe0,0xe0,0xe0,0xe8,0xe8,0xee,0xe0,0xe8,0xec,0xef,0xec,0xef,0xef,0xef, + 0x0, 0x0, 0x0,0x80,0x80,0x80,0x80,0xc0,0x80,0x80,0xc0,0xc0,0xc0,0xc0,0xc0,0xf0, + 0x80,0xc0,0xc0,0xc0,0xc0,0xe0,0xe0,0xf0,0xc0,0xe0,0xe0,0xf0,0xe0,0xf0,0xf0,0xf3, + 0x80,0xc0,0xc0,0xe0,0xc0,0xe0,0xe0,0xf0,0xc0,0xe0,0xe0,0xf0,0xe0,0xf0,0xf0,0xf5, + 0xe0,0xe0,0xe0,0xf0,0xf0,0xf0,0xf0,0xf6,0xf0,0xf0,0xf4,0xf7,0xf4,0xf7,0xf7,0xf7, + 0xc0,0xc0,0xc0,0xe0,0xe0,0xe0,0xe0,0xf0,0xe0,0xe0,0xe0,0xf8,0xf0,0xf8,0xf8,0xf9, + 0xe0,0xf0,0xf0,0xf8,0xf0,0xf8,0xf8,0xfa,0xf0,0xf8,0xf8,0xfb,0xf8,0xfb,0xfb,0xfb, + 0xe0,0xf0,0xf0,0xf8,0xf0,0xf8,0xfc,0xfc,0xf8,0xfc,0xfc,0xfd,0xfc,0xfd,0xfd,0xfd, + 0xf8,0xfc,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfc,0xf8, + 0xfd,0xfd,0xfd,0xfc,0xfd,0xfc,0xfc,0xf8,0xfc,0xfc,0xfc,0xf0,0xf8,0xf0,0xf0,0xe0, + 0xfb,0xfb,0xfb,0xf8,0xfb,0xf8,0xf8,0xf0,0xfa,0xf8,0xf8,0xf0,0xf8,0xf0,0xf0,0xe0, + 0xf9,0xf8,0xf8,0xf0,0xf8,0xf0,0xe0,0xe0,0xf0,0xe0,0xe0,0xe0,0xe0,0xc0,0xc0,0xc0, + 0xf7,0xf7,0xf7,0xf4,0xf7,0xf4,0xf0,0xf0,0xf6,0xf0,0xf0,0xf0,0xf0,0xe0,0xe0,0xe0, + 0xf5,0xf0,0xf0,0xe0,0xf0,0xe0,0xe0,0xc0,0xf0,0xe0,0xe0,0xc0,0xe0,0xc0,0xc0,0x80, + 0xf3,0xf0,0xf0,0xe0,0xf0,0xe0,0xe0,0xc0,0xf0,0xe0,0xe0,0xc0,0xc0,0xc0,0xc0,0x80, + 0xf0,0xe0,0xc0,0xc0,0xc0,0xc0,0x80,0x80,0xc0,0x80,0x80,0x80,0x80, 0x0, 0x0, 0x0, + 0xef,0xef,0xef,0xec,0xef,0xec,0xe8,0xe0,0xee,0xe8,0xe8,0xe0,0xe0,0xe0,0xe0,0xc0, + 0xed,0xe8,0xe0,0xe0,0xe0,0xe0,0xe0,0xc0,0xe0,0xe0,0xc0,0xc0,0xc0,0xc0,0x80,0x80, + 0xeb,0xe0,0xe0,0xe0,0xe0,0xc0,0xc0,0xc0,0xe0,0xc0,0xc0,0x80,0xc0,0x80,0x80, 0x0, + 0xe0,0xc0,0xc0,0x80,0xc0,0x80,0x80, 0x0,0xc0,0x80,0x80, 0x0,0x80, 0x0, 0x0, 0x0, + 0xe7,0xe0,0xe0,0xc0,0xe0,0xc0,0xc0,0x80,0xe0,0xc0,0xc0,0x80,0xc0,0x80,0x80, 0x0, + 0xe0,0xc0,0xc0,0x80,0xc0,0x80,0x80, 0x0,0x80,0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xe0,0xc0,0xc0,0x80,0x80, 0x0, 0x0, 0x0,0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xdf,0xdf,0xdf,0xdc,0xdf,0xdc,0xd8,0xc0,0xde,0xd8,0xd8,0xc0,0xd8,0xc0,0xc0,0xc0, + 0xdd,0xd8,0xd0,0xc0,0xd0,0xc0,0xc0,0x80,0xd0,0xc0,0xc0,0x80,0xc0,0x80,0x80, 0x0, + 0xdb,0xd0,0xd0,0xc0,0xc0,0xc0,0xc0,0x80,0xc0,0xc0,0xc0,0x80,0xc0,0x80,0x80, 0x0, + 0xc0,0xc0,0x80,0x80,0x80, 0x0, 0x0, 0x0,0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xd7,0xd0,0xc0,0xc0,0xc0,0xc0,0xc0,0x80,0xc0,0xc0,0x80, 0x0,0x80, 0x0, 0x0, 0x0, + 0xc0,0x80,0x80, 0x0,0x80, 0x0, 0x0, 0x0,0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xc0,0x80,0x80, 0x0,0x80, 0x0, 0x0, 0x0,0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xcf,0xc0,0xc0,0xc0,0xc0,0x80,0x80, 0x0,0xc0,0x80,0x80, 0x0,0x80, 0x0, 0x0, 0x0, + 0xc0,0x80,0x80, 0x0,0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xc0,0x80,0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xc0,0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xbf,0xbf,0xbf,0xbe,0xbf,0xbc,0xbc,0xa0,0xbe,0xbc,0xb8,0xa0,0xb8,0xa0,0x80,0x80, + 0xbd,0xb8,0xb0,0x80,0xb0,0x80,0x80,0x80,0xb0,0x80,0x80,0x80,0x80, 0x0, 0x0, 0x0, + 0xbb,0xb0,0xb0,0x80,0xa0,0x80,0x80, 0x0,0xa0,0x80,0x80, 0x0,0x80, 0x0, 0x0, 0x0, + 0xa0,0x80,0x80, 0x0,0x80, 0x0, 0x0, 0x0,0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xb7,0xb0,0xa0,0x80,0xa0,0x80,0x80, 0x0,0xa0,0x80,0x80, 0x0,0x80, 0x0, 0x0, 0x0, + 0x80,0x80,0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x80,0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xaf,0xa0,0xa0,0x80,0x80,0x80,0x80, 0x0,0x80,0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x9f,0x90,0x80,0x80,0x80, 0x0, 0x0, 0x0,0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x7f,0x7f,0x7f,0x7e,0x7f,0x7c,0x7c,0x70,0x7e,0x7c,0x78,0x60,0x78,0x60,0x60, 0x0, + 0x7d,0x78,0x78,0x60,0x70,0x40,0x40, 0x0,0x70,0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x7b,0x78,0x70,0x40,0x70,0x40, 0x0, 0x0,0x60, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x60, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x77,0x70,0x70, 0x0,0x60, 0x0, 0x0, 0x0,0x60, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x60, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x6f,0x60,0x60, 0x0,0x60, 0x0, 0x0, 0x0,0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x5f,0x58,0x40, 0x0,0x40, 0x0, 0x0, 0x0,0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x3f,0x3c,0x30, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 +}; + +static const UINT8 waveform60_6581[4096+4096] = +{ + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2,0x1f, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x2f, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x37, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x3b, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x3d, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x3e, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x30,0x3f, 0x0,0x30,0x38,0x3f,0x3e,0x3f,0x3f,0x3f, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x4f, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x57, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x5b, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x5d, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x5e, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x40,0x5f, 0x0,0x40,0x40,0x5f,0x5c,0x5f,0x5f,0x5f, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x67, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x40,0x6b, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x40,0x40,0x6d, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x40, 0x0, 0x0, 0x0,0x40, 0x0,0x40,0x40,0x6e, + 0x0, 0x0, 0x0,0x40, 0x0,0x60,0x60,0x6f, 0x0,0x60,0x60,0x6f,0x60,0x6f,0x6f,0x6f, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x40, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x40, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x40, 0x0, 0x0, 0x0,0x40, 0x0,0x40,0x60,0x73, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x40, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x40, 0x0, 0x0, 0x0,0x40, 0x0,0x60,0x60,0x75, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x60, 0x0, 0x0, 0x0,0x60, 0x0,0x60,0x60,0x76, + 0x0, 0x0, 0x0,0x60, 0x0,0x60,0x60,0x77, 0x0,0x70,0x70,0x77,0x70,0x77,0x77,0x77, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x60, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x60, 0x0, 0x0, 0x0,0x60, 0x0,0x60,0x60,0x79, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x60, 0x0, 0x0, 0x0,0x60, 0x0,0x70,0x70,0x7a, + 0x0, 0x0, 0x0,0x70, 0x0,0x70,0x70,0x7b,0x40,0x70,0x70,0x7b,0x78,0x7b,0x7b,0x7b, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x70, 0x0, 0x0, 0x0,0x70, 0x0,0x70,0x70,0x7c, + 0x0, 0x0, 0x0,0x70,0x40,0x70,0x70,0x7d,0x40,0x70,0x78,0x7d,0x78,0x7d,0x7d,0x7d, + 0x0,0x40,0x40,0x78,0x60,0x78,0x78,0x7e,0x60,0x78,0x78,0x7e,0x7c,0x7e,0x7e,0x7e, + 0x70,0x7c,0x7c,0x7f,0x7e,0x7f,0x7f,0x7f,0x7e,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2,0x1f, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x2f, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x37, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x3b, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x3d, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x3e, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x30,0x3f, 0x0,0x30,0x38,0x3f,0x3e,0x3f,0x3f,0x3f, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x4f, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x57, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x5b, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x5d, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x5e, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x40,0x5f, 0x0,0x40,0x40,0x5f,0x5c,0x5f,0x5f,0x5f, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x67, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x40,0x6b, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x40,0x6d, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x40, 0x0, 0x0, 0x0,0x40, 0x0,0x40,0x40,0x6e, + 0x0, 0x0, 0x0,0x40, 0x0,0x60,0x60,0x6f, 0x0,0x60,0x60,0x6f,0x60,0x6f,0x6f,0x6f, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x40, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x40, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x40, 0x0, 0x0, 0x0,0x40, 0x0,0x40,0x60,0x73, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x40, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x40, 0x0, 0x0, 0x0,0x40, 0x0,0x60,0x60,0x75, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x60, 0x0, 0x0, 0x0,0x60, 0x0,0x60,0x60,0x76, + 0x0, 0x0, 0x0,0x60, 0x0,0x60,0x60,0x77, 0x0,0x70,0x70,0x77,0x70,0x77,0x77,0x77, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x60, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x60, 0x0, 0x0, 0x0,0x60, 0x0,0x60,0x60,0x79, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x60, 0x0, 0x0, 0x0,0x60, 0x0,0x70,0x70,0x7a, + 0x0, 0x0, 0x0,0x70, 0x0,0x70,0x70,0x7b,0x40,0x70,0x70,0x7b,0x78,0x7b,0x7b,0x7b, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x70, 0x0, 0x0, 0x0,0x70, 0x0,0x70,0x70,0x7c, + 0x0, 0x0, 0x0,0x70,0x40,0x70,0x70,0x7d,0x40,0x70,0x78,0x7d,0x78,0x7d,0x7d,0x7d, + 0x0,0x40,0x40,0x78,0x60,0x78,0x78,0x7e,0x60,0x78,0x78,0x7e,0x7c,0x7e,0x7e,0x7e, + 0x70,0x7c,0x7c,0x7f,0x7c,0x7f,0x7f,0x7f,0x7e,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f +}; + +static const UINT8 waveform70_6581[4096+4096] = +{ + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x3f, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x20, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x30, 0x0, 0x0, 0x0,0x78,0x78,0x7e,0x7f,0x7f, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x3f, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x20, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,0x30, 0x0, 0x0, 0x0,0x78,0x78,0x7e,0x7f,0x7f +}; + +#endif // WAVE6581_h diff --git a/src/devices/sound/sidw8580.h b/src/devices/sound/sidw8580.h new file mode 100644 index 00000000000..e1f0c10ec8e --- /dev/null +++ b/src/devices/sound/sidw8580.h @@ -0,0 +1,1399 @@ +// license:GPL-2.0+ +// copyright-holders:Dag Lem +#pragma once + +#ifndef __SIDW8580_H__ +#define __SIDW8580_H__ + + +/* MOS-8580 R5 waveforms $30,$50,$60,$70 + * + * Created with Deadman's Raw Data to C Header converter + */ + +static const UINT8 waveform30_8580[4096] = +{ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x03,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x07,0x07,0x07,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x03, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x0e,0x0e,0x0e,0x0e,0x0f,0x0f,0x0f,0x0f,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x01,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x07,0x07,0x07, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x03,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1e,0x1e,0x1e,0x1e, + 0x1f,0x1f,0x1f,0x1f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x03, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x03,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x0e,0x0e,0x0e,0x0e,0x0f,0x0f,0x0f,0x0f, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x03,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x07,0x07,0x07,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x03, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38, + 0x38,0x38,0x38,0x38,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c, + 0x3e,0x3e,0x3f,0x3f,0x7f,0x7f,0x7f,0x7f,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x01,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x07,0x07,0x07, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x03,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0e,0x0e,0x0e,0x0e, + 0x0f,0x0f,0x0f,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x03, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x07,0x07,0x07,0x07,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x03,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1c,0x1c,0x1c,0x1c, + 0x1c,0x1c,0x1c,0x1c,0x1e,0x1e,0x1e,0x1e,0x1f,0x1f,0x1f,0x1f, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x03,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x07,0x07,0x07,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x03, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x0e,0x0e,0x0e,0x0e,0x0f,0x0f,0x1f,0x1f,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x81,0x83,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x87,0x87,0x87,0x8f, + 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0, + 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0, + 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0, + 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0, + 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0, + 0xc0,0xc0,0xc0,0xc0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0, + 0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0, + 0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0, + 0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0, + 0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0, + 0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe3,0xe3,0xe0,0xf0,0xf0,0xf0, + 0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xe0,0xe0,0xf0,0xf0, + 0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0, + 0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0, + 0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0, + 0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf1, + 0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf8,0xf0,0xf0, + 0xf0,0xf0,0xf8,0xf8,0xf8,0xf8,0xf8,0xf8,0xf8,0xf8,0xf8,0xf8, + 0xf8,0xf8,0xf8,0xf8,0xf8,0xf8,0xf8,0xf8,0xfc,0xfc,0xfc,0xfc, + 0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc, + 0xfc,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff +}; + +static const UINT8 waveform50_8580[4096+4096] = +{ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x1c,0x3f,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x5f, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x40,0x00,0x40,0x40,0x6f,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x40,0x40,0x60,0x60,0x77, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x40,0x40,0x60, + 0x00,0x40,0x40,0x60,0x40,0x70,0x70,0x7b,0x00,0x00,0x40,0x40, + 0x40,0x40,0x40,0x70,0x40,0x60,0x60,0x70,0x60,0x70,0x78,0x7c, + 0x60,0x70,0x70,0x78,0x70,0x78,0x7c,0x7e,0x78,0x7c,0x7c,0x7f, + 0x7e,0x7f,0x7f,0x7f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x80,0x80,0x80, + 0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x9f,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x80,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x80,0x80,0x80, + 0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0xaf,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x80,0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x80, + 0x00,0x00,0x00,0x00,0x00,0x80,0x80,0x80,0x00,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xb7,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xa0, + 0x80,0xa0,0xb0,0xbb,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xa0, + 0x80,0x80,0x80,0xb0,0xa0,0xb0,0xb0,0xbc,0x80,0xa0,0xa0,0xb0, + 0xb0,0xb8,0xb8,0xbe,0xb8,0xbc,0xbc,0xbf,0xbc,0xbf,0xbf,0xbf, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80, + 0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x80,0x00,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80, + 0x00,0x00,0x00,0x80,0x00,0x80,0x80,0x80,0x00,0x00,0x00,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xc0, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0xc0,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xc0, + 0x80,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xcf,0x00,0x00,0x80,0x80, + 0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0xc0,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0xc0,0xc0,0x80,0x80,0x80,0xc0, + 0x80,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xd7, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xc0,0x80,0xc0,0xc0,0xc0, + 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0, + 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xd0,0xd8,0xc0,0xc0,0xc0,0xc0, + 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xd0,0xd0,0xdc, + 0xc0,0xc0,0xc0,0xd0,0xd0,0xd8,0xd8,0xde,0xd0,0xd8,0xdc,0xdf, + 0xdc,0xdf,0xdf,0xdf,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xc0,0x80,0x80,0x80,0x80, + 0x80,0xc0,0xc0,0xc0,0x80,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0, + 0x80,0x80,0x80,0xc0,0x80,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0, + 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xe0, + 0xc0,0xc0,0xc0,0xe0,0xc0,0xe0,0xe0,0xe7,0xc0,0xc0,0xc0,0xc0, + 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xe0, + 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xe0,0xe0,0xc0,0xe0,0xe0,0xe0, + 0xe0,0xe0,0xe0,0xe8,0xc0,0xc0,0xc0,0xe0,0xe0,0xe0,0xe0,0xe0, + 0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xec,0xe0,0xe0,0xe0,0xe0, + 0xe0,0xe0,0xe8,0xee,0xe0,0xe8,0xec,0xee,0xec,0xef,0xef,0xef, + 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xe0,0xc0,0xc0,0xe0,0xe0, + 0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xf0, + 0xe0,0xe0,0xe0,0xf0,0xe0,0xf0,0xf0,0xf0,0xe0,0xe0,0xe0,0xe0, + 0xe0,0xe0,0xe0,0xf0,0xe0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf4, + 0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf4,0xf0,0xf0,0xf0,0xf6, + 0xf4,0xf7,0xf7,0xf7,0xe0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0, + 0xf0,0xf0,0xf0,0xf8,0xf0,0xf8,0xf8,0xf8,0xf0,0xf0,0xf0,0xf8, + 0xf8,0xf8,0xf8,0xf8,0xf8,0xf8,0xf8,0xfa,0xf8,0xfb,0xfb,0xfb, + 0xf8,0xf8,0xf8,0xf8,0xf8,0xfc,0xfc,0xfc,0xf8,0xfc,0xfc,0xfc, + 0xfc,0xfd,0xfd,0xfd,0xfc,0xfc,0xfc,0xfe,0xfe,0xfe,0xfe,0xfe, + 0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfc,0xfc,0xfc, + 0xfd,0xfd,0xfc,0xfc,0xfc,0xfc,0xfc,0xf8,0xfc,0xfc,0xfc,0xf8, + 0xf8,0xf8,0xf8,0xf8,0xfb,0xfb,0xfb,0xf8,0xfa,0xf8,0xf8,0xf8, + 0xf8,0xf8,0xf8,0xf8,0xf8,0xf0,0xf0,0xf0,0xf8,0xf8,0xf8,0xf0, + 0xf8,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xe0, + 0xf7,0xf7,0xf7,0xf4,0xf6,0xf0,0xf0,0xf0,0xf4,0xf0,0xf0,0xf0, + 0xf0,0xf0,0xf0,0xf0,0xf4,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xe0, + 0xf0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xf0,0xf0,0xf0,0xe0, + 0xf0,0xe0,0xe0,0xe0,0xf0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xc0, + 0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xc0,0xc0,0xe0,0xc0,0xc0,0xc0, + 0xc0,0xc0,0xc0,0xc0,0xef,0xef,0xef,0xec,0xee,0xec,0xe8,0xe0, + 0xee,0xe8,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xec,0xe0,0xe0,0xe0, + 0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xc0,0xc0,0xc0, + 0xe8,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xc0,0xe0,0xe0,0xc0,0xc0, + 0xc0,0xc0,0xc0,0xc0,0xe0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0, + 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xe7,0xe0,0xe0,0xc0, + 0xe0,0xc0,0xc0,0xc0,0xe0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0, + 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0x80, + 0xc0,0x80,0x80,0x80,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0x80, + 0xc0,0xc0,0x80,0x80,0x80,0x80,0x80,0x80,0xc0,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0xdf,0xdf,0xdf,0xdc,0xdf,0xdc,0xdc,0xd0,0xde,0xd8,0xd8,0xd0, + 0xd0,0xc0,0xc0,0xc0,0xdc,0xd0,0xd0,0xc0,0xd0,0xc0,0xc0,0xc0, + 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xd8,0xc0,0xc0,0xc0, + 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0, + 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0x80,0xc0,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0xd7,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0, + 0xc0,0xc0,0xc0,0x80,0xc0,0x80,0x80,0x80,0xc0,0xc0,0xc0,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0xc0,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x00,0x00,0xcf,0xc0,0xc0,0xc0, + 0xc0,0xc0,0xc0,0x80,0xc0,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0xc0,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0xc0,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x00,0x00,0x80,0x80,0x80,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x00,0x80,0x80,0x00,0x00, + 0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0xbf,0xbf,0xbf,0xbc,0xbf,0xbc,0xbc,0xb8, + 0xbe,0xb8,0xb8,0xb0,0xb8,0xa0,0xa0,0x80,0xbc,0xb0,0xb0,0xa0, + 0xb0,0x80,0x80,0x80,0xa0,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0xbb,0xb0,0xa0,0x80,0xa0,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xb7,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x00,0x00, + 0x00,0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0xaf,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x00,0x00,0x80,0x80,0x80,0x00,0x80,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x80,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x9f,0x80,0x80,0x80, + 0x80,0x80,0x80,0x00,0x80,0x80,0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x7f,0x7f,0x7f,0x7e,0x7f,0x7c,0x7c,0x78,0x7e,0x7c,0x78,0x70, + 0x78,0x70,0x70,0x60,0x7c,0x78,0x70,0x60,0x70,0x60,0x60,0x40, + 0x70,0x60,0x40,0x40,0x40,0x40,0x00,0x00,0x7b,0x70,0x70,0x40, + 0x60,0x40,0x40,0x00,0x60,0x40,0x40,0x00,0x00,0x00,0x00,0x00, + 0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x77,0x60,0x40,0x40,0x40,0x00,0x00,0x00, + 0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x6f,0x40,0x40,0x00, + 0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x5f,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3f,0x1c,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00 +}; + +static const UINT8 waveform60_8580[4096+4096] = +{ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1f,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x2f, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x37,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3b, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3d,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3e, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3f,0x00,0x00,0x00,0x3f, + 0x00,0x3f,0x3f,0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x4f,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x57,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x5b,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x5d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x5e,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x5f,0x00,0x00,0x00,0x5f,0x00,0x5f,0x5f,0x5f, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x67,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x6b, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x6d,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x6e, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x6f,0x00,0x00,0x00,0x6f, + 0x40,0x6f,0x6f,0x6f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x73,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x71,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x74,0x00,0x00,0x00,0x00, + 0x00,0x40,0x40,0x77,0x00,0x40,0x40,0x77,0x40,0x77,0x77,0x77, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40, + 0x00,0x00,0x00,0x40,0x00,0x40,0x40,0x79,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x40,0x00,0x40,0x40,0x78, + 0x00,0x00,0x00,0x40,0x00,0x40,0x40,0x78,0x40,0x60,0x60,0x78, + 0x60,0x7b,0x7b,0x7b,0x00,0x00,0x00,0x00,0x00,0x40,0x40,0x60, + 0x00,0x40,0x40,0x60,0x40,0x60,0x60,0x7c,0x40,0x40,0x40,0x60, + 0x40,0x70,0x70,0x7c,0x60,0x70,0x70,0x7c,0x70,0x7c,0x7d,0x7d, + 0x40,0x60,0x60,0x70,0x60,0x70,0x78,0x7e,0x70,0x78,0x78,0x7e, + 0x78,0x7e,0x7e,0x7e,0x78,0x7c,0x7c,0x7f,0x7c,0x7f,0x7f,0x7f, + 0x7c,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x8f, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x87,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x8b, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x9d,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x80,0x00,0x80,0x80,0x9e, + 0x00,0x00,0x00,0x80,0x00,0x80,0x80,0x9f,0x80,0x80,0x80,0x9f, + 0x80,0x9f,0x9f,0x9f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x87, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x80, + 0x00,0x80,0x80,0x83,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x80,0x00,0x80,0x80,0x85, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x80,0x00,0x80, + 0x80,0x80,0x80,0xae,0x00,0x80,0x80,0x80,0x80,0x80,0x80,0xaf, + 0x80,0x80,0x80,0xaf,0x80,0xaf,0xaf,0xaf,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x80,0x80,0x80,0x80,0xa3, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x80,0x80,0x00,0x00,0x00,0x80,0x00,0x80,0x80,0x80, + 0x00,0x80,0x80,0x80,0x80,0x80,0x80,0xa1,0x00,0x00,0x80,0x80, + 0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xb0, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xb0,0x80,0x80,0x80,0xb5, + 0x80,0xb7,0xb7,0xb7,0x00,0x00,0x00,0x00,0x00,0x80,0x80,0x80, + 0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xb1, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0xb8,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xb8, + 0x80,0x80,0x80,0xb8,0x80,0xb8,0xbb,0xbb,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xbc, + 0x80,0x80,0x80,0xa0,0x80,0xa0,0xa0,0xbc,0x80,0xa0,0xa0,0xbc, + 0xb0,0xbc,0xbc,0xbd,0x80,0x80,0x80,0xb0,0x80,0xb0,0xb0,0xbc, + 0xa0,0xb0,0xb0,0xbc,0xb8,0xbc,0xbe,0xbe,0xb0,0xb8,0xb8,0xbe, + 0xbc,0xbe,0xbf,0xbf,0xbc,0xbf,0xbf,0xbf,0xbf,0xbf,0xbf,0xbf, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x80, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x80, + 0x00,0x80,0x80,0x80,0x00,0x00,0x00,0x80,0x00,0x80,0x80,0x80, + 0x00,0x80,0x80,0x80,0x80,0x80,0x80,0xc7,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x80, + 0x00,0x80,0x80,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80, + 0x00,0x00,0x00,0x80,0x00,0x80,0x80,0x80,0x00,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xc3, + 0x00,0x00,0x00,0x80,0x00,0x80,0x80,0x80,0x00,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xc5,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0xc0,0x80,0x80,0x80,0xc0,0x80,0xc0,0xc0,0xce, + 0x80,0x80,0x80,0xc0,0x80,0xc0,0xc0,0xcf,0x80,0xc0,0xc0,0xcf, + 0xc0,0xcf,0xcf,0xcf,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80, + 0x00,0x00,0x00,0x80,0x00,0x80,0x80,0x80,0x00,0x00,0x00,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0xc0,0xc0,0xc3,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xc0, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xc0,0x80,0x80,0x80,0xc0, + 0x80,0xc0,0xc0,0xc1,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xc0, + 0x80,0x80,0x80,0xc0,0x80,0xc0,0xc0,0xc0,0x80,0x80,0xc0,0xc0, + 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xd0,0xc0,0xd5,0xd7,0xd7, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0xc0,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xc0, + 0x80,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xd1,0x80,0x80,0x80,0xc0, + 0x80,0xc0,0xc0,0xc0,0x80,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xd0, + 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xd0,0xc0,0xc0,0xc0,0xd8, + 0xc0,0xd8,0xd9,0xdb,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0, + 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xd8,0xc0,0xc0,0xc0,0xc0, + 0xc0,0xc0,0xc0,0xdc,0xc0,0xc0,0xc0,0xdc,0xd0,0xdc,0xdc,0xdd, + 0xc0,0xc0,0xc0,0xd0,0xc0,0xd0,0xd0,0xdc,0xc0,0xd0,0xd0,0xdc, + 0xd0,0xdc,0xde,0xde,0xd0,0xd8,0xd8,0xde,0xd8,0xde,0xde,0xdf, + 0xdc,0xdf,0xdf,0xdf,0xdf,0xdf,0xdf,0xdf,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0xc0,0xc0,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xc0, + 0x80,0x80,0x80,0xc0,0x80,0xc0,0xc0,0xc0,0x80,0x80,0x80,0xc0, + 0x80,0xc0,0xc0,0xc0,0x80,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xe3, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xc0,0x80,0x80,0x80,0xc0, + 0x80,0xc0,0xc0,0xc0,0x80,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0, + 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xe1,0xc0,0xc0,0xc0,0xc0, + 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xe0, + 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xe0,0xc0,0xe0,0xe0,0xe0, + 0xe0,0xe1,0xe7,0xe7,0x80,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0, + 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0, + 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xe0,0xe0,0xe1, + 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xe0,0xc0,0xc0,0xc0,0xe0, + 0xc0,0xe0,0xe0,0xe0,0xc0,0xc0,0xc0,0xe0,0xc0,0xe0,0xe0,0xe0, + 0xe0,0xe0,0xe0,0xe0,0xe0,0xe8,0xe8,0xeb,0xc0,0xc0,0xc0,0xc0, + 0xc0,0xc0,0xc0,0xe0,0xc0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe8, + 0xc0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe8,0xe0,0xe0,0xe0,0xec, + 0xe0,0xec,0xec,0xed,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xec, + 0xe0,0xe0,0xe0,0xec,0xe0,0xec,0xec,0xee,0xe0,0xe8,0xe8,0xee, + 0xe8,0xee,0xee,0xef,0xec,0xef,0xef,0xef,0xef,0xef,0xef,0xef, + 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0, + 0xc0,0xc0,0xc0,0xe0,0xc0,0xc0,0xc0,0xc0,0xc0,0xe0,0xe0,0xe0, + 0xc0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xf0,0xc0,0xc0,0xc0,0xe0, + 0xc0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xf0, + 0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xf0,0xe0,0xe0,0xf0,0xf0, + 0xf0,0xf0,0xf0,0xf3,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xf0, + 0xe0,0xe0,0xe0,0xf0,0xe0,0xf0,0xf0,0xf0,0xe0,0xe0,0xe0,0xf0, + 0xe0,0xf0,0xf0,0xf0,0xe0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf4,0xf5, + 0xe0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf4,0xf0,0xf0,0xf0,0xf4, + 0xf0,0xf4,0xf4,0xf6,0xf0,0xf0,0xf0,0xf4,0xf0,0xf4,0xf6,0xf7, + 0xf4,0xf6,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xe0,0xe0,0xe0,0xf0, + 0xe0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf8, + 0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf8,0xf0,0xf0,0xf8,0xf8, + 0xf8,0xf8,0xf8,0xf9,0xf0,0xf0,0xf0,0xf8,0xf0,0xf8,0xf8,0xf8, + 0xf0,0xf8,0xf8,0xf8,0xf8,0xf8,0xf8,0xfa,0xf8,0xf8,0xf8,0xf8, + 0xf8,0xf8,0xfa,0xfb,0xf8,0xfa,0xfa,0xfb,0xfb,0xfb,0xfb,0xfb, + 0xf8,0xf8,0xf8,0xf8,0xf8,0xf8,0xf8,0xfc,0xf8,0xf8,0xf8,0xfc, + 0xfc,0xfc,0xfc,0xfc,0xf8,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfd, + 0xfc,0xfc,0xfc,0xfd,0xfd,0xfd,0xfd,0xfd,0xfc,0xfc,0xfc,0xfe, + 0xfc,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe, + 0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff +}; + +static const UINT8 waveform70_8580[4096+4096] = +{ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x70, + 0x20,0x70,0x70,0x7c,0x7c,0x7e,0x7f,0x7f,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1c,0x3f, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x9f,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x80,0x80,0x80,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x80,0x80,0x80,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x80, + 0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0xc0,0xc0,0xc0,0xc0,0xc0,0xcf, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0xc0,0xc0,0xc0,0xc0,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xc0,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0, + 0x80,0x80,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0, + 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0, + 0xc0,0xc0,0xc0,0xc0,0xc0,0xe0,0xe0,0xe3,0xc0,0xc0,0xc0,0xc0, + 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0, + 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0, + 0xc0,0xe0,0xe0,0xe0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xe0, + 0xc0,0xc0,0xc0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0, + 0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xf0,0xf0,0xf0, + 0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xf0,0xe0,0xe0,0xe0,0xf0, + 0xf0,0xf0,0xf0,0xf0,0xe0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0, + 0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf8,0xf8,0xf0,0xf0,0xf0,0xf8, + 0xf8,0xf8,0xf8,0xf8,0xf8,0xf8,0xf8,0xf8,0xf8,0xf8,0xfc,0xfc, + 0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfe,0xfe,0xfe,0xfe,0xff, + 0xff,0xff,0xff,0xff +}; + + +#endif /* __SIDW8580_H__ */ diff --git a/src/devices/sound/sn76477.c b/src/devices/sound/sn76477.c new file mode 100644 index 00000000000..ea90e03b185 --- /dev/null +++ b/src/devices/sound/sn76477.c @@ -0,0 +1,2308 @@ +// license:BSD-3-Clause +// copyright-holders:Zsolt Vasvari +/***************************************************************************** + + Texas Instruments SN76477 emulator + + authors: Derrick Renaud - info + Zsolt Vasvari - software + + (see sn76477.h for details) + + Notes: + * All formulas were derived by taking measurements of a real device, + then running the data sets through the numerical analysis + application at http://zunzun.com to come up with the functions. + + Known issues/to-do's: + * VCO + * confirm value of VCO_MAX_EXT_VOLTAGE, VCO_TO_SLF_VOLTAGE_DIFF + VCO_CAP_VOLTAGE_MIN and VCO_CAP_VOLTAGE_MAX + * confirm value of VCO_MIN_DUTY_CYCLE + * get real formulas for VCO cap charging and discharging + * get real formula for VCO duty cycle + * what happens if no vco_res + * what happens if no vco_cap + + * Attack/Decay + * get real formulas for a/d cap charging and discharging + + *****************************************************************************/ + +#include "emu.h" +#include "wavwrite.h" +#include "sn76477.h" + + +/***************************************************************************** + * + * Debugging + * + *****************************************************************************/ + +#define VERBOSE 1 + +/* if 1, create a .wav file of the sound produced */ +#define LOG_WAV 0 + +/* if 1 and LOG_WAV is 1, only logs to .wav file in chip is enabled */ +#define LOG_WAV_ENABLED_ONLY 0 + +/* determines what value will be logged in the left channel of the .wav file */ +#define LOG_WAV_VALUE_L 0 /* 0 = OUT voltage */ + /* 1 = enable line */ + /* 2 = one-shot cap voltage */ + /* 3 = a/d cap voltage */ + /* 4 = slf cap voltage */ + /* 5 = vco cap voltage */ + /* 6 = noise filter cap voltage */ + +/* determines what value will be logged in the right channel of the .wav file + same values as for the left channel above */ +#define LOG_WAV_VALUE_R 3 + +#define LOG_WAV_GAIN_FACTOR 1000 + +#define LOG_WAV_FILE_NAME "sn76477_%s.wav" + + +#define LOG(n,x) do { if (VERBOSE >= (n)) logerror x; } while (0) + +#define CHECK_CHIP_NUM assert(this != NULL) +#define CHECK_CHIP_NUM_AND_BOOLEAN CHECK_CHIP_NUM; assert((state & 0x01) == state) +#define CHECK_CHIP_NUM_AND_POSITIVE CHECK_CHIP_NUM; assert(data >= 0.0) +#define CHECK_CHIP_NUM_AND_VOLTAGE CHECK_CHIP_NUM; assert((data >= 0.0) && (data <= 5.0)) +#define CHECK_CHIP_NUM_AND_CAP_VOLTAGE CHECK_CHIP_NUM; assert(((data >= 0.0) && (data <= 5.0)) || (data == SN76477_EXTERNAL_VOLTAGE_DISCONNECT)) + + + +/***************************************************************************** + * + * Test Mode + * + * in test mode, calls by the driver to + * the input setter functions are ignored. + * Interface values can be set in device_start + * to any desired test value. + * Use the space bar to enable/disable the chip. + * + *****************************************************************************/ + +#define TEST_MODE 0 + +/***************************************************************************** + * + * Constants + * + *****************************************************************************/ + +#define ONE_SHOT_CAP_VOLTAGE_MIN (0) /* the voltage at which the one-shot starts from (measured) */ +#define ONE_SHOT_CAP_VOLTAGE_MAX (2.5) /* the voltage at which the one-shot finishes (measured) */ +#define ONE_SHOT_CAP_VOLTAGE_RANGE (ONE_SHOT_CAP_VOLTAGE_MAX - ONE_SHOT_CAP_VOLTAGE_MIN) + +#define SLF_CAP_VOLTAGE_MIN (0.33) /* the voltage at the bottom peak of the SLF triangle wave (measured) */ +#define SLF_CAP_VOLTAGE_MAX (2.37) /* the voltage at the top peak of the SLF triangle wave (measured) */ +#define SLF_CAP_VOLTAGE_RANGE (SLF_CAP_VOLTAGE_MAX - SLF_CAP_VOLTAGE_MIN) + +#define VCO_MAX_EXT_VOLTAGE (2.35) /* the external voltage at which the VCO saturates and produces no output, + also used as the voltage threshold for the SLF */ +#define VCO_TO_SLF_VOLTAGE_DIFF (0.35) +#define VCO_CAP_VOLTAGE_MIN (SLF_CAP_VOLTAGE_MIN) /* the voltage at the bottom peak of the VCO triangle wave */ +#define VCO_CAP_VOLTAGE_MAX (SLF_CAP_VOLTAGE_MAX + VCO_TO_SLF_VOLTAGE_DIFF) /* the voltage at the bottom peak of the VCO triangle wave */ +#define VCO_CAP_VOLTAGE_RANGE (VCO_CAP_VOLTAGE_MAX - VCO_CAP_VOLTAGE_MIN) +#define VCO_DUTY_CYCLE_50 (5.0) /* the high voltage that produces a 50% duty cycle */ +#define VCO_MIN_DUTY_CYCLE (18) /* the smallest possible duty cycle, in % */ + +#define NOISE_MIN_CLOCK_RES RES_K(10) /* the maximum resistor value that still produces a noise (measured) */ +#define NOISE_MAX_CLOCK_RES RES_M(3.3) /* the minimum resistor value that still produces a noise (measured) */ +#define NOISE_CAP_VOLTAGE_MIN (0) /* the minimum voltage that the noise filter cap can hold (measured) */ +#define NOISE_CAP_VOLTAGE_MAX (5.0) /* the maximum voltage that the noise filter cap can hold (measured) */ +#define NOISE_CAP_VOLTAGE_RANGE (NOISE_CAP_VOLTAGE_MAX - NOISE_CAP_VOLTAGE_MIN) +#define NOISE_CAP_HIGH_THRESHOLD (3.35) /* the voltage at which the filtered noise bit goes to 0 (measured) */ +#define NOISE_CAP_LOW_THRESHOLD (0.74) /* the voltage at which the filtered noise bit goes to 1 (measured) */ + +#define AD_CAP_VOLTAGE_MIN (0) /* the minimum voltage the attack/decay cap can hold (measured) */ +#define AD_CAP_VOLTAGE_MAX (4.44) /* the minimum voltage the attack/decay cap can hold (measured) */ +#define AD_CAP_VOLTAGE_RANGE (AD_CAP_VOLTAGE_MAX - AD_CAP_VOLTAGE_MIN) + +#define OUT_CENTER_LEVEL_VOLTAGE (2.57) /* the voltage that gets outputted when the volumne is 0 (measured) */ +#define OUT_HIGH_CLIP_THRESHOLD (3.51) /* the maximum voltage that can be put out (measured) */ +#define OUT_LOW_CLIP_THRESHOLD (0.715) /* the minimum voltage that can be put out (measured) */ + +/* gain factors for OUT voltage in 0.1V increments (measured) */ +static const double out_pos_gain[] = +{ + 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.01, /* 0.0 - 0.9V */ + 0.03, 0.11, 0.15, 0.19, 0.21, 0.23, 0.26, 0.29, 0.31, 0.33, /* 1.0 - 1.9V */ + 0.36, 0.38, 0.41, 0.43, 0.46, 0.49, 0.52, 0.54, 0.57, 0.60, /* 2.0 - 2.9V */ + 0.62, 0.65, 0.68, 0.70, 0.73, 0.76, 0.80, 0.82, 0.84, 0.87, /* 3.0 - 3.9V */ + 0.90, 0.93, 0.96, 0.98, 1.00 /* 4.0 - 4.4V */ +}; + +static const double out_neg_gain[] = +{ + 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, -0.01, /* 0.0 - 0.9V */ + -0.02, -0.09, -0.13, -0.15, -0.17, -0.19, -0.22, -0.24, -0.26, -0.28, /* 1.0 - 1.9V */ + -0.30, -0.32, -0.34, -0.37, -0.39, -0.41, -0.44, -0.46, -0.48, -0.51, /* 2.0 - 2.9V */ + -0.53, -0.56, -0.58, -0.60, -0.62, -0.65, -0.67, -0.69, -0.72, -0.74, /* 3.0 - 3.9V */ + -0.76, -0.78, -0.81, -0.84, -0.85 /* 4.0 - 4.4V */ +}; + + +const device_type SN76477 = &device_creator; + +sn76477_device::sn76477_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, SN76477, "SN76477", tag, owner, clock, "sn76477", __FILE__), + device_sound_interface(mconfig, *this), + m_enable(0), + m_envelope_mode(0), + m_vco_mode(0), + m_mixer_mode(0), + m_one_shot_res(0), + m_one_shot_cap(0), + m_one_shot_cap_voltage_ext(0), + m_slf_res(0), + m_slf_cap(0), + m_slf_cap_voltage_ext(0), + m_vco_voltage(0), + m_vco_res(0), + m_vco_cap(0), + m_vco_cap_voltage_ext(0), + m_noise_clock_res(0), + m_noise_clock_ext(0), + m_noise_clock(0), + m_noise_filter_res(0), + m_noise_filter_cap(0), + m_noise_filter_cap_voltage_ext(0), + m_attack_res(0), + m_decay_res(0), + m_attack_decay_cap(0), + m_attack_decay_cap_voltage_ext(0), + m_amplitude_res(0), + m_feedback_res(0), + m_pitch_voltage(0), + m_one_shot_cap_voltage(0), + m_one_shot_running_ff(0), + m_slf_cap_voltage(0), + m_slf_out_ff(0), + m_vco_cap_voltage(0), + m_vco_out_ff(0), + m_vco_alt_pos_edge_ff(0), + m_noise_filter_cap_voltage(0), + m_real_noise_bit_ff(0), + m_filtered_noise_bit_ff(0), + m_noise_gen_count(0), + m_attack_decay_cap_voltage(0), + m_rng(0), + m_mixer_a(0), + m_mixer_b(0), + m_mixer_c(0), + m_envelope_1(0), + m_envelope_2(0), + m_channel(NULL), + m_our_sample_rate(0), + m_file(NULL) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void sn76477_device::device_start() +{ + m_channel = machine().sound().stream_alloc(*this, 0, 1, machine().sample_rate()); + + if (clock() > 0) + { + m_our_sample_rate = clock(); + } + else + { + m_our_sample_rate = machine().sample_rate(); + } + + intialize_noise(); + + // set up mixer and envelope modes, based on interface values + _SN76477_mixer_a_w(m_mixer_a); + _SN76477_mixer_b_w(m_mixer_b); + _SN76477_mixer_c_w(m_mixer_c); + _SN76477_envelope_1_w(m_envelope_1); + _SN76477_envelope_2_w(m_envelope_2); + + m_one_shot_cap_voltage = ONE_SHOT_CAP_VOLTAGE_MIN; + m_slf_cap_voltage = SLF_CAP_VOLTAGE_MIN; + m_vco_cap_voltage = VCO_CAP_VOLTAGE_MIN; + m_noise_filter_cap_voltage = NOISE_CAP_VOLTAGE_MIN; + m_attack_decay_cap_voltage = AD_CAP_VOLTAGE_MIN; + + state_save_register(); + + log_complete_state(); + + if (LOG_WAV) + open_wav_file(); +} + +//------------------------------------------------- +// device_stop - device-specific stop +//------------------------------------------------- + +void sn76477_device::device_stop() +{ + if (LOG_WAV) + close_wav_file(); +} + + +/***************************************************************************** + * + * Max/min + * + *****************************************************************************/ + +#undef max +#undef min + +INLINE double max(double a, double b) +{ + return (a > b) ? a : b; +} + + +INLINE double min(double a, double b) +{ + return (a < b) ? a : b; +} + + + +/***************************************************************************** + * + * Functions for computing frequencies, voltages and similar values based + * on the hardware itself. Do NOT put anything emulation specific here, + * such as calculations based on sample_rate. + * + *****************************************************************************/ + +double sn76477_device::compute_one_shot_cap_charging_rate() /* in V/sec */ +{ + /* this formula was derived using the data points below + + Res (kohms) Cap (uF) Time (millisec) + 47 0.33 11.84 + 47 1.0 36.2 + 47 1.5 52.1 + 47 2.0 76.4 + 100 0.33 24.4 + 100 1.0 75.2 + 100 1.5 108.5 + 100 2.0 158.4 + */ + + double ret = 0; + + if ((m_one_shot_res > 0) && (m_one_shot_cap > 0)) + { + ret = ONE_SHOT_CAP_VOLTAGE_RANGE / (0.8024 * m_one_shot_res * m_one_shot_cap + 0.002079); + } + else if (m_one_shot_cap > 0) + { + /* if no resistor, there is no current to charge the cap, + effectively making the one-shot time effectively infinite */ + ret = +1e-30; + } + else if (m_one_shot_res > 0) + { + /* if no cap, the voltage changes extremely fast, + effectively making the one-shot time 0 */ + ret = +1e+30; + } + + return ret; +} + + +double sn76477_device::compute_one_shot_cap_discharging_rate() /* in V/sec */ +{ + /* this formula was derived using the data points below + + Cap (uF) Time (microsec) + 0.33 300 + 1.0 850 + 1.5 1300 + 2.0 1900 + */ + + double ret = 0; + + if ((m_one_shot_res > 0) && (m_one_shot_cap > 0)) + { + ret = ONE_SHOT_CAP_VOLTAGE_RANGE / (854.7 * m_one_shot_cap + 0.00001795); + } + else if (m_one_shot_res > 0) + { + /* if no cap, the voltage changes extremely fast, + effectively making the one-shot time 0 */ + ret = +1e+30; + } + + return ret; +} + + +double sn76477_device::compute_slf_cap_charging_rate() /* in V/sec */ +{ + /* this formula was derived using the data points below + + Res (kohms) Cap (uF) Time (millisec) + 47 0.47 14.3 + 120 0.47 35.6 + 200 0.47 59.2 + 47 1.00 28.6 + 120 1.00 71.6 + 200 1.00 119.0 + */ + double ret = 0; + + if ((m_slf_res > 0) && (m_slf_cap > 0)) + { + ret = SLF_CAP_VOLTAGE_RANGE / (0.5885 * m_slf_res * m_slf_cap + 0.001300); + } + + return ret; +} + + +double sn76477_device::compute_slf_cap_discharging_rate() /* in V/sec */ +{ + /* this formula was derived using the data points below + + Res (kohms) Cap (uF) Time (millisec) + 47 0.47 13.32 + 120 0.47 32.92 + 200 0.47 54.4 + 47 1.00 26.68 + 120 1.00 66.2 + 200 1.00 109.6 + */ + double ret = 0; + + if ((m_slf_res > 0) && (m_slf_cap > 0)) + { + ret = SLF_CAP_VOLTAGE_RANGE / (0.5413 * m_slf_res * m_slf_cap + 0.001343); + } + + return ret; +} + + +double sn76477_device::compute_vco_cap_charging_discharging_rate() /* in V/sec */ +{ + double ret = 0; + + if ((m_vco_res > 0) && (m_vco_cap > 0)) + { + ret = 0.64 * 2 * VCO_CAP_VOLTAGE_RANGE / (m_vco_res * m_vco_cap); + } + + return ret; +} + + +double sn76477_device::compute_vco_duty_cycle() /* no measure, just a number */ +{ + double ret = 0.5; /* 50% */ + + if ((m_vco_voltage > 0) && (m_pitch_voltage != VCO_DUTY_CYCLE_50)) + { + ret = max(0.5 * (m_pitch_voltage / m_vco_voltage), (VCO_MIN_DUTY_CYCLE / 100.0)); + + ret = min(ret, 1); + } + + return ret; +} + + +UINT32 sn76477_device::compute_noise_gen_freq() /* in Hz */ +{ + /* this formula was derived using the data points below + + Res (ohms) Freq (Hz) + 10k 97493 + 12k 83333 + 15k 68493 + 22k 49164 + 27k 41166 + 33k 34449 + 36k 31969 + 47k 25126 + 56k 21322 + 68k 17721.5 + 82k 15089.2 + 100k 12712.0 + 150k 8746.4 + 220k 6122.4 + 270k 5101.5 + 330k 4217.2 + 390k 3614.5 + 470k 3081.7 + 680k 2132.7 + 820k 1801.8 + 1M 1459.9 + 2.2M 705.13 + 3.3M 487.59 + */ + + UINT32 ret = 0; + + if ((m_noise_clock_res >= NOISE_MIN_CLOCK_RES) && + (m_noise_clock_res <= NOISE_MAX_CLOCK_RES)) + { + ret = 339100000 * pow(m_noise_clock_res, -0.8849); + } + + return ret; +} + + +double sn76477_device::compute_noise_filter_cap_charging_rate() /* in V/sec */ +{ + /* this formula was derived using the data points below + + R*C Time (sec) + .000068 .0000184 + .0001496 .0000378 + .0002244 .0000548 + .0003196 .000077 + .0015 .000248 + .0033 .000540 + .00495 .000792 + .00705 .001096 + */ + + double ret = 0; + + if ((m_noise_filter_res > 0) && (m_noise_filter_cap > 0)) + { + ret = NOISE_CAP_VOLTAGE_RANGE / (0.1571 * m_noise_filter_res * m_noise_filter_cap + 0.00001430); + } + else if (m_noise_filter_cap > 0) + { + /* if no resistor, there is no current to charge the cap, + effectively making the filter's output constants */ + ret = +1e-30; + } + else if (m_noise_filter_res > 0) + { + /* if no cap, the voltage changes extremely fast, + effectively disabling the filter */ + ret = +1e+30; + } + + return ret; +} + + +double sn76477_device::compute_noise_filter_cap_discharging_rate() /* in V/sec */ +{ + /* this formula was derived using the data points below + + R*C Time (sec) + .000068 .000016 + .0001496 .0000322 + .0002244 .0000472 + .0003196 .0000654 + .0015 .000219 + .0033 .000468 + .00495 .000676 + .00705 .000948 + */ + + double ret = 0; + + if ((m_noise_filter_res > 0) && (m_noise_filter_cap > 0)) + { + ret = NOISE_CAP_VOLTAGE_RANGE / (0.1331 * m_noise_filter_res * m_noise_filter_cap + 0.00001734); + } + else if (m_noise_filter_cap > 0) + { + /* if no resistor, there is no current to charge the cap, + effectively making the filter's output constants */ + ret = +1e-30; + } + else if (m_noise_filter_res > 0) + { + /* if no cap, the voltage changes extremely fast, + effectively disabling the filter */ + ret = +1e+30; + } + + return ret; +} + + +double sn76477_device::compute_attack_decay_cap_charging_rate() /* in V/sec */ +{ + double ret = 0; + + if ((m_attack_res > 0) && (m_attack_decay_cap > 0)) + { + ret = AD_CAP_VOLTAGE_RANGE / (m_attack_res * m_attack_decay_cap); + } + else if (m_attack_decay_cap > 0) + { + /* if no resistor, there is no current to charge the cap, + effectively making the attack time infinite */ + ret = +1e-30; + } + else if (m_attack_res > 0) + { + /* if no cap, the voltage changes extremely fast, + effectively making the attack time 0 */ + ret = +1e+30; + } + + return ret; +} + + +double sn76477_device::compute_attack_decay_cap_discharging_rate() /* in V/sec */ +{ + double ret = 0; + + if ((m_decay_res > 0) && (m_attack_decay_cap > 0)) + { + ret = AD_CAP_VOLTAGE_RANGE / (m_decay_res * m_attack_decay_cap); + } + else if (m_attack_decay_cap > 0) + { + /* if no resistor, there is no current to charge the cap, + effectively making the decay time infinite */ + ret = +1e-30; + } + else if (m_attack_res > 0) + { + /* if no cap, the voltage changes extremely fast, + effectively making the decay time 0 */ + ret = +1e+30; + } + + return ret; +} + + +double sn76477_device::compute_center_to_peak_voltage_out() +{ + /* this formula was derived using the data points below + + Ra (kohms) Rf (kohms) Voltage + 150 47 1.28 + 200 47 0.96 + 47 22 1.8 + 100 22 0.87 + 150 22 0.6 + 200 22 0.45 + 47 10 0.81 + 100 10 0.4 + 150 10 0.27 + */ + + double ret = 0; + + if (m_amplitude_res > 0) + { + ret = 3.818 * (m_feedback_res / m_amplitude_res) + 0.03; + } + + return ret; +} + + + +/***************************************************************************** + * + * Logging functions + * + *****************************************************************************/ + +void sn76477_device::log_enable_line() +{ + static const char *const desc[] = + { + "Enabled", "Inhibited" + }; + + LOG(1, ("SN76477 '%s': Enable line (9): %d [%s]\n", tag(), m_enable, desc[m_enable])); +} + + +void sn76477_device::log_mixer_mode() +{ + static const char *const desc[] = + { + "VCO", "SLF", "Noise", "VCO/Noise", + "SLF/Noise", "SLF/VCO/Noise", "SLF/VCO", "Inhibit" + }; + + LOG(1, ("SN76477 '%s': Mixer mode (25-27): %d [%s]\n", tag(), m_mixer_mode, desc[m_mixer_mode])); +} + + +void sn76477_device::log_envelope_mode() +{ + static const char *const desc[] = + { + "VCO", "One-Shot", "Mixer Only", "VCO with Alternating Polarity" + }; + + LOG(1, ("SN76477 '%s': Envelope mode (1,28): %d [%s]\n", tag(), m_envelope_mode, desc[m_envelope_mode])); +} + + +void sn76477_device::log_vco_mode() +{ + static const char *const desc[] = + { + "External (Pin 16)", "Internal (SLF)" + }; + + LOG(1, ("SN76477 '%s': VCO mode (22): %d [%s]\n", tag(), m_vco_mode, desc[m_vco_mode])); +} + + +void sn76477_device::log_one_shot_time() +{ + if (!m_one_shot_cap_voltage_ext) + { + if (compute_one_shot_cap_charging_rate() > 0) + { + LOG(1, ("SN76477 '%s': One-shot time (23,24): %.4f sec\n", tag(), ONE_SHOT_CAP_VOLTAGE_RANGE * (1 / compute_one_shot_cap_charging_rate()))); + } + else + { + LOG(1, ("SN76477 '%s': One-shot time (23,24): N/A\n", tag())); + } + } + else + { + LOG(1, ("SN76477 '%s': One-shot time (23,24): External (cap = %.2fV)\n", tag(), m_one_shot_cap_voltage)); + } +} + + +void sn76477_device::log_slf_freq() +{ + if (!m_slf_cap_voltage_ext) + { + if (compute_slf_cap_charging_rate() > 0) + { + double charging_time = (1 / compute_slf_cap_charging_rate()) * SLF_CAP_VOLTAGE_RANGE; + double discharging_time = (1 / compute_slf_cap_discharging_rate()) * SLF_CAP_VOLTAGE_RANGE; + + LOG(1, ("SN76477 '%s': SLF frequency (20,21): %.2f Hz\n", tag(), 1 / (charging_time + discharging_time))); + } + else + { + LOG(1, ("SN76477 '%s': SLF frequency (20,21): N/A\n", tag())); + } + } + else + { + LOG(1, ("SN76477 '%s': SLF frequency (20,21): External (cap = %.2fV)\n", tag(), m_slf_cap_voltage)); + } +} + + +void sn76477_device::log_vco_pitch_voltage() +{ + LOG(1, ("SN76477 '%s': VCO pitch voltage (19): %.2fV\n", tag(), m_pitch_voltage)); +} + + +void sn76477_device::log_vco_duty_cycle() +{ + LOG(1, ("SN76477 '%s': VCO duty cycle (16,19): %.0f%%\n", tag(), compute_vco_duty_cycle() * 100.0)); +} + + +void sn76477_device::log_vco_freq() +{ + if (!m_vco_cap_voltage_ext) + { + if (compute_vco_cap_charging_discharging_rate() > 0) + { + double min_freq = compute_vco_cap_charging_discharging_rate() / (2 * VCO_CAP_VOLTAGE_RANGE); + double max_freq = compute_vco_cap_charging_discharging_rate() / (2 * VCO_TO_SLF_VOLTAGE_DIFF); + + LOG(1, ("SN76477 '%s': VCO frequency (17,18): %.2f Hz - %.1f Hz\n", tag(), min_freq, max_freq)); + } + else + { + LOG(1, ("SN76477 '%s': VCO frequency (17,18): N/A\n", tag())); + } + } + else + { + LOG(1, ("SN76477 '%s': VCO frequency (17,18): External (cap = %.2fV)\n", tag(), m_vco_cap_voltage)); + } +} + + +void sn76477_device::log_vco_ext_voltage() +{ + if (m_vco_voltage <= VCO_MAX_EXT_VOLTAGE) + { + double min_freq = compute_vco_cap_charging_discharging_rate() / (2 * VCO_CAP_VOLTAGE_RANGE); + double max_freq = compute_vco_cap_charging_discharging_rate() / (2 * VCO_TO_SLF_VOLTAGE_DIFF); + + LOG(1, ("SN76477 '%s': VCO ext. voltage (16): %.2fV (%.2f Hz)\n", tag(), + m_vco_voltage, + min_freq + ((max_freq - min_freq) * m_vco_voltage / VCO_MAX_EXT_VOLTAGE))); + } + else + { + LOG(1, ("SN76477 '%s': VCO ext. voltage (16): %.2fV (saturated, no output)\n", tag(), m_vco_voltage)); + } +} + + +void sn76477_device::log_noise_gen_freq() +{ + if (m_noise_clock_ext) + { + LOG(1, ("SN76477 '%s': Noise gen frequency (4): External\n", tag())); + } + else + { + if (compute_noise_gen_freq() > 0) + { + LOG(1, ("SN76477 '%s': Noise gen frequency (4): %d Hz\n", tag(), compute_noise_gen_freq())); + } + else + { + LOG(1, ("SN76477 '%s': Noise gen frequency (4): N/A\n", tag())); + } + } +} + + +void sn76477_device::log_noise_filter_freq() +{ + if (!m_noise_filter_cap_voltage_ext) + { + double charging_rate = compute_noise_filter_cap_charging_rate(); + + if (charging_rate > 0) + { + if (charging_rate < 1000000.0) + { + double charging_time = (1 / charging_rate) * NOISE_CAP_VOLTAGE_RANGE; + double discharging_time = (1 / charging_rate) * NOISE_CAP_VOLTAGE_RANGE; + + LOG(1, ("SN76477 '%s': Noise filter frequency (5,6): %.0f Hz\n", tag(), 1 / (charging_time + discharging_time))); + } + else + { + LOG(1, ("SN76477 '%s': Noise filter frequency (5,6): Very Large (Filtering Disabled)\n", tag())); + } + } + else + { + LOG(1, ("SN76477 '%s': Noise filter frequency (5,6): N/A\n", tag())); + } + } + else + { + LOG(1, ("SN76477 '%s': Noise filter frequency (5,6): External (cap = %.2fV)\n", tag(), m_noise_filter_cap)); + } +} + + +void sn76477_device::log_attack_time() +{ + if (!m_attack_decay_cap_voltage_ext) + { + if (compute_attack_decay_cap_charging_rate() > 0) + { + LOG(1, ("SN76477 '%s': Attack time (8,10): %.4f sec\n", tag(), AD_CAP_VOLTAGE_RANGE * (1 / compute_attack_decay_cap_charging_rate()))); + } + else + { + LOG(1, ("SN76477 '%s': Attack time (8,10): N/A\n", tag())); + } + } + else + { + LOG(1, ("SN76477 '%s': Attack time (8,10): External (cap = %.2fV)\n", tag(), m_attack_decay_cap_voltage)); + } +} + + +void sn76477_device::log_decay_time() +{ + if (!m_attack_decay_cap_voltage_ext) + { + if (compute_attack_decay_cap_discharging_rate() > 0) + { + LOG(1, ("SN76477 '%s': Decay time (7,8): %.4f sec\n", tag(), AD_CAP_VOLTAGE_RANGE * (1 / compute_attack_decay_cap_discharging_rate()))); + } + else + { + LOG(1, ("SN76477 '%s': Decay time (8,10): N/A\n", tag())); + } + } + else + { + LOG(1, ("SN76477 '%s': Decay time (7, 8): External (cap = %.2fV)\n", tag(), m_attack_decay_cap_voltage)); + } +} + + +void sn76477_device::log_voltage_out() +{ + LOG(1, ("SN76477 '%s': Voltage OUT range (11,12): %.2fV - %.2fV (clips above %.2fV)\n", + tag(), + OUT_CENTER_LEVEL_VOLTAGE + compute_center_to_peak_voltage_out() * out_neg_gain[(int)(AD_CAP_VOLTAGE_MAX * 10)], + OUT_CENTER_LEVEL_VOLTAGE + compute_center_to_peak_voltage_out() * out_pos_gain[(int)(AD_CAP_VOLTAGE_MAX * 10)], + OUT_HIGH_CLIP_THRESHOLD)); +} + + +void sn76477_device::log_complete_state() +{ + log_enable_line(); + log_mixer_mode(); + log_envelope_mode(); + log_vco_mode(); + log_one_shot_time(); + log_slf_freq(); + log_vco_freq(); + log_vco_ext_voltage(); + log_vco_pitch_voltage(); + log_vco_duty_cycle(); + log_noise_filter_freq(); + log_noise_gen_freq(); + log_attack_time(); + log_decay_time(); + log_voltage_out(); +} + + + +/***************************************************************************** + * + * .WAV file functions + * + *****************************************************************************/ + + +void sn76477_device::open_wav_file() +{ + char wav_file_name[30]; + + sprintf(wav_file_name, LOG_WAV_FILE_NAME, tag()); + m_file = wav_open(wav_file_name, m_our_sample_rate, 2); + + LOG(1, ("SN76477 '%s': Logging output: %s\n", tag(), wav_file_name)); +} + + +void sn76477_device::close_wav_file() +{ + wav_close(m_file); +} + + +void sn76477_device::add_wav_data(INT16 data_l, INT16 data_r) +{ + wav_add_data_16lr(m_file, &data_l, &data_r, 1); +} + + + +/***************************************************************************** + * + * Noise generator + * + *****************************************************************************/ + +void sn76477_device::intialize_noise() +{ + m_rng = 0; +} + + +inline UINT32 sn76477_device::generate_next_real_noise_bit() +{ + UINT32 out = ((m_rng >> 28) & 1) ^ ((m_rng >> 0) & 1); + + /* if bits 0-4 and 28 are all zero then force the output to 1 */ + if ((m_rng & 0x1000001f) == 0) + { + out = 1; + } + + m_rng = (m_rng >> 1) | (out << 30); + + return out; +} + + + +/***************************************************************************** + * + * Set enable input + * + *****************************************************************************/ + +void sn76477_device::_SN76477_enable_w(UINT32 data) +{ + m_enable = data; + + /* if falling edge */ + if (!m_enable) + { + /* start the attack phase */ + m_attack_decay_cap_voltage = AD_CAP_VOLTAGE_MIN; + + /* one-shot runs regardless of envelope mode */ + m_one_shot_running_ff = 1; + } +} + + +void sn76477_device::SN76477_test_enable_w(UINT32 data) +{ + if (data != m_enable) + { + m_channel->update(); + + _SN76477_enable_w(data); + + log_enable_line(); + } +} + + +WRITE_LINE_MEMBER( sn76477_device::enable_w ) +{ +#if TEST_MODE == 0 + CHECK_CHIP_NUM_AND_BOOLEAN; + + SN76477_test_enable_w(state); +#endif +} + + + +/***************************************************************************** + * + * Set mixer select inputs + * + *****************************************************************************/ + +void sn76477_device::_SN76477_mixer_a_w(UINT32 data) +{ + m_mixer_mode = (m_mixer_mode & ~0x01) | (data << 0); +} + + +WRITE_LINE_MEMBER( sn76477_device::mixer_a_w ) +{ +#if TEST_MODE == 0 + CHECK_CHIP_NUM_AND_BOOLEAN; + + if (state != ((m_mixer_mode >> 0) & 0x01)) + { + m_channel->update(); + + _SN76477_mixer_a_w(state); + + log_mixer_mode(); + } +#endif +} + + +void sn76477_device::_SN76477_mixer_b_w(UINT32 data) +{ + m_mixer_mode = (m_mixer_mode & ~0x02) | (data << 1); +} + + +WRITE_LINE_MEMBER( sn76477_device::mixer_b_w ) +{ +#if TEST_MODE == 0 + CHECK_CHIP_NUM_AND_BOOLEAN; + + if (state != ((m_mixer_mode >> 1) & 0x01)) + { + m_channel->update(); + + _SN76477_mixer_b_w(state); + + log_mixer_mode(); + } +#endif +} + + +void sn76477_device::_SN76477_mixer_c_w(UINT32 data) +{ + m_mixer_mode = (m_mixer_mode & ~0x04) | (data << 2); +} + + +WRITE_LINE_MEMBER( sn76477_device::mixer_c_w ) +{ +#if TEST_MODE == 0 + CHECK_CHIP_NUM_AND_BOOLEAN; + + if (state != ((m_mixer_mode >> 2) & 0x01)) + { + m_channel->update(); + + _SN76477_mixer_c_w(state); + + log_mixer_mode(); + } +#endif +} + + + +/***************************************************************************** + * + * Set envelope select inputs + * + *****************************************************************************/ + +void sn76477_device::_SN76477_envelope_1_w(UINT32 data) +{ + m_envelope_mode = (m_envelope_mode & ~0x01) | (data << 0); +} + + +WRITE_LINE_MEMBER( sn76477_device::envelope_1_w ) +{ +#if TEST_MODE == 0 + CHECK_CHIP_NUM_AND_BOOLEAN; + + if (state != ((m_envelope_mode >> 0) & 0x01)) + { + m_channel->update(); + + _SN76477_envelope_1_w(state); + + log_envelope_mode(); + } +#endif +} + + +void sn76477_device::_SN76477_envelope_2_w(UINT32 data) +{ + m_envelope_mode = (m_envelope_mode & ~0x02) | (data << 1); +} + + +WRITE_LINE_MEMBER( sn76477_device::envelope_2_w ) +{ +#if TEST_MODE == 0 + CHECK_CHIP_NUM_AND_BOOLEAN; + + if (state != ((m_envelope_mode >> 1) & 0x01)) + { + m_channel->update(); + + _SN76477_envelope_2_w(state); + + log_envelope_mode(); + } +#endif +} + + + +/***************************************************************************** + * + * Set VCO select input + * + *****************************************************************************/ + +void sn76477_device::_SN76477_vco_w(UINT32 data) +{ + m_vco_mode = data; +} + + +WRITE_LINE_MEMBER( sn76477_device::vco_w ) +{ +#if TEST_MODE == 0 + CHECK_CHIP_NUM_AND_BOOLEAN; + + if (state != m_vco_mode) + { + m_channel->update(); + + _SN76477_vco_w(state); + + log_vco_mode(); + } +#endif +} + + + +/***************************************************************************** + * + * Set one-shot resistor + * + *****************************************************************************/ + +void sn76477_device::_SN76477_one_shot_res_w(double data) +{ + m_one_shot_res = data; +} + + +void sn76477_device::one_shot_res_w(double data) +{ +#if TEST_MODE == 0 + CHECK_CHIP_NUM_AND_POSITIVE; + + if (data != m_one_shot_res) + { + m_channel->update(); + + _SN76477_one_shot_res_w(data); + + log_one_shot_time(); + } +#endif +} + + + +/***************************************************************************** + * + * Set one-shot capacitor + * + *****************************************************************************/ + +void sn76477_device::_SN76477_one_shot_cap_w(double data) +{ + m_one_shot_cap = data; +} + + +void sn76477_device::one_shot_cap_w(double data) +{ +#if TEST_MODE == 0 + CHECK_CHIP_NUM_AND_POSITIVE; + + if (data != m_one_shot_cap) + { + m_channel->update(); + + _SN76477_one_shot_cap_w(data); + + log_one_shot_time(); + } +#endif +} + + + +/***************************************************************************** + * + * Set the voltage on the one-shot capacitor + * + *****************************************************************************/ + +void sn76477_device::one_shot_cap_voltage_w(double data) +{ +#if TEST_MODE == 0 + CHECK_CHIP_NUM_AND_CAP_VOLTAGE; + + if (data == SN76477_EXTERNAL_VOLTAGE_DISCONNECT) + { + /* switch to internal, if not already */ + if (m_one_shot_cap_voltage_ext) + { + m_channel->update(); + + m_one_shot_cap_voltage_ext = 0; + + log_one_shot_time(); + } + } + else + { + /* set the voltage on the cap */ + if (!m_one_shot_cap_voltage_ext || (data != m_one_shot_cap_voltage)) + { + m_channel->update(); + + m_one_shot_cap_voltage_ext = 1; + m_one_shot_cap_voltage = data; + + log_one_shot_time(); + } + } +#endif +} + + + +/***************************************************************************** + * + * Set SLF resistor + * + *****************************************************************************/ + +void sn76477_device::_SN76477_slf_res_w(double data) +{ + m_slf_res = data; +} + + +void sn76477_device::slf_res_w(double data) +{ +#if TEST_MODE == 0 + CHECK_CHIP_NUM_AND_POSITIVE; + + if (data != m_slf_res) + { + m_channel->update(); + + _SN76477_slf_res_w(data); + + log_slf_freq(); + } +#endif +} + + + +/***************************************************************************** + * + * Set SLF capacitor + * + *****************************************************************************/ + +void sn76477_device::_SN76477_slf_cap_w(double data) +{ + m_slf_cap = data; +} + + +void sn76477_device::slf_cap_w(double data) +{ +#if TEST_MODE == 0 + CHECK_CHIP_NUM_AND_POSITIVE; + + if (data != m_slf_cap) + { + m_channel->update(); + + _SN76477_slf_cap_w(data); + + log_slf_freq(); + } +#endif +} + + + +/***************************************************************************** + * + * Set the voltage on the SLF capacitor + * + * This is an alternate way of controlling the VCO as described in the book + * + *****************************************************************************/ + +void sn76477_device::slf_cap_voltage_w(double data) +{ +#if TEST_MODE == 0 + CHECK_CHIP_NUM_AND_CAP_VOLTAGE; + + if (data == SN76477_EXTERNAL_VOLTAGE_DISCONNECT) + { + /* switch to internal, if not already */ + if (m_slf_cap_voltage_ext) + { + m_channel->update(); + + m_slf_cap_voltage_ext = 0; + + log_slf_freq(); + } + } + else + { + /* set the voltage on the cap */ + if (!m_slf_cap_voltage_ext || (data != m_slf_cap_voltage)) + { + m_channel->update(); + + m_slf_cap_voltage_ext = 1; + m_slf_cap_voltage = data; + + log_slf_freq(); + } + } +#endif +} + + + +/***************************************************************************** + * + * Set VCO resistor + * + *****************************************************************************/ + +void sn76477_device::_SN76477_vco_res_w(double data) +{ + m_vco_res = data; +} + + +void sn76477_device::vco_res_w(double data) +{ +#if TEST_MODE == 0 + CHECK_CHIP_NUM_AND_POSITIVE; + + if (data != m_vco_res) + { + m_channel->update(); + + _SN76477_vco_res_w(data); + + log_vco_freq(); + } +#endif +} + + + +/***************************************************************************** + * + * Set VCO capacitor + * + *****************************************************************************/ + +void sn76477_device::_SN76477_vco_cap_w(double data) +{ + m_vco_cap = data; +} + + +void sn76477_device::vco_cap_w(double data) +{ +#if TEST_MODE == 0 + CHECK_CHIP_NUM_AND_POSITIVE; + + if (data != m_vco_cap) + { + m_channel->update(); + + _SN76477_vco_cap_w(data); + + log_vco_freq(); + } +#endif +} + + + +/***************************************************************************** + * + * Set the voltage on the VCO capacitor + * + *****************************************************************************/ + +void sn76477_device::vco_cap_voltage_w(double data) +{ +#if TEST_MODE == 0 + CHECK_CHIP_NUM_AND_CAP_VOLTAGE; + + if (data == SN76477_EXTERNAL_VOLTAGE_DISCONNECT) + { + /* switch to internal, if not already */ + if (m_vco_cap_voltage_ext) + { + m_channel->update(); + + m_vco_cap_voltage_ext = 0; + + log_vco_freq(); + } + } + else + { + /* set the voltage on the cap */ + if (!m_vco_cap_voltage_ext || (data != m_vco_cap_voltage)) + { + m_channel->update(); + + m_vco_cap_voltage_ext = 1; + m_vco_cap_voltage = data; + + log_vco_freq(); + } + } +#endif +} + + + +/***************************************************************************** + * + * Set VCO voltage + * + *****************************************************************************/ + +void sn76477_device::_SN76477_vco_voltage_w(double data) +{ + m_vco_voltage = data; +} + + +void sn76477_device::vco_voltage_w(double data) +{ +#if TEST_MODE == 0 + CHECK_CHIP_NUM_AND_VOLTAGE; + + if (data != m_vco_voltage) + { + m_channel->update(); + + _SN76477_vco_voltage_w(data); + + log_vco_ext_voltage(); + log_vco_duty_cycle(); + } +#endif +} + + + +/***************************************************************************** + * + * Set pitch voltage + * + *****************************************************************************/ + +void sn76477_device::_SN76477_pitch_voltage_w(double data) +{ + m_pitch_voltage = data; +} + + +void sn76477_device::pitch_voltage_w(double data) +{ +#if TEST_MODE == 0 + CHECK_CHIP_NUM_AND_VOLTAGE; + + if (data != m_pitch_voltage) + { + m_channel->update(); + + _SN76477_pitch_voltage_w(data); + + log_vco_pitch_voltage(); + log_vco_duty_cycle(); + } +#endif +} + + + +/***************************************************************************** + * + * Set noise external clock + * + *****************************************************************************/ + +WRITE_LINE_MEMBER( sn76477_device::noise_clock_w ) +{ +#if TEST_MODE == 0 + CHECK_CHIP_NUM_AND_BOOLEAN; + + if (state != m_noise_clock) + { + m_noise_clock = state; + + /* on the rising edge shift generate next value, + if external control is enabled */ + if (m_noise_clock && m_noise_clock_ext) + { + m_channel->update(); + + m_real_noise_bit_ff = generate_next_real_noise_bit(); + } + } +#endif +} + + + +/***************************************************************************** + * + * Set noise clock resistor + * + *****************************************************************************/ + +void sn76477_device::_SN76477_noise_clock_res_w(double data) +{ + if (data == 0) + { + m_noise_clock_ext = 1; + } + else + { + m_noise_clock_ext = 0; + + m_noise_clock_res = data; + } +} + + +void sn76477_device::noise_clock_res_w(double data) +{ +#if TEST_MODE == 0 + CHECK_CHIP_NUM_AND_POSITIVE; + + if (((data == 0) && !m_noise_clock_ext) || + ((data != 0) && (data != m_noise_clock_res))) + { + m_channel->update(); + + _SN76477_noise_clock_res_w(data); + + log_noise_gen_freq(); + } +#endif +} + + + +/***************************************************************************** + * + * Set noise filter resistor + * + *****************************************************************************/ + +void sn76477_device::_SN76477_noise_filter_res_w(double data) +{ + m_noise_filter_res = data; +} + + +void sn76477_device::noise_filter_res_w(double data) +{ +#if TEST_MODE == 0 + CHECK_CHIP_NUM_AND_POSITIVE; + + if (data != m_noise_filter_res) + { + m_channel->update(); + + _SN76477_noise_filter_res_w(data); + + log_noise_filter_freq(); + } +#endif +} + + + +/***************************************************************************** + * + * Set noise filter capacitor + * + *****************************************************************************/ + +void sn76477_device::_SN76477_noise_filter_cap_w(double data) +{ + m_noise_filter_cap = data; +} + + +void sn76477_device::noise_filter_cap_w(double data) +{ +#if TEST_MODE == 0 + CHECK_CHIP_NUM_AND_POSITIVE; + + if (data != m_noise_filter_cap) + { + m_channel->update(); + + _SN76477_noise_filter_cap_w(data); + + log_noise_filter_freq(); + } +#endif +} + + + +/***************************************************************************** + * + * Set the voltage on the noise filter capacitor + * + *****************************************************************************/ + +void sn76477_device::noise_filter_cap_voltage_w(double data) +{ +#if TEST_MODE == 0 + CHECK_CHIP_NUM_AND_CAP_VOLTAGE; + + if (data == SN76477_EXTERNAL_VOLTAGE_DISCONNECT) + { + /* switch to internal, if not already */ + if (m_noise_filter_cap_voltage_ext) + { + m_channel->update(); + + m_noise_filter_cap_voltage_ext = 0; + + log_noise_filter_freq(); + } + } + else + { + /* set the voltage on the cap */ + if (!m_noise_filter_cap_voltage_ext || (data != m_noise_filter_cap_voltage)) + { + m_channel->update(); + + m_noise_filter_cap_voltage_ext = 1; + m_noise_filter_cap_voltage = data; + + log_noise_filter_freq(); + } + } +#endif +} + + + +/***************************************************************************** + * + * Set attack resistor + * + *****************************************************************************/ + +void sn76477_device::_SN76477_attack_res_w(double data) +{ + m_attack_res = data; +} + + +void sn76477_device::attack_res_w(double data) +{ +#if TEST_MODE == 0 + CHECK_CHIP_NUM_AND_POSITIVE; + + if (data != m_attack_res) + { + m_channel->update(); + + _SN76477_attack_res_w(data); + + log_attack_time(); + } +#endif +} + + + +/***************************************************************************** + * + * Set decay resistor + * + *****************************************************************************/ + +void sn76477_device::_SN76477_decay_res_w(double data) +{ + m_decay_res = data; +} + + +void sn76477_device::decay_res_w(double data) +{ +#if TEST_MODE == 0 + CHECK_CHIP_NUM_AND_POSITIVE; + + if (data != m_decay_res) + { + m_channel->update(); + + _SN76477_decay_res_w(data); + + log_decay_time(); + } +#endif +} + + + +/***************************************************************************** + * + * Set attack/decay capacitor + * + *****************************************************************************/ + +void sn76477_device::_SN76477_attack_decay_cap_w(double data) +{ + m_attack_decay_cap = data; +} + + +void sn76477_device::attack_decay_cap_w(double data) +{ +#if TEST_MODE == 0 + CHECK_CHIP_NUM_AND_POSITIVE; + + if (data != m_attack_decay_cap) + { + m_channel->update(); + + _SN76477_attack_decay_cap_w(data); + + log_attack_time(); + log_decay_time(); + } +#endif +} + + + +/***************************************************************************** + * + * Set the voltage on the attack/decay capacitor + * + *****************************************************************************/ + +void sn76477_device::attack_decay_cap_voltage_w(double data) +{ +#if TEST_MODE == 0 + CHECK_CHIP_NUM_AND_CAP_VOLTAGE; + + if (data == SN76477_EXTERNAL_VOLTAGE_DISCONNECT) + { + /* switch to internal, if not already */ + if (m_attack_decay_cap_voltage_ext) + { + m_channel->update(); + + m_attack_decay_cap_voltage_ext = 0; + + log_attack_time(); + log_decay_time(); + } + } + else + { + /* set the voltage on the cap */ + if (!m_attack_decay_cap_voltage_ext || (data != m_attack_decay_cap_voltage)) + { + m_channel->update(); + + m_attack_decay_cap_voltage_ext = 1; + m_attack_decay_cap_voltage = data; + + log_attack_time(); + log_decay_time(); + } + } +#endif +} + + + +/***************************************************************************** + * + * Set amplitude resistor + * + *****************************************************************************/ + +void sn76477_device::_SN76477_amplitude_res_w(double data) +{ + m_amplitude_res = data; +} + + +void sn76477_device::amplitude_res_w(double data) +{ +#if TEST_MODE == 0 + CHECK_CHIP_NUM_AND_POSITIVE; + + if (data != m_amplitude_res) + { + m_channel->update(); + + _SN76477_amplitude_res_w(data); + + log_voltage_out(); + } +#endif +} + + + +/***************************************************************************** + * + * Set feedback resistor + * + *****************************************************************************/ + +void sn76477_device::_SN76477_feedback_res_w(double data) +{ + m_feedback_res = data; +} + + +void sn76477_device::feedback_res_w(double data) +{ +#if TEST_MODE == 0 + CHECK_CHIP_NUM_AND_POSITIVE; + + if (data != m_feedback_res) + { + m_channel->update(); + + _SN76477_feedback_res_w(data); + + log_voltage_out(); + } +#endif +} + + +/***************************************************************************** + * + * State saving + * + *****************************************************************************/ + +void sn76477_device::state_save_register() +{ + save_item(NAME(m_enable)); + save_item(NAME(m_envelope_mode)); + save_item(NAME(m_vco_mode)); + save_item(NAME(m_mixer_mode)); + + save_item(NAME(m_one_shot_res)); + save_item(NAME(m_one_shot_cap)); + save_item(NAME(m_one_shot_cap_voltage_ext)); + + save_item(NAME(m_slf_res)); + save_item(NAME(m_slf_cap)); + save_item(NAME(m_slf_cap_voltage_ext)); + + save_item(NAME(m_vco_voltage)); + save_item(NAME(m_vco_res)); + save_item(NAME(m_vco_cap)); + save_item(NAME(m_vco_cap_voltage_ext)); + + save_item(NAME(m_noise_clock_res)); + save_item(NAME(m_noise_clock_ext)); + save_item(NAME(m_noise_clock)); + save_item(NAME(m_noise_filter_res)); + save_item(NAME(m_noise_filter_cap)); + save_item(NAME(m_noise_filter_cap_voltage_ext)); + + save_item(NAME(m_attack_res)); + save_item(NAME(m_decay_res)); + save_item(NAME(m_attack_decay_cap)); + save_item(NAME(m_attack_decay_cap_voltage_ext)); + + save_item(NAME(m_amplitude_res)); + save_item(NAME(m_feedback_res)); + save_item(NAME(m_pitch_voltage)); + + save_item(NAME(m_one_shot_cap_voltage)); + save_item(NAME(m_one_shot_running_ff)); + + save_item(NAME(m_slf_cap_voltage)); + save_item(NAME(m_slf_out_ff)); + + save_item(NAME(m_vco_cap_voltage)); + save_item(NAME(m_vco_out_ff)); + save_item(NAME(m_vco_alt_pos_edge_ff)); + + save_item(NAME(m_noise_filter_cap_voltage)); + save_item(NAME(m_real_noise_bit_ff)); + save_item(NAME(m_filtered_noise_bit_ff)); + save_item(NAME(m_noise_gen_count)); + + save_item(NAME(m_attack_decay_cap_voltage)); + + save_item(NAME(m_rng)); +} + +//------------------------------------------------- +// sound_stream_update - handle a stream update +//------------------------------------------------- + +void sn76477_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + double one_shot_cap_charging_step; + double one_shot_cap_discharging_step; + double slf_cap_charging_step; + double slf_cap_discharging_step; + double vco_duty_cycle_multiplier; + double vco_cap_charging_step; + double vco_cap_discharging_step; + double vco_cap_voltage_max; + UINT32 noise_gen_freq; + double noise_filter_cap_charging_step; + double noise_filter_cap_discharging_step; + double attack_decay_cap_charging_step; + double attack_decay_cap_discharging_step; + int attack_decay_cap_charging; + double voltage_out; + double center_to_peak_voltage_out; + + stream_sample_t *buffer = outputs[0]; + + +#if TEST_MODE + static int recursing = 0; /* we need to prevent recursion since enable_w calls machine().input().code_pressed_once(KEYCODE_SPACE->update */ + + if () && !recursing) + { + recursing = 1; + + machine().sound().system_enable(); + SN76477_test_enable_w(!m_enable); + } + + recursing = 0; +#endif + + /* compute charging values, doing it here ensures that we always use the latest values */ + one_shot_cap_charging_step = compute_one_shot_cap_charging_rate() / m_our_sample_rate; + one_shot_cap_discharging_step = compute_one_shot_cap_discharging_rate() / m_our_sample_rate; + + slf_cap_charging_step = compute_slf_cap_charging_rate() / m_our_sample_rate; + slf_cap_discharging_step = compute_slf_cap_discharging_rate() / m_our_sample_rate; + + vco_duty_cycle_multiplier = (1 - compute_vco_duty_cycle()) * 2; + vco_cap_charging_step = compute_vco_cap_charging_discharging_rate() / vco_duty_cycle_multiplier / m_our_sample_rate; + vco_cap_discharging_step = compute_vco_cap_charging_discharging_rate() * vco_duty_cycle_multiplier / m_our_sample_rate; + + noise_filter_cap_charging_step = compute_noise_filter_cap_charging_rate() / m_our_sample_rate; + noise_filter_cap_discharging_step = compute_noise_filter_cap_discharging_rate() / m_our_sample_rate; + noise_gen_freq = compute_noise_gen_freq(); + + attack_decay_cap_charging_step = compute_attack_decay_cap_charging_rate() / m_our_sample_rate; + attack_decay_cap_discharging_step = compute_attack_decay_cap_discharging_rate() / m_our_sample_rate; + + center_to_peak_voltage_out = compute_center_to_peak_voltage_out(); + + + /* process 'samples' number of samples */ + while (samples--) + { + /* update the one-shot cap voltage */ + if (!m_one_shot_cap_voltage_ext) + { + if (m_one_shot_running_ff) + { + /* charging */ + m_one_shot_cap_voltage = min(m_one_shot_cap_voltage + one_shot_cap_charging_step, ONE_SHOT_CAP_VOLTAGE_MAX); + } + else + { + /* discharging */ + m_one_shot_cap_voltage = max(m_one_shot_cap_voltage - one_shot_cap_discharging_step, ONE_SHOT_CAP_VOLTAGE_MIN); + } + } + + if (m_one_shot_cap_voltage >= ONE_SHOT_CAP_VOLTAGE_MAX) + { + m_one_shot_running_ff = 0; + } + + + /* update the SLF (super low frequency oscillator) */ + if (!m_slf_cap_voltage_ext) + { + /* internal */ + if (!m_slf_out_ff) + { + /* charging */ + m_slf_cap_voltage = min(m_slf_cap_voltage + slf_cap_charging_step, SLF_CAP_VOLTAGE_MAX); + } + else + { + /* discharging */ + m_slf_cap_voltage = max(m_slf_cap_voltage - slf_cap_discharging_step, SLF_CAP_VOLTAGE_MIN); + } + } + + if (m_slf_cap_voltage >= SLF_CAP_VOLTAGE_MAX) + { + m_slf_out_ff = 1; + } + else if (m_slf_cap_voltage <= SLF_CAP_VOLTAGE_MIN) + { + m_slf_out_ff = 0; + } + + + /* update the VCO (voltage controlled oscillator) */ + if (m_vco_mode) + { + /* VCO is controlled by SLF */ + vco_cap_voltage_max = m_slf_cap_voltage + VCO_TO_SLF_VOLTAGE_DIFF; + } + else + { + /* VCO is controlled by external voltage */ + vco_cap_voltage_max = m_vco_voltage + VCO_TO_SLF_VOLTAGE_DIFF; + } + + if (!m_vco_cap_voltage_ext) + { + if (!m_vco_out_ff) + { + /* charging */ + m_vco_cap_voltage = min(m_vco_cap_voltage + vco_cap_charging_step, vco_cap_voltage_max); + } + else + { + /* discharging */ + m_vco_cap_voltage = max(m_vco_cap_voltage - vco_cap_discharging_step, VCO_CAP_VOLTAGE_MIN); + } + } + + if (m_vco_cap_voltage >= vco_cap_voltage_max) + { + if (!m_vco_out_ff) + { + /* positive edge */ + m_vco_alt_pos_edge_ff = !m_vco_alt_pos_edge_ff; + } + + m_vco_out_ff = 1; + } + else if (m_vco_cap_voltage <= VCO_CAP_VOLTAGE_MIN) + { + m_vco_out_ff = 0; + } + + + /* update the noise generator */ + while (!m_noise_clock_ext && (m_noise_gen_count <= noise_gen_freq)) + { + m_noise_gen_count = m_noise_gen_count + m_our_sample_rate; + + m_real_noise_bit_ff = generate_next_real_noise_bit(); + } + + m_noise_gen_count = m_noise_gen_count - noise_gen_freq; + + + /* update the noise filter */ + if (!m_noise_filter_cap_voltage_ext) + { + /* internal */ + if (m_real_noise_bit_ff) + { + /* charging */ + m_noise_filter_cap_voltage = min(m_noise_filter_cap_voltage + noise_filter_cap_charging_step, NOISE_CAP_VOLTAGE_MAX); + } + else + { + /* discharging */ + m_noise_filter_cap_voltage = max(m_noise_filter_cap_voltage - noise_filter_cap_discharging_step, NOISE_CAP_VOLTAGE_MIN); + } + } + + /* check the thresholds */ + if (m_noise_filter_cap_voltage >= NOISE_CAP_HIGH_THRESHOLD) + { + m_filtered_noise_bit_ff = 0; + } + else if (m_noise_filter_cap_voltage <= NOISE_CAP_LOW_THRESHOLD) + { + m_filtered_noise_bit_ff = 1; + } + + + /* based on the envelope mode figure out the attack/decay phase we are in */ + switch (m_envelope_mode) + { + case 0: /* VCO */ + attack_decay_cap_charging = m_vco_out_ff; + break; + + case 1: /* one-shot */ + attack_decay_cap_charging = m_one_shot_running_ff; + break; + + case 2: + default: /* mixer only */ + attack_decay_cap_charging = 1; /* never a decay phase */ + break; + + case 3: /* VCO with alternating polarity */ + attack_decay_cap_charging = m_vco_out_ff && m_vco_alt_pos_edge_ff; + break; + } + + + /* update a/d cap voltage */ + if (!m_attack_decay_cap_voltage_ext) + { + if (attack_decay_cap_charging) + { + if (attack_decay_cap_charging_step > 0) + { + m_attack_decay_cap_voltage = min(m_attack_decay_cap_voltage + attack_decay_cap_charging_step, AD_CAP_VOLTAGE_MAX); + } + else + { + /* no attack, voltage to max instantly */ + m_attack_decay_cap_voltage = AD_CAP_VOLTAGE_MAX; + } + } + else + { + /* discharging */ + if (attack_decay_cap_discharging_step > 0) + { + m_attack_decay_cap_voltage = max(m_attack_decay_cap_voltage - attack_decay_cap_discharging_step, AD_CAP_VOLTAGE_MIN); + } + else + { + /* no decay, voltage to min instantly */ + m_attack_decay_cap_voltage = AD_CAP_VOLTAGE_MIN; + } + } + } + + + /* mix the output, if enabled, or not saturated by the VCO */ + if (!m_enable && (m_vco_cap_voltage <= VCO_CAP_VOLTAGE_MAX)) + { + UINT32 out; + + /* enabled */ + switch (m_mixer_mode) + { + case 0: /* VCO */ + out = m_vco_out_ff; + break; + + case 1: /* SLF */ + out = m_slf_out_ff; + break; + + case 2: /* noise */ + out = m_filtered_noise_bit_ff; + break; + + case 3: /* VCO and noise */ + out = m_vco_out_ff & m_filtered_noise_bit_ff; + break; + + case 4: /* SLF and noise */ + out = m_slf_out_ff & m_filtered_noise_bit_ff; + break; + + case 5: /* VCO, SLF and noise */ + out = m_vco_out_ff & m_slf_out_ff & m_filtered_noise_bit_ff; + break; + + case 6: /* VCO and SLF */ + out = m_vco_out_ff & m_slf_out_ff; + break; + + case 7: /* inhibit */ + default: + out = 0; + break; + } + + /* determine the OUT voltage from the attack/delay cap voltage and clip it */ + if (out) + { + voltage_out = OUT_CENTER_LEVEL_VOLTAGE + center_to_peak_voltage_out * out_pos_gain[(int)(m_attack_decay_cap_voltage * 10)], + voltage_out = min(voltage_out, OUT_HIGH_CLIP_THRESHOLD); + } + else + { + voltage_out = OUT_CENTER_LEVEL_VOLTAGE + center_to_peak_voltage_out * out_neg_gain[(int)(m_attack_decay_cap_voltage * 10)], + voltage_out = max(voltage_out, OUT_LOW_CLIP_THRESHOLD); + } + } + else + { + /* disabled */ + voltage_out = OUT_CENTER_LEVEL_VOLTAGE; + } + + + /* convert it to a signed 16-bit sample, + -32767 = OUT_LOW_CLIP_THRESHOLD + 0 = OUT_CENTER_LEVEL_VOLTAGE + 32767 = 2 * OUT_CENTER_LEVEL_VOLTAGE + OUT_LOW_CLIP_THRESHOLD + + / Vout - Vmin \ + sample = | ----------- - 1 | * 32767 + \ Vcen - Vmin / + */ + *buffer++ = (((voltage_out - OUT_LOW_CLIP_THRESHOLD) / (OUT_CENTER_LEVEL_VOLTAGE - OUT_LOW_CLIP_THRESHOLD)) - 1) * 32767; + + if (LOG_WAV && LOG_WAV_ENABLED_ONLY && !m_enable) + { + INT16 log_data_l; + INT16 log_data_r; + + switch (LOG_WAV_VALUE_L) + { + case 0: + log_data_l = LOG_WAV_GAIN_FACTOR * voltage_out; + log_data_r = LOG_WAV_GAIN_FACTOR * voltage_out; + break; + case 1: + log_data_l = LOG_WAV_GAIN_FACTOR * m_enable; + log_data_r = LOG_WAV_GAIN_FACTOR * m_enable; + break; + case 2: + log_data_l = LOG_WAV_GAIN_FACTOR * m_one_shot_cap_voltage; + log_data_r = LOG_WAV_GAIN_FACTOR * m_one_shot_cap_voltage; + break; + case 3: + log_data_l = LOG_WAV_GAIN_FACTOR * m_attack_decay_cap_voltage; + log_data_r = LOG_WAV_GAIN_FACTOR * m_attack_decay_cap_voltage; + break; + case 4: + log_data_l = LOG_WAV_GAIN_FACTOR * m_slf_cap_voltage; + log_data_r = LOG_WAV_GAIN_FACTOR * m_slf_cap_voltage; + break; + case 5: + log_data_l = LOG_WAV_GAIN_FACTOR * m_vco_cap_voltage; + log_data_r = LOG_WAV_GAIN_FACTOR * m_vco_cap_voltage; + break; + case 6: + log_data_l = LOG_WAV_GAIN_FACTOR * m_noise_filter_cap_voltage; + log_data_r = LOG_WAV_GAIN_FACTOR * m_noise_filter_cap_voltage; + break; + } + + add_wav_data(log_data_l, log_data_r); + } + } +} diff --git a/src/devices/sound/sn76477.h b/src/devices/sound/sn76477.h new file mode 100644 index 00000000000..392beb13489 --- /dev/null +++ b/src/devices/sound/sn76477.h @@ -0,0 +1,337 @@ +// license:BSD-3-Clause +// copyright-holders:Zsolt Vasvari +/***************************************************************************** + + Texas Instruments SN76477 emulator + + SN76477 pin layout. There is a corresponding interface variable with the + same name. The only exception is noise_clock which must be programmatically + set. The other pins have programmatic equivalents as well. + The name of the function is SN76477__w. + All capacitor functions can also specify a fixed voltage on the cap. + The name of this function is SN76477__voltage_w + + +-------------------+ + envelope_1 | 1 | | 28| envelope_2 + | 2 GND - 27| mixer_c + noise_clock | 3 26| mixer_a + noise_clock_res | 4 25| mixer_b + noise_filter_res | 5 24| one_shot_res + noise_filter_cap | 6 23| one_shot_cap + decay_res | 7 22| vco + attack_decay_cap | 8 21| slf_cap + enable o| 9 20| slf_res + attack_res |10 19| pitch_voltage + amplitude_res |11 18| vco_res + feedback_res |12 17| vco_cap + |13 OUTPUT 16| vco_voltage + |14 Vcc +5V OUT 15| + +-------------------+ + + All resistor values in Ohms + All capacitor values in Farads + Use RES_K, RES_M and CAP_U, CAP_N, CAP_P macros in rescap.h to convert + magnitudes, eg. 220k = RES_K(220), 47nF = CAP_N(47) + + *****************************************************************************/ + +#pragma once + +#ifndef __SN76477_H__ +#define __SN76477_H__ + +#include "machine/rescap.h" + + +/***************************************************************************** + * + * Interface definition + * + *****************************************************************************/ + + +#define MCFG_SN76477_NOISE_PARAMS(_clock_res, _filter_res, _filter_cap) \ + sn76477_device::set_noise_params(*device, _clock_res, _filter_res, _filter_cap); + +#define MCFG_SN76477_DECAY_RES(_decay_res) \ + sn76477_device::set_decay_res(*device, _decay_res); + +#define MCFG_SN76477_ATTACK_PARAMS(_decay_cap, _res) \ + sn76477_device::set_attack_params(*device, _decay_cap, _res); + +#define MCFG_SN76477_AMP_RES(_amp_res) \ + sn76477_device::set_amp_res(*device, _amp_res); + +#define MCFG_SN76477_FEEDBACK_RES(_feedback_res) \ + sn76477_device::set_feedack_res(*device, _feedback_res); + +#define MCFG_SN76477_VCO_PARAMS(_volt, _cap, _res) \ + sn76477_device::set_vco_params(*device, _volt, _cap, _res); + +#define MCFG_SN76477_PITCH_VOLTAGE(_volt) \ + sn76477_device::set_pitch_voltage(*device, _volt); + +#define MCFG_SN76477_SLF_PARAMS(_cap, _res) \ + sn76477_device::set_slf_params(*device, _cap, _res); + +#define MCFG_SN76477_ONESHOT_PARAMS(_cap, _res) \ + sn76477_device::set_oneshot_params(*device, _cap, _res); + +#define MCFG_SN76477_VCO_MODE(_mode) \ + sn76477_device::set_vco_mode(*device, _mode); + +#define MCFG_SN76477_MIXER_PARAMS(_a, _b, _c) \ + sn76477_device::set_mixer_params(*device, _a, _b, _c); + +#define MCFG_SN76477_ENVELOPE_PARAMS(_env1, _env2) \ + sn76477_device::set_envelope_params(*device, _env1, _env2); + +#define MCFG_SN76477_ENABLE(_enable) \ + sn76477_device::set_enable(*device, _enable); + +class sn76477_device : public device_t, + public device_sound_interface +{ +public: + sn76477_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + ~sn76477_device() {} + + static void set_noise_params(device_t &device, double clock_res, double filter_res, double filter_cap) + { + sn76477_device &dev = downcast(device); + dev.m_noise_clock_res = clock_res; + dev.m_noise_filter_res = filter_res; + dev.m_noise_filter_cap = filter_cap; + } + static void set_decay_res(device_t &device, double decay_res) { downcast(device).m_decay_res = decay_res; } + static void set_attack_params(device_t &device, double decay_cap, double res) + { + sn76477_device &dev = downcast(device); + dev.m_attack_decay_cap = decay_cap; + dev.m_attack_res = res; + } + static void set_amp_res(device_t &device, double amp_res) { downcast(device).m_amplitude_res = amp_res; } + static void set_feedack_res(device_t &device, double feedback_res) { downcast(device).m_feedback_res = feedback_res; } + static void set_vco_params(device_t &device, double volt, double cap, double res) + { + sn76477_device &dev = downcast(device); + dev.m_vco_voltage = volt; + dev.m_vco_cap = cap; + dev.m_vco_res = res; + } + static void set_pitch_voltage(device_t &device, double volt) { downcast(device).m_pitch_voltage = volt; } + static void set_slf_params(device_t &device, double cap, double res) + { + sn76477_device &dev = downcast(device); + dev.m_slf_cap = cap; + dev.m_slf_res = res; + } + static void set_oneshot_params(device_t &device, double cap, double res) + { + sn76477_device &dev = downcast(device); + dev.m_one_shot_cap = cap; + dev.m_one_shot_res = res; + } + static void set_vco_mode(device_t &device, UINT32 mode) { downcast(device).m_vco_mode = mode; } + static void set_mixer_params(device_t &device, UINT32 a, UINT32 b, UINT32 c) + { + sn76477_device &dev = downcast(device); + dev.m_mixer_a = a; + dev.m_mixer_b = b; + dev.m_mixer_c = c; + } + static void set_envelope_params(device_t &device, UINT32 env1, UINT32 env2) + { + sn76477_device &dev = downcast(device); + dev.m_envelope_1 = env1; + dev.m_envelope_2 = env2; + } + static void set_enable(device_t &device, UINT32 enable) { downcast(device).m_enable = enable; } + + + /* these functions take 0 or 1 as a logic input */ + WRITE_LINE_MEMBER( enable_w ); /* active LO, 0 = enabled, 1 = disabled */ + WRITE_LINE_MEMBER( mixer_a_w ); + WRITE_LINE_MEMBER( mixer_b_w ); + WRITE_LINE_MEMBER( mixer_c_w ); + WRITE_LINE_MEMBER( envelope_1_w ); + WRITE_LINE_MEMBER( envelope_2_w ); + WRITE_LINE_MEMBER( vco_w ); /* 0 = external, 1 = controlled by SLF */ + WRITE_LINE_MEMBER( noise_clock_w ); /* noise clock write, if noise_clock_res = 0 */ + + /* these functions take a resistor value in Ohms */ + void one_shot_res_w(double data); + void slf_res_w(double data); + void vco_res_w(double data); + void noise_clock_res_w(double data); /* = 0 if the noise gen is clocked via noise_clock */ + void noise_filter_res_w(double data); + void decay_res_w(double data); + void attack_res_w(double data); + void amplitude_res_w(double data); + void feedback_res_w(double data); + + /* these functions take a capacitor value in Farads or the voltage on it in Volts */ + #define SN76477_EXTERNAL_VOLTAGE_DISCONNECT (-1.0) /* indicates that the voltage is internally computed, + can be used in all the functions that take a + voltage on a capacitor */ + void one_shot_cap_w(double data); + void one_shot_cap_voltage_w(double data); + void slf_cap_w(double data); + void slf_cap_voltage_w(double data); + void vco_cap_w(double data); + void vco_cap_voltage_w(double data); + void noise_filter_cap_w(double data); + void noise_filter_cap_voltage_w(double data); + void attack_decay_cap_w(double data); + void attack_decay_cap_voltage_w(double data); + + /* these functions take a voltage value in Volts */ + void vco_voltage_w(double data); + void pitch_voltage_w(double data); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_stop(); + + // sound stream update overrides + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + +private: + /* chip's external interface */ + UINT32 m_enable; + UINT32 m_envelope_mode; + UINT32 m_vco_mode; + UINT32 m_mixer_mode; + + double m_one_shot_res; + double m_one_shot_cap; + UINT32 m_one_shot_cap_voltage_ext; + + double m_slf_res; + double m_slf_cap; + UINT32 m_slf_cap_voltage_ext; + + double m_vco_voltage; + double m_vco_res; + double m_vco_cap; + UINT32 m_vco_cap_voltage_ext; + + double m_noise_clock_res; + UINT32 m_noise_clock_ext; + UINT32 m_noise_clock; + double m_noise_filter_res; + double m_noise_filter_cap; + UINT32 m_noise_filter_cap_voltage_ext; + + double m_attack_res; + double m_decay_res; + double m_attack_decay_cap; + UINT32 m_attack_decay_cap_voltage_ext; + + double m_amplitude_res; + double m_feedback_res; + double m_pitch_voltage; + + // internal state + double m_one_shot_cap_voltage; /* voltage on the one-shot cap */ + UINT32 m_one_shot_running_ff; /* 1 = one-shot running, 0 = stopped */ + + double m_slf_cap_voltage; /* voltage on the SLF cap */ + UINT32 m_slf_out_ff; /* output of the SLF */ + + double m_vco_cap_voltage; /* voltage on the VCO cap */ + UINT32 m_vco_out_ff; /* output of the VCO */ + UINT32 m_vco_alt_pos_edge_ff; /* keeps track of the # of positive edges for VCO Alt envelope */ + + double m_noise_filter_cap_voltage; /* voltage on the noise filter cap */ + UINT32 m_real_noise_bit_ff; /* the current noise bit before filtering */ + UINT32 m_filtered_noise_bit_ff; /* the noise bit after filtering */ + UINT32 m_noise_gen_count; /* noise freq emulation */ + + double m_attack_decay_cap_voltage; /* voltage on the attack/decay cap */ + + UINT32 m_rng; /* current value of the random number generator */ + + // configured by the drivers and used to setup m_mixer_mode & m_envelope_mode at start + UINT32 m_mixer_a; + UINT32 m_mixer_b; + UINT32 m_mixer_c; + UINT32 m_envelope_1; + UINT32 m_envelope_2; + + /* others */ + sound_stream *m_channel; /* returned by stream_create() */ + int m_our_sample_rate; /* from machine.sample_rate() */ + + wav_file *m_file; /* handle of the wave file to produce */ + + double compute_one_shot_cap_charging_rate(); + double compute_one_shot_cap_discharging_rate(); + double compute_slf_cap_charging_rate(); + double compute_slf_cap_discharging_rate(); + double compute_vco_cap_charging_discharging_rate(); + double compute_vco_duty_cycle(); + UINT32 compute_noise_gen_freq(); + double compute_noise_filter_cap_charging_rate(); + double compute_noise_filter_cap_discharging_rate(); + double compute_attack_decay_cap_charging_rate(); + double compute_attack_decay_cap_discharging_rate(); + double compute_center_to_peak_voltage_out(); + + void log_enable_line(); + void log_mixer_mode(); + void log_envelope_mode(); + void log_vco_mode(); + void log_one_shot_time(); + void log_slf_freq(); + void log_vco_pitch_voltage(); + void log_vco_duty_cycle(); + void log_vco_freq(); + void log_vco_ext_voltage(); + void log_noise_gen_freq(); + void log_noise_filter_freq(); + void log_attack_time(); + void log_decay_time(); + void log_voltage_out(); + void log_complete_state(); + + void open_wav_file(); + void close_wav_file(); + void add_wav_data(INT16 data_l, INT16 data_r); + + void intialize_noise(); + inline UINT32 generate_next_real_noise_bit(); + + void state_save_register(); + + void _SN76477_enable_w(UINT32 data); + void _SN76477_vco_w(UINT32 data); + void _SN76477_mixer_a_w(UINT32 data); + void _SN76477_mixer_b_w(UINT32 data); + void _SN76477_mixer_c_w(UINT32 data); + void _SN76477_envelope_1_w(UINT32 data); + void _SN76477_envelope_2_w(UINT32 data); + void _SN76477_one_shot_res_w(double data); + void _SN76477_one_shot_cap_w(double data); + void _SN76477_slf_res_w(double data); + void _SN76477_slf_cap_w(double data); + void _SN76477_vco_res_w(double data); + void _SN76477_vco_cap_w(double data); + void _SN76477_vco_voltage_w(double data); + void _SN76477_noise_clock_res_w(double data); + void _SN76477_noise_filter_res_w(double data); + void _SN76477_noise_filter_cap_w(double data); + void _SN76477_decay_res_w(double data); + void _SN76477_attack_res_w(double data); + void _SN76477_attack_decay_cap_w(double data); + void _SN76477_amplitude_res_w(double data); + void _SN76477_feedback_res_w(double data); + void _SN76477_pitch_voltage_w(double data); + void SN76477_test_enable_w(UINT32 data); +}; + +extern const device_type SN76477; + + +#endif/* __SN76477_H__ */ diff --git a/src/devices/sound/sn76496.c b/src/devices/sound/sn76496.c new file mode 100644 index 00000000000..7d0ccf50319 --- /dev/null +++ b/src/devices/sound/sn76496.c @@ -0,0 +1,441 @@ +// license:BSD-3-Clause +// copyright-holders:Nicola Salmoria +/*************************************************************************** + + sn76496.c + by Nicola Salmoria + with contributions by others + + Routines to emulate the: + Texas Instruments SN76489, SN76489A, SN76494/SN76496 + ( Also known as, or at least compatible with, the TMS9919 and SN94624.) + and the Sega 'PSG' used on the Master System, Game Gear, and Megadrive/Genesis + This chip is known as the Programmable Sound Generator, or PSG, and is a 4 + channel sound generator, with three squarewave channels and a noise/arbitrary + duty cycle channel. + + Noise emulation for all verified chips should be accurate: + + ** SN76489 uses a 15-bit shift register with taps on bits D and E, output on E, + XOR function. + It uses a 15-bit ring buffer for periodic noise/arbitrary duty cycle. + Its output is inverted. + ** SN94624 is the same as SN76489 but lacks the /8 divider on its clock input. + ** SN76489A uses a 15-bit shift register with taps on bits D and E, output on F, + XOR function. + It uses a 15-bit ring buffer for periodic noise/arbitrary duty cycle. + Its output is not inverted. + ** SN76494 is the same as SN76489A but lacks the /8 divider on its clock input. + ** SN76496 is identical in operation to the SN76489A, but the audio input on pin 9 is + documented. + All the TI-made PSG chips have an audio input line which is mixed with the 4 channels + of output. (It is undocumented and may not function properly on the sn76489, 76489a + and 76494; the sn76489a input is mentioned in datasheets for the tms5200) + All the TI-made PSG chips act as if the frequency was set to 0x400 if 0 is + written to the frequency register. + ** Sega Master System III/MD/Genesis PSG uses a 16-bit shift register with taps + on bits C and F, output on F + It uses a 16-bit ring buffer for periodic noise/arbitrary duty cycle. + (whether it uses an XOR or XNOR needs to be verified, assumed XOR) + (whether output is inverted or not needs to be verified, assumed to be inverted) + ** Sega Game Gear PSG is identical to the SMS3/MD/Genesis one except it has an + extra register for mapping which channels go to which speaker. + The register, connected to a z80 port, means: + for bits 7 6 5 4 3 2 1 0 + L3 L2 L1 L0 R3 R2 R1 R0 + Noise is an XOR function, and audio output is negated before being output. + All the Sega-made PSG chips act as if the frequency was set to 0 if 0 is written + to the frequency register. + ** NCR7496 (as used on the Tandy 1000) is similar to the SN76489 but with a + different noise LFSR patttern: taps on bits A and E, output on E + It uses a 15-bit ring buffer for periodic noise/arbitrary duty cycle. + (all this chip's info needs to be verified) + + 28/03/2005 : Sebastien Chevalier + Update th SN76496Write func, according to SN76489 doc found on SMSPower. + - On write with 0x80 set to 0, when LastRegister is other then TONE, + the function is similar than update with 0x80 set to 1 + + 23/04/2007 : Lord Nightmare + Major update, implement all three different noise generation algorithms and a + set_variant call to discern among them. + + 28/04/2009 : Lord Nightmare + Add READY line readback; cleaned up struct a bit. Cleaned up comments. + Add more TODOs. Fixed some unsaved savestate related stuff. + + 04/11/2009 : Lord Nightmare + Changed the way that the invert works (it now selects between XOR and XNOR + for the taps), and added R->OldNoise to simulate the extra 0 that is always + output before the noise LFSR contents are after an LFSR reset. + This fixes SN76489/A to match chips. Added SN94624. + + 14/11/2009 : Lord Nightmare + Removed STEP mess, vastly simplifying the code. Made output bipolar rather + than always above the 0 line, but disabled that code due to pending issues. + + 16/11/2009 : Lord Nightmare + Fix screeching in regulus: When summing together four equal channels, the + size of the max amplitude per channel should be 1/4 of the max range, not + 1/3. Added NCR7496. + + 18/11/2009 : Lord Nightmare + Modify Init functions to support negating the audio output. The gamegear + psg does this. Change gamegear and sega psgs to use XOR rather than XNOR + based on testing. Got rid of R->OldNoise and fixed taps accordingly. + Added stereo support for game gear. + + 15/01/2010 : Lord Nightmare + Fix an issue with SN76489 and SN76489A having the wrong periodic noise periods. + Note that properly emulating the noise cycle bit timing accurately may require + extensive rewriting. + + 24/01/2010: Lord Nightmare + Implement periodic noise as forcing one of the XNOR or XOR taps to 1 or 0 respectively. + Thanks to PlgDavid for providing samples which helped immensely here. + Added true clock divider emulation, so sn94624 and sn76494 run 8x faster than + the others, as in real life. + + 15/02/2010: Lord Nightmare & Michael Zapf (additional testing by PlgDavid) + Fix noise period when set to mirror channel 3 and channel 3 period is set to 0 (tested on hardware for noise, wave needs tests) - MZ + Fix phase of noise on sn94624 and sn76489; all chips use a standard XOR, the only inversion is the output itself - LN, Plgdavid + Thanks to PlgDavid and Michael Zapf for providing samples which helped immensely here. + + 23/02/2011: Lord Nightmare & Enik + Made it so the Sega PSG chips have a frequency of 0 if 0 is written to the + frequency register, while the others have 0x400 as before. Should fix a bug + or two on sega games, particularly Vigilante on Sega Master System. Verified + on SMS hardware. + + 27/06/2012: Michael Zapf + Converted to modern device, legacy devices were gradually removed afterwards. + + TODO: * Implement the TMS9919 - any difference to sn94624? + * Implement the T6W28; has registers in a weird order, needs writes + to be 'sanitized' first. Also is stereo, similar to game gear. + * Test the NCR7496; Smspower says the whitenoise taps are A and E, + but this needs verification on real hardware. + * Factor out common code so that the SAA1099 can share some code. + +***************************************************************************/ + +#include "emu.h" +#include "sn76496.h" + +#define MAX_OUTPUT 0x7fff + + +sn76496_base_device::sn76496_base_device(const machine_config &mconfig, device_type type, const char *name, + const char *tag, int feedbackmask, int noisetap1, int noisetap2, bool negate, bool stereo, int clockdivider, int freq0, + device_t *owner, UINT32 clock, const char *shortname, const char *source) + + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_sound_interface(mconfig, *this), + m_ready_handler(*this), + m_feedback_mask(feedbackmask), + m_whitenoise_tap1(noisetap1), + m_whitenoise_tap2(noisetap2), + m_negate(negate), + m_stereo(stereo), + m_clock_divider(clockdivider), + m_freq0_is_max(freq0) +{ +} + +sn76496_device::sn76496_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : sn76496_base_device(mconfig, SN76496, "SN76496", tag, 0x10000, 0x04, 0x08, false, false, 8, true, owner, clock, "sn76496", __FILE__) + { } +u8106_device::u8106_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : sn76496_base_device(mconfig, U8106, "U8106", tag, 0x4000, 0x01, 0x02, true, false, 8, true, owner, clock, "u8106", __FILE__) + { } +y2404_device::y2404_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : sn76496_base_device(mconfig, Y2404, "Y2404", tag, 0x10000, 0x04, 0x08, false, false, 8, true, owner, clock, "y2404", __FILE__) + { } +sn76489_device::sn76489_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : sn76496_base_device(mconfig, SN76489, "SN76489", tag, 0x4000, 0x01, 0x02, true, false, 8, true, owner, clock, "sn76489", __FILE__) + { } +sn76489a_device::sn76489a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : sn76496_base_device(mconfig, SN76489A, "SN76489A", tag, 0x10000, 0x04, 0x08, false, false, 8, true, owner, clock, "sn76489a", __FILE__) + { } +sn76494_device::sn76494_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : sn76496_base_device(mconfig, SN76494, "SN76494", tag, 0x10000, 0x04, 0x08, false, false, 1, true, owner, clock, "sn76494", __FILE__) + { } +sn94624_device::sn94624_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : sn76496_base_device(mconfig, SN94624, "SN94624", tag, 0x4000, 0x01, 0x02, true, false, 1, true, owner, clock, "sn94624", __FILE__) + { } +ncr7496_device::ncr7496_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : sn76496_base_device(mconfig, NCR7496, "NCR7496", tag, 0x8000, 0x02, 0x20, false, false, 8, true, owner, clock, "ncr7496", __FILE__) + { } +gamegear_device::gamegear_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : sn76496_base_device(mconfig, GAMEGEAR, "Game Gear PSG", tag, 0x8000, 0x01, 0x08, true, true, 8, false, owner, clock, "gamegear_psg", __FILE__) + { } +segapsg_device::segapsg_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : sn76496_base_device(mconfig, SEGAPSG, "SEGA VDP PSG", tag, 0x8000, 0x01, 0x08, true, false, 8, false, owner, clock, "segapsg", __FILE__) + { } + + +void sn76496_base_device::device_start() +{ + int sample_rate = clock()/2; + int i; + double out; + int gain; + + m_ready_handler.resolve_safe(); + + m_sound = machine().sound().stream_alloc(*this, 0, (m_stereo? 2:1), sample_rate); + + for (i = 0; i < 4; i++) m_volume[i] = 0; + + m_last_register = 0; + for (i = 0; i < 8; i+=2) + { + m_register[i] = 0; + m_register[i + 1] = 0x0f; // volume = 0 + } + + for (i = 0; i < 4; i++) + { + m_output[i] = 0; + m_period[i] = 0; + m_count[i] = 0; + } + + m_RNG = m_feedback_mask; + m_output[3] = m_RNG & 1; + + m_cycles_to_ready = 1; // assume ready is not active immediately on init. is this correct? + m_stereo_mask = 0xFF; // all channels enabled + m_current_clock = m_clock_divider-1; + + // set gain + gain = 0; + + gain &= 0xff; + + // increase max output basing on gain (0.2 dB per step) + out = MAX_OUTPUT / 4; // four channels, each gets 1/4 of the total range + while (gain-- > 0) + out *= 1.023292992; // = (10 ^ (0.2/20)) + + // build volume table (2dB per step) + for (i = 0; i < 15; i++) + { + // limit volume to avoid clipping + if (out > MAX_OUTPUT / 4) m_vol_table[i] = MAX_OUTPUT / 4; + else m_vol_table[i] = out; + + out /= 1.258925412; /* = 10 ^ (2/20) = 2dB */ + } + m_vol_table[15] = 0; + + m_ready_state = true; + + register_for_save_states(); +} + +WRITE8_MEMBER( sn76496_base_device::stereo_w ) +{ + m_sound->update(); + if (m_stereo) m_stereo_mask = data; + else fatalerror("sn76496_base_device: Call to stereo write with mono chip!\n"); +} + +void sn76496_base_device::write(UINT8 data) +{ + int n, r, c; + + // update the output buffer before changing the registers + m_sound->update(); + + // set number of cycles until READY is active; this is always one + // 'sample', i.e. it equals the clock divider exactly + m_cycles_to_ready = 1; + + if (data & 0x80) + { + r = (data & 0x70) >> 4; + m_last_register = r; + m_register[r] = (m_register[r] & 0x3f0) | (data & 0x0f); + } + else + { + r = m_last_register; + } + + c = r >> 1; + switch (r) + { + case 0: // tone 0: frequency + case 2: // tone 1: frequency + case 4: // tone 2: frequency + if ((data & 0x80) == 0) m_register[r] = (m_register[r] & 0x0f) | ((data & 0x3f) << 4); + if ((m_register[r] != 0) || (!m_freq0_is_max)) m_period[c] = m_register[r]; + else m_period[c] = 0x400; + + if (r == 4) + { + // update noise shift frequency + if ((m_register[6] & 0x03) == 0x03) m_period[3] = m_period[2]<<1; + } + break; + case 1: // tone 0: volume + case 3: // tone 1: volume + case 5: // tone 2: volume + case 7: // noise: volume + m_volume[c] = m_vol_table[data & 0x0f]; + if ((data & 0x80) == 0) m_register[r] = (m_register[r] & 0x3f0) | (data & 0x0f); + break; + case 6: // noise: frequency, mode + { + if ((data & 0x80) == 0) logerror("sn76496_base_device: write to reg 6 with bit 7 clear; data was %03x, new write is %02x! report this to LN!\n", m_register[6], data); + if ((data & 0x80) == 0) m_register[r] = (m_register[r] & 0x3f0) | (data & 0x0f); + n = m_register[6]; + // N/512,N/1024,N/2048,Tone #3 output + m_period[3] = ((n&3) == 3)? (m_period[2]<<1) : (1 << (5+(n&3))); + m_RNG = m_feedback_mask; + } + break; + } +} + +WRITE8_MEMBER( sn76496_base_device::write ) +{ + write(data); +} + +inline bool sn76496_base_device::in_noise_mode() +{ + return ((m_register[6] & 4)!=0); +} + +void sn76496_base_device::countdown_cycles() +{ + if (m_cycles_to_ready > 0) + { + m_cycles_to_ready--; + if (m_ready_state==true) m_ready_handler(CLEAR_LINE); + m_ready_state = false; + } + else + { + if (m_ready_state==false) m_ready_handler(ASSERT_LINE); + m_ready_state = true; + } +} + +void sn76496_base_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + int i; + stream_sample_t *lbuffer = outputs[0]; + stream_sample_t *rbuffer = (m_stereo)? outputs[1] : NULL; + + INT16 out = 0; + INT16 out2 = 0; + + while (samples > 0) + { + // clock chip once + if (m_current_clock > 0) // not ready for new divided clock + { + m_current_clock--; + } + else // ready for new divided clock, make a new sample + { + m_current_clock = m_clock_divider-1; + // decrement Cycles to READY by one + countdown_cycles(); + + // handle channels 0,1,2 + for (i = 0; i < 3; i++) + { + m_count[i]--; + if (m_count[i] <= 0) + { + m_output[i] ^= 1; + m_count[i] = m_period[i]; + } + } + + // handle channel 3 + m_count[3]--; + if (m_count[3] <= 0) + { + // if noisemode is 1, both taps are enabled + // if noisemode is 0, the lower tap, whitenoisetap2, is held at 0 + // The != was a bit-XOR (^) before + if (((m_RNG & m_whitenoise_tap1)!=0) != (((m_RNG & m_whitenoise_tap2)!=0) && in_noise_mode())) + { + m_RNG >>= 1; + m_RNG |= m_feedback_mask; + } + else + { + m_RNG >>= 1; + } + m_output[3] = m_RNG & 1; + + m_count[3] = m_period[3]; + } + } + + if (m_stereo) + { + out = ((((m_stereo_mask & 0x10)!=0) && (m_output[0]!=0))? m_volume[0] : 0) + + ((((m_stereo_mask & 0x20)!=0) && (m_output[1]!=0))? m_volume[1] : 0) + + ((((m_stereo_mask & 0x40)!=0) && (m_output[2]!=0))? m_volume[2] : 0) + + ((((m_stereo_mask & 0x80)!=0) && (m_output[3]!=0))? m_volume[3] : 0); + + out2= ((((m_stereo_mask & 0x1)!=0) && (m_output[0]!=0))? m_volume[0] : 0) + + ((((m_stereo_mask & 0x2)!=0) && (m_output[1]!=0))? m_volume[1] : 0) + + ((((m_stereo_mask & 0x4)!=0) && (m_output[2]!=0))? m_volume[2] : 0) + + ((((m_stereo_mask & 0x8)!=0) && (m_output[3]!=0))? m_volume[3] : 0); + } + else + { + out= ((m_output[0]!=0)? m_volume[0]:0) + +((m_output[1]!=0)? m_volume[1]:0) + +((m_output[2]!=0)? m_volume[2]:0) + +((m_output[3]!=0)? m_volume[3]:0); + } + + if (m_negate) { out = -out; out2 = -out2; } + + *(lbuffer++) = out; + if (m_stereo) *(rbuffer++) = out2; + samples--; + } +} + +void sn76496_base_device::register_for_save_states() +{ + save_item(NAME(m_vol_table)); + save_item(NAME(m_register)); + save_item(NAME(m_last_register)); + save_item(NAME(m_volume)); + save_item(NAME(m_RNG)); +// save_item(NAME(m_clock_divider)); + save_item(NAME(m_current_clock)); +// save_item(NAME(m_feedback_mask)); +// save_item(NAME(m_whitenoise_tap1)); +// save_item(NAME(m_whitenoise_tap2)); +// save_item(NAME(m_negate)); +// save_item(NAME(m_stereo)); + save_item(NAME(m_stereo_mask)); + save_item(NAME(m_period)); + save_item(NAME(m_count)); + save_item(NAME(m_output)); + save_item(NAME(m_cycles_to_ready)); +// save_item(NAME(m_freq0_is_max)); +} + +const device_type SN76496 = &device_creator; +const device_type U8106 = &device_creator; +const device_type Y2404 = &device_creator; +const device_type SN76489 = &device_creator; +const device_type SN76489A = &device_creator; +const device_type SN76494 = &device_creator; +const device_type SN94624 = &device_creator; +const device_type NCR7496 = &device_creator; +const device_type GAMEGEAR = &device_creator; +const device_type SEGAPSG = &device_creator; diff --git a/src/devices/sound/sn76496.h b/src/devices/sound/sn76496.h new file mode 100644 index 00000000000..bedee2de532 --- /dev/null +++ b/src/devices/sound/sn76496.h @@ -0,0 +1,144 @@ +// license:BSD-3-Clause +// copyright-holders:Nicola Salmoria +#pragma once + +#ifndef __SN76496_H__ +#define __SN76496_H__ + + +extern const device_type SN76496; +extern const device_type U8106; +extern const device_type Y2404; +extern const device_type SN76489; +extern const device_type SN76489A; +extern const device_type SN76494; +extern const device_type SN94624; +extern const device_type NCR7496; +extern const device_type GAMEGEAR; +extern const device_type SEGAPSG; + +#define MCFG_SN76496_READY_HANDLER(_devcb) \ + devcb = &sn76496_base_device::set_ready_handler(*device, DEVCB_##_devcb); + +class sn76496_base_device : public device_t, public device_sound_interface +{ +public: + sn76496_base_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, + int feedbackmask, int noisetap1, int noisetap2, bool negate, bool stereo, int clockdivider, int freq0, + device_t *owner, UINT32 clock, const char *shortname, const char *source); + + // static configuration helpers + template static devcb_base &set_ready_handler(device_t &device, _Object object) { return downcast(device).m_ready_handler.set_callback(object); } + + DECLARE_WRITE8_MEMBER( stereo_w ); + void write(UINT8 data); + DECLARE_WRITE8_MEMBER( write ); + DECLARE_READ_LINE_MEMBER( ready_r ) { return m_ready_state ? 1 : 0; } + +protected: + virtual void device_start(); + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + +private: + inline bool in_noise_mode(); + void register_for_save_states(); + void countdown_cycles(); + + bool m_ready_state; + + devcb_write_line m_ready_handler; + + sound_stream* m_sound; + + const INT32 m_feedback_mask; // mask for feedback + const INT32 m_whitenoise_tap1; // mask for white noise tap 1 (higher one, usually bit 14) + const INT32 m_whitenoise_tap2; // mask for white noise tap 2 (lower one, usually bit 13) + const bool m_negate; // output negate flag + const bool m_stereo; // whether we're dealing with stereo or not + const INT32 m_clock_divider; // clock divider + const bool m_freq0_is_max; // flag for if frequency zero acts as if it is one more than max (0x3ff+1) or if it acts like 0 + + INT32 m_vol_table[16]; // volume table (for 4-bit to db conversion) + INT32 m_register[8]; // registers + INT32 m_last_register; // last register written + INT32 m_volume[4]; // db volume of voice 0-2 and noise + UINT32 m_RNG; // noise generator LFSR + INT32 m_current_clock; + INT32 m_stereo_mask; // the stereo output mask + INT32 m_period[4]; // Length of 1/2 of waveform + INT32 m_count[4]; // Position within the waveform + INT32 m_output[4]; // 1-bit output of each channel, pre-volume + INT32 m_cycles_to_ready; // number of cycles until the READY line goes active +}; + +// SN76496: Whitenoise verified, phase verified, periodic verified (by Michael Zapf) +class sn76496_device : public sn76496_base_device +{ +public: + sn76496_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +// U8106 not verified yet. todo: verify; (a custom marked sn76489? only used on mr. do and maybe other universal games) +class u8106_device : public sn76496_base_device +{ +public: + u8106_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +// Y2404 not verified yet. todo: verify; (don't be fooled by the Y, it's a TI chip, not Yamaha) +class y2404_device : public sn76496_base_device +{ +public: + y2404_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +// SN76489 not verified yet. todo: verify; +class sn76489_device : public sn76496_base_device +{ +public: + sn76489_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +// SN76489A: whitenoise verified, phase verified, periodic verified (by plgdavid) +class sn76489a_device : public sn76496_base_device +{ +public: + sn76489a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +// SN76494 not verified, (according to datasheet: same as sn76489a but without the /8 divider) +class sn76494_device : public sn76496_base_device +{ +public: + sn76494_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +// SN94624 whitenoise verified, phase verified, period verified; verified by PlgDavid +class sn94624_device : public sn76496_base_device +{ +public: + sn94624_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +// NCR7496 not verified; info from smspower wiki +class ncr7496_device : public sn76496_base_device +{ +public: + ncr7496_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +// Verified by Justin Kerk +class gamegear_device : public sn76496_base_device +{ +public: + gamegear_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +// todo: verify; from smspower wiki, assumed to have same invert as gamegear +class segapsg_device : public sn76496_base_device +{ +public: + segapsg_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +#endif /* __SN76496_H__ */ diff --git a/src/devices/sound/snkwave.c b/src/devices/sound/snkwave.c new file mode 100644 index 00000000000..bc9cca6b59c --- /dev/null +++ b/src/devices/sound/snkwave.c @@ -0,0 +1,153 @@ +// license:BSD-3-Clause +// copyright-holders:Nicola Salmoria +/*************************************************************************** + + SNK Wave sound driver. + + This is a very simple single-voice generator with a programmable waveform. + +***************************************************************************/ + +#include "emu.h" +#include "snkwave.h" + + +#define CLOCK_SHIFT 8 + + +const device_type SNKWAVE = &device_creator; + +//------------------------------------------------- +// snkwave_device - constructor +//------------------------------------------------- + +snkwave_device::snkwave_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, SNKWAVE, "SNK Wave", tag, owner, clock, "snkwave", __FILE__), + device_sound_interface(mconfig, *this), + m_stream(NULL), + m_external_clock(0), + m_sample_rate(0), + m_frequency(0), + m_counter(0), + m_waveform_position(0) +{ + memset(m_waveform, 0, sizeof(m_waveform)); +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void snkwave_device::device_start() +{ + /* adjust internal clock */ + m_external_clock = clock(); + + /* adjust output clock */ + m_sample_rate = m_external_clock >> CLOCK_SHIFT; + + /* get stream channels */ + m_stream = stream_alloc(0, 1, m_sample_rate); + + /* reset all the voices */ + m_frequency = 0; + m_counter = 0; + m_waveform_position = 0; + + /* register with the save state system */ + save_item(NAME(m_frequency)); + save_item(NAME(m_counter)); + save_item(NAME(m_waveform_position)); + save_pointer(NAME(m_waveform), SNKWAVE_WAVEFORM_LENGTH); +} + + +//------------------------------------------------- +// sound_stream_update - handle update requests +// for our sound stream +//------------------------------------------------- + +void snkwave_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + stream_sample_t *buffer = outputs[0]; + + /* zap the contents of the buffer */ + memset(buffer, 0, samples * sizeof(*buffer)); + + assert(m_counter < 0x1000); + assert(m_frequency < 0x1000); + + /* if no sound, we're done */ + if (m_frequency == 0xfff) + return; + + /* generate sound into buffer while updating the counter */ + while (samples-- > 0) + { + int loops; + INT16 out = 0; + + loops = 1 << CLOCK_SHIFT; + while (loops > 0) + { + int steps = 0x1000 - m_counter; + + if (steps <= loops) + { + out += m_waveform[m_waveform_position] * steps; + m_counter = m_frequency; + m_waveform_position = (m_waveform_position + 1) & (SNKWAVE_WAVEFORM_LENGTH-1); + loops -= steps; + } + else + { + out += m_waveform[m_waveform_position] * loops; + m_counter += loops; + loops = 0; + } + } + + *buffer++ = out; + } +} + + +/* SNK wave register map + all registers are 6-bit + 0-1 frequency (12-bit) + 2-5 waveform (8 3-bit nibbles) +*/ + +WRITE8_MEMBER( snkwave_device::snkwave_w ) +{ + m_stream->update(); + + // all registers are 6-bit + data &= 0x3f; + + if (offset == 0) + m_frequency = (m_frequency & 0x03f) | (data << 6); + else if (offset == 1) + m_frequency = (m_frequency & 0xfc0) | data; + else if (offset <= 5) + update_waveform(offset - 2, data); +} + + +/* update the decoded waveform data */ +/* The programmable waveform consists of 8 3-bit nibbles. + The waveform goes to a 4-bit DAC and is played alternatingly forwards and + backwards. + When going forwards, bit 3 is 1. When going backwards, it's 0. + So the sequence 01234567 will play as + 89ABCDEF76543210 +*/ +void snkwave_device::update_waveform(unsigned int offset, UINT8 data) +{ + assert(offset < SNKWAVE_WAVEFORM_LENGTH/4); + + m_waveform[offset * 2] = ((data & 0x38) >> 3) << (12-CLOCK_SHIFT); + m_waveform[offset * 2 + 1] = ((data & 0x07) >> 0) << (12-CLOCK_SHIFT); + m_waveform[SNKWAVE_WAVEFORM_LENGTH-2 - offset * 2] = ~m_waveform[offset * 2 + 1]; + m_waveform[SNKWAVE_WAVEFORM_LENGTH-1 - offset * 2] = ~m_waveform[offset * 2]; +} diff --git a/src/devices/sound/snkwave.h b/src/devices/sound/snkwave.h new file mode 100644 index 00000000000..f613ca3ff5b --- /dev/null +++ b/src/devices/sound/snkwave.h @@ -0,0 +1,64 @@ +// license:BSD-3-Clause +// copyright-holders:Nicola Salmoria +#pragma once + +#ifndef __SNKWAVE_H__ +#define __SNKWAVE_H__ + +#define SNKWAVE_WAVEFORM_LENGTH 16 + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_SNKWAVE_ADD(_tag, _clock) \ + MCFG_DEVICE_ADD(_tag, SNKWAVE, _clock) +#define MCFG_SNKWAVE_REPLACE(_tag, _clock) \ + MCFG_DEVICE_REPLACE(_tag, SNKWAVE, _clock) + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + + +// ======================> snkwave_device + +class snkwave_device : public device_t, + public device_sound_interface +{ +public: + snkwave_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + ~snkwave_device() { } + +protected: + // device-level overrides + virtual void device_start(); + + // sound stream update overrides + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + +public: + DECLARE_WRITE8_MEMBER( snkwave_w ); + +private: + void update_waveform(unsigned int offset, UINT8 data); + +private: + sound_stream *m_stream; + int m_external_clock; + int m_sample_rate; + + // data about the sound system + UINT32 m_frequency; + UINT32 m_counter; + int m_waveform_position; + + // decoded waveform table + INT16 m_waveform[SNKWAVE_WAVEFORM_LENGTH]; +}; + +extern const device_type SNKWAVE; + + +#endif /* __SNKWAVE_H__ */ diff --git a/src/devices/sound/sp0250.c b/src/devices/sound/sp0250.c new file mode 100644 index 00000000000..5bf37c4e924 --- /dev/null +++ b/src/devices/sound/sp0250.c @@ -0,0 +1,247 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +/* + GI SP0250 digital LPC sound synthesizer + + By O. Galibert. + + Unknown: + - Exact clock divider + - Exact noise algorithm + - Exact noise pitch (probably ok) + - 7 bits output mapping + - Whether the pitch starts counting from 0 or 1 + + Unimplemented: + - Direct Data test mode (pin 7) + + Sound quite reasonably already though. +*/ + +#include "emu.h" +#include "sp0250.h" + +/* +standard external clock is 3.12MHz +the chip provides a 445.7kHz output clock, which is = 3.12MHz / 7 +therefore I expect the clock divider to be a multiple of 7 +Also there are 6 cascading filter stages so I expect the divider to be a multiple of 6. + +The SP0250 manual states that the original speech is sampled at 10kHz, so the divider +should be 312, but 312 = 39*8 so it doesn't look right because a divider by 39 is unlikely. + +7*6*8 = 336 gives a 9.286kHz sample rate and matches the samples from the Sega boards. +*/ +#define CLOCK_DIVIDER (7*6*8) + +const device_type SP0250 = &device_creator; + +sp0250_device::sp0250_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, SP0250, "SP0250", tag, owner, clock, "sp0250", __FILE__), + device_sound_interface(mconfig, *this), + m_amp(0), + m_pitch(0), + m_repeat(0), + m_pcount(0), + m_rcount(0), + m_playing(0), + m_RNG(0), + m_stream(NULL), + m_voiced(0), + m_fifo_pos(0), + m_drq(*this) +{ + for (int i = 0; i < 15; i++) + { + m_fifo[i] = 0; + } + + for (int i = 0; i < 6; i++) + { + m_filter[i].F = 0; + m_filter[i].B = 0; + m_filter[i].z1 = 0; + m_filter[i].z2 = 0; + } +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void sp0250_device::device_start() +{ + m_RNG = 1; + m_drq.resolve_safe(); + if (!m_drq.isnull()) + { + m_drq( ASSERT_LINE); + machine().scheduler().timer_pulse(attotime::from_hz(clock()) * CLOCK_DIVIDER, timer_expired_delegate(FUNC(sp0250_device::timer_tick), this)); + } + + m_stream = machine().sound().stream_alloc(*this, 0, 1, clock() / CLOCK_DIVIDER); + + save_item(NAME(m_amp)); + save_item(NAME(m_pitch)); + save_item(NAME(m_repeat)); + save_item(NAME(m_pcount)); + save_item(NAME(m_rcount)); + save_item(NAME(m_playing)); + save_item(NAME(m_RNG)); + save_item(NAME(m_voiced)); + save_item(NAME(m_fifo)); + save_item(NAME(m_fifo_pos)); +} + +static UINT16 sp0250_ga(UINT8 v) +{ + return (v & 0x1f) << (v>>5); +} + +static INT16 sp0250_gc(UINT8 v) +{ + // Internal ROM to the chip, cf. manual + static const UINT16 coefs[128] = + { + 0, 9, 17, 25, 33, 41, 49, 57, 65, 73, 81, 89, 97, 105, 113, 121, + 129, 137, 145, 153, 161, 169, 177, 185, 193, 201, 203, 217, 225, 233, 241, 249, + 257, 265, 273, 281, 289, 297, 301, 305, 309, 313, 317, 321, 325, 329, 333, 337, + 341, 345, 349, 353, 357, 361, 365, 369, 373, 377, 381, 385, 389, 393, 397, 401, + 405, 409, 413, 417, 421, 425, 427, 429, 431, 433, 435, 437, 439, 441, 443, 445, + 447, 449, 451, 453, 455, 457, 459, 461, 463, 465, 467, 469, 471, 473, 475, 477, + 479, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, + 496, 497, 498, 499, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511 + }; + INT16 res = coefs[v & 0x7f]; + + if (!(v & 0x80)) + res = -res; + return res; +} + +void sp0250_device::load_values() +{ + int f; + + + m_filter[0].B = sp0250_gc(m_fifo[ 0]); + m_filter[0].F = sp0250_gc(m_fifo[ 1]); + m_amp = sp0250_ga(m_fifo[ 2]); + m_filter[1].B = sp0250_gc(m_fifo[ 3]); + m_filter[1].F = sp0250_gc(m_fifo[ 4]); + m_pitch = m_fifo[ 5]; + m_filter[2].B = sp0250_gc(m_fifo[ 6]); + m_filter[2].F = sp0250_gc(m_fifo[ 7]); + m_repeat = m_fifo[ 8] & 0x3f; + m_voiced = m_fifo[ 8] & 0x40; + m_filter[3].B = sp0250_gc(m_fifo[ 9]); + m_filter[3].F = sp0250_gc(m_fifo[10]); + m_filter[4].B = sp0250_gc(m_fifo[11]); + m_filter[4].F = sp0250_gc(m_fifo[12]); + m_filter[5].B = sp0250_gc(m_fifo[13]); + m_filter[5].F = sp0250_gc(m_fifo[14]); + m_fifo_pos = 0; + m_drq(ASSERT_LINE); + + m_pcount = 0; + m_rcount = 0; + + for (f = 0; f < 6; f++) + m_filter[f].z1 = m_filter[f].z2 = 0; + + m_playing = 1; +} + +TIMER_CALLBACK_MEMBER( sp0250_device::timer_tick ) +{ + m_stream->update(); +} + +WRITE8_MEMBER( sp0250_device::write ) +{ + m_stream->update(); + if (m_fifo_pos != 15) + { + m_fifo[m_fifo_pos++] = data; + if (m_fifo_pos == 15) + m_drq(CLEAR_LINE); + } + else + logerror("%s: overflow SP0250 FIFO\n", machine().describe_context()); +} + + +UINT8 sp0250_device::drq_r() +{ + m_stream->update(); + return (m_fifo_pos == 15) ? CLEAR_LINE : ASSERT_LINE; +} + +//------------------------------------------------- +// sound_stream_update - handle a stream update +//------------------------------------------------- + +void sp0250_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + stream_sample_t *output = outputs[0]; + int i; + for (i = 0; i < samples; i++) + { + if (m_playing) + { + INT16 z0; + int f; + + if (m_voiced) + { + if(!m_pcount) + z0 = m_amp; + else + z0 = 0; + } + else + { + // Borrowing the ay noise generation LFSR + if(m_RNG & 1) + { + z0 = m_amp; + m_RNG ^= 0x24000; + } + else + z0 = -m_amp; + + m_RNG >>= 1; + } + + for (f = 0; f < 6; f++) + { + z0 += ((m_filter[f].z1 * m_filter[f].F) >> 8) + + ((m_filter[f].z2 * m_filter[f].B) >> 9); + m_filter[f].z2 = m_filter[f].z1; + m_filter[f].z1 = z0; + } + + // Physical resolution is only 7 bits, but heh + + // max amplitude is 0x0f80 so we have margin to push up the output + output[i] = z0 << 3; + + m_pcount++; + if (m_pcount >= m_pitch) + { + m_pcount = 0; + m_rcount++; + if (m_rcount >= m_repeat) + m_playing = 0; + } + } + else + output[i] = 0; + + if (!m_playing) + { + if(m_fifo_pos == 15) + load_values(); + } + } +} diff --git a/src/devices/sound/sp0250.h b/src/devices/sound/sp0250.h new file mode 100644 index 00000000000..846a193cfa2 --- /dev/null +++ b/src/devices/sound/sp0250.h @@ -0,0 +1,58 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +#pragma once + +#ifndef __SP0250_H__ +#define __SP0250_H__ + +class sp0250_device : public device_t, + public device_sound_interface +{ +public: + sp0250_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + ~sp0250_device() {} + + template static devcb_base &set_drq_callback(device_t &device, _Object object) { return downcast(device).m_drq.set_callback(object); } + + DECLARE_WRITE8_MEMBER( write ); + UINT8 drq_r(); + +protected: + // device-level overrides + virtual void device_start(); + + // sound stream update overrides + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + +private: + // internal state + INT16 m_amp; + UINT8 m_pitch; + UINT8 m_repeat; + int m_pcount, m_rcount; + int m_playing; + UINT32 m_RNG; + sound_stream * m_stream; + int m_voiced; + UINT8 m_fifo[15]; + int m_fifo_pos; + devcb_write_line m_drq; + + struct + { + INT16 F, B; + INT16 z1, z2; + } m_filter[6]; + + void load_values(); + TIMER_CALLBACK_MEMBER( timer_tick ); +}; + +extern const device_type SP0250; + +#define MCFG_SP0250_DRQ_CALLBACK(_write) \ + devcb = &sp0250_device::set_drq_callback(*device, DEVCB_##_write); + + + +#endif /* __SP0250_H__ */ diff --git a/src/devices/sound/sp0256.c b/src/devices/sound/sp0256.c new file mode 100644 index 00000000000..31071bb247e --- /dev/null +++ b/src/devices/sound/sp0256.c @@ -0,0 +1,1367 @@ +// license:GPL-2.0+ +// copyright-holders:Joseph Zbiciak,Tim Lindner +/* + GI SP0256 Narrator Speech Processor + GI SPB640 Speech Buffer + + By Joe Zbiciak. Ported to MESS by tim lindner. + + Unimplemented: + - Microsequencer repeat count of zero + - Support for non bit-flipped ROMs + - SPB-640 perpherial/RAM bus + + Copyright Joseph Zbiciak, all rights reserved. + Copyright tim lindner, all rights reserved. + + - This source code is released as freeware for non-commercial purposes. + - You are free to use and redistribute this code in modified or + unmodified form, provided you list us in the credits. + - If you modify this source code, you must add a notice to each + modified source file that it has been changed. If you're a nice + person, you will clearly mark each change too. :) + - If you wish to use this for commercial purposes, please contact us at + intvnut@gmail.com (Joseph Zbiciak), tlindner@macmess.org (tim lindner) + - This entire notice must remain in the source code. + + Note: Bit flipping. + This emulation flips the bits on every byte of the memory map during + the sp0256_start() call. + + If the memory map contents is modified during execution (accross of ROM + bank switching) the bitrevbuff() call must be called after the section + of ROM is modified. +*/ + +#include "emu.h" +#include "sp0256.h" + +#define CLOCK_DIVIDER (7*6*8) +#define HIGH_QUALITY + +#define SCBUF_SIZE (4096) /* Must be power of 2 */ +#define SCBUF_MASK (SCBUF_SIZE - 1) +#define PER_PAUSE (64) /* Equiv timing period for pauses. */ +#define PER_NOISE (64) /* Equiv timing period for noise. */ + +#define FIFO_ADDR (0x1800 << 3) /* SP0256 address of SPB260 speech FIFO. */ + +#define VERBOSE 0 +#define DEBUG_FIFO 0 + +#define LOG(x) do { if (VERBOSE) logerror x; } while (0) + +#define LOG_FIFO(x) do { if (DEBUG_FIFO) logerror x; } while (0) + +#define SET_SBY(line_state) { \ + if (m_sby_line != line_state) \ + { \ + m_sby_line = line_state; \ + m_sby_cb(m_sby_line); \ + } \ +} + +/* ======================================================================== */ +/* qtbl -- Coefficient Quantization Table. This comes from a */ +/* SP0250 data sheet, and should be correct for SP0256. */ +/* ======================================================================== */ +static const INT16 qtbl[128] = +{ + 0, 9, 17, 25, 33, 41, 49, 57, + 65, 73, 81, 89, 97, 105, 113, 121, + 129, 137, 145, 153, 161, 169, 177, 185, + 193, 201, 209, 217, 225, 233, 241, 249, + 257, 265, 273, 281, 289, 297, 301, 305, + 309, 313, 317, 321, 325, 329, 333, 337, + 341, 345, 349, 353, 357, 361, 365, 369, + 373, 377, 381, 385, 389, 393, 397, 401, + 405, 409, 413, 417, 421, 425, 427, 429, + 431, 433, 435, 437, 439, 441, 443, 445, + 447, 449, 451, 453, 455, 457, 459, 461, + 463, 465, 467, 469, 471, 473, 475, 477, + 479, 481, 482, 483, 484, 485, 486, 487, + 488, 489, 490, 491, 492, 493, 494, 495, + 496, 497, 498, 499, 500, 501, 502, 503, + 504, 505, 506, 507, 508, 509, 510, 511 +}; + + + +// device type definition +const device_type SP0256 = &device_creator; + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +sp0256_device::sp0256_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, SP0256, "SP0256", tag, owner, clock, "sp0256", __FILE__), + device_sound_interface(mconfig, *this), + m_rom(*this, DEVICE_SELF), + m_drq_cb(*this), + m_sby_cb(*this) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void sp0256_device::device_start() +{ + m_drq_cb.resolve_safe(); + m_sby_cb.resolve_safe(); + m_drq_cb(1); + m_sby_cb(1); + + m_stream = machine().sound().stream_alloc(*this, 0, 1, clock() / CLOCK_DIVIDER); + + /* -------------------------------------------------------------------- */ + /* Configure our internal variables. */ + /* -------------------------------------------------------------------- */ + m_filt.rng = 1; + + /* -------------------------------------------------------------------- */ + /* Allocate a scratch buffer for generating ~10kHz samples. */ + /* -------------------------------------------------------------------- */ + m_scratch = auto_alloc_array(machine(), INT16, SCBUF_SIZE); + save_pointer(NAME(m_scratch), SCBUF_SIZE); + + m_sc_head = m_sc_tail = 0; + + /* -------------------------------------------------------------------- */ + /* Set up the microsequencer's initial state. */ + /* -------------------------------------------------------------------- */ + m_halted = 1; + m_filt.rpt = -1; + m_lrq = 0x8000; + m_page = 0x1000 << 3; + m_silent = 1; + + /* -------------------------------------------------------------------- */ + /* Setup the ROM. */ + /* -------------------------------------------------------------------- */ + // the rom is not supposed to be reversed first; according to Joe Zbiciak. + // see http://forums.bannister.org/ubbthreads.php?ubb=showflat&Number=72385#Post72385 + // TODO: because of this, check if the bitrev functions are even used anywhere else + // bitrevbuff(m_rom, 0, 0xffff); + + m_lrq_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(sp0256_device::set_lrq_timer_proc),this)); + + // save device variables + save_item(NAME(m_sby_line)); + save_item(NAME(m_cur_len)); + save_item(NAME(m_silent)); + save_item(NAME(m_sc_head)); + save_item(NAME(m_sc_tail)); + save_item(NAME(m_lrq)); + save_item(NAME(m_ald)); + save_item(NAME(m_pc)); + save_item(NAME(m_stack)); + save_item(NAME(m_fifo_sel)); + save_item(NAME(m_halted)); + save_item(NAME(m_mode)); + save_item(NAME(m_page)); + save_item(NAME(m_fifo_head)); + save_item(NAME(m_fifo_tail)); + save_item(NAME(m_fifo_bitp)); + save_item(NAME(m_fifo)); + // save filter variables + save_item(NAME(m_filt.rpt)); + save_item(NAME(m_filt.cnt)); + save_item(NAME(m_filt.per)); + save_item(NAME(m_filt.rng)); + save_item(NAME(m_filt.amp)); + save_item(NAME(m_filt.f_coef)); + save_item(NAME(m_filt.b_coef)); + save_item(NAME(m_filt.z_data)); + save_item(NAME(m_filt.r)); + save_item(NAME(m_filt.interp)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void sp0256_device::device_reset() +{ + // reset FIFO and SP0256 + m_fifo_head = m_fifo_tail = m_fifo_bitp = 0; + + memset(&m_filt, 0, sizeof(m_filt)); + m_halted = 1; + m_filt.rpt = -1; + m_filt.rng = 1; + m_lrq = 0x8000; + m_ald = 0x0000; + m_pc = 0x0000; + m_stack = 0x0000; + m_fifo_sel = 0; + m_mode = 0; + m_page = 0x1000 << 3; + m_silent = 1; + m_sby_line = 0; + m_drq_cb(1); + SET_SBY(1) + + m_lrq = 0; + m_lrq_timer->adjust(attotime::from_ticks(50, m_clock)); +} + + + +/* ======================================================================== */ +/* LIMIT -- Limiter function for digital sample output. */ +/* ======================================================================== */ +INLINE INT16 limit(INT16 s) +{ +#ifdef HIGH_QUALITY /* Higher quality than the original, but who cares? */ + if (s > 8191) return 8191; + if (s < -8192) return -8192; +#else + if (s > 127) return 127; + if (s < -128) return -128; +#endif + return s; +} + +/* ======================================================================== */ +/* LPC12_UPDATE -- Update the 12-pole filter, outputting samples. */ +/* ======================================================================== */ +INLINE int lpc12_update(struct lpc12_t *f, int num_samp, INT16 *out, UINT32 *optr) +{ + int i, j; + INT16 samp; + int do_int; + int oidx = *optr; + + /* -------------------------------------------------------------------- */ + /* Iterate up to the desired number of samples. We actually may */ + /* break out early if our repeat count expires. */ + /* -------------------------------------------------------------------- */ + for (i = 0; i < num_samp; i++) + { + /* ---------------------------------------------------------------- */ + /* Generate a series of periodic impulses, or random noise. */ + /* ---------------------------------------------------------------- */ + do_int = 0; + samp = 0; + if (f->per) + { + if (f->cnt <= 0) + { + f->cnt += f->per; + samp = f->amp; + f->rpt--; + do_int = f->interp; + + for (j = 0; j < 6; j++) + f->z_data[j][1] = f->z_data[j][0] = 0; + + } else + { + samp = 0; + f->cnt--; + } + + } else + { + int bit; + + if (--f->cnt <= 0) + { + do_int = f->interp; + f->cnt = PER_NOISE; + f->rpt--; + for (j = 0; j < 6; j++) + f->z_data[j][0] = f->z_data[j][1] = 0; + } + + bit = f->rng & 1; + f->rng = (f->rng >> 1) ^ (bit ? 0x4001 : 0); + + if (bit) { samp = f->amp; } + else { samp = -f->amp; } + } + + /* ---------------------------------------------------------------- */ + /* If we need to, process the interpolation registers. */ + /* ---------------------------------------------------------------- */ + if (do_int) + { + f->r[0] += f->r[14]; + f->r[1] += f->r[15]; + + f->amp = (f->r[0] & 0x1F) << (((f->r[0] & 0xE0) >> 5) + 0); + f->per = f->r[1]; + + do_int = 0; + } + + /* ---------------------------------------------------------------- */ + /* Stop if we expire our repeat counter and return the actual */ + /* number of samples we did. */ + /* ---------------------------------------------------------------- */ + if (f->rpt <= 0) break; + + /* ---------------------------------------------------------------- */ + /* Each 2nd order stage looks like one of these. The App. Manual */ + /* gives the first form, the patent gives the second form. */ + /* They're equivalent except for time delay. I implement the */ + /* first form. (Note: 1/Z == 1 unit of time delay.) */ + /* */ + /* ---->(+)-------->(+)----------+-------> */ + /* ^ ^ | */ + /* | | | */ + /* | | | */ + /* [B] [2*F] | */ + /* ^ ^ | */ + /* | | | */ + /* | | | */ + /* +---[1/Z]<--+---[1/Z]<--+ */ + /* */ + /* */ + /* +---[2*F]<---+ */ + /* | | */ + /* | | */ + /* v | */ + /* ---->(+)-->[1/Z]-->+-->[1/Z]---+------> */ + /* ^ | */ + /* | | */ + /* | | */ + /* +-----------[B]<---------+ */ + /* */ + /* ---------------------------------------------------------------- */ + for (j = 0; j < 6; j++) + { + samp += (((int)f->b_coef[j] * (int)f->z_data[j][1]) >> 9); + samp += (((int)f->f_coef[j] * (int)f->z_data[j][0]) >> 8); + + f->z_data[j][1] = f->z_data[j][0]; + f->z_data[j][0] = samp; + } + +#ifdef HIGH_QUALITY /* Higher quality than the original, but who cares? */ + out[oidx++ & SCBUF_MASK] = limit(samp) << 2; +#else + out[oidx++ & SCBUF_MASK] = (limit(samp >> 4) << 8); +#endif + } + + *optr = oidx; + + return i; +} + +static const int stage_map[6] = { 0, 1, 2, 3, 4, 5 }; + +/* ======================================================================== */ +/* LPC12_REGDEC -- Decode the register set in the filter bank. */ +/* ======================================================================== */ +INLINE void lpc12_regdec(struct lpc12_t *f) +{ + int i; + + /* -------------------------------------------------------------------- */ + /* Decode the Amplitude and Period registers. Force the 'cnt' to 0 */ + /* to get an initial impulse. We compensate elsewhere by setting */ + /* the repeat count to "repeat + 1". */ + /* -------------------------------------------------------------------- */ + f->amp = (f->r[0] & 0x1F) << (((f->r[0] & 0xE0) >> 5) + 0); + f->cnt = 0; + f->per = f->r[1]; + + /* -------------------------------------------------------------------- */ + /* Decode the filter coefficients from the quant table. */ + /* -------------------------------------------------------------------- */ + for (i = 0; i < 6; i++) + { + #define IQ(x) (((x) & 0x80) ? qtbl[0x7F & -(x)] : -qtbl[(x)]) + + f->b_coef[stage_map[i]] = IQ(f->r[2 + 2*i]); + f->f_coef[stage_map[i]] = IQ(f->r[3 + 2*i]); + } + + /* -------------------------------------------------------------------- */ + /* Set the Interp flag based on whether we have interpolation parms */ + /* -------------------------------------------------------------------- */ + f->interp = f->r[14] || f->r[15]; + + return; +} + +/* ======================================================================== */ +/* SP0256_DATAFMT -- Data format table for the SP0256's microsequencer */ +/* */ +/* len 4 bits Length of field to extract */ +/* lshift 4 bits Left-shift amount on field */ +/* param 4 bits Parameter number being updated */ +/* delta 1 bit This is a delta-update. (Implies sign-extend) */ +/* field 1 bit This is a field replace. */ +/* clr5 1 bit Clear F5, B5. */ +/* clrall 1 bit Clear all before doing this update */ +/* ======================================================================== */ + +#define CR(l,s,p,d,f,c5,ca) \ + ( \ + (((l) & 15) << 0) | \ + (((s) & 15) << 4) | \ + (((p) & 15) << 8) | \ + (((d) & 1) << 12) | \ + (((f) & 1) << 13) | \ + (((c5) & 1) << 14) | \ + (((ca) & 1) << 15) \ + ) + +#define CR_DELTA CR(0,0,0,1,0,0,0) +#define CR_FIELD CR(0,0,0,0,1,0,0) +#define CR_CLR5 CR(0,0,0,0,0,1,0) +#define CR_CLRA CR(0,0,0,0,0,0,1) +#define CR_LEN(x) ((x) & 15) +#define CR_SHF(x) (((x) >> 4) & 15) +#define CR_PRM(x) (((x) >> 8) & 15) + +enum { AM = 0, PR, B0, F0, B1, F1, B2, F2, B3, F3, B4, F4, B5, F5, IA, IP }; + +static const UINT16 sp0256_datafmt[] = +{ + /* -------------------------------------------------------------------- */ + /* OPCODE 1111: PAUSE */ + /* -------------------------------------------------------------------- */ + /* 0 */ CR( 0, 0, 0, 0, 0, 0, 1), /* Clear all */ + + /* -------------------------------------------------------------------- */ + /* Opcode 0001: LOADALL */ + /* -------------------------------------------------------------------- */ + /* All modes */ + /* 1 */ CR( 8, 0, AM, 0, 0, 0, 1), /* Amplitude */ + /* 2 */ CR( 8, 0, PR, 0, 0, 0, 0), /* Period */ + /* 3 */ CR( 8, 0, B0, 0, 0, 0, 0), /* B0 */ + /* 4 */ CR( 8, 0, F0, 0, 0, 0, 0), /* F0 */ + /* 5 */ CR( 8, 0, B1, 0, 0, 0, 0), /* B1 */ + /* 6 */ CR( 8, 0, F1, 0, 0, 0, 0), /* F1 */ + /* 7 */ CR( 8, 0, B2, 0, 0, 0, 0), /* B2 */ + /* 8 */ CR( 8, 0, F2, 0, 0, 0, 0), /* F2 */ + /* 9 */ CR( 8, 0, B3, 0, 0, 0, 0), /* B3 */ + /* 10 */ CR( 8, 0, F3, 0, 0, 0, 0), /* F3 */ + /* 11 */ CR( 8, 0, B4, 0, 0, 0, 0), /* B4 */ + /* 12 */ CR( 8, 0, F4, 0, 0, 0, 0), /* F4 */ + /* 13 */ CR( 8, 0, B5, 0, 0, 0, 0), /* B5 */ + /* 14 */ CR( 8, 0, F5, 0, 0, 0, 0), /* F5 */ + /* Mode 01 and 11 only */ + /* 15 */ CR( 8, 0, IA, 0, 0, 0, 0), /* Amp Interp */ + /* 16 */ CR( 8, 0, IP, 0, 0, 0, 0), /* Pit Interp */ + + /* -------------------------------------------------------------------- */ + /* Opcode 0100: LOAD_4 */ + /* -------------------------------------------------------------------- */ + /* Mode 00 and 01 */ + /* 17 */ CR( 6, 2, AM, 0, 0, 0, 1), /* Amplitude */ + /* 18 */ CR( 8, 0, PR, 0, 0, 0, 0), /* Period */ + /* 19 */ CR( 4, 3, B3, 0, 0, 0, 0), /* B3 (S=0) */ + /* 20 */ CR( 6, 2, F3, 0, 0, 0, 0), /* F3 */ + /* 21 */ CR( 7, 1, B4, 0, 0, 0, 0), /* B4 */ + /* 22 */ CR( 6, 2, F4, 0, 0, 0, 0), /* F4 */ + /* Mode 01 only */ + /* 23 */ CR( 8, 0, B5, 0, 0, 0, 0), /* B5 */ + /* 24 */ CR( 8, 0, F5, 0, 0, 0, 0), /* F5 */ + + /* Mode 10 and 11 */ + /* 25 */ CR( 6, 2, AM, 0, 0, 0, 1), /* Amplitude */ + /* 26 */ CR( 8, 0, PR, 0, 0, 0, 0), /* Period */ + /* 27 */ CR( 6, 1, B3, 0, 0, 0, 0), /* B3 (S=0) */ + /* 28 */ CR( 7, 1, F3, 0, 0, 0, 0), /* F3 */ + /* 29 */ CR( 8, 0, B4, 0, 0, 0, 0), /* B4 */ + /* 30 */ CR( 8, 0, F4, 0, 0, 0, 0), /* F4 */ + /* Mode 11 only */ + /* 31 */ CR( 8, 0, B5, 0, 0, 0, 0), /* B5 */ + /* 32 */ CR( 8, 0, F5, 0, 0, 0, 0), /* F5 */ + + /* -------------------------------------------------------------------- */ + /* Opcode 0110: SETMSB_6 */ + /* -------------------------------------------------------------------- */ + /* Mode 00 only */ + /* 33 */ CR( 0, 0, 0, 0, 0, 1, 0), /* Clear 5 */ + /* Mode 00 and 01 */ + /* 34 */ CR( 6, 2, AM, 0, 0, 0, 0), /* Amplitude */ + /* 35 */ CR( 6, 2, F3, 0, 1, 0, 0), /* F3 (5 MSBs) */ + /* 36 */ CR( 6, 2, F4, 0, 1, 0, 0), /* F4 (5 MSBs) */ + /* Mode 01 only */ + /* 37 */ CR( 8, 0, F5, 0, 1, 0, 0), /* F5 (5 MSBs) */ + + /* Mode 10 only */ + /* 38 */ CR( 0, 0, 0, 0, 0, 1, 0), /* Clear 5 */ + /* Mode 10 and 11 */ + /* 39 */ CR( 6, 2, AM, 0, 0, 0, 0), /* Amplitude */ + /* 40 */ CR( 7, 1, F3, 0, 1, 0, 0), /* F3 (6 MSBs) */ + /* 41 */ CR( 8, 0, F4, 0, 1, 0, 0), /* F4 (6 MSBs) */ + /* Mode 11 only */ + /* 42 */ CR( 8, 0, F5, 0, 1, 0, 0), /* F5 (6 MSBs) */ + + /* 43 */ 0, /* unused */ + /* 44 */ 0, /* unused */ + + /* -------------------------------------------------------------------- */ + /* Opcode 1001: DELTA_9 */ + /* -------------------------------------------------------------------- */ + /* Mode 00 and 01 */ + /* 45 */ CR( 4, 2, AM, 1, 0, 0, 0), /* Amplitude */ + /* 46 */ CR( 5, 0, PR, 1, 0, 0, 0), /* Period */ + /* 47 */ CR( 3, 4, B0, 1, 0, 0, 0), /* B0 4 MSBs */ + /* 48 */ CR( 3, 3, F0, 1, 0, 0, 0), /* F0 5 MSBs */ + /* 49 */ CR( 3, 4, B1, 1, 0, 0, 0), /* B1 4 MSBs */ + /* 50 */ CR( 3, 3, F1, 1, 0, 0, 0), /* F1 5 MSBs */ + /* 51 */ CR( 3, 4, B2, 1, 0, 0, 0), /* B2 4 MSBs */ + /* 52 */ CR( 3, 3, F2, 1, 0, 0, 0), /* F2 5 MSBs */ + /* 53 */ CR( 3, 3, B3, 1, 0, 0, 0), /* B3 5 MSBs */ + /* 54 */ CR( 4, 2, F3, 1, 0, 0, 0), /* F3 6 MSBs */ + /* 55 */ CR( 4, 1, B4, 1, 0, 0, 0), /* B4 7 MSBs */ + /* 56 */ CR( 4, 2, F4, 1, 0, 0, 0), /* F4 6 MSBs */ + /* Mode 01 only */ + /* 57 */ CR( 5, 0, B5, 1, 0, 0, 0), /* B5 8 MSBs */ + /* 58 */ CR( 5, 0, F5, 1, 0, 0, 0), /* F5 8 MSBs */ + + /* Mode 10 and 11 */ + /* 59 */ CR( 4, 2, AM, 1, 0, 0, 0), /* Amplitude */ + /* 60 */ CR( 5, 0, PR, 1, 0, 0, 0), /* Period */ + /* 61 */ CR( 4, 1, B0, 1, 0, 0, 0), /* B0 7 MSBs */ + /* 62 */ CR( 4, 2, F0, 1, 0, 0, 0), /* F0 6 MSBs */ + /* 63 */ CR( 4, 1, B1, 1, 0, 0, 0), /* B1 7 MSBs */ + /* 64 */ CR( 4, 2, F1, 1, 0, 0, 0), /* F1 6 MSBs */ + /* 65 */ CR( 4, 1, B2, 1, 0, 0, 0), /* B2 7 MSBs */ + /* 66 */ CR( 4, 2, F2, 1, 0, 0, 0), /* F2 6 MSBs */ + /* 67 */ CR( 4, 1, B3, 1, 0, 0, 0), /* B3 7 MSBs */ + /* 68 */ CR( 5, 1, F3, 1, 0, 0, 0), /* F3 7 MSBs */ + /* 69 */ CR( 5, 0, B4, 1, 0, 0, 0), /* B4 8 MSBs */ + /* 70 */ CR( 5, 0, F4, 1, 0, 0, 0), /* F4 8 MSBs */ + /* Mode 11 only */ + /* 71 */ CR( 5, 0, B5, 1, 0, 0, 0), /* B5 8 MSBs */ + /* 72 */ CR( 5, 0, F5, 1, 0, 0, 0), /* F5 8 MSBs */ + + /* -------------------------------------------------------------------- */ + /* Opcode 1010: SETMSB_A */ + /* -------------------------------------------------------------------- */ + /* Mode 00 only */ + /* 73 */ CR( 0, 0, 0, 0, 0, 1, 0), /* Clear 5 */ + /* Mode 00 and 01 */ + /* 74 */ CR( 6, 2, AM, 0, 0, 0, 0), /* Amplitude */ + /* 75 */ CR( 5, 3, F0, 0, 1, 0, 0), /* F0 (5 MSBs) */ + /* 76 */ CR( 5, 3, F1, 0, 1, 0, 0), /* F1 (5 MSBs) */ + /* 77 */ CR( 5, 3, F2, 0, 1, 0, 0), /* F2 (5 MSBs) */ + + /* Mode 10 only */ + /* 78 */ CR( 0, 0, 0, 0, 0, 1, 0), /* Clear 5 */ + /* Mode 10 and 11 */ + /* 79 */ CR( 6, 2, AM, 0, 0, 0, 0), /* Amplitude */ + /* 80 */ CR( 6, 2, F0, 0, 1, 0, 0), /* F0 (6 MSBs) */ + /* 81 */ CR( 6, 2, F1, 0, 1, 0, 0), /* F1 (6 MSBs) */ + /* 82 */ CR( 6, 2, F2, 0, 1, 0, 0), /* F2 (6 MSBs) */ + + /* -------------------------------------------------------------------- */ + /* Opcode 0010: LOAD_2 Mode 00 and 10 */ + /* Opcode 1100: LOAD_C Mode 00 and 10 */ + /* -------------------------------------------------------------------- */ + /* LOAD_2, LOAD_C Mode 00 */ + /* 83 */ CR( 6, 2, AM, 0, 0, 0, 1), /* Amplitude */ + /* 84 */ CR( 8, 0, PR, 0, 0, 0, 0), /* Period */ + /* 85 */ CR( 3, 4, B0, 0, 0, 0, 0), /* B0 (S=0) */ + /* 86 */ CR( 5, 3, F0, 0, 0, 0, 0), /* F0 */ + /* 87 */ CR( 3, 4, B1, 0, 0, 0, 0), /* B1 (S=0) */ + /* 88 */ CR( 5, 3, F1, 0, 0, 0, 0), /* F1 */ + /* 89 */ CR( 3, 4, B2, 0, 0, 0, 0), /* B2 (S=0) */ + /* 90 */ CR( 5, 3, F2, 0, 0, 0, 0), /* F2 */ + /* 91 */ CR( 4, 3, B3, 0, 0, 0, 0), /* B3 (S=0) */ + /* 92 */ CR( 6, 2, F3, 0, 0, 0, 0), /* F3 */ + /* 93 */ CR( 7, 1, B4, 0, 0, 0, 0), /* B4 */ + /* 94 */ CR( 6, 2, F4, 0, 0, 0, 0), /* F4 */ + /* LOAD_2 only */ + /* 95 */ CR( 5, 0, IA, 0, 0, 0, 0), /* Ampl. Intr. */ + /* 96 */ CR( 5, 0, IP, 0, 0, 0, 0), /* Per. Intr. */ + + /* LOAD_2, LOAD_C Mode 10 */ + /* 97 */ CR( 6, 2, AM, 0, 0, 0, 1), /* Amplitude */ + /* 98 */ CR( 8, 0, PR, 0, 0, 0, 0), /* Period */ + /* 99 */ CR( 6, 1, B0, 0, 0, 0, 0), /* B0 (S=0) */ + /* 100 */ CR( 6, 2, F0, 0, 0, 0, 0), /* F0 */ + /* 101 */ CR( 6, 1, B1, 0, 0, 0, 0), /* B1 (S=0) */ + /* 102 */ CR( 6, 2, F1, 0, 0, 0, 0), /* F1 */ + /* 103 */ CR( 6, 1, B2, 0, 0, 0, 0), /* B2 (S=0) */ + /* 104 */ CR( 6, 2, F2, 0, 0, 0, 0), /* F2 */ + /* 105 */ CR( 6, 1, B3, 0, 0, 0, 0), /* B3 (S=0) */ + /* 106 */ CR( 7, 1, F3, 0, 0, 0, 0), /* F3 */ + /* 107 */ CR( 8, 0, B4, 0, 0, 0, 0), /* B4 */ + /* 108 */ CR( 8, 0, F4, 0, 0, 0, 0), /* F4 */ + /* LOAD_2 only */ + /* 109 */ CR( 5, 0, IA, 0, 0, 0, 0), /* Ampl. Intr. */ + /* 110 */ CR( 5, 0, IP, 0, 0, 0, 0), /* Per. Intr. */ + + /* -------------------------------------------------------------------- */ + /* OPCODE 1101: DELTA_D */ + /* -------------------------------------------------------------------- */ + /* Mode 00 and 01 */ + /* 111 */ CR( 4, 2, AM, 1, 0, 0, 0), /* Amplitude */ + /* 112 */ CR( 5, 0, PR, 1, 0, 0, 0), /* Period */ + /* 113 */ CR( 3, 3, B3, 1, 0, 0, 0), /* B3 5 MSBs */ + /* 114 */ CR( 4, 2, F3, 1, 0, 0, 0), /* F3 6 MSBs */ + /* 115 */ CR( 4, 1, B4, 1, 0, 0, 0), /* B4 7 MSBs */ + /* 116 */ CR( 4, 2, F4, 1, 0, 0, 0), /* F4 6 MSBs */ + /* Mode 01 only */ + /* 117 */ CR( 5, 0, B5, 1, 0, 0, 0), /* B5 8 MSBs */ + /* 118 */ CR( 5, 0, F5, 1, 0, 0, 0), /* F5 8 MSBs */ + + /* Mode 10 and 11 */ + /* 119 */ CR( 4, 2, AM, 1, 0, 0, 0), /* Amplitude */ + /* 120 */ CR( 5, 0, PR, 1, 0, 0, 0), /* Period */ + /* 121 */ CR( 4, 1, B3, 1, 0, 0, 0), /* B3 7 MSBs */ + /* 122 */ CR( 5, 1, F3, 1, 0, 0, 0), /* F3 7 MSBs */ + /* 123 */ CR( 5, 0, B4, 1, 0, 0, 0), /* B4 8 MSBs */ + /* 124 */ CR( 5, 0, F4, 1, 0, 0, 0), /* F4 8 MSBs */ + /* Mode 11 only */ + /* 125 */ CR( 5, 0, B5, 1, 0, 0, 0), /* B5 8 MSBs */ + /* 126 */ CR( 5, 0, F5, 1, 0, 0, 0), /* F5 8 MSBs */ + + /* -------------------------------------------------------------------- */ + /* OPCODE 1110: LOAD_E */ + /* -------------------------------------------------------------------- */ + /* 127 */ CR( 6, 2, AM, 0, 0, 0, 0), /* Amplitude */ + /* 128 */ CR( 8, 0, PR, 0, 0, 0, 0), /* Period */ + + /* -------------------------------------------------------------------- */ + /* Opcode 0010: LOAD_2 Mode 01 and 11 */ + /* Opcode 1100: LOAD_C Mode 01 and 11 */ + /* -------------------------------------------------------------------- */ + /* LOAD_2, LOAD_C Mode 01 */ + /* 129 */ CR( 6, 2, AM, 0, 0, 0, 1), /* Amplitude */ + /* 130 */ CR( 8, 0, PR, 0, 0, 0, 0), /* Period */ + /* 131 */ CR( 3, 4, B0, 0, 0, 0, 0), /* B0 (S=0) */ + /* 132 */ CR( 5, 3, F0, 0, 0, 0, 0), /* F0 */ + /* 133 */ CR( 3, 4, B1, 0, 0, 0, 0), /* B1 (S=0) */ + /* 134 */ CR( 5, 3, F1, 0, 0, 0, 0), /* F1 */ + /* 135 */ CR( 3, 4, B2, 0, 0, 0, 0), /* B2 (S=0) */ + /* 136 */ CR( 5, 3, F2, 0, 0, 0, 0), /* F2 */ + /* 137 */ CR( 4, 3, B3, 0, 0, 0, 0), /* B3 (S=0) */ + /* 138 */ CR( 6, 2, F3, 0, 0, 0, 0), /* F3 */ + /* 139 */ CR( 7, 1, B4, 0, 0, 0, 0), /* B4 */ + /* 140 */ CR( 6, 2, F4, 0, 0, 0, 0), /* F4 */ + /* 141 */ CR( 8, 0, B5, 0, 0, 0, 0), /* B5 */ + /* 142 */ CR( 8, 0, F5, 0, 0, 0, 0), /* F5 */ + /* LOAD_2 only */ + /* 143 */ CR( 5, 0, IA, 0, 0, 0, 0), /* Ampl. Intr. */ + /* 144 */ CR( 5, 0, IP, 0, 0, 0, 0), /* Per. Intr. */ + + /* LOAD_2, LOAD_C Mode 11 */ + /* 145 */ CR( 6, 2, AM, 0, 0, 0, 1), /* Amplitude */ + /* 146 */ CR( 8, 0, PR, 0, 0, 0, 0), /* Period */ + /* 147 */ CR( 6, 1, B0, 0, 0, 0, 0), /* B0 (S=0) */ + /* 148 */ CR( 6, 2, F0, 0, 0, 0, 0), /* F0 */ + /* 149 */ CR( 6, 1, B1, 0, 0, 0, 0), /* B1 (S=0) */ + /* 150 */ CR( 6, 2, F1, 0, 0, 0, 0), /* F1 */ + /* 151 */ CR( 6, 1, B2, 0, 0, 0, 0), /* B2 (S=0) */ + /* 152 */ CR( 6, 2, F2, 0, 0, 0, 0), /* F2 */ + /* 153 */ CR( 6, 1, B3, 0, 0, 0, 0), /* B3 (S=0) */ + /* 154 */ CR( 7, 1, F3, 0, 0, 0, 0), /* F3 */ + /* 155 */ CR( 8, 0, B4, 0, 0, 0, 0), /* B4 */ + /* 156 */ CR( 8, 0, F4, 0, 0, 0, 0), /* F4 */ + /* 157 */ CR( 8, 0, B5, 0, 0, 0, 0), /* B5 */ + /* 158 */ CR( 8, 0, F5, 0, 0, 0, 0), /* F5 */ + /* LOAD_2 only */ + /* 159 */ CR( 5, 0, IA, 0, 0, 0, 0), /* Ampl. Intr. */ + /* 160 */ CR( 5, 0, IP, 0, 0, 0, 0), /* Per. Intr. */ + + /* -------------------------------------------------------------------- */ + /* Opcode 0011: SETMSB_3 */ + /* Opcode 0101: SETMSB_5 */ + /* -------------------------------------------------------------------- */ + /* Mode 00 only */ + /* 161 */ CR( 0, 0, 0, 0, 0, 1, 0), /* Clear 5 */ + /* Mode 00 and 01 */ + /* 162 */ CR( 6, 2, AM, 0, 0, 0, 0), /* Amplitude */ + /* 163 */ CR( 8, 0, PR, 0, 0, 0, 0), /* Period */ + /* 164 */ CR( 5, 3, F0, 0, 1, 0, 0), /* F0 (5 MSBs) */ + /* 165 */ CR( 5, 3, F1, 0, 1, 0, 0), /* F1 (5 MSBs) */ + /* 166 */ CR( 5, 3, F2, 0, 1, 0, 0), /* F2 (5 MSBs) */ + /* SETMSB_3 only */ + /* 167 */ CR( 5, 0, IA, 0, 0, 0, 0), /* Ampl. Intr. */ + /* 168 */ CR( 5, 0, IP, 0, 0, 0, 0), /* Per. Intr. */ + + /* Mode 10 only */ + /* 169 */ CR( 0, 0, 0, 0, 0, 1, 0), /* Clear 5 */ + /* Mode 10 and 11 */ + /* 170 */ CR( 6, 2, AM, 0, 0, 0, 0), /* Amplitude */ + /* 171 */ CR( 8, 0, PR, 0, 0, 0, 0), /* Period */ + /* 172 */ CR( 6, 2, F0, 0, 1, 0, 0), /* F0 (6 MSBs) */ + /* 173 */ CR( 6, 2, F1, 0, 1, 0, 0), /* F1 (6 MSBs) */ + /* 174 */ CR( 6, 2, F2, 0, 1, 0, 0), /* F2 (6 MSBs) */ + /* SETMSB_3 only */ + /* 175 */ CR( 5, 0, IA, 0, 0, 0, 0), /* Ampl. Intr. */ + /* 176 */ CR( 5, 0, IP, 0, 0, 0, 0), /* Per. Intr. */ +}; + +static const INT16 sp0256_df_idx[16 * 8] = +{ + /* OPCODE 0000 */ -1, -1, -1, -1, -1, -1, -1, -1, + /* OPCODE 1000 */ -1, -1, -1, -1, -1, -1, -1, -1, + /* OPCODE 0100 */ 17, 22, 17, 24, 25, 30, 25, 32, + /* OPCODE 1100 */ 83, 94, 129,142, 97, 108, 145,158, + /* OPCODE 0010 */ 83, 96, 129,144, 97, 110, 145,160, + /* OPCODE 1010 */ 73, 77, 74, 77, 78, 82, 79, 82, + /* OPCODE 0110 */ 33, 36, 34, 37, 38, 41, 39, 42, + /* OPCODE 1110 */ 127,128, 127,128, 127,128, 127,128, + /* OPCODE 0001 */ 1, 14, 1, 16, 1, 14, 1, 16, + /* OPCODE 1001 */ 45, 56, 45, 58, 59, 70, 59, 72, + /* OPCODE 0101 */ 161,166, 162,166, 169,174, 170,174, + /* OPCODE 1101 */ 111,116, 111,118, 119,124, 119,126, + /* OPCODE 0011 */ 161,168, 162,168, 169,176, 170,176, + /* OPCODE 1011 */ -1, -1, -1, -1, -1, -1, -1, -1, + /* OPCODE 0111 */ -1, -1, -1, -1, -1, -1, -1, -1, + /* OPCODE 1111 */ 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* ======================================================================== */ +/* BITREV32 -- Bit-reverse a 32-bit number. */ +/* ======================================================================== */ +INLINE UINT32 bitrev32(UINT32 val) +{ + val = ((val & 0xFFFF0000) >> 16) | ((val & 0x0000FFFF) << 16); + val = ((val & 0xFF00FF00) >> 8) | ((val & 0x00FF00FF) << 8); + val = ((val & 0xF0F0F0F0) >> 4) | ((val & 0x0F0F0F0F) << 4); + val = ((val & 0xCCCCCCCC) >> 2) | ((val & 0x33333333) << 2); + val = ((val & 0xAAAAAAAA) >> 1) | ((val & 0x55555555) << 1); + + return val; +} + +/* ======================================================================== */ +/* BITREV8 -- Bit-reverse a 8-bit number. */ +/* ======================================================================== */ +INLINE UINT8 bitrev8(UINT8 val) +{ + val = ((val & 0xF0) >> 4) | ((val & 0x0F) << 4); + val = ((val & 0xCC) >> 2) | ((val & 0x33) << 2); + val = ((val & 0xAA) >> 1) | ((val & 0x55) << 1); + + return val; +} + +/* ======================================================================== */ +/* BITREVBUFF -- Bit-reverse a buffer. */ +/* ======================================================================== */ +void sp0256_device::bitrevbuff(UINT8 *buffer, unsigned int start, unsigned int length) +{ + for (unsigned int i = start; i < length; i++ ) + buffer[i] = bitrev8(buffer[i]); +} + +/* ======================================================================== */ +/* SP0256_GETB -- Get up to 8 bits at the current PC. */ +/* ======================================================================== */ +UINT32 sp0256_device::getb( int len ) +{ + UINT32 data = 0; + UINT32 d0, d1; + + /* -------------------------------------------------------------------- */ + /* Fetch data from the FIFO or from the MASK */ + /* -------------------------------------------------------------------- */ + if (m_fifo_sel) + { + d0 = m_fifo[(m_fifo_tail ) & 63]; + d1 = m_fifo[(m_fifo_tail + 1) & 63]; + + data = ((d1 << 10) | d0) >> m_fifo_bitp; + + LOG_FIFO(("sp0256: RD_FIFO %.3X %d.%d %d\n", data & ((1 << len) - 1), + m_fifo_tail, m_fifo_bitp, m_fifo_head)); + + /* ---------------------------------------------------------------- */ + /* Note the PC doesn't advance when we execute from FIFO. */ + /* Just the FIFO's bit-pointer advances. (That's not REALLY */ + /* what happens, but that's roughly how it behaves.) */ + /* ---------------------------------------------------------------- */ + m_fifo_bitp += len; + if (m_fifo_bitp >= 10) + { + m_fifo_tail++; + m_fifo_bitp -= 10; + } + } else + { + /* ---------------------------------------------------------------- */ + /* Figure out which ROMs are being fetched into, and grab two */ + /* adjacent bytes. The byte we're interested in is extracted */ + /* from the appropriate bit-boundary between them. */ + /* ---------------------------------------------------------------- */ + int idx0 = (m_pc ) >> 3, d0; + int idx1 = (m_pc + 8) >> 3, d1; + + d0 = m_rom[idx0 & 0xffff]; + d1 = m_rom[idx1 & 0xffff]; + + data = ((d1 << 8) | d0) >> (m_pc & 7); + + m_pc += len; + } + + /* -------------------------------------------------------------------- */ + /* Mask data to the requested length. */ + /* -------------------------------------------------------------------- */ + data &= ((1 << len) - 1); + + return data; +} + +/* ======================================================================== */ +/* SP0256_MICRO -- Emulate the microsequencer in the SP0256. Executes */ +/* instructions either until the repeat count != 0 or */ +/* the sequencer gets halted by a RTS to 0. */ +/* ======================================================================== */ +void sp0256_device::micro() +{ + UINT8 immed4; + UINT8 opcode; + UINT16 cr; + int ctrl_xfer = 0; + int repeat = 0; + int i, idx0, idx1; + + /* -------------------------------------------------------------------- */ + /* Only execute instructions while the filter is not busy. */ + /* -------------------------------------------------------------------- */ + while (m_filt.rpt <= 0) + { + /* ---------------------------------------------------------------- */ + /* If the CPU is halted, see if we have a new command pending */ + /* in the Address LoaD buffer. */ + /* ---------------------------------------------------------------- */ + if (m_halted && !m_lrq) + { + m_pc = m_ald | (0x1000 << 3); + m_fifo_sel = 0; + m_halted = 0; + m_lrq = 0x8000; + m_ald = 0; + for (i = 0; i < 16; i++) + m_filt.r[i] = 0; + m_drq_cb(1); + } + + /* ---------------------------------------------------------------- */ + /* If we're still halted, do nothing. */ + /* ---------------------------------------------------------------- */ + if (m_halted) + { + m_filt.rpt = 1; + m_lrq = 0x8000; + m_ald = 0; + for (i = 0; i < 16; i++) + m_filt.r[i] = 0; + + SET_SBY(1) + + return; + } + + /* ---------------------------------------------------------------- */ + /* Fetch the first 8 bits of the opcode, which are always in the */ + /* same approximate format -- immed4 followed by opcode. */ + /* ---------------------------------------------------------------- */ + immed4 = getb(4); + opcode = getb(4); + repeat = 0; + ctrl_xfer = 0; + + LOG(("$%.4X.%.1X: OPCODE %d%d%d%d.%d%d\n", + (m_pc >> 3) - 1, m_pc & 7, + !!(opcode & 1), !!(opcode & 2), + !!(opcode & 4), !!(opcode & 8), + !!(m_mode&4), !!(m_mode&2))); + + /* ---------------------------------------------------------------- */ + /* Handle the special cases for specific opcodes. */ + /* ---------------------------------------------------------------- */ + switch (opcode) + { + /* ------------------------------------------------------------ */ + /* OPCODE 0000: RTS / SETPAGE */ + /* ------------------------------------------------------------ */ + case 0x0: + { + /* -------------------------------------------------------- */ + /* If immed4 != 0, then this is a SETPAGE instruction. */ + /* -------------------------------------------------------- */ + if (immed4) /* SETPAGE */ + { + m_page = bitrev32(immed4) >> 13; + } else + /* -------------------------------------------------------- */ + /* Otherwise, this is an RTS / HLT. */ + /* -------------------------------------------------------- */ + { + UINT32 btrg; + + /* ---------------------------------------------------- */ + /* Figure out our branch target. */ + /* ---------------------------------------------------- */ + btrg = m_stack; + + m_stack = 0; + + /* ---------------------------------------------------- */ + /* If the branch target is zero, this is a HLT. */ + /* Otherwise, it's an RTS, so set the PC. */ + /* ---------------------------------------------------- */ + if (!btrg) + { + m_halted = 1; + m_pc = 0; + ctrl_xfer = 1; + } else + { + m_pc = btrg; + ctrl_xfer = 1; + } + } + + break; + } + + /* ------------------------------------------------------------ */ + /* OPCODE 0111: JMP Jump to 12-bit/16-bit Abs Addr */ + /* OPCODE 1011: JSR Jump to Subroutine */ + /* ------------------------------------------------------------ */ + case 0xE: + case 0xD: + { + int btrg; + + /* -------------------------------------------------------- */ + /* Figure out our branch target. */ + /* -------------------------------------------------------- */ + btrg = m_page | + (bitrev32(immed4) >> 17) | + (bitrev32(getb(8)) >> 21); + ctrl_xfer = 1; + + /* -------------------------------------------------------- */ + /* If this is a JSR, push our return address on the */ + /* stack. Make sure it's byte aligned. */ + /* -------------------------------------------------------- */ + if (opcode == 0xD) + m_stack = (m_pc + 7) & ~7; + + /* -------------------------------------------------------- */ + /* Jump to the new location! */ + /* -------------------------------------------------------- */ + m_pc = btrg; + break; + } + + /* ------------------------------------------------------------ */ + /* OPCODE 1000: SETMODE Set the Mode and Repeat MSBs */ + /* ------------------------------------------------------------ */ + case 0x1: + { + m_mode = ((immed4 & 8) >> 2) | (immed4 & 4) | ((immed4 & 3) << 4); + break; + } + + /* ------------------------------------------------------------ */ + /* OPCODE 0001: LOADALL Load All Parameters */ + /* OPCODE 0010: LOAD_2 Load Per, Ampl, Coefs, Interp. */ + /* OPCODE 0011: SETMSB_3 Load Pitch, Ampl, MSBs, & Intrp */ + /* OPCODE 0100: LOAD_4 Load Pitch, Ampl, Coeffs */ + /* OPCODE 0101: SETMSB_5 Load Pitch, Ampl, and Coeff MSBs */ + /* OPCODE 0110: SETMSB_6 Load Ampl, and Coeff MSBs. */ + /* OPCODE 1001: DELTA_9 Delta update Ampl, Pitch, Coeffs */ + /* OPCODE 1010: SETMSB_A Load Ampl and MSBs of 3 Coeffs */ + /* OPCODE 1100: LOAD_C Load Pitch, Ampl, Coeffs */ + /* OPCODE 1101: DELTA_D Delta update Ampl, Pitch, Coeffs */ + /* OPCODE 1110: LOAD_E Load Pitch, Amplitude */ + /* OPCODE 1111: PAUSE Silent pause */ + /* ------------------------------------------------------------ */ + default: + { + repeat = immed4 | (m_mode & 0x30); + break; + } + } + if (opcode != 1) m_mode &= 0xF; + + /* ---------------------------------------------------------------- */ + /* If this was a control transfer, handle setting "fifo_sel" */ + /* and all that ugliness. */ + /* ---------------------------------------------------------------- */ + if (ctrl_xfer) + { + LOG(("jumping to $%.4X.%.1X: ", m_pc >> 3, m_pc & 7)); + + /* ------------------------------------------------------------ */ + /* Set our "FIFO Selected" flag based on whether we're going */ + /* to the FIFO's address. */ + /* ------------------------------------------------------------ */ + m_fifo_sel = m_pc == FIFO_ADDR; + + LOG(("%s ", m_fifo_sel ? "FIFO" : "ROM")); + + /* ------------------------------------------------------------ */ + /* Control transfers to the FIFO cause it to discard the */ + /* partial decle that's at the front of the FIFO. */ + /* ------------------------------------------------------------ */ + if (m_fifo_sel && m_fifo_bitp) + { + LOG(("bitp = %d -> Flush", m_fifo_bitp)); + + /* Discard partially-read decle. */ + if (m_fifo_tail < m_fifo_head) m_fifo_tail++; + m_fifo_bitp = 0; + } + + LOG(("\n")); + + continue; + } + + /* ---------------------------------------------------------------- */ + /* Otherwise, if we have a repeat count, then go grab the data */ + /* block and feed it to the filter. */ + /* ---------------------------------------------------------------- */ + if (!repeat) continue; + + m_filt.rpt = repeat + 1; + LOG(("repeat = %d\n", repeat)); + + i = (opcode << 3) | (m_mode & 6); + idx0 = sp0256_df_idx[i++]; + idx1 = sp0256_df_idx[i ]; + + assert(idx0 >= 0 && idx1 >= 0 && idx1 >= idx0); + + /* ---------------------------------------------------------------- */ + /* Step through control words in the description for data block. */ + /* ---------------------------------------------------------------- */ + for (i = idx0; i <= idx1; i++) + { + int len, shf, delta, field, prm, clra, clr5; + INT8 value; + + /* ------------------------------------------------------------ */ + /* Get the control word and pull out some important fields. */ + /* ------------------------------------------------------------ */ + cr = sp0256_datafmt[i]; + + len = CR_LEN(cr); + shf = CR_SHF(cr); + prm = CR_PRM(cr); + clra = cr & CR_CLRA; + clr5 = cr & CR_CLR5; + delta = cr & CR_DELTA; + field = cr & CR_FIELD; + value = 0; + + LOG(("$%.4X.%.1X: len=%2d shf=%2d prm=%2d d=%d f=%d ", + m_pc >> 3, m_pc & 7, len, shf, prm, !!delta, !!field)); + /* ------------------------------------------------------------ */ + /* Clear any registers that were requested to be cleared. */ + /* ------------------------------------------------------------ */ + if (clra) + { + for (int j = 0; j < 16; j++) + m_filt.r[j] = 0; + + m_silent = 1; + } + + if (clr5) + m_filt.r[B5] = m_filt.r[F5] = 0; + + /* ------------------------------------------------------------ */ + /* If this entry has a bitfield with it, grab the bitfield. */ + /* ------------------------------------------------------------ */ + if (len) + { + value = getb(len); + } + else + { + LOG((" (no update)\n")); + continue; + } + + /* ------------------------------------------------------------ */ + /* Sign extend if this is a delta update. */ + /* ------------------------------------------------------------ */ + if (delta) /* Sign extend */ + { + if (value & (1 << (len - 1))) value |= -1 << len; + } + + /* ------------------------------------------------------------ */ + /* Shift the value to the appropriate precision. */ + /* ------------------------------------------------------------ */ + if (shf) + value <<= shf; + + LOG(("v=%.2X (%c%.2X) ", value & 0xFF, + value & 0x80 ? '-' : '+', + 0xFF & (value & 0x80 ? -value : value))); + + m_silent = 0; + + /* ------------------------------------------------------------ */ + /* If this is a field-replace, insert the field. */ + /* ------------------------------------------------------------ */ + if (field) + { + LOG(("--field-> r[%2d] = %.2X -> ", prm, m_filt.r[prm])); + + m_filt.r[prm] &= ~(~0 << shf); /* Clear the old bits. */ + m_filt.r[prm] |= value; /* Merge in the new bits. */ + + LOG(("%.2X\n", m_filt.r[prm])); + + continue; + } + + /* ------------------------------------------------------------ */ + /* If this is a delta update, add to the appropriate field. */ + /* ------------------------------------------------------------ */ + if (delta) + { + LOG(("--delta-> r[%2d] = %.2X -> ", prm, m_filt.r[prm])); + + m_filt.r[prm] += value; + + LOG(("%.2X\n", m_filt.r[prm])); + + continue; + } + + /* ------------------------------------------------------------ */ + /* Otherwise, just write the new value. */ + /* ------------------------------------------------------------ */ + m_filt.r[prm] = value; + LOG(("--value-> r[%2d] = %.2X\n", prm, m_filt.r[prm])); + } + + /* ---------------------------------------------------------------- */ + /* Special case: Set PAUSE's equivalent period. */ + /* ---------------------------------------------------------------- */ + if (opcode == 0xF) + { + m_silent = 1; + m_filt.r[1] = PER_PAUSE; + } + + /* ---------------------------------------------------------------- */ + /* Now that we've updated the registers, go decode them. */ + /* ---------------------------------------------------------------- */ + lpc12_regdec(&m_filt); + + /* ---------------------------------------------------------------- */ + /* Break out since we now have a repeat count. */ + /* ---------------------------------------------------------------- */ + break; + } +} + + + +WRITE8_MEMBER( sp0256_device::ald_w ) +{ + /* ---------------------------------------------------------------- */ + /* Drop writes to the ALD register if we're busy. */ + /* ---------------------------------------------------------------- */ + if (!m_lrq) + { + LOG(("sp0256: Droped ALD write\n")); + return; + } + + /* ---------------------------------------------------------------- */ + /* Set LRQ to "busy" and load the 8 LSBs of the data into the ALD */ + /* reg. We take the command address, and multiply by 2 bytes to */ + /* get the new PC address. */ + /* ---------------------------------------------------------------- */ + m_lrq = 0; + m_ald = (0xff & data) << 4; + m_drq_cb(0); + SET_SBY(0) + + return; +} + +READ_LINE_MEMBER( sp0256_device::lrq_r ) +{ + // force stream update + m_stream->update(); + + return m_lrq == 0x8000; +} + +READ_LINE_MEMBER( sp0256_device::sby_r ) +{ + // TODO: force stream update?? + + return m_sby_line; +} + +READ16_MEMBER( sp0256_device::spb640_r ) +{ + /* -------------------------------------------------------------------- */ + /* Offset 0 returns the SP0256 LRQ status on bit 15. */ + /* -------------------------------------------------------------------- */ + if (offset == 0) + { + return m_lrq; + } + + /* -------------------------------------------------------------------- */ + /* Offset 1 returns the SPB640 FIFO full status on bit 15. */ + /* -------------------------------------------------------------------- */ + if (offset == 1) + { + return (m_fifo_head - m_fifo_tail) >= 64 ? 0x8000 : 0; + } + + /* -------------------------------------------------------------------- */ + /* Just return 255 for all other addresses in our range. */ + /* -------------------------------------------------------------------- */ + return 0x00ff; +} + +WRITE16_MEMBER( sp0256_device::spb640_w ) +{ + if (offset == 0) + { + ald_w(space, 0, data & 0xff); + return; + } + + if (offset == 1) + { + /* ---------------------------------------------------------------- */ + /* If Bit 10 is set, reset the FIFO, and SP0256. */ + /* ---------------------------------------------------------------- */ + + if (data & 0x400) + { + m_fifo_head = m_fifo_tail = m_fifo_bitp = 0; + device_reset(); + return; + } + + /* ---------------------------------------------------------------- */ + /* If the FIFO is full, drop the data. */ + /* ---------------------------------------------------------------- */ + if ((m_fifo_head - m_fifo_tail) >= 64) + { + LOG(("spb640: Dropped FIFO write\n")); + return; + } + + /* ---------------------------------------------------------------- */ + /* FIFO up the lower 10 bits of the data. */ + /* ---------------------------------------------------------------- */ + + LOG(("spb640: WR_FIFO %.3X %d.%d %d\n", data & 0x3ff, + m_fifo_tail, m_fifo_bitp, m_fifo_head)); + + m_fifo[m_fifo_head++ & 63] = data & 0x3ff; + + return; + } +} + +void sp0256_device::set_clock(int clock) +{ + set_unscaled_clock(clock); + m_stream->set_sample_rate(clock / CLOCK_DIVIDER); +} + + +TIMER_CALLBACK_MEMBER(sp0256_device::set_lrq_timer_proc) +{ + m_lrq = 0x8000; +} + +//------------------------------------------------- +// sound_stream_update - handle a stream update +//------------------------------------------------- + +void sp0256_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + stream_sample_t *output = outputs[0]; + int output_index = 0; + int length, did_samp/*, old_idx*/; + + while (output_index < samples) + { + /* ---------------------------------------------------------------- */ + /* First, drain as much of our scratch buffer as we can into the */ + /* sound buffer. */ + /* ---------------------------------------------------------------- */ + + while (m_sc_tail != m_sc_head) + { + output[output_index++] = m_scratch[m_sc_tail++ & SCBUF_MASK]; + m_sc_tail &= SCBUF_MASK; + + if (output_index > samples) + break; + } + + /* ---------------------------------------------------------------- */ + /* If output outputs is full, then we're done. */ + /* ---------------------------------------------------------------- */ + if (output_index > samples) + break; + + length = samples - output_index; + + /* ---------------------------------------------------------------- */ + /* Process the current set of filter coefficients as long as the */ + /* repeat count holds up and we have room in our scratch buffer. */ + /* ---------------------------------------------------------------- */ + did_samp = 0; + //old_idx = m_sc_head; + if (length > 0) do + { + int do_samp; + + /* ------------------------------------------------------------ */ + /* If our repeat count expired, emulate the microsequencer. */ + /* ------------------------------------------------------------ */ + if (m_filt.rpt <= 0) + micro(); + + /* ------------------------------------------------------------ */ + /* Do as many samples as we can. */ + /* ------------------------------------------------------------ */ + do_samp = length - did_samp; + if (m_sc_head + do_samp - m_sc_tail > SCBUF_SIZE) + do_samp = m_sc_tail + SCBUF_SIZE - m_sc_head; + + if (do_samp == 0) break; + + if (m_silent && m_filt.rpt <= 0) + { + int y = m_sc_head; + + for (int x = 0; x < do_samp; x++) + m_scratch[y++ & SCBUF_MASK] = 0; + m_sc_head += do_samp; + did_samp += do_samp; + } + else + { + did_samp += lpc12_update(&m_filt, do_samp, + m_scratch, &m_sc_head); + } + + m_sc_head &= SCBUF_MASK; + + } while (m_filt.rpt >= 0 && length > did_samp); + } +} diff --git a/src/devices/sound/sp0256.h b/src/devices/sound/sp0256.h new file mode 100644 index 00000000000..f4ceb61bb68 --- /dev/null +++ b/src/devices/sound/sp0256.h @@ -0,0 +1,136 @@ +// license:GPL-2.0+ +// copyright-holders:Joseph Zbiciak,Tim Lindner +/********************************************************************** + + SP0256 Narrator Speech Processor emulation + +********************************************************************** + _____ _____ + Vss 1 |* \_/ | 28 OSC 2 + _RESET 2 | | 27 OSC 1 + ROM DISABLE 3 | | 26 ROM CLOCK + C1 4 | | 25 _SBY RESET + C2 5 | | 24 DIGITAL OUT + C3 6 | | 23 Vdi + Vdd 7 | SP0256 | 22 TEST + SBY 8 | | 21 SER IN + _LRQ 9 | | 20 _ALD + A8 10 | | 19 SE + A7 11 | | 18 A1 + SER OUT 12 | | 17 A2 + A6 13 | | 16 A3 + A5 14 |_____________| 15 A4 + +**********************************************************************/ + +/* + GI SP0256 Narrator Speech Processor + + By Joe Zbiciak. Ported to MESS by tim lindner. + + Copyright Joseph Zbiciak, all rights reserved. + Copyright tim lindner, all rights reserved. + + - This source code is released as freeware for non-commercial purposes. + - You are free to use and redistribute this code in modified or + unmodified form, provided you list us in the credits. + - If you modify this source code, you must add a notice to each + modified source file that it has been changed. If you're a nice + person, you will clearly mark each change too. :) + - If you wish to use this for commercial purposes, please contact us at + intvnut@gmail.com (Joe Zbiciak), tlindner@macmess.org (tim lindner) + - This entire notice must remain in the source code. + +*/ + +#pragma once + +#ifndef __SP0256_H__ +#define __SP0256_H__ + +#define MCFG_SP0256_DATA_REQUEST_CB(_devcb) \ + devcb = &sp0256_device::set_data_request_callback(*device, DEVCB_##_devcb); + +#define MCFG_SP0256_STANDBY_CB(_devcb) \ + devcb = &sp0256_device::set_standby_callback(*device, DEVCB_##_devcb); + + +struct lpc12_t +{ + int rpt, cnt; /* Repeat counter, Period down-counter. */ + UINT32 per, rng; /* Period, Amplitude, Random Number Generator */ + int amp; + INT16 f_coef[6]; /* F0 through F5. */ + INT16 b_coef[6]; /* B0 through B5. */ + INT16 z_data[6][2]; /* Time-delay data for the filter stages. */ + UINT8 r[16]; /* The encoded register set. */ + int interp; +}; + +class sp0256_device : public device_t, + public device_sound_interface +{ +public: + sp0256_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + ~sp0256_device() { } + + template static devcb_base &set_data_request_callback(device_t &device, _Object object) { return downcast(device).m_drq_cb.set_callback(object); } + template static devcb_base &set_standby_callback(device_t &device, _Object object) { return downcast(device).m_sby_cb.set_callback(object); } + + DECLARE_WRITE8_MEMBER(ald_w); + DECLARE_READ_LINE_MEMBER(lrq_r); + DECLARE_READ_LINE_MEMBER(sby_r); + DECLARE_READ16_MEMBER(spb640_r); + DECLARE_WRITE16_MEMBER(spb640_w); + + TIMER_CALLBACK_MEMBER(set_lrq_timer_proc); + void set_clock(int clock); + void bitrevbuff(UINT8 *buffer, unsigned int start, unsigned int length); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // sound stream update overrides + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + +private: + UINT32 getb(int len); + void micro(); + required_region_ptr m_rom; /* 64K ROM. */ + sound_stream *m_stream; /* MAME core sound stream */ + devcb_write_line m_drq_cb; /* Data request callback */ + devcb_write_line m_sby_cb; /* Standby callback */ + + int m_sby_line; /* Standby line state */ + int m_cur_len; /* Fullness of current sound buffer. */ + + int m_silent; /* Flag: SP0256 is silent. */ + + INT16 *m_scratch; /* Scratch buffer for audio. */ + UINT32 m_sc_head; /* Head pointer into scratch circular buf */ + UINT32 m_sc_tail; /* Tail pointer into scratch circular buf */ + + struct lpc12_t m_filt; /* 12-pole filter */ + int m_lrq; /* Load ReQuest. == 0 if we can accept a load */ + int m_ald; /* Address LoaD. < 0 if no command pending. */ + int m_pc; /* Microcontroller's PC value. */ + int m_stack; /* Microcontroller's PC stack. */ + int m_fifo_sel; /* True when executing from FIFO. */ + int m_halted; /* True when CPU is halted. */ + UINT32 m_mode; /* Mode register. */ + UINT32 m_page; /* Page set by SETPAGE */ + + UINT32 m_fifo_head; /* FIFO head pointer (where new data goes). */ + UINT32 m_fifo_tail; /* FIFO tail pointer (where data comes from). */ + UINT32 m_fifo_bitp; /* FIFO bit-pointer (for partial decles). */ + UINT16 m_fifo[64]; /* The 64-decle FIFO. */ + + emu_timer *m_lrq_timer; +}; + +extern const device_type SP0256; + + +#endif /* __SP0256_H__ */ diff --git a/src/devices/sound/speaker.c b/src/devices/sound/speaker.c new file mode 100644 index 00000000000..7872351a0e3 --- /dev/null +++ b/src/devices/sound/speaker.c @@ -0,0 +1,409 @@ +// license:BSD-3-Clause +// copyright-holders:Nicola Salmoria +/*************************************************************************** + + speaker.c + + Sound driver to emulate a simple speaker, + driven by one or more output bits + + Original author: (unsigned) + Filtering: Anders Hallstr?m +****************************************************************************/ + +/* Discussion of oversampling and anti-alias filtering: (Anders Hallstr?m) + * + * This driver is for machines that directly control + * one or more simple digital-to-analog converters (DAC) + * connected to one or more audio outputs (such as analog amp + speaker). + * Currently only 1-bit DAC is supported via the interface to this module. + * + * Frequently such machines would oversample the DAC + * in order to overcome the limited DAC resolution. + * For faithful reproduction of the sound, this must be carefully handled + * with anti-alias filtering when converting a high-rate low-resolution signal + * to a moderate-rate high-resolution signal suitable for the DAC in the emulator's sound card. + * (Originally, removal of any redundant high frequency content occurred on the analog side + * with no aliasing effects.) + * + * The most straightforward, naive way to handle this is to use two streams; + * stream 1 modeling the native audio, with a sampling rate that allows for + * accurate representation of over-sampling, i.e. the sampling rate should match + * the clock frequency of the audio generating device (such as the CPU). + * Stream 1 is connected to stream 2, which is concerned with feeding the sound card. + * The stream system has features to handle rate conversion from stream 1 to 2. + * + * I tried it out of curiosity; it works fine conceptually, but + * - it puts an unnecessary burden on system resources + * - sound quality is still not satisfactory, though better than without anti-alias + * - "stream 1" properties are machine specific and so should be configured + * individually in each machine driver using this approach. + * This can also be seen as an advantage for flexibility, though. + * + * Instead, dedicated filtering is implemented in this module, + * in a machine-neutral way (based on machine time and external -samplerate only). + * + * The basic average filter has the advantage that it can be used without + * explicitly generating all samples in "stream 1". However, + * it is poor for anti-alias filtering. + * Therefore, average filtering is combined with windowed sinc. + * + * Virtual stream 1: Samples in true machine time. + * Any sampling rate up to attotime resolution is implicitly supported. + * -> average filtering over each stream 2 sample -> + * Virtual stream 2: Intermediate representation. + * Sample rate = RATE_MULTIPLIER * stream 3 sample rate. + * If effective rate of stream 1 exceeds rate of stream 2, + * some aliasing distorsion is introduced in this step because the average filtering is a compromise. + * The distorsion is however mostly in the higher frequencies. + * -> low-pass anti-alias filtering with kernel ampl[] -> + * -> down-sampling -> + * Actual stream 3: channel output generated by speaker_sound_update(). + * Sample rate = device sample rate = configured "-samplerate". + * + * In the speaker_state data structure, + * "intermediate samples" refers to "stream 2" + * "channel samples" refers to "stream 3" + */ + +/* IMPROVEMENTS POSSIBLE: + * - Make filter length a run-time configurable parameter. min=1 max=1000 or something + * - Optimize cutoff freq automatically after filter length, or configurable too + * - Generalise this approach to other DAC-based sound types if susceptible to aliasing + */ + +#include "emu.h" +#include "sound/speaker.h" + +static const INT16 default_levels[2] = {0, 32767}; + +// Internal oversampling factor (interm. samples vs stream samples) +static const int RATE_MULTIPLIER = 4; + + +const device_type SPEAKER_SOUND = &device_creator; + +speaker_sound_device::speaker_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, SPEAKER_SOUND, "Filtered 1-bit DAC", tag, owner, clock, "speaker_sound", __FILE__), + device_sound_interface(mconfig, *this), + m_num_levels(2), + m_levels(default_levels) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void speaker_sound_device::device_start() +{ + int i; + double x; + + m_channel = machine().sound().stream_alloc(*this, 0, 1, machine().sample_rate()); + + m_level = 0; + for (i = 0; i < FILTER_LENGTH; i++) + m_composed_volume[i] = 0; + + m_composed_sample_index = 0; + m_last_update_time = machine().time(); + m_channel_sample_period = HZ_TO_ATTOSECONDS(machine().sample_rate()); + m_channel_sample_period_secfrac = ATTOSECONDS_TO_DOUBLE(m_channel_sample_period); + m_interm_sample_period = m_channel_sample_period / RATE_MULTIPLIER; + m_interm_sample_period_secfrac = ATTOSECONDS_TO_DOUBLE(m_interm_sample_period); + m_channel_last_sample_time = m_channel->sample_time(); + m_channel_next_sample_time = m_channel_last_sample_time + attotime(0, m_channel_sample_period); + m_next_interm_sample_time = m_channel_last_sample_time + attotime(0, m_interm_sample_period); + m_interm_sample_index = 0; + m_prevx = m_prevy = 0.0; + + /* Note: To avoid time drift due to floating point inaccuracies, + * it is good if the speaker time synchronizes itself with the stream timing regularly. + */ + + /* Compute filter kernel; */ + /* (Done for each device though the data is shared... + * No problem really, but should be done as part of system init if I knew how) + */ +#if 1 + /* This is an approximated sinc (a perfect sinc makes an ideal low-pass filter). + * FILTER_STEP determines the cutoff frequency, + * which should be below the Nyquist freq, i.e. half the sample rate. + * Smaller step => kernel extends in time domain => lower cutoff freq + * In this case, with sinc, filter step PI corresponds to the Nyq. freq. + * Since we do not get a perfect filter => must lower the cutoff freq some more. + * For example, step PI/(2*RATE_MULTIPLIER) corresponds to cutoff freq = sample rate / 4; + * With -samplerate 48000, cutoff freq is ca 12kHz while the Nyq. freq is 24kHz. + * With -samplerate 96000, cutoff freq is ca 24kHz while the Nyq. freq is 48kHz. + * For a steeper, more efficient filter, increase FILTER_LENGTH at the expense of CPU usage. + */ +#define FILTER_STEP (M_PI / 2 / RATE_MULTIPLIER) + /* Distribute symmetrically on x axis; center has x=0 if length is odd */ + for (i = 0, x = (0.5 - FILTER_LENGTH / 2.) * FILTER_STEP; + i < FILTER_LENGTH; + i++, x += FILTER_STEP) + { + if (x == 0) + m_ampl[i] = 1; + else + m_ampl[i] = sin(x) / x; + } +#else + /* Trivial average filter with poor frequency cutoff properties; + * First zero (frequency where amplification=0) = sample rate / filter length + * Cutoff frequency approx <= first zero / 2 + */ + for (i = 0, i < FILTER_LENGTH; i++) + m_ampl[i] = 1; +#endif + + save_item(NAME(m_level)); + save_item(NAME(m_composed_volume)); + save_item(NAME(m_composed_sample_index)); + save_item(NAME(m_channel_last_sample_time)); + save_item(NAME(m_interm_sample_index)); + save_item(NAME(m_last_update_time)); + save_item(NAME(m_prevx)); + save_item(NAME(m_prevy)); + + machine().save().register_postload(save_prepost_delegate(FUNC(speaker_sound_device::speaker_postload), this)); +} + +void speaker_sound_device::device_reset() +{ + int i; + + m_level = 0; + for (i = 0; i < FILTER_LENGTH; i++) + m_composed_volume[i] = 0; + + m_composed_sample_index = 0; + m_last_update_time = machine().time(); + m_channel_sample_period = HZ_TO_ATTOSECONDS(machine().sample_rate()); + m_channel_sample_period_secfrac = ATTOSECONDS_TO_DOUBLE(m_channel_sample_period); + m_interm_sample_period = m_channel_sample_period / RATE_MULTIPLIER; + m_interm_sample_period_secfrac = ATTOSECONDS_TO_DOUBLE(m_interm_sample_period); + m_channel_last_sample_time = m_channel->sample_time(); + m_channel_next_sample_time = m_channel_last_sample_time + attotime(0, m_channel_sample_period); + m_next_interm_sample_time = m_channel_last_sample_time + attotime(0, m_interm_sample_period); + m_interm_sample_index = 0; + m_prevx = m_prevy = 0.0; +} + +void speaker_sound_device::speaker_postload() +{ + m_channel_next_sample_time = m_channel_last_sample_time + attotime(0, m_channel_sample_period); + m_next_interm_sample_time = m_channel_last_sample_time + attotime(0, m_interm_sample_period); +} + +//------------------------------------------------- +// sound_stream_update - handle a stream update +//------------------------------------------------- + +// This can be triggered by the core (based on emulated time) or via level_w(). +void speaker_sound_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + stream_sample_t *buffer = outputs[0]; + int volume = m_levels[m_level]; + double filtered_volume; + attotime sampled_time = attotime::zero; + + if (samples > 0) + { + /* Prepare to update time state */ + sampled_time = attotime(0, m_channel_sample_period); + if (samples > 1) + sampled_time *= samples; + + /* Note: since the stream is in the process of being updated, + * stream->sample_time() will return the time before the update! (MAME 0.130) + * Avoid using it here in order to avoid a subtle dependence on the stream implementation. + */ + } + + if (samples-- > 0) + { + /* Note that first interm. sample may be composed... */ + filtered_volume = update_interm_samples_get_filtered_volume(volume); + + /* Composite volume is now quantized to the stream resolution */ + *buffer++ = (stream_sample_t)filtered_volume; + + /* Any additional samples will be homogeneous, however may need filtering across samples: */ + while (samples-- > 0) + { + filtered_volume = update_interm_samples_get_filtered_volume(volume); + *buffer++ = (stream_sample_t)filtered_volume; + } + + /* Update the time state */ + m_channel_last_sample_time += sampled_time; + m_channel_next_sample_time = m_channel_last_sample_time + attotime(0, m_channel_sample_period); + m_next_interm_sample_time = m_channel_last_sample_time + attotime(0, m_interm_sample_period); + m_last_update_time = m_channel_last_sample_time; + } +} + + + +void speaker_sound_device::level_w(int new_level) +{ + int volume; + attotime time; + + if (new_level == m_level) + return; + + if (new_level < 0) + new_level = 0; + else + if (new_level >= m_num_levels) + new_level = m_num_levels - 1; + + volume = m_levels[m_level]; + time = machine().time(); + + if (time < m_channel_next_sample_time) + { + /* Stream sample is yet unfinished, but we may have one or more interm. samples */ + update_interm_samples(time, volume); + + /* Do not forget to update speaker state before returning! */ + m_level = new_level; + return; + } + /* Reaching here means such time has passed since last stream update + * that we can add at least one complete sample to the stream. + * The details have to be handled by speaker_sound_update() + */ + + /* Force streams.c to update sound until this point in time now */ + m_channel->update(); + + /* This is redundant because time update has to be done within speaker_sound_update() anyway, + * however this ensures synchronization between the speaker and stream timing: + */ + m_channel_last_sample_time = m_channel->sample_time(); + m_channel_next_sample_time = m_channel_last_sample_time + attotime(0, m_channel_sample_period); + m_next_interm_sample_time = m_channel_last_sample_time + attotime(0, m_interm_sample_period); + m_last_update_time = m_channel_last_sample_time; + + /* Assertion: time - last_update_time < channel_sample_period, i.e. time < channel_next_sample_time */ + + /* The overshooting fraction of time will make zero, one or more interm. samples: */ + update_interm_samples(time, volume); + + /* Finally update speaker state before returning */ + m_level = new_level; + +} + + +void speaker_sound_device::update_interm_samples(const attotime &time, int volume) +{ + double fraction; + + /* We may have completed zero, one or more interm. samples: */ + while (time >= m_next_interm_sample_time) + { + /* First interm. sample may be composed, subsequent samples will be homogeneous. */ + /* Treat all the same general way. */ + finalize_interm_sample(volume); + init_next_interm_sample(); + } + /* Depending on status above: + * a) Add latest fraction to unfinished composed sample + * b) The overshooting fraction of time will start a new composed sample + */ + fraction = make_fraction(time, m_last_update_time, m_interm_sample_period_secfrac); + m_composed_volume[m_composed_sample_index] += volume * fraction; + m_last_update_time = time; +} + + +double speaker_sound_device::update_interm_samples_get_filtered_volume(int volume) +{ + double filtered_volume, tempx; + + /* We may have one or more interm. samples to go */ + if (m_interm_sample_index < RATE_MULTIPLIER) + { + /* First interm. sample may be composed. */ + finalize_interm_sample(volume); + + /* Subsequent interm. samples will be homogeneous. */ + while (m_interm_sample_index + 1 < RATE_MULTIPLIER) + { + init_next_interm_sample(); + m_composed_volume[m_composed_sample_index] = volume; + } + } + /* Important: next interm. sample not initialised yet, so that no data is destroyed before filtering... */ + filtered_volume = get_filtered_volume(); + init_next_interm_sample(); + /* Reset counter to next stream sample: */ + m_interm_sample_index = 0; + + /* simple DC blocker filter */ + tempx = filtered_volume; + filtered_volume = tempx - m_prevx + 0.995 * m_prevy; + m_prevx = tempx; + m_prevy = filtered_volume; + + return filtered_volume; +} + + +void speaker_sound_device::finalize_interm_sample(int volume) +{ + double fraction; + + /* Fill the composed sample up if it was incomplete */ + fraction = make_fraction(m_next_interm_sample_time, m_last_update_time, m_interm_sample_period_secfrac); + m_composed_volume[m_composed_sample_index] += volume * fraction; + /* Update time state */ + m_last_update_time = m_next_interm_sample_time; + m_next_interm_sample_time += attotime(0, m_interm_sample_period); + + /* For compatibility with filtering, do not incr. index and initialise next sample yet. */ +} + + +void speaker_sound_device::init_next_interm_sample() +{ + /* Move the index and initialize next composed sample */ + m_composed_sample_index++; + if (m_composed_sample_index >= FILTER_LENGTH) + m_composed_sample_index = 0; + m_composed_volume[m_composed_sample_index] = 0; + + m_interm_sample_index++; + /* No limit check on interm_sample_index here - to be handled by caller */ +} + + +inline double speaker_sound_device::make_fraction(const attotime &a, const attotime &b, double timediv) +{ + /* fraction = (a - b) / timediv */ + return (a - b).as_double() / timediv; +} + + +double speaker_sound_device::get_filtered_volume() +{ + double filtered_volume = 0; + double ampsum = 0; + int i, c; + + /* Filter over composed samples (each composed sample is already average filtered) */ + for (i = m_composed_sample_index + 1, c = 0; c < FILTER_LENGTH; i++, c++) + { + if (i >= FILTER_LENGTH) i = 0; + filtered_volume += m_composed_volume[i] * m_ampl[c]; + ampsum += m_ampl[c]; + } + filtered_volume /= ampsum; + + return filtered_volume; +} diff --git a/src/devices/sound/speaker.h b/src/devices/sound/speaker.h new file mode 100644 index 00000000000..67819769926 --- /dev/null +++ b/src/devices/sound/speaker.h @@ -0,0 +1,93 @@ +// license:BSD-3-Clause +// copyright-holders:Nicola Salmoria +/********************************************************************** + + speaker.h + Sound driver to emulate a simple speaker, + driven by one or more output bits + +**********************************************************************/ + +#pragma once + +#ifndef __SOUND_SPEAKER_H__ +#define __SOUND_SPEAKER_H__ + +// Length of anti-aliasing filter kernel, measured in number of intermediate samples +enum +{ + FILTER_LENGTH = 64 +}; + +#define MCFG_SPEAKER_LEVELS(_num, _levels) \ + speaker_sound_device::static_set_levels(*device, _num, _levels); + +class speaker_sound_device : public device_t, + public device_sound_interface +{ +public: + speaker_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + ~speaker_sound_device() {} + + // static configuration + static void static_set_levels(device_t &device, int num_levels, const INT16 *levels) { downcast(device).m_num_levels = num_levels; downcast(device).m_levels = levels;} + + void level_w(int new_level); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // sound stream update overrides + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + +private: + // internal state + + // Updates the composed volume array according to time + void update_interm_samples(const attotime &time, int volume); + + // Updates the composed volume array and returns final filtered volume of next stream sample + double update_interm_samples_get_filtered_volume(int volume); + + void finalize_interm_sample(int volume); + void init_next_interm_sample(); + inline double make_fraction(const attotime &a, const attotime &b, double timediv); + double get_filtered_volume(); + + // Kernel (pulse response) for filtering across samples (while we avoid fancy filtering within samples) + double m_ampl[FILTER_LENGTH]; + + sound_stream *m_channel; + int m_level; + + /* The volume of a composed sample grows incrementally each time the speaker is over-sampled. + * That is in effect a basic average filter. + * Another filter can and will be applied to the array of composed samples. + */ + double m_composed_volume[FILTER_LENGTH]; /* integrator(s) */ + int m_composed_sample_index; /* array index for composed_volume */ + attoseconds_t m_channel_sample_period; /* in as */ + double m_channel_sample_period_secfrac; /* in fraction of second */ + attotime m_channel_last_sample_time; + attotime m_channel_next_sample_time; + attoseconds_t m_interm_sample_period; + double m_interm_sample_period_secfrac; + attotime m_next_interm_sample_time; + int m_interm_sample_index; /* counts interm. samples between stream samples */ + attotime m_last_update_time; /* internal timestamp */ + + void speaker_postload(); + + // DC blocker state + double m_prevx, m_prevy; + + int m_num_levels; /* optional: number of levels (if not two) */ + const INT16 *m_levels; /* optional: pointer to level lookup table */ +}; + +extern const device_type SPEAKER_SOUND; + + +#endif /* __SPEAKER_H__ */ diff --git a/src/devices/sound/spu.c b/src/devices/sound/spu.c new file mode 100644 index 00000000000..ef5a81e0e82 --- /dev/null +++ b/src/devices/sound/spu.c @@ -0,0 +1,3081 @@ +// license:BSD-3-Clause +// copyright-holders:pSXAuthor, R. Belmont +/* + + Sony PlayStation SPU (CXD2922BQ/CXD2925Q) emulator + by pSXAuthor + MAME adaptation by R. Belmont + +*/ + +#include "emu.h" +#include "spu.h" +#include "spureverb.h" + +// +// +// + +//#define warn_if_sweep_used +#define assert_if_sweep_used +//#define debug_spu_registers +//#define debug_spu +//#define log_loop_cache +//#define show_xa_debug + +//#ifndef _FINAL +// #define show_cache_update +//#endif + +#ifdef show_xa_debug + #define debug_xa printf +#else + #define debug_xa if (0) +#endif + +// device type definition +const device_type SPU = &device_creator; + +// +// +// +INLINE unsigned int min(unsigned int a, unsigned int b) +{ + return (a > b) ? b : a; +} + +INLINE unsigned int max(unsigned int a, unsigned int b) +{ + return (a > b) ? a : b; +} + +INLINE double mindb(double a, double b) +{ + return (a > b) ? b : a; +} + +INLINE double maxdb(double a, double b) +{ + return (a > b) ? a : b; +} + +enum spu_registers +{ + spureg_voice=0, + spureg_voice_last=0x17f, + spureg_mvol_l=0x180, + spureg_mvol_r=0x182, + spureg_rvol_l=0x184, + spureg_rvol_r=0x186, + spureg_keyon=0x188, + spureg_keyoff=0x18c, + spureg_fm=0x190, + spureg_noise=0x194, + spureg_reverb=0x198, + spureg_chon=0x19c, + spureg_reverb_addr=0x1a2, + spureg_irq_addr=0x1a4, + spureg_trans_addr=0x1a6, + spureg_data=0x1a8, + spureg_ctrl=0x1aa, + spureg_status=0x1ac, + spureg_cdvol_l=0x1b0, + spureg_cdvol_r=0x1b2, + spureg_exvol_l=0x1b4, + spureg_exvol_r=0x1b6, + spureg_reverb_config=0x1c0, + spureg_last=0x1ff +}; + +enum spu_ctrl +{ + spuctrl_irq_enable=0x40, + spuctrl_noise_shift=8, + spuctrl_noise_mask=0x3f<>1]; + } +#endif + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +reverb_params *spu_reverb_cfg=NULL; + +float spu_device::freq_multiplier=1.0f; + +//************************************************************************** +// DEVICE CONFIGURATION +//************************************************************************** + +class adpcm_decoder +{ + int l0,l1; + +public: + adpcm_decoder() + { + reset(); + } + + adpcm_decoder(const adpcm_decoder &other) + { + operator =(other); + } + + adpcm_decoder &operator =(const adpcm_decoder &other) + { + l0=other.l0; + l1=other.l1; + return *this; + } + + void reset() + { + l0=l1=0; + } + + signed short *decode_packet(adpcm_packet *ap, signed short *dp); +}; + +// +// +// + +struct spu_device::sample_cache +{ +public: + unsigned int start, + end, + invalid_start, + invalid_end, + loopaddr, + last_update_end; + signed short *data,*loop,*dend; + adpcm_decoder decoder, update_decoder; + mutable int ref_count; + bool valid, + is_loop; + sample_loop_cache *loop_cache; + + static unsigned int cache_size; + + sample_cache() + : invalid_start(0xffffffff), + invalid_end(0), + last_update_end(0xffffffff), + data(NULL), + ref_count(0), + valid(false), + is_loop(false), + loop_cache(NULL) + { + } + + ~sample_cache(); + + void add_ref() const { ref_count++; } + void remove_ref() const + { + ref_count--; + if (ref_count==0) + { + cache_size-=(dend-data)<<1; + global_free(this); + } + } + + signed short *get_sample_pointer(const unsigned int addr); + bool get_sample_pointer(const unsigned int addr, cache_pointer *cp); + bool get_loop_pointer(cache_pointer *cp); + unsigned int get_sample_address(const signed short *ptr) const; + sample_loop_cache *find_loop_cache(const unsigned int lpend, const unsigned int lpstart); + void add_loop_cache(sample_loop_cache *lc); + + bool is_valid_pointer(signed short *ptr) const; + + bool try_update(spu_device *spu); +}; + +unsigned int spu_device::sample_cache::cache_size; + +// +// +// + +struct spu_device::sample_loop_cache +{ +public: + unsigned int loopend, + loopstart, + len; + signed short data[num_loop_cache_samples]; + sample_loop_cache *next; + + sample_loop_cache() + : next(NULL) + { + sample_cache::cache_size+=num_loop_cache_samples<<1; + } + + ~sample_loop_cache() + { + sample_cache::cache_size-=num_loop_cache_samples<<1; + + #ifdef log_loop_cache + log(log_spu,"spu: destroy loop cache %08x\n",this); + #endif + } +}; + +// +// +// + +struct spu_device::cache_pointer +{ + signed short *ptr; + sample_cache *cache; + + cache_pointer() + : ptr(NULL), + cache(NULL) + { + } + + cache_pointer(const cache_pointer &other) + : ptr(NULL), + cache(NULL) + { + operator =(other); + } + + cache_pointer(signed short *_ptr, sample_cache *_cache) + : ptr(_ptr), + cache(_cache) + { + if (cache) cache->add_ref(); + } + + ~cache_pointer() + { + reset(); + } + + void reset(); + cache_pointer &operator =(const cache_pointer &other); + bool update(spu_device *spu); + + unsigned int get_address() const + { + if (cache) + { + return cache->get_sample_address(ptr); + } else + { + return -1; + } + } + + operator bool() const { return cache!=NULL; } + + bool is_valid() const { return ((cache) && (cache->is_valid_pointer(ptr))); } +}; + +// +// +// + +struct spu_device::voiceinfo +{ + cache_pointer play,loop; + sample_loop_cache *loop_cache; + unsigned int dptr, + lcptr; + + int env_state; + float env_ar, + env_dr, + env_sr, + env_rr, + env_sl, + env_level, + env_delta, + + //>> + sweep_vol[2], + sweep_rate[2]; + int vol[2]; + //<< + + unsigned int pitch, + samplestoend, + samplestoirq, + envsamples; + bool hitirq, + inloopcache, + forceloop, + _pad; + INT64 keyontime; +}; + +// +// +// + +class stream_buffer +{ +public: + struct stream_marker + { + public: + unsigned int sector, + offset; + stream_marker *next, + *prev; + }; + + dynamic_buffer buffer; + unsigned int head, + tail, + in, + sector_size, + num_sectors, + buffer_size; + stream_marker *marker_head, + *marker_tail; + + stream_buffer(const unsigned int _sector_size, + const unsigned int _num_sectors) + : head(0), + tail(0), + in(0), + sector_size(_sector_size), + num_sectors(_num_sectors), + marker_head(NULL), + marker_tail(NULL) + { + buffer_size=sector_size*num_sectors; + buffer.resize(buffer_size); + memset(&buffer[0], 0, buffer_size); + } + + ~stream_buffer() + { + flush_all(); + } + + unsigned char *add_sector(const unsigned int sector) + { + stream_marker *xam=new stream_marker; + xam->sector=sector; + xam->offset=head; + xam->next=NULL; + xam->prev=marker_tail; + if (marker_tail) + { + marker_tail->next=xam; + } else + { + marker_head=xam; + } + marker_tail=xam; + + unsigned char *ret=&buffer[head]; + head=(head+sector_size)%buffer_size; + in+=sector_size; + return ret; + } + + void flush(const unsigned int sector) + { + // Remove markers from the end of the buffer if they are after + // the specified sector + + while ((marker_tail) && (marker_tail->sector>=sector)) + { +// debug_xa("flushing: %d\n", marker_tail->sector); + + stream_marker *xam=marker_tail; + head=xam->offset; + marker_tail=xam->prev; + if (marker_tail) marker_tail->next=NULL; + global_free(xam); + } + + // Set marker head to NULL if the list is now empty + + if (! marker_tail) marker_head=NULL; + + // Adjust buffer size counter + + int sz=(head-tail); + if (sz<0) sz+=buffer_size; + assert(sz<=(int)in); + in=sz; + } + + void flush_all() + { + // NOTE: ??what happens to the markers?? + + while (marker_head) + { + stream_marker *m=marker_head; + marker_head=marker_head->next; + global_free(m); + } + + marker_head=marker_tail=NULL; + head=tail=in=0; + } + + void delete_markers(const unsigned int oldtail) + { + while (marker_head) + { + int olddist=marker_head->offset-oldtail, + dist=marker_head->offset-tail; + if (olddist<0) olddist+=buffer_size; + if (dist<0) dist+=buffer_size; + bool passed=(((olddist==0) && (dist!=0)) || (dist>olddist)); + if (! passed) break; + +// debug_xa("passed: %d\n",marker_head->sector); + + stream_marker *xam=marker_head; + marker_head=xam->next; + global_free(xam); + if (marker_head) marker_head->prev=NULL; + } + + if (! marker_head) marker_head=marker_tail=NULL; + } + + unsigned int get_bytes_in() const { return in; } + unsigned int get_bytes_free() const { return buffer_size-in; } + + unsigned char *get_tail_ptr() { return &buffer[tail]; } + unsigned char *get_tail_ptr(const unsigned int offset) + { + return &buffer[((tail+offset)%buffer_size)]; + } + unsigned int get_tail_offset() const { return tail; } + void increment_tail(const unsigned int offset) + { + tail=(tail+offset)%buffer_size; + in-=offset; + } +}; + +// +// +// + +static inline int clamp(const int v) +{ + if (v<-32768) return -32768; + if (v>32767) return 32767; + return v; +} + +// +// +// + +spu_device::sample_cache::~sample_cache() +{ + global_free_array(data); + while (loop_cache) + { + sample_loop_cache *lc=loop_cache; + loop_cache=lc->next; + global_free(lc); + } +} + +// +// +// + +signed short *spu_device::sample_cache::get_sample_pointer(const unsigned int addr) +{ + if ((addr>=start) && (addr>4)*28); + } else + { + return NULL; + } +} + +// +// +// + +bool spu_device::sample_cache::get_sample_pointer(const unsigned int addr, cache_pointer *cp) +{ + cp->reset(); + if ((cp->ptr=get_sample_pointer(addr))) + { + cp->cache=this; + add_ref(); + return true; + } + return false; +} + +// +// +// + +bool spu_device::sample_cache::get_loop_pointer(cache_pointer *cp) +{ + cp->reset(); + if ((cp->ptr=loop)) + { + cp->cache=this; + add_ref(); + return true; + } + return false; +} + +// +// +// + +unsigned int spu_device::sample_cache::get_sample_address(const signed short *ptr) const +{ + if ((ptr>=data) && (ptr<=dend)) + { + return start+(((ptr-data)/28)<<4); + } else + { + return -1; + } +} + +// +// +// + +spu_device::sample_loop_cache *spu_device::sample_cache::find_loop_cache(const unsigned int lpend, const unsigned int lpstart) +{ + sample_loop_cache *lc; + for (lc=loop_cache; lc; lc=lc->next) + if ((lc->loopend==lpend) && (lc->loopstart==lpstart)) break; + return lc; +} + +// +// +// + +void spu_device::sample_cache::add_loop_cache(sample_loop_cache *lc) +{ + lc->next=loop_cache; + loop_cache=lc; +} + +// +// +// + +bool spu_device::sample_cache::is_valid_pointer(signed short *ptr) const +{ + if ((ptr>=data) && (data<=dend)) return true; + for (sample_loop_cache *slc=loop_cache; slc; slc=slc->next) + if ((ptr>=slc->data) && (ptr<(slc->data+num_loop_cache_samples))) + return true; + return false; +} + +// +// +// + +bool spu_device::sample_cache::try_update(spu_device *spu) +{ + if ((invalid_start>=start) && (invalid_end<=end)) + { + adpcm_packet *ap=(adpcm_packet *)(spu->spu_ram+start); + unsigned int a; + unsigned int loop=0; + + for (a=start; a<=end; a+=16, ap++) + { + if ((ap->flags&adpcmflag_loop_start) && (ap->flags&adpcmflag_loop)) loop=a; + if (ap->flags&adpcmflag_end) break; + } + + if ((a==(end-16)) && (loop==loopaddr)) + { + #ifdef show_cache_update + printf("updating %p: ",this); + #endif + + if (invalid_start==start) + { + #ifdef show_cache_update + printf("using end values"); + #endif + + update_decoder=decoder; + } else + if (invalid_start!=last_update_end) + { + #ifdef show_cache_update + printf("resetting decoder (istrt=%08x lupd=%08x)",invalid_start,last_update_end); + #endif + + update_decoder.reset(); + } + #ifdef show_cache_update + printf("\n"); + #endif + + signed short *dp=data+(((invalid_start-start)>>4)*28); + ap=(adpcm_packet *)(spu->spu_ram+invalid_start); + for (a=invalid_start; anext) + { + if (invalid_start==lc->loopstart) + { + adpcm_decoder tmp=decoder; + dp=lc->data; + signed short *dpend=dp+lc->len; + unsigned int adr=lc->loopstart; + for (unsigned int i=0; ((ispu_ram+adr),dp); + } + } + + invalid_end=0; + invalid_start=0xffffffff; + valid=true; + + for (a=start; acache[a>>4]=this; + } + + add_ref(); + + return true; + } + } + + return false; +} + +// +// +// + +void spu_device::cache_pointer::reset() +{ + if (cache) + { + ptr=NULL; + cache->remove_ref(); + cache=NULL; + } +} + +// +// +// + +spu_device::cache_pointer &spu_device::cache_pointer::operator =(const cache_pointer &other) +{ + if (cache) cache->remove_ref(); + ptr=other.ptr; + cache=other.cache; + if (cache) cache->add_ref(); + return *this; +} + +// +// +// + +bool spu_device::cache_pointer::update(spu_device *spu) +{ + if ((cache) && (! cache->valid)) + { +/* log(log_spu,"cache_pointer::update: block %08x-%08x invalidated %08x-%08x\n", + cache->start, + cache->end, + cache->invalid_start, + cache->invalid_end);*/ + + if (! cache->try_update(spu)) + { + // Cache is invalid, calculate play address offset from start of + // old cache block + + unsigned int off=ptr-cache->data, + addr=cache->start; + + // Release cache block and get updated one + + spu->translate_sample_addr(addr,this); + + // Calculate play address in new cache block + + ptr=cache->data+off; + + if (ptr>=cache->dend) + { + // Play address is out of bounds in new cache block, release it and get a + // new one starting at the current play address + + spu->translate_sample_addr(addr+((off/28)<<4),this); + } + } + } + + // Return false if we do not have a cache block or the play address is invalid + + if ((cache) && ((ptr>=cache->data) && (ptrdend))) + { + return true; + } else + { + reset(); + return false; + } +} + +// +// +// + +signed short *adpcm_decoder::decode_packet(adpcm_packet *ap, signed short *dp) +{ + int shift=ap->info&0xf, + filter=ap->info>>4, + f0=filter_coef[filter][0], + f1=filter_coef[filter][1]; + + for (int i=0; i<14; i++) + { + unsigned char b=ap->data[i]; + short bl=(b&0xf)<<12, + bh=(b>>4)<<12; + + bl=(bl>>shift)+(((l0*f0)+(l1*f1)+32)>>6); + *dp++=bl; + l1=l0; + l0=bl; + + bh=(bh>>shift)+(((l0*f0)+(l1*f1)+32)>>6); + *dp++=bh; + l1=l0; + l0=bh; + } + + return dp; +} + +// +// +// + +static int shift_register15(int &shift) +{ + int bit0, bit1, bit14; + + bit0 = shift & 1; + bit1 = (shift & 2) >> 1; + bit14 = (bit0 ^ bit1) ^ 1; + shift >>= 1; + shift |= (bit14 << 14); + return bit0; +} + +// +// +// + +//------------------------------------------------- +// spu_device - constructor +//------------------------------------------------- + +spu_device::spu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, SPU, "SPU", tag, owner, clock, "spu", __FILE__), + device_sound_interface(mconfig, *this), + m_irq_handler(*this), + dirty_flags(-1), + status_enabled(false), + xa_voll(0x8000), + xa_volr(0x8000), + changed_xa_vol(0) +{ +} + +//------------------------------------------------- +// static_set_irqf - configuration helper to set +// the IRQ callback +//------------------------------------------------- + +void spu_device::device_start() +{ + m_irq_handler.resolve_safe(); + + voice=new voiceinfo [24]; + spu_ram=new unsigned char [spu_ram_size]; + + xa_buffer=new stream_buffer(xa_sector_size,xa_buffer_sectors); + cdda_buffer=new stream_buffer(cdda_sector_size,cdda_buffer_sectors); + + init_stream(); + + cache=new sample_cache *[spu_ram_size>>4]; + memset(cache,0,(spu_ram_size>>4)*sizeof(sample_cache *)); + + // register save state stuff + save_item(NAME(reg)); // this covers all spureg.* plus the reverb parameter block + save_item(NAME(xa_cnt)); + save_item(NAME(cdda_cnt)); + save_item(NAME(xa_freq)); + save_item(NAME(cdda_freq)); + save_item(NAME(xa_channels)); + save_item(NAME(xa_spf)); + save_item(NAME(cur_frame_sample)); + save_item(NAME(cur_generate_sample)); + save_pointer(NAME(spu_ram), spu_ram_size); + + save_item(NAME(xa_buffer->head)); + save_item(NAME(xa_buffer->tail)); + save_item(NAME(xa_buffer->in)); + save_item(NAME(xa_buffer->sector_size)); + save_item(NAME(xa_buffer->num_sectors)); + save_item(NAME(xa_buffer->buffer_size)); + save_item(NAME(xa_buffer->buffer)); + + save_item(NAME(cdda_buffer->head)); + save_item(NAME(cdda_buffer->tail)); + save_item(NAME(cdda_buffer->in)); + save_item(NAME(cdda_buffer->sector_size)); + save_item(NAME(cdda_buffer->num_sectors)); + save_item(NAME(cdda_buffer->buffer_size)); + save_item(NAME(cdda_buffer->buffer)); +} + +void spu_device::device_reset() +{ + cur_reverb_preset = NULL; + cur_frame_sample = 0; + cur_generate_sample = 0; + + sample_cache::cache_size = 0; + + status_enabled = false; + xa_voll = xa_volr = 0x8000; + dirty_flags = -1; + changed_xa_vol = 0; + + xa_cnt=0; + xa_freq=0; + xa_channels=2; + xa_spf=0; + xa_out_ptr=0; + xa_playing=false; + memset(xa_last,0,sizeof(xa_last)); + + cdda_cnt=0; + cdda_playing=false; + m_cd_out_ptr = 0; + + memset(spu_ram,0,spu_ram_size); + memset(reg,0,0x200); + memset(voice,0,sizeof(voiceinfo)*24); + + spureg.status|=(1<<7)|(1<<10); + + memset(cache,0,(spu_ram_size>>4)*sizeof(sample_cache *)); + + for (unsigned int i=0; i<4; i++) + output_buf[i]=new unsigned char [output_buffer_size]; + output_head=output_tail=output_size=0; + + noise_t=0; + noise_seed=12345; + noise_cur=shift_register15(noise_seed)?0x7fff:0x8000; +} + +void spu_device::device_post_load() +{ + // invalidate the SPURAM cache + invalidate_cache(0, spu_ram_size); + flush_output_buffer(); + + // mark everything dirty + dirty_flags = -1; + + // kill and reallocate reverb to avoid artifacts + global_free(rev); + rev = new reverb(44100); + + // and do some update processing + update_reverb(); + update_key(); + update_voice_state(); + update_irq_event(); +} + +// +// +// +void spu_device::device_stop() +{ + for (unsigned int i=0; i<4; i++) + global_free_array(output_buf[i]); + + kill_stream(); + + global_free_array(spu_ram); + invalidate_cache(0,spu_ram_size); + global_free_array(cache); + global_free(xa_buffer); + global_free(cdda_buffer); + global_free_array(voice); +} +// +// +// + +void spu_device::init_stream() +{ + const unsigned int hz=44100; + + m_stream = machine().sound().stream_alloc(*this, 0, 2, hz); + + rev=new reverb(hz); + + cdda_freq=(unsigned int)((44100.0f/(float)hz)*4096.0f); + freq_multiplier=(float)spu_base_frequency_hz/(float)hz; +} + +// +// +// + +void spu_device::kill_stream() +{ + global_free(rev); + rev=NULL; +} + +// +// +// + +void spu_device::reinit_sound() +{ + kill_stream(); + init_stream(); + flush_output_buffer(); + dirty_flags|=dirtyflag_voice_mask; +} + +// +// +// + +void spu_device::kill_sound() +{ + kill_stream(); +} + +// +// +// + +READ16_MEMBER( spu_device::read ) +{ + unsigned short ret=0, *rp=(unsigned short *)(reg+((offset*2)&0x1ff)); + + m_stream->update(); + + ret=*rp; + + #ifdef debug_spu_registers + printf("spu: read word %08x = %04x [%s]\n", + offset*2, + ret, + get_register_name(offset*2)); + #endif + + return ret; +} + +// +// +// + +WRITE16_MEMBER( spu_device::write ) +{ + #ifdef debug_spu_registers + printf("spu: write %08x = %04x [%s]\n", + offset*2, + data, + get_register_name(offset*2)); + #endif + + m_stream->update(); + + const unsigned int a=(offset*2)&0x1ff; + switch (a) + { + case spureg_trans_addr: + spureg.trans_addr=data; + taddr=data<<3; + break; + + case spureg_data: + dirty_flags|=dirtyflag_ram; + write_data(data); + break; + + default: + { + unsigned short *rp=(unsigned short *)(reg+a); + + if ((a==spureg_irq_addr) || + ((a==spureg_ctrl) && ((rp[0]^data)&spuctrl_irq_enable))) + dirty_flags|=dirtyflag_irq; + + *rp=data; + break; + } + } + + if ((a>spureg_reverb_config) && (a<=spureg_last)) + dirty_flags|=dirtyflag_reverb; + + if (a<=spureg_voice_last) + { + unsigned int v=(a>>4),r=(a&0xf); + if (r==0xe) + { + voice[v].forceloop=true; + } + + dirty_flags|=(1<>1; + if (ch<2) + { + unsigned int v=addr>>4; + unsigned short newval=*(unsigned short *)(reg+addr); + + if (newval&0x8000) + { + #if 0 + printf("cur=%04x on=%d",voice[v].vol[ch],(spureg.chon>>ch)&1); + switch ((newval>>13)&3) + { + case 0: printf("linear inc: phase=%d val=%02x\n",(newval>>12)&1,newval&0x7f); break; + case 1: printf("linear dec: phase=%d val=%02x\n",(newval>>12)&1,newval&0x7f); break; + case 2: printf("exp inc: phase=%d val=%02x\n",(newval>>12)&1,newval&0x7f); break; + case 3: printf("exp dec: phase=%d val=%02x\n",(newval>>12)&1,newval&0x7f); break; + } + #endif + } + else + { + voice[v].vol[ch]=((int)newval<<17)>>17; + } + } + } +} + +// +// +// + +void spu_device::write_data(const unsigned short data) +{ + #ifdef debug_spu_registers + printf("spu: write data %04x @ %04x\n",data,taddr); + #endif + + assert(taddr>4]) flush_cache(cache[taddr>>4],taddr,taddr+2); + *((unsigned short *)(spu_ram+taddr))=data; + taddr+=2; +} + +// +// +// + +void spu_device::update_key() +{ + dirty_flags|=((spureg.keyon|spureg.keyoff)&dirtyflag_voice_mask); + + if (spureg.keyoff) + { + unsigned int d=spureg.keyoff; + for (int i=0; i<24; i++, d>>=1) + if (d&1) key_off(i); + } + + if (spureg.keyon) + { + unsigned int d=spureg.keyon; + for (int i=0; i<24; i++, d>>=1) + if (d&1) key_on(i); + spureg.chon|=spureg.keyon; + } + + spureg.keyon=spureg.keyoff=0; +} + +// +// +// + +void spu_device::flush_cache(sample_cache *sc, + const unsigned int istart, + const unsigned int iend) +{ + for (unsigned int a=sc->start; aend; a+=16) + cache[a>>4]=NULL; + +/* log_static(log_spu,"cache_invalidate: %08x->%08x\n", + sc->start, + sc->end);*/ + + sc->invalid_start=min(sc->invalid_start,istart); + sc->invalid_end=max(sc->invalid_end,iend); + sc->valid=false; + sc->remove_ref(); +} + +// +// +// + +void spu_device::invalidate_cache(const unsigned int st, const unsigned int en) +{ + for (unsigned int a=st; a>4]) flush_cache(cache[a>>4],st,en); +} + +// +// +// + +spu_device::sample_cache *spu_device::get_sample_cache(const unsigned int addr) +{ +// log_static(log_spu,"get_sample_cache: %08x\n",addr); + + assert(addr>4]; + if (sc) return sc; + + unsigned int loop=0; + + sc=new sample_cache; + sc->valid=true; + sc->start=addr; + sc->loop=NULL; + + adpcm_packet *ap=(adpcm_packet *)(spu_ram+sc->start); + unsigned int a; + for (a=addr; a<(512*1024); a+=16, ap++) + { + if (cache[a>>4]) flush_cache(cache[a>>4],a,a+16); + cache[a>>4]=sc; + + if ((ap->flags&adpcmflag_loop_start) && (ap->flags&adpcmflag_loop)) loop=a; + if (ap->flags&adpcmflag_end) break; + } + + if ((a < 0x80000) && (ap->flags&adpcmflag_loop)) sc->is_loop=true; + + sc->end=min(spu_ram_size,a+16); + + unsigned int sz=((sc->end-sc->start)>>4)*28; + sc->data=new signed short [sz]; + sample_cache::cache_size+=sz<<1; + sc->loopaddr=loop; + if (loop) sc->loop=sc->data+(((loop-sc->start)>>4)*28); + + signed short *dp=sc->data; + ap=(adpcm_packet *)(spu_ram+sc->start); + + for (a=sc->start; aend; a+=16, ap++) + dp=sc->decoder.decode_packet(ap,dp); + + sc->dend=dp; + sc->add_ref(); + +/* log_static(log_spu,"cache_add: %08x->%08x\n", + sc->start, + sc->end);*/ + + return sc; +} + +// +// +// + +bool spu_device::translate_sample_addr(const unsigned int addr, cache_pointer *cp) +{ + assert((addr&0xf)==0); + cp->reset(); + if ((cp->cache=get_sample_cache(addr))) + { + cp->ptr=cp->cache->data+(((addr-cp->cache->start)>>4)*28); + cp->cache->add_ref(); + return true; + } + return false; +} + +// +// Get distance in input samples to next IRQ for voice +// + +unsigned int spu_device::get_irq_distance(const voiceinfo *vi) +{ + if (spureg.ctrl&spuctrl_irq_enable) + { + unsigned int irq_addr=spureg.irq_addr<<3; + signed short *irq_ptr; + + if ((irq_ptr=vi->play.cache->get_sample_pointer(irq_addr))) + { + // IRQ address is inside this voices current cache block. Return distance + // if current play address is lower, or equal (and irq has not already + // triggered) + + if ((vi->play.ptrhitirq) && (vi->play.ptr==irq_ptr))) + { + return irq_ptr-vi->play.ptr; + } + } + + if ((vi->loop) && + (irq_ptr=vi->loop.cache->get_sample_pointer(irq_addr)) && + (irq_ptr>=vi->loop.ptr)) + { + // IRQ address is inside this voices loop cache, return distance + + return (vi->play.cache->dend-vi->play.ptr)+ + (irq_ptr-vi->loop.ptr); + } + } + + // IRQs not enabled, or IRQ address not reachable by voice, distance is spu_infinity + + return spu_infinity; +} + +// +// +// + +void spu_device::update_voice_events(voiceinfo *vi) +{ + if (vi->pitch) + { + // Calculate time until end of sample in output samples + + vi->samplestoend=(unsigned int)((((INT64)(vi->play.cache->dend-vi->play.ptr)<<12)-vi->dptr)+(vi->pitch-1))/vi->pitch; + if (vi->inloopcache) + { + // Voice is inside loop cache, return time until end of that if lower + + assert(vi->lcptrloop_cache->len); + vi->samplestoend=min(vi->samplestoend, + (unsigned int)((((INT64)(vi->loop_cache->len-vi->lcptr)<<12)-vi->dptr)+(vi->pitch-1))/vi->pitch); + } + + // Calculate time until next IRQ in output samples + + unsigned int irqdist=get_irq_distance(vi); + if (irqdist!=spu_infinity) + { + // Convert IRQ input sample distance to output samples + + vi->samplestoirq=(unsigned int)(((((INT64)irqdist)<<12)-vi->dptr)+(vi->pitch-1))/vi->pitch; + } else + { + vi->samplestoirq=spu_infinity; + } + } else + { + // Voice pitch is 0, distance to sample end and IRQ is spu_infinity + + vi->samplestoend=vi->samplestoirq=spu_infinity; + } +} + +// +// +// + +bool spu_device::update_voice_state(const unsigned int v) +{ + voicereg *vr=&spureg.voice[v]; + voiceinfo *vi=&voice[v]; + + // Update sample cache if necessary + + if (! vi->play.update(this)) + return false; + assert(vi->play.ptrplay.cache->dend); + + // Get pitch from voice register and apply frequency multiplier if + // there is one in effect + + vi->pitch=vr->pitch; + vi->pitch=(unsigned int)(vi->pitch*freq_multiplier); + + // Update event times + + update_voice_events(vi); + + return true; +} + +// +// +// + +spu_device::sample_loop_cache *spu_device::get_loop_cache(sample_cache *cache, const unsigned int lpen, sample_cache *lpcache, const unsigned int lpst) +{ + // Check for existing loop cache + + sample_loop_cache *ret=lpcache->find_loop_cache(lpen,lpst); + if (! ret) + { + // No loop cache exists for this address pair, create a new one + + sample_loop_cache *lc=new sample_loop_cache; + lc->loopend=lpen; + lc->loopstart=lpst; + lpcache->add_loop_cache(lc); + ret=lc; + + // Decode samples from start address using decoder state at end address + + unsigned int adr=lpst; + adpcm_decoder tmp=cache->decoder; + signed short *dp=lc->data; + for (unsigned int i=0; ((iend)); i++, adr+=16) + dp=tmp.decode_packet((adpcm_packet *)(spu_ram+adr),dp); + + #ifdef log_loop_cache + log(log_spu,"spu: add loop cache %08x %08x->%08x (end at %08x)\n",lc,lpen,lpst,adr); + #endif + + lc->len=dp-lc->data; + } + + return ret; +} + +// +// +// + +void spu_device::update_voice_loop(const unsigned int v) +{ +// voicereg *vr=&spureg.voice[v]; + voiceinfo *vi=&voice[v]; + unsigned int ra = 0; + + // Check for looping using the voices repeat address register and get + // a pointer to the loop position if enabled + + vi->loop.reset(); + + // If loop address is not forced get the loop pointer from the cache + // block (if present) + + if ((! voice[v].forceloop) && + (vi->play.cache->get_loop_pointer(&vi->loop))) + { + ra=vi->play.cache->loopaddr; + } + + // Otherwise use the address set in repaddr (if set) + + if ((! vi->loop) && (vi->play.cache->is_loop)) + { + ra=spureg.voice[v].repaddr<<3; + ra=(ra+0xf)&~0xf; + const adpcm_packet *ap=ra?(adpcm_packet *)(spu_ram+ra):NULL; + + if (ap) + { + if (ap->flags&adpcmflag_loop) + { + // Repeat address points to a block with loop flag set + + if (! vi->play.cache->get_sample_pointer(ra,&vi->loop)) + { + // Repeat address is in a different block + + translate_sample_addr(ra,&vi->loop); + } + } + } + } + + // Update loop cache + + if (vi->loop) + { + vi->loop_cache=get_loop_cache(vi->play.cache,vi->play.cache->end,vi->loop.cache,ra); + } +} + +// +// +// + +void spu_device::update_voice_state() +{ + // If RAM or irq state is dirty make all voices dirty + + if (dirty_flags&(dirtyflag_ram|dirtyflag_irq)) + { + dirty_flags|=dirtyflag_voice_mask; + dirty_flags&=~(dirtyflag_ram|dirtyflag_irq); + } + + // Update state for dirty voices + + if (dirty_flags&dirtyflag_voice_mask) + { + unsigned int voicemask=1; + for (unsigned int i=0; i<24; i++, voicemask<<=1) + if (dirty_flags&voicemask) + { + update_voice_state(i); + dirty_flags&=~voicemask; + } + } +} + +// +// Process voice state and build output segments +// +// Input: const unsigned int v Voice number +// const unsigned int sz Amount of time to process (in output samples) +// unsigned int *tleft Returned number of output samples remaining +// +// Output: bool true if voice is still playing +// + +bool spu_device::process_voice(const unsigned int v, + const unsigned int sz, + void *ptr, + void *fmnoise_ptr, + void *outxptr, + unsigned int *tleft) +{ + bool ret=true; + unsigned int voice_mask=1<play) + { + *tleft=sz; + return false; + } + + // Generate samples + + while (num) + { + // Play up to end of sample, envelope event, or IRQ, whichever comes first + + unsigned int ntoplay=fm?1:num, + nextevent=min(vi->samplestoend, + min(vi->samplestoirq,vi->envsamples)); + ntoplay=min(ntoplay,nextevent); + + if (ntoplay) + { + signed short *noisep=NULL; + + if (fm) + { + int fmv=((signed short *)fmnoise_ptr)[off<<1]; + vi->pitch=spureg.voice[v].pitch; + vi->pitch=(unsigned int)(vi->pitch*freq_multiplier); + vi->pitch=(vi->pitch*(fmv+32768))>>15; + } else + if (noise) + { + noisep=(signed short *)fmnoise_ptr; + noisep+=(off<<1); + } + + signed short *dp=(signed short *)ptr, + *outxp=(signed short *)outxptr; + dp+=off<<1; + if (outxp) outxp+=off<<1; + + generate_voice(v, dp, noisep, outxp, ntoplay); + + num-=ntoplay; + off+=ntoplay; + + vi->samplestoend-=ntoplay; + if (vi->samplestoirq!=spu_infinity) vi->samplestoirq-=ntoplay; + if (vi->envsamples!=spu_infinity) vi->envsamples-=ntoplay; + vi->hitirq=false; + } + + // Determine which event(s) we hit + + bool hitend=fm?(vi->play.ptr>=vi->play.cache->dend) + :(vi->samplestoend==0), + hitirq=(vi->samplestoirq==0), + hitenv=(vi->envsamples==0); + + // Update loop cache pointer if we are playing a loop cache + + if ((vi->inloopcache) && (vi->lcptr>=vi->loop_cache->len)) + { + vi->inloopcache=false; + hitend=(vi->play.ptr>=vi->play.cache->dend); + + #ifdef log_loop_cache + log(log_spu,"spu: %d leave loop cache %08x, lcptr=%d, hitend=%d\n", + v, + vi->loop_cache, + vi->lcptr, + hitend); + #endif + } + + bool stopped=false; + + if (hitend) + { + // End of sample reached, calculate how far we overshot + + unsigned int poff=vi->play.ptr-vi->play.cache->dend; + + // Make sure loop info is up to date and end the current output segment + + update_voice_loop(v); + if (vi->loop) + { + // We are looping, set play address to loop address and account for + // overshoot + + vi->play=vi->loop; + vi->play.ptr+=poff; + vi->lcptr=poff; + vi->inloopcache=(poffloop_cache->len); + + #ifdef log_loop_cache + if (vi->inloopcache) + log(log_spu,"spu: %d enter loop cache %08x, lcptr=%d\n", + v, + vi->loop_cache, + vi->lcptr); + #endif + + // Check for IRQ at/just after repeat address + + if (spureg.ctrl&spuctrl_irq_enable) + { + if (spureg.voice[v].repaddr==spureg.irq_addr) + hitirq=true; + + signed short *irq_ptr; + unsigned int irq_addr=spureg.irq_addr<<3; + + if ((irq_ptr=vi->loop.cache->get_sample_pointer(irq_addr))) + { + if ((irq_ptr>=vi->loop.ptr) && + (vi->play.ptr>=irq_ptr)) + hitirq=true; + } + } + } else + { + // Not looping, stop voice + + spureg.reverb&=~(1<play.ptrplay.cache->dend)); + } else + { + assert(vi->play.ptrplay.cache->dend); + } + + if (hitirq) + { + // Went past IRQ address, trigger IRQ + m_irq_handler(1); + + vi->samplestoirq=spu_infinity; + vi->hitirq=true; + } + + if (hitenv) + { + // Envelope event, update the envelope (stop if necessary), and start + // a new output segment + + stopped=((stopped) || (! update_envelope(v))); + } + + if (stopped) + { + // Voice is now stopped + + ret=false; + break; + } + + // Update voice event times + + update_voice_events(vi); + } + + // Set current volume register + + spureg.voice[v].curvol=(unsigned short)(vi->env_level*32767.0f); + + // Return how much time is left and whether or not the voice is still playing + + *tleft=num; + return ret; +} + +// +// Generate voice output samples +// +// Inputs: const unsigned int v Voice number +// void *ptr Output buffer (if no reverb) +// const unsigned int sz Number of samples to output +// + +void spu_device::generate_voice(const unsigned int v, + void *ptr, + void *noiseptr, + void *outxptr, + const unsigned int sz) +{ + voiceinfo *vi=&voice[v]; + signed short *fp,*sp; + unsigned int n=sz; + + // Get input pointer + + if (vi->inloopcache) + { + sp=vi->loop_cache->data+vi->lcptr; + } else + { + sp=vi->play.ptr; + } + fp=sp; + + unsigned int dptr=vi->dptr; + + // Get output pointer (and advance output offset) + + signed short *dp=(signed short *)ptr; + signed short *outxp=(signed short *)outxptr; + + // Calculate fixed point envelope levels/deltas premultiplied by channel volume + + int vol_l=outxptr?0x3fff:vi->vol[0], + vol_r=outxptr?0x3fff:vi->vol[1], + env_l=(int)(vi->env_level*2.0f*vol_l), + env_r=(int)(vi->env_level*2.0f*vol_r), + envdelta_l=(int)(vi->env_delta*2.0f*vol_l), + envdelta_r=(int)(vi->env_delta*2.0f*vol_r); + + // Update the segments envelope level + + vi->env_level+=(n*vi->env_delta); + + if (noiseptr) + { + INT64 dptr=((INT64)n*vi->pitch)+vi->dptr; + unsigned int d=(unsigned int)(dptr>>12); + vi->dptr=(unsigned int)(dptr&0xfff); + vi->play.ptr+=d; + if (vi->inloopcache) vi->lcptr+=d; + + sp=(signed short *)noiseptr; + + if (outxp) + { + while (n--) + { + int vl=*sp++, + vr=*sp++, + l=(vl*env_l)>>15, + r=(vr*env_r)>>15; + env_l+=envdelta_l; + env_r+=envdelta_r; + + outxp[0]=l; + outxp[1]=r; + outxp+=2; + + l=(l*vi->vol[0])>>15; + r=(r*vi->vol[1])>>15; + + dp[0]=clamp(l+dp[0]); + dp[1]=clamp(r+dp[1]); + dp+=2; + } + } else + { + while (n--) + { + int vl=*sp++, + vr=*sp++, + l=(vl*env_l)>>15, + r=(vr*env_r)>>15; + env_l+=envdelta_l; + env_r+=envdelta_r; + + dp[0]=clamp(l+dp[0]); + dp[1]=clamp(r+dp[1]); + dp+=2; + } + } + } else + { + if (1) //settings.sound_interpolate) + { + unsigned int num_stitch=0; + signed short *ep; + + // Linear interpolation enabled, calculate how many samples we will + // read from input data + + INT64 fracend=(((INT64)(n-1))*vi->pitch)+dptr; + unsigned int end=(unsigned int)(fracend>>12); + + // Get pointer to last sample of input data + + if (vi->inloopcache) + { + ep=vi->loop_cache->data+vi->loop_cache->len-1; + } else + { + ep=vi->play.cache->dend-1; + } + + // If we read the last sample "stitching" will be necessary (inerpolation + // from last sample of segment to first sample of next segment) + + if (((sp+end)>=ep) && (vi->pitch)) + { + num_stitch=min(n,max(0x1fff/vi->pitch,1)); + n-=num_stitch; + } + + // Generate samples + + if (outxp) + { + while (n--) + { + int v=sp[0]; + + v+=((sp[1]-v)*(int)dptr)>>12; + + int l=(v*env_l)>>15, + r=(v*env_r)>>15; + env_l+=envdelta_l; + env_r+=envdelta_r; + + outxp[0]=l; + outxp[1]=r; + outxp+=2; + + l=(l*vi->vol[0])>>15; + r=(r*vi->vol[1])>>15; + + dp[0]=clamp(l+dp[0]); + dp[1]=clamp(r+dp[1]); + dp+=2; + + dptr+=vi->pitch; + sp+=(dptr>>12); + dptr&=0xfff; + } + } + else + { + while (n--) + { + int v=sp[0]; + + v+=((sp[1]-v)*(int)dptr)>>12; + + int l=(v*env_l)>>15, + r=(v*env_r)>>15; + env_l+=envdelta_l; + env_r+=envdelta_r; + + dp[0]=clamp(l+dp[0]); + dp[1]=clamp(r+dp[1]); + dp+=2; + + dptr+=vi->pitch; + sp+=(dptr>>12); + dptr&=0xfff; + } + } + + if (num_stitch) + { + // Stitch samples, get the first sample of the next segment + + signed short *nsp=NULL; + + if (vi->inloopcache) + { + nsp=vi->play.ptr+(vi->loop_cache->len-vi->lcptr); + if (nsp>=vi->play.cache->dend) + nsp=NULL; + } + + if (! nsp) + { + update_voice_loop(v); + if (vi->loop) nsp=vi->loop_cache->data; + } + + int ns=nsp?nsp[0]:0; + + // Generate stitch samples + + if (outxp) + { + while (num_stitch--) + { + int v=sp[0], + nv=(sp>=ep)?ns:sp[1]; + + v+=((nv-v)*(int)dptr)>>12; + + int l=(v*env_l)>>15, + r=(v*env_r)>>15; + env_l+=envdelta_l; + env_r+=envdelta_r; + + outxp[0]=l; + outxp[1]=r; + outxp+=2; + + l=(l*vi->vol[0])>>15; + r=(r*vi->vol[1])>>15; + + dp[0]=clamp(l+dp[0]); + dp[1]=clamp(r+dp[1]); + dp+=2; + + dptr+=vi->pitch; + sp+=(dptr>>12); + dptr&=0xfff; + } + } else + { + while (num_stitch--) + { + int v=sp[0], + nv=(sp>=ep)?ns:sp[1]; + + v+=((nv-v)*(int)dptr)>>12; + + int l=(v*env_l)>>15, + r=(v*env_r)>>15; + env_l+=envdelta_l; + env_r+=envdelta_r; + + dp[0]=clamp(l+dp[0]); + dp[1]=clamp(r+dp[1]); + dp+=2; + + dptr+=vi->pitch; + sp+=(dptr>>12); + dptr&=0xfff; + } + } + } + } else + { + // Generate samples with no interpolation + + if (outxp) + { + while (n--) + { + int l=(sp[0]*env_l)>>15, + r=(sp[0]*env_r)>>15; + env_l+=envdelta_l; + env_r+=envdelta_r; + + outxp[0]=l; + outxp[1]=r; + outxp+=2; + + l=(l*vi->vol[0])>>15; + r=(r*vi->vol[1])>>15; + + dp[0]=clamp(l+dp[0]); + dp[1]=clamp(r+dp[1]); + dp+=2; + + dptr+=vi->pitch; + sp+=(dptr>>12); + dptr&=0xfff; + } + } else + { + while (n--) + { + int l=(sp[0]*env_l)>>15, + r=(sp[0]*env_r)>>15; + env_l+=envdelta_l; + env_r+=envdelta_r; + + dp[0]=clamp(l+dp[0]); + dp[1]=clamp(r+dp[1]); + dp+=2; + + dptr+=vi->pitch; + sp+=(dptr>>12); + dptr&=0xfff; + } + } + } + + // Update segment pointer + + vi->play.ptr+=sp-fp; + vi->dptr=dptr; + if (vi->inloopcache) + vi->lcptr=sp-vi->loop_cache->data; + } +} + +// +// +// + +bool spu_device::update_envelope(const int v) +{ + while (voice[v].envsamples==0) + { + voice[v].env_state++; + + switch (voice[v].env_state) + { + case 1: // decay + voice[v].env_level=1.0f; + voice[v].env_delta=voice[v].env_dr; + if (voice[v].env_dr!=0.0f) + { + voice[v].envsamples=(unsigned int)((voice[v].env_sl-1.0f)/voice[v].env_dr); + } else + { + voice[v].envsamples=spu_infinity; + } + break; + + case 2: // sustain + voice[v].env_level=voice[v].env_sl; + voice[v].env_delta=voice[v].env_sr; + + if (voice[v].env_sr>0.0f) + { + voice[v].envsamples=(unsigned int)((1.0f-voice[v].env_level)/voice[v].env_sr); + } else + if (voice[v].env_sr<0.0f) + { + voice[v].envsamples=(unsigned int)(voice[v].env_level/-voice[v].env_sr); + } else + { + voice[v].envsamples=spu_infinity; + } + break; + + case 3: // sustain end + voice[v].envsamples=spu_infinity; + voice[v].env_delta=0.0f; + if (voice[v].env_sr<=0.0f) + { + voice[v].env_level=0.0f; + return false; + } else + { + voice[v].env_level=1.0f; + } + break; + + case 4: // release + voice[v].env_level=mindb(1.0f,maxdb(0.0f,voice[v].env_level)); + voice[v].env_delta=voice[v].env_rr; + if (voice[v].env_rr == -0.0f) // 0.0 release means infinite time + { + voice[v].envsamples=spu_infinity; + } + else + { + voice[v].envsamples=(unsigned int)(voice[v].env_level/-voice[v].env_rr); + } + break; + + case 5: // release end + voice[v].env_level=0.0f; + voice[v].env_delta=0.0f; + voice[v].envsamples=spu_infinity; + return false; + } + } + return true; +} + +// +// +// + +void spu_device::key_on(const int v) +{ + voice[v].loop.reset(); + +// printf("key_on: %d @ %x (pitch %x)\n", v, spureg.voice[v].addr<<3, spureg.voice[v].pitch); + + translate_sample_addr(spureg.voice[v].addr<<3,&voice[v].play); + assert(voice[v].play.ptrdend); + + voice[v].keyontime=0; //get_system_time(); + + voice[v].dptr=0; + voice[v].inloopcache=false; + voice[v].lcptr=-1; + voice[v].env_level=0.0f; + voice[v].env_state=0; + voice[v].forceloop=false; + + // Note: ChronoCross has note hang problems if this is 0 immediately + // after key on + spureg.voice[v].curvol=1; + + for (unsigned int ch=0; ch<2; ch++) + { + { + voice[v].sweep_vol[ch]=1.0f; + } + } + + #ifdef warn_if_sweep_used + static bool sweepused; + if ((spureg.voice[v].vol_l|spureg.voice[v].vol_r)&0x8000) + { + if (! sweepused) + { + printf("sweep\n"); + sweepused=true; + } + } + #endif + + #ifdef assert_if_sweep_used + assert(((spureg.voice[v].vol_l|spureg.voice[v].vol_r)&0x8000)==0); + #endif + + if (spureg.voice[v].adsl&adsl_am) + { + voice[v].env_ar=get_pos_exp_rate((spureg.voice[v].adsl&adsl_ar_mask)>>adsl_ar_shift); + } else + { + voice[v].env_ar=get_linear_rate((spureg.voice[v].adsl&adsl_ar_mask)>>adsl_ar_shift); + } + + voice[v].env_dr=-get_decay_rate((spureg.voice[v].adsl&adsl_dr_mask)>>adsl_dr_shift); + voice[v].env_sl=get_sustain_level(spureg.voice[v].adsl&adsl_sl_mask); + + if (spureg.voice[v].srrr&srrr_sm) + { + if (spureg.voice[v].srrr&srrr_sd) + { + voice[v].env_sr=get_neg_exp_rate((spureg.voice[v].srrr&srrr_sr_mask)>>srrr_sr_shift); + } else + { + voice[v].env_sr=get_pos_exp_rate((spureg.voice[v].srrr&srrr_sr_mask)>>srrr_sr_shift); + } + } else + { + voice[v].env_sr=get_linear_rate((spureg.voice[v].srrr&srrr_sr_mask)>>srrr_sr_shift); + if (spureg.voice[v].srrr&srrr_sd) + voice[v].env_sr=-voice[v].env_sr; + } + + if (spureg.voice[v].srrr&srrr_rm) + { + voice[v].env_rr=-get_exp_release_rate(spureg.voice[v].srrr&srrr_rr_mask); + } else + { + voice[v].env_rr=-get_linear_release_rate(spureg.voice[v].srrr&srrr_rr_mask); + } + + voice[v].envsamples=(unsigned int)(1.0f/voice[v].env_ar); + voice[v].env_delta=voice[v].env_ar; +} + +// +// +// + +void spu_device::set_xa_format(const float _freq, const int channels) +{ + // Adjust frequency to compensate for slightly slower/faster frame rate +// float freq=44100.0; //(_freq*get_adjusted_frame_rate())/ps1hw.rcnt->get_vertical_refresh(); + + xa_freq=(unsigned int)((_freq/44100.0f)*4096.0f); + xa_channels=channels; + xa_spf=(unsigned int)(_freq/60.0f)*channels; +} + +// +// +// + +void spu_device::generate_xa(void *ptr, const unsigned int sz) +{ + if (xa_buffer->get_bytes_in()) + { + // Don't start playing until 8 frames worth of data are in + + if ((! xa_playing) && (xa_buffer->get_bytes_in()<(xa_spf<<3))) + { +// debug_xa("waiting...\n"); + return; + } + + xa_playing=true; + + // Init buffer pointers/counters + + int n=sz>>2; + signed short *sp=(signed short *)xa_buffer->get_tail_ptr(), + *dp=(signed short *)ptr; + unsigned int noff=(1<get_tail_offset(); + + assert((xa_channels==1) || (xa_channels==2)); + + // Calculate volume + + int voll=spureg.cdvol_l, + volr=spureg.cdvol_r; + voll=(voll*xa_voll)>>14; + volr=(volr*xa_volr)>>14; + + // Generate requested number of XA samples + + while ((xa_buffer->get_bytes_in()) && (n--)) + { + // Get left/right input samples + + int vl=sp[0], + vr=sp[xa_channels-1]; + + // Linear interpolation + + if (1) //settings.sound_interpolate) + { + signed short *nsp=(signed short *)xa_buffer->get_tail_ptr(noff); + int vdl=nsp[0]-vl, + vdr=nsp[xa_channels-1]-vr; + + vl+=(vdl*(int)xa_cnt)>>12; + vr+=(vdr*(int)xa_cnt)>>12; + } + + // Multiply by + + vl=(vl*voll)>>15; + vr=(vr*volr)>>15; + + // Write to SPU XA buffer (for emulation purposes - some games read this + // back to do analysers, etc...) + + *(signed short *)(spu_ram+xa_out_ptr)=vl; + *(signed short *)(spu_ram+xa_out_ptr+0x800)=vr; + xa_out_ptr=(xa_out_ptr+2)&0x7ff; + + // Mix samples into output buffer + + dp[0]=clamp(dp[0]+vl); + dp[1]=clamp(dp[1]+vr); + dp+=2; + + // Advance input counter/pointer + + xa_cnt+=xa_freq; + int ss=(xa_cnt>>12); + xa_cnt&=0xfff; + + if (ss) + { + ss<<=xa_channels; + ss=min(ss,(int)xa_buffer->get_bytes_in()); + + xa_buffer->increment_tail(ss); + sp=(signed short *)xa_buffer->get_tail_ptr(); + } + } + + // Delete buffer markers we have passed + + xa_buffer->delete_markers(oldtail); + } + + // If we run out of input set status to stopped and clear the SPU XA buffer + + if (! xa_buffer->get_bytes_in()) + { + xa_playing=false; + + memset(spu_ram,0,0x1000); + xa_out_ptr=0; + } +} + +// +// +// + +void spu_device::generate_cdda(void *ptr, const unsigned int sz) +{ + if (cdda_buffer->get_bytes_in()) + { + unsigned int cdda_spf=(44100*4)/60.0, + freq=(unsigned int)((cdda_freq*60.0)/60.0); + + if ((! cdda_playing) && (cdda_buffer->get_bytes_in()<(cdda_spf<<3))) + return; + + cdda_playing=true; + + int n=sz>>2; + signed short *sp=(signed short *)cdda_buffer->get_tail_ptr(), + *dp=(signed short *)ptr; + unsigned int oldtail=cdda_buffer->get_tail_offset(); + + int voll=spureg.cdvol_l, + volr=spureg.cdvol_r; + + while ((cdda_buffer->get_bytes_in()) && (n--)) + { + INT16 vl = ((sp[0]*voll)>>15); + INT16 vr = ((sp[1]*volr)>>15); + + // if the volume adjusted samples are stored here, vibribbon does nothing + *(signed short *)(spu_ram+m_cd_out_ptr)=sp[0]; + *(signed short *)(spu_ram+m_cd_out_ptr+0x400)=sp[1]; + m_cd_out_ptr=(m_cd_out_ptr+2)&0x3ff; + + //if((m_cd_out_ptr == ((spureg.irq_addr << 3) & ~0x400)) && (spureg.ctrl & spuctrl_irq_enable)) + // m_irq_handler(1); + + dp[0]=clamp(dp[0]+vl); + dp[1]=clamp(dp[1]+vr); + dp+=2; + + cdda_cnt+=freq; + int ss=(cdda_cnt>>12); + cdda_cnt&=0xfff; + + if (ss) + { + ss<<=2; + + cdda_buffer->increment_tail(ss); + sp=(signed short *)cdda_buffer->get_tail_ptr(); + } + } + + cdda_buffer->delete_markers(oldtail); + + if (! cdda_buffer->get_bytes_in()) + cdda_playing=false; + +// if (n>0) printf("cdda buffer underflow (n=%d cdda_in=%d spf=%d)\n",n,cdda_buffer->get_bytes_in(),cdda_spf); + } + else if(((spureg.irq_addr << 3) < 0x800) && (spureg.ctrl & spuctrl_irq_enable)) + { + UINT16 irq_addr = (spureg.irq_addr << 3) & ~0x400; + UINT32 end = m_cd_out_ptr + (sz >> 1); + if(((m_cd_out_ptr < irq_addr) && (end > irq_addr)) || ((m_cd_out_ptr > (end & 0x3ff)) && ((end & 0x3ff) > irq_addr))) + m_irq_handler(1); + m_cd_out_ptr = end & 0x3fe; + } +} + +// +// +// + +void spu_device::key_off(const int v) +{ +// printf("key_off: %d\n", v); + + if (voice[v].env_state<=3) + { + voice[v].env_state=3; + voice[v].envsamples=0; + } +} + +// +// +// + +void spu_device::update_reverb() +{ + if (dirty_flags&dirtyflag_reverb) + { + cur_reverb_preset=find_reverb_preset((unsigned short *)®[0x1c0]); + + if (cur_reverb_preset==NULL) + { +// printf("spu: reverb=unknown (reg 1c0 = %x)\n", reg[0x1c0]); + } else + { +// printf("spu: reverb=%s\n",cur_reverb_preset->name); + spu_reverb_cfg=&cur_reverb_preset->cfg; + + if ((core_stricmp("reverb off",cur_reverb_preset->name)) && (spu_reverb_cfg->band_gain<=0.0f)) + { +// printf("spu: no reverb config for %s\n",cur_reverb_preset->name); + } + } + + dirty_flags&=~dirtyflag_reverb; + } +} + +// +// +// + +void spu_device::flush_output_buffer() +{ + output_head=output_tail=output_size=0; +} + +// +// +// + +void spu_device::generate(void *ptr, const unsigned int sz) +{ + cur_generate_sample+=sz>>2; + process_until(cur_generate_sample); + + update_reverb(); + + unsigned int left=sz; + unsigned char *dp=(unsigned char *)ptr; + + while ((left) && (output_size)) + { + unsigned int n=min(min(left,output_buffer_size-output_head),output_size); + memcpy(dp,output_buf[0]+output_head,n); + + rev->process((signed short *)dp, + (signed short *)(output_buf[1]+output_head), + spu_reverb_cfg, + (signed short)spureg.rvol_l, + (signed short)spureg.rvol_r, + n); + + output_size-=n; + output_head+=n; + output_head&=(output_buffer_size-1); + dp+=n; + left-=n; + } + + if (left) + { + memset(dp,0,left); + } + + generate_xa(ptr,sz); + generate_cdda(ptr,sz); +} + +// +// +// + +void spu_device::update_irq_event() +{ + if (spureg.ctrl&spuctrl_irq_enable) + { + unsigned int samplestoirq=spu_infinity; + for (int i=0; i<24; i++) + if (voice[i].samplestoirq!=spu_infinity) + { + if (voice[i].samplestoirq==0) + { + m_irq_handler(1); + + voice[i].samplestoirq=spu_infinity; + voice[i].hitirq=true; + } else + { + samplestoirq=min(samplestoirq,voice[i].samplestoirq); + } + } + } +} + + +// +// +// + +void spu_device::generate_noise(void *ptr, const unsigned int num) +{ + unsigned int np=(unsigned int)(65536.0f/(0x40-((spureg.ctrl&spuctrl_noise_mask)>>spuctrl_noise_shift))); + np=((np<<1)+np)>>1; + + signed short *dp=(signed short *)ptr; + + for (unsigned int i=0; i0xffff) + { + noise_t-=0xffff; + shift_register15(noise_seed); + noise_cur=noise_seed<<1; + } + } +} + +// +// +// + +void spu_device::process_until(const unsigned int tsample) +{ + while (tsample>cur_frame_sample) + { + unsigned int process_samples=(unsigned int)(tsample-cur_frame_sample); + + // Drop samples from the head of the queue if its full + + process_samples=min(process_samples,output_buffer_size>>2); + unsigned int nsz=output_size+(process_samples<<2); + if (nsz>output_buffer_size) + { + nsz-=output_buffer_size; + + output_head+=nsz; + output_size-=nsz; + output_head&=(output_buffer_size-1); + } + + // Decide how many samples to process taking into account buffer + // wrap in output queue. Get pointers to the queues. + + process_samples=min(process_samples, + (output_buffer_size-output_tail)>>2); + + unsigned char *outptr=output_buf[0]+output_tail, + *reverbptr=output_buf[1]+output_tail, + *fmptr=output_buf[2]+output_tail, + *noiseptr=output_buf[3]+output_tail; + + output_tail+=process_samples<<2; + output_tail&=(output_buffer_size-1); + output_size+=process_samples<<2; + assert(output_size<=output_buffer_size); + + // Intialise the output samples to 0 (process_voice always adds samples) + + memset(outptr,0,process_samples<<2); + memset(reverbptr,0,process_samples<<2); + + // If noise is enabled for any channels generate noise samples + + if (spureg.noise&0xffffff) + generate_noise(noiseptr,process_samples); + + unsigned int mask=1; + for (int i=0; i<24; i++, mask<<=1) + { + unsigned int tleft=process_samples; + bool isfmin=((i<23) && (spureg.fm&(1<<(i+1)))), + isfm=(spureg.fm&(1<get_vertical_cycles(); + +} + +// +// +// + +void spu_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + stream_sample_t *outL, *outR; + INT16 temp[44100], *src; + + outL = outputs[0]; + outR = outputs[1]; + + generate(temp, samples*4); // second parameter is bytes, * 2 (size of INT16) * 2 (stereo) + + src = &temp[0]; + for (int i = 0; i < samples; i++) + { + *outL++ = *src++; + *outR++ = *src++; + } +} + +// +// +// + +void spu_device::start_dma(UINT8 *mainram, bool to_spu, UINT32 size) +{ + UINT32 st=spureg.trans_addr<<3, en=st+size; + + if (en>(512*1024)) + { + en=512*1024; + size=en-st; + } + + if (to_spu) + { + invalidate_cache(st,en); + + memcpy(spu_ram+(spureg.trans_addr<<3), mainram, size); + + dirty_flags|=dirtyflag_ram; + } + else + { + memcpy(mainram, spu_ram+(spureg.trans_addr<<3), size); + } +} + +// +// +// + +void spu_device::decode_xa_mono(const unsigned char *xa, + unsigned char *ptr) +{ + signed short *dp=(signed short *)ptr; + + int l0=xa_last[0], + l1=xa_last[1]; + + for (int b=0; b<18; b++) + { + for (int s=0; s<4; s++) + { + unsigned char flags=xa[4+(s<<1)], + shift=flags&0xf, + filter=flags>>4; + int f0=filter_coef[filter][0], + f1=filter_coef[filter][1]; + int i; + + for (i=0; i<28; i++) + { + short d=(xa[16+(i<<2)+s]&0xf)<<12; + d=clamp((d>>shift)+(((l0*f0)+(l1*f1)+32)>>6)); + *dp++=d; + l1=l0; + l0=d; + } + + flags=xa[5+(s<<1)]; + shift=flags&0xf; + filter=flags>>4; + f0=filter_coef[filter][0]; + f1=filter_coef[filter][1]; + + for (i=0; i<28; i++) + { + short d=(xa[16+(i<<2)+s]>>4)<<12; + d=clamp((d>>shift)+(((l0*f0)+(l1*f1)+32)>>6)); + *dp++=d; + l1=l0; + l0=d; + } + } + + xa+=128; + } + + xa_last[0]=l0; + xa_last[1]=l1; +} + +// +// +// + +void spu_device::decode_xa_stereo(const unsigned char *xa, + unsigned char *ptr) +{ + signed short *dp=(signed short *)ptr; + + int l0=xa_last[0], + l1=xa_last[1], + l2=xa_last[2], + l3=xa_last[3]; + + for (int b=0; b<18; b++) + { + for (int s=0; s<4; s++) + { + unsigned char flags0=xa[4+(s<<1)], + shift0=flags0&0xf, + filter0=flags0>>4, + flags1=xa[5+(s<<1)], + shift1=flags1&0xf, + filter1=flags1>>4; + + int f0=filter_coef[filter0][0], + f1=filter_coef[filter0][1], + f2=filter_coef[filter1][0], + f3=filter_coef[filter1][1]; + + for (int i=0; i<28; i++) + { + short d=xa[16+(i<<2)+s], + d0=(d&0xf)<<12, + d1=(d>>4)<<12; + d0=clamp((int)(d0>>shift0)+(((l0*f0)+(l1*f1)+32)>>6)); + *dp++=d0; + l1=l0; + l0=d0; + + d1=clamp((int)(d1>>shift1)+(((l2*f2)+(l3*f3)+32)>>6)); + *dp++=d1; + l3=l2; + l2=d1; + } + } + + xa+=128; + } + + xa_last[0]=l0; + xa_last[1]=l1; + xa_last[2]=l2; + xa_last[3]=l3; +} + +// +// +// + +/* +enum +{ + xaencoding_stereo_mask=3, + xaencoding_freq_shift=2, + xaencoding_freq_mask=3<get_bytes_free()add_sector(sector); + + // Decode the sector + + if (channels==2) + { + decode_xa_stereo(xa+8,ptr); + } else + { + decode_xa_mono(xa+8,ptr); + } + + // Return that we processed the sector + return true; +} + +// +// Flush everything after a given sector in the XA buffer +// + +void spu_device::flush_xa(const unsigned int sector) +{ +// debug_xa("flush_xa: %d\n",sector); + + if (xa_playing) + { + xa_buffer->flush(sector); + } else + { + // Not playing, flush the entire buffer + + xa_buffer->flush_all(); + xa_cnt=0; + } +} + +// +// +// + +bool spu_device::play_cdda(const unsigned int sector, const unsigned char *cdda) +{ + if (cdda_buffer->get_bytes_free()add_sector(sector); + memcpy(dp,cdda,cdda_sector_size); + + // data coming in in MAME is big endian as stored on the CD + unsigned char *flip = (unsigned char *)dp; + for (int i = 0; i < cdda_sector_size; i+= 2) + { + unsigned char temp = flip[i]; + flip[i] = flip[i+1]; + flip[i+1] = temp; + } + // this should be done in generate but sound_stream_update may not be called frequently enough + if(((spureg.irq_addr << 3) < 0x800) && (spureg.ctrl & spuctrl_irq_enable)) + m_irq_handler(1); + + return true; +} + +void spu_device::flush_cdda(const unsigned int sector) +{ +// debug_xa("flush_cdda: %d\n",sector); + + if (cdda_playing) + { + cdda_buffer->flush(sector); + } else + { + cdda_buffer->flush_all(); + cdda_cnt=0; + } +} + +void spu_device::dma_read( UINT32 *p_n_ram, UINT32 n_address, INT32 n_size ) +{ + UINT8 *psxram = (UINT8 *)p_n_ram; + + start_dma(psxram + n_address, false, n_size*4); +} + +void spu_device::dma_write( UINT32 *p_n_ram, UINT32 n_address, INT32 n_size ) +{ + UINT8 *psxram = (UINT8 *)p_n_ram; + +// printf("SPU DMA write from %x, size %x\n", n_address, n_size); + + start_dma(psxram + n_address, true, n_size*4); +} diff --git a/src/devices/sound/spu.h b/src/devices/sound/spu.h new file mode 100644 index 00000000000..8a6727e4833 --- /dev/null +++ b/src/devices/sound/spu.h @@ -0,0 +1,255 @@ +// license:BSD-3-Clause +// copyright-holders:pSXAuthor, R. Belmont +#pragma once + +#ifndef __SPU_H__ +#define __SPU_H__ + +#include "spureverb.h" + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_SPU_IRQ_HANDLER(_devcb) \ + devcb = &spu_device::set_irq_handler(*device, DEVCB_##_devcb); + +#define MCFG_SPU_ADD(_tag, _clock) \ + MCFG_DEVICE_MODIFY( "maincpu" ) \ + MCFG_PSX_SPU_READ_HANDLER(DEVREAD16(_tag, spu_device, read)) \ + MCFG_PSX_SPU_WRITE_HANDLER(DEVWRITE16(_tag, spu_device, write)) \ + MCFG_DEVICE_ADD(_tag, SPU, _clock) \ + MCFG_SPU_IRQ_HANDLER(DEVWRITELINE("maincpu:irq", psxirq_device, intin9)) \ + MCFG_PSX_DMA_CHANNEL_READ( "maincpu", 4, psx_dma_read_delegate( FUNC( spu_device::dma_read ), (spu_device *) device ) ) \ + MCFG_PSX_DMA_CHANNEL_WRITE( "maincpu", 4, psx_dma_write_delegate( FUNC( spu_device::dma_write ), (spu_device *) device ) ) + +// ======================> spu_device + +const unsigned int spu_base_frequency_hz=44100; + +class stream_buffer; + +class spu_device : public device_t, public device_sound_interface +{ + struct sample_cache; + struct sample_loop_cache; + struct cache_pointer; + struct voiceinfo; + + enum + { + dirtyflag_voice_mask=0x00ffffff, + dirtyflag_reverb=0x01000000, + dirtyflag_ram=0x02000000, + dirtyflag_irq=0x04000000 + }; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_post_load(); + virtual void device_stop(); + + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + + // internal state + devcb_write_line m_irq_handler; + + unsigned char *spu_ram; + reverb *rev; + unsigned int taddr, sample_t; + + stream_buffer *xa_buffer, *cdda_buffer; + unsigned int xa_cnt,cdda_cnt, + xa_freq,cdda_freq, + xa_channels, + xa_spf, + xa_out_ptr, + cur_frame_sample, + cur_generate_sample, + dirty_flags; + + UINT16 m_cd_out_ptr; + + signed short xa_last[4]; + bool status_enabled, + xa_playing, + cdda_playing; + int xa_voll,xa_volr, + changed_xa_vol; + voiceinfo *voice; + sample_cache **cache; + float samples_per_frame, + samples_per_cycle; + + static float freq_multiplier; + + unsigned char *output_buf[4]; + unsigned int output_head, + output_tail, + output_size, + cur_qsz; + + unsigned int noise_t; + signed short noise_cur; + int noise_seed; + + #pragma pack(push,spureg,1) + + struct voicereg + { + unsigned short vol_l, // 0 + vol_r, // 2 + pitch, // 4 + addr, // 6 + adsl, // 8 + srrr, // a + curvol, // c + repaddr; // e + }; + + union + { + unsigned char reg[0x200]; + struct + { + voicereg voice[24]; + unsigned short mvol_l,mvol_r, + rvol_l,rvol_r; + unsigned int keyon, + keyoff, + fm, + noise, + reverb, + chon; + unsigned short _unknown, + reverb_addr, + irq_addr, + trans_addr, + data, + ctrl; + unsigned int status; + signed short cdvol_l,cdvol_r, + exvol_l,exvol_r; + } spureg; + }; + + #pragma pack(pop,spureg) + + struct reverb_preset + { + const char *name; + unsigned short param[32]; + reverb_params cfg; + }; + + reverb_preset *cur_reverb_preset; + + static reverb_preset reverb_presets[]; + + void key_on(const int v); + void key_off(const int v); + bool update_envelope(const int v); + void write_data(const unsigned short data); + void generate(void *ptr, const unsigned int sz); + void generate_voice(const unsigned int v, + void *ptr, + void *noiseptr, + void *outxptr, + const unsigned int sz); + void generate_noise(void *ptr, const unsigned int num); + bool process_voice(const unsigned int v, + const unsigned int sz, + void *ptr, + void *fmnoise_ptr, + void *outxptr, + unsigned int *tleft); + void process(); + void process_until(const unsigned int tsample); + void update_voice_loop(const unsigned int v); + bool update_voice_state(const unsigned int v); + void update_voice_state(); + void update_voice_events(voiceinfo *vi); + void update_irq_event(); + unsigned int get_irq_distance(const voiceinfo *vi); + void generate_xa(void *ptr, const unsigned int sz); + void generate_cdda(void *ptr, const unsigned int sz); + void decode_xa_mono(const unsigned char *xa, unsigned char *ptr); + void decode_xa_stereo(const unsigned char *xa, unsigned char *ptr); + void update_key(); + void update_reverb(); + void update_timing(); + + bool translate_sample_addr(const unsigned int addr, cache_pointer *cp); + sample_cache *get_sample_cache(const unsigned int addr); + void flush_cache(sample_cache *sc, + const unsigned int istart, + const unsigned int iend); + void invalidate_cache(const unsigned int st, const unsigned int en); + + void set_xa_format(const float freq, const int channels); + + void init_stream(); + void kill_stream(); + + void update_vol(const unsigned int addr); + + void flush_output_buffer(); + + sample_loop_cache *get_loop_cache(sample_cache *cache, + const unsigned int lpen, + sample_cache *lpcache, + const unsigned int lpst); +#if 0 + void write_cache_pointer(outfile *fout, + cache_pointer *cp, + sample_loop_cache *lc=NULL); + void read_cache_pointer(infile *fin, + cache_pointer *cp, + sample_loop_cache **lc=NULL); +#endif + static float get_linear_rate(const int n); + static float get_linear_rate_neg_phase(const int n); + static float get_pos_exp_rate(const int n); + static float get_pos_exp_rate_neg_phase(const int n); + static float get_neg_exp_rate(const int n); + static float get_neg_exp_rate_neg_phase(const int n); + static float get_decay_rate(const int n); + static float get_sustain_level(const int n); + static float get_linear_release_rate(const int n); + static float get_exp_release_rate(const int n); + static reverb_preset *find_reverb_preset(const unsigned short *param); + +public: + spu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // static configuration helpers + template static devcb_base &set_irq_handler(device_t &device, _Object object) { return downcast(device).m_irq_handler.set_callback(object); } + + void dma_read( UINT32 *ram, UINT32 n_address, INT32 n_size ); + void dma_write( UINT32 *ram, UINT32 n_address, INT32 n_size ); + + void reinit_sound(); + void kill_sound(); + + void update(); + + void start_dma(UINT8 *mainram, bool to_spu, UINT32 size); + bool play_xa(const unsigned int sector, const unsigned char *sec); + bool play_cdda(const unsigned int sector, const unsigned char *sec); + void flush_xa(const unsigned int sector=0); + void flush_cdda(const unsigned int sector=0); + + sound_stream *m_stream; + + DECLARE_READ16_MEMBER( read ); + DECLARE_WRITE16_MEMBER( write ); +}; + +extern reverb_params *spu_reverb_cfg; + +// device type definition +extern const device_type SPU; + +#endif diff --git a/src/devices/sound/spu_tables.c b/src/devices/sound/spu_tables.c new file mode 100644 index 00000000000..faa5719c4c6 --- /dev/null +++ b/src/devices/sound/spu_tables.c @@ -0,0 +1,703 @@ +// license:BSD-3-Clause +// copyright-holders:pSXAuthor, R. Belmont +#include "emu.h" +#include "spu.h" + +static inline float ms_to_rate(const float ms) +{ + return 1.0f/(ms*((float)spu_base_frequency_hz/1000.0f)); +} + +static inline float s_to_rate(const float s) +{ + return ms_to_rate(s*1000.0f); +} + +static float linear_rate[]= +{ + ms_to_rate(0.05f), + ms_to_rate(0.06f), + ms_to_rate(0.07f), + ms_to_rate(0.09f), + ms_to_rate(0.10f), + ms_to_rate(0.12f), + ms_to_rate(0.15f), + ms_to_rate(0.18f), + ms_to_rate(0.21f), + ms_to_rate(0.24f), + ms_to_rate(0.29f), + ms_to_rate(0.36f), + ms_to_rate(0.41f), + ms_to_rate(0.48f), + ms_to_rate(0.58f), + ms_to_rate(0.73f), + ms_to_rate(0.83f), + ms_to_rate(0.97f), + ms_to_rate(1.2f), + ms_to_rate(1.5f), + ms_to_rate(1.7f), + ms_to_rate(1.9f), + ms_to_rate(2.3f), + ms_to_rate(2.9f), + ms_to_rate(3.3f), + ms_to_rate(3.9f), + ms_to_rate(4.6f), + ms_to_rate(5.8f), + ms_to_rate(6.6f), + ms_to_rate(7.7f), + ms_to_rate(9.3f), + ms_to_rate(12.0f), + ms_to_rate(13.0f), + ms_to_rate(15.0f), + ms_to_rate(19.0f), + ms_to_rate(23.0f), + ms_to_rate(27.0f), + ms_to_rate(31.0f), + ms_to_rate(37.0f), + ms_to_rate(46.0f), + ms_to_rate(53.0f), + ms_to_rate(62.0f), + ms_to_rate(74.0f), + ms_to_rate(93.0f), + s_to_rate(0.11f), + s_to_rate(0.12f), + s_to_rate(0.15f), + s_to_rate(0.19f), + s_to_rate(0.21f), + s_to_rate(0.25f), + s_to_rate(0.30f), + s_to_rate(0.37f), + s_to_rate(0.42f), + s_to_rate(0.50f), + s_to_rate(0.59f), + s_to_rate(0.74f), + s_to_rate(0.85f), + s_to_rate(0.99f), + s_to_rate(1.2f), + s_to_rate(1.5f), + s_to_rate(1.7f), + s_to_rate(2.0f), + s_to_rate(2.4f), + s_to_rate(3.0f), + s_to_rate(3.4f), + s_to_rate(4.0f), + s_to_rate(4.8f), + s_to_rate(5.9f), + s_to_rate(6.8f), + s_to_rate(7.9f), + s_to_rate(9.5f), + s_to_rate(12.0f), + s_to_rate(14.0f), + s_to_rate(16.0f), + s_to_rate(19.0f), + s_to_rate(24.0f), + s_to_rate(27.0f), + s_to_rate(32.0f), + s_to_rate(38.0f), + s_to_rate(48.0f), + s_to_rate(54.0f), + s_to_rate(63.0f), + s_to_rate(76.0f), + s_to_rate(95.0f), + s_to_rate(109.0f), + s_to_rate(127.0f), + s_to_rate(152.0f), + s_to_rate(190.0f), + s_to_rate(218.0f), + s_to_rate(254.0f), + s_to_rate(304.0f), + s_to_rate(380.0f), + s_to_rate(436.0f), + s_to_rate(508.0f), + s_to_rate(608.0f), + s_to_rate(760.0f), + s_to_rate(872.0f), + s_to_rate(1016.0f), + s_to_rate(1216.0f), + s_to_rate(1520.0f), + s_to_rate(1744.0f), + s_to_rate(2032.0f), + s_to_rate(2432.0f), + s_to_rate(3040.0f), + s_to_rate(3488.0f), + s_to_rate(4064.0f), + s_to_rate(4864.0f), + s_to_rate(6080.0f) +}; + +static const int num_linear_rates=ARRAY_LENGTH(linear_rate); + +static const float pos_exp_rate[]= +{ + ms_to_rate(0.09f), + ms_to_rate(0.11f), + ms_to_rate(0.13f), + ms_to_rate(0.16f), + ms_to_rate(0.18f), + ms_to_rate(0.21f), + ms_to_rate(0.25f), + ms_to_rate(0.32f), + ms_to_rate(0.36f), + ms_to_rate(0.42f), + ms_to_rate(0.51f), + ms_to_rate(0.64f), + ms_to_rate(0.73f), + ms_to_rate(0.85f), + ms_to_rate(1.0f), + ms_to_rate(1.3f), + ms_to_rate(1.5f), + ms_to_rate(1.7f), + ms_to_rate(2.0f), + ms_to_rate(2.5f), + ms_to_rate(2.9f), + ms_to_rate(3.4f), + ms_to_rate(4.1f), + ms_to_rate(5.1f), + ms_to_rate(5.8f), + ms_to_rate(6.8f), + ms_to_rate(8.1f), + ms_to_rate(10.0f), + ms_to_rate(12.0f), + ms_to_rate(14.0f), + ms_to_rate(16.0f), + ms_to_rate(20.0f), + ms_to_rate(23.0f), + ms_to_rate(27.0f), + ms_to_rate(33.0f), + ms_to_rate(41.0f), + ms_to_rate(46.0f), + ms_to_rate(54.0f), + ms_to_rate(65.0f), + ms_to_rate(81.0f), + ms_to_rate(93.0f), + s_to_rate(0.11f), + s_to_rate(0.13f), + s_to_rate(0.16f), + s_to_rate(0.19f), + s_to_rate(0.22f), + s_to_rate(0.26f), + s_to_rate(0.33f), + s_to_rate(0.37f), + s_to_rate(0.43f), + s_to_rate(0.52f), + s_to_rate(0.65f), + s_to_rate(0.74f), + s_to_rate(0.87f), + s_to_rate(1.0f), + s_to_rate(1.3f), + s_to_rate(1.5f), + s_to_rate(1.7f), + s_to_rate(2.1f), + s_to_rate(2.6f), + s_to_rate(3.0f), + s_to_rate(3.5f), + s_to_rate(4.2f), + s_to_rate(5.2f), + s_to_rate(5.9f), + s_to_rate(6.9f), + s_to_rate(8.3f), + s_to_rate(10.0f), + s_to_rate(12.0f), + s_to_rate(14.0f), + s_to_rate(17.0f), + s_to_rate(21.0f), + s_to_rate(24.0f), + s_to_rate(28.0f), + s_to_rate(33.0f), + s_to_rate(42.0f), + s_to_rate(48.0f), + s_to_rate(55.0f), + s_to_rate(67.0f), + s_to_rate(83.0f), + s_to_rate(95.0f), + s_to_rate(111.0f), + s_to_rate(133.0f), + s_to_rate(166.0f), + s_to_rate(190.0f), + s_to_rate(222.0f), + s_to_rate(266.0f), + s_to_rate(333.0f), + s_to_rate(380.0f), + s_to_rate(444.0f), + s_to_rate(532.0f), + s_to_rate(666.0f), + s_to_rate(760.0f), + s_to_rate(888.0f), + s_to_rate(1064.0f), + s_to_rate(1332.0f), + s_to_rate(1520.0f), + s_to_rate(1776.0f), + s_to_rate(2128.0f), + s_to_rate(2664.0f) +}; + +static const int num_pos_exp_rates=ARRAY_LENGTH(pos_exp_rate); + +static const float neg_exp_rate[]= +{ + ms_to_rate(0.07f), + ms_to_rate(0.09f), + ms_to_rate(0.11f), + ms_to_rate(0.14f), + ms_to_rate(0.18f), + ms_to_rate(0.21f), + ms_to_rate(0.25f), + ms_to_rate(0.31f), + ms_to_rate(0.39f), + ms_to_rate(0.45f), + ms_to_rate(0.53f), + ms_to_rate(0.64f), + ms_to_rate(0.81f), + ms_to_rate(0.93f), + ms_to_rate(1.1f), + ms_to_rate(1.3f), + ms_to_rate(1.6f), + ms_to_rate(1.9f), + ms_to_rate(2.2f), + ms_to_rate(2.6f), + ms_to_rate(3.3f), + ms_to_rate(3.8f), + ms_to_rate(4.4f), + ms_to_rate(5.3f), + ms_to_rate(6.7f), + ms_to_rate(7.6f), + ms_to_rate(8.9f), + ms_to_rate(11.0f), + ms_to_rate(13.0f), + ms_to_rate(15.0f), + ms_to_rate(18.0f), + ms_to_rate(21.0f), + ms_to_rate(27.0f), + ms_to_rate(31.0f), + ms_to_rate(36.0f), + ms_to_rate(43.0f), + ms_to_rate(53.0f), + ms_to_rate(61.0f), + ms_to_rate(71.0f), + ms_to_rate(86.0f), + s_to_rate(0.11f), + s_to_rate(0.12f), + s_to_rate(0.14f), + s_to_rate(0.17f), + s_to_rate(0.21f), + s_to_rate(0.24f), + s_to_rate(0.29f), + s_to_rate(0.34f), + s_to_rate(0.43f), + s_to_rate(0.49f), + s_to_rate(0.57f), + s_to_rate(0.68f), + s_to_rate(0.86f), + s_to_rate(0.98f), + s_to_rate(1.1f), + s_to_rate(1.4f), + s_to_rate(1.7f), + s_to_rate(2.0f), + s_to_rate(2.3f), + s_to_rate(2.7f), + s_to_rate(3.4f), + s_to_rate(3.9f), + s_to_rate(4.6f), + s_to_rate(5.5f), + s_to_rate(6.8f), + s_to_rate(7.8f), + s_to_rate(9.1f), + s_to_rate(11.0f), + s_to_rate(14.0f), + s_to_rate(16.0f), + s_to_rate(18.0f), + s_to_rate(22.0f), + s_to_rate(27.0f), + s_to_rate(31.0f), + s_to_rate(36.0f), + s_to_rate(44.0f), + s_to_rate(55.0f), + s_to_rate(63.0f), + s_to_rate(73.0f), + s_to_rate(88.0f), + s_to_rate(109.0f), + s_to_rate(125.0f), + s_to_rate(146.0f), + s_to_rate(175.0f), + s_to_rate(219.0f), + s_to_rate(250.0f), + s_to_rate(292.0f), + s_to_rate(350.0f), + s_to_rate(438.0f), + s_to_rate(500.0f), + s_to_rate(584.0f), + s_to_rate(700.0f), + s_to_rate(876.0f), + s_to_rate(1000.0f), + s_to_rate(1168.0f), + s_to_rate(1400.0f), + s_to_rate(1752.0f), + s_to_rate(2000.0f), + s_to_rate(2336.0f), + s_to_rate(2800.0f), + s_to_rate(3504.0f), + s_to_rate(4000.0f), + s_to_rate(4672.0f), + s_to_rate(5600.0f), + s_to_rate(7008.0f), + s_to_rate(8000.0f), + s_to_rate(9344.0f), + s_to_rate(11200.0f) +}; + +static const int num_neg_exp_rates=ARRAY_LENGTH(neg_exp_rate); + +static const float decay_rate[16]= +{ + ms_to_rate(0.07f), + ms_to_rate(0.18f), + ms_to_rate(0.39f), + ms_to_rate(0.81f), + ms_to_rate(1.6f), + ms_to_rate(3.3f), + ms_to_rate(6.7f), + ms_to_rate(13.0f), + ms_to_rate(27.0f), + ms_to_rate(53.0f), + s_to_rate(0.11f), + s_to_rate(0.21f), + s_to_rate(0.43f), + s_to_rate(0.86f), + s_to_rate(1.7f), + s_to_rate(3.4f), +}; + +static const float linear_release_rate[]= +{ + ms_to_rate(0.04f), + ms_to_rate(0.09f), + ms_to_rate(0.18f), + ms_to_rate(0.36f), + ms_to_rate(0.73f), + ms_to_rate(1.5f), + ms_to_rate(2.9f), + ms_to_rate(5.8f), + ms_to_rate(12.0f), + ms_to_rate(23.0f), + ms_to_rate(46.0f), + ms_to_rate(93.0f), + s_to_rate(0.19f), + s_to_rate(0.37f), + s_to_rate(1.74f), + s_to_rate(1.5f), + s_to_rate(3.0f), + s_to_rate(5.9f), + s_to_rate(12.0f), + s_to_rate(24.0f), + s_to_rate(48.0f), + s_to_rate(95.0f), + s_to_rate(190.0f), + s_to_rate(380.0f), + s_to_rate(760.0f), + s_to_rate(1520.0f), + s_to_rate(3040.0f) +}; + +static const int num_linear_release_rates=ARRAY_LENGTH(linear_release_rate); + +static const float exp_release_rate[]= +{ + ms_to_rate(0.07f), + ms_to_rate(0.18f), + ms_to_rate(0.39f), + ms_to_rate(0.81f), + ms_to_rate(1.6f), + ms_to_rate(3.3f), + ms_to_rate(6.7f), + ms_to_rate(13.0f), + ms_to_rate(27.0f), + ms_to_rate(53.0f), + s_to_rate(0.11f), + s_to_rate(0.21f), + s_to_rate(0.43f), + s_to_rate(0.86f), + s_to_rate(1.7f), + s_to_rate(3.4f), + s_to_rate(6.8f), + s_to_rate(14.0f), + s_to_rate(27.0f), + s_to_rate(55.0f), + s_to_rate(109.0f), + s_to_rate(219.0f), + s_to_rate(438.0f), + s_to_rate(876.0f), + s_to_rate(1752.0f), + s_to_rate(3504.0f), + s_to_rate(7008.0f) +}; + +static const int num_exp_release_rates=ARRAY_LENGTH(exp_release_rate); + +// +// +// + +spu_device::reverb_preset spu_device::reverb_presets[]= +{ + { + "Reverb off", + { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 + } + }, + + { + "Room", + { + 0x007D, 0x005B, 0x6D80, 0x54B8, 0xBED0, 0x0000, 0x0000, 0xBA80, + 0x5800, 0x5300, 0x04D6, 0x0333, 0x03F0, 0x0227, 0x0374, 0x01EF, + 0x0334, 0x01B5, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x01B4, 0x0136, 0x00B8, 0x005C, 0x8000, 0x8000 + }, + { // made up from studio small [used by BOF3] + -0.3112f, + 0.7832f, + + { { 20.7f, 31.3f,40.1711f,51.6803f }, + { 21.7025f,30.2f,42.6655f,48.6691f } }, + 0.8f, + + 0.0f, + 0.0f + } + }, + + { + "Studio Small", + { + 0x0033, 0x0025, 0x70F0, 0x4FA8, 0xBCE0, 0x4410, 0xC0F0, 0x9C00, + 0x5280, 0x4EC0, 0x03E4, 0x031B, 0x03A4, 0x02AF, 0x0372, 0x0266, + 0x031C, 0x025D, 0x025C, 0x018E, 0x022F, 0x0135, 0x01D2, 0x00B7, + 0x018F, 0x00B5, 0x00B4, 0x0080, 0x004C, 0x0026, 0x8000, 0x8000 + }, + { // made up from studio large [used by Fighters Impact] + -0.3112f, + 0.7832f, + + { { 24.7f,44.3f,49.1711f,59.6803f }, + { 27.7025f,38.2f,51.6655f,59.6691f } }, + 0.6462f, + + 0.0f, + 0.0f + } + }, + + { + "Studio Medium", + { + 0x00B1, 0x007F, 0x70F0, 0x4FA8, 0xBCE0, 0x4510, 0xBEF0, 0xB4C0, + 0x5280, 0x4EC0, 0x0904, 0x076B, 0x0824, 0x065F, 0x07A2, 0x0616, + 0x076C, 0x05ED, 0x05EC, 0x042E, 0x050F, 0x0305, 0x0462, 0x02B7, + 0x042F, 0x0265, 0x0264, 0x01B2, 0x0100, 0x0080, 0x8000, 0x8000 + }, + { // made up from studio large + -0.3112f, + 0.7832f, + + { { 37.7f,62.3f,82.1711f,71.6803f }, + { 43.7025f,62.2f,85.6655f,78.6691f } }, + 0.6462f, + + 0.0f, + 0.0f + } + }, + + { + "Studio Large", + { + 0x00E3, 0x00A9, 0x6F60, 0x4FA8, 0xBCE0, 0x4510, 0xBEF0, 0xA680, + 0x5680, 0x52C0, 0x0DFB, 0x0B58, 0x0D09, 0x0A3C, 0x0BD9, 0x0973, + 0x0B59, 0x08DA, 0x08D9, 0x05E9, 0x07EC, 0x04B0, 0x06EF, 0x03D2, + 0x05EA, 0x031D, 0x031C, 0x0238, 0x0154, 0x00AA, 0x8000, 0x8000 + }, + { // tuned from xenogears ost + -0.3112f, + 0.7832f, + + { { 37.7f,62.3f,82.1711f,71.6803f }, + { 43.7025f,62.2f,85.6655f,78.6691f } }, + 0.8462f, + + 0.0f, + 0.0f + } + }, + + { + "Hall", + { + 0x01A5, 0x0139, 0x6000, 0x5000, 0x4C00, 0xB800, 0xBC00, 0xC000, + 0x6000, 0x5C00, 0x15BA, 0x11BB, 0x14C2, 0x10BD, 0x11BC, 0x0DC1, + 0x11C0, 0x0DC3, 0x0DC0, 0x09C1, 0x0BC4, 0x07C1, 0x0A00, 0x06CD, + 0x09C2, 0x05C1, 0x05C0, 0x041A, 0x0274, 0x013A, 0x8000, 0x8000 + }, + { // made up + -0.4222f, + 0.8889f, + + { { 20.37f,79.63f,107.40f,94.44f }, + { 31.47f,72.22f,116.66f,105.55f } }, + 0.8889f, + + 0.0f, + 0.0f + } + }, + + { + "Space Echo", + { + 0x033D, 0x0231, 0x7E00, 0x5000, 0xB400, 0xB000, 0x4C00, 0xB000, + 0x6000, 0x5400, 0x1ED6, 0x1A31, 0x1D14, 0x183B, 0x1BC2, 0x16B2, + 0x1A32, 0x15EF, 0x15EE, 0x1055, 0x1334, 0x0F2D, 0x11F6, 0x0C5D, + 0x1056, 0x0AE1, 0x0AE0, 0x07A2, 0x0464, 0x0232, 0x8000, 0x8000 + }, + { // made up + 0.3951f, + 0.7552f, + + { + { 36.7138f, 134.6171f, 24.4758f, 194.0596f }, + { 54.1932f, 90.9070f, 29.7174f, 200.0000f }, + }, + + 0.9301f, + + 109.2563f, + 0.4222f + } + }, + + { + "Echo", + { + 0x0001, 0x0001, 0x7FFF, 0x7FFF, 0x0000, 0x0000, 0x0000, 0x8100, + 0x0000, 0x0000, 0x1FFF, 0x0FFF, 0x1005, 0x0005, 0x0000, 0x0000, + 0x1005, 0x0005, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x1004, 0x1002, 0x0004, 0x0002, 0x8000, 0x8000 + } + }, + + { + "Delay", + { + 0x0001, 0x0001, 0x7FFF, 0x7FFF, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x1FFF, 0x0FFF, 0x1005, 0x0005, 0x0000, 0x0000, + 0x1005, 0x0005, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x1004, 0x1002, 0x0004, 0x0002, 0x8000, 0x8000, + } + }, + + { + "Half Echo", + { + 0x0017, 0x0013, 0x70F0, 0x4FA8, 0xBCE0, 0x4510, 0xBEF0, 0x8500, + 0x5F80, 0x54C0, 0x0371, 0x02AF, 0x02E5, 0x01DF, 0x02B0, 0x01D7, + 0x0358, 0x026A, 0x01D6, 0x011E, 0x012D, 0x00B1, 0x011F, 0x0059, + 0x01A0, 0x00E3, 0x0058, 0x0040, 0x0028, 0x0014, 0x8000, 0x8000 + }, + { // made up from space echo + 0.3951f, + 0.7552f, + + { + { 36.7138f, 134.6171f, 24.4758f, 194.0596f }, + { 54.1932f, 90.9070f, 29.7174f, 200.0000f }, + }, + + 0.7301f, + + 109.2563f, + 0.7222f + } + }, + + { NULL } +}; + +// +// +// + +float spu_device::get_linear_rate(const int n) +{ + if (n>=num_linear_rates) return 0.0f; + return linear_rate[n]*freq_multiplier; +} + +float spu_device::get_linear_rate_neg_phase(const int n) +{ + if (n==0) return ms_to_rate(0.04f); + return get_linear_rate(n-1); +} + +float spu_device::get_pos_exp_rate(const int n) +{ + if (n>=num_pos_exp_rates) return 0.0f; + return pos_exp_rate[n]*freq_multiplier; +} + +float spu_device::get_pos_exp_rate_neg_phase(const int n) +{ + if (n==0) return ms_to_rate(0.04f); + return get_pos_exp_rate(n-1); +} + +float spu_device::get_neg_exp_rate(const int n) +{ + if (n>=num_neg_exp_rates) return 0.0f; + return -neg_exp_rate[n]*freq_multiplier; +} + +float spu_device::get_neg_exp_rate_neg_phase(const int n) +{ + if (n==0) return -ms_to_rate(0.04f); + return get_neg_exp_rate(n-1); +} + +float spu_device::get_decay_rate(const int n) +{ + return decay_rate[n]*freq_multiplier; +} + +float spu_device::get_sustain_level(const int n) +{ + return ((float)(n+1))/16.0f; +} + +float spu_device::get_linear_release_rate(const int n) +{ + if (n>=num_linear_release_rates) return 0.0f; + return linear_release_rate[n]*freq_multiplier; +} + +float spu_device::get_exp_release_rate(const int n) +{ + if (n>=num_exp_release_rates) return 0.0f; + return exp_release_rate[n]*freq_multiplier; +} + +spu_device::reverb_preset *spu_device::find_reverb_preset(const unsigned short *param) +{ + for (int i=0; reverb_presets[i].name; i++) + { + int j; + + for (j=0; j<32; j++) + if (reverb_presets[i].param[j]!=param[j]) + break; + if (j==32) return &reverb_presets[i]; + } + + return NULL; +} diff --git a/src/devices/sound/spureverb.c b/src/devices/sound/spureverb.c new file mode 100644 index 00000000000..3c784acbbee --- /dev/null +++ b/src/devices/sound/spureverb.c @@ -0,0 +1,343 @@ +// license:BSD-3-Clause +// copyright-holders:pSXAuthor, R. Belmont +#include "emu.h" +#include "spureverb.h" + +// +// +// + +//#define use_intrinsics + +#ifdef use_intrinsics + #include +#endif + +// +// +// + +static inline int clamp(int v) +{ + if (v<-32768) return -32768; + if (v>32767) return 32767; + return v; +} + +// +// +// + +reverb::reverb(const int hz, const int maxdelay) + : yp(0), + max_delay(maxdelay), + sound_hz(hz) +{ + for (int c=0; c<2; c++) + { + for (int f=0; f<4; f++) { + y[c][f]=new signed short [maxdelay]; + memset(y[c][f], 0, sizeof(signed short) * maxdelay); + } + x[c]=new signed short [maxdelay]; + memset(x[c], 0, sizeof(signed short) * maxdelay); + ax[c]=new signed short [maxdelay]; + memset(ax[c], 0, sizeof(signed short) * maxdelay); + ay[c]=new signed short [maxdelay]; + memset(ay[c], 0, sizeof(signed short) * maxdelay); + } + memset(bx1,0,sizeof(bx1)); + memset(by1,0,sizeof(by1)); +} + +// +// +// + +reverb::~reverb() +{ + for (int c=0; c<2; c++) + { + for (int f=0; f<4; f++) + global_free_array(y[c][f]); + global_free_array(x[c]); + global_free_array(ax[c]); + global_free_array(ay[c]); + } +} + +// +// +// + +void reverb::bandpass(signed short *sp, + const reverb_params *rp, + const unsigned int sz) +{ + int band_pole=(int)(rp->band_pole*32767), + band_gain=(int)(rp->band_gain*32767); + + // Bandpass + + int xp=yp; + for (unsigned int i=0; i<(sz>>2); i++, sp+=2) + { + for (int c=0; c<2; c++) + { + int x1=(xp-1)&(max_delay-1), + bv; + + bv=sp[c]+bx1[c][1]+((band_pole*x[c][x1])>>15); + bv=(bv*band_gain)>>15; + x[c][xp]=clamp(bv); + bx1[c][1]=bx1[c][0]; + bx1[c][0]=sp[c]; + } + + xp=(xp+1)&(max_delay-1); + } +} + +void reverb::comb_allpass1(signed short *sp, + signed short *dp, + const comb_param &comb_delay, + const int comb_gain, + const int allpass_delay, + const int allpass_gain, + const int *rvol, + const unsigned int sz) +{ + for (unsigned int i=0; i<(sz>>2); i++, sp+=2, dp+=2) + { + for (int c=0; c<2; c++) + { + // Comb + + int v=0; + + for (int f=0; f<4; f++) + { + int yck=(yp-comb_delay[c][f])&(max_delay-1); + y[c][f][yp]=clamp(x[c][yck]+((comb_gain*y[c][f][yck])>>15)); + v+=y[c][f][yp]; + } + + v>>=2; + + // Allpass + + if (allpass_delay) + { + ax[c][yp]=v; + + int ypa=(yp-allpass_delay)&(max_delay-1); + v=((allpass_gain*(ay[c][ypa]-x[c][yp]))>>15)+ax[c][ypa]; + v=clamp(v); + ay[c][yp]=v; + } + + // Output + + dp[c]=clamp(((v*rvol[c])>>15)+dp[c]+sp[c]); + } + yp=(yp+1)&(max_delay-1); + } +} + +// +// +// + +void reverb::comb_allpass4(signed short *sp, + signed short *dp, + const comb_param &comb_delay, + const int comb_gain, + const int allpass_delay, + const int allpass_gain, + const int *rvol, + const unsigned int sz) +{ +#ifdef use_intrinsics + __m64 cg=_mm_set1_pi16(comb_gain), + ag=_mm_set1_pi16(allpass_gain), + rv[2]; + rv[0]=_mm_set1_pi16(rvol[0]); + rv[1]=_mm_set1_pi16(rvol[1]); + + for (unsigned int i=0; i<(sz>>4); i++, sp+=2<<2, dp+=2<<2) + { + __m64 dv[2]; + + for (int c=0; c<2; c++) + { + // Comb + + __m64 v=_mm_setzero_si64(); + + for (int f=0; f<4; f++) + { + int yck=(yp-comb_delay[c][f])&(max_delay-1); + __m64 xv=*(__m64 *)(&x[c][yck]), + yv=*(__m64 *)(&y[c][f][yck]); + yv=_mm_mulhi_pi16(yv,cg); + yv=_mm_adds_pi16(yv,yv); + yv=_mm_adds_pi16(xv,yv); + *((__m64 *)&y[c][f][yp])=yv; + yv=_mm_srai_pi16(yv,2); + v=_mm_adds_pi16(v,yv); + } + + // Allpass + + if (allpass_delay) + { + *((__m64 *)&ax[c][yp])=v; + + int ypa=(yp-allpass_delay)&(max_delay-1); + __m64 ayv=*(__m64 *)&ay[c][ypa], + xv=*(__m64 *)&x[c][yp], + axv=*(__m64 *)&ax[c][ypa]; + + ayv=_mm_subs_pi16(ayv,xv); + ayv=_mm_mulhi_pi16(ayv,ag); + ayv=_mm_adds_pi16(ayv,ayv); + v=_mm_adds_pi16(ayv,axv); + *((__m64 *)&ay[c][yp])=v; + } + + // Output + + dv[c]=_mm_mulhi_pi16(v,rv[c]); + dv[c]=_mm_adds_pi16(dv[c],dv[c]); + } + + __m64 dv1=_mm_unpacklo_pi16(dv[0],dv[1]), + dv2=_mm_unpackhi_pi16(dv[0],dv[1]), + d1=*(__m64 *)&dp[0], + d2=*(__m64 *)&dp[4], + s1=*(__m64 *)&sp[0], + s2=*(__m64 *)&sp[4]; + d1=_mm_adds_pi16(d1,s1); + d2=_mm_adds_pi16(d2,s2); + d1=_mm_adds_pi16(d1,dv1); + d2=_mm_adds_pi16(d2,dv2); + *(__m64 *)&dp[0]=d1; + *(__m64 *)&dp[4]=d2; + + yp=(yp+4)&(max_delay-1); + } + + _mm_empty(); +#endif +} + +// +// +// + +void reverb::comb_allpass(signed short *sp, + signed short *dp, + const reverb_params *rp, + const int wetvol_l, + const int wetvol_r, + const unsigned int _sz) +{ + unsigned int sz=_sz; + comb_param comb_delay; + int comb_gain=(int)(rp->comb_gain*32767), + allpass_delay=(int)(((rp->allpass_delay/1000.0f)*sound_hz))&~3, + allpass_gain=(int)(rp->allpass_gain*32767), + rvol[2]={ (signed short)wetvol_l, + (signed short)wetvol_r }; + + for (int i=0; i<4; i++) + for (int c=0; c<2; c++) + comb_delay[c][i]=(int)(((rp->comb_delay[c][i]/1000.0f)*sound_hz))&~3; + + #ifdef use_intrinsics + + if (yp&3) + { + unsigned int n=min(sz,(unsigned int)(4-(yp&3))<<2); + comb_allpass1(sp,dp, + (const comb_param &)comb_delay, + comb_gain, + allpass_delay, + allpass_gain, + rvol, + n); + sp+=(n>>1); + dp+=(n>>1); + sz-=n; + } + + if (sz>=16) + { + unsigned int n=sz&~15; + comb_allpass4(sp,dp, + (const comb_param &)comb_delay, + comb_gain, + allpass_delay, + allpass_gain, + rvol, + n); + sp+=n>>1; + dp+=n>>1; + sz-=n; + } + + if (sz) + { + comb_allpass1(sp,dp, + (const comb_param &)comb_delay, + comb_gain, + allpass_delay, + allpass_gain, + rvol, + sz); + } + + #else + comb_allpass1(sp,dp, + (const comb_param &)comb_delay, + comb_gain, + allpass_delay, + allpass_gain, + rvol, + sz); + #endif +} + +// +// +// + +void reverb::process(signed short *output, + signed short *reverb_input, + const reverb_params *rp, + const int wetvol_l, + const int wetvol_r, + const unsigned int sz) +{ + signed short *sp=(signed short *)reverb_input, + *dp=(signed short *)output; + + if (rp->band_gain>0.0f) + { + // Do reverb processing + + bandpass(sp,rp,sz); + comb_allpass(sp,dp,rp,wetvol_l,wetvol_r,sz); + } else + { + // Reverb disabled - just mix the input to the output + + for (unsigned int i=0; i<(sz>>2); i++) + { + output[0]=clamp(output[0]+reverb_input[0]); + output[1]=clamp(output[1]+reverb_input[1]); + output+=2; + reverb_input+=2; + } + } +} diff --git a/src/devices/sound/spureverb.h b/src/devices/sound/spureverb.h new file mode 100644 index 00000000000..8a8cb040ba8 --- /dev/null +++ b/src/devices/sound/spureverb.h @@ -0,0 +1,72 @@ +// license:BSD-3-Clause +// copyright-holders:pSXAuthor, R. Belmont +#ifndef _included_reverb_ + #define _included_reverb_ + + struct reverb_params + { + float band_pole, + band_gain, + + comb_delay[2][4], + comb_gain, + + allpass_delay, + allpass_gain; + }; + + class reverb + { + signed short *y[2][4], + *x[2], + *ax[2], + *ay[2], + bx1[2][2],by1[2]; + int yp, + max_delay, + sound_hz; + typedef int comb_param[2][4]; + + + + void comb_allpass(signed short *sp, + signed short *dp, + const reverb_params *rp, + const int wetvol_l, + const int wetvol_r, + const unsigned int _sz); + void comb_allpass4(signed short *sp, + signed short *dp, + const comb_param &comb_delay, + const int comb_gain, + const int allpass_delay, + const int allpass_gain, + const int *rvol, + const unsigned int sz); + void comb_allpass1(signed short *sp, + signed short *dp, + const comb_param &comb_delay, + const int comb_gain, + const int allpass_delay, + const int allpass_gain, + const int *rvol, + const unsigned int sz); + void bandpass(signed short *sp, + const reverb_params *rp, + const unsigned int sz); + + public: + reverb(const int hz, const int maxdelay=65536); + ~reverb(); + + void process(signed short *output, + signed short *reverb_input, + const reverb_params *rp, + const int wetvol_l, + const int wetvol_r, + const unsigned int sz); + + void reset(); + }; + +#endif diff --git a/src/devices/sound/st0016.c b/src/devices/sound/st0016.c new file mode 100644 index 00000000000..99328a93b4d --- /dev/null +++ b/src/devices/sound/st0016.c @@ -0,0 +1,164 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont, Tomasz Slanina, David Haywood +/************************************ + Seta custom ST-0016 chip + sound emulation by R. Belmont, Tomasz Slanina, and David Haywood +************************************/ + +#include "emu.h" +#include "st0016.h" + +#define VERBOSE (0) +#define LOG(x) do { if (VERBOSE) logerror x; } while (0) + + +// device type definition +const device_type ST0016 = &device_creator; + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// st0016_device - constructor +//------------------------------------------------- + +st0016_device::st0016_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, ST0016, "ST0016 (Audio)", tag, owner, clock, "st0016_audio", __FILE__), + device_sound_interface(mconfig, *this), + m_stream(NULL), + m_ram_read_cb(*this) +{ + memset(m_vpos, 0, sizeof(int)*8); + memset(m_frac, 0, sizeof(int)*8); + memset(m_lponce, 0, sizeof(int)*8); + memset(m_regs, 0, sizeof(UINT8)*0x100); +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void st0016_device::device_start() +{ + m_stream = stream_alloc(0, 2, 44100); + m_ram_read_cb.resolve_safe(0); + + save_item(NAME(m_vpos)); + save_item(NAME(m_frac)); + save_item(NAME(m_lponce)); + save_item(NAME(m_regs)); +} + + +//------------------------------------------------- +// sound_stream_update - handle a stream update +//------------------------------------------------- + +void st0016_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + int v, i, snum; + unsigned char *slot; + INT32 mix[48000*2]; + INT32 *mixp; + INT16 sample; + int sptr, eptr, freq, lsptr, leptr; + + memset(mix, 0, sizeof(mix[0])*samples*2); + + for (v = 0; v < 8; v++) + { + slot = (unsigned char *)&m_regs[v * 32]; + + if (slot[0x16] & 0x06) + { + mixp = &mix[0]; + + sptr = slot[0x02]<<16 | slot[0x01]<<8 | slot[0x00]; + eptr = slot[0x0e]<<16 | slot[0x0d]<<8 | slot[0x0c]; + freq = slot[0x11]<<8 | slot[0x10]; + lsptr = slot[0x06]<<16 | slot[0x05]<<8 | slot[0x04]; + leptr = slot[0x0a]<<16 | slot[0x09]<<8 | slot[0x08]; + + for (snum = 0; snum < samples; snum++) + { + sample = m_ram_read_cb((sptr + m_vpos[v]) & 0x1fffff) << 8; + + *mixp++ += (sample * (char)slot[0x14]) >> 8; + *mixp++ += (sample * (char)slot[0x15]) >> 8; + + m_frac[v] += freq; + m_vpos[v] += (m_frac[v]>>16); + m_frac[v] &= 0xffff; + + // stop if we're at the end + if (m_lponce[v]) + { + // we've looped once, check loop end rather than sample end + if ((m_vpos[v] + sptr) >= leptr) + { + m_vpos[v] = (lsptr - sptr); + } + } + else + { + // not looped yet, check sample end + if ((m_vpos[v] + sptr) >= eptr) + { + if (slot[0x16] & 0x01) // loop? + { + m_vpos[v] = (lsptr - sptr); + m_lponce[v] = 1; + } + else + { + slot[0x16] = 0; + m_vpos[v] = m_frac[v] = 0; + } + } + } + } + } + } + + mixp = &mix[0]; + for (i = 0; i < samples; i++) + { + outputs[0][i] = (*mixp++)>>4; + outputs[1][i] = (*mixp++)>>4; + } +} + + +READ8_MEMBER( st0016_device::st0016_snd_r ) +{ + return m_regs[offset]; +} + +WRITE8_MEMBER( st0016_device::st0016_snd_w ) +{ + int voice = offset/32; + int reg = offset & 0x1f; + int oldreg = m_regs[offset]; + int vbase = offset & ~0x1f; + + m_regs[offset] = data; + + if ((voice < 8) && (data != oldreg)) + { + if ((reg == 0x16) && (data != 0)) + { + m_vpos[voice] = m_frac[voice] = m_lponce[voice] = 0; + + LOG(("Key on V%02d: st %06x-%06x lp %06x-%06x frq %x flg %x\n", voice, + m_regs[vbase+2]<<16 | m_regs[vbase+1]<<8 | m_regs[vbase+2], + m_regs[vbase+0xe]<<16 | m_regs[vbase+0xd]<<8 | m_regs[vbase+0xc], + m_regs[vbase+6]<<16 | m_regs[vbase+5]<<8 | m_regs[vbase+4], + m_regs[vbase+0xa]<<16 | m_regs[vbase+0x9]<<8 | m_regs[vbase+0x8], + m_regs[vbase+0x11]<<8 | m_regs[vbase+0x10], + m_regs[vbase+0x16])); + } + } +} diff --git a/src/devices/sound/st0016.h b/src/devices/sound/st0016.h new file mode 100644 index 00000000000..dd23b0c9b7a --- /dev/null +++ b/src/devices/sound/st0016.h @@ -0,0 +1,54 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont, Tomasz Slanina, David Haywood +#pragma once + +#ifndef __ST0016_H__ +#define __ST0016_H__ + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_ST0016_SOUNDRAM_READ_CB(_devcb) \ + devcb = &st0016_device::set_soundram_callback(*device, DEVCB_##_devcb); + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> st0016_device + +class st0016_device : public device_t, + public device_sound_interface +{ +public: + st0016_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + ~st0016_device() { } + + template static devcb_base &set_soundram_callback(device_t &device, _Object object) { return downcast(device).m_ram_read_cb.set_callback(object); } + +protected: + // device-level overrides + virtual void device_start(); + + // sound stream update overrides + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + +public: + DECLARE_READ8_MEMBER( st0016_snd_r ); + DECLARE_WRITE8_MEMBER( st0016_snd_w ); + +private: + sound_stream *m_stream; + devcb_read8 m_ram_read_cb; + int m_vpos[8]; + int m_frac[8]; + int m_lponce[8]; + UINT8 m_regs[0x100]; +}; + +extern const device_type ST0016; + + +#endif /* __ST0016_H__ */ diff --git a/src/devices/sound/t6721a.c b/src/devices/sound/t6721a.c new file mode 100644 index 00000000000..2cc9828f407 --- /dev/null +++ b/src/devices/sound/t6721a.c @@ -0,0 +1,112 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Toshiba T6721A C2MOS Voice Synthesizing LSI emulation + +**********************************************************************/ + +#include "t6721a.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define LOG 0 + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +// device type definition +const device_type T6721A = &device_creator; + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// t6721a_device - constructor +//------------------------------------------------- + +t6721a_device::t6721a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, T6721A, "T6721A", tag, owner, clock, "t6721a", __FILE__), + device_sound_interface(mconfig, *this), + m_write_eos(*this), + m_write_phi2(*this), + m_write_dtrd(*this), + m_write_apd(*this), + m_stream(NULL) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void t6721a_device::device_start() +{ + // resolve callbacks + m_write_eos.resolve_safe(); + m_write_phi2.resolve_safe(); + m_write_dtrd.resolve_safe(); + m_write_apd.resolve_safe(); + + // create sound stream + m_stream = machine().sound().stream_alloc(*this, 0, 1, machine().sample_rate()); +} + + +//------------------------------------------------- +// sound_stream_update - handle update requests for +// our sound stream +//------------------------------------------------- + +void t6721a_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ +} + + +//------------------------------------------------- +// read - +//------------------------------------------------- + +READ8_MEMBER( t6721a_device::read ) +{ + return 0; +} + + +//------------------------------------------------- +// write - +//------------------------------------------------- + +WRITE8_MEMBER( t6721a_device::write ) +{ +} + + +//------------------------------------------------- +// di_w - data input write +//------------------------------------------------- + +WRITE_LINE_MEMBER( t6721a_device::di_w ) +{ +} + + +//------------------------------------------------- +// eos_r - eos read +//------------------------------------------------- + +READ_LINE_MEMBER( t6721a_device::eos_r ) +{ + return 1; +} diff --git a/src/devices/sound/t6721a.h b/src/devices/sound/t6721a.h new file mode 100644 index 00000000000..ff969fa60be --- /dev/null +++ b/src/devices/sound/t6721a.h @@ -0,0 +1,123 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Toshiba T6721A C2MOS Voice Synthesizing LSI emulation + +********************************************************************** + _____ _____ + SP3 1 |* \_/ | 42 Vdd + LOSS 2 | | 41 SP2 + TS 3 | | 40 SP1 + TSN 4 | | 39 SP0 + W 5 | | 38 TEM + TDAI 6 | | 37 FR + TFIO 7 | | 36 BR + DAO 8 | | 35 OD + APD 9 | | 34 REP + phi2 10 | | 33 EXP + PD 11 | T6721A | 32 CK2 + ROM ADR RST 12 | | 31 CK1 + ROM RST 13 | | 30 M-START + ALD 14 | | 29 TPN + DI 15 | | 28 _ACL + DTRD 16 | | 27 CPUM + D3 17 | | 26 _EOS + D2 18 | | 25 _BSY + D1 19 | | 24 _CE + D0 20 | | 23 _RD + GND 21 |_____________| 22 _WR + +**********************************************************************/ + +#pragma once + +#ifndef __T6721__ +#define __T6721__ + +#include "emu.h" + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_T6721A_EOS_HANDLER(_eos) \ + downcast(device)->set_eos_callback(DEVCB_##_eos); + +#define MCFG_T6721A_PHI2_HANDLER(_phi2) \ + downcast(device)->set_phi2_callback(DEVCB_##_phi2); + +#define MCFG_T6721A_DTRD_HANDLER(_dtrd) \ + downcast(device)->set_dtrd_callback(DEVCB_##_dtrd); + +#define MCFG_T6721A_APD_HANDLER(_apd) \ + downcast(device)->set_apd_callback(DEVCB_##_apd); + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> t6721a_device + +class t6721a_device : public device_t, + public device_sound_interface +{ +public: + t6721a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // static configuration helpers + template void set_eos_callback(_eos eos) { m_write_eos.set_callback(eos); } + template void set_phi2_callback(_phi2 phi2) { m_write_phi2.set_callback(phi2); } + template void set_dtrd_callback(_dtrd dtrd) { m_write_dtrd.set_callback(dtrd); } + template void set_apd_callback(_apd apd) { m_write_apd.set_callback(apd); } + + DECLARE_READ8_MEMBER( read ); + DECLARE_WRITE8_MEMBER( write ); + + DECLARE_WRITE_LINE_MEMBER( di_w ); + + DECLARE_READ_LINE_MEMBER( eos_r ); + +protected: + // device-level overrides + virtual void device_start(); + + // device_sound_interface overrides + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + +private: + enum + { + CMD_NOP = 0, + CMD_STRT, + CMD_STOP, + CMD_ADLD, + CMD_AAGN, + CMD_SPLD, + CMD_CNDT1, + CMD_CNDT2, + CMD_RRDM, + CMD_SPDN, + CMD_APDN, + CMD_SAGN + }; + + devcb_write_line m_write_eos; + devcb_write_line m_write_phi2; + devcb_write_line m_write_dtrd; + devcb_write_line m_write_apd; + + sound_stream *m_stream; +}; + + +// device type definition +extern const device_type T6721A; + + + +#endif diff --git a/src/devices/sound/t6w28.c b/src/devices/sound/t6w28.c new file mode 100644 index 00000000000..25303ec4f1b --- /dev/null +++ b/src/devices/sound/t6w28.c @@ -0,0 +1,356 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +/*************************************************************************** + + t6w28.c (based on sn74696.c) + + The t6w28 sound core is used in the SNK NeoGeo Pocket. It is a stereo + sound chip based on 2 partial sn76489a cores. + + The block diagram for this chip is as follows: + +Offset 0: + Tone 0 /----------> Att0 ---\ + | | + Tone 1 | /-------> Att1 ---+ + | | | Right + Tone 2 | | /----> Att2 ---+--------> + | | | | | + Noise -----+-------------> Att3 ---/ + | | | | + | | | | + Offset 1: | | | | + Tone 0 --------+----------> Att0 ---\ + | | | | + Tone 1 -----------+-------> Att1 ---+ + | | | Left + Tone 2 --------------+----> Att2 ---+--------> + | | + Noise \-------------> Att3 ---/ + + +***************************************************************************/ + +#include "emu.h" +#include "t6w28.h" + + +#define MAX_OUTPUT 0x7fff + +#define STEP 0x10000 + +WRITE8_MEMBER( t6w28_device::write ) +{ + int n, r, c; + + + /* update the output buffer before changing the registers */ + m_channel->update(); + + offset &= 1; + + if (data & 0x80) + { + r = (data & 0x70) >> 4; + m_last_register[offset] = r; + m_register[offset * 8 + r] = (m_register[offset * 8 + r] & 0x3f0) | (data & 0x0f); + } + else + { + r = m_last_register[offset]; + } + c = r/2; + switch (r) + { + case 0: /* tone 0 : frequency */ + case 2: /* tone 1 : frequency */ + case 4: /* tone 2 : frequency */ + if ((data & 0x80) == 0) m_register[offset * 8 + r] = (m_register[offset * 8 + r] & 0x0f) | ((data & 0x3f) << 4); + m_period[offset * 4 + c] = STEP * m_register[offset * 8 + r]; + if (m_period[offset * 4 + c] == 0) m_period[offset * 4 + c] = STEP; + if (r == 4) + { + /* update noise shift frequency */ + if ((m_register[offset * 8 + 6] & 0x03) == 0x03) + m_period[offset * 4 + 3] = 2 * m_period[offset * 4 + 2]; + } + break; + case 1: /* tone 0 : volume */ + case 3: /* tone 1 : volume */ + case 5: /* tone 2 : volume */ + case 7: /* noise : volume */ + m_volume[offset * 4 + c] = m_vol_table[data & 0x0f]; + if ((data & 0x80) == 0) m_register[offset * 8 + r] = (m_register[offset * 8 + r] & 0x3f0) | (data & 0x0f); + break; + case 6: /* noise : frequency, mode */ + { + if ((data & 0x80) == 0) m_register[offset * 8 + r] = (m_register[offset * 8 + r] & 0x3f0) | (data & 0x0f); + n = m_register[offset * 8 + 6]; + m_noise_mode[offset] = (n & 4) ? 1 : 0; + /* N/512,N/1024,N/2048,Tone #3 output */ + m_period[offset * 4 + 3] = ((n&3) == 3) ? 2 * m_period[offset * 4 + 2] : (STEP << (5+(n&3))); + /* Reset noise shifter */ + m_rng[offset] = m_feedback_mask; /* this is correct according to the smspower document */ + //m_rng = 0xF35; /* this is not, but sounds better in do run run */ + m_output[offset * 4 + 3] = m_rng[offset] & 1; + } + break; + } +} + + + +//------------------------------------------------- +// sound_stream_update - handle a stream update +//------------------------------------------------- + +void t6w28_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + int i; + stream_sample_t *buffer0 = outputs[0]; + stream_sample_t *buffer1 = outputs[1]; + + + /* If the volume is 0, increase the counter */ + for (i = 0;i < 8;i++) + { + if (m_volume[i] == 0) + { + /* note that I do count += samples, NOT count = samples + 1. You might think */ + /* it's the same since the volume is 0, but doing the latter could cause */ + /* interferencies when the program is rapidly modulating the volume. */ + if (m_count[i] <= samples*STEP) m_count[i] += samples*STEP; + } + } + + while (samples > 0) + { + int vol[8]; + unsigned int out0, out1; + int left; + + + /* vol[] keeps track of how long each square wave stays */ + /* in the 1 position during the sample period. */ + vol[0] = vol[1] = vol[2] = vol[3] = vol[4] = vol[5] = vol[6] = vol[7] = 0; + + for (i = 2;i < 3;i++) + { + if (m_output[i]) vol[i] += m_count[i]; + m_count[i] -= STEP; + /* m_period[i] is the half period of the square wave. Here, in each */ + /* loop I add m_period[i] twice, so that at the end of the loop the */ + /* square wave is in the same status (0 or 1) it was at the start. */ + /* vol[i] is also incremented by m_period[i], since the wave has been 1 */ + /* exactly half of the time, regardless of the initial position. */ + /* If we exit the loop in the middle, m_output[i] has to be inverted */ + /* and vol[i] incremented only if the exit status of the square */ + /* wave is 1. */ + while (m_count[i] <= 0) + { + m_count[i] += m_period[i]; + if (m_count[i] > 0) + { + m_output[i] ^= 1; + if (m_output[i]) vol[i] += m_period[i]; + break; + } + m_count[i] += m_period[i]; + vol[i] += m_period[i]; + } + if (m_output[i]) vol[i] -= m_count[i]; + } + + for (i = 4;i < 7;i++) + { + if (m_output[i]) vol[i] += m_count[i]; + m_count[i] -= STEP; + /* m_period[i] is the half period of the square wave. Here, in each */ + /* loop I add m_period[i] twice, so that at the end of the loop the */ + /* square wave is in the same status (0 or 1) it was at the start. */ + /* vol[i] is also incremented by m_period[i], since the wave has been 1 */ + /* exactly half of the time, regardless of the initial position. */ + /* If we exit the loop in the middle, m_output[i] has to be inverted */ + /* and vol[i] incremented only if the exit status of the square */ + /* wave is 1. */ + while (m_count[i] <= 0) + { + m_count[i] += m_period[i]; + if (m_count[i] > 0) + { + m_output[i] ^= 1; + if (m_output[i]) vol[i] += m_period[i]; + break; + } + m_count[i] += m_period[i]; + vol[i] += m_period[i]; + } + if (m_output[i]) vol[i] -= m_count[i]; + } + + left = STEP; + do + { + int nextevent; + + + if (m_count[3] < left) nextevent = m_count[3]; + else nextevent = left; + + if (m_output[3]) vol[3] += m_count[3]; + m_count[3] -= nextevent; + if (m_count[3] <= 0) + { + if (m_noise_mode[0] == 1) /* White Noise Mode */ + { + if (((m_rng[0] & m_whitenoise_taps) != m_whitenoise_taps) && ((m_rng[0] & m_whitenoise_taps) != 0)) /* crappy xor! */ + { + m_rng[0] >>= 1; + m_rng[0] |= m_feedback_mask; + } + else + { + m_rng[0] >>= 1; + } + m_output[3] = m_whitenoise_invert ? !(m_rng[0] & 1) : m_rng[0] & 1; + } + else /* Periodic noise mode */ + { + if (m_rng[0] & 1) + { + m_rng[0] >>= 1; + m_rng[0] |= m_feedback_mask; + } + else + { + m_rng[0] >>= 1; + } + m_output[3] = m_rng[0] & 1; + } + m_count[3] += m_period[3]; + if (m_output[3]) vol[3] += m_period[3]; + } + if (m_output[3]) vol[3] -= m_count[3]; + + left -= nextevent; + } while (left > 0); + + if (m_enabled) + { + out0 = vol[4] * m_volume[4] + vol[5] * m_volume[5] + + vol[6] * m_volume[6] + vol[3] * m_volume[7]; + + out1 = vol[4] * m_volume[0] + vol[5] * m_volume[1] + + vol[6] * m_volume[2] + vol[3] * m_volume[3]; + } + else + { + out0 = 0; + out1 = 0; + } + + if (out0 > MAX_OUTPUT * STEP) out0 = MAX_OUTPUT * STEP; + if (out1 > MAX_OUTPUT * STEP) out1 = MAX_OUTPUT * STEP; + + *(buffer0++) = out0 / STEP; + *(buffer1++) = out1 / STEP; + + samples--; + } +} + + + +void t6w28_device::set_gain(int gain) +{ + int i; + double out; + + gain &= 0xff; + + /* increase max output basing on gain (0.2 dB per step) */ + out = MAX_OUTPUT / 3; + while (gain-- > 0) + out *= 1.023292992; /* = (10 ^ (0.2/20)) */ + + /* build volume table (2dB per step) */ + for (i = 0;i < 15;i++) + { + /* limit volume to avoid clipping */ + if (out > MAX_OUTPUT / 3) m_vol_table[i] = MAX_OUTPUT / 3; + else m_vol_table[i] = out; + + out /= 1.258925412; /* = 10 ^ (2/20) = 2dB */ + } + m_vol_table[15] = 0; +} + + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void t6w28_device::device_start() +{ + int i; + + m_sample_rate = clock() / 16; + m_channel = machine().sound().stream_alloc(*this, 0, 2, m_sample_rate); + + for (i = 0;i < 8;i++) m_volume[i] = 0; + + m_last_register[0] = 0; + m_last_register[1] = 0; + for (i = 0;i < 8;i+=2) + { + m_register[i] = 0; + m_register[i + 1] = 0x0f; /* volume = 0 */ + } + + for (i = 0;i < 8;i++) + { + m_output[i] = 0; + m_period[i] = m_count[i] = STEP; + } + + /* Default is SN76489 non-A */ + m_feedback_mask = 0x4000; /* mask for feedback */ + m_whitenoise_taps = 0x03; /* mask for white noise taps */ + m_whitenoise_invert = 1; /* white noise invert flag */ + + m_rng[0] = m_feedback_mask; + m_rng[1] = m_feedback_mask; + m_output[3] = m_rng[0] & 1; + + set_gain(0); + + /* values from sn76489a */ + m_feedback_mask = 0x8000; + m_whitenoise_taps = 0x06; + m_whitenoise_invert = FALSE; + + save_item(NAME(m_register)); + save_item(NAME(m_last_register)); + save_item(NAME(m_volume)); + save_item(NAME(m_rng)); + save_item(NAME(m_noise_mode)); + save_item(NAME(m_period)); + save_item(NAME(m_count)); + save_item(NAME(m_output)); + save_item(NAME(m_enabled)); +} + + +void t6w28_device::set_enable(bool enable) +{ + m_enabled = enable; +} + +const device_type T6W28 = &device_creator; + +t6w28_device::t6w28_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, T6W28, "T6W28", tag, owner, clock, "t6w28", __FILE__), + device_sound_interface(mconfig, *this) +{ +} diff --git a/src/devices/sound/t6w28.h b/src/devices/sound/t6w28.h new file mode 100644 index 00000000000..7bee03bbc6b --- /dev/null +++ b/src/devices/sound/t6w28.h @@ -0,0 +1,47 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +#pragma once + +#ifndef __T6W28_H__ +#define __T6W28_H__ + +class t6w28_device : public device_t, + public device_sound_interface +{ +public: + t6w28_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + DECLARE_WRITE8_MEMBER( write ); + void set_enable( bool enable ); + +protected: + // device-level overrides + virtual void device_start(); + + // sound stream update overrides + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + + void set_gain(int gain); + +private: + sound_stream *m_channel; + int m_sample_rate; + int m_vol_table[16]; /* volume table */ + INT32 m_register[16]; /* registers */ + INT32 m_last_register[2]; /* last register written */ + INT32 m_volume[8]; /* volume of voice 0-2 and noise */ + UINT32 m_rng[2]; /* noise generator */ + INT32 m_noise_mode[2]; /* active noise mode */ + INT32 m_feedback_mask; /* mask for feedback */ + INT32 m_whitenoise_taps; /* mask for white noise taps */ + INT32 m_whitenoise_invert; /* white noise invert flag */ + INT32 m_period[8]; + INT32 m_count[8]; + INT32 m_output[8]; + bool m_enabled; +}; + +extern const device_type T6W28; + + +#endif /* __T6W28_H__ */ diff --git a/src/devices/sound/tc8830f.c b/src/devices/sound/tc8830f.c new file mode 100644 index 00000000000..824b9d78958 --- /dev/null +++ b/src/devices/sound/tc8830f.c @@ -0,0 +1,256 @@ +// license:BSD-3-Clause +// copyright-holders:hap +/*************************************************************************** + + tc8830f.c - Toshiba TC8830F, CMOS voice recording/reproducing LSI + 1-bit ADM (Adaptive Delta Modulation), similar to TC8801 and T6668. + + Very preliminary... + + TODO: + - improve ADM decoder + - remaining commands + - manual control + - chip read + - RAM + - recording + +***************************************************************************/ + +#include "emu.h" +#include "tc8830f.h" + + +// device type definition +const device_type TC8830F = &device_creator; + +tc8830f_device::tc8830f_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, TC8830F, "TC8830F", tag, owner, clock, "tc8830f", __FILE__), + device_sound_interface(mconfig, *this), + m_playing(false), + m_address(0), + m_stop_address(0), + m_bitcount(0), + m_bitrate(0), + m_prevbits(0), + m_delta(1), + m_output(0), + m_command(0), + m_cmd_rw(0), + m_phrase(0) +{ +} + + +void tc8830f_device::device_start() +{ + // create the stream + m_stream = stream_alloc(0, 1, clock() / 0x10); + + m_mem_base = region()->base(); + m_mem_mask = region()->bytes() - 1; + + // register for savestates + save_item(NAME(m_playing)); + save_item(NAME(m_address)); + save_item(NAME(m_stop_address)); + save_item(NAME(m_bitcount)); + save_item(NAME(m_bitrate)); + save_item(NAME(m_prevbits)); + save_item(NAME(m_delta)); + save_item(NAME(m_output)); + save_item(NAME(m_command)); + save_item(NAME(m_cmd_rw)); + save_item(NAME(m_phrase)); + + reset(); +} + + +void tc8830f_device::device_post_load() +{ + device_clock_changed(); +} + + +void tc8830f_device::device_clock_changed() +{ + int divisor = 0x10 * (4 - (m_bitrate & 3)); + m_stream->set_sample_rate(clock() / divisor); +} + + + +void tc8830f_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + INT32 mix = 0; + + for (int i = 0; i < samples; i++) + { + if (m_playing) + { + // get bit + int bit = m_mem_base[m_address] >> m_bitcount & 1; + m_bitcount = (m_bitcount + 1) & 7; + if (m_bitcount == 0) + { + m_address = (m_address + 1) & m_mem_mask; + if (m_address == m_stop_address) + m_playing = false; + } + + // compute sample, ADM decoding + // if previous bits are 111 or 000, delta increases exponentially + // otherwise, delta decreases linearly + if ((m_prevbits & 7) == 7 || (m_prevbits & 7) == 0) + { + if (m_delta < 0x2000) + m_delta <<= 1; + } + else + m_delta -= 8; + if (m_delta <= 0) + m_delta = 1; + + // determine direction + if (bit) + m_output += m_delta; + else + m_output -= m_delta; + + if (m_output > 32767) + m_output = 32767; + else if (m_output < -32768) + m_output = -32768; + + m_prevbits = m_prevbits << 1 | bit; + mix = m_output; + } + + outputs[0][i] = mix; + } +} + + +void tc8830f_device::reset() +{ + m_stream->update(); + + m_playing = false; + m_address = 0x100; + m_bitcount = 0; + m_prevbits = 0; + m_delta = 1; + m_output = 0; + m_cmd_rw = 0; + + // in cpu control, enter play mode and reset bitrate + write_p(1); + write_p(6); + write_p(0); +} + + +void tc8830f_device::write_p(UINT8 data) +{ + m_stream->update(); + data &= 0xf; + + if (m_cmd_rw == 0) + { + // select command + m_command = data; + switch (m_command) + { + // immediate commands + case 0x1: + break; + + case 0x2: + m_playing = true; + break; + + case 0x3: + m_playing = false; + break; + + // multi-nibble commands + case 0x4: case 0x5: case 0x6: case 0x7: + m_cmd_rw = 1; + break; + + case 0x8: case 0x9: case 0xa: case 0xb: + logerror("tc8830f: Unemulated command %X\n", m_command); + break; + + default: + logerror("tc8830f: Invalid command %X\n", m_command); + break; + } + } + + else + { + // write command + switch (m_command) + { + case 0x4: + // ADLD1: set address counter + m_address = (m_address & ~(0xf << (m_cmd_rw*4))) | (data << (m_cmd_rw*4)); + if (m_cmd_rw == 5) + { + m_address &= m_mem_mask; + m_bitcount = 0; + m_cmd_rw = -1; + } + break; + + case 0x5: + // ADLD2: set address stop + m_stop_address = (m_stop_address & ~(0xf << (m_cmd_rw*4))) | (data << (m_cmd_rw*4)); + if (m_cmd_rw == 5) + { + m_stop_address &= m_mem_mask; + m_cmd_rw = -1; + } + break; + + case 0x6: + // CNDT: d0-d1: bitrate, d2: enable overflow + m_bitrate = data & 3; + device_clock_changed(); + m_cmd_rw = -1; + break; + + case 0x7: + // LABEL: set phrase + if (m_cmd_rw == 1) + { + m_phrase = (m_phrase & 0x30) | data; + } + else + { + m_phrase = (m_phrase & 0x0f) | (data << 4 & 0x30); + + // update addresses and start + UINT8 offs = m_phrase * 4; + m_address = (m_mem_base[offs] | m_mem_base[offs|1]<<8 | m_mem_base[offs|2]<<16) & m_mem_mask; + offs += 4; + m_stop_address = (m_mem_base[offs] | m_mem_base[offs|1]<<8 | m_mem_base[offs|2]<<16) & m_mem_mask; + + m_bitcount = 0; + m_prevbits = 0; + m_delta = 1; + m_output = 0; + m_playing = true; + m_cmd_rw = -1; + } + break; + + default: + m_cmd_rw = -1; + break; + } + m_cmd_rw++; + } +} diff --git a/src/devices/sound/tc8830f.h b/src/devices/sound/tc8830f.h new file mode 100644 index 00000000000..a8b9a2c62f9 --- /dev/null +++ b/src/devices/sound/tc8830f.h @@ -0,0 +1,71 @@ +// license:BSD-3-Clause +// copyright-holders:hap +/*************************************************************************** + + tc8830f.h - Toshiba TC8830F, CMOS voice recording/reproducing LSI + +***************************************************************************/ + +#pragma once + +#ifndef __TC8830F_H__ +#define __TC8830F_H__ + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_TC8830F_ADD(_tag, _clock) \ + MCFG_DEVICE_ADD(_tag, TC8830F, _clock) + +#define MCFG_TC8830F_REPLACE(_tag, _clock) \ + MCFG_DEVICE_REPLACE(_tag, TC8830F, _clock) + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class tc8830f_device : public device_t, + public device_sound_interface +{ +public: + // construction/destruction + tc8830f_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + void reset(); + void write_p(UINT8 data); + + sound_stream *m_stream; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_post_load(); + virtual void device_clock_changed(); + + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + +private: + bool m_playing; + UINT32 m_address; + UINT32 m_stop_address; + UINT8 m_bitcount; + UINT8 m_bitrate; + UINT8 m_prevbits; + int m_delta; + int m_output; + UINT8 m_command; + int m_cmd_rw; + UINT8 m_phrase; + + UINT8 *m_mem_base; + UINT32 m_mem_mask; +}; + + +// device type definition +extern const device_type TC8830F; + +#endif /* __TC8830F_H__ */ diff --git a/src/devices/sound/tiaintf.c b/src/devices/sound/tiaintf.c new file mode 100644 index 00000000000..7cbfe6683e4 --- /dev/null +++ b/src/devices/sound/tiaintf.c @@ -0,0 +1,64 @@ +// license:GPL-2.0+ +// copyright-holders:Ron Fries,Dan Boris +#include "emu.h" +#include "tiaintf.h" +#include "tiasound.h" + +// device type definition +const device_type TIA = &device_creator; + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// tia_device - constructor +//------------------------------------------------- + +tia_device::tia_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, TIA, "TIA", tag, owner, clock, "tia_sound", __FILE__), + device_sound_interface(mconfig, *this), + m_channel(NULL), + m_chip(NULL) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void tia_device::device_start() +{ + m_channel = stream_alloc(0, 1, clock()); + m_chip = tia_sound_init(this, clock(), clock(), 16); + assert_always(m_chip != NULL, "Error creating TIA chip"); +} + + +//------------------------------------------------- +// device_stop - device-specific stop +//------------------------------------------------- + +void tia_device::device_stop() +{ + tia_sound_free(m_chip); +} + + +//------------------------------------------------- +// sound_stream_update - handle a stream update +//------------------------------------------------- + +void tia_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + tia_process(m_chip, outputs[0], samples); +} + + +WRITE8_MEMBER( tia_device::tia_sound_w ) +{ + m_channel->update(); + tia_write(m_chip, offset, data); +} diff --git a/src/devices/sound/tiaintf.h b/src/devices/sound/tiaintf.h new file mode 100644 index 00000000000..0fd349b4037 --- /dev/null +++ b/src/devices/sound/tiaintf.h @@ -0,0 +1,50 @@ +// license:GPL-2.0+ +// copyright-holders:Ron Fries,Dan Boris +#pragma once + +#ifndef __TIAINTF_H__ +#define __TIAINTF_H__ + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_SOUND_TIA_ADD(_tag, _clock) \ + MCFG_DEVICE_ADD(_tag, TIA, _clock) +#define MCFG_SOUND_TIA_REPLACE(_tag, _clock) \ + MCFG_DEVICE_REPLACE(_tag, TIA, _clock) + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> tia_device + +class tia_device : public device_t, + public device_sound_interface +{ +public: + tia_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + ~tia_device() { } + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_stop(); + + // sound stream update overrides + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + +public: + DECLARE_WRITE8_MEMBER( tia_sound_w ); + +private: + sound_stream *m_channel; + void *m_chip; +}; + +extern const device_type TIA; + + +#endif /* __TIAINTF_H__ */ diff --git a/src/devices/sound/tiasound.c b/src/devices/sound/tiasound.c new file mode 100644 index 00000000000..960520b6b79 --- /dev/null +++ b/src/devices/sound/tiasound.c @@ -0,0 +1,612 @@ +// license:GPL-2.0+ +// copyright-holders:Ron Fries,Dan Boris +/*****************************************************************************/ +/* */ +/* Module: TIA Chip Sound Simulator */ +/* Purpose: To emulate the sound generation hardware of the Atari TIA chip. */ +/* Author: Ron Fries */ +/* */ +/* Revision History: */ +/* 10-Sep-96 - V1.0 - Initial Release */ +/* 14-Jan-97 - V1.1 - Cleaned up sound output by eliminating counter */ +/* reset. */ +/* 30-Oct-98 - Modified for use in MESS by Dan Boris */ +/* 28-Jul-01 - Added support for sample rates > TIA clock rate, */ +/* through oversampling */ +/* 30-Jun-07 - Updated the poly generation. Improved handling of the */ +/* POLY5_DIV3 mode. (Wilbert Pol) */ +/* */ +/* */ +/* */ +/*****************************************************************************/ +/* */ +/* License Information and Copyright Notice */ +/* ======================================== */ +/* */ +/* TiaSound is Copyright Ron Fries */ +/* */ +/* This library is free software; you can redistribute it and/or modify it */ +/* under the terms of version 2 of the GNU Library General Public License */ +/* as published by the Free Software Foundation. */ +/* */ +/* This library is distributed in the hope that it will be useful, but */ +/* WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library */ +/* General Public License for more details. */ +/* To obtain a copy of the GNU Library General Public License, write to the */ +/* Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +/* */ +/* Any permitted reproduction of these routines, in whole or in part, must */ +/* bear this legend. */ +/* */ +/*****************************************************************************/ + +#include "emu.h" +#include "tiaintf.h" +#include "tiasound.h" + +/* number of bits to shift left AUDV0/AUDV1 registers for 16 bit volume */ +#define AUDV_SHIFT 10 + +/* CONSTANT DEFINITIONS */ + +/* definitions for AUDCx (15, 16) */ +#define SET_TO_1 0x00 /* 0000 */ +#define POLY4 0x01 /* 0001 */ +#define DIV31_POLY4 0x02 /* 0010 */ +#define POLY5_POLY4 0x03 /* 0011 */ +#define PURE 0x04 /* 0100 */ +#define PURE2 0x05 /* 0101 */ +#define DIV31_PURE 0x06 /* 0110 */ +#define POLY5_2 0x07 /* 0111 */ +#define POLY9 0x08 /* 1000 */ +#define POLY5 0x09 /* 1001 */ +#define DIV31_POLY5 0x0a /* 1010 */ +#define POLY5_POLY5 0x0b /* 1011 */ +#define DIV3_PURE 0x0c /* 1100 */ +#define DIV3_PURE2 0x0d /* 1101 */ +#define DIV93_PURE 0x0e /* 1110 */ +#define POLY5_DIV3 0x0f /* 1111 */ + +#define DIV3_MASK 0x0c + +#define AUDC0 0x15 +#define AUDC1 0x16 +#define AUDF0 0x17 +#define AUDF1 0x18 +#define AUDV0 0x19 +#define AUDV1 0x1a + +/* the size (in entries) of the 4 polynomial tables */ +#define POLY4_SIZE 0x000f +#define POLY5_SIZE 0x001f +#define POLY9_SIZE 0x01ff + +/* channel definitions */ +#define CHAN1 0 +#define CHAN2 1 + +/* LOCAL GLOBAL VARIABLE DEFINITIONS */ + +struct tia +{ + /* structures to hold the 6 tia sound control bytes */ + UINT8 AUDC[2]; /* AUDCx (15, 16) */ + UINT8 AUDF[2]; /* AUDFx (17, 18) */ + INT16 AUDV[2]; /* AUDVx (19, 1A) */ + + INT16 Outvol[2]; /* last output volume for each channel */ + + int tia_gain; /* initialized in tia_sound_init() */ + + /* Initialze the bit patterns for the polynomials. */ + + /* The 4bit and 5bit patterns are the identical ones used in the tia chip. */ + /* Though the patterns could be packed with 8 bits per byte, using only a */ + /* single bit per byte keeps the math simple, which is important for */ + /* efficient processing. */ + + /* HJB: poly bits are initialized at runtime */ + + UINT8 Bit4[POLY4_SIZE]; + UINT8 Bit5[POLY5_SIZE]; + UINT8 Bit9[POLY9_SIZE]; + + + UINT8 P4[2]; /* Position pointer for the 4-bit POLY array */ + UINT8 P5[2]; /* Position pointer for the 5-bit POLY array */ + UINT16 P9[2]; /* Position pointer for the 9-bit POLY array */ + + UINT8 Div_n_cnt[2]; /* Divide by n counter. one for each channel */ + UINT8 Div_n_max[2]; /* Divide by n maximum, one for each channel */ + UINT8 Div_3_cnt[2]; /* Div 3 counter, used for POLY5_DIV3 mode */ + + + /* In my routines, I treat the sample output as another divide by N counter. */ + /* For better accuracy, the Samp_n_cnt has a fixed binary decimal point */ + /* which has 8 binary digits to the right of the decimal point. */ + + UINT16 Samp_n_max; /* Sample max, multiplied by 256 */ + UINT16 Samp_n_cnt; /* Sample cnt. */ + + int oversampling; /* Added oversampling for sample_rate > clock_rate */ +}; + + +/* I've treated the 'Div by 31' counter as another polynomial because of */ +/* the way it operates. It does not have a 50% duty cycle, but instead */ +/* has a 13:18 ratio (of course, 13+18 = 31). This could also be */ +/* implemented by using counters. */ + +static const UINT8 Div31[POLY5_SIZE] = + {0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + + +/*****************************************************************************/ +/* Module: tia_sound_w() */ +/* Purpose: To process the latest control values stored in the AUDF, AUDC, */ +/* and AUDV registers. It pre-calculates as much information as */ +/* possible for better performance. This routine has not been */ +/* optimized. */ +/* */ +/* Author: Ron Fries */ +/* Date: January 14, 1997 */ +/* */ +/* Inputs: addr - the address of the parameter to be changed */ +/* val - the new value to be placed in the specified address */ +/* */ +/* Outputs: Adjusts local globals - no return value */ +/* */ +/*****************************************************************************/ + +void tia_write(void *_chip, offs_t offset, UINT8 data) +{ + struct tia *chip = (struct tia *)_chip; + UINT16 new_val = 0; + UINT8 chan; + + /* determine which address was changed */ + switch (offset) + { + case AUDC0: + chip->AUDC[0] = data & 0x0f; + chan = 0; + break; + + case AUDC1: + chip->AUDC[1] = data & 0x0f; + chan = 1; + break; + + case AUDF0: + chip->AUDF[0] = data & 0x1f; + chan = 0; + break; + + case AUDF1: + chip->AUDF[1] = data & 0x1f; + chan = 1; + break; + + case AUDV0: + chip->AUDV[0] = ((data & 0x0f) << AUDV_SHIFT); + chan = 0; + break; + + case AUDV1: + chip->AUDV[1] = ((data & 0x0f) << AUDV_SHIFT); + chan = 1; + break; + + default: + chan = 255; + break; + } + + /* if the output value changed */ + if (chan != 255) + { + /* an AUDC value of 0 is a special case */ + if (chip->AUDC[chan] == SET_TO_1 || chip->AUDC[chan] == POLY5_POLY5) + { + /* indicate the clock is zero so no processing will occur */ + new_val = 0; + + /* and set the output to the selected volume */ + chip->Outvol[chan] = chip->AUDV[chan]; + } + else + { + /* otherwise calculate the 'divide by N' value */ + new_val = chip->AUDF[chan] + 1; + + /* if bits 2 & 3 are set, then multiply the 'div by n' count by 3 */ + if ((chip->AUDC[chan] & DIV3_MASK) == DIV3_MASK && chip->AUDC[chan] != POLY5_DIV3) + { + new_val *= 3; + } + } + + /* only reset those channels that have changed */ + if (new_val != chip->Div_n_max[chan]) + { + /* reset the divide by n counters */ + chip->Div_n_max[chan] = new_val; + + /* if the channel is now volume only or was volume only */ + if ((chip->Div_n_cnt[chan] == 0) || (new_val == 0)) + { + /* reset the counter (otherwise let it complete the previous) */ + chip->Div_n_cnt[chan] = new_val; + } + } + } +} + + +/*****************************************************************************/ +/* Module: tia_process() */ +/* Purpose: To fill the output buffer with the sound output based on the */ +/* tia chip parameters. This routine has been optimized. */ +/* */ +/* Author: Ron Fries */ +/* Date: September 10, 1996 */ +/* */ +/* Inputs: *buffer - pointer to the buffer where the audio output will */ +/* be placed */ +/* n - size of the playback buffer */ +/* */ +/* Outputs: the buffer will be filled with n bytes of audio - no return val */ +/* */ +/*****************************************************************************/ + +void tia_process(void *_chip, stream_sample_t *buffer, int length) +{ + struct tia *chip = (struct tia *)_chip; + UINT8 audc0, audc1; + UINT8 div_n_cnt0, div_n_cnt1; + UINT8 p5_0, p5_1; + INT16 audv0, audv1, outvol_0, outvol_1; + + audc0 = chip->AUDC[0]; + audc1 = chip->AUDC[1]; + audv0 = chip->AUDV[0]; + audv1 = chip->AUDV[1]; + + /* make temporary local copy */ + p5_0 = chip->P5[0]; + p5_1 = chip->P5[1]; + outvol_0 = chip->Outvol[0]; + outvol_1 = chip->Outvol[1]; + div_n_cnt0 = chip->Div_n_cnt[0]; + div_n_cnt1 = chip->Div_n_cnt[1]; + + /* loop until the buffer is filled */ + while (length > 0) + { + /* Process channel 0 */ + if (div_n_cnt0 > 1) + { + div_n_cnt0--; + } + else if (div_n_cnt0 == 1) + { + int prev_bit5 = chip->Bit5[p5_0]; + + div_n_cnt0 = chip->Div_n_max[0]; + + /* the chip->P5 counter has multiple uses, so we inc it here */ + p5_0++; + if (p5_0 == POLY5_SIZE) + p5_0 = 0; + + /* check clock modifier for clock tick */ + if ((audc0 & 0x02) == 0 || + ((audc0 & 0x01) == 0 && Div31[p5_0]) || + ((audc0 & 0x01) == 1 && chip->Bit5[p5_0]) || + ((audc0 & 0x0f) == POLY5_DIV3 && chip->Bit5[p5_0] != prev_bit5)) + { + if (audc0 & 0x04) /* pure modified clock selected */ + { + if ((audc0 & 0x0f) == POLY5_DIV3) /* POLY5 -> DIV3 mode */ + { + if ( chip->Bit5[p5_0] != prev_bit5 ) + { + chip->Div_3_cnt[0]--; + if ( ! chip->Div_3_cnt[0] ) + { + chip->Div_3_cnt[0] = 3; + if (outvol_0) + outvol_0 = 0; + else + outvol_0 = audv0; + } + } + } + else if (outvol_0) /* if the output was set */ + outvol_0 = 0; /* turn it off */ + else + outvol_0 = audv0; /* else turn it on */ + } + else if (audc0 & 0x08) /* check for p5/p9 */ + { + if (audc0 == POLY9) /* check for poly9 */ + { + /* inc the poly9 counter */ + chip->P9[0]++; + if (chip->P9[0] == POLY9_SIZE) + chip->P9[0] = 0; + + if (chip->Bit9[chip->P9[0]]) + outvol_0 = audv0; + else + outvol_0 = 0; + } + else if ( audc0 & 0x02 ) + { + if (outvol_0 || audc0 & 0x01 ) + outvol_0 = 0; + else + outvol_0 = audv0; + } + else + /* must be poly5 */ + { + if (chip->Bit5[p5_0]) + outvol_0 = audv0; + else + outvol_0 = 0; + } + } + else + /* poly4 is the only remaining option */ + { + /* inc the poly4 counter */ + chip->P4[0]++; + if (chip->P4[0] == POLY4_SIZE) + chip->P4[0] = 0; + + if (chip->Bit4[chip->P4[0]]) + outvol_0 = audv0; + else + outvol_0 = 0; + } + } + } + + + /* Process channel 1 */ + if (div_n_cnt1 > 1) + { + div_n_cnt1--; + } + else if (div_n_cnt1 == 1) + { + int prev_bit5 = chip->Bit5[p5_1]; + + div_n_cnt1 = chip->Div_n_max[1]; + + /* the chip->P5 counter has multiple uses, so we inc it here */ + p5_1++; + if (p5_1 == POLY5_SIZE) + p5_1 = 0; + + /* check clock modifier for clock tick */ + if ((audc1 & 0x02) == 0 || + ((audc1 & 0x01) == 0 && Div31[p5_1]) || + ((audc1 & 0x01) == 1 && chip->Bit5[p5_1]) || + ((audc1 & 0x0f) == POLY5_DIV3 && chip->Bit5[p5_1] != prev_bit5)) + { + if (audc1 & 0x04) /* pure modified clock selected */ + { + if ((audc1 & 0x0f) == POLY5_DIV3) /* POLY5 -> DIV3 mode */ + { + if ( chip->Bit5[p5_1] != prev_bit5 ) + { + chip->Div_3_cnt[1]--; + if ( ! chip->Div_3_cnt[1] ) + { + chip->Div_3_cnt[1] = 3; + if (outvol_1) + outvol_1 = 0; + else + outvol_1 = audv1; + } + } + } + else if (outvol_1) /* if the output was set */ + outvol_1 = 0; /* turn it off */ + else + outvol_1 = audv1; /* else turn it on */ + } + else if (audc1 & 0x08) /* check for p5/p9 */ + { + if (audc1 == POLY9) /* check for poly9 */ + { + /* inc the poly9 counter */ + chip->P9[1]++; + if (chip->P9[1] == POLY9_SIZE) + chip->P9[1] = 0; + + if (chip->Bit9[chip->P9[1]]) + outvol_1 = audv1; + else + outvol_1 = 0; + } + else if ( audc1 & 0x02 ) + { + if (outvol_1 || audc1 & 0x01 ) + outvol_1 = 0; + else + outvol_1 = audv1; + } + else + /* must be poly5 */ + { + if (chip->Bit5[p5_1]) + outvol_1 = audv1; + else + outvol_1 = 0; + } + } + else + /* poly4 is the only remaining option */ + { + /* inc the poly4 counter */ + chip->P4[1]++; + if (chip->P4[1] == POLY4_SIZE) + chip->P4[1] = 0; + + if (chip->Bit4[chip->P4[1]]) + outvol_1 = audv1; + else + outvol_1 = 0; + } + } + } + + if (!chip->oversampling) + { + /* decrement the sample counter - value is 256 since the lower + * byte contains the fractional part */ + chip->Samp_n_cnt -= 256; + + /* if the count down has reached zero */ + if (chip->Samp_n_cnt < 256) + { + /* adjust the sample counter */ + chip->Samp_n_cnt += chip->Samp_n_max; + + /* calculate the latest output value and place in buffer */ + *buffer++ = outvol_0 + outvol_1; + + /* and indicate one less byte to process */ + length--; + } + } + else + { + do + { + /* decrement the sample counter - value is 256 since the lower + * byte contains the fractional part */ + chip->Samp_n_cnt -= 256; + /* calculate the latest output value and place in buffer */ + *buffer++ = outvol_0 + outvol_1; + length--; + } + while ((chip->Samp_n_cnt >= 256) && (length > 0)); + + /* adjust the sample counter if necessary */ + if (chip->Samp_n_cnt < 256) + chip->Samp_n_cnt += chip->Samp_n_max; + } + } + + /* save for next round */ + chip->P5[0] = p5_0; + chip->P5[1] = p5_1; + chip->Outvol[0] = outvol_0; + chip->Outvol[1] = outvol_1; + chip->Div_n_cnt[0] = div_n_cnt0; + chip->Div_n_cnt[1] = div_n_cnt1; + +} + +static void poly_init(UINT8 *poly, int size, int f0, int f1) +{ + int mask = (1 << size) - 1; + int i, x = mask; + + for (i = 0; i < mask; i++) + { + int bit0 = ( ( size - f0 ) ? ( x >> ( size - f0 ) ) : x ) & 0x01; + int bit1 = ( ( size - f1 ) ? ( x >> ( size - f1 ) ) : x ) & 0x01; + poly[i] = x & 1; + /* calculate next bit */ + x = ( x >> 1 ) | ( ( bit0 ^ bit1 ) << ( size - 1) ); + } +} + +static void tia_save_state(device_t *device, tia *tia) +{ + device->save_item(NAME(tia->AUDC)); + device->save_item(NAME(tia->AUDF)); + device->save_item(NAME(tia->AUDV)); + device->save_item(NAME(tia->Outvol)); + device->save_item(NAME(tia->P4)); + device->save_item(NAME(tia->P5)); + device->save_item(NAME(tia->P9)); + device->save_item(NAME(tia->Div_n_cnt)); + device->save_item(NAME(tia->Div_n_max)); + device->save_item(NAME(tia->Div_3_cnt)); + device->save_item(NAME(tia->Samp_n_cnt)); + device->save_item(NAME(tia->oversampling)); +} + +/*****************************************************************************/ +/* Module: tia_sh_start() */ +/* Purpose: to handle the power-up initialization functions */ +/* these functions should only be executed on a cold-restart */ +/* */ +/* Author: Ron Fries */ +/* Date: September 10, 1996 */ +/* */ +/* Inputs: sound_config *msound */ +/* is a pointer to the struct TIAInterface parameters */ +/* */ +/* Outputs: returns zero on success */ +/* */ +/*****************************************************************************/ + +void *tia_sound_init(device_t *device, int clock, int sample_rate, int gain) +{ + struct tia *chip; + int chan; + + chip = global_alloc_clear(struct tia); + + /* set the gain factor (normally use TIA_DEFAULT_GAIN) */ + chip->tia_gain = gain; + + /* fill the polynomials */ + poly_init(chip->Bit4, 4, 4, 3); + poly_init(chip->Bit5, 5, 5, 3); + poly_init(chip->Bit9, 9, 9, 5); + + /* calculate the sample 'divide by N' value based on the playback freq. */ + chip->Samp_n_max = ((UINT16)(UINT32)clock << 8) / sample_rate; + chip->Samp_n_cnt = chip->Samp_n_max; /* initialize all bits of the sample counter */ + + if (chip->Samp_n_max < 256) /* we need to use oversampling for sample_rate > clock_rate */ + { + chip->Samp_n_max = ((UINT16)(UINT32)sample_rate << 8) / clock; + chip->Samp_n_cnt = chip->Samp_n_max; + chip->oversampling = 1; + } + + /* initialize the local globals */ + for (chan = CHAN1; chan <= CHAN2; chan++) + { + chip->Outvol[chan] = 0; + chip->Div_n_cnt[chan] = 0; + chip->Div_n_max[chan] = 0; + chip->Div_3_cnt[chan] = 3; + chip->AUDC[chan] = 0; + chip->AUDF[chan] = 0; + chip->AUDV[chan] = 0; + chip->P4[chan] = 0; + chip->P5[chan] = 0; + chip->P9[chan] = 0; + } + + tia_save_state(device, chip); + + return chip; +} + + +void tia_sound_free(void *chip) +{ + global_free((struct tia *)chip); +} diff --git a/src/devices/sound/tiasound.h b/src/devices/sound/tiasound.h new file mode 100644 index 00000000000..a73b63c9cbe --- /dev/null +++ b/src/devices/sound/tiasound.h @@ -0,0 +1,47 @@ +// license:GPL-2.0+ +// copyright-holders:Ron Fries,Dan Boris +/*****************************************************************************/ +/* */ +/* Module: TIA Chip Sound Simulator Includes, V1.1 */ +/* Purpose: Define global function prototypes and structures for the TIA */ +/* Chip Sound Simulator. */ +/* Author: Ron Fries */ +/* */ +/* Revision History: */ +/* 10-Sep-96 - V1.0 - Initial Release */ +/* 14-Jan-97 - V1.1 - Added compiler directives to facilitate compilation */ +/* on a C++ compiler. */ +/* */ +/*****************************************************************************/ +/* */ +/* License Information and Copyright Notice */ +/* ======================================== */ +/* */ +/* TiaSound is Copyright Ron Fries */ +/* */ +/* This library is free software; you can redistribute it and/or modify it */ +/* under the terms of version 2 of the GNU Library General Public License */ +/* as published by the Free Software Foundation. */ +/* */ +/* This library is distributed in the hope that it will be useful, but */ +/* WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library */ +/* General Public License for more details. */ +/* To obtain a copy of the GNU Library General Public License, write to the */ +/* Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +/* */ +/* Any permitted reproduction of these routines, in whole or in part, must */ +/* bear this legend. */ +/* */ +/*****************************************************************************/ +#pragma once + +#ifndef __TIASOUND_H__ +#define __TIASOUND_H__ + +void *tia_sound_init(device_t *device, int clock, int sample_rate, int gain); +void tia_sound_free(void *chip); +void tia_process (void *chip, stream_sample_t *buffer, int length); +void tia_write(void *chip, offs_t offset, UINT8 data); + +#endif /* __TIASOUND_H__ */ diff --git a/src/devices/sound/tms3615.c b/src/devices/sound/tms3615.c new file mode 100644 index 00000000000..3ccf9159b9d --- /dev/null +++ b/src/devices/sound/tms3615.c @@ -0,0 +1,109 @@ +// license:BSD-3-Clause +// copyright-holders:Juergen Buchmueller +#include "emu.h" +#include "tms3615.h" + +#define VMIN 0x0000 +#define VMAX 0x7fff + +static const int divisor[TMS3615_TONES] = { 478, 451, 426, 402, 379, 358, 338, 319, 301, 284, 268, 253, 239 }; + + +// device type definition +const device_type TMS3615 = &device_creator; + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// tms3615_device - constructor +//------------------------------------------------- + +tms3615_device::tms3615_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, TMS3615, "TMS3615", tag, owner, clock, "tms3615", __FILE__), + device_sound_interface(mconfig, *this), + m_channel(0), + m_samplerate(0), + m_basefreq(0), + m_output8(0), + m_output16(0), + m_enable(0) +{ + memset(m_counter8, 0, TMS3615_TONES); + memset(m_counter16, 0, TMS3615_TONES); +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void tms3615_device::device_start() +{ + m_channel = stream_alloc(0, 2, clock()/8); + m_samplerate = clock()/8; + m_basefreq = clock(); +} + + +//------------------------------------------------- +// sound_stream_update - handle a stream update +//------------------------------------------------- + +void tms3615_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + int samplerate = m_samplerate; + stream_sample_t *buffer8 = outputs[TMS3615_FOOTAGE_8]; + stream_sample_t *buffer16 = outputs[TMS3615_FOOTAGE_16]; + + while( samples-- > 0 ) + { + int sum8 = 0, sum16 = 0, tone = 0; + + for (tone = 0; tone < TMS3615_TONES; tone++) + { + // 8' + + m_counter8[tone] -= (m_basefreq / divisor[tone]); + + while( m_counter8[tone] <= 0 ) + { + m_counter8[tone] += samplerate; + m_output8 ^= 1 << tone; + } + + if (m_output8 & m_enable & (1 << tone)) + { + sum8 += VMAX; + } + + // 16' + + m_counter16[tone] -= (m_basefreq / divisor[tone] / 2); + + while( m_counter16[tone] <= 0 ) + { + m_counter16[tone] += samplerate; + m_output16 ^= 1 << tone; + } + + if (m_output16 & m_enable & (1 << tone)) + { + sum16 += VMAX; + } + } + + *buffer8++ = sum8 / TMS3615_TONES; + *buffer16++ = sum16 / TMS3615_TONES; + } + + m_enable = 0; +} + + +void tms3615_device::enable_w(int enable) +{ + m_enable = enable; +} diff --git a/src/devices/sound/tms3615.h b/src/devices/sound/tms3615.h new file mode 100644 index 00000000000..f68a4718ef1 --- /dev/null +++ b/src/devices/sound/tms3615.h @@ -0,0 +1,61 @@ +// license:BSD-3-Clause +// copyright-holders:Juergen Buchmueller +#pragma once + +#ifndef __TMS3615_H__ +#define __TMS3615_H__ + +#define TMS3615_TONES 13 +#define TMS3615_FOOTAGE_8 0 +#define TMS3615_FOOTAGE_16 1 + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_TMS3615_ADD(_tag, _clock) \ + MCFG_DEVICE_ADD(_tag, TMS3615, _clock) +#define MCFG_TMS3615_REPLACE(_tag, _clock) \ + MCFG_DEVICE_REPLACE(_tag, TMS3615, _clock) + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + + +// ======================> tms3615_device + +class tms3615_device : public device_t, + public device_sound_interface +{ +public: + tms3615_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + ~tms3615_device() { } + +protected: + // device-level overrides + virtual void device_start(); + + // sound stream update overrides + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + +public: + void enable_w(int enable); + +private: + sound_stream *m_channel; /* returned by stream_create() */ + int m_samplerate; /* output sample rate */ + int m_basefreq; /* chip's base frequency */ + int m_counter8[TMS3615_TONES]; /* tone frequency counter for 8' */ + int m_counter16[TMS3615_TONES]; /* tone frequency counter for 16'*/ + int m_output8; /* output signal bits for 8' */ + int m_output16; /* output signal bits for 16' */ + int m_enable; /* mask which tones to play */ +}; + +extern ATTR_DEPRECATED const device_type TMS3615; + + +#endif /* __TMS3615_H__ */ diff --git a/src/devices/sound/tms36xx.c b/src/devices/sound/tms36xx.c new file mode 100644 index 00000000000..18c55ce6235 --- /dev/null +++ b/src/devices/sound/tms36xx.c @@ -0,0 +1,557 @@ +// license:BSD-3-Clause +// copyright-holders:Juergen Buchmueller +#include "emu.h" +#include "tms36xx.h" + +#define VERBOSE 1 + +#define LOG(x) do { if (VERBOSE) logerror x; } while (0) + +/* the frequencies are later adjusted by "* clock / FSCALE" */ +#define FSCALE 1024 + +#define C(n) (int)((FSCALE<<(n-1))*1.18921) /* 2^(3/12) */ +#define Cx(n) (int)((FSCALE<<(n-1))*1.25992) /* 2^(4/12) */ +#define D(n) (int)((FSCALE<<(n-1))*1.33484) /* 2^(5/12) */ +#define Dx(n) (int)((FSCALE<<(n-1))*1.41421) /* 2^(6/12) */ +#define E(n) (int)((FSCALE<<(n-1))*1.49831) /* 2^(7/12) */ +#define F(n) (int)((FSCALE<<(n-1))*1.58740) /* 2^(8/12) */ +#define Fx(n) (int)((FSCALE<<(n-1))*1.68179) /* 2^(9/12) */ +#define G(n) (int)((FSCALE<<(n-1))*1.78180) /* 2^(10/12) */ +#define Gx(n) (int)((FSCALE<<(n-1))*1.88775) /* 2^(11/12) */ +#define A(n) (int)((FSCALE< TMS36XX_VMIN ) \ + { \ + /* decay of first voice */ \ + m_vol_counter[voice] -= m_decay[voice]; \ + while( m_vol_counter[voice] <= 0 ) \ + { \ + m_vol_counter[voice] += samplerate; \ + if( m_vol[voice]-- <= TMS36XX_VMIN ) \ + { \ + m_frequency[voice] = 0; \ + m_vol[voice] = TMS36XX_VMIN; \ + break; \ + } \ + } \ + } + +#define RESTART(voice) \ + if( tunes[m_tune_num][m_tune_ofs*6+voice] ) \ + { \ + m_frequency[m_shift+voice] = \ + tunes[m_tune_num][m_tune_ofs*6+voice] * \ + (m_basefreq << m_octave) / FSCALE; \ + m_vol[m_shift+voice] = TMS36XX_VMAX; \ + } + +#define TONE(voice) \ + if( (m_enable & (1<; + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// tms36xx_device - constructor +//------------------------------------------------- + +tms36xx_device::tms36xx_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, TMS36XX, "TMS36XX", tag, owner, clock, "tms36xx", __FILE__), + device_sound_interface(mconfig, *this), + m_subtype(NULL), + m_channel(NULL), + m_samplerate(0), + m_basefreq(0), + m_octave(0), + m_speed(0), + m_tune_counter(0), + m_note_counter(0), + m_voices(0), + m_shift(0), + m_output(0), + m_enable(0), + m_tune_num(0), + m_tune_ofs(0), + m_tune_max(0) +{ + memset(m_vol, 0, sizeof(int)*12); + memset(m_vol_counter, 0, sizeof(int)*12); + memset(m_decay, 0, sizeof(int)*12); + memset(m_counter, 0, sizeof(int)*12); + memset(m_frequency, 0, sizeof(int)*12); +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void tms36xx_device::device_start() +{ + int enable = 0; + + m_channel = stream_alloc(0, 1, clock() * 64); + m_samplerate = clock() * 64; + m_basefreq = clock(); + + for (int j = 0; j < 6; j++) + { + if (m_decay_time[j] > 0) + { + m_decay[j+0] = m_decay[j+6] = TMS36XX_VMAX / m_decay_time[j]; + enable |= 0x41 << j; + } + } + tms3617_enable(enable); + + LOG(("TMS36xx samplerate %d\n", m_samplerate)); + LOG(("TMS36xx basefreq %d\n", m_basefreq)); + LOG(("TMS36xx decay %d,%d,%d,%d,%d,%d\n", + m_decay[0], m_decay[1], m_decay[2], + m_decay[3], m_decay[4], m_decay[5])); + LOG(("TMS36xx speed %d\n", m_speed)); + + save_item(NAME(m_octave)); + save_item(NAME(m_tune_counter)); + save_item(NAME(m_note_counter)); + save_item(NAME(m_voices)); + save_item(NAME(m_shift)); + save_item(NAME(m_vol)); + save_item(NAME(m_vol_counter)); + save_item(NAME(m_counter)); + save_item(NAME(m_frequency)); + save_item(NAME(m_output)); + save_item(NAME(m_enable)); + save_item(NAME(m_tune_num)); + save_item(NAME(m_tune_ofs)); + save_item(NAME(m_tune_max)); +} + + +//------------------------------------------------- +// sound_stream_update - handle a stream update +//------------------------------------------------- + +void tms36xx_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + int samplerate = m_samplerate; + stream_sample_t *buffer = outputs[0]; + + /* no tune played? */ + if( !tunes[m_tune_num] || m_voices == 0 ) + { + while (--samples >= 0) + buffer[samples] = 0; + return; + } + + while( samples-- > 0 ) + { + int sum = 0; + + /* decay the twelve voices */ + DECAY( 0) DECAY( 1) DECAY( 2) DECAY( 3) DECAY( 4) DECAY( 5) + DECAY( 6) DECAY( 7) DECAY( 8) DECAY( 9) DECAY(10) DECAY(11) + + /* musical note timing */ + m_tune_counter -= m_speed; + if( m_tune_counter <= 0 ) + { + int n = (-m_tune_counter / samplerate) + 1; + m_tune_counter += n * samplerate; + + if( (m_note_counter -= n) <= 0 ) + { + m_note_counter += TMS36XX_VMAX; + if (m_tune_ofs < m_tune_max) + { + /* shift to the other 'bank' of voices */ + m_shift ^= 6; + /* restart one 'bank' of voices */ + RESTART(0) RESTART(1) RESTART(2) + RESTART(3) RESTART(4) RESTART(5) + m_tune_ofs++; + } + } + } + + /* update the twelve voices */ + TONE( 0) TONE( 1) TONE( 2) TONE( 3) TONE( 4) TONE( 5) + TONE( 6) TONE( 7) TONE( 8) TONE( 9) TONE(10) TONE(11) + + *buffer++ = sum / m_voices; + } +} + + +//------------------------------------------------- +// MM6221AA interface functions +//------------------------------------------------- + +void tms36xx_device::mm6221aa_tune_w(int tune) +{ + /* which tune? */ + tune &= 3; + if( tune == m_tune_num ) + return; + + LOG(("%s tune:%X\n", m_subtype, tune)); + + /* update the stream before changing the tune */ + m_channel->update(); + + m_tune_num = tune; + m_tune_ofs = 0; + m_tune_max = 96; /* fixed for now */ +} + + +//------------------------------------------------- +// TMS3615/17 interface functions +//------------------------------------------------- + +void tms36xx_device::tms36xx_note_w(int octave, int note) +{ + octave &= 3; + note &= 15; + + if (note > 12) + return; + + LOG(("%s octave:%X note:%X\n", m_subtype, octave, note)); + + /* update the stream before changing the tune */ + m_channel->update(); + + /* play a single note from 'tune 4', a list of the 13 tones */ + tms36xx_reset_counters(); + m_octave = octave; + m_tune_num = 4; + m_tune_ofs = note; + m_tune_max = note + 1; +} + + +//------------------------------------------------- +// TMS3617 interface functions +//------------------------------------------------- + +void tms36xx_device::tms3617_enable_w(int enable) +{ + tms3617_enable(enable); +} + + +//------------------------------------------------- +// Locals +//------------------------------------------------- + +void tms36xx_device::tms36xx_reset_counters() +{ + m_tune_counter = 0; + m_note_counter = 0; + memset(m_vol_counter, 0, sizeof(m_vol_counter)); + memset(m_counter, 0, sizeof(m_counter)); +} + + +void tms36xx_device::tms3617_enable(int enable) +{ + int i, bits = 0; + + /* duplicate the 6 voice enable bits */ + enable = (enable & 0x3f) | ((enable & 0x3f) << 6); + if (enable == m_enable) + return; + + /* update the stream before changing the tune */ + m_channel->update(); + + LOG(("%s enable voices", m_subtype)); + for (i = 0; i < 6; i++) + { + if (enable & (1 << i)) + { + bits += 2; /* each voice has two instances */ + + switch (i) + { + case 0: LOG((" 16'")); break; + case 1: LOG((" 8'")); break; + case 2: LOG((" 5 1/3'")); break; + case 3: LOG((" 4'")); break; + case 4: LOG((" 2 2/3'")); break; + case 5: LOG((" 2'")); break; + } + } + } + /* set the enable mask and number of active voices */ + m_enable = enable; + m_voices = bits; + LOG(("%s\n", bits ? "" : " none")); +} diff --git a/src/devices/sound/tms36xx.h b/src/devices/sound/tms36xx.h new file mode 100644 index 00000000000..b15e5908cc5 --- /dev/null +++ b/src/devices/sound/tms36xx.h @@ -0,0 +1,137 @@ +// license:BSD-3-Clause +// copyright-holders:Juergen Buchmueller +#pragma once + +#ifndef __TMS36XX_H__ +#define __TMS36XX_H__ + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_TMS36XX_ADD(_tag, _clock) \ + MCFG_DEVICE_ADD(_tag, TMS36XX, _clock) +#define MCFG_TMS36XX_REPLACE(_tag, _clock) \ + MCFG_DEVICE_REPLACE(_tag, TMS36XX, _clock) + +#define MCFG_TMS36XX_TYPE(_type) \ + tms36xx_device::set_subtype(*device, _type); + +#define MCFG_TMS36XX_DECAY_TIMES(_dec0, _dec1, _dec2, _dec3, _dec4, _dec5) \ + tms36xx_device::set_decays(*device, _dec0, _dec1, _dec2, _dec3, _dec4, _dec5); + +#define MCFG_TMS36XX_TUNE_SPEED(_speed) \ + tms36xx_device::set_tune_speed(*device, _speed); + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// subtypes +#define MM6221AA 21 // Phoenix (fixed melodies) +#define TMS3615 15 // Naughty Boy, Pleiads (13 notes, one output) +#define TMS3617 17 // Monster Bash (13 notes, six outputs) + +#define TMS36XX_VMIN 0x0000 +#define TMS36XX_VMAX 0x7fff + + +// ======================> tms36xx_device + +class tms36xx_device : public device_t, + public device_sound_interface +{ +public: + tms36xx_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + ~tms36xx_device() { } + + static void set_subtype(device_t &device, int type) + { + tms36xx_device &dev = downcast(device); + switch (type) + { + case MM6221AA: + dev.m_subtype = "MM6221AA"; + break; + case TMS3615: + dev.m_subtype = "TMS3615"; + break; + case TMS3617: + dev.m_subtype = "TMS3617"; + break; + default: + fatalerror("Invalid TMS36XX type: %d\n", type); + break; + } + } + static void set_tune_speed(device_t &device, double speed) + { + downcast(device).m_speed = (speed > 0) ? TMS36XX_VMAX / speed : TMS36XX_VMAX; + } + static void set_decays(device_t &device, double decay_0, double decay_1, double decay_2, double decay_3, double decay_4, double decay_5) + { + tms36xx_device &dev = downcast(device); + dev.m_decay_time[0] = decay_0; + dev.m_decay_time[1] = decay_1; + dev.m_decay_time[2] = decay_2; + dev.m_decay_time[3] = decay_3; + dev.m_decay_time[4] = decay_4; + dev.m_decay_time[5] = decay_5; + } + +protected: + // device-level overrides + virtual void device_start(); + + // sound stream update overrides + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + +public: + // MM6221AA interface functions + void mm6221aa_tune_w(int tune); + + // TMS3615/17 interface functions + void tms36xx_note_w(int octave, int note); + + // TMS3617 interface functions + void tms3617_enable_w(int enable); + +private: + void tms36xx_reset_counters(); + void tms3617_enable(int enable); + + double m_decay_time[6]; // decay times for the six harmonic notes + + const char *m_subtype; // subtype name MM6221AA, TMS3615 or TMS3617 + sound_stream *m_channel; // returned by stream_create() + + int m_samplerate; // output sample rate + + int m_basefreq; // chip's base frequency + int m_octave; // octave select of the TMS3615 + + int m_speed; // speed of the tune + int m_tune_counter; // tune counter + int m_note_counter; // note counter + + int m_voices; // active voices + int m_shift; // shift toggles between 0 and 6 to allow decaying voices + int m_vol[12]; // (decaying) volume of harmonics notes + int m_vol_counter[12];// volume adjustment counter + int m_decay[12]; // volume adjustment rate - derived from m_intf_decay + + int m_counter[12]; // tone frequency counter + int m_frequency[12]; // tone frequency + int m_output; // output signal bits + int m_enable; // mask which harmoics + + int m_tune_num; // tune currently playing + int m_tune_ofs; // note currently playing + int m_tune_max; // end of tune +}; + +extern const device_type TMS36XX; + + +#endif /* __TMS36XX_H__ */ diff --git a/src/devices/sound/tms5110.c b/src/devices/sound/tms5110.c new file mode 100644 index 00000000000..481229a6bc3 --- /dev/null +++ b/src/devices/sound/tms5110.c @@ -0,0 +1,1620 @@ +// license:??? +// copyright-holders:Frank Palazzolo, Jarek Burczynski, Aaron Giles, Jonathan Gevaryahu, Couriersud +/********************************************************************************************** + + TMS5110 simulator (modified from TMS5220 by Jarek Burczynski) + + Written for MAME by Frank Palazzolo + With help from Neill Corlett + Additional tweaking by Aaron Giles + Various fixes by Lord Nightmare + Additional enhancements by Couriersud + Sub-interpolation-cycle parameter updating added by Lord Nightmare + Read-bit and Output fixes by Lord Nightmare + + Todo: + - implement CS + - TMS5110_CMD_TEST_TALK is only partially implemented + + TMS5100: + + +-----------------+ + TST | 1 28 | CS + PDC | 2 27 | CTL8 + ROM CK | 3 26 | ADD8 + CPU CK | 4 25 | CTL1 + VDD | 5 24 | ADD1 + CR OSC | 6 23 | CTL2 + RC OSC | 7 22 | ADD2 + T11 | 8 21 | ADD4 + NC | 9 20 | CTL4 + I/O | 10 19 | M1 + SPK1 | 11 18 | NC + SPK2 | 12 17 | NC + PROM OUT | 13 16 | NC + VSS | 14 15 | M0 + +-----------------+ + + T11: Sync for serial data out + + + M58817 + + The following connections could be derived from radar scope schematics. + The M58817 is not 100% pin compatible to the 5100, but really close. + + +-----------------+ + (NC) | 1 28 | CS + PDC | 2 27 | CTL8 + ROM CK | 3 26 | ADD8 (to 58819) + (NC) | 4 25 | CTL1 + (VDD,-5) | 5 24 | ADD1 (to 58819) + (GND) | 6 23 | CTL2 + Xin | 7 22 | ADD2 (to 58819) + Xout | 8 21 | ADD4 (to 58819) + (NC) | 9 20 | CTL4 + (VDD,-5) | 10 19 | Status back to CPU + (NC) | 11 18 | C1 (to 58819) + SPKR | 12 17 | (NC) + SPKR | 13 16 | C0 (to 58819) + (NC) | 14 15 | (5V) + +-----------------+ + +***********************************************************************************************/ + +#include "emu.h" +#include "tms5110.h" + +static INT16 clip_analog(INT16 cliptemp); + +/* *****optional defines***** */ + +/* Hacky improvements which don't match patent: */ +/* Interpolation shift logic: + * One of the following two lines should be used, and the other commented + * The second line is more accurate mathematically but not accurate to the patent + */ +#define INTERP_SHIFT >> m_coeff->interp_coeff[m_IP] +//define INTERP_SHIFT / (1<interp_coeff[m_IP]) + +/* Other hacks */ +/* HACK: if defined, outputs the low 4 bits of the lattice filter to the i/o + * or clip logic, even though the real hardware doesn't do this, partially verified by decap */ +#undef ALLOW_4_LSB + +/* forces m_TALK active instantly whenever m_SPEN would be activated, causing speech delay to be reduced by up to one frame time */ +/* for some reason, this hack makes snmath behave marginally more accurate to hardware, though it does not match the patent */ +#define FAST_START_HACK 1 + + +/* *****configuration of chip connection stuff***** */ +/* must be defined; if 0, output the waveform as if it was tapped on the speaker pin as usual, if 1, output the waveform as if it was tapped on the i/o pin (volume is much lower in the latter case) */ +#define FORCE_DIGITAL 0 + + +/* *****debugging defines***** */ +#undef VERBOSE +// above is general, somewhat obsolete, catch all for debugs which don't fit elsewhere +#undef DEBUG_PARSE_FRAME_DUMP +// above dumps each frame to stderr: be sure to select one of the options below if you define it! +#undef DEBUG_PARSE_FRAME_DUMP_BIN +// dumps each speech frame as binary +#undef DEBUG_PARSE_FRAME_DUMP_HEX +// dumps each speech frame as hex +#undef DEBUG_FRAME_ERRORS +// above dumps info if a frame ran out of data +#undef DEBUG_COMMAND_DUMP +// above dumps all command writes and PDC-related state machine changes, plus command writes to VSMs +#undef DEBUG_GENERATION +// above dumps debug information related to the sample generation loop, i.e. whether interpolation is inhibited or not, and what the current and target values for each frame are. +#undef DEBUG_GENERATION_VERBOSE +// above dumps MUCH MORE debug information related to the sample generation loop, namely the excitation, energy, pitch, k*, and output values for EVERY SINGLE SAMPLE during a frame. +#undef DEBUG_LATTICE +// above dumps the lattice filter state data each sample. +#undef DEBUG_CLIP +// above dumps info to stderr whenever the analog clip hardware is (or would be) clipping the signal. + + +#define MAX_SAMPLE_CHUNK 512 + +/* 6 Variants, from tms5110r.inc */ + +#define TMS5110_IS_TMC0281 (1) +#define TMS5110_IS_TMC0281D (2) +#define TMS5110_IS_CD2801 (3) +#define TMS5110_IS_CD2802 (4) +#define TMS5110_IS_TMS5110A (5) +#define TMS5110_IS_M58817 (6) + + +/* States for CTL */ + +// ctl bus is input to tms51xx +#define CTL_STATE_INPUT (0) +// ctl bus is outputting a test talk command on CTL1(bit 0) +#define CTL_STATE_TTALK_OUTPUT (1) +// ctl bus is switching direction, next will be above +#define CTL_STATE_NEXT_TTALK_OUTPUT (2) +// ctl bus is outputting a read nybble 'output' command on CTL1,2,4,8 (bits 0-3) +#define CTL_STATE_OUTPUT (3) +// ctl bus is switching direction, next will be above +#define CTL_STATE_NEXT_OUTPUT (4) + + + +/* Pull in the ROM tables */ +#include "tms5110r.inc" + +#define DEBUG_5110 0 + +void tms5110_device::set_variant(int variant) +{ + switch (variant) + { + case TMS5110_IS_TMC0281: + m_coeff = &T0280B_0281A_coeff; + break; + case TMS5110_IS_TMC0281D: + m_coeff = &T0280D_0281D_coeff; + break; + case TMS5110_IS_CD2801: + m_coeff = &T0280F_2801A_coeff; + break; + case TMS5110_IS_M58817: + m_coeff = &M58817_coeff; + break; + case TMS5110_IS_CD2802: + m_coeff = &T0280F_2802_coeff; + break; + case TMS5110_IS_TMS5110A: + m_coeff = &tms5110a_coeff; + break; + default: + fatalerror("Unknown variant in tms5110_create\n"); + } + + m_variant = variant; +} + +void tms5110_device::new_int_write(UINT8 rc, UINT8 m0, UINT8 m1, UINT8 addr) +{ + if (!m_m0_cb.isnull()) + m_m0_cb(m0); + if (!m_m1_cb.isnull()) + m_m1_cb(m1); + if (!m_addr_cb.isnull()) + m_addr_cb((offs_t)0, addr); + if (!m_romclk_cb.isnull()) + { + //printf("rc %d\n", rc); + m_romclk_cb(rc); + } +} + +void tms5110_device::new_int_write_addr(UINT8 addr) +{ + new_int_write(1, 0, 1, addr); // romclk 1, m0 0, m1 1, addr bus nybble = xxxx + new_int_write(0, 0, 1, addr); // romclk 0, m0 0, m1 1, addr bus nybble = xxxx + new_int_write(1, 0, 0, addr); // romclk 1, m0 0, m1 0, addr bus nybble = xxxx + new_int_write(0, 0, 0, addr); // romclk 0, m0 0, m1 0, addr bus nybble = xxxx +} + +UINT8 tms5110_device::new_int_read() +{ + new_int_write(1, 1, 0, 0); // romclk 1, m0 1, m1 0, addr bus nybble = 0/open bus + new_int_write(0, 1, 0, 0); // romclk 0, m0 1, m1 0, addr bus nybble = 0/open bus + new_int_write(1, 0, 0, 0); // romclk 1, m0 0, m1 0, addr bus nybble = 0/open bus + new_int_write(0, 0, 0, 0); // romclk 0, m0 0, m1 0, addr bus nybble = 0/open bus + if (!m_data_cb.isnull()) + return m_data_cb(); + if (DEBUG_5110) logerror("WARNING: CALLBACK MISSING, RETURNING 0!\n"); + return 0; +} + +void tms5110_device::register_for_save_states() +{ + save_item(NAME(m_variant)); + + save_item(NAME(m_PDC)); + save_item(NAME(m_CTL_pins)); + save_item(NAME(m_SPEN)); + save_item(NAME(m_TALK)); + save_item(NAME(m_TALKD)); + save_item(NAME(m_state)); + + save_item(NAME(m_address)); + save_item(NAME(m_next_is_address)); + save_item(NAME(m_schedule_dummy_read)); + save_item(NAME(m_addr_bit)); + save_item(NAME(m_CTL_buffer)); + + save_item(NAME(m_OLDE)); + save_item(NAME(m_OLDP)); + + save_item(NAME(m_new_frame_energy_idx)); + save_item(NAME(m_new_frame_pitch_idx)); + save_item(NAME(m_new_frame_k_idx)); +#ifdef PERFECT_INTERPOLATION_HACK + save_item(NAME(m_old_frame_energy_idx)); + save_item(NAME(m_old_frame_pitch_idx)); + save_item(NAME(m_old_frame_k_idx)); + save_item(NAME(m_old_zpar)); + save_item(NAME(m_old_uv_zpar)); +#endif + save_item(NAME(m_current_energy)); + save_item(NAME(m_current_pitch)); + save_item(NAME(m_current_k)); + + save_item(NAME(m_previous_energy)); + + save_item(NAME(m_subcycle)); + save_item(NAME(m_subc_reload)); + save_item(NAME(m_PC)); + save_item(NAME(m_IP)); + save_item(NAME(m_inhibit)); + save_item(NAME(m_uv_zpar)); + save_item(NAME(m_zpar)); + save_item(NAME(m_pitch_zero)); + save_item(NAME(m_pitch_count)); + + save_item(NAME(m_u)); + save_item(NAME(m_x)); + + save_item(NAME(m_RNG)); + save_item(NAME(m_excitation_data)); + + save_item(NAME(m_digital_select)); + + save_item(NAME(m_speech_rom_bitnum)); + + save_item(NAME(m_romclk_hack_timer_started)); + save_item(NAME(m_romclk_hack_state)); +} + +/********************************************************************************************** + + printbits helper function: takes a long int input and prints the resulting bits to stderr + +***********************************************************************************************/ + +#ifdef DEBUG_PARSE_FRAME_DUMP_BIN +static void printbits(long data, int num) +{ + int i; + for (i=(num-1); i>=0; i--) + fprintf(stderr,"%0ld", (data>>i)&1); +} +#endif +#ifdef DEBUG_PARSE_FRAME_DUMP_HEX +static void printbits(long data, int num) +{ + switch((num-1)&0xFC) + { + case 0: + fprintf(stderr,"%0lx", data); + break; + case 4: + fprintf(stderr,"%02lx", data); + break; + case 8: + fprintf(stderr,"%03lx", data); + break; + case 12: + fprintf(stderr,"%04lx", data); + break; + default: + fprintf(stderr,"%04lx", data); + break; + } +} +#endif + +/****************************************************************************************** + + extract_bits -- extract a specific number of bits from the VSM + +******************************************************************************************/ + +int tms5110_device::extract_bits(int count) +{ + int val = 0; + if (DEBUG_5110) logerror("requesting %d bits", count); + for (int i = 0; i < count; i++) + { + val = (val<<1) | new_int_read(); + if (DEBUG_5110) logerror("bit read: %d\n", val&1); + } + if (DEBUG_5110) logerror("returning: %02x\n", val); + return val; +} + + +void tms5110_device::perform_dummy_read() +{ + if (m_schedule_dummy_read) + { + int data = new_int_read(); + if (DEBUG_5110) logerror("TMS5110 performing dummy read; value read = %1i\n", data & 1); + m_schedule_dummy_read = FALSE; + } +} + + + + +/********************************************************************************************** + + tms5110_process -- fill the buffer with a specific number of samples + +***********************************************************************************************/ + +void tms5110_device::process(INT16 *buffer, unsigned int size) +{ + int buf_count=0; + int i, bitout; + INT32 this_sample; + + /* loop until the buffer is full or we've stopped speaking */ + while (size > 0) + { + if(m_TALKD) // speaking + { + /* if we're ready for a new frame to be applied, i.e. when IP=0, PC=12, Sub=1 + * (In reality, the frame was really loaded incrementally during the entire IP=0 + * PC=x time period, but it doesn't affect anything until IP=0 PC=12 happens) + */ + if ((m_IP == 0) && (m_PC == 12) && (m_subcycle == 1)) + { + // HACK for regression testing, be sure to comment out before release! + //m_RNG = 0x1234; + // end HACK + +#ifdef PERFECT_INTERPOLATION_HACK + /* remember previous frame energy, pitch, and coefficients */ + m_old_frame_energy_idx = m_new_frame_energy_idx; + m_old_frame_pitch_idx = m_new_frame_pitch_idx; + for (i = 0; i < m_coeff->num_k; i++) + m_old_frame_k_idx[i] = m_new_frame_k_idx[i]; +#endif + + /* Parse a new frame into the new_target_energy, new_target_pitch and new_target_k[] */ + parse_frame(); + + // if the new frame is unvoiced (or silenced via ZPAR), be sure to zero out the k5-k10 parameters + // NOTE: this is probably the bug the tms5100/tmc0280 has, pre-rev D, I think. + // GUESS: Pre-rev D versions start zeroing k5-k10 immediately upon new frame load regardless of interpolation inhibit + // I.e. ZPAR = /TALKD || (PC>5&&P=0) + // GUESS: D and later versions only start or stop zeroing k5-k10 at the IP7->IP0 transition AFTER the frame + // I.e. ZPAR = /TALKD || (PC>5&&OLDP) +#ifdef PERFECT_INTERPOLATION_HACK + m_old_uv_zpar = m_uv_zpar; + m_old_zpar = m_zpar; // unset old zpar on new frame +#endif + m_zpar = 0; + //m_uv_zpar = (OLD_FRAME_UNVOICED_FLAG||m_zpar); // GUESS: fixed version in tmc0280d/tms5100a/cd280x/tms5110 + m_uv_zpar = (NEW_FRAME_UNVOICED_FLAG||m_zpar); // GUESS: buggy version in tmc0280/tms5100 + + /* if the new frame is a stop frame, unset both TALK and SPEN (via TCON). TALKD remains active while the energy is ramping to 0. */ + if (NEW_FRAME_STOP_FLAG == 1) + { + m_TALK = m_SPEN = 0; + } + + /* in all cases where interpolation would be inhibited, set the inhibit flag; otherwise clear it. + Interpolation inhibit cases: + * Old frame was voiced, new is unvoiced + * Old frame was silence/zero energy, new has nonzero energy + * Old frame was unvoiced, new is voiced (note this is the case on the patent but may not be correct on the real final chip) + */ + if ( ((OLD_FRAME_UNVOICED_FLAG == 0) && (NEW_FRAME_UNVOICED_FLAG == 1)) + || ((OLD_FRAME_UNVOICED_FLAG == 1) && (NEW_FRAME_UNVOICED_FLAG == 0)) + || ((OLD_FRAME_SILENCE_FLAG == 1) && (NEW_FRAME_SILENCE_FLAG == 0)) ) + m_inhibit = 1; + else // normal frame, normal interpolation + m_inhibit = 0; + +#ifdef DEBUG_GENERATION + /* Debug info for current parsed frame */ + fprintf(stderr, "OLDE=0: %d; OLDP=0: %d; E=0: %d; P=0: %d; ", m_OLDE, m_OLDP, (m_new_frame_energy_idx==0), (m_new_frame_pitch_idx==0)); + fprintf(stderr,"Processing new frame: "); + if (m_inhibit == 0) + fprintf(stderr, "Normal Frame\n"); + else + fprintf(stderr,"Interpolation Inhibited\n"); + fprintf(stderr,"*** current Energy, Pitch and Ks = %04d, %04d, %04d, %04d, %04d, %04d, %04d, %04d, %04d, %04d, %04d, %04d\n",m_current_energy, m_current_pitch, m_current_k[0], m_current_k[1], m_current_k[2], m_current_k[3], m_current_k[4], m_current_k[5], m_current_k[6], m_current_k[7], m_current_k[8], m_current_k[9]); + fprintf(stderr,"*** target Energy(idx), Pitch, and Ks = %04d(%x),%04d, %04d, %04d, %04d, %04d, %04d, %04d, %04d, %04d, %04d, %04d\n", + (m_coeff->energytable[m_new_frame_energy_idx] * (1-m_zpar)), + m_new_frame_energy_idx, + (m_coeff->pitchtable[m_new_frame_pitch_idx] * (1-m_zpar)), + (m_coeff->ktable[0][m_new_frame_k_idx[0]] * (1-m_zpar)), + (m_coeff->ktable[1][m_new_frame_k_idx[1]] * (1-m_zpar)), + (m_coeff->ktable[2][m_new_frame_k_idx[2]] * (1-m_zpar)), + (m_coeff->ktable[3][m_new_frame_k_idx[3]] * (1-m_zpar)), + (m_coeff->ktable[4][m_new_frame_k_idx[4]] * (1-m_uv_zpar)), + (m_coeff->ktable[5][m_new_frame_k_idx[5]] * (1-m_uv_zpar)), + (m_coeff->ktable[6][m_new_frame_k_idx[6]] * (1-m_uv_zpar)), + (m_coeff->ktable[7][m_new_frame_k_idx[7]] * (1-m_uv_zpar)), + (m_coeff->ktable[8][m_new_frame_k_idx[8]] * (1-m_uv_zpar)), + (m_coeff->ktable[9][m_new_frame_k_idx[9]] * (1-m_uv_zpar)) ); +#endif + + } + else // Not a new frame, just interpolate the existing frame. + { + int inhibit_state = ((m_inhibit==1)&&(m_IP != 0)); // disable inhibit when reaching the last interp period, but don't overwrite the m_inhibit value +#ifdef PERFECT_INTERPOLATION_HACK + int samples_per_frame = m_subc_reload?175:266; // either (13 A cycles + 12 B cycles) * 7 interps for normal SPEAK/SPKEXT, or (13*2 A cycles + 12 B cycles) * 7 interps for SPKSLOW + //int samples_per_frame = m_subc_reload?200:304; // either (13 A cycles + 12 B cycles) * 8 interps for normal SPEAK/SPKEXT, or (13*2 A cycles + 12 B cycles) * 8 interps for SPKSLOW + int current_sample = (m_subcycle - m_subc_reload)+(m_PC*(3-m_subc_reload))+((m_subc_reload?25:38)*((m_IP-1)&7)); + //fprintf(stderr, "CS: %03d", current_sample); + // reset the current energy, pitch, etc to what it was at frame start + m_current_energy = (m_coeff->energytable[m_old_frame_energy_idx] * (1-m_old_zpar)); + m_current_pitch = (m_coeff->pitchtable[m_old_frame_pitch_idx] * (1-m_old_zpar)); + for (i = 0; i < m_coeff->num_k; i++) + m_current_k[i] = (m_coeff->ktable[i][m_old_frame_k_idx[i]] * (1-((i<4)?m_old_zpar:m_old_uv_zpar))); + // now adjust each value to be exactly correct for each of the samples per frame + if (m_IP != 0) // if we're still interpolating... + { + m_current_energy = (m_current_energy + (((m_coeff->energytable[m_new_frame_energy_idx] - m_current_energy)*(1-inhibit_state))*current_sample)/samples_per_frame)*(1-m_zpar); + m_current_pitch = (m_current_pitch + (((m_coeff->pitchtable[m_new_frame_pitch_idx] - m_current_pitch)*(1-inhibit_state))*current_sample)/samples_per_frame)*(1-m_zpar); + for (i = 0; i < m_coeff->num_k; i++) + m_current_k[i] = (m_current_k[i] + (((m_coeff->ktable[i][m_new_frame_k_idx[i]] - m_current_k[i])*(1-inhibit_state))*current_sample)/samples_per_frame)*(1-((i<4)?m_zpar:m_uv_zpar)); + } + else // we're done, play this frame for 1/8 frame. + { + m_current_energy = (m_coeff->energytable[m_new_frame_energy_idx] * (1-m_zpar)); + m_current_pitch = (m_coeff->pitchtable[m_new_frame_pitch_idx] * (1-m_zpar)); + for (i = 0; i < m_coeff->num_k; i++) + m_current_k[i] = (m_coeff->ktable[i][m_new_frame_k_idx[i]] * (1-((i<4)?m_zpar:m_uv_zpar))); + } +#else + //Updates to parameters only happen on subcycle '2' (B cycle) of PCs. + if (m_subcycle == 2) + { + switch(m_PC) + { + case 0: /* PC = 0, B cycle, write updated energy */ + m_current_energy = (m_current_energy + (((m_coeff->energytable[m_new_frame_energy_idx] - m_current_energy)*(1-inhibit_state)) INTERP_SHIFT))*(1-m_zpar); + break; + case 1: /* PC = 1, B cycle, write updated pitch */ + m_current_pitch = (m_current_pitch + (((m_coeff->pitchtable[m_new_frame_pitch_idx] - m_current_pitch)*(1-inhibit_state)) INTERP_SHIFT))*(1-m_zpar); + break; + case 2: case 3: case 4: case 5: case 6: case 7: case 8: case 9: case 10: case 11: + /* PC = 2 through 11, B cycle, write updated K1 through K10 */ + m_current_k[m_PC-2] = (m_current_k[m_PC-2] + (((m_coeff->ktable[m_PC-2][m_new_frame_k_idx[m_PC-2]] - m_current_k[m_PC-2])*(1-inhibit_state)) INTERP_SHIFT))*(1-(((m_PC-2)<4)?m_zpar:m_uv_zpar)); + break; + case 12: /* PC = 12 */ + /* we should NEVER reach this point, PC=12 doesn't have a subcycle 2 */ + break; + } + } +#endif + } + + // calculate the output + if (OLD_FRAME_UNVOICED_FLAG == 1) + { + // generate unvoiced samples here + if (m_RNG & 1) + m_excitation_data = ~0x3F; /* according to the patent it is (either + or -) half of the maximum value in the chirp table, so either 01000000(0x40) or 11000000(0xC0)*/ + else + m_excitation_data = 0x40; + } + else /* (OLD_FRAME_UNVOICED_FLAG == 0) */ + { + // generate voiced samples here + /* US patent 4331836 Figure 14B shows, and logic would hold, that a pitch based chirp + * function has a chirp/peak and then a long chain of zeroes. + * The last entry of the chirp rom is at address 0b110011 (51d), the 52nd sample, + * and if the address reaches that point the ADDRESS incrementer is + * disabled, forcing all samples beyond 51d to be == 51d + */ + if (m_pitch_count >= 51) + m_excitation_data = (INT8)m_coeff->chirptable[51]; + else /*m_pitch_count < 51*/ + m_excitation_data = (INT8)m_coeff->chirptable[m_pitch_count]; + } + + // Update LFSR *20* times every sample (once per T cycle), like patent shows + for (i=0; i<20; i++) + { + bitout = ((m_RNG >> 12) & 1) ^ + ((m_RNG >> 3) & 1) ^ + ((m_RNG >> 2) & 1) ^ + ((m_RNG >> 0) & 1); + m_RNG <<= 1; + m_RNG |= bitout; + } + this_sample = lattice_filter(); /* execute lattice filter */ +#ifdef DEBUG_GENERATION_VERBOSE + //fprintf(stderr,"C:%01d; ",m_subcycle); + fprintf(stderr,"IP:%01d PC:%02d X:%04d E:%03d P:%03d Pc:%03d ",m_IP, m_PC, m_excitation_data, m_current_energy, m_current_pitch, m_pitch_count); + //fprintf(stderr,"X:%04d E:%03d P:%03d Pc:%03d ", m_excitation_data, m_current_energy, m_current_pitch, m_pitch_count); + for (i=0; i<10; i++) + fprintf(stderr,"K%d:%04d ", i+1, m_current_k[i]); + fprintf(stderr,"Out:%06d ", this_sample); +//#ifdef PERFECT_INTERPOLATION_HACK +// fprintf(stderr,"%d%d%d%d",m_old_zpar,m_zpar,m_old_uv_zpar,m_uv_zpar); +//#else +// fprintf(stderr,"x%dx%d",m_zpar,m_uv_zpar); +//#endif + fprintf(stderr,"\n"); +#endif + /* next, force result to 14 bits (since its possible that the addition at the final (k1) stage of the lattice overflowed) */ + while (this_sample > 16383) this_sample -= 32768; + while (this_sample < -16384) this_sample += 32768; + if (m_digital_select == 0) // analog SPK pin output is only 8 bits, with clipping + buffer[buf_count] = clip_analog(this_sample); + else // digital I/O pin output is 12 bits + { +#ifdef ALLOW_4_LSB + // input: ssss ssss ssss ssss ssnn nnnn nnnn nnnn + // N taps: ^ = 0x2000; + // output: ssss ssss ssss ssss snnn nnnn nnnn nnnN + buffer[buf_count] = (this_sample<<1)|((this_sample&0x2000)>>13); +#else + this_sample &= ~0xF; + // input: ssss ssss ssss ssss ssnn nnnn nnnn 0000 + // N taps: ^^ ^^^ = 0x3E00; + // output: ssss ssss ssss ssss snnn nnnn nnnN NNNN + buffer[buf_count] = (this_sample<<1)|((this_sample&0x3E00)>>9); +#endif + } + // Update all counts + + m_subcycle++; + if ((m_subcycle == 2) && (m_PC == 12)) // RESETF3 + { + /* Circuit 412 in the patent acts a reset, resetting the pitch counter to 0 + * if INHIBIT was true during the most recent frame transition. + * The exact time this occurs is betwen IP=7, PC=12 sub=0, T=t12 + * and m_IP = 0, PC=0 sub=0, T=t12, a period of exactly 20 cycles, + * which overlaps the time OLDE and OLDP are updated at IP=7 PC=12 T17 + * (and hence INHIBIT itself 2 t-cycles later). We do it here because it is + * convenient and should make no difference in output. + */ + if ((m_IP == 7)&&(m_inhibit==1)) m_pitch_zero = 1; + if ((m_IP == 0)&&(m_pitch_zero==1)) m_pitch_zero = 0; + if (m_IP == 7) // RESETL4 + { + // Latch OLDE and OLDP + OLD_FRAME_SILENCE_FLAG = NEW_FRAME_SILENCE_FLAG; // m_OLDE + OLD_FRAME_UNVOICED_FLAG = NEW_FRAME_UNVOICED_FLAG; // m_OLDP + /* if TALK was clear last frame, halt speech now, since TALKD (latched from TALK on new frame) just went inactive. */ +#ifdef DEBUG_GENERATION + if (m_TALK == 0) + fprintf(stderr,"tms5110_process: processing frame: TALKD = 0 caused by stop frame or buffer empty, halting speech.\n"); +#endif + m_TALKD = m_TALK; // TALKD is latched from TALK + m_TALK = m_SPEN; // TALK is latched from SPEN + } + m_subcycle = m_subc_reload; + m_PC = 0; + m_IP++; + m_IP&=0x7; + } + else if (m_subcycle == 3) + { + m_subcycle = m_subc_reload; + m_PC++; + } + m_pitch_count++; + if ((m_pitch_count >= m_current_pitch)||(m_pitch_zero == 1)) m_pitch_count = 0; + m_pitch_count &= 0x1FF; + } + else // m_TALKD == 0 + { + m_subcycle++; + if ((m_subcycle == 2) && (m_PC == 12)) // RESETF3 + { + if (m_IP == 7) // RESETL4 + { + m_TALKD = m_TALK; // TALKD is latched from TALK + m_TALK = m_SPEN; // TALK is latched from SPEN + } + m_subcycle = m_subc_reload; + m_PC = 0; + m_IP++; + m_IP&=0x7; + } + else if (m_subcycle == 3) + { + m_subcycle = m_subc_reload; + m_PC++; + } + buffer[buf_count] = -1; /* should be just -1; actual chip outputs -1 every idle sample; (cf note in data sheet, p 10, table 4) */ + } + buf_count++; + size--; + } +} + +/********************************************************************************************** + + clip_analog -- clips the 14 bit return value from the lattice filter to its final 10 bit value (-512 to 511), and upshifts/range extends this to 16 bits + +***********************************************************************************************/ + +static INT16 clip_analog(INT16 cliptemp) +{ + /* clipping, just like the patent shows: + * the top 10 bits of this result are visible on the digital output IO pin. + * next, if the top 3 bits of the 14 bit result are all the same, the lowest of those 3 bits plus the next 7 bits are the signed analog output, otherwise the low bits are all forced to match the inverse of the topmost bit, i.e.: + * 1x xxxx xxxx xxxx -> 0b10000000 + * 11 1bcd efgh xxxx -> 0b1bcdefgh + * 00 0bcd efgh xxxx -> 0b0bcdefgh + * 0x xxxx xxxx xxxx -> 0b01111111 + */ +#ifdef DEBUG_CLIP + if ((cliptemp > 2047) || (cliptemp < -2048)) fprintf(stderr,"clipping cliptemp to range; was %d\n", cliptemp); +#endif + if (cliptemp > 2047) cliptemp = 2047; + else if (cliptemp < -2048) cliptemp = -2048; + /* at this point the analog output is tapped */ +#ifdef ALLOW_4_LSB + // input: ssss snnn nnnn nnnn + // N taps: ^^^ ^ = 0x0780 + // output: snnn nnnn nnnn NNNN + return (cliptemp << 4)|((cliptemp&0x780)>>7); // upshift and range adjust +#else + cliptemp &= ~0xF; + // input: ssss snnn nnnn 0000 + // N taps: ^^^ ^^^^ = 0x07F0 + // P taps: ^ = 0x0400 + // output: snnn nnnn NNNN NNNP + return (cliptemp << 4)|((cliptemp&0x7F0)>>3)|((cliptemp&0x400)>>10); // upshift and range adjust +#endif +} + + +/********************************************************************************************** + + matrix_multiply -- does the proper multiply and shift + a is the k coefficient and is clamped to 10 bits (9 bits plus a sign) + b is the running result and is clamped to 14 bits. + output is 14 bits, but note the result LSB bit is always 1. + Because the low 4 bits of the result are trimmed off before + output, this makes almost no difference in the computation. + +**********************************************************************************************/ +static INT32 matrix_multiply(INT32 a, INT32 b) +{ + INT32 result; + while (a>511) { a-=1024; } + while (a<-512) { a+=1024; } + while (b>16383) { b-=32768; } + while (b<-16384) { b+=32768; } + result = ((a*b)>>9)|1;//&(~1); +#ifdef VERBOSE + if (result>16383) fprintf(stderr,"matrix multiplier overflowed! a: %x, b: %x, result: %x", a, b, result); + if (result<-16384) fprintf(stderr,"matrix multiplier underflowed! a: %x, b: %x, result: %x", a, b, result); +#endif + return result; +} + +/********************************************************************************************** + + lattice_filter -- executes one 'full run' of the lattice filter on a specific byte of + excitation data, and specific values of all the current k constants, and returns the + resulting sample. + +***********************************************************************************************/ + +INT32 tms5110_device::lattice_filter() +{ + // Lattice filter here + // Aug/05/07: redone as unrolled loop, for clarity - LN + /* Originally Copied verbatim from table I in US patent 4,209,804, now updated to be in same order as the actual chip does it, not that it matters. + notation equivalencies from table: + Yn(i) == m_u[n-1] + Kn = m_current_k[n-1] + bn = m_x[n-1] + */ + /* + int ep = matrix_multiply(m_previous_energy, (m_excitation_data<<6)); //Y(11) + m_u[10] = ep; + for (int i = 0; i < 10; i++) + { + int ii = 10-i; // for m = 10, this would be 11 - i, and since i is from 1 to 10, then ii ranges from 10 to 1 + //int jj = ii+1; // this variable, even on the fortran version, is never used. it probably was intended to be used on the two lines below the next one to save some redundant additions on each. + ep = ep - (((m_current_k[ii-1] * m_x[ii-1])>>9)|1); // subtract reflection from lower stage 'top of lattice' + m_u[ii-1] = ep; + m_x[ii] = m_x[ii-1] + (((m_current_k[ii-1] * ep)>>9)|1); // add reflection from upper stage 'bottom of lattice' + } + m_x[0] = ep; // feed the last section of the top of the lattice directly to the bottom of the lattice + */ + m_u[10] = matrix_multiply(m_previous_energy, (m_excitation_data<<6)); //Y(11) + m_u[9] = m_u[10] - matrix_multiply(m_current_k[9], m_x[9]); + m_u[8] = m_u[9] - matrix_multiply(m_current_k[8], m_x[8]); + m_u[7] = m_u[8] - matrix_multiply(m_current_k[7], m_x[7]); + m_u[6] = m_u[7] - matrix_multiply(m_current_k[6], m_x[6]); + m_u[5] = m_u[6] - matrix_multiply(m_current_k[5], m_x[5]); + m_u[4] = m_u[5] - matrix_multiply(m_current_k[4], m_x[4]); + m_u[3] = m_u[4] - matrix_multiply(m_current_k[3], m_x[3]); + m_u[2] = m_u[3] - matrix_multiply(m_current_k[2], m_x[2]); + m_u[1] = m_u[2] - matrix_multiply(m_current_k[1], m_x[1]); + m_u[0] = m_u[1] - matrix_multiply(m_current_k[0], m_x[0]); + m_x[9] = m_x[8] + matrix_multiply(m_current_k[8], m_u[8]); + m_x[8] = m_x[7] + matrix_multiply(m_current_k[7], m_u[7]); + m_x[7] = m_x[6] + matrix_multiply(m_current_k[6], m_u[6]); + m_x[6] = m_x[5] + matrix_multiply(m_current_k[5], m_u[5]); + m_x[5] = m_x[4] + matrix_multiply(m_current_k[4], m_u[4]); + m_x[4] = m_x[3] + matrix_multiply(m_current_k[3], m_u[3]); + m_x[3] = m_x[2] + matrix_multiply(m_current_k[2], m_u[2]); + m_x[2] = m_x[1] + matrix_multiply(m_current_k[1], m_u[1]); + m_x[1] = m_x[0] + matrix_multiply(m_current_k[0], m_u[0]); + m_x[0] = m_u[0]; + m_previous_energy = m_current_energy; +#ifdef DEBUG_LATTICE + int i; + fprintf(stderr,"V:%04d ", m_u[10]); + for (i = 9; i >= 0; i--) + { + fprintf(stderr,"Y%d:%04d ", i+1, m_u[i]); + fprintf(stderr,"b%d:%04d ", i+1, m_x[i]); + if ((i % 5) == 0) fprintf(stderr,"\n"); + } +#endif + return m_u[0]; +} + + + + +/****************************************************************************************** + + PDC_set -- set Processor Data Clock. Execute CTL_pins command on hi-lo transition. + +******************************************************************************************/ + +void tms5110_device::PDC_set(int data) +{ + if (m_PDC != (data & 0x1) ) + { + m_PDC = data & 0x1; + if (m_PDC == 0) /* toggling 1->0 processes command on CTL_pins */ + { +#ifdef DEBUG_COMMAND_DUMP + fprintf(stderr,"PDC falling edge(%02X): ",m_state); +#endif + /* first pdc toggles output, next toggles input */ + switch (m_state) + { + case CTL_STATE_INPUT: + /* continue */ + break; + case CTL_STATE_NEXT_TTALK_OUTPUT: +#ifdef DEBUG_COMMAND_DUMP + fprintf(stderr,"Switching CTL bus direction to output for Test Talk\n"); +#endif + m_state = CTL_STATE_TTALK_OUTPUT; + return; + case CTL_STATE_TTALK_OUTPUT: +#ifdef DEBUG_COMMAND_DUMP + fprintf(stderr,"Switching CTL bus direction back to input from Test Talk\n"); +#endif + m_state = CTL_STATE_INPUT; + return; + case CTL_STATE_NEXT_OUTPUT: +#ifdef DEBUG_COMMAND_DUMP + fprintf(stderr,"Switching CTL bus direction for Read Bit Buffer Output\n"); +#endif + m_state = CTL_STATE_OUTPUT; + return; + case CTL_STATE_OUTPUT: +#ifdef DEBUG_COMMAND_DUMP + fprintf(stderr,"Switching CTL bus direction back to input from Read Bit Buffer Output\n"); +#endif + m_state = CTL_STATE_INPUT; + return; + } + /* the only real commands we handle now are SPEAK and RESET */ + if (m_next_is_address) + { +#ifdef DEBUG_COMMAND_DUMP + fprintf(stderr,"Loading address nybble %02x to VSMs\n", m_CTL_pins); +#endif + m_next_is_address = FALSE; + m_address = m_address | ((m_CTL_pins & 0x0F)<>= 1; + m_CTL_buffer |= (extract_bits(1)<<3); + m_CTL_buffer &= 0xF; + } + break; + + case TMS5110_CMD_SPEAK: +#ifdef DEBUG_COMMAND_DUMP + fprintf(stderr,"SPEAK\n"); +#endif + perform_dummy_read(); + m_SPEN = 1; /* start immediately */ +#ifdef FAST_START_HACK + m_TALK = 1; +#endif + /* clear out variables before speaking */ + m_zpar = 1; // zero all the parameters + m_uv_zpar = 1; // zero k4-k10 as well + m_OLDE = 1; // 'silence/zpar' frames are zero energy + m_OLDP = 1; // 'silence/zpar' frames are zero pitch +#ifdef PERFECT_INTERPOLATION_HACK + m_old_zpar = 1; // zero all the old parameters + m_old_uv_zpar = 1; // zero old k4-k10 as well +#endif + m_subc_reload = 1; // SPEAK means this is 1 + break; + + case TMS5110_CMD_READ_BRANCH: +#ifdef DEBUG_COMMAND_DUMP + fprintf(stderr,"READ AND BRANCH\n"); +#endif + new_int_write(0,1,1,0); + new_int_write(1,1,1,0); + new_int_write(0,1,1,0); + new_int_write(0,0,0,0); + new_int_write(1,0,0,0); + new_int_write(0,0,0,0); + m_schedule_dummy_read = FALSE; + break; + + case TMS5110_CMD_TEST_TALK: +#ifdef DEBUG_COMMAND_DUMP + fprintf(stderr,"TEST TALK\n"); +#endif + m_state = CTL_STATE_NEXT_TTALK_OUTPUT; + break; + + default: +#ifdef DEBUG_COMMAND_DUMP + fprintf(stderr,"tms5110.c: unknown command: 0x%02x\n", m_CTL_pins); +#endif + break; + } + + } + } + } +} + + + +/****************************************************************************************** + + parse_frame -- parse a new frame's worth of data; returns 0 if not enough bits in buffer + +******************************************************************************************/ + +void tms5110_device::parse_frame() +{ + int i, rep_flag; + + // attempt to extract the energy index + m_new_frame_energy_idx = extract_bits(m_coeff->energy_bits); +#ifdef DEBUG_PARSE_FRAME_DUMP + printbits(m_new_frame_energy_idx,m_coeff->energy_bits); + fprintf(stderr," "); +#endif + + // if the energy index is 0 or 15, we're done + if ((m_new_frame_energy_idx == 0) || (m_new_frame_energy_idx == 15)) + return; + + rep_flag = extract_bits(1); +#ifdef DEBUG_PARSE_FRAME_DUMP + printbits(rep_flag, 1); + fprintf(stderr," "); +#endif + + m_new_frame_pitch_idx = extract_bits(m_coeff->pitch_bits); +#ifdef DEBUG_PARSE_FRAME_DUMP + printbits(m_new_frame_pitch_idx,m_coeff->pitch_bits); + fprintf(stderr," "); +#endif + // if this is a repeat frame, just do nothing, it will reuse the old coefficients + if (rep_flag) + return; + + // extract first 4 K coefficients + for (i = 0; i < 4; i++) + { + m_new_frame_k_idx[i] = extract_bits(m_coeff->kbits[i]); +#ifdef DEBUG_PARSE_FRAME_DUMP + printbits(m_new_frame_k_idx[i],m_coeff->kbits[i]); + fprintf(stderr," "); +#endif + } + + // if the pitch index was zero, we only need 4 K's... + if (m_new_frame_pitch_idx == 0) + { + /* and the rest of the coefficients are zeroed, but that's done in the generator code */ + return; + } + + // If we got here, we need the remaining 6 K's + for (i = 4; i < m_coeff->num_k; i++) + { + m_new_frame_k_idx[i] = extract_bits(m_coeff->kbits[i]); +#ifdef DEBUG_PARSE_FRAME_DUMP + printbits(m_new_frame_k_idx[i],m_coeff->kbits[i]); + fprintf(stderr," "); +#endif + } +#ifdef VERBOSE + logerror("Parsed a frame successfully in ROM\n"); +#endif + return; +} + + +#if 0 +/*This is an example word TEN taken from the TMS5110A datasheet*/ +static const unsigned int example_word_TEN[619]={ +/* 1*/1,0,0,0, 0, 0,0,0,0,0, 1,1,0,0,0, 0,0,0,1,0, 0,1,1,1, 0,1,0,1, +/* 2*/1,0,0,0, 0, 0,0,0,0,0, 1,0,0,1,0, 0,0,1,1,0, 0,0,1,1, 0,1,0,1, +/* 3*/1,1,0,0, 0, 1,0,0,0,0, 1,0,1,0,0, 0,1,0,1,0, 0,1,0,0, 1,0,1,0, 1,0,0,0, 1,0,0,1, 0,1,0,1, 0,0,1, 0,1,0, 0,1,1, +/* 4*/1,1,1,0, 0, 0,1,1,1,1, 1,0,1,0,1, 0,1,1,1,0, 0,1,0,1, 0,1,1,1, 0,1,1,1, 1,0,1,1, 1,0,1,0, 0,1,1, 0,1,0, 0,1,1, +/* 5*/1,1,1,0, 0, 1,0,0,0,0, 1,0,1,0,0, 0,1,1,1,0, 0,1,0,1, 1,0,1,0, 1,0,0,0, 1,1,0,0, 1,0,1,1, 1,0,0, 0,1,0, 0,1,1, +/* 6*/1,1,1,0, 0, 1,0,0,0,1, 1,0,1,0,1, 0,1,1,0,1, 0,1,1,0, 0,1,1,1, 0,1,1,1, 1,0,1,0, 1,0,1,0, 1,1,0, 0,0,1, 1,0,0, +/* 7*/1,1,1,0, 0, 1,0,0,1,0, 1,0,1,1,1, 0,1,1,1,0, 0,1,1,1, 0,1,1,1, 0,1,0,1, 0,1,1,0, 1,0,0,1, 1,1,0, 0,1,0, 0,1,1, +/* 8*/1,1,1,0, 1, 1,0,1,0,1, +/* 9*/1,1,1,0, 0, 1,1,0,0,1, 1,0,1,1,1, 0,1,0,1,1, 1,0,1,1, 0,1,1,1, 0,1,0,0, 1,0,0,0, 1,0,0,0, 1,1,0, 0,1,1, 0,1,1, +/*10*/1,1,0,1, 0, 1,1,0,1,0, 1,0,1,0,1, 0,1,1,0,1, 1,0,1,1, 0,1,0,1, 0,1,0,0, 1,0,0,0, 1,0,1,0, 1,1,0, 0,1,0, 1,0,0, +/*11*/1,0,1,1, 0, 1,1,0,1,1, 1,0,0,1,1, 1,0,0,1,0, 0,1,1,0, 0,0,1,1, 0,1,0,1, 1,0,0,1, 1,0,1,0, 1,0,0, 0,1,1, 0,1,1, +/*12*/1,0,0,0, 0, 1,1,1,0,0, 1,0,0,1,1, 0,0,1,1,0, 0,1,0,0, 0,1,1,0, 1,1,0,0, 0,1,0,1, 1,0,0,0, 1,0,0, 0,1,0, 1,0,1, +/*13*/0,1,1,1, 1, 1,1,1,0,1, +/*14*/0,1,1,1, 0, 1,1,1,1,0, 1,0,0,1,1, 0,0,1,1,1, 0,1,0,1, 0,1,0,1, 1,1,0,0, 0,1,1,1, 1,0,0,0, 1,0,0, 0,1,0, 1,0,1, +/*15*/0,1,1,0, 0, 1,1,1,1,0, 1,0,1,0,1, 0,0,1,1,0, 0,1,0,0, 0,0,1,1, 1,1,0,0, 1,0,0,1, 0,1,1,1, 1,0,1, 0,1,0, 1,0,1, +/*16*/1,1,1,1 +}; +#endif + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void tms5110_device::device_start() +{ + m_table = region()->base(); + + set_variant(TMS5110_IS_TMS5110A); + + /* resolve lines */ + m_m0_cb.resolve(); + m_m1_cb.resolve(); + m_romclk_cb.resolve(); + m_addr_cb.resolve(); + m_data_cb.resolve(); + + /* initialize a stream */ + m_stream = machine().sound().stream_alloc(*this, 0, 1, clock() / 80); + + m_state = CTL_STATE_INPUT; /* most probably not defined */ + m_romclk_hack_timer = timer_alloc(0); + + register_for_save_states(); +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void tms5100_device::device_start() +{ + tms5110_device::device_start(); + set_variant(TMS5110_IS_TMC0281); +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void tmc0281_device::device_start() +{ + tms5110_device::device_start(); + set_variant(TMS5110_IS_TMC0281); +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void tms5100a_device::device_start() +{ + tms5110_device::device_start(); + set_variant(TMS5110_IS_TMC0281D); +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void tmc0281d_device::device_start() +{ + tms5110_device::device_start(); + set_variant(TMS5110_IS_TMC0281D); +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void cd2801_device::device_start() +{ + tms5110_device::device_start(); + set_variant(TMS5110_IS_CD2801); +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void cd2802_device::device_start() +{ + tms5110_device::device_start(); + set_variant(TMS5110_IS_CD2802); +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void tms5110a_device::device_start() +{ + tms5110_device::device_start(); + set_variant(TMS5110_IS_TMS5110A); +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void m58817_device::device_start() +{ + tms5110_device::device_start(); + set_variant(TMS5110_IS_M58817); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void tms5110_device::device_reset() +{ + m_digital_select = FORCE_DIGITAL; // assume analog output + + /* initialize the chip state */ + m_SPEN = m_TALK = m_TALKD = 0; + m_CTL_pins = 0; + m_RNG = 0x1fff; + m_CTL_buffer = 0; + m_PDC = 0; + + /* initialize the energy/pitch/k states */ +#ifdef PERFECT_INTERPOLATION_HACK + m_old_frame_energy_idx = m_old_frame_pitch_idx = 0; + memset(m_old_frame_k_idx, 0, sizeof(m_old_frame_k_idx)); + m_old_zpar = m_old_uv_zpar = 0; +#endif + m_new_frame_energy_idx = m_current_energy = m_previous_energy = 0; + m_new_frame_pitch_idx = m_current_pitch = 0; + m_zpar = m_uv_zpar = 0; + memset(m_new_frame_k_idx, 0, sizeof(m_new_frame_k_idx)); + memset(m_current_k, 0, sizeof(m_current_k)); + + /* initialize the sample generators */ + m_inhibit = 1; + m_subcycle = m_pitch_count = m_pitch_zero = m_PC = m_zpar = 0; + m_subc_reload = 1; + m_OLDE = m_OLDP = 1; + m_IP = 0; + m_RNG = 0x1FFF; + memset(m_u, 0, sizeof(m_u)); + memset(m_x, 0, sizeof(m_x)); + if (m_table != NULL) + { + /* legacy interface */ + m_schedule_dummy_read = TRUE; + } + else + { + /* no dummy read! This makes bagman and ad2083 speech fail + * with the new cycle and transition exact interfaces + */ + m_schedule_dummy_read = FALSE; + } + m_next_is_address = FALSE; + m_address = 0; + m_addr_bit = 0; +} + + + +/****************************************************************************** + + tms5110_ctl_w -- write Control Command to the sound chip +commands like Speech, Reset, etc., are loaded into the chip via the CTL pins + +******************************************************************************/ + +WRITE8_MEMBER( tms5110_device::ctl_w ) +{ + /* bring up to date first */ + m_stream->update(); + m_CTL_pins = data & 0xf; +} + + +/****************************************************************************** + + tms5110_pdc_w -- write to PDC pin on the sound chip + +******************************************************************************/ + +WRITE_LINE_MEMBER( tms5110_device::pdc_w ) +{ + /* bring up to date first */ + m_stream->update(); + PDC_set(state); +} + + + +/****************************************************************************** + + tms5110_ctl_r -- read from the VSP (51xx) control bus + The CTL bus can be in three states: + 1. Test talk output: + bit 0 = TS - Talk Status is active (high) when the VSP is processing speech data. + Talk Status goes active at the initiation of a SPEAK command. + It goes inactive (low) when the stop code (Energy=1111) is processed, or + immediately(?????? not TMS5110) by a RESET command. + other bits may be open bus + 2. 'read bit' buffer contents output: + bits 0-3 = buffer contents + 3. Input 'open bus' state: + bits 0-3 = high-z + +******************************************************************************/ + +READ8_MEMBER( tms5110_device::ctl_r ) +{ + /* bring up to date first */ + m_stream->update(); + if (m_state == CTL_STATE_TTALK_OUTPUT) + { + if (DEBUG_5110) logerror("Status read while outputting Test Talk (status=%2d)\n", TALK_STATUS); + return (TALK_STATUS << 0); /*CTL1 = still talking ? */ + } + else if (m_state == CTL_STATE_OUTPUT) + { + if (DEBUG_5110) logerror("Status read while outputting buffer (buffer=%2d)\n", m_CTL_buffer); + return (m_CTL_buffer); + } + else // we're reading with the bus in input mode! just return the last thing written to the bus + { + if (DEBUG_5110) logerror("Status read (not in output mode), returning %02x\n", m_CTL_pins); + return (m_CTL_pins); + } +} + +READ8_MEMBER( m58817_device::status_r ) +{ + /* bring up to date first */ + m_stream->update(); + return (TALK_STATUS << 0); /*CTL1 = still talking ? */ +} + +/****************************************************************************** + + tms5110_romclk_hack_r -- read status of romclk + +******************************************************************************/ + +void tms5110_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + m_romclk_hack_state = !m_romclk_hack_state; +} + +READ8_MEMBER( tms5110_device::romclk_hack_r ) +{ + /* bring up to date first */ + m_stream->update(); + + /* create and start timer if necessary */ + if (!m_romclk_hack_timer_started) + { + m_romclk_hack_timer_started = TRUE; + m_romclk_hack_timer->adjust(attotime::from_hz(clock() / 40), 0, attotime::from_hz(clock() / 40)); + } + return m_romclk_hack_state; +} + + +/****************************************************************************** + + tms5110_update -- update the sound chip so that it is in sync with CPU execution + +******************************************************************************/ + +//------------------------------------------------- +// sound_stream_update - handle a stream update +//------------------------------------------------- + +void tms5110_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + INT16 sample_data[MAX_SAMPLE_CHUNK]; + stream_sample_t *buffer = outputs[0]; + + /* loop while we still have samples to generate */ + while (samples) + { + int length = (samples > MAX_SAMPLE_CHUNK) ? MAX_SAMPLE_CHUNK : samples; + int index; + + /* generate the samples and copy to the target buffer */ + process(sample_data, length); + for (index = 0; index < length; index++) + *buffer++ = sample_data[index]; + + /* account for the samples */ + samples -= length; + } +} + + + +/****************************************************************************** + + tms5110_set_frequency -- adjusts the playback frequency + TODO: kill this function; we should be adjusting the tms51xx device clock itself, + not setting it here! + +******************************************************************************/ + +void tms5110_device::set_frequency(int frequency) +{ + m_stream->set_sample_rate(frequency / 80); +} + + + +/* from here on in this file is a VSM 'Emulator' circuit used by bagman and ad2083 */ + +/* + * + * General Interface design (Bagman) + * + * +------------------------------------------------------------------------+ + * | | + * +-------------+ | +-------------+ +-------------+ +-------------+ | + * | TMS5100 | | | Counters | | Rom(s) | | Decoder | | + * | ADD8 |<--+ | LS393s | | | | | | + * | | | | | | | Out |--+ + * | M0 |---+ | Address |======>| Address | | IN1 | + * | | | | | | Data |======>| ... | + * M | | +---------->| Clk | | | | IN8 | + * A-->| CTL1 | | | | | | | + * P-->| CTL2 | +--->| Reset | | | | | + * P-->| CTL3 | | | | | | | A B C | + * E-->| CTL4 | | +-------------+ +-------------+ +-------------+ + * D-->| PDC | | ^ ^ ^ + * | | +-------------------------------------------------+ | | | + * | | | Bit Select + * | ROMCLK |---+ +-------------+ +-------------+ | + * | | | | Counter | | PROM | | + * +-------------+ | | LS393 | | D1 | M --+ Reset Bit + * | | Q0 |------>| A0 | A + * +---------->| Clk Q1 |------>| A1 | P ==> CTL1 ... CTL4 + * | Q2 |------>| A2 | P --> PDC + * | Reset Q3 |------>| A3 | E --+ Stop Bit + * | | +-->| A4 D8 | D | + * +-------------+ | +-------------+ | + * | | + * | +---+ | + * | | |<-----------------+ + * +---| & | + * | |<-------- Enable + * +---+ + * + */ + +/****************************************************************************** + + device_start( tmsprom ) -- allocate buffers initialize + +******************************************************************************/ + +void tmsprom_device::register_for_save_states() +{ + save_item(NAME(m_address)); + save_item(NAME(m_base_address)); + save_item(NAME(m_bit)); + save_item(NAME(m_enable)); + save_item(NAME(m_prom_cnt)); + save_item(NAME(m_m0)); +} + +void tmsprom_device::update_prom_cnt() +{ + UINT8 prev_val = m_prom[m_prom_cnt] | 0x0200; + if (m_enable && (prev_val & (1<> m_pdc_bit) & 0x01); +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void tmsprom_device::device_start() +{ + /* resolve lines */ + m_pdc_cb.resolve_safe(); + m_ctl_cb.resolve_safe(); + + m_rom = region()->base(); + assert_always(m_rom != NULL, "Error creating TMSPROM chip: No rom region found"); + m_prom = owner()->memregion(m_prom_region)->base(); + assert_always(m_prom != NULL, "Error creating TMSPROM chip: No prom region found"); + + m_romclk_timer = timer_alloc(0); + m_romclk_timer->adjust(attotime::zero, 0, attotime::from_hz(clock())); + + m_bit = 0; + m_base_address = 0; + m_address = 0; + m_enable = 0; + m_m0 = 0; + m_prom_cnt = 0; + + register_for_save_states(); +} + +WRITE_LINE_MEMBER( tmsprom_device::m0_w ) +{ + /* falling edge counts */ + if (m_m0 && !state) + { + m_address += 1; + m_address &= (m_rom_size-1); + } + m_m0 = state; +} + +READ_LINE_MEMBER( tmsprom_device::data_r ) +{ + return (m_rom[m_base_address + m_address] >> m_bit) & 0x01; +} + + +WRITE8_MEMBER( tmsprom_device::rom_csq_w ) +{ + if (!data) + m_base_address = offset * m_rom_size; +} + +WRITE8_MEMBER( tmsprom_device::bit_w ) +{ + m_bit = data; +} + +WRITE_LINE_MEMBER( tmsprom_device::enable_w ) +{ + if (state != m_enable) + { + m_enable = state; + update_prom_cnt(); + + /* the following is needed for ad2084. + * It is difficult to derive the actual connections from + * pcb pictures but the reset pin of the LS393 driving + * the prom address line is connected somewhere. + * + * This does not affect bagman. It just simulates that a + * write to ads3 is always happening when the four lower + * counter bits are 0! + */ + if (state) + m_prom_cnt &= 0x10; + } +} + + +/*------------------------------------------------- + TMS 5110 device definition +-------------------------------------------------*/ + +const device_type TMS5110 = &device_creator; + +tms5110_device::tms5110_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, TMS5110, "TMS5110", tag, owner, clock, "tms5110", __FILE__), + device_sound_interface(mconfig, *this), + m_m0_cb(*this), + m_m1_cb(*this), + m_addr_cb(*this), + m_data_cb(*this), + m_romclk_cb(*this) +{ +} + +tms5110_device::tms5110_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_sound_interface(mconfig, *this), + m_m0_cb(*this), + m_m1_cb(*this), + m_addr_cb(*this), + m_data_cb(*this), + m_romclk_cb(*this) +{ +} + + +const device_type TMS5100 = &device_creator; + +tms5100_device::tms5100_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : tms5110_device(mconfig, TMS5100, "TMS5100", tag, owner, clock, "tms5100", __FILE__) +{ +} + +const device_type TMC0281 = &device_creator; + +tmc0281_device::tmc0281_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : tms5110_device(mconfig, TMC0281, "TMC0281", tag, owner, clock, "tmc0281", __FILE__) +{ +} + +const device_type TMS5100A = &device_creator; + +tms5100a_device::tms5100a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : tms5110_device(mconfig, TMS5100A, "TMS5100A", tag, owner, clock, "tms5100a", __FILE__) +{ +} + +const device_type TMC0281D = &device_creator; + +tmc0281d_device::tmc0281d_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : tms5110_device(mconfig, TMC0281D, "TMC0281D", tag, owner, clock, "tmc0281d", __FILE__) +{ +} + +const device_type CD2801 = &device_creator; + +cd2801_device::cd2801_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : tms5110_device(mconfig, CD2801, "CD2801", tag, owner, clock, "cd2801", __FILE__) +{ +} + +const device_type CD2802 = &device_creator; + +cd2802_device::cd2802_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : tms5110_device(mconfig, CD2802, "CD2802", tag, owner, clock, "cd2802", __FILE__) +{ +} + +const device_type TMS5110A = &device_creator; + +tms5110a_device::tms5110a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : tms5110_device(mconfig, TMS5110A, "TMS5110A", tag, owner, clock, "tms5110a", __FILE__) +{ +} + +const device_type M58817 = &device_creator; + +m58817_device::m58817_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : tms5110_device(mconfig, M58817, "M58817", tag, owner, clock, "m58817", __FILE__) +{ +} + + +const device_type TMSPROM = &device_creator; + +tmsprom_device::tmsprom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, TMSPROM, "TMSPROM", tag, owner, clock, "tmsprom", __FILE__), + m_prom_region(""), + m_rom_size(0), + m_pdc_bit(0), + m_ctl1_bit(0), + m_ctl2_bit(0), + m_ctl4_bit(0), + m_ctl8_bit(0), + m_reset_bit(0), + m_stop_bit(0), + m_pdc_cb(*this), + m_ctl_cb(*this) +{ +} diff --git a/src/devices/sound/tms5110.h b/src/devices/sound/tms5110.h new file mode 100644 index 00000000000..dffb19b29d7 --- /dev/null +++ b/src/devices/sound/tms5110.h @@ -0,0 +1,397 @@ +// license:??? +// copyright-holders:Frank Palazzolo, Jarek Burczynski, Aaron Giles, Jonathan Gevaryahu, Couriersud +#pragma once + +#ifndef __TMS5110_H__ +#define __TMS5110_H__ + +#include "emu.h" + +/* HACK: if defined, uses impossibly perfect 'straight line' interpolation */ +#undef PERFECT_INTERPOLATION_HACK + +/* TMS5110 commands */ + /* CTL8 CTL4 CTL2 CTL1 | PDC's */ + /* (MSB) (LSB) | required */ +#define TMS5110_CMD_RESET (0) /* 0 0 0 x | 1 */ +#define TMS5110_CMD_LOAD_ADDRESS (2) /* 0 0 1 x | 2 */ +#define TMS5110_CMD_OUTPUT (4) /* 0 1 0 x | 3 */ +#define TMS5110_CMD_SPKSLOW (6) /* 0 1 1 x | 1 | Note: this command is undocumented on the datasheets, it only appears on the patents. It might not actually work properly on some of the real chips as manufactured. Acts the same as CMD_SPEAK, but makes the interpolator take three A cycles whereever it would normally only take one, effectively making speech of any given word take twice as long as normal. */ +#define TMS5110_CMD_READ_BIT (8) /* 1 0 0 x | 1 */ +#define TMS5110_CMD_SPEAK (10) /* 1 0 1 x | 1 */ +#define TMS5110_CMD_READ_BRANCH (12) /* 1 1 0 x | 1 */ +#define TMS5110_CMD_TEST_TALK (14) /* 1 1 1 x | 3 */ + +/* clock rate = 80 * output sample rate, */ +/* usually 640000 for 8000 Hz sample rate or */ +/* usually 800000 for 10000 Hz sample rate. */ + +#define MCFG_TMS5110_M0_CB(_devcb) \ + devcb = &tms5110_device::set_m0_callback(*device, DEVCB_##_devcb); + +#define MCFG_TMS5110_M1_CB(_devcb) \ + devcb = &tms5110_device::set_m1_callback(*device, DEVCB_##_devcb); + +#define MCFG_TMS5110_ADDR_CB(_devcb) \ + devcb = &tms5110_device::set_addr_callback(*device, DEVCB_##_devcb); + +#define MCFG_TMS5110_DATA_CB(_devcb) \ + devcb = &tms5110_device::set_data_callback(*device, DEVCB_##_devcb); + +#define MCFG_TMS5110_ROMCLK_CB(_devcb) \ + devcb = &tms5110_device::set_romclk_callback(*device, DEVCB_##_devcb); + + +class tms5110_device : public device_t, + public device_sound_interface +{ +public: + tms5110_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + tms5110_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + template static devcb_base &set_m0_callback(device_t &device, _Object object) { return downcast(device).m_m0_cb.set_callback(object); } + template static devcb_base &set_m1_callback(device_t &device, _Object object) { return downcast(device).m_m1_cb.set_callback(object); } + template static devcb_base &set_addr_callback(device_t &device, _Object object) { return downcast(device).m_addr_cb.set_callback(object); } + template static devcb_base &set_data_callback(device_t &device, _Object object) { return downcast(device).m_data_cb.set_callback(object); } + template static devcb_base &set_romclk_callback(device_t &device, _Object object) { return downcast(device).m_romclk_cb.set_callback(object); } + + DECLARE_WRITE8_MEMBER( ctl_w ); + DECLARE_READ8_MEMBER( ctl_r ); + DECLARE_WRITE_LINE_MEMBER( pdc_w ); + + /* this is only used by cvs.c + * it is not related at all to the speech generation + * and conflicts with the new rom controller interface. + */ + DECLARE_READ8_MEMBER( romclk_hack_r ); + + void set_frequency(int frequency); + + int _speech_rom_read_bit(); + void _speech_rom_set_addr(int addr); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + // sound stream update overrides + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + + void set_variant(int variant); + + UINT8 m_SPEN; /* set on speak command, cleared on stop command or reset command */ + UINT8 m_TALK; /* set on SPEN & RESETL4(pc12->pc0 transition), cleared on stop command or reset command */ +#define TALK_STATUS (m_SPEN|m_TALKD) + UINT8 m_TALKD; /* TALK(TCON) value, latched every RESETL4 */ + sound_stream *m_stream; + +private: + void new_int_write(UINT8 rc, UINT8 m0, UINT8 m1, UINT8 addr); + void new_int_write_addr(UINT8 addr); + UINT8 new_int_read(); + void register_for_save_states(); + int extract_bits(int count); + void perform_dummy_read(); + INT32 lattice_filter(); + void process(INT16 *buffer, unsigned int size); + void PDC_set(int data); + void parse_frame(); + + // internal state + /* coefficient tables */ + int m_variant; /* Variant of the 5110 - see tms5110.h */ + + /* coefficient tables */ + const struct tms5100_coeffs *m_coeff; + + /* these contain global status bits */ + UINT8 m_PDC; + UINT8 m_CTL_pins; + UINT8 m_state; + + /* Rom interface */ + UINT32 m_address; + UINT8 m_next_is_address; + UINT8 m_schedule_dummy_read; + UINT8 m_addr_bit; + /* read byte */ + UINT8 m_CTL_buffer; + + /* callbacks */ + devcb_write_line m_m0_cb; // the M0 line + devcb_write_line m_m1_cb; // the M1 line + devcb_write8 m_addr_cb; // Write to ADD1,2,4,8 - 4 address bits + devcb_read_line m_data_cb; // Read one bit from ADD8/Data - voice data + // On a real chip rom_clk is running all the time + // Here, we only use it to properly emulate the protocol. + // Do not rely on it to be a timed signal. + devcb_write_line m_romclk_cb; // rom clock - Only used to drive the data lines + + /* these contain data describing the current and previous voice frames */ +#define OLD_FRAME_SILENCE_FLAG m_OLDE // 1 if E=0, 0 otherwise. +#define OLD_FRAME_UNVOICED_FLAG m_OLDP // 1 if P=0 (unvoiced), 0 if voiced + UINT8 m_OLDE; + UINT8 m_OLDP; + +#define NEW_FRAME_STOP_FLAG (m_new_frame_energy_idx == 0xF) // 1 if this is a stop (Energy = 0xF) frame +#define NEW_FRAME_SILENCE_FLAG (m_new_frame_energy_idx == 0) // ditto as above +#define NEW_FRAME_UNVOICED_FLAG (m_new_frame_pitch_idx == 0) // ditto as above + UINT8 m_new_frame_energy_idx; + UINT8 m_new_frame_pitch_idx; + UINT8 m_new_frame_k_idx[10]; + + + /* these are all used to contain the current state of the sound generation */ +#ifndef PERFECT_INTERPOLATION_HACK + INT16 m_current_energy; + INT16 m_current_pitch; + INT16 m_current_k[10]; +#else + UINT8 m_old_frame_energy_idx; + UINT8 m_old_frame_pitch_idx; + UINT8 m_old_frame_k_idx[10]; + UINT8 m_old_zpar; + UINT8 m_old_uv_zpar; + + INT32 m_current_energy; + INT32 m_current_pitch; + INT32 m_current_k[10]; +#endif + + UINT16 m_previous_energy; /* needed for lattice filter to match patent */ + + UINT8 m_subcycle; /* contains the current subcycle for a given PC: 0 is A' (only used on SPKSLOW mode on 51xx), 1 is A, 2 is B */ + UINT8 m_subc_reload; /* contains 1 for normal speech, 0 when SPKSLOW is active */ + UINT8 m_PC; /* current parameter counter (what param is being interpolated), ranges from 0 to 12 */ + /* NOTE: the interpolation period counts 1,2,3,4,5,6,7,0 for divide by 8,8,8,4,4,2,2,1 */ + UINT8 m_IP; /* the current interpolation period */ + UINT8 m_inhibit; /* If 1, interpolation is inhibited until the DIV1 period */ + UINT8 m_uv_zpar; /* If 1, zero k5 thru k10 coefficients */ + UINT8 m_zpar; /* If 1, zero ALL parameters. */ + UINT8 m_pitch_zero; /* circuit 412; pitch is forced to zero under certain circumstances */ + UINT16 m_pitch_count; /* pitch counter; provides chirp rom address */ + + INT32 m_u[11]; + INT32 m_x[10]; + + UINT16 m_RNG; /* the random noise generator configuration is: 1 + x + x^3 + x^4 + x^13 TODO: no it isn't */ + INT16 m_excitation_data; + + /* The TMS51xx has two different ways of providing output data: the + analog speaker pins (which were usually used) and the Digital I/O pin. + The internal DAC used to feed the analog pins is only 8 bits, and has the + funny clipping/clamping logic, while the digital pin gives full 10 bit + resolution of the output data. + TODO: add a way to set/reset this other than the FORCE_DIGITAL define + */ + UINT8 m_digital_select; + + INT32 m_speech_rom_bitnum; + + UINT8 m_romclk_hack_timer_started; + UINT8 m_romclk_hack_state; + + emu_timer *m_romclk_hack_timer; + const UINT8 *m_table; +}; + +extern const device_type TMS5110; + +class tms5100_device : public tms5110_device +{ +public: + tms5100_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +protected: + // device-level overrides + virtual void device_start(); +}; + +extern const device_type TMS5100; + +class tmc0281_device : public tms5110_device +{ +public: + tmc0281_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +protected: + // device-level overrides + virtual void device_start(); +}; + +extern const device_type TMC0281; + +class tms5100a_device : public tms5110_device +{ +public: + tms5100a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +protected: + // device-level overrides + virtual void device_start(); +}; + +extern const device_type TMS5100A; + +class tmc0281d_device : public tms5110_device +{ +public: + tmc0281d_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +protected: + // device-level overrides + virtual void device_start(); +}; + +extern const device_type TMC0281D; + +class cd2801_device : public tms5110_device +{ +public: + cd2801_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +protected: + // device-level overrides + virtual void device_start(); +}; + +extern const device_type CD2801; + +class cd2802_device : public tms5110_device +{ +public: + cd2802_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +protected: + // device-level overrides + virtual void device_start(); +}; + +extern const device_type CD2802; + +class tms5110a_device : public tms5110_device +{ +public: + tms5110a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +protected: + // device-level overrides + virtual void device_start(); +}; + +extern const device_type TMS5110A; + +class m58817_device : public tms5110_device +{ +public: + m58817_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + DECLARE_READ8_MEMBER( status_r ); + +protected: + // device-level overrides + virtual void device_start(); +}; + +extern const device_type M58817; + + + +/* PROM controlled TMS5110 interface */ + +class tmsprom_device : public device_t +{ +public: + tmsprom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + static void set_region(device_t &device, const char *region) { downcast(device).m_prom_region = region; } + static void set_rom_size(device_t &device, UINT32 rom_size) { downcast(device).m_rom_size = rom_size; } + static void set_pdc_bit(device_t &device, UINT8 pdc_bit) { downcast(device).m_pdc_bit = pdc_bit; } + static void set_ctl1_bit(device_t &device, UINT8 ctl1_bit) { downcast(device).m_ctl1_bit = ctl1_bit; } + static void set_ctl2_bit(device_t &device, UINT8 ctl2_bit) { downcast(device).m_ctl2_bit = ctl2_bit; } + static void set_ctl4_bit(device_t &device, UINT8 ctl4_bit) { downcast(device).m_ctl4_bit = ctl4_bit; } + static void set_ctl8_bit(device_t &device, UINT8 ctl8_bit) { downcast(device).m_ctl8_bit = ctl8_bit; } + static void set_reset_bit(device_t &device, UINT8 reset_bit) { downcast(device).m_reset_bit = reset_bit; } + static void set_stop_bit(device_t &device, UINT8 stop_bit) { downcast(device).m_stop_bit = stop_bit; } + template static devcb_base &set_pdc_callback(device_t &device, _Object object) { return downcast(device).m_pdc_cb.set_callback(object); } + template static devcb_base &set_ctl_callback(device_t &device, _Object object) { return downcast(device).m_ctl_cb.set_callback(object); } + + DECLARE_WRITE_LINE_MEMBER( m0_w ); + DECLARE_READ_LINE_MEMBER( data_r ); + + /* offset is rom # */ + DECLARE_WRITE8_MEMBER( rom_csq_w ); + DECLARE_WRITE8_MEMBER( bit_w ); + DECLARE_WRITE_LINE_MEMBER( enable_w ); + +protected: + // device-level overrides + virtual void device_start(); + + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + +private: + void register_for_save_states(); + void update_prom_cnt(); + + // internal state + /* Rom interface */ + UINT32 m_address; + /* ctl lines */ + UINT8 m_m0; + UINT8 m_enable; + UINT32 m_base_address; + UINT8 m_bit; + + int m_prom_cnt; + + const char *m_prom_region; /* prom memory region - sound region is automatically assigned */ + UINT32 m_rom_size; /* individual rom_size */ + UINT8 m_pdc_bit; /* bit # of pdc line */ + /* virtual bit 8: constant 0, virtual bit 9:constant 1 */ + UINT8 m_ctl1_bit; /* bit # of ctl1 line */ + UINT8 m_ctl2_bit; /* bit # of ctl2 line */ + UINT8 m_ctl4_bit; /* bit # of ctl4 line */ + UINT8 m_ctl8_bit; /* bit # of ctl8 line */ + UINT8 m_reset_bit; /* bit # of rom reset */ + UINT8 m_stop_bit; /* bit # of stop */ + devcb_write_line m_pdc_cb; /* tms pdc func */ + devcb_write8 m_ctl_cb; /* tms ctl func */ + + emu_timer *m_romclk_timer; + const UINT8 *m_rom; + const UINT8 *m_prom; +}; + +extern const device_type TMSPROM; + +#define MCFG_TMSPROM_REGION(_region) \ + tmsprom_device::set_region(*device, _region); + +#define MCFG_TMSPROM_ROM_SIZE(_size) \ + tmsprom_device::set_rom_size(*device, _size); + +#define MCFG_TMSPROM_PDC_BIT(_bit) \ + tmsprom_device::set_pdc_bit(*device, _bit); + +#define MCFG_TMSPROM_CTL1_BIT(_bit) \ + tmsprom_device::set_ctl1_bit(*device, _bit); + +#define MCFG_TMSPROM_CTL2_BIT(_bit) \ + tmsprom_device::set_ctl2_bit(*device, _bit); + +#define MCFG_TMSPROM_CTL4_BIT(_bit) \ + tmsprom_device::set_ctl4_bit(*device, _bit); + +#define MCFG_TMSPROM_CTL8_BIT(_bit) \ + tmsprom_device::set_ctl8_bit(*device, _bit); + +#define MCFG_TMSPROM_RESET_BIT(_bit) \ + tmsprom_device::set_reset_bit(*device, _bit); + +#define MCFG_TMSPROM_STOP_BIT(_bit) \ + tmsprom_device::set_stop_bit(*device, _bit); + +#define MCFG_TMSPROM_PDC_CB(_devcb) \ + devcb = &tmsprom_device::set_pdc_callback(*device, DEVCB_##_devcb); + +#define MCFG_TMSPROM_CTL_CB(_devcb) \ + devcb = &tmsprom_device::set_ctl_callback(*device, DEVCB_##_devcb); + +#endif /* __TMS5110_H__ */ diff --git a/src/devices/sound/tms5110r.inc b/src/devices/sound/tms5110r.inc new file mode 100644 index 00000000000..7e370853db0 --- /dev/null +++ b/src/devices/sound/tms5110r.inc @@ -0,0 +1,705 @@ +// license:BSD-3-Clause +// copyright-holders:Frank Palazzolo, Couriersud, Jonathan Gevaryahu +/* TMS51xx and TMS52xx ROM Tables */ + +/* The following table is assumed to be for TMS5100 + * + * US Patent 4209836 + * 4331836 + * 4304964 + * 4234761 + * 4189779 + * 4449233 + * + * All patents give interpolation coefficients + * { 1, 8, 8, 8, 4, 4, 2, 2 } + * This sequence will not calculate the published + * fractions: + * 1 8 0.125 + * 2 8 0.234 + * 3 8 0.330 + * 4 4 0.498 + * 5 4 0.623 + * 6 2 0.717 + * 7 2 0.859 + * 0 1 1.000 + * (remember, 1 is the FIRST entry!) + * + * Instead, { 1, 8, 8, 8, 4, 4, 4, 2 } + * will calculate those coefficients. + * Howeever, after simulating the actual circuit from the patent in pspice, + * the { 1, 8, 8, 8, 4, 4, 2, 2 } pattern is revealed as the correct one. + * Since the real chip uses shifters and not true division to achieve those + * factors, they have been replaced by the shifting coefficients: + * { 0, 3, 3, 3, 2, 2, 1, 1 } + */ + + /* quick note on derivative analysis: + Judging by all the TI chips I (Lord Nightmare) have done this test on, the first derivative between successive values of the LPC tables should follow a roughly triangular or sine shaped curve, the second derivative should start at a value, increase slightly, then decrease smoothly and become negative right around where the LPC curve passes 0, finally increase slightly right near the end. If it doesn't do this, there is probably a wrong value in there somewhere. The pitch and energy tables follow similar patterns but aren't the same since they never cross 0. The chirp table doesn't follow this pattern at all. + */ + + /* Chip types based on die marks from decap: + chip type + |||||| rom number + |||||| ||||| + VVVVVV VVVVV + T0280A 0281 = 1978 speak & spell, unknown difference to below, assumed same? uses old chirp + T0280B 0281A = 1979 speak & spell, also == TMS5100, uses old chirp + ?????? ????? (no decap; likely 'T0280D 0281D') = 1980 speak & spell, 1981 speak & spell compact, changed energy table, otherwise same as above, uses old chirp + T0280F 2801A = 1980 speak & math, 1980 speak and read, uses old chirp + T0280F 2802 = touch and tell, language translator; uses a unique chirp rom. + ?????? ????? = TMS5110 + T0280F 5110A = TMS5110AN2L + + + */ + +/* chip rom contents defines */ +#define SUBTYPE_0281A 1 +#define SUBTYPE_0281D 2 +#define SUBTYPE_2801A 4 +#define SUBTYPE_M58817 8 +#define SUBTYPE_2802 16 +#define SUBTYPE_5110 32 +#define SUBTYPE_2501E 64 +#define SUBTYPE_5220 128 +#define SUBTYPE_PAT4335277 256 +#define SUBTYPE_VLM5030 512 + +/* coefficient defines */ +#define MAX_K 10 +#define MAX_SCALE_BITS 6 +#define MAX_SCALE (1<silent + transition. + * CD2801A-NL with datecodes around 1982 have the 'alternate behavior' + */ +static const struct tms5100_coeffs T0280F_2801A_coeff = +{ + /* subtype */ + SUBTYPE_2801A, + 10, + 4, + 5, + { 5, 5, 4, 4, 4, 4, 4, 3, 3, 3 }, + TI_028X_LATER_ENERGY + TI_0280_2801_PATENT_PITCH + { + TI_2801_2501E_LPC + }, + TI_2801_CHIRP + TI_INTERP +}; + +/* Mitsubishi M58817 +The Mitsubishi M58817 seems to have (partly?) copied the coefficients from the +TMC0280/CD2801 above, but has some slight differences to it within the chip: +the main accumulator seems to have 1 extra bit and the digital values are +tapped 1 bit higher than on the TI chips. This is emulated within tms5110.c + */ +static const struct tms5100_coeffs M58817_coeff = +{ + /* subtype */ + SUBTYPE_M58817, + 10, + 4, + 5, + { 5, 5, 4, 4, 4, 4, 4, 3, 3, 3 }, + TI_028X_LATER_ENERGY + TI_0280_2801_PATENT_PITCH + { + TI_2801_2501E_LPC + }, + TI_2801_CHIRP + TI_INTERP +}; + +/* CD2802: + (1984 era?) + Used in Touch and Tell only (and Vocaid?), this chip has a unique pitch, LPC and chirp table. + Has the 'alternate' interpolation behavior. + Digitally dumped via PROMOUT by PlgDavid in 2014 + Decapped by Sean Riddle in 2015 + */ +static const struct tms5100_coeffs T0280F_2802_coeff = +{ + /* subtype */ + SUBTYPE_2802, + 10, + 4, + 5, + { 5, 5, 4, 4, 4, 4, 4, 3, 3, 3 }, + TI_028X_LATER_ENERGY + TI_2802_PITCH + { + TI_2802_LPC + }, + TI_2802_CHIRP + TI_INTERP +}; + +/* TMS5110A: + (1984-90 era? early chips may be called TMS5110C; later chips past 1988 or so may be called TSP5110A) + The TMS5110A LPC coefficients were originally read from an actual TMS5110A + chip by Jarek Burczynski using the PROMOUT pin, later verified/redumped + by PlgDavid. + NullMoogleCable decapped a TMS5110AN2L in 2015: http://wtfmoogle.com/wp-content/uploads/2015/03/0317_1.jpg + which was used to verify the chirp table. + The slightly older but otherwise identical TMS5111NLL was decapped and imaged by digshadow in April, 2013. + The die is marked "TMS5110AJ" + The LPC table is verified from decap to match the values from Jarek and PlgDavid's PROMOUT dumps of the TMS5110. + The LPC table matches that of the TMS5220. + It uses the 'newer' 5200-style chirp table. + It has the 'alternate' interpolation behavor (tested on 5110a; 5111 behavior is unknown) +*/ +static const struct tms5100_coeffs tms5110a_coeff = +{ + /* subtype */ + SUBTYPE_5110, + 10, + 4, + 5, + { 5, 5, 4, 4, 4, 4, 4, 3, 3, 3 }, + TI_028X_LATER_ENERGY + TI_5110_PITCH + { + TI_5110_5220_LPC + }, + TI_LATER_CHIRP + TI_INTERP +}; + +/* The following coefficients come from US Patent 4,335,277 and 4,581,757. +However, the K10 row of coefficients are entirely missing from both of those +patents. +The K values don't match the values read from any of the TI chips so far, but +might match some other undiscovered chip? Or may be complete garbage put as a red +herring in the patent? +*/ + // k* is followed by d if done transcription, c if checked for derivative aberrations +static const struct tms5100_coeffs pat4335277_coeff = +{ + /* subtype */ + SUBTYPE_PAT4335277, + 10, + 4, + 6, + { 5, 5, 4, 4, 4, 4, 4, 3, 3, 3 }, + TI_028X_LATER_ENERGY + TI_2501E_PITCH + { + /* K1dc */ + { -507, -505, -503, -501, -497, -493, -488, -481, + -473, -463, -450, -434, -414, -390, -362, -328, + -288, -242, -191, -135, -75, -13, 49, 110, + 168, 221, 269, 311, 348, 379, 404, 426 }, + /* K2dc */ + { -294, -266, -235, -202, -167, -130, -92, -52, + -12, 28, 68, 108, 145, 182, 216, 248, + 278, 305, 330, 352, 372, 390, 406, 420, + 432, 443, 453, 461, 468, 474, 479, 486 }, + /* K3dc */ + { -449, -432, -411, -385, -354, -317, -273, -223, + -167, -107, -43, 22, 87, 148, 206, 258 }, + /* K4dc (first 4-5 values are probably wrong but close) */ + { -321, -270, -220, -157, -97, -40, 25, 89, + 150, 207, 259, 304, 343, 376, 403, 425 }, + /* K5dc */ + { -373, -347, -318, -284, -247, -206, -162, -115, + -65, -15, 36, 86, 135, 181, 224, 263 }, + /* K6dc */ + { -213, -176, -137, -96, -54, -11, 33, 75, + 117, 157, 195, 231, 264, 294, 322, 347 }, + /* K7dc */ + { -294, -264, -232, -198, -161, -122, -82, -41, + 1, 43, 84, 125, 163, 200, 234, 266 }, + /* K8dc */ + { -195, -117, -32, 54, 137, 213, 279, 335 }, + /* K9dc */ + { -122, -55, 15, 83, 149, 210, 264, 311 }, + /* K10 - this was entirely missing from the patent, and I've simply copied the real TMS5220 one, which is wrong */ + { -205, -132, -59, 14, 87, 160, 234, 307 }, + }, + TI_0280_PATENT_CHIRP + TI_INTERP +}; + +/* TMS5200/CD2501E + (1979-1983 era) +The TMS5200NL was decapped and imaged by digshadow in March, 2013. +It is equivalent to the CD2501E (internally: "TMC0285") chip used + on the TI 99/4(A) speech module. +The LPC table is verified to match the decap. + (It was previously dumped with PROMOUT which matches as well) +The chirp table is verified to match the decap. (sum = 0x3da) +Note that the K coefficients are VERY different from the coefficients given + in the US 4,335,277 patent, which may have been for some sort of prototype or + otherwise intentionally scrambled. The energy and pitch tables, however, are + identical to that patent. +Also note, that the K coefficients are identical to the coefficients from the + CD2801 (which itself is almost identical to the CD2802). +NOTE FROM DECAP: immediately to the left of each of the K1,2,3,4,5,and 6 + coefficients in the LPC rom are extra columns containing the constants + -510, -502, 313, 318, or in hex 0x202, 0x20A, 0x139, 0x13E. + Those EXACT constants DO appear (rather nonsensically) on the lpc table in US + patent 4,335,277. They are likely related to the multiplicative interpolator + described in us patent 4,419,540; whether the 5200/2501E and the 5220 or 5220C + actually implement this interpolator or not is unclear. This interpolator + seems intended for chips with variable frame rate, so it may only exist + on the TMS/TSP5220C and CD2501ECD. +*/ + +static const struct tms5100_coeffs T0285_2501E_coeff = +{ + /* subtype */ + SUBTYPE_2501E, + 10, + 4, + 6, + { 5, 5, 4, 4, 4, 4, 4, 3, 3, 3 }, + TI_028X_LATER_ENERGY + TI_2501E_PITCH + { + TI_2801_2501E_LPC + }, + TI_LATER_CHIRP + TI_INTERP +}; + +/* TMS5220/5220C: +(1983 era for 5220, 1986-1992 era for 5220C; 5220C may also be called TSP5220C) +The TMS5220NL was decapped and imaged by digshadow in April, 2013. +The LPC table table is verified to match the decap. +The chirp table is verified to match the decap. (sum = 0x3da) +Note that all the LPC K* values match the TMS5110a table (as read via PROMOUT) +exactly. +The TMS5220CNL was decapped and imaged by digshadow in April, 2013. +The LPC table table is verified to match the decap and exactly matches TMS5220NL. +The chirp table is verified to match the decap. (sum = 0x3da) +*/ +static const struct tms5100_coeffs tms5220_coeff = +{ + /* subtype */ + SUBTYPE_5220, + 10, + 4, + 6, + { 5, 5, 4, 4, 4, 4, 4, 3, 3, 3 }, + TI_028X_LATER_ENERGY + TI_5220_PITCH + { + TI_5110_5220_LPC + }, + TI_LATER_CHIRP + TI_INTERP +}; + +/* The following Sanyo VLM5030 coefficients are derived from decaps of the chip +done by ogoun, plus image stitching done by John McMaster. The organization of +coefficients beyond k2 is derived from work by Tatsuyuki Satoh. +The actual coefficient rom on the chip die has 5 groups of bits only: +Address | K1A | K1B | K2 | Energy | Pitch | +Decoder | K1A | K1B | K2 | Energy | Pitch | +K1A, K1B and K2 are 10 bits wide, 32 bits long each. +Energy and pitch are both 7 bits wide, 32 bits long each. +K1A holds odd values of K1, K1B holds even values. +K2 holds values for K2 only +K3 and K4 are actually the table index values <<6 +K5 thru K10 are actually the table index values <<7 +The concept of only having non-binary weighted reflection coefficients for the +first two k stages is mentioned in Markel & Gray "Linear Prediction of Speech" +and in Thomas Parsons' "Voice and Speech Processing" + */ +static const struct tms5100_coeffs vlm5030_coeff = +{ + /* subtype */ + SUBTYPE_VLM5030, + 10, + 5, + 5, + { 6, 5, 4, 4, 3, 3, 3, 3, 3, 3 }, + /* E */ + { 0, 1, 2, 3, 5, 6, 7, 9, + 11, 13, 15, 17, 19, 22, 24, 27, + 31, 34, 38, 42, 47, 51, 57, 62, + 68, 75, 82, 89, 98,107,116,127}, + /* P */ + { 0, 21, 22, 23, 24, 25, 26, 27, + 28, 29, 31, 33, 35, 37, 39, 41, + 43, 45, 49, 53, 57, 61, 65, 69, + 73, 77, 85, 93, 101, 109, 117, 125 }, + { + /* K1 */ + /* (NOTE: the order of each table is correct, despite that the index MSb + looks backwards) */ + { 390, 403, 414, 425, 434, 443, 450, 457, + 463, 469, 474, 478, 482, 485, 488, 491, + 494, 496, 498, 499, 501, 502, 503, 504, + 505, 506, 507, 507, 508, 508, 509, 509, + -390,-376,-360,-344,-325,-305,-284,-261, + -237,-211,-183,-155,-125, -95, -64, -32, + 0, 32, 64, 95, 125, 155, 183, 211, + 237, 261, 284, 305, 325, 344, 360, 376 }, + /* K2 */ + { 0, 50, 100, 149, 196, 241, 284, 325, + 362, 396, 426, 452, 473, 490, 502, 510, + 0,-510,-502,-490,-473,-452,-426,-396, /* entry 16(0x10) either has some special function, purpose unknown, or is a manufacturing error and should have been -512 */ + -362,-325,-284,-241,-196,-149,-100, -50 }, + /* K3 */ + /*{ 0, 100, 196, 284, 362, 426, 473, 502, + -510,-490,-452,-396,-325,-241,-149, -50 },*/ + { 0, 64, 128, 192, 256, 320, 384, 448, + -512,-448,-384,-320,-256,-192,-128, -64 }, + /* K4 */ + /*{ 0, 100, 196, 284, 362, 426, 473, 502, + -510,-490,-452,-396,-325,-241,-149, -50 },*/ + { 0, 64, 128, 192, 256, 320, 384, 448, + -512,-448,-384,-320,-256,-192,-128, -64 }, + /* K5 */ + { 0, 128, 256, 384,-512,-384,-256,-128 }, + /* K6 */ + { 0, 128, 256, 384,-512,-384,-256,-128 }, + /* K7 */ + { 0, 128, 256, 384,-512,-384,-256,-128 }, + /* K8 */ + { 0, 128, 256, 384,-512,-384,-256,-128 }, + /* K9 */ + { 0, 128, 256, 384,-512,-384,-256,-128 }, + /* K10 */ + /*{ 0, 196, 362, 473,-510,-452,-325,-149 },*/ + { 0, 128, 256, 384,-512,-384,-256,-128 }, + }, + /* Chirp table */ + { 0,127,127, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0 }, + /* interpolation coefficients */ + { 3, 3, 3, 2, 2, 1, 1, 0 } +}; diff --git a/src/devices/sound/tms5220.c b/src/devices/sound/tms5220.c new file mode 100644 index 00000000000..12b718c98c7 --- /dev/null +++ b/src/devices/sound/tms5220.c @@ -0,0 +1,1953 @@ +// license:BSD-3-Clause +// copyright-holders:Frank Palazzolo, Aaron Giles, Jonathan Gevaryahu, Raphael Nabet, Couriersud, Michael Zapf +/********************************************************************************************** + + TMS5200/5220 simulator + + Written for MAME by Frank Palazzolo + With help from Neill Corlett + Additional tweaking by Aaron Giles + TMS6100 Speech Rom support added by Raphael Nabet + PRNG code by Jarek Burczynski backported from tms5110.c by Lord Nightmare + Chirp/excitation table fixes by Lord Nightmare + Various fixes by Lord Nightmare + Modularization by Lord Nightmare + Sub-interpolation-cycle parameter updating added by Lord Nightmare + Preliminary MASSIVE merge of tms5110 and tms5220 cores by Lord Nightmare + Lattice Filter, Multiplier, and clipping redone by Lord Nightmare + TMS5220C multi-rate feature added by Lord Nightmare + Massive rewrite and reorganization by Lord Nightmare + Additional IP, PC, subcycle timing rewrite by Lord Nightmare + Updated based on the chip decaps done by digshadow + + Much information regarding the lpc encoding used here comes from US patent 4,209,844 + US patent 4,331,836 describes the complete 51xx chip + US patent 4,335,277 describes the complete 52xx chip + Special Thanks to Larry Brantingham for answering questions regarding the chip details + + TMS5200/TMS5220/TMS5220C/CD2501E/CD2501ECD: + + +-----------------+ + D7(d0) | 1 28 | /RS + ADD1 | 2 27 | /WS + ROMCLK | 3 26 | D6(d1) + VDD(-5) | 4 25 | ADD2 + VSS(+5) | 5 24 | D5(d2) + OSC | 6 23 | ADD4 + T11 | 7 22 | D4(d3) + SPKR | 8 21 | ADD8/DATA + I/O | 9 20 | TEST + PROMOUT | 10 19 | D3(d4) + VREF(GND)| 11 18 | /READY + D2(d5) | 12 17 | /INT + D1(d6) | 13 16 | M1 + D0(d7) | 14 15 | M0 + +-----------------+ +Note the standard naming for d* data bits with 7 as MSB and 0 as LSB is in lowercase. +TI's naming has D7 as LSB and D0 as MSB and is in uppercase + +TODO: + * Ever since the big rewrite, there are glitches on certain frame transitions + for example in the word 'rid' during the eprom attract mode, + I (LN) am not entirely sure why the real chip doesn't have these as well. + Needs more real hardware testing/dumps for comparison. + * Implement a ready callback for pc interfaces + - this will be quite a challenge since for it to be really accurate + the whole emulation has to run in sync (lots of timers) with the + cpu cores. + * If a command is still executing, /READY will be kept high until the command has + finished if the next command is written. + * tomcat has a 5220 which is not hooked up at all + +Pedantic detail from observation of real chip: +The 5200 and 5220 chips outputs the following coefficients over PROMOUT while +'idle' and not speaking, in this order: +e[0 or f] p[0] k1[0] k2[0] k3[0] k4[0] k5[f] k6[f] k7[f] k8[7] k9[7] k10[7] + +Patent notes (important timing info for interpolation): +* TCycle ranges from 1 to 20, is clocked based on the clock input or RC clock + to the chip / 4. This emulation core completely ignores TCycle, as it isn't + very relevant. + Every full TCycle count (i.e. overflow from 20 to 1), Subcycle is + incremented. +* Subcycle ranges from 0 to 2, reload is 0 in SPKSLOW mode, 1 normally, and + corresponds to whether an interpolation value is being calculated (0 or 1) + or being written to ram (2). 0 and 1 correspond to 'A' cycles on the + patent, while 2 corresponds to 'B' cycles. + Every Subcycle full count (i.e. overflow from 2 to (0 or 1)), PC is + incremented. (NOTE: if PC=12, overflow happens on the 1->2 transition, + not 2->0; PC=12 has no B cycle.) +* PC ranges from 0 to 12, and corresponds to the parameter being interpolated + or otherwise read from rom using PROMOUT. + The order is: + 0 = Energy + 1 = Pitch + 2 = K1 + 3 = K2 + ... + 11 = K10 + 12 = nothing + Every PC full count (i.e. overflow from 12 to 0), IP (aka "Interpolation Period") + is incremented. +* IP (aka "Interpolation Period") ranges from 0 to 7, and corresponds with the amount + of rightshift that the difference between current and target for a given + parameter will have applied to it, before being added to the current + parameter. Note that when interpolation is inhibited, only IP=0 will + cause any change to the current values of the coefficients. + The order is, after new frame parse (last ip was 0 before parse): + 1 = >>3 (/8) + 2 = >>3 (/8) + 3 = >>3 (/8) + 4 = >>2 (/4) + 5 = >>2 (/4) + 6 = >>1 (/2) (NOTE: the patent has an error regarding this value on one table implying it should be /4, but circuit simulation of parts of the patent shows that the /2 value is correct.) + 7 = >>1 (/2) + 0 = >>0 (/1, forcing current values to equal target values) + Every IP full count, a new frame is parsed, but ONLY on the 0->* + transition. + NOTE: on TMS5220C ONLY, the datasheet IMPLIES the following: + Upon new frame parse (end of IP=0), the IP is forced to a value depending + on the TMS5220C-specific rate setting. For rate settings 0, 1, 2, 3, it + will be forced to 1, 3, 5 or 7 respectively. On non-TMS5220 chips, it + counts as expected (IP=1 follows IP=0) always. + This means, the tms5220c with rates set to n counts IP as follows: + (new frame parse is indicated with a #) + Rate IP Count + 00 7 0#1 2 3 4 5 6 7 0#1 2 3 4 5 6 7 <- non-tms5220c chips always follow this pattern + 01 7 0#3 4 5 6 7 0#3 4 5 6 7 0#3 4 5 + 10 7 0#5 6 7 0#5 6 7 0#5 6 7 0#5 6 7 + 11 7 0#7 0#7 0#7 0#7 0#7 0#7 0#7 0#7 + Based on the behavior tested on the CD2501ECD this is assumed to be the same for that chip as well. + +Most of the following is based on figure 8c of 4,331,836, which is the + TMS5100/TMC0280 patent, but the same information applies to the TMS52xx + as well. + +OLDP is a status flag which controls whether unvoiced or voiced excitation is + being generated. It is latched from "P=0" at IP=7 PC=12 T=16. + (This means that, during normal operation, between IP=7 PC=12 T16 and + IP=0 PC=1 T17, OLDP and P=0 are the same) +"P=0" is a status flag which is set if the index value for pitch for the new + frame being parsed (which will become the new target frame) is zero. + It is used for determining whether interpolation of the next frame is + inhibited or not. It is updated at IP=0 PC=1 T17. See next section. +OLDE is a status flag which is only used for determining whether + interpolation is inhibited or not. + It is latched from "E=0" at IP=7 PC=12 T=16. + (This means that, during normal operation, between IP=7 PC=12 T16 and + IP=0 PC=0 T17, OLDE and E=0 are the same) +"E=0" is a status flag which is set if the index value for energy for the new + frame being parsed (which will become the new target frame) is zero. + It is used for determining whether interpolation of the next frame is + inhibited or not. It is updated at IP=0 PC=0 T17. See next section. + +Interpolation is inhibited (i.e. interpolation at IP frames will not happen + except for IP=0) under the following circumstances: + "P=0" != "OLDP" ("P=0" = 1, and OLDP = 0; OR "P=0" = 0, and OLDP = 1) + This means the new frame is unvoiced and the old one was voiced, or vice + versa. +* TODO the 5100 and 5200 patents are inconsistent about the above. Trace the decaps! + "OLDE" = 1 and "E=0" = 0 + This means the new frame is not silent, and the old frame was silent. + + + +****Documentation of chip commands:*** + x0x0xbcc : on 5200/5220: NOP (does nothing); on 5220C and CD2501ECD: Select frame length by cc, and b selects whether every frame is preceded by 2 bits to select the frame length (instead of using the value set by cc); the default (and after a reset command) is as if '0x00' was written, i.e. for frame length (200 samples) and 0 for whether the preceding 2 bits are enabled (off) + + x001xxxx: READ BYTE (RDBY) Sends eight read bit commands (M0 high M1 low) to VSM and reads the resulting bits serially into a temporary register, which becomes readable as the next byte read from the tms52xx once ready goes active. Note the bit order of the byte read from the TMS52xx is BACKWARDS as compared to the actual data order as in the rom on the VSM chips; the read byte command of the tms5100 reads the bits in the 'correct' order. This was IMHO a rather silly design decision of TI. (I (LN) asked Larry Brantingham about this but he wasn't involved with the TMS52xx chips, just the 5100); There's ASCII data in the TI 99/4 speech module VSMs which has the bit order reversed on purpose because of this! + TALK STATUS must be CLEAR for this command to work; otherwise it is treated as a NOP. + + x011xxxx: READ AND BRANCH (RB) Sends a read and branch command (M0 high, M1 high) to force VSM to set its data pointer to whatever the data is at its current pointer location is) + TALK STATUS must be CLEAR for this command to work; otherwise it is treated as a NOP. + + x100aaaa: LOAD ADDRESS (LA) Send a load address command (M0 low M1 high) to VSM with the 4 'a' bits; Note you need to send four or five of these in sequence to actually specify an address to the vsm. + TALK STATUS must be CLEAR for this command to work; otherwise it is treated as a NOP. + + x101xxxx: SPEAK (SPK) Begins speaking, pulling spech data from the current address pointer location of the VSM modules. + + x110xxxx: SPEAK EXTERNAL (SPKEXT) Clears the FIFO using SPKEE line, then sets TALKD (TALKST remains zero) until 8 bytes have been written to the FIFO, at which point it begins speaking, pulling data from the 16 byte fifo. + The patent implies TALK STATUS must be CLEAR for this command to work; otherwise it is treated as a NOP, but the decap shows that this is not true, and is an error on the patent diagram. + + x111xxxx: RESET (RST) Resets the speech synthesis core immediately, and clears the FIFO. + + + Other chip differences: + The 5220C (and CD2501ECD maybe?) are quieter due to a better dac arrangement on die which allows less crossover between bits, based on the decap differences. + + +***MAME Driver specific notes:*** + + Victory's initial audio selftest is pretty brutal to the FIFO: it sends a + sequence of bytes to the FIFO and checks the status bits after each one; if + even one bit is in the wrong state (i.e. speech starts one byte too early or + late), the test fails! + The sample in Victory 'Shields up!' after you activate shields, the 'up' part + of the sample is missing the STOP frame at the end of it; this causes the + speech core to run out of bits to parse from the FIFO, cutting the sample off + by one frame. This appears to be an original game code bug. + +Progress list for drivers using old vs new interface: +starwars: uses new interface (couriersud) +gauntlet: uses new interface (couriersud) +atarisy1: uses new interface (Lord Nightmare) +atarisy2: uses new interface (Lord Nightmare) +atarijsa: uses new interface (Lord Nightmare) +firefox: uses new interface (couriersud) +mhavoc: uses old interface, and is in the machine file instead of the driver. +monymony/jackrabt(zaccaria.c): uses new interface (couriersud) +victory(audio/exidy.c): uses new interface (couriersud) +looping: uses old interface +portraits: uses *NO* interface; the i/o cpu hasn't been hooked to anything! +dotron and midwayfb(mcr.c): uses old interface + + +As for which games used which chips: + +TMS5200 AKA TMC0285 AKA CD2501E: (1980 to 1983) + Arcade: Zaccaria's 'money money' and 'jack rabbit'; Bally/Midway's +'Discs of Tron' (all environmental cabs and a few upright cabs; the code +exists on all versions for the speech though, and upright cabs can be +upgraded to add it by hacking on a 'Squawk & Talk' pinball speech board +(which is also TMS5200 based) with a few modded components) + Pinball: All Bally/Midway machines which uses the 'Squawk & Talk' board. + Home computer: TI 99/4 PHP1500 Speech module (along with two VSM +serial chips); Street Electronics Corp.'s Apple II 'Echo 2' Speech +synthesizer (early cards only) + +CD2501ECD: (1983) + Home computer: TI 99/8 (prototypes only) + +TMS5220: (mostly on things made between 1981 and 1984-1985) + Arcade: Bally/Midway's 'NFL Football'; Atari's 'Star Wars', +'Firefox', 'Return of the Jedi', 'Road Runner', 'The Empire Strikes +Back' (all verified with schematics); Venture Line's 'Looping' and 'Sky +Bumper' (need verify for both); Olympia's 'Portraits' (need verify); +Exidy's 'Victory' and 'Victor Banana' (need verify for both) + Pinball: Several (don't know names offhand, have not checked schematics; likely Zaccaria's 'Farfalla') + Home computer: Street Electronics Corp.'s Apple II 'Echo 2' Speech +synthesizer (later cards only); Texas Instruments' 'Speak and Learn' +scanner wand unit. + +TMS5220C AKA TSP5220C: (on stuff made from 1984 to 1992 or so) + Arcade: Atari's 'Indiana Jones and the Temple of Doom', '720', +'Gauntlet', 'Gauntlet II', 'A.P.B.', 'Paperboy', 'RoadBlasters', +'Vindicators Pt II'(verify?), and 'Escape from the Planet of the Robot +Monsters' (all verified except for vindicators pt 2) + Pinball: Several (less common than the tms5220? (not sure about +this), mostly on later pinballs with LPC speech) + Home computer: Street Electronics Corp.'s 'ECHO' parallel/hobbyist +module (6511 based), IBM PS/2 Speech adapter (parallel port connection +device), PES Speech adapter (serial port connection) + +Street electronics had a later 1989-era ECHO appleII card which is TSP50c0x/1x +MCU based speech and not tms5xxx based (though it is likely emulating the tms5220 +in MCU code). Look for a 16-pin chip at U6 labeled "ECHO-3 SN". + +***********************************************************************************************/ + +#include "emu.h" +#include "tms5220.h" + +static INT16 clip_analog(INT16 cliptemp); + +/* *****optional defines***** */ + +/* Hacky improvements which don't match patent: */ +/* Interpolation shift logic: + * One of the following two lines should be used, and the other commented + * The second line is more accurate mathematically but not accurate to the patent + */ +#define INTERP_SHIFT >> m_coeff->interp_coeff[m_IP] +//define INTERP_SHIFT / (1<interp_coeff[m_IP]) + +/* Other hacks */ +/* HACK: if defined, outputs the low 4 bits of the lattice filter to the i/o + * or clip logic, even though the real hardware doesn't do this, partially verified by decap */ +#undef ALLOW_4_LSB + +/* forces m_TALK active instantly whenever m_SPEN would be activated, causing speech delay to be reduced by up to one frame time */ +/* for some reason, this hack makes victory behave better, though it does not match the patent */ +#define FAST_START_HACK 1 + + +/* *****configuration of chip connection stuff***** */ +/* must be defined; if 0, output the waveform as if it was tapped on the speaker pin as usual, if 1, output the waveform as if it was tapped on the i/o pin (volume is much lower in the latter case) */ +#define FORCE_DIGITAL 0 + +/* must be defined; if 1, normal speech (one A cycle, one B cycle per interpolation step); if 0; speak as if SPKSLOW was used (two A cycles, one B cycle per interpolation step) */ +#define FORCE_SUBC_RELOAD 1 + + +/* *****debugging defines***** */ +#undef VERBOSE +// above is general, somewhat obsolete, catch all for debugs which don't fit elsewhere +#undef DEBUG_DUMP_INPUT_DATA +// above dumps the data input to the tms52xx to stdout, useful for making logged data dumps for real hardware tests +#undef DEBUG_FIFO +// above debugs fifo stuff: writes, reads and flag updates +#undef DEBUG_PARSE_FRAME_DUMP +// above dumps each frame to stderr: be sure to select one of the options below if you define it! +#undef DEBUG_PARSE_FRAME_DUMP_BIN +// dumps each speech frame as binary +#undef DEBUG_PARSE_FRAME_DUMP_HEX +// dumps each speech frame as hex +#undef DEBUG_FRAME_ERRORS +// above dumps info if a frame ran out of data +#undef DEBUG_COMMAND_DUMP +// above dumps all non-speech-data command writes +#undef DEBUG_PIN_READS +// above spams the errorlog with i/o ready messages whenever the ready or irq pin is read +#undef DEBUG_GENERATION +// above dumps debug information related to the sample generation loop, i.e. whether interpolation is inhibited or not, and what the current and target values for each frame are. +#undef DEBUG_GENERATION_VERBOSE +// above dumps MUCH MORE debug information related to the sample generation loop, namely the excitation, energy, pitch, k*, and output values for EVERY SINGLE SAMPLE during a frame. +#undef DEBUG_LATTICE +// above dumps the lattice filter state data each sample. +#undef DEBUG_CLIP +// above dumps info to stderr whenever the analog clip hardware is (or would be) clipping the signal. +#undef DEBUG_IO_READY +// above debugs the io ready callback +#undef DEBUG_RS_WS +// above debugs the tms5220_data_r and data_w access methods which actually respect rs and ws + +#define MAX_SAMPLE_CHUNK 512 + +/* Variants */ + +#define TMS5220_IS_5220C (4) +#define TMS5220_IS_5200 (5) +#define TMS5220_IS_5220 (6) +#define TMS5220_IS_CD2501ECD (7) + +#define TMS5220_IS_CD2501E TMS5220_IS_5200 + +#define TMS5220_HAS_RATE_CONTROL ((m_variant == TMS5220_IS_5220C) || (m_variant == TMS5220_IS_CD2501ECD)) +#define TMS5220_IS_52xx ((m_variant == TMS5220_IS_5220C) || (m_variant == TMS5220_IS_5200) || (m_variant == TMS5220_IS_5220) || (m_variant == TMS5220_IS_CD2501ECD)) + +static const UINT8 reload_table[4] = { 0, 2, 4, 6 }; //sample count reload for 5220c and cd2501ecd only; 5200 and 5220 always reload with 0; keep in mind this is loaded on IP=0 PC=12 subcycle=1 so it immediately will increment after one sample, effectively being 1,3,5,7 as in the comments above. + +// Pull in the ROM tables +#include "tms5110r.inc" + + +void tms5220_device::set_variant(int variant) +{ + switch (variant) + { + case TMS5220_IS_5200: + case TMS5220_IS_CD2501ECD: + m_coeff = &T0285_2501E_coeff; + break; + case TMS5220_IS_5220C: + case TMS5220_IS_5220: + m_coeff = &tms5220_coeff; + break; + default: + fatalerror("Unknown variant in tms5220_set_variant\n"); + } + m_variant = variant; +} + + +void tms5220_device::register_for_save_states() +{ + save_item(NAME(m_variant)); + + save_item(NAME(m_fifo)); + save_item(NAME(m_fifo_head)); + save_item(NAME(m_fifo_tail)); + save_item(NAME(m_fifo_count)); + save_item(NAME(m_fifo_bits_taken)); + + save_item(NAME(m_previous_TALK_STATUS)); + save_item(NAME(m_SPEN)); + save_item(NAME(m_DDIS)); + save_item(NAME(m_TALK)); + save_item(NAME(m_TALKD)); + save_item(NAME(m_buffer_low)); + save_item(NAME(m_buffer_empty)); + save_item(NAME(m_irq_pin)); + save_item(NAME(m_ready_pin)); + + save_item(NAME(m_OLDE)); + save_item(NAME(m_OLDP)); + + save_item(NAME(m_new_frame_energy_idx)); + save_item(NAME(m_new_frame_pitch_idx)); + save_item(NAME(m_new_frame_k_idx)); +#ifdef PERFECT_INTERPOLATION_HACK + save_item(NAME(m_old_frame_energy_idx)); + save_item(NAME(m_old_frame_pitch_idx)); + save_item(NAME(m_old_frame_k_idx)); +#endif + save_item(NAME(m_current_energy)); + save_item(NAME(m_current_pitch)); + save_item(NAME(m_current_k)); + + save_item(NAME(m_previous_energy)); + + save_item(NAME(m_subcycle)); + save_item(NAME(m_subc_reload)); + save_item(NAME(m_PC)); + save_item(NAME(m_IP)); + save_item(NAME(m_inhibit)); + save_item(NAME(m_uv_zpar)); + save_item(NAME(m_zpar)); + save_item(NAME(m_pitch_zero)); + save_item(NAME(m_c_variant_rate)); + save_item(NAME(m_pitch_count)); + + save_item(NAME(m_u)); + save_item(NAME(m_x)); + + save_item(NAME(m_RNG)); + save_item(NAME(m_excitation_data)); + + save_item(NAME(m_schedule_dummy_read)); + save_item(NAME(m_data_register)); + save_item(NAME(m_RDB_flag)); + save_item(NAME(m_digital_select)); + + save_item(NAME(m_io_ready)); + + save_item(NAME(m_true_timing)); + + save_item(NAME(m_rs_ws)); + save_item(NAME(m_read_latch)); + save_item(NAME(m_write_latch)); +} + + +/********************************************************************************************** + + printbits helper function: takes a long int input and prints the resulting bits to stderr + +***********************************************************************************************/ + +#ifdef DEBUG_PARSE_FRAME_DUMP_BIN +static void printbits(long data, int num) +{ + int i; + for (i=(num-1); i>=0; i--) + fprintf(stderr,"%0ld", (data>>i)&1); +} +#endif +#ifdef DEBUG_PARSE_FRAME_DUMP_HEX +static void printbits(long data, int num) +{ + switch((num-1)&0xFC) + { + case 0: + fprintf(stderr,"%0lx", data); + break; + case 4: + fprintf(stderr,"%02lx", data); + break; + case 8: + fprintf(stderr,"%03lx", data); + break; + case 12: + fprintf(stderr,"%04lx", data); + break; + default: + fprintf(stderr,"%04lx", data); + break; + } +} +#endif + +/********************************************************************************************** + + tms5220_data_write -- handle a write to the TMS5220 + +***********************************************************************************************/ + +void tms5220_device::data_write(int data) +{ + int old_buffer_low = m_buffer_low; +#ifdef DEBUG_DUMP_INPUT_DATA + fprintf(stdout, "%c",data); +#endif + if (m_DDIS) // If we're in speak external mode + { + // add this byte to the FIFO + if (m_fifo_count < FIFO_SIZE) + { + m_fifo[m_fifo_tail] = data; + m_fifo_tail = (m_fifo_tail + 1) % FIFO_SIZE; + m_fifo_count++; +#ifdef DEBUG_FIFO + fprintf(stderr,"data_write: Added byte to FIFO (current count=%2d)\n", m_fifo_count); +#endif + update_fifo_status_and_ints(); + // if we just unset buffer low with that last write, and SPEN *was* zero (see circuit 251, sheet 12) + if ((m_SPEN == 0) && ((old_buffer_low == 1) && (m_buffer_low == 0))) // MUST HAVE EDGE DETECT + { + int i; +#ifdef DEBUG_FIFO + fprintf(stderr,"data_write triggered SPEN to go active!\n"); +#endif + // ...then we now have enough bytes to start talking; set zpar and clear out the new frame parameters (it will become old frame just before the first call to parse_frame() ) + m_zpar = 1; + m_uv_zpar = 1; // zero k4-k10 as well + m_OLDE = 1; // 'silence/zpar' frames are zero energy + m_OLDP = 1; // 'silence/zpar' frames are zero pitch +#ifdef PERFECT_INTERPOLATION_HACK + m_old_zpar = 1; // zero all the old parameters + m_old_uv_zpar = 1; // zero old k4-k10 as well +#endif + m_SPEN = 1; +#ifdef FAST_START_HACK + m_TALK = 1; +#endif + m_new_frame_energy_idx = 0; + m_new_frame_pitch_idx = 0; + for (i = 0; i < 4; i++) + m_new_frame_k_idx[i] = 0; + for (i = 4; i < 7; i++) + m_new_frame_k_idx[i] = 0xF; + for (i = 7; i < m_coeff->num_k; i++) + m_new_frame_k_idx[i] = 0x7; + + } + } + else + { +#ifdef DEBUG_FIFO + fprintf(stderr,"data_write: Ran out of room in the tms52xx FIFO! this should never happen!\n"); + // at this point, /READY should remain HIGH/inactive until the fifo has at least one byte open in it. +#endif + } + + + } + else //(! m_DDIS) + // R Nabet : we parse commands at once. It is necessary for such commands as read. + process_command(data); +} + +/********************************************************************************************** + + update_fifo_status_and_ints -- check to see if the various flags should be on or off + Description of flags, and their position in the status register: + From the data sheet: + bit D0(bit 7) = TS - Talk Status is active (high) when the VSP is processing speech data. + Talk Status goes active at the initiation of a Speak command or after nine + bytes of data are loaded into the FIFO following a Speak External command. It + goes inactive (low) when the stop code (Energy=1111) is processed, or + immediately by a buffer empty condition or a reset command. + bit D1(bit 6) = BL - Buffer Low is active (high) when the FIFO buffer is more than half empty. + Buffer Low is set when the "Last-In" byte is shifted down past the half-full + boundary of the stack. Buffer Low is cleared when data is loaded to the stack + so that the "Last-In" byte lies above the half-full boundary and becomes the + eighth data byte of the stack. + bit D2(bit 5) = BE - Buffer Empty is active (high) when the FIFO buffer has run out of data + while executing a Speak External command. Buffer Empty is set when the last bit + of the "Last-In" byte is shifted out to the Synthesis Section. This causes + Talk Status to be cleared. Speech is terminated at some abnormal point and the + Speak External command execution is terminated. + +***********************************************************************************************/ + +void tms5220_device::update_fifo_status_and_ints() +{ + /* update 52xx fifo flags and set ints if needed */ + if (!TMS5220_IS_52xx) return; // bail out if not a 52xx chip + update_ready_state(); + + /* BL is set if neither byte 9 nor 8 of the fifo are in use; this + translates to having fifo_count (which ranges from 0 bytes in use to 16 + bytes used) being less than or equal to 8. Victory/Victorba depends on this. */ + if (m_fifo_count <= 8) + { + // generate an interrupt if necessary; if /BL was inactive and is now active, set int. + if (!m_buffer_low) + set_interrupt_state(1); + m_buffer_low = 1; + } + else + m_buffer_low = 0; + + /* BE is set if neither byte 15 nor 14 of the fifo are in use; this + translates to having fifo_count equal to exactly 0 + */ + if (m_fifo_count == 0) + { + // generate an interrupt if necessary; if /BE was inactive and is now active, set int. + if (!m_buffer_empty) + set_interrupt_state(1); + m_buffer_empty = 1; + m_TALK = m_SPEN = 0; // /BE being active clears the TALK(TCON) status which in turn clears SPEN + } + else + m_buffer_empty = 0; + + // generate an interrupt if /TS was active, and is now inactive. + // also, in this case, regardless if DDIS was set, unset it. + if (m_previous_TALK_STATUS == 1 && (TALK_STATUS == 0)) + { +#ifdef VERBOSE + fprintf(stderr,"Talk status WAS 1, is now 0, unsetting DDIS and firing an interrupt!\n"); +#endif + set_interrupt_state(1); + m_DDIS = 0; + } + m_previous_TALK_STATUS = TALK_STATUS; + +} + +/********************************************************************************************** + + extract_bits -- extract a specific number of bits from the current input stream (FIFO or VSM) + +***********************************************************************************************/ + +int tms5220_device::extract_bits(int count) +{ + int val = 0; + + if (m_DDIS) + { + // extract from FIFO + while (count--) + { + val = (val << 1) | ((m_fifo[m_fifo_head] >> m_fifo_bits_taken) & 1); + m_fifo_bits_taken++; + if (m_fifo_bits_taken >= 8) + { + m_fifo_count--; + m_fifo[m_fifo_head] = 0; // zero the newly depleted fifo head byte + m_fifo_head = (m_fifo_head + 1) % FIFO_SIZE; + m_fifo_bits_taken = 0; + update_fifo_status_and_ints(); + } + } + } + else + { + // extract from VSM (speech ROM) + if (m_speechrom) + val = m_speechrom->read(count); + } + return val; +} + +/********************************************************************************************** + + tms5220_status_read -- read status or data from the TMS5220 + +***********************************************************************************************/ + +int tms5220_device::status_read() +{ + if (m_RDB_flag) + { /* if last command was read, return data register */ + m_RDB_flag = FALSE; + return(m_data_register); + } + else + { /* read status */ + /* clear the interrupt pin on status read */ + set_interrupt_state(0); +#ifdef DEBUG_PIN_READS + fprintf(stderr,"Status read: TS=%d BL=%d BE=%d\n", TALK_STATUS, m_buffer_low, m_buffer_empty); +#endif + return (TALK_STATUS << 7) | (m_buffer_low << 6) | (m_buffer_empty << 5); + } +} + + +/********************************************************************************************** + + tms5220_ready_read -- returns the ready state of the TMS5220 + +***********************************************************************************************/ + +int tms5220_device::ready_read() +{ +#ifdef DEBUG_PIN_READS + fprintf(stderr,"ready_read: ready pin read, io_ready is %d, fifo count is %d, DDIS(speak external) is %d\n", m_io_ready, m_fifo_count, m_DDIS); +#endif + return ((m_fifo_count < FIFO_SIZE)||(!m_DDIS)) && m_io_ready; +} + + +/********************************************************************************************** + + tms5220_cycles_to_ready -- returns the number of cycles until ready is asserted + NOTE: this function is deprecated and is known to be VERY inaccurate. + Use at your own peril! + +***********************************************************************************************/ + +int tms5220_device::cycles_to_ready() +{ + int answer; + + + if (ready_read()) + answer = 0; + else + { + int val; + int samples_per_frame = m_subc_reload?200:304; // either (13 A cycles + 12 B cycles) * 8 interps for normal SPEAK/SPKEXT, or (13*2 A cycles + 12 B cycles) * 8 interps for SPKSLOW + int current_sample = ((m_PC*(3-m_subc_reload))+((m_subc_reload?38:25)*m_IP)); + answer = samples_per_frame-current_sample+8; + + // total number of bits available in current byte is (8 - m_fifo_bits_taken) + // if more than 4 are available, we need to check the energy + if (m_fifo_bits_taken < 4) + { + // read energy + val = (m_fifo[m_fifo_head] >> m_fifo_bits_taken) & 0xf; + if (val == 0) + /* 0 -> silence frame: we will only read 4 bits, and we will + * therefore need to read another frame before the FIFO is not + * full any more */ + answer += m_subc_reload?200:304; + /* 15 -> stop frame, we will only read 4 bits, but the FIFO will + * we cleared; otherwise, we need to parse the repeat flag (1 bit) + * and the pitch (6 bits), so everything will be OK. */ + } + } + + return answer; +} + + +/********************************************************************************************** + + tms5220_int_read -- returns the interrupt state of the TMS5220 + +***********************************************************************************************/ + +int tms5220_device::int_read() +{ +#ifdef DEBUG_PIN_READS + fprintf(stderr,"int_read: irq pin read, state is %d\n", m_irq_pin); +#endif + return m_irq_pin; +} + + +/********************************************************************************************** + + tms5220_process -- fill the buffer with a specific number of samples + +***********************************************************************************************/ + +void tms5220_device::process(INT16 *buffer, unsigned int size) +{ + int buf_count=0; + int i, bitout; + INT32 this_sample; + +#ifdef VERBOSE + fprintf(stderr,"process called with size of %d; IP=%d, PC=%d, subcycle=%d, m_SPEN=%d, m_TALK=%d, m_TALKD=%d\n", size, m_IP, m_PC, m_subcycle, m_SPEN, m_TALK, m_TALKD); +#endif + + /* loop until the buffer is full or we've stopped speaking */ + while (size > 0) + { + if(m_TALKD) // speaking + { + /* if we're ready for a new frame to be applied, i.e. when IP=0, PC=12, Sub=1 + * (In reality, the frame was really loaded incrementally during the entire IP=0 + * PC=x time period, but it doesn't affect anything until IP=0 PC=12 happens) + */ + if ((m_IP == 0) && (m_PC == 12) && (m_subcycle == 1)) + { + // HACK for regression testing, be sure to comment out before release! + //m_RNG = 0x1234; + // end HACK + + /* appropriately override the interp count if needed; this will be incremented after the frame parse! */ + m_IP = reload_table[m_c_variant_rate&0x3]; + +#ifdef PERFECT_INTERPOLATION_HACK + /* remember previous frame energy, pitch, and coefficients */ + m_old_frame_energy_idx = m_new_frame_energy_idx; + m_old_frame_pitch_idx = m_new_frame_pitch_idx; + for (i = 0; i < m_coeff->num_k; i++) + m_old_frame_k_idx[i] = m_new_frame_k_idx[i]; +#endif + + /* Parse a new frame into the new_target_energy, new_target_pitch and new_target_k[] */ + parse_frame(); + + // if the new frame is unvoiced (or silenced via ZPAR), be sure to zero out the k5-k10 parameters + // NOTE: this is probably the bug the tms5100/tmc0280 has, pre-rev D, I think. + // GUESS: Pre-rev D versions start zeroing k5-k10 immediately upon new frame load regardless of interpolation inhibit + // I.e. ZPAR = /TALKD || (PC>5&&P=0) + // GUESS: D and later versions only start or stop zeroing k5-k10 at the IP7->IP0 transition AFTER the frame + // I.e. ZPAR = /TALKD || (PC>5&&OLDP) +#ifdef PERFECT_INTERPOLATION_HACK + m_old_uv_zpar = m_uv_zpar; + m_old_zpar = m_zpar; // unset old zpar on new frame +#endif + m_zpar = 0; + //m_uv_zpar = (OLD_FRAME_UNVOICED_FLAG||m_zpar); // GUESS: fixed version in tmc0280d/tms5100a/cd280x/tms5110 + m_uv_zpar = (NEW_FRAME_UNVOICED_FLAG||m_zpar); // GUESS: buggy version in tmc0280/tms5100 + + /* if the new frame is a stop frame, unset both TALK and SPEN (via TCON). TALKD remains active while the energy is ramping to 0. */ + if (NEW_FRAME_STOP_FLAG == 1) + { + m_TALK = m_SPEN = 0; + } + + /* in all cases where interpolation would be inhibited, set the inhibit flag; otherwise clear it. + Interpolation inhibit cases: + * Old frame was voiced, new is unvoiced + * Old frame was silence/zero energy, new has nonzero energy + * Old frame was unvoiced, new is voiced + * Old frame was unvoiced, new frame is silence/zero energy (unique to tms52xx) + */ + if ( ((OLD_FRAME_UNVOICED_FLAG == 0) && (NEW_FRAME_UNVOICED_FLAG == 1)) + || ((OLD_FRAME_UNVOICED_FLAG == 1) && (NEW_FRAME_UNVOICED_FLAG == 0)) + || ((OLD_FRAME_SILENCE_FLAG == 1) && (NEW_FRAME_SILENCE_FLAG == 0)) + || ((OLD_FRAME_UNVOICED_FLAG == 1) && (NEW_FRAME_SILENCE_FLAG == 1)) ) + m_inhibit = 1; + else // normal frame, normal interpolation + m_inhibit = 0; + +#ifdef DEBUG_GENERATION + /* Debug info for current parsed frame */ + fprintf(stderr, "OLDE: %d; OLDP: %d; ", m_OLDE, m_OLDP); + fprintf(stderr,"Processing new frame: "); + if (m_inhibit == 0) + fprintf(stderr, "Normal Frame\n"); + else + fprintf(stderr,"Interpolation Inhibited\n"); + fprintf(stderr,"*** current Energy, Pitch and Ks = %04d, %04d, %04d, %04d, %04d, %04d, %04d, %04d, %04d, %04d, %04d, %04d\n",m_current_energy, m_current_pitch, m_current_k[0], m_current_k[1], m_current_k[2], m_current_k[3], m_current_k[4], m_current_k[5], m_current_k[6], m_current_k[7], m_current_k[8], m_current_k[9]); + fprintf(stderr,"*** target Energy(idx), Pitch, and Ks = %04d(%x),%04d, %04d, %04d, %04d, %04d, %04d, %04d, %04d, %04d, %04d, %04d\n", + (m_coeff->energytable[m_new_frame_energy_idx] * (1-m_zpar)), + m_new_frame_energy_idx, + (m_coeff->pitchtable[m_new_frame_pitch_idx] * (1-m_zpar)), + (m_coeff->ktable[0][m_new_frame_k_idx[0]] * (1-m_zpar)), + (m_coeff->ktable[1][m_new_frame_k_idx[1]] * (1-m_zpar)), + (m_coeff->ktable[2][m_new_frame_k_idx[2]] * (1-m_zpar)), + (m_coeff->ktable[3][m_new_frame_k_idx[3]] * (1-m_zpar)), + (m_coeff->ktable[4][m_new_frame_k_idx[4]] * (1-m_uv_zpar)), + (m_coeff->ktable[5][m_new_frame_k_idx[5]] * (1-m_uv_zpar)), + (m_coeff->ktable[6][m_new_frame_k_idx[6]] * (1-m_uv_zpar)), + (m_coeff->ktable[7][m_new_frame_k_idx[7]] * (1-m_uv_zpar)), + (m_coeff->ktable[8][m_new_frame_k_idx[8]] * (1-m_uv_zpar)), + (m_coeff->ktable[9][m_new_frame_k_idx[9]] * (1-m_uv_zpar)) ); +#endif + + } + else // Not a new frame, just interpolate the existing frame. + { + int inhibit_state = ((m_inhibit==1)&&(m_IP != 0)); // disable inhibit when reaching the last interp period, but don't overwrite the m_inhibit value +#ifdef PERFECT_INTERPOLATION_HACK + int samples_per_frame = m_subc_reload?175:266; // either (13 A cycles + 12 B cycles) * 7 interps for normal SPEAK/SPKEXT, or (13*2 A cycles + 12 B cycles) * 7 interps for SPKSLOW + //int samples_per_frame = m_subc_reload?200:304; // either (13 A cycles + 12 B cycles) * 8 interps for normal SPEAK/SPKEXT, or (13*2 A cycles + 12 B cycles) * 8 interps for SPKSLOW + int current_sample = (m_subcycle - m_subc_reload)+(m_PC*(3-m_subc_reload))+((m_subc_reload?25:38)*((m_IP-1)&7)); + //fprintf(stderr, "CS: %03d", current_sample); + // reset the current energy, pitch, etc to what it was at frame start + m_current_energy = (m_coeff->energytable[m_old_frame_energy_idx] * (1-m_old_zpar)); + m_current_pitch = (m_coeff->pitchtable[m_old_frame_pitch_idx] * (1-m_old_zpar)); + for (i = 0; i < m_coeff->num_k; i++) + m_current_k[i] = (m_coeff->ktable[i][m_old_frame_k_idx[i]] * (1-((i<4)?m_old_zpar:m_old_uv_zpar))); + // now adjust each value to be exactly correct for each of the samples per frame + if (m_IP != 0) // if we're still interpolating... + { + m_current_energy = (m_current_energy + (((m_coeff->energytable[m_new_frame_energy_idx] - m_current_energy)*(1-inhibit_state))*current_sample)/samples_per_frame)*(1-m_zpar); + m_current_pitch = (m_current_pitch + (((m_coeff->pitchtable[m_new_frame_pitch_idx] - m_current_pitch)*(1-inhibit_state))*current_sample)/samples_per_frame)*(1-m_zpar); + for (i = 0; i < m_coeff->num_k; i++) + m_current_k[i] = (m_current_k[i] + (((m_coeff->ktable[i][m_new_frame_k_idx[i]] - m_current_k[i])*(1-inhibit_state))*current_sample)/samples_per_frame)*(1-((i<4)?m_zpar:m_uv_zpar)); + } + else // we're done, play this frame for 1/8 frame. + { + m_current_energy = (m_coeff->energytable[m_new_frame_energy_idx] * (1-m_zpar)); + m_current_pitch = (m_coeff->pitchtable[m_new_frame_pitch_idx] * (1-m_zpar)); + for (i = 0; i < m_coeff->num_k; i++) + m_current_k[i] = (m_coeff->ktable[i][m_new_frame_k_idx[i]] * (1-((i<4)?m_zpar:m_uv_zpar))); + } +#else + //Updates to parameters only happen on subcycle '2' (B cycle) of PCs. + if (m_subcycle == 2) + { + switch(m_PC) + { + case 0: /* PC = 0, B cycle, write updated energy */ + m_current_energy = (m_current_energy + (((m_coeff->energytable[m_new_frame_energy_idx] - m_current_energy)*(1-inhibit_state)) INTERP_SHIFT))*(1-m_zpar); + break; + case 1: /* PC = 1, B cycle, write updated pitch */ + m_current_pitch = (m_current_pitch + (((m_coeff->pitchtable[m_new_frame_pitch_idx] - m_current_pitch)*(1-inhibit_state)) INTERP_SHIFT))*(1-m_zpar); + break; + case 2: case 3: case 4: case 5: case 6: case 7: case 8: case 9: case 10: case 11: + /* PC = 2 through 11, B cycle, write updated K1 through K10 */ + m_current_k[m_PC-2] = (m_current_k[m_PC-2] + (((m_coeff->ktable[m_PC-2][m_new_frame_k_idx[m_PC-2]] - m_current_k[m_PC-2])*(1-inhibit_state)) INTERP_SHIFT))*(1-(((m_PC-2)<4)?m_zpar:m_uv_zpar)); + break; + case 12: /* PC = 12 */ + /* we should NEVER reach this point, PC=12 doesn't have a subcycle 2 */ + break; + } + } +#endif + } + + // calculate the output + if (OLD_FRAME_UNVOICED_FLAG == 1) + { + // generate unvoiced samples here + if (m_RNG & 1) + m_excitation_data = ~0x3F; /* according to the patent it is (either + or -) half of the maximum value in the chirp table, so either 01000000(0x40) or 11000000(0xC0)*/ + else + m_excitation_data = 0x40; + } + else /* (OLD_FRAME_UNVOICED_FLAG == 0) */ + { + // generate voiced samples here + /* US patent 4331836 Figure 14B shows, and logic would hold, that a pitch based chirp + * function has a chirp/peak and then a long chain of zeroes. + * The last entry of the chirp rom is at address 0b110011 (51d), the 52nd sample, + * and if the address reaches that point the ADDRESS incrementer is + * disabled, forcing all samples beyond 51d to be == 51d + */ + if (m_pitch_count >= 51) + m_excitation_data = (INT8)m_coeff->chirptable[51]; + else /*m_pitch_count < 51*/ + m_excitation_data = (INT8)m_coeff->chirptable[m_pitch_count]; + } + + // Update LFSR *20* times every sample (once per T cycle), like patent shows + for (i=0; i<20; i++) + { + bitout = ((m_RNG >> 12) & 1) ^ + ((m_RNG >> 3) & 1) ^ + ((m_RNG >> 2) & 1) ^ + ((m_RNG >> 0) & 1); + m_RNG <<= 1; + m_RNG |= bitout; + } + this_sample = lattice_filter(); /* execute lattice filter */ +#ifdef DEBUG_GENERATION_VERBOSE + //fprintf(stderr,"C:%01d; ",m_subcycle); + fprintf(stderr,"IP:%01d PC:%02d X:%04d E:%03d P:%03d Pc:%03d ",m_IP, m_PC, m_excitation_data, m_current_energy, m_current_pitch, m_pitch_count); + //fprintf(stderr,"X:%04d E:%03d P:%03d Pc:%03d ", m_excitation_data, m_current_energy, m_current_pitch, m_pitch_count); + for (i=0; i<10; i++) + fprintf(stderr,"K%d:%04d ", i+1, m_current_k[i]); + fprintf(stderr,"Out:%06d ", this_sample); +//#ifdef PERFECT_INTERPOLATION_HACK +// fprintf(stderr,"%d%d%d%d",m_old_zpar,m_zpar,m_old_uv_zpar,m_uv_zpar); +//#else +// fprintf(stderr,"x%dx%d",m_zpar,m_uv_zpar); +//#endif + fprintf(stderr,"\n"); +#endif + /* next, force result to 14 bits (since its possible that the addition at the final (k1) stage of the lattice overflowed) */ + while (this_sample > 16383) this_sample -= 32768; + while (this_sample < -16384) this_sample += 32768; + if (m_digital_select == 0) // analog SPK pin output is only 8 bits, with clipping + buffer[buf_count] = clip_analog(this_sample); + else // digital I/O pin output is 12 bits + { +#ifdef ALLOW_4_LSB + // input: ssss ssss ssss ssss ssnn nnnn nnnn nnnn + // N taps: ^ = 0x2000; + // output: ssss ssss ssss ssss snnn nnnn nnnn nnnN + buffer[buf_count] = (this_sample<<1)|((this_sample&0x2000)>>13); +#else + this_sample &= ~0xF; + // input: ssss ssss ssss ssss ssnn nnnn nnnn 0000 + // N taps: ^^ ^^^ = 0x3E00; + // output: ssss ssss ssss ssss snnn nnnn nnnN NNNN + buffer[buf_count] = (this_sample<<1)|((this_sample&0x3E00)>>9); +#endif + } + // Update all counts + + m_subcycle++; + if ((m_subcycle == 2) && (m_PC == 12)) // RESETF3 + { + /* Circuit 412 in the patent acts a reset, resetting the pitch counter to 0 + * if INHIBIT was true during the most recent frame transition. + * The exact time this occurs is betwen IP=7, PC=12 sub=0, T=t12 + * and m_IP = 0, PC=0 sub=0, T=t12, a period of exactly 20 cycles, + * which overlaps the time OLDE and OLDP are updated at IP=7 PC=12 T17 + * (and hence INHIBIT itself 2 t-cycles later). We do it here because it is + * convenient and should make no difference in output. + */ + if ((m_IP == 7)&&(m_inhibit==1)) m_pitch_zero = 1; + if ((m_IP == 0)&&(m_pitch_zero==1)) m_pitch_zero = 0; + if (m_IP == 7) // RESETL4 + { + // Latch OLDE and OLDP + OLD_FRAME_SILENCE_FLAG = NEW_FRAME_SILENCE_FLAG; // m_OLDE + OLD_FRAME_UNVOICED_FLAG = NEW_FRAME_UNVOICED_FLAG; // m_OLDP + /* if TALK was clear last frame, halt speech now, since TALKD (latched from TALK on new frame) just went inactive. */ +#ifdef DEBUG_GENERATION + fprintf(stderr,"RESETL4, about to update status: IP=%d, PC=%d, subcycle=%d, m_SPEN=%d, m_TALK=%d, m_TALKD=%d\n", m_IP, m_PC, m_subcycle, m_SPEN, m_TALK, m_TALKD); +#endif +#ifdef DEBUG_GENERATION + if (m_TALK == 0) + fprintf(stderr,"tms5220_process: processing frame: TALKD = 0 caused by stop frame or buffer empty, halting speech.\n"); +#endif + m_TALKD = m_TALK; // TALKD is latched from TALK + update_fifo_status_and_ints(); // to trigger an interrupt if TALK_STATUS is now inactive + m_TALK = m_SPEN; // TALK is latched from SPEN +#ifdef DEBUG_GENERATION + fprintf(stderr,"RESETL4, status updated: IP=%d, PC=%d, subcycle=%d, m_SPEN=%d, m_TALK=%d, m_TALKD=%d\n", m_IP, m_PC, m_subcycle, m_SPEN, m_TALK, m_TALKD); +#endif + } + m_subcycle = m_subc_reload; + m_PC = 0; + m_IP++; + m_IP&=0x7; + } + else if (m_subcycle == 3) + { + m_subcycle = m_subc_reload; + m_PC++; + } + m_pitch_count++; + if ((m_pitch_count >= m_current_pitch)||(m_pitch_zero == 1)) m_pitch_count = 0; + m_pitch_count &= 0x1FF; + } + else // m_TALKD == 0 + { + m_subcycle++; + if ((m_subcycle == 2) && (m_PC == 12)) // RESETF3 + { + if (m_IP == 7) // RESETL4 + { + m_TALKD = m_TALK; // TALKD is latched from TALK + m_TALK = m_SPEN; // TALK is latched from SPEN + } + m_subcycle = m_subc_reload; + m_PC = 0; + m_IP++; + m_IP&=0x7; + } + else if (m_subcycle == 3) + { + m_subcycle = m_subc_reload; + m_PC++; + } + buffer[buf_count] = -1; /* should be just -1; actual chip outputs -1 every idle sample; (cf note in data sheet, p 10, table 4) */ + } + buf_count++; + size--; + } +} + +/********************************************************************************************** + + clip_analog -- clips the 14 bit return value from the lattice filter to its final 10 bit value (-512 to 511), and upshifts/range extends this to 16 bits + +***********************************************************************************************/ + +static INT16 clip_analog(INT16 cliptemp) +{ + /* clipping, just like the patent shows: + * the top 10 bits of this result are visible on the digital output IO pin. + * next, if the top 3 bits of the 14 bit result are all the same, the lowest of those 3 bits plus the next 7 bits are the signed analog output, otherwise the low bits are all forced to match the inverse of the topmost bit, i.e.: + * 1x xxxx xxxx xxxx -> 0b10000000 + * 11 1bcd efgh xxxx -> 0b1bcdefgh + * 00 0bcd efgh xxxx -> 0b0bcdefgh + * 0x xxxx xxxx xxxx -> 0b01111111 + */ +#ifdef DEBUG_CLIP + if ((cliptemp > 2047) || (cliptemp < -2048)) fprintf(stderr,"clipping cliptemp to range; was %d\n", cliptemp); +#endif + if (cliptemp > 2047) cliptemp = 2047; + else if (cliptemp < -2048) cliptemp = -2048; + /* at this point the analog output is tapped */ +#ifdef ALLOW_4_LSB + // input: ssss snnn nnnn nnnn + // N taps: ^^^ ^ = 0x0780 + // output: snnn nnnn nnnn NNNN + return (cliptemp << 4)|((cliptemp&0x780)>>7); // upshift and range adjust +#else + cliptemp &= ~0xF; + // input: ssss snnn nnnn 0000 + // N taps: ^^^ ^^^^ = 0x07F0 + // P taps: ^ = 0x0400 + // output: snnn nnnn NNNN NNNP + return (cliptemp << 4)|((cliptemp&0x7F0)>>3)|((cliptemp&0x400)>>10); // upshift and range adjust +#endif +} + + +/********************************************************************************************** + + matrix_multiply -- does the proper multiply and shift + a is the k coefficient and is clamped to 10 bits (9 bits plus a sign) + b is the running result and is clamped to 14 bits. + output is 14 bits, but note the result LSB bit is always 1. + Because the low 4 bits of the result are trimmed off before + output, this makes almost no difference in the computation. + +**********************************************************************************************/ +static INT32 matrix_multiply(INT32 a, INT32 b) +{ + INT32 result; + while (a>511) { a-=1024; } + while (a<-512) { a+=1024; } + while (b>16383) { b-=32768; } + while (b<-16384) { b+=32768; } + result = ((a*b)>>9)|1;//&(~1); +#ifdef VERBOSE + if (result>16383) fprintf(stderr,"matrix multiplier overflowed! a: %x, b: %x, result: %x", a, b, result); + if (result<-16384) fprintf(stderr,"matrix multiplier underflowed! a: %x, b: %x, result: %x", a, b, result); +#endif + return result; +} + +/********************************************************************************************** + + lattice_filter -- executes one 'full run' of the lattice filter on a specific byte of + excitation data, and specific values of all the current k constants, and returns the + resulting sample. + +***********************************************************************************************/ + +INT32 tms5220_device::lattice_filter() +{ + // Lattice filter here + // Aug/05/07: redone as unrolled loop, for clarity - LN + /* Originally Copied verbatim from table I in US patent 4,209,804, now updated to be in same order as the actual chip does it, not that it matters. + notation equivalencies from table: + Yn(i) == m_u[n-1] + Kn = m_current_k[n-1] + bn = m_x[n-1] + */ + /* + int ep = matrix_multiply(m_previous_energy, (m_excitation_data<<6)); //Y(11) + m_u[10] = ep; + for (int i = 0; i < 10; i++) + { + int ii = 10-i; // for m = 10, this would be 11 - i, and since i is from 1 to 10, then ii ranges from 10 to 1 + //int jj = ii+1; // this variable, even on the fortran version, is never used. it probably was intended to be used on the two lines below the next one to save some redundant additions on each. + ep = ep - (((m_current_k[ii-1] * m_x[ii-1])>>9)|1); // subtract reflection from lower stage 'top of lattice' + m_u[ii-1] = ep; + m_x[ii] = m_x[ii-1] + (((m_current_k[ii-1] * ep)>>9)|1); // add reflection from upper stage 'bottom of lattice' + } + m_x[0] = ep; // feed the last section of the top of the lattice directly to the bottom of the lattice + */ + m_u[10] = matrix_multiply(m_previous_energy, (m_excitation_data<<6)); //Y(11) + m_u[9] = m_u[10] - matrix_multiply(m_current_k[9], m_x[9]); + m_u[8] = m_u[9] - matrix_multiply(m_current_k[8], m_x[8]); + m_u[7] = m_u[8] - matrix_multiply(m_current_k[7], m_x[7]); + m_u[6] = m_u[7] - matrix_multiply(m_current_k[6], m_x[6]); + m_u[5] = m_u[6] - matrix_multiply(m_current_k[5], m_x[5]); + m_u[4] = m_u[5] - matrix_multiply(m_current_k[4], m_x[4]); + m_u[3] = m_u[4] - matrix_multiply(m_current_k[3], m_x[3]); + m_u[2] = m_u[3] - matrix_multiply(m_current_k[2], m_x[2]); + m_u[1] = m_u[2] - matrix_multiply(m_current_k[1], m_x[1]); + m_u[0] = m_u[1] - matrix_multiply(m_current_k[0], m_x[0]); + m_x[9] = m_x[8] + matrix_multiply(m_current_k[8], m_u[8]); + m_x[8] = m_x[7] + matrix_multiply(m_current_k[7], m_u[7]); + m_x[7] = m_x[6] + matrix_multiply(m_current_k[6], m_u[6]); + m_x[6] = m_x[5] + matrix_multiply(m_current_k[5], m_u[5]); + m_x[5] = m_x[4] + matrix_multiply(m_current_k[4], m_u[4]); + m_x[4] = m_x[3] + matrix_multiply(m_current_k[3], m_u[3]); + m_x[3] = m_x[2] + matrix_multiply(m_current_k[2], m_u[2]); + m_x[2] = m_x[1] + matrix_multiply(m_current_k[1], m_u[1]); + m_x[1] = m_x[0] + matrix_multiply(m_current_k[0], m_u[0]); + m_x[0] = m_u[0]; + m_previous_energy = m_current_energy; +#ifdef DEBUG_LATTICE + int i; + fprintf(stderr,"V:%04d ", m_u[10]); + for (i = 9; i >= 0; i--) + { + fprintf(stderr,"Y%d:%04d ", i+1, m_u[i]); + fprintf(stderr,"b%d:%04d ", i+1, m_x[i]); + if ((i % 5) == 0) fprintf(stderr,"\n"); + } +#endif + return m_u[0]; +} + + +/********************************************************************************************** + + process_command -- extract a byte from the FIFO and interpret it as a command + +***********************************************************************************************/ + +void tms5220_device::process_command(unsigned char cmd) +{ + int i; +#ifdef DEBUG_COMMAND_DUMP + fprintf(stderr,"process_command called with parameter %02X\n",cmd); +#endif + /* parse the command */ + switch (cmd & 0x70) + { + case 0x10 : /* read byte */ + if (TALK_STATUS == 0) /* TALKST must be clear for RDBY */ + { + if (m_schedule_dummy_read) + { + m_schedule_dummy_read = FALSE; + if (m_speechrom) + m_speechrom->read(1); + } + if (m_speechrom) + m_data_register = m_speechrom->read(8); /* read one byte from speech ROM... */ + m_RDB_flag = TRUE; + } + break; + + case 0x00: case 0x20: /* set rate (tms5220c and cd2501ecd only), otherwise NOP */ + if (TMS5220_HAS_RATE_CONTROL) + { + m_c_variant_rate = cmd&0x0F; + } + break; + + case 0x30 : /* read and branch */ + if (TALK_STATUS == 0) /* TALKST must be clear for RB */ + { +#ifdef VERBOSE + fprintf(stderr,"read and branch command received\n"); +#endif + m_RDB_flag = FALSE; + if (m_speechrom) + m_speechrom->read_and_branch(); + } + break; + + case 0x40 : /* load address */ + if (TALK_STATUS == 0) /* TALKST must be clear for LA */ + { + /* tms5220 data sheet says that if we load only one 4-bit nibble, it won't work. + This code does not care about this. */ + if (m_speechrom) + m_speechrom->load_address(cmd & 0x0f); + m_schedule_dummy_read = TRUE; + } + break; + + case 0x50 : /* speak */ + if (m_schedule_dummy_read) + { + m_schedule_dummy_read = FALSE; + if (m_speechrom) + m_speechrom->read(1); + } + m_SPEN = 1; +#ifdef FAST_START_HACK + m_TALK = 1; +#endif + m_DDIS = 0; + m_zpar = 1; // zero all the parameters + m_uv_zpar = 1; // zero k4-k10 as well + m_OLDE = 1; // 'silence/zpar' frames are zero energy + m_OLDP = 1; // 'silence/zpar' frames are zero pitch +#ifdef PERFECT_INTERPOLATION_HACK + m_old_zpar = 1; // zero all the old parameters + m_old_uv_zpar = 1; // zero old k4-k10 as well +#endif + // following is semi-hack but matches idle state observed on chip + m_new_frame_energy_idx = 0; + m_new_frame_pitch_idx = 0; + for (i = 0; i < 4; i++) + m_new_frame_k_idx[i] = 0; + for (i = 4; i < 7; i++) + m_new_frame_k_idx[i] = 0xF; + for (i = 7; i < m_coeff->num_k; i++) + m_new_frame_k_idx[i] = 0x7; + break; + + case 0x60 : /* speak external */ + // SPKEXT going active activates SPKEE which clears the fifo + m_fifo_head = m_fifo_tail = m_fifo_count = m_fifo_bits_taken = 0; + // SPEN is enabled when the fifo passes half full (falling edge of BL signal) + m_DDIS = 1; + m_zpar = 1; // zero all the parameters + m_uv_zpar = 1; // zero k4-k10 as well + m_OLDE = 1; // 'silence/zpar' frames are zero energy + m_OLDP = 1; // 'silence/zpar' frames are zero pitch +#ifdef PERFECT_INTERPOLATION_HACK + m_old_zpar = 1; // zero all the old parameters + m_old_uv_zpar = 1; // zero old k4-k10 as well +#endif + // following is semi-hack but matches idle state observed on chip + m_new_frame_energy_idx = 0; + m_new_frame_pitch_idx = 0; + for (i = 0; i < 4; i++) + m_new_frame_k_idx[i] = 0; + for (i = 4; i < 7; i++) + m_new_frame_k_idx[i] = 0xF; + for (i = 7; i < m_coeff->num_k; i++) + m_new_frame_k_idx[i] = 0x7; + m_RDB_flag = FALSE; + break; + + case 0x70 : /* reset */ + if (m_schedule_dummy_read) + { + m_schedule_dummy_read = FALSE; + if (m_speechrom) + m_speechrom->read(1); + } + reset(); + break; + } + + /* update the buffer low state */ + update_fifo_status_and_ints(); +} + +/****************************************************************************************** + + parse_frame -- parse a new frame's worth of data; returns 0 if not enough bits in buffer + +******************************************************************************************/ + +void tms5220_device::parse_frame() +{ + int i, rep_flag; + + // We actually don't care how many bits are left in the fifo here; the frame subpart will be processed normally, and any bits extracted 'past the end' of the fifo will be read as zeroes; the fifo being emptied will set the /BE latch which will halt speech exactly as if a stop frame had been encountered (instead of whatever partial frame was read); the same exact circuitry is used for both on the real chip, see us patent 4335277 sheet 16, gates 232a (decode stop frame) and 232b (decode /BE plus DDIS (decode disable) which is active during speak external). + + /* if the chip is a tms5220C, and the rate mode is set to that each frame (0x04 bit set) + has a 2 bit rate preceding it, grab two bits here and store them as the rate; */ + if ((TMS5220_HAS_RATE_CONTROL) && (m_c_variant_rate & 0x04)) + { + i = extract_bits(2); +#ifdef DEBUG_PARSE_FRAME_DUMP + printbits(i,2); + fprintf(stderr," "); +#endif + m_IP = reload_table[i]; + } + else // non-5220C and 5220C in fixed rate mode + m_IP = reload_table[m_c_variant_rate&0x3]; + + update_fifo_status_and_ints(); + if (m_DDIS && m_buffer_empty) goto ranout; + + // attempt to extract the energy index + m_new_frame_energy_idx = extract_bits(m_coeff->energy_bits); +#ifdef DEBUG_PARSE_FRAME_DUMP + printbits(m_new_frame_energy_idx,m_coeff->energy_bits); + fprintf(stderr," "); +#endif + update_fifo_status_and_ints(); + if (m_DDIS && m_buffer_empty) goto ranout; + // if the energy index is 0 or 15, we're done + if ((m_new_frame_energy_idx == 0) || (m_new_frame_energy_idx == 15)) + return; + + + // attempt to extract the repeat flag + rep_flag = extract_bits(1); +#ifdef DEBUG_PARSE_FRAME_DUMP + printbits(rep_flag, 1); + fprintf(stderr," "); +#endif + + // attempt to extract the pitch + m_new_frame_pitch_idx = extract_bits(m_coeff->pitch_bits); +#ifdef DEBUG_PARSE_FRAME_DUMP + printbits(m_new_frame_pitch_idx,m_coeff->pitch_bits); + fprintf(stderr," "); +#endif + update_fifo_status_and_ints(); + if (m_DDIS && m_buffer_empty) goto ranout; + // if this is a repeat frame, just do nothing, it will reuse the old coefficients + if (rep_flag) + return; + + // extract first 4 K coefficients + for (i = 0; i < 4; i++) + { + m_new_frame_k_idx[i] = extract_bits(m_coeff->kbits[i]); +#ifdef DEBUG_PARSE_FRAME_DUMP + printbits(m_new_frame_k_idx[i],m_coeff->kbits[i]); + fprintf(stderr," "); +#endif + update_fifo_status_and_ints(); + if (m_DDIS && m_buffer_empty) goto ranout; + } + + // if the pitch index was zero, we only need 4 K's... + if (m_new_frame_pitch_idx == 0) + { + /* and the rest of the coefficients are zeroed, but that's done in the generator code */ + return; + } + + // If we got here, we need the remaining 6 K's + for (i = 4; i < m_coeff->num_k; i++) + { + m_new_frame_k_idx[i] = extract_bits(m_coeff->kbits[i]); +#ifdef DEBUG_PARSE_FRAME_DUMP + printbits(m_new_frame_k_idx[i],m_coeff->kbits[i]); + fprintf(stderr," "); +#endif + update_fifo_status_and_ints(); + if (m_DDIS && m_buffer_empty) goto ranout; + } +#ifdef DEBUG_PARSE_FRAME_DUMP + fprintf(stderr,"\n"); +#endif +#ifdef VERBOSE + if (m_DDIS) + fprintf(stderr,"Parsed a frame successfully in FIFO - %d bits remaining\n", (m_fifo_count*8)-(m_fifo_bits_taken)); + else + fprintf(stderr,"Parsed a frame successfully in ROM\n"); +#endif + return; + + ranout: +#ifdef DEBUG_FRAME_ERRORS + fprintf(stderr,"Ran out of bits on a parse!\n"); +#endif + return; +} + +/********************************************************************************************** + + set_interrupt_state -- generate an interrupt + +***********************************************************************************************/ + +void tms5220_device::set_interrupt_state(int state) +{ + if (!TMS5220_IS_52xx) return; // bail out if not a 52xx chip, since there's no int pin +#ifdef DEBUG_PIN_READS + fprintf(stderr,"irq pin set to state %d\n", state); +#endif + if (!m_irq_handler.isnull() && state != m_irq_pin) + m_irq_handler(!state); + m_irq_pin = state; +} + +/********************************************************************************************** + + update_ready_state -- update the ready line + +***********************************************************************************************/ + +void tms5220_device::update_ready_state() +{ + int state = ready_read(); +#ifdef DEBUG_PIN_READS + fprintf(stderr,"ready pin set to state %d\n", state); +#endif + if (!m_readyq_handler.isnull() && state != m_ready_pin) + m_readyq_handler(!state); + m_ready_pin = state; +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void tms5220_device::device_start() +{ + if (m_speechrom_tag) + { + m_speechrom = siblingdevice( m_speechrom_tag ); + if( !m_speechrom ) + { + throw new emu_fatalerror("Error: %s '%s' can't find speechrom '%s'\n", shortname(), tag(), m_speechrom_tag ); + } + } + else + { + m_speechrom = NULL; + } + + set_variant(TMS5220_IS_5220); + m_clock = clock(); + + /* resolve irq and readyq line */ + m_irq_handler.resolve(); + m_readyq_handler.resolve(); + + /* initialize a stream */ + m_stream = machine().sound().stream_alloc(*this, 0, 1, clock() / 80); + + m_timer_io_ready = timer_alloc(0); + + /* not during reset which is called frm within a write! */ + m_io_ready = 1; + m_true_timing = 0; + m_rs_ws = 0x03; // rs and ws are assumed to be inactive on device startup + + register_for_save_states(); +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void tms5220c_device::device_start() +{ + tms5220_device::device_start(); + set_variant(TMS5220_IS_5220C); +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void cd2501e_device::device_start() +{ + tms5220_device::device_start(); + set_variant(TMS5220_IS_CD2501E); +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void tms5200_device::device_start() +{ + tms5220_device::device_start(); + set_variant(TMS5220_IS_5200); +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void cd2501ecd_device::device_start() +{ + tms5220_device::device_start(); + set_variant(TMS5220_IS_CD2501ECD); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void tms5220_device::device_reset() +{ + m_digital_select = FORCE_DIGITAL; // assume analog output + /* initialize the FIFO */ + /*memset(m_fifo, 0, sizeof(m_fifo));*/ + m_fifo_head = m_fifo_tail = m_fifo_count = m_fifo_bits_taken = 0; + + /* initialize the chip state */ + /* Note that we do not actually clear IRQ on start-up : IRQ is even raised if m_buffer_empty or m_buffer_low are 0 */ + m_SPEN = m_DDIS = m_TALK = m_TALKD = m_previous_TALK_STATUS = m_irq_pin = m_ready_pin = 0; + set_interrupt_state(0); + update_ready_state(); + m_buffer_empty = m_buffer_low = 1; + + m_RDB_flag = FALSE; + + /* initialize the energy/pitch/k states */ +#ifdef PERFECT_INTERPOLATION_HACK + m_old_frame_energy_idx = m_old_frame_pitch_idx = 0; + memset(m_old_frame_k_idx, 0, sizeof(m_old_frame_k_idx)); + m_old_zpar = 0; +#endif + m_new_frame_energy_idx = m_current_energy = m_previous_energy = 0; + m_new_frame_pitch_idx = m_current_pitch = 0; + m_zpar = m_uv_zpar = 0; + memset(m_new_frame_k_idx, 0, sizeof(m_new_frame_k_idx)); + memset(m_current_k, 0, sizeof(m_current_k)); + + /* initialize the sample generators */ + m_inhibit = 1; + m_subcycle = m_c_variant_rate = m_pitch_count = m_PC = 0; + m_subc_reload = FORCE_SUBC_RELOAD; + m_OLDE = m_OLDP = 1; + m_IP = reload_table[m_c_variant_rate&0x3]; + m_RNG = 0x1FFF; + memset(m_u, 0, sizeof(m_u)); + memset(m_x, 0, sizeof(m_x)); + m_schedule_dummy_read = 0; + + if (m_speechrom) + { + m_speechrom->load_address(0); + // MZ: Do the dummy read immediately. The previous line will cause a + // shift in the address pointer in the VSM. When the next command is a + // load_address, no dummy read will occur, hence the address will be + // falsely shifted. + m_speechrom->read(1); + m_schedule_dummy_read = FALSE; + } +} + +/********************************************************************************************** + + True timing + +***********************************************************************************************/ + +void tms5220_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch(id) + { + case 0: + if (param) + { + switch (m_rs_ws) + { + case 0x02: + /* Write */ + /* bring up to date first */ +#ifdef DEBUG_IO_READY + fprintf(stderr,"Serviced write: %02x\n", m_write_latch); + //fprintf(stderr, "Processed write data: %02X\n", m_write_latch); +#endif + m_stream->update(); + data_write(m_write_latch); + break; + case 0x01: + /* Read */ + /* bring up to date first */ + m_stream->update(); + m_read_latch = status_read(); + break; + case 0x03: + /* High Impedance */ + case 0x00: + /* illegal */ + break; + } + } + + m_io_ready = param; + update_ready_state(); + break; + } +} + +/* + * /RS line write handler + */ +WRITE_LINE_MEMBER( tms5220_device::rsq_w ) +{ + UINT8 new_val; + + m_true_timing = 1; + state &= 0x01; +#ifdef DEBUG_RS_WS + fprintf(stderr,"/RS written with data: %d\n", state); +#endif + new_val = (m_rs_ws & 0x01) | (state<<1); + if (new_val != m_rs_ws) + { + m_rs_ws = new_val; + if (new_val == 0) + { + if (TMS5220_HAS_RATE_CONTROL) // correct for 5220c, ? for cd2501ecd + reset(); +#ifdef DEBUG_RS_WS + else + /* illegal */ + fprintf(stderr,"tms5220_rs_w: illegal\n"); +#endif + return; + } + else if ( new_val == 3) + { + /* high impedance */ + m_read_latch = 0xff; + return; + } + if (state) + { + /* low to high */ + } + else + { + /* high to low - schedule ready cycle */ +#ifdef DEBUG_RS_WS + fprintf(stderr,"Scheduling ready cycle for /RS...\n"); +#endif + /* upon /RS being activated, /READY goes inactive after 100 nsec from data sheet, through 3 asynchronous gates on patent. This is effectively within one clock, so we immediately set io_ready to 0 and activate the callback. */ + m_io_ready = 0; + update_ready_state(); + /* How long does /READY stay inactive, when /RS is pulled low? I believe its almost always ~16 clocks (25 usec at 800khz as shown on the datasheet) */ + m_timer_io_ready->adjust(attotime::from_hz(clock()/16), 1); // this should take around 10-16 (closer to ~11?) cycles to complete + } + } +} + +/* + * /WS line write handler + */ +WRITE_LINE_MEMBER( tms5220_device::wsq_w ) +{ + UINT8 new_val; + + m_true_timing = 1; + state &= 0x01; +#ifdef DEBUG_RS_WS + fprintf(stderr,"/WS written with data: %d\n", state); +#endif + new_val = (m_rs_ws & 0x02) | (state<<0); + if (new_val != m_rs_ws) + { + m_rs_ws = new_val; + if (new_val == 0) + { + if (TMS5220_HAS_RATE_CONTROL) // correct for 5220c, ? for cd2501ecd + reset(); +#ifdef DEBUG_RS_WS + else + /* illegal */ + fprintf(stderr,"tms5220_ws_w: illegal\n"); +#endif + return; + } + else if ( new_val == 3) + { + /* high impedance */ + m_read_latch = 0xff; + return; + } + if (state) + { + /* low to high */ + } + else + { + /* high to low - schedule ready cycle */ +#ifdef DEBUG_RS_WS + fprintf(stderr,"Scheduling ready cycle for /WS...\n"); +#endif + /* upon /WS being activated, /READY goes inactive after 100 nsec from data sheet, through 3 asynchronous gates on patent. This is effectively within one clock, so we immediately set io_ready to 0 and activate the callback. */ + m_io_ready = 0; + update_ready_state(); + /* Now comes the complicated part: long does /READY stay inactive, when /WS is pulled low? This depends ENTIRELY on the command written, or whether the chip is in speak external mode or not... + Speak external mode: ~16 cycles + Command Mode: + SPK: ? cycles + SPKEXT: ? cycles + RDBY: between 60 and 140 cycles + RB: ? cycles (80?) + RST: between 60 and 140 cycles + SET RATE (5220C and CD2501ECD only): ? cycles (probably ~16) + */ + // TODO: actually HANDLE the timing differences! currently just assuming always 16 cycles + m_timer_io_ready->adjust(attotime::from_hz(clock()/16), 1); // this should take around 10-16 (closer to ~15) cycles to complete for fifo writes, TODO: but actually depends on what command is written if in command mode + } + } +} + +/********************************************************************************************** + + tms5220_data_w -- write data to the sound chip + +***********************************************************************************************/ + +WRITE8_MEMBER( tms5220_device::data_w ) +{ + // prevent debugger from changing the internal state + if (space.debugger_access()) return; + +#ifdef DEBUG_RS_WS + fprintf(stderr,"tms5220_data_w: data %02x\n", data); +#endif + if (!m_true_timing) + { + /* bring up to date first */ + m_stream->update(); + data_write(data); + } + else + { + /* actually in a write ? */ +#ifdef DEBUG_RS_WS + if (!(m_rs_ws == 0x02)) + fprintf(stderr,"tms5220_data_w: data written outside ws, status: %02x!\n", m_rs_ws); +#endif + m_write_latch = data; + } +} + + + +/********************************************************************************************** + + tms5220_status_r -- read status or data from the sound chip + +***********************************************************************************************/ + +READ8_MEMBER( tms5220_device::status_r ) +{ + // prevent debugger from changing the internal state + if (space.debugger_access()) return 0; + + if (!m_true_timing) + { + /* bring up to date first */ + m_stream->update(); + return status_read(); + } + else + { + /* actually in a read ? */ + if (m_rs_ws == 0x01) + return m_read_latch; +#ifdef DEBUG_RS_WS + else + fprintf(stderr,"tms5220_status_r: data read outside rs!\n"); +#endif + return 0xff; + } +} + + + +/********************************************************************************************** + + tms5220_ready_r -- return the not ready status from the sound chip + +***********************************************************************************************/ + +READ_LINE_MEMBER( tms5220_device::readyq_r ) +{ + /* bring up to date first */ + m_stream->update(); + return !ready_read(); +} + + + +/********************************************************************************************** + + tms5220_time_to_ready -- return the time in seconds until the ready line is asserted + +***********************************************************************************************/ + +double tms5220_device::time_to_ready() +{ + double cycles; + + /* bring up to date first */ + m_stream->update(); + cycles = cycles_to_ready(); + return cycles * 80.0 / m_clock; +} + + + +/********************************************************************************************** + + tms5220_int_r -- return the int status from the sound chip + +***********************************************************************************************/ + +READ_LINE_MEMBER( tms5220_device::intq_r ) +{ + /* bring up to date first */ + m_stream->update(); + return !int_read(); +} + + + +/********************************************************************************************** + + tms5220_update -- update the sound chip so that it is in sync with CPU execution + +***********************************************************************************************/ + +//------------------------------------------------- +// sound_stream_update - handle a stream update +//------------------------------------------------- + +void tms5220_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + INT16 sample_data[MAX_SAMPLE_CHUNK]; + stream_sample_t *buffer = outputs[0]; + + /* loop while we still have samples to generate */ + while (samples) + { + int length = (samples > MAX_SAMPLE_CHUNK) ? MAX_SAMPLE_CHUNK : samples; + int index; + + /* generate the samples and copy to the target buffer */ + process(sample_data, length); + for (index = 0; index < length; index++) + *buffer++ = sample_data[index]; + + /* account for the samples */ + samples -= length; + } +} + + + +/********************************************************************************************** + + tms5220_set_frequency -- adjusts the playback frequency + +***********************************************************************************************/ + +void tms5220_device::set_frequency(int frequency) +{ + m_stream->set_sample_rate(frequency / 80); + m_clock = frequency; +} + +const device_type TMS5220C = &device_creator; + +tms5220c_device::tms5220c_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : tms5220_device(mconfig, TMS5220C, "TMS5220C", tag, owner, clock, "tms5220c", __FILE__) +{ +} + + +const device_type TMS5220 = &device_creator; + +tms5220_device::tms5220_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, TMS5220, "TMS5220", tag, owner, clock, "tms5220", __FILE__), + device_sound_interface(mconfig, *this), + m_irq_handler(*this), + m_readyq_handler(*this), + m_speechrom_tag(NULL) +{ +} + +tms5220_device::tms5220_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_sound_interface(mconfig, *this), + m_irq_handler(*this), + m_readyq_handler(*this), + m_speechrom_tag(NULL) +{ +} + +//------------------------------------------------- +// device_config_complete - perform any +// operations now that the configuration is +// complete +//------------------------------------------------- + +void tms5220_device::device_config_complete() +{ +} + + +const device_type CD2501E = &device_creator; + +cd2501e_device::cd2501e_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : tms5220_device(mconfig, CD2501E, "CD2501E", tag, owner, clock, "cd2501e", __FILE__) +{ +} + + +const device_type TMS5200 = &device_creator; + +tms5200_device::tms5200_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : tms5220_device(mconfig, TMS5200, "TMS5200", tag, owner, clock, "tms5200", __FILE__) +{ +} + + +const device_type CD2501ECD = &device_creator; + +cd2501ecd_device::cd2501ecd_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : tms5220_device(mconfig, CD2501ECD, "CD2501ECD", tag, owner, clock, "cd2501ecd", __FILE__) +{ +} diff --git a/src/devices/sound/tms5220.h b/src/devices/sound/tms5220.h new file mode 100644 index 00000000000..12edc66e5c3 --- /dev/null +++ b/src/devices/sound/tms5220.h @@ -0,0 +1,254 @@ +// license:BSD-3-Clause +// copyright-holders:Frank Palazzolo, Aaron Giles, Jonathan Gevaryahu, Raphael Nabet, Couriersud, Michael Zapf +#pragma once + +#ifndef __TMS5220_H__ +#define __TMS5220_H__ + +#include "emu.h" +#include "machine/spchrom.h" + +/* HACK: if defined, uses impossibly perfect 'straight line' interpolation */ +#undef PERFECT_INTERPOLATION_HACK + +#define FIFO_SIZE 16 + +/* clock rate = 80 * output sample rate, */ +/* usually 640000 for 8000 Hz sample rate or */ +/* usually 800000 for 10000 Hz sample rate. */ + +/* IRQ callback function, active low, i.e. state=0 */ +#define MCFG_TMS52XX_IRQ_HANDLER(_devcb) \ + devcb = &tms5220_device::set_irq_handler(*device, DEVCB_##_devcb); + +/* Ready callback function, active low, i.e. state=0 */ +#define MCFG_TMS52XX_READYQ_HANDLER(_devcb) \ + devcb = &tms5220_device::set_readyq_handler(*device, DEVCB_##_devcb); + +#define MCFG_TMS52XX_SPEECHROM(_tag) \ + tms5220_device::set_speechrom_tag(*device, _tag); + +class tms5220_device : public device_t, + public device_sound_interface +{ +public: + tms5220_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + tms5220_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + // static configuration helpers + template static devcb_base &set_irq_handler(device_t &device, _Object object) { return downcast(device).m_irq_handler.set_callback(object); } + template static devcb_base &set_readyq_handler(device_t &device, _Object object) { return downcast(device).m_readyq_handler.set_callback(object); } + static void set_speechrom_tag(device_t &device, const char *_tag) { downcast(device).m_speechrom_tag = _tag; } + + /* Control lines - once written to will switch interface into + * "true" timing behaviour. + */ + + /* all lines with suffix q are active low! */ + + WRITE_LINE_MEMBER( rsq_w ); + WRITE_LINE_MEMBER( wsq_w ); + + DECLARE_WRITE8_MEMBER( data_w ); + DECLARE_READ8_MEMBER( status_r ); + + READ_LINE_MEMBER( readyq_r ); + READ_LINE_MEMBER( intq_r ); + + double time_to_ready(); + + void set_frequency(int frequency); + +protected: + // device-level overrides + virtual void device_config_complete(); + virtual void device_start(); + virtual void device_reset(); + + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + // sound stream update overrides + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + + void set_variant(int variant); + +private: + void register_for_save_states(); + void data_write(int data); + void update_fifo_status_and_ints(); + int extract_bits(int count); + int status_read(); + int ready_read(); + int cycles_to_ready(); + int int_read(); + void process(INT16 *buffer, unsigned int size); + INT32 lattice_filter(); + void process_command(unsigned char cmd); + void parse_frame(); + void set_interrupt_state(int state); + void update_ready_state(); + + // internal state + + /* coefficient tables */ + int m_variant; /* Variant of the 5xxx - see tms5110r.h */ + + /* coefficient tables */ + const struct tms5100_coeffs *m_coeff; + + /* these contain data that describes the 128-bit data FIFO */ + UINT8 m_fifo[FIFO_SIZE]; + UINT8 m_fifo_head; + UINT8 m_fifo_tail; + UINT8 m_fifo_count; + UINT8 m_fifo_bits_taken; + + + /* these contain global status bits */ + UINT8 m_previous_TALK_STATUS; /* this is the OLD value of TALK_STATUS (i.e. previous value of m_SPEN|m_TALKD), needed for generating interrupts on a falling TALK_STATUS edge */ + UINT8 m_SPEN; /* set on speak(or speak external and BL falling edge) command, cleared on stop command, reset command, or buffer out */ + UINT8 m_DDIS; /* If 1, DDIS is 1, i.e. Speak External command in progress, writes go to FIFO. */ + UINT8 m_TALK; /* set on SPEN & RESETL4(pc12->pc0 transition), cleared on stop command or reset command */ +#define TALK_STATUS (m_SPEN|m_TALKD) + UINT8 m_TALKD; /* TALK(TCON) value, latched every RESETL4 */ + UINT8 m_buffer_low; /* If 1, FIFO has less than 8 bytes in it */ + UINT8 m_buffer_empty; /* If 1, FIFO is empty */ + UINT8 m_irq_pin; /* state of the IRQ pin (output) */ + UINT8 m_ready_pin; /* state of the READY pin (output) */ + + /* these contain data describing the current and previous voice frames */ +#define OLD_FRAME_SILENCE_FLAG m_OLDE // 1 if E=0, 0 otherwise. +#define OLD_FRAME_UNVOICED_FLAG m_OLDP // 1 if P=0 (unvoiced), 0 if voiced + UINT8 m_OLDE; + UINT8 m_OLDP; + +#define NEW_FRAME_STOP_FLAG (m_new_frame_energy_idx == 0xF) // 1 if this is a stop (Energy = 0xF) frame +#define NEW_FRAME_SILENCE_FLAG (m_new_frame_energy_idx == 0) // ditto as above +#define NEW_FRAME_UNVOICED_FLAG (m_new_frame_pitch_idx == 0) // ditto as above + UINT8 m_new_frame_energy_idx; + UINT8 m_new_frame_pitch_idx; + UINT8 m_new_frame_k_idx[10]; + + + /* these are all used to contain the current state of the sound generation */ +#ifndef PERFECT_INTERPOLATION_HACK + INT16 m_current_energy; + INT16 m_current_pitch; + INT16 m_current_k[10]; +#else + UINT8 m_old_frame_energy_idx; + UINT8 m_old_frame_pitch_idx; + UINT8 m_old_frame_k_idx[10]; + UINT8 m_old_zpar; + UINT8 m_old_uv_zpar; + + INT32 m_current_energy; + INT32 m_current_pitch; + INT32 m_current_k[10]; +#endif + + UINT16 m_previous_energy; /* needed for lattice filter to match patent */ + + UINT8 m_subcycle; /* contains the current subcycle for a given PC: 0 is A' (only used on SPKSLOW mode on 51xx), 1 is A, 2 is B */ + UINT8 m_subc_reload; /* contains 1 for normal speech, 0 when SPKSLOW is active */ + UINT8 m_PC; /* current parameter counter (what param is being interpolated), ranges from 0 to 12 */ + /* NOTE: the interpolation period counts 1,2,3,4,5,6,7,0 for divide by 8,8,8,4,4,2,2,1 */ + UINT8 m_IP; /* the current interpolation period */ + UINT8 m_inhibit; /* If 1, interpolation is inhibited until the DIV1 period */ + UINT8 m_uv_zpar; /* If 1, zero k5 thru k10 coefficients */ + UINT8 m_zpar; /* If 1, zero ALL parameters. */ + UINT8 m_pitch_zero; /* circuit 412; pitch is forced to zero under certain circumstances */ + UINT8 m_c_variant_rate; /* only relevant for tms5220C's multi frame rate feature; is the actual 4 bit value written on a 0x2* or 0x0* command */ + UINT16 m_pitch_count; /* pitch counter; provides chirp rom address */ + + INT32 m_u[11]; + INT32 m_x[10]; + + UINT16 m_RNG; /* the random noise generator configuration is: 1 + x + x^3 + x^4 + x^13 TODO: no it isn't */ + INT16 m_excitation_data; + + /* R Nabet : These have been added to emulate speech Roms */ + UINT8 m_schedule_dummy_read; /* set after each load address, so that next read operation is preceded by a dummy read */ + UINT8 m_data_register; /* data register, used by read command */ + UINT8 m_RDB_flag; /* whether we should read data register or status register */ + + /* The TMS52xx has two different ways of providing output data: the + analog speaker pin (which was usually used) and the Digital I/O pin. + The internal DAC used to feed the analog pin is only 8 bits, and has the + funny clipping/clamping logic, while the digital pin gives full 10 bit + resolution of the output data. + TODO: add a way to set/reset this other than the FORCE_DIGITAL define + */ + UINT8 m_digital_select; + + /* io_ready: page 3 of the datasheet specifies that READY will be asserted until + * data is available or processed by the system. + */ + UINT8 m_io_ready; + + /* flag for "true" timing involving rs/ws */ + UINT8 m_true_timing; + + /* rsws - state, rs bit 1, ws bit 0 */ + UINT8 m_rs_ws; + UINT8 m_read_latch; + UINT8 m_write_latch; + + sound_stream *m_stream; + int m_clock; + emu_timer *m_timer_io_ready; + + /* callbacks */ + devcb_write_line m_irq_handler; + devcb_write_line m_readyq_handler; + const char *m_speechrom_tag; + speechrom_device *m_speechrom; +}; + +extern const device_type TMS5220; + +class tms5220c_device : public tms5220_device +{ +public: + tms5220c_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +protected: + // device-level overrides + virtual void device_start(); +}; + +extern const device_type TMS5220C; + +class cd2501e_device : public tms5220_device +{ +public: + cd2501e_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +protected: + // device-level overrides + virtual void device_start(); +}; + +extern const device_type CD2501E; + +class tms5200_device : public tms5220_device +{ +public: + tms5200_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +protected: + // device-level overrides + virtual void device_start(); +}; + +extern const device_type TMS5200; + +class cd2501ecd_device : public tms5220_device +{ +public: + cd2501ecd_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +protected: + // device-level overrides + virtual void device_start(); +}; + +extern const device_type CD2501ECD; + +#endif diff --git a/src/devices/sound/tms5220.txt b/src/devices/sound/tms5220.txt new file mode 100644 index 00000000000..d7a8b1a178c --- /dev/null +++ b/src/devices/sound/tms5220.txt @@ -0,0 +1,86 @@ +***************************** + + TI TMS5220 Emulator + (c) Frank Palazzolo + Updated by Raphael Nabet + +***************************** + +The TI TMS5220 Speech chip uses Linear-Predictive decoding scheme to produce +speech from very compact data. This scheme is very similar to the U.S. +Federal Standard LPC-10e coding system, which was developed soon after +this chip. + +It is virtually identical to the chip used in the landmark "Speak 'N Spell" +toy produced in the '70s. + +Acknowledgements: +----------------- + +I would like to thank Larry Brantingham, the original designer of the chip, +for his technical help. + +I would also like to thank Neill Cortlett, who first showed that this chip +could be emulated in real-time in his Multi-Gauntlet Emulator. + +Theory of operation: +-------------------- + +The TI speech chip contains a 128-bit parallel-in, serial-out FIFO, a +10-pole digital lattice filter which models the vocal tract, and a D/A +converter. It was originally design to operate either with a microcomputer +interface, or with a serial speech ROM. The Speech ROM functionality is +now emulated, although no arcade games require it currently. + +The input data is writen a byte at a time into the chip, and it is +decoded bitwise into variable length frames. + +Possible Frame Types are as follows: + + Energy RF Pitch K1 K2 K3 K4 K5 K6 K7 K8 K9 K10 + ----------------------------------------------------------------- + +Silent 0000 +Stop 1111 +Repeat XXXX 1 XXXXXX +Unvoiced XXXX 0 000000 XXXXX XXXXX XXXX XXXX +Voiced XXXX 0 XXXXXX XXXXX XXXXX XXXX XXXX XXXX XXXX XXXX XXX XXX XXX + +Stop Frame: Stops the current speech +Repeat Frame: Uses the digital filter coefficients from the previous frame, + with new Energy and Pitch values +Unvoiced Frame: Uses Noise generator to feed 4 pole digital filter + (All other coefficients are set to zero) +Voiced Frame: Uses Pulse Generator to feed 10 pole digital filter + +All parameters (Energy, Pitch, K1-K10) are indexes into a lookup table for +actual values (see TMS5220R.c) + +K1-K10 are reflection coefficients for the lattice filter. + +Each frame is used to generate 200 samples, and 8 times during each frame, +(every 25 samples), these values are linearly interpolated to smooth out +frame transitions. + +The Noise generator is based on a shift-register type random-bit generator. +The Pulse generator is based on a lookup table. + +API: +---- + +TBD + +More: +----- + +For further technical info, the data sheet is floating around on the net. +(I believe the name is TMS.PDF) If you can't find a copy, email me and +I'll point you towards it. Feel free to contact me if you have a question. + +Frank Palazzolo + +palazzol@home.com + + + + diff --git a/src/devices/sound/upd7752.c b/src/devices/sound/upd7752.c new file mode 100644 index 00000000000..bebe180f722 --- /dev/null +++ b/src/devices/sound/upd7752.c @@ -0,0 +1,195 @@ +// license:BSD-3-Clause +// copyright-holders:Angelo Salese +/*************************************************************************** + +NEC uPD7752 Voice Synthesizing LSI + +skeleton device + +***************************************************************************/ + +#include "emu.h" +#include "sound/upd7752.h" + + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +// device type definition +const device_type UPD7752 = &device_creator; + +/* TODO: unknown exact size */ +static ADDRESS_MAP_START( upd7752_ram, AS_0, 8, upd7752_device ) +// AM_RANGE(0x0000, 0x7fff) AM_ROM + AM_RANGE(0x0000, 0xffff) AM_RAM +ADDRESS_MAP_END + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// upd7752_device - constructor +//------------------------------------------------- + +upd7752_device::upd7752_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, UPD7752, "uPD7752", tag, owner, clock, "upd7752", __FILE__), + device_sound_interface(mconfig, *this), + device_memory_interface(mconfig, *this), + m_space_config("ram", ENDIANNESS_LITTLE, 8, 16, 0, NULL, *ADDRESS_MAP_NAME(upd7752_ram)) +{ +} + + +//------------------------------------------------- +// memory_space_config - return a description of +// any address spaces owned by this device +//------------------------------------------------- + +const address_space_config *upd7752_device::memory_space_config(address_spacenum spacenum) const +{ + return (spacenum == AS_0) ? &m_space_config : NULL; +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void upd7752_device::device_start() +{ + /* TODO: clock */ + m_stream = stream_alloc(0, 1, clock() / 64); + + m_status = 0; +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void upd7752_device::device_reset() +{ +} + + +//------------------------------------------------- +// device_stop - device-specific stop +//------------------------------------------------- + +void upd7752_device::device_stop() +{ +} + +//------------------------------------------------- +// sound_stream_update - handle a stream update +//------------------------------------------------- + +void upd7752_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ +} + +//************************************************************************** +// INLINE HELPERS +//************************************************************************** + +inline UINT8 upd7752_device::readbyte(offs_t address) +{ + return space().read_byte(address); +} + +//------------------------------------------------- +// writebyte - write a byte at the given address +//------------------------------------------------- + +inline void upd7752_device::writebyte(offs_t address, UINT8 data) +{ + space().write_byte(address, data); +} + +//************************************************************************** +// READ/WRITE HANDLERS +//************************************************************************** + +void upd7752_device::status_change(UINT8 flag,bool type) +{ + if(type == true) + m_status |= flag; + else + m_status &= ~flag; +} + +READ8_MEMBER( upd7752_device::read ) +{ + switch(offset & 3) + { + //[0x00]: status register + //x--- ---- BSY busy status (1) processing (0) stopped + //-x-- ---- REQ audio parameter (1) input request (0) prohibited (???) + //--x- ---- ~INT / EXT message data (1) Outside (0) Inside + //---x ---- ERR error flag + case 0x00: return m_status; + //[0x02]: port 0xe2 latch? + case 0x02: return 0xff; + //[0x03]: port 0xe3 latch? + case 0x03: return 0xff; + } + return 0xff; +} + +WRITE8_MEMBER( upd7752_device::write ) +{ + switch(offset & 3) + { + // [0x00]: audio parameter transfer + case 0x00: + if(m_status & EXT) + { + /* + [0] xxxx x--- number of frames (times) to apply next table (N1) + ---- -x-- Quantized Magnification Data (QMAG) + ---- --x- Selective Interpolation Data (SI) + ---- ---x Voicing/Unvoicing Data (VU) + [1] xxxx ---- amp Voice source amplitude + ---- x--- Fricative Voice data + ---- -xxx Pitch + (repeat for N1 times) + if [0] & 0xf8 == 0 then command stop + */ + writebyte(m_ram_addr++,data); + } + //else + // ... + + break; + + // [0x02]: mode set + // ---- -x-- Frame periodic analysis (0) 10 ms / frame (1) 20 ms / frame + // ---- --xx Utterance (tempo?) speed + // 00 : NORMAL SPEED + // 01 : SLOW SPEED + // 10 : FAST SPEED + // 11 : Setting prohibited + + case 0x02: + m_mode = data & 7; + break; + + case 0x03: //command set + switch(data) + { + case 0xfe: // external message select cmd + status_change(EXT,true); + status_change(REQ,true); + //TODO: BSY flag too + m_ram_addr = 0; + break; + } + + break; + + } +} diff --git a/src/devices/sound/upd7752.h b/src/devices/sound/upd7752.h new file mode 100644 index 00000000000..eabd705e047 --- /dev/null +++ b/src/devices/sound/upd7752.h @@ -0,0 +1,78 @@ +// license:BSD-3-Clause +// copyright-holders:Angelo Salese +/*************************************************************************** + +Template for skeleton device + +***************************************************************************/ + +#pragma once + +#ifndef __UPD7752DEV_H__ +#define __UPD7752DEV_H__ + +/* status flags */ +#define BSY 1<<7 +#define REQ 1<<6 +#define EXT 1<<5 +#define ERR 1<<4 + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_UPD7752_ADD(_tag,_freq) \ + MCFG_DEVICE_ADD(_tag, UPD7752, _freq) + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> upd7752_device + +class upd7752_device : public device_t, + public device_sound_interface, + public device_memory_interface +{ +public: + // construction/destruction + upd7752_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // I/O operations + DECLARE_WRITE8_MEMBER( write ); + DECLARE_READ8_MEMBER( read ); + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_stop(); + virtual void device_reset(); + + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + +private: + sound_stream *m_stream; + const address_space_config m_space_config; + UINT8 m_status; + UINT16 m_ram_addr; + UINT8 m_mode; + void status_change(UINT8 flag,bool type); + inline UINT8 readbyte(offs_t address); + inline void writebyte(offs_t address, UINT8 data); +}; + + +// device type definition +extern const device_type UPD7752; + + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + + + +#endif diff --git a/src/devices/sound/upd7759.c b/src/devices/sound/upd7759.c new file mode 100644 index 00000000000..4b7d4e13a18 --- /dev/null +++ b/src/devices/sound/upd7759.c @@ -0,0 +1,874 @@ +// license:BSD-3-Clause +// copyright-holders:Juergen Buchmueller, Mike Balfour, Howie Cohen, Olivier Galibert, Aaron Giles +/************************************************************ + + NEC uPD7759/55/56/P56/57/58 ADPCM Speech Processor + by: Juergen Buchmueller, Mike Balfour, Howie Cohen, + Olivier Galibert, and Aaron Giles + + TODO: + - is there a doable method to dump the internal maskrom? :( + As far as we know, decapping is the only option + - low-level emulation + - watchdog? - according to uPD775x datasheet, the chip goes into standy mode + if CS/ST/RESET have not been accessed for more than 3 seconds + - convert to MAME modern device + +************************************************************* + + uPD7759 Description: + + The uPD7759 is a speech processing LSI that utilizes ADPCM to produce + speech or other sampled sounds. It can directly address up to 1Mbit + (128k) of external data ROM, or the host CPU can control the speech + data transfer. The uPD7759 is usually hooked up to a 640 kHz clock and + has one 8-bit input port, a start pin, a busy pin, and a clock output. + + The chip is composed of 3 parts: + - a clock divider + - a rom-reading engine + - an adpcm engine + - a 4-to-9 bit adpcm converter + + The clock divider takes the base 640KHz clock and divides it first + by a fixed divisor of 4 and then by a value between 9 and 32. The + result gives a clock between 5KHz and 17.78KHz. It's probably + possible, but not recommended and certainly out-of-spec, to push the + chip harder by reducing the divider. + + The rom-reading engine reads one byte every two divided clock cycles. + The factor two comes from the fact that a byte has two nibbles, i.e. + two samples. + + The apdcm engine takes bytes and interprets them as commands: + + 00000000 sample end + 00dddddd silence + 01ffffff send the 256 following nibbles to the converter + 10ffffff nnnnnnnn send the n+1 following nibbles to the converter + 11---rrr --ffffff nnnnnnnn send the n+1 following nibbles to the converter, and repeat r+1 times + + "ffffff" is sent to the clock divider to be the base clock for the + adpcm converter, i.e., it's the sampling rate. If the number of + nibbles to send is odd the last nibble is ignored. The commands + are always 8-bit aligned. + + "dddddd" is the duration of the silence. The base speed is unknown, + 1ms sounds reasonably. It does not seem linked to the adpcm clock + speed because there often is a silence before any 01 or 10 command. + + The adpcm converter converts nibbles into 9-bit DAC values. It has + an internal state of 4 bits that's used in conjunction with the + nibble to lookup which of the 256 possible steps is used. Then + the state is changed according to the nibble value. Essentially, the + higher the state, the bigger the steps are, and using big steps + increase the state. Conversely, using small steps reduces the state. + This allows the engine to be a little more adaptative than a + classical ADPCM algorithm. + + The uPD7759 can run in two modes, master (also known as standalone) + and slave. The mode is selected through the "md" pin. No known + game changes modes on the fly, and it's unsure if that's even + possible to do. + + + Master mode: + + The output of the rom reader is directly connected to the adpcm + converter. The controlling cpu only sends a sample number and the + 7759 plays it. + + The sample rom has a header at the beginning of the form + + nn 5a a5 69 55 + + where nn is the number of the last sample. This is then followed by + a vector of 2-bytes msb-first values, one per sample. Multiplying + them by two gives the sample start offset in the rom. A 0x00 marks + the end of each sample. + + It seems that the uPD7759 reads at least part of the rom header at + startup. Games doing rom banking are careful to reset the chip after + each change. + + + Slave mode: + + The rom reader is completely disconnected. The input port is + connected directly to the adpcm engine. The first write to the input + port activates the engine (the value itself is ignored). The engine + activates the clock output and waits for commands. The clock speed + is unknown, but its probably a divider of 640KHz. We use 40KHz here + because 80KHz crashes altbeast. The chip probably has an internal + fifo to the converter and suspends the clock when the fifo is full. + The first command is always 0xFF. A second 0xFF marks the end of the + sample and the engine stops. OTOH, there is a 0x00 at the end too. + Go figure. + +************************************************************* + + The other chip models don't support slave mode, and have an internal ROM. + Other than that, they are thought to be nearly identical to uPD7759. + + 55C 18-pin DIP 96 Kbit ROM + 55G 24-pin SOP 96 Kbit ROM + 56C 18-pin DIP 256 Kbit ROM + 56G 24-pin SOP 256 Kbit ROM + P56CR 20-pin DIP 256 Kbit ROM (OTP) - dumping the ROM is trivial + P56G 24-pin SOP 256 Kbit ROM (OTP) - " + 57C 18-pin DIP 512 Kbit ROM + 57G 24-pin SOP 512 Kbit ROM + 58C 18-pin DIP 1 Mbit ROM + 58G 24-pin SOP 1 Mbit ROM + +*************************************************************/ + +#include "emu.h" +#include "upd7759.h" + + +#define DEBUG_STATES (0) +#define DEBUG_METHOD osd_printf_debug + + + +/************************************************************ + + Constants + +*************************************************************/ + +/* step value fractional bits */ +#define FRAC_BITS 20 +#define FRAC_ONE (1 << FRAC_BITS) +#define FRAC_MASK (FRAC_ONE - 1) + + +upd775x_device::upd775x_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_sound_interface(mconfig, *this), + m_channel(NULL), + m_sample_offset_shift(0), + m_pos(0), + m_step(0), + m_fifo_in(0), + m_reset(0), + m_start(0), + m_drq(0), + m_state(0), + m_clocks_left(0), + m_nibbles_left(0), + m_repeat_count(0), + m_post_drq_state(0), + m_post_drq_clocks(0), + m_req_sample(0), + m_last_sample(0), + m_block_header(0), + m_sample_rate(0), + m_first_valid_header(0), + m_offset(0), + m_repeat_offset(0), + m_adpcm_state(0), + m_adpcm_data(0), + m_sample(0), + m_rom(NULL), + m_rombase(NULL), + m_romoffset(0), + m_rommask(0), + m_drqcallback(*this) +{ +} + +const device_type UPD7759 = &device_creator; + +upd7759_device::upd7759_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : upd775x_device(mconfig, UPD7759, "uPD7759", tag, owner, clock, "upd7759", __FILE__), + m_timer(NULL) +{ +} + + +upd7759_device::upd7759_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : upd775x_device(mconfig, type, name, tag, owner, clock, shortname, source), + m_timer(NULL) +{ +} + + +const device_type UPD7756 = &device_creator; + +upd7756_device::upd7756_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : upd775x_device(mconfig, UPD7756, "uPD7756", tag, owner, clock, "upd7756", __FILE__) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void upd775x_device::device_start() +{ +} + +void upd7759_device::device_start() +{ + m_drqcallback.resolve_safe(); + + /* chip configuration */ + m_sample_offset_shift = (type() == UPD7759) ? 1 : 0; + + /* allocate a stream channel */ + m_channel = machine().sound().stream_alloc(*this, 0, 1, clock()/4); + + /* compute the stepping rate based on the chip's clock speed */ + m_step = 4 * FRAC_ONE; + + /* compute the clock period */ + m_clock_period = attotime::from_hz(clock()); + + /* set the intial state */ + m_state = STATE_IDLE; + + /* compute the ROM base or allocate a timer */ + m_romoffset = 0; + m_rom = m_rombase = region()->base(); + if (m_rombase == NULL) + { + assert(type() == UPD7759); // other chips do not support slave mode + m_timer = timer_alloc(TIMER_SLAVE_UPDATE); + m_rommask = 0; + } + else + { + UINT32 romsize = region()->bytes(); + if (romsize >= 0x20000) m_rommask = 0x1ffff; + else m_rommask = romsize - 1; + + m_drqcallback.set_callback(DEVCB_NULL); + } + + /* assume /RESET and /START are both high */ + m_reset = 1; + m_start = 1; + + /* toggle the reset line to finish the reset */ + device_reset(); + + save_item(NAME(m_pos)); + save_item(NAME(m_step)); + + save_item(NAME(m_fifo_in)); + save_item(NAME(m_reset)); + save_item(NAME(m_start)); + save_item(NAME(m_drq)); + + save_item(NAME(m_state)); + save_item(NAME(m_clocks_left)); + save_item(NAME(m_nibbles_left)); + save_item(NAME(m_repeat_count)); + save_item(NAME(m_post_drq_state)); + save_item(NAME(m_post_drq_clocks)); + save_item(NAME(m_req_sample)); + save_item(NAME(m_last_sample)); + save_item(NAME(m_block_header)); + save_item(NAME(m_sample_rate)); + save_item(NAME(m_first_valid_header)); + save_item(NAME(m_offset)); + save_item(NAME(m_repeat_offset)); + + save_item(NAME(m_adpcm_state)); + save_item(NAME(m_adpcm_data)); + save_item(NAME(m_sample)); + + save_item(NAME(m_romoffset)); + machine().save().register_postload(save_prepost_delegate(FUNC(upd7759_device::postload), this)); +} + + +void upd7756_device::device_start() +{ + m_drqcallback.resolve_safe(); + + /* chip configuration */ + m_sample_offset_shift = (type() == UPD7759) ? 1 : 0; + + /* allocate a stream channel */ + m_channel = machine().sound().stream_alloc(*this, 0, 1, clock()/4); + + /* compute the stepping rate based on the chip's clock speed */ + m_step = 4 * FRAC_ONE; + + /* compute the clock period */ + m_clock_period = attotime::from_hz(clock()); + + /* set the intial state */ + m_state = STATE_IDLE; + + /* compute the ROM base or allocate a timer */ + m_romoffset = 0; + m_rom = m_rombase = region()->base(); + if (m_rombase == NULL) + { + m_rommask = 0; + } + else + { + UINT32 romsize = region()->bytes(); + if (romsize >= 0x20000) m_rommask = 0x1ffff; + else m_rommask = romsize - 1; + + m_drqcallback.set_callback(DEVCB_NULL); + } + + /* assume /RESET and /START are both high */ + m_reset = 1; + m_start = 1; + + /* toggle the reset line to finish the reset */ + device_reset(); + + save_item(NAME(m_pos)); + save_item(NAME(m_step)); + + save_item(NAME(m_fifo_in)); + save_item(NAME(m_reset)); + save_item(NAME(m_start)); + save_item(NAME(m_drq)); + + save_item(NAME(m_state)); + save_item(NAME(m_clocks_left)); + save_item(NAME(m_nibbles_left)); + save_item(NAME(m_repeat_count)); + save_item(NAME(m_post_drq_state)); + save_item(NAME(m_post_drq_clocks)); + save_item(NAME(m_req_sample)); + save_item(NAME(m_last_sample)); + save_item(NAME(m_block_header)); + save_item(NAME(m_sample_rate)); + save_item(NAME(m_first_valid_header)); + save_item(NAME(m_offset)); + save_item(NAME(m_repeat_offset)); + + save_item(NAME(m_adpcm_state)); + save_item(NAME(m_adpcm_data)); + save_item(NAME(m_sample)); + + save_item(NAME(m_romoffset)); + machine().save().register_postload(save_prepost_delegate(FUNC(upd7759_device::postload), this)); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void upd775x_device::device_reset() +{ +} + +void upd7759_device::device_reset() +{ + m_pos = 0; + m_fifo_in = 0; + m_drq = 0; + m_state = STATE_IDLE; + m_clocks_left = 0; + m_nibbles_left = 0; + m_repeat_count = 0; + m_post_drq_state = STATE_IDLE; + m_post_drq_clocks = 0; + m_req_sample = 0; + m_last_sample = 0; + m_block_header = 0; + m_sample_rate = 0; + m_first_valid_header = 0; + m_offset = 0; + m_repeat_offset = 0; + m_adpcm_state = 0; + m_adpcm_data = 0; + m_sample = 0; + + /* turn off any timer */ + if (m_timer) + m_timer->adjust(attotime::never); +} + +void upd7756_device::device_reset() +{ + m_pos = 0; + m_fifo_in = 0; + m_drq = 0; + m_state = STATE_IDLE; + m_clocks_left = 0; + m_nibbles_left = 0; + m_repeat_count = 0; + m_post_drq_state = STATE_IDLE; + m_post_drq_clocks = 0; + m_req_sample = 0; + m_last_sample = 0; + m_block_header = 0; + m_sample_rate = 0; + m_first_valid_header = 0; + m_offset = 0; + m_repeat_offset = 0; + m_adpcm_state = 0; + m_adpcm_data = 0; + m_sample = 0; +} + + +/************************************************************ + + Local variables + +*************************************************************/ + +static const int upd775x_step[16][16] = +{ + { 0, 0, 1, 2, 3, 5, 7, 10, 0, 0, -1, -2, -3, -5, -7, -10 }, + { 0, 1, 2, 3, 4, 6, 8, 13, 0, -1, -2, -3, -4, -6, -8, -13 }, + { 0, 1, 2, 4, 5, 7, 10, 15, 0, -1, -2, -4, -5, -7, -10, -15 }, + { 0, 1, 3, 4, 6, 9, 13, 19, 0, -1, -3, -4, -6, -9, -13, -19 }, + { 0, 2, 3, 5, 8, 11, 15, 23, 0, -2, -3, -5, -8, -11, -15, -23 }, + { 0, 2, 4, 7, 10, 14, 19, 29, 0, -2, -4, -7, -10, -14, -19, -29 }, + { 0, 3, 5, 8, 12, 16, 22, 33, 0, -3, -5, -8, -12, -16, -22, -33 }, + { 1, 4, 7, 10, 15, 20, 29, 43, -1, -4, -7, -10, -15, -20, -29, -43 }, + { 1, 4, 8, 13, 18, 25, 35, 53, -1, -4, -8, -13, -18, -25, -35, -53 }, + { 1, 6, 10, 16, 22, 31, 43, 64, -1, -6, -10, -16, -22, -31, -43, -64 }, + { 2, 7, 12, 19, 27, 37, 51, 76, -2, -7, -12, -19, -27, -37, -51, -76 }, + { 2, 9, 16, 24, 34, 46, 64, 96, -2, -9, -16, -24, -34, -46, -64, -96 }, + { 3, 11, 19, 29, 41, 57, 79, 117, -3, -11, -19, -29, -41, -57, -79, -117 }, + { 4, 13, 24, 36, 50, 69, 96, 143, -4, -13, -24, -36, -50, -69, -96, -143 }, + { 4, 16, 29, 44, 62, 85, 118, 175, -4, -16, -29, -44, -62, -85, -118, -175 }, + { 6, 20, 36, 54, 76, 104, 144, 214, -6, -20, -36, -54, -76, -104, -144, -214 }, +}; + +static const int upd775x_state_table[16] = { -1, -1, 0, 0, 1, 2, 2, 3, -1, -1, 0, 0, 1, 2, 2, 3 }; + + +/************************************************************ + + ADPCM sample updater + +*************************************************************/ + +void upd775x_device::update_adpcm(int data) +{ + /* update the sample and the state */ + m_sample += upd775x_step[m_adpcm_state][data]; + m_adpcm_state += upd775x_state_table[data]; + + /* clamp the state to 0..15 */ + if (m_adpcm_state < 0) + m_adpcm_state = 0; + else if (m_adpcm_state > 15) + m_adpcm_state = 15; +} + + + +/************************************************************ + + Master chip state machine + +*************************************************************/ + +void upd775x_device::advance_state() +{ + switch (m_state) + { + /* Idle state: we stick around here while there's nothing to do */ + case STATE_IDLE: + m_clocks_left = 4; + break; + + /* drop DRQ state: update to the intended state */ + case STATE_DROP_DRQ: + m_drq = 0; + + m_clocks_left = m_post_drq_clocks; + m_state = m_post_drq_state; + break; + + /* Start state: we begin here as soon as a sample is triggered */ + case STATE_START: + m_req_sample = m_rom ? m_fifo_in : 0x10; + if (DEBUG_STATES) DEBUG_METHOD("uPD7759: req_sample = %02X\n", m_req_sample); + + /* 35+ cycles after we get here, the /DRQ goes low + * (first byte (number of samples in ROM) should be sent in response) + * + * (35 is the minimum number of cycles I found during heavy tests. + * Depending on the state the chip was in just before the /MD was set to 0 (reset, standby + * or just-finished-playing-previous-sample) this number can range from 35 up to ~24000). + * It also varies slightly from test to test, but not much - a few cycles at most.) */ + m_clocks_left = 70; /* 35 - breaks cotton */ + m_state = STATE_FIRST_REQ; + break; + + /* First request state: issue a request for the first byte */ + /* The expected response will be the index of the last sample */ + case STATE_FIRST_REQ: + if (DEBUG_STATES) DEBUG_METHOD("uPD7759: first data request\n"); + m_drq = 1; + + /* 44 cycles later, we will latch this value and request another byte */ + m_clocks_left = 44; + m_state = STATE_LAST_SAMPLE; + break; + + /* Last sample state: latch the last sample value and issue a request for the second byte */ + /* The second byte read will be just a dummy */ + case STATE_LAST_SAMPLE: + m_last_sample = m_rom ? m_rom[0] : m_fifo_in; + if (DEBUG_STATES) DEBUG_METHOD("uPD7759: last_sample = %02X, requesting dummy 1\n", m_last_sample); + m_drq = 1; + + /* 28 cycles later, we will latch this value and request another byte */ + m_clocks_left = 28; /* 28 - breaks cotton */ + m_state = (m_req_sample > m_last_sample) ? STATE_IDLE : STATE_DUMMY1; + break; + + /* First dummy state: ignore any data here and issue a request for the third byte */ + /* The expected response will be the MSB of the sample address */ + case STATE_DUMMY1: + if (DEBUG_STATES) DEBUG_METHOD("uPD7759: dummy1, requesting offset_hi\n"); + m_drq = 1; + + /* 32 cycles later, we will latch this value and request another byte */ + m_clocks_left = 32; + m_state = STATE_ADDR_MSB; + break; + + /* Address MSB state: latch the MSB of the sample address and issue a request for the fourth byte */ + /* The expected response will be the LSB of the sample address */ + case STATE_ADDR_MSB: + m_offset = (m_rom ? m_rom[m_req_sample * 2 + 5] : m_fifo_in) << (8 + m_sample_offset_shift); + if (DEBUG_STATES) DEBUG_METHOD("uPD7759: offset_hi = %02X, requesting offset_lo\n", m_offset >> (8 + m_sample_offset_shift)); + m_drq = 1; + + /* 44 cycles later, we will latch this value and request another byte */ + m_clocks_left = 44; + m_state = STATE_ADDR_LSB; + break; + + /* Address LSB state: latch the LSB of the sample address and issue a request for the fifth byte */ + /* The expected response will be just a dummy */ + case STATE_ADDR_LSB: + m_offset |= (m_rom ? m_rom[m_req_sample * 2 + 6] : m_fifo_in) << m_sample_offset_shift; + if (DEBUG_STATES) DEBUG_METHOD("uPD7759: offset_lo = %02X, requesting dummy 2\n", (m_offset >> m_sample_offset_shift) & 0xff); + if (m_offset > m_rommask) logerror("uPD7759 offset %X > rommask %X\n",m_offset, m_rommask); + m_drq = 1; + + /* 36 cycles later, we will latch this value and request another byte */ + m_clocks_left = 36; + m_state = STATE_DUMMY2; + break; + + /* Second dummy state: ignore any data here and issue a request for the sixth byte */ + /* The expected response will be the first block header */ + case STATE_DUMMY2: + m_offset++; + m_first_valid_header = 0; + if (DEBUG_STATES) DEBUG_METHOD("uPD7759: dummy2, requesting block header\n"); + m_drq = 1; + + /* 36?? cycles later, we will latch this value and request another byte */ + m_clocks_left = 36; + m_state = STATE_BLOCK_HEADER; + break; + + /* Block header state: latch the header and issue a request for the first byte afterwards */ + case STATE_BLOCK_HEADER: + + /* if we're in a repeat loop, reset the offset to the repeat point and decrement the count */ + if (m_repeat_count) + { + m_repeat_count--; + m_offset = m_repeat_offset; + } + m_block_header = m_rom ? m_rom[m_offset++ & m_rommask] : m_fifo_in; + if (DEBUG_STATES) DEBUG_METHOD("uPD7759: header (@%05X) = %02X, requesting next byte\n", m_offset, m_block_header); + m_drq = 1; + + /* our next step depends on the top two bits */ + switch (m_block_header & 0xc0) + { + case 0x00: /* silence */ + m_clocks_left = 1024 * ((m_block_header & 0x3f) + 1); + m_state = (m_block_header == 0 && m_first_valid_header) ? STATE_IDLE : STATE_BLOCK_HEADER; + m_sample = 0; + m_adpcm_state = 0; + break; + + case 0x40: /* 256 nibbles */ + m_sample_rate = (m_block_header & 0x3f) + 1; + m_nibbles_left = 256; + m_clocks_left = 36; /* just a guess */ + m_state = STATE_NIBBLE_MSN; + break; + + case 0x80: /* n nibbles */ + m_sample_rate = (m_block_header & 0x3f) + 1; + m_clocks_left = 36; /* just a guess */ + m_state = STATE_NIBBLE_COUNT; + break; + + case 0xc0: /* repeat loop */ + m_repeat_count = (m_block_header & 7) + 1; + m_repeat_offset = m_offset; + m_clocks_left = 36; /* just a guess */ + m_state = STATE_BLOCK_HEADER; + break; + } + + /* set a flag when we get the first non-zero header */ + if (m_block_header != 0) + m_first_valid_header = 1; + break; + + /* Nibble count state: latch the number of nibbles to play and request another byte */ + /* The expected response will be the first data byte */ + case STATE_NIBBLE_COUNT: + m_nibbles_left = (m_rom ? m_rom[m_offset++ & m_rommask] : m_fifo_in) + 1; + if (DEBUG_STATES) DEBUG_METHOD("uPD7759: nibble_count = %u, requesting next byte\n", (unsigned)m_nibbles_left); + m_drq = 1; + + /* 36?? cycles later, we will latch this value and request another byte */ + m_clocks_left = 36; /* just a guess */ + m_state = STATE_NIBBLE_MSN; + break; + + /* MSN state: latch the data for this pair of samples and request another byte */ + /* The expected response will be the next sample data or another header */ + case STATE_NIBBLE_MSN: + m_adpcm_data = m_rom ? m_rom[m_offset++ & m_rommask] : m_fifo_in; + update_adpcm(m_adpcm_data >> 4); + m_drq = 1; + + /* we stay in this state until the time for this sample is complete */ + m_clocks_left = m_sample_rate * 4; + if (--m_nibbles_left == 0) + m_state = STATE_BLOCK_HEADER; + else + m_state = STATE_NIBBLE_LSN; + break; + + /* LSN state: process the lower nibble */ + case STATE_NIBBLE_LSN: + update_adpcm(m_adpcm_data & 15); + + /* we stay in this state until the time for this sample is complete */ + m_clocks_left = m_sample_rate * 4; + if (--m_nibbles_left == 0) + m_state = STATE_BLOCK_HEADER; + else + m_state = STATE_NIBBLE_MSN; + break; + } + + /* if there's a DRQ, fudge the state */ + if (m_drq) + { + m_post_drq_state = m_state; + m_post_drq_clocks = m_clocks_left - 21; + m_state = STATE_DROP_DRQ; + m_clocks_left = 21; + } +} + +/************************************************************ + + DRQ callback + +*************************************************************/ + +void upd7759_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + UINT8 olddrq = m_drq; + + switch (id) + { + case TIMER_SLAVE_UPDATE: + + /* update the stream */ + m_channel->update(); + + /* advance the state */ + advance_state(); + + /* if the DRQ changed, update it */ + logerror("upd7759_slave_update: DRQ %d->%d\n", olddrq, m_drq); + if (olddrq != m_drq) + m_drqcallback(m_drq); + + /* set a timer to go off when that is done */ + if (m_state != STATE_IDLE) + m_timer->adjust(m_clock_period * m_clocks_left); + break; + + default: + assert_always(FALSE, "Unknown id in upd7759_device::device_timer"); + } +} + +/************************************************************ + + Sound startup + +*************************************************************/ + +void upd775x_device::postload() +{ + if (m_rombase) + m_rom = m_rombase + m_romoffset; +} + +/************************************************************ + + I/O handlers + +*************************************************************/ + +WRITE_LINE_MEMBER( upd775x_device::reset_w ) +{ + /* update the reset value */ + UINT8 oldreset = m_reset; + m_reset = (state != 0); + + /* update the stream first */ + m_channel->update(); + + /* on the falling edge, reset everything */ + if (oldreset && !m_reset) + device_reset(); +} + +WRITE_LINE_MEMBER( upd7759_device::start_w ) +{ + /* update the start value */ + UINT8 oldstart = m_start; + m_start = (state != 0); + + logerror("upd7759_start_w: %d->%d\n", oldstart, m_start); + + /* update the stream first */ + m_channel->update(); + + /* on the rising edge, if we're idle, start going, but not if we're held in reset */ + if (m_state == STATE_IDLE && !oldstart && m_start && m_reset) + { + m_state = STATE_START; + + /* for slave mode, start the timer going */ + if (m_timer) + m_timer->adjust(attotime::zero); + } +} + +WRITE_LINE_MEMBER( upd7756_device::start_w ) +{ + /* update the start value */ + UINT8 oldstart = m_start; + m_start = (state != 0); + + logerror("upd7759_start_w: %d->%d\n", oldstart, m_start); + + /* update the stream first */ + m_channel->update(); + + /* on the rising edge, if we're idle, start going, but not if we're held in reset */ + if (m_state == STATE_IDLE && !oldstart && m_start && m_reset) + { + m_state = STATE_START; + } +} + + +WRITE8_MEMBER( upd775x_device::port_w ) +{ + /* update the FIFO value */ + m_fifo_in = data; +} + + +READ_LINE_MEMBER( upd775x_device::busy_r ) +{ + /* return /BUSY */ + return (m_state == STATE_IDLE); +} + + +void upd775x_device::set_bank_base(UINT32 base) +{ + assert(m_rombase != NULL); + m_rom = m_rombase + base; + m_romoffset = base; +} + +//------------------------------------------------- +// sound_stream_update - handle a stream update +//------------------------------------------------- + +void upd775x_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + INT32 clocks_left = m_clocks_left; + INT16 sample = m_sample; + UINT32 step = m_step; + UINT32 pos = m_pos; + stream_sample_t *buffer = outputs[0]; + + /* loop until done */ + if (m_state != STATE_IDLE) + while (samples != 0) + { + /* store the current sample */ + *buffer++ = sample << 7; + samples--; + + /* advance by the number of clocks/output sample */ + pos += step; + + /* handle clocks, but only in standalone mode */ + while (m_rom && pos >= FRAC_ONE) + { + int clocks_this_time = pos >> FRAC_BITS; + if (clocks_this_time > clocks_left) + clocks_this_time = clocks_left; + + /* clock once */ + pos -= clocks_this_time * FRAC_ONE; + clocks_left -= clocks_this_time; + + /* if we're out of clocks, time to handle the next state */ + if (clocks_left == 0) + { + /* advance one state; if we hit idle, bail */ + advance_state(); + if (m_state == STATE_IDLE) + break; + + /* reimport the variables that we cached */ + clocks_left = m_clocks_left; + sample = m_sample; + } + } + } + + /* if we got out early, just zap the rest of the buffer */ + if (samples != 0) + memset(buffer, 0, samples * sizeof(*buffer)); + + /* flush the state back */ + m_clocks_left = clocks_left; + m_pos = pos; +} + +void upd7759_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + upd775x_device::sound_stream_update(stream, inputs, outputs, samples); +} + +void upd7756_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + upd775x_device::sound_stream_update(stream, inputs, outputs, samples); +} diff --git a/src/devices/sound/upd7759.h b/src/devices/sound/upd7759.h new file mode 100644 index 00000000000..94286e7cd57 --- /dev/null +++ b/src/devices/sound/upd7759.h @@ -0,0 +1,151 @@ +// license:BSD-3-Clause +// copyright-holders:Juergen Buchmueller, Mike Balfour, Howie Cohen, Olivier Galibert, Aaron Giles +#pragma once + +#ifndef __UPD7759_H__ +#define __UPD7759_H__ + +/* chip states */ +enum +{ + STATE_IDLE, + STATE_DROP_DRQ, + STATE_START, + STATE_FIRST_REQ, + STATE_LAST_SAMPLE, + STATE_DUMMY1, + STATE_ADDR_MSB, + STATE_ADDR_LSB, + STATE_DUMMY2, + STATE_BLOCK_HEADER, + STATE_NIBBLE_COUNT, + STATE_NIBBLE_MSN, + STATE_NIBBLE_LSN +}; + +/* NEC uPD7759/55/56/P56/57/58 ADPCM Speech Processor */ + +/* There are two modes for the uPD7759, selected through the !MD pin. + This is the mode select input. High is stand alone, low is slave. + We're making the assumption that nobody switches modes through + software. +*/ + +#define UPD7759_STANDARD_CLOCK XTAL_640kHz + +class upd775x_device : public device_t, + public device_sound_interface +{ +public: + upd775x_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + ~upd775x_device() {} + + template static devcb_base &set_drq_callback(device_t &device, _Object object) { return downcast(device).m_drqcallback.set_callback(object); } + + void set_bank_base(offs_t base); + + DECLARE_WRITE_LINE_MEMBER( reset_w ); + DECLARE_READ_LINE_MEMBER( busy_r ); + virtual DECLARE_WRITE8_MEMBER( port_w ); + void postload(); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // sound stream update overrides + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + + // internal state + sound_stream *m_channel; /* stream channel for playback */ + + /* chip configuration */ + UINT8 m_sample_offset_shift; /* header sample address shift (access data > 0xffff) */ + + /* internal clock to output sample rate mapping */ + UINT32 m_pos; /* current output sample position */ + UINT32 m_step; /* step value per output sample */ + attotime m_clock_period; /* clock period */ + + /* I/O lines */ + UINT8 m_fifo_in; /* last data written to the sound chip */ + UINT8 m_reset; /* current state of the RESET line */ + UINT8 m_start; /* current state of the START line */ + UINT8 m_drq; /* current state of the DRQ line */ + + /* internal state machine */ + INT8 m_state; /* current overall chip state */ + INT32 m_clocks_left; /* number of clocks left in this state */ + UINT16 m_nibbles_left; /* number of ADPCM nibbles left to process */ + UINT8 m_repeat_count; /* number of repeats remaining in current repeat block */ + INT8 m_post_drq_state; /* state we will be in after the DRQ line is dropped */ + INT32 m_post_drq_clocks; /* clocks that will be left after the DRQ line is dropped */ + UINT8 m_req_sample; /* requested sample number */ + UINT8 m_last_sample; /* last sample number available */ + UINT8 m_block_header; /* header byte */ + UINT8 m_sample_rate; /* number of UPD clocks per ADPCM nibble */ + UINT8 m_first_valid_header; /* did we get our first valid header yet? */ + UINT32 m_offset; /* current ROM offset */ + UINT32 m_repeat_offset; /* current ROM repeat offset */ + + /* ADPCM processing */ + INT8 m_adpcm_state; /* ADPCM state index */ + UINT8 m_adpcm_data; /* current byte of ADPCM data */ + INT16 m_sample; /* current sample value */ + + /* ROM access */ + UINT8 * m_rom; /* pointer to ROM data or NULL for slave mode */ + UINT8 * m_rombase; /* pointer to ROM data or NULL for slave mode */ + UINT32 m_romoffset; /* ROM offset to make save/restore easier */ + UINT32 m_rommask; /* maximum address offset */ + + devcb_write_line m_drqcallback; + + void update_adpcm(int data); + virtual void advance_state(); +}; + +class upd7759_device : public upd775x_device +{ +public: + upd7759_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + upd7759_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + enum + { + TIMER_SLAVE_UPDATE + }; + + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + + emu_timer *m_timer; /* timer */ + + DECLARE_WRITE_LINE_MEMBER( start_w ); +}; + +class upd7756_device : public upd775x_device +{ +public: + upd7756_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual void device_start(); + virtual void device_reset(); + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + + DECLARE_WRITE_LINE_MEMBER( start_w ); +}; + +extern const device_type UPD7759; +extern const device_type UPD7756; + +#define MCFG_UPD7759_DRQ_CALLBACK(_write) \ + devcb = &upd7759_device::set_drq_callback(*device, DEVCB_##_write); + +#define MCFG_UPD7756_DRQ_CALLBACK(_write) \ + devcb = &upd7756_device::set_drq_callback(*device, DEVCB_##_write); + +#endif /* __UPD7759_H__ */ diff --git a/src/devices/sound/vlm5030.c b/src/devices/sound/vlm5030.c new file mode 100644 index 00000000000..6a66cfab937 --- /dev/null +++ b/src/devices/sound/vlm5030.c @@ -0,0 +1,655 @@ +// license:BSD-3-Clause +// copyright-holders:Tatsuyuki Satoh +/* + vlm5030.c + + Sanyo VLM5030 emulator + + Written by Tatsuyuki Satoh + Based on TMS5220 simulator (tms5220.c) + + +-------,_,-------+ + GND -- | 1 40 | <- RST + (gnd) TST1 -> | 2 39 | ?? TST4 + OSC2 ck | 3 _ 38 | ?? TST3 + OSC1 ck | 4 (_) 37 | ?? TST2 + D0 -> | 5 36 | -> DAO + D1 -> | 6 35 | -- VREF (+5v through 5.6k resistor) + D2 -> | 7 34 | -> MTE + D3 -> | 8 V 33 | -> /ME + D4 -> | 9 L 32 | <- VCU + D5 -> | 10 M 31 | <- START + D6 -> | 11 5 30 | -> BSY + D7 -> | 12 0 29 | -- Vdd (+5v) + A0 <- | 13 3 28 | -> A15 + A1 <- | 14 0 27 | -> A14 + A2 <- | 15 26 | -> A13 + A3 <- | 16 _ 25 | -> A12 + A4 <- | 17 (_) 24 | -> A11 + A5 <- | 18 23 | -> A10 + A6 <- | 19 22 | -> A9 + A7 <- | 20 21 | -> A8 + +-----------------+ + +TST1 is probably a test mode enable pin, must be grounded for normal operation. +TST2-4 are some sort of test pins but can be left floating? +VREF is probably the 0v ref for the output dac +DAO is the output dac +/ME is connected to the voice data rom /OE enable +START strobes in a byte of data over the data bus from host cpu +OSC1/2 are to both ends of a 3.579545MHz xtal with a 100pf cap from each end to gnd +VCU makes the data bus select the upper 8 bits of the word register internally instead of the lower 8 bits. it is only useful if you need more than 256 phrases in rom? (recheck this) +MTE is an output for roms which need to be clocked to latch address before use, or for a latch sitting in front of the voice rom address lines? (recheck this) +RST not only resets the chip on its rising edge but grabs a byte of mode state data from the data bus on its falling edge? (recheck this) + + note: + memory read cycle(==sampling rate) = 122.9u(440clock) + interpolator (LC8109 = 2.5ms) = 20 * samples(125us) + frame time (20ms) = 4 * interpolator + 9bit DAC is composed of 5bit Physical and 3bitPWM. + + todo: + Noise Generator circuit without 'machine.rand()' function. + +----------- command format (Analytical result) ---------- + +1)end of speech (8bit) +:00000011: + +2)silent some frame (8bit) +:????SS01: + +SS : number of silent frames + 00 = 2 frame + 01 = 4 frame + 10 = 6 frame + 11 = 8 frame + +3)-speech frame (48bit) +function: 6th : 5th : 4th : 3rd : 2nd : 1st : +end : --- : --- : --- : --- : --- :00000011: +silent : --- : --- : --- : --- : --- :0000SS01: +speech :11111122:22233334:44455566:67778889:99AAAEEE:EEPPPPP0: + +EEEEE : energy : volume 0=off,0x1f=max +PPPPP : pitch : 0=noize , 1=fast,0x1f=slow +111111 : K1 : 48=off +22222 : K2 : 0=off,1=+min,0x0f=+max,0x10=off,0x11=+max,0x1f=-min + : 16 == special function?? +3333 : K3 : 0=off,1=+min,0x07=+max,0x08=-max,0x0f=-min +4444 : K4 : +555 : K5 : 0=off,1=+min,0x03=+max,0x04=-max,0x07=-min +666 : K6 : +777 : K7 : +888 : K8 : +999 : K9 : +AAA : K10 : + + ---------- chirp table information ---------- + +DAC PWM cycle == 88system clock , (11clock x 8 pattern) = 40.6KHz +one chirp == 5 x PWM cycle == 440systemclock(8,136Hz) + +chirp 0 : volume 10- 8 : with filter +chirp 1 : volume 8- 6 : with filter +chirp 2 : volume 6- 4 : with filter +chirp 3 : volume 4 : no filter ?? +chirp 4- 5: volume 4- 2 : with filter +chirp 6-11: volume 2- 0 : with filter +chirp 12-..: vokume 0 : silent + + ---------- digial output information ---------- + when ME pin = high , some status output to A0..15 pins + + A0..8 : DAC output value (abs) + A9 : DAC sign flag , L=minus,H=Plus + A10 : energy reload flag (pitch pulse) + A11..15 : unknown + + [DAC output value(signed 6bit)] = A9 ? A0..8 : -(A0..8) + +*/ +#include "emu.h" +#include "vlm5030.h" + +/* interpolator per frame */ +#define FR_SIZE 4 +/* samples per interpolator */ +#define IP_SIZE_SLOWER (240/FR_SIZE) +#define IP_SIZE_SLOW (200/FR_SIZE) +#define IP_SIZE_NORMAL (160/FR_SIZE) +#define IP_SIZE_FAST (120/FR_SIZE) +#define IP_SIZE_FASTER ( 80/FR_SIZE) + + +/* phase value */ +enum { + PH_RESET, + PH_IDLE, + PH_SETUP, + PH_WAIT, + PH_RUN, + PH_STOP, + PH_END +}; + +/* Pull in the ROM tables */ +#include "tms5110r.inc" + +/* + speed parameter +SPC SPB SPA + 1 0 1 more slow (05h) : 42ms (150%) : 60sample + 1 1 x slow (06h,07h) : 34ms (125%) : 50sample + x 0 0 normal (00h,04h) : 25.6ms (100%) : 40samplme + 0 0 1 fast (01h) : 20.2ms (75%) : 30sample + 0 1 x more fast (02h,03h) : 12.2ms (50%) : 20sample +*/ +static const int vlm5030_speed_table[8] = +{ + IP_SIZE_NORMAL, + IP_SIZE_FAST, + IP_SIZE_FASTER, + IP_SIZE_FASTER, + IP_SIZE_NORMAL, + IP_SIZE_SLOWER, + IP_SIZE_SLOW, + IP_SIZE_SLOW +}; + +const device_type VLM5030 = &device_creator; + +vlm5030_device::vlm5030_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, VLM5030, "VLM5030", tag, owner, clock, "vlm5030", __FILE__), + device_sound_interface(mconfig, *this), + m_channel(NULL), + m_coeff(NULL), + m_rom(NULL), + m_address_mask(0), + m_address(0), + m_pin_BSY(0), + m_pin_ST(0), + m_pin_VCU(0), + m_pin_RST(0), + m_latch_data(0), + m_vcu_addr_h(0), + m_parameter(0), + m_phase(PH_RESET), + m_frame_size(0), + m_pitch_offset(0), + m_interp_step(0), + m_interp_count(0), + m_sample_count(0), + m_pitch_count(0), + m_old_energy(0), + m_old_pitch(0), + m_target_energy(0), + m_target_pitch(0), + m_new_energy(0), + m_new_pitch(0), + m_current_energy(0), + m_current_pitch(0) +{ + memset(m_old_k, 0, sizeof(m_old_k)); + memset(m_new_k, 0, sizeof(m_new_k)); + memset(m_current_k, 0, sizeof(m_current_k)); + memset(m_target_k, 0, sizeof(m_target_k)); + memset(m_x, 0, sizeof(m_x)); +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +/* start VLM5030 with sound rom */ +/* speech_rom == 0 -> use sampling data mode */ + +void vlm5030_device::device_start() +{ + m_coeff = &vlm5030_coeff; + + /* reset input pins */ + m_pin_RST = m_pin_ST = m_pin_VCU= 0; + m_latch_data = 0; + + device_reset(); + m_phase = PH_IDLE; + + m_rom = region()->base(); + m_address_mask = (region()->bytes() - 1) & 0xffff; + + m_channel = machine().sound().stream_alloc(*this, 0, 1, clock() / 440); + + /* don't restore "UINT8 *m_rom" when use vlm5030_set_rom() */ + + save_item(NAME(m_address)); + save_item(NAME(m_pin_BSY)); + save_item(NAME(m_pin_ST)); + save_item(NAME(m_pin_VCU)); + save_item(NAME(m_pin_RST)); + save_item(NAME(m_latch_data)); + save_item(NAME(m_vcu_addr_h)); + save_item(NAME(m_parameter)); + save_item(NAME(m_phase)); + save_item(NAME(m_interp_count)); + save_item(NAME(m_sample_count)); + save_item(NAME(m_pitch_count)); + save_item(NAME(m_old_energy)); + save_item(NAME(m_old_pitch)); + save_item(NAME(m_old_k)); + save_item(NAME(m_target_energy)); + save_item(NAME(m_target_pitch)); + save_item(NAME(m_target_k)); + save_item(NAME(m_x)); + machine().save().register_postload(save_prepost_delegate(FUNC(vlm5030_device::restore_state), this)); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void vlm5030_device::device_reset() +{ + m_phase = PH_RESET; + m_address = 0; + m_vcu_addr_h = 0; + m_pin_BSY = 0; + + m_old_energy = m_old_pitch = 0; + m_new_energy = m_new_pitch = 0; + m_current_energy = m_current_pitch = 0; + m_target_energy = m_target_pitch = 0; + memset(m_old_k, 0, sizeof(m_old_k)); + memset(m_new_k, 0, sizeof(m_new_k)); + memset(m_current_k, 0, sizeof(m_current_k)); + memset(m_target_k, 0, sizeof(m_target_k)); + m_interp_count = m_sample_count = m_pitch_count = 0; + memset(m_x, 0, sizeof(m_x)); + /* reset parameters */ + setup_parameter( 0x00); +} + +int vlm5030_device::get_bits(int sbit,int bits) +{ + int offset = m_address + (sbit>>3); + int data; + + data = m_rom[offset&m_address_mask] + + (((int)m_rom[(offset+1)&m_address_mask])*256); + data >>= (sbit&7); + data &= (0xff>>(8-bits)); + + return data; +} + +/* get next frame */ +int vlm5030_device::parse_frame() +{ + unsigned char cmd; + int i; + + /* remember previous frame */ + m_old_energy = m_new_energy; + m_old_pitch = m_new_pitch; + for(i=0;i<=9;i++) + m_old_k[i] = m_new_k[i]; + + /* command byte check */ + cmd = m_rom[m_address&m_address_mask]; + if( cmd & 0x01 ) + { /* extend frame */ + m_new_energy = m_new_pitch = 0; + for(i=0;i<=9;i++) + m_new_k[i] = 0; + m_address++; + if( cmd & 0x02 ) + { /* end of speech */ + + /* logerror("VLM5030 %04X end \n",m_address ); */ + return 0; + } + else + { /* silent frame */ + int nums = ( (cmd>>2)+1 )*2; + /* logerror("VLM5030 %04X silent %d frame\n",m_address,nums ); */ + return nums * FR_SIZE; + } + } + /* pitch */ + m_new_pitch = ( m_coeff->pitchtable[get_bits(1,m_coeff->pitch_bits)] + m_pitch_offset )&0xff; + /* energy */ + m_new_energy = m_coeff->energytable[get_bits(6,m_coeff->energy_bits)]; + + /* 10 K's */ + m_new_k[9] = m_coeff->ktable[9][get_bits(11,m_coeff->kbits[9])]; + m_new_k[8] = m_coeff->ktable[8][get_bits(14,m_coeff->kbits[8])]; + m_new_k[7] = m_coeff->ktable[7][get_bits(17,m_coeff->kbits[7])]; + m_new_k[6] = m_coeff->ktable[6][get_bits(20,m_coeff->kbits[6])]; + m_new_k[5] = m_coeff->ktable[5][get_bits(23,m_coeff->kbits[5])]; + m_new_k[4] = m_coeff->ktable[4][get_bits(26,m_coeff->kbits[4])]; + m_new_k[3] = m_coeff->ktable[3][get_bits(29,m_coeff->kbits[3])]; + m_new_k[2] = m_coeff->ktable[2][get_bits(33,m_coeff->kbits[2])]; + m_new_k[1] = m_coeff->ktable[1][get_bits(37,m_coeff->kbits[1])]; + m_new_k[0] = m_coeff->ktable[0][get_bits(42,m_coeff->kbits[0])]; + + m_address+=6; + logerror("VLM5030 %04X voice \n",m_address ); + //fprintf(stderr,"*** target Energy, Pitch, and Ks = %04d, %04d, %04d, %04d, %04d, %04d, %04d, %04d, %04d, %04d, %04d, %04d\n",m_new_energy, m_new_pitch, m_new_k[0], m_new_k[1], m_new_k[2], m_new_k[3], m_new_k[4], m_new_k[5], m_new_k[6], m_new_k[7], m_new_k[8], m_new_k[9]); + return FR_SIZE; +} + +/* realtime update */ +void vlm5030_device::update() +{ + m_channel->update(); +} + +/* setup parameteroption when RST=H */ +void vlm5030_device::setup_parameter(UINT8 param) +{ + /* latch parameter value */ + m_parameter = param; + + /* bit 0,1 : 4800bps / 9600bps , interporator step */ + if(param&2) /* bit 1 = 1 , 9600bps */ + m_interp_step = 4; /* 9600bps : no interporator */ + else if(param&1) /* bit1 = 0 & bit0 = 1 , 4800bps */ + m_interp_step = 2; /* 4800bps : 2 interporator */ + else /* bit1 = bit0 = 0 : 2400bps */ + m_interp_step = 1; /* 2400bps : 4 interporator */ + + /* bit 3,4,5 : speed (frame size) */ + m_frame_size = vlm5030_speed_table[(param>>3) &7]; + + /* bit 6,7 : low / high pitch */ + if(param&0x80) /* bit7=1 , high pitch */ + m_pitch_offset = -8; + else if(param&0x40) /* bit6=1 , low pitch */ + m_pitch_offset = 8; + else + m_pitch_offset = 0; +} + + +void vlm5030_device::restore_state() +{ + int i; + + int interp_effect = FR_SIZE - (m_interp_count%FR_SIZE); + /* restore parameter data */ + setup_parameter( m_parameter); + + /* restore current energy,pitch & filter */ + m_current_energy = m_old_energy + (m_target_energy - m_old_energy) * interp_effect / FR_SIZE; + if (m_old_pitch > 1) + m_current_pitch = m_old_pitch + (m_target_pitch - m_old_pitch) * interp_effect / FR_SIZE; + for (i = 0; i <= 9 ; i++) + m_current_k[i] = m_old_k[i] + (m_target_k[i] - m_old_k[i]) * interp_effect / FR_SIZE; +} + +/* set speech rom address */ +void vlm5030_device::set_rom(void *speech_rom) +{ + m_rom = (UINT8 *)speech_rom; +} + +/* get BSY pin level */ +READ_LINE_MEMBER( vlm5030_device::bsy ) +{ + update(); + return m_pin_BSY; +} + +/* latch contoll data */ +WRITE8_MEMBER( vlm5030_device::data_w ) +{ + m_latch_data = (UINT8)data; +} + +/* set RST pin level : reset / set table address A8-A15 */ +WRITE_LINE_MEMBER( vlm5030_device::rst ) +{ + if( m_pin_RST ) + { + if( !state ) + { /* H -> L : latch parameters */ + m_pin_RST = 0; + setup_parameter( m_latch_data); + } + } + else + { + if( state ) + { /* L -> H : reset chip */ + m_pin_RST = 1; + if( m_pin_BSY ) + { + device_reset(); + } + } + } +} + +/* set VCU pin level : ?? unknown */ +WRITE_LINE_MEMBER( vlm5030_device::vcu ) +{ + /* direct mode / indirect mode */ + m_pin_VCU = state; +} + +/* set ST pin level : set table address A0-A7 / start speech */ +WRITE_LINE_MEMBER( vlm5030_device::st ) +{ + int table; + + if( m_pin_ST != state ) + { + /* pin level is change */ + if( !state ) + { /* H -> L */ + m_pin_ST = 0; + + if( m_pin_VCU ) + { /* direct access mode & address High */ + m_vcu_addr_h = ((int)m_latch_data<<8) + 0x01; + } + else + { + /* start speech */ + /* check access mode */ + if( m_vcu_addr_h ) + { /* direct access mode */ + m_address = (m_vcu_addr_h&0xff00) + m_latch_data; + m_vcu_addr_h = 0; + } + else + { /* indirect accedd mode */ + table = (m_latch_data&0xfe) + (((int)m_latch_data&1)<<8); + m_address = (((int)m_rom[table&m_address_mask])<<8) + | m_rom[(table+1)&m_address_mask]; +#if 0 +/* show unsupported parameter message */ +if( m_interp_step != 1) + popmessage("No %d %dBPS parameter",table/2,m_interp_step*2400); +#endif + } + update(); + /* logerror("VLM5030 %02X start adr=%04X\n",table/2,m_address ); */ + /* reset process status */ + m_sample_count = m_frame_size; + m_interp_count = FR_SIZE; + /* clear filter */ + /* start after 3 sampling cycle */ + m_phase = PH_RUN; + } + } + else + { /* L -> H */ + m_pin_ST = 1; + /* setup speech , BSY on after 30ms? */ + m_phase = PH_SETUP; + m_sample_count = 1; /* wait time for busy on */ + m_pin_BSY = 1; /* */ + } + } +} + + +//------------------------------------------------- +// sound_stream_update - handle a stream update +//------------------------------------------------- + +void vlm5030_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + int buf_count=0; + int interp_effect; + int i; + int u[11]; + stream_sample_t *buffer = outputs[0]; + + /* running */ + if( m_phase == PH_RUN || m_phase == PH_STOP ) + { + /* playing speech */ + while (samples > 0) + { + int current_val; + + /* check new interpolator or new frame */ + if( m_sample_count == 0 ) + { + if( m_phase == PH_STOP ) + { + m_phase = PH_END; + m_sample_count = 1; + goto phase_stop; /* continue to end phase */ + } + m_sample_count = m_frame_size; + /* interpolator changes */ + if ( m_interp_count == 0 ) + { + /* change to new frame */ + m_interp_count = parse_frame(); /* with change phase */ + if ( m_interp_count == 0 ) + { /* end mark found */ + m_interp_count = FR_SIZE; + m_sample_count = m_frame_size; /* end -> stop time */ + m_phase = PH_STOP; + } + /* Set old target as new start of frame */ + m_current_energy = m_old_energy; + m_current_pitch = m_old_pitch; + for(i=0;i<=9;i++) + m_current_k[i] = m_old_k[i]; + /* is this a zero energy frame? */ + if (m_current_energy == 0) + { + /*osd_printf_debug("processing frame: zero energy\n");*/ + m_target_energy = 0; + m_target_pitch = m_current_pitch; + for(i=0;i<=9;i++) + m_target_k[i] = m_current_k[i]; + } + else + { + /*osd_printf_debug("processing frame: Normal\n");*/ + /*osd_printf_debug("*** Energy = %d\n",m_current_energy);*/ + /*osd_printf_debug("proc: %d %d\n",last_fbuf_head,fbuf_head);*/ + m_target_energy = m_new_energy; + m_target_pitch = m_new_pitch; + for(i=0;i<=9;i++) + m_target_k[i] = m_new_k[i]; + } + } + /* next interpolator */ + /* Update values based on step values 25% , 50% , 75% , 100% */ + m_interp_count -= m_interp_step; + /* 3,2,1,0 -> 1,2,3,4 */ + interp_effect = FR_SIZE - (m_interp_count%FR_SIZE); + m_current_energy = m_old_energy + (m_target_energy - m_old_energy) * interp_effect / FR_SIZE; + if (m_old_pitch > 1) + m_current_pitch = m_old_pitch + (m_target_pitch - m_old_pitch) * interp_effect / FR_SIZE; + for (i = 0; i <= 9 ; i++) + m_current_k[i] = m_old_k[i] + (m_target_k[i] - m_old_k[i]) * interp_effect / FR_SIZE; + } + /* calcrate digital filter */ + if (m_old_energy == 0) + { + /* generate silent samples here */ + current_val = 0x00; + } + else if (m_old_pitch <= 1) + { /* generate unvoiced samples here */ + current_val = (machine().rand()&1) ? m_current_energy : -m_current_energy; + } + else + { + /* generate voiced samples here */ + current_val = ( m_pitch_count == 0) ? m_current_energy : 0; + } + + /* Lattice filter here */ + u[10] = current_val; + for (i = 9; i >= 0; i--) + u[i] = u[i+1] - ((-m_current_k[i] * m_x[i]) / 512); + for (i = 9; i >= 1; i--) + m_x[i] = m_x[i-1] + ((-m_current_k[i-1] * u[i-1]) / 512); + m_x[0] = u[0]; + + /* clipping, buffering */ + if (u[0] > 511) + buffer[buf_count] = 511<<6; + else if (u[0] < -511) + buffer[buf_count] = -511<<6; + else + buffer[buf_count] = (u[0] << 6); + buf_count++; + + /* sample count */ + m_sample_count--; + /* pitch */ + m_pitch_count++; + if (m_pitch_count >= m_current_pitch ) + m_pitch_count = 0; + /* size */ + samples--; + } +/* return;*/ + } + /* stop phase */ +phase_stop: + switch( m_phase ) + { + case PH_SETUP: + if( m_sample_count <= samples) + { + m_sample_count = 0; + /* logerror("VLM5030 BSY=H\n" ); */ + /* pin_BSY = 1; */ + m_phase = PH_WAIT; + } + else + { + m_sample_count -= samples; + } + break; + case PH_END: + if( m_sample_count <= samples) + { + m_sample_count = 0; + /* logerror("VLM5030 BSY=L\n" ); */ + m_pin_BSY = 0; + m_phase = PH_IDLE; + } + else + { + m_sample_count -= samples; + } + } + /* silent buffering */ + while (samples > 0) + { + buffer[buf_count++] = 0x00; + samples--; + } +} diff --git a/src/devices/sound/vlm5030.h b/src/devices/sound/vlm5030.h new file mode 100644 index 00000000000..94a5b846b39 --- /dev/null +++ b/src/devices/sound/vlm5030.h @@ -0,0 +1,100 @@ +// license:BSD-3-Clause +// copyright-holders:Tatsuyuki Satoh +#pragma once + +#ifndef __VLM5030_H__ +#define __VLM5030_H__ + + class vlm5030_device : public device_t, + public device_sound_interface + { + public: + vlm5030_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + ~vlm5030_device() {} + + /* set speech rom address */ + void set_rom(void *speech_rom); + + /* get BSY pin level */ + DECLARE_READ_LINE_MEMBER( bsy ); + + /* latch contoll data */ + DECLARE_WRITE8_MEMBER( data_w ); + + /* set RST pin level : reset / set table address A8-A15 */ + DECLARE_WRITE_LINE_MEMBER( rst ); + + /* set VCU pin level : ?? unknown */ + DECLARE_WRITE_LINE_MEMBER( vcu ); + + /* set ST pin level : set table address A0-A7 / start speech */ + DECLARE_WRITE_LINE_MEMBER( st ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // sound stream update overrides + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + +private: + // internal state + sound_stream * m_channel; + + /* coefficient tables */ + const struct tms5100_coeffs *m_coeff; + + /* need to save state */ + + UINT8 *m_rom; + int m_address_mask; + UINT16 m_address; + UINT8 m_pin_BSY; + UINT8 m_pin_ST; + UINT8 m_pin_VCU; + UINT8 m_pin_RST; + UINT8 m_latch_data; + UINT16 m_vcu_addr_h; + UINT8 m_parameter; + UINT8 m_phase; + + /* state of option paramter */ + int m_frame_size; + int m_pitch_offset; + UINT8 m_interp_step; + + UINT8 m_interp_count; /* number of interp periods */ + UINT8 m_sample_count; /* sample number within interp */ + UINT8 m_pitch_count; + + /* these contain data describing the current and previous voice frames */ + UINT16 m_old_energy; + UINT8 m_old_pitch; + INT16 m_old_k[10]; + UINT16 m_target_energy; + UINT8 m_target_pitch; + INT16 m_target_k[10]; + + UINT16 m_new_energy; + UINT8 m_new_pitch; + INT16 m_new_k[10]; + + /* these are all used to contain the current state of the sound generation */ + unsigned int m_current_energy; + unsigned int m_current_pitch; + int m_current_k[10]; + + INT32 m_x[10]; + + int get_bits(int sbit,int bits); + int parse_frame(); + void update(); + void setup_parameter(UINT8 param); + void restore_state(); +}; + +extern const device_type VLM5030; + + +#endif /* __VLM5030_H__ */ diff --git a/src/devices/sound/votrax.c b/src/devices/sound/votrax.c new file mode 100644 index 00000000000..f6b857c5dea --- /dev/null +++ b/src/devices/sound/votrax.c @@ -0,0 +1,1362 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + votrax.c + + Simple VOTRAX SC-01 simulator based on sample fragments. + +***************************************************************************/ + +#include "emu.h" +#include "votrax.h" + + +//************************************************************************** +// DEBUGGING +//************************************************************************** + +#define TEMP_HACKS (1) + +#define LOG_TIMING (0) +#define LOG_LOWPARAM (0) +#define LOG_GLOTTAL (0) +#define LOG_TRANSITION (0) + + + +//************************************************************************** +// CONSTANTS +//************************************************************************** + +// note that according to the patent timing circuit, p1/p2 and phi1/phi2 +// run 4x faster than all references in the patent text +const UINT32 P_CLOCK_BIT = 5; // 5 according to timing diagram +const UINT32 PHI_CLOCK_BIT = 3; // 3 according to timing diagram + + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +// device type definition +const device_type VOTRAX_SC01 = &device_creator; + +// ROM definition for the Votrax phoneme ROM +ROM_START( votrax_sc01 ) + ROM_REGION( 0x200, "phoneme", 0 ) + ROM_LOAD( "sc01.bin", 0x0000, 0x200, CRC(0353dd6c) SHA1(00e8e497b96a10bd9f4d7e559433c3c209b0d3a8) ) +ROM_END + +// textual phoneme names for debugging +const char *const votrax_sc01_device::s_phoneme_table[64] = +{ + "EH3", "EH2", "EH1", "PA0", "DT", "A1", "A2", "ZH", + "AH2", "I3", "I2", "I1", "M", "N", "B", "V", + "CH", "SH", "Z", "AW1", "NG", "AH1", "OO1", "OO", + "L", "K", "J", "H", "G", "F", "D", "S", + "A", "AY", "Y1", "UH3", "AH", "P", "O", "I", + "U", "Y", "T", "R", "E", "W", "AE", "AE1", + "AW2", "UH2", "UH1", "UH", "O2", "O1", "IU", "U1", + "THV", "TH", "ER", "EH", "E1", "AW", "PA1", "STOP" +}; + +// this waveform is derived from measuring fig. 10 in the patent +// it is only an approximation +const double votrax_sc01_device::s_glottal_wave[16] = +{ + 0, + 16.0/22.0, + -22.0/22.0, + -17.0/22.0, + -15.0/22.0, + -10.0/22.0, + -7.0/22.0, + -4.0/22.0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 +}; + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// votrax_sc01_device - constructor +//------------------------------------------------- + +votrax_sc01_device::votrax_sc01_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, VOTRAX_SC01, "Votrax SC-01", tag, owner, clock, "votrax", __FILE__), + device_sound_interface(mconfig, *this), + m_stream(NULL), + m_phoneme_timer(NULL), + m_request_cb(*this) +{ +} + +//************************************************************************** +// READ/WRITE HANDLERS +//************************************************************************** + +//------------------------------------------------- +// write - handle a write to the control register +//------------------------------------------------- + +WRITE8_MEMBER( votrax_sc01_device::write ) +{ + // flush out anything currently processing + m_stream->update(); + + // only 6 bits matter + m_phoneme = data & 0x3f; +const UINT8 *rom = m_rom + (m_phoneme << 3); +osd_printf_debug("%s: STROBE %s (F1=%X F2=%X FC=%X F3=%X F2Q=%X VA=%X FA=%X CL=%X CLD=%X VD=%X PAC=%X PH=%02X)\n", + machine().time().as_string(3), s_phoneme_table[m_phoneme], + rom[0] >> 4, rom[1] >> 4, rom[2] >> 4, rom[3] >> 4, rom[4] >> 4, rom[5] >> 4, rom[6] >> 4, + rom[3] & 0xf, rom[4] & 0xf, rom[5] & 0xf, rom[6] & 0xf, rom[7]); + + // the STROBE signal resets the phoneme counter + m_counter_84 = 0xf; + + // not in the schematics, but necessary to fully reset the request latch + m_latch_92 = 0; + + // clear the request signal + m_request_cb(m_request_state = m_internal_request = CLEAR_LINE); + m_phoneme_timer->adjust(attotime::zero); +} + + +//------------------------------------------------- +// inflection_w - handle a write to the +// inflection bits +//------------------------------------------------- + +WRITE8_MEMBER( votrax_sc01_device::inflection_w ) +{ + // only 2 bits matter + data &= 3; + if (m_inflection == data) + return; + + // append an inflection marker + m_stream->update(); + m_inflection = data; +} + + + +//************************************************************************** +// CORE LOGIC +//************************************************************************** + +//------------------------------------------------- +// update_subphoneme_clock_period - re-compute the +// period of the sub-phoneme clock, as a multiple +// of the master clock +//------------------------------------------------- + +void votrax_sc01_device::update_subphoneme_clock_period() +{ + assert(m_latch_80 < 128); + +/* + The sub-phoneme timing circuit is based off the switching capacitor + technique described in the Votrax patent. Replacing the capacitor + ladder with [Rx] representing the effective resistance, the circuit + becomes essentially a pair of op-amps: + + VM + | i1 + [R1] + | Vc + +----------------------+ + | +---|C1|---+ | + [R2] | | | |\ + |Vb i2 | |\ | +--++\ + +--[Rx]--+----+-\ | | > + | | >--+-----+-/ + [R3] +----++/ Vc |/ + |i3 | |/ + +--------+ Va + | + [R4] + | + 0 + + We have two op-amps, the left used as a standard amplifier, the right + one as a comparator. The circuit triggers when the two inputs of the + right op-amp are equal. + + The left part of the circuit (before C1) is simply a current injector. + It's all made of resistors, there's no modulated input, so everything + is going to be constant. If you don't know about op-amps used as + amplifiers, you just need to know that it forces its two inputs to + have the same voltage while not sending or providing any current + through there (only though its output in fact). + + In the schema, the injected current is i2. Basic equations apply: + Va = R4.i3 + Vb = Va + R3.i3 + Vb = Va + Rx.i2 + Vc = Vb + R2.i1 + VM = Vc + R1.i1 + i1 = i2 + i3 + + And the tipping happens when the voltage on the right of C1 reaches + Vc, so: + Vc = Va + i2.T/C1 + + (i2 being a constant, the integration is kinda easy) + + Some maths later: + R3.i3 = Rx.i2 -> i3 = Rx/R3.i2 + i1 = (1+Rx/R3).i2 + Va + (Rx + R2 + R2.Rx/R3).i2 = Va + T/C1.i2 + T = C1*(Rx*(1+R2/R3) + R2) + + Which isn't, interestingly though not surprisingly, dependant on Vm, + R1 or R4. And you have to round it to the next multiple of + 0.2ms+0.1ms due to the clocking on p2 and its offset to p1 (charging + only happens on p1 active), and add one p1/p2 cycle (0.2ms) for the + discharge. + + So now you have your base clock, which you have to multiply by 16 to + get the phoneme length. + + r2 = 9e3 + r3 = 1e3 + c1 = 1000e-12 + rx = 1/(5KHz * cx) +*/ + + // determine total capacitance + double cx = 0; + if ((m_latch_80 & 0x01) != 0) cx += 5e-12; + if ((m_latch_80 & 0x02) != 0) cx += 11e-12; + if ((m_latch_80 & 0x04) != 0) cx += 21e-12; + if ((m_latch_80 & 0x08) != 0) cx += 43e-12; + if ((m_latch_80 & 0x10) != 0) cx += 86e-12; + if ((m_latch_80 & 0x20) != 0) cx += 173e-12; + if ((m_latch_80 & 0x40) != 0) cx += 345e-12; + + // apply the equation above to determine charging time + // note that the 5kHz listed above for P1 is for a nominal master + // clock frequency of 1.28MHz, meaning it is master clock / 128 + // which should be the P1 clock but appears to be a bit different + double p1_frequency = double(m_master_clock_freq) / double(1 << (P_CLOCK_BIT + 2)); + double rx = 1.0 / (p1_frequency * cx); + double period = 1000e-12 * (rx * (1.0 + 9e3 / 1e3) + 9e3); + + // convert to master clock cycles and round up + m_subphoneme_period = UINT32(ceil(period * double(m_master_clock_freq))); +} + +//------------------------------------------------- +// bits_to_caps - compute the final capacity from +// a grid of bit-selected caps +//------------------------------------------------- + +double votrax_sc01_device::bits_to_caps(UINT32 value, int caps_count, const double *caps_values) +{ + double sum = 0; + for(int i=0; i--+--[Rx]--+ | >--+----- Vo + | | 0-++/ 0-++/ | + | | |/ +--[R0]--+ |/ | + | | | | | + | | | /| | | + | | | /-+--+--[R0]--+ + | +--[R4]-------+--< | + | V2^ \++-0 + | \| + + You need to determine the transfer function H(s) of the circuit, which is + defined as the ratio Vo/Vi. To do that, you use some properties: + + - The intensity through an element is equal to the voltage + difference through the element divided by the impedence + + - The impedence of a resistance is equal to its resistance + + - The impedence of a capacitor is 1/(s*C) where C is its capacitance + + - The impedence of elements in series is the sum of the impedences + + - The impedence of elements in parallel is the inverse of the sum of + the inverses + + - The sum of all intensities flowing into a node is 0 (there's no + charge accumulation in a wire) + + - An operational amplifier in looped mode is an interesting beast: + the intensity at its two inputs is always 0, and the voltage is + forced identical between the inputs. In our case, since the '+' + inputs are all tied to ground, that means that the '-' inputs are at + voltage 0, intensity 0. + + From here we can build some equations. Noting: + X1 = 1/(1/R1 + s*C1) + X2 = 1/(1/R2 + s*C2) + X3 = 1/(s*C3) + + Then computing the intensity flow at each '-' input we have: + Vi/X1 + V2/R4 + V1/X2 = 0 + V2/R0 + Vo/R0 = 0 + V1/Rx + Vo/X3 = 0 + + Wrangling the equations, one eventually gets: + | 1 + s * C1*R1 + | Vo/Vi = H(s) = (R4/R1) * ------------------------------------------- + | 1 + s * C3*Rx*R4/R2 + s^2 * C2*C3*Rx*R4 + + To check the mathematics between the 's' stuff, check "Laplace + transform". In short, it's a nice way of manipulating derivatives + and integrals without having to manipulate derivatives and + integrals. + + With that transfer function, we first can compute what happens to + every frequency in the input signal. You just compute H(2i*pi*f) + where f is the frequency, which will give you a complex number + representing the amplitude and phase effect. To get the usual dB + curves, compute 20*log10(abs(v))). + + Now, once you have an analog transfer function, you can build a + digital filter from it using what is called the bilinear transform. + + In our case, we have an analog filter with the transfer function: + | 1 + k[0]*s + | H(s) = ------------------------- + | 1 + k[1]*s + k[2]*s^2 + + We can always reintroduce the global multipler later, and it's 1 in + most of our cases anyway. + + The we pose: + | z-1 + | s(z) = zc * --- + | z+1 + + where zc = 2*pi*fr/tan(pi*fr/fs) + with fs = sampling frequency + and fr = most interesting frequency + + Then we rewrite H in function of negative integer powers of z. + + Noting m0 = zc*k[0], m1 = zc*k[1], m2=zc*zc*k[2], + + a little equation wrangling then gives: + + | (1+m0) + (3+m0) *z^-1 + (3-m0) *z^-2 + (1-m0)*z^-3 + | H(z) = ---------------------------------------------------------------- + | (1+m1+m2) + (3+m1-m2)*z^-1 + (3-m1-m2)*z^-2 + (1-m1+m2)*z^-3 + + That beast in the digital transfer function, of which you can + extract response curves by posing z = exp(2*i*pi*f/fs). + + Note that the bilinear transform is an approximation, and H(z(f)) = + H(s(f)) only at frequency fr. And the shape of the filter will be + better respected around fr. If you look at the curves of the + filters we're interested in, the frequency: + fr = sqrt(abs(k[0]*k[1]-k[2]))/(2*pi*k[2]) + + which is a (good) approximation of the filter peak position is a + good choice. + + Note that terminology wise, the "standard" bilinear transform is + with fr = fs/2, and using a different fr is called "pre-warping". + + So now we have a digital transfer function of the generic form: + + | a[0] + a[1]*z^-1 + a[2]*z^-2 + a[3]*z^-3 + | H(z) = -------------------------------------------- + | b[0] + b[1]*z^-1 + b[2]*z^-2 + b[3]*z^-3 + + The magic then is that the powers of z represent time in samples. + Noting x the input stream and y the output stream, you have: + H(z) = y(z)/x(z) + + or in other words: + y*b[0]*z^0 + y*b[1]*z^-1 + y*b[2]*z^-2 + y*b[3]*z^-3 = x*a[0]*z^0 + x*a[1]*z^-1 + x*a[2]*z^-2 + x*a[3]*z^-3 + + i.e. + + y*z^0 = (x*a[0]*z^0 + x*a[1]*z^-1 + x*a[2]*z^-2 + x*a[3]*z^-3 - y*b[1]*z^-1 - y*b[2]*z^-2 - y*b[3]*z^-3) / b[0] + + and powers of z being time in samples, + + y[0] = (x[0]*a[0] + x[-1]*a[1] + x[-2]*a[2] + x[-3]*a[3] - y[-1]*b[1] - y[-2]*b[2] - y[-3]*b[3]) / b[0] + + So you have a filter you can apply. Note that this is why you want + negative powers of z. Positive powers would mean looking into the + future (which is possible in some cases, in particular with x, and + has some very interesting properties, but is not very useful in + analog circuit simulation). + + Note that if you have multiple inputs, all this stuff is linear. + Or, in other words, you just have to split it in multiple circuits + with only one input connected each time and sum the results. It + will be correct. + + Also, since we're in practice in a dynamic system, for an amplifying + filter (i.e. where things like r4/r1 is not 1), it's better to + proceed in two steps: + + - amplify the input by the current value of the coefficient, and + historize it + - apply the now non-amplifying filter to the historized amplified + input + + That way reduces the probability of the output boucing all over the + place. + +*/ + + +//------------------------------------------------------------- +// filter_s_to_z - analog to digital filter transformation +//------------------------------------------------------------- + +void votrax_sc01_device::filter_s_to_z(const double *k, double fs, double *a, double *b) +{ + double fpeak = sqrt(fabs(k[0]*k[1]-k[2]))/(2*M_PI*k[2]); + double zc = 2*M_PI*fpeak/tan(M_PI*fpeak/fs); + + double m0 = zc*k[0]; + double m1 = zc*k[1]; + double m2 = zc*zc*k[2]; + + a[0] = 1+m0; + a[1] = 3+m0; + a[2] = 3-m0; + a[3] = 1-m0; + b[0] = 1+m1+m2; + b[1] = 3+m1-m2; + b[2] = 3-m1-m2; + b[3] = 1-m1+m2; +} + + +//------------------------------------------------------------- +// apply_filter - apply the digital filter (before output +// shifting, so y[0] is one step in the past) +//------------------------------------------------------------- +double votrax_sc01_device::apply_filter(const double *x, const double *y, const double *a, const double *b) +{ + return (x[0]*a[0] + x[1]*a[1] + x[2]*a[2] + x[3]*a[3] - y[0]*b[1] - y[1]*b[2] - y[2]*b[3]) / b[0]; +} + + +//------------------------------------------------------------- +// shift_hist - shift a value in an output history +//------------------------------------------------------------- + +void votrax_sc01_device::shift_hist(double val, double *hist_array, int hist_size) +{ + for(int i = 0; i < hist_size-1; i++) + hist_array[hist_size-1-i] = hist_array[hist_size-2-i]; + hist_array[0] = val; +} + + +//------------------------------------------------- +// sound_stream_update - handle update requests +// for our sound stream +//------------------------------------------------- + +void votrax_sc01_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + // determine how many master half-clocks per sample + int half_clocks_per_sample = (m_master_clock_freq * 2) / stream.sample_rate(); + + // iterate over clocks (samples) + stream_sample_t *dest = outputs[0]; + while (samples--) + { + // run the digital logic at the master clock rate + double glottal_out = 0; + UINT8 noise_out_digital = 0; + for (int curclock = 0; curclock < half_clocks_per_sample; curclock++) + { +if (LOG_TIMING | LOG_LOWPARAM | LOG_GLOTTAL | LOG_TRANSITION) +{ + if (m_counter_34 % 32 == 0 && m_master_clock == 0) + { + if (LOG_TIMING) + osd_printf_debug("MCLK C034 L070 L072 BET1 P1 P2 PHI1 PHI2 PH1' PH2' SUBC C088 C084 L092 IIRQ "); + if (LOG_LOWPARAM) + osd_printf_debug("F132 F114 F112 F142 L080 "); + if (LOG_GLOTTAL) + osd_printf_debug("C220 C222 C224 C234 C236 FGAT GLSY "); + if (LOG_TRANSITION) + osd_printf_debug("0625 C046 L046 A0-2 L168 L170 FC VA FA F1 F2 F3 F2Q "); + osd_printf_debug("\n"); + } + if (LOG_TIMING) + osd_printf_debug("%4X %4X %4X %4X %4X %4X %4X %4X %4X %4X %4X %4X %4X %4X %4X %4X ", m_master_clock, m_counter_34, m_latch_70, m_latch_72, m_beta1, m_p1, m_p2, m_phi1, m_phi2, m_phi1_20, m_phi2_20, m_subphoneme_count, m_clock_88, m_counter_84, m_latch_92, m_internal_request); + if (LOG_LOWPARAM) + osd_printf_debug("%4X %4X %4X %4X %4X ", m_srff_132, m_srff_114, m_srff_112, m_srff_142, m_latch_80); + if (LOG_GLOTTAL) + osd_printf_debug("%4X %4X %4X %4X %4X %4X %4X ", m_counter_220, m_counter_222, m_counter_224, m_counter_234, m_counter_236, m_fgate, m_glottal_sync); + if (LOG_TRANSITION) + osd_printf_debug("%4X %4X %4X %4X %4X %4X %4X %4X %4X %4X %4X %4X %4X ", m_0625_clock, m_counter_46, m_latch_46, m_latch_72 & 7, m_latch_168, m_latch_170, m_fc, m_va, m_fa, m_f1, m_f2, m_f3, m_f2q); + osd_printf_debug("\n"); +} + + //============================================== + // + // Timing circuit (patent figure 2a) + // + //============================================== + + // update master clock + m_master_clock ^= 1; + + // on the falling edge of the master clock, advance the 10-bit counter at 34 + UINT8 old_latch_72 = m_latch_72; + if (m_master_clock == 0) + m_counter_34 = (m_counter_34 + 1) & 0x3ff; + else + { + m_latch_70 = m_counter_34 & 0xf; + m_latch_72 = ((m_counter_34 >> 4) & 7) | ((m_counter_34 >> 6) & 8); + } + + // derive beta 1 clock: + // set if m_latch_70.0 == 1 + // reset if m_latch_70.0 == 0 +// UINT8 old_beta1 = m_beta1; + m_beta1 = BIT(m_latch_70, 0); + + // derive p2 clock: + // set if (m_counter_34.P_CLOCK_BIT & clock) == 1 + // reset if (m_counter_34.P_CLOCK_BIT == 0) + UINT8 old_p2 = m_p2; + if (BIT(m_counter_34, P_CLOCK_BIT) & m_master_clock) + m_p2 = 1; + else if (!BIT(m_counter_34, P_CLOCK_BIT)) + m_p2 = 0; + + // derive p1 clock: + // set if (!m_counter_34.P_CLOCK_BIT & clock) == 1 + // reset if (m_counter_34.P_CLOCK_BIT == 1) +// UINT8 old_p1 = m_p1; + if (BIT(~m_counter_34, P_CLOCK_BIT) & m_master_clock) + m_p1 = 1; + else if (BIT(m_counter_34, P_CLOCK_BIT)) + m_p1 = 0; + + // derive phi2 clock: + // set if (m_counter_34.PHI_CLOCK_BIT & clock) == 1 + // reset if (m_counter_34.PHI_CLOCK_BIT == 0) + UINT8 old_phi2 = m_phi2; + if (BIT(m_counter_34, PHI_CLOCK_BIT) & m_master_clock) + m_phi2 = 1; + else if (!BIT(m_counter_34, PHI_CLOCK_BIT)) + m_phi2 = 0; + + // derive phi1 clock: + // set if (!m_counter_34.PHI_CLOCK_BIT & clock) == 1 + // reset if (m_counter_34.PHI_CLOCK_BIT == 1) + UINT8 old_phi1 = m_phi1; + if (BIT(~m_counter_34, PHI_CLOCK_BIT) & m_master_clock) + m_phi1 = 1; + else if (BIT(m_counter_34, PHI_CLOCK_BIT)) + m_phi1 = 0; + + // derive alternate phi2 clock: + // set if (m_counter_34.PHI_CLOCK_BIT & clock) == 1 + // reset if (m_counter_34.PHI_CLOCK_BIT == 0) + UINT8 old_phi2_20 = m_phi2_20; + if (BIT(m_counter_34, PHI_CLOCK_BIT + 2) & m_master_clock) + m_phi2_20 = 1; + else if (!BIT(m_counter_34, PHI_CLOCK_BIT + 2)) + m_phi2_20 = 0; + + // derive alternate phi1 clock: + // set if (!m_counter_34.PHI_CLOCK_BIT & clock) == 1 + // reset if (m_counter_34.PHI_CLOCK_BIT == 1) +// UINT8 old_phi1_20 = m_phi1_20; + if (BIT(~m_counter_34, PHI_CLOCK_BIT + 2) & m_master_clock) + m_phi1_20 = 1; + else if (BIT(m_counter_34, PHI_CLOCK_BIT + 2)) + m_phi1_20 = 0; + + // determine rising edges of each clock of interest +// UINT8 beta1_rising = (old_beta1 ^ m_beta1) & m_beta1; + UINT8 p2_rising = (old_p2 ^ m_p2) & m_p2; +// UINT8 p1_rising = (old_p1 ^ m_p1) & m_p1; + UINT8 phi2_rising = (old_phi2 ^ m_phi2) & m_phi2; + UINT8 phi1_rising = (old_phi1 ^ m_phi1) & m_phi1; + UINT8 phi2_20_rising = (old_phi2_20 ^ m_phi2_20) & m_phi2_20; +// UINT8 phi1_20_rising = (old_phi1_20 ^ m_phi1_20) & m_phi1_20; + UINT8 a0_rising = BIT((old_latch_72 ^ m_latch_72) & m_latch_72, 0); + UINT8 a2_rising = BIT((old_latch_72 ^ m_latch_72) & m_latch_72, 2); + UINT8 _125k_rising = BIT((old_latch_72 ^ m_latch_72) & m_latch_72, 3); + + // track subphoneme counter state + if (!(m_latch_42 | m_phi1)) + m_subphoneme_count = 0; + else + m_subphoneme_count++; + if (p2_rising) + m_latch_42 = (m_subphoneme_count < m_subphoneme_period); + + // update the state of the subphoneme clock line + UINT8 old_clock_88 = m_clock_88; + m_clock_88 = !m_latch_42; //!(m_latch_42 | m_phi1); -- figure 7 seems to be wrong here + UINT8 clock_88_rising = (old_clock_88 ^ m_clock_88) & m_clock_88; + + // the A/R line holds the counter in reset except during phoneme processing, + // when it is clocked on the rising edge of the subphoneme timer clock + if (m_internal_request != CLEAR_LINE) + m_counter_84 = 0xf; + else if (clock_88_rising) + { + m_counter_84 = (m_counter_84 - 1) & 0x0f; +osd_printf_debug("counter=%d\n", m_counter_84); + } + + // clock the zero count latch + if (p2_rising) + m_latch_92 = ((m_counter_84 == 0) | (m_latch_92 << 1)) & 3; + + // once both bits are set, the request line goes high + if (m_latch_92 == 3) + { + // if the request line was previously low, reset the VD/CLD flip-flops + if (m_internal_request == CLEAR_LINE) + m_srff_112 = m_srff_114 = 0; + m_internal_request = ASSERT_LINE; + } + + //============================================== + // + // Low parameter clocking (patent figure 2b) + // + //============================================== + + // fetch ROM data; note that the address lines come directly from + // counter_34 and not from the latches, which are 1 cycle delayed + UINT8 romdata = m_rom[(m_phoneme << 3) | ((m_counter_34 >> 4) & 7)]; + + // update the ROM data; ROM format is (upper nibble/lower nibble) + // +00 = F1 parameter / 0 + // +01 = F2 parameter / 0 + // +02 = FC parameter / 0 + // +03 = F3 parameter / CL + // +04 = F2Q Parameter / CLD + // +05 = VA Parameter / VD + // +06 = FA Parameter / PAC + // +07 = Phoneme timing (full 7 bits) + + // latch a new value from ROM on phi2 + UINT8 a = m_latch_72 & 7; + UINT8 romdata_swapped; + if (phi2_rising) + { + switch (a) + { + // update CL + case 3: + m_srff_132 = m_srff_114 & BIT(~romdata, 3); + break; + + // update CLD + case 4: + romdata_swapped = (BIT(romdata, 0) << 3) | (BIT(romdata, 1) << 2) | (BIT(romdata, 2) << 1) | (BIT(romdata, 3) << 0); + if (m_counter_84 != 0 && romdata_swapped == (m_counter_84 ^ 0xf)) + m_srff_114 = 1; + break; + + // update VD + case 5: + romdata_swapped = (BIT(romdata, 0) << 3) | (BIT(romdata, 1) << 2) | (BIT(romdata, 2) << 1) | (BIT(romdata, 3) << 0); + if (m_counter_84 != 0 && romdata_swapped == (m_counter_84 ^ 0xf)) + m_srff_112 = 1; + break; + + // update FF == PAC & (VA | FA) + case 6: + m_srff_142 = BIT(romdata, 3); + break; + + // update PH + case 7: + if (m_latch_80 != (romdata & 0x7f)) + { + m_latch_80 = romdata & 0x7f; +osd_printf_debug("[PH=%02X]\n", m_latch_80); + UINT32 old_period = m_subphoneme_period; + update_subphoneme_clock_period(); + m_subphoneme_count = (m_subphoneme_count * m_subphoneme_period) / old_period; + m_phoneme_timer->adjust(attotime::zero); + } + break; + } + } + + //============================================== + // + // Glottal circuit (patent figure 6) + // + //============================================== + + // determine the TC output from the counters (note that TC requires ET) + UINT8 counter_222_tc = (m_counter_222 == 0xf); + UINT8 counter_220_tc = (m_counter_220 == 0xf && counter_222_tc); + UINT8 counter_224_tc = (m_counter_224 == 0xf && counter_222_tc); + + // clock glottal counter 224 on rising edge of a0 + if (a0_rising) + { + // counter 224 is only enabled if TC of counter 222 is 1 + if (counter_222_tc) + { + // if counter 220's TC is 1, do a load instead of a count + if (counter_220_tc) + m_counter_224 = (m_inflection << 1) | ((~m_f1 & 0x8) >> 3); + else + m_counter_224 = (m_counter_224 + 1) & 0xf; + } + } + + // clock remaining glottal counters (220, 222, 236) on rising edge of phi2 + if (phi2_20_rising) + { + // counter 220 is only enabled if TC of counter 222 is 1 + if (counter_222_tc) + { + // if counter 220's TC is 1, do a load instead of a count + if (counter_220_tc) + m_counter_220 = (m_inflection << 1) | ((~m_f1 & 0x8) >> 3); + else + m_counter_220 = (m_counter_220 + 1) & 0xf; + } + + // counter 222 is always enabled + if (1) + { + // if counter 220's TC is 1, do a load instead of a count + if (counter_220_tc) + m_counter_222 = (~m_f1 & 0x7) << 1; + else + m_counter_222 = (m_counter_222 + 1) & 0xf; + } + + // counter 236 is always enabled + if (1) + { + m_counter_236 = (m_counter_236 + 1) & 0xf; + + // rising edge of Q1 from counter 236 clocks counter 234 + if ((m_counter_236 & 0x3) == 0x2) + { + // counter 234 is only enabled if it has not reached terminal + if (m_counter_234 != 0xf) + m_counter_234 = (m_counter_234 + 1) & 0xf; + } + } + } + + // update FGATE state + if (counter_220_tc) + m_fgate = 0; + if (counter_224_tc) + m_fgate = 1; + + // apply asynchronous clear to counters 234/236 + if (counter_220_tc && m_phi1_20) + m_counter_236 = m_counter_234 = 0; + + // derive glottal circuit output signals +#if !TEMP_HACKS + UINT8 old_glottal_sync = m_glottal_sync; +#endif + m_glottal_sync = (m_counter_234 == 0); + glottal_out = s_glottal_wave[m_counter_234]; + + //============================================== + // + // Transition circuit (patent figure 3a/3b) + // + //============================================== + + // divide 1.25k clock by 2 (lower-left of 46) + UINT8 old_0625_clock = m_0625_clock; + if (_125k_rising) + m_0625_clock = !m_0625_clock; + UINT8 _0625_rising = (old_0625_clock ^ m_0625_clock) & m_0625_clock; + + // update counter above + if (_0625_rising) + { + if (m_counter_46 == 0xf) + m_counter_46 = 0xd; + else + m_counter_46 = (m_counter_46 + 1) & 0xf; + } + + // and then the latch to the right + if (a2_rising) + m_latch_46 = (BIT(m_counter_46, 1) << 0) | + (BIT(m_latch_46, 0) << 1) | + (m_0625_clock << 2) | + (BIT(m_latch_46, 2) << 3); + +#if TEMP_HACKS + m_latch_46 = 0xf; +#endif + + // determine the read/write signal + UINT8 ram_write = 0; + switch (a) + { + // write if not FF and low 2 bits of latch + // FF is the S/R flip-flop at 142 ANDed with !(/FA & /VA) + case 0: case 1: case 2: case 3: case 4: + if (!(m_srff_142 & !((m_fa == 0) & (m_va == 0))) && (m_latch_46 & 0x3) == 0x3) + ram_write = 1; + break; + + case 5: + if ((m_latch_46 & 0xc) == 0xc && m_srff_112) + ram_write = 1; + break; + + case 6: + if ((m_latch_46 & 0xc) == 0xc && m_srff_114) + ram_write = 1; + break; + } + + // gate on the phi2 clock (OR gate @ 172) + ram_write &= m_phi2; + + // write the transitioned values to RAM if requested + // (note we consolidate the serial addition and clocking steps here) + if (ram_write) + { + UINT8 old = (m_latch_168 << 4) | m_latch_170; + m_ram[a] = old - (old >> 3) + ((romdata & 0xf0) >> 3); + } + + // latch some parameter values on rising edge of phi2 + if (phi2_rising) + { + switch (a) + { + case 2: + m_fc = m_latch_168; + break; + + case 5: + m_va = m_latch_168; + break; + + case 6: + m_fa = m_latch_168; + break; + } + } + + // latch remaining parameter values on rising edge of (phi2 & glottal sync) +#if TEMP_HACKS + if (phi2_rising) +#else + UINT8 old_phi2_glottal = (old_phi2 & old_glottal_sync); + UINT8 new_phi2_glottal = m_phi2 & m_glottal_sync; + if ((old_phi2_glottal ^ new_phi2_glottal) & new_phi2_glottal) +#endif + switch (a) + { + case 0: + m_f1 = m_latch_168; + break; + + case 1: + m_f2 = (m_latch_168 << 1) | (m_latch_170 >> 3); + break; + + case 3: + m_f3 = m_latch_168; + break; + + case 4: + m_f2q = m_latch_168; + break; + } + + // latch value from RAM on rising edge of phi1 + if (phi1_rising) + { + m_latch_168 = m_ram[a] >> 4; + m_latch_170 = m_ram[a] & 0xf; + } + + //============================================== + // + // Noise generator circuit (patent figure 8) + // + //============================================== + + // nose is clocked by the NOR of /FA and P1 + UINT8 old_noise_clock = m_noise_clock; + m_noise_clock = !((m_fa == 0) | m_p1); + UINT8 noise_clock_rising = (old_noise_clock ^ m_noise_clock) & m_noise_clock; + UINT8 noise_clock_falling = (old_noise_clock ^ m_noise_clock) & old_noise_clock; + + // falling edge clocks the shift register + if (noise_clock_falling) + { + // shift register 252 is actually 4 shift registers (2 4-bit, 2 5-bit) + // d1 and d3 are the 4-bit registers, d2 and d4 are the 5-bit registers + // XOR'ed input goes into d4, which shifts in to d2, then d3, then d1 + // thus the full 18-bit value is effectively + // + // d4 = (m_shift_252 >> 0) & 0x1f; + // d2 = (m_shift_252 >> 5) & 0x1f; + // d3 = (m_shift_252 >> 10) & 0xf; + // d1 = (m_shift_252 >> 14) & 0xf; + // + // input at the low end is ((d1+4 ^ d2+5) ^ (d4+4 ^ d4+5)) ^ !(counter2 | counter3) + // output is tapped at d3+4 + + UINT32 old_shift = m_shift_252; + m_shift_252 <<= 1; + m_shift_252 |= ((BIT(old_shift, 17) ^ BIT(old_shift, 9)) ^ (BIT(old_shift, 3) ^ BIT(old_shift, 4))) ^ + ((m_counter_250 & 0xc) == 0); + } + + // rising edge clocks the counter + if (noise_clock_rising) + { + // counter is reset to 1 if terminal, otherwise it increments + if (m_counter_250 == 0xf) + m_counter_250 = 0x1; + else + m_counter_250 = (m_counter_250 + 1) & 0xf; + } + + // compute final noise out signal + noise_out_digital = !(BIT(m_shift_252, 13) & (m_fgate | (m_va == 0))); + } + + // TODO: cache the filters + // filter coefs + double k[3], a[4], b[4]; + + // base frequencies + double fc = m_master_clock_freq / 30.0; // Nominal is 20KHz + double fs = stream.sample_rate(); + + // useful temporaries + double rcp, rcq, rca; + + // amplification stage + static const double va_caps[4] = { 27, 53, 107, 213 }; + double va_out = glottal_out * bits_to_caps(m_va, 4, va_caps) / 400; + + shift_hist(va_out, m_va_hist, 4); + + + // noise shaping + static const double fa_caps[4] = { 27, 53, 107, 213 }; + rcp = bits_to_caps(m_fa, 4, fa_caps); + + shift_hist(-noise_out_digital * 400*rcp/(358.0*100000*566*(fc*rcp*1e-12 + 1.0/100000 + 1.0/2000)), m_ni_hist, 4); + + k[0] = 400/(fc*358); + k[1] = 400*400/(fc*358*566); + k[2] = 400*400/(fc*fc*358*358); + + filter_s_to_z(k, fs, a, b); + double no_out = apply_filter(m_ni_hist, m_no_hist, a, b); + shift_hist(no_out, m_no_hist, 4); + + + // stage 1 filter + + static const double s1_p_caps[4] = { 16.4, 33, 66, 130 }; + rcp = 24 + bits_to_caps(m_f1, 4, s1_p_caps); + rcq = 20; + + k[0] = 253/(fc*270); + k[1] = 1080*rcq/(fc*270*rcp); + k[2] = 1080*1080/(fc*fc*270*rcp); + + filter_s_to_z(k, fs, a, b); + double s1_out = apply_filter(m_va_hist, m_s1_hist, a, b); + shift_hist(s1_out, m_s1_hist, 4); + + + // stage 2 filter, glottal half + + static const double s2_p_caps[5] = { 14, 28, 56, 113, 226 }; + static const double s2_q_caps[4] = { 23, 46, 93, 186 }; + rcp = 46 + bits_to_caps(m_f2, 5, s2_p_caps); + rcq = 20 + bits_to_caps(m_f2q, 4, s2_q_caps);; + + k[0] = 400/(fc*470); + k[1] = 620*rcq/(fc*470*rcp); + k[2] = 620*620/(fc*fc*470*rcp); + + filter_s_to_z(k, fs, a, b); + double s2g_out = apply_filter(m_s1_hist, m_s2g_hist, a, b); + shift_hist(s2g_out, m_s2g_hist, 4); + + + // stage 2 filter, noise half (rcp and rcq kept from stage 2 glottal) + + static const double s2_n_caps[5] = { 19, 38, 76, 152 }; + rca = bits_to_caps(m_fc, 4, s2_n_caps); + + shift_hist(-no_out*rcq*rca/(470*rcp), m_s2ni_hist, 4); + + k[0] = 400/(fc*470); + k[1] = 620*rcq/(fc*470*rcp); + k[2] = 620*620/(fc*fc*470*rcp); + + filter_s_to_z(k, fs, a, b); + double s2n_out = apply_filter(m_s2ni_hist, m_s2n_hist, a, b); + shift_hist(s2n_out, m_s2n_hist, 4); + + // sum the stage 2 outputs + double s2_out = s2g_out + s2n_out; + shift_hist(s2_out, m_s2_hist, 4); + + + // stage 3 filter + + static const double s3_p_caps[4] = { 21, 42, 84, 168 }; + rcp = 76 + bits_to_caps(m_f3, 4, s3_p_caps); + rcq = 20; + + k[0] = 0; + k[1] = 420*rcq/(fc*390*rcp); + k[2] = 420*420/(fc*fc*390*rcp); + + filter_s_to_z(k, fs, a, b); + double s3_out = apply_filter(m_s2_hist, m_s3_hist, a, b); + shift_hist(s3_out, m_s3_hist, 4); + + + // stage 4 filter, noise injection + + // The resulting non-amplifying filter is identical, so we + // inject instead of splitting + + static const double s4_n_caps[4] = { 24, 48, 96, 192 }; + rca = 115 + bits_to_caps(~m_fc, 4, s4_n_caps); + + shift_hist(s3_out + no_out*470/rca, m_s4i_hist, 4); + + + // stage 4 filter + + rcp = 30; + rcq = 20; + + k[0] = 0; + k[1] = 338*rcq/(fc*470*rcp); + k[2] = 338*338/(fc*fc*470*rcp); + + filter_s_to_z(k, fs, a, b); + double s4_out = apply_filter(m_s4i_hist, m_s4_hist, a, b); + shift_hist(s4_out, m_s4_hist, 4); + + + // TODO: apply closure circuit (undocumented) + + // output the current result + *dest++ = INT16(s4_out * 4000); + } +} + + + +//************************************************************************** +// DEVICE INTERFACE +//************************************************************************** + +//------------------------------------------------- +// rom_region - return a pointer to the device's +// internal ROM region +//------------------------------------------------- + +const rom_entry *votrax_sc01_device::device_rom_region() const +{ + return ROM_NAME( votrax_sc01 ); +} + + +//------------------------------------------------- +// device_start - handle device startup +//------------------------------------------------- + +void votrax_sc01_device::device_start() +{ + // initialize internal state + m_master_clock_freq = clock(); + m_stream = stream_alloc(0, 1, m_master_clock_freq / 16); + m_phoneme_timer = timer_alloc(); + m_rom = memregion("phoneme")->base(); + + // reset inputs + m_inflection = 0; + m_phoneme = 0x3f; + + // reset outputs + m_request_cb.resolve_safe(); + m_request_state = ASSERT_LINE; + m_internal_request = ASSERT_LINE; + + // save inputs + save_item(NAME(m_inflection)); + save_item(NAME(m_phoneme)); + + // save outputs + save_item(NAME(m_request_state)); + save_item(NAME(m_internal_request)); + + // save timing circuit + save_item(NAME(m_master_clock_freq)); + save_item(NAME(m_master_clock)); + save_item(NAME(m_counter_34)); + save_item(NAME(m_latch_70)); + save_item(NAME(m_latch_72)); + save_item(NAME(m_beta1)); + save_item(NAME(m_p2)); + save_item(NAME(m_p1)); + save_item(NAME(m_phi2)); + save_item(NAME(m_phi1)); + save_item(NAME(m_subphoneme_period)); + save_item(NAME(m_subphoneme_count)); + save_item(NAME(m_clock_88)); + save_item(NAME(m_latch_42)); + save_item(NAME(m_counter_84)); + save_item(NAME(m_latch_92)); + + // save low parameter clocking + save_item(NAME(m_srff_132)); + save_item(NAME(m_srff_114)); + save_item(NAME(m_srff_112)); + save_item(NAME(m_srff_142)); + save_item(NAME(m_latch_80)); + + // save glottal circuit + save_item(NAME(m_counter_220)); + save_item(NAME(m_counter_222)); + save_item(NAME(m_counter_224)); + save_item(NAME(m_counter_234)); + save_item(NAME(m_counter_236)); + save_item(NAME(m_fgate)); + save_item(NAME(m_glottal_sync)); + + // save transition circuit + save_item(NAME(m_0625_clock)); + save_item(NAME(m_counter_46)); + save_item(NAME(m_latch_46)); + save_item(NAME(m_ram)); + save_item(NAME(m_latch_168)); + save_item(NAME(m_latch_170)); + save_item(NAME(m_f1)); + save_item(NAME(m_f2)); + save_item(NAME(m_fc)); + save_item(NAME(m_f3)); + save_item(NAME(m_f2q)); + save_item(NAME(m_va)); + save_item(NAME(m_fa)); + + // save noise generator circuit + save_item(NAME(m_noise_clock)); + save_item(NAME(m_shift_252)); + save_item(NAME(m_counter_250)); + + // save filter histories + save_item(NAME(m_ni_hist)); + save_item(NAME(m_no_hist)); + save_item(NAME(m_va_hist)); + save_item(NAME(m_s1_hist)); + save_item(NAME(m_s2g_hist)); + save_item(NAME(m_s2n_hist)); + save_item(NAME(m_s2ni_hist)); + save_item(NAME(m_s2_hist)); + save_item(NAME(m_s3_hist)); + save_item(NAME(m_s4i_hist)); + save_item(NAME(m_s4_hist)); +} + + +//------------------------------------------------- +// device_reset - handle device reset +//------------------------------------------------- + +void votrax_sc01_device::device_reset() +{ + // set the initial state + m_stream->update(); + + // reset inputs + m_phoneme = 0x3f; + m_request_cb(m_internal_request = m_request_state = ASSERT_LINE); + + // reset timing circuit + m_master_clock = 0; + m_counter_34 = 0; + m_latch_70 = 0; + m_latch_72 = 0; + m_beta1 = 0; + m_p2 = 0; + m_p1 = 0; + m_phi2 = 0; + m_phi1 = 0; + m_subphoneme_period = 1000; + m_subphoneme_count = 0; + m_clock_88 = 0; + m_latch_42 = 0; + m_counter_84 = 0; + m_latch_92 = 0; + + // reset low parameter clocking + m_srff_132 = 0; + m_srff_114 = 0; + m_srff_112 = 0; + m_srff_142 = 0; + m_latch_80 = 50; + update_subphoneme_clock_period(); + + // reset glottal circuit + m_counter_220 = 0; + m_counter_222 = 0; + m_counter_224 = 0; + m_counter_234 = 0; + m_counter_236 = 0; + m_fgate = 0; + m_glottal_sync = 0; + + // reset transition circuit + m_0625_clock = 0; + m_counter_46 = 0; + m_latch_46 = 0; + memset(m_ram, 0, sizeof(m_ram)); + m_latch_168 = 0; + m_latch_170 = 0; + m_f1 = 0; + m_f2 = 0; + m_fc = 0; + m_f3 = 0; + m_f2q = 0; + m_va = 0; + m_fa = 0; + + // reset noise circuit + m_noise_clock = 0; + m_shift_252 = 0; + m_counter_250 = 0; + + // reset filter histories + memset(m_ni_hist, 0, sizeof(m_ni_hist)); + memset(m_no_hist, 0, sizeof(m_no_hist)); + memset(m_va_hist, 0, sizeof(m_va_hist)); + memset(m_s1_hist, 0, sizeof(m_s1_hist)); + memset(m_s2g_hist, 0, sizeof(m_s2g_hist)); + memset(m_s2n_hist, 0, sizeof(m_s2n_hist)); + memset(m_s2ni_hist, 0, sizeof(m_s2ni_hist)); + memset(m_s2_hist, 0, sizeof(m_s2_hist)); + memset(m_s3_hist, 0, sizeof(m_s3_hist)); + memset(m_s4i_hist, 0, sizeof(m_s4i_hist)); + memset(m_s4_hist, 0, sizeof(m_s4_hist)); +} + + +//------------------------------------------------- +// device_clock_changed - handle dynamic clock +// changes by altering our output frequency +//------------------------------------------------- + +void votrax_sc01_device::device_clock_changed() +{ + // compute new frequency of the master clock, and update if changed + UINT32 newfreq = clock(); + if (newfreq != m_master_clock_freq) + { + // if we have a stream + if (m_stream != NULL) + { + m_stream->update(); + m_stream->set_sample_rate(newfreq / 16); + } + + // determine how many clock ticks remained on the phoneme timer + UINT64 remaining = m_phoneme_timer->remaining().as_ticks(m_master_clock_freq); + + // recompute the master clock + m_master_clock_freq = newfreq; + + // adjust the phoneme timer to the same number of ticks based on the new frequency + if (remaining > 0) + m_phoneme_timer->adjust(attotime::from_ticks(remaining, newfreq)); + } +} + + +//------------------------------------------------- +// device_timer - handle device timer +//------------------------------------------------- + +void votrax_sc01_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + // force a stream update + m_stream->update(); + + // if we're requesting more data, no need for timing + if (m_request_state == ASSERT_LINE) + return; + + // if we're supposed to have fired, do it now + if (m_internal_request == ASSERT_LINE) + { +osd_printf_debug("%s: REQUEST\n", timer.machine().time().as_string(3)); + m_request_cb(m_request_state = ASSERT_LINE); + return; + } + + // account for the rest of this subphoneme clock + UINT32 clocks_until_request = 0; + if (m_counter_84 != 0) + { + if (m_subphoneme_count < m_subphoneme_period) + clocks_until_request += m_subphoneme_period - m_subphoneme_count; + clocks_until_request += m_subphoneme_period * (m_counter_84 - 1); + } + + // plus 1/2 + clocks_until_request = MAX(clocks_until_request, (1 << P_CLOCK_BIT) / 2); + timer.adjust(attotime::from_ticks(clocks_until_request, m_master_clock_freq)); +} diff --git a/src/devices/sound/votrax.h b/src/devices/sound/votrax.h new file mode 100644 index 00000000000..152c1a51f99 --- /dev/null +++ b/src/devices/sound/votrax.h @@ -0,0 +1,164 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + votrax.h + + Simple VOTRAX SC-01 simulator based on sample fragments. + +***************************************************************************/ + +#pragma once + +#ifndef __VOTRAX_H__ +#define __VOTRAX_H__ + +#include "sound/samples.h" + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_VOTRAX_SC01_REQUEST_CB(_devcb) \ + devcb = &votrax_sc01_device::set_request_callback(*device, DEVCB_##_devcb); + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> votrax_sc01_device + +class votrax_sc01_device : public device_t, + public device_sound_interface +{ +public: + // construction/destruction + votrax_sc01_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + template static devcb_base &set_request_callback(device_t &device, _Object object) { return downcast(device).m_request_cb.set_callback(object); } + + // writers + DECLARE_WRITE8_MEMBER( write ); + DECLARE_WRITE8_MEMBER( inflection_w ); + DECLARE_READ_LINE_MEMBER( request ) { return m_request_state; } + +protected: + // device-level overrides + virtual const rom_entry *device_rom_region() const; + virtual void device_start(); + virtual void device_reset(); + virtual void device_clock_changed(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + // device_sound_interface overrides + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + +private: + // internal helpers + void update_subphoneme_clock_period(); + static double bits_to_caps(UINT32 value, int caps_count, const double *caps_values); + static void shift_hist(double val, double *hist_array, int hist_size); + static void filter_s_to_z(const double *k, double fs, double *a, double *b); + static double apply_filter(const double *x, const double *y, const double *a, const double *b); + + // internal state + sound_stream * m_stream; // output stream + emu_timer * m_phoneme_timer; // phoneme timer + const UINT8 * m_rom; // pointer to our ROM + + // inputs + UINT8 m_inflection; // 2-bit inflection value + UINT8 m_phoneme; // 6-bit phoneme value + + // outputs + devcb_write_line m_request_cb; // callback for request + UINT8 m_request_state; // request as seen to the outside world + UINT8 m_internal_request; // request managed by stream timing + + // timing circuit + UINT32 m_master_clock_freq; // frequency of the master clock + UINT8 m_master_clock; // master clock + UINT16 m_counter_34; // ripple counter @ 34 + UINT8 m_latch_70; // 4-bit latch @ 70 + UINT8 m_latch_72; // 4-bit latch @ 72 + UINT8 m_beta1; // beta1 clock state + UINT8 m_p2; // P2 clock state + UINT8 m_p1; // P1 clock state + UINT8 m_phi2; // phi2 clock state + UINT8 m_phi1; // phi1 clock state + UINT8 m_phi2_20; // alternate phi2 clock state (20kHz) + UINT8 m_phi1_20; // alternate phi1 clock state (20kHz) + UINT32 m_subphoneme_period; // period of the subphoneme timer + UINT32 m_subphoneme_count; // number of ticks executed already + UINT8 m_clock_88; // subphoneme clock output @ 88 + UINT8 m_latch_42; // D flip-flop @ 42 + UINT8 m_counter_84; // 4-bit phoneme counter @ 84 + UINT8 m_latch_92; // 2-bit latch @ 92 + + // low parameter clocking + UINT8 m_srff_132; // S/R flip-flop @ 132 + UINT8 m_srff_114; // S/R flip-flop @ 114 + UINT8 m_srff_112; // S/R flip-flop @ 112 + UINT8 m_srff_142; // S/R flip-flop @ 142 + UINT8 m_latch_80; // phoneme timing latch @ 80 + + // glottal circuit + UINT8 m_counter_220; // 4-bit counter @ 220 + UINT8 m_counter_222; // 4-bit counter @ 222 + UINT8 m_counter_224; // 4-bit counter @ 224 + UINT8 m_counter_234; // 4-bit counter @ 234 + UINT8 m_counter_236; // 4-bit counter @ 236 + UINT8 m_fgate; // FGATE signal + UINT8 m_glottal_sync; // Glottal Sync signal + + // transition circuit + UINT8 m_0625_clock; // state of 0.625kHz clock + UINT8 m_counter_46; // 4-bit counter in block @ 46 + UINT8 m_latch_46; // 4-bit latch in block @ 46 + UINT8 m_ram[8]; // RAM to hold parameters + UINT8 m_latch_168; // 4-bit latch @ 168 + UINT8 m_latch_170; // 4-bit latch @ 170 + UINT8 m_f1; // latched 4-bit F1 value + UINT8 m_f2; // latched 5-bit F2 value + UINT8 m_fc; // latched 4-bit FC value + UINT8 m_f3; // latched 4-bit F3 value + UINT8 m_f2q; // latched 4-bit F2Q value + UINT8 m_va; // latched 4-bit VA value + UINT8 m_fa; // latched 4-bit FA value + + // noise generator circuit + UINT8 m_noise_clock; // clock input to noise generator + UINT32 m_shift_252; // shift register @ 252 + UINT8 m_counter_250; // 4-bit counter @ 250 + + // stages outputs history + double m_ni_hist[4]; + double m_no_hist[4]; + double m_va_hist[4]; + double m_s1_hist[4]; + double m_s2g_hist[4]; + double m_s2ni_hist[4]; + double m_s2n_hist[4]; + double m_s2_hist[4]; + double m_s3_hist[4]; + double m_s4i_hist[4]; + double m_s4_hist[4]; + + // static tables + static const char *const s_phoneme_table[64]; + static const double s_glottal_wave[16]; +}; + + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +// device type definition +extern const device_type VOTRAX_SC01; + + +#endif /* __VOTRAX_H__ */ diff --git a/src/devices/sound/vrc6.c b/src/devices/sound/vrc6.c new file mode 100644 index 00000000000..91775d932b6 --- /dev/null +++ b/src/devices/sound/vrc6.c @@ -0,0 +1,320 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/*************************************************************************** + + vrc6.c + Konami VRC6 additional sound channels + + Emulation by R. Belmont + + References: + http://wiki.nesdev.com/w/index.php/VRC6_audio + http://nesdev.com/vrcvi.txt + +***************************************************************************/ + +#include "emu.h" +#include "vrc6.h" + +#define DISABLE_VRC6_SOUND // not ready yet + +// device type definition +const device_type VRC6 = &device_creator; + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// vrc6snd_device - constructor +//------------------------------------------------- + +vrc6snd_device::vrc6snd_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, VRC6, "VRC6 sound", tag, owner, clock, "vrc6snd", __FILE__), + device_sound_interface(mconfig, *this) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void vrc6snd_device::device_start() +{ + m_stream = machine().sound().stream_alloc(*this, 0, 1, clock()); + + m_freqctrl = m_pulsectrl[0] = m_pulsectrl[1] = 0; + m_pulsefrql[0] = m_pulsefrql[1] = m_pulsefrqh[0] = m_pulsefrqh[1] = 0; + m_sawaccum = m_sawfrql = m_sawfrqh = m_sawclock = m_sawrate = 0; + m_ticks[0] = m_ticks[1] = m_ticks[2] = 0; + m_output[0] = m_output[1] = m_output[2] = 0; + m_pulseduty[0] = m_pulseduty[1] = 15; + + save_item(NAME(m_freqctrl)); + save_item(NAME(m_pulsectrl)); + save_item(NAME(m_sawrate)); + save_item(NAME(m_sawaccum)); + save_item(NAME(m_pulsefrql)); + save_item(NAME(m_pulsefrqh)); + save_item(NAME(m_sawfrql)); + save_item(NAME(m_sawfrqh)); + save_item(NAME(m_ticks)); + save_item(NAME(m_output)); + save_item(NAME(m_pulseduty)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void vrc6snd_device::device_reset() +{ + m_stream->update(); + + m_freqctrl = m_pulsectrl[0] = m_pulsectrl[1] = 0; + m_pulsefrql[0] = m_pulsefrql[1] = 0; + m_sawaccum = m_sawfrql = m_sawclock = m_sawrate = 0; + m_ticks[0] = m_ticks[1] = m_ticks[2] = 0; + m_output[0] = m_output[1] = m_output[2] = 0; + m_pulseduty[0] = m_pulseduty[1] = 15; + m_pulsefrqh[0] = m_pulsefrqh[1] = m_sawfrqh = 0; +} + +//------------------------------------------------- +// sound_stream_update - handle update requests for +// our sound stream +//------------------------------------------------- + +void vrc6snd_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + stream_sample_t *out = outputs[0]; + INT16 tmp; + int i; + + // check global halt bit + if (m_freqctrl & 1) + { + return; + } + + for (i = 0; i < samples; i++) + { + // update pulse1 + if (m_pulsefrqh[0] & 0x80) + { + m_ticks[0]--; + if (m_ticks[0] == 0) + { + m_ticks[0] = m_pulsefrql[0] | (m_pulsefrqh[0] & 0xf)<<4; + + m_pulseduty[0]--; + if (m_pulsectrl[0] & 0x80) + { + m_output[0] = m_pulsectrl[0] & 0xf; + } + else + { + if (m_pulseduty[0] <= ((m_pulsectrl[0]>>4) & 0x7)) + { + m_output[0] = m_pulsectrl[0] & 0xf; + } + else + { + m_output[0] = 0; + } + } + + if (m_pulseduty[0] == 0) + { + m_pulseduty[0] = 15; + } + } + } + else + { + m_output[0] = 0; + } + + // update pulse2 + if (m_pulsefrqh[1] & 0x80) + { + m_ticks[1]--; + if (m_ticks[1] == 0) + { + m_ticks[1] = m_pulsefrql[1] | (m_pulsefrqh[1] & 0xf)<<4; + + m_pulseduty[1]--; + if (m_pulsectrl[1] & 0x80) + { + m_output[1] = m_pulsectrl[1] & 0xf; + } + else + { + if (m_pulseduty[1] <= ((m_pulsectrl[1]>>4) & 0x7)) + { + m_output[1] = m_pulsectrl[1] & 0xf; + } + else + { + m_output[1] = 0; + } + } + + if (m_pulseduty[1] == 0) + { + m_pulseduty[1] = 15; + } + } + } + else + { + m_output[1] = 0; + } + + // update saw + if (m_sawfrqh & 0x80) + { + m_ticks[2]--; + if (m_ticks[2] == 0) + { + m_ticks[2] = m_sawfrql | (m_sawfrqh & 0xf)<<4; + + // only update on even steps + if ((m_sawclock > 0) && (!(m_sawclock & 1))) + { + m_sawaccum += (m_sawrate & 0x3f); + m_output[2] = (m_sawaccum>>3); + } + m_sawclock++; + + if (m_sawclock >= 14) + { + m_sawclock = m_sawaccum = 0; + m_output[2] = 0; + } + } + } + else + { + m_output[2] = 0; + } + + // sum 2 4-bit pulses, 1 5-bit saw = unsigned 6 bit output + tmp = (INT16)(UINT8)(m_output[0] + m_output[1] + m_output[2]); + tmp <<= 8; + + out[i] = tmp; + } +} + +//--------------------------------------- +// write - write to the chip's registers +//--------------------------------------- + +WRITE8_MEMBER( vrc6snd_device::write ) +{ + switch (offset >> 8) + { + case 0: + m_stream->update(); + switch (offset & 3) + { + case 0: + m_pulsectrl[0] = data; + break; + + case 1: + m_pulsefrql[0] = data; + if (!(m_pulsefrqh[1] & 0x80)) + { + m_ticks[0] &= ~0xff; + m_ticks[0] |= m_pulsefrql[0]; + } + break; + + case 2: + #ifndef DISABLE_VRC6_SOUND + m_pulsefrqh[0] = data; + // if disabling channel, reset phase + if (!(data & 0x80)) + { + m_pulseduty[0] = 15; + m_ticks[0] &= 0xff; + m_ticks[0] |= (m_pulsefrqh[0] & 0xf)<<4; + } + #endif + break; + + case 3: + m_freqctrl = data; + break; + } + break; + + case 1: + m_stream->update(); + switch (offset & 3) + { + case 0: + m_pulsectrl[1] = data; + break; + + case 1: + m_pulsefrql[1] = data; + if (!(m_pulsefrqh[1] & 0x80)) + { + m_ticks[1] &= ~0xff; + m_ticks[1] |= m_pulsefrql[1]; + } + break; + + case 2: + #ifndef DISABLE_VRC6_SOUND + m_pulsefrqh[1] = data; + // if disabling channel, reset phase + if (!(data & 0x80)) + { + m_pulseduty[1] = 15; + m_ticks[1] &= 0xff; + m_ticks[1] |= (m_pulsefrqh[1] & 0xf)<<4; + } + #endif + break; + } + break; + + case 2: + m_stream->update(); + switch (offset & 3) + { + case 0: + m_sawrate = data; + break; + + case 1: + m_sawfrql = data; + if (!(m_sawfrqh & 0x80)) + { + m_ticks[2] &= ~0xff; + m_ticks[2] |= m_sawfrql; + } + break; + + case 2: + #ifndef DISABLE_VRC6_SOUND + m_sawfrqh = data; + // if disabling channel, reset phase + if (!(data & 0x80)) + { + m_sawaccum = 0; + m_ticks[2] &= 0xff; + m_ticks[2] |= (m_sawfrqh & 0xf)<<4; + } + #endif + break; + } + break; + } + +} diff --git a/src/devices/sound/vrc6.h b/src/devices/sound/vrc6.h new file mode 100644 index 00000000000..db2cdffd542 --- /dev/null +++ b/src/devices/sound/vrc6.h @@ -0,0 +1,61 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/*************************************************************************** + + vrc6.h + Konami VRC6 add-on sound + +***************************************************************************/ + +#pragma once + +#ifndef __VRC6_H__ +#define __VRC6_H__ + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_VRC6_ADD(_tag, _clock) \ + MCFG_DEVICE_ADD(_tag, VRC6, _clock) + +#define MCFG_VRC6_REPLACE(_tag, _clock) \ + MCFG_DEVICE_REPLACE(_tag, VRC6, _clock) + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> vrc6snd_device + +class vrc6snd_device : public device_t, public device_sound_interface +{ +public: + // construction/destruction + vrc6snd_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + DECLARE_WRITE8_MEMBER(write); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + +private: + UINT8 m_freqctrl, m_pulsectrl[2], m_sawrate; + UINT8 m_pulsefrql[2], m_pulsefrqh[2], m_pulseduty[2]; + UINT8 m_sawfrql, m_sawfrqh, m_sawclock, m_sawaccum; + UINT16 m_ticks[3]; + UINT8 m_output[3]; + + sound_stream *m_stream; +}; + + +// device type definition +extern const device_type VRC6; + + +#endif /* __VRC6_H__ */ diff --git a/src/devices/sound/vrender0.c b/src/devices/sound/vrender0.c new file mode 100644 index 00000000000..b13f4556525 --- /dev/null +++ b/src/devices/sound/vrender0.c @@ -0,0 +1,250 @@ +// license:BSD-3-Clause +// copyright-holders:ElSemi +#include "emu.h" +#include "vrender0.h" + +/*********************************** + VRENDER ZERO + AUDIO EMULATION +************************************/ +/************ +MISSING: +envelopes +reverb +interrupts +*************/ + +//Correct table thanks to Evoga +//they left a ulaw<->linear conversion tool inside the roms +static const unsigned short ULawTo16[]= +{ + 0x8000,0x8400,0x8800,0x8C00,0x9000,0x9400,0x9800,0x9C00, + 0xA000,0xA400,0xA800,0xAC00,0xB000,0xB400,0xB800,0xBC00, + 0x4000,0x4400,0x4800,0x4C00,0x5000,0x5400,0x5800,0x5C00, + 0x6000,0x6400,0x6800,0x6C00,0x7000,0x7400,0x7800,0x7C00, + 0xC000,0xC200,0xC400,0xC600,0xC800,0xCA00,0xCC00,0xCE00, + 0xD000,0xD200,0xD400,0xD600,0xD800,0xDA00,0xDC00,0xDE00, + 0x2000,0x2200,0x2400,0x2600,0x2800,0x2A00,0x2C00,0x2E00, + 0x3000,0x3200,0x3400,0x3600,0x3800,0x3A00,0x3C00,0x3E00, + 0xE000,0xE100,0xE200,0xE300,0xE400,0xE500,0xE600,0xE700, + 0xE800,0xE900,0xEA00,0xEB00,0xEC00,0xED00,0xEE00,0xEF00, + 0x1000,0x1100,0x1200,0x1300,0x1400,0x1500,0x1600,0x1700, + 0x1800,0x1900,0x1A00,0x1B00,0x1C00,0x1D00,0x1E00,0x1F00, + 0xF000,0xF080,0xF100,0xF180,0xF200,0xF280,0xF300,0xF380, + 0xF400,0xF480,0xF500,0xF580,0xF600,0xF680,0xF700,0xF780, + 0x0800,0x0880,0x0900,0x0980,0x0A00,0x0A80,0x0B00,0x0B80, + 0x0C00,0x0C80,0x0D00,0x0D80,0x0E00,0x0E80,0x0F00,0x0F80, + 0xF800,0xF840,0xF880,0xF8C0,0xF900,0xF940,0xF980,0xF9C0, + 0xFA00,0xFA40,0xFA80,0xFAC0,0xFB00,0xFB40,0xFB80,0xFBC0, + 0x0400,0x0440,0x0480,0x04C0,0x0500,0x0540,0x0580,0x05C0, + 0x0600,0x0640,0x0680,0x06C0,0x0700,0x0740,0x0780,0x07C0, + 0xFC00,0xFC20,0xFC40,0xFC60,0xFC80,0xFCA0,0xFCC0,0xFCE0, + 0xFD00,0xFD20,0xFD40,0xFD60,0xFD80,0xFDA0,0xFDC0,0xFDE0, + 0x0200,0x0220,0x0240,0x0260,0x0280,0x02A0,0x02C0,0x02E0, + 0x0300,0x0320,0x0340,0x0360,0x0380,0x03A0,0x03C0,0x03E0, + 0xFE00,0xFE10,0xFE20,0xFE30,0xFE40,0xFE50,0xFE60,0xFE70, + 0xFE80,0xFE90,0xFEA0,0xFEB0,0xFEC0,0xFED0,0xFEE0,0xFEF0, + 0x0100,0x0110,0x0120,0x0130,0x0140,0x0150,0x0160,0x0170, + 0x0180,0x0190,0x01A0,0x01B0,0x01C0,0x01D0,0x01E0,0x01F0, + 0x0000,0x0008,0x0010,0x0018,0x0020,0x0028,0x0030,0x0038, + 0x0040,0x0048,0x0050,0x0058,0x0060,0x0068,0x0070,0x0078, + 0xFF80,0xFF88,0xFF90,0xFF98,0xFFA0,0xFFA8,0xFFB0,0xFFB8, + 0xFFC0,0xFFC8,0xFFD0,0xFFD8,0xFFE0,0xFFE8,0xFFF0,0xFFF8, +}; + + +#define STATUS m_SOUNDREGS[0x404/4] +#define CURSADDR(chan) (m_SOUNDREGS[(0x20/4)*chan+0x00]) +#define DSADDR(chan) ((m_SOUNDREGS[(0x20/4)*chan+0x08/4]>>0)&0xffff) +#define LOOPBEGIN(chan) (m_SOUNDREGS[(0x20/4)*chan+0x0c/4]&0x3fffff) +#define LOOPEND(chan) (m_SOUNDREGS[(0x20/4)*chan+0x10/4]&0x3fffff) +#define ENVVOL(chan) (m_SOUNDREGS[(0x20/4)*chan+0x04/4]&0xffffff) + +/* +#define GETSOUNDREG16(Chan,Offs) space.read_word(m_reg_base+0x20*Chan+Offs) +#define GETSOUNDREG32(Chan,Offs) space.read_dword(m_reg_base+0x20*Chan+Offs) + +#define CURSADDR(chan) GETSOUNDREG32(chan,0x00) +#define DSADDR(chan) GETSOUNDREG16(chan,0x08) +#define LOOPBEGIN(chan) (GETSOUNDREG32(chan,0x0c)&0x3fffff) +#define LOOPEND(chan) (GETSOUNDREG32(chan,0x10)&0x3fffff) +#define ENVVOL(chan) (GETSOUNDREG32(chan,0x04)&0xffffff) +*/ + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +const device_type VRENDER0 = &device_creator; + +//------------------------------------------------- +// vrender0_device - constructor +//------------------------------------------------- + +vrender0_device::vrender0_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, VRENDER0, "VRender0", tag, owner, clock, "vrender0", __FILE__), + device_sound_interface(mconfig, *this), + m_TexBase(NULL), + m_FBBase(NULL), + m_stream(NULL), + m_reg_base(0) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void vrender0_device::device_start() +{ + memset(m_SOUNDREGS,0,sizeof(m_SOUNDREGS)); + + m_stream = stream_alloc(0, 2, 44100); + + save_item(NAME(m_SOUNDREGS)); +} + + +//------------------------------------------------- +// sound_stream_update - handle update requests +// for our sound stream +//------------------------------------------------- + +void vrender0_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + VR0_RenderAudio(samples, outputs[0], outputs[1]); +} + + + +READ32_MEMBER(vrender0_device::vr0_snd_read) +{ + return m_SOUNDREGS[offset]; +} + + +WRITE32_MEMBER(vrender0_device::vr0_snd_write) +{ + if(offset==0x404/4) + { + data&=0xffff; + if(data&0x8000) + { + UINT32 c=data&0x1f; + STATUS|=1<>0)&0xff; + UINT32 NCH=(m_SOUNDREGS[0x600/4]>>8)&0xff; + UINT32 CT1=(m_SOUNDREGS[0x600/4]>>16)&0xff; + UINT32 CT2=(m_SOUNDREGS[0x600/4]>>24)&0xff; + int div; + int s; + + + if(CT1&0x20) + SAMPLES=(INT16 *)m_TexBase; + else + SAMPLES=(INT16 *)m_FBBase; + + if(CLK) + div=((30<<16)|0x8000)/(CLK+1); + else + div=1<<16; + + for(s=0;s>10); + UINT8 Mode=m_SOUNDREGS[(0x20/4)*i+0x8/4]>>24; + signed int LVOL=m_SOUNDREGS[(0x20/4)*i+0xc/4]>>24; + signed int RVOL=m_SOUNDREGS[(0x20/4)*i+0x10/4]>>24; + + INT32 DSADD=(DSADDR(i)*div)>>16; + + if(!(st&(1<>=8; + sample=(signed short)ULawTo16[s&0xff]; + } + else + { + if(Mode&0x20) //8bit + { + UINT16 s=SAMPLES[a]; + if((cur&0x200)) + s>>=8; + sample=(signed short) (((signed char) (s&0xff))<<8); + } + else //16bit + { + sample=SAMPLES[a]; + } + } + + CURSADDR(i)+=DSADD; + if(a>=LOOPEND(i)) + { + if(Mode&1) //Loop + CURSADDR(i)=0;//LOOPBEGIN(i)<<10; + else + { + STATUS&=~(1<<(i&0x1f)); + break; + } + } +// UINT32 v=(ENVVOL(i))>>8; +// sample=(sample*v)>>16; + lsample+=(sample*LVOL)>>8; + rsample+=(sample*RVOL)>>8; + } + if(lsample>32767) + lsample=32767; + if(lsample<-32768) + lsample=-32768; + l[s]=lsample; + if(rsample>32767) + rsample=32767; + if(rsample<-32768) + rsample=-32768; + r[s]=rsample; + } +} diff --git a/src/devices/sound/vrender0.h b/src/devices/sound/vrender0.h new file mode 100644 index 00000000000..9baaefac203 --- /dev/null +++ b/src/devices/sound/vrender0.h @@ -0,0 +1,63 @@ +// license:BSD-3-Clause +// copyright-holders:ElSemi +#pragma once + +#ifndef __VRENDER0_H__ +#define __VRENDER0_H__ + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_SOUND_VRENDER0_ADD(_tag, _clock) \ + MCFG_DEVICE_ADD(_tag, VRENDER0, _clock) +#define MCFG_SOUND_VRENDER0_REPLACE(_tag, _clock) \ + MCFG_DEVICE_REPLACE(_tag, VRENDER0, _clock) + +#define MCFG_VR0_REGBASE(_base) \ + vrender0_device::set_reg_base(*device, _base); + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + + +// ======================> vrender0_device + +class vrender0_device : public device_t, + public device_sound_interface +{ +public: + vrender0_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + ~vrender0_device() { } + + // static configuration + static void set_reg_base(device_t &device, int base) { downcast(device).m_reg_base = base; } + + DECLARE_READ32_MEMBER( vr0_snd_read ); + DECLARE_WRITE32_MEMBER( vr0_snd_write ); + + void set_areas(UINT32 *texture, UINT32 *frame); + +protected: + // device-level overrides + virtual void device_start(); + + // sound stream update overrides + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + +private: + UINT32 *m_TexBase; + UINT32 *m_FBBase; + UINT32 m_SOUNDREGS[0x10000/4]; + sound_stream *m_stream; + UINT32 m_reg_base; + + void VR0_RenderAudio(int nsamples, stream_sample_t *l, stream_sample_t *r); +}; + +extern const device_type VRENDER0; + + +#endif /* __VRENDER0_H__ */ diff --git a/src/devices/sound/wave.c b/src/devices/sound/wave.c new file mode 100644 index 00000000000..76f9bdda8d6 --- /dev/null +++ b/src/devices/sound/wave.c @@ -0,0 +1,110 @@ +// license:BSD-3-Clause +// copyright-holders:Nathan Woods +/*************************************************************************** + + wave.c + + Code that interfaces + Functions to handle loading, creation, recording and playback + of wave samples for IO_CASSETTE + + 2010-06-19 - Found that since 0.132, the right channel is badly out of + sync on a mono system, causing bad sound. Added code to disable + the second channel on a mono system. + + +****************************************************************************/ + +#include "emu.h" +#include "wave.h" + +#define ALWAYS_PLAY_SOUND 0 + + + +void wave_device::static_set_cassette_tag(device_t &device, const char *cassette_tag) +{ + wave_device &wave = downcast(device); + wave.m_cassette_tag = cassette_tag; +} + +const device_type WAVE = &device_creator; + +wave_device::wave_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, WAVE, "Wave", tag, owner, clock, "wave", __FILE__), + device_sound_interface(mconfig, *this) +{ + m_cassette_tag = 0; +} + +//------------------------------------------------- +// device_config_complete - perform any +// operations now that the configuration is +// complete +//------------------------------------------------- + +void wave_device::device_config_complete() +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void wave_device::device_start() +{ + speaker_device_iterator spkiter(machine().root_device()); + int speakers = spkiter.count(); + if (speakers > 1) + machine().sound().stream_alloc(*this, 0, 2, machine().sample_rate()); + else + machine().sound().stream_alloc(*this, 0, 1, machine().sample_rate()); + m_cass = machine().device(m_cassette_tag); +} + +//------------------------------------------------- +// sound_stream_update - handle a stream update +//------------------------------------------------- + +void wave_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + cassette_state state; + double time_index; + double duration; + stream_sample_t *left_buffer = outputs[0]; + stream_sample_t *right_buffer = NULL; + int i; + + speaker_device_iterator spkiter(m_cass->machine().root_device()); + int speakers = spkiter.count(); + if (speakers>1) + right_buffer = outputs[1]; + + state = m_cass->get_state(); + + state = (cassette_state)(state & (CASSETTE_MASK_UISTATE | CASSETTE_MASK_MOTOR | CASSETTE_MASK_SPEAKER)); + + if (m_cass->exists() && (ALWAYS_PLAY_SOUND || (state == (CASSETTE_PLAY | CASSETTE_MOTOR_ENABLED | CASSETTE_SPEAKER_ENABLED)))) + { + cassette_image *cassette = m_cass->get_image(); + time_index = m_cass->get_position(); + duration = ((double) samples) / m_cass->machine().sample_rate(); + + cassette_get_samples(cassette, 0, time_index, duration, samples, 2, left_buffer, CASSETTE_WAVEFORM_16BIT); + if (speakers > 1) + cassette_get_samples(cassette, 1, time_index, duration, samples, 2, right_buffer, CASSETTE_WAVEFORM_16BIT); + + for (i = samples - 1; i >= 0; i--) + { + left_buffer[i] = ((INT16 *) left_buffer)[i]; + if (speakers > 1) + right_buffer[i] = ((INT16 *) right_buffer)[i]; + } + } + else + { + memset(left_buffer, 0, sizeof(*left_buffer) * samples); + if (speakers > 1) + memset(right_buffer, 0, sizeof(*right_buffer) * samples); + } +} diff --git a/src/devices/sound/wave.h b/src/devices/sound/wave.h new file mode 100644 index 00000000000..d4ff4865551 --- /dev/null +++ b/src/devices/sound/wave.h @@ -0,0 +1,47 @@ +// license:BSD-3-Clause +// copyright-holders:Nathan Woods +#pragma once + +#ifndef __WAVE_H__ +#define __WAVE_H__ + +#include "imagedev/cassette.h" + + +/***************************************************************************** + * CassetteWave interface + *****************************************************************************/ + +class wave_device : public device_t, + public device_sound_interface +{ +public: + wave_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + static void static_set_cassette_tag(device_t &device, const char *cassette_tag); + +protected: + // device-level overrides + virtual void device_config_complete(); + virtual void device_start(); + + // sound stream update overrides + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + +private: + const char *m_cassette_tag; + cassette_image_device *m_cass; +}; + +extern const device_type WAVE; + + +#define WAVE_TAG "wave" +#define WAVE2_TAG "wave2" + + +#define MCFG_SOUND_WAVE_ADD(_tag, _cass_tag) \ + MCFG_SOUND_ADD( _tag, WAVE, 0 ) \ + wave_device::static_set_cassette_tag(*device, _cass_tag); + +#endif /* __WAVE_H__ */ diff --git a/src/devices/sound/wavwrite.c b/src/devices/sound/wavwrite.c new file mode 100644 index 00000000000..baf5498f02c --- /dev/null +++ b/src/devices/sound/wavwrite.c @@ -0,0 +1,189 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +#include "emu.h" +#include "sound/wavwrite.h" + +struct wav_file +{ + FILE *file; + UINT32 total_offs; + UINT32 data_offs; +}; + + +wav_file *wav_open(const char *filename, int sample_rate, int channels) +{ + wav_file *wav; + UINT32 bps, temp32; + UINT16 align, temp16; + + /* allocate memory for the wav struct */ + wav = (wav_file *) global_alloc(wav_file); + if (!wav) + return NULL; + + /* create the file */ + wav->file = fopen(filename, "wb"); + if (!wav->file) + { + global_free(wav); + return NULL; + } + + /* write the 'RIFF' header */ + fwrite("RIFF", 1, 4, wav->file); + + /* write the total size */ + temp32 = 0; + wav->total_offs = ftell(wav->file); + fwrite(&temp32, 1, 4, wav->file); + + /* write the 'WAVE' type */ + fwrite("WAVE", 1, 4, wav->file); + + /* write the 'fmt ' tag */ + fwrite("fmt ", 1, 4, wav->file); + + /* write the format length */ + temp32 = LITTLE_ENDIANIZE_INT32(16); + fwrite(&temp32, 1, 4, wav->file); + + /* write the format (PCM) */ + temp16 = LITTLE_ENDIANIZE_INT16(1); + fwrite(&temp16, 1, 2, wav->file); + + /* write the channels */ + temp16 = LITTLE_ENDIANIZE_INT16(channels); + fwrite(&temp16, 1, 2, wav->file); + + /* write the sample rate */ + temp32 = LITTLE_ENDIANIZE_INT32(sample_rate); + fwrite(&temp32, 1, 4, wav->file); + + /* write the bytes/second */ + bps = sample_rate * 2 * channels; + temp32 = LITTLE_ENDIANIZE_INT32(bps); + fwrite(&temp32, 1, 4, wav->file); + + /* write the block align */ + align = 2 * channels; + temp16 = LITTLE_ENDIANIZE_INT16(align); + fwrite(&temp16, 1, 2, wav->file); + + /* write the bits/sample */ + temp16 = LITTLE_ENDIANIZE_INT16(16); + fwrite(&temp16, 1, 2, wav->file); + + /* write the 'data' tag */ + fwrite("data", 1, 4, wav->file); + + /* write the data length */ + temp32 = 0; + wav->data_offs = ftell(wav->file); + fwrite(&temp32, 1, 4, wav->file); + + return wav; +} + + +void wav_close(wav_file *wav) +{ + UINT32 total; + UINT32 temp32; + + if (!wav) return; + + total = ftell(wav->file); + + /* update the total file size */ + fseek(wav->file, wav->total_offs, SEEK_SET); + temp32 = total - (wav->total_offs + 4); + temp32 = LITTLE_ENDIANIZE_INT32(temp32); + fwrite(&temp32, 1, 4, wav->file); + + /* update the data size */ + fseek(wav->file, wav->data_offs, SEEK_SET); + temp32 = total - (wav->data_offs + 4); + temp32 = LITTLE_ENDIANIZE_INT32(temp32); + fwrite(&temp32, 1, 4, wav->file); + + fclose(wav->file); + global_free(wav); +} + + +void wav_add_data_16(wav_file *wav, INT16 *data, int samples) +{ + if (!wav) return; + + /* just write and flush the data */ + fwrite(data, 2, samples, wav->file); + fflush(wav->file); +} + + +void wav_add_data_32(wav_file *wav, INT32 *data, int samples, int shift) +{ + std::vector temp; + int i; + + if (!wav || !samples) return; + + /* resize dynamic array */ + temp.resize(samples); + + /* clamp */ + for (i = 0; i < samples; i++) + { + int val = data[i] >> shift; + temp[i] = (val < -32768) ? -32768 : (val > 32767) ? 32767 : val; + } + + /* write and flush */ + fwrite(&temp[0], 2, samples, wav->file); + fflush(wav->file); +} + + +void wav_add_data_16lr(wav_file *wav, INT16 *left, INT16 *right, int samples) +{ + std::vector temp; + int i; + + if (!wav || !samples) return; + + /* resize dynamic array */ + temp.resize(samples * 2); + + /* interleave */ + for (i = 0; i < samples * 2; i++) + temp[i] = (i & 1) ? right[i / 2] : left[i / 2]; + + /* write and flush */ + fwrite(&temp[0], 4, samples, wav->file); + fflush(wav->file); +} + + +void wav_add_data_32lr(wav_file *wav, INT32 *left, INT32 *right, int samples, int shift) +{ + std::vector temp; + int i; + + if (!wav || !samples) return; + + /* resize dynamic array */ + temp.resize(samples); + + /* interleave */ + for (i = 0; i < samples * 2; i++) + { + int val = (i & 1) ? right[i / 2] : left[i / 2]; + val >>= shift; + temp[i] = (val < -32768) ? -32768 : (val > 32767) ? 32767 : val; + } + + /* write and flush */ + fwrite(&temp[0], 4, samples, wav->file); + fflush(wav->file); +} diff --git a/src/devices/sound/wavwrite.h b/src/devices/sound/wavwrite.h new file mode 100644 index 00000000000..376856fb16f --- /dev/null +++ b/src/devices/sound/wavwrite.h @@ -0,0 +1,18 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +#pragma once + +#ifndef __WAVWRITE_H__ +#define __WAVWRITE_H__ + +struct wav_file; + +wav_file *wav_open(const char *filename, int sample_rate, int channels); +void wav_close(wav_file*wavptr); + +void wav_add_data_16(wav_file *wavptr, INT16 *data, int samples); +void wav_add_data_32(wav_file *wavptr, INT32 *data, int samples, int shift); +void wav_add_data_16lr(wav_file *wavptr, INT16 *left, INT16 *right, int samples); +void wav_add_data_32lr(wav_file *wavptr, INT32 *left, INT32 *right, int samples, int shift); + +#endif /* __WAVWRITE_H__ */ diff --git a/src/devices/sound/x1_010.c b/src/devices/sound/x1_010.c new file mode 100644 index 00000000000..5d8377569bb --- /dev/null +++ b/src/devices/sound/x1_010.c @@ -0,0 +1,276 @@ +// license:BSD-3-Clause +// copyright-holders:Luca Elia +/*************************************************************************** + + -= Seta Hardware =- + + driver by Luca Elia (l.elia@tin.it) + + rewrite by Manbow-J(manbowj@hamal.freemail.ne.jp) + + X1-010 Seta Custom Sound Chip (80 Pin PQFP) + + Custom programmed Mitsubishi M60016 Gate Array, 3608 gates, 148 Max I/O ports + + The X1-010 is 16 Voices sound generator, each channel gets it's + waveform from RAM (128 bytes per waveform, 8 bit unsigned data) + or sampling PCM(8bit unsigned data). + +Registers: + 8 registers per channel (mapped to the lower bytes of 16 words on the 68K) + + Reg: Bits: Meaning: + + 0 7--- ---- Frequency divider flag (only downtown seems to set this) + -654 3--- + ---- -2-- PCM/Waveform repeat flag (0:Ones 1:Repeat) (*1) + ---- --1- Sound out select (0:PCM 1:Waveform) + ---- ---0 Key on / off + + 1 7654 ---- PCM Volume 1 (L?) + ---- 3210 PCM Volume 2 (R?) + Waveform No. + + 2 PCM Frequency + Waveform Pitch Lo + + 3 Waveform Pitch Hi + + 4 PCM Sample Start / 0x1000 [Start/End in bytes] + Waveform Envelope Time + + 5 PCM Sample End 0x100 - (Sample End / 0x1000) [PCM ROM is Max 1MB?] + Waveform Envelope No. + 6 Reserved + 7 Reserved + + offset 0x0000 - 0x0fff Wave form data + offset 0x1000 - 0x1fff Envelope data + + *1 : when 0 is specified, hardware interrupt is caused(allways return soon) + +***************************************************************************/ + +#include "emu.h" +#include "x1_010.h" + + +#define VERBOSE_SOUND 0 +#define VERBOSE_REGISTER_WRITE 0 +#define VERBOSE_REGISTER_READ 0 + +#define LOG_SOUND(x) do { if (VERBOSE_SOUND) logerror x; } while (0) +#define LOG_REGISTER_WRITE(x) do { if (VERBOSE_REGISTER_WRITE) logerror x; } while (0) +#define LOG_REGISTER_READ(x) do { if (VERBOSE_REGISTER_READ) logerror x; } while (0) + +#define FREQ_BASE_BITS 8 // Frequency fixed decimal shift bits +#define ENV_BASE_BITS 16 // wave form envelope fixed decimal shift bits +#define VOL_BASE (2*32*256/30) // Volume base + +/* this structure defines the parameters for a channel */ +struct X1_010_CHANNEL { + unsigned char status; + unsigned char volume; // volume / wave form no. + unsigned char frequency; // frequency / pitch lo + unsigned char pitch_hi; // reserved / pitch hi + unsigned char start; // start address / envelope time + unsigned char end; // end address / envelope no. + unsigned char reserve[2]; +}; + + +/* mixer tables and internal buffers */ +//static short *mixer_buffer = NULL; + + +const device_type X1_010 = &device_creator; + +x1_010_device::x1_010_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, X1_010, "X1-010", tag, owner, clock, "x1_010", __FILE__), + device_sound_interface(mconfig, *this), + m_region(*this, DEVICE_SELF), + m_rate(0), + m_adr(0), + m_stream(NULL), + m_sound_enable(0), + m_base_clock(0) +{ + memset(m_reg, 0, sizeof(m_reg)); + memset(m_HI_WORD_BUF, 0, sizeof(m_HI_WORD_BUF)); + memset(m_smp_offset, 0, sizeof(SETA_NUM_CHANNELS)); + memset(m_env_offset, 0, sizeof(SETA_NUM_CHANNELS)); +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void x1_010_device::device_start() +{ + int i; + + m_base_clock = clock(); + m_rate = clock() / 1024; + + for( i = 0; i < SETA_NUM_CHANNELS; i++ ) { + m_smp_offset[i] = 0; + m_env_offset[i] = 0; + } + /* Print some more debug info */ + LOG_SOUND(("masterclock = %d rate = %d\n", clock(), m_rate )); + + /* get stream channels */ + m_stream = machine().sound().stream_alloc(*this, 0, 2, m_rate); + + save_item(NAME(m_rate)); + save_item(NAME(m_sound_enable)); + save_item(NAME(m_reg)); + save_item(NAME(m_HI_WORD_BUF)); + save_item(NAME(m_smp_offset)); + save_item(NAME(m_env_offset)); + save_item(NAME(m_base_clock)); +} + + +void x1_010_device::enable_w(int data) +{ + m_sound_enable = data; +} + +/* Use these for 8 bit CPUs */ + + +READ8_MEMBER( x1_010_device::read ) +{ + offset ^= m_adr; + return m_reg[offset]; +} + +WRITE8_MEMBER( x1_010_device::write ) +{ + int channel, reg; + offset ^= m_adr; + + channel = offset/sizeof(X1_010_CHANNEL); + reg = offset%sizeof(X1_010_CHANNEL); + + if( channel < SETA_NUM_CHANNELS && reg == 0 + && (m_reg[offset]&1) == 0 && (data&1) != 0 ) { + m_smp_offset[channel] = 0; + m_env_offset[channel] = 0; + } + LOG_REGISTER_WRITE(("%s: offset %6X : data %2X\n", machine().describe_context(), offset, data )); + m_reg[offset] = data; +} + + +/* Use these for 16 bit CPUs */ + +READ16_MEMBER( x1_010_device::word_r ) +{ + UINT16 ret; + + ret = m_HI_WORD_BUF[offset]<<8; + ret += (read( space, offset )&0xff); + LOG_REGISTER_READ(( "%s: Read X1-010 Offset:%04X Data:%04X\n", machine().describe_context(), offset, ret )); + return ret; +} + +WRITE16_MEMBER( x1_010_device::word_w ) +{ + m_HI_WORD_BUF[offset] = (data>>8)&0xff; + write( space, offset, data&0xff ); + LOG_REGISTER_WRITE(( "%s: Write X1-010 Offset:%04X Data:%04X\n", machine().describe_context(), offset, data )); +} + + +//------------------------------------------------- +// sound_stream_update - handle a stream update +//------------------------------------------------- + +void x1_010_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + X1_010_CHANNEL *reg; + int ch, i, volL, volR, freq, div; + register INT8 *start, *end, data; + register UINT8 *env; + register UINT32 smp_offs, smp_step, env_offs, env_step, delta; + + // mixer buffer zero clear + memset( outputs[0], 0, samples*sizeof(*outputs[0]) ); + memset( outputs[1], 0, samples*sizeof(*outputs[1]) ); + +// if( m_sound_enable == 0 ) return; + + for( ch = 0; ch < SETA_NUM_CHANNELS; ch++ ) { + reg = (X1_010_CHANNEL *)&(m_reg[ch*sizeof(X1_010_CHANNEL)]); + if( (reg->status&1) != 0 ) { // Key On + stream_sample_t *bufL = outputs[0]; + stream_sample_t *bufR = outputs[1]; + div = (reg->status&0x80) ? 1 : 0; + if( (reg->status&2) == 0 ) { // PCM sampling + start = m_region + reg->start*0x1000; + end = m_region + (0x100-reg->end)*0x1000; + volL = ((reg->volume>>4)&0xf)*VOL_BASE; + volR = ((reg->volume>>0)&0xf)*VOL_BASE; + smp_offs = m_smp_offset[ch]; + freq = reg->frequency>>div; + // Meta Fox does write the frequency register, but this is a hack to make it "work" with the current setup + // This is broken for Arbalester (it writes 8), but that'll be fixed later. + if( freq == 0 ) freq = 4; + smp_step = (UINT32)((float)m_base_clock/8192.0f + *freq*(1<>FREQ_BASE_BITS; + // sample ended? + if( start+delta >= end ) { + reg->status &= 0xfe; // Key off + break; + } + data = *(start+delta); + *bufL++ += (data*volL/256); + *bufR++ += (data*volR/256); + smp_offs += smp_step; + } + m_smp_offset[ch] = smp_offs; + } else { // Wave form + start = (INT8 *)&(m_reg[reg->volume*128+0x1000]); + smp_offs = m_smp_offset[ch]; + freq = ((reg->pitch_hi<<8)+reg->frequency)>>div; + smp_step = (UINT32)((float)m_base_clock/128.0f/1024.0f/4.0f*freq*(1<end*128]); + env_offs = m_env_offset[ch]; + env_step = (UINT32)((float)m_base_clock/128.0f/1024.0f/4.0f*reg->start*(1<volume, ch, reg->end, freq, smp_step, smp_offs )); + } + for( i = 0; i < samples; i++ ) { + int vol; + delta = env_offs>>ENV_BASE_BITS; + // Envelope one shot mode + if( (reg->status&4) != 0 && delta >= 0x80 ) { + reg->status &= 0xfe; // Key off + break; + } + vol = *(env+(delta&0x7f)); + volL = ((vol>>4)&0xf)*VOL_BASE; + volR = ((vol>>0)&0xf)*VOL_BASE; + data = *(start+((smp_offs>>FREQ_BASE_BITS)&0x7f)); + *bufL++ += (data*volL/256); + *bufR++ += (data*volR/256); + smp_offs += smp_step; + env_offs += env_step; + } + m_smp_offset[ch] = smp_offs; + m_env_offset[ch] = env_offs; + } + } + } +} diff --git a/src/devices/sound/x1_010.h b/src/devices/sound/x1_010.h new file mode 100644 index 00000000000..a5026124210 --- /dev/null +++ b/src/devices/sound/x1_010.h @@ -0,0 +1,58 @@ +// license:BSD-3-Clause +// copyright-holders:Luca Elia +#pragma once + +#ifndef __X1_010_H__ +#define __X1_010_H__ + +#define SETA_NUM_CHANNELS 16 + +class x1_010_device : public device_t, + public device_sound_interface +{ +public: + x1_010_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + ~x1_010_device() {} + + // static configuration + static void set_address(device_t &device, int addr) { downcast(device).m_adr = addr; } + + DECLARE_READ8_MEMBER ( read ); + DECLARE_WRITE8_MEMBER( write ); + + DECLARE_READ16_MEMBER ( word_r ); + DECLARE_WRITE16_MEMBER( word_w ); + + void enable_w(int data); + +protected: + // device-level overrides + virtual void device_start(); + + // sound stream update overrides + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); +private: + // internal state + + /* Variables only used here */ + required_region_ptr m_region; // ROM + int m_rate; // Output sampling rate (Hz) + int m_adr; // address + sound_stream * m_stream; // Stream handle + int m_sound_enable; // sound output enable/disable + UINT8 m_reg[0x2000]; // X1-010 Register & wave form area + UINT8 m_HI_WORD_BUF[0x2000]; // X1-010 16bit access ram check avoidance work + UINT32 m_smp_offset[SETA_NUM_CHANNELS]; + UINT32 m_env_offset[SETA_NUM_CHANNELS]; + + UINT32 m_base_clock; +}; + +extern const device_type X1_010; + + +#define MCFG_X1_010_ADDRESS(_addr) \ + x1_010_device::set_address(*device, _addr); + + +#endif /* __X1_010_H__ */ diff --git a/src/devices/sound/ym2151.c b/src/devices/sound/ym2151.c new file mode 100644 index 00000000000..804cbc5a6fd --- /dev/null +++ b/src/devices/sound/ym2151.c @@ -0,0 +1,2500 @@ +// license:??? +// copyright-holders:Jarek Burczynski +/***************************************************************************** +* +* Yamaha YM2151 driver (version 2.150 final beta) +* +******************************************************************************/ + +#include "emu.h" +#include "ym2151.h" + + +/* undef this to not use MAME timer system */ +#define USE_MAME_TIMERS + +/*#define FM_EMU*/ +#ifdef FM_EMU + #ifdef USE_MAME_TIMERS + #undef USE_MAME_TIMERS + #endif +#endif + +#define LOG_CYM_FILE 0 +static FILE * cymfile = NULL; + + +/* struct describing a single operator */ +struct YM2151Operator +{ + UINT32 phase; /* accumulated operator phase */ + UINT32 freq; /* operator frequency count */ + INT32 dt1; /* current DT1 (detune 1 phase inc/decrement) value */ + UINT32 mul; /* frequency count multiply */ + UINT32 dt1_i; /* DT1 index * 32 */ + UINT32 dt2; /* current DT2 (detune 2) value */ + + signed int *connect; /* operator output 'direction' */ + + /* only M1 (operator 0) is filled with this data: */ + signed int *mem_connect; /* where to put the delayed sample (MEM) */ + INT32 mem_value; /* delayed sample (MEM) value */ + + /* channel specific data; note: each operator number 0 contains channel specific data */ + UINT32 fb_shift; /* feedback shift value for operators 0 in each channel */ + INT32 fb_out_curr; /* operator feedback value (used only by operators 0) */ + INT32 fb_out_prev; /* previous feedback value (used only by operators 0) */ + UINT32 kc; /* channel KC (copied to all operators) */ + UINT32 kc_i; /* just for speedup */ + UINT32 pms; /* channel PMS */ + UINT32 ams; /* channel AMS */ + /* end of channel specific data */ + + UINT32 AMmask; /* LFO Amplitude Modulation enable mask */ + UINT32 state; /* Envelope state: 4-attack(AR) 3-decay(D1R) 2-sustain(D2R) 1-release(RR) 0-off */ + UINT8 eg_sh_ar; /* (attack state) */ + UINT8 eg_sel_ar; /* (attack state) */ + UINT32 tl; /* Total attenuation Level */ + INT32 volume; /* current envelope attenuation level */ + UINT8 eg_sh_d1r; /* (decay state) */ + UINT8 eg_sel_d1r; /* (decay state) */ + UINT32 d1l; /* envelope switches to sustain state after reaching this level */ + UINT8 eg_sh_d2r; /* (sustain state) */ + UINT8 eg_sel_d2r; /* (sustain state) */ + UINT8 eg_sh_rr; /* (release state) */ + UINT8 eg_sel_rr; /* (release state) */ + + UINT32 key; /* 0=last key was KEY OFF, 1=last key was KEY ON */ + + UINT32 ks; /* key scale */ + UINT32 ar; /* attack rate */ + UINT32 d1r; /* decay rate */ + UINT32 d2r; /* sustain rate */ + UINT32 rr; /* release rate */ + + UINT32 reserved0; /**/ + UINT32 reserved1; /**/ + +}; + + +struct YM2151 +{ + signed int chanout[8]; + signed int m2,c1,c2; /* Phase Modulation input for operators 2,3,4 */ + signed int mem; /* one sample delay memory */ + + YM2151Operator oper[32]; /* the 32 operators */ + + UINT32 pan[16]; /* channels output masks (0xffffffff = enable) */ + + UINT32 eg_cnt; /* global envelope generator counter */ + UINT32 eg_timer; /* global envelope generator counter works at frequency = chipclock/64/3 */ + UINT32 eg_timer_add; /* step of eg_timer */ + UINT32 eg_timer_overflow; /* envelope generator timer overlfows every 3 samples (on real chip) */ + + UINT32 lfo_phase; /* accumulated LFO phase (0 to 255) */ + UINT32 lfo_timer; /* LFO timer */ + UINT32 lfo_timer_add; /* step of lfo_timer */ + UINT32 lfo_overflow; /* LFO generates new output when lfo_timer reaches this value */ + UINT32 lfo_counter; /* LFO phase increment counter */ + UINT32 lfo_counter_add; /* step of lfo_counter */ + UINT8 lfo_wsel; /* LFO waveform (0-saw, 1-square, 2-triangle, 3-random noise) */ + UINT8 amd; /* LFO Amplitude Modulation Depth */ + INT8 pmd; /* LFO Phase Modulation Depth */ + UINT32 lfa; /* LFO current AM output */ + INT32 lfp; /* LFO current PM output */ + + UINT8 test; /* TEST register */ + UINT8 ct; /* output control pins (bit1-CT2, bit0-CT1) */ + + UINT32 noise; /* noise enable/period register (bit 7 - noise enable, bits 4-0 - noise period */ + UINT32 noise_rng; /* 17 bit noise shift register */ + UINT32 noise_p; /* current noise 'phase'*/ + UINT32 noise_f; /* current noise period */ + + UINT32 csm_req; /* CSM KEY ON / KEY OFF sequence request */ + + UINT32 irq_enable; /* IRQ enable for timer B (bit 3) and timer A (bit 2); bit 7 - CSM mode (keyon to all slots, everytime timer A overflows) */ + UINT32 status; /* chip status (BUSY, IRQ Flags) */ + UINT8 connect[8]; /* channels connections */ + +#ifdef USE_MAME_TIMERS +/* ASG 980324 -- added for tracking timers */ + emu_timer *timer_A; + emu_timer *timer_B; + attotime timer_A_time[1024]; /* timer A times for MAME */ + attotime timer_B_time[256]; /* timer B times for MAME */ + int irqlinestate; +#else + UINT8 tim_A; /* timer A enable (0-disabled) */ + UINT8 tim_B; /* timer B enable (0-disabled) */ + INT32 tim_A_val; /* current value of timer A */ + INT32 tim_B_val; /* current value of timer B */ + UINT32 tim_A_tab[1024]; /* timer A deltas */ + UINT32 tim_B_tab[256]; /* timer B deltas */ +#endif + UINT32 timer_A_index; /* timer A index */ + UINT32 timer_B_index; /* timer B index */ + UINT32 timer_A_index_old; /* timer A previous index */ + UINT32 timer_B_index_old; /* timer B previous index */ + + /* Frequency-deltas to get the closest frequency possible. + * There are 11 octaves because of DT2 (max 950 cents over base frequency) + * and LFO phase modulation (max 800 cents below AND over base frequency) + * Summary: octave explanation + * 0 note code - LFO PM + * 1 note code + * 2 note code + * 3 note code + * 4 note code + * 5 note code + * 6 note code + * 7 note code + * 8 note code + * 9 note code + DT2 + LFO PM + * 10 note code + DT2 + LFO PM + */ + UINT32 freq[11*768]; /* 11 octaves, 768 'cents' per octave */ + + /* Frequency deltas for DT1. These deltas alter operator frequency + * after it has been taken from frequency-deltas table. + */ + INT32 dt1_freq[8*32]; /* 8 DT1 levels, 32 KC values */ + + UINT32 noise_tab[32]; /* 17bit Noise Generator periods */ + + void (*irqhandler)(device_t *device, int irq); /* IRQ function handler */ + void (*porthandler)(device_t *, offs_t, UINT8); /* port write function handler */ + + device_t *device; + unsigned int clock; /* chip clock in Hz (passed from 2151intf.c) */ + unsigned int sampfreq; /* sampling frequency in Hz (passed from 2151intf.c) */ +}; + + +#define FREQ_SH 16 /* 16.16 fixed point (frequency calculations) */ +#define EG_SH 16 /* 16.16 fixed point (envelope generator timing) */ +#define LFO_SH 10 /* 22.10 fixed point (LFO calculations) */ +#define TIMER_SH 16 /* 16.16 fixed point (timers calculations) */ + +#define FREQ_MASK ((1<>3) + +/* sin waveform table in 'decibel' scale */ +static unsigned int sin_tab[SIN_LEN]; + + +/* translate from D1L to volume index (16 D1L levels) */ +static UINT32 d1l_tab[16]; + + +#define RATE_STEPS (8) +static const UINT8 eg_inc[19*RATE_STEPS]={ +/*cycle:0 1 2 3 4 5 6 7*/ + +/* 0 */ 0,1, 0,1, 0,1, 0,1, /* rates 00..11 0 (increment by 0 or 1) */ +/* 1 */ 0,1, 0,1, 1,1, 0,1, /* rates 00..11 1 */ +/* 2 */ 0,1, 1,1, 0,1, 1,1, /* rates 00..11 2 */ +/* 3 */ 0,1, 1,1, 1,1, 1,1, /* rates 00..11 3 */ + +/* 4 */ 1,1, 1,1, 1,1, 1,1, /* rate 12 0 (increment by 1) */ +/* 5 */ 1,1, 1,2, 1,1, 1,2, /* rate 12 1 */ +/* 6 */ 1,2, 1,2, 1,2, 1,2, /* rate 12 2 */ +/* 7 */ 1,2, 2,2, 1,2, 2,2, /* rate 12 3 */ + +/* 8 */ 2,2, 2,2, 2,2, 2,2, /* rate 13 0 (increment by 2) */ +/* 9 */ 2,2, 2,4, 2,2, 2,4, /* rate 13 1 */ +/*10 */ 2,4, 2,4, 2,4, 2,4, /* rate 13 2 */ +/*11 */ 2,4, 4,4, 2,4, 4,4, /* rate 13 3 */ + +/*12 */ 4,4, 4,4, 4,4, 4,4, /* rate 14 0 (increment by 4) */ +/*13 */ 4,4, 4,8, 4,4, 4,8, /* rate 14 1 */ +/*14 */ 4,8, 4,8, 4,8, 4,8, /* rate 14 2 */ +/*15 */ 4,8, 8,8, 4,8, 8,8, /* rate 14 3 */ + +/*16 */ 8,8, 8,8, 8,8, 8,8, /* rates 15 0, 15 1, 15 2, 15 3 (increment by 8) */ +/*17 */ 16,16,16,16,16,16,16,16, /* rates 15 2, 15 3 for attack */ +/*18 */ 0,0, 0,0, 0,0, 0,0, /* infinity rates for attack and decay(s) */ +}; + + +#define O(a) (a*RATE_STEPS) + +/*note that there is no O(17) in this table - it's directly in the code */ +static const UINT8 eg_rate_select[32+64+32]={ /* Envelope Generator rates (32 + 64 rates + 32 RKS) */ +/* 32 dummy (infinite time) rates */ +O(18),O(18),O(18),O(18),O(18),O(18),O(18),O(18), +O(18),O(18),O(18),O(18),O(18),O(18),O(18),O(18), +O(18),O(18),O(18),O(18),O(18),O(18),O(18),O(18), +O(18),O(18),O(18),O(18),O(18),O(18),O(18),O(18), + +/* rates 00-11 */ +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), + +/* rate 12 */ +O( 4),O( 5),O( 6),O( 7), + +/* rate 13 */ +O( 8),O( 9),O(10),O(11), + +/* rate 14 */ +O(12),O(13),O(14),O(15), + +/* rate 15 */ +O(16),O(16),O(16),O(16), + +/* 32 dummy rates (same as 15 3) */ +O(16),O(16),O(16),O(16),O(16),O(16),O(16),O(16), +O(16),O(16),O(16),O(16),O(16),O(16),O(16),O(16), +O(16),O(16),O(16),O(16),O(16),O(16),O(16),O(16), +O(16),O(16),O(16),O(16),O(16),O(16),O(16),O(16) + +}; +#undef O + +/*rate 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15*/ +/*shift 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0, 0, 0, 0 */ +/*mask 2047, 1023, 511, 255, 127, 63, 31, 15, 7, 3, 1, 0, 0, 0, 0, 0 */ + +#define O(a) (a*1) +static const UINT8 eg_rate_shift[32+64+32]={ /* Envelope Generator counter shifts (32 + 64 rates + 32 RKS) */ +/* 32 infinite time rates */ +O(0),O(0),O(0),O(0),O(0),O(0),O(0),O(0), +O(0),O(0),O(0),O(0),O(0),O(0),O(0),O(0), +O(0),O(0),O(0),O(0),O(0),O(0),O(0),O(0), +O(0),O(0),O(0),O(0),O(0),O(0),O(0),O(0), + + +/* rates 00-11 */ +O(11),O(11),O(11),O(11), +O(10),O(10),O(10),O(10), +O( 9),O( 9),O( 9),O( 9), +O( 8),O( 8),O( 8),O( 8), +O( 7),O( 7),O( 7),O( 7), +O( 6),O( 6),O( 6),O( 6), +O( 5),O( 5),O( 5),O( 5), +O( 4),O( 4),O( 4),O( 4), +O( 3),O( 3),O( 3),O( 3), +O( 2),O( 2),O( 2),O( 2), +O( 1),O( 1),O( 1),O( 1), +O( 0),O( 0),O( 0),O( 0), + +/* rate 12 */ +O( 0),O( 0),O( 0),O( 0), + +/* rate 13 */ +O( 0),O( 0),O( 0),O( 0), + +/* rate 14 */ +O( 0),O( 0),O( 0),O( 0), + +/* rate 15 */ +O( 0),O( 0),O( 0),O( 0), + +/* 32 dummy rates (same as 15 3) */ +O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0), +O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0), +O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0), +O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0) + +}; +#undef O + +/* DT2 defines offset in cents from base note +* +* This table defines offset in frequency-deltas table. +* User's Manual page 22 +* +* Values below were calculated using formula: value = orig.val / 1.5625 +* +* DT2=0 DT2=1 DT2=2 DT2=3 +* 0 600 781 950 +*/ +static const UINT32 dt2_tab[4] = { 0, 384, 500, 608 }; + +/* DT1 defines offset in Hertz from base note +* This table is converted while initialization... +* Detune table shown in YM2151 User's Manual is wrong (verified on the real chip) +*/ + +static const UINT8 dt1_tab[4*32] = { /* 4*32 DT1 values */ +/* DT1=0 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + +/* DT1=1 */ + 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, + 2, 3, 3, 3, 4, 4, 4, 5, 5, 6, 6, 7, 8, 8, 8, 8, + +/* DT1=2 */ + 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, + 5, 6, 6, 7, 8, 8, 9,10,11,12,13,14,16,16,16,16, + +/* DT1=3 */ + 2, 2, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 6, 6, 7, + 8, 8, 9,10,11,12,13,14,16,17,19,20,22,22,22,22 +}; + +static const UINT16 phaseinc_rom[768]={ +1299,1300,1301,1302,1303,1304,1305,1306,1308,1309,1310,1311,1313,1314,1315,1316, +1318,1319,1320,1321,1322,1323,1324,1325,1327,1328,1329,1330,1332,1333,1334,1335, +1337,1338,1339,1340,1341,1342,1343,1344,1346,1347,1348,1349,1351,1352,1353,1354, +1356,1357,1358,1359,1361,1362,1363,1364,1366,1367,1368,1369,1371,1372,1373,1374, +1376,1377,1378,1379,1381,1382,1383,1384,1386,1387,1388,1389,1391,1392,1393,1394, +1396,1397,1398,1399,1401,1402,1403,1404,1406,1407,1408,1409,1411,1412,1413,1414, +1416,1417,1418,1419,1421,1422,1423,1424,1426,1427,1429,1430,1431,1432,1434,1435, +1437,1438,1439,1440,1442,1443,1444,1445,1447,1448,1449,1450,1452,1453,1454,1455, +1458,1459,1460,1461,1463,1464,1465,1466,1468,1469,1471,1472,1473,1474,1476,1477, +1479,1480,1481,1482,1484,1485,1486,1487,1489,1490,1492,1493,1494,1495,1497,1498, +1501,1502,1503,1504,1506,1507,1509,1510,1512,1513,1514,1515,1517,1518,1520,1521, +1523,1524,1525,1526,1528,1529,1531,1532,1534,1535,1536,1537,1539,1540,1542,1543, +1545,1546,1547,1548,1550,1551,1553,1554,1556,1557,1558,1559,1561,1562,1564,1565, +1567,1568,1569,1570,1572,1573,1575,1576,1578,1579,1580,1581,1583,1584,1586,1587, +1590,1591,1592,1593,1595,1596,1598,1599,1601,1602,1604,1605,1607,1608,1609,1610, +1613,1614,1615,1616,1618,1619,1621,1622,1624,1625,1627,1628,1630,1631,1632,1633, +1637,1638,1639,1640,1642,1643,1645,1646,1648,1649,1651,1652,1654,1655,1656,1657, +1660,1661,1663,1664,1666,1667,1669,1670,1672,1673,1675,1676,1678,1679,1681,1682, +1685,1686,1688,1689,1691,1692,1694,1695,1697,1698,1700,1701,1703,1704,1706,1707, +1709,1710,1712,1713,1715,1716,1718,1719,1721,1722,1724,1725,1727,1728,1730,1731, +1734,1735,1737,1738,1740,1741,1743,1744,1746,1748,1749,1751,1752,1754,1755,1757, +1759,1760,1762,1763,1765,1766,1768,1769,1771,1773,1774,1776,1777,1779,1780,1782, +1785,1786,1788,1789,1791,1793,1794,1796,1798,1799,1801,1802,1804,1806,1807,1809, +1811,1812,1814,1815,1817,1819,1820,1822,1824,1825,1827,1828,1830,1832,1833,1835, +1837,1838,1840,1841,1843,1845,1846,1848,1850,1851,1853,1854,1856,1858,1859,1861, +1864,1865,1867,1868,1870,1872,1873,1875,1877,1879,1880,1882,1884,1885,1887,1888, +1891,1892,1894,1895,1897,1899,1900,1902,1904,1906,1907,1909,1911,1912,1914,1915, +1918,1919,1921,1923,1925,1926,1928,1930,1932,1933,1935,1937,1939,1940,1942,1944, +1946,1947,1949,1951,1953,1954,1956,1958,1960,1961,1963,1965,1967,1968,1970,1972, +1975,1976,1978,1980,1982,1983,1985,1987,1989,1990,1992,1994,1996,1997,1999,2001, +2003,2004,2006,2008,2010,2011,2013,2015,2017,2019,2021,2022,2024,2026,2028,2029, +2032,2033,2035,2037,2039,2041,2043,2044,2047,2048,2050,2052,2054,2056,2058,2059, +2062,2063,2065,2067,2069,2071,2073,2074,2077,2078,2080,2082,2084,2086,2088,2089, +2092,2093,2095,2097,2099,2101,2103,2104,2107,2108,2110,2112,2114,2116,2118,2119, +2122,2123,2125,2127,2129,2131,2133,2134,2137,2139,2141,2142,2145,2146,2148,2150, +2153,2154,2156,2158,2160,2162,2164,2165,2168,2170,2172,2173,2176,2177,2179,2181, +2185,2186,2188,2190,2192,2194,2196,2197,2200,2202,2204,2205,2208,2209,2211,2213, +2216,2218,2220,2222,2223,2226,2227,2230,2232,2234,2236,2238,2239,2242,2243,2246, +2249,2251,2253,2255,2256,2259,2260,2263,2265,2267,2269,2271,2272,2275,2276,2279, +2281,2283,2285,2287,2288,2291,2292,2295,2297,2299,2301,2303,2304,2307,2308,2311, +2315,2317,2319,2321,2322,2325,2326,2329,2331,2333,2335,2337,2338,2341,2342,2345, +2348,2350,2352,2354,2355,2358,2359,2362,2364,2366,2368,2370,2371,2374,2375,2378, +2382,2384,2386,2388,2389,2392,2393,2396,2398,2400,2402,2404,2407,2410,2411,2414, +2417,2419,2421,2423,2424,2427,2428,2431,2433,2435,2437,2439,2442,2445,2446,2449, +2452,2454,2456,2458,2459,2462,2463,2466,2468,2470,2472,2474,2477,2480,2481,2484, +2488,2490,2492,2494,2495,2498,2499,2502,2504,2506,2508,2510,2513,2516,2517,2520, +2524,2526,2528,2530,2531,2534,2535,2538,2540,2542,2544,2546,2549,2552,2553,2556, +2561,2563,2565,2567,2568,2571,2572,2575,2577,2579,2581,2583,2586,2589,2590,2593 +}; + + +/* + Noise LFO waveform. + + Here are just 256 samples out of much longer data. + + It does NOT repeat every 256 samples on real chip and I wasnt able to find + the point where it repeats (even in strings as long as 131072 samples). + + I only put it here because its better than nothing and perhaps + someone might be able to figure out the real algorithm. + + + Note that (due to the way the LFO output is calculated) it is quite + possible that two values: 0x80 and 0x00 might be wrong in this table. + To be exact: + some 0x80 could be 0x81 as well as some 0x00 could be 0x01. +*/ + +static const UINT8 lfo_noise_waveform[256] = { +0xFF,0xEE,0xD3,0x80,0x58,0xDA,0x7F,0x94,0x9E,0xE3,0xFA,0x00,0x4D,0xFA,0xFF,0x6A, +0x7A,0xDE,0x49,0xF6,0x00,0x33,0xBB,0x63,0x91,0x60,0x51,0xFF,0x00,0xD8,0x7F,0xDE, +0xDC,0x73,0x21,0x85,0xB2,0x9C,0x5D,0x24,0xCD,0x91,0x9E,0x76,0x7F,0x20,0xFB,0xF3, +0x00,0xA6,0x3E,0x42,0x27,0x69,0xAE,0x33,0x45,0x44,0x11,0x41,0x72,0x73,0xDF,0xA2, + +0x32,0xBD,0x7E,0xA8,0x13,0xEB,0xD3,0x15,0xDD,0xFB,0xC9,0x9D,0x61,0x2F,0xBE,0x9D, +0x23,0x65,0x51,0x6A,0x84,0xF9,0xC9,0xD7,0x23,0xBF,0x65,0x19,0xDC,0x03,0xF3,0x24, +0x33,0xB6,0x1E,0x57,0x5C,0xAC,0x25,0x89,0x4D,0xC5,0x9C,0x99,0x15,0x07,0xCF,0xBA, +0xC5,0x9B,0x15,0x4D,0x8D,0x2A,0x1E,0x1F,0xEA,0x2B,0x2F,0x64,0xA9,0x50,0x3D,0xAB, + +0x50,0x77,0xE9,0xC0,0xAC,0x6D,0x3F,0xCA,0xCF,0x71,0x7D,0x80,0xA6,0xFD,0xFF,0xB5, +0xBD,0x6F,0x24,0x7B,0x00,0x99,0x5D,0xB1,0x48,0xB0,0x28,0x7F,0x80,0xEC,0xBF,0x6F, +0x6E,0x39,0x90,0x42,0xD9,0x4E,0x2E,0x12,0x66,0xC8,0xCF,0x3B,0x3F,0x10,0x7D,0x79, +0x00,0xD3,0x1F,0x21,0x93,0x34,0xD7,0x19,0x22,0xA2,0x08,0x20,0xB9,0xB9,0xEF,0x51, + +0x99,0xDE,0xBF,0xD4,0x09,0x75,0xE9,0x8A,0xEE,0xFD,0xE4,0x4E,0x30,0x17,0xDF,0xCE, +0x11,0xB2,0x28,0x35,0xC2,0x7C,0x64,0xEB,0x91,0x5F,0x32,0x0C,0x6E,0x00,0xF9,0x92, +0x19,0xDB,0x8F,0xAB,0xAE,0xD6,0x12,0xC4,0x26,0x62,0xCE,0xCC,0x0A,0x03,0xE7,0xDD, +0xE2,0x4D,0x8A,0xA6,0x46,0x95,0x0F,0x8F,0xF5,0x15,0x97,0x32,0xD4,0x28,0x1E,0x55 +}; + + + + +/* save output as raw 16-bit sample */ +/* #define SAVE_SAMPLE */ +/* #define SAVE_SEPARATE_CHANNELS */ +#if defined SAVE_SAMPLE || defined SAVE_SEPARATE_CHANNELS +static FILE *sample[9]; +#endif + + + + +static void init_tables(void) +{ + signed int i,x,n; + double o,m; + + for (x=0; x>= 4; /* 12 bits here */ + if (n&1) /* round to closest */ + n = (n>>1)+1; + else + n = n>>1; + /* 11 bits here (rounded) */ + n <<= 2; /* 13 bits here (as in real chip) */ + tl_tab[ x*2 + 0 ] = n; + tl_tab[ x*2 + 1 ] = -tl_tab[ x*2 + 0 ]; + + for (i=1; i<13; i++) + { + tl_tab[ x*2+0 + i*2*TL_RES_LEN ] = tl_tab[ x*2+0 ]>>i; + tl_tab[ x*2+1 + i*2*TL_RES_LEN ] = -tl_tab[ x*2+0 + i*2*TL_RES_LEN ]; + } + #if 0 + logerror("tl %04i", x*2); + for (i=0; i<13; i++) + logerror(", [%02i] %4i", i*2, tl_tab[ x*2 /*+1*/ + i*2*TL_RES_LEN ]); + logerror("\n"); + #endif + } + /*logerror("TL_TAB_LEN = %i (%i bytes)\n",TL_TAB_LEN, (int)sizeof(tl_tab));*/ + /*logerror("ENV_QUIET= %i\n",ENV_QUIET );*/ + + + for (i=0; i0.0) + o = 8*log(1.0/m)/log(2.0); /* convert to 'decibels' */ + else + o = 8*log(-1.0/m)/log(2.0); /* convert to 'decibels' */ + + o = o / (ENV_STEP/4); + + n = (int)(2.0*o); + if (n&1) /* round to closest */ + n = (n>>1)+1; + else + n = n>>1; + + sin_tab[ i ] = n*2 + (m>=0.0? 0: 1 ); + /*logerror("sin [0x%4x]= %4i (tl_tab value=%8x)\n", i, sin_tab[i],tl_tab[sin_tab[i]]);*/ + } + + + /* calculate d1l_tab table */ + for (i=0; i<16; i++) + { + m = (i!=15 ? i : i+16) * (4.0/ENV_STEP); /* every 3 'dB' except for all bits = 1 = 45+48 'dB' */ + d1l_tab[i] = m; + /*logerror("d1l_tab[%02x]=%08x\n",i,d1l_tab[i] );*/ + } + +#ifdef SAVE_SAMPLE + sample[8]=fopen("sampsum.pcm","wb"); +#endif +#ifdef SAVE_SEPARATE_CHANNELS + sample[0]=fopen("samp0.pcm","wb"); + sample[1]=fopen("samp1.pcm","wb"); + sample[2]=fopen("samp2.pcm","wb"); + sample[3]=fopen("samp3.pcm","wb"); + sample[4]=fopen("samp4.pcm","wb"); + sample[5]=fopen("samp5.pcm","wb"); + sample[6]=fopen("samp6.pcm","wb"); + sample[7]=fopen("samp7.pcm","wb"); +#endif +} + + +static void init_chip_tables(YM2151 *chip) +{ + int i,j; + double mult,phaseinc,Hz; + double scaler; + attotime pom; + + scaler = ( (double)chip->clock / 64.0 ) / ( (double)chip->sampfreq ); + /*logerror("scaler = %20.15f\n", scaler);*/ + + + /* this loop calculates Hertz values for notes from c-0 to b-7 */ + /* including 64 'cents' (100/64 that is 1.5625 of real cent) per note */ + /* i*100/64/1200 is equal to i/768 */ + + /* real chip works with 10 bits fixed point values (10.10) */ + mult = (1<<(FREQ_SH-10)); /* -10 because phaseinc_rom table values are already in 10.10 format */ + + for (i=0; i<768; i++) + { + /* 3.4375 Hz is note A; C# is 4 semitones higher */ + Hz = 1000; +#if 0 +/* Hz is close, but not perfect */ + //Hz = scaler * 3.4375 * pow (2, (i + 4 * 64 ) / 768.0 ); + /* calculate phase increment */ + phaseinc = (Hz*SIN_LEN) / (double)chip->sampfreq; +#endif + + phaseinc = phaseinc_rom[i]; /* real chip phase increment */ + phaseinc *= scaler; /* adjust */ + + + /* octave 2 - reference octave */ + chip->freq[ 768+2*768+i ] = ((int)(phaseinc*mult)) & 0xffffffc0; /* adjust to X.10 fixed point */ + /* octave 0 and octave 1 */ + for (j=0; j<2; j++) + { + chip->freq[768 + j*768 + i] = (chip->freq[ 768+2*768+i ] >> (2-j) ) & 0xffffffc0; /* adjust to X.10 fixed point */ + } + /* octave 3 to 7 */ + for (j=3; j<8; j++) + { + chip->freq[768 + j*768 + i] = chip->freq[ 768+2*768+i ] << (j-2); + } + + #if 0 + pom = (double)chip->freq[ 768+2*768+i ] / ((double)(1<sampfreq / (double)SIN_LEN; + logerror("1freq[%4i][%08x]= real %20.15f Hz emul %20.15f Hz\n", i, chip->freq[ 768+2*768+i ], Hz, pom); + #endif + } + + /* octave -1 (all equal to: oct 0, _KC_00_, _KF_00_) */ + for (i=0; i<768; i++) + { + chip->freq[ 0*768 + i ] = chip->freq[1*768+0]; + } + + /* octave 8 and 9 (all equal to: oct 7, _KC_14_, _KF_63_) */ + for (j=8; j<10; j++) + { + for (i=0; i<768; i++) + { + chip->freq[768+ j*768 + i ] = chip->freq[768 + 8*768 -1]; + } + } + +#if 0 + for (i=0; i<11*768; i++) + { + pom = (double)chip->freq[i] / ((double)(1<sampfreq / (double)SIN_LEN; + logerror("freq[%4i][%08x]= emul %20.15f Hz\n", i, chip->freq[i], pom); + } +#endif + + mult = (1<clock/64.0) ) / (double)(1<<20); + + /*calculate phase increment*/ + phaseinc = (Hz*SIN_LEN) / (double)chip->sampfreq; + + /*positive and negative values*/ + chip->dt1_freq[ (j+0)*32 + i ] = phaseinc * mult; + chip->dt1_freq[ (j+4)*32 + i ] = -chip->dt1_freq[ (j+0)*32 + i ]; + +#if 0 + { + int x = j*32 + i; + pom = (double)chip->dt1_freq[x] / mult; + pom = pom * (double)chip->sampfreq / (double)SIN_LEN; + logerror("DT1(%03i)[%02i %02i][%08x]= real %19.15f Hz emul %19.15f Hz\n", + x, j, i, chip->dt1_freq[x], Hz, pom); + } +#endif + } + } + + + /* calculate timers' deltas */ + /* User's Manual pages 15,16 */ + mult = (1<clock) * (64 * (1024 - i)); + #ifdef USE_MAME_TIMERS + chip->timer_A_time[i] = pom; + #else + chip->tim_A_tab[i] = pom.as_double() * (double)chip->sampfreq * mult; /* number of samples that timer period takes (fixed point) */ + #endif + } + for (i=0; i<256; i++) + { + /* ASG 980324: changed to compute both tim_B_tab and timer_B_time */ + pom= attotime::from_hz(chip->clock) * (1024 * (256 - i)); + #ifdef USE_MAME_TIMERS + chip->timer_B_time[i] = pom; + #else + chip->tim_B_tab[i] = pom.as_double() * (double)chip->sampfreq * mult; /* number of samples that timer period takes (fixed point) */ + #endif + } + + /* calculate noise periods table */ + scaler = ( (double)chip->clock / 64.0 ) / ( (double)chip->sampfreq ); + for (i=0; i<32; i++) + { + j = (i!=31 ? i : 30); /* rate 30 and 31 are the same */ + j = 32-j; + j = (65536.0 / (double)(j*32.0)); /* number of samples per one shift of the shift register */ + /*chip->noise_tab[i] = j * 64;*/ /* number of chip clock cycles per one shift */ + chip->noise_tab[i] = j * 64 * scaler; + /*logerror("noise_tab[%02x]=%08x\n", i, chip->noise_tab[i]);*/ + } +} + +#define KEY_ON(op, key_set){ \ + if (!(op)->key) \ + { \ + (op)->phase = 0; /* clear phase */ \ + (op)->state = EG_ATT; /* KEY ON = attack */ \ + (op)->volume += (~(op)->volume * \ + (eg_inc[(op)->eg_sel_ar + ((PSG->eg_cnt>>(op)->eg_sh_ar)&7)]) \ + ) >>4; \ + if ((op)->volume <= MIN_ATT_INDEX) \ + { \ + (op)->volume = MIN_ATT_INDEX; \ + (op)->state = EG_DEC; \ + } \ + } \ + (op)->key |= key_set; \ +} + +#define KEY_OFF(op, key_clr){ \ + if ((op)->key) \ + { \ + (op)->key &= key_clr; \ + if (!(op)->key) \ + { \ + if ((op)->state>EG_REL) \ + (op)->state = EG_REL;/* KEY OFF = release */\ + } \ + } \ +} + +INLINE void envelope_KONKOFF(YM2151 *PSG, YM2151Operator * op, int v) +{ + if (v&0x08) /* M1 */ + KEY_ON (op+0, 1) + else + KEY_OFF(op+0,~1) + + if (v&0x20) /* M2 */ + KEY_ON (op+1, 1) + else + KEY_OFF(op+1,~1) + + if (v&0x10) /* C1 */ + KEY_ON (op+2, 1) + else + KEY_OFF(op+2,~1) + + if (v&0x40) /* C2 */ + KEY_ON (op+3, 1) + else + KEY_OFF(op+3,~1) +} + + +#ifdef USE_MAME_TIMERS + +static TIMER_CALLBACK( irqAon_callback ) +{ + YM2151 *chip = (YM2151 *)ptr; + int oldstate = chip->irqlinestate; + + chip->irqlinestate |= 1; + + if (oldstate == 0 && chip->irqhandler) (*chip->irqhandler)(chip->device, 1); +} + +static TIMER_CALLBACK( irqBon_callback ) +{ + YM2151 *chip = (YM2151 *)ptr; + int oldstate = chip->irqlinestate; + + chip->irqlinestate |= 2; + + if (oldstate == 0 && chip->irqhandler) (*chip->irqhandler)(chip->device, 1); +} + +static TIMER_CALLBACK( irqAoff_callback ) +{ + YM2151 *chip = (YM2151 *)ptr; + int oldstate = chip->irqlinestate; + + chip->irqlinestate &= ~1; + + if (oldstate == 1 && chip->irqhandler) (*chip->irqhandler)(chip->device, 0); +} + +static TIMER_CALLBACK( irqBoff_callback ) +{ + YM2151 *chip = (YM2151 *)ptr; + int oldstate = chip->irqlinestate; + + chip->irqlinestate &= ~2; + + if (oldstate == 2 && chip->irqhandler) (*chip->irqhandler)(chip->device, 0); +} + +static TIMER_CALLBACK( timer_callback_a ) +{ + YM2151 *chip = (YM2151 *)ptr; + chip->timer_A->adjust(chip->timer_A_time[ chip->timer_A_index ]); + chip->timer_A_index_old = chip->timer_A_index; + if (chip->irq_enable & 0x04) + { + chip->status |= 1; + machine.scheduler().timer_set(attotime::zero, FUNC(irqAon_callback), 0, chip); + } + if (chip->irq_enable & 0x80) + chip->csm_req = 2; /* request KEY ON / KEY OFF sequence */ +} +static TIMER_CALLBACK( timer_callback_b ) +{ + YM2151 *chip = (YM2151 *)ptr; + chip->timer_B->adjust(chip->timer_B_time[ chip->timer_B_index ]); + chip->timer_B_index_old = chip->timer_B_index; + if (chip->irq_enable & 0x08) + { + chip->status |= 2; + machine.scheduler().timer_set(attotime::zero, FUNC(irqBon_callback), 0, chip); + } +} +#if 0 +static TIMER_CALLBACK( timer_callback_chip_busy ) +{ + YM2151 *chip = (YM2151 *)ptr; + chip->status &= 0x7f; /* reset busy flag */ +} +#endif +#endif + + + + + + +INLINE void set_connect(YM2151 *PSG, YM2151Operator *om1, int cha, int v) +{ + YM2151Operator *om2 = om1+1; + YM2151Operator *oc1 = om1+2; + + /* set connect algorithm */ + + /* MEM is simply one sample delay */ + + switch( v&7 ) + { + case 0: + /* M1---C1---MEM---M2---C2---OUT */ + om1->connect = &PSG->c1; + oc1->connect = &PSG->mem; + om2->connect = &PSG->c2; + om1->mem_connect = &PSG->m2; + break; + + case 1: + /* M1------+-MEM---M2---C2---OUT */ + /* C1-+ */ + om1->connect = &PSG->mem; + oc1->connect = &PSG->mem; + om2->connect = &PSG->c2; + om1->mem_connect = &PSG->m2; + break; + + case 2: + /* M1-----------------+-C2---OUT */ + /* C1---MEM---M2-+ */ + om1->connect = &PSG->c2; + oc1->connect = &PSG->mem; + om2->connect = &PSG->c2; + om1->mem_connect = &PSG->m2; + break; + + case 3: + /* M1---C1---MEM------+-C2---OUT */ + /* M2-+ */ + om1->connect = &PSG->c1; + oc1->connect = &PSG->mem; + om2->connect = &PSG->c2; + om1->mem_connect = &PSG->c2; + break; + + case 4: + /* M1---C1-+-OUT */ + /* M2---C2-+ */ + /* MEM: not used */ + om1->connect = &PSG->c1; + oc1->connect = &PSG->chanout[cha]; + om2->connect = &PSG->c2; + om1->mem_connect = &PSG->mem; /* store it anywhere where it will not be used */ + break; + + case 5: + /* +----C1----+ */ + /* M1-+-MEM---M2-+-OUT */ + /* +----C2----+ */ + om1->connect = 0; /* special mark */ + oc1->connect = &PSG->chanout[cha]; + om2->connect = &PSG->chanout[cha]; + om1->mem_connect = &PSG->m2; + break; + + case 6: + /* M1---C1-+ */ + /* M2-+-OUT */ + /* C2-+ */ + /* MEM: not used */ + om1->connect = &PSG->c1; + oc1->connect = &PSG->chanout[cha]; + om2->connect = &PSG->chanout[cha]; + om1->mem_connect = &PSG->mem; /* store it anywhere where it will not be used */ + break; + + case 7: + /* M1-+ */ + /* C1-+-OUT */ + /* M2-+ */ + /* C2-+ */ + /* MEM: not used*/ + om1->connect = &PSG->chanout[cha]; + oc1->connect = &PSG->chanout[cha]; + om2->connect = &PSG->chanout[cha]; + om1->mem_connect = &PSG->mem; /* store it anywhere where it will not be used */ + break; + } +} + + +INLINE void refresh_EG(YM2151Operator * op) +{ + UINT32 kc; + UINT32 v; + + kc = op->kc; + + /* v = 32 + 2*RATE + RKS = max 126 */ + + v = kc >> op->ks; + if ((op->ar+v) < 32+62) + { + op->eg_sh_ar = eg_rate_shift [op->ar + v ]; + op->eg_sel_ar = eg_rate_select[op->ar + v ]; + } + else + { + op->eg_sh_ar = 0; + op->eg_sel_ar = 17*RATE_STEPS; + } + op->eg_sh_d1r = eg_rate_shift [op->d1r + v]; + op->eg_sel_d1r= eg_rate_select[op->d1r + v]; + op->eg_sh_d2r = eg_rate_shift [op->d2r + v]; + op->eg_sel_d2r= eg_rate_select[op->d2r + v]; + op->eg_sh_rr = eg_rate_shift [op->rr + v]; + op->eg_sel_rr = eg_rate_select[op->rr + v]; + + + op+=1; + + v = kc >> op->ks; + if ((op->ar+v) < 32+62) + { + op->eg_sh_ar = eg_rate_shift [op->ar + v ]; + op->eg_sel_ar = eg_rate_select[op->ar + v ]; + } + else + { + op->eg_sh_ar = 0; + op->eg_sel_ar = 17*RATE_STEPS; + } + op->eg_sh_d1r = eg_rate_shift [op->d1r + v]; + op->eg_sel_d1r= eg_rate_select[op->d1r + v]; + op->eg_sh_d2r = eg_rate_shift [op->d2r + v]; + op->eg_sel_d2r= eg_rate_select[op->d2r + v]; + op->eg_sh_rr = eg_rate_shift [op->rr + v]; + op->eg_sel_rr = eg_rate_select[op->rr + v]; + + op+=1; + + v = kc >> op->ks; + if ((op->ar+v) < 32+62) + { + op->eg_sh_ar = eg_rate_shift [op->ar + v ]; + op->eg_sel_ar = eg_rate_select[op->ar + v ]; + } + else + { + op->eg_sh_ar = 0; + op->eg_sel_ar = 17*RATE_STEPS; + } + op->eg_sh_d1r = eg_rate_shift [op->d1r + v]; + op->eg_sel_d1r= eg_rate_select[op->d1r + v]; + op->eg_sh_d2r = eg_rate_shift [op->d2r + v]; + op->eg_sel_d2r= eg_rate_select[op->d2r + v]; + op->eg_sh_rr = eg_rate_shift [op->rr + v]; + op->eg_sel_rr = eg_rate_select[op->rr + v]; + + op+=1; + + v = kc >> op->ks; + if ((op->ar+v) < 32+62) + { + op->eg_sh_ar = eg_rate_shift [op->ar + v ]; + op->eg_sel_ar = eg_rate_select[op->ar + v ]; + } + else + { + op->eg_sh_ar = 0; + op->eg_sel_ar = 17*RATE_STEPS; + } + op->eg_sh_d1r = eg_rate_shift [op->d1r + v]; + op->eg_sel_d1r= eg_rate_select[op->d1r + v]; + op->eg_sh_d2r = eg_rate_shift [op->d2r + v]; + op->eg_sel_d2r= eg_rate_select[op->d2r + v]; + op->eg_sh_rr = eg_rate_shift [op->rr + v]; + op->eg_sel_rr = eg_rate_select[op->rr + v]; +} + + +/* write a register on YM2151 chip number 'n' */ +void ym2151_write_reg(void *_chip, int r, int v) +{ + YM2151 *chip = (YM2151 *)_chip; + YM2151Operator *op = &chip->oper[ (r&0x07)*4+((r&0x18)>>3) ]; + + /* adjust bus to 8 bits */ + r &= 0xff; + v &= 0xff; + +#if 0 + /* There is no info on what YM2151 really does when busy flag is set */ + if ( chip->status & 0x80 ) return; + timer_set ( attotime::from_hz(chip->clock) * 64, chip, 0, timer_callback_chip_busy); + chip->status |= 0x80; /* set busy flag for 64 chip clock cycles */ +#endif + + if (LOG_CYM_FILE && (cymfile) && (r!=0) ) + { + fputc( (unsigned char)r, cymfile ); + fputc( (unsigned char)v, cymfile ); + } + + + switch(r & 0xe0) + { + case 0x00: + switch(r){ + case 0x01: /* LFO reset(bit 1), Test Register (other bits) */ + chip->test = v; + if (v&2) chip->lfo_phase = 0; + break; + + case 0x08: + envelope_KONKOFF(chip, &chip->oper[ (v&7)*4 ], v ); + break; + + case 0x0f: /* noise mode enable, noise period */ + chip->noise = v; + chip->noise_f = chip->noise_tab[ v & 0x1f ]; + break; + + case 0x10: /* timer A hi */ + chip->timer_A_index = (chip->timer_A_index & 0x003) | (v<<2); + break; + + case 0x11: /* timer A low */ + chip->timer_A_index = (chip->timer_A_index & 0x3fc) | (v & 3); + break; + + case 0x12: /* timer B */ + chip->timer_B_index = v; + break; + + case 0x14: /* CSM, irq flag reset, irq enable, timer start/stop */ + + chip->irq_enable = v; /* bit 3-timer B, bit 2-timer A, bit 7 - CSM */ + + if (v&0x10) /* reset timer A irq flag */ + { +#ifdef USE_MAME_TIMERS + chip->status &= ~1; + chip->device->machine().scheduler().timer_set(attotime::zero, FUNC(irqAoff_callback), 0, chip); +#else + int oldstate = chip->status & 3; + chip->status &= ~1; + if ((oldstate==1) && (chip->irqhandler)) (*chip->irqhandler)(chip->device, 0); +#endif + } + + if (v&0x20) /* reset timer B irq flag */ + { +#ifdef USE_MAME_TIMERS + chip->status &= ~2; + chip->device->machine().scheduler().timer_set(attotime::zero, FUNC(irqBoff_callback), 0, chip); +#else + int oldstate = chip->status & 3; + chip->status &= ~2; + if ((oldstate==2) && (chip->irqhandler)) (*chip->irqhandler)(chip->device, 0); +#endif + } + + if (v&0x02) + { /* load and start timer B */ + #ifdef USE_MAME_TIMERS + /* ASG 980324: added a real timer */ + /* start timer _only_ if it wasn't already started (it will reload time value next round) */ + if (!chip->timer_B->enable(true)) + { + chip->timer_B->adjust(chip->timer_B_time[ chip->timer_B_index ]); + chip->timer_B_index_old = chip->timer_B_index; + } + #else + if (!chip->tim_B) + { + chip->tim_B = 1; + chip->tim_B_val = chip->tim_B_tab[ chip->timer_B_index ]; + } + #endif + } + else + { /* stop timer B */ + #ifdef USE_MAME_TIMERS + /* ASG 980324: added a real timer */ + chip->timer_B->enable(false); + #else + chip->tim_B = 0; + #endif + } + + if (v&0x01) + { /* load and start timer A */ + #ifdef USE_MAME_TIMERS + /* ASG 980324: added a real timer */ + /* start timer _only_ if it wasn't already started (it will reload time value next round) */ + if (!chip->timer_A->enable(true)) + { + chip->timer_A->adjust(chip->timer_A_time[ chip->timer_A_index ]); + chip->timer_A_index_old = chip->timer_A_index; + } + #else + if (!chip->tim_A) + { + chip->tim_A = 1; + chip->tim_A_val = chip->tim_A_tab[ chip->timer_A_index ]; + } + #endif + } + else + { /* stop timer A */ + #ifdef USE_MAME_TIMERS + /* ASG 980324: added a real timer */ + chip->timer_A->enable(false); + #else + chip->tim_A = 0; + #endif + } + break; + + case 0x18: /* LFO frequency */ + { + chip->lfo_overflow = ( 1 << ((15-(v>>4))+3) ) * (1<lfo_counter_add = 0x10 + (v & 0x0f); + } + break; + + case 0x19: /* PMD (bit 7==1) or AMD (bit 7==0) */ + if (v&0x80) + chip->pmd = v & 0x7f; + else + chip->amd = v & 0x7f; + break; + + case 0x1b: /* CT2, CT1, LFO waveform */ + chip->ct = v >> 6; + chip->lfo_wsel = v & 3; + if (chip->porthandler) (*chip->porthandler)(chip->device, 0 , chip->ct ); + break; + + default: + logerror("YM2151 Write %02x to undocumented register #%02x\n",v,r); + break; + } + break; + + case 0x20: + op = &chip->oper[ (r&7) * 4 ]; + switch(r & 0x18) + { + case 0x00: /* RL enable, Feedback, Connection */ + op->fb_shift = ((v>>3)&7) ? ((v>>3)&7)+6:0; + chip->pan[ (r&7)*2 ] = (v & 0x40) ? ~0 : 0; + chip->pan[ (r&7)*2 +1 ] = (v & 0x80) ? ~0 : 0; + chip->connect[r&7] = v&7; + set_connect(chip, op, r&7, v&7); + break; + + case 0x08: /* Key Code */ + v &= 0x7f; + if (v != op->kc) + { + UINT32 kc, kc_channel; + + kc_channel = (v - (v>>2))*64; + kc_channel += 768; + kc_channel |= (op->kc_i & 63); + + (op+0)->kc = v; + (op+0)->kc_i = kc_channel; + (op+1)->kc = v; + (op+1)->kc_i = kc_channel; + (op+2)->kc = v; + (op+2)->kc_i = kc_channel; + (op+3)->kc = v; + (op+3)->kc_i = kc_channel; + + kc = v>>2; + + (op+0)->dt1 = chip->dt1_freq[ (op+0)->dt1_i + kc ]; + (op+0)->freq = ( (chip->freq[ kc_channel + (op+0)->dt2 ] + (op+0)->dt1) * (op+0)->mul ) >> 1; + + (op+1)->dt1 = chip->dt1_freq[ (op+1)->dt1_i + kc ]; + (op+1)->freq = ( (chip->freq[ kc_channel + (op+1)->dt2 ] + (op+1)->dt1) * (op+1)->mul ) >> 1; + + (op+2)->dt1 = chip->dt1_freq[ (op+2)->dt1_i + kc ]; + (op+2)->freq = ( (chip->freq[ kc_channel + (op+2)->dt2 ] + (op+2)->dt1) * (op+2)->mul ) >> 1; + + (op+3)->dt1 = chip->dt1_freq[ (op+3)->dt1_i + kc ]; + (op+3)->freq = ( (chip->freq[ kc_channel + (op+3)->dt2 ] + (op+3)->dt1) * (op+3)->mul ) >> 1; + + refresh_EG( op ); + } + break; + + case 0x10: /* Key Fraction */ + v >>= 2; + if (v != (op->kc_i & 63)) + { + UINT32 kc_channel; + + kc_channel = v; + kc_channel |= (op->kc_i & ~63); + + (op+0)->kc_i = kc_channel; + (op+1)->kc_i = kc_channel; + (op+2)->kc_i = kc_channel; + (op+3)->kc_i = kc_channel; + + (op+0)->freq = ( (chip->freq[ kc_channel + (op+0)->dt2 ] + (op+0)->dt1) * (op+0)->mul ) >> 1; + (op+1)->freq = ( (chip->freq[ kc_channel + (op+1)->dt2 ] + (op+1)->dt1) * (op+1)->mul ) >> 1; + (op+2)->freq = ( (chip->freq[ kc_channel + (op+2)->dt2 ] + (op+2)->dt1) * (op+2)->mul ) >> 1; + (op+3)->freq = ( (chip->freq[ kc_channel + (op+3)->dt2 ] + (op+3)->dt1) * (op+3)->mul ) >> 1; + } + break; + + case 0x18: /* PMS, AMS */ + op->pms = (v>>4) & 7; + op->ams = (v & 3); + break; + } + break; + + case 0x40: /* DT1, MUL */ + { + UINT32 olddt1_i = op->dt1_i; + UINT32 oldmul = op->mul; + + op->dt1_i = (v&0x70)<<1; + op->mul = (v&0x0f) ? (v&0x0f)<<1: 1; + + if (olddt1_i != op->dt1_i) + op->dt1 = chip->dt1_freq[ op->dt1_i + (op->kc>>2) ]; + + if ( (olddt1_i != op->dt1_i) || (oldmul != op->mul) ) + op->freq = ( (chip->freq[ op->kc_i + op->dt2 ] + op->dt1) * op->mul ) >> 1; + } + break; + + case 0x60: /* TL */ + op->tl = (v&0x7f)<<(ENV_BITS-7); /* 7bit TL */ + break; + + case 0x80: /* KS, AR */ + { + UINT32 oldks = op->ks; + UINT32 oldar = op->ar; + + op->ks = 5-(v>>6); + op->ar = (v&0x1f) ? 32 + ((v&0x1f)<<1) : 0; + + if ( (op->ar != oldar) || (op->ks != oldks) ) + { + if ((op->ar + (op->kc>>op->ks)) < 32+62) + { + op->eg_sh_ar = eg_rate_shift [op->ar + (op->kc>>op->ks) ]; + op->eg_sel_ar = eg_rate_select[op->ar + (op->kc>>op->ks) ]; + } + else + { + op->eg_sh_ar = 0; + op->eg_sel_ar = 17*RATE_STEPS; + } + } + + if (op->ks != oldks) + { + op->eg_sh_d1r = eg_rate_shift [op->d1r + (op->kc>>op->ks) ]; + op->eg_sel_d1r= eg_rate_select[op->d1r + (op->kc>>op->ks) ]; + op->eg_sh_d2r = eg_rate_shift [op->d2r + (op->kc>>op->ks) ]; + op->eg_sel_d2r= eg_rate_select[op->d2r + (op->kc>>op->ks) ]; + op->eg_sh_rr = eg_rate_shift [op->rr + (op->kc>>op->ks) ]; + op->eg_sel_rr = eg_rate_select[op->rr + (op->kc>>op->ks) ]; + } + } + break; + + case 0xa0: /* LFO AM enable, D1R */ + op->AMmask = (v&0x80) ? ~0 : 0; + op->d1r = (v&0x1f) ? 32 + ((v&0x1f)<<1) : 0; + op->eg_sh_d1r = eg_rate_shift [op->d1r + (op->kc>>op->ks) ]; + op->eg_sel_d1r= eg_rate_select[op->d1r + (op->kc>>op->ks) ]; + break; + + case 0xc0: /* DT2, D2R */ + { + UINT32 olddt2 = op->dt2; + op->dt2 = dt2_tab[ v>>6 ]; + if (op->dt2 != olddt2) + op->freq = ( (chip->freq[ op->kc_i + op->dt2 ] + op->dt1) * op->mul ) >> 1; + } + op->d2r = (v&0x1f) ? 32 + ((v&0x1f)<<1) : 0; + op->eg_sh_d2r = eg_rate_shift [op->d2r + (op->kc>>op->ks) ]; + op->eg_sel_d2r= eg_rate_select[op->d2r + (op->kc>>op->ks) ]; + break; + + case 0xe0: /* D1L, RR */ + op->d1l = d1l_tab[ v>>4 ]; + op->rr = 34 + ((v&0x0f)<<2); + op->eg_sh_rr = eg_rate_shift [op->rr + (op->kc>>op->ks) ]; + op->eg_sel_rr = eg_rate_select[op->rr + (op->kc>>op->ks) ]; + break; + } +} + + +static TIMER_CALLBACK( cymfile_callback ) +{ + if (cymfile) + fputc( (unsigned char)0, cymfile ); +} + + +int ym2151_read_status( void *_chip ) +{ + YM2151 *chip = (YM2151 *)_chip; + return chip->status; +} + + + +//#ifdef USE_MAME_TIMERS +#if 1 // disabled for now due to crashing with winalloc.c (ERROR_NOT_ENOUGH_MEMORY) +/* +* state save support for MAME +*/ +void ym2151_postload(YM2151 *YM2151_chip) +{ + int j; + + for (j=0; j<8; j++) + set_connect(YM2151_chip, &YM2151_chip->oper[j*4], j, YM2151_chip->connect[j]); +} + +static void ym2151_state_save_register( YM2151 *chip, device_t *device ) +{ + int j; + + /* save all 32 operators of chip #i */ + for (j=0; j<32; j++) + { + YM2151Operator *op; + + op = &chip->oper[(j&7)*4+(j>>3)]; + + device->save_item(NAME(op->phase), j); + device->save_item(NAME(op->freq), j); + device->save_item(NAME(op->dt1), j); + device->save_item(NAME(op->mul), j); + device->save_item(NAME(op->dt1_i), j); + device->save_item(NAME(op->dt2), j); + /* operators connection is saved in chip data block */ + device->save_item(NAME(op->mem_value), j); + + device->save_item(NAME(op->fb_shift), j); + device->save_item(NAME(op->fb_out_curr), j); + device->save_item(NAME(op->fb_out_prev), j); + device->save_item(NAME(op->kc), j); + device->save_item(NAME(op->kc_i), j); + device->save_item(NAME(op->pms), j); + device->save_item(NAME(op->ams), j); + device->save_item(NAME(op->AMmask), j); + + device->save_item(NAME(op->state), j); + device->save_item(NAME(op->eg_sh_ar), j); + device->save_item(NAME(op->eg_sel_ar), j); + device->save_item(NAME(op->tl), j); + device->save_item(NAME(op->volume), j); + device->save_item(NAME(op->eg_sh_d1r), j); + device->save_item(NAME(op->eg_sel_d1r), j); + device->save_item(NAME(op->d1l), j); + device->save_item(NAME(op->eg_sh_d2r), j); + device->save_item(NAME(op->eg_sel_d2r), j); + device->save_item(NAME(op->eg_sh_rr), j); + device->save_item(NAME(op->eg_sel_rr), j); + + device->save_item(NAME(op->key), j); + device->save_item(NAME(op->ks), j); + device->save_item(NAME(op->ar), j); + device->save_item(NAME(op->d1r), j); + device->save_item(NAME(op->d2r), j); + device->save_item(NAME(op->rr), j); + + device->save_item(NAME(op->reserved0), j); + device->save_item(NAME(op->reserved1), j); + } + + device->save_item(NAME(chip->pan)); + + device->save_item(NAME(chip->eg_cnt)); + device->save_item(NAME(chip->eg_timer)); + device->save_item(NAME(chip->eg_timer_add)); + device->save_item(NAME(chip->eg_timer_overflow)); + + device->save_item(NAME(chip->lfo_phase)); + device->save_item(NAME(chip->lfo_timer)); + device->save_item(NAME(chip->lfo_timer_add)); + device->save_item(NAME(chip->lfo_overflow)); + device->save_item(NAME(chip->lfo_counter)); + device->save_item(NAME(chip->lfo_counter_add)); + device->save_item(NAME(chip->lfo_wsel)); + device->save_item(NAME(chip->amd)); + device->save_item(NAME(chip->pmd)); + device->save_item(NAME(chip->lfa)); + device->save_item(NAME(chip->lfp)); + + device->save_item(NAME(chip->test)); + device->save_item(NAME(chip->ct)); + + device->save_item(NAME(chip->noise)); + device->save_item(NAME(chip->noise_rng)); + device->save_item(NAME(chip->noise_p)); + device->save_item(NAME(chip->noise_f)); + + device->save_item(NAME(chip->csm_req)); + device->save_item(NAME(chip->irq_enable)); + device->save_item(NAME(chip->status)); + + device->save_item(NAME(chip->timer_A_index)); + device->save_item(NAME(chip->timer_B_index)); + device->save_item(NAME(chip->timer_A_index_old)); + device->save_item(NAME(chip->timer_B_index_old)); + +#ifdef USE_MAME_TIMERS + device->save_item(NAME(chip->irqlinestate)); +#endif + + device->save_item(NAME(chip->connect)); + + device->machine().save().register_postload(save_prepost_delegate(FUNC(ym2151_postload), chip)); +} +#else +void ym2151_postload(YM2151 *chip) +{ +} + +static void ym2151_state_save_register( YM2151 *chip, device_t *device ) +{ +} +#endif + + +/* +* Initialize YM2151 emulator(s). +* +* 'num' is the number of virtual YM2151's to allocate +* 'clock' is the chip clock in Hz +* 'rate' is sampling rate +*/ +void * ym2151_init(device_t *device, int clock, int rate) +{ + YM2151 *PSG; + + PSG = auto_alloc(device->machine(), YM2151); + + memset(PSG, 0, sizeof(YM2151)); + + ym2151_state_save_register( PSG, device ); + + init_tables(); + + PSG->device = device; + PSG->clock = clock; + /*rate = clock/64;*/ + PSG->sampfreq = rate ? rate : 44100; /* avoid division by 0 in init_chip_tables() */ + PSG->irqhandler = NULL; /* interrupt handler */ + PSG->porthandler = NULL; /* port write handler */ + init_chip_tables( PSG ); + + PSG->lfo_timer_add = (1<sampfreq; + + PSG->eg_timer_add = (1<sampfreq; + PSG->eg_timer_overflow = ( 3 ) * (1<eg_timer_add, PSG->eg_timer_overflow);*/ + +#ifdef USE_MAME_TIMERS +/* this must be done _before_ a call to ym2151_reset_chip() */ + PSG->timer_A = device->machine().scheduler().timer_alloc(FUNC(timer_callback_a), PSG); + PSG->timer_B = device->machine().scheduler().timer_alloc(FUNC(timer_callback_b), PSG); +#else + PSG->tim_A = 0; + PSG->tim_B = 0; +#endif + ym2151_reset_chip(PSG); + /*logerror("YM2151[init] clock=%i sampfreq=%i\n", PSG->clock, PSG->sampfreq);*/ + + if (LOG_CYM_FILE) + { + cymfile = fopen("2151_.cym","wb"); + if (cymfile) + device->machine().scheduler().timer_pulse ( attotime::from_hz(110), FUNC(cymfile_callback)); /*110 Hz pulse timer*/ + else + logerror("Could not create file 2151_.cym\n"); + } + + return PSG; +} + + + +void ym2151_shutdown(void *_chip) +{ + YM2151 *chip = (YM2151 *)_chip; + + auto_free (chip->device->machine(), chip); + + if (cymfile) + fclose (cymfile); + cymfile = NULL; + +#ifdef SAVE_SAMPLE + fclose(sample[8]); +#endif +#ifdef SAVE_SEPARATE_CHANNELS + fclose(sample[0]); + fclose(sample[1]); + fclose(sample[2]); + fclose(sample[3]); + fclose(sample[4]); + fclose(sample[5]); + fclose(sample[6]); + fclose(sample[7]); +#endif +} + + + +/* +* Reset chip number 'n'. +*/ +void ym2151_reset_chip(void *_chip) +{ + int i; + YM2151 *chip = (YM2151 *)_chip; + + + /* initialize hardware registers */ + for (i=0; i<32; i++) + { + memset(&chip->oper[i],'\0',sizeof(YM2151Operator)); + chip->oper[i].volume = MAX_ATT_INDEX; + chip->oper[i].kc_i = 768; /* min kc_i value */ + } + + chip->eg_timer = 0; + chip->eg_cnt = 0; + + chip->lfo_timer = 0; + chip->lfo_counter= 0; + chip->lfo_phase = 0; + chip->lfo_wsel = 0; + chip->pmd = 0; + chip->amd = 0; + chip->lfa = 0; + chip->lfp = 0; + + chip->test= 0; + + chip->irq_enable = 0; +#ifdef USE_MAME_TIMERS + /* ASG 980324 -- reset the timers before writing to the registers */ + chip->timer_A->enable(false); + chip->timer_B->enable(false); +#else + chip->tim_A = 0; + chip->tim_B = 0; + chip->tim_A_val = 0; + chip->tim_B_val = 0; +#endif + chip->timer_A_index = 0; + chip->timer_B_index = 0; + chip->timer_A_index_old = 0; + chip->timer_B_index_old = 0; + + chip->noise = 0; + chip->noise_rng = 0; + chip->noise_p = 0; + chip->noise_f = chip->noise_tab[0]; + + chip->csm_req = 0; + chip->status = 0; + + ym2151_write_reg(chip, 0x1b, 0); /* only because of CT1, CT2 output pins */ + ym2151_write_reg(chip, 0x18, 0); /* set LFO frequency */ + for (i=0x20; i<0x100; i++) /* set the operators */ + { + ym2151_write_reg(chip, i, 0); + } +} + + + +INLINE signed int op_calc(YM2151Operator * OP, unsigned int env, signed int pm) +{ + UINT32 p; + + + p = (env<<3) + sin_tab[ ( ((signed int)((OP->phase & ~FREQ_MASK) + (pm<<15))) >> FREQ_SH ) & SIN_MASK ]; + + if (p >= TL_TAB_LEN) + return 0; + + return tl_tab[p]; +} + +INLINE signed int op_calc1(YM2151Operator * OP, unsigned int env, signed int pm) +{ + UINT32 p; + INT32 i; + + + i = (OP->phase & ~FREQ_MASK) + pm; + +/*logerror("i=%08x (i>>16)&511=%8i phase=%i [pm=%08x] ",i, (i>>16)&511, OP->phase>>FREQ_SH, pm);*/ + + p = (env<<3) + sin_tab[ (i>>FREQ_SH) & SIN_MASK]; + +/*logerror("(p&255=%i p>>8=%i) out= %i\n", p&255,p>>8, tl_tab[p&255]>>(p>>8) );*/ + + if (p >= TL_TAB_LEN) + return 0; + + return tl_tab[p]; +} + + + +#define volume_calc(OP) ((OP)->tl + ((UINT32)(OP)->volume) + (AM & (OP)->AMmask)) + +INLINE void chan_calc(YM2151 *PSG, unsigned int chan) +{ + YM2151Operator *op; + unsigned int env; + UINT32 AM = 0; + + PSG->m2 = PSG->c1 = PSG->c2 = PSG->mem = 0; + op = &PSG->oper[chan*4]; /* M1 */ + + *op->mem_connect = op->mem_value; /* restore delayed sample (MEM) value to m2 or c2 */ + + if (op->ams) + AM = PSG->lfa << (op->ams-1); + env = volume_calc(op); + { + INT32 out = op->fb_out_prev + op->fb_out_curr; + op->fb_out_prev = op->fb_out_curr; + + if (!op->connect) + /* algorithm 5 */ + PSG->mem = PSG->c1 = PSG->c2 = op->fb_out_prev; + else + /* other algorithms */ + *op->connect = op->fb_out_prev; + + op->fb_out_curr = 0; + if (env < ENV_QUIET) + { + if (!op->fb_shift) + out=0; + op->fb_out_curr = op_calc1(op, env, (out<fb_shift) ); + } + } + + env = volume_calc(op+1); /* M2 */ + if (env < ENV_QUIET) + *(op+1)->connect += op_calc(op+1, env, PSG->m2); + + env = volume_calc(op+2); /* C1 */ + if (env < ENV_QUIET) + *(op+2)->connect += op_calc(op+2, env, PSG->c1); + + env = volume_calc(op+3); /* C2 */ + if (env < ENV_QUIET) + PSG->chanout[chan] += op_calc(op+3, env, PSG->c2); + + /* M1 */ + op->mem_value = PSG->mem; +} + +INLINE void chan7_calc(YM2151 *PSG) +{ + YM2151Operator *op; + unsigned int env; + UINT32 AM = 0; + + PSG->m2 = PSG->c1 = PSG->c2 = PSG->mem = 0; + op = &PSG->oper[7*4]; /* M1 */ + + *op->mem_connect = op->mem_value; /* restore delayed sample (MEM) value to m2 or c2 */ + + if (op->ams) + AM = PSG->lfa << (op->ams-1); + env = volume_calc(op); + { + INT32 out = op->fb_out_prev + op->fb_out_curr; + op->fb_out_prev = op->fb_out_curr; + + if (!op->connect) + /* algorithm 5 */ + PSG->mem = PSG->c1 = PSG->c2 = op->fb_out_prev; + else + /* other algorithms */ + *op->connect = op->fb_out_prev; + + op->fb_out_curr = 0; + if (env < ENV_QUIET) + { + if (!op->fb_shift) + out=0; + op->fb_out_curr = op_calc1(op, env, (out<fb_shift) ); + } + } + + env = volume_calc(op+1); /* M2 */ + if (env < ENV_QUIET) + *(op+1)->connect += op_calc(op+1, env, PSG->m2); + + env = volume_calc(op+2); /* C1 */ + if (env < ENV_QUIET) + *(op+2)->connect += op_calc(op+2, env, PSG->c1); + + env = volume_calc(op+3); /* C2 */ + if (PSG->noise & 0x80) + { + UINT32 noiseout; + + noiseout = 0; + if (env < 0x3ff) + noiseout = (env ^ 0x3ff) * 2; /* range of the YM2151 noise output is -2044 to 2040 */ + PSG->chanout[7] += ((PSG->noise_rng&0x10000) ? noiseout: -noiseout); /* bit 16 -> output */ + } + else + { + if (env < ENV_QUIET) + PSG->chanout[7] += op_calc(op+3, env, PSG->c2); + } + /* M1 */ + op->mem_value = PSG->mem; +} + + + + + + +/* +The 'rate' is calculated from following formula (example on decay rate): + rks = notecode after key scaling (a value from 0 to 31) + DR = value written to the chip register + rate = 2*DR + rks; (max rate = 2*31+31 = 93) +Four MSBs of the 'rate' above are the 'main' rate (from 00 to 15) +Two LSBs of the 'rate' above are the value 'x' (the shape type). +(eg. '11 2' means that 'rate' is 11*4+2=46) + +NOTE: A 'sample' in the description below is actually 3 output samples, +thats because the Envelope Generator clock is equal to internal_clock/3. + +Single '-' (minus) character in the diagrams below represents one sample +on the output; this is for rates 11 x (11 0, 11 1, 11 2 and 11 3) + +these 'main' rates: +00 x: single '-' = 2048 samples; (ie. level can change every 2048 samples) +01 x: single '-' = 1024 samples; +02 x: single '-' = 512 samples; +03 x: single '-' = 256 samples; +04 x: single '-' = 128 samples; +05 x: single '-' = 64 samples; +06 x: single '-' = 32 samples; +07 x: single '-' = 16 samples; +08 x: single '-' = 8 samples; +09 x: single '-' = 4 samples; +10 x: single '-' = 2 samples; +11 x: single '-' = 1 sample; (ie. level can change every 1 sample) + +Shapes for rates 11 x look like this: +rate: step: +11 0 01234567 + +level: +0 -- +1 -- +2 -- +3 -- + +rate: step: +11 1 01234567 + +level: +0 -- +1 -- +2 - +3 - +4 -- + +rate: step: +11 2 01234567 + +level: +0 -- +1 - +2 - +3 -- +4 - +5 - + +rate: step: +11 3 01234567 + +level: +0 -- +1 - +2 - +3 - +4 - +5 - +6 - + + +For rates 12 x, 13 x, 14 x and 15 x output level changes on every +sample - this means that the waveform looks like this: (but the level +changes by different values on different steps) +12 3 01234567 + +0 - +2 - +4 - +8 - +10 - +12 - +14 - +18 - +20 - + +Notes about the timing: +---------------------- + +1. Synchronism + +Output level of each two (or more) voices running at the same 'main' rate +(eg 11 0 and 11 1 in the diagram below) will always be changing in sync, +even if there're started with some delay. + +Note that, in the diagram below, the decay phase in channel 0 starts at +sample #2, while in channel 1 it starts at sample #6. Anyway, both channels +will always change their levels at exactly the same (following) samples. + +(S - start point of this channel, A-attack phase, D-decay phase): + +step: +01234567012345670123456 + +channel 0: + -- + | -- + | - + | - + | -- + | -- +| -- +| - +| - +| -- +AADDDDDDDDDDDDDDDD +S + +01234567012345670123456 +channel 1: + - + | - + | -- + | -- + | -- + | - + | - + | -- + | -- + | -- + AADDDDDDDDDDDDDDDD + S +01234567012345670123456 + + +2. Shifted (delayed) synchronism + +Output of each two (or more) voices running at different 'main' rate +(9 1, 10 1 and 11 1 in the diagrams below) will always be changing +in 'delayed-sync' (even if there're started with some delay as in "1.") + +Note that the shapes are delayed by exactly one sample per one 'main' rate +increment. (Normally one would expect them to start at the same samples.) + +See diagram below (* - start point of the shape). + +cycle: +0123456701234567012345670123456701234567012345670123456701234567 + +rate 09 1 +*------- + -------- + ---- + ---- + -------- + *------- + | -------- + | ---- + | ---- + | -------- +rate 10 1 | +-- | + *--- | + ---- | + -- | + -- | + ---- | + *--- | + | ---- | + | -- | | <- one step (two samples) delay between 9 1 and 10 1 + | -- | | + | ----| + | *--- + | ---- + | -- + | -- + | ---- +rate 11 1 | +- | + -- | + *- | + -- | + - | + - | + -- | + *- | + -- | + - || <- one step (one sample) delay between 10 1 and 11 1 + - || + --| + *- + -- + - + - + -- + *- + -- + - + - + -- +*/ + +INLINE void advance_eg(YM2151 *PSG) +{ + YM2151Operator *op; + unsigned int i; + + + + PSG->eg_timer += PSG->eg_timer_add; + + while (PSG->eg_timer >= PSG->eg_timer_overflow) + { + PSG->eg_timer -= PSG->eg_timer_overflow; + + PSG->eg_cnt++; + + /* envelope generator */ + op = &PSG->oper[0]; /* CH 0 M1 */ + i = 32; + do + { + switch(op->state) + { + case EG_ATT: /* attack phase */ + if ( !(PSG->eg_cnt & ((1<eg_sh_ar)-1) ) ) + { + op->volume += (~op->volume * + (eg_inc[op->eg_sel_ar + ((PSG->eg_cnt>>op->eg_sh_ar)&7)]) + ) >>4; + + if (op->volume <= MIN_ATT_INDEX) + { + op->volume = MIN_ATT_INDEX; + op->state = EG_DEC; + } + + } + break; + + case EG_DEC: /* decay phase */ + if ( !(PSG->eg_cnt & ((1<eg_sh_d1r)-1) ) ) + { + op->volume += eg_inc[op->eg_sel_d1r + ((PSG->eg_cnt>>op->eg_sh_d1r)&7)]; + + if ( op->volume >= op->d1l ) + op->state = EG_SUS; + + } + break; + + case EG_SUS: /* sustain phase */ + if ( !(PSG->eg_cnt & ((1<eg_sh_d2r)-1) ) ) + { + op->volume += eg_inc[op->eg_sel_d2r + ((PSG->eg_cnt>>op->eg_sh_d2r)&7)]; + + if ( op->volume >= MAX_ATT_INDEX ) + { + op->volume = MAX_ATT_INDEX; + op->state = EG_OFF; + } + + } + break; + + case EG_REL: /* release phase */ + if ( !(PSG->eg_cnt & ((1<eg_sh_rr)-1) ) ) + { + op->volume += eg_inc[op->eg_sel_rr + ((PSG->eg_cnt>>op->eg_sh_rr)&7)]; + + if ( op->volume >= MAX_ATT_INDEX ) + { + op->volume = MAX_ATT_INDEX; + op->state = EG_OFF; + } + + } + break; + } + op++; + i--; + }while (i); + } +} + + +INLINE void advance(YM2151 *PSG) +{ + YM2151Operator *op; + unsigned int i; + int a,p; + + /* LFO */ + if (PSG->test&2) + PSG->lfo_phase = 0; + else + { + PSG->lfo_timer += PSG->lfo_timer_add; + if (PSG->lfo_timer >= PSG->lfo_overflow) + { + PSG->lfo_timer -= PSG->lfo_overflow; + PSG->lfo_counter += PSG->lfo_counter_add; + PSG->lfo_phase += (PSG->lfo_counter>>4); + PSG->lfo_phase &= 255; + PSG->lfo_counter &= 15; + } + } + + i = PSG->lfo_phase; + /* calculate LFO AM and PM waveform value (all verified on real chip, except for noise algorithm which is impossible to analyse)*/ + switch (PSG->lfo_wsel) + { + case 0: + /* saw */ + /* AM: 255 down to 0 */ + /* PM: 0 to 127, -127 to 0 (at PMD=127: LFP = 0 to 126, -126 to 0) */ + a = 255 - i; + if (i<128) + p = i; + else + p = i - 255; + break; + case 1: + /* square */ + /* AM: 255, 0 */ + /* PM: 128,-128 (LFP = exactly +PMD, -PMD) */ + if (i<128) + { + a = 255; + p = 128; + } + else + { + a = 0; + p = -128; + } + break; + case 2: + /* triangle */ + /* AM: 255 down to 1 step -2; 0 up to 254 step +2 */ + /* PM: 0 to 126 step +2, 127 to 1 step -2, 0 to -126 step -2, -127 to -1 step +2*/ + if (i<128) + a = 255 - (i*2); + else + a = (i*2) - 256; + + if (i<64) /* i = 0..63 */ + p = i*2; /* 0 to 126 step +2 */ + else if (i<128) /* i = 64..127 */ + p = 255 - i*2; /* 127 to 1 step -2 */ + else if (i<192) /* i = 128..191 */ + p = 256 - i*2; /* 0 to -126 step -2*/ + else /* i = 192..255 */ + p = i*2 - 511; /*-127 to -1 step +2*/ + break; + case 3: + default: /*keep the compiler happy*/ + /* random */ + /* the real algorithm is unknown !!! + We just use a snapshot of data from real chip */ + + /* AM: range 0 to 255 */ + /* PM: range -128 to 127 */ + + a = lfo_noise_waveform[i]; + p = a-128; + break; + } + PSG->lfa = a * PSG->amd / 128; + PSG->lfp = p * PSG->pmd / 128; + + + /* The Noise Generator of the YM2151 is 17-bit shift register. + * Input to the bit16 is negated (bit0 XOR bit3) (EXNOR). + * Output of the register is negated (bit0 XOR bit3). + * Simply use bit16 as the noise output. + */ + PSG->noise_p += PSG->noise_f; + i = (PSG->noise_p>>16); /* number of events (shifts of the shift register) */ + PSG->noise_p &= 0xffff; + while (i) + { + UINT32 j; + j = ( (PSG->noise_rng ^ (PSG->noise_rng>>3) ) & 1) ^ 1; + PSG->noise_rng = (j<<16) | (PSG->noise_rng>>1); + i--; + } + + + /* phase generator */ + op = &PSG->oper[0]; /* CH 0 M1 */ + i = 8; + do + { + if (op->pms) /* only when phase modulation from LFO is enabled for this channel */ + { + INT32 mod_ind = PSG->lfp; /* -128..+127 (8bits signed) */ + if (op->pms < 6) + mod_ind >>= (6 - op->pms); + else + mod_ind <<= (op->pms - 5); + + if (mod_ind) + { + UINT32 kc_channel = op->kc_i + mod_ind; + (op+0)->phase += ( (PSG->freq[ kc_channel + (op+0)->dt2 ] + (op+0)->dt1) * (op+0)->mul ) >> 1; + (op+1)->phase += ( (PSG->freq[ kc_channel + (op+1)->dt2 ] + (op+1)->dt1) * (op+1)->mul ) >> 1; + (op+2)->phase += ( (PSG->freq[ kc_channel + (op+2)->dt2 ] + (op+2)->dt1) * (op+2)->mul ) >> 1; + (op+3)->phase += ( (PSG->freq[ kc_channel + (op+3)->dt2 ] + (op+3)->dt1) * (op+3)->mul ) >> 1; + } + else /* phase modulation from LFO is equal to zero */ + { + (op+0)->phase += (op+0)->freq; + (op+1)->phase += (op+1)->freq; + (op+2)->phase += (op+2)->freq; + (op+3)->phase += (op+3)->freq; + } + } + else /* phase modulation from LFO is disabled */ + { + (op+0)->phase += (op+0)->freq; + (op+1)->phase += (op+1)->freq; + (op+2)->phase += (op+2)->freq; + (op+3)->phase += (op+3)->freq; + } + + op+=4; + i--; + }while (i); + + + /* CSM is calculated *after* the phase generator calculations (verified on real chip) + * CSM keyon line seems to be ORed with the KO line inside of the chip. + * The result is that it only works when KO (register 0x08) is off, ie. 0 + * + * Interesting effect is that when timer A is set to 1023, the KEY ON happens + * on every sample, so there is no KEY OFF at all - the result is that + * the sound played is the same as after normal KEY ON. + */ + + if (PSG->csm_req) /* CSM KEYON/KEYOFF seqeunce request */ + { + if (PSG->csm_req==2) /* KEY ON */ + { + op = &PSG->oper[0]; /* CH 0 M1 */ + i = 32; + do + { + KEY_ON(op, 2); + op++; + i--; + }while (i); + PSG->csm_req = 1; + } + else /* KEY OFF */ + { + op = &PSG->oper[0]; /* CH 0 M1 */ + i = 32; + do + { + KEY_OFF(op,~2); + op++; + i--; + }while (i); + PSG->csm_req = 0; + } + } +} + +#if 0 +INLINE signed int acc_calc(signed int value) +{ + if (value>=0) + { + if (value < 0x0200) + return (value & ~0); + if (value < 0x0400) + return (value & ~1); + if (value < 0x0800) + return (value & ~3); + if (value < 0x1000) + return (value & ~7); + if (value < 0x2000) + return (value & ~15); + if (value < 0x4000) + return (value & ~31); + return (value & ~63); + } + /*else value < 0*/ + if (value > -0x0200) + return (~abs(value) & ~0); + if (value > -0x0400) + return (~abs(value) & ~1); + if (value > -0x0800) + return (~abs(value) & ~3); + if (value > -0x1000) + return (~abs(value) & ~7); + if (value > -0x2000) + return (~abs(value) & ~15); + if (value > -0x4000) + return (~abs(value) & ~31); + return (~abs(value) & ~63); +} +#endif + +/* first macro saves left and right channels to mono file */ +/* second macro saves left and right channels to stereo file */ +#if 0 /*MONO*/ + #ifdef SAVE_SEPARATE_CHANNELS + #define SAVE_SINGLE_CHANNEL(j) \ + { signed int pom= -(chanout[j] & PSG->pan[j*2]); \ + if (pom > 32767) pom = 32767; else if (pom < -32768) pom = -32768; \ + fputc((unsigned short)pom&0xff,sample[j]); \ + fputc(((unsigned short)pom>>8)&0xff,sample[j]); \ + } + #else + #define SAVE_SINGLE_CHANNEL(j) + #endif +#else /*STEREO*/ + #ifdef SAVE_SEPARATE_CHANNELS + #define SAVE_SINGLE_CHANNEL(j) \ + { signed int pom = -(chanout[j] & PSG->pan[j*2]); \ + if (pom > 32767) pom = 32767; else if (pom < -32768) pom = -32768; \ + fputc((unsigned short)pom&0xff,sample[j]); \ + fputc(((unsigned short)pom>>8)&0xff,sample[j]); \ + pom = -(chanout[j] & PSG->pan[j*2+1]); \ + if (pom > 32767) pom = 32767; else if (pom < -32768) pom = -32768; \ + fputc((unsigned short)pom&0xff,sample[j]); \ + fputc(((unsigned short)pom>>8)&0xff,sample[j]); \ + } + #else + #define SAVE_SINGLE_CHANNEL(j) + #endif +#endif + +/* first macro saves left and right channels to mono file */ +/* second macro saves left and right channels to stereo file */ +#if 1 /*MONO*/ + #ifdef SAVE_SAMPLE + #define SAVE_ALL_CHANNELS \ + { signed int pom = outl; \ + /*pom = acc_calc(pom);*/ \ + /*fprintf(sample[8]," %i\n",pom);*/ \ + fputc((unsigned short)pom&0xff,sample[8]); \ + fputc(((unsigned short)pom>>8)&0xff,sample[8]); \ + } + #else + #define SAVE_ALL_CHANNELS + #endif +#else /*STEREO*/ + #ifdef SAVE_SAMPLE + #define SAVE_ALL_CHANNELS \ + { signed int pom = outl; \ + fputc((unsigned short)pom&0xff,sample[8]); \ + fputc(((unsigned short)pom>>8)&0xff,sample[8]); \ + pom = outr; \ + fputc((unsigned short)pom&0xff,sample[8]); \ + fputc(((unsigned short)pom>>8)&0xff,sample[8]); \ + } + #else + #define SAVE_ALL_CHANNELS + #endif +#endif + + +/* Generate samples for one of the YM2151's +* +* 'num' is the number of virtual YM2151 +* '**buffers' is table of pointers to the buffers: left and right +* 'length' is the number of samples that should be generated +*/ +void ym2151_update_one(void *chip, SAMP **buffers, int length) +{ + YM2151 *PSG = (YM2151 *)chip; + signed int *chanout = PSG->chanout; + int i; + signed int outl,outr; + SAMP *bufL, *bufR; + + bufL = buffers[0]; + bufR = buffers[1]; + +#ifdef USE_MAME_TIMERS + /* ASG 980324 - handled by real timers now */ +#else + if (PSG->tim_B) + { + PSG->tim_B_val -= ( length << TIMER_SH ); + if (PSG->tim_B_val<=0) + { + PSG->tim_B_val += PSG->tim_B_tab[ PSG->timer_B_index ]; + if ( PSG->irq_enable & 0x08 ) + { + int oldstate = PSG->status & 3; + PSG->status |= 2; + if ((!oldstate) && (PSG->irqhandler)) (*PSG->irqhandler)(chip->device, 1); + } + } + } +#endif + + for (i=0; ipan[0]; + outr = chanout[0] & PSG->pan[1]; + outl += (chanout[1] & PSG->pan[2]); + outr += (chanout[1] & PSG->pan[3]); + outl += (chanout[2] & PSG->pan[4]); + outr += (chanout[2] & PSG->pan[5]); + outl += (chanout[3] & PSG->pan[6]); + outr += (chanout[3] & PSG->pan[7]); + outl += (chanout[4] & PSG->pan[8]); + outr += (chanout[4] & PSG->pan[9]); + outl += (chanout[5] & PSG->pan[10]); + outr += (chanout[5] & PSG->pan[11]); + outl += (chanout[6] & PSG->pan[12]); + outr += (chanout[6] & PSG->pan[13]); + outl += (chanout[7] & PSG->pan[14]); + outr += (chanout[7] & PSG->pan[15]); + + outl >>= FINAL_SH; + outr >>= FINAL_SH; + if (outl > MAXOUT) outl = MAXOUT; + else if (outl < MINOUT) outl = MINOUT; + if (outr > MAXOUT) outr = MAXOUT; + else if (outr < MINOUT) outr = MINOUT; + ((SAMP*)bufL)[i] = (SAMP)outl; + ((SAMP*)bufR)[i] = (SAMP)outr; + + SAVE_ALL_CHANNELS + +#ifdef USE_MAME_TIMERS + /* ASG 980324 - handled by real timers now */ +#else + /* calculate timer A */ + if (PSG->tim_A) + { + PSG->tim_A_val -= ( 1 << TIMER_SH ); + if (PSG->tim_A_val <= 0) + { + PSG->tim_A_val += PSG->tim_A_tab[ PSG->timer_A_index ]; + if (PSG->irq_enable & 0x04) + { + int oldstate = PSG->status & 3; + PSG->status |= 1; + if ((!oldstate) && (PSG->irqhandler)) (*PSG->irqhandler)(chip->device, 1); + } + if (PSG->irq_enable & 0x80) + PSG->csm_req = 2; /* request KEY ON / KEY OFF sequence */ + } + } +#endif + advance(PSG); + } +} + +void ym2151_set_irq_handler(void *chip, void(*handler)(device_t *device, int irq)) +{ + YM2151 *PSG = (YM2151 *)chip; + PSG->irqhandler = handler; +} + +void ym2151_set_port_write_handler(void *chip, void (*handler)(device_t *, offs_t, UINT8)) +{ + YM2151 *PSG = (YM2151 *)chip; + PSG->porthandler = handler; +} diff --git a/src/devices/sound/ym2151.h b/src/devices/sound/ym2151.h new file mode 100644 index 00000000000..3d62ac278ac --- /dev/null +++ b/src/devices/sound/ym2151.h @@ -0,0 +1,88 @@ +// license:??? +// copyright-holders:Jarek Burczynski +/* +** File: ym2151.h - header file for software implementation of YM2151 +** FM Operator Type-M(OPM) +** +** (c) 1997-2002 Jarek Burczynski (s0246@poczta.onet.pl, bujar@mame.net) +** Some of the optimizing ideas by Tatsuyuki Satoh +** +** Version 2.150 final beta May, 11th 2002 +** +** +** I would like to thank following people for making this project possible: +** +** Beauty Planets - for making a lot of real YM2151 samples and providing +** additional informations about the chip. Also for the time spent making +** the samples and the speed of replying to my endless requests. +** +** Shigeharu Isoda - for general help, for taking time to scan his YM2151 +** Japanese Manual first of all, and answering MANY of my questions. +** +** Nao - for giving me some info about YM2151 and pointing me to Shigeharu. +** Also for creating fmemu (which I still use to test the emulator). +** +** Aaron Giles and Chris Hardy - they made some samples of one of my favourite +** arcade games so I could compare it to my emulator. +** +** Bryan McPhail and Tim (powerjaw) - for making some samples. +** +** Ishmair - for the datasheet and motivation. +*/ + +#pragma once + +#ifndef __YM2151_H__ +#define __YM2151_H__ + + +/* 16- and 8-bit samples (signed) are supported*/ +#define SAMPLE_BITS 16 + +typedef stream_sample_t SAMP; +/* +#if (SAMPLE_BITS==16) + typedef INT16 SAMP; +#endif +#if (SAMPLE_BITS==8) + typedef signed char SAMP; +#endif +*/ + +/* +** Initialize YM2151 emulator(s). +** +** 'num' is the number of virtual YM2151's to allocate +** 'clock' is the chip clock in Hz +** 'rate' is sampling rate +*/ +void *ym2151_init(device_t *device, int clock, int rate); + +/* shutdown the YM2151 emulators*/ +void ym2151_shutdown(void *chip); + +/* reset all chip registers for YM2151 number 'num'*/ +void ym2151_reset_chip(void *chip); + +/* +** Generate samples for one of the YM2151's +** +** 'num' is the number of virtual YM2151 +** '**buffers' is table of pointers to the buffers: left and right +** 'length' is the number of samples that should be generated +*/ +void ym2151_update_one(void *chip, SAMP **buffers, int length); + +/* write 'v' to register 'r' on YM2151 chip number 'n'*/ +void ym2151_write_reg(void *chip, int r, int v); + +/* read status register on YM2151 chip number 'n'*/ +int ym2151_read_status(void *chip); + +/* set interrupt handler on YM2151 chip number 'n'*/ +void ym2151_set_irq_handler(void *chip, void (*handler)(device_t *device, int irq)); + +/* set port write handler on YM2151 chip number 'n'*/ +void ym2151_set_port_write_handler(void *chip, void (*handler)(device_t *, offs_t, UINT8)); + +#endif /*__YM2151_H__*/ diff --git a/src/devices/sound/ym2151.txt b/src/devices/sound/ym2151.txt new file mode 100644 index 00000000000..a28893ae3ff --- /dev/null +++ b/src/devices/sound/ym2151.txt @@ -0,0 +1,162 @@ + +This is some very technical info I found during my experiments with real chip. +I hope someone will find it interesting. + + + YM2151 TIMING DIAGRAM + +-------------------------------------------------------------------------------------------------------------------------------|--------- +Cycle no. | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |10 |11 |12 |13 |14 |15 |16 |17 |18 |19 |20 |21 |22 |23 |24 |25 |26 |27 |28 |29 |30 |31 | 0 | 1 | + +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---|---+---+- + | _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _| _ _ +D/A clock |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_ + | | + +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---|---+---+- + | _______________________________ | +SH1 signal |_______________________________| |_______________________________________________________________|_________ + | | + +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---|---+---+- + | _______________________________| +SH2 signal |_______________________________________________________________________________________________| |_________ + | | + +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---|---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---|---+---+- + | | | +SO | x | x | x | D0| D1| D2| D3| D4| D5| D6| D7| D8| D9| S0| S1| S2| x | x | x | D0| D1| D2| D3| D4| D5| D6| D7| D8| D9| S0| S1| S2| x | x | +(D/A data) | | | + | R I G H T C H A N N E L | L E F T C H A N N E L | + +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---|---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---|---+---+- +READ | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | +INTERNAL CH| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 0 | 1 | +DATA OP| C2| C2| C2| C2| C2| C2| C2| C2| M1| M1| M1| M1| M1| M1| M1| M1| M2| M2| M2| M2| M2| M2| M2| M2| C1| C1| C1| C1| C1| C1| C1| C1| C2| C2| + | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | + operator #| 24| 25| 26| 27| 28| 29| 30| 31| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10| 11| 12| 13| 14| 15| 16| 17| 18| 19| 20| 21| 22| 23| 24| 25| + +---------------------------------------------------------------|---------------------------------------------------------------|--------- + + + Note: + ----- + The SO (D/A data) is sequentially output to the YM3012 (stereo) or YM3014 (mono). + Formula to calculate sample from SO data is: + N = S2(2^2) + S1(2^1) + S0 + where S2 = S1 = S0 = 0 - not allowed + SAMPLE = (-1+D9 + D8(2^-1) + D7(2^-2) + D6(2^-3) + ... + D0(2^-9) + 2^-10) * 2^-N + + Anyway, important is that SO data is delayed by one sample compared to READ INTERNAL DATA. + This is logical since chip has to sum all channels' outputs before it will send SO data + (this is what the ACC (accumulator) does). + + + +YM2151 Test register (0x01): + + +----------+-----+------+-----+-----+------+------+------+-------+ + | bit no. | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | + +----------+-----+------+-----+-----+------+------+------+-------+ + | hex val. | 80 | 40 | 20 | 10 | 08 | 04 | 02 | 01 | + +----------+-----+------+-----+-----+------+------+------+-------+ + | |LS/MS| RIen | HEG | NEG | HPGL | ILFO | HLFO | u_clk | + +----------+-----+------+-----+-----+------+------+------+-------+ + + +bit 6 - RIen (Read Internal data Enable) + + When set to 1, chip's internal data can be read via status register. + + Simply set this bit and read data that will come out sequentially via the 8-bit + bus. Format of this data and the timing will be described later (diagram is above). + + + +bit 7 - LS/MS (Least Significant or Most Significant 8 bits of internal data) + + When 0 - chip's internal data read via status register is lower 8 bits (LSB), + When 1 - chip's internal data is upper 8 bits (MSB) (plus something I haven't figured out). + + In other words: in order to read 8 LSB bits set this bit to 0, in order to read + 8 MSB bits set this bit to 1. + + + +bit 5 - HEG (Halt Envelope Generator) + + When 1 - Envelope Generator gets halted. + + This means that *Phase* Generator data can be read out when: + HEG bit is set to 1 (EG gets halted), and data coming out via the status register + will be pure sinus wave at the _CURRENT_ EG output. + This means you need to know _EXACTLY_ when to set this bit. + + Simple workaround is to do the following: + - TL (Total Level) of the operator to minimum dB value (0x00) - it is max volume, + - AR (Attack Rate) of the operator to maximum speed (shortest time) (0x1f), + - D1L (Decay Level) of the operator to max (93 dB) (0xf0), + - D1R (Decay Rate) of the operator to zero (infinite time) speed (0x00), + - set KEYON of that operator, + - wait a while (long enough so Attack phase of the EG can be done), + - set HEG bit in the test register to 1, + and its done, since EG will be halted generating 0 (zero) dB level for + that operator (exactly speaking EG will stay in D1R phase) and, since 0 dB from EG + means no change on the sinus data stored inside of the chip's internal ROM, + you can read this ROM data. + + Careful reader will notice that it may not be needed to use HEG bit to read the data + (bacause EG will be at 0dB anyway), but using this bit, one can make samples + of pure PHASE generator innerworking - that is how I obtained phaseinc_rom[]. + + + +bit 4 - NEG (Negate output data) + + When 1 - output data sign will be simply inverted. + + Worth noticing is that when this bit is 1 - also chip output data will be negated, + causing bad sound coming out of the speakers since the YM3012 (the D/A converter) + does not expect the negated data !!! + + + +bit 3 - HPGL (Halt Phase Generator AND LFO amplitude modulation) + + When 1 - Phase Generator is halted. Also amplitude modulation + (from LFO to Envelope Generator) is halted. + + You can use this bit to analyse Envelope Generator work. + As it was in the case of HEG bit you need to know _EXACTLY_ when to set this bit. + Unfortunately, there is no _simple_ way. You will need to synchronise on the chip + output signals to know when to set it. + + + +bit 2 - ILFO (Internal LFO related) + + When 1 - LFO output (depends on selected waveform) + + LFO outputs some internal signals...what are they ? + I did not test if this bit alters Phase Modulation in any way. + + Also alters timer A somehow. At least it sounds like a restart. + + + +bit 1 - HLFO (Halt LFO) + + When 1 - LFO gets HALTED (at maximum amplitude in case of AM). + + On the 1 to 0 transition LFO will be RESET to startup of the waveform + (phase of the LFO _only_). + + + +bit 0 - u_clk (unknown, but probably internal clock related) + + When 1 - Envelope Generator times are much shorter (faster envelopes). + + I do not know if it alters Attacks parts of the envelope. I'm sure it + alters Decays times. Also timers are much (twice ?) faster than normally. + Perhaps this bit is disabling some internal clock divider. + FWIW, frequencies of the operators are NOT altered by setting this bit. + + +Jarek Burczynski + +s0246@poczta.onet.pl +bujar at mame dot net diff --git a/src/devices/sound/ym2413.c b/src/devices/sound/ym2413.c new file mode 100644 index 00000000000..631560912b0 --- /dev/null +++ b/src/devices/sound/ym2413.c @@ -0,0 +1,2176 @@ +// license:??? +// copyright-holders:Jarek Burczynski +/* +** +** File: ym2413.c - software implementation of YM2413 +** FM sound generator type OPLL +** +** Copyright Jarek Burczynski +** +** Version 1.0 +** + + Features as listed in LSI-212413A2 data sheet: + 1. FM Sound Generator for real sound creation. + 2. Two Selectable modes: 9 simultaneous sounds or 6 melody sounds plus 5 rhythm sounds + (different tones can be used together in either case). + 3. Built-in Instruments data (15 melody tones, 5 rhythm tones, "CAPTAIN and TELETEXT applicalbe tones). + 4. Built-in DA Converter. + 5. Built-in Quartz Oscillator. + 6. Built-in Vibrato Oscillator/AM Oscillator + 7. TTL Compatible Input. + 8. Si-Gate NMOS LSI + 9. A single 5V power source. + +to do: + +- make sure of the sinus amplitude bits + +- make sure of the EG resolution bits (looks like the biggest + modulation index generated by the modulator is 123, 124 = no modulation) +- find proper algorithm for attack phase of EG + +- tune up instruments ROM + +- support sample replay in test mode (it is NOT as simple as setting bit 0 + in register 0x0f and using register 0x10 for sample data). + Which games use this feature ? + + +*/ + +#include "emu.h" +#include "ym2413.h" + + + +/* output final shift */ +#if (SAMPLE_BITS==16) + #define FINAL_SH (0) + #define MAXOUT (+32767) + #define MINOUT (-32768) +#else + #define FINAL_SH (8) + #define MAXOUT (+127) + #define MINOUT (-128) +#endif + + +#define FREQ_SH 16 /* 16.16 fixed point (frequency calculations) */ +#define EG_SH 16 /* 16.16 fixed point (EG timing) */ +#define LFO_SH 24 /* 8.24 fixed point (LFO calculations) */ + +#define FREQ_MASK ((1<=0) + { + if (value < 0x0200) + return (value & ~0); + if (value < 0x0400) + return (value & ~1); + if (value < 0x0800) + return (value & ~3); + if (value < 0x1000) + return (value & ~7); + if (value < 0x2000) + return (value & ~15); + if (value < 0x4000) + return (value & ~31); + return (value & ~63); + } + /*else value < 0*/ + if (value > -0x0200) + return (~abs(value) & ~0); + if (value > -0x0400) + return (~abs(value) & ~1); + if (value > -0x0800) + return (~abs(value) & ~3); + if (value > -0x1000) + return (~abs(value) & ~7); + if (value > -0x2000) + return (~abs(value) & ~15); + if (value > -0x4000) + return (~abs(value) & ~31); + return (~abs(value) & ~63); +} + + +static FILE *sample[1]; + #if 0 /*save to MONO file */ + #define SAVE_ALL_CHANNELS \ + { signed int pom = acc_calc(mo); \ + fputc((unsigned short)pom&0xff,sample[0]); \ + fputc(((unsigned short)pom>>8)&0xff,sample[0]); \ + } + #else /*save to STEREO file */ + #define SAVE_ALL_CHANNELS \ + { signed int pom = mo; \ + fputc((unsigned short)pom&0xff,sample[0]); \ + fputc(((unsigned short)pom>>8)&0xff,sample[0]); \ + pom = ro; \ + fputc((unsigned short)pom&0xff,sample[0]); \ + fputc(((unsigned short)pom>>8)&0xff,sample[0]); \ + } + #define SAVE_SEPARATE_CHANNEL(j) \ + { signed int pom = outchan; \ + fputc((unsigned short)pom&0xff,sample[0]); \ + fputc(((unsigned short)pom>>8)&0xff,sample[0]); \ + pom = chip->instvol_r[j]>>4; \ + fputc((unsigned short)pom&0xff,sample[0]); \ + fputc(((unsigned short)pom>>8)&0xff,sample[0]); \ + } + #endif +#endif + +#define LOG_CYM_FILE 0 +static FILE * cymfile = NULL; + + + + +struct OPLL_SLOT +{ + UINT32 ar; /* attack rate: AR<<2 */ + UINT32 dr; /* decay rate: DR<<2 */ + UINT32 rr; /* release rate:RR<<2 */ + UINT8 KSR; /* key scale rate */ + UINT8 ksl; /* keyscale level */ + UINT8 ksr; /* key scale rate: kcode>>KSR */ + UINT8 mul; /* multiple: mul_tab[ML] */ + + /* Phase Generator */ + UINT32 phase; /* frequency counter */ + UINT32 freq; /* frequency counter step */ + UINT8 fb_shift; /* feedback shift value */ + INT32 op1_out[2]; /* slot1 output for feedback */ + + /* Envelope Generator */ + UINT8 eg_type; /* percussive/nonpercussive mode*/ + UINT8 state; /* phase type */ + UINT32 TL; /* total level: TL << 2 */ + INT32 TLL; /* adjusted now TL */ + INT32 volume; /* envelope counter */ + UINT32 sl; /* sustain level: sl_tab[SL] */ + + UINT8 eg_sh_dp; /* (dump state) */ + UINT8 eg_sel_dp; /* (dump state) */ + UINT8 eg_sh_ar; /* (attack state) */ + UINT8 eg_sel_ar; /* (attack state) */ + UINT8 eg_sh_dr; /* (decay state) */ + UINT8 eg_sel_dr; /* (decay state) */ + UINT8 eg_sh_rr; /* (release state for non-perc.)*/ + UINT8 eg_sel_rr; /* (release state for non-perc.)*/ + UINT8 eg_sh_rs; /* (release state for perc.mode)*/ + UINT8 eg_sel_rs; /* (release state for perc.mode)*/ + + UINT32 key; /* 0 = KEY OFF, >0 = KEY ON */ + + /* LFO */ + UINT32 AMmask; /* LFO Amplitude Modulation enable mask */ + UINT8 vib; /* LFO Phase Modulation enable flag (active high)*/ + + /* waveform select */ + unsigned int wavetable; +}; + +struct OPLL_CH +{ + OPLL_SLOT SLOT[2]; + /* phase generator state */ + UINT32 block_fnum; /* block+fnum */ + UINT32 fc; /* Freq. freqement base */ + UINT32 ksl_base; /* KeyScaleLevel Base step */ + UINT8 kcode; /* key code (for key scaling) */ + UINT8 sus; /* sus on/off (release speed in percussive mode)*/ +}; + +/* chip state */ +struct YM2413 +{ + OPLL_CH P_CH[9]; /* OPLL chips have 9 channels*/ + UINT8 instvol_r[9]; /* instrument/volume (or volume/volume in percussive mode)*/ + + UINT32 eg_cnt; /* global envelope generator counter */ + UINT32 eg_timer; /* global envelope generator counter works at frequency = chipclock/72 */ + UINT32 eg_timer_add; /* step of eg_timer */ + UINT32 eg_timer_overflow; /* envelope generator timer overlfows every 1 sample (on real chip) */ + + UINT8 rhythm; /* Rhythm mode */ + + /* LFO */ + UINT32 LFO_AM; + INT32 LFO_PM; + UINT32 lfo_am_cnt; + UINT32 lfo_am_inc; + UINT32 lfo_pm_cnt; + UINT32 lfo_pm_inc; + + UINT32 noise_rng; /* 23 bit noise shift register */ + UINT32 noise_p; /* current noise 'phase' */ + UINT32 noise_f; /* current noise period */ + + +/* instrument settings */ +/* + 0-user instrument + 1-15 - fixed instruments + 16 -bass drum settings + 17,18 - other percussion instruments +*/ + UINT8 inst_tab[19][8]; + + /* external event callback handlers */ + OPLL_UPDATEHANDLER UpdateHandler; /* stream update handler */ + void * UpdateParam; /* stream update parameter */ + + UINT32 fn_tab[1024]; /* fnumber->increment counter */ + + UINT8 address; /* address register */ + UINT8 status; /* status flag */ + + int clock; /* master clock (Hz) */ + int rate; /* sampling rate (Hz) */ + double freqbase; /* frequency base */ + device_t *device; + + signed int output[2]; + signed int outchan; + +}; + +/* key scale level */ +/* table is 3dB/octave, DV converts this into 6dB/octave */ +/* 0.1875 is bit 0 weight of the envelope counter (volume) expressed in the 'decibel' scale */ +#define DV (0.1875/1.0) +static const UINT32 ksl_tab[8*16]= +{ + /* OCT 0 */ + 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV, + 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV, + 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV, + 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV, + /* OCT 1 */ + 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV, + 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV, + 0.000/DV, 0.750/DV, 1.125/DV, 1.500/DV, + 1.875/DV, 2.250/DV, 2.625/DV, 3.000/DV, + /* OCT 2 */ + 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV, + 0.000/DV, 1.125/DV, 1.875/DV, 2.625/DV, + 3.000/DV, 3.750/DV, 4.125/DV, 4.500/DV, + 4.875/DV, 5.250/DV, 5.625/DV, 6.000/DV, + /* OCT 3 */ + 0.000/DV, 0.000/DV, 0.000/DV, 1.875/DV, + 3.000/DV, 4.125/DV, 4.875/DV, 5.625/DV, + 6.000/DV, 6.750/DV, 7.125/DV, 7.500/DV, + 7.875/DV, 8.250/DV, 8.625/DV, 9.000/DV, + /* OCT 4 */ + 0.000/DV, 0.000/DV, 3.000/DV, 4.875/DV, + 6.000/DV, 7.125/DV, 7.875/DV, 8.625/DV, + 9.000/DV, 9.750/DV,10.125/DV,10.500/DV, + 10.875/DV,11.250/DV,11.625/DV,12.000/DV, + /* OCT 5 */ + 0.000/DV, 3.000/DV, 6.000/DV, 7.875/DV, + 9.000/DV,10.125/DV,10.875/DV,11.625/DV, + 12.000/DV,12.750/DV,13.125/DV,13.500/DV, + 13.875/DV,14.250/DV,14.625/DV,15.000/DV, + /* OCT 6 */ + 0.000/DV, 6.000/DV, 9.000/DV,10.875/DV, + 12.000/DV,13.125/DV,13.875/DV,14.625/DV, + 15.000/DV,15.750/DV,16.125/DV,16.500/DV, + 16.875/DV,17.250/DV,17.625/DV,18.000/DV, + /* OCT 7 */ + 0.000/DV, 9.000/DV,12.000/DV,13.875/DV, + 15.000/DV,16.125/DV,16.875/DV,17.625/DV, + 18.000/DV,18.750/DV,19.125/DV,19.500/DV, + 19.875/DV,20.250/DV,20.625/DV,21.000/DV +}; +#undef DV + +/* 0 / 1.5 / 3.0 / 6.0 dB/OCT, confirmed on a real YM2413 (the application manual is incorrect) */ +static const UINT32 ksl_shift[4] = { 31, 2, 1, 0 }; + + +/* sustain level table (3dB per step) */ +/* 0 - 15: 0, 3, 6, 9,12,15,18,21,24,27,30,33,36,39,42,45 (dB)*/ +#define SC(db) (UINT32) ( db * (1.0/ENV_STEP) ) +static const UINT32 sl_tab[16]={ + SC( 0),SC( 1),SC( 2),SC(3 ),SC(4 ),SC(5 ),SC(6 ),SC( 7), + SC( 8),SC( 9),SC(10),SC(11),SC(12),SC(13),SC(14),SC(15) +}; +#undef SC + + +#define RATE_STEPS (8) +static const unsigned char eg_inc[15*RATE_STEPS]={ +/*cycle:0 1 2 3 4 5 6 7*/ + +/* 0 */ 0,1, 0,1, 0,1, 0,1, /* rates 00..12 0 (increment by 0 or 1) */ +/* 1 */ 0,1, 0,1, 1,1, 0,1, /* rates 00..12 1 */ +/* 2 */ 0,1, 1,1, 0,1, 1,1, /* rates 00..12 2 */ +/* 3 */ 0,1, 1,1, 1,1, 1,1, /* rates 00..12 3 */ + +/* 4 */ 1,1, 1,1, 1,1, 1,1, /* rate 13 0 (increment by 1) */ +/* 5 */ 1,1, 1,2, 1,1, 1,2, /* rate 13 1 */ +/* 6 */ 1,2, 1,2, 1,2, 1,2, /* rate 13 2 */ +/* 7 */ 1,2, 2,2, 1,2, 2,2, /* rate 13 3 */ + +/* 8 */ 2,2, 2,2, 2,2, 2,2, /* rate 14 0 (increment by 2) */ +/* 9 */ 2,2, 2,4, 2,2, 2,4, /* rate 14 1 */ +/*10 */ 2,4, 2,4, 2,4, 2,4, /* rate 14 2 */ +/*11 */ 2,4, 4,4, 2,4, 4,4, /* rate 14 3 */ + +/*12 */ 4,4, 4,4, 4,4, 4,4, /* rates 15 0, 15 1, 15 2, 15 3 (increment by 4) */ +/*13 */ 8,8, 8,8, 8,8, 8,8, /* rates 15 2, 15 3 for attack */ +/*14 */ 0,0, 0,0, 0,0, 0,0, /* infinity rates for attack and decay(s) */ +}; + + +#define O(a) (a*RATE_STEPS) + +/*note that there is no O(13) in this table - it's directly in the code */ +static const unsigned char eg_rate_select[16+64+16]={ /* Envelope Generator rates (16 + 64 rates + 16 RKS) */ +/* 16 infinite time rates */ +O(14),O(14),O(14),O(14),O(14),O(14),O(14),O(14), +O(14),O(14),O(14),O(14),O(14),O(14),O(14),O(14), + +/* rates 00-12 */ +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), + +/* rate 13 */ +O( 4),O( 5),O( 6),O( 7), + +/* rate 14 */ +O( 8),O( 9),O(10),O(11), + +/* rate 15 */ +O(12),O(12),O(12),O(12), + +/* 16 dummy rates (same as 15 3) */ +O(12),O(12),O(12),O(12),O(12),O(12),O(12),O(12), +O(12),O(12),O(12),O(12),O(12),O(12),O(12),O(12), + +}; +#undef O + +/*rate 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 */ +/*shift 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0, 0 */ +/*mask 8191, 4095, 2047, 1023, 511, 255, 127, 63, 31, 15, 7, 3, 1, 0, 0, 0 */ + +#define O(a) (a*1) +static const unsigned char eg_rate_shift[16+64+16]={ /* Envelope Generator counter shifts (16 + 64 rates + 16 RKS) */ +/* 16 infinite time rates */ +O(0),O(0),O(0),O(0),O(0),O(0),O(0),O(0), +O(0),O(0),O(0),O(0),O(0),O(0),O(0),O(0), + +/* rates 00-12 */ +O(13),O(13),O(13),O(13), +O(12),O(12),O(12),O(12), +O(11),O(11),O(11),O(11), +O(10),O(10),O(10),O(10), +O( 9),O( 9),O( 9),O( 9), +O( 8),O( 8),O( 8),O( 8), +O( 7),O( 7),O( 7),O( 7), +O( 6),O( 6),O( 6),O( 6), +O( 5),O( 5),O( 5),O( 5), +O( 4),O( 4),O( 4),O( 4), +O( 3),O( 3),O( 3),O( 3), +O( 2),O( 2),O( 2),O( 2), +O( 1),O( 1),O( 1),O( 1), + +/* rate 13 */ +O( 0),O( 0),O( 0),O( 0), + +/* rate 14 */ +O( 0),O( 0),O( 0),O( 0), + +/* rate 15 */ +O( 0),O( 0),O( 0),O( 0), + +/* 16 dummy rates (same as 15 3) */ +O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0), +O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0), + +}; +#undef O + + +/* multiple table */ +#define ML 2 +static const UINT8 mul_tab[16]= { +/* 1/2, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,10,12,12,15,15 */ + ML/2, 1*ML, 2*ML, 3*ML, 4*ML, 5*ML, 6*ML, 7*ML, + 8*ML, 9*ML,10*ML,10*ML,12*ML,12*ML,15*ML,15*ML +}; +#undef ML + +/* TL_TAB_LEN is calculated as: +* 11 - sinus amplitude bits (Y axis) +* 2 - sinus sign bit (Y axis) +* TL_RES_LEN - sinus resolution (X axis) +*/ +#define TL_TAB_LEN (11*2*TL_RES_LEN) +static signed int tl_tab[TL_TAB_LEN]; + +#define ENV_QUIET (TL_TAB_LEN>>5) + +/* sin waveform table in 'decibel' scale */ +/* two waveforms on OPLL type chips */ +static unsigned int sin_tab[SIN_LEN * 2]; + + +/* LFO Amplitude Modulation table (verified on real YM3812) + 27 output levels (triangle waveform); 1 level takes one of: 192, 256 or 448 samples + + Length: 210 elements. + + Each of the elements has to be repeated + exactly 64 times (on 64 consecutive samples). + The whole table takes: 64 * 210 = 13440 samples. + +We use data>>1, until we find what it really is on real chip... + +*/ + +#define LFO_AM_TAB_ELEMENTS 210 + +static const UINT8 lfo_am_table[LFO_AM_TAB_ELEMENTS] = { +0,0,0,0,0,0,0, +1,1,1,1, +2,2,2,2, +3,3,3,3, +4,4,4,4, +5,5,5,5, +6,6,6,6, +7,7,7,7, +8,8,8,8, +9,9,9,9, +10,10,10,10, +11,11,11,11, +12,12,12,12, +13,13,13,13, +14,14,14,14, +15,15,15,15, +16,16,16,16, +17,17,17,17, +18,18,18,18, +19,19,19,19, +20,20,20,20, +21,21,21,21, +22,22,22,22, +23,23,23,23, +24,24,24,24, +25,25,25,25, +26,26,26, +25,25,25,25, +24,24,24,24, +23,23,23,23, +22,22,22,22, +21,21,21,21, +20,20,20,20, +19,19,19,19, +18,18,18,18, +17,17,17,17, +16,16,16,16, +15,15,15,15, +14,14,14,14, +13,13,13,13, +12,12,12,12, +11,11,11,11, +10,10,10,10, +9,9,9,9, +8,8,8,8, +7,7,7,7, +6,6,6,6, +5,5,5,5, +4,4,4,4, +3,3,3,3, +2,2,2,2, +1,1,1,1 +}; + +/* LFO Phase Modulation table (verified on real YM2413) */ +static const INT8 lfo_pm_table[8*8] = { +/* FNUM2/FNUM = 0 00xxxxxx (0x0000) */ +0, 0, 0, 0, 0, 0, 0, 0, + +/* FNUM2/FNUM = 0 01xxxxxx (0x0040) */ +1, 0, 0, 0,-1, 0, 0, 0, + +/* FNUM2/FNUM = 0 10xxxxxx (0x0080) */ +2, 1, 0,-1,-2,-1, 0, 1, + +/* FNUM2/FNUM = 0 11xxxxxx (0x00C0) */ +3, 1, 0,-1,-3,-1, 0, 1, + +/* FNUM2/FNUM = 1 00xxxxxx (0x0100) */ +4, 2, 0,-2,-4,-2, 0, 2, + +/* FNUM2/FNUM = 1 01xxxxxx (0x0140) */ +5, 2, 0,-2,-5,-2, 0, 2, + +/* FNUM2/FNUM = 1 10xxxxxx (0x0180) */ +6, 3, 0,-3,-6,-3, 0, 3, + +/* FNUM2/FNUM = 1 11xxxxxx (0x01C0) */ +7, 3, 0,-3,-7,-3, 0, 3, +}; + + + + + + +/* This is not 100% perfect yet but very close */ +/* + - multi parameters are 100% correct (instruments and drums) + - LFO PM and AM enable are 100% correct + - waveform DC and DM select are 100% correct +*/ + +static const unsigned char table[19][8] = { +/* MULT MULT modTL DcDmFb AR/DR AR/DR SL/RR SL/RR */ +/* 0 1 2 3 4 5 6 7 */ + {0x49, 0x4c, 0x4c, 0x12, 0x00, 0x00, 0x00, 0x00 }, //0 + + {0x61, 0x61, 0x1e, 0x17, 0xf0, 0x78, 0x00, 0x17 }, //1 + {0x13, 0x41, 0x1e, 0x0d, 0xd7, 0xf7, 0x13, 0x13 }, //2 + {0x13, 0x01, 0x99, 0x04, 0xf2, 0xf4, 0x11, 0x23 }, //3 + {0x21, 0x61, 0x1b, 0x07, 0xaf, 0x64, 0x40, 0x27 }, //4 + +//{0x22, 0x21, 0x1e, 0x09, 0xf0, 0x76, 0x08, 0x28 }, //5 + {0x22, 0x21, 0x1e, 0x06, 0xf0, 0x75, 0x08, 0x18 }, //5 + +//{0x31, 0x22, 0x16, 0x09, 0x90, 0x7f, 0x00, 0x08 }, //6 + {0x31, 0x22, 0x16, 0x05, 0x90, 0x71, 0x00, 0x13 }, //6 + + {0x21, 0x61, 0x1d, 0x07, 0x82, 0x80, 0x10, 0x17 }, //7 + {0x23, 0x21, 0x2d, 0x16, 0xc0, 0x70, 0x07, 0x07 }, //8 + {0x61, 0x61, 0x1b, 0x06, 0x64, 0x65, 0x10, 0x17 }, //9 + +//{0x61, 0x61, 0x0c, 0x08, 0x85, 0xa0, 0x79, 0x07 }, //A + {0x61, 0x61, 0x0c, 0x18, 0x85, 0xf0, 0x70, 0x07 }, //A + + {0x23, 0x01, 0x07, 0x11, 0xf0, 0xa4, 0x00, 0x22 }, //B + {0x97, 0xc1, 0x24, 0x07, 0xff, 0xf8, 0x22, 0x12 }, //C + +//{0x61, 0x10, 0x0c, 0x08, 0xf2, 0xc4, 0x40, 0xc8 }, //D + {0x61, 0x10, 0x0c, 0x05, 0xf2, 0xf4, 0x40, 0x44 }, //D + + {0x01, 0x01, 0x55, 0x03, 0xf3, 0x92, 0xf3, 0xf3 }, //E + {0x61, 0x41, 0x89, 0x03, 0xf1, 0xf4, 0xf0, 0x13 }, //F + +/* drum instruments definitions */ +/* MULTI MULTI modTL xxx AR/DR AR/DR SL/RR SL/RR */ +/* 0 1 2 3 4 5 6 7 */ + {0x01, 0x01, 0x16, 0x00, 0xfd, 0xf8, 0x2f, 0x6d },/* BD(multi verified, modTL verified, mod env - verified(close), carr. env verifed) */ + {0x01, 0x01, 0x00, 0x00, 0xd8, 0xd8, 0xf9, 0xf8 },/* HH(multi verified), SD(multi not used) */ + {0x05, 0x01, 0x00, 0x00, 0xf8, 0xba, 0x49, 0x55 },/* TOM(multi,env verified), TOP CYM(multi verified, env verified) */ +}; + +/* lock level of common table */ +static int num_lock = 0; + +/* work table */ +#define SLOT7_1 (&chip->P_CH[7].SLOT[SLOT1]) +#define SLOT7_2 (&chip->P_CH[7].SLOT[SLOT2]) +#define SLOT8_1 (&chip->P_CH[8].SLOT[SLOT1]) +#define SLOT8_2 (&chip->P_CH[8].SLOT[SLOT2]) + + +INLINE int limit( int val, int max, int min ) +{ + if ( val > max ) + val = max; + else if ( val < min ) + val = min; + + return val; +} + + +/* advance LFO to next sample */ +INLINE void advance_lfo(YM2413 *chip) +{ + /* LFO */ + chip->lfo_am_cnt += chip->lfo_am_inc; + if (chip->lfo_am_cnt >= ((UINT32)LFO_AM_TAB_ELEMENTS<lfo_am_cnt -= ((UINT32)LFO_AM_TAB_ELEMENTS<LFO_AM = lfo_am_table[ chip->lfo_am_cnt >> LFO_SH ] >> 1; + + chip->lfo_pm_cnt += chip->lfo_pm_inc; + chip->LFO_PM = (chip->lfo_pm_cnt>>LFO_SH) & 7; +} + +/* advance to next sample */ +INLINE void advance(YM2413 *chip) +{ + OPLL_CH *CH; + OPLL_SLOT *op; + unsigned int i; + + /* Envelope Generator */ + chip->eg_timer += chip->eg_timer_add; + + while (chip->eg_timer >= chip->eg_timer_overflow) + { + chip->eg_timer -= chip->eg_timer_overflow; + + chip->eg_cnt++; + + for (i=0; i<9*2; i++) + { + CH = &chip->P_CH[i/2]; + + op = &CH->SLOT[i&1]; + + switch(op->state) + { + case EG_DMP: /* dump phase */ + /*dump phase is performed by both operators in each channel*/ + /*when CARRIER envelope gets down to zero level, + ** phases in BOTH opearators are reset (at the same time ?) + */ + if ( !(chip->eg_cnt & ((1<eg_sh_dp)-1) ) ) + { + op->volume += eg_inc[op->eg_sel_dp + ((chip->eg_cnt>>op->eg_sh_dp)&7)]; + + if ( op->volume >= MAX_ATT_INDEX ) + { + op->volume = MAX_ATT_INDEX; + op->state = EG_ATT; + /* restart Phase Generator */ + op->phase = 0; + } + } + break; + + case EG_ATT: /* attack phase */ + if ( !(chip->eg_cnt & ((1<eg_sh_ar)-1) ) ) + { + op->volume += (~op->volume * + (eg_inc[op->eg_sel_ar + ((chip->eg_cnt>>op->eg_sh_ar)&7)]) + ) >>2; + + if (op->volume <= MIN_ATT_INDEX) + { + op->volume = MIN_ATT_INDEX; + op->state = EG_DEC; + } + } + break; + + case EG_DEC: /* decay phase */ + if ( !(chip->eg_cnt & ((1<eg_sh_dr)-1) ) ) + { + op->volume += eg_inc[op->eg_sel_dr + ((chip->eg_cnt>>op->eg_sh_dr)&7)]; + + if ( op->volume >= op->sl ) + op->state = EG_SUS; + } + break; + + case EG_SUS: /* sustain phase */ + /* this is important behaviour: + one can change percusive/non-percussive modes on the fly and + the chip will remain in sustain phase - verified on real YM3812 */ + + if(op->eg_type) /* non-percussive mode (sustained tone) */ + { + /* do nothing */ + } + else /* percussive mode */ + { + /* during sustain phase chip adds Release Rate (in percussive mode) */ + if ( !(chip->eg_cnt & ((1<eg_sh_rr)-1) ) ) + { + op->volume += eg_inc[op->eg_sel_rr + ((chip->eg_cnt>>op->eg_sh_rr)&7)]; + + if ( op->volume >= MAX_ATT_INDEX ) + op->volume = MAX_ATT_INDEX; + } + /* else do nothing in sustain phase */ + } + break; + + case EG_REL: /* release phase */ + /* exclude modulators in melody channels from performing anything in this mode*/ + /* allowed are only carriers in melody mode and rhythm slots in rhythm mode */ + + /*This table shows which operators and on what conditions are allowed to perform EG_REL: + (a) - always perform EG_REL + (n) - never perform EG_REL + (r) - perform EG_REL in Rhythm mode ONLY + 0: 0 (n), 1 (a) + 1: 2 (n), 3 (a) + 2: 4 (n), 5 (a) + 3: 6 (n), 7 (a) + 4: 8 (n), 9 (a) + 5: 10(n), 11(a) + 6: 12(r), 13(a) + 7: 14(r), 15(a) + 8: 16(r), 17(a) + */ + if ( (i&1) || ((chip->rhythm&0x20) && (i>=12)) )/* exclude modulators */ + { + if(op->eg_type) /* non-percussive mode (sustained tone) */ + /*this is correct: use RR when SUS = OFF*/ + /*and use RS when SUS = ON*/ + { + if (CH->sus) + { + if ( !(chip->eg_cnt & ((1<eg_sh_rs)-1) ) ) + { + op->volume += eg_inc[op->eg_sel_rs + ((chip->eg_cnt>>op->eg_sh_rs)&7)]; + if ( op->volume >= MAX_ATT_INDEX ) + { + op->volume = MAX_ATT_INDEX; + op->state = EG_OFF; + } + } + } + else + { + if ( !(chip->eg_cnt & ((1<eg_sh_rr)-1) ) ) + { + op->volume += eg_inc[op->eg_sel_rr + ((chip->eg_cnt>>op->eg_sh_rr)&7)]; + if ( op->volume >= MAX_ATT_INDEX ) + { + op->volume = MAX_ATT_INDEX; + op->state = EG_OFF; + } + } + } + } + else /* percussive mode */ + { + if ( !(chip->eg_cnt & ((1<eg_sh_rs)-1) ) ) + { + op->volume += eg_inc[op->eg_sel_rs + ((chip->eg_cnt>>op->eg_sh_rs)&7)]; + if ( op->volume >= MAX_ATT_INDEX ) + { + op->volume = MAX_ATT_INDEX; + op->state = EG_OFF; + } + } + } + } + break; + + default: + break; + } + } + } + + for (i=0; i<9*2; i++) + { + CH = &chip->P_CH[i/2]; + op = &CH->SLOT[i&1]; + + /* Phase Generator */ + if(op->vib) + { + UINT8 block; + + unsigned int fnum_lfo = 8*((CH->block_fnum&0x01c0) >> 6); + unsigned int block_fnum = CH->block_fnum * 2; + signed int lfo_fn_table_index_offset = lfo_pm_table[chip->LFO_PM + fnum_lfo ]; + + if (lfo_fn_table_index_offset) /* LFO phase modulation active */ + { + block_fnum += lfo_fn_table_index_offset; + block = (block_fnum&0x1c00) >> 10; + op->phase += (chip->fn_tab[block_fnum&0x03ff] >> (7-block)) * op->mul; + } + else /* LFO phase modulation = zero */ + { + op->phase += op->freq; + } + } + else /* LFO phase modulation disabled for this operator */ + { + op->phase += op->freq; + } + } + + /* The Noise Generator of the YM3812 is 23-bit shift register. + * Period is equal to 2^23-2 samples. + * Register works at sampling frequency of the chip, so output + * can change on every sample. + * + * Output of the register and input to the bit 22 is: + * bit0 XOR bit14 XOR bit15 XOR bit22 + * + * Simply use bit 22 as the noise output. + */ + + chip->noise_p += chip->noise_f; + i = chip->noise_p >> FREQ_SH; /* number of events (shifts of the shift register) */ + chip->noise_p &= FREQ_MASK; + while (i) + { + /* + UINT32 j; + j = ( (chip->noise_rng) ^ (chip->noise_rng>>14) ^ (chip->noise_rng>>15) ^ (chip->noise_rng>>22) ) & 1; + chip->noise_rng = (j<<22) | (chip->noise_rng>>1); + */ + + /* + Instead of doing all the logic operations above, we + use a trick here (and use bit 0 as the noise output). + The difference is only that the noise bit changes one + step ahead. This doesn't matter since we don't know + what is real state of the noise_rng after the reset. + */ + + if (chip->noise_rng & 1) chip->noise_rng ^= 0x800302; + chip->noise_rng >>= 1; + + i--; + } +} + + +INLINE signed int op_calc(UINT32 phase, unsigned int env, signed int pm, unsigned int wave_tab) +{ + UINT32 p; + + p = (env<<5) + sin_tab[wave_tab + ((((signed int)((phase & ~FREQ_MASK) + (pm<<17))) >> FREQ_SH ) & SIN_MASK) ]; + + if (p >= TL_TAB_LEN) + return 0; + return tl_tab[p]; +} + +INLINE signed int op_calc1(UINT32 phase, unsigned int env, signed int pm, unsigned int wave_tab) +{ + UINT32 p; + INT32 i; + + i = (phase & ~FREQ_MASK) + pm; + +/*logerror("i=%08x (i>>16)&511=%8i phase=%i [pm=%08x] ",i, (i>>16)&511, phase>>FREQ_SH, pm);*/ + + p = (env<<5) + sin_tab[ wave_tab + ((i>>FREQ_SH) & SIN_MASK)]; + +/*logerror("(p&255=%i p>>8=%i) out= %i\n", p&255,p>>8, tl_tab[p&255]>>(p>>8) );*/ + + if (p >= TL_TAB_LEN) + return 0; + return tl_tab[p]; +} + + +#define volume_calc(OP) ((OP)->TLL + ((UINT32)(OP)->volume) + (chip->LFO_AM & (OP)->AMmask)) + +/* calculate output */ +INLINE void chan_calc( YM2413 *chip, OPLL_CH *CH ) +{ + OPLL_SLOT *SLOT; + unsigned int env; + signed int out; + signed int phase_modulation; /* phase modulation input (SLOT 2) */ + + + /* SLOT 1 */ + SLOT = &CH->SLOT[SLOT1]; + env = volume_calc(SLOT); + out = SLOT->op1_out[0] + SLOT->op1_out[1]; + + SLOT->op1_out[0] = SLOT->op1_out[1]; + phase_modulation = SLOT->op1_out[0]; + + SLOT->op1_out[1] = 0; + + if( env < ENV_QUIET ) + { + if (!SLOT->fb_shift) + out = 0; + SLOT->op1_out[1] = op_calc1(SLOT->phase, env, (out<fb_shift), SLOT->wavetable ); + } + + /* SLOT 2 */ + + chip->outchan=0; + + SLOT++; + env = volume_calc(SLOT); + if( env < ENV_QUIET ) + { + signed int outp = op_calc(SLOT->phase, env, phase_modulation, SLOT->wavetable); + chip->output[0] += outp; + chip->outchan = outp; + //chip->output[0] += op_calc(SLOT->phase, env, phase_modulation, SLOT->wavetable); + } +} + +/* + operators used in the rhythm sounds generation process: + + Envelope Generator: + +channel operator register number Bass High Snare Tom Top +/ slot number TL ARDR SLRR Wave Drum Hat Drum Tom Cymbal + 6 / 0 12 50 70 90 f0 + + 6 / 1 15 53 73 93 f3 + + 7 / 0 13 51 71 91 f1 + + 7 / 1 16 54 74 94 f4 + + 8 / 0 14 52 72 92 f2 + + 8 / 1 17 55 75 95 f5 + + + Phase Generator: + +channel operator register number Bass High Snare Tom Top +/ slot number MULTIPLE Drum Hat Drum Tom Cymbal + 6 / 0 12 30 + + 6 / 1 15 33 + + 7 / 0 13 31 + + + + 7 / 1 16 34 ----- n o t u s e d ----- + 8 / 0 14 32 + + 8 / 1 17 35 + + + +channel operator register number Bass High Snare Tom Top +number number BLK/FNUM2 FNUM Drum Hat Drum Tom Cymbal + 6 12,15 B6 A6 + + + 7 13,16 B7 A7 + + + + + 8 14,17 B8 A8 + + + + +*/ + +/* calculate rhythm */ + +INLINE void rhythm_calc( YM2413 *chip, OPLL_CH *CH, unsigned int noise ) +{ + OPLL_SLOT *SLOT; + signed int out; + unsigned int env; + signed int phase_modulation; /* phase modulation input (SLOT 2) */ + + + /* Bass Drum (verified on real YM3812): + - depends on the channel 6 'connect' register: + when connect = 0 it works the same as in normal (non-rhythm) mode (op1->op2->out) + when connect = 1 _only_ operator 2 is present on output (op2->out), operator 1 is ignored + - output sample always is multiplied by 2 + */ + + + /* SLOT 1 */ + SLOT = &CH[6].SLOT[SLOT1]; + env = volume_calc(SLOT); + + out = SLOT->op1_out[0] + SLOT->op1_out[1]; + SLOT->op1_out[0] = SLOT->op1_out[1]; + + phase_modulation = SLOT->op1_out[0]; + + SLOT->op1_out[1] = 0; + if( env < ENV_QUIET ) + { + if (!SLOT->fb_shift) + out = 0; + SLOT->op1_out[1] = op_calc1(SLOT->phase, env, (out<fb_shift), SLOT->wavetable ); + } + + /* SLOT 2 */ + SLOT++; + env = volume_calc(SLOT); + if( env < ENV_QUIET ) + chip->output[1] += op_calc(SLOT->phase, env, phase_modulation, SLOT->wavetable) * 2; + + + /* Phase generation is based on: */ + // HH (13) channel 7->slot 1 combined with channel 8->slot 2 (same combination as TOP CYMBAL but different output phases) + // SD (16) channel 7->slot 1 + // TOM (14) channel 8->slot 1 + // TOP (17) channel 7->slot 1 combined with channel 8->slot 2 (same combination as HIGH HAT but different output phases) + + /* Envelope generation based on: */ + // HH channel 7->slot1 + // SD channel 7->slot2 + // TOM channel 8->slot1 + // TOP channel 8->slot2 + + + /* The following formulas can be well optimized. + I leave them in direct form for now (in case I've missed something). + */ + + /* High Hat (verified on real YM3812) */ + env = volume_calc(SLOT7_1); + if( env < ENV_QUIET ) + { + /* high hat phase generation: + phase = d0 or 234 (based on frequency only) + phase = 34 or 2d0 (based on noise) + */ + + /* base frequency derived from operator 1 in channel 7 */ + unsigned char bit7 = ((SLOT7_1->phase>>FREQ_SH)>>7)&1; + unsigned char bit3 = ((SLOT7_1->phase>>FREQ_SH)>>3)&1; + unsigned char bit2 = ((SLOT7_1->phase>>FREQ_SH)>>2)&1; + + unsigned char res1 = (bit2 ^ bit7) | bit3; + + /* when res1 = 0 phase = 0x000 | 0xd0; */ + /* when res1 = 1 phase = 0x200 | (0xd0>>2); */ + UINT32 phase = res1 ? (0x200|(0xd0>>2)) : 0xd0; + + /* enable gate based on frequency of operator 2 in channel 8 */ + unsigned char bit5e= ((SLOT8_2->phase>>FREQ_SH)>>5)&1; + unsigned char bit3e= ((SLOT8_2->phase>>FREQ_SH)>>3)&1; + + unsigned char res2 = (bit3e | bit5e); + + /* when res2 = 0 pass the phase from calculation above (res1); */ + /* when res2 = 1 phase = 0x200 | (0xd0>>2); */ + if (res2) + phase = (0x200|(0xd0>>2)); + + + /* when phase & 0x200 is set and noise=1 then phase = 0x200|0xd0 */ + /* when phase & 0x200 is set and noise=0 then phase = 0x200|(0xd0>>2), ie no change */ + if (phase&0x200) + { + if (noise) + phase = 0x200|0xd0; + } + else + /* when phase & 0x200 is clear and noise=1 then phase = 0xd0>>2 */ + /* when phase & 0x200 is clear and noise=0 then phase = 0xd0, ie no change */ + { + if (noise) + phase = 0xd0>>2; + } + + chip->output[1] += op_calc(phase<wavetable) * 2; + } + + /* Snare Drum (verified on real YM3812) */ + env = volume_calc(SLOT7_2); + if( env < ENV_QUIET ) + { + /* base frequency derived from operator 1 in channel 7 */ + unsigned char bit8 = ((SLOT7_1->phase>>FREQ_SH)>>8)&1; + + /* when bit8 = 0 phase = 0x100; */ + /* when bit8 = 1 phase = 0x200; */ + UINT32 phase = bit8 ? 0x200 : 0x100; + + /* Noise bit XOR'es phase by 0x100 */ + /* when noisebit = 0 pass the phase from calculation above */ + /* when noisebit = 1 phase ^= 0x100; */ + /* in other words: phase ^= (noisebit<<8); */ + if (noise) + phase ^= 0x100; + + chip->output[1] += op_calc(phase<wavetable) * 2; + } + + /* Tom Tom (verified on real YM3812) */ + env = volume_calc(SLOT8_1); + if( env < ENV_QUIET ) + chip->output[1] += op_calc(SLOT8_1->phase, env, 0, SLOT8_1->wavetable) * 2; + + /* Top Cymbal (verified on real YM2413) */ + env = volume_calc(SLOT8_2); + if( env < ENV_QUIET ) + { + /* base frequency derived from operator 1 in channel 7 */ + unsigned char bit7 = ((SLOT7_1->phase>>FREQ_SH)>>7)&1; + unsigned char bit3 = ((SLOT7_1->phase>>FREQ_SH)>>3)&1; + unsigned char bit2 = ((SLOT7_1->phase>>FREQ_SH)>>2)&1; + + unsigned char res1 = (bit2 ^ bit7) | bit3; + + /* when res1 = 0 phase = 0x000 | 0x100; */ + /* when res1 = 1 phase = 0x200 | 0x100; */ + UINT32 phase = res1 ? 0x300 : 0x100; + + /* enable gate based on frequency of operator 2 in channel 8 */ + unsigned char bit5e= ((SLOT8_2->phase>>FREQ_SH)>>5)&1; + unsigned char bit3e= ((SLOT8_2->phase>>FREQ_SH)>>3)&1; + + unsigned char res2 = (bit3e | bit5e); + /* when res2 = 0 pass the phase from calculation above (res1); */ + /* when res2 = 1 phase = 0x200 | 0x100; */ + if (res2) + phase = 0x300; + + chip->output[1] += op_calc(phase<wavetable) * 2; + } + +} + + +/* generic table initialize */ +static int init_tables(void) +{ + signed int i,x; + signed int n; + double o,m; + + + for (x=0; x>= 4; /* 12 bits here */ + if (n&1) /* round to nearest */ + n = (n>>1)+1; + else + n = n>>1; + /* 11 bits here (rounded) */ + tl_tab[ x*2 + 0 ] = n; + tl_tab[ x*2 + 1 ] = -tl_tab[ x*2 + 0 ]; + + for (i=1; i<11; i++) + { + tl_tab[ x*2+0 + i*2*TL_RES_LEN ] = tl_tab[ x*2+0 ]>>i; + tl_tab[ x*2+1 + i*2*TL_RES_LEN ] = -tl_tab[ x*2+0 + i*2*TL_RES_LEN ]; + } + #if 0 + logerror("tl %04i", x*2); + for (i=0; i<11; i++) + logerror(", [%02i] %5i", i*2, tl_tab[ x*2 /*+1*/ + i*2*TL_RES_LEN ] ); + logerror("\n"); + #endif + } + /*logerror("ym2413.c: TL_TAB_LEN = %i elements (%i bytes)\n",TL_TAB_LEN, (int)sizeof(tl_tab));*/ + + + for (i=0; i0.0) + o = 8*log(1.0/m)/log(2.0); /* convert to 'decibels' */ + else + o = 8*log(-1.0/m)/log(2.0); /* convert to 'decibels' */ + + o = o / (ENV_STEP/4); + + n = (int)(2.0*o); + if (n&1) /* round to nearest */ + n = (n>>1)+1; + else + n = n>>1; + + /* waveform 0: standard sinus */ + sin_tab[ i ] = n*2 + (m>=0.0? 0: 1 ); + + /*logerror("ym2413.c: sin [%4i (hex=%03x)]= %4i (tl_tab value=%5i)\n", i, i, sin_tab[i], tl_tab[sin_tab[i]] );*/ + + + /* waveform 1: __ __ */ + /* / \____/ \____*/ + /* output only first half of the sinus waveform (positive one) */ + if (i & (1<<(SIN_BITS-1)) ) + sin_tab[1*SIN_LEN+i] = TL_TAB_LEN; + else + sin_tab[1*SIN_LEN+i] = sin_tab[i]; + + /*logerror("ym2413.c: sin1[%4i]= %4i (tl_tab value=%5i)\n", i, sin_tab[1*SIN_LEN+i], tl_tab[sin_tab[1*SIN_LEN+i]] );*/ + } +#if 0 + logerror("YM2413.C: ENV_QUIET= %08x (*32=%08x)\n", ENV_QUIET, ENV_QUIET*32 ); + for (i=0; isave_item(NAME(chip->instvol_r)); + device->save_item(NAME(chip->eg_cnt)); + device->save_item(NAME(chip->eg_timer)); + device->save_item(NAME(chip->eg_timer_add)); + device->save_item(NAME(chip->eg_timer_overflow)); + device->save_item(NAME(chip->rhythm)); + device->save_item(NAME(chip->lfo_am_cnt)); + device->save_item(NAME(chip->lfo_am_inc)); + device->save_item(NAME(chip->lfo_pm_cnt)); + device->save_item(NAME(chip->lfo_pm_inc)); + device->save_item(NAME(chip->noise_rng)); + device->save_item(NAME(chip->noise_p)); + device->save_item(NAME(chip->noise_f)); + device->save_item(NAME(chip->inst_tab)); + device->save_item(NAME(chip->address)); + device->save_item(NAME(chip->status)); + + for (chnum = 0; chnum < ARRAY_LENGTH(chip->P_CH); chnum++) + { + OPLL_CH *ch = &chip->P_CH[chnum]; + int slotnum; + + device->save_item(NAME(ch->block_fnum), chnum); + device->save_item(NAME(ch->fc), chnum); + device->save_item(NAME(ch->ksl_base), chnum); + device->save_item(NAME(ch->kcode), chnum); + device->save_item(NAME(ch->sus), chnum); + + for (slotnum = 0; slotnum < ARRAY_LENGTH(ch->SLOT); slotnum++) + { + OPLL_SLOT *sl = &ch->SLOT[slotnum]; + + device->save_item(NAME(sl->ar), chnum * ARRAY_LENGTH(ch->SLOT) + slotnum); + device->save_item(NAME(sl->dr), chnum * ARRAY_LENGTH(ch->SLOT) + slotnum); + device->save_item(NAME(sl->rr), chnum * ARRAY_LENGTH(ch->SLOT) + slotnum); + device->save_item(NAME(sl->KSR), chnum * ARRAY_LENGTH(ch->SLOT) + slotnum); + device->save_item(NAME(sl->ksl), chnum * ARRAY_LENGTH(ch->SLOT) + slotnum); + device->save_item(NAME(sl->ksr), chnum * ARRAY_LENGTH(ch->SLOT) + slotnum); + device->save_item(NAME(sl->mul), chnum * ARRAY_LENGTH(ch->SLOT) + slotnum); + device->save_item(NAME(sl->phase), chnum * ARRAY_LENGTH(ch->SLOT) + slotnum); + device->save_item(NAME(sl->freq), chnum * ARRAY_LENGTH(ch->SLOT) + slotnum); + device->save_item(NAME(sl->fb_shift), chnum * ARRAY_LENGTH(ch->SLOT) + slotnum); + device->save_item(NAME(sl->op1_out), chnum * ARRAY_LENGTH(ch->SLOT) + slotnum); + device->save_item(NAME(sl->eg_type), chnum * ARRAY_LENGTH(ch->SLOT) + slotnum); + device->save_item(NAME(sl->state), chnum * ARRAY_LENGTH(ch->SLOT) + slotnum); + device->save_item(NAME(sl->TL), chnum * ARRAY_LENGTH(ch->SLOT) + slotnum); + device->save_item(NAME(sl->TLL), chnum * ARRAY_LENGTH(ch->SLOT) + slotnum); + device->save_item(NAME(sl->volume), chnum * ARRAY_LENGTH(ch->SLOT) + slotnum); + device->save_item(NAME(sl->sl), chnum * ARRAY_LENGTH(ch->SLOT) + slotnum); + device->save_item(NAME(sl->eg_sh_dp), chnum * ARRAY_LENGTH(ch->SLOT) + slotnum); + device->save_item(NAME(sl->eg_sel_dp), chnum * ARRAY_LENGTH(ch->SLOT) + slotnum); + device->save_item(NAME(sl->eg_sh_ar), chnum * ARRAY_LENGTH(ch->SLOT) + slotnum); + device->save_item(NAME(sl->eg_sel_ar), chnum * ARRAY_LENGTH(ch->SLOT) + slotnum); + device->save_item(NAME(sl->eg_sh_dr), chnum * ARRAY_LENGTH(ch->SLOT) + slotnum); + device->save_item(NAME(sl->eg_sel_dr), chnum * ARRAY_LENGTH(ch->SLOT) + slotnum); + device->save_item(NAME(sl->eg_sh_rr), chnum * ARRAY_LENGTH(ch->SLOT) + slotnum); + device->save_item(NAME(sl->eg_sel_rr), chnum * ARRAY_LENGTH(ch->SLOT) + slotnum); + device->save_item(NAME(sl->eg_sh_rs), chnum * ARRAY_LENGTH(ch->SLOT) + slotnum); + device->save_item(NAME(sl->eg_sel_rs), chnum * ARRAY_LENGTH(ch->SLOT) + slotnum); + device->save_item(NAME(sl->key), chnum * ARRAY_LENGTH(ch->SLOT) + slotnum); + device->save_item(NAME(sl->AMmask), chnum * ARRAY_LENGTH(ch->SLOT) + slotnum); + device->save_item(NAME(sl->vib), chnum * ARRAY_LENGTH(ch->SLOT) + slotnum); + device->save_item(NAME(sl->wavetable), chnum * ARRAY_LENGTH(ch->SLOT) + slotnum); + } + } +} + + +static void OPLL_initalize(YM2413 *chip, device_t *device) +{ + int i; + + OPLL_init_save(chip, device); + + /* frequency base */ + chip->freqbase = (chip->rate) ? ((double)chip->clock / 72.0) / chip->rate : 0; +#if 0 + chip->rate = (double)chip->clock / 72.0; + chip->freqbase = 1.0; + logerror("freqbase=%f\n", chip->freqbase); +#endif + + + + /* make fnumber -> increment counter table */ + for( i = 0 ; i < 1024; i++ ) + { + /* OPLL (YM2413) phase increment counter = 18bit */ + + chip->fn_tab[i] = (UINT32)( (double)i * 64 * chip->freqbase * (1<<(FREQ_SH-10)) ); /* -10 because chip works with 10.10 fixed point, while we use 16.16 */ +#if 0 + logerror("ym2413.c: fn_tab[%4i] = %08x (dec=%8i)\n", + i, chip->fn_tab[i]>>6, chip->fn_tab[i]>>6 ); +#endif + } + +#if 0 + for( i=0 ; i < 16 ; i++ ) + { + logerror("ym2413.c: sl_tab[%i] = %08x\n", i, sl_tab[i] ); + } + for( i=0 ; i < 8 ; i++ ) + { + int j; + logerror("ym2413.c: ksl_tab[oct=%2i] =",i); + for (j=0; j<16; j++) + { + logerror("%08x ", ksl_tab[i*16+j] ); + } + logerror("\n"); + } +#endif + + + /* Amplitude modulation: 27 output levels (triangle waveform); 1 level takes one of: 192, 256 or 448 samples */ + /* One entry from LFO_AM_TABLE lasts for 64 samples */ + chip->lfo_am_inc = (1.0 / 64.0 ) * (1<freqbase; + + /* Vibrato: 8 output levels (triangle waveform); 1 level takes 1024 samples */ + chip->lfo_pm_inc = (1.0 / 1024.0) * (1<freqbase; + + /*logerror ("chip->lfo_am_inc = %8x ; chip->lfo_pm_inc = %8x\n", chip->lfo_am_inc, chip->lfo_pm_inc);*/ + + /* Noise generator: a step takes 1 sample */ + chip->noise_f = (1.0 / 1.0) * (1<freqbase; + /*logerror("YM2413init noise_f=%8x\n", chip->noise_f);*/ + + chip->eg_timer_add = (1<freqbase; + chip->eg_timer_overflow = ( 1 ) * (1<eg_timer_add, chip->eg_timer_overflow);*/ +} + +INLINE void KEY_ON(OPLL_SLOT *SLOT, UINT32 key_set) +{ + if( !SLOT->key ) + { + /* do NOT restart Phase Generator (verified on real YM2413)*/ + /* phase -> Dump */ + SLOT->state = EG_DMP; + } + SLOT->key |= key_set; +} + +INLINE void KEY_OFF(OPLL_SLOT *SLOT, UINT32 key_clr) +{ + if( SLOT->key ) + { + SLOT->key &= key_clr; + + if( !SLOT->key ) + { + /* phase -> Release */ + if (SLOT->state>EG_REL) + SLOT->state = EG_REL; + } + } +} + +/* update phase increment counter of operator (also update the EG rates if necessary) */ +INLINE void CALC_FCSLOT(OPLL_CH *CH,OPLL_SLOT *SLOT) +{ + int ksr; + UINT32 SLOT_rs; + UINT32 SLOT_dp; + + /* (frequency) phase increment counter */ + SLOT->freq = CH->fc * SLOT->mul; + ksr = CH->kcode >> SLOT->KSR; + + if( SLOT->ksr != ksr ) + { + SLOT->ksr = ksr; + + /* calculate envelope generator rates */ + if ((SLOT->ar + SLOT->ksr) < 16+62) + { + SLOT->eg_sh_ar = eg_rate_shift [SLOT->ar + SLOT->ksr ]; + SLOT->eg_sel_ar = eg_rate_select[SLOT->ar + SLOT->ksr ]; + } + else + { + SLOT->eg_sh_ar = 0; + SLOT->eg_sel_ar = 13*RATE_STEPS; + } + SLOT->eg_sh_dr = eg_rate_shift [SLOT->dr + SLOT->ksr ]; + SLOT->eg_sel_dr = eg_rate_select[SLOT->dr + SLOT->ksr ]; + SLOT->eg_sh_rr = eg_rate_shift [SLOT->rr + SLOT->ksr ]; + SLOT->eg_sel_rr = eg_rate_select[SLOT->rr + SLOT->ksr ]; + + } + + if (CH->sus) + SLOT_rs = 16 + (5<<2); + else + SLOT_rs = 16 + (7<<2); + + SLOT->eg_sh_rs = eg_rate_shift [SLOT_rs + SLOT->ksr ]; + SLOT->eg_sel_rs = eg_rate_select[SLOT_rs + SLOT->ksr ]; + + SLOT_dp = 16 + (13<<2); + SLOT->eg_sh_dp = eg_rate_shift [SLOT_dp + SLOT->ksr ]; + SLOT->eg_sel_dp = eg_rate_select[SLOT_dp + SLOT->ksr ]; +} + +/* set multi,am,vib,EG-TYP,KSR,mul */ +INLINE void set_mul(YM2413 *chip,int slot,int v) +{ + OPLL_CH *CH = &chip->P_CH[slot/2]; + OPLL_SLOT *SLOT = &CH->SLOT[slot&1]; + + SLOT->mul = mul_tab[v&0x0f]; + SLOT->KSR = (v&0x10) ? 0 : 2; + SLOT->eg_type = (v&0x20); + SLOT->vib = (v&0x40); + SLOT->AMmask = (v&0x80) ? ~0 : 0; + CALC_FCSLOT(CH,SLOT); +} + +/* set ksl, tl */ +INLINE void set_ksl_tl(YM2413 *chip,int chan,int v) +{ + OPLL_CH *CH = &chip->P_CH[chan]; +/* modulator */ + OPLL_SLOT *SLOT = &CH->SLOT[SLOT1]; + + SLOT->ksl = ksl_shift[v >> 6]; + SLOT->TL = (v&0x3f)<<(ENV_BITS-2-7); /* 7 bits TL (bit 6 = always 0) */ + SLOT->TLL = SLOT->TL + (CH->ksl_base>>SLOT->ksl); +} + +/* set ksl , waveforms, feedback */ +INLINE void set_ksl_wave_fb(YM2413 *chip,int chan,int v) +{ + OPLL_CH *CH = &chip->P_CH[chan]; +/* modulator */ + OPLL_SLOT *SLOT = &CH->SLOT[SLOT1]; + SLOT->wavetable = ((v&0x08)>>3)*SIN_LEN; + SLOT->fb_shift = (v&7) ? (v&7) + 8 : 0; + +/*carrier*/ + SLOT = &CH->SLOT[SLOT2]; + + SLOT->ksl = ksl_shift[v >> 6]; + SLOT->TLL = SLOT->TL + (CH->ksl_base>>SLOT->ksl); + + SLOT->wavetable = ((v&0x10)>>4)*SIN_LEN; +} + +/* set attack rate & decay rate */ +INLINE void set_ar_dr(YM2413 *chip,int slot,int v) +{ + OPLL_CH *CH = &chip->P_CH[slot/2]; + OPLL_SLOT *SLOT = &CH->SLOT[slot&1]; + + SLOT->ar = (v>>4) ? 16 + ((v>>4) <<2) : 0; + + if ((SLOT->ar + SLOT->ksr) < 16+62) + { + SLOT->eg_sh_ar = eg_rate_shift [SLOT->ar + SLOT->ksr ]; + SLOT->eg_sel_ar = eg_rate_select[SLOT->ar + SLOT->ksr ]; + } + else + { + SLOT->eg_sh_ar = 0; + SLOT->eg_sel_ar = 13*RATE_STEPS; + } + + SLOT->dr = (v&0x0f)? 16 + ((v&0x0f)<<2) : 0; + SLOT->eg_sh_dr = eg_rate_shift [SLOT->dr + SLOT->ksr ]; + SLOT->eg_sel_dr = eg_rate_select[SLOT->dr + SLOT->ksr ]; +} + +/* set sustain level & release rate */ +INLINE void set_sl_rr(YM2413 *chip,int slot,int v) +{ + OPLL_CH *CH = &chip->P_CH[slot/2]; + OPLL_SLOT *SLOT = &CH->SLOT[slot&1]; + + SLOT->sl = sl_tab[ v>>4 ]; + + SLOT->rr = (v&0x0f)? 16 + ((v&0x0f)<<2) : 0; + SLOT->eg_sh_rr = eg_rate_shift [SLOT->rr + SLOT->ksr ]; + SLOT->eg_sel_rr = eg_rate_select[SLOT->rr + SLOT->ksr ]; +} + +static void load_instrument(YM2413 *chip, UINT32 chan, UINT32 slot, UINT8* inst ) +{ + set_mul (chip, slot, inst[0]); + set_mul (chip, slot+1, inst[1]); + set_ksl_tl (chip, chan, inst[2]); + set_ksl_wave_fb (chip, chan, inst[3]); + set_ar_dr (chip, slot, inst[4]); + set_ar_dr (chip, slot+1, inst[5]); + set_sl_rr (chip, slot, inst[6]); + set_sl_rr (chip, slot+1, inst[7]); +} +static void update_instrument_zero(YM2413 *chip, UINT8 r ) +{ + UINT8* inst = &chip->inst_tab[0][0]; /* point to user instrument */ + UINT32 chan; + UINT32 chan_max; + + chan_max = 9; + if (chip->rhythm & 0x20) + chan_max=6; + + switch(r) + { + case 0: + for (chan=0; chaninstvol_r[chan]&0xf0)==0) + { + set_mul (chip, chan*2, inst[0]); + } + } + break; + case 1: + for (chan=0; chaninstvol_r[chan]&0xf0)==0) + { + set_mul (chip, chan*2+1,inst[1]); + } + } + break; + case 2: + for (chan=0; chaninstvol_r[chan]&0xf0)==0) + { + set_ksl_tl (chip, chan, inst[2]); + } + } + break; + case 3: + for (chan=0; chaninstvol_r[chan]&0xf0)==0) + { + set_ksl_wave_fb (chip, chan, inst[3]); + } + } + break; + case 4: + for (chan=0; chaninstvol_r[chan]&0xf0)==0) + { + set_ar_dr (chip, chan*2, inst[4]); + } + } + break; + case 5: + for (chan=0; chaninstvol_r[chan]&0xf0)==0) + { + set_ar_dr (chip, chan*2+1,inst[5]); + } + } + break; + case 6: + for (chan=0; chaninstvol_r[chan]&0xf0)==0) + { + set_sl_rr (chip, chan*2, inst[6]); + } + } + break; + case 7: + for (chan=0; chaninstvol_r[chan]&0xf0)==0) + { + set_sl_rr (chip, chan*2+1,inst[7]); + } + } + break; + } +} + +/* write a value v to register r on chip chip */ +static void OPLLWriteReg(YM2413 *chip, int r, int v) +{ + OPLL_CH *CH; + OPLL_SLOT *SLOT; + UINT8 *inst; + int chan; + int slot; + + /* adjust bus to 8 bits */ + r &= 0xff; + v &= 0xff; + + + if (LOG_CYM_FILE && (cymfile) && (r!=8) ) + { + fputc( (unsigned char)r, cymfile ); + fputc( (unsigned char)v, cymfile ); + } + + + switch(r&0xf0) + { + case 0x00: /* 00-0f:control */ + { + switch(r&0x0f) + { + case 0x00: /* AM/VIB/EGTYP/KSR/MULTI (modulator) */ + case 0x01: /* AM/VIB/EGTYP/KSR/MULTI (carrier) */ + case 0x02: /* Key Scale Level, Total Level (modulator) */ + case 0x03: /* Key Scale Level, carrier waveform, modulator waveform, Feedback */ + case 0x04: /* Attack, Decay (modulator) */ + case 0x05: /* Attack, Decay (carrier) */ + case 0x06: /* Sustain, Release (modulator) */ + case 0x07: /* Sustain, Release (carrier) */ + chip->inst_tab[0][r & 0x07] = v; + update_instrument_zero(chip,r&7); + break; + + case 0x0e: /* x, x, r,bd,sd,tom,tc,hh */ + { + if(v&0x20) + { + if ((chip->rhythm&0x20)==0) + /*rhythm off to on*/ + { + logerror("YM2413: Rhythm mode enable\n"); + + /* Load instrument settings for channel seven(chan=6 since we're zero based). (Bass drum) */ + chan = 6; + inst = &chip->inst_tab[16][0]; + slot = chan*2; + + load_instrument(chip, chan, slot, inst); + + /* Load instrument settings for channel eight. (High hat and snare drum) */ + chan = 7; + inst = &chip->inst_tab[17][0]; + slot = chan*2; + + load_instrument(chip, chan, slot, inst); + + CH = &chip->P_CH[chan]; + SLOT = &CH->SLOT[SLOT1]; /* modulator envelope is HH */ + SLOT->TL = ((chip->instvol_r[chan]>>4)<<2)<<(ENV_BITS-2-7); /* 7 bits TL (bit 6 = always 0) */ + SLOT->TLL = SLOT->TL + (CH->ksl_base>>SLOT->ksl); + + /* Load instrument settings for channel nine. (Tom-tom and top cymbal) */ + chan = 8; + inst = &chip->inst_tab[18][0]; + slot = chan*2; + + load_instrument(chip, chan, slot, inst); + + CH = &chip->P_CH[chan]; + SLOT = &CH->SLOT[SLOT1]; /* modulator envelope is TOM */ + SLOT->TL = ((chip->instvol_r[chan]>>4)<<2)<<(ENV_BITS-2-7); /* 7 bits TL (bit 6 = always 0) */ + SLOT->TLL = SLOT->TL + (CH->ksl_base>>SLOT->ksl); + } + /* BD key on/off */ + if(v&0x10) + { + KEY_ON (&chip->P_CH[6].SLOT[SLOT1], 2); + KEY_ON (&chip->P_CH[6].SLOT[SLOT2], 2); + } + else + { + KEY_OFF(&chip->P_CH[6].SLOT[SLOT1],~2); + KEY_OFF(&chip->P_CH[6].SLOT[SLOT2],~2); + } + /* HH key on/off */ + if(v&0x01) KEY_ON (&chip->P_CH[7].SLOT[SLOT1], 2); + else KEY_OFF(&chip->P_CH[7].SLOT[SLOT1],~2); + /* SD key on/off */ + if(v&0x08) KEY_ON (&chip->P_CH[7].SLOT[SLOT2], 2); + else KEY_OFF(&chip->P_CH[7].SLOT[SLOT2],~2); + /* TOM key on/off */ + if(v&0x04) KEY_ON (&chip->P_CH[8].SLOT[SLOT1], 2); + else KEY_OFF(&chip->P_CH[8].SLOT[SLOT1],~2); + /* TOP-CY key on/off */ + if(v&0x02) KEY_ON (&chip->P_CH[8].SLOT[SLOT2], 2); + else KEY_OFF(&chip->P_CH[8].SLOT[SLOT2],~2); + } + else + { + if (chip->rhythm&0x20) + /*rhythm on to off*/ + { + logerror("YM2413: Rhythm mode disable\n"); + /* Load instrument settings for channel seven(chan=6 since we're zero based).*/ + chan = 6; + inst = &chip->inst_tab[chip->instvol_r[chan]>>4][0]; + slot = chan*2; + + load_instrument(chip, chan, slot, inst); + + /* Load instrument settings for channel eight.*/ + chan = 7; + inst = &chip->inst_tab[chip->instvol_r[chan]>>4][0]; + slot = chan*2; + + load_instrument(chip, chan, slot, inst); + + /* Load instrument settings for channel nine.*/ + chan = 8; + inst = &chip->inst_tab[chip->instvol_r[chan]>>4][0]; + slot = chan*2; + + load_instrument(chip, chan, slot, inst); + } + /* BD key off */ + KEY_OFF(&chip->P_CH[6].SLOT[SLOT1],~2); + KEY_OFF(&chip->P_CH[6].SLOT[SLOT2],~2); + /* HH key off */ + KEY_OFF(&chip->P_CH[7].SLOT[SLOT1],~2); + /* SD key off */ + KEY_OFF(&chip->P_CH[7].SLOT[SLOT2],~2); + /* TOM key off */ + KEY_OFF(&chip->P_CH[8].SLOT[SLOT1],~2); + /* TOP-CY off */ + KEY_OFF(&chip->P_CH[8].SLOT[SLOT2],~2); + } + chip->rhythm = v&0x3f; + } + break; + } + } + break; + + case 0x10: + case 0x20: + { + int block_fnum; + + chan = r&0x0f; + + if (chan >= 9) + chan -= 9; /* verified on real YM2413 */ + + CH = &chip->P_CH[chan]; + + if(r&0x10) + { /* 10-18: FNUM 0-7 */ + block_fnum = (CH->block_fnum&0x0f00) | v; + } + else + { /* 20-28: suson, keyon, block, FNUM 8 */ + block_fnum = ((v&0x0f)<<8) | (CH->block_fnum&0xff); + + if(v&0x10) + { + KEY_ON (&CH->SLOT[SLOT1], 1); + KEY_ON (&CH->SLOT[SLOT2], 1); + } + else + { + KEY_OFF(&CH->SLOT[SLOT1],~1); + KEY_OFF(&CH->SLOT[SLOT2],~1); + } + + + if (CH->sus!=(v&0x20)) + logerror("chan=%i sus=%2x\n",chan,v&0x20); + + CH->sus = v & 0x20; + } + /* update */ + if(CH->block_fnum != block_fnum) + { + UINT8 block; + + CH->block_fnum = block_fnum; + + /* BLK 2,1,0 bits -> bits 3,2,1 of kcode, FNUM MSB -> kcode LSB */ + CH->kcode = (block_fnum&0x0f00)>>8; + + CH->ksl_base = ksl_tab[block_fnum>>5]; + + block_fnum = block_fnum * 2; + block = (block_fnum&0x1c00) >> 10; + CH->fc = chip->fn_tab[block_fnum&0x03ff] >> (7-block); + + /* refresh Total Level in both SLOTs of this channel */ + CH->SLOT[SLOT1].TLL = CH->SLOT[SLOT1].TL + (CH->ksl_base>>CH->SLOT[SLOT1].ksl); + CH->SLOT[SLOT2].TLL = CH->SLOT[SLOT2].TL + (CH->ksl_base>>CH->SLOT[SLOT2].ksl); + + /* refresh frequency counter in both SLOTs of this channel */ + CALC_FCSLOT(CH,&CH->SLOT[SLOT1]); + CALC_FCSLOT(CH,&CH->SLOT[SLOT2]); + } + } + break; + + case 0x30: /* inst 4 MSBs, VOL 4 LSBs */ + { + UINT8 old_instvol; + + chan = r&0x0f; + + if (chan >= 9) + chan -= 9; /* verified on real YM2413 */ + + old_instvol = chip->instvol_r[chan]; + chip->instvol_r[chan] = v; /* store for later use */ + + CH = &chip->P_CH[chan]; + SLOT = &CH->SLOT[SLOT2]; /* carrier */ + SLOT->TL = ((v&0x0f)<<2)<<(ENV_BITS-2-7); /* 7 bits TL (bit 6 = always 0) */ + SLOT->TLL = SLOT->TL + (CH->ksl_base>>SLOT->ksl); + + + /*check whether we are in rhythm mode and handle instrument/volume register accordingly*/ + if ((chan>=6) && (chip->rhythm&0x20)) + { + /* we're in rhythm mode*/ + + if (chan>=7) /* only for channel 7 and 8 (channel 6 is handled in usual way)*/ + { + SLOT = &CH->SLOT[SLOT1]; /* modulator envelope is HH(chan=7) or TOM(chan=8) */ + SLOT->TL = ((chip->instvol_r[chan]>>4)<<2)<<(ENV_BITS-2-7); /* 7 bits TL (bit 6 = always 0) */ + SLOT->TLL = SLOT->TL + (CH->ksl_base>>SLOT->ksl); + } + } + else + { + if ( (old_instvol&0xf0) == (v&0xf0) ) + return; + + inst = &chip->inst_tab[chip->instvol_r[chan]>>4][0]; + slot = chan*2; + + load_instrument(chip, chan, slot, inst); + + #if 0 + logerror("YM2413: chan#%02i inst=%02i: (r=%2x, v=%2x)\n",chan,v>>4,r,v); + logerror(" 0:%2x 1:%2x\n",inst[0],inst[1]); logerror(" 2:%2x 3:%2x\n",inst[2],inst[3]); + logerror(" 4:%2x 5:%2x\n",inst[4],inst[5]); logerror(" 6:%2x 7:%2x\n",inst[6],inst[7]); + #endif + } + } + break; + + default: + break; + } +} + +static TIMER_CALLBACK( cymfile_callback ) +{ + if (cymfile) + { + fputc( (unsigned char)8, cymfile ); + } +} + +/* lock/unlock for common table */ +static int OPLL_LockTable(device_t *device) +{ + num_lock++; + if(num_lock>1) return 0; + + /* first time */ + + /* allocate total level table (128kb space) */ + if( !init_tables() ) + { + num_lock--; + return -1; + } + + if (LOG_CYM_FILE) + { + cymfile = fopen("2413_.cym","wb"); + if (cymfile) + device->machine().scheduler().timer_pulse ( attotime::from_hz(110), FUNC(cymfile_callback)); /*110 Hz pulse timer*/ + else + logerror("Could not create file 2413_.cym\n"); + } + + return 0; +} + +static void OPLL_UnLockTable(void) +{ + if(num_lock) num_lock--; + if(num_lock) return; + + /* last time */ + + OPLCloseTable(); + + if (cymfile) + fclose (cymfile); + cymfile = NULL; +} + +static void OPLLResetChip(YM2413 *chip) +{ + int c,s; + int i; + + chip->eg_timer = 0; + chip->eg_cnt = 0; + + chip->noise_rng = 1; /* noise shift register */ + + + /* setup instruments table */ + for (i=0; i<19; i++) + { + for (c=0; c<8; c++) + { + chip->inst_tab[i][c] = table[i][c]; + } + } + + + /* reset with register write */ + OPLLWriteReg(chip,0x0f,0); /*test reg*/ + for(i = 0x3f ; i >= 0x10 ; i-- ) OPLLWriteReg(chip,i,0x00); + + /* reset operator parameters */ + for( c = 0 ; c < 9 ; c++ ) + { + OPLL_CH *CH = &chip->P_CH[c]; + for(s = 0 ; s < 2 ; s++ ) + { + /* wave table */ + CH->SLOT[s].wavetable = 0; + CH->SLOT[s].state = EG_OFF; + CH->SLOT[s].volume = MAX_ATT_INDEX; + } + } +} + +/* Create one of virtual YM2413 */ +/* 'clock' is chip clock in Hz */ +/* 'rate' is sampling rate */ +static YM2413 *OPLLCreate(device_t *device, int clock, int rate) +{ + YM2413 *chip; + + if (OPLL_LockTable(device) == -1) return NULL; + + /* allocate memory block */ + chip = auto_alloc_clear(device->machine(), YM2413); + + chip->device = device; + chip->clock = clock; + chip->rate = rate; + + /* init global tables */ + OPLL_initalize(chip, device); + + /* reset chip */ + OPLLResetChip(chip); + return chip; +} + +/* Destroy one of virtual YM3812 */ +static void OPLLDestroy(YM2413 *chip) +{ + OPLL_UnLockTable(); + auto_free(chip->device->machine(), chip); +} + +/* Option handlers */ + +static void OPLLSetUpdateHandler(YM2413 *chip,OPLL_UPDATEHANDLER UpdateHandler,void * param) +{ + chip->UpdateHandler = UpdateHandler; + chip->UpdateParam = param; +} + +/* YM3812 I/O interface */ +static void OPLLWrite(YM2413 *chip,int a,int v) +{ + if( !(a&1) ) + { /* address port */ + chip->address = v & 0xff; + } + else + { /* data port */ + if(chip->UpdateHandler) chip->UpdateHandler(chip->UpdateParam,0); + OPLLWriteReg(chip,chip->address,v); + } +} + +static unsigned char OPLLRead(YM2413 *chip,int a) +{ + if( !(a&1) ) + { + /* status port */ + return chip->status; + } + return 0xff; +} + + + + + +void * ym2413_init(device_t *device, int clock, int rate) +{ + /* emulator create */ + return OPLLCreate(device, clock, rate); +} + +void ym2413_shutdown(void *chip) +{ + YM2413 *OPLL = (YM2413 *)chip; + + /* emulator shutdown */ + OPLLDestroy(OPLL); +} + +void ym2413_reset_chip(void *chip) +{ + YM2413 *OPLL = (YM2413 *)chip; + OPLLResetChip(OPLL); +} + +void ym2413_write(void *chip, int a, int v) +{ + YM2413 *OPLL = (YM2413 *)chip; + OPLLWrite(OPLL, a, v); +} + +unsigned char ym2413_read(void *chip, int a) +{ + YM2413 *OPLL = (YM2413 *)chip; + return OPLLRead(OPLL, a) & 0x03 ; +} + +void ym2413_set_update_handler(void *chip,OPLL_UPDATEHANDLER UpdateHandler,void *param) +{ + YM2413 *OPLL = (YM2413 *)chip; + OPLLSetUpdateHandler(OPLL, UpdateHandler, param); +} + + +/* +** Generate samples for one of the YM2413's +** +** 'which' is the virtual YM2413 number +** '*buffer' is the output buffer pointer +** 'length' is the number of samples that should be generated +*/ +void ym2413_update_one(void *_chip, SAMP **buffers, int length) +{ + YM2413 *chip = (YM2413 *)_chip; + UINT8 rhythm = chip->rhythm&0x20; + SAMP *bufMO = buffers[0]; + SAMP *bufRO = buffers[1]; + + int i; + + for( i=0; i < length ; i++ ) + { + int mo,ro; + + chip->output[0] = 0; + chip->output[1] = 0; + + advance_lfo(chip); + + /* FM part */ + chan_calc(chip, &chip->P_CH[0]); +//SAVE_SEPARATE_CHANNEL(0); + chan_calc(chip, &chip->P_CH[1]); + chan_calc(chip, &chip->P_CH[2]); + chan_calc(chip, &chip->P_CH[3]); + chan_calc(chip, &chip->P_CH[4]); + chan_calc(chip, &chip->P_CH[5]); + + if(!rhythm) + { + chan_calc(chip, &chip->P_CH[6]); + chan_calc(chip, &chip->P_CH[7]); + chan_calc(chip, &chip->P_CH[8]); + } + else /* Rhythm part */ + { + rhythm_calc(chip, &chip->P_CH[0], (chip->noise_rng>>0)&1 ); + } + + mo = chip->output[0]; + ro = chip->output[1]; + + mo >>= FINAL_SH; + ro >>= FINAL_SH; + + /* limit check */ + mo = limit( mo , MAXOUT, MINOUT ); + ro = limit( ro , MAXOUT, MINOUT ); + + #ifdef SAVE_SAMPLE + if (which==0) + { + SAVE_ALL_CHANNELS + } + #endif + + /* store to sound buffer */ + bufMO[i] = mo; + bufRO[i] = ro; + + advance(chip); + } + +} diff --git a/src/devices/sound/ym2413.h b/src/devices/sound/ym2413.h new file mode 100644 index 00000000000..eb9441bec5a --- /dev/null +++ b/src/devices/sound/ym2413.h @@ -0,0 +1,45 @@ +// license:??? +// copyright-holders:Jarek Burczynski +#pragma once + +#ifndef __YM2413_H__ +#define __YM2413_H__ + +/* select output bits size of output : 8 or 16 */ +#define SAMPLE_BITS 16 + +/* compiler dependence */ +#ifndef __OSDCOMM_H__ +#define __OSDCOMM_H__ +typedef unsigned char UINT8; /* unsigned 8bit */ +typedef unsigned short UINT16; /* unsigned 16bit */ +typedef unsigned int UINT32; /* unsigned 32bit */ +typedef signed char INT8; /* signed 8bit */ +typedef signed short INT16; /* signed 16bit */ +typedef signed int INT32; /* signed 32bit */ +#endif + +typedef stream_sample_t SAMP; +/* +#if (SAMPLE_BITS==16) +typedef INT16 SAMP; +#endif +#if (SAMPLE_BITS==8) +typedef INT8 SAMP; +#endif +*/ + + + +void *ym2413_init(device_t *device, int clock, int rate); +void ym2413_shutdown(void *chip); +void ym2413_reset_chip(void *chip); +void ym2413_write(void *chip, int a, int v); +unsigned char ym2413_read(void *chip, int a); +void ym2413_update_one(void *chip, SAMP **buffers, int length); + +typedef void (*OPLL_UPDATEHANDLER)(void *param,int min_interval_us); + +void ym2413_set_update_handler(void *chip, OPLL_UPDATEHANDLER UpdateHandler, void *param); + +#endif /*__YM2413_H__*/ diff --git a/src/devices/sound/ymdeltat.c b/src/devices/sound/ymdeltat.c new file mode 100644 index 00000000000..30600b2d02b --- /dev/null +++ b/src/devices/sound/ymdeltat.c @@ -0,0 +1,650 @@ +// license:??? +// copyright-holders:Jarek Burczynski +/* +** +** File: ymdeltat.c +** +** YAMAHA DELTA-T adpcm sound emulation subroutine +** used by fmopl.c (Y8950) and fm.c (YM2608 and YM2610/B) +** +** Base program is YM2610 emulator by Hiromitsu Shioya. +** Written by Tatsuyuki Satoh +** Improvements by Jarek Burczynski (bujar at mame dot net) +** +** +** History: +** +** 03-08-2003 Jarek Burczynski: +** - fixed BRDY flag implementation. +** +** 24-07-2003 Jarek Burczynski, Frits Hilderink: +** - fixed delault value for control2 in YM_DELTAT_ADPCM_Reset +** +** 22-07-2003 Jarek Burczynski, Frits Hilderink: +** - fixed external memory support +** +** 15-06-2003 Jarek Burczynski: +** - implemented CPU -> AUDIO ADPCM synthesis (via writes to the ADPCM data reg $08) +** - implemented support for the Limit address register +** - supported two bits from the control register 2 ($01): RAM TYPE (x1 bit/x8 bit), ROM/RAM +** - implemented external memory access (read/write) via the ADPCM data reg reads/writes +** Thanks go to Frits Hilderink for the example code. +** +** 14-06-2003 Jarek Burczynski: +** - various fixes to enable proper support for status register flags: BSRDY, PCM BSY, ZERO +** - modified EOS handling +** +** 05-04-2003 Jarek Burczynski: +** - implemented partial support for external/processor memory on sample replay +** +** 01-12-2002 Jarek Burczynski: +** - fixed first missing sound in gigandes thanks to previous fix (interpolator) by ElSemi +** - renamed/removed some YM_DELTAT struct fields +** +** 28-12-2001 Acho A. Tang +** - added EOS status report on ADPCM playback. +** +** 05-08-2001 Jarek Burczynski: +** - now_step is initialized with 0 at the start of play. +** +** 12-06-2001 Jarek Burczynski: +** - corrected end of sample bug in YM_DELTAT_ADPCM_CALC. +** Checked on real YM2610 chip - address register is 24 bits wide. +** Thanks go to Stefan Jokisch (stefan.jokisch@gmx.de) for tracking down the problem. +** +** TO DO: +** Check size of the address register on the other chips.... +** +** Version 0.72 +** +** sound chips that have this unit: +** YM2608 OPNA +** YM2610/B OPNB +** Y8950 MSX AUDIO +** +*/ + +#include "emu.h" +#include "ymdeltat.h" + +#define YM_DELTAT_DELTA_MAX (24576) +#define YM_DELTAT_DELTA_MIN (127) +#define YM_DELTAT_DELTA_DEF (127) + +#define YM_DELTAT_DECODE_RANGE 32768 +#define YM_DELTAT_DECODE_MIN (-(YM_DELTAT_DECODE_RANGE)) +#define YM_DELTAT_DECODE_MAX ((YM_DELTAT_DECODE_RANGE)-1) + + +/* Forecast to next Forecast (rate = *8) */ +/* 1/8 , 3/8 , 5/8 , 7/8 , 9/8 , 11/8 , 13/8 , 15/8 */ +static const INT32 ym_deltat_decode_tableB1[16] = { + 1, 3, 5, 7, 9, 11, 13, 15, + -1, -3, -5, -7, -9, -11, -13, -15, +}; +/* delta to next delta (rate= *64) */ +/* 0.9 , 0.9 , 0.9 , 0.9 , 1.2 , 1.6 , 2.0 , 2.4 */ +static const INT32 ym_deltat_decode_tableB2[16] = { + 57, 57, 57, 57, 77, 102, 128, 153, + 57, 57, 57, 57, 77, 102, 128, 153 +}; + +#if 0 +void YM_DELTAT_BRDY_callback(YM_DELTAT *DELTAT) +{ + logerror("BRDY_callback reached (flag set) !\n"); + + /* set BRDY bit in status register */ + if(DELTAT->status_set_handler) + if(DELTAT->status_change_BRDY_bit) + (DELTAT->status_set_handler)(DELTAT->status_change_which_chip, DELTAT->status_change_BRDY_bit); +} +#endif + +UINT8 YM_DELTAT_ADPCM_Read(YM_DELTAT *DELTAT) +{ + UINT8 v = 0; + + /* external memory read */ + if ( (DELTAT->portstate & 0xe0)==0x20 ) + { + /* two dummy reads */ + if (DELTAT->memread) + { + DELTAT->now_addr = DELTAT->start << 1; + DELTAT->memread--; + return 0; + } + + + if ( DELTAT->now_addr != (DELTAT->end<<1) ) + { + v = DELTAT->memory[DELTAT->now_addr>>1]; + + /*logerror("YM Delta-T memory read $%08x, v=$%02x\n", DELTAT->now_addr >> 1, v);*/ + + DELTAT->now_addr+=2; /* two nibbles at a time */ + + /* reset BRDY bit in status register, which means we are reading the memory now */ + if(DELTAT->status_reset_handler) + if(DELTAT->status_change_BRDY_bit) + (DELTAT->status_reset_handler)(DELTAT->status_change_which_chip, DELTAT->status_change_BRDY_bit); + + /* setup a timer that will callback us in 10 master clock cycles for Y8950 + * in the callback set the BRDY flag to 1 , which means we have another data ready. + * For now, we don't really do this; we simply reset and set the flag in zero time, so that the IRQ will work. + */ + /* set BRDY bit in status register */ + if(DELTAT->status_set_handler) + if(DELTAT->status_change_BRDY_bit) + (DELTAT->status_set_handler)(DELTAT->status_change_which_chip, DELTAT->status_change_BRDY_bit); + } + else + { + /* set EOS bit in status register */ + if(DELTAT->status_set_handler) + if(DELTAT->status_change_EOS_bit) + (DELTAT->status_set_handler)(DELTAT->status_change_which_chip, DELTAT->status_change_EOS_bit); + } + } + + return v; +} + + +/* 0-DRAM x1, 1-ROM, 2-DRAM x8, 3-ROM (3 is bad setting - not allowed by the manual) */ +static const UINT8 dram_rightshift[4]={3,0,0,0}; + +/* DELTA-T ADPCM write register */ +void YM_DELTAT_ADPCM_Write(YM_DELTAT *DELTAT,int r,int v) +{ + if(r>=0x10) return; + DELTAT->reg[r] = v; /* stock data */ + + switch( r ) + { + case 0x00: +/* +START: + Accessing *external* memory is started when START bit (D7) is set to "1", so + you must set all conditions needed for recording/playback before starting. + If you access *CPU-managed* memory, recording/playback starts after + read/write of ADPCM data register $08. + +REC: + 0 = ADPCM synthesis (playback) + 1 = ADPCM analysis (record) + +MEMDATA: + 0 = processor (*CPU-managed*) memory (means: using register $08) + 1 = external memory (using start/end/limit registers to access memory: RAM or ROM) + + +SPOFF: + controls output pin that should disable the speaker while ADPCM analysis + +RESET and REPEAT only work with external memory. + + +some examples: +value: START, REC, MEMDAT, REPEAT, SPOFF, x,x,RESET meaning: + C8 1 1 0 0 1 0 0 0 Analysis (recording) from AUDIO to CPU (to reg $08), sample rate in PRESCALER register + E8 1 1 1 0 1 0 0 0 Analysis (recording) from AUDIO to EXT.MEMORY, sample rate in PRESCALER register + 80 1 0 0 0 0 0 0 0 Synthesis (playing) from CPU (from reg $08) to AUDIO,sample rate in DELTA-N register + a0 1 0 1 0 0 0 0 0 Synthesis (playing) from EXT.MEMORY to AUDIO, sample rate in DELTA-N register + + 60 0 1 1 0 0 0 0 0 External memory write via ADPCM data register $08 + 20 0 0 1 0 0 0 0 0 External memory read via ADPCM data register $08 + +*/ + /* handle emulation mode */ + if(DELTAT->emulation_mode == YM_DELTAT_EMULATION_MODE_YM2610) + { + v |= 0x20; /* YM2610 always uses external memory and doesn't even have memory flag bit. */ + } + + DELTAT->portstate = v & (0x80|0x40|0x20|0x10|0x01); /* start, rec, memory mode, repeat flag copy, reset(bit0) */ + + if( DELTAT->portstate&0x80 )/* START,REC,MEMDATA,REPEAT,SPOFF,--,--,RESET */ + { + /* set PCM BUSY bit */ + DELTAT->PCM_BSY = 1; + + /* start ADPCM */ + DELTAT->now_step = 0; + DELTAT->acc = 0; + DELTAT->prev_acc = 0; + DELTAT->adpcml = 0; + DELTAT->adpcmd = YM_DELTAT_DELTA_DEF; + DELTAT->now_data = 0; + + } + + if( DELTAT->portstate&0x20 ) /* do we access external memory? */ + { + DELTAT->now_addr = DELTAT->start << 1; + DELTAT->memread = 2; /* two dummy reads needed before accesing external memory via register $08*/ + + /* if yes, then let's check if ADPCM memory is mapped and big enough */ + if(DELTAT->memory == 0) + { + logerror("YM Delta-T ADPCM rom not mapped\n"); + DELTAT->portstate = 0x00; + DELTAT->PCM_BSY = 0; + } + else + { + if( DELTAT->end >= DELTAT->memory_size ) /* Check End in Range */ + { + logerror("YM Delta-T ADPCM end out of range: $%08x\n", DELTAT->end); + DELTAT->end = DELTAT->memory_size - 1; + } + if( DELTAT->start >= DELTAT->memory_size ) /* Check Start in Range */ + { + logerror("YM Delta-T ADPCM start out of range: $%08x\n", DELTAT->start); + DELTAT->portstate = 0x00; + DELTAT->PCM_BSY = 0; + } + } + } + else /* we access CPU memory (ADPCM data register $08) so we only reset now_addr here */ + { + DELTAT->now_addr = 0; + } + + if( DELTAT->portstate&0x01 ) + { + DELTAT->portstate = 0x00; + + /* clear PCM BUSY bit (in status register) */ + DELTAT->PCM_BSY = 0; + + /* set BRDY flag */ + if(DELTAT->status_set_handler) + if(DELTAT->status_change_BRDY_bit) + (DELTAT->status_set_handler)(DELTAT->status_change_which_chip, DELTAT->status_change_BRDY_bit); + } + break; + case 0x01: /* L,R,-,-,SAMPLE,DA/AD,RAMTYPE,ROM */ + /* handle emulation mode */ + if(DELTAT->emulation_mode == YM_DELTAT_EMULATION_MODE_YM2610) + { + v |= 0x01; /* YM2610 always uses ROM as an external memory and doesn't tave ROM/RAM memory flag bit. */ + } + + DELTAT->pan = &DELTAT->output_pointer[(v>>6)&0x03]; + if ((DELTAT->control2 & 3) != (v & 3)) + { + /*0-DRAM x1, 1-ROM, 2-DRAM x8, 3-ROM (3 is bad setting - not allowed by the manual) */ + if (DELTAT->DRAMportshift != dram_rightshift[v&3]) + { + DELTAT->DRAMportshift = dram_rightshift[v&3]; + + /* final shift value depends on chip type and memory type selected: + 8 for YM2610 (ROM only), + 5 for ROM for Y8950 and YM2608, + 5 for x8bit DRAMs for Y8950 and YM2608, + 2 for x1bit DRAMs for Y8950 and YM2608. + */ + + /* refresh addresses */ + DELTAT->start = (DELTAT->reg[0x3]*0x0100 | DELTAT->reg[0x2]) << (DELTAT->portshift - DELTAT->DRAMportshift); + DELTAT->end = (DELTAT->reg[0x5]*0x0100 | DELTAT->reg[0x4]) << (DELTAT->portshift - DELTAT->DRAMportshift); + DELTAT->end += (1 << (DELTAT->portshift-DELTAT->DRAMportshift) ) - 1; + DELTAT->limit = (DELTAT->reg[0xd]*0x0100 | DELTAT->reg[0xc]) << (DELTAT->portshift - DELTAT->DRAMportshift); + } + } + DELTAT->control2 = v; + break; + case 0x02: /* Start Address L */ + case 0x03: /* Start Address H */ + DELTAT->start = (DELTAT->reg[0x3]*0x0100 | DELTAT->reg[0x2]) << (DELTAT->portshift - DELTAT->DRAMportshift); + /*logerror("DELTAT start: 02=%2x 03=%2x addr=%8x\n",DELTAT->reg[0x2], DELTAT->reg[0x3],DELTAT->start );*/ + break; + case 0x04: /* Stop Address L */ + case 0x05: /* Stop Address H */ + DELTAT->end = (DELTAT->reg[0x5]*0x0100 | DELTAT->reg[0x4]) << (DELTAT->portshift - DELTAT->DRAMportshift); + DELTAT->end += (1 << (DELTAT->portshift-DELTAT->DRAMportshift) ) - 1; + /*logerror("DELTAT end : 04=%2x 05=%2x addr=%8x\n",DELTAT->reg[0x4], DELTAT->reg[0x5],DELTAT->end );*/ + break; + case 0x06: /* Prescale L (ADPCM and Record frq) */ + case 0x07: /* Prescale H */ + break; + case 0x08: /* ADPCM data */ + +/* +some examples: +value: START, REC, MEMDAT, REPEAT, SPOFF, x,x,RESET meaning: + C8 1 1 0 0 1 0 0 0 Analysis (recording) from AUDIO to CPU (to reg $08), sample rate in PRESCALER register + E8 1 1 1 0 1 0 0 0 Analysis (recording) from AUDIO to EXT.MEMORY, sample rate in PRESCALER register + 80 1 0 0 0 0 0 0 0 Synthesis (playing) from CPU (from reg $08) to AUDIO,sample rate in DELTA-N register + a0 1 0 1 0 0 0 0 0 Synthesis (playing) from EXT.MEMORY to AUDIO, sample rate in DELTA-N register + + 60 0 1 1 0 0 0 0 0 External memory write via ADPCM data register $08 + 20 0 0 1 0 0 0 0 0 External memory read via ADPCM data register $08 + +*/ + + /* external memory write */ + if ( (DELTAT->portstate & 0xe0)==0x60 ) + { + if (DELTAT->memread) + { + DELTAT->now_addr = DELTAT->start << 1; + DELTAT->memread = 0; + } + + /*logerror("YM Delta-T memory write $%08x, v=$%02x\n", DELTAT->now_addr >> 1, v);*/ + + if ( DELTAT->now_addr != (DELTAT->end<<1) ) + { + DELTAT->memory[DELTAT->now_addr>>1] = v; + DELTAT->now_addr+=2; /* two nibbles at a time */ + + /* reset BRDY bit in status register, which means we are processing the write */ + if(DELTAT->status_reset_handler) + if(DELTAT->status_change_BRDY_bit) + (DELTAT->status_reset_handler)(DELTAT->status_change_which_chip, DELTAT->status_change_BRDY_bit); + + /* setup a timer that will callback us in 10 master clock cycles for Y8950 + * in the callback set the BRDY flag to 1 , which means we have written the data. + * For now, we don't really do this; we simply reset and set the flag in zero time, so that the IRQ will work. + */ + /* set BRDY bit in status register */ + if(DELTAT->status_set_handler) + if(DELTAT->status_change_BRDY_bit) + (DELTAT->status_set_handler)(DELTAT->status_change_which_chip, DELTAT->status_change_BRDY_bit); + + } + else + { + /* set EOS bit in status register */ + if(DELTAT->status_set_handler) + if(DELTAT->status_change_EOS_bit) + (DELTAT->status_set_handler)(DELTAT->status_change_which_chip, DELTAT->status_change_EOS_bit); + } + + return; + } + + /* ADPCM synthesis from CPU */ + if ( (DELTAT->portstate & 0xe0)==0x80 ) + { + DELTAT->CPU_data = v; + + /* Reset BRDY bit in status register, which means we are full of data */ + if(DELTAT->status_reset_handler) + if(DELTAT->status_change_BRDY_bit) + (DELTAT->status_reset_handler)(DELTAT->status_change_which_chip, DELTAT->status_change_BRDY_bit); + return; + } + + break; + case 0x09: /* DELTA-N L (ADPCM Playback Prescaler) */ + case 0x0a: /* DELTA-N H */ + DELTAT->delta = (DELTAT->reg[0xa]*0x0100 | DELTAT->reg[0x9]); + DELTAT->step = (UINT32)( (double)(DELTAT->delta /* *(1<<(YM_DELTAT_SHIFT-16)) */ ) * (DELTAT->freqbase) ); + /*logerror("DELTAT deltan:09=%2x 0a=%2x\n",DELTAT->reg[0x9], DELTAT->reg[0xa]);*/ + break; + case 0x0b: /* Output level control (volume, linear) */ + { + INT32 oldvol = DELTAT->volume; + DELTAT->volume = (v&0xff) * (DELTAT->output_range/256) / YM_DELTAT_DECODE_RANGE; +/* v * ((1<<16)>>8) >> 15; +* thus: v * (1<<8) >> 15; +* thus: output_range must be (1 << (15+8)) at least +* v * ((1<<23)>>8) >> 15; +* v * (1<<15) >> 15; +*/ + /*logerror("DELTAT vol = %2x\n",v&0xff);*/ + if( oldvol != 0 ) + { + DELTAT->adpcml = (int)((double)DELTAT->adpcml / (double)oldvol * (double)DELTAT->volume); + } + } + break; + case 0x0c: /* Limit Address L */ + case 0x0d: /* Limit Address H */ + DELTAT->limit = (DELTAT->reg[0xd]*0x0100 | DELTAT->reg[0xc]) << (DELTAT->portshift - DELTAT->DRAMportshift); + /*logerror("DELTAT limit: 0c=%2x 0d=%2x addr=%8x\n",DELTAT->reg[0xc], DELTAT->reg[0xd],DELTAT->limit );*/ + break; + } +} + +void YM_DELTAT_ADPCM_Reset(YM_DELTAT *DELTAT,int pan,int emulation_mode) +{ + DELTAT->now_addr = 0; + DELTAT->now_step = 0; + DELTAT->step = 0; + DELTAT->start = 0; + DELTAT->end = 0; + DELTAT->limit = ~0; /* this way YM2610 and Y8950 (both of which don't have limit address reg) will still work */ + DELTAT->volume = 0; + DELTAT->pan = &DELTAT->output_pointer[pan]; + DELTAT->acc = 0; + DELTAT->prev_acc = 0; + DELTAT->adpcmd = 127; + DELTAT->adpcml = 0; + DELTAT->emulation_mode = (UINT8)emulation_mode; + DELTAT->portstate = (emulation_mode == YM_DELTAT_EMULATION_MODE_YM2610) ? 0x20 : 0; + DELTAT->control2 = (emulation_mode == YM_DELTAT_EMULATION_MODE_YM2610) ? 0x01 : 0; /* default setting depends on the emulation mode. MSX demo called "facdemo_4" doesn't setup control2 register at all and still works */ + DELTAT->DRAMportshift = dram_rightshift[DELTAT->control2 & 3]; + + /* The flag mask register disables the BRDY after the reset, however + ** as soon as the mask is enabled the flag needs to be set. */ + + /* set BRDY bit in status register */ + if(DELTAT->status_set_handler) + if(DELTAT->status_change_BRDY_bit) + (DELTAT->status_set_handler)(DELTAT->status_change_which_chip, DELTAT->status_change_BRDY_bit); +} + +void YM_DELTAT_postload(YM_DELTAT *DELTAT,UINT8 *regs) +{ + int r; + + /* to keep adpcml */ + DELTAT->volume = 0; + /* update */ + for(r=1;r<16;r++) + YM_DELTAT_ADPCM_Write(DELTAT,r,regs[r]); + DELTAT->reg[0] = regs[0]; + + /* current rom data */ + if (DELTAT->memory) + DELTAT->now_data = *(DELTAT->memory + (DELTAT->now_addr>>1) ); + +} +void YM_DELTAT_savestate(device_t *device,YM_DELTAT *DELTAT) +{ +#ifdef __SAVE_H__ + device->save_item(NAME(DELTAT->portstate)); + device->save_item(NAME(DELTAT->now_addr)); + device->save_item(NAME(DELTAT->now_step)); + device->save_item(NAME(DELTAT->acc)); + device->save_item(NAME(DELTAT->prev_acc)); + device->save_item(NAME(DELTAT->adpcmd)); + device->save_item(NAME(DELTAT->adpcml)); +#endif +} + + +#define YM_DELTAT_Limit(val,max,min) \ +{ \ + if ( val > max ) val = max; \ + else if ( val < min ) val = min; \ +} + +INLINE void YM_DELTAT_synthesis_from_external_memory(YM_DELTAT *DELTAT) +{ + UINT32 step; + int data; + + DELTAT->now_step += DELTAT->step; + if ( DELTAT->now_step >= (1<now_step >> YM_DELTAT_SHIFT; + DELTAT->now_step &= (1<now_addr == (DELTAT->limit<<1) ) + DELTAT->now_addr = 0; + + if ( DELTAT->now_addr == (DELTAT->end<<1) ) { /* 12-06-2001 JB: corrected comparison. Was > instead of == */ + if( DELTAT->portstate&0x10 ){ + /* repeat start */ + DELTAT->now_addr = DELTAT->start<<1; + DELTAT->acc = 0; + DELTAT->adpcmd = YM_DELTAT_DELTA_DEF; + DELTAT->prev_acc = 0; + }else{ + /* set EOS bit in status register */ + if(DELTAT->status_set_handler) + if(DELTAT->status_change_EOS_bit) + (DELTAT->status_set_handler)(DELTAT->status_change_which_chip, DELTAT->status_change_EOS_bit); + + /* clear PCM BUSY bit (reflected in status register) */ + DELTAT->PCM_BSY = 0; + + DELTAT->portstate = 0; + DELTAT->adpcml = 0; + DELTAT->prev_acc = 0; + return; + } + } + + if( DELTAT->now_addr&1 ) data = DELTAT->now_data & 0x0f; + else + { + DELTAT->now_data = *(DELTAT->memory + (DELTAT->now_addr>>1)); + data = DELTAT->now_data >> 4; + } + + DELTAT->now_addr++; + /* 12-06-2001 JB: */ + /* YM2610 address register is 24 bits wide.*/ + /* The "+1" is there because we use 1 bit more for nibble calculations.*/ + /* WARNING: */ + /* Side effect: we should take the size of the mapped ROM into account */ + DELTAT->now_addr &= ( (1<<(24+1))-1); + + /* store accumulator value */ + DELTAT->prev_acc = DELTAT->acc; + + /* Forecast to next Forecast */ + DELTAT->acc += (ym_deltat_decode_tableB1[data] * DELTAT->adpcmd / 8); + YM_DELTAT_Limit(DELTAT->acc,YM_DELTAT_DECODE_MAX, YM_DELTAT_DECODE_MIN); + + /* delta to next delta */ + DELTAT->adpcmd = (DELTAT->adpcmd * ym_deltat_decode_tableB2[data] ) / 64; + YM_DELTAT_Limit(DELTAT->adpcmd,YM_DELTAT_DELTA_MAX, YM_DELTAT_DELTA_MIN ); + + /* ElSemi: Fix interpolator. */ + /*DELTAT->prev_acc = prev_acc + ((DELTAT->acc - prev_acc) / 2 );*/ + + }while(--step); + + } + + /* ElSemi: Fix interpolator. */ + DELTAT->adpcml = DELTAT->prev_acc * (int)((1<now_step); + DELTAT->adpcml += (DELTAT->acc * (int)DELTAT->now_step); + DELTAT->adpcml = (DELTAT->adpcml>>YM_DELTAT_SHIFT) * (int)DELTAT->volume; + + /* output for work of output channels (outd[OPNxxxx])*/ + *(DELTAT->pan) += DELTAT->adpcml; +} + + + +INLINE void YM_DELTAT_synthesis_from_CPU_memory(YM_DELTAT *DELTAT) +{ + UINT32 step; + int data; + + DELTAT->now_step += DELTAT->step; + if ( DELTAT->now_step >= (1<now_step >> YM_DELTAT_SHIFT; + DELTAT->now_step &= (1<now_addr&1 ) + { + data = DELTAT->now_data & 0x0f; + + DELTAT->now_data = DELTAT->CPU_data; + + /* after we used CPU_data, we set BRDY bit in status register, + * which means we are ready to accept another byte of data */ + if(DELTAT->status_set_handler) + if(DELTAT->status_change_BRDY_bit) + (DELTAT->status_set_handler)(DELTAT->status_change_which_chip, DELTAT->status_change_BRDY_bit); + } + else + { + data = DELTAT->now_data >> 4; + } + + DELTAT->now_addr++; + + /* store accumulator value */ + DELTAT->prev_acc = DELTAT->acc; + + /* Forecast to next Forecast */ + DELTAT->acc += (ym_deltat_decode_tableB1[data] * DELTAT->adpcmd / 8); + YM_DELTAT_Limit(DELTAT->acc,YM_DELTAT_DECODE_MAX, YM_DELTAT_DECODE_MIN); + + /* delta to next delta */ + DELTAT->adpcmd = (DELTAT->adpcmd * ym_deltat_decode_tableB2[data] ) / 64; + YM_DELTAT_Limit(DELTAT->adpcmd,YM_DELTAT_DELTA_MAX, YM_DELTAT_DELTA_MIN ); + + + }while(--step); + + } + + /* ElSemi: Fix interpolator. */ + DELTAT->adpcml = DELTAT->prev_acc * (int)((1<now_step); + DELTAT->adpcml += (DELTAT->acc * (int)DELTAT->now_step); + DELTAT->adpcml = (DELTAT->adpcml>>YM_DELTAT_SHIFT) * (int)DELTAT->volume; + + /* output for work of output channels (outd[OPNxxxx])*/ + *(DELTAT->pan) += DELTAT->adpcml; +} + + + +/* ADPCM B (Delta-T control type) */ +void YM_DELTAT_ADPCM_CALC(YM_DELTAT *DELTAT) +{ +/* +some examples: +value: START, REC, MEMDAT, REPEAT, SPOFF, x,x,RESET meaning: + 80 1 0 0 0 0 0 0 0 Synthesis (playing) from CPU (from reg $08) to AUDIO,sample rate in DELTA-N register + a0 1 0 1 0 0 0 0 0 Synthesis (playing) from EXT.MEMORY to AUDIO, sample rate in DELTA-N register + C8 1 1 0 0 1 0 0 0 Analysis (recording) from AUDIO to CPU (to reg $08), sample rate in PRESCALER register + E8 1 1 1 0 1 0 0 0 Analysis (recording) from AUDIO to EXT.MEMORY, sample rate in PRESCALER register + + 60 0 1 1 0 0 0 0 0 External memory write via ADPCM data register $08 + 20 0 0 1 0 0 0 0 0 External memory read via ADPCM data register $08 + +*/ + + if ( (DELTAT->portstate & 0xe0)==0xa0 ) + { + YM_DELTAT_synthesis_from_external_memory(DELTAT); + return; + } + + if ( (DELTAT->portstate & 0xe0)==0x80 ) + { + /* ADPCM synthesis from CPU-managed memory (from reg $08) */ + YM_DELTAT_synthesis_from_CPU_memory(DELTAT); /* change output based on data in ADPCM data reg ($08) */ + return; + } + +//todo: ADPCM analysis +// if ( (DELTAT->portstate & 0xe0)==0xc0 ) +// if ( (DELTAT->portstate & 0xe0)==0xe0 ) + + return; +} diff --git a/src/devices/sound/ymdeltat.h b/src/devices/sound/ymdeltat.h new file mode 100644 index 00000000000..28b5d535b32 --- /dev/null +++ b/src/devices/sound/ymdeltat.h @@ -0,0 +1,86 @@ +// license:??? +// copyright-holders:Jarek Burczynski +#pragma once + +#ifndef __YMDELTAT_H__ +#define __YMDELTAT_H__ + +#define YM_DELTAT_SHIFT (16) + +#define YM_DELTAT_EMULATION_MODE_NORMAL 0 +#define YM_DELTAT_EMULATION_MODE_YM2610 1 + + +typedef void (*STATUS_CHANGE_HANDLER)(void *chip, UINT8 status_bits); + + +/* DELTA-T (adpcm type B) struct */ +struct YM_DELTAT { /* AT: rearranged and tigntened structure */ + UINT8 *memory; + INT32 *output_pointer;/* pointer of output pointers */ + INT32 *pan; /* pan : &output_pointer[pan] */ + double freqbase; +#if 0 + double write_time; /* Y8950: 10 cycles of main clock; YM2608: 20 cycles of main clock */ + double read_time; /* Y8950: 8 cycles of main clock; YM2608: 18 cycles of main clock */ +#endif + UINT32 memory_size; + int output_range; + UINT32 now_addr; /* current address */ + UINT32 now_step; /* currect step */ + UINT32 step; /* step */ + UINT32 start; /* start address */ + UINT32 limit; /* limit address */ + UINT32 end; /* end address */ + UINT32 delta; /* delta scale */ + INT32 volume; /* current volume */ + INT32 acc; /* shift Measurement value*/ + INT32 adpcmd; /* next Forecast */ + INT32 adpcml; /* current value */ + INT32 prev_acc; /* leveling value */ + UINT8 now_data; /* current rom data */ + UINT8 CPU_data; /* current data from reg 08 */ + UINT8 portstate; /* port status */ + UINT8 control2; /* control reg: SAMPLE, DA/AD, RAM TYPE (x8bit / x1bit), ROM/RAM */ + UINT8 portshift; /* address bits shift-left: + ** 8 for YM2610, + ** 5 for Y8950 and YM2608 */ + + UINT8 DRAMportshift; /* address bits shift-right: + ** 0 for ROM and x8bit DRAMs, + ** 3 for x1 DRAMs */ + + UINT8 memread; /* needed for reading/writing external memory */ + + /* handlers and parameters for the status flags support */ + STATUS_CHANGE_HANDLER status_set_handler; + STATUS_CHANGE_HANDLER status_reset_handler; + + /* note that different chips have these flags on different + ** bits of the status register + */ + void * status_change_which_chip; /* this chip id */ + UINT8 status_change_EOS_bit; /* 1 on End Of Sample (record/playback/cycle time of AD/DA converting has passed)*/ + UINT8 status_change_BRDY_bit; /* 1 after recording 2 datas (2x4bits) or after reading/writing 1 data */ + UINT8 status_change_ZERO_bit; /* 1 if silence lasts for more than 290 miliseconds on ADPCM recording */ + + /* neither Y8950 nor YM2608 can generate IRQ when PCMBSY bit changes, so instead of above, + ** the statusflag gets ORed with PCM_BSY (below) (on each read of statusflag of Y8950 and YM2608) + */ + UINT8 PCM_BSY; /* 1 when ADPCM is playing; Y8950/YM2608 only */ + + UINT8 reg[16]; /* adpcm registers */ + UINT8 emulation_mode; /* which chip we're emulating */ +}; + +/*void YM_DELTAT_BRDY_callback(YM_DELTAT *DELTAT);*/ + +UINT8 YM_DELTAT_ADPCM_Read(YM_DELTAT *DELTAT); +void YM_DELTAT_ADPCM_Write(YM_DELTAT *DELTAT,int r,int v); +void YM_DELTAT_ADPCM_Reset(YM_DELTAT *DELTAT,int pan,int emulation_mode); +void YM_DELTAT_ADPCM_CALC(YM_DELTAT *DELTAT); + +void YM_DELTAT_postload(YM_DELTAT *DELTAT,UINT8 *regs); +void YM_DELTAT_savestate(device_t *device,YM_DELTAT *DELTAT); + +#endif /* __YMDELTAT_H__ */ diff --git a/src/devices/sound/ymf262.c b/src/devices/sound/ymf262.c new file mode 100644 index 00000000000..0982ae266e8 --- /dev/null +++ b/src/devices/sound/ymf262.c @@ -0,0 +1,2715 @@ +// license:??? +// copyright-holders:Jarek Burczynski +/* +** +** File: ymf262.c - software implementation of YMF262 +** FM sound generator type OPL3 +** +** Copyright Jarek Burczynski +** +** Version 0.2 +** + +Revision History: + +03-03-2003: initial release + - thanks to Olivier Galibert and Chris Hardy for YMF262 and YAC512 chips + - thanks to Stiletto for the datasheets + + Features as listed in 4MF262A6 data sheet: + 1. Registers are compatible with YM3812 (OPL2) FM sound source. + 2. Up to six sounds can be used as four-operator melody sounds for variety. + 3. 18 simultaneous melody sounds, or 15 melody sounds with 5 rhythm sounds (with two operators). + 4. 6 four-operator melody sounds and 6 two-operator melody sounds, or 6 four-operator melody + sounds, 3 two-operator melody sounds and 5 rhythm sounds (with four operators). + 5. 8 selectable waveforms. + 6. 4-channel sound output. + 7. YMF262 compabile DAC (YAC512) is available. + 8. LFO for vibrato and tremolo effedts. + 9. 2 programable timers. + 10. Shorter register access time compared with YM3812. + 11. 5V single supply silicon gate CMOS process. + 12. 24 Pin SOP Package (YMF262-M), 48 Pin SQFP Package (YMF262-S). + + +differences between OPL2 and OPL3 not documented in Yamaha datahasheets: +- sinus table is a little different: the negative part is off by one... + +- in order to enable selection of four different waveforms on OPL2 + one must set bit 5 in register 0x01(test). + on OPL3 this bit is ignored and 4-waveform select works *always*. + (Don't confuse this with OPL3's 8-waveform select.) + +- Envelope Generator: all 15 x rates take zero time on OPL3 + (on OPL2 15 0 and 15 1 rates take some time while 15 2 and 15 3 rates + take zero time) + +- channel calculations: output of operator 1 is in perfect sync with + output of operator 2 on OPL3; on OPL and OPL2 output of operator 1 + is always delayed by one sample compared to output of operator 2 + + +differences between OPL2 and OPL3 shown in datasheets: +- YMF262 does not support CSM mode + + +*/ + +#include "emu.h" +#include "ymf262.h" + + + +/* output final shift */ +#if (OPL3_SAMPLE_BITS==16) + #define FINAL_SH (0) + #define MAXOUT (+32767) + #define MINOUT (-32768) +#else + #define FINAL_SH (8) + #define MAXOUT (+127) + #define MINOUT (-128) +#endif + + +#define FREQ_SH 16 /* 16.16 fixed point (frequency calculations) */ +#define EG_SH 16 /* 16.16 fixed point (EG timing) */ +#define LFO_SH 24 /* 8.24 fixed point (LFO calculations) */ +#define TIMER_SH 16 /* 16.16 fixed point (timers calculations) */ + +#define FREQ_MASK ((1<>8)&0xff,sample[0]); \ + } + #else /*save to STEREO file */ + #define SAVE_ALL_CHANNELS \ + { signed int pom = a; \ + fputc((unsigned short)pom&0xff,sample[0]); \ + fputc(((unsigned short)pom>>8)&0xff,sample[0]); \ + pom = b; \ + fputc((unsigned short)pom&0xff,sample[0]); \ + fputc(((unsigned short)pom>>8)&0xff,sample[0]); \ + } + #endif +#endif + +#define LOG_CYM_FILE 0 +static FILE * cymfile = NULL; + + + + + +#define OPL3_TYPE_YMF262 (0) /* 36 operators, 8 waveforms */ + + +struct OPL3_SLOT +{ + UINT32 ar; /* attack rate: AR<<2 */ + UINT32 dr; /* decay rate: DR<<2 */ + UINT32 rr; /* release rate:RR<<2 */ + UINT8 KSR; /* key scale rate */ + UINT8 ksl; /* keyscale level */ + UINT8 ksr; /* key scale rate: kcode>>KSR */ + UINT8 mul; /* multiple: mul_tab[ML] */ + + /* Phase Generator */ + UINT32 Cnt; /* frequency counter */ + UINT32 Incr; /* frequency counter step */ + UINT8 FB; /* feedback shift value */ + INT32 *connect; /* slot output pointer */ + INT32 op1_out[2]; /* slot1 output for feedback */ + UINT8 CON; /* connection (algorithm) type */ + + /* Envelope Generator */ + UINT8 eg_type; /* percussive/non-percussive mode */ + UINT8 state; /* phase type */ + UINT32 TL; /* total level: TL << 2 */ + INT32 TLL; /* adjusted now TL */ + INT32 volume; /* envelope counter */ + UINT32 sl; /* sustain level: sl_tab[SL] */ + + UINT32 eg_m_ar; /* (attack state) */ + UINT8 eg_sh_ar; /* (attack state) */ + UINT8 eg_sel_ar; /* (attack state) */ + UINT32 eg_m_dr; /* (decay state) */ + UINT8 eg_sh_dr; /* (decay state) */ + UINT8 eg_sel_dr; /* (decay state) */ + UINT32 eg_m_rr; /* (release state) */ + UINT8 eg_sh_rr; /* (release state) */ + UINT8 eg_sel_rr; /* (release state) */ + + UINT32 key; /* 0 = KEY OFF, >0 = KEY ON */ + + /* LFO */ + UINT32 AMmask; /* LFO Amplitude Modulation enable mask */ + UINT8 vib; /* LFO Phase Modulation enable flag (active high)*/ + + /* waveform select */ + UINT8 waveform_number; + unsigned int wavetable; + +//unsigned char reserved[128-84];//speedup: pump up the struct size to power of 2 +unsigned char reserved[128-100];//speedup: pump up the struct size to power of 2 + +}; + +struct OPL3_CH +{ + OPL3_SLOT SLOT[2]; + + UINT32 block_fnum; /* block+fnum */ + UINT32 fc; /* Freq. Increment base */ + UINT32 ksl_base; /* KeyScaleLevel Base step */ + UINT8 kcode; /* key code (for key scaling) */ + + /* + there are 12 2-operator channels which can be combined in pairs + to form six 4-operator channel, they are: + 0 and 3, + 1 and 4, + 2 and 5, + 9 and 12, + 10 and 13, + 11 and 14 + */ + UINT8 extended; /* set to 1 if this channel forms up a 4op channel with another channel(only used by first of pair of channels, ie 0,1,2 and 9,10,11) */ + +unsigned char reserved[512-272];//speedup:pump up the struct size to power of 2 + +}; + +/* OPL3 state */ +struct OPL3 +{ + OPL3_CH P_CH[18]; /* OPL3 chips have 18 channels */ + + UINT32 pan[18*4]; /* channels output masks (0xffffffff = enable); 4 masks per one channel */ + UINT32 pan_ctrl_value[18]; /* output control values 1 per one channel (1 value contains 4 masks) */ + + signed int chanout[18]; + signed int phase_modulation; /* phase modulation input (SLOT 2) */ + signed int phase_modulation2; /* phase modulation input (SLOT 3 in 4 operator channels) */ + + UINT32 eg_cnt; /* global envelope generator counter */ + UINT32 eg_timer; /* global envelope generator counter works at frequency = chipclock/288 (288=8*36) */ + UINT32 eg_timer_add; /* step of eg_timer */ + UINT32 eg_timer_overflow; /* envelope generator timer overlfows every 1 sample (on real chip) */ + + UINT32 fn_tab[1024]; /* fnumber->increment counter */ + + /* LFO */ + UINT32 LFO_AM; + INT32 LFO_PM; + + UINT8 lfo_am_depth; + UINT8 lfo_pm_depth_range; + UINT32 lfo_am_cnt; + UINT32 lfo_am_inc; + UINT32 lfo_pm_cnt; + UINT32 lfo_pm_inc; + + UINT32 noise_rng; /* 23 bit noise shift register */ + UINT32 noise_p; /* current noise 'phase' */ + UINT32 noise_f; /* current noise period */ + + UINT8 OPL3_mode; /* OPL3 extension enable flag */ + + UINT8 rhythm; /* Rhythm mode */ + + int T[2]; /* timer counters */ + UINT8 st[2]; /* timer enable */ + + UINT32 address; /* address register */ + UINT8 status; /* status flag */ + UINT8 statusmask; /* status mask */ + + UINT8 nts; /* NTS (note select) */ + + /* external event callback handlers */ + OPL3_TIMERHANDLER timer_handler;/* TIMER handler */ + void *TimerParam; /* TIMER parameter */ + OPL3_IRQHANDLER IRQHandler; /* IRQ handler */ + void *IRQParam; /* IRQ parameter */ + OPL3_UPDATEHANDLER UpdateHandler;/* stream update handler */ + void *UpdateParam; /* stream update parameter */ + + UINT8 type; /* chip type */ + int clock; /* master clock (Hz) */ + int rate; /* sampling rate (Hz) */ + double freqbase; /* frequency base */ + attotime TimerBase; /* Timer base time (==sampling time)*/ + device_t *device; +}; + + + +/* mapping of register number (offset) to slot number used by the emulator */ +static const int slot_array[32]= +{ + 0, 2, 4, 1, 3, 5,-1,-1, + 6, 8,10, 7, 9,11,-1,-1, + 12,14,16,13,15,17,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1 +}; + +/* key scale level */ +/* table is 3dB/octave , DV converts this into 6dB/octave */ +/* 0.1875 is bit 0 weight of the envelope counter (volume) expressed in the 'decibel' scale */ +#define DV (0.1875/2.0) +static const UINT32 ksl_tab[8*16]= +{ + /* OCT 0 */ + 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV, + 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV, + 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV, + 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV, + /* OCT 1 */ + 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV, + 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV, + 0.000/DV, 0.750/DV, 1.125/DV, 1.500/DV, + 1.875/DV, 2.250/DV, 2.625/DV, 3.000/DV, + /* OCT 2 */ + 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV, + 0.000/DV, 1.125/DV, 1.875/DV, 2.625/DV, + 3.000/DV, 3.750/DV, 4.125/DV, 4.500/DV, + 4.875/DV, 5.250/DV, 5.625/DV, 6.000/DV, + /* OCT 3 */ + 0.000/DV, 0.000/DV, 0.000/DV, 1.875/DV, + 3.000/DV, 4.125/DV, 4.875/DV, 5.625/DV, + 6.000/DV, 6.750/DV, 7.125/DV, 7.500/DV, + 7.875/DV, 8.250/DV, 8.625/DV, 9.000/DV, + /* OCT 4 */ + 0.000/DV, 0.000/DV, 3.000/DV, 4.875/DV, + 6.000/DV, 7.125/DV, 7.875/DV, 8.625/DV, + 9.000/DV, 9.750/DV,10.125/DV,10.500/DV, + 10.875/DV,11.250/DV,11.625/DV,12.000/DV, + /* OCT 5 */ + 0.000/DV, 3.000/DV, 6.000/DV, 7.875/DV, + 9.000/DV,10.125/DV,10.875/DV,11.625/DV, + 12.000/DV,12.750/DV,13.125/DV,13.500/DV, + 13.875/DV,14.250/DV,14.625/DV,15.000/DV, + /* OCT 6 */ + 0.000/DV, 6.000/DV, 9.000/DV,10.875/DV, + 12.000/DV,13.125/DV,13.875/DV,14.625/DV, + 15.000/DV,15.750/DV,16.125/DV,16.500/DV, + 16.875/DV,17.250/DV,17.625/DV,18.000/DV, + /* OCT 7 */ + 0.000/DV, 9.000/DV,12.000/DV,13.875/DV, + 15.000/DV,16.125/DV,16.875/DV,17.625/DV, + 18.000/DV,18.750/DV,19.125/DV,19.500/DV, + 19.875/DV,20.250/DV,20.625/DV,21.000/DV +}; +#undef DV + +/* 0 / 3.0 / 1.5 / 6.0 dB/OCT */ +static const UINT32 ksl_shift[4] = { 31, 1, 2, 0 }; + + +/* sustain level table (3dB per step) */ +/* 0 - 15: 0, 3, 6, 9,12,15,18,21,24,27,30,33,36,39,42,93 (dB)*/ +#define SC(db) (UINT32) ( db * (2.0/ENV_STEP) ) +static const UINT32 sl_tab[16]={ + SC( 0),SC( 1),SC( 2),SC(3 ),SC(4 ),SC(5 ),SC(6 ),SC( 7), + SC( 8),SC( 9),SC(10),SC(11),SC(12),SC(13),SC(14),SC(31) +}; +#undef SC + + +#define RATE_STEPS (8) +static const unsigned char eg_inc[15*RATE_STEPS]={ +/*cycle:0 1 2 3 4 5 6 7*/ + +/* 0 */ 0,1, 0,1, 0,1, 0,1, /* rates 00..12 0 (increment by 0 or 1) */ +/* 1 */ 0,1, 0,1, 1,1, 0,1, /* rates 00..12 1 */ +/* 2 */ 0,1, 1,1, 0,1, 1,1, /* rates 00..12 2 */ +/* 3 */ 0,1, 1,1, 1,1, 1,1, /* rates 00..12 3 */ + +/* 4 */ 1,1, 1,1, 1,1, 1,1, /* rate 13 0 (increment by 1) */ +/* 5 */ 1,1, 1,2, 1,1, 1,2, /* rate 13 1 */ +/* 6 */ 1,2, 1,2, 1,2, 1,2, /* rate 13 2 */ +/* 7 */ 1,2, 2,2, 1,2, 2,2, /* rate 13 3 */ + +/* 8 */ 2,2, 2,2, 2,2, 2,2, /* rate 14 0 (increment by 2) */ +/* 9 */ 2,2, 2,4, 2,2, 2,4, /* rate 14 1 */ +/*10 */ 2,4, 2,4, 2,4, 2,4, /* rate 14 2 */ +/*11 */ 2,4, 4,4, 2,4, 4,4, /* rate 14 3 */ + +/*12 */ 4,4, 4,4, 4,4, 4,4, /* rates 15 0, 15 1, 15 2, 15 3 for decay */ +/*13 */ 8,8, 8,8, 8,8, 8,8, /* rates 15 0, 15 1, 15 2, 15 3 for attack (zero time) */ +/*14 */ 0,0, 0,0, 0,0, 0,0, /* infinity rates for attack and decay(s) */ +}; + + +#define O(a) (a*RATE_STEPS) + +/* note that there is no O(13) in this table - it's directly in the code */ +static const unsigned char eg_rate_select[16+64+16]={ /* Envelope Generator rates (16 + 64 rates + 16 RKS) */ +/* 16 infinite time rates */ +O(14),O(14),O(14),O(14),O(14),O(14),O(14),O(14), +O(14),O(14),O(14),O(14),O(14),O(14),O(14),O(14), + +/* rates 00-12 */ +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), + +/* rate 13 */ +O( 4),O( 5),O( 6),O( 7), + +/* rate 14 */ +O( 8),O( 9),O(10),O(11), + +/* rate 15 */ +O(12),O(12),O(12),O(12), + +/* 16 dummy rates (same as 15 3) */ +O(12),O(12),O(12),O(12),O(12),O(12),O(12),O(12), +O(12),O(12),O(12),O(12),O(12),O(12),O(12),O(12), + +}; +#undef O + +/*rate 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 */ +/*shift 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0, 0, 0 */ +/*mask 4095, 2047, 1023, 511, 255, 127, 63, 31, 15, 7, 3, 1, 0, 0, 0, 0 */ + +#define O(a) (a*1) +static const unsigned char eg_rate_shift[16+64+16]={ /* Envelope Generator counter shifts (16 + 64 rates + 16 RKS) */ +/* 16 infinite time rates */ +O(0),O(0),O(0),O(0),O(0),O(0),O(0),O(0), +O(0),O(0),O(0),O(0),O(0),O(0),O(0),O(0), + +/* rates 00-12 */ +O(12),O(12),O(12),O(12), +O(11),O(11),O(11),O(11), +O(10),O(10),O(10),O(10), +O( 9),O( 9),O( 9),O( 9), +O( 8),O( 8),O( 8),O( 8), +O( 7),O( 7),O( 7),O( 7), +O( 6),O( 6),O( 6),O( 6), +O( 5),O( 5),O( 5),O( 5), +O( 4),O( 4),O( 4),O( 4), +O( 3),O( 3),O( 3),O( 3), +O( 2),O( 2),O( 2),O( 2), +O( 1),O( 1),O( 1),O( 1), +O( 0),O( 0),O( 0),O( 0), + +/* rate 13 */ +O( 0),O( 0),O( 0),O( 0), + +/* rate 14 */ +O( 0),O( 0),O( 0),O( 0), + +/* rate 15 */ +O( 0),O( 0),O( 0),O( 0), + +/* 16 dummy rates (same as 15 3) */ +O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0), +O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0), + +}; +#undef O + + +/* multiple table */ +#define ML 2 +static const UINT8 mul_tab[16]= { +/* 1/2, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,10,12,12,15,15 */ + ML/2, 1*ML, 2*ML, 3*ML, 4*ML, 5*ML, 6*ML, 7*ML, + 8*ML, 9*ML,10*ML,10*ML,12*ML,12*ML,15*ML,15*ML +}; +#undef ML + +/* TL_TAB_LEN is calculated as: + +* (12+1)=13 - sinus amplitude bits (Y axis) +* additional 1: to compensate for calculations of negative part of waveform +* (if we don't add it then the greatest possible _negative_ value would be -2 +* and we really need -1 for waveform #7) +* 2 - sinus sign bit (Y axis) +* TL_RES_LEN - sinus resolution (X axis) +*/ +#define TL_TAB_LEN (13*2*TL_RES_LEN) +static signed int tl_tab[TL_TAB_LEN]; + +#define ENV_QUIET (TL_TAB_LEN>>4) + +/* sin waveform table in 'decibel' scale */ +/* there are eight waveforms on OPL3 chips */ +static unsigned int sin_tab[SIN_LEN * 8]; + + +/* LFO Amplitude Modulation table (verified on real YM3812) + 27 output levels (triangle waveform); 1 level takes one of: 192, 256 or 448 samples + + Length: 210 elements. + + Each of the elements has to be repeated + exactly 64 times (on 64 consecutive samples). + The whole table takes: 64 * 210 = 13440 samples. + + When AM = 1 data is used directly + When AM = 0 data is divided by 4 before being used (losing precision is important) +*/ + +#define LFO_AM_TAB_ELEMENTS 210 + +static const UINT8 lfo_am_table[LFO_AM_TAB_ELEMENTS] = { +0,0,0,0,0,0,0, +1,1,1,1, +2,2,2,2, +3,3,3,3, +4,4,4,4, +5,5,5,5, +6,6,6,6, +7,7,7,7, +8,8,8,8, +9,9,9,9, +10,10,10,10, +11,11,11,11, +12,12,12,12, +13,13,13,13, +14,14,14,14, +15,15,15,15, +16,16,16,16, +17,17,17,17, +18,18,18,18, +19,19,19,19, +20,20,20,20, +21,21,21,21, +22,22,22,22, +23,23,23,23, +24,24,24,24, +25,25,25,25, +26,26,26, +25,25,25,25, +24,24,24,24, +23,23,23,23, +22,22,22,22, +21,21,21,21, +20,20,20,20, +19,19,19,19, +18,18,18,18, +17,17,17,17, +16,16,16,16, +15,15,15,15, +14,14,14,14, +13,13,13,13, +12,12,12,12, +11,11,11,11, +10,10,10,10, +9,9,9,9, +8,8,8,8, +7,7,7,7, +6,6,6,6, +5,5,5,5, +4,4,4,4, +3,3,3,3, +2,2,2,2, +1,1,1,1 +}; + +/* LFO Phase Modulation table (verified on real YM3812) */ +static const INT8 lfo_pm_table[8*8*2] = { +/* FNUM2/FNUM = 00 0xxxxxxx (0x0000) */ +0, 0, 0, 0, 0, 0, 0, 0, /*LFO PM depth = 0*/ +0, 0, 0, 0, 0, 0, 0, 0, /*LFO PM depth = 1*/ + +/* FNUM2/FNUM = 00 1xxxxxxx (0x0080) */ +0, 0, 0, 0, 0, 0, 0, 0, /*LFO PM depth = 0*/ +1, 0, 0, 0,-1, 0, 0, 0, /*LFO PM depth = 1*/ + +/* FNUM2/FNUM = 01 0xxxxxxx (0x0100) */ +1, 0, 0, 0,-1, 0, 0, 0, /*LFO PM depth = 0*/ +2, 1, 0,-1,-2,-1, 0, 1, /*LFO PM depth = 1*/ + +/* FNUM2/FNUM = 01 1xxxxxxx (0x0180) */ +1, 0, 0, 0,-1, 0, 0, 0, /*LFO PM depth = 0*/ +3, 1, 0,-1,-3,-1, 0, 1, /*LFO PM depth = 1*/ + +/* FNUM2/FNUM = 10 0xxxxxxx (0x0200) */ +2, 1, 0,-1,-2,-1, 0, 1, /*LFO PM depth = 0*/ +4, 2, 0,-2,-4,-2, 0, 2, /*LFO PM depth = 1*/ + +/* FNUM2/FNUM = 10 1xxxxxxx (0x0280) */ +2, 1, 0,-1,-2,-1, 0, 1, /*LFO PM depth = 0*/ +5, 2, 0,-2,-5,-2, 0, 2, /*LFO PM depth = 1*/ + +/* FNUM2/FNUM = 11 0xxxxxxx (0x0300) */ +3, 1, 0,-1,-3,-1, 0, 1, /*LFO PM depth = 0*/ +6, 3, 0,-3,-6,-3, 0, 3, /*LFO PM depth = 1*/ + +/* FNUM2/FNUM = 11 1xxxxxxx (0x0380) */ +3, 1, 0,-1,-3,-1, 0, 1, /*LFO PM depth = 0*/ +7, 3, 0,-3,-7,-3, 0, 3 /*LFO PM depth = 1*/ +}; + + +/* lock level of common table */ +static int num_lock = 0; + +/* work table */ +#define SLOT7_1 (&chip->P_CH[7].SLOT[SLOT1]) +#define SLOT7_2 (&chip->P_CH[7].SLOT[SLOT2]) +#define SLOT8_1 (&chip->P_CH[8].SLOT[SLOT1]) +#define SLOT8_2 (&chip->P_CH[8].SLOT[SLOT2]) + + + + + +INLINE int limit( int val, int max, int min ) { + if ( val > max ) + val = max; + else if ( val < min ) + val = min; + + return val; +} + + +/* status set and IRQ handling */ +INLINE void OPL3_STATUS_SET(OPL3 *chip,int flag) +{ + /* set status flag masking out disabled IRQs */ + chip->status |= (flag & chip->statusmask); + if(!(chip->status & 0x80)) + { + if(chip->status & 0x7f) + { /* IRQ on */ + chip->status |= 0x80; + /* callback user interrupt handler (IRQ is OFF to ON) */ + if(chip->IRQHandler) (chip->IRQHandler)(chip->IRQParam,1); + } + } +} + +/* status reset and IRQ handling */ +INLINE void OPL3_STATUS_RESET(OPL3 *chip,int flag) +{ + /* reset status flag */ + chip->status &= ~flag; + if(chip->status & 0x80) + { + if (!(chip->status & 0x7f)) + { + chip->status &= 0x7f; + /* callback user interrupt handler (IRQ is ON to OFF) */ + if(chip->IRQHandler) (chip->IRQHandler)(chip->IRQParam,0); + } + } +} + +/* IRQ mask set */ +INLINE void OPL3_STATUSMASK_SET(OPL3 *chip,int flag) +{ + chip->statusmask = flag; + /* IRQ handling check */ + OPL3_STATUS_SET(chip,0); + OPL3_STATUS_RESET(chip,0); +} + + +/* advance LFO to next sample */ +INLINE void advance_lfo(OPL3 *chip) +{ + UINT8 tmp; + + /* LFO */ + chip->lfo_am_cnt += chip->lfo_am_inc; + if (chip->lfo_am_cnt >= ((UINT32)LFO_AM_TAB_ELEMENTS<lfo_am_cnt -= ((UINT32)LFO_AM_TAB_ELEMENTS<lfo_am_cnt >> LFO_SH ]; + + if (chip->lfo_am_depth) + chip->LFO_AM = tmp; + else + chip->LFO_AM = tmp>>2; + + chip->lfo_pm_cnt += chip->lfo_pm_inc; + chip->LFO_PM = ((chip->lfo_pm_cnt>>LFO_SH) & 7) | chip->lfo_pm_depth_range; +} + +/* advance to next sample */ +INLINE void advance(OPL3 *chip) +{ + OPL3_CH *CH; + OPL3_SLOT *op; + int i; + + chip->eg_timer += chip->eg_timer_add; + + while (chip->eg_timer >= chip->eg_timer_overflow) + { + chip->eg_timer -= chip->eg_timer_overflow; + + chip->eg_cnt++; + + for (i=0; i<9*2*2; i++) + { + CH = &chip->P_CH[i/2]; + op = &CH->SLOT[i&1]; +#if 1 + /* Envelope Generator */ + switch(op->state) + { + case EG_ATT: /* attack phase */ +// if ( !(chip->eg_cnt & ((1<eg_sh_ar)-1) ) ) + if ( !(chip->eg_cnt & op->eg_m_ar) ) + { + op->volume += (~op->volume * + (eg_inc[op->eg_sel_ar + ((chip->eg_cnt>>op->eg_sh_ar)&7)]) + ) >>3; + + if (op->volume <= MIN_ATT_INDEX) + { + op->volume = MIN_ATT_INDEX; + op->state = EG_DEC; + } + + } + break; + + case EG_DEC: /* decay phase */ +// if ( !(chip->eg_cnt & ((1<eg_sh_dr)-1) ) ) + if ( !(chip->eg_cnt & op->eg_m_dr) ) + { + op->volume += eg_inc[op->eg_sel_dr + ((chip->eg_cnt>>op->eg_sh_dr)&7)]; + + if ( op->volume >= op->sl ) + op->state = EG_SUS; + + } + break; + + case EG_SUS: /* sustain phase */ + + /* this is important behaviour: + one can change percusive/non-percussive modes on the fly and + the chip will remain in sustain phase - verified on real YM3812 */ + + if(op->eg_type) /* non-percussive mode */ + { + /* do nothing */ + } + else /* percussive mode */ + { + /* during sustain phase chip adds Release Rate (in percussive mode) */ +// if ( !(chip->eg_cnt & ((1<eg_sh_rr)-1) ) ) + if ( !(chip->eg_cnt & op->eg_m_rr) ) + { + op->volume += eg_inc[op->eg_sel_rr + ((chip->eg_cnt>>op->eg_sh_rr)&7)]; + + if ( op->volume >= MAX_ATT_INDEX ) + op->volume = MAX_ATT_INDEX; + } + /* else do nothing in sustain phase */ + } + break; + + case EG_REL: /* release phase */ +// if ( !(chip->eg_cnt & ((1<eg_sh_rr)-1) ) ) + if ( !(chip->eg_cnt & op->eg_m_rr) ) + { + op->volume += eg_inc[op->eg_sel_rr + ((chip->eg_cnt>>op->eg_sh_rr)&7)]; + + if ( op->volume >= MAX_ATT_INDEX ) + { + op->volume = MAX_ATT_INDEX; + op->state = EG_OFF; + } + + } + break; + + default: + break; + } +#endif + } + } + + for (i=0; i<9*2*2; i++) + { + CH = &chip->P_CH[i/2]; + op = &CH->SLOT[i&1]; + + /* Phase Generator */ + if(op->vib) + { + UINT8 block; + unsigned int block_fnum = CH->block_fnum; + + unsigned int fnum_lfo = (block_fnum&0x0380) >> 7; + + signed int lfo_fn_table_index_offset = lfo_pm_table[chip->LFO_PM + 16*fnum_lfo ]; + + if (lfo_fn_table_index_offset) /* LFO phase modulation active */ + { + block_fnum += lfo_fn_table_index_offset; + block = (block_fnum&0x1c00) >> 10; + op->Cnt += (chip->fn_tab[block_fnum&0x03ff] >> (7-block)) * op->mul; + } + else /* LFO phase modulation = zero */ + { + op->Cnt += op->Incr; + } + } + else /* LFO phase modulation disabled for this operator */ + { + op->Cnt += op->Incr; + } + } + + /* The Noise Generator of the YM3812 is 23-bit shift register. + * Period is equal to 2^23-2 samples. + * Register works at sampling frequency of the chip, so output + * can change on every sample. + * + * Output of the register and input to the bit 22 is: + * bit0 XOR bit14 XOR bit15 XOR bit22 + * + * Simply use bit 22 as the noise output. + */ + + chip->noise_p += chip->noise_f; + i = chip->noise_p >> FREQ_SH; /* number of events (shifts of the shift register) */ + chip->noise_p &= FREQ_MASK; + while (i) + { + /* + UINT32 j; + j = ( (chip->noise_rng) ^ (chip->noise_rng>>14) ^ (chip->noise_rng>>15) ^ (chip->noise_rng>>22) ) & 1; + chip->noise_rng = (j<<22) | (chip->noise_rng>>1); + */ + + /* + Instead of doing all the logic operations above, we + use a trick here (and use bit 0 as the noise output). + The difference is only that the noise bit changes one + step ahead. This doesn't matter since we don't know + what is real state of the noise_rng after the reset. + */ + + if (chip->noise_rng & 1) chip->noise_rng ^= 0x800302; + chip->noise_rng >>= 1; + + i--; + } +} + + +INLINE signed int op_calc(UINT32 phase, unsigned int env, signed int pm, unsigned int wave_tab) +{ + UINT32 p; + + p = (env<<4) + sin_tab[wave_tab + ((((signed int)((phase & ~FREQ_MASK) + (pm<<16))) >> FREQ_SH ) & SIN_MASK) ]; + + if (p >= TL_TAB_LEN) + return 0; + return tl_tab[p]; +} + +INLINE signed int op_calc1(UINT32 phase, unsigned int env, signed int pm, unsigned int wave_tab) +{ + UINT32 p; + + p = (env<<4) + sin_tab[wave_tab + ((((signed int)((phase & ~FREQ_MASK) + pm))>>FREQ_SH) & SIN_MASK)]; + + if (p >= TL_TAB_LEN) + return 0; + return tl_tab[p]; +} + + +#define volume_calc(OP) ((OP)->TLL + ((UINT32)(OP)->volume) + (chip->LFO_AM & (OP)->AMmask)) + +/* calculate output of a standard 2 operator channel + (or 1st part of a 4-op channel) */ +INLINE void chan_calc( OPL3 *chip, OPL3_CH *CH ) +{ + OPL3_SLOT *SLOT; + unsigned int env; + signed int out; + + chip->phase_modulation = 0; + chip->phase_modulation2= 0; + + /* SLOT 1 */ + SLOT = &CH->SLOT[SLOT1]; + env = volume_calc(SLOT); + out = SLOT->op1_out[0] + SLOT->op1_out[1]; + SLOT->op1_out[0] = SLOT->op1_out[1]; + SLOT->op1_out[1] = 0; + if( env < ENV_QUIET ) + { + if (!SLOT->FB) + out = 0; + SLOT->op1_out[1] = op_calc1(SLOT->Cnt, env, (out<FB), SLOT->wavetable ); + } + *SLOT->connect += SLOT->op1_out[1]; +//logerror("out0=%5i vol0=%4i ", SLOT->op1_out[1], env ); + + /* SLOT 2 */ + SLOT++; + env = volume_calc(SLOT); + if( env < ENV_QUIET ) + *SLOT->connect += op_calc(SLOT->Cnt, env, chip->phase_modulation, SLOT->wavetable); + +//logerror("out1=%5i vol1=%4i\n", op_calc(SLOT->Cnt, env, chip->phase_modulation, SLOT->wavetable), env ); + +} + +/* calculate output of a 2nd part of 4-op channel */ +INLINE void chan_calc_ext( OPL3 *chip, OPL3_CH *CH ) +{ + OPL3_SLOT *SLOT; + unsigned int env; + + chip->phase_modulation = 0; + + /* SLOT 1 */ + SLOT = &CH->SLOT[SLOT1]; + env = volume_calc(SLOT); + if( env < ENV_QUIET ) + *SLOT->connect += op_calc(SLOT->Cnt, env, chip->phase_modulation2, SLOT->wavetable ); + + /* SLOT 2 */ + SLOT++; + env = volume_calc(SLOT); + if( env < ENV_QUIET ) + *SLOT->connect += op_calc(SLOT->Cnt, env, chip->phase_modulation, SLOT->wavetable); + +} + +/* + operators used in the rhythm sounds generation process: + + Envelope Generator: + +channel operator register number Bass High Snare Tom Top +/ slot number TL ARDR SLRR Wave Drum Hat Drum Tom Cymbal + 6 / 0 12 50 70 90 f0 + + 6 / 1 15 53 73 93 f3 + + 7 / 0 13 51 71 91 f1 + + 7 / 1 16 54 74 94 f4 + + 8 / 0 14 52 72 92 f2 + + 8 / 1 17 55 75 95 f5 + + + Phase Generator: + +channel operator register number Bass High Snare Tom Top +/ slot number MULTIPLE Drum Hat Drum Tom Cymbal + 6 / 0 12 30 + + 6 / 1 15 33 + + 7 / 0 13 31 + + + + 7 / 1 16 34 ----- n o t u s e d ----- + 8 / 0 14 32 + + 8 / 1 17 35 + + + +channel operator register number Bass High Snare Tom Top +number number BLK/FNUM2 FNUM Drum Hat Drum Tom Cymbal + 6 12,15 B6 A6 + + + 7 13,16 B7 A7 + + + + + 8 14,17 B8 A8 + + + + +*/ + +/* calculate rhythm */ + +INLINE void chan_calc_rhythm( OPL3 *chip, OPL3_CH *CH, unsigned int noise ) +{ + OPL3_SLOT *SLOT; + signed int *chanout = chip->chanout; + signed int out; + unsigned int env; + + + /* Bass Drum (verified on real YM3812): + - depends on the channel 6 'connect' register: + when connect = 0 it works the same as in normal (non-rhythm) mode (op1->op2->out) + when connect = 1 _only_ operator 2 is present on output (op2->out), operator 1 is ignored + - output sample always is multiplied by 2 + */ + + chip->phase_modulation = 0; + + /* SLOT 1 */ + SLOT = &CH[6].SLOT[SLOT1]; + env = volume_calc(SLOT); + + out = SLOT->op1_out[0] + SLOT->op1_out[1]; + SLOT->op1_out[0] = SLOT->op1_out[1]; + + if (!SLOT->CON) + chip->phase_modulation = SLOT->op1_out[0]; + //else ignore output of operator 1 + + SLOT->op1_out[1] = 0; + if( env < ENV_QUIET ) + { + if (!SLOT->FB) + out = 0; + SLOT->op1_out[1] = op_calc1(SLOT->Cnt, env, (out<FB), SLOT->wavetable ); + } + + /* SLOT 2 */ + SLOT++; + env = volume_calc(SLOT); + if( env < ENV_QUIET ) + chanout[6] += op_calc(SLOT->Cnt, env, chip->phase_modulation, SLOT->wavetable) * 2; + + + /* Phase generation is based on: */ + // HH (13) channel 7->slot 1 combined with channel 8->slot 2 (same combination as TOP CYMBAL but different output phases) + // SD (16) channel 7->slot 1 + // TOM (14) channel 8->slot 1 + // TOP (17) channel 7->slot 1 combined with channel 8->slot 2 (same combination as HIGH HAT but different output phases) + + /* Envelope generation based on: */ + // HH channel 7->slot1 + // SD channel 7->slot2 + // TOM channel 8->slot1 + // TOP channel 8->slot2 + + + /* The following formulas can be well optimized. + I leave them in direct form for now (in case I've missed something). + */ + + /* High Hat (verified on real YM3812) */ + env = volume_calc(SLOT7_1); + if( env < ENV_QUIET ) + { + /* high hat phase generation: + phase = d0 or 234 (based on frequency only) + phase = 34 or 2d0 (based on noise) + */ + + /* base frequency derived from operator 1 in channel 7 */ + unsigned char bit7 = ((SLOT7_1->Cnt>>FREQ_SH)>>7)&1; + unsigned char bit3 = ((SLOT7_1->Cnt>>FREQ_SH)>>3)&1; + unsigned char bit2 = ((SLOT7_1->Cnt>>FREQ_SH)>>2)&1; + + unsigned char res1 = (bit2 ^ bit7) | bit3; + + /* when res1 = 0 phase = 0x000 | 0xd0; */ + /* when res1 = 1 phase = 0x200 | (0xd0>>2); */ + UINT32 phase = res1 ? (0x200|(0xd0>>2)) : 0xd0; + + /* enable gate based on frequency of operator 2 in channel 8 */ + unsigned char bit5e= ((SLOT8_2->Cnt>>FREQ_SH)>>5)&1; + unsigned char bit3e= ((SLOT8_2->Cnt>>FREQ_SH)>>3)&1; + + unsigned char res2 = (bit3e ^ bit5e); + + /* when res2 = 0 pass the phase from calculation above (res1); */ + /* when res2 = 1 phase = 0x200 | (0xd0>>2); */ + if (res2) + phase = (0x200|(0xd0>>2)); + + + /* when phase & 0x200 is set and noise=1 then phase = 0x200|0xd0 */ + /* when phase & 0x200 is set and noise=0 then phase = 0x200|(0xd0>>2), ie no change */ + if (phase&0x200) + { + if (noise) + phase = 0x200|0xd0; + } + else + /* when phase & 0x200 is clear and noise=1 then phase = 0xd0>>2 */ + /* when phase & 0x200 is clear and noise=0 then phase = 0xd0, ie no change */ + { + if (noise) + phase = 0xd0>>2; + } + + chanout[7] += op_calc(phase<wavetable) * 2; + } + + /* Snare Drum (verified on real YM3812) */ + env = volume_calc(SLOT7_2); + if( env < ENV_QUIET ) + { + /* base frequency derived from operator 1 in channel 7 */ + unsigned char bit8 = ((SLOT7_1->Cnt>>FREQ_SH)>>8)&1; + + /* when bit8 = 0 phase = 0x100; */ + /* when bit8 = 1 phase = 0x200; */ + UINT32 phase = bit8 ? 0x200 : 0x100; + + /* Noise bit XOR'es phase by 0x100 */ + /* when noisebit = 0 pass the phase from calculation above */ + /* when noisebit = 1 phase ^= 0x100; */ + /* in other words: phase ^= (noisebit<<8); */ + if (noise) + phase ^= 0x100; + + chanout[7] += op_calc(phase<wavetable) * 2; + } + + /* Tom Tom (verified on real YM3812) */ + env = volume_calc(SLOT8_1); + if( env < ENV_QUIET ) + chanout[8] += op_calc(SLOT8_1->Cnt, env, 0, SLOT8_1->wavetable) * 2; + + /* Top Cymbal (verified on real YM3812) */ + env = volume_calc(SLOT8_2); + if( env < ENV_QUIET ) + { + /* base frequency derived from operator 1 in channel 7 */ + unsigned char bit7 = ((SLOT7_1->Cnt>>FREQ_SH)>>7)&1; + unsigned char bit3 = ((SLOT7_1->Cnt>>FREQ_SH)>>3)&1; + unsigned char bit2 = ((SLOT7_1->Cnt>>FREQ_SH)>>2)&1; + + unsigned char res1 = (bit2 ^ bit7) | bit3; + + /* when res1 = 0 phase = 0x000 | 0x100; */ + /* when res1 = 1 phase = 0x200 | 0x100; */ + UINT32 phase = res1 ? 0x300 : 0x100; + + /* enable gate based on frequency of operator 2 in channel 8 */ + unsigned char bit5e= ((SLOT8_2->Cnt>>FREQ_SH)>>5)&1; + unsigned char bit3e= ((SLOT8_2->Cnt>>FREQ_SH)>>3)&1; + + unsigned char res2 = (bit3e ^ bit5e); + /* when res2 = 0 pass the phase from calculation above (res1); */ + /* when res2 = 1 phase = 0x200 | 0x100; */ + if (res2) + phase = 0x300; + + chanout[8] += op_calc(phase<wavetable) * 2; + } + +} + + +/* generic table initialize */ +static int init_tables(void) +{ + signed int i,x; + signed int n; + double o,m; + + + for (x=0; x>= 4; /* 12 bits here */ + if (n&1) /* round to nearest */ + n = (n>>1)+1; + else + n = n>>1; + /* 11 bits here (rounded) */ + n <<= 1; /* 12 bits here (as in real chip) */ + tl_tab[ x*2 + 0 ] = n; + tl_tab[ x*2 + 1 ] = ~tl_tab[ x*2 + 0 ]; /* this *is* different from OPL2 (verified on real YMF262) */ + + for (i=1; i<13; i++) + { + tl_tab[ x*2+0 + i*2*TL_RES_LEN ] = tl_tab[ x*2+0 ]>>i; + tl_tab[ x*2+1 + i*2*TL_RES_LEN ] = ~tl_tab[ x*2+0 + i*2*TL_RES_LEN ]; /* this *is* different from OPL2 (verified on real YMF262) */ + } + #if 0 + logerror("tl %04i", x*2); + for (i=0; i<13; i++) + logerror(", [%02i] %5i", i*2, tl_tab[ x*2 +0 + i*2*TL_RES_LEN ] ); /* positive */ + logerror("\n"); + + logerror("tl %04i", x*2); + for (i=0; i<13; i++) + logerror(", [%02i] %5i", i*2, tl_tab[ x*2 +1 + i*2*TL_RES_LEN ] ); /* negative */ + logerror("\n"); + #endif + } + + for (i=0; i0.0) + o = 8*log(1.0/m)/log(2.0); /* convert to 'decibels' */ + else + o = 8*log(-1.0/m)/log(2.0); /* convert to 'decibels' */ + + o = o / (ENV_STEP/4); + + n = (int)(2.0*o); + if (n&1) /* round to nearest */ + n = (n>>1)+1; + else + n = n>>1; + + sin_tab[ i ] = n*2 + (m>=0.0? 0: 1 ); + + /*logerror("YMF262.C: sin [%4i (hex=%03x)]= %4i (tl_tab value=%5i)\n", i, i, sin_tab[i], tl_tab[sin_tab[i]] );*/ + } + + for (i=0; i>1) ]; + + /* waveform 3: _ _ _ _ */ + /* / |_/ |_/ |_/ |_*/ + /* abs(output only first quarter of the sinus waveform) */ + + if (i & (1<<(SIN_BITS-2)) ) + sin_tab[3*SIN_LEN+i] = TL_TAB_LEN; + else + sin_tab[3*SIN_LEN+i] = sin_tab[i & (SIN_MASK>>2)]; + + /* waveform 4: */ + /* /\ ____/\ ____*/ + /* \/ \/ */ + /* output whole sinus waveform in half the cycle(step=2) and output 0 on the other half of cycle */ + + if (i & (1<<(SIN_BITS-1)) ) + sin_tab[4*SIN_LEN+i] = TL_TAB_LEN; + else + sin_tab[4*SIN_LEN+i] = sin_tab[i*2]; + + /* waveform 5: */ + /* /\/\____/\/\____*/ + /* */ + /* output abs(whole sinus) waveform in half the cycle(step=2) and output 0 on the other half of cycle */ + + if (i & (1<<(SIN_BITS-1)) ) + sin_tab[5*SIN_LEN+i] = TL_TAB_LEN; + else + sin_tab[5*SIN_LEN+i] = sin_tab[(i*2) & (SIN_MASK>>1) ]; + + /* waveform 6: ____ ____ */ + /* */ + /* ____ ____*/ + /* output maximum in half the cycle and output minimum on the other half of cycle */ + + if (i & (1<<(SIN_BITS-1)) ) + sin_tab[6*SIN_LEN+i] = 1; /* negative */ + else + sin_tab[6*SIN_LEN+i] = 0; /* positive */ + + /* waveform 7: */ + /* |\____ |\____ */ + /* \| \|*/ + /* output sawtooth waveform */ + + if (i & (1<<(SIN_BITS-1)) ) + x = ((SIN_LEN-1)-i)*16 + 1; /* negative: from 8177 to 1 */ + else + x = i*16; /*positive: from 0 to 8176 */ + + if (x > TL_TAB_LEN) + x = TL_TAB_LEN; /* clip to the allowed range */ + + sin_tab[7*SIN_LEN+i] = x; + + //logerror("YMF262.C: sin1[%4i]= %4i (tl_tab value=%5i)\n", i, sin_tab[1*SIN_LEN+i], tl_tab[sin_tab[1*SIN_LEN+i]] ); + //logerror("YMF262.C: sin2[%4i]= %4i (tl_tab value=%5i)\n", i, sin_tab[2*SIN_LEN+i], tl_tab[sin_tab[2*SIN_LEN+i]] ); + //logerror("YMF262.C: sin3[%4i]= %4i (tl_tab value=%5i)\n", i, sin_tab[3*SIN_LEN+i], tl_tab[sin_tab[3*SIN_LEN+i]] ); + //logerror("YMF262.C: sin4[%4i]= %4i (tl_tab value=%5i)\n", i, sin_tab[4*SIN_LEN+i], tl_tab[sin_tab[4*SIN_LEN+i]] ); + //logerror("YMF262.C: sin5[%4i]= %4i (tl_tab value=%5i)\n", i, sin_tab[5*SIN_LEN+i], tl_tab[sin_tab[5*SIN_LEN+i]] ); + //logerror("YMF262.C: sin6[%4i]= %4i (tl_tab value=%5i)\n", i, sin_tab[6*SIN_LEN+i], tl_tab[sin_tab[6*SIN_LEN+i]] ); + //logerror("YMF262.C: sin7[%4i]= %4i (tl_tab value=%5i)\n", i, sin_tab[7*SIN_LEN+i], tl_tab[sin_tab[7*SIN_LEN+i]] ); + } + /*logerror("YMF262.C: ENV_QUIET= %08x (dec*8=%i)\n", ENV_QUIET, ENV_QUIET*8 );*/ + +#ifdef SAVE_SAMPLE + sample[0]=fopen("sampsum.pcm","wb"); +#endif + + return 1; +} + +static void OPLCloseTable( void ) +{ +#ifdef SAVE_SAMPLE + fclose(sample[0]); +#endif +} + + + +static void OPL3_initalize(OPL3 *chip) +{ + int i; + + /* frequency base */ + chip->freqbase = (chip->rate) ? ((double)chip->clock / (8.0*36)) / chip->rate : 0; +#if 0 + chip->rate = (double)chip->clock / (8.0*36); + chip->freqbase = 1.0; +#endif + + /* logerror("YMF262: freqbase=%f\n", chip->freqbase); */ + + /* Timer base time */ + chip->TimerBase = attotime::from_hz(chip->clock) * (8*36); + + /* make fnumber -> increment counter table */ + for( i=0 ; i < 1024 ; i++ ) + { + /* opn phase increment counter = 20bit */ + chip->fn_tab[i] = (UINT32)( (double)i * 64 * chip->freqbase * (1<<(FREQ_SH-10)) ); /* -10 because chip works with 10.10 fixed point, while we use 16.16 */ +#if 0 + logerror("YMF262.C: fn_tab[%4i] = %08x (dec=%8i)\n", + i, chip->fn_tab[i]>>6, chip->fn_tab[i]>>6 ); +#endif + } + +#if 0 + for( i=0 ; i < 16 ; i++ ) + { + logerror("YMF262.C: sl_tab[%i] = %08x\n", + i, sl_tab[i] ); + } + for( i=0 ; i < 8 ; i++ ) + { + int j; + logerror("YMF262.C: ksl_tab[oct=%2i] =",i); + for (j=0; j<16; j++) + { + logerror("%08x ", ksl_tab[i*16+j] ); + } + logerror("\n"); + } +#endif + + + /* Amplitude modulation: 27 output levels (triangle waveform); 1 level takes one of: 192, 256 or 448 samples */ + /* One entry from LFO_AM_TABLE lasts for 64 samples */ + chip->lfo_am_inc = (1.0 / 64.0 ) * (1<freqbase; + + /* Vibrato: 8 output levels (triangle waveform); 1 level takes 1024 samples */ + chip->lfo_pm_inc = (1.0 / 1024.0) * (1<freqbase; + + /*logerror ("chip->lfo_am_inc = %8x ; chip->lfo_pm_inc = %8x\n", chip->lfo_am_inc, chip->lfo_pm_inc);*/ + + /* Noise generator: a step takes 1 sample */ + chip->noise_f = (1.0 / 1.0) * (1<freqbase; + + chip->eg_timer_add = (1<freqbase; + chip->eg_timer_overflow = ( 1 ) * (1<eg_timer_add, chip->eg_timer_overflow);*/ + +} + +INLINE void FM_KEYON(OPL3_SLOT *SLOT, UINT32 key_set) +{ + if( !SLOT->key ) + { + /* restart Phase Generator */ + SLOT->Cnt = 0; + /* phase -> Attack */ + SLOT->state = EG_ATT; + } + SLOT->key |= key_set; +} + +INLINE void FM_KEYOFF(OPL3_SLOT *SLOT, UINT32 key_clr) +{ + if( SLOT->key ) + { + SLOT->key &= key_clr; + + if( !SLOT->key ) + { + /* phase -> Release */ + if (SLOT->state>EG_REL) + SLOT->state = EG_REL; + } + } +} + +/* update phase increment counter of operator (also update the EG rates if necessary) */ +INLINE void CALC_FCSLOT(OPL3_CH *CH,OPL3_SLOT *SLOT) +{ + int ksr; + + /* (frequency) phase increment counter */ + SLOT->Incr = CH->fc * SLOT->mul; + ksr = CH->kcode >> SLOT->KSR; + + if( SLOT->ksr != ksr ) + { + SLOT->ksr = ksr; + + /* calculate envelope generator rates */ + if ((SLOT->ar + SLOT->ksr) < 16+60) + { + SLOT->eg_sh_ar = eg_rate_shift [SLOT->ar + SLOT->ksr ]; + SLOT->eg_m_ar = (1<eg_sh_ar)-1; + SLOT->eg_sel_ar = eg_rate_select[SLOT->ar + SLOT->ksr ]; + } + else + { + SLOT->eg_sh_ar = 0; + SLOT->eg_m_ar = (1<eg_sh_ar)-1; + SLOT->eg_sel_ar = 13*RATE_STEPS; + } + SLOT->eg_sh_dr = eg_rate_shift [SLOT->dr + SLOT->ksr ]; + SLOT->eg_m_dr = (1<eg_sh_dr)-1; + SLOT->eg_sel_dr = eg_rate_select[SLOT->dr + SLOT->ksr ]; + SLOT->eg_sh_rr = eg_rate_shift [SLOT->rr + SLOT->ksr ]; + SLOT->eg_m_rr = (1<eg_sh_rr)-1; + SLOT->eg_sel_rr = eg_rate_select[SLOT->rr + SLOT->ksr ]; + } +} + +/* set multi,am,vib,EG-TYP,KSR,mul */ +INLINE void set_mul(OPL3 *chip,int slot,int v) +{ + OPL3_CH *CH = &chip->P_CH[slot/2]; + OPL3_SLOT *SLOT = &CH->SLOT[slot&1]; + + SLOT->mul = mul_tab[v&0x0f]; + SLOT->KSR = (v&0x10) ? 0 : 2; + SLOT->eg_type = (v&0x20); + SLOT->vib = (v&0x40); + SLOT->AMmask = (v&0x80) ? ~0 : 0; + + if (chip->OPL3_mode & 1) + { + int chan_no = slot/2; + + /* in OPL3 mode */ + //DO THIS: + //if this is one of the slots of 1st channel forming up a 4-op channel + //do normal operation + //else normal 2 operator function + //OR THIS: + //if this is one of the slots of 2nd channel forming up a 4-op channel + //update it using channel data of 1st channel of a pair + //else normal 2 operator function + switch(chan_no) + { + case 0: case 1: case 2: + case 9: case 10: case 11: + if (CH->extended) + { + /* normal */ + CALC_FCSLOT(CH,SLOT); + } + else + { + /* normal */ + CALC_FCSLOT(CH,SLOT); + } + break; + case 3: case 4: case 5: + case 12: case 13: case 14: + if ((CH-3)->extended) + { + /* update this SLOT using frequency data for 1st channel of a pair */ + CALC_FCSLOT(CH-3,SLOT); + } + else + { + /* normal */ + CALC_FCSLOT(CH,SLOT); + } + break; + default: + /* normal */ + CALC_FCSLOT(CH,SLOT); + break; + } + } + else + { + /* in OPL2 mode */ + CALC_FCSLOT(CH,SLOT); + } +} + +/* set ksl & tl */ +INLINE void set_ksl_tl(OPL3 *chip,int slot,int v) +{ + OPL3_CH *CH = &chip->P_CH[slot/2]; + OPL3_SLOT *SLOT = &CH->SLOT[slot&1]; + + SLOT->ksl = ksl_shift[v >> 6]; + SLOT->TL = (v&0x3f)<<(ENV_BITS-1-7); /* 7 bits TL (bit 6 = always 0) */ + + if (chip->OPL3_mode & 1) + { + int chan_no = slot/2; + + /* in OPL3 mode */ + //DO THIS: + //if this is one of the slots of 1st channel forming up a 4-op channel + //do normal operation + //else normal 2 operator function + //OR THIS: + //if this is one of the slots of 2nd channel forming up a 4-op channel + //update it using channel data of 1st channel of a pair + //else normal 2 operator function + switch(chan_no) + { + case 0: case 1: case 2: + case 9: case 10: case 11: + if (CH->extended) + { + /* normal */ + SLOT->TLL = SLOT->TL + (CH->ksl_base>>SLOT->ksl); + } + else + { + /* normal */ + SLOT->TLL = SLOT->TL + (CH->ksl_base>>SLOT->ksl); + } + break; + case 3: case 4: case 5: + case 12: case 13: case 14: + if ((CH-3)->extended) + { + /* update this SLOT using frequency data for 1st channel of a pair */ + SLOT->TLL = SLOT->TL + ((CH-3)->ksl_base>>SLOT->ksl); + } + else + { + /* normal */ + SLOT->TLL = SLOT->TL + (CH->ksl_base>>SLOT->ksl); + } + break; + default: + /* normal */ + SLOT->TLL = SLOT->TL + (CH->ksl_base>>SLOT->ksl); + break; + } + } + else + { + /* in OPL2 mode */ + SLOT->TLL = SLOT->TL + (CH->ksl_base>>SLOT->ksl); + } + +} + +/* set attack rate & decay rate */ +INLINE void set_ar_dr(OPL3 *chip,int slot,int v) +{ + OPL3_CH *CH = &chip->P_CH[slot/2]; + OPL3_SLOT *SLOT = &CH->SLOT[slot&1]; + + SLOT->ar = (v>>4) ? 16 + ((v>>4) <<2) : 0; + + if ((SLOT->ar + SLOT->ksr) < 16+60) /* verified on real YMF262 - all 15 x rates take "zero" time */ + { + SLOT->eg_sh_ar = eg_rate_shift [SLOT->ar + SLOT->ksr ]; + SLOT->eg_m_ar = (1<eg_sh_ar)-1; + SLOT->eg_sel_ar = eg_rate_select[SLOT->ar + SLOT->ksr ]; + } + else + { + SLOT->eg_sh_ar = 0; + SLOT->eg_m_ar = (1<eg_sh_ar)-1; + SLOT->eg_sel_ar = 13*RATE_STEPS; + } + + SLOT->dr = (v&0x0f)? 16 + ((v&0x0f)<<2) : 0; + SLOT->eg_sh_dr = eg_rate_shift [SLOT->dr + SLOT->ksr ]; + SLOT->eg_m_dr = (1<eg_sh_dr)-1; + SLOT->eg_sel_dr = eg_rate_select[SLOT->dr + SLOT->ksr ]; +} + +/* set sustain level & release rate */ +INLINE void set_sl_rr(OPL3 *chip,int slot,int v) +{ + OPL3_CH *CH = &chip->P_CH[slot/2]; + OPL3_SLOT *SLOT = &CH->SLOT[slot&1]; + + SLOT->sl = sl_tab[ v>>4 ]; + + SLOT->rr = (v&0x0f)? 16 + ((v&0x0f)<<2) : 0; + SLOT->eg_sh_rr = eg_rate_shift [SLOT->rr + SLOT->ksr ]; + SLOT->eg_m_rr = (1<eg_sh_rr)-1; + SLOT->eg_sel_rr = eg_rate_select[SLOT->rr + SLOT->ksr ]; +} + + +static void update_channels(OPL3 *chip, OPL3_CH *CH) +{ + /* update channel passed as a parameter and a channel at CH+=3; */ + if (CH->extended) + { /* we've just switched to combined 4 operator mode */ + + } + else + { /* we've just switched to normal 2 operator mode */ + + } + +} + +/* write a value v to register r on OPL chip */ +static void OPL3WriteReg(OPL3 *chip, int r, int v) +{ + OPL3_CH *CH; + signed int *chanout = chip->chanout; + unsigned int ch_offset = 0; + int slot; + int block_fnum; + + + + if (LOG_CYM_FILE && (cymfile) && ((r&255)!=0) && (r!=255) ) + { + if (r>0xff) + fputc( (unsigned char)0xff, cymfile );/*mark writes to second register set*/ + + fputc( (unsigned char)r&0xff, cymfile ); + fputc( (unsigned char)v, cymfile ); + } + + if(r&0x100) + { + switch(r) + { + case 0x101: /* test register */ + return; + + case 0x104: /* 6 channels enable */ + { + UINT8 prev; + + CH = &chip->P_CH[0]; /* channel 0 */ + prev = CH->extended; + CH->extended = (v>>0) & 1; + if(prev != CH->extended) + update_channels(chip, CH); + CH++; /* channel 1 */ + prev = CH->extended; + CH->extended = (v>>1) & 1; + if(prev != CH->extended) + update_channels(chip, CH); + CH++; /* channel 2 */ + prev = CH->extended; + CH->extended = (v>>2) & 1; + if(prev != CH->extended) + update_channels(chip, CH); + + + CH = &chip->P_CH[9]; /* channel 9 */ + prev = CH->extended; + CH->extended = (v>>3) & 1; + if(prev != CH->extended) + update_channels(chip, CH); + CH++; /* channel 10 */ + prev = CH->extended; + CH->extended = (v>>4) & 1; + if(prev != CH->extended) + update_channels(chip, CH); + CH++; /* channel 11 */ + prev = CH->extended; + CH->extended = (v>>5) & 1; + if(prev != CH->extended) + update_channels(chip, CH); + + } + return; + + case 0x105: /* OPL3 extensions enable register */ + + chip->OPL3_mode = v&0x01; /* OPL3 mode when bit0=1 otherwise it is OPL2 mode */ + + /* following behaviour was tested on real YMF262, + switching OPL3/OPL2 modes on the fly: + - does not change the waveform previously selected (unless when ....) + - does not update CH.A, CH.B, CH.C and CH.D output selectors (registers c0-c8) (unless when ....) + - does not disable channels 9-17 on OPL3->OPL2 switch + - does not switch 4 operator channels back to 2 operator channels + */ + + return; + + default: + if (r < 0x120) + logerror("YMF262: write to unknown register (set#2): %03x value=%02x\n",r,v); + break; + } + + ch_offset = 9; /* register page #2 starts from channel 9 (counting from 0) */ + } + + /* adjust bus to 8 bits */ + r &= 0xff; + v &= 0xff; + + + switch(r&0xe0) + { + case 0x00: /* 00-1f:control */ + switch(r&0x1f) + { + case 0x01: /* test register */ + break; + case 0x02: /* Timer 1 */ + chip->T[0] = (256-v)*4; + break; + case 0x03: /* Timer 2 */ + chip->T[1] = (256-v)*16; + break; + case 0x04: /* IRQ clear / mask and Timer enable */ + if(v&0x80) + { /* IRQ flags clear */ + OPL3_STATUS_RESET(chip,0x60); + } + else + { /* set IRQ mask ,timer enable */ + UINT8 st1 = v & 1; + UINT8 st2 = (v>>1) & 1; + + /* IRQRST,T1MSK,t2MSK,x,x,x,ST2,ST1 */ + OPL3_STATUS_RESET(chip, v & 0x60); + OPL3_STATUSMASK_SET(chip, (~v) & 0x60 ); + + /* timer 2 */ + if(chip->st[1] != st2) + { + attotime period = st2 ? chip->TimerBase * chip->T[1] : attotime::zero; + chip->st[1] = st2; + if (chip->timer_handler) (chip->timer_handler)(chip->TimerParam,1,period); + } + /* timer 1 */ + if(chip->st[0] != st1) + { + attotime period = st1 ? chip->TimerBase * chip->T[0] : attotime::zero; + chip->st[0] = st1; + if (chip->timer_handler) (chip->timer_handler)(chip->TimerParam,0,period); + } + } + break; + case 0x08: /* x,NTS,x,x, x,x,x,x */ + chip->nts = v; + break; + + default: + logerror("YMF262: write to unknown register: %02x value=%02x\n",r,v); + break; + } + break; + case 0x20: /* am ON, vib ON, ksr, eg_type, mul */ + slot = slot_array[r&0x1f]; + if(slot < 0) return; + set_mul(chip, slot + ch_offset*2, v); + break; + case 0x40: + slot = slot_array[r&0x1f]; + if(slot < 0) return; + set_ksl_tl(chip, slot + ch_offset*2, v); + break; + case 0x60: + slot = slot_array[r&0x1f]; + if(slot < 0) return; + set_ar_dr(chip, slot + ch_offset*2, v); + break; + case 0x80: + slot = slot_array[r&0x1f]; + if(slot < 0) return; + set_sl_rr(chip, slot + ch_offset*2, v); + break; + case 0xa0: + if (r == 0xbd) /* am depth, vibrato depth, r,bd,sd,tom,tc,hh */ + { + if (ch_offset != 0) /* 0xbd register is present in set #1 only */ + return; + + chip->lfo_am_depth = v & 0x80; + chip->lfo_pm_depth_range = (v&0x40) ? 8 : 0; + + chip->rhythm = v&0x3f; + + if(chip->rhythm&0x20) + { + /* BD key on/off */ + if(v&0x10) + { + FM_KEYON (&chip->P_CH[6].SLOT[SLOT1], 2); + FM_KEYON (&chip->P_CH[6].SLOT[SLOT2], 2); + } + else + { + FM_KEYOFF(&chip->P_CH[6].SLOT[SLOT1],~2); + FM_KEYOFF(&chip->P_CH[6].SLOT[SLOT2],~2); + } + /* HH key on/off */ + if(v&0x01) FM_KEYON (&chip->P_CH[7].SLOT[SLOT1], 2); + else FM_KEYOFF(&chip->P_CH[7].SLOT[SLOT1],~2); + /* SD key on/off */ + if(v&0x08) FM_KEYON (&chip->P_CH[7].SLOT[SLOT2], 2); + else FM_KEYOFF(&chip->P_CH[7].SLOT[SLOT2],~2); + /* TOM key on/off */ + if(v&0x04) FM_KEYON (&chip->P_CH[8].SLOT[SLOT1], 2); + else FM_KEYOFF(&chip->P_CH[8].SLOT[SLOT1],~2); + /* TOP-CY key on/off */ + if(v&0x02) FM_KEYON (&chip->P_CH[8].SLOT[SLOT2], 2); + else FM_KEYOFF(&chip->P_CH[8].SLOT[SLOT2],~2); + } + else + { + /* BD key off */ + FM_KEYOFF(&chip->P_CH[6].SLOT[SLOT1],~2); + FM_KEYOFF(&chip->P_CH[6].SLOT[SLOT2],~2); + /* HH key off */ + FM_KEYOFF(&chip->P_CH[7].SLOT[SLOT1],~2); + /* SD key off */ + FM_KEYOFF(&chip->P_CH[7].SLOT[SLOT2],~2); + /* TOM key off */ + FM_KEYOFF(&chip->P_CH[8].SLOT[SLOT1],~2); + /* TOP-CY off */ + FM_KEYOFF(&chip->P_CH[8].SLOT[SLOT2],~2); + } + return; + } + + /* keyon,block,fnum */ + if( (r&0x0f) > 8) return; + CH = &chip->P_CH[(r&0x0f) + ch_offset]; + + if(!(r&0x10)) + { /* a0-a8 */ + block_fnum = (CH->block_fnum&0x1f00) | v; + } + else + { /* b0-b8 */ + block_fnum = ((v&0x1f)<<8) | (CH->block_fnum&0xff); + + if (chip->OPL3_mode & 1) + { + int chan_no = (r&0x0f) + ch_offset; + + /* in OPL3 mode */ + //DO THIS: + //if this is 1st channel forming up a 4-op channel + //ALSO keyon/off slots of 2nd channel forming up 4-op channel + //else normal 2 operator function keyon/off + //OR THIS: + //if this is 2nd channel forming up 4-op channel just do nothing + //else normal 2 operator function keyon/off + switch(chan_no) + { + case 0: case 1: case 2: + case 9: case 10: case 11: + if (CH->extended) + { + //if this is 1st channel forming up a 4-op channel + //ALSO keyon/off slots of 2nd channel forming up 4-op channel + if(v&0x20) + { + FM_KEYON (&CH->SLOT[SLOT1], 1); + FM_KEYON (&CH->SLOT[SLOT2], 1); + FM_KEYON (&(CH+3)->SLOT[SLOT1], 1); + FM_KEYON (&(CH+3)->SLOT[SLOT2], 1); + } + else + { + FM_KEYOFF(&CH->SLOT[SLOT1],~1); + FM_KEYOFF(&CH->SLOT[SLOT2],~1); + FM_KEYOFF(&(CH+3)->SLOT[SLOT1],~1); + FM_KEYOFF(&(CH+3)->SLOT[SLOT2],~1); + } + } + else + { + //else normal 2 operator function keyon/off + if(v&0x20) + { + FM_KEYON (&CH->SLOT[SLOT1], 1); + FM_KEYON (&CH->SLOT[SLOT2], 1); + } + else + { + FM_KEYOFF(&CH->SLOT[SLOT1],~1); + FM_KEYOFF(&CH->SLOT[SLOT2],~1); + } + } + break; + + case 3: case 4: case 5: + case 12: case 13: case 14: + if ((CH-3)->extended) + { + //if this is 2nd channel forming up 4-op channel just do nothing + } + else + { + //else normal 2 operator function keyon/off + if(v&0x20) + { + FM_KEYON (&CH->SLOT[SLOT1], 1); + FM_KEYON (&CH->SLOT[SLOT2], 1); + } + else + { + FM_KEYOFF(&CH->SLOT[SLOT1],~1); + FM_KEYOFF(&CH->SLOT[SLOT2],~1); + } + } + break; + + default: + if(v&0x20) + { + FM_KEYON (&CH->SLOT[SLOT1], 1); + FM_KEYON (&CH->SLOT[SLOT2], 1); + } + else + { + FM_KEYOFF(&CH->SLOT[SLOT1],~1); + FM_KEYOFF(&CH->SLOT[SLOT2],~1); + } + break; + } + } + else + { + if(v&0x20) + { + FM_KEYON (&CH->SLOT[SLOT1], 1); + FM_KEYON (&CH->SLOT[SLOT2], 1); + } + else + { + FM_KEYOFF(&CH->SLOT[SLOT1],~1); + FM_KEYOFF(&CH->SLOT[SLOT2],~1); + } + } + } + /* update */ + if(CH->block_fnum != block_fnum) + { + UINT8 block = block_fnum >> 10; + + CH->block_fnum = block_fnum; + + CH->ksl_base = ksl_tab[block_fnum>>6]; + CH->fc = chip->fn_tab[block_fnum&0x03ff] >> (7-block); + + /* BLK 2,1,0 bits -> bits 3,2,1 of kcode */ + CH->kcode = (CH->block_fnum&0x1c00)>>9; + + /* the info below is actually opposite to what is stated in the Manuals (verifed on real YMF262) */ + /* if notesel == 0 -> lsb of kcode is bit 10 (MSB) of fnum */ + /* if notesel == 1 -> lsb of kcode is bit 9 (MSB-1) of fnum */ + if (chip->nts&0x40) + CH->kcode |= (CH->block_fnum&0x100)>>8; /* notesel == 1 */ + else + CH->kcode |= (CH->block_fnum&0x200)>>9; /* notesel == 0 */ + + if (chip->OPL3_mode & 1) + { + int chan_no = (r&0x0f) + ch_offset; + /* in OPL3 mode */ + //DO THIS: + //if this is 1st channel forming up a 4-op channel + //ALSO update slots of 2nd channel forming up 4-op channel + //else normal 2 operator function keyon/off + //OR THIS: + //if this is 2nd channel forming up 4-op channel just do nothing + //else normal 2 operator function keyon/off + switch(chan_no) + { + case 0: case 1: case 2: + case 9: case 10: case 11: + if (CH->extended) + { + //if this is 1st channel forming up a 4-op channel + //ALSO update slots of 2nd channel forming up 4-op channel + + /* refresh Total Level in FOUR SLOTs of this channel and channel+3 using data from THIS channel */ + CH->SLOT[SLOT1].TLL = CH->SLOT[SLOT1].TL + (CH->ksl_base>>CH->SLOT[SLOT1].ksl); + CH->SLOT[SLOT2].TLL = CH->SLOT[SLOT2].TL + (CH->ksl_base>>CH->SLOT[SLOT2].ksl); + (CH+3)->SLOT[SLOT1].TLL = (CH+3)->SLOT[SLOT1].TL + (CH->ksl_base>>(CH+3)->SLOT[SLOT1].ksl); + (CH+3)->SLOT[SLOT2].TLL = (CH+3)->SLOT[SLOT2].TL + (CH->ksl_base>>(CH+3)->SLOT[SLOT2].ksl); + + /* refresh frequency counter in FOUR SLOTs of this channel and channel+3 using data from THIS channel */ + CALC_FCSLOT(CH,&CH->SLOT[SLOT1]); + CALC_FCSLOT(CH,&CH->SLOT[SLOT2]); + CALC_FCSLOT(CH,&(CH+3)->SLOT[SLOT1]); + CALC_FCSLOT(CH,&(CH+3)->SLOT[SLOT2]); + } + else + { + //else normal 2 operator function + /* refresh Total Level in both SLOTs of this channel */ + CH->SLOT[SLOT1].TLL = CH->SLOT[SLOT1].TL + (CH->ksl_base>>CH->SLOT[SLOT1].ksl); + CH->SLOT[SLOT2].TLL = CH->SLOT[SLOT2].TL + (CH->ksl_base>>CH->SLOT[SLOT2].ksl); + + /* refresh frequency counter in both SLOTs of this channel */ + CALC_FCSLOT(CH,&CH->SLOT[SLOT1]); + CALC_FCSLOT(CH,&CH->SLOT[SLOT2]); + } + break; + + case 3: case 4: case 5: + case 12: case 13: case 14: + if ((CH-3)->extended) + { + //if this is 2nd channel forming up 4-op channel just do nothing + } + else + { + //else normal 2 operator function + /* refresh Total Level in both SLOTs of this channel */ + CH->SLOT[SLOT1].TLL = CH->SLOT[SLOT1].TL + (CH->ksl_base>>CH->SLOT[SLOT1].ksl); + CH->SLOT[SLOT2].TLL = CH->SLOT[SLOT2].TL + (CH->ksl_base>>CH->SLOT[SLOT2].ksl); + + /* refresh frequency counter in both SLOTs of this channel */ + CALC_FCSLOT(CH,&CH->SLOT[SLOT1]); + CALC_FCSLOT(CH,&CH->SLOT[SLOT2]); + } + break; + + default: + /* refresh Total Level in both SLOTs of this channel */ + CH->SLOT[SLOT1].TLL = CH->SLOT[SLOT1].TL + (CH->ksl_base>>CH->SLOT[SLOT1].ksl); + CH->SLOT[SLOT2].TLL = CH->SLOT[SLOT2].TL + (CH->ksl_base>>CH->SLOT[SLOT2].ksl); + + /* refresh frequency counter in both SLOTs of this channel */ + CALC_FCSLOT(CH,&CH->SLOT[SLOT1]); + CALC_FCSLOT(CH,&CH->SLOT[SLOT2]); + break; + } + } + else + { + /* in OPL2 mode */ + + /* refresh Total Level in both SLOTs of this channel */ + CH->SLOT[SLOT1].TLL = CH->SLOT[SLOT1].TL + (CH->ksl_base>>CH->SLOT[SLOT1].ksl); + CH->SLOT[SLOT2].TLL = CH->SLOT[SLOT2].TL + (CH->ksl_base>>CH->SLOT[SLOT2].ksl); + + /* refresh frequency counter in both SLOTs of this channel */ + CALC_FCSLOT(CH,&CH->SLOT[SLOT1]); + CALC_FCSLOT(CH,&CH->SLOT[SLOT2]); + } + } + break; + + case 0xc0: + /* CH.D, CH.C, CH.B, CH.A, FB(3bits), C */ + if( (r&0xf) > 8) return; + + CH = &chip->P_CH[(r&0xf) + ch_offset]; + + if( chip->OPL3_mode & 1 ) + { + int base = ((r&0xf) + ch_offset) * 4; + + /* OPL3 mode */ + chip->pan[ base ] = (v & 0x10) ? ~0 : 0; /* ch.A */ + chip->pan[ base +1 ] = (v & 0x20) ? ~0 : 0; /* ch.B */ + chip->pan[ base +2 ] = (v & 0x40) ? ~0 : 0; /* ch.C */ + chip->pan[ base +3 ] = (v & 0x80) ? ~0 : 0; /* ch.D */ + } + else + { + int base = ((r&0xf) + ch_offset) * 4; + + /* OPL2 mode - always enabled */ + chip->pan[ base ] = ~0; /* ch.A */ + chip->pan[ base +1 ] = ~0; /* ch.B */ + chip->pan[ base +2 ] = ~0; /* ch.C */ + chip->pan[ base +3 ] = ~0; /* ch.D */ + } + + chip->pan_ctrl_value[ (r&0xf) + ch_offset ] = v; /* store control value for OPL3/OPL2 mode switching on the fly */ + + CH->SLOT[SLOT1].FB = (v>>1)&7 ? ((v>>1)&7) + 7 : 0; + CH->SLOT[SLOT1].CON = v&1; + + if( chip->OPL3_mode & 1 ) + { + int chan_no = (r&0x0f) + ch_offset; + + switch(chan_no) + { + case 0: case 1: case 2: + case 9: case 10: case 11: + if (CH->extended) + { + UINT8 conn = (CH->SLOT[SLOT1].CON<<1) | ((CH+3)->SLOT[SLOT1].CON<<0); + switch(conn) + { + case 0: + /* 1 -> 2 -> 3 -> 4 - out */ + + CH->SLOT[SLOT1].connect = &chip->phase_modulation; + CH->SLOT[SLOT2].connect = &chip->phase_modulation2; + (CH+3)->SLOT[SLOT1].connect = &chip->phase_modulation; + (CH+3)->SLOT[SLOT2].connect = &chanout[ chan_no + 3 ]; + break; + case 1: + /* 1 -> 2 -\ + 3 -> 4 -+- out */ + + CH->SLOT[SLOT1].connect = &chip->phase_modulation; + CH->SLOT[SLOT2].connect = &chanout[ chan_no ]; + (CH+3)->SLOT[SLOT1].connect = &chip->phase_modulation; + (CH+3)->SLOT[SLOT2].connect = &chanout[ chan_no + 3 ]; + break; + case 2: + /* 1 -----------\ + 2 -> 3 -> 4 -+- out */ + + CH->SLOT[SLOT1].connect = &chanout[ chan_no ]; + CH->SLOT[SLOT2].connect = &chip->phase_modulation2; + (CH+3)->SLOT[SLOT1].connect = &chip->phase_modulation; + (CH+3)->SLOT[SLOT2].connect = &chanout[ chan_no + 3 ]; + break; + case 3: + /* 1 ------\ + 2 -> 3 -+- out + 4 ------/ */ + CH->SLOT[SLOT1].connect = &chanout[ chan_no ]; + CH->SLOT[SLOT2].connect = &chip->phase_modulation2; + (CH+3)->SLOT[SLOT1].connect = &chanout[ chan_no + 3 ]; + (CH+3)->SLOT[SLOT2].connect = &chanout[ chan_no + 3 ]; + break; + } + } + else + { + /* 2 operators mode */ + CH->SLOT[SLOT1].connect = CH->SLOT[SLOT1].CON ? &chanout[(r&0xf)+ch_offset] : &chip->phase_modulation; + CH->SLOT[SLOT2].connect = &chanout[(r&0xf)+ch_offset]; + } + break; + + case 3: case 4: case 5: + case 12: case 13: case 14: + if ((CH-3)->extended) + { + UINT8 conn = ((CH-3)->SLOT[SLOT1].CON<<1) | (CH->SLOT[SLOT1].CON<<0); + switch(conn) + { + case 0: + /* 1 -> 2 -> 3 -> 4 - out */ + + (CH-3)->SLOT[SLOT1].connect = &chip->phase_modulation; + (CH-3)->SLOT[SLOT2].connect = &chip->phase_modulation2; + CH->SLOT[SLOT1].connect = &chip->phase_modulation; + CH->SLOT[SLOT2].connect = &chanout[ chan_no ]; + break; + case 1: + /* 1 -> 2 -\ + 3 -> 4 -+- out */ + + (CH-3)->SLOT[SLOT1].connect = &chip->phase_modulation; + (CH-3)->SLOT[SLOT2].connect = &chanout[ chan_no - 3 ]; + CH->SLOT[SLOT1].connect = &chip->phase_modulation; + CH->SLOT[SLOT2].connect = &chanout[ chan_no ]; + break; + case 2: + /* 1 -----------\ + 2 -> 3 -> 4 -+- out */ + + (CH-3)->SLOT[SLOT1].connect = &chanout[ chan_no - 3 ]; + (CH-3)->SLOT[SLOT2].connect = &chip->phase_modulation2; + CH->SLOT[SLOT1].connect = &chip->phase_modulation; + CH->SLOT[SLOT2].connect = &chanout[ chan_no ]; + break; + case 3: + /* 1 ------\ + 2 -> 3 -+- out + 4 ------/ */ + (CH-3)->SLOT[SLOT1].connect = &chanout[ chan_no - 3 ]; + (CH-3)->SLOT[SLOT2].connect = &chip->phase_modulation2; + CH->SLOT[SLOT1].connect = &chanout[ chan_no ]; + CH->SLOT[SLOT2].connect = &chanout[ chan_no ]; + break; + } + } + else + { + /* 2 operators mode */ + CH->SLOT[SLOT1].connect = CH->SLOT[SLOT1].CON ? &chanout[(r&0xf)+ch_offset] : &chip->phase_modulation; + CH->SLOT[SLOT2].connect = &chanout[(r&0xf)+ch_offset]; + } + break; + + default: + /* 2 operators mode */ + CH->SLOT[SLOT1].connect = CH->SLOT[SLOT1].CON ? &chanout[(r&0xf)+ch_offset] : &chip->phase_modulation; + CH->SLOT[SLOT2].connect = &chanout[(r&0xf)+ch_offset]; + break; + } + } + else + { + /* OPL2 mode - always 2 operators mode */ + CH->SLOT[SLOT1].connect = CH->SLOT[SLOT1].CON ? &chanout[(r&0xf)+ch_offset] : &chip->phase_modulation; + CH->SLOT[SLOT2].connect = &chanout[(r&0xf)+ch_offset]; + } + break; + + case 0xe0: /* waveform select */ + slot = slot_array[r&0x1f]; + if(slot < 0) return; + + slot += ch_offset*2; + + CH = &chip->P_CH[slot/2]; + + + /* store 3-bit value written regardless of current OPL2 or OPL3 mode... (verified on real YMF262) */ + v &= 7; + CH->SLOT[slot&1].waveform_number = v; + + /* ... but select only waveforms 0-3 in OPL2 mode */ + if( !(chip->OPL3_mode & 1) ) + { + v &= 3; /* we're in OPL2 mode */ + } + CH->SLOT[slot&1].wavetable = v * SIN_LEN; + break; + } +} + +static TIMER_CALLBACK( cymfile_callback ) +{ + if (cymfile) + { + fputc( (unsigned char)0, cymfile ); + } +} + +/* lock/unlock for common table */ +static int OPL3_LockTable(device_t *device) +{ + num_lock++; + if(num_lock>1) return 0; + + /* first time */ + + if( !init_tables() ) + { + num_lock--; + return -1; + } + + if (LOG_CYM_FILE) + { + cymfile = fopen("ymf262_.cym","wb"); + if (cymfile) + device->machine().scheduler().timer_pulse ( attotime::from_hz(110), FUNC(cymfile_callback)); /*110 Hz pulse timer*/ + else + logerror("Could not create ymf262_.cym file\n"); + } + + return 0; +} + +static void OPL3_UnLockTable(void) +{ + if(num_lock) num_lock--; + if(num_lock) return; + + /* last time */ + OPLCloseTable(); + + if (LOG_CYM_FILE) + fclose (cymfile); + cymfile = NULL; +} + +static void OPL3ResetChip(OPL3 *chip) +{ + int c,s; + + chip->eg_timer = 0; + chip->eg_cnt = 0; + + chip->noise_rng = 1; /* noise shift register */ + chip->nts = 0; /* note split */ + OPL3_STATUS_RESET(chip,0x60); + + /* reset with register write */ + OPL3WriteReg(chip,0x01,0); /* test register */ + OPL3WriteReg(chip,0x02,0); /* Timer1 */ + OPL3WriteReg(chip,0x03,0); /* Timer2 */ + OPL3WriteReg(chip,0x04,0); /* IRQ mask clear */ + + +//FIX IT registers 101, 104 and 105 + + +//FIX IT (dont change CH.D, CH.C, CH.B and CH.A in C0-C8 registers) + for(c = 0xff ; c >= 0x20 ; c-- ) + OPL3WriteReg(chip,c,0); +//FIX IT (dont change CH.D, CH.C, CH.B and CH.A in C0-C8 registers) + for(c = 0x1ff ; c >= 0x120 ; c-- ) + OPL3WriteReg(chip,c,0); + + + + /* reset operator parameters */ + for( c = 0 ; c < 9*2 ; c++ ) + { + OPL3_CH *CH = &chip->P_CH[c]; + for(s = 0 ; s < 2 ; s++ ) + { + CH->SLOT[s].state = EG_OFF; + CH->SLOT[s].volume = MAX_ATT_INDEX; + } + } +} + +/* Create one of virtual YMF262 */ +/* 'clock' is chip clock in Hz */ +/* 'rate' is sampling rate */ +static OPL3 *OPL3Create(device_t *device, int clock, int rate, int type) +{ + OPL3 *chip; + + if (OPL3_LockTable(device) == -1) return NULL; + + /* allocate memory block */ + chip = auto_alloc_clear(device->machine(), OPL3); + + chip->device = device; + chip->type = type; + chip->clock = clock; + chip->rate = rate; + + /* init global tables */ + OPL3_initalize(chip); + + /* reset chip */ + OPL3ResetChip(chip); + return chip; +} + +/* Destroy one of virtual YMF262 */ +static void OPL3Destroy(OPL3 *chip) +{ + OPL3_UnLockTable(); + auto_free(chip->device->machine(), chip); +} + + +/* Optional handlers */ + +static void OPL3SetTimerHandler(OPL3 *chip,OPL3_TIMERHANDLER timer_handler,void *param) +{ + chip->timer_handler = timer_handler; + chip->TimerParam = param; +} +static void OPL3SetIRQHandler(OPL3 *chip,OPL3_IRQHANDLER IRQHandler,void *param) +{ + chip->IRQHandler = IRQHandler; + chip->IRQParam = param; +} +static void OPL3SetUpdateHandler(OPL3 *chip,OPL3_UPDATEHANDLER UpdateHandler,void *param) +{ + chip->UpdateHandler = UpdateHandler; + chip->UpdateParam = param; +} + +/* YMF262 I/O interface */ +static int OPL3Write(OPL3 *chip, int a, int v) +{ + /* data bus is 8 bits */ + v &= 0xff; + + switch(a&3) + { + case 0: /* address port 0 (register set #1) */ + chip->address = v; + break; + + case 1: /* data port - ignore A1 */ + case 3: /* data port - ignore A1 */ + if(chip->UpdateHandler) chip->UpdateHandler(chip->UpdateParam,0); + OPL3WriteReg(chip,chip->address,v); + break; + + case 2: /* address port 1 (register set #2) */ + + /* verified on real YMF262: + in OPL3 mode: + address line A1 is stored during *address* write and ignored during *data* write. + + in OPL2 mode: + register set#2 writes go to register set#1 (ignoring A1) + verified on registers from set#2: 0x01, 0x04, 0x20-0xef + The only exception is register 0x05. + */ + if( chip->OPL3_mode & 1 ) + { + /* OPL3 mode */ + chip->address = v | 0x100; + } + else + { + /* in OPL2 mode the only accessible in set #2 is register 0x05 */ + if( v==5 ) + chip->address = v | 0x100; + else + chip->address = v; /* verified range: 0x01, 0x04, 0x20-0xef(set #2 becomes set #1 in opl2 mode) */ + } + break; + } + + return chip->status>>7; +} + +static unsigned char OPL3Read(OPL3 *chip,int a) +{ + if( a==0 ) + { + /* status port */ + return chip->status; + } + + return 0x00; /* verified on real YMF262 */ +} + + + +static int OPL3TimerOver(OPL3 *chip,int c) +{ + if( c ) + { /* Timer B */ + OPL3_STATUS_SET(chip,0x20); + } + else + { /* Timer A */ + OPL3_STATUS_SET(chip,0x40); + } + /* reload timer */ + if (chip->timer_handler) (chip->timer_handler)(chip->TimerParam,c,chip->TimerBase * chip->T[c]); + return chip->status>>7; +} + + + + +void * ymf262_init(device_t *device, int clock, int rate) +{ + return OPL3Create(device,clock,rate,OPL3_TYPE_YMF262); +} + +void ymf262_shutdown(void *chip) +{ + OPL3Destroy((OPL3 *)chip); +} +void ymf262_reset_chip(void *chip) +{ + OPL3ResetChip((OPL3 *)chip); +} + +int ymf262_write(void *chip, int a, int v) +{ + return OPL3Write((OPL3 *)chip, a, v); +} + +unsigned char ymf262_read(void *chip, int a) +{ + /* Note on status register: */ + + /* YM3526(OPL) and YM3812(OPL2) return bit2 and bit1 in HIGH state */ + + /* YMF262(OPL3) always returns bit2 and bit1 in LOW state */ + /* which can be used to identify the chip */ + + /* YMF278(OPL4) returns bit2 in LOW and bit1 in HIGH state ??? info from manual - not verified */ + + return OPL3Read((OPL3 *)chip, a); +} +int ymf262_timer_over(void *chip, int c) +{ + return OPL3TimerOver((OPL3 *)chip, c); +} + +void ymf262_set_timer_handler(void *chip, OPL3_TIMERHANDLER timer_handler, void *param) +{ + OPL3SetTimerHandler((OPL3 *)chip, timer_handler, param); +} +void ymf262_set_irq_handler(void *chip,OPL3_IRQHANDLER IRQHandler,void *param) +{ + OPL3SetIRQHandler((OPL3 *)chip, IRQHandler, param); +} +void ymf262_set_update_handler(void *chip,OPL3_UPDATEHANDLER UpdateHandler,void *param) +{ + OPL3SetUpdateHandler((OPL3 *)chip, UpdateHandler, param); +} + + +/* +** Generate samples for one of the YMF262's +** +** 'which' is the virtual YMF262 number +** '**buffers' is table of 4 pointers to the buffers: CH.A, CH.B, CH.C and CH.D +** 'length' is the number of samples that should be generated +*/ +void ymf262_update_one(void *_chip, OPL3SAMPLE **buffers, int length) +{ + int i; + OPL3 *chip = (OPL3 *)_chip; + signed int *chanout = chip->chanout; + UINT8 rhythm = chip->rhythm&0x20; + + OPL3SAMPLE *ch_a = buffers[0]; + OPL3SAMPLE *ch_b = buffers[1]; + OPL3SAMPLE *ch_c = buffers[2]; + OPL3SAMPLE *ch_d = buffers[3]; + + for( i=0; i < length ; i++ ) + { + int a,b,c,d; + + + advance_lfo(chip); + + /* clear channel outputs */ + memset(chip->chanout, 0, sizeof(chip->chanout)); + +#if 1 + /* register set #1 */ + chan_calc(chip, &chip->P_CH[0]); /* extended 4op ch#0 part 1 or 2op ch#0 */ + if (chip->P_CH[0].extended) + chan_calc_ext(chip, &chip->P_CH[3]); /* extended 4op ch#0 part 2 */ + else + chan_calc(chip, &chip->P_CH[3]); /* standard 2op ch#3 */ + + + chan_calc(chip, &chip->P_CH[1]); /* extended 4op ch#1 part 1 or 2op ch#1 */ + if (chip->P_CH[1].extended) + chan_calc_ext(chip, &chip->P_CH[4]); /* extended 4op ch#1 part 2 */ + else + chan_calc(chip, &chip->P_CH[4]); /* standard 2op ch#4 */ + + + chan_calc(chip, &chip->P_CH[2]); /* extended 4op ch#2 part 1 or 2op ch#2 */ + if (chip->P_CH[2].extended) + chan_calc_ext(chip, &chip->P_CH[5]); /* extended 4op ch#2 part 2 */ + else + chan_calc(chip, &chip->P_CH[5]); /* standard 2op ch#5 */ + + + if(!rhythm) + { + chan_calc(chip, &chip->P_CH[6]); + chan_calc(chip, &chip->P_CH[7]); + chan_calc(chip, &chip->P_CH[8]); + } + else /* Rhythm part */ + { + chan_calc_rhythm(chip, &chip->P_CH[0], (chip->noise_rng>>0)&1 ); + } + + /* register set #2 */ + chan_calc(chip, &chip->P_CH[ 9]); + if (chip->P_CH[9].extended) + chan_calc_ext(chip, &chip->P_CH[12]); + else + chan_calc(chip, &chip->P_CH[12]); + + + chan_calc(chip, &chip->P_CH[10]); + if (chip->P_CH[10].extended) + chan_calc_ext(chip, &chip->P_CH[13]); + else + chan_calc(chip, &chip->P_CH[13]); + + + chan_calc(chip, &chip->P_CH[11]); + if (chip->P_CH[11].extended) + chan_calc_ext(chip, &chip->P_CH[14]); + else + chan_calc(chip, &chip->P_CH[14]); + + + /* channels 15,16,17 are fixed 2-operator channels only */ + chan_calc(chip, &chip->P_CH[15]); + chan_calc(chip, &chip->P_CH[16]); + chan_calc(chip, &chip->P_CH[17]); +#endif + + /* accumulator register set #1 */ + a = chanout[0] & chip->pan[0]; + b = chanout[0] & chip->pan[1]; + c = chanout[0] & chip->pan[2]; + d = chanout[0] & chip->pan[3]; +#if 1 + a += chanout[1] & chip->pan[4]; + b += chanout[1] & chip->pan[5]; + c += chanout[1] & chip->pan[6]; + d += chanout[1] & chip->pan[7]; + a += chanout[2] & chip->pan[8]; + b += chanout[2] & chip->pan[9]; + c += chanout[2] & chip->pan[10]; + d += chanout[2] & chip->pan[11]; + + a += chanout[3] & chip->pan[12]; + b += chanout[3] & chip->pan[13]; + c += chanout[3] & chip->pan[14]; + d += chanout[3] & chip->pan[15]; + a += chanout[4] & chip->pan[16]; + b += chanout[4] & chip->pan[17]; + c += chanout[4] & chip->pan[18]; + d += chanout[4] & chip->pan[19]; + a += chanout[5] & chip->pan[20]; + b += chanout[5] & chip->pan[21]; + c += chanout[5] & chip->pan[22]; + d += chanout[5] & chip->pan[23]; + + a += chanout[6] & chip->pan[24]; + b += chanout[6] & chip->pan[25]; + c += chanout[6] & chip->pan[26]; + d += chanout[6] & chip->pan[27]; + a += chanout[7] & chip->pan[28]; + b += chanout[7] & chip->pan[29]; + c += chanout[7] & chip->pan[30]; + d += chanout[7] & chip->pan[31]; + a += chanout[8] & chip->pan[32]; + b += chanout[8] & chip->pan[33]; + c += chanout[8] & chip->pan[34]; + d += chanout[8] & chip->pan[35]; + + /* accumulator register set #2 */ + a += chanout[9] & chip->pan[36]; + b += chanout[9] & chip->pan[37]; + c += chanout[9] & chip->pan[38]; + d += chanout[9] & chip->pan[39]; + a += chanout[10] & chip->pan[40]; + b += chanout[10] & chip->pan[41]; + c += chanout[10] & chip->pan[42]; + d += chanout[10] & chip->pan[43]; + a += chanout[11] & chip->pan[44]; + b += chanout[11] & chip->pan[45]; + c += chanout[11] & chip->pan[46]; + d += chanout[11] & chip->pan[47]; + + a += chanout[12] & chip->pan[48]; + b += chanout[12] & chip->pan[49]; + c += chanout[12] & chip->pan[50]; + d += chanout[12] & chip->pan[51]; + a += chanout[13] & chip->pan[52]; + b += chanout[13] & chip->pan[53]; + c += chanout[13] & chip->pan[54]; + d += chanout[13] & chip->pan[55]; + a += chanout[14] & chip->pan[56]; + b += chanout[14] & chip->pan[57]; + c += chanout[14] & chip->pan[58]; + d += chanout[14] & chip->pan[59]; + + a += chanout[15] & chip->pan[60]; + b += chanout[15] & chip->pan[61]; + c += chanout[15] & chip->pan[62]; + d += chanout[15] & chip->pan[63]; + a += chanout[16] & chip->pan[64]; + b += chanout[16] & chip->pan[65]; + c += chanout[16] & chip->pan[66]; + d += chanout[16] & chip->pan[67]; + a += chanout[17] & chip->pan[68]; + b += chanout[17] & chip->pan[69]; + c += chanout[17] & chip->pan[70]; + d += chanout[17] & chip->pan[71]; +#endif + a >>= FINAL_SH; + b >>= FINAL_SH; + c >>= FINAL_SH; + d >>= FINAL_SH; + + /* limit check */ + a = limit( a , MAXOUT, MINOUT ); + b = limit( b , MAXOUT, MINOUT ); + c = limit( c , MAXOUT, MINOUT ); + d = limit( d , MAXOUT, MINOUT ); + + #ifdef SAVE_SAMPLE + if (which==0) + { + SAVE_ALL_CHANNELS + } + #endif + + /* store to sound buffer */ + ch_a[i] = a; + ch_b[i] = b; + ch_c[i] = c; + ch_d[i] = d; + + advance(chip); + } + +} diff --git a/src/devices/sound/ymf262.h b/src/devices/sound/ymf262.h new file mode 100644 index 00000000000..904b4f259c5 --- /dev/null +++ b/src/devices/sound/ymf262.h @@ -0,0 +1,50 @@ +// license:??? +// copyright-holders:Jarek Burczynski +#pragma once + +#ifndef __YMF262_H__ +#define __YMF262_H__ + +/* select number of output bits: 8 or 16 */ +#define OPL3_SAMPLE_BITS 16 + +/* compiler dependence */ +#ifndef __OSDCOMM_H__ +#define __OSDCOMM_H__ +typedef unsigned char UINT8; /* unsigned 8bit */ +typedef unsigned short UINT16; /* unsigned 16bit */ +typedef unsigned int UINT32; /* unsigned 32bit */ +typedef signed char INT8; /* signed 8bit */ +typedef signed short INT16; /* signed 16bit */ +typedef signed int INT32; /* signed 32bit */ +#endif + +typedef stream_sample_t OPL3SAMPLE; +/* +#if (OPL3_SAMPLE_BITS==16) +typedef INT16 OPL3SAMPLE; +#endif +#if (OPL3_SAMPLE_BITS==8) +typedef INT8 OPL3SAMPLE; +#endif +*/ + +typedef void (*OPL3_TIMERHANDLER)(void *param,int timer,const attotime &period); +typedef void (*OPL3_IRQHANDLER)(void *param,int irq); +typedef void (*OPL3_UPDATEHANDLER)(void *param,int min_interval_us); + + +void *ymf262_init(device_t *device, int clock, int rate); +void ymf262_shutdown(void *chip); +void ymf262_reset_chip(void *chip); +int ymf262_write(void *chip, int a, int v); +unsigned char ymf262_read(void *chip, int a); +int ymf262_timer_over(void *chip, int c); +void ymf262_update_one(void *chip, OPL3SAMPLE **buffers, int length); + +void ymf262_set_timer_handler(void *chip, OPL3_TIMERHANDLER TimerHandler, void *param); +void ymf262_set_irq_handler(void *chip, OPL3_IRQHANDLER IRQHandler, void *param); +void ymf262_set_update_handler(void *chip, OPL3_UPDATEHANDLER UpdateHandler, void *param); + + +#endif /* __YMF262_H__ */ diff --git a/src/devices/sound/ymf271.c b/src/devices/sound/ymf271.c new file mode 100644 index 00000000000..c10420af8a4 --- /dev/null +++ b/src/devices/sound/ymf271.c @@ -0,0 +1,1777 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert, R. Belmont, hap +/* + Yamaha YMF271-F "OPX" emulator v0.1 + By R. Belmont. + Based in part on YMF278B emulator by R. Belmont and O. Galibert. + 12June04 update by Toshiaki Nijiura + Copyright R. Belmont. + + TODO: + - A/L bit (alternate loop) + - EN and EXT Out bits + - Src B and Src NOTE bits + - statusreg Busy and End bits + - timer register 0x11 + - ch2/ch3 (4 speakers) + - PFM (FM using external PCM waveform) + - detune (should be same as on other Yamaha chips) + - Acc On bit (some sound effects in viprp1?). The documentation says + "determines if slot output is accumulated(1), or output directly(0)" + - Is memory handling 100% correct? At the moment, seibuspi.c is the only + hardware currently emulated that uses external handlers. +*/ + +#include "emu.h" +#include "ymf271.h" + +#define STD_CLOCK (16934400) + +#define MAXOUT (+32767) +#define MINOUT (-32768) + +#define SIN_BITS 10 +#define SIN_LEN (1<> 4; return (entry & 0x0f) << 7; + if(ex) } + return (ma | 16) << (ex+6); else + else { + return ma << 7; int shift = 6 + (entry >> 4); +} return (0x10 + (entry & 0x0f)) << shift; + } +lfo_freq = 44100 / lfo_period } + +*/ + +static const double LFO_frequency_table[256] = +{ + 0.00066, 0.00068, 0.00070, 0.00073, 0.00075, 0.00078, 0.00081, 0.00084, + 0.00088, 0.00091, 0.00096, 0.00100, 0.00105, 0.00111, 0.00117, 0.00124, + 0.00131, 0.00136, 0.00140, 0.00145, 0.00150, 0.00156, 0.00162, 0.00168, + 0.00175, 0.00183, 0.00191, 0.00200, 0.00210, 0.00221, 0.00234, 0.00247, + 0.00263, 0.00271, 0.00280, 0.00290, 0.00300, 0.00312, 0.00324, 0.00336, + 0.00350, 0.00366, 0.00382, 0.00401, 0.00421, 0.00443, 0.00467, 0.00495, + 0.00526, 0.00543, 0.00561, 0.00580, 0.00601, 0.00623, 0.00647, 0.00673, + 0.00701, 0.00731, 0.00765, 0.00801, 0.00841, 0.00885, 0.00935, 0.00990, + 0.01051, 0.01085, 0.01122, 0.01160, 0.01202, 0.01246, 0.01294, 0.01346, + 0.01402, 0.01463, 0.01529, 0.01602, 0.01682, 0.01771, 0.01869, 0.01979, + 0.02103, 0.02171, 0.02243, 0.02320, 0.02403, 0.02492, 0.02588, 0.02692, + 0.02804, 0.02926, 0.03059, 0.03204, 0.03365, 0.03542, 0.03738, 0.03958, + 0.04206, 0.04341, 0.04486, 0.04641, 0.04807, 0.04985, 0.05176, 0.05383, + 0.05608, 0.05851, 0.06117, 0.06409, 0.06729, 0.07083, 0.07477, 0.07917, + 0.08411, 0.08683, 0.08972, 0.09282, 0.09613, 0.09969, 0.10353, 0.10767, + 0.11215, 0.11703, 0.12235, 0.12817, 0.13458, 0.14167, 0.14954, 0.15833, + 0.16823, 0.17365, 0.17944, 0.18563, 0.19226, 0.19938, 0.20705, 0.21533, + 0.22430, 0.23406, 0.24470, 0.25635, 0.26917, 0.28333, 0.29907, 0.31666, + 0.33646, 0.34731, 0.35889, 0.37126, 0.38452, 0.39876, 0.41410, 0.43066, + 0.44861, 0.46811, 0.48939, 0.51270, 0.53833, 0.56666, 0.59814, 0.63333, + 0.67291, 0.69462, 0.71777, 0.74252, 0.76904, 0.79753, 0.82820, 0.86133, + 0.89722, 0.93623, 0.97878, 1.02539, 1.07666, 1.13333, 1.19629, 1.26666, + 1.34583, 1.38924, 1.43555, 1.48505, 1.53809, 1.59509, 1.65640, 1.72266, + 1.79443, 1.87245, 1.95756, 2.05078, 2.15332, 2.26665, 2.39258, 2.53332, + 2.69165, 2.77848, 2.87109, 2.97010, 3.07617, 3.19010, 3.31280, 3.44531, + 3.58887, 3.74490, 3.91513, 4.10156, 4.30664, 4.53331, 4.78516, 5.06664, + 5.38330, 5.55696, 5.74219, 5.94019, 6.15234, 6.38021, 6.62560, 6.89062, + 7.17773, 7.48981, 7.83026, 8.20312, 8.61328, 9.06661, 9.57031, 10.13327, + 10.76660, 11.11391, 11.48438, 11.88039, 12.30469, 12.76042, 13.25120, 13.78125, + 14.35547, 14.97962, 15.66051, 16.40625, 17.22656, 18.13322, 19.14062, 20.26654, + 21.53320, 22.96875, 24.60938, 26.50240, 28.71094, 31.32102, 34.45312, 38.28125, + 43.06641, 49.21875, 57.42188, 68.90625, 86.13281, 114.84375, 172.26562, 344.53125 +}; + +static const int RKS_Table[32][8] = +{ + { 0, 0, 0, 0, 0, 2, 4, 8 }, + { 0, 0, 0, 0, 1, 3, 5, 9 }, + { 0, 0, 0, 1, 2, 4, 6, 10 }, + { 0, 0, 0, 1, 3, 5, 7, 11 }, + { 0, 0, 1, 2, 4, 6, 8, 12 }, + { 0, 0, 1, 2, 5, 7, 9, 13 }, + { 0, 0, 1, 3, 6, 8, 10, 14 }, + { 0, 0, 1, 3, 7, 9, 11, 15 }, + { 0, 1, 2, 4, 8, 10, 12, 16 }, + { 0, 1, 2, 4, 9, 11, 13, 17 }, + { 0, 1, 2, 5, 10, 12, 14, 18 }, + { 0, 1, 2, 5, 11, 13, 15, 19 }, + { 0, 1, 3, 6, 12, 14, 16, 20 }, + { 0, 1, 3, 6, 13, 15, 17, 21 }, + { 0, 1, 3, 7, 14, 16, 18, 22 }, + { 0, 1, 3, 7, 15, 17, 19, 23 }, + { 0, 2, 4, 8, 16, 18, 20, 24 }, + { 0, 2, 4, 8, 17, 19, 21, 25 }, + { 0, 2, 4, 9, 18, 20, 22, 26 }, + { 0, 2, 4, 9, 19, 21, 23, 27 }, + { 0, 2, 5, 10, 20, 22, 24, 28 }, + { 0, 2, 5, 10, 21, 23, 25, 29 }, + { 0, 2, 5, 11, 22, 24, 26, 30 }, + { 0, 2, 5, 11, 23, 25, 27, 31 }, + { 0, 3, 6, 12, 24, 26, 28, 31 }, + { 0, 3, 6, 12, 25, 27, 29, 31 }, + { 0, 3, 6, 13, 26, 28, 30, 31 }, + { 0, 3, 6, 13, 27, 29, 31, 31 }, + { 0, 3, 7, 14, 28, 30, 31, 31 }, + { 0, 3, 7, 14, 29, 31, 31, 31 }, + { 0, 3, 7, 15, 30, 31, 31, 31 }, + { 0, 3, 7, 15, 31, 31, 31, 31 }, +}; + +static const double multiple_table[16] = { 0.5, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }; + +static const double pow_table[16] = { 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 0.5, 1, 2, 4, 8, 16, 32, 64 }; + +static const double fs_frequency[4] = { 1.0/1.0, 1.0/2.0, 1.0/4.0, 1.0/8.0 }; + +static const double channel_attenuation_table[16] = +{ + 0.0, 2.5, 6.0, 8.5, 12.0, 14.5, 18.1, 20.6, 24.1, 26.6, 30.1, 32.6, 36.1, 96.1, 96.1, 96.1 +}; + +static const int modulation_level[8] = { 16, 8, 4, 2, 1, 32, 64, 128 }; + +// feedback_level * 16 +static const int feedback_level[8] = { 0, 1, 2, 4, 8, 16, 32, 64 }; + +// slot mapping assists +static const int fm_tab[16] = { 0, 1, 2, -1, 3, 4, 5, -1, 6, 7, 8, -1, 9, 10, 11, -1 }; +static const int pcm_tab[16] = { 0, 4, 8, -1, 12, 16, 20, -1, 24, 28, 32, -1, 36, 40, 44, -1 }; + + +/*****************************************************************************/ + +void ymf271_device::calculate_step(YMF271Slot *slot) +{ + double st; + + if (slot->waveform == 7) + { + // external waveform (PCM) + st = (double)(2 * (slot->fns | 2048)) * pow_table[slot->block] * fs_frequency[slot->fs]; + st = st * multiple_table[slot->multiple]; + + // LFO phase modulation + st *= slot->lfo_phasemod; + + st /= (double)(524288/65536); // pre-multiply with 65536 + + slot->step = (UINT32)st; + } + else + { + // internal waveform (FM) + st = (double)(2 * slot->fns) * pow_table[slot->block]; + st = st * multiple_table[slot->multiple] * (double)(SIN_LEN); + + // LFO phase modulation + st *= slot->lfo_phasemod; + + st /= (double)(536870912/65536); // pre-multiply with 65536 + + slot->step = (UINT32)st; + } +} + +inline bool ymf271_device::check_envelope_end(YMF271Slot *slot) +{ + if (slot->volume <= 0) + { + slot->active = 0; + slot->volume = 0; + return true; + } + return false; +} + +void ymf271_device::update_envelope(YMF271Slot *slot) +{ + switch (slot->env_state) + { + case ENV_ATTACK: + { + slot->volume += slot->env_attack_step; + + if (slot->volume >= (255 << ENV_VOLUME_SHIFT)) + { + slot->volume = (255 << ENV_VOLUME_SHIFT); + slot->env_state = ENV_DECAY1; + } + break; + } + + case ENV_DECAY1: + { + int decay_level = 255 - (slot->decay1lvl << 4); + slot->volume -= slot->env_decay1_step; + + if (!check_envelope_end(slot) && (slot->volume >> ENV_VOLUME_SHIFT) <= decay_level) + { + slot->env_state = ENV_DECAY2; + } + break; + } + + case ENV_DECAY2: + { + slot->volume -= slot->env_decay2_step; + check_envelope_end(slot); + break; + } + + case ENV_RELEASE: + { + slot->volume -= slot->env_release_step; + check_envelope_end(slot); + break; + } + } +} + +inline int ymf271_device::get_keyscaled_rate(int rate, int keycode, int keyscale) +{ + int newrate = rate + RKS_Table[keycode][keyscale]; + + if (newrate > 63) + { + newrate = 63; + } + if (newrate < 0) + { + newrate = 0; + } + return newrate; +} + +inline int ymf271_device::get_internal_keycode(int block, int fns) +{ + int n43; + if (fns < 0x780) + { + n43 = 0; + } + else if (fns < 0x900) + { + n43 = 1; + } + else if (fns < 0xa80) + { + n43 = 2; + } + else + { + n43 = 3; + } + + return ((block & 7) * 4) + n43; +} + +inline int ymf271_device::get_external_keycode(int block, int fns) +{ + int n43; + if (fns < 0x100) + { + n43 = 0; + } + else if (fns < 0x300) + { + n43 = 1; + } + else if (fns < 0x500) + { + n43 = 2; + } + else + { + n43 = 3; + } + + return ((block & 7) * 4) + n43; +} + +void ymf271_device::init_envelope(YMF271Slot *slot) +{ + int keycode, rate; + int decay_level = 255 - (slot->decay1lvl << 4); + + if (slot->waveform != 7) + { + keycode = get_internal_keycode(slot->block, slot->fns); + } + else + { + keycode = get_external_keycode(slot->block, slot->fns & 0x7ff); + /* keycode = (keycode + slot->srcb * 4 + slot->srcnote) / 2; */ // not sure + } + + // init attack state + rate = get_keyscaled_rate(slot->ar * 2, keycode, slot->keyscale); + slot->env_attack_step = (rate < 4) ? 0 : (int)(((double)(255-0) / m_lut_ar[rate]) * 65536.0); + + // init decay1 state + rate = get_keyscaled_rate(slot->decay1rate * 2, keycode, slot->keyscale); + slot->env_decay1_step = (rate < 4) ? 0 : (int)(((double)(255-decay_level) / m_lut_dc[rate]) * 65536.0); + + // init decay2 state + rate = get_keyscaled_rate(slot->decay2rate * 2, keycode, slot->keyscale); + slot->env_decay2_step = (rate < 4) ? 0 : (int)(((double)(255-0) / m_lut_dc[rate]) * 65536.0); + + // init release state + rate = get_keyscaled_rate(slot->relrate * 4, keycode, slot->keyscale); + slot->env_release_step = (rate < 4) ? 0 : (int)(((double)(255-0) / m_lut_ar[rate]) * 65536.0); + + slot->volume = (255-160) << ENV_VOLUME_SHIFT; // -60db + slot->env_state = ENV_ATTACK; +} + +void ymf271_device::init_lfo(YMF271Slot *slot) +{ + slot->lfo_phase = 0; + slot->lfo_amplitude = 0; + slot->lfo_phasemod = 0; + + slot->lfo_step = (int)((((double)LFO_LENGTH * m_lut_lfo[slot->lfoFreq]) / 44100.0) * 256.0); +} + +void ymf271_device::update_lfo(YMF271Slot *slot) +{ + slot->lfo_phase += slot->lfo_step; + + slot->lfo_amplitude = m_lut_alfo[slot->lfowave][(slot->lfo_phase >> LFO_SHIFT) & (LFO_LENGTH-1)]; + slot->lfo_phasemod = m_lut_plfo[slot->lfowave][slot->pms][(slot->lfo_phase >> LFO_SHIFT) & (LFO_LENGTH-1)]; + + calculate_step(slot); +} + +INT64 ymf271_device::calculate_slot_volume(YMF271Slot *slot) +{ + INT64 volume; + INT64 env_volume; + INT64 lfo_volume = 65536; + + switch (slot->ams) + { + case 0: lfo_volume = 65536; break; // 0dB + case 1: lfo_volume = 65536 - ((slot->lfo_amplitude * 33124) >> 16); break; // 5.90625dB + case 2: lfo_volume = 65536 - ((slot->lfo_amplitude * 16742) >> 16); break; // 11.8125dB + case 3: lfo_volume = 65536 - ((slot->lfo_amplitude * 4277) >> 16); break; // 23.625dB + } + + env_volume = (m_lut_env_volume[255 - (slot->volume >> ENV_VOLUME_SHIFT)] * lfo_volume) >> 16; + + volume = (env_volume * m_lut_total_level[slot->tl]) >> 16; + + return volume; +} + +void ymf271_device::update_pcm(int slotnum, INT32 *mixp, int length) +{ + int i; + INT64 final_volume; + INT16 sample; + INT64 ch0_vol, ch1_vol; //, ch2_vol, ch3_vol; + + YMF271Slot *slot = &m_slots[slotnum]; + + if (!slot->active) + { + return; + } + + if (slot->waveform != 7) + { + fatalerror("Waveform %d in update_pcm!!!\n", slot->waveform); + } + + for (i = 0; i < length; i++) + { + // loop + if ((slot->stepptr>>16) > slot->endaddr) + { + slot->stepptr = slot->stepptr - ((UINT64)slot->endaddr<<16) + ((UINT64)slot->loopaddr<<16); + if ((slot->stepptr>>16) > slot->endaddr) + { + // overflow + slot->stepptr &= 0xffff; + slot->stepptr |= ((UINT64)slot->loopaddr<<16); + if ((slot->stepptr>>16) > slot->endaddr) + { + // still overflow? (triggers in rdft2, rarely) + slot->stepptr &= 0xffff; + slot->stepptr |= ((UINT64)slot->endaddr<<16); + } + } + } + + if (slot->bits == 8) + { + // 8bit + sample = ymf271_read_memory(slot->startaddr + (slot->stepptr>>16))<<8; + } + else + { + // 12bit + if (slot->stepptr & 0x10000) + sample = ymf271_read_memory(slot->startaddr + (slot->stepptr>>17)*3 + 2)<<8 | ((ymf271_read_memory(slot->startaddr + (slot->stepptr>>17)*3 + 1) << 4) & 0xf0); + else + sample = ymf271_read_memory(slot->startaddr + (slot->stepptr>>17)*3)<<8 | (ymf271_read_memory(slot->startaddr + (slot->stepptr>>17)*3 + 1) & 0xf0); + } + + update_envelope(slot); + update_lfo(slot); + + final_volume = calculate_slot_volume(slot); + + ch0_vol = (final_volume * m_lut_attenuation[slot->ch0_level]) >> 16; + ch1_vol = (final_volume * m_lut_attenuation[slot->ch1_level]) >> 16; +// ch2_vol = (final_volume * m_lut_attenuation[slot->ch2_level]) >> 16; +// ch3_vol = (final_volume * m_lut_attenuation[slot->ch3_level]) >> 16; + + if (ch0_vol > 65536) ch0_vol = 65536; + if (ch1_vol > 65536) ch1_vol = 65536; + + *mixp++ += (sample * ch0_vol) >> 16; + *mixp++ += (sample * ch1_vol) >> 16; + + // go to next step + slot->stepptr += slot->step; + } +} + +// calculates the output of one FM operator +INT64 ymf271_device::calculate_op(int slotnum, INT64 inp) +{ + YMF271Slot *slot = &m_slots[slotnum]; + INT64 env, slot_output, slot_input = 0; + + update_envelope(slot); + update_lfo(slot); + env = calculate_slot_volume(slot); + + if (inp == OP_INPUT_FEEDBACK) + { + // from own feedback + slot_input = (slot->feedback_modulation0 + slot->feedback_modulation1) / 2; + slot->feedback_modulation0 = slot->feedback_modulation1; + } + else if (inp != OP_INPUT_NONE) + { + // from previous slot output + slot_input = ((inp << (SIN_BITS-2)) * modulation_level[slot->feedback]); + } + + slot_output = m_lut_waves[slot->waveform][((slot->stepptr + slot_input) >> 16) & SIN_MASK]; + slot_output = (slot_output * env) >> 16; + slot->stepptr += slot->step; + + return slot_output; +} + +void ymf271_device::set_feedback(int slotnum, INT64 inp) +{ + YMF271Slot *slot = &m_slots[slotnum]; + slot->feedback_modulation1 = (((inp << (SIN_BITS-2)) * feedback_level[slot->feedback]) / 16); +} + +//------------------------------------------------- +// sound_stream_update - handle a stream update +//------------------------------------------------- + +void ymf271_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + int i, j; + int op; + INT32 *mixp; + + memset(m_mix_buffer, 0, sizeof(m_mix_buffer[0])*samples*2); + + for (j = 0; j < 12; j++) + { + YMF271Group *slot_group = &m_groups[j]; + mixp = m_mix_buffer; + + if (slot_group->pfm && slot_group->sync != 3) + { + popmessage("ymf271 PFM, contact MAMEdev"); + logerror("ymf271 Group %d: PFM, Sync = %d, Waveform Slot1 = %d, Slot2 = %d, Slot3 = %d, Slot4 = %d\n", + j, slot_group->sync, m_slots[j+0].waveform, m_slots[j+12].waveform, m_slots[j+24].waveform, m_slots[j+36].waveform); + } + + switch (slot_group->sync) + { + // 4 operator FM + case 0: + { + int slot1 = j + (0*12); + int slot2 = j + (1*12); + int slot3 = j + (2*12); + int slot4 = j + (3*12); + mixp = m_mix_buffer; + + if (m_slots[slot1].active) + { + for (i = 0; i < samples; i++) + { + INT64 output1 = 0, output2 = 0, output3 = 0, output4 = 0; + INT64 phase_mod1 = 0, phase_mod2 = 0, phase_mod3 = 0; + switch (m_slots[slot1].algorithm) + { + // <--------| + // +--[S1]--|--+--[S3]--+--[S2]--+--[S4]--> + case 0: + phase_mod1 = calculate_op(slot1, OP_INPUT_FEEDBACK); + set_feedback(slot1, phase_mod1); + phase_mod3 = calculate_op(slot3, phase_mod1); + phase_mod2 = calculate_op(slot2, phase_mod3); + output4 = calculate_op(slot4, phase_mod2); + break; + + // <-----------------| + // +--[S1]--+--[S3]--|--+--[S2]--+--[S4]--> + case 1: + phase_mod1 = calculate_op(slot1, OP_INPUT_FEEDBACK); + phase_mod3 = calculate_op(slot3, phase_mod1); + set_feedback(slot1, phase_mod3); + phase_mod2 = calculate_op(slot2, phase_mod3); + output4 = calculate_op(slot4, phase_mod2); + break; + + // <--------| + // +--[S1]--| + // | + // --[S3]--+--[S2]--+--[S4]--> + case 2: + phase_mod1 = calculate_op(slot1, OP_INPUT_FEEDBACK); + set_feedback(slot1, phase_mod1); + phase_mod3 = calculate_op(slot3, OP_INPUT_NONE); + phase_mod2 = calculate_op(slot2, (phase_mod1 + phase_mod3) / 1); + output4 = calculate_op(slot4, phase_mod2); + break; + + // <--------| + // +--[S1]--| + // | + // --[S3]--+--[S2]--+--[S4]--> + case 3: + phase_mod1 = calculate_op(slot1, OP_INPUT_FEEDBACK); + set_feedback(slot1, phase_mod1); + phase_mod3 = calculate_op(slot3, OP_INPUT_NONE); + phase_mod2 = calculate_op(slot2, phase_mod3); + output4 = calculate_op(slot4, (phase_mod1 + phase_mod2) / 1); + break; + + // --[S2]--| + // <--------| | + // +--[S1]--|--+--[S3]--+--[S4]--> + case 4: + phase_mod1 = calculate_op(slot1, OP_INPUT_FEEDBACK); + set_feedback(slot1, phase_mod1); + phase_mod3 = calculate_op(slot3, phase_mod1); + phase_mod2 = calculate_op(slot2, OP_INPUT_NONE); + output4 = calculate_op(slot4, (phase_mod3 + phase_mod2) / 1); + break; + + // --[S2]-----| + // <-----------------| | + // +--[S1]--+--[S3]--|--+--[S4]--> + case 5: + phase_mod1 = calculate_op(slot1, OP_INPUT_FEEDBACK); + phase_mod3 = calculate_op(slot3, phase_mod1); + set_feedback(slot1, phase_mod3); + phase_mod2 = calculate_op(slot2, OP_INPUT_NONE); + output4 = calculate_op(slot4, (phase_mod3 + phase_mod2) / 1); + break; + + // --[S2]-----+--[S4]--| + // | + // <--------| | + // +--[S1]--|--+--[S3]--+--> + case 6: + phase_mod1 = calculate_op(slot1, OP_INPUT_FEEDBACK); + set_feedback(slot1, phase_mod1); + output3 = calculate_op(slot3, phase_mod1); + phase_mod2 = calculate_op(slot2, OP_INPUT_NONE); + output4 = calculate_op(slot4, phase_mod2); + break; + + // --[S2]--+--[S4]-----| + // | + // <-----------------| | + // +--[S1]--+--[S3]--|--+--> + case 7: + phase_mod1 = calculate_op(slot1, OP_INPUT_FEEDBACK); + phase_mod3 = calculate_op(slot3, phase_mod1); + set_feedback(slot1, phase_mod3); + output3 = phase_mod3; + phase_mod2 = calculate_op(slot2, OP_INPUT_NONE); + output4 = calculate_op(slot4, phase_mod2); + break; + + // --[S3]--+--[S2]--+--[S4]--| + // | + // <--------| | + // +--[S1]--|-----------------+--> + case 8: + phase_mod1 = calculate_op(slot1, OP_INPUT_FEEDBACK); + set_feedback(slot1, phase_mod1); + output1 = phase_mod1; + phase_mod3 = calculate_op(slot3, OP_INPUT_NONE); + phase_mod2 = calculate_op(slot2, phase_mod3); + output4 = calculate_op(slot4, phase_mod2); + break; + + // <--------| + // +--[S1]--| + // | + // --[S3]--| | + // --[S2]--+--[S4]--+--> + case 9: + phase_mod1 = calculate_op(slot1, OP_INPUT_FEEDBACK); + set_feedback(slot1, phase_mod1); + output1 = phase_mod1; + phase_mod3 = calculate_op(slot3, OP_INPUT_NONE); + phase_mod2 = calculate_op(slot2, OP_INPUT_NONE); + output4 = calculate_op(slot4, (phase_mod3 + phase_mod2) / 1); + break; + + // --[S4]--| + // --[S2]--| + // <--------| | + // +--[S1]--|--+--[S3]--+--> + case 10: + phase_mod1 = calculate_op(slot1, OP_INPUT_FEEDBACK); + set_feedback(slot1, phase_mod1); + output3 = calculate_op(slot3, phase_mod1); + output2 = calculate_op(slot2, OP_INPUT_NONE); + output4 = calculate_op(slot4, OP_INPUT_NONE); + break; + + // --[S4]-----| + // --[S2]-----| + // <-----------------| | + // +--[S1]--+--[S3]--|--+--> + case 11: + phase_mod1 = calculate_op(slot1, OP_INPUT_FEEDBACK); + phase_mod3 = calculate_op(slot3, phase_mod1); + set_feedback(slot1, phase_mod3); + output3 = phase_mod3; + output2 = calculate_op(slot2, OP_INPUT_NONE); + output4 = calculate_op(slot4, OP_INPUT_NONE); + break; + + // |--+--[S4]--| + // <--------| |--+--[S3]--| + // +--[S1]--|--|--+--[S2]--+--> + case 12: + phase_mod1 = calculate_op(slot1, OP_INPUT_FEEDBACK); + set_feedback(slot1, phase_mod1); + output3 = calculate_op(slot3, phase_mod1); + output2 = calculate_op(slot2, phase_mod1); + output4 = calculate_op(slot4, phase_mod1); + break; + + // --[S3]--+--[S2]--| + // | + // --[S4]-----------| + // <--------| | + // +--[S1]--|--------+--> + case 13: + phase_mod1 = calculate_op(slot1, OP_INPUT_FEEDBACK); + set_feedback(slot1, phase_mod1); + output1 = phase_mod1; + phase_mod3 = calculate_op(slot3, OP_INPUT_NONE); + output2 = calculate_op(slot2, phase_mod3); + output4 = calculate_op(slot4, OP_INPUT_NONE); + break; + + // --[S2]-----+--[S4]--| + // | + // <--------| +--[S3]--| + // +--[S1]--|--|--------+--> + case 14: + phase_mod1 = calculate_op(slot1, OP_INPUT_FEEDBACK); + set_feedback(slot1, phase_mod1); + output1 = phase_mod1; + output3 = calculate_op(slot3, phase_mod1); + phase_mod2 = calculate_op(slot2, OP_INPUT_NONE); + output4 = calculate_op(slot4, phase_mod2); + break; + + // --[S4]-----| + // --[S2]-----| + // --[S3]-----| + // <--------| | + // +--[S1]--|--+--> + case 15: + phase_mod1 = calculate_op(slot1, OP_INPUT_FEEDBACK); + set_feedback(slot1, phase_mod1); + output1 = phase_mod1; + output3 = calculate_op(slot3, OP_INPUT_NONE); + output2 = calculate_op(slot2, OP_INPUT_NONE); + output4 = calculate_op(slot4, OP_INPUT_NONE); + break; + } + + *mixp++ += ((output1 * m_lut_attenuation[m_slots[slot1].ch0_level]) + + (output2 * m_lut_attenuation[m_slots[slot2].ch0_level]) + + (output3 * m_lut_attenuation[m_slots[slot3].ch0_level]) + + (output4 * m_lut_attenuation[m_slots[slot4].ch0_level])) >> 16; + *mixp++ += ((output1 * m_lut_attenuation[m_slots[slot1].ch1_level]) + + (output2 * m_lut_attenuation[m_slots[slot2].ch1_level]) + + (output3 * m_lut_attenuation[m_slots[slot3].ch1_level]) + + (output4 * m_lut_attenuation[m_slots[slot4].ch1_level])) >> 16; + } + } + break; + } + + // 2x 2 operator FM + case 1: + { + for (op = 0; op < 2; op++) + { + int slot1 = j + ((op + 0) * 12); + int slot3 = j + ((op + 2) * 12); + + mixp = m_mix_buffer; + if (m_slots[slot1].active) + { + for (i = 0; i < samples; i++) + { + INT64 output1 = 0, output3 = 0; + INT64 phase_mod1, phase_mod3 = 0; + switch (m_slots[slot1].algorithm & 3) + { + // <--------| + // +--[S1]--|--+--[S3]--> + case 0: + phase_mod1 = calculate_op(slot1, OP_INPUT_FEEDBACK); + set_feedback(slot1, phase_mod1); + output3 = calculate_op(slot3, phase_mod1); + break; + + // <-----------------| + // +--[S1]--+--[S3]--|--> + case 1: + phase_mod1 = calculate_op(slot1, OP_INPUT_FEEDBACK); + phase_mod3 = calculate_op(slot3, phase_mod1); + set_feedback(slot1, phase_mod3); + output3 = phase_mod3; + break; + + // --[S3]-----| + // <--------| | + // +--[S1]--|--+--> + case 2: + phase_mod1 = calculate_op(slot1, OP_INPUT_FEEDBACK); + set_feedback(slot1, phase_mod1); + output1 = phase_mod1; + output3 = calculate_op(slot3, OP_INPUT_NONE); + break; + // + // <--------| +--[S3]--| + // +--[S1]--|--|--------+--> + case 3: + phase_mod1 = calculate_op(slot1, OP_INPUT_FEEDBACK); + set_feedback(slot1, phase_mod1); + output1 = phase_mod1; + output3 = calculate_op(slot3, phase_mod1); + break; + } + + *mixp++ += ((output1 * m_lut_attenuation[m_slots[slot1].ch0_level]) + + (output3 * m_lut_attenuation[m_slots[slot3].ch0_level])) >> 16; + *mixp++ += ((output1 * m_lut_attenuation[m_slots[slot1].ch1_level]) + + (output3 * m_lut_attenuation[m_slots[slot3].ch1_level])) >> 16; + } + } + } + break; + } + + // 3 operator FM + PCM + case 2: + { + int slot1 = j + (0*12); + int slot2 = j + (1*12); + int slot3 = j + (2*12); + mixp = m_mix_buffer; + + if (m_slots[slot1].active) + { + for (i = 0; i < samples; i++) + { + INT64 output1 = 0, output2 = 0, output3 = 0; + INT64 phase_mod1 = 0, phase_mod3 = 0; + switch (m_slots[slot1].algorithm & 7) + { + // <--------| + // +--[S1]--|--+--[S3]--+--[S2]--> + case 0: + phase_mod1 = calculate_op(slot1, OP_INPUT_FEEDBACK); + set_feedback(slot1, phase_mod1); + phase_mod3 = calculate_op(slot3, phase_mod1); + output2 = calculate_op(slot2, phase_mod3); + break; + + // <-----------------| + // +--[S1]--+--[S3]--|--+--[S2]--> + case 1: + phase_mod1 = calculate_op(slot1, OP_INPUT_FEEDBACK); + phase_mod3 = calculate_op(slot3, phase_mod1); + set_feedback(slot1, phase_mod3); + output2 = calculate_op(slot2, phase_mod3); + break; + + // --[S3]-----| + // <--------| | + // +--[S1]--|--+--[S2]--> + case 2: + phase_mod1 = calculate_op(slot1, OP_INPUT_FEEDBACK); + set_feedback(slot1, phase_mod1); + phase_mod3 = calculate_op(slot3, OP_INPUT_NONE); + output2 = calculate_op(slot2, (phase_mod1 + phase_mod3) / 1); + break; + + // --[S3]--+--[S2]--| + // <--------| | + // +--[S1]--|--------+--> + case 3: + phase_mod1 = calculate_op(slot1, OP_INPUT_FEEDBACK); + set_feedback(slot1, phase_mod1); + output1 = phase_mod1; + phase_mod3 = calculate_op(slot3, OP_INPUT_NONE); + output2 = calculate_op(slot2, phase_mod3); + break; + + // --[S2]--| + // <--------| | + // +--[S1]--|--+--[S3]--+--> + case 4: + phase_mod1 = calculate_op(slot1, OP_INPUT_FEEDBACK); + set_feedback(slot1, phase_mod1); + output3 = calculate_op(slot3, phase_mod1); + output2 = calculate_op(slot2, OP_INPUT_NONE); + break; + + // --[S2]--| + // <-----------------| | + // +--[S1]--+--[S3]--|--+--> + case 5: + phase_mod1 = calculate_op(slot1, OP_INPUT_FEEDBACK); + phase_mod3 = calculate_op(slot3, phase_mod1); + set_feedback(slot1, phase_mod3); + output3 = phase_mod3; + output2 = calculate_op(slot2, OP_INPUT_NONE); + break; + + // --[S2]-----| + // --[S3]-----| + // <--------| | + // +--[S1]--|--+--> + case 6: + phase_mod1 = calculate_op(slot1, OP_INPUT_FEEDBACK); + set_feedback(slot1, phase_mod1); + output1 = phase_mod1; + output3 = calculate_op(slot3, OP_INPUT_NONE); + output2 = calculate_op(slot2, OP_INPUT_NONE); + break; + + // --[S2]--| + // <--------| +--[S3]--| + // +--[S1]--|--|--------+--> + case 7: + phase_mod1 = calculate_op(slot1, OP_INPUT_FEEDBACK); + set_feedback(slot1, phase_mod1); + output1 = phase_mod1; + output3 = calculate_op(slot3, phase_mod1); + output2 = calculate_op(slot2, OP_INPUT_NONE); + break; + } + + *mixp++ += ((output1 * m_lut_attenuation[m_slots[slot1].ch0_level]) + + (output2 * m_lut_attenuation[m_slots[slot2].ch0_level]) + + (output3 * m_lut_attenuation[m_slots[slot3].ch0_level])) >> 16; + *mixp++ += ((output1 * m_lut_attenuation[m_slots[slot1].ch1_level]) + + (output2 * m_lut_attenuation[m_slots[slot2].ch1_level]) + + (output3 * m_lut_attenuation[m_slots[slot3].ch1_level])) >> 16; + } + } + + mixp = m_mix_buffer; + update_pcm(j + (3*12), mixp, samples); + break; + } + + // PCM + case 3: + { + update_pcm(j + (0*12), mixp, samples); + update_pcm(j + (1*12), mixp, samples); + update_pcm(j + (2*12), mixp, samples); + update_pcm(j + (3*12), mixp, samples); + break; + } + } + } + + mixp = m_mix_buffer; + for (i = 0; i < samples; i++) + { + outputs[0][i] = (*mixp++)>>2; + outputs[1][i] = (*mixp++)>>2; + } +} + +void ymf271_device::write_register(int slotnum, int reg, UINT8 data) +{ + YMF271Slot *slot = &m_slots[slotnum]; + + switch (reg) + { + case 0x0: + slot->ext_en = (data & 0x80) ? 1 : 0; + slot->ext_out = (data>>3)&0xf; + + if (data & 1) + { + // key on + slot->step = 0; + slot->stepptr = 0; + + slot->active = 1; + + calculate_step(slot); + init_envelope(slot); + init_lfo(slot); + slot->feedback_modulation0 = 0; + slot->feedback_modulation1 = 0; + } + else + { + if (slot->active) + { + slot->env_state = ENV_RELEASE; + } + } + break; + + case 0x1: + slot->lfoFreq = data; + break; + + case 0x2: + slot->lfowave = data & 3; + slot->pms = (data >> 3) & 0x7; + slot->ams = (data >> 6) & 0x3; + break; + + case 0x3: + slot->multiple = data & 0xf; + slot->detune = (data >> 4) & 0x7; + break; + + case 0x4: + slot->tl = data & 0x7f; + break; + + case 0x5: + slot->ar = data & 0x1f; + slot->keyscale = (data >> 5) & 0x7; + break; + + case 0x6: + slot->decay1rate = data & 0x1f; + break; + + case 0x7: + slot->decay2rate = data & 0x1f; + break; + + case 0x8: + slot->relrate = data & 0xf; + slot->decay1lvl = (data >> 4) & 0xf; + break; + + case 0x9: + // write frequency and block here + slot->fns = (slot->fns_hi << 8 & 0x0f00) | data; + slot->block = slot->fns_hi >> 4 & 0xf; + break; + + case 0xa: + slot->fns_hi = data; + break; + + case 0xb: + slot->waveform = data & 0x7; + slot->feedback = (data >> 4) & 0x7; + slot->accon = (data & 0x80) ? 1 : 0; + break; + + case 0xc: + slot->algorithm = data & 0xf; + break; + + case 0xd: + slot->ch0_level = data >> 4; + slot->ch1_level = data & 0xf; + break; + + case 0xe: + slot->ch2_level = data >> 4; + slot->ch3_level = data & 0xf; + break; + + default: + break; + } +} + +void ymf271_device::ymf271_write_fm(int bank, UINT8 address, UINT8 data) +{ + int groupnum = fm_tab[address & 0xf]; + if (groupnum == -1) + { + logerror("ymf271_write_fm invalid group %02X %02X\n", address, data); + return; + } + + int reg = (address >> 4) & 0xf; + + // check if the register is a synchronized register + int sync_reg = 0; + switch (reg) + { + case 0: + case 9: + case 10: + case 12: + case 13: + case 14: + sync_reg = 1; + break; + + default: + break; + } + + // check if the slot is key on slot for synchronizing + int sync_mode = 0; + switch (m_groups[groupnum].sync) + { + // 4 slot mode + case 0: + if (bank == 0) + sync_mode = 1; + break; + + // 2x 2 slot mode + case 1: + if (bank == 0 || bank == 1) + sync_mode = 1; + break; + + // 3 slot + 1 slot mode + case 2: + if (bank == 0) + sync_mode = 1; + break; + + default: + break; + } + + // key-on slot & synced register + if (sync_mode && sync_reg) + { + switch (m_groups[groupnum].sync) + { + // 4 slot mode + case 0: + write_register((12 * 0) + groupnum, reg, data); + write_register((12 * 1) + groupnum, reg, data); + write_register((12 * 2) + groupnum, reg, data); + write_register((12 * 3) + groupnum, reg, data); + break; + + // 2x 2 slot mode + case 1: + if (bank == 0) + { + // Slot 1 - Slot 3 + write_register((12 * 0) + groupnum, reg, data); + write_register((12 * 2) + groupnum, reg, data); + } + else + { + // Slot 2 - Slot 4 + write_register((12 * 1) + groupnum, reg, data); + write_register((12 * 3) + groupnum, reg, data); + } + break; + + // 3 slot + 1 slot mode (1 slot is handled normally) + case 2: + write_register((12 * 0) + groupnum, reg, data); + write_register((12 * 1) + groupnum, reg, data); + write_register((12 * 2) + groupnum, reg, data); + break; + } + } + else + { + // write register normally + write_register((12 * bank) + groupnum, reg, data); + } +} + +void ymf271_device::ymf271_write_pcm(UINT8 address, UINT8 data) +{ + int slotnum = pcm_tab[address & 0xf]; + if (slotnum == -1) + { + logerror("ymf271_write_pcm invalid slot %02X %02X\n", address, data); + return; + } + YMF271Slot *slot = &m_slots[slotnum]; + + switch (address >> 4 & 0xf) + { + case 0x0: + slot->startaddr &= ~0xff; + slot->startaddr |= data; + break; + + case 0x1: + slot->startaddr &= ~0xff00; + slot->startaddr |= data<<8; + break; + + case 0x2: + slot->startaddr &= ~0xff0000; + slot->startaddr |= (data & 0x7f)<<16; + slot->altloop = (data & 0x80) ? 1 : 0; + if (slot->altloop) + popmessage("ymf271 A/L, contact MAMEdev"); + break; + + case 0x3: + slot->endaddr &= ~0xff; + slot->endaddr |= data; + break; + + case 0x4: + slot->endaddr &= ~0xff00; + slot->endaddr |= data<<8; + break; + + case 0x5: + slot->endaddr &= ~0xff0000; + slot->endaddr |= (data & 0x7f)<<16; + break; + + case 0x6: + slot->loopaddr &= ~0xff; + slot->loopaddr |= data; + break; + + case 0x7: + slot->loopaddr &= ~0xff00; + slot->loopaddr |= data<<8; + break; + + case 0x8: + slot->loopaddr &= ~0xff0000; + slot->loopaddr |= (data & 0x7f)<<16; + break; + + case 0x9: + slot->fs = data & 0x3; + slot->bits = (data & 0x4) ? 12 : 8; + slot->srcnote = (data >> 3) & 0x3; + slot->srcb = (data >> 5) & 0x7; + break; + + default: + break; + } +} + +void ymf271_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch(id) + { + case 0: + m_status |= 1; + + // assert IRQ + if (m_enable & 4) + { + m_irqstate |= 1; + + if (!m_irq_handler.isnull()) + m_irq_handler(1); + } + + // reload timer + m_timA->adjust(attotime::from_hz(m_clock) * (384 * 4 * (256 - m_timerA)), 0); + break; + + case 1: + m_status |= 2; + + // assert IRQ + if (m_enable & 8) + { + m_irqstate |= 2; + + if (!m_irq_handler.isnull()) + m_irq_handler(1); + } + + // reload timer + m_timB->adjust(attotime::from_hz(m_clock) * (384 * 16 * (256 - m_timerB)), 0); + break; + + default: + assert_always(FALSE, "Unknown id in ymf271_device::device_timer"); + break; + } +} + +UINT8 ymf271_device::ymf271_read_memory(UINT32 offset) +{ + if (m_ext_read_handler.isnull()) + { + if (offset < m_mem_size) + return m_mem_base[offset]; + + /* 8MB chip limit (shouldn't happen) */ + else if (offset > 0x7fffff) + return ymf271_read_memory(offset & 0x7fffff); + + else + return 0; + } + else + return m_ext_read_handler(offset); +} + +void ymf271_device::ymf271_write_timer(UINT8 address, UINT8 data) +{ + if ((address & 0xf0) == 0) + { + int groupnum = fm_tab[address & 0xf]; + if (groupnum == -1) + { + logerror("ymf271_write_timer invalid group %02X %02X\n", address, data); + return; + } + YMF271Group *group = &m_groups[groupnum]; + + group->sync = data & 0x3; + group->pfm = data >> 7; + } + else + { + switch (address) + { + case 0x10: + m_timerA = data; + break; + + case 0x11: + // According to Yamaha's documentation, this sets timer A upper 2 bits + // (it says timer A is 10 bits). But, PCB audio recordings proves + // otherwise: it doesn't affect timer A frequency. (see ms32.c tetrisp) + // Does this register have another function regarding timer A/B? + break; + + case 0x12: + m_timerB = data; + break; + + case 0x13: + // timer A load + if (~m_enable & data & 1) + { + attotime period = attotime::from_hz(m_clock) * (384 * 4 * (256 - m_timerA)); + m_timA->adjust((data & 1) ? period : attotime::never, 0); + } + + // timer B load + if (~m_enable & data & 2) + { + attotime period = attotime::from_hz(m_clock) * (384 * 16 * (256 - m_timerB)); + m_timB->adjust((data & 2) ? period : attotime::never, 0); + } + + // timer A reset + if (data & 0x10) + { + m_irqstate &= ~1; + m_status &= ~1; + + if (!m_irq_handler.isnull() && ~m_irqstate & 2) + m_irq_handler(0); + } + + // timer B reset + if (data & 0x20) + { + m_irqstate &= ~2; + m_status &= ~2; + + if (!m_irq_handler.isnull() && ~m_irqstate & 1) + m_irq_handler(0); + } + + m_enable = data; + break; + + case 0x14: + m_ext_address &= ~0xff; + m_ext_address |= data; + break; + + case 0x15: + m_ext_address &= ~0xff00; + m_ext_address |= data << 8; + break; + + case 0x16: + m_ext_address &= ~0xff0000; + m_ext_address |= (data & 0x7f) << 16; + m_ext_rw = (data & 0x80) ? 1 : 0; + break; + + case 0x17: + m_ext_address = (m_ext_address + 1) & 0x7fffff; + if (!m_ext_rw && !m_ext_write_handler.isnull()) + m_ext_write_handler(m_ext_address, data); + break; + + case 0x20: + case 0x21: + case 0x22: + // test + break; + + default: + break; + } + } +} + +WRITE8_MEMBER( ymf271_device::write ) +{ + m_stream->update(); + + m_regs_main[offset & 0xf] = data; + + switch (offset & 0xf) + { + case 0x0: + case 0x2: + case 0x4: + case 0x6: + case 0x8: + case 0xc: + // address regs + break; + + case 0x1: + ymf271_write_fm(0, m_regs_main[0x0], data); + break; + + case 0x3: + ymf271_write_fm(1, m_regs_main[0x2], data); + break; + + case 0x5: + ymf271_write_fm(2, m_regs_main[0x4], data); + break; + + case 0x7: + ymf271_write_fm(3, m_regs_main[0x6], data); + break; + + case 0x9: + ymf271_write_pcm(m_regs_main[0x8], data); + break; + + case 0xd: + ymf271_write_timer(m_regs_main[0xc], data); + break; + + default: + break; + } +} + +READ8_MEMBER( ymf271_device::read ) +{ + switch (offset & 0xf) + { + case 0x0: + return m_status; + + case 0x1: + // statusreg 2 + return 0; + + case 0x2: + { + if (!m_ext_rw) + return 0xff; + + UINT8 ret = m_ext_readlatch; + m_ext_address = (m_ext_address + 1) & 0x7fffff; + m_ext_readlatch = ymf271_read_memory(m_ext_address); + return ret; + } + + default: + break; + } + + return 0xff; +} + +void ymf271_device::init_tables() +{ + int i, j; + + for (i = 0; i < 8; i++) + m_lut_waves[i] = auto_alloc_array(machine(), INT16, SIN_LEN); + + for (i = 0; i < 4*8; i++) + m_lut_plfo[i>>3][i&7] = auto_alloc_array(machine(), double, LFO_LENGTH); + + for (i = 0; i < 4; i++) + m_lut_alfo[i] = auto_alloc_array(machine(), int, LFO_LENGTH); + + for (i = 0; i < SIN_LEN; i++) + { + double m = sin( ((i*2)+1) * M_PI / SIN_LEN ); + double m2 = sin( ((i*4)+1) * M_PI / SIN_LEN ); + + // Waveform 0: sin(wt) (0 <= wt <= 2PI) + m_lut_waves[0][i] = (INT16)(m * MAXOUT); + + // Waveform 1: sin?(wt) (0 <= wt <= PI) -sin?(wt) (PI <= wt <= 2PI) + m_lut_waves[1][i] = (i < (SIN_LEN/2)) ? (INT16)((m * m) * MAXOUT) : (INT16)((m * m) * MINOUT); + + // Waveform 2: sin(wt) (0 <= wt <= PI) -sin(wt) (PI <= wt <= 2PI) + m_lut_waves[2][i] = (i < (SIN_LEN/2)) ? (INT16)(m * MAXOUT) : (INT16)(-m * MAXOUT); + + // Waveform 3: sin(wt) (0 <= wt <= PI) 0 + m_lut_waves[3][i] = (i < (SIN_LEN/2)) ? (INT16)(m * MAXOUT) : 0; + + // Waveform 4: sin(2wt) (0 <= wt <= PI) 0 + m_lut_waves[4][i] = (i < (SIN_LEN/2)) ? (INT16)(m2 * MAXOUT) : 0; + + // Waveform 5: |sin(2wt)| (0 <= wt <= PI) 0 + m_lut_waves[5][i] = (i < (SIN_LEN/2)) ? (INT16)(fabs(m2) * MAXOUT) : 0; + + // Waveform 6: 1 (0 <= wt <= 2PI) + m_lut_waves[6][i] = (INT16)(1 * MAXOUT); + + m_lut_waves[7][i] = 0; + } + + for (i = 0; i < LFO_LENGTH; i++) + { + int tri_wave; + double ftri_wave, fsaw_wave; + double plfo[4]; + + // LFO phase modulation + plfo[0] = 0; + + fsaw_wave = ((i % (LFO_LENGTH/2)) * PLFO_MAX) / (double)((LFO_LENGTH/2)-1); + plfo[1] = (i < (LFO_LENGTH/2)) ? fsaw_wave : fsaw_wave - PLFO_MAX; + + plfo[2] = (i < (LFO_LENGTH/2)) ? PLFO_MAX : PLFO_MIN; + + ftri_wave = ((i % (LFO_LENGTH/4)) * PLFO_MAX) / (double)(LFO_LENGTH/4); + switch (i / (LFO_LENGTH/4)) + { + case 0: plfo[3] = ftri_wave; break; + case 1: plfo[3] = PLFO_MAX - ftri_wave; break; + case 2: plfo[3] = 0 - ftri_wave; break; + case 3: plfo[3] = 0 - (PLFO_MAX - ftri_wave); break; + default: plfo[3] = 0; assert(0); break; + } + + for (j = 0; j < 4; j++) + { + m_lut_plfo[j][0][i] = pow(2.0, 0.0); + m_lut_plfo[j][1][i] = pow(2.0, (3.378 * plfo[j]) / 1200.0); + m_lut_plfo[j][2][i] = pow(2.0, (5.0646 * plfo[j]) / 1200.0); + m_lut_plfo[j][3][i] = pow(2.0, (6.7495 * plfo[j]) / 1200.0); + m_lut_plfo[j][4][i] = pow(2.0, (10.1143 * plfo[j]) / 1200.0); + m_lut_plfo[j][5][i] = pow(2.0, (20.1699 * plfo[j]) / 1200.0); + m_lut_plfo[j][6][i] = pow(2.0, (40.1076 * plfo[j]) / 1200.0); + m_lut_plfo[j][7][i] = pow(2.0, (79.307 * plfo[j]) / 1200.0); + } + + // LFO amplitude modulation + m_lut_alfo[0][i] = 0; + + m_lut_alfo[1][i] = ALFO_MAX - ((i * ALFO_MAX) / LFO_LENGTH); + + m_lut_alfo[2][i] = (i < (LFO_LENGTH/2)) ? ALFO_MAX : ALFO_MIN; + + tri_wave = ((i % (LFO_LENGTH/2)) * ALFO_MAX) / (LFO_LENGTH/2); + m_lut_alfo[3][i] = (i < (LFO_LENGTH/2)) ? ALFO_MAX-tri_wave : tri_wave; + } + + for (i = 0; i < 256; i++) + { + m_lut_env_volume[i] = (int)(65536.0 / pow(10.0, ((double)i / (256.0 / 96.0)) / 20.0)); + } + + for (i = 0; i < 16; i++) + { + m_lut_attenuation[i] = (int)(65536.0 / pow(10.0, channel_attenuation_table[i] / 20.0)); + } + for (i = 0; i < 128; i++) + { + double db = 0.75 * (double)i; + m_lut_total_level[i] = (int)(65536.0 / pow(10.0, db / 20.0)); + } + + // timing may use a non-standard XTAL + double clock_correction = (double)(STD_CLOCK) / (double)(m_clock); + for (i = 0; i < 256; i++) + { + m_lut_lfo[i] = LFO_frequency_table[i] * clock_correction; + } + + for (i = 0; i < 64; i++) + { + // attack/release rate in number of samples + m_lut_ar[i] = (ARTime[i] * clock_correction * 44100.0) / 1000.0; + } + for (i = 0; i < 64; i++) + { + // decay rate in number of samples + m_lut_dc[i] = (DCTime[i] * clock_correction * 44100.0) / 1000.0; + } +} + +void ymf271_device::init_state() +{ + int i; + + for (i = 0; i < ARRAY_LENGTH(m_slots); i++) + { + save_item(NAME(m_slots[i].ext_en), i); + save_item(NAME(m_slots[i].ext_out), i); + save_item(NAME(m_slots[i].lfoFreq), i); + save_item(NAME(m_slots[i].pms), i); + save_item(NAME(m_slots[i].ams), i); + save_item(NAME(m_slots[i].detune), i); + save_item(NAME(m_slots[i].multiple), i); + save_item(NAME(m_slots[i].tl), i); + save_item(NAME(m_slots[i].keyscale), i); + save_item(NAME(m_slots[i].ar), i); + save_item(NAME(m_slots[i].decay1rate), i); + save_item(NAME(m_slots[i].decay2rate), i); + save_item(NAME(m_slots[i].decay1lvl), i); + save_item(NAME(m_slots[i].relrate), i); + save_item(NAME(m_slots[i].block), i); + save_item(NAME(m_slots[i].fns_hi), i); + save_item(NAME(m_slots[i].fns), i); + save_item(NAME(m_slots[i].feedback), i); + save_item(NAME(m_slots[i].waveform), i); + save_item(NAME(m_slots[i].accon), i); + save_item(NAME(m_slots[i].algorithm), i); + save_item(NAME(m_slots[i].ch0_level), i); + save_item(NAME(m_slots[i].ch1_level), i); + save_item(NAME(m_slots[i].ch2_level), i); + save_item(NAME(m_slots[i].ch3_level), i); + save_item(NAME(m_slots[i].startaddr), i); + save_item(NAME(m_slots[i].loopaddr), i); + save_item(NAME(m_slots[i].endaddr), i); + save_item(NAME(m_slots[i].altloop), i); + save_item(NAME(m_slots[i].fs), i); + save_item(NAME(m_slots[i].srcnote), i); + save_item(NAME(m_slots[i].srcb), i); + save_item(NAME(m_slots[i].step), i); + save_item(NAME(m_slots[i].stepptr), i); + save_item(NAME(m_slots[i].active), i); + save_item(NAME(m_slots[i].bits), i); + save_item(NAME(m_slots[i].volume), i); + save_item(NAME(m_slots[i].env_state), i); + save_item(NAME(m_slots[i].env_attack_step), i); + save_item(NAME(m_slots[i].env_decay1_step), i); + save_item(NAME(m_slots[i].env_decay2_step), i); + save_item(NAME(m_slots[i].env_release_step), i); + save_item(NAME(m_slots[i].feedback_modulation0), i); + save_item(NAME(m_slots[i].feedback_modulation1), i); + save_item(NAME(m_slots[i].lfo_phase), i); + save_item(NAME(m_slots[i].lfo_step), i); + save_item(NAME(m_slots[i].lfo_amplitude), i); + } + + for (i = 0; i < ARRAY_LENGTH(m_groups); i++) + { + save_item(NAME(m_groups[i].sync), i); + save_item(NAME(m_groups[i].pfm), i); + } + + save_item(NAME(m_regs_main)); + save_item(NAME(m_timerA)); + save_item(NAME(m_timerB)); + save_item(NAME(m_irqstate)); + save_item(NAME(m_status)); + save_item(NAME(m_enable)); + save_item(NAME(m_ext_address)); + save_item(NAME(m_ext_rw)); + save_item(NAME(m_ext_readlatch)); +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void ymf271_device::device_start() +{ + m_clock = clock(); + + m_timA = timer_alloc(0); + m_timB = timer_alloc(1); + + m_mem_base = region()->base(); + m_mem_size = region()->bytes(); + m_irq_handler.resolve(); + + m_ext_read_handler.resolve(); + m_ext_write_handler.resolve(); + + init_tables(); + init_state(); + + m_stream = machine().sound().stream_alloc(*this, 0, 2, clock()/384); + m_mix_buffer = auto_alloc_array(machine(), INT32, 44100*2); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void ymf271_device::device_reset() +{ + for (int i = 0; i < 48; i++) + { + m_slots[i].active = 0; + m_slots[i].volume = 0; + } + + // reset timers and IRQ + m_timA->reset(); + m_timB->reset(); + + m_irqstate = 0; + m_status = 0; + m_enable = 0; + + if (!m_irq_handler.isnull()) + m_irq_handler(0); +} + +const device_type YMF271 = &device_creator; + +ymf271_device::ymf271_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, YMF271, "YMF271", tag, owner, clock, "ymf271", __FILE__), + device_sound_interface(mconfig, *this), + m_timerA(0), + m_timerB(0), + m_irqstate(0), + m_status(0), + m_enable(0), + m_ext_address(0), + m_ext_rw(0), + m_ext_readlatch(0), + m_irq_handler(*this), + m_ext_read_handler(*this), + m_ext_write_handler(*this) +{ + memset(m_slots, 0, sizeof(m_slots)); + memset(m_groups, 0, sizeof(m_groups)); + memset(m_regs_main, 0, sizeof(m_regs_main)); +} + +//------------------------------------------------- +// device_config_complete - perform any +// operations now that the configuration is +// complete +//------------------------------------------------- + +void ymf271_device::device_config_complete() +{ +} diff --git a/src/devices/sound/ymf271.h b/src/devices/sound/ymf271.h new file mode 100644 index 00000000000..185a8fda4eb --- /dev/null +++ b/src/devices/sound/ymf271.h @@ -0,0 +1,166 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert, R. Belmont, hap +#pragma once + +#ifndef __YMF271_H__ +#define __YMF271_H__ + +#include "emu.h" + +#define MCFG_YMF271_IRQ_HANDLER(_devcb) \ + devcb = &ymf271_device::set_irq_handler(*device, DEVCB_##_devcb); + +#define MCFG_YMF271_EXT_READ_HANDLER(_devcb) \ + devcb = &ymf271_device::set_ext_read_handler(*device, DEVCB_##_devcb); + +#define MCFG_YMF271_EXT_WRITE_HANDLER(_devcb) \ + devcb = &ymf271_device::set_ext_write_handler(*device, DEVCB_##_devcb); + +class ymf271_device : public device_t, + public device_sound_interface +{ +public: + ymf271_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // static configuration helpers + template static devcb_base &set_irq_handler(device_t &device, _Object object) { return downcast(device).m_irq_handler.set_callback(object); } + template static devcb_base &set_ext_read_handler(device_t &device, _Object object) { return downcast(device).m_ext_read_handler.set_callback(object); } + template static devcb_base &set_ext_write_handler(device_t &device, _Object object) { return downcast(device).m_ext_write_handler.set_callback(object); } + + DECLARE_READ8_MEMBER( read ); + DECLARE_WRITE8_MEMBER( write ); + +protected: + // device-level overrides + virtual void device_config_complete(); + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + // sound stream update overrides + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); +private: + struct YMF271Slot + { + UINT8 ext_en; + UINT8 ext_out; + UINT8 lfoFreq; + UINT8 lfowave; + UINT8 pms, ams; + UINT8 detune; + UINT8 multiple; + UINT8 tl; + UINT8 keyscale; + UINT8 ar; + UINT8 decay1rate, decay2rate; + UINT8 decay1lvl; + UINT8 relrate; + UINT8 block; + UINT8 fns_hi; + UINT32 fns; + UINT8 feedback; + UINT8 waveform; + UINT8 accon; + UINT8 algorithm; + UINT8 ch0_level, ch1_level, ch2_level, ch3_level; + + UINT32 startaddr; + UINT32 loopaddr; + UINT32 endaddr; + UINT8 altloop; + UINT8 fs; + UINT8 srcnote, srcb; + + UINT32 step; + UINT64 stepptr; + + UINT8 active; + UINT8 bits; + + // envelope generator + INT32 volume; + INT32 env_state; + INT32 env_attack_step; // volume increase step in attack state + INT32 env_decay1_step; + INT32 env_decay2_step; + INT32 env_release_step; + + INT64 feedback_modulation0; + INT64 feedback_modulation1; + + int lfo_phase, lfo_step; + int lfo_amplitude; + double lfo_phasemod; + }; + + struct YMF271Group + { + UINT8 sync, pfm; + }; + + void init_state(); + void init_tables(); + void calculate_step(YMF271Slot *slot); + void update_envelope(YMF271Slot *slot); + void init_envelope(YMF271Slot *slot); + void init_lfo(YMF271Slot *slot); + void update_lfo(YMF271Slot *slot); + INT64 calculate_slot_volume(YMF271Slot *slot); + void update_pcm(int slotnum, INT32 *mixp, int length); + INT64 calculate_op(int slotnum, INT64 inp); + void set_feedback(int slotnum, INT64 inp); + void write_register(int slotnum, int reg, UINT8 data); + void ymf271_write_fm(int bank, UINT8 address, UINT8 data); + void ymf271_write_pcm(UINT8 address, UINT8 data); + void ymf271_write_timer(UINT8 address, UINT8 data); + UINT8 ymf271_read_memory(UINT32 offset); + + inline int get_keyscaled_rate(int rate, int keycode, int keyscale); + inline int get_internal_keycode(int block, int fns); + inline int get_external_keycode(int block, int fns); + inline bool check_envelope_end(YMF271Slot *slot); + + // lookup tables + INT16 *m_lut_waves[8]; + double *m_lut_plfo[4][8]; + int *m_lut_alfo[4]; + double m_lut_ar[64]; + double m_lut_dc[64]; + double m_lut_lfo[256]; + int m_lut_attenuation[16]; + int m_lut_total_level[128]; + int m_lut_env_volume[256]; + + // internal state + YMF271Slot m_slots[48]; + YMF271Group m_groups[12]; + + UINT8 m_regs_main[0x10]; + + UINT32 m_timerA; + UINT32 m_timerB; + UINT8 m_irqstate; + UINT8 m_status; + UINT8 m_enable; + + UINT32 m_ext_address; + UINT8 m_ext_rw; + UINT8 m_ext_readlatch; + + UINT8 *m_mem_base; + UINT32 m_mem_size; + UINT32 m_clock; + + emu_timer *m_timA, *m_timB; + sound_stream *m_stream; + INT32 *m_mix_buffer; + + devcb_write_line m_irq_handler; + devcb_read8 m_ext_read_handler; + devcb_write8 m_ext_write_handler; +}; + +extern const device_type YMF271; + + +#endif /* __YMF271_H__ */ diff --git a/src/devices/sound/ymf278b.c b/src/devices/sound/ymf278b.c new file mode 100644 index 00000000000..60097767655 --- /dev/null +++ b/src/devices/sound/ymf278b.c @@ -0,0 +1,1051 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont, Olivier Galibert, hap +/* + + YMF278B FM + Wave table Synthesizer (OPL4) + + Timer and PCM YMF278B. The FM will be shared with the ymf262, eventually. + + This chip roughly splits the difference between the Sega 315-5560 MultiPCM + (Multi32, Model 1/2) and YMF 292-F SCSP (later Model 2, STV, Saturn, Model 3). + + Features as listed in LSI-4MF2782 data sheet: + FM Synthesis (same as YMF262) + 1. Sound generation mode + Two-operater mode + Generates eighteen voices or fifteen voices plus five rhythm sounds simultaneously + Four-operator mode + Generates six voices in four-operator mode plus six voices in two-operator mode simultaneously, + or generates six voices in four-operator mode plus three voices in two-operator mode plus five + rhythm sounds simultaneously + 2. Eight selectable waveforms + 3. Stereo output + Wave Table Synthesis + 1. Generates twenty-four voices simultaneously + 2. 44.1kHz sampling rate for output sound data + 3. Selectable from 8-bit, 12-bit and 16-bit word lengths for wave data + 4. Stereo output (16-stage panpot for each voice) + Wave Data + 1. Accepts 32M bit external memory at maximum + 2. Up to 512 wave tables + 3. External ROM or SRAM can be connected. With SRAM connected, the CPU can download wave data + 4. Outputs chip select signals for 1Mbit, 4Mbit, 8Mbit or 16Mbit memory + 5. Can be directly connected to the Yamaha YRW801 (Wave data ROM) + Features of YRW801 as listed in LSI 4RW801A2 + Built-in wave data of tones which comply with GM system Level 1 + Melody tone ....... 128 tones + Percussion tone ... 47 tones + 16Mbit capacity (2,097,152word x 8) + + By R. Belmont and O. Galibert. + + + TODO: + - accurate timing of envelopes + - LFO (vibrato, tremolo) + - integrate YMF262 mixing (used by Fuuki games, not used by Psikyo and Metro games) +*/ + +#include "emu.h" +#include "ymf278b.h" +#include "ymf262.h" + +#define VERBOSE 0 +#define LOG(x) do { if (VERBOSE) logerror x; } while (0) + + +// default address map +static ADDRESS_MAP_START( ymf278b, AS_0, 8, ymf278b_device ) + AM_RANGE(0x000000, 0x3fffff) AM_ROM +ADDRESS_MAP_END + + +/**************************************************************************/ + +int ymf278b_device::compute_rate(YMF278BSlot *slot, int val) +{ + int res, oct; + + if(val == 0) + return 0; + if(val == 15) + return 63; + if(slot->RC != 15) + { + oct = slot->octave; + if (oct & 8) + oct |= -8; + + res = (oct+slot->RC)*2 + (slot->F_NUMBER & 0x200 ? 1 : 0) + val*4; + } + else + res = val * 4; + if(res < 0) + res = 0; + else if(res > 63) + res = 63; + + return res; +} + +UINT32 ymf278b_device::compute_decay_env_vol_step(YMF278BSlot *slot, int val) +{ + int rate; + UINT32 res; + + // rate override with damping/pseudo reverb + if (slot->DAMP) + rate = 56; // approximate, datasheet says it's slightly curved though + else if (slot->preverb && slot->env_vol > ((6*8)<<23)) + { + // pseudo reverb starts at -18dB (6 in voltab) + slot->env_preverb = 1; + rate = 5; + } + else + rate = compute_rate(slot, val); + + if (rate < 4) + res = 0; + else + res = (256U<<23) / m_lut_dr[rate]; + + return res; +} + +void ymf278b_device::compute_freq_step(YMF278BSlot *slot) +{ + UINT32 step; + int oct; + + oct = slot->octave; + if(oct & 8) + oct |= -8; + + step = (slot->F_NUMBER | 1024) << (oct + 8); + slot->step = step >> 3; +} + +void ymf278b_device::compute_envelope(YMF278BSlot *slot) +{ + switch (slot->env_step) + { + // Attack + case 0: + { + // Attack + int rate = compute_rate(slot, slot->AR); + slot->env_vol = 256U<<23; + slot->env_vol_lim = (256U<<23) - 1; + + if (rate==63) + { + // immediate + LOG(("YMF278B: Attack skipped - ")); + slot->env_vol = 0; + slot->env_step++; + compute_envelope(slot); + } + else if (rate<4) + { + slot->env_vol_step = 0; + } + else + { + // NOTE: attack rate is linear here, but datasheet shows a smooth curve + LOG(("YMF278B: Attack, val = %d, rate = %d, delay = %g\n", slot->AR, rate, m_lut_ar[rate]*1000.0)); + slot->env_vol_step = ~((256U<<23) / m_lut_ar[rate]); + } + + break; + } + + // Decay 1 + case 1: + if(slot->DL) + { + LOG(("YMF278B: Decay step 1, dl=%d, val = %d rate = %d, delay = %g, PRVB = %d, DAMP = %d\n", slot->DL, slot->D1R, compute_rate(slot, slot->D1R), m_lut_dr[compute_rate(slot, slot->D1R)]*1000.0, slot->preverb, slot->DAMP)); + slot->env_vol_step = compute_decay_env_vol_step(slot, slot->D1R); + slot->env_vol_lim = (slot->DL*8)<<23; + } + else + { + LOG(("YMF278B: Decay 1 skipped - ")); + slot->env_step++; + compute_envelope(slot); + } + + break; + + // Decay 2 + case 2: + LOG(("YMF278B: Decay step 2, val = %d, rate = %d, delay = %g, , PRVB = %d, DAMP = %d, current vol = %d\n", slot->D2R, compute_rate(slot, slot->D2R), m_lut_dr[compute_rate(slot, slot->D2R)]*1000.0, slot->preverb, slot->DAMP, slot->env_vol >> 23)); + slot->env_vol_step = compute_decay_env_vol_step(slot, slot->D2R); + slot->env_vol_lim = 256U<<23; + break; + + // Decay 2 reached -96dB + case 3: + LOG(("YMF278B: Voice cleared because of decay 2\n")); + slot->env_vol = 256U<<23; + slot->env_vol_step = 0; + slot->env_vol_lim = 0; + slot->active = 0; + break; + + // Release + case 4: + LOG(("YMF278B: Release, val = %d, rate = %d, delay = %g, PRVB = %d, DAMP = %d\n", slot->RR, compute_rate(slot, slot->RR), m_lut_dr[compute_rate(slot, slot->RR)]*1000.0, slot->preverb, slot->DAMP)); + slot->env_vol_step = compute_decay_env_vol_step(slot, slot->RR); + slot->env_vol_lim = 256U<<23; + break; + + // Release reached -96dB + case 5: + LOG(("YMF278B: Release ends\n")); + slot->env_vol = 256U<<23; + slot->env_vol_step = 0; + slot->env_vol_lim = 0; + slot->active = 0; + break; + + default: break; + } +} + +//------------------------------------------------- +// sound_stream_update - handle a stream update +//------------------------------------------------- + +void ymf278b_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + int i, j; + YMF278BSlot *slot = NULL; + INT16 sample = 0; + INT32 *mixp; + INT32 vl, vr; + + if (&stream == m_stream_ymf262) + { + ymf262_update_one(m_ymf262, outputs, samples); + return; + } + + memset(m_mix_buffer, 0, sizeof(m_mix_buffer[0])*samples*2); + + for (i = 0; i < 24; i++) + { + slot = &m_slots[i]; + + if (slot->active) + { + mixp = m_mix_buffer; + + for (j = 0; j < samples; j++) + { + if (slot->stepptr >= slot->endaddr) + { + slot->stepptr = slot->stepptr - slot->endaddr + slot->loopaddr; + + // NOTE: loop overflow is still possible here if (slot->stepptr >= slot->endaddr) + // This glitch may be (ab)used to your advantage to create pseudorandom noise. + } + + switch (slot->bits) + { + // 8 bit + case 0: + sample = m_direct->read_byte(slot->startaddr + (slot->stepptr>>16))<<8; + break; + + // 12 bit + case 1: + if (slot->stepptr & 0x10000) + sample = m_direct->read_byte(slot->startaddr + (slot->stepptr>>17)*3+2)<<8 | + (m_direct->read_byte(slot->startaddr + (slot->stepptr>>17)*3+1) << 4 & 0xf0); + else + sample = m_direct->read_byte(slot->startaddr + (slot->stepptr>>17)*3)<<8 | + (m_direct->read_byte(slot->startaddr + (slot->stepptr>>17)*3+1) & 0xf0); + break; + + // 16 bit + case 2: + sample = m_direct->read_byte(slot->startaddr + ((slot->stepptr>>16)*2))<<8 | + m_direct->read_byte(slot->startaddr + ((slot->stepptr>>16)*2)+1); + break; + + // ?? bit, effect is unknown, datasheet says it's prohibited + case 3: + sample = 0; + break; + } + + *mixp++ += (sample * m_volume[slot->TL+m_pan_left [slot->pan]+(slot->env_vol>>23)])>>17; + *mixp++ += (sample * m_volume[slot->TL+m_pan_right[slot->pan]+(slot->env_vol>>23)])>>17; + + // update frequency + slot->stepptr += slot->step; + + // update envelope + slot->env_vol += slot->env_vol_step; + if (((INT32)(slot->env_vol - slot->env_vol_lim)) >= 0) + { + slot->env_step++; + compute_envelope(slot); + } + else if (slot->preverb && !slot->env_preverb && slot->env_step && slot->env_vol > ((6*8)<<23)) + compute_envelope(slot); + } + } + } + + mixp = m_mix_buffer; + vl = m_mix_level[m_pcm_l]; + vr = m_mix_level[m_pcm_r]; + for (i = 0; i < samples; i++) + { + outputs[0][i] = (*mixp++ * vl) >> 16; + outputs[1][i] = (*mixp++ * vr) >> 16; + } +} + +void ymf278b_device::irq_check() +{ + int prev_line = m_irq_line; + m_irq_line = m_current_irq ? 1 : 0; + if (m_irq_line != prev_line && !m_irq_handler.isnull()) + m_irq_handler(m_irq_line); +} + +enum +{ + TIMER_A = 0, + TIMER_B, + TIMER_BUSY_CLEAR, + TIMER_LD_CLEAR +}; + +void ymf278b_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch(id) + { + case TIMER_A: + if(!(m_enable & 0x40)) + { + m_current_irq |= 0x40; + irq_check(); + } + break; + + case TIMER_B: + if(!(m_enable & 0x20)) + { + m_current_irq |= 0x20; + irq_check(); + } + break; + + case TIMER_BUSY_CLEAR: + m_status_busy = 0; + break; + + case TIMER_LD_CLEAR: + m_status_ld = 0; + break; + } +} + + +/**************************************************************************/ + +void ymf278b_device::A_w(UINT8 reg, UINT8 data) +{ + // FM register array 0 (compatible with YMF262) + switch(reg) + { + // LSI TEST + case 0x00: + case 0x01: + break; + + // timer a count + case 0x02: + if (data != m_timer_a_count) + { + m_timer_a_count = data; + + // change period, ~80.8us * t + if (m_enable & 1) + m_timer_a->adjust(m_timer_a->remaining(), 0, m_timer_base * (256-data) * 4); + } + break; + + // timer b count + case 0x03: + if (data != m_timer_b_count) + { + m_timer_b_count = data; + + // change period, ~323.1us * t + if (m_enable & 2) + m_timer_b->adjust(m_timer_b->remaining(), 0, m_timer_base * (256-data) * 16); + } + break; + + // timer control + case 0x04: + if(data & 0x80) + m_current_irq = 0; + else + { + // reset timers + if((m_enable ^ data) & 1) + { + attotime period = (data & 1) ? m_timer_base * (256-m_timer_a_count) * 4 : attotime::never; + m_timer_a->adjust(period, 0, period); + } + if((m_enable ^ data) & 2) + { + attotime period = (data & 2) ? m_timer_base * (256-m_timer_b_count) * 16 : attotime::never; + m_timer_b->adjust(period, 0, period); + } + + m_enable = data; + m_current_irq &= ~data; + } + irq_check(); + break; + + default: + logerror("YMF278B: Port A write %02x, %02x\n", reg, data); + break; + } +} + +void ymf278b_device::B_w(UINT8 reg, UINT8 data) +{ + // FM register array 1 (compatible with YMF262) + switch(reg) + { + // LSI TEST + case 0x00: + case 0x01: + break; + + // expansion register (NEW2/NEW) + case 0x05: + m_exp = data; + break; + + default: + logerror("YMF278B: Port B write %02x, %02x\n", reg, data); + break; + } +} + +void ymf278b_device::retrigger_note(YMF278BSlot *slot) +{ + // activate channel + if (slot->octave != 8) + slot->active = 1; + + // reset sample pos and go to attack stage + slot->stepptr = 0; + slot->env_step = 0; + slot->env_preverb = 0; + + compute_freq_step(slot); + compute_envelope(slot); +} + +void ymf278b_device::C_w(UINT8 reg, UINT8 data) +{ + // Handle slot registers specifically + if (reg >= 0x08 && reg <= 0xf7) + { + YMF278BSlot *slot = NULL; + int snum; + snum = (reg-8) % 24; + slot = &m_slots[snum]; + switch((reg-8) / 24) + { + case 0: + { + attotime period; + UINT32 offset; + UINT8 p[12]; + int i; + + slot->wave &= 0x100; + slot->wave |= data; + + // load wavetable header + if(slot->wave < 384 || !m_wavetblhdr) + offset = slot->wave * 12; + else + offset = m_wavetblhdr*0x80000 + (slot->wave - 384) * 12; + for (i = 0; i < 12; i++) + p[i] = m_direct->read_byte(offset+i); + + slot->bits = (p[0]&0xc0)>>6; + slot->startaddr = (p[2] | (p[1]<<8) | ((p[0]&0x3f)<<16)); + slot->loopaddr = (p[4]<<16) | (p[3]<<24); + slot->endaddr = (p[6]<<16) | (p[5]<<24); + slot->endaddr -= 0x00010000U; + slot->endaddr ^= 0xffff0000U; + + // copy internal registers data + for (i = 7; i < 12; i++) + C_w(8 + snum + (i-2) * 24, p[i]); + + // status register LD bit is on for approx 300us + m_status_ld = 1; + period = attotime::from_usec(300); + if (m_clock != YMF278B_STD_CLOCK) + period = (period * m_clock) / YMF278B_STD_CLOCK; + m_timer_ld->adjust(period); + + // retrigger if key is on + if (slot->KEY_ON) + retrigger_note(slot); + else if (slot->active) + { + // deactivate channel + slot->env_step = 5; + compute_envelope(slot); + } + + break; + } + + case 1: + slot->wave &= 0xff; + slot->wave |= ((data&0x1)<<8); + slot->F_NUMBER &= 0x380; + slot->F_NUMBER |= (data>>1); + if (slot->active && (data ^ m_pcmregs[reg]) & 0xfe) + { + compute_freq_step(slot); + compute_envelope(slot); + } + break; + + case 2: + slot->F_NUMBER &= 0x07f; + slot->F_NUMBER |= ((data&0x07)<<7); + slot->preverb = (data&0x8)>>3; + slot->octave = (data&0xf0)>>4; + if (data != m_pcmregs[reg]) + { + // channel goes off if octave is set to -8 (datasheet says it's prohibited) + // (it is ok if this activates the channel while it was off: compute_envelope will reset it again if needed) + slot->active = (slot->octave != 8); + + if (slot->active) + { + slot->env_preverb = 0; + compute_freq_step(slot); + compute_envelope(slot); + } + } + break; + + case 3: + slot->TL = data>>1; + slot->LD = data&0x1; + break; + + case 4: + slot->CH = (data&0x10)>>4; + // CH bit note: output to DO1 pin (1) or DO2 pin (0), this may + // silence the channel depending on how it's wired up on the PCB. + // For now, it's always enabled. + // (bit 5 (LFO reset) is also not hooked up yet) + + slot->pan = data&0xf; + slot->DAMP = (data&0x40)>>6; + if (data & 0x80) + { + // don't retrigger if key was already on + if (slot->KEY_ON) + { + if ((data ^ m_pcmregs[reg]) & 0x40) + compute_envelope(slot); + + break; + } + + retrigger_note(slot); + } + else if (slot->active) + { + // release + slot->env_step = 4; + compute_envelope(slot); + } + slot->KEY_ON = (data&0x80)>>7; + break; + + case 5: + // LFO and vibrato level, not hooked up yet + slot->LFO = (data>>3)&0x7; + slot->VIB = data&0x7; + break; + + case 6: + slot->AR = data>>4; + slot->D1R = data&0xf; + if (slot->active && data != m_pcmregs[reg]) + compute_envelope(slot); + break; + + case 7: + slot->DL = data>>4; + slot->D2R = data&0xf; + if (slot->active && data != m_pcmregs[reg]) + compute_envelope(slot); + break; + + case 8: + slot->RC = data>>4; + slot->RR = data&0xf; + if (slot->active && data != m_pcmregs[reg]) + compute_envelope(slot); + break; + + case 9: + // tremolo level, not hooked up yet + slot->AM = data & 0x7; + break; + } + } + else + { + // All non-slot registers + switch (reg) + { + // LSI TEST + case 0x00: + case 0x01: + break; + + case 0x02: + m_wavetblhdr = (data>>2)&0x7; + m_memmode = data&3; + break; + + case 0x03: + data &= 0x3f; // ! + break; + case 0x04: + break; + case 0x05: + // set memory address + m_memadr = m_pcmregs[3] << 16 | m_pcmregs[4] << 8 | data; + break; + + case 0x06: + // memory data + m_addrspace[0]->write_byte(m_memadr, data); + m_memadr = (m_memadr + 1) & 0x3fffff; + break; + + case 0x07: + break; // unused + + case 0xf8: + m_fm_l = data & 0x7; + m_fm_r = (data>>3)&0x7; + break; + + case 0xf9: + m_pcm_l = data & 0x7; + m_pcm_r = (data>>3)&0x7; + break; + + default: + logerror("YMF278B: Port C write %02x, %02x\n", reg, data); + break; + } + } + + m_pcmregs[reg] = data; +} + +void ymf278b_device::timer_busy_start(int is_pcm) +{ + // status register BUSY bit is on for 56(FM) or 88(PCM) cycles + m_status_busy = 1; + m_timer_busy->adjust(attotime::from_hz(m_clock / (is_pcm ? 88 : 56))); +} + +WRITE8_MEMBER( ymf278b_device::write ) +{ + switch (offset) + { + case 0: + case 2: + timer_busy_start(0); + m_port_AB = data; + m_lastport = offset>>1 & 1; + ymf262_write(m_ymf262, offset, data); + break; + + case 1: + case 3: + timer_busy_start(0); + if (m_lastport) B_w(m_port_AB, data); + else A_w(m_port_AB, data); + m_last_fm_data = data; + ymf262_write(m_ymf262, offset, data); + break; + + case 4: + timer_busy_start(1); + m_port_C = data; + break; + + case 5: + // PCM regs are only accessible if NEW2 is set + if (~m_exp & 2) + break; + + m_stream->update(); + + timer_busy_start(1); + C_w(m_port_C, data); + break; + + default: + logerror("%s: unexpected write at offset %X to ymf278b = %02X\n", machine().describe_context(), offset, data); + break; + } +} + + +READ8_MEMBER( ymf278b_device::read ) +{ + UINT8 ret = 0; + + switch (offset) + { + // status register + case 0: + { + // bits 0 and 1 are only valid if NEW2 is set + UINT8 newbits = 0; + if (m_exp & 2) + newbits = (m_status_ld << 1) | m_status_busy; + + ret = newbits | m_current_irq | (m_irq_line ? 0x80 : 0x00); + break; + } + + // FM regs can be read too (on contrary to what the datasheet says) + case 1: + case 3: + // but they're not implemented here yet + // This may be incorrect, but it makes the mbwave moonsound detection in msx drivers pass. + ret = m_last_fm_data; + break; + + // PCM regs + case 5: + // only accessible if NEW2 is set + if (~m_exp & 2) + break; + + switch (m_port_C) + { + // special cases + case 2: + ret = (m_pcmregs[m_port_C] & 0x1f) | 0x20; // device ID in upper bits + break; + case 6: + ret = m_direct->read_byte(m_memadr); + m_memadr = (m_memadr + 1) & 0x3fffff; + break; + + default: + ret = m_pcmregs[m_port_C]; + break; + } + break; + + default: + logerror("%s: unexpected read at offset %X from ymf278b\n", machine().describe_context(), offset); + break; + } + + return ret; +} + + +/**************************************************************************/ + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void ymf278b_device::device_reset() +{ + int i; + + // clear registers + for (i = 0; i <= 4; i++) + A_w(i, 0); + B_w(5, 0); + for (i = 0; i < 8; i++) + C_w(i, 0); + for (i = 0xff; i >= 8; i--) + C_w(i, 0); + C_w(0xf8, 0x1b); + + m_port_AB = m_port_C = 0; + m_lastport = 0; + m_memadr = 0; + + // init/silence channels + for (i = 0; i < 24 ; i++) + { + YMF278BSlot *slot = &m_slots[i]; + + slot->LFO = 0; + slot->VIB = 0; + slot->AR = 0; + slot->D1R = 0; + slot->DL = 0; + slot->D2R = 0; + slot->RC = 0; + slot->RR = 0; + slot->AM = 0; + + slot->startaddr = 0; + slot->loopaddr = 0; + slot->endaddr = 0; + + slot->env_step = 5; + compute_envelope(slot); + } + + m_timer_a->reset(); + m_timer_b->reset(); + m_timer_busy->reset(); m_status_busy = 0; + m_timer_ld->reset(); m_status_ld = 0; + + m_irq_line = 0; + m_current_irq = 0; + if (!m_irq_handler.isnull()) + m_irq_handler(0); + + ymf262_reset_chip(m_ymf262); +} + +void ymf278b_device::device_stop() +{ + ymf262_shutdown(m_ymf262); + m_ymf262 = NULL; +} + +void ymf278b_device::precompute_rate_tables() +{ + int i; + + // decay rate + for (i = 0; i < 64; i++) + { + if (i <= 3) + m_lut_dr[i] = 0; + else if (i >= 60) + m_lut_dr[i] = 15 << 4; + else + m_lut_dr[i] = (15 << (21 - i / 4)) / (4 + i % 4); + } + + // attack rate (manual shows curve instead of linear though, so this is not entirely accurate) + for (i = 0; i < 64; i++) + { + if (i <= 3 || i == 63) + m_lut_ar[i] = 0; + else if (i >= 60) + m_lut_ar[i] = 17; + else + m_lut_ar[i] = (67 << (15 - i / 4)) / (4 + i % 4); + } +} + +void ymf278b_device::register_save_state() +{ + int i; + + save_item(NAME(m_pcmregs)); + save_item(NAME(m_wavetblhdr)); + save_item(NAME(m_memmode)); + save_item(NAME(m_memadr)); + save_item(NAME(m_status_busy)); + save_item(NAME(m_status_ld)); + save_item(NAME(m_exp)); + save_item(NAME(m_fm_l)); + save_item(NAME(m_fm_r)); + save_item(NAME(m_pcm_l)); + save_item(NAME(m_pcm_r)); + save_item(NAME(m_timer_a_count)); + save_item(NAME(m_timer_b_count)); + save_item(NAME(m_enable)); + save_item(NAME(m_current_irq)); + save_item(NAME(m_irq_line)); + save_item(NAME(m_port_AB)); + save_item(NAME(m_port_C)); + save_item(NAME(m_lastport)); + save_item(NAME(m_last_fm_data)); + + for (i = 0; i < 24; ++i) + { + save_item(NAME(m_slots[i].wave), i); + save_item(NAME(m_slots[i].F_NUMBER), i); + save_item(NAME(m_slots[i].octave), i); + save_item(NAME(m_slots[i].preverb), i); + save_item(NAME(m_slots[i].DAMP), i); + save_item(NAME(m_slots[i].CH), i); + save_item(NAME(m_slots[i].LD), i); + save_item(NAME(m_slots[i].TL), i); + save_item(NAME(m_slots[i].pan), i); + save_item(NAME(m_slots[i].LFO), i); + save_item(NAME(m_slots[i].VIB), i); + save_item(NAME(m_slots[i].AM), i); + + save_item(NAME(m_slots[i].AR), i); + save_item(NAME(m_slots[i].D1R), i); + save_item(NAME(m_slots[i].DL), i); + save_item(NAME(m_slots[i].D2R), i); + save_item(NAME(m_slots[i].RC), i); + save_item(NAME(m_slots[i].RR), i); + + save_item(NAME(m_slots[i].step), i); + save_item(NAME(m_slots[i].stepptr), i); + + save_item(NAME(m_slots[i].active), i); + save_item(NAME(m_slots[i].KEY_ON), i); + save_item(NAME(m_slots[i].bits), i); + save_item(NAME(m_slots[i].startaddr), i); + save_item(NAME(m_slots[i].loopaddr), i); + save_item(NAME(m_slots[i].endaddr), i); + + save_item(NAME(m_slots[i].env_step), i); + save_item(NAME(m_slots[i].env_vol), i); + save_item(NAME(m_slots[i].env_vol_step), i); + save_item(NAME(m_slots[i].env_vol_lim), i); + save_item(NAME(m_slots[i].env_preverb), i); + } +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +static void ymf278b_ymf262_irq_handler(void *param,int irq) +{ +} + + +static void ymf278b_ymf262_timer_handler(void *param, int c, const attotime &period) +{ +} + +static void ymf278b_ymf262_update_request(void *param, int interval) +{ + ymf278b_device *ymf278b = (ymf278b_device *) param; + ymf278b->ymf262_update_request(); +} + + +void ymf278b_device::ymf262_update_request() +{ + m_stream_ymf262->update(); +} + + +void ymf278b_device::device_start() +{ + int i; + + m_direct = &space().direct(); + m_clock = clock(); + m_irq_handler.resolve(); + + m_timer_base = attotime::from_hz(m_clock) * (19*36); + m_timer_a = timer_alloc(TIMER_A); + m_timer_b = timer_alloc(TIMER_B); + m_timer_busy = timer_alloc(TIMER_BUSY_CLEAR); + m_timer_ld = timer_alloc(TIMER_LD_CLEAR); + + for (i = 0; i < 24; i++) + { + m_slots[i].num = i; + } + + m_stream = machine().sound().stream_alloc(*this, 0, 2, clock()/768); + m_mix_buffer = auto_alloc_array(machine(), INT32, 44100*2); + + // rate tables + precompute_rate_tables(); + + // Volume table, 1 = -0.375dB, 8 = -3dB, 256 = -96dB + for(i = 0; i < 256; i++) + m_volume[i] = 65536*pow(2.0, (-0.375/6)*i); + for(i = 256; i < 256*4; i++) + m_volume[i] = 0; + + // Pan values, units are -3dB, i.e. 8. + for(i = 0; i < 16; i++) + { + m_pan_left[i] = i < 7 ? i*8 : i < 9 ? 256 : 0; + m_pan_right[i] = i < 8 ? 0 : i < 10 ? 256 : (16-i)*8; + } + + // Mixing levels, units are -3dB, and add some margin to avoid clipping + for(i=0; i<7; i++) + m_mix_level[i] = m_volume[8*i+13]; + m_mix_level[7] = 0; + + // Register state for saving + register_save_state(); + + // YMF262 related + + /* stream system initialize */ + int ymf262_clock = clock() / (19/8.0); + m_ymf262 = ymf262_init(this, ymf262_clock, ymf262_clock / 288); + assert_always(m_ymf262 != NULL, "Error creating YMF262 chip"); + + m_stream_ymf262 = machine().sound().stream_alloc(*this, 0, 4, ymf262_clock / 288); + + /* YMF262 setup */ + ymf262_set_timer_handler (m_ymf262, ymf278b_ymf262_timer_handler, this); + ymf262_set_irq_handler (m_ymf262, ymf278b_ymf262_irq_handler, this); + ymf262_set_update_handler(m_ymf262, ymf278b_ymf262_update_request, this); +} + + +const device_type YMF278B = &device_creator; + +ymf278b_device::ymf278b_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, YMF278B, "YMF278B", tag, owner, clock, "ymf278b", __FILE__), + device_sound_interface(mconfig, *this), + device_memory_interface(mconfig, *this), + m_space_config("samples", ENDIANNESS_BIG, 8, 22, 0, NULL), + m_irq_handler(*this), + m_last_fm_data(0) +{ + m_address_map[0] = *ADDRESS_MAP_NAME(ymf278b); +} + +//------------------------------------------------- +// device_config_complete - perform any +// operations now that the configuration is +// complete +//------------------------------------------------- + +void ymf278b_device::device_config_complete() +{ +} diff --git a/src/devices/sound/ymf278b.h b/src/devices/sound/ymf278b.h new file mode 100644 index 00000000000..096e2e3d3c4 --- /dev/null +++ b/src/devices/sound/ymf278b.h @@ -0,0 +1,147 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont, Olivier Galibert, hap +#pragma once + +#ifndef __YMF278B_H__ +#define __YMF278B_H__ + +#include "emu.h" + +#define YMF278B_STD_CLOCK (33868800) /* standard clock for OPL4 */ + +#define MCFG_YMF278B_IRQ_HANDLER(_devcb) \ + devcb = &ymf278b_device::set_irq_handler(*device, DEVCB_##_devcb); + +class ymf278b_device : public device_t, + public device_sound_interface, + public device_memory_interface +{ +public: + ymf278b_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // static configuration helpers + template static devcb_base &set_irq_handler(device_t &device, _Object object) { return downcast(device).m_irq_handler.set_callback(object); } + + DECLARE_READ8_MEMBER( read ); + DECLARE_WRITE8_MEMBER( write ); + + void ymf262_update_request(); + +protected: + // device-level overrides + virtual void device_config_complete(); + virtual void device_start(); + virtual void device_reset(); + virtual void device_stop(); + + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const { return (spacenum == AS_0) ? &m_space_config : NULL; } + + // sound stream update overrides + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + +private: + struct YMF278BSlot + { + INT16 wave; /* wavetable number */ + INT16 F_NUMBER; /* frequency */ + INT8 octave; /* octave */ + INT8 preverb; /* pseudo-reverb */ + INT8 DAMP; /* damping */ + INT8 CH; /* output channel */ + INT8 LD; /* level direct */ + INT8 TL; /* total level */ + INT8 pan; /* panpot */ + INT8 LFO; /* LFO */ + INT8 VIB; /* vibrato */ + INT8 AM; /* tremolo */ + + INT8 AR; /* attack rate */ + INT8 D1R; /* decay 1 rate */ + INT8 DL; /* decay level */ + INT8 D2R; /* decay 2 rate */ + INT8 RC; /* rate correction */ + INT8 RR; /* release rate */ + + UINT32 step; /* fixed-point frequency step */ + UINT64 stepptr; /* fixed-point pointer into the sample */ + + INT8 active; /* channel is playing */ + INT8 KEY_ON; /* slot keyed on */ + INT8 bits; /* width of the samples */ + UINT32 startaddr; + UINT32 loopaddr; + UINT32 endaddr; + + int env_step; + UINT32 env_vol; + UINT32 env_vol_step; + UINT32 env_vol_lim; + INT8 env_preverb; + + int num; /* slot number (for debug only) */ + }; + + int compute_rate(YMF278BSlot *slot, int val); + UINT32 compute_decay_env_vol_step(YMF278BSlot *slot, int val); + void compute_freq_step(YMF278BSlot *slot); + void compute_envelope(YMF278BSlot *slot); + void irq_check(); + void A_w(UINT8 reg, UINT8 data); + void B_w(UINT8 reg, UINT8 data); + void retrigger_note(YMF278BSlot *slot); + void C_w(UINT8 reg, UINT8 data); + void timer_busy_start(int is_pcm); + void precompute_rate_tables(); + void register_save_state(); + + // internal state + UINT8 m_pcmregs[256]; + YMF278BSlot m_slots[24]; + INT8 m_wavetblhdr; + INT8 m_memmode; + INT32 m_memadr; + + UINT8 m_status_busy, m_status_ld; + emu_timer *m_timer_busy; + emu_timer *m_timer_ld; + UINT8 m_exp; + + INT32 m_fm_l, m_fm_r; + INT32 m_pcm_l, m_pcm_r; + + attotime m_timer_base; + UINT8 m_timer_a_count, m_timer_b_count; + UINT8 m_enable, m_current_irq; + int m_irq_line; + + UINT8 m_port_C, m_port_AB, m_lastport; + + // precomputed tables + UINT32 m_lut_ar[64]; // attack rate + UINT32 m_lut_dr[64]; // decay rate + INT32 m_volume[256*4]; // precalculated attenuation values with some margin for envelope and pan levels + int m_pan_left[16],m_pan_right[16]; // pan volume offsets + INT32 m_mix_level[8]; + + emu_timer *m_timer_a, *m_timer_b; + int m_clock; + + sound_stream * m_stream; + INT32 *m_mix_buffer; + direct_read_data * m_direct; + const address_space_config m_space_config; + devcb_write_line m_irq_handler; + UINT8 m_last_fm_data; + + // ymf262 + void *m_ymf262; + sound_stream * m_stream_ymf262; +}; + +extern const device_type YMF278B; + + +#endif /* __YMF278B_H__ */ diff --git a/src/devices/sound/ymz280b.c b/src/devices/sound/ymz280b.c new file mode 100644 index 00000000000..8a1f323bbdd --- /dev/null +++ b/src/devices/sound/ymz280b.c @@ -0,0 +1,968 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/* + + Yamaha YMZ280B driver + by Aaron Giles + + YMZ280B 8-Channel PCMD8 PCM/ADPCM Decoder + + Features as listed in LSI-4MZ280B3 data sheet: + Voice data stored in external memory can be played back simultaneously for up to eight voices + Voice data format can be selected from 4-bit ADPCM, 8-bit PCM and 16-bit PCM + Control of voice data external memory + Up to 16M bytes of ROM or SRAM (x 8 bits, access time 150ms max) can be connected + Continuous access is possible + Loop playback between selective addresses is possible + Voice data playback frequency control + 4-bit ADPCM ................ 0.172 to 44.1kHz in 256 steps + 8-bit PCM, 16-bit PCM ...... 0.172 to 88.2kHz in 512 steps + 256 steps total level and 16 steps panpot can be set + Voice signal is output in stereo 16-bit 2's complement MSB-first format + + TODO: + - Is memory handling 100% correct? At the moment, Konami firebeat.c is the only + hardware currently emulated that uses external handlers. + It also happens to be the only one using 16-bit PCM. + + Some other drivers (eg. bishi.c, bfm_sc4/5.c) also use ROM readback. + +*/ + + +#include "emu.h" +#include "ymz280b.h" + + +#define MAX_SAMPLE_CHUNK 10000 + +#define FRAC_BITS 14 +#define FRAC_ONE (1 << FRAC_BITS) +#define FRAC_MASK (FRAC_ONE - 1) + +#define INTERNAL_BUFFER_SIZE (1 << 15) +#define INTERNAL_SAMPLE_RATE (m_master_clock * 2.0) + +#if MAKE_WAVS +#include "wavwrite.h" +#endif + + + +/* step size index shift table */ +static const int index_scale[8] = { 0x0e6, 0x0e6, 0x0e6, 0x0e6, 0x133, 0x199, 0x200, 0x266 }; + +/* lookup table for the precomputed difference */ +static int diff_lookup[16]; + + +UINT8 ymz280b_device::ymz280b_read_memory(UINT32 offset) +{ + if (m_ext_read_handler.isnull()) + { + if (offset < m_mem_size) + return m_mem_base[offset]; + + /* 16MB chip limit (shouldn't happen) */ + else if (offset > 0xffffff) + return m_mem_base[offset & 0xffffff]; + + else + return 0; + } + else + return m_ext_read_handler(offset); +} + + +void ymz280b_device::update_irq_state() +{ + int irq_bits = m_status_register & m_irq_mask; + + /* always off if the enable is off */ + if (!m_irq_enable) + irq_bits = 0; + + /* update the state if changed */ + if (irq_bits && !m_irq_state) + { + m_irq_state = 1; + if (!m_irq_handler.isnull()) + m_irq_handler(1); + else logerror("YMZ280B: IRQ generated, but no callback specified!\n"); + } + else if (!irq_bits && m_irq_state) + { + m_irq_state = 0; + if (!m_irq_handler.isnull()) + m_irq_handler(0); + else logerror("YMZ280B: IRQ generated, but no callback specified!\n"); + } +} + + +void ymz280b_device::update_step(struct YMZ280BVoice *voice) +{ + double frequency; + + /* compute the frequency */ + if (voice->mode == 1) + frequency = m_master_clock * (double)((voice->fnum & 0x0ff) + 1) * (1.0 / 256.0); + else + frequency = m_master_clock * (double)((voice->fnum & 0x1ff) + 1) * (1.0 / 256.0); + voice->output_step = (UINT32)(frequency * (double)FRAC_ONE / INTERNAL_SAMPLE_RATE); +} + + +void ymz280b_device::update_volumes(struct YMZ280BVoice *voice) +{ + if (voice->pan == 8) + { + voice->output_left = voice->level; + voice->output_right = voice->level; + } + else if (voice->pan < 8) + { + voice->output_left = voice->level; + + /* pan 1 is hard-left, what's pan 0? for now assume same as pan 1 */ + voice->output_right = (voice->pan == 0) ? 0 : voice->level * (voice->pan - 1) / 7; + } + else + { + voice->output_left = voice->level * (15 - voice->pan) / 7; + voice->output_right = voice->level; + } +} + + +void ymz280b_device::device_post_load() +{ + for (int j = 0; j < 8; j++) + { + struct YMZ280BVoice *voice = &m_voice[j]; + update_step(voice); + if(voice->irq_schedule) + voice->timer->adjust(attotime::zero); + } +} + + +void ymz280b_device::update_irq_state_timer_common(int voicenum) +{ + struct YMZ280BVoice *voice = &m_voice[voicenum]; + + if(!voice->irq_schedule) return; + + voice->playing = 0; + m_status_register |= 1 << voicenum; + update_irq_state(); + voice->irq_schedule = 0; +} + +/********************************************************************************************** + + compute_tables -- compute the difference tables + +***********************************************************************************************/ + +static void compute_tables(void) +{ + /* loop over all nibbles and compute the difference */ + for (int nib = 0; nib < 16; nib++) + { + int value = (nib & 0x07) * 2 + 1; + diff_lookup[nib] = (nib & 0x08) ? -value : value; + } +} + + + +/********************************************************************************************** + + generate_adpcm -- general ADPCM decoding routine + +***********************************************************************************************/ + +int ymz280b_device::generate_adpcm(struct YMZ280BVoice *voice, INT16 *buffer, int samples) +{ + int position = voice->position; + int signal = voice->signal; + int step = voice->step; + int val; + + /* two cases: first cases is non-looping */ + if (!voice->looping) + { + /* loop while we still have samples to generate */ + while (samples) + { + /* compute the new amplitude and update the current step */ + val = ymz280b_read_memory(position / 2) >> ((~position & 1) << 2); + signal += (step * diff_lookup[val & 15]) / 8; + + /* clamp to the maximum */ + if (signal > 32767) + signal = 32767; + else if (signal < -32768) + signal = -32768; + + /* adjust the step size and clamp */ + step = (step * index_scale[val & 7]) >> 8; + if (step > 0x6000) + step = 0x6000; + else if (step < 0x7f) + step = 0x7f; + + /* output to the buffer, scaling by the volume */ + *buffer++ = signal; + samples--; + + /* next! */ + position++; + if (position >= voice->stop) + { + voice->ended = true; + break; + } + } + } + + /* second case: looping */ + else + { + /* loop while we still have samples to generate */ + while (samples) + { + /* compute the new amplitude and update the current step */ + val = ymz280b_read_memory(position / 2) >> ((~position & 1) << 2); + signal += (step * diff_lookup[val & 15]) / 8; + + /* clamp to the maximum */ + if (signal > 32767) + signal = 32767; + else if (signal < -32768) + signal = -32768; + + /* adjust the step size and clamp */ + step = (step * index_scale[val & 7]) >> 8; + if (step > 0x6000) + step = 0x6000; + else if (step < 0x7f) + step = 0x7f; + + /* output to the buffer, scaling by the volume */ + *buffer++ = signal; + samples--; + + /* next! */ + position++; + if (position == voice->loop_start && voice->loop_count == 0) + { + voice->loop_signal = signal; + voice->loop_step = step; + } + if (position >= voice->loop_end) + { + if (voice->keyon) + { + position = voice->loop_start; + signal = voice->loop_signal; + step = voice->loop_step; + voice->loop_count++; + } + } + if (position >= voice->stop) + { + voice->ended = true; + break; + } + } + } + + /* update the parameters */ + voice->position = position; + voice->signal = signal; + voice->step = step; + + return samples; +} + + + +/********************************************************************************************** + + generate_pcm8 -- general 8-bit PCM decoding routine + +***********************************************************************************************/ + +int ymz280b_device::generate_pcm8(struct YMZ280BVoice *voice, INT16 *buffer, int samples) +{ + int position = voice->position; + int val; + + /* two cases: first cases is non-looping */ + if (!voice->looping) + { + /* loop while we still have samples to generate */ + while (samples) + { + /* fetch the current value */ + val = ymz280b_read_memory(position / 2); + + /* output to the buffer, scaling by the volume */ + *buffer++ = (INT8)val * 256; + samples--; + + /* next! */ + position += 2; + if (position >= voice->stop) + { + voice->ended = true; + break; + } + } + } + + /* second case: looping */ + else + { + /* loop while we still have samples to generate */ + while (samples) + { + /* fetch the current value */ + val = ymz280b_read_memory(position / 2); + + /* output to the buffer, scaling by the volume */ + *buffer++ = (INT8)val * 256; + samples--; + + /* next! */ + position += 2; + if (position >= voice->loop_end) + { + if (voice->keyon) + position = voice->loop_start; + } + if (position >= voice->stop) + { + voice->ended = true; + break; + } + } + } + + /* update the parameters */ + voice->position = position; + + return samples; +} + + + +/********************************************************************************************** + + generate_pcm16 -- general 16-bit PCM decoding routine + +***********************************************************************************************/ + +int ymz280b_device::generate_pcm16(struct YMZ280BVoice *voice, INT16 *buffer, int samples) +{ + int position = voice->position; + int val; + + /* two cases: first cases is non-looping */ + if (!voice->looping) + { + /* loop while we still have samples to generate */ + while (samples) + { + /* fetch the current value */ + val = (INT16)((ymz280b_read_memory(position / 2 + 1) << 8) + ymz280b_read_memory(position / 2 + 0)); + + /* output to the buffer, scaling by the volume */ + *buffer++ = val; + samples--; + + /* next! */ + position += 4; + if (position >= voice->stop) + { + voice->ended = true; + break; + } + } + } + + /* second case: looping */ + else + { + /* loop while we still have samples to generate */ + while (samples) + { + /* fetch the current value */ + val = (INT16)((ymz280b_read_memory(position / 2 + 1) << 8) + ymz280b_read_memory(position / 2 + 0)); + + /* output to the buffer, scaling by the volume */ + *buffer++ = val; + samples--; + + /* next! */ + position += 4; + if (position >= voice->loop_end) + { + if (voice->keyon) + position = voice->loop_start; + } + if (position >= voice->stop) + { + voice->ended = true; + break; + } + } + } + + /* update the parameters */ + voice->position = position; + + return samples; +} + + + + +//------------------------------------------------- +// sound_stream_update - handle a stream update +//------------------------------------------------- + +void ymz280b_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + stream_sample_t *lacc = outputs[0]; + stream_sample_t *racc = outputs[1]; + int v; + + /* clear out the accumulator */ + memset(lacc, 0, samples * sizeof(lacc[0])); + memset(racc, 0, samples * sizeof(racc[0])); + + /* loop over voices */ + for (v = 0; v < 8; v++) + { + struct YMZ280BVoice *voice = &m_voice[v]; + INT16 prev = voice->last_sample; + INT16 curr = voice->curr_sample; + INT16 *curr_data = m_scratch; + INT32 *ldest = lacc; + INT32 *rdest = racc; + UINT32 new_samples, samples_left; + UINT32 final_pos; + int remaining = samples; + int lvol = voice->output_left; + int rvol = voice->output_right; + + /* quick out if we're not playing and we're at 0 */ + if (!voice->playing && curr == 0 && prev == 0) + { + /* make sure next sound plays immediately */ + voice->output_pos = FRAC_ONE; + + continue; + } + + /* finish off the current sample */ + /* interpolate */ + while (remaining > 0 && voice->output_pos < FRAC_ONE) + { + int interp_sample = (((INT32)prev * (FRAC_ONE - voice->output_pos)) + ((INT32)curr * voice->output_pos)) >> FRAC_BITS; + *ldest++ += interp_sample * lvol; + *rdest++ += interp_sample * rvol; + voice->output_pos += voice->output_step; + remaining--; + } + + /* if we're over, continue; otherwise, we're done */ + if (voice->output_pos >= FRAC_ONE) + voice->output_pos -= FRAC_ONE; + else + continue; + + /* compute how many new samples we need */ + final_pos = voice->output_pos + remaining * voice->output_step; + new_samples = (final_pos + FRAC_ONE) >> FRAC_BITS; + if (new_samples > MAX_SAMPLE_CHUNK) + new_samples = MAX_SAMPLE_CHUNK; + samples_left = new_samples; + + /* generate them into our buffer */ + switch (voice->playing << 7 | voice->mode) + { + case 0x81: samples_left = generate_adpcm(voice, m_scratch, new_samples); break; + case 0x82: samples_left = generate_pcm8(voice, m_scratch, new_samples); break; + case 0x83: samples_left = generate_pcm16(voice, m_scratch, new_samples); break; + default: samples_left = 0; memset(m_scratch, 0, new_samples * sizeof(m_scratch[0])); break; + } + + if (samples_left || voice->ended) + { + voice->ended = false; + + /* if there are leftovers, ramp back to 0 */ + int base = new_samples - samples_left; + int i, t = (base == 0) ? curr : m_scratch[base - 1]; + for (i = 0; i < samples_left; i++) + { + if (t < 0) t = -((-t * 15) >> 4); + else if (t > 0) t = (t * 15) >> 4; + m_scratch[base + i] = t; + } + + /* if we hit the end and IRQs are enabled, signal it */ + if (base != 0) + { + voice->playing = 0; + + /* set update_irq_state_timer. IRQ is signaled on next CPU execution. */ + voice->timer->adjust(attotime::zero); + voice->irq_schedule = 1; + } + } + + /* advance forward one sample */ + prev = curr; + curr = *curr_data++; + + /* then sample-rate convert with linear interpolation */ + while (remaining > 0) + { + /* interpolate */ + while (remaining > 0 && voice->output_pos < FRAC_ONE) + { + int interp_sample = (((INT32)prev * (FRAC_ONE - voice->output_pos)) + ((INT32)curr * voice->output_pos)) >> FRAC_BITS; + *ldest++ += interp_sample * lvol; + *rdest++ += interp_sample * rvol; + voice->output_pos += voice->output_step; + remaining--; + } + + /* if we're over, grab the next samples */ + if (voice->output_pos >= FRAC_ONE) + { + voice->output_pos -= FRAC_ONE; + prev = curr; + curr = *curr_data++; + } + } + + /* remember the last samples */ + voice->last_sample = prev; + voice->curr_sample = curr; + } + + for (v = 0; v < samples; v++) + { + outputs[0][v] /= 256; + outputs[1][v] /= 256; + } +} + + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void ymz280b_device::device_start() +{ + m_ext_read_handler.resolve(); + m_ext_write_handler.resolve(); + + /* compute ADPCM tables */ + compute_tables(); + + /* initialize the rest of the structure */ + m_master_clock = (double)clock() / 384.0; + m_mem_base = region()->base(); + m_mem_size = region()->bytes(); + m_irq_handler.resolve(); + + for (int i = 0; i < 8; i++) + { + m_voice[i].timer = timer_alloc(i); + } + + /* create the stream */ + m_stream = machine().sound().stream_alloc(*this, 0, 2, INTERNAL_SAMPLE_RATE); + + /* allocate memory */ + assert(MAX_SAMPLE_CHUNK < 0x10000); + m_scratch = auto_alloc_array(machine(), INT16, MAX_SAMPLE_CHUNK); + + /* state save */ + save_item(NAME(m_current_register)); + save_item(NAME(m_status_register)); + save_item(NAME(m_irq_state)); + save_item(NAME(m_irq_mask)); + save_item(NAME(m_irq_enable)); + save_item(NAME(m_keyon_enable)); + save_item(NAME(m_ext_mem_enable)); + save_item(NAME(m_ext_mem_address)); + save_item(NAME(m_ext_readlatch)); + save_item(NAME(m_ext_mem_address_hi)); + save_item(NAME(m_ext_mem_address_mid)); + for (int j = 0; j < 8; j++) + { + save_item(NAME(m_voice[j].playing), j); + save_item(NAME(m_voice[j].ended), j); + save_item(NAME(m_voice[j].keyon), j); + save_item(NAME(m_voice[j].looping), j); + save_item(NAME(m_voice[j].mode), j); + save_item(NAME(m_voice[j].fnum), j); + save_item(NAME(m_voice[j].level), j); + save_item(NAME(m_voice[j].pan), j); + save_item(NAME(m_voice[j].start), j); + save_item(NAME(m_voice[j].stop), j); + save_item(NAME(m_voice[j].loop_start), j); + save_item(NAME(m_voice[j].loop_end), j); + save_item(NAME(m_voice[j].position), j); + save_item(NAME(m_voice[j].signal), j); + save_item(NAME(m_voice[j].step), j); + save_item(NAME(m_voice[j].loop_signal), j); + save_item(NAME(m_voice[j].loop_step), j); + save_item(NAME(m_voice[j].loop_count), j); + save_item(NAME(m_voice[j].output_left), j); + save_item(NAME(m_voice[j].output_right), j); + save_item(NAME(m_voice[j].output_pos), j); + save_item(NAME(m_voice[j].last_sample), j); + save_item(NAME(m_voice[j].curr_sample), j); + save_item(NAME(m_voice[j].irq_schedule), j); + } + +#if MAKE_WAVS + m_wavresample = wav_open("resamp.wav", INTERNAL_SAMPLE_RATE, 2); +#endif +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void ymz280b_device::device_reset() +{ + /* initial clear registers */ + for (int i = 0xff; i >= 0; i--) + { + m_current_register = i; + write_to_register(0); + } + + m_current_register = 0; + m_status_register = 0; + m_ext_mem_address = 0; + + /* clear other voice parameters */ + for (int i = 0; i < 8; i++) + { + struct YMZ280BVoice *voice = &m_voice[i]; + + voice->curr_sample = 0; + voice->last_sample = 0; + voice->output_pos = FRAC_ONE; + voice->playing = 0; + } +} + + +void ymz280b_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + if (id < 8) + update_irq_state_timer_common( id ); + else + assert_always(FALSE, "Unknown id in ymz280b_device::device_timer"); +} + + +/********************************************************************************************** + + write_to_register -- handle a write to the current register + +***********************************************************************************************/ + +void ymz280b_device::write_to_register(int data) +{ + struct YMZ280BVoice *voice; + int i; + + /* lower registers follow a pattern */ + if (m_current_register < 0x80) + { + voice = &m_voice[(m_current_register >> 2) & 7]; + + switch (m_current_register & 0xe3) + { + case 0x00: /* pitch low 8 bits */ + voice->fnum = (voice->fnum & 0x100) | (data & 0xff); + update_step(voice); + break; + + case 0x01: /* pitch upper 1 bit, loop, key on, mode */ + voice->fnum = (voice->fnum & 0xff) | ((data & 0x01) << 8); + voice->looping = (data & 0x10) >> 4; + if ((data & 0x60) == 0) data &= 0x7f; /* ignore mode setting and set to same state as KON=0 */ + else voice->mode = (data & 0x60) >> 5; + if (!voice->keyon && (data & 0x80) && m_keyon_enable) + { + voice->playing = 1; + voice->position = voice->start; + voice->signal = voice->loop_signal = 0; + voice->step = voice->loop_step = 0x7f; + voice->loop_count = 0; + + /* if update_irq_state_timer is set, cancel it. */ + voice->irq_schedule = 0; + } + else if (voice->keyon && !(data & 0x80)) + { + voice->playing = 0; + + /* if update_irq_state_timer is set, cancel it. */ + voice->irq_schedule = 0; + } + voice->keyon = (data & 0x80) >> 7; + update_step(voice); + break; + + case 0x02: /* total level */ + voice->level = data; + update_volumes(voice); + break; + + case 0x03: /* pan */ + voice->pan = data & 0x0f; + update_volumes(voice); + break; + + case 0x20: /* start address high */ + voice->start = (voice->start & (0x00ffff << 1)) | (data << 17); + break; + + case 0x21: /* loop start address high */ + voice->loop_start = (voice->loop_start & (0x00ffff << 1)) | (data << 17); + break; + + case 0x22: /* loop end address high */ + voice->loop_end = (voice->loop_end & (0x00ffff << 1)) | (data << 17); + break; + + case 0x23: /* stop address high */ + voice->stop = (voice->stop & (0x00ffff << 1)) | (data << 17); + break; + + case 0x40: /* start address middle */ + voice->start = (voice->start & (0xff00ff << 1)) | (data << 9); + break; + + case 0x41: /* loop start address middle */ + voice->loop_start = (voice->loop_start & (0xff00ff << 1)) | (data << 9); + break; + + case 0x42: /* loop end address middle */ + voice->loop_end = (voice->loop_end & (0xff00ff << 1)) | (data << 9); + break; + + case 0x43: /* stop address middle */ + voice->stop = (voice->stop & (0xff00ff << 1)) | (data << 9); + break; + + case 0x60: /* start address low */ + voice->start = (voice->start & (0xffff00 << 1)) | (data << 1); + break; + + case 0x61: /* loop start address low */ + voice->loop_start = (voice->loop_start & (0xffff00 << 1)) | (data << 1); + break; + + case 0x62: /* loop end address low */ + voice->loop_end = (voice->loop_end & (0xffff00 << 1)) | (data << 1); + break; + + case 0x63: /* stop address low */ + voice->stop = (voice->stop & (0xffff00 << 1)) | (data << 1); + break; + + default: + logerror("YMZ280B: unknown register write %02X = %02X\n", m_current_register, data); + break; + } + } + + /* upper registers are special */ + else + { + switch (m_current_register) + { + /* DSP related (not implemented yet) */ + case 0x80: // d0-2: DSP Rch, d3: enable Rch (0: yes, 1: no), d4-6: DSP Lch, d7: enable Lch (0: yes, 1: no) + case 0x81: // d0: enable control of $82 (0: yes, 1: no) + case 0x82: // DSP data + logerror("YMZ280B: DSP register write %02X = %02X\n", m_current_register, data); + break; + + case 0x84: /* ROM readback / RAM write (high) */ + m_ext_mem_address_hi = data << 16; + break; + + case 0x85: /* ROM readback / RAM write (middle) */ + m_ext_mem_address_mid = data << 8; + break; + + case 0x86: /* ROM readback / RAM write (low) -> update latch */ + m_ext_mem_address = m_ext_mem_address_hi | m_ext_mem_address_mid | data; + if (m_ext_mem_enable) + m_ext_readlatch = ymz280b_read_memory(m_ext_mem_address); + break; + + case 0x87: /* RAM write */ + if (m_ext_mem_enable) + { + if (!m_ext_write_handler.isnull()) + m_ext_write_handler(m_ext_mem_address, data); + else + logerror("YMZ280B attempted RAM write to %X\n", m_ext_mem_address); + m_ext_mem_address = (m_ext_mem_address + 1) & 0xffffff; + } + break; + + case 0xfe: /* IRQ mask */ + m_irq_mask = data; + update_irq_state(); + break; + + case 0xff: /* IRQ enable, test, etc */ + m_ext_mem_enable = (data & 0x40) >> 6; + m_irq_enable = (data & 0x10) >> 4; + update_irq_state(); + + if (m_keyon_enable && !(data & 0x80)) + { + for (i = 0; i < 8; i++) + { + m_voice[i].playing = 0; + + /* if update_irq_state_timer is set, cancel it. */ + m_voice[i].irq_schedule = 0; + } + } + else if (!m_keyon_enable && (data & 0x80)) + { + for (i = 0; i < 8; i++) + { + if (m_voice[i].keyon && m_voice[i].looping) + m_voice[i].playing = 1; + } + } + m_keyon_enable = (data & 0x80) >> 7; + break; + + default: + logerror("YMZ280B: unknown register write %02X = %02X\n", m_current_register, data); + break; + } + } +} + + + +/********************************************************************************************** + + compute_status -- determine the status bits + +***********************************************************************************************/ + +int ymz280b_device::compute_status() +{ + UINT8 result; + + /* force an update */ + m_stream->update(); + + result = m_status_register; + + /* clear the IRQ state */ + m_status_register = 0; + update_irq_state(); + + return result; +} + + + +/********************************************************************************************** + + ymz280b_r/ymz280b_w -- handle external accesses + +***********************************************************************************************/ + +READ8_MEMBER( ymz280b_device::read ) +{ + if ((offset & 1) == 0) + { + if (!m_ext_mem_enable) + return 0xff; + + /* read from external memory */ + UINT8 ret = m_ext_readlatch; + m_ext_readlatch = ymz280b_read_memory(m_ext_mem_address); + m_ext_mem_address = (m_ext_mem_address + 1) & 0xffffff; + return ret; + } + else + return compute_status(); +} + + +WRITE8_MEMBER( ymz280b_device::write ) +{ + if ((offset & 1) == 0) + m_current_register = data; + else + { + /* force an update */ + m_stream->update(); + + write_to_register(data); + } +} + + +const device_type YMZ280B = &device_creator; + +ymz280b_device::ymz280b_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, YMZ280B, "YMZ280B", tag, owner, clock, "ymz280b", __FILE__), + device_sound_interface(mconfig, *this), + m_current_register(0), + m_status_register(0), + m_irq_state(0), + m_irq_mask(0), + m_irq_enable(0), + m_keyon_enable(0), + m_ext_mem_enable(0), + m_ext_readlatch(0), + m_ext_mem_address_hi(0), + m_ext_mem_address_mid(0), + m_ext_mem_address(0), + m_irq_handler(*this), + m_ext_read_handler(*this), + m_ext_write_handler(*this) +{ + memset(m_voice, 0, sizeof(m_voice)); +} + +//------------------------------------------------- +// device_config_complete - perform any +// operations now that the configuration is +// complete +//------------------------------------------------- + +void ymz280b_device::device_config_complete() +{ +} diff --git a/src/devices/sound/ymz280b.h b/src/devices/sound/ymz280b.h new file mode 100644 index 00000000000..a67c0d8567b --- /dev/null +++ b/src/devices/sound/ymz280b.h @@ -0,0 +1,133 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/********************************************************************************************** + * + * Yamaha YMZ280B driver + * by Aaron Giles + * + **********************************************************************************************/ + +#pragma once + +#ifndef __YMZ280B_H__ +#define __YMZ280B_H__ + +#include "emu.h" + +#define MAKE_WAVS 0 + +#define MCFG_YMZ280B_IRQ_HANDLER(_devcb) \ + devcb = &ymz280b_device::set_irq_handler(*device, DEVCB_##_devcb); + +#define MCFG_YMZ280B_EXT_READ_HANDLER(_devcb) \ + devcb = &ymz280b_device::set_ext_read_handler(*device, DEVCB_##_devcb); + +#define MCFG_YMZ280B_EXT_WRITE_HANDLER(_devcb) \ + devcb = &ymz280b_device::set_ext_write_handler(*device, DEVCB_##_devcb); + +class ymz280b_device : public device_t, + public device_sound_interface +{ +public: + ymz280b_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // static configuration helpers + template static devcb_base &set_irq_handler(device_t &device, _Object object) { return downcast(device).m_irq_handler.set_callback(object); } + template static devcb_base &set_ext_read_handler(device_t &device, _Object object) { return downcast(device).m_ext_read_handler.set_callback(object); } + template static devcb_base &set_ext_write_handler(device_t &device, _Object object) { return downcast(device).m_ext_write_handler.set_callback(object); } + + DECLARE_READ8_MEMBER( read ); + DECLARE_WRITE8_MEMBER( write ); + +protected: + // device-level overrides + virtual void device_config_complete(); + virtual void device_start(); + virtual void device_post_load(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + // sound stream update overrides + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); +private: + + /* struct describing a single playing ADPCM voice */ + struct YMZ280BVoice + { + UINT8 playing; /* 1 if we are actively playing */ + bool ended; /* indicate voice has ended in case samples_left is 0 */ + + UINT8 keyon; /* 1 if the key is on */ + UINT8 looping; /* 1 if looping is enabled */ + UINT8 mode; /* current playback mode */ + UINT16 fnum; /* frequency */ + UINT8 level; /* output level */ + UINT8 pan; /* panning */ + + UINT32 start; /* start address, in nibbles */ + UINT32 stop; /* stop address, in nibbles */ + UINT32 loop_start; /* loop start address, in nibbles */ + UINT32 loop_end; /* loop end address, in nibbles */ + UINT32 position; /* current position, in nibbles */ + + INT32 signal; /* current ADPCM signal */ + INT32 step; /* current ADPCM step */ + + INT32 loop_signal; /* signal at loop start */ + INT32 loop_step; /* step at loop start */ + UINT32 loop_count; /* number of loops so far */ + + INT32 output_left; /* output volume (left) */ + INT32 output_right; /* output volume (right) */ + INT32 output_step; /* step value for frequency conversion */ + INT32 output_pos; /* current fractional position */ + INT16 last_sample; /* last sample output */ + INT16 curr_sample; /* current sample target */ + UINT8 irq_schedule; /* 1 if the IRQ state is updated by timer */ + + emu_timer *timer; + }; + + UINT8 ymz280b_read_memory(UINT32 offset); + void update_irq_state(); + void update_step(struct YMZ280BVoice *voice); + void update_volumes(struct YMZ280BVoice *voice); + void update_irq_state_timer_common(int voicenum); + int generate_adpcm(struct YMZ280BVoice *voice, INT16 *buffer, int samples); + int generate_pcm8(struct YMZ280BVoice *voice, INT16 *buffer, int samples); + int generate_pcm16(struct YMZ280BVoice *voice, INT16 *buffer, int samples); + void write_to_register(int data); + int compute_status(); + + // internal state + struct YMZ280BVoice m_voice[8]; /* the 8 voices */ + UINT8 m_current_register; /* currently accessible register */ + UINT8 m_status_register; /* current status register */ + UINT8 m_irq_state; /* current IRQ state */ + UINT8 m_irq_mask; /* current IRQ mask */ + UINT8 m_irq_enable; /* current IRQ enable */ + UINT8 m_keyon_enable; /* key on enable */ + UINT8 m_ext_mem_enable; /* external memory enable */ + UINT8 m_ext_readlatch; /* external memory prefetched data */ + UINT32 m_ext_mem_address_hi; + UINT32 m_ext_mem_address_mid; + UINT32 m_ext_mem_address; /* where the CPU can read the ROM */ + + devcb_write_line m_irq_handler; /* IRQ callback */ + devcb_read8 m_ext_read_handler; /* external RAM read handler */ + devcb_write8 m_ext_write_handler;/* external RAM write handler */ + + double m_master_clock; /* master clock frequency */ + UINT8 *m_mem_base; /* pointer to the base of external memory */ + UINT32 m_mem_size; + sound_stream *m_stream; /* which stream are we using */ + INT16 *m_scratch; +#if MAKE_WAVS + void *m_wavresample; /* resampled waveform */ +#endif +}; + +extern const device_type YMZ280B; + + +#endif /* __YMZ280B_H__ */ diff --git a/src/devices/sound/ymz770.c b/src/devices/sound/ymz770.c new file mode 100644 index 00000000000..f367f4d10eb --- /dev/null +++ b/src/devices/sound/ymz770.c @@ -0,0 +1,345 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert, R. Belmont +/*************************************************************************** + + ymz770.c + + Emulation by R. Belmont + AMM decode by Olivier Galibert + +----- +TODO: +- A lot of unimplemented features, even simple ones like panning, + these should be added once we find out any software that uses it. +- Is channel volume linear(current implementation) or logarithmic? +- Sequencer is very preliminary +- What does channel ATBL mean? +- Is YMZ774(and other variants) the same family as this chip? + What are the differences? + +***************************************************************************/ + +#include "emu.h" +#include "ymz770.h" +#include "mpeg_audio.h" + +// device type definition +const device_type YMZ770 = &device_creator; + +//------------------------------------------------- +// ymz770_device - constructor +//------------------------------------------------- + +ymz770_device::ymz770_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, YMZ770, "Yamaha YMZ770", tag, owner, clock, "ymz770", __FILE__), + device_sound_interface(mconfig, *this), + m_cur_reg(0), + m_mute(0), + m_doen(0), + m_vlma(0), + m_bsl(0), + m_cpl(0) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void ymz770_device::device_start() +{ + // create the stream + m_stream = machine().sound().stream_alloc(*this, 0, 2, 16000); + m_rom_base = region()->base(); + m_rom_limit = region()->bytes() * 8; + + for (int i = 0; i < 8; i++) + { + m_channels[i].is_playing = false; + m_channels[i].is_seq_playing = false; + m_channels[i].decoder = new mpeg_audio(m_rom_base, mpeg_audio::AMM, false, 0); + } + + // register for save states + save_item(NAME(m_cur_reg)); + save_item(NAME(m_mute)); + save_item(NAME(m_doen)); + save_item(NAME(m_vlma)); + save_item(NAME(m_bsl)); + save_item(NAME(m_cpl)); + + for (int ch = 0; ch < 8; ch++) + { + save_item(NAME(m_channels[ch].phrase), ch); + save_item(NAME(m_channels[ch].pan), ch); + save_item(NAME(m_channels[ch].volume), ch); + save_item(NAME(m_channels[ch].control), ch); + save_item(NAME(m_channels[ch].is_playing), ch); + save_item(NAME(m_channels[ch].last_block), ch); + save_item(NAME(m_channels[ch].output_remaining), ch); + save_item(NAME(m_channels[ch].output_ptr), ch); + save_item(NAME(m_channels[ch].atbl), ch); + save_item(NAME(m_channels[ch].pptr), ch); + save_item(NAME(m_channels[ch].sequence), ch); + save_item(NAME(m_channels[ch].seqcontrol), ch); + save_item(NAME(m_channels[ch].seqdelay), ch); + save_item(NAME(m_channels[ch].is_seq_playing), ch); + save_item(NAME(m_channels[ch].output_data), ch); + } +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void ymz770_device::device_reset() +{ + for (int ch = 0; ch < 8; ch++) + { + m_channels[ch].phrase = 0; + m_channels[ch].pan = 8; + m_channels[ch].volume = 0; + m_channels[ch].control = 0; + m_channels[ch].sequence = 0; + m_channels[ch].seqcontrol = 0; + m_channels[ch].seqdelay = 0; + m_channels[ch].is_playing = false; + m_channels[ch].is_seq_playing = false; + m_channels[ch].output_remaining = 0; + m_channels[ch].decoder->clear(); + } +} + + +//------------------------------------------------- +// sound_stream_update - handle update requests for +// our sound stream +//------------------------------------------------- + +void ymz770_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + stream_sample_t *outL, *outR; + + outL = outputs[0]; + outR = outputs[1]; + + for (int i = 0; i < samples; i++) + { + // run sequencers (should probably be in separate timer callbacks) + for (int ch = 0; ch < 8; ch++) + { + if (m_channels[ch].is_seq_playing) + { + if (m_channels[ch].seqdelay > 0) + { + m_channels[ch].seqdelay--; + } + else + { + int reg = *m_channels[ch].seqdata++; + UINT8 data = *m_channels[ch].seqdata++; + switch (reg) + { + case 0x0f: + if (m_channels[ch].seqcontrol & 1) + { + // loop sequence + UINT8 sqn = m_channels[ch].sequence; + UINT32 pptr = m_rom_base[(4*sqn)+1+0x400]<<16 | m_rom_base[(4*sqn)+2+0x400]<<8 | m_rom_base[(4*sqn)+3+0x400]; + m_channels[ch].seqdata = &m_rom_base[pptr]; + } + else + { + m_channels[ch].is_seq_playing = false; + } + break; + case 0x0e: + m_channels[ch].seqdelay = 32 - 1; + break; + default: + internal_reg_write(reg, data); + break; + } + } + } + } + + // process channels + INT32 mix = 0; + + for (int ch = 0; ch < 8; ch++) + { + if (m_channels[ch].output_remaining > 0) + { + // force finish current block + mix += (m_channels[ch].output_data[m_channels[ch].output_ptr++]*m_channels[ch].volume); + m_channels[ch].output_remaining--; + + if (m_channels[ch].output_remaining == 0 && !m_channels[ch].is_playing) + m_channels[ch].decoder->clear(); + } + + else if (m_channels[ch].is_playing) + { +retry: + if (m_channels[ch].last_block) + { + if (m_channels[ch].control & 1) + { + // loop sample + UINT8 phrase = m_channels[ch].phrase; + m_channels[ch].atbl = m_rom_base[(4*phrase)+0] >> 4 & 7; + m_channels[ch].pptr = 8*(m_rom_base[(4*phrase)+1]<<16 | m_rom_base[(4*phrase)+2]<<8 | m_rom_base[(4*phrase)+3]); + } + else + { + m_channels[ch].is_playing = false; + m_channels[ch].output_remaining = 0; + m_channels[ch].decoder->clear(); + } + } + + if (m_channels[ch].is_playing) + { + // next block + int sample_rate, channel_count; + if (!m_channels[ch].decoder->decode_buffer(m_channels[ch].pptr, m_rom_limit, m_channels[ch].output_data, m_channels[ch].output_remaining, sample_rate, channel_count) || m_channels[ch].output_remaining == 0) + { + m_channels[ch].is_playing = !m_channels[ch].last_block; // detect infinite retry loop + m_channels[ch].last_block = true; + m_channels[ch].output_remaining = 0; + goto retry; + } + + m_channels[ch].last_block = m_channels[ch].output_remaining < 1152; + m_channels[ch].output_remaining--; + m_channels[ch].output_ptr = 1; + + mix += (m_channels[ch].output_data[0]*m_channels[ch].volume); + } + } + } + + outL[i] = outR[i] = mix>>8; + } +} + + +//------------------------------------------------- +// write - write to the chip's registers +//------------------------------------------------- + +WRITE8_MEMBER( ymz770_device::write ) +{ + if (offset & 1) + { + m_stream->update(); + internal_reg_write(m_cur_reg, data); + } + else + { + m_cur_reg = data; + } +} + + +void ymz770_device::internal_reg_write(UINT8 reg, UINT8 data) +{ + // global registers + if (reg < 0x40) + { + switch (reg) + { + case 0x00: + m_mute = data & 1; + m_doen = data >> 1 & 1; + break; + + case 0x01: + m_vlma = data; + break; + + case 0x02: + m_bsl = data & 7; + m_cpl = data >> 4 & 7; + break; + + // unused + default: + break; + } + } + + // playback registers + else if (reg < 0x60) + { + int ch = reg >> 2 & 0x07; + + switch (reg & 0x03) + { + case 0: + m_channels[ch].phrase = data; + break; + + case 1: + m_channels[ch].volume = data; + break; + + case 2: + m_channels[ch].pan = data; + break; + + case 3: + if (data & 6) + { + UINT8 phrase = m_channels[ch].phrase; + m_channels[ch].atbl = m_rom_base[(4*phrase)+0] >> 4 & 7; + m_channels[ch].pptr = 8*(m_rom_base[(4*phrase)+1]<<16 | m_rom_base[(4*phrase)+2]<<8 | m_rom_base[(4*phrase)+3]); + m_channels[ch].last_block = false; + + m_channels[ch].is_playing = true; + } + else + { + m_channels[ch].is_playing = false; + } + + m_channels[ch].control = data; + break; + } + } + + // sequencer registers + else + { + int ch = reg >> 4 & 0x07; + + switch (reg & 0x0f) + { + case 0: + m_channels[ch].sequence = data; + break; + case 1: + if (data & 6) + { + UINT8 sqn = m_channels[ch].sequence; + UINT32 pptr = m_rom_base[(4*sqn)+1+0x400]<<16 | m_rom_base[(4*sqn)+2+0x400]<<8 | m_rom_base[(4*sqn)+3+0x400]; + m_channels[ch].seqdata = &m_rom_base[pptr]; + m_channels[ch].seqdelay = 0; + m_channels[ch].is_seq_playing = true; + } + else + { + m_channels[ch].is_seq_playing = false; + } + + m_channels[ch].seqcontrol = data; + break; + + default: + break; + } + } +} diff --git a/src/devices/sound/ymz770.h b/src/devices/sound/ymz770.h new file mode 100644 index 00000000000..d98d40308ca --- /dev/null +++ b/src/devices/sound/ymz770.h @@ -0,0 +1,99 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert, R. Belmont +/*************************************************************************** + + ymz770.h + +***************************************************************************/ + +#pragma once + +#ifndef __YMZ770_H__ +#define __YMZ770_H__ + +//************************************************************************** +// CONSTANTS +//************************************************************************** + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_YMZ770_ADD(_tag, _clock) \ + MCFG_DEVICE_ADD(_tag, YMZ770, _clock) + +#define MCFG_YMZ770_REPLACE(_tag, _clock) \ + MCFG_DEVICE_REPLACE(_tag, YMZ770, _clock) + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// forward definition +class mpeg_audio; + +// ======================> ymz770_device + +class ymz770_device : public device_t, public device_sound_interface +{ + struct ymz_channel + { + UINT8 phrase; + UINT8 pan; + UINT8 volume; + UINT8 control; + + bool is_playing, last_block; + + mpeg_audio *decoder; + + INT16 output_data[0x1000]; + int output_remaining; + int output_ptr; + int atbl; + int pptr; + + UINT8 sequence; + UINT8 seqcontrol; + UINT8 seqdelay; + UINT8 *seqdata; + bool is_seq_playing; + }; + + +public: + // construction/destruction + ymz770_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + DECLARE_WRITE8_MEMBER(write); + + sound_stream *m_stream; + +protected: + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + + void internal_reg_write(UINT8 reg, UINT8 data); + + // data + UINT8 m_cur_reg; + UINT8 m_mute; // mute chip + UINT8 m_doen; // digital output enable + UINT8 m_vlma; // overall AAM volume + UINT8 m_bsl; // boost level + UINT8 m_cpl; // clip limiter + UINT8 *m_rom_base; + int m_rom_limit; + + ymz_channel m_channels[8]; +}; + + +// device type definition +extern const device_type YMZ770; + +#endif /* __ymz770_H__ */ diff --git a/src/devices/sound/zsg2.c b/src/devices/sound/zsg2.c new file mode 100644 index 00000000000..4f3f1a42ca9 --- /dev/null +++ b/src/devices/sound/zsg2.c @@ -0,0 +1,464 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert, R. Belmont, hap +/* + ZOOM ZSG-2 custom wavetable synthesizer + + Written by Olivier Galibert + MAME conversion by R. Belmont + Working emulation by The Talentuous Hands Of The Popularious hap + --------------------------------------------------------- + + Additional notes on the sample format, reverse-engineered + by Olivier Galibert and David Haywood: + + The zoom sample rom is decomposed in 0x40000 bytes pages. Each page + starts by a header and is followed by compressed samples. + + The header is a vector of 16 bytes structures composed of 4 32bits + little-endian values representing: + - sample start position in bytes, always a multiple of 4 + - sample end position in bytes, minus 4, always... + - loop position in bytes, always.... + - flags, probably + + It is interesting to note that this header is *not* parsed by the + ZSG. The main program reads the rom through appropriate ZSG + commands, and use the results in subsequent register setups. It's + not even obvious that the ZSG cares about the pages, it may just + see the address space as linear. In the same line, the + interpretation of the flags is obviously dependent on the main + program, not the ZSG, but some of the bits are directly copied to + some of the registers. + + The samples are compressed with a 2:1 ratio. Each block of 4-bytes + becomes 4 16-bits samples. Reading the 4 bytes as a *little-endian* + 32bits values, the structure is: + + 42222222 51111111 60000000 ssss3333 + + 's' is a 4-bit scale value. '0000000', '1111111', '2222222' and + '6543333' are signed 7-bits values corresponding to the 4 samples. + To compute the final 16bits value, left-align and shift right by s. + Yes, that simple. + + --------------------------------------------------------- + +TODO: +- volume/panning is linear? volume slides are too steep +- most music sounds tinny, probably due to missing DSP? +- what is reg 0xa/0xc? seems related to volume +- identify sample flags + * bassdrum in shikigam level 1 music is a good hint: it should be one octave + lower, indicating possible stereo sample, or base octave(like in ymf278) +- memory reads out of range sometimes + +*/ + +#include "emu.h" +#include "zsg2.h" + + +// device type definition +const device_type ZSG2 = &device_creator; + +//------------------------------------------------- +// zsg2_device - constructor +//------------------------------------------------- + +zsg2_device::zsg2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, ZSG2, "ZSG-2", tag, owner, clock, "zsg2", __FILE__), + device_sound_interface(mconfig, *this), + m_mem_base(*this, DEVICE_SELF), + m_read_address(0), + m_ext_read_handler(*this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void zsg2_device::device_start() +{ + m_ext_read_handler.resolve(); + + memset(&m_chan, 0, sizeof(m_chan)); + + m_stream = stream_alloc(0, 2, clock() / 768); + + m_mem_blocks = m_mem_base.length(); + m_mem_copy = auto_alloc_array_clear(machine(), UINT32, m_mem_blocks); + m_full_samples = auto_alloc_array_clear(machine(), INT16, m_mem_blocks * 4 + 4); // +4 is for empty block + + // register for savestates + save_pointer(NAME(m_mem_copy), m_mem_blocks / sizeof(UINT32)); + save_pointer(NAME(m_full_samples), (m_mem_blocks * 4 + 4) / sizeof(INT16)); + save_item(NAME(m_read_address)); + + for (int ch = 0; ch < 48; ch++) + { + save_item(NAME(m_chan[ch].v), ch); + save_item(NAME(m_chan[ch].is_playing), ch); + save_item(NAME(m_chan[ch].cur_pos), ch); + save_item(NAME(m_chan[ch].step_ptr), ch); + save_item(NAME(m_chan[ch].step), ch); + save_item(NAME(m_chan[ch].start_pos), ch); + save_item(NAME(m_chan[ch].end_pos), ch); + save_item(NAME(m_chan[ch].loop_pos), ch); + save_item(NAME(m_chan[ch].page), ch); + save_item(NAME(m_chan[ch].vol), ch); + save_item(NAME(m_chan[ch].flags), ch); + save_item(NAME(m_chan[ch].panl), ch); + save_item(NAME(m_chan[ch].panr), ch); + } +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void zsg2_device::device_reset() +{ + m_read_address = 0; + + // stop playing and clear all channels + control_w(4, 0xffff); + control_w(5, 0xffff); + control_w(6, 0xffff); + + for (int ch = 0; ch < 48; ch++) + for (int reg = 0; reg < 0x10; reg++) + chan_w(ch, reg, 0); + +#if 0 + for (int i = 0; i < m_mem_blocks; i++) + prepare_samples(i); + + FILE* f; + + f = fopen("zoom_samples.bin","wb"); + fwrite(m_mem_copy,1,m_mem_blocks*4,f); + fclose(f); + + f = fopen("zoom_samples.raw","wb"); + fwrite(m_full_samples,2,m_mem_blocks*4,f); + fclose(f); +#endif +} + + +/******************************************************************************/ + +UINT32 zsg2_device::read_memory(UINT32 offset) +{ + if (offset >= m_mem_blocks) + return 0; + + if (m_ext_read_handler.isnull()) + return m_mem_base[offset]; + + return m_ext_read_handler(offset); +} + +INT16 *zsg2_device::prepare_samples(UINT32 offset) +{ + UINT32 block = read_memory(offset); + + if (block == 0) + return &m_full_samples[m_mem_blocks]; // overflow or 0 + + if (block == m_mem_copy[offset]) + return &m_full_samples[offset * 4]; // cached + + m_mem_copy[offset] = block; + offset *= 4; + + // decompress 32 byte block to 4 16-bit samples + // 42222222 51111111 60000000 ssss3333 + m_full_samples[offset|0] = block >> 8 & 0x7f; + m_full_samples[offset|1] = block >> 16 & 0x7f; + m_full_samples[offset|2] = block >> 24 & 0x7f; + m_full_samples[offset|3] = (block >> (8+1) & 0x40) | (block >> (16+2) & 0x20) | (block >> (24+3) & 0x10) | (block & 0xf); + + // sign-extend and shift + UINT8 shift = block >> 4 & 0xf; + for (int i = offset; i < (offset + 4); i++) + { + m_full_samples[i] <<= 9; + m_full_samples[i] >>= shift; + } + + return &m_full_samples[offset]; +} + + +//------------------------------------------------- +// sound_stream_update - handle a stream update +//------------------------------------------------- + +void zsg2_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + for (int i = 0; i < samples; i++) + { + INT32 mix_l = 0; + INT32 mix_r = 0; + + // loop over all channels + for (int ch = 0; ch < 48; ch++) + { + if (!m_chan[ch].is_playing) + continue; + + m_chan[ch].step_ptr += m_chan[ch].step; + if (m_chan[ch].step_ptr & 0x10000) + { + m_chan[ch].step_ptr &= 0xffff; + if (++m_chan[ch].cur_pos >= m_chan[ch].end_pos) + { + // loop sample + m_chan[ch].cur_pos = m_chan[ch].loop_pos; + if ((m_chan[ch].cur_pos + 1) >= m_chan[ch].end_pos) + { + // end of sample + m_chan[ch].is_playing = false; + continue; + } + } + m_chan[ch].samples = prepare_samples(m_chan[ch].page | m_chan[ch].cur_pos); + } + + INT32 sample = (m_chan[ch].samples[m_chan[ch].step_ptr >> 14 & 3] * m_chan[ch].vol) >> 16; + + mix_l += (sample * m_chan[ch].panl + sample * (0x1f - m_chan[ch].panr)) >> 5; + mix_r += (sample * m_chan[ch].panr + sample * (0x1f - m_chan[ch].panl)) >> 5; + } + + outputs[0][i] = mix_l; + outputs[1][i] = mix_r; + } +} + + +/******************************************************************************/ + +void zsg2_device::chan_w(int ch, int reg, UINT16 data) +{ + switch (reg) + { + case 0x0: + // lo byte: unknown, 0 on most games + // hi byte: start address low + m_chan[ch].start_pos = (m_chan[ch].start_pos & 0xff00) | (data >> 8 & 0xff); + break; + + case 0x1: + // lo byte: start address high + // hi byte: address page + m_chan[ch].start_pos = (m_chan[ch].start_pos & 0x00ff) | (data << 8 & 0xff00); + m_chan[ch].page = data << 8 & 0xff0000; + break; + + case 0x2: + // no function? always 0 + break; + + case 0x3: + // unknown, always 0x0400 + break; + + case 0x4: + // frequency + m_chan[ch].step = data + 1; + break; + + case 0x5: + // lo byte: loop address low + // hi byte: right panning (high bits always 0) + m_chan[ch].loop_pos = (m_chan[ch].loop_pos & 0xff00) | (data & 0xff); + m_chan[ch].panr = data >> 8 & 0x1f; + break; + + case 0x6: + // end address + m_chan[ch].end_pos = data; + break; + + case 0x7: + // lo byte: loop address high + // hi byte: left panning (high bits always 0) + m_chan[ch].loop_pos = (m_chan[ch].loop_pos & 0x00ff) | (data << 8 & 0xff00); + m_chan[ch].panl = data >> 8 & 0x1f; + break; + + case 0x9: + // no function? always 0 + break; + + case 0xb: + // always writes 0 + // this register is read-only + break; + + case 0xe: + // volume + m_chan[ch].vol = data; + break; + + case 0xf: + // flags + m_chan[ch].flags = data; + break; + + default: + break; + } + + m_chan[ch].v[reg] = data; +} + +UINT16 zsg2_device::chan_r(int ch, int reg) +{ + switch (reg) + { + case 0xb: + // ? + return 0; + + default: + break; + } + + return m_chan[ch].v[reg]; +} + + +/******************************************************************************/ + +void zsg2_device::control_w(int reg, UINT16 data) +{ + switch (reg) + { + case 0x00: case 0x01: case 0x02: + { + // key on + int base = (reg & 3) << 4; + for (int i = 0; i < 16; i++) + { + if (data & (1 << i)) + { + int ch = base | i; + m_chan[ch].is_playing = true; + m_chan[ch].cur_pos = m_chan[ch].start_pos; + m_chan[ch].step_ptr = 0; + m_chan[ch].samples = prepare_samples(m_chan[ch].page | m_chan[ch].cur_pos); + } + } + break; + } + + case 0x04: case 0x05: case 0x06: + { + // key off + int base = (reg & 3) << 4; + for (int i = 0; i < 16; i++) + { + if (data & (1 << i)) + { + int ch = base | i; + m_chan[ch].is_playing = false; + } + } + break; + } + + case 0x18: + break; + + case 0x1c: + // rom readback address low (low 2 bits always 0) + if (data & 3) popmessage("ZSG2 address %04X, contact MAMEdev", data); + m_read_address = (m_read_address & 0x3fffc000) | (data >> 2 & 0x00003fff); + break; + case 0x1d: + // rom readback address high + m_read_address = (m_read_address & 0x00003fff) | (data << 14 & 0x3fffc000); + break; + + default: + break; + } +} + +UINT16 zsg2_device::control_r(int reg) +{ + switch (reg) + { + case 0x14: + // memory bus busy? + // right before reading memory, it polls until low 8 bits are 0 + return 0; + + case 0x1e: + // rom readback word low + return read_memory(m_read_address) & 0xffff; + case 0x1f: + // rom readback word high + return read_memory(m_read_address) >> 16; + + default: + break; + } + + return 0; +} + + +/******************************************************************************/ + +WRITE16_MEMBER(zsg2_device::write) +{ + // we only support full 16-bit accesses + if (mem_mask != 0xffff) + { + popmessage("ZSG2 write mask %04X, contact MAMEdev", mem_mask); + return; + } + + m_stream->update(); + + if (offset < 0x300) + { + int chan = offset >> 4; + int reg = offset & 0xf; + + chan_w(chan, reg, data); + } + else + { + control_w(offset - 0x300, data); + } +} + +READ16_MEMBER(zsg2_device::read) +{ + // we only support full 16-bit accesses + if (mem_mask != 0xffff) + { + popmessage("ZSG2 read mask %04X, contact MAMEdev", mem_mask); + return 0; + } + + if (offset < 0x300) + { + int chan = offset >> 4; + int reg = offset & 0xf; + + return chan_r(chan, reg); + } + else + { + return control_r(offset - 0x300); + } +} diff --git a/src/devices/sound/zsg2.h b/src/devices/sound/zsg2.h new file mode 100644 index 00000000000..e98e2c315ae --- /dev/null +++ b/src/devices/sound/zsg2.h @@ -0,0 +1,92 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert, R. Belmont, hap +/* + ZOOM ZSG-2 custom wavetable synthesizer +*/ + +#pragma once + +#ifndef __ZSG2_H__ +#define __ZSG2_H__ + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_ZSG2_ADD(_tag, _clock) \ + MCFG_DEVICE_ADD(_tag, ZSG2, _clock) +#define MCFG_ZSG2_REPLACE(_tag, _clock) \ + MCFG_DEVICE_REPLACE(_tag, ZSG2, _clock) + +#define MCFG_ZSG2_EXT_READ_HANDLER(_devcb) \ + devcb = &zsg2_device::set_ext_read_handler(*device, DEVCB_##_devcb); + + +// ======================> zsg2_device + +class zsg2_device : public device_t, + public device_sound_interface +{ +public: + zsg2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + ~zsg2_device() { } + + // static configuration helpers + template static devcb_base &set_ext_read_handler(device_t &device, _Object object) { return downcast(device).m_ext_read_handler.set_callback(object); } + + DECLARE_READ16_MEMBER(read); + DECLARE_WRITE16_MEMBER(write); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // sound stream update overrides + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + +private: + // 16 registers per channel, 48 channels + struct zchan + { + UINT16 v[16]; + bool is_playing; + INT16 *samples; + UINT32 cur_pos; + UINT32 step_ptr; + UINT32 step; + UINT32 start_pos; + UINT32 end_pos; + UINT32 loop_pos; + UINT32 page; + UINT16 vol; + UINT16 flags; + UINT8 panl; + UINT8 panr; + }; + + zchan m_chan[48]; + + required_region_ptr m_mem_base; + UINT32 m_read_address; + UINT32 *m_mem_copy; + UINT32 m_mem_blocks; + INT16 *m_full_samples; + + sound_stream *m_stream; + + devcb_read32 m_ext_read_handler; + + UINT32 read_memory(UINT32 offset); + void chan_w(int ch, int reg, UINT16 data); + UINT16 chan_r(int ch, int reg); + void control_w(int reg, UINT16 data); + UINT16 control_r(int reg); + INT16 *prepare_samples(UINT32 offset); +}; + +extern const device_type ZSG2; + + +#endif /* __ZSG2_H__ */ diff --git a/src/devices/video/315_5124.c b/src/devices/video/315_5124.c new file mode 100644 index 00000000000..dac2027d126 --- /dev/null +++ b/src/devices/video/315_5124.c @@ -0,0 +1,1709 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol, Enik Land +/********************************************************************* + + sega315_5124.c + + Implementation of video hardware chips used by Sega System E, + Master System, and Game Gear. + +**********************************************************************/ + +/* + +To do: + + - Display mode 1 (text) + - Display mode 3 (multicolor) + - Sprite doubling bug of the 315-5124 chip + - Verify timing on the Game Gear (315-5378 chip) + + +SMS Display Timing +------------------ + For more information, please see: + - http://cgfm2.emuviews.com/txt/msvdp.txt + - http://www.smspower.org/forums/viewtopic.php?p=44198 + +A scanline contains the following sections: + - horizontal sync 9 E9-ED => HSYNC high + - left blanking 2 ED-EE + - color burst 14 EE-F5 => increment line counter/generate interrupts/etc + - left blanking 8 F5-F9 + - left border 13 F9-FF + - active display 256 00-7F + - right border 15 80-87 + - right blanking 8 87-8B + - horizontal sync 17 8B-93 => HSYNC low + + +NTSC frame timing + 256x192 256x224 256x240 (doesn't work on real hardware) + - vertical blanking 3 D5-D7 3 E5-E7 3 ED-EF + - top blanking 13 D8-E4 13 E8-F4 13 F0-FC + - top border 27 E5-FF 11 F5-FF 3 FD-FF + - active display 192 00-BF 224 00-DF 240 00-EF + - bottom border 24 C0-D7 8 E0-E7 0 F0-F0 + - bottom blanking 3 D8-DA 3 E8-EA 3 F0-F2 + + +PAL frame timing + 256x192 256x224 256x240 + - vertical blanking 3 BA-BC 3 CA-CC 3 D2-D4 + - top blanking 13 BD-C9 13 CD-D9 13 D5-E1 + - top border 54 CA-FF 38 DA-FF 30 E2-FF + - active display 192 00-BF 224 00-DF 240 00-EF + - bottom border 48 C0-EF 32 E0-FF 24 F0-07 + - bottom blanking 3 F0-F2 3 00-02 3 08-0A + +*/ + +#include "emu.h" +#include "video/315_5124.h" + + +#define STATUS_VINT 0x80 /* Pending vertical interrupt flag */ +#define STATUS_SPROVR 0x40 /* Sprite overflow flag */ +#define STATUS_SPRCOL 0x20 /* Object collision flag */ +#define STATUS_HINT 0x02 /* Pending horizontal interrupt flag */ + +#define VINT_HPOS 24 +#define VINT_FLAG_HPOS 24 +#define HINT_HPOS 26 +#define NMI_HPOS 28 /* not verified */ +#define VCOUNT_CHANGE_HPOS 23 +#define SPROVR_HPOS 24 +#define SPRCOL_BASEHPOS 59 +#define XSCROLL_HPOS 21 +#define DISPLAY_DISABLED_HPOS 24 /* not verified, works if above 18 (for 'pstrike2') and below 25 (for 'fantdizzy') */ +#define DISPLAY_CB_HPOS 2 /* fixes 'roadrash' (SMS game) title scrolling, due to line counter reload timing */ + +#define DRAW_TIME_GG 94 /* 9 + 2 + 14 + 8 + 13 + 96/2 */ +#define DRAW_TIME_SMS 46 /* 9 + 2 + 14 + 8 + 13 */ + +#define PRIORITY_BIT 0x1000 +#define BACKDROP_COLOR ((m_vdp_mode == 4 ? 0x10 : 0x00) + (m_reg[0x07] & 0x0f)) + +#define VERTICAL_BLANKING 0 +#define TOP_BLANKING 1 +#define TOP_BORDER 2 +#define ACTIVE_DISPLAY_V 3 +#define BOTTOM_BORDER 4 +#define BOTTOM_BLANKING 5 + +static const UINT8 ntsc_192[6] = { 3, 13, 27, 192, 24, 3 }; +static const UINT8 ntsc_224[6] = { 3, 13, 11, 224, 8, 3 }; +static const UINT8 ntsc_240[6] = { 3, 13, 3, 240, 0, 3 }; +static const UINT8 pal_192[6] = { 3, 13, 54, 192, 48, 3 }; +static const UINT8 pal_224[6] = { 3, 13, 38, 224, 32, 3 }; +static const UINT8 pal_240[6] = { 3, 13, 30, 240, 24, 3 }; + + +const device_type SEGA315_5124 = &device_creator; +const device_type SEGA315_5246 = &device_creator; +const device_type SEGA315_5378 = &device_creator; + + +PALETTE_INIT_MEMBER(sega315_5124_device, sega315_5124) +{ + int i; + for (i = 0; i < 64; i++) + { + int r = i & 0x03; + int g = (i & 0x0c) >> 2; + int b = (i & 0x30) >> 4; + palette.set_pen_color(i, pal2bit(r), pal2bit(g), pal2bit(b)); + } + /* sms and sg1000-mark3 uses a different palette for modes 0 to 3 - see http://www.smspower.org/Development/Palette */ + /* TMS9918 palette */ + palette.set_pen_color(64+ 0, 0, 0, 0); // palette.set_pen_color(64+ 0, 0, 0, 0); + palette.set_pen_color(64+ 1, 0, 0, 0); // palette.set_pen_color(64+ 1, 0, 0, 0); + palette.set_pen_color(64+ 2, 0, 170, 0); // palette.set_pen_color(64+ 2, 33, 200, 66); + palette.set_pen_color(64+ 3, 0, 255, 0); // palette.set_pen_color(64+ 3, 94, 220, 120); + palette.set_pen_color(64+ 4, 0, 0, 85); // palette.set_pen_color(64+ 4, 84, 85, 237); + palette.set_pen_color(64+ 5, 0, 0, 255); // palette.set_pen_color(64+ 5, 125, 118, 252); + palette.set_pen_color(64+ 6, 85, 0, 0); // palette.set_pen_color(64+ 6, 212, 82, 77); + palette.set_pen_color(64+ 7, 0, 255, 255); // palette.set_pen_color(64+ 7, 66, 235, 245); + palette.set_pen_color(64+ 8, 170, 0, 0); // palette.set_pen_color(64+ 8, 252, 85, 84); + palette.set_pen_color(64+ 9, 255, 0, 0); // palette.set_pen_color(64+ 9, 255, 121, 120); + palette.set_pen_color(64+10, 85, 85, 0); // palette.set_pen_color(64+10, 212, 193, 84); + palette.set_pen_color(64+11, 255, 255, 0); // palette.set_pen_color(64+11, 230, 206, 128); + palette.set_pen_color(64+12, 0, 85, 0); // palette.set_pen_color(64+12, 33, 176, 59); + palette.set_pen_color(64+13, 255, 0, 255); // palette.set_pen_color(64+13, 201, 91, 186); + palette.set_pen_color(64+14, 85, 85, 85); // palette.set_pen_color(64+14, 204, 204, 204); + palette.set_pen_color(64+15, 255, 255, 255); // palette.set_pen_color(64+15, 255, 255, 255); +} + + +PALETTE_INIT_MEMBER(sega315_5378_device, sega315_5378) +{ + int i; + for (i = 0; i < 4096; i++) + { + int r = i & 0x000f; + int g = (i & 0x00f0) >> 4; + int b = (i & 0x0f00) >> 8; + palette.set_pen_color(i, pal4bit(r), pal4bit(g), pal4bit(b)); + } +} + + +// default address map +static ADDRESS_MAP_START( sega315_5124, AS_0, 8, sega315_5124_device ) + AM_RANGE(0x0000, VRAM_SIZE-1) AM_RAM +ADDRESS_MAP_END + + +sega315_5124_device::sega315_5124_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t( mconfig, SEGA315_5124, "Sega 315-5124 VDP", tag, owner, clock, "sega315_5124", __FILE__) + , device_memory_interface(mconfig, *this) + , device_video_interface(mconfig, *this) + , m_cram_size( SEGA315_5124_CRAM_SIZE ) + , m_palette_offset( 0 ) + , m_supports_224_240( false ) + , m_is_pal(false) + , m_int_cb(*this) + , m_pause_cb(*this) + , m_space_config("videoram", ENDIANNESS_LITTLE, 8, 14, 0, NULL, *ADDRESS_MAP_NAME(sega315_5124)) + , m_palette(*this, "palette") +{ +} + + +sega315_5124_device::sega315_5124_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, UINT8 cram_size, UINT8 palette_offset, bool supports_224_240, const char *shortname, const char *source) + : device_t( mconfig, type, name, tag, owner, clock, shortname, source) + , device_memory_interface(mconfig, *this) + , device_video_interface(mconfig, *this) + , m_cram_size( cram_size ) + , m_palette_offset( palette_offset ) + , m_supports_224_240( supports_224_240 ) + , m_is_pal(false) + , m_int_cb(*this) + , m_pause_cb(*this) + , m_space_config("videoram", ENDIANNESS_LITTLE, 8, 14, 0, NULL, *ADDRESS_MAP_NAME(sega315_5124)) + , m_palette(*this, "palette") +{ +} + + +sega315_5246_device::sega315_5246_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : sega315_5124_device( mconfig, SEGA315_5246, "Sega 315-5246 VDP", tag, owner, clock, SEGA315_5124_CRAM_SIZE, 0, true, "sega315_5246", __FILE__) +{ +} + + +sega315_5378_device::sega315_5378_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : sega315_5124_device( mconfig, SEGA315_5378, "Sega 315-5378 VDP", tag, owner, clock, SEGA315_5378_CRAM_SIZE, 0x10, true, "sega315_5378", __FILE__) +{ +} + + +void sega315_5124_device::set_display_settings() +{ + const bool M1 = m_reg[0x01] & 0x10; + const bool M2 = m_reg[0x00] & 0x02; + const bool M3 = m_reg[0x01] & 0x08; + const bool M4 = m_reg[0x00] & 0x04; + + m_y_pixels = 192; + + if (M4) + { + /* mode 4 */ + m_vdp_mode = 4; + if ( m_supports_224_240 ) + { + if (M2) + { + if (M1 && !M3) + { + m_y_pixels = 224; /* 224-line display */ + } + else if (!M1 && M3) + { + m_y_pixels = 240; /* 240-line display */ + } + } + } + } + else + { + /* original TMS9918 mode */ + if (!M1 && !M2 && !M3) + { + m_vdp_mode = 0; + } +#if 0 + /* Mode 1, not implemented */ + else if (M1 && !M2 && !M3) + { + m_vdp_mode = 1; + } +#endif + else if (!M1 && M2 && !M3) + { + m_vdp_mode = 2; + } +#if 0 + /* Mode 3, not implemented */ + else if (!M1 && !M2 && M3) + { + m_vdp_mode = 3; + } +#endif + else + { + logerror("Unknown video mode detected (M1 = %c, M2 = %c, M3 = %c, M4 = %c)\n", M1 ? '1' : '0', M2 ? '1' : '0', M3 ? '1' : '0', M4 ? '1' : '0'); + } + } + + set_frame_timing(); + m_cram_dirty = 1; +} + + +void sega315_5124_device::set_frame_timing() +{ + switch (m_y_pixels) + { + case 192: + m_frame_timing = (m_is_pal) ? pal_192 : ntsc_192; + break; + + case 224: + m_frame_timing = (m_is_pal) ? pal_224 : ntsc_224; + break; + + case 240: + m_frame_timing = (m_is_pal) ? pal_240 : ntsc_240; + break; + } +} + + +READ8_MEMBER( sega315_5124_device::vcount_read ) +{ + const int active_scr_start = m_frame_timing[VERTICAL_BLANKING] + m_frame_timing[TOP_BLANKING] + m_frame_timing[TOP_BORDER]; + int vpos = m_screen->vpos(); + + if (m_screen->hpos() < VCOUNT_CHANGE_HPOS) + { + vpos--; + if (vpos < 0) + vpos += m_screen->height(); + } + + return (vpos - active_scr_start) & 0xff; +} + + +READ8_MEMBER( sega315_5124_device::hcount_read ) +{ + return m_hcounter; +} + + +void sega315_5124_device::hcount_latch_at_hpos( int hpos ) +{ + const int active_scr_start = 46; /* 9 + 2 + 14 + 8 + 13 */ + + /* The hcount value returned by the VDP seems to be based on the previous hpos */ + int hclock = hpos - 1; + if (hclock < 0) + hclock += SEGA315_5124_WIDTH; + + m_hcounter = ((hclock - active_scr_start) >> 1) & 0xff; +} + + +void sega315_5378_device::set_sega315_5124_compatibility_mode( bool sega315_5124_compatibility_mode ) +{ + m_sega315_5124_compatibility_mode = sega315_5124_compatibility_mode; + m_cram_mask = (!m_sega315_5124_compatibility_mode) ? (SEGA315_5378_CRAM_SIZE - 1) : (SEGA315_5124_CRAM_SIZE - 1); + m_draw_time = m_sega315_5124_compatibility_mode ? DRAW_TIME_SMS : DRAW_TIME_GG; +} + + +void sega315_5124_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch( id ) + { + case TIMER_LINE: + process_line_timer(); + break; + + case TIMER_FLAGS: + /* Activate flags that were pending until the end of the line. */ + check_pending_flags(); + break; + + case TIMER_DRAW: + update_palette(); + draw_scanline( SEGA315_5124_LBORDER_START + SEGA315_5124_LBORDER_WIDTH, param, m_screen->vpos() - param ); + break; + + case TIMER_LBORDER: + { + rectangle rec; + rec.min_y = rec.max_y = param; + + update_palette(); + + /* Draw left border */ + rec.min_x = SEGA315_5124_LBORDER_START; + rec.max_x = SEGA315_5124_LBORDER_START + SEGA315_5124_LBORDER_WIDTH - 1; + m_tmpbitmap.fill(m_palette->pen(m_current_palette[BACKDROP_COLOR]), rec); + m_y1_bitmap.fill(( m_reg[0x07] & 0x0f ) ? 1 : 0, rec); + } + break; + + case TIMER_RBORDER: + { + rectangle rec; + rec.min_y = rec.max_y = param; + + update_palette(); + + /* Draw right border */ + rec.min_x = SEGA315_5124_LBORDER_START + SEGA315_5124_LBORDER_WIDTH + 256; + rec.max_x = rec.min_x + SEGA315_5124_RBORDER_WIDTH - 1; + m_tmpbitmap.fill(m_palette->pen(m_current_palette[BACKDROP_COLOR]), rec); + m_y1_bitmap.fill(( m_reg[0x07] & 0x0f ) ? 1 : 0, rec); + } + break; + + case TIMER_HINT: + if ((m_pending_status & STATUS_HINT) || (m_status & STATUS_HINT)) + { + if ((m_reg[0x00] & 0x10)) + { + m_irq_state = 1; + + if ( !m_int_cb.isnull() ) + m_int_cb(ASSERT_LINE); + } + } + break; + + case TIMER_VINT: + if ((m_pending_status & STATUS_VINT) || (m_status & STATUS_VINT)) + { + if ((m_reg[0x01] & 0x20)) + { + m_irq_state = 1; + + if ( !m_int_cb.isnull() ) + m_int_cb(ASSERT_LINE); + } + } + break; + + case TIMER_NMI: + if ( !m_pause_cb.isnull() ) + m_pause_cb(0); + break; + } +} + + +void sega315_5124_device::process_line_timer() +{ + const int vpos = m_screen->vpos(); + int vpos_limit = m_frame_timing[VERTICAL_BLANKING] + m_frame_timing[TOP_BLANKING] + + m_frame_timing[TOP_BORDER] + m_frame_timing[ACTIVE_DISPLAY_V] + + m_frame_timing[BOTTOM_BORDER] + m_frame_timing[BOTTOM_BLANKING]; + + /* copy current values in case they are not changed until latch time */ + m_display_disabled = !(m_reg[0x01] & 0x40); + m_reg8copy = m_reg[0x08]; + + vpos_limit -= m_frame_timing[BOTTOM_BLANKING]; + + /* Check if we're below the bottom border */ + if (vpos >= vpos_limit) + { + m_line_counter = m_reg[0x0a]; + return; + } + + vpos_limit -= m_frame_timing[BOTTOM_BORDER]; + + /* Check if we're in the bottom border area */ + if (vpos >= vpos_limit) + { + if (vpos == vpos_limit) + { + if (m_line_counter == 0x00) + { + m_line_counter = m_reg[0x0a]; + m_hint_timer->adjust( m_screen->time_until_pos( vpos, HINT_HPOS ) ); + m_pending_status |= STATUS_HINT; + } + else + { + m_line_counter--; + } + } + else + { + m_line_counter = m_reg[0x0a]; + } + + if (vpos == vpos_limit + 1) + { + m_vint_timer->adjust( m_screen->time_until_pos( vpos, VINT_HPOS ) ); + m_pending_status |= STATUS_VINT; + } + + /* Draw borders */ + m_lborder_timer->adjust( m_screen->time_until_pos( vpos, SEGA315_5124_LBORDER_START ), vpos ); + m_rborder_timer->adjust( m_screen->time_until_pos( vpos, SEGA315_5124_LBORDER_START + SEGA315_5124_LBORDER_WIDTH + 256 ), vpos ); + + /* Draw middle of the border */ + /* We need to do this through the regular drawing function */ + /* so sprite collisions can occur on the border. */ + select_sprites( vpos - (vpos_limit - m_frame_timing[ACTIVE_DISPLAY_V]) ); + m_draw_timer->adjust( m_screen->time_until_pos( vpos, m_draw_time ), vpos_limit - m_frame_timing[ACTIVE_DISPLAY_V] ); + return; + } + + vpos_limit -= m_frame_timing[ACTIVE_DISPLAY_V]; + + /* Check if we're in the active display area */ + if (vpos >= vpos_limit) + { + if (vpos == vpos_limit) + { + m_reg9copy = m_reg[0x09]; + } + + if (m_line_counter == 0x00) + { + m_line_counter = m_reg[0x0a]; + m_hint_timer->adjust( m_screen->time_until_pos( vpos, HINT_HPOS ) ); + m_pending_status |= STATUS_HINT; + } + else + { + m_line_counter--; + } + + /* Draw borders */ + m_lborder_timer->adjust( m_screen->time_until_pos( vpos, SEGA315_5124_LBORDER_START ), vpos ); + m_rborder_timer->adjust( m_screen->time_until_pos( vpos, SEGA315_5124_LBORDER_START + SEGA315_5124_LBORDER_WIDTH + 256 ), vpos ); + + /* Draw active display */ + select_sprites( vpos - vpos_limit ); + m_draw_timer->adjust( m_screen->time_until_pos( vpos, m_draw_time ), vpos_limit ); + return; + } + + vpos_limit -= m_frame_timing[TOP_BORDER]; + + /* Check if we're in the top border area */ + if (vpos >= vpos_limit) + { + m_line_counter = m_reg[0x0a]; + + /* Check if we're on the last line of the top border */ + if (vpos == vpos_limit + m_frame_timing[TOP_BORDER] - 1) + { + m_nmi_timer->adjust( m_screen->time_until_pos( vpos, NMI_HPOS ) ); + } + + /* Draw borders */ + m_lborder_timer->adjust( m_screen->time_until_pos( vpos, SEGA315_5124_LBORDER_START ), vpos ); + m_rborder_timer->adjust( m_screen->time_until_pos( vpos, SEGA315_5124_LBORDER_START + SEGA315_5124_LBORDER_WIDTH + 256 ), vpos ); + + /* Draw middle of the border */ + /* We need to do this through the regular drawing function */ + /* so sprite collisions can occur on the border. */ + select_sprites( vpos - (vpos_limit + m_frame_timing[TOP_BORDER]) ); + m_draw_timer->adjust( m_screen->time_until_pos( vpos, m_draw_time ), vpos_limit + m_frame_timing[TOP_BORDER] ); + return; + } + + /* we're in the vertical or top blanking area */ + m_line_counter = m_reg[0x0a]; +} + + +READ8_MEMBER( sega315_5124_device::vram_read ) +{ + UINT8 temp; + + /* SMS 2 & GG behaviour. Seems like the latched data is passed straight through */ + /* to the address register when in the middle of doing a command. */ + /* Cosmic Spacehead needs this, among others */ + /* Clear pending write flag */ + m_pending_reg_write = 0; + + /* Return read buffer contents */ + temp = m_buffer; + + if ( !space.debugger_access() ) + { + /* Load read buffer */ + m_buffer = this->space().read_byte(m_addr & 0x3fff); + + /* Bump internal address register */ + m_addr += 1; + } + return temp; +} + + +void sega315_5124_device::check_pending_flags() +{ + int hpos; + + if (!m_pending_status) + { + return; + } + + /* A timer ensures that this function will run at least at end of each line. + When this function runs through a CPU instruction executed when the timer + was about to fire, the time added in the CPU timeslice may make hpos() + return some position in the beginning of next line. To ensure the instruction + will get updated status, here a maximum hpos is set if the timer reports no + remaining time, what could also occur due to the ahead time of the timeslice. */ + if (m_pending_flags_timer->remaining() == attotime::zero) + { + hpos = SEGA315_5124_WIDTH - 1; + } + else + { + hpos = m_screen->hpos(); + } + + if ((m_pending_status & STATUS_HINT) && hpos >= HINT_HPOS) + { + m_pending_status &= ~STATUS_HINT; + m_status |= STATUS_HINT; // fake flag, it is overridden on register read. + } + if ((m_pending_status & STATUS_VINT) && hpos >= VINT_FLAG_HPOS) + { + m_pending_status &= ~STATUS_VINT; + m_status |= STATUS_VINT; + } + if ((m_pending_status & STATUS_SPROVR) && hpos >= SPROVR_HPOS) + { + m_pending_status &= ~STATUS_SPROVR; + m_status |= STATUS_SPROVR; + } + if ((m_pending_status & STATUS_SPRCOL) && hpos >= m_pending_sprcol_x) + { + m_pending_status &= ~STATUS_SPRCOL; + m_status |= STATUS_SPRCOL; + m_pending_sprcol_x = 0; + } +} + + +READ8_MEMBER( sega315_5124_device::register_read ) +{ + UINT8 temp; + + check_pending_flags(); + temp = m_status; + + if ( !space.debugger_access() ) + { + /* Clear pending write flag */ + m_pending_reg_write = 0; + + m_status &= ~(STATUS_VINT | STATUS_SPROVR | STATUS_SPRCOL | STATUS_HINT); + + if (m_irq_state == 1) + { + m_irq_state = 0; + + if ( !m_int_cb.isnull() ) + m_int_cb(CLEAR_LINE); + } + } + + /* low 5 bits return non-zero data (it fixes PGA Tour Golf course map introduction) */ + return temp | 0x1f; +} + + +WRITE8_MEMBER( sega315_5124_device::vram_write ) +{ + /* SMS 2 & GG behaviour. Seems like the latched data is passed straight through */ + /* to the address register when in the middle of doing a command. */ + /* Cosmic Spacehead needs this, among others */ + /* Clear pending write flag */ + m_pending_reg_write = 0; + + switch(m_addrmode) + { + case 0x00: + case 0x01: + case 0x02: + this->space().write_byte(m_addr & 0x3fff, data); + break; + + case 0x03: + cram_write(data); + break; + } + + m_buffer = data; + m_addr += 1; +} + + +WRITE8_MEMBER( sega315_5124_device::register_write ) +{ + int reg_num; + + if (m_pending_reg_write == 0) + { + m_addr = (m_addr & 0xff00) | data; + m_pending_reg_write = 1; + } + else + { + /* Clear pending write flag */ + m_pending_reg_write = 0; + + m_addrmode = (data >> 6) & 0x03; + m_addr = (data << 8) | (m_addr & 0xff); + switch (m_addrmode) + { + case 0: /* VRAM reading mode */ + m_buffer = this->space().read_byte(m_addr & 0x3fff); + m_addr += 1; + break; + + case 1: /* VRAM writing mode */ + break; + + case 2: /* VDP register write */ + reg_num = data & 0x0f; + m_reg[reg_num] = m_addr & 0xff; + //logerror("%s: %s: setting register %x to %02x\n", machine().describe_context(), tag(), reg_num, m_addr & 0xff); + + switch (reg_num) + { + case 0: + set_display_settings(); + if (m_addr & 0x02) + logerror("overscan enabled.\n"); + break; + case 1: + set_display_settings(); + if (m_screen->hpos() <= DISPLAY_DISABLED_HPOS) + m_display_disabled = !(m_reg[0x01] & 0x40); + break; + case 8: + if (m_screen->hpos() <= XSCROLL_HPOS) + m_reg8copy = m_reg[0x08]; + } + + check_pending_flags(); + + if ( ( reg_num == 0 && (m_status & STATUS_HINT) ) || + ( reg_num == 1 && (m_status & STATUS_VINT) ) ) + { + // For HINT disabling through register 00: + // "Line IRQ VCount" test, of Flubba's VDPTest ROM, disables HINT to wait + // for next VINT, but HINT occurs when the operation is about to execute. + // So here, where the setting is done, the irq_state needs to be cleared. + // + // For VINT disabling through register 01: + // When running eagles5 on the smskr driver the irq_state is 1 because of some + // previos HINTs that occurred. eagles5 sets register 01 to 0x02 and expects + // the irq state to be cleared after that. + // The following bit of code takes care of that. + // + if ( ( reg_num == 0 && !(m_reg[0x00] & 0x10) ) || + ( reg_num == 1 && !(m_reg[0x01] & 0x20) ) ) + { + if (m_irq_state == 1) + { + m_irq_state = 0; + + if ( !m_int_cb.isnull() ) + { + m_int_cb(CLEAR_LINE); + } + } + } + else + { + // For register 01 and VINT enabling: + // Assert the IRQ line for the scoreboard of robocop3, + // on the sms/smspal driver, be displayed correctly. + // + // Assume the same behavior for reg0+HINT. + // + m_irq_state = 1; + + if ( !m_int_cb.isnull() ) + m_int_cb(ASSERT_LINE); + } + } + m_addrmode = 0; + break; + + case 3: /* CRAM writing mode */ + break; + } + } +} + + +UINT16 sega315_5124_device::get_name_table_row(int row) +{ + return ((row >> 3) << 6) & (((m_reg[0x02] & 0x01) << 10) | 0x3bff); +} + + +UINT16 sega315_5246_device::get_name_table_row(int row) +{ + return (row >> 3) << 6; +} + + +UINT16 sega315_5378_device::get_name_table_row(int row) +{ + return (row >> 3) << 6; +} + + +void sega315_5124_device::draw_scanline_mode4( int *line_buffer, int *priority_selected, int line ) +{ + int tile_column; + int y_scroll, scroll_mod; + int pixel_x, pixel_plot_x; + int bit_plane_0, bit_plane_1, bit_plane_2, bit_plane_3; + UINT16 name_table_address; + + /* if top 2 rows of screen not affected by horizontal scrolling, then x_scroll = 0 */ + /* else x_scroll = m_reg8copy */ + const int x_scroll = (((m_reg[0x00] & 0x40) && (line < 16)) ? 0 : 0x0100 - m_reg8copy); + + const int x_scroll_start_column = (x_scroll >> 3); /* x starting column tile */ + + if ( m_y_pixels != 192 ) + { + name_table_address = ((m_reg[0x02] & 0x0c) << 10) | 0x0700; + scroll_mod = 256; + } + else + { + name_table_address = (m_reg[0x02] << 10) & 0x3800; + scroll_mod = 224; + } + + /* Draw background layer */ + for (tile_column = 0; tile_column < 33; tile_column++) + { + UINT16 tile_data; + int tile_selected, palette_selected, horiz_selected, vert_selected, priority_select; + int tile_line; + + /* Rightmost 8 columns for SMS (or 2 columns for GG) not affected by */ + /* vertical scrolling when bit 7 of reg[0x00] is set */ + y_scroll = ((m_reg[0x00] & 0x80) && (tile_column > 23)) ? 0 : m_reg9copy; + + tile_line = ((tile_column + x_scroll_start_column) & 0x1f) << 1; + tile_data = space().read_word(name_table_address + get_name_table_row((line + y_scroll) % scroll_mod) + tile_line); + + tile_selected = (tile_data & 0x01ff); + priority_select = tile_data & PRIORITY_BIT; + palette_selected = (tile_data >> 11) & 0x01; + vert_selected = (tile_data >> 10) & 0x01; + horiz_selected = (tile_data >> 9) & 0x01; + + tile_line = line - ((0x07 - (y_scroll & 0x07)) + 1); + if (vert_selected) + tile_line = 0x07 - tile_line; + + bit_plane_0 = space().read_byte(((tile_selected << 5) + ((tile_line & 0x07) << 2)) + 0x00); + bit_plane_1 = space().read_byte(((tile_selected << 5) + ((tile_line & 0x07) << 2)) + 0x01); + bit_plane_2 = space().read_byte(((tile_selected << 5) + ((tile_line & 0x07) << 2)) + 0x02); + bit_plane_3 = space().read_byte(((tile_selected << 5) + ((tile_line & 0x07) << 2)) + 0x03); + + for (pixel_x = 0; pixel_x < 8; pixel_x++) + { + UINT8 pen_bit_0, pen_bit_1, pen_bit_2, pen_bit_3; + UINT8 pen_selected; + + pen_bit_0 = (bit_plane_0 >> (7 - pixel_x)) & 0x01; + pen_bit_1 = (bit_plane_1 >> (7 - pixel_x)) & 0x01; + pen_bit_2 = (bit_plane_2 >> (7 - pixel_x)) & 0x01; + pen_bit_3 = (bit_plane_3 >> (7 - pixel_x)) & 0x01; + + pen_selected = (pen_bit_3 << 3 | pen_bit_2 << 2 | pen_bit_1 << 1 | pen_bit_0); + if (palette_selected) + pen_selected |= 0x10; + + if (!horiz_selected) + { + pixel_plot_x = pixel_x; + } + else + { + pixel_plot_x = 7 - pixel_x; + } + + pixel_plot_x = (0 - (x_scroll & 0x07) + (tile_column << 3) + pixel_plot_x); + if (pixel_plot_x >= 0 && pixel_plot_x < 256) + { + //logerror("%x %x\n", pixel_plot_x, line); + if (tile_column == 0 && (x_scroll & 0x07)) + { + /* when the first column hasn't completely entered in the screen, its + background is filled only with color #0 of the selected palette */ + line_buffer[pixel_plot_x] = m_current_palette[palette_selected ? 0x10 : 0x00]; + priority_selected[pixel_plot_x] = priority_select; + } + else + { + line_buffer[pixel_plot_x] = m_current_palette[pen_selected]; + priority_selected[pixel_plot_x] = priority_select | (pen_selected & 0x0f); + } + } + } + } +} + + +void sega315_5124_device::select_sprites( int line ) +{ + int max_sprites; + + /* At this point the VDP vcount still doesn't refer the new line, + because the logical start point is slightly shifted on the scanline */ + int parse_line = line - 1; + + /* Check if SI is set */ + m_sprite_height = (m_reg[0x01] & 0x02) ? 16 : 8; + /* Check if MAG is set */ + m_sprite_zoom = (m_reg[0x01] & 0x01) ? 2 : 1; + + if (m_sprite_zoom > 1) + { + /* Divide before use the value for comparison, same later with sprite_y, or + else an off-by-one bug could occur, as seen with Tarzan, for Game Gear */ + parse_line >>= 1; + } + + m_sprite_count = 0; + + if ( m_vdp_mode == 0 || m_vdp_mode == 2 ) + { + /* TMS9918 compatibility sprites */ + + max_sprites = 4; + + m_sprite_base = ((m_reg[0x05] & 0x7f) << 7); + + for (int sprite_index = 0; (sprite_index < 32 * 4) && (m_sprite_count <= max_sprites); sprite_index += 4) + { + int sprite_y = space().read_byte(m_sprite_base + sprite_index); + if (sprite_y == 0xd0) + break; + + if (sprite_y >= 240) + { + sprite_y -= 256; + } + + if (m_sprite_zoom > 1) + { + sprite_y >>= 1; + } + + if ((parse_line >= sprite_y) && (parse_line < (sprite_y + m_sprite_height))) + { + if (m_sprite_count < max_sprites) + { + int sprite_x = space().read_byte( m_sprite_base + sprite_index + 1 ); + int sprite_tile_selected = space().read_byte( m_sprite_base + sprite_index + 2 ); + UINT8 flags = space().read_byte( m_sprite_base + sprite_index + 3 ); + + if (flags & 0x80) + sprite_x -= 32; + + int sprite_line = parse_line - sprite_y; + + if (m_reg[0x01] & 0x01) + sprite_line >>= 1; + + if (m_reg[0x01] & 0x02) + { + sprite_tile_selected &= 0xfc; + + if (sprite_line > 0x07) + { + sprite_tile_selected += 1; + sprite_line -= 8; + } + } + + m_sprite_x[m_sprite_count] = sprite_x; + m_sprite_tile_selected[m_sprite_count] = sprite_tile_selected; + m_sprite_flags[m_sprite_count] = flags; + m_sprite_pattern_line[m_sprite_count] = ((m_reg[0x06] & 0x07) << 11) + sprite_line; + } + m_sprite_count++; + } + } + } + else + { + /* Regular sprites */ + + max_sprites = 8; + + m_sprite_base = ((m_reg[0x05] << 7) & 0x3f00); + + for (int sprite_index = 0; (sprite_index < 64) && (m_sprite_count <= max_sprites); sprite_index++) + { + int sprite_y = space().read_byte(m_sprite_base + sprite_index); + if (m_y_pixels == 192 && sprite_y == 0xd0) + break; + + if (sprite_y >= 240) + { + sprite_y -= 256; /* wrap from top if y position is > 240 */ + } + + if (m_sprite_zoom > 1) + { + sprite_y >>= 1; + } + + if ((parse_line >= sprite_y) && (parse_line < (sprite_y + m_sprite_height))) + { + if (m_sprite_count < max_sprites) + { + int sprite_x = space().read_byte( m_sprite_base + 0x80 + (sprite_index << 1) ); + int sprite_tile_selected = space().read_byte( m_sprite_base + 0x81 + (sprite_index << 1) ); + + if (m_reg[0x00] & 0x08) + { + sprite_x -= 0x08; /* sprite shift */ + } + + if (m_reg[0x06] & 0x04) + { + sprite_tile_selected += 256; /* pattern table select */ + } + + if (m_reg[0x01] & 0x02) + { + sprite_tile_selected &= 0x01fe; /* force even index */ + } + + int sprite_line = parse_line - sprite_y; + + if (sprite_line > 0x07) + { + sprite_tile_selected += 1; + } + + m_sprite_x[m_sprite_count] = sprite_x; + m_sprite_tile_selected[m_sprite_count] = sprite_tile_selected; + m_sprite_pattern_line[m_sprite_count] = ((sprite_line & 0x07) << 2); + } + m_sprite_count++; + } + } + } + + if ( m_sprite_count > max_sprites ) + { + /* Too many sprites per line */ + + m_sprite_count = max_sprites; + + /* Overflow is flagged only on active display and when VINT isn't active */ + if (!(m_status & STATUS_VINT) && line >= 0 && line < m_frame_timing[ACTIVE_DISPLAY_V]) + { + m_pending_status |= STATUS_SPROVR; + } + } +} + + +void sega315_5124_device::draw_sprites_mode4( int *line_buffer, int *priority_selected, int line ) +{ + bool sprite_col_occurred = false; + int sprite_col_x = 255; + UINT8 collision_buffer[256]; + int plot_min_x = 0; + + if (m_display_disabled || m_sprite_count == 0) + return; + + /* Sprites aren't drawn and collisions don't occur on column 0 if it is disabled. + Note: On Megadrive/Genesis VDP, collisions occur on the disabled column 0. */ + if (m_reg[0x00] & 0x20) + plot_min_x = 8; + + memset(collision_buffer, 0, sizeof(collision_buffer)); + + /* Draw sprite layer */ + for (int sprite_buffer_index = m_sprite_count - 1; sprite_buffer_index >= 0; sprite_buffer_index--) + { + int sprite_x = m_sprite_x[sprite_buffer_index]; + int sprite_tile_selected = m_sprite_tile_selected[sprite_buffer_index]; + UINT16 sprite_pattern_line = m_sprite_pattern_line[sprite_buffer_index]; + + UINT8 bit_plane_0 = space().read_byte((sprite_tile_selected << 5) + sprite_pattern_line + 0x00); + UINT8 bit_plane_1 = space().read_byte((sprite_tile_selected << 5) + sprite_pattern_line + 0x01); + UINT8 bit_plane_2 = space().read_byte((sprite_tile_selected << 5) + sprite_pattern_line + 0x02); + UINT8 bit_plane_3 = space().read_byte((sprite_tile_selected << 5) + sprite_pattern_line + 0x03); + + for (int pixel_x = 0; pixel_x < 8; pixel_x++) + { + int pixel_plot_x; + UINT8 pen_bit_0 = (bit_plane_0 >> (7 - pixel_x)) & 0x01; + UINT8 pen_bit_1 = (bit_plane_1 >> (7 - pixel_x)) & 0x01; + UINT8 pen_bit_2 = (bit_plane_2 >> (7 - pixel_x)) & 0x01; + UINT8 pen_bit_3 = (bit_plane_3 >> (7 - pixel_x)) & 0x01; + UINT8 pen_selected = (pen_bit_3 << 3 | pen_bit_2 << 2 | pen_bit_1 << 1 | pen_bit_0) | 0x10; + + if (pen_selected == 0x10) + { + /* Transparent palette so skip draw */ + continue; + } + + if (m_sprite_zoom > 1) + { + /* sprite doubling is enabled */ + pixel_plot_x = sprite_x + (pixel_x << 1); + } + else + { + pixel_plot_x = sprite_x + pixel_x; + } + + /* Draw at pixel position and, if zoomed, at pixel+1 */ + for (int zoom = 0; zoom < m_sprite_zoom; zoom++) + { + pixel_plot_x += zoom; + + /* check to prevent going outside of active display area */ + if (pixel_plot_x < plot_min_x || pixel_plot_x > 255) + { + continue; + } + + /* Draw sprite pixel */ + /* Check if the background has lower priority */ + if (!(priority_selected[pixel_plot_x] & PRIORITY_BIT)) + { + line_buffer[pixel_plot_x] = m_current_palette[pen_selected]; + priority_selected[pixel_plot_x] = pen_selected; + } + else + { + /* Check if the higher priority background has transparent pixel */ + if (priority_selected[pixel_plot_x] == PRIORITY_BIT) + { + line_buffer[pixel_plot_x] = m_current_palette[pen_selected]; + priority_selected[pixel_plot_x] = pen_selected; + } + } + if (collision_buffer[pixel_plot_x] != 1) + { + collision_buffer[pixel_plot_x] = 1; + } + else + { + sprite_col_occurred = true; + sprite_col_x = MIN(sprite_col_x, pixel_plot_x); + } + } + } + if (sprite_col_occurred) + { + m_pending_status |= STATUS_SPRCOL; + m_pending_sprcol_x = SPRCOL_BASEHPOS + sprite_col_x; + } + } +} + + +void sega315_5124_device::draw_sprites_tms9918_mode( int *line_buffer, int line ) +{ + bool sprite_col_occurred = false; + int sprite_col_x = 255; + UINT8 collision_buffer[256]; + + if (m_display_disabled || m_sprite_count == 0) + return; + + memset(collision_buffer, 0, sizeof(collision_buffer)); + + /* Draw sprite layer */ + for (int sprite_buffer_index = m_sprite_count - 1; sprite_buffer_index >= 0; sprite_buffer_index--) + { + int sprite_x = m_sprite_x[sprite_buffer_index]; + UINT8 flags = m_sprite_flags[sprite_buffer_index]; + int pen_selected = m_palette_offset + ( flags & 0x0f ); + + int sprite_tile_selected = m_sprite_tile_selected[sprite_buffer_index]; + UINT16 sprite_pattern_line = m_sprite_pattern_line[sprite_buffer_index]; + + for (int height = 8; height <= m_sprite_height; height += 8) + { + if (height == 16) + { + sprite_tile_selected += 2; + sprite_x += (m_sprite_zoom > 1 ? 16 : 8); + } + + UINT8 pattern = space().read_byte( sprite_pattern_line + sprite_tile_selected * 8 ); + + for (int pixel_x = 0; pixel_x < 8; pixel_x++) + { + if (pen_selected && (pattern & (1 << (7 - pixel_x)))) + { + int pixel_plot_x; + if (m_sprite_zoom > 1) + { + pixel_plot_x = sprite_x + (pixel_x << 1); + } + else + { + pixel_plot_x = sprite_x + pixel_x; + } + + /* Draw at pixel position and, if zoomed, at pixel+1 */ + for (int zoom = 0; zoom < m_sprite_zoom; zoom++) + { + pixel_plot_x += zoom; + + /* check to prevent going outside of active display area */ + if (pixel_plot_x < 0 || pixel_plot_x > 255) + { + continue; + } + + line_buffer[pixel_plot_x] = m_current_palette[pen_selected]; + + if (collision_buffer[pixel_plot_x] != 1) + { + collision_buffer[pixel_plot_x] = 1; + } + else + { + sprite_col_occurred = true; + sprite_col_x = MIN(sprite_col_x, pixel_plot_x); + } + } + } + } + } + if (sprite_col_occurred) + { + m_pending_status |= STATUS_SPRCOL; + m_pending_sprcol_x = SPRCOL_BASEHPOS + sprite_col_x; + } + } +} + + +void sega315_5124_device::draw_scanline_mode2( int *line_buffer, int line ) +{ + int tile_column; + int pixel_x, pixel_plot_x; + UINT16 name_table_base, color_base, pattern_base; + int pattern_mask, color_mask, pattern_offset; + + name_table_base = ((m_reg[0x02] & 0x0f) << 10) + ((line >> 3) * 32); + color_base = ((m_reg[0x03] & 0x80) << 6); + color_mask = ((m_reg[0x03] & 0x7f) << 3) | 0x07; + pattern_base = ((m_reg[0x04] & 0x04) << 11); + pattern_mask = ((m_reg[0x04] & 0x03) << 8) | 0xff; + pattern_offset = (line & 0xc0) << 2; + + /* Draw background layer */ + for (tile_column = 0; tile_column < 32; tile_column++) + { + UINT8 name = space().read_byte( name_table_base + tile_column ); + UINT8 pattern; + UINT8 colors; + + pattern = space().read_byte(pattern_base + (((pattern_offset + name) & pattern_mask) * 8) + (line & 0x07) ); + colors = space().read_byte(color_base + (((pattern_offset + name) & color_mask) * 8) + (line & 0x07) ); + + for (pixel_x = 0; pixel_x < 8; pixel_x++) + { + UINT8 pen_selected; + + if (pattern & (1 << (7 - pixel_x))) + { + pen_selected = colors >> 4; + } + else + { + pen_selected = colors & 0x0f; + } + + if (!pen_selected) + pen_selected = BACKDROP_COLOR; + + pixel_plot_x = (tile_column << 3) + pixel_x; + + pen_selected += m_palette_offset; + + line_buffer[pixel_plot_x] = m_current_palette[pen_selected]; + } + } +} + + +void sega315_5124_device::draw_scanline_mode0( int *line_buffer, int line ) +{ + int tile_column; + int pixel_x, pixel_plot_x; + UINT16 name_base, color_base, pattern_base; + + name_base = ((m_reg[0x02] & 0x0f) << 10) + ((line >> 3) * 32); + color_base = ((m_reg[0x03] << 6) & (VRAM_SIZE - 1)); + pattern_base = ((m_reg[0x04] << 11) & (VRAM_SIZE - 1)); + + /* Draw background layer */ + for (tile_column = 0; tile_column < 32; tile_column++) + { + UINT8 name = space().read_byte( name_base + tile_column ); + UINT8 pattern; + UINT8 colors; + + pattern = space().read_byte( pattern_base + (name * 8) + (line & 0x07) ); + colors = space().read_byte( color_base + ( name >> 3 ) ); + + for (pixel_x = 0; pixel_x < 8; pixel_x++) + { + int pen_selected; + + if (pattern & (1 << (7 - pixel_x))) + pen_selected = colors >> 4; + else + pen_selected = colors & 0x0f; + + pen_selected += m_palette_offset; + + pixel_plot_x = (tile_column << 3) + pixel_x; + line_buffer[pixel_plot_x] = m_current_palette[pen_selected]; + } + } +} + + +void sega315_5124_device::draw_scanline( int pixel_offset_x, int pixel_plot_y, int line ) +{ + int blitline_buffer[256]; + int priority_selected[256]; + + /* Sprite processing is restricted because collisions on top border of extended + resolution break the scoreboard of Fantasy Dizzy (SMS) on smspal driver */ + + if ( line < m_frame_timing[ACTIVE_DISPLAY_V] ) + { + memset(priority_selected, 1, sizeof(priority_selected)); + + switch( m_vdp_mode ) + { + case 0: + if ( line >= 0 ) + { + draw_scanline_mode0( blitline_buffer, line ); + } + if ( line >= 0 || ( line >= -13 && m_y_pixels == 192 ) ) + { + draw_sprites_tms9918_mode( blitline_buffer, line ); + } + break; + + case 2: + if ( line >= 0 ) + { + draw_scanline_mode2( blitline_buffer, line ); + } + if ( line >= 0 || ( line >= -13 && m_y_pixels == 192 ) ) + { + draw_sprites_tms9918_mode( blitline_buffer, line ); + } + break; + + case 4: + default: + if ( line >= 0 ) + { + draw_scanline_mode4( blitline_buffer, priority_selected, line ); + } + if ( line >= 0 || ( line >= -13 && m_y_pixels == 192 ) ) + { + draw_sprites_mode4( blitline_buffer, priority_selected, line ); + } + break; + } + } + + /* Check if display is disabled or we're below/above active area */ + if (m_display_disabled || line < 0 || line >= m_frame_timing[ACTIVE_DISPLAY_V]) + { + rectangle rec; + rec.min_y = rec.max_y = pixel_plot_y + line; + + rec.min_x = pixel_offset_x; + rec.max_x = pixel_offset_x + 255; + m_tmpbitmap.fill(m_palette->pen(m_current_palette[BACKDROP_COLOR]), rec); + m_y1_bitmap.fill(( m_reg[0x07] & 0x0f ) ? 1 : 0, rec); + } + else + { + blit_scanline(blitline_buffer, priority_selected, pixel_offset_x, pixel_plot_y, line); + } +} + + +void sega315_5124_device::blit_scanline( int *line_buffer, int *priority_selected, int pixel_offset_x, int pixel_plot_y, int line ) +{ + UINT32 *p_bitmap = &m_tmpbitmap.pix32(pixel_plot_y + line, pixel_offset_x); + UINT8 *p_y1 = &m_y1_bitmap.pix8(pixel_plot_y + line, pixel_offset_x); + int x = 0; + + if (m_vdp_mode == 4 && (m_reg[0x00] & 0x20)) + { + /* Fill column 0 with overscan color from m_reg[0x07] */ + do + { + p_bitmap[x] = m_palette->pen(m_current_palette[BACKDROP_COLOR]); + p_y1[x] = ( m_reg[0x07] & 0x0f ) ? 1 : 0; + } + while(++x < 8); + } + + do + { + p_bitmap[x] = m_palette->pen(line_buffer[x]); + p_y1[x] = ( priority_selected[x] & 0x0f ) ? 1 : 0; + } + while(++x < 256); +} + + +void sega315_5378_device::blit_scanline( int *line_buffer, int *priority_selected, int pixel_offset_x, int pixel_plot_y, int line ) +{ + if (m_sega315_5124_compatibility_mode) + { + sega315_5124_device::blit_scanline(line_buffer, priority_selected, pixel_offset_x, pixel_plot_y, line); + } + else + { + UINT32 *p_bitmap = &m_tmpbitmap.pix32(pixel_plot_y + line, pixel_offset_x); + UINT8 *p_y1 = &m_y1_bitmap.pix8(pixel_plot_y + line, pixel_offset_x); + int x = 0; + + /* border on left side of the GG active screen */ + do + { + p_bitmap[x] = m_palette->pen(m_current_palette[BACKDROP_COLOR]); + p_y1[x] = ( m_reg[0x07] & 0x0f ) ? 1 : 0; + } + while (++x < 48); + + if ( line >= 24 && line < 168 ) + { + do + { + p_bitmap[x] = m_palette->pen(line_buffer[x]); + p_y1[x] = ( priority_selected[x] & 0x0f ) ? 1 : 0; + } + while (++x < 208); + } + else + { + /* top/bottom GG border */ + do + { + p_bitmap[x] = m_palette->pen(m_current_palette[BACKDROP_COLOR]); + p_y1[x] = ( m_reg[0x07] & 0x0f ) ? 1 : 0; + } + while (++x < 208); + } + + /* border on right side of the GG active screen */ + do + { + p_bitmap[x] = m_palette->pen(m_current_palette[BACKDROP_COLOR]); + p_y1[x] = ( m_reg[0x07] & 0x0f ) ? 1 : 0; + } + while (++x < 256); + } +} + + +void sega315_5124_device::update_palette() +{ + int i; + + /* Exit if palette has no changes */ + if (m_cram_dirty == 0) + { + return; + } + m_cram_dirty = 0; + + if (m_vdp_mode != 4) + { + for(i = 0; i < 16; i++) + { + m_current_palette[i] = 64 + i; + } + return; + } + + for (i = 0; i < 32; i++) + { + m_current_palette[i] = m_CRAM[i] & 0x3f; + } +} + + +void sega315_5378_device::update_palette() +{ + int i; + + /* Exit if palette has no changes */ + if (m_cram_dirty == 0) + { + return; + } + m_cram_dirty = 0; + + if (m_sega315_5124_compatibility_mode) + { + for (i = 0; i < 32; i++) + { + m_current_palette[i] = ((m_CRAM[i] & 0x30) << 6) | ((m_CRAM[i] & 0x0c ) << 4) | ((m_CRAM[i] & 0x03) << 2); + } + } + else + { + for (i = 0; i < 32; i++) + { + m_current_palette[i] = (m_CRAM[2*i] | (m_CRAM[2*i+1] << 8)) & 0x0fff; + } + } +} + + +void sega315_5124_device::cram_write(UINT8 data) +{ + UINT16 address = m_addr & m_cram_mask; + if (data != m_CRAM[address]) + { + m_CRAM[address] = data; + m_cram_dirty = 1; + } +} + + +void sega315_5378_device::cram_write(UINT8 data) +{ + if (m_sega315_5124_compatibility_mode) + { + sega315_5124_device::cram_write(data); + } + else + { + if (m_addr & 1) + { + UINT16 address = (m_addr & m_cram_mask) & ~1; + if (m_buffer != m_CRAM[address] || data != m_CRAM[address + 1]) + { + m_CRAM[address] = m_buffer; + m_CRAM[address + 1] = data; + m_cram_dirty = 1; + } + } + } +} + + +UINT32 sega315_5124_device::screen_update( screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect ) +{ + copybitmap(bitmap, m_tmpbitmap, 0, 0, 0, 0, cliprect); + return 0; +} + + +// MegaDrive/Genesis VDP (315-5313) is currently coded as superset of the 315-5124 +// To support properly SMS VDP in MegaTech and MegaPlay, we start the 315-5124 +// in all systems using MegaDrive/Genesis VDP, but this affects the performance +// of the emulator hence we stop it in systems that don't need it +// Proper way to handle this would be implement the 315-5124 modes in the 315-5313 +// device instead of running the two chips separately... +void sega315_5124_device::stop_timers() +{ + m_display_timer->adjust(attotime::never); + m_pending_flags_timer->adjust(attotime::never); + m_hint_timer->adjust(attotime::never); + m_vint_timer->adjust(attotime::never); + m_nmi_timer->adjust(attotime::never); + m_draw_timer->adjust(attotime::never); + m_lborder_timer->adjust(attotime::never); + m_rborder_timer->adjust(attotime::never); +} + + +/***************************************************************************** + DEVICE INTERFACE +*****************************************************************************/ + +void sega315_5124_device::vdp_postload() +{ + set_frame_timing(); +} + +void sega315_5124_device::device_start() +{ + /* Resolve callbacks */ + m_int_cb.resolve(); + m_pause_cb.resolve(); + + /* Allocate video RAM */ + m_frame_timing = (m_is_pal) ? pal_192 : ntsc_192; + + /* Make temp bitmap for rendering */ + m_screen->register_screen_bitmap(m_tmpbitmap); + m_screen->register_screen_bitmap(m_y1_bitmap); + + m_display_timer = timer_alloc(TIMER_LINE); + m_display_timer->adjust(m_screen->time_until_pos(0, DISPLAY_CB_HPOS), 0, m_screen->scan_period()); + m_pending_flags_timer = timer_alloc(TIMER_FLAGS); + m_pending_flags_timer->adjust(m_screen->time_until_pos(0, SEGA315_5124_WIDTH - 1), 0, m_screen->scan_period()); + m_draw_timer = timer_alloc(TIMER_DRAW); + m_lborder_timer = timer_alloc(TIMER_LBORDER); + m_rborder_timer = timer_alloc(TIMER_RBORDER); + m_hint_timer = timer_alloc(TIMER_HINT); + m_vint_timer = timer_alloc(TIMER_VINT); + m_nmi_timer = timer_alloc(TIMER_NMI); + + save_item(NAME(m_status)); + save_item(NAME(m_pending_status)); + save_item(NAME(m_pending_sprcol_x)); + save_item(NAME(m_reg8copy)); + save_item(NAME(m_reg9copy)); + save_item(NAME(m_addrmode)); + save_item(NAME(m_addr)); + save_item(NAME(m_cram_mask)); + save_item(NAME(m_cram_dirty)); + save_item(NAME(m_pending_reg_write)); + save_item(NAME(m_buffer)); + save_item(NAME(m_sega315_5124_compatibility_mode)); + save_item(NAME(m_display_disabled)); + save_item(NAME(m_irq_state)); + save_item(NAME(m_vdp_mode)); + save_item(NAME(m_y_pixels)); + save_item(NAME(m_line_counter)); + save_item(NAME(m_hcounter)); + save_item(NAME(m_reg)); + save_item(NAME(m_current_palette)); + + // these were created with register_screen_bitmap which is dynamic, and will reallocate if the screen size changes, saving them is NOT safe with the current core. + // The Genesis VDP (315_5313.c) which uses this as a base in order to support the legacy SMS operaiton mode can change resolutions for example. + //save_item(NAME(m_tmpbitmap)); + //save_item(NAME(m_y1_bitmap)); + save_item(NAME(m_draw_time)); + save_item(NAME(m_sprite_base)); + save_item(NAME(m_sprite_pattern_line)); + save_item(NAME(m_sprite_tile_selected)); + save_item(NAME(m_sprite_x)); + save_item(NAME(m_sprite_flags)); + save_item(NAME(m_sprite_count)); + save_item(NAME(m_sprite_height)); + save_item(NAME(m_sprite_zoom)); + save_item(NAME(m_CRAM)); + + machine().save().register_postload(save_prepost_delegate(FUNC(sega315_5124_device::vdp_postload), this)); +} + + +void sega315_5124_device::device_reset() +{ + int i; + + /* Most register are 0x00 at power-up */ + for (i = 0; i < 16; i++) + m_reg[i] = 0x00; + + m_reg[0x02] = 0x0e; + m_reg[0x0a] = 0xff; + + m_status = 0; + m_pending_status = 0; + m_pending_sprcol_x = 0; + m_pending_reg_write = 0; + m_reg8copy = 0; + m_reg9copy = 0; + m_addrmode = 0; + m_addr = 0; + m_sega315_5124_compatibility_mode = false; + m_display_disabled = false; + m_cram_mask = m_cram_size - 1; + m_cram_dirty = 1; + m_buffer = 0; + m_irq_state = 0; + m_line_counter = 0; + m_hcounter = 0; + m_draw_time = DRAW_TIME_SMS; + + for (i = 0; i < 0x20; i++) + m_current_palette[i] = 0; + + set_display_settings(); + + /* Clear RAM */ + memset(m_CRAM, 0, sizeof(m_CRAM)); +} + +static MACHINE_CONFIG_FRAGMENT( sega315_5124 ) + MCFG_PALETTE_ADD("palette", SEGA315_5124_PALETTE_SIZE) + MCFG_PALETTE_INIT_OWNER(sega315_5124_device, sega315_5124) +MACHINE_CONFIG_END + +//------------------------------------------------- +// machine_config_additions - return a pointer to +// the device's machine fragment +//------------------------------------------------- + +machine_config_constructor sega315_5124_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( sega315_5124 ); +} + + +void sega315_5378_device::device_reset() +{ + sega315_5124_device::device_reset(); + m_draw_time = DRAW_TIME_GG; +} + +static MACHINE_CONFIG_FRAGMENT( sega315_5378 ) + MCFG_PALETTE_ADD("palette", SEGA315_5378_PALETTE_SIZE) + MCFG_PALETTE_INIT_OWNER(sega315_5378_device, sega315_5378) +MACHINE_CONFIG_END + +//------------------------------------------------- +// machine_config_additions - return a pointer to +// the device's machine fragment +//------------------------------------------------- + +machine_config_constructor sega315_5378_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( sega315_5378 ); +} diff --git a/src/devices/video/315_5124.h b/src/devices/video/315_5124.h new file mode 100644 index 00000000000..409dc2e08a3 --- /dev/null +++ b/src/devices/video/315_5124.h @@ -0,0 +1,255 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol, Enik Land +/************************************************************************* + + sega315_5124.h + + Implementation of Sega VDP chips used in System E, Master System and Game Gear + +**************************************************************************/ + +#ifndef __SEGA315_5124_H__ +#define __SEGA315_5124_H__ + + +/*************************************************************************** + CONSTANTS +***************************************************************************/ + +#define SEGA315_5124_WIDTH 342 /* 342 pixels */ +#define SEGA315_5124_HEIGHT_NTSC 262 /* 262 lines */ +#define SEGA315_5124_HEIGHT_PAL 313 /* 313 lines */ +#define SEGA315_5124_LBORDER_START (9 + 2 + 14 + 8) +#define SEGA315_5124_LBORDER_WIDTH 13 /* 13 pixels */ +#define SEGA315_5124_RBORDER_WIDTH 15 /* 15 pixels */ +#define SEGA315_5124_TBORDER_START (3 + 13) +#define SEGA315_5124_NTSC_192_TBORDER_HEIGHT (0x1b) /* 27 lines */ +//#define SEGA315_5124_NTSC_192_BBORDER_HEIGHT (0x18) /* 24 lines */ +#define SEGA315_5124_NTSC_224_TBORDER_HEIGHT (0x0b) /* 11 lines */ +//#define SEGA315_5124_NTSC_224_BBORDER_HEIGHT (0x08) /* 8 lines */ +//#define SEGA315_5124_PAL_192_TBORDER_HEIGHT (0x36) /* 54 lines */ +//#define SEGA315_5124_PAL_192_BBORDER_HEIGHT (0x30) /* 48 lines */ +//#define SEGA315_5124_PAL_224_TBORDER_HEIGHT (0x26) /* 38 lines */ +//#define SEGA315_5124_PAL_224_BBORDER_HEIGHT (0x20) /* 32 lines */ +#define SEGA315_5124_PAL_240_TBORDER_HEIGHT (0x1e) /* 30 lines */ +//#define SEGA315_5124_PAL_240_BBORDER_HEIGHT (0x18) /* 24 lines */ + + +#define SEGA315_5124_PALETTE_SIZE (64+16) +#define SEGA315_5378_PALETTE_SIZE 4096 + + +#define SEGA315_5378_CRAM_SIZE 0x40 /* 32 colors x 2 bytes per color = 64 bytes */ +#define SEGA315_5124_CRAM_SIZE 0x20 /* 32 colors x 1 bytes per color = 32 bytes */ + +#define VRAM_SIZE 0x4000 + + +/*************************************************************************** + TYPE DEFINITIONS +***************************************************************************/ + +extern const device_type SEGA315_5124; /* aka SMS1 vdp */ +extern const device_type SEGA315_5246; /* aka SMS2 vdp */ +extern const device_type SEGA315_5378; /* aka Gamegear vdp */ + + +class sega315_5124_device : public device_t, + public device_memory_interface, + public device_video_interface +{ +public: + // construction/destruction + sega315_5124_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + sega315_5124_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, UINT8 cram_size, UINT8 palette_offset, bool supports_224_240, const char *shortname, const char *source); + + static void set_signal_type(device_t &device, bool is_pal) { downcast(device).m_is_pal = is_pal; } + + + + template static devcb_base &set_int_callback(device_t &device, _Object object) { return downcast(device).m_int_cb.set_callback(object); } + template static devcb_base &set_pause_callback(device_t &device, _Object object) { return downcast(device).m_pause_cb.set_callback(object); } + + DECLARE_READ8_MEMBER( vram_read ); + DECLARE_WRITE8_MEMBER( vram_write ); + DECLARE_READ8_MEMBER( register_read ); + DECLARE_WRITE8_MEMBER( register_write ); + DECLARE_READ8_MEMBER( vcount_read ); + DECLARE_READ8_MEMBER( hcount_read ); + + DECLARE_PALETTE_INIT( sega315_5124 ); + + void hcount_latch() { hcount_latch_at_hpos( m_screen->hpos() ); }; + void hcount_latch_at_hpos( int hpos ); + void stop_timers(); + + bitmap_rgb32 &get_bitmap() { return m_tmpbitmap; }; + bitmap_ind8 &get_y1_bitmap() { return m_y1_bitmap; }; + + /* update the screen */ + UINT32 screen_update( screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect ); + + virtual void set_sega315_5124_compatibility_mode( bool sega315_5124_compatibility_mode ) { }; + +protected: + void set_display_settings(); + void set_frame_timing(); + virtual void update_palette(); + virtual void cram_write(UINT8 data); + virtual void draw_scanline( int pixel_offset_x, int pixel_plot_y, int line ); + virtual void blit_scanline( int *line_buffer, int *priority_selected, int pixel_offset_x, int pixel_plot_y, int line ); + virtual UINT16 get_name_table_row(int row); + void process_line_timer(); + void select_sprites( int line ); + void draw_scanline_mode4( int *line_buffer, int *priority_selected, int line ); + void draw_sprites_mode4( int *line_buffer, int *priority_selected, int line ); + void draw_sprites_tms9918_mode( int *line_buffer, int line ); + void draw_scanline_mode2( int *line_buffer, int line ); + void draw_scanline_mode0( int *line_buffer, int line ); + void check_pending_flags(); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + virtual machine_config_constructor device_mconfig_additions() const; + + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const { return (spacenum == AS_0) ? &m_space_config : NULL; } + + void vdp_postload(); + + UINT8 m_reg[16]; /* All the registers */ + UINT8 m_status; /* Status register */ + UINT8 m_pending_status; /* Pending status flags */ + UINT8 m_reg8copy; /* Internal copy of register 8 (X-Scroll) */ + UINT8 m_reg9copy; /* Internal copy of register 9 (Y-Scroll) */ + UINT8 m_addrmode; /* Type of VDP action */ + UINT16 m_addr; /* Contents of internal VDP address register */ + UINT8 m_cram_size; /* CRAM size */ + UINT8 m_cram_mask; /* Mask to switch between SMS and GG CRAM sizes */ + int m_cram_dirty; /* Have there been any changes to the CRAM area */ + int m_pending_reg_write; + int m_pending_sprcol_x; + UINT8 m_buffer; + bool m_sega315_5124_compatibility_mode; /* Shrunk SMS screen on GG lcd mode flag */ + int m_irq_state; /* The status of the IRQ line of the VDP */ + int m_vdp_mode; /* Current mode of the VDP: 0,1,2,3,4 */ + int m_y_pixels; /* 192, 224, 240 */ + int m_draw_time; + UINT8 m_line_counter; + UINT8 m_hcounter; + UINT8 m_CRAM[SEGA315_5378_CRAM_SIZE]; /* CRAM */ + const UINT8 *m_frame_timing; + bitmap_rgb32 m_tmpbitmap; + bitmap_ind8 m_y1_bitmap; + UINT8 m_palette_offset; + bool m_supports_224_240; + bool m_display_disabled; + UINT16 m_sprite_base; + UINT16 m_sprite_pattern_line[8]; + int m_sprite_tile_selected[8]; + int m_sprite_x[8]; + UINT8 m_sprite_flags[8]; + int m_sprite_count; + int m_sprite_height; + int m_sprite_zoom; + int m_current_palette[32]; + bool m_is_pal; /* false = NTSC, true = PAL */ + devcb_write_line m_int_cb; /* Interrupt callback function */ + devcb_write_line m_pause_cb; /* Pause callback function */ + emu_timer *m_display_timer; + emu_timer *m_hint_timer; + emu_timer *m_vint_timer; + emu_timer *m_nmi_timer; + emu_timer *m_draw_timer; + emu_timer *m_lborder_timer; + emu_timer *m_rborder_timer; + emu_timer *m_pending_flags_timer; + + const address_space_config m_space_config; + + /* Timers */ + static const device_timer_id TIMER_LINE = 0; + static const device_timer_id TIMER_DRAW = 1; + static const device_timer_id TIMER_LBORDER = 2; + static const device_timer_id TIMER_RBORDER = 3; + static const device_timer_id TIMER_HINT = 4; + static const device_timer_id TIMER_VINT = 5; + static const device_timer_id TIMER_NMI = 6; + static const device_timer_id TIMER_FLAGS = 7; + + required_device m_palette; +}; + + +class sega315_5246_device : public sega315_5124_device +{ +public: + sega315_5246_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual UINT16 get_name_table_row(int row); +}; + + +class sega315_5378_device : public sega315_5124_device +{ +public: + sega315_5378_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + DECLARE_PALETTE_INIT( sega315_5378 ); + + virtual void set_sega315_5124_compatibility_mode( bool sega315_5124_compatibility_mode ); + +protected: + virtual void device_reset(); + virtual machine_config_constructor device_mconfig_additions() const; + + virtual void update_palette(); + virtual void cram_write(UINT8 data); + virtual void blit_scanline( int *line_buffer, int *priority_selected, int pixel_offset_x, int pixel_plot_y, int line ); + virtual UINT16 get_name_table_row(int row); +}; + + +/*************************************************************************** + DEVICE CONFIGURATION MACROS +***************************************************************************/ + +#define MCFG_SEGA315_5124_SET_SCREEN MCFG_VIDEO_SET_SCREEN + +#define MCFG_SEGA315_5124_IS_PAL(_bool) \ + sega315_5124_device::set_signal_type(*device, _bool); + +#define MCFG_SEGA315_5124_INT_CB(_devcb) \ + devcb = &sega315_5124_device::set_int_callback(*device, DEVCB_##_devcb); + +#define MCFG_SEGA315_5124_PAUSE_CB(_devcb) \ + devcb = &sega315_5124_device::set_pause_callback(*device, DEVCB_##_devcb); + + +#define MCFG_SEGA315_5246_SET_SCREEN MCFG_VIDEO_SET_SCREEN + +#define MCFG_SEGA315_5246_IS_PAL(_bool) \ + sega315_5246_device::set_signal_type(*device, _bool); + +#define MCFG_SEGA315_5246_INT_CB(_devcb) \ + devcb = &sega315_5246_device::set_int_callback(*device, DEVCB_##_devcb); + +#define MCFG_SEGA315_5246_PAUSE_CB(_devcb) \ + devcb = &sega315_5246_device::set_pause_callback(*device, DEVCB_##_devcb); + + +#define MCFG_SEGA315_5378_SET_SCREEN MCFG_VIDEO_SET_SCREEN + +#define MCFG_SEGA315_5378_IS_PAL(_bool) \ + sega315_5378_device::set_signal_type(*device, _bool); + +#define MCFG_SEGA315_5378_INT_CB(_devcb) \ + devcb = &sega315_5378_device::set_int_callback(*device, DEVCB_##_devcb); + +#define MCFG_SEGA315_5378_PAUSE_CB(_devcb) \ + devcb = &sega315_5378_device::set_pause_callback(*device, DEVCB_##_devcb); + + +#endif /* __SEGA315_5124_H__ */ diff --git a/src/devices/video/315_5313.c b/src/devices/video/315_5313.c new file mode 100644 index 00000000000..a612c384e99 --- /dev/null +++ b/src/devices/video/315_5313.c @@ -0,0 +1,2776 @@ +// license:BSD-3-Clause +// copyright-holders:David Haywood +/* Sega 315-5313 - Megadrive VDP */ + +#include "emu.h" +#include "video/315_5313.h" + +/* still have dependencies on the following external gunk */ + +#include "sound/sn76496.h" + +#define MAX_HPOSITION 480 + + +const device_type SEGA315_5313 = &device_creator; + +sega315_5313_device::sega315_5313_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : sega315_5124_device(mconfig, SEGA315_5313, "Sega 315-5313 Megadrive VDP", tag, owner, clock, SEGA315_5124_CRAM_SIZE, 0, true, "sega315_5313", __FILE__), + m_sndirqline_callback(*this), + m_lv6irqline_callback(*this), + m_lv4irqline_callback(*this), + m_dma_delay(0) +{ + m_use_alt_timing = 0; + m_palwrite_base = -1; +} + +//------------------------------------------------- +// static_set_palette_tag: Set the tag of the +// palette device +//------------------------------------------------- + +void sega315_5313_device::static_set_palette_tag(device_t &device, const char *tag) +{ + downcast(device).m_palette.set_tag(tag); +} + + +static MACHINE_CONFIG_FRAGMENT( sega_genesis_vdp ) + MCFG_PALETTE_ADD("palette", 0x200) + MCFG_PALETTE_INIT_OWNER(sega315_5124_device, sega315_5124) +MACHINE_CONFIG_END + +//------------------------------------------------- +// machine_config_additions - return a pointer to +// the device's machine fragment +//------------------------------------------------- + +machine_config_constructor sega315_5313_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( sega_genesis_vdp ); +} + +static TIMER_CALLBACK( render_timer_callback ) +{ + sega315_5313_device* vdp = (sega315_5313_device*)ptr; + vdp->render_scanline(); +} + +void sega315_5313_device::vdp_handle_irq6_on_timer_callback(int param) +{ +// m_irq6_pending = 1; + if (MEGADRIVE_REG01_IRQ6_ENABLE) + m_lv6irqline_callback(true); +} + +static TIMER_CALLBACK( irq6_on_timer_callback ) +{ + sega315_5313_device* vdp = (sega315_5313_device*)ptr; + vdp->vdp_handle_irq6_on_timer_callback(param); +} + +void sega315_5313_device::vdp_handle_irq4_on_timer_callback(int param) +{ + m_lv4irqline_callback(true); +} + +static TIMER_CALLBACK( irq4_on_timer_callback ) +{ + sega315_5313_device* vdp = (sega315_5313_device*)ptr; + vdp->vdp_handle_irq4_on_timer_callback(param); +} + + + +void sega315_5313_device::set_alt_timing(device_t &device, int use_alt_timing) +{ + sega315_5313_device &dev = downcast(device); + dev.m_use_alt_timing = use_alt_timing; +} + +void sega315_5313_device::set_palwrite_base(device_t &device, int palwrite_base) +{ + sega315_5313_device &dev = downcast(device); + dev.m_palwrite_base = palwrite_base; +} + + + + +void sega315_5313_device::device_start() +{ + m_sndirqline_callback.resolve_safe(); + m_lv6irqline_callback.resolve_safe(); + m_lv4irqline_callback.resolve_safe(); + + m_32x_scanline_func.bind_relative_to(*owner()); + m_32x_interrupt_func.bind_relative_to(*owner()); + m_32x_scanline_helper_func.bind_relative_to(*owner()); + + m_vram = auto_alloc_array(machine(), UINT16, 0x10000/2); + m_cram = auto_alloc_array(machine(), UINT16, 0x80/2); + m_vsram = auto_alloc_array(machine(), UINT16, 0x80/2); + m_regs = auto_alloc_array(machine(), UINT16, 0x40/2); + m_internal_sprite_attribute_table = auto_alloc_array(machine(), UINT16, 0x400/2); + + memset(m_vram, 0x00, 0x10000); + memset(m_cram, 0x00, 0x80); + memset(m_vsram, 0x00, 0x80); + memset(m_regs, 0x00, 0x40); + memset(m_internal_sprite_attribute_table, 0x00, 0x400); + + + save_pointer(NAME(m_vram), 0x10000/2); + save_pointer(NAME(m_cram), 0x80/2); + save_pointer(NAME(m_vsram), 0x80/2); + save_pointer(NAME(m_regs), 0x40/2); + save_pointer(NAME(m_internal_sprite_attribute_table), 0x400/2); + + save_item(NAME(m_command_pending)); + save_item(NAME(m_command_part1)); + save_item(NAME(m_command_part2)); + save_item(NAME(m_vdp_code)); + save_item(NAME(m_vdp_address)); + save_item(NAME(m_vram_fill_pending)); + save_item(NAME(m_vram_fill_length)); + save_item(NAME(m_irq4counter)); + save_item(NAME(m_imode_odd_frame)); + save_item(NAME(m_sprite_collision)); + save_item(NAME(m_imode)); + save_item(NAME(m_irq6_pending)); + save_item(NAME(m_irq4_pending)); + save_item(NAME(m_visible_scanlines)); + save_item(NAME(m_irq6_scanline)); + save_item(NAME(m_z80irq_scanline)); + save_item(NAME(m_scanline_counter)); + save_item(NAME(m_vblank_flag)); + save_item(NAME(m_total_scanlines)); + + m_sprite_renderline = auto_alloc_array(machine(), UINT8, 1024); + m_highpri_renderline = auto_alloc_array(machine(), UINT8, 320); + m_video_renderline = auto_alloc_array(machine(), UINT32, 320); + + m_palette_lookup = auto_alloc_array(machine(), UINT16, 0x40); + m_palette_lookup_sprite = auto_alloc_array(machine(), UINT16, 0x40); + + m_palette_lookup_shadow = auto_alloc_array(machine(), UINT16, 0x40); + m_palette_lookup_highlight = auto_alloc_array(machine(), UINT16, 0x40); + + memset(m_palette_lookup,0x00,0x40*2); + memset(m_palette_lookup_sprite,0x00,0x40*2); + + memset(m_palette_lookup_shadow,0x00,0x40*2); + memset(m_palette_lookup_highlight,0x00,0x40*2); + + + if (!m_use_alt_timing) + m_render_bitmap = auto_bitmap_ind16_alloc(machine(), 320, 512); // allocate maximum sizes we're going to use, it's safer. + else + m_render_line = auto_alloc_array(machine(), UINT16, 320); + + m_render_line_raw = auto_alloc_array(machine(), UINT16, 320); + + // FIXME: are these all needed? I'm pretty sure some of these (most?) are just helpers which don't need to be saved, + // but better safe than sorry... + save_pointer(NAME(m_sprite_renderline), 1024); + save_pointer(NAME(m_highpri_renderline), 320); + save_pointer(NAME(m_video_renderline), 320/4); + save_pointer(NAME(m_palette_lookup), 0x40); + save_pointer(NAME(m_palette_lookup_sprite), 0x40); + save_pointer(NAME(m_palette_lookup_shadow), 0x40); + save_pointer(NAME(m_palette_lookup_highlight), 0x40); + save_pointer(NAME(m_render_line_raw), 320/2); + if (m_use_alt_timing) + save_pointer(NAME(m_render_line), 320/2); + + m_irq6_on_timer = machine().scheduler().timer_alloc(FUNC(irq6_on_timer_callback), (void*)this); + m_irq4_on_timer = machine().scheduler().timer_alloc(FUNC(irq4_on_timer_callback), (void*)this); + m_render_timer = machine().scheduler().timer_alloc(FUNC(render_timer_callback), (void*)this); + + m_space68k = &machine().device(":maincpu")->space(); + m_cpu68k = machine().device(":maincpu"); + + sega315_5124_device::device_start(); +} + +void sega315_5313_device::device_reset() +{ + m_command_pending = 0; + m_command_part1 = 0; + m_command_part2 = 0; + m_vdp_code = 0; + m_vdp_address = 0; + m_vram_fill_pending = 0; + m_vram_fill_length = 0; + m_irq4counter = -1; + m_imode_odd_frame = 0; + m_sprite_collision = 0; + m_imode = 0; + m_irq6_pending = 0; + m_irq4_pending = 0; + m_scanline_counter = 0; + m_vblank_flag = 0; + m_total_scanlines = 262; + + sega315_5124_device::device_reset(); +} + +void sega315_5313_device::device_reset_old() +{ + // other stuff, are we sure we want to set some of these every reset? + // it's called from machine_reset + m_total_scanlines = 262; + m_visible_scanlines = 224; + m_irq6_scanline = 224; + m_z80irq_scanline = 226; +} + + + +void sega315_5313_device::vdp_vram_write(UINT16 data) +{ + UINT16 sprite_base_address = MEGADRIVE_REG0C_RS1?((MEGADRIVE_REG05_SPRITE_ADDR&0x7e)<<9):((MEGADRIVE_REG05_SPRITE_ADDR&0x7f)<<9); + int spritetable_size = MEGADRIVE_REG0C_RS1?0x400:0x200; + int lowlimit = sprite_base_address; + int highlimit = sprite_base_address+spritetable_size; + + if (m_vdp_address&1) + { + data = ((data&0x00ff)<<8)|((data&0xff00)>>8); + } + + MEGADRIV_VDP_VRAM(m_vdp_address>>1) = data; + + /* The VDP stores an Internal copy of any data written to the Sprite Attribute Table. + This data is _NOT_ invalidated when the Sprite Base Address changes, thus allowing + for some funky effects, as used by Castlevania Bloodlines Stage 6-3 */ + if (m_vdp_address>=lowlimit && m_vdp_address>1] = data; + } + + m_vdp_address+=MEGADRIVE_REG0F_AUTO_INC; + m_vdp_address &= 0xffff; +} + +void sega315_5313_device::vdp_vsram_write(UINT16 data) +{ + m_vsram[(m_vdp_address&0x7e)>>1] = data; + + //logerror("Wrote to VSRAM addr %04x data %04x\n",m_vdp_address&0xfffe,m_vsram[m_vdp_address>>1]); + + m_vdp_address+=MEGADRIVE_REG0F_AUTO_INC; + + m_vdp_address &=0xffff; +} + +void sega315_5313_device::write_cram_value(int offset, int data) +{ + m_cram[offset] = data; + + //logerror("Wrote to CRAM addr %04x data %04x\n",m_vdp_address&0xfffe,m_cram[m_vdp_address>>1]); + if (m_use_cram) + { + int r,g,b; + r = ((data >> 1)&0x07); + g = ((data >> 5)&0x07); + b = ((data >> 9)&0x07); + if (m_palwrite_base != -1) + { + m_palette->set_pen_color(offset + m_palwrite_base ,pal3bit(r),pal3bit(g),pal3bit(b)); + m_palette->set_pen_color(offset + m_palwrite_base + 0x40 ,pal3bit(r>>1),pal3bit(g>>1),pal3bit(b>>1)); + m_palette->set_pen_color(offset + m_palwrite_base + 0x80 ,pal3bit((r>>1)|0x4),pal3bit((g>>1)|0x4),pal3bit((b>>1)|0x4)); + } + m_palette_lookup[offset] = (b<<2) | (g<<7) | (r<<12); + m_palette_lookup_sprite[offset] = (b<<2) | (g<<7) | (r<<12); + m_palette_lookup_shadow[offset] = (b<<1) | (g<<6) | (r<<11); + m_palette_lookup_highlight[offset] = ((b|0x08)<<1) | ((g|0x08)<<6) | ((r|0x08)<<11); + } +} + +void sega315_5313_device::vdp_cram_write(UINT16 data) +{ + int offset; + offset = (m_vdp_address&0x7e)>>1; + + write_cram_value(offset,data); + + m_vdp_address+=MEGADRIVE_REG0F_AUTO_INC; + + m_vdp_address &=0xffff; +} + + +void sega315_5313_device::data_port_w(int data) +{ + m_command_pending = 0; + + /* + 0000b : VRAM read + 0001b : VRAM write + 0011b : CRAM write + 0100b : VSRAM read + 0101b : VSRAM write + 1000b : CRAM read + */ +// logerror("write to vdp data port %04x with code %04x, write address %04x\n",data, m_vdp_code, m_vdp_address ); + + if (m_vram_fill_pending) + { + int count; + + m_vdp_address&=0xffff; + + if (m_vdp_address&1) + { + MEGADRIV_VDP_VRAM((m_vdp_address>>1)) = (MEGADRIV_VDP_VRAM((m_vdp_address>>1))&0xff00) | (data&0x00ff); + } + else + { + MEGADRIV_VDP_VRAM((m_vdp_address>>1)) = (MEGADRIV_VDP_VRAM((m_vdp_address>>1))&0x00ff) | ((data&0x00ff)<<8); + } + + + for (count=0;count<=m_vram_fill_length;count++) // <= for james pond 3 + { + if (m_vdp_address&1) + { + MEGADRIV_VDP_VRAM((m_vdp_address>>1)) = (MEGADRIV_VDP_VRAM((m_vdp_address>>1))&0x00ff) | (data&0xff00); + } + else + { + MEGADRIV_VDP_VRAM((m_vdp_address>>1)) = (MEGADRIV_VDP_VRAM((m_vdp_address>>1))&0xff00) | ((data&0xff00)>>8); + } + + m_vdp_address+=MEGADRIVE_REG0F_AUTO_INC; + m_vdp_address&=0xffff; + + } + + m_regs[0x13] = 0; + m_regs[0x14] = 0; + + // m_regs[0x15] = (source>>1) & 0xff; + // m_regs[0x16] = (source>>9) & 0xff; + // m_regs[0x17] = (source>>17) & 0xff; + + + } + else + { + switch (m_vdp_code & 0x000f) + { + case 0x0000: + logerror("Attempting to WRITE to DATA PORT in VRAM READ MODE\n"); + break; + + case 0x0001: + vdp_vram_write(data); + break; + + case 0x0003: + vdp_cram_write(data); + break; + + case 0x0004: + logerror("Attempting to WRITE to DATA PORT in VSRAM READ MODE\n"); + break; + + case 0x0005: + vdp_vsram_write(data); + break; + + case 0x0008: + logerror("Attempting to WRITE to DATA PORT in CRAM READ MODE\n"); + break; + + default: + logerror("Attempting to WRITE to DATA PORT in #UNDEFINED# MODE %1x %04x\n",m_vdp_code&0xf, data); + break; + } + } + + + +} + + + +void sega315_5313_device::vdp_set_register(int regnum, UINT8 value) +{ + m_regs[regnum] = value; + + /* We need special handling for the IRQ enable registers, some games turn + off the irqs before they are taken, delaying them until the IRQ is turned + back on */ + + if (regnum == 0x00) + { + //osd_printf_debug("setting reg 0, irq enable is now %d\n",MEGADRIVE_REG0_IRQ4_ENABLE); + + if (m_irq4_pending) + { + if (MEGADRIVE_REG0_IRQ4_ENABLE) + m_lv4irqline_callback(true); + else + m_lv4irqline_callback(false); + } + + /* ??? Fatal Rewind needs this but I'm not sure it's accurate behavior + it causes flickering in roadrash */ + // m_irq6_pending = 0; + // m_irq4_pending = 0; + + } + + if (regnum == 0x01) + { + if (m_irq6_pending) + { + if (MEGADRIVE_REG01_IRQ6_ENABLE ) + m_lv6irqline_callback(true); + else + m_lv6irqline_callback(false); + + } + + /* ??? */ + // m_irq6_pending = 0; + // m_irq4_pending = 0; + + } + + +// if (regnum == 0x0a) +// osd_printf_debug("Set HINT Reload Register to %d on scanline %d\n",value, get_scanline_counter()); + +// osd_printf_debug("%s: Setting VDP Register #%02x to %02x\n",machine().describe_context(), regnum,value); +} + +void sega315_5313_device::update_code_and_address(void) +{ + m_vdp_code = ((m_command_part1 & 0xc000) >> 14) | + ((m_command_part2 & 0x00f0) >> 2); + + m_vdp_address = ((m_command_part1 & 0x3fff) >> 0) | + ((m_command_part2 & 0x0003) << 14); +} + +// if either SVP CPU or segaCD is present, there is a 'lag' we have to compensate for +// hence, for segacd and svp we set m_dma_delay to the appropriate value at start +inline UINT16 sega315_5313_device::vdp_get_word_from_68k_mem(UINT32 source) +{ + // should we limit the valid areas here? + // how does this behave with the segacd etc? + // note, the RV bit on 32x is important for this to work, because it causes a normal cart mapping - see tempo + + //printf("vdp_get_word_from_68k_mem_default %08x\n", source); + + if (source <= 0x3fffff) + return m_space68k->read_word(source - m_dma_delay); // compensate DMA lag + else if ((source >= 0xe00000) && (source <= 0xffffff)) + return m_space68k->read_word(source); + else + { + printf("DMA Read unmapped %06x\n",source); + return machine().rand(); + } +} + +/* Table from Charles Macdonald + + + DMA Mode Width Display Transfer Count + ----------------------------------------------------- + 68K > VDP 32-cell Active 16 + Blanking 167 + 40-cell Active 18 + Blanking 205 + VRAM Fill 32-cell Active 15 + Blanking 166 + 40-cell Active 17 + Blanking 204 + VRAM Copy 32-cell Active 8 + Blanking 83 + 40-cell Active 9 + Blanking 102 + +*/ + + +/* Note, In reality this transfer is NOT instant, the 68k isn't paused + as the 68k address bus isn't accessed */ + +/* Wani Wani World, James Pond 3, Pirates Gold! */ +void sega315_5313_device::insta_vram_copy(UINT32 source, UINT16 length) +{ + int x; + + for (x=0;x>1)&0x00ff; + else source_byte = (MEGADRIV_VDP_VRAM((source&0xffff)>>1)&0xff00)>>8; + + if (m_vdp_address&1) + { + MEGADRIV_VDP_VRAM((m_vdp_address&0xffff)>>1) = (MEGADRIV_VDP_VRAM((m_vdp_address&0xffff)>>1)&0xff00) | source_byte; + } + else + { + MEGADRIV_VDP_VRAM((m_vdp_address&0xffff)>>1) = (MEGADRIV_VDP_VRAM((m_vdp_address&0xffff)>>1)&0x00ff) | (source_byte<<8); + } + + source++; + m_vdp_address+=MEGADRIVE_REG0F_AUTO_INC; + m_vdp_address&=0xffff; + } +} + +/* Instant, but we pause the 68k a bit */ +void sega315_5313_device::insta_68k_to_vram_dma(UINT32 source,int length) +{ + int count; + + if (length==0x00) length = 0xffff; + + /* This is a hack until real DMA timings are implemented */ + m_cpu68k->spin_until_time(attotime::from_nsec(length * 1000 / 3500)); + + for (count = 0;count<(length>>1);count++) + { + vdp_vram_write(vdp_get_word_from_68k_mem(source)); + source+=2; + if (source>0xffffff) source = 0xe00000; + } + + m_vdp_address&=0xffff; + + m_regs[0x13] = 0; + m_regs[0x14] = 0; + + m_regs[0x15] = (source>>1) & 0xff; + m_regs[0x16] = (source>>9) & 0xff; + m_regs[0x17] = (source>>17) & 0xff; +} + + +void sega315_5313_device::insta_68k_to_cram_dma(UINT32 source,UINT16 length) +{ + int count; + + if (length==0x00) length = 0xffff; + + for (count = 0;count<(length>>1);count++) + { + //if (m_vdp_address>=0x80) return; // abandon + + write_cram_value((m_vdp_address&0x7e)>>1, vdp_get_word_from_68k_mem(source)); + source+=2; + + if (source>0xffffff) source = 0xfe0000; + + m_vdp_address+=MEGADRIVE_REG0F_AUTO_INC; + m_vdp_address&=0xffff; + } + + m_regs[0x13] = 0; + m_regs[0x14] = 0; + + m_regs[0x15] = (source>>1) & 0xff; + m_regs[0x16] = (source>>9) & 0xff; + m_regs[0x17] = (source>>17) & 0xff; + +} + +void sega315_5313_device::insta_68k_to_vsram_dma(UINT32 source,UINT16 length) +{ + int count; + + if (length==0x00) length = 0xffff; + + for (count = 0;count<(length>>1);count++) + { + if (m_vdp_address>=0x80) return; // abandon + + m_vsram[(m_vdp_address&0x7e)>>1] = vdp_get_word_from_68k_mem(source); + source+=2; + + if (source>0xffffff) source = 0xfe0000; + + m_vdp_address+=MEGADRIVE_REG0F_AUTO_INC; + m_vdp_address&=0xffff; + } + + m_regs[0x13] = 0; + m_regs[0x14] = 0; + + m_regs[0x15] = (source>>1) & 0xff; + m_regs[0x16] = (source>>9) & 0xff; + m_regs[0x17] = (source>>17) & 0xff; +} + +/* This can be simplified quite a lot.. */ +void sega315_5313_device::handle_dma_bits() +{ +#if 0 + if (m_vdp_code&0x20) + { + UINT32 source; + UINT16 length; + source = (MEGADRIVE_REG15_DMASOURCE1 | (MEGADRIVE_REG16_DMASOURCE2<<8) | ((MEGADRIVE_REG17_DMASOURCE3&0xff)<<16))<<1; + length = (MEGADRIVE_REG13_DMALENGTH1 | (MEGADRIVE_REG14_DMALENGTH2<<8))<<1; + osd_printf_debug("%s 68k DMAtran set source %06x length %04x dest %04x enabled %01x code %02x %02x\n", machine().describe_context(), source, length, m_vdp_address,MEGADRIVE_REG01_DMA_ENABLE, m_vdp_code,MEGADRIVE_REG0F_AUTO_INC); + } +#endif + if (m_vdp_code==0x20) + { + osd_printf_debug("DMA bit set 0x20 but invalid??\n"); + } + else if (m_vdp_code==0x21 || m_vdp_code==0x31) /* 0x31 used by tecmo cup */ + { + if (MEGADRIVE_REG17_DMATYPE==0x0 || MEGADRIVE_REG17_DMATYPE==0x1) + { + UINT32 source; + UINT16 length; + source = (MEGADRIVE_REG15_DMASOURCE1 | (MEGADRIVE_REG16_DMASOURCE2<<8) | ((MEGADRIVE_REG17_DMASOURCE3&0x7f)<<16))<<1; + length = (MEGADRIVE_REG13_DMALENGTH1 | (MEGADRIVE_REG14_DMALENGTH2<<8))<<1; + + /* The 68k is frozen during this transfer, it should be safe to throw a few cycles away and do 'instant' DMA because the 68k can't detect it being in progress (can the z80?) */ + //osd_printf_debug("68k->VRAM DMA transfer source %06x length %04x dest %04x enabled %01x\n", source, length, m_vdp_address,MEGADRIVE_REG01_DMA_ENABLE); + if (MEGADRIVE_REG01_DMA_ENABLE) insta_68k_to_vram_dma(source,length); + + } + else if (MEGADRIVE_REG17_DMATYPE==0x2) + { + //osd_printf_debug("vram fill length %02x %02x other regs! %02x %02x %02x(Mode Bits %02x) Enable %02x\n", MEGADRIVE_REG13_DMALENGTH1, MEGADRIVE_REG14_DMALENGTH2, MEGADRIVE_REG15_DMASOURCE1, MEGADRIVE_REG16_DMASOURCE2, MEGADRIVE_REG17_DMASOURCE3, MEGADRIVE_REG17_DMATYPE, MEGADRIVE_REG01_DMA_ENABLE); + if (MEGADRIVE_REG01_DMA_ENABLE) + { + m_vram_fill_pending = 1; + m_vram_fill_length = (MEGADRIVE_REG13_DMALENGTH1 | (MEGADRIVE_REG14_DMALENGTH2<<8)); + } + } + else if (MEGADRIVE_REG17_DMATYPE==0x3) + { + UINT32 source; + UINT16 length; + source = (MEGADRIVE_REG15_DMASOURCE1 | (MEGADRIVE_REG16_DMASOURCE2<<8)); // source (byte offset) + length = (MEGADRIVE_REG13_DMALENGTH1 | (MEGADRIVE_REG14_DMALENGTH2<<8)); // length in bytes + //osd_printf_debug("setting vram copy mode length registers are %02x %02x other regs! %02x %02x %02x(Mode Bits %02x) Enable %02x\n", MEGADRIVE_REG13_DMALENGTH1, MEGADRIVE_REG14_DMALENGTH2, MEGADRIVE_REG15_DMASOURCE1, MEGADRIVE_REG16_DMASOURCE2, MEGADRIVE_REG17_DMASOURCE3, MEGADRIVE_REG17_DMATYPE, MEGADRIVE_REG01_DMA_ENABLE); + + if (MEGADRIVE_REG01_DMA_ENABLE) insta_vram_copy(source, length); + } + } + else if (m_vdp_code==0x23) + { + if (MEGADRIVE_REG17_DMATYPE==0x0 || MEGADRIVE_REG17_DMATYPE==0x1) + { + UINT32 source; + UINT16 length; + source = (MEGADRIVE_REG15_DMASOURCE1 | (MEGADRIVE_REG16_DMASOURCE2<<8) | ((MEGADRIVE_REG17_DMASOURCE3&0x7f)<<16))<<1; + length = (MEGADRIVE_REG13_DMALENGTH1 | (MEGADRIVE_REG14_DMALENGTH2<<8))<<1; + + /* The 68k is frozen during this transfer, it should be safe to throw a few cycles away and do 'instant' DMA because the 68k can't detect it being in progress (can the z80?) */ + //osd_printf_debug("68k->CRAM DMA transfer source %06x length %04x dest %04x enabled %01x\n", source, length, m_vdp_address,MEGADRIVE_REG01_DMA_ENABLE); + if (MEGADRIVE_REG01_DMA_ENABLE) insta_68k_to_cram_dma(source,length); + } + else if (MEGADRIVE_REG17_DMATYPE==0x2) + { + //osd_printf_debug("vram fill length %02x %02x other regs! %02x %02x %02x(Mode Bits %02x) Enable %02x\n", MEGADRIVE_REG13_DMALENGTH1, MEGADRIVE_REG14_DMALENGTH2, MEGADRIVE_REG15_DMASOURCE1, MEGADRIVE_REG16_DMASOURCE2, MEGADRIVE_REG17_DMASOURCE3, MEGADRIVE_REG17_DMATYPE, MEGADRIVE_REG01_DMA_ENABLE); + if (MEGADRIVE_REG01_DMA_ENABLE) + { + m_vram_fill_pending = 1; + m_vram_fill_length = (MEGADRIVE_REG13_DMALENGTH1 | (MEGADRIVE_REG14_DMALENGTH2<<8)); + } + } + else if (MEGADRIVE_REG17_DMATYPE==0x3) + { + osd_printf_debug("setting vram copy (INVALID?) mode length registers are %02x %02x other regs! %02x %02x %02x(Mode Bits %02x) Enable %02x\n", MEGADRIVE_REG13_DMALENGTH1, MEGADRIVE_REG14_DMALENGTH2, MEGADRIVE_REG15_DMASOURCE1, MEGADRIVE_REG16_DMASOURCE2, MEGADRIVE_REG17_DMASOURCE3, MEGADRIVE_REG17_DMATYPE, MEGADRIVE_REG01_DMA_ENABLE); + } + } + else if (m_vdp_code==0x25) + { + if (MEGADRIVE_REG17_DMATYPE==0x0 || MEGADRIVE_REG17_DMATYPE==0x1) + { + UINT32 source; + UINT16 length; + source = (MEGADRIVE_REG15_DMASOURCE1 | (MEGADRIVE_REG16_DMASOURCE2<<8) | ((MEGADRIVE_REG17_DMASOURCE3&0x7f)<<16))<<1; + length = (MEGADRIVE_REG13_DMALENGTH1 | (MEGADRIVE_REG14_DMALENGTH2<<8))<<1; + + /* The 68k is frozen during this transfer, it should be safe to throw a few cycles away and do 'instant' DMA because the 68k can't detect it being in progress (can the z80?) */ + //osd_printf_debug("68k->VSRAM DMA transfer source %06x length %04x dest %04x enabled %01x\n", source, length, m_vdp_address,MEGADRIVE_REG01_DMA_ENABLE); + if (MEGADRIVE_REG01_DMA_ENABLE) insta_68k_to_vsram_dma(source,length); + } + else if (MEGADRIVE_REG17_DMATYPE==0x2) + { + //osd_printf_debug("vram fill length %02x %02x other regs! %02x %02x %02x(Mode Bits %02x) Enable %02x\n", MEGADRIVE_REG13_DMALENGTH1, MEGADRIVE_REG14_DMALENGTH2, MEGADRIVE_REG15_DMASOURCE1, MEGADRIVE_REG16_DMASOURCE2, MEGADRIVE_REG17_DMASOURCE3, MEGADRIVE_REG17_DMATYPE, MEGADRIVE_REG01_DMA_ENABLE); + if (MEGADRIVE_REG01_DMA_ENABLE) + { + m_vram_fill_pending = 1; + m_vram_fill_length = (MEGADRIVE_REG13_DMALENGTH1 | (MEGADRIVE_REG14_DMALENGTH2<<8)); + } + } + else if (MEGADRIVE_REG17_DMATYPE==0x3) + { + osd_printf_debug("setting vram copy (INVALID?) mode length registers are %02x %02x other regs! %02x %02x %02x(Mode Bits %02x) Enable %02x\n", MEGADRIVE_REG13_DMALENGTH1, MEGADRIVE_REG14_DMALENGTH2, MEGADRIVE_REG15_DMASOURCE1, MEGADRIVE_REG16_DMASOURCE2, MEGADRIVE_REG17_DMASOURCE3, MEGADRIVE_REG17_DMATYPE, MEGADRIVE_REG01_DMA_ENABLE); + } + } + else if (m_vdp_code==0x30) + { + if (MEGADRIVE_REG17_DMATYPE==0x0) + { + osd_printf_debug("setting vram 68k->vram (INVALID?) mode length registers are %02x %02x other regs! %02x %02x %02x(Mode Bits %02x) Enable %02x\n", MEGADRIVE_REG13_DMALENGTH1, MEGADRIVE_REG14_DMALENGTH2, MEGADRIVE_REG15_DMASOURCE1, MEGADRIVE_REG16_DMASOURCE2, MEGADRIVE_REG17_DMASOURCE3, MEGADRIVE_REG17_DMATYPE, MEGADRIVE_REG01_DMA_ENABLE); + } + else if (MEGADRIVE_REG17_DMATYPE==0x1) + { + osd_printf_debug("setting vram 68k->vram (INVALID?) mode length registers are %02x %02x other regs! %02x %02x %02x(Mode Bits %02x) Enable %02x\n", MEGADRIVE_REG13_DMALENGTH1, MEGADRIVE_REG14_DMALENGTH2, MEGADRIVE_REG15_DMASOURCE1, MEGADRIVE_REG16_DMASOURCE2, MEGADRIVE_REG17_DMASOURCE3, MEGADRIVE_REG17_DMATYPE, MEGADRIVE_REG01_DMA_ENABLE); + } + else if (MEGADRIVE_REG17_DMATYPE==0x2) + { + osd_printf_debug("setting vram fill (INVALID?) mode length registers are %02x %02x other regs! %02x %02x %02x(Mode Bits %02x) Enable %02x\n", MEGADRIVE_REG13_DMALENGTH1, MEGADRIVE_REG14_DMALENGTH2, MEGADRIVE_REG15_DMASOURCE1, MEGADRIVE_REG16_DMASOURCE2, MEGADRIVE_REG17_DMASOURCE3, MEGADRIVE_REG17_DMATYPE, MEGADRIVE_REG01_DMA_ENABLE); + } + else if (MEGADRIVE_REG17_DMATYPE==0x3) + { + UINT32 source; + UINT16 length; + source = (MEGADRIVE_REG15_DMASOURCE1 | (MEGADRIVE_REG16_DMASOURCE2<<8)); // source (byte offset) + length = (MEGADRIVE_REG13_DMALENGTH1 | (MEGADRIVE_REG14_DMALENGTH2<<8)); // length in bytes + //osd_printf_debug("setting vram copy mode length registers are %02x %02x other regs! %02x %02x %02x(Mode Bits %02x) Enable %02x\n", MEGADRIVE_REG13_DMALENGTH1, MEGADRIVE_REG14_DMALENGTH2, MEGADRIVE_REG15_DMASOURCE1, MEGADRIVE_REG16_DMASOURCE2, MEGADRIVE_REG17_DMASOURCE3, MEGADRIVE_REG17_DMATYPE, MEGADRIVE_REG01_DMA_ENABLE); + + if (MEGADRIVE_REG01_DMA_ENABLE) insta_vram_copy(source, length); + } + } +} + +void sega315_5313_device::ctrl_port_w(int data) +{ +// logerror("write to vdp control port %04x\n",data); + m_vram_fill_pending = 0; // ?? + + if (m_command_pending) + { + /* 2nd part of 32-bit command */ + m_command_pending = 0; + m_command_part2 = data; + + update_code_and_address(); + handle_dma_bits(); + + //logerror("VDP Write Part 2 setting Code %02x Address %04x\n",m_vdp_code, m_vdp_address); + + } + else + { + if ((data & 0xc000) == 0x8000) + { /* Register Setting Command */ + int regnum = (data & 0x3f00) >> 8; + int value = (data & 0x00ff); + + if (regnum &0x20) osd_printf_debug("reg error\n"); + + vdp_set_register(regnum & 0x1f, value); + m_vdp_code = 0; + m_vdp_address = 0; + } + else + { + m_command_pending = 1; + m_command_part1 = data; + update_code_and_address(); + //logerror("VDP Write Part 1 setting Code %02x Address %04x\n",m_vdp_code, m_vdp_address); + } + + } +} + +WRITE16_MEMBER( sega315_5313_device::vdp_w ) +{ + switch (offset<<1) + { + case 0x00: + case 0x02: + if (!ACCESSING_BITS_8_15) + { + data = (data&0x00ff) | data<<8; + // osd_printf_debug("8-bit write VDP data port access, offset %04x data %04x mem_mask %04x\n",offset,data,mem_mask); + } + else if (!ACCESSING_BITS_0_7) + { + data = (data&0xff00) | data>>8; + // osd_printf_debug("8-bit write VDP data port access, offset %04x data %04x mem_mask %04x\n",offset,data,mem_mask); + } + data_port_w(data); + break; + + case 0x04: + case 0x06: + if ((!ACCESSING_BITS_8_15) || (!ACCESSING_BITS_0_7)) osd_printf_debug("8-bit write VDP control port access, offset %04x data %04x mem_mask %04x\n",offset,data,mem_mask); + ctrl_port_w(data); + break; + + case 0x08: + case 0x0a: + case 0x0c: + case 0x0e: + logerror("Attempt to Write to HV counters!!\n"); + break; + + case 0x10: + case 0x12: + case 0x14: + case 0x16: + { + // accessed by either segapsg_device or sn76496_device + sn76496_base_device *sn = machine().device(":snsnd"); + if (ACCESSING_BITS_0_7) sn->write(space, 0, data & 0xff); + //if (ACCESSING_BITS_8_15) sn->write(space, 0, (data>>8) & 0xff); + break; + } + + default: + osd_printf_debug("write to unmapped vdp port\n"); + } +} + +UINT16 sega315_5313_device::vdp_vram_r(void) +{ + return MEGADRIV_VDP_VRAM((m_vdp_address&0xfffe)>>1); +} + +UINT16 sega315_5313_device::vdp_vsram_r(void) +{ + return m_vsram[(m_vdp_address&0x7e)>>1]; +} + +UINT16 sega315_5313_device::vdp_cram_r(void) +{ + return m_cram[(m_vdp_address&0x7e)>>1]; +} + +UINT16 sega315_5313_device::data_port_r() +{ + UINT16 retdata=0; + + //return machine().rand(); + + m_command_pending = 0; + + switch (m_vdp_code & 0x000f) + { + case 0x0000: + retdata = vdp_vram_r(); + m_vdp_address+=MEGADRIVE_REG0F_AUTO_INC; + m_vdp_address&=0xffff; + break; + + case 0x0001: + logerror("Attempting to READ from DATA PORT in VRAM WRITE MODE\n"); + retdata = machine().rand(); + break; + + case 0x0003: + logerror("Attempting to READ from DATA PORT in CRAM WRITE MODE\n"); + retdata = machine().rand(); + break; + + case 0x0004: + retdata = vdp_vsram_r(); + m_vdp_address+=MEGADRIVE_REG0F_AUTO_INC; + m_vdp_address&=0xffff; + break; + + case 0x0005: + logerror("Attempting to READ from DATA PORT in VSRAM WRITE MODE\n"); + break; + + case 0x0008: + retdata = vdp_cram_r(); + m_vdp_address+=MEGADRIVE_REG0F_AUTO_INC; + m_vdp_address&=0xffff; + break; + + default: + logerror("Attempting to READ from DATA PORT in #UNDEFINED# MODE\n"); + retdata = machine().rand(); + break; + } + +// osd_printf_debug("vdp_data_port_r %04x %04x %04x\n",m_vdp_code, m_vdp_address, retdata); + +// logerror("Read VDP Data Port\n"); + return retdata; +} + +/* + + NTSC, 256x224 + ------------- + + Lines Description + + 224 Active display + 8 Bottom border + 3 Bottom blanking + 3 Vertical blanking + 13 Top blanking + 11 Top border + + V counter values + 00-EA, E5-FF + +PAL, 256x224 + ------------ + + Lines Description + + 224 Active display + 32 Bottom border + 3 Bottom blanking + 3 Vertical blanking + 13 Top blanking + 38 Top border + + V counter values + 00-FF, 00-02, CA-FF + + PAL, 256x240 + ------------ + + Lines Description + + 240 Active display + 24 Bottom border + 3 Bottom blanking + 3 Vertical blanking + 13 Top blanking + 30 Top border + + V counter values + 00-FF, 00-0A, D2-FF + + + + Pixels H.Cnt Description + 256 : 00-7F : Active display + 15 : 80-87 : Right border + 8 : 87-8B : Right blanking + 26 : 8B-ED : Horizontal sync + 2 : ED-EE : Left blanking + 14 : EE-F5 : Color burst + 8 : F5-F9 : Left blanking + 13 : F9-FF : Left border + +*/ + + + +UINT16 sega315_5313_device::ctrl_port_r() +{ + /* Battletoads is very fussy about the vblank flag + it wants it to be 1. in scanline 224 */ + + /* Double Dragon 2 is very sensitive to hblank timing */ + /* xperts is very fussy too */ + + /* Game no Kanzume Otokuyou (J) [!] is also fussy + - it cares about the bits labeled always 0, always 1.. (!) + */ + + /* Megalo Mania also fussy - cares about pending flag*/ + + int sprite_overflow = 0; + int odd_frame = m_imode_odd_frame^1; + int hblank_flag = 0; + int dma_active = 0; + int vblank = m_vblank_flag; + int fifo_empty = 1; + int fifo_full = 0; + + UINT16 hpos = get_hposition(); + + if (hpos>400) hblank_flag = 1; + if (hpos>460) hblank_flag = 0; + + /* extra case */ + if (MEGADRIVE_REG01_DISP_ENABLE==0) vblank = 1; + +/* + +// these aren't *always* 0/1 some of them are open bus return + d15 - Always 0 + d14 - Always 0 + d13 - Always 1 + d12 - Always 1 + + d11 - Always 0 + d10 - Always 1 + d9 - FIFO Empty + d8 - FIFO Full + + d7 - Vertical interrupt pending + d6 - Sprite overflow on current scan line + d5 - Sprite collision + d4 - Odd frame + + d3 - Vertical blanking + d2 - Horizontal blanking + d1 - DMA in progress + d0 - PAL mode flag +*/ + + return (0<<15) | // ALWAYS 0 + (0<<14) | // ALWAYS 0 + (1<<13) | // ALWAYS 1 + (1<<12) | // ALWAYS 1 + (0<<11) | // ALWAYS 0 + (1<<10) | // ALWAYS 1 + (fifo_empty<<9 ) | // FIFO EMPTY + (fifo_full<<8 ) | // FIFO FULL + (m_irq6_pending << 7) | // exmutants has a tight loop checking this .. + (sprite_overflow << 6) | + (m_sprite_collision << 5) | + (odd_frame << 4) | + (vblank << 3) | + (hblank_flag << 2) | + (dma_active << 1 ) | + (m_vdp_pal << 0); // PAL MODE FLAG checked by striker for region prot.. +} + +static const UINT8 vc_ntsc_224[] = +{ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, + 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, + 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, + 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, + 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,/**/0xe5, 0xe6, 0xe7, 0xe8, 0xe9, + 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, + 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff +}; + +static const UINT8 vc_ntsc_240[] = +{ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, + 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, + 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, + 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, + 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05 +}; + +static const UINT8 vc_pal_224[] = +{ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, + 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, + 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, + 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, + 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, + 0x00, 0x01, 0x02,/**/0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, + 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, + 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, + 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff +}; + +static const UINT8 vc_pal_240[] = +{ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, + 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, + 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, + 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, + 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,/**/0xd2, 0xd3, 0xd4, 0xd5, 0xd6, + 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, + 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, + 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff +}; + + +UINT16 sega315_5313_device::get_hposition() +{ + UINT16 value4; + + if (!m_use_alt_timing) + { + attotime time_elapsed_since_megadriv_scanline_timer; + + time_elapsed_since_megadriv_scanline_timer = m_megadriv_scanline_timer->time_elapsed(); + + if (time_elapsed_since_megadriv_scanline_timer.attoseconds() < (ATTOSECONDS_PER_SECOND/m_framerate /m_total_scanlines)) + { + value4 = (UINT16)(MAX_HPOSITION*((double)(time_elapsed_since_megadriv_scanline_timer.attoseconds()) / (double)(ATTOSECONDS_PER_SECOND/m_framerate /m_total_scanlines))); + } + else /* in some cases (probably due to rounding errors) we get some stupid results (the odd huge value where the time elapsed is much higher than the scanline time??!).. hopefully by clamping the result to the maximum we limit errors */ + { + value4 = MAX_HPOSITION; + } + + } + else + { + value4 = m_screen->hpos(); + } + + return value4; +} + +int sega315_5313_device::get_scanline_counter() +{ + if (!m_use_alt_timing) + return m_scanline_counter; + else + return m_screen->vpos(); +} + + +UINT16 sega315_5313_device::megadriv_read_hv_counters() +{ + /* Bubble and Squeek wants vcount=0xe0 */ + /* Dracula is very sensitive to this */ + /* Marvel Land is sensitive to this */ + + int vpos = get_scanline_counter(); + UINT16 hpos = get_hposition(); + +// if (hpos>424) vpos++; // fixes dracula, breaks road rash + if (hpos>460) vpos++; // when does vpos increase.. also on sms, check game gear manual.. + + /* shouldn't happen.. */ + if (vpos<0) + { + vpos = m_total_scanlines; + osd_printf_debug("negative vpos?!\n"); + } + + if (MEGADRIVE_REG01_240_LINE) + { + assert(vpos % m_total_scanlines < (m_vdp_pal ? sizeof(vc_pal_240) : sizeof(vc_ntsc_240))); + vpos = m_vdp_pal ? vc_pal_240[vpos % m_total_scanlines] : vc_ntsc_240[vpos % m_total_scanlines]; + } + else + { + assert(vpos % m_total_scanlines < (m_vdp_pal ? sizeof(vc_pal_224) : sizeof(vc_ntsc_224))); + vpos = m_vdp_pal ? vc_pal_224[vpos % m_total_scanlines] : vc_ntsc_224[vpos % m_total_scanlines]; + } + + if (hpos>0xf7) hpos -=0x49; + + return ((vpos&0xff)<<8)|(hpos&0xff); + +} + +READ16_MEMBER( sega315_5313_device::vdp_r ) +{ + UINT16 retvalue = 0; + + + + switch (offset<<1) + { + case 0x00: + case 0x02: + if ((!ACCESSING_BITS_8_15) || (!ACCESSING_BITS_0_7)) osd_printf_debug("8-bit VDP read data port access, offset %04x mem_mask %04x\n",offset,mem_mask); + retvalue = data_port_r(); + break; + + case 0x04: + case 0x06: + // if ((!ACCESSING_BITS_8_15) || (!ACCESSING_BITS_0_7)) osd_printf_debug("8-bit VDP read control port access, offset %04x mem_mask %04x\n",offset,mem_mask); + retvalue = ctrl_port_r(); + // retvalue = machine().rand(); + // osd_printf_debug("%06x: Read Control Port at scanline %d hpos %d (return %04x)\n",space.device().safe_pc(),get_scanline_counter(), get_hposition(),retvalue); + break; + + case 0x08: + case 0x0a: + case 0x0c: + case 0x0e: + // if ((!ACCESSING_BITS_8_15) || (!ACCESSING_BITS_0_7)) osd_printf_debug("8-bit VDP read HV counter port access, offset %04x mem_mask %04x\n",offset,mem_mask); + retvalue = megadriv_read_hv_counters(); + // retvalue = machine().rand(); + // osd_printf_debug("%06x: Read HV counters at scanline %d hpos %d (return %04x)\n",space.device().safe_pc(),get_scanline_counter(), get_hposition(),retvalue); + break; + + case 0x10: + case 0x12: + case 0x14: + case 0x16: + logerror("Attempting to read PSG!\n"); + retvalue = 0; + break; + } + return retvalue; +} + + + +// line length = 342 + +/* + The V counter counts up from 00h to EAh, then it jumps back to E5h and + continues counting up to FFh. This allows it to cover the entire 262 line + display. + + The H counter counts up from 00h to E9h, then it jumps back to 93h and + continues counting up to FFh. This allows it to cover an entire 342 pixel + line. +*/ + +/* + + - The 80th sprite has been drawn in 40-cell mode. + - The 64th sprite has been drawn in 32-cell mode. + - Twenty sprites on the same scanline have been drawn in 40 cell mode. + - Sixteen sprites on the same scanline have been drawn in 32 cell mode. + - 320 pixels worth of sprite data has been drawn on the same scanline + in 40 cell mode. + - 256 pixels worth of sprite data has been drawn on the same scanline + in 32 cell mode. + - The currently drawn sprite has a link field of zero. + +*/ + +/* + + $05 - Sprite Attribute Table Base Address + ----------------------------------------- + + Bits 6-0 of this register correspond to bits A15-A09 of the sprite + attribute table. + + In 40-cell mode, A09 is always forced to zero. + +*/ + +void sega315_5313_device::render_spriteline_to_spritebuffer(int scanline) +{ + int screenwidth; + int maxsprites=0; + int maxpixels=0; + UINT16 base_address=0; + + + + screenwidth = MEGADRIVE_REG0C_RS0 | (MEGADRIVE_REG0C_RS1 << 1); + + switch (screenwidth&3) + { + case 0: maxsprites = 64; maxpixels = 256; base_address = (MEGADRIVE_REG05_SPRITE_ADDR&0x7f)<<9; break; + case 1: maxsprites = 64; maxpixels = 256; base_address = (MEGADRIVE_REG05_SPRITE_ADDR&0x7f)<<9; break; + case 2: maxsprites = 80; maxpixels = 320; base_address = (MEGADRIVE_REG05_SPRITE_ADDR&0x7e)<<9; break; + case 3: maxsprites = 80; maxpixels = 320; base_address = (MEGADRIVE_REG05_SPRITE_ADDR&0x7e)<<9; break; + } + + + /* Clear our Render Buffer */ + memset(m_sprite_renderline, 0, 1024); + + + { + int spritenum; + int ypos,xpos,addr; + int drawypos; + int /*drawwidth,*/ drawheight; + int spritemask = 0; + UINT8 height,width=0,link=0,xflip,yflip,colour,pri; + + /* Get Sprite Attribs */ + spritenum = 0; + + //if (scanline==40) osd_printf_debug("spritelist start base %04x\n",base_address); + + do + { + //UINT16 value1,value2,value3,value4; + + //value1 = m_vram[((base_address>>1)+spritenum*4)+0x0]; + //value2 = m_vram[((base_address>>1)+spritenum*4)+0x1]; + //value3 = m_vram[((base_address>>1)+spritenum*4)+0x2]; + //value4 = m_vram[((base_address>>1)+spritenum*4)+0x3]; + + ypos = (m_internal_sprite_attribute_table[(spritenum*4)+0x0] & 0x01ff)>>0; /* 0x03ff? */ // puyo puyo requires 0x1ff mask, not 0x3ff, see speech bubble corners + height= (m_internal_sprite_attribute_table[(spritenum*4)+0x1] & 0x0300)>>8; + width = (m_internal_sprite_attribute_table[(spritenum*4)+0x1] & 0x0c00)>>10; + link = (m_internal_sprite_attribute_table[(spritenum*4)+0x1] & 0x007f)>>0; + xpos = (MEGADRIV_VDP_VRAM(((base_address>>1)+spritenum*4)+0x3) & 0x01ff)>>0; /* 0x03ff? */ // pirates gold has a sprite with co-ord 0x200... + + if(m_imode == 3) + { + ypos = (m_internal_sprite_attribute_table[(spritenum*4)+0x0] & 0x03ff)>>0; /* 0x3ff requried in interlace mode (sonic 2 2 player) */ + drawypos = ypos - 256; + drawheight = (height+1)*16; + } + else + { + ypos = (m_internal_sprite_attribute_table[(spritenum*4)+0x0] & 0x01ff)>>0; /* 0x03ff? */ // puyo puyo requires 0x1ff mask, not 0x3ff, see speech bubble corners + drawypos = ypos - 128; + drawheight = (height+1)*8; + } + + + + //if (scanline==40) osd_printf_debug("xpos %04x ypos %04x\n",xpos,ypos); + + if ((drawypos<=scanline) && ((drawypos+drawheight)>scanline)) + { + addr = (MEGADRIV_VDP_VRAM(((base_address>>1)+spritenum*4)+0x2) & 0x07ff)>>0; + xflip = (MEGADRIV_VDP_VRAM(((base_address>>1)+spritenum*4)+0x2) & 0x0800)>>11; + yflip = (MEGADRIV_VDP_VRAM(((base_address>>1)+spritenum*4)+0x2) & 0x1000)>>12; + colour= (MEGADRIV_VDP_VRAM(((base_address>>1)+spritenum*4)+0x2) & 0x6000)>>13; + pri = (MEGADRIV_VDP_VRAM(((base_address>>1)+spritenum*4)+0x2) & 0x8000)>>15; + + if(m_imode == 3) + { + addr<<=1; + addr &=0x7ff; + } + + //drawwidth = (width+1)*8; + if (pri==1) pri = 0x80; + else pri = 0x40; + + /* todo: fix me, I'm sure this isn't right but sprite 0 + other sprite seem to do something.. + maybe spritemask|=2 should be set for anything < 0x40 ?*/ + if (xpos==0x00) spritemask|=1; + + //if (xpos==0x01) spritemask|=2; + //if (xpos==0x04) spritemask|=2; // sonic 2 title screen + //if (xpos==0x08) spritemask|=2; // rocket night adventures + //if (xpos==0x10) spritemask|=2; // mercs l1 boss + //if (xpos==0x0a) spritemask|=2; // legend of galahad + //if (xpos==0x21) spritemask|=2; // shadow of the beast? + if ((xpos>0) && (xpos<0x40)) spritemask|=2; + + if (spritemask==0x3) + return; + /* end todo: */ + + { + //int xdraw; + int xtile; + int yline = scanline - drawypos; + + for (xtile=0;xtile>28; gfxdata <<=4; + if (dat) { if (!m_sprite_renderline[xxx]) { m_sprite_renderline[xxx] = dat | (colour<<4)| pri; } else { m_sprite_collision = 1; } } + xxx++;xxx&=0x1ff; + if (--maxpixels == 0x00) return; + } + + } + else + { + UINT16 base_addr; + int xxx; + UINT32 gfxdata; + + int loopcount; + + if(m_imode == 3) + { + if (!yflip) base_addr = (addr<<4)+(((width-xtile))*((height+1)*(2*16)))+(yline*2); + else base_addr = (addr<<4)+(((width-xtile))*((height+1)*(2*16)))+((((height+1)*16)-yline-1)*2); + + } + else + { + if (!yflip) base_addr = (addr<<4)+(((width-xtile))*((height+1)*(2*8)))+(yline*2); + else base_addr = (addr<<4)+(((width-xtile))*((height+1)*(2*8)))+((((height+1)*8)-yline-1)*2); + } + + xxx = (xpos+xtile*8)&0x1ff; + + gfxdata = MEGADRIV_VDP_VRAM((base_addr+1)&0x7fff) | (MEGADRIV_VDP_VRAM((base_addr+0)&0x7fff)<<16); + + for(loopcount=0;loopcount<8;loopcount++) + { + dat = (gfxdata & 0x0000000f)>>0; gfxdata >>=4; + if (dat) { if (!m_sprite_renderline[xxx]) { m_sprite_renderline[xxx] = dat | (colour<<4)| pri; } else { m_sprite_collision = 1; } } + xxx++;xxx&=0x1ff; + if (--maxpixels == 0x00) return; + } + + } + } + } + } + + spritenum = link; + maxsprites--; + } + while ((maxsprites>=0) && (link!=0)); + + + } +} + +/* Clean up this function (!) */ +void sega315_5313_device::render_videoline_to_videobuffer(int scanline) +{ + UINT16 base_a; + UINT16 base_w=0; + UINT16 base_b; + + UINT16 size; + UINT16 hsize = 64; + UINT16 vsize = 64; + UINT16 window_right; +// UINT16 window_hpos; + UINT16 window_down; +// UINT16 window_vpos; + UINT16 hscroll_base; +// UINT8 vscroll_mode; +// UINT8 hscroll_mode; + int window_firstline; + int window_lastline; + int window_firstcol; + int window_lastcol; + int screenwidth; + int numcolumns = 0; + int hscroll_a = 0; + int hscroll_b = 0; + int x; + int window_hsize=0; + int window_vsize=0; + int window_is_bugged = 0; + int non_window_firstcol; + int non_window_lastcol; + int screenheight = MEGADRIVE_REG01_240_LINE?240:224; + + /* Clear our Render Buffer */ + for (x=0;x<320;x++) + { + m_video_renderline[x]=MEGADRIVE_REG07_BGCOLOUR | 0x20000; // mark as BG + } + + memset(m_highpri_renderline, 0, 320); + + /* is this line enabled? */ + if (!MEGADRIVE_REG01_DISP_ENABLE) + { + //osd_printf_debug("line disabled %d\n",scanline); + return; + } + + /* looks different? */ + if (MEGADRIVE_REG0_DISPLAY_DISABLE) + { + return; + } + + + + base_a = MEGADRIVE_REG02_PATTERN_ADDR_A << 13; + + base_b = MEGADRIVE_REG04_PATTERN_ADDR_B << 13; + size = MEGADRIVE_REG10_HSCROLL_SIZE | (MEGADRIVE_REG10_VSCROLL_SIZE<<4); + window_right = MEGADRIVE_REG11_WINDOW_RIGHT; +// window_hpos = MEGADRIVE_REG11_WINDOW_HPOS; + window_down = MEGADRIVE_REG12_WINDOW_DOWN; +// window_vpos = MEGADRIVE_REG12_WINDOW_VPOS; + + screenwidth = MEGADRIVE_REG0C_RS0 | (MEGADRIVE_REG0C_RS1 << 1); + + switch (screenwidth) + { + case 0: numcolumns = 32; window_hsize = 32; window_vsize = 32; base_w = (MEGADRIVE_REG03_PATTERN_ADDR_W&0x1f) << 11; break; + case 1: numcolumns = 32; window_hsize = 32; window_vsize = 32; base_w = (MEGADRIVE_REG03_PATTERN_ADDR_W&0x1f) << 11; break; + case 2: numcolumns = 40; window_hsize = 64; window_vsize = 32; base_w = (MEGADRIVE_REG03_PATTERN_ADDR_W&0x1e) << 11; break; + case 3: numcolumns = 40; window_hsize = 64; window_vsize = 32; base_w = (MEGADRIVE_REG03_PATTERN_ADDR_W&0x1e) << 11; break; // talespin cares about base mask, used for status bar + } + + //osd_printf_debug("screenwidth %d\n",screenwidth); + + //base_w = machine().rand()&0xff; + + /* Calculate Exactly where we're going to draw the Window, and if the Window Bug applies */ + window_is_bugged = 0; + if (window_right) + { + window_firstcol = MEGADRIVE_REG11_WINDOW_HPOS*16; + window_lastcol = numcolumns*8; + if (window_firstcol>window_lastcol) window_firstcol = window_lastcol; + + non_window_firstcol = 0; + non_window_lastcol = window_firstcol; + } + else + { + window_firstcol = 0; + window_lastcol = MEGADRIVE_REG11_WINDOW_HPOS*16; + if (window_lastcol>numcolumns*8) window_lastcol = numcolumns*8; + + non_window_firstcol = window_lastcol; + non_window_lastcol = numcolumns*8; + + if (window_lastcol!=0) window_is_bugged=1; + } + + if (window_down) + { + window_firstline = MEGADRIVE_REG12_WINDOW_VPOS*8; + window_lastline = screenheight; // 240 in PAL? + if (window_firstline>screenheight) window_firstline = screenheight; + } + else + { + window_firstline = 0; + window_lastline = MEGADRIVE_REG12_WINDOW_VPOS*8; + if (window_lastline>screenheight) window_lastline = screenheight; + } + + /* if we're on a window scanline between window_firstline and window_lastline the window is the full width of the screen */ + if (scanline>=window_firstline && scanline < window_lastline) + { + window_firstcol = 0; window_lastcol = numcolumns*8; // window is full-width of the screen + non_window_firstcol = 0; non_window_lastcol=0; // disable non-window + } + + +// vscroll_mode = MEGADRIVE_REG0B_VSCROLL_MODE; +// hscroll_mode = MEGADRIVE_REG0B_HSCROLL_MODE; + hscroll_base = MEGADRIVE_REG0D_HSCROLL_ADDR<<10; + + switch (size) + { + case 0x00: hsize = 32; vsize = 32; break; + case 0x01: hsize = 64; vsize = 32; break; + case 0x02: hsize = 64; vsize = 1; /* osd_printf_debug("Invalid HSize! %02x\n",size);*/ break; + case 0x03: hsize = 128;vsize = 32; break; + + case 0x10: hsize = 32; vsize = 64; break; + case 0x11: hsize = 64; vsize = 64; break; + case 0x12: hsize = 64; vsize = 1; /*osd_printf_debug("Invalid HSize! %02x\n",size);*/ break; + case 0x13: hsize = 128;vsize = 32;/*osd_printf_debug("Invalid Total Size! %02x\n",size);*/break; + + case 0x20: hsize = 32; vsize = 64; osd_printf_debug("Invalid VSize!\n"); break; + case 0x21: hsize = 64; vsize = 64; osd_printf_debug("Invalid VSize!\n"); break; + case 0x22: hsize = 64; vsize = 1; /*osd_printf_debug("Invalid HSize & Invalid VSize!\n");*/ break; + case 0x23: hsize = 128;vsize = 64; osd_printf_debug("Invalid VSize!\n"); break; + + case 0x30: hsize = 32; vsize = 128; break; + case 0x31: hsize = 64; vsize = 64; /*osd_printf_debug("Invalid Total Size! %02x\n",size);*/break; // super skidmarks attempts this.. + case 0x32: hsize = 64; vsize = 1; /*osd_printf_debug("Invalid HSize & Invalid Total Size!\n");*/ break; + case 0x33: hsize = 128;vsize = 128; osd_printf_debug("Invalid Total Size! %02x\n",size);break; + } + + switch (MEGADRIVE_REG0B_HSCROLL_MODE) + { + case 0x00: // Full Screen Scroll + hscroll_a = MEGADRIV_VDP_VRAM((hscroll_base>>1)+0); + hscroll_b = MEGADRIV_VDP_VRAM((hscroll_base>>1)+1); + break; + + case 0x01: // 'Broken' Line Scroll + if(m_imode == 3) + { + hscroll_a = MEGADRIV_VDP_VRAM((hscroll_base>>1)+0+((scanline>>1)&7)*2); + hscroll_b = MEGADRIV_VDP_VRAM((hscroll_base>>1)+1+((scanline>>1)&7)*2); + } + else + { + hscroll_a = MEGADRIV_VDP_VRAM((hscroll_base>>1)+0+(scanline&7)*2); + hscroll_b = MEGADRIV_VDP_VRAM((hscroll_base>>1)+1+(scanline&7)*2); + } + break; + + case 0x02: // Cell Scroll + if(m_imode == 3) + { + hscroll_a = MEGADRIV_VDP_VRAM((hscroll_base>>1)+0+((scanline>>1)&~7)*2); + hscroll_b = MEGADRIV_VDP_VRAM((hscroll_base>>1)+1+((scanline>>1)&~7)*2); + } + else + { + hscroll_a = MEGADRIV_VDP_VRAM((hscroll_base>>1)+0+(scanline&~7)*2); + hscroll_b = MEGADRIV_VDP_VRAM((hscroll_base>>1)+1+(scanline&~7)*2); + } + break; + + case 0x03: // Full Line Scroll + if(m_imode == 3) + { + hscroll_a = MEGADRIV_VDP_VRAM((hscroll_base>>1)+0+(scanline>>1)*2); + hscroll_b = MEGADRIV_VDP_VRAM((hscroll_base>>1)+1+(scanline>>1)*2); + } + else + { + hscroll_a = MEGADRIV_VDP_VRAM((hscroll_base>>1)+0+scanline*2); + hscroll_b = MEGADRIV_VDP_VRAM((hscroll_base>>1)+1+scanline*2); + } + break; + } + + /* Low Priority B Tiles */ + { + int column; + int vscroll; + + for (column=0;column>3))&(hsize-1); + + if(m_imode == 3) + { + vcolumn = (vscroll + scanline)&((vsize*16)-1); + tile_base = (base_b>>1)+((vcolumn>>4)*hsize)+hcolumn; + + } + else + { + vcolumn = (vscroll + scanline)&((vsize*8)-1); + tile_base = (base_b>>1)+((vcolumn>>3)*hsize)+hcolumn; + } + + + tile_base &=0x7fff; + tile_dat = MEGADRIV_VDP_VRAM(tile_base); + tile_xflip = (tile_dat&0x0800); + tile_yflip = (tile_dat&0x1000); + tile_colour =(tile_dat&0x6000)>>13; + tile_pri = (tile_dat&0x8000)>>15; + tile_addr = ((tile_dat&0x07ff)<<4); + + if(m_imode == 3) + { + tile_addr <<=1; + tile_addr &=0x7fff; + if (!tile_yflip) tile_addr+=(vcolumn&0xf)*2; + else tile_addr+=((0xf-vcolumn)&0xf)*2; + } + else + { + if (!tile_yflip) tile_addr+=(vcolumn&7)*2; + else tile_addr+=((7-vcolumn)&7)*2; + } + + if (!tile_xflip) + { + /* 8 pixels */ + UINT32 gfxdata = (MEGADRIV_VDP_VRAM(tile_addr+0)<<16)|MEGADRIV_VDP_VRAM(tile_addr+1); + int shift; + + for (shift=hscroll_part;shift<8;shift++) + { + dat = (gfxdata>>(28-(shift*4)))&0x000f; if (!tile_pri) { if(dat) m_video_renderline[dpos] = dat | (tile_colour<<4); } else m_highpri_renderline[dpos] = dat | (tile_colour<<4) | 0x80; + dpos++; + } + } + else + { + UINT32 gfxdata = (MEGADRIV_VDP_VRAM(tile_addr+0)<<16)|MEGADRIV_VDP_VRAM(tile_addr+1); + int shift; + for (shift=hscroll_part;shift<8;shift++) + { + dat = (gfxdata>>(shift*4) )&0x000f; if (!tile_pri) { if(dat) m_video_renderline[dpos] = dat | (tile_colour<<4); } else m_highpri_renderline[dpos] = dat | (tile_colour<<4) | 0x80; + dpos++; + } + } + + if (MEGADRIVE_REG0B_VSCROLL_MODE) + { + if (hscroll_b&0xf) vscroll = m_vsram[((column-1)*2+1)&0x3f]; + else vscroll = m_vsram[((column)*2+1)&0x3f]; + } + else + { + vscroll = m_vsram[1]; + } + + hcolumn = ((column*2)-(hscroll_b>>3))&(hsize-1); + + if(m_imode == 3) + { + vcolumn = (vscroll + scanline)&((vsize*16)-1); + tile_base = (base_b>>1)+((vcolumn>>4)*hsize)+hcolumn; + } + else + { + vcolumn = (vscroll + scanline)&((vsize*8)-1); + tile_base = (base_b>>1)+((vcolumn>>3)*hsize)+hcolumn; + } + + tile_base &=0x7fff; + tile_dat = MEGADRIV_VDP_VRAM(tile_base); + tile_xflip = (tile_dat&0x0800); + tile_yflip = (tile_dat&0x1000); + tile_colour =(tile_dat&0x6000)>>13; + tile_pri = (tile_dat&0x8000)>>15; + tile_addr = ((tile_dat&0x07ff)<<4); + + if(m_imode == 3) + { + tile_addr <<=1; + tile_addr &=0x7fff; + + if (!tile_yflip) tile_addr+=(vcolumn&0xf)*2; + else tile_addr+=((0xf-vcolumn)&0xf)*2; + } + else + { + if (!tile_yflip) tile_addr+=(vcolumn&7)*2; + else tile_addr+=((7-vcolumn)&7)*2; + } + + if (!tile_xflip) + { + /* 8 pixels */ + UINT32 gfxdata = (MEGADRIV_VDP_VRAM(tile_addr+0)<<16)|MEGADRIV_VDP_VRAM(tile_addr+1); + int shift; + + for (shift=0;shift<8;shift++) + { + dat = (gfxdata>>(28-(shift*4)))&0x000f; if (!tile_pri) { if(dat) m_video_renderline[dpos] = dat | (tile_colour<<4); } else m_highpri_renderline[dpos] = dat | (tile_colour<<4) | 0x80; + dpos++; + } + } + else + { + UINT32 gfxdata = (MEGADRIV_VDP_VRAM(tile_addr+0)<<16)|MEGADRIV_VDP_VRAM(tile_addr+1); + int shift; + for (shift=0;shift<8;shift++) + { + dat = (gfxdata>>(shift*4))&0x000f; if (!tile_pri) { if(dat) m_video_renderline[dpos] = dat | (tile_colour<<4); } else m_highpri_renderline[dpos] = dat | (tile_colour<<4) | 0x80; + dpos++; + } + } + + if (MEGADRIVE_REG0B_VSCROLL_MODE) + { + vscroll = m_vsram[((column)*2+1)&0x3f]; + } + else + { + vscroll = m_vsram[1]; + } + + hcolumn = ((column*2+1)-(hscroll_b>>3))&(hsize-1); + + if(m_imode == 3) + { + vcolumn = (vscroll + scanline)&((vsize*16)-1); + tile_base = (base_b>>1)+((vcolumn>>4)*hsize)+hcolumn; + } + else + { + vcolumn = (vscroll + scanline)&((vsize*8)-1); + tile_base = (base_b>>1)+((vcolumn>>3)*hsize)+hcolumn; + } + + tile_base &=0x7fff; + tile_dat = MEGADRIV_VDP_VRAM(tile_base); + tile_xflip = (tile_dat&0x0800); + tile_yflip = (tile_dat&0x1000); + tile_colour =(tile_dat&0x6000)>>13; + tile_pri = (tile_dat&0x8000)>>15; + tile_addr = ((tile_dat&0x07ff)<<4); + + if(m_imode == 3) + { + tile_addr <<=1; + tile_addr &=0x7fff; + if (!tile_yflip) tile_addr+=(vcolumn&0xf)*2; + else tile_addr+=((0xf-vcolumn)&0xf)*2; + } + else + { + if (!tile_yflip) tile_addr+=(vcolumn&7)*2; + else tile_addr+=((7-vcolumn)&7)*2; + } + + + if (!tile_xflip) + { + /* 8 pixels */ + UINT32 gfxdata = (MEGADRIV_VDP_VRAM(tile_addr+0)<<16)|MEGADRIV_VDP_VRAM(tile_addr+1); + int shift; + + for (shift=0;shift<(hscroll_part);shift++) + { + dat = (gfxdata>>(28-(shift*4)))&0x000f; if (!tile_pri) { if(dat) m_video_renderline[dpos] = dat | (tile_colour<<4); } else m_highpri_renderline[dpos] = dat | (tile_colour<<4) | 0x80; + dpos++; + } + } + else + { + UINT32 gfxdata = (MEGADRIV_VDP_VRAM(tile_addr+0)<<16)|MEGADRIV_VDP_VRAM(tile_addr+1); + int shift; + for (shift=0;shift<(hscroll_part);shift++) + { + dat = (gfxdata>>(shift*4) )&0x000f; if (!tile_pri) { if(dat) m_video_renderline[dpos] = dat | (tile_colour<<4); } else m_highpri_renderline[dpos] = dat | (tile_colour<<4) | 0x80; + dpos++; + } + } + } + } + /* END */ + } + /* Low Priority A Tiles + Window(!) */ + + { + int column; + int vscroll; + + for (column=window_firstcol/16;column>1)+((vcolumn>>4)*window_hsize)+hcolumn; + } + else + { + tile_base = (base_w>>1)+((vcolumn>>3)*window_hsize)+hcolumn; + } + + tile_base &=0x7fff; + tile_dat = MEGADRIV_VDP_VRAM(tile_base); + tile_xflip = (tile_dat&0x0800); + tile_yflip = (tile_dat&0x1000); + tile_colour =(tile_dat&0x6000)>>13; + tile_pri = (tile_dat&0x8000)>>15; + tile_addr = ((tile_dat&0x07ff)<<4); + + if(m_imode == 3) + { + tile_addr <<=1; + tile_addr &=0x7fff; + } + + if(m_imode == 3) + { + if (!tile_yflip) tile_addr+=(vcolumn&0xf)*2; + else tile_addr+=((0xf-vcolumn)&0xf)*2; + } + else + { + if (!tile_yflip) tile_addr+=(vcolumn&7)*2; + else tile_addr+=((7-vcolumn)&7)*2; + } + + if (!tile_xflip) + { + /* 8 pixels */ + UINT32 gfxdata = (MEGADRIV_VDP_VRAM(tile_addr+0)<<16)|MEGADRIV_VDP_VRAM(tile_addr+1); + int shift; + + for (shift=0;shift<8;shift++) + { + dat = (gfxdata>>(28-(shift*4)))&0x000f; + if (!tile_pri) + { + if(dat) m_video_renderline[dpos] = dat | (tile_colour<<4); + } + else + { + if (dat) m_highpri_renderline[dpos] = dat | (tile_colour<<4) | 0x80; + else m_highpri_renderline[dpos] = m_highpri_renderline[dpos]|0x80; + } + dpos++; + } + } + else + { + UINT32 gfxdata = (MEGADRIV_VDP_VRAM(tile_addr+0)<<16)|MEGADRIV_VDP_VRAM(tile_addr+1); + int shift; + for (shift=0;shift<8;shift++) + { + dat = (gfxdata>>(shift*4) )&0x000f; + if (!tile_pri) + { + if(dat) m_video_renderline[dpos] = dat | (tile_colour<<4); + } + else + { + if (dat) m_highpri_renderline[dpos] = dat | (tile_colour<<4) | 0x80; + else m_highpri_renderline[dpos] = m_highpri_renderline[dpos]|0x80; + } + dpos++; + + } + } + + + hcolumn = (column*2+1)&(window_hsize-1); + if(m_imode == 3) + { + tile_base = (base_w>>1)+((vcolumn>>4)*window_hsize)+hcolumn; + } + else + { + tile_base = (base_w>>1)+((vcolumn>>3)*window_hsize)+hcolumn; + } + tile_base &=0x7fff; + tile_dat = MEGADRIV_VDP_VRAM(tile_base); + tile_xflip = (tile_dat&0x0800); + tile_yflip = (tile_dat&0x1000); + tile_colour =(tile_dat&0x6000)>>13; + tile_pri = (tile_dat&0x8000)>>15; + tile_addr = ((tile_dat&0x07ff)<<4); + + if(m_imode == 3) + { + tile_addr <<=1; + tile_addr &=0x7fff; + } + + if(m_imode == 3) + { + if (!tile_yflip) tile_addr+=(vcolumn&0xf)*2; + else tile_addr+=((0xf-vcolumn)&0xf)*2; + } + else + { + if (!tile_yflip) tile_addr+=(vcolumn&7)*2; + else tile_addr+=((7-vcolumn)&7)*2; + } + + if (!tile_xflip) + { + /* 8 pixels */ + UINT32 gfxdata = (MEGADRIV_VDP_VRAM(tile_addr+0)<<16)|MEGADRIV_VDP_VRAM(tile_addr+1); + int shift; + + for (shift=0;shift<8;shift++) + { + dat = (gfxdata>>(28-(shift*4)))&0x000f; + if (!tile_pri) + { + if(dat) m_video_renderline[dpos] = dat | (tile_colour<<4); + } + else + { + if (dat) m_highpri_renderline[dpos] = dat | (tile_colour<<4) | 0x80; + else m_highpri_renderline[dpos] = m_highpri_renderline[dpos]|0x80; + } + dpos++; + } + } + else + { + UINT32 gfxdata = (MEGADRIV_VDP_VRAM(tile_addr+0)<<16)|MEGADRIV_VDP_VRAM(tile_addr+1); + int shift; + for (shift=0;shift<8;shift++) + { + dat = (gfxdata>>(shift*4) )&0x000f; + if (!tile_pri) + { + if(dat) m_video_renderline[dpos] = dat | (tile_colour<<4); + } + else + { + if (dat) m_highpri_renderline[dpos] = dat | (tile_colour<<4) | 0x80; + else m_highpri_renderline[dpos] = m_highpri_renderline[dpos]|0x80; + } + dpos++; + } + } + } + + /* Non Window Part */ + + for (column=non_window_firstcol/16;columnnon_window_firstcol/16)) hcolumn = ((column*2-1)-(hscroll_a>>3))&(hsize-1); + else hcolumn = ((column*2+1)-(hscroll_a>>3))&(hsize-1); + + if(m_imode == 3) + { + vcolumn = (vscroll + scanline)&((vsize*16)-1); + } + else + { + vcolumn = (vscroll + scanline)&((vsize*8)-1); + } + + if(m_imode == 3) + { + tile_base = (base_a>>1)+((vcolumn>>4)*hsize)+hcolumn; + } + else + { + tile_base = (base_a>>1)+((vcolumn>>3)*hsize)+hcolumn; + } + + + tile_base &=0x7fff; + tile_dat = MEGADRIV_VDP_VRAM(tile_base); + tile_xflip = (tile_dat&0x0800); + tile_yflip = (tile_dat&0x1000); + tile_colour =(tile_dat&0x6000)>>13; + tile_pri = (tile_dat&0x8000)>>15; + tile_addr = ((tile_dat&0x07ff)<<4); + + if(m_imode == 3) + { + tile_addr <<=1; + tile_addr &=0x7fff; + if (!tile_yflip) tile_addr+=(vcolumn&0xf)*2; + else tile_addr+=((0xf-vcolumn)&0xf)*2; + } + else + { + if (!tile_yflip) tile_addr+=(vcolumn&7)*2; + else tile_addr+=((7-vcolumn)&7)*2; + } + + if (!tile_xflip) + { + /* 8 pixels */ + UINT32 gfxdata = (MEGADRIV_VDP_VRAM(tile_addr+0)<<16)|MEGADRIV_VDP_VRAM(tile_addr+1); + int shift; + + for (shift=hscroll_part;shift<8;shift++) + { + dat = (gfxdata>>(28-(shift*4)))&0x000f; + if (!tile_pri) + { + if(dat) m_video_renderline[dpos] = dat | (tile_colour<<4); + } + else + { + if (dat) m_highpri_renderline[dpos] = dat | (tile_colour<<4) | 0x80; + else m_highpri_renderline[dpos] = m_highpri_renderline[dpos]|0x80; + } + dpos++; + } + } + else + { + UINT32 gfxdata = (MEGADRIV_VDP_VRAM(tile_addr+0)<<16)|MEGADRIV_VDP_VRAM(tile_addr+1); + int shift; + for (shift=hscroll_part;shift<8;shift++) + { + dat = (gfxdata>>(shift*4) )&0x000f; + if (!tile_pri) + { + if(dat) m_video_renderline[dpos] = dat | (tile_colour<<4); + } + else + { + if (dat) m_highpri_renderline[dpos] = dat | (tile_colour<<4) | 0x80; + else m_highpri_renderline[dpos] = m_highpri_renderline[dpos]|0x80; + } + dpos++; + } + } + + if (MEGADRIVE_REG0B_VSCROLL_MODE) + { + if (hscroll_a&0xf) vscroll = m_vsram[((column-1)*2+0)&0x3f]; + else vscroll = m_vsram[((column)*2+0)&0x3f]; + } + else + { + vscroll = m_vsram[0]; + } + + if ((!window_is_bugged) || ((hscroll_a&0xf)==0) || (column>non_window_firstcol/16)) hcolumn = ((column*2)-(hscroll_a>>3))&(hsize-1); // not affected by bug? + else + { + if ((hscroll_a&0xf)<8) hcolumn = ((column*2)-(hscroll_a>>3))&(hsize-1); + else hcolumn = ((column*2+2)-(hscroll_a>>3))&(hsize-1); + } + + + if(m_imode == 3) + { + vcolumn = (vscroll + scanline)&((vsize*16)-1); + tile_base = (base_a>>1)+((vcolumn>>4)*hsize)+hcolumn; + } + else + { + vcolumn = (vscroll + scanline)&((vsize*8)-1); + tile_base = (base_a>>1)+((vcolumn>>3)*hsize)+hcolumn; + } + + tile_base &=0x7fff; + tile_dat = MEGADRIV_VDP_VRAM(tile_base); + tile_xflip = (tile_dat&0x0800); + tile_yflip = (tile_dat&0x1000); + tile_colour =(tile_dat&0x6000)>>13; + tile_pri = (tile_dat&0x8000)>>15; + tile_addr = ((tile_dat&0x07ff)<<4); + + + if(m_imode == 3) + { + tile_addr <<=1; + tile_addr &=0x7fff; + if (!tile_yflip) tile_addr+=(vcolumn&0xf)*2; + else tile_addr+=((0xf-vcolumn)&0xf)*2; + } + else + { + if (!tile_yflip) tile_addr+=(vcolumn&7)*2; + else tile_addr+=((7-vcolumn)&7)*2; + } + + if (!tile_xflip) + { + /* 8 pixels */ + UINT32 gfxdata = (MEGADRIV_VDP_VRAM(tile_addr+0)<<16)|MEGADRIV_VDP_VRAM(tile_addr+1); + int shift; + + for (shift=0;shift<8;shift++) + { + dat = (gfxdata>>(28-(shift*4)))&0x000f; + if (!tile_pri) + { + if(dat) m_video_renderline[dpos] = dat | (tile_colour<<4); + } + else + { + if (dat) m_highpri_renderline[dpos] = dat | (tile_colour<<4) | 0x80; + else m_highpri_renderline[dpos] = m_highpri_renderline[dpos]|0x80; + } + dpos++; + } + } + else + { + UINT32 gfxdata = (MEGADRIV_VDP_VRAM(tile_addr+0)<<16)|MEGADRIV_VDP_VRAM(tile_addr+1); + int shift; + for (shift=0;shift<8;shift++) + { + dat = (gfxdata>>(shift*4) )&0x000f; + if (!tile_pri) + { + if(dat) m_video_renderline[dpos] = dat | (tile_colour<<4); + } + else + { + if (dat) m_highpri_renderline[dpos] = dat | (tile_colour<<4) | 0x80; + else m_highpri_renderline[dpos] = m_highpri_renderline[dpos]|0x80; + } + dpos++; + } + } + + if (MEGADRIVE_REG0B_VSCROLL_MODE) + { + vscroll = m_vsram[((column)*2+0)&0x3f]; + } + else + { + vscroll = m_vsram[0]; + } + + if ((!window_is_bugged) || ((hscroll_a&0xf)==0) || (column>non_window_firstcol/16)) hcolumn = ((column*2+1)-(hscroll_a>>3))&(hsize-1); + else hcolumn = ((column*2+1)-(hscroll_a>>3))&(hsize-1); + + if(m_imode == 3) + { + vcolumn = (vscroll + scanline)&((vsize*16)-1); + tile_base = (base_a>>1)+((vcolumn>>4)*hsize)+hcolumn; + } + else + { + vcolumn = (vscroll + scanline)&((vsize*8)-1); + tile_base = (base_a>>1)+((vcolumn>>3)*hsize)+hcolumn; + } + tile_base &=0x7fff; + tile_dat = MEGADRIV_VDP_VRAM(tile_base); + tile_xflip = (tile_dat&0x0800); + tile_yflip = (tile_dat&0x1000); + tile_colour =(tile_dat&0x6000)>>13; + tile_pri = (tile_dat&0x8000)>>15; + tile_addr = ((tile_dat&0x07ff)<<4); + + if(m_imode == 3) + { + tile_addr <<=1; + tile_addr &=0x7fff; + } + + if(m_imode == 3) + { + if (!tile_yflip) tile_addr+=(vcolumn&0xf)*2; + else tile_addr+=((0xf-vcolumn)&0xf)*2; + } + else + { + if (!tile_yflip) tile_addr+=(vcolumn&7)*2; + else tile_addr+=((7-vcolumn)&7)*2; + } + + if (!tile_xflip) + { + /* 8 pixels */ + UINT32 gfxdata = (MEGADRIV_VDP_VRAM(tile_addr+0)<<16)|MEGADRIV_VDP_VRAM(tile_addr+1); + int shift; + + for (shift=0;shift<(hscroll_part);shift++) + { + dat = (gfxdata>>(28-(shift*4)))&0x000f; + if (!tile_pri) + { + if(dat) m_video_renderline[dpos] = dat | (tile_colour<<4); + } + else + { + if (dat) m_highpri_renderline[dpos] = dat | (tile_colour<<4) | 0x80; + else m_highpri_renderline[dpos] = m_highpri_renderline[dpos]|0x80; + } + dpos++; + } + } + else + { + UINT32 gfxdata = (MEGADRIV_VDP_VRAM(tile_addr+0)<<16)|MEGADRIV_VDP_VRAM(tile_addr+1); + int shift; + for (shift=0;shift<(hscroll_part);shift++) + { + dat = (gfxdata>>(shift*4) )&0x000f; + if (!tile_pri) + { + if(dat) m_video_renderline[dpos] = dat | (tile_colour<<4); + } + else + { + if (dat) m_highpri_renderline[dpos] = dat | (tile_colour<<4) | 0x80; + else m_highpri_renderline[dpos] = m_highpri_renderline[dpos]|0x80; + } + dpos++; + } + } + } + } + } + /* END */ + +/* MEGADRIVE_REG0C_SHADOW_HIGLIGHT */ + /* Low Priority Sprites */ + for (x=0;x<320;x++) + { + if (!MEGADRIVE_REG0C_SHADOW_HIGLIGHT) + { + if (m_sprite_renderline[x+128] & 0x40) + { + m_video_renderline[x] = m_sprite_renderline[x+128]&0x3f; + m_video_renderline[x] |= 0x10000; // mark as sprite pixel + } + } + else + { /* Special Shadow / Highlight processing */ + + if (m_sprite_renderline[x+128] & 0x40) + { + UINT8 spritedata; + spritedata = m_sprite_renderline[x+128]&0x3f; + + if ((spritedata==0x0e) || (spritedata==0x1e) || (spritedata==0x2e)) + { + /* BUG in sprite chip, these colours are always normal intensity */ + m_video_renderline[x] = spritedata | 0x4000; + m_video_renderline[x] |= 0x10000; // mark as sprite pixel + } + else if (spritedata==0x3e) + { + /* Everything below this is half colour, mark with 0x8000 to mark highlight' */ + m_video_renderline[x] = m_video_renderline[x]|0x8000; // spiderwebs.. + } + else if (spritedata==0x3f) + { + /* This is a Shadow operator, but everything below is already low pri, no effect */ + m_video_renderline[x] = m_video_renderline[x]|0x2000; + + } + else + { + m_video_renderline[x] = spritedata; + m_video_renderline[x] |= 0x10000; // mark as sprite pixel + } + + } + } + } + /* High Priority A+B Tiles */ + for (x=0;x<320;x++) + { + if (!MEGADRIVE_REG0C_SHADOW_HIGLIGHT) + { + /* Normal Processing */ + int dat; + dat = m_highpri_renderline[x]; + + if (dat&0x80) + { + if (dat&0x0f) m_video_renderline[x] = m_highpri_renderline[x]&0x3f; + } + } + else + { + /* Shadow / Highlight Mode */ + int dat; + dat = m_highpri_renderline[x]; + + if (dat&0x80) + { + if (dat&0x0f) m_video_renderline[x] = (m_highpri_renderline[x]&0x3f) | 0x4000; + else m_video_renderline[x] = m_video_renderline[x] | 0x4000; // set 'normal' + } + } + } + + /* High Priority Sprites */ + for (x=0;x<320;x++) + { + if (!MEGADRIVE_REG0C_SHADOW_HIGLIGHT) + { + /* Normal */ + if (m_sprite_renderline[x+128] & 0x80) + { + m_video_renderline[x] = m_sprite_renderline[x+128]&0x3f; + m_video_renderline[x] |= 0x10000; // mark as sprite pixel + } + } + else + { + if (m_sprite_renderline[x+128] & 0x80) + { + UINT8 spritedata; + spritedata = m_sprite_renderline[x+128]&0x3f; + + if (spritedata==0x3e) + { + /* set flag 0x8000 to indicate highlight */ + m_video_renderline[x] = m_video_renderline[x]|0x8000; + } + else if (spritedata==0x3f) + { + /* This is a Shadow operator set shadow bit */ + m_video_renderline[x] = m_video_renderline[x]|0x2000; + } + else + { + m_video_renderline[x] = spritedata | 0x4000; + m_video_renderline[x] |= 0x10000; // mark as sprite pixel + } + } + } + } +} + + +/* This converts our render buffer to real screen colours */ +void sega315_5313_device::render_videobuffer_to_screenbuffer(int scanline) +{ + UINT16 *lineptr; + + + + if (!m_use_alt_timing) + { + if (scanline >= m_render_bitmap->height()) // safety, shouldn't happen now we allocate a fixed amount tho + return; + + lineptr = &m_render_bitmap->pix16(scanline); + + } + else + lineptr = m_render_line; + + for (int x = 0; x < 320; x++) + { + UINT32 dat = m_video_renderline[x]; + + if (!(dat & 0x20000)) + m_render_line_raw[x] = 0x100; + else + m_render_line_raw[x] = 0x000; + + + if (!MEGADRIVE_REG0C_SHADOW_HIGLIGHT) + { + if (dat & 0x10000) + { + lineptr[x] = m_palette_lookup_sprite[(dat & 0x3f)]; + m_render_line_raw[x] |= (dat & 0x3f) | 0x080; + } + else + { + lineptr[x] = m_palette_lookup[(dat & 0x3f)]; + m_render_line_raw[x] |= (dat & 0x3f) | 0x040; + } + + } + else + { + /* Verify my handling.. I'm not sure all cases are correct */ + switch (dat & 0x1e000) + { + case 0x00000: // low priority, no shadow sprite, no highlight = shadow + case 0x02000: // low priority, shadow sprite, no highlight = shadow + case 0x06000: // normal pri, shadow sprite, no highlight = shadow? + case 0x10000: // (sprite) low priority, no shadow sprite, no highlight = shadow + case 0x12000: // (sprite) low priority, shadow sprite, no highlight = shadow + case 0x16000: // (sprite) normal pri, shadow sprite, no highlight = shadow? + lineptr[x] = m_palette_lookup_shadow[(dat & 0x3f)]; + m_render_line_raw[x] |= (dat & 0x3f) | 0x000; + break; + + case 0x4000: // normal pri, no shadow sprite, no highlight = normal; + case 0x8000: // low pri, highlight sprite = normal; + lineptr[x] = m_palette_lookup[(dat & 0x3f)]; + m_render_line_raw[x] |= (dat & 0x3f) | 0x040; + break; + + case 0x14000: // (sprite) normal pri, no shadow sprite, no highlight = normal; + case 0x18000: // (sprite) low pri, highlight sprite = normal; + lineptr[x] = m_palette_lookup_sprite[(dat & 0x3f)]; + m_render_line_raw[x] |= (dat & 0x3f) | 0x080; + break; + + + case 0x0c000: // normal pri, highlight set = highlight? + case 0x1c000: // (sprite) normal pri, highlight set = highlight? + lineptr[x] = m_palette_lookup_highlight[(dat & 0x3f)]; + m_render_line_raw[x] |= (dat & 0x3f) | 0x0c0; + break; + + case 0x0a000: // shadow set, highlight set - not possible + case 0x0e000: // shadow set, highlight set, normal set, not possible + case 0x1a000: // (sprite)shadow set, highlight set - not possible + case 0x1e000: // (sprite)shadow set, highlight set, normal set, not possible + default: + lineptr[x] = m_render_line_raw[x] |= (machine().rand() & 0x3f); + break; + } + } + } + + if (!m_32x_scanline_helper_func.isnull()) + m_32x_scanline_helper_func(scanline); + if (!m_32x_scanline_func.isnull()) + { + for (int x = 0; x < 320; x++) + m_32x_scanline_func(x, m_video_renderline[x] & 0x20000, lineptr[x]); + } +} + +void sega315_5313_device::render_scanline() +{ + int scanline = get_scanline_counter(); + + if (scanline >= 0 && scanline < m_visible_scanlines) + { + //if (MEGADRIVE_REG01_DMA_ENABLE==0) osd_printf_debug("off\n"); + render_spriteline_to_spritebuffer(get_scanline_counter()); + render_videoline_to_videobuffer(scanline); + render_videobuffer_to_screenbuffer(scanline); + } +} + +void sega315_5313_device::vdp_handle_scanline_callback(int scanline) +{ +/* Compensate for some rounding errors + + When the counter reaches 261 we should have reached the end of the frame, however due + to rounding errors in the timer calculation we're not quite there. Let's assume we are + still in the previous scanline for now. + */ + + if (get_scanline_counter() != (m_total_scanlines - 1)) + { + if (!m_use_alt_timing) m_scanline_counter++; +// osd_printf_debug("scanline %d\n",get_scanline_counter()); + m_render_timer->adjust(attotime::from_usec(1)); + + if (get_scanline_counter() == m_irq6_scanline) + { + // osd_printf_debug("x %d",get_scanline_counter()); + m_irq6_on_timer->adjust(attotime::from_usec(6)); + m_irq6_pending = 1; + m_vblank_flag = 1; + + } + + // if (get_scanline_counter()==0) m_irq4counter = MEGADRIVE_REG0A_HINT_VALUE; + // m_irq4counter = MEGADRIVE_REG0A_HINT_VALUE; + + if (get_scanline_counter()<=224) + { + m_irq4counter--; + + if (m_irq4counter==-1) + { + if (m_imode == 3) m_irq4counter = MEGADRIVE_REG0A_HINT_VALUE*2; + else m_irq4counter=MEGADRIVE_REG0A_HINT_VALUE; + + m_irq4_pending = 1; + + if (MEGADRIVE_REG0_IRQ4_ENABLE) + { + m_irq4_on_timer->adjust(attotime::from_usec(1)); + //osd_printf_debug("irq4 on scanline %d reload %d\n",get_scanline_counter(),MEGADRIVE_REG0A_HINT_VALUE); + } + } + } + else + { + if (m_imode == 3) m_irq4counter = MEGADRIVE_REG0A_HINT_VALUE*2; + else m_irq4counter=MEGADRIVE_REG0A_HINT_VALUE; + } + + //if (get_scanline_counter()==0) irq4_on_timer->adjust(attotime::from_usec(2)); + + + if (get_scanline_counter() == m_z80irq_scanline) + { + m_sndirqline_callback(true); + } + if (get_scanline_counter() == m_z80irq_scanline + 1) + { + m_sndirqline_callback(false); + } + } + else /* pretend we're still on the same scanline to compensate for rounding errors */ + { + if (!m_use_alt_timing) m_scanline_counter = m_total_scanlines - 1; + } + + // 32x interrupts! + if (!m_32x_interrupt_func.isnull()) + m_32x_interrupt_func(get_scanline_counter(), m_irq6_scanline); +} + + +void sega315_5313_device::vdp_handle_eof() +{ + rectangle visarea; + int scr_width = 320; + + m_vblank_flag = 0; + //m_irq6_pending = 0; /* NO! (breaks warlock) */ + + /* Set it to -1 here, so it becomes 0 when the first timer kicks in */ + if (!m_use_alt_timing) m_scanline_counter = -1; + m_sprite_collision=0;//? when to reset this .. + m_imode = MEGADRIVE_REG0C_INTERLEAVE; // can't change mid-frame.. + m_imode_odd_frame^=1; +// m_genesis_snd_z80->set_input_line(0, CLEAR_LINE); // if the z80 interrupt hasn't happened by now, clear it.. + + if (MEGADRIVE_REG01_240_LINE) + { + /* this is invalid in PAL! */ + m_total_scanlines = m_base_total_scanlines; + m_visible_scanlines = 240; + m_irq6_scanline = 240; + m_z80irq_scanline = 240; + } + else + { + m_total_scanlines = m_base_total_scanlines; + m_visible_scanlines = 224; + m_irq6_scanline = 224; + m_z80irq_scanline = 224; + } + + if (m_imode == 3) + { + m_total_scanlines <<= 1; + m_visible_scanlines <<= 1; + m_irq6_scanline <<= 1; + m_z80irq_scanline <<= 1; + } + + + switch (MEGADRIVE_REG0C_RS0 | (MEGADRIVE_REG0C_RS1 << 1)) + { + /* note, add 240 mode + init new timings! */ + case 0:scr_width = 256;break; + case 1:scr_width = 256;break; + case 2:scr_width = 320;break; + case 3:scr_width = 320;break; + } +// osd_printf_debug("my mode %02x", m_regs[0x0c]); + + visarea.set(0, scr_width - 1, 0, m_visible_scanlines - 1); + + m_screen->configure(480, m_total_scanlines, visarea, m_screen->frame_period().attoseconds()); +} + + +// called at the start of each scanline +TIMER_DEVICE_CALLBACK_MEMBER( sega315_5313_device::megadriv_scanline_timer_callback ) +{ + if (!m_use_alt_timing) + { + machine().scheduler().synchronize(); + vdp_handle_scanline_callback(param); + + m_megadriv_scanline_timer->adjust(attotime::from_hz(get_framerate()) / m_total_scanlines); + } + else + { + vdp_handle_scanline_callback(param); + } +} + +TIMER_DEVICE_CALLBACK_MEMBER( sega315_5313_device::megadriv_scanline_timer_callback_alt_timing ) +{ + if (m_use_alt_timing) + { + if (param==0) + { + //printf("where are we? %d %d\n", m_screen->vpos(), screen().hpos()); + vdp_handle_eof(); + //vdp_clear_bitmap(); + } + + + vdp_handle_scanline_callback(param); + + int vpos = screen().vpos(); + if (vpos > 0) + screen().update_partial(vpos-1); + } +} diff --git a/src/devices/video/315_5313.h b/src/devices/video/315_5313.h new file mode 100644 index 00000000000..8bcf91a6d5f --- /dev/null +++ b/src/devices/video/315_5313.h @@ -0,0 +1,358 @@ +// license:BSD-3-Clause +// copyright-holders:David Haywood +/* Sega Megadrive / Genesis VDP */ + +#pragma once + +#include "video/315_5124.h" +#include "cpu/m68000/m68000.h" + + +/* The VDP occupies addresses C00000h to C0001Fh. + + C00000h - Data port (8=r/w, 16=r/w) + C00002h - Data port (mirror) + C00004h - Control port (8=r/w, 16=r/w) + C00006h - Control port (mirror) + C00008h - HV counter (8/16=r/o) + C0000Ah - HV counter (mirror) + C0000Ch - HV counter (mirror) + C0000Eh - HV counter (mirror) + C00011h - SN76489 PSG (8=w/o) + C00013h - SN76489 PSG (mirror) + C00015h - SN76489 PSG (mirror) + C00017h - SN76489 PSG (mirror) +*/ + +#define MEGADRIV_VDP_VRAM(address) m_vram[(address)&0x7fff] + + + +/* + + $00 - Mode Set Register No. 1 + ----------------------------- + + d7 - No effect + d6 - No effect + d5 - No effect + d4 - IE1 (Horizontal interrupt enable) + d3 - 1= Invalid display setting + d2 - Palette select + d1 - M3 (HV counter latch enable) + d0 - Display disable + + */ + +#define MEGADRIVE_REG0_UNUSED ((m_regs[0x00]&0xc0)>>6) +#define MEGADRIVE_REG0_BLANK_LEFT ((m_regs[0x00]&0x20)>>5) // like SMS, not used by any commercial games? +#define MEGADRIVE_REG0_IRQ4_ENABLE ((m_regs[0x00]&0x10)>>4) +#define MEGADRIVE_REG0_INVALID_MODE ((m_regs[0x00]&0x08)>>3) // invalid display mode, unhandled +#define MEGADRIVE_REG0_SPECIAL_PAL ((m_regs[0x00]&0x04)>>2) // strange palette mode, unhandled +#define MEGADRIVE_REG0_HVLATCH_ENABLE ((m_regs[0x00]&0x02)>>1) // HV Latch, used by lightgun games +#define MEGADRIVE_REG0_DISPLAY_DISABLE ((m_regs[0x00]&0x01)>>0) + +/* + + $01 - Mode Set Register No. 2 + ----------------------------- + + d7 - TMS9918 / Genesis display select + d6 - DISP (Display Enable) + d5 - IE0 (Vertical Interrupt Enable) + d4 - M1 (DMA Enable) + d3 - M2 (PAL / NTSC) + d2 - SMS / Genesis display select + d1 - 0 (No effect) + d0 - 0 (See notes) + +*/ + +#define MEGADRIVE_REG01_TMS9918_SELECT ((m_regs[0x01]&0x80)>>7) +#define MEGADRIVE_REG01_DISP_ENABLE ((m_regs[0x01]&0x40)>>6) +#define MEGADRIVE_REG01_IRQ6_ENABLE ((m_regs[0x01]&0x20)>>5) +#define MEGADRIVE_REG01_DMA_ENABLE ((m_regs[0x01]&0x10)>>4) +#define MEGADRIVE_REG01_240_LINE ((m_regs[0x01]&0x08)>>3) +#define MEGADRIVE_REG01_SMS_SELECT ((m_regs[0x01]&0x04)>>2) +#define MEGADRIVE_REG01_UNUSED ((m_regs[0x01]&0x02)>>1) +#define MEGADRIVE_REG01_STRANGE_VIDEO ((m_regs[0x01]&0x01)>>0) // unhandled, does strange things to the display + +#define MEGADRIVE_REG02_UNUSED1 ((m_regs[0x02]&0xc0)>>6) +#define MEGADRIVE_REG02_PATTERN_ADDR_A ((m_regs[0x02]&0x38)>>3) +#define MEGADRIVE_REG02_UNUSED2 ((m_regs[0x02]&0x07)>>0) + +#define MEGADRIVE_REG03_UNUSED1 ((m_regs[0x03]&0xc0)>>6) +#define MEGADRIVE_REG03_PATTERN_ADDR_W ((m_regs[0x03]&0x3e)>>1) +#define MEGADRIVE_REG03_UNUSED2 ((m_regs[0x03]&0x01)>>0) + +#define MEGADRIVE_REG04_UNUSED ((m_regs[0x04]&0xf8)>>3) +#define MEGADRIVE_REG04_PATTERN_ADDR_B ((m_regs[0x04]&0x07)>>0) + +#define MEGADRIVE_REG05_UNUSED ((m_regs[0x05]&0x80)>>7) +#define MEGADRIVE_REG05_SPRITE_ADDR ((m_regs[0x05]&0x7f)>>0) + +/* 6? */ + +#define MEGADRIVE_REG07_UNUSED ((m_regs[0x07]&0xc0)>>6) +#define MEGADRIVE_REG07_BGCOLOUR ((m_regs[0x07]&0x3f)>>0) + +/* 8? */ +/* 9? */ + +#define MEGADRIVE_REG0A_HINT_VALUE ((m_regs[0x0a]&0xff)>>0) + +#define MEGADRIVE_REG0B_UNUSED ((m_regs[0x0b]&0xf0)>>4) +#define MEGADRIVE_REG0B_IRQ2_ENABLE ((m_regs[0x0b]&0x08)>>3) +#define MEGADRIVE_REG0B_VSCROLL_MODE ((m_regs[0x0b]&0x04)>>2) +#define MEGADRIVE_REG0B_HSCROLL_MODE ((m_regs[0x0b]&0x03)>>0) + +#define MEGADRIVE_REG0C_RS0 ((m_regs[0x0c]&0x80)>>7) +#define MEGADRIVE_REG0C_UNUSED1 ((m_regs[0x0c]&0x40)>>6) +#define MEGADRIVE_REG0C_SPECIAL ((m_regs[0x0c]&0x20)>>5) +#define MEGADRIVE_REG0C_UNUSED2 ((m_regs[0x0c]&0x10)>>4) +#define MEGADRIVE_REG0C_SHADOW_HIGLIGHT ((m_regs[0x0c]&0x08)>>3) +#define MEGADRIVE_REG0C_INTERLEAVE ((m_regs[0x0c]&0x06)>>1) +#define MEGADRIVE_REG0C_RS1 ((m_regs[0x0c]&0x01)>>0) + +#define MEGADRIVE_REG0D_UNUSED ((m_regs[0x0d]&0xc0)>>6) +#define MEGADRIVE_REG0D_HSCROLL_ADDR ((m_regs[0x0d]&0x3f)>>0) + +/* e? */ + +#define MEGADRIVE_REG0F_AUTO_INC ((m_regs[0x0f]&0xff)>>0) + +#define MEGADRIVE_REG10_UNUSED1 ((m_regs[0x10]&0xc0)>>6) +#define MEGADRIVE_REG10_VSCROLL_SIZE ((m_regs[0x10]&0x30)>>4) +#define MEGADRIVE_REG10_UNUSED2 ((m_regs[0x10]&0x0c)>>2) +#define MEGADRIVE_REG10_HSCROLL_SIZE ((m_regs[0x10]&0x03)>>0) + +#define MEGADRIVE_REG11_WINDOW_RIGHT ((m_regs[0x11]&0x80)>>7) +#define MEGADRIVE_REG11_UNUSED ((m_regs[0x11]&0x60)>>5) +#define MEGADRIVE_REG11_WINDOW_HPOS ((m_regs[0x11]&0x1f)>>0) + +#define MEGADRIVE_REG12_WINDOW_DOWN ((m_regs[0x12]&0x80)>>7) +#define MEGADRIVE_REG12_UNUSED ((m_regs[0x12]&0x60)>>5) +#define MEGADRIVE_REG12_WINDOW_VPOS ((m_regs[0x12]&0x1f)>>0) + +#define MEGADRIVE_REG13_DMALENGTH1 ((m_regs[0x13]&0xff)>>0) + +#define MEGADRIVE_REG14_DMALENGTH2 ((m_regs[0x14]&0xff)>>0) + +#define MEGADRIVE_REG15_DMASOURCE1 ((m_regs[0x15]&0xff)>>0) +#define MEGADRIVE_REG16_DMASOURCE2 ((m_regs[0x16]&0xff)>>0) + +#define MEGADRIVE_REG17_DMASOURCE3 ((m_regs[0x17]&0xff)>>0) +#define MEGADRIVE_REG17_DMATYPE ((m_regs[0x17]&0xc0)>>6) +#define MEGADRIVE_REG17_UNUSED ((m_regs[0x17]&0x3f)>>0) + + +#define MCFG_SEGA315_5313_IS_PAL(_bool) \ + sega315_5313_device::set_signal_type(*device, _bool); + +#define MCFG_SEGA315_5313_INT_CB(_devcb) \ + devcb = &sega315_5313_device::set_int_callback(*device, DEVCB_##_devcb); + +#define MCFG_SEGA315_5313_PAUSE_CB(_devcb) \ + devcb = &sega315_5313_device::set_pause_callback(*device, DEVCB_##_devcb); + +#define MCFG_SEGA315_5313_SND_IRQ_CALLBACK(_write) \ + devcb = &sega315_5313_device::set_sndirqline_callback(*device, DEVCB_##_write); + +#define MCFG_SEGA315_5313_LV6_IRQ_CALLBACK(_write) \ + devcb = &sega315_5313_device::set_lv6irqline_callback(*device, DEVCB_##_write); + +#define MCFG_SEGA315_5313_LV4_IRQ_CALLBACK(_write) \ + devcb = &sega315_5313_device::set_lv4irqline_callback(*device, DEVCB_##_write); + +#define MCFG_SEGA315_5313_ALT_TIMING(_data) \ + sega315_5313_device::set_alt_timing(*device, _data); + +#define MCFG_SEGA315_5313_PAL_WRITE_BASE(_data) \ + sega315_5313_device::set_palwrite_base(*device, _data); + +#define MCFG_SEGA315_5313_PALETTE(_palette_tag) \ + sega315_5313_device::static_set_palette_tag(*device, "^" _palette_tag); + + +// Temporary solution while 32x VDP mixing and scanline interrupting is moved outside MD VDP +typedef device_delegate md_32x_scanline_delegate; +typedef device_delegate md_32x_interrupt_delegate; +typedef device_delegate md_32x_scanline_helper_delegate; + +#define MCFG_SEGA315_5313_32X_SCANLINE_CB(_class, _method) \ + sega315_5313_device::set_md_32x_scanline(*device, md_32x_scanline_delegate(&_class::_method, #_class "::" #_method, downcast<_class *>(owner))); + +#define MCFG_SEGA315_5313_32X_INTERRUPT_CB(_class, _method) \ + sega315_5313_device::set_md_32x_interrupt(*device, md_32x_interrupt_delegate(&_class::_method, #_class "::" #_method, downcast<_class *>(owner))); + +#define MCFG_SEGA315_5313_32X_SCANLINE_HELPER_CB(_class, _method) \ + sega315_5313_device::set_md_32x_scanline_helper(*device, md_32x_scanline_helper_delegate(&_class::_method, #_class "::" #_method, downcast<_class *>(owner))); + + +class sega315_5313_device : public sega315_5124_device +{ +public: + sega315_5313_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + template static devcb_base &set_sndirqline_callback(device_t &device, _Object object) { return downcast(device).m_sndirqline_callback.set_callback(object); } + template static devcb_base &set_lv6irqline_callback(device_t &device, _Object object) { return downcast(device).m_lv6irqline_callback.set_callback(object); } + template static devcb_base &set_lv4irqline_callback(device_t &device, _Object object) { return downcast(device).m_lv4irqline_callback.set_callback(object); } + static void set_alt_timing(device_t &device, int use_alt_timing); + static void set_palwrite_base(device_t &device, int palwrite_base); + static void static_set_palette_tag(device_t &device, const char *tag); + + static void set_md_32x_scanline(device_t &device, md_32x_scanline_delegate callback) { downcast(device).m_32x_scanline_func = callback; } + static void set_md_32x_interrupt(device_t &device, md_32x_interrupt_delegate callback) { downcast(device).m_32x_interrupt_func = callback; } + static void set_md_32x_scanline_helper(device_t &device, md_32x_scanline_helper_delegate callback) { downcast(device).m_32x_scanline_helper_func = callback; } + + int m_use_alt_timing; // use MAME scanline timer instead, render only one scanline to a single line buffer, to be rendered by a partial update call.. experimental + + int m_palwrite_base; // if we want to write to the actual MAME palette.. + + DECLARE_READ16_MEMBER( vdp_r ); + DECLARE_WRITE16_MEMBER( vdp_w ); + + int get_scanline_counter(); + + void render_scanline(); + void vdp_handle_scanline_callback(int scanline); + void vdp_handle_irq6_on_timer_callback(int param); + void vdp_handle_irq4_on_timer_callback(int param); + void vdp_handle_eof(); + void device_reset_old(); + void vdp_clear_irq6_pending(void) { m_irq6_pending = 0; }; + void vdp_clear_irq4_pending(void) { m_irq4_pending = 0; }; + + // set some VDP variables at start (shall be moved to a device interface?) + void set_scanline_counter(int scanline) { m_scanline_counter = scanline; } + void set_total_scanlines(int total) { m_base_total_scanlines = total; } + void set_framerate(int rate) { m_framerate = rate; } + void set_vdp_pal(bool pal) { m_vdp_pal = pal ? 1 : 0; } + void set_use_cram(int cram) { m_use_cram = cram; } + void set_dma_delay(int delay) { m_dma_delay = delay; } + int get_framerate() { return m_framerate; } + int get_imode() { return m_imode; } + + + void vdp_clear_bitmap(void) + { + if (m_render_bitmap) + m_render_bitmap->fill(0); + } + + bitmap_ind16* m_render_bitmap; + UINT16* m_render_line; + UINT16* m_render_line_raw; + + TIMER_DEVICE_CALLBACK_MEMBER( megadriv_scanline_timer_callback_alt_timing ); + TIMER_DEVICE_CALLBACK_MEMBER( megadriv_scanline_timer_callback ); + timer_device* m_megadriv_scanline_timer; + + inline UINT16 vdp_get_word_from_68k_mem(UINT32 source); + +protected: + virtual void device_start(); + virtual void device_reset(); + virtual machine_config_constructor device_mconfig_additions() const; + + // called when we hit 240 and 241 (used to control the z80 irq line on genesis, or the main irq on c2) + devcb_write_line m_sndirqline_callback; + devcb_write_line m_lv6irqline_callback; + devcb_write_line m_lv4irqline_callback; + + md_32x_scanline_delegate m_32x_scanline_func; + md_32x_interrupt_delegate m_32x_interrupt_func; + md_32x_scanline_helper_delegate m_32x_scanline_helper_func; + +private: + + int m_command_pending; // 2nd half of command pending.. + UINT16 m_command_part1; + UINT16 m_command_part2; + UINT8 m_vdp_code; + UINT16 m_vdp_address; + UINT8 m_vram_fill_pending; + UINT16 m_vram_fill_length; + int m_irq4counter; + int m_imode_odd_frame; + int m_sprite_collision; + int m_irq6_pending; + int m_irq4_pending; + int m_scanline_counter; + int m_vblank_flag; + + int m_imode; + + int m_visible_scanlines; + int m_irq6_scanline; + int m_z80irq_scanline; + int m_total_scanlines; + // this is only set at init: 262 for PAL, 313 for NTSC + int m_base_total_scanlines; + + int m_framerate; + int m_vdp_pal; + int m_use_cram; // c2 uses it's own palette ram, so it sets this to 0 + int m_dma_delay; // SVP and SegaCD have some 'lag' in DMA transfers + + UINT16* m_regs; + UINT16* m_vram; + UINT16* m_cram; + UINT16* m_vsram; + /* The VDP keeps a 0x400 byte on-chip cache of the Sprite Attribute Table + to speed up processing, Castlevania Bloodlines abuses this on the upside down level */ + UINT16* m_internal_sprite_attribute_table; + + // these are used internally by the VDP to schedule when after the start of a scanline + // to trigger the various interrupts / rendering to our bitmap, bit of a hack really + emu_timer* m_irq6_on_timer; + emu_timer* m_irq4_on_timer; + emu_timer* m_render_timer; + + UINT16 vdp_vram_r(void); + UINT16 vdp_vsram_r(void); + UINT16 vdp_cram_r(void); + + void insta_68k_to_cram_dma(UINT32 source,UINT16 length); + void insta_68k_to_vsram_dma(UINT32 source,UINT16 length); + void insta_68k_to_vram_dma(UINT32 source,int length); + void insta_vram_copy(UINT32 source, UINT16 length); + + void vdp_vram_write(UINT16 data); + void vdp_cram_write(UINT16 data); + void write_cram_value(int offset, int data); + void vdp_vsram_write(UINT16 data); + + void vdp_set_register(int regnum, UINT8 value); + + void handle_dma_bits(); + + UINT16 get_hposition(); + UINT16 megadriv_read_hv_counters(); + + UINT16 ctrl_port_r(); + UINT16 data_port_r(); + void data_port_w(int data); + void ctrl_port_w(int data); + void update_code_and_address(void); + + + void render_spriteline_to_spritebuffer(int scanline); + void render_videoline_to_videobuffer(int scanline); + void render_videobuffer_to_screenbuffer(int scanline); + + /* variables used during emulation - not saved */ + UINT8* m_sprite_renderline; + UINT8* m_highpri_renderline; + UINT32* m_video_renderline; + UINT16* m_palette_lookup; + UINT16* m_palette_lookup_sprite; // for C2 + UINT16* m_palette_lookup_shadow; + UINT16* m_palette_lookup_highlight; + + address_space *m_space68k; + m68000_base_device* m_cpu68k; +}; + + +extern const device_type SEGA315_5313; diff --git a/src/devices/video/bufsprite.c b/src/devices/video/bufsprite.c new file mode 100644 index 00000000000..bc9717d8ef7 --- /dev/null +++ b/src/devices/video/bufsprite.c @@ -0,0 +1,23 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/********************************************************************* + + bufsprite.h + + Buffered Sprite RAM device. + +*********************************************************************/ + +#include "emu.h" +#include "bufsprite.h" + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +// device type definition +extern const device_type BUFFERED_SPRITERAM8 = &device_creator; +extern const device_type BUFFERED_SPRITERAM16 = &device_creator; +extern const device_type BUFFERED_SPRITERAM32 = &device_creator; +extern const device_type BUFFERED_SPRITERAM64 = &device_creator; diff --git a/src/devices/video/bufsprite.h b/src/devices/video/bufsprite.h new file mode 100644 index 00000000000..86fb699085a --- /dev/null +++ b/src/devices/video/bufsprite.h @@ -0,0 +1,143 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/********************************************************************* + + bufsprite.h + + Buffered Sprite RAM device. + +*********************************************************************/ + +#pragma once + +#ifndef __BUFSPRITE_H__ +#define __BUFSPRITE_H__ + + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +// device type definition +extern const device_type BUFFERED_SPRITERAM8; +extern const device_type BUFFERED_SPRITERAM16; +extern const device_type BUFFERED_SPRITERAM32; +extern const device_type BUFFERED_SPRITERAM64; + + + +//************************************************************************** +// DEVICE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_BUFFERED_SPRITERAM8_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, BUFFERED_SPRITERAM8, 0) +#define MCFG_BUFFERED_SPRITERAM16_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, BUFFERED_SPRITERAM16, 0) +#define MCFG_BUFFERED_SPRITERAM32_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, BUFFERED_SPRITERAM32, 0) +#define MCFG_BUFFERED_SPRITERAM64_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, BUFFERED_SPRITERAM64, 0) + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> buffered_spriteram_device + +// base class to manage buffered spriteram +template +class buffered_spriteram_device : public device_t +{ +public: + // construction + buffered_spriteram_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, type, "Buffered Sprite RAM", tag, owner, clock, "buffered_spriteram", __FILE__), + m_spriteram(*owner, tag) { } + + // getters + _Type *live() const { return m_spriteram; } + _Type *buffer() { return &m_buffered[0]; } + UINT32 bytes() const { return m_spriteram.bytes(); } + + // operations + _Type *copy(UINT32 srcoffset = 0, UINT32 srclength = 0x7fffffff) + { + assert(m_spriteram != NULL); + if (m_spriteram != NULL) + memcpy(&m_buffered[0], m_spriteram + srcoffset, MIN(srclength, m_spriteram.bytes() / sizeof(_Type) - srcoffset) * sizeof(_Type)); + return &m_buffered[0]; + } + + // read/write handlers + void write(address_space &space, offs_t offset, _Type data, _Type mem_mask = ~_Type(0)) { copy(); } + + // VBLANK handlers + void vblank_copy_rising(screen_device &screen, bool state) { if (state) copy(); } + void vblank_copy_falling(screen_device &screen, bool state) { if (!state) copy(); } + +protected: + // first-time setup + virtual void device_start() + { + if (m_spriteram != NULL) + { + m_buffered.resize(m_spriteram.bytes() / sizeof(_Type)); + save_item(NAME(m_buffered)); + } + } + +private: + // internal state + required_shared_ptr<_Type> m_spriteram; + std::vector<_Type> m_buffered; +}; + + +// ======================> buffered_spriteram8_device + +class buffered_spriteram8_device : public buffered_spriteram_device +{ +public: + // construction + buffered_spriteram8_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : buffered_spriteram_device(mconfig, BUFFERED_SPRITERAM8, tag, owner, clock) { } +}; + + +// ======================> buffered_spriteram16_device + +class buffered_spriteram16_device : public buffered_spriteram_device +{ +public: + // construction + buffered_spriteram16_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : buffered_spriteram_device(mconfig, BUFFERED_SPRITERAM16, tag, owner, clock) { } +}; + + +// ======================> buffered_spriteram32_device + +class buffered_spriteram32_device : public buffered_spriteram_device +{ +public: + // construction + buffered_spriteram32_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : buffered_spriteram_device(mconfig, BUFFERED_SPRITERAM32, tag, owner, clock) { } +}; + + +// ======================> buffered_spriteram64_device + +class buffered_spriteram64_device : public buffered_spriteram_device +{ +public: + // construction + buffered_spriteram64_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : buffered_spriteram_device(mconfig, BUFFERED_SPRITERAM64, tag, owner, clock) { } +}; + + +#endif /* __BUFSPRITE_H__ */ diff --git a/src/devices/video/cdp1861.c b/src/devices/video/cdp1861.c new file mode 100644 index 00000000000..a02309decca --- /dev/null +++ b/src/devices/video/cdp1861.c @@ -0,0 +1,253 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + RCA CDP1861 Video Display Controller emulation + +**********************************************************************/ + +#include "emu.h" +#include "cdp1861.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define CDP1861_CYCLES_DMA_START 2*8 +#define CDP1861_CYCLES_DMA_ACTIVE 8*8 +#define CDP1861_CYCLES_DMA_WAIT 6*8 + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +// device type definition +const device_type CDP1861 = &device_creator; + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// cdp1861_device - constructor +//------------------------------------------------- + +cdp1861_device::cdp1861_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, CDP1861, "CDP1861", tag, owner, clock, "cdp1861", __FILE__), + device_video_interface(mconfig, *this), + m_write_irq(*this), + m_write_dma_out(*this), + m_write_efx(*this), + m_disp(0), + m_dispon(0), + m_dispoff(0), + m_dmaout(CLEAR_LINE) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void cdp1861_device::device_start() +{ + // resolve callbacks + m_write_irq.resolve_safe(); + m_write_dma_out.resolve_safe(); + m_write_efx.resolve_safe(); + + // allocate timers + m_int_timer = timer_alloc(TIMER_INT); + m_efx_timer = timer_alloc(TIMER_EFX); + m_dma_timer = timer_alloc(TIMER_DMA); + + // find devices + m_screen->register_screen_bitmap(m_bitmap); + + // register for state saving + save_item(NAME(m_disp)); + save_item(NAME(m_dispon)); + save_item(NAME(m_dispoff)); + save_item(NAME(m_dmaout)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void cdp1861_device::device_reset() +{ + m_int_timer->adjust(m_screen->time_until_pos(CDP1861_SCANLINE_INT_START, 0)); + m_efx_timer->adjust(m_screen->time_until_pos(CDP1861_SCANLINE_EFX_TOP_START, 0)); + m_dma_timer->adjust(clocks_to_attotime(CDP1861_CYCLES_DMA_START)); + + m_disp = 0; + m_dmaout = 0; + m_dispon = 0; + + m_write_irq(CLEAR_LINE); + m_write_dma_out(CLEAR_LINE); + m_write_efx(CLEAR_LINE); +} + + +//------------------------------------------------- +// device_timer - handle timer events +//------------------------------------------------- + +void cdp1861_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + int scanline = m_screen->vpos(); + + switch (id) + { + case TIMER_INT: + if (scanline == CDP1861_SCANLINE_INT_START) + { + if (m_disp) + { + m_write_irq(ASSERT_LINE); + } + + m_int_timer->adjust(m_screen->time_until_pos( CDP1861_SCANLINE_INT_END, 0)); + } + else + { + if (m_disp) + { + m_write_irq(CLEAR_LINE); + } + + m_int_timer->adjust(m_screen->time_until_pos(CDP1861_SCANLINE_INT_START, 0)); + } + break; + + case TIMER_EFX: + switch (scanline) + { + case CDP1861_SCANLINE_EFX_TOP_START: + m_write_efx(ASSERT_LINE); + m_efx_timer->adjust(m_screen->time_until_pos(CDP1861_SCANLINE_EFX_TOP_END, 0)); + break; + + case CDP1861_SCANLINE_EFX_TOP_END: + m_write_efx(CLEAR_LINE); + m_efx_timer->adjust(m_screen->time_until_pos(CDP1861_SCANLINE_EFX_BOTTOM_START, 0)); + break; + + case CDP1861_SCANLINE_EFX_BOTTOM_START: + m_write_efx(ASSERT_LINE); + m_efx_timer->adjust(m_screen->time_until_pos(CDP1861_SCANLINE_EFX_BOTTOM_END, 0)); + break; + + case CDP1861_SCANLINE_EFX_BOTTOM_END: + m_write_efx(CLEAR_LINE); + m_efx_timer->adjust(m_screen->time_until_pos(CDP1861_SCANLINE_EFX_TOP_START, 0)); + break; + } + break; + + case TIMER_DMA: + if (m_dmaout) + { + if (m_disp) + { + if (scanline >= CDP1861_SCANLINE_DISPLAY_START && scanline < CDP1861_SCANLINE_DISPLAY_END) + { + m_write_dma_out(CLEAR_LINE); + } + } + + m_dma_timer->adjust(clocks_to_attotime(CDP1861_CYCLES_DMA_WAIT)); + + m_dmaout = CLEAR_LINE; + } + else + { + if (m_disp) + { + if (scanline >= CDP1861_SCANLINE_DISPLAY_START && scanline < CDP1861_SCANLINE_DISPLAY_END) + { + m_write_dma_out(ASSERT_LINE); + } + } + + m_dma_timer->adjust(clocks_to_attotime(CDP1861_CYCLES_DMA_ACTIVE)); + + m_dmaout = ASSERT_LINE; + } + break; + } +} + + +//------------------------------------------------- +// dma_w - +//------------------------------------------------- + +WRITE8_MEMBER( cdp1861_device::dma_w ) +{ + int sx = m_screen->hpos() + 4; + int y = m_screen->vpos(); + int x; + + for (x = 0; x < 8; x++) + { + pen_t color = BIT(data, 7) ? rgb_t::white : rgb_t::black; + m_bitmap.pix32(y, sx + x) = color; + data <<= 1; + } +} + + +//------------------------------------------------- +// disp_on_w - +//------------------------------------------------- + +WRITE_LINE_MEMBER( cdp1861_device::disp_on_w ) +{ + if (!m_dispon && state) m_disp = 1; + + m_dispon = state; +} + + +//------------------------------------------------- +// disp_off_w - +//------------------------------------------------- + +WRITE_LINE_MEMBER( cdp1861_device::disp_off_w ) +{ + if (!m_dispon && !m_dispoff && state) m_disp = 0; + + m_dispoff = state; + + m_write_irq(CLEAR_LINE); + m_write_dma_out(CLEAR_LINE); +} + + +//------------------------------------------------- +// screen_update - +//------------------------------------------------- + +UINT32 cdp1861_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + if (m_disp) + { + copybitmap(bitmap, m_bitmap, 0, 0, 0, 0, cliprect); + } + else + { + bitmap.fill(rgb_t::black, cliprect); + } + return 0; +} diff --git a/src/devices/video/cdp1861.h b/src/devices/video/cdp1861.h new file mode 100644 index 00000000000..ccf6938173b --- /dev/null +++ b/src/devices/video/cdp1861.h @@ -0,0 +1,145 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + RCA CDP1861 Video Display Controller emulation + +********************************************************************** + _____ _____ + _CLK 1 |* \_/ | 24 Vdd + _DMAO 2 | | 23 _CLEAR + _INT 3 | | 22 SC1 + TPA 4 | | 21 SC0 + TPB 5 | | 20 DI7 + _COMP SYNC 6 | CDP1861 | 19 DI6 + VIDEO 7 | | 18 DI5 + _RESET 8 | | 17 DI4 + _EFX 9 | | 16 DI3 + DISP ON 10 | | 15 DI2 + DISP OFF 11 | | 14 DI1 + Vss 12 |_____________| 13 DI0 + +**********************************************************************/ + +#pragma once + +#ifndef __CDP1861__ +#define __CDP1861__ + +#include "emu.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define CDP1861_VISIBLE_COLUMNS 64 +#define CDP1861_VISIBLE_LINES 128 + +#define CDP1861_HBLANK_START 14 * 8 +#define CDP1861_HBLANK_END 12 +#define CDP1861_HSYNC_START 0 +#define CDP1861_HSYNC_END 12 +#define CDP1861_SCREEN_WIDTH 14 * 8 + +#define CDP1861_TOTAL_SCANLINES 262 + +#define CDP1861_SCANLINE_DISPLAY_START 80 +#define CDP1861_SCANLINE_DISPLAY_END 208 +#define CDP1861_SCANLINE_VBLANK_START 262 +#define CDP1861_SCANLINE_VBLANK_END 16 +#define CDP1861_SCANLINE_VSYNC_START 16 +#define CDP1861_SCANLINE_VSYNC_END 0 +#define CDP1861_SCANLINE_INT_START CDP1861_SCANLINE_DISPLAY_START - 2 +#define CDP1861_SCANLINE_INT_END CDP1861_SCANLINE_DISPLAY_START +#define CDP1861_SCANLINE_EFX_TOP_START CDP1861_SCANLINE_DISPLAY_START - 4 +#define CDP1861_SCANLINE_EFX_TOP_END CDP1861_SCANLINE_DISPLAY_START +#define CDP1861_SCANLINE_EFX_BOTTOM_START CDP1861_SCANLINE_DISPLAY_END - 4 +#define CDP1861_SCANLINE_EFX_BOTTOM_END CDP1861_SCANLINE_DISPLAY_END + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_CDP1861_IRQ_CALLBACK(_write) \ + devcb = &cdp1861_device::set_irq_wr_callback(*device, DEVCB_##_write); + +#define MCFG_CDP1861_DMA_OUT_CALLBACK(_write) \ + devcb = &cdp1861_device::set_dma_out_wr_callback(*device, DEVCB_##_write); + +#define MCFG_CDP1861_EFX_CALLBACK(_write) \ + devcb = &cdp1861_device::set_efx_wr_callback(*device, DEVCB_##_write); + + +#define MCFG_CDP1861_SCREEN_ADD(_cdptag, _tag, _clock) \ + MCFG_VIDEO_SET_SCREEN(_tag) \ + MCFG_SCREEN_ADD(_tag, RASTER) \ + MCFG_SCREEN_UPDATE_DEVICE(_cdptag, cdp1861_device, screen_update) \ + MCFG_SCREEN_RAW_PARAMS(_clock, CDP1861_SCREEN_WIDTH, CDP1861_HBLANK_END, CDP1861_HBLANK_START, CDP1861_TOTAL_SCANLINES, CDP1861_SCANLINE_VBLANK_END, CDP1861_SCANLINE_VBLANK_START) + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> cdp1861_device + +class cdp1861_device : public device_t, + public device_video_interface +{ +public: + // construction/destruction + cdp1861_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + template static devcb_base &set_irq_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_irq.set_callback(object); } + template static devcb_base &set_dma_out_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_dma_out.set_callback(object); } + template static devcb_base &set_efx_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_efx.set_callback(object); } + + DECLARE_WRITE8_MEMBER( dma_w ); + DECLARE_WRITE_LINE_MEMBER( disp_on_w ); + DECLARE_WRITE_LINE_MEMBER( disp_off_w ); + + UINT32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); + + bitmap_rgb32 m_bitmap; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + +private: + enum + { + TIMER_INT, + TIMER_EFX, + TIMER_DMA + }; + + devcb_write_line m_write_irq; + devcb_write_line m_write_dma_out; + devcb_write_line m_write_efx; + + int m_disp; // display enabled + int m_dispon; // display on latch + int m_dispoff; // display off latch + int m_dmaout; // DMA request active + + // timers + emu_timer *m_int_timer; // interrupt timer + emu_timer *m_efx_timer; // EFx timer + emu_timer *m_dma_timer; // DMA timer +}; + + +// device type definition +extern const device_type CDP1861; + + + +#endif diff --git a/src/devices/video/cdp1862.c b/src/devices/video/cdp1862.c new file mode 100644 index 00000000000..e75cb66c888 --- /dev/null +++ b/src/devices/video/cdp1862.c @@ -0,0 +1,198 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + RCA CDP1862 Video Display Controller emulation + +**********************************************************************/ + +#include "cdp1862.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +static const int CDP1862_BACKGROUND_COLOR_SEQUENCE[] = { 2, 0, 1, 4 }; + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +// device type definition +const device_type CDP1862 = &device_creator; + + + +//************************************************************************** +// INLINE HELPERS +//************************************************************************** + +//------------------------------------------------- +// initialize_palette - +//------------------------------------------------- + +inline void cdp1862_device::initialize_palette() +{ + int i; + + double res_total = m_chr_r + m_chr_g + m_chr_b + m_chr_bkg; + + int weight_r = (m_chr_r / res_total) * 100; + int weight_g = (m_chr_g / res_total) * 100; + int weight_b = (m_chr_b / res_total) * 100; + int weight_bkg = (m_chr_bkg / res_total) * 100; + + for (i = 0; i < 16; i++) + { + int r, g, b, luma = 0; + + luma += (i & 4) ? weight_r : 0; + luma += (i & 1) ? weight_g : 0; + luma += (i & 2) ? weight_b : 0; + luma += (i & 8) ? 0 : weight_bkg; + + luma = (luma * 0xff) / 100; + + r = (i & 4) ? luma : 0; + g = (i & 1) ? luma : 0; + b = (i & 2) ? luma : 0; + + m_palette[i] = rgb_t(r, g, b); + } +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// cdp1862_device - constructor +//------------------------------------------------- + +cdp1862_device::cdp1862_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, CDP1862, "CDP1862", tag, owner, clock, "cdp1862", __FILE__), + device_video_interface(mconfig, *this), + m_read_rd(*this), + m_read_bd(*this), + m_read_gd(*this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void cdp1862_device::device_start() +{ + // resolve callbacks + m_read_rd.resolve_safe(0); + m_read_bd.resolve_safe(0); + m_read_gd.resolve_safe(0); + + // find devices + m_screen->register_screen_bitmap(m_bitmap); + + // init palette + initialize_palette(); + + // register for state saving + save_item(NAME(m_bgcolor)); + save_item(NAME(m_con)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void cdp1862_device::device_reset() +{ + m_bgcolor = 0; + m_con = 1; +} + + +//------------------------------------------------- +// dma_w - +//------------------------------------------------- + +WRITE8_MEMBER( cdp1862_device::dma_w ) +{ + int rd = 1, bd = 1, gd = 1; + int sx = m_screen->hpos() + 4; + int y = m_screen->vpos(); + int x; + + if (!m_con) + { + rd = m_read_rd(); + bd = m_read_bd(); + gd = m_read_gd(); + } + + for (x = 0; x < 8; x++) + { + int color = CDP1862_BACKGROUND_COLOR_SEQUENCE[m_bgcolor] + 8; + + if (BIT(data, 7)) + { + color = (gd << 2) | (bd << 1) | rd; + } + + m_bitmap.pix32(y, sx + x) = m_palette[color]; + + data <<= 1; + } +} + + +//------------------------------------------------- +// disp_on_w - +//------------------------------------------------- + +WRITE_LINE_MEMBER( cdp1862_device::bkg_w ) +{ + if (state) + { + m_bgcolor++; + + if (m_bgcolor > 3) + { + m_bgcolor = 0; + } + } +} + + +//------------------------------------------------- +// disp_off_w - +//------------------------------------------------- + +WRITE_LINE_MEMBER( cdp1862_device::con_w ) +{ + if (!state) + { + m_con = 0; + } +} + + +//------------------------------------------------- +// screen_update - +//------------------------------------------------- + +UINT32 cdp1862_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + copybitmap(bitmap, m_bitmap, 0, 0, 0, 0, cliprect); + + m_bitmap.fill(m_palette[CDP1862_BACKGROUND_COLOR_SEQUENCE[m_bgcolor] + 8], cliprect); + + return 0; +} diff --git a/src/devices/video/cdp1862.h b/src/devices/video/cdp1862.h new file mode 100644 index 00000000000..159c12f8a3c --- /dev/null +++ b/src/devices/video/cdp1862.h @@ -0,0 +1,123 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + RCA CDP1862 COS/MOS Color Generator Controller emulation + +********************************************************************** + _____ _____ + RD 1 |* \_/ | 24 Vdd + _RESET 2 | | 23 R LUM + _CON 3 | | 22 G LUM + B CHR 4 | | 21 GD + B LUM 5 | | 20 BKG LUM + BKG 6 | CDP1862 | 19 G CHR + _LD CLK 7 | | 18 R CHR + STP 8 | | 17 BKG CHR + CLK OUT 9 | | 16 BD + _SYNC 10 | | 15 BURST + LUM IN 11 | | 14 _XTAL + Vss 12 |_____________| 13 XTAL + +**********************************************************************/ + +#pragma once + +#ifndef __CDP1862__ +#define __CDP1862__ + +#include "emu.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define CPD1862_CLOCK XTAL_7_15909MHz + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_CDP1861_RD_CALLBACK(_read) \ + devcb = &cdp1862_device::set_rd_rd_callback(*device, DEVCB_##_read); + +#define MCFG_CDP1861_BD_CALLBACK(_read) \ + devcb = &cdp1862_device::set_bd_rd_callback(*device, DEVCB_##_read); + +#define MCFG_CDP1861_GD_CALLBACK(_read) \ + devcb = &cdp1862_device::set_gd_rd_callback(*device, DEVCB_##_read); + +#define MCFG_CDP1862_LUMINANCE(_r, _b, _g, _bkg) \ + cdp1862_device::static_set_luminance(*device, _r, _b, _g, _bkg); + +#define MCFG_CDP1862_CHROMINANCE(_r, _b, _g, _bkg) \ + cdp1862_device::static_set_chrominance(*device, _r, _b, _g, _bkg); + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> cdp1862_device + +class cdp1862_device : public device_t, + public device_video_interface +{ +public: + // construction/destruction + cdp1862_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + template static devcb_base &set_rd_rd_callback(device_t &device, _Object object) { return downcast(device).m_read_rd.set_callback(object); } + template static devcb_base &set_bd_rd_callback(device_t &device, _Object object) { return downcast(device).m_read_bd.set_callback(object); } + template static devcb_base &set_gd_rd_callback(device_t &device, _Object object) { return downcast(device).m_read_gd.set_callback(object); } + + static void static_set_luminance(device_t &device, double r, double b, double g, double bkg) { downcast(device).m_lum_r = r; downcast(device).m_lum_b = b; downcast(device).m_lum_g = g; downcast(device).m_lum_bkg = bkg; } + static void static_set_chrominance(device_t &device, double r, double b, double g, double bkg) { downcast(device).m_chr_r = r; downcast(device).m_chr_b = b; downcast(device).m_chr_g = g; downcast(device).m_chr_bkg = bkg; } + + DECLARE_WRITE8_MEMBER( dma_w ); + DECLARE_WRITE_LINE_MEMBER( bkg_w ); + DECLARE_WRITE_LINE_MEMBER( con_w ); + + UINT32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + +private: + inline void initialize_palette(); + + devcb_read_line m_read_rd; + devcb_read_line m_read_bd; + devcb_read_line m_read_gd; + + bitmap_rgb32 m_bitmap; // bitmap + + double m_lum_r; // red luminance resistor value + double m_lum_b; // blue luminance resistor value + double m_lum_g; // green luminance resistor value + double m_lum_bkg; // background luminance resistor value + + double m_chr_r; // red chrominance resistor value + double m_chr_b; // blue chrominance resistor value + double m_chr_g; // green chrominance resistor value + double m_chr_bkg; // background chrominance resistor value + + rgb_t m_palette[16]; + int m_bgcolor; // background color + int m_con; // color on +}; + + +// device type definition +extern const device_type CDP1862; + + + +#endif diff --git a/src/devices/video/cgapal.c b/src/devices/video/cgapal.c new file mode 100644 index 00000000000..396c313c1ba --- /dev/null +++ b/src/devices/video/cgapal.c @@ -0,0 +1,433 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol + +/* CGA palettes + * + * The first 16 are for RGB monitors + * The next 16 are for greyscale modes + * The next 16 are for text modes on colour composite + * The next 16*16 are Mode 6 (colour composite) } + * The next 64*16 are Mode 4 (colour composite) } both indexed by the CGA colour select register 0x3D9 + * + */ + +#include "video/cgapal.h" + +const unsigned char cga_palette[16 * CGA_PALETTE_SETS][3] = +{ +/* RGB colours */ + { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0xaa }, { 0x00, 0xaa, 0x00 }, { 0x00, 0xaa, 0xaa }, + { 0xaa, 0x00, 0x00 }, { 0xaa, 0x00, 0xaa }, { 0xaa, 0x55, 0x00 }, { 0xaa, 0xaa, 0xaa }, + { 0x55, 0x55, 0x55 }, { 0x55, 0x55, 0xff }, { 0x55, 0xff, 0x55 }, { 0x55, 0xff, 0xff }, + { 0xff, 0x55, 0x55 }, { 0xff, 0x55, 0xff }, { 0xff, 0xff, 0x55 }, { 0xff, 0xff, 0xff }, +/* Greyscale */ + { 0x00, 0x00, 0x00 }, { 0x11, 0x11, 0x11 }, { 0x44, 0x44, 0x44 }, { 0x55, 0x55, 0x55 }, + { 0x22, 0x22, 0x22 }, { 0x33, 0x33, 0x33 }, { 0x66, 0x66, 0x66 }, { 0x77, 0x77, 0x77 }, + { 0x88, 0x88, 0x88 }, { 0x99, 0x99, 0x99 }, { 0xCC, 0xCC, 0xCC }, { 0xDD, 0xDD, 0xDD }, + { 0xAA, 0xAA, 0xAA }, { 0xBB, 0xBB, 0xBB }, { 0xEE, 0xEE, 0xEE }, { 0xFF, 0xFF, 0xFF }, +/* Text mode, composite monitor */ + { 0x00, 0x00, 0x00 }, { 0x0E, 0x00, 0x7A }, { 0x07, 0x55, 0x00 }, { 0x02, 0x65, 0x39 }, + { 0x51, 0x00, 0x1A }, { 0x54, 0x00, 0x76 }, { 0x48, 0x63, 0x00 }, { 0x8c, 0x8c, 0x8c }, + { 0x38, 0x38, 0x38 }, { 0x58, 0x49, 0xD5 }, { 0x5F, 0xAD, 0x26 }, { 0x5B, 0xB9, 0xAC }, + { 0xAA, 0x4A, 0x5E }, { 0xA7, 0x55, 0xD2 }, { 0xA2, 0xB9, 0x31 }, { 0xE2, 0xE2, 0xE2 }, +/* Composite hi-res, colour reg = 0 */ + { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 }, +/* Composite hi-res, colour reg = 1 */ + { 0x00, 0x00, 0x00 }, { 0x00, 0x04, 0x04 }, { 0x00, 0x00, 0x61 }, { 0x00, 0x00, 0x6b }, + { 0x25, 0x00, 0x1E }, { 0x15, 0x00, 0x23 }, { 0x18, 0x00, 0x87 }, { 0x06, 0x00, 0x91 }, + { 0x00, 0x00, 0x00 }, { 0x00, 0x0b, 0x00 }, { 0x00, 0x00, 0x4C }, { 0x00, 0x02, 0x52 }, + { 0x24, 0x00, 0x08 }, { 0x0E, 0x00, 0x0D }, { 0x18, 0x00, 0x6f }, { 0x07, 0x00, 0x7C }, +/* Composite hi-res, colour reg = 2 */ + { 0x00, 0x00, 0x00 }, { 0x00, 0x28, 0x00 }, { 0x01, 0x00, 0x46 }, { 0x00, 0x21, 0x36 }, + { 0x22, 0x00, 0x01 }, { 0x00, 0x21, 0x00 }, { 0x1b, 0x00, 0x43 }, { 0x00, 0x22, 0x33 }, + { 0x07, 0x0D, 0x00 }, { 0x00, 0x4B, 0x00 }, { 0x04, 0x0E, 0x00 }, { 0x00, 0x57, 0x00 }, + { 0x25, 0x02, 0x00 }, { 0x01, 0x46, 0x00 }, { 0x30, 0x04, 0x00 }, { 0x04, 0x53, 0x00 }, +/* Composite hi-res, colour reg = 3 */ + { 0x00, 0x00, 0x00 }, { 0x00, 0x30, 0x00 }, { 0x00, 0x00, 0x8E }, { 0x00, 0x38, 0x87 }, + { 0x2E, 0x00, 0x01 }, { 0x00, 0x21, 0x00 }, { 0x22, 0x00, 0x8C }, { 0x00, 0x35, 0x95 }, + { 0x00, 0x0F, 0x00 }, { 0x00, 0x4F, 0x00 }, { 0x00, 0x0B, 0x3F }, { 0x00, 0x62, 0x45 }, + { 0x29, 0x00, 0x00 }, { 0x00, 0x4E, 0x00 }, { 0x35, 0x04, 0x48 }, { 0x01, 0x62, 0x49 }, +/* Composite hi-res, colour reg = 4 */ + { 0x00, 0x00, 0x00 }, { 0x00, 0x06, 0x02 }, { 0x01, 0x00, 0x1f }, { 0x00, 0x00, 0x24 }, + { 0x54, 0x00, 0x38 }, { 0x25, 0x00, 0x23 }, { 0x3A, 0x00, 0x4f }, { 0x29, 0x00, 0x56 }, + { 0x10, 0x03, 0x00 }, { 0x06, 0x08, 0x00 }, { 0x15, 0x00, 0x00 }, { 0x02, 0x03, 0x00 }, + { 0x82, 0x00, 0x00 }, { 0x49, 0x00, 0x00 }, { 0x5B, 0x00, 0x0b }, { 0x52, 0x00, 0x0c }, +/* Composite hi-res, colour reg = 5 */ + { 0x00, 0x00, 0x00 }, { 0x00, 0x2c, 0x00 }, { 0x06, 0x01, 0x57 }, { 0x00, 0x22, 0x42 }, + { 0x33, 0x00, 0x01 }, { 0x00, 0x26, 0x00 }, { 0x3a, 0x00, 0x54 }, { 0x08, 0x1D, 0x54 }, + { 0x13, 0x17, 0x00 }, { 0x00, 0x64, 0x00 }, { 0x29, 0x15, 0x00 }, { 0x00, 0x64, 0x00 }, + { 0x59, 0x0A, 0x00 }, { 0x30, 0x61, 0x00 }, { 0x7A, 0x06, 0x00 }, { 0x4A, 0x64, 0x00 }, +/* Composite hi-res, colour reg = 6 */ + { 0x00, 0x00, 0x00 }, { 0x00, 0x33, 0x00 }, { 0x06, 0x00, 0x5E }, { 0x00, 0x22, 0x45 }, + { 0x34, 0x00, 0x04 }, { 0x00, 0x1e, 0x00 }, { 0x3d, 0x00, 0x4c }, { 0x0c, 0x22, 0x58 }, + { 0x18, 0x19, 0x00 }, { 0x00, 0x62, 0x00 }, { 0x2b, 0x14, 0x00 }, { 0x01, 0x64, 0x00 }, + { 0x57, 0x0f, 0x00 }, { 0x29, 0x63, 0x00 }, { 0x78, 0x09, 0x00 }, { 0x51, 0x61, 0x00 }, +/* Composite hi-res, colour reg = 7 */ + { 0x00, 0x00, 0x00 }, { 0x00, 0x3C, 0x01 }, { 0x04, 0x00, 0xC5 }, { 0x00, 0x4C, 0xC7 }, + { 0x6A, 0x00, 0x15 }, { 0x28, 0x28, 0x24 }, { 0x8A, 0x00, 0xF8 }, { 0x70, 0x61, 0xFF }, + { 0x20, 0x33, 0x00 }, { 0x00, 0x85, 0x00 }, { 0x2E, 0x25, 0x28 }, { 0x00, 0x98, 0x3B }, + { 0xb1, 0x11, 0x00 }, { 0x6A, 0x75, 0x00 }, { 0xcc, 0x16, 0x81 }, { 0x91, 0x8e, 0x91 }, +/* Composite hi-res, colour reg = 8 */ + { 0x00, 0x00, 0x00 }, { 0x00, 0x12, 0x0F }, { 0x04, 0x00, 0x5F }, { 0x00, 0x02, 0x67 }, + { 0x31, 0x00, 0x01 }, { 0x04, 0x01, 0x04 }, { 0x37, 0x00, 0x52 }, { 0x17, 0x00, 0x6d }, + { 0x00, 0x10, 0x00 }, { 0x00, 0x29, 0x00 }, { 0x04, 0x03, 0x04 }, { 0x00, 0x24, 0x16 }, + { 0x2f, 0x00, 0x00 }, { 0x07, 0x23, 0x00 }, { 0x43, 0x00, 0x08 }, { 0x25, 0x23, 0x24 }, +/* Composite hi-res, colour reg = 9 */ + { 0x00, 0x00, 0x00 }, { 0x00, 0x19, 0x14 }, { 0x00, 0x00, 0xc2 }, { 0x00, 0x1c, 0xed }, + { 0x5e, 0x00, 0x13 }, { 0x2c, 0x03, 0x3a }, { 0x78, 0x00, 0xfa }, { 0x49, 0x11, 0xff }, + { 0x00, 0x15, 0x00 }, { 0x00, 0x40, 0x00 }, { 0x0d, 0x11, 0x68 }, { 0x00, 0x4f, 0x9c }, + { 0x67, 0x00, 0x00 }, { 0x39, 0x36, 0x00 }, { 0x91, 0x05, 0xa6 }, { 0x62, 0x45, 0xdc }, +/* Composite hi-res, colour reg = A */ + { 0x00, 0x00, 0x00 }, { 0x00, 0x4B, 0x08 }, { 0x05, 0x00, 0xAA }, { 0x00, 0x50, 0xc7 }, + { 0x58, 0x00, 0x06 }, { 0x05, 0x44, 0x06 }, { 0x75, 0x00, 0xb0 }, { 0x2e, 0x4f, 0xdc }, + { 0x0c, 0x2f, 0x00 }, { 0x00, 0xa7, 0x00 }, { 0x26, 0x2e, 0x03 }, { 0x00, 0xb4, 0x24 }, + { 0x84, 0x1b, 0x00 }, { 0x2d, 0xa5, 0x00 }, { 0xa5, 0x2a, 0x16 }, { 0x5f, 0xb2, 0x2a }, +/* Composite hi-res, colour reg = B */ + { 0x00, 0x00, 0x00 }, { 0x00, 0x59, 0x07 }, { 0x00, 0x08, 0xf0 }, { 0x00, 0x06, 0xfd }, + { 0x69, 0x00, 0x09 }, { 0x0d, 0x4c, 0x10 }, { 0x8f, 0x00, 0xf4 }, { 0x38, 0x66, 0xff }, + { 0x02, 0x27, 0x00 }, { 0x00, 0xac, 0x00 }, { 0x19, 0x2f, 0x6d }, { 0x00, 0xc5, 0x82 }, + { 0x7b, 0x18, 0x00 }, { 0x30, 0xa7, 0x00 }, { 0xac, 0x2b, 0x81 }, { 0x5b, 0xc0, 0xa4 }, +/* Composite hi-res, colour reg = C */ + { 0x00, 0x00, 0x00 }, { 0x00, 0x1C, 0x0C }, { 0x0a, 0x00, 0x7c }, { 0x00, 0x0d, 0x8f }, + { 0x6e, 0x00, 0x18 }, { 0x48, 0x02, 0x4a }, { 0x95, 0x00, 0xc3 }, { 0x68, 0x01, 0xef }, + { 0x12, 0x1d, 0x00 }, { 0x00, 0x53, 0x00 }, { 0x33, 0x21, 0x00 }, { 0x05, 0x52, 0x13 }, + { 0xb4, 0x09, 0x00 }, { 0x87, 0x41, 0x00 }, { 0xd8, 0x07, 0x3a }, { 0xb0, 0x49, 0x63 }, +/* Composite hi-res, colour reg = D */ + { 0x00, 0x00, 0x00 }, { 0x00, 0x1d, 0x17 }, { 0x00, 0x08, 0xcf }, { 0x00, 0x1b, 0xf2 }, + { 0x83, 0x00, 0x30 }, { 0x4c, 0x08, 0x53 }, { 0xae, 0x00, 0xfa }, { 0x85, 0x0b, 0xff }, + { 0x09, 0x19, 0x00 }, { 0x00, 0x57, 0x00 }, { 0x21, 0x15, 0x4f }, { 0x00, 0x5e, 0x89 }, + { 0xb0, 0x04, 0x00 }, { 0x76, 0x4e, 0x00 }, { 0xe2, 0x0a, 0xa9 }, { 0xae, 0x56, 0xe1 }, +/* Composite hi-res, colour reg = E */ + { 0x00, 0x00, 0x00 }, { 0x00, 0x57, 0x06 }, { 0x17, 0x00, 0xc3 }, { 0x00, 0x55, 0xd9 }, + { 0x6f, 0x00, 0x06 }, { 0x18, 0x49, 0x0d }, { 0xa4, 0x00, 0xcd }, { 0x4e, 0x4c, 0xf7 }, + { 0x1c, 0x3f, 0x00 }, { 0x00, 0xbf, 0x00 }, { 0x51, 0x35, 0x00 }, { 0x06, 0xc4, 0x1b }, + { 0xb6, 0x2d, 0x00 }, { 0x73, 0xb2, 0x00 }, { 0xf5, 0x30, 0x21 }, { 0xaa, 0xbf, 0x2f }, +/* Composite hi-res, colour reg = F */ + { 0x00, 0x00, 0x00 }, { 0x00, 0x68, 0x10 }, { 0x10, 0x00, 0xff }, { 0x00, 0x7c, 0xFF }, + { 0xb3, 0x00, 0x2A }, { 0x53, 0x55, 0x51 }, { 0xf0, 0x00, 0xff }, { 0x95, 0x72, 0xff }, + { 0x25, 0x3e, 0x00 }, { 0x00, 0xda, 0x00 }, { 0x58, 0x52, 0x56 }, { 0x00, 0xf8, 0x7f }, + { 0xf8, 0x2c, 0x00 }, { 0xa8, 0xcf, 0x00 }, { 0xff, 0x41, 0xb8 }, { 0xed, 0xea, 0xed }, +/* Composite lo-res, colour reg = 0 */ + { 0x00, 0x00, 0x00 }, { 0x00, 0x26, 0x34 }, { 0x00, 0x00, 0x24 }, { 0x00, 0x25, 0x46 }, + { 0x29, 0x03, 0x00 }, { 0x04, 0x55, 0x00 }, { 0x1f, 0x0c, 0x00 }, { 0x0e, 0x53, 0x03 }, + { 0x50, 0x00, 0x00 }, { 0x33, 0x36, 0x2b }, { 0x51, 0x00, 0x0b }, { 0x43, 0x37, 0x44 }, + { 0x60, 0x07, 0x00 }, { 0x3c, 0x61, 0x00 }, { 0x59, 0x1c, 0x00 }, { 0x4a, 0x64, 0x00 }, +/* Composite lo-res, colour reg = 1 */ + { 0x07, 0x00, 0x7d }, { 0x00, 0x21, 0x4e }, { 0x15, 0x00, 0x36 }, { 0x04, 0x19, 0x77 }, + { 0x16, 0x1a, 0x00 }, { 0x04, 0x55, 0x00 }, { 0x23, 0x0b, 0x00 }, { 0x13, 0x51, 0x03 }, + { 0x41, 0x02, 0x3e }, { 0x2e, 0x33, 0x24 }, { 0x51, 0x00, 0x14 }, { 0x41, 0x33, 0x46 }, + { 0x51, 0x2b, 0x00 }, { 0x3f, 0x60, 0x00 }, { 0x60, 0x17, 0x00 }, { 0x4d, 0x61, 0x00 }, +/* Composite lo-res, colour reg = 2 */ + { 0x03, 0x55, 0x00 }, { 0x03, 0x55, 0x00 }, { 0x21, 0x0c, 0x00 }, { 0x11, 0x51, 0x03 }, + { 0x03, 0x55, 0x00 }, { 0x03, 0x55, 0x00 }, { 0x21, 0x0c, 0x00 }, { 0x11, 0x51, 0x03 }, + { 0x31, 0x37, 0x29 }, { 0x30, 0x36, 0x2a }, { 0x51, 0x00, 0x11 }, { 0x41, 0x34, 0x46 }, + { 0x3c, 0x63, 0x00 }, { 0x3d, 0x63, 0x00 }, { 0x5f, 0x17, 0x00 }, { 0x4d, 0x61, 0x00 }, +/* Composite lo-res, colour reg = 3 */ + { 0x04, 0x61, 0x4e }, { 0x05, 0x49, 0x02 }, { 0x1f, 0x04, 0x00 }, { 0x12, 0x47, 0x13 }, + { 0x03, 0x68, 0x2f }, { 0x05, 0x54, 0x00 }, { 0x1e, 0x0e, 0x00 }, { 0x0f, 0x51, 0x01 }, + { 0x26, 0x46, 0x73 }, { 0x2f, 0x34, 0x27 }, { 0x50, 0x00, 0x0b }, { 0x48, 0x31, 0x47 }, + { 0x3e, 0x70, 0x1e }, { 0x40, 0x5f, 0x00 }, { 0x57, 0x1d, 0x00 }, { 0x4a, 0x62, 0x00 }, +/* Composite lo-res, colour reg = 4 */ + { 0x52, 0x00, 0x14 }, { 0x2e, 0x32, 0x25 }, { 0x52, 0x00, 0x14 }, { 0x46, 0x2f, 0x47 }, + { 0x1f, 0x09, 0x00 }, { 0x04, 0x55, 0x00 }, { 0x21, 0x0e, 0x00 }, { 0x11, 0x50, 0x02 }, + { 0x52, 0x00, 0x14 }, { 0x2d, 0x33, 0x25 }, { 0x52, 0x00, 0x14 }, { 0x40, 0x36, 0x3f }, + { 0x5c, 0x18, 0x00 }, { 0x40, 0x5f, 0x00 }, { 0x5e, 0x19, 0x00 }, { 0x4b, 0x62, 0x00 }, +/* Composite lo-res, colour reg = 5 */ + { 0x51, 0x00, 0x81 }, { 0x2a, 0x2a, 0x3f }, { 0x4f, 0x00, 0x1c }, { 0x3b, 0x2b, 0x5c }, + { 0x22, 0x1b, 0x13 }, { 0x04, 0x55, 0x00 }, { 0x21, 0x0e, 0x00 }, { 0x0e, 0x52, 0x04 }, + { 0x4c, 0x03, 0x59 }, { 0x2e, 0x32, 0x25 }, { 0x51, 0x00, 0x0b }, { 0x3e, 0x37, 0x3d }, + { 0x5d, 0x2a, 0x03 }, { 0x3d, 0x60, 0x00 }, { 0x5d, 0x19, 0x00 }, { 0x4a, 0x63, 0x00 }, +/* Composite lo-res, colour reg = 6 */ + { 0x4b, 0x60, 0x00 }, { 0x41, 0x5f, 0x00 }, { 0x5b, 0x1a, 0x00 }, { 0x4b, 0x60, 0x00 }, + { 0x0e, 0x51, 0x03 }, { 0x03, 0x55, 0x00 }, { 0x22, 0x0b, 0x00 }, { 0x12, 0x51, 0x03 }, + { 0x41, 0x34, 0x47 }, { 0x31, 0x37, 0x29 }, { 0x50, 0x00, 0x10 }, { 0x3f, 0x32, 0x43 }, + { 0x4b, 0x60, 0x00 }, { 0x3d, 0x61, 0x00 }, { 0x62, 0x16, 0x00 }, { 0x4b, 0x60, 0x00 }, +/* Composite lo-res, colour reg = 7 */ + { 0x8b, 0x8b, 0x8b }, { 0x83, 0x5b, 0x00 }, { 0xa4, 0x1b, 0x00 }, { 0x92, 0x5a, 0x09 }, + { 0x07, 0x79, 0x6f }, { 0x06, 0x55, 0x00 }, { 0x1f, 0x0d, 0x00 }, { 0x10, 0x52, 0x01 }, + { 0x23, 0x62, 0xa4 }, { 0x2b, 0x33, 0x29 }, { 0x51, 0x00, 0x11 }, { 0x40, 0x36, 0x42 }, + { 0x46, 0x86, 0x63 }, { 0x42, 0x5e, 0x00 }, { 0x5e, 0x17, 0x00 }, { 0x4a, 0x62, 0x00 }, +/* Composite lo-res, colour reg = 8 */ + { 0x26, 0x26, 0x26 }, { 0x0a, 0x49, 0x00 }, { 0x25, 0x07, 0x00 }, { 0x16, 0x4c, 0x0e }, + { 0x1c, 0x29, 0x12 }, { 0x06, 0x55, 0x00 }, { 0x21, 0x0c, 0x00 }, { 0x11, 0x51, 0x02 }, + { 0x4d, 0x10, 0x5f }, { 0x2c, 0x33, 0x26 }, { 0x51, 0x00, 0x0f }, { 0x41, 0x35, 0x47 }, + { 0x5a, 0x35, 0x00 }, { 0x43, 0x5f, 0x00 }, { 0x5f, 0x15, 0x00 }, { 0x4d, 0x62, 0x00 }, +/* Composite lo-res, colour reg = 9 */ + { 0x92, 0x47, 0xd3 }, { 0x47, 0x47, 0x1b }, { 0x66, 0x00, 0x09 }, { 0x54, 0x44, 0x37 }, + { 0x15, 0x4b, 0x8a }, { 0x05, 0x55, 0x00 }, { 0x00, 0x10, 0x00 }, { 0x10, 0x52, 0x02 }, + { 0x40, 0x33, 0xd4 }, { 0x2f, 0x33, 0x26 }, { 0x51, 0x00, 0x0d }, { 0x3e, 0x37, 0x3e }, + { 0x51, 0x59, 0x75 }, { 0x3b, 0x63, 0x00 }, { 0x5b, 0x1a, 0x00 }, { 0x49, 0x64, 0x00 }, +/* Composite lo-res, colour reg = A */ + { 0x57, 0xac, 0x33 }, { 0x54, 0x7f, 0x00 }, { 0x7f, 0x2e, 0x00 }, { 0x6a, 0x77, 0x00 }, + { 0x05, 0x80, 0x70 }, { 0x03, 0x54, 0x00 }, { 0x22, 0x0c, 0x00 }, { 0x13, 0x52, 0x00 }, + { 0x31, 0x64, 0xbe }, { 0x30, 0x35, 0x2a }, { 0x52, 0x00, 0x12 }, { 0x41, 0x33, 0x46 }, + { 0x3c, 0x91, 0x50 }, { 0x3c, 0x62, 0x00 }, { 0x60, 0x15, 0x00 }, { 0x4f, 0x61, 0x00 }, +/* Composite lo-res, colour reg = B */ + { 0x5b, 0xb9, 0xa7 }, { 0x5b, 0x6d, 0x00 }, { 0x7f, 0x29, 0x00 }, { 0x6c, 0x6e, 0x00 }, + { 0x05, 0x95, 0xcb }, { 0x04, 0x54, 0x00 }, { 0x23, 0x0a, 0x00 }, { 0x12, 0x51, 0x02 }, + { 0x28, 0x77, 0xfb }, { 0x32, 0x37, 0x2f }, { 0x52, 0x00, 0x12 }, { 0x3e, 0x34, 0x40 }, + { 0x3a, 0xa3, 0xaf }, { 0x3c, 0x63, 0x00 }, { 0x60, 0x15, 0x00 }, { 0x50, 0x61, 0x00 }, +/* Composite lo-res, colour reg = C */ + { 0xaa, 0x45, 0x6a }, { 0x8c, 0x59, 0x00 }, { 0xa8, 0x1a, 0x00 }, { 0x96, 0x60, 0x05 }, + { 0x20, 0x35, 0x41 }, { 0x03, 0x55, 0x00 }, { 0x22, 0x0b, 0x00 }, { 0x10, 0x52, 0x02 }, + { 0x4f, 0x1e, 0xa2 }, { 0x2e, 0x34, 0x25 }, { 0x50, 0x00, 0x10 }, { 0x42, 0x36, 0x45 }, + { 0x56, 0x48, 0x2a }, { 0x41, 0x5e, 0x00 }, { 0x5d, 0x19, 0x00 }, { 0x49, 0x64, 0x00 }, +/* Composite lo-res, colour reg = D */ + { 0xa9, 0x54, 0xd6 }, { 0x85, 0x52, 0x09 }, { 0xa5, 0x17, 0x00 }, { 0x96, 0x52, 0x23 }, + { 0x1e, 0x48, 0x9f }, { 0x06, 0x55, 0x00 }, { 0x1f, 0x0c, 0x00 }, { 0x0f, 0x52, 0x01 }, + { 0x46, 0x35, 0xe1 }, { 0x2b, 0x32, 0x26 }, { 0x51, 0x00, 0x0e }, { 0x3e, 0x39, 0x3e }, + { 0x5d, 0x58, 0x88 }, { 0x41, 0x60, 0x00 }, { 0x57, 0x1c, 0x00 }, { 0x4a, 0x62, 0x00 }, +/* Composite lo-res, colour reg = E */ + { 0xa4, 0xbb, 0x30 }, { 0x9d, 0x84, 0x00 }, { 0xb6, 0x3f, 0x00 }, { 0xa1, 0x8c, 0x00 }, + { 0x14, 0x7b, 0x8a }, { 0x06, 0x55, 0x00 }, { 0x21, 0x0b, 0x00 }, { 0x13, 0x51, 0x02 }, + { 0x3f, 0x67, 0xd5 }, { 0x2d, 0x36, 0x29 }, { 0x52, 0x00, 0x11 }, { 0x41, 0x33, 0x46 }, + { 0x4c, 0x8e, 0x6e }, { 0x3e, 0x61, 0x00 }, { 0x5f, 0x16, 0x00 }, { 0x4c, 0x61, 0x00 }, +/* Composite lo-res, colour reg = F */ + { 0xe3, 0xe3, 0xe3 }, { 0xdb, 0x82, 0x00 }, { 0xf5, 0x43, 0x00 }, { 0xee, 0x83, 0x00 }, + { 0x08, 0xa6, 0xf5 }, { 0x04, 0x53, 0x00 }, { 0x1c, 0x0d, 0x00 }, { 0x13, 0x52, 0x00 }, + { 0x25, 0x91, 0xfc }, { 0x2c, 0x35, 0x30 }, { 0x51, 0x00, 0x0e }, { 0x3b, 0x36, 0x38 }, + { 0x43, 0xb5, 0xf7 }, { 0x3b, 0x62, 0x00 }, { 0x56, 0x1c, 0x00 }, { 0x4d, 0x61, 0x00 }, +/* Composite lo-res, colour reg = 10 */ + { 0x00, 0x00, 0x00 }, { 0x00, 0x58, 0xb9 }, { 0x00, 0x11, 0x8a }, { 0x00, 0x4a, 0xe1 }, + { 0x73, 0x22, 0x00 }, { 0x5a, 0xad, 0x2e }, { 0x78, 0x61, 0x0d }, { 0x6a, 0xa9, 0x4c }, + { 0xac, 0x0a, 0x00 }, { 0x87, 0x8d, 0x80 }, { 0xab, 0x46, 0x6c }, { 0x95, 0x8b, 0x97 }, + { 0xac, 0x30, 0x00 }, { 0x91, 0xbc, 0x16 }, { 0xb8, 0x6d, 0x07 }, { 0xa7, 0xb9, 0x2d }, +/* Composite lo-res, colour reg = 11 */ + { 0x60, 0x00, 0x7c }, { 0x01, 0x54, 0xdb }, { 0x09, 0x11, 0xb9 }, { 0x07, 0x47, 0xf8 }, + { 0x76, 0x46, 0x02 }, { 0x5a, 0xae, 0x2e }, { 0x78, 0x62, 0x0c }, { 0x68, 0xa9, 0x4b }, + { 0x99, 0x2a, 0x09 }, { 0x87, 0x8d, 0x80 }, { 0xab, 0x46, 0x6b }, { 0x93, 0x89, 0x95 }, + { 0xa4, 0x54, 0x00 }, { 0x93, 0xbb, 0x16 }, { 0xb9, 0x6b, 0x04 }, { 0xa4, 0xb9, 0x30 }, +/* Composite lo-res, colour reg = 12 */ + { 0x07, 0x55, 0x00 }, { 0x03, 0x83, 0x70 }, { 0x1c, 0x3a, 0x42 }, { 0x0e, 0x81, 0x82 }, + { 0x58, 0x7e, 0x00 }, { 0x5b, 0xad, 0x2f }, { 0x77, 0x60, 0x0f }, { 0x67, 0xac, 0x49 }, + { 0x87, 0x5a, 0x00 }, { 0x89, 0x8c, 0x81 }, { 0xa9, 0x49, 0x5e }, { 0x9b, 0x8a, 0x96 }, + { 0x9f, 0x83, 0x00 }, { 0x94, 0xb9, 0x19 }, { 0xb0, 0x72, 0x03 }, { 0xa5, 0xbb, 0x30 }, +/* Composite lo-res, colour reg = 13 */ + { 0x03, 0x63, 0x48 }, { 0x04, 0x76, 0x8c }, { 0x1d, 0x34, 0x5a }, { 0x0d, 0x7a, 0x9c }, + { 0x5a, 0x8e, 0x03 }, { 0x58, 0xac, 0x33 }, { 0x76, 0x60, 0x0b }, { 0x68, 0xaa, 0x4b }, + { 0x7e, 0x6e, 0x3b }, { 0x88, 0x8c, 0x80 }, { 0xaa, 0x48, 0x64 }, { 0x94, 0x91, 0x92 }, + { 0x94, 0x9b, 0x00 }, { 0x96, 0xb9, 0x16 }, { 0xb0, 0x73, 0x01 }, { 0xa7, 0xb8, 0x2e }, +/* Composite lo-res, colour reg = 14 */ + { 0x52, 0x00, 0x13 }, { 0x29, 0x61, 0xb6 }, { 0x52, 0x1e, 0xa1 }, { 0x41, 0x63, 0xdb }, + { 0x7b, 0x2f, 0x00 }, { 0x5d, 0xac, 0x2c }, { 0x77, 0x63, 0x0a }, { 0x67, 0xa9, 0x51 }, + { 0xaf, 0x18, 0x00 }, { 0x83, 0x8a, 0x7d }, { 0xa9, 0x46, 0x66 }, { 0x9a, 0x8c, 0xa0 }, + { 0xb1, 0x43, 0x00 }, { 0x9a, 0xb7, 0x19 }, { 0xb7, 0x6e, 0x05 }, { 0xa4, 0xb9, 0x2f }, +/* Composite lo-res, colour reg = 15 */ + { 0x52, 0x00, 0x7a }, { 0x2e, 0x55, 0xdc }, { 0x4e, 0x1b, 0xb1 }, { 0x3c, 0x55, 0xec }, + { 0x80, 0x3f, 0x00 }, { 0x5b, 0xad, 0x2e }, { 0x73, 0x61, 0x0a }, { 0x66, 0xaa, 0x50 }, + { 0xa7, 0x29, 0x29 }, { 0x86, 0x8a, 0x7d }, { 0xa8, 0x48, 0x60 }, { 0x98, 0x8e, 0x9b }, + { 0xc0, 0x4a, 0x00 }, { 0x9a, 0xb5, 0x18 }, { 0xb3, 0x72, 0x06 }, { 0xa2, 0xba, 0x31 }, +/* Composite lo-res, colour reg = 16 */ + { 0x4d, 0x61, 0x00 }, { 0x3b, 0x91, 0x53 }, { 0x59, 0x46, 0x2c }, { 0x48, 0x95, 0x63 }, + { 0x6c, 0x77, 0x00 }, { 0x5a, 0xac, 0x31 }, { 0x75, 0x63, 0x09 }, { 0x66, 0xa9, 0x4e }, + { 0x8e, 0x6a, 0x0f }, { 0x87, 0x8b, 0x7f }, { 0xa9, 0x47, 0x66 }, { 0x9b, 0x8c, 0x9f }, + { 0xab, 0x86, 0x00 }, { 0x9a, 0xb6, 0x18 }, { 0xae, 0x74, 0x01 }, { 0xa2, 0xba, 0x2f }, +/* Composite lo-res, colour reg = 17 */ + { 0x8b, 0x8b, 0x8b }, { 0x7f, 0x89, 0x79 }, { 0xa4, 0x4a, 0x5c }, { 0x96, 0x8a, 0x95 }, + { 0x5c, 0xa1, 0x36 }, { 0x5d, 0xad, 0x2b }, { 0x77, 0x62, 0x0a }, { 0x68, 0xa8, 0x4f }, + { 0x83, 0x88, 0x6f }, { 0x85, 0x8d, 0x81 }, { 0xa9, 0x46, 0x69 }, { 0x99, 0x8b, 0x9f }, + { 0x97, 0xb1, 0x22 }, { 0x99, 0xb7, 0x18 }, { 0xb8, 0x6c, 0x04 }, { 0xa2, 0xba, 0x2e }, +/* Composite lo-res, colour reg = 18 */ + { 0x25, 0x25, 0x25 }, { 0x0b, 0x78, 0x8b }, { 0x25, 0x34, 0x5a }, { 0x14, 0x7d, 0x9d }, + { 0x76, 0x4f, 0x00 }, { 0x5a, 0xac, 0x2e }, { 0x74, 0x64, 0x07 }, { 0x66, 0xaa, 0x49 }, + { 0xa7, 0x37, 0x25 }, { 0x87, 0x8b, 0x80 }, { 0xa8, 0x48, 0x64 }, { 0x9a, 0x8f, 0x9a }, + { 0xb6, 0x5a, 0x00 }, { 0x96, 0xba, 0x17 }, { 0xae, 0x73, 0x01 }, { 0xa2, 0xba, 0x30 }, +/* Composite lo-res, colour reg = 19 */ + { 0x5d, 0x48, 0xd5 }, { 0x4a, 0x77, 0xb3 }, { 0x65, 0x35, 0x86 }, { 0x4d, 0x77, 0xc2 }, + { 0x6f, 0x72, 0x53 }, { 0x5a, 0xac, 0x30 }, { 0x75, 0x62, 0x09 }, { 0x68, 0xa9, 0x48 }, + { 0x9c, 0x57, 0xa1 }, { 0x87, 0x8b, 0x80 }, { 0xa7, 0x49, 0x62 }, { 0x92, 0x90, 0x92 }, + { 0xab, 0x7d, 0x3a }, { 0x97, 0xb8, 0x17 }, { 0xb0, 0x74, 0x03 }, { 0xa2, 0xba, 0x2e }, +/* Composite lo-res, colour reg = 1A */ + { 0x59, 0xad, 0x2e }, { 0x59, 0xad, 0x2e }, { 0x75, 0x64, 0x08 }, { 0x69, 0xa7, 0x4d }, + { 0x59, 0xad, 0x2e }, { 0x59, 0xad, 0x2e }, { 0x75, 0x64, 0x08 }, { 0x69, 0xa7, 0x4d }, + { 0x87, 0x8d, 0x82 }, { 0x85, 0x8b, 0x7d }, { 0xa9, 0x47, 0x67 }, { 0x99, 0x8c, 0x9d }, + { 0x94, 0xba, 0x17 }, { 0x94, 0xba, 0x17 }, { 0xb6, 0x6e, 0x06 }, { 0xa2, 0xbb, 0x30 }, +/* Composite lo-res, colour reg = 1B */ + { 0x5b, 0xb9, 0xa6 }, { 0x5c, 0xa2, 0x4a }, { 0x7a, 0x5c, 0x24 }, { 0x6a, 0x9a, 0x6c }, + { 0x56, 0xbf, 0x8e }, { 0x59, 0xae, 0x31 }, { 0x78, 0x60, 0x0d }, { 0x68, 0xa9, 0x4f }, + { 0x7f, 0xa3, 0xcd }, { 0x85, 0x8c, 0x80 }, { 0xaa, 0x47, 0x6a }, { 0x98, 0x8b, 0x9c }, + { 0x93, 0xcd, 0x72 }, { 0x92, 0xbd, 0x14 }, { 0xb8, 0x6c, 0x06 }, { 0xa4, 0xb9, 0x2f }, +/* Composite lo-res, colour reg = 1C */ + { 0xa9, 0x44, 0x63 }, { 0x85, 0x8a, 0x7f }, { 0xa9, 0x44, 0x63 }, { 0x99, 0x8e, 0x9d }, + { 0x74, 0x5f, 0x0d }, { 0x5c, 0xad, 0x2c }, { 0x77, 0x63, 0x0a }, { 0x68, 0xa8, 0x4e }, + { 0xa9, 0x44, 0x63 }, { 0x84, 0x8b, 0x7e }, { 0xa9, 0x44, 0x63 }, { 0x99, 0x8c, 0x9e }, + { 0xad, 0x72, 0x01 }, { 0x9b, 0xb6, 0x1a }, { 0xb3, 0x6e, 0x05 }, { 0xa4, 0xb9, 0x2f }, +/* Composite lo-res, colour reg = 1D */ + { 0xaa, 0x55, 0xd4 }, { 0x83, 0x81, 0x9b }, { 0xa6, 0x43, 0x7b }, { 0x95, 0x80, 0xbd }, + { 0x76, 0x72, 0x66 }, { 0x5a, 0xad, 0x2c }, { 0x7b, 0x61, 0x0c }, { 0x68, 0xa9, 0x50 }, + { 0xa5, 0x59, 0xaa }, { 0x87, 0x8e, 0x7f }, { 0xa9, 0x45, 0x6a }, { 0x97, 0x8b, 0x98 }, + { 0xb2, 0x82, 0x48 }, { 0x93, 0xbb, 0x16 }, { 0xb9, 0x6d, 0x05 }, { 0xa4, 0xb9, 0x2f }, +/* Composite lo-res, colour reg = 1E */ + { 0xa5, 0xb8, 0x2d }, { 0xa5, 0xb8, 0x2d }, { 0xb4, 0x70, 0x05 }, { 0xa5, 0xb8, 0x2d }, + { 0x64, 0xaa, 0x4e }, { 0x5b, 0xad, 0x2c }, { 0x77, 0x63, 0x0b }, { 0x68, 0xa8, 0x4f }, + { 0x94, 0x91, 0x95 }, { 0x83, 0x8a, 0x7b }, { 0xa9, 0x47, 0x67 }, { 0x98, 0x8a, 0x9e }, + { 0xa5, 0xb8, 0x2d }, { 0x9a, 0xb6, 0x1a }, { 0xb2, 0x70, 0x05 }, { 0xa5, 0xb8, 0x2d }, +/* Composite lo-res, colour reg = 1F */ + { 0xe3, 0xe3, 0xe3 }, { 0xde, 0xb1, 0x45 }, { 0xf8, 0x71, 0x3e }, { 0xeb, 0xb3, 0x5e }, + { 0x58, 0xd3, 0xc4 }, { 0x5b, 0xad, 0x2d }, { 0x78, 0x63, 0x0b }, { 0x68, 0xa8, 0x4f }, + { 0x7f, 0xb7, 0xf4 }, { 0x86, 0x8b, 0x7d }, { 0xa8, 0x46, 0x69 }, { 0x9a, 0x8c, 0x9f }, + { 0x99, 0xe0, 0xbc }, { 0x99, 0xb6, 0x1a }, { 0xb8, 0x6d, 0x07 }, { 0xa5, 0xb8, 0x30 }, +/* Composite lo-res, colour reg = 20 */ + { 0x00, 0x00, 0x00 }, { 0x00, 0x3a, 0x85 }, { 0x00, 0x00, 0x6c }, { 0x00, 0x46, 0xce }, + { 0x26, 0x01, 0x00 }, { 0x03, 0x61, 0x4a }, { 0x24, 0x16, 0x2a }, { 0x09, 0x72, 0x8d }, + { 0x4d, 0x00, 0x00 }, { 0x2d, 0x45, 0x9c }, { 0x51, 0x00, 0x7c }, { 0x30, 0x58, 0xe1 }, + { 0x9e, 0x0f, 0x00 }, { 0x86, 0x7b, 0x45 }, { 0xab, 0x29, 0x2c }, { 0x8b, 0x89, 0x88 }, +/* Composite lo-res, colour reg = 21 */ + { 0x06, 0x00, 0x7C }, { 0x00, 0x3B, 0xA0 }, { 0x14, 0x00, 0x93 }, { 0x00, 0x49, 0xF7 }, + { 0x19, 0x12, 0x13 }, { 0x02, 0x63, 0x3f }, { 0x25, 0x16, 0x2b }, { 0x09, 0x71, 0x93 }, + { 0x46, 0x00, 0x65 }, { 0x28, 0x45, 0x93 }, { 0x50, 0x00, 0x80 }, { 0x32, 0x55, 0xe6 }, + { 0x9c, 0x2d, 0x0c }, { 0x86, 0x78, 0x44 }, { 0xaa, 0x29, 0x33 }, { 0x92, 0x84, 0x84 }, +/* Composite lo-res, colour reg = 22 */ + { 0x05, 0x56, 0x00 }, { 0x04, 0x69, 0x32 }, { 0x21, 0x1d, 0x13 }, { 0x07, 0x76, 0x7e }, + { 0x05, 0x48, 0x03 }, { 0x03, 0x64, 0x43 }, { 0x24, 0x16, 0x28 }, { 0x08, 0x70, 0x92 }, + { 0x45, 0x41, 0x74 }, { 0x27, 0x44, 0x92 }, { 0x4f, 0x00, 0x7f }, { 0x36, 0x58, 0xe8 }, + { 0x85, 0x57, 0x02 }, { 0x87, 0x77, 0x45 }, { 0xa6, 0x2c, 0x2c }, { 0x8b, 0x8b, 0x8b }, +/* Composite lo-res, colour reg = 23 */ + { 0x02, 0x61, 0x49 }, { 0x02, 0x61, 0x49 }, { 0x24, 0x15, 0x27 }, { 0x05, 0x73, 0x84 }, + { 0x02, 0x61, 0x49 }, { 0x02, 0x61, 0x49 }, { 0x24, 0x15, 0x27 }, { 0x05, 0x73, 0x84 }, + { 0x2a, 0x43, 0x96 }, { 0x2a, 0x43, 0x96 }, { 0x51, 0x00, 0x7d }, { 0x31, 0x5a, 0xdc }, + { 0x86, 0x79, 0x3d }, { 0x86, 0x79, 0x3d }, { 0xa8, 0x2a, 0x21 }, { 0x8a, 0x8a, 0x8a }, +/* Composite lo-res, colour reg = 24 */ + { 0x51, 0x00, 0x0e }, { 0x2b, 0x49, 0x76 }, { 0x4c, 0x04, 0x53 }, { 0x23, 0x5a, 0xf5 }, + { 0x22, 0x05, 0x00 }, { 0x04, 0x06, 0x4b }, { 0x22, 0x13, 0x22 }, { 0x03, 0x74, 0x82 }, + { 0x4e, 0x00, 0x25 }, { 0x2d, 0x46, 0x9d }, { 0x52, 0x00, 0x7c }, { 0x34, 0x59, 0xe3 }, + { 0xaa, 0x17, 0x00 }, { 0x85, 0x79, 0x3d }, { 0xa7, 0x2e, 0x24 }, { 0x8b, 0x8b, 0x8b }, +/* Composite lo-res, colour reg = 25 */ + { 0x50, 0x00, 0x7e }, { 0x2d, 0x45, 0x9d }, { 0x50, 0x00, 0x7e }, { 0x30, 0x57, 0xde }, + { 0x23, 0x16, 0x29 }, { 0x05, 0x61, 0x49 }, { 0x23, 0x13, 0x26 }, { 0x04, 0x75, 0x87 }, + { 0x50, 0x00, 0x7e }, { 0x28, 0x44, 0x96 }, { 0x50, 0x00, 0x7e }, { 0x31, 0x59, 0xdf }, + { 0xac, 0x28, 0x33 }, { 0x85, 0x79, 0x3c }, { 0xa7, 0x2d, 0x23 }, { 0x8b, 0x8b, 0x8b }, +/* Composite lo-res, colour reg = 26 */ + { 0x4f, 0x62, 0x00 }, { 0x3d, 0x71, 0x1f }, { 0x60, 0x2a, 0x07 }, { 0x43, 0x88, 0x69 }, + { 0x13, 0x42, 0x19 }, { 0x05, 0x63, 0x46 }, { 0x24, 0x16, 0x27 }, { 0x07, 0x72, 0x91 }, + { 0x3c, 0x2b, 0x5f }, { 0x2a, 0x45, 0x92 }, { 0x4f, 0x00, 0x82 }, { 0x36, 0x57, 0xe9 }, + { 0x92, 0x5a, 0x0b }, { 0x87, 0x78, 0x45 }, { 0xa7, 0x2c, 0x2a }, { 0x8b, 0x8b, 0x8c }, +/* Composite lo-res, colour reg = 27 */ + { 0x8b, 0x8b, 0x8b }, { 0x89, 0x78, 0x47 }, { 0xa8, 0x2a, 0x2d }, { 0x8b, 0x8b, 0x8b }, + { 0x08, 0x71, 0x93 }, { 0x02, 0x62, 0x4a }, { 0x26, 0x16, 0x2a }, { 0x06, 0x73, 0x87 }, + { 0x35, 0x58, 0xe6 }, { 0x2f, 0x45, 0x9e }, { 0x50, 0x00, 0x78 }, { 0x2f, 0x59, 0xe0 }, + { 0x8b, 0x8b, 0x8b }, { 0x87, 0x7a, 0x46 }, { 0xaa, 0x29, 0x30 }, { 0x8b, 0x8b, 0x8b }, +/* Composite lo-res, colour reg = 28 */ + { 0x25, 0x25, 0x25 }, { 0x08, 0x5f, 0x4b }, { 0x2b, 0x15, 0x25 }, { 0x09, 0x71, 0x88 }, + { 0x1e, 0x23, 0x26 }, { 0x04, 0x62, 0x47 }, { 0x21, 0x19, 0x28 }, { 0x06, 0x74, 0x88 }, + { 0x48, 0x0b, 0x70 }, { 0x26, 0x42, 0x95 }, { 0x52, 0x00, 0x7c }, { 0x34, 0x58, 0xe6 }, + { 0xa1, 0x37, 0x1c }, { 0x85, 0x78, 0x3e }, { 0xa6, 0x2e, 0x23 }, { 0x8b, 0x8b, 0x8b }, +/* Composite lo-res, colour reg = 29 */ + { 0x5e, 0x44, 0xd3 }, { 0x45, 0x61, 0x73 }, { 0x6c, 0x18, 0x53 }, { 0x4c, 0x72, 0xbf }, + { 0x14, 0x45, 0xa3 }, { 0x04, 0x61, 0x49 }, { 0x22, 0x15, 0x25 }, { 0x06, 0x72, 0x8d }, + { 0x41, 0x2d, 0xf6 }, { 0x27, 0x43, 0x96 }, { 0x51, 0x00, 0x7c }, { 0x34, 0x58, 0xe4 }, + { 0x9b, 0x5a, 0xa5 }, { 0x85, 0x78, 0x3d }, { 0xa6, 0x2e, 0x23 }, { 0x8c, 0x8c, 0x8c }, +/* Composite lo-res, colour reg = 2A */ + { 0x5c, 0xae, 0x2a }, { 0x58, 0x91, 0x00 }, { 0x7b, 0x41, 0x00 }, { 0x5e, 0xa0, 0x36 }, + { 0x06, 0x78, 0x86 }, { 0x03, 0x62, 0x49 }, { 0x25, 0x14, 0x28 }, { 0x03, 0x74, 0x82 }, + { 0x25, 0x5b, 0xcc }, { 0x2a, 0x43, 0x97 }, { 0x52, 0x00, 0x79 }, { 0x31, 0x5b, 0xe0 }, + { 0x7e, 0x88, 0x7b }, { 0x86, 0x7b, 0x3e }, { 0xa7, 0x2c, 0x22 }, { 0x89, 0x89, 0x89 }, +/* Composite lo-res, colour reg = 2B */ + { 0x58, 0xbb, 0x98 }, { 0x5a, 0x8c, 0x0a }, { 0x7f, 0x3b, 0x02 }, { 0x60, 0x9a, 0x4b }, + { 0x03, 0x96, 0xce }, { 0x04, 0x61, 0x4a }, { 0x23, 0x14, 0x24 }, { 0x04, 0x75, 0x86 }, + { 0x23, 0x76, 0xfe }, { 0x28, 0x43, 0x95 }, { 0x51, 0x00, 0x7b }, { 0x30, 0x59, 0xdb }, + { 0x80, 0xab, 0xd2 }, { 0x85, 0x7a, 0x3d }, { 0xa8, 0x2e, 0x26 }, { 0x8b, 0x8b, 0x8b }, +/* Composite lo-res, colour reg = 2C */ + { 0xa9, 0x46, 0x66 }, { 0x7f, 0x6f, 0x37 }, { 0xa9, 0x27, 0x27 }, { 0x87, 0x82, 0x7f }, + { 0x1e, 0x31, 0x5c }, { 0x04, 0x63, 0x44 }, { 0x23, 0x16, 0x2a }, { 0x08, 0x71, 0x92 }, + { 0x4e, 0x1a, 0xb0 }, { 0x27, 0x46, 0x92 }, { 0x50, 0x00, 0x80 }, { 0x33, 0x56, 0xe7 }, + { 0xa3, 0x4a, 0x58 }, { 0x87, 0x78, 0x46 }, { 0xab, 0x29, 0x34 }, { 0x8b, 0x8b, 0x8b }, +/* Composite lo-res, colour reg = 2D */ + { 0xa8, 0x53, 0xd8 }, { 0x82, 0x6c, 0x5f }, { 0xac, 0x25, 0x3f }, { 0x8d, 0x7f, 0xa8 }, + { 0x21, 0x46, 0xb9 }, { 0x04, 0x61, 0x4d }, { 0x24, 0x13, 0x23 }, { 0x04, 0x75, 0x87 }, + { 0x4c, 0x2e, 0xfe }, { 0x2a, 0x45, 0x99 }, { 0x52, 0x00, 0x78 }, { 0x32, 0x5a, 0xde }, + { 0xa8, 0x53, 0xd8 }, { 0x84, 0x7c, 0x3d }, { 0xa7, 0x2d, 0x22 }, { 0x8b, 0x8b, 0x8b }, +/* Composite lo-res, colour reg = 2E */ + { 0xa4, 0xba, 0x2e }, { 0x8e, 0x9f, 0x00 }, { 0xbf, 0x4e, 0x00 }, { 0xa5, 0xae, 0x2d }, + { 0x13, 0x71, 0xa6 }, { 0x03, 0x62, 0x4a }, { 0x24, 0x14, 0x28 }, { 0x05, 0x74, 0x83 }, + { 0x32, 0x5d, 0xe0 }, { 0x2e, 0x46, 0x9c }, { 0x51, 0x00, 0x7c }, { 0x2f, 0x59, 0xe0 }, + { 0x8a, 0x8d, 0x94 }, { 0x86, 0x7b, 0x40 }, { 0xa8, 0x2c, 0x22 }, { 0x8a, 0x8a, 0x8a }, +/* Composite lo-res, colour reg = 2F */ + { 0xe4, 0xe4, 0xe4 }, { 0xdd, 0xa6, 0x0a }, { 0xf9, 0x53, 0x04 }, { 0xea, 0xae, 0x54 }, + { 0x08, 0xa2, 0xfc }, { 0x03, 0x62, 0x48 }, { 0x24, 0x14, 0x28 }, { 0x05, 0x74, 0x84 }, + { 0x27, 0x90, 0xff }, { 0x2a, 0x43, 0x95 }, { 0x52, 0x00, 0x79 }, { 0x34, 0x5a, 0xe3 }, + { 0x85, 0xbb, 0xff }, { 0x85, 0x7a, 0x3d }, { 0xa7, 0x2c, 0x23 }, { 0x8a, 0x8a, 0x8a }, +/* Composite lo-res, colour reg = 30 */ + { 0x00, 0x00, 0x00 }, { 0x00, 0x63, 0xfe }, { 0x00, 0x1d, 0xe9 }, { 0x00, 0x81, 0xff }, + { 0x7e, 0x16, 0x00 }, { 0x5b, 0xb9, 0xa5 }, { 0x79, 0x6a, 0x79 }, { 0x59, 0xce, 0xdc }, + { 0xa8, 0x05, 0x00 }, { 0x84, 0x9e, 0xf3 }, { 0xaa, 0x54, 0xd3 }, { 0x8c, 0xb1, 0xff }, + { 0xfb, 0x28, 0x00 }, { 0xde, 0xd2, 0x94 }, { 0xfc, 0x85, 0x7b }, { 0xe4, 0xe4, 0xe4 }, +/* Composite lo-res, colour reg = 31 */ + { 0x07, 0x00, 0x7c }, { 0x00, 0x70, 0xfe }, { 0x0d, 0x20, 0xff }, { 0x04, 0x7f, 0xff }, + { 0x6f, 0x3b, 0x00 }, { 0x59, 0xbb, 0x9b }, { 0x79, 0x6c, 0x81 }, { 0x5d, 0xcb, 0xe4 }, + { 0x99, 0x26, 0x29 }, { 0x83, 0x9d, 0xf2 }, { 0xaa, 0x54, 0xd4 }, { 0x88, 0xb0, 0xff }, + { 0xf4, 0x57, 0x00 }, { 0xdf, 0xd3, 0x9a }, { 0xfe, 0x81, 0x7f }, { 0xe4, 0xe4, 0xe4 }, +/* Composite lo-res, colour reg = 32 */ + { 0x06, 0x55, 0x00 }, { 0x03, 0x99, 0xbe }, { 0x22, 0x46, 0xa4 }, { 0x09, 0xa4, 0xfa }, + { 0x62, 0x6d, 0x00 }, { 0x59, 0xbb, 0x9b }, { 0x7a, 0x6d, 0x7e }, { 0x5c, 0xc8, 0xe7 }, + { 0x8a, 0x4f, 0x11 }, { 0x80, 0x9b, 0xea }, { 0xa7, 0x55, 0xda }, { 0x8c, 0xad, 0xff }, + { 0xdf, 0x7f, 0x00 }, { 0xe2, 0xd1, 0x9c }, { 0xfd, 0x81, 0x87 }, { 0xe4, 0xe4, 0xe4 }, +/* Composite lo-res, colour reg = 33 */ + { 0x03, 0x63, 0x47 }, { 0x06, 0x91, 0xda }, { 0x23, 0x41, 0xbc }, { 0x06, 0xa5, 0xfa }, + { 0x5d, 0x8a, 0x07 }, { 0x59, 0xbb, 0x9b }, { 0x7c, 0x6e, 0x80 }, { 0x5d, 0xc9, 0xe8 }, + { 0x86, 0x6b, 0x60 }, { 0x81, 0x9d, 0xea }, { 0xa8, 0x55, 0xd8 }, { 0x8e, 0xae, 0xff }, + { 0xdf, 0xa4, 0x0c }, { 0xe1, 0xd0, 0x9e }, { 0xfd, 0x81, 0x85 }, { 0xe4, 0xe4, 0xe4 }, +/* Composite lo-res, colour reg = 34 */ + { 0x52, 0x00, 0x14 }, { 0x20, 0x7b, 0xf7 }, { 0x4e, 0x2f, 0xed }, { 0x22, 0x91, 0xff }, + { 0x7f, 0x28, 0x00 }, { 0x5a, 0xbb, 0x9a }, { 0x79, 0x6d, 0x7f }, { 0x5e, 0xc8, 0xeb }, + { 0xac, 0x13, 0x02 }, { 0x7e, 0x9c, 0xea }, { 0xa8, 0x54, 0xd6 }, { 0x8e, 0xae, 0xff }, + { 0xf5, 0x43, 0x00 }, { 0xdf, 0xcf, 0x9d }, { 0xfd, 0x81, 0x88 }, { 0xe4, 0xe4, 0xe4 }, +/* Composite lo-res, colour reg = 35 */ + { 0x50, 0x00, 0x7b }, { 0x22, 0x76, 0xfe }, { 0x4c, 0x2f, 0xff }, { 0x36, 0x85, 0xff }, + { 0x7b, 0x3d, 0x00 }, { 0x5b, 0xbc, 0xa1 }, { 0x7b, 0x6c, 0x7f }, { 0x5d, 0xca, 0xe8 }, + { 0xa9, 0x26, 0x3c }, { 0x81, 0x9c, 0xec }, { 0xa7, 0x54, 0xdc }, { 0x8b, 0xad, 0xff }, + { 0xf8, 0x57, 0x03 }, { 0xe1, 0xd4, 0x9e }, { 0xfd, 0x80, 0x82 }, { 0xe4, 0xe4, 0xe4 }, +/* Composite lo-res, colour reg = 36 */ + { 0x4c, 0x61, 0x00 }, { 0x39, 0xa2, 0xaf }, { 0x5b, 0x5a, 0x8c }, { 0x42, 0xb6, 0xf4 }, + { 0x66, 0x6b, 0x00 }, { 0x5b, 0xba, 0xa4 }, { 0x7a, 0x6c, 0x7e }, { 0x5e, 0xca, 0xe8 }, + { 0x91, 0x51, 0x1f }, { 0x85, 0x9d, 0xf4 }, { 0xaa, 0x55, 0xd7 }, { 0x88, 0xaf, 0xff }, + { 0xea, 0x87, 0x00 }, { 0xde, 0xd4, 0x98 }, { 0xfd, 0x7f, 0x81 }, { 0xe4, 0xe4, 0xe4 }, +/* Composite lo-res, colour reg = 37 */ + { 0x8b, 0x8b, 0x8b }, { 0x86, 0xa7, 0xde }, { 0xa6, 0x5a, 0xbf }, { 0x85, 0xbb, 0xff }, + { 0x5f, 0x9b, 0x51 }, { 0x5a, 0xb9, 0xa7 }, { 0x78, 0x6a, 0x7b }, { 0x5b, 0xce, 0xdb }, + { 0x8b, 0x7c, 0xae }, { 0x82, 0x9c, 0xf2 }, { 0xaa, 0x54, 0xd3 }, { 0x87, 0xb2, 0xff }, + { 0xe7, 0xb0, 0x54 }, { 0xdc, 0xd2, 0x95 }, { 0xfc, 0x84, 0x77 }, { 0xe3, 0xe3, 0xe3 }, +/* Composite lo-res, colour reg = 38 */ + { 0x24, 0x24, 0x24 }, { 0x06, 0x91, 0xd8 }, { 0x2a, 0x44, 0xb9 }, { 0x0f, 0x9e, 0xfe }, + { 0x7a, 0x49, 0x00 }, { 0x58, 0xbc, 0x98 }, { 0x7a, 0x6d, 0x7f }, { 0x5e, 0xc8, 0xeb }, + { 0xa3, 0x36, 0x3a }, { 0x7f, 0x9c, 0xec }, { 0xa8, 0x54, 0xd7 }, { 0x8a, 0xad, 0xff }, + { 0xf7, 0x64, 0x00 }, { 0xe1, 0xd1, 0x9c }, { 0xfd, 0x7f, 0x8b }, { 0xe4, 0xe4, 0xe4 }, +/* Composite lo-res, colour reg = 39 */ + { 0x62, 0x46, 0xd3 }, { 0x3d, 0x93, 0xf2 }, { 0x6b, 0x46, 0xeb }, { 0x4f, 0xa0, 0xff }, + { 0x6f, 0x69, 0x6b }, { 0x58, 0xbb, 0x9b }, { 0x7b, 0x6e, 0x80 }, { 0x5e, 0xc8, 0xec }, + { 0x9d, 0x53, 0xbd }, { 0x81, 0x9d, 0xf0 }, { 0xa8, 0x54, 0xd8 }, { 0x86, 0xb1, 0xff }, + { 0xf4, 0x85, 0x5e }, { 0xdf, 0xd1, 0x9f }, { 0xfe, 0x7f, 0x88 }, { 0xe3, 0xe3, 0xe3 }, +/* Composite lo-res, colour reg = 3A */ + { 0x5a, 0xad, 0x2d }, { 0x58, 0xc1, 0x81 }, { 0x77, 0x74, 0x68 }, { 0x58, 0xcf, 0xd1 }, + { 0x5d, 0xa0, 0x4d }, { 0x59, 0xbb, 0x9b }, { 0x7c, 0x6d, 0x7f }, { 0x5e, 0xc9, 0xeb }, + { 0x83, 0x7d, 0x9e }, { 0x7f, 0x9c, 0xec }, { 0xa9, 0x54, 0xd6 }, { 0x8c, 0xae, 0xff }, + { 0xde, 0xae, 0x4b }, { 0xdc, 0xd0, 0x98 }, { 0xfc, 0x81, 0x8a }, { 0xe4, 0xe4, 0xe4 }, +/* Composite lo-res, colour reg = 3B */ + { 0x59, 0xbc, 0x9c }, { 0x59, 0xbc, 0x9c }, { 0x7a, 0x6a, 0x79 }, { 0x59, 0xce, 0xd9 }, + { 0x59, 0xbc, 0x9c }, { 0x59, 0xbc, 0x9c }, { 0x7b, 0x6b, 0x80 }, { 0x59, 0xcc, 0xd9 }, + { 0x81, 0x9b, 0xec }, { 0x81, 0x9b, 0xec }, { 0xa9, 0x54, 0xd4 }, { 0x8e, 0xb2, 0xff }, + { 0xdf, 0xcf, 0x9b }, { 0xdf, 0xcf, 0x9b }, { 0xfd, 0x85, 0x79 }, { 0xe3, 0xe3, 0xe3 }, +/* Composite lo-res, colour reg = 3C */ + { 0xaa, 0x46, 0x6a }, { 0x7a, 0xa3, 0xc7 }, { 0xa7, 0x58, 0xba }, { 0x84, 0xb5, 0xf8 }, + { 0x78, 0x5b, 0x23 }, { 0x59, 0xbc, 0x9c }, { 0x7a, 0x6e, 0x81 }, { 0x5f, 0xc9, 0xeb }, + { 0xa3, 0x44, 0x71 }, { 0x80, 0x9d, 0xec }, { 0xa8, 0x54, 0xd7 }, { 0x8a, 0xae, 0xff }, + { 0xf8, 0x74, 0x1a }, { 0xdf, 0xd1, 0x9e }, { 0xfe, 0x81, 0x8b }, { 0xe3, 0xe3, 0xe3 }, +/* Composite lo-res, colour reg = 3D */ + { 0xaa, 0x53, 0xd1 }, { 0x80, 0x9c, 0xec }, { 0xaa, 0x53, 0xd1 }, { 0x88, 0xad, 0xff }, + { 0x7a, 0x6b, 0x7e }, { 0x58, 0xbb, 0x9d }, { 0x7a, 0x6d, 0x81 }, { 0x5f, 0xc9, 0xe5 }, + { 0xaa, 0x53, 0xd1 }, { 0x84, 0x9d, 0xf2 }, { 0xaa, 0x53, 0xd1 }, { 0x88, 0xad, 0xff }, + { 0xfd, 0x85, 0x78 }, { 0xe0, 0xd2, 0x9e }, { 0xfe, 0x80, 0x87 }, { 0xe3, 0xe3, 0xe3 }, +/* Composite lo-res, colour reg = 3E */ + { 0xa1, 0xba, 0x2f }, { 0x90, 0xce, 0x70 }, { 0xb4, 0x80, 0x4b }, { 0x9d, 0xe0, 0xba }, + { 0x6a, 0x9f, 0x68 }, { 0x5a, 0xba, 0x9f }, { 0x7a, 0x6b, 0x7a }, { 0x5a, 0xce, 0xdb }, + { 0x91, 0x83, 0xae }, { 0x80, 0x9b, 0xef }, { 0xaa, 0x54, 0xd2 }, { 0x8c, 0xb1, 0xff }, + { 0xeb, 0xb3, 0x59 }, { 0xdd, 0xd3, 0x94 }, { 0xfc, 0x85, 0x79 }, { 0xe4, 0xe4, 0xe4 }, +/* Composite lo-res, colour reg = 3F */ + { 0xe4, 0xe4, 0xe4 }, { 0xdd, 0xd2, 0x93 }, { 0xfc, 0x85, 0x7a }, { 0xe4, 0xe4, 0xe4 }, + { 0x59, 0xcc, 0xda }, { 0x59, 0xbb, 0x9c }, { 0x7b, 0x6d, 0x7f }, { 0x5c, 0xca, 0xe5 }, + { 0x87, 0xb3, 0xff }, { 0x7f, 0x9a, 0xea }, { 0xa8, 0x54, 0xd4 }, { 0x8c, 0xb0, 0xff }, + { 0xe4, 0xe4, 0xe4 }, { 0xdf, 0xd1, 0x98 }, { 0xfd, 0x84, 0x7d }, { 0xe4, 0xe4, 0xe4 }, +}; diff --git a/src/devices/video/cgapal.h b/src/devices/video/cgapal.h new file mode 100644 index 00000000000..c5dfafd636e --- /dev/null +++ b/src/devices/video/cgapal.h @@ -0,0 +1,5 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +#define CGA_PALETTE_SETS 83 /* one for colour, one for mono, + * 81 for colour composite */ +extern const unsigned char cga_palette[16 * CGA_PALETTE_SETS][3]; diff --git a/src/devices/video/clgd542x.c b/src/devices/video/clgd542x.c new file mode 100644 index 00000000000..854611d1c80 --- /dev/null +++ b/src/devices/video/clgd542x.c @@ -0,0 +1,1512 @@ +// license:BSD-3-Clause +// copyright-holders:Barry Rodewald +/* + + Cirrus Logic GD542x/3x video chipsets + +*/ + +#include "clgd542x.h" + +#define LOG_REG 0 +#define LOG_BLIT 1 + +#define CRTC_PORT_ADDR ((vga.miscellaneous_output&1)?0x3d0:0x3b0) + +//#define TEXT_LINES (LINES_HELPER) +#define LINES (vga.crtc.vert_disp_end+1) +#define TEXT_LINES (vga.crtc.vert_disp_end+1) + +#define GRAPHIC_MODE (vga.gc.alpha_dis) /* else text mode */ + +#define EGA_COLUMNS (vga.crtc.horz_disp_end+1) +#define EGA_START_ADDRESS (vga.crtc.start_addr) +#define EGA_LINE_LENGTH (vga.crtc.offset<<1) + +#define VGA_COLUMNS (vga.crtc.horz_disp_end+1) +#define VGA_START_ADDRESS (vga.crtc.start_addr) +#define VGA_LINE_LENGTH (vga.crtc.offset<<3) + +#define IBM8514_LINE_LENGTH (m_vga->offset()) + +#define CHAR_WIDTH ((vga.sequencer.data[1]&1)?8:9) + +#define TEXT_COLUMNS (vga.crtc.horz_disp_end+1) +#define TEXT_START_ADDRESS (vga.crtc.start_addr<<3) +#define TEXT_LINE_LENGTH (vga.crtc.offset<<1) + +#define TEXT_COPY_9COLUMN(ch) (((ch & 0xe0) == 0xc0)&&(vga.attribute.data[0x10]&4)) + +const device_type CIRRUS_GD5428 = &device_creator; +const device_type CIRRUS_GD5430 = &device_creator; + + +cirrus_gd5428_device::cirrus_gd5428_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : svga_device(mconfig, CIRRUS_GD5428, "Cirrus Logic GD5428", tag, owner, clock, "clgd5428", __FILE__) +{ +} + +cirrus_gd5428_device::cirrus_gd5428_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : svga_device(mconfig, type, name, tag, owner, clock, shortname, source) +{ +} + +cirrus_gd5430_device::cirrus_gd5430_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : cirrus_gd5428_device(mconfig, CIRRUS_GD5430, "Cirrus Logic GD5430", tag, owner, clock, "clgd5430", __FILE__) +{ +} + +MACHINE_CONFIG_FRAGMENT( pcvideo_cirrus_gd5428 ) + MCFG_SCREEN_ADD("screen", RASTER) + MCFG_SCREEN_RAW_PARAMS(XTAL_25_1748MHz,900,0,640,526,0,480) + MCFG_SCREEN_UPDATE_DEVICE("vga", cirrus_gd5428_device, screen_update) + + MCFG_PALETTE_ADD("palette", 0x100) + MCFG_DEVICE_ADD("vga", CIRRUS_GD5428, 0) +MACHINE_CONFIG_END + +MACHINE_CONFIG_FRAGMENT( pcvideo_cirrus_gd5430 ) + MCFG_SCREEN_ADD("screen", RASTER) + MCFG_SCREEN_RAW_PARAMS(XTAL_25_1748MHz,900,0,640,526,0,480) + MCFG_SCREEN_UPDATE_DEVICE("vga", cirrus_gd5430_device, screen_update) + + MCFG_PALETTE_ADD("palette", 0x100) + MCFG_DEVICE_ADD("vga", CIRRUS_GD5430, 0) +MACHINE_CONFIG_END + +void cirrus_gd5428_device::device_start() +{ + zero(); + + int i; + for (i = 0; i < 0x100; i++) + m_palette->set_pen_color(i, 0, 0, 0); + + // Avoid an infinite loop when displaying. 0 is not possible anyway. + vga.crtc.maximum_scan_line = 1; + + // copy over interfaces + vga.read_dipswitch = read8_delegate(); //read_dipswitch; + vga.svga_intf.seq_regcount = 0x1f; + vga.svga_intf.crtc_regcount = 0x2d; + vga.svga_intf.vram_size = 0x200000; + + vga.memory.resize(vga.svga_intf.vram_size); + memset(&vga.memory[0], 0, vga.svga_intf.vram_size); + save_item(NAME(vga.memory)); + save_pointer(vga.crtc.data,"CRTC Registers",0x100); + save_pointer(vga.sequencer.data,"Sequencer Registers",0x100); + save_pointer(vga.attribute.data,"Attribute Registers", 0x15); + save_item(NAME(m_chip_id)); + + m_vblank_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(vga_device::vblank_timer_cb),this)); + + m_chip_id = 0x98; // GD5428 - Rev 0 +} + +void cirrus_gd5430_device::device_start() +{ + cirrus_gd5428_device::device_start(); + m_chip_id = 0xa0; // GD5430 - Rev 0 +} + +void cirrus_gd5428_device::device_reset() +{ + vga_device::device_reset(); + gc_locked = true; + gc_mode_ext = 0; + gc_bank_0 = gc_bank_1 = 0; + m_lock_reg = 0; + m_blt_status = 0; + m_cursor_attr = 0x00; // disable hardware cursor and extra palette + m_cursor_x = m_cursor_y = 0; + m_cursor_addr = 0; + m_scratchpad1 = m_scratchpad2 = m_scratchpad3 = 0; + m_cr19 = m_cr1a = m_cr1b = 0; + m_vclk_num[0] = 0x4a; + m_vclk_denom[0] = 0x2b; + m_vclk_num[1] = 0x5b; + m_vclk_denom[1] = 0x2f; + m_blt_source = m_blt_dest = m_blt_source_current = m_blt_dest_current = 0; + memset(m_ext_palette, 0, sizeof(m_ext_palette)); + m_ext_palette_enabled = false; + m_blt_system_transfer = false; +} + +UINT32 cirrus_gd5428_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + int x,y,bit; + UINT32 ptr = (vga.svga_intf.vram_size - 0x4000); // cursor patterns are stored in the last 16kB of VRAM + svga_device::screen_update(screen, bitmap, cliprect); + + /*UINT8 cur_mode =*/ pc_vga_choosevideomode(); + if(m_cursor_attr & 0x01) // hardware cursor enabled + { + // draw hardware graphics cursor + if(m_cursor_attr & 0x04) // 64x64 + { + ptr += ((m_cursor_addr & 0x3c) * 256); + for(y=0;y<64;y++) + { + for(x=0;x<64;x+=8) + { + for(bit=0;bit<8;bit++) + { + UINT8 pixel1 = vga.memory[ptr % vga.svga_intf.vram_size] >> (7-bit); + UINT8 pixel2 = vga.memory[(ptr+512) % vga.svga_intf.vram_size] >> (7-bit); + UINT8 output = ((pixel1 & 0x01) << 1) | (pixel2 & 0x01); + switch(output) + { + case 0: // transparent - do nothing + break; + case 1: // background + bitmap.pix32(m_cursor_y+y,m_cursor_x+x+bit) = (m_ext_palette[0].red << 16) | (m_ext_palette[0].green << 8) | (m_ext_palette[0].blue); + break; + case 2: // XOR + bitmap.pix32(m_cursor_y+y,m_cursor_x+x+bit) = ~bitmap.pix32(m_cursor_y+y,m_cursor_x+x+bit); + break; + case 3: // foreground + bitmap.pix32(m_cursor_y+y,m_cursor_x+x+bit) = (m_ext_palette[15].red << 16) | (m_ext_palette[15].green << 8) | (m_ext_palette[15].blue); + break; + } + } + } + } + } + else + { + ptr += ((m_cursor_addr & 0x3f) * 256); + for(y=0;y<32;y++) + { + for(x=0;x<32;x+=8) + { + for(bit=0;bit<8;bit++) + { + UINT8 pixel1 = vga.memory[ptr % vga.svga_intf.vram_size] >> (7-bit); + UINT8 pixel2 = vga.memory[(ptr+128) % vga.svga_intf.vram_size] >> (7-bit); + UINT8 output = ((pixel1 & 0x01) << 1) | (pixel2 & 0x01); + switch(output) + { + case 0: // transparent - do nothing + break; + case 1: // background + bitmap.pix32(m_cursor_y+y,m_cursor_x+x+bit) = (m_ext_palette[0].red << 18) | (m_ext_palette[0].green << 10) | (m_ext_palette[0].blue << 2); + break; + case 2: // XOR + bitmap.pix32(m_cursor_y+y,m_cursor_x+x+bit) = ~bitmap.pix32(m_cursor_y+y,m_cursor_x+x+bit); + break; + case 3: // foreground + bitmap.pix32(m_cursor_y+y,m_cursor_x+x+bit) = (m_ext_palette[15].red << 18) | (m_ext_palette[15].green << 10) | (m_ext_palette[15].blue << 2); + break; + } + } + ptr++; + } + } + } + } + return 0; +} + +void cirrus_gd5428_device::cirrus_define_video_mode() +{ + UINT8 divisor = 1; + float clock; + UINT8 clocksel = (vga.miscellaneous_output & 0xc) >> 2; + + svga.rgb8_en = 0; + svga.rgb15_en = 0; + svga.rgb16_en = 0; + svga.rgb24_en = 0; + svga.rgb32_en = 0; + + if(gc_locked || m_vclk_num[clocksel] == 0 || m_vclk_denom[clocksel] == 0) + clock = (vga.miscellaneous_output & 0xc) ? XTAL_28_63636MHz : XTAL_25_1748MHz; + else + { + int numerator = m_vclk_num[clocksel] & 0x7f; + int denominator = (m_vclk_denom[clocksel] & 0x3e) >> 1; + int mul = m_vclk_denom[clocksel] & 0x01 ? 2 : 1; + clock = 14.31818f * ((float)numerator / ((float)denominator * mul)); + clock *= 1000000; + } + + if (!gc_locked && (vga.sequencer.data[0x07] & 0x01)) + { + switch(vga.sequencer.data[0x07] & 0x06) // bit 3 is reserved on GD542x + { + case 0x00: svga.rgb8_en = 1; break; + case 0x02: svga.rgb16_en = 1; clock /= 2; break; // Clock / 2 for 16-bit data + case 0x04: svga.rgb24_en = 1; clock /= 3; break; // Clock / 3 for 24-bit data + case 0x06: svga.rgb16_en = 1; divisor = 2; break; // Clock rate for 16-bit data + } + } + recompute_params_clock(divisor, (int)clock); +} + +UINT16 cirrus_gd5428_device::offset() +{ + UINT16 off = vga_device::offset(); + + if (svga.rgb8_en == 1) // guess + off <<= 2; + if (svga.rgb16_en == 1) + off <<= 2; + if (svga.rgb24_en == 1) + off <<= 2; + if (svga.rgb32_en == 1) + off <<= 2; +// popmessage("Offset: %04x %s %s ** -- actual: %04x",vga.crtc.offset,vga.crtc.dw?"DW":"--",vga.crtc.word_mode?"BYTE":"WORD",off); + return off; +} + +void cirrus_gd5428_device::start_bitblt() +{ + UINT32 x,y; + + if(m_blt_mode & 0x01) + { + start_reverse_bitblt(); + return; + } + + if(LOG_BLIT) logerror("CL: BitBLT started: Src: %06x Dst: %06x Width: %i Height %i ROP: %02x Mode: %02x\n",m_blt_source,m_blt_dest,m_blt_width,m_blt_height,m_blt_rop,m_blt_mode); + + m_blt_source_current = m_blt_source; + m_blt_dest_current = m_blt_dest; + + for(y=0;y<=m_blt_height;y++) + { + for(x=0;x<=m_blt_width;x++) + { + if(m_blt_mode & 0x80) // colour expand + { + if(m_blt_mode & 0x10) // 16-bit colour expansion / transparency width + { + // use GR0/1/10/11 background/foreground regs + UINT16 pixel = (vga.memory[m_blt_source_current % vga.svga_intf.vram_size] >> (7-((x/2) % 8)) & 0x01) ? ((m_gr11 << 8) | vga.gc.enable_set_reset) : ((m_gr10 << 8) | vga.gc.set_reset); + + if(m_blt_dest_current & 1) + copy_pixel(pixel >> 8, vga.memory[m_blt_dest_current % vga.svga_intf.vram_size]); + else + copy_pixel(pixel & 0xff, vga.memory[m_blt_dest_current % vga.svga_intf.vram_size]); + if((x % 8) == 7 && !(m_blt_mode & 0x40)) // don't increment if a pattern (it's only 8 bits) + m_blt_source_current++; + } + else + { + UINT8 pixel = (vga.memory[m_blt_source_current % vga.svga_intf.vram_size] >> (7-(x % 8)) & 0x01) ? vga.gc.enable_set_reset : vga.gc.set_reset; // use GR0/1/10/11 background/foreground regs + + copy_pixel(pixel, vga.memory[m_blt_dest_current % vga.svga_intf.vram_size]); + if((x % 8) == 7 && !(m_blt_mode & 0x40)) // don't increment if a pattern (it's only 8 bits) + m_blt_source_current++; + } + } + else + { + copy_pixel(vga.memory[m_blt_source_current % vga.svga_intf.vram_size], vga.memory[m_blt_dest_current % vga.svga_intf.vram_size]); + m_blt_source_current++; + } + + m_blt_dest_current++; + if(m_blt_mode & 0x40 && (x % 8) == 7) // 8x8 pattern - reset pattern source location + { + if(m_blt_mode & 0x80) // colour expand + m_blt_source_current = m_blt_source + (1*(y % 8)); // patterns are linear data + else if(svga.rgb15_en || svga.rgb16_en) + { + if(m_blt_mode & 0x40 && (x % 16) == 15) + m_blt_source_current = m_blt_source + (16*(y % 8)); + } + else + m_blt_source_current = m_blt_source + (8*(y % 8)); + } + } + if(m_blt_mode & 0x40) // 8x8 pattern + { + if(m_blt_mode & 0x80) // colour expand + m_blt_source_current = m_blt_source + (1*(y % 8)); // patterns are linear data + else if(svga.rgb15_en || svga.rgb16_en) + { + if(m_blt_mode & 0x40 && (x % 16) == 15) + m_blt_source_current = m_blt_source + (16*(y % 8)); + } + else + m_blt_source_current = m_blt_source + (8*(y % 8)); + } + else + m_blt_source_current = m_blt_source + (m_blt_source_pitch*(y+1)); + m_blt_dest_current = m_blt_dest + (m_blt_dest_pitch*(y+1)); + } + m_blt_status &= ~0x02; +} + +void cirrus_gd5428_device::start_reverse_bitblt() +{ + UINT32 x,y; + + if(LOG_BLIT) logerror("CL: Reverse BitBLT started: Src: %06x Dst: %06x Width: %i Height %i ROP: %02x Mode: %02x\n",m_blt_source,m_blt_dest,m_blt_width,m_blt_height,m_blt_rop,m_blt_mode); + + // Start at end of blit + m_blt_source_current = m_blt_source; + m_blt_dest_current = m_blt_dest; + + for(y=0;y<=m_blt_height;y++) + { + for(x=0;x<=m_blt_width;x++) + { + if(m_blt_mode & 0x80) // colour expand + { + if(m_blt_mode & 0x10) // 16-bit colour expansion / transparency width + { + // use GR0/1/10/11 background/foreground regs + UINT16 pixel = (vga.memory[m_blt_source_current % vga.svga_intf.vram_size] >> (7-((x/2) % 8)) & 0x01) ? ((m_gr11 << 8) | vga.gc.enable_set_reset) : ((m_gr10 << 8) | vga.gc.set_reset); + + if(m_blt_dest_current & 1) + copy_pixel(pixel >> 8, vga.memory[m_blt_dest_current % vga.svga_intf.vram_size]); + else + copy_pixel(pixel & 0xff, vga.memory[m_blt_dest_current % vga.svga_intf.vram_size]); + if((x % 8) == 7 && !(m_blt_mode & 0x40)) // don't increment if a pattern (it's only 8 bits) + m_blt_source_current--; + } + else + { + UINT8 pixel = (vga.memory[m_blt_source_current % vga.svga_intf.vram_size] >> (7-(x % 8)) & 0x01) ? vga.gc.enable_set_reset : vga.gc.set_reset; // use GR0/1/10/11 background/foreground regs + + copy_pixel(pixel, vga.memory[m_blt_dest_current % vga.svga_intf.vram_size]); + if((x % 8) == 7 && !(m_blt_mode & 0x40)) // don't decrement if a pattern (it's only 8 bits) + m_blt_source_current--; + } + } + else + { + copy_pixel(vga.memory[m_blt_source_current % vga.svga_intf.vram_size], vga.memory[m_blt_dest_current % vga.svga_intf.vram_size]); + m_blt_source_current--; + } + m_blt_dest_current--; + if(m_blt_mode & 0x40 && (x % 8) == 7) // 8x8 pattern - reset pattern source location + { + if(m_blt_mode & 0x80) // colour expand + m_blt_source_current = m_blt_source - (1*(y % 8)); // patterns are linear data + else if(svga.rgb15_en || svga.rgb16_en) + { + if(m_blt_mode & 0x40 && (x % 16) == 15) + m_blt_source_current = m_blt_source - (16*(y % 8)); + } + else + m_blt_source_current = m_blt_source - (8*(y % 8)); + } + } + if(m_blt_mode & 0x40) // 8x8 pattern + { + if(m_blt_mode & 0x80) // colour expand + m_blt_source_current = m_blt_source - (1*(y % 8)); // patterns are linear data + else if(svga.rgb15_en || svga.rgb16_en) + { + if(m_blt_mode & 0x40 && (x % 16) == 15) + m_blt_source_current = m_blt_source - (16*(y % 8)); + } + else + m_blt_source_current = m_blt_source - (8*(y % 8)); + } + else + m_blt_source_current = m_blt_source - (m_blt_source_pitch*(y+1)); + m_blt_dest_current = m_blt_dest - (m_blt_dest_pitch*(y+1)); + } + m_blt_status &= ~0x02; +} + +void cirrus_gd5428_device::start_system_bitblt() +{ + if(LOG_BLIT) logerror("CL: BitBLT from system memory started: Src: %06x Dst: %06x Width: %i Height %i ROP: %02x Mode: %02x\n",m_blt_source,m_blt_dest,m_blt_width,m_blt_height,m_blt_rop,m_blt_mode); + m_blt_system_transfer = true; + m_blt_system_count = 0; + m_blt_system_buffer = 0; + m_blt_pixel_count = m_blt_scan_count = 0; + m_blt_source_current = m_blt_source; + m_blt_dest_current = m_blt_dest; + m_blt_status |= 0x09; +} + +// non colour-expanded BitBLTs from system memory must be doubleword sized, extra bytes are ignored +void cirrus_gd5428_device::blit_dword() +{ + // TODO: add support for reverse direction + UINT8 x,pixel; + + for(x=0;x<32;x+=8) + { + pixel = ((m_blt_system_buffer & (0x000000ff << x)) >> x); + if(m_blt_pixel_count <= m_blt_width) + copy_pixel(pixel,vga.memory[m_blt_dest_current % vga.svga_intf.vram_size]); + m_blt_dest_current++; + m_blt_pixel_count++; + } + if(m_blt_pixel_count > m_blt_width) + { + m_blt_pixel_count = 0; + m_blt_scan_count++; + m_blt_dest_current = m_blt_dest + (m_blt_dest_pitch*m_blt_scan_count); + } + if(m_blt_scan_count > m_blt_height) + { + m_blt_system_transfer = false; // BitBLT complete + m_blt_status &= ~0x0b; + } +} + +// colour-expanded BitBLTs from system memory are on a byte boundary, unused bits are ignored +void cirrus_gd5428_device::blit_byte() +{ + // TODO: add support for reverse direction + UINT8 x,pixel; + + for(x=0;x<8;x++) + { + // use GR0/1/10/11 background/foreground regs + if(m_blt_dest_current & 1) + pixel = ((m_blt_system_buffer & (0x00000001 << (7-x))) >> (7-x)) ? m_gr11 : m_gr10; + else + pixel = ((m_blt_system_buffer & (0x00000001 << (7-x))) >> (7-x)) ? vga.gc.enable_set_reset : vga.gc.set_reset; + if(m_blt_pixel_count <= m_blt_width - 1) + copy_pixel(pixel,vga.memory[m_blt_dest_current % vga.svga_intf.vram_size]); + m_blt_dest_current++; + m_blt_pixel_count++; + } + if(m_blt_pixel_count > m_blt_width) + { + m_blt_pixel_count = 0; + m_blt_scan_count++; + m_blt_dest_current = m_blt_dest + (m_blt_dest_pitch*m_blt_scan_count); + } + if(m_blt_scan_count > m_blt_height) + { + m_blt_system_transfer = false; // BitBLT complete + m_blt_status &= ~0x0b; + } +} + +void cirrus_gd5428_device::copy_pixel(UINT8 src, UINT8 dst) +{ + UINT8 res = src; + + switch(m_blt_rop) + { + case 0x00: // BLACK + res = 0x00; + break; + case 0x0b: // DSTINVERT + res = ~dst; + break; + case 0x0d: // SRC + res = src; + break; + case 0x0e: // WHITE + res = 0xff; + break; + case 0x59: // SRCINVERT + res = src ^ dst; + break; + default: + popmessage("CL: Unsupported BitBLT ROP mode %02x",m_blt_rop); + } + + // handle transparency compare + if(m_blt_mode & 0x08) // TODO: 16-bit compare + { + // if ROP result matches the transparency colour, don't change the pixel + if((res & (~m_blt_trans_colour_mask & 0xff)) == ((m_blt_trans_colour & 0xff) & (~m_blt_trans_colour_mask & 0xff))) + return; + } + + vga.memory[m_blt_dest_current % vga.svga_intf.vram_size] = res; +} + +UINT8 cirrus_gd5428_device::cirrus_seq_reg_read(UINT8 index) +{ + UINT8 res; + + res = 0xff; + + switch(index) + { + case 0x02: + if(gc_mode_ext & 0x08) + res = vga.sequencer.map_mask & 0xff; + else + res = vga.sequencer.map_mask & 0x0f; + break; + case 0x06: + if(gc_locked) + return 0x0f; + else + return m_lock_reg; + break; + case 0x09: + //printf("%02x\n",index); + res = vga.sequencer.data[index]; + break; + case 0x0a: + res = m_scratchpad1; + break; + case 0x0b: + case 0x0c: + case 0x0d: + case 0x0e: + res = m_vclk_num[index-0x0b]; + break; + case 0x0f: + res = vga.sequencer.data[index] & 0xe7; + res |= 0x18; // 32-bit DRAM data bus width (1MB-2MB) + break; + case 0x12: + res = m_cursor_attr; + break; + case 0x14: + res = m_scratchpad2; + break; + case 0x15: + res = m_scratchpad3; + break; + case 0x1b: + case 0x1c: + case 0x1d: + case 0x1e: + res = m_vclk_denom[index-0x1b]; + break; + default: + res = vga.sequencer.data[index]; + } + + return res; +} + +void cirrus_gd5428_device::cirrus_seq_reg_write(UINT8 index, UINT8 data) +{ + if(LOG_REG) logerror("CL: SEQ write %02x to SR%02x\n",data,index); + switch(index) + { + case 0x02: + if(gc_mode_ext & 0x08) + vga.sequencer.map_mask = data & 0xff; + else + vga.sequencer.map_mask = data & 0x0f; + break; + case 0x06: + // Note: extensions are always enabled on the GD5429 + if((data & 0x17) == 0x12) // bits 3,5,6,7 ignored + { + gc_locked = false; + logerror("Cirrus register extensions unlocked\n"); + } + else + { + gc_locked = true; + logerror("Cirrus register extensions locked\n"); + } + m_lock_reg = data & 0x17; + break; + case 0x07: + if((data & 0xf0) != 0) + popmessage("1MB framebuffer window enabled at %iMB (%02x)",data >> 4,data); + vga.sequencer.data[vga.sequencer.index] = data; + break; + case 0x09: + //printf("%02x %02x\n",index,data); + vga.sequencer.data[vga.sequencer.index] = data; + break; + case 0x0a: + m_scratchpad1 = data; // GD5402/GD542x BIOS writes VRAM size here. + break; + case 0x0b: + case 0x0c: + case 0x0d: + case 0x0e: + m_vclk_num[index-0x0b] = data; + break; + case 0x10: + case 0x30: + case 0x50: + case 0x70: + case 0x90: + case 0xb0: + case 0xd0: + case 0xf0: // bits 5-7 of the register index are the low bits of the X co-ordinate + m_cursor_x = (data << 3) | ((index & 0xe0) >> 5); + break; + case 0x11: + case 0x31: + case 0x51: + case 0x71: + case 0x91: + case 0xb1: + case 0xd1: + case 0xf1: // bits 5-7 of the register index are the low bits of the Y co-ordinate + m_cursor_y = (data << 3) | ((index & 0xe0) >> 5); + break; + case 0x12: + // bit 0 - enable cursor + // bit 1 - enable extra palette (cursor colours are there) + // bit 2 - 64x64 cursor (32x32 if clear, GD5422+) + // bit 7 - overscan colour protect - if set, use colour 2 in the extra palette for the border (GD5424+) + m_cursor_attr = data; + m_ext_palette_enabled = data & 0x02; + break; + case 0x13: + m_cursor_addr = data; // bits 0 and 1 are ignored if using 64x64 cursor + break; + case 0x14: + m_scratchpad2 = data; + break; + case 0x15: + m_scratchpad3 = data; // GD543x BIOS writes VRAM size here + break; + case 0x1b: + case 0x1c: + case 0x1d: + case 0x1e: + m_vclk_denom[index-0x1b] = data; + break; + default: + vga.sequencer.data[vga.sequencer.index] = data; + seq_reg_write(vga.sequencer.index,data); + } +} + +UINT8 cirrus_gd5428_device::cirrus_gc_reg_read(UINT8 index) +{ + UINT8 res = 0xff; + + switch(index) + { + case 0x00: + if(gc_mode_ext & 0x04) + res = vga.gc.set_reset & 0xff; + else + res = vga.gc.set_reset & 0x0f; + break; + case 0x01: + if(gc_mode_ext & 0x04) + res = vga.gc.enable_set_reset & 0xff; + else + res = vga.gc.enable_set_reset & 0x0f; + break; + case 0x05: + res = (vga.gc.shift256 & 1) << 6; + res |= (vga.gc.shift_reg & 1) << 5; + res |= (vga.gc.host_oe & 1) << 4; + res |= (vga.gc.read_mode & 1) << 3; + if(gc_mode_ext & 0x04) + res |= (vga.gc.write_mode & 7); + else + res |= (vga.gc.write_mode & 3); + break; + case 0x09: // Offset register 0 + res = gc_bank_0; + break; + case 0x0a: // Offset register 1 + res = gc_bank_1; + break; + case 0x0b: // Graphics controller mode extensions + res = gc_mode_ext; + break; + case 0x0c: // Colour Key + break; + case 0x0d: // Colour Key Mask + break; + case 0x0e: // Miscellaneous Control + break; + case 0x10: // Background Colour Byte 1 + res = m_gr10; + break; + case 0x11: // Foreground Colour Byte 1 + res = m_gr11; + break; + case 0x20: // BLT Width 0 + res = m_blt_width & 0x00ff; + break; + case 0x21: // BLT Width 1 + res = m_blt_width >> 8; + break; + case 0x22: // BLT Height 0 + res = m_blt_height & 0x00ff; + break; + case 0x23: // BLT Height 1 + res = m_blt_height >> 8; + break; + case 0x24: // BLT Destination Pitch 0 + res = m_blt_dest_pitch & 0x00ff; + break; + case 0x25: // BLT Destination Pitch 1 + res = m_blt_dest_pitch >> 8; + break; + case 0x26: // BLT Source Pitch 0 + res = m_blt_source_pitch & 0x00ff; + break; + case 0x27: // BLT Source Pitch 1 + res = m_blt_source_pitch >> 8; + break; + case 0x28: // BLT Destination start 0 + res = m_blt_dest & 0x000000ff; + break; + case 0x29: // BLT Destination start 1 + res = (m_blt_dest & 0x0000ff00) >> 8; + break; + case 0x2a: // BLT Destination start 2 + res = (m_blt_dest & 0x00ff0000) >> 16; + break; + case 0x2c: // BLT source start 0 + res = m_blt_source & 0x000000ff; + break; + case 0x2d: // BLT source start 1 + res = (m_blt_source & 0x0000ff00) >> 8; + break; + case 0x2e: // BLT source start 2 + res = (m_blt_source & 0x00ff0000) >> 16; + break; + case 0x2f: // BLT destination write mask (GD5430/36/40) + // TODO + break; + case 0x30: // BLT Mode + res = m_blt_mode; + break; + case 0x31: // BitBLT Start / Status + res = m_blt_status; + break; + case 0x32: // BitBLT ROP mode + res = m_blt_rop; + break; + case 0x34: // BitBLT Transparent Colour + res = m_blt_trans_colour & 0x00ff; + break; + case 0x35: + res = m_blt_trans_colour >> 8; + break; + case 0x36: // BitBLT Transparent Colour Mask + res = m_blt_trans_colour_mask & 0x00ff; + break; + case 0x37: + res = m_blt_trans_colour_mask >> 8; + break; + default: + res = gc_reg_read(index); + } + + return res; +} + +void cirrus_gd5428_device::cirrus_gc_reg_write(UINT8 index, UINT8 data) +{ + if(LOG_REG) logerror("CL: GC write %02x to GR%02x\n",data,index); + switch(index) + { + case 0x00: // if extended writes are enabled (bit 2 of index 0bh), then index 0 and 1 are extended to 8 bits, however XFree86 does not appear to do this... + vga.gc.set_reset = data & 0xff; + break; + case 0x01: + vga.gc.enable_set_reset = data & 0xff; + break; + case 0x05: + vga.gc.shift256 = (data & 0x40) >> 6; + vga.gc.shift_reg = (data & 0x20) >> 5; + vga.gc.host_oe = (data & 0x10) >> 4; + vga.gc.read_mode = (data & 8) >> 3; + if(gc_mode_ext & 0x04) + vga.gc.write_mode = data & 7; + else + vga.gc.write_mode = data & 3; + break; + case 0x09: // Offset register 0 + gc_bank_0 = data; + logerror("CL: Offset register 0 set to %i\n",data); + break; + case 0x0a: // Offset register 1 + gc_bank_1 = data; + logerror("CL: Offset register 1 set to %i\n",data); + break; + case 0x0b: // Graphics controller mode extensions + gc_mode_ext = data; + if(!(data & 0x04)) + { + vga.gc.set_reset &= 0x0f; + vga.gc.enable_set_reset &= 0x0f; + } + if(!(data & 0x08)) + vga.sequencer.map_mask &= 0x0f; + break; + case 0x0c: // Colour Key + break; + case 0x0d: // Colour Key Mask + break; + case 0x0e: // Miscellaneous Control + break; + case 0x10: // Background Colour Byte 1 + m_gr10 = data; + break; + case 0x11: // Foreground Colour Byte 1 + m_gr11 = data; + break; + case 0x20: // BLT Width 0 + m_blt_width = (m_blt_width & 0xff00) | data; + break; + case 0x21: // BLT Width 1 + m_blt_width = (m_blt_width & 0x00ff) | (data << 8); + break; + case 0x22: // BLT Height 0 + m_blt_height = (m_blt_height & 0xff00) | data; + break; + case 0x23: // BLT Height 1 + m_blt_height = (m_blt_height & 0x00ff) | (data << 8); + break; + case 0x24: // BLT Destination Pitch 0 + m_blt_dest_pitch = (m_blt_dest_pitch & 0xff00) | data; + break; + case 0x25: // BLT Destination Pitch 1 + m_blt_dest_pitch = (m_blt_dest_pitch & 0x00ff) | (data << 8); + break; + case 0x26: // BLT Source Pitch 0 + m_blt_source_pitch = (m_blt_source_pitch & 0xff00) | data; + break; + case 0x27: // BLT Source Pitch 1 + m_blt_source_pitch = (m_blt_source_pitch & 0x00ff) | (data << 8); + break; + case 0x28: // BLT Destination start 0 + m_blt_dest = (m_blt_dest & 0xffffff00) | data; + break; + case 0x29: // BLT Destination start 1 + m_blt_dest = (m_blt_dest & 0xffff00ff) | (data << 8); + break; + case 0x2a: // BLT Destination start 2 + m_blt_dest = (m_blt_dest & 0xff00ffff) | (data << 16); + break; + case 0x2c: // BLT source start 0 + m_blt_source = (m_blt_source & 0xffffff00) | data; + break; + case 0x2d: // BLT source start 1 + m_blt_source = (m_blt_source & 0xffff00ff) | (data << 8); + break; + case 0x2e: // BLT source start 2 + m_blt_source = (m_blt_source & 0xff00ffff) | (data << 16); + break; + case 0x2f: // BLT destination write mask (GD5430/36/40) + // TODO + break; + case 0x30: // BLT Mode + m_blt_mode = data; + break; + case 0x31: // BitBLT Start / Status + m_blt_status = data & ~0xf2; + if(data & 0x02) + { + if(m_blt_mode & 0x04) // blit source is system memory + start_system_bitblt(); + else + start_bitblt(); + } + break; + case 0x32: // BitBLT ROP mode + m_blt_rop = data; + break; + case 0x34: // BitBLT Transparent Colour + m_blt_trans_colour = (m_blt_trans_colour & 0xff00) | data; + break; + case 0x35: + m_blt_trans_colour = (m_blt_trans_colour & 0x00ff) | (data << 8); + break; + case 0x36: // BitBLT Transparent Colour Mask + m_blt_trans_colour_mask = (m_blt_trans_colour_mask & 0xff00) | data; + break; + case 0x37: + m_blt_trans_colour_mask = (m_blt_trans_colour_mask & 0x00ff) | (data << 8); + break; + default: + gc_reg_write(index,data); + } +} + +READ8_MEMBER(cirrus_gd5428_device::port_03c0_r) +{ + UINT8 res = 0xff; + + switch(offset) + { + case 0x05: + res = cirrus_seq_reg_read(vga.sequencer.index); + break; + case 0x09: + if(!m_ext_palette_enabled) + res = vga_device::port_03c0_r(space,offset,mem_mask); + else + { + if (vga.dac.read) + { + switch (vga.dac.state++) + { + case 0: + res = m_ext_palette[vga.dac.read_index & 0x0f].red; + break; + case 1: + res = m_ext_palette[vga.dac.read_index & 0x0f].green; + break; + case 2: + res = m_ext_palette[vga.dac.read_index & 0x0f].blue; + break; + } + + if (vga.dac.state==3) + { + vga.dac.state = 0; + vga.dac.read_index++; + } + } + } + break; + case 0x0f: + res = cirrus_gc_reg_read(vga.gc.index); + break; + default: + res = vga_device::port_03c0_r(space,offset,mem_mask); + break; + } + + return res; +} + +WRITE8_MEMBER(cirrus_gd5428_device::port_03c0_w) +{ + switch(offset) + { + case 0x05: + cirrus_seq_reg_write(vga.sequencer.index,data); + break; + case 0x09: + if(!m_ext_palette_enabled) + vga_device::port_03c0_w(space,offset,data,mem_mask); + else + { + if (!vga.dac.read) + { + switch (vga.dac.state++) { + case 0: + m_ext_palette[vga.dac.write_index & 0x0f].red=data; + break; + case 1: + m_ext_palette[vga.dac.write_index & 0x0f].green=data; + break; + case 2: + m_ext_palette[vga.dac.write_index & 0x0f].blue=data; + break; + } + vga.dac.dirty=1; + if (vga.dac.state==3) + { + vga.dac.state=0; + vga.dac.write_index++; + } + } + } + break; + case 0x0f: + cirrus_gc_reg_write(vga.gc.index,data); + break; + default: + vga_device::port_03c0_w(space,offset,data,mem_mask); + break; + } + cirrus_define_video_mode(); +} + +READ8_MEMBER(cirrus_gd5428_device::port_03b0_r) +{ + UINT8 res = 0xff; + + if (CRTC_PORT_ADDR == 0x3b0) + { + switch(offset) + { + case 5: + res = cirrus_crtc_reg_read(vga.crtc.index); + break; + default: + res = vga_device::port_03b0_r(space,offset,mem_mask); + break; + } + } + + return res; +} + +READ8_MEMBER(cirrus_gd5428_device::port_03d0_r) +{ + UINT8 res = 0xff; + + if (CRTC_PORT_ADDR == 0x3d0) + { + switch(offset) + { + case 5: + res = cirrus_crtc_reg_read(vga.crtc.index); + break; + default: + res = vga_device::port_03d0_r(space,offset,mem_mask); + break; + } + } + + return res; +} + +WRITE8_MEMBER(cirrus_gd5428_device::port_03b0_w) +{ + if (CRTC_PORT_ADDR == 0x3b0) + { + switch(offset) + { + case 5: + vga.crtc.data[vga.crtc.index] = data; + cirrus_crtc_reg_write(vga.crtc.index,data); + break; + default: + vga_device::port_03b0_w(space,offset,data,mem_mask); + break; + } + } + cirrus_define_video_mode(); +} + +WRITE8_MEMBER(cirrus_gd5428_device::port_03d0_w) +{ + if (CRTC_PORT_ADDR == 0x3d0) + { + switch(offset) + { + case 5: + vga.crtc.data[vga.crtc.index] = data; + cirrus_crtc_reg_write(vga.crtc.index,data); + break; + default: + vga_device::port_03d0_w(space,offset,data,mem_mask); + break; + } + } + cirrus_define_video_mode(); +} + +UINT8 cirrus_gd5428_device::cirrus_crtc_reg_read(UINT8 index) +{ + UINT8 res = 0xff; + + switch(index) + { + case 0x16: // VGA Vertical Blank end - some SVGA chipsets use all 8 bits, and this is one of them (according to MFGTST CRTC tests) + res = vga.crtc.vert_blank_end & 0x00ff; + break; + case 0x19: + res = m_cr19; + break; + case 0x1a: + res = m_cr1a; + break; + case 0x1b: + res = m_cr1b; + break; + case 0x27: + res = m_chip_id; + break; + default: + res = crtc_reg_read(index); + break; + } + + return res; +} + +void cirrus_gd5428_device::cirrus_crtc_reg_write(UINT8 index, UINT8 data) +{ + if(LOG_REG) logerror("CL: CRTC write %02x to CR%02x\n",data,index); + switch(index) + { + case 0x16: // VGA Vertical Blank end - some SVGA chipsets use all 8 bits, and this is one of them (according to MFGTST CRTC tests) + vga.crtc.vert_blank_end &= ~0x00ff; + vga.crtc.vert_blank_end |= data; + break; + case 0x19: + m_cr19 = data; + break; + case 0x1a: + m_cr1a = data; + vga.crtc.horz_blank_end = (vga.crtc.horz_blank_end & 0xff3f) | ((data & 0x30) << 2); + vga.crtc.vert_blank_end = (vga.crtc.vert_blank_end & 0xfcff) | ((data & 0xc0) << 2); + break; + case 0x1b: + m_cr1b = data; + vga.crtc.start_addr_latch &= ~0x070000; + vga.crtc.start_addr_latch |= ((data & 0x01) << 16); + vga.crtc.start_addr_latch |= ((data & 0x0c) << 15); + vga.crtc.offset = (vga.crtc.offset & 0x00ff) | ((data & 0x10) << 4); + cirrus_define_video_mode(); + break; + case 0x1d: + //vga.crtc.start_addr_latch = (vga.crtc.start_addr_latch & 0xf7ffff) | ((data & 0x01) << 16); // GD543x + break; + case 0x27: + // Do nothing, read only + break; + default: + crtc_reg_write(index,data); + break; + } + +} + +inline UINT8 cirrus_gd5428_device::cirrus_vga_latch_write(int offs, UINT8 data) +{ + UINT8 res = 0; + UINT8 mode_mask = (gc_mode_ext & 0x04) ? 0x07 : 0x03; + + switch (vga.gc.write_mode & mode_mask) { + case 0: + data = rotate_right(data); + if(vga.gc.enable_set_reset & 1<= 0x10000 || cur_mode == TEXT_MODE || cur_mode == SCREEN_OFF) + return vga_device::mem_r(space,offset,mem_mask); + + if(offset >= 0x8000 && offset < 0x10000 && (gc_mode_ext & 0x01)) // if accessing bank 1 (if enabled) + bank = gc_bank_1; + else + bank = gc_bank_0; + + if(gc_mode_ext & 0x20) // 16kB bank granularity + addr = bank * 0x4000; + else // 4kB bank granularity + addr = bank * 0x1000; + + // Is the display address adjusted automatically when not using Chain-4 addressing? The GD542x BIOS doesn't do it, but Virtual Pool expects it. + if(!(vga.sequencer.data[4] & 0x8)) + addr <<= 2; + + if(svga.rgb8_en || svga.rgb15_en || svga.rgb16_en || svga.rgb24_en) + { + UINT8 data = 0; + if(gc_mode_ext & 0x01) + { + if(offset & 0x10000) + return 0; + if(offset < 0x8000) + offset &= 0x7fff; + else + { + offset -= 0x8000; + offset &= 0x7fff; + } + } + else + offset &= 0xffff; + + if(vga.sequencer.data[4] & 0x8) + data = vga.memory[(offset+addr) % vga.svga_intf.vram_size]; + else + { + { + int i; + + for(i=0;i<4;i++) + { + if(vga.sequencer.map_mask & 1 << i) + data |= vga.memory[((offset*4+i)+addr) % vga.svga_intf.vram_size]; + } + } + return data; + } + } + + switch(vga.gc.memory_map_sel & 0x03) + { + case 0: break; + case 1: if(gc_mode_ext & 0x01) offset &= 0x7fff; else offset &= 0x0ffff; break; + case 2: offset -= 0x10000; offset &= 0x07fff; break; + case 3: offset -= 0x18000; offset &= 0x07fff; break; + } + + if(vga.sequencer.data[4] & 4) + { + int data; + if (!space.debugger_access()) + { + vga.gc.latch[0]=vga.memory[(offset+addr) % vga.svga_intf.vram_size]; + vga.gc.latch[1]=vga.memory[((offset+addr)+0x10000) % vga.svga_intf.vram_size]; + vga.gc.latch[2]=vga.memory[((offset+addr)+0x20000) % vga.svga_intf.vram_size]; + vga.gc.latch[3]=vga.memory[((offset+addr)+0x30000) % vga.svga_intf.vram_size]; + } + + if (vga.gc.read_mode) + { + UINT8 byte,layer; + UINT8 fill_latch; + data=0; + + for(byte=0;byte<8;byte++) + { + fill_latch = 0; + for(layer=0;layer<4;layer++) + { + if(vga.gc.latch[layer] & 1 << byte) + fill_latch |= 1 << layer; + } + fill_latch &= vga.gc.color_dont_care; + if(fill_latch == vga.gc.color_compare) + data |= 1 << byte; + } + } + else + data=vga.gc.latch[vga.gc.read_map_sel]; + + return data; + } + else + { + // TODO: Lines up in 16-colour mode, likely different for 256-colour modes (docs say video addresses are shifted right 3 places) + UINT8 i,data; +// UINT8 bits = ((gc_mode_ext & 0x08) && (vga.gc.write_mode == 1)) ? 8 : 4; + + data = 0; + //printf("%08x\n",offset); + + if(gc_mode_ext & 0x02) + { + for(i=0;i<8;i++) + { + if(vga.sequencer.map_mask & 1 << i) + data |= vga.memory[(((offset+addr))+i*0x10000) % vga.svga_intf.vram_size]; + } + } + else + { + for(i=0;i<4;i++) + { + if(vga.sequencer.map_mask & 1 << i) + data |= vga.memory[(((offset+addr))+i*0x10000) % vga.svga_intf.vram_size]; + } + } + + return data; + } +} + +WRITE8_MEMBER(cirrus_gd5428_device::mem_w) +{ + UINT32 addr; + UINT8 bank; + UINT8 cur_mode = pc_vga_choosevideomode(); + + if(m_blt_system_transfer) + { + if(m_blt_mode & 0x80) // colour expand + { + m_blt_system_buffer &= ~(0x000000ff); + m_blt_system_buffer |= data; + blit_byte(); + m_blt_system_count = 0; + } + else + { + m_blt_system_buffer &= ~(0x000000ff << (m_blt_system_count * 8)); + m_blt_system_buffer |= (data << (m_blt_system_count * 8)); + m_blt_system_count++; + if(m_blt_system_count >= 4) + { + blit_dword(); + m_blt_system_count = 0; + } + } + return; + } + + if(gc_locked || offset >= 0x10000 || cur_mode == TEXT_MODE || cur_mode == SCREEN_OFF) + { + vga_device::mem_w(space,offset,data,mem_mask); + return; + } + + if(offset >= 0x8000 && offset < 0x10000 && (gc_mode_ext & 0x01)) // if accessing bank 1 (if enabled) + bank = gc_bank_1; + else + bank = gc_bank_0; + + if(gc_mode_ext & 0x20) // 16kB bank granularity + addr = bank * 0x4000; + else // 4kB bank granularity + addr = bank * 0x1000; + + // Is the display address adjusted automatically when using Chain-4 addressing? The GD542x BIOS doesn't do it, but Virtual Pool expects it. + if(!(vga.sequencer.data[4] & 0x8)) + addr <<= 2; + + if(svga.rgb8_en || svga.rgb15_en || svga.rgb16_en || svga.rgb24_en) + { + if(offset & 0x10000) + return; + if(gc_mode_ext & 0x01) + { + if(offset < 0x8000) + offset &= 0x7fff; + else + { + offset -= 0x8000; + offset &= 0x7fff; + } + } + else + offset &= 0xffff; + + // GR0 (and GR10 in 15/16bpp modes) = background colour in write mode 5 + // GR1 (and GR11 in 15/16bpp modes) = foreground colour in write modes 4 or 5 + if(vga.gc.write_mode == 4) + { + int i; + + for(i=0;i<8;i++) + { + if(svga.rgb8_en) + { + if(data & (0x01 << (7-i))) + vga.memory[((addr+offset)*8+i) % vga.svga_intf.vram_size] = vga.gc.enable_set_reset; + } + else if(svga.rgb15_en || svga.rgb16_en) + { + if(data & (0x01 << (7-i))) + { + vga.memory[((addr+offset)*16+(i*2)) % vga.svga_intf.vram_size] = vga.gc.enable_set_reset; + vga.memory[((addr+offset)*16+(i*2)+1) % vga.svga_intf.vram_size] = m_gr11; + } + } + } + return; + } + + if(vga.gc.write_mode == 5) + { + int i; + + for(i=0;i<8;i++) + { + if(svga.rgb8_en) + { + if(data & (0x01 << (7-i))) + vga.memory[((addr+offset)*8+i) % vga.svga_intf.vram_size] = vga.gc.enable_set_reset; + else + vga.memory[((addr+offset)*8+i) % vga.svga_intf.vram_size] = vga.gc.set_reset; + } + else if(svga.rgb15_en || svga.rgb16_en) + { + if(data & (0x01 << (7-i))) + { + vga.memory[((addr+offset)*16+(i*2)) % vga.svga_intf.vram_size] = vga.gc.enable_set_reset; + vga.memory[((addr+offset)*16+(i*2)+1) % vga.svga_intf.vram_size] = m_gr11; + } + else + { + vga.memory[((addr+offset)*16+(i*2)) % vga.svga_intf.vram_size] = vga.gc.set_reset; + vga.memory[((addr+offset)*16+(i*2)+1) % vga.svga_intf.vram_size] = m_gr10; + } + } + } + return; + } + + if(vga.sequencer.data[4] & 0x8) + vga.memory[(offset+addr) % vga.svga_intf.vram_size] = data; + else + { + int i; + for(i=0;i<4;i++) + { + if(vga.sequencer.map_mask & 1 << i) + vga.memory[((offset*4+i)+addr) % vga.svga_intf.vram_size] = data; + } + } + } + else + { + //Inside each case must prevent writes to non-mapped VGA memory regions, not only mask the offset. + switch(vga.gc.memory_map_sel & 0x03) + { + case 0: break; + case 1: + if(offset & 0x10000) + return; + + if(gc_mode_ext & 0x01) + offset &= 0x7fff; + else + offset &= 0xffff; + break; + case 2: + if((offset & 0x18000) != 0x10000) + return; + + offset &= 0x07fff; + break; + case 3: + if((offset & 0x18000) != 0x18000) + return; + + offset &= 0x07fff; + break; + } + + { + // TODO: Lines up in 16-colour mode, likely different for 256-colour modes (docs say video addresses are shifted right 3 places) + UINT8 i; +// UINT8 bits = ((gc_mode_ext & 0x08) && (vga.gc.write_mode == 1)) ? 8 : 4; + + for(i=0;i<4;i++) + { + if(vga.sequencer.map_mask & 1 << i) + { + if(gc_mode_ext & 0x02) + { + vga.memory[(((offset+addr) << 1)+i*0x10000) % vga.svga_intf.vram_size] = (vga.sequencer.data[4] & 4) ? cirrus_vga_latch_write(i,data) : data; + vga.memory[(((offset+addr) << 1)+i*0x10000+1) % vga.svga_intf.vram_size] = (vga.sequencer.data[4] & 4) ? cirrus_vga_latch_write(i,data) : data; + } + else + vga.memory[(((offset+addr))+i*0x10000) % vga.svga_intf.vram_size] = (vga.sequencer.data[4] & 4) ? cirrus_vga_latch_write(i,data) : data; + } + } + return; + } + } +} diff --git a/src/devices/video/clgd542x.h b/src/devices/video/clgd542x.h new file mode 100644 index 00000000000..20300d160fd --- /dev/null +++ b/src/devices/video/clgd542x.h @@ -0,0 +1,114 @@ +// license:BSD-3-Clause +// copyright-holders:Barry Rodewald +/* + + Cirrus Logic GD542x/3x video chipsets + +*/ + +#include "emu.h" +#include "video/pc_vga.h" + +MACHINE_CONFIG_EXTERN( pcvideo_cirrus_gd5428 ); +MACHINE_CONFIG_EXTERN( pcvideo_cirrus_gd5430 ); + +class cirrus_gd5428_device : public svga_device +{ +public: + // construction/destruction + cirrus_gd5428_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + cirrus_gd5428_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + virtual READ8_MEMBER(port_03c0_r); + virtual WRITE8_MEMBER(port_03c0_w); + virtual READ8_MEMBER(port_03b0_r); + virtual WRITE8_MEMBER(port_03b0_w); + virtual READ8_MEMBER(port_03d0_r); + virtual WRITE8_MEMBER(port_03d0_w); + virtual READ8_MEMBER(mem_r); + virtual WRITE8_MEMBER(mem_w); + + virtual UINT32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual UINT16 offset(); + + UINT8 m_chip_id; + + UINT8 gc_mode_ext; + UINT8 gc_bank_0; + UINT8 gc_bank_1; + bool gc_locked; + UINT8 m_lock_reg; + UINT8 m_gr10; // high byte of background colour (in 15/16bpp) + UINT8 m_gr11; // high byte of foreground colour (in 15/16bpp) + + UINT8 m_cr19; + UINT8 m_cr1a; + UINT8 m_cr1b; + + // hardware cursor + UINT16 m_cursor_x; + UINT16 m_cursor_y; + UINT16 m_cursor_addr; + UINT8 m_cursor_attr; + bool m_ext_palette_enabled; + struct { UINT8 red, green, blue; } m_ext_palette[16]; // extra palette, colour 0 is cursor background, colour 15 is cursor foreground, colour 2 is overscan border colour + + // BitBLT engine + UINT8 m_blt_status; + UINT8 m_blt_rop; + UINT8 m_blt_mode; + UINT32 m_blt_source; + UINT32 m_blt_dest; + UINT16 m_blt_source_pitch; + UINT16 m_blt_dest_pitch; + UINT16 m_blt_height; + UINT16 m_blt_width; + UINT32 m_blt_source_current; + UINT32 m_blt_dest_current; + UINT16 m_blt_trans_colour; + UINT16 m_blt_trans_colour_mask; + + bool m_blt_system_transfer; // blit from system memory + UINT8 m_blt_system_count; + UINT32 m_blt_system_buffer; + UINT16 m_blt_pixel_count; + UINT16 m_blt_scan_count; + + UINT8 m_scratchpad1; + UINT8 m_scratchpad2; + UINT8 m_scratchpad3; + UINT8 m_vclk_num[4]; + UINT8 m_vclk_denom[4]; + + inline UINT8 cirrus_vga_latch_write(int offs, UINT8 data); +private: + void cirrus_define_video_mode(); + UINT8 cirrus_seq_reg_read(UINT8 index); + void cirrus_seq_reg_write(UINT8 index, UINT8 data); + UINT8 cirrus_gc_reg_read(UINT8 index); + void cirrus_gc_reg_write(UINT8 index, UINT8 data); + UINT8 cirrus_crtc_reg_read(UINT8 index); + void cirrus_crtc_reg_write(UINT8 index, UINT8 data); + + void start_bitblt(); + void start_reverse_bitblt(); + void start_system_bitblt(); + void blit_dword(); + void blit_byte(); // used for colour expanded system-to-vram bitblts + void copy_pixel(UINT8 src, UINT8 dst); +}; + +class cirrus_gd5430_device : public cirrus_gd5428_device +{ +public: + cirrus_gd5430_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +protected: + virtual void device_start(); +}; + +// device type definition +extern const device_type CIRRUS_GD5428; +extern const device_type CIRRUS_GD5430; diff --git a/src/devices/video/crt9007.c b/src/devices/video/crt9007.c new file mode 100644 index 00000000000..a5722fbd3bf --- /dev/null +++ b/src/devices/video/crt9007.c @@ -0,0 +1,935 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + SMC CRT9007 CRT Video Processor and Controller (VPAC) emulation + +**********************************************************************/ + +/* + + TODO: + + - cursor timer + - interrupts + - light pen + - frame timer + - non-DMA mode + - DMA mode + - cursor/blank skew + - sequential breaks + - interlaced mode + - smooth scroll + - page blank + - double height cursor + - row attributes + - pin configuration + - operation modes 0,4,7 + - address modes 1,2,3 + - light pen + - state saving + +*/ + +#include "emu.h" +#include "crt9007.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type CRT9007 = &device_creator; + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define LOG 0 + +#define HAS_VALID_PARAMETERS \ + (m_reg[0x00] && m_reg[0x01] && m_reg[0x07] && m_reg[0x08] && m_reg[0x09]) + +#define CHARACTERS_PER_HORIZONTAL_PERIOD \ + m_reg[0x00] + +#define CHARACTERS_PER_DATA_ROW \ + (m_reg[0x01] + 1) + +#define HORIZONTAL_DELAY \ + m_reg[0x02] + +#define HORIZONTAL_SYNC_WIDTH \ + m_reg[0x03] + +#define VERTICAL_SYNC_WIDTH \ + m_reg[0x04] + +#define VERTICAL_DELAY \ + (m_reg[0x05] - 1) + +#define PIN_CONFIGURATION \ + (m_reg[0x06] >> 6) + +#define CURSOR_SKEW \ + ((m_reg[0x06] >> 3) & 0x07) + +#define BLANK_SKEW \ + (m_reg[0x06] & 0x07) + +#define VISIBLE_DATA_ROWS_PER_FRAME \ + (m_reg[0x07] + 1) + +#define SCAN_LINES_PER_DATA_ROW \ + ((m_reg[0x08] & 0x1f) + 1) + +#define SCAN_LINES_PER_FRAME \ + (((m_reg[0x08] << 3) & 0x0700) | m_reg[0x09]) + +#define DMA_BURST_COUNT \ + ((m_reg[0x0a] & 0x0f) + 1) + +#define DMA_BURST_DELAY \ + ((((m_reg[0x0a] >> 4) & 0x07) + 1) % 8) + +#define DMA_DISABLE \ + BIT(m_reg[0x0a], 7) + +#define SINGLE_HEIGHT_CURSOR \ + BIT(m_reg[0x0b], 0) + +#define OPERATION_MODE \ + ((m_reg[0x0b] >> 1) & 0x07) + +#define INTERLACE_MODE \ + ((m_reg[0x0b] >> 4) & 0x03) + +#define PAGE_BLANK \ + BIT(m_reg[0x0b], 6) + +#define TABLE_START \ + (((m_reg[0x0d] << 8) & 0x3f00) | m_reg[0x0c]) + +#define ADDRESS_MODE \ + ((m_reg[0x0d] >> 6) & 0x03) + +#define AUXILIARY_ADDRESS_1 \ + (((m_reg[0x0f] << 8) & 0x3f00) | m_reg[0x0e]) + +#define ROW_ATTRIBUTES_1 \ + ((m_reg[0x0f] >> 6) & 0x03) + +#define SEQUENTIAL_BREAK_1 \ + m_reg[0x10] + +#define SEQUENTIAL_BREAK_2 \ + m_reg[0x12] + +#define DATA_ROW_START \ + m_reg[0x11] + +#define DATA_ROW_END \ + m_reg[0x12] + +#define AUXILIARY_ADDRESS_2 \ + (((m_reg[0x14] << 8) & 0x3f00) | m_reg[0x13]) + +#define ROW_ATTRIBUTES_2 \ + ((m_reg[0x14] >> 6) & 0x03) + +#define SMOOTH_SCROLL_OFFSET \ + ((m_reg[0x17] >> 1) & 0x3f) + +#define SMOOTH_SCROLL_OFFSET_OVERFLOW \ + BIT(m_reg[0x17], 7) + +#define VERTICAL_CURSOR \ + m_reg[0x18] + +#define HORIZONTAL_CURSOR \ + m_reg[0x19] + +#define INTERRUPT_ENABLE \ + m_reg[0x1a] + +#define FRAME_TIMER \ + BIT(m_reg[0x1a], 0) + +#define LIGHT_PEN_INTERRUPT \ + BIT(m_reg[0x1a], 5) + +#define VERTICAL_RETRACE_INTERRUPT \ + BIT(m_reg[0x1a], 6) + +#define VERTICAL_LIGHT_PEN \ + m_reg[0x3b] + +#define HORIZONTAL_LIGHT_PEN \ + m_reg[0x3c] + + +// interlace +enum +{ + NON_INTERLACED = 0, + ENHANCED_VIDEO_INTERFACE, + NORMAL_VIDEO_INTERFACE +}; + + +// operation modes +enum +{ + OPERATION_MODE_REPETITIVE_MEMORY_ADDRESSING = 0, // not implemented + OPERATION_MODE_DOUBLE_ROW_BUFFER = 1, + OPERATION_MODE_SINGLE_ROW_BUFFER = 4, // not implemented + OPERATION_MODE_ATTRIBUTE_ASSEMBLE = 7 // not implemented +}; + + +// addressing modes +enum +{ + ADDRESS_MODE_SEQUENTIAL_ADDRESSING = 0, + ADDRESS_MODE_SEQUENTIAL_ROLL_ADDRESSING, // not implemented + ADDRESS_MODE_CONTIGUOUS_ROW_TABLE, // not implemented + ADDRESS_MODE_LINKED_LIST_ROW_TABLE // not implemented +}; + + +// interrupt enable register bits +const int IE_VERTICAL_RETRACE = 0x40; +//const int IE_LIGHT_PEN = 0x20; +//const int IE_FRAME_TIMER = 0x01; + +// status register bits +const int STATUS_INTERRUPT_PENDING = 0x80; +//const int STATUS_VERTICAL_RETRACE = 0x40; +const int STATUS_LIGHT_PEN_UPDATE = 0x20; +//const int STATUS_ODD_EVEN = 0x04; +//const int STATUS_FRAME_TIMER_OCCURRED = 0x01; + + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +// default address map +static ADDRESS_MAP_START( crt9007, AS_0, 8, crt9007_t ) + AM_RANGE(0x0000, 0x3fff) AM_RAM +ADDRESS_MAP_END + + + +//************************************************************************** +// INLINE HELPERS +//************************************************************************** + +//------------------------------------------------- +// readbyte - read a byte at the given address +//------------------------------------------------- + +inline UINT8 crt9007_t::readbyte(offs_t address) +{ + return space().read_byte(address); +} + + +//------------------------------------------------- +// trigger_interrupt - +//------------------------------------------------- + +inline void crt9007_t::trigger_interrupt(int line) +{ + if (INTERRUPT_ENABLE & line) + { + int status = m_status; + + m_status |= STATUS_INTERRUPT_PENDING | line; + + if (!(status & STATUS_INTERRUPT_PENDING)) + { + if (LOG) logerror("CRT9007 '%s' INT 1\n", tag()); + m_write_int(ASSERT_LINE); + } + } +} + + +//------------------------------------------------- +// update_cblank_line - +//------------------------------------------------- + +inline void crt9007_t::update_cblank_line() +{ + int x = m_screen->hpos(); + int y = m_screen->vpos(); + + // composite blank + int cblank = !(m_hs & m_vs); + + if (m_cblank != cblank) + { + m_cblank = cblank; + + if (LOG) logerror("CRT9007 '%s' y %03u x %04u : CBLANK %u\n", tag(), y, x, m_cblank); + + m_write_cblank(m_cblank); + } +} + + +//------------------------------------------------- +// update_hsync_timer - +//------------------------------------------------- + +inline void crt9007_t::update_hsync_timer(int state) +{ + int y = m_screen->vpos(); + + int next_x = state ? m_hsync_start : m_hsync_end; + int next_y = state ? (y + 1) % SCAN_LINES_PER_FRAME : y; + + attotime duration = m_screen->time_until_pos(next_y, next_x); + + m_hsync_timer->adjust(duration, !state); +} + + +//------------------------------------------------- +// update_vsync_timer - +//------------------------------------------------- + +inline void crt9007_t::update_vsync_timer(int state) +{ + int next_y = state ? m_vsync_start : m_vsync_end; + + attotime duration = m_screen->time_until_pos(next_y, 0); + + m_vsync_timer->adjust(duration, !state); +} + + +//------------------------------------------------- +// update_vlt_timer - +//------------------------------------------------- + +inline void crt9007_t::update_vlt_timer(int state) +{ + // this signal is active during all visible scan lines and during the horizontal trace at vertical retrace + int y = m_screen->vpos(); + + int next_x = state ? m_vlt_end : m_vlt_start; + int next_y = state ? y : ((y == m_vlt_bottom) ? 0 : (y + 1)); + + attotime duration = m_screen->time_until_pos(next_y, next_x); + + m_vlt_timer->adjust(duration, !state); +} + + +//------------------------------------------------- +// update_curs_timer - +//------------------------------------------------- + +inline void crt9007_t::update_curs_timer(int state) +{ + // this signal is active for 1 character time for all scanlines within the data row + // TODO +} + + +//------------------------------------------------- +// update_drb_timer - +//------------------------------------------------- + +inline void crt9007_t::update_drb_timer(int state) +{ + // this signal is active for 1 full scan line (VLT edge to edge) at the top scan line of each new row + // there is 1 extra DRB signal during the 1st scanline of the vertical retrace interval + int y = m_screen->vpos(); + + int next_x = m_vlt_end; + int next_y = y ? y + 1 : y; + + if (state) + { + if (y == 0) + { + next_y = VERTICAL_DELAY - 1; + } + else if (y == m_drb_bottom) + { + next_x = 0; + next_y = 0; + } + else + { + next_y = y + SCAN_LINES_PER_DATA_ROW - 1; + } + } + + attotime duration = m_screen->time_until_pos(next_y, next_x); + + m_drb_timer->adjust(duration, !state); +} + + +//------------------------------------------------- +// update_dma_timer - +//------------------------------------------------- + +inline void crt9007_t::update_dma_timer() +{ + // TODO +} + + +//------------------------------------------------- +// recompute_parameters - +//------------------------------------------------- + +inline void crt9007_t::recompute_parameters() +{ + // check that necessary registers have been loaded + if (!HAS_VALID_PARAMETERS) return; + + // screen dimensions + //int horiz_pix_total = CHARACTERS_PER_HORIZONTAL_PERIOD * m_hpixels_per_column; + //int vert_pix_total = SCAN_LINES_PER_FRAME; + + // refresh rate + //attoseconds_t refresh = HZ_TO_ATTOSECONDS(clock()) * horiz_pix_total * vert_pix_total; + + // horizontal sync + m_hsync_start = 0; + m_hsync_end = HORIZONTAL_SYNC_WIDTH * m_hpixels_per_column; + + // visible line time + m_vlt_start = HORIZONTAL_DELAY * m_hpixels_per_column; + m_vlt_end = (HORIZONTAL_DELAY + CHARACTERS_PER_DATA_ROW) * m_hpixels_per_column; + m_vlt_bottom = VERTICAL_DELAY + (VISIBLE_DATA_ROWS_PER_FRAME * SCAN_LINES_PER_DATA_ROW) - 1; + + // data row boundary + m_drb_bottom = VERTICAL_DELAY + (VISIBLE_DATA_ROWS_PER_FRAME * SCAN_LINES_PER_DATA_ROW) - SCAN_LINES_PER_DATA_ROW; + + // vertical sync + m_vsync_start = 0; + m_vsync_end = VERTICAL_SYNC_WIDTH; + + // visible area + //rectangle visarea; + + //visarea.set(m_hsync_end, horiz_pix_total - 1, m_vsync_end, vert_pix_total - 1); + + //if (LOG) + //{ + // logerror("CRT9007 '%s' Screen: %u x %u @ %f Hz\n", tag(), horiz_pix_total, vert_pix_total, 1 / ATTOSECONDS_TO_DOUBLE(refresh)); + // logerror("CRT9007 '%s' Visible Area: (%u, %u) - (%u, %u)\n", tag(), visarea.min_x, visarea.min_y, visarea.max_x, visarea.max_y); + //} + + //m_screen->configure(horiz_pix_total, vert_pix_total, visarea, refresh); + + m_hsync_timer->adjust(m_screen->time_until_pos(0, 0)); + m_vsync_timer->adjust(m_screen->time_until_pos(0, 0)); + m_vlt_timer->adjust(m_screen->time_until_pos(0, m_vlt_start), 1); + m_drb_timer->adjust(m_screen->time_until_pos(0, 0)); +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// crt9007_t - constructor +//------------------------------------------------- + +crt9007_t::crt9007_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, CRT9007, "SMC CRT9007", tag, owner, clock, "crt9007", __FILE__), + device_memory_interface(mconfig, *this), + device_video_interface(mconfig, *this), + m_space_config("videoram", ENDIANNESS_LITTLE, 8, 14, 0, NULL, *ADDRESS_MAP_NAME(crt9007)), + m_write_int(*this), + m_write_dmar(*this), + m_write_hs(*this), + m_write_vs(*this), + m_write_vlt(*this), + m_write_curs(*this), + m_write_drb(*this), + m_write_wben(*this), + m_write_cblank(*this), + m_write_slg(*this), + m_write_sld(*this) +{ + for (int i = 0; i < 0x3d; i++) + m_reg[i] = 0; +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void crt9007_t::device_start() +{ + // allocate timers + m_hsync_timer = timer_alloc(TIMER_HSYNC); + m_vsync_timer = timer_alloc(TIMER_VSYNC); + m_vlt_timer = timer_alloc(TIMER_VLT); + m_curs_timer = timer_alloc(TIMER_CURS); + m_drb_timer = timer_alloc(TIMER_DRB); + m_dma_timer = timer_alloc(TIMER_DMA); + + // resolve callbacks + m_write_int.resolve_safe(); + m_write_dmar.resolve_safe(); + m_write_hs.resolve_safe(); + m_write_vs.resolve_safe(); + m_write_vlt.resolve_safe(); + m_write_curs.resolve_safe(); + m_write_drb.resolve_safe(); + m_write_wben.resolve_safe(); + m_write_cblank.resolve_safe(); + m_write_slg.resolve_safe(); + m_write_sld.resolve_safe(); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void crt9007_t::device_reset() +{ + m_disp = 0; + m_vs = 0; + m_cblank = 0; + + // HS = 1 + m_write_hs(1); + + // VS = 1 + m_write_vs(1); + + // CBLANK = 1 + m_write_cblank(0); + + // CURS = 0 + m_write_curs(0); + + // VLT = 0 + m_write_vlt(0); + + // DRB = 1 + m_write_drb(1); + + // INT = 0 + m_write_int(CLEAR_LINE); + + // 28 (DMAR) = 0 + m_write_dmar(CLEAR_LINE); + + // 29 (WBEN) = 0 + m_write_wben(1); // HACK + + // 30 (SLG) = 0 + m_write_slg(0); + + // 31 (SLD) = 0 + m_write_sld(0); + + // 32 (LPSTB) = 0 +} + + +//------------------------------------------------- +// device_clock_changed - handle clock change +//------------------------------------------------- + +void crt9007_t::device_clock_changed() +{ + recompute_parameters(); +} + + +//------------------------------------------------- +// device_timer - handle timer events +//------------------------------------------------- + +void crt9007_t::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + int x = m_screen->hpos(); + int y = m_screen->vpos(); + + switch (id) + { + case TIMER_HSYNC: + m_hs = param; + + if (LOG) logerror("CRT9007 '%s' y %03u x %04u : HS %u\n", tag(), y, x, m_hs); + + m_write_hs(m_hs); + + update_cblank_line(); + + update_hsync_timer(param); + break; + + case TIMER_VSYNC: + m_vs = param; + + if (LOG) logerror("CRT9007 '%s' y %03u x %04u : VS %u\n", tag(), y, x, m_vs); + + m_write_vs(param); + + if (m_vs) + { + // reset all other bits except Light Pen Update to logic 0 + m_status &= STATUS_LIGHT_PEN_UPDATE; + } + else + { + trigger_interrupt(IE_VERTICAL_RETRACE); + + update_cblank_line(); + } + + update_vsync_timer(param); + break; + + case TIMER_VLT: + m_vlt = param; + + if (LOG) logerror("CRT9007 '%s' y %03u x %04u : VLT %u\n", tag(), y, x, m_vlt); + + m_write_vlt(param); + + update_vlt_timer(param); + break; + + case TIMER_CURS: + if (LOG) logerror("CRT9007 '%s' y %03u x %04u : CURS %u\n", tag(), y, x, param); + + m_write_curs(param); + + update_curs_timer(param); + break; + + case TIMER_DRB: + m_drb = param; + + if (LOG) logerror("CRT9007 '%s' y %03u x %04u : DRB %u\n", tag(), y, x, m_drb); + + m_write_drb(param); + + if (!m_drb && !DMA_DISABLE) + { + // start DMA burst sequence + m_dma_count = CHARACTERS_PER_DATA_ROW; + m_dma_burst = DMA_BURST_COUNT ? (DMA_BURST_COUNT * 4) : CHARACTERS_PER_DATA_ROW; + m_dma_delay = DMA_BURST_DELAY; + m_dmar = 1; + + if (LOG) logerror("CRT9007 '%s' DMAR 1\n", tag()); + m_write_dmar(ASSERT_LINE); + } + + update_drb_timer(param); + break; + + case TIMER_DMA: + readbyte(AUXILIARY_ADDRESS_2); + + update_dma_timer(); + break; + } +} + + +//------------------------------------------------- +// memory_space_config - return a description of +// any address spaces owned by this device +//------------------------------------------------- + +const address_space_config *crt9007_t::memory_space_config(address_spacenum spacenum) const +{ + return (spacenum == AS_0) ? &m_space_config : NULL; +} + + +//------------------------------------------------- +// read - register read +//------------------------------------------------- + +READ8_MEMBER( crt9007_t::read ) +{ + UINT8 data = 0; + + switch (offset) + { + case 0x15: + if (LOG) logerror("CRT9007 '%s' Start\n", tag()); + m_disp = 1; + break; + + case 0x16: + if (LOG) logerror("CRT9007 '%s' Reset\n", tag()); + device_reset(); + break; + + case 0x38: + data = VERTICAL_CURSOR; + break; + + case 0x39: + data = HORIZONTAL_CURSOR; + break; + + case 0x3a: + data = m_status; + + // reset interrupt pending bit + m_status &= ~STATUS_INTERRUPT_PENDING; + if (LOG) logerror("CRT9007 '%s' INT 0\n", tag()); + m_write_int(CLEAR_LINE); + break; + + case 0x3b: + data = VERTICAL_LIGHT_PEN; + break; + + case 0x3c: + data = HORIZONTAL_LIGHT_PEN; + + // reset light pen update bit + m_status &= ~STATUS_LIGHT_PEN_UPDATE; + break; + + default: + logerror("CRT9007 '%s' Read from Invalid Register: %02x!\n", tag(), offset); + } + + return data; +} + + +//------------------------------------------------- +// write - register write +//------------------------------------------------- + +WRITE8_MEMBER( crt9007_t::write ) +{ + m_reg[offset] = data; + + switch (offset) + { + case 0x00: + recompute_parameters(); + if (LOG) logerror("CRT9007 '%s' Characters per Horizontal Period: %u\n", tag(), CHARACTERS_PER_HORIZONTAL_PERIOD); + break; + + case 0x01: + recompute_parameters(); + if (LOG) logerror("CRT9007 '%s' Characters per Data Row: %u\n", tag(), CHARACTERS_PER_DATA_ROW); + break; + + case 0x02: + recompute_parameters(); + if (LOG) logerror("CRT9007 '%s' Horizontal Delay: %u\n", tag(), HORIZONTAL_DELAY); + break; + + case 0x03: + recompute_parameters(); + if (LOG) logerror("CRT9007 '%s' Horizontal Sync Width: %u\n", tag(), HORIZONTAL_SYNC_WIDTH); + break; + + case 0x04: + recompute_parameters(); + if (LOG) logerror("CRT9007 '%s' Vertical Sync Width: %u\n", tag(), VERTICAL_SYNC_WIDTH); + break; + + case 0x05: + recompute_parameters(); + if (LOG) logerror("CRT9007 '%s' Vertical Delay: %u\n", tag(), VERTICAL_DELAY); + break; + + case 0x06: + recompute_parameters(); + if (LOG) + { + logerror("CRT9007 '%s' Pin Configuration: %u\n", tag(), PIN_CONFIGURATION); + logerror("CRT9007 '%s' Cursor Skew: %u\n", tag(), CURSOR_SKEW); + logerror("CRT9007 '%s' Blank Skew: %u\n", tag(), BLANK_SKEW); + } + break; + + case 0x07: + recompute_parameters(); + if (LOG) logerror("CRT9007 '%s' Visible Data Rows per Frame: %u\n", tag(), VISIBLE_DATA_ROWS_PER_FRAME); + break; + + case 0x08: + recompute_parameters(); + if (LOG) logerror("CRT9007 '%s' Scan Lines per Data Row: %u\n", tag(), SCAN_LINES_PER_DATA_ROW); + break; + + case 0x09: + recompute_parameters(); + if (LOG) logerror("CRT9007 '%s' Scan Lines per Frame: %u\n", tag(), SCAN_LINES_PER_FRAME); + break; + + case 0x0a: + if (LOG) + { + logerror("CRT9007 '%s' DMA Burst Count: %u\n", tag(), DMA_BURST_COUNT); + logerror("CRT9007 '%s' DMA Burst Delay: %u\n", tag(), DMA_BURST_DELAY); + logerror("CRT9007 '%s' DMA Disable: %u\n", tag(), DMA_DISABLE); + } + break; + + case 0x0b: + if (LOG) + { + logerror("CRT9007 '%s' %s Height Cursor\n", tag(), SINGLE_HEIGHT_CURSOR ? "Single" : "Double"); + logerror("CRT9007 '%s' Operation Mode: %u\n", tag(), OPERATION_MODE); + logerror("CRT9007 '%s' Interlace Mode: %u\n", tag(), INTERLACE_MODE); + logerror("CRT9007 '%s' %s Mechanism\n", tag(), PAGE_BLANK ? "Page Blank" : "Smooth Scroll"); + } + break; + + case 0x0c: + break; + + case 0x0d: + if (LOG) + { + logerror("CRT9007 '%s' Table Start Register: %04x\n", tag(), TABLE_START); + logerror("CRT9007 '%s' Address Mode: %u\n", tag(), ADDRESS_MODE); + } + break; + + case 0x0e: + break; + + case 0x0f: + if (LOG) + { + logerror("CRT9007 '%s' Auxialiary Address Register 1: %04x\n", tag(), AUXILIARY_ADDRESS_1); + logerror("CRT9007 '%s' Row Attributes: %u\n", tag(), ROW_ATTRIBUTES_1); + } + break; + + case 0x10: + if (LOG) logerror("CRT9007 '%s' Sequential Break Register 1: %u\n", tag(), SEQUENTIAL_BREAK_1); + break; + + case 0x11: + if (LOG) logerror("CRT9007 '%s' Data Row Start Register: %u\n", tag(), DATA_ROW_START); + break; + + case 0x12: + if (LOG) logerror("CRT9007 '%s' Data Row End/Sequential Break Register 2: %u\n", tag(), SEQUENTIAL_BREAK_2); + break; + + case 0x13: + break; + + case 0x14: + if (LOG) + { + logerror("CRT9007 '%s' Auxiliary Address Register 2: %04x\n", tag(), AUXILIARY_ADDRESS_2); + logerror("CRT9007 '%s' Row Attributes: %u\n", tag(), ROW_ATTRIBUTES_2); + } + break; + + case 0x15: + if (LOG) logerror("CRT9007 '%s' Start\n", tag()); + m_disp = 1; + break; + + case 0x16: + if (LOG) logerror("CRT9007 '%s' Reset\n", tag()); + device_reset(); + break; + + case 0x17: + if (LOG) + { + logerror("CRT9007 '%s' Smooth Scroll Offset: %u\n", tag(), SMOOTH_SCROLL_OFFSET); + logerror("CRT9007 '%s' Smooth Scroll Offset Overflow: %u\n", tag(), SMOOTH_SCROLL_OFFSET_OVERFLOW); + } + break; + + case 0x18: + if (LOG) logerror("CRT9007 '%s' Vertical Cursor Register: %u\n", tag(), VERTICAL_CURSOR); + break; + + case 0x19: + if (LOG) logerror("CRT9007 '%s' Horizontal Cursor Register: %u\n", tag(), HORIZONTAL_CURSOR); + break; + + case 0x1a: + if (LOG) + { + logerror("CRT9007 '%s' Frame Timer: %u\n", tag(), FRAME_TIMER); + logerror("CRT9007 '%s' Light Pen Interrupt: %u\n", tag(), LIGHT_PEN_INTERRUPT); + logerror("CRT9007 '%s' Vertical Retrace Interrupt: %u\n", tag(), VERTICAL_RETRACE_INTERRUPT); + } + break; + + default: + logerror("CRT9007 '%s' Write to Invalid Register: %02x!\n", tag(), offset); + } +} + + +//------------------------------------------------- +// ack_w - DMA acknowledge +//------------------------------------------------- + +WRITE_LINE_MEMBER( crt9007_t::ack_w ) +{ + if (LOG) logerror("CRT9007 '%s' ACK: %u\n", tag(), state); + + if (m_dmar && !m_ack && state) + { + // start DMA transfer + m_dma_timer->adjust(attotime::from_hz(clock())); + } + + m_ack = state; +} + + +//------------------------------------------------- +// lpstb_w - light pen strobe +//------------------------------------------------- + +WRITE_LINE_MEMBER( crt9007_t::lpstb_w ) +{ + if (LOG) logerror("CRT9007 '%s' LPSTB: %u\n", tag(), state); + + if (!m_lpstb && state) + { + // TODO latch current row/column position + } + + m_lpstb = state; +} + + +//------------------------------------------------- +// set_character_width - +//------------------------------------------------- + +void crt9007_t::set_character_width(int value) +{ + m_hpixels_per_column = value; + + recompute_parameters(); +} diff --git a/src/devices/video/crt9007.h b/src/devices/video/crt9007.h new file mode 100644 index 00000000000..95745ecece6 --- /dev/null +++ b/src/devices/video/crt9007.h @@ -0,0 +1,222 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + SMC CRT9007 CRT Video Processor and Controller (VPAC) emulation + +********************************************************************** + _____ _____ + VA2 1 |* \_/ | 40 GND + VA10 2 | | 39 VA9 + VA3 3 | | 38 VA1 + VA11 4 | | 37 VA8 + VA12 5 | | 36 VA0 + VA4 6 | | 35 CBLANK + VA13 7 | | 34 CURS + VA5 8 | | 33 ACK/_TSC + VA6 9 | | 32 _CSYNC/LPSTB + VA7 10 | CRT9007 | 31 SLD/SL0 + VLT 11 | | 30 _SLG/SL1 + _VS 12 | | 29 WBEN/SL2/_CSYNC + _HS 13 | | 28 DMAR/SL3/VBLANK + _CCLK 14 | | 27 INT + _DRB 15 | | 26 _RST + VD7 16 | | 25 _CS + VD6 17 | | 24 VD0 + VD5 18 | | 23 VD1 + VD4 19 | | 22 VD2 + VD3 20 |_____________| 21 +5V + +**********************************************************************/ + +#pragma once + +#ifndef __CRT9007__ +#define __CRT9007__ + +#include "emu.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_CRT9007_CHARACTER_WIDTH(_value) \ + crt9007_t::static_set_character_width(*device, _value); + +#define MCFG_CRT9007_INT_CALLBACK(_write) \ + devcb = &crt9007_t::set_int_wr_callback(*device, DEVCB_##_write); + +#define MCFG_CRT9007_DMAR_CALLBACK(_write) \ + devcb = &crt9007_t::set_dmar_wr_callback(*device, DEVCB_##_write); + +#define MCFG_CRT9007_VS_CALLBACK(_write) \ + devcb = &crt9007_t::set_vs_wr_callback(*device, DEVCB_##_write); + +#define MCFG_CRT9007_HS_CALLBACK(_write) \ + devcb = &crt9007_t::set_hs_wr_callback(*device, DEVCB_##_write); + +#define MCFG_CRT9007_VLT_CALLBACK(_write) \ + devcb = &crt9007_t::set_vlt_wr_callback(*device, DEVCB_##_write); + +#define MCFG_CRT9007_CURS_CALLBACK(_write) \ + devcb = &crt9007_t::set_curs_wr_callback(*device, DEVCB_##_write); + +#define MCFG_CRT9007_DRB_CALLBACK(_write) \ + devcb = &crt9007_t::set_drb_wr_callback(*device, DEVCB_##_write); + +#define MCFG_CRT9007_WBEN_CALLBACK(_write) \ + devcb = &crt9007_t::set_wben_wr_callback(*device, DEVCB_##_write); + +#define MCFG_CRT9007_CBLANK_CALLBACK(_write) \ + devcb = &crt9007_t::set_cblank_wr_callback(*device, DEVCB_##_write); + +#define MCFG_CRT9007_SLG_CALLBACK(_write) \ + devcb = &crt9007_t::set_slg_wr_callback(*device, DEVCB_##_write); + +#define MCFG_CRT9007_SLD_CALLBACK(_write) \ + devcb = &crt9007_t::set_sld_wr_callback(*device, DEVCB_##_write); + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> crt9007_t + +class crt9007_t : public device_t, + public device_memory_interface, + public device_video_interface +{ +public: + // construction/destruction + crt9007_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + static void static_set_character_width(device_t &device, int value) { downcast(device).m_hpixels_per_column = value; } + + template static devcb_base &set_int_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_int.set_callback(object); } + template static devcb_base &set_dmar_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_dmar.set_callback(object); } + template static devcb_base &set_vs_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_vs.set_callback(object); } + template static devcb_base &set_hs_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_hs.set_callback(object); } + template static devcb_base &set_vlt_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_vlt.set_callback(object); } + template static devcb_base &set_curs_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_curs.set_callback(object); } + template static devcb_base &set_drb_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_drb.set_callback(object); } + template static devcb_base &set_wben_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_wben.set_callback(object); } + template static devcb_base &set_cblank_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_cblank.set_callback(object); } + template static devcb_base &set_slg_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_slg.set_callback(object); } + template static devcb_base &set_sld_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_sld.set_callback(object); } + + DECLARE_READ8_MEMBER( read ); + DECLARE_WRITE8_MEMBER( write ); + DECLARE_WRITE_LINE_MEMBER( ack_w ); + DECLARE_WRITE_LINE_MEMBER( lpstb_w ); + + void set_character_width(int value); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_clock_changed(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const; + +private: + enum + { + TIMER_HSYNC, + TIMER_VSYNC, + TIMER_VLT, + TIMER_CURS, + TIMER_DRB, + TIMER_DMA + }; + + inline UINT8 readbyte(offs_t address); + + inline void trigger_interrupt(int line); + inline void update_cblank_line(); + inline void update_hsync_timer(int state); + inline void update_vsync_timer(int state); + inline void update_vlt_timer(int state); + inline void update_curs_timer(int state); + inline void update_drb_timer(int state); + inline void update_dma_timer(); + + inline void recompute_parameters(); + + // address space configurations + const address_space_config m_space_config; + + devcb_write_line m_write_int; + devcb_write_line m_write_dmar; + devcb_write_line m_write_hs; + devcb_write_line m_write_vs; + devcb_write_line m_write_vlt; + devcb_write_line m_write_curs; + devcb_write_line m_write_drb; + devcb_write_line m_write_wben; + devcb_write_line m_write_cblank; + devcb_write_line m_write_slg; + devcb_write_line m_write_sld; + + // registers + UINT8 m_reg[0x3d]; + UINT8 m_status; + + int m_disp; + int m_hpixels_per_column; + + // runtime variables, do not state save + int m_vsync_start; + int m_vsync_end; + int m_hsync_start; + int m_hsync_end; + int m_vlt_start; + int m_vlt_end; + int m_vlt_bottom; + int m_drb_bottom; + int m_hs; + int m_vs; + int m_cblank; + int m_vlt; + int m_drb; + //int m_wben; + //int m_slg; + //int m_sld; + int m_lpstb; + + // DMA + int m_dmar; + int m_ack; + int m_dma_count; + int m_dma_burst; + int m_dma_delay; + + // timers + emu_timer *m_vsync_timer; + emu_timer *m_hsync_timer; + emu_timer *m_vlt_timer; + emu_timer *m_curs_timer; + emu_timer *m_drb_timer; + emu_timer *m_dma_timer; +}; + + +// device type definition +extern const device_type CRT9007; + + + +#endif diff --git a/src/devices/video/crt9021.c b/src/devices/video/crt9021.c new file mode 100644 index 00000000000..d72baff2b2b --- /dev/null +++ b/src/devices/video/crt9021.c @@ -0,0 +1,187 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + SMC CRT9021 Video Attributes Controller (VAC) emulation + +**********************************************************************/ + +/* + + TODO: + + - attributes + - character blink + - underline + - full/half intensity + - operation modes + - wide graphics + - thin graphics + - character mode w/o underline + - character mode w/underline + - double height characters + - double width characters + - serial scan line + - cursor + - underline + - blinking underline + - reverse video + - blinking reverse video + - programmable character blink rate (75/25 duty) + - programmable cursor blink rate (50/50 duty) + - attribute latches + +*/ + +#include "crt9021.h" + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type CRT9021 = &device_creator; + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define LOG 0 + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// crt9021_t - constructor +//------------------------------------------------- + +crt9021_t::crt9021_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, CRT9021, "SMC CRT9021", tag, owner, clock, "crt9021", __FILE__), + device_video_interface(mconfig, *this), + m_data(0), + m_ms0(0), + m_ms1(0), + m_revid(0), + m_chabl(0), + m_blink(0), + m_intin(0), + m_atten(0), + m_cursor(0), + m_retbl(0), + m_ld_sh(1), + m_sld(1), + m_slg(0), + m_blc(0), + m_bkc(0), + m_sl0(0), + m_sl1(0), + m_sl2(0), + m_sl3(0), + m_vsync(0), + m_sr(0), + m_intout(0) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void crt9021_t::device_start() +{ + // register bitmap + m_screen->register_screen_bitmap(m_bitmap); + + // state saving + save_item(NAME(m_data)); + save_item(NAME(m_ms0)); + save_item(NAME(m_ms1)); + save_item(NAME(m_revid)); + save_item(NAME(m_chabl)); + save_item(NAME(m_blink)); + save_item(NAME(m_intin)); + save_item(NAME(m_atten)); + save_item(NAME(m_cursor)); + save_item(NAME(m_retbl)); + save_item(NAME(m_ld_sh)); + save_item(NAME(m_sld)); + save_item(NAME(m_slg)); + save_item(NAME(m_blc)); + save_item(NAME(m_bkc)); + save_item(NAME(m_sl0)); + save_item(NAME(m_sl1)); + save_item(NAME(m_sl2)); + save_item(NAME(m_sl3)); + save_item(NAME(m_vsync)); + save_item(NAME(m_sr)); + save_item(NAME(m_intout)); + save_item(NAME(m_sl)); +} + + +//------------------------------------------------- +// ld_sh_w - load/shift +//------------------------------------------------- + +WRITE_LINE_MEMBER( crt9021_t::ld_sh_w ) +{ + if (LOG) logerror("CRT9021 '%s' LD/SH: %u\n", tag(), state); + + if (!m_ld_sh && state) + { + // shift in scanline data + if (!m_slg) + { + m_sl >>= 1; + m_sl |= m_sld << 3; + } + + // latch data + if (m_retbl) + { + m_sr = 0; + } + else + { + m_sr = m_chabl ? 0 : m_data; + + if (m_revid) m_sr ^= 0xff; + } + + // latch attributes + if (m_atten) + { + // TODO + } + + m_display_cb(m_bitmap, m_screen->vpos(), m_screen->hpos(), m_sr, m_intout); + } +} + + +//------------------------------------------------- +// vsync_w - vertical sync +//------------------------------------------------- + +WRITE_LINE_MEMBER( crt9021_t::vsync_w ) +{ + if (LOG) logerror("CRT9021 '%s' VSYNC: %u\n", tag(), state); +} + + +//------------------------------------------------- +// screen_update - update screen +//------------------------------------------------- + +UINT32 crt9021_t::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + m_bitmap.fill(rgb_t::black, cliprect); + + return 0; +} diff --git a/src/devices/video/crt9021.h b/src/devices/video/crt9021.h new file mode 100644 index 00000000000..f050f7d745c --- /dev/null +++ b/src/devices/video/crt9021.h @@ -0,0 +1,139 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + SMC CRT9021 Video Attributes Controller (VAC) emulation + +********************************************************************** + _____ _____ + D0 1 |* \_/ | 28 D1 + MS0 2 | | 27 D2 + MS1 3 | | 26 D3 + REVID 4 | | 25 D4 + CHABL 5 | | 24 D5 + BLINK 6 | | 23 D6 + INTIN 7 | CRT9021 | 22 D7 + +5V 8 | | 21 _VSYNC + ATTEN 9 | | 20 GND + INTOUT 10 | | 19 SL0/SLD + CURSOR 11 | | 18 SL1/_SLG + RETBL 12 | | 17 SL2/BLC + _LD/SH 13 | | 16 SL3/BKC + VIDEO 14 |_____________| 15 VDC + +**********************************************************************/ + +#pragma once + +#ifndef __CRT9021__ +#define __CRT9021__ + +#include "emu.h" + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define CRT9021_DRAW_CHARACTER_MEMBER(_name) void _name(bitmap_rgb32 &bitmap, int y, int x, UINT8 video, int intout) + + +#define MCFG_CRT9021_DRAW_CHARACTER_CALLBACK_OWNER(_class, _method) \ + crt9021_t::static_set_display_callback(*device, crt9021_draw_character_delegate(&_class::_method, #_class "::" #_method, downcast<_class *>(owner))); + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +typedef device_delegate crt9021_draw_character_delegate; + + +// ======================> crt9021_t + +class crt9021_t : public device_t, + public device_video_interface +{ +public: + // construction/destruction + crt9021_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + static void static_set_display_callback(device_t &device, crt9021_draw_character_delegate callback) { downcast(device).m_display_cb = callback; } + + void write(UINT8 data) { m_data = data; } + DECLARE_WRITE8_MEMBER( write ) { write(data); } + DECLARE_WRITE_LINE_MEMBER( ms0_w ) { m_ms0 = state; } + DECLARE_WRITE_LINE_MEMBER( ms1_w ) { m_ms1 = state; } + DECLARE_WRITE_LINE_MEMBER( revid_w ) { m_revid = state; } + DECLARE_WRITE_LINE_MEMBER( chabl_w ) { m_chabl = state; } + DECLARE_WRITE_LINE_MEMBER( blink_w ) { m_blink = state; } + DECLARE_WRITE_LINE_MEMBER( intin_w ) { m_intin = state; } + DECLARE_WRITE_LINE_MEMBER( atten_w ) { m_atten = state; } + DECLARE_WRITE_LINE_MEMBER( cursor_w ) { m_cursor = state; } + DECLARE_WRITE_LINE_MEMBER( retbl_w ) { m_retbl = state; } + DECLARE_WRITE_LINE_MEMBER( ld_sh_w ); + DECLARE_WRITE_LINE_MEMBER( sld_w ) { m_sld = state; } + DECLARE_WRITE_LINE_MEMBER( slg_w ) { m_slg = state; } + DECLARE_WRITE_LINE_MEMBER( blc_w ) { m_blc = state; } + DECLARE_WRITE_LINE_MEMBER( bkc_w ) { m_bkc = state; } + DECLARE_WRITE_LINE_MEMBER( sl0_w ) { m_sl0 = state; } + DECLARE_WRITE_LINE_MEMBER( sl1_w ) { m_sl1 = state; } + DECLARE_WRITE_LINE_MEMBER( sl2_w ) { m_sl2 = state; } + DECLARE_WRITE_LINE_MEMBER( sl3_w ) { m_sl3 = state; } + DECLARE_WRITE_LINE_MEMBER( vsync_w ); + + UINT32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); + +protected: + // device-level overrides + virtual void device_start(); + +private: + enum + { + MS_WIDE_GRAPHICS, + MS_CHARACTER, + MS_THIN_GRAPHICS, + MS_UNDERLINE + }; + + crt9021_draw_character_delegate m_display_cb; + + bitmap_rgb32 m_bitmap; + + // inputs + UINT8 m_data; + int m_ms0; + int m_ms1; + int m_revid; + int m_chabl; + int m_blink; + int m_intin; + int m_atten; + int m_cursor; + int m_retbl; + int m_ld_sh; + int m_sld; + int m_slg; + int m_blc; + int m_bkc; + int m_sl0; + int m_sl1; + int m_sl2; + int m_sl3; + int m_vsync; + + // outputs + UINT8 m_sr; + int m_intout; + int m_sl; +}; + + +// device type definition +extern const device_type CRT9021; + + + +#endif diff --git a/src/devices/video/crt9212.c b/src/devices/video/crt9212.c new file mode 100644 index 00000000000..0535afa169b --- /dev/null +++ b/src/devices/video/crt9212.c @@ -0,0 +1,195 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + SMC CRT9212 Double Row Buffer (DRB) emulation + +**********************************************************************/ + +#include "crt9212.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type CRT9212 = &device_creator; + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define LOG 0 + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// crt9212_t - constructor +//------------------------------------------------- + +crt9212_t::crt9212_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, CRT9212, "SMC CRT9212", tag, owner, clock, "crt9212", __FILE__), + m_write_dout(*this), + m_write_rof(*this), + m_write_wof(*this), + m_data(0), + m_clrcnt(0), + m_tog(0), + m_ren(0), + m_wen1(1), + m_wen2(0), + m_oe(0), + m_rclk(0), + m_wclk(0), + m_clrcnt_edge(false), + m_data_latch(0), + m_ren_int(0), + m_wen_int(0), + m_buffer(0), + m_rac(0), + m_wac(0) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void crt9212_t::device_start() +{ + // resolve callbacks + m_write_dout.resolve_safe(); + m_write_rof.resolve_safe(); + m_write_wof.resolve_safe(); + + // state saving + save_item(NAME(m_data)); + save_item(NAME(m_clrcnt)); + save_item(NAME(m_tog)); + save_item(NAME(m_ren)); + save_item(NAME(m_wen1)); + save_item(NAME(m_wen2)); + save_item(NAME(m_oe)); + save_item(NAME(m_rclk)); + save_item(NAME(m_wclk)); + save_item(NAME(m_clrcnt_edge)); + save_item(NAME(m_data_latch)); + save_item(NAME(m_ren_int)); + save_item(NAME(m_wen_int)); + save_item(NAME(m_ram[0])); + save_item(NAME(m_ram[1])); + save_item(NAME(m_buffer)); + save_item(NAME(m_rac)); + save_item(NAME(m_wac)); +} + + +//------------------------------------------------- +// clrcnt_w - clear counter +//------------------------------------------------- + +WRITE_LINE_MEMBER( crt9212_t::clrcnt_w ) +{ + if (m_clrcnt && !state) + { + m_clrcnt_edge = true; + } + + m_clrcnt = state; +} + + +//------------------------------------------------- +// rclk_w - read clock +//------------------------------------------------- + +WRITE_LINE_MEMBER( crt9212_t::rclk_w ) +{ + if (!m_rclk && state) + { + if (m_clrcnt_edge) + { + // reset read address counter + m_rac = 0; + + // reset read overflow + m_write_rof(0); + + if (!m_tog) + { + // switch buffers + m_buffer = !m_buffer; + + // reset write address counter + m_wac = 0; + + // reset write overflow + m_write_wof(0); + } + + m_clrcnt_edge = false; + } + + if (m_ren_int && (m_rac < CRT9212_RAM_SIZE)) + { + // output data + m_write_dout(m_ram[m_rac][!m_buffer]); + + // increment read address counter + m_rac++; + + if (m_rac == CRT9212_RAM_SIZE - 1) + { + // set read overflow + m_write_rof(1); + } + } + + m_ren_int = m_ren; + } + + m_rclk = state; +} + + +//------------------------------------------------- +// wclk_w - write clock +//------------------------------------------------- + +WRITE_LINE_MEMBER( crt9212_t::wclk_w ) +{ + if (!m_wclk && state) + { + if (m_wen_int && (m_wac < CRT9212_RAM_SIZE)) + { + // input data + m_ram[m_rac][m_buffer] = m_data_latch; + + // increment write address counter + m_wac++; + + if (m_wac == CRT9212_RAM_SIZE - 1) + { + // set write overflow + m_write_wof(1); + } + } + + if (m_wen1 && m_wen2) + { + m_data_latch = m_data; + } + + m_wen_int = m_wen1 && m_wen2; + } + + m_wclk = state; +} diff --git a/src/devices/video/crt9212.h b/src/devices/video/crt9212.h new file mode 100644 index 00000000000..71590ee35f8 --- /dev/null +++ b/src/devices/video/crt9212.h @@ -0,0 +1,126 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + SMC CRT9212 Double Row Buffer (DRB) emulation + +********************************************************************** + _____ _____ + DIN2 1 |* \_/ | 28 DIN3 + DIN1 2 | | 27 _WCLK + DIN0 3 | | 26 _OE + DOUT7 4 | | 25 WEN2 + DOUT6 5 | | 24 WEN1 + DOUT5 6 | | 23 GND + DOUT4 7 | CRT9212 | 22 ROF + Vcc 8 | | 21 WOF + DOUT3 9 | | 20 REN + DOUT2 10 | | 19 _CLRCNT + DOUT1 11 | | 18 _TOG + DOUT0 12 | | 17 _RCLK + DIN7 13 | | 16 DIN4 + DIN6 14 |_____________| 15 DIN5 + +**********************************************************************/ + +#pragma once + +#ifndef __CRT9212__ +#define __CRT9212__ + +#include "emu.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +const int CRT9212_RAM_SIZE = 135; + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_CRT9212_WEN2_VCC() \ + crt9212_t::static_set_wen2(*device, 1); + +#define MCFG_CRT9212_DOUT_CALLBACK(_write) \ + devcb = &crt9212_t::set_dout_wr_callback(*device, DEVCB_##_write); + +#define MCFG_CRT9212_ROF_CALLBACK(_write) \ + devcb = &crt9212_t::set_rof_wr_callback(*device, DEVCB_##_write); + +#define MCFG_CRT9212_WOF_CALLBACK(_write) \ + devcb = &crt9212_t::set_wof_wr_callback(*device, DEVCB_##_write); + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> crt9212_t + +class crt9212_t : public device_t +{ +public: + // construction/destruction + crt9212_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + static void static_set_wen2(device_t &device, int state) { downcast(device).m_wen2 = state; } + + template static devcb_base &set_dout_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_dout.set_callback(object); } + template static devcb_base &set_rof_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_rof.set_callback(object); } + template static devcb_base &set_wof_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_wof.set_callback(object); } + + DECLARE_WRITE8_MEMBER( write ) { m_data = data; } + DECLARE_WRITE_LINE_MEMBER( clrcnt_w ); + DECLARE_WRITE_LINE_MEMBER( tog_w ) { m_tog = state; } + DECLARE_WRITE_LINE_MEMBER( ren_w ) { m_ren = state; } + DECLARE_WRITE_LINE_MEMBER( wen1_w ) { m_wen1 = state; } + DECLARE_WRITE_LINE_MEMBER( wen2_w ) { m_wen2 = state; } + DECLARE_WRITE_LINE_MEMBER( oe_w ) { m_oe = state; } + DECLARE_WRITE_LINE_MEMBER( rclk_w ); + DECLARE_WRITE_LINE_MEMBER( wclk_w ); + +protected: + // device-level overrides + virtual void device_start(); + +private: + devcb_write8 m_write_dout; + devcb_write_line m_write_rof; + devcb_write_line m_write_wof; + + // inputs + UINT8 m_data; + int m_clrcnt; + int m_tog; + int m_ren; + int m_wen1; + int m_wen2; + int m_oe; + int m_rclk; + int m_wclk; + + // internal state + bool m_clrcnt_edge; + UINT8 m_data_latch; + int m_ren_int; + int m_wen_int; + UINT8 m_ram[CRT9212_RAM_SIZE][2]; + int m_buffer; + int m_rac; + int m_wac; +}; + + +// device type definition +extern const device_type CRT9212; + + + +#endif diff --git a/src/devices/video/crtc_ega.c b/src/devices/video/crtc_ega.c new file mode 100644 index 00000000000..102df087008 --- /dev/null +++ b/src/devices/video/crtc_ega.c @@ -0,0 +1,728 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +/********************************************************************** + + IBM EGA CRT Controller emulation + + This controller is very loosely based on the mc6845. + +**********************************************************************/ + +#include "emu.h" +#include "crtc_ega.h" + + +#define LOG (1) + + +const device_type CRTC_EGA = &device_creator; + + +crtc_ega_device::crtc_ega_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, CRTC_EGA, "crtc_EGA", tag, owner, clock, "crtc_ega", __FILE__), + device_video_interface(mconfig, *this, false), + m_res_out_de_cb(*this), + m_res_out_hsync_cb(*this), + m_res_out_vsync_cb(*this), + m_res_out_vblank_cb(*this), + m_hpixels_per_column(0) +{ +} + + +void crtc_ega_device::device_post_load() +{ + recompute_parameters(true); +} + + +WRITE8_MEMBER( crtc_ega_device::address_w ) +{ + m_register_address_latch = data & 0x1f; +} + + +READ8_MEMBER( crtc_ega_device::register_r ) +{ + UINT8 ret = 0; + + switch (m_register_address_latch) + { + case 0x0c: ret = (m_disp_start_addr >> 8) & 0xff; break; + case 0x0d: ret = (m_disp_start_addr >> 0) & 0xff; break; + case 0x0e: ret = (m_cursor_addr >> 8) & 0xff; break; + case 0x0f: ret = (m_cursor_addr >> 0) & 0xff; break; + case 0x10: ret = (m_light_pen_addr >> 8) & 0xff; m_light_pen_latched = FALSE; break; + case 0x11: ret = (m_light_pen_addr >> 0) & 0xff; m_light_pen_latched = FALSE; break; + + /* all other registers are write only and return 0 */ + default: break; + } + + return ret; +} + + +WRITE8_MEMBER( crtc_ega_device::register_w ) +{ + if (LOG) logerror("%s CRTC_EGA: reg 0x%02x = 0x%02x\n", machine().describe_context(), m_register_address_latch, data); + + switch (m_register_address_latch) + { + case 0x00: m_horiz_char_total = data & 0xff; break; + case 0x01: m_horiz_disp = data & 0xff; break; + case 0x02: m_horiz_blank_start = data & 0xff; break; + case 0x03: m_horiz_blank_end = ((data & 0x1f) << 0) | (m_horiz_blank_end & 0x20); + m_de_skew = ((data & 0x60) >> 5); + m_ena_vert_access = data & 0x80; + break; + case 0x04: m_horiz_retr_start = data & 0xff; break; + case 0x05: m_horiz_retr_end = data & 0x1f; + m_horiz_retr_skew = ((data & 0x60) >> 5); + m_horiz_blank_end = ((data & 0x80) >> 2) | (m_horiz_blank_end & 0x1f); + break; + case 0x06: m_vert_total = ((data & 0xff) << 0) | (m_vert_total & 0x0300); break; + case 0x07: m_vert_total = ((data & 0x01) << 8) | (m_vert_total & 0x02ff); + m_vert_disp_end = ((data & 0x02) << 7) | (m_vert_disp_end & 0x02ff); + m_vert_retr_start = ((data & 0x04) << 6) | (m_vert_retr_start & 0x02ff); + m_vert_blank_start = ((data & 0x08) << 5) | (m_vert_blank_start & 0x02ff); + m_line_compare = ((data & 0x10) << 4) | (m_line_compare & 0x02ff); + m_vert_total = ((data & 0x20) << 4) | (m_vert_total & 0x01ff); + m_vert_disp_end = ((data & 0x40) << 3) | (m_vert_disp_end & 0x1ff); + m_vert_retr_start = ((data & 0x80) << 2) | (m_vert_retr_start & 0x01ff); + break; + case 0x08: m_preset_row_scan = data & 0x1f; + m_byte_panning = ((data & 0x60) >> 5); + break; + case 0x09: m_max_ras_addr = data & 0x1f; + m_vert_blank_start = ((data & 0x20) << 4) | (m_vert_blank_start & 0x01ff); + m_line_compare = ((data & 0x40) << 3) | (m_line_compare & 0x01ff); + m_scan_doubling = data & 0x80; + break; + case 0x0a: m_cursor_start_ras = data & 0x1f; + m_cursor_disable = data & 0x20; + break; + case 0x0b: m_cursor_end_ras = data & 0x1f; + m_cursor_skew = ((data & 0x60) >> 5); + break; + case 0x0c: m_disp_start_addr = ((data & 0xff) << 8) | (m_disp_start_addr & 0x00ff); break; + case 0x0d: m_disp_start_addr = ((data & 0xff) << 0) | (m_disp_start_addr & 0xff00); break; + case 0x0e: m_cursor_addr = ((data & 0xff) << 8) | (m_cursor_addr & 0x00ff); break; + case 0x0f: m_cursor_addr = ((data & 0xff) << 0) | (m_cursor_addr & 0xff00); break; + case 0x10: m_vert_retr_start = ((data & 0xff) << 0) | (m_vert_retr_start & 0x0300); break; + case 0x11: m_vert_retr_end = data & 0x0f; + m_bandwidth = data & 0x40; + m_protect = data & 0x80; + break; + case 0x12: m_vert_disp_end = ((data & 0xff) << 0) | (m_vert_disp_end & 0x0300); break; + case 0x13: m_offset = data & 0xff; break; + case 0x14: m_underline_loc = data & 0x7f; break; + case 0x15: m_vert_blank_start = ((data & 0xff) << 0) | (m_vert_blank_start & 0x0300); break; + case 0x16: m_vert_blank_end = data & 0x7f; break; + case 0x17: m_mode_control = data & 0xff; break; + case 0x18: m_line_compare = ((data & 0xff) << 0) | (m_line_compare & 0x0300); break; + default: break; + } + + recompute_parameters(false); +} + + +void crtc_ega_device::recompute_parameters(bool postload) +{ + UINT16 hsync_on_pos, hsync_off_pos, vsync_on_pos, vsync_off_pos; + + /* compute the screen sizes */ + UINT16 horiz_pix_total = (m_horiz_char_total + 2) * m_hpixels_per_column; + UINT16 vert_pix_total = m_vert_total + 1; + + /* determine the visible area, avoid division by 0 */ + UINT16 max_visible_x = ( m_horiz_disp + 1 ) * m_hpixels_per_column - 1; + UINT16 max_visible_y = m_vert_disp_end; + + /* determine the syncing positions */ + int horiz_sync_char_width = ( m_horiz_retr_end + 1 ) - ( m_horiz_retr_start & 0x1f ); + int vert_sync_pix_width = m_vert_retr_end - ( m_vert_retr_start & 0x0f ); + + if (horiz_sync_char_width <= 0) + horiz_sync_char_width += 0x10; + + if (vert_sync_pix_width <= 0) + vert_sync_pix_width += 0x10; + + hsync_on_pos = m_horiz_retr_start * m_hpixels_per_column; + hsync_off_pos = hsync_on_pos + (horiz_sync_char_width * m_hpixels_per_column); + vsync_on_pos = m_vert_retr_start; /* + 1 ?? */ + vsync_off_pos = vsync_on_pos + vert_sync_pix_width; + + if (hsync_off_pos > horiz_pix_total) + hsync_off_pos = horiz_pix_total; + + if (vsync_off_pos > vert_pix_total) + vsync_off_pos = vert_pix_total; + + if ( vsync_on_pos >= vsync_off_pos ) + { + vsync_on_pos = vsync_off_pos - 2; + } + + /* update only if screen parameters changed, unless we are coming here after loading the saved state */ + if (postload || + (horiz_pix_total != m_horiz_pix_total) || (vert_pix_total != m_vert_pix_total) || + (max_visible_x != m_max_visible_x) || (max_visible_y != m_max_visible_y) || + (hsync_on_pos != m_hsync_on_pos) || (vsync_on_pos != m_vsync_on_pos) || + (hsync_off_pos != m_hsync_off_pos) || (vsync_off_pos != m_vsync_off_pos)) + { + /* update the screen if we have valid data */ + if ((horiz_pix_total > 0) && (max_visible_x < horiz_pix_total) && + (vert_pix_total > 0) && (max_visible_y < vert_pix_total) && + (hsync_on_pos <= horiz_pix_total) && (vsync_on_pos <= vert_pix_total) && + (hsync_on_pos != hsync_off_pos)) + { + attoseconds_t refresh = HZ_TO_ATTOSECONDS(m_clock) * (m_horiz_char_total + 2) * vert_pix_total; + + rectangle visarea(0, max_visible_x, 0, max_visible_y); + + if (LOG) logerror("CRTC_EGA config screen: HTOTAL: 0x%x VTOTAL: 0x%x MAX_X: 0x%x MAX_Y: 0x%x HSYNC: 0x%x-0x%x VSYNC: 0x%x-0x%x Freq: %ffps\n", + horiz_pix_total, vert_pix_total, max_visible_x, max_visible_y, hsync_on_pos, hsync_off_pos - 1, vsync_on_pos, vsync_off_pos - 1, 1 / ATTOSECONDS_TO_DOUBLE(refresh)); + + if ( m_screen != NULL ) + m_screen->configure(horiz_pix_total, vert_pix_total, visarea, refresh); + + m_has_valid_parameters = true; + } + else + { + m_has_valid_parameters = false; + if (LOG) logerror("CRTC_EGA bad config screen: HTOTAL: 0x%x VTOTAL: 0x%x MAX_X: 0x%x MAX_Y: 0x%x HSYNC: 0x%x-0x%x VSYNC: 0x%x-0x%x\n", + horiz_pix_total, vert_pix_total, max_visible_x, max_visible_y, hsync_on_pos, hsync_off_pos - 1, vsync_on_pos, vsync_off_pos - 1); + + } + + m_horiz_pix_total = horiz_pix_total; + m_vert_pix_total = vert_pix_total; + m_max_visible_x = max_visible_x; + m_max_visible_y = max_visible_y; + m_hsync_on_pos = hsync_on_pos; + m_hsync_off_pos = hsync_off_pos; + m_vsync_on_pos = vsync_on_pos; + m_vsync_off_pos = vsync_off_pos; + } +} + + +void crtc_ega_device::update_counters() +{ + m_character_counter = m_line_timer->elapsed().as_ticks( m_clock ); + + if ( m_hsync_off_timer->enabled() ) + { + m_hsync_width_counter = m_hsync_off_timer->elapsed().as_ticks( m_clock ); + } +} + + +void crtc_ega_device::set_de(int state) +{ + if (m_de != state) + { + m_de = state; + + if (!m_res_out_de_cb.isnull()) + m_res_out_de_cb(m_de); + } +} + + +void crtc_ega_device::set_hsync(int state) +{ + if (m_hsync != state) + { + m_hsync = state; + + if (!m_res_out_hsync_cb.isnull()) + m_res_out_hsync_cb(m_hsync); + } +} + + +void crtc_ega_device::set_vsync(int state) +{ + if (m_vsync != state) + { + m_vsync = state; + + if (!m_res_out_vsync_cb.isnull()) + m_res_out_vsync_cb(m_vsync); + } +} + + +void crtc_ega_device::set_vblank(int state) +{ + if (m_vblank != state) + { + m_vblank = state; + + if (!m_res_out_vblank_cb.isnull()) + m_res_out_vblank_cb(m_vblank); + } +} + + +void crtc_ega_device::set_cur(int state) +{ + if (m_cur != state) + { + m_cur = state; + +// if (!m_res_out_cur_cb.isnull()) +// m_res_out_cur_cb(m_cur); + } +} + + +void crtc_ega_device::handle_line_timer() +{ + int new_vsync = m_vsync; + + m_character_counter = 0; + m_cursor_x = -1; + + /* Check if VSYNC is active */ + if ( m_vsync_ff ) + { + m_vsync_width_counter = ( m_vsync_width_counter + 1 ) & 0x0F; + + /* Check if we've reached end of VSYNC */ + if ( m_vsync_width_counter == m_vert_retr_end ) + { + m_vsync_ff = 0; + + new_vsync = FALSE; + } + } + + if ( m_raster_counter == m_max_ras_addr ) + { + m_raster_counter = 0; + m_line_address = ( m_line_address + m_horiz_disp + 1 ) & 0xffff; + } + else + { + m_raster_counter = ( m_raster_counter + 1 ) & 0x1F; + } + + m_line_counter = ( m_line_counter + 1 ) & 0x3ff; + + /* Check if we've reached the end of active display */ + if ( m_line_counter == m_vert_disp_end ) + { + m_line_enable_ff = false; + } + + /* Check if VSYNC should be enabled */ + if ( m_line_counter == m_vert_retr_start ) + { + m_vsync_width_counter = 0; + m_vsync_ff = 1; + + new_vsync = TRUE; + } + + /* Check if we have reached the end of the vertical area */ + if ( m_line_counter == m_vert_total ) + { + m_line_counter = 0; + m_line_address = m_disp_start_addr; + m_line_enable_ff = true; + set_vblank( FALSE ); + /* also update the cursor state now */ + update_cursor_state(); + + if (m_screen != NULL) + m_screen->reset_origin(); + } + + if ( m_line_enable_ff ) + { + /* Schedule DE off signal change */ + m_de_off_timer->adjust(attotime::from_ticks( m_horiz_disp + 1, m_clock )); + + /* Is cursor visible on this line? */ + if ( m_cursor_state && + (m_raster_counter >= (m_cursor_start_ras & 0x1f)) && + (m_raster_counter <= m_cursor_end_ras) && + (m_cursor_addr >= m_line_address) && + (m_cursor_addr < (m_line_address + m_horiz_disp + 1)) ) + { + m_cursor_x = m_cursor_addr - m_line_address; + + /* Schedule CURSOR ON signal */ + m_cur_on_timer->adjust( attotime::from_ticks( m_cursor_x, m_clock ) ); + } + } + + /* Schedule HSYNC on signal */ + m_hsync_on_timer->adjust( attotime::from_ticks( m_horiz_blank_start, m_clock ) ); + + /* Set VBlank signal */ + if ( m_line_counter == m_vert_disp_end + 1 ) + { + set_vblank( TRUE ); + } + + /* Schedule our next callback */ + m_line_timer->adjust( attotime::from_ticks( m_horiz_char_total + 2, m_clock ) ); + + /* Set VSYNC and DE signals */ + set_vsync( new_vsync ); + set_de( m_line_enable_ff ? TRUE : FALSE ); +} + + +void crtc_ega_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch (id) + { + case TIMER_LINE: + handle_line_timer(); + break; + + case TIMER_DE_OFF: + set_de( FALSE ); + break; + + case TIMER_CUR_ON: + set_cur( TRUE ); + + /* Schedule CURSOR off signal */ + m_cur_off_timer->adjust( attotime::from_ticks( 1, m_clock ) ); + break; + + case TIMER_CUR_OFF: + set_cur( FALSE ); + break; + + case TIMER_HSYNC_ON: + { + INT8 hsync_width = ( 0x20 | m_horiz_blank_end ) - ( m_horiz_blank_start & 0x1f ); + + if ( hsync_width <= 0 ) + { + hsync_width += 0x20; + } + + m_hsync_width_counter = 0; + set_hsync( TRUE ); + + /* Schedule HSYNC off signal */ + m_hsync_off_timer->adjust( attotime::from_ticks( hsync_width, m_clock ) ); + } + break; + + case TIMER_HSYNC_OFF: + set_hsync( FALSE ); + break; + + case TIMER_LIGHT_PEN_LATCH: + m_light_pen_addr = get_ma(); + m_light_pen_latched = true; + break; + } +} + + +UINT16 crtc_ega_device::get_ma() +{ + update_counters(); + + return m_line_address + m_character_counter; +} + + +UINT8 crtc_ega_device::get_ra() +{ + return m_raster_counter; +} + + +void crtc_ega_device::assert_light_pen_input() +{ + /* compute the pixel coordinate of the NEXT character -- this is when the light pen latches */ + /* set the timer that will latch the display address into the light pen registers */ + m_light_pen_latch_timer->adjust(attotime::from_ticks( 1, m_clock )); +} + + +void crtc_ega_device::set_clock(int clock) +{ + /* validate arguments */ + assert(clock > 0); + + if (clock != m_clock) + { + m_clock = clock; + recompute_parameters(true); + } +} + + +void crtc_ega_device::set_hpixels_per_column(int hpixels_per_column) +{ + /* validate arguments */ + assert(hpixels_per_column > 0); + + if (hpixels_per_column != m_hpixels_per_column) + { + m_hpixels_per_column = hpixels_per_column; + recompute_parameters(true); + } +} + + +void crtc_ega_device::update_cursor_state() +{ + /* save and increment cursor counter */ + UINT8 last_cursor_blink_count = m_cursor_blink_count; + m_cursor_blink_count = m_cursor_blink_count + 1; + + /* switch on cursor blinking mode */ + switch (m_cursor_start_ras & 0x60) + { + /* always on */ + case 0x00: m_cursor_state = true; break; + + /* always off */ + case 0x20: m_cursor_state = false; break; + + /* fast blink */ + case 0x40: + if ((last_cursor_blink_count & 0x10) != (m_cursor_blink_count & 0x10)) + { + m_cursor_state = !m_cursor_state; + } + break; + + /* slow blink */ + case 0x60: + if ((last_cursor_blink_count & 0x20) != (m_cursor_blink_count & 0x20)) + { + m_cursor_state = !m_cursor_state; + } + break; + } +} + + +UINT32 crtc_ega_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) +{ + assert(bitmap.valid()); + + if (m_has_valid_parameters) + { + UINT16 y; + + assert(!m_row_update_cb.isnull()); + + /* call the set up function if any */ + if (!m_begin_update_cb.isnull()) + m_begin_update_cb(bitmap, cliprect); + + if (cliprect.min_y == 0) + { + /* read the start address at the beginning of the frame */ + m_current_disp_addr = m_disp_start_addr; + } + + /* for each row in the visible region */ + for (y = cliprect.min_y; y <= cliprect.max_y; y++) + { + /* compute the current raster line */ + UINT8 ra = y % (m_max_ras_addr + 1); + + /* check if the cursor is visible and is on this scanline */ + int cursor_visible = m_cursor_state && + (ra >= (m_cursor_start_ras & 0x1f)) && + ( (ra <= (m_cursor_end_ras & 0x1f)) || ((m_cursor_end_ras & 0x1f) == 0x00 )) && + (m_cursor_addr >= m_current_disp_addr) && + (m_cursor_addr < (m_current_disp_addr + ( m_horiz_disp + 1 ))); + + /* compute the cursor X position, or -1 if not visible */ + INT8 cursor_x = cursor_visible ? (m_cursor_addr - m_current_disp_addr) : -1; + + /* call the external system to draw it */ + m_row_update_cb(bitmap, cliprect, m_current_disp_addr, ra, y, m_horiz_disp + 1, cursor_x); + + /* update MA if the last raster address */ + if (ra == m_max_ras_addr) + m_current_disp_addr = (m_current_disp_addr + m_horiz_disp + 1) & 0xffff; + } + + /* call the tear down function if any */ + if (!m_end_update_cb.isnull()) + m_end_update_cb(bitmap, cliprect); + } + else + logerror("Invalid crtc_ega screen parameters - display disabled!!!\n"); + + return 0; +} + + +/* device interface */ +void crtc_ega_device::device_start() +{ + /* validate arguments */ + assert(m_clock > 0); + assert(m_hpixels_per_column > 0); + + /* resolve callbacks */ + m_res_out_de_cb.resolve(); + m_res_out_hsync_cb.resolve(); + m_res_out_vsync_cb.resolve(); + m_res_out_vblank_cb.resolve(); + + /* bind delegates */ + m_begin_update_cb.bind_relative_to(*owner()); + m_row_update_cb.bind_relative_to(*owner()); + m_end_update_cb.bind_relative_to(*owner()); + + /* create the timers */ + m_line_timer = timer_alloc(TIMER_LINE); + m_de_off_timer = timer_alloc(TIMER_DE_OFF); + m_cur_on_timer = timer_alloc(TIMER_CUR_ON); + m_cur_off_timer = timer_alloc(TIMER_CUR_OFF); + m_hsync_on_timer = timer_alloc(TIMER_HSYNC_ON); + m_hsync_off_timer = timer_alloc(TIMER_HSYNC_OFF); + m_light_pen_latch_timer = timer_alloc(TIMER_LIGHT_PEN_LATCH); + + /* Use some large startup values */ + m_horiz_char_total = 0xff; + m_max_ras_addr = 0x1f; + m_vert_total = 0x3ff; + + m_ena_vert_access = 0; + m_de_skew = 0; + m_horiz_retr_start = 0; + m_horiz_retr_end = 0; + m_horiz_retr_skew = 0; + m_preset_row_scan = 0; + m_byte_panning = 0; + m_scan_doubling = 0; + m_cursor_start_ras = 0x20; + m_cursor_disable = 0; + m_cursor_end_ras = 0; + m_cursor_skew = 0; + m_disp_start_addr = 0; + m_light_pen_addr = 0; + m_vert_retr_end = 0; + m_protect = 0; + m_bandwidth = 0; + m_offset = 0; + m_underline_loc = 0; + m_vert_blank_end = 0; + m_mode_control = 0; + m_line_compare = 0; + m_register_address_latch = 0; + m_cursor_state = false; + m_cursor_blink_count = 0; + m_cur = 0; + m_hsync = 0; + m_vsync = 0; + m_vblank = 0; + m_de = 0; + m_character_counter = 0; + m_hsync_width_counter = 0; + m_vsync_width_counter = 0; + m_line_enable_ff = false; + m_vsync_ff = 0; + m_adjust_active = 0; + + m_current_disp_addr = 0; + m_light_pen_latched = FALSE; + m_has_valid_parameters = false; + + /* register for state saving */ + save_item(NAME(m_hpixels_per_column)); + save_item(NAME(m_register_address_latch)); + save_item(NAME(m_horiz_char_total)); + save_item(NAME(m_horiz_disp)); + save_item(NAME(m_horiz_blank_start)); + save_item(NAME(m_mode_control)); + save_item(NAME(m_cursor_start_ras)); + save_item(NAME(m_cursor_end_ras)); + save_item(NAME(m_disp_start_addr)); + save_item(NAME(m_cursor_addr)); + save_item(NAME(m_light_pen_addr)); + save_item(NAME(m_light_pen_latched)); + save_item(NAME(m_cursor_state)); + save_item(NAME(m_cursor_blink_count)); + save_item(NAME(m_horiz_blank_end)); + save_item(NAME(m_ena_vert_access)); + save_item(NAME(m_de_skew)); + save_item(NAME(m_horiz_retr_start)); + save_item(NAME(m_horiz_retr_end)); + save_item(NAME(m_horiz_retr_skew)); + save_item(NAME(m_vert_total)); + save_item(NAME(m_preset_row_scan)); + save_item(NAME(m_byte_panning)); + save_item(NAME(m_max_ras_addr)); + save_item(NAME(m_scan_doubling)); + save_item(NAME(m_cursor_disable)); + save_item(NAME(m_cursor_skew)); + save_item(NAME(m_vert_retr_start)); + save_item(NAME(m_vert_retr_end)); + save_item(NAME(m_protect)); + save_item(NAME(m_bandwidth)); + save_item(NAME(m_vert_disp_end)); + save_item(NAME(m_offset)); + save_item(NAME(m_underline_loc)); + save_item(NAME(m_vert_blank_start)); + save_item(NAME(m_vert_blank_end)); + save_item(NAME(m_line_compare)); +} + + +void crtc_ega_device::device_reset() +{ + /* internal registers other than status remain unchanged, all outputs go low */ + if (!m_res_out_de_cb.isnull()) + m_res_out_de_cb(false); + + if (!m_res_out_hsync_cb.isnull()) + m_res_out_hsync_cb(false); + + if (!m_res_out_vsync_cb.isnull()) + m_res_out_vsync_cb(false); + + if (!m_res_out_vblank_cb.isnull()) + m_res_out_vblank_cb(false); + + if (!m_line_timer->enabled()) + { + m_line_timer->adjust( attotime::from_ticks( m_horiz_char_total + 2, m_clock ) ); + } + + m_light_pen_latched = false; + + m_cursor_addr = 0; + m_line_address = 0; + m_horiz_disp = 0; + m_cursor_x = 0; + m_horiz_blank_start = 0; + m_horiz_blank_end = 0; + m_vert_disp_end = 0; + m_vert_retr_start = 0; + m_vert_blank_start = 0; + m_line_counter = 0; + m_raster_counter = 0; + m_horiz_pix_total = 0; + m_vert_pix_total = 0; + m_max_visible_x = 0; + m_max_visible_y = 0; + m_hsync_on_pos = 0; + m_vsync_on_pos = 0; + m_hsync_off_pos = 0; + m_vsync_off_pos = 0; +} diff --git a/src/devices/video/crtc_ega.h b/src/devices/video/crtc_ega.h new file mode 100644 index 00000000000..b06fa31560c --- /dev/null +++ b/src/devices/video/crtc_ega.h @@ -0,0 +1,236 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +/********************************************************************** + + IBM EGA CRT Controller emulation + +**********************************************************************/ + +#ifndef __CRTC_EGA__ +#define __CRTC_EGA__ + +#include "emu.h" + +/* callback definitions */ +typedef device_delegate crtc_ega_begin_update_delegate; + +typedef device_delegate crtc_ega_row_update_delegate; + +typedef device_delegate crtc_ega_end_update_delegate; + + +#define CRTC_EGA_BEGIN_UPDATE(_name) void _name(bitmap_ind16 &bitmap, const rectangle &cliprect) +#define CRTC_EGA_ROW_UPDATE(_name) void _name(bitmap_ind16 &bitmap, \ + const rectangle &cliprect, UINT16 ma, UINT8 ra, \ + UINT16 y, UINT8 x_count, INT8 cursor_x) +#define CRTC_EGA_END_UPDATE(_name) void _name(bitmap_ind16 &bitmap, const rectangle &cliprect) + + + +#define MCFG_CRTC_EGA_SET_SCREEN MCFG_VIDEO_SET_SCREEN + +#define MCFG_CRTC_EGA_BEGIN_UPDATE_CB(_class, _method) \ + crtc_ega_device::set_begin_update_callback(*device, crtc_ega_begin_update_delegate(&_class::_method, #_class "::" #_method, downcast<_class *>(owner))); + +#define MCFG_CRTC_EGA_ROW_UPDATE_CB(_class, _method) \ + crtc_ega_device::set_row_update_callback(*device, crtc_ega_row_update_delegate(&_class::_method, #_class "::" #_method, downcast<_class *>(owner))); + +#define MCFG_CRTC_EGA_END_UPDATE_CB(_class, _method) \ + crtc_ega_device::set_end_update_callback(*device, crtc_ega_end_update_delegate(&_class::_method, #_class "::" #_method, downcast<_class *>(owner))); + +#define MCFG_CRTC_EGA_HPIXELS_PER_COLUMN(_pix) \ + crtc_ega_device::set_hpixels_per_column(*device, _pix); + +#define MCFG_CRTC_EGA_RES_OUT_DE_CB(_devcb) \ + devcb = &crtc_ega_device::set_res_out_de_callback(*device, DEVCB_##_devcb); + +#define MCFG_CRTC_EGA_RES_OUT_HSYNC_CB(_devcb) \ + devcb = &crtc_ega_device::set_res_out_hsync_callback(*device, DEVCB_##_devcb); + +#define MCFG_CRTC_EGA_RES_OUT_VSYNC_CB(_devcb) \ + devcb = &crtc_ega_device::set_res_out_vsync_callback(*device, DEVCB_##_devcb); + +#define MCFG_CRTC_EGA_RES_OUT_VBLANK_CB(_devcb) \ + devcb = &crtc_ega_device::set_res_out_vblank_callback(*device, DEVCB_##_devcb); + + +class crtc_ega_device : public device_t, + public device_video_interface +{ +public: + crtc_ega_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + template static devcb_base &set_res_out_de_callback(device_t &device, _Object object) + { return downcast(device).m_res_out_de_cb.set_callback(object); } + template static devcb_base &set_res_out_hsync_callback(device_t &device, _Object object) + { return downcast(device).m_res_out_hsync_cb.set_callback(object); } + template static devcb_base &set_res_out_vsync_callback(device_t &device, _Object object) + { return downcast(device).m_res_out_vsync_cb.set_callback(object); } + template static devcb_base &set_res_out_vblank_callback(device_t &device, _Object object) + { return downcast(device).m_res_out_vblank_cb.set_callback(object); } + + static void set_begin_update_callback(device_t &device, crtc_ega_begin_update_delegate callback) { downcast(device).m_begin_update_cb = callback; } + static void set_row_update_callback(device_t &device, crtc_ega_row_update_delegate callback) { downcast(device).m_row_update_cb = callback; } + static void set_end_update_callback(device_t &device, crtc_ega_end_update_delegate callback) { downcast(device).m_end_update_cb = callback; } + static void set_hpixels_per_column(device_t &device, int hpixels_per_column) { downcast(device).m_hpixels_per_column = hpixels_per_column; } + + /* select one of the registers for reading or writing */ + DECLARE_WRITE8_MEMBER( address_w ); + + /* read from the currently selected register */ + DECLARE_READ8_MEMBER( register_r ); + + /* write to the currently selected register */ + DECLARE_WRITE8_MEMBER( register_w ); + + /* return the current value on the MA0-MA15 pins */ + UINT16 get_ma(); + + /* return the current value on the RA0-RA4 pins */ + UINT8 get_ra(); + + /* simulates the LO->HI clocking of the light pen pin */ + void assert_light_pen_input(); + + /* set the clock of the chip */ + void set_clock(int clock); + + /* set number of pixels per video memory address */ + void set_hpixels_per_column(int hpixels_per_column); + + /* updates the screen -- this will call begin_update(), */ + /* followed by update_row() reapeatedly and after all row */ + /* updating is complete, end_update() */ + UINT32 screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_post_load(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + +private: + devcb_write_line m_res_out_de_cb; + devcb_write_line m_res_out_hsync_cb; + devcb_write_line m_res_out_vsync_cb; + devcb_write_line m_res_out_vblank_cb; + + /* if specified, this gets called before any pixel update, + optionally return a pointer that will be passed to the + update and tear down callbacks */ + crtc_ega_begin_update_delegate m_begin_update_cb; + + /* this gets called for every row, the driver must output + x_count * hpixels_per_column pixels. + cursor_x indicates the character position where the cursor is, or -1 + if there is no cursor on this row */ + crtc_ega_row_update_delegate m_row_update_cb; + + /* if specified, this gets called after all row updating is complete */ + crtc_ega_end_update_delegate m_end_update_cb; + + /* ega/vga register file */ + UINT8 m_horiz_char_total; /* 0x00 */ + UINT8 m_horiz_disp; /* 0x01 */ + UINT8 m_horiz_blank_start; /* 0x02 */ + UINT8 m_horiz_blank_end; /* 0x03/0x05 */ + UINT8 m_ena_vert_access; /* 0x03 */ + UINT8 m_de_skew; /* 0x03 */ + UINT8 m_horiz_retr_start; /* 0x04 */ + UINT8 m_horiz_retr_end; /* 0x05 */ + UINT8 m_horiz_retr_skew; /* 0x05 */ + UINT16 m_vert_total; /* 0x06/0x07 */ + UINT8 m_preset_row_scan; /* 0x08 */ + UINT8 m_byte_panning; /* 0x08 */ + UINT8 m_max_ras_addr; /* 0x09 */ + UINT8 m_scan_doubling; /* 0x09 */ + UINT8 m_cursor_start_ras; /* 0x0a */ + UINT8 m_cursor_disable; /* 0x0a */ + UINT8 m_cursor_end_ras; /* 0x0b */ + UINT8 m_cursor_skew; /* 0x0b */ + UINT16 m_disp_start_addr; /* 0x0c/0x0d */ + UINT16 m_cursor_addr; /* 0x0e/0x0f */ + UINT16 m_light_pen_addr; /* 0x10/0x11 */ + UINT16 m_vert_retr_start; /* 0x10/0x07 */ + UINT8 m_vert_retr_end; /* 0x11 */ + UINT8 m_protect; /* 0x11 */ + UINT8 m_bandwidth; /* 0x11 */ + UINT16 m_vert_disp_end; /* 0x12/0x07 */ + UINT8 m_offset; /* 0x13 */ + UINT8 m_underline_loc; /* 0x14 */ + UINT16 m_vert_blank_start; /* 0x15/0x07/0x09 */ + UINT8 m_vert_blank_end; /* 0x16 */ + UINT8 m_mode_control; /* 0x17 */ + UINT16 m_line_compare; /* 0x18/0x07/0x09 */ + + /* other internal state */ + UINT8 m_register_address_latch; + bool m_cursor_state; /* 0 = off, 1 = on */ + UINT8 m_cursor_blink_count; + int m_hpixels_per_column; /* number of pixels per video memory address */ + + /* output signals */ + int m_cur; + int m_hsync; + int m_vsync; + int m_vblank; + int m_de; + + /* internal counters */ + UINT8 m_character_counter; + UINT8 m_hsync_width_counter; + UINT16 m_line_counter; + UINT8 m_raster_counter; + UINT8 m_vsync_width_counter; + bool m_line_enable_ff; /* Internal flip flop which is set when the line_counter is reset and reset when vert_disp is reached */ + UINT8 m_vsync_ff; + UINT8 m_adjust_active; + UINT16 m_line_address; + INT16 m_cursor_x; + + /* timers */ + static const device_timer_id TIMER_LINE = 0; + static const device_timer_id TIMER_DE_OFF = 1; + static const device_timer_id TIMER_CUR_ON = 2; + static const device_timer_id TIMER_CUR_OFF = 3; + static const device_timer_id TIMER_HSYNC_ON = 4; + static const device_timer_id TIMER_HSYNC_OFF = 5; + static const device_timer_id TIMER_LIGHT_PEN_LATCH = 6; + + emu_timer *m_line_timer; + emu_timer *m_de_off_timer; + emu_timer *m_cur_on_timer; + emu_timer *m_cur_off_timer; + emu_timer *m_hsync_on_timer; + emu_timer *m_hsync_off_timer; + emu_timer *m_light_pen_latch_timer; + + /* computed values - do NOT state save these! */ + UINT16 m_horiz_pix_total; + UINT16 m_vert_pix_total; + UINT16 m_max_visible_x; + UINT16 m_max_visible_y; + UINT16 m_hsync_on_pos; + UINT16 m_hsync_off_pos; + UINT16 m_vsync_on_pos; + UINT16 m_vsync_off_pos; + UINT16 m_current_disp_addr; /* the display address currently drawn */ + UINT8 m_light_pen_latched; + bool m_has_valid_parameters; + + void recompute_parameters(bool postload); + void update_counters(); + void set_de(int state); + void set_hsync(int state); + void set_vsync(int state); + void set_vblank(int state); + void set_cur(int state); + void handle_line_timer(); + void update_cursor_state(); +}; + +extern const device_type CRTC_EGA; + +#endif diff --git a/src/devices/video/dl1416.c b/src/devices/video/dl1416.c new file mode 100644 index 00000000000..b017e9994e1 --- /dev/null +++ b/src/devices/video/dl1416.c @@ -0,0 +1,297 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best +/***************************************************************************** + * + * DL1416 + * + * + * 4-Digit 16-Segment Alphanumeric Intelligent Display + * with Memory/Decoder/Driver + * + * Notes: + * - Currently supports the DL1416T and by virtue of it being nearly the same, the DL1414. + * - Partial support for DL1416B is available, it just needs the right + * character set and MAME core support for its display. + * - Cursor support is implemented but not tested, as the AIM65 does not + * seem to use it. + * + * Todo: + * - Is the DL1416A identical to the DL1416T? If not, we need to add + * support for it. + * - Add proper support for DL1414 (pretty much DL1416T without the cursor) + * + * Changes: + * - 2007-07-30: Initial version. [Dirk Best] + * - 2008-02-25: Converted to the new device interface. [Dirk Best] + * - 2008-12-18: Cleanups. [Dirk Best] + * - 2011-10-08: Changed the ram to store character rather than segment data. [Lord Nightmare] + * + * + * We use the following order for the segments: + * + * 000 111 + * 7D A E2 + * 7 D A E 2 + * 7 DAE 2 + * 888 999 + * 6 CBF 3 + * 6 C B F 3 + * 6C B F3 + * 555 444 + * + ****************************************************************************/ + +#include "emu.h" +#include "dl1416.h" + + +/*************************************************************************** + CONSTANTS +***************************************************************************/ + +#define SEG_UNDEF (0xfffe) +#define SEG_BLANK (0) +#define SEG_CURSOR (0xffff) +#define CURSOR_ON (1) +#define CURSOR_OFF (0) + +/* character set DL1416T */ +static const UINT16 dl1416t_segments[128] = { + SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, /* undefined */ + SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, /* undefined */ + SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, /* undefined */ + SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, /* undefined */ + SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, /* undefined */ + SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, /* undefined */ + SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, /* undefined */ + SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, /* undefined */ + 0x0000, 0x2421, 0x0480, 0x0f3c, /* ! " # */ + 0x0fbb, 0x5f99, 0xa579, 0x4000, /* $ % & ' */ + 0xc000, 0x3000, 0xff00, 0x0f00, /* ( ) * + */ + 0x1000, 0x0300, 0x0020, 0x5000, /* , - . / */ + 0x0ce1, 0x0c00, 0x0561, 0x0d21, /* 0 1 2 3 */ + 0x0d80, 0x09a1, 0x09e1, 0x0c01, /* 4 5 6 7 */ + 0x0de1, 0x0da1, 0x0021, 0x1001, /* 8 9 : ; */ + 0x5030, 0x0330, 0xa030, 0x0a07, /* < = > ? */ + 0x097f, 0x03cf, 0x0e3f, 0x00f3, /* @ A B C */ + 0x0c3f, 0x01f3, 0x01c3, 0x02fb, /* D E F G */ + 0x03cc, 0x0c33, 0x0c63, 0xc1c0, /* H I J K */ + 0x00f0, 0x60cc, 0xa0cc, 0x00ff, /* L M N O */ + 0x03c7, 0x80ff, 0x83c7, 0x03bb, /* P Q R S */ + 0x0c03, 0x00fc, 0x50c0, 0x90cc, /* T U V W */ + 0xf000, 0x6800, 0x5033, 0x00e1, /* X Y Z [ */ + 0xa000, 0x001e, 0x9000, 0x0030, /* \ ] ^ _ */ + SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, /* undefined */ + SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, /* undefined */ + SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, /* undefined */ + SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, /* undefined */ + SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, /* undefined */ + SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, /* undefined */ + SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, /* undefined */ + SEG_UNDEF, SEG_UNDEF, SEG_UNDEF, SEG_UNDEF /* undefined */ +}; + + +/***************************************************************************** + DEVICE INTERFACE +*****************************************************************************/ + +dl1416_device::dl1416_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + m_write_enable(FALSE), + m_chip_enable(FALSE), + m_cursor_enable(FALSE), + m_update(*this) +{ + for (int i = 0; i < 4; i++) + { + m_digit_ram[i] = 0; + m_cursor_state[i] = 0; + } +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void dl1416_device::device_start() +{ + /* register for state saving */ + save_item(NAME(m_chip_enable)); + save_item(NAME(m_cursor_enable)); + save_item(NAME(m_write_enable)); + save_item(NAME(m_digit_ram)); + + m_update.resolve(); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void dl1416_device::device_reset() +{ + int i; + UINT16 pattern; + /* disable all lines */ + m_chip_enable = FALSE; + m_write_enable = FALSE; + m_cursor_enable = FALSE; + + /* randomize digit and cursor memory */ + for (i = 0; i < 4; i++) + { + m_digit_ram[i] = machine().rand()&0x3F; + // TODO: only enable the following line if the device actually has a cursor (DL1416T and DL1416B), if DL1414 then cursor is always 0! + //m_cursor_state[i] = ((device->machine().rand()&0xFF) >= 0x80) ? CURSOR_ON : CURSOR_OFF; + m_cursor_state[i] = CURSOR_OFF; + pattern = dl1416t_segments[m_digit_ram[i]]; + + /* If cursor for this digit position is enabled and segment is not */ + /* undefined, replace digit with cursor */ + if ((m_cursor_state[i] == CURSOR_ON) && (pattern != SEG_UNDEF)) + pattern = SEG_CURSOR; + + /* Undefined characters are replaced by blanks */ + if (pattern == SEG_UNDEF) + pattern = SEG_BLANK; + + /* Call update function */ + if (!m_update.isnull()) + m_update((offs_t)i, pattern); + } +} + + +const device_type DL1416B = &device_creator; + +dl1416b_device::dl1416b_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : dl1416_device(mconfig, DL1416B, "DL1416B", tag, owner, clock, "dl1416b", __FILE__) +{ +} + + +const device_type DL1416T = &device_creator; + +dl1416t_device::dl1416t_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : dl1416_device(mconfig, DL1416T, "DL1416T", tag, owner, clock, "dl1416t", __FILE__) +{ +} + + +/***************************************************************************** + IMPLEMENTATION +*****************************************************************************/ + +/* write enable, active low */ +WRITE_LINE_MEMBER( dl1416_device::wr_w ) +{ + m_write_enable = !state; +} + +/* chip enable, active low */ +WRITE_LINE_MEMBER( dl1416_device::ce_w ) +{ + m_chip_enable = !state; +} + +/* cursor enable, active low */ +WRITE_LINE_MEMBER( dl1416_device::cu_w ) +{ + m_cursor_enable = !state; +} + +/* data */ +WRITE8_MEMBER( dl1416_device::data_w ) +{ + offset &= 0x03; /* A0-A1 */ + data &= 0x7f; /* D0-D6 */ + + /* Only try to update the data if we are enabled and write is enabled */ + if (m_chip_enable && m_write_enable) + { + /* fprintf(stderr,"DL1416 Write: Cursor: %d, Offset: %d, Data: %02X\n (%c)", m_cursor_enable, offset, data, data); */ + int i, pattern, previous_state; + + if (m_cursor_enable) /* cursor enable is set */ + { + if (type() == DL1416B) + { + /* DL1416B uses offset to decide cursor pos to change and D0 to hold new state */ + + /* The cursor will be set if D0 is high and the original */ + /* character restored otherwise */ + previous_state = m_cursor_state[offset]; + m_cursor_state[offset] = data & 1 ? CURSOR_ON : CURSOR_OFF; + + if (previous_state != m_cursor_state[offset]) + { + pattern = dl1416t_segments[m_digit_ram[offset]]; + + /* If cursor for this digit position is enabled and segment is not */ + /* undefined, replace digit with cursor */ + if ((m_cursor_state[offset] == CURSOR_ON) && (pattern != SEG_UNDEF)) + pattern = SEG_CURSOR; + + /* Undefined characters are replaced by blanks */ + if (pattern == SEG_UNDEF) + pattern = SEG_BLANK; + + /* Call update function */ + if (!m_update.isnull()) + m_update(offset, pattern, mem_mask); + } + } + else { + /* DL1416T uses a bitmap of 4 data bits D0,D1,D2,D3 to decide cursor pos to change and new state */ + + for (i = 0; i < 4; i++) + { + /* The cursor will be set if D0-D3 is high and the original */ + /* character at the appropriate position restored otherwise */ + previous_state = m_cursor_state[i]; + m_cursor_state[i] = data & (1< static devcb_base &set_update_handler(device_t &device, _Object object) { return downcast(device).m_update.set_callback(object); } + + /* inputs */ + DECLARE_WRITE_LINE_MEMBER( wr_w ); /* write enable */ + DECLARE_WRITE_LINE_MEMBER( ce_w ); /* chip enable */ + DECLARE_WRITE_LINE_MEMBER( cu_w ); /* cursor enable */ + DECLARE_WRITE8_MEMBER( data_w ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + +private: + // internal state + int m_write_enable; + int m_chip_enable; + int m_cursor_enable; + devcb_write16 m_update; + + UINT16 m_digit_ram[4]; // holds the digit code for each position + UINT8 m_cursor_state[4]; // holds the cursor state for each position, 0=off, 1=on +}; + +class dl1416b_device : public dl1416_device +{ +public: + dl1416b_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +extern const device_type DL1416B; + +class dl1416t_device : public dl1416_device +{ +public: + dl1416t_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +extern const device_type DL1416T; + + +#endif /* DL1416_H_ */ diff --git a/src/devices/video/dm9368.c b/src/devices/video/dm9368.c new file mode 100644 index 00000000000..16dee4e420f --- /dev/null +++ b/src/devices/video/dm9368.c @@ -0,0 +1,96 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Fairchild DM9368 7-Segment Decoder/Driver/Latch emulation + +**********************************************************************/ + +#include "dm9368.h" + + + +//************************************************************************** +// DEVICE DEFINITION +//************************************************************************** + +const device_type DM9368 = &device_creator; + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define LOG 0 + + +const UINT8 dm9368_device::m_segment_data[16] = +{ + 0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x67, 0x77, 0x7c, 0x39, 0x5e, 0x79, 0x71 +}; + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// dm9368_device - constructor +//------------------------------------------------- + +dm9368_device::dm9368_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, DM9368, "DM9368 7-Segment Decoder", tag, owner, clock, "dm9368", __FILE__), + device_output_interface(mconfig, *this), + m_write_rbo(*this), + m_rbi(1), + m_rbo(1) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void dm9368_device::device_start() +{ + // resolve callbacks + m_write_rbo.resolve_safe(); + + // state saving + save_item(NAME(m_rbi)); + save_item(NAME(m_rbo)); +} + + +//------------------------------------------------- +// a_w - +//------------------------------------------------- + +void dm9368_device::a_w(UINT8 data) +{ + int a = data & 0x0f; + UINT8 value = 0; + + if (!m_rbi && !a) + { + if (LOG) logerror("DM9368 '%s' Blanked Rippling Zero\n", tag()); + + // blank rippling 0 + m_rbo = 0; + } + else + { + if (LOG) logerror("DM9368 '%s' Output Data: %u = %02x\n", tag(), a, m_segment_data[a]); + + value = m_segment_data[a]; + + m_rbo = 1; + } + + set_digit_value(value); + + m_write_rbo(m_rbo); +} diff --git a/src/devices/video/dm9368.h b/src/devices/video/dm9368.h new file mode 100644 index 00000000000..35a2da3431d --- /dev/null +++ b/src/devices/video/dm9368.h @@ -0,0 +1,75 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Fairchild DM9368 7-Segment Decoder/Driver/Latch emulation + +********************************************************************** + _____ _____ + A1 1 |* \_/ | 16 Vcc + A2 2 | | 15 F + _LE 3 | | 14 G + _RBO 4 | DM9368 | 13 A + _RBI 5 | | 12 B + A3 6 | | 11 C + A0 7 | | 10 D + GND 8 |_____________| 9 E + +**********************************************************************/ + +#pragma once + +#ifndef __DM9368__ +#define __DM9368__ + +#include "emu.h" + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_DM9368_RBO_CALLBACK(_write) \ + devcb = &dm9368_device::set_rbo_wr_callback(*device, DEVCB_##_read); + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> dm9368_device + +class dm9368_device : public device_t, + public device_output_interface +{ +public: + // construction/destruction + dm9368_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + void a_w(UINT8 data); + + DECLARE_WRITE_LINE_MEMBER( rbi_w ) { m_rbi = state; } + DECLARE_READ_LINE_MEMBER( rbo_r ) { return m_rbo; } + +protected: + // device-level overrides + virtual void device_start(); + +private: + devcb_write_line m_write_rbo; + + int m_rbi; + int m_rbo; + + static const UINT8 m_segment_data[]; +}; + + +// device type definition +extern const device_type DM9368; + + + +#endif diff --git a/src/devices/video/ef9340_1.c b/src/devices/video/ef9340_1.c new file mode 100644 index 00000000000..d3dd81f5d2e --- /dev/null +++ b/src/devices/video/ef9340_1.c @@ -0,0 +1,383 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +/*************************************************************************** + + ef9340_1.h + + Thomson EF9340 + EF9341 teletext graphics chips with 1KB external + character ram. + +***************************************************************************/ + +#include "ef9340_1.h" +#include "ef9341_chargen.h" + + +// device type definition +const device_type EF9340_1 = &device_creator; + + +static const UINT8 bgr2rgb[8] = +{ + 0x00, 0x04, 0x02, 0x06, 0x01, 0x05, 0x03, 0x07 +}; + + +ef9340_1_device::ef9340_1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, EF9340_1, "EF9340+EF9341", tag, owner, clock, "ef9340_1", __FILE__) + , device_video_interface(mconfig, *this) + //, m_start_vpos(START_Y) + //, m_start_vblank(START_Y + SCREEN_HEIGHT) + //, m_screen_lines(LINES) +{ +} + + +void ef9340_1_device::device_start() +{ + // Let the screen create our temporary bitmap with the screen's dimensions + m_screen->register_screen_bitmap(m_tmp_bitmap); + + m_line_timer = timer_alloc(TIMER_LINE); + m_line_timer->adjust( m_screen->time_until_pos(0, 0), 0, m_screen->scan_period() ); + + // register our state + save_item(NAME(m_ef9341.TA)); + save_item(NAME(m_ef9341.TB)); + save_item(NAME(m_ef9341.busy)); + save_item(NAME(m_ef9340.X)); + save_item(NAME(m_ef9340.Y)); + save_item(NAME(m_ef9340.Y0)); + save_item(NAME(m_ef9340.R)); + save_item(NAME(m_ef9340.M)); + save_pointer(NAME(m_ef934x_ram_a), 1024); + save_pointer(NAME(m_ef934x_ram_b), 1024); + save_pointer(NAME(m_ef934x_ext_char_ram), 1024); +} + + +void ef9340_1_device::device_reset() +{ + memset(m_ef934x_ram_a, 0, sizeof(m_ef934x_ram_a)); + memset(m_ef934x_ram_b, 0, sizeof(m_ef934x_ram_b)); + + m_ef9340.X = 0; + m_ef9340.Y = 0; + m_ef9340.Y0 = 0; + m_ef9340.R = 0; + m_ef9340.M = 0; + m_ef9340.max_vpos = 210; + m_ef9341.TA = 0; + m_ef9341.TB = 0; + m_ef9341.busy = 0; +} + + +void ef9340_1_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch ( id ) + { + case TIMER_LINE: + ef9340_scanline(m_screen->vpos()); + break; + } +} + + +UINT16 ef9340_1_device::ef9340_get_c_addr(UINT8 x, UINT8 y) +{ + if ( ( y & 0x18 ) == 0x18 ) + { + return 0x318 | ( ( x & 0x38 ) << 2 ) | ( x & 0x07 ); + } + if ( x & 0x20 ) + { + return 0x300 | ( ( y & 0x07 ) << 5 ) | ( y & 0x18 ) | ( x & 0x07 ); + } + return y << 5 | x; +} + + +void ef9340_1_device::ef9340_inc_c() +{ + m_ef9340.X++; + if ( m_ef9340.X == 40 || m_ef9340.X == 48 || m_ef9340.X == 56 || m_ef9340.X == 64 ) + { + m_ef9340.Y = ( m_ef9340.Y + 1 ) & 0x1f; + if ( m_ef9340.Y == 24 ) + { + m_ef9340.Y = 0; + } + m_ef9340.X = 0; + } +} + + +UINT16 ef9340_1_device::external_chargen_address(UINT8 b, UINT8 slice) +{ + UINT8 cc = b & 0x7f; + + if ( slice & 8 ) + { + // 0 0 CCE4 CCE3 CCE2 CCE1 CCE0 CCE6 CCE5 ADR0 + return ( ( cc << 3 ) & 0xf8 ) | ( ( cc >> 4 ) & 0x06) | ( slice & 0x01 ); + } + // CCE6 CCE5 CCE4 CCE3 CCE2 CCE1 CCE0 ADR2 ADR1 ADR0 + return ( cc << 3 ) | ( slice & 0x07 ); +} + + +void ef9340_1_device::ef9341_write( UINT8 command, UINT8 b, UINT8 data ) +{ + logerror("ef9341 %s write, t%s, data %02X\n", command ? "command" : "data", b ? "B" : "A", data ); + + if ( command ) + { + if ( b ) + { + m_ef9341.TB = data; + m_ef9341.busy = 0x80; + switch( m_ef9341.TB & 0xE0 ) + { + case 0x00: /* Begin row */ + m_ef9340.X = 0; + m_ef9340.Y = m_ef9341.TA & 0x1F; + break; + case 0x20: /* Load Y */ + m_ef9340.Y = m_ef9341.TA & 0x1F; + break; + case 0x40: /* Load X */ + m_ef9340.X = m_ef9341.TA & 0x3F; + break; + case 0x60: /* INC C */ + ef9340_inc_c(); + break; + case 0x80: /* Load M */ + m_ef9340.M = m_ef9341.TA; + break; + case 0xA0: /* Load R */ + m_ef9340.R = m_ef9341.TA; + m_ef9340.max_vpos = ( m_ef9340.R & 0x40 ) ? 250 : 210; + break; + case 0xC0: /* Load Y0 */ + m_ef9340.Y0 = m_ef9341.TA & 0x3F; + break; + } + m_ef9341.busy = 0; + } + else + { + m_ef9341.TA = data; + } + } + else + { + if ( b ) + { + UINT16 addr = ef9340_get_c_addr( m_ef9340.X, m_ef9340.Y ) & 0x3ff; + + m_ef9341.TB = data; + m_ef9341.busy = 0x80; + switch ( m_ef9340.M & 0xE0 ) + { + case 0x00: /* Write */ + m_ef934x_ram_a[addr] = m_ef9341.TA; + m_ef934x_ram_b[addr] = m_ef9341.TB; + ef9340_inc_c(); + break; + + case 0x20: /* Read */ + m_ef9341.TA = m_ef934x_ram_a[addr]; + m_ef9341.TB = m_ef934x_ram_b[addr]; + ef9340_inc_c(); + break; + + case 0x40: /* Write without increment */ + m_ef934x_ram_a[addr] = m_ef9341.TA; + m_ef934x_ram_b[addr] = m_ef9341.TB; + break; + + case 0x60: /* Read without increment */ + m_ef9341.TA = m_ef934x_ram_a[addr]; + m_ef9341.TB = m_ef934x_ram_b[addr]; + break; + + case 0x80: /* Write slice */ + { + UINT8 a = m_ef934x_ram_a[addr]; + UINT8 b = m_ef934x_ram_b[addr]; + UINT8 slice = ( m_ef9340.M & 0x0f ) % 10; + + if ( b >= 0xa0 ) + { + m_ef934x_ext_char_ram[ ( ( a & 0x80 ) << 3 ) | external_chargen_address( b, slice ) ] = BITSWAP8(m_ef9341.TA,0,1,2,3,4,5,6,7); + } + + // Increment slice number + m_ef9340.M = ( m_ef9340.M & 0xf0) | ( ( slice + 1 ) % 10 ); + } + break; + + case 0xA0: /* Read slice */ + default: + fatalerror/*logerror*/("ef9341 unimplemented data action %02X\n", m_ef9340.M & 0xE0 ); + } + m_ef9341.busy = 0; + } + else + { + m_ef9341.TA = data; + } + } +} + + +UINT8 ef9340_1_device::ef9341_read( UINT8 command, UINT8 b ) +{ + UINT8 data = 0xFF; + + logerror("ef9341 %s read, t%s\n", command ? "command" : "data", b ? "B" : "A" ); + if ( command ) + { + if ( b ) + { + data = 0; + } + else + { + data = m_ef9341.busy; + } + } + else + { + if ( b ) + { + data = m_ef9341.TB; + } + else + { + data = m_ef9341.TA; + } + } + return data; +} + + +void ef9340_1_device::ef9340_scanline(int vpos) +{ + if ( vpos < m_ef9340.max_vpos ) + { + int y = vpos - 0; + int y_row, slice; + + if ( y < 10 ) + { + // Service row + + if ( m_ef9340.R & 0x08 ) + { + // Service row is enabled + + y_row = 31; + slice = y; + } + else + { + // Service row is disabled + + for ( int i = 0; i < 40 * 8; i++ ) + { + m_tmp_bitmap.pix16(vpos, 0 + i ) = 24; + } + return; + } + } + else + { + // Displaying regular row + y_row = (y - 10) / 10; + slice = (y - 10) % 10; + } + + for ( int x = 0; x < 40; x++ ) + { + UINT16 addr = ef9340_get_c_addr( x, y_row ); + UINT8 a = m_ef934x_ram_a[addr]; + UINT8 b = m_ef934x_ram_b[addr]; + UINT8 fg = 0; + UINT8 bg = 0; + UINT8 char_data = 0x00; + + if ( a & 0x80 ) + { + // Graphics + if ( b & 0x80 ) + { + if ( b & 0x60 ) + { + // Extension + char_data = m_ef934x_ext_char_ram[ 0x400 | external_chargen_address( b & 0x7f, slice ) ]; + fg = bgr2rgb[ a & 0x07 ]; + bg = bgr2rgb[ ( a >> 4 ) & 0x07 ]; + } + } + else + { + // Normal + char_data = ef9341_char_set[1][b & 0x7f][slice]; + fg = bgr2rgb[ a & 0x07 ]; + bg = bgr2rgb[ ( a >> 4 ) & 0x07 ]; + } + } + else + { + // Alphannumeric + if ( b & 0x80 ) + { + if ( b & 0x60 ) + { + // Extension + char_data = m_ef934x_ext_char_ram[ external_chargen_address( b & 0x7f, slice ) ]; + + if ( a & 0x40 ) + { + fg = bg; + bg = bgr2rgb[ a & 0x07 ]; + } + else + { + fg = bgr2rgb[ a & 0x07 ]; + } + } + else + { + // DEL + char_data = 0xff; + fg = bgr2rgb[ a & 0x07 ]; + } + } + else + { + // Normal + char_data = ef9341_char_set[0][b & 0x7f][slice]; + + if ( a & 0x40 ) + { + fg = bg; + bg = bgr2rgb[ a & 0x07 ]; + } + else + { + fg = bgr2rgb[ a & 0x07 ]; + } + } + } + + for ( int i = 0; i < 8; i++ ) + { + m_tmp_bitmap.pix16(vpos, 0 + x*8 + i ) = (char_data & 0x80) ? fg : bg; + char_data <<= 1; + } + } + } +} diff --git a/src/devices/video/ef9340_1.h b/src/devices/video/ef9340_1.h new file mode 100644 index 00000000000..3aa2d6539d9 --- /dev/null +++ b/src/devices/video/ef9340_1.h @@ -0,0 +1,81 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +/*************************************************************************** + + ef9340_1.h + + Thomson EF9340 + EF9341 teletext graphics chips with 1KB external + character ram. + +***************************************************************************/ + +#pragma once + +#ifndef __EF9340_1_H__ +#define __EF9340_1_H__ + +#include "emu.h" + + +#define MCFG_EF9340_1_ADD(_tag, _clock, _screen_tag) \ + MCFG_DEVICE_ADD(_tag, EF9340_1, _clock) \ + MCFG_VIDEO_SET_SCREEN(_screen_tag) + +class ef9340_1_device : public device_t, + public device_video_interface +{ +public: + // construction/destruction + ef9340_1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + inline bitmap_ind16 *get_bitmap() { return &m_tmp_bitmap; } + + void ef9341_write( UINT8 command, UINT8 b, UINT8 data ); + UINT8 ef9341_read( UINT8 command, UINT8 b ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + inline UINT16 ef9340_get_c_addr(UINT8 x, UINT8 y); + inline void ef9340_inc_c(); + + // Calculate the external chargen address for a character and slice + inline UINT16 external_chargen_address(UINT8 b, UINT8 slice); + + void ef9340_scanline(int vpos); + + /* timers */ + static const device_timer_id TIMER_LINE = 0; + + emu_timer *m_line_timer; + + bitmap_ind16 m_tmp_bitmap; + + struct + { + UINT8 TA; + UINT8 TB; + UINT8 busy; + } m_ef9341; + struct + { + UINT8 X; + UINT8 Y; + UINT8 Y0; + UINT8 R; + UINT8 M; + int max_vpos; + } m_ef9340; + UINT8 m_ef934x_ram_a[1024]; + UINT8 m_ef934x_ram_b[1024]; + UINT8 m_ef934x_ext_char_ram[2048]; /* The G7400 has 2KB of external ram hooked up. The datasheet only describes how to hookup 1KB. */ +}; + + +// device type definition +extern const device_type EF9340_1; + +#endif /* __EF9340_1_H__ */ diff --git a/src/devices/video/ef9341_chargen.h b/src/devices/video/ef9341_chargen.h new file mode 100644 index 00000000000..d33db19d18e --- /dev/null +++ b/src/devices/video/ef9341_chargen.h @@ -0,0 +1,269 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +static const UINT8 ef9341_char_set[2][128][10] = { + // Alphanumeric character set (128 characters) + { + { 0x00,0x38,0x44,0x40,0x20,0x10,0x00,0x10,0x00,0x00 }, + { 0x00,0x10,0x28,0x00,0x38,0x44,0x7c,0x44,0x00,0x00 }, + { 0x00,0x08,0x10,0x3c,0x20,0x30,0x20,0x3c,0x00,0x00 }, + { 0x00,0x08,0x14,0x10,0x38,0x10,0x24,0x3c,0x00,0x00 }, + { 0x00,0x10,0x38,0x50,0x38,0x14,0x54,0x38,0x10,0x00 }, + { 0x00,0x38,0x44,0x40,0x40,0x40,0x44,0x38,0x10,0x20 }, + { 0x00,0x28,0x28,0x7c,0x28,0x7c,0x28,0x28,0x00,0x00 }, + { 0x00,0x20,0x18,0x00,0x38,0x44,0x7c,0x44,0x00,0x00 }, + { 0x00,0x20,0x18,0x00,0x44,0x44,0x44,0x38,0x00,0x00 }, + { 0x00,0x10,0x08,0x3c,0x20,0x30,0x20,0x3c,0x00,0x00 }, + { 0x00,0x3c,0x50,0x50,0x58,0x50,0x50,0x3c,0x00,0x00 }, + { 0x00,0x08,0x14,0x3c,0x20,0x30,0x20,0x3c,0x00,0x00 }, + { 0x00,0x00,0x10,0x20,0x7f,0x20,0x10,0x00,0x00,0x00 }, + { 0x00,0x10,0x38,0x54,0x10,0x10,0x10,0x10,0x10,0x10 }, + { 0x00,0x00,0x08,0x04,0xfe,0x04,0x08,0x00,0x00,0x00 }, + { 0x10,0x10,0x10,0x10,0x10,0x10,0x54,0x38,0x10,0x00 }, + { 0x00,0x18,0x24,0x18,0x00,0x00,0x00,0x00,0x00,0x00 }, + { 0x00,0x10,0x10,0x7c,0x10,0x10,0x00,0x7c,0x00,0x00 }, + { 0x00,0x08,0x10,0x38,0x44,0x7c,0x40,0x38,0x00,0x00 }, + { 0x00,0x28,0x00,0x38,0x44,0x7c,0x40,0x38,0x00,0x00 }, + { 0x00,0x28,0x00,0x30,0x10,0x10,0x10,0x38,0x00,0x00 }, + { 0x00,0x00,0x00,0x38,0x40,0x40,0x40,0x38,0x10,0x20 }, + { 0x00,0x10,0x28,0x00,0x44,0x44,0x4c,0x34,0x00,0x00 }, + { 0x00,0x20,0x10,0x34,0x4c,0x44,0x4c,0x34,0x00,0x00 }, + { 0x00,0x00,0x10,0x00,0x7c,0x00,0x10,0x00,0x00,0x00 }, + { 0x00,0x20,0x10,0x38,0x44,0x7c,0x40,0x38,0x00,0x00 }, + { 0x00,0x00,0x00,0x3c,0x52,0x5e,0x50,0x3e,0x00,0x00 }, + { 0x00,0x10,0x28,0x38,0x44,0x7c,0x40,0x38,0x00,0x00 }, + { 0x00,0x40,0xc0,0x40,0x44,0x4c,0x14,0x3e,0x04,0x00 }, + { 0x00,0x40,0xc0,0x40,0x4c,0x52,0x04,0x08,0x1e,0x00 }, + { 0x00,0xe0,0x20,0x40,0x24,0xcc,0x14,0x3e,0x04,0x00 }, + { 0x00,0x10,0x28,0x00,0x38,0x44,0x44,0x38,0x00,0x00 }, + { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, + { 0x00,0x10,0x10,0x10,0x10,0x10,0x00,0x10,0x00,0x00 }, + { 0x00,0x28,0x28,0x28,0x00,0x00,0x00,0x00,0x00,0x00 }, + { 0x00,0x28,0x00,0x3c,0x20,0x30,0x20,0x3c,0x00,0x00 }, + { 0x00,0x10,0x28,0x34,0x4c,0x44,0x4c,0x34,0x00,0x00 }, + { 0x00,0x60,0x64,0x08,0x10,0x20,0x4c,0x0c,0x00,0x00 }, + { 0x00,0x20,0x50,0x50,0x20,0x54,0x48,0x34,0x00,0x00 }, + { 0x00,0x10,0x10,0x20,0x00,0x00,0x00,0x00,0x00,0x00 }, + { 0x00,0x08,0x10,0x20,0x20,0x20,0x10,0x08,0x00,0x00 }, + { 0x00,0x20,0x10,0x08,0x08,0x08,0x10,0x20,0x00,0x00 }, + { 0x00,0x10,0x54,0x38,0x10,0x38,0x54,0x10,0x00,0x00 }, + { 0x00,0x00,0x10,0x10,0x7c,0x10,0x10,0x00,0x00,0x00 }, + { 0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x40,0x00 }, + { 0x00,0x00,0x00,0x00,0x00,0x3c,0x00,0x00,0x00,0x00 }, + { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x00 }, + { 0x01,0x02,0x02,0x04,0x08,0x10,0x20,0x20,0x40,0x80 }, + { 0x00,0x10,0x28,0x44,0x44,0x44,0x28,0x10,0x00,0x00 }, + { 0x00,0x10,0x30,0x10,0x10,0x10,0x10,0x10,0x00,0x00 }, + { 0x00,0x38,0x44,0x04,0x18,0x20,0x40,0x7c,0x00,0x00 }, + { 0x00,0x7c,0x04,0x08,0x18,0x04,0x44,0x38,0x00,0x00 }, + { 0x00,0x08,0x18,0x28,0x48,0x7c,0x08,0x08,0x00,0x00 }, + { 0x00,0x7c,0x40,0x78,0x04,0x04,0x44,0x38,0x00,0x00 }, + { 0x00,0x18,0x20,0x40,0x78,0x44,0x44,0x38,0x00,0x00 }, + { 0x00,0x7c,0x04,0x08,0x10,0x20,0x20,0x20,0x00,0x00 }, + { 0x00,0x38,0x44,0x44,0x38,0x44,0x44,0x38,0x00,0x00 }, + { 0x00,0x38,0x44,0x44,0x3c,0x04,0x04,0x38,0x00,0x00 }, + { 0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x20,0x00,0x00 }, + { 0x00,0x00,0x00,0x20,0x00,0x00,0x20,0x20,0x40,0x00 }, + { 0x00,0x04,0x08,0x10,0x20,0x10,0x08,0x04,0x00,0x00 }, + { 0x00,0x00,0x00,0x7c,0x00,0x7c,0x00,0x00,0x00,0x00 }, + { 0x00,0x40,0x20,0x10,0x08,0x10,0x20,0x40,0x00,0x00 }, + { 0x00,0x38,0x44,0x04,0x08,0x10,0x00,0x10,0x00,0x00 }, + { 0x00,0x38,0x44,0x5c,0x54,0x5c,0x40,0x38,0x00,0x00 }, + { 0x00,0x38,0x44,0x44,0x44,0x7c,0x44,0x44,0x00,0x00 }, + { 0x00,0x78,0x44,0x44,0x78,0x44,0x44,0x78,0x00,0x00 }, + { 0x00,0x38,0x44,0x40,0x40,0x40,0x44,0x38,0x00,0x00 }, + { 0x00,0x78,0x44,0x44,0x44,0x44,0x44,0x78,0x00,0x00 }, + { 0x00,0x7c,0x40,0x40,0x70,0x40,0x40,0x7c,0x00,0x00 }, + { 0x00,0x7c,0x40,0x40,0x70,0x40,0x40,0x40,0x00,0x00 }, + { 0x00,0x38,0x44,0x40,0x40,0x4c,0x44,0x3c,0x00,0x00 }, + { 0x00,0x44,0x44,0x44,0x7c,0x44,0x44,0x44,0x00,0x00 }, + { 0x00,0x38,0x10,0x10,0x10,0x10,0x10,0x38,0x00,0x00 }, + { 0x00,0x1c,0x08,0x08,0x08,0x08,0x48,0x30,0x00,0x00 }, + { 0x00,0x44,0x48,0x50,0x60,0x50,0x48,0x44,0x00,0x00 }, + { 0x00,0x40,0x40,0x40,0x40,0x40,0x40,0x7c,0x00,0x00 }, + { 0x00,0x44,0x6c,0x54,0x44,0x44,0x44,0x44,0x00,0x00 }, + { 0x00,0x44,0x44,0x64,0x54,0x4c,0x44,0x44,0x00,0x00 }, + { 0x00,0x38,0x44,0x44,0x44,0x44,0x44,0x38,0x00,0x00 }, + { 0x00,0x78,0x44,0x44,0x78,0x40,0x40,0x40,0x00,0x00 }, + { 0x00,0x38,0x44,0x44,0x44,0x54,0x48,0x34,0x00,0x00 }, + { 0x00,0x78,0x44,0x44,0x78,0x50,0x48,0x44,0x00,0x00 }, + { 0x00,0x38,0x44,0x40,0x38,0x04,0x44,0x38,0x00,0x00 }, + { 0x00,0x7c,0x10,0x10,0x10,0x10,0x10,0x10,0x00,0x00 }, + { 0x00,0x44,0x44,0x44,0x44,0x44,0x44,0x38,0x00,0x00 }, + { 0x00,0x44,0x44,0x44,0x28,0x28,0x10,0x10,0x00,0x00 }, + { 0x00,0x44,0x44,0x44,0x54,0x54,0x54,0x28,0x00,0x00 }, + { 0x00,0x44,0x44,0x28,0x10,0x28,0x44,0x44,0x00,0x00 }, + { 0x00,0x44,0x44,0x28,0x10,0x10,0x10,0x10,0x00,0x00 }, + { 0x00,0x7c,0x04,0x08,0x10,0x20,0x40,0x7c,0x00,0x00 }, + { 0x00,0x1c,0x10,0x10,0x10,0x10,0x10,0x1c,0x00,0x00 }, + { 0x80,0x40,0x40,0x20,0x10,0x08,0x04,0x04,0x02,0x01 }, + { 0x00,0x38,0x08,0x08,0x08,0x08,0x08,0x38,0x00,0x00 }, + { 0x00,0x10,0x28,0x00,0x30,0x10,0x10,0x38,0x00,0x00 }, + { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff }, + { 0x00,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0x00,0x00 }, + { 0x00,0x00,0x00,0x34,0x4c,0x44,0x4c,0x34,0x00,0x00 }, + { 0x00,0x40,0x40,0x78,0x44,0x44,0x44,0x78,0x00,0x00 }, + { 0x00,0x00,0x00,0x38,0x40,0x40,0x40,0x38,0x00,0x00 }, + { 0x00,0x04,0x04,0x3c,0x44,0x44,0x44,0x3c,0x00,0x00 }, + { 0x00,0x00,0x00,0x38,0x44,0x7c,0x40,0x38,0x00,0x00 }, + { 0x00,0x18,0x24,0x20,0x70,0x20,0x20,0x20,0x00,0x00 }, + { 0x00,0x00,0x00,0x3c,0x44,0x44,0x3c,0x04,0x24,0x18 }, + { 0x00,0x40,0x40,0x58,0x64,0x44,0x44,0x44,0x00,0x00 }, + { 0x00,0x10,0x00,0x30,0x10,0x10,0x10,0x38,0x00,0x00 }, + { 0x00,0x08,0x00,0x18,0x08,0x08,0x08,0x08,0x48,0x30 }, + { 0x00,0x20,0x20,0x24,0x28,0x30,0x28,0x24,0x00,0x00 }, + { 0x00,0x30,0x10,0x10,0x10,0x10,0x10,0x38,0x00,0x00 }, + { 0x00,0x00,0x00,0x68,0x54,0x54,0x54,0x54,0x00,0x00 }, + { 0x00,0x00,0x00,0x58,0x64,0x44,0x44,0x44,0x00,0x00 }, + { 0x00,0x00,0x00,0x38,0x44,0x44,0x44,0x38,0x00,0x00 }, + { 0x00,0x00,0x00,0x78,0x44,0x44,0x44,0x78,0x40,0x40 }, + { 0x00,0x00,0x00,0x3c,0x44,0x44,0x44,0x3c,0x04,0x04 }, + { 0x00,0x00,0x00,0x58,0x64,0x40,0x40,0x40,0x00,0x00 }, + { 0x00,0x00,0x00,0x38,0x40,0x38,0x04,0x78,0x00,0x00 }, + { 0x00,0x20,0x20,0x38,0x20,0x20,0x20,0x18,0x00,0x00 }, + { 0x00,0x00,0x00,0x44,0x44,0x44,0x4c,0x34,0x00,0x00 }, + { 0x00,0x00,0x00,0x44,0x44,0x28,0x28,0x10,0x00,0x00 }, + { 0x00,0x00,0x00,0x44,0x44,0x54,0x54,0x28,0x00,0x00 }, + { 0x00,0x00,0x00,0x44,0x28,0x10,0x28,0x44,0x00,0x00 }, + { 0x00,0x00,0x00,0x44,0x44,0x4c,0x34,0x04,0x44,0x38 }, + { 0x00,0x00,0x00,0x7c,0x08,0x10,0x20,0x7c,0x00,0x00 }, + { 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80 }, + { 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10 }, + { 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01 }, + { 0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, + { 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff } + }, + + { + // Separated semi-graphic character set (64 characters) + { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, + { 0x70,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, + { 0x07,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, + { 0x77,0x77,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, + { 0x00,0x00,0x00,0x70,0x70,0x70,0x00,0x00,0x00,0x00 }, + { 0x70,0x70,0x00,0x70,0x70,0x70,0x00,0x00,0x00,0x00 }, + { 0x07,0x07,0x00,0x70,0x70,0x70,0x00,0x00,0x00,0x00 }, + { 0x77,0x77,0x00,0x70,0x70,0x70,0x00,0x00,0x00,0x00 }, + { 0x00,0x00,0x00,0x07,0x07,0x07,0x00,0x00,0x00,0x00 }, + { 0x70,0x70,0x00,0x07,0x07,0x07,0x00,0x00,0x00,0x00 }, + { 0x07,0x07,0x00,0x07,0x07,0x07,0x00,0x00,0x00,0x00 }, + { 0x77,0x77,0x00,0x07,0x07,0x07,0x00,0x00,0x00,0x00 }, + { 0x00,0x00,0x00,0x77,0x77,0x77,0x00,0x00,0x00,0x00 }, + { 0x70,0x70,0x00,0x77,0x77,0x77,0x00,0x00,0x00,0x00 }, + { 0x07,0x07,0x00,0x77,0x77,0x77,0x00,0x00,0x00,0x00 }, + { 0x77,0x77,0x00,0x77,0x77,0x77,0x00,0x00,0x00,0x00 }, + { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x70,0x70,0x00 }, + { 0x70,0x70,0x00,0x00,0x00,0x00,0x00,0x70,0x70,0x00 }, + { 0x07,0x07,0x00,0x00,0x00,0x00,0x00,0x70,0x70,0x00 }, + { 0x77,0x77,0x00,0x00,0x00,0x00,0x00,0x70,0x70,0x00 }, + { 0x00,0x00,0x00,0x70,0x70,0x70,0x00,0x70,0x70,0x00 }, + { 0x70,0x70,0x00,0x70,0x70,0x70,0x00,0x70,0x70,0x00 }, + { 0x07,0x07,0x00,0x70,0x70,0x70,0x00,0x70,0x70,0x00 }, + { 0x77,0x77,0x00,0x70,0x70,0x70,0x00,0x70,0x70,0x00 }, + { 0x00,0x00,0x00,0x07,0x07,0x07,0x00,0x70,0x70,0x00 }, + { 0x70,0x70,0x00,0x07,0x07,0x07,0x00,0x70,0x70,0x00 }, + { 0x07,0x07,0x00,0x07,0x07,0x07,0x00,0x70,0x70,0x00 }, + { 0x77,0x77,0x00,0x07,0x07,0x07,0x00,0x70,0x70,0x00 }, + { 0x00,0x00,0x00,0x77,0x77,0x77,0x00,0x70,0x70,0x00 }, + { 0x70,0x70,0x00,0x77,0x77,0x77,0x00,0x70,0x70,0x00 }, + { 0x07,0x07,0x00,0x77,0x77,0x77,0x00,0x70,0x70,0x00 }, + { 0x77,0x77,0x00,0x77,0x77,0x77,0x00,0x70,0x70,0x00 }, + { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x07,0x00 }, + { 0x70,0x70,0x00,0x00,0x00,0x00,0x00,0x07,0x07,0x00 }, + { 0x07,0x07,0x00,0x00,0x00,0x00,0x00,0x07,0x07,0x00 }, + { 0x77,0x77,0x00,0x00,0x00,0x00,0x00,0x07,0x07,0x00 }, + { 0x00,0x00,0x00,0x70,0x70,0x70,0x00,0x07,0x07,0x00 }, + { 0x70,0x70,0x00,0x70,0x70,0x70,0x00,0x07,0x07,0x00 }, + { 0x07,0x07,0x00,0x70,0x70,0x70,0x00,0x07,0x07,0x00 }, + { 0x77,0x77,0x00,0x70,0x70,0x70,0x00,0x07,0x07,0x00 }, + { 0x00,0x00,0x00,0x07,0x07,0x07,0x00,0x07,0x07,0x00 }, + { 0x70,0x70,0x00,0x07,0x07,0x07,0x00,0x07,0x07,0x00 }, + { 0x07,0x07,0x00,0x07,0x07,0x07,0x00,0x07,0x07,0x00 }, + { 0x77,0x77,0x00,0x07,0x07,0x07,0x00,0x07,0x07,0x00 }, + { 0x00,0x00,0x00,0x77,0x77,0x77,0x00,0x07,0x07,0x00 }, + { 0x70,0x70,0x00,0x77,0x77,0x77,0x00,0x07,0x07,0x00 }, + { 0x07,0x07,0x00,0x77,0x77,0x77,0x00,0x07,0x07,0x00 }, + { 0x77,0x77,0x00,0x77,0x77,0x77,0x00,0x07,0x07,0x00 }, + { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x77,0x77,0x00 }, + { 0x70,0x70,0x00,0x00,0x00,0x00,0x00,0x77,0x77,0x00 }, + { 0x07,0x07,0x00,0x00,0x00,0x00,0x00,0x77,0x77,0x00 }, + { 0x77,0x77,0x00,0x00,0x00,0x00,0x00,0x77,0x77,0x00 }, + { 0x00,0x00,0x00,0x70,0x70,0x70,0x00,0x77,0x77,0x00 }, + { 0x70,0x70,0x00,0x70,0x70,0x70,0x00,0x77,0x77,0x00 }, + { 0x07,0x07,0x00,0x70,0x70,0x70,0x00,0x77,0x77,0x00 }, + { 0x77,0x77,0x00,0x70,0x70,0x70,0x00,0x77,0x77,0x00 }, + { 0x00,0x00,0x00,0x07,0x07,0x07,0x00,0x77,0x77,0x00 }, + { 0x70,0x70,0x00,0x07,0x07,0x07,0x00,0x77,0x77,0x00 }, + { 0x07,0x07,0x00,0x07,0x07,0x07,0x00,0x77,0x77,0x00 }, + { 0x77,0x77,0x00,0x07,0x07,0x07,0x00,0x77,0x77,0x00 }, + { 0x00,0x00,0x00,0x77,0x77,0x77,0x00,0x77,0x77,0x00 }, + { 0x70,0x70,0x00,0x77,0x77,0x77,0x00,0x77,0x77,0x00 }, + { 0x07,0x07,0x00,0x77,0x77,0x77,0x00,0x77,0x77,0x00 }, + { 0x77,0x77,0x00,0x77,0x77,0x77,0x00,0x77,0x77,0x00 }, + + // Mosaic semi-graphic character set (64 characters) + { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, + { 0xf0,0xf0,0xf0,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, + { 0x0f,0x0f,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, + { 0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, + { 0x00,0x00,0x00,0xf0,0xf0,0xf0,0xf0,0x00,0x00,0x00 }, + { 0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0x00,0x00,0x00 }, + { 0x0f,0x0f,0x0f,0xf0,0xf0,0xf0,0xf0,0x00,0x00,0x00 }, + { 0xff,0xff,0xff,0xf0,0xf0,0xf0,0xf0,0x00,0x00,0x00 }, + { 0x00,0x00,0x00,0x0f,0x0f,0x0f,0x0f,0x00,0x00,0x00 }, + { 0xf0,0xf0,0xf0,0x0f,0x0f,0x0f,0x0f,0x00,0x00,0x00 }, + { 0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x00,0x00,0x00 }, + { 0xff,0xff,0xff,0x0f,0x0f,0x0f,0x0f,0x00,0x00,0x00 }, + { 0x00,0x00,0x00,0xff,0xff,0xff,0xff,0x00,0x00,0x00 }, + { 0xf0,0xf0,0xf0,0xff,0xff,0xff,0xff,0x00,0x00,0x00 }, + { 0x0f,0x0f,0x0f,0xff,0xff,0xff,0xff,0x00,0x00,0x00 }, + { 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00 }, + { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf0,0xf0,0xf0 }, + { 0xf0,0xf0,0xf0,0x00,0x00,0x00,0x00,0xf0,0xf0,0xf0 }, + { 0x0f,0x0f,0x0f,0x00,0x00,0x00,0x00,0xf0,0xf0,0xf0 }, + { 0xff,0xff,0xff,0x00,0x00,0x00,0x00,0xf0,0xf0,0xf0 }, + { 0x00,0x00,0x00,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0 }, + { 0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0 }, + { 0x0f,0x0f,0x0f,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0 }, + { 0xff,0xff,0xff,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0 }, + { 0x00,0x00,0x00,0x0f,0x0f,0x0f,0x0f,0xf0,0xf0,0xf0 }, + { 0xf0,0xf0,0xf0,0x0f,0x0f,0x0f,0x0f,0xf0,0xf0,0xf0 }, + { 0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0xf0,0xf0,0xf0 }, + { 0xff,0xff,0xff,0x0f,0x0f,0x0f,0x0f,0xf0,0xf0,0xf0 }, + { 0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xf0,0xf0,0xf0 }, + { 0xf0,0xf0,0xf0,0xff,0xff,0xff,0xff,0xf0,0xf0,0xf0 }, + { 0x0f,0x0f,0x0f,0xff,0xff,0xff,0xff,0xf0,0xf0,0xf0 }, + { 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0xf0,0xf0 }, + { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0x0f,0x0f }, + { 0xf0,0xf0,0xf0,0x00,0x00,0x00,0x00,0x0f,0x0f,0x0f }, + { 0x0f,0x0f,0x0f,0x00,0x00,0x00,0x00,0x0f,0x0f,0x0f }, + { 0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x0f,0x0f,0x0f }, + { 0x00,0x00,0x00,0xf0,0xf0,0xf0,0xf0,0x0f,0x0f,0x0f }, + { 0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0x0f,0x0f,0x0f }, + { 0x0f,0x0f,0x0f,0xf0,0xf0,0xf0,0xf0,0x0f,0x0f,0x0f }, + { 0xff,0xff,0xff,0xf0,0xf0,0xf0,0xf0,0x0f,0x0f,0x0f }, + { 0x00,0x00,0x00,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f }, + { 0xf0,0xf0,0xf0,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f }, + { 0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f }, + { 0xff,0xff,0xff,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f }, + { 0x00,0x00,0x00,0xff,0xff,0xff,0xff,0x0f,0x0f,0x0f }, + { 0xf0,0xf0,0xf0,0xff,0xff,0xff,0xff,0x0f,0x0f,0x0f }, + { 0x0f,0x0f,0x0f,0xff,0xff,0xff,0xff,0x0f,0x0f,0x0f }, + { 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0x0f,0x0f }, + { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xff }, + { 0xf0,0xf0,0xf0,0x00,0x00,0x00,0x00,0xff,0xff,0xff }, + { 0x0f,0x0f,0x0f,0x00,0x00,0x00,0x00,0xff,0xff,0xff }, + { 0xff,0xff,0xff,0x00,0x00,0x00,0x00,0xff,0xff,0xff }, + { 0x00,0x00,0x00,0xf0,0xf0,0xf0,0xf0,0xff,0xff,0xff }, + { 0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xff,0xff,0xff }, + { 0x0f,0x0f,0x0f,0xf0,0xf0,0xf0,0xf0,0xff,0xff,0xff }, + { 0xff,0xff,0xff,0xf0,0xf0,0xf0,0xf0,0xff,0xff,0xff }, + { 0x00,0x00,0x00,0x0f,0x0f,0x0f,0x0f,0xff,0xff,0xff }, + { 0xf0,0xf0,0xf0,0x0f,0x0f,0x0f,0x0f,0xff,0xff,0xff }, + { 0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0xff,0xff,0xff }, + { 0xff,0xff,0xff,0x0f,0x0f,0x0f,0x0f,0xff,0xff,0xff }, + { 0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff }, + { 0xf0,0xf0,0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0xff }, + { 0x0f,0x0f,0x0f,0xff,0xff,0xff,0xff,0xff,0xff,0xff }, + { 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff } + } +}; diff --git a/src/devices/video/ef9345.c b/src/devices/video/ef9345.c new file mode 100644 index 00000000000..ca8062bbb95 --- /dev/null +++ b/src/devices/video/ef9345.c @@ -0,0 +1,1021 @@ +// license:GPL-2.0+ +// copyright-holders:Daniel Coulom,Sandro Ronco +/********************************************************************* + + ef9345.c + + Thomson EF9345 video controller emulator code + + This code is based on Daniel Coulom's implementation in DCVG5k + and DCAlice released by Daniel Coulom under GPL license + +*********************************************************************/ + +#include "emu.h" +#include "ef9345.h" + +#define MODE24x40 0 +#define MODEVAR40 1 +#define MODE8x80 2 +#define MODE12x80 3 +#define MODE16x40 4 + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +// devices +const device_type EF9345 = &device_creator; + +// default address map +static ADDRESS_MAP_START( ef9345, AS_0, 8, ef9345_device ) + AM_RANGE(0x0000, 0x3fff) AM_RAM +ADDRESS_MAP_END + +//------------------------------------------------- +// memory_space_config - return a description of +// any address spaces owned by this device +//------------------------------------------------- + +const address_space_config *ef9345_device::memory_space_config(address_spacenum spacenum) const +{ + return (spacenum == AS_0) ? &m_space_config : NULL; +} + +//************************************************************************** +// INLINE HELPERS +//************************************************************************** + +// calculate the internal RAM offset +inline UINT16 ef9345_device::indexram(UINT8 r) +{ + UINT8 x = m_registers[r]; + UINT8 y = m_registers[r - 1]; + if (y < 8) + y &= 1; + return ((x&0x3f) | ((x & 0x40) << 6) | ((x & 0x80) << 4) | ((y & 0x1f) << 6) | ((y & 0x20) << 8)); +} + +// calculate the internal ROM offset +inline UINT16 ef9345_device::indexrom(UINT8 r) +{ + UINT8 x = m_registers[r]; + UINT8 y = m_registers[r - 1]; + if (y < 8) + y &= 1; + return((x&0x3f)|((x&0x40)<<6)|((x&0x80)<<4)|((y&0x1f)<<6)); +} + +// increment x +inline void ef9345_device::inc_x(UINT8 r) +{ + UINT8 i = (m_registers[r] & 0x3f) + 1; + if (i > 39) + { + i -= 40; + m_state |= 0x40; + } + m_registers[r] = (m_registers[r] & 0xc0) | i; +} + +// increment y +inline void ef9345_device::inc_y(UINT8 r) +{ + UINT8 i = (m_registers[r] & 0x1f) + 1; + if (i > 31) + i -= 24; + m_registers[r] = (m_registers[r] & 0xe0) | i; +} + + +//************************************************************************** +// live device +//************************************************************************** + +//------------------------------------------------- +// ef9345_device - constructor +//------------------------------------------------- + +ef9345_device::ef9345_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, EF9345, "EF9345", tag, owner, clock, "ef9345", __FILE__), + device_memory_interface(mconfig, *this), + device_video_interface(mconfig, *this), + m_space_config("videoram", ENDIANNESS_LITTLE, 8, 16, 0, NULL, *ADDRESS_MAP_NAME(ef9345)), + m_palette(*this) +{ +} + +//------------------------------------------------- +// static_set_palette_tag: Set the tag of the +// palette device +//------------------------------------------------- + +void ef9345_device::static_set_palette_tag(device_t &device, const char *tag) +{ + downcast(device).m_palette.set_tag(tag); +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void ef9345_device::device_start() +{ + m_busy_timer = timer_alloc(BUSY_TIMER); + m_blink_timer = timer_alloc(BLINKING_TIMER); + + m_videoram = &space(0); + m_charset = region(); + + m_screen_out.allocate(496, m_screen->height()); + + m_blink_timer->adjust(attotime::from_msec(500), 0, attotime::from_msec(500)); + + init_accented_chars(); + + save_item(NAME(m_border)); + save_item(NAME(m_registers)); + save_item(NAME(m_last_dial)); + save_item(NAME(m_ram_base)); + save_item(NAME(m_bf)); + save_item(NAME(m_char_mode)); + save_item(NAME(m_state)); + save_item(NAME(m_tgs)); + save_item(NAME(m_mat)); + save_item(NAME(m_pat)); + save_item(NAME(m_dor)); + save_item(NAME(m_ror)); + save_item(NAME(m_block)); + save_item(NAME(m_blink)); + save_item(NAME(m_latchc0)); + save_item(NAME(m_latchm)); + save_item(NAME(m_latchi)); + save_item(NAME(m_latchu)); + + save_item(NAME(m_screen_out)); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- +void ef9345_device::device_reset() +{ + m_tgs = m_mat = m_pat = m_dor = m_ror = 0; + m_state = 0; + m_bf = 0; + m_block = 0; + m_blink = 0; + m_latchc0 = 0; + m_latchm = 0; + m_latchi = 0; + m_latchu = 0; + m_char_mode = 0; + + memset(m_last_dial, 0, sizeof(m_last_dial)); + memset(m_registers, 0, sizeof(m_registers)); + memset(m_border, 0, sizeof(m_border)); + memset(m_border, 0, sizeof(m_ram_base)); + + m_screen_out.fill(0); + + set_video_mode(); +} + +//------------------------------------------------- +// device_timer - handler timer events +//------------------------------------------------- +void ef9345_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch(id) + { + case BUSY_TIMER: + m_bf = 0; + break; + + case BLINKING_TIMER: + m_blink = !m_blink; + break; + } +} + + +// set busy flag and timer to clear it +void ef9345_device::set_busy_flag(int period) +{ + m_bf = 1; + m_busy_timer->adjust(attotime::from_usec(period)); +} + +// draw a char in 40 char line mode +void ef9345_device::draw_char_40(UINT8 *c, UINT16 x, UINT16 y) +{ + //verify size limit + if (y * 10 >= m_screen->height() || x * 8 >= m_screen->width()) + return; + + const rgb_t *palette = m_palette->palette()->entry_list_raw(); + for(int i = 0; i < 10; i++) + for(int j = 0; j < 8; j++) + m_screen_out.pix32(y * 10 + i, x * 8 + j) = palette[c[8 * i + j] & 0x07]; +} + +// draw a char in 80 char line mode +void ef9345_device::draw_char_80(UINT8 *c, UINT16 x, UINT16 y) +{ + // verify size limit + if (y * 10 >= m_screen->height() || x * 6 >= m_screen->width()) + return; + + const rgb_t *palette = m_palette->palette()->entry_list_raw(); + for(int i = 0; i < 10; i++) + for(int j = 0; j < 6; j++) + m_screen_out.pix32(y * 10 + i, x * 6 + j) = palette[c[6 * i + j] & 0x07]; +} + + +// set then ef9345 mode +void ef9345_device::set_video_mode(void) +{ + m_char_mode = ((m_pat & 0x80) >> 5) | ((m_tgs & 0xc0) >> 6); + UINT16 new_width = (m_char_mode == MODE12x80 || m_char_mode == MODE8x80) ? 492 : 336; + + if (m_screen->width() != new_width) + { + rectangle visarea = m_screen->visible_area(); + visarea.max_x = new_width - 1; + + m_screen->configure(new_width, m_screen->height(), visarea, m_screen->frame_period().attoseconds()); + } + + //border color + memset(m_border, m_mat & 0x07, sizeof(m_border)); + + //set the base for the m_videoram charset + m_ram_base[0] = ((m_dor & 0x07) << 11); + m_ram_base[1] = m_ram_base[0]; + m_ram_base[2] = ((m_dor & 0x30) << 8); + m_ram_base[3] = m_ram_base[2] + 0x0800; + + //address of the current memory block + m_block = 0x0800 * ((((m_ror & 0xf0) >> 4) | ((m_ror & 0x40) >> 5) | ((m_ror & 0x20) >> 3)) & 0x0c); +} + +// initialize the ef9345 accented chars +void ef9345_device::init_accented_chars(void) +{ + UINT16 i, j; + for(j = 0; j < 0x10; j++) + for(i = 0; i < 0x200; i++) + m_acc_char[(j << 9) + i] = m_charset->u8(0x0600 + i); + + for(j = 0; j < 0x200; j += 0x40) + for(i = 0; i < 4; i++) + { + m_acc_char[0x0200 + j + i + 4] |= 0x1c; //tilde + m_acc_char[0x0400 + j + i + 4] |= 0x10; //acute + m_acc_char[0x0400 + j + i + 8] |= 0x08; //acute + m_acc_char[0x0600 + j + i + 4] |= 0x04; //grave + m_acc_char[0x0600 + j + i + 8] |= 0x08; //grave + + m_acc_char[0x0a00 + j + i + 4] |= 0x1c; //tilde + m_acc_char[0x0c00 + j + i + 4] |= 0x10; //acute + m_acc_char[0x0c00 + j + i + 8] |= 0x08; //acute + m_acc_char[0x0e00 + j + i + 4] |= 0x04; //grave + m_acc_char[0x0e00 + j + i + 8] |= 0x08; //grave + + m_acc_char[0x1200 + j + i + 4] |= 0x08; //point + m_acc_char[0x1400 + j + i + 4] |= 0x14; //trema + m_acc_char[0x1600 + j + i + 32] |= 0x08; //cedilla + m_acc_char[0x1600 + j + i + 36] |= 0x04; //cedilla + + m_acc_char[0x1a00 + j + i + 4] |= 0x08; //point + m_acc_char[0x1c00 + j + i + 4] |= 0x14; //trema + m_acc_char[0x1e00 + j + i + 32] |= 0x08; //cedilla + m_acc_char[0x1e00 + j + i + 36] |= 0x04; //cedilla + } +} + +// read a char in charset or in m_videoram +UINT8 ef9345_device::read_char(UINT8 index, UINT16 addr) +{ + if (index < 0x04) + return m_charset->u8(0x0800*index + addr); + else if (index < 0x08) + return m_acc_char[0x0800*(index&3) + addr]; + else if (index < 0x0c) + return m_videoram->read_byte(m_ram_base[index-8] + addr); + else + return m_videoram->read_byte(addr); +} + +// calculate the dial position of the char +UINT8 ef9345_device::get_dial(UINT8 x, UINT8 attrib) +{ + if (x > 0 && m_last_dial[x-1] == 1) //top right + m_last_dial[x] = 2; + else if (x > 0 && m_last_dial[x-1] == 5) //half right + m_last_dial[x] = 10; + else if (m_last_dial[x] == 1) //bottom left + m_last_dial[x] = 4; + else if (m_last_dial[x] == 2) //bottom right + m_last_dial[x] = 8; + else if (m_last_dial[x] == 3) //lower half + m_last_dial[x] = 12; + else if (attrib == 1) //Left half + m_last_dial[x] = 5; + else if (attrib == 2) //half high + m_last_dial[x] = 3; + else if (attrib == 3) //top left + m_last_dial[x] = 1; + else //none + m_last_dial[x] = 0; + + return m_last_dial[x]; +} + +// zoom the char +void ef9345_device::zoom(UINT8 *pix, UINT16 n) +{ + UINT8 i, j; + if ((n & 0x0a) == 0) + for(i = 0; i < 80; i += 8) // 1, 4, 5 + for(j = 7; j > 0; j--) + pix[i + j] = pix[i + j / 2]; + + if ((n & 0x05) == 0) + for(i = 0; i < 80; i += 8) // 2, 8, 10 + for(j =0 ; j < 7; j++) + pix[i + j] = pix[i + 4 + j / 2]; + + if ((n & 0x0c) == 0) + for(i = 0; i < 8; i++) // 1, 2, 3 + for(j = 9; j > 0; j--) + pix[i + 8 * j] = pix[i + 8 * (j / 2)]; + + if ((n & 0x03) == 0) + for(i = 0; i < 8; i++) // 4, 8, 12 + for(j = 0; j < 9; j++) + pix[i + 8 * j] = pix[i + 40 + 8 * (j / 2)]; +} + + +// calculate the address of the char x,y +UINT16 ef9345_device::indexblock(UINT16 x, UINT16 y) +{ + UINT16 i = x, j; + j = (y == 0) ? ((m_tgs & 0x20) >> 5) : ((m_ror & 0x1f) + y - 1); + + //right side of a double width character + if ((m_tgs & 0x80) == 0 && x > 0) + { + if (m_last_dial[x - 1] == 1) i--; + if (m_last_dial[x - 1] == 4) i--; + if (m_last_dial[x - 1] == 5) i--; + } + + return 0x40 * j + i; +} + +// draw bichrome character (40 columns) +void ef9345_device::bichrome40(UINT8 type, UINT16 address, UINT8 dial, UINT16 iblock, UINT16 x, UINT16 y, UINT8 c0, UINT8 c1, UINT8 insert, UINT8 flash, UINT8 hided, UINT8 negative, UINT8 underline) +{ + UINT16 i; + UINT8 pix[80]; + + if (flash && m_pat & 0x40 && m_blink) + c1 = c0; //flash + if (hided && m_pat & 0x08) + c1 = c0; //hided + if (negative) //negative + { + i = c1; + c1 = c0; + c0 = i; + } + + if ((m_pat & 0x30) == 0x30) + insert = 0; //active area mark + if (insert == 0) + c1 += 8; //foreground color + if ((m_pat & 0x30) == 0x00) + insert = 1; //insert mode + if (insert == 0) + c0 += 8; //background color + + //draw the cursor + i = (m_registers[6] & 0x1f); + if (i < 8) + i &= 1; + + if (iblock == 0x40 * i + (m_registers[7] & 0x3f)) //cursor position + { + switch(m_mat & 0x70) + { + case 0x40: //00 = fixed complemented + c0 = (23 - c0) & 15; + c1 = (23 - c1) & 15; + break; + case 0x50: //01 = fixed underlined + underline = 1; + break; + case 0x60: //10 = flash complemented + if (m_blink) + { + c0 = (23 - c0) & 15; + c1 = (23 - c1) & 15; + } + break; + case 0x70: //11 = flash underlined + if (m_blink) + underline = 1; + break; + } + } + + // generate the pixel table + for(i = 0; i < 40; i+=4) + { + UINT8 ch = read_char(type, address + i); + + for (UINT8 b=0; b<8; b++) + pix[i*2 + b] = (ch & (1< 0) + zoom(pix, dial); + + //doubles the height of the char + if (m_mat & 0x80) + zoom(pix, (y & 0x01) ? 0x0c : 0x03); + + draw_char_40(pix, x + 1 , y + 1); +} + +// draw quadrichrome character (40 columns) +void ef9345_device::quadrichrome40(UINT8 c, UINT8 b, UINT8 a, UINT16 x, UINT16 y) +{ + //C0-6= character code + //B0= insert not yet implemented !!! + //B1= low resolution + //B2= subset index (low resolution only) + //B3-5 = set number + //A0-6 = 4 color palette + + UINT8 i, j, n, col[8], pix[80]; + UINT8 lowresolution = (b & 0x02) >> 1, ramx, ramy, ramblock; + UINT16 ramindex; + + //quadrichrome don't suppor double size + m_last_dial[x] = 0; + + //initialize the color table + for(j = 1, n = 0, i = 0; i < 8; i++) + { + col[n++] = (a & j) ? i : 7; + j <<= 1; + } + + //find block number in ram + ramblock = 0; + if (b & 0x20) ramblock |= 4; //B5 + if (b & 0x08) ramblock |= 2; //B3 + if (b & 0x10) ramblock |= 1; //B4 + + //find character address in ram + ramx = c & 0x03; + ramy =(c & 0x7f) >> 2; + ramindex = 0x0800 * ramblock + 0x40 * ramy + ramx; + if (lowresolution) ramindex += 5 * (b & 0x04); + + //fill pixel table + for(i = 0, j = 0; i < 10; i++) + { + UINT8 ch = read_char(0x0c, ramindex + 4 * (i >> lowresolution)); + pix[j] = pix[j + 1] = col[(ch & 0x03) >> 0]; j += 2; + pix[j] = pix[j + 1] = col[(ch & 0x0c) >> 2]; j += 2; + pix[j] = pix[j + 1] = col[(ch & 0x30) >> 4]; j += 2; + pix[j] = pix[j + 1] = col[(ch & 0xc0) >> 6]; j += 2; + } + + draw_char_40(pix, x + 1, y + 1); +} + +// draw bichrome character (80 columns) +void ef9345_device::bichrome80(UINT8 c, UINT8 a, UINT16 x, UINT16 y) +{ + UINT8 c0, c1, pix[60]; + UINT16 i, j, d; + + c1 = (a & 1) ? (m_dor >> 4) & 7 : m_dor & 7; //foreground color = DOR + c0 = m_mat & 7; //background color = MAT + + switch(c & 0x80) + { + case 0: //alphanumeric G0 set + //A0: D = color set + //A1: U = underline + //A2: F = flash + //A3: N = negative + //C0-6: character code + + if ((a & 4) && (m_pat & 0x40) && (m_blink)) + c1 = c0; //flash + if (a & 8) //negative + { + i = c1; + c1 = c0; + c0 = i; + } + + d = ((c & 0x7f) >> 2) * 0x40 + (c & 0x03); //char position + + for(i=0, j=0; i < 10; i++) + { + UINT8 ch = read_char(0, d + 4 * i); + for (UINT8 b=0; b<6; b++) + pix[j++] = (ch & (1< 1) ? indexblock(x, y / 2) : indexblock(x, y); + a = m_videoram->read_byte(m_block + iblock); + b = m_videoram->read_byte(m_block + iblock + 0x0800); + + dial = get_dial(x, (a & 0x80) ? 0 : (((a & 0x20) >> 5) | ((a & 0x10) >> 3))); + + //type and address of the char + type = ((b & 0x80) >> 4) | ((a & 0x80) >> 6); + address = ((b & 0x7f) >> 2) * 0x40 + (b & 0x03); + + //negative space + if ((b & 0xe0) == 0x80) + { + address = 0; + type = 3; + } + + //reset attributes latch + if (x == 0) + m_latchm = m_latchi = m_latchu = m_latchc0 = 0; + + if (type == 4) + { + m_latchm = b & 1; + m_latchi = (b & 2) >> 1; + m_latchu = (b & 4) >> 2; + } + + if (a & 0x80) + m_latchc0 = (a & 0x70) >> 4; + + //char attributes + c0 = m_latchc0; //background + c1 = a & 0x07; //foreground + i = m_latchi; //insert mode + f = (a & 0x08) >> 3; //flash + m = m_latchm; //hided + n = (a & 0x80) ? 0: ((a & 0x40) >> 6); //negative + u = m_latchu; //underline + + bichrome40(type, address, dial, iblock, x, y, c0, c1, i, f, m, n, u); +} + +// generate 24 bits 40 columns char +void ef9345_device::makechar_24x40(UINT16 x, UINT16 y) +{ + UINT8 a, b, c, c0, c1, i, f, m, n, u, type, dial; + UINT16 address, iblock; + + iblock = (m_mat & 0x80 && y > 1) ? indexblock(x, y / 2) : indexblock(x, y); + c = m_videoram->read_byte(m_block + iblock); + b = m_videoram->read_byte(m_block + iblock + 0x0800); + a = m_videoram->read_byte(m_block + iblock + 0x1000); + + if ((b & 0xc0) == 0xc0) + { + quadrichrome40(c, b, a, x, y); + return; + } + + dial = get_dial(x, (b & 0x02) + ((b & 0x08) >> 3)); + + //type and address of the char + address = ((c & 0x7f) >> 2) * 0x40 + (c & 0x03); + type = (b & 0xf0) >> 4; + + //char attributes + c0 = a & 0x07; //background + c1 = (a & 0x70) >> 4; //foreground + i = b & 0x01; //insert + f = (a & 0x08) >> 3; //flash + m = (b & 0x04) >> 2; //hided + n = ((a & 0x80) >> 7); //negative + u = (((b & 0x60) == 0) || ((b & 0xc0) == 0x40)) ? ((b & 0x10) >> 4) : 0; //underline + + bichrome40(type, address, dial, iblock, x, y, c0, c1, i, f, m, n, u); +} + +// generate 12 bits 80 columns char +void ef9345_device::makechar_12x80(UINT16 x, UINT16 y) +{ + UINT16 iblock = indexblock(x, y); + bichrome80(m_videoram->read_byte(m_block + iblock), (m_videoram->read_byte(m_block + iblock + 0x1000) >> 4) & 0x0f, 2 * x + 1, y + 1); + bichrome80(m_videoram->read_byte(m_block + iblock + 0x0800), m_videoram->read_byte(m_block + iblock + 0x1000) & 0x0f, 2 * x + 2, y + 1); +} + +void ef9345_device::draw_border(UINT16 line) +{ + if (m_char_mode == MODE12x80 || m_char_mode == MODE8x80) + for(int i = 0; i < 82; i++) + draw_char_80(m_border, i, line); + else + for(int i = 0; i < 42; i++) + draw_char_40(m_border, i, line); +} + +void ef9345_device::makechar(UINT16 x, UINT16 y) +{ + switch (m_char_mode) + { + case MODE24x40: + makechar_24x40(x, y); + break; + case MODEVAR40: + case MODE8x80: + logerror("Unemulated EF9345 mode: %02x\n", m_char_mode); + break; + case MODE12x80: + makechar_12x80(x, y); + break; + case MODE16x40: + makechar_16x40(x, y); + break; + default: + logerror("Unknown EF9345 mode: %02x\n", m_char_mode); + break; + } +} + +// Execute EF9345 command +void ef9345_device::ef9345_exec(UINT8 cmd) +{ + m_state = 0; + if ((m_registers[5] & 0x3f) == 39) m_state |= 0x10; //S4(LXa) set + if ((m_registers[7] & 0x3f) == 39) m_state |= 0x20; //S5(LXm) set + + UINT16 a = indexram(7); + + switch(cmd) + { + case 0x00: //KRF: R1,R2,R3->ram + case 0x01: //KRF: R1,R2,R3->ram + increment + set_busy_flag(4); + m_videoram->write_byte(a, m_registers[1]); + m_videoram->write_byte(a + 0x0800, m_registers[2]); + m_videoram->write_byte(a + 0x1000, m_registers[3]); + if (cmd&1) inc_x(7); + break; + case 0x02: //KRG: R1,R2->ram + case 0x03: //KRG: R1,R2->ram + increment + set_busy_flag(5.5); + m_videoram->write_byte(a, m_registers[1]); + m_videoram->write_byte(a + 0x0800, m_registers[2]); + if (cmd&1) inc_x(7); + break; + case 0x08: //KRF: ram->R1,R2,R3 + case 0x09: //KRF: ram->R1,R2,R3 + increment + set_busy_flag(7.5); + m_registers[1] = m_videoram->read_byte(a); + m_registers[2] = m_videoram->read_byte(a + 0x0800); + m_registers[3] = m_videoram->read_byte(a + 0x1000); + if (cmd&1) inc_x(7); + break; + case 0x0a: //KRG: ram->R1,R2 + case 0x0b: //KRG: ram->R1,R2 + increment + set_busy_flag(7.5); + m_registers[1] = m_videoram->read_byte(a); + m_registers[2] = m_videoram->read_byte(a + 0x0800); + if (cmd&1) inc_x(7); + break; + case 0x30: //OCT: R1->RAM, main pointer + case 0x31: //OCT: R1->RAM, main pointer + inc + set_busy_flag(4); + m_videoram->write_byte(indexram(7), m_registers[1]); + + if (cmd&1) + { + inc_x(7); + if ((m_registers[7] & 0x3f) == 0) + inc_y(6); + } + break; + case 0x34: //OCT: R1->RAM, aux pointer + case 0x35: //OCT: R1->RAM, aux pointer + inc + set_busy_flag(4); + m_videoram->write_byte(indexram(5), m_registers[1]); + + if (cmd&1) + inc_x(5); + break; + case 0x38: //OCT: RAM->R1, main pointer + case 0x39: //OCT: RAM->R1, main pointer + inc + set_busy_flag(4.5); + m_registers[1] = m_videoram->read_byte(indexram(7)); + + if (cmd&1) + { + inc_x(7); + + if ((m_registers[7] & 0x3f) == 0) + inc_y(6); + } + break; + case 0x3c: //OCT: RAM->R1, aux pointer + case 0x3d: //OCT: RAM->R1, aux pointer + inc + set_busy_flag(4.5); + m_registers[1] = m_videoram->read_byte(indexram(5)); + + if (cmd&1) + inc_x(5); + break; + case 0x50: //KRL: 80 UINT8 - 12 bits write + case 0x51: //KRL: 80 UINT8 - 12 bits write + inc + set_busy_flag(12.5); + m_videoram->write_byte(a, m_registers[1]); + switch((a / 0x0800) & 1) + { + case 0: + { + UINT8 tmp_data = m_videoram->read_byte(a + 0x1000); + m_videoram->write_byte(a + 0x1000, (tmp_data & 0x0f) | (m_registers[3] & 0xf0)); + break; + } + case 1: + { + UINT8 tmp_data = m_videoram->read_byte(a + 0x0800); + m_videoram->write_byte(a + 0x0800, (tmp_data & 0xf0) | (m_registers[3] & 0x0f)); + break; + } + } + if (cmd&1) + { + if ((m_registers[7] & 0x80) == 0x00) { m_registers[7] |= 0x80; return; } + m_registers[7] &= 0x80; + inc_x(7); + } + break; + case 0x58: //KRL: 80 UINT8 - 12 bits read + case 0x59: //KRL: 80 UINT8 - 12 bits read + inc + set_busy_flag(11.5); + m_registers[1] = m_videoram->read_byte(a); + switch((a / 0x0800) & 1) + { + case 0: + m_registers[3] = m_videoram->read_byte(a + 0x1000); + break; + case 1: + m_registers[3] = m_videoram->read_byte(a + 0x0800); + break; + } + if (cmd&1) + { + if ((m_registers[7] & 0x80) == 0x00) + { + m_registers[7] |= 0x80; + break; + } + m_registers[7] &= 0x80; + inc_x(7); + } + break; + case 0x80: //IND: R1->ROM (impossible ?) + break; + case 0x81: //IND: R1->TGS + case 0x82: //IND: R1->MAT + case 0x83: //IND: R1->PAT + case 0x84: //IND: R1->DOR + case 0x87: //IND: R1->ROR + set_busy_flag(2); + switch(cmd&7) + { + case 1: m_tgs = m_registers[1]; break; + case 2: m_mat = m_registers[1]; break; + case 3: m_pat = m_registers[1]; break; + case 4: m_dor = m_registers[1]; break; + case 7: m_ror = m_registers[1]; break; + } + set_video_mode(); + m_state &= 0x8f; //reset S4(LXa), S5(LXm), S6(Al) + break; + case 0x88: //IND: ROM->R1 + case 0x89: //IND: TGS->R1 + case 0x8a: //IND: MAT->R1 + case 0x8b: //IND: PAT->R1 + case 0x8c: //IND: DOR->R1 + case 0x8f: //IND: ROR->R1 + set_busy_flag(3.5); + switch(cmd&7) + { + case 0: m_registers[1] = m_charset->u8(indexrom(7) & 0x1fff); + case 1: m_registers[1] = m_tgs; break; + case 2: m_registers[1] = m_mat; break; + case 3: m_registers[1] = m_pat; break; + case 4: m_registers[1] = m_dor; break; + case 7: m_registers[1] = m_ror; break; + } + m_state &= 0x8f; //reset S4(LXa), S5(LXm), S6(Al) + break; + case 0x90: //NOP: no operation + case 0x91: //NOP: no operation + case 0x95: //VRM: vertical sync mask reset + case 0x99: //VSM: vertical sync mask set + break; + case 0xb0: //INY: increment Y + set_busy_flag(2); + inc_y(6); + m_state &= 0x8f; //reset S4(LXa), S5(LXm), S6(Al) + break; + case 0xd5: //MVB: move buffer MP->AP stop + case 0xd6: //MVB: move buffer MP->AP nostop + case 0xd9: //MVB: move buffer AP->MP stop + case 0xda: //MVB: move buffer AP->MP nostop + case 0xe5: //MVD: move double buffer MP->AP stop + case 0xe6: //MVD: move double buffer MP->AP nostop + case 0xe9: //MVD: move double buffer AP->MP stop + case 0xea: //MVD: move double buffer AP->MP nostop + case 0xf5: //MVT: move triple buffer MP->AP stop + case 0xf6: //MVT: move triple buffer MP->AP nostop + case 0xf9: //MVT: move triple buffer AP->MP stop + case 0xfa: //MVT: move triple buffer AP->MP nostop + { + UINT16 i, a1, a2; + UINT8 n = (cmd>>4) - 0x0c; + UINT8 r1 = (cmd&0x04) ? 7 : 5; + UINT8 r2 = (cmd&0x04) ? 5 : 7; + int busy = 2; + + for(i = 0; i < 1280; i++) + { + a1 = indexram(r1); a2 = indexram(r2); + m_videoram->write_byte(a2, m_videoram->read_byte(a1)); + + if (n > 1) m_videoram->write_byte(a2 + 0x0800, m_videoram->read_byte(a1 + 0x0800)); + if (n > 2) m_videoram->write_byte(a2 + 0x1000, m_videoram->read_byte(a1 + 0x1000)); + + inc_x(r1); + inc_x(r2); + if ((m_registers[5] & 0x3f) == 0 && (cmd&1)) + break; + + if ((m_registers[7] & 0x3f) == 0) + { + if (cmd&1) + break; + else + inc_y(6); + } + + busy += 4 * n; + } + m_state &= 0x8f; //reset S4(LXa), S5(LXm), S6(Al) + set_busy_flag(busy); + } + break; + case 0x05: //CLF: Clear page 24 bits + case 0x07: //CLG: Clear page 16 bits + case 0x40: //KRC: R1 -> ram + case 0x41: //KRC: R1 -> ram + inc + case 0x48: //KRC: 80 characters - 8 bits + case 0x49: //KRC: 80 characters - 8 bits + default: + logerror("Unemulated EF9345 cmd: %02x\n", cmd); + } +} + + +/************************************************************** + EF9345 interface +**************************************************************/ + +UINT32 ef9345_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + copybitmap(bitmap, m_screen_out, 0, 0, 0, 0, cliprect); + return 0; +} + +void ef9345_device::update_scanline(UINT16 scanline) +{ + UINT16 i; + + if (scanline == 250) + m_state &= 0xfb; + + set_busy_flag(104); + + if (m_char_mode == MODE12x80 || m_char_mode == MODE8x80) + { + draw_char_80(m_border, 0, (scanline / 10) + 1); + draw_char_80(m_border, 81, (scanline / 10) + 1); + } + else + { + draw_char_40(m_border, 0, (scanline / 10) + 1); + draw_char_40(m_border, 41, (scanline / 10) + 1); + } + + if (scanline == 0) + { + m_state |= 0x04; + draw_border(0); + if (m_pat & 1) + for(i = 0; i < 40; i++) + makechar(i, (scanline / 10)); + else + for(i = 0; i < 42; i++) + draw_char_40(m_border, i, 1); + } + else if (scanline < 120) + { + if (m_pat & 2) + for(i = 0; i < 40; i++) + makechar(i, (scanline / 10)); + else + draw_border(scanline / 10); + } + else if (scanline < 250) + { + if (m_pat & 4) + for(i = 0; i < 40; i++) + makechar(i, (scanline / 10)); + else + draw_border(scanline / 10); + + if (scanline == 240) + draw_border(26); + } +} + +READ8_MEMBER( ef9345_device::data_r ) +{ + if (offset & 7) + return m_registers[offset & 7]; + + if (m_bf) + m_state |= 0x80; + else + m_state &= 0x7f; + + return m_state; +} + +WRITE8_MEMBER( ef9345_device::data_w ) +{ + m_registers[offset & 7] = data; + + if (offset & 8) + ef9345_exec(m_registers[0] & 0xff); +} diff --git a/src/devices/video/ef9345.h b/src/devices/video/ef9345.h new file mode 100644 index 00000000000..332b037a223 --- /dev/null +++ b/src/devices/video/ef9345.h @@ -0,0 +1,118 @@ +// license:GPL-2.0+ +// copyright-holders:Daniel Coulom,Sandro Ronco +/********************************************************************* + + ef9345.h + + Thomson EF9345 video controller + +*********************************************************************/ + + +#pragma once + +#ifndef __EF9345_H__ +#define __EF9345_H__ + + +#define MCFG_EF9345_PALETTE(_palette_tag) \ + ef9345_device::static_set_palette_tag(*device, "^" _palette_tag); + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> ef9345_device + +class ef9345_device : public device_t, + public device_memory_interface, + public device_video_interface +{ +public: + // construction/destruction + ef9345_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // static configuration + static void static_set_palette_tag(device_t &device, const char *tag); + + // device interface + DECLARE_READ8_MEMBER( data_r ); + DECLARE_WRITE8_MEMBER( data_w ); + void update_scanline(UINT16 scanline); + UINT32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + // device_config_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const; + + // address space configurations + const address_space_config m_space_config; + + // inline helper + inline UINT16 indexram(UINT8 r); + inline UINT16 indexrom(UINT8 r); + inline void inc_x(UINT8 r); + inline void inc_y(UINT8 r); + +private: + + void set_busy_flag(int period); + void draw_char_40(UINT8 *c, UINT16 x, UINT16 y); + void draw_char_80(UINT8 *c, UINT16 x, UINT16 y); + void set_video_mode(void); + void init_accented_chars(void); + UINT8 read_char(UINT8 index, UINT16 addr); + UINT8 get_dial(UINT8 x, UINT8 attrib); + void zoom(UINT8 *pix, UINT16 n); + UINT16 indexblock(UINT16 x, UINT16 y); + void bichrome40(UINT8 type, UINT16 address, UINT8 dial, UINT16 iblock, UINT16 x, UINT16 y, UINT8 c0, UINT8 c1, UINT8 insert, UINT8 flash, UINT8 hided, UINT8 negative, UINT8 underline); + void quadrichrome40(UINT8 c, UINT8 b, UINT8 a, UINT16 x, UINT16 y); + void bichrome80(UINT8 c, UINT8 a, UINT16 x, UINT16 y); + void makechar(UINT16 x, UINT16 y); + void draw_border(UINT16 line); + void makechar_16x40(UINT16 x, UINT16 y); + void makechar_24x40(UINT16 x, UINT16 y); + void makechar_12x80(UINT16 x, UINT16 y); + void ef9345_exec(UINT8 cmd); + + // internal state + static const device_timer_id BUSY_TIMER = 0; + static const device_timer_id BLINKING_TIMER = 1; + + memory_region *m_charset; + address_space *m_videoram; + + UINT8 m_bf; //busy flag + UINT8 m_char_mode; //40 or 80 chars for line + UINT8 m_acc_char[0x2000]; //accented chars + UINT8 m_registers[8]; //registers R0-R7 + UINT8 m_state; //status register + UINT8 m_tgs,m_mat,m_pat,m_dor,m_ror; //indirect registers + UINT8 m_border[80]; //border color + UINT16 m_block; //current memory block + UINT16 m_ram_base[4]; //index of ram charset + UINT8 m_blink; //cursor status + UINT8 m_last_dial[40]; //last chars dial (for determinate the zoom position) + UINT8 m_latchc0; //background color latch + UINT8 m_latchm; //hided atribute latch + UINT8 m_latchi; //insert atribute latch + UINT8 m_latchu; //underline atribute latch + + bitmap_rgb32 m_screen_out; + + // timers + emu_timer *m_busy_timer; + emu_timer *m_blink_timer; + + required_device m_palette; +}; + +// device type definition +extern const device_type EF9345; + +#endif diff --git a/src/devices/video/epic12.c b/src/devices/video/epic12.c new file mode 100644 index 00000000000..a22100e5543 --- /dev/null +++ b/src/devices/video/epic12.c @@ -0,0 +1,949 @@ +// license:BSD-3-Clause +// copyright-holders:David Haywood, Luca Elia, MetalliC +/* emulation of Altera Cyclone EPIC12 FPGA programmed as a blitter */ + +#include "emu.h" +#include "epic12.h" + + + +const device_type EPIC12 = &device_creator; + +epic12_device::epic12_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, EPIC12, "EP1C12 Blitter", tag, owner, clock, "epic12", __FILE__), + device_video_interface(mconfig, *this) +{ + m_is_unsafe = 0; + m_delay_scale = 0; + m_blitter_request = 0; + m_blitter_delay_timer = 0; + m_blitter_busy = 0; + m_gfx_addr = 0; + m_gfx_scroll_0_x = 0; + m_gfx_scroll_0_y = 0; + m_gfx_scroll_1_x = 0; + m_gfx_scroll_1_y = 0; + m_gfx_addr_shadowcopy = 0; + m_gfx_scroll_0_x_shadowcopy = 0; + m_gfx_scroll_0_y_shadowcopy = 0; + m_gfx_scroll_1_x_shadowcopy = 0; + m_gfx_scroll_1_y_shadowcopy = 0; + epic12_device_blit_delay = 0; +} + +TIMER_CALLBACK_MEMBER( epic12_device::blitter_delay_callback ) +{ + m_blitter_busy = 0; +} + + +void epic12_device::device_start() +{ + m_gfx_size = 0x2000 * 0x1000; + m_bitmaps = auto_bitmap_rgb32_alloc(machine(), 0x2000, 0x1000); + m_clip = m_bitmaps->cliprect(); + m_clip.set(0, 0x2000-1, 0, 0x1000-1); + + m_ram16_copy = auto_alloc_array(machine(), UINT16, m_main_ramsize/2); + + m_blitter_delay_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(epic12_device::blitter_delay_callback),this)); + m_blitter_delay_timer->adjust(attotime::never); +} + +void epic12_device::device_reset() +{ + if (m_is_unsafe) + { + m_use_ram = m_ram16; + m_work_queue = osd_work_queue_alloc(WORK_QUEUE_FLAG_HIGH_FREQ|WORK_QUEUE_FLAG_MULTI); + } + else + { + m_use_ram = m_ram16_copy; // slow mode + m_work_queue = osd_work_queue_alloc(WORK_QUEUE_FLAG_HIGH_FREQ); + } + + // cache table to avoid divides in blit code, also pre-clamped + int x,y; + for (y=0;y<0x40;y++) + { + for (x=0;x<0x20;x++) + { + epic12_device_colrtable[x][y] = (x*y) / 0x1f; + if (epic12_device_colrtable[x][y]>0x1f) epic12_device_colrtable[x][y] = 0x1f; + + epic12_device_colrtable_rev[x^0x1f][y] = (x*y) / 0x1f; + if (epic12_device_colrtable_rev[x^0x1f][y]>0x1f) epic12_device_colrtable_rev[x^0x1f][y] = 0x1f; + } + } + + // preclamped add table + for (y=0;y<0x20;y++) + { + for (x=0;x<0x20;x++) + { + epic12_device_colrtable_add[x][y] = (x+y); + if (epic12_device_colrtable_add[x][y]>0x1f) epic12_device_colrtable_add[x][y] = 0x1f; + } + } + + m_blitter_busy = 0; +} + +// todo, get these into the device class without ruining performance +UINT8 epic12_device_colrtable[0x20][0x40]; +UINT8 epic12_device_colrtable_rev[0x20][0x40]; +UINT8 epic12_device_colrtable_add[0x20][0x20]; +UINT64 epic12_device_blit_delay; + +inline UINT16 epic12_device::READ_NEXT_WORD(offs_t *addr) +{ +// UINT16 data = space.read_word(*addr); // going through the memory system is 'more correct' but noticeably slower + UINT16 data = m_use_ram[((*addr & m_main_rammask) >> 1) ^ NATIVE_ENDIAN_VALUE_LE_BE(3, 0)]; + + *addr += 2; + +// printf("data %04x\n", data); + return data; +} + +inline UINT16 epic12_device::COPY_NEXT_WORD(address_space &space, offs_t *addr) +{ +// UINT16 data = space.read_word(*addr); // going through the memory system is 'more correct' but noticeably slower + UINT16 data = m_ram16[((*addr & m_main_rammask) >> 1) ^ NATIVE_ENDIAN_VALUE_LE_BE(3, 0)]; + m_ram16_copy[((*addr & m_main_rammask) >> 1) ^ NATIVE_ENDIAN_VALUE_LE_BE(3, 0)] = data; + + *addr += 2; + +// printf("data %04x\n", data); + return data; +} + + +inline void epic12_device::gfx_upload_shadow_copy(address_space &space, offs_t *addr) +{ + UINT32 x,y, dimx,dimy; + COPY_NEXT_WORD(space, addr); + COPY_NEXT_WORD(space, addr); + COPY_NEXT_WORD(space, addr); + COPY_NEXT_WORD(space, addr); + COPY_NEXT_WORD(space, addr); + COPY_NEXT_WORD(space, addr); + + dimx = (COPY_NEXT_WORD(space, addr) & 0x1fff) + 1; + dimy = (COPY_NEXT_WORD(space, addr) & 0x0fff) + 1; + + for (y = 0; y < dimy; y++) + { + for (x = 0; x < dimx; x++) + { + COPY_NEXT_WORD(space, addr); + } + } +} + +inline void epic12_device::gfx_upload(offs_t *addr) +{ + UINT32 x,y, dst_p,dst_x_start,dst_y_start, dimx,dimy; + UINT32 *dst; + + // 0x20000000 + READ_NEXT_WORD(addr); + READ_NEXT_WORD(addr); + + // 0x99999999 + READ_NEXT_WORD(addr); + READ_NEXT_WORD(addr); + + dst_x_start = READ_NEXT_WORD(addr); + dst_y_start = READ_NEXT_WORD(addr); + + dst_p = 0; + dst_x_start &= 0x1fff; + dst_y_start &= 0x0fff; + + dimx = (READ_NEXT_WORD(addr) & 0x1fff) + 1; + dimy = (READ_NEXT_WORD(addr) & 0x0fff) + 1; + + logerror("GFX COPY: DST %02X,%02X,%03X DIM %02X,%03X\n", dst_p,dst_x_start,dst_y_start, dimx,dimy); + + for (y = 0; y < dimy; y++) + { + dst = &m_bitmaps->pix(dst_y_start + y, 0); + dst += dst_x_start; + + for (x = 0; x < dimx; x++) + { + UINT16 pendat = READ_NEXT_WORD(addr); + // real hw would upload the gfxword directly, but our VRAM is 32-bit, so convert it. + //dst[dst_x_start + x] = pendat; + *dst++ = ((pendat&0x8000)<<14) | ((pendat&0x7c00)<<9) | ((pendat&0x03e0)<<6) | ((pendat&0x001f)<<3); // --t- ---- rrrr r--- gggg g--- bbbb b--- format + //dst[dst_x_start + x] = ((pendat&0x8000)<<14) | ((pendat&0x7c00)<<6) | ((pendat&0x03e0)<<3) | ((pendat&0x001f)<<0); // --t- ---- ---r rrrr ---g gggg ---b bbbb format + + + } + } +} + +#define draw_params m_bitmaps, &m_clip, &m_bitmaps->pix(0,0),src_x,src_y, x,y, dimx,dimy, flipy, s_alpha, d_alpha, &tint_clr + + + +epic12_device_blitfunction epic12_device_f0_ti1_tr1_blit_funcs[] = +{ + epic12_device::draw_sprite_f0_ti1_tr1_s0_d0, epic12_device::draw_sprite_f0_ti1_tr1_s1_d0, epic12_device::draw_sprite_f0_ti1_tr1_s2_d0, epic12_device::draw_sprite_f0_ti1_tr1_s3_d0, epic12_device::draw_sprite_f0_ti1_tr1_s4_d0, epic12_device::draw_sprite_f0_ti1_tr1_s5_d0, epic12_device::draw_sprite_f0_ti1_tr1_s6_d0, epic12_device::draw_sprite_f0_ti1_tr1_s7_d0, + epic12_device::draw_sprite_f0_ti1_tr1_s0_d1, epic12_device::draw_sprite_f0_ti1_tr1_s1_d1, epic12_device::draw_sprite_f0_ti1_tr1_s2_d1, epic12_device::draw_sprite_f0_ti1_tr1_s3_d1, epic12_device::draw_sprite_f0_ti1_tr1_s4_d1, epic12_device::draw_sprite_f0_ti1_tr1_s5_d1, epic12_device::draw_sprite_f0_ti1_tr1_s6_d1, epic12_device::draw_sprite_f0_ti1_tr1_s7_d1, + epic12_device::draw_sprite_f0_ti1_tr1_s0_d2, epic12_device::draw_sprite_f0_ti1_tr1_s1_d2, epic12_device::draw_sprite_f0_ti1_tr1_s2_d2, epic12_device::draw_sprite_f0_ti1_tr1_s3_d2, epic12_device::draw_sprite_f0_ti1_tr1_s4_d2, epic12_device::draw_sprite_f0_ti1_tr1_s5_d2, epic12_device::draw_sprite_f0_ti1_tr1_s6_d2, epic12_device::draw_sprite_f0_ti1_tr1_s7_d2, + epic12_device::draw_sprite_f0_ti1_tr1_s0_d3, epic12_device::draw_sprite_f0_ti1_tr1_s1_d3, epic12_device::draw_sprite_f0_ti1_tr1_s2_d3, epic12_device::draw_sprite_f0_ti1_tr1_s3_d3, epic12_device::draw_sprite_f0_ti1_tr1_s4_d3, epic12_device::draw_sprite_f0_ti1_tr1_s5_d3, epic12_device::draw_sprite_f0_ti1_tr1_s6_d3, epic12_device::draw_sprite_f0_ti1_tr1_s7_d3, + epic12_device::draw_sprite_f0_ti1_tr1_s0_d4, epic12_device::draw_sprite_f0_ti1_tr1_s1_d4, epic12_device::draw_sprite_f0_ti1_tr1_s2_d4, epic12_device::draw_sprite_f0_ti1_tr1_s3_d4, epic12_device::draw_sprite_f0_ti1_tr1_s4_d4, epic12_device::draw_sprite_f0_ti1_tr1_s5_d4, epic12_device::draw_sprite_f0_ti1_tr1_s6_d4, epic12_device::draw_sprite_f0_ti1_tr1_s7_d4, + epic12_device::draw_sprite_f0_ti1_tr1_s0_d5, epic12_device::draw_sprite_f0_ti1_tr1_s1_d5, epic12_device::draw_sprite_f0_ti1_tr1_s2_d5, epic12_device::draw_sprite_f0_ti1_tr1_s3_d5, epic12_device::draw_sprite_f0_ti1_tr1_s4_d5, epic12_device::draw_sprite_f0_ti1_tr1_s5_d5, epic12_device::draw_sprite_f0_ti1_tr1_s6_d5, epic12_device::draw_sprite_f0_ti1_tr1_s7_d5, + epic12_device::draw_sprite_f0_ti1_tr1_s0_d6, epic12_device::draw_sprite_f0_ti1_tr1_s1_d6, epic12_device::draw_sprite_f0_ti1_tr1_s2_d6, epic12_device::draw_sprite_f0_ti1_tr1_s3_d6, epic12_device::draw_sprite_f0_ti1_tr1_s4_d6, epic12_device::draw_sprite_f0_ti1_tr1_s5_d6, epic12_device::draw_sprite_f0_ti1_tr1_s6_d6, epic12_device::draw_sprite_f0_ti1_tr1_s7_d6, + epic12_device::draw_sprite_f0_ti1_tr1_s0_d7, epic12_device::draw_sprite_f0_ti1_tr1_s1_d7, epic12_device::draw_sprite_f0_ti1_tr1_s2_d7, epic12_device::draw_sprite_f0_ti1_tr1_s3_d7, epic12_device::draw_sprite_f0_ti1_tr1_s4_d7, epic12_device::draw_sprite_f0_ti1_tr1_s5_d7, epic12_device::draw_sprite_f0_ti1_tr1_s6_d7, epic12_device::draw_sprite_f0_ti1_tr1_s7_d7, +}; + +epic12_device_blitfunction epic12_device_f0_ti1_tr0_blit_funcs[] = +{ + epic12_device::draw_sprite_f0_ti1_tr0_s0_d0, epic12_device::draw_sprite_f0_ti1_tr0_s1_d0, epic12_device::draw_sprite_f0_ti1_tr0_s2_d0, epic12_device::draw_sprite_f0_ti1_tr0_s3_d0, epic12_device::draw_sprite_f0_ti1_tr0_s4_d0, epic12_device::draw_sprite_f0_ti1_tr0_s5_d0, epic12_device::draw_sprite_f0_ti1_tr0_s6_d0, epic12_device::draw_sprite_f0_ti1_tr0_s7_d0, + epic12_device::draw_sprite_f0_ti1_tr0_s0_d1, epic12_device::draw_sprite_f0_ti1_tr0_s1_d1, epic12_device::draw_sprite_f0_ti1_tr0_s2_d1, epic12_device::draw_sprite_f0_ti1_tr0_s3_d1, epic12_device::draw_sprite_f0_ti1_tr0_s4_d1, epic12_device::draw_sprite_f0_ti1_tr0_s5_d1, epic12_device::draw_sprite_f0_ti1_tr0_s6_d1, epic12_device::draw_sprite_f0_ti1_tr0_s7_d1, + epic12_device::draw_sprite_f0_ti1_tr0_s0_d2, epic12_device::draw_sprite_f0_ti1_tr0_s1_d2, epic12_device::draw_sprite_f0_ti1_tr0_s2_d2, epic12_device::draw_sprite_f0_ti1_tr0_s3_d2, epic12_device::draw_sprite_f0_ti1_tr0_s4_d2, epic12_device::draw_sprite_f0_ti1_tr0_s5_d2, epic12_device::draw_sprite_f0_ti1_tr0_s6_d2, epic12_device::draw_sprite_f0_ti1_tr0_s7_d2, + epic12_device::draw_sprite_f0_ti1_tr0_s0_d3, epic12_device::draw_sprite_f0_ti1_tr0_s1_d3, epic12_device::draw_sprite_f0_ti1_tr0_s2_d3, epic12_device::draw_sprite_f0_ti1_tr0_s3_d3, epic12_device::draw_sprite_f0_ti1_tr0_s4_d3, epic12_device::draw_sprite_f0_ti1_tr0_s5_d3, epic12_device::draw_sprite_f0_ti1_tr0_s6_d3, epic12_device::draw_sprite_f0_ti1_tr0_s7_d3, + epic12_device::draw_sprite_f0_ti1_tr0_s0_d4, epic12_device::draw_sprite_f0_ti1_tr0_s1_d4, epic12_device::draw_sprite_f0_ti1_tr0_s2_d4, epic12_device::draw_sprite_f0_ti1_tr0_s3_d4, epic12_device::draw_sprite_f0_ti1_tr0_s4_d4, epic12_device::draw_sprite_f0_ti1_tr0_s5_d4, epic12_device::draw_sprite_f0_ti1_tr0_s6_d4, epic12_device::draw_sprite_f0_ti1_tr0_s7_d4, + epic12_device::draw_sprite_f0_ti1_tr0_s0_d5, epic12_device::draw_sprite_f0_ti1_tr0_s1_d5, epic12_device::draw_sprite_f0_ti1_tr0_s2_d5, epic12_device::draw_sprite_f0_ti1_tr0_s3_d5, epic12_device::draw_sprite_f0_ti1_tr0_s4_d5, epic12_device::draw_sprite_f0_ti1_tr0_s5_d5, epic12_device::draw_sprite_f0_ti1_tr0_s6_d5, epic12_device::draw_sprite_f0_ti1_tr0_s7_d5, + epic12_device::draw_sprite_f0_ti1_tr0_s0_d6, epic12_device::draw_sprite_f0_ti1_tr0_s1_d6, epic12_device::draw_sprite_f0_ti1_tr0_s2_d6, epic12_device::draw_sprite_f0_ti1_tr0_s3_d6, epic12_device::draw_sprite_f0_ti1_tr0_s4_d6, epic12_device::draw_sprite_f0_ti1_tr0_s5_d6, epic12_device::draw_sprite_f0_ti1_tr0_s6_d6, epic12_device::draw_sprite_f0_ti1_tr0_s7_d6, + epic12_device::draw_sprite_f0_ti1_tr0_s0_d7, epic12_device::draw_sprite_f0_ti1_tr0_s1_d7, epic12_device::draw_sprite_f0_ti1_tr0_s2_d7, epic12_device::draw_sprite_f0_ti1_tr0_s3_d7, epic12_device::draw_sprite_f0_ti1_tr0_s4_d7, epic12_device::draw_sprite_f0_ti1_tr0_s5_d7, epic12_device::draw_sprite_f0_ti1_tr0_s6_d7, epic12_device::draw_sprite_f0_ti1_tr0_s7_d7, +}; + +epic12_device_blitfunction epic12_device_f1_ti1_tr1_blit_funcs[] = +{ + epic12_device::draw_sprite_f1_ti1_tr1_s0_d0, epic12_device::draw_sprite_f1_ti1_tr1_s1_d0, epic12_device::draw_sprite_f1_ti1_tr1_s2_d0, epic12_device::draw_sprite_f1_ti1_tr1_s3_d0, epic12_device::draw_sprite_f1_ti1_tr1_s4_d0, epic12_device::draw_sprite_f1_ti1_tr1_s5_d0, epic12_device::draw_sprite_f1_ti1_tr1_s6_d0, epic12_device::draw_sprite_f1_ti1_tr1_s7_d0, + epic12_device::draw_sprite_f1_ti1_tr1_s0_d1, epic12_device::draw_sprite_f1_ti1_tr1_s1_d1, epic12_device::draw_sprite_f1_ti1_tr1_s2_d1, epic12_device::draw_sprite_f1_ti1_tr1_s3_d1, epic12_device::draw_sprite_f1_ti1_tr1_s4_d1, epic12_device::draw_sprite_f1_ti1_tr1_s5_d1, epic12_device::draw_sprite_f1_ti1_tr1_s6_d1, epic12_device::draw_sprite_f1_ti1_tr1_s7_d1, + epic12_device::draw_sprite_f1_ti1_tr1_s0_d2, epic12_device::draw_sprite_f1_ti1_tr1_s1_d2, epic12_device::draw_sprite_f1_ti1_tr1_s2_d2, epic12_device::draw_sprite_f1_ti1_tr1_s3_d2, epic12_device::draw_sprite_f1_ti1_tr1_s4_d2, epic12_device::draw_sprite_f1_ti1_tr1_s5_d2, epic12_device::draw_sprite_f1_ti1_tr1_s6_d2, epic12_device::draw_sprite_f1_ti1_tr1_s7_d2, + epic12_device::draw_sprite_f1_ti1_tr1_s0_d3, epic12_device::draw_sprite_f1_ti1_tr1_s1_d3, epic12_device::draw_sprite_f1_ti1_tr1_s2_d3, epic12_device::draw_sprite_f1_ti1_tr1_s3_d3, epic12_device::draw_sprite_f1_ti1_tr1_s4_d3, epic12_device::draw_sprite_f1_ti1_tr1_s5_d3, epic12_device::draw_sprite_f1_ti1_tr1_s6_d3, epic12_device::draw_sprite_f1_ti1_tr1_s7_d3, + epic12_device::draw_sprite_f1_ti1_tr1_s0_d4, epic12_device::draw_sprite_f1_ti1_tr1_s1_d4, epic12_device::draw_sprite_f1_ti1_tr1_s2_d4, epic12_device::draw_sprite_f1_ti1_tr1_s3_d4, epic12_device::draw_sprite_f1_ti1_tr1_s4_d4, epic12_device::draw_sprite_f1_ti1_tr1_s5_d4, epic12_device::draw_sprite_f1_ti1_tr1_s6_d4, epic12_device::draw_sprite_f1_ti1_tr1_s7_d4, + epic12_device::draw_sprite_f1_ti1_tr1_s0_d5, epic12_device::draw_sprite_f1_ti1_tr1_s1_d5, epic12_device::draw_sprite_f1_ti1_tr1_s2_d5, epic12_device::draw_sprite_f1_ti1_tr1_s3_d5, epic12_device::draw_sprite_f1_ti1_tr1_s4_d5, epic12_device::draw_sprite_f1_ti1_tr1_s5_d5, epic12_device::draw_sprite_f1_ti1_tr1_s6_d5, epic12_device::draw_sprite_f1_ti1_tr1_s7_d5, + epic12_device::draw_sprite_f1_ti1_tr1_s0_d6, epic12_device::draw_sprite_f1_ti1_tr1_s1_d6, epic12_device::draw_sprite_f1_ti1_tr1_s2_d6, epic12_device::draw_sprite_f1_ti1_tr1_s3_d6, epic12_device::draw_sprite_f1_ti1_tr1_s4_d6, epic12_device::draw_sprite_f1_ti1_tr1_s5_d6, epic12_device::draw_sprite_f1_ti1_tr1_s6_d6, epic12_device::draw_sprite_f1_ti1_tr1_s7_d6, + epic12_device::draw_sprite_f1_ti1_tr1_s0_d7, epic12_device::draw_sprite_f1_ti1_tr1_s1_d7, epic12_device::draw_sprite_f1_ti1_tr1_s2_d7, epic12_device::draw_sprite_f1_ti1_tr1_s3_d7, epic12_device::draw_sprite_f1_ti1_tr1_s4_d7, epic12_device::draw_sprite_f1_ti1_tr1_s5_d7, epic12_device::draw_sprite_f1_ti1_tr1_s6_d7, epic12_device::draw_sprite_f1_ti1_tr1_s7_d7, +}; + +epic12_device_blitfunction epic12_device_f1_ti1_tr0_blit_funcs[] = +{ + epic12_device::draw_sprite_f1_ti1_tr0_s0_d0, epic12_device::draw_sprite_f1_ti1_tr0_s1_d0, epic12_device::draw_sprite_f1_ti1_tr0_s2_d0, epic12_device::draw_sprite_f1_ti1_tr0_s3_d0, epic12_device::draw_sprite_f1_ti1_tr0_s4_d0, epic12_device::draw_sprite_f1_ti1_tr0_s5_d0, epic12_device::draw_sprite_f1_ti1_tr0_s6_d0, epic12_device::draw_sprite_f1_ti1_tr0_s7_d0, + epic12_device::draw_sprite_f1_ti1_tr0_s0_d1, epic12_device::draw_sprite_f1_ti1_tr0_s1_d1, epic12_device::draw_sprite_f1_ti1_tr0_s2_d1, epic12_device::draw_sprite_f1_ti1_tr0_s3_d1, epic12_device::draw_sprite_f1_ti1_tr0_s4_d1, epic12_device::draw_sprite_f1_ti1_tr0_s5_d1, epic12_device::draw_sprite_f1_ti1_tr0_s6_d1, epic12_device::draw_sprite_f1_ti1_tr0_s7_d1, + epic12_device::draw_sprite_f1_ti1_tr0_s0_d2, epic12_device::draw_sprite_f1_ti1_tr0_s1_d2, epic12_device::draw_sprite_f1_ti1_tr0_s2_d2, epic12_device::draw_sprite_f1_ti1_tr0_s3_d2, epic12_device::draw_sprite_f1_ti1_tr0_s4_d2, epic12_device::draw_sprite_f1_ti1_tr0_s5_d2, epic12_device::draw_sprite_f1_ti1_tr0_s6_d2, epic12_device::draw_sprite_f1_ti1_tr0_s7_d2, + epic12_device::draw_sprite_f1_ti1_tr0_s0_d3, epic12_device::draw_sprite_f1_ti1_tr0_s1_d3, epic12_device::draw_sprite_f1_ti1_tr0_s2_d3, epic12_device::draw_sprite_f1_ti1_tr0_s3_d3, epic12_device::draw_sprite_f1_ti1_tr0_s4_d3, epic12_device::draw_sprite_f1_ti1_tr0_s5_d3, epic12_device::draw_sprite_f1_ti1_tr0_s6_d3, epic12_device::draw_sprite_f1_ti1_tr0_s7_d3, + epic12_device::draw_sprite_f1_ti1_tr0_s0_d4, epic12_device::draw_sprite_f1_ti1_tr0_s1_d4, epic12_device::draw_sprite_f1_ti1_tr0_s2_d4, epic12_device::draw_sprite_f1_ti1_tr0_s3_d4, epic12_device::draw_sprite_f1_ti1_tr0_s4_d4, epic12_device::draw_sprite_f1_ti1_tr0_s5_d4, epic12_device::draw_sprite_f1_ti1_tr0_s6_d4, epic12_device::draw_sprite_f1_ti1_tr0_s7_d4, + epic12_device::draw_sprite_f1_ti1_tr0_s0_d5, epic12_device::draw_sprite_f1_ti1_tr0_s1_d5, epic12_device::draw_sprite_f1_ti1_tr0_s2_d5, epic12_device::draw_sprite_f1_ti1_tr0_s3_d5, epic12_device::draw_sprite_f1_ti1_tr0_s4_d5, epic12_device::draw_sprite_f1_ti1_tr0_s5_d5, epic12_device::draw_sprite_f1_ti1_tr0_s6_d5, epic12_device::draw_sprite_f1_ti1_tr0_s7_d5, + epic12_device::draw_sprite_f1_ti1_tr0_s0_d6, epic12_device::draw_sprite_f1_ti1_tr0_s1_d6, epic12_device::draw_sprite_f1_ti1_tr0_s2_d6, epic12_device::draw_sprite_f1_ti1_tr0_s3_d6, epic12_device::draw_sprite_f1_ti1_tr0_s4_d6, epic12_device::draw_sprite_f1_ti1_tr0_s5_d6, epic12_device::draw_sprite_f1_ti1_tr0_s6_d6, epic12_device::draw_sprite_f1_ti1_tr0_s7_d6, + epic12_device::draw_sprite_f1_ti1_tr0_s0_d7, epic12_device::draw_sprite_f1_ti1_tr0_s1_d7, epic12_device::draw_sprite_f1_ti1_tr0_s2_d7, epic12_device::draw_sprite_f1_ti1_tr0_s3_d7, epic12_device::draw_sprite_f1_ti1_tr0_s4_d7, epic12_device::draw_sprite_f1_ti1_tr0_s5_d7, epic12_device::draw_sprite_f1_ti1_tr0_s6_d7, epic12_device::draw_sprite_f1_ti1_tr0_s7_d7, +}; + + + +epic12_device_blitfunction epic12_device_f0_ti0_tr1_blit_funcs[] = +{ + epic12_device::draw_sprite_f0_ti0_tr1_s0_d0, epic12_device::draw_sprite_f0_ti0_tr1_s1_d0, epic12_device::draw_sprite_f0_ti0_tr1_s2_d0, epic12_device::draw_sprite_f0_ti0_tr1_s3_d0, epic12_device::draw_sprite_f0_ti0_tr1_s4_d0, epic12_device::draw_sprite_f0_ti0_tr1_s5_d0, epic12_device::draw_sprite_f0_ti0_tr1_s6_d0, epic12_device::draw_sprite_f0_ti0_tr1_s7_d0, + epic12_device::draw_sprite_f0_ti0_tr1_s0_d1, epic12_device::draw_sprite_f0_ti0_tr1_s1_d1, epic12_device::draw_sprite_f0_ti0_tr1_s2_d1, epic12_device::draw_sprite_f0_ti0_tr1_s3_d1, epic12_device::draw_sprite_f0_ti0_tr1_s4_d1, epic12_device::draw_sprite_f0_ti0_tr1_s5_d1, epic12_device::draw_sprite_f0_ti0_tr1_s6_d1, epic12_device::draw_sprite_f0_ti0_tr1_s7_d1, + epic12_device::draw_sprite_f0_ti0_tr1_s0_d2, epic12_device::draw_sprite_f0_ti0_tr1_s1_d2, epic12_device::draw_sprite_f0_ti0_tr1_s2_d2, epic12_device::draw_sprite_f0_ti0_tr1_s3_d2, epic12_device::draw_sprite_f0_ti0_tr1_s4_d2, epic12_device::draw_sprite_f0_ti0_tr1_s5_d2, epic12_device::draw_sprite_f0_ti0_tr1_s6_d2, epic12_device::draw_sprite_f0_ti0_tr1_s7_d2, + epic12_device::draw_sprite_f0_ti0_tr1_s0_d3, epic12_device::draw_sprite_f0_ti0_tr1_s1_d3, epic12_device::draw_sprite_f0_ti0_tr1_s2_d3, epic12_device::draw_sprite_f0_ti0_tr1_s3_d3, epic12_device::draw_sprite_f0_ti0_tr1_s4_d3, epic12_device::draw_sprite_f0_ti0_tr1_s5_d3, epic12_device::draw_sprite_f0_ti0_tr1_s6_d3, epic12_device::draw_sprite_f0_ti0_tr1_s7_d3, + epic12_device::draw_sprite_f0_ti0_tr1_s0_d4, epic12_device::draw_sprite_f0_ti0_tr1_s1_d4, epic12_device::draw_sprite_f0_ti0_tr1_s2_d4, epic12_device::draw_sprite_f0_ti0_tr1_s3_d4, epic12_device::draw_sprite_f0_ti0_tr1_s4_d4, epic12_device::draw_sprite_f0_ti0_tr1_s5_d4, epic12_device::draw_sprite_f0_ti0_tr1_s6_d4, epic12_device::draw_sprite_f0_ti0_tr1_s7_d4, + epic12_device::draw_sprite_f0_ti0_tr1_s0_d5, epic12_device::draw_sprite_f0_ti0_tr1_s1_d5, epic12_device::draw_sprite_f0_ti0_tr1_s2_d5, epic12_device::draw_sprite_f0_ti0_tr1_s3_d5, epic12_device::draw_sprite_f0_ti0_tr1_s4_d5, epic12_device::draw_sprite_f0_ti0_tr1_s5_d5, epic12_device::draw_sprite_f0_ti0_tr1_s6_d5, epic12_device::draw_sprite_f0_ti0_tr1_s7_d5, + epic12_device::draw_sprite_f0_ti0_tr1_s0_d6, epic12_device::draw_sprite_f0_ti0_tr1_s1_d6, epic12_device::draw_sprite_f0_ti0_tr1_s2_d6, epic12_device::draw_sprite_f0_ti0_tr1_s3_d6, epic12_device::draw_sprite_f0_ti0_tr1_s4_d6, epic12_device::draw_sprite_f0_ti0_tr1_s5_d6, epic12_device::draw_sprite_f0_ti0_tr1_s6_d6, epic12_device::draw_sprite_f0_ti0_tr1_s7_d6, + epic12_device::draw_sprite_f0_ti0_tr1_s0_d7, epic12_device::draw_sprite_f0_ti0_tr1_s1_d7, epic12_device::draw_sprite_f0_ti0_tr1_s2_d7, epic12_device::draw_sprite_f0_ti0_tr1_s3_d7, epic12_device::draw_sprite_f0_ti0_tr1_s4_d7, epic12_device::draw_sprite_f0_ti0_tr1_s5_d7, epic12_device::draw_sprite_f0_ti0_tr1_s6_d7, epic12_device::draw_sprite_f0_ti0_tr1_s7_d7, +}; + +epic12_device_blitfunction epic12_device_f0_ti0_tr0_blit_funcs[] = +{ + epic12_device::draw_sprite_f0_ti0_tr0_s0_d0, epic12_device::draw_sprite_f0_ti0_tr0_s1_d0, epic12_device::draw_sprite_f0_ti0_tr0_s2_d0, epic12_device::draw_sprite_f0_ti0_tr0_s3_d0, epic12_device::draw_sprite_f0_ti0_tr0_s4_d0, epic12_device::draw_sprite_f0_ti0_tr0_s5_d0, epic12_device::draw_sprite_f0_ti0_tr0_s6_d0, epic12_device::draw_sprite_f0_ti0_tr0_s7_d0, + epic12_device::draw_sprite_f0_ti0_tr0_s0_d1, epic12_device::draw_sprite_f0_ti0_tr0_s1_d1, epic12_device::draw_sprite_f0_ti0_tr0_s2_d1, epic12_device::draw_sprite_f0_ti0_tr0_s3_d1, epic12_device::draw_sprite_f0_ti0_tr0_s4_d1, epic12_device::draw_sprite_f0_ti0_tr0_s5_d1, epic12_device::draw_sprite_f0_ti0_tr0_s6_d1, epic12_device::draw_sprite_f0_ti0_tr0_s7_d1, + epic12_device::draw_sprite_f0_ti0_tr0_s0_d2, epic12_device::draw_sprite_f0_ti0_tr0_s1_d2, epic12_device::draw_sprite_f0_ti0_tr0_s2_d2, epic12_device::draw_sprite_f0_ti0_tr0_s3_d2, epic12_device::draw_sprite_f0_ti0_tr0_s4_d2, epic12_device::draw_sprite_f0_ti0_tr0_s5_d2, epic12_device::draw_sprite_f0_ti0_tr0_s6_d2, epic12_device::draw_sprite_f0_ti0_tr0_s7_d2, + epic12_device::draw_sprite_f0_ti0_tr0_s0_d3, epic12_device::draw_sprite_f0_ti0_tr0_s1_d3, epic12_device::draw_sprite_f0_ti0_tr0_s2_d3, epic12_device::draw_sprite_f0_ti0_tr0_s3_d3, epic12_device::draw_sprite_f0_ti0_tr0_s4_d3, epic12_device::draw_sprite_f0_ti0_tr0_s5_d3, epic12_device::draw_sprite_f0_ti0_tr0_s6_d3, epic12_device::draw_sprite_f0_ti0_tr0_s7_d3, + epic12_device::draw_sprite_f0_ti0_tr0_s0_d4, epic12_device::draw_sprite_f0_ti0_tr0_s1_d4, epic12_device::draw_sprite_f0_ti0_tr0_s2_d4, epic12_device::draw_sprite_f0_ti0_tr0_s3_d4, epic12_device::draw_sprite_f0_ti0_tr0_s4_d4, epic12_device::draw_sprite_f0_ti0_tr0_s5_d4, epic12_device::draw_sprite_f0_ti0_tr0_s6_d4, epic12_device::draw_sprite_f0_ti0_tr0_s7_d4, + epic12_device::draw_sprite_f0_ti0_tr0_s0_d5, epic12_device::draw_sprite_f0_ti0_tr0_s1_d5, epic12_device::draw_sprite_f0_ti0_tr0_s2_d5, epic12_device::draw_sprite_f0_ti0_tr0_s3_d5, epic12_device::draw_sprite_f0_ti0_tr0_s4_d5, epic12_device::draw_sprite_f0_ti0_tr0_s5_d5, epic12_device::draw_sprite_f0_ti0_tr0_s6_d5, epic12_device::draw_sprite_f0_ti0_tr0_s7_d5, + epic12_device::draw_sprite_f0_ti0_tr0_s0_d6, epic12_device::draw_sprite_f0_ti0_tr0_s1_d6, epic12_device::draw_sprite_f0_ti0_tr0_s2_d6, epic12_device::draw_sprite_f0_ti0_tr0_s3_d6, epic12_device::draw_sprite_f0_ti0_tr0_s4_d6, epic12_device::draw_sprite_f0_ti0_tr0_s5_d6, epic12_device::draw_sprite_f0_ti0_tr0_s6_d6, epic12_device::draw_sprite_f0_ti0_tr0_s7_d6, + epic12_device::draw_sprite_f0_ti0_tr0_s0_d7, epic12_device::draw_sprite_f0_ti0_tr0_s1_d7, epic12_device::draw_sprite_f0_ti0_tr0_s2_d7, epic12_device::draw_sprite_f0_ti0_tr0_s3_d7, epic12_device::draw_sprite_f0_ti0_tr0_s4_d7, epic12_device::draw_sprite_f0_ti0_tr0_s5_d7, epic12_device::draw_sprite_f0_ti0_tr0_s6_d7, epic12_device::draw_sprite_f0_ti0_tr0_s7_d7, +}; + +epic12_device_blitfunction epic12_device_f1_ti0_tr1_blit_funcs[] = +{ + epic12_device::draw_sprite_f1_ti0_tr1_s0_d0, epic12_device::draw_sprite_f1_ti0_tr1_s1_d0, epic12_device::draw_sprite_f1_ti0_tr1_s2_d0, epic12_device::draw_sprite_f1_ti0_tr1_s3_d0, epic12_device::draw_sprite_f1_ti0_tr1_s4_d0, epic12_device::draw_sprite_f1_ti0_tr1_s5_d0, epic12_device::draw_sprite_f1_ti0_tr1_s6_d0, epic12_device::draw_sprite_f1_ti0_tr1_s7_d0, + epic12_device::draw_sprite_f1_ti0_tr1_s0_d1, epic12_device::draw_sprite_f1_ti0_tr1_s1_d1, epic12_device::draw_sprite_f1_ti0_tr1_s2_d1, epic12_device::draw_sprite_f1_ti0_tr1_s3_d1, epic12_device::draw_sprite_f1_ti0_tr1_s4_d1, epic12_device::draw_sprite_f1_ti0_tr1_s5_d1, epic12_device::draw_sprite_f1_ti0_tr1_s6_d1, epic12_device::draw_sprite_f1_ti0_tr1_s7_d1, + epic12_device::draw_sprite_f1_ti0_tr1_s0_d2, epic12_device::draw_sprite_f1_ti0_tr1_s1_d2, epic12_device::draw_sprite_f1_ti0_tr1_s2_d2, epic12_device::draw_sprite_f1_ti0_tr1_s3_d2, epic12_device::draw_sprite_f1_ti0_tr1_s4_d2, epic12_device::draw_sprite_f1_ti0_tr1_s5_d2, epic12_device::draw_sprite_f1_ti0_tr1_s6_d2, epic12_device::draw_sprite_f1_ti0_tr1_s7_d2, + epic12_device::draw_sprite_f1_ti0_tr1_s0_d3, epic12_device::draw_sprite_f1_ti0_tr1_s1_d3, epic12_device::draw_sprite_f1_ti0_tr1_s2_d3, epic12_device::draw_sprite_f1_ti0_tr1_s3_d3, epic12_device::draw_sprite_f1_ti0_tr1_s4_d3, epic12_device::draw_sprite_f1_ti0_tr1_s5_d3, epic12_device::draw_sprite_f1_ti0_tr1_s6_d3, epic12_device::draw_sprite_f1_ti0_tr1_s7_d3, + epic12_device::draw_sprite_f1_ti0_tr1_s0_d4, epic12_device::draw_sprite_f1_ti0_tr1_s1_d4, epic12_device::draw_sprite_f1_ti0_tr1_s2_d4, epic12_device::draw_sprite_f1_ti0_tr1_s3_d4, epic12_device::draw_sprite_f1_ti0_tr1_s4_d4, epic12_device::draw_sprite_f1_ti0_tr1_s5_d4, epic12_device::draw_sprite_f1_ti0_tr1_s6_d4, epic12_device::draw_sprite_f1_ti0_tr1_s7_d4, + epic12_device::draw_sprite_f1_ti0_tr1_s0_d5, epic12_device::draw_sprite_f1_ti0_tr1_s1_d5, epic12_device::draw_sprite_f1_ti0_tr1_s2_d5, epic12_device::draw_sprite_f1_ti0_tr1_s3_d5, epic12_device::draw_sprite_f1_ti0_tr1_s4_d5, epic12_device::draw_sprite_f1_ti0_tr1_s5_d5, epic12_device::draw_sprite_f1_ti0_tr1_s6_d5, epic12_device::draw_sprite_f1_ti0_tr1_s7_d5, + epic12_device::draw_sprite_f1_ti0_tr1_s0_d6, epic12_device::draw_sprite_f1_ti0_tr1_s1_d6, epic12_device::draw_sprite_f1_ti0_tr1_s2_d6, epic12_device::draw_sprite_f1_ti0_tr1_s3_d6, epic12_device::draw_sprite_f1_ti0_tr1_s4_d6, epic12_device::draw_sprite_f1_ti0_tr1_s5_d6, epic12_device::draw_sprite_f1_ti0_tr1_s6_d6, epic12_device::draw_sprite_f1_ti0_tr1_s7_d6, + epic12_device::draw_sprite_f1_ti0_tr1_s0_d7, epic12_device::draw_sprite_f1_ti0_tr1_s1_d7, epic12_device::draw_sprite_f1_ti0_tr1_s2_d7, epic12_device::draw_sprite_f1_ti0_tr1_s3_d7, epic12_device::draw_sprite_f1_ti0_tr1_s4_d7, epic12_device::draw_sprite_f1_ti0_tr1_s5_d7, epic12_device::draw_sprite_f1_ti0_tr1_s6_d7, epic12_device::draw_sprite_f1_ti0_tr1_s7_d7, +}; + +epic12_device_blitfunction epic12_device_f1_ti0_tr0_blit_funcs[] = +{ + epic12_device::draw_sprite_f1_ti0_tr0_s0_d0, epic12_device::draw_sprite_f1_ti0_tr0_s1_d0, epic12_device::draw_sprite_f1_ti0_tr0_s2_d0, epic12_device::draw_sprite_f1_ti0_tr0_s3_d0, epic12_device::draw_sprite_f1_ti0_tr0_s4_d0, epic12_device::draw_sprite_f1_ti0_tr0_s5_d0, epic12_device::draw_sprite_f1_ti0_tr0_s6_d0, epic12_device::draw_sprite_f1_ti0_tr0_s7_d0, + epic12_device::draw_sprite_f1_ti0_tr0_s0_d1, epic12_device::draw_sprite_f1_ti0_tr0_s1_d1, epic12_device::draw_sprite_f1_ti0_tr0_s2_d1, epic12_device::draw_sprite_f1_ti0_tr0_s3_d1, epic12_device::draw_sprite_f1_ti0_tr0_s4_d1, epic12_device::draw_sprite_f1_ti0_tr0_s5_d1, epic12_device::draw_sprite_f1_ti0_tr0_s6_d1, epic12_device::draw_sprite_f1_ti0_tr0_s7_d1, + epic12_device::draw_sprite_f1_ti0_tr0_s0_d2, epic12_device::draw_sprite_f1_ti0_tr0_s1_d2, epic12_device::draw_sprite_f1_ti0_tr0_s2_d2, epic12_device::draw_sprite_f1_ti0_tr0_s3_d2, epic12_device::draw_sprite_f1_ti0_tr0_s4_d2, epic12_device::draw_sprite_f1_ti0_tr0_s5_d2, epic12_device::draw_sprite_f1_ti0_tr0_s6_d2, epic12_device::draw_sprite_f1_ti0_tr0_s7_d2, + epic12_device::draw_sprite_f1_ti0_tr0_s0_d3, epic12_device::draw_sprite_f1_ti0_tr0_s1_d3, epic12_device::draw_sprite_f1_ti0_tr0_s2_d3, epic12_device::draw_sprite_f1_ti0_tr0_s3_d3, epic12_device::draw_sprite_f1_ti0_tr0_s4_d3, epic12_device::draw_sprite_f1_ti0_tr0_s5_d3, epic12_device::draw_sprite_f1_ti0_tr0_s6_d3, epic12_device::draw_sprite_f1_ti0_tr0_s7_d3, + epic12_device::draw_sprite_f1_ti0_tr0_s0_d4, epic12_device::draw_sprite_f1_ti0_tr0_s1_d4, epic12_device::draw_sprite_f1_ti0_tr0_s2_d4, epic12_device::draw_sprite_f1_ti0_tr0_s3_d4, epic12_device::draw_sprite_f1_ti0_tr0_s4_d4, epic12_device::draw_sprite_f1_ti0_tr0_s5_d4, epic12_device::draw_sprite_f1_ti0_tr0_s6_d4, epic12_device::draw_sprite_f1_ti0_tr0_s7_d4, + epic12_device::draw_sprite_f1_ti0_tr0_s0_d5, epic12_device::draw_sprite_f1_ti0_tr0_s1_d5, epic12_device::draw_sprite_f1_ti0_tr0_s2_d5, epic12_device::draw_sprite_f1_ti0_tr0_s3_d5, epic12_device::draw_sprite_f1_ti0_tr0_s4_d5, epic12_device::draw_sprite_f1_ti0_tr0_s5_d5, epic12_device::draw_sprite_f1_ti0_tr0_s6_d5, epic12_device::draw_sprite_f1_ti0_tr0_s7_d5, + epic12_device::draw_sprite_f1_ti0_tr0_s0_d6, epic12_device::draw_sprite_f1_ti0_tr0_s1_d6, epic12_device::draw_sprite_f1_ti0_tr0_s2_d6, epic12_device::draw_sprite_f1_ti0_tr0_s3_d6, epic12_device::draw_sprite_f1_ti0_tr0_s4_d6, epic12_device::draw_sprite_f1_ti0_tr0_s5_d6, epic12_device::draw_sprite_f1_ti0_tr0_s6_d6, epic12_device::draw_sprite_f1_ti0_tr0_s7_d6, + epic12_device::draw_sprite_f1_ti0_tr0_s0_d7, epic12_device::draw_sprite_f1_ti0_tr0_s1_d7, epic12_device::draw_sprite_f1_ti0_tr0_s2_d7, epic12_device::draw_sprite_f1_ti0_tr0_s3_d7, epic12_device::draw_sprite_f1_ti0_tr0_s4_d7, epic12_device::draw_sprite_f1_ti0_tr0_s5_d7, epic12_device::draw_sprite_f1_ti0_tr0_s6_d7, epic12_device::draw_sprite_f1_ti0_tr0_s7_d7, +}; + + + +inline void epic12_device::gfx_draw_shadow_copy(address_space &space, offs_t *addr) +{ + COPY_NEXT_WORD(space, addr); + COPY_NEXT_WORD(space, addr); + COPY_NEXT_WORD(space, addr); + COPY_NEXT_WORD(space, addr); + COPY_NEXT_WORD(space, addr); // UINT16 dst_x_start = COPY_NEXT_WORD(space, addr); + COPY_NEXT_WORD(space, addr); // UINT16 dst_y_start = COPY_NEXT_WORD(space, addr); + UINT16 w = COPY_NEXT_WORD(space, addr); + UINT16 h = COPY_NEXT_WORD(space, addr); + COPY_NEXT_WORD(space, addr); + COPY_NEXT_WORD(space, addr); + + + + // todo, calcualte clipping. + epic12_device_blit_delay += w*h; + +} + + + +inline void epic12_device::gfx_draw(offs_t *addr) +{ + int x,y, dimx,dimy, flipx,flipy;//, src_p; + int trans,blend, s_mode, d_mode; + clr_t tint_clr; + int tinted = 0; + + UINT16 attr = READ_NEXT_WORD(addr); + UINT16 alpha = READ_NEXT_WORD(addr); + UINT16 src_x = READ_NEXT_WORD(addr); + UINT16 src_y = READ_NEXT_WORD(addr); + UINT16 dst_x_start = READ_NEXT_WORD(addr); + UINT16 dst_y_start = READ_NEXT_WORD(addr); + UINT16 w = READ_NEXT_WORD(addr); + UINT16 h = READ_NEXT_WORD(addr); + UINT16 tint_r = READ_NEXT_WORD(addr); + UINT16 tint_gb = READ_NEXT_WORD(addr); + + // 0: +alpha + // 1: +source + // 2: +dest + // 3: * + // 4: -alpha + // 5: -source + // 6: -dest + // 7: * + + d_mode = attr & 0x0007; + s_mode = (attr & 0x0070) >> 4; + + trans = attr & 0x0100; + blend = attr & 0x0200; + + flipy = attr & 0x0400; + flipx = attr & 0x0800; + + const UINT8 d_alpha = ((alpha & 0x00ff) )>>3; + const UINT8 s_alpha = ((alpha & 0xff00) >> 8 )>>3; + +// src_p = 0; + src_x = src_x & 0x1fff; + src_y = src_y & 0x0fff; + + + x = (dst_x_start & 0x7fff) - (dst_x_start & 0x8000); + y = (dst_y_start & 0x7fff) - (dst_y_start & 0x8000); + + dimx = (w & 0x1fff) + 1; + dimy = (h & 0x0fff) + 1; + + // convert parameters to clr + + + tint_to_clr(tint_r & 0x00ff, (tint_gb >> 8) & 0xff, tint_gb & 0xff, &tint_clr); + + /* interestingly this gets set to 0x20 for 'normal' not 0x1f */ + + if (tint_clr.r!=0x20) + tinted = 1; + + if (tint_clr.g!=0x20) + tinted = 1; + + if (tint_clr.b!=0x20) + tinted = 1; + + + // surprisingly frequent, need to verify if it produces a worthwhile speedup tho. + if ((s_mode==0 && s_alpha==0x1f) && (d_mode==4 && d_alpha==0x1f)) + blend = 0; + + if (tinted) + { + if (!flipx) + { + if (trans) + { + if (!blend) + { + draw_sprite_f0_ti1_tr1_plain(draw_params); + } + else + { + epic12_device_f0_ti1_tr1_blit_funcs[s_mode | (d_mode<<3)](draw_params); + } + } + else + { + if (!blend) + { + draw_sprite_f0_ti1_tr0_plain(draw_params); + } + else + { + epic12_device_f0_ti1_tr0_blit_funcs[s_mode | (d_mode<<3)](draw_params); + } + } + } + else // flipx + { + if (trans) + { + if (!blend) + { + draw_sprite_f1_ti1_tr1_plain(draw_params); + } + else + { + epic12_device_f1_ti1_tr1_blit_funcs[s_mode | (d_mode<<3)](draw_params); + } + } + else + { + if (!blend) + { + draw_sprite_f1_ti1_tr0_plain(draw_params); + } + else + { + epic12_device_f1_ti1_tr0_blit_funcs[s_mode | (d_mode<<3)](draw_params); + } + } + } + } + else + { + if (blend==0 && tinted==0) + { + if (!flipx) + { + if (trans) + { + draw_sprite_f0_ti0_tr1_simple(draw_params); + } + else + { + draw_sprite_f0_ti0_tr0_simple(draw_params); + } + } + else + { + if (trans) + { + draw_sprite_f1_ti0_tr1_simple(draw_params); + } + else + { + draw_sprite_f1_ti0_tr0_simple(draw_params); + } + + } + + return; + } + + + + //printf("smode %d dmode %d\n", s_mode, d_mode); + + if (!flipx) + { + if (trans) + { + if (!blend) + { + draw_sprite_f0_ti0_plain(draw_params); + } + else + { + epic12_device_f0_ti0_tr1_blit_funcs[s_mode | (d_mode<<3)](draw_params); + } + } + else + { + if (!blend) + { + draw_sprite_f0_ti0_tr0_plain(draw_params); + } + else + { + epic12_device_f0_ti0_tr0_blit_funcs[s_mode | (d_mode<<3)](draw_params); + } + } + } + else // flipx + { + if (trans) + { + if (!blend) + { + draw_sprite_f1_ti0_plain(draw_params); + } + else + { + epic12_device_f1_ti0_tr1_blit_funcs[s_mode | (d_mode<<3)](draw_params); + } + } + else + { + if (!blend) + { + draw_sprite_f1_ti0_tr0_plain(draw_params); + } + else + { + epic12_device_f1_ti0_tr0_blit_funcs[s_mode | (d_mode<<3)](draw_params); + } + } + } + } + + + +} + + +void epic12_device::gfx_create_shadow_copy(address_space &space) +{ + offs_t addr = m_gfx_addr & 0x1fffffff; + m_clip.set(m_gfx_scroll_1_x_shadowcopy, m_gfx_scroll_1_x_shadowcopy + 320-1, m_gfx_scroll_1_y_shadowcopy, m_gfx_scroll_1_y_shadowcopy + 240-1); + + while (1) + { + UINT16 data = COPY_NEXT_WORD(space, &addr); + + switch( data & 0xf000 ) + { + case 0x0000: + case 0xf000: + return; + + case 0xc000: + if (COPY_NEXT_WORD(space, &addr)) // cliptype + m_clip.set(m_gfx_scroll_1_x_shadowcopy, m_gfx_scroll_1_x_shadowcopy + 320-1, m_gfx_scroll_1_y_shadowcopy, m_gfx_scroll_1_y_shadowcopy + 240-1); + else + m_clip.set(0, 0x2000-1, 0, 0x1000-1); + break; + + case 0x2000: + addr -= 2; + gfx_upload_shadow_copy(space, &addr); + break; + + case 0x1000: + addr -= 2; + gfx_draw_shadow_copy(space, &addr); + break; + + default: + popmessage("GFX op = %04X", data); + return; + } + } +} + + +void epic12_device::gfx_exec(void) +{ + offs_t addr = m_gfx_addr_shadowcopy & 0x1fffffff; + m_clip.set(m_gfx_scroll_1_x_shadowcopy, m_gfx_scroll_1_x_shadowcopy + 320-1, m_gfx_scroll_1_y_shadowcopy, m_gfx_scroll_1_y_shadowcopy + 240-1); + +// logerror("GFX EXEC: %08X\n", addr); + + while (1) + { + UINT16 data = READ_NEXT_WORD(&addr); + + switch( data & 0xf000 ) + { + case 0x0000: + case 0xf000: + return; + + case 0xc000: + if (READ_NEXT_WORD(&addr)) // cliptype + m_clip.set(m_gfx_scroll_1_x_shadowcopy, m_gfx_scroll_1_x_shadowcopy + 320-1, m_gfx_scroll_1_y_shadowcopy, m_gfx_scroll_1_y_shadowcopy + 240-1); + else + m_clip.set(0, 0x2000-1, 0, 0x1000-1); + break; + + case 0x2000: + addr -= 2; + gfx_upload(&addr); + break; + + case 0x1000: + addr -= 2; + gfx_draw(&addr); + break; + + default: + popmessage("GFX op = %04X", data); + return; + } + } +} + + +void epic12_device::gfx_exec_unsafe(void) +{ + offs_t addr = m_gfx_addr & 0x1fffffff; + m_clip.set(m_gfx_scroll_1_x, m_gfx_scroll_1_x + 320-1, m_gfx_scroll_1_y, m_gfx_scroll_1_y + 240-1); + +// logerror("GFX EXEC: %08X\n", addr); + + while (1) + { + UINT16 data = READ_NEXT_WORD(&addr); + + switch( data & 0xf000 ) + { + case 0x0000: + case 0xf000: + return; + + case 0xc000: + if (READ_NEXT_WORD(&addr)) // cliptype + m_clip.set(m_gfx_scroll_1_x, m_gfx_scroll_1_x + 320-1, m_gfx_scroll_1_y, m_gfx_scroll_1_y + 240-1); + else + m_clip.set(0, 0x2000-1, 0, 0x1000-1); + break; + + case 0x2000: + addr -= 2; + gfx_upload(&addr); + break; + + case 0x1000: + addr -= 2; + gfx_draw(&addr); + break; + + default: + popmessage("GFX op = %04X", data); + return; + } + } +} + + + +void *epic12_device::blit_request_callback(void *param, int threadid) +{ + epic12_device *object = reinterpret_cast(param); + + object->gfx_exec(); + return NULL; +} + + + +void *epic12_device::blit_request_callback_unsafe(void *param, int threadid) +{ + epic12_device *object = reinterpret_cast(param); + + epic12_device_blit_delay = 0; + object->gfx_exec_unsafe(); + return NULL; +} + + +READ32_MEMBER( epic12_device::gfx_ready_r ) +{ + return 0x00000010; +} + +READ32_MEMBER( epic12_device::gfx_ready_r_unsafe ) +{ + if (m_blitter_busy) + { + m_maincpu->spin_until_time(attotime::from_usec(10)); + return 0x00000000; + } + else + return 0x00000010; +} + +WRITE32_MEMBER( epic12_device::gfx_exec_w ) +{ + if ( ACCESSING_BITS_0_7 ) + { + if (data & 1) + { + //g_profiler.start(PROFILER_USER1); + // make sure we've not already got a request running + if (m_blitter_request) + { + int result; + do + { + result = osd_work_item_wait(m_blitter_request, 1000); + } while (result==0); + osd_work_item_release(m_blitter_request); + } + + epic12_device_blit_delay = 0; + gfx_create_shadow_copy(space); // create a copy of the blit list so we can safely thread it. + + if (epic12_device_blit_delay) + { + m_blitter_busy = 1; + m_blitter_delay_timer->adjust(attotime::from_nsec(epic12_device_blit_delay*8)); // NOT accurate timing (currently ignored anyway) + } + + m_gfx_addr_shadowcopy = m_gfx_addr; + m_gfx_scroll_0_x_shadowcopy = m_gfx_scroll_0_x; + m_gfx_scroll_0_y_shadowcopy = m_gfx_scroll_0_y; + m_gfx_scroll_1_x_shadowcopy = m_gfx_scroll_1_x; + m_gfx_scroll_1_y_shadowcopy = m_gfx_scroll_1_y; + m_blitter_request = osd_work_item_queue(m_work_queue, blit_request_callback, (void*)this, 0); + //g_profiler.stop(); + } + } +} + + +WRITE32_MEMBER( epic12_device::gfx_exec_w_unsafe ) +{ + if ( ACCESSING_BITS_0_7 ) + { + if (data & 1) + { + //g_profiler.start(PROFILER_USER1); + // make sure we've not already got a request running + if (m_blitter_request) + { + int result; + do + { + result = osd_work_item_wait(m_blitter_request, 1000); + } while (result==0); + osd_work_item_release(m_blitter_request); + } + + if (epic12_device_blit_delay) + { + m_blitter_busy = 1; + int delay = epic12_device_blit_delay*(15 * m_delay_scale / 50); + //printf("delay %d\n", delay); + m_blitter_delay_timer->adjust(attotime::from_nsec(delay)); + } + else + { + m_blitter_busy = 0; + } + + m_blitter_request = osd_work_item_queue(m_work_queue, blit_request_callback_unsafe, (void*)this, 0); + //g_profiler.stop(); + } + } +} + + +void epic12_device::draw_screen(bitmap_rgb32 &bitmap, const rectangle &cliprect ) +{ + if (!m_is_unsafe) + { + if (m_blitter_request) + { + int result; + do + { + result = osd_work_item_wait(m_blitter_request, 1000); + } while (result==0); + osd_work_item_release(m_blitter_request); + } + } + + int scroll_0_x, scroll_0_y; +// int scroll_1_x, scroll_1_y; + + bitmap.fill(0, cliprect); + + scroll_0_x = -m_gfx_scroll_0_x; + scroll_0_y = -m_gfx_scroll_0_y; +// scroll_1_x = -m_gfx_scroll_1_x; +// scroll_1_y = -m_gfx_scroll_1_y; + + //printf("SCREEN UPDATE\n %d %d %d %d\n", scroll_0_x, scroll_0_y, scroll_1_x, scroll_1_y); + + copyscrollbitmap(bitmap, *m_bitmaps, 1,&scroll_0_x, 1,&scroll_0_y, cliprect); +} + + + + + + +READ32_MEMBER( epic12_device::blitter_r ) +{ + switch (offset*4) + { + case 0x10: + return gfx_ready_r(space, offset, mem_mask); + + case 0x24: + return 0xffffffff; + + case 0x28: + return 0xffffffff; + + case 0x50: + return space.machine().root_device().ioport(":DSW")->read(); + + default: + logerror("unknownblitter_r %08x %08x\n", offset*4, mem_mask); + break; + + } + return 0; +} + +READ32_MEMBER( epic12_device::blitter_r_unsafe ) +{ + switch (offset*4) + { + case 0x10: + return gfx_ready_r_unsafe(space, offset, mem_mask); + + case 0x24: + return 0xffffffff; + + case 0x28: + return 0xffffffff; + + case 0x50: + return space.machine().root_device().ioport(":DSW")->read(); + + default: + logerror("unknownblitter_r %08x %08x\n", offset*4, mem_mask); + break; + + } + return 0; +} + + +WRITE32_MEMBER( epic12_device::blitter_w ) +{ + switch (offset*4) + { + case 0x04: + gfx_exec_w(space,offset,data,mem_mask); + break; + + case 0x08: + COMBINE_DATA(&m_gfx_addr); + break; + + case 0x14: + COMBINE_DATA(&m_gfx_scroll_0_x); + break; + + case 0x18: + COMBINE_DATA(&m_gfx_scroll_0_y); + break; + + case 0x40: + COMBINE_DATA(&m_gfx_scroll_1_x); + break; + + case 0x44: + COMBINE_DATA(&m_gfx_scroll_1_y); + break; + + } +} + +WRITE32_MEMBER( epic12_device::blitter_w_unsafe ) +{ + switch (offset*4) + { + case 0x04: + gfx_exec_w_unsafe(space,offset,data,mem_mask); + break; + + case 0x08: + COMBINE_DATA(&m_gfx_addr); + break; + + case 0x14: + COMBINE_DATA(&m_gfx_scroll_0_x); + break; + + case 0x18: + COMBINE_DATA(&m_gfx_scroll_0_y); + break; + + case 0x40: + COMBINE_DATA(&m_gfx_scroll_1_x); + break; + + case 0x44: + COMBINE_DATA(&m_gfx_scroll_1_y); + break; + + } +} + +void epic12_device::install_handlers(int addr1, int addr2) +{ + address_space &space = m_maincpu->space(AS_PROGRAM); + + read32_delegate read; + write32_delegate write; + + if (m_is_unsafe) + { + printf("using unsafe blit code!\n"); + read = read32_delegate(FUNC(epic12_device::blitter_r_unsafe), this); + write = write32_delegate(FUNC(epic12_device::blitter_w_unsafe), this); + } + else + { + read = read32_delegate(FUNC(epic12_device::blitter_r), this); + write = write32_delegate(FUNC(epic12_device::blitter_w), this); + } + + space.install_readwrite_handler(addr1, addr2, read , write, U64(0xffffffffffffffff)); +} + +READ64_MEMBER( epic12_device::fpga_r ) +{ + return 0xff; +} + +// todo, store what's written here and checksum it, different microcode probably leads to slightly different blitter timings +WRITE64_MEMBER( epic12_device::fpga_w ) +{ + if (ACCESSING_BITS_24_31) + { + // data & 0x08 = CE + // data & 0x10 = CLK + // data & 0x20 = DATA + } +} diff --git a/src/devices/video/epic12.h b/src/devices/video/epic12.h new file mode 100644 index 00000000000..42d4d3d2172 --- /dev/null +++ b/src/devices/video/epic12.h @@ -0,0 +1,840 @@ +// license:BSD-3-Clause +// copyright-holders:David Haywood, Luca Elia, MetalliC +/* emulation of Altera Cyclone EPIC12 FPGA programmed as a blitter */ + +#define MCFG_EPIC12_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, EPIC12, 0) + +#define MCFG_EPIC12_SET_MAINRAMSIZE( _rgn ) \ + epic12_device::set_mainramsize(*device, _rgn); + + +extern UINT8 epic12_device_colrtable[0x20][0x40]; +extern UINT8 epic12_device_colrtable_rev[0x20][0x40]; +extern UINT8 epic12_device_colrtable_add[0x20][0x20]; +extern UINT64 epic12_device_blit_delay; + +struct _clr_t +{ + UINT8 b,g,r,t; +}; + +typedef struct _clr_t clr_t; + +union colour_t +{ + clr_t trgb; + UINT32 u32; +}; + +typedef void (*epic12_device_blitfunction)(bitmap_rgb32 *, + const rectangle *, + UINT32 *, /* gfx */ + int , /* src_x */ + int , /* src_y */ + const int , /* dst_x_start */ + const int , /* dst_y_start */ + int , /* dimx */ + int , /* dimy */ + const int , /* flipy */ + const UINT8 , /* s_alpha */ + const UINT8 , /* d_alpha */ + //int , /* tint */ + const clr_t * ); + + +class epic12_device : public device_t, + public device_video_interface +{ +public: + epic12_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + void set_rambase(UINT16* rambase) { m_ram16 = rambase; } + void set_delay_scale(int delay_scale) { m_delay_scale = delay_scale; } + void set_is_unsafe(int is_unsafe) { m_is_unsafe = is_unsafe; } + void set_cpu_device(cpu_device* maincpu) { m_maincpu = maincpu; } + + inline UINT16 READ_NEXT_WORD(offs_t *addr); + + static void set_mainramsize(device_t &device, int ramsize) + { + epic12_device &dev = downcast(device); + dev.m_main_ramsize = ramsize; + dev.m_main_rammask = ramsize-1; + } + + static void *blit_request_callback(void *param, int threadid); + + DECLARE_READ64_MEMBER( fpga_r ); + DECLARE_WRITE64_MEMBER( fpga_w ); + + void draw_screen(bitmap_rgb32 &bitmap, const rectangle &cliprect); + + UINT16* m_ram16; + UINT32 m_gfx_addr; + UINT32 m_gfx_scroll_0_x, m_gfx_scroll_0_y; + UINT32 m_gfx_scroll_1_x, m_gfx_scroll_1_y; + + int m_gfx_size; + bitmap_rgb32 *m_bitmaps; + rectangle m_clip; + + UINT16* m_use_ram; + int m_main_ramsize; // type D has double the main ram + int m_main_rammask; + + int m_is_unsafe; + int m_delay_scale; + cpu_device* m_maincpu; + + void install_handlers(int addr1, int addr2); + + // thread safe mode, with no delays & shadow ram copy + DECLARE_READ32_MEMBER(blitter_r); + DECLARE_WRITE32_MEMBER(blitter_w); + UINT32 m_gfx_addr_shadowcopy; + UINT32 m_gfx_scroll_0_x_shadowcopy, m_gfx_scroll_0_y_shadowcopy; + UINT32 m_gfx_scroll_1_x_shadowcopy, m_gfx_scroll_1_y_shadowcopy; + UINT16* m_ram16_copy; + inline void gfx_upload_shadow_copy(address_space &space, offs_t *addr); + inline void gfx_create_shadow_copy(address_space &space); + inline UINT16 COPY_NEXT_WORD(address_space &space, offs_t *addr); + inline void gfx_draw_shadow_copy(address_space &space, offs_t *addr); + inline void gfx_upload(offs_t *addr); + inline void gfx_draw(offs_t *addr); + void gfx_exec(void); + DECLARE_READ32_MEMBER( gfx_ready_r ); + DECLARE_WRITE32_MEMBER( gfx_exec_w ); + + // for thread unsafe mode with blitter delays, no shadow copy of RAM + DECLARE_READ32_MEMBER(blitter_r_unsafe); + DECLARE_WRITE32_MEMBER(blitter_w_unsafe); + READ32_MEMBER( gfx_ready_r_unsafe ); + WRITE32_MEMBER( gfx_exec_w_unsafe ); + void gfx_exec_unsafe(void); + static void *blit_request_callback_unsafe(void *param, int threadid); + +#define BLIT_FUNCTION static void +#define BLIT_PARAMS bitmap_rgb32 *bitmap, const rectangle *clip, UINT32 *gfx, int src_x, int src_y, const int dst_x_start, const int dst_y_start, int dimx, int dimy, const int flipy, const UINT8 s_alpha, const UINT8 d_alpha, const clr_t *tint_clr + + BLIT_FUNCTION draw_sprite_f0_ti0_plain(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr1_s0_d0(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr1_s1_d0(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr1_s2_d0(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr1_s3_d0(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr1_s4_d0(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr1_s5_d0(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr1_s6_d0(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr1_s7_d0(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr1_s0_d1(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr1_s1_d1(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr1_s2_d1(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr1_s3_d1(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr1_s4_d1(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr1_s5_d1(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr1_s6_d1(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr1_s7_d1(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr1_s0_d2(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr1_s1_d2(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr1_s2_d2(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr1_s3_d2(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr1_s4_d2(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr1_s5_d2(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr1_s6_d2(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr1_s7_d2(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr1_s0_d3(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr1_s1_d3(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr1_s2_d3(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr1_s3_d3(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr1_s4_d3(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr1_s5_d3(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr1_s6_d3(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr1_s7_d3(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr1_s0_d4(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr1_s1_d4(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr1_s2_d4(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr1_s3_d4(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr1_s4_d4(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr1_s5_d4(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr1_s6_d4(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr1_s7_d4(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr1_s0_d5(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr1_s1_d5(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr1_s2_d5(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr1_s3_d5(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr1_s4_d5(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr1_s5_d5(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr1_s6_d5(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr1_s7_d5(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr1_s0_d6(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr1_s1_d6(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr1_s2_d6(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr1_s3_d6(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr1_s4_d6(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr1_s5_d6(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr1_s6_d6(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr1_s7_d6(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr1_s0_d7(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr1_s1_d7(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr1_s2_d7(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr1_s3_d7(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr1_s4_d7(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr1_s5_d7(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr1_s6_d7(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr1_s7_d7(BLIT_PARAMS); + + BLIT_FUNCTION draw_sprite_f0_ti0_tr0_plain(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr0_s0_d0(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr0_s1_d0(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr0_s2_d0(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr0_s3_d0(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr0_s4_d0(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr0_s5_d0(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr0_s6_d0(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr0_s7_d0(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr0_s0_d1(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr0_s1_d1(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr0_s2_d1(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr0_s3_d1(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr0_s4_d1(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr0_s5_d1(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr0_s6_d1(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr0_s7_d1(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr0_s0_d2(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr0_s1_d2(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr0_s2_d2(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr0_s3_d2(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr0_s4_d2(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr0_s5_d2(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr0_s6_d2(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr0_s7_d2(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr0_s0_d3(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr0_s1_d3(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr0_s2_d3(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr0_s3_d3(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr0_s4_d3(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr0_s5_d3(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr0_s6_d3(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr0_s7_d3(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr0_s0_d4(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr0_s1_d4(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr0_s2_d4(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr0_s3_d4(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr0_s4_d4(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr0_s5_d4(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr0_s6_d4(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr0_s7_d4(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr0_s0_d5(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr0_s1_d5(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr0_s2_d5(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr0_s3_d5(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr0_s4_d5(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr0_s5_d5(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr0_s6_d5(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr0_s7_d5(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr0_s0_d6(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr0_s1_d6(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr0_s2_d6(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr0_s3_d6(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr0_s4_d6(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr0_s5_d6(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr0_s6_d6(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr0_s7_d6(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr0_s0_d7(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr0_s1_d7(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr0_s2_d7(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr0_s3_d7(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr0_s4_d7(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr0_s5_d7(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr0_s6_d7(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr0_s7_d7(BLIT_PARAMS); + + BLIT_FUNCTION draw_sprite_f1_ti0_plain(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr1_s0_d0(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr1_s1_d0(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr1_s2_d0(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr1_s3_d0(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr1_s4_d0(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr1_s5_d0(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr1_s6_d0(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr1_s7_d0(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr1_s0_d1(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr1_s1_d1(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr1_s2_d1(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr1_s3_d1(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr1_s4_d1(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr1_s5_d1(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr1_s6_d1(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr1_s7_d1(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr1_s0_d2(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr1_s1_d2(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr1_s2_d2(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr1_s3_d2(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr1_s4_d2(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr1_s5_d2(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr1_s6_d2(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr1_s7_d2(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr1_s0_d3(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr1_s1_d3(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr1_s2_d3(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr1_s3_d3(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr1_s4_d3(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr1_s5_d3(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr1_s6_d3(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr1_s7_d3(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr1_s0_d4(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr1_s1_d4(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr1_s2_d4(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr1_s3_d4(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr1_s4_d4(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr1_s5_d4(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr1_s6_d4(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr1_s7_d4(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr1_s0_d5(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr1_s1_d5(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr1_s2_d5(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr1_s3_d5(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr1_s4_d5(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr1_s5_d5(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr1_s6_d5(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr1_s7_d5(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr1_s0_d6(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr1_s1_d6(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr1_s2_d6(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr1_s3_d6(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr1_s4_d6(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr1_s5_d6(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr1_s6_d6(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr1_s7_d6(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr1_s0_d7(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr1_s1_d7(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr1_s2_d7(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr1_s3_d7(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr1_s4_d7(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr1_s5_d7(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr1_s6_d7(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr1_s7_d7(BLIT_PARAMS); + + BLIT_FUNCTION draw_sprite_f1_ti0_tr0_plain(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr0_s0_d0(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr0_s1_d0(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr0_s2_d0(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr0_s3_d0(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr0_s4_d0(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr0_s5_d0(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr0_s6_d0(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr0_s7_d0(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr0_s0_d1(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr0_s1_d1(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr0_s2_d1(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr0_s3_d1(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr0_s4_d1(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr0_s5_d1(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr0_s6_d1(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr0_s7_d1(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr0_s0_d2(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr0_s1_d2(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr0_s2_d2(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr0_s3_d2(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr0_s4_d2(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr0_s5_d2(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr0_s6_d2(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr0_s7_d2(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr0_s0_d3(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr0_s1_d3(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr0_s2_d3(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr0_s3_d3(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr0_s4_d3(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr0_s5_d3(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr0_s6_d3(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr0_s7_d3(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr0_s0_d4(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr0_s1_d4(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr0_s2_d4(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr0_s3_d4(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr0_s4_d4(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr0_s5_d4(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr0_s6_d4(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr0_s7_d4(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr0_s0_d5(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr0_s1_d5(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr0_s2_d5(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr0_s3_d5(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr0_s4_d5(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr0_s5_d5(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr0_s6_d5(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr0_s7_d5(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr0_s0_d6(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr0_s1_d6(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr0_s2_d6(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr0_s3_d6(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr0_s4_d6(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr0_s5_d6(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr0_s6_d6(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr0_s7_d6(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr0_s0_d7(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr0_s1_d7(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr0_s2_d7(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr0_s3_d7(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr0_s4_d7(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr0_s5_d7(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr0_s6_d7(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr0_s7_d7(BLIT_PARAMS); + + BLIT_FUNCTION draw_sprite_f0_ti1_tr1_plain(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr1_s0_d0(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr1_s1_d0(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr1_s2_d0(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr1_s3_d0(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr1_s4_d0(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr1_s5_d0(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr1_s6_d0(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr1_s7_d0(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr1_s0_d1(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr1_s1_d1(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr1_s2_d1(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr1_s3_d1(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr1_s4_d1(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr1_s5_d1(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr1_s6_d1(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr1_s7_d1(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr1_s0_d2(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr1_s1_d2(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr1_s2_d2(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr1_s3_d2(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr1_s4_d2(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr1_s5_d2(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr1_s6_d2(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr1_s7_d2(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr1_s0_d3(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr1_s1_d3(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr1_s2_d3(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr1_s3_d3(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr1_s4_d3(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr1_s5_d3(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr1_s6_d3(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr1_s7_d3(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr1_s0_d4(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr1_s1_d4(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr1_s2_d4(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr1_s3_d4(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr1_s4_d4(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr1_s5_d4(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr1_s6_d4(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr1_s7_d4(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr1_s0_d5(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr1_s1_d5(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr1_s2_d5(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr1_s3_d5(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr1_s4_d5(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr1_s5_d5(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr1_s6_d5(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr1_s7_d5(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr1_s0_d6(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr1_s1_d6(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr1_s2_d6(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr1_s3_d6(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr1_s4_d6(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr1_s5_d6(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr1_s6_d6(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr1_s7_d6(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr1_s0_d7(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr1_s1_d7(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr1_s2_d7(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr1_s3_d7(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr1_s4_d7(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr1_s5_d7(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr1_s6_d7(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr1_s7_d7(BLIT_PARAMS); + + BLIT_FUNCTION draw_sprite_f0_ti1_tr0_plain(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr0_s0_d0(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr0_s1_d0(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr0_s2_d0(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr0_s3_d0(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr0_s4_d0(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr0_s5_d0(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr0_s6_d0(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr0_s7_d0(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr0_s0_d1(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr0_s1_d1(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr0_s2_d1(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr0_s3_d1(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr0_s4_d1(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr0_s5_d1(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr0_s6_d1(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr0_s7_d1(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr0_s0_d2(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr0_s1_d2(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr0_s2_d2(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr0_s3_d2(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr0_s4_d2(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr0_s5_d2(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr0_s6_d2(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr0_s7_d2(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr0_s0_d3(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr0_s1_d3(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr0_s2_d3(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr0_s3_d3(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr0_s4_d3(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr0_s5_d3(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr0_s6_d3(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr0_s7_d3(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr0_s0_d4(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr0_s1_d4(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr0_s2_d4(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr0_s3_d4(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr0_s4_d4(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr0_s5_d4(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr0_s6_d4(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr0_s7_d4(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr0_s0_d5(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr0_s1_d5(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr0_s2_d5(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr0_s3_d5(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr0_s4_d5(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr0_s5_d5(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr0_s6_d5(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr0_s7_d5(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr0_s0_d6(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr0_s1_d6(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr0_s2_d6(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr0_s3_d6(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr0_s4_d6(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr0_s5_d6(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr0_s6_d6(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr0_s7_d6(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr0_s0_d7(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr0_s1_d7(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr0_s2_d7(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr0_s3_d7(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr0_s4_d7(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr0_s5_d7(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr0_s6_d7(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti1_tr0_s7_d7(BLIT_PARAMS); + + BLIT_FUNCTION draw_sprite_f1_ti1_tr1_plain(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr1_s0_d0(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr1_s1_d0(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr1_s2_d0(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr1_s3_d0(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr1_s4_d0(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr1_s5_d0(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr1_s6_d0(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr1_s7_d0(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr1_s0_d1(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr1_s1_d1(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr1_s2_d1(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr1_s3_d1(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr1_s4_d1(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr1_s5_d1(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr1_s6_d1(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr1_s7_d1(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr1_s0_d2(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr1_s1_d2(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr1_s2_d2(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr1_s3_d2(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr1_s4_d2(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr1_s5_d2(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr1_s6_d2(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr1_s7_d2(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr1_s0_d3(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr1_s1_d3(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr1_s2_d3(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr1_s3_d3(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr1_s4_d3(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr1_s5_d3(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr1_s6_d3(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr1_s7_d3(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr1_s0_d4(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr1_s1_d4(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr1_s2_d4(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr1_s3_d4(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr1_s4_d4(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr1_s5_d4(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr1_s6_d4(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr1_s7_d4(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr1_s0_d5(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr1_s1_d5(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr1_s2_d5(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr1_s3_d5(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr1_s4_d5(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr1_s5_d5(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr1_s6_d5(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr1_s7_d5(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr1_s0_d6(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr1_s1_d6(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr1_s2_d6(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr1_s3_d6(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr1_s4_d6(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr1_s5_d6(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr1_s6_d6(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr1_s7_d6(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr1_s0_d7(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr1_s1_d7(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr1_s2_d7(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr1_s3_d7(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr1_s4_d7(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr1_s5_d7(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr1_s6_d7(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr1_s7_d7(BLIT_PARAMS); + + BLIT_FUNCTION draw_sprite_f1_ti1_tr0_plain(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr0_s0_d0(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr0_s1_d0(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr0_s2_d0(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr0_s3_d0(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr0_s4_d0(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr0_s5_d0(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr0_s6_d0(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr0_s7_d0(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr0_s0_d1(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr0_s1_d1(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr0_s2_d1(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr0_s3_d1(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr0_s4_d1(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr0_s5_d1(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr0_s6_d1(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr0_s7_d1(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr0_s0_d2(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr0_s1_d2(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr0_s2_d2(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr0_s3_d2(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr0_s4_d2(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr0_s5_d2(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr0_s6_d2(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr0_s7_d2(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr0_s0_d3(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr0_s1_d3(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr0_s2_d3(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr0_s3_d3(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr0_s4_d3(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr0_s5_d3(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr0_s6_d3(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr0_s7_d3(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr0_s0_d4(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr0_s1_d4(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr0_s2_d4(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr0_s3_d4(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr0_s4_d4(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr0_s5_d4(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr0_s6_d4(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr0_s7_d4(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr0_s0_d5(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr0_s1_d5(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr0_s2_d5(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr0_s3_d5(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr0_s4_d5(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr0_s5_d5(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr0_s6_d5(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr0_s7_d5(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr0_s0_d6(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr0_s1_d6(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr0_s2_d6(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr0_s3_d6(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr0_s4_d6(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr0_s5_d6(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr0_s6_d6(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr0_s7_d6(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr0_s0_d7(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr0_s1_d7(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr0_s2_d7(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr0_s3_d7(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr0_s4_d7(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr0_s5_d7(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr0_s6_d7(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti1_tr0_s7_d7(BLIT_PARAMS); + + BLIT_FUNCTION draw_sprite_f0_ti0_tr1_simple(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f0_ti0_tr0_simple(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr1_simple(BLIT_PARAMS); + BLIT_FUNCTION draw_sprite_f1_ti0_tr0_simple(BLIT_PARAMS); + + + + static inline void pen_to_clr(UINT32 pen, clr_t *clr) + { + // --t- ---- rrrr r--- gggg g--- bbbb b--- format + clr->r = (pen >> (16+3));// & 0x1f; + clr->g = (pen >> (8+3));// & 0x1f; + clr->b = (pen >> 3);// & 0x1f; + + // --t- ---- ---r rrrr ---g gggg ---b bbbb format + // clr->r = (pen >> 16) & 0x1f; + // clr->g = (pen >> 8) & 0x1f; + // clr->b = (pen >> 0) & 0x1f; + + }; + + + // convert separate r,g,b biases (0..80..ff) to clr_t (-1f..0..1f) + static inline void tint_to_clr(UINT8 r, UINT8 g, UINT8 b, clr_t *clr) + { + clr->r = r>>2; + clr->g = g>>2; + clr->b = b>>2; + }; + + // clr_t to r5g5b5 + static inline UINT32 clr_to_pen(const clr_t *clr) + { + // --t- ---- rrrr r--- gggg g--- bbbb b--- format + return (clr->r << (16+3)) | (clr->g << (8+3)) | (clr->b << 3); + + // --t- ---- ---r rrrr ---g gggg ---b bbbb format + // return (clr->r << (16)) | (clr->g << (8)) | (clr->b); + }; + + + static inline void clr_add_with_clr_mul_fixed(clr_t *clr, const clr_t *clr0, const UINT8 mulfixed_val, const clr_t *mulfixed_clr0) + { + clr->r = epic12_device_colrtable_add[clr0->r][epic12_device_colrtable[(mulfixed_clr0->r)][mulfixed_val]]; + clr->g = epic12_device_colrtable_add[clr0->g][epic12_device_colrtable[(mulfixed_clr0->g)][mulfixed_val]]; + clr->b = epic12_device_colrtable_add[clr0->b][epic12_device_colrtable[(mulfixed_clr0->b)][mulfixed_val]]; + } + + static inline void clr_add_with_clr_mul_3param(clr_t *clr, const clr_t *clr0, const clr_t *clr1, const clr_t *clr2) + { + clr->r = epic12_device_colrtable_add[clr0->r][epic12_device_colrtable[(clr2->r)][(clr1->r)]]; + clr->g = epic12_device_colrtable_add[clr0->g][epic12_device_colrtable[(clr2->g)][(clr1->g)]]; + clr->b = epic12_device_colrtable_add[clr0->b][epic12_device_colrtable[(clr2->b)][(clr1->b)]]; + } + + static inline void clr_add_with_clr_square(clr_t *clr, const clr_t *clr0, const clr_t *clr1) + { + clr->r = epic12_device_colrtable_add[clr0->r][epic12_device_colrtable[(clr1->r)][(clr1->r)]]; + clr->g = epic12_device_colrtable_add[clr0->r][epic12_device_colrtable[(clr1->g)][(clr1->g)]]; + clr->b = epic12_device_colrtable_add[clr0->r][epic12_device_colrtable[(clr1->b)][(clr1->b)]]; + } + + static inline void clr_add_with_clr_mul_fixed_rev(clr_t *clr, const clr_t *clr0, const UINT8 val, const clr_t *clr1) + { + clr->r = epic12_device_colrtable_add[clr0->r][epic12_device_colrtable_rev[val][(clr1->r)]]; + clr->g = epic12_device_colrtable_add[clr0->g][epic12_device_colrtable_rev[val][(clr1->g)]]; + clr->b = epic12_device_colrtable_add[clr0->b][epic12_device_colrtable_rev[val][(clr1->b)]]; + } + + static inline void clr_add_with_clr_mul_rev_3param(clr_t *clr, const clr_t *clr0, const clr_t *clr1, const clr_t *clr2) + { + clr->r = epic12_device_colrtable_add[clr0->r][epic12_device_colrtable_rev[(clr2->r)][(clr1->r)]]; + clr->g = epic12_device_colrtable_add[clr0->g][epic12_device_colrtable_rev[(clr2->g)][(clr1->g)]]; + clr->b = epic12_device_colrtable_add[clr0->b][epic12_device_colrtable_rev[(clr2->b)][(clr1->b)]]; + } + + static inline void clr_add_with_clr_mul_rev_square(clr_t *clr, const clr_t *clr0, const clr_t *clr1) + { + clr->r = epic12_device_colrtable_add[clr0->r][epic12_device_colrtable_rev[(clr1->r)][(clr1->r)]]; + clr->g = epic12_device_colrtable_add[clr0->g][epic12_device_colrtable_rev[(clr1->g)][(clr1->g)]]; + clr->b = epic12_device_colrtable_add[clr0->b][epic12_device_colrtable_rev[(clr1->b)][(clr1->b)]]; + } + + + static inline void clr_add(clr_t *clr, const clr_t *clr0, const clr_t *clr1) + { + /* + clr->r = clr0->r + clr1->r; + clr->g = clr0->g + clr1->g; + clr->b = clr0->b + clr1->b; + */ + // use pre-clamped lookup table + clr->r = epic12_device_colrtable_add[clr0->r][clr1->r]; + clr->g = epic12_device_colrtable_add[clr0->g][clr1->g]; + clr->b = epic12_device_colrtable_add[clr0->b][clr1->b]; + + } + + + static inline void clr_mul(clr_t *clr0, const clr_t *clr1) + { + clr0->r = epic12_device_colrtable[(clr0->r)][(clr1->r)]; + clr0->g = epic12_device_colrtable[(clr0->g)][(clr1->g)]; + clr0->b = epic12_device_colrtable[(clr0->b)][(clr1->b)]; + } + + static inline void clr_square(clr_t *clr0, const clr_t *clr1) + { + clr0->r = epic12_device_colrtable[(clr1->r)][(clr1->r)]; + clr0->g = epic12_device_colrtable[(clr1->g)][(clr1->g)]; + clr0->b = epic12_device_colrtable[(clr1->b)][(clr1->b)]; + } + + static inline void clr_mul_3param(clr_t *clr0, const clr_t *clr1, const clr_t *clr2) + { + clr0->r = epic12_device_colrtable[(clr2->r)][(clr1->r)]; + clr0->g = epic12_device_colrtable[(clr2->g)][(clr1->g)]; + clr0->b = epic12_device_colrtable[(clr2->b)][(clr1->b)]; + } + + static inline void clr_mul_rev(clr_t *clr0, const clr_t *clr1) + { + clr0->r = epic12_device_colrtable_rev[(clr0->r)][(clr1->r)]; + clr0->g = epic12_device_colrtable_rev[(clr0->g)][(clr1->g)]; + clr0->b = epic12_device_colrtable_rev[(clr0->b)][(clr1->b)]; + } + + static inline void clr_mul_rev_square(clr_t *clr0, const clr_t *clr1) + { + clr0->r = epic12_device_colrtable_rev[(clr1->r)][(clr1->r)]; + clr0->g = epic12_device_colrtable_rev[(clr1->g)][(clr1->g)]; + clr0->b = epic12_device_colrtable_rev[(clr1->b)][(clr1->b)]; + } + + + static inline void clr_mul_rev_3param(clr_t *clr0, const clr_t *clr1, const clr_t *clr2) + { + clr0->r = epic12_device_colrtable_rev[(clr2->r)][(clr1->r)]; + clr0->g = epic12_device_colrtable_rev[(clr2->g)][(clr1->g)]; + clr0->b = epic12_device_colrtable_rev[(clr2->b)][(clr1->b)]; + } + + static inline void clr_mul_fixed(clr_t *clr, const UINT8 val, const clr_t *clr0) + { + clr->r = epic12_device_colrtable[val][(clr0->r)]; + clr->g = epic12_device_colrtable[val][(clr0->g)]; + clr->b = epic12_device_colrtable[val][(clr0->b)]; + } + + static inline void clr_mul_fixed_rev(clr_t *clr, const UINT8 val, const clr_t *clr0) + { + clr->r = epic12_device_colrtable_rev[val][(clr0->r)]; + clr->g = epic12_device_colrtable_rev[val][(clr0->g)]; + clr->b = epic12_device_colrtable_rev[val][(clr0->b)]; + } + + static inline void clr_copy(clr_t *clr, const clr_t *clr0) + { + clr->r = clr0->r; + clr->g = clr0->g; + clr->b = clr0->b; + } + + + + // (1|s|d) * s_factor * s + (1|s|d) * d_factor * d + // 0: +alpha + // 1: +source + // 2: +dest + // 3: * + // 4: -alpha + // 5: -source + // 6: -dest + // 7: * + + +protected: + virtual void device_start(); + virtual void device_reset(); + + osd_work_queue *m_work_queue; + osd_work_item *m_blitter_request; + + // blit timing + emu_timer *m_blitter_delay_timer; + int m_blitter_busy; + + TIMER_CALLBACK_MEMBER( blitter_delay_callback ); +}; + + + +extern const device_type EPIC12; diff --git a/src/devices/video/epic12_blit0.c b/src/devices/video/epic12_blit0.c new file mode 100644 index 00000000000..3588573bdee --- /dev/null +++ b/src/devices/video/epic12_blit0.c @@ -0,0 +1,558 @@ +// license:BSD-3-Clause +// copyright-holders:David Haywood +#define REALLY_SIMPLE 0 +/* Non-Flipped, Non-Tinted, Transparent */ +#define FLIPX 0 +#define TINT 0 +#define TRANSPARENT 1 + +#include "emu.h" +#include "epic12.h" + +/* Special Case */ +#define BLENDED 0 +#define FUNCNAME draw_sprite_f0_ti0_plain +#include "epic12in.inc" +#undef FUNCNAME +#undef BLENDED + +/* Regular Cases*/ +#define BLENDED 1 + +#define _SMODE 0 +#define _DMODE 0 +#define FUNCNAME draw_sprite_f0_ti0_tr1_s0_d0 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 1 +#define _DMODE 0 +#define FUNCNAME draw_sprite_f0_ti0_tr1_s1_d0 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 2 +#define _DMODE 0 +#define FUNCNAME draw_sprite_f0_ti0_tr1_s2_d0 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 3 +#define _DMODE 0 +#define FUNCNAME draw_sprite_f0_ti0_tr1_s3_d0 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 4 +#define _DMODE 0 +#define FUNCNAME draw_sprite_f0_ti0_tr1_s4_d0 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 5 +#define _DMODE 0 +#define FUNCNAME draw_sprite_f0_ti0_tr1_s5_d0 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 6 +#define _DMODE 0 +#define FUNCNAME draw_sprite_f0_ti0_tr1_s6_d0 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 7 +#define _DMODE 0 +#define FUNCNAME draw_sprite_f0_ti0_tr1_s7_d0 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +/////// + + +#define _SMODE 0 +#define _DMODE 1 +#define FUNCNAME draw_sprite_f0_ti0_tr1_s0_d1 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 1 +#define _DMODE 1 +#define FUNCNAME draw_sprite_f0_ti0_tr1_s1_d1 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 2 +#define _DMODE 1 +#define FUNCNAME draw_sprite_f0_ti0_tr1_s2_d1 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 3 +#define _DMODE 1 +#define FUNCNAME draw_sprite_f0_ti0_tr1_s3_d1 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 4 +#define _DMODE 1 +#define FUNCNAME draw_sprite_f0_ti0_tr1_s4_d1 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 5 +#define _DMODE 1 +#define FUNCNAME draw_sprite_f0_ti0_tr1_s5_d1 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 6 +#define _DMODE 1 +#define FUNCNAME draw_sprite_f0_ti0_tr1_s6_d1 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 7 +#define _DMODE 1 +#define FUNCNAME draw_sprite_f0_ti0_tr1_s7_d1 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +//// + + +#define _SMODE 0 +#define _DMODE 2 +#define FUNCNAME draw_sprite_f0_ti0_tr1_s0_d2 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 1 +#define _DMODE 2 +#define FUNCNAME draw_sprite_f0_ti0_tr1_s1_d2 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 2 +#define _DMODE 2 +#define FUNCNAME draw_sprite_f0_ti0_tr1_s2_d2 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 3 +#define _DMODE 2 +#define FUNCNAME draw_sprite_f0_ti0_tr1_s3_d2 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 4 +#define _DMODE 2 +#define FUNCNAME draw_sprite_f0_ti0_tr1_s4_d2 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 5 +#define _DMODE 2 +#define FUNCNAME draw_sprite_f0_ti0_tr1_s5_d2 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 6 +#define _DMODE 2 +#define FUNCNAME draw_sprite_f0_ti0_tr1_s6_d2 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 7 +#define _DMODE 2 +#define FUNCNAME draw_sprite_f0_ti0_tr1_s7_d2 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +/// + + +#define _SMODE 0 +#define _DMODE 3 +#define FUNCNAME draw_sprite_f0_ti0_tr1_s0_d3 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 1 +#define _DMODE 3 +#define FUNCNAME draw_sprite_f0_ti0_tr1_s1_d3 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 2 +#define _DMODE 3 +#define FUNCNAME draw_sprite_f0_ti0_tr1_s2_d3 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 3 +#define _DMODE 3 +#define FUNCNAME draw_sprite_f0_ti0_tr1_s3_d3 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 4 +#define _DMODE 3 +#define FUNCNAME draw_sprite_f0_ti0_tr1_s4_d3 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 5 +#define _DMODE 3 +#define FUNCNAME draw_sprite_f0_ti0_tr1_s5_d3 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 6 +#define _DMODE 3 +#define FUNCNAME draw_sprite_f0_ti0_tr1_s6_d3 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 7 +#define _DMODE 3 +#define FUNCNAME draw_sprite_f0_ti0_tr1_s7_d3 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +/// + + +#define _SMODE 0 +#define _DMODE 4 +#define FUNCNAME draw_sprite_f0_ti0_tr1_s0_d4 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 1 +#define _DMODE 4 +#define FUNCNAME draw_sprite_f0_ti0_tr1_s1_d4 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 2 +#define _DMODE 4 +#define FUNCNAME draw_sprite_f0_ti0_tr1_s2_d4 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 3 +#define _DMODE 4 +#define FUNCNAME draw_sprite_f0_ti0_tr1_s3_d4 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 4 +#define _DMODE 4 +#define FUNCNAME draw_sprite_f0_ti0_tr1_s4_d4 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 5 +#define _DMODE 4 +#define FUNCNAME draw_sprite_f0_ti0_tr1_s5_d4 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 6 +#define _DMODE 4 +#define FUNCNAME draw_sprite_f0_ti0_tr1_s6_d4 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 7 +#define _DMODE 4 +#define FUNCNAME draw_sprite_f0_ti0_tr1_s7_d4 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +/// + +#define _SMODE 0 +#define _DMODE 5 +#define FUNCNAME draw_sprite_f0_ti0_tr1_s0_d5 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 1 +#define _DMODE 5 +#define FUNCNAME draw_sprite_f0_ti0_tr1_s1_d5 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 2 +#define _DMODE 5 +#define FUNCNAME draw_sprite_f0_ti0_tr1_s2_d5 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 3 +#define _DMODE 5 +#define FUNCNAME draw_sprite_f0_ti0_tr1_s3_d5 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 4 +#define _DMODE 5 +#define FUNCNAME draw_sprite_f0_ti0_tr1_s4_d5 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 5 +#define _DMODE 5 +#define FUNCNAME draw_sprite_f0_ti0_tr1_s5_d5 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 6 +#define _DMODE 5 +#define FUNCNAME draw_sprite_f0_ti0_tr1_s6_d5 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 7 +#define _DMODE 5 +#define FUNCNAME draw_sprite_f0_ti0_tr1_s7_d5 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +/// + +#define _SMODE 0 +#define _DMODE 6 +#define FUNCNAME draw_sprite_f0_ti0_tr1_s0_d6 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 1 +#define _DMODE 6 +#define FUNCNAME draw_sprite_f0_ti0_tr1_s1_d6 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 2 +#define _DMODE 6 +#define FUNCNAME draw_sprite_f0_ti0_tr1_s2_d6 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 3 +#define _DMODE 6 +#define FUNCNAME draw_sprite_f0_ti0_tr1_s3_d6 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 4 +#define _DMODE 6 +#define FUNCNAME draw_sprite_f0_ti0_tr1_s4_d6 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 5 +#define _DMODE 6 +#define FUNCNAME draw_sprite_f0_ti0_tr1_s5_d6 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 6 +#define _DMODE 6 +#define FUNCNAME draw_sprite_f0_ti0_tr1_s6_d6 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 7 +#define _DMODE 6 +#define FUNCNAME draw_sprite_f0_ti0_tr1_s7_d6 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +/// + + +#define _SMODE 0 +#define _DMODE 7 +#define FUNCNAME draw_sprite_f0_ti0_tr1_s0_d7 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 1 +#define _DMODE 7 +#define FUNCNAME draw_sprite_f0_ti0_tr1_s1_d7 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 2 +#define _DMODE 7 +#define FUNCNAME draw_sprite_f0_ti0_tr1_s2_d7 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 3 +#define _DMODE 7 +#define FUNCNAME draw_sprite_f0_ti0_tr1_s3_d7 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 4 +#define _DMODE 7 +#define FUNCNAME draw_sprite_f0_ti0_tr1_s4_d7 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 5 +#define _DMODE 7 +#define FUNCNAME draw_sprite_f0_ti0_tr1_s5_d7 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 6 +#define _DMODE 7 +#define FUNCNAME draw_sprite_f0_ti0_tr1_s6_d7 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 7 +#define _DMODE 7 +#define FUNCNAME draw_sprite_f0_ti0_tr1_s7_d7 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#undef BLENDED + +#undef FLIPX +#undef TINT +#undef TRANSPARENT +#undef REALLY_SIMPLE diff --git a/src/devices/video/epic12_blit1.c b/src/devices/video/epic12_blit1.c new file mode 100644 index 00000000000..2cef4fae933 --- /dev/null +++ b/src/devices/video/epic12_blit1.c @@ -0,0 +1,558 @@ +// license:BSD-3-Clause +// copyright-holders:David Haywood +#define REALLY_SIMPLE 0 +/* Non-Flipped, Non-Tinted, Non-Transparent */ +#define FLIPX 0 +#define TINT 0 +#define TRANSPARENT 0 + +#include "emu.h" +#include "epic12.h" + +/* Special Case */ +#define BLENDED 0 +#define FUNCNAME draw_sprite_f0_ti0_tr0_plain +#include "epic12in.inc" +#undef FUNCNAME +#undef BLENDED + +/* Regular Cases*/ +#define BLENDED 1 + +#define _SMODE 0 +#define _DMODE 0 +#define FUNCNAME draw_sprite_f0_ti0_tr0_s0_d0 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 1 +#define _DMODE 0 +#define FUNCNAME draw_sprite_f0_ti0_tr0_s1_d0 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 2 +#define _DMODE 0 +#define FUNCNAME draw_sprite_f0_ti0_tr0_s2_d0 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 3 +#define _DMODE 0 +#define FUNCNAME draw_sprite_f0_ti0_tr0_s3_d0 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 4 +#define _DMODE 0 +#define FUNCNAME draw_sprite_f0_ti0_tr0_s4_d0 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 5 +#define _DMODE 0 +#define FUNCNAME draw_sprite_f0_ti0_tr0_s5_d0 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 6 +#define _DMODE 0 +#define FUNCNAME draw_sprite_f0_ti0_tr0_s6_d0 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 7 +#define _DMODE 0 +#define FUNCNAME draw_sprite_f0_ti0_tr0_s7_d0 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +/////// + + +#define _SMODE 0 +#define _DMODE 1 +#define FUNCNAME draw_sprite_f0_ti0_tr0_s0_d1 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 1 +#define _DMODE 1 +#define FUNCNAME draw_sprite_f0_ti0_tr0_s1_d1 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 2 +#define _DMODE 1 +#define FUNCNAME draw_sprite_f0_ti0_tr0_s2_d1 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 3 +#define _DMODE 1 +#define FUNCNAME draw_sprite_f0_ti0_tr0_s3_d1 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 4 +#define _DMODE 1 +#define FUNCNAME draw_sprite_f0_ti0_tr0_s4_d1 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 5 +#define _DMODE 1 +#define FUNCNAME draw_sprite_f0_ti0_tr0_s5_d1 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 6 +#define _DMODE 1 +#define FUNCNAME draw_sprite_f0_ti0_tr0_s6_d1 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 7 +#define _DMODE 1 +#define FUNCNAME draw_sprite_f0_ti0_tr0_s7_d1 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +//// + + +#define _SMODE 0 +#define _DMODE 2 +#define FUNCNAME draw_sprite_f0_ti0_tr0_s0_d2 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 1 +#define _DMODE 2 +#define FUNCNAME draw_sprite_f0_ti0_tr0_s1_d2 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 2 +#define _DMODE 2 +#define FUNCNAME draw_sprite_f0_ti0_tr0_s2_d2 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 3 +#define _DMODE 2 +#define FUNCNAME draw_sprite_f0_ti0_tr0_s3_d2 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 4 +#define _DMODE 2 +#define FUNCNAME draw_sprite_f0_ti0_tr0_s4_d2 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 5 +#define _DMODE 2 +#define FUNCNAME draw_sprite_f0_ti0_tr0_s5_d2 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 6 +#define _DMODE 2 +#define FUNCNAME draw_sprite_f0_ti0_tr0_s6_d2 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 7 +#define _DMODE 2 +#define FUNCNAME draw_sprite_f0_ti0_tr0_s7_d2 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +/// + + +#define _SMODE 0 +#define _DMODE 3 +#define FUNCNAME draw_sprite_f0_ti0_tr0_s0_d3 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 1 +#define _DMODE 3 +#define FUNCNAME draw_sprite_f0_ti0_tr0_s1_d3 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 2 +#define _DMODE 3 +#define FUNCNAME draw_sprite_f0_ti0_tr0_s2_d3 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 3 +#define _DMODE 3 +#define FUNCNAME draw_sprite_f0_ti0_tr0_s3_d3 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 4 +#define _DMODE 3 +#define FUNCNAME draw_sprite_f0_ti0_tr0_s4_d3 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 5 +#define _DMODE 3 +#define FUNCNAME draw_sprite_f0_ti0_tr0_s5_d3 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 6 +#define _DMODE 3 +#define FUNCNAME draw_sprite_f0_ti0_tr0_s6_d3 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 7 +#define _DMODE 3 +#define FUNCNAME draw_sprite_f0_ti0_tr0_s7_d3 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +/// + + +#define _SMODE 0 +#define _DMODE 4 +#define FUNCNAME draw_sprite_f0_ti0_tr0_s0_d4 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 1 +#define _DMODE 4 +#define FUNCNAME draw_sprite_f0_ti0_tr0_s1_d4 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 2 +#define _DMODE 4 +#define FUNCNAME draw_sprite_f0_ti0_tr0_s2_d4 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 3 +#define _DMODE 4 +#define FUNCNAME draw_sprite_f0_ti0_tr0_s3_d4 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 4 +#define _DMODE 4 +#define FUNCNAME draw_sprite_f0_ti0_tr0_s4_d4 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 5 +#define _DMODE 4 +#define FUNCNAME draw_sprite_f0_ti0_tr0_s5_d4 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 6 +#define _DMODE 4 +#define FUNCNAME draw_sprite_f0_ti0_tr0_s6_d4 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 7 +#define _DMODE 4 +#define FUNCNAME draw_sprite_f0_ti0_tr0_s7_d4 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +/// + +#define _SMODE 0 +#define _DMODE 5 +#define FUNCNAME draw_sprite_f0_ti0_tr0_s0_d5 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 1 +#define _DMODE 5 +#define FUNCNAME draw_sprite_f0_ti0_tr0_s1_d5 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 2 +#define _DMODE 5 +#define FUNCNAME draw_sprite_f0_ti0_tr0_s2_d5 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 3 +#define _DMODE 5 +#define FUNCNAME draw_sprite_f0_ti0_tr0_s3_d5 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 4 +#define _DMODE 5 +#define FUNCNAME draw_sprite_f0_ti0_tr0_s4_d5 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 5 +#define _DMODE 5 +#define FUNCNAME draw_sprite_f0_ti0_tr0_s5_d5 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 6 +#define _DMODE 5 +#define FUNCNAME draw_sprite_f0_ti0_tr0_s6_d5 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 7 +#define _DMODE 5 +#define FUNCNAME draw_sprite_f0_ti0_tr0_s7_d5 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +/// + +#define _SMODE 0 +#define _DMODE 6 +#define FUNCNAME draw_sprite_f0_ti0_tr0_s0_d6 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 1 +#define _DMODE 6 +#define FUNCNAME draw_sprite_f0_ti0_tr0_s1_d6 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 2 +#define _DMODE 6 +#define FUNCNAME draw_sprite_f0_ti0_tr0_s2_d6 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 3 +#define _DMODE 6 +#define FUNCNAME draw_sprite_f0_ti0_tr0_s3_d6 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 4 +#define _DMODE 6 +#define FUNCNAME draw_sprite_f0_ti0_tr0_s4_d6 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 5 +#define _DMODE 6 +#define FUNCNAME draw_sprite_f0_ti0_tr0_s5_d6 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 6 +#define _DMODE 6 +#define FUNCNAME draw_sprite_f0_ti0_tr0_s6_d6 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 7 +#define _DMODE 6 +#define FUNCNAME draw_sprite_f0_ti0_tr0_s7_d6 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +/// + + +#define _SMODE 0 +#define _DMODE 7 +#define FUNCNAME draw_sprite_f0_ti0_tr0_s0_d7 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 1 +#define _DMODE 7 +#define FUNCNAME draw_sprite_f0_ti0_tr0_s1_d7 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 2 +#define _DMODE 7 +#define FUNCNAME draw_sprite_f0_ti0_tr0_s2_d7 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 3 +#define _DMODE 7 +#define FUNCNAME draw_sprite_f0_ti0_tr0_s3_d7 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 4 +#define _DMODE 7 +#define FUNCNAME draw_sprite_f0_ti0_tr0_s4_d7 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 5 +#define _DMODE 7 +#define FUNCNAME draw_sprite_f0_ti0_tr0_s5_d7 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 6 +#define _DMODE 7 +#define FUNCNAME draw_sprite_f0_ti0_tr0_s6_d7 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 7 +#define _DMODE 7 +#define FUNCNAME draw_sprite_f0_ti0_tr0_s7_d7 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#undef BLENDED + +#undef FLIPX +#undef TINT +#undef TRANSPARENT +#undef REALLY_SIMPLE diff --git a/src/devices/video/epic12_blit2.c b/src/devices/video/epic12_blit2.c new file mode 100644 index 00000000000..039ab762635 --- /dev/null +++ b/src/devices/video/epic12_blit2.c @@ -0,0 +1,558 @@ +// license:BSD-3-Clause +// copyright-holders:David Haywood +#define REALLY_SIMPLE 0 +/* X-Flipped, Non-Tinted, Transparent */ +#define FLIPX 1 +#define TINT 0 +#define TRANSPARENT 1 + +#include "emu.h" +#include "epic12.h" + +/* Special Case */ +#define BLENDED 0 +#define FUNCNAME draw_sprite_f1_ti0_plain +#include "epic12in.inc" +#undef FUNCNAME +#undef BLENDED + +/* Regular Cases*/ +#define BLENDED 1 + +#define _SMODE 0 +#define _DMODE 0 +#define FUNCNAME draw_sprite_f1_ti0_tr1_s0_d0 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 1 +#define _DMODE 0 +#define FUNCNAME draw_sprite_f1_ti0_tr1_s1_d0 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 2 +#define _DMODE 0 +#define FUNCNAME draw_sprite_f1_ti0_tr1_s2_d0 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 3 +#define _DMODE 0 +#define FUNCNAME draw_sprite_f1_ti0_tr1_s3_d0 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 4 +#define _DMODE 0 +#define FUNCNAME draw_sprite_f1_ti0_tr1_s4_d0 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 5 +#define _DMODE 0 +#define FUNCNAME draw_sprite_f1_ti0_tr1_s5_d0 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 6 +#define _DMODE 0 +#define FUNCNAME draw_sprite_f1_ti0_tr1_s6_d0 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 7 +#define _DMODE 0 +#define FUNCNAME draw_sprite_f1_ti0_tr1_s7_d0 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +/////// + + +#define _SMODE 0 +#define _DMODE 1 +#define FUNCNAME draw_sprite_f1_ti0_tr1_s0_d1 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 1 +#define _DMODE 1 +#define FUNCNAME draw_sprite_f1_ti0_tr1_s1_d1 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 2 +#define _DMODE 1 +#define FUNCNAME draw_sprite_f1_ti0_tr1_s2_d1 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 3 +#define _DMODE 1 +#define FUNCNAME draw_sprite_f1_ti0_tr1_s3_d1 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 4 +#define _DMODE 1 +#define FUNCNAME draw_sprite_f1_ti0_tr1_s4_d1 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 5 +#define _DMODE 1 +#define FUNCNAME draw_sprite_f1_ti0_tr1_s5_d1 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 6 +#define _DMODE 1 +#define FUNCNAME draw_sprite_f1_ti0_tr1_s6_d1 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 7 +#define _DMODE 1 +#define FUNCNAME draw_sprite_f1_ti0_tr1_s7_d1 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +//// + + +#define _SMODE 0 +#define _DMODE 2 +#define FUNCNAME draw_sprite_f1_ti0_tr1_s0_d2 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 1 +#define _DMODE 2 +#define FUNCNAME draw_sprite_f1_ti0_tr1_s1_d2 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 2 +#define _DMODE 2 +#define FUNCNAME draw_sprite_f1_ti0_tr1_s2_d2 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 3 +#define _DMODE 2 +#define FUNCNAME draw_sprite_f1_ti0_tr1_s3_d2 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 4 +#define _DMODE 2 +#define FUNCNAME draw_sprite_f1_ti0_tr1_s4_d2 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 5 +#define _DMODE 2 +#define FUNCNAME draw_sprite_f1_ti0_tr1_s5_d2 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 6 +#define _DMODE 2 +#define FUNCNAME draw_sprite_f1_ti0_tr1_s6_d2 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 7 +#define _DMODE 2 +#define FUNCNAME draw_sprite_f1_ti0_tr1_s7_d2 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +/// + + +#define _SMODE 0 +#define _DMODE 3 +#define FUNCNAME draw_sprite_f1_ti0_tr1_s0_d3 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 1 +#define _DMODE 3 +#define FUNCNAME draw_sprite_f1_ti0_tr1_s1_d3 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 2 +#define _DMODE 3 +#define FUNCNAME draw_sprite_f1_ti0_tr1_s2_d3 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 3 +#define _DMODE 3 +#define FUNCNAME draw_sprite_f1_ti0_tr1_s3_d3 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 4 +#define _DMODE 3 +#define FUNCNAME draw_sprite_f1_ti0_tr1_s4_d3 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 5 +#define _DMODE 3 +#define FUNCNAME draw_sprite_f1_ti0_tr1_s5_d3 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 6 +#define _DMODE 3 +#define FUNCNAME draw_sprite_f1_ti0_tr1_s6_d3 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 7 +#define _DMODE 3 +#define FUNCNAME draw_sprite_f1_ti0_tr1_s7_d3 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +/// + + +#define _SMODE 0 +#define _DMODE 4 +#define FUNCNAME draw_sprite_f1_ti0_tr1_s0_d4 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 1 +#define _DMODE 4 +#define FUNCNAME draw_sprite_f1_ti0_tr1_s1_d4 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 2 +#define _DMODE 4 +#define FUNCNAME draw_sprite_f1_ti0_tr1_s2_d4 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 3 +#define _DMODE 4 +#define FUNCNAME draw_sprite_f1_ti0_tr1_s3_d4 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 4 +#define _DMODE 4 +#define FUNCNAME draw_sprite_f1_ti0_tr1_s4_d4 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 5 +#define _DMODE 4 +#define FUNCNAME draw_sprite_f1_ti0_tr1_s5_d4 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 6 +#define _DMODE 4 +#define FUNCNAME draw_sprite_f1_ti0_tr1_s6_d4 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 7 +#define _DMODE 4 +#define FUNCNAME draw_sprite_f1_ti0_tr1_s7_d4 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +/// + +#define _SMODE 0 +#define _DMODE 5 +#define FUNCNAME draw_sprite_f1_ti0_tr1_s0_d5 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 1 +#define _DMODE 5 +#define FUNCNAME draw_sprite_f1_ti0_tr1_s1_d5 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 2 +#define _DMODE 5 +#define FUNCNAME draw_sprite_f1_ti0_tr1_s2_d5 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 3 +#define _DMODE 5 +#define FUNCNAME draw_sprite_f1_ti0_tr1_s3_d5 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 4 +#define _DMODE 5 +#define FUNCNAME draw_sprite_f1_ti0_tr1_s4_d5 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 5 +#define _DMODE 5 +#define FUNCNAME draw_sprite_f1_ti0_tr1_s5_d5 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 6 +#define _DMODE 5 +#define FUNCNAME draw_sprite_f1_ti0_tr1_s6_d5 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 7 +#define _DMODE 5 +#define FUNCNAME draw_sprite_f1_ti0_tr1_s7_d5 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +/// + +#define _SMODE 0 +#define _DMODE 6 +#define FUNCNAME draw_sprite_f1_ti0_tr1_s0_d6 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 1 +#define _DMODE 6 +#define FUNCNAME draw_sprite_f1_ti0_tr1_s1_d6 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 2 +#define _DMODE 6 +#define FUNCNAME draw_sprite_f1_ti0_tr1_s2_d6 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 3 +#define _DMODE 6 +#define FUNCNAME draw_sprite_f1_ti0_tr1_s3_d6 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 4 +#define _DMODE 6 +#define FUNCNAME draw_sprite_f1_ti0_tr1_s4_d6 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 5 +#define _DMODE 6 +#define FUNCNAME draw_sprite_f1_ti0_tr1_s5_d6 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 6 +#define _DMODE 6 +#define FUNCNAME draw_sprite_f1_ti0_tr1_s6_d6 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 7 +#define _DMODE 6 +#define FUNCNAME draw_sprite_f1_ti0_tr1_s7_d6 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +/// + + +#define _SMODE 0 +#define _DMODE 7 +#define FUNCNAME draw_sprite_f1_ti0_tr1_s0_d7 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 1 +#define _DMODE 7 +#define FUNCNAME draw_sprite_f1_ti0_tr1_s1_d7 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 2 +#define _DMODE 7 +#define FUNCNAME draw_sprite_f1_ti0_tr1_s2_d7 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 3 +#define _DMODE 7 +#define FUNCNAME draw_sprite_f1_ti0_tr1_s3_d7 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 4 +#define _DMODE 7 +#define FUNCNAME draw_sprite_f1_ti0_tr1_s4_d7 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 5 +#define _DMODE 7 +#define FUNCNAME draw_sprite_f1_ti0_tr1_s5_d7 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 6 +#define _DMODE 7 +#define FUNCNAME draw_sprite_f1_ti0_tr1_s6_d7 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 7 +#define _DMODE 7 +#define FUNCNAME draw_sprite_f1_ti0_tr1_s7_d7 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#undef BLENDED + +#undef FLIPX +#undef TINT +#undef TRANSPARENT +#undef REALLY_SIMPLE diff --git a/src/devices/video/epic12_blit3.c b/src/devices/video/epic12_blit3.c new file mode 100644 index 00000000000..868f4c1e25e --- /dev/null +++ b/src/devices/video/epic12_blit3.c @@ -0,0 +1,558 @@ +// license:BSD-3-Clause +// copyright-holders:David Haywood +#define REALLY_SIMPLE 0 +/* X-Flipped, Non-Tinted, Non-Transparent */ +#define FLIPX 1 +#define TINT 0 +#define TRANSPARENT 0 + +#include "emu.h" +#include "epic12.h" + +/* Special Case */ +#define BLENDED 0 +#define FUNCNAME draw_sprite_f1_ti0_tr0_plain +#include "epic12in.inc" +#undef FUNCNAME +#undef BLENDED + +/* Regular Cases*/ +#define BLENDED 1 + +#define _SMODE 0 +#define _DMODE 0 +#define FUNCNAME draw_sprite_f1_ti0_tr0_s0_d0 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 1 +#define _DMODE 0 +#define FUNCNAME draw_sprite_f1_ti0_tr0_s1_d0 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 2 +#define _DMODE 0 +#define FUNCNAME draw_sprite_f1_ti0_tr0_s2_d0 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 3 +#define _DMODE 0 +#define FUNCNAME draw_sprite_f1_ti0_tr0_s3_d0 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 4 +#define _DMODE 0 +#define FUNCNAME draw_sprite_f1_ti0_tr0_s4_d0 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 5 +#define _DMODE 0 +#define FUNCNAME draw_sprite_f1_ti0_tr0_s5_d0 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 6 +#define _DMODE 0 +#define FUNCNAME draw_sprite_f1_ti0_tr0_s6_d0 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 7 +#define _DMODE 0 +#define FUNCNAME draw_sprite_f1_ti0_tr0_s7_d0 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +/////// + + +#define _SMODE 0 +#define _DMODE 1 +#define FUNCNAME draw_sprite_f1_ti0_tr0_s0_d1 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 1 +#define _DMODE 1 +#define FUNCNAME draw_sprite_f1_ti0_tr0_s1_d1 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 2 +#define _DMODE 1 +#define FUNCNAME draw_sprite_f1_ti0_tr0_s2_d1 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 3 +#define _DMODE 1 +#define FUNCNAME draw_sprite_f1_ti0_tr0_s3_d1 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 4 +#define _DMODE 1 +#define FUNCNAME draw_sprite_f1_ti0_tr0_s4_d1 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 5 +#define _DMODE 1 +#define FUNCNAME draw_sprite_f1_ti0_tr0_s5_d1 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 6 +#define _DMODE 1 +#define FUNCNAME draw_sprite_f1_ti0_tr0_s6_d1 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 7 +#define _DMODE 1 +#define FUNCNAME draw_sprite_f1_ti0_tr0_s7_d1 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +//// + + +#define _SMODE 0 +#define _DMODE 2 +#define FUNCNAME draw_sprite_f1_ti0_tr0_s0_d2 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 1 +#define _DMODE 2 +#define FUNCNAME draw_sprite_f1_ti0_tr0_s1_d2 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 2 +#define _DMODE 2 +#define FUNCNAME draw_sprite_f1_ti0_tr0_s2_d2 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 3 +#define _DMODE 2 +#define FUNCNAME draw_sprite_f1_ti0_tr0_s3_d2 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 4 +#define _DMODE 2 +#define FUNCNAME draw_sprite_f1_ti0_tr0_s4_d2 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 5 +#define _DMODE 2 +#define FUNCNAME draw_sprite_f1_ti0_tr0_s5_d2 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 6 +#define _DMODE 2 +#define FUNCNAME draw_sprite_f1_ti0_tr0_s6_d2 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 7 +#define _DMODE 2 +#define FUNCNAME draw_sprite_f1_ti0_tr0_s7_d2 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +/// + + +#define _SMODE 0 +#define _DMODE 3 +#define FUNCNAME draw_sprite_f1_ti0_tr0_s0_d3 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 1 +#define _DMODE 3 +#define FUNCNAME draw_sprite_f1_ti0_tr0_s1_d3 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 2 +#define _DMODE 3 +#define FUNCNAME draw_sprite_f1_ti0_tr0_s2_d3 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 3 +#define _DMODE 3 +#define FUNCNAME draw_sprite_f1_ti0_tr0_s3_d3 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 4 +#define _DMODE 3 +#define FUNCNAME draw_sprite_f1_ti0_tr0_s4_d3 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 5 +#define _DMODE 3 +#define FUNCNAME draw_sprite_f1_ti0_tr0_s5_d3 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 6 +#define _DMODE 3 +#define FUNCNAME draw_sprite_f1_ti0_tr0_s6_d3 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 7 +#define _DMODE 3 +#define FUNCNAME draw_sprite_f1_ti0_tr0_s7_d3 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +/// + + +#define _SMODE 0 +#define _DMODE 4 +#define FUNCNAME draw_sprite_f1_ti0_tr0_s0_d4 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 1 +#define _DMODE 4 +#define FUNCNAME draw_sprite_f1_ti0_tr0_s1_d4 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 2 +#define _DMODE 4 +#define FUNCNAME draw_sprite_f1_ti0_tr0_s2_d4 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 3 +#define _DMODE 4 +#define FUNCNAME draw_sprite_f1_ti0_tr0_s3_d4 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 4 +#define _DMODE 4 +#define FUNCNAME draw_sprite_f1_ti0_tr0_s4_d4 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 5 +#define _DMODE 4 +#define FUNCNAME draw_sprite_f1_ti0_tr0_s5_d4 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 6 +#define _DMODE 4 +#define FUNCNAME draw_sprite_f1_ti0_tr0_s6_d4 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 7 +#define _DMODE 4 +#define FUNCNAME draw_sprite_f1_ti0_tr0_s7_d4 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +/// + +#define _SMODE 0 +#define _DMODE 5 +#define FUNCNAME draw_sprite_f1_ti0_tr0_s0_d5 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 1 +#define _DMODE 5 +#define FUNCNAME draw_sprite_f1_ti0_tr0_s1_d5 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 2 +#define _DMODE 5 +#define FUNCNAME draw_sprite_f1_ti0_tr0_s2_d5 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 3 +#define _DMODE 5 +#define FUNCNAME draw_sprite_f1_ti0_tr0_s3_d5 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 4 +#define _DMODE 5 +#define FUNCNAME draw_sprite_f1_ti0_tr0_s4_d5 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 5 +#define _DMODE 5 +#define FUNCNAME draw_sprite_f1_ti0_tr0_s5_d5 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 6 +#define _DMODE 5 +#define FUNCNAME draw_sprite_f1_ti0_tr0_s6_d5 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 7 +#define _DMODE 5 +#define FUNCNAME draw_sprite_f1_ti0_tr0_s7_d5 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +/// + +#define _SMODE 0 +#define _DMODE 6 +#define FUNCNAME draw_sprite_f1_ti0_tr0_s0_d6 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 1 +#define _DMODE 6 +#define FUNCNAME draw_sprite_f1_ti0_tr0_s1_d6 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 2 +#define _DMODE 6 +#define FUNCNAME draw_sprite_f1_ti0_tr0_s2_d6 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 3 +#define _DMODE 6 +#define FUNCNAME draw_sprite_f1_ti0_tr0_s3_d6 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 4 +#define _DMODE 6 +#define FUNCNAME draw_sprite_f1_ti0_tr0_s4_d6 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 5 +#define _DMODE 6 +#define FUNCNAME draw_sprite_f1_ti0_tr0_s5_d6 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 6 +#define _DMODE 6 +#define FUNCNAME draw_sprite_f1_ti0_tr0_s6_d6 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 7 +#define _DMODE 6 +#define FUNCNAME draw_sprite_f1_ti0_tr0_s7_d6 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +/// + + +#define _SMODE 0 +#define _DMODE 7 +#define FUNCNAME draw_sprite_f1_ti0_tr0_s0_d7 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 1 +#define _DMODE 7 +#define FUNCNAME draw_sprite_f1_ti0_tr0_s1_d7 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 2 +#define _DMODE 7 +#define FUNCNAME draw_sprite_f1_ti0_tr0_s2_d7 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 3 +#define _DMODE 7 +#define FUNCNAME draw_sprite_f1_ti0_tr0_s3_d7 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 4 +#define _DMODE 7 +#define FUNCNAME draw_sprite_f1_ti0_tr0_s4_d7 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 5 +#define _DMODE 7 +#define FUNCNAME draw_sprite_f1_ti0_tr0_s5_d7 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 6 +#define _DMODE 7 +#define FUNCNAME draw_sprite_f1_ti0_tr0_s6_d7 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 7 +#define _DMODE 7 +#define FUNCNAME draw_sprite_f1_ti0_tr0_s7_d7 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#undef BLENDED + +#undef FLIPX +#undef TINT +#undef TRANSPARENT +#undef REALLY_SIMPLE diff --git a/src/devices/video/epic12_blit4.c b/src/devices/video/epic12_blit4.c new file mode 100644 index 00000000000..c5ed93ae70b --- /dev/null +++ b/src/devices/video/epic12_blit4.c @@ -0,0 +1,558 @@ +// license:BSD-3-Clause +// copyright-holders:David Haywood +#define REALLY_SIMPLE 0 +/* Non-Flipped, Tinted, Transparent */ +#define FLIPX 0 +#define TINT 1 +#define TRANSPARENT 1 + +#include "emu.h" +#include "epic12.h" + +/* Special Case */ +#define BLENDED 0 +#define FUNCNAME draw_sprite_f0_ti1_tr1_plain +#include "epic12in.inc" +#undef FUNCNAME +#undef BLENDED + +/* Regular Cases*/ +#define BLENDED 1 + +#define _SMODE 0 +#define _DMODE 0 +#define FUNCNAME draw_sprite_f0_ti1_tr1_s0_d0 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 1 +#define _DMODE 0 +#define FUNCNAME draw_sprite_f0_ti1_tr1_s1_d0 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 2 +#define _DMODE 0 +#define FUNCNAME draw_sprite_f0_ti1_tr1_s2_d0 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 3 +#define _DMODE 0 +#define FUNCNAME draw_sprite_f0_ti1_tr1_s3_d0 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 4 +#define _DMODE 0 +#define FUNCNAME draw_sprite_f0_ti1_tr1_s4_d0 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 5 +#define _DMODE 0 +#define FUNCNAME draw_sprite_f0_ti1_tr1_s5_d0 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 6 +#define _DMODE 0 +#define FUNCNAME draw_sprite_f0_ti1_tr1_s6_d0 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 7 +#define _DMODE 0 +#define FUNCNAME draw_sprite_f0_ti1_tr1_s7_d0 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +/////// + + +#define _SMODE 0 +#define _DMODE 1 +#define FUNCNAME draw_sprite_f0_ti1_tr1_s0_d1 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 1 +#define _DMODE 1 +#define FUNCNAME draw_sprite_f0_ti1_tr1_s1_d1 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 2 +#define _DMODE 1 +#define FUNCNAME draw_sprite_f0_ti1_tr1_s2_d1 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 3 +#define _DMODE 1 +#define FUNCNAME draw_sprite_f0_ti1_tr1_s3_d1 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 4 +#define _DMODE 1 +#define FUNCNAME draw_sprite_f0_ti1_tr1_s4_d1 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 5 +#define _DMODE 1 +#define FUNCNAME draw_sprite_f0_ti1_tr1_s5_d1 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 6 +#define _DMODE 1 +#define FUNCNAME draw_sprite_f0_ti1_tr1_s6_d1 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 7 +#define _DMODE 1 +#define FUNCNAME draw_sprite_f0_ti1_tr1_s7_d1 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +//// + + +#define _SMODE 0 +#define _DMODE 2 +#define FUNCNAME draw_sprite_f0_ti1_tr1_s0_d2 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 1 +#define _DMODE 2 +#define FUNCNAME draw_sprite_f0_ti1_tr1_s1_d2 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 2 +#define _DMODE 2 +#define FUNCNAME draw_sprite_f0_ti1_tr1_s2_d2 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 3 +#define _DMODE 2 +#define FUNCNAME draw_sprite_f0_ti1_tr1_s3_d2 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 4 +#define _DMODE 2 +#define FUNCNAME draw_sprite_f0_ti1_tr1_s4_d2 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 5 +#define _DMODE 2 +#define FUNCNAME draw_sprite_f0_ti1_tr1_s5_d2 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 6 +#define _DMODE 2 +#define FUNCNAME draw_sprite_f0_ti1_tr1_s6_d2 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 7 +#define _DMODE 2 +#define FUNCNAME draw_sprite_f0_ti1_tr1_s7_d2 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +/// + + +#define _SMODE 0 +#define _DMODE 3 +#define FUNCNAME draw_sprite_f0_ti1_tr1_s0_d3 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 1 +#define _DMODE 3 +#define FUNCNAME draw_sprite_f0_ti1_tr1_s1_d3 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 2 +#define _DMODE 3 +#define FUNCNAME draw_sprite_f0_ti1_tr1_s2_d3 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 3 +#define _DMODE 3 +#define FUNCNAME draw_sprite_f0_ti1_tr1_s3_d3 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 4 +#define _DMODE 3 +#define FUNCNAME draw_sprite_f0_ti1_tr1_s4_d3 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 5 +#define _DMODE 3 +#define FUNCNAME draw_sprite_f0_ti1_tr1_s5_d3 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 6 +#define _DMODE 3 +#define FUNCNAME draw_sprite_f0_ti1_tr1_s6_d3 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 7 +#define _DMODE 3 +#define FUNCNAME draw_sprite_f0_ti1_tr1_s7_d3 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +/// + + +#define _SMODE 0 +#define _DMODE 4 +#define FUNCNAME draw_sprite_f0_ti1_tr1_s0_d4 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 1 +#define _DMODE 4 +#define FUNCNAME draw_sprite_f0_ti1_tr1_s1_d4 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 2 +#define _DMODE 4 +#define FUNCNAME draw_sprite_f0_ti1_tr1_s2_d4 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 3 +#define _DMODE 4 +#define FUNCNAME draw_sprite_f0_ti1_tr1_s3_d4 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 4 +#define _DMODE 4 +#define FUNCNAME draw_sprite_f0_ti1_tr1_s4_d4 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 5 +#define _DMODE 4 +#define FUNCNAME draw_sprite_f0_ti1_tr1_s5_d4 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 6 +#define _DMODE 4 +#define FUNCNAME draw_sprite_f0_ti1_tr1_s6_d4 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 7 +#define _DMODE 4 +#define FUNCNAME draw_sprite_f0_ti1_tr1_s7_d4 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +/// + +#define _SMODE 0 +#define _DMODE 5 +#define FUNCNAME draw_sprite_f0_ti1_tr1_s0_d5 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 1 +#define _DMODE 5 +#define FUNCNAME draw_sprite_f0_ti1_tr1_s1_d5 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 2 +#define _DMODE 5 +#define FUNCNAME draw_sprite_f0_ti1_tr1_s2_d5 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 3 +#define _DMODE 5 +#define FUNCNAME draw_sprite_f0_ti1_tr1_s3_d5 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 4 +#define _DMODE 5 +#define FUNCNAME draw_sprite_f0_ti1_tr1_s4_d5 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 5 +#define _DMODE 5 +#define FUNCNAME draw_sprite_f0_ti1_tr1_s5_d5 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 6 +#define _DMODE 5 +#define FUNCNAME draw_sprite_f0_ti1_tr1_s6_d5 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 7 +#define _DMODE 5 +#define FUNCNAME draw_sprite_f0_ti1_tr1_s7_d5 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +/// + +#define _SMODE 0 +#define _DMODE 6 +#define FUNCNAME draw_sprite_f0_ti1_tr1_s0_d6 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 1 +#define _DMODE 6 +#define FUNCNAME draw_sprite_f0_ti1_tr1_s1_d6 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 2 +#define _DMODE 6 +#define FUNCNAME draw_sprite_f0_ti1_tr1_s2_d6 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 3 +#define _DMODE 6 +#define FUNCNAME draw_sprite_f0_ti1_tr1_s3_d6 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 4 +#define _DMODE 6 +#define FUNCNAME draw_sprite_f0_ti1_tr1_s4_d6 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 5 +#define _DMODE 6 +#define FUNCNAME draw_sprite_f0_ti1_tr1_s5_d6 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 6 +#define _DMODE 6 +#define FUNCNAME draw_sprite_f0_ti1_tr1_s6_d6 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 7 +#define _DMODE 6 +#define FUNCNAME draw_sprite_f0_ti1_tr1_s7_d6 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +/// + + +#define _SMODE 0 +#define _DMODE 7 +#define FUNCNAME draw_sprite_f0_ti1_tr1_s0_d7 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 1 +#define _DMODE 7 +#define FUNCNAME draw_sprite_f0_ti1_tr1_s1_d7 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 2 +#define _DMODE 7 +#define FUNCNAME draw_sprite_f0_ti1_tr1_s2_d7 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 3 +#define _DMODE 7 +#define FUNCNAME draw_sprite_f0_ti1_tr1_s3_d7 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 4 +#define _DMODE 7 +#define FUNCNAME draw_sprite_f0_ti1_tr1_s4_d7 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 5 +#define _DMODE 7 +#define FUNCNAME draw_sprite_f0_ti1_tr1_s5_d7 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 6 +#define _DMODE 7 +#define FUNCNAME draw_sprite_f0_ti1_tr1_s6_d7 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 7 +#define _DMODE 7 +#define FUNCNAME draw_sprite_f0_ti1_tr1_s7_d7 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#undef BLENDED + +#undef FLIPX +#undef TINT +#undef TRANSPARENT +#undef REALLY_SIMPLE diff --git a/src/devices/video/epic12_blit5.c b/src/devices/video/epic12_blit5.c new file mode 100644 index 00000000000..4c0a3b0bd0d --- /dev/null +++ b/src/devices/video/epic12_blit5.c @@ -0,0 +1,558 @@ +// license:BSD-3-Clause +// copyright-holders:David Haywood +#define REALLY_SIMPLE 0 +/* Non-Flipped, Tinted, Non-Transparent */ +#define FLIPX 0 +#define TINT 1 +#define TRANSPARENT 0 + +#include "emu.h" +#include "epic12.h" + +/* Special Case */ +#define BLENDED 0 +#define FUNCNAME draw_sprite_f0_ti1_tr0_plain +#include "epic12in.inc" +#undef FUNCNAME +#undef BLENDED + +/* Regular Cases*/ +#define BLENDED 1 + +#define _SMODE 0 +#define _DMODE 0 +#define FUNCNAME draw_sprite_f0_ti1_tr0_s0_d0 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 1 +#define _DMODE 0 +#define FUNCNAME draw_sprite_f0_ti1_tr0_s1_d0 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 2 +#define _DMODE 0 +#define FUNCNAME draw_sprite_f0_ti1_tr0_s2_d0 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 3 +#define _DMODE 0 +#define FUNCNAME draw_sprite_f0_ti1_tr0_s3_d0 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 4 +#define _DMODE 0 +#define FUNCNAME draw_sprite_f0_ti1_tr0_s4_d0 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 5 +#define _DMODE 0 +#define FUNCNAME draw_sprite_f0_ti1_tr0_s5_d0 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 6 +#define _DMODE 0 +#define FUNCNAME draw_sprite_f0_ti1_tr0_s6_d0 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 7 +#define _DMODE 0 +#define FUNCNAME draw_sprite_f0_ti1_tr0_s7_d0 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +/////// + + +#define _SMODE 0 +#define _DMODE 1 +#define FUNCNAME draw_sprite_f0_ti1_tr0_s0_d1 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 1 +#define _DMODE 1 +#define FUNCNAME draw_sprite_f0_ti1_tr0_s1_d1 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 2 +#define _DMODE 1 +#define FUNCNAME draw_sprite_f0_ti1_tr0_s2_d1 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 3 +#define _DMODE 1 +#define FUNCNAME draw_sprite_f0_ti1_tr0_s3_d1 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 4 +#define _DMODE 1 +#define FUNCNAME draw_sprite_f0_ti1_tr0_s4_d1 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 5 +#define _DMODE 1 +#define FUNCNAME draw_sprite_f0_ti1_tr0_s5_d1 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 6 +#define _DMODE 1 +#define FUNCNAME draw_sprite_f0_ti1_tr0_s6_d1 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 7 +#define _DMODE 1 +#define FUNCNAME draw_sprite_f0_ti1_tr0_s7_d1 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +//// + + +#define _SMODE 0 +#define _DMODE 2 +#define FUNCNAME draw_sprite_f0_ti1_tr0_s0_d2 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 1 +#define _DMODE 2 +#define FUNCNAME draw_sprite_f0_ti1_tr0_s1_d2 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 2 +#define _DMODE 2 +#define FUNCNAME draw_sprite_f0_ti1_tr0_s2_d2 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 3 +#define _DMODE 2 +#define FUNCNAME draw_sprite_f0_ti1_tr0_s3_d2 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 4 +#define _DMODE 2 +#define FUNCNAME draw_sprite_f0_ti1_tr0_s4_d2 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 5 +#define _DMODE 2 +#define FUNCNAME draw_sprite_f0_ti1_tr0_s5_d2 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 6 +#define _DMODE 2 +#define FUNCNAME draw_sprite_f0_ti1_tr0_s6_d2 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 7 +#define _DMODE 2 +#define FUNCNAME draw_sprite_f0_ti1_tr0_s7_d2 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +/// + + +#define _SMODE 0 +#define _DMODE 3 +#define FUNCNAME draw_sprite_f0_ti1_tr0_s0_d3 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 1 +#define _DMODE 3 +#define FUNCNAME draw_sprite_f0_ti1_tr0_s1_d3 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 2 +#define _DMODE 3 +#define FUNCNAME draw_sprite_f0_ti1_tr0_s2_d3 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 3 +#define _DMODE 3 +#define FUNCNAME draw_sprite_f0_ti1_tr0_s3_d3 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 4 +#define _DMODE 3 +#define FUNCNAME draw_sprite_f0_ti1_tr0_s4_d3 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 5 +#define _DMODE 3 +#define FUNCNAME draw_sprite_f0_ti1_tr0_s5_d3 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 6 +#define _DMODE 3 +#define FUNCNAME draw_sprite_f0_ti1_tr0_s6_d3 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 7 +#define _DMODE 3 +#define FUNCNAME draw_sprite_f0_ti1_tr0_s7_d3 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +/// + + +#define _SMODE 0 +#define _DMODE 4 +#define FUNCNAME draw_sprite_f0_ti1_tr0_s0_d4 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 1 +#define _DMODE 4 +#define FUNCNAME draw_sprite_f0_ti1_tr0_s1_d4 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 2 +#define _DMODE 4 +#define FUNCNAME draw_sprite_f0_ti1_tr0_s2_d4 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 3 +#define _DMODE 4 +#define FUNCNAME draw_sprite_f0_ti1_tr0_s3_d4 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 4 +#define _DMODE 4 +#define FUNCNAME draw_sprite_f0_ti1_tr0_s4_d4 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 5 +#define _DMODE 4 +#define FUNCNAME draw_sprite_f0_ti1_tr0_s5_d4 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 6 +#define _DMODE 4 +#define FUNCNAME draw_sprite_f0_ti1_tr0_s6_d4 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 7 +#define _DMODE 4 +#define FUNCNAME draw_sprite_f0_ti1_tr0_s7_d4 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +/// + +#define _SMODE 0 +#define _DMODE 5 +#define FUNCNAME draw_sprite_f0_ti1_tr0_s0_d5 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 1 +#define _DMODE 5 +#define FUNCNAME draw_sprite_f0_ti1_tr0_s1_d5 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 2 +#define _DMODE 5 +#define FUNCNAME draw_sprite_f0_ti1_tr0_s2_d5 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 3 +#define _DMODE 5 +#define FUNCNAME draw_sprite_f0_ti1_tr0_s3_d5 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 4 +#define _DMODE 5 +#define FUNCNAME draw_sprite_f0_ti1_tr0_s4_d5 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 5 +#define _DMODE 5 +#define FUNCNAME draw_sprite_f0_ti1_tr0_s5_d5 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 6 +#define _DMODE 5 +#define FUNCNAME draw_sprite_f0_ti1_tr0_s6_d5 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 7 +#define _DMODE 5 +#define FUNCNAME draw_sprite_f0_ti1_tr0_s7_d5 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +/// + +#define _SMODE 0 +#define _DMODE 6 +#define FUNCNAME draw_sprite_f0_ti1_tr0_s0_d6 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 1 +#define _DMODE 6 +#define FUNCNAME draw_sprite_f0_ti1_tr0_s1_d6 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 2 +#define _DMODE 6 +#define FUNCNAME draw_sprite_f0_ti1_tr0_s2_d6 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 3 +#define _DMODE 6 +#define FUNCNAME draw_sprite_f0_ti1_tr0_s3_d6 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 4 +#define _DMODE 6 +#define FUNCNAME draw_sprite_f0_ti1_tr0_s4_d6 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 5 +#define _DMODE 6 +#define FUNCNAME draw_sprite_f0_ti1_tr0_s5_d6 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 6 +#define _DMODE 6 +#define FUNCNAME draw_sprite_f0_ti1_tr0_s6_d6 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 7 +#define _DMODE 6 +#define FUNCNAME draw_sprite_f0_ti1_tr0_s7_d6 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +/// + + +#define _SMODE 0 +#define _DMODE 7 +#define FUNCNAME draw_sprite_f0_ti1_tr0_s0_d7 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 1 +#define _DMODE 7 +#define FUNCNAME draw_sprite_f0_ti1_tr0_s1_d7 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 2 +#define _DMODE 7 +#define FUNCNAME draw_sprite_f0_ti1_tr0_s2_d7 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 3 +#define _DMODE 7 +#define FUNCNAME draw_sprite_f0_ti1_tr0_s3_d7 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 4 +#define _DMODE 7 +#define FUNCNAME draw_sprite_f0_ti1_tr0_s4_d7 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 5 +#define _DMODE 7 +#define FUNCNAME draw_sprite_f0_ti1_tr0_s5_d7 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 6 +#define _DMODE 7 +#define FUNCNAME draw_sprite_f0_ti1_tr0_s6_d7 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 7 +#define _DMODE 7 +#define FUNCNAME draw_sprite_f0_ti1_tr0_s7_d7 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#undef BLENDED + +#undef FLIPX +#undef TINT +#undef TRANSPARENT +#undef REALLY_SIMPLE diff --git a/src/devices/video/epic12_blit6.c b/src/devices/video/epic12_blit6.c new file mode 100644 index 00000000000..9ef7302b139 --- /dev/null +++ b/src/devices/video/epic12_blit6.c @@ -0,0 +1,558 @@ +// license:BSD-3-Clause +// copyright-holders:David Haywood +#define REALLY_SIMPLE 0 +/* X-Flipped, Tinted, Transparent */ +#define FLIPX 1 +#define TINT 1 +#define TRANSPARENT 1 + +#include "emu.h" +#include "epic12.h" + +/* Special Case */ +#define BLENDED 0 +#define FUNCNAME draw_sprite_f1_ti1_tr1_plain +#include "epic12in.inc" +#undef FUNCNAME +#undef BLENDED + +/* Regular Cases*/ +#define BLENDED 1 + +#define _SMODE 0 +#define _DMODE 0 +#define FUNCNAME draw_sprite_f1_ti1_tr1_s0_d0 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 1 +#define _DMODE 0 +#define FUNCNAME draw_sprite_f1_ti1_tr1_s1_d0 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 2 +#define _DMODE 0 +#define FUNCNAME draw_sprite_f1_ti1_tr1_s2_d0 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 3 +#define _DMODE 0 +#define FUNCNAME draw_sprite_f1_ti1_tr1_s3_d0 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 4 +#define _DMODE 0 +#define FUNCNAME draw_sprite_f1_ti1_tr1_s4_d0 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 5 +#define _DMODE 0 +#define FUNCNAME draw_sprite_f1_ti1_tr1_s5_d0 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 6 +#define _DMODE 0 +#define FUNCNAME draw_sprite_f1_ti1_tr1_s6_d0 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 7 +#define _DMODE 0 +#define FUNCNAME draw_sprite_f1_ti1_tr1_s7_d0 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +/////// + + +#define _SMODE 0 +#define _DMODE 1 +#define FUNCNAME draw_sprite_f1_ti1_tr1_s0_d1 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 1 +#define _DMODE 1 +#define FUNCNAME draw_sprite_f1_ti1_tr1_s1_d1 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 2 +#define _DMODE 1 +#define FUNCNAME draw_sprite_f1_ti1_tr1_s2_d1 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 3 +#define _DMODE 1 +#define FUNCNAME draw_sprite_f1_ti1_tr1_s3_d1 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 4 +#define _DMODE 1 +#define FUNCNAME draw_sprite_f1_ti1_tr1_s4_d1 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 5 +#define _DMODE 1 +#define FUNCNAME draw_sprite_f1_ti1_tr1_s5_d1 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 6 +#define _DMODE 1 +#define FUNCNAME draw_sprite_f1_ti1_tr1_s6_d1 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 7 +#define _DMODE 1 +#define FUNCNAME draw_sprite_f1_ti1_tr1_s7_d1 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +//// + + +#define _SMODE 0 +#define _DMODE 2 +#define FUNCNAME draw_sprite_f1_ti1_tr1_s0_d2 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 1 +#define _DMODE 2 +#define FUNCNAME draw_sprite_f1_ti1_tr1_s1_d2 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 2 +#define _DMODE 2 +#define FUNCNAME draw_sprite_f1_ti1_tr1_s2_d2 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 3 +#define _DMODE 2 +#define FUNCNAME draw_sprite_f1_ti1_tr1_s3_d2 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 4 +#define _DMODE 2 +#define FUNCNAME draw_sprite_f1_ti1_tr1_s4_d2 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 5 +#define _DMODE 2 +#define FUNCNAME draw_sprite_f1_ti1_tr1_s5_d2 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 6 +#define _DMODE 2 +#define FUNCNAME draw_sprite_f1_ti1_tr1_s6_d2 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 7 +#define _DMODE 2 +#define FUNCNAME draw_sprite_f1_ti1_tr1_s7_d2 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +/// + + +#define _SMODE 0 +#define _DMODE 3 +#define FUNCNAME draw_sprite_f1_ti1_tr1_s0_d3 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 1 +#define _DMODE 3 +#define FUNCNAME draw_sprite_f1_ti1_tr1_s1_d3 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 2 +#define _DMODE 3 +#define FUNCNAME draw_sprite_f1_ti1_tr1_s2_d3 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 3 +#define _DMODE 3 +#define FUNCNAME draw_sprite_f1_ti1_tr1_s3_d3 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 4 +#define _DMODE 3 +#define FUNCNAME draw_sprite_f1_ti1_tr1_s4_d3 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 5 +#define _DMODE 3 +#define FUNCNAME draw_sprite_f1_ti1_tr1_s5_d3 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 6 +#define _DMODE 3 +#define FUNCNAME draw_sprite_f1_ti1_tr1_s6_d3 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 7 +#define _DMODE 3 +#define FUNCNAME draw_sprite_f1_ti1_tr1_s7_d3 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +/// + + +#define _SMODE 0 +#define _DMODE 4 +#define FUNCNAME draw_sprite_f1_ti1_tr1_s0_d4 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 1 +#define _DMODE 4 +#define FUNCNAME draw_sprite_f1_ti1_tr1_s1_d4 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 2 +#define _DMODE 4 +#define FUNCNAME draw_sprite_f1_ti1_tr1_s2_d4 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 3 +#define _DMODE 4 +#define FUNCNAME draw_sprite_f1_ti1_tr1_s3_d4 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 4 +#define _DMODE 4 +#define FUNCNAME draw_sprite_f1_ti1_tr1_s4_d4 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 5 +#define _DMODE 4 +#define FUNCNAME draw_sprite_f1_ti1_tr1_s5_d4 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 6 +#define _DMODE 4 +#define FUNCNAME draw_sprite_f1_ti1_tr1_s6_d4 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 7 +#define _DMODE 4 +#define FUNCNAME draw_sprite_f1_ti1_tr1_s7_d4 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +/// + +#define _SMODE 0 +#define _DMODE 5 +#define FUNCNAME draw_sprite_f1_ti1_tr1_s0_d5 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 1 +#define _DMODE 5 +#define FUNCNAME draw_sprite_f1_ti1_tr1_s1_d5 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 2 +#define _DMODE 5 +#define FUNCNAME draw_sprite_f1_ti1_tr1_s2_d5 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 3 +#define _DMODE 5 +#define FUNCNAME draw_sprite_f1_ti1_tr1_s3_d5 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 4 +#define _DMODE 5 +#define FUNCNAME draw_sprite_f1_ti1_tr1_s4_d5 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 5 +#define _DMODE 5 +#define FUNCNAME draw_sprite_f1_ti1_tr1_s5_d5 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 6 +#define _DMODE 5 +#define FUNCNAME draw_sprite_f1_ti1_tr1_s6_d5 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 7 +#define _DMODE 5 +#define FUNCNAME draw_sprite_f1_ti1_tr1_s7_d5 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +/// + +#define _SMODE 0 +#define _DMODE 6 +#define FUNCNAME draw_sprite_f1_ti1_tr1_s0_d6 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 1 +#define _DMODE 6 +#define FUNCNAME draw_sprite_f1_ti1_tr1_s1_d6 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 2 +#define _DMODE 6 +#define FUNCNAME draw_sprite_f1_ti1_tr1_s2_d6 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 3 +#define _DMODE 6 +#define FUNCNAME draw_sprite_f1_ti1_tr1_s3_d6 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 4 +#define _DMODE 6 +#define FUNCNAME draw_sprite_f1_ti1_tr1_s4_d6 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 5 +#define _DMODE 6 +#define FUNCNAME draw_sprite_f1_ti1_tr1_s5_d6 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 6 +#define _DMODE 6 +#define FUNCNAME draw_sprite_f1_ti1_tr1_s6_d6 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 7 +#define _DMODE 6 +#define FUNCNAME draw_sprite_f1_ti1_tr1_s7_d6 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +/// + + +#define _SMODE 0 +#define _DMODE 7 +#define FUNCNAME draw_sprite_f1_ti1_tr1_s0_d7 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 1 +#define _DMODE 7 +#define FUNCNAME draw_sprite_f1_ti1_tr1_s1_d7 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 2 +#define _DMODE 7 +#define FUNCNAME draw_sprite_f1_ti1_tr1_s2_d7 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 3 +#define _DMODE 7 +#define FUNCNAME draw_sprite_f1_ti1_tr1_s3_d7 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 4 +#define _DMODE 7 +#define FUNCNAME draw_sprite_f1_ti1_tr1_s4_d7 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 5 +#define _DMODE 7 +#define FUNCNAME draw_sprite_f1_ti1_tr1_s5_d7 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 6 +#define _DMODE 7 +#define FUNCNAME draw_sprite_f1_ti1_tr1_s6_d7 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 7 +#define _DMODE 7 +#define FUNCNAME draw_sprite_f1_ti1_tr1_s7_d7 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#undef BLENDED + +#undef FLIPX +#undef TINT +#undef TRANSPARENT +#undef REALLY_SIMPLE diff --git a/src/devices/video/epic12_blit7.c b/src/devices/video/epic12_blit7.c new file mode 100644 index 00000000000..6ab5366a721 --- /dev/null +++ b/src/devices/video/epic12_blit7.c @@ -0,0 +1,558 @@ +// license:BSD-3-Clause +// copyright-holders:David Haywood +#define REALLY_SIMPLE 0 +/* X-Flipped, Tinted, Non-Transparent */ +#define FLIPX 1 +#define TINT 1 +#define TRANSPARENT 0 + +#include "emu.h" +#include "epic12.h" + +/* Special Case */ +#define BLENDED 0 +#define FUNCNAME draw_sprite_f1_ti1_tr0_plain +#include "epic12in.inc" +#undef FUNCNAME +#undef BLENDED + +/* Regular Cases*/ +#define BLENDED 1 + +#define _SMODE 0 +#define _DMODE 0 +#define FUNCNAME draw_sprite_f1_ti1_tr0_s0_d0 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 1 +#define _DMODE 0 +#define FUNCNAME draw_sprite_f1_ti1_tr0_s1_d0 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 2 +#define _DMODE 0 +#define FUNCNAME draw_sprite_f1_ti1_tr0_s2_d0 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 3 +#define _DMODE 0 +#define FUNCNAME draw_sprite_f1_ti1_tr0_s3_d0 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 4 +#define _DMODE 0 +#define FUNCNAME draw_sprite_f1_ti1_tr0_s4_d0 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 5 +#define _DMODE 0 +#define FUNCNAME draw_sprite_f1_ti1_tr0_s5_d0 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 6 +#define _DMODE 0 +#define FUNCNAME draw_sprite_f1_ti1_tr0_s6_d0 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 7 +#define _DMODE 0 +#define FUNCNAME draw_sprite_f1_ti1_tr0_s7_d0 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +/////// + + +#define _SMODE 0 +#define _DMODE 1 +#define FUNCNAME draw_sprite_f1_ti1_tr0_s0_d1 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 1 +#define _DMODE 1 +#define FUNCNAME draw_sprite_f1_ti1_tr0_s1_d1 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 2 +#define _DMODE 1 +#define FUNCNAME draw_sprite_f1_ti1_tr0_s2_d1 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 3 +#define _DMODE 1 +#define FUNCNAME draw_sprite_f1_ti1_tr0_s3_d1 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 4 +#define _DMODE 1 +#define FUNCNAME draw_sprite_f1_ti1_tr0_s4_d1 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 5 +#define _DMODE 1 +#define FUNCNAME draw_sprite_f1_ti1_tr0_s5_d1 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 6 +#define _DMODE 1 +#define FUNCNAME draw_sprite_f1_ti1_tr0_s6_d1 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 7 +#define _DMODE 1 +#define FUNCNAME draw_sprite_f1_ti1_tr0_s7_d1 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +//// + + +#define _SMODE 0 +#define _DMODE 2 +#define FUNCNAME draw_sprite_f1_ti1_tr0_s0_d2 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 1 +#define _DMODE 2 +#define FUNCNAME draw_sprite_f1_ti1_tr0_s1_d2 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 2 +#define _DMODE 2 +#define FUNCNAME draw_sprite_f1_ti1_tr0_s2_d2 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 3 +#define _DMODE 2 +#define FUNCNAME draw_sprite_f1_ti1_tr0_s3_d2 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 4 +#define _DMODE 2 +#define FUNCNAME draw_sprite_f1_ti1_tr0_s4_d2 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 5 +#define _DMODE 2 +#define FUNCNAME draw_sprite_f1_ti1_tr0_s5_d2 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 6 +#define _DMODE 2 +#define FUNCNAME draw_sprite_f1_ti1_tr0_s6_d2 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 7 +#define _DMODE 2 +#define FUNCNAME draw_sprite_f1_ti1_tr0_s7_d2 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +/// + + +#define _SMODE 0 +#define _DMODE 3 +#define FUNCNAME draw_sprite_f1_ti1_tr0_s0_d3 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 1 +#define _DMODE 3 +#define FUNCNAME draw_sprite_f1_ti1_tr0_s1_d3 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 2 +#define _DMODE 3 +#define FUNCNAME draw_sprite_f1_ti1_tr0_s2_d3 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 3 +#define _DMODE 3 +#define FUNCNAME draw_sprite_f1_ti1_tr0_s3_d3 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 4 +#define _DMODE 3 +#define FUNCNAME draw_sprite_f1_ti1_tr0_s4_d3 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 5 +#define _DMODE 3 +#define FUNCNAME draw_sprite_f1_ti1_tr0_s5_d3 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 6 +#define _DMODE 3 +#define FUNCNAME draw_sprite_f1_ti1_tr0_s6_d3 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 7 +#define _DMODE 3 +#define FUNCNAME draw_sprite_f1_ti1_tr0_s7_d3 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +/// + + +#define _SMODE 0 +#define _DMODE 4 +#define FUNCNAME draw_sprite_f1_ti1_tr0_s0_d4 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 1 +#define _DMODE 4 +#define FUNCNAME draw_sprite_f1_ti1_tr0_s1_d4 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 2 +#define _DMODE 4 +#define FUNCNAME draw_sprite_f1_ti1_tr0_s2_d4 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 3 +#define _DMODE 4 +#define FUNCNAME draw_sprite_f1_ti1_tr0_s3_d4 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 4 +#define _DMODE 4 +#define FUNCNAME draw_sprite_f1_ti1_tr0_s4_d4 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 5 +#define _DMODE 4 +#define FUNCNAME draw_sprite_f1_ti1_tr0_s5_d4 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 6 +#define _DMODE 4 +#define FUNCNAME draw_sprite_f1_ti1_tr0_s6_d4 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 7 +#define _DMODE 4 +#define FUNCNAME draw_sprite_f1_ti1_tr0_s7_d4 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +/// + +#define _SMODE 0 +#define _DMODE 5 +#define FUNCNAME draw_sprite_f1_ti1_tr0_s0_d5 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 1 +#define _DMODE 5 +#define FUNCNAME draw_sprite_f1_ti1_tr0_s1_d5 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 2 +#define _DMODE 5 +#define FUNCNAME draw_sprite_f1_ti1_tr0_s2_d5 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 3 +#define _DMODE 5 +#define FUNCNAME draw_sprite_f1_ti1_tr0_s3_d5 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 4 +#define _DMODE 5 +#define FUNCNAME draw_sprite_f1_ti1_tr0_s4_d5 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 5 +#define _DMODE 5 +#define FUNCNAME draw_sprite_f1_ti1_tr0_s5_d5 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 6 +#define _DMODE 5 +#define FUNCNAME draw_sprite_f1_ti1_tr0_s6_d5 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 7 +#define _DMODE 5 +#define FUNCNAME draw_sprite_f1_ti1_tr0_s7_d5 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +/// + +#define _SMODE 0 +#define _DMODE 6 +#define FUNCNAME draw_sprite_f1_ti1_tr0_s0_d6 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 1 +#define _DMODE 6 +#define FUNCNAME draw_sprite_f1_ti1_tr0_s1_d6 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 2 +#define _DMODE 6 +#define FUNCNAME draw_sprite_f1_ti1_tr0_s2_d6 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 3 +#define _DMODE 6 +#define FUNCNAME draw_sprite_f1_ti1_tr0_s3_d6 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 4 +#define _DMODE 6 +#define FUNCNAME draw_sprite_f1_ti1_tr0_s4_d6 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 5 +#define _DMODE 6 +#define FUNCNAME draw_sprite_f1_ti1_tr0_s5_d6 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 6 +#define _DMODE 6 +#define FUNCNAME draw_sprite_f1_ti1_tr0_s6_d6 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 7 +#define _DMODE 6 +#define FUNCNAME draw_sprite_f1_ti1_tr0_s7_d6 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +/// + + +#define _SMODE 0 +#define _DMODE 7 +#define FUNCNAME draw_sprite_f1_ti1_tr0_s0_d7 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 1 +#define _DMODE 7 +#define FUNCNAME draw_sprite_f1_ti1_tr0_s1_d7 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 2 +#define _DMODE 7 +#define FUNCNAME draw_sprite_f1_ti1_tr0_s2_d7 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 3 +#define _DMODE 7 +#define FUNCNAME draw_sprite_f1_ti1_tr0_s3_d7 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 4 +#define _DMODE 7 +#define FUNCNAME draw_sprite_f1_ti1_tr0_s4_d7 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 5 +#define _DMODE 7 +#define FUNCNAME draw_sprite_f1_ti1_tr0_s5_d7 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 6 +#define _DMODE 7 +#define FUNCNAME draw_sprite_f1_ti1_tr0_s6_d7 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#define _SMODE 7 +#define _DMODE 7 +#define FUNCNAME draw_sprite_f1_ti1_tr0_s7_d7 +#include "epic12in.inc" +#undef FUNCNAME +#undef _SMODE +#undef _DMODE + +#undef BLENDED + +#undef FLIPX +#undef TINT +#undef TRANSPARENT +#undef REALLY_SIMPLE diff --git a/src/devices/video/epic12_blit8.c b/src/devices/video/epic12_blit8.c new file mode 100644 index 00000000000..fb9cc763395 --- /dev/null +++ b/src/devices/video/epic12_blit8.c @@ -0,0 +1,42 @@ +// license:BSD-3-Clause +// copyright-holders:David Haywood +/* Special case 'Really Simple' blitters, no blending, no tinting etc.*/ + +#include "emu.h" +#include "epic12.h" + + +#define REALLY_SIMPLE 1 +#define BLENDED 0 + +#define TRANSPARENT 1 +#define FLIPX 0 +#define FUNCNAME draw_sprite_f0_ti0_tr1_simple +#include "epic12in.inc" +#undef FUNCNAME +#undef FLIPX + +#define FLIPX 1 +#define FUNCNAME draw_sprite_f1_ti0_tr1_simple +#include "epic12in.inc" +#undef FUNCNAME +#undef FLIPX +#undef TRANSPARENT + + +#define TRANSPARENT 0 +#define FLIPX 0 +#define FUNCNAME draw_sprite_f0_ti0_tr0_simple +#include "epic12in.inc" +#undef FUNCNAME +#undef FLIPX + +#define FLIPX 1 +#define FUNCNAME draw_sprite_f1_ti0_tr0_simple +#include "epic12in.inc" +#undef FUNCNAME +#undef FLIPX +#undef TRANSPARENT + +#undef BLENDED +#undef REALLY_SIMPLE diff --git a/src/devices/video/epic12in.inc b/src/devices/video/epic12in.inc new file mode 100644 index 00000000000..cf0c81dd80f --- /dev/null +++ b/src/devices/video/epic12in.inc @@ -0,0 +1,166 @@ +/* blitter function */ + +void epic12_device::FUNCNAME(BLIT_PARAMS) +{ + UINT32* gfx2; + int y, yf; + +#if REALLY_SIMPLE == 0 + colour_t s_clr; +#endif + +#if BLENDED == 1 + colour_t d_clr; + +#if _SMODE == 2 +#if _DMODE != 0 + colour_t clr0; +#endif +#elif _SMODE == 0 +#if _DMODE != 0 +#if _DMODE != 5 +#if _DMODE != 1 + colour_t clr0; +#endif +#endif +#endif +#else + colour_t clr0; +#endif + + +#endif + +#if REALLY_SIMPLE == 1 +#if TRANSPARENT == 1 + UINT32 pen; +#endif +#else + UINT32 pen; +#endif + UINT32 *bmp; + +#if FLIPX == 1 + src_x += (dimx-1); +#endif + + if (flipy) { yf = -1; src_y += (dimy-1); } + else { yf = +1; } + + int starty = 0; + const int dst_y_end = dst_y_start+dimy; + + if (dst_y_start < clip->min_y) + starty = clip->min_y - dst_y_start; + + if (dst_y_end > clip->max_y) + dimy -= (dst_y_end-1) - clip->max_y; + + // check things are safe to draw (note, if the source would wrap round an edge of the 0x2000*0x1000 vram we don't draw.. not sure what the hw does anyway) + // ddpdfk triggers this on boss explosions so it needs fixing +#if FLIPX == 1 + if ((src_x &0x1fff) < ((src_x-(dimx-1))&0x1fff)) + { + // popmessage("sprite gets clipped off src_x %04x dimx %04x\n", src_x, dimx); + return; + } +#else + if ((src_x &0x1fff) > ((src_x+(dimx-1))&0x1fff)) + { + // popmessage("sprite gets clipped off src_x %04x dimx %04x\n", src_x, dimx); + return; + } +#endif + + int startx = 0; + const int dst_x_end = dst_x_start+dimx; + + if (dst_x_start < clip->min_x) + startx = clip->min_x - dst_x_start; + + if (dst_x_end > clip->max_x) + dimx -= (dst_x_end-1) - clip->max_x; + +// wrong/unsafe slowdown sim + if (dimy > starty && dimx > startx) + { + epic12_device_blit_delay += (dimy - starty)*(dimx - startx); + + //printf("delay is now %d\n", epic12_device_blit_delay); + } + +#if BLENDED == 1 +#if _SMODE == 0 +#if _DMODE == 0 + const UINT8* salpha_table = epic12_device_colrtable[s_alpha]; + const UINT8* dalpha_table = epic12_device_colrtable[d_alpha]; +#endif + +#if _DMODE == 5 + const UINT8* salpha_table = epic12_device_colrtable[s_alpha]; +#endif +#if _DMODE == 1 + const UINT8* salpha_table = epic12_device_colrtable[s_alpha]; +#endif + +#endif + +#if _SMODE == 2 +#if _DMODE == 0 + + const UINT8* dalpha_table = epic12_device_colrtable[d_alpha]; +#endif +#endif +#endif + + + + for (y = starty; y < dimy; y++) + { + bmp = &bitmap->pix(dst_y_start + y, dst_x_start+startx); + const int ysrc_index = ((src_y + yf * y) & 0x0fff) * 0x2000; + gfx2 = gfx + ysrc_index; + + #if FLIPX == 1 + gfx2 += (src_x-startx); + #else + gfx2 += (src_x+startx); + #endif + +#if 1 + const UINT32* end = bmp+(dimx-startx); +#else + // maybe we can do some SSE type optimizations on larger blocks? right now this just results in more code and slower compiling tho. + + const int width = dimx-startx; + const UINT32* end = bmp+(width); + + if (width<0) return; + + int bigblocks = width>>3; + + while (bigblocks) + { + #include "epic12pixel.inc" + #include "epic12pixel.inc" + #include "epic12pixel.inc" + #include "epic12pixel.inc" + #include "epic12pixel.inc" + #include "epic12pixel.inc" + #include "epic12pixel.inc" + #include "epic12pixel.inc" + + bigblocks--; + } +#endif + while (bmp> 3); // using the union is actually significantly slower than our pen_to_clr to function! + // source * intesity and clamp + +#if TINT == 1 + clr_mul(&s_clr.trgb, tint_clr); +#endif + + #if BLENDED == 1 + + // convert destination to clr + pen_to_clr(*bmp, &d_clr.trgb); + //d_clr.u32 = *bmp >> 3; // using the union is actually significantly slower than our pen_to_clr to function! + #if _SMODE == 0 + //g_profiler.start(PROFILER_USER7); + + + #if _DMODE == 0 + //g_profiler.start(PROFILER_USER1); + // this is used extensively in the games (ingame, futari title screens etc.) + + s_clr.trgb.r = epic12_device_colrtable_add[salpha_table[(s_clr.trgb.r)]][dalpha_table[(d_clr.trgb.r)]]; + s_clr.trgb.g = epic12_device_colrtable_add[salpha_table[(s_clr.trgb.g)]][dalpha_table[(d_clr.trgb.g)]]; + s_clr.trgb.b = epic12_device_colrtable_add[salpha_table[(s_clr.trgb.b)]][dalpha_table[(d_clr.trgb.b)]]; + #elif _DMODE == 1 + //g_profiler.start(PROFILER_USER2); + // futari ~7% + s_clr.trgb.r = epic12_device_colrtable_add[salpha_table[(s_clr.trgb.r)]][epic12_device_colrtable[(s_clr.trgb.r)][(d_clr.trgb.r)]]; + s_clr.trgb.g = epic12_device_colrtable_add[salpha_table[(s_clr.trgb.g)]][epic12_device_colrtable[(s_clr.trgb.g)][(d_clr.trgb.g)]]; + s_clr.trgb.b = epic12_device_colrtable_add[salpha_table[(s_clr.trgb.b)]][epic12_device_colrtable[(s_clr.trgb.b)][(d_clr.trgb.b)]]; + #elif _DMODE == 2 + //g_profiler.start(PROFILER_USER3); + clr_mul_fixed(&clr0.trgb, s_alpha, &s_clr.trgb); + clr_add_with_clr_square(&s_clr.trgb, &clr0.trgb, &d_clr.trgb); + #elif _DMODE == 3 + //g_profiler.start(PROFILER_USER4); + clr_mul_fixed(&clr0.trgb, s_alpha, &s_clr.trgb); + clr_add(&s_clr.trgb, &clr0.trgb, &d_clr.trgb); + + #elif _DMODE == 4 + //g_profiler.start(PROFILER_USER5); + clr_mul_fixed(&clr0.trgb, s_alpha, &s_clr.trgb); + clr_add_with_clr_mul_fixed_rev(&s_clr.trgb, &clr0.trgb, d_alpha, &d_clr.trgb); + #elif _DMODE == 5 + // futari black character select ~13% + //g_profiler.start(PROFILER_USER6); + s_clr.trgb.r = epic12_device_colrtable_add[salpha_table[(s_clr.trgb.r)]][epic12_device_colrtable_rev[(s_clr.trgb.r)][(d_clr.trgb.r)]]; + s_clr.trgb.g = epic12_device_colrtable_add[salpha_table[(s_clr.trgb.g)]][epic12_device_colrtable_rev[(s_clr.trgb.g)][(d_clr.trgb.g)]]; + s_clr.trgb.b = epic12_device_colrtable_add[salpha_table[(s_clr.trgb.b)]][epic12_device_colrtable_rev[(s_clr.trgb.b)][(d_clr.trgb.b)]]; + + #elif _DMODE == 6 + //g_profiler.start(PROFILER_USER7); + clr_mul_fixed(&clr0.trgb, s_alpha, &s_clr.trgb); + clr_add_with_clr_mul_rev_square(&s_clr.trgb, &clr0.trgb, &d_clr.trgb); + #elif _DMODE == 7 + //g_profiler.start(PROFILER_USER8); + clr_mul_fixed(&clr0.trgb, s_alpha, &s_clr.trgb); + clr_add(&s_clr.trgb, &clr0.trgb, &d_clr.trgb); + #endif + + //g_profiler.stop(); + #elif _SMODE == 1 + //g_profiler.start(PROFILER_USER6); + clr_square(&clr0.trgb, &s_clr.trgb); + + #elif _SMODE == 2 + // g_profiler.start(PROFILER_USER4); + #if _DMODE == 0 + // this is used heavily on espgal2 highscore screen (~28%) optimized to avoid use of temp clr0 variable + s_clr.trgb.r = epic12_device_colrtable_add[epic12_device_colrtable[(d_clr.trgb.r)][(s_clr.trgb.r)]][dalpha_table[(d_clr.trgb.r)]]; + s_clr.trgb.g = epic12_device_colrtable_add[epic12_device_colrtable[(d_clr.trgb.g)][(s_clr.trgb.g)]][dalpha_table[(d_clr.trgb.g)]]; + s_clr.trgb.b = epic12_device_colrtable_add[epic12_device_colrtable[(d_clr.trgb.b)][(s_clr.trgb.b)]][dalpha_table[(d_clr.trgb.b)]]; + #elif _DMODE == 1 + clr_mul_3param(&clr0.trgb, &s_clr.trgb, &d_clr.trgb); + clr_add_with_clr_mul_3param(&s_clr.trgb, &clr0.trgb, &d_clr.trgb, &s_clr.trgb); + #elif _DMODE == 2 + clr_mul_3param(&clr0.trgb, &s_clr.trgb, &d_clr.trgb); + clr_add_with_clr_square(&s_clr.trgb, &clr0.trgb, &d_clr.trgb); + #elif _DMODE == 3 + clr_mul_3param(&clr0.trgb, &s_clr.trgb, &d_clr.trgb); + clr_add(&s_clr.trgb, &clr0.trgb, &d_clr.trgb); + + #elif _DMODE == 4 + clr_mul_3param(&clr0.trgb, &s_clr.trgb, &d_clr.trgb); + clr_add_with_clr_mul_fixed_rev(&s_clr.trgb, &clr0.trgb, d_alpha, &d_clr.trgb); + #elif _DMODE == 5 + clr_mul_3param(&clr0.trgb, &s_clr.trgb, &d_clr.trgb); + clr_add_with_clr_mul_rev_3param(&s_clr.trgb, &clr0.trgb, &d_clr.trgb, &s_clr.trgb); + #elif _DMODE == 6 + clr_mul_3param(&clr0.trgb, &s_clr.trgb, &d_clr.trgb); + clr_add_with_clr_mul_rev_square(&s_clr.trgb, &clr0.trgb, &d_clr.trgb); + #elif _DMODE == 7 + clr_mul_3param(&clr0.trgb, &s_clr.trgb, &d_clr.trgb); + clr_add(&s_clr.trgb, &clr0.trgb, &d_clr.trgb); + #endif + //g_profiler.stop(); + + #elif _SMODE == 3 + //g_profiler.start(PROFILER_USER1); + clr_copy(&clr0.trgb, &s_clr.trgb); + + #elif _SMODE == 4 + //g_profiler.start(PROFILER_USER2); + clr_mul_fixed_rev(&clr0.trgb, s_alpha, &s_clr.trgb); + #elif _SMODE == 5 + //g_profiler.start(PROFILER_USER3); + clr_mul_rev_square(&clr0.trgb, &s_clr.trgb); + #elif _SMODE == 6 + //g_profiler.start(PROFILER_USER4); + clr_mul_rev_3param(&clr0.trgb, &s_clr.trgb, &d_clr.trgb); + #elif _SMODE == 7 + //g_profiler.start(PROFILER_USER5); + clr_copy(&clr0.trgb, &s_clr.trgb); + #endif + + +// smode 0/2 cases are already split up and handled above. +#if _SMODE != 2 +#if _SMODE != 0 + + #if _DMODE == 0 + clr_add_with_clr_mul_fixed(&s_clr.trgb, &clr0.trgb, d_alpha, &d_clr.trgb); + #elif _DMODE == 1 + clr_add_with_clr_mul_3param(&s_clr.trgb, &clr0.trgb, &d_clr.trgb, &s_clr.trgb); + #elif _DMODE == 2 + clr_add_with_clr_square(&s_clr.trgb, &clr0.trgb, &d_clr.trgb); + #elif _DMODE == 3 + clr_add(&s_clr.trgb, &clr0.trgb, &d_clr.trgb); + + #elif _DMODE == 4 + clr_add_with_clr_mul_fixed_rev(&s_clr.trgb, &clr0.trgb, d_alpha, &d_clr.trgb); + #elif _DMODE == 5 + clr_add_with_clr_mul_rev_3param(&s_clr.trgb, &clr0.trgb, &d_clr.trgb, &s_clr.trgb); + #elif _DMODE == 6 + clr_add_with_clr_mul_rev_square(&s_clr.trgb, &clr0.trgb, &d_clr.trgb); + #elif _DMODE == 7 + clr_add(&s_clr.trgb, &clr0.trgb, &d_clr.trgb); + #endif + + //g_profiler.stop(); +#endif +#endif + + + #endif + + // write result + *bmp = clr_to_pen(&s_clr.trgb)|(pen&0x20000000); + //*bmp = (s_clr.u32<<3)|(pen&0x20000000); // using the union is actually significantly slower than our clr_to_pen function! + +#endif // END NOT REALLY SIMPLE + +#if TRANSPARENT == 1 + } +#endif + LOOP_INCREMENTS diff --git a/src/devices/video/fixfreq.c b/src/devices/video/fixfreq.c new file mode 100644 index 00000000000..033bcb5b301 --- /dev/null +++ b/src/devices/video/fixfreq.c @@ -0,0 +1,304 @@ +// license:BSD-3-Clause +// copyright-holders:Couriersud +/*************************************************************************** + + fixfreq.h + + 2013 Couriersud + + Fixed frequency monochrome monitor emulation + + The driver is intended for drivers which provide an analog video signal. + VSYNC and HSYNC levels are used to create the bitmap. + +***************************************************************************/ + +#include "emu.h" +#include "fixfreq.h" + +/*************************************************************************** + + Local variables + +***************************************************************************/ + +//#define VERBOSE_OUT(x) printf x +#define VERBOSE_OUT(x) + +/*************************************************************************** + + Fixed frequency monitor + +***************************************************************************/ +// device type definition +const device_type FIXFREQ = &device_creator; + +fixedfreq_device::fixedfreq_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_video_interface(mconfig, *this, false), + // default to NTSC "704x480@30i" + m_monitor_clock(13500000), + m_hvisible(704), + m_hfrontporch(728), + m_hsync(791), + m_hbackporch(858), + m_vvisible(480), + m_vfrontporch(486), + m_vsync(492), + m_vbackporch(525), + m_fieldcount(2), + m_sync_threshold(0.3), + m_gain(1.0 / 3.7) +{ +} + +fixedfreq_device::fixedfreq_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, FIXFREQ, "Fixed Frequency Monochrome Monitor", tag, owner, clock, "fixfreq", __FILE__), + device_video_interface(mconfig, *this, false), + // default to NTSC "704x480@30i" + m_monitor_clock(13500000), + m_hvisible(704), + m_hfrontporch(728), + m_hsync(791), + m_hbackporch(858), + m_vvisible(480), + m_vfrontporch(486), + m_vsync(492), + m_vbackporch(525), + m_fieldcount(2), + m_sync_threshold(0.3), + m_gain(1.0 / 3.7) +{ +} + +void fixedfreq_device::device_start() +{ + m_htotal = 0; + m_vtotal = 0; + + m_vid = 0.0; + m_last_x = 0; + m_last_y = 0; + m_last_time = attotime::zero; + m_line_time = attotime::zero; + m_last_hsync_time = attotime::zero; + m_last_vsync_time = attotime::zero; + m_refresh = attotime::zero; + m_clock_period = attotime::zero; + //bitmap_rgb32 *m_bitmap[2]; + m_cur_bm = 0; + + /* sync separator */ + m_vint = 0.0; + m_int_trig = 0.0; + m_mult = 0.0; + + m_sig_vsync = 0; + m_sig_composite = 0; + m_sig_field = 0; + + m_bitmap[0] = NULL; + m_bitmap[1] = NULL; + //m_vblank_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(vga_device::vblank_timer_cb),this)); + recompute_parameters(false); + + save_item(NAME(m_vid)); + save_item(NAME(m_last_x)); + save_item(NAME(m_last_y)); + save_item(NAME(m_last_time)); + save_item(NAME(m_line_time)); + save_item(NAME(m_last_hsync_time)); + save_item(NAME(m_last_vsync_time)); + save_item(NAME(m_refresh)); + save_item(NAME(m_clock_period)); + //save_item(NAME(m_bitmap[0])); + //save_item(NAME(m_bitmap[1])); + save_item(NAME(m_cur_bm)); + + /* sync separator */ + save_item(NAME(m_vint)); + save_item(NAME(m_int_trig)); + save_item(NAME(m_mult)); + + save_item(NAME(m_sig_vsync)); + save_item(NAME(m_sig_composite)); + save_item(NAME(m_sig_field)); + + + +} + +void fixedfreq_device::device_reset() +{ + m_last_time = attotime::zero; + m_line_time = attotime::zero; + m_last_hsync_time = attotime::zero; + m_last_vsync_time = attotime::zero; + m_vint = 0; + +} + + +void fixedfreq_device::device_post_load() +{ + //recompute_parameters(true); +} + +void fixedfreq_device::recompute_parameters(bool postload) +{ + bool needs_realloc = (m_htotal != m_hbackporch) && (m_vtotal != m_vbackporch); + + if (m_bitmap[0] != NULL || needs_realloc) + auto_free(machine(), m_bitmap[0]); + if (m_bitmap[1] != NULL || needs_realloc) + auto_free(machine(), m_bitmap[0]); + + m_htotal = m_hbackporch; + m_vtotal = m_vbackporch; + + /* sync separator */ + + m_int_trig = (exp(- 3.0/(3.0+3.0))) - exp(-1.0); + m_mult = (double) (m_monitor_clock) / (double) m_htotal * 1.0; // / (3.0 + 3.0); + VERBOSE_OUT(("trigger %f with len %f\n", m_int_trig, 1e6 / m_mult)); + + m_bitmap[0] = auto_bitmap_rgb32_alloc(machine(),m_htotal, m_vtotal); + m_bitmap[1] = auto_bitmap_rgb32_alloc(machine(),m_htotal, m_vtotal); + + rectangle visarea( + m_hbackporch - m_hfrontporch, + m_hbackporch - m_hfrontporch + m_hvisible - 1, + m_vbackporch - m_vfrontporch, + m_vbackporch - m_vfrontporch + m_vvisible - 1); + + m_clock_period = attotime::from_hz(m_monitor_clock); + + m_refresh = attotime::from_hz(m_monitor_clock) * m_vtotal * m_htotal; + screen().configure(m_htotal, m_vtotal, visarea, m_refresh.as_attoseconds()); +} + +void fixedfreq_device::update_screen_parameters(const attotime &refresh) +{ + rectangle visarea( +// m_hsync - m_hvisible, +// m_hsync - 1 , + m_hbackporch - m_hfrontporch, + m_hbackporch - m_hfrontporch + m_hvisible - 1, + m_vbackporch - m_vfrontporch, + m_vbackporch - m_vfrontporch + m_vvisible - 1); + + m_refresh = refresh; + screen().configure(m_htotal, m_vtotal, visarea, m_refresh.as_attoseconds()); +} + +int fixedfreq_device::sync_separator(const attotime &time, double newval) +{ + int last_vsync = m_sig_vsync; + int last_comp = m_sig_composite; + int ret = 0; + + m_vint += ((double) last_comp - m_vint) * (1.0 - exp(-time.as_double() * m_mult)); + m_sig_composite = (newval < m_sync_threshold) ? 1 : 0 ; + + m_sig_vsync = (m_vint > m_int_trig) ? 1 : 0; + + if (!last_vsync && m_sig_vsync) + { + /* TODO - time since last hsync and field detection */ + ret |= 1; + } + if (last_vsync && !m_sig_vsync) + { + m_sig_field = last_comp; /* force false-progressive */ + m_sig_field = (m_sig_field ^ 1) ^ last_comp; /* if there is no field switch, auto switch */ + VERBOSE_OUT(("Field: %d\n", m_sig_field)); + } + if (!last_comp && m_sig_composite) + { + /* TODO - time since last hsync and field detection */ + ret |= 2; + } + if (last_comp && !m_sig_composite) + { + /* falling composite */ + ret |= 4; + } + return ret; +} + +UINT32 fixedfreq_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + copybitmap(bitmap, *m_bitmap[!m_cur_bm], 0, 0, 0, 0, cliprect); + + return 0; +} + +NETDEV_ANALOG_CALLBACK_MEMBER(fixedfreq_device::update_vid) +{ + bitmap_rgb32 *bm = m_bitmap[m_cur_bm]; + const int has_fields = (m_fieldcount > 1) ? 1: 0; + + int pixels = round((time - m_line_time).as_double() / m_clock_period.as_double()); + attotime delta_time = (time - m_last_time); + + if (data == m_vid) + return; + + ATTR_UNUSED int sync = sync_separator(delta_time, data); + + if (m_last_y < bm->height()) + { + rgb_t col; + + if (m_vid < m_sync_threshold) + // Mark sync areas + col = rgb_t(255, 0, 0); + else + { + int colv = (int) ((m_vid - m_sync_threshold) * m_gain * 255.0); + if (colv > 255) + colv = 255; + col = rgb_t(colv, colv, colv); + } + + bm->plot_box(m_last_x, m_last_y + m_sig_field * has_fields, pixels - m_last_x, 1, col); + m_last_x = pixels; + } + if (sync & 1) + { + VERBOSE_OUT(("VSYNC %d %d\n", pixels, m_last_y + m_sig_field)); + } + if (sync & 2) + { + VERBOSE_OUT(("HSYNC up %d\n", pixels)); + //if (m_last_y == 27) printf("HSYNC up %d %d\n", m_last_y, pixels); + } + if (sync & 4) + { + VERBOSE_OUT(("HSYNC down %f %d %f\n", time.as_double()* 1e6, pixels, m_vid)); + } + + if (sync & 1) + { + m_last_y = m_vbackporch - m_vsync; + // toggle bitmap + m_cur_bm ^= 1; + update_screen_parameters(time - m_last_vsync_time); + m_last_vsync_time = time; + } + + // FIXME: pixels > 50 filters some spurious hysnc on line 27 in breakout + if ((sync & 2) && !m_sig_vsync && (pixels > 100)) + { + m_last_y += m_fieldcount; + m_last_x = 0; + m_line_time = time; + } + + m_last_time = time; + m_vid = data; + +} + + +/***************************************************************************/ diff --git a/src/devices/video/fixfreq.h b/src/devices/video/fixfreq.h new file mode 100644 index 00000000000..833829fbc3b --- /dev/null +++ b/src/devices/video/fixfreq.h @@ -0,0 +1,163 @@ +// license:BSD-3-Clause +// copyright-holders:Couriersud +/*************************************************************************** + + fixfreq.h + + Fixed frequency monochrome monitor emulation + + The driver is intended for drivers which provide an analog video signal. + VSYNC and HSYNC levels are used to create the bitmap. + +***************************************************************************/ + +#ifndef FIXFREQ_H +#define FIXFREQ_H + +#include "emu.h" +#include "machine/netlist.h" + +#define FIXFREQ_INTERFACE(name) \ + const fixedfreq_interface (name) = + +#define MCFG_FIXFREQ_ADD(_tag, _screen_tag) \ + MCFG_SCREEN_ADD(_screen_tag, RASTER) \ + MCFG_SCREEN_RAW_PARAMS(13500000, 858, 0, 858, 525, 0, 525) \ + MCFG_SCREEN_UPDATE_DEVICE(_tag, fixedfreq_device, screen_update) \ + MCFG_DEVICE_ADD(_tag, FIXFREQ, 0) \ + MCFG_VIDEO_SET_SCREEN(_screen_tag) + +#define MCFG_FIXFREQ_MONITOR_CLOCK(_clock) \ + fixedfreq_device::set_minitor_clock(*device, _clock); + +#define MCFG_FIXFREQ_HORZ_PARAMS(_visible, _frontporch, _sync, _backporch) \ + fixedfreq_device::set_horz_params(*device, _visible, _frontporch, _sync, _backporch); + +#define MCFG_FIXFREQ_VERT_PARAMS(_visible, _frontporch, _sync, _backporch) \ + fixedfreq_device::set_vert_params(*device, _visible, _frontporch, _sync, _backporch); + +#define MCFG_FIXFREQ_FIELDCOUNT(_count) \ + fixedfreq_device::set_fieldcount(*device, _count); + +#define MCFG_FIXFREQ_SYNC_THRESHOLD(_threshold) \ + fixedfreq_device::set_threshold(*device, _threshold); + +#define MCFG_FIXFREQ_GAIN(_gain) \ + fixedfreq_device::set_gain(*device, _gain); + +// pre-defined configurations + +//ModeLine "720x480@30i" 13.5 720 736 799 858 480 486 492 525 interlace -hsync -vsync +#define MCFG_FIXFREQ_MODE_NTSC720 \ + MCFG_FIXFREQ_MONITOR_CLOCK(13500000) \ + MCFG_FIXFREQ_HORZ_PARAMS(720, 736, 799, 858) \ + MCFG_FIXFREQ_VERT_PARAMS(480, 486, 492, 525) \ + MCFG_FIXFREQ_FIELDCOUNT(2) \ + MCFG_FIXFREQ_SYNC_THRESHOLD(0.3) + +//ModeLine "704x480@30i" 13.5 704 728 791 858 480 486 492 525 +#define MCFG_FIXFREQ_MODE_NTSC704 \ + MCFG_FIXFREQ_MONITOR_CLOCK(13500000) \ + MCFG_FIXFREQ_HORZ_PARAMS(704, 728, 791, 858) \ + MCFG_FIXFREQ_VERT_PARAMS(480, 486, 492, 525) \ + MCFG_FIXFREQ_FIELDCOUNT(2) \ + MCFG_FIXFREQ_SYNC_THRESHOLD(0.3) + + +// ======================> vga_device + +class fixedfreq_device : public device_t, + public device_video_interface +{ +public: + // construction/destruction + fixedfreq_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + fixedfreq_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + // inline configuration helpers + static void set_minitor_clock(device_t &device, UINT32 clock) { downcast(device).m_monitor_clock = clock; } + static void set_fieldcount(device_t &device, int count) { downcast(device).m_fieldcount = count; } + static void set_threshold(device_t &device, double threshold) { downcast(device).m_sync_threshold = threshold; } + static void set_gain(device_t &device, double gain) { downcast(device).m_gain = gain; } + static void set_horz_params(device_t &device, int visible, int frontporch, int sync, int backporch) + { + fixedfreq_device &dev = downcast(device); + dev.m_hvisible = visible; + dev.m_hfrontporch = frontporch; + dev.m_hsync = sync; + dev.m_hbackporch = backporch; + } + static void set_vert_params(device_t &device, int visible, int frontporch, int sync, int backporch) + { + fixedfreq_device &dev = downcast(device); + dev.m_vvisible = visible; + dev.m_vfrontporch = frontporch; + dev.m_vsync = sync; + dev.m_vbackporch = backporch; + } + + virtual UINT32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); + + NETDEV_ANALOG_CALLBACK_MEMBER(update_vid); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_post_load(); + //virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + void recompute_parameters(bool postload); + void update_screen_parameters(const attotime &refresh); + +private: + + int sync_separator(const attotime &time, double newval); + + int m_htotal; + int m_vtotal; + + double m_vid; + int m_last_x; + int m_last_y; + attotime m_last_time; + attotime m_line_time; + attotime m_last_hsync_time; + attotime m_last_vsync_time; + attotime m_refresh; + attotime m_clock_period; + bitmap_rgb32 *m_bitmap[2]; + int m_cur_bm; + + /* adjustable by drivers */ + UINT32 m_monitor_clock; + int m_hvisible; + int m_hfrontporch; + int m_hsync; + int m_hbackporch; + int m_vvisible; + int m_vfrontporch; + int m_vsync; + int m_vbackporch; + int m_fieldcount; + double m_sync_threshold; + double m_gain; + + /* sync separator */ + double m_vint; + double m_int_trig; + double m_mult; + + int m_sig_vsync; + int m_sig_composite; + int m_sig_field; + +protected: + +}; + + +// device type definition +extern const device_type FIXFREQ; + +#endif /* FIXFREQ_H */ diff --git a/src/devices/video/generic.c b/src/devices/video/generic.c new file mode 100644 index 00000000000..e9356e05037 --- /dev/null +++ b/src/devices/video/generic.c @@ -0,0 +1,94 @@ +// license:BSD-3-Clause +// copyright-holders:Nicola Salmoria +/********************************************************************* + + generic.c + + Generic simple video functions. + +*********************************************************************/ + +#include "emu.h" + + + +/*************************************************************************** + COMMON GRAPHICS LAYOUTS +***************************************************************************/ + +const gfx_layout gfx_8x8x1 = +{ + 8,8, + RGN_FRAC(1,1), + 1, + { RGN_FRAC(0,1) }, + { STEP8(0,1) }, + { STEP8(0,8) }, + 8*8 +}; + +const gfx_layout gfx_8x8x2_planar = +{ + 8,8, + RGN_FRAC(1,2), + 2, + { RGN_FRAC(1,2), RGN_FRAC(0,2) }, + { STEP8(0,1) }, + { STEP8(0,8) }, + 8*8 +}; + +const gfx_layout gfx_8x8x3_planar = +{ + 8,8, + RGN_FRAC(1,3), + 3, + { RGN_FRAC(2,3), RGN_FRAC(1,3), RGN_FRAC(0,3) }, + { STEP8(0,1) }, + { STEP8(0,8) }, + 8*8 +}; + +const gfx_layout gfx_8x8x4_planar = +{ + 8,8, + RGN_FRAC(1,4), + 4, + { RGN_FRAC(3,4), RGN_FRAC(2,4), RGN_FRAC(1,4), RGN_FRAC(0,4) }, + { STEP8(0,1) }, + { STEP8(0,8) }, + 8*8 +}; + +const gfx_layout gfx_8x8x5_planar = +{ + 8,8, + RGN_FRAC(1,5), + 5, + { RGN_FRAC(4,5), RGN_FRAC(3,5), RGN_FRAC(2,5), RGN_FRAC(1,5), RGN_FRAC(0,5) }, + { STEP8(0,1) }, + { STEP8(0,8) }, + 8*8 +}; + +const gfx_layout gfx_8x8x6_planar = +{ + 8,8, + RGN_FRAC(1,6), + 6, + { RGN_FRAC(5,6), RGN_FRAC(4,6), RGN_FRAC(3,6), RGN_FRAC(2,6), RGN_FRAC(1,6), RGN_FRAC(0,6) }, + { STEP8(0,1) }, + { STEP8(0,8) }, + 8*8 +}; + +const gfx_layout gfx_16x16x4_planar = +{ + 16,16, + RGN_FRAC(1,4), + 4, + { RGN_FRAC(3,4), RGN_FRAC(2,4), RGN_FRAC(1,4), RGN_FRAC(0,4) }, + { STEP16(0,1) }, + { STEP16(0,16) }, + 16*16 +}; diff --git a/src/devices/video/generic.h b/src/devices/video/generic.h new file mode 100644 index 00000000000..5f2ef27966c --- /dev/null +++ b/src/devices/video/generic.h @@ -0,0 +1,31 @@ +// license:BSD-3-Clause +// copyright-holders:Nicola Salmoria +/********************************************************************* + + generic.h + + Generic simple video functions. + +*********************************************************************/ + +#pragma once + +#ifndef __VIDEO_GENERIC_H__ +#define __VIDEO_GENERIC_H__ + + + +/*************************************************************************** + COMMON GRAPHICS LAYOUTS +***************************************************************************/ + +extern const gfx_layout gfx_8x8x1; +extern const gfx_layout gfx_8x8x2_planar; +extern const gfx_layout gfx_8x8x3_planar; +extern const gfx_layout gfx_8x8x4_planar; +extern const gfx_layout gfx_8x8x5_planar; +extern const gfx_layout gfx_8x8x6_planar; + +extern const gfx_layout gfx_16x16x4_planar; + +#endif /* __VIDEO_GENERIC_H__ */ diff --git a/src/devices/video/gf4500.c b/src/devices/video/gf4500.c new file mode 100644 index 00000000000..48e2f8495c3 --- /dev/null +++ b/src/devices/video/gf4500.c @@ -0,0 +1,184 @@ +// license:BSD-3-Clause +// copyright-holders:Tim Schuerewegen +/* + + NVIDIA GoForce 4500 + + (c) 2010 Tim Schuerewegen + +*/ + +#include "emu.h" +#include "video/gf4500.h" + +#define VERBOSE_LEVEL ( 0 ) + +INLINE void ATTR_PRINTF(3,4) verboselog( running_machine &machine, int n_level, const char *s_fmt, ...) +{ + if (VERBOSE_LEVEL >= n_level) + { + va_list v; + char buf[32768]; + va_start(v, s_fmt); + vsprintf(buf, s_fmt, v); + va_end(v); + logerror("%s: %s", machine.describe_context(), buf); + } +} + +#define BIT(x,n) (((x)>>(n))&1) +#define BITS(x,m,n) (((x)>>(n))&(((UINT32)1<<((m)-(n)+1))-1)) + +#define GF4500_FRAMEBUF_OFFSET 0x20000 + + +const device_type GF4500 = &device_creator; + + +gf4500_device::gf4500_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, GF4500, "NVIDIA GoForce 4500", tag, owner, clock, "gf4500", __FILE__) +{ +} + + +//------------------------------------------------- +// device_config_complete - perform any +// operations now that the configuration is +// complete +//------------------------------------------------- + +void gf4500_device::device_config_complete() +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void gf4500_device::device_start() +{ + m_data = auto_alloc_array_clear(machine(), UINT32, 0x140000/4); + + save_pointer(NAME(m_data), 0x140000/4); + save_item(NAME(m_screen_x)); + save_item(NAME(m_screen_y)); + save_item(NAME(m_screen_x_max)); + save_item(NAME(m_screen_y_max)); + save_item(NAME(m_screen_x_min)); + save_item(NAME(m_screen_y_min)); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void gf4500_device::device_reset() +{ + m_screen_x = m_screen_y = 0; + m_screen_x_max = m_screen_y_max = m_screen_x_min = m_screen_y_min = 0; +} + + +void gf4500_device::vram_write16( UINT16 data ) +{ + if ((m_screen_x < m_screen_x_max) && (m_screen_y < m_screen_y_max)) + { + UINT16 *vram = (UINT16 *)((UINT8 *)m_data + GF4500_FRAMEBUF_OFFSET + (((m_screen_y_min + m_screen_y) * (320 + 1)) + (m_screen_x_min + m_screen_x)) * 2); + *vram = data; + m_screen_x++; + } +} + +static rgb_t gf4500_get_color_16( UINT16 data ) +{ + UINT8 r, g, b; + r = BITS(data, 15, 11) << 3; + g = BITS(data, 10, 5) << 2; + b = BITS(data, 4, 0) << 3; + return rgb_t(r, g, b); +} + +UINT32 gf4500_device::screen_update(screen_device &device, bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + UINT16 *vram = (UINT16 *)(m_data + GF4500_FRAMEBUF_OFFSET / 4); + int x, y; + for (y = 0; y < 240; y++) + { + UINT32 *scanline = &bitmap.pix32(y); + for (x = 0; x < 320; x++) + { + *scanline++ = gf4500_get_color_16(*vram++); + } + vram += 1; + } + return 0; +} + +READ32_MEMBER( gf4500_device::read ) +{ + UINT32 data = m_data[offset]; + switch (offset) + { + case 0x4c / 4: + data = 0x00145000; + break; + } + if ((offset < (GF4500_FRAMEBUF_OFFSET / 4)) || (offset >= ((GF4500_FRAMEBUF_OFFSET + (321 * 240 * 2)) / 4))) + { + verboselog(machine(), 9, "(GFO) %08X -> %08X\n", 0x34000000 + (offset << 2), data); + } + return data; +} + +WRITE32_MEMBER( gf4500_device::write ) +{ + COMBINE_DATA(&m_data[offset]); + if ((offset < (GF4500_FRAMEBUF_OFFSET / 4)) || (offset >= ((GF4500_FRAMEBUF_OFFSET + (321 * 240 * 2)) / 4))) + { + verboselog(machine(), 9, "(GFO) %08X <- %08X\n", 0x34000000 + (offset << 2), data); + } + switch (offset) + { + case 0x300 / 4 : + m_screen_x = m_screen_y = 0; + break; + case 0x304 / 4 : + m_screen_x_max = (data >> 0) & 0xFFFF; + m_screen_y_max = (data >> 16) & 0xFFFF; + if (m_screen_x_max & 1) m_screen_x_min++; + //if (screen_y_max & 1) screen_y_min++; + break; + case 0x308 / 4 : + m_screen_x_min = (data >> 0) & 0xFFFF; + m_screen_y_min = (data >> 16) & 0xFFFF; + if (m_screen_x_min & 1) m_screen_x_min--; + //if (screen_y_min & 1) screen_y_min--; + break; + } + if ((offset >= (0x200 / 4)) && (offset < (0x280 / 4))) + { +// 'maincpu' (02996998): (GFO) 34000304 <- 00F00140 +// 'maincpu' (029969A8): (GFO) 34000308 <- 00000000 +// 'maincpu' (029969B4): (GFO) 34000324 <- 00000000 +// 'maincpu' (029969C4): (GFO) 34000328 <- 40000282 +// 'maincpu' (029969D4): (GFO) 34000300 <- 001022CC +// +// 'maincpu' (01DCC55C): (GFO) 34000024 -> 00000000 +// 'maincpu' (02996A24): (GFO) 34000200 <- AE9FAE9F +// +// 'maincpu' (02996A24): (GFO) 3400027C <- AE9FAE9F +// +// 'maincpu' (01DCC55C): (GFO) 34000024 -> 00000000 +// 'maincpu' (02996A24): (GFO) 34000200 <- AE9FAE9F +// ... +// 'maincpu' (02996A24): (GFO) 3400027C <- AE9FAE9F + + vram_write16((data >> 0) & 0xFFFF); + vram_write16((data >> 16) & 0xFFFF); + if (m_screen_x >= m_screen_x_max) + { + m_screen_x = 0; + m_screen_y++; + } + } +} diff --git a/src/devices/video/gf4500.h b/src/devices/video/gf4500.h new file mode 100644 index 00000000000..eb246ec0ea9 --- /dev/null +++ b/src/devices/video/gf4500.h @@ -0,0 +1,56 @@ +// license:BSD-3-Clause +// copyright-holders:Tim Schuerewegen +/* + + NVIDIA GoForce 4500 + + (c) 2010 Tim Schuerewegen + +*/ + +#ifndef __GF4500_H__ +#define __GF4500_H__ + + +class gf4500_device : public device_t +{ +public: + gf4500_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + ~gf4500_device() {} + + + DECLARE_READ32_MEMBER( read ); + DECLARE_WRITE32_MEMBER( write ); + + UINT32 screen_update(screen_device &device, bitmap_rgb32 &bitmap, const rectangle &cliprect); + +protected: + // device-level overrides + virtual void device_config_complete(); + virtual void device_start(); + virtual void device_reset(); + +private: + // internal state + + void vram_write16(UINT16 data); + + UINT32 *m_data; + int m_screen_x; + int m_screen_y; + int m_screen_x_max; + int m_screen_y_max; + int m_screen_x_min; + int m_screen_y_min; +}; + + + +#define MCFG_GF4500_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, GF4500, 0) + + +extern const device_type GF4500; + + +#endif /* __GF4500_H__ */ diff --git a/src/devices/video/gf7600gs.c b/src/devices/video/gf7600gs.c new file mode 100644 index 00000000000..85b6b2f06da --- /dev/null +++ b/src/devices/video/gf7600gs.c @@ -0,0 +1,33 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +#include "gf7600gs.h" + +const device_type GEFORCE_7600GS = &device_creator; + +DEVICE_ADDRESS_MAP_START(map1, 32, geforce_7600gs_device) +ADDRESS_MAP_END + +DEVICE_ADDRESS_MAP_START(map2, 32, geforce_7600gs_device) +ADDRESS_MAP_END + +DEVICE_ADDRESS_MAP_START(map3, 32, geforce_7600gs_device) +ADDRESS_MAP_END + +geforce_7600gs_device::geforce_7600gs_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : pci_device(mconfig, GEFORCE_7600GS, "NVidia GeForce 7600GS", tag, owner, clock, "geforce_7600gs", __FILE__) +{ +} + +void geforce_7600gs_device::device_start() +{ + pci_device::device_start(); + add_map( 16*1024*1024, M_MEM, FUNC(geforce_7600gs_device::map1)); + add_map(256*1024*1024, M_MEM, FUNC(geforce_7600gs_device::map2)); + add_map( 16*1024*1024, M_MEM, FUNC(geforce_7600gs_device::map3)); + add_rom_from_region(); +} + +void geforce_7600gs_device::device_reset() +{ + pci_device::device_reset(); +} diff --git a/src/devices/video/gf7600gs.h b/src/devices/video/gf7600gs.h new file mode 100644 index 00000000000..1d336ee5454 --- /dev/null +++ b/src/devices/video/gf7600gs.h @@ -0,0 +1,27 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +#ifndef GF7600GS_H +#define GF7600GS_H + +#include "machine/pci.h" + +#define MCFG_GEFORCE_7600GS_ADD(_tag, _subdevice_id) \ + MCFG_AGP_DEVICE_ADD(_tag, GEFORCE_7600GS, 0x10de02e1, 0xa1, _subdevice_id) + +class geforce_7600gs_device : public pci_device { +public: + geforce_7600gs_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual void device_start(); + virtual void device_reset(); + +private: + DECLARE_ADDRESS_MAP(map1, 32); + DECLARE_ADDRESS_MAP(map2, 32); + DECLARE_ADDRESS_MAP(map3, 32); +}; + +extern const device_type GEFORCE_7600GS; + +#endif diff --git a/src/devices/video/h63484.c b/src/devices/video/h63484.c new file mode 100644 index 00000000000..906c01573e4 --- /dev/null +++ b/src/devices/video/h63484.c @@ -0,0 +1,2190 @@ +// license:BSD-3-Clause +// copyright-holders:Angelo Salese, Sandro Ronco +/*************************************************************************** + + HD63484 ACRTC (rewrite in progress) + + TODO: + - 8-bit support for FIFO, parameters and command values + - execution cycles; + +***************************************************************************/ + +#include "emu.h" +#include "h63484.h" + +#define LOG 0 +#define FIFO_LOG 0 +#define CMD_LOG 0 + +// default address map +static ADDRESS_MAP_START( h63484_vram, AS_0, 16, h63484_device ) +// AM_RANGE(0x00000, 0x7ffff) AM_RAM +// AM_RANGE(0x80000, 0xfffff) AM_NOP +ADDRESS_MAP_END + + +//------------------------------------------------- +// h63484_device - constructor +//------------------------------------------------- + +h63484_device::h63484_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, H63484, "HD63484 CRTC (rewrite)", tag, owner, clock, "h63484", __FILE__), + device_memory_interface(mconfig, *this), + device_video_interface(mconfig, *this), + m_ar(0), + m_sr(0), + m_fifo_ptr(-1), + m_fifo_r_ptr(-1), + m_cr(0), + m_param_ptr(0), + m_rwp_dn(0), + m_org_dpa(0), + m_org_dn(0), + m_org_dpd(0), + m_cl0(0), + m_cl1(0), + m_dcr(0), + m_space_config("videoram", ENDIANNESS_BIG, 16, 20, -1, NULL, *ADDRESS_MAP_NAME(h63484_vram)) +{ +} + +enum +{ + FIFO_READ = 0, + FIFO_WRITE +}; + +enum +{ + FIFO_EMPTY = -1, + FIFO_PARAMETER, + FIFO_COMMAND +}; + +#define H63484_SR_CER 0x80 // Command Error +#define H63484_SR_ARD 0x40 // Area Detect +#define H63484_SR_CED 0x20 // Command End +#define H63484_SR_LPD 0x10 // Light Pen Strobe Detect +#define H63484_SR_RFF 0x08 // Read FIFO Full +#define H63484_SR_RFR 0x04 // Read FIFO Ready +#define H63484_SR_WFR 0x02 // Write FIFO Ready +#define H63484_SR_WFE 0x01 // Write FIFO Empty + + +static const char *const acrtc_regnames[0x100/2] = +{ + "FIFO Entry", // 0x00 + "Command Control (CCR)", // 0x02 + "Operation Mode (OMR)", // 0x04 + "Display Control (DCR)", // 0x06 + "(Undefined)", // 0x08 + "(Undefined)", // 0x0a + "(Undefined)", // 0x0c + "(Undefined)", // 0x0e + "(Undefined)", // 0x10 + "(Undefined)", // 0x12 + "(Undefined)", // 0x14 + "(Undefined)", // 0x16 + "(Undefined)", // 0x18 + "(Undefined)", // 0x1a + "(Undefined)", // 0x1c + "(Undefined)", // 0x1e + "(Undefined)", // 0x20 + "(Undefined)", // 0x22 + "(Undefined)", // 0x24 + "(Undefined)", // 0x26 + "(Undefined)", // 0x28 + "(Undefined)", // 0x2a + "(Undefined)", // 0x2c + "(Undefined)", // 0x2e + "(Undefined)", // 0x30 + "(Undefined)", // 0x32 + "(Undefined)", // 0x34 + "(Undefined)", // 0x36 + "(Undefined)", // 0x38 + "(Undefined)", // 0x3a + "(Undefined)", // 0x3c + "(Undefined)", // 0x3e + "(Undefined)", // 0x40 + "(Undefined)", // 0x42 + "(Undefined)", // 0x44 + "(Undefined)", // 0x46 + "(Undefined)", // 0x48 + "(Undefined)", // 0x4a + "(Undefined)", // 0x4c + "(Undefined)", // 0x4e + "(Undefined)", // 0x50 + "(Undefined)", // 0x52 + "(Undefined)", // 0x54 + "(Undefined)", // 0x56 + "(Undefined)", // 0x58 + "(Undefined)", // 0x5a + "(Undefined)", // 0x5c + "(Undefined)", // 0x5e + "(Undefined)", // 0x60 + "(Undefined)", // 0x62 + "(Undefined)", // 0x64 + "(Undefined)", // 0x66 + "(Undefined)", // 0x68 + "(Undefined)", // 0x6a + "(Undefined)", // 0x6c + "(Undefined)", // 0x6e + "(Undefined)", // 0x70 + "(Undefined)", // 0x72 + "(Undefined)", // 0x74 + "(Undefined)", // 0x76 + "(Undefined)", // 0x78 + "(Undefined)", // 0x7a + "(Undefined)", // 0x7c + "(Undefined)", // 0x7e + "Raster Count (RCR)", // 0x80 + "Horizontal Sync (HSR)", // 0x82 + "Horizontal Display (HDR)", // 0x84 + "Vertical Sync (VSR)", // 0x86 + "Vertical Display (VDR)", // 0x88 + "Split Screen Width (SSW) 0x8a", // 0x8a + "Split Screen Width (SSW) 0x8c", // 0x8c + "Split Screen Width (SSW) 0x8e", // 0x8e + "Blink Control (BCR)", // 0x90 + "Horizontal Window Display (HWR)", // 0x92 + "Vertical Window Display (VWR) 0x94", // 0x94 + "Vertical Window Display (VWR) 0x96", // 0x96 + "Graphic Cursor (GCR0)", // 0x98 + "Graphic Cursor (GCR1)", // 0x9a + "Graphic Cursor (GCR2)", // 0x9c + "(Undefined)", // 0x9e + "(Undefined)", // 0xa0 + "(Undefined)", // 0xa2 + "(Undefined)", // 0xa4 + "(Undefined)", // 0xa6 + "(Undefined)", // 0xa8 + "(Undefined)", // 0xaa + "(Undefined)", // 0xac + "(Undefined)", // 0xae + "(Undefined)", // 0xb0 + "(Undefined)", // 0xb2 + "(Undefined)", // 0xb4 + "(Undefined)", // 0xb6 + "(Undefined)", // 0xb8 + "(Undefined)", // 0xba + "(Undefined)", // 0xbc + "(Undefined)", // 0xbe + // upper screen + "Raster Address 0 (RAR0)", // 0xc0 + "Memory Width 0 (MWR0)", // 0xc2 + "Start Address 0 (SAR0) 0xc4", // 0xc4 + "Start Address 0 (SAR0) 0xc6", // 0xc6 + // base screen + "Raster Address 1 (RAR1)", // 0xc8 + "Memory Width 1 (MWR1)", // 0xca + "Start Address 1 (SAR1) 0xcc", // 0xcc + "Start Address 1 (SAR1) 0xce", // 0xce + // lower screen + "Raster Address 2 (RAR2)", // 0xd0 + "Memory Width 2 (MWR2)", // 0xd2 + "Start Address 2 (SAR2) 0xd4", // 0xd4 + "Start Address 2 (SAR2) 0xd6", // 0xd6 + // window screen + "Raster Address 3 (RAR3)", // 0xd8 + "Memory Width 3 (MWR3)", // 0xda + "Start Address 3 (SAR3) 0xdc", // 0xdc + "Start Address 3 (SAR3) 0xde", // 0xde + // block cursor 1 + "Block Cursor 1 (BCUR1) 0xe0", + "Block Cursor 1 (BCUR1) 0xe2", + // block cursor 2 + "Block Cursor 2 (BCUR2) 0xe4", + "Block Cursor 2 (BCUR2) 0xe6", + "Cursor Definition (CDR)", + "Zoom Factor (ZFR)", + "Lightpen Address (LPAR) 0xec", + "Lightpen Address (LPAR) 0xee", + "(Undefined)", // 0xf0 + "(Undefined)", // 0xf2 + "(Undefined)", // 0xf4 + "(Undefined)", // 0xf6 + "(Undefined)", // 0xf8 + "(Undefined)", // 0xfa + "(Undefined)", // 0xfc + "(Undefined)" // 0xfe +}; + +static const char *const wpr_regnames[0x20] = +{ + "Color 0 (CL0)", + "Color 1 (CL1)", + "Color Comparison (COMP)", + "Edge Color (EDG)", + "Mask (MASK)", + "Pattern RAM Control (PRC) 0x05", + "Pattern RAM Control (PRC) 0x06", + "Pattern RAM Control (PRC) 0x07", + "Area Definition (ADR) 0x08", + "Area Definition (ADR) 0x09", + "Area Definition (ADR) 0x0a", + "Area Definition (ADR) 0x0b", + "Read Write Pointer (RWP) H", + "Read Write Pointer (RWP) L", + "(Undefined)", + "(Undefined)", + "Drawing Pointer (DP) H", + "Drawing Pointer (DP) L", + "Current Pointer (CP) H", + "Current Pointer (CP) L", + "(Undefined)", // 0x14 + "(Undefined)", + "(Undefined)", // 0x16 + "(Undefined)", + "(Undefined)", // 0x18 + "(Undefined)", + "(Undefined)", // 0x1a + "(Undefined)", + "(Undefined)", // 0x1c + "(Undefined)", + "(Undefined)", // 0x1e + "(Undefined)" +}; + +enum +{ + COMMAND_INVALID = -1, + COMMAND_ORG, + COMMAND_WPR, + COMMAND_RPR, + COMMAND_WPTN, + COMMAND_RPTN, + COMMAND_DRD, + COMMAND_DWT, + COMMAND_DMOD, + COMMAND_RD, + COMMAND_WT, + COMMAND_MOD, + COMMAND_CLR, + COMMAND_SCLR, + COMMAND_CPY, + COMMAND_SCPY, + COMMAND_AMOVE, + COMMAND_RMOVE, + COMMAND_ALINE, + COMMAND_RLINE, + COMMAND_ARCT, + COMMAND_RRCT, + COMMAND_APLL, + COMMAND_RPLL, + COMMAND_APLG, + COMMAND_RPLG, + COMMAND_CRCL, + COMMAND_ELPS, + COMMAND_AARC, + COMMAND_RARC, + COMMAND_AEARC, + COMMAND_REARC, + COMMAND_AFRCT, + COMMAND_RFRCT, + COMMAND_PAINT, + COMMAND_DOT, + COMMAND_PTN, + COMMAND_AGCPY, + COMMAND_RGCPY +}; + +#define H63484_COMMAND_ORG 0x0400 // p: 2 +#define H63484_COMMAND_WPR 0x0800 // & ~0x1f p: 1 +#define H63484_COMMAND_RPR 0x0c00 // & ~0x1f p: 0 +#define H63484_COMMAND_WPTN 0x1800 // & ~0xf p: 1 + n +#define H63484_COMMAND_RPTN 0x1c00 // & ~0xf p: 1 +#define H63484_COMMAND_DRD 0x2400 // p: 2 +#define H63484_COMMAND_DWT 0x2800 // p: 2 +#define H63484_COMMAND_DMOD 0x2c00 // & ~3 p: 2 +#define H63484_COMMAND_RD 0x4400 // p: 0 +#define H63484_COMMAND_WT 0x4800 // p: 1 +#define H63484_COMMAND_MOD 0x4c00 // & ~3 p: 1 +#define H63484_COMMAND_CLR 0x5800 // p: 3 +#define H63484_COMMAND_SCLR 0x5c00 // & ~3 p: 3 +#define H63484_COMMAND_CPY 0x6000 // & ~0x0f03 p: 4 +#define H63484_COMMAND_SCPY 0x7000 // & ~0x0f03 p: 4 +#define H63484_COMMAND_AMOVE 0x8000 // p: 2 +#define H63484_COMMAND_RMOVE 0x8400 // p: 2 +#define H63484_COMMAND_ALINE 0x8800 // & ~0x00ff p: 2 +#define H63484_COMMAND_RLINE 0x8c00 // & ~0x00ff p: 2 +#define H63484_COMMAND_ARCT 0x9000 // & ~0x00ff p: 2 +#define H63484_COMMAND_RRCT 0x9400 // & ~0x00ff p: 2 +#define H63484_COMMAND_APLL 0x9800 // & ~0x00ff p: 1 + n +#define H63484_COMMAND_RPLL 0x9c00 // & ~0x00ff p: 1 + n +#define H63484_COMMAND_APLG 0xa000 // & ~0x00ff p: 1 + n +#define H63484_COMMAND_RPLG 0xa400 // & ~0x00ff p: 1 + n +#define H63484_COMMAND_CRCL 0xa800 // & ~0x01ff p: 1 +#define H63484_COMMAND_ELPS 0xac00 // & ~0x01ff p: 3 +#define H63484_COMMAND_AARC 0xb000 // & ~0x01ff p: 4 +#define H63484_COMMAND_RARC 0xb400 // & ~0x01ff p: 4 +#define H63484_COMMAND_AEARC 0xb800 // & ~0x01ff p: 6 +#define H63484_COMMAND_REARC 0xbc00 // & ~0x01ff p: 6 +#define H63484_COMMAND_AFRCT 0xc000 // & ~0x00ff p: 2 +#define H63484_COMMAND_RFRCT 0xc400 // & ~0x00ff p: 2 +#define H63484_COMMAND_PAINT 0xc800 // & ~0x01ff p: 0 +#define H63484_COMMAND_DOT 0xcc00 // & ~0x00ff p: 0 +#define H63484_COMMAND_PTN 0xd000 // & ~0x0fff p: 1 +#define H63484_COMMAND_AGCPY 0xe000 // & ~0x0fff p: 4 +#define H63484_COMMAND_RGCPY 0xf000 // & ~0x0fff p: 4 + + +/*------------------------------------------------- + ROM( h63484 ) +-------------------------------------------------*/ + +// devices +const device_type H63484 = &device_creator; + + +ROM_START( h63484 ) + ROM_REGION( 0x100, "h63484", 0 ) + ROM_LOAD( "h63484.bin", 0x000, 0x100, NO_DUMP ) /* internal control ROM */ +ROM_END + +//------------------------------------------------- +// memory_space_config - return a description of +// any address spaces owned by this device +//------------------------------------------------- + +const address_space_config *h63484_device::memory_space_config(address_spacenum spacenum) const +{ + return (spacenum == AS_0) ? &m_space_config : NULL; +} + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *h63484_device::device_rom_region() const +{ + return ROM_NAME( h63484 ); +} + +//------------------------------------------------- +// readword - read a word at the given address +//------------------------------------------------- + +inline UINT16 h63484_device::readword(offs_t address) +{ + return space().read_word(address << 1); +} + + +//------------------------------------------------- +// writeword - write a word at the given address +//------------------------------------------------- + +inline void h63484_device::writeword(offs_t address, UINT16 data) +{ + space().write_word(address << 1, data); +} + + +inline void h63484_device::inc_ar(int value) +{ + if(m_ar & 0x80) + { + if (m_ar + value > 0xff) // TODO: what happens if it overflows? + logerror("HD63484 '%s': Address Register overflows 0x%02x\n", tag(), m_ar + value); + + m_ar = (m_ar + value) & 0xff; + } +} + +inline void h63484_device::fifo_w_clear() +{ + int i; + + for (i = 0; i < 16; i++) + m_fifo[i] = 0; + + m_fifo_ptr = -1; + + m_sr |= H63484_SR_WFR; + m_sr |= H63484_SR_WFE; +} + +inline void h63484_device::queue_w(UINT8 data) +{ + if (m_fifo_ptr < 15) + { + m_fifo_ptr++; + + m_fifo[m_fifo_ptr] = data; + + if (m_fifo_ptr == 16) + m_sr &= ~H63484_SR_WFR; + + m_sr &= ~H63484_SR_WFE; + } + else + { + // TODO what happen? somebody set us up the bomb + printf("FIFO?\n"); + } +} + +inline void h63484_device::dequeue_w(UINT8 *data) +{ + int i; + + *data = m_fifo[0]; + + if (m_fifo_ptr > -1) + { + for (i = 0; i < 15; i++) + m_fifo[i] = m_fifo[i + 1]; + + m_fifo[15] = 0; + + m_fifo_ptr--; + + m_sr |= H63484_SR_WFR; + + if (m_fifo_ptr == -1) + m_sr |= H63484_SR_WFE; + + } +} + +inline void h63484_device::fifo_r_clear() +{ + int i; + + for (i = 0; i < 16; i++) + m_fifo_r[i] = 0; + + m_fifo_r_ptr = -1; + + m_sr &= ~H63484_SR_RFR; + m_sr &= ~H63484_SR_RFF; +} + +inline void h63484_device::queue_r(UINT8 data) +{ + if (m_fifo_r_ptr < 15) + { + m_fifo_r_ptr++; + + m_fifo_r[m_fifo_r_ptr] = data; + + if (m_fifo_r_ptr == 16) + m_sr |= H63484_SR_RFF; + + m_sr |= H63484_SR_RFR; + } + else + { + // TODO what happen? somebody set us up the bomb + printf("FIFO?\n"); + } +} + +inline void h63484_device::dequeue_r(UINT8 *data) +{ + int i; + + *data = m_fifo_r[0]; + + if (m_fifo_r_ptr > -1) + { + for (i = 0; i < 15; i++) + m_fifo_r[i] = m_fifo_r[i + 1]; + + m_fifo_r[15] = 0; + + m_fifo_r_ptr--; + + m_sr &= ~H63484_SR_RFF; + + if (m_fifo_r_ptr == -1) + m_sr &= ~H63484_SR_RFR; + } +} + +//------------------------------------------------- +// recompute_parameters - +//------------------------------------------------- + +inline void h63484_device::recompute_parameters() +{ + if(m_hdw < 3 || m_hc == 0 || m_vc == 0) //bail out if screen params aren't valid + return; + + if (LOG) + { + printf("HC %d HSW %d HDS %d HDW %d HWS %d HWW %d\n",m_hc,m_hsw,m_hds,m_hdw,m_hws,m_hww); + printf("VC %d VDS %d VSW %d VWS %d VWW %d\n",m_vc,m_vds,m_vsw,m_vws,m_vww); + printf("SP0 %d SP1 %d SP2 %d\n",m_sp[0],m_sp[1],m_sp[2]); + } + + int gai = (m_omr>>4) & 0x07; + if (gai > 3) printf("unsupported GAI=%d\n", gai); + int acm = (m_omr & 0x08) ? 2 : 1; + int ppw = 16 / get_bpp(); + int ppmc = ppw * (1 << gai) / acm; // TODO: GAI > 3 + int vbstart = m_vds + m_sp[1]; + if (BIT(m_dcr, 13)) vbstart += m_sp[0]; + if (BIT(m_dcr, 11)) vbstart += m_sp[2]; + + rectangle visarea = m_screen->visible_area(); + visarea.set((m_hsw + m_hds) * ppmc, (m_hsw + m_hds + m_hdw) * ppmc - 1, m_vds, vbstart - 1); + attoseconds_t frame_period = m_screen->frame_period().attoseconds(); // TODO: use clock() to calculate the frame_period + m_screen->configure(m_hc * ppmc, m_vc, visarea, frame_period); +} + + +/***************************************************************************** + IMPLEMENTATION +*****************************************************************************/ + +int h63484_device::translate_command(UINT16 data) +{ + /* annoying switch-case sequence, but it's the only way to get invalid commands ... */ + switch (data) + { + case H63484_COMMAND_ORG: return COMMAND_ORG; + case H63484_COMMAND_DRD: return COMMAND_DRD; + case H63484_COMMAND_DWT: return COMMAND_DWT; + case H63484_COMMAND_RD: return COMMAND_RD; + case H63484_COMMAND_WT: return COMMAND_WT; + case H63484_COMMAND_CLR: return COMMAND_CLR; + case H63484_COMMAND_AMOVE: return COMMAND_AMOVE; + case H63484_COMMAND_RMOVE: return COMMAND_RMOVE; + } + + switch(data & ~0x3) + { + case H63484_COMMAND_DMOD: return COMMAND_DMOD; + case H63484_COMMAND_MOD: return COMMAND_MOD; + case H63484_COMMAND_SCLR: return COMMAND_SCLR; + } + + switch(data & ~0xf) + { + case H63484_COMMAND_WPTN: return COMMAND_WPTN; + case H63484_COMMAND_RPTN: return COMMAND_RPTN; + } + + switch(data & ~0x1f) + { + case H63484_COMMAND_WPR: return COMMAND_WPR; + case H63484_COMMAND_RPR: return COMMAND_RPR; + } + + switch(data & ~0x0f03) + { + case H63484_COMMAND_CPY: return COMMAND_CPY; + case H63484_COMMAND_SCPY: return COMMAND_SCPY; + } + + switch(data & ~0x00ff) + { + case H63484_COMMAND_ALINE: return COMMAND_ALINE; + case H63484_COMMAND_RLINE: return COMMAND_RLINE; + case H63484_COMMAND_ARCT: return COMMAND_ARCT; + case H63484_COMMAND_RRCT: return COMMAND_RRCT; + case H63484_COMMAND_APLL: return COMMAND_APLL; + case H63484_COMMAND_RPLL: return COMMAND_RPLL; + case H63484_COMMAND_APLG: return COMMAND_APLG; + case H63484_COMMAND_RPLG: return COMMAND_RPLG; + case H63484_COMMAND_AFRCT: return COMMAND_AFRCT; + case H63484_COMMAND_RFRCT: return COMMAND_RFRCT; + case H63484_COMMAND_DOT: return COMMAND_DOT; + } + + switch(data & ~0x01ff) + { + case H63484_COMMAND_CRCL: return COMMAND_CRCL; + case H63484_COMMAND_ELPS: return COMMAND_ELPS; + case H63484_COMMAND_AARC: return COMMAND_AARC; + case H63484_COMMAND_RARC: return COMMAND_RARC; + case H63484_COMMAND_AEARC: return COMMAND_AEARC; + case H63484_COMMAND_REARC: return COMMAND_REARC; + case H63484_COMMAND_PAINT: return COMMAND_PAINT; + } + + switch(data & ~0x0fff) + { + case H63484_COMMAND_PTN: return COMMAND_PTN; + case H63484_COMMAND_AGCPY: return COMMAND_AGCPY; + case H63484_COMMAND_RGCPY: return COMMAND_RGCPY; + } + + return COMMAND_INVALID; +} + +inline void h63484_device::command_end_seq() +{ + //h63484->param_ptr = 0; + m_sr |= H63484_SR_CED; + + /* TODO: we might need to be more aggressive and clear the params in there */ +} + +int h63484_device::get_bpp() +{ + int gbm = (m_ccr >> 8) & 0x07; + + if (gbm <= 4) + return 1 << gbm; + + //logerror ("Invalid Graphic Bit Mode (%d)\n", gbm); + return 1; +} + +void h63484_device::calc_offset(INT16 x, INT16 y, UINT32 &offset, UINT8 &bit_pos) +{ + int bpp = get_bpp(); + int ppw = 16 / bpp; + int gbm = (m_ccr >> 8) & 0x07; + x += (m_org_dpd >> gbm); + if (x >= 0) + { + offset = x / ppw; + bit_pos = x % ppw; + } + else + { + offset = x / ppw; + bit_pos= (-x) % ppw; + if (bit_pos != 0) + { + offset--; + bit_pos = ppw - bit_pos; + } + } + + offset += m_org_dpa - y * m_mwr[m_org_dn]; + bit_pos *= bpp; +} + +UINT16 h63484_device::get_dot(INT16 x, INT16 y) +{ + UINT8 bpp = get_bpp(); + UINT32 offset = 0; + UINT8 bit_pos = 0; + + calc_offset(x, y, offset, bit_pos); + + return (readword(offset) >> bit_pos) & ((1 << bpp) - 1); +} + +bool h63484_device::set_dot(INT16 x, INT16 y, INT16 px, INT16 py) +{ + int xs = m_pex - m_psx + 1; + int ys = m_pey - m_psy + 1; + int zx = m_pzx + 1; + int zy = m_pzy + 1; + int xp = m_psx + ((px % (xs * zx)) / zx); + int yp = m_psy + ((py % (ys * zy)) / zy); + + if (xp < m_psx) + xp = (m_pex + 1) - (m_psx - xp); + + if (yp < m_psy) + yp = (m_pey + 1) - (m_psy - yp); + + int pix = (m_pram[yp & 0x0f] >> (xp & 0x0f)) & 0x01; + + UINT8 col = (m_cr >> 3) & 0x03; + UINT8 bpp = get_bpp(); + UINT16 mask = (1 << bpp) - 1; + UINT16 xmask = (16 / bpp) - 1; + UINT16 cl0 = (m_cl0 >> ((x & xmask) * bpp)) & mask; + UINT16 cl1 = (m_cl1 >> ((x & xmask) * bpp)) & mask; + + switch (col) + { + case 0x00: + return set_dot(x, y, pix ? cl1 : cl0); + case 0x01: + if (pix) + return set_dot(x, y, cl1); + break; + case 0x02: + if (!pix) + return set_dot(x, y, cl0); + break; + case 0x03: + fatalerror("HD63484 color modes (Pattern RAM indirect)\n"); + // TODO + } + + return false; +} + +bool h63484_device::set_dot(INT16 x, INT16 y, UINT16 color) +{ + UINT8 bpp = get_bpp(); + UINT32 offset = 0; + UINT8 bit_pos = 0; + UINT8 opm = m_cr & 0x07; + UINT8 area = (m_cr >> 5) & 0x07; + + calc_offset(x, y, offset, bit_pos); + + UINT16 mask = ((1 << bpp) - 1) << bit_pos; + UINT16 color_shifted = (color << bit_pos) & mask; + + UINT16 data = readword(offset); + UINT16 res = data; + + switch (opm) + { + case 0: + res = (data & ~mask) | color_shifted; + break; + case 1: + res = (data & ~mask) | ((data & mask) | color_shifted); + break; + case 2: + res = (data & ~mask) | ((data & mask) & color_shifted); + break; + case 3: + res = (data & ~mask) | ((data & mask) ^ color_shifted); + break; + case 4: + if (get_dot(x, y) == ((m_ccmp & mask) >> bit_pos)) + res = (data & ~mask) | color_shifted; + break; + case 5: + if (get_dot(x, y) != ((m_ccmp & mask) >> bit_pos)) + res = (data & ~mask) | color_shifted; + break; + case 6: + if (get_dot(x, y) < ((m_cl0 & mask) >> bit_pos)) + res = (data & ~mask) | color_shifted; + break; + case 7: + if (get_dot(x, y) > ((m_cl1 & mask) >> bit_pos)) + res = (data & ~mask) | color_shifted; + break; + } + + writeword(offset, res); + + if (area) + logerror("HD63484 '%s': unsupported area detection %x (%d %d)\n", tag(), area, x, y); + + return false; // TODO: return area detection status +} + +void h63484_device::draw_line(INT16 sx, INT16 sy, INT16 ex, INT16 ey) +{ + UINT16 delta_x = abs(ex - sx) * 2; + UINT16 delta_y = abs(ey - sy) * 2; + int dir_x = (ex < sx) ? -1 : ((ex > sx) ? +1 : 0); + int dir_y = (ey < sy) ? -1 : ((ey > sy) ? +1 : 0); + int pram_pos = 0; + + if(delta_x > delta_y) + { + int delta = delta_y - delta_x / 2; + while(sx != ex) + { + set_dot(sx, sy, pram_pos, 0); + + if(delta >= 0) + { + sy += dir_y; + delta -= delta_x; + } + pram_pos++; + sx += dir_x; + delta += delta_y; + } + } + else + { + int delta = delta_x - delta_y / 2; + while(sy != ey) + { + set_dot(sx, sy, pram_pos, 0); + + if(delta >= 0) + { + sx += dir_x; + delta -= delta_y; + } + pram_pos++; + sy += dir_y; + delta += delta_x; + } + } +} + +void h63484_device::draw_ellipse(INT16 cx, INT16 cy, double dx, double dy, double s_angol, double e_angol, bool c) +{ + double inc = 1.0 / (MAX(dx, dy) * 100); + for (double angol = s_angol; fabs(angol - e_angol) >= inc*2; angol += inc * (c ? -1 : +1)) + { + if (angol > DEGREE_TO_RADIAN(360)) angol -= DEGREE_TO_RADIAN(360); + if (angol < DEGREE_TO_RADIAN(0)) angol += DEGREE_TO_RADIAN(360); + + double px = cos(angol) * dx; + double py = sin(angol) * dy; + set_dot(cx + round(px), cy + round(py), 0, 0); + } +} + +void h63484_device::paint(INT16 sx, INT16 sy) +{ +/* + This is not accurate since real hardware can only paint 4 'unpaintable' areas, + the other 'unpaintable' points are pushed into the read FIFO to be processed + later by the program, but currently is impossible suspend/resume the command + in case the read FIFO is full, so all 'unpaintable' areas are painted. + Also CP is not in the correct position after this command. +*/ + UINT8 e = BIT(m_cr, 8); + UINT8 bpp = get_bpp(); + UINT16 mask = (1 << bpp) - 1; + UINT16 xmask = (16 / bpp) - 1; + + for (int ydir=0; ydir<2; ydir++) + for(UINT16 y=0;y<0x7fff; y++) + { + bool limit = true; + bool unpaintable_up = false; + bool unpaintable_dn = false; + + for (int xdir=0; xdir<2; xdir++) + for(UINT16 x=0; x<0x7fff; x++) + { + INT16 px = sx + (xdir ? -x : x); + INT16 py = sy + (ydir ? -y : y); + + UINT16 dot = get_dot(px, py); + UINT16 edg = (m_edg >> (px & xmask) * bpp) & mask; + UINT16 cl0 = (m_cl0 >> (px & xmask) * bpp) & mask; + UINT16 cl1 = (m_cl1 >> (px & xmask) * bpp) & mask; + + if ((e && dot != edg) || (!e && dot == edg) || dot == cl0 || dot == cl1) + break; + + if ((!ydir && !xdir && x && y) || (xdir && y) || (ydir && x) || (ydir && xdir)) + set_dot(px, py, px - m_cpx, py - m_cpy); + + dot = get_dot(px, py + 1); + if (unpaintable_up && !((e && dot == edg) && (!e && dot != edg) && dot != cl0 && dot != cl1)) + paint(px, py + 1); + else if (!unpaintable_up && ((e && dot != edg) || (!e && dot == edg) || dot == cl0 || dot == cl1)) + unpaintable_up = true; + + dot = get_dot(px, py - 1); + if (unpaintable_dn && !((e && dot == edg) && (!e && dot != edg) && dot != cl0 && dot != cl1)) + paint(px, py - 1); + else if (!unpaintable_dn && ((e && dot != edg) || (!e && dot == edg) || dot == cl0 || dot == cl1)) + unpaintable_dn = true; + + limit = false; + } + if (limit) break; + } +} + +UINT16 h63484_device::command_rpr_exec() +{ + switch(m_cr & 0x1f) + { + case 0x00: // color 0 + return m_cl0; + case 0x01: // color 1 + return m_cl1; + case 0x02: // color comparison + return m_ccmp; + case 0x03: // edge color + return m_edg; + case 0x04: // mask + return m_mask; + case 0x05: // Pattern RAM Control 1 + return (m_ppy << 12) | (m_pzcy << 8) | (m_ppx << 4) | m_pzcx; + case 0x06: // Pattern RAM Control 2 + return (m_psy << 12) | (m_psx << 4); + case 0x07: // Pattern RAM Control 3 + return (m_pey << 12) | (m_pzy << 8) | (m_pex << 4) | m_pzx; + case 0x08: // Area Definition XMIN + return m_xmin; + case 0x09: // Area Definition YMIN + return m_ymin; + case 0x0a: // Area Definition XMAX + return m_xmax; + case 0x0b: // Area Definition YMAX + return m_ymax; + case 0x0c: // Read Write Pointer H + return (m_rwp_dn << 14) | ((m_rwp[m_rwp_dn] >> 12) & 0xff); + case 0x0d: // Read Write Pointer L + return (m_rwp[m_rwp_dn] & 0x0fff) << 4; + default: + if(LOG) printf("Read %sx\n", wpr_regnames[m_cr & 0x1f]); + return 0; + } +} + +void h63484_device::command_wpr_exec() +{ + switch(m_cr & 0x1f) + { + case 0x00: // color 0 + m_cl0 = m_pr[0]; + break; + case 0x01: // color 1 + m_cl1 = m_pr[0]; + break; + case 0x02: // color comparison + m_ccmp = m_pr[0]; + break; + case 0x03: // edge color + m_edg = m_pr[0]; + break; + case 0x04: // mask + m_mask = m_pr[0]; + break; + case 0x05: // Pattern RAM Control 1 + m_pzcx = (m_pr[0] >> 0) & 0x0f; + m_ppx = (m_pr[0] >> 4) & 0x0f; + m_pzcy = (m_pr[0] >> 8) & 0x0f; + m_ppy = (m_pr[0] >> 12) & 0x0f; + break; + case 0x06: // Pattern RAM Control 2 + m_psx = (m_pr[0] >> 4) & 0x0f; + m_psy = (m_pr[0] >> 12) & 0x0f; + break; + case 0x07: // Pattern RAM Control 3 + m_pzx = (m_pr[0] >> 0) & 0x0f; + m_pex = (m_pr[0] >> 4) & 0x0f; + m_pzy = (m_pr[0] >> 8) & 0x0f; + m_pey = (m_pr[0] >> 12) & 0x0f; + break; + case 0x08: // Area Definition XMIN + m_xmin = m_pr[0]; + break; + case 0x09: // Area Definition YMIN + m_ymin = m_pr[0]; + break; + case 0x0a: // Area Definition XMAX + m_xmax = m_pr[0]; + break; + case 0x0b: // Area Definition YMAX + m_ymax = m_pr[0]; + break; + case 0x0c: // Read Write Pointer H + m_rwp_dn = (m_pr[0] & 0xc000) >> 14; + m_rwp[m_rwp_dn] = (m_rwp[m_rwp_dn] & 0x00fff) | ((m_pr[0] & 0x00ff) << 12); + break; + case 0x0d: // Read Write Pointer L + m_rwp[m_rwp_dn] = (m_rwp[m_rwp_dn] & 0xff000) | ((m_pr[0] & 0xfff0) >> 4); + break; + default: + if(LOG) printf("%s -> %02x\n",wpr_regnames[m_cr & 0x1f],m_pr[0]); + break; + } +} + +void h63484_device::command_clr_exec() +{ + UINT8 mm = m_cr & 0x03; + UINT16 d = m_pr[0]; + INT16 ax = (INT16)m_pr[1]; + INT16 ay = (INT16)m_pr[2]; + + int d0_inc = (ax < 0) ? -1 : 1; + int d1_inc = (ay < 0) ? -1 : 1; + + for(INT16 d1=0; d1!=ay+d1_inc; d1+=d1_inc) + { + for(INT16 d0=0; d0!=ax+d0_inc; d0+=d0_inc) + { + UINT32 offset = m_rwp[m_rwp_dn] - d1 * m_mwr[m_rwp_dn] + d0; + UINT16 data = readword(offset); + UINT16 res = 0; + + if (BIT(m_cr, 10)) + { + switch(mm) + { + case 0: // replace + res = (data & ~m_mask) | (d & m_mask); + break; + case 1: // OR + res = (data & ~m_mask) | ((data | d) & m_mask); + break; + case 2: // AND + res = (data & ~m_mask) | ((data & d) & m_mask); + break; + case 3: // EOR + res = (data & ~m_mask) | ((data ^ d) & m_mask); + break; + } + } + else + res = d; + + writeword(offset, res); + } + } + + m_rwp[m_rwp_dn] -= (ay + d1_inc) * m_mwr[m_rwp_dn]; + m_rwp[m_rwp_dn] &= 0xfffff; +} + +void h63484_device::command_cpy_exec() +{ + UINT8 mm = m_cr & 0x03; + UINT8 dsd = (m_cr >> 8) & 0x07; + UINT8 s = BIT(m_cr, 11); + UINT32 SA = ((m_pr[0] & 0xff) << 12) | ((m_pr[1]&0xfff0) >> 4); + INT16 DX = (INT16)m_pr[s ? 3 : 2]; + INT16 DY = (INT16)m_pr[s ? 2 : 3]; + + int sd0_inc = (DX < 0) ? -1 : 1; + int sd1_inc = (DY < 0) ? -1 : 1; + int dd0_inc, dd1_inc; + if (dsd & 0x04) + { + dd0_inc = dsd & 0x01 ? -1 : +1; + dd1_inc = dsd & 0x02 ? -1 : +1; + } + else + { + dd0_inc = dsd & 0x02 ? -1 : +1; + dd1_inc = dsd & 0x01 ? -1 : +1; + } + + for(INT16 sd1=0, dd1=0; sd1!=DY+sd1_inc; sd1+=sd1_inc, dd1+=dd1_inc) + { + for(INT16 sd0=0, dd0=0; sd0!=DX+sd0_inc; sd0+=sd0_inc, dd0+=dd0_inc) + { + UINT32 src_offset, dst_offset; + + if (s) + src_offset = SA + sd1 - sd0 * m_mwr[m_rwp_dn]; + else + src_offset = SA + sd0 - sd1 * m_mwr[m_rwp_dn]; + + if (BIT(dsd, 2)) + dst_offset = m_rwp[m_rwp_dn] + dd1 - dd0 * m_mwr[m_rwp_dn]; + else + dst_offset = m_rwp[m_rwp_dn] + dd0 - dd1 * m_mwr[m_rwp_dn]; + + UINT16 src_data = readword(src_offset); + UINT16 dst_data = readword(dst_offset); + + if (BIT(m_cr, 12)) + { + switch(mm) + { + case 0: // replace + dst_data = (dst_data & ~m_mask) | (src_data & m_mask); + break; + case 1: // OR + dst_data = (dst_data & ~m_mask) | ((dst_data | src_data) & m_mask); + break; + case 2: // AND + dst_data = (dst_data & ~m_mask) | ((dst_data & src_data) & m_mask); + break; + case 3: // EOR + dst_data = (dst_data & ~m_mask) | ((dst_data ^ src_data) & m_mask); + break; + } + } + else + dst_data = src_data; + + writeword(dst_offset, dst_data); + } + } + + m_rwp[m_rwp_dn] += dsd & 0x04 ? (DY + dd1_inc) : (-(DY + dd1_inc) * m_mwr[m_rwp_dn]); + m_rwp[m_rwp_dn] &= 0xfffff; +} + +void h63484_device::command_line_exec() +{ + INT16 x = (INT16)m_pr[0]; + INT16 y = (INT16)m_pr[1]; + + if (BIT(m_cr, 10)) + { + x += m_cpx; + y += m_cpy; + } + + draw_line(m_cpx, m_cpy, x, y); + + m_cpx = x; + m_cpy = y; +} + +void h63484_device::command_rct_exec() +{ + INT16 dX = m_pr[0]; + INT16 dY = m_pr[1]; + + if (BIT(m_cr, 10)) // relative (RRCT) + { + dX += m_cpx; + dY += m_cpy; + } + + /* + 3<-2 + | ^ + v | + 0->1 + */ + + /* 0 -> 1 */ + draw_line(m_cpx, m_cpy, dX, m_cpy); + + /* 1 -> 2 */ + draw_line(dX, m_cpy, dX, dY); + + /* 2 -> 3 */ + draw_line(dX, dY, m_cpx, dY); + + /* 3 -> 4 */ + draw_line(m_cpx, dY, m_cpx, m_cpy); +} + +void h63484_device::command_gcpy_exec() +{ + UINT8 dsd = (m_cr >> 8) & 0x07; + UINT8 s = BIT(m_cr, 11); + INT16 Xs = (INT16)m_pr[0]; + INT16 Ys = (INT16)m_pr[1]; + INT16 DX = (INT16)m_pr[s ? 3 : 2]; + INT16 DY = (INT16)m_pr[s ? 2 : 3]; + + if (BIT(m_cr, 12)) // relative (RGCPY) + { + Xs += m_cpx; + Ys += m_cpy; + } + + int sd0_inc = (DX < 0) ? -1 : 1; + int sd1_inc = (DY < 0) ? -1 : 1; + int dd0_inc, dd1_inc; + if (dsd & 0x04) + { + dd0_inc = dsd & 0x01 ? -1 : +1; + dd1_inc = dsd & 0x02 ? -1 : +1; + } + else + { + dd0_inc = dsd & 0x02 ? -1 : +1; + dd1_inc = dsd & 0x01 ? -1 : +1; + } + + for(INT16 sd1=0, dd1=0; sd1!=DY+sd1_inc; sd1+=sd1_inc, dd1+=dd1_inc) + { + for(INT16 sd0=0, dd0=0; sd0!=DX+sd0_inc; sd0+=sd0_inc, dd0+=dd0_inc) + { + UINT16 color; + if (s) + color = get_dot(Xs + sd1, Ys + sd0); + else + color = get_dot(Xs + sd0, Ys + sd1); + + if (BIT(dsd, 2)) + set_dot(m_cpx + dd1, m_cpy + dd0, color); + else + set_dot(m_cpx + dd0, m_cpy + dd1, color); + } + } + + if (dsd & 0x04) + m_cpx += DY + dd1_inc; + else + m_cpy += DY + dd1_inc; + +} + +void h63484_device::command_frct_exec() +{ + INT16 X = (INT16)m_pr[0]; + INT16 Y = (INT16)m_pr[1]; + + if (!BIT(m_cr, 10)) + { + X -= m_cpx; + Y -= m_cpy; + } + + int d0_inc = (X < 0) ? -1 : 1; + int d1_inc = (Y < 0) ? -1 : 1; + + for(INT16 d1=0; d1!=Y+d1_inc; d1+=d1_inc) + { + for(INT16 d0=0; d0!=X+d0_inc; d0+=d0_inc) + set_dot(m_cpx + d0, m_cpy + d1, d0, d1); + } + + m_cpy += (Y + d1_inc); +} + +void h63484_device::command_ptn_exec() +{ + INT16 szx = ((m_pr[0] >> 0) & 0xff); + INT16 szy = ((m_pr[0] >> 8) & 0xff); + UINT8 sl_sd = (m_cr >> 8) & 0x0f; + INT16 px = 0; + INT16 py = 0; + + for(INT16 d1=0; d1!=szy+1; d1++) + { + switch (sl_sd) + { + case 0x00: px = 0; py = d1; break; + case 0x01: px = -d1; py = d1; break; + case 0x02: py = 0; px = -d1; break; + case 0x03: px = -d1; py = -d1; break; + case 0x04: px = 0; py = -d1; break; + case 0x05: px = d1; py = -d1; break; + case 0x06: py = 0; px = d1; break; + case 0x07: px = d1; py = d1; break; + case 0x08: px = d1; py = d1; break; + case 0x09: px = 0; py = d1; break; + case 0x0a: px = -d1; py = d1; break; + case 0x0b: px = -d1; py = 0; break; + case 0x0c: px = -d1; py = -d1; break; + case 0x0d: px = 0; py = -d1; break; + case 0x0e: px = +d1; py = -d1; break; + case 0x0f: px = +d1; py = 0; break; + } + + for(INT16 d0=0; d0!=szx+1; d0++) + { + set_dot(m_cpx + px, m_cpy + py, d0, d1); + + switch (sl_sd) + { + case 0x00: px++; break; + case 0x01: px++; py++; break; + case 0x02: py++; break; + case 0x03: px--; py++; break; + case 0x04: px--; break; + case 0x05: px--; py--; break; + case 0x06: py--; break; + case 0x07: px++; py--; break; + case 0x08: px++; break; + case 0x09: px++; py++; break; + case 0x0a: py++; break; + case 0x0b: px--; py++; break; + case 0x0c: px--; break; + case 0x0d: px--; py--; break; + case 0x0e: py--; break; + case 0x0f: px++; py--; break; + } + } + } + + switch (sl_sd) + { + case 0x00: m_cpy += (szy + 1); break; + case 0x01: m_cpx -= (szy + 1); m_cpy += (szy + 1); break; + case 0x02: m_cpx -= (szy + 1); break; + case 0x03: m_cpx -= (szy + 1); m_cpy -= (szy + 1); break; + case 0x04: m_cpy -= (szy + 1); break; + case 0x05: m_cpx += (szy + 1); m_cpy -= (szy + 1); break; + case 0x06: m_cpx += (szy + 1); break; + case 0x07: m_cpx += (szy + 1); m_cpy += (szy + 1); break; + case 0x08: m_cpx += (szy + 1); m_cpy += (szy + 1); break; + case 0x09: m_cpy += (szy + 1); break; + case 0x0a: m_cpx -= (szy + 1); m_cpy += (szy + 1); break; + case 0x0b: m_cpx -= (szy + 1); break; + case 0x0c: m_cpx -= (szy + 1); m_cpy -= (szy + 1); break; + case 0x0d: m_cpy -= (szy + 1); break; + case 0x0e: m_cpx += (szy + 1); m_cpy -= (szy + 1); break; + case 0x0f: m_cpx += (szy + 1); break; + } +} + +void h63484_device::command_plg_exec() +{ + int sx = m_cpx; + int sy = m_cpy; + int ex=0; + int ey=0; + + for (int i = 0; i < m_dn; i++) + { + if (BIT(m_cr, 10)) + { + ex = sx + (INT16)m_pr[1 + i * 2]; + ey = sy + (INT16)m_pr[1 + i * 2 + 1]; + } + else + { + ex = (INT16)m_pr[1 + i * 2]; + ey = (INT16)m_pr[1 + i * 2 + 1]; + } + + draw_line(sx, sy, ex, ey); + + sx = ex; + sy = ey; + } + + if (m_cr & 0x2000) + { + // APLG/RPLG + draw_line(sx, sy, m_cpx, m_cpy); + } + else + { + // APLL/RPLL + m_cpx = ex; + m_cpy = ey; + } +} + +void h63484_device::command_arc_exec() +{ + INT16 xc = (INT16)m_pr[0]; + INT16 yc = (INT16)m_pr[1]; + INT16 xe = (INT16)m_pr[2]; + INT16 ye = (INT16)m_pr[3]; + + if (BIT(m_cr, 10)) + { + xc += m_cpx; + yc += m_cpy; + xe += m_cpx; + ye += m_cpy; + } + + double r = sqrt(pow((double)(xc - m_cpx), 2) + pow((double)(yc - m_cpy), 2)); + double s_angol = atan2((double)(m_cpy - yc), (double)(m_cpx - xc)); + double e_angol = atan2((double)(ye - yc), (double)(xe - xc)); + if (s_angol < 0) s_angol += DEGREE_TO_RADIAN(360); + if (e_angol < 0) e_angol += DEGREE_TO_RADIAN(360); + + draw_ellipse(xc, yc, r, r, s_angol, e_angol, BIT(m_cr, 8)); + + m_cpx = xe; + m_cpy = ye; +} + +void h63484_device::command_earc_exec() +{ + UINT16 a = m_pr[0]; + UINT16 b = m_pr[1]; + INT16 xc = (INT16)m_pr[2]; + INT16 yc = (INT16)m_pr[3]; + INT16 xe = (INT16)m_pr[4]; + INT16 ye = (INT16)m_pr[5]; + + if (BIT(m_cr, 10)) + { + xc += m_cpx; + yc += m_cpy; + xe += m_cpx; + ye += m_cpy; + } + + double r = sqrt(pow((double)(xc - m_cpx), 2) / a + pow((double)(yc - m_cpy), 2) / b); + double dx = sqrt((double)a); + double dy = sqrt((double)b); + double s_angol = atan2((double)(m_cpy - yc) / dy, (double)(m_cpx - xc) / dx); + double e_angol = atan2((double)(ye - yc) / dy, (double)(xe - xc) / dx); + if (s_angol < 0) s_angol += DEGREE_TO_RADIAN(360); + if (e_angol < 0) e_angol += DEGREE_TO_RADIAN(360); + + draw_ellipse(xc, yc, r * dx, r * dy, s_angol, e_angol, BIT(m_cr, 8)); + + m_cpx = xe; + m_cpy = ye; +} + +void h63484_device::process_fifo() +{ + UINT8 data; + + dequeue_w(&data); + + if (m_sr & H63484_SR_CED) + { + m_cr = (data & 0xff) << 8; + dequeue_w(&data); + m_cr |= data & 0xff; + m_param_ptr = 0; + m_sr &= ~H63484_SR_CED; + } + else + { + m_pr[m_param_ptr] = (data & 0xff) << 8; + dequeue_w(&data); + m_pr[m_param_ptr] |= (data & 0xff); + m_param_ptr++; + } + + switch (translate_command(m_cr)) + { + case COMMAND_INVALID: + if (CMD_LOG) logerror("HD63484 '%s': \n", tag(), m_cr); + printf("H63484 '%s' Invalid Command Byte %02x\n", tag(), m_cr); + m_sr |= H63484_SR_CER; // command error + command_end_seq(); + break; + + case COMMAND_ORG: + if (m_param_ptr == 2) + { + if (CMD_LOG) logerror("HD63484 '%s': ORG 0x%04x, 0x%04x\n", tag(), m_pr[0], m_pr[1]); + m_org_dn = (m_pr[0] & 0xc000) >> 14; + m_org_dpa = ((m_pr[0] & 0xff) << 12) | ((m_pr[1] & 0xfff0) >> 4); + m_org_dpd = (m_pr[1] & 0xf); + m_cpx = m_cpy = 0; + command_end_seq(); + } + break; + + case COMMAND_WPR: // 0x0800 & ~0x1f + if (m_param_ptr == 1) + { + if (CMD_LOG) logerror("HD63484 '%s': WPR (%d) 0x%04x\n", tag(), m_cr & 0x1f, m_pr[0]); + command_wpr_exec(); + command_end_seq(); + } + break; + + case COMMAND_RPR: + if (m_param_ptr == 0) + { + if (CMD_LOG) logerror("HD63484 '%s': RPR (%d)\n", tag(), m_cr & 0x1f); + UINT16 data = command_rpr_exec(); + queue_r((data >> 8) & 0xff); + queue_r((data >> 0) & 0xff); + command_end_seq(); + } + break; + + case COMMAND_WPTN: + if(m_param_ptr == 1) + { + m_dn = m_pr[0]; // number of param words + + //if(m_dn > 0x10 || m_dn == 0) + // fatalerror("stop!\n"); + } + + if(m_param_ptr == (1 + m_dn)) + { + if (CMD_LOG) logerror("HD63484 '%s': WPTN (%d) %d", tag(), m_cr & 0x0f, m_pr[0]); + + int pra = m_cr & 0xf; + for(int i=0; i> 8) & 0xff); + queue_r((data >> 0) & 0xff); + m_rwp[m_rwp_dn]+=1; + m_rwp[m_rwp_dn]&=0xfffff; + command_end_seq(); + } + break; + + case COMMAND_WT: + if (m_param_ptr == 1) + { + if (CMD_LOG) logerror("HD63484 '%s': WT 0x%04x\n", tag(), m_pr[0]); + writeword(m_rwp[m_rwp_dn], m_pr[0]); + m_rwp[m_rwp_dn]+=1; + m_rwp[m_rwp_dn]&=0xfffff; + command_end_seq(); + } + break; + + case COMMAND_MOD: + if(m_param_ptr == 1) + { + if (CMD_LOG) logerror("HD63484 '%s': MOD (%d) 0x%04x\n", tag(), m_cr & 0x03, m_pr[0]); + UINT16 d = m_pr[0]; + UINT16 data = readword(m_rwp[m_rwp_dn]); + UINT16 res = 0; + + switch(m_cr & 0x03) + { + case 0: // replace + res = (data & ~m_mask) | (d & m_mask); + break; + case 1: // OR + res = (data & ~m_mask) | ((data | d) & m_mask); + break; + case 2: // AND + res = (data & ~m_mask) | ((data & d) & m_mask); + break; + case 3: // EOR + res = (data & ~m_mask) | ((data ^ d) & m_mask); + break; + } + + writeword(m_rwp[m_rwp_dn], res); + command_end_seq(); + } + break; + + case COMMAND_CLR: + case COMMAND_SCLR: + if (m_param_ptr == 3) + { + if (CMD_LOG) + { + if (BIT(m_cr, 10)) + logerror("HD63484 '%s': SCLR (%d) 0x%04x, %d, %d\n", tag(), m_cr & 0x03, m_pr[0], (INT16)m_pr[1], (INT16)m_pr[2]); + else + logerror("HD63484 '%s': CLR 0x%04x, %d, %d\n", tag(), m_pr[0], (INT16)m_pr[1], (INT16)m_pr[2]); + } + + command_clr_exec(); + command_end_seq(); + } + break; + + case COMMAND_CPY: + case COMMAND_SCPY: + if (m_param_ptr == 4) + { + if (CMD_LOG) + { + if (BIT(m_cr, 12)) + logerror("HD63484 '%s': SCPY (%d, %d, %d) 0x%x, 0x%x, %d, %d\n", tag(), BIT(m_cr, 11), (m_cr >> 8) & 0x07, m_cr & 0x07, m_pr[0] & 0xff, (m_pr[1]&0xfff0) >> 4, (INT16)m_pr[2], (INT16)m_pr[3]); + else + logerror("HD63484 '%s': CPY (%d, %d) 0x%x, 0x%x, %d, %d\n", tag(), BIT(m_cr, 11), (m_cr >> 8) & 0x07, m_pr[0] & 0xff, (m_pr[1]&0xfff0) >> 4, (INT16)m_pr[2], (INT16)m_pr[3]); + } + + command_cpy_exec(); + command_end_seq(); + } + break; + + case COMMAND_AMOVE: + case COMMAND_RMOVE: + if (m_param_ptr == 2) + { + if (CMD_LOG) logerror("HD63484 '%s': %cMOVE %d, %d\n", tag(), BIT(m_cr, 10) ? 'R' : 'A', (INT16)m_pr[0], (INT16)m_pr[1]); + if (BIT(m_cr, 10)) + { + m_cpx += (INT16)m_pr[0]; + m_cpy += (INT16)m_pr[1]; + } + else + { + m_cpx = (INT16)m_pr[0]; + m_cpy = (INT16)m_pr[1]; + } + command_end_seq(); + } + break; + + case COMMAND_RRCT: + case COMMAND_ARCT: + if (m_param_ptr == 2) + { + if (CMD_LOG) logerror("HD63484 '%s': %cRTC (%d, %d, %d) %d, %d\n", tag(), BIT(m_cr, 10) ? 'R' : 'A', (m_cr >> 5) & 0x07, (m_cr >> 3) & 0x03, (m_cr >> 0) & 0x07, (INT16)m_pr[0], (INT16)m_pr[1]); + command_rct_exec(); + command_end_seq(); + } + break; + + case COMMAND_RLINE: + case COMMAND_ALINE: + if (m_param_ptr == 2) + { + if (CMD_LOG) logerror("HD63484 '%s': %cLINE (%d, %d, %d) %d, %d\n", tag(), BIT(m_cr, 10) ? 'R' : 'A', (m_cr >> 5) & 0x07, (m_cr >> 3) & 0x03, (m_cr >> 0) & 0x07, (INT16)m_pr[0], (INT16)m_pr[1]); + command_line_exec(); + command_end_seq(); + } + break; + + case COMMAND_APLG: + case COMMAND_RPLG: + case COMMAND_APLL: + case COMMAND_RPLL: + if(m_param_ptr == 1) + m_dn = m_pr[0]; // number of param words + + if(m_param_ptr == (1 + m_dn*2)) + { + if (CMD_LOG) + { + logerror("HD63484 '%s': %cPL%c (%d, %d, %d) %d", tag(), BIT(m_cr, 10) ? 'R' : 'A', m_cr & 0x2000 ? 'G' : 'L', (m_cr >> 5) & 0x07, (m_cr >> 3) & 0x03, (m_cr >> 0) & 0x07, m_pr[0]); + for (int i=0; i> 5) & 0x07, (m_cr >> 3) & 0x03, (m_cr >> 0) & 0x07, m_pr[0]); + UINT16 r = m_pr[0] & 0x1fff; + draw_ellipse(m_cpx, m_cpy, r, r, DEGREE_TO_RADIAN(0), DEGREE_TO_RADIAN(360), BIT(m_cr, 8)); + command_end_seq(); + } + break; + + case COMMAND_ELPS: + if(m_param_ptr == 3) + { + if (CMD_LOG) logerror("HD63484 '%s': ELPS (%d, %d, %d, %d) %d, %d, %d\n", tag(), BIT(m_cr, 8), (m_cr >> 5) & 0x07, (m_cr >> 3) & 0x03, (m_cr >> 0) & 0x07, m_pr[0], m_pr[1], m_pr[2]); + double dx = (double)m_pr[3]; + double dy = sqrt(pow(dx, 2) / ((double)m_pr[0] / m_pr[1])); + draw_ellipse(m_cpx, m_cpy, dx, dy, DEGREE_TO_RADIAN(0), DEGREE_TO_RADIAN(360), BIT(m_cr, 8)); + command_end_seq(); + } + break; + + case COMMAND_AARC: + case COMMAND_RARC: + if(m_param_ptr == 4) + { + if (CMD_LOG) logerror("HD63484 '%s': %cARC (%d, %d, %d, %d) %d, %d, %d, %d\n", tag(), BIT(m_cr, 10) ? 'R' : 'A', BIT(m_cr, 8), (m_cr >> 5) & 0x07, (m_cr >> 3) & 0x03, (m_cr >> 0) & 0x07, (INT16)m_pr[0], (INT16)m_pr[1], (INT16)m_pr[2], (INT16)m_pr[3]); + command_arc_exec(); + command_end_seq(); + } + break; + + case COMMAND_AEARC: + case COMMAND_REARC: + if(m_param_ptr == 6) + { + if (CMD_LOG) logerror("HD63484 '%s': %cEARC (%d, %d, %d, %d) %d, %d, %d, %d, %d, %d\n", tag(), BIT(m_cr, 10) ? 'R' : 'A', BIT(m_cr, 8), (m_cr >> 5) & 0x07, (m_cr >> 3) & 0x03, (m_cr >> 0) & 0x07, m_pr[0], m_pr[1], m_pr[2], m_pr[3], m_pr[4], m_pr[5]); + command_earc_exec(); + command_end_seq(); + } + break; + + case COMMAND_AFRCT: + case COMMAND_RFRCT: + if (m_param_ptr == 2) + { + if (CMD_LOG) logerror("HD63484 '%s': %cFRCT (%d, %d, %d) %d, %d\n", tag(), BIT(m_cr, 10) ? 'R' : 'A', (m_cr >> 5) & 0x07, (m_cr >> 3) & 0x03, (m_cr >> 0) & 0x07, (INT16)m_pr[0], (INT16)m_pr[1]); + + command_frct_exec(); + command_end_seq(); + } + break; + + case COMMAND_PAINT: + if (m_param_ptr == 0) + { + if (CMD_LOG) logerror("HD63484 '%s': PAINT (%d, %d, %d, %d)\n", tag(), BIT(m_cr, 8), (m_cr >> 5) & 0x07, (m_cr >> 3) & 0x03, (m_cr >> 0) & 0x07); + paint(m_cpx, m_cpy); + command_end_seq(); + } + break; + + case COMMAND_DOT: + if (m_param_ptr == 0) + { + if (CMD_LOG) logerror("HD63484 '%s': DOT (%d, %d, %d)\n", tag(), (m_cr >> 5) & 0x07, (m_cr >> 3) & 0x03, (m_cr >> 0) & 0x07); + set_dot(m_cpx, m_cpy, 0, 0); + command_end_seq(); + } + break; + + case COMMAND_PTN: + if (m_param_ptr == 1) + { + if (CMD_LOG) logerror("HD63484 '%s': PTN (%d, %d, %d, %d, %d) 0x%04x\n", tag(), (m_cr >> 11) & 0x01, (m_cr >> 8) & 0x07, (m_cr >> 5) & 0x07, (m_cr >> 3) & 0x03, (m_cr >> 0) & 0x07, m_pr[0]); + command_ptn_exec(); + command_end_seq(); + } + break; + + case COMMAND_RGCPY: + case COMMAND_AGCPY: + if (m_param_ptr == 4) + { + if (CMD_LOG) logerror("HD63484 '%s': %cGCPY (%d, %d, %d, %d, %d) %d, %d, %d, %d\n", tag(), BIT(m_cr, 12) ? 'R' : 'A', (m_cr >> 11) & 0x01, (m_cr >> 8) & 0x07, (m_cr >> 5) & 0x07, (m_cr >> 3) & 0x03, (m_cr >> 0) & 0x07, (INT16)m_pr[0], (INT16)m_pr[1], (INT16)m_pr[2], (INT16)m_pr[3]); + + command_gcpy_exec(); + command_end_seq(); + } + break; + + default: + printf("%04x\n",m_cr); + fatalerror("stop!\n"); + } +} + +void h63484_device::exec_abort_sequence() +{ + fifo_w_clear(); + fifo_r_clear(); + m_sr = H63484_SR_WFR | H63484_SR_WFE | H63484_SR_CED; // hard-set to 0x23 +} + +UINT16 h63484_device::video_registers_r(int offset) +{ + UINT16 res = (m_vreg[offset] << 8) | (m_vreg[offset+1] & 0xff); + + switch(offset) + { + case 0x06: + res = m_dcr; + break; + + case 0x80: + res = m_screen->vpos() & 0xfff; // Raster Count + break; + + default: + if(LOG) printf("%s R\n",acrtc_regnames[m_ar/2]); + break; + } + + return res; +} + +void h63484_device::video_registers_w(int offset) +{ + UINT16 vreg_data; + + vreg_data = (m_vreg[offset]<<8)|(m_vreg[offset+1]&0xff); + + switch(offset) + { + case 0x00: // FIFO entry + queue_w((vreg_data & 0xff00) >> 8); + queue_w((vreg_data & 0x00ff) >> 0); + if(FIFO_LOG) printf("%s -> %04x\n",acrtc_regnames[m_ar/2],vreg_data); + process_fifo(); + break; + + case 0x02: // Command Entry + + if(vreg_data & 0x8000) // abort sequence (ABT) + exec_abort_sequence(); + + /* + x--- ---- ---- ---- ABorT + -x-- ---- ---- ---- PauSE + ... + ---- -xxx ---- ---- Graphic Bit Mode (bpp) + ---- ---- xxxx xxxx irq mask, directly correlated to sr + */ + m_ccr = vreg_data; + break; + + case 0x04: + m_omr = vreg_data; + break; + + case 0x06: + m_dcr = vreg_data; + recompute_parameters(); + break; + + case 0x82: // Horizontal Sync Register + m_hc = ((vreg_data & 0xff00) >> 8) + 1; + m_hsw = vreg_data & 0x1f; + recompute_parameters(); + break; + case 0x84: // Horizontal Display Register + m_hds = ((vreg_data & 0xff00) >> 8) + 1; + m_hdw = ((vreg_data & 0x00ff) >> 0) + 1; + recompute_parameters(); + break; + case 0x92: // Horizontal Window Register + m_hws = ((vreg_data & 0xff00) >> 8) + 1; + m_hww = ((vreg_data & 0x00ff) >> 0) + 1; + recompute_parameters(); + break; + + case 0x86: // Vertical Sync Register + m_vc = (vreg_data & 0xfff); + recompute_parameters(); + break; + case 0x88: // Vertical Display Register + m_vds = ((vreg_data & 0xff00) >> 8) + 1; + m_vsw = (vreg_data & 0x1f); + recompute_parameters(); + break; + case 0x8a: // Split Screen Width 1 + m_sp[1] = vreg_data & 0x0fff; + recompute_parameters(); + break; + case 0x8c: // Split Screen Width 0 + m_sp[0] = vreg_data & 0x0fff; + recompute_parameters(); + break; + case 0x8e: // Split Screen Width 2 + m_sp[2] = vreg_data & 0x0fff; + recompute_parameters(); + break; + case 0x94: // Vertical Window Register A + m_vws = (vreg_data & 0xfff) + 1; + recompute_parameters(); + break; + case 0x96: // Vertical Window Register B + m_vww = (vreg_data & 0xfff); + recompute_parameters(); + break; + + case 0xc2: // Memory Width Register + case 0xca: + case 0xd2: + case 0xda: + m_mwr[(offset & 0x18) >> 3] = vreg_data & 0xfff; // pitch + m_mwr_chr[(offset & 0x18) >> 3] = (vreg_data & 0x8000) >> 15; + break; + + case 0xc4: // Start Address Register + case 0xcc: + case 0xd4: + case 0xdc: + m_sar[(offset & 0x18) >> 3] = ((vreg_data & 0xf) << 16) | (m_sar[(offset & 0x18) >> 3] & 0xffff); + m_sda[(offset & 0x18) >> 3] = (vreg_data & 0x0f00) >> 8; + break; + + case 0xc6: // Start Address Register + case 0xce: + case 0xd6: + case 0xde: + m_sar[(offset & 0x18) >> 3] = (vreg_data & 0xffff) | (m_sar[(offset & 0x18) >> 3] & 0xf0000); + break; + + default: + if(LOG) printf("%s -> %04x\n",acrtc_regnames[m_ar/2],vreg_data); + break; + } +} + +READ16_MEMBER( h63484_device::status_r ) +{ + return m_sr; +} + +READ16_MEMBER( h63484_device::data_r ) +{ + UINT16 res = 0xffff; + + if(m_ar == 0) // FIFO read + { + UINT8 data; + + dequeue_r(&data); + res = (data & 0xff) << 8; + dequeue_r(&data); + res |= data & 0xff; + } + else + res = video_registers_r(m_ar); + + inc_ar(2); + + return res; +} + +WRITE16_MEMBER( h63484_device::address_w ) +{ + if(ACCESSING_BITS_0_7) + m_ar = data & 0xfe; +} + +WRITE16_MEMBER( h63484_device::data_w ) +{ + if(ACCESSING_BITS_8_15) + m_vreg[m_ar] = (data & 0xff00) >> 8; + + if(ACCESSING_BITS_0_7) + m_vreg[m_ar+1] = (data & 0xff); + + video_registers_w(m_ar); + + inc_ar(2); +} + +READ8_MEMBER( h63484_device::status_r ) +{ + return m_sr; +} + +WRITE8_MEMBER( h63484_device::address_w ) +{ + m_ar = data; +} + +READ8_MEMBER( h63484_device::data_r ) +{ + UINT8 res = 0xff; + + if(m_ar < 2) // FIFO read + dequeue_r(&res); + else + res = video_registers_r(m_ar & 0xfe) >> (m_ar & 1 ? 0 : 8); + + inc_ar(1); + + return res; +} + +WRITE8_MEMBER( h63484_device::data_w ) +{ + m_vreg[m_ar] = data; + + if(m_ar < 2) // FIFO write + { + queue_w(data); + if (m_ar & 1) + process_fifo(); + + m_ar ^= 1; + } + else + video_registers_w(m_ar & 0xfe); + + inc_ar(1); +} + +void h63484_device::device_start() +{ + m_display_cb.bind_relative_to(*owner()); + + register_save_state(); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void h63484_device::device_reset() +{ + m_sr = H63484_SR_CED | H63484_SR_WFR | H63484_SR_WFE; + m_ccr = m_omr = m_edg = m_dcr = m_hsw = 0; + m_hc = m_hds = m_hdw = m_hws = m_hww = 0; + m_vc = m_vws = m_vww = m_vds = m_vsw = 0; + m_sp[0] = m_sp[1] = m_sp[2] = 0; + m_ppx = m_ppy = 0; + m_cl0 = m_cl1 = 0; + m_xmin = m_ymin = m_xmax = m_ymax = 0; + m_ppx = m_pzcx = m_psx = m_pzx = m_pex = 0; + m_ppy = m_pzcy= m_psy = m_pzy = m_pey = 0; + m_ar = m_cr = 0; + m_param_ptr = 0; + m_rwp_dn = 0; + m_org_dpa = 0; + m_org_dn = 0; + m_org_dpd = 0; + m_ccmp = 0; + m_mask = -1; + m_cpx = m_cpy = 0; + m_dn = 0; + + memset(m_vreg, 0, sizeof(m_vreg)); + memset(m_fifo, 0, sizeof(m_fifo)); + memset(m_fifo_r, 0, sizeof(m_fifo_r)); + memset(m_pr, 0, sizeof(m_pr)); + memset(m_rwp, 0, sizeof(m_rwp)); + memset(m_mwr, 0, sizeof(m_mwr)); + memset(m_mwr_chr, 0, sizeof(m_mwr_chr)); + memset(m_sar, 0, sizeof(m_sar)); + memset(m_sda, 0, sizeof(m_sda)); + memset(m_pram, 0, sizeof(m_pram)); +} + +//------------------------------------------------- +// draw_graphics_line - +//------------------------------------------------- + +void h63484_device::draw_graphics_line(bitmap_ind16 &bitmap, const rectangle &cliprect, int vs, int y, int layer_n, bool active, bool ins_window) +{ + int bpp = get_bpp(); + int ppw = 16 / bpp; + UINT32 mask = (1 << bpp) - 1; + UINT32 base_offs = m_sar[layer_n] + (y - vs) * m_mwr[layer_n]; + UINT32 wind_offs = m_sar[3] + (y - m_vws) * m_mwr[3]; + int step = (m_omr & 0x08) ? 2 : 1; + int gai = (m_omr>>4) & 0x07; + int ppmc = ppw * (1 << gai) / step; // TODO: GAI > 3 + int ws = m_hsw + m_hws; + + if (m_omr & 0x08) + { + /* + According to the datasheet, in interleaved and superimposed modes: + - HDW and HWW must be even + - the relation between HDS and HWS must be even/even or odd/odd + */ + + if (m_hww & 1) + ws += step; + + if ((m_hws & 1) ^ (m_hds & 1)) + wind_offs++; + } + + for(int x=cliprect.min_x; x<=cliprect.max_x; x+=ppw) + { + UINT16 data = 0; + if (ins_window && x >= ws * ppmc && x < (ws + m_hww) * ppmc) + { + data = readword(wind_offs); + wind_offs++; + } + else if (active) + data = readword(base_offs); + + for (int b=0; b>= bpp; + } + + base_offs++; + } +} + +//------------------------------------------------- +// update_screen - +//------------------------------------------------- + +UINT32 h63484_device::update_screen(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) +{ + int l0 = cliprect.min_y + (BIT(m_dcr, 13) ? m_sp[0] : 0); + int l1 = l0 + m_sp[1]; + int l2 = l1 + (BIT(m_dcr, 11) ? m_sp[2] : 0); + + if(m_omr & 0x4000) + { + for(int y=cliprect.min_y; y<=cliprect.max_y; y++) + { + bool ins_window = BIT(m_dcr, 9) && y >= m_vws && y < m_vws+m_vww; + + if (BIT(m_dcr, 13) && y >= cliprect.min_y && y < l0) + draw_graphics_line(bitmap, cliprect, cliprect.min_y, y, 0, BIT(m_dcr, 12), ins_window); + else if (y >= l0 && y < l1) + draw_graphics_line(bitmap, cliprect, l0, y, 1, BIT(m_dcr, 14), ins_window); + else if (BIT(m_dcr, 11) && y >= l1 && y < l2) + draw_graphics_line(bitmap, cliprect, l1, y, 2, BIT(m_dcr, 10), ins_window); + } + } + return 0; +} + +void h63484_device::register_save_state() +{ + save_item(NAME(m_ar)); + save_item(NAME(m_vreg)); + save_item(NAME(m_sr)); + save_item(NAME(m_fifo)); + save_item(NAME(m_fifo_ptr)); + save_item(NAME(m_fifo_r)); + save_item(NAME(m_fifo_r_ptr)); + save_item(NAME(m_cr)); + save_item(NAME(m_pr)); + save_item(NAME(m_param_ptr)); + save_item(NAME(m_rwp)); + save_item(NAME(m_rwp_dn)); + save_item(NAME(m_org_dpa)); + save_item(NAME(m_org_dn)); + save_item(NAME(m_org_dpd)); + save_item(NAME(m_cl0)); + save_item(NAME(m_cl1)); + save_item(NAME(m_ccmp)); + save_item(NAME(m_mask)); + save_item(NAME(m_cpx)); + save_item(NAME(m_cpy)); + save_item(NAME(m_mwr)); + save_item(NAME(m_mwr_chr)); + save_item(NAME(m_sar)); + save_item(NAME(m_sda)); + save_item(NAME(m_pram)); + save_item(NAME(m_dn)); + save_item(NAME(m_ccr)); + save_item(NAME(m_omr)); + save_item(NAME(m_edg)); + save_item(NAME(m_dcr)); + save_item(NAME(m_hc)); + save_item(NAME(m_hds)); + save_item(NAME(m_hdw)); + save_item(NAME(m_hws)); + save_item(NAME(m_hww)); + save_item(NAME(m_sp)); + save_item(NAME(m_hsw)); + save_item(NAME(m_vc)); + save_item(NAME(m_vws)); + save_item(NAME(m_vww)); + save_item(NAME(m_vds)); + save_item(NAME(m_vsw)); + save_item(NAME(m_ppy)); + save_item(NAME(m_pzcy)); + save_item(NAME(m_ppx)); + save_item(NAME(m_pzcx)); + save_item(NAME(m_psx)); + save_item(NAME(m_pex)); + save_item(NAME(m_pzx)); + save_item(NAME(m_psy)); + save_item(NAME(m_pzy)); + save_item(NAME(m_pey)); + save_item(NAME(m_xmin)); + save_item(NAME(m_ymin)); + save_item(NAME(m_xmax)); + save_item(NAME(m_ymax)); +} diff --git a/src/devices/video/h63484.h b/src/devices/video/h63484.h new file mode 100644 index 00000000000..ac0232fae8f --- /dev/null +++ b/src/devices/video/h63484.h @@ -0,0 +1,189 @@ +// license:BSD-3-Clause +// copyright-holders:Angelo Salese, Sandro Ronco +/************************************************************************* + + HD63484 ACRTC + Advanced CRT Controller. + +**************************************************************************/ + +#pragma once + +#ifndef __H63484__ +#define __H63484__ + + +#include "emu.h" + + +typedef device_delegate h63484_display_delegate; + + +/*************************************************************************** + DEVICE CONFIGURATION MACROS +***************************************************************************/ + +#define MCFG_H63484_ADD(_tag, _clock, _map) \ + MCFG_DEVICE_ADD(_tag, H63484, _clock) \ + MCFG_DEVICE_ADDRESS_MAP(AS_0, _map) + +#define MCFG_H63484_ADDRESS_MAP(_map) \ + MCFG_DEVICE_ADDRESS_MAP(AS_0, _map) + +#define MCFG_H63484_DISPLAY_CALLBACK_OWNER(_class, _method) \ + h63484_device::static_set_display_callback(*device, h63484_display_delegate(&_class::_method, #_class "::" #_method, downcast<_class *>(owner))); + +#define H63484_DISPLAY_PIXELS_MEMBER(_name) void _name(bitmap_ind16 &bitmap, const rectangle &cliprect, int y, int x, UINT16 data) + + +// ======================> h63484_device + +class h63484_device : public device_t, + public device_memory_interface, + public device_video_interface +{ +public: + // construction/destruction + h63484_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + static void static_set_display_callback(device_t &device, h63484_display_delegate callback) { downcast(device).m_display_cb = callback; } + + DECLARE_WRITE16_MEMBER( address_w ); + DECLARE_WRITE16_MEMBER( data_w ); + DECLARE_READ16_MEMBER( status_r ); + DECLARE_READ16_MEMBER( data_r ); + + DECLARE_WRITE8_MEMBER( address_w ); + DECLARE_WRITE8_MEMBER( data_w ); + DECLARE_READ8_MEMBER( status_r ); + DECLARE_READ8_MEMBER( data_r ); + + UINT32 update_screen(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); + virtual const rom_entry *device_rom_region() const; + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + //virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + inline UINT16 readword(offs_t address); + inline void writeword(offs_t address, UINT16 data); + +private: + inline void inc_ar(int value); + inline void fifo_w_clear(); + inline void queue_w(UINT8 data); + inline void dequeue_w(UINT8 *data); + inline void fifo_r_clear(); + inline void queue_r(UINT8 data); + inline void dequeue_r(UINT8 *data); + inline void recompute_parameters(); + inline void command_end_seq(); + void calc_offset(INT16 x, INT16 y, UINT32 &offset, UINT8 &bit_pos); + int get_bpp(); + UINT16 get_dot(INT16 x, INT16 y); + bool set_dot(INT16 x, INT16 y, INT16 px, INT16 py); + bool set_dot(INT16 x, INT16 y, UINT16 color); + void draw_line(INT16 sx, INT16 sy, INT16 ex, INT16 ey); + void draw_ellipse(INT16 cx, INT16 cy, double dx, double dy, double s_angol, double e_angol, bool c); + void paint(INT16 sx, INT16 sy); + + void command_wpr_exec(); + UINT16 command_rpr_exec(); + void command_clr_exec(); + void command_cpy_exec(); + void command_rct_exec(); + void command_line_exec(); + void command_gcpy_exec(); + void command_ptn_exec(); + void command_plg_exec(); + void command_frct_exec(); + void command_arc_exec(); + void command_earc_exec(); + + void process_fifo(); + void exec_abort_sequence(); + UINT16 video_registers_r(int offset); + void video_registers_w(int offset); + int translate_command(UINT16 data); + void draw_graphics_line(bitmap_ind16 &bitmap, const rectangle &cliprect, int vs, int y, int layer_n, bool active, bool ins_window); + + void register_save_state(); + + h63484_display_delegate m_display_cb; + + UINT8 m_ar; + UINT8 m_vreg[0x100]; + UINT8 m_sr; + + UINT8 m_fifo[16]; /* FIFO W data queue */ + int m_fifo_ptr; /* FIFO W pointer */ + + UINT8 m_fifo_r[16]; /* FIFO R data queue */ + int m_fifo_r_ptr; /* FIFO R pointer */ + + + UINT16 m_cr; + UINT16 m_pr[0x100]; /* parameter byte register */ + int m_param_ptr; /* parameter pointer */ + + UINT32 m_rwp[4]; + UINT8 m_rwp_dn; + + UINT32 m_org_dpa; + UINT8 m_org_dn; + UINT8 m_org_dpd; + UINT16 m_cl0; + UINT16 m_cl1; + UINT16 m_ccmp; + UINT16 m_mask; + + INT16 m_cpx; + INT16 m_cpy; + + UINT16 m_mwr[4]; + UINT8 m_mwr_chr[4]; + + UINT32 m_sar[4]; + UINT8 m_sda[4]; + + UINT16 m_pram[0x10]; + UINT8 m_dn; + + UINT16 m_ccr; + UINT16 m_omr; + UINT16 m_edg; + UINT16 m_dcr; + + UINT16 m_hc, m_hds, m_hdw, m_hws, m_hww; + UINT16 m_sp[3]; + UINT8 m_hsw; + + UINT16 m_vc, m_vws, m_vww, m_vds; + UINT8 m_vsw; + + UINT16 m_ppy; + UINT16 m_pzcy; + UINT16 m_ppx; + UINT16 m_pzcx; + UINT16 m_psx; + UINT16 m_pex; + UINT16 m_pzx; + UINT16 m_psy; + UINT16 m_pzy; + UINT16 m_pey; + + UINT16 m_xmin; + UINT16 m_ymin; + UINT16 m_xmax; + UINT16 m_ymax; + + const address_space_config m_space_config; +}; + +// device type definition +extern const device_type H63484; + +#endif /* __H63484_H__ */ diff --git a/src/devices/video/hd44102.c b/src/devices/video/hd44102.c new file mode 100644 index 00000000000..e9a1a9d014d --- /dev/null +++ b/src/devices/video/hd44102.c @@ -0,0 +1,292 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + HD44102 Dot Matrix Liquid Crystal Graphic Display Column Driver emulation + +**********************************************************************/ + +#include "emu.h" +#include "hd44102.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define LOG 0 + + +#define CONTROL_DISPLAY_OFF 0x38 +#define CONTROL_DISPLAY_ON 0x39 +#define CONTROL_COUNT_DOWN_MODE 0x3a +#define CONTROL_COUNT_UP_MODE 0x3b +#define CONTROL_Y_ADDRESS_MASK 0x3f +#define CONTROL_X_ADDRESS_MASK 0xc0 +#define CONTROL_DISPLAY_START_PAGE 0x3e + + +#define STATUS_BUSY 0x80 /* not supported */ +#define STATUS_COUNT_UP 0x40 +#define STATUS_DISPLAY_OFF 0x20 +#define STATUS_RESET 0x10 /* not supported */ + + +// device type definition +const device_type HD44102 = &device_creator; + + +//************************************************************************** +// INLINE HELPERS +//************************************************************************** + +//------------------------------------------------- +// count_up_or_down - +//------------------------------------------------- + +inline void hd44102_device::count_up_or_down() +{ + if (m_status & STATUS_COUNT_UP) + { + if (++m_y > 49) m_y = 0; + } + else + { + if (--m_y < 0) m_y = 49; + } +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// hd44102_device - constructor +//------------------------------------------------- + +hd44102_device::hd44102_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, HD44102, "HD44102", tag, owner, clock, "hd44102", __FILE__), + device_video_interface(mconfig, *this), + m_cs2(0), + m_page(0), + m_x(0), + m_y(0) +{ +} + + +//------------------------------------------------- +// static_set_offsets - configuration helper +//------------------------------------------------- + +void hd44102_device::static_set_offsets(device_t &device, int sx, int sy) +{ + hd44102_device &hd44102 = downcast(device); + + hd44102.m_sx = sx; + hd44102.m_sy = sy; +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void hd44102_device::device_start() +{ + // register for state saving + save_item(NAME(m_ram[0])); + save_item(NAME(m_ram[1])); + save_item(NAME(m_ram[2])); + save_item(NAME(m_ram[3])); + save_item(NAME(m_status)); + save_item(NAME(m_output)); + save_item(NAME(m_cs2)); + save_item(NAME(m_page)); + save_item(NAME(m_x)); + save_item(NAME(m_y)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void hd44102_device::device_reset() +{ + m_status = STATUS_DISPLAY_OFF | STATUS_COUNT_UP; +} + + +//------------------------------------------------- +// read - register read +//------------------------------------------------- + +READ8_MEMBER( hd44102_device::read ) +{ + UINT8 data = 0; + + if (m_cs2) + { + data = (offset & 0x01) ? data_r(space, offset) : status_r(space, offset); + } + + return data; +} + + +//------------------------------------------------- +// write - register write +//------------------------------------------------- + +WRITE8_MEMBER( hd44102_device::write ) +{ + if (m_cs2) + { + (offset & 0x01) ? data_w(space, offset, data) : control_w(space, offset, data); + } +} + + +//------------------------------------------------- +// status_r - status read +//------------------------------------------------- + +READ8_MEMBER( hd44102_device::status_r ) +{ + return m_status; +} + + +//------------------------------------------------- +// control_w - control write +//------------------------------------------------- + +WRITE8_MEMBER( hd44102_device::control_w ) +{ + if (m_status & STATUS_BUSY) return; + + switch (data) + { + case CONTROL_DISPLAY_OFF: + if (LOG) logerror("HD44102 '%s' Display Off\n", tag()); + + m_status |= STATUS_DISPLAY_OFF; + break; + + case CONTROL_DISPLAY_ON: + if (LOG) logerror("HD44102 '%s' Display On\n", tag()); + + m_status &= ~STATUS_DISPLAY_OFF; + break; + + case CONTROL_COUNT_DOWN_MODE: + if (LOG) logerror("HD44102 '%s' Count Down Mode\n", tag()); + + m_status &= ~STATUS_COUNT_UP; + break; + + case CONTROL_COUNT_UP_MODE: + if (LOG) logerror("HD44102 '%s' Count Up Mode\n", tag()); + + m_status |= STATUS_COUNT_UP; + break; + + default: + { + int x = (data & CONTROL_X_ADDRESS_MASK) >> 6; + int y = data & CONTROL_Y_ADDRESS_MASK; + + if ((data & CONTROL_Y_ADDRESS_MASK) == CONTROL_DISPLAY_START_PAGE) + { + if (LOG) logerror("HD44102 '%s' Display Start Page %u\n", tag(), x); + + m_page = x; + } + else if (y > 49) + { + logerror("HD44102 '%s' Invalid Address X %u Y %u (%02x)!\n", tag(), data, x, y); + } + else + { + if (LOG) logerror("HD44102 '%s' Address X %u Y %u (%02x)\n", tag(), data, x, y); + + m_x = x; + m_y = y; + } + } + } +} + + +//------------------------------------------------- +// data_r - data read +//------------------------------------------------- + +READ8_MEMBER( hd44102_device::data_r ) +{ + UINT8 data = m_output; + + m_output = m_ram[m_x][m_y]; + + count_up_or_down(); + + return data; +} + + +//------------------------------------------------- +// data_w - data write +//------------------------------------------------- + +WRITE8_MEMBER( hd44102_device::data_w ) +{ + m_ram[m_x][m_y] = data; + + count_up_or_down(); +} + + +//------------------------------------------------- +// cs2_w - chip select 2 write +//------------------------------------------------- + +WRITE_LINE_MEMBER( hd44102_device::cs2_w ) +{ + m_cs2 = state; +} + + +//------------------------------------------------- +// update_screen - update screen +//------------------------------------------------- + +UINT32 hd44102_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) +{ + for (int y = 0; y < 50; y++) + { + int z = m_page << 3; + + for (int x = 0; x < 32; x++) + { + UINT8 data = m_ram[z / 8][y]; + + int sy = m_sy + z; + int sx = m_sx + y; + + if (cliprect.contains(sx, sy)) + { + int color = (m_status & STATUS_DISPLAY_OFF) ? 0 : BIT(data, z % 8); + + bitmap.pix16(sy, sx) = color; + } + + z++; + z %= 32; + } + } + return 0; +} diff --git a/src/devices/video/hd44102.h b/src/devices/video/hd44102.h new file mode 100644 index 00000000000..2ba39282e9e --- /dev/null +++ b/src/devices/video/hd44102.h @@ -0,0 +1,86 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + HD44102 Dot Matrix Liquid Crystal Graphic Display Column Driver emulation + +**********************************************************************/ + +#pragma once + +#ifndef __HD44102__ +#define __HD44102__ + +#include "emu.h" + + + +///************************************************************************* +// INTERFACE CONFIGURATION MACROS +///************************************************************************* + +#define MCFG_HD44102_ADD(_tag, _screen_tag, _sx, _sy) \ + MCFG_DEVICE_ADD(_tag, HD44102, 0) \ + MCFG_VIDEO_SET_SCREEN(_screen_tag) \ + hd44102_device::static_set_offsets(*device, _sx, _sy); + + + +///************************************************************************* +// TYPE DEFINITIONS +///************************************************************************* + +// ======================> hd44102_device + +class hd44102_device : public device_t, + public device_video_interface +{ +public: + // construction/destruction + hd44102_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // inline configuration helpers + static void static_set_offsets(device_t &device, int sx, int sy); + + DECLARE_READ8_MEMBER( read ); + DECLARE_WRITE8_MEMBER( write ); + + DECLARE_WRITE_LINE_MEMBER( cs2_w ); + + UINT32 screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + +private: + DECLARE_READ8_MEMBER( status_r ); + DECLARE_WRITE8_MEMBER( control_w ); + + DECLARE_READ8_MEMBER( data_r ); + DECLARE_WRITE8_MEMBER( data_w ); + + inline void count_up_or_down(); + + UINT8 m_ram[4][50]; // display memory + + UINT8 m_status; // status register + UINT8 m_output; // output register + + int m_cs2; // chip select + int m_page; // display start page + int m_x; // X address + int m_y; // Y address + + int m_sx; + int m_sy; +}; + + +// device type definition +extern const device_type HD44102; + + + +#endif diff --git a/src/devices/video/hd44352.c b/src/devices/video/hd44352.c new file mode 100644 index 00000000000..8b30b0afd9b --- /dev/null +++ b/src/devices/video/hd44352.c @@ -0,0 +1,439 @@ +// license:BSD-3-Clause +// copyright-holders:Sandro Ronco +/*************************************************************************** + + Hitachi HD44352 LCD controller + +***************************************************************************/ + +#include "emu.h" +#include "video/hd44352.h" + +#define LCD_BYTE_INPUT 0x01 +#define LCD_BYTE_OUTPUT 0x02 +#define LCD_CHAR_OUTPUT 0x03 +#define LCD_ON_OFF 0x04 +#define LCD_CURSOR_GRAPHIC 0x06 +#define LCD_CURSOR_CHAR 0x07 +#define LCD_SCROLL_CHAR_WIDTH 0x08 +#define LCD_CURSOR_STATUS 0x09 +#define LCD_USER_CHARACTER 0x0b +#define LCD_CONTRAST 0x0c +#define LCD_IRQ_FREQUENCY 0x0d +#define LCD_CURSOR_POSITION 0x0e + + +// devices +const device_type HD44352 = &device_creator; + +//************************************************************************** +// live device +//************************************************************************** + +//------------------------------------------------- +// hd44352_device - constructor +//------------------------------------------------- + +hd44352_device::hd44352_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock): + device_t(mconfig, HD44352, "hd44352", tag, owner, clock, "hd44352", __FILE__), + m_on_cb(*this) +{ +} + +//------------------------------------------------- +// device_validity_check - perform validity checks +// on this device +//------------------------------------------------- + +void hd44352_device::device_validity_check(validity_checker &valid) const +{ +} +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void hd44352_device::device_start() +{ + m_on_cb.resolve_safe(); + + m_on_timer = timer_alloc(ON_TIMER); + m_on_timer->adjust(attotime::from_hz(m_clock/16384), 0, attotime::from_hz(m_clock/16384)); + + save_item( NAME(m_control_lines)); + save_item( NAME(m_data_bus)); + save_item( NAME(m_state)); + save_item( NAME(m_offset)); + save_item( NAME(m_char_width)); + save_item( NAME(m_bank)); + save_item( NAME(m_lcd_on)); + save_item( NAME(m_scroll)); + save_item( NAME(m_contrast)); + save_item( NAME(m_byte_count)); + save_item( NAME(m_cursor_status)); + save_item( NAME(m_cursor_x)); + save_item( NAME(m_cursor_y)); + save_item( NAME(m_cursor_lcd)); + save_item( NAME(m_video_ram[0])); + save_item( NAME(m_video_ram[1])); + save_item( NAME(m_par)); + save_item( NAME(m_cursor)); + save_item( NAME(m_custom_char[0])); + save_item( NAME(m_custom_char[1])); + save_item( NAME(m_custom_char[2])); + save_item( NAME(m_custom_char[3])); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void hd44352_device::device_reset() +{ + memset(m_video_ram, 0x00, sizeof(m_video_ram)); + memset(m_par, 0x00, sizeof(m_par)); + memset(m_custom_char, 0x00, sizeof(m_custom_char)); + memset(m_cursor, 0x00, sizeof(m_cursor)); + m_control_lines = 0; + m_data_bus = 0xff; + m_state = 0; + m_bank = 0; + m_offset = 0; + m_char_width = 6; + m_lcd_on = 0; + m_scroll = 0; + m_byte_count = 0; + m_cursor_status = 0; + m_cursor_x = 0; + m_cursor_y = 0; + m_cursor_lcd = 0; + m_contrast = 0; +} + + +//------------------------------------------------- +// device_timer - handler timer events +//------------------------------------------------- +void hd44352_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch(id) + { + case ON_TIMER: + if (m_control_lines & 0x40) + { + m_on_cb(ASSERT_LINE); + m_on_cb(CLEAR_LINE); + } + break; + } +} + +//************************************************************************** +// device interface +//************************************************************************** + +UINT32 hd44352_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) +{ + UINT8 cw = m_char_width; + + bitmap.fill(0, cliprect); + + if (m_control_lines&0x80 && m_lcd_on) + { + for (int a=0; a<2; a++) + for (int py=0; py<4; py++) + for (int px=0; px<16; px++) + if (BIT(m_cursor_status, 4) && px == m_cursor_x && py == m_cursor_y && a == m_cursor_lcd) + { + //draw the cursor + for (int c=0; c>5) & 0x07, m_video_ram[a][py*16*cw + px*cw + c + m_scroll * 48], m_cursor[c]); + for (int b=0; b<8; b++) + { + bitmap.pix16(py*8 + b, a*cw*16 + px*cw + c) = BIT(d, 7-b); + } + } + } + else + { + for (int c=0; cu8(pos); + } +} + +void hd44352_device::data_write(UINT8 data) +{ + // verify that controller is active + if (!(m_control_lines&0x80)) + return; + + if (m_control_lines & 0x01) + { + if (!(m_control_lines&0x02) && !(m_control_lines&0x04)) + return; + + switch (m_state) + { + case 0: //parameter 0 + m_par[m_state++] = data; + break; + case 1: //parameter 1 + m_par[m_state++] = data; + break; + case 2: //parameter 2 + m_par[m_state++] = data; + break; + } + + switch (m_par[0] & 0x0f) + { + case LCD_BYTE_INPUT: + case LCD_CHAR_OUTPUT: + { + if (m_state == 1) + m_bank = BIT(data, 4); + else if (m_state == 2) + m_offset = ((data>>1)&0x3f) % 48 + (BIT(data,7) * 48); + else if (m_state == 3) + m_offset += ((data & 0x03) * 96); + } + break; + case LCD_BYTE_OUTPUT: + { + if (m_state == 1) + m_bank = BIT(data, 4); + else if (m_state == 2) + m_offset = ((data>>1)&0x3f) % 48 + (BIT(data,7) * 48); + else if (m_state == 3) + m_offset += ((data & 0x03) * 96); + } + break; + case LCD_ON_OFF: + { + if (m_state == 1) + m_lcd_on = BIT(data, 4); + m_data_bus = 0xff; + m_state = 0; + } + break; + case LCD_SCROLL_CHAR_WIDTH: + { + if (m_state == 1) + { + m_char_width = 8-((data>>4)&3); + m_scroll = ((data>>6)&3); + } + + m_data_bus = 0xff; + m_state = 0; + } + break; + case LCD_CURSOR_STATUS: + { + if (m_state == 1) + m_cursor_status = data; + m_data_bus = 0xff; + m_state = 0; + } + break; + case LCD_CONTRAST: + { + if (m_state == 1) + m_contrast = (m_contrast & 0x00ffff) | (data<<16); + else if (m_state == 2) + m_contrast = (m_contrast & 0xff00ff) | (data<<8); + else if (m_state == 3) + { + m_contrast = (m_contrast & 0xffff00) | (data<<0); + m_state = 0; + } + + m_data_bus = 0xff; + } + break; + case LCD_IRQ_FREQUENCY: + { + if (m_state == 1) + { + UINT32 on_timer_rate; + + switch((data>>4) & 0x0f) + { + case 0x00: on_timer_rate = 16384; break; + case 0x01: on_timer_rate = 8; break; + case 0x02: on_timer_rate = 16; break; + case 0x03: on_timer_rate = 32; break; + case 0x04: on_timer_rate = 64; break; + case 0x05: on_timer_rate = 128; break; + case 0x06: on_timer_rate = 256; break; + case 0x07: on_timer_rate = 512; break; + case 0x08: on_timer_rate = 1024; break; + case 0x09: on_timer_rate = 2048; break; + case 0x0a: on_timer_rate = 4096; break; + case 0x0b: on_timer_rate = 4096; break; + default: on_timer_rate = 8192; break; + } + + m_on_timer->adjust(attotime::from_hz(m_clock/on_timer_rate), 0, attotime::from_hz(m_clock/on_timer_rate)); + } + m_data_bus = 0xff; + m_state = 0; + } + break; + case LCD_CURSOR_POSITION: + { + if (m_state == 1) + m_cursor_lcd = BIT(data, 4); //0:left lcd 1:right lcd; + else if (m_state == 2) + m_cursor_x = ((data>>1)&0x3f) % 48 + (BIT(data,7) * 48); + else if (m_state == 3) + { + m_cursor_y = data & 0x03; + m_state = 0; + } + + m_data_bus = 0xff; + } + break; + } + + m_byte_count = 0; + m_data_bus = 0xff; + } + else + { + switch (m_par[0] & 0x0f) + { + case LCD_BYTE_INPUT: + { + if (((m_par[0]>>5) & 0x07) != 0x03) + break; + + m_offset %= 0x180; + m_data_bus = ((m_video_ram[m_bank][m_offset]<<4)&0xf0) | ((m_video_ram[m_bank][m_offset]>>4)&0x0f); + m_offset++; m_byte_count++; + } + break; + case LCD_BYTE_OUTPUT: + { + m_offset %= 0x180; + m_video_ram[m_bank][m_offset] = compute_newval((m_par[0]>>5) & 0x07, m_video_ram[m_bank][m_offset], data); + m_offset++; m_byte_count++; + + m_data_bus = 0xff; + } + break; + case LCD_CHAR_OUTPUT: + { + int char_pos = data*8; + + for (int i=0; i>5) & 0x07, m_video_ram[m_bank][m_offset], get_char(char_pos)); + m_offset++; char_pos++; + } + + m_byte_count++; + m_data_bus = 0xff; + } + break; + case LCD_CURSOR_GRAPHIC: + if (m_byte_count<8) + { + m_cursor[m_byte_count] = data; + m_byte_count++; + m_data_bus = 0xff; + } + break; + case LCD_CURSOR_CHAR: + if (m_byte_count<1) + { + UINT8 char_code = ((data<<4)&0xf0) | ((data>>4)&0x0f); + + for (int i=0; i<8; i++) + m_cursor[i] = get_char(char_code*8 + i); + + m_byte_count++; + m_data_bus = 0xff; + } + break; + case LCD_USER_CHARACTER: + if (m_byte_count<8) + { + m_custom_char[(m_par[1]&0x03)][m_byte_count] = data; + m_byte_count++; + m_data_bus = 0xff; + } + break; + default: + m_data_bus = 0xff; + } + + m_state=0; + } +} + +UINT8 hd44352_device::data_read() +{ + return m_data_bus; +} diff --git a/src/devices/video/hd44352.h b/src/devices/video/hd44352.h new file mode 100644 index 00000000000..b305e8ccfa9 --- /dev/null +++ b/src/devices/video/hd44352.h @@ -0,0 +1,81 @@ +// license:BSD-3-Clause +// copyright-holders:Sandro Ronco +/*************************************************************************** + + Hitachi HD44352 LCD controller + +***************************************************************************/ + +#pragma once + +#ifndef __hd44352_H__ +#define __hd44352_H__ + + +#define MCFG_HD44352_ON_CB(_devcb) \ + devcb = &hd44352_device::set_on_callback(*device, DEVCB_##_devcb); + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> hd44352_device + +class hd44352_device : + public device_t +{ +public: + // construction/destruction + hd44352_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + template static devcb_base &set_on_callback(device_t &device, _Object object) { return downcast(device).m_on_cb.set_callback(object); } + + // device interface + UINT8 data_read(); + void data_write(UINT8 data); + void control_write(UINT8 data); + + UINT32 screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + virtual void device_validity_check(validity_checker &valid) const; + +private: + UINT8 compute_newval(UINT8 type, UINT8 oldval, UINT8 newval); + UINT8 get_char(UINT16 pos); + + static const device_timer_id ON_TIMER = 1; + emu_timer *m_on_timer; + + UINT8 m_video_ram[2][0x180]; + UINT8 m_control_lines; + UINT8 m_data_bus; + UINT8 m_par[3]; + UINT8 m_state; + UINT16 m_bank; + UINT16 m_offset; + UINT8 m_char_width; + UINT8 m_lcd_on; + UINT8 m_scroll; + UINT32 m_contrast; + + UINT8 m_custom_char[4][8]; // 4 chars * 8 bytes + UINT8 m_byte_count; + UINT8 m_cursor_status; + UINT8 m_cursor[8]; + UINT8 m_cursor_x; + UINT8 m_cursor_y; + UINT8 m_cursor_lcd; + + devcb_write_line m_on_cb; // ON line callback +}; + +// device type definition +extern const device_type HD44352; + +#endif diff --git a/src/devices/video/hd44780.c b/src/devices/video/hd44780.c new file mode 100644 index 00000000000..b21dc2e04e1 --- /dev/null +++ b/src/devices/video/hd44780.c @@ -0,0 +1,569 @@ +// license:BSD-3-Clause +// copyright-holders:Sandro Ronco +/*************************************************************************** + + Hitachi HD44780 LCD controller + + TODO: + - dump internal CGROM + - emulate osc pin, determine video timings and busy flag duration from it + +***************************************************************************/ + +#include "emu.h" +#include "video/hd44780.h" + +#define LOG 0 + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type HD44780 = &device_creator; +const device_type KS0066_F05 = &device_creator; + + +//------------------------------------------------- +// ROM( hd44780 ) +//------------------------------------------------- + +ROM_START( hd44780_a00 ) + ROM_REGION( 0x1000, "cgrom", 0 ) + ROM_LOAD( "hd44780_a00.bin", 0x0000, 0x1000, BAD_DUMP CRC(01d108e2) SHA1(bc0cdf0c9ba895f22e183c7bd35a3f655f2ca96f)) // from page 17 of the HD44780 datasheet +ROM_END + +ROM_START( ks0066_f05 ) + ROM_REGION( 0x1000, "cgrom", 0 ) + ROM_LOAD( "ks0066_f05.bin", 0x0000, 0x1000, BAD_DUMP CRC(af9e7bd6) SHA1(0196e871584ee5d370856e7307c0f9d1466e3e51)) // from page 51 of the KS0066 datasheet +ROM_END + +//************************************************************************** +// live device +//************************************************************************** + +//------------------------------------------------- +// hd44780_device - constructor +//------------------------------------------------- + +hd44780_device::hd44780_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, HD44780, "HD44780 A00", tag, owner, clock, "hd44780_a00", __FILE__), + m_pixel_update_func(NULL) +{ + set_charset_type(CHARSET_HD44780_A00); +} + +hd44780_device::hd44780_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + m_pixel_update_func(NULL) +{ +} + +ks0066_f05_device::ks0066_f05_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + hd44780_device(mconfig, KS0066_F05, "KS0066 F05", tag, owner, clock, "ks0066_f05", __FILE__) +{ + set_charset_type(CHARSET_KS0066_F05); +} + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *hd44780_device::device_rom_region() const +{ + switch (m_charset_type) + { + case CHARSET_HD44780_A00: return ROM_NAME( hd44780_a00 ); + case CHARSET_KS0066_F05: return ROM_NAME( ks0066_f05 ); + } + + return NULL; +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void hd44780_device::device_start() +{ + if (region()) + m_cgrom = region()->base(); + else + m_cgrom = memregion("cgrom")->base(); + + m_busy_timer = timer_alloc(TIMER_BUSY); + m_blink_timer = timer_alloc(TIMER_BLINKING); + m_blink_timer->adjust(attotime::from_msec(409), 0, attotime::from_msec(409)); + + // state saving + save_item(NAME(m_busy_flag)); + save_item(NAME(m_ac)); + save_item(NAME(m_dr)); + save_item(NAME(m_ir)); + save_item(NAME(m_active_ram)); + save_item(NAME(m_display_on)); + save_item(NAME(m_cursor_on)); + save_item(NAME(m_shift_on)); + save_item(NAME(m_blink_on)); + save_item(NAME(m_direction)); + save_item(NAME(m_data_len)); + save_item(NAME(m_num_line)); + save_item(NAME(m_char_size)); + save_item(NAME(m_disp_shift)); + save_item(NAME(m_blink)); + save_item(NAME(m_ddram)); + save_item(NAME(m_cgram)); + save_item(NAME(m_nibble)); + save_item(NAME(m_rs_state)); + save_item(NAME(m_rw_state)); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void hd44780_device::device_reset() +{ + memset(m_ddram, 0x20, sizeof(m_ddram)); // filled with SPACE char + memset(m_cgram, 0, sizeof(m_cgram)); + + m_ac = 0; + m_dr = 0; + m_ir = 0; + m_active_ram = DDRAM; + m_display_on = false; + m_cursor_on = false; + m_blink_on = false; + m_shift_on = false; + m_direction = 1; + m_data_len = 8; + m_num_line = 1; + m_char_size = 8; + m_disp_shift = 0; + m_blink = false; + m_nibble = false; + m_first_cmd = true; + m_rs_state = 0; + m_rw_state = 0; + + set_busy_flag(1520); +} + + +//------------------------------------------------- +// device_timer - handler timer events +//------------------------------------------------- + +void hd44780_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch (id) + { + case TIMER_BUSY: + m_busy_flag = false; + break; + + case TIMER_BLINKING: + m_blink = !m_blink; + break; + } +} + + +//************************************************************************** +// HELPERS +//************************************************************************** + +void hd44780_device::set_charset_type(int type) +{ + m_charset_type = type; +} + +void hd44780_device::set_busy_flag(UINT16 usec) +{ + m_busy_flag = true; + m_busy_timer->adjust( attotime::from_usec( usec ) ); +} + +void hd44780_device::correct_ac() +{ + if (m_active_ram == DDRAM) + { + int max_ac = (m_num_line == 1) ? 0x4f : 0x67; + + if (m_ac > max_ac) + m_ac -= max_ac + 1; + else if (m_ac < 0) + m_ac = max_ac; + else if (m_num_line == 2 && m_ac > 0x27 && m_ac < 0x40) + m_ac = 0x40 + (m_ac - 0x28); + } + else + m_ac &= 0x3f; +} + +void hd44780_device::update_ac(int direction) +{ + if (m_active_ram == DDRAM && m_num_line == 2 && direction == -1 && m_ac == 0x40) + m_ac = 0x27; + else + m_ac += direction; + + correct_ac(); +} + +void hd44780_device::shift_display(int direction) +{ + m_disp_shift += direction; + + if (m_disp_shift == 0x50) + m_disp_shift = 0; + else if (m_disp_shift == -1) + m_disp_shift = 0x4f; +} + +void hd44780_device::update_nibble(int rs, int rw) +{ + if (m_rs_state != rs || m_rw_state != rw) + { + m_rs_state = rs; + m_rw_state = rw; + m_nibble = false; + } + + m_nibble = !m_nibble; +} + +inline void hd44780_device::pixel_update(bitmap_ind16 &bitmap, UINT8 line, UINT8 pos, UINT8 y, UINT8 x, int state) +{ + if (m_pixel_update_func != NULL) + { + m_pixel_update_func(*this, bitmap, line, pos, y, x, state); + } + else + { + UINT8 line_height = (m_char_size == 8) ? m_char_size : m_char_size + 1; + + if (m_lines <= 2) + { + if (pos < m_chars) + bitmap.pix16(line * (line_height + 1) + y, pos * 6 + x) = state; + } + else if (m_lines <= 4) + { + if (pos < m_chars*2) + { + if (pos >= m_chars) + { + line += 2; + pos -= m_chars; + } + + if (line < m_lines) + bitmap.pix16(line * (line_height + 1) + y, pos * 6 + x) = state; + } + } + else + { + fatalerror("%s: use a custom callback for this LCD configuration (%d x %d)\n", tag(), m_lines, m_chars); + } + } +} + + +//************************************************************************** +// device interface +//************************************************************************** + +const UINT8 *hd44780_device::render() +{ + memset(m_render_buf, 0, sizeof(m_render_buf)); + + if (m_display_on) + { + UINT8 line_size = 80 / m_num_line; + + for (int line = 0; line < m_num_line; line++) + { + for (int pos = 0; pos < line_size; pos++) + { + UINT16 char_pos = line * 0x40 + ((pos + m_disp_shift) % line_size); + + int char_base = 0; + if (m_ddram[char_pos] < 0x10) + { + // draw CGRAM characters + if (m_char_size == 8) + char_base = (m_ddram[char_pos] & 0x07) * 8; + else + char_base = ((m_ddram[char_pos] >> 1) & 0x03) * 16; + } + else + { + // draw CGROM characters + char_base = m_ddram[char_pos] * 0x10; + } + + const UINT8 * charset = (m_ddram[char_pos] < 0x10) ? m_cgram : m_cgrom; + UINT8 *dest = m_render_buf + 16 * (line * line_size + pos); + memcpy (dest, charset + char_base, m_char_size); + + if (char_pos == m_ac) + { + // draw the cursor + if (m_cursor_on) + dest[m_char_size - 1] = 0x1f; + + if (!m_blink && m_blink_on) + memset(dest, 0x1f, m_char_size); + } + } + } + } + + return m_render_buf; +} + +UINT32 hd44780_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) +{ + bitmap.fill(0, cliprect); + const UINT8 *img = render(); + + UINT8 line_size = 80 / m_num_line; + + for (int line = 0; line < m_num_line; line++) + { + for (int pos = 0; pos < line_size; pos++) + { + const UINT8 *src = img + 16 * (line * line_size + pos); + for (int y = 0; y < m_char_size; y++) + for (int x = 0; x < 5; x++) + pixel_update(bitmap, line, pos, y, x, BIT(src[y], 4 - x)); + } + } + + return 0; +} + +READ8_MEMBER(hd44780_device::read) +{ + switch (offset & 0x01) + { + case 0: return control_read(space, 0); + case 1: return data_read(space, 0); + } + + return 0; +} + +WRITE8_MEMBER(hd44780_device::write) +{ + switch (offset & 0x01) + { + case 0: control_write(space, 0, data); break; + case 1: data_write(space, 0, data); break; + } +} + +WRITE8_MEMBER(hd44780_device::control_write) +{ + if (m_data_len == 4) + { + update_nibble(0, 0); + + if (m_nibble) + { + m_ir = data & 0xf0; + return; + } + else + { + m_ir |= ((data >> 4) & 0x0f); + } + } + else + { + m_ir = data; + } + + if (BIT(m_ir, 7)) + { + // set DDRAM address + m_active_ram = DDRAM; + m_ac = m_ir & 0x7f; + correct_ac(); + set_busy_flag(37); + + if (LOG) logerror("HD44780 '%s': set DDRAM address %x\n", tag(), m_ac); + return; + } + else if (BIT(m_ir, 6)) + { + // set CGRAM address + m_active_ram = CGRAM; + m_ac = m_ir & 0x3f; + set_busy_flag(37); + + if (LOG) logerror("HD44780 '%s': set CGRAM address %x\n", tag(), m_ac); + return; + } + else if (BIT(m_ir, 5)) + { + // function set + if (!m_first_cmd && m_data_len == (BIT(m_ir, 4) ? 8 : 4) && (m_char_size != (BIT(m_ir, 2) ? 10 : 8) || m_num_line != (BIT(m_ir, 3) + 1))) + { + logerror("HD44780 '%s': function set cannot be executed after other instructions unless the interface data length is changed\n", tag()); + return; + } + + m_char_size = BIT(m_ir, 2) ? 10 : 8; + m_data_len = BIT(m_ir, 4) ? 8 : 4; + m_num_line = BIT(m_ir, 3) + 1; + correct_ac(); + set_busy_flag(37); + + if (LOG) logerror("HD44780 '%s': char size 5x%d, data len %d, lines %d\n", tag(), m_char_size, m_data_len, m_num_line); + return; + } + else if (BIT(m_ir, 4)) + { + // cursor or display shift + int direction = (BIT(m_ir, 2)) ? +1 : -1; + + if (LOG) logerror("HD44780 '%s': %s shift %d\n", tag(), BIT(m_ir, 3) ? "display" : "cursor", direction); + + if (BIT(m_ir, 3)) + shift_display(direction); + else + update_ac(direction); + + set_busy_flag(37); + } + else if (BIT(m_ir, 3)) + { + // display on/off control + m_display_on = BIT(m_ir, 2); + m_cursor_on = BIT(m_ir, 1); + m_blink_on = BIT(m_ir, 0); + set_busy_flag(37); + + if (LOG) logerror("HD44780 '%s': display %d, cursor %d, blink %d\n", tag(), m_display_on, m_cursor_on, m_blink_on); + } + else if (BIT(m_ir, 2)) + { + // entry mode set + m_direction = (BIT(m_ir, 1)) ? +1 : -1; + m_shift_on = BIT(m_ir, 0); + set_busy_flag(37); + + if (LOG) logerror("HD44780 '%s': entry mode set: direction %d, shift %d\n", tag(), m_direction, m_shift_on); + } + else if (BIT(m_ir, 1)) + { + // return home + if (LOG) logerror("HD44780 '%s': return home\n", tag()); + + m_ac = 0; + m_active_ram = DDRAM; + m_direction = 1; + m_disp_shift = 0; + set_busy_flag(1520); + } + else if (BIT(m_ir, 0)) + { + // clear display + if (LOG) logerror("HD44780 '%s': clear display\n", tag()); + + m_ac = 0; + m_active_ram = DDRAM; + m_direction = 1; + m_disp_shift = 0; + memset(m_ddram, 0x20, sizeof(m_ddram)); + set_busy_flag(1520); + } + + m_first_cmd = false; +} + +READ8_MEMBER(hd44780_device::control_read) +{ + if (m_data_len == 4) + { + if (!space.debugger_access()) + update_nibble(0, 1); + + if (m_nibble) + return (m_busy_flag ? 0x80 : 0) | (m_ac & 0x70); + else + return (m_ac << 4) & 0xf0; + } + else + { + return (m_busy_flag ? 0x80 : 0) | (m_ac & 0x7f); + } +} + +WRITE8_MEMBER(hd44780_device::data_write) +{ + if (m_busy_flag) + { + logerror("HD44780 '%s': Ignoring data write %02x due of busy flag\n", tag(), data); + return; + } + + if (m_data_len == 4) + { + update_nibble(1, 0); + + if (m_nibble) + { + m_dr = data & 0xf0; + return; + } + else + { + m_dr |= ((data >> 4) & 0x0f); + } + } + else + { + m_dr = data; + } + + if (LOG) logerror("HD44780 '%s': %sRAM write %x %x '%c'\n", tag(), m_active_ram == DDRAM ? "DD" : "CG", m_ac, m_dr, isprint(m_dr) ? m_dr : '.'); + + if (m_active_ram == DDRAM) + m_ddram[m_ac] = m_dr; + else + m_cgram[m_ac] = m_dr; + + update_ac(m_direction); + if (m_shift_on) + shift_display(m_direction); + set_busy_flag(41); +} + +READ8_MEMBER(hd44780_device::data_read) +{ + UINT8 data = (m_active_ram == DDRAM) ? m_ddram[m_ac] : m_cgram[m_ac]; + + if (LOG) logerror("HD44780 '%s': %sRAM read %x %c\n", tag(), m_active_ram == DDRAM ? "DD" : "CG", m_ac, data); + + if (m_data_len == 4) + { + if (!space.debugger_access()) + update_nibble(1, 1); + + if (m_nibble) + return data & 0xf0; + else + data = (data << 4) & 0xf0; + } + + if (!space.debugger_access()) + { + update_ac(m_direction); + set_busy_flag(41); + } + + return data; +} diff --git a/src/devices/video/hd44780.h b/src/devices/video/hd44780.h new file mode 100644 index 00000000000..c175ccb9e47 --- /dev/null +++ b/src/devices/video/hd44780.h @@ -0,0 +1,146 @@ +// license:BSD-3-Clause +// copyright-holders:Sandro Ronco +/*************************************************************************** + + Hitachi HD44780 LCD controller + +***************************************************************************/ + +#pragma once + +#ifndef __HD44780_H__ +#define __HD44780_H__ + + +#define MCFG_HD44780_ADD( _tag ) \ + MCFG_DEVICE_ADD( _tag, HD44780, 0 ) + +#define MCFG_KS0066_F05_ADD( _tag ) \ + MCFG_DEVICE_ADD( _tag, KS0066_F05, 0 ) + +#define MCFG_HD44780_LCD_SIZE(_lines, _chars) \ + hd44780_device::static_set_lcd_size(*device, _lines, _chars); + +#define MCFG_HD44780_PIXEL_UPDATE_CB(_cb) \ + hd44780_device::static_set_pixel_update_cb(*device, _cb); + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +typedef void (*hd44780_pixel_update_func)(device_t &device, bitmap_ind16 &bitmap, UINT8 line, UINT8 pos, UINT8 y, UINT8 x, int state); +#define HD44780_PIXEL_UPDATE(name) void name(device_t &device, bitmap_ind16 &bitmap, UINT8 line, UINT8 pos, UINT8 y, UINT8 x, int state) + + +// ======================> hd44780_device + +class hd44780_device : public device_t +{ +public: + // construction/destruction + hd44780_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + hd44780_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + // static configuration helpers + static void static_set_lcd_size(device_t &device, int _lines, int _chars) { hd44780_device &dev=downcast(device); dev.m_lines = _lines; dev.m_chars = _chars; } + static void static_set_pixel_update_cb(device_t &device, hd44780_pixel_update_func _cb) { downcast(device).m_pixel_update_func = _cb; } + + // device interface + virtual DECLARE_WRITE8_MEMBER(write); + virtual DECLARE_READ8_MEMBER(read); + virtual DECLARE_WRITE8_MEMBER(control_write); + virtual DECLARE_READ8_MEMBER(control_read); + virtual DECLARE_WRITE8_MEMBER(data_write); + virtual DECLARE_READ8_MEMBER(data_read); + + const UINT8 *render(); + virtual UINT32 screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + + // charset + enum + { + CHARSET_HD44780_A00, + CHARSET_KS0066_F05 /*, + CHARSET_HD44780_A01, + CHARSET_HD44780_A02, + CHARSET_KS0066_F00, + CHARSET_KS0066_F03, + CHARSET_KS0066_F04, + CHARSET_KS0066_F06, + CHARSET_KS0066_F59 + */ + }; + + void set_charset_type(int type); + +private: + // internal helper + void set_busy_flag(UINT16 usec); + void correct_ac(); + void update_ac(int direction); + void update_nibble(int rs, int rw); + void shift_display(int direction); + void pixel_update(bitmap_ind16 &bitmap, UINT8 line, UINT8 pos, UINT8 y, UINT8 x, int state); + + // internal state + static const device_timer_id TIMER_BUSY = 0; + static const device_timer_id TIMER_BLINKING = 1; + + emu_timer * m_blink_timer; + emu_timer * m_busy_timer; + + UINT8 m_lines; // number of lines + UINT8 m_chars; // chars for line + hd44780_pixel_update_func m_pixel_update_func; // pixel update callback + + bool m_busy_flag; // busy flag + UINT8 m_ddram[0x80]; // internal display data RAM + UINT8 m_cgram[0x40]; // internal chargen RAM + UINT8 * m_cgrom; // internal chargen ROM + int m_ac; // address counter + UINT8 m_dr; // data register + UINT8 m_ir; // instruction register + UINT8 m_active_ram; // DDRAM or CGRAM + bool m_display_on; // display on/off + bool m_cursor_on; // cursor on/off + bool m_blink_on; // blink on/off + bool m_shift_on; // shift on/off + int m_disp_shift; // display shift + int m_direction; // auto increment/decrement (-1 or +1) + UINT8 m_data_len; // interface data length 4 or 8 bit + UINT8 m_num_line; // number of lines + UINT8 m_char_size; // char size 5x8 or 5x10 + bool m_blink; + bool m_first_cmd; + int m_rs_state; + int m_rw_state; + bool m_nibble; + int m_charset_type; + UINT8 m_render_buf[80 * 16]; + + enum { DDRAM, CGRAM }; +}; + +// ======================> ks0066_f05_device + +class ks0066_f05_device : public hd44780_device +{ +public: + // construction/destruction + ks0066_f05_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +// device type definition +extern const device_type HD44780; +extern const device_type KS0066_F05; + +#endif diff --git a/src/devices/video/hd61830.c b/src/devices/video/hd61830.c new file mode 100644 index 00000000000..a9a21e7dbc5 --- /dev/null +++ b/src/devices/video/hd61830.c @@ -0,0 +1,535 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Hitachi HD61830 LCD Timing Controller emulation + +**********************************************************************/ + +#include "hd61830.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type HD61830 = &device_creator; +const device_type HD61830B = &device_creator; + + +// default address map +static ADDRESS_MAP_START( hd61830, AS_0, 8, hd61830_device ) + AM_RANGE(0x0000, 0xffff) AM_RAM +ADDRESS_MAP_END + + +// internal character generator ROM +ROM_START( hd61830 ) + ROM_REGION( 0x5c0, "hd61830", 0 ) // internal 7360-bit chargen ROM + ROM_LOAD( "hd61830.bin", 0x000, 0x5c0, BAD_DUMP CRC(06a934da) SHA1(bf3f074db5dc92e6f530cb18d6c013563099a87d) ) // typed in from manual +ROM_END + + +//------------------------------------------------- +// device_rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *hd61830_device::device_rom_region() const +{ + return ROM_NAME(hd61830); +} + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define LOG 0 + +static const int CYCLES[] = +{ + 4, 4, 4, 4, 4, -1, -1, -1, 4, 4, 4, 4, 6, 6, 36, 36 +}; + +const int MODE_EXTERNAL_CG = 0x01; +const int MODE_GRAPHIC = 0x02; +const int MODE_CURSOR = 0x04; +const int MODE_BLINK = 0x08; +const int MODE_MASTER = 0x10; +const int MODE_DISPLAY_ON = 0x20; + + + +//************************************************************************** +// INLINE HELPERS +//************************************************************************** + +//------------------------------------------------- +// readbyte - read a byte at the given address +//------------------------------------------------- + +inline UINT8 hd61830_device::readbyte(offs_t address) +{ + return space().read_byte(address); +} + + +//------------------------------------------------- +// writebyte - write a byte at the given address +//------------------------------------------------- + +inline void hd61830_device::writebyte(offs_t address, UINT8 data) +{ + space().write_byte(address, data); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// hd61830_device - constructor +//------------------------------------------------- + +hd61830_device::hd61830_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, HD61830, "HD61830 LCDC", tag, owner, clock, "hd61830", __FILE__), + device_memory_interface(mconfig, *this), + device_video_interface(mconfig, *this), + m_read_rd(*this), + m_bf(false), + m_cac(0), + m_blink(0), + m_cursor(0), + m_space_config("videoram", ENDIANNESS_LITTLE, 8, 16, 0, NULL, *ADDRESS_MAP_NAME(hd61830)), + m_char_rom(*this, "hd61830") +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void hd61830_device::device_start() +{ + // allocate timers + m_busy_timer = timer_alloc(); + + // resolve callbacks + m_read_rd.resolve_safe(0); + + // register for state saving + save_item(NAME(m_bf)); + save_item(NAME(m_ir)); + save_item(NAME(m_mcr)); + save_item(NAME(m_dor)); + save_item(NAME(m_cac)); + save_item(NAME(m_dsa)); + save_item(NAME(m_vp)); + save_item(NAME(m_hp)); + save_item(NAME(m_hn)); + save_item(NAME(m_nx)); + save_item(NAME(m_cp)); + save_item(NAME(m_blink)); + save_item(NAME(m_cursor)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void hd61830_device::device_reset() +{ + // display off, slave mode + m_mcr &= ~(MODE_MASTER | MODE_DISPLAY_ON); + + // default horizontal pitch + m_hp = 6; +} + + +//------------------------------------------------- +// device_timer - handler timer events +//------------------------------------------------- + +void hd61830_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + // clear busy flag + m_bf = false; +} + + +//------------------------------------------------- +// memory_space_config - return a description of +// any address spaces owned by this device +//------------------------------------------------- + +const address_space_config *hd61830_device::memory_space_config(address_spacenum spacenum) const +{ + return (spacenum == AS_0) ? &m_space_config : NULL; +} + + +/*------------------------------------------------- + set_busy_flag - set busy flag and arm timer + to clear it later +-------------------------------------------------*/ + +void hd61830_device::set_busy_flag() +{ + // set busy flag + //m_bf = true; TODO figure out correct timing + + // adjust busy timer + m_busy_timer->adjust(clocks_to_attotime(CYCLES[m_ir])); +} + + +//------------------------------------------------- +// status_r - status register read +//------------------------------------------------- + +READ8_MEMBER( hd61830_device::status_r ) +{ + if (LOG) logerror("HD61830 '%s' Status Read: %s\n", tag(), m_bf ? "busy" : "ready"); + + return m_bf ? 0x80 : 0; +} + + +//------------------------------------------------- +// control_w - instruction register write +//------------------------------------------------- + +WRITE8_MEMBER( hd61830_device::control_w ) +{ + m_ir = data; +} + + +//------------------------------------------------- +// data_r - data register read +//------------------------------------------------- + +READ8_MEMBER( hd61830_device::data_r ) +{ + UINT8 data = m_dor; + + if (LOG) logerror("HD61830 '%s' Display Data Read %02x\n", tag(), m_dor); + + m_dor = readbyte(m_cac); + + m_cac++; + + return data; +} + + +//------------------------------------------------- +// data_w - data register write +//------------------------------------------------- + +WRITE8_MEMBER( hd61830_device::data_w ) +{ + if (m_bf) + { + logerror("HD61830 '%s' Ignoring data write %02x due to business\n", tag(), data); + return; + } + + switch (m_ir) + { + case INSTRUCTION_MODE_CONTROL: + m_mcr = data; + + if (LOG) + { + logerror("HD61830 '%s' %s CG\n", tag(), (data & MODE_EXTERNAL_CG) ? "External" : "Internal"); + logerror("HD61830 '%s' %s Display Mode\n", tag(), (data & MODE_GRAPHIC) ? "Graphic" : "Character"); + logerror("HD61830 '%s' %s Mode\n", tag(), (data & MODE_MASTER) ? "Master" : "Slave"); + logerror("HD61830 '%s' Cursor %s\n", tag(), (data & MODE_CURSOR) ? "On" : "Off"); + logerror("HD61830 '%s' Blink %s\n", tag(), (data & MODE_BLINK) ? "On" : "Off"); + logerror("HD61830 '%s' Display %s\n", tag(), (data & MODE_DISPLAY_ON) ? "On" : "Off"); + } + break; + + case INSTRUCTION_CHARACTER_PITCH: + m_hp = (data & 0x07) + 1; + m_vp = (data >> 4) + 1; + + if (LOG) logerror("HD61830 '%s' Horizontal Character Pitch: %u\n", tag(), m_hp); + if (LOG) logerror("HD61830 '%s' Vertical Character Pitch: %u\n", tag(), m_vp); + break; + + case INSTRUCTION_NUMBER_OF_CHARACTERS: + m_hn = (data & 0x7f) + 1; + + if (LOG) logerror("HD61830 '%s' Number of Characters: %u\n", tag(), m_hn); + break; + + case INSTRUCTION_NUMBER_OF_TIME_DIVISIONS: + m_nx = (data & 0x7f) + 1; + + if (LOG) logerror("HD61830 '%s' Number of Time Divisions: %u\n", tag(), m_nx); + break; + + case INSTRUCTION_CURSOR_POSITION: + m_cp = (data & 0x7f) + 1; + + if (LOG) logerror("HD61830 '%s' Cursor Position: %u\n", tag(), m_cp); + break; + + case INSTRUCTION_DISPLAY_START_LOW: + m_dsa = (m_dsa & 0xff00) | data; + + if (LOG) logerror("HD61830 '%s' Display Start Address Low %04x\n", tag(), m_dsa); + break; + + case INSTRUCTION_DISPLAY_START_HIGH: + m_dsa = (data << 8) | (m_dsa & 0xff); + + if (LOG) logerror("HD61830 '%s' Display Start Address High %04x\n", tag(), m_dsa); + break; + + case INSTRUCTION_CURSOR_ADDRESS_LOW: + if (BIT(m_cac, 7) && !BIT(data, 7)) + { + m_cac = (((m_cac >> 8) + 1) << 8) | data; + } + else + { + m_cac = (m_cac & 0xff00) | data; + } + + if (LOG) logerror("HD61830 '%s' Cursor Address Low %02x: %04x\n", tag(), data, m_cac); + break; + + case INSTRUCTION_CURSOR_ADDRESS_HIGH: + m_cac = (data << 8) | (m_cac & 0xff); + + if (LOG) logerror("HD61830 '%s' Cursor Address High %02x: %04x\n", tag(), data, m_cac); + break; + + case INSTRUCTION_DISPLAY_DATA_WRITE: + writebyte(m_cac, data); + + if (LOG) logerror("HD61830 '%s' Display Data Write %02x -> %04x row %u col %u\n", tag(), data, m_cac, m_cac / 40, m_cac % 40); + + m_cac++; + break; + + case INSTRUCTION_CLEAR_BIT: + { + int bit = data & 0x07; + UINT8 md = readbyte(m_cac); + + md &= ~(1 << bit); + + if (LOG) logerror("HD61830 '%s' Clear Bit %u at %04x\n", tag(), bit + 1, m_cac); + + writebyte(m_cac, md); + + m_cac++; + } + break; + + case INSTRUCTION_SET_BIT: + { + int bit = data & 0x07; + UINT8 md = readbyte(m_cac); + + md |= 1 << bit; + + if (LOG) logerror("HD61830 '%s' Set Bit %u at %04x\n", tag(), bit + 1, m_cac); + + writebyte(m_cac, md); + + m_cac++; + } + break; + + default: + logerror("HD61830 '%s' Illegal Instruction %02x!\n", tag(), m_ir); + return; + } + + // burn cycles + set_busy_flag(); +} + + +//------------------------------------------------- +// draw_scanline - draw one graphics scanline +//------------------------------------------------- + +UINT16 hd61830_device::draw_scanline(bitmap_ind16 &bitmap, const rectangle &cliprect, int y, UINT16 ra) +{ + for (int sx = 0; sx < m_hn; sx+=2) + { + UINT8 data1 = readbyte(ra++); + UINT8 data2 = readbyte(ra++); + + for (int x = 0; x < m_hp; x++) + { + if(y >= 0 && y < bitmap.height()) + { + if(((sx * m_hp) + x) >= 0 && ((sx * m_hp) + x) < bitmap.width()) + bitmap.pix16(y, (sx * m_hp) + x) = BIT(data1, x); + if(((sx * m_hp) + x + m_hp) >= 0 && ((sx * m_hp) + x + m_hp) < bitmap.width()) + bitmap.pix16(y, (sx * m_hp) + x + m_hp) = BIT(data2, x); + } + } + } + return ra; +} + + +//------------------------------------------------- +// update_graphics - draw graphics mode screen +//------------------------------------------------- + +void hd61830_device::update_graphics(bitmap_ind16 &bitmap, const rectangle &cliprect) +{ + UINT16 rac1 = m_dsa; + UINT16 rac2 = rac1 + (m_nx * m_hn); + for (int y = 0; y < m_nx; y++) + { + /* draw upper half scanline */ + rac1 = draw_scanline(bitmap, cliprect, y, rac1); + + /* draw lower half scanline */ + rac2 = draw_scanline(bitmap, cliprect, y + m_nx, rac2); + } +} + + +//------------------------------------------------- +// draw_char - draw a char +//------------------------------------------------- + +void hd61830_device::draw_char(bitmap_ind16 &bitmap, const rectangle &cliprect, UINT16 ma, int x, int y, UINT8 md) +{ + for (int cl = 0; cl < m_vp; cl++) + { + for (int cr = 0; cr < m_hp; cr++) + { + int sy = y * m_vp + cl; + int sx = x * m_hp + cr; + UINT8 data = 0; + + if (m_mcr & MODE_EXTERNAL_CG) + { + data = m_read_rd((cl << 12) | md); + } + else + { + UINT16 addr = 0; + + if (md >= 0x20 && md < 0x80 && cl < 7) + { + // 5x7 characters 0x20..0x7f + addr = (md - 0x20) * 7 + cl; + } + else if (md >= 0xa0 && md < 0xe0 && cl < 7) + { + // 5x7 characters 0xa0..0xdf + addr = 96*7 + (md - 0xa0) * 7 + cl; + } + else if (md >= 0xe0 && cl < 11) + { + // 5x11 characters 0xe0..0xff + addr = 160*7 + (md - 0xe0) * 11 + cl; + } + + data = m_char_rom[addr]; + } + + int cursor = m_mcr & MODE_CURSOR; + int blink = m_mcr & MODE_BLINK; + + // cursor off + int pixel = BIT(data, cr); + + if (blink && (ma == m_cac)) + { + // cursor off, character blink + if (!cursor) + pixel = m_cursor ? pixel : 0; + + // cursor blink + if (cursor && (cl == m_cp)) + pixel = m_cursor ? 1 : 0; + } + else + { + // cursor on + if (cursor && (cl == m_cp)) + pixel = m_cursor ? 1 : 0; + } + + if (sy < m_screen->height() && sx < m_screen->width()) + bitmap.pix16(sy, sx) = pixel; + } + } +} + + +//------------------------------------------------- +// update_text - draw text mode screen +//------------------------------------------------- + +void hd61830_device::update_text(bitmap_ind16 &bitmap, const rectangle &cliprect) +{ + UINT16 ma = 0; + for (int y = 0; y < (m_nx / m_vp); y++) + { + for (int x = 0; x < m_hn; x+=2) + { + UINT8 md1 = readbyte(ma); + UINT8 md2 = readbyte(ma+1); + + draw_char(bitmap, cliprect, ma, x, y, md1); + draw_char(bitmap, cliprect, ma+1, x+1, y, md2); + + ma+=2; + } + } +} + + +//------------------------------------------------- +// update_screen - update screen +//------------------------------------------------- + +UINT32 hd61830_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) +{ + if (m_mcr & MODE_DISPLAY_ON) + { + if (m_mcr & MODE_GRAPHIC) + { + update_graphics(bitmap, cliprect); + } + else + { + update_text(bitmap, cliprect); + } + } + else + { + bitmap.fill(0, cliprect); + } + + m_blink++; + + if (m_blink == 0x20) + { + m_blink = 0; + m_cursor = !m_cursor; + } + return 0; +} diff --git a/src/devices/video/hd61830.h b/src/devices/video/hd61830.h new file mode 100644 index 00000000000..359f2d78b1a --- /dev/null +++ b/src/devices/video/hd61830.h @@ -0,0 +1,125 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Hitachi HD61830 LCD Timing Controller emulation + +**********************************************************************/ + +#pragma once + +#ifndef __HD61830__ +#define __HD61830__ + +#include "emu.h" + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_HD61830_RD_CALLBACK(_read) \ + devcb = &hd61830_device::set_rd_rd_callback(*device, DEVCB_##_read); + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> hd61830_device + +class hd61830_device : public device_t, + public device_memory_interface, + public device_video_interface +{ +public: + // construction/destruction + hd61830_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + template static devcb_base &set_rd_rd_callback(device_t &device, _Object object) { return downcast(device).m_read_rd.set_callback(object); } + + DECLARE_READ8_MEMBER( status_r ); + DECLARE_WRITE8_MEMBER( control_w ); + + DECLARE_READ8_MEMBER( data_r ); + DECLARE_WRITE8_MEMBER( data_w ); + + UINT32 screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); + +protected: + // device-level overrides + virtual const rom_entry *device_rom_region() const; + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const; + + inline UINT8 readbyte(offs_t address); + inline void writebyte(offs_t address, UINT8 data); + +private: + enum + { + INSTRUCTION_MODE_CONTROL = 0, + INSTRUCTION_CHARACTER_PITCH, + INSTRUCTION_NUMBER_OF_CHARACTERS, + INSTRUCTION_NUMBER_OF_TIME_DIVISIONS, + INSTRUCTION_CURSOR_POSITION, + INSTRUCTION_DISPLAY_START_LOW = 8, + INSTRUCTION_DISPLAY_START_HIGH, + INSTRUCTION_CURSOR_ADDRESS_LOW, + INSTRUCTION_CURSOR_ADDRESS_HIGH, + INSTRUCTION_DISPLAY_DATA_WRITE, + INSTRUCTION_DISPLAY_DATA_READ, + INSTRUCTION_CLEAR_BIT, + INSTRUCTION_SET_BIT + }; + + void set_busy_flag(); + + UINT16 draw_scanline(bitmap_ind16 &bitmap, const rectangle &cliprect, int y, UINT16 ra); + void update_graphics(bitmap_ind16 &bitmap, const rectangle &cliprect); + void draw_char(bitmap_ind16 &bitmap, const rectangle &cliprect, UINT16 ma, int x, int y, UINT8 md); + void update_text(bitmap_ind16 &bitmap, const rectangle &cliprect); + + devcb_read8 m_read_rd; + + emu_timer *m_busy_timer; + //address_space *m_data; + + bool m_bf; // busy flag + + UINT8 m_ir; // instruction register + UINT8 m_mcr; // mode control register + UINT8 m_dor; // data output register + + UINT16 m_dsa; // display start address + UINT16 m_cac; // cursor address counter + + int m_vp; // vertical character pitch + int m_hp; // horizontal character pitch + int m_hn; // horizontal number of characters + int m_nx; // number of time divisions + int m_cp; // cursor position + + int m_blink; // blink counter + int m_cursor; // cursor visible + + // address space configurations + const address_space_config m_space_config; + + required_region_ptr m_char_rom; +}; + + +// device type definition +extern const device_type HD61830; +extern const device_type HD61830B; + + + +#endif diff --git a/src/devices/video/hd63484.c b/src/devices/video/hd63484.c new file mode 100644 index 00000000000..cdfddbcb23d --- /dev/null +++ b/src/devices/video/hd63484.c @@ -0,0 +1,1578 @@ +// license:BSD-3-Clause +// copyright-holders:Roberto Zandona' +/*************************************************************************** + + HD63484 ACRTC + Advanced CRT Controller. + + This chip is used in: + - shanghai.c + - adp.c + - sigmab52.c + - wildpkr.c + + ACRTC memory map: + + 00000-3ffff = RAM + 40000-7ffff = ROM handled with a hack in the drivers + 80000-bffff = unused + c0000-fffff = unused + +***************************************************************************/ + +#include "emu.h" +#include "video/hd63484.h" + +#define LOG_COMMANDS 0 + +const device_type HD63484 = &device_creator; + +hd63484_device::hd63484_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, HD63484, "HD63484 CRTC", tag, owner, clock, "hd63484", __FILE__), + m_ram(NULL), + m_fifo_counter(0), + m_readfifo(0), + m_org(0), + m_org_dpd(0), + m_rwp(0), + m_cl0(0), + m_cl1(0), + m_ccmp(0), + m_edg(0), + m_mask(0), + m_ppy(0), + m_pzcy(0), + m_ppx(0), + m_pzcx(0), + m_psy(0), + m_psx(0), + m_pey(0), + m_pzy(0), + m_pex(0), + m_pzx(0), + m_xmin(0), + m_ymin(0), + m_xmax(0), + m_ymax(0), + m_rwp_dn(0), + m_cpx(0), + m_cpy(0), + m_regno(0), + m_skattva_hack(0) +{ + memset(m_reg, 0x00, sizeof(m_reg)); + //m_pattern[16], +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void hd63484_device::device_start() +{ + m_ram = auto_alloc_array_clear(machine(), UINT16, HD63484_RAM_SIZE); + + save_pointer(NAME(m_ram), HD63484_RAM_SIZE); + save_item(NAME(m_reg)); + save_item(NAME(m_fifo_counter)); + save_item(NAME(m_fifo)); + save_item(NAME(m_readfifo)); + save_item(NAME(m_pattern)); + save_item(NAME(m_org)); + save_item(NAME(m_org_dpd)); + save_item(NAME(m_rwp)); + save_item(NAME(m_cl0)); + save_item(NAME(m_cl1)); + save_item(NAME(m_ccmp)); + save_item(NAME(m_edg)); + save_item(NAME(m_mask)); + save_item(NAME(m_ppy)); + save_item(NAME(m_pzcy)); + save_item(NAME(m_ppx)); + save_item(NAME(m_pzcx)); + save_item(NAME(m_psy)); + save_item(NAME(m_psx)); + save_item(NAME(m_pey)); + save_item(NAME(m_pzy)); + save_item(NAME(m_pex)); + save_item(NAME(m_pzx)); + save_item(NAME(m_xmin)); + save_item(NAME(m_ymin)); + save_item(NAME(m_xmax)); + save_item(NAME(m_ymax)); + save_item(NAME(m_rwp_dn)); + save_item(NAME(m_cpx)); + save_item(NAME(m_cpy)); + save_item(NAME(m_regno)); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void hd63484_device::device_reset() +{ + m_fifo_counter = 0; +} + +/***************************************************************************** + IMPLEMENTATION +*****************************************************************************/ + +static const int instruction_length[64] = +{ + 0, 3, 2, 1, /* 0x */ + 0, 0,-1, 2, /* 1x */ + 0, 3, 3, 3, /* 2x */ + 0, 0, 0, 0, /* 3x */ + 0, 1, 2, 2, /* 4x */ + 0, 0, 4, 4, /* 5x */ + 5, 5, 5, 5, /* 6x */ + 5, 5, 5, 5, /* 7x */ + 3, 3, 3, 3, /* 8x */ + 3, 3,-2,-2, /* 9x */ + -2,-2, 2, 4, /* Ax */ + 5, 5, 7, 7, /* Bx */ + 3, 3, 1, 1, /* Cx */ + 2, 2, 2, 2, /* Dx */ + 5, 5, 5, 5, /* Ex */ + 5, 5, 5, 5 /* Fx */ +}; + +static const char *const instruction_name[64] = +{ + "undef","ORG ","WPR ","RPR ", /* 0x */ + "undef","undef","WPTN ","RPTN ", /* 1x */ + "undef","DRD ","DWT ","DMOD ", /* 2x */ + "undef","undef","undef","undef", /* 3x */ + "undef","RD ","WT ","MOD ", /* 4x */ + "undef","undef","CLR ","SCLR ", /* 5x */ + "CPY ","CPY ","CPY ","CPY ", /* 6x */ + "SCPY ","SCPY ","SCPY ","SCPY ", /* 7x */ + "AMOVE","RMOVE","ALINE","RLINE", /* 8x */ + "ARCT ","RRCT ","APLL ","RPLL ", /* 9x */ + "APLG ","RPLG ","CRCL ","ELPS ", /* Ax */ + "AARC ","RARC ","AEARC","REARC", /* Bx */ + "AFRCT","RFRCT","PAINT","DOT ", /* Cx */ + "PTN ","PTN ","PTN ","PTN ", /* Dx */ + "AGCPY","AGCPY","AGCPY","AGCPY", /* Ex */ + "RGCPY","RGCPY","RGCPY","RGCPY" /* Fx */ +}; + +void hd63484_device::doclr16( int opcode, UINT16 fill, int *dst, INT16 _ax, INT16 _ay ) +{ + INT16 ax,ay; + + ax = _ax; + ay = _ay; + + for (;;) + { + for (;;) + { + switch (opcode & 0x0003) + { + case 0: + m_ram[*dst] = fill; + break; + case 1: + m_ram[*dst] |= fill; + break; + case 2: + m_ram[*dst] &= fill; + break; + case 3: + m_ram[*dst] ^= fill; + break; + } + if (ax == 0) + break; + else if (ax > 0) + { + *dst = (*dst + 1) & (HD63484_RAM_SIZE - 1); + ax--; + } + else + { + *dst = (*dst - 1) & (HD63484_RAM_SIZE - 1); + ax++; + } + } + + ax = _ax; + if (_ay < 0) + { + *dst = (*dst + (m_reg[0xca/2] & 0x0fff) - ax) & (HD63484_RAM_SIZE - 1); + if (ay == 0) + break; + ay++; + } + else + { + *dst = (*dst - (m_reg[0xca/2] & 0x0fff) - ax) & (HD63484_RAM_SIZE - 1); + if (ay == 0) + break; + ay--; + } + } +} + +void hd63484_device::docpy16( int opcode, int src, int *dst, INT16 _ax, INT16 _ay ) +{ + int dstep1,dstep2; + int ax = _ax; + int ay = _ay; + + switch (opcode & 0x0700) + { + default: + case 0x0000: dstep1 = 1; dstep2 = -1 * (m_reg[0xca/2] & 0x0fff) - ax * dstep1; break; + case 0x0100: dstep1 = 1; dstep2 = (m_reg[0xca/2] & 0x0fff) - ax * dstep1; break; + case 0x0200: dstep1 = -1; dstep2 = -1 * (m_reg[0xca/2] & 0x0fff) + ax * dstep1; break; + case 0x0300: dstep1 = -1; dstep2 = (m_reg[0xca/2] & 0x0fff) + ax * dstep1; break; + case 0x0400: dstep1 = -1 * (m_reg[0xca/2] & 0x0fff); dstep2 = 1 - ay * dstep1; break; + case 0x0500: dstep1 = (m_reg[0xca/2] & 0x0fff); dstep2 = 1 - ay * dstep1; break; + case 0x0600: dstep1 = -1 * (m_reg[0xca/2] & 0x0fff); dstep2 = -1 + ay * dstep1; break; + case 0x0700: dstep1 = (m_reg[0xca/2] & 0x0fff); dstep2 = -1 + ay * dstep1; break; + } + + for (;;) + { + for (;;) + { + switch (opcode & 0x0007) + { + case 0: + m_ram[*dst] = m_ram[src]; + break; + case 1: + m_ram[*dst] |= m_ram[src]; + break; + case 2: + m_ram[*dst] &= m_ram[src]; + break; + case 3: + m_ram[*dst] ^= m_ram[src]; + break; + case 4: + if (m_ram[*dst] == (m_ccmp & 0xff)) + m_ram[*dst] = m_ram[src]; + break; + case 5: + if (m_ram[*dst] != (m_ccmp & 0xff)) + m_ram[*dst] = m_ram[src]; + break; + case 6: + if (m_ram[*dst] < m_ram[src]) + m_ram[*dst] = m_ram[src]; + break; + case 7: + if (m_ram[*dst] > m_ram[src]) + m_ram[*dst] = m_ram[src]; + break; + } + + if (opcode & 0x0800) + { + if (ay == 0) break; + if (_ay > 0) + { + src = (src - (m_reg[0xca/2] & 0x0fff)) & (HD63484_RAM_SIZE - 1); + *dst = (*dst + dstep1) & (HD63484_RAM_SIZE - 1); + ay--; + } + else + { + src = (src + (m_reg[0xca/2] & 0x0fff)) & (HD63484_RAM_SIZE - 1); + *dst = (*dst + dstep1) & (HD63484_RAM_SIZE - 1); + ay++; + } + } + else + { + if (ax == 0) break; + else if (ax > 0) + { + src = (src + 1) & (HD63484_RAM_SIZE - 1); + *dst = (*dst + dstep1) & (HD63484_RAM_SIZE - 1); + ax--; + } + else + { + src = (src - 1) & (HD63484_RAM_SIZE - 1); + *dst = (*dst + dstep1) & (HD63484_RAM_SIZE - 1); + ax++; + } + } + } + + if (opcode & 0x0800) + { + ay = _ay; + if (_ax < 0) + { + src = (src - 1 + ay * (m_reg[0xca/2] & 0x0fff)) & (HD63484_RAM_SIZE - 1); + *dst = (*dst + dstep2) & (HD63484_RAM_SIZE - 1); + if (ax == 0) break; + ax++; + } + else + { + src = (src + 1 - ay * (m_reg[0xca/2] & 0x0fff)) & (HD63484_RAM_SIZE - 1); + *dst = (*dst + dstep2) & (HD63484_RAM_SIZE - 1); + if (ax == 0) break; + ax--; + } + } + else + { + ax = _ax; + if (_ay < 0) + { + src = (src + (m_reg[0xca/2] & 0x0fff) - ax) & (HD63484_RAM_SIZE - 1); + *dst = (*dst + dstep2) & (HD63484_RAM_SIZE - 1); + if (ay == 0) break; + ay++; + } + else + { + src = (src - (m_reg[0xca/2] & 0x0fff) - ax) & (HD63484_RAM_SIZE - 1); + *dst = (*dst + dstep2) & (HD63484_RAM_SIZE - 1); + if (ay == 0) break; + ay--; + } + } + } +} + +int hd63484_device::org_first_pixel( int _org_dpd ) +{ + int gbm = (m_reg[0x02/2] & 0x700) >> 8; + + switch (gbm) + { + case 0: + return (_org_dpd & 0x0f); + case 1: + return (_org_dpd & 0x0e) >> 1; + case 2: + return (_org_dpd & 0x0c) >> 2; + case 3: + return (_org_dpd & 0x08) >> 3; + case 4: + return 0; + + default: + logerror ("Graphic bit mode not supported\n"); + return 0; + } +} + +void hd63484_device::dot( int x, int y, int opm, UINT16 color ) +{ + int dst, x_int, x_mod, bpp; + UINT16 color_shifted, bitmask, bitmask_shifted; + + x += org_first_pixel(m_org_dpd); + + switch ((m_reg[0x02/2] & 0x700) >> 8) + { + case 0: + bpp = 1; + bitmask = 0x0001; + break; + case 1: + bpp = 2; + bitmask = 0x0003; + break; + case 2: + bpp = 4; + bitmask = 0x000f; + break; + case 3: + bpp = 8; + bitmask = 0x00ff; + break; + case 4: + bpp = 16; + bitmask = 0xffff; + break; + + default: + bpp = 0; + bitmask = 0x0000; + logerror ("Graphic bit mode not supported\n"); + } + + // bpp = 4; // for skattva + // bitmask = 0x000f; // for skattva + + if (x >= 0) + { + x_int = x / (16 / bpp); + x_mod = x % (16 / bpp); + } + else + { + x_int = x / (16 / bpp); + x_mod = -1 * (x % (16 / bpp)); + if (x_mod) { + x_int--; + x_mod = (16 / bpp) - x_mod; + } + } + + color &= bitmask; + + bitmask_shifted = bitmask << (x_mod * bpp); + color_shifted = color << (x_mod * bpp); + + dst = (m_org + x_int - y * (m_reg[0xca/2] & 0x0fff)) & (HD63484_RAM_SIZE - 1); + + switch (opm) + { + case 0: + m_ram[dst] = (m_ram[dst] & ~bitmask_shifted) | color_shifted; + break; + case 1: + m_ram[dst] = m_ram[dst] | color_shifted; + break; + case 2: + m_ram[dst] = m_ram[dst] & ((m_ram[dst] & ~bitmask_shifted) | color_shifted); + break; + case 3: + m_ram[dst] = m_ram[dst] ^ color_shifted; + break; + case 4: + if (get_pixel(x, y) == (m_ccmp & bitmask)) + m_ram[dst] = (m_ram[dst] & ~bitmask_shifted) | color_shifted; + break; + case 5: + if (get_pixel(x, y) != (m_ccmp & bitmask)) + m_ram[dst] = (m_ram[dst] & ~bitmask_shifted) | color_shifted; + break; + case 6: + if (get_pixel(x, y) < (m_cl0 & bitmask)) + m_ram[dst] = (m_ram[dst] & ~bitmask_shifted) | color_shifted; + break; + case 7: + if (get_pixel(x, y) > (m_cl0 & bitmask)) + m_ram[dst] = (m_ram[dst] & ~bitmask_shifted) | color_shifted; + break; + } +} + +int hd63484_device::get_pixel( int x, int y ) +{ + int dst, x_int, x_mod, bpp; + UINT16 bitmask, bitmask_shifted; + + switch ((m_reg[0x02/2] & 0x700) >> 8) + { + case 0: + bpp = 1; + bitmask = 0x0001; + break; + case 1: + bpp = 2; + bitmask = 0x0003; + break; + case 2: + bpp = 4; + bitmask = 0x000f; + break; + case 3: + bpp = 8; + bitmask = 0x00ff; + break; + case 4: + bpp = 16; + bitmask = 0xffff; + break; + + default: + bpp = 0; + bitmask = 0x0000; + logerror ("Graphic bit mode not supported\n"); + } + if (x >= 0) + { + x_int = x / (16 / bpp); + x_mod = x % (16 / bpp); + } + else + { + x_int = x / (16 / bpp); + x_mod = -1 * (x % (16 / bpp)); + if (x_mod) { + x_int--; + x_mod = (16 / bpp) - x_mod; + } + } + + bitmask_shifted = bitmask << (x_mod * bpp); + + dst = (m_org + x_int - y * (m_reg[0xca/2] & 0x0fff)) & (HD63484_RAM_SIZE - 1); + + return ((m_ram[dst] & bitmask_shifted) >> (x_mod * bpp)); +} + +int hd63484_device::get_pixel_ptn( int x, int y ) +{ + int dst, x_int, x_mod, bpp; + UINT16 bitmask, bitmask_shifted; + + bpp = 1; + bitmask = 0x0001; + + if (x >= 0) + { + x_int = x / (16 / bpp); + x_mod = x % (16 / bpp); + } + else + { + x_int = x / (16 / bpp); + x_mod = -1 * (x % (16 / bpp)); + if (x_mod) { + x_int--; + x_mod = (16 / bpp) - x_mod; + } + } + + bitmask_shifted = bitmask << (x_mod * bpp); + + dst = (x_int + y * 1); + + if ((m_pattern[dst] & bitmask_shifted) >> (x_mod * bpp)) + return 1; + else + return 0; +} + +void hd63484_device::agcpy( int opcode, int src_x, int src_y, int dst_x, int dst_y, INT16 _ax, INT16 _ay ) +{ + int dst_step1_x,dst_step1_y,dst_step2_x,dst_step2_y; + int src_step1_x,src_step1_y,src_step2_x,src_step2_y; + int ax_neg,ay_neg; + int ax = _ax; + int ay = _ay; + int xxs = src_x; + int yys = src_y; + int xxd = dst_x; + int yyd = dst_y; + + if (ax < 0) + ax_neg = -1; + else + ax_neg = 1; + if (ay < 0) + ay_neg = -1; + else + ay_neg = 1; + + if (opcode & 0x0800) + switch (opcode & 0x0700) + { + default: + case 0x0000: dst_step1_x = 1; dst_step1_y = 0; dst_step2_x = -ay_neg*ay; dst_step2_y = 1; break; + case 0x0100: dst_step1_x = 1; dst_step1_y = 0; dst_step2_x = -ay_neg*ay; dst_step2_y = -1; break; + case 0x0200: dst_step1_x = -1; dst_step1_y = 0; dst_step2_x = ay_neg*ay; dst_step2_y = 1; break; + case 0x0300: dst_step1_x = -1; dst_step1_y = 0; dst_step2_x = ay_neg*ay; dst_step2_y = -1; break; + case 0x0400: dst_step1_x = 0; dst_step1_y = 1; dst_step2_x = 1; dst_step2_y = -ay_neg*ay; break; + case 0x0500: dst_step1_x = 0; dst_step1_y = -1; dst_step2_x = 1; dst_step2_y = ay_neg*ay; break; + case 0x0600: dst_step1_x = 0; dst_step1_y = 1; dst_step2_x = -1; dst_step2_y = -ay_neg*ay; break; + case 0x0700: dst_step1_x = 0; dst_step1_y = -1; dst_step2_x = -1; dst_step2_y = ay_neg*ay; break; + } + else + switch (opcode & 0x0700) + { + default: + case 0x0000: dst_step1_x = 1; dst_step1_y = 0; dst_step2_x = -ax_neg*ax; dst_step2_y = 1; break; + case 0x0100: dst_step1_x = 1; dst_step1_y = 0; dst_step2_x = -ax_neg*ax; dst_step2_y = -1; break; + case 0x0200: dst_step1_x = -1; dst_step1_y = 0; dst_step2_x = ax_neg*ax; dst_step2_y = 1; break; + case 0x0300: dst_step1_x = -1; dst_step1_y = 0; dst_step2_x = ax_neg*ax; dst_step2_y = -1; break; + case 0x0400: dst_step1_x = 0; dst_step1_y = 1; dst_step2_x = 1; dst_step2_y = ax_neg*ax; break; + case 0x0500: dst_step1_x = 0; dst_step1_y = -1; dst_step2_x = 1; dst_step2_y = -ax_neg*ax; break; + case 0x0600: dst_step1_x = 0; dst_step1_y = 1; dst_step2_x = -1; dst_step2_y = ax_neg*ax; break; + case 0x0700: dst_step1_x = 0; dst_step1_y = -1; dst_step2_x = -1; dst_step2_y = -ax_neg*ax; break; + } + + if ((_ax >= 0) && (_ay >= 0) && ((opcode & 0x0800) == 0x0000)) + { src_step1_x = 1; src_step1_y = 0; src_step2_x = -ax; src_step2_y = 1; } + else if ((_ax >= 0) && (_ay < 0) && ((opcode & 0x0800) == 0x0000)) + { src_step1_x = 1; src_step1_y = 0; src_step2_x = -ax; src_step2_y = -1; } + else if ((_ax < 0) && (_ay >= 0) && ((opcode & 0x0800) == 0x0000)) + { src_step1_x = -1; src_step1_y = 0; src_step2_x = -ax; src_step2_y = 1; } + else if ((_ax < 0) && (_ay < 0) && ((opcode & 0x0800) == 0x0000)) + { src_step1_x = -1; src_step1_y = 0; src_step2_x = -ax; src_step2_y = -1; } + else if ((_ax >= 0) && (_ay >= 0) && ((opcode & 0x0800) == 0x0800)) + { src_step1_x = 0; src_step1_y = 1; src_step2_x = 1; src_step2_y = -ay; } + else if ((_ax >= 0) && (_ay < 0) && ((opcode & 0x0800) == 0x0800)) + { src_step1_x = 0; src_step1_y = -1; src_step2_x = 1; src_step2_y = -ay; } + else if ((_ax < 0) && (_ay >= 0) && ((opcode & 0x0800) == 0x0800)) + { src_step1_x = 0; src_step1_y = 1; src_step2_x = -1; src_step2_y = -ay; } + else // ((_ax < 0) && (_ay < 0) && ((opcode & 0x0800) == 0x0800)) + { src_step1_x = 0; src_step1_y = -1; src_step2_x = -1; src_step2_y = -ay; } + + for (;;) + { + for (;;) + { + dot(xxd, yyd, opcode & 0x0007, get_pixel(xxs, yys)); + + if (opcode & 0x0800) + { + if (ay == 0) break; + if (_ay > 0) + { + xxs += src_step1_x; + yys += src_step1_y; + xxd += dst_step1_x; + yyd += dst_step1_y; + ay--; + } + else + { + xxs += src_step1_x; + yys += src_step1_y; + xxd += dst_step1_x; + yyd += dst_step1_y; + ay++; + } + } + else + { + if (ax == 0) break; + else if (ax > 0) + { + xxs += src_step1_x; + yys += src_step1_y; + xxd += dst_step1_x; + yyd += dst_step1_y; + ax--; + } + else + { + xxs += src_step1_x; + yys += src_step1_y; + xxd += dst_step1_x; + yyd += dst_step1_y; + ax++; + } + } + } + + if (opcode & 0x0800) + { + ay = _ay; + if (_ax < 0) + { + xxs += src_step2_x; + yys += src_step2_y; + xxd += dst_step2_x; + yyd += dst_step2_y; + if (ax == 0) break; + ax++; + } + else + { + xxs += src_step2_x; + yys += src_step2_y; + xxd += dst_step2_x; + yyd += dst_step2_y; + if (ax == 0) break; + ax--; + } + } + else + { + ax = _ax; + if (_ay < 0) + { + xxs += src_step2_x; + yys += src_step2_y; + xxd += dst_step2_x; + yyd += dst_step2_y; + if (ay == 0) break; + ay++; + } + else + { + xxs += src_step2_x; + yys += src_step2_y; + xxd += dst_step2_x; + yyd += dst_step2_y; + if (ay == 0) break; + ay--; + } + } + } +} + +void hd63484_device::ptn( int opcode, int src_x, int src_y, INT16 _ax, INT16 _ay ) +{ + int dst_step1_x = 0,dst_step1_y = 0,dst_step2_x = 0,dst_step2_y = 0; + int src_step1_x,src_step1_y,src_step2_x,src_step2_y; + int ax = _ax; + int ay = _ay; + int ax_neg; //,ay_neg; + int xxs = src_x; + int yys = src_y; + int xxd = m_cpx; + int yyd = m_cpy; + int getpixel; + + if (ax < 0) + ax_neg = -1; + else + ax_neg = 1; +/* if (ay < 0) + ay_neg = -1; + else + ay_neg = 1;*/ + + if (opcode & 0x0800) + switch (opcode & 0x0700) + { + default: + case 0x0000: logerror("PTN: not supported"); break; + case 0x0100: logerror("PTN: not supported"); break; + case 0x0200: logerror("PTN: not supported"); break; + case 0x0300: logerror("PTN: not supported"); break; + case 0x0400: logerror("PTN: not supported"); break; + case 0x0500: logerror("PTN: not supported"); break; + case 0x0600: logerror("PTN: not supported"); break; + case 0x0700: logerror("PTN: not supported"); break; + } + else + switch (opcode & 0x0700) + { + default: + case 0x0000: dst_step1_x = 1; dst_step1_y = 0; dst_step2_x = -ax_neg*ax; dst_step2_y = 1; break; + case 0x0100: logerror("PTN: not supported"); break; + case 0x0200: dst_step1_x = 0; dst_step1_y = 1; dst_step2_x = -1; dst_step2_y = -ax_neg*ax; break; + case 0x0300: logerror("PTN: not supported"); break; + case 0x0400: dst_step1_x = -1; dst_step1_y = 0; dst_step2_x = ax_neg*ax; dst_step2_y = -1; break; + case 0x0500: logerror("PTN: not supported"); break; + case 0x0600: dst_step1_x = 0; dst_step1_y = -1; dst_step2_x = 1; dst_step2_y = ax_neg*ax; break; + case 0x0700: logerror("PTN: not supported"); break; + } + + src_step1_x = 1; src_step1_y = 0; src_step2_x = -ax; src_step2_y = 1; + + for (;;) + { + for (;;) + { + getpixel = get_pixel_ptn(xxs, yys); + switch ((opcode & 0x0018) >> 3) + { + case 0x0000: + if (getpixel) + dot(xxd, yyd, opcode & 0x0007, m_cl1); + else + dot(xxd, yyd, opcode & 0x0007, m_cl0); + break; + case 0x0001: + if (getpixel) + dot(xxd, yyd, opcode & 0x0007, m_cl1); + break; + case 0x0002: + if (getpixel == 0) + dot(xxd, yyd, opcode & 0x0007, m_cl0); + break; + case 0x0003: + logerror("PTN: not supported"); + break; + } + + if (opcode & 0x0800) + { + if (ay == 0) break; + if (_ay > 0) + { + xxs += src_step1_x; + yys += src_step1_y; + xxd += dst_step1_x; + yyd += dst_step1_y; + ay--; + } + else + { + xxs += src_step1_x; + yys += src_step1_y; + xxd += dst_step1_x; + yyd += dst_step1_y; + ay++; + } + } + else + { + if (ax == 0) break; + else if (ax > 0) + { + xxs += src_step1_x; + yys += src_step1_y; + xxd += dst_step1_x; + yyd += dst_step1_y; + ax--; + } + else + { + xxs += src_step1_x; + yys += src_step1_y; + xxd += dst_step1_x; + yyd += dst_step1_y; + ax++; + } + } + } + + if (opcode & 0x0800) + { + ay = _ay; + if (_ax < 0) + { + xxs += src_step2_x; + yys += src_step2_y; + xxd += dst_step2_x; + yyd += dst_step2_y; + if (ax == 0) break; + ax++; + } + else + { + xxs += src_step2_x; + yys += src_step2_y; + xxd += dst_step2_x; + yyd += dst_step2_y; + if (ax == 0) break; + ax--; + } + } + else + { + ax = _ax; + if (_ay < 0) + { + xxs += src_step2_x; + yys += src_step2_y; + xxd += dst_step2_x; + yyd += dst_step2_y; + if (ay == 0) break; + ay++; + } + else + { + xxs += src_step2_x; + yys += src_step2_y; + xxd += dst_step2_x; + yyd += dst_step2_y; + if (ay == 0) break; + ay--; + } + } + } +} + +void hd63484_device::line( INT16 sx, INT16 sy, INT16 ex, INT16 ey, INT16 col ) +{ + INT16 ax,ay; + + int cpx_t = sx; + int cpy_t = sy; + + ax = ex - sx; + ay = ey - sy; + + if (abs(ax) >= abs(ay)) + { + while (ax) + { + dot(cpx_t, cpy_t, col & 7, m_cl0); + + if (ax > 0) + { + cpx_t++; + ax--; + } + else + { + cpx_t--; + ax++; + } + cpy_t = sy + ay * (cpx_t - sx) / (ex - sx); + } + } + else + { + while (ay) + { + dot(cpx_t, cpy_t, col & 7, m_cl0); + + if (ay > 0) + { + cpy_t++; + ay--; + } + else + { + cpy_t--; + ay++; + } + cpx_t = sx + ax * (cpy_t - sy) / (ey - sy); + } + } + +} + +void hd63484_device::circle( INT16 sx, INT16 sy, UINT16 r, INT16 col ) +{ + const float DEG2RAD = 3.14159f/180; + int i; + + for (i = 0; i < 360 * (r / 10); i++) + { + float degInRad = i * DEG2RAD / (r / 10); + dot(sx + cos(degInRad) * r,sy + sin(degInRad) * r, col & 7, m_cl0); + } +} + +void hd63484_device::paint( int sx, int sy, int col ) +{ + int getpixel; + dot(sx, sy, 0, col); + + getpixel = get_pixel(sx+1,sy); + switch ((m_reg[0x02/2] & 0x700) >> 8) + { + case 0: + break; + case 1: + break; + case 2: + getpixel = (getpixel << 12) | (getpixel << 8) | (getpixel << 4) | (getpixel << 0); + break; + case 3: + getpixel = (getpixel << 8) | (getpixel << 0); + break; + case 4: + break; + + default: + logerror ("Graphic bit mode not supported\n"); + } + if ((getpixel != col) && (getpixel != m_edg)) + { + sx++; + paint(sx, sy, col); + sx--; + } + + getpixel = get_pixel(sx - 1, sy); + switch ((m_reg[0x02/2] & 0x700) >> 8) + { + case 0: + break; + case 1: + break; + case 2: + getpixel = (getpixel << 12) | (getpixel << 8) | (getpixel << 4) | (getpixel << 0); + break; + case 3: + getpixel = (getpixel << 8) | (getpixel << 0); + break; + case 4: + break; + + default: + logerror ("Graphic bit mode not supported\n"); + } + if ((getpixel != col) && (getpixel != m_edg)) + { + sx--; + paint(sx, sy, col); + sx++; + } + + getpixel = get_pixel(sx, sy + 1); + switch ((m_reg[0x02/2] & 0x700) >> 8) + { + case 0: + break; + case 1: + break; + case 2: + getpixel = (getpixel << 12) | (getpixel << 8) | (getpixel << 4) | (getpixel << 0); + break; + case 3: + getpixel = (getpixel << 8) | (getpixel << 0); + break; + case 4: + break; + + default: + logerror ("Graphic bit mode not supported\n"); + } + if ((getpixel != col) && (getpixel != m_edg)) + { + sy++; + paint(sx, sy, col); + sy--; + } + + getpixel = get_pixel(sx, sy - 1); + switch ((m_reg[0x02/2] & 0x700) >> 8) + { + case 0: + break; + case 1: + break; + case 2: + getpixel = (getpixel << 12) | (getpixel << 8) | (getpixel << 4) | (getpixel << 0); + break; + case 3: + getpixel = (getpixel << 8) | (getpixel << 0); + break; + case 4: + break; + + default: + logerror ("Graphic bit mode not supported\n"); + } + if ((getpixel != col) && (getpixel != m_edg)) + { + sy--; + paint(sx, sy, col); + sy++; + } +} + +void hd63484_device::command_w(UINT16 cmd) +{ + int len; + + m_fifo[m_fifo_counter++] = cmd; + + len = instruction_length[m_fifo[0] >> 10]; + if (len == -1) + { + if (m_fifo_counter < 2) return; + else len = m_fifo[1] + 2; + } + else if (len == -2) + { + if (m_fifo_counter < 2) return; + else len = 2 * m_fifo[1] + 2; + } + + if (m_fifo_counter >= len) + { +#if LOG_COMMANDS + int i; + + logerror("%s: HD63484 command %s (%04x) ", machine().describe_context(), instruction_name[m_fifo[0] >> 10], m_fifo[0]); + for (i = 1; i < m_fifo_counter; i++) + logerror("%04x ", m_fifo[i]); + logerror("\n"); +#endif + + if (m_fifo[0] == 0x0400) { /* ORG */ + m_org = ((m_fifo[1] & 0x00ff) << 12) | ((m_fifo[2] & 0xfff0) >> 4); + m_org_dpd = m_fifo[2] & 0x000f; + } + else if ((m_fifo[0] & 0xffe0) == 0x0800) /* WPR */ + { + if (m_fifo[0] == 0x0800) + m_cl0 = m_fifo[1]; + else if (m_fifo[0] == 0x0801) + m_cl1 = m_fifo[1]; + else if (m_fifo[0] == 0x0802) + m_ccmp = m_fifo[1]; + else if (m_fifo[0] == 0x0803) + m_edg = m_fifo[1]; + else if (m_fifo[0] == 0x0804) + m_mask = m_fifo[1]; + else if (m_fifo[0] == 0x0805) + { + m_ppy = (m_fifo[1] & 0xf000) >> 12; + m_pzcy = (m_fifo[1] & 0x0f00) >> 8; + m_ppx = (m_fifo[1] & 0x00f0) >> 4; + m_pzcx = (m_fifo[1] & 0x000f) >> 0; + } + else if (m_fifo[0] == 0x0806) + { + m_psy = (m_fifo[1] & 0xf000) >> 12; + m_psx = (m_fifo[1] & 0x00f0) >> 4; + } + else if (m_fifo[0] == 0x0807) + { + m_pey = (m_fifo[1] & 0xf000) >> 12; + m_pzy = (m_fifo[1] & 0x0f00) >> 8; + m_pex = (m_fifo[1] & 0x00f0) >> 4; + m_pzx = (m_fifo[1] & 0x000f) >> 0; + } + else if (m_fifo[0] == 0x0808) + m_xmin = m_fifo[1]; + else if (m_fifo[0] == 0x0809) + m_ymin = m_fifo[1]; + else if (m_fifo[0] == 0x080a) + m_xmax = m_fifo[1]; + else if (m_fifo[0] == 0x080b) + m_ymax = m_fifo[1]; + else if (m_fifo[0] == 0x080c) + { + m_rwp = (m_rwp & 0x00fff) | ((m_fifo[1] & 0x00ff) << 12); + m_rwp_dn = (m_fifo[1] & 0xc000) >> 14; + } + else if (m_fifo[0] == 0x080d) + { + m_rwp = (m_rwp & 0xff000) | ((m_fifo[1] & 0xfff0) >> 4); + } + else + logerror("unsupported register\n"); + } + else if ((m_fifo[0] & 0xffe0) == 0x0c00) /* RPR */ + { + if (m_fifo[0] == 0x0c00) + m_fifo[1] = m_cl0; + else if (m_fifo[0] == 0x0c01) + m_fifo[1] = m_cl1; + else if (m_fifo[0] == 0x0c02) + m_fifo[1] = m_ccmp; + else if (m_fifo[0] == 0x0c03) + m_fifo[1] = m_edg; + else if (m_fifo[0] == 0x0c04) + m_fifo[1] = m_mask; + else if (m_fifo[0] == 0x0c05) + { + m_fifo[1] = (m_ppy << 12) | (m_pzcy << 8) | (m_ppx << 4) | m_pzcx; + } + else if (m_fifo[0] == 0x0c06) + { + m_fifo[1] = (m_psx << 12) | (m_psx << 4); + } + else if (m_fifo[0] == 0x0c07) + { + m_fifo[1] = (m_pey << 12) | (m_pzy << 8) | (m_pex << 4) | m_pzx; + } + else if (m_fifo[0] == 0x0c08) + m_fifo[1] = m_xmin; + else if (m_fifo[0] == 0x0c09) + m_fifo[1] = m_ymin; + else if (m_fifo[0] == 0x0c0a) + m_fifo[1] = m_xmax; + else if (m_fifo[0] == 0x0c0b) + m_fifo[1] = m_ymax; + else if (m_fifo[0] == 0x0c0c) + { + m_fifo[1] = (m_rwp_dn << 14) | ((m_rwp >> 12) & 0xff); + } + else if (m_fifo[0] == 0x0c0d) + { + m_fifo[1] = (m_rwp & 0x0fff) << 4; + } + else if (m_fifo[0] == 0x0c10) + { + // TODO + } + else if (m_fifo[0] == 0x0c11) + { + // TODO + } + else if (m_fifo[0] == 0x0c12) + { + m_fifo[1] = m_cpx; + } + else if (m_fifo[0] == 0x0c13) + { + m_fifo[1] = m_cpy; + } + else + logerror("unsupported register\n"); + } + else if ((m_fifo[0] & 0xfff0) == 0x1800) /* WPTN */ + { + int i; + int start = m_fifo[0] & 0x000f; + int n = m_fifo[1]; + for (i = 0; i < n; i++) + m_pattern[start + i] = m_fifo[2 + i]; + } + else if (m_fifo[0] == 0x4400) /* RD */ + { + m_readfifo = m_ram[m_rwp]; + m_rwp = (m_rwp + 1) & (HD63484_RAM_SIZE - 1); + } + else if (m_fifo[0] == 0x4800) /* WT */ + { + m_ram[m_rwp] = m_fifo[1]; + m_rwp = (m_rwp + 1) & (HD63484_RAM_SIZE - 1); + } + else if (m_fifo[0] == 0x5800) /* CLR */ + { + doclr16(m_fifo[0], m_fifo[1], &m_rwp, m_fifo[2], m_fifo[3]); + + { + int fifo2 = (int)m_fifo[2], fifo3 = (int)m_fifo[3]; + if (fifo2 < 0) fifo2 *= -1; + if (fifo3 < 0) fifo3 *= -1; + m_rwp += ((fifo2 + 1) * (fifo3 + 1)); + } + + } + else if ((m_fifo[0] & 0xfffc) == 0x5c00) /* SCLR */ + { + doclr16(m_fifo[0], m_fifo[1], &m_rwp, m_fifo[2], m_fifo[3]); + + { + int fifo2 = (int)m_fifo[2], fifo3 = (int)m_fifo[3]; + if (fifo2 < 0) fifo2 *= -1; + if (fifo3 < 0) fifo3 *= -1; + m_rwp += ((fifo2 + 1) * (fifo3 + 1)); + } + + } + else if ((m_fifo[0] & 0xf0ff) == 0x6000) /* CPY */ + { + docpy16(m_fifo[0], ((m_fifo[1] & 0x00ff) << 12) | ((m_fifo[2] & 0xfff0) >> 4), &m_rwp, m_fifo[3], m_fifo[4]); + + { + int fifo2 = (int)m_fifo[2], fifo3 = (int)m_fifo[3]; + if (fifo2 < 0) fifo2 *= -1; + if (fifo3 < 0) fifo3 *= -1; + m_rwp += ((fifo2 + 1) * (fifo3 + 1)); + } + + } + else if ((m_fifo[0] & 0xf0fc) == 0x7000) /* SCPY */ + { + docpy16(m_fifo[0], ((m_fifo[1] & 0x00ff) << 12) | ((m_fifo[2] & 0xfff0) >> 4), &m_rwp, m_fifo[3], m_fifo[4]); + + { + int fifo2 = (int)m_fifo[2], fifo3 = (int)m_fifo[3]; + if (fifo2 < 0) fifo2 *= -1; + if (fifo3 < 0) fifo3 *= -1; + m_rwp += ((fifo2 + 1) * (fifo3 + 1)); + } + + } + else if (m_fifo[0] == 0x8000) /* AMOVE */ + { + m_cpx = m_fifo[1]; + m_cpy = m_fifo[2]; + } + else if (m_fifo[0] == 0x8400) /* RMOVE */ + { + m_cpx += (INT16)m_fifo[1]; + m_cpy += (INT16)m_fifo[2]; + } + else if ((m_fifo[0] & 0xff00) == 0x8800) /* ALINE */ + { + line(m_cpx, m_cpy, m_fifo[1], m_fifo[2], m_fifo[0] & 0xff); + m_cpx = (INT16)m_fifo[1]; + m_cpy = (INT16)m_fifo[2]; + } + else if ((m_fifo[0] & 0xff00) == 0x8c00) /* RLINE */ + { + line(m_cpx, m_cpy, m_cpx + (INT16)m_fifo[1], m_cpy + (INT16)m_fifo[2], m_fifo[0] & 0xff); + m_cpx += (INT16)m_fifo[1]; + m_cpy += (INT16)m_fifo[2]; + } + else if ((m_fifo[0] & 0xfff8) == 0x9000) /* ARCT */ + { + line(m_cpx, m_cpy, (INT16)m_fifo[1], m_cpy, m_fifo[0] & 0xff); + line((INT16)m_fifo[1], m_cpy, (INT16)m_fifo[1], (INT16)m_fifo[2], m_fifo[0] & 0xff); + line((INT16)m_fifo[1], (INT16)m_fifo[2], m_cpx, (INT16)m_fifo[2], m_fifo[0] & 0xff); + line(m_cpx, (INT16)m_fifo[2], m_cpx, m_cpy, m_fifo[0] & 0xff); + m_cpx = (INT16)m_fifo[1]; + m_cpy = (INT16)m_fifo[2]; + } + else if ((m_fifo[0] & 0xfff8) == 0x9400) /* RRCT added*/ + { + line(m_cpx, m_cpy, m_cpx + (INT16)m_fifo[1], m_cpy, m_fifo[0] & 0xff); + line(m_cpx + (INT16)m_fifo[1], m_cpy, m_cpx + (INT16)m_fifo[1], m_cpy + (INT16)m_fifo[2], m_fifo[0] & 0xff); + line(m_cpx + (INT16)m_fifo[1], m_cpy + (INT16)m_fifo[2], m_cpx, m_cpy + (INT16)m_fifo[2], m_fifo[0] & 0xff); + line(m_cpx, m_cpy + (INT16)m_fifo[2], m_cpx, m_cpy, m_fifo[0] & 0xff); + + m_cpx += (INT16)m_fifo[1]; + m_cpy += (INT16)m_fifo[2]; + } + else if ((m_fifo[0] & 0xfff8) == 0xa400) /* RPLG added*/ + { + int nseg, sx, sy, ex, ey; + sx = m_cpx; + sy = m_cpy; + for (nseg = 0; nseg < m_fifo[1]; nseg++) + { + ex = sx + (INT16)m_fifo[2 + nseg * 2]; + ey = sy + (INT16)m_fifo[2 + nseg * 2 + 1]; + line(sx, sy, ex, ey, m_fifo[0] & 7); + sx = ex; + sy = ey; + } + line(sx, sy, m_cpx, m_cpy, m_fifo[0] & 7); + } + else if ((m_fifo[0] & 0xfe00) == 0xa800) /* CRCL added*/ + { + circle(m_cpx, m_cpy, m_fifo[1] & 0x1fff, m_fifo[0] & 7); // only 13 bit are used for the radius + } + else if ((m_fifo[0] & 0xfff8) == 0xc000) /* AFRCT */ + { + INT16 pcx, pcy; + INT16 ax, ay, xx, yy; + + + pcx = m_fifo[1]; + pcy = m_fifo[2]; + ax = pcx - m_cpx; + ay = pcy - m_cpy; + xx = m_cpx; + yy = m_cpy; + + for (;;) + { + for (;;) + { + dot(xx, yy, m_fifo[0] & 0x07, m_cl0); + + if (ax == 0) break; + else if (ax > 0) + { + xx++; + ax--; + } + else + { + xx--; + ax++; + } + } + + ax = pcx - m_cpx; + if (pcy < m_cpy) + { + yy--; + xx -= ax; + if (ay == 0) break; + ay++; + } + else + { + yy++; + xx -= ax; + if (ay == 0) break; + ay--; + } + } + } + else if ((m_fifo[0] & 0xfff8) == 0xc400) /* RFRCT added TODO*/ + { + line(m_cpx, m_cpy, m_cpx + (INT16)m_fifo[1], m_cpy, m_fifo[0] & 0xff); + line(m_cpx + m_fifo[1], m_cpy, m_cpx + m_fifo[1], m_cpy + m_fifo[2], m_fifo[0] & 0xff); + line(m_cpx + m_fifo[1], m_cpy + m_fifo[2], m_cpx, m_cpy + m_fifo[2], m_fifo[0] & 0xff); + line(m_cpx, m_cpy + m_fifo[2], m_cpx, m_cpy, m_fifo[0] & 0xff); + + m_cpx = m_cpx + (INT16)m_fifo[1]; + m_cpy = m_cpy + (INT16)m_fifo[2]; + } + else if (m_fifo[0] == 0xc800) /* PAINT */ + { + paint(m_cpx, m_cpy, m_cl0); + } + else if ((m_fifo[0] & 0xfff8) == 0xcc00) /* DOT */ + { + dot(m_cpx, m_cpy, m_fifo[0] & 0xff, m_cl0); + } + else if ((m_fifo[0] & 0xf000) == 0xd000) /* PTN (to do) */ + { + ptn(m_fifo[0], m_psx, m_psy, m_pex - m_psx, m_pey - m_psy); + + if ((m_fifo[0] & 0x0800) == 0x0000) + switch (m_fifo[0] & 0x0700) + { + case 0x0000: + if ((m_pey - m_psy) > 0) + m_cpy += (m_pey - m_psy); + else + m_cpy -= (m_pey - m_psy); + break; + case 0x0100: + // missing + break; + case 0x0200: + if ((m_pey - m_psy) > 0) + m_cpx += (m_pey - m_psy); + else + m_cpx -= (m_pey - m_psy); + break; + case 0x0300: + // missing + break; + case 0x0400: + if ((m_pey - m_psy) > 0) + m_cpy -= (m_pey - m_psy); + else + m_cpy += (m_pey - m_psy); + break; + case 0x0500: + // missing + break; + case 0x0600: + if ((m_pey - m_psy) > 0) + m_cpx -= (m_pey - m_psy); + else + m_cpx += (m_pey - m_psy); + break; + case 0x0700: + // missing + break; + } + else + { + // missing + } + } + else if ((m_fifo[0] & 0xf018) == 0xe000) /* agcpy */ + { + agcpy(m_fifo[0], (INT16)m_fifo[1], (INT16)m_fifo[2], m_cpx, m_cpy, m_fifo[3], m_fifo[4]); + + switch (m_fifo[0] & 0x0700) + { + case 0x0000: + if (m_fifo[4] > 0) + m_cpy += m_fifo[4]; + else + m_cpy -= m_fifo[4]; + break; + case 0x0100: + if (m_fifo[4] > 0) + m_cpy -= m_fifo[4]; + else + m_cpy += m_fifo[4]; + break; + case 0x0200: + if (m_fifo[4] > 0) + m_cpy += m_fifo[4]; + else + m_cpy -= m_fifo[4]; + break; + case 0x0300: + if (m_fifo[4] > 0) + m_cpy -= m_fifo[4]; + else + m_cpy += m_fifo[4]; + break; + case 0x0400: + if (m_fifo[3] > 0) + m_cpx += m_fifo[3]; + else + m_cpx -= m_fifo[3]; + break; + case 0x0500: + if (m_fifo[3] > 0) + m_cpx += m_fifo[3]; + else + m_cpx -= m_fifo[3]; + break; + case 0x0600: + if (m_fifo[3] > 0) + m_cpx -= m_fifo[3]; + else + m_cpx += m_fifo[3]; + break; + case 0x0700: + if (m_fifo[3] > 0) + m_cpx -= m_fifo[3]; + else + m_cpx += m_fifo[3]; + break; + } + } + else + { + logerror("unsupported command\n"); + popmessage("unsupported command %s (%04x)", instruction_name[m_fifo[0] >> 10], m_fifo[0]); + } + + m_fifo_counter = 0; + } +} + +READ16_MEMBER( hd63484_device::status_r ) +{ +// if (space.device().safe_pc() != 0xfced6 && space.device().safe_pc() != 0xfe1d6) +// logerror("%05x: HD63484 status read\n",space.device().safe_pc()); + + return 0xff22 | (machine().rand() & 0x0004); /* write FIFO ready + command end + (read FIFO ready or read FIFO not ready) */ +} + +WRITE16_MEMBER( hd63484_device::address_w ) +{ + /* only low 8 bits are used */ + if (ACCESSING_BITS_0_7) + m_regno = data; +} + +WRITE16_MEMBER( hd63484_device::data_w ) +{ + COMBINE_DATA(&m_reg[m_regno/2]); + + if (m_skattva_hack) + m_reg[2/2] = (m_reg[2/2] & 0xf8ff) | 0x0200; // hack to set proper color depth in skattva + + if (m_regno & 0x80) + m_regno += 2; /* autoincrement */ + +#if LOG_COMMANDS +// logerror("PC %05x: HD63484 register %02x write %04x\n", space.device().safe_pc(), m_regno, m_reg[m_regno/2]); +#endif + + if (m_regno == 0) /* FIFO */ + command_w(m_reg[0]); +} + +READ16_MEMBER( hd63484_device::data_r ) +{ + int res; + + if (m_regno == 0x80) + res = machine().first_screen()->vpos(); + else if (m_regno == 0) + { +#if LOG_COMMANDS +// logerror("%05x: HD63484 read FIFO\n", space.device().safe_pc()); +#endif + res = m_readfifo; + } + else + { +#if LOG_COMMANDS +// logerror("%05x: HD63484 read register %02x\n", space.device().safe_pc(), m_regno); +#endif + res = 0; + } + + return res; +} + +READ16_MEMBER( hd63484_device::ram_r ) +{ + return m_ram[offset]; +} + +READ16_MEMBER( hd63484_device::regs_r ) +{ + return m_reg[offset]; +} + +WRITE16_MEMBER( hd63484_device::ram_w ) +{ + COMBINE_DATA(&m_ram[offset]); +} + +WRITE16_MEMBER( hd63484_device::regs_w ) +{ + COMBINE_DATA(&m_reg[offset]); +} diff --git a/src/devices/video/hd63484.h b/src/devices/video/hd63484.h new file mode 100644 index 00000000000..08d147a8081 --- /dev/null +++ b/src/devices/video/hd63484.h @@ -0,0 +1,81 @@ +// license:BSD-3-Clause +// copyright-holders:Roberto Zandona' +/************************************************************************* + + HD63484 ACRTC + Advanced CRT Controller. + +**************************************************************************/ + +#ifndef __HD63484_H__ +#define __HD63484_H__ + + +/* the on-chip FIFO is 16 bytes long, but we use a larger one to simplify */ +/* decoding of long commands. Commands can be up to 64KB long... but Shanghai */ +/* doesn't reach that length. */ + +#define FIFO_LENGTH 256 +#define HD63484_RAM_SIZE 0x100000 + + +/*************************************************************************** + TYPE DEFINITIONS +***************************************************************************/ + +class hd63484_device : public device_t +{ +public: + hd63484_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + ~hd63484_device() {} + + DECLARE_READ16_MEMBER( status_r ); + DECLARE_WRITE16_MEMBER( address_w ); + DECLARE_WRITE16_MEMBER( data_w ); + DECLARE_READ16_MEMBER( data_r ); + + DECLARE_READ16_MEMBER( ram_r ); + DECLARE_READ16_MEMBER( regs_r ); + DECLARE_WRITE16_MEMBER( ram_w ); + DECLARE_WRITE16_MEMBER( regs_w ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + +private: + // internal state + UINT16 * m_ram; + UINT16 m_reg[256/2]; + + int m_fifo_counter; + UINT16 m_fifo[FIFO_LENGTH]; + UINT16 m_readfifo; + + UINT16 m_pattern[16]; + int m_org, m_org_dpd, m_rwp; + UINT16 m_cl0, m_cl1, m_ccmp, m_edg, m_mask, m_ppy, m_pzcy, m_ppx, m_pzcx, m_psy, m_psx, m_pey, m_pzy, m_pex, m_pzx, m_xmin, m_ymin, m_xmax, m_ymax, m_rwp_dn; + INT16 m_cpx, m_cpy; + + int m_regno; + int m_skattva_hack; + + void doclr16( int opcode, UINT16 fill, int *dst, INT16 _ax, INT16 _ay ); + void docpy16( int opcode, int src, int *dst, INT16 _ax, INT16 _ay ); + int org_first_pixel( int _org_dpd ); + void dot( int x, int y, int opm, UINT16 color ); + int get_pixel( int x, int y ); + int get_pixel_ptn( int x, int y ); + void agcpy( int opcode, int src_x, int src_y, int dst_x, int dst_y, INT16 _ax, INT16 _ay ); + void ptn( int opcode, int src_x, int src_y, INT16 _ax, INT16 _ay ); + void line( INT16 sx, INT16 sy, INT16 ex, INT16 ey, INT16 col ); + void circle( INT16 sx, INT16 sy, UINT16 r, INT16 col ); + void paint( int sx, int sy, int col ); + + void command_w(UINT16 cmd); +}; + +extern ATTR_DEPRECATED const device_type HD63484; + +#endif /* __HD63484_H__ */ diff --git a/src/devices/video/hd66421.c b/src/devices/video/hd66421.c new file mode 100644 index 00000000000..af67be24d78 --- /dev/null +++ b/src/devices/video/hd66421.c @@ -0,0 +1,287 @@ +// license:BSD-3-Clause +// copyright-holders:Tim Schuerewegen +/* + + Hitachi HD66421 LCD Controller/Driver + + (c) 2001-2007 Tim Schuerewegen + +*/ + +#include "emu.h" +#include "hd66421.h" + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define LOG_LEVEL 1 +#define _logerror(level,x) do { if (LOG_LEVEL > level) logerror x; } while (0) + +#define HD66421_RAM_SIZE (HD66421_WIDTH * HD66421_HEIGHT / 4) // 2-bits per pixel + +// R0 - control register 1 +#define LCD_R0_RMW 0x80 // read-modify-write mode +#define LCD_R0_DISP 0x40 // display on/off +#define LCD_R0_STBY 0x20 // standby (internal operation and power circuit halt) +#define LCD_R0_PWR 0x10 +#define LCD_R0_AMP 0x08 +#define LCD_R0_REV 0x04 // reverse +#define LCD_R0_HOLT 0x02 +#define LCD_R0_ADC 0x01 + +// R1 - control register 2 +#define LCD_R1_BIS1 0x80 // bias ratio (bit 1) +#define LCD_R1_BIS0 0x40 // bias ratio (bit 0) +#define LCD_R1_WLS 0x20 +#define LCD_R1_GRAY 0x10 // grayscale palette 4/32 +#define LCD_R1_DTY1 0x08 // display duty cycle (bit 1) +#define LCD_R1_DTY0 0x04 // display duty cycle (bit 0) +#define LCD_R1_INC 0x02 +#define LCD_R1_BLK 0x01 // blink function + +// register 0 to 16 +#define LCD_REG_CONTROL_1 0x00 // control register 1 +#define LCD_REG_CONTROL_2 0x01 // control register 2 +#define LCD_REG_ADDR_X 0x02 // x address register +#define LCD_REG_ADDR_Y 0x03 // y address register +#define LCD_REG_RAM 0x04 // display ram access register +#define LCD_REG_START_Y 0x05 // display start line register +#define LCD_REG_BLINK_START 0x06 // blink start line register +#define LCD_REG_BLINK_END 0x07 // blink end line register +#define LCD_REG_BLINK_1 0x08 // blink register 1 +#define LCD_REG_BLINK_2 0x09 // blink register 2 +#define LCD_REG_BLINK_3 0x0A // blink register 3 +#define LCD_REG_PARTIAL 0x0B // partial display block register +#define LCD_REG_COLOR_1 0x0C // gray scale palette 1 (0,0) +#define LCD_REG_COLOR_2 0x0D // gray scale palette 2 (0,1) +#define LCD_REG_COLOR_3 0x0E // gray scale palette 3 (1,0) +#define LCD_REG_COLOR_4 0x0F // gray scale palette 4 (1,1) +#define LCD_REG_CONTRAST 0x10 // contrast control register +#define LCD_REG_PLANE 0x11 // plane selection register + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +// devices +const device_type HD66421 = &device_creator; + + +// default address map +static ADDRESS_MAP_START( hd66421, AS_0, 8, hd66421_device ) + AM_RANGE(0x0000, HD66421_RAM_SIZE) AM_RAM +ADDRESS_MAP_END + +//------------------------------------------------- +// memory_space_config - return a description of +// any address spaces owned by this device +//------------------------------------------------- + +const address_space_config *hd66421_device::memory_space_config(address_spacenum spacenum) const +{ + return (spacenum == AS_0) ? &m_space_config : NULL; +} + + +//************************************************************************** +// INLINE HELPERS +//************************************************************************** + +//------------------------------------------------- +// readbyte - read a byte at the given address +//------------------------------------------------- + +inline UINT8 hd66421_device::readbyte(offs_t address) +{ + return space().read_byte(address); +} + + +//------------------------------------------------- +// writebyte - write a byte at the given address +//------------------------------------------------- + +inline void hd66421_device::writebyte(offs_t address, UINT8 data) +{ + space().write_byte(address, data); +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// hd66421_device - constructor +//------------------------------------------------- + +hd66421_device::hd66421_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, HD66421, "Hitachi HD66421 LCD Controller", tag, owner, clock, "hd66421", __FILE__), + device_memory_interface(mconfig, *this), + m_space_config("videoram", ENDIANNESS_LITTLE, 8, 17, 0, NULL, *ADDRESS_MAP_NAME(hd66421)), + m_cmd(0), + m_x(0), + m_y(0), + m_palette(*this, "palette") +{ + for (int i = 0; i < 32; i++) + { + m_reg[i] = 0; + } +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void hd66421_device::device_start() +{ + // register for state saving + save_item(NAME(m_cmd)); + save_item(NAME(m_reg)); + save_item(NAME(m_x)); + save_item(NAME(m_y)); +} + +READ8_MEMBER( hd66421_device::reg_idx_r ) +{ + _logerror( 2, ("reg_idx_r\n")); + return m_cmd; +} + +WRITE8_MEMBER( hd66421_device::reg_idx_w ) +{ + _logerror( 2, ("reg_idx_w (%02X)\n", data)); + m_cmd = data; +} + +READ8_MEMBER( hd66421_device::reg_dat_r ) +{ + _logerror( 2, ("reg_dat_r\n")); + return m_reg[m_cmd]; +} + +WRITE8_MEMBER( hd66421_device::reg_dat_w ) +{ + _logerror( 2, ("reg_dat_w (%02X)\n", data)); + m_reg[m_cmd] = data; + + switch (m_cmd) + { + case LCD_REG_ADDR_X : + m_x = data; + break; + + case LCD_REG_ADDR_Y : + m_y = data; + break; + + case LCD_REG_RAM : + { + UINT8 r1; + writebyte(m_y * (HD66421_WIDTH / 4) + m_x, data); + r1 = m_reg[LCD_REG_CONTROL_2]; + if (r1 & 0x02) + m_x++; + else + m_y++; + + if (m_x >= (HD66421_WIDTH / 4)) + { + m_x = 0; + m_y++; + } + + if (m_y >= HD66421_HEIGHT) + m_y = 0; + } + break; + } +} + +void hd66421_device::plot_pixel(bitmap_ind16 &bitmap, int x, int y, UINT32 color) +{ + bitmap.pix16(y, x) = (UINT16)color; +} + +UINT32 hd66421_device::update_screen(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) +{ + pen_t pen[4]; + + _logerror( 1, ("video_update_hd66421\n")); + + // update palette + for (int i = 0; i < 4; i++) + { + double bright; + int temp; + temp = 31 - (m_reg[LCD_REG_COLOR_1 + i] - m_reg[LCD_REG_CONTRAST] + 0x03); + if (temp < 0) temp = 0; + if (temp > 31) temp = 31; + bright = 1.0 * temp / 31; + pen[i] = i; + #ifdef HD66421_BRIGHTNESS_DOES_NOT_WORK + m_palette->set_pen_color(pen[i], 255 * bright, 255 * bright, 255 * bright); + #else + m_palette->set_pen_contrast(pen[i], bright); + #endif + } + + // draw bitmap (bottom to top) + if (m_reg[0] & LCD_R0_DISP) + { + int x, y; + x = 0; + y = HD66421_HEIGHT - 1; + + for (int i = 0; i < HD66421_RAM_SIZE; i++) + { + plot_pixel(bitmap, x++, y, pen[(readbyte(i) >> 6) & 3]); + plot_pixel(bitmap, x++, y, pen[(readbyte(i) >> 4) & 3]); + plot_pixel(bitmap, x++, y, pen[(readbyte(i) >> 2) & 3]); + plot_pixel(bitmap, x++, y, pen[(readbyte(i) >> 0) & 3]); + if (x >= HD66421_WIDTH) + { + x = 0; + y = y - 1; + } + } + } + else + { + rectangle rect(0, HD66421_WIDTH - 1, 0, HD66421_HEIGHT - 1); + bitmap.fill(m_palette->white_pen(), rect); + } + + return 0; +} + +PALETTE_INIT_MEMBER(hd66421_device, hd66421) +{ + // init palette + for (int i = 0; i < 4; i++) + { + palette.set_pen_color(i, rgb_t::white); +#ifndef HD66421_BRIGHTNESS_DOES_NOT_WORK + palette.set_pen_contrast(i, 1.0 * i / (4 - 1)); +#endif + } +} + + +static MACHINE_CONFIG_FRAGMENT( hd66421 ) + MCFG_PALETTE_ADD("palette", 4) + MCFG_PALETTE_INIT_OWNER(hd66421_device, hd66421) +MACHINE_CONFIG_END + +//------------------------------------------------- +// machine_config_additions - return a pointer to +// the device's machine fragment +//------------------------------------------------- + +machine_config_constructor hd66421_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( hd66421 ); +} diff --git a/src/devices/video/hd66421.h b/src/devices/video/hd66421.h new file mode 100644 index 00000000000..baed72ad30c --- /dev/null +++ b/src/devices/video/hd66421.h @@ -0,0 +1,84 @@ +// license:BSD-3-Clause +// copyright-holders:Tim Schuerewegen +/*************************************************************************** + + Hitachi HD66421 LCD Controller + + (c) 2001-2007 Tim Schuerewegen + + ***************************************************************************/ + +#pragma once + +#ifndef __HD66421_H__ +#define __HD66421_H__ + + +///************************************************************************* +// MACROS / CONSTANTS +///************************************************************************* + +//#define HD66421_BRIGHTNESS_DOES_NOT_WORK + +#define HD66421_WIDTH 160 +#define HD66421_HEIGHT 100 + + +/*----------- defined in video/hd66421.c -----------*/ + +///************************************************************************* +// INTERFACE CONFIGURATION MACROS +///************************************************************************* + +#define MCFG_HD66421_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, HD66421, 0) + +///************************************************************************* +// TYPE DEFINITIONS +///************************************************************************* + +// ======================> hd66421_device + +class hd66421_device : public device_t, + public device_memory_interface +{ +public: + // construction/destruction + hd66421_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + DECLARE_READ8_MEMBER( reg_idx_r ); + DECLARE_WRITE8_MEMBER( reg_idx_w ); + DECLARE_READ8_MEMBER( reg_dat_r ); + DECLARE_WRITE8_MEMBER( reg_dat_w ); + DECLARE_PALETTE_INIT(hd66421); + + UINT32 update_screen(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); + +protected: + // device-level overrides + virtual void device_start(); + virtual machine_config_constructor device_mconfig_additions() const; + + // device_config_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const; + + // address space configurations + const address_space_config m_space_config; + + inline UINT8 readbyte(offs_t address); + inline void writebyte(offs_t address, UINT8 data); + + void plot_pixel(bitmap_ind16 &bitmap, int x, int y, UINT32 color); + +private: + UINT8 m_cmd, m_reg[32]; + int m_x, m_y; + required_device m_palette; +}; + + +// device type definition +extern const device_type HD66421; + + +#endif diff --git a/src/devices/video/huc6202.c b/src/devices/video/huc6202.c new file mode 100644 index 00000000000..3f33a3eaa05 --- /dev/null +++ b/src/devices/video/huc6202.c @@ -0,0 +1,367 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +/********************************************************************** + + Hudson/NEC HuC6202 Video Priority Controller + +**********************************************************************/ + +#include "emu.h" +#include "huc6270.h" +#include "huc6202.h" + + +const device_type HUC6202 = &device_creator; + + +huc6202_device::huc6202_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, HUC6202, "HuC6202 VPC", tag, owner, clock, "huc6202", __FILE__), + m_next_pixel_0_cb(*this), + m_time_til_next_event_0_cb(*this), + m_vsync_changed_0_cb(*this), + m_hsync_changed_0_cb(*this), + m_read_0_cb(*this), + m_write_0_cb(*this), + m_next_pixel_1_cb(*this), + m_time_til_next_event_1_cb(*this), + m_vsync_changed_1_cb(*this), + m_hsync_changed_1_cb(*this), + m_read_1_cb(*this), + m_write_1_cb(*this) +{ +} + + +READ16_MEMBER( huc6202_device::next_pixel ) +{ + UINT16 data = huc6270_device::HUC6270_BACKGROUND; + + UINT16 data_0 = m_next_pixel_0_cb( 0, 0xffff ); + UINT16 data_1 = m_next_pixel_1_cb( 0, 0xffff ); + + if ( data_0 == huc6270_device::HUC6270_SPRITE && data_1 == huc6270_device::HUC6270_SPRITE ) + { + m_map_index = 0; + if ( m_map_dirty ) + { + int i; + + for ( i = 0; i < 512; i++ ) + { + m_prio_map[ i ] = 0; + if ( m_window1 < 0x40 || i > m_window1 ) + { + m_prio_map [ i ] |= 1; + } + if ( m_window2 < 0x40 || i > m_window2 ) + { + m_prio_map[ i ] |= 2; + } + } + m_map_dirty = 0; + } + } + else + { + UINT8 prio_index = m_prio_map[ m_map_index ]; + + if ( m_prio[ prio_index ].dev0_enabled && data_0 != huc6270_device::HUC6270_SPRITE ) + { + if ( m_prio[ prio_index ].dev1_enabled && data_1 != huc6270_device::HUC6270_SPRITE ) + { + switch ( m_prio[ prio_index ].prio_type ) + { + case 0: /* Back - BG1 SP1 BG0 SP0 - Front */ + data = ( data_0 & 0x0F ) ? data_0 : data_1; + break; + + case 1: /* Back - BG1 BG0 SP1 SP0 - Front */ + if ( data_0 > huc6270_device::HUC6270_SPRITE ) + { + /* Device 0 sprite */ + data = data_0; + } + else if ( data_1 > huc6270_device::HUC6270_SPRITE ) + { + /* Device 1 sprite */ + data = data_1; + } + else + { + /* Device 0 and 1 backgrounds */ + data = ( data_0 & 0x0F ) ? data_0 : data_1; + } + break; + + case 2: /* Back - BG0 + SP1 => BG0 - Front + BG0 + BG1 => BG0 + BG1 + SP0 => BG1 + SP0 + SP1 => SP0 + */ + if ( data_1 > huc6270_device::HUC6270_SPRITE ) + { + if ( data_0 > huc6270_device::HUC6270_SPRITE ) + { + /* Device 1 sprite, device 0 sprite */ + data = data_0; + } + else + { + /* Device 1 sprite, device 0 background */ + data = ( data_0 & 0x0F ) ? data_0 : data_1; + } + } + else + { + if ( data_0 > huc6270_device::HUC6270_SPRITE ) + { + /* Device 1 background, device 0 sprite */ + data = data_1; + } + else + { + /* Device 1 background, device 0 background */ + data = ( data_0 & 0x0F ) ? data_0 : data_1; + } + } + break; + + case 3: /* ?? */ + break; + } + } + else + { + /* Only device 0 is enabled */ + data = data_0; + } + } + else + { + /* Only device 1 is enabled */ + if ( m_prio[ prio_index ].dev1_enabled && data_1 != huc6270_device::HUC6270_SPRITE ) + { + data = data_1; + } + } + m_map_index += 1; + } + return data; +} + + +READ16_MEMBER( huc6202_device::time_until_next_event ) +{ + UINT16 next_event_clocks_0 = m_time_til_next_event_0_cb( 0, 0xffff ); + UINT16 next_event_clocks_1 = m_time_til_next_event_1_cb( 0, 0xffff ); + + return MIN( next_event_clocks_0, next_event_clocks_1 ); +} + + +WRITE_LINE_MEMBER( huc6202_device::vsync_changed ) +{ + m_vsync_changed_0_cb( state ); + m_vsync_changed_1_cb( state ); +} + + +WRITE_LINE_MEMBER( huc6202_device::hsync_changed ) +{ + m_hsync_changed_0_cb( state ); + m_hsync_changed_1_cb( state ); +} + + +READ8_MEMBER( huc6202_device::read ) +{ + UINT8 data = 0xFF; + + switch ( offset & 7 ) + { + case 0x00: /* Priority register #0 */ + data = ( m_prio[0].prio_type << 2 ) | + ( m_prio[0].dev0_enabled ? 0x01 : 0 ) | + ( m_prio[0].dev1_enabled ? 0x02 : 0 ) | + ( m_prio[1].prio_type << 6 ) | + ( m_prio[1].dev0_enabled ? 0x10 : 0 ) | + ( m_prio[1].dev1_enabled ? 0x20 : 0 ); + break; + + case 0x01: /* Priority register #1 */ + data = ( m_prio[2].prio_type << 2 ) | + ( m_prio[2].dev0_enabled ? 0x01 : 0 ) | + ( m_prio[2].dev1_enabled ? 0x02 : 0 ) | + ( m_prio[3].prio_type << 6 ) | + ( m_prio[3].dev0_enabled ? 0x10 : 0 ) | + ( m_prio[3].dev1_enabled ? 0x20 : 0 ); + break; + + case 0x02: /* Window 1 LSB */ + data = m_window1 & 0xFF; + break; + + case 0x03: /* Window 1 MSB */ + data = ( m_window1 >> 8 ) & 0xFF; + break; + + case 0x04: /* Window 2 LSB */ + data = m_window2 & 0xFF; + break; + + case 0x05: /* Window 2 MSB */ + data = ( m_window2 >> 8 ) & 0xFF; + break; + } + + return data; +} + + +WRITE8_MEMBER( huc6202_device::write ) +{ + switch ( offset & 7 ) + { + case 0x00: /* Priority register #0 */ + m_prio[0].dev0_enabled = data & 0x01; + m_prio[0].dev1_enabled = data & 0x02; + m_prio[0].prio_type = ( data >> 2 ) & 0x03; + m_prio[1].dev0_enabled = data & 0x10; + m_prio[1].dev1_enabled = data & 0x20; + m_prio[1].prio_type = ( data >> 6 ) & 0x03; + break; + + case 0x01: /* Priority register #1 */ + m_prio[2].dev0_enabled = data & 0x01; + m_prio[2].dev1_enabled = data & 0x02; + m_prio[2].prio_type = ( data >> 2 ) & 0x03; + m_prio[3].dev0_enabled = data & 0x10; + m_prio[3].dev1_enabled = data & 0x20; + m_prio[3].prio_type = ( data >> 6 ) & 0x03; + break; + + case 0x02: /* Window 1 LSB */ + m_window1 = ( m_window1 & 0xFF00 ) | data; + m_map_dirty = 1; + break; + + case 0x03: /* Window 1 MSB */ + m_window1 = ( ( m_window1 & 0x00FF ) | ( data << 8 ) ) & 0x3FF; + m_map_dirty = 1; + break; + + case 0x04: /* Window 2 LSB */ + m_window2 = ( m_window2 & 0xFF00 ) | data; + m_map_dirty = 1; + break; + + case 0x05: /* Window 2 MSB */ + m_window2 = ( ( m_window2 & 0x00FF ) | ( data << 8 ) ) & 0x3FF; + m_map_dirty = 1; + break; + + case 0x06: /* I/O select */ + m_io_device = data & 0x01; + break; + } +} + + +READ8_MEMBER( huc6202_device::io_read ) +{ + if ( m_io_device ) + { + return m_read_1_cb( offset ); + } + else + { + return m_read_0_cb( offset ); + } +} + + +WRITE8_MEMBER( huc6202_device::io_write ) +{ + if ( m_io_device ) + { + m_write_1_cb( offset, data ); + } + else + { + m_write_0_cb( offset, data ); + } +} + + +void huc6202_device::device_start() +{ + /* Resolve callbacks */ + m_next_pixel_0_cb.resolve(); + m_time_til_next_event_0_cb.resolve(); + m_hsync_changed_0_cb.resolve(); + m_vsync_changed_0_cb.resolve(); + m_read_0_cb.resolve(); + m_write_0_cb.resolve(); + + m_next_pixel_1_cb.resolve(); + m_time_til_next_event_1_cb.resolve(); + m_hsync_changed_1_cb.resolve(); + m_vsync_changed_1_cb.resolve(); + m_read_1_cb.resolve(); + m_write_1_cb.resolve(); + + /* We want all our callbacks to be resolved */ + assert( ! m_next_pixel_0_cb.isnull() ); + assert( ! m_time_til_next_event_0_cb.isnull() ); + assert( ! m_hsync_changed_0_cb.isnull() ); + assert( ! m_vsync_changed_0_cb.isnull() ); + assert( ! m_read_0_cb.isnull() ); + assert( ! m_write_0_cb.isnull() ); + assert( ! m_next_pixel_1_cb.isnull() ); + assert( ! m_time_til_next_event_1_cb.isnull() ); + assert( ! m_hsync_changed_1_cb.isnull() ); + assert( ! m_vsync_changed_1_cb.isnull() ); + assert( ! m_read_1_cb.isnull() ); + assert( ! m_write_1_cb.isnull() ); + + /* Register save items */ + save_item(NAME(m_prio[0].prio_type)); + save_item(NAME(m_prio[0].dev0_enabled)); + save_item(NAME(m_prio[0].dev1_enabled)); + save_item(NAME(m_prio[1].prio_type)); + save_item(NAME(m_prio[1].dev0_enabled)); + save_item(NAME(m_prio[1].dev1_enabled)); + save_item(NAME(m_prio[2].prio_type)); + save_item(NAME(m_prio[2].dev0_enabled)); + save_item(NAME(m_prio[2].dev1_enabled)); + save_item(NAME(m_prio[3].prio_type)); + save_item(NAME(m_prio[3].dev0_enabled)); + save_item(NAME(m_prio[3].dev1_enabled)); + save_item(NAME(m_window1)); + save_item(NAME(m_window2)); + save_item(NAME(m_io_device)); + save_item(NAME(m_map_index)); + save_item(NAME(m_map_dirty)); + save_item(NAME(m_prio_map)); +} + + +void huc6202_device::device_reset() +{ + m_prio[0].prio_type = 0; + m_prio[0].dev0_enabled = 1; + m_prio[0].dev1_enabled = 0; + m_prio[1].prio_type = 0; + m_prio[1].dev0_enabled = 1; + m_prio[1].dev1_enabled = 0; + m_prio[2].prio_type = 0; + m_prio[2].dev0_enabled = 1; + m_prio[2].dev1_enabled = 0; + m_prio[3].prio_type = 0; + m_prio[3].dev0_enabled = 1; + m_prio[3].dev1_enabled = 0; + m_map_dirty = 1; + m_window1 = 0; + m_window2 = 0; + m_io_device = 0; +} diff --git a/src/devices/video/huc6202.h b/src/devices/video/huc6202.h new file mode 100644 index 00000000000..85ae87c1db7 --- /dev/null +++ b/src/devices/video/huc6202.h @@ -0,0 +1,130 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +/********************************************************************** + + Hudson/NEC HuC6202 interface + +**********************************************************************/ + +#ifndef __HUC6202_H_ +#define __HUC6202_H_ + +#include "emu.h" + + +#define MCFG_HUC6202_NEXT_PIXEL_0_CB(_devcb) \ + devcb = &huc6202_device::set_next_pixel_0_callback(*device, DEVCB_##_devcb); + +#define MCFG_HUC6202_TIME_TIL_NEXT_EVENT_0_CB(_devcb) \ + devcb = &huc6202_device::set_time_til_next_event_0_callback(*device, DEVCB_##_devcb); + +#define MCFG_HUC6202_VSYNC_CHANGED_0_CB(_devcb) \ + devcb = &huc6202_device::set_vsync_changed_0_callback(*device, DEVCB_##_devcb); + +#define MCFG_HUC6202_HSYNC_CHANGED_0_CB(_devcb) \ + devcb = &huc6202_device::set_hsync_changed_0_callback(*device, DEVCB_##_devcb); + +#define MCFG_HUC6202_READ_0_CB(_devcb) \ + devcb = &huc6202_device::set_read_0_callback(*device, DEVCB_##_devcb); + +#define MCFG_HUC6202_WRITE_0_CB(_devcb) \ + devcb = &huc6202_device::set_write_0_callback(*device, DEVCB_##_devcb); + +#define MCFG_HUC6202_NEXT_PIXEL_1_CB(_devcb) \ + devcb = &huc6202_device::set_next_pixel_1_callback(*device, DEVCB_##_devcb); + +#define MCFG_HUC6202_TIME_TIL_NEXT_EVENT_1_CB(_devcb) \ + devcb = &huc6202_device::set_time_til_next_event_1_callback(*device, DEVCB_##_devcb); + +#define MCFG_HUC6202_VSYNC_CHANGED_1_CB(_devcb) \ + devcb = &huc6202_device::set_vsync_changed_1_callback(*device, DEVCB_##_devcb); + +#define MCFG_HUC6202_HSYNC_CHANGED_1_CB(_devcb) \ + devcb = &huc6202_device::set_hsync_changed_1_callback(*device, DEVCB_##_devcb); + +#define MCFG_HUC6202_READ_1_CB(_devcb) \ + devcb = &huc6202_device::set_read_1_callback(*device, DEVCB_##_devcb); + +#define MCFG_HUC6202_WRITE_1_CB(_devcb) \ + devcb = &huc6202_device::set_write_1_callback(*device, DEVCB_##_devcb); + + +class huc6202_device : public device_t +{ +public: + // construction/destruction + huc6202_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + template static devcb_base &set_next_pixel_0_callback(device_t &device, _Object object) { return downcast(device).m_next_pixel_0_cb.set_callback(object); } + template static devcb_base &set_time_til_next_event_0_callback(device_t &device, _Object object) { return downcast(device).m_time_til_next_event_0_cb.set_callback(object); } + template static devcb_base &set_vsync_changed_0_callback(device_t &device, _Object object) { return downcast(device).m_vsync_changed_0_cb.set_callback(object); } + template static devcb_base &set_hsync_changed_0_callback(device_t &device, _Object object) { return downcast(device).m_hsync_changed_0_cb.set_callback(object); } + template static devcb_base &set_read_0_callback(device_t &device, _Object object) { return downcast(device).m_read_0_cb.set_callback(object); } + template static devcb_base &set_write_0_callback(device_t &device, _Object object) { return downcast(device).m_write_0_cb.set_callback(object); } + template static devcb_base &set_next_pixel_1_callback(device_t &device, _Object object) { return downcast(device).m_next_pixel_1_cb.set_callback(object); } + template static devcb_base &set_time_til_next_event_1_callback(device_t &device, _Object object) { return downcast(device).m_time_til_next_event_1_cb.set_callback(object); } + template static devcb_base &set_vsync_changed_1_callback(device_t &device, _Object object) { return downcast(device).m_vsync_changed_1_cb.set_callback(object); } + template static devcb_base &set_hsync_changed_1_callback(device_t &device, _Object object) { return downcast(device).m_hsync_changed_1_cb.set_callback(object); } + template static devcb_base &set_read_1_callback(device_t &device, _Object object) { return downcast(device).m_read_1_cb.set_callback(object); } + template static devcb_base &set_write_1_callback(device_t &device, _Object object) { return downcast(device).m_write_1_cb.set_callback(object); } + + DECLARE_READ8_MEMBER( read ); + DECLARE_WRITE8_MEMBER( write ); + DECLARE_READ8_MEMBER( io_read ); + DECLARE_WRITE8_MEMBER( io_write ); + DECLARE_READ16_MEMBER( next_pixel ); + DECLARE_READ16_MEMBER( time_until_next_event ); + DECLARE_WRITE_LINE_MEMBER( vsync_changed ); + DECLARE_WRITE_LINE_MEMBER( hsync_changed ); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + +private: + /* callbacks */ + /* First gfx input device */ + devcb_read16 m_next_pixel_0_cb; + + /* TODO: Choose proper types */ + /* Callback function to get time until next event */ + devcb_read16 m_time_til_next_event_0_cb; + + devcb_write_line m_vsync_changed_0_cb; + devcb_write_line m_hsync_changed_0_cb; + devcb_read8 m_read_0_cb; + devcb_write8 m_write_0_cb; + + + /* Second gfx input device */ + devcb_read16 m_next_pixel_1_cb; + + /* TODO: Choose proper types */ + /* Callback function to get time until next event */ + devcb_read16 m_time_til_next_event_1_cb; + + devcb_write_line m_vsync_changed_1_cb; + devcb_write_line m_hsync_changed_1_cb; + devcb_read8 m_read_1_cb; + devcb_write8 m_write_1_cb; + + struct { + UINT8 prio_type; + UINT8 dev0_enabled; + UINT8 dev1_enabled; + } m_prio[4]; + UINT16 m_window1; + UINT16 m_window2; + int m_io_device; + int m_map_index; + int m_map_dirty; + UINT8 m_prio_map[512]; + +}; + + +extern const device_type HUC6202; + + +#endif diff --git a/src/devices/video/huc6260.c b/src/devices/video/huc6260.c new file mode 100644 index 00000000000..7d3ccc75f78 --- /dev/null +++ b/src/devices/video/huc6260.c @@ -0,0 +1,311 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +/********************************************************************** + + Hudson/NEC HuC6260 Video Colour Encoder + + The HuC6260 takes a stream of pixel data, looks up the correct + palette data and outputs a video stream. + + The HuC6260 generates the tv control signals. A full line lasts + 1365 "master" cycles (typically at 21.47727Mhz). + + HSync is low for 237 and high for 1128 master cycles. + VSync is low for 4095 master cycles (3 lines). + VSync changes 30 master cycles after HSync would go low. + +**********************************************************************/ + +#include "emu.h" +#include "huc6260.h" + +#define LOG 0 + +#define HUC6260_HSYNC_LENGTH 237 +#define HUC6260_HSYNC_START ( HUC6260_WPF - HUC6260_HSYNC_LENGTH ) + + +PALETTE_INIT_MEMBER(huc6260_device, huc6260) +{ + int i; + + for ( i = 0; i < 512; i++ ) + { + int r = pal3bit( ( i >> 3 ) & 7 ); + int g = pal3bit( ( i >> 6 ) & 7 ); + int b = pal3bit( ( i ) & 7 ); + int y = ( ( 66 * r + 129 * g + 25 * b + 128 ) >> 8 ) + 16; + + palette.set_pen_color( i, r, g, b ); + palette.set_pen_color( 512 + i, y, y, y ); + } +} + + +const device_type HUC6260 = &device_creator; + + +huc6260_device::huc6260_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, HUC6260, "HuC6260 VCE", tag, owner, clock, "huc6260", __FILE__), + device_video_interface(mconfig, *this), + m_next_pixel_data_cb(*this), + m_time_til_next_event_cb(*this), + m_vsync_changed_cb(*this), + m_hsync_changed_cb(*this) +{ +} + + +void huc6260_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + int vpos = m_screen->vpos(); + int hpos = m_screen->hpos(); + int h = m_last_h; + int v = m_last_v; + UINT16 *bitmap_line = &m_bmp->pix16(v); + + while ( h != hpos || v != vpos ) + { + if ( m_pixel_clock == 0 ) + { + g_profiler.start( PROFILER_VIDEO ); + /* Get next pixel information */ + m_pixel_data = m_next_pixel_data_cb( 0, 0xffff ); + g_profiler.stop(); + if ( m_greyscales ) + { + m_pixel_data += 512; + } + } + + bitmap_line[ h ] = m_palette[ m_pixel_data ]; + m_pixel_clock = ( m_pixel_clock + 1 ) % m_pixels_per_clock; + h = ( h + 1 ) % HUC6260_WPF; + + switch( h ) + { + case HUC6260_HSYNC_START: /* Start of HSync */ + m_hsync_changed_cb( 0 ); +// if ( v == 0 ) +// { +// /* Check if the screen should be resized */ +// m_height = HUC6260_LPF - ( m_blur ? 1 : 0 ); +// if ( m_height != video_screen_get_height( m_screen ) ) +// { +// rectangle visible_area; +// +// /* TODO: Set proper visible area parameters */ +// visible_area.min_x = 64; +// visible_area.min_y = 18; +// visible_area.max_x = 64 + 1024 + 64 - 1; +// visible_area.max_y = 18 + 242 - 1; +// +// video_screen_configure( m_screen, HUC6260_WPF, m_height, &visible_area, HZ_TO_ATTOSECONDS( device->clock / ( HUC6260_WPF * m_height ) ) ); +// } +// } + break; + + case 0: /* End of HSync */ + m_hsync_changed_cb( 1 ); + m_pixel_clock = 0; + v = ( v + 1 ) % m_height; + bitmap_line = &m_bmp->pix16(v); + break; + + case HUC6260_HSYNC_START + 30: /* End/Start of VSync */ + if ( v>= m_height - 4 ) + { + m_vsync_changed_cb( ( v >= m_height - 4 && v < m_height - 1 ) ? 0 : 1 ); + } + break; + } + } + + m_last_h = h; + m_last_v = v; + + /* Reschedule timer */ + if ( m_last_h < HUC6260_HSYNC_START ) + { + /* Next event is start of HSync signal */ + v = m_last_v; + h = HUC6260_HSYNC_START; + } + else if ( ( m_last_v == m_height - 4 || m_last_v == m_height - 1 ) && m_last_h < HUC6260_HSYNC_START + 30 ) + { + /* Next event is start/end of VSync signal */ + v = m_last_v; + h = HUC6260_HSYNC_START + 30; + } + else + { + /* Next event is end of HSync signal */ + v = ( m_last_v + 1 ) % m_height; + h = 0; + } + + /* Ask our slave device for time until next possible event */ + { + UINT16 next_event_clocks = m_time_til_next_event_cb( 0, 0xffff ); + int event_hpos, event_vpos; + + /* Adjust for pixel clocks per pixel */ + next_event_clocks *= m_pixels_per_clock; + + /* Adjust for clocks left to go for current pixel */ + next_event_clocks += ( m_pixels_per_clock - ( m_pixel_clock + 1 ) ); + + event_hpos = hpos + next_event_clocks; + event_vpos = vpos; + while ( event_hpos > HUC6260_WPF ) + { + event_vpos += 1; + event_hpos -= HUC6260_WPF; + } + + if ( event_vpos < v || ( event_vpos == v && event_hpos <= h ) ) + { + if ( event_vpos > vpos || ( event_vpos == vpos && event_hpos > hpos ) ) + { + v = event_vpos; + h = event_hpos; + } + } + } + + m_timer->adjust( m_screen->time_until_pos( v, h ) ); +} + + +void huc6260_device::video_update( bitmap_ind16 &bitmap, const rectangle &cliprect ) +{ + copybitmap( bitmap, *m_bmp, 0, 0, 0, 0, cliprect ); +} + + +// the battlera arcade board reads/writes the palette directly +READ8_MEMBER(huc6260_device::palette_direct_read) +{ + if (!(offset&1)) return m_palette[offset>>1]; + else return m_palette[offset >> 1] >> 8; +} + +WRITE8_MEMBER(huc6260_device::palette_direct_write) +{ + if (!(offset&1)) m_palette[offset>>1] = (m_palette[offset>>1] & 0xff00) | data; + else m_palette[offset>>1] = (m_palette[offset>>1] & 0x00ff) | (data<<8); +} + +READ8_MEMBER( huc6260_device::read ) +{ + UINT8 data = 0xFF; + + switch ( offset & 7 ) + { + case 0x04: /* Color table data LSB */ + data = m_palette[ m_address ] & 0xFF; + break; + + case 0x05: /* Color table data MSB */ + data = 0xFE | ( m_palette[ m_address ] >> 8 ); + + /* Increment internal address */ + m_address = ( m_address + 1 ) & 0x1FF; + break; + } + + return data; +} + + +WRITE8_MEMBER( huc6260_device::write ) +{ + switch ( offset & 7 ) + { + case 0x00: /* Control register */ + m_greyscales = data & 0x80; + m_blur = data & 0x04; + m_pixels_per_clock = ( data & 0x02 ) ? 2 : ( ( data & 0x01 ) ? 3 : 4 ); + break; + + case 0x02: /* Color table address LSB */ + m_address = ( ( m_address & 0xFF00 ) | data ) & 0x1FF; + break; + + case 0x03: /* Color table address MSB */ + m_address = ( ( m_address & 0x00FF ) | ( data << 8 ) ) & 0x1FF; + break; + + case 0x04: /* Color table data LSB */ + m_palette[ m_address ] = ( ( m_palette[ m_address ] & 0xFF00 ) | data ) & 0x1FF; + break; + + case 0x05: /* Color table data MSB */ + m_palette[ m_address ] = ( ( m_palette[ m_address ] & 0x00FF ) | ( data << 8 ) ) & 0x1FF; + + /* Increment internal address */ + m_address = ( m_address + 1 ) & 0x1FF; + break; + } +} + + +void huc6260_device::device_start() +{ + m_timer = timer_alloc(); + m_bmp = auto_bitmap_ind16_alloc( machine(), HUC6260_WPF, HUC6260_LPF ); + + /* Resolve callbacks */ + m_hsync_changed_cb.resolve(); + m_vsync_changed_cb.resolve(); + m_next_pixel_data_cb.resolve(); + m_time_til_next_event_cb.resolve(); + + /* We want to have a valid screen and valid callbacks */ + assert( ! m_hsync_changed_cb.isnull() ); + assert( ! m_vsync_changed_cb.isnull() ); + assert( ! m_next_pixel_data_cb.isnull() ); + assert( ! m_time_til_next_event_cb.isnull() ); + + save_item(NAME(m_last_h)); + save_item(NAME(m_last_v)); + save_item(NAME(m_height)); + save_item(NAME(m_palette)); + save_item(NAME(m_address)); + save_item(NAME(m_greyscales)); + save_item(NAME(m_blur)); + save_item(NAME(m_pixels_per_clock)); + save_item(NAME(m_pixel_data)); + save_item(NAME(m_pixel_clock)); +} + + +void huc6260_device::device_reset() +{ + m_address = 0; + m_greyscales = 0; + m_blur = 0; + m_pixels_per_clock = 4; + m_height = 263; + m_pixel_clock = 0; + memset(m_palette, 0x00, sizeof(m_palette)); + + m_last_v = m_screen->vpos(); + m_last_h = m_screen->hpos(); + m_timer->adjust( m_screen->time_until_pos( ( m_screen->vpos() + 1 ) % 263, 0 ) ); +} + +static MACHINE_CONFIG_FRAGMENT( huc6260 ) + MCFG_PALETTE_ADD("palette", HUC6260_PALETTE_SIZE ) + MCFG_PALETTE_INIT_OWNER(huc6260_device, huc6260) +MACHINE_CONFIG_END + +//------------------------------------------------- +// machine_config_additions - return a pointer to +// the device's machine fragment +//------------------------------------------------- + +machine_config_constructor huc6260_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( huc6260 ); +} diff --git a/src/devices/video/huc6260.h b/src/devices/video/huc6260.h new file mode 100644 index 00000000000..2ff38ccf131 --- /dev/null +++ b/src/devices/video/huc6260.h @@ -0,0 +1,98 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +/********************************************************************** + + Hudson/NEC HuC6260 interface and definitions + +**********************************************************************/ + + +#ifndef __HUC6260_H_ +#define __HUC6260_H_ + +#include "emu.h" + + +#define HUC6260_PALETTE_SIZE 1024 + +/* Screen timing stuff */ +#define HUC6260_WPF 1365 /* width of a line in frame including blanking areas */ +#define HUC6260_LPF 263 /* max number of lines in a single frame */ + + +#define MCFG_HUC6260_NEXT_PIXEL_DATA_CB(_devcb) \ + devcb = &huc6260_device::set_next_pixel_data_callback(*device, DEVCB_##_devcb); + +#define MCFG_HUC6260_TIME_TIL_NEXT_EVENT_CB(_devcb) \ + devcb = &huc6260_device::set_time_til_next_event_callback(*device, DEVCB_##_devcb); + +#define MCFG_HUC6260_VSYNC_CHANGED_CB(_devcb) \ + devcb = &huc6260_device::set_vsync_changed_callback(*device, DEVCB_##_devcb); + +#define MCFG_HUC6260_HSYNC_CHANGED_CB(_devcb) \ + devcb = &huc6260_device::set_hsync_changed_callback(*device, DEVCB_##_devcb); + + +class huc6260_device : public device_t, + public device_video_interface +{ +public: + // construction/destruction + huc6260_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + template static devcb_base &set_next_pixel_data_callback(device_t &device, _Object object) { return downcast(device).m_next_pixel_data_cb.set_callback(object); } + template static devcb_base &set_time_til_next_event_callback(device_t &device, _Object object) { return downcast(device).m_time_til_next_event_cb.set_callback(object); } + template static devcb_base &set_vsync_changed_callback(device_t &device, _Object object) { return downcast(device).m_vsync_changed_cb.set_callback(object); } + template static devcb_base &set_hsync_changed_callback(device_t &device, _Object object) { return downcast(device).m_hsync_changed_cb.set_callback(object); } + + void video_update(bitmap_ind16 &bitmap, const rectangle &cliprect); + DECLARE_READ8_MEMBER( read ); + DECLARE_WRITE8_MEMBER( write ); + DECLARE_PALETTE_INIT(huc6260); + + READ8_MEMBER(palette_direct_read); + WRITE8_MEMBER(palette_direct_write); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + virtual machine_config_constructor device_mconfig_additions() const; + +private: + int m_last_h; + int m_last_v; + int m_height; + + /* callbacks */ + /* Callback function to retrieve pixel data */ + devcb_read16 m_next_pixel_data_cb; + + /* TODO: Choose proper types */ + /* Callback function to get time until next event */ + devcb_read16 m_time_til_next_event_cb; + + /* Callback function which gets called when vsync changes */ + devcb_write_line m_vsync_changed_cb; + + /* Callback function which gets called when hsync changes */ + devcb_write_line m_hsync_changed_cb; + + UINT16 m_palette[512]; + UINT16 m_address; + UINT8 m_greyscales; /* Should the HuC6260 output grey or color graphics */ + UINT8 m_blur; /* Should the edges of graphics be blurred/Select screen height 0=262, 1=263 */ + UINT8 m_pixels_per_clock; /* Number of pixels to output per colour clock */ + UINT16 m_pixel_data; + UINT8 m_pixel_clock; + + emu_timer *m_timer; + bitmap_ind16 *m_bmp; +}; + + +extern const device_type HUC6260; + + +#endif diff --git a/src/devices/video/huc6261.c b/src/devices/video/huc6261.c new file mode 100644 index 00000000000..f22bdfba582 --- /dev/null +++ b/src/devices/video/huc6261.c @@ -0,0 +1,434 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +/********************************************************************** + + Hudson/NEC HuC6261 Video Colour Encoder + + The HuC6261 generates the tv control signals. A full line lasts + 1365 "master" cycles (typically at 21.47727Mhz). + + HSync is low for 237 and high for 1128 master cycles. + VSync is low for 4095 master cycles (3 lines). + VSync changes 30 master cycles after HSync would go low. + +**********************************************************************/ + +#include "emu.h" +#include "huc6261.h" + +#define LOG 0 + +#define HUC6261_HSYNC_LENGTH 237 +#define HUC6261_HSYNC_START ( HUC6261_WPF - HUC6261_HSYNC_LENGTH ) + + +const device_type HUC6261 = &device_creator; + + +huc6261_device::huc6261_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, HUC6261, "HuC6261", tag, owner, clock, "huc6261", __FILE__), + device_video_interface(mconfig, *this) +{ + // Set up UV lookup table + for ( int ur = 0; ur < 256; ur++ ) + { + for ( int vr = 0; vr < 256; vr++ ) + { + INT32 r,g,b; + INT32 u = ur - 128; + INT32 v = vr - 128; + + r = - 1.13983 * v; + g = -0.35465 * u - 0.58060 * v; + b = 2.03211 * u; + + m_uv_lookup[ ( ur << 8 ) | vr ][0] = r; + m_uv_lookup[ ( ur << 8 ) | vr ][1] = g; + m_uv_lookup[ ( ur << 8 ) | vr ][2] = b; + } + } +} + + +inline UINT32 huc6261_device::yuv2rgb(UINT32 yuv) +{ + INT32 r, g, b; + UINT8 y = yuv >> 16; + UINT16 uv = yuv & 0xffff; + + r = y + m_uv_lookup[uv][0]; + g = y + m_uv_lookup[uv][1]; + b = y + m_uv_lookup[uv][2]; + + if ( r < 0 ) r = 0; + if ( g < 0 ) g = 0; + if ( b < 0 ) b = 0; + if ( r > 255 ) r = 255; + if ( g > 255 ) g = 255; + if ( b > 255 ) b = 255; + + return ( r << 16 ) | ( g << 8 ) | b; +} + +void huc6261_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + int vpos = m_screen->vpos(); + int hpos = m_screen->hpos(); + int h = m_last_h; + int v = m_last_v; + UINT32 *bitmap_line = &m_bmp->pix32(v); + + while ( h != hpos || v != vpos ) + { + if ( m_pixel_clock == 0 ) + { + g_profiler.start( PROFILER_VIDEO ); + /* Get next pixel information */ + m_pixel_data = m_huc6270_b->next_pixel( machine().driver_data()->generic_space(), 0, 0xffff ); + g_profiler.stop(); + } + + bitmap_line[ h ] = yuv2rgb( ( ( m_palette[m_pixel_data] & 0xff00 ) << 8 ) | ( ( m_palette[m_pixel_data] & 0xf0 ) << 8 ) | ( ( m_palette[m_pixel_data] & 0x0f ) << 4 ) ); + m_pixel_clock = ( m_pixel_clock + 1 ) % m_pixels_per_clock; + h = ( h + 1 ) % HUC6261_WPF; + + switch( h ) + { + case HUC6261_HSYNC_START: /* Start of HSync */ + m_huc6270_a->hsync_changed( 0 ); + m_huc6270_b->hsync_changed( 0 ); +// if ( v == 0 ) +// { +// /* Check if the screen should be resized */ +// m_height = HUC6261_LPF - ( m_blur ? 1 : 0 ); +// if ( m_height != video_screen_get_height( m_screen ) ) +// { +// rectangle visible_area; +// +// /* TODO: Set proper visible area parameters */ +// visible_area.min_x = 64; +// visible_area.min_y = 18; +// visible_area.max_x = 64 + 1024 + 64 - 1; +// visible_area.max_y = 18 + 242 - 1; +// +// video_screen_configure( m_screen, HUC6261_WPF, m_height, &visible_area, HZ_TO_ATTOSECONDS( device->clock / ( HUC6261_WPF * m_height ) ) ); +// } +// } + break; + + case 0: /* End of HSync */ + m_huc6270_a->hsync_changed( 1 ); + m_huc6270_b->hsync_changed( 1 ); + m_pixel_clock = 0; + v = ( v + 1 ) % m_height; + bitmap_line = &m_bmp->pix32(v); + break; + + case HUC6261_HSYNC_START + 30: /* End/Start of VSync */ + if ( v>= m_height - 4 ) + { + int vsync = ( v >= m_height - 4 && v < m_height - 1 ) ? 0 : 1; + + m_huc6270_a->vsync_changed( vsync ); + m_huc6270_b->vsync_changed( vsync ); + } + break; + } + } + + m_last_h = h; + m_last_v = v; + + /* Reschedule timer */ + if ( m_last_h < HUC6261_HSYNC_START ) + { + /* Next event is start of HSync signal */ + v = m_last_v; + h = HUC6261_HSYNC_START; + } + else if ( ( m_last_v == m_height - 4 || m_last_v == m_height - 1 ) && m_last_h < HUC6261_HSYNC_START + 30 ) + { + /* Next event is start/end of VSync signal */ + v = m_last_v; + h = HUC6261_HSYNC_START + 30; + } + else + { + /* Next event is end of HSync signal */ + v = ( m_last_v + 1 ) % m_height; + h = 0; + } + + /* Ask our slave device for time until next possible event */ + { + UINT16 next_event_clocks = HUC6261_WPF; //m_get_time_til_next_event( 0, 0xffff ); + int event_hpos, event_vpos; + + /* Adjust for pixel clocks per pixel */ + next_event_clocks *= m_pixels_per_clock; + + /* Adjust for clocks left to go for current pixel */ + next_event_clocks += ( m_pixels_per_clock - ( m_pixel_clock + 1 ) ); + + event_hpos = hpos + next_event_clocks; + event_vpos = vpos; + while ( event_hpos > HUC6261_WPF ) + { + event_vpos += 1; + event_hpos -= HUC6261_WPF; + } + + if ( event_vpos < v || ( event_vpos == v && event_hpos <= h ) ) + { + if ( event_vpos > vpos || ( event_vpos == vpos && event_hpos > hpos ) ) + { + v = event_vpos; + h = event_hpos; + } + } + } + + m_timer->adjust( m_screen->time_until_pos( v, h ) ); +} + + +void huc6261_device::video_update( bitmap_rgb32 &bitmap, const rectangle &cliprect ) +{ + copybitmap( bitmap, *m_bmp, 0, 0, 0, 0, cliprect ); +} + + +READ16_MEMBER( huc6261_device::read ) +{ + UINT16 data = 0xFFFF; + + switch ( offset & 1 ) + { + /* Status info */ + case 0x00: + { + UINT16 vpos = m_screen->vpos(); + UINT16 hpos = m_screen->hpos(); + + data = ( vpos << 5 ) | ( m_register & 0x1F); + + if ( vpos >= 22 && vpos < 262 && hpos < HUC6261_HSYNC_START ) + { + data |= 0x8000; + } + } + break; + + /* Register contents(?) */ + case 0x01: + switch( m_register ) + { + case 0x00: + data = m_control; + break; + + case 0x01: + data = m_address; + break; + + case 0x02: + case 0x03: + data = m_palette_latch; + m_address = ( m_address + 1 ) & 0x1FF; + m_palette_latch = m_palette[ m_address ]; + break; + + case 0x08: + data = m_priority[4] | ( m_priority[5] << 4 ) | ( m_priority[6] << 8 ); + break; + + case 0x09: + data = m_priority[0] | ( m_priority[1] << 4 ) | ( m_priority[2] << 8 ) | ( m_priority[3] << 12 );; + break; + } + break; + } + + return data; +} + + +WRITE16_MEMBER( huc6261_device::write ) +{ + switch ( offset & 1 ) + { + /* Register */ + case 0x00: + m_register = data; + break; + + case 0x01: + logerror("huc6261: writing 0x%04x to register 0x%02x\n", data, m_register ); + switch( m_register ) + { + /* Control register */ + // -x-------------- Enable HuC6271: 0 - disabled, 1 - enabled + // --x------------- Enable HuC6272 BG3: 0 - disabled, 1 - enabled + // ---x------------ Enable HuC6272 BG2: 0 - disabled, 1 - enabled + // ----x----------- Enable Huc6272 BG1: 0 - disabled, 1 - enabled + // -----x---------- Enable HuC6272 BG0: 0 - disabled, 1 - enabled + // ------x--------- Enable HuC6270 SPR: 0 - disabled, 1 - enabled + // -------x-------- Enable HuC6270 BG: 0 - disabled, 1 - enabled + // --------x------- Number of SPR colors?: 0 - 16, 1 - 256 + // ---------x------ Number of BG colors?: 0 - 16, 1 - 256 + // ------------x--- Dot clock: 0 - 5MHz, 1 - 7MHz + // -------------x-- Synchronization: 0 - internal, 1 - external + // --------------xx Screen height: 00 - 262 lines, 01 - 263 lines, 10 - interlace, 11 - unknown/undefined + case 0x00: + m_control = data; + m_pixels_per_clock = ( data & 0x04 ) ? 3 : 4; + break; + + // Palette address + case 0x01: + m_address = data & 0x1FF; + m_palette_latch = m_palette[ m_address ]; + break; + + // Palette data + case 0x02: + m_palette_latch = data; + m_palette[ m_address ] = m_palette_latch; + m_address = ( m_address + 1 ) & 0x1FF; + break; + + // Palette offset 0 + case 0x04: + break; + + // Palette offset 1 + case 0x05: + break; + + // Palette offset 2 + case 0x06: + break; + + // Palette offset 3 + case 0x07: + break; + + // Priority 0 + // -----xxx-------- HuC6271 Rainbow priority + // ---------xxx---- HuC6270 SPR priority + // -------------xxx HuC6270 BG priority + case 0x08: + m_priority[4] = ( data >> 0 ) & 0x07; + m_priority[5] = ( data >> 4 ) & 0x07; + m_priority[6] = ( data >> 8 ) & 0x07; + break; + + // Priority 1 + // -xxx------------ HuC6272 BG3 priority + // -----xxx-------- HuC6272 BG2 priority + // ---------xxx---- HuC6272 BG1 priority + // -------------xxx HuC6272 BG0 priority + case 0x09: + m_priority[0] = ( data >> 0 ) & 0x07; + m_priority[1] = ( data >> 4 ) & 0x07; + m_priority[2] = ( data >> 8 ) & 0x07; + m_priority[3] = ( data >> 12 ) & 0x07; + break; + + // Chroma key Y + case 0x0A: + break; + + // Chroma key U + case 0x0B: + break; + + // Chroma key V + case 0x0C: + break; + + // + case 0x0D: + break; + + // + case 0x0E: + break; + + // + case 0x0F: + break; + + // + case 0x10: + break; + + // + case 0x11: + break; + + // + case 0x12: + break; + + // + case 0x13: + break; + + // + case 0x14: + break; + + // + case 0x15: + break; + } + break; + } +} + + +void huc6261_device::device_start() +{ + /* Make sure we are supplied all our mandatory tags */ + assert( m_huc6270_a_tag != NULL ); + assert( m_huc6270_b_tag != NULL ); + + m_timer = timer_alloc(); + m_huc6270_a = machine().device(m_huc6270_a_tag); + m_huc6270_b = machine().device(m_huc6270_b_tag); + + m_bmp = auto_bitmap_rgb32_alloc( machine(), HUC6261_WPF, HUC6261_LPF ); + + /* We want to have valid devices */ + assert( m_huc6270_a != NULL ); + assert( m_huc6270_b != NULL ); + + save_item(NAME(m_last_h)); + save_item(NAME(m_last_v)); + save_item(NAME(m_height)); + save_item(NAME(m_palette)); + save_item(NAME(m_palette_latch)); + save_item(NAME(m_address)); + save_item(NAME(m_register)); + save_item(NAME(m_control)); + save_item(NAME(m_priority)); + save_item(NAME(m_pixels_per_clock)); + save_item(NAME(m_pixel_data)); + save_item(NAME(m_pixel_clock)); +} + + +void huc6261_device::device_reset() +{ + m_register = 0; + m_pixels_per_clock = 4; + m_height = 263; + m_pixel_clock = 0; + + memset(m_palette, 0, sizeof(m_palette)); + + m_last_v = m_screen->vpos(); + m_last_h = m_screen->hpos(); + m_timer->adjust( m_screen->time_until_pos( ( m_screen->vpos() + 1 ) % 263, 0 ) ); +} diff --git a/src/devices/video/huc6261.h b/src/devices/video/huc6261.h new file mode 100644 index 00000000000..e5ef43a8429 --- /dev/null +++ b/src/devices/video/huc6261.h @@ -0,0 +1,81 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +/********************************************************************** + + Hudson/NEC HuC6261 interface and definitions + +**********************************************************************/ + + +#ifndef __HUC6261_H_ +#define __HUC6261_H_ + +#include "emu.h" +#include "video/huc6270.h" + + +/* Screen timing stuff */ +#define HUC6261_WPF 1365 /* width of a line in frame including blanking areas */ +#define HUC6261_LPF 263 /* max number of lines in a single frame */ + + +#define MCFG_HUC6261_VDC1(_tag) \ + huc6261_device::set_vdc1_tag(*device, _tag); + +#define MCFG_HUC6261_VDC2(_tag) \ + huc6261_device::set_vdc2_tag(*device, _tag); + + +class huc6261_device : public device_t, + public device_video_interface +{ +public: + // construction/destruction + huc6261_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + static void set_vdc1_tag(device_t &device, const char *tag) { downcast(device).m_huc6270_a_tag = tag; } + static void set_vdc2_tag(device_t &device, const char *tag) { downcast(device).m_huc6270_b_tag = tag; } + + void video_update(bitmap_rgb32 &bitmap, const rectangle &cliprect); + DECLARE_READ16_MEMBER( read ); + DECLARE_WRITE16_MEMBER( write ); + + inline UINT32 yuv2rgb(UINT32 yuv); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + +private: + const char *m_huc6270_a_tag; + const char *m_huc6270_b_tag; + + huc6270_device *m_huc6270_a; + huc6270_device *m_huc6270_b; + int m_last_h; + int m_last_v; + int m_height; + + UINT16 m_palette[512]; + UINT16 m_address; + UINT16 m_palette_latch; + UINT16 m_register; + UINT16 m_control; + UINT8 m_priority[7]; + + UINT8 m_pixels_per_clock; /* Number of pixels to output per colour clock */ + UINT16 m_pixel_data; + UINT8 m_pixel_clock; + + emu_timer *m_timer; + bitmap_rgb32 *m_bmp; + INT32 m_uv_lookup[65536][3]; +}; + + +extern const device_type HUC6261; + + +#endif diff --git a/src/devices/video/huc6270.c b/src/devices/video/huc6270.c new file mode 100644 index 00000000000..c0fe5225c8e --- /dev/null +++ b/src/devices/video/huc6270.c @@ -0,0 +1,895 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +/********************************************************************** + + NEC HuC6270 Video Display Controller + + The HuC6270 basically outputs a 9-bit stream of pixel data which + holds a color index, a palette index, and an indication whether + the pixel contains background data or from sprite data. + + This data can be used by a colour encoder to output graphics. + + A regular screen is displayed as follows: + + |<- HDS ->|<-- HDW -->|<- HDE ->|<- HSW ->| + |---------|-----------------------|---------|---------| + VSW | | + |---------|-----------------------|---------|---------| + VDS | | + | overscan | + |---------|-----------------------|---------|---------| + | | | | + | | | | + | | | | + | | | | + VDW | overscan| active display | overscan | + | | | | + | | | | + | | | | + | | | | + |---------|-----------------------|---------|---------| + VCR | overscan | + | | + |---------|-----------------------|---------|---------| + ^end hsync + ^start vsync (30 cycles after hsync) + + +KNOWN ISSUES + - Violent Soldier (probably connected): + - In the intro some artefacts appear at the top of the + screen every now and then. + - In ccovell's splitres test not all sections seem to be aligned properly. + - Side Arms: Seems to be totally broken. + + +TODO + - Fix timing of VRAM-SATB DMA + - Implement VRAM-VRAM DMA + - DMA speeds differ depending on the dot clock selected in the huc6270 + +**********************************************************************/ + +#include "emu.h" +#include "huc6270.h" + +#define LOG 0 + +enum { + MAWR = 0x00, + MARR = 0x01, + VxR = 0x02, + CR = 0x05, + RCR = 0x06, + BXR = 0x07, + BYR = 0x08, + MWR = 0x09, + HSR = 0x0A, + HDR = 0x0B, + VPR = 0x0C, + VDW = 0x0D, + VCR = 0x0E, + DCR = 0x0F, + SOUR = 0x10, + DESR = 0x11, + LENR = 0x12, + DVSSR = 0x13 +}; + +ALLOW_SAVE_TYPE(huc6270_device::huc6270_v_state); +ALLOW_SAVE_TYPE(huc6270_device::huc6270_h_state); + + +/* Bits in the VDC status register */ +#define HUC6270_BSY 0x40 /* Set when the VDC accesses VRAM */ +#define HUC6270_VD 0x20 /* Set when in the vertical blanking period */ +#define HUC6270_DV 0x10 /* Set when a VRAM > VRAM DMA transfer is done */ +#define HUC6270_DS 0x08 /* Set when a VRAM > SATB DMA transfer is done */ +#define HUC6270_RR 0x04 /* Set when the current scanline equals the RCR register */ +#define HUC6270_OR 0x02 /* Set when there are more than 16 sprites on a line */ +#define HUC6270_CR 0x01 /* Set when sprite #0 overlaps with another sprite */ + + +const device_type HUC6270 = &device_creator; + + +const UINT8 huc6270_device::vram_increments[4] = { 1, 32, 64, 128 }; + +huc6270_device::huc6270_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, HUC6270, "HuC6270 VDC", tag, owner, clock, "huc6270", __FILE__), + m_vram_size(0), + m_irq_changed_cb(*this) +{ +} + + +/* + Read one row of tile data from video ram +*/ +inline void huc6270_device::fetch_bat_tile_row() +{ + UINT16 bat_data, data1, data2, data3, data4, tile_palette; + int i; + + bat_data = m_vram[ m_bat_address & m_vram_mask ]; + tile_palette = ( bat_data >> 8 ) & 0xF0; + data1 = m_vram[ ( ( ( bat_data & 0x0FFF ) << 4 ) + m_bat_row + 0 ) & m_vram_mask ]; + data2 = ( data1 >> 7 ) & 0x1FE; + data3 = m_vram[ ( ( ( bat_data & 0x0FFF ) << 4 ) + m_bat_row + 8 ) & m_vram_mask ]; + data4 = ( data3 >> 5 ) & 0x7F8; + data3 <<= 2; + + for ( i = 7; i >= 0; i-- ) + { + UINT16 c = ( data1 & 0x01 ) | ( data2 & 0x02 ) | ( data3 & 0x04 ) | ( data4 & 0x08 ); + + /* Colour 0 for background tiles is always taken from palette 0 */ + if ( c ) + c |= tile_palette; + + m_bat_tile_row[i] = c; + + data1 >>= 1; + data2 >>= 1; + data3 >>= 1; + data4 >>= 1; + } +} + + +void huc6270_device::add_sprite( int index, int x, int pattern, int line, int flip_x, int palette, int priority, int sat_lsb ) +{ + int i = m_sprites_this_line; + + if ( i < 16 ) + { + UINT32 b0, b1, b2, b3; + int j; + + if ( flip_x ) + flip_x = 0x0F; + + pattern += ( ( line >> 4 ) << 1 ); + + if ( ( m_mwr & 0x0c ) == 0x04 ) + { + if ( ! sat_lsb ) + { + b0 = m_vram[ ( ( pattern * 0x40 ) + ( line & 0x0F ) + 0x00 ) & m_vram_mask ]; + b1 = m_vram[ ( ( pattern * 0x40 ) + ( line & 0x0F ) + 0x10 ) & m_vram_mask ] << 1; + } + else + { + b0 = m_vram[ ( ( pattern * 0x40 ) + ( line & 0x0F ) + 0x20 ) & m_vram_mask ]; + b1 = m_vram[ ( ( pattern * 0x40 ) + ( line & 0x0F ) + 0x30 ) & m_vram_mask ] << 1; + } + b2 = 0; + b3 = 0; + } + else + { + b0 = m_vram[ ( ( pattern * 0x40 ) + ( line & 0x0F ) + 0x00 ) & m_vram_mask ]; + b1 = m_vram[ ( ( pattern * 0x40 ) + ( line & 0x0F ) + 0x10 ) & m_vram_mask ] << 1; + b2 = m_vram[ ( ( pattern * 0x40 ) + ( line & 0x0F ) + 0x20 ) & m_vram_mask ] << 2; + b3 = m_vram[ ( ( pattern * 0x40 ) + ( line & 0x0F ) + 0x30 ) & m_vram_mask ] << 3; + } + + for ( j = 15; j >= 0; j-- ) + { + UINT8 data = ( b3 & 0x08 ) | ( b2 & 0x04 ) | ( b1 & 0x02 ) | ( b0 & 0x01 ); + + if ( data ) + { + data |= palette << 4; + + if ( x + ( j ^ flip_x ) < 1024 ) + { + if (! m_sprite_row[ x + ( j ^ flip_x ) ] ) + { + m_sprite_row[ x + ( j ^ flip_x ) ] = ( priority ? 0x4000 : 0x0000 ) | ( index << 8 ) | data; + } + else + { + if ( ! ( m_sprite_row[ x + ( j ^ flip_x ) ] & 0xFF00 ) ) + { + /* Sprite 0 collission */ + m_sprite_row[ x + ( j ^ flip_x ) ] |= 0x8000; + } + } + } + } + + b0 >>= 1; + b1 >>= 1; + b2 >>= 1; + b3 >>= 1; + } + + m_sprites_this_line += 1; + } +} + + +void huc6270_device::select_sprites() +{ + int i; + + m_sprites_this_line = 0; + memset( m_sprite_row, 0, sizeof( m_sprite_row ) ); + m_sprite_row_index = 0x20; + + for ( i = 0; i < 4 * 64; i += 4 ) + { + static const int cgy_table[4] = { 16, 32, 64, 64 }; + int cgy = ( m_sat[i+3] >> 12 ) & 0x03; + int height = cgy_table[ cgy ]; + int sprite_line = m_raster_count - m_sat[i]; + + if ( sprite_line >= 0 && sprite_line < height ) + { + int pattern = m_sat[i+2] >> 1; + int sat_lsb = m_sat[i+2] & 0x01; + int palette = m_sat[i+3] & 0x0F; + int priority = m_sat[i+3] & 0x80; + int cgx = m_sat[i+3] & 0x0100; + + /* If CGY is set to 1, bit 1 of the sprite pattern index is forced to 0 */ + if ( cgy & 1 ) + pattern &= ~0x0002; + + /* If CGY is set to 2 or 3, bits 1 and 2 of the sprite pattern index are forced to 0 */ + if ( cgy & 2 ) + pattern &= ~0x0006; + + /* Recalculate line index when sprite is flipped vertically */ + if ( m_sat[i+3] & 0x8000 ) + sprite_line = ( height - 1 ) - sprite_line; + + /* Is the sprite 32 pixels wide */ + if ( cgx ) + { + /* If CGX is set, bit 0 of the sprite pattern index is forced to 0 */ + pattern &= ~0x0001; + + /* Check for horizontal flip */ + if ( m_sat[i+3] & 0x0800 ) + { + /* Add to our list of sprites for this line */ + add_sprite( i/4, m_sat[i+1], pattern + 1, sprite_line, 1, palette, priority, sat_lsb ); + add_sprite( i/4, m_sat[i+1] + 16, pattern, sprite_line, 1, palette, priority, sat_lsb ); + } + else + { + /* Add to our list of sprites for this line */ + add_sprite( i/4, m_sat[i+1], pattern, sprite_line, 0, palette, priority, sat_lsb ); + add_sprite( i/4, m_sat[i+1] + 16, pattern + 1, sprite_line, 0, palette, priority, sat_lsb ); + } + } + else + { + /* Add to our list of sprites for this line */ + add_sprite( i/4, m_sat[i+1], pattern, sprite_line, m_sat[i+3] & 0x0800, palette, priority, sat_lsb ); + } + } + } + + /* Check for sprite overflow */ + if ( m_sprites_this_line >= 16 ) + { + /* note: flag is set only if irq is taken, Mizubaku Daibouken relies on this behaviour */ + if ( m_cr & 0x02 ) + { + m_status |= HUC6270_OR; + m_irq_changed_cb( ASSERT_LINE ); + } + } +} + + +inline void huc6270_device::handle_vblank() +{ + if ( ! m_vd_triggered ) + { + if ( m_cr & 0x08 ) + { + m_status |= HUC6270_VD; + m_irq_changed_cb( ASSERT_LINE ); + } + + /* Should we initiate a VRAM->SATB DMA transfer. + The timing for this is incorrect. + */ + if ( m_dvssr_written || ( m_dcr & 0x10 ) ) + { + int i; + + if (LOG) logerror("SATB transfer from %05x\n", m_dvssr << 1 ); + for ( i = 0; i < 4 * 64; i += 4 ) + { + m_sat[i + 0] = m_vram[ ( m_dvssr + i + 0 ) & m_vram_mask ] & 0x03FF; + m_sat[i + 1] = m_vram[ ( m_dvssr + i + 1 ) & m_vram_mask ] & 0x03FF; + m_sat[i + 2] = m_vram[ ( m_dvssr + i + 2 ) & m_vram_mask ] & 0x07FF; + m_sat[i + 3] = m_vram[ ( m_dvssr + i + 3 ) & m_vram_mask ]; + } + m_dvssr_written = 0; + + /* Generate SATB interrupt if requested */ + if ( m_dcr & 0x01 ) + { + m_satb_countdown = 4; +// m_status |= HUC6270_DS; +// m_irq_changed_cb( ASSERT_LINE ); + } + } + + m_vd_triggered = 1; + } +} + + +inline void huc6270_device::next_vert_state() +{ + switch ( m_vert_state ) + { + case HUC6270_VSW: + m_vert_state = HUC6270_VDS; + m_vert_to_go = ( ( m_vpr >> 8 ) & 0xFF ) + 2; + break; + + case HUC6270_VDS: + m_vert_state = HUC6270_VDW; + m_vert_to_go = ( m_vdw & 0x1FF ) + 1; + m_byr_latched = m_byr; + m_vd_triggered = 0; + break; + + case HUC6270_VDW: + m_vert_state = HUC6270_VCR; + m_vert_to_go = ( m_vcr & 0xFF ); + handle_vblank(); + break; + + case HUC6270_VCR: + m_vert_state = HUC6270_VSW; + m_vert_to_go = ( m_vpr & 0x1F ) + 1; + break; + } +} + + +inline void huc6270_device::next_horz_state() +{ + switch ( m_horz_state ) + { + case HUC6270_HDS: + m_bxr_latched = m_bxr; +//if (LOG) printf("latched bxr vpos=%d, hpos=%d\n", video_screen_get_vpos(device->machine->first_screen()), video_screen_get_hpos(device->machine->first_screen())); + m_horz_state = HUC6270_HDW; + m_horz_to_go = ( m_hdr & 0x7F ) + 1; + { + static const int width_shift[4] = { 5, 6, 7, 7 }; + UINT16 v; + + v = ( m_byr_latched ) & ( ( m_mwr & 0x40 ) ? 0x1FF : 0xFF ); + m_bat_row = v & 7; + m_bat_address_mask = ( 1 << width_shift[ ( m_mwr >> 4 ) & 0x03 ] ) - 1; + m_bat_address = ( ( v >> 3 ) << ( width_shift[ ( m_mwr >> 4 ) & 0x03 ] ) ) + | ( ( m_bxr_latched >> 3 ) & m_bat_address_mask ); + m_bat_column = m_bxr & 7; + fetch_bat_tile_row(); + } + break; + + case HUC6270_HDW: + m_horz_state = HUC6270_HDE; + m_horz_to_go = ( ( m_hdr >> 8 ) & 0x7F ) + 1; + break; + + case HUC6270_HDE: + m_horz_state = HUC6270_HSW; + m_horz_to_go = ( m_hsr & 0x1F ) + 1; + break; + + case HUC6270_HSW: + m_horz_state = HUC6270_HDS; + m_horz_to_go = MAX( ( ( m_hsr >> 8 ) & 0x7F ), 2 ) + 1; + + /* If section has ended, advance to next vertical state */ + while ( m_vert_to_go == 0 ) + next_vert_state(); + + /* Select sprites for the coming line */ + select_sprites(); + break; + } + m_horz_steps = 0; +} + + +READ16_MEMBER( huc6270_device::next_pixel ) +{ + UINT16 data = HUC6270_SPRITE; + + /* Check if we're on an active display line */ + if ( m_vert_state == HUC6270_VDW ) + { + /* Check if we're in active display area */ + if ( m_horz_state == HUC6270_HDW ) + { + UINT8 sprite_data = m_sprite_row[ m_sprite_row_index ] & 0x00FF; + int collission = ( m_sprite_row[ m_sprite_row_index ] & 0x8000 ) ? 1 : 0; + + if ( m_cr & 0x80 ) + { + data = HUC6270_BACKGROUND | m_bat_tile_row[ m_bat_column ]; + if ( sprite_data && ( m_cr & 0x40 ) ) + { + if ( m_sprite_row[ m_sprite_row_index ] & 0x4000 ) + { + data = HUC6270_SPRITE | sprite_data; + } + else + { + if ( data == HUC6270_BACKGROUND ) + { + data = HUC6270_SPRITE | sprite_data; + } + } + } + } + else + { + if ( m_cr & 0x40 ) + { + data = HUC6270_SPRITE | sprite_data; + } + } + + m_sprite_row_index = m_sprite_row_index + 1; + m_bat_column += 1; + if ( m_bat_column >= 8 ) + { + m_bat_address = ( m_bat_address & ~m_bat_address_mask ) + | ( ( m_bat_address + 1 ) & m_bat_address_mask ); + m_bat_column = 0; + fetch_bat_tile_row(); + } + + if ( collission && ( m_cr & 0x01 ) ) + { + m_status |= HUC6270_CR; + m_irq_changed_cb( ASSERT_LINE ); + } + } + } + + m_horz_steps++; + if ( m_horz_steps == 8 ) + { + m_horz_to_go -= 1; + m_horz_steps = 0; + while ( m_horz_to_go == 0 ) + next_horz_state(); + } + return data; +} + + +//inline READ16_MEMBER( huc6270_device::time_until_next_event ) +//{ +// return m_horz_to_go * 8 + m_horz_steps; +//} + + +WRITE_LINE_MEMBER( huc6270_device::vsync_changed ) +{ + state &= 0x01; + if ( m_vsync != state ) + { + /* Check for low->high VSYNC transition */ + if ( state ) + { + m_vert_state = HUC6270_VCR; + m_vert_to_go = 0; + + while ( m_vert_to_go == 0 ) + next_vert_state(); + } + else + /* High->low transition */ + { + handle_vblank(); + + /* Should we perform VRAM-VRAM dma. + The timing for this is incorrect. + */ + if ( m_dma_enabled ) + { + int desr_inc = ( m_dcr & 0x0008 ) ? -1 : +1; + int sour_inc = ( m_dcr & 0x0004 ) ? -1 : +1; + + if (LOG) logerror("doing dma sour = %04x, desr = %04x, lenr = %04x\n", m_sour, m_desr, m_lenr ); + do { + UINT16 data = m_vram[ m_sour & m_vram_mask ]; + m_vram[ m_desr & m_vram_mask ] = data; + m_sour += sour_inc; + m_desr += desr_inc; + m_lenr -= 1; + } while ( m_lenr != 0xFFFF ); + + if ( m_dcr & 0x0002 ) + { + m_status |= HUC6270_DV; + m_irq_changed_cb( ASSERT_LINE ); + } + m_dma_enabled = 0; + } + } + } + + m_vsync = state; +} + + +WRITE_LINE_MEMBER( huc6270_device::hsync_changed ) +{ + state &= 0x01; + + /* Check for high->low HSYNC transition */ + /* Check for low->high HSYNC transition */ + if( ! m_hsync && state ) + { + if ( m_satb_countdown ) + { + m_satb_countdown--; + + if ( m_satb_countdown == 0 ) + { + m_status |= HUC6270_DS; + m_irq_changed_cb( ASSERT_LINE ); + } + } + + m_horz_state = HUC6270_HSW; + m_horz_to_go = 0; + m_horz_steps = 0; + m_byr_latched += 1; + m_raster_count += 1; + if ( m_vert_to_go == 1 && m_vert_state == HUC6270_VDS ) + { + m_raster_count = 0x40; + } + + m_vert_to_go -= 1; + + while ( m_horz_to_go == 0 ) + next_horz_state(); + + if ( m_raster_count == m_rcr && ( m_cr & 0x04 ) ) + { + m_status |= HUC6270_RR; + m_irq_changed_cb( ASSERT_LINE ); + } + } + + m_hsync = state; +} + + +READ8_MEMBER( huc6270_device::read ) +{ + UINT8 data = 0x00; + + switch ( offset & 3 ) + { + case 0x00: /* status */ + data = m_status; + m_status &= ~( HUC6270_VD | HUC6270_DV | HUC6270_RR | HUC6270_CR | HUC6270_OR | HUC6270_DS ); + m_irq_changed_cb( CLEAR_LINE ); + break; + + case 0x02: + data = m_vrr & 0xFF; + break; + + case 0x03: + data = m_vrr >> 8; + if ( m_register_index == VxR ) + { + m_marr += vram_increments[ ( m_cr >> 11 ) & 3 ]; + m_vrr = m_vram[ m_marr & m_vram_mask ]; + } + break; + } + return data; +} + + +WRITE8_MEMBER( huc6270_device::write ) +{ + if (LOG) logerror("%s: huc6270 write %02x <- %02x ", machine().describe_context(), offset, data); + + switch ( offset & 3 ) + { + case 0x00: /* VDC register select */ + m_register_index = data & 0x1F; + break; + + case 0x02: /* VDC data LSB */ + switch ( m_register_index ) + { + case MAWR: /* memory address write register LSB */ + m_mawr = ( m_mawr & 0xFF00 ) | data; + break; + + case MARR: /* memory address read register LSB */ + m_marr = ( m_marr & 0xFF00 ) | data; + m_vrr = m_vram[ m_marr & m_vram_mask ]; + break; + + case VxR: /* vram write data LSB */ + m_vwr = ( m_vwr & 0xFF00 ) | data; + break; + + case CR: /* control register LSB */ + m_cr = ( m_cr & 0xFF00 ) | data; + break; + + case RCR: /* raster compare register LSB */ + m_rcr = ( m_rcr & 0x0300 ) | data; +//printf("%s: RCR set to %03x\n", machine().describe_context(), m_rcr); +// if ( m_raster_count == m_rcr && m_cr & 0x04 ) +// { +// m_status |= HUC6270_RR; +// m_irq_changed_cb( ASSERT_LINE ); +// } +//if (LOG) printf("%04x: RCR (%03x) written at %d,%d\n", activecpu_get_pc(), huc6270->m_rcr, video_screen_get_vpos(device->machine->first_screen()), video_screen_get_hpos(device->machine->first_screen()) ); + break; + + case BXR: /* background x-scroll register LSB */ + m_bxr = ( m_bxr & 0x0300 ) | data; +//if (LOG) printf("*********************** BXR written %d at %d,%d\n", m_bxr, video_screen_get_vpos(device->machine->first_screen()), video_screen_get_hpos(device->machine->first_screen()) ); + break; + + case BYR: /* background y-scroll register LSB */ + m_byr = ( m_byr & 0x0100 ) | data; + m_byr_latched = m_byr; +//if (LOG) printf("******************** BYR written %d at %d,%d\n", huc6270->m_byr, video_screen_get_vpos(device->machine->first_screen()), video_screen_get_hpos(device->machine->first_screen()) ); + break; + + case MWR: /* memory width register LSB */ + m_mwr = ( m_mwr & 0xFF00 ) | data; + break; + + case HSR: /* horizontal sync register LSB */ + m_hsr = ( m_hsr & 0xFF00 ) | data; + break; + + case HDR: /* horizontal display register LSB */ + m_hdr = ( m_hdr & 0xFF00 ) | data; + break; + + case VPR: /* vertical sync register LSB */ + m_vpr = ( m_vpr & 0xFF00 ) | data; + break; + + case VDW: /* vertical display register LSB */ + m_vdw = ( m_vdw & 0xFF00 ) | data; + break; + + case VCR: /* vertical display end position register LSB */ + m_vcr = ( m_vcr & 0xFF00 ) | data; + break; + + case DCR: /* DMA control register LSB */ + m_dcr = ( m_dcr & 0xFF00 ) | data; + break; + + case SOUR: /* DMA source address register LSB */ + m_sour = ( m_sour & 0xFF00 ) | data; + break; + + case DESR: /* DMA destination address register LSB */ + m_desr = ( m_desr & 0xFF00 ) | data; + break; + + case LENR: /* DMA length register LSB */ + m_lenr = ( m_lenr & 0xFF00 ) | data; + break; + + case DVSSR: /* Sprite attribute table LSB */ + m_dvssr = ( m_dvssr & 0xFF00 ) | data; + m_dvssr_written = 1; + break; + } + break; + + case 0x03: /* VDC data MSB */ + switch ( m_register_index ) + { + case MAWR: /* memory address write register MSB */ + m_mawr = ( m_mawr & 0x00FF ) | ( data << 8 ); + break; + + case MARR: /* memory address read register MSB */ + m_marr = ( m_marr & 0x00FF ) | ( data << 8 ); + m_vrr = m_vram[ m_marr & m_vram_mask ]; + break; + + case VxR: /* vram write data MSB */ + m_vwr = ( m_vwr & 0x00FF ) | ( data << 8 ); + m_vram[ m_mawr & m_vram_mask ] = m_vwr; + m_mawr += vram_increments[ ( m_cr >> 11 ) & 3 ]; + break; + + case CR: /* control register MSB */ + m_cr = ( m_cr & 0x00FF ) | ( data << 8 ); + break; + + case RCR: /* raster compare register MSB */ + m_rcr = ( m_rcr & 0x00FF ) | ( ( data & 0x03 ) << 8 ); +//printf("%s: RCR set to %03x\n", machine().describe_context(), m_rcr); +// if ( m_raster_count == m_rcr && m_cr & 0x04 ) +// { +// m_status |= HUC6270_RR; +// m_irq_changed_cb( ASSERT_LINE ); +// } + break; + + case BXR: /* background x-scroll register MSB */ + m_bxr = ( m_bxr & 0x00FF ) | ( ( data & 0x03 ) << 8 ); + break; + + case BYR: /* background y-scroll register MSB */ + m_byr = ( m_byr & 0x00FF ) | ( ( data & 0x01 ) << 8 ); + m_byr_latched = m_byr; + break; + + case MWR: /* memory width register MSB */ + m_mwr = ( m_mwr & 0x00FF ) | ( data << 8 ); + break; + + case HSR: /* horizontal sync register MSB */ + m_hsr = ( m_hsr & 0x00FF ) | ( data << 8 ); + break; + + case HDR: /* horizontal display register MSB */ + m_hdr = ( m_hdr & 0x00FF ) | ( data << 8 ); + break; + + case VPR: /* vertical sync register MSB */ + m_vpr = ( m_vpr & 0x00FF ) | ( data << 8 ); + break; + + case VDW: /* vertical display register MSB */ + m_vdw = ( m_vdw & 0x00FF ) | ( data << 8 ); + break; + + case VCR: /* vertical display end position register MSB */ + m_vcr = ( m_vcr & 0x00FF ) | ( data << 8 ); + break; + + case DCR: /* DMA control register MSB */ + m_dcr = ( m_dcr & 0x00FF ) | ( data << 8 ); + break; + + case SOUR: /* DMA source address register MSB */ + m_sour = ( m_sour & 0x00FF ) | ( data << 8 ); + break; + + case DESR: /* DMA destination address register MSB */ + m_desr = ( m_desr & 0x00FF ) | ( data << 8 ); + break; + + case LENR: /* DMA length register MSB */ + m_lenr = ( m_lenr & 0x00FF ) | ( data << 8 ); + m_dma_enabled = 1; +//logerror("DMA is not supported yet.\n"); + break; + + case DVSSR: /* Sprite attribute table MSB */ + m_dvssr = ( m_dvssr & 0x00FF ) | ( data << 8 ); + m_dvssr_written = 1; + break; + } + break; + } + if (LOG) logerror("\n"); +} + + +void huc6270_device::device_start() +{ + /* Resolve callbacks */ + m_irq_changed_cb.resolve_safe(); + + m_vram = auto_alloc_array_clear(machine(), UINT16, m_vram_size/sizeof(UINT16)); + m_vram_mask = (m_vram_size >> 1) - 1; + + save_pointer(NAME(m_vram), m_vram_size/sizeof(UINT16)); + + save_item(NAME(m_register_index)); + save_item(NAME(m_mawr)); + save_item(NAME(m_marr)); + save_item(NAME(m_vrr)); + save_item(NAME(m_vwr)); + save_item(NAME(m_cr)); + save_item(NAME(m_rcr)); + save_item(NAME(m_bxr)); + save_item(NAME(m_byr)); + save_item(NAME(m_mwr)); + save_item(NAME(m_hsr)); + save_item(NAME(m_hdr)); + save_item(NAME(m_vpr)); + save_item(NAME(m_vdw)); + save_item(NAME(m_vcr)); + save_item(NAME(m_dcr)); + save_item(NAME(m_sour)); + save_item(NAME(m_desr)); + save_item(NAME(m_lenr)); + save_item(NAME(m_dvssr)); + save_item(NAME(m_status)); + save_item(NAME(m_hsync)); + save_item(NAME(m_vsync)); + save_item(NAME(m_vert_state)); + save_item(NAME(m_horz_state)); + save_item(NAME(m_vd_triggered)); + save_item(NAME(m_vert_to_go)); + save_item(NAME(m_horz_to_go)); + save_item(NAME(m_horz_steps)); + save_item(NAME(m_raster_count)); + save_item(NAME(m_dvssr_written)); + save_item(NAME(m_satb_countdown)); + save_item(NAME(m_dma_enabled)); + save_item(NAME(m_byr_latched)); + save_item(NAME(m_bxr_latched)); + save_item(NAME(m_bat_address)); + save_item(NAME(m_bat_address_mask)); + save_item(NAME(m_bat_row)); + save_item(NAME(m_bat_column)); + save_item(NAME(m_bat_tile_row)); + save_item(NAME(m_sat)); + save_item(NAME(m_sprites_this_line)); + save_item(NAME(m_sprite_row_index)); + save_item(NAME(m_sprite_row)); +} + + +void huc6270_device::device_reset() +{ + m_mawr = 0; + m_marr = 0; + m_vrr = 0; + m_vwr = 0; + m_cr = 0; + m_rcr = 0; + m_bxr = 0; + m_byr = 0; + m_mwr = 0; + m_hsr = 0x0202; /* Take some defaults for horizontal timing */ + m_hdr = 0x041f; + m_vpr = 0x0f02; /* Take some defaults for vertical timing */ + m_vdw = 0x00ef; + m_vcr = 0x0004; + m_dcr = 0; + m_sour = 0; + m_lenr = 0; + m_dvssr = 0; + m_status = 0; + m_vd_triggered = 0; + m_dvssr_written = 0; + m_satb_countdown = 0; + m_raster_count = 0x4000; + m_vert_to_go = 0; + m_vert_state = HUC6270_VSW; + m_horz_steps = 0; + m_horz_to_go = 0; + m_horz_state = HUC6270_HDS; + m_hsync = 0; + m_vsync = 0; + m_dma_enabled = 0; + m_byr_latched = 0; + + memset(m_sat, 0, sizeof(m_sat)); +} diff --git a/src/devices/video/huc6270.h b/src/devices/video/huc6270.h new file mode 100644 index 00000000000..017fe5c9e70 --- /dev/null +++ b/src/devices/video/huc6270.h @@ -0,0 +1,141 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +/********************************************************************** + + Hudson/NEC HuC6270 interface + +**********************************************************************/ + +#ifndef __HUC6270_H_ +#define __HUC6270_H_ + +#include "emu.h" + +#define MCFG_HUC6270_VRAM_SIZE(_size) \ + huc6270_device::set_vram_size(*device, _size); + +#define MCFG_HUC6270_IRQ_CHANGED_CB(_devcb) \ + devcb = &huc6270_device::set_irq_changed_callback(*device, DEVCB_##_devcb); + +class huc6270_device : public device_t +{ +public: + // construction/destruction + huc6270_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + static void set_vram_size(device_t &device, UINT32 vram_size) { downcast(device).m_vram_size = vram_size; } + template static devcb_base &set_irq_changed_callback(device_t &device, _Object object) { return downcast(device).m_irq_changed_cb.set_callback(object); } + + DECLARE_READ8_MEMBER( read ); + DECLARE_WRITE8_MEMBER( write ); + DECLARE_READ16_MEMBER( next_pixel ); + inline DECLARE_READ16_MEMBER( time_until_next_event ) + { + return m_horz_to_go * 8 + m_horz_steps; + } + + DECLARE_WRITE_LINE_MEMBER( vsync_changed ); + DECLARE_WRITE_LINE_MEMBER( hsync_changed ); + + static const UINT16 HUC6270_SPRITE = 0x0100; // sprite colour information + static const UINT16 HUC6270_BACKGROUND = 0x0000; // background colour information + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + inline void fetch_bat_tile_row(); + void add_sprite( int index, int x, int pattern, int line, int flip_x, int palette, int priority, int sat_lsb ); + void select_sprites(); + inline void handle_vblank(); + inline void next_vert_state(); + inline void next_horz_state(); + +private: + + enum huc6270_v_state { + HUC6270_VSW, + HUC6270_VDS, + HUC6270_VDW, + HUC6270_VCR + }; + + enum huc6270_h_state { + HUC6270_HDS, + HUC6270_HDW, + HUC6270_HDE, + HUC6270_HSW + }; + + + /* Size of Video ram (mandatory) */ + UINT32 m_vram_size; + + /* Callback for when the irq line may have changed (mandatory) */ + devcb_write_line m_irq_changed_cb; + + UINT8 m_register_index; + + /* HuC6270 registers */ + UINT16 m_mawr; + UINT16 m_marr; + UINT16 m_vrr; + UINT16 m_vwr; + UINT16 m_cr; + UINT16 m_rcr; + UINT16 m_bxr; + UINT16 m_byr; + UINT16 m_mwr; + UINT16 m_hsr; + UINT16 m_hdr; + UINT16 m_vpr; + UINT16 m_vdw; + UINT16 m_vcr; + UINT16 m_dcr; + UINT16 m_sour; + UINT16 m_desr; + UINT16 m_lenr; + UINT16 m_dvssr; + UINT8 m_status; + + /* To keep track of external hsync and vsync signals */ + int m_hsync; + int m_vsync; + + /* internal variables */ + huc6270_v_state m_vert_state; + huc6270_h_state m_horz_state; + int m_vd_triggered; + int m_vert_to_go; + int m_horz_to_go; + int m_horz_steps; + int m_raster_count; + int m_dvssr_written; + int m_satb_countdown; + int m_dma_enabled; + UINT16 m_byr_latched; + UINT16 m_bxr_latched; + UINT16 m_bat_address; + UINT16 m_bat_address_mask; + UINT16 m_bat_row; + UINT16 m_bat_column; + UINT8 m_bat_tile_row[8]; + /* Internal sprite attribute table. SATB DMA is used to transfer data + from VRAM to this internal table. + */ + UINT16 m_sat[4*64]; + int m_sprites_this_line; + int m_sprite_row_index; + UINT16 m_sprite_row[1024]; + UINT16 *m_vram; + UINT16 m_vram_mask; + + const static UINT8 vram_increments[4]; +}; + + +extern const device_type HUC6270; + + +#endif diff --git a/src/devices/video/huc6272.c b/src/devices/video/huc6272.c new file mode 100644 index 00000000000..849ec9f09d6 --- /dev/null +++ b/src/devices/video/huc6272.c @@ -0,0 +1,249 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +/*************************************************************************** + + Hudson/NEC HuC6272 "King" device + +***************************************************************************/ + +#include "emu.h" +#include "video/huc6272.h" + + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +// device type definition +const device_type huc6272 = &device_creator; + +static ADDRESS_MAP_START( huc6272_vram, AS_0, 32, huc6272_device ) + AM_RANGE(0x000000, 0x0fffff) AM_RAM + AM_RANGE(0x100000, 0x1fffff) AM_RAM +ADDRESS_MAP_END + + +//------------------------------------------------- +// memory_space_config - return a description of +// any address spaces owned by this device +//------------------------------------------------- + +const address_space_config *huc6272_device::memory_space_config(address_spacenum spacenum) const +{ + return (spacenum == AS_0) ? &m_space_config : NULL; +} + +//************************************************************************** +// INLINE HELPERS +//************************************************************************** + +//------------------------------------------------- +// read_dword - read a dword at the given address +//------------------------------------------------- + +inline UINT32 huc6272_device::read_dword(offs_t address) +{ + return space().read_dword(address << 2); +} + + +//------------------------------------------------- +// write_dword - write a dword at the given address +//------------------------------------------------- + +inline void huc6272_device::write_dword(offs_t address, UINT32 data) +{ + space().write_dword(address << 2, data); +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// huc6272_device - constructor +//------------------------------------------------- + +huc6272_device::huc6272_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, huc6272, "huc6272", tag, owner, clock, "huc6272", __FILE__), + device_memory_interface(mconfig, *this), + m_space_config("videoram", ENDIANNESS_LITTLE, 32, 32, 0, NULL, *ADDRESS_MAP_NAME(huc6272_vram)) +{ +} + + +//------------------------------------------------- +// device_validity_check - perform validity checks +// on this device +//------------------------------------------------- + +void huc6272_device::device_validity_check(validity_checker &valid) const +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void huc6272_device::device_start() +{ +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void huc6272_device::device_reset() +{ +} + + +//************************************************************************** +// READ/WRITE HANDLERS +//************************************************************************** + +READ32_MEMBER( huc6272_device::read ) +{ + UINT32 res = 0; + + if((offset & 1) == 0) + { + /* + xxxx xxxx ---- ---- ---- ---- ---- ---- Sub Channel Buffer + ---- ---- x--- ---- ---- ---- ---- ---- SCSI RST flag + ---- ---- -x-- ---- ---- ---- ---- ---- SCSI BUSY flag + ---- ---- --x- ---- ---- ---- ---- ---- SCSI REQ flag + ---- ---- ---x ---- ---- ---- ---- ---- SCSI MSG flag + ---- ---- ---- x--- ---- ---- ---- ---- SCSI CD flag + ---- ---- ---- -x-- ---- ---- ---- ---- SCSI IO flag + ---- ---- ---- --x- ---- ---- ---- ---- SCSI SEL flag + ---- ---- ---- ---- -x-- ---- ---- ---- SCSI IRQ pending + ---- ---- ---- ---- --x- ---- ---- ---- DMA IRQ pending + ---- ---- ---- ---- ---x ---- ---- ---- CD Sub Channel IRQ pending + ---- ---- ---- ---- ---- x--- ---- ---- Raster IRQ pending + ---- ---- ---- ---- ---- -x-- ---- ---- ADPCM IRQ pending + ---- ---- ---- ---- ---- ---- -xxx xxxx register read-back + */ + res = m_register & 0x7f; + res |= (0) << 16; + } + else + { + switch(m_register) + { + /* + x--- ---- ---- ---- ---- + */ + case 0x0c: // KRAM load address + res = (m_kram_addr_r & 0x3ffff) | ((m_kram_inc_r & 0x1ff) << 18) | ((m_kram_page_r & 1) << 31); + break; + + case 0x0d: // KRAM write address + res = (m_kram_addr_w & 0x3ffff) | ((m_kram_inc_w & 0x1ff) << 18) | ((m_kram_page_w & 1) << 31); + break; + + case 0x0e: + res = read_dword((m_kram_addr_r)|(m_kram_page_r<<18)); + m_kram_addr_r += (m_kram_inc_r & 0x100) ? ((m_kram_inc_r & 0xff) - 0x100) : (m_kram_inc_r & 0xff); + break; + + case 0x0f: + res = m_page_setting; + break; + //default: printf("%04x\n",m_register); + } + } + + return res; +} + +WRITE32_MEMBER( huc6272_device::write ) +{ + if((offset & 1) == 0) + m_register = data & 0x7f; + else + { + switch(m_register) + { + case 0x09: // DMA addr + //printf("%08x DMA ADDR\n",data); + break; + case 0x0a: // DMA size + //printf("%08x DMA SIZE\n",data); + break; + case 0x0b: // DMA status + //printf("%08x DMA STATUS\n",data); + break; + /* + ---- ---- ---- ---- ---- + */ + case 0x0c: // KRAM load address + m_kram_addr_r = (data & 0x0003ffff); + m_kram_inc_r = (data & 0x07fc0000) >> 18; + m_kram_page_r = (data & 0x80000000) >> 31; + break; + + case 0x0d: // KRAM write address + m_kram_addr_w = (data & 0x0003ffff); + m_kram_inc_w = (data & 0x07fc0000) >> 18; + m_kram_page_w = (data & 0x80000000) >> 31; + break; + + case 0x0e: // KRAM write VRAM + write_dword((m_kram_addr_w)|(m_kram_page_w<<18),data); /* TODO: there are some 32-bits accesses during BIOS? */ + m_kram_addr_w += (m_kram_inc_w & 0x100) ? ((m_kram_inc_w & 0xff) - 0x100) : (m_kram_inc_w & 0xff); + break; + + /* + ---x ---- ---- ---- ADPCM page setting + ---- ---x ---- ---- RAINBOW page setting + ---- ---- ---x ---- BG page setting + ---- ---- ---- ---x SCSI page setting + */ + case 0x0f: + m_page_setting = data; + break; + + // + // xxxx ---- ---- ---- BG3 mode setting + // ---- xxxx ---- ---- BG2 mode setting + // ---- ---- xxxx ---- BG1 mode setting + // ---- ---- ---- xxxx BG0 mode setting + // + // 0001 - 4 color palette + // 0010 - 16 color palette + // 0011 - 256 color palette + // 0100 - 64k color + // 0101 - 16M color + // 1001 - 4 color palette block mode + // 1010 - 16 color palette block mode + // 1011 - 256 color palette block mode + // others - unused/invalid + case 0x10: + m_bgmode[0] = data & 0x0f; + m_bgmode[1] = ( data >> 4 ) & 0x0f; + m_bgmode[2] = ( data >> 8 ) & 0x0f; + m_bgmode[3] = ( data >> 12 ) & 0x0f; + break; + + case 0x13: + m_micro_prg.addr = data & 0xf; + break; + + case 0x14: + m_micro_prg.data[m_micro_prg.addr] = data & 0xffff; + m_micro_prg.addr++; + m_micro_prg.addr &= 0xf; + break; + + case 0x15: + m_micro_prg.ctrl = data & 1; + break; + + //default: printf("%04x %04x %08x\n",m_register,data,mem_mask); + } + } +} diff --git a/src/devices/video/huc6272.h b/src/devices/video/huc6272.h new file mode 100644 index 00000000000..140d086efb0 --- /dev/null +++ b/src/devices/video/huc6272.h @@ -0,0 +1,80 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +/*************************************************************************** + +Template for skeleton device + +***************************************************************************/ + +#pragma once + +#ifndef __huc6272DEV_H__ +#define __huc6272DEV_H__ + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_HUC6272_ADD(_tag,_freq) \ + MCFG_DEVICE_ADD(_tag, huc6272, _freq) + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> huc6272_device + +class huc6272_device : public device_t, + public device_memory_interface +{ +public: + // construction/destruction + huc6272_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // I/O operations + DECLARE_WRITE32_MEMBER( write ); + DECLARE_READ32_MEMBER( read ); + + +protected: + // device-level overrides + virtual void device_validity_check(validity_checker &valid) const; + virtual void device_start(); + virtual void device_reset(); + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const; + +private: + inline UINT32 read_dword(offs_t address); + inline void write_dword(offs_t address, UINT32 data); + UINT8 m_register; + UINT32 m_kram_addr_r, m_kram_addr_w; + UINT16 m_kram_inc_r,m_kram_inc_w; + UINT8 m_kram_page_r,m_kram_page_w; + UINT32 m_page_setting; + UINT8 m_bgmode[4]; + + struct{ + UINT8 addr; + UINT8 ctrl; + UINT16 data[16]; + }m_micro_prg; + + const address_space_config m_space_config; +}; + + +// device type definition +extern const device_type huc6272; + + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + + + +#endif diff --git a/src/devices/video/i8244.c b/src/devices/video/i8244.c new file mode 100644 index 00000000000..a074b676e64 --- /dev/null +++ b/src/devices/video/i8244.c @@ -0,0 +1,799 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +/*************************************************************************** + + i8244.c + + Intel 8244 (NTSC)/8245 (PAL) Graphics and sound chip + + +***************************************************************************/ + +#include "emu.h" +#include "i8244.h" + + +// device type definition +const device_type I8244 = &device_creator; +const device_type I8245 = &device_creator; + + +// Kevtris verified that the data below matches a dump +// taken from a real chip. +static const UINT8 c_shape[0x40 * 8] = +{ + 0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00, // 0 + 0x18,0x38,0x18,0x18,0x18,0x18,0x3C,0x00, + 0x3C,0x66,0x0C,0x18,0x30,0x60,0x7E,0x00, + 0x7C,0xC6,0x06,0x3C,0x06,0xC6,0x7C,0x00, + 0xCC,0xCC,0xCC,0xFE,0x0C,0x0C,0x0C,0x00, + 0xFE,0xC0,0xC0,0x7C,0x06,0xC6,0x7C,0x00, + 0x7C,0xC6,0xC0,0xFC,0xC6,0xC6,0x7C,0x00, + 0xFE,0x06,0x0C,0x18,0x30,0x60,0xC0,0x00, + 0x7C,0xC6,0xC6,0x7C,0xC6,0xC6,0x7C,0x00, + 0x7C,0xC6,0xC6,0x7E,0x06,0xC6,0x7C,0x00, + 0x00,0x18,0x18,0x00,0x18,0x18,0x00,0x00, + 0x18,0x7E,0x58,0x7E,0x1A,0x7E,0x18,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x3C,0x66,0x0C,0x18,0x18,0x00,0x18,0x00, + 0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xFE,0x00, + 0xFC,0xC6,0xC6,0xFC,0xC0,0xC0,0xC0,0x00, + 0x00,0x18,0x18,0x7E,0x18,0x18,0x00,0x00, + 0xC6,0xC6,0xC6,0xD6,0xFE,0xEE,0xC6,0x00, + 0xFE,0xC0,0xC0,0xF8,0xC0,0xC0,0xFE,0x00, + 0xFC,0xC6,0xC6,0xFC,0xD8,0xCC,0xC6,0x00, + 0x7E,0x18,0x18,0x18,0x18,0x18,0x18,0x00, + 0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00, + 0x3C,0x18,0x18,0x18,0x18,0x18,0x3C,0x00, + 0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00, + 0x7C,0xC6,0xC6,0xC6,0xDE,0xCC,0x76,0x00, + 0x7C,0xC6,0xC0,0x7C,0x06,0xC6,0x7C,0x00, + 0xFC,0xC6,0xC6,0xC6,0xC6,0xC6,0xFC,0x00, + 0xFE,0xC0,0xC0,0xF8,0xC0,0xC0,0xC0,0x00, + 0x7C,0xC6,0xC0,0xC0,0xCE,0xC6,0x7E,0x00, + 0xC6,0xC6,0xC6,0xFE,0xC6,0xC6,0xC6,0x00, + 0x06,0x06,0x06,0x06,0x06,0xC6,0x7C,0x00, + 0xC6,0xCC,0xD8,0xF0,0xD8,0xCC,0xC6,0x00, + 0x38,0x6C,0xC6,0xC6,0xFE,0xC6,0xC6,0x00, + 0x7E,0x06,0x0C,0x18,0x30,0x60,0x7E,0x00, + 0xC6,0xC6,0x6C,0x38,0x6C,0xC6,0xC6,0x00, + 0x7C,0xC6,0xC0,0xC0,0xC0,0xC6,0x7C,0x00, + 0xC6,0xC6,0xC6,0xC6,0xC6,0x6C,0x38,0x00, + 0xFC,0xC6,0xC6,0xFC,0xC6,0xC6,0xFC,0x00, + 0xC6,0xEE,0xFE,0xD6,0xC6,0xC6,0xC6,0x00, + 0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00, + 0x00,0x00,0x00,0x7E,0x00,0x00,0x00,0x00, + 0x00,0x66,0x3C,0x18,0x3C,0x66,0x00,0x00, + 0x00,0x18,0x00,0x7E,0x00,0x18,0x00,0x00, + 0x00,0x00,0x7E,0x00,0x7E,0x00,0x00,0x00, + 0x66,0x66,0x66,0x3C,0x18,0x18,0x18,0x00, + 0xC6,0xE6,0xF6,0xFE,0xDE,0xCE,0xC6,0x00, + 0x03,0x06,0x0C,0x18,0x30,0x60,0xC0,0x00, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00, + 0xCE,0xDB,0xDB,0xDB,0xDB,0xDB,0xCE,0x00, + 0x00,0x00,0x3C,0x7E,0x7E,0x7E,0x3C,0x00, + 0x1C,0x1C,0x18,0x1E,0x18,0x18,0x1C,0x00, + 0x1C,0x1C,0x18,0x1E,0x18,0x34,0x26,0x00, + 0x38,0x38,0x18,0x78,0x18,0x2C,0x64,0x00, + 0x38,0x38,0x18,0x78,0x18,0x18,0x38,0x00, + 0x00,0x18,0x0C,0xFE,0x0C,0x18,0x00,0x00, + 0x18,0x3C,0x7E,0xFF,0xFF,0x18,0x18,0x00, + 0x03,0x07,0x0F,0x1F,0x3F,0x7F,0xFF,0x00, + 0xC0,0xE0,0xF0,0xF8,0xFC,0xFE,0xFF,0x00, + 0x38,0x38,0x12,0xFE,0xB8,0x28,0x6C,0x00, + 0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0x00, + 0x00,0x00,0x0C,0x08,0x08,0x7F,0x3E,0x00, + 0x00,0x03,0x63,0xFF,0xFF,0x18,0x08,0x00, + 0x00,0x00,0x00,0x10,0x38,0xFF,0x7E,0x00 +}; + + +// Background and grid information is stored in RGB format +// while the character and sprite colors are stored in BGR +// format. +static const UINT8 bgr2rgb[8] = +{ + 0x00, 0x04, 0x02, 0x06, 0x01, 0x05, 0x03, 0x07 +}; + + +//------------------------------------------------- +// i8244_device - constructor +//------------------------------------------------- + +i8244_device::i8244_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, I8244, "I8244", tag, owner, clock, "i8244", __FILE__) + , device_sound_interface(mconfig, *this) + , device_video_interface(mconfig, *this) + , m_irq_func(*this) + , m_postprocess_func(*this) + , m_start_vpos(START_Y) + , m_start_vblank(START_Y + SCREEN_HEIGHT) + , m_screen_lines(LINES) +{ +} + + +i8244_device::i8244_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, int lines, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source) + , device_sound_interface(mconfig, *this) + , device_video_interface(mconfig, *this) + , m_irq_func(*this) + , m_postprocess_func(*this) + , m_start_vpos(START_Y) + , m_start_vblank(START_Y + SCREEN_HEIGHT) + , m_screen_lines(lines) +{ +} + + +i8245_device::i8245_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : i8244_device(mconfig, I8245, "I8245", tag, owner, clock, i8245_device::LINES, "i8245", __FILE__) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void i8244_device::device_start() +{ + // Let the screen create our temporary bitmap with the screen's dimensions + m_screen->register_screen_bitmap(m_tmp_bitmap); + + m_line_timer = timer_alloc(TIMER_LINE); + m_line_timer->adjust( m_screen->time_until_pos(1, START_ACTIVE_SCAN ), 0, m_screen->scan_period() ); + + m_hblank_timer = timer_alloc(TIMER_HBLANK); + m_hblank_timer->adjust( m_screen->time_until_pos(1, END_ACTIVE_SCAN + 18 ), 0, m_screen->scan_period() ); + + m_irq_func.resolve_safe(); + m_postprocess_func.resolve_safe(); + + // allocate a stream + m_stream = stream_alloc( 0, 1, clock()/(LINE_CLOCKS*4) ); + + // register our state + save_pointer(NAME(m_vdc.reg), 0x100); + save_item(NAME(m_sh_count)); + save_item(NAME(m_x_beam_pos)); + save_item(NAME(m_y_beam_pos)); + save_item(NAME(m_control_status)); + save_item(NAME(m_collision_status)); + save_item(NAME(m_iff)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void i8244_device::device_reset() +{ + memset(m_vdc.reg, 0, 0x100); + + m_sh_count = 0; + m_x_beam_pos = 0; + m_y_beam_pos = 0; + m_control_status = 0; + m_collision_status = 0; + m_iff = 0; +} + + +PALETTE_INIT_MEMBER(i8244_device, i8244) +{ + static const UINT8 i8244_colors[3*16] = + { + 0x00, 0x00, 0x00, // i r g b + 0x00, 0x00, 0xAA, // i r g B + 0x00, 0xAA, 0x00, // i r G b + 0x00, 0xAA, 0xAA, // i r G B + 0xAA, 0x00, 0x00, // i R g b + 0xAA, 0x00, 0xAA, // i R g B + 0xAA, 0xAA, 0x00, // i R G b + 0xAA, 0xAA, 0xAA, // i R G B + 0x55, 0x55, 0x55, // I r g b + 0x55, 0x55, 0xFF, // I r g B + 0x55, 0xFF, 0x55, // I r G b + 0x55, 0xFF, 0xFF, // I r G B + 0xFF, 0x55, 0x55, // I R g b + 0xFF, 0x55, 0xFF, // I R g B + 0xFF, 0xFF, 0x55, // I R G b + 0xFF, 0xFF, 0xFF, // I R G B + }; + + for ( int i = 0; i < 16; i++ ) + { + palette.set_pen_color( i, i8244_colors[i*3], i8244_colors[i*3+1], i8244_colors[i*3+2] ); + } +} + + +void i8244_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + int vpos = m_screen->vpos(); + + switch ( id ) + { + case TIMER_LINE: + // handle i824x line timer + render_scanline(vpos); + break; + + case TIMER_HBLANK: + // handle i824x HBlank timer + if ( vpos < m_start_vpos - 1 ) + { + return; + } + + if ( vpos < m_start_vblank - 1 ) + { + m_control_status |= 0x01; + } + break; + } +} + + +int i8244_device::get_y_beam() +{ + int y = m_screen->vpos() - m_start_vpos; + + // The Y register becomes 0 only when the VBlank signal is turned off! + if ( y < 0 || ( y == 0 && m_screen->hpos() < 366+42 ) ) + { + y += m_screen_lines; + } + + return y; +} + + +int i8244_device::get_x_beam() +{ + int x = m_screen->hpos() - START_ACTIVE_SCAN; + + if ( x < 0 ) + { + x += LINE_CLOCKS; + } + + return x >> 1; +} + + +offs_t i8244_device::fix_register_mirrors( offs_t offset ) +{ + // registers $40,$41 are mirrored at $44,$45, $48,$49, and $4C,$4D + if ( ( offset & 0xF2 ) == 0x40 ) + { + offset &= ~0x0C; + } + + // registers $A0-$AF are mirrored at $B0-$BF + if ( ( offset & 0xF0 ) == 0xB0 ) + { + offset &= ~0x10; + } + + return offset; +} + + +READ8_MEMBER(i8244_device::read) +{ + UINT8 data = 0; + + offset = fix_register_mirrors( offset ); + + switch (offset) + { + case 0xa1: + data = m_control_status & 0xFE; + m_iff = 0; + m_irq_func(CLEAR_LINE); + m_control_status &= ~0x08; + if ( hblank() ) + { + data |= 1; + } + break; + + case 0xa2: + data = m_collision_status; + m_collision_status = 0; + break; + + case 0xa4: + if (m_vdc.s.control & VDC_CONTROL_REG_STROBE_XY) + { + m_y_beam_pos = get_y_beam(); + } + data = m_y_beam_pos; + break; + + + case 0xa5: + if ((m_vdc.s.control & VDC_CONTROL_REG_STROBE_XY)) + { + m_x_beam_pos = get_x_beam(); + } + data = m_x_beam_pos; + break; + + default: + data = m_vdc.reg[offset]; + break; + } + + return data; +} + + +WRITE8_MEMBER(i8244_device::write) +{ + offset = fix_register_mirrors( offset ); + + /* Update the sound */ + if( offset >= 0xa7 && offset <= 0xaa ) + { + m_stream->update(); + } + + if (offset == 0xa0) + { + if ( ( m_vdc.s.control & VDC_CONTROL_REG_STROBE_XY ) + && !(data & VDC_CONTROL_REG_STROBE_XY)) + { + /* Toggling strobe bit, tuck away values */ + m_x_beam_pos = get_x_beam(); + m_y_beam_pos = get_y_beam(); + } + } + + m_vdc.reg[offset] = data; +} + + +READ_LINE_MEMBER(i8244_device::vblank) +{ + if ( m_screen->vpos() > m_start_vpos && m_screen->vpos() < m_start_vblank ) + { + return 0; + } + return 1; +} + + +READ_LINE_MEMBER(i8244_device::hblank) +{ + int hpos = m_screen->hpos(); + int vpos = m_screen->vpos(); + + if ( hpos >= START_ACTIVE_SCAN && hpos < END_ACTIVE_SCAN ) + { + return 0; + } + + // Before active area? + if ( vpos < m_start_vpos - 1 ) + { + return 0; + } + + // During active area? + if ( vpos < m_start_vblank - 1 ) + { + return 1; + } + + // After active area + return 0; +} + + +void i8244_device::render_scanline(int vpos) +{ + // Some local constants for this method + //static const UINT8 COLLISION_SPRITE_0 = 0x01; + //static const UINT8 COLLISION_SPRITE_1 = 0x02; + //static const UINT8 COLLISION_SPRITE_2 = 0x04; + //static const UINT8 COLLISION_SPRITE_3 = 0x08; + static const UINT8 COLLISION_VERTICAL_GRID = 0x10; + static const UINT8 COLLISION_HORIZ_GRID_DOTS = 0x20; + //static const UINT8 COLLISION_EXTERNAL_UNUSED = 0x40; + static const UINT8 COLLISION_CHARACTERS = 0x80; + + UINT8 collision_map[160]; + + if ( vpos == m_start_vpos ) + { + m_control_status &= ~0x08; + } + + if ( m_start_vpos < vpos && vpos < m_start_vblank ) + { + rectangle rect; + int scanline = vpos - m_start_vpos; + + m_control_status &= ~ 0x01; + + /* Draw a line */ + rect.set(START_ACTIVE_SCAN, END_ACTIVE_SCAN - 1, vpos, vpos); + m_tmp_bitmap.fill( (m_vdc.s.color >> 3) & 0x7, rect ); + + /* Clear collision map */ + memset( collision_map, 0, sizeof( collision_map ) ); + + /* Display grid if enabled */ + if ( m_vdc.s.control & 0x08 ) + { + UINT16 color = ( m_vdc.s.color & 7 ) | ( ( m_vdc.s.color >> 3 ) & 0x08 ); + int x_grid_offset = 8; + int y_grid_offset = 24; + int width = 16; + int height = 24; + int w = ( m_vdc.s.control & 0x80 ) ? width : 2; + + /* Draw horizontal part of grid */ + for ( int j = 1, y = 0; y < 9; y++, j <<= 1 ) + { + if ( y_grid_offset + y * height <= scanline && scanline < y_grid_offset + y * height + 3 ) + { + for ( int i = 0; i < 9; i++ ) + { + if ( ( m_vdc.s.hgrid[0][i] & j ) || ( m_vdc.s.hgrid[1][i] & ( j >> 8 ) ) ) + { + for ( int k = 0; k < width + 2; k++ ) + { + int px = x_grid_offset + i * width + k; + + if ( px < 160 ) + { + collision_map[ px ] |= COLLISION_HORIZ_GRID_DOTS; + m_tmp_bitmap.pix16( vpos, START_ACTIVE_SCAN + 10 + 2 * px ) = color; + m_tmp_bitmap.pix16( vpos, START_ACTIVE_SCAN + 10 + 2 * px + 1 ) = color; + } + } + } + } + } + } + + /* Draw vertical part of grid */ + for( int j = 1, y = 0; y < 8; y++, j <<= 1 ) + { + if ( y_grid_offset + y * height <= scanline && scanline < y_grid_offset + ( y + 1 ) * height ) + { + for ( int i = 0; i < 10; i++ ) + { + if ( m_vdc.s.vgrid[i] & j ) + { + for ( int k = 0; k < w; k++ ) + { + int px = x_grid_offset + i * width + k; + + if ( px < 160 ) + { + /* Check if we collide with an already drawn source object */ + if ( collision_map[ px ] & m_vdc.s.collision ) + { + m_collision_status |= COLLISION_VERTICAL_GRID; + } + /* Check if an already drawn object would collide with us */ + if ( COLLISION_VERTICAL_GRID & m_vdc.s.collision && collision_map[ px ] ) + { + m_collision_status |= collision_map[ px ]; + } + collision_map[ px ] |= COLLISION_VERTICAL_GRID; + m_tmp_bitmap.pix16( vpos, START_ACTIVE_SCAN + 10 + 2 * px ) = color; + m_tmp_bitmap.pix16( vpos, START_ACTIVE_SCAN + 10 + 2 * px + 1 ) = color; + } + } + } + } + } + } + } + + /* Display objects if enabled */ + if ( m_vdc.s.control & 0x20 ) + { + /* Regular foreground objects */ + for ( int i = 0; i < ARRAY_LENGTH( m_vdc.s.foreground ); i++ ) + { + int y = m_vdc.s.foreground[i].y & 0xFE; + int height = 8 - ( ( ( y >> 1 ) + m_vdc.s.foreground[i].ptr ) & 7 ); + + if ( y >= 0x0E && y <= scanline && scanline < y + height * 2 ) + { + UINT16 color = 8 + bgr2rgb[ ( ( m_vdc.s.foreground[i].color >> 1 ) & 0x07 ) ]; + int offset = ( m_vdc.s.foreground[i].ptr | ( ( m_vdc.s.foreground[i].color & 0x01 ) << 8 ) ) + ( y >> 1 ) + ( ( scanline - y ) >> 1 ); + UINT8 chr = c_shape[ offset & 0x1FF ]; + int x = m_vdc.s.foreground[i].x; + + for ( UINT8 m = 0x80; m > 0; m >>= 1, x++ ) + { + if ( chr & m ) + { + if ( x >= 0 && x < 160 ) + { + /* Check if we collide with an already drawn source object */ + if ( collision_map[ x ] & m_vdc.s.collision ) + { + m_collision_status |= COLLISION_CHARACTERS; + } + /* Check if an already drawn object would collide with us */ + if ( COLLISION_CHARACTERS & m_vdc.s.collision && collision_map[ x ] ) + { + m_collision_status |= collision_map[ x ]; + } + collision_map[ x ] |= COLLISION_CHARACTERS; + m_tmp_bitmap.pix16( vpos, START_ACTIVE_SCAN + 10 + 2 * x ) = color; + m_tmp_bitmap.pix16( vpos, START_ACTIVE_SCAN + 10 + 2 * x + 1 ) = color; + } + } + } + } + } + + /* Quad objects */ + for ( int i = 0; i < ARRAY_LENGTH( m_vdc.s.quad ); i++ ) + { + int y = m_vdc.s.quad[i].single[0].y; + int height = 8; + + if ( y <= scanline && scanline < y + height * 2 ) + { + int x = m_vdc.s.quad[i].single[0].x; + + // Charaecter height is always determined by the height of the 4th character + int char_height = 8 - ( ( ( y >> 1 ) + m_vdc.s.quad[i].single[3].ptr ) & 7 ); + + for ( int j = 0; j < ARRAY_LENGTH( m_vdc.s.quad[0].single ); j++, x += 8 ) + { + if ( y <= scanline && scanline < y + char_height * 2 ) + { + UINT16 color = 8 + bgr2rgb[ ( ( m_vdc.s.quad[i].single[j].color >> 1 ) & 0x07 ) ]; + int offset = ( m_vdc.s.quad[i].single[j].ptr | ( ( m_vdc.s.quad[i].single[j].color & 0x01 ) << 8 ) ) + ( y >> 1 ) + ( ( scanline - y ) >> 1 ); + UINT8 chr = c_shape[ offset & 0x1FF ]; + + for ( UINT8 m = 0x80; m > 0; m >>= 1, x++ ) + { + if ( chr & m ) + { + if ( x >= 0 && x < 160 ) + { + /* Check if we collide with an already drawn source object */ + if ( collision_map[ x ] & m_vdc.s.collision ) + { + m_collision_status |= COLLISION_CHARACTERS; + } + /* Check if an already drawn object would collide with us */ + if ( COLLISION_CHARACTERS & m_vdc.s.collision && collision_map[ x ] ) + { + m_collision_status |= collision_map[ x ]; + } + collision_map[ x ] |= COLLISION_CHARACTERS; + m_tmp_bitmap.pix16( vpos, START_ACTIVE_SCAN + 10 + 2 * x ) = color; + m_tmp_bitmap.pix16( vpos, START_ACTIVE_SCAN + 10 + 2 * x + 1 ) = color; + } + } + } + } + else + { + x += 8; + } + } + } + } + + /* Sprites */ + for ( int i = 0; i < ARRAY_LENGTH( m_vdc.s.sprites ); i++ ) + { + int y = m_vdc.s.sprites[i].y; + int height = 8; + + if ( m_vdc.s.sprites[i].color & 4 ) + { + /* Zoomed sprite */ + if ( y <= scanline && scanline < y + height * 4 ) + { + UINT16 color = 8 + bgr2rgb[ ( ( m_vdc.s.sprites[i].color >> 3 ) & 0x07 ) ]; + UINT8 chr = m_vdc.s.shape[i][ ( ( scanline - y ) >> 2 ) ]; + int x = m_vdc.s.sprites[i].x; + int x_shift = 0; + + switch ( m_vdc.s.sprites[i].color & 0x03 ) + { + case 1: // Xg attribute set + x_shift = 2; + break; + case 2: // S attribute set + x_shift = ( ( ( scanline - y ) >> 1 ) & 0x01 ) ^ 0x01; + break; + case 3: // Xg and S attributes set + x_shift = ( ( scanline - y ) >> 1 ) & 0x01; + break; + } + x_shift <<= 1; + + for ( UINT8 m = 0x01; m > 0; m <<= 1, x += 2 ) + { + if ( chr & m ) + { + if ( x >= 0 && x < 160 ) + { + /* Check if we collide with an already drawn source object */ + if ( collision_map[ x ] & m_vdc.s.collision ) + { + m_collision_status |= ( 1 << i ); + } + /* Check if an already drawn object would collide with us */ + if ( ( 1 << i ) & m_vdc.s.collision && collision_map[ x ] ) + { + m_collision_status |= collision_map[ x ]; + } + collision_map[ x ] |= ( 1 << i ); + m_tmp_bitmap.pix16( vpos, START_ACTIVE_SCAN + 10 + x_shift + 2 * x ) = color; + m_tmp_bitmap.pix16( vpos, START_ACTIVE_SCAN + 10 + x_shift + 2 * x + 1 ) = color; + } + if ( x >= -1 && x < 159 ) + { + if ( x >= 0 ) + { + /* Check if we collide with an already drawn source object */ + if ( collision_map[ x ] & m_vdc.s.collision ) + { + m_collision_status |= ( 1 << i ); + } + /* Check if an already drawn object would collide with us */ + if ( ( 1 << i ) & m_vdc.s.collision && collision_map[ x ] ) + { + m_collision_status |= collision_map[ x ]; + } + collision_map[ x ] |= ( 1 << i ); + } + m_tmp_bitmap.pix16( vpos, START_ACTIVE_SCAN + 10 + x_shift + 2 * x + 2 ) = color; + m_tmp_bitmap.pix16( vpos, START_ACTIVE_SCAN + 10 + x_shift + 2 * x + 3 ) = color; + } + } + } + } + } + else + { + /* Regular sprite */ + if ( y <= scanline && scanline < y + height * 2 ) + { + UINT16 color = 8 + bgr2rgb[ ( ( m_vdc.s.sprites[i].color >> 3 ) & 0x07 ) ]; + UINT8 chr = m_vdc.s.shape[i][ ( ( scanline - y ) >> 1 ) ]; + int x = m_vdc.s.sprites[i].x; + int x_shift = 0; + + switch ( m_vdc.s.sprites[i].color & 0x03 ) + { + case 1: // Xg attribute set + x_shift = 1; + break; + case 2: // S attribute set + x_shift = ( ( ( scanline - y ) >> 1 ) & 0x01 ) ^ 0x01; + break; + case 3: // Xg and S attributes set + x_shift = ( ( scanline - y ) >> 1 ) & 0x01; + break; + } + + for ( UINT8 m = 0x01; m > 0; m <<= 1, x++ ) + { + if ( chr & m ) + { + if ( x >= 0 && x < 160 ) + { + /* Check if we collide with an already drawn source object */ + if ( collision_map[ x ] & m_vdc.s.collision ) + { + m_collision_status |= ( 1 << i ); + } + /* Check if an already drawn object would collide with us */ + if ( ( 1 << i ) & m_vdc.s.collision && collision_map[ x ] ) + { + m_collision_status |= collision_map[ x ]; + } + collision_map[ x ] |= ( 1 << i ); + m_tmp_bitmap.pix16( vpos, START_ACTIVE_SCAN + 10 + x_shift + 2 * x ) = color; + m_tmp_bitmap.pix16( vpos, START_ACTIVE_SCAN + 10 + x_shift + 2 * x + 1 ) = color; + } + } + } + } + } + } + } + } + + // Allow driver to do additional processing + m_postprocess_func( vpos ); + + /* Check for start of VBlank */ + if ( vpos == m_start_vblank ) + { + m_control_status |= 0x08; + if ( ! m_iff ) + { + m_iff = 1; + m_irq_func(ASSERT_LINE); + } + } +} + + +void i8244_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + UINT32 old_signal, signal; + int ii; + int period; + stream_sample_t *buffer = outputs[0]; + + /* Generate the signal */ + old_signal = signal = m_vdc.s.shift3 | (m_vdc.s.shift2 << 8) | (m_vdc.s.shift1 << 16); + + if( m_vdc.s.sound & 0x80 ) /* Sound is enabled */ + { + for( ii = 0; ii < samples; ii++, buffer++ ) + { + *buffer = 0; + *buffer = signal & 0x1; + period = (m_vdc.s.sound & 0x20) ? 1 : 4; + if( ++m_sh_count >= period ) + { + m_sh_count = 0; + signal >>= 1; + /* Loop sound */ + signal |= *buffer << 23; + /* Check if noise should be applied */ + if ( m_vdc.s.sound & 0x10 ) + { + /* Noise tap is on bits 0 and 5 and fed back to bits 15 (and 23!) */ + UINT32 new_bit = ( ( old_signal ) ^ ( old_signal >> 5 ) ) & 0x01; + signal = ( old_signal & 0xFF0000 ) | ( ( old_signal & 0xFFFF ) >> 1 ) | ( new_bit << 15 ) | ( new_bit << 23 ); + } + m_vdc.s.shift3 = signal & 0xFF; + m_vdc.s.shift2 = ( signal >> 8 ) & 0xFF; + m_vdc.s.shift1 = ( signal >> 16 ) & 0xFF; + old_signal = signal; + } + + /* Throw an interrupt if enabled */ + if( m_vdc.s.control & 0x4 ) + { + // This feature does not seem to be finished/enabled in hardware! + } + + /* Adjust volume */ + *buffer *= m_vdc.s.sound & 0xf; + /* Pump the volume up */ + *buffer <<= 10; + } + } + else + { + /* Sound disabled, so clear the buffer */ + for( ii = 0; ii < samples; ii++, buffer++ ) + { + *buffer = 0; + } + } +} + + +UINT32 i8244_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) +{ + copybitmap( bitmap, m_tmp_bitmap, 0, 0, 0, 0, cliprect ); + + return 0; +} diff --git a/src/devices/video/i8244.h b/src/devices/video/i8244.h new file mode 100644 index 00000000000..ea518051a9f --- /dev/null +++ b/src/devices/video/i8244.h @@ -0,0 +1,169 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +/*************************************************************************** + + i8244.h + + Intel 8244 (NTSC)/8245 (PAL) Graphics and sound chip + +***************************************************************************/ + +#pragma once + +#ifndef __I8244_H__ +#define __I8244_H__ + +#include "emu.h" + + +/*************************************************************************** + DEVICE CONFIGURATION MACROS +***************************************************************************/ + +#define MCFG_I8244_ADD(_tag, _clock, _screen_tag, _irq_cb, _postprocess_cb) \ + MCFG_DEVICE_ADD(_tag, I8244, _clock) \ + MCFG_VIDEO_SET_SCREEN(_screen_tag) \ + MCFG_I8244_IRQ_CB(_irq_cb) \ + MCFG_I8244_POSTPROCESS_CB(_postprocess_cb) +#define MCFG_I8244_IRQ_CB(_devcb) \ + devcb = &i8244_device::set_irq_cb(*device, DEVCB_##_devcb); +#define MCFG_I8244_POSTPROCESS_CB(_devcb) \ + devcb = &i8244_device::set_postprocess_cb(*device, DEVCB_##_devcb); +#define MCFG_I8245_ADD(_tag, _clock, _screen_tag, _irq_cb, _postprocess_cb) \ + MCFG_DEVICE_ADD(_tag, I8245, _clock) \ + MCFG_VIDEO_SET_SCREEN(_screen_tag) \ + MCFG_I8244_IRQ_CB(_irq_cb) \ + MCFG_I8244_POSTPROCESS_CB(_postprocess_cb ) + +/*************************************************************************** + TYPE DEFINITIONS +***************************************************************************/ + +union vdc_t { + UINT8 reg[0x100]; + struct { + struct { + UINT8 y,x,color,res; + } sprites[4]; + struct { + UINT8 y,x,ptr,color; + } foreground[12]; + struct { + struct { + UINT8 y,x,ptr,color; + } single[4]; + } quad[4]; + UINT8 shape[4][8]; + UINT8 control; + UINT8 status; + UINT8 collision; + UINT8 color; + UINT8 y; + UINT8 x; + UINT8 res; + UINT8 shift1; + UINT8 shift2; + UINT8 shift3; + UINT8 sound; + UINT8 res2[5+0x10]; + UINT8 hgrid[2][0x10]; + UINT8 vgrid[0x10]; + } s; +}; + + +// ======================> i8244_device + +class i8244_device : public device_t + , public device_sound_interface + , public device_video_interface +{ +public: + // construction/destruction + i8244_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + i8244_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, int lines, const char *shortname, const char *source); + + // static configuration helpers + static void set_screen_tag(device_t &device, const char *screen_tag) { downcast(device).m_screen_tag = screen_tag; } + template static devcb_base &set_irq_cb(device_t &device, _Object object) { return downcast(device).m_irq_func.set_callback(object); } + template static devcb_base &set_postprocess_cb(device_t &device, _Object object) { return downcast(device).m_postprocess_func.set_callback(object); } + + DECLARE_READ8_MEMBER(read); + DECLARE_WRITE8_MEMBER(write); + DECLARE_READ_LINE_MEMBER(vblank); + DECLARE_READ_LINE_MEMBER(hblank); + DECLARE_PALETTE_INIT(i8244); + + UINT32 screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); + + inline bitmap_ind16 *get_bitmap() { return &m_tmp_bitmap; } + + // Global constants + static const int START_ACTIVE_SCAN = 42; + static const int BORDER_SIZE = 10; + static const int END_ACTIVE_SCAN = 42 + 10 + 320 + 10; + static const int START_Y = 1; + static const int SCREEN_HEIGHT = 243; + static const int LINE_CLOCKS = 455; + static const int LINES = 262; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + // device_sound_interface overrides + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + + void render_scanline(int vpos); + int get_y_beam(); + int get_x_beam(); + offs_t fix_register_mirrors( offs_t offset ); + + // Local constants + static const UINT8 VDC_CONTROL_REG_STROBE_XY = 0x02; + + /* timers */ + static const device_timer_id TIMER_LINE = 0; + static const device_timer_id TIMER_HBLANK = 1; + + // callbacks + devcb_write_line m_irq_func; + devcb_write16 m_postprocess_func; + + bitmap_ind16 m_tmp_bitmap; + emu_timer *m_line_timer; + emu_timer *m_hblank_timer; + sound_stream *m_stream; + + int m_start_vpos; + int m_start_vblank; + int m_screen_lines; + + vdc_t m_vdc; + UINT16 m_sh_count; + UINT8 m_x_beam_pos; + UINT8 m_y_beam_pos; + UINT8 m_control_status; + UINT8 m_collision_status; + int m_iff; +}; + + +class i8245_device : public i8244_device +{ +public: + // construction/destruction + i8245_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + static const int LINES = 312; +}; + + +// device type definition +extern const device_type I8244; +extern const device_type I8245; + + +#endif /* __I8244_H__ */ diff --git a/src/devices/video/i82730.c b/src/devices/video/i82730.c new file mode 100644 index 00000000000..d90a79d04ee --- /dev/null +++ b/src/devices/video/i82730.c @@ -0,0 +1,527 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best +/*************************************************************************** + + Intel 82730 + + Text Coprocessor + +***************************************************************************/ + +#include "i82730.h" + + +//************************************************************************** +// CONSTANTS +//************************************************************************** + +#define VERBOSE 1 +#define VERBOSE_COMMANDS 1 +#define VERBOSE_DATASTREAM 0 + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type I82730 = &device_creator; + +const char *i82730_device::m_command_names[] = +{ + /* 00 */ "NOP", + /* 01 */ "START DISPLAY", + /* 02 */ "START VIRTUAL DISPLAY", + /* 03 */ "STOP DISPLAY", + /* 04 */ "MODE SET", + /* 05 */ "LOAD CBP", + /* 06 */ "LOAD INTMASK", + /* 07 */ "LPEN ENABLE", + /* 08 */ "READ STATUS", + /* 09 */ "LD CUR POS", + /* 0a */ "SELF TEST", + /* 0b */ "TEST ROW BUFFER" +}; + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// i82730_device - constructor +//------------------------------------------------- + +i82730_device::i82730_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, I82730, "I82730", tag, owner, clock, "i82730", __FILE__), + device_video_interface(mconfig, *this), + m_sint_handler(*this), + m_cpu_tag(NULL), m_program(NULL), + m_row_timer(NULL), + m_initialized(false), m_mode_set(false), + m_ca(0), + m_sysbus(0x00), m_ibp(0x0000), m_cbp(0x0000), m_intmask(0xffff), m_status(0x0000), + m_list_switch(0), m_auto_line_feed(0), m_max_dma_count(0), + m_lptr(0), m_sptr(0), + m_dma_burst_space(0), m_dma_burst_length(0), + m_hfldstrt(0), m_margin(0), m_lpr(0), m_field_attribute_mask(0), m_vsyncstp(0), m_vfldstrt(0), m_vfldstp(0), + m_frame_int_count(0), + m_row_index(0) +{ +} + +//------------------------------------------------- +// set_cpu_tag - set cpu we are attached to +//------------------------------------------------- + +void i82730_device::set_cpu_tag(device_t &device, device_t *owner, const char *tag) +{ + i82730_device &dev = dynamic_cast(device); + dev.m_cpu_tag = tag; +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void i82730_device::device_start() +{ + // register bitmap + m_screen->register_screen_bitmap(m_bitmap); + + // resolve callbacks + m_sint_handler.resolve_safe(); + + // bind delegates + m_update_row_cb.bind_relative_to(*owner()); + + // allocate row timer + m_row_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(i82730_device::row_update), this)); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void i82730_device::device_reset() +{ + cpu_device *cpu = m_owner->subdevice(m_cpu_tag); + m_program = &cpu->space(AS_PROGRAM); + + m_initialized = false; + m_mode_set = false; + + m_ca = 0; + m_status = 0x0000; +} + + +//************************************************************************** +// MEMORY ACCESS +//************************************************************************** + +UINT8 i82730_device::read_byte(offs_t address) +{ + return m_program->read_byte(address); +} + +UINT16 i82730_device::read_word(offs_t address) +{ + UINT16 data = 0xffff; + + if (sysbus_16bit() && !(address & 1)) + { + data = m_program->read_word(address); + } + else + { + data = m_program->read_byte(address); + data |= m_program->read_byte(address + 1) << 8; + } + + return data; +} + +void i82730_device::write_byte(offs_t address, UINT8 data) +{ + m_program->write_byte(address, data); +} + +void i82730_device::write_word(offs_t address, UINT16 data) +{ + if (sysbus_16bit() && !(address & 1)) + { + m_program->write_word(address, data); + } + else + { + m_program->write_byte(address, data & 0xff); + m_program->write_byte(address + 1, (data >> 8) & 0xff); + } +} + + +//************************************************************************** +// IMPLEMENTATION +//************************************************************************** + +void i82730_device::update_interrupts() +{ + UINT16 code = m_status & ~m_intmask & ~(VDIP | DIP); + write_word(m_cbp + 20, code); + + if (code) + m_sint_handler(1); +} + +void i82730_device::mode_set() +{ + UINT32 mptr = (read_word(m_cbp + 32) << 16) | read_word(m_cbp + 30); + UINT16 tmp; + + tmp = read_word(mptr); + m_dma_burst_space = tmp & 0x7f; + m_dma_burst_length = (tmp >> 8) & 0x7f; + + tmp = read_word(mptr + 2); + UINT8 hsyncstp = tmp & 0xff; + UINT8 line_length = (tmp >> 8) & 0xff; + + tmp = read_word(mptr + 4); + UINT8 hfldstp = tmp & 0xff; + m_hfldstrt = (tmp >> 8) & 0xff; + + tmp = read_word(mptr + 6); + UINT8 hbrdstp = tmp & 0xff; + UINT8 hbrdstrt = (tmp >> 8) & 0xff; + + tmp = read_word(mptr + 8); + m_margin = tmp & 0x1f; + + tmp = read_word(mptr + 10); + m_lpr = tmp & 0x1f; + + tmp = read_word(mptr + 24); + m_field_attribute_mask = tmp & 0x7fff; + + tmp = read_word(mptr + 26); + UINT16 frame_length = tmp & 0x7ff; + + tmp = read_word(mptr + 28); + m_vsyncstp = tmp & 0x7ff; + + tmp = read_word(mptr + 30); + m_vfldstrt = tmp & 0x7ff; + + tmp = read_word(mptr + 32); + m_vfldstp = tmp & 0x7ff; + + tmp = read_word(mptr + 38); + m_frame_int_count = tmp & 0x0f; + + // setup screen mode + rectangle visarea(hbrdstrt * 16, hbrdstp * 16 - 1, m_vsyncstp, m_vfldstp + m_margin + 1 + m_lpr - 1); + attoseconds_t period = HZ_TO_ATTOSECONDS(clock() * 16) * line_length * 16 * frame_length; + m_screen->configure(line_length * 16, frame_length, visarea, period); + + // start display is now valid + m_mode_set = true; + + // adjust timer for the new mode + m_row_timer->adjust(m_screen->time_until_pos(0)); + + // output some debug info + if (VERBOSE) + { + logerror("%s('%s'): ---- setting mode ----\n", shortname(), basetag()); + logerror("%s('%s'): dma burst length %02x, space %02x\n", shortname(), basetag(), m_dma_burst_length, m_dma_burst_space); + logerror("%s('%s'): margin %02x, lpr %02x\n", shortname(), basetag(), m_margin, m_lpr); + logerror("%s('%s'): hsyncstp: %02x, line_length: %02x, hfldstrt: %02x, hbrdstart: %02x, hfldstop: %02x, hbrdstop: %02x\n", + shortname(), basetag(), hsyncstp, line_length, m_hfldstrt, hbrdstrt, hfldstp, hbrdstp); + logerror("%s('%s'): frame_length %04x, vsyncstp: %04x, vfldstrt: %04x, vfldstp: %04x\n", + shortname(), basetag(), frame_length, m_vsyncstp, m_vfldstrt, m_vfldstp); + } +} + +void i82730_device::execute_command() +{ + UINT8 command = read_byte(m_cbp + 1); + UINT16 tmp; + + if (VERBOSE_COMMANDS && command < ARRAY_LENGTH(m_command_names)) + logerror("%s('%s'): executing command: %s [cbp = %08x]\n", shortname(), basetag(), m_command_names[command], m_cbp); + + tmp = read_word(m_cbp + 2); + m_list_switch = BIT(tmp, 6); + m_auto_line_feed = BIT(tmp, 7); + + tmp = read_word(m_cbp + 4); + m_max_dma_count = tmp & 0xff; + + switch (command) + { + // NOP + case 0x00: + break; + + // START DISPLAY + case 0x01: + if (m_mode_set) + m_status = (m_status & ~VDIP) | DIP; + break; + + // START VIRTUAL DISPLAY + case 0x02: + if (m_mode_set) + m_status = VDIP | (m_status & ~DIP); + break; + + // STOP DISPLAY + case 0x03: + m_status &= ~(VDIP | DIP); + break; + + // MODE SET + case 0x04: + mode_set(); + break; + + // LOAD CBP + case 0x05: + m_cbp = (read_word(m_cbp + 16) << 16) | read_word(m_cbp + 14); + execute_command(); + break; + + // LOAD INTMASK + case 0x06: + m_intmask = read_word(m_cbp + 22); + if (VERBOSE_COMMANDS) + logerror("%s('%s'): intmask now %04x\n", shortname(), basetag(), m_intmask); + break; + + // LPEN ENABLE + case 0x07: + fatalerror("%s('%s'): Unimplemented command %s\n", shortname(), basetag(), m_command_names[command]); + break; + + // READ STATUS + case 0x08: + write_word(m_cbp + 18, m_status); + m_status &= (VDIP | DIP); + break; + + // LD CUR POS + case 0x09: + fatalerror("%s('%s'): Unimplemented command %s\n", shortname(), basetag(), m_command_names[command]); + break; + + // SELF TEST + case 0x0a: + fatalerror("%s('%s'): Unimplemented command %s\n", shortname(), basetag(), m_command_names[command]); + break; + + // TEST ROW BUFFER + case 0x0b: + fatalerror("%s('%s'): Unimplemented command %s\n", shortname(), basetag(), m_command_names[command]); + break; + + default: + if (VERBOSE_COMMANDS) + logerror("%s('%s'): executing command: (reserved) [cbp = %08x]\n", shortname(), basetag(), m_cbp); + m_status |= RCC; + update_interrupts(); + break; + } + + // clear busy + write_word(m_cbp, read_word(m_cbp) & 0xff00); +} + +void i82730_device::load_row() +{ + bool finished = false; + + m_row[m_row_index].count = 0; + + while (!finished) + { + UINT16 data = read_word(m_sptr); + m_sptr += 2; + + if (BIT(data, 15)) + { + switch (data >> 8) + { + case 0x8e: + m_field_attribute_mask = read_word(m_sptr) & 0x7fff; + m_sptr += 2; + + if (VERBOSE_DATASTREAM) + logerror("%s('%s'): SET FIELD ATTRIB to %04x\n", shortname(), basetag(), m_field_attribute_mask); + + break; + + default: + fatalerror("%s('%s'): Unimplemented datastream command %02x\n", shortname(), basetag(), data >> 8); + } + } + else + { + // maximum row size is 200 + if (m_row[m_row_index].count < m_max_dma_count && m_row[m_row_index].count < 200) + { + m_row[m_row_index].data[m_row[m_row_index].count++] = data; + } + else + { +#if 0 + // move to next string? + if (m_auto_line_feed == 0) + { + m_sptr = (read_word(m_lptr + 2) << 16) | read_word(m_lptr); + m_lptr += 4; + } +#endif + finished = true; + } + } + } + + m_sptr -= 2; +} + +TIMER_CALLBACK_MEMBER( i82730_device::row_update ) +{ + int y = m_screen->vpos(); + + if (y == 0) + { + // clear interrupt status flags + m_status &= (VDIP | DIP); + + // clear field attribute mask + m_field_attribute_mask = 0; + + // get listbase + if (m_list_switch) + m_lptr = (read_word(m_cbp + 8) << 16) | read_word(m_cbp + 6); + else + m_lptr = (read_word(m_cbp + 12) << 16) | read_word(m_cbp + 10); + + m_sptr = (read_word(m_lptr + 2) << 16) | read_word(m_lptr); + m_lptr += 4; + + // fetch initial row + m_row_index = 0; + load_row(); + } + else if (y >= m_vsyncstp && y < m_vfldstrt) + { + // blank (top border) + } + else if (y >= m_vfldstrt && y < m_vfldstp) + { + UINT8 lc = (y - m_vfldstrt) % (m_lpr + 1); + + // call driver + m_update_row_cb(m_bitmap, m_row[m_row_index].data, lc, y - m_vsyncstp, m_row[m_row_index].count); + + // swap buffers at end of row + if (lc == m_lpr) + { + m_row_index ^= 1; + load_row(); + } + } + else if (y >= m_vfldstp && y < m_vfldstp + m_margin + 1) + { + // margin + } + else if (y >= m_vfldstp + m_margin + 1 && y < m_vfldstp + m_margin + 1 + m_lpr + 1) + { + UINT8 lc = (y - (m_vfldstp + m_margin + 1)) % (m_lpr + 1); + + m_sptr = (read_word(m_cbp + 36) << 16) | read_word(m_cbp + 34); + load_row(); + + // call driver + m_update_row_cb(m_bitmap, m_row[m_row_index].data, lc, y - m_vsyncstp, m_row[m_row_index].count); + } + else if (y == m_vfldstp + m_margin + 1 + m_lpr + 1) + { + // todo: check ca + + // frame interrupt? + if ((m_screen->frame_number() % m_frame_int_count) == 0) + m_status |= EONF; + + // check interrupts + update_interrupts(); + } + else + { + // vblank + } + + m_row_timer->adjust(m_screen->time_until_pos((y + 1) % m_screen->height())); +} + +WRITE_LINE_MEMBER( i82730_device::ca_w ) +{ + if (VERBOSE) + logerror("%s('%s'): ca_w %d\n", shortname(), basetag(), state); + + // falling edge + if (m_ca == 1 && state == 0) + { + if (!m_initialized) + { + // get system bus width + m_sysbus = m_program->read_byte(0xfffffff6); + + // get intermediate block pointer + m_ibp = (read_word(0xfffffffe) << 16) | read_word(0xfffffffc); + + // get system configuration byte + UINT8 scb = read_byte(m_ibp + 6); + + // clear busy + write_word(m_ibp, read_word(m_ibp) & 0xff00); + + // done + m_initialized = true; + + // output some debug info + if (VERBOSE) + { + logerror("%s('%s'): ---- initializing ----\n", shortname(), basetag()); + logerror("%s('%s'): %s system bus\n", shortname(), basetag(), sysbus_16bit() ? "16-bit" : "8-bit"); + logerror("%s('%s'): intermediate block pointer: %08x\n", shortname(), basetag(), m_ibp); + logerror("%s('%s'): addrbus: %s, clno: %d, clpos: %d, mode: %s, dtw16: %s, srdy: %s\n", shortname(), basetag(), + BIT(scb, 0) ? "32-bit" : "16-bit", (scb >> 1) & 0x03, (scb >> 3) & 0x03, + BIT(scb, 5) ? "master" : "slave", BIT(scb, 6) ? "16-bit" : "8-bit", BIT(scb, 7) ? "synchronous" : "asynchronous"); + } + } + + // fetch command block pointer + m_cbp = (read_word(m_ibp + 4) << 16) | read_word(m_ibp + 2); + + // and execute command + execute_command(); + } + + m_ca = state; +} + +WRITE_LINE_MEMBER( i82730_device::irst_w ) +{ + if (VERBOSE) + logerror("%s('%s'): irst_w %d\n", shortname(), basetag(), state); + + m_sint_handler(0); +} + +UINT32 i82730_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + copybitmap(bitmap, m_bitmap, 0, 0, m_hfldstrt * 16, 0, cliprect); + return 0; +} diff --git a/src/devices/video/i82730.h b/src/devices/video/i82730.h new file mode 100644 index 00000000000..ff2602d2307 --- /dev/null +++ b/src/devices/video/i82730.h @@ -0,0 +1,157 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best +/*************************************************************************** + + Intel 82730 + + Text Coprocessor + +***************************************************************************/ + +#pragma once + +#ifndef __I82730_H__ +#define __I82730_H__ + +#include "emu.h" + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_I82730_ADD(_tag, _cpu_tag, _clock) \ + MCFG_DEVICE_ADD(_tag, I82730, _clock) \ + i82730_device::set_cpu_tag(*device, owner, _cpu_tag); + +#define MCFG_I82730_SINT_HANDLER(_devcb) \ + devcb = &i82730_device::set_sint_handler(*device, DEVCB_##_devcb); + +#define MCFG_I82730_UPDATE_ROW_CB(_class, _method) \ + i82730_device::set_update_row_callback(*device, i82730_update_row_delegate(&_class::_method, #_class "::" #_method, downcast<_class *>(owner))); + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +typedef device_delegate i82730_update_row_delegate; + +#define I82730_UPDATE_ROW(name) \ + void name(bitmap_rgb32 &bitmap, UINT16 *data, UINT8 lc, UINT16 y, int x_count) + + +// ======================> i82730_device + +class i82730_device : public device_t, public device_video_interface +{ +public: + // construction/destruction + i82730_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // callbacks + template static devcb_base &set_sint_handler(device_t &device, _Object object) + { return downcast(device).m_sint_handler.set_callback(object); } + + // inline configuration + static void set_cpu_tag(device_t &device, device_t *owner, const char *tag); + static void set_update_row_callback(device_t &device, i82730_update_row_delegate callback) { downcast(device).m_update_row_cb = callback; } + + UINT32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); + + DECLARE_WRITE_LINE_MEMBER(ca_w); + DECLARE_WRITE_LINE_MEMBER(irst_w); + +protected: + virtual void device_start(); + virtual void device_reset(); + +private: + // status + enum + { + DUR = 0x001, // data underrun + LPU = 0x002, // light pen update + DBOR = 0x004, // data buffer overrun + EONF = 0x008, // end of n frames + FDE = 0x010, // frame data error + RCC = 0x020, // reserved channel command executed + RDC = 0x040, // reserved data stream command executed + DIP = 0x080, // display in progress + VDIP = 0x100 // virtual display in progress + }; + + static const char* m_command_names[]; + + bool sysbus_16bit() { return BIT(m_sysbus, 0); } + + UINT8 read_byte(offs_t address); + UINT16 read_word(offs_t address); + void write_byte(offs_t address, UINT8 data); + void write_word(offs_t address, UINT16 data); + + void update_interrupts(); + void mode_set(); + void execute_command(); + void load_row(); + + TIMER_CALLBACK_MEMBER(row_update); + + devcb_write_line m_sint_handler; + i82730_update_row_delegate m_update_row_cb; + + const char *m_cpu_tag; + address_space *m_program; + + emu_timer *m_row_timer; + + bitmap_rgb32 m_bitmap; + + bool m_initialized; + bool m_mode_set; + + int m_ca; + + // internal registers + UINT8 m_sysbus; + UINT32 m_ibp; + UINT32 m_cbp; + UINT16 m_intmask; + UINT16 m_status; + + int m_list_switch; + int m_auto_line_feed; + UINT8 m_max_dma_count; + + UINT32 m_lptr; + UINT32 m_sptr; + + int m_dma_burst_space; + int m_dma_burst_length; + + // display parameters + int m_hfldstrt; + int m_margin; + int m_lpr; + UINT16 m_field_attribute_mask; + int m_vsyncstp; + int m_vfldstrt; + int m_vfldstp; + + int m_frame_int_count; + + // row buffers + struct row_buffer + { + UINT16 data[200]; + int count; + }; + + row_buffer m_row[2]; + int m_row_index; +}; + +// device type definition +extern const device_type I82730; + +#endif // __I82730_H__ diff --git a/src/devices/video/i8275.c b/src/devices/video/i8275.c new file mode 100644 index 00000000000..4f75d7cbc1a --- /dev/null +++ b/src/devices/video/i8275.c @@ -0,0 +1,691 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Intel 8275 Programmable CRT Controller emulation + +**********************************************************************/ + +/* + + TODO: + + - double spaced rows + +*/ + +#include "i8275.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define LOG 0 + + +const int DMA_BURST_SPACING[] = { 0, 7, 15, 23, 31, 39, 47, 55 }; + + +#define DOUBLE_SPACED_ROWS \ + BIT(m_param[REG_SCN1], 7) + +#define CHARACTERS_PER_ROW \ + ((m_param[REG_SCN1] & 0x7f) + 1) + +#define VRTC_ROW_COUNT \ + ((m_param[REG_SCN2] >> 5) + 1) + +#define CHARACTER_ROWS_PER_FRAME \ + ((m_param[REG_SCN2] & 0x3f) + 1) + +#define UNDERLINE \ + (m_param[REG_SCN3] >> 4) + +#define SCANLINES_PER_ROW \ + ((m_param[REG_SCN3] & 0x0f) + 1) + +#define OFFSET_LINE_COUNTER \ + BIT(m_param[REG_SCN4], 7) + +#define VISIBLE_FIELD_ATTRIBUTE \ + BIT(m_param[REG_SCN4], 6) + +#define CURSOR_FORMAT \ + ((m_param[REG_SCN4] >> 4) & 0x03) + +#define HRTC_COUNT \ + (((m_param[REG_SCN4] & 0x0f) + 1) * 2) + +#define DMA_BURST_COUNT \ + (1 << (m_param[REG_DMA] & 0x03)) + +#define DMA_BURST_SPACE \ + DMA_BURST_SPACING[(m_param[REG_DMA] >> 2) & 0x07] + + +const int i8275_device::character_attribute[3][16] = +{ + { 2, 2, 4, 4, 2, 4, 4, 4, 2, 4, 4, 0, 2, 0, 0, 0 }, + { 8, 0xc, 8, 0xc, 1, 0xc, 8, 1, 1, 4, 1, 0, 2, 0, 0, 0 }, + { 4, 4, 2, 2, 4, 4, 4, 2, 2, 4, 4, 0, 2, 0, 0, 0 } +}; + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +// device type definition +const device_type I8275 = &device_creator; + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// i8275_device - constructor +//------------------------------------------------- + +i8275_device::i8275_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, I8275, "I8275 CRTC", tag, owner, clock, "i8275x", __FILE__), + device_video_interface(mconfig, *this), + m_write_irq(*this), + m_write_drq(*this), + m_write_hrtc(*this), + m_write_vrtc(*this), + m_status(0), + m_param_idx(0), + m_param_end(0), + m_buffer_idx(0), + m_fifo_next(false), + m_buffer_dma(0), + m_lpen(0), + m_hlgt(0), + m_vsp(0), + m_gpa(0), + m_rvv(0), + m_lten(0), + m_scanline(0), + m_du(false), + m_dma_stop(false), + m_end_of_screen(false), + m_cursor_blink(0), + m_char_blink(0), + m_stored_attr(0) +{ + memset(m_param, 0x00, sizeof(m_param)); +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void i8275_device::device_start() +{ + // get the screen device + m_screen->register_screen_bitmap(m_bitmap); + + // resolve callbacks + m_display_cb.bind_relative_to(*owner()); + m_write_drq.resolve_safe(); + m_write_irq.resolve_safe(); + m_write_hrtc.resolve_safe(); + m_write_vrtc.resolve_safe(); + + // allocate timers + m_hrtc_on_timer = timer_alloc(TIMER_HRTC_ON); + m_drq_on_timer = timer_alloc(TIMER_DRQ_ON); + m_scanline_timer = timer_alloc(TIMER_SCANLINE); + + // state saving + save_item(NAME(m_status)); + save_item(NAME(m_param)); + save_item(NAME(m_param_idx)); + save_item(NAME(m_param_end)); + save_item(NAME(m_buffer[0])); + save_item(NAME(m_buffer[1])); + save_item(NAME(m_buffer_idx)); + save_item(NAME(m_fifo_idx)); + save_item(NAME(m_fifo_next)); + save_item(NAME(m_buffer_dma)); + save_item(NAME(m_lpen)); + save_item(NAME(m_hlgt)); + save_item(NAME(m_vsp)); + save_item(NAME(m_gpa)); + save_item(NAME(m_rvv)); + save_item(NAME(m_lten)); + save_item(NAME(m_scanline)); + save_item(NAME(m_irq_scanline)); + save_item(NAME(m_vrtc_scanline)); + save_item(NAME(m_vrtc_drq_scanline)); + save_item(NAME(m_du)); + save_item(NAME(m_dma_stop)); + save_item(NAME(m_end_of_screen)); + save_item(NAME(m_cursor_blink)); + save_item(NAME(m_char_blink)); + save_item(NAME(m_stored_attr)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void i8275_device::device_reset() +{ + memset(m_buffer, 0, sizeof(m_buffer)); + + m_status &= ~ST_IE; + + m_write_irq(CLEAR_LINE); +} + + +//------------------------------------------------- +// device_timer - handle timer events +//------------------------------------------------- + +void i8275_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + //int y = m_screen->vpos(); + //int x = m_screen->hpos(); + int rc = m_scanline / SCANLINES_PER_ROW; + int lc = m_scanline % SCANLINES_PER_ROW; + + switch (id) + { + case TIMER_HRTC_ON: + //if (LOG) logerror("I8275 '%s' y %u x %u HRTC 1\n", tag(), y, x); + m_write_hrtc(1); + break; + + case TIMER_DRQ_ON: + //if (LOG) logerror("I8275 '%s' y %u x %u DRQ 1\n", tag(), y, x); + m_write_drq(1); + break; + + case TIMER_SCANLINE: + if (!(m_status & ST_VE)) break; + + //if (LOG) logerror("I8275 '%s' y %u x %u HRTC 0\n", tag(), y, x); + m_write_hrtc(0); + + if (m_scanline == 0) + { + //if (LOG) logerror("I8275 '%s' y %u x %u VRTC 0\n", tag(), y, x); + m_write_vrtc(0); + } + + if (m_scanline <= (m_vrtc_scanline - SCANLINES_PER_ROW)) + { + if (lc == 0) + { + if (m_buffer_idx < CHARACTERS_PER_ROW) + { + m_status |= ST_DU; + m_du = true; + + //if (LOG) logerror("I8275 '%s' y %u x %u DMA Underrun\n", tag(), y, x); + + m_write_drq(0); + } + + if (!m_du && !m_dma_stop) + { + // swap line buffers + m_buffer_dma = !m_buffer_dma; + m_buffer_idx = 0; + m_fifo_idx = 0; + + if ((m_scanline < (m_vrtc_scanline - SCANLINES_PER_ROW))) + { + // start DMA burst + m_drq_on_timer->adjust(clocks_to_attotime(DMA_BURST_SPACE)); + } + } + } + } + + if (m_scanline == m_irq_scanline) + { + if (m_status & ST_IE) + { + //if (LOG) logerror("I8275 '%s' y %u x %u IRQ 1\n", tag(), y, x); + m_status |= ST_IR; + m_write_irq(ASSERT_LINE); + } + } + + if (m_scanline == m_vrtc_scanline) + { + //if (LOG) logerror("I8275 '%s' y %u x %u VRTC 1\n", tag(), y, x); + m_write_vrtc(1); + + // reset field attributes + m_hlgt = 0; + m_vsp = 0; + m_gpa = 0; + m_rvv = 0, + m_lten = 0; + + m_du = false; + m_dma_stop = false; + m_end_of_screen = false; + + m_cursor_blink++; + m_cursor_blink &= 0x1f; + + m_char_blink++; + m_char_blink &= 0x3f; + m_stored_attr = 0; + } + + if (m_scanline == m_vrtc_drq_scanline) + { + // swap line buffers + m_buffer_dma = !m_buffer_dma; + m_buffer_idx = 0; + m_fifo_idx = 0; + + // start DMA burst + m_drq_on_timer->adjust(clocks_to_attotime(DMA_BURST_SPACE)); + } + + if (m_scanline < m_vrtc_scanline) + { + int line_counter = OFFSET_LINE_COUNTER ? ((lc - 1) % SCANLINES_PER_ROW) : lc; + bool end_of_row = false; + int fifo_idx = 0; + m_hlgt = (m_stored_attr & FAC_H) ? 1 : 0; + m_vsp = (m_stored_attr & FAC_B) ? 1 : 0; + m_gpa = (m_stored_attr & FAC_GG) >> 2; + m_rvv = (m_stored_attr & FAC_R) ? 1 : 0; + m_lten = ((m_stored_attr & FAC_U) != 0) && (lc == UNDERLINE) ? 1 : 0; + + for (int sx = 0; sx < CHARACTERS_PER_ROW; sx++) + { + int m_lineattr = 0; + int lten = 0; + int vsp = 0; + int rvv = 0; + + UINT8 data = (end_of_row || m_end_of_screen) ? 0 : m_buffer[!m_buffer_dma][sx]; + + if (data & 0x80) + { + if ((data & 0xc0) == 0x80) + { + // field attribute code + m_hlgt = (data & FAC_H) ? 1 : 0; + m_vsp = (data & FAC_B) ? 1 : 0; + m_gpa = (data & FAC_GG) >> 2; + m_rvv = (data & FAC_R) ? 1 : 0; + m_lten = ((data & FAC_U) != 0) && (lc == UNDERLINE) ? 1 : 0; + if ((SCANLINES_PER_ROW - lc)==1) + m_stored_attr = data; + + if (!VISIBLE_FIELD_ATTRIBUTE) + { + data = m_fifo[!m_buffer_dma][fifo_idx]; + + fifo_idx++; + fifo_idx &= 0xf; + } + else + { + vsp = 1; + } + } + else + { + if ((data & 0xf0) == 0xf0) + { + // special control character + switch (data) + { + case SCC_END_OF_ROW: + case SCC_END_OF_ROW_DMA: + end_of_row = true; + break; + + case SCC_END_OF_SCREEN: + case SCC_END_OF_SCREEN_DMA: + m_end_of_screen = true; + break; + } + //vsp = 1; + } + else + { + // character attribute code + m_hlgt = (data & CA_H) ? 1 : 0; + m_vsp = (data & CA_B) ? 1 : 0; + + UINT8 ca = 0; + int cccc = (data >> 2) & 0x0f; + + if (line_counter < UNDERLINE) + { + ca = character_attribute[0][cccc]; + } + else if (line_counter == UNDERLINE) + { + ca = character_attribute[1][cccc]; + } + else + { + ca = character_attribute[2][cccc]; + } + + m_lten = (ca & CA_LTEN) ? 1 : 0; + m_vsp = (ca & CA_VSP) ? 1 : 0; + m_lineattr = ca >> 2; + } + } + } + + if (!vsp && m_vsp) + { + vsp = (m_char_blink < 32) ? 1 : 0; + } + + if ((rc == m_param[REG_CUR_ROW]) && (sx == m_param[REG_CUR_COL])) + { + int vis = 1; + + if (!(CURSOR_FORMAT & 0x02)) + { + vis = (m_cursor_blink < 16) ? 1 : 0; + } + + if (CURSOR_FORMAT & 0x01) + { + lten = (lc == UNDERLINE) ? vis : 0; + } + else + { + rvv = vis; + } + } + + if (end_of_row || m_end_of_screen) + { + vsp = 1; + } + + if (!m_display_cb.isnull()) + m_display_cb(m_bitmap, + sx * m_hpixels_per_column, // x position on screen of starting point + m_scanline, // y position on screen + line_counter, // current line of char + (data & 0x7f), // char code to be displayed + m_lineattr, // line attribute code + lten | m_lten, // light enable signal + rvv ^ m_rvv, // reverse video signal + vsp, // video suppression + m_gpa, // general purpose attribute code + m_hlgt // highlight + ); + } + } + + m_scanline++; + m_scanline %= ((CHARACTER_ROWS_PER_FRAME + VRTC_ROW_COUNT) * SCANLINES_PER_ROW); + break; + } +} + + +//------------------------------------------------- +// read - +//------------------------------------------------- + +READ8_MEMBER( i8275_device::read ) +{ + UINT8 data = 0; + + if (offset & 0x01) + { + data = m_status; + + if (m_status & ST_IR) + { + //if (LOG) logerror("I8275 '%s' IRQ 0\n", tag()); + m_write_irq(CLEAR_LINE); + } + + m_status &= ~(ST_IR | ST_LP | ST_IC | ST_DU | ST_FO); + } + else + { + data = m_param[m_param_idx]; + m_param_idx++; + + if (m_param_idx > m_param_end) + { + m_status |= ST_IC; + } + } + + return data; +} + + +//------------------------------------------------- +// write - +//------------------------------------------------- + +WRITE8_MEMBER( i8275_device::write ) +{ + if (offset & 0x01) + { + if (LOG) logerror("I8275 '%s' Command %02x\n", tag(), data); + + switch (data >> 5) + { + case CMD_RESET: + if (LOG) logerror("I8275 '%s' Reset\n", tag()); + + m_status &= ~ST_IE; + if (LOG) logerror("I8275 '%s' IRQ 0\n", tag()); + m_write_irq(CLEAR_LINE); + m_write_drq(0); + + m_param_idx = REG_SCN1; + m_param_end = REG_SCN4; + break; + + case CMD_START_DISPLAY: + { + m_param[REG_DMA] = data; + if (LOG) logerror("I8275 '%s' Start Display %u %u\n", tag(), DMA_BURST_COUNT, DMA_BURST_SPACE); + m_status |= (ST_IE | ST_VE); + } + break; + + case CMD_STOP_DISPLAY: + if (LOG) logerror("I8275 '%s' Stop Display\n", tag()); + m_status &= ~ST_VE; + break; + + case CMD_READ_LIGHT_PEN: + if (LOG) logerror("I8275 '%s' Read Light Pen\n", tag()); + m_param_idx = REG_LPEN_COL; + m_param_end = REG_LPEN_ROW; + break; + + case CMD_LOAD_CURSOR: + if (LOG) logerror("I8275 '%s' Load Cursor\n", tag()); + m_param_idx = REG_CUR_COL; + m_param_end = REG_CUR_ROW; + break; + + case CMD_ENABLE_INTERRUPT: + if (LOG) logerror("I8275 '%s' Enable Interrupt\n", tag()); + m_status |= ST_IE; + break; + + case CMD_DISABLE_INTERRUPT: + if (LOG) logerror("I8275 '%s' Disable Interrupt\n", tag()); + m_status &= ~ST_IE; + break; + + case CMD_PRESET_COUNTERS: + if (LOG) logerror("I8275 '%s' Preset Counters\n", tag()); + m_scanline = 0; + break; + } + } + else + { + if (LOG) logerror("I8275 '%s' Parameter %02x\n", tag(), data); + + m_param[m_param_idx] = data; + + if (m_param_idx == REG_SCN4) + { + recompute_parameters(); + } + + m_param_idx++; + } +} + + +//------------------------------------------------- +// dack_w - +//------------------------------------------------- + +WRITE8_MEMBER( i8275_device::dack_w ) +{ + //if (LOG) logerror("I8275 '%s' y %u x %u DACK %04x:%02x %u\n", tag(), m_screen->vpos(), m_screen->hpos(), offset, data, m_buffer_idx); + + m_write_drq(0); + + if (m_fifo_next) + { + if (m_fifo_idx == 16) + { + m_fifo_idx = 0; + m_status |= ST_FO; + } + + m_fifo[m_buffer_dma][m_fifo_idx++] = data; + + m_fifo_next = false; + } + else + { + assert(m_buffer_idx >= 0 && m_buffer_idx < ARRAY_LENGTH(m_buffer[m_buffer_dma])); + m_buffer[m_buffer_dma][m_buffer_idx++] = data; + + if (!VISIBLE_FIELD_ATTRIBUTE && ((data & 0xc0) == 0x80)) + { + m_fifo_next = true; + } + + switch (data) + { + case SCC_END_OF_ROW_DMA: + // stop DMA + // TODO should read one more character if DMA burst not completed + break; + + case SCC_END_OF_SCREEN_DMA: + m_dma_stop = true; + // TODO should read one more character if DMA burst not completed + break; + + default: + if (m_buffer_idx == CHARACTERS_PER_ROW) + { + // stop DMA + } + else if (!(m_buffer_idx % DMA_BURST_COUNT)) + { + m_drq_on_timer->adjust(clocks_to_attotime(DMA_BURST_SPACE)); + } + else + { + m_drq_on_timer->adjust(attotime::zero); + } + } + + } +} + + +//------------------------------------------------- +// lpen_w - +//------------------------------------------------- + +WRITE_LINE_MEMBER( i8275_device::lpen_w ) +{ + if (!m_lpen && state) + { + m_param[REG_LPEN_COL] = m_screen->hpos() / m_hpixels_per_column; + m_param[REG_LPEN_ROW] = m_screen->vpos() / SCANLINES_PER_ROW; + + m_status |= ST_LP; + } + + m_lpen = state; +} + + +//------------------------------------------------- +// screen_update - +//------------------------------------------------- + +UINT32 i8275_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + if (!(m_status & ST_VE)) + { + m_bitmap.fill(rgb_t::black); + } + + copybitmap(bitmap, m_bitmap, 0, 0, 0, 0, cliprect); + + return 0; +} + + +//------------------------------------------------- +// recompute_parameters - +//------------------------------------------------- + +void i8275_device::recompute_parameters() +{ + int y = m_screen->vpos(); + + int horiz_pix_total = (CHARACTERS_PER_ROW + HRTC_COUNT) * m_hpixels_per_column; + int vert_pix_total = (CHARACTER_ROWS_PER_FRAME + VRTC_ROW_COUNT) * SCANLINES_PER_ROW; + attoseconds_t refresh = m_screen->frame_period().attoseconds(); + int max_visible_x = (CHARACTERS_PER_ROW * m_hpixels_per_column) - 1; + int max_visible_y = (CHARACTER_ROWS_PER_FRAME * SCANLINES_PER_ROW) - 1; + + if (LOG) logerror("width %u height %u max_x %u max_y %u refresh %f\n", horiz_pix_total, vert_pix_total, max_visible_x, max_visible_y, 1 / ATTOSECONDS_TO_DOUBLE(refresh)); + + rectangle visarea; + visarea.set(0, max_visible_x, 0, max_visible_y); + m_screen->configure(horiz_pix_total, vert_pix_total, visarea, refresh); + + int hrtc_on_pos = CHARACTERS_PER_ROW * m_hpixels_per_column; + m_hrtc_on_timer->adjust(m_screen->time_until_pos(y, hrtc_on_pos), 0, m_screen->scan_period()); + + m_irq_scanline = (CHARACTER_ROWS_PER_FRAME - 1) * SCANLINES_PER_ROW; + m_vrtc_scanline = CHARACTER_ROWS_PER_FRAME * SCANLINES_PER_ROW; + m_vrtc_drq_scanline = vert_pix_total - SCANLINES_PER_ROW; + + if (LOG) logerror("irq_y %u vrtc_y %u drq_y %u\n", m_irq_scanline, m_vrtc_scanline, m_vrtc_drq_scanline); + + m_scanline_timer->adjust(m_screen->time_until_pos(0, 0), 0, m_screen->scan_period()); + + if (DOUBLE_SPACED_ROWS) fatalerror("Double spaced rows not supported!"); +} diff --git a/src/devices/video/i8275.h b/src/devices/video/i8275.h new file mode 100644 index 00000000000..15451d4c7e8 --- /dev/null +++ b/src/devices/video/i8275.h @@ -0,0 +1,236 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Intel 8275 Programmable CRT Controller emulation + +********************************************************************** + _____ _____ + LC3 1 |* \_/ | 40 Vcc + LC2 2 | | 39 LA0 + LC1 3 | | 38 LA1 + LC0 4 | | 37 LTEN + DRQ 5 | | 36 RVV + _DACK 6 | | 35 VSP + HRTC 7 | | 34 GPA1 + VRTC 8 | | 33 GPA0 + _RD 9 | | 32 HLGT + _WR 10 | 8275 | 31 IRQ + LPEN 11 | | 30 CCLK + DB0 12 | | 29 CC6 + DB1 13 | | 28 CC5 + DB2 14 | | 27 CC4 + DB3 15 | | 26 CC3 + DB4 16 | | 25 CC2 + DB5 17 | | 24 CC1 + DB6 18 | | 23 CC0 + DB7 19 | | 22 _CS + GND 20 |_____________| 21 A0 + +**********************************************************************/ + +#pragma once + +#ifndef __I8275x__ +#define __I8275x__ + +#include "emu.h" + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define I8275_DRAW_CHARACTER_MEMBER(_name) void _name(bitmap_rgb32 &bitmap, int x, int y, UINT8 linecount, UINT8 charcode, UINT8 lineattr, UINT8 lten, UINT8 rvv, UINT8 vsp, UINT8 gpa, UINT8 hlgt) + + +#define MCFG_I8275_CHARACTER_WIDTH(_value) \ + i8275_device::static_set_character_width(*device, _value); + +#define MCFG_I8275_DRAW_CHARACTER_CALLBACK_OWNER(_class, _method) \ + i8275_device::static_set_display_callback(*device, i8275_draw_character_delegate(&_class::_method, #_class "::" #_method, downcast<_class *>(owner))); + +#define MCFG_I8275_DRQ_CALLBACK(_write) \ + devcb = &i8275_device::set_drq_wr_callback(*device, DEVCB_##_write); + +#define MCFG_I8275_IRQ_CALLBACK(_write) \ + devcb = &i8275_device::set_irq_wr_callback(*device, DEVCB_##_write); + +#define MCFG_I8275_HRTC_CALLBACK(_write) \ + devcb = &i8275_device::set_hrtc_wr_callback(*device, DEVCB_##_write); + +#define MCFG_I8275_VRTC_CALLBACK(_write) \ + devcb = &i8275_device::set_vrtc_wr_callback(*device, DEVCB_##_write); + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +typedef device_delegate i8275_draw_character_delegate; + + +// ======================> i8275_device + +class i8275_device : public device_t, + public device_video_interface +{ +public: + // construction/destruction + i8275_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + static void static_set_character_width(device_t &device, int value) { downcast(device).m_hpixels_per_column = value; } + static void static_set_display_callback(device_t &device, i8275_draw_character_delegate callback) { downcast(device).m_display_cb = callback; } + + template static devcb_base &set_drq_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_drq.set_callback(object); } + template static devcb_base &set_irq_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_irq.set_callback(object); } + template static devcb_base &set_hrtc_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_hrtc.set_callback(object); } + template static devcb_base &set_vrtc_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_vrtc.set_callback(object); } + + DECLARE_READ8_MEMBER( read ); + DECLARE_WRITE8_MEMBER( write ); + + DECLARE_WRITE8_MEMBER( dack_w ); + + DECLARE_WRITE_LINE_MEMBER( lpen_w ); + + UINT32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + void recompute_parameters(); + + enum + { + TIMER_HRTC_ON, + TIMER_DRQ_ON, + TIMER_SCANLINE + }; + + enum + { + ST_IE = 0x40, + ST_IR = 0x20, + ST_LP = 0x10, + ST_IC = 0x08, + ST_VE = 0x04, + ST_DU = 0x02, + ST_FO = 0x01 + }; + + enum + { + CMD_RESET = 0, + CMD_START_DISPLAY, + CMD_STOP_DISPLAY, + CMD_READ_LIGHT_PEN, + CMD_LOAD_CURSOR, + CMD_ENABLE_INTERRUPT, + CMD_DISABLE_INTERRUPT, + CMD_PRESET_COUNTERS + }; + + enum + { + REG_SCN1 = 0, + REG_SCN2, + REG_SCN3, + REG_SCN4, + REG_CUR_COL, + REG_CUR_ROW, + REG_LPEN_COL, + REG_LPEN_ROW, + REG_DMA + }; + + enum + { + CA_H = 0x01, + CA_B = 0x02, + CA_CCCC = 0x3c, + CA_LTEN = 0x01, + CA_VSP = 0x02, + CA_LA0 = 0x04, + CA_LA1 = 0x08 + }; + + enum + { + SCC_END_OF_ROW = 0xf0, + SCC_END_OF_ROW_DMA = 0xf1, + SCC_END_OF_SCREEN = 0xf2, + SCC_END_OF_SCREEN_DMA = 0xf3 + }; + + enum + { + FAC_H = 0x01, + FAC_B = 0x02, + FAC_GG = 0x0c, + FAC_R = 0x10, + FAC_U = 0x20 + }; + + static const int character_attribute[3][16]; + + devcb_write_line m_write_irq; + devcb_write_line m_write_drq; + devcb_write_line m_write_hrtc; + devcb_write_line m_write_vrtc; + + i8275_draw_character_delegate m_display_cb; + int m_hpixels_per_column; + + bitmap_rgb32 m_bitmap; + + UINT8 m_status; + UINT8 m_param[REG_DMA + 1]; + int m_param_idx; + int m_param_end; + + UINT8 m_buffer[2][80]; + UINT8 m_fifo[2][16]; + int m_buffer_idx; + int m_fifo_idx; + bool m_fifo_next; + int m_buffer_dma; + + int m_lpen; + + int m_hlgt; + int m_vsp; + int m_gpa; + int m_rvv; + int m_lten; + + int m_scanline; + int m_irq_scanline; + int m_vrtc_scanline; + int m_vrtc_drq_scanline; + bool m_du; + bool m_dma_stop; + bool m_end_of_screen; + + int m_cursor_blink; + int m_char_blink; + UINT8 m_stored_attr; + + // timers + emu_timer *m_hrtc_on_timer; + emu_timer *m_drq_on_timer; + emu_timer *m_scanline_timer; +}; + + +// device type definition +extern const device_type I8275; + + + +#endif diff --git a/src/devices/video/m50458.c b/src/devices/video/m50458.c new file mode 100644 index 00000000000..1db8b57aaf0 --- /dev/null +++ b/src/devices/video/m50458.c @@ -0,0 +1,449 @@ +// license:LGPL-2.1+ +// copyright-holders:Angelo Salese +/*************************************************************************** + + Mitsubishi M50458 OSD chip + + device by Angelo Salese + + TODO: + - vertical scrolling needs references (might work differently and/or in + "worse" ways, the one currently implemented guesses that the screen is + masked at the top and the end when in scrolling mode). + - Understand what the "vertical start position" really does (vblank?) + - Check if the ROM source is actually 2bpp once that a redump is made + (the shadow ROM copy doesn't convince me 100%); + +***************************************************************************/ + +#include "emu.h" +#include "video/m50458.h" + + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +// device type definition +const device_type M50458 = &device_creator; + +static ADDRESS_MAP_START( m50458_vram, AS_0, 16, m50458_device ) + AM_RANGE(0x0000, 0x023f) AM_RAM // vram + AM_RANGE(0x0240, 0x0241) AM_WRITE(vreg_120_w) + AM_RANGE(0x0242, 0x0243) AM_WRITE(vreg_121_w) + AM_RANGE(0x0244, 0x0245) AM_WRITE(vreg_122_w) + AM_RANGE(0x0246, 0x0247) AM_WRITE(vreg_123_w) + AM_RANGE(0x0248, 0x0249) AM_WRITE(vreg_124_w) + AM_RANGE(0x024a, 0x024b) AM_WRITE(vreg_125_w) + AM_RANGE(0x024c, 0x024d) AM_WRITE(vreg_126_w) + AM_RANGE(0x024e, 0x024f) AM_WRITE(vreg_127_w) +ADDRESS_MAP_END + +// internal GFX ROM (TODO: GFXs in here should be 12x18, not 16x18) +// (also note: ROM length CAN'T be 0x1200) +ROM_START( m50458 ) + ROM_REGION( 0x1200, "m50458", 0 ) + ROM_LOAD("m50458-001sp", 0x0000, 0x1200, BAD_DUMP CRC(444f597d) SHA1(96beda6aba3d9f7bb781a3cd0352ed6ae45e2ebe) ) + ROM_LOAD("m50458_char.bin", 0x0000, 0x1200, BAD_DUMP CRC(011cc342) SHA1(d5b9f32d6e251b4b25945267d7c68c099bd83e96) ) +ROM_END + +WRITE16_MEMBER( m50458_device::vreg_120_w) +{ +// printf("%04x\n",data); +} + +WRITE16_MEMBER( m50458_device::vreg_121_w) +{ + /* Horizontal char size for line 0 */ + m_hsz1 = (data & 0xc0) >> 6; + + /* Horizontal char size for line 1 - 10 */ + m_hsz2 = (data & 0x300) >> 8; + + /* Horizontal char size for line 11 */ + m_hsz3 = (data & 0xc00) >> 10; +} + + +WRITE16_MEMBER( m50458_device::vreg_122_w) +{ + /* Vertical char size for line 0 */ + m_vsz1 = (data & 0xc0) >> 6; + + /* Vertical char size for line 1 - 10 */ + m_vsz2 = (data & 0x300) >> 8; + + /* Vertical char size for line 11 */ + m_vsz3 = (data & 0xc00) >> 10; + +} + +WRITE16_MEMBER( m50458_device::vreg_123_w) +{ + /* fractional part of vertical scrolling */ + m_scrf = data & 0x1f; + + m_space = (data & 0x60) >> 5; + + /* char part of vertical scrolling */ + m_scrr = (data & 0x0f00) >> 8; + +// printf("%02x %02x %02x\n",m_scrr,m_scrf,m_space); +} + +WRITE16_MEMBER( m50458_device::vreg_124_w) +{ +} + +WRITE16_MEMBER( m50458_device::vreg_125_w) +{ + /* blinking cycle */ + m_blink = data & 4 ? 0x20 : 0x40; +} + +WRITE16_MEMBER( m50458_device::vreg_126_w) +{ + /* Raster Color Setting */ + m_phase = data & 7; + + //printf("%04x\n",data); +} + + +WRITE16_MEMBER( m50458_device::vreg_127_w) +{ + if(data & 0x20) // RAMERS, display RAM is erased + { + int i; + + for(i=0;i<0x120;i++) + write_word(i,0x007f); + } +} + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *m50458_device::device_rom_region() const +{ + return ROM_NAME( m50458 ); +} + +//------------------------------------------------- +// memory_space_config - return a description of +// any address spaces owned by this device +//------------------------------------------------- + +const address_space_config *m50458_device::memory_space_config(address_spacenum spacenum) const +{ + return (spacenum == AS_0) ? &m_space_config : NULL; +} + +//************************************************************************** +// INLINE HELPERS +//************************************************************************** + +//------------------------------------------------- +// read_word - read a word at the given address +//------------------------------------------------- + +inline UINT16 m50458_device::read_word(offs_t address) +{ + return space().read_word(address << 1); +} + +//------------------------------------------------- +// write_word - write a word at the given address +//------------------------------------------------- + +inline void m50458_device::write_word(offs_t address, UINT16 data) +{ + space().write_word(address << 1, data); +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// m50458_device - constructor +//------------------------------------------------- + +m50458_device::m50458_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, M50458, "M50458 OSD", tag, owner, clock, "m50458", __FILE__), + device_memory_interface(mconfig, *this), + device_video_interface(mconfig, *this), + m_space_config("videoram", ENDIANNESS_LITTLE, 16, 16, 0, NULL, *ADDRESS_MAP_NAME(m50458_vram)) +{ +} + + +//------------------------------------------------- +// device_validity_check - perform validity checks +// on this device +//------------------------------------------------- + +void m50458_device::device_validity_check(validity_checker &valid) const +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void m50458_device::device_start() +{ + UINT16 tmp; + UINT8 *pcg = memregion("m50458")->base(); + int tile; + int yi; + UINT16 src,dst; + + /* Create an array for shadow gfx */ + /* this will spread the source ROM into four directions (up-left, up-right, down-left, down-right) thus creating a working shadow copy */ + m_shadow_gfx = auto_alloc_array_clear(machine(), UINT8, 0x1200); + + for(tile=0;tile<0x80;tile++) + { + for(yi=1;yi<17;yi++) + { + src = (tile & 0x7f)*36+yi*2; /* source offset */ + + dst = (tile & 0x7f)*36+(yi-1)*2; /* destination offset */ + + tmp = (((pcg[src]<<8)|(pcg[src+1]&0xff)) & 0xfffe) >> 1; + + m_shadow_gfx[dst+1] |= tmp & 0xff; + m_shadow_gfx[dst] |= (tmp >> 8); + + tmp = (((pcg[src]<<8)|(pcg[src+1]&0xff)) & 0x7fff) << 1; + + m_shadow_gfx[dst+1] |= tmp & 0xff; + m_shadow_gfx[dst] |= (tmp >> 8); + + dst = (tile & 0x7f)*36+(yi+1)*2; /* destination offset */ + + tmp = (((pcg[src]<<8)|(pcg[src+1]&0xff)) & 0xfffe) >> 1; + + m_shadow_gfx[dst+1] |= tmp & 0xff; + m_shadow_gfx[dst] |= (tmp >> 8); + + tmp = (((pcg[src]<<8)|(pcg[src+1]&0xff)) & 0x7fff) << 1; + + m_shadow_gfx[dst+1] |= tmp & 0xff; + m_shadow_gfx[dst] |= (tmp >> 8); + } + } +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void m50458_device::device_reset() +{ + int i; + + /* clear VRAM at boot */ + for(i=0;i<0x120;i++) + write_word(i,0x007f); + + m_blink = 0x40; +} + + +//************************************************************************** +// READ/WRITE HANDLERS +//************************************************************************** + +WRITE_LINE_MEMBER( m50458_device::write_bit ) +{ + m_latch = state; +} + +WRITE_LINE_MEMBER( m50458_device::set_cs_line ) +{ + m_reset_line = state; + + if(m_reset_line != CLEAR_LINE) + { + //printf("Reset asserted\n"); + m_cmd_stream_pos = 0; + m_current_cmd = 0; + m_osd_state = OSD_SET_ADDRESS; + } +} + + +WRITE_LINE_MEMBER( m50458_device::set_clock_line ) +{ + if (m_reset_line == CLEAR_LINE) + { + if(state == 1) + { + //printf("%d\n",m_latch); + + m_current_cmd = (m_current_cmd >> 1) | ((m_latch<<15)&0x8000); + m_cmd_stream_pos++; + + if(m_cmd_stream_pos == 16) + { + switch(m_osd_state) + { + case OSD_SET_ADDRESS: + m_osd_addr = m_current_cmd; + m_osd_state = OSD_SET_DATA; + break; + case OSD_SET_DATA: + //if(m_osd_addr >= 0x120) + //printf("%04x %04x\n",m_osd_addr,m_current_cmd); + write_word(m_osd_addr,m_current_cmd); + m_osd_addr++; + /* Presumably wraps at 0x127? */ + if(m_osd_addr > 0x127) { m_osd_addr = 0; } + break; + } + + m_cmd_stream_pos = 0; + m_current_cmd = 0; + } + } + } +} + +//------------------------------------------------- +// update_screen - +//------------------------------------------------- + +UINT32 m50458_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + int x,y; + UINT8 *pcg = memregion("m50458")->base(); + UINT8 bg_r,bg_g,bg_b; + + /* TODO: there's probably a way to control the brightness in this */ + bg_r = m_phase & 1 ? 0xdf : 0; + bg_g = m_phase & 2 ? 0xdf : 0; + bg_b = m_phase & 4 ? 0xdf : 0; + bitmap.fill(rgb_t(0xff,bg_r,bg_g,bg_b),cliprect); + + for(y=0;y<12;y++) + { + for(x=0;x<24;x++) + { + int xi,yi; + UINT16 tile; + int y_base = y; + + if(y != 0 && m_scrr > 1) { y_base+=(m_scrr - 1); } + if(y_base > 11) { y_base -= 11; } + if(m_scrr && y == 11) { y_base = 0; } /* Guess: repeat line 0 if scrolling is active */ + + tile = read_word(x+y_base*24); + + for(yi=0;yi<18;yi++) + { + for(xi=4;xi<16;xi++) /* TODO: remove 4 / 16 / -4 offset once that the ROM is fixed */ + { + UINT8 pix; + UINT8 color = (tile & 0x700) >> 8; + UINT16 offset = ((tile & 0x7f)*36+yi*2); + int res_y,res_x; + UINT8 xh,yh; + + if(xi>=8) + pix = ((pcg[offset+1] >> (7-(xi & 0x7))) & 1) << 1; + else + pix = ((pcg[offset+0] >> (7-(xi & 0x7))) & 1) << 1; + + if(xi>=8) + pix |= ((m_shadow_gfx[offset+1] >> (7-(xi & 0x7))) & 1); + else + pix |= ((m_shadow_gfx[offset+0] >> (7-(xi & 0x7))) & 1); + + /* blinking, VERY preliminary */ + if(tile & 0x800 && m_screen->frame_number() & m_blink) + pix = 0; + + if(yi == 17 && tile & 0x1000) /* underline? */ + pix |= 1; + + res_y = y*18+yi; + res_x = x*12+(xi-4); + + if(y != 0 && y != 11) + { + res_y -= m_scrf; + if(res_y < 18) /* wrap-around */ + res_y += 216; + } + + if(pix != 0) + { + UINT8 r,g,b; + + if(pix & 2) + { + r = (color & 0x1) ? 0xff : 0x00; + g = (color & 0x2) ? 0xff : 0x00; + b = (color & 0x4) ? 0xff : 0x00; + } + else //if(pix & 1) + { + /* TODO: is there a parameter for the border parameter? */ + r = 0x00; + g = 0x00; + b = 0x00; + } + + /* TODO: clean this up (also needs better testing) */ + if(y_base == 0) + { + res_x *= (m_hsz1 + 1); + res_y *= (m_vsz1 + 1); + + if(res_y > 215 || res_x > 288) + continue; + + for(yh=0;yh 215 || res_x > 288) + continue; + + for(yh=0;yh 215 || res_x > 288) + continue; + + for(yh=0;yh m50458_device + +class m50458_device : public device_t, + public device_memory_interface, + public device_video_interface +{ +public: + // construction/destruction + m50458_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // I/O operations + DECLARE_WRITE_LINE_MEMBER( write_bit ); + DECLARE_WRITE_LINE_MEMBER( set_cs_line ); + DECLARE_WRITE_LINE_MEMBER( set_clock_line ); + DECLARE_WRITE16_MEMBER(vreg_120_w); + DECLARE_WRITE16_MEMBER(vreg_121_w); + DECLARE_WRITE16_MEMBER(vreg_122_w); + DECLARE_WRITE16_MEMBER(vreg_123_w); + DECLARE_WRITE16_MEMBER(vreg_124_w); + DECLARE_WRITE16_MEMBER(vreg_125_w); + DECLARE_WRITE16_MEMBER(vreg_126_w); + DECLARE_WRITE16_MEMBER(vreg_127_w); + + UINT32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); + virtual const rom_entry *device_rom_region() const; + +protected: + // device-level overrides + virtual void device_validity_check(validity_checker &valid) const; + virtual void device_start(); + virtual void device_reset(); + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const; + + int m_latch; + int m_reset_line; + int m_clock_line; + UINT16 m_current_cmd; + int m_cmd_stream_pos; + UINT16 m_osd_addr; + UINT8 *m_shadow_gfx; + + UINT8 m_bg_pen; + UINT8 m_phase; + UINT8 m_scrf,m_scrr; + UINT8 m_space; + UINT8 m_hsz1,m_hsz2,m_hsz3; + UINT8 m_vsz1,m_vsz2,m_vsz3; + UINT8 m_blink; + + m50458_state_t m_osd_state; + +private: + inline UINT16 read_word(offs_t address); + inline void write_word(offs_t address, UINT16 data); + + const address_space_config m_space_config; +}; + + +// device type definition +extern const device_type M50458; + + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + + + +#endif diff --git a/src/devices/video/mb90082.c b/src/devices/video/mb90082.c new file mode 100644 index 00000000000..cefa4e60415 --- /dev/null +++ b/src/devices/video/mb90082.c @@ -0,0 +1,248 @@ +// license:LGPL-2.1+ +// copyright-holders:Angelo Salese +/*************************************************************************** + + Fujitsu MB90082 OSD + + preliminary device by Angelo Salese + + TODO: + - get a real charset ROM; + +***************************************************************************/ + +#include "emu.h" +#include "video/mb90082.h" + + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +// device type definition +const device_type MB90082 = &device_creator; + +static ADDRESS_MAP_START( mb90082_vram, AS_0, 16, mb90082_device ) + AM_RANGE(0x0000, 0x023f) AM_RAM // main screen vram + AM_RANGE(0x0400, 0x063f) AM_RAM // main screen attr +// AM_RANGE(0x0800, 0x0a3f) AM_RAM // sub screen vram +// AM_RANGE(0x0c00, 0x0e3f) AM_RAM // sub screen attr +ADDRESS_MAP_END + +/* charset is undumped, but apparently a normal ASCII one is enough for the time being (for example "fnt0808.x1" in Sharp X1) */ +ROM_START( mb90082 ) + ROM_REGION( 0x2000, "mb90082", ROMREGION_ERASEFF ) + ROM_LOAD("mb90082_char.bin", 0x0000, 0x0800, NO_DUMP ) +ROM_END + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *mb90082_device::device_rom_region() const +{ + return ROM_NAME( mb90082 ); +} + +//------------------------------------------------- +// memory_space_config - return a description of +// any address spaces owned by this device +//------------------------------------------------- + +const address_space_config *mb90082_device::memory_space_config(address_spacenum spacenum) const +{ + return (spacenum == AS_0) ? &m_space_config : NULL; +} + +//************************************************************************** +// INLINE HELPERS +//************************************************************************** + +//------------------------------------------------- +// readbyte - read a byte at the given address +//------------------------------------------------- + +inline UINT16 mb90082_device::read_word(offs_t address) +{ + return space().read_word(address << 1); +} + +//------------------------------------------------- +// writebyte - write a byte at the given address +//------------------------------------------------- + +inline void mb90082_device::write_word(offs_t address, UINT16 data) +{ + space().write_word(address << 1, data); +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// mb90082_device - constructor +//------------------------------------------------- + +mb90082_device::mb90082_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, MB90082, "MB90082 OSD", tag, owner, clock, "mb90082", __FILE__), + device_memory_interface(mconfig, *this), + m_space_config("videoram", ENDIANNESS_LITTLE, 16, 16, 0, NULL, *ADDRESS_MAP_NAME(mb90082_vram)) +{ +} + + +//------------------------------------------------- +// device_validity_check - perform validity checks +// on this device +//------------------------------------------------- + +void mb90082_device::device_validity_check(validity_checker &valid) const +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void mb90082_device::device_start() +{ +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void mb90082_device::device_reset() +{ + m_cmd_ff = 0; +} + + +//************************************************************************** +// READ/WRITE HANDLERS +//************************************************************************** + +WRITE_LINE_MEMBER( mb90082_device::set_cs_line ) +{ + m_reset_line = state; + + if(m_reset_line != CLEAR_LINE) + { + // ... + } +} + + +WRITE8_MEMBER( mb90082_device::write ) +{ + UINT16 dat; + + switch(m_cmd_ff) + { + case OSD_COMMAND: + m_cmd = data & 0xf8; + m_cmd_param = data & 7; + //printf("cmd %02x\n",data); + break; + case OSD_DATA: + dat = ((m_cmd_param & 7)<<7) | (data & 0x7f); + switch(m_cmd) + { + case 0x80: // Preset VRAM address + m_osd_addr = dat & 0x1ff; + m_fil = (dat & 0x200) >> 9; + break; + case 0x88: // Attribute select + m_attr = dat; + break; + case 0x90: // Write Character + int x,y; + x = (m_osd_addr & 0x01f); + y = (m_osd_addr & 0x1e0) >> 5; + + if(m_fil) + { + int i; + if(x != 0) + printf("FIL with %d %d\n",x,y); + + for(i=0;i<24;i++) + { + write_word((i+y*24)|0x000,dat); + write_word((i+y*24)|0x200,m_attr); + } + } + else + { + write_word((x+y*24)|0x000,dat); + write_word((x+y*24)|0x200,m_attr); + + /* handle address increments */ + x = ((x + 1) % 24); + if(x == 0) + y = ((y + 1) % 12); + m_osd_addr = x + (y << 5); + } + break; + case 0xd0: // Set Under Color + m_uc = dat & 7; + break; + + } + break; + } + + m_cmd_ff ^= 1; +} + +UINT32 mb90082_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + int x,y; + UINT8 *pcg = memregion("mb90082")->base(); + UINT16 tile,attr; + UINT8 bg_r,bg_g,bg_b; + + /* TODO: there's probably a way to control the brightness in this */ + bg_b = m_uc & 1 ? 0xdf : 0; + bg_g = m_uc & 2 ? 0xdf : 0; + bg_r = m_uc & 4 ? 0xdf : 0; + bitmap.fill(rgb_t(0xff,bg_r,bg_g,bg_b),cliprect); + + for(y=0;y<12;y++) + { + for(x=0;x<24;x++) + { + int xi,yi; + + tile = read_word(x+y*24); + attr = read_word((x+y*24)|0x200); + + /* TODO: charset hook-up is obviously WRONG so following mustn't be trusted at all */ + for(yi=0;yi<16;yi++) + { + for(xi=0;xi<16;xi++) + { + UINT8 pix; + UINT8 color = (attr & 0x70) >> 4; + UINT8 r,g,b; + + pix = (pcg[(tile*8)+(yi >> 1)] >> (7-(xi >> 1))) & 1; + + /* TODO: check this */ + b = (color & 1) ? 0xff : 0; + g = (color & 2) ? 0xff : 0; + r = (color & 4) ? 0xff : 0; + + if(tile != 0xff && pix != 0) + bitmap.pix32(y*16+yi,x*16+xi) = r << 16 | g << 8 | b; + } + } + } + } + + return 0; +} diff --git a/src/devices/video/mb90082.h b/src/devices/video/mb90082.h new file mode 100644 index 00000000000..863a3aec797 --- /dev/null +++ b/src/devices/video/mb90082.h @@ -0,0 +1,85 @@ +// license:LGPL-2.1+ +// copyright-holders:Angelo Salese +/*************************************************************************** + + Fujitsu MB90082 OSD + +***************************************************************************/ + +#pragma once + +#ifndef __MB90082DEV_H__ +#define __MB90082DEV_H__ + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_MB90082_ADD(_tag,_freq) \ + MCFG_DEVICE_ADD(_tag, MB90082, _freq) + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +enum +{ + OSD_COMMAND = 0, + OSD_DATA +}; + + +// ======================> mb90082_device + +class mb90082_device : public device_t, + public device_memory_interface +{ +public: + // construction/destruction + mb90082_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // I/O operations + DECLARE_WRITE8_MEMBER( write ); + DECLARE_WRITE_LINE_MEMBER( set_cs_line ); + + UINT32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); + virtual const rom_entry *device_rom_region() const; + +protected: + // device-level overrides + virtual void device_validity_check(validity_checker &valid) const; + virtual void device_start(); + virtual void device_reset(); + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const; + +private: + UINT8 m_cmd_ff; + UINT8 m_cmd,m_cmd_param; + UINT8 m_reset_line; + + UINT16 m_osd_addr; + UINT8 m_fil; + UINT8 m_uc; + UINT8 m_attr; + + inline UINT16 read_word(offs_t address); + inline void write_word(offs_t address, UINT16 data); + + const address_space_config m_space_config; +}; + + +// device type definition +extern const device_type MB90082; + + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + + + +#endif diff --git a/src/devices/video/mb_vcu.c b/src/devices/video/mb_vcu.c new file mode 100644 index 00000000000..0ad568976f8 --- /dev/null +++ b/src/devices/video/mb_vcu.c @@ -0,0 +1,579 @@ +// license:LGPL-2.1+ +// copyright-holders:Angelo Salese +/*************************************************************************** + +Device for Mazer Blazer/Great Guns custom Video Controller Unit + +Written by Angelo Salese, based off old implementation by Jarek Burczynski + +TODO: +- understand what exactly modes 0x03 and 0x13 really reads in set_clr() and + where it puts results (yeah, shared VCU RAM, but exactly where?). Almost + surely Mazer Blazer tries to read the pixel data for collision detection and + Great Guns read backs VRAM for VCU test (patched for now, btw). +- Understand look-up tables in i/o space. +- Understand how to handle layer clearance. +- Understand how planes are really handled. +- Understand how transparent pens are handled (is 0x0f always transparent or + there's some clut gimmick? Great Guns title screen makes me think of the + latter option) + +***************************************************************************/ + +#include "emu.h" +#include "video/mb_vcu.h" +#include "video/resnet.h" + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +// device type definition +const device_type MB_VCU = &device_creator; + +//------------------------------------------------- +// static_set_palette_tag: Set the tag of the +// palette device +//------------------------------------------------- + +void mb_vcu_device::static_set_palette_tag(device_t &device, const char *tag) +{ + downcast(device).m_palette.set_tag(tag); +} + + +static ADDRESS_MAP_START( mb_vcu_vram, AS_0, 8, mb_vcu_device ) + AM_RANGE(0x00000,0x7ffff) AM_RAM // enough for a 256x256x4 x 2 pages of framebuffer with 4 layers (TODO: doubled for simplicity) +ADDRESS_MAP_END + + +static ADDRESS_MAP_START( mb_vcu_pal_ram, AS_1, 8, mb_vcu_device ) + AM_RANGE(0x0000, 0x00ff) AM_RAM + AM_RANGE(0x0200, 0x02ff) AM_RAM + AM_RANGE(0x0400, 0x04ff) AM_RAM + AM_RANGE(0x0600, 0x06ff) AM_READWRITE(mb_vcu_paletteram_r,mb_vcu_paletteram_w) +ADDRESS_MAP_END + +READ8_MEMBER( mb_vcu_device::mb_vcu_paletteram_r ) +{ + return m_palram[offset]; +} + +WRITE8_MEMBER( mb_vcu_device::mb_vcu_paletteram_w ) +{ + int r,g,b, bit0, bit1, bit2; + + m_palram[offset] = data; + + /* red component */ + bit1 = (m_palram[offset] >> 7) & 0x01; + bit0 = (m_palram[offset] >> 6) & 0x01; + r = combine_2_weights(m_weights_r, bit0, bit1); + + /* green component */ + bit2 = (m_palram[offset] >> 5) & 0x01; + bit1 = (m_palram[offset] >> 4) & 0x01; + bit0 = (m_palram[offset] >> 3) & 0x01; + g = combine_3_weights(m_weights_g, bit0, bit1, bit2); + + /* blue component */ + bit2 = (m_palram[offset] >> 2) & 0x01; + bit1 = (m_palram[offset] >> 1) & 0x01; + bit0 = (m_palram[offset] >> 0) & 0x01; + b = combine_3_weights(m_weights_b, bit0, bit1, bit2); + + m_palette->set_pen_color(offset, rgb_t(r, g, b)); +} + +//------------------------------------------------- +// memory_space_config - return a description of +// any address spaces owned by this device +//------------------------------------------------- + +const address_space_config *mb_vcu_device::memory_space_config(address_spacenum spacenum) const +{ + switch (spacenum) + { + case AS_0: return &m_videoram_space_config; + case AS_1: return &m_paletteram_space_config; + default: return NULL; + } +} + +//************************************************************************** +// INLINE HELPERS +//************************************************************************** + +//------------------------------------------------- +// read_byte - read a byte at the given address +//------------------------------------------------- + +inline UINT8 mb_vcu_device::read_byte(offs_t address) +{ + return space(AS_0).read_byte(address); +} + +//------------------------------------------------- +// write_byte - write a byte at the given address +//------------------------------------------------- + +inline void mb_vcu_device::write_byte(offs_t address, UINT8 data) +{ + space(AS_0).write_byte(address, data); +} + +//------------------------------------------------- +// read_byte - read a byte at the given i/o +//------------------------------------------------- + +inline UINT8 mb_vcu_device::read_io(offs_t address) +{ + return space(AS_1).read_byte(address); +} + +//------------------------------------------------- +// write_byte - write a byte at the given i/o +//------------------------------------------------- + +inline void mb_vcu_device::write_io(offs_t address, UINT8 data) +{ + space(AS_1).write_byte(address, data); +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// mb_vcu_device - constructor +//------------------------------------------------- + +mb_vcu_device::mb_vcu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, MB_VCU, "Mazer Blazer custom VCU", tag, owner, clock, "mb_vcu", __FILE__), + device_memory_interface(mconfig, *this), + device_video_interface(mconfig, *this), + m_videoram_space_config("videoram", ENDIANNESS_LITTLE, 8, 19, 0, NULL, *ADDRESS_MAP_NAME(mb_vcu_vram)), + m_paletteram_space_config("palram", ENDIANNESS_LITTLE, 8, 16, 0, NULL, *ADDRESS_MAP_NAME(mb_vcu_pal_ram)), + m_cpu(*this), + m_palette(*this) +{ +} + +//------------------------------------------------- +// device_validity_check - perform validity checks +// on this device +//------------------------------------------------- + +void mb_vcu_device::device_validity_check(validity_checker &valid) const +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void mb_vcu_device::device_start() +{ + // TODO: m_screen_tag + m_ram = auto_alloc_array_clear(machine(), UINT8, 0x800); + m_palram = auto_alloc_array_clear(machine(), UINT8, 0x100); + + { + static const int resistances_r[2] = { 4700, 2200 }; + static const int resistances_gb[3] = { 10000, 4700, 2200 }; + + /* just to calculate coefficients for later use */ + compute_resistor_weights(0, 255, -1.0, + 3, resistances_gb, m_weights_g, 3600, 0, + 3, resistances_gb, m_weights_b, 3600, 0, + 2, resistances_r, m_weights_r, 3600, 0); + } + + save_item(NAME(m_status)); + save_pointer(NAME(m_ram), 0x800); + save_pointer(NAME(m_palram), 0x100); + save_item(NAME(m_param_offset_latch)); + save_item(NAME(m_xpos)); + save_item(NAME(m_ypos)); + save_item(NAME(m_color1)); + save_item(NAME(m_color2)); + save_item(NAME(m_mode)); + save_item(NAME(m_pix_xsize)); + save_item(NAME(m_pix_ysize)); + save_item(NAME(m_vregs)); + save_item(NAME(m_bk_color)); + save_item(NAME(m_vbank)); + save_item(NAME(m_weights_r)); + save_item(NAME(m_weights_g)); + save_item(NAME(m_weights_b)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void mb_vcu_device::device_reset() +{ + m_status = 1; + + for(int i=0;i<0x80000;i++) + { + write_byte(i,0x0f); + } +} + + +//************************************************************************** +// READ/WRITE HANDLERS +//************************************************************************** +// UINT8 *pcg = memregion("sub2")->base(); + +READ8_MEMBER( mb_vcu_device::read_ram ) +{ + return m_ram[offset]; +} + +WRITE8_MEMBER( mb_vcu_device::write_ram ) +{ + m_ram[offset] = data; +} + +WRITE8_MEMBER( mb_vcu_device::write_vregs ) +{ + m_vregs[offset] = data; +} + +/* latches RAM offset to send to params */ +READ8_MEMBER( mb_vcu_device::load_params ) +{ + m_param_offset_latch = offset; + + m_xpos = m_ram[m_param_offset_latch + 1] | (m_ram[m_param_offset_latch + 2]<<8); + m_ypos = m_ram[m_param_offset_latch + 3] | (m_ram[m_param_offset_latch + 4]<<8); + m_color1 = m_ram[m_param_offset_latch + 5]; + m_color2 = m_ram[m_param_offset_latch + 6]; + m_mode = m_ram[m_param_offset_latch + 7]; + m_pix_xsize = m_ram[m_param_offset_latch + 8] + 1; + m_pix_ysize = m_ram[m_param_offset_latch + 9] + 1; + + if(0) + { + printf("[0] %02x ",m_ram[m_param_offset_latch]); + printf("X: %04x ",m_xpos); + printf("Y: %04x ",m_ypos); + printf("C1:%02x ",m_color1); + printf("C2:%02x ",m_color2); + printf("M :%02x ",m_mode); + printf("XS:%02x ",m_pix_xsize); + printf("YS:%02x ",m_pix_ysize); + printf("\n"); + } + + return 0; // open bus? +} + +READ8_MEMBER( mb_vcu_device::load_gfx ) +{ + int xi,yi; + int dstx,dsty; + UINT8 dot; + int bits = 0; + UINT8 pen = 0; + UINT8 cur_layer; + +// cur_layer = (m_mode & 0x3); + cur_layer = 0; + + switch(m_mode >> 2) + { + case 0x00: // 4bpp + for(yi=0;yi= 0 && dsty >= 0 && dstx < 256 && dsty < 256) + { + dot = m_cpu->space(AS_PROGRAM).read_byte(((offset + (bits >> 3)) & 0x1fff) + 0x4000) >> (4-(bits & 7)); + dot&= 0xf; + + //if(dot != 0xf || m_mode & 2) + write_byte(dstx|dsty<<8|cur_layer<<16|m_vbank<<18, dot); + } + bits += 4; + } + } + break; + + case 0x02: // 1bpp + for(yi=0;yi= 0 && dsty >= 0 && dstx < 256 && dsty < 256) + { + dot = m_cpu->space(AS_PROGRAM).read_byte(((offset + (bits >> 3)) & 0x1fff) + 0x4000) >> (7-(bits & 7)); + dot&= 1; + + pen = dot ? (m_color1 >> 4) : (m_color1 & 0xf); + //if(pen != 0xf || m_mode & 2) + write_byte(dstx|dsty<<8|cur_layer<<16|m_vbank<<18, pen); + } + bits++; + } + } + break; + case 0x03: //2bpp + for (yi = 0; yi < m_pix_ysize; yi++) + { + for (xi = 0; xi < m_pix_xsize; xi++) + { + dstx = (m_xpos + xi); + dsty = (m_ypos + yi); + + if(dstx >= 0 && dsty >= 0 && dstx < 256 && dsty < 256) + { + dot = m_cpu->space(AS_PROGRAM).read_byte(((offset + (bits >> 3)) & 0x1fff) + 0x4000) >> (6-(bits & 7)); + + switch(dot & 3) + { + case 0: + pen = m_color1 & 0xf; + break; + case 1: + pen = m_color1 >> 4; + break; + case 2: + pen = m_color2 & 0xf; + break; + case 3: + pen = m_color2 >> 4; + break; + } + + //if(pen != 0xf) + write_byte(dstx|dsty<<8|cur_layer<<16|m_vbank<<18, pen); + } + + bits+=2; + } + } + break; + + default: + popmessage("Unsupported draw mode"); + break; + } + + return 0; // open bus? +} + +/* +---0 -111 (0x07) write to i/o? +---0 -011 (0x03) read to i/o? +---1 -011 (0x13) read to vram? +*/ +READ8_MEMBER( mb_vcu_device::load_set_clr ) +{ + int xi,yi; + int dstx,dsty; +// UINT8 dot; + int bits = 0; + if(m_mode == 0x13 || m_mode == 0x03) + { + printf("[0] %02x ",m_ram[m_param_offset_latch]); + printf("X: %04x ",m_xpos); + printf("Y: %04x ",m_ypos); + printf("C1:%02x ",m_color1); + printf("C2:%02x ",m_color2); + printf("M :%02x ",m_mode); + printf("XS:%02x ",m_pix_xsize); + printf("YS:%02x ",m_pix_ysize); + printf("VB:%02x ",m_vbank); + printf("\n"); + } + + switch(m_mode) + { + case 0x13: + case 0x03: + for (yi = 0; yi < m_pix_ysize; yi++) + { + for (xi = 0; xi < m_pix_xsize; xi++) + { + dstx = (m_xpos + xi); + dsty = (m_ypos + yi); + + if(dstx < 256 && dsty < 256) + { + #if 0 + dot = m_cpu->space(AS_PROGRAM).read_byte(((offset + (bits >> 3)) & 0x1fff) + 0x4000) >> (6-(bits & 7)); + dot&= 3; + + switch(dot) + { + case 0: + write_byte(dstx|dsty<<8, m_color1 & 0xf); + break; + case 1: + write_byte(dstx|dsty<<8, m_color1 >> 4); + break; + case 2: + write_byte(dstx|dsty<<8, m_color2 & 0xf); + break; + case 3: + write_byte(dstx|dsty<<8, m_color2 >> 4); + break; + } + #endif + + //write_byte(dstx|dsty<<8, m_mode >> 4); + } + + bits+=2; + } + } + break; + + case 0x07: + for(int i=0;i> 7) & 0x01; + bit0 = (m_bk_color >> 6) & 0x01; + r = combine_2_weights(m_weights_r, bit0, bit1); + + /* green component */ + bit2 = (m_bk_color >> 5) & 0x01; + bit1 = (m_bk_color >> 4) & 0x01; + bit0 = (m_bk_color >> 3) & 0x01; + g = combine_3_weights(m_weights_g, bit0, bit1, bit2); + + /* blue component */ + bit2 = (m_bk_color >> 2) & 0x01; + bit1 = (m_bk_color >> 1) & 0x01; + bit0 = (m_bk_color >> 0) & 0x01; + b = combine_3_weights(m_weights_b, bit0, bit1, bit2); + + m_palette->set_pen_color(0x100, rgb_t(r, g, b)); +} + +READ8_MEMBER( mb_vcu_device::status_r ) +{ + /* + ---- ---x busy or vblank flag + */ + return m_status; +} + +WRITE8_MEMBER( mb_vcu_device::vbank_w ) +{ + m_vbank = (data & 0x40) >> 6; +} + +//------------------------------------------------- +// update_screen - +//------------------------------------------------- + +UINT32 mb_vcu_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + int x,y; + UINT8 dot; + + bitmap.fill(0x100,cliprect); + + for(y=0;y<256;y++) + { + for(x=0;x<256;x++) + { + dot = read_byte((x >> 0)|(y<<8)|0<<16|(m_vbank ^ 1)<<18); + //if(dot != 0xf) + { + dot|= m_vregs[1] << 4; + + bitmap.pix32(y,x) = m_palette->pen(dot); + } + } + } + + #if 0 + for(y=0;y<256;y++) + { + for(x=0;x<256;x++) + { + dot = read_byte((x >> 0)|(y<<8)|3<<16); + + if(dot != 0xf) + { + dot|= m_vregs[1] << 4; + + bitmap.pix32(y,x) = machine().pens[dot]; + } + } + } + + for(y=0;y<256;y++) + { + for(x=0;x<256;x++) + { + dot = read_byte((x >> 0)|(y<<8)|0<<16); + + if(dot != 0xf) + { + dot|= m_vregs[1] << 4; + + bitmap.pix32(y,x) = machine().pens[dot]; + } + } + } + + for(y=0;y<256;y++) + { + for(x=0;x<256;x++) + { + dot = read_byte((x >> 0)|(y<<8)|1<<16); + + if(dot != 0xf) + { + dot|= m_vregs[1] << 4; + + bitmap.pix32(y,x) = machine().pens[dot]; + } + } + } + #endif + + return 0; +} + +void mb_vcu_device::screen_eof(void) +{ + //for(int i=0;i<0x10000;i++) + { + //write_byte(i|0x00000|m_vbank<<18,0x0f); + //write_byte(i|0x10000|m_vbank<<18,0x0f); + //write_byte(i|0x30000|m_vbank<<18,0x0f); + } +} diff --git a/src/devices/video/mb_vcu.h b/src/devices/video/mb_vcu.h new file mode 100644 index 00000000000..ed6e45663c9 --- /dev/null +++ b/src/devices/video/mb_vcu.h @@ -0,0 +1,92 @@ +// license:LGPL-2.1+ +// copyright-holders:Angelo Salese +#pragma once + +#ifndef __MB_VCUDEV_H__ +#define __MB_VCUDEV_H__ + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> mb_vcu_device + +class mb_vcu_device : public device_t, + public device_memory_interface, + public device_video_interface +{ +public: + // construction/destruction + mb_vcu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // static configuration + static void static_set_palette_tag(device_t &device, const char *tag); + static void set_cpu_tag(device_t &device, const char *tag) { downcast(device).m_cpu.set_tag(tag); } + + // I/O operations + DECLARE_WRITE8_MEMBER( write_vregs ); + DECLARE_READ8_MEMBER( read_ram ); + DECLARE_WRITE8_MEMBER( write_ram ); + DECLARE_READ8_MEMBER( load_params ); + DECLARE_READ8_MEMBER( load_gfx ); + DECLARE_READ8_MEMBER( load_set_clr ); + DECLARE_WRITE8_MEMBER( background_color_w ); + DECLARE_READ8_MEMBER( status_r ); + DECLARE_WRITE8_MEMBER( vbank_w ); + DECLARE_READ8_MEMBER( mb_vcu_paletteram_r ); + DECLARE_WRITE8_MEMBER( mb_vcu_paletteram_w ); + + UINT32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); + void screen_eof(void); + +protected: + // device-level overrides + virtual void device_validity_check(validity_checker &valid) const; + virtual void device_start(); + virtual void device_reset(); + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const; +private: + inline UINT8 read_byte(offs_t address); + inline void write_byte(offs_t address, UINT8 data); + inline UINT8 read_io(offs_t address); + inline void write_io(offs_t address, UINT8 data); + + const address_space_config m_videoram_space_config; + const address_space_config m_paletteram_space_config; + UINT8 m_status; + UINT8 *m_ram; + UINT8 *m_palram; + UINT16 m_param_offset_latch; + + INT16 m_xpos, m_ypos; + UINT8 m_color1, m_color2; + UINT8 m_mode; + UINT16 m_pix_xsize, m_pix_ysize; + UINT8 m_vregs[4]; + UINT8 m_bk_color; + UINT8 m_vbank; + + double m_weights_r[2]; + double m_weights_g[3]; + double m_weights_b[3]; + required_device m_cpu; + required_device m_palette; +}; + + +// device type definition +extern const device_type MB_VCU; + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_MB_VCU_CPU(_tag) \ + mb_vcu_device::set_cpu_tag(*device, "^" _tag); + +#define MCFG_MB_VCU_PALETTE(_palette_tag) \ + mb_vcu_device::static_set_palette_tag(*device, "^" _palette_tag); + +#endif diff --git a/src/devices/video/mc6845.c b/src/devices/video/mc6845.c new file mode 100644 index 00000000000..4c1d811369c --- /dev/null +++ b/src/devices/video/mc6845.c @@ -0,0 +1,1601 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +/********************************************************************** + + Motorola MC6845 and compatible CRT controller emulation + + The following variations exist that are different in + functionality and not just in speed rating(1): + * Motorola 6845, 6845-1 + * Hitachi 46505 + * Rockwell 6545, 6545-1 (= Synertek SY6545-1) + * MOS Technology 6545-1 + + (1) as per the document at + http://www.6502.org/users/andre/hwinfo/crtc/diffs.html + + The various speed rated devices are identified by a letter, + for example M68A45, M68B45, etc. + + The chip is originally designed by Hitachi, not by Motorola. + +**********************************************************************/ + +/* + + TODO: + + - Change device video emulation x/y offsets when "show border color" + is true + - Support 'interlace and video' mode + + - mos8563 + + - horizontal scroll + - vertical scroll + - bitmap modes + - display enable begin/end + +*/ + +#include "emu.h" +#include "mc6845.h" + + +#define LOG (0) + + +const device_type MC6845 = &device_creator; +const device_type MC6845_1 = &device_creator; +const device_type R6545_1 = &device_creator; +const device_type C6545_1 = &device_creator; +const device_type H46505 = &device_creator; +const device_type HD6845 = &device_creator; +const device_type SY6545_1 = &device_creator; +const device_type SY6845E = &device_creator; +const device_type HD6345 = &device_creator; +const device_type AMS40041 = &device_creator; +const device_type MOS8563 = &device_creator; +const device_type MOS8568 = &device_creator; + + +/* mode macros */ +#define MODE_TRANSPARENT ((m_mode_control & 0x08) != 0) +#define MODE_TRANSPARENT_PHI2 ((m_mode_control & 0x88) == 0x88) +/* FIXME: not supported yet */ +#define MODE_TRANSPARENT_BLANK ((m_mode_control & 0x88) == 0x08) +#define MODE_UPDATE_STROBE ((m_mode_control & 0x40) != 0) +#define MODE_CURSOR_SKEW ((m_mode_control & 0x20) != 0) +#define MODE_DISPLAY_ENABLE_SKEW ((m_mode_control & 0x10) != 0) +#define MODE_ROW_COLUMN_ADDRESSING ((m_mode_control & 0x04) != 0) +#define MODE_INTERLACE_AND_VIDEO ((m_mode_control & 0x03) == 3) + +#define VSS_CBRATE BIT(m_vert_scroll, 5) +#define VSS_RVS BIT(m_vert_scroll, 6) +#define VSS_COPY BIT(m_vert_scroll, 7) + +#define HSS_DBL BIT(m_horiz_scroll, 4) +#define HSS_SEMI BIT(m_horiz_scroll, 5) +#define HSS_ATTR BIT(m_horiz_scroll, 6) +#define HSS_TEXT BIT(m_horiz_scroll, 7) + +#define ATTR_COLOR (attr & 0x0f) +#define ATTR_BACKGROUND (attr & 0x0f) +#define ATTR_FOREGROUND (attr >> 4) +#define ATTR_BLINK BIT(attr, 4) +#define ATTR_UNDERLINE BIT(attr, 5) +#define ATTR_REVERSE BIT(attr, 6) +#define ATTR_ALTERNATE_CHARSET BIT(attr, 7) + + +mc6845_device::mc6845_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_video_interface(mconfig, *this, false), + m_show_border_area(true), + m_interlace_adjust(0), + m_visarea_adjust_min_x(0), + m_visarea_adjust_max_x(0), + m_visarea_adjust_min_y(0), + m_visarea_adjust_max_y(0), + m_hpixels_per_column(0), + m_out_de_cb(*this), + m_out_cur_cb(*this), + m_out_hsync_cb(*this), + m_out_vsync_cb(*this) +{ +} + +mc6845_device::mc6845_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, MC6845, "MC6845 CRTC", tag, owner, clock, "mc6845", __FILE__), + device_video_interface(mconfig, *this, false), + m_show_border_area(true), + m_interlace_adjust(0), + m_visarea_adjust_min_x(0), + m_visarea_adjust_max_x(0), + m_visarea_adjust_min_y(0), + m_visarea_adjust_max_y(0), + m_hpixels_per_column(0), + m_out_de_cb(*this), + m_out_cur_cb(*this), + m_out_hsync_cb(*this), + m_out_vsync_cb(*this) +{ +} + + +void mc6845_device::device_post_load() +{ + recompute_parameters(true); +} + + +void mc6845_device::call_on_update_address(int strobe) +{ + if (!m_on_update_addr_changed_cb.isnull()) + m_upd_trans_timer->adjust(attotime::zero, (m_update_addr << 8) | strobe); + else + fatalerror("M6845: transparent memory mode without handler\n"); +} + + +WRITE8_MEMBER( mc6845_device::address_w ) +{ + m_register_address_latch = data & 0x1f; +} + + +READ8_MEMBER( mc6845_device::status_r ) +{ + UINT8 ret = 0; + + /* VBLANK bit */ + if (m_supports_status_reg_d5 && !m_line_enable_ff) + ret = ret | 0x20; + + /* light pen latched */ + if (m_supports_status_reg_d6 && m_light_pen_latched) + ret = ret | 0x40; + + /* UPDATE ready */ + if (m_supports_status_reg_d7 && m_update_ready_bit) + ret = ret | 0x80; + + return ret; +} + + +READ8_MEMBER( mc6845_device::register_r ) +{ + UINT8 ret = 0; + + switch (m_register_address_latch) + { + case 0x0c: ret = m_supports_disp_start_addr_r ? (m_disp_start_addr >> 8) & 0xff : 0; break; + case 0x0d: ret = m_supports_disp_start_addr_r ? (m_disp_start_addr >> 0) & 0xff : 0; break; + case 0x0e: ret = (m_cursor_addr >> 8) & 0xff; break; + case 0x0f: ret = (m_cursor_addr >> 0) & 0xff; break; + case 0x10: ret = (m_light_pen_addr >> 8) & 0xff; m_light_pen_latched = false; break; + case 0x11: ret = (m_light_pen_addr >> 0) & 0xff; m_light_pen_latched = false; break; + case 0x1f: + if (m_supports_transparent && MODE_TRANSPARENT) + { + if(MODE_TRANSPARENT_PHI2) + { + m_update_addr++; + m_update_addr &= 0x3fff; + call_on_update_address(0); + } + else + { + /* MODE_TRANSPARENT_BLANK */ + if(m_update_ready_bit) + { + m_update_ready_bit = false; + update_upd_adr_timer(); + } + } + } + break; + + /* all other registers are write only and return 0 */ + default: break; + } + + return ret; +} + + +WRITE8_MEMBER( mc6845_device::register_w ) +{ + if (LOG) logerror("%s:M6845 reg 0x%02x = 0x%02x\n", machine().describe_context(), m_register_address_latch, data); + + switch (m_register_address_latch) + { + case 0x00: m_horiz_char_total = data & 0xff; break; + case 0x01: m_horiz_disp = data & 0xff; break; + case 0x02: m_horiz_sync_pos = data & 0xff; break; + case 0x03: m_sync_width = data & 0xff; break; + case 0x04: m_vert_char_total = data & 0x7f; break; + case 0x05: m_vert_total_adj = data & 0x1f; break; + case 0x06: m_vert_disp = data & 0x7f; break; + case 0x07: m_vert_sync_pos = data & 0x7f; break; + case 0x08: m_mode_control = data & 0xff; break; + case 0x09: m_max_ras_addr = data & 0x1f; if (MODE_INTERLACE_AND_VIDEO) m_max_ras_addr += m_interlace_adjust; break; + case 0x0a: m_cursor_start_ras = data & 0x7f; break; + case 0x0b: m_cursor_end_ras = data & 0x1f; break; + case 0x0c: m_disp_start_addr = ((data & 0x3f) << 8) | (m_disp_start_addr & 0x00ff); break; + case 0x0d: m_disp_start_addr = ((data & 0xff) << 0) | (m_disp_start_addr & 0xff00); break; + case 0x0e: m_cursor_addr = ((data & 0x3f) << 8) | (m_cursor_addr & 0x00ff); break; + case 0x0f: m_cursor_addr = ((data & 0xff) << 0) | (m_cursor_addr & 0xff00); break; + case 0x10: /* read-only */ break; + case 0x11: /* read-only */ break; + case 0x12: + if (m_supports_transparent) + { + m_update_addr = ((data & 0x3f) << 8) | (m_update_addr & 0x00ff); + if(MODE_TRANSPARENT_PHI2) + call_on_update_address(0); + } + break; + case 0x13: + if (m_supports_transparent) + { + m_update_addr = ((data & 0xff) << 0) | (m_update_addr & 0xff00); + if(MODE_TRANSPARENT_PHI2) + call_on_update_address(0); + } + break; + case 0x1f: + if (m_supports_transparent && MODE_TRANSPARENT) + { + if(MODE_TRANSPARENT_PHI2) + { + m_update_addr++; + m_update_addr &= 0x3fff; + call_on_update_address(0); + } + else + { + /* MODE_TRANSPARENT_BLANK */ + if(m_update_ready_bit) + { + m_update_ready_bit = false; + update_upd_adr_timer(); + } + } + } + break; + default: break; + } + + /* display message if the Mode Control register is not zero */ + if ((m_register_address_latch == 0x08) && (m_mode_control != 0)) + if (!m_supports_transparent) + logerror("M6845: Mode Control %02X is not supported!!!\n", m_mode_control); + + recompute_parameters(false); +} + + +WRITE8_MEMBER( mos8563_device::address_w ) +{ + m_register_address_latch = data & 0x3f; +} + + +READ8_MEMBER( mos8563_device::status_r ) +{ + UINT8 ret = m_revision; + + /* VBLANK bit */ + if (!m_line_enable_ff) + ret = ret | 0x20; + + /* light pen latched */ + if (m_light_pen_latched) + ret = ret | 0x40; + + /* UPDATE ready */ + if (m_update_ready_bit) + ret = ret | 0x80; + + return ret; +} + + +READ8_MEMBER( mos8563_device::register_r ) +{ + UINT8 ret = 0xff; + + switch (m_register_address_latch) + { + case 0x00: ret = m_horiz_char_total; break; + case 0x01: ret = m_horiz_disp; break; + case 0x02: ret = m_horiz_sync_pos; break; + case 0x03: ret = m_sync_width; break; + case 0x04: ret = m_vert_char_total; break; + case 0x05: ret = m_vert_total_adj | 0xc0; break; + case 0x06: ret = m_vert_disp; break; + case 0x07: ret = m_vert_sync_pos; break; + case 0x08: ret = m_mode_control | 0xfc; break; + case 0x09: ret = m_max_ras_addr | 0xe0; break; + case 0x0a: ret = m_cursor_start_ras | 0x80; break; + case 0x0b: ret = m_cursor_end_ras | 0xe0; break; + case 0x0c: ret = (m_disp_start_addr >> 8) & 0xff; break; + case 0x0d: ret = (m_disp_start_addr >> 0) & 0xff; break; + case 0x0e: ret = (m_cursor_addr >> 8) & 0xff; break; + case 0x0f: ret = (m_cursor_addr >> 0) & 0xff; break; + case 0x10: ret = (m_light_pen_addr >> 8) & 0xff; m_light_pen_latched = false; break; + case 0x11: ret = (m_light_pen_addr >> 0) & 0xff; m_light_pen_latched = false; break; + case 0x12: ret = (m_update_addr >> 8) & 0xff; break; + case 0x13: ret = (m_update_addr >> 0) & 0xff; break; + case 0x14: ret = (m_attribute_addr >> 8) & 0xff; break; + case 0x15: ret = (m_attribute_addr >> 0) & 0xff; break; + case 0x16: ret = m_horiz_char; break; + case 0x17: ret = m_vert_char_disp | 0xe0; break; + case 0x18: ret = m_vert_scroll; break; + case 0x19: ret = m_horiz_scroll; break; + case 0x1a: ret = m_color; break; + case 0x1b: ret = m_row_addr_incr; break; + case 0x1c: ret = m_char_base_addr | 0x1f; break; + case 0x1d: ret = m_underline_ras | 0xe0; break; + case 0x1e: ret = m_word_count; break; + case 0x1f: ret = read_videoram(m_update_addr++); break; + case 0x20: ret = (m_block_addr >> 8) & 0xff; break; + case 0x21: ret = (m_block_addr >> 0) & 0xff; break; + case 0x22: ret = (m_de_begin >> 8) & 0xff; break; + case 0x23: ret = (m_de_begin >> 0) & 0xff; break; + case 0x24: ret = m_dram_refresh | 0xf0; break; + case 0x25: ret = m_sync_polarity | 0x3f; break; + } + + return ret; +} + + +WRITE8_MEMBER( mos8563_device::register_w ) +{ + if (LOG) logerror("%s:MOS8563 reg 0x%02x = 0x%02x\n", machine().describe_context(), m_register_address_latch, data); + + switch (m_register_address_latch) + { + case 0x00: m_horiz_char_total = data & 0xff; break; + case 0x01: m_horiz_disp = data & 0xff; break; + case 0x02: m_horiz_sync_pos = data & 0xff; break; + case 0x03: m_sync_width = data & 0xff; break; + case 0x04: m_vert_char_total = data & 0xff; break; + case 0x05: m_vert_total_adj = data & 0x1f; break; + case 0x06: m_vert_disp = data & 0xff; break; + case 0x07: m_vert_sync_pos = data & 0xff; break; + case 0x08: m_mode_control = data & 0x03; break; + case 0x09: m_max_ras_addr = data & 0x1f; break; + case 0x0a: m_cursor_start_ras = data & 0x7f; break; + case 0x0b: m_cursor_end_ras = data & 0x1f; break; + case 0x0c: m_disp_start_addr = ((data & 0xff) << 8) | (m_disp_start_addr & 0x00ff); break; + case 0x0d: m_disp_start_addr = ((data & 0xff) << 0) | (m_disp_start_addr & 0xff00); break; + case 0x0e: m_cursor_addr = ((data & 0xff) << 8) | (m_cursor_addr & 0x00ff); break; + case 0x0f: m_cursor_addr = ((data & 0xff) << 0) | (m_cursor_addr & 0xff00); break; + case 0x10: /* read-only */ break; + case 0x11: /* read-only */ break; + case 0x12: m_update_addr = ((data & 0xff) << 8) | (m_update_addr & 0x00ff); break; + case 0x13: m_update_addr = ((data & 0xff) << 0) | (m_update_addr & 0xff00); break; + case 0x14: m_attribute_addr = ((data & 0xff) << 8) | (m_attribute_addr & 0x00ff); break; + case 0x15: m_attribute_addr = ((data & 0xff) << 0) | (m_attribute_addr & 0xff00); break; + case 0x16: m_horiz_char = data & 0xff; break; + case 0x17: m_vert_char_disp = data & 0x1f; break; + case 0x18: m_vert_scroll = data & 0xff; break; + case 0x19: + { + int dbl = HSS_DBL; + m_horiz_scroll = data & 0xff; + if (dbl && !HSS_DBL) set_clock(m_clock << 1); + if (!dbl && HSS_DBL) set_clock(m_clock >> 1); + break; + } + case 0x1a: m_color = data & 0xff; break; + case 0x1b: m_row_addr_incr = data & 0xff; break; + case 0x1c: m_char_base_addr = data & 0xe0; break; + case 0x1d: m_underline_ras = data & 0x1f; break; + case 0x1e: + m_word_count = data & 0xff; + m_update_ready_bit = 0; + m_block_copy_timer->adjust( attotime::from_ticks( 1, m_clock ) ); + break; + case 0x1f: + m_data = data & 0xff; + write_videoram(m_update_addr++, m_data); + break; + case 0x20: m_block_addr = ((data & 0xff) << 8) | (m_block_addr & 0x00ff); break; + case 0x21: m_block_addr = ((data & 0xff) << 0) | (m_block_addr & 0xff00); break; + case 0x22: m_de_begin = ((data & 0xff) << 8) | (m_de_begin & 0x00ff); break; + case 0x23: m_de_begin = ((data & 0xff) << 0) | (m_de_begin & 0xff00); break; + case 0x24: m_dram_refresh = data & 0x0f; break; + case 0x25: m_sync_polarity = data & 0xc0; break; + } + + recompute_parameters(false); +} + + +inline UINT8 mos8563_device::read_videoram(offs_t offset) +{ + return space(AS_0).read_byte(offset); +} + +inline void mos8563_device::write_videoram(offs_t offset, UINT8 data) +{ + space(AS_0).write_byte(offset, data); +} + + +READ_LINE_MEMBER( mc6845_device::de_r ) +{ + return m_de; +} + + +READ_LINE_MEMBER( mc6845_device::cursor_r ) +{ + return m_cur; +} + + +READ_LINE_MEMBER( mc6845_device::hsync_r ) +{ + return m_hsync; +} + + +READ_LINE_MEMBER( mc6845_device::vsync_r ) +{ + return m_vsync; +} + + +void mc6845_device::recompute_parameters(bool postload) +{ + UINT16 hsync_on_pos, hsync_off_pos, vsync_on_pos, vsync_off_pos; + + UINT16 video_char_height = m_max_ras_addr + 1; // fix garbage at the bottom of the screen (eg victor9k) + // Would be useful for 'interlace and video' mode support... + // UINT16 frame_char_height = (MODE_INTERLACE_AND_VIDEO ? m_max_ras_addr / 2 : m_max_ras_addr) + 1; + + /* compute the screen sizes */ + UINT16 horiz_pix_total = (m_horiz_char_total + 1) * m_hpixels_per_column; + UINT16 vert_pix_total = (m_vert_char_total + 1) * video_char_height + m_vert_total_adj; + + /* determine the visible area, avoid division by 0 */ + UINT16 max_visible_x = m_horiz_disp * m_hpixels_per_column - 1; + UINT16 max_visible_y = m_vert_disp * video_char_height - 1; + + /* determine the syncing positions */ + UINT8 horiz_sync_char_width = m_sync_width & 0x0f; + UINT8 vert_sync_pix_width = m_supports_vert_sync_width ? (m_sync_width >> 4) & 0x0f : 0x10; + + if (horiz_sync_char_width == 0) + horiz_sync_char_width = 0x10; + + if (vert_sync_pix_width == 0) + vert_sync_pix_width = 0x10; + + /* determine the transparent update cycle time, 1 update every 4 character clocks */ + m_upd_time = attotime::from_hz(m_clock) * (4 * m_hpixels_per_column); + + hsync_on_pos = m_horiz_sync_pos * m_hpixels_per_column; + hsync_off_pos = hsync_on_pos + (horiz_sync_char_width * m_hpixels_per_column); + vsync_on_pos = m_vert_sync_pos * video_char_height; + vsync_off_pos = vsync_on_pos + vert_sync_pix_width; + + // the Commodore PET computers have a non-standard 20kHz monitor which + // requires a wider HSYNC pulse that extends past the scanline width + if (hsync_off_pos > horiz_pix_total) + hsync_off_pos = horiz_pix_total; + + if (vsync_on_pos > vert_pix_total) + vsync_on_pos = vert_pix_total; + + if (vsync_off_pos > vert_pix_total) + vsync_off_pos = vert_pix_total; + + /* update only if screen parameters changed, unless we are coming here after loading the saved state */ + if (postload || + (horiz_pix_total != m_horiz_pix_total) || (vert_pix_total != m_vert_pix_total) || + (max_visible_x != m_max_visible_x) || (max_visible_y != m_max_visible_y) || + (hsync_on_pos != m_hsync_on_pos) || (vsync_on_pos != m_vsync_on_pos) || + (hsync_off_pos != m_hsync_off_pos) || (vsync_off_pos != m_vsync_off_pos)) + { + /* update the screen if we have valid data */ + if ((horiz_pix_total > 0) && (max_visible_x < horiz_pix_total) && + (vert_pix_total > 0) && (max_visible_y < vert_pix_total) && + (hsync_on_pos <= horiz_pix_total) && (vsync_on_pos <= vert_pix_total) && + (hsync_on_pos != hsync_off_pos)) + { + rectangle visarea; + + attoseconds_t refresh = HZ_TO_ATTOSECONDS(m_clock) * (m_horiz_char_total + 1) * vert_pix_total; + + // This doubles the vertical resolution, required for 'interlace and video' mode support. + // Tested and works for super80v, which was designed with this in mind (choose green or monochrome colour in config switches). + // However it breaks some other drivers (apricot,a6809,victor9k,bbc(mode7)). + // So, it is commented out for now. + // Also, the mode-register change needs to be added to the changed-parameter tests above. + if (MODE_INTERLACE_AND_VIDEO) + { + //max_visible_y *= 2; + //vert_pix_total *= 2; + } + + if(m_show_border_area) + visarea.set(0, horiz_pix_total-1, 0, vert_pix_total-1); + else + visarea.set(0 + m_visarea_adjust_min_x, max_visible_x + m_visarea_adjust_max_x, 0 + m_visarea_adjust_min_y, max_visible_y + m_visarea_adjust_max_y); + + if (LOG) logerror("M6845 config screen: HTOTAL: 0x%x VTOTAL: 0x%x MAX_X: 0x%x MAX_Y: 0x%x HSYNC: 0x%x-0x%x VSYNC: 0x%x-0x%x Freq: %ffps\n", + horiz_pix_total, vert_pix_total, max_visible_x, max_visible_y, hsync_on_pos, hsync_off_pos - 1, vsync_on_pos, vsync_off_pos - 1, 1 / ATTOSECONDS_TO_DOUBLE(refresh)); + + if ( m_screen != NULL ) + m_screen->configure(horiz_pix_total, vert_pix_total, visarea, refresh); + + m_has_valid_parameters = true; + } + else + m_has_valid_parameters = false; + + m_horiz_pix_total = horiz_pix_total; + m_vert_pix_total = vert_pix_total; + m_max_visible_x = max_visible_x; + m_max_visible_y = max_visible_y; + m_hsync_on_pos = hsync_on_pos; + m_hsync_off_pos = hsync_off_pos; + m_vsync_on_pos = vsync_on_pos; + m_vsync_off_pos = vsync_off_pos; + } +} + + +void mc6845_device::update_counters() +{ + m_character_counter = m_line_timer->elapsed( ).as_ticks( m_clock ); + + if ( m_hsync_off_timer ->enabled( ) ) + { + m_hsync_width_counter = m_hsync_off_timer ->elapsed( ).as_ticks( m_clock ); + } +} + + +void mc6845_device::set_de(int state) +{ + if (m_de != state) + { + m_de = state; + + if (m_de) + { + /* If the upd_adr_timer was running, cancel it */ + m_upd_adr_timer->adjust(attotime::never); + } + else + { + /* if transparent update was requested fire the update timer */ + if(!m_update_ready_bit) + update_upd_adr_timer(); + } + + m_out_de_cb(m_de); + } +} + + +void mc6845_device::set_hsync(int state) +{ + if (m_hsync != state) + { + m_hsync = state; + m_out_hsync_cb(m_hsync); + } +} + + +void mc6845_device::set_vsync(int state) +{ + if (m_vsync != state) + { + m_vsync = state; + m_out_vsync_cb(m_vsync); + } +} + + +void mc6845_device::set_cur(int state) +{ + if (m_cur != state) + { + m_cur = state; + m_out_cur_cb(m_cur); + } +} + + +void mc6845_device::update_upd_adr_timer() +{ + if (! m_de && m_supports_transparent) + m_upd_adr_timer->adjust(m_upd_time); +} + + +void mc6845_device::handle_line_timer() +{ + int new_vsync = m_vsync; + + m_character_counter = 0; + m_cursor_x = -1; + + /* Check if VSYNC is active */ + if ( m_vsync_ff ) + { + UINT8 vsync_width = m_supports_vert_sync_width ? (m_sync_width >> 4) & 0x0f : 0; + + m_vsync_width_counter = ( m_vsync_width_counter + 1 ) & 0x0F; + + /* Check if we've reached end of VSYNC */ + if ( m_vsync_width_counter == vsync_width ) + { + m_vsync_ff = 0; + + new_vsync = FALSE; + } + } + + // For rudimentary 'interlace and video' support, m_raster_counter increments by 1 rather than the correct 2. + // The correct test would be: + // if ( m_raster_counter == (MODE_INTERLACE_AND_VIDEO ? m_max_ras_addr + 1 : m_max_ras_addr) ) + if ( m_raster_counter == m_max_ras_addr ) + { + /* Check if we have reached the end of the vertical area */ + if ( m_line_counter == m_vert_char_total ) + { + m_adjust_counter = 0; + m_adjust_active = 1; + } + + m_raster_counter = 0; + m_line_counter = ( m_line_counter + 1 ) & 0x7F; + m_line_address = ( m_line_address + m_horiz_disp ) & 0x3fff; + + /* Check if we've reached the end of active display */ + if ( m_line_counter == m_vert_disp ) + { + m_line_enable_ff = false; + } + + /* Check if VSYNC should be enabled */ + if ( m_line_counter == m_vert_sync_pos ) + { + m_vsync_width_counter = 0; + m_vsync_ff = 1; + + new_vsync = TRUE; + } + } + else + { + // For rudimentary 'interlace and video' support, m_raster_counter increments by 1 rather than the correct 2. + // m_raster_counter = ( m_raster_counter + (MODE_INTERLACE_AND_VIDEO ? 2 : 1) ) & 0x1F; + m_raster_counter = ( m_raster_counter + 1 ) & 0x1F; + } + + if ( m_adjust_active ) + { + /* Check if we have reached the end of a full cycle */ + if ( m_adjust_counter == m_vert_total_adj ) + { + m_adjust_active = 0; + m_raster_counter = 0; + m_line_counter = 0; + m_line_address = m_disp_start_addr; + m_line_enable_ff = true; + /* also update the cursor state now */ + update_cursor_state(); + + if (m_screen != NULL) + m_screen->reset_origin(); + } + else + { + m_adjust_counter = ( m_adjust_counter + 1 ) & 0x1F; + } + } + + if ( m_line_enable_ff ) + { + /* Schedule DE off signal change */ + m_de_off_timer->adjust(attotime::from_ticks( m_horiz_disp, m_clock )); + + /* Is cursor visible on this line? */ + if ( m_cursor_state && + (m_raster_counter >= (m_cursor_start_ras & 0x1f)) && + (m_raster_counter <= m_cursor_end_ras) && + (m_cursor_addr >= m_line_address) && + (m_cursor_addr < (m_line_address + m_horiz_disp)) ) + { + m_cursor_x = m_cursor_addr - m_line_address; + + /* Schedule CURSOR ON signal */ + m_cur_on_timer->adjust( attotime::from_ticks( m_cursor_x, m_clock ) ); + } + } + + /* Schedule HSYNC on signal */ + m_hsync_on_timer->adjust( attotime::from_ticks( m_horiz_sync_pos, m_clock ) ); + + /* Schedule our next callback */ + m_line_timer->adjust( attotime::from_ticks( m_horiz_char_total + 1, m_clock ) ); + + /* Set VSYNC and DE signals */ + set_vsync( new_vsync ); + set_de( m_line_enable_ff ? TRUE : FALSE ); +} + + +void mc6845_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch (id) + { + case TIMER_LINE: + handle_line_timer(); + break; + + case TIMER_DE_OFF: + set_de( FALSE ); + break; + + case TIMER_CUR_ON: + set_cur( TRUE ); + + /* Schedule CURSOR off signal */ + m_cur_off_timer->adjust( attotime::from_ticks( 1, m_clock ) ); + break; + + case TIMER_CUR_OFF: + set_cur( FALSE ); + break; + + case TIMER_HSYNC_ON: + { + UINT8 hsync_width = ( m_sync_width & 0x0f ) ? ( m_sync_width & 0x0f ) : 0x10; + + m_hsync_width_counter = 0; + set_hsync( TRUE ); + + /* Schedule HSYNC off signal */ + m_hsync_off_timer->adjust( attotime::from_ticks( hsync_width, m_clock ) ); + } + break; + + case TIMER_HSYNC_OFF: + set_hsync( FALSE ); + break; + + case TIMER_LIGHT_PEN_LATCH: + m_light_pen_addr = get_ma(); + m_light_pen_latched = true; + break; + + case TIMER_UPD_ADR: + /* fire a update address strobe */ + call_on_update_address(0); + break; + + case TIMER_UPD_TRANS: + { + int addr = (param >> 8); + int strobe = (param & 0xff); + + /* call the callback function -- we know it exists */ + m_on_update_addr_changed_cb(addr, strobe); + + if(!m_update_ready_bit && MODE_TRANSPARENT_BLANK) + { + m_update_addr++; + m_update_addr &= 0x3fff; + m_update_ready_bit = true; + } + } + break; + + } +} + + +void mos8563_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch (id) + { + case TIMER_BLOCK_COPY: + { + UINT8 data = VSS_COPY ? read_videoram(m_block_addr++) : m_data; + + write_videoram(m_update_addr++, data); + + if (--m_word_count) + { + m_block_copy_timer->adjust( attotime::from_ticks( 1, m_clock ) ); + } + else + { + m_update_ready_bit = 1; + } + break; + } + default: + mc6845_device::device_timer(timer, id, param, ptr); + break; + } +} + + +UINT16 mc6845_device::get_ma() +{ + update_counters(); + + return ( m_line_address + m_character_counter ) & 0x3fff; +} + + +UINT8 mc6845_device::get_ra() +{ + return m_raster_counter; +} + + +void mc6845_device::assert_light_pen_input() +{ + /* compute the pixel coordinate of the NEXT character -- this is when the light pen latches */ + /* set the timer that will latch the display address into the light pen registers */ + m_light_pen_latch_timer->adjust(attotime::from_ticks( 1, m_clock )); +} + + +void mc6845_device::set_clock(int clock) +{ + /* validate arguments */ + assert(clock > 0); + + if (clock != m_clock) + { + m_clock = clock; + recompute_parameters(true); + } +} + + +void mc6845_device::set_hpixels_per_column(int hpixels_per_column) +{ + /* validate arguments */ + assert(hpixels_per_column > 0); + + if (hpixels_per_column != m_hpixels_per_column) + { + m_hpixels_per_column = hpixels_per_column; + recompute_parameters(false); + } +} + + +void mc6845_device::update_cursor_state() +{ + /* save and increment cursor counter */ + UINT8 last_cursor_blink_count = m_cursor_blink_count; + m_cursor_blink_count = m_cursor_blink_count + 1; + + /* switch on cursor blinking mode */ + switch (m_cursor_start_ras & 0x60) + { + /* always on */ + case 0x00: m_cursor_state = true; break; + + /* always off */ + default: + case 0x20: m_cursor_state = false; break; + + /* fast blink */ + case 0x40: + if ((last_cursor_blink_count & 0x10) != (m_cursor_blink_count & 0x10)) + m_cursor_state = !m_cursor_state; + break; + + /* slow blink */ + case 0x60: + if ((last_cursor_blink_count & 0x20) != (m_cursor_blink_count & 0x20)) + m_cursor_state = !m_cursor_state; + break; + } +} + + +UINT8 mc6845_device::draw_scanline(int y, bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + /* compute the current raster line */ + UINT8 ra = y % (m_max_ras_addr + 1); + + /* check if the cursor is visible and is on this scanline */ + int cursor_visible = m_cursor_state && + (ra >= (m_cursor_start_ras & 0x1f)) && + (ra <= m_cursor_end_ras) && + (m_cursor_addr >= m_current_disp_addr) && + (m_cursor_addr < (m_current_disp_addr + m_horiz_disp)); + + /* compute the cursor X position, or -1 if not visible */ + INT8 cursor_x = cursor_visible ? (m_cursor_addr - m_current_disp_addr) : -1; + int de = (y < m_max_visible_y) ? 1 : 0; + int vbp = m_vert_pix_total - m_vsync_off_pos; + if (vbp < 0) vbp = 0; + int hbp = m_horiz_pix_total - m_hsync_off_pos; + if (hbp < 0) hbp = 0; + + /* call the external system to draw it */ + if (MODE_ROW_COLUMN_ADDRESSING) + { + UINT8 cc = 0; + UINT8 cr = y / (m_max_ras_addr + 1); + UINT16 ma = (cr << 8) | cc; + + m_update_row_cb(bitmap, cliprect, ma, ra, y, m_horiz_disp, cursor_x, de, hbp, vbp); + } + else + { + m_update_row_cb(bitmap, cliprect, m_current_disp_addr, ra, y, m_horiz_disp, cursor_x, de, hbp, vbp); + } + + /* update MA if the last raster address */ + if (ra == m_max_ras_addr) + m_current_disp_addr = (m_current_disp_addr + m_horiz_disp) & 0x3fff; + + return ra; +} + + +UINT32 mc6845_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + assert(bitmap.valid()); + + if (m_has_valid_parameters) + { + assert(!m_update_row_cb.isnull()); + + /* call the set up function if any */ + if (!m_begin_update_cb.isnull()) + m_begin_update_cb(bitmap, cliprect); + + if (cliprect.min_y == 0) + { + /* read the start address at the beginning of the frame */ + m_current_disp_addr = m_disp_start_addr; + } + + /* for each row in the visible region */ + for (UINT16 y = cliprect.min_y; y <= cliprect.max_y; y++) + { + this->draw_scanline(y, bitmap, cliprect); + } + + /* call the tear down function if any */ + if (!m_end_update_cb.isnull()) + m_end_update_cb(bitmap, cliprect); + } + else + { + if (LOG) logerror("M6845: Invalid screen parameters - display disabled!!!\n"); + } + + return 0; +} + + +void mc6845_device::device_start() +{ + assert(m_clock > 0); + assert(m_hpixels_per_column > 0); + + /* resolve callbacks */ + m_out_de_cb.resolve_safe(); + m_out_cur_cb.resolve_safe(); + m_out_hsync_cb.resolve_safe(); + m_out_vsync_cb.resolve_safe(); + + /* bind delegates */ + m_begin_update_cb.bind_relative_to(*owner()); + m_update_row_cb.bind_relative_to(*owner()); + m_end_update_cb.bind_relative_to(*owner()); + m_on_update_addr_changed_cb.bind_relative_to(*owner()); + + /* create the timers */ + m_line_timer = timer_alloc(TIMER_LINE); + m_de_off_timer = timer_alloc(TIMER_DE_OFF); + m_cur_on_timer = timer_alloc(TIMER_CUR_ON); + m_cur_off_timer = timer_alloc(TIMER_CUR_OFF); + m_hsync_on_timer = timer_alloc(TIMER_HSYNC_ON); + m_hsync_off_timer = timer_alloc(TIMER_HSYNC_OFF); + m_light_pen_latch_timer = timer_alloc(TIMER_LIGHT_PEN_LATCH); + m_upd_adr_timer = timer_alloc(TIMER_UPD_ADR); + m_upd_trans_timer = timer_alloc(TIMER_UPD_TRANS); + + /* Use some large startup values */ + m_horiz_char_total = 0xff; + m_max_ras_addr = 0x1f; + m_vert_char_total = 0x7f; + + m_supports_disp_start_addr_r = true; + m_supports_vert_sync_width = false; + m_supports_status_reg_d5 = false; + m_supports_status_reg_d6 = false; + m_supports_status_reg_d7 = false; + m_supports_transparent = false; + m_has_valid_parameters = false; + m_line_enable_ff = false; + m_vsync_ff = 0; + m_raster_counter = 0; + m_adjust_active = 0; + m_horiz_sync_pos = 1; + m_vert_sync_pos = 1; + m_de = 0; + m_sync_width = 1; + m_vert_disp = 0; + m_horiz_pix_total = m_vert_pix_total = 0; + m_max_visible_x = m_max_visible_y = 0; + m_hsync_on_pos = m_vsync_on_pos = 0; + m_hsync_off_pos = m_vsync_off_pos = 0; + m_vsync = m_hsync = 0; + m_cur = 0; + m_line_counter = 0; + m_horiz_disp = m_vert_disp = 0; + m_vert_sync_pos = 0; + m_vert_total_adj = 0; + m_cursor_start_ras = m_cursor_end_ras = m_cursor_addr = 0; + m_cursor_blink_count = 0; + m_cursor_state = 0; + m_update_ready_bit = 0; + m_line_address = 0; + m_current_disp_addr = 0; + m_disp_start_addr = 0; + + save_item(NAME(m_show_border_area)); + save_item(NAME(m_visarea_adjust_min_x)); + save_item(NAME(m_visarea_adjust_max_x)); + save_item(NAME(m_visarea_adjust_min_y)); + save_item(NAME(m_visarea_adjust_max_y)); + save_item(NAME(m_hpixels_per_column)); + save_item(NAME(m_register_address_latch)); + save_item(NAME(m_horiz_char_total)); + save_item(NAME(m_horiz_disp)); + save_item(NAME(m_horiz_sync_pos)); + save_item(NAME(m_sync_width)); + save_item(NAME(m_vert_char_total)); + save_item(NAME(m_vert_total_adj)); + save_item(NAME(m_vert_disp)); + save_item(NAME(m_vert_sync_pos)); + save_item(NAME(m_mode_control)); + save_item(NAME(m_max_ras_addr)); + save_item(NAME(m_cursor_start_ras)); + save_item(NAME(m_cursor_end_ras)); + save_item(NAME(m_disp_start_addr)); + save_item(NAME(m_cursor_addr)); + save_item(NAME(m_light_pen_addr)); + save_item(NAME(m_light_pen_latched)); + save_item(NAME(m_cursor_state)); + save_item(NAME(m_cursor_blink_count)); + save_item(NAME(m_update_addr)); + save_item(NAME(m_update_ready_bit)); + save_item(NAME(m_cur)); + save_item(NAME(m_hsync)); + save_item(NAME(m_vsync)); + save_item(NAME(m_de)); + save_item(NAME(m_character_counter)); + save_item(NAME(m_hsync_width_counter)); + save_item(NAME(m_line_counter)); + save_item(NAME(m_raster_counter)); + save_item(NAME(m_adjust_counter)); + save_item(NAME(m_vsync_width_counter)); + save_item(NAME(m_line_enable_ff)); + save_item(NAME(m_vsync_ff)); + save_item(NAME(m_adjust_active)); + save_item(NAME(m_line_address)); + save_item(NAME(m_cursor_x)); + save_item(NAME(m_has_valid_parameters)); +} + + +void mc6845_1_device::device_start() +{ + mc6845_device::device_start(); + + m_supports_disp_start_addr_r = true; + m_supports_vert_sync_width = true; + m_supports_status_reg_d5 = false; + m_supports_status_reg_d6 = false; + m_supports_status_reg_d7 = false; + m_supports_transparent = false; +} + + +void c6545_1_device::device_start() +{ + mc6845_device::device_start(); + + m_supports_disp_start_addr_r = false; + m_supports_vert_sync_width = true; + m_supports_status_reg_d5 = true; + m_supports_status_reg_d6 = true; + m_supports_status_reg_d7 = false; + m_supports_transparent = false; +} + + +void r6545_1_device::device_start() +{ + mc6845_device::device_start(); + + m_supports_disp_start_addr_r = false; + m_supports_vert_sync_width = true; + m_supports_status_reg_d5 = true; + m_supports_status_reg_d6 = true; + m_supports_status_reg_d7 = true; + m_supports_transparent = true; +} + + +void h46505_device::device_start() +{ + mc6845_device::device_start(); + + m_supports_disp_start_addr_r = false; + m_supports_vert_sync_width = false; + m_supports_status_reg_d5 = false; + m_supports_status_reg_d6 = false; + m_supports_status_reg_d7 = false; + m_supports_transparent = false; +} + + +void hd6845_device::device_start() +{ + mc6845_device::device_start(); + + m_supports_disp_start_addr_r = false; + m_supports_vert_sync_width = true; + m_supports_status_reg_d5 = false; + m_supports_status_reg_d6 = false; + m_supports_status_reg_d7 = false; + m_supports_transparent = false; +} + + +void sy6545_1_device::device_start() +{ + mc6845_device::device_start(); + + m_supports_disp_start_addr_r = false; + m_supports_vert_sync_width = true; + m_supports_status_reg_d5 = true; + m_supports_status_reg_d6 = true; + m_supports_status_reg_d7 = true; + m_supports_transparent = true; +} + + +void sy6845e_device::device_start() +{ + mc6845_device::device_start(); + + m_supports_disp_start_addr_r = false; + m_supports_vert_sync_width = true; + m_supports_status_reg_d5 = true; + m_supports_status_reg_d6 = true; + m_supports_status_reg_d7 = true; + m_supports_transparent = true; +} + + +void hd6345_device::device_start() +{ + mc6845_device::device_start(); + + m_supports_disp_start_addr_r = true; + m_supports_vert_sync_width = true; + m_supports_status_reg_d5 = true; + m_supports_status_reg_d6 = true; + m_supports_status_reg_d7 = true; + m_supports_transparent = true; +} + + +void ams40041_device::device_start() +{ + mc6845_device::device_start(); + + m_horiz_char_total = 113; + m_horiz_disp = 80; + m_horiz_sync_pos = 90; + m_sync_width = 10; + m_vert_char_total = 127; + m_vert_total_adj = 6; + m_vert_disp = 100; + m_vert_sync_pos = 112; + m_mode_control = 2; + + m_supports_disp_start_addr_r = false; + m_supports_vert_sync_width = false; + m_supports_status_reg_d5 = false; + m_supports_status_reg_d6 = false; + m_supports_status_reg_d7 = false; + m_supports_transparent = false; +} + + +void mos8563_device::device_start() +{ + mc6845_device::device_start(); + + /* create the timers */ + m_block_copy_timer = timer_alloc(TIMER_BLOCK_COPY); + + m_supports_status_reg_d5 = true; + m_supports_status_reg_d6 = true; + m_supports_status_reg_d7 = true; + m_update_ready_bit = 1; + + // default update_row delegate + m_update_row_cb = mc6845_update_row_delegate(FUNC(mos8563_device::vdc_update_row), this); + + m_char_blink_state = false; + m_char_blink_count = 0; + m_attribute_addr = 0; + m_horiz_char = 0; + m_vert_char_disp = 0; + m_vert_scroll = 0; + m_horiz_scroll = 0; + m_color = 0; + m_row_addr_incr = 0; + m_char_base_addr = 0; + m_underline_ras = 0; + m_word_count = 0; + m_data = 0; + m_block_addr = 0; + m_de_begin = 0; + m_dram_refresh = 0; + m_sync_polarity = 0; + + m_revision = 1; + + // initialize video RAM + UINT8 data = 0xff; + + for (offs_t offset = 0; offset < 0x10000; offset++) + { + write_videoram(offset, data); + data ^= 0xff; + } + + save_item(NAME(m_char_buffer)); + save_item(NAME(m_attr_buffer)); + save_item(NAME(m_attribute_addr)); + save_item(NAME(m_horiz_char)); + save_item(NAME(m_vert_char_disp)); + save_item(NAME(m_vert_scroll)); + save_item(NAME(m_horiz_scroll)); + save_item(NAME(m_color)); + save_item(NAME(m_row_addr_incr)); + save_item(NAME(m_char_base_addr)); + save_item(NAME(m_underline_ras)); + save_item(NAME(m_word_count)); + save_item(NAME(m_data)); + save_item(NAME(m_block_addr)); + save_item(NAME(m_de_begin)); + save_item(NAME(m_dram_refresh)); + save_item(NAME(m_sync_polarity)); + save_item(NAME(m_revision)); +} + + +void mos8568_device::device_start() +{ + mos8563_device::device_start(); +} + + +void mc6845_device::device_reset() +{ + /* internal registers other than status remain unchanged, all outputs go low */ + m_out_de_cb(false); + + m_out_hsync_cb(false); + + m_out_vsync_cb(false); + + if (!m_line_timer->enabled()) + m_line_timer->adjust(attotime::from_ticks(m_horiz_char_total + 1, m_clock)); + + m_light_pen_latched = false; + + m_cursor_addr = 0; + m_line_address = 0; + m_horiz_disp = 0; + m_cursor_x = 0; + m_mode_control = 0; + m_register_address_latch = 0; + m_update_addr = 0; + m_light_pen_addr = 0; +} + + +void r6545_1_device::device_reset() { mc6845_device::device_reset(); } +void h46505_device::device_reset() { mc6845_device::device_reset(); } +void mc6845_1_device::device_reset() { mc6845_device::device_reset(); } +void hd6845_device::device_reset() { mc6845_device::device_reset(); } +void c6545_1_device::device_reset() { mc6845_device::device_reset(); } +void sy6545_1_device::device_reset() { mc6845_device::device_reset(); } +void sy6845e_device::device_reset() { mc6845_device::device_reset(); } +void hd6345_device::device_reset() { mc6845_device::device_reset(); } +void ams40041_device::device_reset() { mc6845_device::device_reset(); } + +void mos8563_device::device_reset() +{ + mc6845_device::device_reset(); + + m_sync_polarity = 0xc0; +} + +void mos8568_device::device_reset() { mos8563_device::device_reset(); } + + +//------------------------------------------------- +// memory_space_config - return a description of +// any address spaces owned by this device +//------------------------------------------------- + +const address_space_config *mos8563_device::memory_space_config(address_spacenum spacenum) const +{ + switch (spacenum) + { + case AS_0: return &m_videoram_space_config; + default: return NULL; + } +} + +// default address maps +static ADDRESS_MAP_START( mos8563_videoram_map, AS_0, 8, mos8563_device ) + AM_RANGE(0x0000, 0xffff) AM_RAM +ADDRESS_MAP_END + + +r6545_1_device::r6545_1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : mc6845_device(mconfig, R6545_1, "R6545-1 CRTC", tag, owner, clock, "r6545_1", __FILE__) +{ +} + + +h46505_device::h46505_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : mc6845_device(mconfig, H46505, "H46505 CRTC", tag, owner, clock, "h46505", __FILE__) +{ +} + + +mc6845_1_device::mc6845_1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : mc6845_device(mconfig, MC6845_1, "MC6845-1 CRTC", tag, owner, clock, "mc6845_1", __FILE__) +{ +} + + +hd6845_device::hd6845_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : mc6845_device(mconfig, HD6845, "HD6845 CRTC", tag, owner, clock, "hd6845", __FILE__) +{ +} + + +c6545_1_device::c6545_1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : mc6845_device(mconfig, C6545_1, "C6545-1 CRTC", tag, owner, clock, "c6545_1", __FILE__) +{ +} + + +sy6545_1_device::sy6545_1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : mc6845_device(mconfig, SY6545_1, "SY6545-1 CRTC", tag, owner, clock, "sy6545_1", __FILE__) +{ +} + + +sy6845e_device::sy6845e_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : mc6845_device(mconfig, SY6845E, "SY6845E CRTC", tag, owner, clock, "sy6845e", __FILE__) +{ +} + + +hd6345_device::hd6345_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : mc6845_device(mconfig, HD6345, "HD6345 CRTC", tag, owner, clock, "hd6345", __FILE__) +{ +} + + +ams40041_device::ams40041_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : mc6845_device(mconfig, AMS40041, "AMS40041 CRTC", tag, owner, clock, "ams40041", __FILE__) +{ +} + + +mos8563_device::mos8563_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : mc6845_device(mconfig, type, name, tag, owner, clock, shortname, source), + device_memory_interface(mconfig, *this), + m_videoram_space_config("videoram", ENDIANNESS_LITTLE, 8, 16, 0, NULL, *ADDRESS_MAP_NAME(mos8563_videoram_map)), + m_palette(*this, "palette") +{ + set_clock_scale(1.0/8); +} + + +mos8563_device::mos8563_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : mc6845_device(mconfig, MOS8563, "MOS8563", tag, owner, clock, "mos8563", __FILE__), + device_memory_interface(mconfig, *this), + m_videoram_space_config("videoram", ENDIANNESS_LITTLE, 8, 16, 0, NULL, *ADDRESS_MAP_NAME(mos8563_videoram_map)), + m_palette(*this, "palette") +{ + set_clock_scale(1.0/8); +} + + +mos8568_device::mos8568_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : mos8563_device(mconfig, MOS8568, "MOS8568", tag, owner, clock, "mos8568", __FILE__) +{ +} + + +static MACHINE_CONFIG_FRAGMENT(mos8563) + MCFG_PALETTE_ADD("palette", 16) + MCFG_PALETTE_INIT_OWNER(mos8563_device, mos8563) +MACHINE_CONFIG_END + +machine_config_constructor mos8563_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( mos8563 ); +} + + +// VICE palette +PALETTE_INIT_MEMBER(mos8563_device, mos8563) +{ + palette.set_pen_color(0, rgb_t::black); + palette.set_pen_color(1, rgb_t(0x55, 0x55, 0x55)); + palette.set_pen_color(2, rgb_t(0x00, 0x00, 0xaa)); + palette.set_pen_color(3, rgb_t(0x55, 0x55, 0xff)); + palette.set_pen_color(4, rgb_t(0x00, 0xaa, 0x00)); + palette.set_pen_color(5, rgb_t(0x55, 0xff, 0x55)); + palette.set_pen_color(6, rgb_t(0x00, 0xaa, 0xaa)); + palette.set_pen_color(7, rgb_t(0x55, 0xff, 0xff)); + palette.set_pen_color(8, rgb_t(0xaa, 0x00, 0x00)); + palette.set_pen_color(9, rgb_t(0xff, 0x55, 0x55)); + palette.set_pen_color(10, rgb_t(0xaa, 0x00, 0xaa)); + palette.set_pen_color(11, rgb_t(0xff, 0x55, 0xff)); + palette.set_pen_color(12, rgb_t(0xaa, 0x55, 0x00)); + palette.set_pen_color(13, rgb_t(0xff, 0xff, 0x55)); + palette.set_pen_color(14, rgb_t(0xaa, 0xaa, 0xaa)); + palette.set_pen_color(15, rgb_t::white); +} + + +void mos8563_device::update_cursor_state() +{ + mc6845_device::update_cursor_state(); + + /* save and increment character blink counter */ + UINT8 last_char_blink_count = m_char_blink_count; + m_char_blink_count++; + + /* switch on character blinking mode */ + if (VSS_CBRATE) + { + if ((last_char_blink_count & 0x20) != (m_char_blink_count & 0x20)) + m_char_blink_state = !m_char_blink_state; + } + else + { + if ((last_char_blink_count & 0x10) != (m_char_blink_count & 0x10)) + m_char_blink_state = !m_char_blink_state; + } +} + + +UINT8 mos8563_device::draw_scanline(int y, bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + UINT8 ra = mc6845_device::draw_scanline(y, bitmap, cliprect); + + if (ra == m_max_ras_addr) + m_current_disp_addr = (m_current_disp_addr + m_row_addr_incr) & 0x3fff; + + return ra; +} + + +MC6845_UPDATE_ROW( mos8563_device::vdc_update_row ) +{ + const pen_t *pen = m_palette->pens(); + + ra += (m_vert_scroll & 0x0f); + ra &= 0x0f; + + UINT8 cth = (m_horiz_char >> 4) + (HSS_DBL ? 0 : 1); + UINT8 cdh = (m_horiz_char & 0x0f) + (HSS_DBL ? 0 : 1); + UINT8 cdv = m_vert_char_disp; + + for (int column = 0; column < x_count; column++) + { + UINT8 code = read_videoram(ma + column); + UINT8 attr = 0; + + int fg = m_color >> 4; + int bg = m_color & 0x0f; + + if (HSS_ATTR) + { + offs_t attr_addr = m_attribute_addr + ma + column; + attr = read_videoram(attr_addr); + } + + if (HSS_TEXT) + { + if (HSS_ATTR) + { + fg = ATTR_FOREGROUND; + bg = ATTR_BACKGROUND; + } + + if (VSS_RVS) code ^= 0xff; + + for (int bit = 0; bit < cdh; bit++) + { + int x = (m_horiz_scroll & 0x0f) - cth + (column * cth) + bit; + if (x < 0) x = 0; + int color = BIT(code, 7) ? fg : bg; + + bitmap.pix32(vbp + y, hbp + x) = pen[de ? color : 0]; + } + } + else + { + if (HSS_ATTR) + { + fg = ATTR_COLOR; + } + + offs_t font_addr; + + if (m_max_ras_addr < 16) + { + font_addr = ((m_char_base_addr & 0xe0) << 8) | (ATTR_ALTERNATE_CHARSET << 12) | (code << 4) | (ra & 0x0f); + } + else + { + font_addr = ((m_char_base_addr & 0xc0) << 8) | (ATTR_ALTERNATE_CHARSET << 13) | (code << 5) | (ra & 0x1f); + } + + UINT8 data = read_videoram(font_addr); + + if (ra >= cdv) data = 0; + if (ATTR_UNDERLINE && (ra == m_underline_ras)) data = 0xff; + if (ATTR_BLINK && !m_char_blink_state) data = 0; + if (ATTR_REVERSE) data ^= 0xff; + if (column == cursor_x) data ^= 0xff; + if (VSS_RVS) data ^= 0xff; + + for (int bit = 0; bit < cdh; bit++) + { + int x = (m_horiz_scroll & 0x0f) - cth + (column * cth) + bit; + if (x < 0) x = 0; + int color = BIT(data, 7) ? fg : bg; + + bitmap.pix32(vbp + y, hbp + x) = pen[de ? color : 0]; + + if ((bit < 8) || !HSS_SEMI) data <<= 1; + } + } + } +} diff --git a/src/devices/video/mc6845.h b/src/devices/video/mc6845.h new file mode 100644 index 00000000000..053c2b9491e --- /dev/null +++ b/src/devices/video/mc6845.h @@ -0,0 +1,503 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +/********************************************************************** + + Motorola MC6845 and compatible CRT controller emulation + +**********************************************************************/ + +#ifndef __MC6845__ +#define __MC6845__ + +#include "emu.h" + + +#define MCFG_MC6845_ADD(_tag, _variant, _screen_tag, _clock) \ + MCFG_DEVICE_ADD(_tag, _variant, _clock) \ + MCFG_VIDEO_SET_SCREEN(_screen_tag) + +#define MCFG_MOS8563_ADD(_tag, _screen_tag, _clock, _map) \ + MCFG_DEVICE_ADD(_tag, MOS8563, _clock) \ + MCFG_VIDEO_SET_SCREEN(_screen_tag) \ + MCFG_DEVICE_ADDRESS_MAP(AS_0, _map) + +#define MCFG_MOS8568_ADD(_tag, _screen_tag, _clock, _map) \ + MCFG_DEVICE_ADD(_tag, MOS8568, _clock) \ + MCFG_VIDEO_SET_SCREEN(_screen_tag) \ + MCFG_DEVICE_ADDRESS_MAP(AS_0, _map) + + +#define MCFG_MC6845_SHOW_BORDER_AREA(_show) \ + mc6845_device::set_show_border_area(*device, _show); + +#define MCFG_MC6845_INTERLACE_ADJUST(_value) \ + mc6845_device::set_interlace_adjust(*device, _value); + +#define MCFG_MC6845_VISAREA_ADJUST(_minx, _maxx, _miny, _maxy) \ + mc6845_device::set_visarea_adjust(*device, _minx, _maxx, _miny, _maxy); + +#define MCFG_MC6845_CHAR_WIDTH(_pixels) \ + mc6845_device::set_char_width(*device, _pixels); + +#define MCFG_MC6845_BEGIN_UPDATE_CB(_class, _method) \ + mc6845_device::set_begin_update_callback(*device, mc6845_begin_update_delegate(&_class::_method, #_class "::" #_method, downcast<_class *>(owner))); + +#define MCFG_MC6845_UPDATE_ROW_CB(_class, _method) \ + mc6845_device::set_update_row_callback(*device, mc6845_update_row_delegate(&_class::_method, #_class "::" #_method, downcast<_class *>(owner))); + +#define MCFG_MC6845_END_UPDATE_CB(_class, _method) \ + mc6845_device::set_end_update_callback(*device, mc6845_end_update_delegate(&_class::_method, #_class "::" #_method, downcast<_class *>(owner))); + +#define MCFG_MC6845_ADDR_CHANGED_CB(_class, _method) \ + mc6845_device::set_on_update_addr_change_callback(*device, mc6845_on_update_addr_changed_delegate(&_class::_method, #_class "::" #_method, downcast<_class *>(owner))); + +#define MCFG_MC6845_OUT_DE_CB(_write) \ + devcb = &mc6845_device::set_out_de_callback(*device, DEVCB_##_write); + +#define MCFG_MC6845_OUT_CUR_CB(_write) \ + devcb = &mc6845_device::set_out_cur_callback(*device, DEVCB_##_write); + +#define MCFG_MC6845_OUT_HSYNC_CB(_write) \ + devcb = &mc6845_device::set_out_hsync_callback(*device, DEVCB_##_write); + +#define MCFG_MC6845_OUT_VSYNC_CB(_write) \ + devcb = &mc6845_device::set_out_vsync_callback(*device, DEVCB_##_write); + + +/* callback definitions */ +typedef device_delegate mc6845_begin_update_delegate; +#define MC6845_BEGIN_UPDATE(name) void name(bitmap_rgb32 &bitmap, const rectangle &cliprect) + +typedef device_delegate mc6845_update_row_delegate; +#define MC6845_UPDATE_ROW(name) void name(bitmap_rgb32 &bitmap, const rectangle &cliprect, UINT16 ma, UINT8 ra, \ + UINT16 y, UINT8 x_count, INT8 cursor_x, int de, int hbp, int vbp) + +typedef device_delegate mc6845_end_update_delegate; +#define MC6845_END_UPDATE(name) void name(bitmap_rgb32 &bitmap, const rectangle &cliprect) + +typedef device_delegate mc6845_on_update_addr_changed_delegate; +#define MC6845_ON_UPDATE_ADDR_CHANGED(name) void name(int address, int strobe) + + +class mc6845_device : public device_t, + public device_video_interface +{ + friend class mc6845_1_device; + friend class r6545_1_device; + friend class c6545_1_device; + friend class h46505_device; + friend class hd6845_device; + friend class sy6545_1_device; + friend class sy6845e_device; + friend class hd6345_device; + friend class ams40041_device; + +public: + // construction/destruction + mc6845_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + mc6845_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + static void set_show_border_area(device_t &device, bool show) { downcast(device).m_show_border_area = show; } + static void set_interlace_adjust(device_t &device, int value) { downcast(device).m_interlace_adjust = value; } + static void set_visarea_adjust(device_t &device, int min_x, int max_x, int min_y, int max_y) + { + mc6845_device &dev = downcast(device); + dev.m_visarea_adjust_min_x = min_x; + dev.m_visarea_adjust_max_x = max_x; + dev.m_visarea_adjust_min_y = min_y; + dev.m_visarea_adjust_max_y = max_y; + } + static void set_char_width(device_t &device, int pixels) { downcast(device).m_hpixels_per_column = pixels; } + + static void set_begin_update_callback(device_t &device, mc6845_begin_update_delegate callback) { downcast(device).m_begin_update_cb = callback; } + static void set_update_row_callback(device_t &device, mc6845_update_row_delegate callback) { downcast(device).m_update_row_cb = callback; } + static void set_end_update_callback(device_t &device, mc6845_end_update_delegate callback) { downcast(device).m_end_update_cb = callback; } + static void set_on_update_addr_change_callback(device_t &device, mc6845_on_update_addr_changed_delegate callback) { downcast(device).m_on_update_addr_changed_cb = callback; } + + template static devcb_base &set_out_de_callback(device_t &device, _Object object) { return downcast(device).m_out_de_cb.set_callback(object); } + template static devcb_base &set_out_cur_callback(device_t &device, _Object object) { return downcast(device).m_out_cur_cb.set_callback(object); } + template static devcb_base &set_out_hsync_callback(device_t &device, _Object object) { return downcast(device).m_out_hsync_cb.set_callback(object); } + template static devcb_base &set_out_vsync_callback(device_t &device, _Object object) { return downcast(device).m_out_vsync_cb.set_callback(object); } + + /* select one of the registers for reading or writing */ + DECLARE_WRITE8_MEMBER( address_w ); + + /* read from the status register */ + DECLARE_READ8_MEMBER( status_r ); + + /* read from the currently selected register */ + DECLARE_READ8_MEMBER( register_r ); + + /* write to the currently selected register */ + DECLARE_WRITE8_MEMBER( register_w ); + + // read display enable line state + DECLARE_READ_LINE_MEMBER( de_r ); + + // read cursor line state + DECLARE_READ_LINE_MEMBER( cursor_r ); + + // read horizontal sync line state + DECLARE_READ_LINE_MEMBER( hsync_r ); + + // read vertical sync line state + DECLARE_READ_LINE_MEMBER( vsync_r ); + + /* return the current value on the MA0-MA13 pins */ + UINT16 get_ma(); + + /* return the current value on the RA0-RA4 pins */ + UINT8 get_ra(); + + /* simulates the LO->HI clocking of the light pen pin (pin 3) */ + void assert_light_pen_input(); + + /* set the clock (pin 21) of the chip */ + void set_clock(int clock); + + /* set number of pixels per video memory address */ + void set_hpixels_per_column(int hpixels_per_column); + + /* updates the screen -- this will call begin_update(), + followed by update_row() reapeatedly and after all row + updating is complete, end_update() */ + UINT32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_post_load(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + bool m_supports_disp_start_addr_r; + bool m_supports_vert_sync_width; + bool m_supports_status_reg_d5; + bool m_supports_status_reg_d6; + bool m_supports_status_reg_d7; + bool m_supports_transparent; + + /* register file */ + UINT8 m_horiz_char_total; /* 0x00 */ + UINT8 m_horiz_disp; /* 0x01 */ + UINT8 m_horiz_sync_pos; /* 0x02 */ + UINT8 m_sync_width; /* 0x03 */ + UINT8 m_vert_char_total; /* 0x04 */ + UINT8 m_vert_total_adj; /* 0x05 */ + UINT8 m_vert_disp; /* 0x06 */ + UINT8 m_vert_sync_pos; /* 0x07 */ + UINT8 m_mode_control; /* 0x08 */ + UINT8 m_max_ras_addr; /* 0x09 */ + UINT8 m_cursor_start_ras; /* 0x0a */ + UINT8 m_cursor_end_ras; /* 0x0b */ + UINT16 m_disp_start_addr; /* 0x0c/0x0d */ + UINT16 m_cursor_addr; /* 0x0e/0x0f */ + UINT16 m_light_pen_addr; /* 0x10/0x11 */ + UINT16 m_update_addr; /* 0x12/0x13 */ + + /* other internal state */ + UINT8 m_register_address_latch; + bool m_cursor_state; + UINT8 m_cursor_blink_count; + bool m_update_ready_bit; + /* output signals */ + int m_cur; + int m_hsync; + int m_vsync; + int m_de; + + /* internal counters */ + UINT8 m_character_counter; /* Not used yet */ + UINT8 m_hsync_width_counter; /* Not used yet */ + UINT8 m_line_counter; + UINT8 m_raster_counter; + UINT8 m_adjust_counter; + UINT8 m_vsync_width_counter; + + bool m_line_enable_ff; /* Internal flip flop which is set when the line_counter is reset and reset when vert_disp is reached */ + UINT8 m_vsync_ff; + UINT8 m_adjust_active; + UINT16 m_line_address; + INT16 m_cursor_x; + + /* timers */ + static const device_timer_id TIMER_LINE = 0; + static const device_timer_id TIMER_DE_OFF = 1; + static const device_timer_id TIMER_CUR_ON = 2; + static const device_timer_id TIMER_CUR_OFF = 3; + static const device_timer_id TIMER_HSYNC_ON = 4; + static const device_timer_id TIMER_HSYNC_OFF = 5; + static const device_timer_id TIMER_LIGHT_PEN_LATCH = 6; + static const device_timer_id TIMER_UPD_ADR = 7; + static const device_timer_id TIMER_UPD_TRANS = 8; + + emu_timer *m_line_timer; + emu_timer *m_de_off_timer; + emu_timer *m_cur_on_timer; + emu_timer *m_cur_off_timer; + emu_timer *m_hsync_on_timer; + emu_timer *m_hsync_off_timer; + emu_timer *m_light_pen_latch_timer; + emu_timer *m_upd_adr_timer; + emu_timer *m_upd_trans_timer; + + /* computed values - do NOT state save these! */ + /* These computed are used to define the screen parameters for a driver */ + UINT16 m_horiz_pix_total; + UINT16 m_vert_pix_total; + UINT16 m_max_visible_x; + UINT16 m_max_visible_y; + UINT16 m_hsync_on_pos; + UINT16 m_hsync_off_pos; + UINT16 m_vsync_on_pos; + UINT16 m_vsync_off_pos; + bool m_has_valid_parameters; + + UINT16 m_current_disp_addr; /* the display address currently drawn (used only in mc6845_update) */ + + bool m_light_pen_latched; + attotime m_upd_time; + + void update_upd_adr_timer(); + void call_on_update_address(int strobe); + void recompute_parameters(bool postload); + void update_counters(); + void set_de(int state); + void set_hsync(int state); + void set_vsync(int state); + void set_cur(int state); + void handle_line_timer(); + virtual void update_cursor_state(); + virtual UINT8 draw_scanline(int y, bitmap_rgb32 &bitmap, const rectangle &cliprect); + + /************************ + interface CRTC - driver + ************************/ + + bool m_show_border_area; /* visible screen area (false) active display (true) active display + blanking */ + int m_interlace_adjust; /* adjust max ras in interlace mode */ + + /* visible screen area adjustment */ + int m_visarea_adjust_min_x; + int m_visarea_adjust_max_x; + int m_visarea_adjust_min_y; + int m_visarea_adjust_max_y; + + int m_hpixels_per_column; /* number of pixels per video memory address */ + + /* if specified, this gets called before any pixel update, + optionally return a pointer that will be passed to the + update and tear down callbacks */ + mc6845_begin_update_delegate m_begin_update_cb; + + /* this gets called for every row, the driver must output + x_count * hpixels_per_column pixels. + cursor_x indicates the character position where the cursor is, or -1 + if there is no cursor on this row */ + mc6845_update_row_delegate m_update_row_cb; + + /* if specified, this gets called after all row updating is complete */ + mc6845_end_update_delegate m_end_update_cb; + + /* Called whenever the update address changes + * For vblank/hblank timing strobe indicates the physical update. + * vblank/hblank timing not supported yet! */ + mc6845_on_update_addr_changed_delegate m_on_update_addr_changed_cb; + + /* if specified, this gets called for every change of the disply enable pin (pin 18) */ + devcb_write_line m_out_de_cb; + + /* if specified, this gets called for every change of the cursor pin (pin 19) */ + devcb_write_line m_out_cur_cb; + + /* if specified, this gets called for every change of the HSYNC pin (pin 39) */ + devcb_write_line m_out_hsync_cb; + + /* if specified, this gets called for every change of the VSYNC pin (pin 40) */ + devcb_write_line m_out_vsync_cb; +}; + + +class mc6845_1_device : public mc6845_device +{ +public: + mc6845_1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual void device_start(); + virtual void device_reset(); +}; + +class r6545_1_device : public mc6845_device +{ +public: + r6545_1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual void device_start(); + virtual void device_reset(); +}; + +class c6545_1_device : public mc6845_device +{ +public: + c6545_1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual void device_start(); + virtual void device_reset(); +}; + +class h46505_device : public mc6845_device +{ +public: + h46505_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual void device_start(); + virtual void device_reset(); +}; + +class hd6845_device : public mc6845_device +{ +public: + hd6845_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual void device_start(); + virtual void device_reset(); +}; + +class sy6545_1_device : public mc6845_device +{ +public: + sy6545_1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual void device_start(); + virtual void device_reset(); +}; + +class sy6845e_device : public mc6845_device +{ +public: + sy6845e_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual void device_start(); + virtual void device_reset(); +}; + +class hd6345_device : public mc6845_device +{ +public: + hd6345_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual void device_start(); + virtual void device_reset(); +}; + +class ams40041_device : public mc6845_device +{ +public: + ams40041_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual void device_start(); + virtual void device_reset(); +}; + +class mos8563_device : public mc6845_device, + public device_memory_interface +{ +public: + mos8563_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + mos8563_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const; + + DECLARE_PALETTE_INIT(mos8563); + + DECLARE_WRITE8_MEMBER( address_w ); + DECLARE_READ8_MEMBER( status_r ); + DECLARE_READ8_MEMBER( register_r ); + DECLARE_WRITE8_MEMBER( register_w ); + + inline UINT8 read_videoram(offs_t offset); + inline void write_videoram(offs_t offset, UINT8 data); + + MC6845_UPDATE_ROW( vdc_update_row ); + +protected: + // device-level overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + const address_space_config m_videoram_space_config; + required_device m_palette; + + UINT8 m_char_buffer[80]; + UINT8 m_attr_buffer[80]; + + bool m_char_blink_state; + UINT8 m_char_blink_count; + + /* register file */ + UINT16 m_attribute_addr; /* 0x14/0x15 */ + UINT8 m_horiz_char; /* 0x16 */ + UINT8 m_vert_char_disp; /* 0x17 */ + UINT8 m_vert_scroll; /* 0x18 */ + UINT8 m_horiz_scroll; /* 0x19 */ + UINT8 m_color; /* 0x1a */ + UINT8 m_row_addr_incr; /* 0x1b */ + UINT8 m_char_base_addr; /* 0x1c */ + UINT8 m_underline_ras; /* 0x1d */ + UINT8 m_word_count; /* 0x1e */ + UINT8 m_data; /* 0x1f */ + UINT16 m_block_addr; /* 0x20/0x21 */ + UINT16 m_de_begin; /* 0x22/0x23 */ + UINT8 m_dram_refresh; /* 0x24 */ + UINT8 m_sync_polarity; /* 0x25 */ + + int m_revision; + + virtual void update_cursor_state(); + virtual UINT8 draw_scanline(int y, bitmap_rgb32 &bitmap, const rectangle &cliprect); + + static const device_timer_id TIMER_BLOCK_COPY = 9; + + emu_timer *m_block_copy_timer; +}; + +class mos8568_device : public mos8563_device +{ +public: + mos8568_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); +}; + + +extern const device_type MC6845; +extern const device_type MC6845_1; +extern const device_type R6545_1; +extern const device_type C6545_1; +extern const device_type H46505; +extern const device_type HD6845; +extern const device_type SY6545_1; +extern const device_type SY6845E; +extern const device_type HD6345; +extern const device_type AMS40041; +extern const device_type MOS8563; +extern const device_type MOS8568; + + + +#endif diff --git a/src/devices/video/mc6847.c b/src/devices/video/mc6847.c new file mode 100644 index 00000000000..76c0dcb4c92 --- /dev/null +++ b/src/devices/video/mc6847.c @@ -0,0 +1,1890 @@ +// license:BSD-3-Clause +// copyright-holders:Nathan Woods +/********************************************************************* + + mc6847.c + + Implementation of Motorola 6847 video hardware chip + + Sources: + M6847 data sheet + M6847T1 info from Rainbow magazine (10/1986-12/1986) + + + AG AS INTEXT INV GM2 GM1 GM0 + -- -- ------ --- --- --- --- + 0 0 0 0 X X X Internal Alphanumerics + 0 0 0 1 X X X Internal Alphanumerics Inverted + 0 0 1 0 X X X External Alphanumerics + 0 0 1 1 X X X External Alphanumerics Inverted + 0 1 0 X X X X Semigraphics 4 + 0 1 1 X X X X Semigraphics 6 + 1 X X X 0 0 0 Graphics CG1 (64x64x4) (16 bpr) + 1 X X X 0 0 1 Graphics RG1 (128x64x2) (16 bpr) + 1 X X X 0 1 0 Graphics CG2 (128x64x4) (32 bpr) + 1 X X X 0 1 1 Graphics RG2 (128x96x2) (16 bpr) + 1 X X X 1 0 0 Graphics CG3 (128x96x4) (32 bpr) + 1 X X X 1 0 1 Graphics RG3 (128x192x2) (16 bpr) + 1 X X X 1 1 0 Graphics CG6 (128x192x4) (32 bpr) + 1 X X X 1 1 1 Graphics RG6 (256x192x2) (32 bpr) + + Note: The M6847 relies on an external source (typically a 6883 SAM chip) + to feed it bytes; so the BPR (bytes per row) figures are effectively + suggestions. Mismatching modes is responsible for the semigraphic modes + on the CoCo. + + Timing: (source Motorola M6847 Manual, experimentation, SockMaster) + + Horizontal Sync: Total Period: 228 clock cycles + @ CLK(0) + DHS_F - falling edge (high to low) + @ CLK(16.5) + DHS_R - rising edge (low to high) + @ CLK(42) - left border start + @ CLK(71.5) - body start + @ CLK(199.5) - right border start + @ CLK(228) + DHS_F - falling edge (high to low) + ... + + Field Sync: Total Period 262*228 clock cycles + @ CLK(0) + DFS_F - falling edge (high to low) + @ CLK(32*228) + DFS_R - rising edge (low to high) + @ CLK(262*228) + DFS_F - falling edge (high to low) (262.5 for the M6847Y) + + DHS_F: 550ns + DHS_R: 740ns + DFS_F: 520ns + DFS_R: 500ns + + The M6847T1 is a later variant of the M6847 chip that implements lower + case support and some other nifty features. This chip is in the CoCo 2B. + I have not been able to find a pinout diagram for this chip so I am + assuming that the extra text modes on the CoCo 2B are activated by the + GM2-0 pins. This needs to be confirmed. + + The MC6847 datasheet states that a scanline is 227.5 clock cycles, + but experimentation suggests that it is 228. The game "Dragon Fire" + has a fine tuned loop that runs in 57 clock cycles by the CPU's + reckoning (228 actual clock cycles) and would not function correctly + if skew existed. SockMaster has confirmed that scanlines are in + fact 228 clock cycles. + + The PAL emulation is little more than having more scanlines; surely + there are details that we are missing here. + +**********************************************************************/ + + +#include "emu.h" +#include "video/mc6847.h" + + +//************************************************************************** +// CONSTANTS +//************************************************************************** + +#define TOP_BORDER 25 +#define USE_HORIZONTAL_CLIP false + +#define TIMER_HSYNC_PERIOD (228) +#define TIMER_HSYNC_OFF_TIME (10.0) +#define TIMER_HSYNC_ON_TIME (TIMER_HSYNC_OFF_TIME + 16.5) +#define TIMER_FSYNC_OFF_TIME (TIMER_HSYNC_PERIOD * TOP_BORDER + TIMER_HSYNC_ON_TIME) +#define TIMER_FSYNC_ON_TIME (TIMER_HSYNC_PERIOD * (TOP_BORDER + 192) + TIMER_HSYNC_ON_TIME) + +#define LOG_SCANLINE 0 +#define LOG_HSYNC 0 +#define LOG_FSYNC 0 +#define LOG_FLUSH 0 +#define LOG_INPUT 0 + + +const UINT32 mc6847_base_device::s_palette[mc6847_base_device::PALETTE_LENGTH] = +{ + rgb_t(0x07, 0xff, 0x00), /* GREEN */ + rgb_t(0xff, 0xff, 0x00), /* YELLOW */ + rgb_t(0x3b, 0x08, 0xff), /* BLUE */ + rgb_t(0xcc, 0x00, 0x3b), /* RED */ + rgb_t(0xff, 0xff, 0xff), /* BUFF */ + rgb_t(0x07, 0xe3, 0x99), /* CYAN */ + rgb_t(0xff, 0x1c, 0xff), /* MAGENTA */ + rgb_t(0xff, 0x81, 0x00), /* ORANGE */ + + rgb_t(0x00, 0x00, 0x00), /* BLACK */ + rgb_t(0x07, 0xff, 0x00), /* GREEN */ + rgb_t(0x00, 0x00, 0x00), /* BLACK */ + rgb_t(0xff, 0xff, 0xff), /* BUFF */ + + rgb_t(0x00, 0x7c, 0x00), /* ALPHANUMERIC DARK GREEN */ + rgb_t(0x07, 0xff, 0x00), /* ALPHANUMERIC BRIGHT GREEN */ + rgb_t(0x91, 0x00, 0x00), /* ALPHANUMERIC DARK ORANGE */ + rgb_t(0xff, 0x81, 0x00) /* ALPHANUMERIC BRIGHT ORANGE */ +}; + + + +//************************************************************************** +// FRIEND DEVICE +//************************************************************************** + +//------------------------------------------------- +// ctor +//------------------------------------------------- + +mc6847_friend_device::mc6847_friend_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, + const UINT8 *fontdata, bool is_mc6847t1, double tpfs, int field_sync_falling_edge_scanline, bool supports_partial_body_scanlines, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + m_write_hsync(*this), + m_write_fsync(*this), + m_character_map(fontdata, is_mc6847t1) +{ + m_tpfs = tpfs; + m_supports_partial_body_scanlines = supports_partial_body_scanlines; + + // The MC6847 and the GIME apply field sync on different scanlines + m_field_sync_falling_edge_scanline = field_sync_falling_edge_scanline; +} + + + +//------------------------------------------------- +// setup_timer - sets up a single timer relative +// to the clock +//------------------------------------------------- + +inline emu_timer *mc6847_friend_device::setup_timer(device_timer_id id, double offset, double period) +{ + emu_timer *timer = timer_alloc(id); + timer->adjust( + attotime::from_ticks(offset * 4, m_clock * 4), + 0, + attotime::from_ticks(period * 4, m_clock * 4)); + return timer; +} + + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void mc6847_friend_device::device_start(void) +{ + m_write_hsync.resolve_safe(); + m_write_fsync.resolve_safe(); + + /* create the timers */ + m_frame_timer = setup_timer( TIMER_FRAME, 0, m_tpfs * TIMER_HSYNC_PERIOD); + m_hsync_on_timer = setup_timer( TIMER_HSYNC_ON, TIMER_HSYNC_ON_TIME, TIMER_HSYNC_PERIOD); + m_hsync_off_timer = setup_timer(TIMER_HSYNC_OFF, TIMER_HSYNC_OFF_TIME, TIMER_HSYNC_PERIOD); + m_fsync_timer = timer_alloc(TIMER_FSYNC); + + m_top_border_scanlines = 0; + m_body_scanlines = 0; + m_wide = false; + m_recording_scanline = false; + m_physical_scanline = 0; + m_logical_scanline_zone = 0; + m_field_sync = false; + m_horizontal_sync = false; + set_geometry(25, 192, false); + + /* save states */ + save_item(NAME(m_physical_scanline)); + save_item(NAME(m_logical_scanline)); + save_item(NAME(m_logical_scanline_zone)); + save_item(NAME(m_horizontal_sync)); + save_item(NAME(m_field_sync)); + + /* artifacting */ + m_artifacter.setup_config(this); +} + + + +//------------------------------------------------- +// device_start - device-specific reset +//------------------------------------------------- + +void mc6847_friend_device::device_reset(void) +{ + device_t::device_reset(); + m_video_changed = true; +} + + + +//------------------------------------------------- +// device_post_load - device-specific post load +//------------------------------------------------- + +void mc6847_friend_device::device_post_load(void) +{ + device_t::device_post_load(); + m_video_changed = true; +} + + + +//------------------------------------------------- +// update_field_sync_timer +//------------------------------------------------- + +void mc6847_friend_device::update_field_sync_timer(void) +{ + // are we expecting field sync? + bool expected_field_sync = (m_physical_scanline < m_field_sync_falling_edge_scanline) + || (m_logical_scanline_zone == SCANLINE_ZONE_VBLANK); + + // do we need to adjust the timer? + if (expected_field_sync != m_field_sync) + { + // if so, determine the duration + attotime duration = attotime::from_ticks(160, m_clock); + + // and reset the timer + m_fsync_timer->adjust(duration, expected_field_sync ? 1 : 0); + } +} + + + +//------------------------------------------------- +// device_timer +//------------------------------------------------- + +void mc6847_friend_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch(id) + { + case TIMER_FRAME: new_frame(); break; + case TIMER_HSYNC_ON: change_horizontal_sync(true); break; + case TIMER_HSYNC_OFF: change_horizontal_sync(false); break; + case TIMER_FSYNC: change_field_sync(param != 0); break; + } +} + + + +//------------------------------------------------- +// new_frame +//------------------------------------------------- + +inline void mc6847_friend_device::new_frame(void) +{ + m_physical_scanline = 0; + m_logical_scanline = 0; + m_logical_scanline_zone = SCANLINE_ZONE_FRAME_END; +} + + + +//------------------------------------------------- +// scanline_zone_string +//------------------------------------------------- + +const char *mc6847_friend_device::scanline_zone_string(scanline_zone zone) +{ + const char *result; + switch(zone) + { + case SCANLINE_ZONE_TOP_BORDER: result = "SCANLINE_ZONE_TOP_BORDER"; break; + case SCANLINE_ZONE_BODY: result = "SCANLINE_ZONE_BODY"; break; + case SCANLINE_ZONE_BOTTOM_BORDER: result = "SCANLINE_ZONE_BOTTOM_BORDER"; break; + case SCANLINE_ZONE_RETRACE: result = "SCANLINE_ZONE_RETRACE"; break; + case SCANLINE_ZONE_VBLANK: result = "SCANLINE_ZONE_VBLANK"; break; + case SCANLINE_ZONE_FRAME_END: result = "SCANLINE_ZONE_FRAME_END"; break; + default: + fatalerror("Should not get here\n"); + } + return result; +} + + + +//------------------------------------------------- +// change_horizontal_sync +//------------------------------------------------- + +inline void mc6847_friend_device::change_horizontal_sync(bool line) +{ + g_profiler.start(PROFILER_USER1); + + // are we on a rising edge? + if (line && !m_horizontal_sync) + { + if (LOG_SCANLINE) + logerror("%s: change_horizontal_sync(): Recording scanline\n", describe_context()); + + // first store the scanline + g_profiler.start(PROFILER_USER2); + switch((scanline_zone) m_logical_scanline_zone) + { + case SCANLINE_ZONE_TOP_BORDER: + case SCANLINE_ZONE_BOTTOM_BORDER: + record_border_scanline(m_physical_scanline); + break; + + case SCANLINE_ZONE_BODY: + m_recording_scanline = true; + if (m_partial_scanline_clocks > 0) + record_partial_body_scanline(m_physical_scanline, m_logical_scanline, m_partial_scanline_clocks, 228); + else + record_body_scanline(m_physical_scanline, m_logical_scanline); + m_recording_scanline = false; + break; + + case SCANLINE_ZONE_RETRACE: + case SCANLINE_ZONE_VBLANK: + case SCANLINE_ZONE_FRAME_END: + // do nothing + break; + } + g_profiler.stop(); + + // advance to next scanline + next_scanline(); + + // and update the field sync timer + update_field_sync_timer(); + } + + // finally output horizontal sync + if (line != m_horizontal_sync) + { + m_horizontal_sync = line; + + // log if apprpriate + if (LOG_HSYNC) + logerror("%s: change_horizontal_sync(): line=%d\n", describe_context(), line ? 1 : 0); + + // invoke callback + m_write_hsync(line); + + // call virtual function + horizontal_sync_changed(m_horizontal_sync); + } + + g_profiler.stop(); +} + + + +//------------------------------------------------- +// change_field_sync +//------------------------------------------------- + +inline void mc6847_friend_device::change_field_sync(bool line) +{ + /* output field sync */ + if (line != m_field_sync) + { + m_field_sync = line; + + /* log if apprpriate */ + if (LOG_FSYNC) + logerror("%s: change_field_sync(): line=%d\n", describe_context(), line ? 1 : 0); + + /* invoke callback */ + m_write_fsync(line); + + /* call virtual function */ + field_sync_changed(m_field_sync); + } +} + + + +//------------------------------------------------- +// next_scanline +//------------------------------------------------- + +inline void mc6847_friend_device::next_scanline(void) +{ + /* advance to next scanline */ + m_physical_scanline++; + m_logical_scanline++; + m_partial_scanline_clocks = 0; + + /* check for movement into the next "zone" */ + if (m_logical_scanline_zone == SCANLINE_ZONE_FRAME_END) + { + /* we're now in the top border */ + m_logical_scanline = 0; + m_logical_scanline_zone = SCANLINE_ZONE_TOP_BORDER; + } + else if ((m_logical_scanline_zone < SCANLINE_ZONE_VBLANK) && (m_physical_scanline >= 25+192+26+6)) + { + /* we're now into vblank */ + m_logical_scanline = 0; + m_logical_scanline_zone = SCANLINE_ZONE_VBLANK; + } + else if ((m_logical_scanline_zone < SCANLINE_ZONE_RETRACE) && (m_physical_scanline >= 25+192+26)) + { + /* we're now into retrace */ + m_logical_scanline = 0; + m_logical_scanline_zone = SCANLINE_ZONE_RETRACE; + } + else if ((m_logical_scanline_zone == SCANLINE_ZONE_TOP_BORDER) && (m_logical_scanline >= m_top_border_scanlines)) + { + /* we're now into the body */ + m_logical_scanline = 0; + m_logical_scanline_zone = SCANLINE_ZONE_BODY; + } + else if ((m_logical_scanline_zone == SCANLINE_ZONE_BODY) && (m_logical_scanline >= m_body_scanlines)) + { + /* we're now into the bottom border */ + m_logical_scanline = 0; + m_logical_scanline_zone = SCANLINE_ZONE_BOTTOM_BORDER; + enter_bottom_border(); + } +} + + + +//------------------------------------------------- +// horizontal_sync_changed +//------------------------------------------------- + +void mc6847_friend_device::horizontal_sync_changed(bool line) +{ +} + + + +//------------------------------------------------- +// field_sync_changed +//------------------------------------------------- + +void mc6847_friend_device::field_sync_changed(bool line) +{ +} + + + +//------------------------------------------------- +// enter_bottom_border +//------------------------------------------------- + +void mc6847_friend_device::enter_bottom_border(void) +{ +} + + + +//------------------------------------------------- +// record_border_scanline +//------------------------------------------------- + +void mc6847_friend_device::record_border_scanline(UINT16 physical_scanline) +{ +} + + + +//------------------------------------------------- +// get_clocks_since_hsync +//------------------------------------------------- + +INT32 mc6847_friend_device::get_clocks_since_hsync() +{ + UINT64 hsync_on_clocks = attotime_to_clocks(m_hsync_on_timer->start()); + UINT64 current_clocks = attotime_to_clocks(machine().time()); + return (INT32) (current_clocks - hsync_on_clocks); +} + + + +//------------------------------------------------- +// video_flush +//------------------------------------------------- + +void mc6847_friend_device::video_flush() +{ + // first, only flush if... + // 1. We support partial scanlines + // 2. We're not already recording + // 3. We're in the body + if (m_supports_partial_body_scanlines && !m_recording_scanline && (m_logical_scanline_zone == SCANLINE_ZONE_BODY)) + { + UINT32 new_partial_scanline_clocks = get_clocks_since_hsync(); + if (m_partial_scanline_clocks < new_partial_scanline_clocks) + { + if (LOG_FLUSH) + logerror("%s: new_partial_scanline_clocks=%u\n", describe_context(), new_partial_scanline_clocks); + + m_recording_scanline = true; + record_partial_body_scanline(m_physical_scanline, m_logical_scanline, m_partial_scanline_clocks, new_partial_scanline_clocks); + m_recording_scanline = false; + + m_partial_scanline_clocks = new_partial_scanline_clocks; + } + } +} + + + +//------------------------------------------------- +// describe_context +//------------------------------------------------- + +const char *mc6847_friend_device::describe_context(void) +{ + static char buffer[128]; + snprintf(buffer, ARRAY_LENGTH(buffer), "%s (scanline %s:%d)", + machine().describe_context(), + scanline_zone_string((scanline_zone) m_logical_scanline_zone), + m_logical_scanline); + return buffer; +} + + + +//************************************************************************** +// BASE DEVICE +//************************************************************************** + +//------------------------------------------------- +// ctor +//------------------------------------------------- + +mc6847_base_device::mc6847_base_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const UINT8 *fontdata, double tpfs, const char *shortname, const char *source) : + mc6847_friend_device(mconfig, type, name, tag, owner, clock, fontdata, (type == MC6847T1_NTSC) || (type == MC6847T1_PAL), tpfs, 25+191, true, shortname, source), + m_input_cb(*this), + m_black_and_white(false), + m_fixed_mode(0), + m_fixed_mode_mask(0) +{ + m_palette = s_palette; + + for (int i = 0; i < ARRAY_LENGTH(s_palette); i++) + { + m_bw_palette[i] = black_and_white(s_palette[i]); + } +} + + + +//------------------------------------------------- +// setup_fixed_mode - sets up fixed mode mask +//------------------------------------------------- + +void mc6847_base_device::setup_fixed_mode() +{ + for (int i = 0; i < 8; i++) + { + if (BIT(m_fixed_mode, i)) + m_fixed_mode_mask |= (1 << i); + } +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void mc6847_base_device::device_start() +{ + /* inherited function */ + mc6847_friend_device::device_start(); + + /* setup */ + memset(m_data, 0, sizeof(m_data)); + + /* resolve callbacks */ + m_input_cb.resolve_safe(0); + m_charrom_cb.bind_relative_to(*owner()); + + /* set up fixed mode */ + setup_fixed_mode(); + + m_dirty = false; + m_mode = 0; + + /* state save */ + save_item(NAME(m_dirty)); + save_item(NAME(m_mode)); + + /* colors */ + m_palette = m_black_and_white ? m_bw_palette : s_palette; +} + + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void mc6847_base_device::device_reset() +{ + mc6847_friend_device::device_reset(); + m_mode = m_fixed_mode; +} + + + +//------------------------------------------------- +// input +//------------------------------------------------- + +UINT8 mc6847_base_device::input(UINT16 address) +{ + UINT8 data = m_input_cb(address); + if (LOG_INPUT) + logerror("%s: input: address=0x%04X data=0x%02X\n", describe_context(), address, data); + return data; +} + + + +//------------------------------------------------- +// record_scanline_res +//------------------------------------------------- + +template +void mc6847_base_device::record_scanline_res(int scanline, INT32 start_pos, INT32 end_pos) +{ + UINT8 current_sample_count = (start_pos > 0) ? m_data[scanline].m_sample_count : 0; + + // main loop + for (INT32 pos = start_pos; pos < end_pos; pos++) + { + // set address at beginning of line + if (pos == 0) + m_video_address = scanline / (192 / yres) * sample_count; + + if ((sample_count == 32) || ((pos % 1) == 0)) + { + // input data + UINT8 data = input(m_video_address++); + + if (pos < 32) + { + // update values + //assert(current_sample_count >= 0); + assert(current_sample_count < ARRAY_LENGTH(m_data[scanline].m_mode)); + update_value(&m_data[scanline].m_mode[current_sample_count], simplify_mode(data, m_mode)); + update_value(&m_data[scanline].m_data[current_sample_count], data); + current_sample_count++; + } + } + } + + // update sample count + update_value(&m_data[scanline].m_sample_count, current_sample_count); +} + + + +//------------------------------------------------- +// record_body_scanline +//------------------------------------------------- + +inline void mc6847_base_device::record_body_scanline(UINT16 physical_scanline, UINT16 scanline, INT32 start_pos, INT32 end_pos) +{ + // sanity checks + assert(scanline < 192); + + if (m_mode & MODE_AG) + { + switch(m_mode & (MODE_GM2|MODE_GM1|MODE_GM0)) + { + case 0: + case MODE_GM0: + record_scanline_res<16, 64>(scanline, start_pos, end_pos); + break; + + case MODE_GM1: + record_scanline_res<32, 64>(scanline, start_pos, end_pos); + break; + + case MODE_GM1|MODE_GM0: + record_scanline_res<16, 96>(scanline, start_pos, end_pos); + break; + + case MODE_GM2: + record_scanline_res<32, 96>(scanline, start_pos, end_pos); + break; + + case MODE_GM2|MODE_GM0: + record_scanline_res<16, 192>(scanline, start_pos, end_pos); + break; + + case MODE_GM2|MODE_GM1: + case MODE_GM2|MODE_GM1|MODE_GM0: + record_scanline_res<32, 192>(scanline, start_pos, end_pos); + break; + + default: + /* should not get here */ + fatalerror("should not get here\n"); + } + } + else + { + record_scanline_res<32, 16>(scanline, start_pos, end_pos); + } +} + + + +//------------------------------------------------- +// record_body_scanline +//------------------------------------------------- + +void mc6847_base_device::record_body_scanline(UINT16 physical_scanline, UINT16 scanline) +{ + record_body_scanline(physical_scanline, scanline, 0, 32); +} + + + +//------------------------------------------------- +// record_partial_body_scanline +//------------------------------------------------- + +void mc6847_base_device::record_partial_body_scanline(UINT16 physical_scanline, UINT16 scanline, INT32 start_clock, INT32 end_clock) +{ + INT32 start_pos = MAX(scanline_position_from_clock(start_clock), 0); + INT32 end_pos = MIN(scanline_position_from_clock(end_clock), 42); + + if (start_pos < end_pos) + record_body_scanline(physical_scanline, scanline, start_pos, end_pos); +} + + + +//------------------------------------------------- +// scanline_position_from_clock +//------------------------------------------------- + +INT32 mc6847_base_device::scanline_position_from_clock(INT32 clocks_since_hsync) +{ + return (clocks_since_hsync - 20) / 4; +} + + + +//------------------------------------------------- +// field_sync_changed +//------------------------------------------------- + +void mc6847_base_device::field_sync_changed(bool line) +{ + /* when field sync is on, the DA* enter the Hi-Z state */ + if (line) + m_input_cb(~0); +} + + + +//------------------------------------------------- +// border_value +//------------------------------------------------- + +inline mc6847_base_device::pixel_t mc6847_base_device::border_value(UINT8 mode, const pixel_t *palette, bool is_mc6847t1) +{ + pixel_t result; + switch(mc6847_friend_device::border_value(mode, is_mc6847t1)) + { + case BORDER_COLOR_BLACK: + result = palette[8]; + break; + case BORDER_COLOR_GREEN: + result = palette[0]; + break; + case BORDER_COLOR_WHITE: + result = palette[4]; + break; + case BORDER_COLOR_ORANGE: + result = palette[7]; + break; + default: + fatalerror("Should not get here\n"); + } + return result; +} + + + +//------------------------------------------------- +// update +//------------------------------------------------- + +UINT32 mc6847_base_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + int base_x = 32; + int base_y = 25; + int x, x2, y, width; + bool is_mc6847t1 = (type() == MC6847T1_NTSC) || (type() == MC6847T1_PAL); + int min_x = USE_HORIZONTAL_CLIP ? cliprect.min_x : 0; + int max_x = USE_HORIZONTAL_CLIP ? cliprect.max_x : (base_x * 2 + 256 - 1); + int min_y = cliprect.min_y; + int max_y = cliprect.max_y; + const pixel_t *palette = m_palette; + + /* if the video didn't change, indicate as much */ + if (!has_video_changed()) + return UPDATE_HAS_NOT_CHANGED; + + /* top border */ + for (y = min_y; y < base_y; y++) + { + for (x = min_x; x <= max_x; x++) + { + *bitmap_addr(bitmap, y, x) = border_value(m_data[0].m_mode[0], palette, is_mc6847t1); + } + } + + for (y = MAX(0, min_y - base_y); y < MIN(192, max_y - base_y); y++) + { + /* left border */ + for (x = min_x; x < base_x; x++) + { + *bitmap_addr(bitmap, y + base_y, x) = border_value(m_data[y].m_mode[0], palette, is_mc6847t1); + } + + /* body */ + x = 0; + width = m_data[y].m_sample_count; + pixel_t *RESTRICT pixels = bitmap_addr(bitmap, base_y + y, base_x); + while(x < width) + { + /* determine how many bytes exist for which the mode is identical */ + for (x2 = x + 1; (x2 < width) && (m_data[y].m_mode[x] == m_data[y].m_mode[x2]); x2++) + ; + + /* emit the samples */ + pixels += emit_mc6847_samples<1>( + m_data[y].m_mode[x], + &m_data[y].m_data[x], + x2 - x, + pixels, + m_palette, + m_charrom_cb, + x, + y); + + /* update x */ + x = x2; + } + + /* right border */ + if (width) + for (x = base_x + 256; x <= max_x; x++) + *bitmap_addr(bitmap, y + base_y, x) = border_value(m_data[y].m_mode[width - 1], palette, is_mc6847t1); + + /* artifacting */ + m_artifacter.process_artifacts<1>(bitmap_addr(bitmap, y + base_y, base_x), m_data[y].m_mode[0], palette); + } + + width = m_data[191].m_sample_count; + + /* bottom border */ + if (width) + for (y = base_y + 192; y <= max_y; y++) + for (x = min_x; x <= max_x; x++) + *bitmap_addr(bitmap, y, x) = border_value(m_data[191].m_mode[width - 1], palette, is_mc6847t1); + + return 0; +} + + + +//************************************************************************** +// CHARACTER MAP +//************************************************************************** + +mc6847_friend_device::character_map::character_map(const UINT8 *text_fontdata, bool is_mc6847t1) +{ + int mode, i; + + // set up font data + for (i = 0; i < 64*12; i++) + { + m_text_fontdata_inverse[i] = text_fontdata[i] ^ 0xFF; + m_text_fontdata_lower_case[i] = text_fontdata[i + (i < 32*12 ? 64*12 : 0)] ^ (i < 32*12 ? 0xFF : 0x00); + m_text_fontdata_lower_case_inverse[i] = m_text_fontdata_lower_case[i] ^ 0xFF; + } + + // loop through all modes + for (mode = 0; mode < ARRAY_LENGTH(m_entries); mode++) + { + const UINT8 *fontdata; + UINT8 character_mask; + UINT8 color_shift_0 = 0; + UINT8 color_shift_1 = 0; + UINT8 color_mask_0 = 0x00; + UINT8 color_mask_1 = 0x00; + UINT16 color_base_0; + UINT16 color_base_1; + + if ((mode & MODE_INTEXT) && !is_mc6847t1) + { + // semigraphics 6 + fontdata = semigraphics6_fontdata8x12; + character_mask = 0x3F; + color_base_0 = 8; + color_base_1 = mode & MODE_CSS ? 4 : 0; + color_shift_1 = 6; + color_mask_1 = 0x03; + } + else if (mode & MODE_AS) + { + // semigraphics 4 + fontdata = semigraphics4_fontdata8x12; + character_mask = 0x0F; + color_base_0 = 8; + color_base_1 = 0; + color_shift_1 = 4; + color_mask_1 = 0x07; + } + else + { + // text + bool is_lower_case = is_mc6847t1 && ((mode & MODE_INV) == 0) && (mode & MODE_GM0); + bool is_inverse1 = (mode & MODE_INV) ? true : false; + bool is_inverse2 = is_mc6847t1 && (mode & MODE_GM1); + bool is_inverse = (is_inverse1 && !is_inverse2) || (!is_inverse1 && is_inverse2); + fontdata = is_inverse + ? (is_lower_case ? m_text_fontdata_lower_case_inverse : m_text_fontdata_inverse) + : (is_lower_case ? m_text_fontdata_lower_case : text_fontdata); + character_mask = 0x3F; + color_base_0 = (mode & MODE_CSS ? 14 : 12); + color_base_1 = (mode & MODE_CSS ? 15 : 13); + } + + // populate the entry + memset(&m_entries[mode], 0, sizeof(m_entries[mode])); + m_entries[mode].m_fontdata = fontdata; + m_entries[mode].m_character_mask = character_mask; + m_entries[mode].m_color_shift_0 = color_shift_0; + m_entries[mode].m_color_shift_1 = color_shift_1; + m_entries[mode].m_color_mask_0 = color_mask_0; + m_entries[mode].m_color_mask_1 = color_mask_1; + m_entries[mode].m_color_base_0 = color_base_0; + m_entries[mode].m_color_base_1 = color_base_1; + } +} + + + +//------------------------------------------------- +// pal_round_fontdata8x12 +//------------------------------------------------- + +const UINT8 mc6847_friend_device::pal_round_fontdata8x12[] = +{ + 0x00, 0x00, 0x38, 0x44, 0x04, 0x34, 0x4C, 0x4C, 0x38, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x10, 0x28, 0x44, 0x44, 0x7C, 0x44, 0x44, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x78, 0x24, 0x24, 0x38, 0x24, 0x24, 0x78, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x44, 0x40, 0x40, 0x40, 0x44, 0x38, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x78, 0x24, 0x24, 0x24, 0x24, 0x24, 0x78, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7C, 0x40, 0x40, 0x70, 0x40, 0x40, 0x7C, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7C, 0x40, 0x40, 0x70, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x44, 0x40, 0x40, 0x4C, 0x44, 0x38, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x44, 0x44, 0x44, 0x7C, 0x44, 0x44, 0x44, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x10, 0x10, 0x10, 0x10, 0x10, 0x38, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x44, 0x38, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x44, 0x48, 0x50, 0x60, 0x50, 0x48, 0x44, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x7C, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x44, 0x6C, 0x54, 0x54, 0x44, 0x44, 0x44, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x44, 0x44, 0x64, 0x54, 0x4C, 0x44, 0x44, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x44, 0x44, 0x44, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x78, 0x44, 0x44, 0x78, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x44, 0x44, 0x44, 0x54, 0x48, 0x34, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x78, 0x44, 0x44, 0x78, 0x50, 0x48, 0x44, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x44, 0x40, 0x38, 0x04, 0x44, 0x38, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7C, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x44, 0x44, 0x44, 0x28, 0x28, 0x10, 0x10, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x44, 0x44, 0x44, 0x44, 0x54, 0x6C, 0x44, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x44, 0x44, 0x28, 0x10, 0x28, 0x44, 0x44, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x44, 0x44, 0x28, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7C, 0x04, 0x08, 0x10, 0x20, 0x40, 0x7C, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x20, 0x20, 0x20, 0x20, 0x20, 0x38, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x40, 0x20, 0x10, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x08, 0x08, 0x08, 0x08, 0x08, 0x38, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x10, 0x38, 0x54, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x10, 0x20, 0x7C, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x28, 0x28, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x28, 0x28, 0x7C, 0x28, 0x7C, 0x28, 0x28, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x10, 0x3C, 0x50, 0x38, 0x14, 0x78, 0x10, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x60, 0x64, 0x08, 0x10, 0x20, 0x4C, 0x0C, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x20, 0x50, 0x50, 0x20, 0x54, 0x48, 0x34, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x10, 0x10, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x08, 0x10, 0x20, 0x20, 0x20, 0x10, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x20, 0x10, 0x08, 0x08, 0x08, 0x10, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x10, 0x54, 0x38, 0x38, 0x54, 0x10, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x10, 0x10, 0x7C, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x20, 0x40, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x04, 0x08, 0x10, 0x20, 0x40, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x44, 0x4C, 0x54, 0x64, 0x44, 0x38, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x10, 0x30, 0x10, 0x10, 0x10, 0x10, 0x38, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x44, 0x04, 0x38, 0x40, 0x40, 0x7C, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x44, 0x04, 0x08, 0x04, 0x44, 0x38, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x08, 0x18, 0x28, 0x48, 0x7C, 0x08, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7C, 0x40, 0x78, 0x04, 0x04, 0x44, 0x38, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x40, 0x40, 0x78, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7C, 0x04, 0x08, 0x10, 0x20, 0x40, 0x40, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x44, 0x44, 0x38, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x44, 0x44, 0x3C, 0x04, 0x04, 0x38, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x10, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x08, 0x10, 0x20, 0x40, 0x20, 0x10, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x20, 0x10, 0x08, 0x04, 0x08, 0x10, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x44, 0x04, 0x08, 0x10, 0x00, 0x10, 0x00, 0x00, 0x00, + + /* Lower case */ + 0x00, 0x00, 0x18, 0x24, 0x20, 0x70, 0x20, 0x24, 0x78, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x38, 0x04, 0x3C, 0x44, 0x3C, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x40, 0x40, 0x58, 0x64, 0x44, 0x64, 0x58, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x38, 0x44, 0x40, 0x44, 0x38, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0x04, 0x34, 0x4C, 0x44, 0x4C, 0x34, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x38, 0x44, 0x7C, 0x40, 0x38, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x08, 0x14, 0x10, 0x38, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x34, 0x4C, 0x44, 0x4C, 0x34, 0x04, 0x38, 0x00, + 0x00, 0x00, 0x40, 0x40, 0x58, 0x64, 0x44, 0x44, 0x44, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x10, 0x00, 0x30, 0x10, 0x10, 0x10, 0x38, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0x00, 0x04, 0x04, 0x04, 0x04, 0x44, 0x38, 0x00, 0x00, + 0x00, 0x00, 0x40, 0x40, 0x48, 0x50, 0x60, 0x50, 0x48, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x30, 0x10, 0x10, 0x10, 0x10, 0x10, 0x38, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x78, 0x54, 0x54, 0x54, 0x54, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x58, 0x64, 0x44, 0x44, 0x44, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x38, 0x44, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x78, 0x44, 0x44, 0x44, 0x78, 0x40, 0x40, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x3C, 0x44, 0x44, 0x44, 0x3C, 0x04, 0x04, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x58, 0x64, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x3C, 0x40, 0x38, 0x04, 0x78, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x20, 0x20, 0x70, 0x20, 0x20, 0x24, 0x18, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x4C, 0x34, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x28, 0x10, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x44, 0x54, 0x54, 0x28, 0x28, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x44, 0x28, 0x10, 0x28, 0x44, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x3C, 0x04, 0x38, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x7C, 0x08, 0x10, 0x20, 0x7C, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x08, 0x10, 0x10, 0x20, 0x10, 0x10, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x10, 0x10, 0x10, 0x00, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x20, 0x10, 0x10, 0x08, 0x10, 0x10, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x20, 0x54, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x00 +}; + + + +//------------------------------------------------- +// pal_square_fontdata8x12 +//------------------------------------------------- + +const UINT8 mc6847_friend_device::pal_square_fontdata8x12[] = +{ + 0x00, 0x00, 0x00, 0x1C, 0x22, 0x02, 0x1A, 0x2A, 0x2A, 0x1C, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x08, 0x14, 0x22, 0x22, 0x3E, 0x22, 0x22, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x3C, 0x12, 0x12, 0x1C, 0x12, 0x12, 0x3C, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1C, 0x22, 0x20, 0x20, 0x20, 0x22, 0x1C, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x3C, 0x12, 0x12, 0x12, 0x12, 0x12, 0x3C, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x3E, 0x20, 0x20, 0x3C, 0x20, 0x20, 0x3E, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x3E, 0x20, 0x20, 0x3C, 0x20, 0x20, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1E, 0x20, 0x20, 0x26, 0x22, 0x22, 0x1E, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x3E, 0x22, 0x22, 0x22, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1C, 0x08, 0x08, 0x08, 0x08, 0x08, 0x1C, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x22, 0x22, 0x1C, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x22, 0x24, 0x28, 0x30, 0x28, 0x24, 0x22, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3E, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x22, 0x36, 0x2A, 0x2A, 0x22, 0x22, 0x22, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x22, 0x32, 0x2A, 0x26, 0x22, 0x22, 0x22, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x3E, 0x22, 0x22, 0x22, 0x22, 0x22, 0x3E, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x3C, 0x22, 0x22, 0x3C, 0x20, 0x20, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1C, 0x22, 0x22, 0x22, 0x2A, 0x24, 0x1A, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x3C, 0x22, 0x22, 0x3C, 0x28, 0x24, 0x22, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1C, 0x22, 0x10, 0x08, 0x04, 0x22, 0x1C, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x3E, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x1C, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x14, 0x14, 0x08, 0x08, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x2A, 0x2A, 0x36, 0x22, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x22, 0x22, 0x14, 0x08, 0x14, 0x22, 0x22, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x22, 0x22, 0x14, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x3E, 0x02, 0x04, 0x08, 0x10, 0x20, 0x3E, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x38, 0x20, 0x20, 0x20, 0x20, 0x20, 0x38, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x20, 0x20, 0x10, 0x08, 0x04, 0x02, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0E, 0x02, 0x02, 0x02, 0x02, 0x02, 0x0E, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x08, 0x1C, 0x2A, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x08, 0x10, 0x3E, 0x10, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x08, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x14, 0x14, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x14, 0x14, 0x36, 0x00, 0x36, 0x14, 0x14, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x08, 0x1E, 0x20, 0x1C, 0x02, 0x3C, 0x08, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x32, 0x32, 0x04, 0x08, 0x10, 0x26, 0x26, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x10, 0x28, 0x28, 0x10, 0x2A, 0x24, 0x1A, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x08, 0x10, 0x20, 0x20, 0x20, 0x10, 0x08, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x08, 0x04, 0x02, 0x02, 0x02, 0x04, 0x08, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x08, 0x1C, 0x3E, 0x1C, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x3E, 0x08, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x10, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x02, 0x02, 0x04, 0x08, 0x10, 0x20, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x18, 0x24, 0x24, 0x24, 0x24, 0x24, 0x18, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x08, 0x18, 0x08, 0x08, 0x08, 0x08, 0x1C, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1C, 0x22, 0x02, 0x1C, 0x20, 0x20, 0x3E, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1C, 0x22, 0x02, 0x0C, 0x02, 0x22, 0x1C, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x04, 0x0C, 0x14, 0x3E, 0x04, 0x04, 0x04, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x3E, 0x20, 0x3C, 0x02, 0x02, 0x22, 0x1C, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1C, 0x20, 0x20, 0x3C, 0x22, 0x22, 0x1C, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x3E, 0x02, 0x04, 0x08, 0x10, 0x20, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1C, 0x22, 0x22, 0x1C, 0x22, 0x22, 0x1C, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1C, 0x22, 0x22, 0x1E, 0x02, 0x02, 0x1C, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x08, 0x10, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x04, 0x08, 0x10, 0x20, 0x10, 0x08, 0x04, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x10, 0x08, 0x04, 0x02, 0x04, 0x08, 0x10, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x18, 0x24, 0x04, 0x08, 0x08, 0x00, 0x08, 0x00, 0x00, + + /* Lower case */ + 0x00, 0x00, 0x00, 0x0C, 0x12, 0x10, 0x38, 0x10, 0x12, 0x3C, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x02, 0x1E, 0x22, 0x1E, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x20, 0x20, 0x3C, 0x22, 0x22, 0x22, 0x3C, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x20, 0x20, 0x20, 0x1C, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x02, 0x02, 0x1E, 0x22, 0x22, 0x22, 0x1E, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x22, 0x3E, 0x20, 0x1C, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0C, 0x12, 0x10, 0x38, 0x10, 0x10, 0x10, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x22, 0x22, 0x22, 0x1E, 0x02, 0x1C, + 0x00, 0x00, 0x00, 0x20, 0x20, 0x3C, 0x22, 0x22, 0x22, 0x22, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x08, 0x00, 0x18, 0x08, 0x08, 0x08, 0x1C, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x04, 0x04, 0x04, 0x04, 0x24, 0x18, + 0x00, 0x00, 0x00, 0x20, 0x20, 0x24, 0x28, 0x38, 0x24, 0x22, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x18, 0x08, 0x08, 0x08, 0x08, 0x08, 0x1C, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x2A, 0x2A, 0x2A, 0x2A, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x2C, 0x32, 0x22, 0x22, 0x22, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x22, 0x22, 0x22, 0x1C, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x22, 0x22, 0x22, 0x3C, 0x20, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x22, 0x22, 0x22, 0x1E, 0x02, 0x03, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x2C, 0x32, 0x20, 0x20, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x20, 0x1C, 0x02, 0x3C, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x10, 0x3C, 0x10, 0x10, 0x10, 0x12, 0x0C, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x26, 0x1A, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x14, 0x14, 0x08, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x2A, 0x2A, 0x1C, 0x14, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x14, 0x08, 0x14, 0x22, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0x1E, 0x02, 0x1C, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x04, 0x08, 0x10, 0x3E, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x08, 0x10, 0x10, 0x20, 0x10, 0x10, 0x08, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x00, 0x08, 0x08, 0x08, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x08, 0x04, 0x04, 0x02, 0x04, 0x04, 0x08, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x2A, 0x1C, 0x08, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x08, 0x04, 0x3E, 0x04, 0x08, 0x00, 0x00, 0x00, 0x00, +}; + + + +//------------------------------------------------- +// ntsc_round_fontdata8x12 +//------------------------------------------------- + +const UINT8 mc6847_friend_device::ntsc_round_fontdata8x12[] = +{ + 0x00, 0x00, 0x38, 0x44, 0x04, 0x34, 0x4C, 0x4C, 0x38, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x10, 0x28, 0x44, 0x44, 0x7C, 0x44, 0x44, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x78, 0x24, 0x24, 0x38, 0x24, 0x24, 0x78, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x44, 0x40, 0x40, 0x40, 0x44, 0x38, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x78, 0x24, 0x24, 0x24, 0x24, 0x24, 0x78, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7C, 0x40, 0x40, 0x70, 0x40, 0x40, 0x7C, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7C, 0x40, 0x40, 0x70, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x44, 0x40, 0x40, 0x4C, 0x44, 0x38, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x44, 0x44, 0x44, 0x7C, 0x44, 0x44, 0x44, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x10, 0x10, 0x10, 0x10, 0x10, 0x38, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x44, 0x38, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x44, 0x48, 0x50, 0x60, 0x50, 0x48, 0x44, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x7C, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x44, 0x6C, 0x54, 0x54, 0x44, 0x44, 0x44, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x44, 0x44, 0x64, 0x54, 0x4C, 0x44, 0x44, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x44, 0x44, 0x44, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x78, 0x44, 0x44, 0x78, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x44, 0x44, 0x44, 0x54, 0x48, 0x34, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x78, 0x44, 0x44, 0x78, 0x50, 0x48, 0x44, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x44, 0x40, 0x38, 0x04, 0x44, 0x38, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7C, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x44, 0x44, 0x44, 0x28, 0x28, 0x10, 0x10, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x44, 0x44, 0x44, 0x44, 0x54, 0x6C, 0x44, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x44, 0x44, 0x28, 0x10, 0x28, 0x44, 0x44, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x44, 0x44, 0x28, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7C, 0x04, 0x08, 0x10, 0x20, 0x40, 0x7C, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x20, 0x20, 0x20, 0x20, 0x20, 0x38, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x40, 0x20, 0x10, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x08, 0x08, 0x08, 0x08, 0x08, 0x38, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x10, 0x38, 0x54, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x10, 0x20, 0x7C, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x28, 0x28, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x28, 0x28, 0x7C, 0x28, 0x7C, 0x28, 0x28, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x10, 0x3C, 0x50, 0x38, 0x14, 0x78, 0x10, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x60, 0x64, 0x08, 0x10, 0x20, 0x4C, 0x0C, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x20, 0x50, 0x50, 0x20, 0x54, 0x48, 0x34, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x10, 0x10, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x08, 0x10, 0x20, 0x20, 0x20, 0x10, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x20, 0x10, 0x08, 0x08, 0x08, 0x10, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x10, 0x54, 0x38, 0x38, 0x54, 0x10, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x10, 0x10, 0x7C, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x20, 0x40, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x04, 0x08, 0x10, 0x20, 0x40, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x44, 0x4C, 0x54, 0x64, 0x44, 0x38, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x10, 0x30, 0x10, 0x10, 0x10, 0x10, 0x38, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x44, 0x04, 0x38, 0x40, 0x40, 0x7C, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x44, 0x04, 0x08, 0x04, 0x44, 0x38, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x08, 0x18, 0x28, 0x48, 0x7C, 0x08, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7C, 0x40, 0x78, 0x04, 0x04, 0x44, 0x38, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x40, 0x40, 0x78, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7C, 0x04, 0x08, 0x10, 0x20, 0x40, 0x40, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x44, 0x44, 0x38, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x44, 0x44, 0x3C, 0x04, 0x04, 0x38, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x10, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x08, 0x10, 0x20, 0x40, 0x20, 0x10, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x20, 0x10, 0x08, 0x04, 0x08, 0x10, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x44, 0x04, 0x08, 0x10, 0x00, 0x10, 0x00, 0x00, 0x00, + + /* Lower case */ + 0x00, 0x00, 0x10, 0x28, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x38, 0x04, 0x3C, 0x44, 0x3C, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x40, 0x40, 0x58, 0x64, 0x44, 0x64, 0x58, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x38, 0x44, 0x40, 0x44, 0x38, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0x04, 0x34, 0x4C, 0x44, 0x4C, 0x34, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x38, 0x44, 0x7C, 0x40, 0x38, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x08, 0x14, 0x10, 0x38, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x34, 0x4C, 0x44, 0x4C, 0x34, 0x04, 0x38, 0x00, + 0x00, 0x00, 0x40, 0x40, 0x58, 0x64, 0x44, 0x44, 0x44, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x10, 0x00, 0x30, 0x10, 0x10, 0x10, 0x38, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0x00, 0x04, 0x04, 0x04, 0x04, 0x44, 0x38, 0x00, 0x00, + 0x00, 0x00, 0x40, 0x40, 0x48, 0x50, 0x60, 0x50, 0x48, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x30, 0x10, 0x10, 0x10, 0x10, 0x10, 0x38, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x78, 0x54, 0x54, 0x54, 0x54, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x58, 0x64, 0x44, 0x44, 0x44, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x38, 0x44, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x78, 0x44, 0x44, 0x44, 0x78, 0x40, 0x40, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x3C, 0x44, 0x44, 0x44, 0x3C, 0x04, 0x04, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x58, 0x64, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x3C, 0x40, 0x38, 0x04, 0x78, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x20, 0x20, 0x70, 0x20, 0x20, 0x24, 0x18, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x4C, 0x34, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x28, 0x10, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x44, 0x54, 0x54, 0x28, 0x28, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x44, 0x28, 0x10, 0x28, 0x44, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x3C, 0x04, 0x38, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x7C, 0x08, 0x10, 0x20, 0x7C, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x08, 0x10, 0x10, 0x20, 0x10, 0x10, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x10, 0x10, 0x10, 0x00, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x20, 0x10, 0x10, 0x08, 0x10, 0x10, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x20, 0x54, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x00, +}; + + + +//------------------------------------------------- +// ntsc_square_fontdata8x12 +//------------------------------------------------- + +const UINT8 mc6847_friend_device::ntsc_square_fontdata8x12[] = +{ + 0x00, 0x00, 0x00, 0x1C, 0x22, 0x02, 0x1A, 0x2A, 0x2A, 0x1C, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x08, 0x14, 0x22, 0x22, 0x3E, 0x22, 0x22, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x3C, 0x12, 0x12, 0x1C, 0x12, 0x12, 0x3C, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1C, 0x22, 0x20, 0x20, 0x20, 0x22, 0x1C, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x3C, 0x12, 0x12, 0x12, 0x12, 0x12, 0x3C, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x3E, 0x20, 0x20, 0x38, 0x20, 0x20, 0x3E, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x3E, 0x20, 0x20, 0x38, 0x20, 0x20, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1E, 0x20, 0x20, 0x26, 0x22, 0x22, 0x1E, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x3E, 0x22, 0x22, 0x22, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1C, 0x08, 0x08, 0x08, 0x08, 0x08, 0x1C, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x22, 0x22, 0x1C, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x22, 0x24, 0x28, 0x30, 0x28, 0x24, 0x22, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3E, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x22, 0x36, 0x2A, 0x2A, 0x22, 0x22, 0x22, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x22, 0x32, 0x2A, 0x26, 0x22, 0x22, 0x22, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x3E, 0x22, 0x22, 0x22, 0x22, 0x22, 0x3E, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x3C, 0x22, 0x22, 0x3C, 0x20, 0x20, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1C, 0x22, 0x22, 0x22, 0x2A, 0x24, 0x1A, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x3C, 0x22, 0x22, 0x3C, 0x28, 0x24, 0x22, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1C, 0x22, 0x10, 0x08, 0x04, 0x22, 0x1C, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x3E, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x1C, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x14, 0x14, 0x08, 0x08, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x2A, 0x2A, 0x36, 0x22, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x22, 0x22, 0x14, 0x08, 0x14, 0x22, 0x22, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x22, 0x22, 0x14, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x3E, 0x02, 0x04, 0x08, 0x10, 0x20, 0x3E, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x38, 0x20, 0x20, 0x20, 0x20, 0x20, 0x38, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x20, 0x20, 0x10, 0x08, 0x04, 0x02, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0E, 0x02, 0x02, 0x02, 0x02, 0x02, 0x0E, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x08, 0x1C, 0x2A, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x08, 0x10, 0x3E, 0x10, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x08, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x14, 0x14, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x14, 0x14, 0x36, 0x00, 0x36, 0x14, 0x14, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x08, 0x1E, 0x20, 0x1C, 0x02, 0x3C, 0x08, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x32, 0x32, 0x04, 0x08, 0x10, 0x26, 0x26, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x10, 0x28, 0x28, 0x10, 0x2A, 0x24, 0x1A, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x08, 0x10, 0x20, 0x20, 0x20, 0x10, 0x08, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x08, 0x04, 0x02, 0x02, 0x02, 0x04, 0x08, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x08, 0x1C, 0x3E, 0x1C, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x3E, 0x08, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x10, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x02, 0x02, 0x04, 0x08, 0x10, 0x20, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x18, 0x24, 0x24, 0x24, 0x24, 0x24, 0x18, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x08, 0x18, 0x08, 0x08, 0x08, 0x08, 0x1C, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1C, 0x22, 0x02, 0x1C, 0x20, 0x20, 0x3E, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1C, 0x22, 0x02, 0x04, 0x02, 0x22, 0x1C, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x04, 0x0C, 0x14, 0x3E, 0x04, 0x04, 0x04, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x3E, 0x20, 0x3C, 0x02, 0x02, 0x22, 0x1C, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1C, 0x20, 0x20, 0x3C, 0x22, 0x22, 0x1C, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x3E, 0x02, 0x04, 0x08, 0x10, 0x20, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1C, 0x22, 0x22, 0x1C, 0x22, 0x22, 0x1C, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1C, 0x22, 0x22, 0x1E, 0x02, 0x02, 0x1C, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x08, 0x10, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x04, 0x08, 0x10, 0x20, 0x10, 0x08, 0x04, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x10, 0x08, 0x04, 0x02, 0x04, 0x08, 0x10, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x18, 0x24, 0x04, 0x08, 0x08, 0x00, 0x08, 0x00, 0x00, + + /* Lower case */ + 0x00, 0x00, 0x00, 0x0C, 0x12, 0x10, 0x38, 0x10, 0x12, 0x3C, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x02, 0x1E, 0x22, 0x1E, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x20, 0x20, 0x3C, 0x22, 0x22, 0x22, 0x3C, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x20, 0x20, 0x20, 0x1C, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x02, 0x02, 0x1E, 0x22, 0x22, 0x22, 0x1E, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x22, 0x3E, 0x20, 0x1C, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0C, 0x12, 0x10, 0x38, 0x10, 0x10, 0x10, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x22, 0x22, 0x22, 0x1E, 0x02, 0x1C, + 0x00, 0x00, 0x00, 0x20, 0x20, 0x3C, 0x22, 0x22, 0x22, 0x22, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x08, 0x00, 0x18, 0x08, 0x08, 0x08, 0x1C, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x04, 0x04, 0x04, 0x04, 0x24, 0x18, + 0x00, 0x00, 0x00, 0x20, 0x20, 0x24, 0x28, 0x38, 0x24, 0x22, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x18, 0x08, 0x08, 0x08, 0x08, 0x08, 0x1C, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x2A, 0x2A, 0x2A, 0x2A, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x2C, 0x32, 0x22, 0x22, 0x22, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x22, 0x22, 0x22, 0x1C, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x22, 0x22, 0x22, 0x3C, 0x20, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x22, 0x22, 0x22, 0x1E, 0x02, 0x03, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x2C, 0x32, 0x20, 0x20, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x20, 0x1C, 0x02, 0x3C, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x10, 0x3C, 0x10, 0x10, 0x10, 0x12, 0x0C, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x26, 0x1A, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x14, 0x14, 0x08, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x2A, 0x2A, 0x1C, 0x14, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x14, 0x08, 0x14, 0x22, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0x1E, 0x02, 0x1C, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x04, 0x08, 0x10, 0x3E, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x08, 0x10, 0x10, 0x20, 0x10, 0x10, 0x08, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x00, 0x08, 0x08, 0x08, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x08, 0x04, 0x04, 0x02, 0x04, 0x04, 0x08, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x2A, 0x1C, 0x08, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x08, 0x04, 0x3E, 0x04, 0x08, 0x00, 0x00, 0x00, 0x00 +}; + + + +//------------------------------------------------- +// s68047_fontdata8x12 +//------------------------------------------------- + +const UINT8 mc6847_friend_device::s68047_fontdata8x12[] = +{ + 0x00, 0x00, 0x00, 0x1C, 0x22, 0x2A, 0x2A, 0x2C, 0x20, 0x1E, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x08, 0x14, 0x22, 0x22, 0x3E, 0x22, 0x22, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x3C, 0x22, 0x22, 0x3C, 0x22, 0x22, 0x3C, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1C, 0x22, 0x20, 0x20, 0x20, 0x22, 0x1C, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x3C, 0x22, 0x22, 0x22, 0x22, 0x22, 0x3C, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x3E, 0x20, 0x20, 0x3C, 0x20, 0x20, 0x3E, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x3E, 0x20, 0x20, 0x3C, 0x20, 0x20, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1C, 0x22, 0x20, 0x20, 0x26, 0x22, 0x1C, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x3E, 0x22, 0x22, 0x22, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1C, 0x08, 0x08, 0x08, 0x08, 0x08, 0x1C, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x22, 0x1C, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x22, 0x24, 0x28, 0x30, 0x28, 0x24, 0x22, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3E, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x22, 0x36, 0x2A, 0x2A, 0x22, 0x22, 0x22, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x22, 0x32, 0x32, 0x2A, 0x26, 0x26, 0x22, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1C, 0x22, 0x22, 0x22, 0x22, 0x22, 0x1C, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x3C, 0x22, 0x22, 0x3C, 0x20, 0x20, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1C, 0x22, 0x22, 0x22, 0x2A, 0x24, 0x1A, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x3C, 0x22, 0x22, 0x3C, 0x28, 0x24, 0x22, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1C, 0x22, 0x20, 0x1C, 0x02, 0x22, 0x1C, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x3E, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x1C, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x14, 0x14, 0x08, 0x08, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x2A, 0x2A, 0x2A, 0x14, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x22, 0x22, 0x14, 0x08, 0x14, 0x22, 0x22, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x22, 0x22, 0x14, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x3E, 0x02, 0x04, 0x08, 0x10, 0x20, 0x3E, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1C, 0x10, 0x10, 0x10, 0x10, 0x10, 0x1C, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x20, 0x20, 0x10, 0x08, 0x04, 0x02, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1C, 0x04, 0x04, 0x04, 0x04, 0x04, 0x1C, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x08, 0x1C, 0x2A, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x08, 0x10, 0x3E, 0x10, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x08, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x14, 0x14, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x14, 0x14, 0x3E, 0x14, 0x3E, 0x14, 0x14, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x08, 0x1E, 0x28, 0x1C, 0x0A, 0x3C, 0x08, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x32, 0x32, 0x04, 0x08, 0x10, 0x26, 0x26, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x10, 0x28, 0x28, 0x10, 0x2A, 0x24, 0x1A, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x04, 0x08, 0x10, 0x10, 0x10, 0x08, 0x04, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x10, 0x08, 0x04, 0x04, 0x04, 0x08, 0x10, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x08, 0x2A, 0x1C, 0x2A, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x3E, 0x08, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x10, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x02, 0x02, 0x04, 0x08, 0x10, 0x20, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1C, 0x22, 0x26, 0x2A, 0x32, 0x22, 0x1C, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x08, 0x18, 0x08, 0x08, 0x08, 0x08, 0x1C, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1C, 0x22, 0x02, 0x1C, 0x20, 0x20, 0x3E, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x3E, 0x02, 0x04, 0x0C, 0x02, 0x22, 0x1C, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x04, 0x0C, 0x14, 0x24, 0x3E, 0x04, 0x04, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x3E, 0x20, 0x3C, 0x02, 0x02, 0x22, 0x1C, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0E, 0x10, 0x20, 0x3C, 0x22, 0x22, 0x1C, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x3E, 0x02, 0x02, 0x04, 0x08, 0x10, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1C, 0x22, 0x22, 0x1C, 0x22, 0x22, 0x1C, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1C, 0x22, 0x22, 0x1E, 0x02, 0x04, 0x38, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x08, 0x08, 0x10, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x06, 0x08, 0x10, 0x20, 0x10, 0x08, 0x06, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x30, 0x08, 0x04, 0x02, 0x04, 0x08, 0x30, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1C, 0x22, 0x02, 0x04, 0x08, 0x00, 0x08, 0x00, 0x00, + + // No lower case, copy/paste of first 32 characters + 0x00, 0x00, 0x00, 0x1C, 0x22, 0x2A, 0x2A, 0x2C, 0x20, 0x1E, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x08, 0x14, 0x22, 0x22, 0x3E, 0x22, 0x22, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x3C, 0x22, 0x22, 0x3C, 0x22, 0x22, 0x3C, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1C, 0x22, 0x20, 0x20, 0x20, 0x22, 0x1C, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x3C, 0x22, 0x22, 0x22, 0x22, 0x22, 0x3C, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x3E, 0x20, 0x20, 0x3C, 0x20, 0x20, 0x3E, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x3E, 0x20, 0x20, 0x3C, 0x20, 0x20, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1C, 0x22, 0x20, 0x20, 0x26, 0x22, 0x1C, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x3E, 0x22, 0x22, 0x22, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1C, 0x08, 0x08, 0x08, 0x08, 0x08, 0x1C, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x22, 0x1C, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x22, 0x24, 0x28, 0x30, 0x28, 0x24, 0x22, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3E, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x22, 0x36, 0x2A, 0x2A, 0x22, 0x22, 0x22, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x22, 0x32, 0x32, 0x2A, 0x26, 0x26, 0x22, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1C, 0x22, 0x22, 0x22, 0x22, 0x22, 0x1C, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x3C, 0x22, 0x22, 0x3C, 0x20, 0x20, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1C, 0x22, 0x22, 0x22, 0x2A, 0x24, 0x1A, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x3C, 0x22, 0x22, 0x3C, 0x28, 0x24, 0x22, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1C, 0x22, 0x20, 0x1C, 0x02, 0x22, 0x1C, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x3E, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x1C, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x14, 0x14, 0x08, 0x08, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x2A, 0x2A, 0x2A, 0x14, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x22, 0x22, 0x14, 0x08, 0x14, 0x22, 0x22, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x22, 0x22, 0x14, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x3E, 0x02, 0x04, 0x08, 0x10, 0x20, 0x3E, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1C, 0x10, 0x10, 0x10, 0x10, 0x10, 0x1C, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x20, 0x20, 0x10, 0x08, 0x04, 0x02, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1C, 0x04, 0x04, 0x04, 0x04, 0x04, 0x1C, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x08, 0x1C, 0x2A, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x08, 0x10, 0x3E, 0x10, 0x08, 0x00, 0x00, 0x00, +}; + + + +//------------------------------------------------- +// semigraphics4_fontdata8x12 +//------------------------------------------------- + +const UINT8 mc6847_friend_device::semigraphics4_fontdata8x12[] = +{ + /* Block Graphics (Semigraphics 4 Graphics ) */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, + 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, + 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, + 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, + 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF +}; + + + +//------------------------------------------------- +// semigraphics6_fontdata8x12 +//------------------------------------------------- + +const UINT8 mc6847_friend_device::semigraphics6_fontdata8x12[] = +{ + /* Semigraphics 6 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x0F, 0x0F, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xF0, 0xF0, 0xF0, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, + 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x0F, 0x0F, 0xF0, 0xF0, 0xF0, 0xF0, + 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x0F, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0xF0, 0xF0, 0xF0, 0xF0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xF0, 0xF0, 0xF0, 0xF0, 0x0F, 0x0F, 0x0F, 0x0F, + 0x00, 0x00, 0x00, 0x00, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, + 0x00, 0x00, 0x00, 0x00, 0xF0, 0xF0, 0xF0, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x0F, 0x0F, 0x0F, + 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xF0, 0xF0, 0xF0, + 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x0F, 0x0F, + 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xF0, 0xF0, 0xF0, + 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, + 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, + 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0xF0, 0xF0, 0xF0, 0xF0, + 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, + 0x0F, 0x0F, 0x0F, 0x0F, 0xF0, 0xF0, 0xF0, 0xF0, 0x00, 0x00, 0x00, 0x00, + 0x0F, 0x0F, 0x0F, 0x0F, 0xF0, 0xF0, 0xF0, 0xF0, 0x0F, 0x0F, 0x0F, 0x0F, + 0x0F, 0x0F, 0x0F, 0x0F, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, + 0x0F, 0x0F, 0x0F, 0x0F, 0xF0, 0xF0, 0xF0, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, + 0x0F, 0x0F, 0x0F, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0x0F, 0x0F, 0x0F, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x0F, 0x0F, 0x0F, + 0x0F, 0x0F, 0x0F, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xF0, 0xF0, 0xF0, + 0x0F, 0x0F, 0x0F, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xF0, 0xF0, 0xF0, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xF0, 0xF0, 0xF0, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x0F, 0x0F, + 0xF0, 0xF0, 0xF0, 0xF0, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xF0, 0xF0, 0xF0, + 0xF0, 0xF0, 0xF0, 0xF0, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0xF0, 0xF0, 0xF0, 0xF0, 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, + 0xF0, 0xF0, 0xF0, 0xF0, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, + 0xF0, 0xF0, 0xF0, 0xF0, 0x0F, 0x0F, 0x0F, 0x0F, 0xF0, 0xF0, 0xF0, 0xF0, + 0xF0, 0xF0, 0xF0, 0xF0, 0x0F, 0x0F, 0x0F, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, + 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0x00, 0x00, 0x00, 0x00, + 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0x0F, 0x0F, 0x0F, 0x0F, + 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, + 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, + 0xF0, 0xF0, 0xF0, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0xF0, 0xF0, 0xF0, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x0F, 0x0F, 0x0F, + 0xF0, 0xF0, 0xF0, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xF0, 0xF0, 0xF0, + 0xF0, 0xF0, 0xF0, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x0F, 0x0F, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xF0, 0xF0, 0xF0, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, + 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x0F, 0x0F, 0x0F, 0xF0, 0xF0, 0xF0, 0xF0, + 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x0F, 0x0F, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xF0, 0xF0, 0xF0, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xF0, 0xF0, 0xF0, 0x0F, 0x0F, 0x0F, 0x0F, + 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, + 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xF0, 0xF0, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x0F, 0x0F, 0x0F, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xF0, 0xF0, 0xF0, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF +}; + + + +//************************************************************************** +// ARTIFACTING +//************************************************************************** + +INPUT_PORTS_START(mc6847_artifacting) + PORT_START(ARTIFACTING_TAG) + PORT_CONFNAME( 0x03, 0x01, "Artifacting" ) + PORT_CONFSETTING( 0x00, DEF_STR( Off ) ) + PORT_CONFSETTING( 0x01, DEF_STR( Standard ) ) + PORT_CONFSETTING( 0x02, DEF_STR( Reverse ) ) +INPUT_PORTS_END + +ioport_constructor mc6847_base_device::device_input_ports() const +{ + return INPUT_PORTS_NAME(mc6847_artifacting); +} + + + +//------------------------------------------------- +// ctor +//------------------------------------------------- + +mc6847_base_device::artifacter::artifacter() +{ + m_config = NULL; + m_artifacting = 0; + m_saved_artifacting = 0; + m_saved_c0 = 0; + m_saved_c1 = 0; + memset(m_expanded_colors, 0, sizeof(m_expanded_colors)); +} + + + +//------------------------------------------------- +// artifacter::setup_config +//------------------------------------------------- + +void mc6847_base_device::artifacter::setup_config(device_t *device) +{ + char port_name[32]; + snprintf(port_name, ARRAY_LENGTH(port_name), "%s:%s", device->tag(), ARTIFACTING_TAG); + m_config = device->ioport(port_name); +} + + + +//------------------------------------------------- +// artifacter::update_colors +//------------------------------------------------- + +void mc6847_base_device::artifacter::update_colors(pixel_t c0, pixel_t c1) +{ + /* Boy this code sucks; this code was adapted from the old M6847 + * artifacting implmentation. The only reason that it didn't look as + * horrible was because the code around it sucked as well. Now that I + * have cleaned everything up, the ugliness is much more prominent. + * + * Hopefully we will have a generic artifacting algorithm that plugs into + * the MESS/MAME core directly so we can chuck this hack */ + static const double artifact_colors[14*3] = + { + 0.157, 0.000, 0.157, /* [ 1] - dk purple (reverse 2) */ + 0.000, 0.157, 0.000, /* [ 2] - dk green (reverse 1) */ + 1.000, 0.824, 1.000, /* [ 3] - lt purple (reverse 4) */ + 0.824, 1.000, 0.824, /* [ 4] - lt green (reverse 3) */ + 0.706, 0.236, 0.118, /* [ 5] - dk blue (reverse 6) */ + 0.000, 0.197, 0.471, /* [ 6] - dk red (reverse 5) */ + 1.000, 0.550, 0.393, /* [ 7] - lt blue (reverse 8) */ + 0.275, 0.785, 1.000, /* [ 8] - lt red (reverse 7) */ + 0.000, 0.500, 1.000, /* [ 9] - red (reverse 10) */ + 1.000, 0.500, 0.000, /* [10] - blue (reverse 9) */ + 1.000, 0.942, 0.785, /* [11] - cyan (reverse 12) */ + 0.393, 0.942, 1.000, /* [12] - yellow (reverse 11) */ + 0.236, 0.000, 0.000, /* [13] - black-blue (reverse 14) */ + 0.000, 0.000, 0.236 /* [14] - black-red (reverse 13) */ + }; + + static const UINT8 artifact_correction[128] = + { + 0, 0, 0, 0, 0, 6, 0, 2, + 5, 7, 5, 7, 1, 3, 1, 11, + 8, 6, 8, 14, 8, 9, 8, 9, + 4, 4, 4, 15, 12, 12, 12, 15, + + 5, 13, 5, 13, 13, 0, 13, 2, + 10, 10, 10, 10, 10, 15, 10, 11, + 3, 1, 3, 1, 15, 9, 15, 9, + 11, 11, 11, 11, 15, 15, 15, 15, + + 14, 0, 14, 0, 14, 6, 14, 2, + 0, 7, 0, 7, 1, 3, 1, 11, + 9, 6, 9, 14, 9, 9, 9, 9, + 15, 4, 15, 15, 12, 12, 12, 15, + + 2, 13, 2, 13, 2, 0, 2, 2, + 10, 10, 10, 10, 10, 15, 10, 11, + 12, 1, 12, 1, 12, 9, 12, 9, + 15, 11, 15, 11, 15, 15, 15, 15 + }; + + pixel_t colors[16]; + int i; + + /* do we need to update our artifact colors table? */ + if ((m_artifacting != m_saved_artifacting) || (c0 != m_saved_c0) || (c1 != m_saved_c1)) + { + m_saved_artifacting = m_artifacting; + m_saved_c0 = colors[0] = c0; + m_saved_c1 = colors[15] = c1; + + /* mix the other colors */ + for (i = 1; i <= 14; i++) + { + const double *factors = &artifact_colors[((i - 1) ^ (m_artifacting & 0x01)) * 3]; + + colors[i] = (mix_color(factors[0], c0 >> 16, c1 >> 16) << 16) + | (mix_color(factors[1], c0 >> 8, c1 >> 8) << 8) + | (mix_color(factors[2], c0 >> 0, c1 >> 0) << 0); + } + for (i = 0; i < 128; i++) + { + m_expanded_colors[i] = colors[artifact_correction[i]]; + } + } +} + + + +//------------------------------------------------- +// artifacter::update +//------------------------------------------------- + +mc6847_base_device::pixel_t mc6847_base_device::artifacter::mix_color(double factor, UINT8 c0, UINT8 c1) +{ + return (UINT32) (UINT8) ((c0 * (1.0 - factor)) + (c1 * (0.0 + factor)) + 0.5); +} + + + +//************************************************************************** +// VARIATIONS +//************************************************************************** + +const device_type MC6847_NTSC = &device_creator; +const device_type MC6847_PAL = &device_creator; +const device_type MC6847Y_NTSC = &device_creator; +const device_type MC6847Y_PAL = &device_creator; +const device_type MC6847T1_NTSC = &device_creator; +const device_type MC6847T1_PAL = &device_creator; +const device_type S68047 = &device_creator; +const device_type M5C6847P1 = &device_creator; + + + +//------------------------------------------------- +// mc6847_ntsc_device +//------------------------------------------------- + +mc6847_ntsc_device::mc6847_ntsc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : mc6847_base_device(mconfig, MC6847_NTSC, "MC6847_NTSC", tag, owner, clock, ntsc_square_fontdata8x12, 262.0, "mc6847_ntsc", __FILE__) +{ +} + + + +//------------------------------------------------- +// mc6847_pal_device +//------------------------------------------------- + +mc6847_pal_device::mc6847_pal_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : mc6847_base_device(mconfig, MC6847_PAL, "MC6847_PAL", tag, owner, clock, pal_square_fontdata8x12, 313.0, "mc6847_pal", __FILE__) +{ +} + + + +//------------------------------------------------- +// mc6847y_ntsc_device +//------------------------------------------------- + +mc6847y_ntsc_device::mc6847y_ntsc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : mc6847_base_device(mconfig, MC6847Y_NTSC, "MC6847Y_NTSC", tag, owner, clock, ntsc_square_fontdata8x12, 262.5, "mc6847y", __FILE__) +{ +} + + + +//------------------------------------------------- +// mc6847y_pal_device +//------------------------------------------------- + +mc6847y_pal_device::mc6847y_pal_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : mc6847_base_device(mconfig, MC6847Y_PAL, "MC6847Y_PAL", tag, owner, clock, pal_square_fontdata8x12, 313.0, "mc6847y_pal", __FILE__) +{ +} + + + +//------------------------------------------------- +// mc6847t1_ntsc_device +//------------------------------------------------- + +mc6847t1_ntsc_device::mc6847t1_ntsc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : mc6847_base_device(mconfig, MC6847T1_NTSC, "MC6847T1_NTSC", tag, owner, clock, ntsc_round_fontdata8x12, 262.0, "mc6847t1_ntsc", __FILE__) +{ +} + + + +//------------------------------------------------- +// mc6847t1_pal_device +//------------------------------------------------- + +mc6847t1_pal_device::mc6847t1_pal_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : mc6847_base_device(mconfig, MC6847T1_PAL, "MC6847T1_PAL", tag, owner, clock, pal_round_fontdata8x12, 313.0, "mc6847t1_pal", __FILE__) +{ +} + + + +//------------------------------------------------- +// s68047_device +//------------------------------------------------- + +s68047_device::s68047_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : mc6847_base_device(mconfig, S68047, "S68047", tag, owner, clock, s68047_fontdata8x12, 262.0, "s68047", __FILE__) +{ +} + + +// +// In the Bandai Super Vision 8000 there is a video setting +// bit which causes black to be displayed as blue when css=1. +// +// This is probably done through circuitry outside the s68047, +// but lacking schematics we don't know how it is hooked up +// exactly. +// +// See https://www.youtube.com/watch?v=QCo24GLyff4 +// +void s68047_device::hack_black_becomes_blue(bool flag) +{ + set_custom_palette( flag ? s_s68047_hack_palette : NULL ); +} + +const UINT32 s68047_device::s_s68047_hack_palette[16] = +{ + rgb_t(0x07, 0xff, 0x00), /* GREEN */ + rgb_t(0xff, 0xff, 0x00), /* YELLOW */ + rgb_t(0x3b, 0x08, 0xff), /* BLUE */ + rgb_t(0xcc, 0x00, 0x3b), /* RED */ + rgb_t(0xff, 0xff, 0xff), /* BUFF */ + rgb_t(0x07, 0xe3, 0x99), /* CYAN */ + rgb_t(0xff, 0x1c, 0xff), /* MAGENTA */ + rgb_t(0xff, 0x81, 0x00), /* ORANGE */ + + rgb_t(0x00, 0x00, 0x00), /* BLACK */ + rgb_t(0x07, 0xff, 0x00), /* GREEN */ + rgb_t(0x3b, 0x08, 0xff), /* BLUE */ + rgb_t(0xff, 0xff, 0xff), /* BUFF */ + + rgb_t(0x00, 0x7c, 0x00), /* ALPHANUMERIC DARK GREEN */ + rgb_t(0x07, 0xff, 0x00), /* ALPHANUMERIC BRIGHT GREEN */ + rgb_t(0x91, 0x00, 0x00), /* ALPHANUMERIC DARK ORANGE */ + rgb_t(0xff, 0x81, 0x00) /* ALPHANUMERIC BRIGHT ORANGE */ +}; + + + +//------------------------------------------------- +// m5c6847p1_device +//------------------------------------------------- + +m5c6847p1_device::m5c6847p1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : mc6847_base_device(mconfig, M5C6847P1, "M5C6847P-1", tag, owner, clock, ntsc_square_fontdata8x12, 262.5, "m5c6847p1", __FILE__) +{ +} diff --git a/src/devices/video/mc6847.h b/src/devices/video/mc6847.h new file mode 100644 index 00000000000..d3420a7fcba --- /dev/null +++ b/src/devices/video/mc6847.h @@ -0,0 +1,706 @@ +// license:BSD-3-Clause +// copyright-holders:Nathan Woods +/********************************************************************* + + mc6847.h + + Implementation of Motorola 6847 video hardware chip + +***************************************************************************/ + +#pragma once + +#ifndef __MC6847__ +#define __MC6847__ + + +#define MC6847_MODE_AG 0x80 +#define MC6847_MODE_GM2 0x40 +#define MC6847_MODE_GM1 0x20 +#define MC6847_MODE_GM0 0x10 +#define MC6847_MODE_CSS 0x08 +#define MC6847_MODE_AS 0x04 +#define MC6847_MODE_INTEXT 0x02 +#define MC6847_MODE_INV 0x01 + + +//************************************************************************** +// MC6847 CONFIGURATION / INTERFACE +//************************************************************************** + +#define MCFG_SCREEN_MC6847_NTSC_ADD(_tag, _mctag) \ + MCFG_SCREEN_ADD(_tag, RASTER) \ + MCFG_SCREEN_UPDATE_DEVICE(_mctag, mc6847_base_device, screen_update) \ + MCFG_SCREEN_REFRESH_RATE(60) \ + MCFG_SCREEN_SIZE(320, 243) \ + MCFG_SCREEN_VISIBLE_AREA(0, 320-1, 1, 241-1) \ + MCFG_SCREEN_VBLANK_TIME(0) + +#define MCFG_SCREEN_MC6847_PAL_ADD(_tag, _mctag) \ + MCFG_SCREEN_ADD(_tag, RASTER) \ + MCFG_SCREEN_UPDATE_DEVICE(_mctag, mc6847_base_device, screen_update) \ + MCFG_SCREEN_REFRESH_RATE(50) \ + MCFG_SCREEN_SIZE(320, 243) \ + MCFG_SCREEN_VISIBLE_AREA(0, 320-1, 1, 241-1) \ + MCFG_SCREEN_VBLANK_TIME(0) + +#define MCFG_MC6847_HSYNC_CALLBACK(_write) \ + devcb = &mc6847_friend_device::set_hsync_wr_callback(*device, DEVCB_##_write); + +#define MCFG_MC6847_FSYNC_CALLBACK(_write) \ + devcb = &mc6847_friend_device::set_fsync_wr_callback(*device, DEVCB_##_write); + +#define MCFG_MC6847_CHARROM_CALLBACK(_class, _method) \ + mc6847_friend_device::set_get_char_rom(*device, mc6847_get_char_rom_delegate(&_class::_method, #_class "::" #_method, downcast<_class *>(owner))); + +#define MCFG_MC6847_INPUT_CALLBACK(_read) \ + devcb = &mc6847_base_device::set_input_callback(*device, DEVCB_##_read); + +#define MCFG_MC6847_FIXED_MODE(_mode) \ + mc6847_base_device::set_get_fixed_mode(*device, _mode); + +#define MCFG_MC6847_BW(_bw) \ + mc6847_base_device::set_black_and_white(*device, _bw); + + +typedef device_delegate mc6847_get_char_rom_delegate; +#define MC6847_GET_CHARROM_MEMBER(_name) UINT8 _name(UINT8 ch, int line) + + +#define ARTIFACTING_TAG "artifacting" + +INPUT_PORTS_EXTERN(mc6847_artifacting); + + +//************************************************************************** +// MC6847 CORE +//************************************************************************** + +// base class so that the GIME emulation can access mc6847 stuff +class mc6847_friend_device : public device_t +{ +public: + // inlines + bool hs_r(void) { return m_horizontal_sync; } + bool fs_r(void) { return m_field_sync; } + + template static devcb_base &set_hsync_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_hsync.set_callback(object); } + template static devcb_base &set_fsync_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_fsync.set_callback(object); } + + static void set_get_char_rom(device_t &device, mc6847_get_char_rom_delegate callback) { downcast(device).m_charrom_cb = callback; } + +protected: + mc6847_friend_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, + const UINT8 *fontdata, bool is_mc6847t1, double tpfs, int field_sync_falling_edge_scanline, bool supports_partial_body_scanlines, const char *shortname, const char *source); + + // video mode constants + static const UINT8 MODE_AG = 0x80; + static const UINT8 MODE_GM2 = 0x40; + static const UINT8 MODE_GM1 = 0x20; + static const UINT8 MODE_GM0 = 0x10; + static const UINT8 MODE_CSS = 0x08; + static const UINT8 MODE_AS = 0x04; + static const UINT8 MODE_INTEXT = 0x02; + static const UINT8 MODE_INV = 0x01; + + // timer constants + static const device_timer_id TIMER_FRAME = 0; + static const device_timer_id TIMER_HSYNC_OFF = 1; + static const device_timer_id TIMER_HSYNC_ON = 2; + static const device_timer_id TIMER_FSYNC = 3; + + // fonts + static const UINT8 pal_round_fontdata8x12[]; + static const UINT8 pal_square_fontdata8x12[]; + static const UINT8 ntsc_round_fontdata8x12[]; + static const UINT8 ntsc_square_fontdata8x12[]; + static const UINT8 semigraphics4_fontdata8x12[]; + static const UINT8 semigraphics6_fontdata8x12[]; + static const UINT8 s68047_fontdata8x12[]; + + // pixel definitions + typedef UINT32 pixel_t; + + pixel_t *bitmap_addr(bitmap_rgb32 &bitmap, int y, int x) + { + return &bitmap.pix32(y, x); + } + + static UINT8 simplify_mode(UINT8 data, UINT8 mode) + { + // simplifies MC6847 modes to drop mode flags that are not significant + return mode & ~((mode & MODE_AG) ? (MODE_AS | MODE_INV) : 0); + } + + // internal class that represents a MC6847 character map + class character_map + { + public: + // constructor that sets up the font data + character_map(const UINT8 *fontdata, bool is_mc6847t1); + + // optimized template function that emits a single character + template + ATTR_FORCE_INLINE void emit_character(UINT8 mode, const UINT8 *data, int length, pixel_t *RESTRICT pixels, int y, const pixel_t *palette) + { + for (int i = 0; i < length; i++) + { + // get the character + UINT8 character = data[i]; + + // based on the mode, determine which entry to use + const entry *e = &m_entries[mode % ARRAY_LENGTH(m_entries)]; + + // identify the character in the font data + const UINT8 *font_character = e->m_fontdata + (character & e->m_character_mask) * 12; + + // get the particular slice out + UINT8 font_character_slice = font_character[y % 12]; + + // get the two colors + UINT16 color_base_0 = e->m_color_base_0 + ((character >> e->m_color_shift_0) & e->m_color_mask_0); + UINT16 color_base_1 = e->m_color_base_1 + ((character >> e->m_color_shift_1) & e->m_color_mask_1); + pixel_t color_0 = palette[color_base_0]; + pixel_t color_1 = palette[color_base_1]; + + // emit the bits + for (int j = 0; j < 8; j++) + { + for (int k = 0; k < xscale; k++) + { + pixels[(i * 8 + j) * xscale + k] = bit_test(font_character_slice, j, color_0, color_1); + } + } + } + } + + private: + struct entry + { + const UINT8 *m_fontdata; + UINT8 m_character_mask; + UINT8 m_color_shift_0; + UINT8 m_color_shift_1; + UINT8 m_color_mask_0; + UINT8 m_color_mask_1; + UINT16 m_color_base_0; + UINT16 m_color_base_1; + }; + + // lookup table for MC6847 modes to determine font data and color + entry m_entries[128]; + + // text font data calculated on startup + UINT8 m_text_fontdata_inverse[64*12]; + UINT8 m_text_fontdata_lower_case[64*12]; + UINT8 m_text_fontdata_lower_case_inverse[64*12]; + + // optimized function that tests a single bit + ATTR_FORCE_INLINE pixel_t bit_test(UINT8 data, int shift, pixel_t color_0, pixel_t color_1) + { + return data & (0x80 >> shift) ? color_1 : color_0; + } + }; + + // artficater internal class + class artifacter + { + public: + artifacter(); + + // artifacting config + void setup_config(device_t *device); + void poll_config(void) { m_artifacting = (m_config!=NULL) ? m_config->read() : 0; } + + // artifacting application + template + ATTR_FORCE_INLINE void process_artifacts(pixel_t *pixels, UINT8 mode, const pixel_t *palette) + { + if (((mode & (MODE_AG|MODE_GM2|MODE_GM1|MODE_GM0)) == (MODE_AG|MODE_GM2|MODE_GM1|MODE_GM0)) + && (m_artifacting != 0)) + { + // identify the new colors and update + pixel_t c0 = palette[(mode & MODE_CSS) ? 10 : 8]; + pixel_t c1 = palette[(mode & MODE_CSS) ? 11 : 9]; + update_colors(c0, c1); + + // generate the new line + pixel_t new_line[256]; + int x, i; + for (x = 0; x < 256; x += 2) + { + UINT8 val = ((pixels[(x - 2) * xscale] == c1) ? 0x20 : 0x00) + | ((pixels[(x - 1) * xscale] == c1) ? 0x10 : 0x00) + | ((pixels[(x + 0) * xscale] == c1) ? 0x08 : 0x00) + | ((pixels[(x + 1) * xscale] == c1) ? 0x04 : 0x00) + | ((pixels[(x + 2) * xscale] == c1) ? 0x02 : 0x00) + | ((pixels[(x + 3) * xscale] == c1) ? 0x01 : 0x00); + + new_line[x + 0] = m_expanded_colors[val * 2 + 0]; + new_line[x + 1] = m_expanded_colors[val * 2 + 1]; + } + + // and copy it in + for (x = 0; x < 256; x++) + { + for (i = 0; i < xscale; i++) + pixels[x * xscale + i] = new_line[x]; + } + } + } + + private: + ioport_port *m_config; + ioport_value m_artifacting; + ioport_value m_saved_artifacting; + pixel_t m_saved_c0, m_saved_c1; + pixel_t m_expanded_colors[128]; + + void update_colors(pixel_t c0, pixel_t c1); + static pixel_t mix_color(double factor, UINT8 c0, UINT8 c1); + }; + + enum border_color_t + { + BORDER_COLOR_BLACK, + BORDER_COLOR_GREEN, + BORDER_COLOR_WHITE, + BORDER_COLOR_ORANGE + }; + + // callbacks + devcb_write_line m_write_hsync; + devcb_write_line m_write_fsync; + + /* if specified, this reads the external char rom off of the driver state */ + // moved here from mc6847_base_device so to be useable in GIME + mc6847_get_char_rom_delegate m_charrom_cb; + + // incidentals + character_map m_character_map; + artifacter m_artifacter; + + // device-level overrides + virtual void device_start(void); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + virtual void device_reset(void); + virtual void device_post_load(void); + + // other overridables + virtual void new_frame(void); + virtual void horizontal_sync_changed(bool line); + virtual void field_sync_changed(bool line); + virtual void enter_bottom_border(void); + virtual void record_border_scanline(UINT16 physical_scanline); + virtual void record_body_scanline(UINT16 physical_scanline, UINT16 logical_scanline) = 0; + virtual void record_partial_body_scanline(UINT16 physical_scanline, UINT16 logical_scanline, INT32 start_clock, INT32 end_clock) = 0; + + // miscellaneous + void video_flush(void); + const char *describe_context(void); + + // setup functions + emu_timer *setup_timer(device_timer_id id, double offset, double period); + + // converts to B&W + static pixel_t black_and_white(rgb_t color) + { + UINT8 average_color = (color.r() + color.g() + color.b()) / 3; + return rgb_t(average_color, average_color, average_color); + } + + // changes the geometry + ATTR_FORCE_INLINE void set_geometry(UINT16 top_border_scanlines, UINT16 body_scanlines, bool wide) + { + if (UNEXPECTED((m_top_border_scanlines != top_border_scanlines) + || (m_body_scanlines != body_scanlines) + || (m_wide != wide))) + { + m_top_border_scanlines = top_border_scanlines; + m_body_scanlines = body_scanlines; + m_wide = wide; + update_field_sync_timer(); + } + } + + // calculates the border color + static ATTR_FORCE_INLINE border_color_t border_value(UINT8 mode, bool is_mc6847t1) + { + border_color_t result; + + if (mode & MODE_AG) + { + // graphics + result = mode & MODE_CSS ? BORDER_COLOR_WHITE : BORDER_COLOR_GREEN; + } + else if (!is_mc6847t1 || ((mode & MODE_GM2) == 0)) + { + // text, black border + result = BORDER_COLOR_BLACK; + } + else + { + // text, green or orange border + result = mode & MODE_CSS ? BORDER_COLOR_ORANGE : BORDER_COLOR_GREEN; + } + return result; + } + + // checks to see if the video has changed + ATTR_FORCE_INLINE bool has_video_changed(void) + { + /* poll the artifacting config */ + m_artifacter.poll_config(); + + /* if the video didn't change, indicate as much */ + bool video_changed = m_video_changed; + m_video_changed = false; + return video_changed; + } + + // updates a byte in the video state + template + ATTR_FORCE_INLINE bool update_value(T *ptr, T byte) + { + bool result = false; + if (*ptr != byte) + { + *ptr = byte; + m_video_changed = true; + result = true; + } + return result; + } + + // template function for emitting graphics bytes + template + ATTR_FORCE_INLINE void emit_graphics(const UINT8 *data, int length, pixel_t *RESTRICT pixels, UINT16 color_base, const pixel_t *RESTRICT palette) + { + for (int i = 0; i < length; i++) + { + for (int j = 0; j < (8 / bits_per_pixel); j++) + { + for (int k = 0; k < xscale; k++) + { + UINT16 color = color_base + ((data[i] >> (8 - (j + 1) * bits_per_pixel)) & ((1 << bits_per_pixel) - 1)); + pixels[(i * (8 / bits_per_pixel) + j) * xscale + k] = palette[color]; + } + } + } + } + + // template function for external bytes + template + ATTR_FORCE_INLINE void emit_extbytes(const UINT8 *data, int length, pixel_t *RESTRICT pixels, UINT16 color_base, const pixel_t *RESTRICT palette) + { + for (int i = 0; i < length; i++) + { + for (int j = 0; j < (8 / bits_per_pixel); j++) + { + for (int k = 0; k < xscale; k++) + { + UINT16 color = color_base + BIT(data[i], 7-j); + pixels[(i * (8 / bits_per_pixel) + j) * xscale + k] = palette[color]; + } + } + } + } + + // template function for emitting samples + template + UINT32 emit_mc6847_samples(UINT8 mode, const UINT8 *data, int length, pixel_t *RESTRICT pixels, const pixel_t *RESTRICT palette, + mc6847_get_char_rom_delegate get_char_rom, int x, int y) + { + UINT32 result = 0; + if (mode & MODE_AG) + { + /* graphics */ + switch(mode & (MODE_GM2|MODE_GM1|MODE_GM0)) + { + case 0: + emit_graphics<2, xscale * 4>(data, length, pixels, (mode & MODE_CSS) ? 4 : 0, palette); + result = length * 8 * xscale * 2; + break; + + case MODE_GM0: + case MODE_GM1|MODE_GM0: + case MODE_GM2|MODE_GM0: + emit_graphics<1, xscale * 2>(data, length, pixels, (mode & MODE_CSS) ? 10 : 8, palette); + result = length * 8 * xscale * 2; + break; + + case MODE_GM1: + case MODE_GM2: + case MODE_GM2|MODE_GM1: + emit_graphics<2, xscale * 2>(data, length, pixels, (mode & MODE_CSS) ? 4 : 0, palette); + result = length * 8 * xscale; + break; + + case MODE_GM2|MODE_GM1|MODE_GM0: + emit_graphics<1, xscale * 1>(data, length, pixels, (mode & MODE_CSS) ? 10 : 8, palette); + result = length * 8 * xscale; + break; + + default: + /* should not get here */ + fatalerror("Should not get here\n"); + break; + } + } + else if (!get_char_rom.isnull() && ((mode & (MODE_AG|MODE_AS|MODE_INTEXT)) == MODE_INTEXT)) + { + /* external ROM */ + for (int i = 0; i < length; i++) + { + UINT8 byte = get_char_rom(data[i], y % 12) ^ (mode & MODE_INV ? 0xFF : 0x00); + emit_extbytes<1, xscale>(&byte, 1, &pixels[i * 8], (mode & MODE_CSS) ? 14 : 12, palette); + } + result = length * 8 * xscale; + } + else + { + /* text/semigraphics */ + m_character_map.emit_character(mode, data, length, pixels, y, palette); + result = length * 8 * xscale; + } + return result; + } + +private: + enum scanline_zone + { + SCANLINE_ZONE_TOP_BORDER, + SCANLINE_ZONE_BODY, + SCANLINE_ZONE_BOTTOM_BORDER, + SCANLINE_ZONE_RETRACE, + SCANLINE_ZONE_VBLANK, + SCANLINE_ZONE_FRAME_END + }; + + // timers + emu_timer *m_frame_timer; + emu_timer *m_hsync_on_timer; + emu_timer *m_hsync_off_timer; + emu_timer *m_fsync_timer; + + // incidentals + double m_tpfs; + int m_field_sync_falling_edge_scanline; + bool m_wide; + bool m_video_changed; + UINT16 m_top_border_scanlines; + UINT16 m_body_scanlines; + bool m_recording_scanline; + bool m_supports_partial_body_scanlines; + + // video state + UINT16 m_physical_scanline; + UINT16 m_logical_scanline; + UINT16 m_logical_scanline_zone; + bool m_horizontal_sync; + bool m_field_sync; + UINT32 m_partial_scanline_clocks; + + // functions + void change_horizontal_sync(bool line); + void change_field_sync(bool line); + void update_field_sync_timer(void); + void next_scanline(void); + INT32 get_clocks_since_hsync(); + + // debugging + const char *scanline_zone_string(scanline_zone zone); +}; + +// actual base class for MC6847 family of devices +class mc6847_base_device : public mc6847_friend_device +{ +public: + template static devcb_base &set_input_callback(device_t &device, _Object object) { return downcast(device).m_input_cb.set_callback(object); } + + static void set_get_fixed_mode(device_t &device, UINT8 mode) { downcast(device).m_fixed_mode = mode; } + static void set_black_and_white(device_t &device, bool bw) { downcast(device).m_black_and_white = bw; } + + /* updates the screen -- this will call begin_update(), + followed by update_row() reapeatedly and after all row + updating is complete, end_update() */ + UINT32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); + + // mode changing operations + DECLARE_WRITE_LINE_MEMBER( ag_w ) { change_mode(MODE_AG, state); } + DECLARE_WRITE_LINE_MEMBER( gm2_w ) { change_mode(MODE_GM2, state); } + DECLARE_WRITE_LINE_MEMBER( gm1_w ) { change_mode(MODE_GM1, state); } + DECLARE_WRITE_LINE_MEMBER( gm0_w ) { change_mode(MODE_GM0, state); } + DECLARE_WRITE_LINE_MEMBER( as_w ) { change_mode(MODE_AS, state); } + DECLARE_WRITE_LINE_MEMBER( css_w ) { change_mode(MODE_CSS, state); } + DECLARE_WRITE_LINE_MEMBER( intext_w ) { change_mode(MODE_INTEXT, state); } + DECLARE_WRITE_LINE_MEMBER( inv_w ) { change_mode(MODE_INV, state); } + +protected: + mc6847_base_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const UINT8 *fontdata, double tpfs, const char *shortname, const char *source); + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual ioport_constructor device_input_ports() const; + + // other overrides + virtual void field_sync_changed(bool line); + virtual void record_body_scanline(UINT16 physical_scanline, UINT16 scanline); + virtual void record_partial_body_scanline(UINT16 physical_scanline, UINT16 logical_scanline, INT32 start_clock, INT32 end_clock); + + void set_custom_palette(const pixel_t *custom_palette) + { + if ( m_palette != m_bw_palette ) + { + m_palette = custom_palette ? custom_palette : s_palette; + } + } + +private: + struct video_scanline + { + UINT8 m_sample_count; + UINT8 m_mode[32]; + UINT8 m_data[32]; + }; + + // palette + static const int PALETTE_LENGTH = 16; + static const UINT32 s_palette[PALETTE_LENGTH]; + + // callbacks + + /* if specified, this gets called whenever reading a byte (offs_t ~0 specifies DA* entering the tristate mode) */ + devcb_read8 m_input_cb; + + /* if true, this is black and white */ + bool m_black_and_white; + + // incidentals + UINT8 m_fixed_mode; + UINT8 m_fixed_mode_mask; + const pixel_t *m_palette; + pixel_t m_bw_palette[PALETTE_LENGTH]; + + // state + UINT8 m_mode; + UINT16 m_video_address; + bool m_dirty; + video_scanline m_data[192]; + + void change_mode(UINT8 mode, int state) + { + // sanity check, to ensure that we're not changing fixed modes + assert((mode & m_fixed_mode_mask) == 0); + + // calculate new mode + UINT8 new_mode; + if (state) + new_mode = m_mode | mode; + else + new_mode = m_mode & ~mode; + + // has the mode changed? + if (new_mode != m_mode) + { + // it has! check dirty flag + video_flush(); + if (!m_dirty) + { + m_dirty = true; + } + + // and set the new mode + m_mode = new_mode; + } + } + + // setup functions + void setup_fixed_mode(); + + // runtime functions + void record_body_scanline(UINT16 physical_scanline, UINT16 scanline, INT32 start_pos, INT32 end_pos); + pixel_t border_value(UINT8 mode, const pixel_t *palette, bool is_mc6847t1); + + template + void emit_samples(UINT8 mode, const UINT8 *data, int length, pixel_t *pixels, int x, int y); + + // template function for doing video update collection + template + void record_scanline_res(int scanline, INT32 start_pos, INT32 end_pos); + + // miscellaneous + UINT8 input(UINT16 address); + INT32 scanline_position_from_clock(INT32 clocks_since_hsync); +}; + + +//************************************************************************** +// VARIATIONS +//************************************************************************** + +class mc6847_ntsc_device : public mc6847_base_device +{ +public: + mc6847_ntsc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class mc6847_pal_device : public mc6847_base_device +{ +public: + mc6847_pal_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class mc6847y_ntsc_device : public mc6847_base_device +{ +public: + mc6847y_ntsc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class mc6847y_pal_device : public mc6847_base_device +{ +public: + mc6847y_pal_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class mc6847t1_ntsc_device : public mc6847_base_device +{ +public: + mc6847t1_ntsc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class mc6847t1_pal_device : public mc6847_base_device +{ +public: + mc6847t1_pal_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class s68047_device : public mc6847_base_device +{ +public: + s68047_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + void hack_black_becomes_blue(bool flag); + +private: + static const UINT32 s_s68047_hack_palette[16]; +}; + +class m5c6847p1_device : public mc6847_base_device +{ +public: + m5c6847p1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +extern const device_type MC6847_NTSC; +extern const device_type MC6847_PAL; +extern const device_type MC6847Y_NTSC; +extern const device_type MC6847Y_PAL; +extern const device_type MC6847T1_NTSC; +extern const device_type MC6847T1_PAL; +extern const device_type S68047; +extern const device_type M5C6847P1; + +#endif /* __MC6847__ */ diff --git a/src/devices/video/mos6566.c b/src/devices/video/mos6566.c new file mode 100644 index 00000000000..64b061c3107 --- /dev/null +++ b/src/devices/video/mos6566.c @@ -0,0 +1,2839 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/*************************************************************************** + + MOS 6566/6567/6569 Video Interface Chip (VIC-II) emulation + + A part of the code (cycle routine and drawing routines) is a modified version of the vic ii emulation used in + commodore 64 emulator "frodo" by Christian Bauer + + http://frodo.cebix.net/ + The rights on the source code remain at the author. + It may not - not even in parts - used for commercial purposes without explicit written permission by the author. + Permission to use it for non-commercial purposes is hereby granted als long as my copyright notice remains in the program. + You are not allowed to use the source to create and distribute a modified version of Frodo. + +***************************************************************************/ + +/* + + TODO: + + - cleanup + - http://hitmen.c02.at/temp/palstuff/ + +*/ + +#include "mos6566.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define LOG 0 + + +enum +{ + REGISTER_M0X = 0, + REGISTER_M0Y, + REGISTER_M1X, + REGISTER_M1Y, + REGISTER_M2X, + REGISTER_M2Y, + REGISTER_M3X, + REGISTER_M3Y, + REGISTER_M4X, + REGISTER_M4Y, + REGISTER_M5X, + REGISTER_M5Y, + REGISTER_M6X, + REGISTER_M6Y, + REGISTER_M7X, + REGISTER_M7Y, + REGISTER_MX_MSB, + REGISTER_CR1, + REGISTER_RASTER, + REGISTER_LPX, + REGISTER_LPY, + REGISTER_ME, + REGISTER_CR2, + REGISTER_MYE, + REGISTER_MP, + REGISTER_IRQ, + REGISTER_IE, + REGISTER_MDP, + REGISTER_MMC, + REGISTER_MXE, + REGISTER_MM, + REGISTER_MD, + REGISTER_EC, + REGISTER_B0C, + REGISTER_B1C, + REGISTER_B2C, + REGISTER_B3C, + REGISTER_MM0, + REGISTER_MM1, + REGISTER_M0C, + REGISTER_M1C, + REGISTER_M2C, + REGISTER_M3C, + REGISTER_M4C, + REGISTER_M5C, + REGISTER_M6C, + REGISTER_M7C, + REGISTER_KCR, + REGISTER_FAST +}; + +static int UNUSED_BITS[0x40] = +{ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x01, 0x70, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff +}; + +// VICE palette +static const rgb_t PALETTE_MOS[] = +{ + rgb_t(0x00, 0x00, 0x00), + rgb_t(0xfd, 0xfe, 0xfc), + rgb_t(0xbe, 0x1a, 0x24), + rgb_t(0x30, 0xe6, 0xc6), + rgb_t(0xb4, 0x1a, 0xe2), + rgb_t(0x1f, 0xd2, 0x1e), + rgb_t(0x21, 0x1b, 0xae), + rgb_t(0xdf, 0xf6, 0x0a), + rgb_t(0xb8, 0x41, 0x04), + rgb_t(0x6a, 0x33, 0x04), + rgb_t(0xfe, 0x4a, 0x57), + rgb_t(0x42, 0x45, 0x40), + rgb_t(0x70, 0x74, 0x6f), + rgb_t(0x59, 0xfe, 0x59), + rgb_t(0x5f, 0x53, 0xfe), + rgb_t(0xa4, 0xa7, 0xa2) +}; + + +#define VERBOSE_LEVEL 0 +#define DBG_LOG(N,M,A) \ + do { \ + if(VERBOSE_LEVEL >= N) \ + { \ + if( M ) \ + logerror("%11.6f: %-24s", machine().time().as_double(), (char*) M ); \ + logerror A; \ + } \ + } while (0) + +#define IS_PAL ((m_variant == TYPE_6569) || (m_variant == TYPE_6572) || (m_variant == TYPE_6573) || (m_variant == TYPE_8565) || (m_variant == TYPE_8565) || (m_variant == TYPE_8569)) +#define IS_VICIIE ((m_variant == TYPE_8564) || (m_variant == TYPE_8566) || (m_variant == TYPE_8569)) + +#define ROW25_YSTART 0x33 +#define ROW25_YSTOP 0xfb +#define ROW24_YSTART 0x37 +#define ROW24_YSTOP 0xf7 + +#define RASTERLINE_2_C64(a) (a) +#define C64_2_RASTERLINE(a) (a) +#define XPOS (VIC2_STARTVISIBLECOLUMNS + (VIC2_VISIBLECOLUMNS - VIC2_HSIZE) / 2) +#define YPOS (VIC2_STARTVISIBLELINES /* + (VIC2_VISIBLELINES - VIC2_VSIZE) / 2 */) +#define FIRSTCOLUMN 50 + +/* 2008-05 FP: lightpen code needs to read input port from c64.c and cbmb.c */ + +#define LIGHTPEN_BUTTON (m_in_lightpen_button_func(0)) +#define LIGHTPEN_X_VALUE (m_in_lightpen_x_func(0)) +#define LIGHTPEN_Y_VALUE (m_in_lightpen_y_func(0)) + +/* lightpen delivers values from internal counters; they do not start with the visual area or frame area */ +#define VIC2_MAME_XPOS 0 +#define VIC2_MAME_YPOS 0 +#define VIC6567_X_BEGIN 38 +#define VIC6567_Y_BEGIN -6 /* first 6 lines after retrace not for lightpen! */ +#define VIC6569_X_BEGIN 38 +#define VIC6569_Y_BEGIN -6 +#define VIC2_X_BEGIN (IS_PAL ? VIC6569_X_BEGIN : VIC6567_X_BEGIN) +#define VIC2_Y_BEGIN (IS_PAL ? VIC6569_Y_BEGIN : VIC6567_Y_BEGIN) +#define VIC2_X_VALUE ((LIGHTPEN_X_VALUE / 1.3) + 12) +#define VIC2_Y_VALUE ((LIGHTPEN_Y_VALUE ) + 10) + +/* sprites 0 .. 7 */ +#define SPRITEON(nr) (m_reg[0x15] & (1 << nr)) +#define SPRITE_Y_EXPAND(nr) (m_reg[0x17] & (1 << nr)) +#define SPRITE_Y_SIZE(nr) (SPRITE_Y_EXPAND(nr) ? 2 * 21 : 21) +#define SPRITE_X_EXPAND(nr) (m_reg[0x1d] & (1 << nr)) +#define SPRITE_X_SIZE(nr) (SPRITE_X_EXPAND(nr) ? 2 * 24 : 24) +#define SPRITE_X_POS(nr) (m_reg[(nr) * 2] | (m_reg[0x10] & (1 << (nr)) ? 0x100 : 0)) +#define SPRITE_Y_POS(nr) (m_reg[1 + 2 * (nr)]) +#define SPRITE_MULTICOLOR(nr) (m_reg[0x1c] & (1 << nr)) +#define SPRITE_PRIORITY(nr) (m_reg[0x1b] & (1 << nr)) +#define SPRITE_MULTICOLOR1 (m_reg[0x25] & 0x0f) +#define SPRITE_MULTICOLOR2 (m_reg[0x26] & 0x0f) +#define SPRITE_COLOR(nr) (m_reg[0x27+nr] & 0x0f) +#define SPRITE_ADDR(nr) (m_videoaddr | 0x3f8 | nr) +#define SPRITE_COLL (m_reg[0x1e]) +#define SPRITE_BG_COLL (m_reg[0x1f]) + +#define GFXMODE ((m_reg[0x11] & 0x60) | (m_reg[0x16] & 0x10)) >> 4 +#define SCREENON (m_reg[0x11] & 0x10) +#define YSCROLL (m_reg[0x11] & 0x07) +#define XSCROLL (m_reg[0x16] & 0x07) +#define ECMON (m_reg[0x11] & 0x40) +#define HIRESON (m_reg[0x11] & 0x20) +#define COLUMNS40 (m_reg[0x16] & 0x08) /* else 38 Columns */ + +#define VIDEOADDR ((m_reg[0x18] & 0xf0) << (10 - 4)) +#define CHARGENADDR ((m_reg[0x18] & 0x0e) << 10) +#define BITMAPADDR ((data & 0x08) << 10) + +#define RASTERLINE (((m_reg[0x11] & 0x80) << 1) | m_reg[0x12]) + +#define FRAMECOLOR (m_reg[0x20] & 0x0f) +#define BACKGROUNDCOLOR (m_reg[0x21] & 0x0f) +#define MULTICOLOR1 (m_reg[0x22] & 0x0f) +#define MULTICOLOR2 (m_reg[0x23] & 0x0f) +#define FOREGROUNDCOLOR (m_reg[0x24] & 0x0f) + +#define VIC2_LINES (IS_PAL ? VIC6569_LINES : VIC6567_LINES) +#define VIC2_FIRST_DMA_LINE (IS_PAL ? VIC6569_FIRST_DMA_LINE : VIC6567_FIRST_DMA_LINE) +#define VIC2_LAST_DMA_LINE (IS_PAL ? VIC6569_LAST_DMA_LINE : VIC6567_LAST_DMA_LINE) +#define VIC2_FIRST_DISP_LINE (IS_PAL ? VIC6569_FIRST_DISP_LINE : VIC6567_FIRST_DISP_LINE) +#define VIC2_LAST_DISP_LINE (IS_PAL ? VIC6569_LAST_DISP_LINE : VIC6567_LAST_DISP_LINE) +#define VIC2_RASTER_2_EMU(a) (IS_PAL ? VIC6569_RASTER_2_EMU(a) : VIC6567_RASTER_2_EMU(a)) +#define VIC2_FIRSTCOLUMN (IS_PAL ? VIC6569_FIRSTCOLUMN : VIC6567_FIRSTCOLUMN) +#define VIC2_X_2_EMU(a) (IS_PAL ? VIC6569_X_2_EMU(a) : VIC6567_X_2_EMU(a)) + +#define IRQ_RST 0x01 +#define IRQ_MBC 0x02 +#define IRQ_MMC 0x04 +#define IRQ_LP 0x08 + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type MOS6566 = &device_creator; +const device_type MOS6567 = &device_creator; +const device_type MOS8562 = &device_creator; +const device_type MOS8564 = &device_creator; +const device_type MOS6569 = &device_creator; +const device_type MOS8565 = &device_creator; +const device_type MOS8566 = &device_creator; + + +// default address maps +static ADDRESS_MAP_START( mos6566_videoram_map, AS_0, 8, mos6566_device ) + AM_RANGE(0x0000, 0x3fff) AM_RAM +ADDRESS_MAP_END + +static ADDRESS_MAP_START( mos6566_colorram_map, AS_1, 8, mos6566_device ) + AM_RANGE(0x000, 0x3ff) AM_RAM +ADDRESS_MAP_END + + +//------------------------------------------------- +// memory_space_config - return a description of +// any address spaces owned by this device +//------------------------------------------------- + +const address_space_config *mos6566_device::memory_space_config(address_spacenum spacenum) const +{ + switch (spacenum) + { + case AS_0: return &m_videoram_space_config; + case AS_1: return &m_colorram_space_config; + default: return NULL; + } +} + + + +//************************************************************************** +// INLINE HELPERS +//************************************************************************** + +inline void mos6566_device::set_interrupt( int mask ) +{ + if (((m_reg[0x19] ^ mask) & m_reg[0x1a] & 0xf)) + { + if (!(m_reg[0x19] & 0x80)) + { + DBG_LOG(2, "vic2", ("irq start %.2x\n", mask)); + m_reg[0x19] |= 0x80; + m_write_irq(ASSERT_LINE); + } + } + m_reg[0x19] |= mask; +} + +inline void mos6566_device::clear_interrupt( int mask ) +{ + m_reg[0x19] &= ~mask; + if ((m_reg[0x19] & 0x80) && !(m_reg[0x19] & m_reg[0x1a] & 0xf)) + { + DBG_LOG(2, "vic2", ("irq end %.2x\n", mask)); + m_reg[0x19] &= ~0x80; + m_write_irq(CLEAR_LINE); + } +} + +inline UINT8 mos6566_device::read_videoram(offs_t offset) +{ + //logerror("cycle %u VRAM %04x BA %u AEC %u\n", m_cycle, offset & 0x3fff, m_ba, m_aec); + m_last_data = space(AS_0).read_byte(offset & 0x3fff); + + return m_last_data; +} + +inline UINT8 mos6566_device::read_colorram(offs_t offset) +{ + return space(AS_1).read_byte(offset & 0x3ff); +} + +// Idle access +inline void mos6566_device::idle_access() +{ + read_videoram(0x3fff); +} + +// Fetch sprite data pointer +inline void mos6566_device::spr_ptr_access( int num ) +{ + m_spr_ptr[num] = read_videoram(SPRITE_ADDR(num)) << 6; +} + +inline void mos6566_device::spr_ba(int num) +{ + if (BIT(m_spr_dma_on, num)) + { + set_ba(CLEAR_LINE); + m_rdy_cycles += 2; + } + else if (num > 1 && !BIT(m_spr_dma_on, num - 1)) + { + set_ba(ASSERT_LINE); + } +} + +// Fetch sprite data, increment data counter +inline void mos6566_device::spr_data_access( int num, int bytenum ) +{ + if (m_spr_dma_on & (1 << num)) + { + m_spr_data[num][bytenum] = read_videoram((m_mc[num] & 0x3f) | m_spr_ptr[num]); + m_mc[num]++; + } + else + if (bytenum == 1) + idle_access(); +} + +// Turn on display if Bad Line +inline void mos6566_device::display_if_bad_line() +{ + if (m_is_bad_line) + m_display_state = 1; +} + +inline void mos6566_device::set_ba(int state) +{ + if (m_ba != state) + { + m_ba = state; + + if (m_ba) + { + m_aec_delay = 0xff; + } + } +} + +inline void mos6566_device::set_aec(int state) +{ + if (m_aec != state) + { + m_aec = state; + } +} + +inline void mos6566_device::bad_line_ba() +{ + if (m_is_bad_line) + { + if (m_ba) + { + set_ba(CLEAR_LINE); + m_rdy_cycles += 55 - m_cycle; + } + } + else + { + set_ba(ASSERT_LINE); + } +} + +// Refresh access +inline void mos6566_device::refresh_access() +{ + read_videoram(0x3f00 | m_ref_cnt--); +} + + +inline void mos6566_device::fetch_if_bad_line() +{ + if (m_is_bad_line) + m_display_state = 1; +} + + +// Turn on display and matrix access and reset RC if Bad Line +inline void mos6566_device::rc_if_bad_line() +{ + if (m_is_bad_line) + { + m_display_state = 1; + m_rc = 0; + } +} + +// Sample border color and increment m_graphic_x +inline void mos6566_device::sample_border() +{ + if (m_draw_this_line) + { + if (m_border_on) + m_border_color_sample[m_cycle - 13] = FRAMECOLOR; + m_graphic_x += 8; + } +} + + +// Turn on sprite DMA if necessary +inline void mos6566_device::check_sprite_dma() +{ + int i; + UINT8 mask = 1; + + for (i = 0; i < 8; i++, mask <<= 1) + if (SPRITEON(i) && ((m_rasterline & 0xff) == SPRITE_Y_POS(i))) + { + m_spr_dma_on |= mask; + m_mc_base[i] = 0; + if (SPRITE_Y_EXPAND(i)) + m_spr_exp_y &= ~mask; + } +} + +// Video matrix access +inline void mos6566_device::matrix_access() +{ + if (!m_is_bad_line) return; + + UINT16 adr = (m_vc & 0x03ff) | VIDEOADDR; + + // we're in the second clock phase + m_phi0 = 1; + set_aec(BIT(m_aec_delay, 2)); + + if (!m_ba && m_aec) + { + m_matrix_line[m_ml_index] = 0xff; + } + else + { + m_matrix_line[m_ml_index] = read_videoram(adr); + } + + m_color_line[m_ml_index] = read_colorram(adr & 0x03ff); +} + +// Graphics data access +inline void mos6566_device::graphics_access() +{ + if (m_display_state == 1) + { + UINT16 adr; + if (HIRESON) + adr = ((m_vc & 0x03ff) << 3) | m_bitmapaddr | m_rc; + else + adr = (m_matrix_line[m_ml_index] << 3) | m_chargenaddr | m_rc; + if (ECMON) + adr &= 0xf9ff; + m_gfx_data = read_videoram(adr); + m_char_data = m_matrix_line[m_ml_index]; + m_color_data = m_color_line[m_ml_index]; + m_ml_index++; + m_vc++; + } + else + { + m_gfx_data = read_videoram((ECMON ? 0x39ff : 0x3fff)); + m_char_data = 0; + } +} + +inline void mos6566_device::draw_background() +{ + if (m_draw_this_line) + { + UINT8 c; + + switch (GFXMODE) + { + case 0: + case 1: + case 3: + c = m_colors[0]; + break; + case 2: + c = m_last_char_data & 0x0f; + break; + case 4: + if (m_last_char_data & 0x80) + if (m_last_char_data & 0x40) + c = m_colors[3]; + else + c = m_colors[2]; + else + if (m_last_char_data & 0x40) + c = m_colors[1]; + else + c = m_colors[0]; + break; + default: + c = 0; + break; + } + m_bitmap.plot_box(m_graphic_x, VIC2_RASTER_2_EMU(m_rasterline), 8, 1, PALETTE_MOS[c]); + } +} + +inline void mos6566_device::draw_mono( UINT16 p, UINT8 c0, UINT8 c1 ) +{ + UINT8 c[2]; + UINT8 data = m_gfx_data; + + c[0] = c0; + c[1] = c1; + + m_bitmap.pix32(VIC2_RASTER_2_EMU(m_rasterline), p + 7) = PALETTE_MOS[c[data & 1]]; + m_fore_coll_buf[p + 7] = data & 1; data >>= 1; + m_bitmap.pix32(VIC2_RASTER_2_EMU(m_rasterline), p + 6) = PALETTE_MOS[c[data & 1]]; + m_fore_coll_buf[p + 6] = data & 1; data >>= 1; + m_bitmap.pix32(VIC2_RASTER_2_EMU(m_rasterline), p + 5) = PALETTE_MOS[c[data & 1]]; + m_fore_coll_buf[p + 5] = data & 1; data >>= 1; + m_bitmap.pix32(VIC2_RASTER_2_EMU(m_rasterline), p + 4) = PALETTE_MOS[c[data & 1]]; + m_fore_coll_buf[p + 4] = data & 1; data >>= 1; + m_bitmap.pix32(VIC2_RASTER_2_EMU(m_rasterline), p + 3) = PALETTE_MOS[c[data & 1]]; + m_fore_coll_buf[p + 3] = data & 1; data >>= 1; + m_bitmap.pix32(VIC2_RASTER_2_EMU(m_rasterline), p + 2) = PALETTE_MOS[c[data & 1]]; + m_fore_coll_buf[p + 2] = data & 1; data >>= 1; + m_bitmap.pix32(VIC2_RASTER_2_EMU(m_rasterline), p + 1) = PALETTE_MOS[c[data & 1]]; + m_fore_coll_buf[p + 1] = data & 1; data >>= 1; + m_bitmap.pix32(VIC2_RASTER_2_EMU(m_rasterline), p + 0) = PALETTE_MOS[c[data]]; + m_fore_coll_buf[p + 0] = data & 1; +} + +inline void mos6566_device::draw_multi( UINT16 p, UINT8 c0, UINT8 c1, UINT8 c2, UINT8 c3 ) +{ + UINT8 c[4]; + UINT8 data = m_gfx_data; + + c[0] = c0; + c[1] = c1; + c[2] = c2; + c[3] = c3; + + m_bitmap.pix32(VIC2_RASTER_2_EMU(m_rasterline), p + 7) = PALETTE_MOS[c[data & 3]]; + m_fore_coll_buf[p + 7] = data & 2; + m_bitmap.pix32(VIC2_RASTER_2_EMU(m_rasterline), p + 6) = PALETTE_MOS[c[data & 3]]; + m_fore_coll_buf[p + 6] = data & 2; data >>= 2; + m_bitmap.pix32(VIC2_RASTER_2_EMU(m_rasterline), p + 5) = PALETTE_MOS[c[data & 3]]; + m_fore_coll_buf[p + 5] = data & 2; + m_bitmap.pix32(VIC2_RASTER_2_EMU(m_rasterline), p + 4) = PALETTE_MOS[c[data & 3]]; + m_fore_coll_buf[p + 4] = data & 2; data >>= 2; + m_bitmap.pix32(VIC2_RASTER_2_EMU(m_rasterline), p + 3) = PALETTE_MOS[c[data & 3]]; + m_fore_coll_buf[p + 3] = data & 2; + m_bitmap.pix32(VIC2_RASTER_2_EMU(m_rasterline), p + 2) = PALETTE_MOS[c[data & 3]]; + m_fore_coll_buf[p + 2] = data & 2; data >>= 2; + m_bitmap.pix32(VIC2_RASTER_2_EMU(m_rasterline), p + 1) = PALETTE_MOS[c[data]]; + m_fore_coll_buf[p + 1] = data & 2; + m_bitmap.pix32(VIC2_RASTER_2_EMU(m_rasterline), p + 0) = PALETTE_MOS[c[data]]; + m_fore_coll_buf[p + 0] = data & 2; +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// mos6566_device - constructor +//------------------------------------------------- + +mos6566_device::mos6566_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, MOS6566, "MOS6566", tag, owner, clock, "mos6566", __FILE__), + device_memory_interface(mconfig, *this), + device_video_interface(mconfig, *this), + device_execute_interface(mconfig, *this), + m_icount(0), + m_variant(TYPE_6566), + m_videoram_space_config("videoram", ENDIANNESS_LITTLE, 8, 14, 0, NULL, *ADDRESS_MAP_NAME(mos6566_videoram_map)), + m_colorram_space_config("colorram", ENDIANNESS_LITTLE, 8, 10, 0, NULL, *ADDRESS_MAP_NAME(mos6566_colorram_map)), + m_write_irq(*this), + m_write_ba(*this), + m_write_aec(*this), + m_write_k(*this), + m_cpu(*this) +{ +} + +mos6566_device::mos6566_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, UINT32 variant, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_memory_interface(mconfig, *this), + device_video_interface(mconfig, *this), + device_execute_interface(mconfig, *this), + m_icount(0), + m_variant(variant), + m_videoram_space_config("videoram", ENDIANNESS_LITTLE, 8, 14, 0, NULL, *ADDRESS_MAP_NAME(mos6566_videoram_map)), + m_colorram_space_config("colorram", ENDIANNESS_LITTLE, 8, 10, 0, NULL, *ADDRESS_MAP_NAME(mos6566_colorram_map)), + m_write_irq(*this), + m_write_ba(*this), + m_write_aec(*this), + m_write_k(*this), + m_cpu(*this), + m_phi0(1), + m_ba(ASSERT_LINE), + m_aec(ASSERT_LINE) +{ +} + +mos6567_device::mos6567_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + :mos6566_device(mconfig, MOS6567, "MOS6567", tag, owner, clock, TYPE_6567, "mos6567", __FILE__) { } + +mos6567_device::mos6567_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, UINT32 variant, const char *shortname, const char *source) + :mos6566_device(mconfig, type, name, tag, owner, clock, variant, shortname, source) { } + +mos8562_device::mos8562_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + :mos6567_device(mconfig, MOS8562, "MOS8562", tag, owner, clock, TYPE_8562, "mos8562", __FILE__) { } + +mos8564_device::mos8564_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + :mos6567_device(mconfig, MOS8564, "MOS8564", tag, owner, clock, TYPE_8564, "mos8564", __FILE__) { } + +mos6569_device::mos6569_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + :mos6566_device(mconfig, MOS6566, "MOS6569", tag, owner, clock, TYPE_6569, "mos6569", __FILE__) { } + +mos6569_device::mos6569_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, UINT32 variant, const char *shortname, const char *source) + :mos6566_device(mconfig, type, name, tag, owner, clock, variant, shortname, source) { } + +mos8565_device::mos8565_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + :mos6569_device(mconfig, MOS8565, "MOS8565", tag, owner, clock, TYPE_8565, "mos8565", __FILE__) { } + +mos8566_device::mos8566_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + :mos6569_device(mconfig, MOS8566, "MOS8566", tag, owner, clock, TYPE_8566, "mos8566", __FILE__) { } + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void mos6566_device::device_start() +{ + // set our instruction counter + m_icountptr = &m_icount; + + // resolve callbacks + m_write_irq.resolve_safe(); + m_write_ba.resolve_safe(); + m_write_aec.resolve_safe(); + m_write_k.resolve_safe(); + + m_screen->register_screen_bitmap(m_bitmap); + + for (int i = 0; i < 256; i++) + { + m_expandx[i] = 0; + if (i & 1) + m_expandx[i] |= 3; + if (i & 2) + m_expandx[i] |= 0xc; + if (i & 4) + m_expandx[i] |= 0x30; + if (i & 8) + m_expandx[i] |= 0xc0; + if (i & 0x10) + m_expandx[i] |= 0x300; + if (i & 0x20) + m_expandx[i] |= 0xc00; + if (i & 0x40) + m_expandx[i] |= 0x3000; + if (i & 0x80) + m_expandx[i] |= 0xc000; + } + + for (int i = 0; i < 256; i++) + { + m_expandx_multi[i] = 0; + if (i & 1) + m_expandx_multi[i] |= 5; + if (i & 2) + m_expandx_multi[i] |= 0xa; + if (i & 4) + m_expandx_multi[i] |= 0x50; + if (i & 8) + m_expandx_multi[i] |= 0xa0; + if (i & 0x10) + m_expandx_multi[i] |= 0x500; + if (i & 0x20) + m_expandx_multi[i] |= 0xa00; + if (i & 0x40) + m_expandx_multi[i] |= 0x5000; + if (i & 0x80) + m_expandx_multi[i] |= 0xa000; + } + + // state saving + save_item(NAME(m_reg)); + + save_item(NAME(m_on)); + + //save_item(NAME(m_bitmap)); + + save_item(NAME(m_chargenaddr)); + save_item(NAME(m_videoaddr)); + save_item(NAME(m_bitmapaddr)); + + save_item(NAME(m_colors)); + save_item(NAME(m_spritemulti)); + + save_item(NAME(m_rasterline)); + save_item(NAME(m_cycle)); + save_item(NAME(m_raster_x)); + save_item(NAME(m_graphic_x)); + save_item(NAME(m_last_data)); + + save_item(NAME(m_dy_start)); + save_item(NAME(m_dy_stop)); + + save_item(NAME(m_draw_this_line)); + save_item(NAME(m_is_bad_line)); + save_item(NAME(m_bad_lines_enabled)); + save_item(NAME(m_display_state)); + save_item(NAME(m_char_data)); + save_item(NAME(m_gfx_data)); + save_item(NAME(m_color_data)); + save_item(NAME(m_last_char_data)); + save_item(NAME(m_matrix_line)); + save_item(NAME(m_color_line)); + save_item(NAME(m_vblanking)); + save_item(NAME(m_ml_index)); + save_item(NAME(m_rc)); + save_item(NAME(m_vc)); + save_item(NAME(m_vc_base)); + save_item(NAME(m_ref_cnt)); + + save_item(NAME(m_spr_coll_buf)); + save_item(NAME(m_fore_coll_buf)); + save_item(NAME(m_spr_exp_y)); + save_item(NAME(m_spr_dma_on)); + save_item(NAME(m_spr_draw)); + save_item(NAME(m_spr_disp_on)); + save_item(NAME(m_spr_ptr)); + save_item(NAME(m_mc_base)); + save_item(NAME(m_mc)); + + for (int i = 0; i < 8; i++) + { + save_item(NAME(m_spr_data[i]), i); + save_item(NAME(m_spr_draw_data[i]), i); + } + + save_item(NAME(m_border_on)); + save_item(NAME(m_ud_border_on)); + save_item(NAME(m_border_on_sample)); + save_item(NAME(m_border_color_sample)); + + save_item(NAME(m_first_ba_cycle)); + save_item(NAME(m_device_suspended)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void mos6566_device::device_reset() +{ + memset(m_reg, 0, sizeof(m_reg)); + + for (int i = 0; i < ARRAY_LENGTH(m_mc); i++) + m_mc[i] = 63; + + // from 0 to 311 (0 first, PAL) or from 0 to 261 (? first, NTSC 6567R56A) or from 0 to 262 (? first, NTSC 6567R8) + m_rasterline = 0; // VIC2_LINES - 1; + + m_cycle = 14; + m_raster_x = 0x004; + m_graphic_x = 0; + m_last_data = 0; + + m_on = 1; + + m_chargenaddr = m_videoaddr = m_bitmapaddr = 0; + + m_dy_start = ROW24_YSTART; + m_dy_stop = ROW24_YSTOP; + + m_draw_this_line = 0; + m_is_bad_line = 0; + m_bad_lines_enabled = 0; + m_display_state = 0; + m_char_data = 0; + m_gfx_data = 0; + m_color_data = 0; + m_last_char_data = 0; + m_vblanking = 0; + m_ml_index = 0; + m_rc = 0; + m_vc = 0; + m_vc_base = 0; + m_ref_cnt = 0; + + m_spr_exp_y = 0; + m_spr_dma_on = 0; + m_spr_draw = 0; + m_spr_disp_on = 0; + + + m_border_on = 0; + m_ud_border_on = 0; + + m_first_ba_cycle = 0; + m_device_suspended = 0; + + memset(m_matrix_line, 0, sizeof(m_matrix_line)); + memset(m_color_line, 0, sizeof(m_color_line)); + + memset(m_spr_coll_buf, 0, sizeof(m_spr_coll_buf)); + memset(m_fore_coll_buf, 0, sizeof(m_fore_coll_buf)); + memset(m_border_on_sample, 0, sizeof(m_border_on_sample)); + memset(m_border_color_sample, 0, sizeof(m_border_color_sample)); + + for (int i = 0; i < 8; i++) + { + m_spr_ptr[i] = 0; + m_mc_base[i] = 0; + m_mc[i] = 0; + + for (int j = 0; j < 4; j++) + { + m_spr_draw_data[i][j] = 0; + m_spr_data[i][j] = 0; + } + } + + for (int i = 0; i < 4; i++) + { + m_colors[i] = 0; + m_spritemulti[i] = 0; + } + + m_phi0 = 1; + m_ba = CLEAR_LINE; + m_aec = CLEAR_LINE; + m_aec_delay = 0xff; + m_rdy_cycles = 0; + + set_ba(ASSERT_LINE); + set_aec(ASSERT_LINE); +} + + +//------------------------------------------------- +// execute_run - +//------------------------------------------------- + +void mos6566_device::execute_run() +{ + do + { + UINT8 cpu_cycles = m_cpu->total_cycles() & 0xff; + UINT8 vic_cycles = total_cycles() & 0xff; + + m_phi0 = 0; + + m_aec_delay <<= 1; + m_aec_delay |= m_ba; + + set_aec(CLEAR_LINE); + + int i; + UINT8 mask; + + if (m_rasterline == VIC2_FIRST_DMA_LINE) + m_bad_lines_enabled = SCREENON; + + m_is_bad_line = ((m_rasterline >= VIC2_FIRST_DMA_LINE) && (m_rasterline <= VIC2_LAST_DMA_LINE) && + ((m_rasterline & 0x07) == YSCROLL) && m_bad_lines_enabled); + + switch (m_cycle) + { + // Sprite 3, raster counter, raster IRQ, bad line + case 1: + if (m_rasterline == (VIC2_LINES - 1)) + { + m_vblanking = 1; + } + else + { + m_rasterline++; + + m_draw_this_line = ((VIC2_RASTER_2_EMU(m_rasterline) >= VIC2_RASTER_2_EMU(VIC2_FIRST_DISP_LINE)) && + (VIC2_RASTER_2_EMU(m_rasterline ) <= VIC2_RASTER_2_EMU(VIC2_LAST_DISP_LINE))); + } + + m_border_on_sample[0] = m_border_on; + spr_ptr_access(3); + spr_data_access(3, 0); + display_if_bad_line(); + + m_cycle++; + break; + + // Sprite 3 + case 2: + if (m_vblanking) + { + // Vertical blank, reset counters + m_rasterline = m_vc_base = 0; + m_ref_cnt = 0xff; + m_vblanking = 0; + + // Trigger raster IRQ if IRQ in line 0 + if (RASTERLINE == 0) + { + set_interrupt(IRQ_RST); + } + } + + if (m_rasterline == RASTERLINE) + { + set_interrupt(IRQ_RST); + } + + m_graphic_x = VIC2_X_2_EMU(0); + + spr_data_access(3, 1); + spr_data_access(3, 2); + display_if_bad_line(); + + spr_ba(5); + + m_cycle++; + break; + + // Sprite 4 + case 3: + spr_ptr_access(4); + spr_data_access(4, 0); + display_if_bad_line(); + + m_cycle++; + break; + + // Sprite 4 + case 4: + spr_data_access(4, 1); + spr_data_access(4, 2); + display_if_bad_line(); + + spr_ba(6); + + m_cycle++; + break; + + // Sprite 5 + case 5: + spr_ptr_access(5); + spr_data_access(5, 0); + display_if_bad_line(); + + m_cycle++; + break; + + // Sprite 5 + case 6: + spr_data_access(5, 1); + spr_data_access(5, 2); + display_if_bad_line(); + + spr_ba(7); + + m_cycle++; + break; + + // Sprite 6 + case 7: + spr_ptr_access(6); + spr_data_access(6, 0); + display_if_bad_line(); + + m_cycle++; + break; + + // Sprite 6 + case 8: + spr_data_access(6, 1); + spr_data_access(6, 2); + display_if_bad_line(); + + m_cycle++; + break; + + // Sprite 7 + case 9: + spr_ptr_access(7); + spr_data_access(7, 0); + display_if_bad_line(); + + m_cycle++; + break; + + // Sprite 7 + case 10: + spr_data_access(7, 1); + spr_data_access(7, 2); + display_if_bad_line(); + + set_ba(ASSERT_LINE); + + m_cycle++; + break; + + // Refresh + case 11: + refresh_access(); + display_if_bad_line(); + + m_cycle++; + break; + + // Refresh, fetch if bad line + case 12: + bad_line_ba(); + + refresh_access(); + fetch_if_bad_line(); + + m_cycle++; + break; + + // Refresh, fetch if bad line, raster_x + case 13: + bad_line_ba(); + + draw_background(); + sample_border(); + refresh_access(); + fetch_if_bad_line(); + + m_cycle++; + break; + + // Refresh, fetch if bad line, RC, VC + case 14: + bad_line_ba(); + + draw_background(); + sample_border(); + refresh_access(); + rc_if_bad_line(); + + m_vc = m_vc_base; + + m_cycle++; + break; + + // Refresh, fetch if bad line, sprite y expansion + case 15: + bad_line_ba(); + + draw_background(); + sample_border(); + refresh_access(); + fetch_if_bad_line(); + + for (i = 0; i < 8; i++) + if (m_spr_exp_y & (1 << i)) + m_mc_base[i] += 2; + + m_ml_index = 0; + matrix_access(); + + m_cycle++; + break; + + // Graphics, sprite y expansion, sprite DMA + case 16: + bad_line_ba(); + + draw_background(); + sample_border(); + graphics_access(); + fetch_if_bad_line(); + + mask = 1; + for (i = 0; i < 8; i++, mask <<= 1) + { + if (m_spr_exp_y & mask) + m_mc_base[i]++; + if ((m_mc_base[i] & 0x3f) == 0x3f) + m_spr_dma_on &= ~mask; + } + + matrix_access(); + + m_cycle++; + break; + + // Graphics, check border + case 17: + bad_line_ba(); + + if (COLUMNS40) + { + if (m_rasterline == m_dy_stop) + m_ud_border_on = 1; + else + { + if (SCREENON) + { + if (m_rasterline == m_dy_start) + m_border_on = m_ud_border_on = 0; + else + if (m_ud_border_on == 0) + m_border_on = 0; + } + else + if (m_ud_border_on == 0) + m_border_on = 0; + } + } + + // Second sample of border state + m_border_on_sample[1] = m_border_on; + + draw_background(); + draw_graphics(); + sample_border(); + graphics_access(); + fetch_if_bad_line(); + matrix_access(); + + m_cycle++; + break; + + // Check border + case 18: + bad_line_ba(); + + if (!COLUMNS40) + { + if (m_rasterline == m_dy_stop) + m_ud_border_on = 1; + else + { + if (SCREENON) + { + if (m_rasterline == m_dy_start) + m_border_on = m_ud_border_on = 0; + else + if (m_ud_border_on == 0) + m_border_on = 0; + } + else + if (m_ud_border_on == 0) + m_border_on = 0; + } + } + + // Third sample of border state + m_border_on_sample[2] = m_border_on; + + // Graphics + + case 19: + case 20: + case 21: + case 22: + case 23: + case 24: + case 25: + case 26: + case 27: + case 28: + case 29: + case 30: + case 31: + case 32: + case 33: + case 34: + case 35: + case 36: + case 37: + case 38: + case 39: + case 40: + case 41: + case 42: + case 43: + case 44: + case 45: + case 46: + case 47: + case 48: + case 49: + case 50: + case 51: + case 52: + case 53: + case 54: + draw_graphics(); + sample_border(); + graphics_access(); + fetch_if_bad_line(); + matrix_access(); + m_last_char_data = m_char_data; + + m_cycle++; + break; + + // Graphics, sprite y expansion, sprite DMA + case 55: + if (m_is_bad_line) + set_ba(ASSERT_LINE); + + draw_graphics(); + sample_border(); + graphics_access(); + display_if_bad_line(); + + // sprite y expansion + mask = 1; + for (i = 0; i < 8; i++, mask <<= 1) + if (SPRITE_Y_EXPAND (i)) + m_spr_exp_y ^= mask; + + check_sprite_dma(); + + m_cycle++; + break; + + // Check border, sprite DMA + case 56: + if (!COLUMNS40) + m_border_on = 1; + + // Fourth sample of border state + m_border_on_sample[3] = m_border_on; + + draw_graphics(); + sample_border(); + idle_access(); + display_if_bad_line(); + check_sprite_dma(); + + m_cycle++; + break; + + // Check border, sprites + case 57: + if (COLUMNS40) + m_border_on = 1; + + // Fifth sample of border state + m_border_on_sample[4] = m_border_on; + + // Sample spr_disp_on and spr_data for sprite drawing + m_spr_draw = m_spr_disp_on; + if (m_spr_draw) + memcpy(m_spr_draw_data, m_spr_data, 8 * 4); + + mask = 1; + for (i = 0; i < 8; i++, mask <<= 1) + if ((m_spr_disp_on & mask) && !(m_spr_dma_on & mask)) + m_spr_disp_on &= ~mask; + + draw_background(); + sample_border(); + idle_access(); + display_if_bad_line(); + + spr_ba(0); + + m_cycle++; + break; + + // for NTSC 6567R8 + case 58: + draw_background(); + sample_border(); + idle_access(); + display_if_bad_line(); + + m_cycle++; + break; + + // for NTSC 6567R8 + case 59: + draw_background(); + sample_border(); + idle_access(); + display_if_bad_line(); + + spr_ba(1); + + m_cycle++; + break; + + // Sprite 0, sprite DMA, MC, RC + case 60: + draw_background(); + sample_border(); + + mask = 1; + for (i = 0; i < 8; i++, mask <<= 1) + { + m_mc[i] = m_mc_base[i]; + if ((m_spr_dma_on & mask) && ((m_rasterline & 0xff) == SPRITE_Y_POS(i))) + m_spr_disp_on |= mask; + } + + spr_ptr_access(0); + spr_data_access(0, 0); + + if (m_rc == 7) + { + m_vc_base = m_vc; + m_display_state = 0; + } + + if (m_is_bad_line || m_display_state) + { + m_display_state = 1; + m_rc = (m_rc + 1) & 7; + } + + m_cycle++; + break; + + // Sprite 0 + case 61: + draw_background(); + sample_border(); + spr_data_access(0, 1); + spr_data_access(0, 2); + display_if_bad_line(); + + spr_ba(2); + + m_cycle++; + break; + + // Sprite 1, draw + case 62: + draw_background(); + sample_border(); + + if (m_draw_this_line) + { + draw_sprites(); + + if (m_border_on_sample[0]) + for (i = 0; i < 4; i++) + m_bitmap.plot_box(VIC2_X_2_EMU(i * 8), VIC2_RASTER_2_EMU(m_rasterline), 8, 1, PALETTE_MOS[m_border_color_sample[i]]); + + if (m_border_on_sample[1]) + m_bitmap.plot_box(VIC2_X_2_EMU(4 * 8), VIC2_RASTER_2_EMU(m_rasterline), 8, 1, PALETTE_MOS[m_border_color_sample[4]]); + + if (m_border_on_sample[2]) + for (i = 5; i < 43; i++) + m_bitmap.plot_box(VIC2_X_2_EMU(i * 8), VIC2_RASTER_2_EMU(m_rasterline), 8, 1, PALETTE_MOS[m_border_color_sample[i]]); + + if (m_border_on_sample[3]) + m_bitmap.plot_box(VIC2_X_2_EMU(43 * 8), VIC2_RASTER_2_EMU(m_rasterline), 8, 1, PALETTE_MOS[m_border_color_sample[43]]); + + if (m_border_on_sample[4]) + { + for (i = 44; i < 48; i++) + m_bitmap.plot_box(VIC2_X_2_EMU(i * 8), VIC2_RASTER_2_EMU(m_rasterline), 8, 1, PALETTE_MOS[m_border_color_sample[i]]); + for (i = 48; i < 53; i++) + m_bitmap.plot_box(VIC2_X_2_EMU(i * 8), VIC2_RASTER_2_EMU(m_rasterline), 8, 1, PALETTE_MOS[m_border_color_sample[47]]); + } + } + + spr_ptr_access(1); + spr_data_access(1, 0); + display_if_bad_line(); + + m_cycle++; + break; + + // Sprite 1 + case 63: + spr_data_access(1, 1); + spr_data_access(1, 2); + display_if_bad_line(); + + spr_ba(3); + + m_cycle++; + break; + + // Sprite 2 + case 64: + spr_ptr_access(2); + spr_data_access(2, 0); + display_if_bad_line(); + + m_cycle++; + break; + + // Sprite 2 + case 65: + spr_data_access(2, 1); + spr_data_access(2, 2); + display_if_bad_line(); + + if (m_rasterline == m_dy_stop) + m_ud_border_on = 1; + else + if (SCREENON && (m_rasterline == m_dy_start)) + m_ud_border_on = 0; + + spr_ba(4); + + // Last cycle + m_cycle = 1; + } + + m_phi0 = 1; + set_aec(BIT(m_aec_delay, 2)); + + m_write_ba(m_ba); + m_write_aec(m_aec); + + m_raster_x += 8; + if (m_raster_x == 0x1fc) m_raster_x = 0x004; + + if ((cpu_cycles == vic_cycles) && (m_rdy_cycles > 0)) + { + m_cpu->spin_until_time(m_cpu->cycles_to_attotime(m_rdy_cycles)); + m_rdy_cycles = 0; + } + + m_icount--; + } while (m_icount > 0); +} + + +//------------------------------------------------- +// execute_run - +//------------------------------------------------- + +void mos6569_device::execute_run() +{ + do + { + UINT8 cpu_cycles = m_cpu->total_cycles() & 0xff; + UINT8 vic_cycles = total_cycles() & 0xff; + + m_phi0 = 0; + + m_aec_delay <<= 1; + m_aec_delay |= m_ba; + + set_aec(CLEAR_LINE); + + int i; + UINT8 mask; + + if ((m_rasterline == VIC2_FIRST_DMA_LINE) && !m_bad_lines_enabled) + m_bad_lines_enabled = SCREENON; + + m_is_bad_line = ((m_rasterline >= VIC2_FIRST_DMA_LINE) && (m_rasterline <= VIC2_LAST_DMA_LINE) && + ((m_rasterline & 0x07) == YSCROLL) && m_bad_lines_enabled); + + switch (m_cycle) + { + // Sprite 3, raster counter, raster IRQ, bad line + case 1: + if (m_rasterline == (VIC2_LINES - 1)) + { + m_vblanking = 1; + } + else + { + m_rasterline++; + + m_draw_this_line = ((VIC2_RASTER_2_EMU(m_rasterline) >= VIC2_RASTER_2_EMU(VIC2_FIRST_DISP_LINE)) && + (VIC2_RASTER_2_EMU(m_rasterline ) <= VIC2_RASTER_2_EMU(VIC2_LAST_DISP_LINE))); + } + + m_border_on_sample[0] = m_border_on; + spr_ptr_access(3); + spr_data_access(3, 0); + display_if_bad_line(); + + m_cycle++; + break; + + // Sprite 3 + case 2: + spr_ba(5); + + if (m_vblanking) + { + // Vertical blank, reset counters + m_rasterline = m_vc_base = 0; + m_ref_cnt = 0xff; + m_vblanking = 0; + + // Trigger raster IRQ if IRQ in line 0 + if (RASTERLINE == 0) + { + set_interrupt(IRQ_RST); + } + } + + if (m_rasterline == RASTERLINE) + { + set_interrupt(IRQ_RST); + } + + m_graphic_x = VIC2_X_2_EMU(0); + + spr_data_access(3, 1); + spr_data_access(3, 2); + display_if_bad_line(); + + m_cycle++; + break; + + // Sprite 4 + case 3: + spr_ptr_access(4); + spr_data_access(4, 0); + display_if_bad_line(); + + m_cycle++; + break; + + // Sprite 4 + case 4: + spr_ba(6); + + spr_data_access(4, 1); + spr_data_access(4, 2); + display_if_bad_line(); + + m_cycle++; + break; + + // Sprite 5 + case 5: + spr_ptr_access(5); + spr_data_access(5, 0); + display_if_bad_line(); + + m_cycle++; + break; + + // Sprite 5 + case 6: + spr_ba(7); + + spr_data_access(5, 1); + spr_data_access(5, 2); + display_if_bad_line(); + + m_cycle++; + break; + + // Sprite 6 + case 7: + spr_ptr_access(6); + spr_data_access(6, 0); + display_if_bad_line(); + + m_cycle++; + break; + + // Sprite 6 + case 8: + spr_data_access(6, 1); + spr_data_access(6, 2); + display_if_bad_line(); + + m_cycle++; + break; + + // Sprite 7 + case 9: + spr_ptr_access(7); + spr_data_access(7, 0); + display_if_bad_line(); + + m_cycle++; + break; + + // Sprite 7 + case 10: + spr_data_access(7, 1); + spr_data_access(7, 2); + display_if_bad_line(); + + set_ba(ASSERT_LINE); + + m_cycle++; + break; + + // Refresh + case 11: + refresh_access(); + display_if_bad_line(); + + m_cycle++; + break; + + // Refresh, fetch if bad line + case 12: + bad_line_ba(); + + refresh_access(); + fetch_if_bad_line(); + + m_cycle++; + break; + + // Refresh, fetch if bad line, raster_x + case 13: + bad_line_ba(); + + draw_background(); + sample_border(); + refresh_access(); + fetch_if_bad_line(); + + m_cycle++; + break; + + // Refresh, fetch if bad line, RC, VC + case 14: + bad_line_ba(); + + draw_background(); + sample_border(); + refresh_access(); + rc_if_bad_line(); + + m_vc = m_vc_base; + + m_cycle++; + break; + + // Refresh, fetch if bad line, sprite y expansion + case 15: + bad_line_ba(); + + draw_background(); + sample_border(); + refresh_access(); + fetch_if_bad_line(); + + for (i = 0; i < 8; i++) + if (m_spr_exp_y & (1 << i)) + m_mc_base[i] += 2; + + m_ml_index = 0; + + matrix_access(); + + m_cycle++; + break; + + // Graphics, sprite y expansion, sprite DMA + case 16: + bad_line_ba(); + + draw_background(); + sample_border(); + graphics_access(); + fetch_if_bad_line(); + + mask = 1; + for (i = 0; i < 8; i++, mask <<= 1) + { + if (m_spr_exp_y & (1 << i)) + m_mc_base[i]++; + if ((m_mc_base[i] & 0x3f) == 0x3f) + m_spr_dma_on &= ~mask; + } + + matrix_access(); + + m_cycle++; + break; + + // Graphics, check border + case 17: + bad_line_ba(); + + if (COLUMNS40) + { + if (m_rasterline == m_dy_stop) + m_ud_border_on = 1; + else + { + if (SCREENON) + { + if (m_rasterline == m_dy_start) + m_border_on = m_ud_border_on = 0; + else + if (m_ud_border_on == 0) + m_border_on = 0; + } else + if (m_ud_border_on == 0) + m_border_on = 0; + } + } + + // Second sample of border state + m_border_on_sample[1] = m_border_on; + + draw_background(); + draw_graphics(); + sample_border(); + graphics_access(); + fetch_if_bad_line(); + matrix_access(); + + m_cycle++; + break; + + // Check border + case 18: + bad_line_ba(); + + if (!COLUMNS40) + { + if (m_rasterline == m_dy_stop) + m_ud_border_on = 1; + else + { + if (SCREENON) + { + if (m_rasterline == m_dy_start) + m_border_on = m_ud_border_on = 0; + else + if (m_ud_border_on == 0) + m_border_on = 0; + } else + if (m_ud_border_on == 0) + m_border_on = 0; + } + } + + // Third sample of border state + m_border_on_sample[2] = m_border_on; + + // Graphics + + case 19: + case 20: + case 21: + case 22: + case 23: + case 24: + case 25: + case 26: + case 27: + case 28: + case 29: + case 30: + case 31: + case 32: + case 33: + case 34: + case 35: + case 36: + case 37: + case 38: + case 39: + case 40: + case 41: + case 42: + case 43: + case 44: + case 45: + case 46: + case 47: + case 48: + case 49: + case 50: + case 51: + case 52: + case 53: + case 54: + bad_line_ba(); + + draw_graphics(); + sample_border(); + graphics_access(); + fetch_if_bad_line(); + matrix_access(); + m_last_char_data = m_char_data; + + m_cycle++; + break; + + // Graphics, sprite y expansion, sprite DMA + case 55: + if (m_is_bad_line) + set_ba(ASSERT_LINE); + + draw_graphics(); + sample_border(); + graphics_access(); + display_if_bad_line(); + + // sprite y expansion + mask = 1; + for (i = 0; i < 8; i++, mask <<= 1) + if (SPRITE_Y_EXPAND (i)) + m_spr_exp_y ^= mask; + + check_sprite_dma(); + + spr_ba(0); + + m_cycle++; + break; + + // Check border, sprite DMA + case 56: + if (!COLUMNS40) + m_border_on = 1; + + // Fourth sample of border state + m_border_on_sample[3] = m_border_on; + + draw_graphics(); + sample_border(); + idle_access(); + display_if_bad_line(); + check_sprite_dma(); + + m_cycle++; + break; + + // Check border, sprites + case 57: + spr_ba(1); + + if (COLUMNS40) + m_border_on = 1; + + // Fifth sample of border state + m_border_on_sample[4] = m_border_on; + + // Sample spr_disp_on and spr_data for sprite drawing + m_spr_draw = m_spr_disp_on; + if (m_spr_draw) + memcpy(m_spr_draw_data, m_spr_data, 8 * 4); + + mask = 1; + for (i = 0; i < 8; i++, mask <<= 1) + if ((m_spr_disp_on & mask) && !(m_spr_dma_on & mask)) + m_spr_disp_on &= ~mask; + + draw_background(); + sample_border(); + idle_access(); + display_if_bad_line(); + + m_cycle++; + break; + + // Sprite 0, sprite DMA, MC, RC + case 58: + draw_background(); + sample_border(); + + mask = 1; + for (i = 0; i < 8; i++, mask <<= 1) + { + m_mc[i] = m_mc_base[i]; + if ((m_spr_dma_on & mask) && ((m_rasterline & 0xff) == SPRITE_Y_POS(i))) + m_spr_disp_on |= mask; + } + + spr_ptr_access(0); + spr_data_access(0, 0); + + if (m_rc == 7) + { + m_vc_base = m_vc; + m_display_state = 0; + } + + if (m_is_bad_line || m_display_state) + { + m_display_state = 1; + m_rc = (m_rc + 1) & 7; + } + + m_cycle++; + break; + + // Sprite 0 + case 59: + spr_ba(2); + + draw_background(); + sample_border(); + spr_data_access(0, 1); + spr_data_access(0, 2); + display_if_bad_line(); + + m_cycle++; + break; + + // Sprite 1, draw + case 60: + draw_background(); + sample_border(); + + if (m_draw_this_line) + { + draw_sprites(); + + if (m_border_on_sample[0]) + for (i = 0; i < 4; i++) + m_bitmap.plot_box(VIC2_X_2_EMU(i * 8), VIC2_RASTER_2_EMU(m_rasterline), 8, 1, PALETTE_MOS[m_border_color_sample[i]]); + + if (m_border_on_sample[1]) + m_bitmap.plot_box(VIC2_X_2_EMU(4 * 8), VIC2_RASTER_2_EMU(m_rasterline), 8, 1, PALETTE_MOS[m_border_color_sample[4]]); + + if (m_border_on_sample[2]) + for (i = 5; i < 43; i++) + m_bitmap.plot_box(VIC2_X_2_EMU(i * 8), VIC2_RASTER_2_EMU(m_rasterline), 8, 1, PALETTE_MOS[m_border_color_sample[i]]); + + if (m_border_on_sample[3]) + m_bitmap.plot_box(VIC2_X_2_EMU(43 * 8), VIC2_RASTER_2_EMU(m_rasterline), 8, 1, PALETTE_MOS[m_border_color_sample[43]]); + + if (m_border_on_sample[4]) + { + for (i = 44; i < 48; i++) + m_bitmap.plot_box(VIC2_X_2_EMU(i * 8), VIC2_RASTER_2_EMU(m_rasterline), 8, 1, PALETTE_MOS[m_border_color_sample[i]]); + for (i = 48; i < 51; i++) + m_bitmap.plot_box(VIC2_X_2_EMU(i * 8), VIC2_RASTER_2_EMU(m_rasterline), 8, 1, PALETTE_MOS[m_border_color_sample[47]]); + } + } + + spr_ptr_access(1); + spr_data_access(1, 0); + display_if_bad_line(); + + m_cycle++; + break; + + // Sprite 1 + case 61: + spr_ba(3); + + spr_data_access(1, 1); + spr_data_access(1, 2); + display_if_bad_line(); + + m_cycle++; + break; + + // Sprite 2 + case 62: + spr_ptr_access(2); + spr_data_access(2, 0); + display_if_bad_line(); + + m_cycle++; + break; + + // Sprite 2 + case 63: + spr_ba(4); + + spr_data_access(2, 1); + spr_data_access(2, 2); + display_if_bad_line(); + + if (m_rasterline == m_dy_stop) + m_ud_border_on = 1; + else + if (SCREENON && (m_rasterline == m_dy_start)) + m_ud_border_on = 0; + + // Last cycle + m_cycle = 1; + } + + m_phi0 = 1; + set_aec(BIT(m_aec_delay, 2)); + + m_write_ba(m_ba); + m_write_aec(m_aec); + + m_raster_x += 8; + if (m_raster_x == 0x1fc) m_raster_x = 0x004; + + if ((cpu_cycles == vic_cycles) && (m_rdy_cycles > 0)) + { + m_cpu->spin_until_time(m_cpu->cycles_to_attotime(m_rdy_cycles)); + m_rdy_cycles = 0; + } + + m_icount--; + } while (m_icount > 0); +} + +// Graphics display (8 pixels) +void mos6566_device::draw_graphics() +{ + if (m_draw_this_line == 0) + { + UINT16 p = m_graphic_x + XSCROLL; + m_fore_coll_buf[p + 7] = 0; + m_fore_coll_buf[p + 6] = 0; + m_fore_coll_buf[p + 5] = 0; + m_fore_coll_buf[p + 4] = 0; + m_fore_coll_buf[p + 3] = 0; + m_fore_coll_buf[p + 2] = 0; + m_fore_coll_buf[p + 1] = 0; + m_fore_coll_buf[p + 0] = 0; + } + else if (m_ud_border_on) + { + UINT16 p = m_graphic_x + XSCROLL; + m_fore_coll_buf[p + 7] = 0; + m_fore_coll_buf[p + 6] = 0; + m_fore_coll_buf[p + 5] = 0; + m_fore_coll_buf[p + 4] = 0; + m_fore_coll_buf[p + 3] = 0; + m_fore_coll_buf[p + 2] = 0; + m_fore_coll_buf[p + 1] = 0; + m_fore_coll_buf[p + 0] = 0; + draw_background(); + } + else + { + UINT8 tmp_col; + UINT16 p = m_graphic_x + XSCROLL; + switch (GFXMODE) + { + case 0: + draw_mono(p, m_colors[0], m_color_data & 0x0f); + break; + case 1: + if (m_color_data & 0x08) + draw_multi(p, m_colors[0], m_colors[1], m_colors[2], m_color_data & 0x07); + else + draw_mono(p, m_colors[0], m_color_data & 0x0f); + break; + case 2: + draw_mono(p, m_char_data & 0x0f, m_char_data >> 4); + break; + case 3: + draw_multi(p, m_colors[0], m_char_data >> 4, m_char_data & 0x0f, m_color_data & 0x0f); + break; + case 4: + if (m_char_data & 0x80) + if (m_char_data & 0x40) + tmp_col = m_colors[3]; + else + tmp_col = m_colors[2]; + else + if (m_char_data & 0x40) + tmp_col = m_colors[1]; + else + tmp_col = m_colors[0]; + draw_mono(p, tmp_col, m_color_data & 0x0f); + break; + case 5: + m_bitmap.pix32(VIC2_RASTER_2_EMU(m_rasterline), p + 7) = PALETTE_MOS[0]; + m_fore_coll_buf[p + 7] = 0; + m_bitmap.pix32(VIC2_RASTER_2_EMU(m_rasterline), p + 6) = PALETTE_MOS[0]; + m_fore_coll_buf[p + 6] = 0; + m_bitmap.pix32(VIC2_RASTER_2_EMU(m_rasterline), p + 5) = PALETTE_MOS[0]; + m_fore_coll_buf[p + 5] = 0; + m_bitmap.pix32(VIC2_RASTER_2_EMU(m_rasterline), p + 4) = PALETTE_MOS[0]; + m_fore_coll_buf[p + 4] = 0; + m_bitmap.pix32(VIC2_RASTER_2_EMU(m_rasterline), p + 3) = PALETTE_MOS[0]; + m_fore_coll_buf[p + 3] = 0; + m_bitmap.pix32(VIC2_RASTER_2_EMU(m_rasterline), p + 2) = PALETTE_MOS[0]; + m_fore_coll_buf[p + 2] = 0; + m_bitmap.pix32(VIC2_RASTER_2_EMU(m_rasterline), p + 1) = PALETTE_MOS[0]; + m_fore_coll_buf[p + 1] = 0; + m_bitmap.pix32(VIC2_RASTER_2_EMU(m_rasterline), p + 0) = PALETTE_MOS[0]; + m_fore_coll_buf[p + 0] = 0; + break; + case 6: + m_bitmap.pix32(VIC2_RASTER_2_EMU(m_rasterline), p + 7) = PALETTE_MOS[0]; + m_fore_coll_buf[p + 7] = 0; + m_bitmap.pix32(VIC2_RASTER_2_EMU(m_rasterline), p + 6) = PALETTE_MOS[0]; + m_fore_coll_buf[p + 6] = 0; + m_bitmap.pix32(VIC2_RASTER_2_EMU(m_rasterline), p + 5) = PALETTE_MOS[0]; + m_fore_coll_buf[p + 5] = 0; + m_bitmap.pix32(VIC2_RASTER_2_EMU(m_rasterline), p + 4) = PALETTE_MOS[0]; + m_fore_coll_buf[p + 4] = 0; + m_bitmap.pix32(VIC2_RASTER_2_EMU(m_rasterline), p + 3) = PALETTE_MOS[0]; + m_fore_coll_buf[p + 3] = 0; + m_bitmap.pix32(VIC2_RASTER_2_EMU(m_rasterline), p + 2) = PALETTE_MOS[0]; + m_fore_coll_buf[p + 2] = 0; + m_bitmap.pix32(VIC2_RASTER_2_EMU(m_rasterline), p + 1) = PALETTE_MOS[0]; + m_fore_coll_buf[p + 1] = 0; + m_bitmap.pix32(VIC2_RASTER_2_EMU(m_rasterline), p + 0) = PALETTE_MOS[0]; + m_fore_coll_buf[p + 0] = 0; + break; + case 7: + m_bitmap.pix32(VIC2_RASTER_2_EMU(m_rasterline), p + 7) = PALETTE_MOS[0]; + m_fore_coll_buf[p + 7] = 0; + m_bitmap.pix32(VIC2_RASTER_2_EMU(m_rasterline), p + 6) = PALETTE_MOS[0]; + m_fore_coll_buf[p + 6] = 0; + m_bitmap.pix32(VIC2_RASTER_2_EMU(m_rasterline), p + 5) = PALETTE_MOS[0]; + m_fore_coll_buf[p + 5] = 0; + m_bitmap.pix32(VIC2_RASTER_2_EMU(m_rasterline), p + 4) = PALETTE_MOS[0]; + m_fore_coll_buf[p + 4] = 0; + m_bitmap.pix32(VIC2_RASTER_2_EMU(m_rasterline), p + 3) = PALETTE_MOS[0]; + m_fore_coll_buf[p + 3] = 0; + m_bitmap.pix32(VIC2_RASTER_2_EMU(m_rasterline), p + 2) = PALETTE_MOS[0]; + m_fore_coll_buf[p + 2] = 0; + m_bitmap.pix32(VIC2_RASTER_2_EMU(m_rasterline), p + 1) = PALETTE_MOS[0]; + m_fore_coll_buf[p + 1] = 0; + m_bitmap.pix32(VIC2_RASTER_2_EMU(m_rasterline), p + 0) = PALETTE_MOS[0]; + m_fore_coll_buf[p + 0] = 0; + break; + } + } +} + +void mos6566_device::draw_sprites() +{ + int i; + UINT8 snum, sbit; + UINT8 spr_coll = 0, gfx_coll = 0; + UINT32 plane0_l, plane0_r, plane1_l, plane1_r; + UINT32 sdata_l = 0, sdata_r = 0; + + for (i = 0; i < 0x400; i++) + m_spr_coll_buf[i] = 0; + + for (snum = 0, sbit = 1; snum < 8; snum++, sbit <<= 1) + { + if ((m_spr_draw & sbit) && (SPRITE_X_POS(snum) <= (403 - (VIC2_FIRSTCOLUMN + 1)))) + { + UINT16 p = SPRITE_X_POS(snum) + VIC2_X_2_EMU(0) + 8; + UINT8 color = SPRITE_COLOR(snum); + UINT32 sdata = (m_spr_draw_data[snum][0] << 24) | (m_spr_draw_data[snum][1] << 16) | (m_spr_draw_data[snum][2] << 8); + + if (SPRITE_X_EXPAND(snum)) + { + if (SPRITE_X_POS(snum) > (403 - 24 - (VIC2_FIRSTCOLUMN + 1))) + continue; + + if (SPRITE_MULTICOLOR(snum)) + { + sdata_l = (m_expandx_multi[(sdata >> 24) & 0xff] << 16) | m_expandx_multi[(sdata >> 16) & 0xff]; + sdata_r = m_expandx_multi[(sdata >> 8) & 0xff] << 16; + plane0_l = (sdata_l & 0x55555555) | (sdata_l & 0x55555555) << 1; + plane1_l = (sdata_l & 0xaaaaaaaa) | (sdata_l & 0xaaaaaaaa) >> 1; + plane0_r = (sdata_r & 0x55555555) | (sdata_r & 0x55555555) << 1; + plane1_r = (sdata_r & 0xaaaaaaaa) | (sdata_r & 0xaaaaaaaa) >> 1; + for (i = 0; i < 32; i++, plane0_l <<= 1, plane1_l <<= 1) + { + UINT8 col; + + if (plane1_l & 0x80000000) + { + if (m_fore_coll_buf[p + i]) + { + gfx_coll |= sbit; + } + if (plane0_l & 0x80000000) + col = m_spritemulti[3]; + else + col = color; + } + else + { + if (plane0_l & 0x80000000) + { + if (m_fore_coll_buf[p + i]) + { + gfx_coll |= sbit; + } + col = m_spritemulti[1]; + } + else + continue; + } + + if (m_spr_coll_buf[p + i]) + spr_coll |= m_spr_coll_buf[p + i] | sbit; + else + { + if (SPRITE_PRIORITY(snum)) + { + if (m_fore_coll_buf[p + i] == 0) + m_bitmap.pix32(VIC2_RASTER_2_EMU(m_rasterline), p + i) = PALETTE_MOS[col]; + m_spr_coll_buf[p + i] = sbit; + } + else + { + m_bitmap.pix32(VIC2_RASTER_2_EMU(m_rasterline), p + i) = PALETTE_MOS[col]; + m_spr_coll_buf[p + i] = sbit; + } + } + } + + for (; i < 48; i++, plane0_r <<= 1, plane1_r <<= 1) + { + UINT8 col; + + if(plane1_r & 0x80000000) + { + if (m_fore_coll_buf[p + i]) + { + gfx_coll |= sbit; + } + + if (plane0_r & 0x80000000) + col = m_spritemulti[3]; + else + col = color; + } + else + { + if (plane0_r & 0x80000000) + { + if (m_fore_coll_buf[p + i]) + { + gfx_coll |= sbit; + } + col = m_spritemulti[1]; + } + else + continue; + } + + if (m_spr_coll_buf[p + i]) + spr_coll |= m_spr_coll_buf[p + i] | sbit; + else + { + if (SPRITE_PRIORITY(snum)) + { + if (m_fore_coll_buf[p + i] == 0) + m_bitmap.pix32(VIC2_RASTER_2_EMU(m_rasterline), p + i) = PALETTE_MOS[col]; + m_spr_coll_buf[p + i] = sbit; + } + else + { + m_bitmap.pix32(VIC2_RASTER_2_EMU(m_rasterline), p + i) = PALETTE_MOS[col]; + m_spr_coll_buf[p + i] = sbit; + } + } + } + } + else + { + sdata_l = (m_expandx[(sdata >> 24) & 0xff] << 16) | m_expandx[(sdata >> 16) & 0xff]; + sdata_r = m_expandx[(sdata >> 8) & 0xff] << 16; + + for (i = 0; i < 32; i++, sdata_l <<= 1) + if (sdata_l & 0x80000000) + { + if (m_fore_coll_buf[p + i]) + { + gfx_coll |= sbit; + } + + if (m_spr_coll_buf[p + i]) + spr_coll |= m_spr_coll_buf[p + i] | sbit; + else + { + if (SPRITE_PRIORITY(snum)) + { + if (m_fore_coll_buf[p + i] == 0) + m_bitmap.pix32(VIC2_RASTER_2_EMU(m_rasterline), p + i) = PALETTE_MOS[color]; + m_spr_coll_buf[p + i] = sbit; + } + else + { + m_bitmap.pix32(VIC2_RASTER_2_EMU(m_rasterline), p + i) = PALETTE_MOS[color]; + m_spr_coll_buf[p + i] = sbit; + } + } + } + + for (; i < 48; i++, sdata_r <<= 1) + if (sdata_r & 0x80000000) + { + if (m_fore_coll_buf[p + i]) + { + gfx_coll |= sbit; + } + + if (m_spr_coll_buf[p + i]) + spr_coll |= m_spr_coll_buf[p + i] | sbit; + else + { + if (SPRITE_PRIORITY(snum)) + { + if (m_fore_coll_buf[p + i] == 0) + m_bitmap.pix32(VIC2_RASTER_2_EMU(m_rasterline), p + i) = PALETTE_MOS[color]; + m_spr_coll_buf[p + i] = sbit; + } + else + { + m_bitmap.pix32(VIC2_RASTER_2_EMU(m_rasterline), p + i) = PALETTE_MOS[color]; + m_spr_coll_buf[p + i] = sbit; + } + } + } + } + } + else + { + if (SPRITE_MULTICOLOR(snum)) + { + UINT32 plane0 = (sdata & 0x55555555) | (sdata & 0x55555555) << 1; + UINT32 plane1 = (sdata & 0xaaaaaaaa) | (sdata & 0xaaaaaaaa) >> 1; + + for (i = 0; i < 24; i++, plane0 <<= 1, plane1 <<= 1) + { + UINT8 col; + + if (plane1 & 0x80000000) + { + if (m_fore_coll_buf[p + i]) + { + gfx_coll |= sbit; + } + + if (plane0 & 0x80000000) + col = m_spritemulti[3]; + else + col = color; + } + else + { + if (m_fore_coll_buf[p + i]) + { + gfx_coll |= sbit; + } + + if (plane0 & 0x80000000) + col = m_spritemulti[1]; + else + continue; + } + + if (m_spr_coll_buf[p + i]) + spr_coll |= m_spr_coll_buf[p + i] | sbit; + else + { + if (SPRITE_PRIORITY(snum)) + { + if (m_fore_coll_buf[p + i] == 0) + m_bitmap.pix32(VIC2_RASTER_2_EMU(m_rasterline), p + i) = PALETTE_MOS[col]; + m_spr_coll_buf[p + i] = sbit; + } + else + { + m_bitmap.pix32(VIC2_RASTER_2_EMU(m_rasterline), p + i) = PALETTE_MOS[col]; + m_spr_coll_buf[p + i] = sbit; + } + } + } + } + else + { + for (i = 0; i < 24; i++, sdata <<= 1) + { + if (sdata & 0x80000000) + { + if (m_fore_coll_buf[p + i]) + { + gfx_coll |= sbit; + } + if (m_spr_coll_buf[p + i]) + { + spr_coll |= m_spr_coll_buf[p + i] | sbit; + } + else + { + if (SPRITE_PRIORITY(snum)) + { + if (m_fore_coll_buf[p + i] == 0) + m_bitmap.pix32(VIC2_RASTER_2_EMU(m_rasterline), p + i) = PALETTE_MOS[color]; + m_spr_coll_buf[p + i] = sbit; + } + else + { + m_bitmap.pix32(VIC2_RASTER_2_EMU(m_rasterline), p + i) = PALETTE_MOS[color]; + m_spr_coll_buf[p + i] = sbit; + } + } + } + } + } + } + } + } + + if (SPRITE_COLL) + SPRITE_COLL |= spr_coll; + else + { + SPRITE_COLL = spr_coll; + if (SPRITE_COLL) + set_interrupt(IRQ_MMC); + } + + if (SPRITE_BG_COLL) + SPRITE_BG_COLL |= gfx_coll; + else + { + SPRITE_BG_COLL = gfx_coll; + if (SPRITE_BG_COLL) + set_interrupt(IRQ_MBC); + } +} + + +//------------------------------------------------- +// screen_update - +//------------------------------------------------- + +UINT32 mos6566_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + bitmap.fill(PALETTE_MOS[0], cliprect); + + if (m_on) + copybitmap(bitmap, m_bitmap, 0, 0, 0, 0, cliprect); + + return 0; +} + + +//------------------------------------------------- +// read - +//------------------------------------------------- + +READ8_MEMBER( mos6566_device::read ) +{ + UINT8 val = 0; + + offset &= 0x3f; + + switch (offset) + { + case 0x11: + val = (m_reg[offset] & ~0x80) | ((m_rasterline & 0x100) >> 1); + val |= UNUSED_BITS[offset]; + break; + + case 0x12: + val = m_rasterline & 0xff; + val |= UNUSED_BITS[offset]; + break; + + case 0x16: + val = m_reg[offset] | 0xc0; + val |= UNUSED_BITS[offset]; + break; + + case 0x18: + val = m_reg[offset] | 0x01; + val |= UNUSED_BITS[offset]; + break; + + case 0x19: /* interrupt flag register */ + /* clear_interrupt(0xf); */ + val = m_reg[offset] | 0x70; + val |= UNUSED_BITS[offset]; + break; + + case 0x1a: + val = m_reg[offset] | 0xf0; + val |= UNUSED_BITS[offset]; + break; + + case 0x1e: /* sprite to sprite collision detect */ + val = m_reg[offset]; + m_reg[offset] = 0; + clear_interrupt(4); + val |= UNUSED_BITS[offset]; + break; + + case 0x1f: /* sprite to background collision detect */ + val = m_reg[offset]; + m_reg[offset] = 0; + clear_interrupt(2); + val |= UNUSED_BITS[offset]; + break; + + case 0x20: + case 0x21: + case 0x22: + case 0x23: + case 0x24: + val = m_reg[offset]; + val |= UNUSED_BITS[offset]; + break; + + case 0x00: + case 0x01: + case 0x02: + case 0x03: + case 0x04: + case 0x05: + case 0x06: + case 0x07: + case 0x08: + case 0x09: + case 0x0a: + case 0x0b: + case 0x0c: + case 0x0d: + case 0x0e: + case 0x0f: + case 0x10: + case 0x17: + case 0x1b: + case 0x1c: + case 0x1d: + case 0x25: + case 0x26: + case 0x27: + case 0x28: + case 0x29: + case 0x2a: + case 0x2b: + case 0x2c: + case 0x2d: + case 0x2e: + val = m_reg[offset]; + val |= UNUSED_BITS[offset]; + break; + + case REGISTER_KCR: + case REGISTER_FAST: + if (IS_VICIIE) + { + val = m_reg[offset]; + DBG_LOG(2, "vic read", ("%.2x:%.2x\n", offset, val)); + } + else + { + val |= UNUSED_BITS[offset]; + } + break; + + 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: /* not used */ + DBG_LOG(2, "vic read", ("%.2x:%.2x\n", offset, val)); + val |= UNUSED_BITS[offset]; + break; + + default: + val = m_reg[offset]; + val |= UNUSED_BITS[offset]; + } + + if ((offset != 0x11) && (offset != 0x12)) + DBG_LOG(2, "vic read", ("%.2x:%.2x\n", offset, val)); + + return val; +} + + +//------------------------------------------------- +// write - +//------------------------------------------------- + +WRITE8_MEMBER( mos6566_device::write ) +{ + DBG_LOG(2, "vic write", ("%.2x:%.2x\n", offset, data)); + offset &= 0x3f; + + switch (offset) + { + case 0x01: + case 0x03: + case 0x05: + case 0x07: + case 0x09: + case 0x0b: + case 0x0d: + case 0x0f: + m_reg[offset] = data; /* sprite y positions */ + break; + + case 0x00: + case 0x02: + case 0x04: + case 0x06: + case 0x08: + case 0x0a: + case 0x0c: + case 0x0e: + m_reg[offset] = data; /* sprite x positions */ + break; + + case 0x10: + m_reg[offset] = data; /* sprite x positions */ + break; + + case 0x17: /* sprite y size */ + m_spr_exp_y |= ~data; + if (m_reg[offset] != data) + { + m_reg[offset] = data; + } + break; + + case 0x1d: /* sprite x size */ + if (m_reg[offset] != data) + { + m_reg[offset] = data; + } + break; + + case 0x1b: /* sprite background priority */ + if (m_reg[offset] != data) + { + m_reg[offset] = data; + } + break; + + case 0x1c: /* sprite multicolor mode select */ + if (m_reg[offset] != data) + { + m_reg[offset] = data; + } + break; + + case 0x27: + case 0x28: + case 0x29: + case 0x2a: + case 0x2b: + case 0x2c: + case 0x2d: + case 0x2e: + /* sprite colors */ + if (m_reg[offset] != data) + { + m_reg[offset] = data; + } + break; + + case 0x25: /* sprite multicolor */ + if (m_reg[offset] != data) + { + m_reg[offset] = data; + m_spritemulti[1] = SPRITE_MULTICOLOR1; + } + break; + + case 0x26: /* sprite multicolor */ + if (m_reg[offset] != data) + { + m_reg[offset] = data; + m_spritemulti[3] = SPRITE_MULTICOLOR2; + } + break; + + case 0x19: + clear_interrupt(data & 0x0f); + break; + + case 0x1a: /* irq mask */ + m_reg[offset] = data; + set_interrupt(0); // beamrider needs this + break; + + case 0x11: + if (m_reg[offset] != data) + { + m_reg[offset] = data; + if (data & 8) + { + m_dy_start = ROW25_YSTART; + m_dy_stop = ROW25_YSTOP; + } + else + { + m_dy_start = ROW24_YSTART; + m_dy_stop = ROW24_YSTOP; + } + } + break; + + case 0x12: + if (data != m_reg[offset]) + { + m_reg[offset] = data; + } + break; + + case 0x16: + if (m_reg[offset] != data) + { + m_reg[offset] = data; + } + break; + + case 0x18: + if (m_reg[offset] != data) + { + m_reg[offset] = data; + m_videoaddr = VIDEOADDR; + m_chargenaddr = CHARGENADDR; + m_bitmapaddr = BITMAPADDR; + } + break; + + case 0x21: /* background color */ + if (m_reg[offset] != data) + { + m_reg[offset] = data; + m_colors[0] = BACKGROUNDCOLOR; + } + break; + + case 0x22: /* background color 1 */ + if (m_reg[offset] != data) + { + m_reg[offset] = data; + m_colors[1] = MULTICOLOR1; + } + break; + + case 0x23: /* background color 2 */ + if (m_reg[offset] != data) + { + m_reg[offset] = data; + m_colors[2] = MULTICOLOR2; + } + break; + + case 0x24: /* background color 3 */ + if (m_reg[offset] != data) + { + m_reg[offset] = data; + m_colors[3] = FOREGROUNDCOLOR; + } + break; + + case 0x20: /* framecolor */ + if (m_reg[offset] != data) + { + m_reg[offset] = data; + } + break; + + case REGISTER_KCR: + if (IS_VICIIE) + { + m_reg[offset] = data | 0xf8; + + m_write_k((offs_t)0, data & 0x07); + } + break; + + case REGISTER_FAST: + if (IS_VICIIE) + { + if (BIT(m_reg[offset], 0) != BIT(data, 0)) + { + m_cpu->set_unscaled_clock(clock() << BIT(data, 0)); + } + + m_reg[offset] = data | 0xfc; + + m_on = !BIT(data, 0); + } + break; + + 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: + m_reg[offset] = data; + DBG_LOG(2, "vic write", ("%.2x:%.2x\n", offset, data)); + break; + + default: + m_reg[offset] = data; + break; + } +} + + +//------------------------------------------------- +// lp_w - light pen strobe +//------------------------------------------------- + +WRITE_LINE_MEMBER( mos6566_device::lp_w ) +{ + if (m_lp && !state && !(m_reg[REGISTER_IRQ] & IRQ_LP)) + { + m_reg[REGISTER_LPX] = m_raster_x >> 1; + m_reg[REGISTER_LPY] = m_rasterline; + + set_interrupt(IRQ_LP); + } + + m_lp = state; +} diff --git a/src/devices/video/mos6566.h b/src/devices/video/mos6566.h new file mode 100644 index 00000000000..e14c00140e9 --- /dev/null +++ b/src/devices/video/mos6566.h @@ -0,0 +1,455 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/*************************************************************************** + + MOS 6566/6567/6569 Video Interface Chip II (VIC-II) emulation + +**************************************************************************** + _____ _____ + DB6 1 |* \_/ | 40 Vcc + DB5 2 | | 39 DB7 + DB4 3 | | 38 DB8 + DB3 4 | | 37 DB9 + DB2 5 | | 36 DB10 + DB1 6 | | 35 DB11 + DB0 7 | | 34 A13 + _IRQ 8 | | 33 A12 + LP 9 | | 32 A11 + _CS 10 | MOS6566 | 31 A10 + R/W 11 | | 30 A9 + BA 12 | | 29 A8 + Vdd 13 | | 28 A7 + COLOR 14 | | 27 A6 + S/LUM 15 | | 26 A5 + AEC 16 | | 25 A4 + PH0 17 | | 24 A3 + PHIN 18 | | 23 A2 + PHCOL 19 | | 22 A1 + Vss 20 |_____________| 21 A0 + + _____ _____ + DB6 1 |* \_/ | 40 Vcc + DB5 2 | | 39 DB7 + DB4 3 | | 38 DB8 + DB3 4 | | 37 DB9 + DB2 5 | | 36 DB10 + DB1 6 | | 35 DB11 + DB0 7 | | 34 A10 + _IRQ 8 | | 33 A9 + LP 9 | MOS6567 | 32 A8 + _CS 10 | MOS6569 | 31 A7 + R/W 11 | MOS8562 | 30 A6 + BA 12 | MOS8565 | 29 A5/A13 + Vdd 13 | | 28 A4/A12 + COLOR 14 | | 27 A3/A11 + S/LUM 15 | | 26 A2/A10 + AEC 16 | | 25 A1/A9 + PH0 17 | | 24 A0/A8 + _RAS 18 | | 23 A11 + CAS 19 | | 22 PHIN + Vss 20 |_____________| 21 PHCL + + _____ _____ + D6 1 |* \_/ | 48 Vcc + D5 2 | | 47 D7 + D4 3 | | 46 D8 + D3 4 | | 45 D9 + D2 5 | | 44 D10 + D1 6 | | 43 D11 + D0 7 | | 42 MA10 + _IRQ 8 | | 41 MA9 + _LP 9 | | 40 MA8 + BA 10 | | 39 A7 + _DMARQST 11 | | 38 A6 + AEC 12 | MOS8564 | 37 MA5 + _CS 13 | MOS8566 | 36 MA4 + R/W 14 | | 35 MA3 + _DMAACK 15 | | 34 MA2 + CHROMA 16 | | 33 MA1 + SYNC/LUM 17 | | 32 MA0 + 1 MHZ 18 | | 31 MA11 + _RAS 19 | | 30 PHI IN + _CAS 20 | | 29 PHI COLOR + MUX 21 | | 28 K2 + _IOACC 22 | | 27 K1 + 2 MHZ 23 | | 26 K0 + Vss 24 |_____________| 25 Z80 PHI + +***************************************************************************/ + +#pragma once + +#ifndef __MOS6566__ +#define __MOS6566__ + +#include "emu.h" + + + +//*************************************************************************** +// DEVICE CONFIGURATION MACROS +//*************************************************************************** + +#define MCFG_MOS6566_CPU(_tag) \ + mos6566_device::static_set_cpu_tag(*device, "^" _tag); + +#define MCFG_MOS6566_IRQ_CALLBACK(_write) \ + devcb = &mos6566_device::set_irq_wr_callback(*device, DEVCB_##_write); + +#define MCFG_MOS6566_BA_CALLBACK(_write) \ + devcb = &mos6566_device::set_ba_wr_callback(*device, DEVCB_##_write); + +#define MCFG_MOS6566_AEC_CALLBACK(_write) \ + devcb = &mos6566_device::set_aec_wr_callback(*device, DEVCB_##_write); + +#define MCFG_MOS8564_K_CALLBACK(_write) \ + devcb = &mos6566_device::set_k_wr_callback(*device, DEVCB_##_write); + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define VIC6566_CLOCK (XTAL_8MHz / 8) // 1000000 +#define VIC6567R56A_CLOCK (XTAL_8MHz / 8) // 1000000 +#define VIC6567_CLOCK (XTAL_14_31818MHz / 14) // 1022727 +#define VIC6569_CLOCK (XTAL_17_734472MHz / 18) // 985248 + +#define VIC6566_DOTCLOCK (VIC6566_CLOCK * 8) // 8000000 +#define VIC6567R56A_DOTCLOCK (VIC6567R56A_CLOCK * 8) // 8000000 +#define VIC6567_DOTCLOCK (VIC6567_CLOCK * 8) // 8181818 +#define VIC6569_DOTCLOCK (VIC6569_CLOCK * 8) // 7881988 + +#define VIC6567_CYCLESPERLINE 65 +#define VIC6569_CYCLESPERLINE 63 + +#define VIC6567_LINES 263 +#define VIC6569_LINES 312 + +#define VIC6566_VRETRACERATE ((float)VIC6566_CLOCK / 262 / 64) +#define VIC6567R56A_VRETRACERATE ((float)VIC6567R56A_CLOCK / 262 / 64) +#define VIC6567_VRETRACERATE ((float)VIC6567_CLOCK / 263 / 65) +#define VIC6569_VRETRACERATE ((float)VIC6569_CLOCK / 312 / 63) + +#define VIC6566_HRETRACERATE (VIC6566_CLOCK / VIC6566_CYCLESPERLINE) +#define VIC6567_HRETRACERATE (VIC6567_CLOCK / VIC6567_CYCLESPERLINE) +#define VIC6569_HRETRACERATE (VIC6569_CLOCK / VIC6569_CYCLESPERLINE) + +#define VIC2_HSIZE 320 +#define VIC2_VSIZE 200 + +#define VIC6567_VISIBLELINES 235 +#define VIC6569_VISIBLELINES 284 + +#define VIC6567_FIRST_DMA_LINE 0x30 +#define VIC6569_FIRST_DMA_LINE 0x30 + +#define VIC6567_LAST_DMA_LINE 0xf7 +#define VIC6569_LAST_DMA_LINE 0xf7 + +#define VIC6567_FIRST_DISP_LINE 0x29 +#define VIC6569_FIRST_DISP_LINE 0x10 + +#define VIC6567_LAST_DISP_LINE (VIC6567_FIRST_DISP_LINE + VIC6567_VISIBLELINES - 1) +#define VIC6569_LAST_DISP_LINE (VIC6569_FIRST_DISP_LINE + VIC6569_VISIBLELINES - 1) + +#define VIC6567_RASTER_2_EMU(a) ((a >= VIC6567_FIRST_DISP_LINE) ? (a - VIC6567_FIRST_DISP_LINE) : (a + 222)) +#define VIC6569_RASTER_2_EMU(a) (a - VIC6569_FIRST_DISP_LINE) + +#define VIC6567_FIRSTCOLUMN 50 +#define VIC6569_FIRSTCOLUMN 50 + +#define VIC6567_VISIBLECOLUMNS 418 +#define VIC6569_VISIBLECOLUMNS 403 + +#define VIC6567_X_2_EMU(a) (a) +#define VIC6569_X_2_EMU(a) (a) + +#define VIC6567_STARTVISIBLELINES ((VIC6567_LINES - VIC6567_VISIBLELINES)/2) +#define VIC6569_STARTVISIBLELINES 16 /* ((VIC6569_LINES - VIC6569_VISIBLELINES)/2) */ + +#define VIC6567_FIRSTRASTERLINE 34 +#define VIC6569_FIRSTRASTERLINE 0 + +#define VIC6567_COLUMNS 512 +#define VIC6569_COLUMNS 504 + +#define VIC6567_STARTVISIBLECOLUMNS ((VIC6567_COLUMNS - VIC6567_VISIBLECOLUMNS)/2) +#define VIC6569_STARTVISIBLECOLUMNS ((VIC6569_COLUMNS - VIC6569_VISIBLECOLUMNS)/2) + +#define VIC6567_FIRSTRASTERCOLUMNS 412 +#define VIC6569_FIRSTRASTERCOLUMNS 404 + +#define VIC6569_FIRST_X 0x194 +#define VIC6567_FIRST_X 0x19c + +#define VIC6569_FIRST_VISIBLE_X 0x1e0 +#define VIC6567_FIRST_VISIBLE_X 0x1e8 + +#define VIC6569_MAX_X 0x1f7 +#define VIC6567_MAX_X 0x1ff + +#define VIC6569_LAST_VISIBLE_X 0x17c +#define VIC6567_LAST_VISIBLE_X 0x184 + +#define VIC6569_LAST_X 0x193 +#define VIC6567_LAST_X 0x19b + + + +//*************************************************************************** +// TYPE DEFINITIONS +//*************************************************************************** + +// ======================> mos6566_device + +class mos6566_device : public device_t, + public device_memory_interface, + public device_video_interface, + public device_execute_interface +{ +public: + // construction/destruction + mos6566_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, UINT32 variant, const char *shortname, const char *source); + mos6566_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + static void static_set_cpu_tag(device_t &device, const char *tag) { downcast(device).m_cpu.set_tag(tag); } + template static devcb_base &set_irq_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_irq.set_callback(object); } + template static devcb_base &set_ba_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_ba.set_callback(object); } + template static devcb_base &set_aec_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_aec.set_callback(object); } + template static devcb_base &set_k_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_k.set_callback(object); } + + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const; + + DECLARE_READ8_MEMBER( read ); + DECLARE_WRITE8_MEMBER( write ); + + DECLARE_WRITE_LINE_MEMBER( lp_w ); + + DECLARE_READ_LINE_MEMBER( phi0_r ) { return m_phi0; } // phi 0 + DECLARE_READ_LINE_MEMBER( ba_r ) { return m_ba; } // bus available + DECLARE_READ_LINE_MEMBER( aec_r ) { return m_aec; } // address enable control + + UINT8 bus_r() { return m_last_data; } + + UINT32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); + +protected: + enum + { + TYPE_6566, // NTSC-M (SRAM) + TYPE_6567, // NTSC-M (NMOS) + TYPE_8562, // NTSC-M (HMOS) + TYPE_8564, // NTSC-M VIC-IIe (C128) + + TYPE_6569, // PAL-B + TYPE_6572, // PAL-N + TYPE_6573, // PAL-M + TYPE_8565, // PAL-B (HMOS) + TYPE_8566, // PAL-B VIC-IIe (C128) + TYPE_8569 // PAL-N VIC-IIe (C128) + }; + + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void execute_run(); + + int m_icount; + int m_variant; + + const address_space_config m_videoram_space_config; + const address_space_config m_colorram_space_config; + + inline void set_interrupt( int mask ); + inline void clear_interrupt( int mask ); + inline void set_ba(int state); + inline void set_aec(int state); + inline void bad_line_ba(); + inline UINT8 read_videoram(offs_t offset); + inline UINT8 read_colorram(offs_t offset); + inline void idle_access(); + inline void spr_ba(int num); + inline void spr_ptr_access( int num ); + inline void spr_data_access( int num, int bytenum ); + inline void display_if_bad_line(); + inline void refresh_access(); + inline void fetch_if_bad_line(); + inline void rc_if_bad_line(); + inline void sample_border(); + inline void check_sprite_dma(); + inline void matrix_access(); + inline void graphics_access(); + inline void draw_background(); + inline void draw_mono( UINT16 p, UINT8 c0, UINT8 c1 ); + inline void draw_multi( UINT16 p, UINT8 c0, UINT8 c1, UINT8 c2, UINT8 c3 ); + void draw_graphics(); + void draw_sprites(); + + devcb_write_line m_write_irq; + devcb_write_line m_write_ba; + devcb_write_line m_write_aec; + devcb_write8 m_write_k; + + required_device m_cpu; + + int m_phi0; + int m_ba; + int m_aec; + UINT8 m_aec_delay; + int m_rdy_cycles; + + UINT8 m_reg[0x80]; + + int m_on; /* rastering of the screen */ + + UINT16 m_chargenaddr, m_videoaddr, m_bitmapaddr; + + bitmap_rgb32 m_bitmap; + + UINT16 m_colors[4], m_spritemulti[4]; + + int m_rasterline; + UINT8 m_cycle; + UINT16 m_raster_x; + UINT16 m_graphic_x; + UINT8 m_last_data; + int m_lp; + + /* convert multicolor byte to background/foreground for sprite collision */ + UINT16 m_expandx[256]; + UINT16 m_expandx_multi[256]; + + /* Display */ + UINT16 m_dy_start; + UINT16 m_dy_stop; + + /* GFX */ + UINT8 m_draw_this_line; + UINT8 m_is_bad_line; + UINT8 m_bad_lines_enabled; + UINT8 m_display_state; + UINT8 m_char_data; + UINT8 m_gfx_data; + UINT8 m_color_data; + UINT8 m_last_char_data; + UINT8 m_matrix_line[40]; // Buffer for video line, read in Bad Lines + UINT8 m_color_line[40]; // Buffer for color line, read in Bad Lines + UINT8 m_vblanking; + UINT16 m_ml_index; + UINT8 m_rc; + UINT16 m_vc; + UINT16 m_vc_base; + UINT8 m_ref_cnt; + + /* Sprites */ + UINT8 m_spr_coll_buf[0x400]; // Buffer for sprite-sprite collisions and priorities + UINT8 m_fore_coll_buf[0x400]; // Buffer for foreground-sprite collisions and priorities + UINT8 m_spr_draw_data[8][4]; // Sprite data for drawing + UINT8 m_spr_exp_y; + UINT8 m_spr_dma_on; + UINT8 m_spr_draw; + UINT8 m_spr_disp_on; + UINT16 m_spr_ptr[8]; + UINT8 m_spr_data[8][4]; + UINT16 m_mc_base[8]; // Sprite data counter bases + UINT16 m_mc[8]; // Sprite data counters + + /* Border */ + UINT8 m_border_on; + UINT8 m_ud_border_on; + UINT8 m_border_on_sample[5]; + UINT8 m_border_color_sample[0x400 / 8]; // Samples of border color at each "displayed" cycle + + /* Cycles */ + UINT64 m_first_ba_cycle; + UINT8 m_device_suspended; +}; + + +// ======================> mos6567_device + +class mos6567_device : public mos6566_device +{ +public: + // construction/destruction + mos6567_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + mos6567_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, UINT32 variant, const char *shortname, const char *source); +}; + + +// ======================> mos8562_device + +class mos8562_device : public mos6567_device +{ +public: + // construction/destruction + mos8562_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +// ======================> mos8564_device + +class mos8564_device : public mos6567_device +{ +public: + // construction/destruction + mos8564_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device_execute_interface overrides + virtual UINT64 execute_clocks_to_cycles(UINT64 clocks) const { return (clocks / 8); } + virtual UINT64 execute_cycles_to_clocks(UINT64 cycles) const { return (cycles * 8); } +}; + + +// ======================> mos6569_device + +class mos6569_device : public mos6566_device +{ +public: + // construction/destruction + mos6569_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + mos6569_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, UINT32 variant, const char *shortname, const char *source); + + // device-level overrides + virtual void execute_run(); +}; + + +// ======================> mos8565_device + +class mos8565_device : public mos6569_device +{ +public: + // construction/destruction + mos8565_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +// ======================> mos8566_device + +class mos8566_device : public mos6569_device +{ +public: + // construction/destruction + mos8566_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device_execute_interface overrides + virtual UINT64 execute_clocks_to_cycles(UINT64 clocks) const { return (clocks / 8); } + virtual UINT64 execute_cycles_to_clocks(UINT64 cycles) const { return (cycles * 8); } +}; + + +// device type definitions +extern const device_type MOS6566; +extern const device_type MOS6567; +extern const device_type MOS8562; +extern const device_type MOS8564; +extern const device_type MOS6569; +extern const device_type MOS8565; +extern const device_type MOS8566; + + + +#endif diff --git a/src/devices/video/msm6222b.c b/src/devices/video/msm6222b.c new file mode 100644 index 00000000000..f6c2c9564a3 --- /dev/null +++ b/src/devices/video/msm6222b.c @@ -0,0 +1,246 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +/*************************************************************************** + + MSM6222B + + A somewhat hd44780-compatible LCD controller. + + The -01 variant has a fixed cgrom, the other variants are mask-programmed. + +***************************************************************************/ + +#include "emu.h" +#include "msm6222b.h" + +const device_type MSM6222B = &device_creator; +const device_type MSM6222B_01 = &device_creator; + +ROM_START( msm6222b_01 ) + ROM_REGION( 0x1000, "cgrom", 0 ) + ROM_LOAD( "msm6222b-01.bin", 0x0000, 0x1000, CRC(8ffa8521) SHA1(e108b520e6d20459a7bbd5958bbfa1d551a690bd) ) +ROM_END + +msm6222b_device::msm6222b_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source) +{ +} + +msm6222b_device::msm6222b_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, MSM6222B, "msm6222b-xx", tag, owner, clock, "msm6222b", __FILE__) +{ +} + +msm6222b_01_device::msm6222b_01_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + msm6222b_device(mconfig, MSM6222B_01, "msm6222b-01", tag, owner, clock, "msm6222b", __FILE__) +{ +} + +const rom_entry *msm6222b_01_device::device_rom_region() const +{ + return ROM_NAME(msm6222b_01); +} + +void msm6222b_device::device_start() +{ + if(memregion("cgrom")) + cgrom = memregion("cgrom")->base(); + else if(m_region) + cgrom = m_region->base(); + else + cgrom = NULL; + + memset(cgram, 0, sizeof(cgram)); + memset(ddram, 0x20, sizeof(ddram)); + + cursor_direction = true; + cursor_blinking = false; + display_on = false; + two_line = false; + cursor_on = false; + shift_on_write = false; + double_height = false; + adc = 0x00; + shift = 0; +} + +void msm6222b_device::control_w(UINT8 data) +{ + int cmd; + for(cmd = 7; cmd >= 0 && !(data & (1<= 40 && adr < 64) || adr >= 64+40) + adr = -1; + if(adr >= 64) + adr += 40-64; + } else { + if(adr >= 80) + adr = -1; + } + if(adr != -1) { + ddram[adr] = data; + if(shift_on_write) + shift_step(cursor_direction); + else + cursor_step(cursor_direction); + } + } else { + if(adc < 8*8) { + cgram[adc] = data; + cursor_step(cursor_direction); + } + } +} + +void msm6222b_device::cursor_step(bool direction) +{ + if(direction) { + if(adc & 0x80) { + if(two_line && adc == (0x80|39)) + adc = 0x80|64; + else if(two_line && adc == (0x80|(64+39))) + adc = 0x80; + else if((!two_line) && adc == (0x80|79)) + adc = 0x80; + else + adc++; + } else { + if(adc == 8*8-1) + adc = 0x00; + else + adc++; + } + } else { + if(adc & 0x80) { + if(adc == 0x80) + adc = two_line ? 0x80|(64+39) : 0x80|79; + else if(two_line && adc == (0x80|64)) + adc = 0x80|39; + else + adc--; + } else { + if(adc == 0x00) + adc = 8*8-1; + else + adc--; + } + } +} + +void msm6222b_device::shift_step(bool direction) +{ + if(direction) { + if(shift == 79) + shift = 0; + else + shift++; + } else { + if(shift == 0) + shift = 79; + else + shift--; + } +} + +bool msm6222b_device::blink_on() const +{ + if(!cursor_blinking) + return false; + UINT64 clocks = machine().time().as_ticks(250000); + if(double_height) + return clocks % 281600 >= 140800; + else + return clocks % 204800 >= 102400; +} + +const UINT8 *msm6222b_device::render() +{ + memset(render_buf, 0, 80*16); + if(!display_on) + return render_buf; + + int char_height = double_height ? 11 : 8; + + for(int i=0; i<80; i++) { + UINT8 c = ddram[(i+shift) % 80]; + if(c < 16) + memcpy(render_buf + 16*i, double_height ? cgram + 8*(c & 6) : cgram + 8*(c & 7), char_height); + else if(cgrom) + memcpy(render_buf + 16*i, cgrom + 16*c, char_height); + } + + if(cursor_on) { + int cpos = adc & 0x7f; + if(two_line) { + if((cpos >= 40 && cpos < 64) || cpos >= 64+40) + cpos = -1; + else if(cpos >= 64) + cpos += 40-64; + } else { + if(cpos >= 80) + cpos = -1; + } + if(cpos != -1) { + cpos = (cpos + shift) % 80; + render_buf[cpos*16 + (double_height ? 10 : 7)] |= 0x1f; + if(blink_on()) + for(int i=0; i; + +// I/O map +DEVICE_ADDRESS_MAP_START( map, 8, msm6255_device ) + AM_RANGE(0x00, 0x00) AM_READWRITE(dr_r, dr_w) + AM_RANGE(0x01, 0x01) AM_READWRITE(ir_r, ir_w) +ADDRESS_MAP_END + +// default address map +static ADDRESS_MAP_START( msm6255, AS_0, 8, msm6255_device ) + AM_RANGE(0x00000, 0xfffff) AM_RAM +ADDRESS_MAP_END + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// msm6255_device - constructor +//------------------------------------------------- + +msm6255_device::msm6255_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, MSM6255, "MSM6255", tag, owner, clock, "msm6255", __FILE__), + device_memory_interface(mconfig, *this), + device_video_interface(mconfig, *this), + m_space_config("videoram", ENDIANNESS_LITTLE, 8, 20, 0, NULL, *ADDRESS_MAP_NAME(msm6255)), + m_cursor(0) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void msm6255_device::device_start() +{ + // register for state saving + save_item(NAME(m_ir)); + save_item(NAME(m_mor)); + save_item(NAME(m_pr)); + save_item(NAME(m_hnr)); + save_item(NAME(m_dvr)); + save_item(NAME(m_cpr)); + save_item(NAME(m_slr)); + save_item(NAME(m_sur)); + save_item(NAME(m_clr)); + save_item(NAME(m_cur)); + save_item(NAME(m_cursor)); + save_item(NAME(m_frame)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void msm6255_device::device_reset() +{ + m_frame = 0; +} + + +//------------------------------------------------- +// memory_space_config - return a description of +// any address spaces owned by this device +//------------------------------------------------- + +const address_space_config *msm6255_device::memory_space_config(address_spacenum spacenum) const +{ + return (spacenum == AS_0) ? &m_space_config : NULL; +} + + +//------------------------------------------------- +// ir_r - +//------------------------------------------------- + +READ8_MEMBER( msm6255_device::ir_r ) +{ + return m_ir; +} + + +//------------------------------------------------- +// ir_w - +//------------------------------------------------- + +WRITE8_MEMBER( msm6255_device::ir_w ) +{ + m_ir = data & 0x0f; +} + + +//------------------------------------------------- +// dr_r - +//------------------------------------------------- + +READ8_MEMBER( msm6255_device::dr_r ) +{ + UINT8 data = 0; + + switch (m_ir) + { + case REGISTER_MOR: + break; // write-only + + case REGISTER_PR: + data = m_pr; + break; + + case REGISTER_HNR: + data = m_hnr; + break; + + case REGISTER_DVR: + break; // write-only + + case REGISTER_CPR: + data = m_cpr; + break; + + case REGISTER_SLR: + data = m_slr; + break; + + case REGISTER_SUR: + data = m_sur; + break; + + case REGISTER_CLR: + data = m_clr; + break; + + case REGISTER_CUR: + data = m_cur; + break; + } + + return data; +} + + +//------------------------------------------------- +// dr_w - +//------------------------------------------------- + +WRITE8_MEMBER( msm6255_device::dr_w ) +{ + switch (m_ir) + { + case REGISTER_MOR: + m_mor = data & 0x7f; + break; + + case REGISTER_PR: + m_pr = data & 0xf7; + break; + + case REGISTER_HNR: + m_hnr = data & 0x7f; + break; + + case REGISTER_DVR: + m_dvr = data; + break; + + case REGISTER_CPR: + m_cpr = data; + break; + + case REGISTER_SLR: + m_slr = data; + break; + + case REGISTER_SUR: + m_sur = data; + break; + + case REGISTER_CLR: + m_clr = data; + break; + + case REGISTER_CUR: + m_cur = data; + break; + } +} + + +//------------------------------------------------- +// read_byte - +//------------------------------------------------- + +UINT8 msm6255_device::read_byte(UINT16 ma, UINT8 ra) +{ + offs_t offset; + + if (m_mor & MOR_GRAPHICS) + { + offset = ma; + } + else + { + offset = ((offs_t)ma << 4) | ra; + } + + return space().read_byte(offset); +} + + +//------------------------------------------------- +// update_cursor - +//------------------------------------------------- + +void msm6255_device::update_cursor() +{ + if (m_mor & MOR_CURSOR_ON) + { + if (m_mor & MOR_CURSOR_BLINK) + { + if (m_mor & MOR_BLINK_TIME_16) + { + if (m_frame == 16) + { + m_cursor = !m_cursor; + m_frame = 0; + } + else + { + m_frame++; + } + } + else + { + if (m_frame == 32) + { + m_cursor = !m_cursor; + m_frame = 0; + } + else + { + m_frame++; + } + } + } + else + { + m_cursor = 1; + } + } + else + { + m_cursor = 0; + } +} + + +//------------------------------------------------- +// draw_scanline - +//------------------------------------------------- + +void msm6255_device::draw_scanline(bitmap_ind16 &bitmap, const rectangle &cliprect, int y, UINT16 ma, UINT8 ra) +{ + UINT8 hp = (m_pr & PR_HP_MASK) + 1; + UINT8 hn = (m_hnr & HNR_HN_MASK) + 1; + UINT8 cpu = m_cpr & CPR_CPU_MASK; + UINT8 cpd = m_cpr & CPR_CPD_MASK; + UINT16 car = (m_cur << 8) | m_clr; + + int sx, x; + + for (sx = 0; sx < hn; sx++) + { + UINT8 data = read_byte(ma, ra); + + if (m_cursor) + { + if (ma == car) + { + if (ra >= cpu && ra <= cpd) + { + data ^= 0xff; + } + } + } + + for (x = 0; x < hp; x++) + { + bitmap.pix16(y, (sx * hp) + x) = BIT(data, 7); + + data <<= 1; + } + + ma++; + } +} + + +//------------------------------------------------- +// update_graphics - +//------------------------------------------------- + +void msm6255_device::update_graphics(bitmap_ind16 &bitmap, const rectangle &cliprect) +{ + UINT8 hn = (m_hnr & HNR_HN_MASK) + 1; + UINT8 nx = (m_dvr & DVR_DN_MASK) + 1; + UINT16 sar = (m_sur << 8) | m_slr; + + int y; + + m_cursor = 0; + m_frame = 0; + + for (y = 0; y < nx; y++) + { + // draw upper half scanline + UINT16 ma = sar + (y * hn); + draw_scanline(bitmap, cliprect, y, ma); + + // draw lower half scanline + ma = sar + ((y + nx) * hn); + draw_scanline(bitmap, cliprect, y + nx, ma); + } +} + + +//------------------------------------------------- +// update_text - +//------------------------------------------------- + +void msm6255_device::update_text(bitmap_ind16 &bitmap, const rectangle &cliprect) +{ + UINT8 hn = (m_hnr & HNR_HN_MASK) + 1; + UINT8 vp = (m_pr & PR_VP_MASK) + 1; + UINT8 nx = (m_dvr & DVR_DN_MASK) + 1; + UINT16 sar = (m_sur << 8) | m_slr; + + int sy, y; + + update_cursor(); + + for (sy = 0; sy < nx; sy++) + { + for (y = 0; y < vp; y++) + { + // draw upper half scanline + UINT16 ma = sar + ((sy * vp) + y) * hn; + draw_scanline(bitmap, cliprect, (sy * vp) + y, ma, y); + + // draw lower half scanline + ma = sar + (((sy + nx) * vp) + y) * hn; + draw_scanline(bitmap, cliprect, (sy * vp) + y, ma, y); + } + } +} + + +//------------------------------------------------- +// update_screen - update screen +//------------------------------------------------- + +UINT32 msm6255_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) +{ + if (m_mor & MOR_DISPLAY_ON) + { + if (m_mor & MOR_GRAPHICS) + { + update_graphics(bitmap, cliprect); + } + else + { + update_text(bitmap, cliprect); + } + } + else + { + bitmap.fill(0, cliprect); + } + + return 0; +} diff --git a/src/devices/video/msm6255.h b/src/devices/video/msm6255.h new file mode 100644 index 00000000000..32975132cf6 --- /dev/null +++ b/src/devices/video/msm6255.h @@ -0,0 +1,95 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + OKI MSM6255 Dot Matrix LCD Controller implementation + +**********************************************************************/ + +#pragma once + +#ifndef __MSM6255__ +#define __MSM6255__ + +#include "emu.h" + + + +///************************************************************************* +// TYPE DEFINITIONS +///************************************************************************* + +// ======================> msm6255_device + +class msm6255_device : public device_t, + public device_memory_interface, + public device_video_interface +{ +public: + // construction/destruction + msm6255_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual DECLARE_ADDRESS_MAP(map, 8); + + DECLARE_READ8_MEMBER( ir_r ); + DECLARE_WRITE8_MEMBER( ir_w ); + + DECLARE_READ8_MEMBER( dr_r ); + DECLARE_WRITE8_MEMBER( dr_w ); + + UINT32 screen_update(screen_device &device, bitmap_ind16 &bitmap, const rectangle &cliprect); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const; + +private: + // registers + enum + { + REGISTER_MOR = 0, + REGISTER_PR, + REGISTER_HNR, + REGISTER_DVR, + REGISTER_CPR, + REGISTER_SLR, + REGISTER_SUR, + REGISTER_CLR, + REGISTER_CUR + }; + + UINT8 read_byte(UINT16 ma, UINT8 ra); + + void update_cursor(); + void draw_scanline(bitmap_ind16 &bitmap, const rectangle &cliprect, int y, UINT16 ma, UINT8 ra = 0); + void update_graphics(bitmap_ind16 &bitmap, const rectangle &cliprect); + void update_text(bitmap_ind16 &bitmap, const rectangle &cliprect); + + const address_space_config m_space_config; + + UINT8 m_ir; // instruction register + UINT8 m_mor; // mode control register + UINT8 m_pr; // character pitch register + UINT8 m_hnr; // horizontal character number register + UINT8 m_dvr; // duty number register + UINT8 m_cpr; // cursor form register + UINT8 m_slr; // start address (lower) register + UINT8 m_sur; // start address (upper) register + UINT8 m_clr; // cursor address (lower) register + UINT8 m_cur; // cursor address (upper) register + + int m_cursor; // is cursor displayed + int m_frame; // frame counter +}; + + +// device type definition +extern const device_type MSM6255; + + + +#endif diff --git a/src/devices/video/pc_vga.c b/src/devices/video/pc_vga.c new file mode 100644 index 00000000000..c494e4904ec --- /dev/null +++ b/src/devices/video/pc_vga.c @@ -0,0 +1,5559 @@ +// license:BSD-3-Clause +// copyright-holders:Nathan Woods, Peter Trauner, Angelo Salese +/*************************************************************************** + + Video Graphics Adapter (VGA) section + + Nathan Woods npwoods@mess.org + Peter Trauner PeT mess@utanet.at + + This code takes care of installing the various VGA memory and port + handlers + + The VGA standard is compatible with MDA, CGA, Hercules, EGA + (mda, cga, hercules not real register compatible) + several vga cards drive also mda, cga, ega monitors + some vga cards have register compatible mda, cga, hercules modes + + ega/vga + 64k (early ega 16k) words of 32 bit memory + + TODO: + - modernize + - fix video update, still need to get that choosevideomode() out of it. + - rewrite video drawing functions (they are horrible) + - add per-gfx card VESA functions; + - (and many more ...) + + per-game issues: + - The Incredible Machine: fix partial updates + - MAME 0.01: fix 92 Hz refresh rate bug (uses VESA register?). + - Virtual Pool: ET4k unrecognized; + - California Chase (calchase): various gfx bugs, CPU related? + - Jazz Jackrabbit: status bar is very jerky, but main screen scrolling is fine? + - Catacombs: weird resolution (untested) + + ROM declarations: + + (oti 037 chip) + ROM_LOAD("oakvga.bin", 0xc0000, 0x8000, 0x318c5f43) + (tseng labs famous et4000 isa vga card (oem)) + ROM_LOAD("et4000b.bin", 0xc0000, 0x8000, 0xa903540d) + (tseng labs famous et4000 isa vga card) + ROM_LOAD("et4000.bin", 0xc0000, 0x8000, 0xf01e4be0) + +***************************************************************************/ + +#include "emu.h" +#include "pc_vga.h" +#include "bus/isa/trident.h" +#include "machine/eepromser.h" +#include "debugger.h" + +/*************************************************************************** + + Local variables + +***************************************************************************/ + +enum +{ + IBM8514_IDLE = 0, + IBM8514_DRAWING_RECT, + IBM8514_DRAWING_LINE, + IBM8514_DRAWING_BITBLT, + IBM8514_DRAWING_PATTERN, + IBM8514_DRAWING_SSV_1, + IBM8514_DRAWING_SSV_2 +}; + +#define CRTC_PORT_ADDR ((vga.miscellaneous_output&1)?0x3d0:0x3b0) + +//#define TEXT_LINES (LINES_HELPER) +#define LINES (vga.crtc.vert_disp_end+1) +#define TEXT_LINES (vga.crtc.vert_disp_end+1) + +#define GRAPHIC_MODE (vga.gc.alpha_dis) /* else text mode */ + +#define EGA_COLUMNS (vga.crtc.horz_disp_end+1) +#define EGA_START_ADDRESS (vga.crtc.start_addr) +#define EGA_LINE_LENGTH (vga.crtc.offset<<1) + +#define VGA_COLUMNS (vga.crtc.horz_disp_end+1) +#define VGA_START_ADDRESS (vga.crtc.start_addr) +#define VGA_LINE_LENGTH (vga.crtc.offset<<3) + +#define IBM8514_LINE_LENGTH (m_vga->offset()) + +#define CHAR_WIDTH ((vga.sequencer.data[1]&1)?8:9) + +#define TEXT_COLUMNS (vga.crtc.horz_disp_end+1) +#define TEXT_START_ADDRESS (vga.crtc.start_addr<<3) +#define TEXT_LINE_LENGTH (vga.crtc.offset<<1) + +#define TEXT_COPY_9COLUMN(ch) (((ch & 0xe0) == 0xc0)&&(vga.attribute.data[0x10]&4)) + +// Special values for SVGA Trident - Mode Vesa 110h +#define TLINES (LINES) +#define TGA_COLUMNS (EGA_COLUMNS) +#define TGA_START_ADDRESS (vga.crtc.start_addr<<2) +#define TGA_LINE_LENGTH (vga.crtc.offset<<3) + + +/*************************************************************************** + + Static declarations + +***************************************************************************/ + +#define LOG_ACCESSES 0 +#define LOG_REGISTERS 0 + +#define LOG_8514 1 + +/*************************************************************************** + + Generic VGA + +***************************************************************************/ +// device type definition +const device_type VGA = &device_creator; +const device_type TSENG_VGA = &device_creator; +const device_type S3_VGA = &device_creator; +const device_type GAMTOR_VGA = &device_creator; +const device_type ATI_VGA = &device_creator; +const device_type IBM8514A = &device_creator; +const device_type MACH8 = &device_creator; + +vga_device::vga_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + m_palette(*this, "^palette"), + m_screen(*this,"^screen") +{ +} + +vga_device::vga_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, VGA, "VGA", tag, owner, clock, "vga", __FILE__), + m_palette(*this, "^palette"), + m_screen(*this,"^screen") +{ +} + +svga_device::svga_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : vga_device(mconfig, type, name, tag, owner, clock, shortname, source) +{ +} + +tseng_vga_device::tseng_vga_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : svga_device(mconfig, TSENG_VGA, "TSENG LABS VGA", tag, owner, clock, "tseng_vga", __FILE__) +{ +} + +s3_vga_device::s3_vga_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : ati_vga_device(mconfig, S3_VGA, "S3 Graphics VGA", tag, owner, clock, "s3_vga", __FILE__) +{ +} + +s3_vga_device::s3_vga_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : ati_vga_device(mconfig, type, name, tag, owner, clock, shortname, source) +{ +} + +gamtor_vga_device::gamtor_vga_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : svga_device(mconfig, GAMTOR_VGA, "GAMTOR VGA", tag, owner, clock, "gamtor_vga", __FILE__) +{ +} + +ati_vga_device::ati_vga_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : svga_device(mconfig, ATI_VGA, "ATI VGA", tag, owner, clock, "ati_vga", __FILE__) +{ +} + +ati_vga_device::ati_vga_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : svga_device(mconfig, type, name, tag, owner, clock, shortname, source) +{ +} + +ibm8514a_device::ibm8514a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, IBM8514A, "IBM8514A Video", tag, owner, clock, "ibm8514a", __FILE__) +{ +} + +ibm8514a_device::ibm8514a_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source) +{ +} + +mach8_device::mach8_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : ibm8514a_device(mconfig, type, name, tag, owner, clock, shortname, source) +{ +} + +mach8_device::mach8_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : ibm8514a_device(mconfig, MACH8, "MACH8", tag, owner, clock, "mach8", __FILE__) +{ +} + +// zero everything, keep vtbls +void vga_device::zero() +{ + memset(&vga.svga_intf, 0, sizeof(vga.svga_intf)); + vga.memory.resize(0); + memset(vga.pens, 0, sizeof(vga.pens)); + vga.miscellaneous_output = 0; + vga.feature_control = 0; + memset(&vga.sequencer, 0, sizeof(vga.sequencer)); + memset(&vga.crtc, 0, sizeof(vga.crtc)); + memset(&vga.gc, 0, sizeof(vga.gc)); + memset(&vga.attribute, 0, sizeof(vga.attribute)); + memset(&vga.dac, 0, sizeof(vga.dac)); + memset(&vga.oak, 0, sizeof(vga.oak)); +} + +void svga_device::zero() +{ + vga_device::zero(); + memset(&svga, 0, sizeof(svga)); +} + +/* VBLANK callback, start address definitely updates AT vblank, not before. */ +TIMER_CALLBACK_MEMBER(vga_device::vblank_timer_cb) +{ + vga.crtc.start_addr = vga.crtc.start_addr_latch; + vga.attribute.pel_shift = vga.attribute.pel_shift_latch; + m_vblank_timer->adjust( machine().first_screen()->time_until_pos(vga.crtc.vert_blank_start + vga.crtc.vert_blank_end) ); +} + +void vga_device::device_start() +{ + zero(); + + int i; + for (i = 0; i < 0x100; i++) + m_palette->set_pen_color(i, 0, 0, 0); + + // Avoid an infinite loop when displaying. 0 is not possible anyway. + vga.crtc.maximum_scan_line = 1; + + + // copy over interfaces + vga.read_dipswitch = read8_delegate(); //read_dipswitch; + vga.svga_intf.seq_regcount = 0x05; + vga.svga_intf.crtc_regcount = 0x19; + vga.svga_intf.vram_size = 0x100000; + + vga.memory.resize(vga.svga_intf.vram_size); + memset(&vga.memory[0], 0, vga.svga_intf.vram_size); + save_item(NAME(vga.memory)); + save_pointer(vga.crtc.data,"CRTC Registers",0x100); + save_pointer(vga.sequencer.data,"Sequencer Registers",0x100); + save_pointer(vga.attribute.data,"Attribute Registers", 0x15); + + m_vblank_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(vga_device::vblank_timer_cb),this)); +} + +void svga_device::device_start() +{ + vga_device::device_start(); + memset(&svga, 0, sizeof(svga)); +} + +void ati_vga_device::device_start() +{ + svga_device::device_start(); + memset(&ati, 0, sizeof(ati)); + save_pointer(ati.ext_reg,"ATi Extended Registers",64); + m_8514 = subdevice("8514a"); + ati.vga_chip_id = 0x06; // 28800-6 +} + +void s3_vga_device::device_start() +{ + svga_device::device_start(); + memset(&s3, 0, sizeof(s3)); + int x; + // Initialise hardware graphics cursor colours, Windows 95 doesn't touch the registers for some reason + for(x=0;x<4;x++) + { + s3.cursor_fg[x] = 0xff; + s3.cursor_bg[x] = 0x00; + } + m_8514 = subdevice("8514a"); + // set device ID + s3.id_high = 0x88; // CR2D + s3.id_low = 0x11; // CR2E + s3.revision = 0x00; // CR2F + s3.id_cr30 = 0xe1; // CR30 +} + +void tseng_vga_device::device_start() +{ + svga_device::device_start(); + memset(&et4k, 0, sizeof(et4k)); +} + +void ibm8514a_device::device_start() +{ + memset(&ibm8514, 0, sizeof(ibm8514)); + ibm8514.read_mask = 0x00000000; + ibm8514.write_mask = 0xffffffff; +} + +void ibm8514a_device::device_config_complete() +{ + if(m_vga_tag.length() != 0) + { + m_vga = machine().device(m_vga_tag.c_str()); + } +} + +void mach8_device::device_start() +{ + ibm8514a_device::device_start(); + memset(&mach8, 0, sizeof(mach8)); +} + +UINT16 vga_device::offset() +{ +// popmessage("Offset: %04x %s %s **",vga.crtc.offset,vga.crtc.dw?"DW":"--",vga.crtc.word_mode?"BYTE":"WORD"); + if(vga.crtc.dw) + return vga.crtc.offset << 3; + if(vga.crtc.word_mode) + return vga.crtc.offset << 1; + else + return vga.crtc.offset << 2; +} + +void vga_device::vga_vh_text(bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + UINT8 ch, attr; + UINT8 bits; + UINT32 font_base; + UINT32 *bitmapline; + int width=CHAR_WIDTH, height = (vga.crtc.maximum_scan_line) * (vga.crtc.scan_doubling + 1); + int pos, line, column, mask, w, h, addr; + UINT8 blink_en,fore_col,back_col; + pen_t pen; + + if(vga.crtc.cursor_enable) + vga.cursor.visible = machine().first_screen()->frame_number() & 0x10; + else + vga.cursor.visible = 0; + + for (addr = vga.crtc.start_addr, line = -vga.crtc.preset_row_scan; line < TEXT_LINES; + line += height, addr += (offset()>>1)) + { + for (pos = addr, column=0; columnframe_number() & 0x20) ? attr & 0x80 : 0; + + fore_col = attr & 0xf; + back_col = (attr & 0x70) >> 4; + back_col |= (vga.attribute.data[0x10]&8) ? 0 : ((attr & 0x80) >> 4); + + for (h = MAX(-line, 0); (h < height) && (line+h < MIN(TEXT_LINES, bitmap.height())); h++) + { + bitmapline = &bitmap.pix32(line+h); + bits = vga.memory[font_base+(h>>(vga.crtc.scan_doubling))]; + + for (mask=0x80, w=0; (w>=1) + { + if (bits&mask) + pen = vga.pens[blink_en ? back_col : fore_col]; + else + pen = vga.pens[back_col]; + + if(!machine().first_screen()->visible_area().contains(column*width+w, line+h)) + continue; + bitmapline[column*width+w] = pen; + + } + if (wvisible_area().contains(column*width+w, line+h)) + continue; + bitmapline[column*width+w] = pen; + } + } + if (vga.cursor.visible&&(pos==vga.crtc.cursor_addr)) + { + for (h=vga.crtc.cursor_scan_start; + (h<=vga.crtc.cursor_scan_end)&&(hvisible_area().contains(column*width, line+h)) + continue; + bitmap.plot_box(column*width, line+h, width, 1, vga.pens[attr&0xf]); + } + } + } + } +} + +void vga_device::vga_vh_ega(bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + int pos, line, column, c, addr, i, yi; + int height = vga.crtc.maximum_scan_line * (vga.crtc.scan_doubling + 1); + UINT32 *bitmapline; + pen_t pen; + int pel_shift = (vga.attribute.pel_shift & 7); + +// popmessage("%08x %02x",EGA_START_ADDRESS,pel_shift); + + /**/ + for (addr=EGA_START_ADDRESS, pos=0, line=0; line= 0; i--) + { + pen = vga.pens[(data[0]&1) | (data[1]&2) | (data[2]&4) | (data[3]&8)]; + + data[0]>>=1; + data[1]>>=1; + data[2]>>=1; + data[3]>>=1; + + if(!machine().first_screen()->visible_area().contains(c+i-pel_shift, line + yi)) + continue; + bitmapline[c+i-pel_shift] = pen; + } + } + } + } +} + +/* TODO: I'm guessing that in 256 colors mode every pixel actually outputs two pixels. Is it right? */ +void vga_device::vga_vh_vga(bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + int pos, line, column, c, addr, curr_addr; + UINT32 *bitmapline; + UINT16 mask_comp; + int height = vga.crtc.maximum_scan_line * (vga.crtc.scan_doubling + 1); + int yi; + int xi; + int pel_shift = (vga.attribute.pel_shift & 6); + + /* line compare is screen sensitive */ + mask_comp = 0x3ff; //| (LINES & 0x300); + +// popmessage("%02x %02x",vga.attribute.pel_shift,vga.sequencer.data[4] & 0x08); + + curr_addr = 0; + if(!(vga.sequencer.data[4] & 0x08)) + { + for (addr = VGA_START_ADDRESS, line=0; line 0x80000/4) + return; + + for(xi=0;xi<8;xi++) + { + if(!machine().first_screen()->visible_area().contains(c+xi-(pel_shift), line + yi)) + continue; + bitmapline[c+xi-(pel_shift)] = m_palette->pen(vga.memory[(pos & 0xffff)+((xi >> 1)*0x10000)]); + } + } + } + } + } + else + { + for (addr = VGA_START_ADDRESS, line=0; line 0x80000) + return; + + for(xi=0;xi<0x10;xi++) + { + if(!machine().first_screen()->visible_area().contains(c+xi-(pel_shift), line + yi)) + continue; + bitmapline[c+xi-pel_shift] = m_palette->pen(vga.memory[(pos+(xi >> 1)) & 0xffff]); + } + } + } + } + } +} + +void vga_device::vga_vh_cga(bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + UINT32 *bitmapline; + int height = (vga.crtc.scan_doubling + 1); + int x,xi,y,yi; + UINT32 addr; + pen_t pen; + int width; + + width = (vga.crtc.horz_disp_end + 1) * 8; + + for(y=0;y> 1) * width/4); + + for(x=0;x> (6-xi*2)) & 3]; + if(!machine().first_screen()->visible_area().contains(x+xi, y * height + yi)) + continue; + bitmapline[x+xi] = pen; + } + } + + addr++; + } + } +} + +void vga_device::vga_vh_mono(bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + UINT32 *bitmapline; + int height = (vga.crtc.scan_doubling + 1); + int x,xi,y,yi; + UINT32 addr; + pen_t pen; + int width; + + width = (vga.crtc.horz_disp_end + 1) * 8; + + for(y=0;y> 1) * width/8); + + for(x=0;x> (7-xi)) & 1]; + if(!machine().first_screen()->visible_area().contains(x+xi, y * height + yi)) + continue; + bitmapline[x+xi] = pen; + } + } + + addr++; + } + } +} + +void svga_device::svga_vh_rgb8(bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + int pos, line, column, c, addr, curr_addr; + UINT32 *bitmapline; + UINT16 mask_comp; + int height = vga.crtc.maximum_scan_line * (vga.crtc.scan_doubling + 1); + int yi; + int xi; + UINT8 start_shift; +// UINT16 line_length; + + /* line compare is screen sensitive */ + mask_comp = 0x3ff; + curr_addr = 0; +// if(vga.crtc.dw) +// line_length = vga.crtc.offset << 3; // doubleword mode +// else +// { +// line_length = vga.crtc.offset << 4; +// } + + start_shift = (!(vga.sequencer.data[4] & 0x08)) ? 2 : 0; + { + for (addr = VGA_START_ADDRESS << start_shift, line=0; line= vga.svga_intf.vram_size) + return; + + for(xi=0;xi<8;xi++) + { + if(!machine().first_screen()->visible_area().contains(c+xi, line + yi)) + continue; + bitmapline[c+xi] = m_palette->pen(vga.memory[(pos+(xi))]); + } + } + } + } + } +} + +void svga_device::svga_vh_rgb15(bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + #define MV(x) (vga.memory[x]+(vga.memory[x+1]<<8)) + #define IV 0xff000000 + int height = vga.crtc.maximum_scan_line * (vga.crtc.scan_doubling + 1); + int xi; + int yi; + int xm; + int pos, line, column, c, addr, curr_addr; + + UINT32 *bitmapline; +// UINT16 mask_comp; + + /* line compare is screen sensitive */ +// mask_comp = 0xff | (TLINES & 0x300); + curr_addr = 0; + yi=0; + for (addr = TGA_START_ADDRESS, line=0; line= vga.svga_intf.vram_size) + return; + for(xi=0,xm=0;xi<8;xi++,xm+=2) + { + int r,g,b; + + if(!machine().first_screen()->visible_area().contains(c+xi, line + yi)) + continue; + + r = (MV(pos+xm)&0x7c00)>>10; + g = (MV(pos+xm)&0x03e0)>>5; + b = (MV(pos+xm)&0x001f)>>0; + r = (r << 3) | (r & 0x7); + g = (g << 3) | (g & 0x7); + b = (b << 3) | (b & 0x7); + bitmapline[c+xi] = IV|(r<<16)|(g<<8)|(b<<0); + } + } + } +} + +void svga_device::svga_vh_rgb16(bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + #define MV(x) (vga.memory[x]+(vga.memory[x+1]<<8)) + #define IV 0xff000000 + int height = vga.crtc.maximum_scan_line * (vga.crtc.scan_doubling + 1); + int xi; + int yi; + int xm; + int pos, line, column, c, addr, curr_addr; + + UINT32 *bitmapline; +// UINT16 mask_comp; + + /* line compare is screen sensitive */ +// mask_comp = 0xff | (TLINES & 0x300); + curr_addr = 0; + yi=0; + for (addr = TGA_START_ADDRESS, line=0; line= vga.svga_intf.vram_size) + return; + for(xi=0,xm=0;xi<8;xi++,xm+=2) + { + int r,g,b; + + if(!machine().first_screen()->visible_area().contains(c+xi, line + yi)) + continue; + + r = (MV(pos+xm)&0xf800)>>11; + g = (MV(pos+xm)&0x07e0)>>5; + b = (MV(pos+xm)&0x001f)>>0; + r = (r << 3) | (r & 0x7); + g = (g << 2) | (g & 0x3); + b = (b << 3) | (b & 0x7); + bitmapline[c+xi] = IV|(r<<16)|(g<<8)|(b<<0); + } + } + } +} + +void svga_device::svga_vh_rgb24(bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + #define MD(x) (vga.memory[x]+(vga.memory[x+1]<<8)+(vga.memory[x+2]<<16)) + #define ID 0xff000000 + int height = vga.crtc.maximum_scan_line * (vga.crtc.scan_doubling + 1); + int xi; + int yi; + int xm; + int pos, line, column, c, addr, curr_addr; + UINT32 *bitmapline; + +// UINT16 mask_comp; + + /* line compare is screen sensitive */ +// mask_comp = 0xff | (TLINES & 0x300); + curr_addr = 0; + yi=0; + for (addr = TGA_START_ADDRESS<<1, line=0; line= vga.svga_intf.vram_size) + return; + for(xi=0,xm=0;xi<8;xi++,xm+=3) + { + int r,g,b; + + if(!machine().first_screen()->visible_area().contains(c+xi, line + yi)) + continue; + + r = (MD(pos+xm)&0xff0000)>>16; + g = (MD(pos+xm)&0x00ff00)>>8; + b = (MD(pos+xm)&0x0000ff)>>0; + bitmapline[c+xi] = IV|(r<<16)|(g<<8)|(b<<0); + } + } + } +} + +void svga_device::svga_vh_rgb32(bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + #define MD(x) (vga.memory[x]+(vga.memory[x+1]<<8)+(vga.memory[x+2]<<16)) + #define ID 0xff000000 + int height = vga.crtc.maximum_scan_line * (vga.crtc.scan_doubling + 1); + int xi; + int yi; + int xm; + int pos, line, column, c, addr, curr_addr; + UINT32 *bitmapline; + +// UINT16 mask_comp; + + /* line compare is screen sensitive */ +// mask_comp = 0xff | (TLINES & 0x300); + curr_addr = 0; + yi=0; + for (addr = TGA_START_ADDRESS, line=0; line= vga.svga_intf.vram_size) + return; + for(xi=0,xm=0;xi<8;xi++,xm+=4) + { + int r,g,b; + + if(!machine().first_screen()->visible_area().contains(c+xi, line + yi)) + continue; + + r = (MD(pos+xm)&0xff0000)>>16; + g = (MD(pos+xm)&0x00ff00)>>8; + b = (MD(pos+xm)&0x0000ff)>>0; + bitmapline[c+xi] = IV|(r<<16)|(g<<8)|(b<<0); + } + } + } +} + +UINT8 vga_device::pc_vga_choosevideomode() +{ + int i; + + if (vga.crtc.sync_en) + { + if (vga.dac.dirty) + { + for (i=0; i<256;i++) + { + /* TODO: color shifters? */ + m_palette->set_pen_color(i, (vga.dac.color[i & vga.dac.mask].red & 0x3f) << 2, + (vga.dac.color[i & vga.dac.mask].green & 0x3f) << 2, + (vga.dac.color[i & vga.dac.mask].blue & 0x3f) << 2); + } + vga.dac.dirty = 0; + } + + if (vga.attribute.data[0x10] & 0x80) + { + for (i=0; i<16;i++) + { + vga.pens[i] = m_palette->pen((vga.attribute.data[i]&0x0f) + |((vga.attribute.data[0x14]&0xf)<<4)); + } + } + else + { + for (i=0; i<16;i++) + { + vga.pens[i]=m_palette->pen((vga.attribute.data[i]&0x3f) + |((vga.attribute.data[0x14]&0xc)<<4)); + } + } + + if (!GRAPHIC_MODE) + { + return TEXT_MODE; + } + else if (vga.gc.shift256) + { + return VGA_MODE; + } + else if (vga.gc.shift_reg) + { + return CGA_MODE; + } + else if (vga.gc.memory_map_sel == 0x03) + { + return MONO_MODE; + } + else + { + return EGA_MODE; + } + } + + return SCREEN_OFF; +} + + +UINT8 svga_device::pc_vga_choosevideomode() +{ + int i; + + if (vga.crtc.sync_en) + { + if (vga.dac.dirty) + { + for (i=0; i<256;i++) + { + /* TODO: color shifters? */ + m_palette->set_pen_color(i, (vga.dac.color[i & vga.dac.mask].red & 0x3f) << 2, + (vga.dac.color[i & vga.dac.mask].green & 0x3f) << 2, + (vga.dac.color[i & vga.dac.mask].blue & 0x3f) << 2); + } + vga.dac.dirty = 0; + } + + if (vga.attribute.data[0x10] & 0x80) + { + for (i=0; i<16;i++) + { + vga.pens[i] = m_palette->pen((vga.attribute.data[i]&0x0f) + |((vga.attribute.data[0x14]&0xf)<<4)); + } + } + else + { + for (i=0; i<16;i++) + { + vga.pens[i]=m_palette->pen((vga.attribute.data[i]&0x3f) + |((vga.attribute.data[0x14]&0xc)<<4)); + } + } + + if (svga.rgb32_en) + { + return RGB32_MODE; + } + else if (svga.rgb24_en) + { + return RGB24_MODE; + } + else if (svga.rgb16_en) + { + return RGB16_MODE; + } + else if (svga.rgb15_en) + { + return RGB15_MODE; + } + else if (svga.rgb8_en) + { + return RGB8_MODE; + } + else if (!GRAPHIC_MODE) + { + return TEXT_MODE; + } + else if (vga.gc.shift256) + { + return VGA_MODE; + } + else if (vga.gc.shift_reg) + { + return CGA_MODE; + } + else if (vga.gc.memory_map_sel == 0x03) + { + return MONO_MODE; + } + else + { + return EGA_MODE; + } + } + + return SCREEN_OFF; +} + + +UINT32 vga_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + UINT8 cur_mode = pc_vga_choosevideomode(); + switch(cur_mode) + { + case SCREEN_OFF: bitmap.fill (m_palette->black_pen(), cliprect);break; + case TEXT_MODE: vga_vh_text (bitmap, cliprect); break; + case VGA_MODE: vga_vh_vga (bitmap, cliprect); break; + case EGA_MODE: vga_vh_ega (bitmap, cliprect); break; + case CGA_MODE: vga_vh_cga (bitmap, cliprect); break; + case MONO_MODE: vga_vh_mono (bitmap, cliprect); break; + } + + return 0; +} + +UINT32 svga_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + UINT8 cur_mode = pc_vga_choosevideomode(); + + switch(cur_mode) + { + case SCREEN_OFF: bitmap.fill (m_palette->black_pen(), cliprect);break; + case TEXT_MODE: vga_vh_text (bitmap, cliprect); break; + case VGA_MODE: vga_vh_vga (bitmap, cliprect); break; + case EGA_MODE: vga_vh_ega (bitmap, cliprect); break; + case CGA_MODE: vga_vh_cga (bitmap, cliprect); break; + case MONO_MODE: vga_vh_mono (bitmap, cliprect); break; + case RGB8_MODE: svga_vh_rgb8 (bitmap, cliprect); break; + case RGB15_MODE: svga_vh_rgb15(bitmap, cliprect); break; + case RGB16_MODE: svga_vh_rgb16(bitmap, cliprect); break; + case RGB24_MODE: svga_vh_rgb24(bitmap, cliprect); break; + case RGB32_MODE: svga_vh_rgb32(bitmap, cliprect); break; + } + + return 0; +} + +UINT32 s3_vga_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + UINT8 cur_mode = 0; + + svga_device::screen_update(screen, bitmap, cliprect); + + cur_mode = pc_vga_choosevideomode(); + + // draw hardware graphics cursor + // TODO: support 16 bit and greater video modes + if(s3.cursor_mode & 0x01) // if cursor is enabled + { + UINT32 src; + UINT32* dst; + UINT8 val; + int x,y; + UINT16 cx = s3.cursor_x & 0x07ff; + UINT16 cy = s3.cursor_y & 0x07ff; + UINT32 bg_col; + UINT32 fg_col; + + if(cur_mode == SCREEN_OFF || cur_mode == TEXT_MODE || cur_mode == MONO_MODE || cur_mode == CGA_MODE || cur_mode == EGA_MODE) + return 0; // cursor only works in VGA or SVGA modes + + src = s3.cursor_start_addr * 1024; // start address is in units of 1024 bytes + + if(cur_mode == RGB16_MODE) + { + int r,g,b; + UINT16 datax; + + datax = s3.cursor_bg[0]|s3.cursor_bg[1]<<8; + r = (datax&0xf800)>>11; + g = (datax&0x07e0)>>5; + b = (datax&0x001f)>>0; + r = (r << 3) | (r & 0x7); + g = (g << 2) | (g & 0x3); + b = (b << 3) | (b & 0x7); + bg_col = (0xff<<24)|(r<<16)|(g<<8)|(b<<0); + + datax = s3.cursor_fg[0]|s3.cursor_fg[1]<<8; + r = (datax&0xf800)>>11; + g = (datax&0x07e0)>>5; + b = (datax&0x001f)>>0; + r = (r << 3) | (r & 0x7); + g = (g << 2) | (g & 0x3); + b = (b << 3) | (b & 0x7); + fg_col = (0xff<<24)|(r<<16)|(g<<8)|(b<<0); + } + else /* TODO: other modes */ + { + bg_col = m_palette->pen(s3.cursor_bg[0]); + fg_col = m_palette->pen(s3.cursor_fg[0]); + } + + //popmessage("%08x %08x",(s3.cursor_bg[0])|(s3.cursor_bg[1]<<8)|(s3.cursor_bg[2]<<16)|(s3.cursor_bg[3]<<24) + // ,(s3.cursor_fg[0])|(s3.cursor_fg[1]<<8)|(s3.cursor_fg[2]<<16)|(s3.cursor_fg[3]<<24)); +// for(x=0;x<64;x++) +// printf("%08x: %02x %02x %02x %02x\n",src+x*4,vga.memory[src+x*4],vga.memory[src+x*4+1],vga.memory[src+x*4+2],vga.memory[src+x*4+3]); + for(y=0;y<64;y++) + { + dst = &bitmap.pix32(cy + y, cx); + for(x=0;x<64;x++) + { + UINT16 bita = (vga.memory[(src+1) % vga.svga_intf.vram_size] | ((vga.memory[(src+0) % vga.svga_intf.vram_size]) << 8)) >> (15-(x % 16)); + UINT16 bitb = (vga.memory[(src+3) % vga.svga_intf.vram_size] | ((vga.memory[(src+2) % vga.svga_intf.vram_size]) << 8)) >> (15-(x % 16)); + val = ((bita & 0x01) << 1) | (bitb & 0x01); + if(s3.extended_dac_ctrl & 0x10) + { // X11 mode + switch(val) + { + case 0x00: + // no change + break; + case 0x01: + // no change + break; + case 0x02: + dst[x] = bg_col; + break; + case 0x03: + dst[x] = fg_col; + break; + } + } + else + { // Windows mode + switch(val) + { + case 0x00: + dst[x] = bg_col; + break; + case 0x01: + dst[x] = fg_col; + break; + case 0x02: // screen data + // no change + break; + case 0x03: // inverted screen data + dst[x] = ~(dst[x]); + break; + } + } + if(x % 16 == 15) + src+=4; + } + } + } + return 0; +} + + +/***************************************************************************/ + +inline UINT8 vga_device::vga_latch_write(int offs, UINT8 data) +{ + UINT8 res = 0; + + switch (vga.gc.write_mode & 3) { + case 0: + data = rotate_right(data); + if(vga.gc.enable_set_reset & 1<> 4; + res |= (vga.crtc.vert_retrace_start & 0x200) >> 2; + res |= (vga.crtc.vert_disp_end & 0x200) >> 3; + res |= (vga.crtc.vert_total & 0x200) >> 4; + res |= (vga.crtc.vert_blank_start & 0x100) >> 5; + res |= (vga.crtc.vert_retrace_start & 0x100) >> 6; + res |= (vga.crtc.vert_disp_end & 0x100) >> 7; + res |= (vga.crtc.vert_total & 0x100) >> 8; + break; + case 0x08: // Preset Row Scan Register + res = (vga.crtc.byte_panning & 3) << 5; + res |= (vga.crtc.preset_row_scan & 0x1f); + break; + case 0x09: // Maximum Scan Line Register + res = (vga.crtc.maximum_scan_line - 1) & 0x1f; + res |= (vga.crtc.scan_doubling & 1) << 7; + res |= (vga.crtc.line_compare & 0x200) >> 3; + res |= (vga.crtc.vert_blank_start & 0x200) >> 4; + break; + case 0x0a: + res = (vga.crtc.cursor_scan_start & 0x1f); + res |= ((vga.crtc.cursor_enable & 1) ^ 1) << 5; + break; + case 0x0b: + res = (vga.crtc.cursor_skew & 3) << 5; + res |= (vga.crtc.cursor_scan_end & 0x1f); + break; + case 0x0c: + case 0x0d: + res = (vga.crtc.start_addr_latch >> ((index & 1) ^ 1)*8) & 0xff; + break; + case 0x0e: + case 0x0f: + res = (vga.crtc.cursor_addr >> ((index & 1) ^ 1)*8) & 0xff; + break; + case 0x10: + res = vga.crtc.vert_retrace_start & 0xff; + break; + case 0x11: + res = (vga.crtc.protect_enable & 1) << 7; + res |= (vga.crtc.bandwidth & 1) << 6; + res |= (vga.crtc.vert_retrace_end & 0xf); + res |= (vga.crtc.irq_clear & 1) << 4; + res |= (vga.crtc.irq_disable & 1) << 5; + break; + case 0x12: + res = vga.crtc.vert_disp_end & 0xff; + break; + case 0x13: + res = vga.crtc.offset & 0xff; + break; + case 0x14: + res = (vga.crtc.dw & 1) << 6; + res |= (vga.crtc.div4 & 1) << 5; + res |= (vga.crtc.underline_loc & 0x1f); + break; + case 0x15: + res = vga.crtc.vert_blank_start & 0xff; + break; + case 0x16: + res = vga.crtc.vert_blank_end & 0x7f; + break; + case 0x17: + res = (vga.crtc.sync_en & 1) << 7; + res |= (vga.crtc.word_mode & 1) << 6; + res |= (vga.crtc.aw & 1) << 5; + res |= (vga.crtc.div2 & 1) << 3; + res |= (vga.crtc.sldiv & 1) << 2; + res |= (vga.crtc.map14 & 1) << 1; + res |= (vga.crtc.map13 & 1) << 0; + break; + case 0x18: + res = vga.crtc.line_compare & 0xff; + break; + default: + printf("Unhandled CRTC reg r %02x\n",index); + break; + } + return res; +} + +void vga_device::recompute_params_clock(int divisor, int xtal) +{ + int vblank_period,hblank_period; + attoseconds_t refresh; + UINT8 hclock_m = (!GRAPHIC_MODE) ? CHAR_WIDTH : 8; + int pixel_clock; + + /* safety check */ + if(!vga.crtc.horz_disp_end || !vga.crtc.vert_disp_end || !vga.crtc.horz_total || !vga.crtc.vert_total) + return; + + rectangle visarea(0, ((vga.crtc.horz_disp_end + 1) * ((float)(hclock_m)/divisor))-1, 0, vga.crtc.vert_disp_end); + + vblank_period = (vga.crtc.vert_total + 2); + hblank_period = ((vga.crtc.horz_total + 5) * ((float)(hclock_m)/divisor)); + + /* TODO: 10b and 11b settings aren't known */ + pixel_clock = xtal / (((vga.sequencer.data[1]&8) >> 3) + 1); + + refresh = HZ_TO_ATTOSECONDS(pixel_clock) * (hblank_period) * vblank_period; + machine().first_screen()->configure((hblank_period), (vblank_period), visarea, refresh ); + //popmessage("%d %d\n",vga.crtc.horz_total * 8,vga.crtc.vert_total); + m_vblank_timer->adjust( machine().first_screen()->time_until_pos(vga.crtc.vert_blank_start + vga.crtc.vert_blank_end) ); +} + +void vga_device::recompute_params() +{ + if(vga.miscellaneous_output & 8) + logerror("Warning: VGA external clock latch selected\n"); + else + recompute_params_clock(1, (vga.miscellaneous_output & 0xc) ? XTAL_28_63636MHz : XTAL_25_1748MHz); +} + +void vga_device::crtc_reg_write(UINT8 index, UINT8 data) +{ + /* Doom does this */ +// if(vga.crtc.protect_enable && index <= 0x07) +// printf("write to protected address %02x\n",index); + switch(index) + { + case 0x00: + if(vga.crtc.protect_enable) + break; + vga.crtc.horz_total = (vga.crtc.horz_total & ~0xff) | (data & 0xff); + recompute_params(); + break; + case 0x01: + if(vga.crtc.protect_enable) + break; + vga.crtc.horz_disp_end = (data & 0xff); + recompute_params(); + break; + case 0x02: + if(vga.crtc.protect_enable) + break; + vga.crtc.horz_blank_start = (data & 0xff); + break; + case 0x03: + if(vga.crtc.protect_enable) + break; + vga.crtc.horz_blank_end &= ~0x1f; + vga.crtc.horz_blank_end |= data & 0x1f; + vga.crtc.disp_enable_skew = (data & 0x60) >> 5; + vga.crtc.evra = (data & 0x80) >> 7; + break; + case 0x04: + if(vga.crtc.protect_enable) + break; + vga.crtc.horz_retrace_start = data & 0xff; + break; + case 0x05: + if(vga.crtc.protect_enable) + break; + vga.crtc.horz_blank_end &= ~0x20; + vga.crtc.horz_blank_end |= ((data & 0x80) >> 2); + vga.crtc.horz_retrace_skew = ((data & 0x60) >> 5); + vga.crtc.horz_retrace_end = data & 0x1f; + break; + case 0x06: + if(vga.crtc.protect_enable) + break; + vga.crtc.vert_total &= ~0xff; + vga.crtc.vert_total |= data & 0xff; + recompute_params(); + break; + case 0x07: // Overflow Register + vga.crtc.line_compare &= ~0x100; + vga.crtc.line_compare |= ((data & 0x10) << (8-4)); + if(vga.crtc.protect_enable) + break; + vga.crtc.vert_total &= ~0x300; + vga.crtc.vert_retrace_start &= ~0x300; + vga.crtc.vert_disp_end &= ~0x300; + vga.crtc.vert_blank_start &= ~0x100; + vga.crtc.vert_retrace_start |= ((data & 0x80) << (9-7)); + vga.crtc.vert_disp_end |= ((data & 0x40) << (9-6)); + vga.crtc.vert_total |= ((data & 0x20) << (9-5)); + vga.crtc.vert_blank_start |= ((data & 0x08) << (8-3)); + vga.crtc.vert_retrace_start |= ((data & 0x04) << (8-2)); + vga.crtc.vert_disp_end |= ((data & 0x02) << (8-1)); + vga.crtc.vert_total |= ((data & 0x01) << (8-0)); + recompute_params(); + break; + case 0x08: // Preset Row Scan Register + vga.crtc.byte_panning = (data & 0x60) >> 5; + vga.crtc.preset_row_scan = (data & 0x1f); + break; + case 0x09: // Maximum Scan Line Register + vga.crtc.line_compare &= ~0x200; + vga.crtc.vert_blank_start &= ~0x200; + vga.crtc.scan_doubling = ((data & 0x80) >> 7); + vga.crtc.line_compare |= ((data & 0x40) << (9-6)); + vga.crtc.vert_blank_start |= ((data & 0x20) << (9-5)); + vga.crtc.maximum_scan_line = (data & 0x1f) + 1; + break; + case 0x0a: + vga.crtc.cursor_enable = ((data & 0x20) ^ 0x20) >> 5; + vga.crtc.cursor_scan_start = data & 0x1f; + break; + case 0x0b: + vga.crtc.cursor_skew = (data & 0x60) >> 5; + vga.crtc.cursor_scan_end = data & 0x1f; + break; + case 0x0c: + case 0x0d: + vga.crtc.start_addr_latch &= ~(0xff << (((index & 1)^1) * 8)); + vga.crtc.start_addr_latch |= (data << (((index & 1)^1) * 8)); + break; + case 0x0e: + case 0x0f: + vga.crtc.cursor_addr &= ~(0xff << (((index & 1)^1) * 8)); + vga.crtc.cursor_addr |= (data << (((index & 1)^1) * 8)); + break; + case 0x10: + vga.crtc.vert_retrace_start &= ~0xff; + vga.crtc.vert_retrace_start |= data & 0xff; + break; + case 0x11: + vga.crtc.protect_enable = (data & 0x80) >> 7; + vga.crtc.bandwidth = (data & 0x40) >> 6; + vga.crtc.vert_retrace_end = data & 0x0f; + vga.crtc.irq_clear = (data & 0x10) >> 4; + vga.crtc.irq_disable = (data & 0x20) >> 5; + break; + case 0x12: + vga.crtc.vert_disp_end &= ~0xff; + vga.crtc.vert_disp_end |= data & 0xff; + recompute_params(); + break; + case 0x13: + vga.crtc.offset &= ~0xff; + vga.crtc.offset |= data & 0xff; + break; + case 0x14: + vga.crtc.dw = (data & 0x40) >> 6; + vga.crtc.div4 = (data & 0x20) >> 5; + vga.crtc.underline_loc = (data & 0x1f); + break; + case 0x15: + vga.crtc.vert_blank_start &= ~0xff; + vga.crtc.vert_blank_start |= data & 0xff; + break; + case 0x16: + vga.crtc.vert_blank_end = data & 0x7f; + break; + case 0x17: + vga.crtc.sync_en = (data & 0x80) >> 7; + vga.crtc.word_mode = (data & 0x40) >> 6; + vga.crtc.aw = (data & 0x20) >> 5; + vga.crtc.div2 = (data & 0x08) >> 3; + vga.crtc.sldiv = (data & 0x04) >> 2; + vga.crtc.map14 = (data & 0x02) >> 1; + vga.crtc.map13 = (data & 0x01) >> 0; + break; + case 0x18: + vga.crtc.line_compare &= ~0xff; + vga.crtc.line_compare |= data & 0xff; + break; + default: + logerror("Unhandled CRTC reg w %02x %02x\n",index,data); + break; + } +} + +void vga_device::seq_reg_write(UINT8 index, UINT8 data) +{ + switch(index) + { + case 0x02: + vga.sequencer.map_mask = data & 0xf; + break; + case 0x03: + /* --2- 84-- character select A + ---2 --84 character select B */ + vga.sequencer.char_sel.A = (((data & 0xc) >> 2)<<1) | ((data & 0x20) >> 5); + vga.sequencer.char_sel.B = (((data & 0x3) >> 0)<<1) | ((data & 0x10) >> 4); + if(data) + popmessage("Char SEL checker, contact MAMEdev (%02x %02x)\n",vga.sequencer.char_sel.A,vga.sequencer.char_sel.B); + break; + } +} + +UINT8 vga_device::vga_vblank() +{ + UINT8 res; + UINT16 vblank_start,vblank_end,vpos; + + /* calculate vblank start / end positions */ + res = 0; + vblank_start = vga.crtc.vert_blank_start; + vblank_end = vga.crtc.vert_blank_start + vga.crtc.vert_blank_end; + vpos = machine().first_screen()->vpos(); + + /* check if we are under vblank period */ + if(vblank_end > vga.crtc.vert_total) + { + vblank_end -= vga.crtc.vert_total; + if(vpos >= vblank_start || vpos <= vblank_end) + res = 1; + } + else + { + if(vpos >= vblank_start && vpos <= vblank_end) + res = 1; + } + + //popmessage("%d %d %d - SR1=%02x",vblank_start,vblank_end,vga.crtc.vert_total,vga.sequencer.data[1]); + + return res; +} + +READ8_MEMBER(vga_device::vga_crtc_r) +{ + UINT8 data = 0xff; + + switch (offset) { + case 4: + data = vga.crtc.index; + break; + case 5: + data = crtc_reg_read(vga.crtc.index); + break; + case 0xa: + UINT8 hsync,vsync; + vga.attribute.state = 0; + data = 0; + + hsync = space.machine().first_screen()->hblank() & 1; + vsync = vga_vblank(); //space.machine().first_screen()->vblank() & 1; + + data |= (hsync | vsync) & 1; // DD - display disable register + data |= (vsync & 1) << 3; // VRetrace register + + /* ega diagnostic readback enough for oak bios */ + switch (vga.attribute.data[0x12]&0x30) { + case 0: + if (vga.attribute.data[0x11]&1) data|=0x10; + if (vga.attribute.data[0x11]&4) data|=0x20; + break; + case 0x10: + data|=(vga.attribute.data[0x11]&0x30); + break; + case 0x20: + if (vga.attribute.data[0x11]&2) data|=0x10; + if (vga.attribute.data[0x11]&8) data|=0x20; + break; + case 0x30: + data|=(vga.attribute.data[0x11]&0xc0)>>2; + break; + } + break; + case 0xf: + /* oak test */ + //data=0; + /* pega bios on/off */ + data=0x80; + break; + } + return data; +} + +WRITE8_MEMBER(vga_device::vga_crtc_w) +{ + switch (offset) + { + case 4: + vga.crtc.index = data; + break; + + case 5: + if (LOG_REGISTERS) + { + logerror("vga_crtc_w(): CRTC[0x%02X%s] = 0x%02X\n", + vga.crtc.index, + (vga.crtc.index < vga.svga_intf.crtc_regcount) ? "" : "?", + data); + } + + crtc_reg_write(vga.crtc.index,data); + //space.machine().first_screen()->update_partial(space.machine().first_screen()->vpos()); + #if 0 + if((vga.crtc.index & 0xfe) != 0x0e) + printf("%02x %02x %d\n",vga.crtc.index,data,space.machine().first_screen()->vpos()); + #endif + break; + + case 0xa: + vga.feature_control = data; + break; + } +} + + + +READ8_MEMBER(vga_device::port_03b0_r) +{ + UINT8 data = 0xff; + if (CRTC_PORT_ADDR==0x3b0) + data=vga_crtc_r(space, offset, mem_mask); + return data; +} + +UINT8 vga_device::gc_reg_read(UINT8 index) +{ + UINT8 res; + + switch(index) + { + case 0x00: + res = vga.gc.set_reset & 0xf; + break; + case 0x01: + res = vga.gc.enable_set_reset & 0xf; + break; + case 0x02: + res = vga.gc.color_compare & 0xf; + break; + case 0x03: + res = (vga.gc.logical_op & 3) << 3; + res |= (vga.gc.rotate_count & 7); + break; + case 0x04: + res = vga.gc.read_map_sel & 3; + break; + case 0x05: + res = (vga.gc.shift256 & 1) << 6; + res |= (vga.gc.shift_reg & 1) << 5;; + res |= (vga.gc.host_oe & 1) << 4; + res |= (vga.gc.read_mode & 1) << 3; + res |= (vga.gc.write_mode & 3); + break; + case 0x06: + res = (vga.gc.memory_map_sel & 3) << 2; + res |= (vga.gc.chain_oe & 1) << 1; + res |= (vga.gc.alpha_dis & 1); + break; + case 0x07: + res = vga.gc.color_dont_care & 0xf; + break; + case 0x08: + res = vga.gc.bit_mask & 0xff; + break; + default: + res = 0xff; + break; + } + + return res; +} + +READ8_MEMBER(vga_device::port_03c0_r) +{ + UINT8 data = 0xff; + + switch (offset) + { + case 0: + data = vga.attribute.index; + break; + case 1: + if((vga.attribute.index&0x20) + && ((vga.attribute.index&0x1f)<0x10)) + data = 0; // palette access is disabled in this mode + else if ((vga.attribute.index&0x1f)>2)&3) + { + case 3: + if (!vga.read_dipswitch.isnull() && vga.read_dipswitch(space, 0, mem_mask) & 0x01) + data |= 0x10; + else + data |= 0x10; + break; + case 2: + if (!vga.read_dipswitch.isnull() && vga.read_dipswitch(space, 0, mem_mask) & 0x02) + data |= 0x10; + else + data |= 0x10; + break; + case 1: + if (!vga.read_dipswitch.isnull() && vga.read_dipswitch(space, 0, mem_mask) & 0x04) + data |= 0x10; + else + data |= 0x10; + break; + case 0: + if (!vga.read_dipswitch.isnull() && vga.read_dipswitch(space, 0, mem_mask) & 0x08) + data |= 0x10; + else + data |= 0x10; + break; + } + break; + + case 3: + data = vga.oak.reg; + break; + + case 4: + data = vga.sequencer.index; + break; + + case 5: + if (vga.sequencer.index < vga.svga_intf.seq_regcount) + data = vga.sequencer.data[vga.sequencer.index]; + break; + + case 6: + data = vga.dac.mask; + break; + + case 7: + data = (vga.dac.read) ? 3 : 0; + break; + + case 8: + data = vga.dac.write_index; + break; + + case 9: + if (vga.dac.read) + { + switch (vga.dac.state++) + { + case 0: + data = vga.dac.color[vga.dac.read_index].red; + break; + case 1: + data = vga.dac.color[vga.dac.read_index].green; + break; + case 2: + data = vga.dac.color[vga.dac.read_index].blue; + break; + } + + if (vga.dac.state==3) + { + vga.dac.state = 0; + vga.dac.read_index++; + } + } + break; + + case 0xa: + data = vga.feature_control; + break; + + case 0xc: + data = vga.miscellaneous_output; + break; + + case 0xe: + data = vga.gc.index; + break; + + case 0xf: + data = gc_reg_read(vga.gc.index); + break; + } + return data; +} + +READ8_MEMBER(vga_device::port_03d0_r) +{ + UINT8 data = 0xff; + if (CRTC_PORT_ADDR == 0x3d0) + data = vga_crtc_r(space, offset, mem_mask); + if(offset == 8) + { + logerror("VGA: 0x3d8 read at %08x\n",space.device().safe_pc()); + data = 0; // TODO: PC-200 reads back CGA register here, everything else returns open bus OR CGA emulation of register 0x3d8 + } + + return data; +} + +WRITE8_MEMBER(vga_device::port_03b0_w) +{ + if (LOG_ACCESSES) + logerror("vga_port_03b0_w(): port=0x%04x data=0x%02x\n", offset + 0x3b0, data); + + if (CRTC_PORT_ADDR == 0x3b0) + vga_crtc_w(space, offset, data, mem_mask); +} + +void vga_device::attribute_reg_write(UINT8 index, UINT8 data) +{ + if((index & 0x30) == 0) + { + //if(vga.sequencer.data[1]&0x20) // ok? + vga.attribute.data[index & 0x1f] = data & 0x3f; + } + else + { + switch(index & 0x1f) + { + /* TODO: intentional dirtiness, variable names to be properly changed */ + case 0x10: vga.attribute.data[0x10] = data; break; + case 0x11: vga.attribute.data[0x11] = data; break; + case 0x12: vga.attribute.data[0x12] = data; break; + case 0x13: vga.attribute.pel_shift_latch = vga.attribute.data[0x13] = data; break; + case 0x14: vga.attribute.data[0x14] = data; break; + } + } +} + +void vga_device::gc_reg_write(UINT8 index,UINT8 data) +{ + switch(index) + { + case 0x00: + vga.gc.set_reset = data & 0xf; + break; + case 0x01: + vga.gc.enable_set_reset = data & 0xf; + break; + case 0x02: + vga.gc.color_compare = data & 0xf; + break; + case 0x03: + vga.gc.logical_op = (data & 0x18) >> 3; + vga.gc.rotate_count = data & 7; + break; + case 0x04: + vga.gc.read_map_sel = data & 3; + break; + case 0x05: + vga.gc.shift256 = (data & 0x40) >> 6; + vga.gc.shift_reg = (data & 0x20) >> 5; + vga.gc.host_oe = (data & 0x10) >> 4; + vga.gc.read_mode = (data & 8) >> 3; + vga.gc.write_mode = data & 3; + //if(data & 0x10 && vga.gc.alpha_dis) + // popmessage("Host O/E enabled, contact MAMEdev"); + break; + case 0x06: + vga.gc.memory_map_sel = (data & 0xc) >> 2; + vga.gc.chain_oe = (data & 2) >> 1; + vga.gc.alpha_dis = (data & 1); + //if(data & 2 && vga.gc.alpha_dis) + // popmessage("Chain O/E enabled, contact MAMEdev"); + break; + case 0x07: + vga.gc.color_dont_care = data & 0xf; + break; + case 0x08: + vga.gc.bit_mask = data & 0xff; + break; + } +} + +WRITE8_MEMBER(vga_device::port_03c0_w) +{ + if (LOG_ACCESSES) + logerror("vga_port_03c0_w(): port=0x%04x data=0x%02x\n", offset + 0x3c0, data); + + switch (offset) { + case 0: + if (vga.attribute.state==0) + { + vga.attribute.index=data; + } + else + { + attribute_reg_write(vga.attribute.index,data); + } + vga.attribute.state=!vga.attribute.state; + break; + case 2: + vga.miscellaneous_output=data; + recompute_params(); + break; + case 3: + vga.oak.reg = data; + break; + case 4: + vga.sequencer.index = data; + break; + case 5: + if (LOG_REGISTERS) + { + logerror("vga_port_03c0_w(): SEQ[0x%02X%s] = 0x%02X\n", + vga.sequencer.index, + (vga.sequencer.index < vga.svga_intf.seq_regcount) ? "" : "?", + data); + } + if (vga.sequencer.index < vga.svga_intf.seq_regcount) + { + vga.sequencer.data[vga.sequencer.index] = data; + } + + seq_reg_write(vga.sequencer.index,data); + recompute_params(); + break; + case 6: + vga.dac.mask=data; + vga.dac.dirty=1; + break; + case 7: + vga.dac.read_index=data; + vga.dac.state=0; + vga.dac.read=1; + break; + case 8: + vga.dac.write_index=data; + vga.dac.state=0; + vga.dac.read=0; + break; + case 9: + if (!vga.dac.read) + { + switch (vga.dac.state++) { + case 0: + vga.dac.color[vga.dac.write_index].red=data; + break; + case 1: + vga.dac.color[vga.dac.write_index].green=data; + break; + case 2: + vga.dac.color[vga.dac.write_index].blue=data; + break; + } + vga.dac.dirty=1; + if (vga.dac.state==3) { + vga.dac.state=0; vga.dac.write_index++; + } + } + break; + case 0xe: + vga.gc.index=data; + break; + case 0xf: + gc_reg_write(vga.gc.index,data); + break; + } +} + + + +WRITE8_MEMBER(vga_device::port_03d0_w) +{ + if (LOG_ACCESSES) + logerror("vga_port_03d0_w(): port=0x%04x data=0x%02x\n", offset + 0x3d0, data); + + if (CRTC_PORT_ADDR == 0x3d0) + vga_crtc_w(space, offset, data, mem_mask); +} + +void vga_device::device_reset() +{ + /* clear out the VGA structure */ + memset(vga.pens, 0, sizeof(vga.pens)); + vga.miscellaneous_output = 0; + vga.feature_control = 0; + vga.sequencer.index = 0; + memset(vga.sequencer.data, 0, sizeof(vga.sequencer.data)); + vga.crtc.index = 0; + memset(vga.crtc.data, 0, sizeof(vga.crtc.data)); + vga.gc.index = 0; + memset(vga.gc.latch, 0, sizeof(vga.gc.latch)); + memset(&vga.attribute, 0, sizeof(vga.attribute)); + memset(&vga.dac, 0, sizeof(vga.dac)); + memset(&vga.cursor, 0, sizeof(vga.cursor)); + memset(&vga.oak, 0, sizeof(vga.oak)); + + vga.gc.memory_map_sel = 0x3; /* prevent xtbios excepting vga ram as system ram */ +/* amstrad pc1640 bios relies on the position of + the video memory area, + so I introduced the reset to switch to b8000 area */ + vga.sequencer.data[4] = 0; + + /* TODO: real defaults */ + vga.crtc.line_compare = 0x3ff; + /* indiana.c boot PROM doesn't set this and assumes it's 0xff */ + vga.dac.mask = 0xff; +} + +void s3_vga_device::device_reset() +{ + vga_device::device_reset(); + // Power-on strapping bits. Sampled at reset, but can be modified later. + // These are just assumed defaults. + s3.strapping = 0x000f0b1e; + s3.sr10 = 0x42; + s3.sr11 = 0x41; +} + +READ8_MEMBER(vga_device::mem_r) +{ + /* TODO: check me */ + switch(vga.gc.memory_map_sel & 0x03) + { + case 0: break; + case 1: offset &= 0x0ffff; break; + case 2: offset -= 0x10000; offset &= 0x07fff; break; + case 3: offset -= 0x18000; offset &= 0x07fff; break; + } + + if(vga.sequencer.data[4] & 4) + { + int data; + if (!space.debugger_access()) + { + vga.gc.latch[0]=vga.memory[(offset)]; + vga.gc.latch[1]=vga.memory[(offset)+0x10000]; + vga.gc.latch[2]=vga.memory[(offset)+0x20000]; + vga.gc.latch[3]=vga.memory[(offset)+0x30000]; + } + + if (vga.gc.read_mode) + { + UINT8 byte,layer; + UINT8 fill_latch; + data=0; + + for(byte=0;byte<8;byte++) + { + fill_latch = 0; + for(layer=0;layer<4;layer++) + { + if(vga.gc.latch[layer] & 1 << byte) + fill_latch |= 1 << layer; + } + fill_latch &= vga.gc.color_dont_care; + if(fill_latch == vga.gc.color_compare) + data |= 1 << byte; + } + } + else + data=vga.gc.latch[vga.gc.read_map_sel]; + + return data; + } + else + { + // TODO: Guesswork, probably not right + UINT8 i,data; + + data = 0; + //printf("%08x\n",offset); + + for(i=0;i<4;i++) + { + if(vga.sequencer.map_mask & 1 << i) + data |= vga.memory[offset+i*0x10000]; + } + + return data; + } + + // never executed + //return 0; +} + +WRITE8_MEMBER(vga_device::mem_w) +{ + //Inside each case must prevent writes to non-mapped VGA memory regions, not only mask the offset. + switch(vga.gc.memory_map_sel & 0x03) + { + case 0: break; + case 1: + if(offset & 0x10000) + return; + + offset &= 0x0ffff; + break; + case 2: + if((offset & 0x18000) != 0x10000) + return; + + offset &= 0x07fff; + break; + case 3: + if((offset & 0x18000) != 0x18000) + return; + + offset &= 0x07fff; + break; + } + + { + UINT8 i; + + for(i=0;i<4;i++) + { + if(vga.sequencer.map_mask & 1 << i) + vga.memory[offset+i*0x10000] = (vga.sequencer.data[4] & 4) ? vga_latch_write(i,data) : data; + } + return; + } +} + +READ8_MEMBER(vga_device::mem_linear_r) +{ + return vga.memory[offset]; +} + +WRITE8_MEMBER(vga_device::mem_linear_w) +{ + vga.memory[offset] = data; +} + +MACHINE_CONFIG_FRAGMENT( pcvideo_vga ) + MCFG_SCREEN_ADD("screen", RASTER) + MCFG_SCREEN_RAW_PARAMS(XTAL_25_1748MHz,900,0,640,526,0,480) + MCFG_SCREEN_UPDATE_DEVICE("vga", vga_device, screen_update) + + MCFG_PALETTE_ADD("palette", 0x100) + MCFG_DEVICE_ADD("vga", VGA, 0) +MACHINE_CONFIG_END + +MACHINE_CONFIG_FRAGMENT( pcvideo_trident_vga ) + MCFG_SCREEN_ADD("screen", RASTER) + MCFG_SCREEN_RAW_PARAMS(XTAL_25_1748MHz,900,0,640,526,0,480) + MCFG_SCREEN_UPDATE_DEVICE("vga", trident_vga_device, screen_update) + + MCFG_PALETTE_ADD("palette", 0x100) + MCFG_DEVICE_ADD("vga", TRIDENT_VGA, 0) +MACHINE_CONFIG_END + +MACHINE_CONFIG_FRAGMENT( pcvideo_gamtor_vga ) + MCFG_SCREEN_ADD("screen", RASTER) + MCFG_SCREEN_RAW_PARAMS(XTAL_25_1748MHz,900,0,640,526,0,480) + MCFG_SCREEN_UPDATE_DEVICE("vga", gamtor_vga_device, screen_update) + + MCFG_PALETTE_ADD("palette", 0x100) + MCFG_DEVICE_ADD("vga", GAMTOR_VGA, 0) +MACHINE_CONFIG_END + +MACHINE_CONFIG_FRAGMENT( pcvideo_s3_vga ) + MCFG_SCREEN_ADD("screen", RASTER) + MCFG_SCREEN_RAW_PARAMS(XTAL_25_1748MHz,900,0,640,526,0,480) + MCFG_SCREEN_UPDATE_DEVICE("vga", s3_vga_device, screen_update) + + MCFG_PALETTE_ADD("palette", 0x100) + MCFG_DEVICE_ADD("vga", S3_VGA, 0) +MACHINE_CONFIG_END + + +static MACHINE_CONFIG_FRAGMENT( ati_vga ) + MCFG_MACH8_ADD_OWNER("8514a") + MCFG_EEPROM_SERIAL_93C46_ADD("ati_eeprom") +MACHINE_CONFIG_END + +static MACHINE_CONFIG_FRAGMENT( s3_764 ) + MCFG_8514A_ADD_OWNER("8514a") +MACHINE_CONFIG_END + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor ati_vga_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( ati_vga ); +} + +machine_config_constructor s3_vga_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( s3_764 ); +} + +/****************************************** + +Tseng ET4000k implementation + +******************************************/ + +void tseng_vga_device::tseng_define_video_mode() +{ + int divisor; + int xtal = 0; + svga.rgb8_en = 0; + svga.rgb15_en = 0; + svga.rgb16_en = 0; + svga.rgb24_en = 0; + switch(((et4k.aux_ctrl << 1) & 4)|(vga.miscellaneous_output & 0xc)>>2) + { + case 0: + xtal = XTAL_25_1748MHz; + break; + case 1: + xtal = XTAL_28_63636MHz; + break; + case 2: + xtal = 16257000*2; //2xEGA clock + break; + case 3: + xtal = XTAL_40MHz; + break; + case 4: + xtal = XTAL_36MHz; + break; + case 5: + xtal = XTAL_45MHz; + break; + case 6: + xtal = 31000000; + break; + case 7: + xtal = 38000000; + break; + } + switch(et4k.dac_ctrl & 0xe0) + { + case 0xa0: + svga.rgb15_en = 1; + divisor = 2; + break; + case 0xe0: + svga.rgb16_en = 1; + divisor = 2; + break; + case 0x60: + svga.rgb24_en = 1; + divisor = 3; + xtal *= 2.0f/3.0f; + break; + default: + svga.rgb8_en = (!(vga.sequencer.data[1] & 8) && (vga.sequencer.data[4] & 8) && vga.gc.shift256 && vga.crtc.div2 && GRAPHIC_MODE); + divisor = 1; + break; + } + recompute_params_clock(divisor, xtal); +} + +UINT8 tseng_vga_device::tseng_crtc_reg_read(UINT8 index) +{ + UINT8 res; + + if(index <= 0x18) + res = crtc_reg_read(index); + else + { + switch(index) + { + case 0x34: + res = et4k.aux_ctrl; + break; + case 0x3f: + res = et4k.horz_overflow; + break; + default: + res = vga.crtc.data[index]; + //printf("%02x\n",index); + break; + } + } + + return res; +} + +void tseng_vga_device::tseng_crtc_reg_write(UINT8 index, UINT8 data) +{ + if(index <= 0x18) + crtc_reg_write(index,data); + else + { + switch(index) + { + case 0x34: + et4k.aux_ctrl = data; + break; + case 0x3f: + et4k.horz_overflow = data; + vga.crtc.horz_total = (vga.crtc.horz_total & 0xff) | ((data & 1) << 8); + break; + default: + //printf("%02x %02x\n",index,data); + break; + } + } +} + +UINT8 tseng_vga_device::tseng_seq_reg_read(UINT8 index) +{ + UINT8 res; + + res = 0xff; + + if(index <= 0x04) + res = vga.sequencer.data[index]; + else + { + switch(index) + { + case 0x06: + case 0x07: + //printf("%02x\n",index); + break; + } + } + + return res; +} + +void tseng_vga_device::tseng_seq_reg_write(UINT8 index, UINT8 data) +{ + if(index <= 0x04) + { + vga.sequencer.data[vga.sequencer.index] = data; + seq_reg_write(vga.sequencer.index,data); + } + else + { + switch(index) + { + case 0x06: + case 0x07: + //printf("%02x %02x\n",index,data); + break; + } + } +} + +READ8_MEMBER(tseng_vga_device::port_03b0_r) +{ + UINT8 res = 0xff; + + if (CRTC_PORT_ADDR == 0x3b0) + { + switch(offset) + { + case 5: + res = tseng_crtc_reg_read(vga.crtc.index); + break; + case 8: + res = et4k.reg_3d8; + break; + default: + res = vga_device::port_03b0_r(space,offset,mem_mask); + break; + } + } + + return res; +} + +WRITE8_MEMBER(tseng_vga_device::port_03b0_w) +{ + if (CRTC_PORT_ADDR == 0x3b0) + { + switch(offset) + { + case 5: + vga.crtc.data[vga.crtc.index] = data; + tseng_crtc_reg_write(vga.crtc.index,data); + break; + case 8: + et4k.reg_3d8 = data; + if(data == 0xa0) + et4k.ext_reg_ena = true; + else if(data == 0x29) + et4k.ext_reg_ena = false; + break; + default: + vga_device::port_03b0_w(space,offset,data,mem_mask); + break; + } + } + tseng_define_video_mode(); +} + +void tseng_vga_device::tseng_attribute_reg_write(UINT8 index, UINT8 data) +{ + switch(index) + { + case 0x16: + et4k.misc1 = data; + #if 0 + svga.rgb8_en = 0; + svga.rgb15_en = 0; + svga.rgb16_en = 0; + svga.rgb32_en = 0; + /* TODO: et4k and w32 are different here */ + switch(et4k.misc1 & 0x30) + { + case 0: + // normal power-up mode + break; + case 0x10: + svga.rgb8_en = 1; + break; + case 0x20: + case 0x30: + popmessage("Tseng 15/16 bit HiColor mode, contact MAMEdev"); + break; + } + #endif + break; + case 0x17: et4k.misc2 = data; break; + default: + attribute_reg_write(index,data); + } + +} + +READ8_MEMBER(tseng_vga_device::port_03c0_r) +{ + UINT8 res; + + switch(offset) + { + case 0x01: + switch(vga.attribute.index) + { + case 0x16: res = et4k.misc1; break; + case 0x17: res = et4k.misc2; break; + default: + res = vga_device::port_03c0_r(space,offset,mem_mask); + break; + } + + break; + + case 0x05: + res = tseng_seq_reg_read(vga.sequencer.index); + break; + case 0x0d: + res = svga.bank_w & 0xf; + res |= (svga.bank_r & 0xf) << 4; + break; + case 0x06: + if(et4k.dac_state == 4) + { + if(!et4k.dac_ctrl) + et4k.dac_ctrl = 0x80; + res = et4k.dac_ctrl; + break; + } + et4k.dac_state++; + res = vga_device::port_03c0_r(space,offset,mem_mask); + break; + case 0x08: + et4k.dac_state = 0; + default: + res = vga_device::port_03c0_r(space,offset,mem_mask); + break; + } + + return res; +} + +WRITE8_MEMBER(tseng_vga_device::port_03c0_w) +{ + switch(offset) + { + case 0: + if (vga.attribute.state==0) + { + vga.attribute.index=data; + } + else + { + tseng_attribute_reg_write(vga.attribute.index,data); + } + vga.attribute.state=!vga.attribute.state; + break; + + case 0x05: + tseng_seq_reg_write(vga.sequencer.index,data); + break; + case 0x0d: + svga.bank_w = data & 0xf; + svga.bank_r = (data & 0xf0) >> 4; + break; + case 0x06: + if(et4k.dac_state == 4) + { + et4k.dac_ctrl = data; + break; + } + default: + vga_device::port_03c0_w(space,offset,data,mem_mask); + break; + } + tseng_define_video_mode(); +} + +READ8_MEMBER(tseng_vga_device::port_03d0_r) +{ + UINT8 res = 0xff; + + if (CRTC_PORT_ADDR == 0x3d0) + { + switch(offset) + { + case 5: + res = tseng_crtc_reg_read(vga.crtc.index); + break; + case 8: + res = et4k.reg_3d8; + break; + default: + res = vga_device::port_03d0_r(space,offset,mem_mask); + break; + } + } + + return res; +} + +WRITE8_MEMBER(tseng_vga_device::port_03d0_w) +{ + if (CRTC_PORT_ADDR == 0x3d0) + { + switch(offset) + { + case 5: + vga.crtc.data[vga.crtc.index] = data; + tseng_crtc_reg_write(vga.crtc.index,data); + //if((vga.crtc.index & 0xfe) != 0x0e) + // printf("%02x %02x %d\n",vga.crtc.index,data,space.machine().first_screen()->vpos()); + break; + case 8: + et4k.reg_3d8 = data; + if(data == 0xa0) + et4k.ext_reg_ena = true; + else if(data == 0x29) + et4k.ext_reg_ena = false; + break; + default: + vga_device::port_03d0_w(space,offset,data,mem_mask); + break; + } + } + tseng_define_video_mode(); +} + +READ8_MEMBER(tseng_vga_device::mem_r) +{ + if(svga.rgb8_en || svga.rgb15_en || svga.rgb16_en || svga.rgb24_en) + { + offset &= 0xffff; + return vga.memory[(offset+svga.bank_r*0x10000)]; + } + + return vga_device::mem_r(space,offset,mem_mask); +} + +WRITE8_MEMBER(tseng_vga_device::mem_w) +{ + if(svga.rgb8_en || svga.rgb15_en || svga.rgb16_en || svga.rgb24_en) + { + offset &= 0xffff; + vga.memory[(offset+svga.bank_w*0x10000)] = data; + } + else + vga_device::mem_w(space,offset,data,mem_mask); +} + +/****************************************** + +S3 implementation + +******************************************/ + +UINT16 s3_vga_device::offset() +{ + //popmessage("Offset: %04x %s %s %s",vga.crtc.offset,vga.crtc.dw?"DW":"--",vga.crtc.word_mode?"BYTE":"WORD",(s3.memory_config & 0x08)?"31":"--"); + if(s3.memory_config & 0x08) + return vga.crtc.offset << 3; + return vga_device::offset(); +} + +UINT8 s3_vga_device::s3_crtc_reg_read(UINT8 index) +{ + UINT8 res; + + if(index <= 0x18) + res = crtc_reg_read(index); + else + { + switch(index) + { + case 0x2d: + res = s3.id_high; + break; + case 0x2e: + res = s3.id_low; + break; + case 0x2f: + res = s3.revision; + break; + case 0x30: // CR30 Chip ID/REV register + res = s3.id_cr30; + break; + case 0x31: + res = s3.memory_config; + break; + case 0x35: + res = s3.crt_reg_lock; + break; + case 0x36: // Configuration register 1 + res = s3.strapping & 0x000000ff; // PCI (not really), Fast Page Mode DRAM + break; + case 0x37: // Configuration register 2 + res = (s3.strapping & 0x0000ff00) >> 8; // enable chipset, 64k BIOS size, internal DCLK/MCLK + break; + case 0x38: + res = s3.reg_lock1; + break; + case 0x39: + res = s3.reg_lock2; + break; + case 0x42: // CR42 Mode Control + res = s3.cr42 & 0x0f; // bit 5 set if interlaced, leave it unset for now. + break; + case 0x43: + res = s3.cr43; + break; + case 0x45: + res = s3.cursor_mode; + break; + case 0x46: + res = (s3.cursor_x & 0xff00) >> 8; + break; + case 0x47: + res = s3.cursor_x & 0x00ff; + break; + case 0x48: + res = (s3.cursor_y & 0xff00) >> 8; + break; + case 0x49: + res = s3.cursor_y & 0x00ff; + break; + case 0x4a: + res = s3.cursor_fg[s3.cursor_fg_ptr]; + s3.cursor_fg_ptr = 0; + break; + case 0x4b: + res = s3.cursor_bg[s3.cursor_bg_ptr]; + s3.cursor_bg_ptr = 0; + break; + case 0x4c: + res = (s3.cursor_start_addr & 0xff00) >> 8; + break; + case 0x4d: + res = s3.cursor_start_addr & 0x00ff; + break; + case 0x4e: + res = s3.cursor_pattern_x; + break; + case 0x4f: + res = s3.cursor_pattern_y; + break; + case 0x51: + res = (vga.crtc.start_addr_latch & 0x0c0000) >> 18; + res |= ((svga.bank_w & 0x30) >> 2); + res |= ((vga.crtc.offset & 0x0300) >> 4); + break; + case 0x55: + res = s3.extended_dac_ctrl; + break; + case 0x5c: + // if VGA dot clock is set to 3 (misc reg bits 2-3), then selected dot clock is read, otherwise read VGA clock select + if((vga.miscellaneous_output & 0xc) == 0x0c) + res = s3.cr42 & 0x0f; + else + res = (vga.miscellaneous_output & 0xc) >> 2; + break; + case 0x67: + res = s3.ext_misc_ctrl_2; + break; + case 0x68: // Configuration register 3 + res = (s3.strapping & 0x00ff0000) >> 16; // no /CAS,/OE stretch time, 32-bit data bus size + break; + case 0x69: + res = vga.crtc.start_addr_latch >> 16; + break; + case 0x6a: + res = svga.bank_r & 0x7f; + break; + case 0x6f: // Configuration register 4 (Trio64V+) + res = (s3.strapping & 0xff000000) >> 24; // LPB(?) mode, Serial port I/O at port 0xe8, Serial port I/O disabled (MMIO only), no WE delay + break; + default: + res = vga.crtc.data[index]; + //debugger_break(machine); + //printf("%02x\n",index); + break; + } + } + + return res; +} + +void s3_vga_device::s3_define_video_mode() +{ + int divisor = 1; + int xtal = (vga.miscellaneous_output & 0xc) ? XTAL_28_63636MHz : XTAL_25_1748MHz; + double freq; + + if((vga.miscellaneous_output & 0xc) == 0x0c) + { + // DCLK calculation + freq = ((double)(s3.clk_pll_m+2) / (double)((s3.clk_pll_n+2)*(pow(2.0,s3.clk_pll_r)))) * 14.318; // clock between XIN and XOUT + xtal = freq * 1000000; + } + + if((s3.ext_misc_ctrl_2) >> 4) + { + svga.rgb8_en = 0; + svga.rgb15_en = 0; + svga.rgb16_en = 0; + svga.rgb32_en = 0; + switch((s3.ext_misc_ctrl_2) >> 4) + { + case 0x01: svga.rgb8_en = 1; break; + case 0x03: svga.rgb15_en = 1; divisor = 2; break; + case 0x05: svga.rgb16_en = 1; divisor = 2; break; + case 0x0d: svga.rgb32_en = 1; divisor = 1; break; + default: fatalerror("TODO: S3 colour mode not implemented %02x\n",((s3.ext_misc_ctrl_2) >> 4)); + } + } + else + { + svga.rgb8_en = (s3.memory_config & 8) >> 3; + svga.rgb15_en = 0; + svga.rgb16_en = 0; + svga.rgb32_en = 0; + } + recompute_params_clock(divisor, xtal); +} + +void s3_vga_device::s3_crtc_reg_write(UINT8 index, UINT8 data) +{ + if(index <= 0x18) + crtc_reg_write(index,data); + else + { + switch(index) + { + case 0x31: // CR31 Memory Configuration Register + s3.memory_config = data; + vga.crtc.start_addr_latch &= ~0x30000; + vga.crtc.start_addr_latch |= ((data & 0x30) << 12); + s3_define_video_mode(); + break; + case 0x35: + if((s3.reg_lock1 & 0xc) != 8 || ((s3.reg_lock1 & 0xc0) == 0)) // lock register + return; + s3.crt_reg_lock = data; + svga.bank_w = data & 0xf; + svga.bank_r = svga.bank_w; + break; + case 0x36: + if(s3.reg_lock2 == 0xa5) + { + s3.strapping = (s3.strapping & 0xffffff00) | data; + logerror("CR36: Strapping data = %08x\n",s3.strapping); + } + break; + case 0x37: + if(s3.reg_lock2 == 0xa5) + { + s3.strapping = (s3.strapping & 0xffff00ff) | (data << 8); + logerror("CR37: Strapping data = %08x\n",s3.strapping); + } + break; + case 0x38: + s3.reg_lock1 = data; + break; + case 0x39: + /* TODO: reg lock mechanism */ + s3.reg_lock2 = data; + break; + case 0x40: + s3.enable_8514 = data & 0x01; // enable 8514/A registers (x2e8, x6e8, xae8, xee8) + break; + case 0x42: + s3.cr42 = data; // bit 5 = interlace, bits 0-3 = dot clock (seems to be undocumented) + break; + case 0x43: + s3.cr43 = data; // bit 2 = bit 8 of offset register, but only if bits 4-5 of CR51 are 00h. + vga.crtc.offset = (vga.crtc.offset & 0x00ff) | ((data & 0x04) << 6); + s3_define_video_mode(); + break; +/* +3d4h index 45h (R/W): CR45 Hardware Graphics Cursor Mode +bit 0 HWGC ENB. Hardware Graphics Cursor Enable. Set to enable the + HardWare Cursor in VGA and enhanced modes. + 1 (911/24) Delay Timing for Pattern Data Fetch + 2 (801/5,928) Hardware Cursor Horizontal Stretch 2. If set the cursor + pixels are stretched horizontally to two bytes and items 0 and 1 of + the fore/background stacks in 3d4h index 4Ah/4Bh are used. + 3 (801/5,928) Hardware Cursor Horizontal Stretch 3. If set the cursor + pixels are stretched horizontally to three bytes and items 0,1 and + 2 of the fore/background stacks in 3d4h index 4Ah/4Bh are used. + 2-3 (805i,864/964) HWC-CSEL. Hardware Cursor Color Select. + 0: 4/8bit, 1: 15/16bt, 2: 24bit, 3: 32bit + Note: So far I've had better luck with: 0: 8/15/16bit, 1: 32bit?? + 4 (80x +) Hardware Cursor Right Storage. If set the cursor data is + stored in the last 256 bytes of 4 1Kyte lines (4bits/pixel) or the + last 512 bytes of 2 2Kbyte lines (8bits/pixel). Intended for + 1280x1024 modes where there are no free lines at the bottom. + 5 (928) Cursor Control Enable for Brooktree Bt485 DAC. If set and 3d4h + index 55h bit 5 is set the HC1 output becomes the ODF and the HC0 + output becomes the CDE + (964) BT485 ODF Selection for Bt485A RAMDAC. If set pin 185 (RS3 + /ODF) is the ODF output to a Bt485A compatible RamDAC (low for even + fields and high for odd fields), if clear pin185 is the RS3 output. + */ + case 0x45: + s3.cursor_mode = data; + break; +/* +3d4h index 46h M(R/W): CR46/7 Hardware Graphics Cursor Origin-X +bit 0-10 The HardWare Cursor X position. For 64k modes this value should be + twice the actual X co-ordinate. + */ + case 0x46: + s3.cursor_x = (s3.cursor_x & 0x00ff) | (data << 8); + break; + case 0x47: + s3.cursor_x = (s3.cursor_x & 0xff00) | data; + break; +/* +3d4h index 48h M(R/W): CR48/9 Hardware Graphics Cursor Origin-Y +bit 0-9 (911/24) The HardWare Cursor Y position. + 0-10 (80x +) The HardWare Cursor Y position. +Note: The position is activated when the high byte of the Y coordinate (index + 48h) is written, so this byte should be written last (not 911/924 ?) + */ + case 0x48: + s3.cursor_y = (s3.cursor_y & 0x00ff) | (data << 8); + break; + case 0x49: + s3.cursor_y = (s3.cursor_y & 0xff00) | data; + break; + +/* +3d4h index 4Ah (R/W): Hardware Graphics Cursor Foreground Stack (80x +) +bit 0-7 The Foreground Cursor color. Three bytes (4 for the 864/964) are + stacked here. When the Cursor Mode register (3d4h index 45h) is read + the stackpointer is reset. When a byte is written the byte is + written into the current top of stack and the stackpointer is + increased. The first byte written (item 0) is allways used, the + other two(3) only when Hardware Cursor Horizontal Stretch (3d4h + index 45h bit 2-3) is enabled. + */ + case 0x4a: + s3.cursor_fg[s3.cursor_fg_ptr++] = data; + s3.cursor_fg_ptr %= 4; + break; +/* +3d4h index 4Bh (R/W): Hardware Graphics Cursor Background Stack (80x +) +bit 0-7 The Background Cursor color. Three bytes (4 for the 864/964) are + stacked here. When the Cursor Mode register (3d4h index 45h) is read + the stackpointer is reset. When a byte is written the byte is + written into the current top of stack and the stackpointer is + increased. The first byte written (item 0) is allways used, the + other two(3) only when Hardware Cursor Horizontal Stretch (3d4h + index 45h bit 2-3) is enabled. + */ + case 0x4b: + s3.cursor_bg[s3.cursor_bg_ptr++] = data; + s3.cursor_bg_ptr %= 4; + break; +/* +3d4h index 4Ch M(R/W): CR4C/D Hardware Graphics Cursor Storage Start Address +bit 0-9 (911,924) HCS_STADR. Hardware Graphics Cursor Storage Start Address + 0-11 (80x,928) HWGC_STA. Hardware Graphics Cursor Storage Start Address + 0-12 (864,964) HWGC_STA. Hardware Graphics Cursor Storage Start Address + Address of the HardWare Cursor Map in units of 1024 bytes (256 bytes + for planar modes). The cursor map is a 64x64 bitmap with 2 bits (A + and B) per pixel. The map is stored as one word (16 bits) of bit A, + followed by one word with the corresponding 16 B bits. + The bits are interpreted as: + A B MS-Windows: X-11: + 0 0 Background Screen data + 0 1 Foreground Screen data + 1 0 Screen data Background + 1 1 Inverted screen Foreground + The Windows/X11 switch is only available for the 80x +. + (911/24) For 64k color modes the cursor is stored as one byte (8 + bits) of A bits, followed by the 8 B-bits, and each bit in the + cursor should be doubled to provide a consistent cursor image. + (801/5,928) For Hi/True color modes use the Horizontal Stretch bits + (3d4h index 45h bits 2 and 3). + */ + case 0x4c: + s3.cursor_start_addr = (s3.cursor_start_addr & 0x00ff) | (data << 8); + break; + case 0x4d: + s3.cursor_start_addr = (s3.cursor_start_addr & 0xff00) | data; + break; +/* +3d4h index 4Eh (R/W): CR4E HGC Pattern Disp Start X-Pixel Position +bit 0-5 Pattern Display Start X-Pixel Position. + */ + case 0x4e: + s3.cursor_pattern_x = data; + break; +/* +3d4h index 4Fh (R/W): CR4F HGC Pattern Disp Start Y-Pixel Position +bit 0-5 Pattern Display Start Y-Pixel Position. + */ + case 0x4f: + s3.cursor_pattern_y = data; + break; + case 0x51: + vga.crtc.start_addr_latch &= ~0xc0000; + vga.crtc.start_addr_latch |= ((data & 0x3) << 18); + svga.bank_w = (svga.bank_w & 0xcf) | ((data & 0x0c) << 2); + svga.bank_r = svga.bank_w; + if((data & 0x30) != 0x00) + vga.crtc.offset = (vga.crtc.offset & 0x00ff) | ((data & 0x30) << 4); + else + vga.crtc.offset = (vga.crtc.offset & 0x00ff) | ((s3.cr43 & 0x04) << 6); + s3_define_video_mode(); + break; + case 0x53: + s3.cr53 = data; + break; +/* +3d4h index 55h (R/W): Extended Video DAC Control Register (80x +) +bit 0-1 DAC Register Select Bits. Passed to the RS2 and RS3 pins on the + RAMDAC, allowing access to all 8 or 16 registers on advanced RAMDACs. + If this field is 0, 3d4h index 43h bit 1 is active. + 2 Enable General Input Port Read. If set DAC reads are disabled and the + STRD strobe for reading the General Input Port is enabled for reading + while DACRD is active, if clear DAC reads are enabled. + 3 (928) Enable External SID Operation if set. If set video data is + passed directly from the VRAMs to the DAC rather than through the + VGA chip + 4 Hardware Cursor MS/X11 Mode. If set the Hardware Cursor is in X11 + mode, if clear in MS-Windows mode + 5 (80x,928) Hardware Cursor External Operation Mode. If set the two + bits of cursor data ,is output on the HC[0-1] pins for the video DAC + The SENS pin becomes HC1 and the MID2 pin becomes HC0. + 6 ?? + 7 (80x,928) Disable PA Output. If set PA[0-7] and VCLK are tristated. + (864/964) TOFF VCLK. Tri-State Off VCLK Output. VCLK output tri + -stated if set + */ + case 0x55: + s3.extended_dac_ctrl = data; + break; +/* +3d4h index 5Dh (R/W): Extended Horizontal Overflow Register (80x +) +bit 0 Horizontal Total bit 8. Bit 8 of the Horizontal Total register (3d4h + index 0) + 1 Horizontal Display End bit 8. Bit 8 of the Horizontal Display End + register (3d4h index 1) + 2 Start Horizontal Blank bit 8. Bit 8 of the Horizontal Start Blanking + register (3d4h index 2). + 3 (864,964) EHB+64. End Horizontal Blank +64. If set the /BLANK pulse + is extended by 64 DCLKs. Note: Is this bit 6 of 3d4h index 3 or + does it really extend by 64 ? + 4 Start Horizontal Sync Position bit 8. Bit 8 of the Horizontal Start + Retrace register (3d4h index 4). + 5 (864,964) EHS+32. End Horizontal Sync +32. If set the HSYNC pulse + is extended by 32 DCLKs. Note: Is this bit 5 of 3d4h index 5 or + does it really extend by 32 ? + 6 (928,964) Data Transfer Position bit 8. Bit 8 of the Data Transfer + Position register (3d4h index 3Bh) + 7 (928,964) Bus-Grant Terminate Position bit 8. Bit 8 of the Bus Grant + Termination register (3d4h index 5Fh). +*/ + case 0x5d: + vga.crtc.horz_total = (vga.crtc.horz_total & 0xfeff) | ((data & 0x01) << 8); + vga.crtc.horz_disp_end = (vga.crtc.horz_disp_end & 0xfeff) | ((data & 0x02) << 7); + vga.crtc.horz_blank_start = (vga.crtc.horz_blank_start & 0xfeff) | ((data & 0x04) << 6); + vga.crtc.horz_blank_end = (vga.crtc.horz_blank_end & 0xffbf) | ((data & 0x08) << 3); + vga.crtc.horz_retrace_start = (vga.crtc.horz_retrace_start & 0xfeff) | ((data & 0x10) << 4); + vga.crtc.horz_retrace_end = (vga.crtc.horz_retrace_end & 0xffdf) | (data & 0x20); + s3_define_video_mode(); + break; +/* +3d4h index 5Eh (R/W): Extended Vertical Overflow Register (80x +) +bit 0 Vertical Total bit 10. Bit 10 of the Vertical Total register (3d4h + index 6). Bits 8 and 9 are in 3d4h index 7 bit 0 and 5. + 1 Vertical Display End bit 10. Bit 10 of the Vertical Display End + register (3d4h index 12h). Bits 8 and 9 are in 3d4h index 7 bit 1 + and 6 + 2 Start Vertical Blank bit 10. Bit 10 of the Vertical Start Blanking + register (3d4h index 15h). Bit 8 is in 3d4h index 7 bit 3 and bit 9 + in 3d4h index 9 bit 5 + 4 Vertical Retrace Start bit 10. Bit 10 of the Vertical Start Retrace + register (3d4h index 10h). Bits 8 and 9 are in 3d4h index 7 bit 2 + and 7. + 6 Line Compare Position bit 10. Bit 10 of the Line Compare register + (3d4h index 18h). Bit 8 is in 3d4h index 7 bit 4 and bit 9 in 3d4h + index 9 bit 6. + */ + case 0x5e: + vga.crtc.vert_total = (vga.crtc.vert_total & 0xfbff) | ((data & 0x01) << 10); + vga.crtc.vert_disp_end = (vga.crtc.vert_disp_end & 0xfbff) | ((data & 0x02) << 9); + vga.crtc.vert_blank_start = (vga.crtc.vert_blank_start & 0xfbff) | ((data & 0x04) << 8); + vga.crtc.vert_retrace_start = (vga.crtc.vert_retrace_start & 0xfbff) | ((data & 0x10) << 6); + vga.crtc.line_compare = (vga.crtc.line_compare & 0xfbff) | ((data & 0x40) << 4); + s3_define_video_mode(); + break; + case 0x67: + s3.ext_misc_ctrl_2 = data; + s3_define_video_mode(); + break; + case 0x68: + if(s3.reg_lock2 == 0xa5) + { + s3.strapping = (s3.strapping & 0xff00ffff) | (data << 16); + logerror("CR68: Strapping data = %08x\n",s3.strapping); + } + break; + case 0x69: + vga.crtc.start_addr_latch &= ~0x1f0000; + vga.crtc.start_addr_latch |= ((data & 0x1f) << 16); + s3_define_video_mode(); + break; + case 0x6a: + svga.bank_w = data & 0x3f; + svga.bank_r = svga.bank_w; + break; + case 0x6f: + if(s3.reg_lock2 == 0xa5) + { + s3.strapping = (s3.strapping & 0x00ffffff) | (data << 24); + logerror("CR6F: Strapping data = %08x\n",s3.strapping); + } + break; + default: + if(LOG_8514) logerror("S3: 3D4 index %02x write %02x\n",index,data); + break; + } + } +} + +UINT8 s3_vga_device::s3_seq_reg_read(UINT8 index) +{ + UINT8 res = 0xff; + + if(index <= 0x0c) + res = vga.sequencer.data[index]; + else + { + switch(index) + { + case 0x10: + res = s3.sr10; + break; + case 0x11: + res = s3.sr11; + break; + case 0x12: + res = s3.sr12; + break; + case 0x13: + res = s3.sr13; + break; + case 0x15: + res = s3.sr15; + break; + case 0x17: + res = s3.sr17; // CLKSYN test register + s3.sr17--; // who knows what it should return, docs only say it defaults to 0, and is reserved for testing of the clock synthesiser + break; + } + } + + return res; +} + +void s3_vga_device::s3_seq_reg_write(UINT8 index, UINT8 data) +{ + if(index <= 0x0c) + { + vga.sequencer.data[vga.sequencer.index] = data; + seq_reg_write(vga.sequencer.index,data); + } + else + { + switch(index) + { + // Memory CLK PLL + case 0x10: + s3.sr10 = data; + break; + case 0x11: + s3.sr11 = data; + break; + // Video CLK PLL + case 0x12: + s3.sr12 = data; + break; + case 0x13: + s3.sr13 = data; + break; + case 0x15: + if(data & 0x02) // load DCLK frequency (would normally have a small variable delay) + { + s3.clk_pll_n = s3.sr12 & 0x1f; + s3.clk_pll_r = (s3.sr12 & 0x60) >> 5; + s3.clk_pll_m = s3.sr13 & 0x7f; + s3_define_video_mode(); + } + if(data & 0x20) // immediate DCLK/MCLK load + { + s3.clk_pll_n = s3.sr12 & 0x1f; + s3.clk_pll_r = (s3.sr12 & 0x60) >> 5; + s3.clk_pll_m = s3.sr13 & 0x7f; + s3_define_video_mode(); + } + s3.sr15 = data; + } + } +} + + + +READ8_MEMBER(s3_vga_device::port_03b0_r) +{ + UINT8 res = 0xff; + + if (CRTC_PORT_ADDR == 0x3b0) + { + switch(offset) + { + case 5: + res = s3_crtc_reg_read(vga.crtc.index); + break; + default: + res = vga_device::port_03b0_r(space,offset,mem_mask); + break; + } + } + + return res; +} + +WRITE8_MEMBER(s3_vga_device::port_03b0_w) +{ + if (CRTC_PORT_ADDR == 0x3b0) + { + switch(offset) + { + case 5: + vga.crtc.data[vga.crtc.index] = data; + s3_crtc_reg_write(vga.crtc.index,data); + break; + default: + vga_device::port_03b0_w(space,offset,data,mem_mask); + break; + } + } +} + +READ8_MEMBER(s3_vga_device::port_03c0_r) +{ + UINT8 res; + + switch(offset) + { + case 5: + res = s3_seq_reg_read(vga.sequencer.index); + break; + default: + res = vga_device::port_03c0_r(space,offset,mem_mask); + break; + } + + return res; +} + +WRITE8_MEMBER(s3_vga_device::port_03c0_w) +{ + switch(offset) + { + case 5: + s3_seq_reg_write(vga.sequencer.index,data); + break; + default: + vga_device::port_03c0_w(space,offset,data,mem_mask); + break; + } +} + +READ8_MEMBER(s3_vga_device::port_03d0_r) +{ + UINT8 res = 0xff; + + if (CRTC_PORT_ADDR == 0x3d0) + { + switch(offset) + { + case 5: + res = s3_crtc_reg_read(vga.crtc.index); + break; + default: + res = vga_device::port_03d0_r(space,offset,mem_mask); + break; + } + } + + return res; +} + +WRITE8_MEMBER(s3_vga_device::port_03d0_w) +{ + if (CRTC_PORT_ADDR == 0x3d0) + { + switch(offset) + { + case 5: + vga.crtc.data[vga.crtc.index] = data; + s3_crtc_reg_write(vga.crtc.index,data); + break; + default: + vga_device::port_03d0_w(space,offset,data,mem_mask); + break; + } + } +} + +READ8_MEMBER(ati_vga_device::port_03c0_r) +{ + UINT8 data = 0xff; + + switch(offset) + { + case 1: + if ((vga.attribute.index&0x1f) < sizeof(vga.attribute.data)) + data = vga.attribute.data[vga.attribute.index&0x1f]; + break; + default: + data = vga_device::port_03c0_r(space,offset,mem_mask); + break; + } + return data; +} + + +/* accelerated ports, TBD ... */ + +void ibm8514a_device::ibm8514_write_fg(UINT32 offset) +{ + address_space& space = machine().device("maincpu")->memory().space(AS_PROGRAM); + offset %= m_vga->vga.svga_intf.vram_size; + UINT8 dst = m_vga->mem_linear_r(space,offset,0xff); + UINT8 src = 0; + + // check clipping rectangle + if((ibm8514.current_cmd & 0xe000) == 0xc000) // BitBLT writes to the destination X/Y, so check that instead + { + if(ibm8514.dest_x < ibm8514.scissors_left || ibm8514.dest_x > ibm8514.scissors_right || ibm8514.dest_y < ibm8514.scissors_top || ibm8514.dest_y > ibm8514.scissors_bottom) + return; // do nothing + } + else + if(ibm8514.curr_x < ibm8514.scissors_left || ibm8514.curr_x > ibm8514.scissors_right || ibm8514.curr_y < ibm8514.scissors_top || ibm8514.curr_y > ibm8514.scissors_bottom) + return; // do nothing + + // determine source + switch(ibm8514.fgmix & 0x0060) + { + case 0x0000: + src = ibm8514.bgcolour; + break; + case 0x0020: + src = ibm8514.fgcolour; + break; + case 0x0040: + src = ibm8514.pixel_xfer; + break; + case 0x0060: + // video memory - presume the memory is sourced from the current X/Y co-ords + src = m_vga->mem_linear_r(space,((ibm8514.curr_y * IBM8514_LINE_LENGTH) + ibm8514.curr_x),0xff); + break; + } + + // write the data + switch(ibm8514.fgmix & 0x000f) + { + case 0x0000: + m_vga->mem_linear_w(space,offset,~dst,0xff); + break; + case 0x0001: + m_vga->mem_linear_w(space,offset,0x00,0xff); + break; + case 0x0002: + m_vga->mem_linear_w(space,offset,0xff,0xff); + break; + case 0x0003: + m_vga->mem_linear_w(space,offset,dst,0xff); + break; + case 0x0004: + m_vga->mem_linear_w(space,offset,~src,0xff); + break; + case 0x0005: + m_vga->mem_linear_w(space,offset,src ^ dst,0xff); + break; + case 0x0006: + m_vga->mem_linear_w(space,offset,~(src ^ dst),0xff); + break; + case 0x0007: + m_vga->mem_linear_w(space,offset,src,0xff); + break; + case 0x0008: + m_vga->mem_linear_w(space,offset,~(src & dst),0xff); + break; + case 0x0009: + m_vga->mem_linear_w(space,offset,(~src) | dst,0xff); + break; + case 0x000a: + m_vga->mem_linear_w(space,offset,src | (~dst),0xff); + break; + case 0x000b: + m_vga->mem_linear_w(space,offset,src | dst,0xff); + break; + case 0x000c: + m_vga->mem_linear_w(space,offset,src & dst,0xff); + break; + case 0x000d: + m_vga->mem_linear_w(space,offset,src & (~dst),0xff); + break; + case 0x000e: + m_vga->mem_linear_w(space,offset,(~src) & dst,0xff); + break; + case 0x000f: + m_vga->mem_linear_w(space,offset,~(src | dst),0xff); + break; + } +} + +void ibm8514a_device::ibm8514_write_bg(UINT32 offset) +{ + address_space& space = machine().device("maincpu")->memory().space(AS_PROGRAM); + offset %= m_vga->vga.svga_intf.vram_size; + UINT8 dst = m_vga->mem_linear_r(space,offset,0xff); + UINT8 src = 0; + + // check clipping rectangle + if((ibm8514.current_cmd & 0xe000) == 0xc000) // BitBLT writes to the destination X/Y, so check that instead + { + if(ibm8514.dest_x < ibm8514.scissors_left || ibm8514.dest_x > ibm8514.scissors_right || ibm8514.dest_y < ibm8514.scissors_top || ibm8514.dest_y > ibm8514.scissors_bottom) + return; // do nothing + } + else + if(ibm8514.curr_x < ibm8514.scissors_left || ibm8514.curr_x > ibm8514.scissors_right || ibm8514.curr_y < ibm8514.scissors_top || ibm8514.curr_y > ibm8514.scissors_bottom) + return; // do nothing + + // determine source + switch(ibm8514.bgmix & 0x0060) + { + case 0x0000: + src = ibm8514.bgcolour; + break; + case 0x0020: + src = ibm8514.fgcolour; + break; + case 0x0040: + src = ibm8514.pixel_xfer; + break; + case 0x0060: + // video memory - presume the memory is sourced from the current X/Y co-ords + src = m_vga->mem_linear_r(space,((ibm8514.curr_y * IBM8514_LINE_LENGTH) + ibm8514.curr_x),0xff); + break; + } + + // write the data + switch(ibm8514.bgmix & 0x000f) + { + case 0x0000: + m_vga->mem_linear_w(space,offset,~dst,0xff); + break; + case 0x0001: + m_vga->mem_linear_w(space,offset,0x00,0xff); + break; + case 0x0002: + m_vga->mem_linear_w(space,offset,0xff,0xff); + break; + case 0x0003: + m_vga->mem_linear_w(space,offset,dst,0xff); + break; + case 0x0004: + m_vga->mem_linear_w(space,offset,~src,0xff); + break; + case 0x0005: + m_vga->mem_linear_w(space,offset,src ^ dst,0xff); + break; + case 0x0006: + m_vga->mem_linear_w(space,offset,~(src ^ dst),0xff); + break; + case 0x0007: + m_vga->mem_linear_w(space,offset,src,0xff); + break; + case 0x0008: + m_vga->mem_linear_w(space,offset,~(src & dst),0xff); + break; + case 0x0009: + m_vga->mem_linear_w(space,offset,(~src) | dst,0xff); + break; + case 0x000a: + m_vga->mem_linear_w(space,offset,src | (~dst),0xff); + break; + case 0x000b: + m_vga->mem_linear_w(space,offset,src | dst,0xff); + break; + case 0x000c: + m_vga->mem_linear_w(space,offset,src & dst,0xff); + break; + case 0x000d: + m_vga->mem_linear_w(space,offset,src & (~dst),0xff); + break; + case 0x000e: + m_vga->mem_linear_w(space,offset,(~src) & dst,0xff); + break; + case 0x000f: + m_vga->mem_linear_w(space,offset,~(src | dst),0xff); + break; + } +} + +void ibm8514a_device::ibm8514_write(UINT32 offset, UINT32 src) +{ + int data_size = 8; + UINT32 xfer = 0; + address_space& space = machine().device("maincpu")->memory().space(AS_PROGRAM); + + switch(ibm8514.pixel_control & 0x00c0) + { + case 0x0000: // Foreground Mix only + ibm8514_write_fg(offset); + break; + case 0x0040: // fixed pattern (?) + // TODO + break; + case 0x0080: // use pixel transfer register + if(ibm8514.bus_size == 0) // 8-bit + data_size = 8; + if(ibm8514.bus_size == 1) // 16-bit + data_size = 16; + if(ibm8514.bus_size == 2) // 32-bit + data_size = 32; + if((ibm8514.current_cmd & 0x1000) && (data_size != 8)) + { + xfer = ((ibm8514.pixel_xfer & 0x000000ff) << 8) | ((ibm8514.pixel_xfer & 0x0000ff00) >> 8) + | ((ibm8514.pixel_xfer & 0x00ff0000) << 8) | ((ibm8514.pixel_xfer & 0xff000000) >> 8); + } + else + xfer = ibm8514.pixel_xfer; + if(ibm8514.current_cmd & 0x0002) + { + if((xfer & ((1<<(data_size-1))>>ibm8514.src_x)) != 0) + ibm8514_write_fg(offset); + else + ibm8514_write_bg(offset); + } + else + { + ibm8514_write_fg(offset); + } + ibm8514.src_x++; + if(ibm8514.src_x >= data_size) + ibm8514.src_x = 0; + break; + case 0x00c0: // use source plane + if(m_vga->mem_linear_r(space,src,0xff) != 0x00) + ibm8514_write_fg(offset); + else + ibm8514_write_bg(offset); + break; + } +} + +/* +92E8h W(R/W): Line Error Term Read/Write Register (ERR_TERM). +bit 0-12 (911/924) LINE PARAMETER/ERROR TERM. For Line Drawing this is the + Bresenham Initial Error Term 2*dminor-dmajor (one less if the + starting X is less than the ending X) in two's complement format. + (dminor is the length of the line projected onto the minor or + dependent axis, dmajor is the length of the line projected onto + the major or independent axis). + 0-13 (80x +) LINE PARAMETER/ERROR TERM. See above. + */ +READ16_MEMBER(ibm8514a_device::ibm8514_line_error_r) +{ + return ibm8514.line_errorterm; +} + +WRITE16_MEMBER(ibm8514a_device::ibm8514_line_error_w) +{ + ibm8514.line_errorterm = data; + if(LOG_8514) logerror("8514/A: Line Parameter/Error Term write %04x\n",data); +} + +/* + 9AE8h W(R): Graphics Processor Status Register (GP_STAT) +bit 0-7 Queue State. + 00h = 8 words available - queue is empty + 01h = 7 words available + 03h = 6 words available + 07h = 5 words available + 0Fh = 4 words available + 1Fh = 3 words available + 3Fh = 2 words available + 7Fh = 1 word available + FFh = 0 words available - queue is full + 8 (911-928) DTA AVA. Read Data Available. If set data is ready to be + read from the PIX_TRANS register (E2E8h). + 9 HDW BSY. Hardware Graphics Processor Busy + If set the Graphics Processor is busy. + 10 (928 +) AE. All FIFO Slots Empty. If set all FIFO slots are empty. + 11-15 (864/964) (R) Queue State bits 8-12. 1Fh if 8 words or less + available, Fh for 9 words, 7 for 10 words, 3 for 11 words, 1 for + 12 words and 0 for 13 words available. + */ +READ16_MEMBER(ibm8514a_device::ibm8514_gpstatus_r) +{ + UINT16 ret = 0x0000; + + //if(LOG_8514) logerror("S3: 9AE8 read\n"); + if(ibm8514.gpbusy == true) + ret |= 0x0200; + if(ibm8514.data_avail == true) + ret |= 0x0100; + return ret; +} + +void ibm8514a_device::ibm8514_draw_vector(UINT8 len, UINT8 dir, bool draw) +{ + UINT32 offset; + int x = 0; + + while(x <= len) + { + offset = (ibm8514.curr_y * IBM8514_LINE_LENGTH) + ibm8514.curr_x; + if(draw) + ibm8514_write(offset,offset); + switch(dir) + { + case 0: // 0 degrees + ibm8514.curr_x++; + break; + case 1: // 45 degrees + ibm8514.curr_x++; + ibm8514.curr_y--; + break; + case 2: // 90 degrees + ibm8514.curr_y--; + break; + case 3: // 135 degrees + ibm8514.curr_y--; + ibm8514.curr_x--; + break; + case 4: // 180 degrees + ibm8514.curr_x--; + break; + case 5: // 225 degrees + ibm8514.curr_x--; + ibm8514.curr_y++; + break; + case 6: // 270 degrees + ibm8514.curr_y++; + break; + case 7: // 315 degrees + ibm8514.curr_y++; + ibm8514.curr_x++; + break; + } + x++; + } +} + +/* +9AE8h W(W): Drawing Command Register (CMD) +bit 0 (911-928) ~RD/WT. Read/Write Data. If set VRAM write operations are + enabled. If clear operations execute normally but writes are + disabled. + 1 PX MD. Pixel Mode. Defines the orientation of the display bitmap. + 0 = Through plane mode (Single pixel transferred at a time) + 1 = Across plane mode (Multiple pixels transferred at a time). + 2 LAST PXOF. Last Pixel Off. If set the last pixel of a line command + (CMD_LINE, SSV or LINEAF) is not drawn. This is used for mixes such + as XOR where drawing the same pixel twice would give the wrong + color. + 3 DIR TYP. Direction Type. + 0: Bresenham line drawing (X-Y Axial) + CMD_LINE draws a line using the Bresenham algorithm as + specified in the DESTY_AXSTP (8AE8h), DESTX_DIASTP (8EE8h), + ERR_TERM (92E8h) and MAJ_AXIS_PCNT (96E8h) registers + INC_X, INC_Y and YMAJAXIS determines the direction. + 1: Vector line draws (Radial). + CMD_NOP allows drawing of Short Stroke Vectors (SSVs) by + writing to the Short Stroke register (9EE8h). + CMD_LINE draws a vector of length MAJ_AXIS_PCNT (96E8h) + in the direction specified by LINEDIR (bits 5-7). + DRWG-DIR determines the direction of the line. + 4 DRAW YES. If clear the current position is moved, but no pixels + are modified. This bit should be set when attempting read or + write of bitmap data. + 5-7 DRWG-DIR. Drawing Direction. When a line draw command (CMD_LINE) + with DIR TYP=1 (Radial) is issued, these bits define the direction + of the line counter clockwise relative to the positive X-axis. + 0 = 000 degrees + 1 = 045 degrees + 2 = 090 degrees + 3 = 135 degrees + 4 = 180 degrees + 5 = 225 degrees + 6 = 270 degrees + 7 = 315 degrees + 5 INC_X. This bit together with INC_Y determines which quadrant + the slope of a line lies within. They also determine the + orientation of rectangle draw commands. + If set lines are drawn in the positive X direction (left to right). + 6 YMAJAXIS. For Bresenham line drawing commands this bit determines + which axis is the independent or major axis. INC_X and INC_Y + determines which quadrant the slope falls within. This bit further + defines the slope to within an octant. + If set Y is the major (independent) axis. + 7 INC_Y. This bit together with INC_X determines which quadrant + the slope of a line lies within. They also determine the + orientation of rectangle draw commands. + If set lines are drawn in the positive Y direction (down). + 8 WAIT YES. If set the drawing engine waits for read/write of the + PIX_TRANS register (E2E8h) for each pixel during a draw operation. + 9 (911-928) BUS SIZE. If set the PIX_TRANS register (E2E8h) is + processed internally as two bytes in the order specified by BYTE + SWAP. If clear all accesses to E2E8h are 8bit. + 9-10 (864,964) BUS SIZE. Select System Bus Size. Controls the width of + the Pixel Data Transfer registers (E2E8h,E2EAh) and the memory + mapped I/O. 0: 8bit, 1: 16bit, 2: 32bit + 12 BYTE SWAP. Affects both reads and writes of SHORT_STROKE (9EE8h) + and PIX_TRANS (E2E8h) when 16bit=1. + If set take low byte first, if clear take high byte first. + 13-15 Draw Command: + 0 = NOP. Used for Short Stroke Vectors. + 1 = Draw Line. If bit 3 is set the line is drawn to the angle in + bits 5-7 and the length in the Major Axis Pixel Count register + (96E8h), if clear the line is drawn from the Bresenham + constants in the Axial Step Constant register(8AE8h), Diagonal + Step Constant register (8EE8h), Line Error Term register + (92E8h) and bits 5-7 of this register. + 2 = Rectangle Fill. The Current X (86E8h) and Y (82E8h) + registers holds the coordinates of the rectangle to fill and + the Major Axis Pixel Count register (96E8h) holds the + horizontal width (in pixels) fill and the Minor Axis Pixel + Count register (BEE8h index 0) holds the height of the + rectangle. + 6 = BitBLT. Copies the source rectangle specified by the Current X + (86E8h) and Y (8AE8h) registers to the destination rectangle, + specified as for the Rectangle Fills. + 7 = (80x +) Pattern Fill. The source rectangle is an 8x8 pattern + rectangle, which is copied repeatably to the destination + rectangle. + */ +WRITE16_MEMBER(ibm8514a_device::ibm8514_cmd_w) +{ + int x,y; + int pattern_x,pattern_y; + UINT32 off,src; + UINT8 readmask; + + ibm8514.current_cmd = data; + ibm8514.src_x = 0; + ibm8514.src_y = 0; + ibm8514.bus_size = (data & 0x0600) >> 9; + switch(data & 0xe000) + { + case 0x0000: // NOP (for "Short Stroke Vectors") + ibm8514.state = IBM8514_IDLE; + ibm8514.gpbusy = false; + if(LOG_8514) logerror("8514/A: Command (%04x) - NOP (Short Stroke Vector)\n",ibm8514.current_cmd); + break; + case 0x2000: // Line + ibm8514.state = IBM8514_IDLE; + ibm8514.gpbusy = false; + if(data & 0x0008) + { + if(data & 0x0100) + { + ibm8514.state = IBM8514_DRAWING_LINE; + ibm8514.data_avail = true; + if(LOG_8514) logerror("8514/A: Command (%04x) - Vector Line (WAIT) %i,%i \n",ibm8514.current_cmd,ibm8514.curr_x,ibm8514.curr_y); + } + else + { + ibm8514_draw_vector(ibm8514.rect_width,(data & 0x00e0) >> 5,(data & 0010) ? true : false); + if(LOG_8514) logerror("8514/A: Command (%04x) - Vector Line - %i,%i \n",ibm8514.current_cmd,ibm8514.curr_x,ibm8514.curr_y); + } + } + else + { + // Not perfect, but will do for now. + INT16 dx = ibm8514.rect_width; + INT16 dy = ibm8514.line_axial_step >> 1; + INT16 err = ibm8514.line_errorterm; + int sx = (data & 0x0020) ? 1 : -1; + int sy = (data & 0x0080) ? 1 : -1; + int count = 0; + INT16 temp; + + if(LOG_8514) logerror("8514/A: Command (%04x) - Line (Bresenham) - %i,%i Axial %i, Diagonal %i, Error %i, Major Axis %i, Minor Axis %i\n",ibm8514.current_cmd, + ibm8514.curr_x,ibm8514.curr_y,ibm8514.line_axial_step,ibm8514.line_diagonal_step,ibm8514.line_errorterm,ibm8514.rect_width,ibm8514.rect_height); + + if((data & 0x0040)) + { + temp = dx; dx = dy; dy = temp; + } + for(;;) + { + ibm8514_write(ibm8514.curr_x + (ibm8514.curr_y * IBM8514_LINE_LENGTH),ibm8514.curr_x + (ibm8514.curr_y * IBM8514_LINE_LENGTH)); + if (count > ibm8514.rect_width) break; + count++; + if((err*2) > -dy) + { + err -= dy; + ibm8514.curr_x += sx; + } + if((err*2) < dx) + { + err += dx; + ibm8514.curr_y += sy; + } + } + } + break; + case 0x4000: // Rectangle Fill + if(data & 0x0100) // WAIT (for read/write of PIXEL TRANSFER (E2E8)) + { + ibm8514.state = IBM8514_DRAWING_RECT; + //ibm8514.gpbusy = true; // DirectX 5 keeps waiting for the busy bit to be clear... + ibm8514.bus_size = (data & 0x0600) >> 9; + ibm8514.data_avail = true; + if(LOG_8514) logerror("8514/A: Command (%04x) - Rectangle Fill (WAIT) %i,%i Width: %i Height: %i Colour: %08x\n",ibm8514.current_cmd,ibm8514.curr_x, + ibm8514.curr_y,ibm8514.rect_width,ibm8514.rect_height,ibm8514.fgcolour); + break; + } + if(LOG_8514) logerror("8514/A: Command (%04x) - Rectangle Fill %i,%i Width: %i Height: %i Colour: %08x\n",ibm8514.current_cmd,ibm8514.curr_x, + ibm8514.curr_y,ibm8514.rect_width,ibm8514.rect_height,ibm8514.fgcolour); + off = 0; + off += (IBM8514_LINE_LENGTH * ibm8514.curr_y); + off += ibm8514.curr_x; + for(y=0;y<=ibm8514.rect_height;y++) + { + for(x=0;x<=ibm8514.rect_width;x++) + { + if(data & 0x0020) // source pattern is always based on current X/Y? + ibm8514_write((off+x) % m_vga->vga.svga_intf.vram_size,(off+x) % m_vga->vga.svga_intf.vram_size); + else + ibm8514_write((off-x) % m_vga->vga.svga_intf.vram_size,(off-x) % m_vga->vga.svga_intf.vram_size); + if(ibm8514.current_cmd & 0x0020) + { + ibm8514.curr_x++; + if(ibm8514.curr_x > ibm8514.prev_x + ibm8514.rect_width) + { + ibm8514.curr_x = ibm8514.prev_x; + ibm8514.src_x = 0; + if(ibm8514.current_cmd & 0x0080) + ibm8514.curr_y++; + else + ibm8514.curr_y--; + } + } + else + { + ibm8514.curr_x--; + if(ibm8514.curr_x < ibm8514.prev_x - ibm8514.rect_width) + { + ibm8514.curr_x = ibm8514.prev_x; + ibm8514.src_x = 0; + if(ibm8514.current_cmd & 0x0080) + ibm8514.curr_y++; + else + ibm8514.curr_y--; + } + } + } + if(data & 0x0080) + off += IBM8514_LINE_LENGTH; + else + off -= IBM8514_LINE_LENGTH; + } + ibm8514.state = IBM8514_IDLE; + ibm8514.gpbusy = false; + break; + case 0xc000: // BitBLT + if(LOG_8514) logerror("8514/A: Command (%04x) - BitBLT from %i,%i to %i,%i Width: %i Height: %i\n",ibm8514.current_cmd, + ibm8514.curr_x,ibm8514.curr_y,ibm8514.dest_x,ibm8514.dest_y,ibm8514.rect_width,ibm8514.rect_height); + off = 0; + off += (IBM8514_LINE_LENGTH * ibm8514.dest_y); + off += ibm8514.dest_x; + src = 0; + src += (IBM8514_LINE_LENGTH * ibm8514.curr_y); + src += ibm8514.curr_x; + readmask = ((ibm8514.read_mask & 0x01) << 7) | ((ibm8514.read_mask & 0xfe) >> 1); + for(y=0;y<=ibm8514.rect_height;y++) + { + for(x=0;x<=ibm8514.rect_width;x++) + { + if((ibm8514.pixel_control & 0xc0) == 0xc0) + { + // only check read mask if Mix Select is set to 11 (VRAM determines mix) + if(m_vga->mem_linear_r(space,(src+x),0xff) & ~readmask) + { + // presumably every program is going to be smart enough to set the FG mix to use VRAM (0x6x) + if(data & 0x0020) + ibm8514_write(off+x,src+x); + else + ibm8514_write(off-x,src-x); + } + } + else + { + // presumably every program is going to be smart enough to set the FG mix to use VRAM (0x6x) + if(data & 0x0020) + ibm8514_write(off+x,src+x); + else + ibm8514_write(off-x,src-x); + } + if(ibm8514.current_cmd & 0x0020) + { + ibm8514.curr_x++; + if(ibm8514.curr_x > ibm8514.prev_x + ibm8514.rect_width) + { + ibm8514.curr_x = ibm8514.prev_x; + ibm8514.src_x = 0; + if(ibm8514.current_cmd & 0x0080) + ibm8514.curr_y++; + else + ibm8514.curr_y--; + } + } + else + { + ibm8514.curr_x--; + if(ibm8514.curr_x < ibm8514.prev_x - ibm8514.rect_width) + { + ibm8514.curr_x = ibm8514.prev_x; + ibm8514.src_x = 0; + if(ibm8514.current_cmd & 0x0080) + ibm8514.curr_y++; + else + ibm8514.curr_y--; + } + } + } + if(data & 0x0080) + { + src += IBM8514_LINE_LENGTH; + off += IBM8514_LINE_LENGTH; + } + else + { + src -= IBM8514_LINE_LENGTH; + off -= IBM8514_LINE_LENGTH; + } + } + ibm8514.state = IBM8514_IDLE; + ibm8514.gpbusy = false; + ibm8514.curr_x = ibm8514.prev_x; + ibm8514.curr_y = ibm8514.prev_y; + break; + case 0xe000: // Pattern Fill + if(LOG_8514) logerror("8514/A: Command (%04x) - Pattern Fill - source %i,%i dest %i,%i Width: %i Height: %i\n",ibm8514.current_cmd, + ibm8514.curr_x,ibm8514.curr_y,ibm8514.dest_x,ibm8514.dest_y,ibm8514.rect_width,ibm8514.rect_height); + off = 0; + off += (IBM8514_LINE_LENGTH * ibm8514.dest_y); + off += ibm8514.dest_x; + src = 0; + src += (IBM8514_LINE_LENGTH * ibm8514.curr_y); + src += ibm8514.curr_x; + if(data & 0x0020) + pattern_x = 0; + else + pattern_x = 7; + if(data & 0x0080) + pattern_y = 0; + else + pattern_y = 7; + + for(y=0;y<=ibm8514.rect_height;y++) + { + for(x=0;x<=ibm8514.rect_width;x++) + { + if(data & 0x0020) + { + ibm8514_write(off+x,src+pattern_x); + pattern_x++; + if(pattern_x >= 8) + pattern_x = 0; + } + else + { + ibm8514_write(off-x,src-pattern_x); + pattern_x--; + if(pattern_x < 0) + pattern_x = 7; + } + } + + // for now, presume that INC_X and INC_Y affect both src and dest, at is would for a bitblt. + if(data & 0x0020) + pattern_x = 0; + else + pattern_x = 7; + if(data & 0x0080) + { + pattern_y++; + src += IBM8514_LINE_LENGTH; + if(pattern_y >= 8) + { + pattern_y = 0; + src -= (IBM8514_LINE_LENGTH * 8); // move src pointer back to top of pattern + } + off += IBM8514_LINE_LENGTH; + } + else + { + pattern_y--; + src -= IBM8514_LINE_LENGTH; + if(pattern_y < 0) + { + pattern_y = 7; + src += (IBM8514_LINE_LENGTH * 8); // move src pointer back to bottom of pattern + } + off -= IBM8514_LINE_LENGTH; + } + } + ibm8514.state = IBM8514_IDLE; + ibm8514.gpbusy = false; + break; + default: + ibm8514.state = IBM8514_IDLE; + ibm8514.gpbusy = false; + if(LOG_8514) logerror("8514/A: Unknown command: %04x\n",data); + } +} + +/* +8AE8h W(R/W): Destination Y Position & Axial Step Constant Register + (DESTY_AXSTP) +bit 0-11 DESTINATION Y-POSITION. During BITBLT operations this is the Y + co-ordinate of the destination in pixels. + 0-12 (911/924) LINE PARAMETER AXIAL STEP CONSTANT. During Line Drawing, + this is the Bresenham constant 2*dminor in two's complement + format. (dminor is the length of the line projected onto the minor + or dependent axis). + 0-13 (80 x+) LINE PARAMETER AXIAL STEP CONSTANT. Se above + + */ +READ16_MEMBER(ibm8514a_device::ibm8514_desty_r) +{ + return ibm8514.line_axial_step; +} + +WRITE16_MEMBER(ibm8514a_device::ibm8514_desty_w) +{ + ibm8514.line_axial_step = data; + ibm8514.dest_y = data; + if(LOG_8514) logerror("8514/A: Line Axial Step / Destination Y write %04x\n",data); +} + +/* +8EE8h W(R/W): Destination X Position & Diagonal Step Constant Register + (DESTX_DISTP) +bit 0-11 DESTINATION X-POSITION. During BITBLT operations this is the X + co-ordinate of the destination in pixels. + 0-12 (911/924) LINE PARAMETER DIAGONAL STEP CONSTANT. During Line + Drawing this is the Bresenham constant 2*dminor-2*dmajor in two's + complement format. (dminor is the length of the line projected + onto the minor or dependent axis, dmajor is the length of the line + projected onto the major or independent axis) + 0-13 (80x +) LINE PARAMETER DIAGONAL STEP CONSTANT. Se above + + */ +READ16_MEMBER(ibm8514a_device::ibm8514_destx_r) +{ + return ibm8514.line_diagonal_step; +} + +WRITE16_MEMBER(ibm8514a_device::ibm8514_destx_w) +{ + ibm8514.line_diagonal_step = data; + ibm8514.dest_x = data; + if(LOG_8514) logerror("8514/A: Line Diagonal Step / Destination X write %04x\n",data); +} + +/* +9EE8h W(R/W): Short Stroke Vector Transfer Register (SHORT_STROKE) +bit 0-3 Length of vector projected onto the major axis. + This is also the number of pixels drawn. + 4 Must be set for pixels to be written. + 5-7 VECDIR. The angle measured counter-clockwise from horizontal + right) at which the line is drawn, + 0 = 000 degrees + 1 = 045 degrees + 2 = 090 degrees + 3 = 135 degrees + 4 = 180 degrees + 5 = 225 degrees + 6 = 270 degrees + 7 = 315 degrees + 8-15 The lower 8 bits are duplicated in the upper 8 bits so two + short stroke vectors can be drawn with one command. +Note: The upper byte must be written for the SSV command to be executed. + Thus if a byte is written to 9EE8h another byte must be written to + 9EE9h before execution starts. A single 16bit write will do. + If only one SSV is desired the other byte can be set to 0. + */ +void ibm8514a_device::ibm8514_wait_draw_ssv() +{ + UINT8 len = ibm8514.wait_vector_len; + UINT8 dir = ibm8514.wait_vector_dir; + bool draw = ibm8514.wait_vector_draw; + UINT8 count = ibm8514.wait_vector_count; + UINT32 offset; + int x; + int data_size; + + switch(ibm8514.bus_size) + { + case 0: + data_size = 8; + break; + case 1: + data_size = 16; + break; + case 2: + data_size = 32; + break; + default: + data_size = 8; + break; + } + + for(x=0;x count) + { + if(ibm8514.state == IBM8514_DRAWING_SSV_1) + { + ibm8514.state = IBM8514_DRAWING_SSV_2; + ibm8514.wait_vector_len = (ibm8514.ssv & 0x0f00) >> 8; + ibm8514.wait_vector_dir = (ibm8514.ssv & 0xe000) >> 13; + ibm8514.wait_vector_draw = (ibm8514.ssv & 0x1000) ? true : false; + ibm8514.wait_vector_count = 0; + return; + } + else if(ibm8514.state == IBM8514_DRAWING_SSV_2) + { + ibm8514.state = IBM8514_IDLE; + ibm8514.gpbusy = false; + ibm8514.data_avail = false; + return; + } + } + + if(ibm8514.state == IBM8514_DRAWING_SSV_1 || ibm8514.state == IBM8514_DRAWING_SSV_2) + { + offset = (ibm8514.curr_y * IBM8514_LINE_LENGTH) + ibm8514.curr_x; + if(draw) + ibm8514_write(offset,offset); + switch(dir) + { + case 0: // 0 degrees + ibm8514.curr_x++; + break; + case 1: // 45 degrees + ibm8514.curr_x++; + ibm8514.curr_y--; + break; + case 2: // 90 degrees + ibm8514.curr_y--; + break; + case 3: // 135 degrees + ibm8514.curr_y--; + ibm8514.curr_x--; + break; + case 4: // 180 degrees + ibm8514.curr_x--; + break; + case 5: // 225 degrees + ibm8514.curr_x--; + ibm8514.curr_y++; + break; + case 6: // 270 degrees + ibm8514.curr_y++; + break; + case 7: // 315 degrees + ibm8514.curr_y++; + ibm8514.curr_x++; + break; + } + } + } +} + +void ibm8514a_device::ibm8514_draw_ssv(UINT8 data) +{ + UINT8 len = data & 0x0f; + UINT8 dir = (data & 0xe0) >> 5; + bool draw = (data & 0x10) ? true : false; + + ibm8514_draw_vector(len,dir,draw); +} + +READ16_MEMBER(ibm8514a_device::ibm8514_ssv_r) +{ + return ibm8514.ssv; +} + +WRITE16_MEMBER(ibm8514a_device::ibm8514_ssv_w) +{ + ibm8514.ssv = data; + + if(ibm8514.current_cmd & 0x0100) + { + ibm8514.state = IBM8514_DRAWING_SSV_1; + ibm8514.data_avail = true; + ibm8514.wait_vector_len = ibm8514.ssv & 0x0f; + ibm8514.wait_vector_dir = (ibm8514.ssv & 0xe0) >> 5; + ibm8514.wait_vector_draw = (ibm8514.ssv & 0x10) ? true : false; + ibm8514.wait_vector_count = 0; + return; + } + + if(ibm8514.current_cmd & 0x1000) // byte sequence + { + ibm8514_draw_ssv(data & 0xff); + ibm8514_draw_ssv(data >> 8); + } + else + { + ibm8514_draw_ssv(data >> 8); + ibm8514_draw_ssv(data & 0xff); + } + if(LOG_8514) logerror("8514/A: Short Stroke Vector write %04x\n",data); +} + +void ibm8514a_device::ibm8514_wait_draw_vector() +{ + UINT8 len = ibm8514.wait_vector_len; + UINT8 dir = ibm8514.wait_vector_dir; + bool draw = ibm8514.wait_vector_draw; + UINT8 count = ibm8514.wait_vector_count; + UINT32 offset; + UINT8 data_size = 0; + int x; + + if(ibm8514.bus_size == 0) // 8-bit + data_size = 8; + if(ibm8514.bus_size == 1) // 16-bit + data_size = 16; + if(ibm8514.bus_size == 2) // 32-bit + data_size = 32; + + for(x=0;x count) + { + if(ibm8514.state == IBM8514_DRAWING_LINE) + { + ibm8514.state = IBM8514_IDLE; + ibm8514.gpbusy = false; + ibm8514.data_avail = false; + return; + } + } + + if(ibm8514.state == IBM8514_DRAWING_LINE) + { + offset = (ibm8514.curr_y * IBM8514_LINE_LENGTH) + ibm8514.curr_x; + if(draw) + ibm8514_write(offset,offset); + switch(dir) + { + case 0: // 0 degrees + ibm8514.curr_x++; + break; + case 1: // 45 degrees + ibm8514.curr_x++; + ibm8514.curr_y--; + break; + case 2: // 90 degrees + ibm8514.curr_y--; + break; + case 3: // 135 degrees + ibm8514.curr_y--; + ibm8514.curr_x--; + break; + case 4: // 180 degrees + ibm8514.curr_x--; + break; + case 5: // 225 degrees + ibm8514.curr_x--; + ibm8514.curr_y++; + break; + case 6: // 270 degrees + ibm8514.curr_y++; + break; + case 7: // 315 degrees + ibm8514.curr_y++; + ibm8514.curr_x++; + break; + } + } + } +} + +/* +96E8h W(R/W): Major Axis Pixel Count/Rectangle Width Register (MAJ_AXIS_PCNT) +bit 0-10 (911/924) RECTANGLE WIDTH/LINE PARAMETER MAX. For BITBLT and + rectangle commands this is the width of the area. For Line Drawing + this is the Bresenham constant dmajor in two's complement format. + (dmajor is the length of the line projected onto the major or + independent axis). Must be positive. + 0-11 (80x +) RECTANGLE WIDTH/LINE PARAMETER MAX. See above + */ +READ16_MEMBER(ibm8514a_device::ibm8514_width_r) +{ + return ibm8514.rect_width; +} + +WRITE16_MEMBER(ibm8514a_device::ibm8514_width_w) +{ + ibm8514.rect_width = data & 0x1fff; + if(LOG_8514) logerror("8514/A: Major Axis Pixel Count / Rectangle Width write %04x\n",data); +} + +READ16_MEMBER(ibm8514a_device::ibm8514_currentx_r) +{ + return ibm8514.curr_x; +} + +WRITE16_MEMBER(ibm8514a_device::ibm8514_currentx_w) +{ + ibm8514.curr_x = data; + ibm8514.prev_x = data; + if(LOG_8514) logerror("8514/A: Current X set to %04x (%i)\n",data,ibm8514.curr_x); +} + +READ16_MEMBER(ibm8514a_device::ibm8514_currenty_r) +{ + return ibm8514.curr_y; +} + +WRITE16_MEMBER(ibm8514a_device::ibm8514_currenty_w) +{ + ibm8514.curr_y = data; + ibm8514.prev_y = data; + if(LOG_8514) logerror("8514/A: Current Y set to %04x (%i)\n",data,ibm8514.curr_y); +} + +READ16_MEMBER(ibm8514a_device::ibm8514_fgcolour_r) +{ + return ibm8514.fgcolour; +} + +WRITE16_MEMBER(ibm8514a_device::ibm8514_fgcolour_w) +{ + ibm8514.fgcolour = data; + if(LOG_8514) logerror("8514/A: Foreground Colour write %04x\n",data); +} + +READ16_MEMBER(ibm8514a_device::ibm8514_bgcolour_r) +{ + return ibm8514.bgcolour; +} + +WRITE16_MEMBER(ibm8514a_device::ibm8514_bgcolour_w) +{ + ibm8514.bgcolour = data; + if(LOG_8514) logerror("8514/A: Background Colour write %04x\n",data); +} + +/* +AEE8h W(R/W): Read Mask Register (RD_MASK) +bit 0-7 (911/924) Read Mask affects the following commands: CMD_RECT, + CMD_BITBLT and reading data in Across Plane Mode. + Each bit set prevents the plane from being read. + 0-15 (801/5) Readmask. See above. + 0-31 (928 +) Readmask. See above. In 32 bits per pixel modes there are + two 16bit registers at this address. BEE8h index 0Eh bit 4 selects + which 16 bits are accessible and each access toggles to the other + 16 bits. + */ +READ16_MEMBER(ibm8514a_device::ibm8514_read_mask_r) +{ + return ibm8514.read_mask & 0xffff; +} + +WRITE16_MEMBER(ibm8514a_device::ibm8514_read_mask_w) +{ + ibm8514.read_mask = (ibm8514.read_mask & 0xffff0000) | data; + if(LOG_8514) logerror("8514/A: Read Mask (Low) write = %08x\n",ibm8514.read_mask); +} + +/* +AAE8h W(R/W): Write Mask Register (WRT_MASK) +bit 0-7 (911/924) Writemask. A plane can only be modified if the + corresponding bit is set. + 0-15 (801/5) Writemask. See above. + 0-31 (928 +) Writemask. See above. In 32 bits per pixel modes there are + two 16bit registers at this address. BEE8h index 0Eh bit 4 selects + which 16 bits are accessible and each access toggles to the other + 16 bits. + */ +READ16_MEMBER(ibm8514a_device::ibm8514_write_mask_r) +{ + return ibm8514.write_mask & 0xffff; +} + +WRITE16_MEMBER(ibm8514a_device::ibm8514_write_mask_w) +{ + ibm8514.write_mask = (ibm8514.write_mask & 0xffff0000) | data; + if(LOG_8514) logerror("8514/A: Write Mask (Low) write = %08x\n",ibm8514.write_mask); +} + +READ16_MEMBER(ibm8514a_device::ibm8514_multifunc_r ) +{ + switch(ibm8514.multifunc_sel) + { + case 0: + return ibm8514.rect_height; + case 1: + return ibm8514.scissors_top; + case 2: + return ibm8514.scissors_left; + case 3: + return ibm8514.scissors_bottom; + case 4: + return ibm8514.scissors_right; + // TODO: remaining functions + default: + if(LOG_8514) logerror("8514/A: Unimplemented multifunction register %i selected\n",ibm8514.multifunc_sel); + return 0xff; + } +} + +WRITE16_MEMBER(ibm8514a_device::ibm8514_multifunc_w ) +{ + switch(data & 0xf000) + { +/* +BEE8h index 00h W(R/W): Minor Axis Pixel Count Register (MIN_AXIS_PCNT). +bit 0-10 (911/924) Rectangle Height. Height of BITBLT or rectangle command. + Actual height is one larger. + 0-11 (80x +) Rectangle Height. See above +*/ + case 0x0000: + ibm8514.rect_height = data & 0x0fff; + if(LOG_8514) logerror("8514/A: Minor Axis Pixel Count / Rectangle Height write %04x\n",data); + break; +/* +BEE8h index 01h W(R/W): Top Scissors Register (SCISSORS_T). +bit 0-10 (911/924) Clipping Top Limit. Defines the upper bound of the + Clipping Rectangle (Lowest Y coordinate). + 0-11 (80x +) Clipping Top Limit. See above + +BEE8h index 02h W(R/W): Left Scissors Registers (SCISSORS_L). +bit 0-10 (911,924) Clipping Left Limit. Defines the left bound of the + Clipping Rectangle (Lowest X coordinate). + 0-11 (80x +) Clipping Left Limit. See above. + +BEE8h index 03h W(R/W): Bottom Scissors Register (SCISSORS_B). +bit 0-10 (911,924) Clipping Bottom Limit. Defines the bottom bound of the + Clipping Rectangle (Highest Y coordinate). + 0-11 (80x +) Clipping Bottom Limit. See above. + +BEE8h index 04h W(R/W): Right Scissors Register (SCISSORS_R). +bit 0-10 (911,924) Clipping Right Limit. Defines the right bound of the + Clipping Rectangle (Highest X coordinate). + 0-11 (80x +) Clipping Bottom Limit. See above. + */ + case 0x1000: + ibm8514.scissors_top = data & 0x0fff; + if(LOG_8514) logerror("S3: Scissors Top write %04x\n",data); + break; + case 0x2000: + ibm8514.scissors_left = data & 0x0fff; + if(LOG_8514) logerror("S3: Scissors Left write %04x\n",data); + break; + case 0x3000: + ibm8514.scissors_bottom = data & 0x0fff; + if(LOG_8514) logerror("S3: Scissors Bottom write %04x\n",data); + break; + case 0x4000: + ibm8514.scissors_right = data & 0x0fff; + if(LOG_8514) logerror("S3: Scissors Right write %04x\n",data); + break; +/* +BEE8h index 0Ah W(R/W): Pixel Control Register (PIX_CNTL). +BIT 2 (911-928) Pack Data. If set image read data is a monochrome bitmap, + if clear it is a bitmap of the current pixel depth + 6-7 DT-EX-DRC. Select Mix Select. + 0 Foreground Mix is always used. + 1 use fixed pattern to decide which mix setting to use on a pixel + 2 CPU Data (Pixel Transfer register) determines the Mix register used. + 3 Video memory determines the Mix register used. + */ + case 0xa000: + ibm8514.pixel_control = data; + if(LOG_8514) logerror("S3: Pixel control write %04x\n",data); + break; + case 0xe000: + ibm8514.multifunc_misc = data; + if(LOG_8514) logerror("S3: Multifunction Miscellaneous write %04x\n",data); + break; +/* +BEE8h index 0Fh W(W): Read Register Select Register (READ_SEL) (801/5,928) +bit 0-2 (911-928) READ-REG-SEL. Read Register Select. Selects the register + that is actually read when a read of BEE8h happens. Each read of + BEE8h increments this register by one. + 0: Read will return contents of BEE8h index 0. + 1: Read will return contents of BEE8h index 1. + 2: Read will return contents of BEE8h index 2. + 3: Read will return contents of BEE8h index 3. + 4: Read will return contents of BEE8h index 4. + 5: Read will return contents of BEE8h index 0Ah. + 6: Read will return contents of BEE8h index 0Eh. + 7: Read will return contents of 9AE8h (Bits 13-15 will be 0). + 0-3 (864,964) READ-REG-SEL. See above plus: + 8: Read will return contents of 42E8h (Bits 12-15 will be 0) + 9: Read will return contents of 46E8h + 10: Read will return contents of BEE8h index 0Dh + */ + case 0xf000: + ibm8514.multifunc_sel = data & 0x000f; + if(LOG_8514) logerror("S3: Multifunction select write %04x\n",data); + default: + if(LOG_8514) logerror("S3: Unimplemented multifunction register %i write %03x\n",data >> 12,data & 0x0fff); + } +} + +void ibm8514a_device::ibm8514_wait_draw() +{ + int x, data_size = 8; + UINT32 off; + + // the data in the pixel transfer register or written to VRAM masks the rectangle output + if(ibm8514.bus_size == 0) // 8-bit + data_size = 8; + if(ibm8514.bus_size == 1) // 16-bit + data_size = 16; + if(ibm8514.bus_size == 2) // 32-bit + data_size = 32; + off = 0; + off += (IBM8514_LINE_LENGTH * ibm8514.curr_y); + off += ibm8514.curr_x; + if(ibm8514.current_cmd & 0x02) // "across plane mode" + { + for(x=0;x ibm8514.prev_x + ibm8514.rect_width) + { + ibm8514.curr_x = ibm8514.prev_x; + ibm8514.src_x = 0; + if(ibm8514.current_cmd & 0x0080) + { + ibm8514.curr_y++; + if(ibm8514.curr_y > ibm8514.prev_y + ibm8514.rect_height) + { + ibm8514.state = IBM8514_IDLE; + ibm8514.data_avail = false; + ibm8514.gpbusy = false; + } + } + else + { + ibm8514.curr_y--; + if(ibm8514.curr_y < ibm8514.prev_y - ibm8514.rect_height) + { + ibm8514.state = IBM8514_IDLE; + ibm8514.data_avail = false; + ibm8514.gpbusy = false; + } + } + return; + } + } + else + { + off--; + ibm8514.curr_x--; + if(ibm8514.curr_x < ibm8514.prev_x - ibm8514.rect_width) + { + ibm8514.curr_x = ibm8514.prev_x; + ibm8514.src_x = 0; + if(ibm8514.current_cmd & 0x0080) + { + ibm8514.curr_y++; + if(ibm8514.curr_y > ibm8514.prev_y + ibm8514.rect_height) + { + ibm8514.state = IBM8514_IDLE; + ibm8514.gpbusy = false; + ibm8514.data_avail = false; + } + } + else + { + ibm8514.curr_y--; + if(ibm8514.curr_y < ibm8514.prev_y - ibm8514.rect_height) + { + ibm8514.state = IBM8514_IDLE; + ibm8514.gpbusy = false; + ibm8514.data_avail = false; + } + } + return; + } + } + } + } + else + { + // "through plane" mode (single pixel) + for(x=0;x ibm8514.prev_x + ibm8514.rect_width) + { + ibm8514.curr_x = ibm8514.prev_x; + ibm8514.src_x = 0; + if(ibm8514.current_cmd & 0x0080) + { + ibm8514.curr_y++; + if(ibm8514.curr_y > ibm8514.prev_y + ibm8514.rect_height) + { + ibm8514.state = IBM8514_IDLE; + ibm8514.gpbusy = false; + ibm8514.data_avail = false; + } + } + else + { + ibm8514.curr_y--; + if(ibm8514.curr_y < ibm8514.prev_y - ibm8514.rect_height) + { + ibm8514.state = IBM8514_IDLE; + ibm8514.gpbusy = false; + ibm8514.data_avail = false; + } + } + return; + } + } + else + { + off--; + ibm8514.curr_x--; + if(ibm8514.curr_x < ibm8514.prev_x - ibm8514.rect_width) + { + ibm8514.curr_x = ibm8514.prev_x; + ibm8514.src_x = 0; + if(ibm8514.current_cmd & 0x0080) + { + ibm8514.curr_y++; + if(ibm8514.curr_y > ibm8514.prev_y + ibm8514.rect_height) + { + ibm8514.state = IBM8514_IDLE; + ibm8514.gpbusy = false; + ibm8514.data_avail = false; + } + } + else + { + ibm8514.curr_y--; + if(ibm8514.curr_y < ibm8514.prev_y - ibm8514.rect_height) + { + ibm8514.state = IBM8514_IDLE; + ibm8514.gpbusy = false; + ibm8514.data_avail = false; + } + } + return; + } + } + } + } +} + +/* +B6E8h W(R/W): Background Mix Register (BKGD_MIX) +bit 0-3 Background MIX (BACKMIX). + 00 not DST + 01 0 (false) + 02 1 (true) + 03 2 DST + 04 not SRC + 05 SRC xor DST + 06 not (SRC xor DST) + 07 SRC + 08 not (SRC and DST) + 09 (not SRC) or DST + 0A SRC or (not DST) + 0B SRC or DST + 0C SRC and DST + 0D SRC and (not DST) + 0E (not SRC) and DST + 0F not (SRC or DST) + DST is always the destination bitmap, bit SRC has four + possible sources selected by the BSS bits. + 5-6 Background Source Select (BSS) + 0 BSS is Background Color + 1 BSS is Foreground Color + 2 BSS is Pixel Data from the PIX_TRANS register (E2E8h) + 3 BSS is Bitmap Data (Source data from display buffer). + */ +READ16_MEMBER(ibm8514a_device::ibm8514_backmix_r) +{ + return ibm8514.bgmix; +} + +WRITE16_MEMBER(ibm8514a_device::ibm8514_backmix_w) +{ + ibm8514.bgmix = data; + if(LOG_8514) logerror("8514/A: BG Mix write %04x\n",data); +} + +READ16_MEMBER(ibm8514a_device::ibm8514_foremix_r) +{ + return ibm8514.fgmix; +} + +WRITE16_MEMBER(ibm8514a_device::ibm8514_foremix_w) +{ + ibm8514.fgmix = data; + if(LOG_8514) logerror("8514/A: FG Mix write %04x\n",data); +} + +READ16_MEMBER(ibm8514a_device::ibm8514_pixel_xfer_r) +{ + if(offset == 1) + return (ibm8514.pixel_xfer & 0xffff0000) >> 16; + else + return ibm8514.pixel_xfer & 0x0000ffff; +} + +WRITE16_MEMBER(ibm8514a_device::ibm8514_pixel_xfer_w) +{ + if(offset == 1) + ibm8514.pixel_xfer = (ibm8514.pixel_xfer & 0x0000ffff) | (data << 16); + else + ibm8514.pixel_xfer = (ibm8514.pixel_xfer & 0xffff0000) | data; + + if(ibm8514.state == IBM8514_DRAWING_RECT) + ibm8514_wait_draw(); + + if(ibm8514.state == IBM8514_DRAWING_SSV_1 || ibm8514.state == IBM8514_DRAWING_SSV_2) + ibm8514_wait_draw_ssv(); + + if(ibm8514.state == IBM8514_DRAWING_LINE) + ibm8514_wait_draw_vector(); + + if(LOG_8514) logerror("S3: Pixel Transfer = %08x\n",ibm8514.pixel_xfer); +} + +READ8_MEMBER(s3_vga_device::mem_r) +{ + if (svga.rgb8_en || svga.rgb15_en || svga.rgb16_en || svga.rgb32_en) + { + int data; + if(offset & 0x10000) + return 0; + data = 0; + if(vga.sequencer.data[4] & 0x8) + { + if((offset + (svga.bank_r*0x10000)) < vga.svga_intf.vram_size) + data = vga.memory[(offset + (svga.bank_r*0x10000))]; + } + else + { + int i; + + for(i=0;i<4;i++) + { + if(vga.sequencer.map_mask & 1 << i) + { + if((offset*4+i+(svga.bank_r*0x10000)) < vga.svga_intf.vram_size) + data |= vga.memory[(offset*4+i+(svga.bank_r*0x10000))]; + } + } + } + return data; + } + if((offset + (svga.bank_r*0x10000)) < vga.svga_intf.vram_size) + return vga_device::mem_r(space,offset,mem_mask); + else + return 0xff; +} + +WRITE8_MEMBER(s3_vga_device::mem_w) +{ + ibm8514a_device* dev = get_8514(); + // bit 4 of CR53 enables memory-mapped I/O + // 0xA0000-0xA7fff maps to port 0xE2E8 (pixel transfer) + if(s3.cr53 & 0x10) + { + if(offset < 0x8000) + { + // pass through to the pixel transfer register (DirectX 5 wants this) + if(dev->ibm8514.bus_size == 0) + { + dev->ibm8514.pixel_xfer = (dev->ibm8514.pixel_xfer & 0xffffff00) | data; + dev->ibm8514_wait_draw(); + } + if(dev->ibm8514.bus_size == 1) + { + switch(offset & 0x0001) + { + case 0: + default: + dev->ibm8514.pixel_xfer = (dev->ibm8514.pixel_xfer & 0xffffff00) | data; + break; + case 1: + dev->ibm8514.pixel_xfer = (dev->ibm8514.pixel_xfer & 0xffff00ff) | (data << 8); + dev->ibm8514_wait_draw(); + break; + } + } + if(dev->ibm8514.bus_size == 2) + { + switch(offset & 0x0003) + { + case 0: + default: + dev->ibm8514.pixel_xfer = (dev->ibm8514.pixel_xfer & 0xffffff00) | data; + break; + case 1: + dev->ibm8514.pixel_xfer = (dev->ibm8514.pixel_xfer & 0xffff00ff) | (data << 8); + break; + case 2: + dev->ibm8514.pixel_xfer = (dev->ibm8514.pixel_xfer & 0xff00ffff) | (data << 16); + break; + case 3: + dev->ibm8514.pixel_xfer = (dev->ibm8514.pixel_xfer & 0x00ffffff) | (data << 24); + dev->ibm8514_wait_draw(); + break; + } + } + return; + } + switch(offset) + { + case 0x8100: + case 0x82e8: + dev->ibm8514.curr_y = (dev->ibm8514.curr_y & 0xff00) | data; + dev->ibm8514.prev_y = (dev->ibm8514.prev_y & 0xff00) | data; + break; + case 0x8101: + case 0x82e9: + dev->ibm8514.curr_y = (dev->ibm8514.curr_y & 0x00ff) | (data << 8); + dev->ibm8514.prev_y = (dev->ibm8514.prev_y & 0x00ff) | (data << 8); + break; + case 0x8102: + case 0x86e8: + dev->ibm8514.curr_x = (dev->ibm8514.curr_x & 0xff00) | data; + dev->ibm8514.prev_x = (dev->ibm8514.prev_x & 0xff00) | data; + break; + case 0x8103: + case 0x86e9: + dev->ibm8514.curr_x = (dev->ibm8514.curr_x & 0x00ff) | (data << 8); + dev->ibm8514.prev_x = (dev->ibm8514.prev_x & 0x00ff) | (data << 8); + break; + case 0x8108: + case 0x8ae8: + dev->ibm8514.line_axial_step = (dev->ibm8514.line_axial_step & 0xff00) | data; + dev->ibm8514.dest_y = (dev->ibm8514.dest_y & 0xff00) | data; + break; + case 0x8109: + case 0x8ae9: + dev->ibm8514.line_axial_step = (dev->ibm8514.line_axial_step & 0x00ff) | ((data & 0x3f) << 8); + dev->ibm8514.dest_y = (dev->ibm8514.dest_y & 0x00ff) | (data << 8); + break; + case 0x810a: + case 0x8ee8: + dev->ibm8514.line_diagonal_step = (dev->ibm8514.line_diagonal_step & 0xff00) | data; + dev->ibm8514.dest_x = (dev->ibm8514.dest_x & 0xff00) | data; + break; + case 0x810b: + case 0x8ee9: + dev->ibm8514.line_diagonal_step = (dev->ibm8514.line_diagonal_step & 0x00ff) | ((data & 0x3f) << 8); + dev->ibm8514.dest_x = (dev->ibm8514.dest_x & 0x00ff) | (data << 8); + break; + case 0x8118: + case 0x9ae8: + s3.mmio_9ae8 = (s3.mmio_9ae8 & 0xff00) | data; + break; + case 0x8119: + case 0x9ae9: + s3.mmio_9ae8 = (s3.mmio_9ae8 & 0x00ff) | (data << 8); + dev->ibm8514_cmd_w(space,0,s3.mmio_9ae8,0xffff); + break; + case 0x8120: + case 0xa2e8: + dev->ibm8514.bgcolour = (dev->ibm8514.bgcolour & 0xff00) | data; + break; + case 0x8121: + case 0xa2e9: + dev->ibm8514.bgcolour = (dev->ibm8514.bgcolour & 0x00ff) | (data << 8); + break; + case 0x8124: + case 0xa6e8: + dev->ibm8514.fgcolour = (dev->ibm8514.fgcolour & 0xff00) | data; + break; + case 0x8125: + case 0xa6e9: + dev->ibm8514.fgcolour = (dev->ibm8514.fgcolour & 0x00ff) | (data << 8); + break; + case 0x8128: + case 0xaae8: + dev->ibm8514.write_mask = (dev->ibm8514.write_mask & 0xff00) | data; + break; + case 0x8129: + case 0xaae9: + dev->ibm8514.write_mask = (dev->ibm8514.write_mask & 0x00ff) | (data << 8); + break; + case 0x812c: + case 0xaee8: + dev->ibm8514.read_mask = (dev->ibm8514.read_mask & 0xff00) | data; + break; + case 0x812d: + case 0xaee9: + dev->ibm8514.read_mask = (dev->ibm8514.read_mask & 0x00ff) | (data << 8); + break; + case 0xb6e8: + case 0x8134: + dev->ibm8514.bgmix = (dev->ibm8514.bgmix & 0xff00) | data; + break; + case 0x8135: + case 0xb6e9: + dev->ibm8514.bgmix = (dev->ibm8514.bgmix & 0x00ff) | (data << 8); + break; + case 0x8136: + case 0xbae8: + dev->ibm8514.fgmix = (dev->ibm8514.fgmix & 0xff00) | data; + break; + case 0x8137: + case 0xbae9: + dev->ibm8514.fgmix = (dev->ibm8514.fgmix & 0x00ff) | (data << 8); + break; + case 0x8138: + dev->ibm8514.scissors_top = (dev->ibm8514.scissors_top & 0xff00) | data; + break; + case 0x8139: + dev->ibm8514.scissors_top = (dev->ibm8514.scissors_top & 0x00ff) | (data << 8); + break; + case 0x813a: + dev->ibm8514.scissors_left = (dev->ibm8514.scissors_left & 0xff00) | data; + break; + case 0x813b: + dev->ibm8514.scissors_left = (dev->ibm8514.scissors_left & 0x00ff) | (data << 8); + break; + case 0x813c: + dev->ibm8514.scissors_bottom = (dev->ibm8514.scissors_bottom & 0xff00) | data; + break; + case 0x813d: + dev->ibm8514.scissors_bottom = (dev->ibm8514.scissors_bottom & 0x00ff) | (data << 8); + break; + case 0x813e: + dev->ibm8514.scissors_right = (dev->ibm8514.scissors_right & 0xff00) | data; + break; + case 0x813f: + dev->ibm8514.scissors_right = (dev->ibm8514.scissors_right & 0x00ff) | (data << 8); + break; + case 0x8140: + dev->ibm8514.pixel_control = (dev->ibm8514.pixel_control & 0xff00) | data; + break; + case 0x8141: + dev->ibm8514.pixel_control = (dev->ibm8514.pixel_control & 0x00ff) | (data << 8); + break; + case 0x8146: + dev->ibm8514.multifunc_sel = (dev->ibm8514.multifunc_sel & 0xff00) | data; + break; + case 0x8148: + dev->ibm8514.rect_height = (dev->ibm8514.rect_height & 0xff00) | data; + break; + case 0x8149: + dev->ibm8514.rect_height = (dev->ibm8514.rect_height & 0x00ff) | (data << 8); + break; + case 0x814a: + dev->ibm8514.rect_width = (dev->ibm8514.rect_width & 0xff00) | data; + break; + case 0x814b: + dev->ibm8514.rect_width = (dev->ibm8514.rect_width & 0x00ff) | (data << 8); + break; + case 0x8150: + dev->ibm8514.pixel_xfer = (dev->ibm8514.pixel_xfer & 0xffffff00) | data; + if(dev->ibm8514.state == IBM8514_DRAWING_RECT) + dev->ibm8514_wait_draw(); + break; + case 0x8151: + dev->ibm8514.pixel_xfer = (dev->ibm8514.pixel_xfer & 0xffff00ff) | (data << 8); + if(dev->ibm8514.state == IBM8514_DRAWING_RECT) + dev->ibm8514_wait_draw(); + break; + case 0x8152: + dev->ibm8514.pixel_xfer = (dev->ibm8514.pixel_xfer & 0xff00ffff) | (data << 16); + if(dev->ibm8514.state == IBM8514_DRAWING_RECT) + dev->ibm8514_wait_draw(); + break; + case 0x8153: + dev->ibm8514.pixel_xfer = (dev->ibm8514.pixel_xfer & 0x00ffffff) | (data << 24); + if(dev->ibm8514.state == IBM8514_DRAWING_RECT) + dev->ibm8514_wait_draw(); + break; + case 0xbee8: + s3.mmio_bee8 = (s3.mmio_bee8 & 0xff00) | data; + break; + case 0xbee9: + s3.mmio_bee8 = (s3.mmio_bee8 & 0x00ff) | (data << 8); + dev->ibm8514_multifunc_w(space,0,s3.mmio_bee8,0xffff); + break; + case 0x96e8: + s3.mmio_96e8 = (s3.mmio_96e8 & 0xff00) | data; + break; + case 0x96e9: + s3.mmio_96e8 = (s3.mmio_96e8 & 0x00ff) | (data << 8); + dev->ibm8514_width_w(space,0,s3.mmio_96e8,0xffff); + break; + case 0xe2e8: + dev->ibm8514.pixel_xfer = (dev->ibm8514.pixel_xfer & 0xffffff00) | data; + dev->ibm8514_wait_draw(); + break; + default: + if(LOG_8514) logerror("S3: MMIO offset %05x write %02x\n",offset+0xa0000,data); + } + return; + } + + if (svga.rgb8_en || svga.rgb15_en || svga.rgb16_en || svga.rgb32_en) + { + //printf("%08x %02x (%02x %02x) %02X\n",offset,data,vga.sequencer.map_mask,svga.bank_w,(vga.sequencer.data[4] & 0x08)); + if(offset & 0x10000) + return; + if(vga.sequencer.data[4] & 0x8) + { + if((offset + (svga.bank_w*0x10000)) < vga.svga_intf.vram_size) + vga.memory[(offset + (svga.bank_w*0x10000))] = data; + } + else + { + int i; + for(i=0;i<4;i++) + { + if(vga.sequencer.map_mask & 1 << i) + { + if((offset*4+i+(svga.bank_w*0x10000)) < vga.svga_intf.vram_size) + vga.memory[(offset*4+i+(svga.bank_w*0x10000))] = data; + } + } + } + return; + } + + if((offset + (svga.bank_w*0x10000)) < vga.svga_intf.vram_size) + vga_device::mem_w(space,offset,data,mem_mask); +} + +/****************************************** + +gamtor.c implementation (TODO: identify the video card) + +******************************************/ + +READ8_MEMBER(gamtor_vga_device::mem_r) +{ + return vga.memory[offset]; +} + +WRITE8_MEMBER(gamtor_vga_device::mem_w) +{ + vga.memory[offset] = data; +} + + +READ8_MEMBER(gamtor_vga_device::port_03b0_r) +{ + UINT8 res; + + switch(offset) + { + default: + res = vga_device::port_03b0_r(space,offset ^ 3,mem_mask); + break; + } + + return res; +} + +WRITE8_MEMBER(gamtor_vga_device::port_03b0_w) +{ + switch(offset) + { + default: + vga_device::port_03b0_w(space,offset ^ 3,data,mem_mask); + break; + } +} + +READ8_MEMBER(gamtor_vga_device::port_03c0_r) +{ + UINT8 res; + + switch(offset) + { + default: + res = vga_device::port_03c0_r(space,offset ^ 3,mem_mask); + break; + } + + return res; +} + +WRITE8_MEMBER(gamtor_vga_device::port_03c0_w) +{ + switch(offset) + { + default: + vga_device::port_03c0_w(space,offset ^ 3,data,mem_mask); + break; + } +} + +READ8_MEMBER(gamtor_vga_device::port_03d0_r) +{ + UINT8 res; + + switch(offset) + { + default: + res = vga_device::port_03d0_r(space,offset ^ 3,mem_mask); + break; + } + + return res; +} + +WRITE8_MEMBER(gamtor_vga_device::port_03d0_w) +{ + switch(offset) + { + default: + vga_device::port_03d0_w(space,offset ^ 3,data,mem_mask); + break; + } +} + +UINT16 ati_vga_device::offset() +{ + //popmessage("Offset: %04x %s %s %s %s",vga.crtc.offset,vga.crtc.dw?"DW":"--",vga.crtc.word_mode?"BYTE":"WORD",(ati.ext_reg[0x33] & 0x40) ? "PEL" : "---",(ati.ext_reg[0x30] & 0x20) ? "256" : "---"); + if(ati.ext_reg[0x30] & 0x20) // likely wrong, gets 640x400/480 SVGA and tweaked 256 colour modes displaying correctly in Fractint. + return vga_device::offset() << 3; + if(ati.ext_reg[0x33] & 0x40) + return vga_device::offset() << 2; + return vga_device::offset(); +} + + +void ati_vga_device::ati_define_video_mode() +{ + int clock; + UINT8 clock_type; + int div = ((ati.ext_reg[0x38] & 0xc0) >> 6) + 1; + int divisor = 1; + + svga.rgb8_en = 0; + svga.rgb15_en = 0; + svga.rgb16_en = 0; + svga.rgb32_en = 0; + + if(ati.ext_reg[0x30] & 0x20) + svga.rgb8_en = 1; + + clock_type = ((ati.ext_reg[0x3e] & 0x10)>>1) | ((ati.ext_reg[0x39] & 0x02)<<1) | ((vga.miscellaneous_output & 0x0c)>>2); + switch(clock_type) + { + case 0: + clock = XTAL_42_9545MHz; + break; + case 1: + clock = 48771000; + break; + case 2: + clock = 16657000; + break; + case 3: + clock = XTAL_36MHz; + break; + case 4: + clock = 50350000; + break; + case 5: + clock = 56640000; + break; + case 6: + clock = 28322000; + break; + case 7: + clock = 44900000; + break; + case 8: + clock = 30240000; + break; + case 9: + clock = XTAL_32MHz; + break; + case 10: + clock = 37500000; + break; + case 11: + clock = 39000000; + break; + case 12: + clock = XTAL_40MHz; + break; + case 13: + clock = 56644000; + break; + case 14: + clock = 75000000; + break; + case 15: + clock = 65000000; + break; + default: + clock = XTAL_42_9545MHz; + logerror("Invalid dot clock %i selected.\n",clock_type); + } +// logerror("ATI: Clock select type %i (%iHz / %i)\n",clock_type,clock,div); + recompute_params_clock(divisor,clock / div); +} + +READ8_MEMBER(ati_vga_device::mem_r) +{ + if(svga.rgb8_en || svga.rgb15_en || svga.rgb16_en || svga.rgb24_en) + { + if(ati.ext_reg[0x3d] & 0x04) + { + offset &= 0x1ffff; + return vga.memory[(offset+svga.bank_r*0x20000) % vga.svga_intf.vram_size]; + } + else + { + offset &= 0xffff; + return vga.memory[(offset+svga.bank_r*0x10000) % vga.svga_intf.vram_size]; + } + } + + return vga_device::mem_r(space,offset,mem_mask); +} + +WRITE8_MEMBER(ati_vga_device::mem_w) +{ + if(svga.rgb8_en || svga.rgb15_en || svga.rgb16_en || svga.rgb24_en) + { + if(ati.ext_reg[0x3d] & 0x04) + { + offset &= 0x1ffff; + vga.memory[(offset+svga.bank_w*0x20000) % vga.svga_intf.vram_size] = data; + } + else + { + offset &= 0xffff; + vga.memory[(offset+svga.bank_w*0x10000) % vga.svga_intf.vram_size] = data; + } + } + else + vga_device::mem_w(space,offset,data,mem_mask); +} + + +READ8_MEMBER(ati_vga_device::ati_port_ext_r) +{ + UINT8 ret = 0xff; + + switch(offset) + { + case 0: + break; + case 1: + switch(ati.ext_reg_select) + { + case 0x20: + ret = 0x10; // 512kB memory + break; + case 0x28: // Vertical line counter (high) + ret = (machine().first_screen()->vpos() >> 8) & 0x03; + break; + case 0x29: // Vertical line counter (low) + ret = machine().first_screen()->vpos() & 0xff; // correct? + break; + case 0x2a: + ret = ati.vga_chip_id; // Chip revision (6 for the 28800-6, 5 for the 28800-5) + break; + case 0x37: + { + eeprom_serial_93cxx_device* eep = subdevice("ati_eeprom"); + ret = 0x00; + ret |= eep->do_read() << 3; + } + break; + case 0x3d: + ret = ati.ext_reg[ati.ext_reg_select] & 0x0f; + ret |= 0x10; // EGA DIP switch emulation + break; + default: + ret = ati.ext_reg[ati.ext_reg_select]; + logerror("ATI: Extended VGA register 0x01CE index %02x read\n",ati.ext_reg_select); + } + break; + } + return ret; +} + +WRITE8_MEMBER(ati_vga_device::ati_port_ext_w) +{ + switch(offset) + { + case 0: + ati.ext_reg_select = data & 0x3f; + break; + case 1: + ati.ext_reg[ati.ext_reg_select] = data; + switch(ati.ext_reg_select) + { + case 0x23: + vga.crtc.start_addr_latch = (vga.crtc.start_addr_latch & 0xfffdffff) | ((data & 0x10) << 13); + vga.crtc.cursor_addr = (vga.crtc.cursor_addr & 0xfffdffff) | ((data & 0x08) << 14); + logerror("ATI: ATI23 write %02x\n",data); + break; + case 0x2d: + if(data & 0x08) + { + vga.crtc.horz_total = (vga.crtc.horz_total & 0x00ff) | (data & 0x01) << 8; + // bit 1 = bit 8 of horizontal blank start + // bit 2 = bit 8 of horizontal retrace start + } + logerror("ATI: ATI2D (extensions) write %02x\n",data); + break; + case 0x30: + vga.crtc.start_addr_latch = (vga.crtc.start_addr_latch & 0xfffeffff) | ((data & 0x40) << 10); + vga.crtc.cursor_addr = (vga.crtc.cursor_addr & 0xfffeffff) | ((data & 0x04) << 14); + logerror("ATI: ATI30 write %02x\n",data); + break; + case 0x32: // memory page select + if(ati.ext_reg[0x3e] & 0x08) + { + svga.bank_r = ((data & 0x01) << 3) | ((data & 0xe0) >> 5); + svga.bank_w = ((data & 0x1e) >> 1); + } + else + { + svga.bank_r = ((data & 0x1e) >> 1); + svga.bank_w = ((data & 0x1e) >> 1); + } + //logerror("ATI: Memory Page Select write %02x (read: %i write %i)\n",data,svga.bank_r,svga.bank_w); + break; + case 0x33: // EEPROM + if(data & 0x04) + { + eeprom_serial_93cxx_device* eep = subdevice("ati_eeprom"); + if(eep != NULL) + { + eep->di_write((data & 0x01) ? ASSERT_LINE : CLEAR_LINE); + eep->clk_write((data & 0x02) ? ASSERT_LINE : CLEAR_LINE); + eep->cs_write((data & 0x08) ? ASSERT_LINE : CLEAR_LINE); + } + } + else + logerror("ATI: ATI33 write %02x\n",data); + break; + default: + logerror("ATI: Extended VGA register 0x01CE index %02x write %02x\n",ati.ext_reg_select,data); + } + break; + } + ati_define_video_mode(); +} + +/* +02E8h W(R): Display Status Register +bit 0 SENSE is the result of a wired-OR of 3 comparators, one + for each of the RGB video signal. + By programming the RAMDAC for various values + and patterns and then reading the SENSE, the monitor type + (color, monochrome or none) can be determined. + 1 VBLANK. Vertical Blank State + If Vertical Blank is active this bit is set. + 2 HORTOG. Horizontal Toggle + This bit toggles every time a HSYNC pulse starts + 3-15 Reserved(0) + */ +READ16_MEMBER(ibm8514a_device::ibm8514_status_r) +{ + return m_vga->vga_vblank() << 1; +} + +WRITE16_MEMBER(ibm8514a_device::ibm8514_htotal_w) +{ + ibm8514.htotal = data & 0x01ff; + //vga.crtc.horz_total = data & 0x01ff; + if(LOG_8514) logerror("8514/A: Horizontal total write %04x\n",data); +} + +/* +42E8h W(R): Subsystem Status Register (SUBSYS_STAT) +bit 0-3 Interrupt requests. These bits show the state of internal interrupt + requests. An interrupt will only occur if the corresponding bit(s) + in SUBSYS_CNTL is set. Interrupts can only be reset by writing a 1 + to the corresponding Interrupt Clear bit in SUBSYS_CNTL. + Bit 0: VBLNKFLG + 1: PICKFLAG + 2: INVALIDIO + 3: GPIDLE + 4-6 MONITORID. + 1: IBM 8507 (1024x768) Monochrome + 2: IBM 8514 (1024x768) Color + 5: IBM 8503 (640x480) Monochrome + 6: IBM 8512/13 (640x480) Color + 7 8PLANE. + (CT82c480) This bit is latched on reset from pin P4D7. + 8-11 CHIP_REV. Chip revision number. + 12-15 (CT82c480) CHIP_ID. 0=CT 82c480. + */ +READ16_MEMBER(ibm8514a_device::ibm8514_substatus_r) +{ + // TODO: + if(m_vga->vga_vblank() != 0) // not correct, but will do for now + ibm8514.substatus |= 0x01; + return ibm8514.substatus; +} + +/* +42E8h W(W): Subsystem Control Register (SUBSYS_CNTL) +bit 0-3 Interrupt Reset. Write 1 to a bit to reset the interrupt. + Bit 0 RVBLNKFLG Write 1 to reset Vertical Blank interrupt. + 1 RPICKFLAG Write 1 to reset PICK interrupt. + 2 RINVALIDIO Write 1 to reset Queue Overflow/Data + Underflow interrupt. + 3 RGPIDLE Write 1 to reset GPIDLE interrupt. + 4-7 Reserved(0) + 8 IBLNKFLG. If set Vertical Blank Interrupts are enabled. + 9 IPICKFLAG. If set PICK Interrupts are enabled. + 10 IINVALIDIO. If set Queue Overflow/Data Underflow Interrupts are + enabled. + 11 IGPIDLE. If set Graphics Engine Idle Interrupts are enabled. + 12-13 CHPTEST. Used for chip testing. + 14-15 Graphics Processor Control (GPCTRL). + */ +WRITE16_MEMBER(ibm8514a_device::ibm8514_subcontrol_w) +{ + ibm8514.subctrl = data; + ibm8514.substatus &= ~(data & 0x0f); // reset interrupts +// if(LOG_8514) logerror("8514/A: Subsystem control write %04x\n",data); +} + +READ16_MEMBER(ibm8514a_device::ibm8514_subcontrol_r) +{ + return ibm8514.subctrl; +} + +READ16_MEMBER(ibm8514a_device::ibm8514_htotal_r) +{ + return ibm8514.htotal; +} + +READ16_MEMBER(ibm8514a_device::ibm8514_vtotal_r) +{ + return ibm8514.vtotal; +} + +WRITE16_MEMBER(ibm8514a_device::ibm8514_vtotal_w) +{ + ibm8514.vtotal = data; +// vga.crtc.vert_total = data; + if(LOG_8514) logerror("8514/A: Vertical total write %04x\n",data); +} + +READ16_MEMBER(ibm8514a_device::ibm8514_vdisp_r) +{ + return ibm8514.vdisp; +} + +WRITE16_MEMBER(ibm8514a_device::ibm8514_vdisp_w) +{ + ibm8514.vdisp = data; +// vga.crtc.vert_disp_end = data >> 3; + if(LOG_8514) logerror("8514/A: Vertical Displayed write %04x\n",data); +} + +READ16_MEMBER(ibm8514a_device::ibm8514_vsync_r) +{ + return ibm8514.vsync; +} + +WRITE16_MEMBER(ibm8514a_device::ibm8514_vsync_w) +{ + ibm8514.vsync = data; + if(LOG_8514) logerror("8514/A: Vertical Sync write %04x\n",data); +} + +void ibm8514a_device::enabled() +{ + ibm8514.state = IBM8514_IDLE; + ibm8514.gpbusy = false; +} + +READ16_MEMBER(mach8_device::mach8_ec0_r) +{ + return ibm8514.ec0; +} + +WRITE16_MEMBER(mach8_device::mach8_ec0_w) +{ + ibm8514.ec0 = data; + if(LOG_8514) logerror("8514/A: Extended configuration 0 write %04x\n",data); +} + +READ16_MEMBER(mach8_device::mach8_ec1_r) +{ + return ibm8514.ec1; +} + +WRITE16_MEMBER(mach8_device::mach8_ec1_w) +{ + ibm8514.ec1 = data; + if(LOG_8514) logerror("8514/A: Extended configuration 1 write %04x\n",data); +} + +READ16_MEMBER(mach8_device::mach8_ec2_r) +{ + return ibm8514.ec2; +} + +WRITE16_MEMBER(mach8_device::mach8_ec2_w) +{ + ibm8514.ec2 = data; + if(LOG_8514) logerror("8514/A: Extended configuration 2 write %04x\n",data); +} + +READ16_MEMBER(mach8_device::mach8_ec3_r) +{ + return ibm8514.ec3; +} + +WRITE16_MEMBER(mach8_device::mach8_ec3_w) +{ + ibm8514.ec3 = data; + if(LOG_8514) logerror("8514/A: Extended configuration 3 write %04x\n",data); +} + +READ16_MEMBER(mach8_device::mach8_ext_fifo_r) +{ + return 0x00; // for now, report all FIFO slots at free +} + +WRITE16_MEMBER(mach8_device::mach8_linedraw_index_w) +{ + mach8.linedraw = data & 0x07; + if(LOG_8514) logerror("Mach8: Line Draw Index write %04x\n",data); +} + +READ16_MEMBER(mach8_device::mach8_bresenham_count_r) +{ + return ibm8514.rect_width & 0x1fff; +} + +WRITE16_MEMBER(mach8_device::mach8_bresenham_count_w) +{ + ibm8514.rect_width = data & 0x1fff; + if(LOG_8514) logerror("Mach8: Bresenham count write %04x\n",data); +} + +READ16_MEMBER(mach8_device::mach8_linedraw_r) +{ + return 0xff; +} + +WRITE16_MEMBER(mach8_device::mach8_linedraw_w) +{ + // TODO: actually draw the lines + switch(mach8.linedraw) + { + case 0: // Set current X + ibm8514.curr_x = data; + mach8.linedraw++; + break; + case 1: // Set current Y + ibm8514.curr_y = data; + mach8.linedraw++; + break; + case 2: // Line end X + ibm8514.curr_x = data; + mach8.linedraw++; + break; + case 3: // Line end Y + ibm8514.curr_y = data; + mach8.linedraw = 2; + break; + case 4: // Set current X + ibm8514.curr_x = data; + mach8.linedraw++; + break; + case 5: // Set current Y + ibm8514.curr_y = data; + mach8.linedraw = 4; + break; + } + logerror("ATI: Linedraw register write %04x, mode %i\n",data,mach8.linedraw); +} + +READ16_MEMBER(mach8_device::mach8_sourcex_r) +{ + return ibm8514.dest_x; +} + +READ16_MEMBER(mach8_device::mach8_sourcey_r) +{ + return ibm8514.dest_y; +} + +WRITE16_MEMBER(mach8_device::mach8_ext_leftscissor_w) +{ + // TODO +} + +WRITE16_MEMBER(mach8_device::mach8_ext_topscissor_w) +{ + // TODO +} + +READ16_MEMBER(mach8_device::mach8_scratch0_r) +{ + return mach8.scratch0; +} + +WRITE16_MEMBER(mach8_device::mach8_scratch0_w) +{ + mach8.scratch0 = data; + if(LOG_8514) logerror("Mach8: Scratch Pad 0 write %04x\n",data); +} + +READ16_MEMBER(mach8_device::mach8_scratch1_r) +{ + return mach8.scratch1; +} + +WRITE16_MEMBER(mach8_device::mach8_scratch1_w) +{ + mach8.scratch1 = data; + if(LOG_8514) logerror("Mach8: Scratch Pad 1 write %04x\n",data); +} + +/* +12EEh W(R): Configuration Status 1 Register (Mach8) +bit 0 CLK_MODE. Set to use clock chip, clear to use crystals. + 1 BUS_16. Set for 16bit bus, clear for 8bit bus + 2 MC_BUS. Set for MicroChannel bus, clear for ISA/EISA bus + 3 EEPROM_ENA. EEPROM enabled if set + 4 DRAM_ENA. Set for DRAM, clear for VRAM. + 5-6 MEM_INSTALLED. Video memory. 0: 512K, 1: 1024K + 7 ROM_ENA. Set is ROM is enabled + 8 ROM_PAGE_ENA. Set if ROM paging enabled + 9-15 ROM_LOCATION. If bit 2 and 3 are 0 the ROM will be at this location: + 0: C000h, 1: C080h, 2: C100h, .. 127: FF80h (unlikely) + */ +READ16_MEMBER(mach8_device::mach8_config1_r) +{ + return 0x0082; +} + +/* +16EEh (R): Configuration Status 2 Register (Mach8) +bit 0 SHARE_CLOCK. If set the Mach8 shares clock with the VGA + 1 HIRES_BOOT. Boot in hi-res mode if set + 2 EPROM_16_ENA. Adapter configured for 16bit ROM if set + 3 WRITE_PER_BIT. Write masked VRAM operations supported if set + 4 FLASH_ENA. Flash page writes supported if set + */ +READ16_MEMBER(mach8_device::mach8_config2_r) +{ + return 0x0002; +} diff --git a/src/devices/video/pc_vga.h b/src/devices/video/pc_vga.h new file mode 100644 index 00000000000..ee0504a95e1 --- /dev/null +++ b/src/devices/video/pc_vga.h @@ -0,0 +1,705 @@ +// license:BSD-3-Clause +// copyright-holders:Nathan Woods, Peter Trauner, Angelo Salese +/*************************************************************************** + + pc_vga.h + + PC standard VGA adaptor + +***************************************************************************/ + +#ifndef PC_VGA_H +#define PC_VGA_H + +MACHINE_CONFIG_EXTERN( pcvideo_vga ); +MACHINE_CONFIG_EXTERN( pcvideo_trident_vga ); +MACHINE_CONFIG_EXTERN( pcvideo_gamtor_vga ); +MACHINE_CONFIG_EXTERN( pcvideo_s3_vga ); + +enum +{ + SCREEN_OFF = 0, + TEXT_MODE, + VGA_MODE, + EGA_MODE, + CGA_MODE, + MONO_MODE, + RGB8_MODE, + RGB15_MODE, + RGB16_MODE, + RGB24_MODE, + RGB32_MODE +}; + +// ======================> vga_device + +class vga_device : public device_t +{ + friend class ibm8514a_device; + +public: + // construction/destruction + vga_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + vga_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + virtual void zero(); + virtual UINT32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); + + virtual READ8_MEMBER(port_03b0_r); + virtual WRITE8_MEMBER(port_03b0_w); + virtual READ8_MEMBER(port_03c0_r); + virtual WRITE8_MEMBER(port_03c0_w); + virtual READ8_MEMBER(port_03d0_r); + virtual WRITE8_MEMBER(port_03d0_w); + virtual READ8_MEMBER(mem_r); + virtual WRITE8_MEMBER(mem_w); + virtual READ8_MEMBER(mem_linear_r); + virtual WRITE8_MEMBER(mem_linear_w); + virtual TIMER_CALLBACK_MEMBER(vblank_timer_cb); +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + void vga_vh_text(bitmap_rgb32 &bitmap, const rectangle &cliprect); + void vga_vh_ega(bitmap_rgb32 &bitmap, const rectangle &cliprect); + void vga_vh_vga(bitmap_rgb32 &bitmap, const rectangle &cliprect); + void vga_vh_cga(bitmap_rgb32 &bitmap, const rectangle &cliprect); + void vga_vh_mono(bitmap_rgb32 &bitmap, const rectangle &cliprect); + virtual UINT8 pc_vga_choosevideomode(); + void recompute_params_clock(int divisor, int xtal); + UINT8 crtc_reg_read(UINT8 index); + void recompute_params(); + void crtc_reg_write(UINT8 index, UINT8 data); + void seq_reg_write(UINT8 index, UINT8 data); + UINT8 vga_vblank(); + READ8_MEMBER(vga_crtc_r); + WRITE8_MEMBER(vga_crtc_w); + UINT8 gc_reg_read(UINT8 index); + void attribute_reg_write(UINT8 index, UINT8 data); + void gc_reg_write(UINT8 index,UINT8 data); + virtual UINT16 offset(); + inline UINT8 vga_latch_write(int offs, UINT8 data); + inline UINT8 rotate_right(UINT8 val) { return (val >> vga.gc.rotate_count) | (val << (8 - vga.gc.rotate_count)); } + inline UINT8 vga_logical_op(UINT8 data, UINT8 plane, UINT8 mask) + { + UINT8 res = 0; + + switch(vga.gc.logical_op & 3) + { + case 0: /* NONE */ + res = (data & mask) | (vga.gc.latch[plane] & ~mask); + break; + case 1: /* AND */ + res = (data | ~mask) & (vga.gc.latch[plane]); + break; + case 2: /* OR */ + res = (data & mask) | (vga.gc.latch[plane]); + break; + case 3: /* XOR */ + res = (data & mask) ^ (vga.gc.latch[plane]); + break; + } + + return res; + } + + + struct + { + read8_delegate read_dipswitch; + struct + { + size_t vram_size; + int seq_regcount; + int crtc_regcount; + } svga_intf; + + dynamic_buffer memory; + UINT32 pens[16]; /* the current 16 pens */ + + UINT8 miscellaneous_output; + UINT8 feature_control; + + struct + { + UINT8 index; + UINT8 data[0x100]; + UINT8 map_mask; + struct + { + UINT8 A, B; + }char_sel; + } sequencer; + + /* An empty comment at the start of the line indicates that register is currently unused */ + struct + { + UINT8 index; + UINT8 data[0x100]; + UINT16 horz_total; + UINT16 horz_disp_end; + /**/ UINT8 horz_blank_start; + /**/ UINT8 horz_blank_end; + /**/ UINT8 horz_retrace_start; + /**/ UINT8 horz_retrace_skew; + /**/ UINT8 horz_retrace_end; + /**/ UINT8 disp_enable_skew; + /**/ UINT8 evra; + UINT16 vert_total; + UINT16 vert_disp_end; + /**/ UINT16 vert_retrace_start; + /**/ UINT8 vert_retrace_end; + /**/ UINT16 vert_blank_start; + UINT16 line_compare; + /**/ UINT32 cursor_addr; + /**/ UINT8 byte_panning; + /**/ UINT8 preset_row_scan; + UINT8 scan_doubling; + /**/ UINT8 maximum_scan_line; + /**/ UINT8 cursor_enable; + /**/ UINT8 cursor_scan_start; + /**/ UINT8 cursor_skew; + /**/ UINT8 cursor_scan_end; + UINT32 start_addr; + UINT32 start_addr_latch; + /**/ UINT8 protect_enable; + /**/ UINT8 bandwidth; + /**/ UINT16 offset; + /**/ UINT8 word_mode; + /**/ UINT8 dw; + /**/ UINT8 div4; + /**/ UINT8 underline_loc; + /**/ UINT16 vert_blank_end; + UINT8 sync_en; + /**/ UINT8 aw; + /**/ UINT8 div2; + /**/ UINT8 sldiv; + /**/ UINT8 map14; + /**/ UINT8 map13; + /**/ UINT8 irq_clear; + /**/ UINT8 irq_disable; + } crtc; + + struct + { + UINT8 index; + UINT8 latch[4]; + UINT8 set_reset; + UINT8 enable_set_reset; + UINT8 color_compare; + UINT8 logical_op; + UINT8 rotate_count; + UINT8 shift256; + UINT8 shift_reg; + UINT8 read_map_sel; + UINT8 read_mode; + UINT8 write_mode; + UINT8 color_dont_care; + UINT8 bit_mask; + UINT8 alpha_dis; + UINT8 memory_map_sel; + UINT8 host_oe; + UINT8 chain_oe; + } gc; + + struct + { + UINT8 index, data[0x15]; int state; + UINT8 prot_bit; + UINT8 pel_shift; + UINT8 pel_shift_latch; + } attribute; + + + struct { + UINT8 read_index, write_index, mask; + int read; + int state; + struct { UINT8 red, green, blue; } color[0x100]; + int dirty; + } dac; + + struct { + UINT8 visible; + } cursor; + + /* oak vga */ + struct { UINT8 reg; } oak; + } vga; + + emu_timer *m_vblank_timer; + required_device m_palette; + required_device m_screen; +}; + + +// device type definition +extern const device_type VGA; + +// ======================> svga_device + +class svga_device : public vga_device +{ +public: + // construction/destruction + svga_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + virtual void zero(); + virtual UINT32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); +protected: + void svga_vh_rgb8(bitmap_rgb32 &bitmap, const rectangle &cliprect); + void svga_vh_rgb15(bitmap_rgb32 &bitmap, const rectangle &cliprect); + void svga_vh_rgb16(bitmap_rgb32 &bitmap, const rectangle &cliprect); + void svga_vh_rgb24(bitmap_rgb32 &bitmap, const rectangle &cliprect); + void svga_vh_rgb32(bitmap_rgb32 &bitmap, const rectangle &cliprect); + virtual UINT8 pc_vga_choosevideomode(); + virtual void device_start(); + struct + { + UINT8 bank_r,bank_w; + UINT8 rgb8_en; + UINT8 rgb15_en; + UINT8 rgb16_en; + UINT8 rgb24_en; + UINT8 rgb32_en; + UINT8 id; + }svga; +private: +}; + +// ======================> ibm8514_device + +class ibm8514a_device : public device_t +{ +public: + ibm8514a_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + ibm8514a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + void set_vga(const char* tag) { m_vga_tag.assign(tag); } + void set_vga_owner() { m_vga = dynamic_cast(owner()); } + + void enabled(); + + READ16_MEMBER(ibm8514_gpstatus_r); + WRITE16_MEMBER(ibm8514_cmd_w); + READ16_MEMBER(ibm8514_line_error_r); + WRITE16_MEMBER(ibm8514_line_error_w); + READ16_MEMBER(ibm8514_status_r); + WRITE16_MEMBER(ibm8514_htotal_w); + READ16_MEMBER(ibm8514_substatus_r); + WRITE16_MEMBER(ibm8514_subcontrol_w); + READ16_MEMBER(ibm8514_subcontrol_r); + READ16_MEMBER(ibm8514_htotal_r); + READ16_MEMBER(ibm8514_vtotal_r); + WRITE16_MEMBER(ibm8514_vtotal_w); + READ16_MEMBER(ibm8514_vdisp_r); + WRITE16_MEMBER(ibm8514_vdisp_w); + READ16_MEMBER(ibm8514_vsync_r); + WRITE16_MEMBER(ibm8514_vsync_w); + READ16_MEMBER(ibm8514_desty_r); + WRITE16_MEMBER(ibm8514_desty_w); + READ16_MEMBER(ibm8514_destx_r); + WRITE16_MEMBER(ibm8514_destx_w); + READ16_MEMBER(ibm8514_ssv_r); + WRITE16_MEMBER(ibm8514_ssv_w); + READ16_MEMBER(ibm8514_currentx_r); + WRITE16_MEMBER(ibm8514_currentx_w); + READ16_MEMBER(ibm8514_currenty_r); + WRITE16_MEMBER(ibm8514_currenty_w); + READ16_MEMBER(ibm8514_width_r); + WRITE16_MEMBER(ibm8514_width_w); + READ16_MEMBER(ibm8514_fgcolour_r); + WRITE16_MEMBER(ibm8514_fgcolour_w); + READ16_MEMBER(ibm8514_bgcolour_r); + WRITE16_MEMBER(ibm8514_bgcolour_w); + READ16_MEMBER(ibm8514_multifunc_r); + WRITE16_MEMBER(ibm8514_multifunc_w); + READ16_MEMBER(ibm8514_backmix_r); + WRITE16_MEMBER(ibm8514_backmix_w); + READ16_MEMBER(ibm8514_foremix_r); + WRITE16_MEMBER(ibm8514_foremix_w); + READ16_MEMBER(ibm8514_pixel_xfer_r); + WRITE16_MEMBER(ibm8514_pixel_xfer_w); + READ16_MEMBER(ibm8514_read_mask_r); + WRITE16_MEMBER(ibm8514_read_mask_w); + READ16_MEMBER(ibm8514_write_mask_r); + WRITE16_MEMBER(ibm8514_write_mask_w); + void ibm8514_wait_draw(); + struct + { + UINT16 htotal; // Horizontal total (9 bits) + UINT16 vtotal; // Vertical total adjust (3 bits), Vertical total base (9 bit) + UINT16 vdisp; + UINT16 vsync; + UINT16 subctrl; + UINT16 substatus; + UINT16 ssv; + UINT16 ec0; + UINT16 ec1; + UINT16 ec2; + UINT16 ec3; + bool gpbusy; + bool data_avail; + INT16 dest_x; + INT16 dest_y; + INT16 curr_x; + INT16 curr_y; + INT16 prev_x; + INT16 prev_y; + INT16 line_axial_step; + INT16 line_diagonal_step; + INT16 line_errorterm; + UINT16 current_cmd; + UINT16 src_x; + UINT16 src_y; + INT16 scissors_left; + INT16 scissors_right; + INT16 scissors_top; + INT16 scissors_bottom; + UINT16 rect_width; + UINT16 rect_height; + UINT32 fgcolour; + UINT32 bgcolour; + UINT16 fgmix; + UINT16 bgmix; + UINT32 pixel_xfer; + UINT16 pixel_control; + UINT8 bus_size; + UINT8 multifunc_sel; + UINT16 multifunc_misc; + UINT32 read_mask; + UINT32 write_mask; + + int state; + UINT8 wait_vector_len; + UINT8 wait_vector_dir; + bool wait_vector_draw; + UINT8 wait_vector_count; + + } ibm8514; +protected: + virtual void device_start(); + virtual void device_config_complete(); + vga_device* m_vga; // for pass-through + std::string m_vga_tag; // pass-through device tag +private: + void ibm8514_draw_vector(UINT8 len, UINT8 dir, bool draw); + void ibm8514_wait_draw_ssv(); + void ibm8514_draw_ssv(UINT8 data); + void ibm8514_wait_draw_vector(); + void ibm8514_write_fg(UINT32 offset); + void ibm8514_write_bg(UINT32 offset); + void ibm8514_write(UINT32 offset, UINT32 src); + + //UINT8* m_vram; // the original 8514/A has it's own VRAM, but most VGA+8514 combination cards will have + // only one set of VRAM, so this will only be needed in standalone 8514/A cards + //UINT32 m_vramsize; +}; + +// device type definition +extern const device_type IBM8514A; + +#define MCFG_8514A_ADD(_tag, _param) \ + MCFG_DEVICE_ADD(_tag, IBM8514A, 0) \ + downcast(device)->set_vga(_param); + +#define MCFG_8514A_ADD_OWNER(_tag) \ + MCFG_DEVICE_ADD(_tag, IBM8514A, 0) \ + downcast(device)->set_vga_owner(); + + +class mach8_device : public ibm8514a_device +{ +public: + mach8_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + mach8_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + READ16_MEMBER(mach8_ec0_r); + WRITE16_MEMBER(mach8_ec0_w); + READ16_MEMBER(mach8_ec1_r); + WRITE16_MEMBER(mach8_ec1_w); + READ16_MEMBER(mach8_ec2_r); + WRITE16_MEMBER(mach8_ec2_w); + READ16_MEMBER(mach8_ec3_r); + WRITE16_MEMBER(mach8_ec3_w); + READ16_MEMBER(mach8_ext_fifo_r); + WRITE16_MEMBER(mach8_linedraw_index_w); + READ16_MEMBER(mach8_bresenham_count_r); + WRITE16_MEMBER(mach8_bresenham_count_w); + WRITE16_MEMBER(mach8_linedraw_w); + READ16_MEMBER(mach8_linedraw_r); + READ16_MEMBER(mach8_scratch0_r); + WRITE16_MEMBER(mach8_scratch0_w); + READ16_MEMBER(mach8_scratch1_r); + WRITE16_MEMBER(mach8_scratch1_w); + READ16_MEMBER(mach8_config1_r); + READ16_MEMBER(mach8_config2_r); + READ16_MEMBER(mach8_sourcex_r); + READ16_MEMBER(mach8_sourcey_r); + WRITE16_MEMBER(mach8_ext_leftscissor_w); + WRITE16_MEMBER(mach8_ext_topscissor_w); + READ16_MEMBER(mach8_clksel_r) { return mach8.clksel; } + +protected: + virtual void device_start(); + struct + { + UINT16 scratch0; + UINT16 scratch1; + UINT16 linedraw; + UINT16 clksel; + } mach8; +}; + +// device type definition +extern const device_type MACH8; + +#define MCFG_MACH8_ADD(_tag, _param) \ + MCFG_DEVICE_ADD(_tag, MACH8, 0) \ + downcast(device)->set_vga(_param); + +#define MCFG_MACH8_ADD_OWNER(_tag) \ + MCFG_DEVICE_ADD(_tag, MACH8, 0) \ + downcast(device)->set_vga_owner(); + +// ======================> tseng_vga_device + +class tseng_vga_device : public svga_device +{ +public: + // construction/destruction + tseng_vga_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual READ8_MEMBER(port_03b0_r); + virtual WRITE8_MEMBER(port_03b0_w); + virtual READ8_MEMBER(port_03c0_r); + virtual WRITE8_MEMBER(port_03c0_w); + virtual READ8_MEMBER(port_03d0_r); + virtual WRITE8_MEMBER(port_03d0_w); + virtual READ8_MEMBER(mem_r); + virtual WRITE8_MEMBER(mem_w); + +protected: + virtual void device_start(); + +private: + void tseng_define_video_mode(); + UINT8 tseng_crtc_reg_read(UINT8 index); + void tseng_crtc_reg_write(UINT8 index, UINT8 data); + UINT8 tseng_seq_reg_read(UINT8 index); + void tseng_seq_reg_write(UINT8 index, UINT8 data); + void tseng_attribute_reg_write(UINT8 index, UINT8 data); + + struct + { + UINT8 reg_3d8; + UINT8 dac_ctrl; + UINT8 dac_state; + UINT8 horz_overflow; + UINT8 aux_ctrl; + bool ext_reg_ena; + UINT8 misc1; + UINT8 misc2; + }et4k; + +}; + + +// device type definition +extern const device_type TSENG_VGA; + + +// ======================> ati_vga_device + +class ati_vga_device : public svga_device +{ +public: + // construction/destruction + ati_vga_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + ati_vga_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + virtual READ8_MEMBER(mem_r); + virtual WRITE8_MEMBER(mem_w); + + // VGA registers + virtual READ8_MEMBER(port_03c0_r); + READ8_MEMBER(ati_port_ext_r); + WRITE8_MEMBER(ati_port_ext_w); + + virtual machine_config_constructor device_mconfig_additions() const; + virtual UINT16 offset(); + + mach8_device* get_8514() { return m_8514; } +protected: + virtual void device_start(); +private: + void ati_define_video_mode(); + struct + { + UINT8 ext_reg[64]; + UINT8 ext_reg_select; + UINT8 vga_chip_id; + } ati; + mach8_device* m_8514; +}; + +// device type definition +extern const device_type ATI_VGA; + + +// ======================> s3_vga_device + +class s3_vga_device : public ati_vga_device +{ +public: + // construction/destruction + s3_vga_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + s3_vga_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + virtual READ8_MEMBER(port_03b0_r); + virtual WRITE8_MEMBER(port_03b0_w); + virtual READ8_MEMBER(port_03c0_r); + virtual WRITE8_MEMBER(port_03c0_w); + virtual READ8_MEMBER(port_03d0_r); + virtual WRITE8_MEMBER(port_03d0_w); + virtual READ8_MEMBER(mem_r); + virtual WRITE8_MEMBER(mem_w); + + virtual UINT32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); + + virtual machine_config_constructor device_mconfig_additions() const; + + ibm8514a_device* get_8514() { return m_8514; } +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + struct + { + UINT8 memory_config; + UINT8 ext_misc_ctrl_2; + UINT8 crt_reg_lock; + UINT8 reg_lock1; + UINT8 reg_lock2; + UINT8 enable_8514; + UINT8 enable_s3d; + UINT8 cr3a; + UINT8 cr42; + UINT8 cr43; + UINT8 cr53; + UINT8 id_high; + UINT8 id_low; + UINT8 revision; + UINT8 id_cr30; + UINT32 strapping; // power-on strapping bits + UINT8 sr10; // MCLK PLL + UINT8 sr11; // MCLK PLL + UINT8 sr12; // DCLK PLL + UINT8 sr13; // DCLK PLL + UINT8 sr15; // CLKSYN control 2 + UINT8 sr17; // CLKSYN test + UINT8 clk_pll_r; // individual DCLK PLL values + UINT8 clk_pll_m; + UINT8 clk_pll_n; + + // data for memory-mapped I/O + UINT16 mmio_9ae8; + UINT16 mmio_bee8; + UINT16 mmio_96e8; + + // hardware graphics cursor + UINT8 cursor_mode; + UINT16 cursor_x; + UINT16 cursor_y; + UINT16 cursor_start_addr; + UINT8 cursor_pattern_x; // cursor pattern origin + UINT8 cursor_pattern_y; + UINT8 cursor_fg[4]; + UINT8 cursor_bg[4]; + UINT8 cursor_fg_ptr; + UINT8 cursor_bg_ptr; + UINT8 extended_dac_ctrl; + } s3; + virtual UINT16 offset(); + +private: + UINT8 s3_crtc_reg_read(UINT8 index); + void s3_define_video_mode(void); + void s3_crtc_reg_write(UINT8 index, UINT8 data); + UINT8 s3_seq_reg_read(UINT8 index); + void s3_seq_reg_write(UINT8 index, UINT8 data); + ibm8514a_device* m_8514; +}; + +// device type definition +extern const device_type S3_VGA; + +// ======================> gamtor_vga_device + +class gamtor_vga_device : public svga_device +{ +public: + // construction/destruction + gamtor_vga_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + + virtual READ8_MEMBER(port_03b0_r); + virtual WRITE8_MEMBER(port_03b0_w); + virtual READ8_MEMBER(port_03c0_r); + virtual WRITE8_MEMBER(port_03c0_w); + virtual READ8_MEMBER(port_03d0_r); + virtual WRITE8_MEMBER(port_03d0_w); + virtual READ8_MEMBER(mem_r); + virtual WRITE8_MEMBER(mem_w); + +protected: +private: +}; + + +// device type definition +extern const device_type GAMTOR_VGA; + +/* + pega notes (paradise) + build in amstrad pc1640 + + ROM_LOAD("40100", 0xc0000, 0x8000, CRC(d2d1f1ae)) + + 4 additional dipswitches + seems to have emulation modes at register level + (mda/hgc lines bit 8 not identical to ega/vga) + + standard ega/vga dipswitches + 00000000 320x200 + 00000001 640x200 hanging + 00000010 640x200 hanging + 00000011 640x200 hanging + + 00000100 640x350 hanging + 00000101 640x350 hanging EGA mono + 00000110 320x200 + 00000111 640x200 + + 00001000 640x200 + 00001001 640x200 + 00001010 720x350 partial visible + 00001011 720x350 partial visible + + 00001100 320x200 + 00001101 320x200 + 00001110 320x200 + 00001111 320x200 + +*/ + +/* + oak vga (oti 037 chip) + (below bios patch needed for running) + + ROM_LOAD("oakvga.bin", 0xc0000, 0x8000, CRC(318c5f43)) +*/ + + +#endif /* PC_VGA_H */ diff --git a/src/devices/video/poly.h b/src/devices/video/poly.h new file mode 100644 index 00000000000..1a564a2092d --- /dev/null +++ b/src/devices/video/poly.h @@ -0,0 +1,1175 @@ +// license:BSD-3-Clause +// copyright-holders:Ville Linde, Aaron Giles +/*************************************************************************** + + poly.h + + Polygon helper routines. + +**************************************************************************** + + Pixel model: + + (0.0,0.0) (1.0,0.0) (2.0,0.0) (3.0,0.0) + +---------------+---------------+---------------+ + | | | | + | | | | + | (0.5,0.5) | (1.5,0.5) | (2.5,0.5) | + | * | * | * | + | | | | + | | | | + (0.0,1.0) (1.0,1.0) (2.0,1.0) (3.0,1.0) + +---------------+---------------+---------------+ + | | | | + | | | | + | (0.5,1.5) | (1.5,1.5) | (2.5,1.5) | + | * | * | * | + | | | | + | | | | + | | | | + +---------------+---------------+---------------+ + (0.0,2.0) (1.0,2.0) (2.0,2.0) (3.0,2.0) + +***************************************************************************/ + +#pragma once + +#ifndef __POLY_H__ +#define __POLY_H__ + +#include + +//************************************************************************** +// DEBUGGING +//************************************************************************** + +// keep statistics +#define KEEP_POLY_STATISTICS 0 + +// turn this on to log the reasons for any long waits +#define LOG_WAITS 0 + +// number of profiling ticks before we consider a wait "long" +#define LOG_WAIT_THRESHOLD 1000 + + + +/*************************************************************************** + CONSTANTS +***************************************************************************/ + +#define POLYFLAG_INCLUDE_BOTTOM_EDGE 0x01 +#define POLYFLAG_INCLUDE_RIGHT_EDGE 0x02 +#define POLYFLAG_NO_WORK_QUEUE 0x04 + +#define SCANLINES_PER_BUCKET 8 +#define CACHE_LINE_SIZE 64 // this is a general guess +#define TOTAL_BUCKETS (512 / SCANLINES_PER_BUCKET) +#define UNITS_PER_POLY (100 / SCANLINES_PER_BUCKET) + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +//------------------------------------------------- +// global helpers for float base types +//------------------------------------------------- + +inline float poly_floor(float x) { return floorf(x); } +inline float poly_abs(float x) { return fabsf(x); } +inline float poly_recip(float x) { return 1.0f / x; } + + +//------------------------------------------------- +// global helpers for double base types +//------------------------------------------------- + +inline double poly_floor(double x) { return floor(x); } +inline double poly_abs(double x) { return fabs(x); } +inline double poly_recip(double x) { return 1.0 / x; } + + +// poly_manager is a template class +template +class poly_manager +{ +public: + // each vertex has an X/Y coordinate and a set of parameters + struct vertex_t + { + vertex_t() { } + vertex_t(_BaseType _x, _BaseType _y) { x = _x; y = _y; } + + _BaseType x, y; // X, Y coordinates + _BaseType p[_MaxParams]; // interpolated parameters + }; + + // a single extent describes a span and a list of parameter extents + struct extent_t + { + INT16 startx, stopx; // starting (inclusive)/ending (exclusive) endpoints + struct + { + _BaseType start; // parameter value at start + _BaseType dpdx; // dp/dx relative to start + } param[_MaxParams]; + void *userdata; // custom per-span data + }; + + // delegate type for scanline callbacks + typedef delegate render_delegate; + + // construction/destruction + poly_manager(running_machine &machine, UINT8 flags = 0); + poly_manager(screen_device &screen, UINT8 flags = 0); + virtual ~poly_manager(); + + // getters + running_machine &machine() const { return m_machine; } + screen_device &screen() const { assert(m_screen != NULL); return *m_screen; } + + // synchronization + void wait(const char *debug_reason = "general"); + + // object data allocators + _ObjectData &object_data_alloc(); + _ObjectData &object_data_last() const { return m_object.last(); } + + // tiles + UINT32 render_tile(const rectangle &cliprect, render_delegate callback, int paramcount, const vertex_t &v1, const vertex_t &v2); + + // triangles + UINT32 render_triangle(const rectangle &cliprect, render_delegate callback, int paramcount, const vertex_t &v1, const vertex_t &v2, const vertex_t &v3); + UINT32 render_triangle_fan(const rectangle &cliprect, render_delegate callback, int paramcount, int numverts, const vertex_t *v); + UINT32 render_triangle_strip(const rectangle &cliprect, render_delegate callback, int paramcount, int numverts, const vertex_t *v); + UINT32 render_triangle_custom(const rectangle &cliprect, render_delegate callback, int startscanline, int numscanlines, const extent_t *extents); + + // polygons + template + UINT32 render_polygon(const rectangle &cliprect, render_delegate callback, int paramcount, const vertex_t *v); + + // public helpers + int zclip_if_less(int numverts, const vertex_t *v, vertex_t *outv, int paramcount, _BaseType clipval); + +private: + // polygon_info describes a single polygon, which includes the poly_params + struct polygon_info + { + poly_manager * m_owner; // pointer back to the poly manager + _ObjectData * m_object; // object data pointer + render_delegate m_callback; // callback to handle a scanline's worth of work + }; + + // internal unit of work + struct work_unit + { + volatile UINT32 count_next; // number of scanlines and index of next item to process + polygon_info * polygon; // pointer to polygon + INT16 scanline; // starting scanline + UINT16 previtem; // index of previous item in the same bucket + #ifndef PTR64 + UINT32 dummy; // pad to 16 bytes + #endif + extent_t extent[SCANLINES_PER_BUCKET]; // array of scanline extents + }; + + // class for managing an array of items + template + class poly_array + { + // size of an item, rounded up to the cache line size + static const int k_itemsize = ((sizeof(_Type) + CACHE_LINE_SIZE - 1) / CACHE_LINE_SIZE) * CACHE_LINE_SIZE; + + public: + // construction + poly_array(running_machine &machine, poly_manager &manager) + : m_manager(manager), + m_base(auto_alloc_array_clear(machine, UINT8, k_itemsize * _Count)), + m_next(0), + m_max(0), + m_waits(0) { } + + // destruction + ~poly_array() { auto_free(m_manager.machine(), m_base); } + + // operators + _Type &operator[](int index) const { assert(index >= 0 && index < _Count); return *reinterpret_cast<_Type *>(m_base + index * k_itemsize); } + + // getters + int count() const { return m_next; } + int max() const { return m_max; } + int waits() const { return m_waits; } + int itemsize() const { return k_itemsize; } + int allocated() const { return _Count; } + int indexof(_Type &item) const { int result = (reinterpret_cast(&item) - m_base) / k_itemsize; assert(result >= 0 && result < _Count); return result; } + + // operations + void reset() { m_next = 0; } + _Type &next() { if (m_next > m_max) m_max = m_next; assert(m_next < _Count); return *new(m_base + m_next++ * k_itemsize) _Type; } + _Type &last() const { return (*this)[m_next - 1]; } + void wait_for_space(int count = 1) { while ((m_next + count) >= _Count) { m_waits++; m_manager.wait(""); } } + + private: + // internal state + poly_manager & m_manager; + UINT8 * m_base; + int m_next; + int m_max; + int m_waits; + }; + + // internal array types + typedef poly_array polygon_array; + typedef poly_array<_ObjectData, _MaxPolys + 1> objectdata_array; + typedef poly_array unit_array; + + // round in a cross-platform consistent manner + inline INT32 round_coordinate(_BaseType value) + { + INT32 result = poly_floor(value); + + if ((value > 0) && (result < 0)) + return INT_MAX-1; + return result + (value - _BaseType(result) > _BaseType(0.5)); + } + + // internal helpers + polygon_info &polygon_alloc(int minx, int maxx, int miny, int maxy, render_delegate callback) + { + // wait for space in the polygon and unit arrays + m_polygon.wait_for_space(); + m_unit.wait_for_space((maxy - miny) / SCANLINES_PER_BUCKET + 2); + + // return and initialize the next one + polygon_info &polygon = m_polygon.next(); + polygon.m_owner = this; + polygon.m_object = &object_data_last(); + polygon.m_callback = callback; + return polygon; + } + + static void *work_item_callback(void *param, int threadid); + void presave() { wait("pre-save"); } + + // queue management + running_machine & m_machine; + screen_device * m_screen; + osd_work_queue * m_queue; // work queue + + // arrays + polygon_array m_polygon; // array of polygons + objectdata_array m_object; // array of object data + unit_array m_unit; // array of work units + + // misc data + UINT8 m_flags; // flags + + // buckets + UINT16 m_unit_bucket[TOTAL_BUCKETS]; // buckets for tracking unit usage + + // statistics + UINT32 m_tiles; // number of tiles queued + UINT32 m_triangles; // number of triangles queued + UINT32 m_quads; // number of quads queued + UINT64 m_pixels; // number of pixels rendered +#if KEEP_POLY_STATISTICS + UINT32 m_conflicts[WORK_MAX_THREADS]; // number of conflicts found, per thread + UINT32 m_resolved[WORK_MAX_THREADS]; // number of conflicts resolved, per thread +#endif +}; + + +//------------------------------------------------- +// poly_manager - constructor +//------------------------------------------------- + +template +poly_manager<_BaseType, _ObjectData, _MaxParams, _MaxPolys>::poly_manager(running_machine &machine, UINT8 flags) + : m_machine(machine), + m_screen(NULL), + m_queue(NULL), + m_polygon(machine, *this), + m_object(machine, *this), + m_unit(machine, *this), + m_flags(flags), + m_triangles(0), + m_quads(0), + m_pixels(0) +{ +#if KEEP_POLY_STATISTICS + memset(m_conflicts, 0, sizeof(m_conflicts)); + memset(m_resolved, 0, sizeof(m_resolved)); +#endif + + // create the work queue + if (!(flags & POLYFLAG_NO_WORK_QUEUE)) + m_queue = osd_work_queue_alloc(WORK_QUEUE_FLAG_MULTI | WORK_QUEUE_FLAG_HIGH_FREQ); + + // request a pre-save callback for synchronization + machine.save().register_presave(save_prepost_delegate(FUNC(poly_manager::presave), this)); +} + + +template +poly_manager<_BaseType, _ObjectData, _MaxParams, _MaxPolys>::poly_manager(screen_device &screen, UINT8 flags) + : m_machine(screen.machine()), + m_screen(&screen), + m_queue(NULL), + m_polygon(screen.machine(), *this), + m_object(screen.machine(), *this), + m_unit(screen.machine(), *this), + m_flags(flags), + m_triangles(0), + m_quads(0), + m_pixels(0) +{ +#if KEEP_POLY_STATISTICS + memset(m_conflicts, 0, sizeof(m_conflicts)); + memset(m_resolved, 0, sizeof(m_resolved)); +#endif + + // create the work queue + if (!(flags & POLYFLAG_NO_WORK_QUEUE)) + m_queue = osd_work_queue_alloc(WORK_QUEUE_FLAG_MULTI | WORK_QUEUE_FLAG_HIGH_FREQ); + + // request a pre-save callback for synchronization + machine().save().register_presave(save_prepost_delegate(FUNC(poly_manager::presave), this)); +} + + +//------------------------------------------------- +// ~poly_manager - destructor +//------------------------------------------------- + +template +poly_manager<_BaseType, _ObjectData, _MaxParams, _MaxPolys>::~poly_manager() +{ +#if KEEP_POLY_STATISTICS +{ + // accumulate stats over the entire collection + int conflicts = 0, resolved = 0; + for (int i = 0; i < ARRAY_LENGTH(m_conflicts); i++) + { + conflicts += m_conflicts[i]; + resolved += m_resolved[i]; + } + + // output global stats + printf("Total triangles = %d\n", m_triangles); + printf("Total quads = %d\n", m_quads); + if (m_pixels > 1000000000) + printf("Total pixels = %d%09d\n", (UINT32)(m_pixels / 1000000000), (UINT32)(m_pixels % 1000000000)); + else + printf("Total pixels = %d\n", (UINT32)m_pixels); + + printf("Conflicts: %d resolved, %d total\n", resolved, conflicts); + printf("Units: %5d used, %5d allocated, %5d waits, %4d bytes each, %7d total\n", m_unit.max(), m_unit.allocated(), m_unit.waits(), m_unit.itemsize(), m_unit.allocated() * m_unit.itemsize()); + printf("Polygons: %5d used, %5d allocated, %5d waits, %4d bytes each, %7d total\n", m_polygon.max(), m_polygon.allocated(), m_polygon.waits(), m_polygon.itemsize(), m_polygon.allocated() * m_polygon.itemsize()); + printf("Object data: %5d used, %5d allocated, %5d waits, %4d bytes each, %7d total\n", m_object.max(), m_object.allocated(), m_object.waits(), m_object.itemsize(), m_object.allocated() * m_object.itemsize()); +} +#endif + + // free the work queue + if (m_queue != NULL) + osd_work_queue_free(m_queue); +} + + +//------------------------------------------------- +// work_item_callback - process a work item +//------------------------------------------------- + +template +void *poly_manager<_BaseType, _ObjectData, _MaxParams, _MaxPolys>::work_item_callback(void *param, int threadid) +{ + while (1) + { + work_unit &unit = *(work_unit *)param; + polygon_info &polygon = *unit.polygon; + int count = unit.count_next & 0xffff; + UINT32 orig_count_next; + + // if our previous item isn't done yet, enqueue this item to the end and proceed + if (unit.previtem != 0xffff) + { + work_unit &prevunit = polygon.m_owner->m_unit[unit.previtem]; + if (prevunit.count_next != 0) + { + UINT32 unitnum = polygon.m_owner->m_unit.indexof(unit); + UINT32 new_count_next; + + // attempt to atomically swap in this new value + do + { + orig_count_next = prevunit.count_next; + new_count_next = orig_count_next | (unitnum << 16); + } while (compare_exchange32((volatile INT32 *)&prevunit.count_next, orig_count_next, new_count_next) != orig_count_next); + +#if KEEP_POLY_STATISTICS + // track resolved conflicts + polygon.m_owner->m_conflicts[threadid]++; + if (orig_count_next != 0) + polygon.m_owner->m_resolved[threadid]++; +#endif + // if we succeeded, skip out early so we can do other work + if (orig_count_next != 0) + break; + } + } + + // iterate over extents + for (int curscan = 0; curscan < count; curscan++) + polygon.m_callback(unit.scanline + curscan, unit.extent[curscan], *polygon.m_object, threadid); + + // set our count to 0 and re-fetch the original count value + do + { + orig_count_next = unit.count_next; + } while (compare_exchange32((volatile INT32 *)&unit.count_next, orig_count_next, 0) != orig_count_next); + + // if we have no more work to do, do nothing + orig_count_next >>= 16; + if (orig_count_next == 0) + break; + param = &polygon.m_owner->m_unit[orig_count_next]; + } + return NULL; +} + + +//------------------------------------------------- +// wait - stall until all work is complete +//------------------------------------------------- + +template +void poly_manager<_BaseType, _ObjectData, _MaxParams, _MaxPolys>::wait(const char *debug_reason) +{ + osd_ticks_t time; + + // remember the start time if we're logging + if (LOG_WAITS) + time = get_profile_ticks(); + + // wait for all pending work items to complete + if (m_queue != NULL) + osd_work_queue_wait(m_queue, osd_ticks_per_second() * 100); + + // if we don't have a queue, just run the whole list now + else + for (int unitnum = 0; unitnum < m_unit.count(); unitnum++) + work_item_callback(&m_unit[unitnum], 0); + + // log any long waits + if (LOG_WAITS) + { + time = get_profile_ticks() - time; + if (time > LOG_WAIT_THRESHOLD) + logerror("Poly:Waited %d cycles for %s\n", (int)time, debug_reason); + } + + // reset the state + m_polygon.reset(); + m_unit.reset(); + memset(m_unit_bucket, 0xff, sizeof(m_unit_bucket)); + + // we need to preserve the last object data that was supplied + if (m_object.count() > 0) + { + _ObjectData temp = object_data_last(); + m_object.reset(); + m_object.next() = temp; + } + else + m_object.reset(); +} + + +//------------------------------------------------- +// object_data_alloc - allocate a new _ObjectData +//------------------------------------------------- + +template +_ObjectData &poly_manager<_BaseType, _ObjectData, _MaxParams, _MaxPolys>::object_data_alloc() +{ + // wait for a work item if we have to, then return the next item + m_object.wait_for_space(); + return m_object.next(); +} + + +//------------------------------------------------- +// render_tile - render a tile +//------------------------------------------------- + +template +UINT32 poly_manager<_BaseType, _ObjectData, _MaxParams, _MaxPolys>::render_tile(const rectangle &cliprect, render_delegate callback, int paramcount, const vertex_t &_v1, const vertex_t &_v2) +{ + const vertex_t *v1 = &_v1; + const vertex_t *v2 = &_v2; + + // first sort by Y + if (v2->y < v1->y) + { + const vertex_t *tv = v1; + v1 = v2; + v2 = tv; + } + + // compute some integral X/Y vertex values + INT32 v1y = round_coordinate(v1->y); + INT32 v2y = round_coordinate(v2->y); + + // clip coordinates + INT32 v1yclip = v1y; + INT32 v2yclip = v2y + ((m_flags & POLYFLAG_INCLUDE_BOTTOM_EDGE) ? 1 : 0); + v1yclip = MAX(v1yclip, cliprect.min_y); + v2yclip = MIN(v2yclip, cliprect.max_y + 1); + if (v2yclip - v1yclip <= 0) + return 0; + + // determine total X extents + _BaseType minx = v1->x; + _BaseType maxx = v2->x; + if (minx > maxx) + return 0; + + // allocate and populate a new polygon + polygon_info &polygon = polygon_alloc(round_coordinate(minx), round_coordinate(maxx), v1yclip, v2yclip, callback); + + // compute parameter deltas + _BaseType param_dpdx[_MaxParams]; + _BaseType param_dpdy[_MaxParams]; + if (paramcount > 0) + { + _BaseType oox = poly_recip(v2->x - v1->x); + _BaseType ooy = poly_recip(v2->y - v1->y); + for (int paramnum = 0; paramnum < paramcount; paramnum++) + { + param_dpdx[paramnum] = oox * (v2->p[paramnum] - v1->p[paramnum]); + param_dpdy[paramnum] = ooy * (v2->p[paramnum] - v1->p[paramnum]); + } + } + + // clamp to full pixels + INT32 istartx = round_coordinate(v1->x); + INT32 istopx = round_coordinate(v2->x); + + // force start < stop + if (istartx > istopx) + { + INT32 temp = istartx; + istartx = istopx; + istopx = temp; + } + + // include the right edge if requested + if (m_flags & POLYFLAG_INCLUDE_RIGHT_EDGE) + istopx++; + + // apply left/right clipping + if (istartx < cliprect.min_x) + istartx = cliprect.min_x; + if (istopx > cliprect.max_x) + istopx = cliprect.max_x + 1; + if (istartx >= istopx) + return 0; + + // compute the X extents for each scanline + INT32 pixels = 0; + UINT32 startunit = m_unit.count(); + INT32 scaninc = 1; + for (INT32 curscan = v1yclip; curscan < v2yclip; curscan += scaninc) + { + UINT32 bucketnum = ((UINT32)curscan / SCANLINES_PER_BUCKET) % TOTAL_BUCKETS; + UINT32 unit_index = m_unit.count(); + work_unit &unit = m_unit.next(); + + // determine how much to advance to hit the next bucket + scaninc = SCANLINES_PER_BUCKET - (UINT32)curscan % SCANLINES_PER_BUCKET; + + // fill in the work unit basics + unit.polygon = &polygon; + unit.count_next = MIN(v2yclip - curscan, scaninc); + unit.scanline = curscan; + unit.previtem = m_unit_bucket[bucketnum]; + m_unit_bucket[bucketnum] = unit_index; + + // iterate over extents + for (int extnum = 0; extnum < unit.count_next; extnum++) + { + // compute the ending X based on which part of the triangle we're in + _BaseType fully = _BaseType(curscan + extnum) + _BaseType(0.5); + + // set the extent and update the total pixel count + extent_t &extent = unit.extent[extnum]; + extent.startx = istartx; + extent.stopx = istopx; + extent.userdata = NULL; + pixels += istopx - istartx; + + // fill in the parameters for the extent + _BaseType fullstartx = _BaseType(istartx) + _BaseType(0.5); + for (int paramnum = 0; paramnum < paramcount; paramnum++) + { + extent.param[paramnum].start = v1->p[paramnum] + fullstartx * param_dpdx[paramnum] + fully * param_dpdy[paramnum]; + extent.param[paramnum].dpdx = param_dpdx[paramnum]; + } + } + } + + // enqueue the work items + if (m_queue != NULL) + osd_work_item_queue_multiple(m_queue, work_item_callback, m_unit.count() - startunit, &m_unit[startunit], m_unit.itemsize(), WORK_ITEM_FLAG_AUTO_RELEASE); + + // return the total number of pixels in the triangle + m_tiles++; + m_pixels += pixels; + return pixels; +} + + +//------------------------------------------------- +// render_triangle - render a single triangle +// given 3 vertexes +//------------------------------------------------- + +template +UINT32 poly_manager<_BaseType, _ObjectData, _MaxParams, _MaxPolys>::render_triangle(const rectangle &cliprect, render_delegate callback, int paramcount, const vertex_t &_v1, const vertex_t &_v2, const vertex_t &_v3) +{ + const vertex_t *v1 = &_v1; + const vertex_t *v2 = &_v2; + const vertex_t *v3 = &_v3; + + // first sort by Y + if (v2->y < v1->y) + { + const vertex_t *tv = v1; + v1 = v2; + v2 = tv; + } + if (v3->y < v2->y) + { + const vertex_t *tv = v2; + v2 = v3; + v3 = tv; + if (v2->y < v1->y) + { + const vertex_t *tv = v1; + v1 = v2; + v2 = tv; + } + } + + // compute some integral X/Y vertex values + INT32 v1y = round_coordinate(v1->y); + INT32 v3y = round_coordinate(v3->y); + + // clip coordinates + INT32 v1yclip = v1y; + INT32 v3yclip = v3y + ((m_flags & POLYFLAG_INCLUDE_BOTTOM_EDGE) ? 1 : 0); + v1yclip = MAX(v1yclip, cliprect.min_y); + v3yclip = MIN(v3yclip, cliprect.max_y + 1); + if (v3yclip - v1yclip <= 0) + return 0; + + // determine total X extents + _BaseType minx = v1->x; + _BaseType maxx = v1->x; + if (v2->x < minx) minx = v2->x; + else if (v2->x > maxx) maxx = v2->x; + if (v3->x < minx) minx = v3->x; + else if (v3->x > maxx) maxx = v3->x; + + // allocate and populate a new polygon + polygon_info &polygon = polygon_alloc(round_coordinate(minx), round_coordinate(maxx), v1yclip, v3yclip, callback); + + // compute the slopes for each portion of the triangle + _BaseType dxdy_v1v2 = (v2->y == v1->y) ? _BaseType(0.0) : (v2->x - v1->x) / (v2->y - v1->y); + _BaseType dxdy_v1v3 = (v3->y == v1->y) ? _BaseType(0.0) : (v3->x - v1->x) / (v3->y - v1->y); + _BaseType dxdy_v2v3 = (v3->y == v2->y) ? _BaseType(0.0) : (v3->x - v2->x) / (v3->y - v2->y); + + // compute parameter starting points and deltas + _BaseType param_start[_MaxParams]; + _BaseType param_dpdx[_MaxParams]; + _BaseType param_dpdy[_MaxParams]; + if (paramcount > 0) + { + _BaseType a00 = v2->y - v3->y; + _BaseType a01 = v3->x - v2->x; + _BaseType a02 = v2->x*v3->y - v3->x*v2->y; + _BaseType a10 = v3->y - v1->y; + _BaseType a11 = v1->x - v3->x; + _BaseType a12 = v3->x*v1->y - v1->x*v3->y; + _BaseType a20 = v1->y - v2->y; + _BaseType a21 = v2->x - v1->x; + _BaseType a22 = v1->x*v2->y - v2->x*v1->y; + _BaseType det = a02 + a12 + a22; + + if (poly_abs(det) < _BaseType(0.00001)) + { + for (int paramnum = 0; paramnum < paramcount; paramnum++) + { + param_dpdx[paramnum] = _BaseType(0.0); + param_dpdy[paramnum] = _BaseType(0.0); + param_start[paramnum] = v1->p[paramnum]; + } + } + else + { + _BaseType idet = poly_recip(det); + for (int paramnum = 0; paramnum < paramcount; paramnum++) + { + param_dpdx[paramnum] = idet * (v1->p[paramnum]*a00 + v2->p[paramnum]*a10 + v3->p[paramnum]*a20); + param_dpdy[paramnum] = idet * (v1->p[paramnum]*a01 + v2->p[paramnum]*a11 + v3->p[paramnum]*a21); + param_start[paramnum] = idet * (v1->p[paramnum]*a02 + v2->p[paramnum]*a12 + v3->p[paramnum]*a22); + } + } + } + else // GCC 4.7.0 incorrectly claims these are uninitialized; humor it by initializing in the (hopefully rare) zero parameter case + { + param_start[0] = _BaseType(0.0); + param_dpdx[0] = _BaseType(0.0); + param_dpdy[0] = _BaseType(0.0); + } + + // compute the X extents for each scanline + INT32 pixels = 0; + UINT32 startunit = m_unit.count(); + INT32 scaninc = 1; + for (INT32 curscan = v1yclip; curscan < v3yclip; curscan += scaninc) + { + UINT32 bucketnum = ((UINT32)curscan / SCANLINES_PER_BUCKET) % TOTAL_BUCKETS; + UINT32 unit_index = m_unit.count(); + work_unit &unit = m_unit.next(); + + // determine how much to advance to hit the next bucket + scaninc = SCANLINES_PER_BUCKET - (UINT32)curscan % SCANLINES_PER_BUCKET; + + // fill in the work unit basics + unit.polygon = &polygon; + unit.count_next = MIN(v3yclip - curscan, scaninc); + unit.scanline = curscan; + unit.previtem = m_unit_bucket[bucketnum]; + m_unit_bucket[bucketnum] = unit_index; + + // iterate over extents + for (int extnum = 0; extnum < unit.count_next; extnum++) + { + // compute the ending X based on which part of the triangle we're in + _BaseType fully = _BaseType(curscan + extnum) + _BaseType(0.5); + _BaseType startx = v1->x + (fully - v1->y) * dxdy_v1v3; + _BaseType stopx; + if (fully < v2->y) + stopx = v1->x + (fully - v1->y) * dxdy_v1v2; + else + stopx = v2->x + (fully - v2->y) * dxdy_v2v3; + + // clamp to full pixels + INT32 istartx = round_coordinate(startx); + INT32 istopx = round_coordinate(stopx); + + // force start < stop + if (istartx > istopx) + { + INT32 temp = istartx; + istartx = istopx; + istopx = temp; + } + + // include the right edge if requested + if (m_flags & POLYFLAG_INCLUDE_RIGHT_EDGE) + istopx++; + + // apply left/right clipping + if (istartx < cliprect.min_x) + istartx = cliprect.min_x; + if (istopx > cliprect.max_x) + istopx = cliprect.max_x + 1; + + // set the extent and update the total pixel count + if (istartx >= istopx) + istartx = istopx = 0; + extent_t &extent = unit.extent[extnum]; + extent.startx = istartx; + extent.stopx = istopx; + extent.userdata = NULL; + pixels += istopx - istartx; + + // fill in the parameters for the extent + _BaseType fullstartx = _BaseType(istartx) + _BaseType(0.5); + for (int paramnum = 0; paramnum < paramcount; paramnum++) + { + extent.param[paramnum].start = param_start[paramnum] + fullstartx * param_dpdx[paramnum] + fully * param_dpdy[paramnum]; + extent.param[paramnum].dpdx = param_dpdx[paramnum]; + } + } + } + + // enqueue the work items + if (m_queue != NULL) + osd_work_item_queue_multiple(m_queue, work_item_callback, m_unit.count() - startunit, &m_unit[startunit], m_unit.itemsize(), WORK_ITEM_FLAG_AUTO_RELEASE); + + // return the total number of pixels in the triangle + m_triangles++; + m_pixels += pixels; + return pixels; +} + + +//------------------------------------------------- +// render_triangle_fan - render a set of +// triangles in a fan +//------------------------------------------------- + +template +UINT32 poly_manager<_BaseType, _ObjectData, _MaxParams, _MaxPolys>::render_triangle_fan(const rectangle &cliprect, render_delegate callback, int paramcount, int numverts, const vertex_t *v) +{ + // iterate over vertices + UINT32 pixels = 0; + for (int vertnum = 2; vertnum < numverts; vertnum++) + pixels += render_triangle(cliprect, callback, paramcount, v[0], v[vertnum - 1], v[vertnum]); + return pixels; +} + + +//------------------------------------------------- +// render_triangle_strip - render a set of +// triangles in a strip +//------------------------------------------------- + +template +UINT32 poly_manager<_BaseType, _ObjectData, _MaxParams, _MaxPolys>::render_triangle_strip(const rectangle &cliprect, render_delegate callback, int paramcount, int numverts, const vertex_t *v) +{ + // iterate over vertices + UINT32 pixels = 0; + for (int vertnum = 2; vertnum < numverts; vertnum++) + pixels += render_triangle(cliprect, callback, paramcount, v[vertnum - 2], v[vertnum - 1], v[vertnum]); + return pixels; +} + + +//------------------------------------------------- +// render_triangle_custom - perform a custom +// render of an object, given specific extents +//------------------------------------------------- + +template +UINT32 poly_manager<_BaseType, _ObjectData, _MaxParams, _MaxPolys>::render_triangle_custom(const rectangle &cliprect, render_delegate callback, int startscanline, int numscanlines, const extent_t *extents) +{ + // clip coordinates + INT32 v1yclip = MAX(startscanline, cliprect.min_y); + INT32 v3yclip = MIN(startscanline + numscanlines, cliprect.max_y + 1); + if (v3yclip - v1yclip <= 0) + return 0; + + // allocate and populate a new polygon + polygon_info &polygon = polygon_alloc(0, 0, v1yclip, v3yclip, callback); + + // compute the X extents for each scanline + INT32 pixels = 0; + UINT32 startunit = m_unit.count(); + INT32 scaninc = 1; + for (INT32 curscan = v1yclip; curscan < v3yclip; curscan += scaninc) + { + UINT32 bucketnum = ((UINT32)curscan / SCANLINES_PER_BUCKET) % TOTAL_BUCKETS; + UINT32 unit_index = m_unit.count(); + work_unit &unit = m_unit.next(); + + // determine how much to advance to hit the next bucket + scaninc = SCANLINES_PER_BUCKET - (UINT32)curscan % SCANLINES_PER_BUCKET; + + // fill in the work unit basics + unit.polygon = &polygon; + unit.count_next = MIN(v3yclip - curscan, scaninc); + unit.scanline = curscan; + unit.previtem = m_unit_bucket[bucketnum]; + m_unit_bucket[bucketnum] = unit_index; + + // iterate over extents + for (int extnum = 0; extnum < unit.count_next; extnum++) + { + const extent_t &srcextent = extents[(curscan + extnum) - startscanline]; + INT32 istartx = srcextent.startx, istopx = srcextent.stopx; + + // apply left/right clipping + if (istartx < cliprect.min_x) + istartx = cliprect.min_x; + if (istartx > cliprect.max_x) + istartx = cliprect.max_x + 1; + if (istopx < cliprect.min_x) + istopx = cliprect.min_x; + if (istopx > cliprect.max_x) + istopx = cliprect.max_x + 1; + + // set the extent and update the total pixel count + extent_t &extent = unit.extent[extnum]; + extent.startx = istartx; + extent.stopx = istopx; + + // fill in the parameters for the extent + for (int paramnum = 0; paramnum < _MaxParams; paramnum++) + { + extent.param[paramnum].start = srcextent.param[paramnum].start; + extent.param[paramnum].dpdx = srcextent.param[paramnum].dpdx; + } + + extent.userdata = srcextent.userdata; + if (istartx < istopx) + pixels += istopx - istartx; + else if(istopx < istartx) + pixels += istartx - istopx; + } + } + + // enqueue the work items + if (m_queue != NULL) + osd_work_item_queue_multiple(m_queue, work_item_callback, m_unit.count() - startunit, &m_unit[startunit], m_unit.itemsize(), WORK_ITEM_FLAG_AUTO_RELEASE); + + // return the total number of pixels in the object + m_triangles++; + m_pixels += pixels; + return pixels; +} + + +//------------------------------------------------- +// render_polygon - render a single polygon up +// to 32 vertices +//------------------------------------------------- + +template +template +UINT32 poly_manager<_BaseType, _ObjectData, _MaxParams, _MaxPolys>::render_polygon(const rectangle &cliprect, render_delegate callback, int paramcount, const vertex_t *v) +{ + // determine min/max Y vertices + _BaseType minx = v[0].x; + _BaseType maxx = v[0].x; + int minv = 0; + int maxv = 0; + for (int vertnum = 1; vertnum < _NumVerts; vertnum++) + { + if (v[vertnum].y < v[minv].y) + minv = vertnum; + else if (v[vertnum].y > v[maxv].y) + maxv = vertnum; + if (v[vertnum].x < minx) + minx = v[vertnum].x; + else if (v[vertnum].x > maxx) + maxx = v[vertnum].x; + } + + // determine start/end scanlines + INT32 miny = round_coordinate(v[minv].y); + INT32 maxy = round_coordinate(v[maxv].y); + + // clip coordinates + INT32 minyclip = miny; + INT32 maxyclip = maxy + ((m_flags & POLYFLAG_INCLUDE_BOTTOM_EDGE) ? 1 : 0); + minyclip = MAX(minyclip, cliprect.min_y); + maxyclip = MIN(maxyclip, cliprect.max_y + 1); + if (maxyclip - minyclip <= 0) + return 0; + + // allocate a new polygon + polygon_info &polygon = polygon_alloc(round_coordinate(minx), round_coordinate(maxx), minyclip, maxyclip, callback); + + // walk forward to build up the forward edge list + struct poly_edge + { + poly_edge * next; // next edge in sequence + int index; // index of this edge + const vertex_t * v1; // pointer to first vertex + const vertex_t * v2; // pointer to second vertex + _BaseType dxdy; // dx/dy along the edge + _BaseType dpdy[_MaxParams]; // per-parameter dp/dy values + }; + poly_edge fedgelist[_NumVerts - 1]; + poly_edge *edgeptr = &fedgelist[0]; + for (int curv = minv; curv != maxv; curv = (curv == _NumVerts - 1) ? 0 : (curv + 1)) + { + // set the two vertices + edgeptr->v1 = &v[curv]; + edgeptr->v2 = &v[(curv == _NumVerts - 1) ? 0 : (curv + 1)]; + + // if horizontal, skip altogether + if (edgeptr->v1->y == edgeptr->v2->y) + continue; + + // need dx/dy always, and parameter deltas as necessary + _BaseType ooy = poly_recip(edgeptr->v2->y - edgeptr->v1->y); + edgeptr->dxdy = (edgeptr->v2->x - edgeptr->v1->x) * ooy; + for (int paramnum = 0; paramnum < paramcount; paramnum++) + edgeptr->dpdy[paramnum] = (edgeptr->v2->p[paramnum] - edgeptr->v1->p[paramnum]) * ooy; + edgeptr++; + } + + // walk backward to build up the backward edge list + poly_edge bedgelist[_NumVerts - 1]; + edgeptr = &bedgelist[0]; + for (int curv = minv; curv != maxv; curv = (curv == 0) ? (_NumVerts - 1) : (curv - 1)) + { + // set the two vertices + edgeptr->v1 = &v[curv]; + edgeptr->v2 = &v[(curv == 0) ? (_NumVerts - 1) : (curv - 1)]; + + // if horizontal, skip altogether + if (edgeptr->v1->y == edgeptr->v2->y) + continue; + + // need dx/dy always, and parameter deltas as necessary + _BaseType ooy = poly_recip(edgeptr->v2->y - edgeptr->v1->y); + edgeptr->dxdy = (edgeptr->v2->x - edgeptr->v1->x) * ooy; + for (int paramnum = 0; paramnum < paramcount; paramnum++) + edgeptr->dpdy[paramnum] = (edgeptr->v2->p[paramnum] - edgeptr->v1->p[paramnum]) * ooy; + edgeptr++; + } + + // determine which list is left/right: + // if the first vertex is shared, compare the slopes + // if the first vertex is not shared, compare the X coordinates + const poly_edge *ledge, *redge; + if ((fedgelist[0].v1 == bedgelist[0].v1 && fedgelist[0].dxdy < bedgelist[0].dxdy) || + (fedgelist[0].v1 != bedgelist[0].v1 && fedgelist[0].v1->x < bedgelist[0].v1->x)) + { + ledge = fedgelist; + redge = bedgelist; + } + else + { + ledge = bedgelist; + redge = fedgelist; + } + + // compute the X extents for each scanline + INT32 pixels = 0; + UINT32 startunit = m_unit.count(); + INT32 scaninc = 1; + for (INT32 curscan = minyclip; curscan < maxyclip; curscan += scaninc) + { + UINT32 bucketnum = ((UINT32)curscan / SCANLINES_PER_BUCKET) % TOTAL_BUCKETS; + UINT32 unit_index = m_unit.count(); + work_unit &unit = m_unit.next(); + + // determine how much to advance to hit the next bucket + scaninc = SCANLINES_PER_BUCKET - (UINT32)curscan % SCANLINES_PER_BUCKET; + + // fill in the work unit basics + unit.polygon = &polygon; + unit.count_next = MIN(maxyclip - curscan, scaninc); + unit.scanline = curscan; + unit.previtem = m_unit_bucket[bucketnum]; + m_unit_bucket[bucketnum] = unit_index; + + // iterate over extents + for (int extnum = 0; extnum < unit.count_next; extnum++) + { + // compute the ending X based on which part of the triangle we're in + _BaseType fully = _BaseType(curscan + extnum) + _BaseType(0.5); + while (fully > ledge->v2->y && fully < v[maxv].y) + ledge++; + while (fully > redge->v2->y && fully < v[maxv].y) + redge++; + _BaseType startx = ledge->v1->x + (fully - ledge->v1->y) * ledge->dxdy; + _BaseType stopx = redge->v1->x + (fully - redge->v1->y) * redge->dxdy; + + // clamp to full pixels + INT32 istartx = round_coordinate(startx); + INT32 istopx = round_coordinate(stopx); + + // compute parameter starting points and deltas + extent_t &extent = unit.extent[extnum]; + if (paramcount > 0) + { + _BaseType ldy = fully - ledge->v1->y; + _BaseType rdy = fully - redge->v1->y; + _BaseType oox = poly_recip(stopx - startx); + + // iterate over parameters + for (int paramnum = 0; paramnum < paramcount; paramnum++) + { + _BaseType lparam = ledge->v1->p[paramnum] + ldy * ledge->dpdy[paramnum]; + _BaseType rparam = redge->v1->p[paramnum] + rdy * redge->dpdy[paramnum]; + _BaseType dpdx = (rparam - lparam) * oox; + + extent.param[paramnum].start = lparam;// - (_BaseType(istartx) + 0.5f) * dpdx; + extent.param[paramnum].dpdx = dpdx; + } + } + + // include the right edge if requested + if (m_flags & POLYFLAG_INCLUDE_RIGHT_EDGE) + istopx++; + + // apply left/right clipping + if (istartx < cliprect.min_x) + { + for (int paramnum = 0; paramnum < paramcount; paramnum++) + extent.param[paramnum].start += (cliprect.min_x - istartx) * extent.param[paramnum].dpdx; + istartx = cliprect.min_x; + } + if (istopx > cliprect.max_x) + istopx = cliprect.max_x + 1; + + // set the extent and update the total pixel count + if (istartx >= istopx) + istartx = istopx = 0; + extent.startx = istartx; + extent.stopx = istopx; + extent.userdata = NULL; + pixels += istopx - istartx; + } + } + + // enqueue the work items + if (m_queue != NULL) + osd_work_item_queue_multiple(m_queue, work_item_callback, m_unit.count() - startunit, &m_unit[startunit], m_unit.itemsize(), WORK_ITEM_FLAG_AUTO_RELEASE); + + // return the total number of pixels in the triangle + m_quads++; + m_pixels += pixels; + return pixels; +} + + +//------------------------------------------------- +// zclip_if_less - clip a polygon using p[0] as +// a z coordinate +//------------------------------------------------- + +template +int poly_manager<_BaseType, _ObjectData, _MaxParams, _MaxPolys>::zclip_if_less(int numverts, const vertex_t *v, vertex_t *outv, int paramcount, _BaseType clipval) +{ + bool prevclipped = (v[numverts - 1].p[0] < clipval); + vertex_t *nextout = outv; + + // iterate over vertices + for (int vertnum = 0; vertnum < numverts; vertnum++) + { + bool thisclipped = (v[vertnum].p[0] < clipval); + + // if we switched from clipped to non-clipped, interpolate a vertex + if (thisclipped != prevclipped) + { + const vertex_t &v1 = v[(vertnum == 0) ? (numverts - 1) : (vertnum - 1)]; + const vertex_t &v2 = v[vertnum]; + _BaseType frac = (clipval - v1.p[0]) / (v2.p[0] - v1.p[0]); + nextout->x = v1.x + frac * (v2.x - v1.x); + nextout->y = v1.y + frac * (v2.y - v1.y); + for (int paramnum = 0; paramnum < paramcount; paramnum++) + nextout->p[paramnum] = v1.p[paramnum] + frac * (v2.p[paramnum] - v1.p[paramnum]); + nextout++; + } + + // if this vertex is not clipped, copy it in + if (!thisclipped) + *nextout++ = v[vertnum]; + + // remember the last state + prevclipped = thisclipped; + } + return nextout - outv; +} + +#endif // __POLY_H__ diff --git a/src/devices/video/polylgcy.c b/src/devices/video/polylgcy.c new file mode 100644 index 00000000000..720110e5ca3 --- /dev/null +++ b/src/devices/video/polylgcy.c @@ -0,0 +1,1359 @@ +// license:BSD-3-Clause +// copyright-holders:Ville Linde, Aaron Giles +/*************************************************************************** + + polylgcy.c + + Legacy helper routines for polygon rendering. + +***************************************************************************/ + +#include "emu.h" +#include "polylgcy.h" + + +/*************************************************************************** + DEBUGGING +***************************************************************************/ + +/* keep statistics */ +#define KEEP_STATISTICS 0 + +/* turn this on to log the reasons for any long waits */ +#define LOG_WAITS 0 + +/* number of profiling ticks before we consider a wait "long" */ +#define LOG_WAIT_THRESHOLD 1000 + + + +/*************************************************************************** + CONSTANTS +***************************************************************************/ + +#define SCANLINES_PER_BUCKET 8 +#define CACHE_LINE_SIZE 64 /* this is a general guess */ +#define TOTAL_BUCKETS (512 / SCANLINES_PER_BUCKET) +#define UNITS_PER_POLY (100 / SCANLINES_PER_BUCKET) + + + +/*************************************************************************** + TYPE DEFINITIONS +***************************************************************************/ + +/* forward definitions */ +struct polygon_info; + + +/* tri_extent describes start/end points for a scanline */ +struct tri_extent +{ + INT16 startx; /* starting X coordinate (inclusive) */ + INT16 stopx; /* ending X coordinate (exclusive) */ +}; + + +/* single set of polygon per-parameter data */ +struct poly_param +{ + float start; /* parameter value at starting X,Y */ + float dpdx; /* dp/dx relative to starting X */ + float dpdy; /* dp/dy relative to starting Y */ +}; + + +/* poly edge is used internally for quad rendering */ +struct poly_edge +{ + poly_edge * next; /* next edge in sequence */ + int index; /* index of this edge */ + const poly_vertex * v1; /* pointer to first vertex */ + const poly_vertex * v2; /* pointer to second vertex */ + float dxdy; /* dx/dy along the edge */ + float dpdy[MAX_VERTEX_PARAMS];/* per-parameter dp/dy values */ +}; + + +/* poly section is used internally for quad rendering */ +struct poly_section +{ + const poly_edge * ledge; /* pointer to left edge */ + const poly_edge * redge; /* pointer to right edge */ + float ybottom; /* bottom of this section */ +}; + + +/* work_unit_shared is a common set of data shared between tris and quads */ +struct work_unit_shared +{ + polygon_info * polygon; /* pointer to polygon */ + volatile UINT32 count_next; /* number of scanlines and index of next item to process */ + INT16 scanline; /* starting scanline and count */ + UINT16 previtem; /* index of previous item in the same bucket */ +#ifndef PTR64 + UINT32 dummy; /* pad to 16 bytes */ +#endif +}; + + +/* tri_work_unit is a triangle-specific work-unit */ +struct tri_work_unit +{ + work_unit_shared shared; /* shared data */ + tri_extent extent[SCANLINES_PER_BUCKET]; /* array of scanline extents */ +}; + + +/* quad_work_unit is a quad-specific work-unit */ +struct quad_work_unit +{ + work_unit_shared shared; /* shared data */ + poly_extent extent[SCANLINES_PER_BUCKET]; /* array of scanline extents */ +}; + + +/* work_unit is a union of the two types */ +union work_unit +{ + work_unit_shared shared; /* shared data */ + tri_work_unit tri; /* triangle work unit */ + quad_work_unit quad; /* quad work unit */ +}; + + +/* polygon_info describes a single polygon, which includes the poly_params */ +struct polygon_info +{ + legacy_poly_manager * poly; /* pointer back to the poly manager */ + void * dest; /* pointer to the destination we are rendering to */ + void * extra; /* extra data pointer */ + UINT8 numparams; /* number of parameters for this polygon */ + UINT8 numverts; /* number of vertices in this polygon */ + poly_draw_scanline_func callback; /* callback to handle a scanline's worth of work */ + INT32 xorigin; /* X origin for all parameters */ + INT32 yorigin; /* Y origin for all parameters */ + poly_param param[MAX_VERTEX_PARAMS];/* array of parameter data */ +}; + + +/* full poly manager description */ +struct legacy_poly_manager +{ + /* queue management */ + osd_work_queue * queue; /* work queue */ + + /* triangle work units */ + work_unit ** unit; /* array of work unit pointers */ + UINT32 unit_next; /* index of next unit to allocate */ + UINT32 unit_count; /* number of work units available */ + size_t unit_size; /* size of each work unit, in bytes */ + + /* quad work units */ + UINT32 quadunit_next; /* index of next unit to allocate */ + UINT32 quadunit_count; /* number of work units available */ + size_t quadunit_size; /* size of each work unit, in bytes */ + + /* poly data */ + polygon_info ** polygon; /* array of polygon pointers */ + UINT32 polygon_next; /* index of next polygon to allocate */ + UINT32 polygon_count; /* number of polygon items available */ + size_t polygon_size; /* size of each polygon, in bytes */ + + /* extra data */ + void ** extra; /* array of extra data pointers */ + UINT32 extra_next; /* index of next extra data to allocate */ + UINT32 extra_count; /* number of extra data items available */ + size_t extra_size; /* size of each extra data, in bytes */ + + /* misc data */ + UINT8 flags; /* flags */ + + /* buckets */ + UINT16 unit_bucket[TOTAL_BUCKETS]; /* buckets for tracking unit usage */ + + /* statistics */ + UINT32 triangles; /* number of triangles queued */ + UINT32 quads; /* number of quads queued */ + UINT64 pixels; /* number of pixels rendered */ +#if KEEP_STATISTICS + UINT32 unit_waits; /* number of times we waited for a unit */ + UINT32 unit_max; /* maximum units used */ + UINT32 polygon_waits; /* number of times we waited for a polygon */ + UINT32 polygon_max; /* maximum polygons used */ + UINT32 extra_waits; /* number of times we waited for an extra data */ + UINT32 extra_max; /* maximum extra data used */ + UINT32 conflicts[WORK_MAX_THREADS]; /* number of conflicts found, per thread */ + UINT32 resolved[WORK_MAX_THREADS]; /* number of conflicts resolved, per thread */ +#endif +}; + + + +/*************************************************************************** + FUNCTION PROTOTYPES +***************************************************************************/ + +static void **allocate_array(running_machine &machine, size_t *itemsize, UINT32 itemcount); +static void *poly_item_callback(void *param, int threadid); +static void poly_state_presave(legacy_poly_manager *poly); + + + +/*************************************************************************** + INLINE FUNCTIONS +***************************************************************************/ + +/*------------------------------------------------- + round_coordinate - round a coordinate to + an integer, following rules that 0.5 rounds + down +-------------------------------------------------*/ + +INLINE INT32 round_coordinate(float value) +{ + INT32 result = floor(value); + return result + (value - (float)result > 0.5f); +} + + +/*------------------------------------------------- + convert_tri_extent_to_poly_extent - convert + a simple tri_extent to a full poly_extent +-------------------------------------------------*/ + +INLINE void convert_tri_extent_to_poly_extent(poly_extent *dstextent, const tri_extent *srcextent, const polygon_info *polygon, INT32 y) +{ + /* copy start/stop always */ + dstextent->startx = srcextent->startx; + dstextent->stopx = srcextent->stopx; + + /* if we have parameters, process them as well */ + for (int paramnum = 0; paramnum < polygon->numparams; paramnum++) + { + dstextent->param[paramnum].start = polygon->param[paramnum].start + srcextent->startx * polygon->param[paramnum].dpdx + y * polygon->param[paramnum].dpdy; + dstextent->param[paramnum].dpdx = polygon->param[paramnum].dpdx; + } +} + + +/*------------------------------------------------- + interpolate_vertex - interpolate values in + a vertex based on p[0] crossing the clipval +-------------------------------------------------*/ + +INLINE void interpolate_vertex(poly_vertex *outv, const poly_vertex *v1, const poly_vertex *v2, int paramcount, float clipval) +{ + float frac = (clipval - v1->p[0]) / (v2->p[0] - v1->p[0]); + int paramnum; + + /* create a new one at the intersection point */ + outv->x = v1->x + frac * (v2->x - v1->x); + outv->y = v1->y + frac * (v2->y - v1->y); + for (paramnum = 0; paramnum < paramcount; paramnum++) + outv->p[paramnum] = v1->p[paramnum] + frac * (v2->p[paramnum] - v1->p[paramnum]); +} + + +/*------------------------------------------------- + copy_vertex - copy vertex data from one to + another +-------------------------------------------------*/ + +INLINE void copy_vertex(poly_vertex *outv, const poly_vertex *v, int paramcount) +{ + int paramnum; + + outv->x = v->x; + outv->y = v->y; + for (paramnum = 0; paramnum < paramcount; paramnum++) + outv->p[paramnum] = v->p[paramnum]; +} + + +/*------------------------------------------------- + allocate_polygon - allocate a new polygon + object, blocking if we run out +-------------------------------------------------*/ + +INLINE polygon_info *allocate_polygon(legacy_poly_manager *poly, int miny, int maxy) +{ + /* wait for a work item if we have to */ + if (poly->polygon_next + 1 > poly->polygon_count) + { + poly_wait(poly, "Out of polygons"); +#if KEEP_STATISTICS + poly->polygon_waits++; +#endif + } + else if (poly->unit_next + (maxy - miny) / SCANLINES_PER_BUCKET + 2 > poly->unit_count) + { + poly_wait(poly, "Out of work units"); +#if KEEP_STATISTICS + poly->unit_waits++; +#endif + } +#if KEEP_STATISTICS + poly->polygon_max = MAX(poly->polygon_max, poly->polygon_next + 1); +#endif + return poly->polygon[poly->polygon_next++]; +} + + + +/*************************************************************************** + INITIALIZATION/TEARDOWN +***************************************************************************/ + +/*------------------------------------------------- + poly_alloc - initialize a new polygon + manager +-------------------------------------------------*/ + +legacy_poly_manager *poly_alloc(running_machine &machine, int max_polys, size_t extra_data_size, UINT8 flags) +{ + legacy_poly_manager *poly; + + /* allocate the manager itself */ + poly = auto_alloc_clear(machine, legacy_poly_manager); + poly->flags = flags; + + /* allocate polygons */ + poly->polygon_size = sizeof(polygon_info); + poly->polygon_count = MAX(max_polys, 1); + poly->polygon_next = 0; + poly->polygon = (polygon_info **)allocate_array(machine, &poly->polygon_size, poly->polygon_count); + + /* allocate extra data */ + poly->extra_size = extra_data_size; + poly->extra_count = poly->polygon_count; + poly->extra_next = 1; + poly->extra = allocate_array(machine, &poly->extra_size, poly->extra_count); + + /* allocate triangle work units */ + poly->unit_size = (flags & POLYFLAG_ALLOW_QUADS) ? sizeof(quad_work_unit) : sizeof(tri_work_unit); + poly->unit_count = MIN(poly->polygon_count * UNITS_PER_POLY, 65535); + poly->unit_next = 0; + poly->unit = (work_unit **)allocate_array(machine, &poly->unit_size, poly->unit_count); + + /* create the work queue */ + if (!(flags & POLYFLAG_NO_WORK_QUEUE)) + poly->queue = osd_work_queue_alloc(WORK_QUEUE_FLAG_MULTI | WORK_QUEUE_FLAG_HIGH_FREQ); + + /* request a pre-save callback for synchronization */ + machine.save().register_presave(save_prepost_delegate(FUNC(poly_state_presave), poly)); + return poly; +} + + +/*------------------------------------------------- + poly_free - free a polygon manager +-------------------------------------------------*/ + +void poly_free(legacy_poly_manager *poly) +{ +#if KEEP_STATISTICS +{ + int i, conflicts = 0, resolved = 0; + for (i = 0; i < ARRAY_LENGTH(poly->conflicts); i++) + { + conflicts += poly->conflicts[i]; + resolved += poly->resolved[i]; + } + printf("Total triangles = %d\n", poly->triangles); + printf("Total quads = %d\n", poly->quads); + if (poly->pixels > 1000000000) + printf("Total pixels = %d%09d\n", (UINT32)(poly->pixels / 1000000000), (UINT32)(poly->pixels % 1000000000)); + else + printf("Total pixels = %d\n", (UINT32)poly->pixels); + printf("Conflicts: %d resolved, %d total\n", resolved, conflicts); + printf("Units: %5d used, %5d allocated, %5d waits, %4d bytes each, %7d total\n", poly->unit_max, poly->unit_count, poly->unit_waits, poly->unit_size, poly->unit_count * poly->unit_size); + printf("Polygons: %5d used, %5d allocated, %5d waits, %4d bytes each, %7d total\n", poly->polygon_max, poly->polygon_count, poly->polygon_waits, poly->polygon_size, poly->polygon_count * poly->polygon_size); + printf("Extra data: %5d used, %5d allocated, %5d waits, %4d bytes each, %7d total\n", poly->extra_max, poly->extra_count, poly->extra_waits, poly->extra_size, poly->extra_count * poly->extra_size); +} +#endif + + /* free the work queue */ + if (poly->queue != NULL) + osd_work_queue_free(poly->queue); +} + + + +/*************************************************************************** + COMMON FUNCTIONS +***************************************************************************/ + +/*------------------------------------------------- + poly_wait - wait for all pending rendering + to complete +-------------------------------------------------*/ + +void poly_wait(legacy_poly_manager *poly, const char *debug_reason) +{ + osd_ticks_t time; + + /* remember the start time if we're logging */ + if (LOG_WAITS) + time = get_profile_ticks(); + + /* wait for all pending work items to complete */ + if (poly->queue != NULL) + osd_work_queue_wait(poly->queue, osd_ticks_per_second() * 100); + + /* if we don't have a queue, just run the whole list now */ + else + { + int unitnum; + for (unitnum = 0; unitnum < poly->unit_next; unitnum++) + poly_item_callback(poly->unit[unitnum], 0); + } + + /* log any long waits */ + if (LOG_WAITS) + { + time = get_profile_ticks() - time; + if (time > LOG_WAIT_THRESHOLD) + logerror("Poly:Waited %d cycles for %s\n", (int)time, debug_reason); + } + + /* reset the state */ + poly->polygon_next = poly->unit_next = 0; + memset(poly->unit_bucket, 0xff, sizeof(poly->unit_bucket)); + + /* we need to preserve the last extra data that was supplied */ + if (poly->extra_next > 1) + memcpy(poly->extra[0], poly->extra[poly->extra_next - 1], poly->extra_size); + poly->extra_next = 1; +} + + +/*------------------------------------------------- + poly_get_extra_data - get a pointer to the + extra data for the next polygon +-------------------------------------------------*/ + +void *poly_get_extra_data(legacy_poly_manager *poly) +{ + /* wait for a work item if we have to */ + if (poly->extra_next + 1 > poly->extra_count) + { + poly_wait(poly, "Out of extra data"); +#if KEEP_STATISTICS + poly->extra_waits++; +#endif + } + + /* return a pointer to the extra data for the next item */ +#if KEEP_STATISTICS + poly->extra_max = MAX(poly->extra_max, poly->extra_next + 1); +#endif + return poly->extra[poly->extra_next++]; +} + + + +/*************************************************************************** + CORE TRIANGLE RENDERING +***************************************************************************/ + +/*------------------------------------------------- + poly_render_triangle - render a single + triangle given 3 vertexes +-------------------------------------------------*/ + +UINT32 poly_render_triangle(legacy_poly_manager *poly, void *dest, const rectangle &cliprect, poly_draw_scanline_func callback, int paramcount, const poly_vertex *v1, const poly_vertex *v2, const poly_vertex *v3) +{ + float dxdy_v1v2, dxdy_v1v3, dxdy_v2v3; + const poly_vertex *tv; + INT32 curscan, scaninc; + polygon_info *polygon; + INT32 v1yclip, v3yclip; + INT32 v1y, v3y, v1x; + INT32 pixels = 0; + UINT32 startunit; + + /* first sort by Y */ + if (v2->y < v1->y) + { + tv = v1; + v1 = v2; + v2 = tv; + } + if (v3->y < v2->y) + { + tv = v2; + v2 = v3; + v3 = tv; + if (v2->y < v1->y) + { + tv = v1; + v1 = v2; + v2 = tv; + } + } + + /* compute some integral X/Y vertex values */ + v1x = round_coordinate(v1->x); + v1y = round_coordinate(v1->y); + v3y = round_coordinate(v3->y); + + /* clip coordinates */ + v1yclip = v1y; + v3yclip = v3y + ((poly->flags & POLYFLAG_INCLUDE_BOTTOM_EDGE) ? 1 : 0); + v1yclip = MAX(v1yclip, cliprect.min_y); + v3yclip = MIN(v3yclip, cliprect.max_y + 1); + if (v3yclip - v1yclip <= 0) + return 0; + + /* allocate a new polygon */ + polygon = allocate_polygon(poly, v1yclip, v3yclip); + + /* fill in the polygon information */ + polygon->poly = poly; + polygon->dest = dest; + polygon->callback = callback; + polygon->extra = poly->extra[poly->extra_next - 1]; + polygon->numparams = paramcount; + polygon->numverts = 3; + + /* set the start X/Y coordinates */ + polygon->xorigin = v1x; + polygon->yorigin = v1y; + + /* compute the slopes for each portion of the triangle */ + dxdy_v1v2 = (v2->y == v1->y) ? 0.0f : (v2->x - v1->x) / (v2->y - v1->y); + dxdy_v1v3 = (v3->y == v1->y) ? 0.0f : (v3->x - v1->x) / (v3->y - v1->y); + dxdy_v2v3 = (v3->y == v2->y) ? 0.0f : (v3->x - v2->x) / (v3->y - v2->y); + + /* compute the X extents for each scanline */ + startunit = poly->unit_next; + for (curscan = v1yclip; curscan < v3yclip; curscan += scaninc) + { + UINT32 bucketnum = ((UINT32)curscan / SCANLINES_PER_BUCKET) % TOTAL_BUCKETS; + UINT32 unit_index = poly->unit_next++; + tri_work_unit *unit = &poly->unit[unit_index]->tri; + int extnum; + + /* determine how much to advance to hit the next bucket */ + scaninc = SCANLINES_PER_BUCKET - (UINT32)curscan % SCANLINES_PER_BUCKET; + + /* fill in the work unit basics */ + unit->shared.polygon = polygon; + unit->shared.count_next = MIN(v3yclip - curscan, scaninc); + unit->shared.scanline = curscan; + unit->shared.previtem = poly->unit_bucket[bucketnum]; + poly->unit_bucket[bucketnum] = unit_index; + + /* iterate over extents */ + for (extnum = 0; extnum < unit->shared.count_next; extnum++) + { + float fully = (float)(curscan + extnum) + 0.5f; + float startx = v1->x + (fully - v1->y) * dxdy_v1v3; + float stopx; + INT32 istartx, istopx; + + /* compute the ending X based on which part of the triangle we're in */ + if (fully < v2->y) + stopx = v1->x + (fully - v1->y) * dxdy_v1v2; + else + stopx = v2->x + (fully - v2->y) * dxdy_v2v3; + + /* clamp to full pixels */ + istartx = round_coordinate(startx); + istopx = round_coordinate(stopx); + + /* force start < stop */ + if (istartx > istopx) + { + INT32 temp = istartx; + istartx = istopx; + istopx = temp; + } + + /* include the right edge if requested */ + if (poly->flags & POLYFLAG_INCLUDE_RIGHT_EDGE) + istopx++; + + /* apply left/right clipping */ + if (istartx < cliprect.min_x) + istartx = cliprect.min_x; + if (istopx > cliprect.max_x) + istopx = cliprect.max_x + 1; + + /* set the extent and update the total pixel count */ + if (istartx >= istopx) + istartx = istopx = 0; + unit->extent[extnum].startx = istartx; + unit->extent[extnum].stopx = istopx; + pixels += istopx - istartx; + } + } +#if KEEP_STATISTICS + poly->unit_max = MAX(poly->unit_max, poly->unit_next); +#endif + + /* compute parameter starting points and deltas */ + if (paramcount > 0) + { + float a00 = v2->y - v3->y; + float a01 = v3->x - v2->x; + float a02 = v2->x*v3->y - v3->x*v2->y; + float a10 = v3->y - v1->y; + float a11 = v1->x - v3->x; + float a12 = v3->x*v1->y - v1->x*v3->y; + float a20 = v1->y - v2->y; + float a21 = v2->x - v1->x; + float a22 = v1->x*v2->y - v2->x*v1->y; + float det = a02 + a12 + a22; + + if(fabsf(det) < 0.001f) { + for (int paramnum = 0; paramnum < paramcount; paramnum++) + { + poly_param *params = &polygon->param[paramnum]; + params->dpdx = 0; + params->dpdy = 0; + params->start = v1->p[paramnum]; + } + } + else + { + float idet = 1/det; + for (int paramnum = 0; paramnum < paramcount; paramnum++) + { + poly_param *params = &polygon->param[paramnum]; + params->dpdx = idet*(v1->p[paramnum]*a00 + v2->p[paramnum]*a10 + v3->p[paramnum]*a20); + params->dpdy = idet*(v1->p[paramnum]*a01 + v2->p[paramnum]*a11 + v3->p[paramnum]*a21); + params->start = idet*(v1->p[paramnum]*a02 + v2->p[paramnum]*a12 + v3->p[paramnum]*a22); + } + } + } + + /* enqueue the work items */ + if (poly->queue != NULL) + osd_work_item_queue_multiple(poly->queue, poly_item_callback, poly->unit_next - startunit, poly->unit[startunit], poly->unit_size, WORK_ITEM_FLAG_AUTO_RELEASE); + + /* return the total number of pixels in the triangle */ + poly->triangles++; + poly->pixels += pixels; + return pixels; +} + + +/*------------------------------------------------- + poly_render_triangle_fan - render a set of + triangles in a fan +-------------------------------------------------*/ + +UINT32 poly_render_triangle_fan(legacy_poly_manager *poly, void *dest, const rectangle &cliprect, poly_draw_scanline_func callback, int paramcount, int numverts, const poly_vertex *v) +{ + UINT32 pixels = 0; + int vertnum; + + /* iterate over vertices */ + for (vertnum = 2; vertnum < numverts; vertnum++) + pixels += poly_render_triangle(poly, dest, cliprect, callback, paramcount, &v[0], &v[vertnum - 1], &v[vertnum]); + return pixels; +} + + +/*------------------------------------------------- + poly_render_triangle_custom - perform a custom + render of an object, given specific extents +-------------------------------------------------*/ + +UINT32 poly_render_triangle_custom(legacy_poly_manager *poly, void *dest, const rectangle &cliprect, poly_draw_scanline_func callback, int startscanline, int numscanlines, const poly_extent *extents) +{ + INT32 curscan, scaninc; + polygon_info *polygon; + INT32 v1yclip, v3yclip; + INT32 pixels = 0; + UINT32 startunit; + + /* clip coordinates */ + v1yclip = MAX(startscanline, cliprect.min_y); + v3yclip = MIN(startscanline + numscanlines, cliprect.max_y + 1); + if (v3yclip - v1yclip <= 0) + return 0; + + /* allocate a new polygon */ + polygon = allocate_polygon(poly, v1yclip, v3yclip); + + /* fill in the polygon information */ + polygon->poly = poly; + polygon->dest = dest; + polygon->callback = callback; + polygon->extra = poly->extra[poly->extra_next - 1]; + polygon->numparams = 0; + polygon->numverts = 3; + + /* compute the X extents for each scanline */ + startunit = poly->unit_next; + for (curscan = v1yclip; curscan < v3yclip; curscan += scaninc) + { + UINT32 bucketnum = ((UINT32)curscan / SCANLINES_PER_BUCKET) % TOTAL_BUCKETS; + UINT32 unit_index = poly->unit_next++; + tri_work_unit *unit = &poly->unit[unit_index]->tri; + int extnum; + + /* determine how much to advance to hit the next bucket */ + scaninc = SCANLINES_PER_BUCKET - (UINT32)curscan % SCANLINES_PER_BUCKET; + + /* fill in the work unit basics */ + unit->shared.polygon = polygon; + unit->shared.count_next = MIN(v3yclip - curscan, scaninc); + unit->shared.scanline = curscan; + unit->shared.previtem = poly->unit_bucket[bucketnum]; + poly->unit_bucket[bucketnum] = unit_index; + + /* iterate over extents */ + for (extnum = 0; extnum < unit->shared.count_next; extnum++) + { + const poly_extent *extent = &extents[(curscan + extnum) - startscanline]; + INT32 istartx = extent->startx, istopx = extent->stopx; + + /* force start < stop */ + if (istartx > istopx) + { + INT32 temp = istartx; + istartx = istopx; + istopx = temp; + } + + /* apply left/right clipping */ + if (istartx < cliprect.min_x) + istartx = cliprect.min_x; + if (istopx > cliprect.max_x) + istopx = cliprect.max_x + 1; + + /* set the extent and update the total pixel count */ + unit->extent[extnum].startx = istartx; + unit->extent[extnum].stopx = istopx; + if (istartx < istopx) + pixels += istopx - istartx; + } + } +#if KEEP_STATISTICS + poly->unit_max = MAX(poly->unit_max, poly->unit_next); +#endif + + /* enqueue the work items */ + if (poly->queue != NULL) + osd_work_item_queue_multiple(poly->queue, poly_item_callback, poly->unit_next - startunit, poly->unit[startunit], poly->unit_size, WORK_ITEM_FLAG_AUTO_RELEASE); + + /* return the total number of pixels in the object */ + poly->triangles++; + poly->pixels += pixels; + return pixels; +} + + + +/*************************************************************************** + CORE QUAD RENDERING +***************************************************************************/ + +/*------------------------------------------------- + poly_render_quad - render a single quad + given 4 vertexes +-------------------------------------------------*/ + +UINT32 poly_render_quad(legacy_poly_manager *poly, void *dest, const rectangle &cliprect, poly_draw_scanline_func callback, int paramcount, const poly_vertex *v1, const poly_vertex *v2, const poly_vertex *v3, const poly_vertex *v4) +{ + poly_edge fedgelist[3], bedgelist[3]; + const poly_edge *ledge, *redge; + const poly_vertex *v[4]; + poly_edge *edgeptr; + int minv, maxv, curv; + INT32 minyclip, maxyclip; + INT32 miny, maxy; + INT32 curscan, scaninc; + polygon_info *polygon; + INT32 pixels = 0; + UINT32 startunit; + + assert(poly->flags & POLYFLAG_ALLOW_QUADS); + + /* arrays make things easier */ + v[0] = v1; + v[1] = v2; + v[2] = v3; + v[3] = v4; + + /* determine min/max Y vertices */ + if (v[1]->y < v[0]->y) + minv = 1, maxv = 0; + else + minv = 0, maxv = 1; + if (v[2]->y < v[minv]->y) + minv = 2; + else if (v[2]->y > v[maxv]->y) + maxv = 2; + if (v[3]->y < v[minv]->y) + minv = 3; + else if (v[3]->y > v[maxv]->y) + maxv = 3; + + /* determine start/end scanlines */ + miny = round_coordinate(v[minv]->y); + maxy = round_coordinate(v[maxv]->y); + + /* clip coordinates */ + minyclip = miny; + maxyclip = maxy + ((poly->flags & POLYFLAG_INCLUDE_BOTTOM_EDGE) ? 1 : 0); + minyclip = MAX(minyclip, cliprect.min_y); + maxyclip = MIN(maxyclip, cliprect.max_y + 1); + if (maxyclip - minyclip <= 0) + return 0; + + /* allocate a new polygon */ + polygon = allocate_polygon(poly, minyclip, maxyclip); + + /* fill in the polygon information */ + polygon->poly = poly; + polygon->dest = dest; + polygon->callback = callback; + polygon->extra = poly->extra[poly->extra_next - 1]; + polygon->numparams = paramcount; + polygon->numverts = 4; + + /* walk forward to build up the forward edge list */ + edgeptr = &fedgelist[0]; + for (curv = minv; curv != maxv; curv = (curv + 1) & 3) + { + int paramnum; + float ooy; + + /* set the two vertices */ + edgeptr->v1 = v[curv]; + edgeptr->v2 = v[(curv + 1) & 3]; + + /* if horizontal, skip altogether */ + if (edgeptr->v1->y == edgeptr->v2->y) + continue; + + /* need dx/dy always, and parameter deltas as necessary */ + ooy = 1.0f / (edgeptr->v2->y - edgeptr->v1->y); + edgeptr->dxdy = (edgeptr->v2->x - edgeptr->v1->x) * ooy; + for (paramnum = 0; paramnum < paramcount; paramnum++) + edgeptr->dpdy[paramnum] = (edgeptr->v2->p[paramnum] - edgeptr->v1->p[paramnum]) * ooy; + edgeptr++; + } + + /* walk backward to build up the backward edge list */ + edgeptr = &bedgelist[0]; + for (curv = minv; curv != maxv; curv = (curv - 1) & 3) + { + int paramnum; + float ooy; + + /* set the two vertices */ + edgeptr->v1 = v[curv]; + edgeptr->v2 = v[(curv - 1) & 3]; + + /* if horizontal, skip altogether */ + if (edgeptr->v1->y == edgeptr->v2->y) + continue; + + /* need dx/dy always, and parameter deltas as necessary */ + ooy = 1.0f / (edgeptr->v2->y - edgeptr->v1->y); + edgeptr->dxdy = (edgeptr->v2->x - edgeptr->v1->x) * ooy; + for (paramnum = 0; paramnum < paramcount; paramnum++) + edgeptr->dpdy[paramnum] = (edgeptr->v2->p[paramnum] - edgeptr->v1->p[paramnum]) * ooy; + edgeptr++; + } + + /* determine which list is left/right: */ + /* if the first vertex is shared, compare the slopes */ + /* if the first vertex is not shared, compare the X coordinates */ + if ((fedgelist[0].v1 == bedgelist[0].v1 && fedgelist[0].dxdy < bedgelist[0].dxdy) || + (fedgelist[0].v1 != bedgelist[0].v1 && fedgelist[0].v1->x < bedgelist[0].v1->x)) + { + ledge = fedgelist; + redge = bedgelist; + } + else + { + ledge = bedgelist; + redge = fedgelist; + } + + /* compute the X extents for each scanline */ + startunit = poly->unit_next; + for (curscan = minyclip; curscan < maxyclip; curscan += scaninc) + { + UINT32 bucketnum = ((UINT32)curscan / SCANLINES_PER_BUCKET) % TOTAL_BUCKETS; + UINT32 unit_index = poly->unit_next++; + quad_work_unit *unit = &poly->unit[unit_index]->quad; + int extnum; + + /* determine how much to advance to hit the next bucket */ + scaninc = SCANLINES_PER_BUCKET - (UINT32)curscan % SCANLINES_PER_BUCKET; + + /* fill in the work unit basics */ + unit->shared.polygon = polygon; + unit->shared.count_next = MIN(maxyclip - curscan, scaninc); + unit->shared.scanline = curscan; + unit->shared.previtem = poly->unit_bucket[bucketnum]; + poly->unit_bucket[bucketnum] = unit_index; + + /* iterate over extents */ + for (extnum = 0; extnum < unit->shared.count_next; extnum++) + { + float fully = (float)(curscan + extnum) + 0.5f; + float startx, stopx; + INT32 istartx, istopx; + int paramnum; + + /* compute the ending X based on which part of the triangle we're in */ + while (fully > ledge->v2->y && fully < v[maxv]->y) + ledge++; + while (fully > redge->v2->y && fully < v[maxv]->y) + redge++; + startx = ledge->v1->x + (fully - ledge->v1->y) * ledge->dxdy; + stopx = redge->v1->x + (fully - redge->v1->y) * redge->dxdy; + + /* clamp to full pixels */ + istartx = round_coordinate(startx); + istopx = round_coordinate(stopx); + + /* compute parameter starting points and deltas */ + if (paramcount > 0) + { + float ldy = fully - ledge->v1->y; + float rdy = fully - redge->v1->y; + float oox = 1.0f / (stopx - startx); + + /* iterate over parameters */ + for (paramnum = 0; paramnum < paramcount; paramnum++) + { + float lparam = ledge->v1->p[paramnum] + ldy * ledge->dpdy[paramnum]; + float rparam = redge->v1->p[paramnum] + rdy * redge->dpdy[paramnum]; + float dpdx = (rparam - lparam) * oox; + + unit->extent[extnum].param[paramnum].start = lparam;// - ((float)istartx + 0.5f) * dpdx; + unit->extent[extnum].param[paramnum].dpdx = dpdx; + } + } + + /* include the right edge if requested */ + if (poly->flags & POLYFLAG_INCLUDE_RIGHT_EDGE) + istopx++; + + /* apply left/right clipping */ + if (istartx < cliprect.min_x) + { + for (paramnum = 0; paramnum < paramcount; paramnum++) + unit->extent[extnum].param[paramnum].start += (cliprect.min_x - istartx) * unit->extent[extnum].param[paramnum].dpdx; + istartx = cliprect.min_x; + } + if (istopx > cliprect.max_x) + istopx = cliprect.max_x + 1; + + /* set the extent and update the total pixel count */ + if (istartx >= istopx) + istartx = istopx = 0; + unit->extent[extnum].startx = istartx; + unit->extent[extnum].stopx = istopx; + pixels += istopx - istartx; + } + } +#if KEEP_STATISTICS + poly->unit_max = MAX(poly->unit_max, poly->unit_next); +#endif + + /* enqueue the work items */ + if (poly->queue != NULL) + osd_work_item_queue_multiple(poly->queue, poly_item_callback, poly->unit_next - startunit, poly->unit[startunit], poly->unit_size, WORK_ITEM_FLAG_AUTO_RELEASE); + + /* return the total number of pixels in the triangle */ + poly->quads++; + poly->pixels += pixels; + return pixels; +} + + +/*------------------------------------------------- + poly_render_quad_fan - render a set of + quads in a fan +-------------------------------------------------*/ + +UINT32 poly_render_quad_fan(legacy_poly_manager *poly, void *dest, const rectangle &cliprect, poly_draw_scanline_func callback, int paramcount, int numverts, const poly_vertex *v) +{ + UINT32 pixels = 0; + int vertnum; + + /* iterate over vertices */ + for (vertnum = 2; vertnum < numverts; vertnum += 2) + pixels += poly_render_quad(poly, dest, cliprect, callback, paramcount, &v[0], &v[vertnum - 1], &v[vertnum], &v[MIN(vertnum + 1, numverts - 1)]); + return pixels; +} + + + +/*************************************************************************** + CORE POLYGON RENDERING +***************************************************************************/ + +/*------------------------------------------------- + poly_render_polygon - render a single polygon up + to 32 vertices +-------------------------------------------------*/ + +UINT32 poly_render_polygon(legacy_poly_manager *poly, void *dest, const rectangle &cliprect, poly_draw_scanline_func callback, int paramcount, int numverts, const poly_vertex *v) +{ + poly_edge fedgelist[MAX_POLYGON_VERTS - 1], bedgelist[MAX_POLYGON_VERTS - 1]; + const poly_edge *ledge, *redge; + poly_edge *edgeptr; + int minv, maxv, curv; + INT32 minyclip, maxyclip; + INT32 miny, maxy; + INT32 curscan, scaninc; + polygon_info *polygon; + INT32 pixels = 0; + UINT32 startunit; + int vertnum; + + assert(poly->flags & POLYFLAG_ALLOW_QUADS); + + /* determine min/max Y vertices */ + minv = maxv = 0; + for (vertnum = 1; vertnum < numverts; vertnum++) + { + if (v[vertnum].y < v[minv].y) + minv = vertnum; + else if (v[vertnum].y > v[maxv].y) + maxv = vertnum; + } + + /* determine start/end scanlines */ + miny = round_coordinate(v[minv].y); + maxy = round_coordinate(v[maxv].y); + + /* clip coordinates */ + minyclip = miny; + maxyclip = maxy + ((poly->flags & POLYFLAG_INCLUDE_BOTTOM_EDGE) ? 1 : 0); + minyclip = MAX(minyclip, cliprect.min_y); + maxyclip = MIN(maxyclip, cliprect.max_y + 1); + if (maxyclip - minyclip <= 0) + return 0; + + /* allocate a new polygon */ + polygon = allocate_polygon(poly, minyclip, maxyclip); + + /* fill in the polygon information */ + polygon->poly = poly; + polygon->dest = dest; + polygon->callback = callback; + polygon->extra = poly->extra[poly->extra_next - 1]; + polygon->numparams = paramcount; + polygon->numverts = numverts; + + /* walk forward to build up the forward edge list */ + edgeptr = &fedgelist[0]; + for (curv = minv; curv != maxv; curv = (curv == numverts - 1) ? 0 : (curv + 1)) + { + int paramnum; + float ooy; + + /* set the two vertices */ + edgeptr->v1 = &v[curv]; + edgeptr->v2 = &v[(curv == numverts - 1) ? 0 : (curv + 1)]; + + /* if horizontal, skip altogether */ + if (edgeptr->v1->y == edgeptr->v2->y) + continue; + + /* need dx/dy always, and parameter deltas as necessary */ + ooy = 1.0f / (edgeptr->v2->y - edgeptr->v1->y); + edgeptr->dxdy = (edgeptr->v2->x - edgeptr->v1->x) * ooy; + for (paramnum = 0; paramnum < paramcount; paramnum++) + edgeptr->dpdy[paramnum] = (edgeptr->v2->p[paramnum] - edgeptr->v1->p[paramnum]) * ooy; + edgeptr++; + } + + /* walk backward to build up the backward edge list */ + edgeptr = &bedgelist[0]; + for (curv = minv; curv != maxv; curv = (curv == 0) ? (numverts - 1) : (curv - 1)) + { + int paramnum; + float ooy; + + /* set the two vertices */ + edgeptr->v1 = &v[curv]; + edgeptr->v2 = &v[(curv == 0) ? (numverts - 1) : (curv - 1)]; + + /* if horizontal, skip altogether */ + if (edgeptr->v1->y == edgeptr->v2->y) + continue; + + /* need dx/dy always, and parameter deltas as necessary */ + ooy = 1.0f / (edgeptr->v2->y - edgeptr->v1->y); + edgeptr->dxdy = (edgeptr->v2->x - edgeptr->v1->x) * ooy; + for (paramnum = 0; paramnum < paramcount; paramnum++) + edgeptr->dpdy[paramnum] = (edgeptr->v2->p[paramnum] - edgeptr->v1->p[paramnum]) * ooy; + edgeptr++; + } + + /* determine which list is left/right: */ + /* if the first vertex is shared, compare the slopes */ + /* if the first vertex is not shared, compare the X coordinates */ + if ((fedgelist[0].v1 == bedgelist[0].v1 && fedgelist[0].dxdy < bedgelist[0].dxdy) || + (fedgelist[0].v1 != bedgelist[0].v1 && fedgelist[0].v1->x < bedgelist[0].v1->x)) + { + ledge = fedgelist; + redge = bedgelist; + } + else + { + ledge = bedgelist; + redge = fedgelist; + } + + /* compute the X extents for each scanline */ + startunit = poly->unit_next; + for (curscan = minyclip; curscan < maxyclip; curscan += scaninc) + { + UINT32 bucketnum = ((UINT32)curscan / SCANLINES_PER_BUCKET) % TOTAL_BUCKETS; + UINT32 unit_index = poly->unit_next++; + quad_work_unit *unit = &poly->unit[unit_index]->quad; + int extnum; + + /* determine how much to advance to hit the next bucket */ + scaninc = SCANLINES_PER_BUCKET - (UINT32)curscan % SCANLINES_PER_BUCKET; + + /* fill in the work unit basics */ + unit->shared.polygon = polygon; + unit->shared.count_next = MIN(maxyclip - curscan, scaninc); + unit->shared.scanline = curscan; + unit->shared.previtem = poly->unit_bucket[bucketnum]; + poly->unit_bucket[bucketnum] = unit_index; + + /* iterate over extents */ + for (extnum = 0; extnum < unit->shared.count_next; extnum++) + { + float fully = (float)(curscan + extnum) + 0.5f; + float startx, stopx; + INT32 istartx, istopx; + int paramnum; + + /* compute the ending X based on which part of the triangle we're in */ + while (fully > ledge->v2->y && fully < v[maxv].y) + ledge++; + while (fully > redge->v2->y && fully < v[maxv].y) + redge++; + startx = ledge->v1->x + (fully - ledge->v1->y) * ledge->dxdy; + stopx = redge->v1->x + (fully - redge->v1->y) * redge->dxdy; + + /* clamp to full pixels */ + istartx = round_coordinate(startx); + istopx = round_coordinate(stopx); + + /* compute parameter starting points and deltas */ + if (paramcount > 0) + { + float ldy = fully - ledge->v1->y; + float rdy = fully - redge->v1->y; + float oox = 1.0f / (stopx - startx); + + /* iterate over parameters */ + for (paramnum = 0; paramnum < paramcount; paramnum++) + { + float lparam = ledge->v1->p[paramnum] + ldy * ledge->dpdy[paramnum]; + float rparam = redge->v1->p[paramnum] + rdy * redge->dpdy[paramnum]; + float dpdx = (rparam - lparam) * oox; + + unit->extent[extnum].param[paramnum].start = lparam;// - ((float)istartx + 0.5f) * dpdx; + unit->extent[extnum].param[paramnum].dpdx = dpdx; + } + } + + /* include the right edge if requested */ + if (poly->flags & POLYFLAG_INCLUDE_RIGHT_EDGE) + istopx++; + + /* apply left/right clipping */ + if (istartx < cliprect.min_x) + { + for (paramnum = 0; paramnum < paramcount; paramnum++) + unit->extent[extnum].param[paramnum].start += (cliprect.min_x - istartx) * unit->extent[extnum].param[paramnum].dpdx; + istartx = cliprect.min_x; + } + if (istopx > cliprect.max_x) + istopx = cliprect.max_x + 1; + + /* set the extent and update the total pixel count */ + if (istartx >= istopx) + istartx = istopx = 0; + unit->extent[extnum].startx = istartx; + unit->extent[extnum].stopx = istopx; + pixels += istopx - istartx; + } + } +#if KEEP_STATISTICS + poly->unit_max = MAX(poly->unit_max, poly->unit_next); +#endif + + /* enqueue the work items */ + if (poly->queue != NULL) + osd_work_item_queue_multiple(poly->queue, poly_item_callback, poly->unit_next - startunit, poly->unit[startunit], poly->unit_size, WORK_ITEM_FLAG_AUTO_RELEASE); + + /* return the total number of pixels in the triangle */ + poly->quads++; + poly->pixels += pixels; + return pixels; +} + + + +/*************************************************************************** + CLIPPING +***************************************************************************/ + +/*------------------------------------------------- + poly_zclip_if_less - z clip a polygon against + the given value, returning a set of clipped + vertices +-------------------------------------------------*/ + +int poly_zclip_if_less(int numverts, const poly_vertex *v, poly_vertex *outv, int paramcount, float clipval) +{ + int prevclipped = (v[numverts - 1].p[0] < clipval); + poly_vertex *nextout = outv; + int vertnum; + + /* iterate over vertices */ + for (vertnum = 0; vertnum < numverts; vertnum++) + { + int thisclipped = (v[vertnum].p[0] < clipval); + + /* if we switched from clipped to non-clipped, interpolate a vertex */ + if (thisclipped != prevclipped) + interpolate_vertex(nextout++, &v[(vertnum == 0) ? (numverts - 1) : (vertnum - 1)], &v[vertnum], paramcount, clipval); + + /* if this vertex is not clipped, copy it in */ + if (!thisclipped) + copy_vertex(nextout++, &v[vertnum], paramcount); + + /* remember the last state */ + prevclipped = thisclipped; + } + return nextout - outv; +} + + + +/*************************************************************************** + INTERNAL FUNCTIONS +***************************************************************************/ + +/*------------------------------------------------- + allocate_array - allocate an array of pointers +-------------------------------------------------*/ + +static void **allocate_array(running_machine &machine, size_t *itemsize, UINT32 itemcount) +{ + void **ptrarray; + int itemnum; + + /* fail if 0 */ + if (itemcount == 0) + return NULL; + + /* round to a cache line boundary */ + *itemsize = ((*itemsize + CACHE_LINE_SIZE - 1) / CACHE_LINE_SIZE) * CACHE_LINE_SIZE; + + /* allocate the array */ + ptrarray = auto_alloc_array_clear(machine, void *, itemcount); + + /* allocate the actual items */ + ptrarray[0] = auto_alloc_array_clear(machine, UINT8, *itemsize * itemcount); + + /* initialize the pointer array */ + for (itemnum = 1; itemnum < itemcount; itemnum++) + ptrarray[itemnum] = (UINT8 *)ptrarray[0] + *itemsize * itemnum; + return ptrarray; +} + + +/*------------------------------------------------- + poly_item_callback - callback for each poly + item +-------------------------------------------------*/ + +static void *poly_item_callback(void *param, int threadid) +{ + while (1) + { + work_unit *unit = (work_unit *)param; + polygon_info *polygon = unit->shared.polygon; + int count = unit->shared.count_next & 0xffff; + UINT32 orig_count_next; + int curscan; + + /* if our previous item isn't done yet, enqueue this item to the end and proceed */ + if (unit->shared.previtem != 0xffff) + { + work_unit *prevunit = polygon->poly->unit[unit->shared.previtem]; + if (prevunit->shared.count_next != 0) + { + UINT32 unitnum = ((UINT8 *)unit - (UINT8 *)polygon->poly->unit[0]) / polygon->poly->unit_size; + UINT32 new_count_next; + + /* attempt to atomically swap in this new value */ + do + { + orig_count_next = prevunit->shared.count_next; + new_count_next = orig_count_next | (unitnum << 16); + } while (compare_exchange32((volatile INT32 *)&prevunit->shared.count_next, orig_count_next, new_count_next) != orig_count_next); + +#if KEEP_STATISTICS + /* track resolved conflicts */ + polygon->poly->conflicts[threadid]++; + if (orig_count_next != 0) + polygon->poly->resolved[threadid]++; +#endif + /* if we succeeded, skip out early so we can do other work */ + if (orig_count_next != 0) + break; + } + } + + /* iterate over extents */ + for (curscan = 0; curscan < count; curscan++) + { + if (polygon->numverts == 3) + { + poly_extent tmpextent; + convert_tri_extent_to_poly_extent(&tmpextent, &unit->tri.extent[curscan], polygon, unit->shared.scanline + curscan); + (*polygon->callback)(polygon->dest, unit->shared.scanline + curscan, &tmpextent, polygon->extra, threadid); + } + else + (*polygon->callback)(polygon->dest, unit->shared.scanline + curscan, &unit->quad.extent[curscan], polygon->extra, threadid); + } + + /* set our count to 0 and re-fetch the original count value */ + do + { + orig_count_next = unit->shared.count_next; + } while (compare_exchange32((volatile INT32 *)&unit->shared.count_next, orig_count_next, 0) != orig_count_next); + + /* if we have no more work to do, do nothing */ + orig_count_next >>= 16; + if (orig_count_next == 0) + break; + param = polygon->poly->unit[orig_count_next]; + } + return NULL; +} + + +/*------------------------------------------------- + poly_state_presave - pre-save callback to + ensure everything is synced before saving +-------------------------------------------------*/ + +static void poly_state_presave(legacy_poly_manager *poly) +{ + poly_wait(poly, "pre-save"); +} diff --git a/src/devices/video/polylgcy.h b/src/devices/video/polylgcy.h new file mode 100644 index 00000000000..bc409d77db5 --- /dev/null +++ b/src/devices/video/polylgcy.h @@ -0,0 +1,155 @@ +// license:BSD-3-Clause +// copyright-holders:Ville Linde, Aaron Giles +/*************************************************************************** + + polylgcy.h + + Legacy polygon helper routines. + +**************************************************************************** + + Pixel model: + + (0.0,0.0) (1.0,0.0) (2.0,0.0) (3.0,0.0) + +---------------+---------------+---------------+ + | | | | + | | | | + | (0.5,0.5) | (1.5,0.5) | (2.5,0.5) | + | * | * | * | + | | | | + | | | | + (0.0,1.0) (1.0,1.0) (2.0,1.0) (3.0,1.0) + +---------------+---------------+---------------+ + | | | | + | | | | + | (0.5,1.5) | (1.5,1.5) | (2.5,1.5) | + | * | * | * | + | | | | + | | | | + | | | | + +---------------+---------------+---------------+ + (0.0,2.0) (1.0,2.0) (2.0,2.0) (3.0,2.0) + +***************************************************************************/ + +#pragma once + +#ifndef __POLYLGCY_H__ +#define __POLYLGCY_H__ + + +/*************************************************************************** + CONSTANTS +***************************************************************************/ + +#define MAX_VERTEX_PARAMS 6 +#define MAX_POLYGON_VERTS 32 + +#define POLYFLAG_INCLUDE_BOTTOM_EDGE 0x01 +#define POLYFLAG_INCLUDE_RIGHT_EDGE 0x02 +#define POLYFLAG_NO_WORK_QUEUE 0x04 +#define POLYFLAG_ALLOW_QUADS 0x08 + + + +/*************************************************************************** + TYPE DEFINITIONS +***************************************************************************/ + +/* opaque reference to the poly manager */ +struct legacy_poly_manager; + + +/* input vertex data */ +struct poly_vertex +{ + float x; /* X coordinate */ + float y; /* Y coordinate */ + float p[MAX_VERTEX_PARAMS]; /* interpolated parameter values */ +}; + + +/* poly_param_extent describes information for a single parameter in an extent */ +struct poly_param_extent +{ + float start; /* parameter value at starting X,Y */ + float dpdx; /* dp/dx relative to starting X */ +}; + + +/* poly_extent describes start/end points for a scanline, along with per-scanline parameters */ +struct poly_extent +{ + INT16 startx; /* starting X coordinate (inclusive) */ + INT16 stopx; /* ending X coordinate (exclusive) */ + poly_param_extent param[MAX_VERTEX_PARAMS]; /* starting and dx values for each parameter */ +}; + + +/* callback routine to process a batch of scanlines in a triangle */ +typedef void (*poly_draw_scanline_func)(void *dest, INT32 scanline, const poly_extent *extent, const void *extradata, int threadid); + + + +/*************************************************************************** + TYPE DEFINITIONS +***************************************************************************/ + + +/* ----- initialization/teardown ----- */ + +/* allocate a new poly manager that can render triangles */ +legacy_poly_manager *poly_alloc(running_machine &machine, int max_polys, size_t extra_data_size, UINT8 flags); + +/* free a poly manager */ +void poly_free(legacy_poly_manager *poly); + + + +/* ----- common functions ----- */ + +/* wait until all polygons in the queue have been rendered */ +void poly_wait(legacy_poly_manager *poly, const char *debug_reason); + +/* get a pointer to the extra data for the next polygon */ +void *poly_get_extra_data(legacy_poly_manager *poly); + + + +/* ----- core triangle rendering ----- */ + +/* render a single triangle given 3 vertexes */ +UINT32 poly_render_triangle(legacy_poly_manager *poly, void *dest, const rectangle &cliprect, poly_draw_scanline_func callback, int paramcount, const poly_vertex *v1, const poly_vertex *v2, const poly_vertex *v3); + +/* render a set of triangles in a fan */ +UINT32 poly_render_triangle_fan(legacy_poly_manager *poly, void *dest, const rectangle &cliprect, poly_draw_scanline_func callback, int paramcount, int numverts, const poly_vertex *v); + +/* perform a custom render of an object, given specific extents */ +UINT32 poly_render_triangle_custom(legacy_poly_manager *poly, void *dest, const rectangle &cliprect, poly_draw_scanline_func callback, int startscanline, int numscanlines, const poly_extent *extents); + + + +/* ----- core quad rendering ----- */ + +/* render a single quad given 4 vertexes */ +UINT32 poly_render_quad(legacy_poly_manager *poly, void *dest, const rectangle &cliprect, poly_draw_scanline_func callback, int paramcount, const poly_vertex *v1, const poly_vertex *v2, const poly_vertex *v3, const poly_vertex *v4); + +/* render a set of quads in a fan */ +UINT32 poly_render_quad_fan(legacy_poly_manager *poly, void *dest, const rectangle &cliprect, poly_draw_scanline_func callback, int paramcount, int numverts, const poly_vertex *v); + + + +/* ----- core polygon rendering ----- */ + +/* render a single polygon up to 32 vertices */ +UINT32 poly_render_polygon(legacy_poly_manager *poly, void *dest, const rectangle &cliprect, poly_draw_scanline_func callback, int paramcount, int numverts, const poly_vertex *v); + + + +/* ----- clipping ----- */ + +/* zclip (assumes p[0] == z) a polygon */ +int poly_zclip_if_less(int numverts, const poly_vertex *v, poly_vertex *outv, int paramcount, float clipval); + + +#endif /* __POLYLGCY_H__ */ diff --git a/src/devices/video/psx.c b/src/devices/video/psx.c new file mode 100644 index 00000000000..167280e3415 --- /dev/null +++ b/src/devices/video/psx.c @@ -0,0 +1,3822 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/* + * PlayStation GPU emulator + * + * Copyright 2003-2014 smf + * + */ + +#define DEBUG_VIEWER ( 0 ) + +#include "emu.h" +#include "video/psx.h" + +#define VERBOSE_LEVEL ( 0 ) + +// device type definition +const device_type CXD8514Q = &device_creator; +const device_type CXD8538Q = &device_creator; +const device_type CXD8561Q = &device_creator; +const device_type CXD8561BQ = &device_creator; +const device_type CXD8561CQ = &device_creator; +const device_type CXD8654Q = &device_creator; + +psxgpu_device::psxgpu_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + m_vblank_handler(*this) +#if DEBUG_VIEWER +, + m_screen(*this, "screen") +#endif +{ +} + +void psxgpu_device::device_start( void ) +{ + m_vblank_handler.resolve_safe(); + + if( m_type == CXD8538Q ) + { + psx_gpu_init( 1 ); + } + else + { + psx_gpu_init( 2 ); + } +} + +void psxgpu_device::device_reset( void ) +{ + gpu_reset(); +} + +cxd8514q_device::cxd8514q_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : psxgpu_device(mconfig, CXD8514Q, "CXD8514Q GPU", tag, owner, clock, "cxd8514q", __FILE__) +{ +} + +cxd8538q_device::cxd8538q_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : psxgpu_device(mconfig, CXD8538Q, "CXD8538Q GPU", tag, owner, clock, "cxd8538q", __FILE__) +{ +} + +cxd8561q_device::cxd8561q_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : psxgpu_device(mconfig, CXD8561Q, "CXD8561Q GPU", tag, owner, clock, "cxd8561q", __FILE__) +{ +} + +cxd8561bq_device::cxd8561bq_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : psxgpu_device(mconfig, CXD8561BQ, "CXD8561BQ", tag, owner, clock, "cxd8561bq", __FILE__) +{ +} + +cxd8561cq_device::cxd8561cq_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : psxgpu_device(mconfig, CXD8561CQ, "CXD8561CQ GPU", tag, owner, clock, "cxd8561cq", __FILE__) +{ +} + +cxd8654q_device::cxd8654q_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : psxgpu_device(mconfig, CXD8654Q, "CXD8654Q GPU", tag, owner, clock, "cxd8654q", __FILE__) +{ +} + +static const UINT16 m_p_n_nextpointlist4[] = { 1, 3, 0, 2 }; +static const UINT16 m_p_n_prevpointlist4[] = { 2, 0, 3, 1 }; +static const UINT16 m_p_n_nextpointlist4b[] = { 0, 3, 1, 2 }; +static const UINT16 m_p_n_prevpointlist4b[] = { 0, 2, 3, 1 }; +static const UINT16 m_p_n_nextpointlist3[] = { 1, 2, 0 }; +static const UINT16 m_p_n_prevpointlist3[] = { 2, 0, 1 }; + +#define SINT11( x ) ( ( (INT32)( x ) << 21 ) >> 21 ) + +#define COORD_X( a ) ( a.sw.l ) +#define COORD_Y( a ) ( a.sw.h ) +#define SIZE_W( a ) ( a.w.l ) +#define SIZE_H( a ) ( a.w.h ) +#define BGR_C( a ) ( a.b.h3 ) +#define BGR_B( a ) ( a.b.h2 ) +#define BGR_G( a ) ( a.b.h ) +#define BGR_R( a ) ( a.b.l ) +#define TEXTURE_V( a ) ( a.b.h ) +#define TEXTURE_U( a ) ( a.b.l ) + +INLINE void ATTR_PRINTF(3,4) verboselog( running_machine& machine, int n_level, const char *s_fmt, ... ) +{ + if( VERBOSE_LEVEL >= n_level ) + { + va_list v; + char buf[ 32768 ]; + va_start( v, s_fmt ); + vsprintf( buf, s_fmt, v ); + va_end( v ); + logerror( "%s: %s", machine.describe_context(), buf ); + } +} + +#if DEBUG_VIEWER + +void psxgpu_device::DebugMeshInit( void ) +{ + int width = m_screen->width(); + int height = m_screen->height(); + + m_debug.b_mesh = 0; + m_debug.b_texture = 0; + m_debug.n_interleave = -1; + m_debug.b_clear = 1; + m_debug.n_coord = 0; + m_debug.n_skip = 0; + m_debug.mesh = auto_bitmap_ind16_alloc( machine(), width, height ); +} + +void psxgpu_device::DebugMesh( int n_coordx, int n_coordy ) +{ + int n_coord; + int n_colour; + int width = m_screen->width(); + int height = m_screen->height(); + + n_coordx += m_n_displaystartx; + n_coordy += n_displaystarty; + + if( m_debug.b_clear ) + { + m_debug.mesh->fill(0x0000); + m_debug.b_clear = 0; + } + + n_colour = 0x1f; + for( n_coord = 0; n_coord < m_debug.n_coord; n_coord++ ) + { + if( n_coordx != m_debug.n_coordx[ n_coord ] || + n_coordy != m_debug.n_coordy[ n_coord ] ) + { + break; + } + } + if( n_coord == m_debug.n_coord && m_debug.n_coord > 1 ) + { + n_colour = 0xffff; + } + for( n_coord = 0; n_coord < m_debug.n_coord; n_coord++ ) + { + PAIR n_x; + PAIR n_y; + INT32 n_xstart; + INT32 n_ystart; + INT32 n_xend; + INT32 n_yend; + INT32 n_xlen; + INT32 n_ylen; + INT32 n_len; + INT32 n_dx; + INT32 n_dy; + + n_xstart = m_debug.n_coordx[ n_coord ]; + n_xend = n_coordx; + if( n_xend > n_xstart ) + { + n_xlen = n_xend - n_xstart; + } + else + { + n_xlen = n_xstart - n_xend; + } + + n_ystart = m_debug.n_coordy[ n_coord ]; + n_yend = n_coordy; + if( n_yend > n_ystart ) + { + n_ylen = n_yend - n_ystart; + } + else + { + n_ylen = n_ystart - n_yend; + } + + if( n_xlen > n_ylen ) + { + n_len = n_xlen; + } + else + { + n_len = n_ylen; + } + + n_x.sw.h = n_xstart; n_x.sw.l = 0; + n_y.sw.h = n_ystart; n_y.sw.l = 0; + + if( n_len == 0 ) + { + n_len = 1; + } + + n_dx = (INT32)( ( n_xend << 16 ) - n_x.d ) / n_len; + n_dy = (INT32)( ( n_yend << 16 ) - n_y.d ) / n_len; + while( n_len > 0 ) + { + if( (INT16)n_x.w.h >= 0 && + (INT16)n_y.w.h >= 0 && + (INT16)n_x.w.h <= width - 1 && + (INT16)n_y.w.h <= height - 1 ) + { + if( m_debug.mesh->pix16(n_y.w.h, n_x.w.h) != 0xffff ) + m_debug.mesh->pix16(n_y.w.h, n_x.w.h) = n_colour; + } + n_x.d += n_dx; + n_y.d += n_dy; + n_len--; + } + } + + if( m_debug.n_coord < DEBUG_COORDS ) + { + m_debug.n_coordx[ m_debug.n_coord ] = n_coordx; + m_debug.n_coordy[ m_debug.n_coord ] = n_coordy; + m_debug.n_coord++; + } +} + +void psxgpu_device::DebugMeshEnd( void ) +{ + m_debug.n_coord = 0; +} + +void psxgpu_device::DebugCheckKeys( void ) +{ + if( machine().input().code_pressed_once( KEYCODE_M ) ) + { + m_debug.b_mesh = !m_debug.b_mesh; + updatevisiblearea(); + } + + if( machine().input().code_pressed_once( KEYCODE_V ) ) + { + m_debug.b_texture = !m_debug.b_texture; + updatevisiblearea(); + } + + if( machine().input().code_pressed_once( KEYCODE_I ) ) + { + if( m_debug.b_texture ) + { + m_debug.n_interleave++; + + if( m_debug.n_interleave == 2 ) + m_debug.n_interleave = -1; + + if( m_debug.n_interleave == -1 ) + popmessage( "interleave off" ); + else if( m_debug.n_interleave == 0 ) + popmessage( "4 bit interleave" ); + else if( m_debug.n_interleave == 1 ) + popmessage( "8 bit interleave" ); + } + else + { + m_debug.n_skip++; + + if( m_debug.n_skip > 15 ) + m_debug.n_skip = 0; + + popmessage( "debug skip %d", m_debug.n_skip ); + } + } + +#if 0 + if( machine().input().code_pressed_once( KEYCODE_D ) ) + { + FILE *f; + int n_x; + f = fopen( "dump.txt", "w" ); + for( n_y = 256; n_y < 512; n_y++ ) + for( n_x = 640; n_x < 1024; n_x++ ) + fprintf( f, "%04u,%04u = %04x\n", n_y, n_x, p_p_vram[ n_y ][ n_x ] ); + fclose( f ); + } + if( machine().input().code_pressed_once( KEYCODE_S ) ) + { + FILE *f; + popmessage( "saving..." ); + f = fopen( "VRAM.BIN", "wb" ); + for( n_y = 0; n_y < 1024; n_y++ ) + fwrite( p_p_vram[ n_y ], 1024 * 2, 1, f ); + fclose( f ); + } + if( machine().input().code_pressed_once( KEYCODE_L ) ) + { + FILE *f; + popmessage( "loading..." ); + f = fopen( "VRAM.BIN", "rb" ); + for( n_y = 0; n_y < 1024; n_y++ ) + fread( p_p_vram[ n_y ], 1024 * 2, 1, f ); + fclose( f ); + } +#endif +} + +int psxgpu_device::DebugMeshDisplay( bitmap_ind16 &bitmap, const rectangle &cliprect ) +{ + if( m_debug.b_mesh ) + { + copybitmap( bitmap, *m_debug.mesh, 0, 0, 0, 0, cliprect ); + } + m_debug.b_clear = 1; + return m_debug.b_mesh; +} + +int psxgpu_device::DebugTextureDisplay( bitmap_ind16 &bitmap ) +{ + UINT32 n_y; + + if( m_debug.b_texture ) + { + int width = m_screen->width(); + int height = m_screen->height(); + + for( n_y = 0; n_y < height; n_y++ ) + { + int n_x; + int n_xi; + int n_yi; + UINT16 p_n_interleave[ 1024 ]; + + for( n_x = 0; n_x < width; n_x++ ) + { + if( m_debug.n_interleave == 0 ) + { + n_xi = ( n_x & ~0x3c ) + ( ( n_y << 2 ) & 0x3c ); + n_yi = ( n_y & ~0xf ) + ( ( n_x >> 2 ) & 0xf ); + } + else if( m_debug.n_interleave == 1 ) + { + n_xi = ( n_x & ~0x78 ) + ( ( n_x << 3 ) & 0x40 ) + ( ( n_y << 3 ) & 0x38 ); + n_yi = ( n_y & ~0x7 ) + ( ( n_x >> 4 ) & 0x7 ); + } + else + { + n_xi = n_x; + n_yi = n_y; + } + p_n_interleave[ n_x ] = p_p_vram[ n_yi ][ n_xi ]; + } + draw_scanline16( bitmap, 0, n_y, width, p_n_interleave, m_screen->palette()->pens() ); + } + } + return m_debug.b_texture; +} + +#endif + +void psxgpu_device::updatevisiblearea() +{ + rectangle visarea; + float refresh; + + if( ( n_gpustatus & ( 1 << 0x14 ) ) != 0 ) + { + /* pal */ + refresh = 50; + switch( ( n_gpustatus >> 0x13 ) & 1 ) + { + case 0: + n_screenheight = 256; + break; + case 1: + n_screenheight = 512; + break; + } + } + else + { + /* ntsc */ + refresh = 60; + switch( ( n_gpustatus >> 0x13 ) & 1 ) + { + case 0: + n_screenheight = 240; + break; + case 1: + n_screenheight = 480; + break; + } + } + switch( ( n_gpustatus >> 0x11 ) & 3 ) + { + case 0: + switch( ( n_gpustatus >> 0x10 ) & 1 ) + { + case 0: + n_screenwidth = 256; + break; + case 1: + n_screenwidth = 368; + break; + } + break; + case 1: + switch( ( n_gpustatus >> 0x10 ) & 1 ) + { + case 0: + n_screenwidth = 320; + break; + case 1: + n_screenwidth = 384; + break; + } + break; + case 2: + n_screenwidth = 512; + break; + case 3: + n_screenwidth = 640; + break; + } + +#if DEBUG_VIEWER + if( m_debug.b_mesh || m_debug.b_texture ) + { + n_screenheight = 1024; + n_screenwidth = 1024; + } +#endif + + visarea.set(0, n_screenwidth - 1, 0, n_screenheight - 1); + machine().first_screen()->configure(n_screenwidth, n_screenheight, visarea, HZ_TO_ATTOSECONDS(refresh)); +} + +void psxgpu_device::psx_gpu_init( int n_gputype ) +{ + int n_line; + int n_level; + int n_level2; + int n_shade; + int n_shaded; + int width = 1024; + int height = ( vramSize / width ) / sizeof( UINT16 ); + + m_n_gputype = n_gputype; + +#if DEBUG_VIEWER + DebugMeshInit(); +#endif + + n_gpustatus = 0x14802000; + n_gpuinfo = 0; + n_gpu_buffer_offset = 0; + n_lightgun_x = 0; + n_lightgun_y = 0; + b_reverseflag = 0; + + p_vram = auto_alloc_array_clear( machine(), UINT16, width * height ); + + for( n_line = 0; n_line < 1024; n_line++ ) + { + p_p_vram[ n_line ] = &p_vram[ ( n_line % height ) * width ]; + } + + for( n_level = 0; n_level < MAX_LEVEL; n_level++ ) + { + for( n_shade = 0; n_shade < MAX_SHADE; n_shade++ ) + { + /* shaded */ + n_shaded = ( n_level * n_shade ) / MID_SHADE; + if( n_shaded > MAX_LEVEL - 1 ) + { + n_shaded = MAX_LEVEL - 1; + } + p_n_redshade[ ( n_level * MAX_SHADE ) | n_shade ] = n_shaded; + p_n_greenshade[ ( n_level * MAX_SHADE ) | n_shade ] = n_shaded << 5; + p_n_blueshade[ ( n_level * MAX_SHADE ) | n_shade ] = n_shaded << 10; + + /* 1/4 x transparency */ + n_shaded = ( n_level * n_shade ) / MID_SHADE; + n_shaded >>= 2; + if( n_shaded > MAX_LEVEL - 1 ) + { + n_shaded = MAX_LEVEL - 1; + } + p_n_f025[ ( n_level * MAX_SHADE ) | n_shade ] = n_shaded; + + /* 1/2 x transparency */ + n_shaded = ( n_level * n_shade ) / MID_SHADE; + n_shaded >>= 1; + if( n_shaded > MAX_LEVEL - 1 ) + { + n_shaded = MAX_LEVEL - 1; + } + p_n_f05[ ( n_level * MAX_SHADE ) | n_shade ] = n_shaded; + + /* 1 x transparency */ + n_shaded = ( n_level * n_shade ) / MID_SHADE; + if( n_shaded > MAX_LEVEL - 1 ) + { + n_shaded = MAX_LEVEL - 1; + } + p_n_f1[ ( n_level * MAX_SHADE ) | n_shade ] = n_shaded; + } + } + + for( n_level = 0; n_level < 0x10000; n_level++ ) + { + p_n_redlevel[ n_level ] = ( n_level & ( MAX_LEVEL - 1 ) ) * MAX_SHADE; + p_n_greenlevel[ n_level ] = ( ( n_level >> 5 ) & ( MAX_LEVEL - 1 ) ) * MAX_SHADE; + p_n_bluelevel[ n_level ] = ( ( n_level >> 10 ) & ( MAX_LEVEL - 1 ) ) * MAX_SHADE; + + /* 0.5 * background */ + p_n_redb05[ n_level ] = ( ( n_level & ( MAX_LEVEL - 1 ) ) / 2 ) * MAX_LEVEL; + p_n_greenb05[ n_level ] = ( ( ( n_level >> 5 ) & ( MAX_LEVEL - 1 ) ) / 2 ) * MAX_LEVEL; + p_n_blueb05[ n_level ] = ( ( ( n_level >> 10 ) & ( MAX_LEVEL - 1 ) ) / 2 ) * MAX_LEVEL; + + /* 1 * background */ + p_n_redb1[ n_level ] = ( n_level & ( MAX_LEVEL - 1 ) ) * MAX_LEVEL; + p_n_greenb1[ n_level ] = ( ( n_level >> 5 ) & ( MAX_LEVEL - 1 ) ) * MAX_LEVEL; + p_n_blueb1[ n_level ] = ( ( n_level >> 10 ) & ( MAX_LEVEL - 1 ) ) * MAX_LEVEL; + + /* 24bit to 15 bit conversion */ + p_n_g0r0[ n_level ] = ( ( ( n_level >> 11 ) & ( MAX_LEVEL - 1 ) ) << 5 ) | ( ( ( n_level >> 3 ) & ( MAX_LEVEL - 1 ) ) << 0 ); + p_n_b0[ n_level ] = ( ( n_level >> 3 ) & ( MAX_LEVEL - 1 ) ) << 10; + p_n_r1[ n_level ] = ( ( n_level >> 11 ) & ( MAX_LEVEL - 1 ) ) << 0; + p_n_b1g1[ n_level ] = ( ( ( n_level >> 11 ) & ( MAX_LEVEL - 1 ) ) << 10 ) | ( ( ( n_level >> 3 ) & ( MAX_LEVEL - 1 ) ) << 5 ); + } + + for( n_level = 0; n_level < MAX_LEVEL; n_level++ ) + { + for( n_level2 = 0; n_level2 < MAX_LEVEL; n_level2++ ) + { + /* add transparency */ + n_shaded = ( n_level + n_level2 ); + if( n_shaded > MAX_LEVEL - 1 ) + { + n_shaded = MAX_LEVEL - 1; + } + p_n_redaddtrans[ ( n_level * MAX_LEVEL ) | n_level2 ] = n_shaded; + p_n_greenaddtrans[ ( n_level * MAX_LEVEL ) | n_level2 ] = n_shaded << 5; + p_n_blueaddtrans[ ( n_level * MAX_LEVEL ) | n_level2 ] = n_shaded << 10; + + /* sub transparency */ + n_shaded = ( n_level - n_level2 ); + if( n_shaded < 0 ) + { + n_shaded = 0; + } + p_n_redsubtrans[ ( n_level * MAX_LEVEL ) | n_level2 ] = n_shaded; + p_n_greensubtrans[ ( n_level * MAX_LEVEL ) | n_level2 ] = n_shaded << 5; + p_n_bluesubtrans[ ( n_level * MAX_LEVEL ) | n_level2 ] = n_shaded << 10; + } + } + + // icky!!! + machine().save().save_memory( this, "globals", NULL, 0, "m_packet", (UINT8 *)&m_packet, 1, sizeof( m_packet ) ); + + save_pointer(NAME(p_vram), width * height ); + save_item(NAME(n_gpu_buffer_offset)); + save_item(NAME(n_vramx)); + save_item(NAME(n_vramy)); + save_item(NAME(n_twy)); + save_item(NAME(n_twx)); + save_item(NAME(n_tww)); + save_item(NAME(n_drawarea_x1)); + save_item(NAME(n_drawarea_y1)); + save_item(NAME(n_drawarea_x2)); + save_item(NAME(n_drawarea_y2)); + save_item(NAME(n_horiz_disstart)); + save_item(NAME(n_horiz_disend)); + save_item(NAME(n_vert_disstart)); + save_item(NAME(n_vert_disend)); + save_item(NAME(b_reverseflag)); + save_item(NAME(n_drawoffset_x)); + save_item(NAME(n_drawoffset_y)); + save_item(NAME(m_n_displaystartx)); + save_item(NAME(n_displaystarty)); + save_item(NAME(n_gpustatus)); + save_item(NAME(n_gpuinfo)); + save_item(NAME(n_lightgun_x)); + save_item(NAME(n_lightgun_y)); + save_item(NAME(m_n_tx)); + save_item(NAME(m_n_ty)); + save_item(NAME(n_abr)); + save_item(NAME(n_tp)); + save_item(NAME(n_ix)); + save_item(NAME(n_iy)); + save_item(NAME(n_ti)); + + machine().save().register_postload( save_prepost_delegate( FUNC( psxgpu_device::updatevisiblearea ), this ) ); +} + +UINT32 psxgpu_device::update_screen(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) +{ + UINT32 n_x; + UINT32 n_y; + int n_top; + int n_line; + int n_lines; + int n_left; + int n_column; + int n_columns; + int n_displaystartx; + int n_overscantop; + int n_overscanleft; + +#if DEBUG_VIEWER + if( DebugMeshDisplay( bitmap, cliprect ) ) + { + return 0; + } + if( DebugTextureDisplay( bitmap ) ) + { + return 0; + } +#endif + + if( ( n_gpustatus & ( 1 << 0x17 ) ) != 0 ) + { + /* todo: only draw to necessary area */ + bitmap.fill(0, cliprect); + } + else + { + if( b_reverseflag ) + { + n_displaystartx = ( 1023 - m_n_displaystartx ); + /* todo: make this flip the screen, in the meantime.. */ + n_displaystartx -= ( n_screenwidth - 1 ); + } + else + { + n_displaystartx = m_n_displaystartx; + } + + if( ( n_gpustatus & ( 1 << 0x14 ) ) != 0 ) + { + /* pal */ + n_overscantop = 0x23; + n_overscanleft = 0x27e; + } + else + { + /* ntsc */ + n_overscantop = 0x10; + n_overscanleft = 0x260; + } + + n_top = (INT32)n_vert_disstart - n_overscantop; + n_lines = (INT32)n_vert_disend - (INT32)n_vert_disstart; + if( n_top < 0 ) + { + n_y = -n_top; + n_lines += n_top; + } + else + { + n_y = 0; + + /* draw top border */ + rectangle clip(cliprect.left(), cliprect.right(), cliprect.top(), n_top); + bitmap.fill(0, clip); + } + if( ( n_gpustatus & ( 1 << 0x16 ) ) != 0 ) + { + /* interlaced */ + n_lines *= 2; + } + if( n_lines > n_screenheight - ( n_y + n_top ) ) + { + n_lines = n_screenheight - ( n_y + n_top ); + } + else + { + /* draw bottom border */ + rectangle clip(cliprect.left(), cliprect.right(), n_y + n_top + n_lines, cliprect.bottom()); + bitmap.fill(0, clip); + } + + n_left = ( ( (INT32)n_horiz_disstart - n_overscanleft ) * (INT32)n_screenwidth ) / 2560; + n_columns = ( ( ( (INT32)n_horiz_disend - n_horiz_disstart ) * (INT32)n_screenwidth ) / 2560 ); + if( n_left < 0 ) + { + n_x = -n_left; + n_columns += n_left; + } + else + { + n_x = 0; + + /* draw left border */ + rectangle clip(cliprect.left(), n_x + n_left, cliprect.top(), cliprect.bottom()); + bitmap.fill(0, clip); + } + if( n_columns > n_screenwidth - ( n_x + n_left ) ) + { + n_columns = n_screenwidth - ( n_x + n_left ); + } + else + { + /* draw right border */ + rectangle clip(n_x + n_left + n_columns, cliprect.right(), cliprect.top(), cliprect.bottom()); + bitmap.fill(0, clip); + } + + if( ( n_gpustatus & ( 1 << 0x15 ) ) != 0 ) + { + /* 24bit */ + n_line = n_lines; + while( n_line > 0 ) + { + UINT16 *p_n_src = p_p_vram[ n_y + n_displaystarty ] + ((n_x + n_displaystartx) * 3); + UINT16 *p_n_dest = &bitmap.pix16(n_y + n_top, n_x + n_left); + + n_column = n_columns; + while( n_column > 0 ) + { + UINT32 n_g0r0 = *( p_n_src++ ); + UINT32 n_r1b0 = *( p_n_src++ ); + UINT32 n_b1g1 = *( p_n_src++ ); + + *( p_n_dest++ ) = p_n_g0r0[ n_g0r0 ] | p_n_b0[ n_r1b0 ]; + n_column--; + if( n_column > 0 ) + { + *( p_n_dest++ ) = p_n_r1[ n_r1b0 ] | p_n_b1g1[ n_b1g1 ]; + n_column--; + } + } + n_y++; + n_line--; + } + } + else + { + /* 15bit */ + n_line = n_lines; + while( n_line > 0 ) + { + draw_scanline16( bitmap, n_x + n_left, n_y + n_top, n_columns, p_p_vram[ ( n_y + n_displaystarty ) & 1023 ] + n_x + n_displaystartx, NULL ); + n_y++; + n_line--; + } + } + } + return 0; +} + +#define WRITE_PIXEL( p ) *( p_vram ) = p + +/* +type 1 +f e| d| c b| a 9| 8 7| 6 5| 4| 3 2 1 0 + |ti| | tp| abr| ty| | tx +*/ + +/* +type 2 +f e| d c| b| a 9| 8 7| 6 5| 4| 3 2 1 0 + |iy|ix|ty| | tp| abr|ty| tx +*/ + +void psxgpu_device::decode_tpage( UINT32 tpage ) +{ + if( m_n_gputype == 2 ) + { + n_gpustatus = ( n_gpustatus & 0xfffff800 ) | ( tpage & 0x7ff ); + + m_n_tx = ( tpage & 0x0f ) << 6; + m_n_ty = ( ( tpage & 0x10 ) << 4 ) | ( ( tpage & 0x800 ) >> 2 ); + n_abr = ( tpage & 0x60 ) >> 5; + n_tp = ( tpage & 0x180 ) >> 7; + n_ix = ( tpage & 0x1000 ) >> 12; + n_iy = ( tpage & 0x2000 ) >> 13; + n_ti = 0; + if( ( tpage & ~0x39ff ) != 0 ) + { + verboselog( machine(), 1, "not handled: draw mode %08x\n", tpage & ~0x39ff ); + } + if( n_tp == 3 ) + { + verboselog( machine(), 0, "not handled: tp == 3\n" ); + } + } + else + { + n_gpustatus = ( n_gpustatus & 0xffffe000 ) | ( tpage & 0x1fff ); + + m_n_tx = ( tpage & 0x0f ) << 6; + m_n_ty = ( ( tpage & 0x60 ) << 3 ); + n_abr = ( tpage & 0x180 ) >> 7; + n_tp = ( tpage & 0x600 ) >> 9; + n_ti = ( tpage & 0x2000 ) >> 13; + n_ix = 0; + n_iy = 0; + if( ( tpage & ~0x27ef ) != 0 ) + { + verboselog( machine(), 1, "not handled: draw mode %08x\n", tpage & ~0x27ef ); + } + if( n_tp == 3 ) + { + verboselog( machine(), 0, "not handled: tp == 3\n" ); + } + else if( n_tp == 2 && n_ti != 0 ) + { + verboselog( machine(), 0, "not handled: interleaved 15 bit texture\n" ); + } + } +} + +#define SPRITESETUP \ + if( n_iy != 0 ) \ + { \ + n_dv = -1; \ + } \ + else \ + { \ + n_dv = 1; \ + } \ + if( n_ix != 0 ) \ + { \ + n_du = -1; \ + } \ + else \ + { \ + n_du = 1; \ + } + +#define TRANSPARENCYSETUP \ + p_n_f = p_n_f1; \ + p_n_redb = p_n_redb1; \ + p_n_greenb = p_n_greenb1; \ + p_n_blueb = p_n_blueb1; \ + p_n_redtrans = p_n_redaddtrans; \ + p_n_greentrans = p_n_greenaddtrans; \ + p_n_bluetrans = p_n_blueaddtrans; \ + \ + switch( n_cmd & 0x02 ) \ + { \ + case 0x02: \ + switch( n_abr ) \ + { \ + case 0x00: \ + p_n_f = p_n_f05; \ + p_n_redb = p_n_redb05; \ + p_n_greenb = p_n_greenb05; \ + p_n_blueb = p_n_blueb05; \ + p_n_redtrans = p_n_redaddtrans; \ + p_n_greentrans = p_n_greenaddtrans; \ + p_n_bluetrans = p_n_blueaddtrans; \ + verboselog( machine(), 2, "Transparency Mode: 0.5*B + 0.5*F\n" ); \ + break; \ + case 0x01: \ + p_n_f = p_n_f1; \ + p_n_redb = p_n_redb1; \ + p_n_greenb = p_n_greenb1; \ + p_n_blueb = p_n_blueb1; \ + p_n_redtrans = p_n_redaddtrans; \ + p_n_greentrans = p_n_greenaddtrans; \ + p_n_bluetrans = p_n_blueaddtrans; \ + verboselog( machine(), 2, "Transparency Mode: 1.0*B + 1.0*F\n" ); \ + break; \ + case 0x02: \ + p_n_f = p_n_f1; \ + p_n_redb = p_n_redb1; \ + p_n_greenb = p_n_greenb1; \ + p_n_blueb = p_n_blueb1; \ + p_n_redtrans = p_n_redsubtrans; \ + p_n_greentrans = p_n_greensubtrans; \ + p_n_bluetrans = p_n_bluesubtrans; \ + verboselog( machine(), 2, "Transparency Mode: 1.0*B - 1.0*F\n" ); \ + break; \ + case 0x03: \ + p_n_f = p_n_f025; \ + p_n_redb = p_n_redb1; \ + p_n_greenb = p_n_greenb1; \ + p_n_blueb = p_n_blueb1; \ + p_n_redtrans = p_n_redaddtrans; \ + p_n_greentrans = p_n_greenaddtrans; \ + p_n_bluetrans = p_n_blueaddtrans; \ + verboselog( machine(), 2, "Transparency Mode: 1.0*B + 0.25*F\n" ); \ + break; \ + } \ + break; \ + } + +#define SOLIDSETUP \ + TRANSPARENCYSETUP + +#define TEXTURESETUP \ + n_tx = m_n_tx; \ + n_ty = m_n_ty; \ + p_clut = p_p_vram[ n_cluty ] + n_clutx; \ + switch( n_tp ) \ + { \ + case 0: \ + n_tx += n_twx >> 2; \ + n_ty += n_twy; \ + break; \ + case 1: \ + n_tx += n_twx >> 1; \ + n_ty += n_twy; \ + break; \ + case 2: \ + n_tx += n_twx >> 0; \ + n_ty += n_twy; \ + break; \ + } \ + TRANSPARENCYSETUP + +#define FLATPOLYGONUPDATE +#define FLATRECTANGEUPDATE +#define GOURAUDPOLYGONUPDATE \ + n_r.d += n_dr; \ + n_g.d += n_dg; \ + n_b.d += n_db; + +#define SOLIDFILL( PIXELUPDATE ) \ + if( n_distance > ( (INT32)n_drawarea_x2 - drawx ) + 1 ) \ + { \ + n_distance = ( n_drawarea_x2 - drawx ) + 1; \ + } \ + p_vram = p_p_vram[ drawy ] + drawx; \ + \ + switch( n_cmd & 0x02 ) \ + { \ + case 0x00: \ + /* transparency off */ \ + while( n_distance > 0 ) \ + { \ + WRITE_PIXEL( \ + p_n_redshade[ MID_LEVEL | n_r.w.h ] | \ + p_n_greenshade[ MID_LEVEL | n_g.w.h ] | \ + p_n_blueshade[ MID_LEVEL | n_b.w.h ] ); \ + p_vram++; \ + PIXELUPDATE \ + n_distance--; \ + } \ + break; \ + case 0x02: \ + /* transparency on */ \ + while( n_distance > 0 ) \ + { \ + WRITE_PIXEL( \ + p_n_redtrans[ p_n_f[ MID_LEVEL | n_r.w.h ] | p_n_redb[ *( p_vram ) ] ] | \ + p_n_greentrans[ p_n_f[ MID_LEVEL | n_g.w.h ] | p_n_greenb[ *( p_vram ) ] ] | \ + p_n_bluetrans[ p_n_f[ MID_LEVEL | n_b.w.h ] | p_n_blueb[ *( p_vram ) ] ] ); \ + p_vram++; \ + PIXELUPDATE \ + n_distance--; \ + } \ + break; \ + } + +#define FLATTEXTUREDPOLYGONUPDATE \ + n_u.d += n_du; \ + n_v.d += n_dv; + +#define GOURAUDTEXTUREDPOLYGONUPDATE \ + n_r.d += n_dr; \ + n_g.d += n_dg; \ + n_b.d += n_db; \ + n_u.d += n_du; \ + n_v.d += n_dv; + +#define FLATTEXTUREDRECTANGLEUPDATE \ + n_u += n_du; + +#define TEXTURE_LOOP \ + while( n_distance > 0 ) \ + { +#define TEXTURE_ENDLOOP \ + } + +#define TEXTURE4BIT( TXV, TXU ) \ + TEXTURE_LOOP \ + n_bgr = p_clut[ ( *( p_p_vram[ n_ty + TXV ] + n_tx + ( TXU >> 2 ) ) >> ( ( TXU & 0x03 ) << 2 ) ) & 0x0f ]; + +#define TEXTURE8BIT( TXV, TXU ) \ + TEXTURE_LOOP \ + n_bgr = p_clut[ ( *( p_p_vram[ n_ty + TXV ] + n_tx + ( TXU >> 1 ) ) >> ( ( TXU & 0x01 ) << 3 ) ) & 0xff ]; + +#define TEXTURE15BIT( TXV, TXU ) \ + TEXTURE_LOOP \ + n_bgr = *( p_p_vram[ n_ty + TXV ] + n_tx + TXU ); + +#define TEXTUREWINDOW4BIT( TXV, TXU ) TEXTURE4BIT( ( TXV & n_twh ), ( TXU & n_tww ) ) +#define TEXTUREWINDOW8BIT( TXV, TXU ) TEXTURE8BIT( ( TXV & n_twh ), ( TXU & n_tww ) ) +#define TEXTUREWINDOW15BIT( TXV, TXU ) TEXTURE15BIT( ( TXV & n_twh ), ( TXU & n_tww ) ) + +#define TEXTUREINTERLEAVED4BIT( TXV, TXU ) \ + TEXTURE_LOOP \ + int n_xi = ( ( TXU >> 2 ) & ~0x3c ) + ( ( TXV << 2 ) & 0x3c ); \ + int n_yi = ( TXV & ~0xf ) + ( ( TXU >> 4 ) & 0xf ); \ + n_bgr = p_clut[ ( *( p_p_vram[ n_ty + n_yi ] + n_tx + n_xi ) >> ( ( TXU & 0x03 ) << 2 ) ) & 0x0f ]; + +#define TEXTUREINTERLEAVED8BIT( TXV, TXU ) \ + TEXTURE_LOOP \ + int n_xi = ( ( TXU >> 1 ) & ~0x78 ) + ( ( TXU << 2 ) & 0x40 ) + ( ( TXV << 3 ) & 0x38 ); \ + int n_yi = ( TXV & ~0x7 ) + ( ( TXU >> 5 ) & 0x7 ); \ + n_bgr = p_clut[ ( *( p_p_vram[ n_ty + n_yi ] + n_tx + n_xi ) >> ( ( TXU & 0x01 ) << 3 ) ) & 0xff ]; + +#define TEXTUREINTERLEAVED15BIT( TXV, TXU ) \ + TEXTURE_LOOP \ + int n_xi = TXU; \ + int n_yi = TXV; \ + n_bgr = *( p_p_vram[ n_ty + n_yi ] + n_tx + n_xi ); + +#define TEXTUREWINDOWINTERLEAVED4BIT( TXV, TXU ) TEXTUREINTERLEAVED4BIT( ( TXV & n_twh ), ( TXU & n_tww ) ) +#define TEXTUREWINDOWINTERLEAVED8BIT( TXV, TXU ) TEXTUREINTERLEAVED8BIT( ( TXV & n_twh ), ( TXU & n_tww ) ) +#define TEXTUREWINDOWINTERLEAVED15BIT( TXV, TXU ) TEXTUREINTERLEAVED15BIT( ( TXV & n_twh ), ( TXU & n_tww ) ) + +#define SHADEDPIXEL( PIXELUPDATE ) \ + if( n_bgr != 0 ) \ + { \ + WRITE_PIXEL( \ + p_n_redshade[ p_n_redlevel[ n_bgr ] | n_r.w.h ] | \ + p_n_greenshade[ p_n_greenlevel[ n_bgr ] | n_g.w.h ] | \ + p_n_blueshade[ p_n_bluelevel[ n_bgr ] | n_b.w.h ] ); \ + } \ + p_vram++; \ + PIXELUPDATE \ + n_distance--; \ + TEXTURE_ENDLOOP + +#define TRANSPARENTPIXEL( PIXELUPDATE ) \ + if( n_bgr != 0 ) \ + { \ + if( ( n_bgr & 0x8000 ) != 0 ) \ + { \ + WRITE_PIXEL( \ + p_n_redtrans[ p_n_f[ p_n_redlevel[ n_bgr ] | n_r.w.h ] | p_n_redb[ *( p_vram ) ] ] | \ + p_n_greentrans[ p_n_f[ p_n_greenlevel[ n_bgr ] | n_g.w.h ] | p_n_greenb[ *( p_vram ) ] ] | \ + p_n_bluetrans[ p_n_f[ p_n_bluelevel[ n_bgr ] | n_b.w.h ] | p_n_blueb[ *( p_vram ) ] ] ); \ + } \ + else \ + { \ + WRITE_PIXEL( \ + p_n_redshade[ p_n_redlevel[ n_bgr ] | n_r.w.h ] | \ + p_n_greenshade[ p_n_greenlevel[ n_bgr ] | n_g.w.h ] | \ + p_n_blueshade[ p_n_bluelevel[ n_bgr ] | n_b.w.h ] ); \ + } \ + } \ + p_vram++; \ + PIXELUPDATE \ + n_distance--; \ + TEXTURE_ENDLOOP + +#define TEXTUREFILL( PIXELUPDATE, TXU, TXV ) \ + if( n_distance > ( (INT32)n_drawarea_x2 - drawx ) + 1 ) \ + { \ + n_distance = ( n_drawarea_x2 - drawx ) + 1; \ + } \ + p_vram = p_p_vram[ drawy ] + drawx; \ + \ + if( n_ti != 0 ) \ + { \ + /* interleaved texture */ \ + if( n_twh != 255 || \ + n_tww != 255 || \ + n_twx != 0 || \ + n_twy != 0 ) \ + { \ + /* texture window */ \ + switch( n_cmd & 0x02 ) \ + { \ + case 0x00: \ + /* shading */ \ + switch( n_tp ) \ + { \ + case 0: \ + /* 4 bit clut */ \ + TEXTUREWINDOWINTERLEAVED4BIT( TXV, TXU ) \ + SHADEDPIXEL( PIXELUPDATE ) \ + break; \ + case 1: \ + /* 8 bit clut */ \ + TEXTUREWINDOWINTERLEAVED8BIT( TXV, TXU ) \ + SHADEDPIXEL( PIXELUPDATE ) \ + break; \ + case 2: \ + /* 15 bit */ \ + TEXTUREWINDOWINTERLEAVED15BIT( TXV, TXU ) \ + SHADEDPIXEL( PIXELUPDATE ) \ + break; \ + } \ + break; \ + case 0x02: \ + /* semi transparency */ \ + switch( n_tp ) \ + { \ + case 0: \ + /* 4 bit clut */ \ + TEXTUREWINDOWINTERLEAVED4BIT( TXV, TXU ) \ + TRANSPARENTPIXEL( PIXELUPDATE ) \ + break; \ + case 1: \ + /* 8 bit clut */ \ + TEXTUREWINDOWINTERLEAVED8BIT( TXV, TXU ) \ + TRANSPARENTPIXEL( PIXELUPDATE ) \ + break; \ + case 2: \ + /* 15 bit */ \ + TEXTUREWINDOWINTERLEAVED15BIT( TXV, TXU ) \ + TRANSPARENTPIXEL( PIXELUPDATE ) \ + break; \ + } \ + break; \ + } \ + } \ + else \ + { \ + /* no texture window */ \ + switch( n_cmd & 0x02 ) \ + { \ + case 0x00: \ + /* shading */ \ + switch( n_tp ) \ + { \ + case 0: \ + /* 4 bit clut */ \ + TEXTUREINTERLEAVED4BIT( TXV, TXU ) \ + SHADEDPIXEL( PIXELUPDATE ) \ + break; \ + case 1: \ + /* 8 bit clut */ \ + TEXTUREINTERLEAVED8BIT( TXV, TXU ) \ + SHADEDPIXEL( PIXELUPDATE ) \ + break; \ + case 2: \ + /* 15 bit */ \ + TEXTUREINTERLEAVED15BIT( TXV, TXU ) \ + SHADEDPIXEL( PIXELUPDATE ) \ + break; \ + } \ + break; \ + case 0x02: \ + /* semi transparency */ \ + switch( n_tp ) \ + { \ + case 0: \ + /* 4 bit clut */ \ + TEXTUREINTERLEAVED4BIT( TXV, TXU ) \ + TRANSPARENTPIXEL( PIXELUPDATE ) \ + break; \ + case 1: \ + /* 8 bit clut */ \ + TEXTUREINTERLEAVED8BIT( TXV, TXU ) \ + TRANSPARENTPIXEL( PIXELUPDATE ) \ + break; \ + case 2: \ + /* 15 bit */ \ + TEXTUREINTERLEAVED15BIT( TXV, TXU ) \ + TRANSPARENTPIXEL( PIXELUPDATE ) \ + break; \ + } \ + break; \ + } \ + } \ + } \ + else \ + { \ + /* standard texture */ \ + if( n_twh != 255 || \ + n_tww != 255 || \ + n_twx != 0 || \ + n_twy != 0 ) \ + { \ + /* texture window */ \ + switch( n_cmd & 0x02 ) \ + { \ + case 0x00: \ + /* shading */ \ + switch( n_tp ) \ + { \ + case 0: \ + /* 4 bit clut */ \ + TEXTUREWINDOW4BIT( TXV, TXU ) \ + SHADEDPIXEL( PIXELUPDATE ) \ + break; \ + case 1: \ + /* 8 bit clut */ \ + TEXTUREWINDOW8BIT( TXV, TXU ) \ + SHADEDPIXEL( PIXELUPDATE ) \ + break; \ + case 2: \ + /* 15 bit */ \ + TEXTUREWINDOW15BIT( TXV, TXU ) \ + SHADEDPIXEL( PIXELUPDATE ) \ + break; \ + } \ + break; \ + case 0x02: \ + /* semi transparency */ \ + switch( n_tp ) \ + { \ + case 0: \ + /* 4 bit clut */ \ + TEXTUREWINDOW4BIT( TXV, TXU ) \ + TRANSPARENTPIXEL( PIXELUPDATE ) \ + break; \ + case 1: \ + /* 8 bit clut */ \ + TEXTUREWINDOW8BIT( TXV, TXU ) \ + TRANSPARENTPIXEL( PIXELUPDATE ) \ + break; \ + case 2: \ + /* 15 bit */ \ + TEXTUREWINDOW15BIT( TXV, TXU ) \ + TRANSPARENTPIXEL( PIXELUPDATE ) \ + break; \ + } \ + break; \ + } \ + } \ + else \ + { \ + /* no texture window */ \ + switch( n_cmd & 0x02 ) \ + { \ + case 0x00: \ + /* shading */ \ + switch( n_tp ) \ + { \ + case 0: \ + TEXTURE4BIT( TXV, TXU ) \ + SHADEDPIXEL( PIXELUPDATE ) \ + break; \ + case 1: \ + /* 8 bit clut */ \ + TEXTURE8BIT( TXV, TXU ) \ + SHADEDPIXEL( PIXELUPDATE ) \ + break; \ + case 2: \ + /* 15 bit */ \ + TEXTURE15BIT( TXV, TXU ) \ + SHADEDPIXEL( PIXELUPDATE ) \ + break; \ + } \ + break; \ + case 0x02: \ + /* semi transparency */ \ + switch( n_tp ) \ + { \ + case 0: \ + /* 4 bit clut */ \ + TEXTURE4BIT( TXV, TXU ) \ + TRANSPARENTPIXEL( PIXELUPDATE ) \ + break; \ + case 1: \ + /* 8 bit clut */ \ + TEXTURE8BIT( TXV, TXU ) \ + TRANSPARENTPIXEL( PIXELUPDATE ) \ + break; \ + case 2: \ + /* 15 bit */ \ + TEXTURE15BIT( TXV, TXU ) \ + TRANSPARENTPIXEL( PIXELUPDATE ) \ + break; \ + } \ + break; \ + } \ + } \ + } + +#define GET_COORD( a ) \ + a.sw.l = SINT11( COORD_X( a ) ); \ + a.sw.h = SINT11( COORD_Y( a ) ); + +INLINE int CullVertex( int a, int b ) +{ + int d = a - b; + if( d < -1023 || d > 1023 ) + { + return 1; + } + + return 0; +} + +#define CULLPOINT( PacketType, p1, p2 ) \ +( \ + CullVertex( COORD_Y( m_packet.PacketType.vertex[ p1 ].n_coord ), COORD_Y( m_packet.PacketType.vertex[ p2 ].n_coord ) ) || \ + CullVertex( COORD_X( m_packet.PacketType.vertex[ p1 ].n_coord ), COORD_X( m_packet.PacketType.vertex[ p2 ].n_coord ) ) \ +) + +#define CULLTRIANGLE( PacketType, start ) \ +( \ + CULLPOINT( PacketType, start, start + 1 ) || CULLPOINT( PacketType, start + 1, start + 2 ) || CULLPOINT( PacketType, start + 2, start ) \ +) + +#define FINDTOPLEFT( PacketType ) \ + for( n_point = 0; n_point < n_points; n_point++ ) \ + { \ + GET_COORD( m_packet.PacketType.vertex[ n_point ].n_coord ); \ + } \ + \ + n_leftpoint = 0; \ + if( n_points == 4 ) \ + { \ + if( CULLTRIANGLE( PacketType, 0 ) ) \ + { \ + if( CULLTRIANGLE( PacketType, 1 ) ) \ + { \ + return; \ + } \ + \ + p_n_rightpointlist = m_p_n_nextpointlist4b; \ + p_n_leftpointlist = m_p_n_prevpointlist4b; \ + n_leftpoint++; \ + } \ + else if( CULLTRIANGLE( PacketType, 1 ) ) \ + { \ + p_n_rightpointlist = m_p_n_nextpointlist3; \ + p_n_leftpointlist = m_p_n_prevpointlist3; \ + n_points--; \ + } \ + else \ + { \ + p_n_rightpointlist = m_p_n_nextpointlist4; \ + p_n_leftpointlist = m_p_n_prevpointlist4; \ + } \ + } \ + else if( CULLTRIANGLE( PacketType, 0 ) ) \ + { \ + return; \ + } \ + else \ + { \ + p_n_rightpointlist = m_p_n_nextpointlist3; \ + p_n_leftpointlist = m_p_n_prevpointlist3; \ + } \ + \ + for( n_point = n_leftpoint + 1; n_point < n_points; n_point++ ) \ + { \ + if( COORD_Y( m_packet.PacketType.vertex[ n_point ].n_coord ) < COORD_Y( m_packet.PacketType.vertex[ n_leftpoint ].n_coord ) || \ + ( COORD_Y( m_packet.PacketType.vertex[ n_point ].n_coord ) == COORD_Y( m_packet.PacketType.vertex[ n_leftpoint ].n_coord ) && \ + COORD_X( m_packet.PacketType.vertex[ n_point ].n_coord ) < COORD_X( m_packet.PacketType.vertex[ n_leftpoint ].n_coord ) ) ) \ + { \ + n_leftpoint = n_point; \ + } \ + } \ + n_rightpoint = n_leftpoint; + +void psxgpu_device::FlatPolygon( int n_points ) +{ + INT16 n_y; + INT16 n_x; + + UINT16 *p_n_f; + UINT16 *p_n_redb; + UINT16 *p_n_greenb; + UINT16 *p_n_blueb; + UINT16 *p_n_redtrans; + UINT16 *p_n_greentrans; + UINT16 *p_n_bluetrans; + + PAIR n_r; + PAIR n_g; + PAIR n_b; + PAIR n_cx1; + PAIR n_cx2; + INT32 n_dx1; + INT32 n_dx2; + + UINT8 n_cmd; + + INT32 n_distance; + + UINT16 n_point; + UINT16 n_rightpoint; + UINT16 n_leftpoint; + const UINT16 *p_n_rightpointlist; + const UINT16 *p_n_leftpointlist; + + UINT16 *p_vram; + +#if DEBUG_VIEWER + if( m_debug.n_skip == 1 ) + { + return; + } + for( n_point = 0; n_point < n_points; n_point++ ) + { + DebugMesh( SINT11( COORD_X( m_packet.FlatPolygon.vertex[ n_point ].n_coord ) ) + n_drawoffset_x, SINT11( COORD_Y( m_packet.FlatPolygon.vertex[ n_point ].n_coord ) ) + n_drawoffset_y ); + } + DebugMeshEnd(); +#endif + + n_cmd = BGR_C( m_packet.FlatPolygon.n_bgr ); + + n_cx1.d = 0; + n_cx2.d = 0; + + SOLIDSETUP + + n_r.w.h = BGR_R( m_packet.FlatPolygon.n_bgr ); n_r.w.l = 0; + n_g.w.h = BGR_G( m_packet.FlatPolygon.n_bgr ); n_g.w.l = 0; + n_b.w.h = BGR_B( m_packet.FlatPolygon.n_bgr ); n_b.w.l = 0; + + FINDTOPLEFT( FlatPolygon ) + + n_dx1 = 0; + n_dx2 = 0; + + n_y = COORD_Y( m_packet.FlatPolygon.vertex[ n_rightpoint ].n_coord ); + + for( ;; ) + { + if( n_y == COORD_Y( m_packet.FlatPolygon.vertex[ n_leftpoint ].n_coord ) ) + { + while( n_y == COORD_Y( m_packet.FlatPolygon.vertex[ p_n_leftpointlist[ n_leftpoint ] ].n_coord ) ) + { + n_leftpoint = p_n_leftpointlist[ n_leftpoint ]; + if( n_leftpoint == n_rightpoint ) + { + break; + } + } + n_cx1.sw.h = COORD_X( m_packet.FlatPolygon.vertex[ n_leftpoint ].n_coord ); n_cx1.sw.l = 0; + n_leftpoint = p_n_leftpointlist[ n_leftpoint ]; + n_distance = COORD_Y( m_packet.FlatPolygon.vertex[ n_leftpoint ].n_coord ) - n_y; + if( n_distance < 1 ) + { + break; + } + n_dx1 = (INT32)( ( COORD_X( m_packet.FlatPolygon.vertex[ n_leftpoint ].n_coord ) << 16 ) - n_cx1.d ) / n_distance; + } + if( n_y == COORD_Y( m_packet.FlatPolygon.vertex[ n_rightpoint ].n_coord ) ) + { + while( n_y == COORD_Y( m_packet.FlatPolygon.vertex[ p_n_rightpointlist[ n_rightpoint ] ].n_coord ) ) + { + n_rightpoint = p_n_rightpointlist[ n_rightpoint ]; + if( n_rightpoint == n_leftpoint ) + { + break; + } + } + n_cx2.sw.h = COORD_X( m_packet.FlatPolygon.vertex[ n_rightpoint ].n_coord ); n_cx2.sw.l = 0; + n_rightpoint = p_n_rightpointlist[ n_rightpoint ]; + n_distance = COORD_Y( m_packet.FlatPolygon.vertex[ n_rightpoint ].n_coord ) - n_y; + if( n_distance < 1 ) + { + break; + } + n_dx2 = (INT32)( ( COORD_X( m_packet.FlatPolygon.vertex[ n_rightpoint ].n_coord ) << 16 ) - n_cx2.d ) / n_distance; + } + + int drawy = n_y + n_drawoffset_y; + + if( (INT16)n_cx1.sw.h != (INT16)n_cx2.sw.h && drawy >= (INT32)n_drawarea_y1 && drawy <= (INT32)n_drawarea_y2 ) + { + if( (INT16)n_cx1.sw.h < (INT16)n_cx2.sw.h ) + { + n_x = n_cx1.sw.h; + n_distance = (INT16)n_cx2.sw.h - n_x; + } + else + { + n_x = n_cx2.sw.h; + n_distance = (INT16)n_cx1.sw.h - n_x; + } + + int drawx = n_x + n_drawoffset_x; + + if( ( (INT32)n_drawarea_x1 - drawx ) > 0 ) + { + n_distance -= ( n_drawarea_x1 - drawx ); + drawx = n_drawarea_x1; + } + + SOLIDFILL( FLATPOLYGONUPDATE ) + } + n_cx1.d += n_dx1; + n_cx2.d += n_dx2; + n_y++; + } +} + +void psxgpu_device::FlatTexturedPolygon( int n_points ) +{ + INT16 n_y; + INT16 n_x; + int n_tx; + int n_ty; + + UINT8 n_cmd; + + UINT32 n_clutx; + UINT32 n_cluty; + + UINT16 *p_n_f; + UINT16 *p_n_redb; + UINT16 *p_n_greenb; + UINT16 *p_n_blueb; + UINT16 *p_n_redtrans; + UINT16 *p_n_greentrans; + UINT16 *p_n_bluetrans; + + PAIR n_r; + PAIR n_g; + PAIR n_b; + PAIR n_u; + PAIR n_v; + + PAIR n_cx1; + PAIR n_cx2; + PAIR n_cu1; + PAIR n_cv1; + PAIR n_cu2; + PAIR n_cv2; + INT32 n_du; + INT32 n_dv; + INT32 n_dx1; + INT32 n_dx2; + INT32 n_du1; + INT32 n_dv1; + INT32 n_du2; + INT32 n_dv2; + + INT32 n_distance; + UINT16 n_point; + UINT16 n_rightpoint; + UINT16 n_leftpoint; + const UINT16 *p_n_rightpointlist; + const UINT16 *p_n_leftpointlist; + UINT16 *p_clut; + UINT16 *p_vram; + UINT32 n_bgr; + +#if DEBUG_VIEWER + if( m_debug.n_skip == 2 ) + { + return; + } + for( n_point = 0; n_point < n_points; n_point++ ) + { + DebugMesh( SINT11( COORD_X( m_packet.FlatTexturedPolygon.vertex[ n_point ].n_coord ) ) + n_drawoffset_x, SINT11( COORD_Y( m_packet.FlatTexturedPolygon.vertex[ n_point ].n_coord ) ) + n_drawoffset_y ); + } + DebugMeshEnd(); +#endif + + n_cmd = BGR_C( m_packet.FlatTexturedPolygon.n_bgr ); + + n_clutx = ( m_packet.FlatTexturedPolygon.vertex[ 0 ].n_texture.w.h & 0x3f ) << 4; + n_cluty = ( m_packet.FlatTexturedPolygon.vertex[ 0 ].n_texture.w.h >> 6 ) & 0x3ff; + + n_r.d = 0; + n_g.d = 0; + n_b.d = 0; + n_cx1.d = 0; + n_cu1.d = 0; + n_cv1.d = 0; + n_cx2.d = 0; + n_cu2.d = 0; + n_cv2.d = 0; + + decode_tpage( m_packet.FlatTexturedPolygon.vertex[ 1 ].n_texture.w.h ); + TEXTURESETUP + + switch( n_cmd & 0x01 ) + { + case 0: + n_r.w.h = BGR_R( m_packet.FlatTexturedPolygon.n_bgr ); n_r.w.l = 0; + n_g.w.h = BGR_G( m_packet.FlatTexturedPolygon.n_bgr ); n_g.w.l = 0; + n_b.w.h = BGR_B( m_packet.FlatTexturedPolygon.n_bgr ); n_b.w.l = 0; + break; + case 1: + n_r.w.h = 0x80; n_r.w.l = 0; + n_g.w.h = 0x80; n_g.w.l = 0; + n_b.w.h = 0x80; n_b.w.l = 0; + break; + } + + FINDTOPLEFT( FlatTexturedPolygon ) + + n_dx1 = 0; + n_dx2 = 0; + n_du1 = 0; + n_du2 = 0; + n_dv1 = 0; + n_dv2 = 0; + + n_y = COORD_Y( m_packet.FlatTexturedPolygon.vertex[ n_rightpoint ].n_coord ); + + for( ;; ) + { + if( n_y == COORD_Y( m_packet.FlatTexturedPolygon.vertex[ n_leftpoint ].n_coord ) ) + { + while( n_y == COORD_Y( m_packet.FlatTexturedPolygon.vertex[ p_n_leftpointlist[ n_leftpoint ] ].n_coord ) ) + { + n_leftpoint = p_n_leftpointlist[ n_leftpoint ]; + if( n_leftpoint == n_rightpoint ) + { + break; + } + } + n_cx1.sw.h = COORD_X( m_packet.FlatTexturedPolygon.vertex[ n_leftpoint ].n_coord ); n_cx1.sw.l = 0; + n_cu1.w.h = TEXTURE_U( m_packet.FlatTexturedPolygon.vertex[ n_leftpoint ].n_texture ); n_cu1.w.l = 0; + n_cv1.w.h = TEXTURE_V( m_packet.FlatTexturedPolygon.vertex[ n_leftpoint ].n_texture ); n_cv1.w.l = 0; + n_leftpoint = p_n_leftpointlist[ n_leftpoint ]; + n_distance = COORD_Y( m_packet.FlatTexturedPolygon.vertex[ n_leftpoint ].n_coord ) - n_y; + if( n_distance < 1 ) + { + break; + } + n_dx1 = (INT32)( ( COORD_X( m_packet.FlatTexturedPolygon.vertex[ n_leftpoint ].n_coord ) << 16 ) - n_cx1.d ) / n_distance; + n_du1 = (INT32)( ( TEXTURE_U( m_packet.FlatTexturedPolygon.vertex[ n_leftpoint ].n_texture ) << 16 ) - n_cu1.d ) / n_distance; + n_dv1 = (INT32)( ( TEXTURE_V( m_packet.FlatTexturedPolygon.vertex[ n_leftpoint ].n_texture ) << 16 ) - n_cv1.d ) / n_distance; + } + if( n_y == COORD_Y( m_packet.FlatTexturedPolygon.vertex[ n_rightpoint ].n_coord ) ) + { + while( n_y == COORD_Y( m_packet.FlatTexturedPolygon.vertex[ p_n_rightpointlist[ n_rightpoint ] ].n_coord ) ) + { + n_rightpoint = p_n_rightpointlist[ n_rightpoint ]; + if( n_rightpoint == n_leftpoint ) + { + break; + } + } + n_cx2.sw.h = COORD_X( m_packet.FlatTexturedPolygon.vertex[ n_rightpoint ].n_coord ); n_cx2.sw.l = 0; + n_cu2.w.h = TEXTURE_U( m_packet.FlatTexturedPolygon.vertex[ n_rightpoint ].n_texture ); n_cu2.w.l = 0; + n_cv2.w.h = TEXTURE_V( m_packet.FlatTexturedPolygon.vertex[ n_rightpoint ].n_texture ); n_cv2.w.l = 0; + n_rightpoint = p_n_rightpointlist[ n_rightpoint ]; + n_distance = COORD_Y( m_packet.FlatTexturedPolygon.vertex[ n_rightpoint ].n_coord ) - n_y; + if( n_distance < 1 ) + { + break; + } + n_dx2 = (INT32)( ( COORD_X( m_packet.FlatTexturedPolygon.vertex[ n_rightpoint ].n_coord ) << 16 ) - n_cx2.d ) / n_distance; + n_du2 = (INT32)( ( TEXTURE_U( m_packet.FlatTexturedPolygon.vertex[ n_rightpoint ].n_texture ) << 16 ) - n_cu2.d ) / n_distance; + n_dv2 = (INT32)( ( TEXTURE_V( m_packet.FlatTexturedPolygon.vertex[ n_rightpoint ].n_texture ) << 16 ) - n_cv2.d ) / n_distance; + } + + int drawy = n_y + n_drawoffset_y; + + if( (INT16)n_cx1.sw.h != (INT16)n_cx2.sw.h && drawy >= (INT32)n_drawarea_y1 && drawy <= (INT32)n_drawarea_y2 ) + { + if( (INT16)n_cx1.sw.h < (INT16)n_cx2.sw.h ) + { + n_x = n_cx1.sw.h; + n_distance = (INT16)n_cx2.sw.h - n_x; + + n_u.d = n_cu1.d; + n_v.d = n_cv1.d; + n_du = (INT32)( n_cu2.d - n_cu1.d ) / n_distance; + n_dv = (INT32)( n_cv2.d - n_cv1.d ) / n_distance; + } + else + { + n_x = n_cx2.sw.h; + n_distance = (INT16)n_cx1.sw.h - n_x; + + n_u.d = n_cu2.d; + n_v.d = n_cv2.d; + n_du = (INT32)( n_cu1.d - n_cu2.d ) / n_distance; + n_dv = (INT32)( n_cv1.d - n_cv2.d ) / n_distance; + } + + int drawx = n_x + n_drawoffset_x; + + if( ( (INT32)n_drawarea_x1 - drawx ) > 0 ) + { + n_u.d += n_du * ( n_drawarea_x1 - drawx ); + n_v.d += n_dv * ( n_drawarea_x1 - drawx ); + n_distance -= ( n_drawarea_x1 - drawx ); + drawx = n_drawarea_x1; + } + + TEXTUREFILL( FLATTEXTUREDPOLYGONUPDATE, n_u.w.h, n_v.w.h ); + } + n_cx1.d += n_dx1; + n_cu1.d += n_du1; + n_cv1.d += n_dv1; + n_cx2.d += n_dx2; + n_cu2.d += n_du2; + n_cv2.d += n_dv2; + n_y++; + } +} + +void psxgpu_device::GouraudPolygon( int n_points ) +{ + INT16 n_y; + INT16 n_x; + + UINT16 *p_n_f; + UINT16 *p_n_redb; + UINT16 *p_n_greenb; + UINT16 *p_n_blueb; + UINT16 *p_n_redtrans; + UINT16 *p_n_greentrans; + UINT16 *p_n_bluetrans; + + UINT8 n_cmd; + + PAIR n_r; + PAIR n_g; + PAIR n_b; + PAIR n_cx1; + PAIR n_cx2; + PAIR n_cr1; + PAIR n_cg1; + PAIR n_cb1; + PAIR n_cr2; + PAIR n_cg2; + PAIR n_cb2; + INT32 n_dr; + INT32 n_dg; + INT32 n_db; + INT32 n_dx1; + INT32 n_dx2; + INT32 n_dr1; + INT32 n_dg1; + INT32 n_db1; + INT32 n_dr2; + INT32 n_dg2; + INT32 n_db2; + + INT32 n_distance; + + UINT16 n_point; + UINT16 n_rightpoint; + UINT16 n_leftpoint; + const UINT16 *p_n_rightpointlist; + const UINT16 *p_n_leftpointlist; + + UINT16 *p_vram; + +#if DEBUG_VIEWER + if( m_debug.n_skip == 3 ) + { + return; + } + for( n_point = 0; n_point < n_points; n_point++ ) + { + DebugMesh( SINT11( COORD_X( m_packet.GouraudPolygon.vertex[ n_point ].n_coord ) ) + n_drawoffset_x, SINT11( COORD_Y( m_packet.GouraudPolygon.vertex[ n_point ].n_coord ) ) + n_drawoffset_y ); + } + DebugMeshEnd(); +#endif + + n_cmd = BGR_C( m_packet.GouraudPolygon.vertex[ 0 ].n_bgr ); + + n_cx1.d = 0; + n_cr1.d = 0; + n_cg1.d = 0; + n_cb1.d = 0; + n_cx2.d = 0; + n_cr2.d = 0; + n_cg2.d = 0; + n_cb2.d = 0; + + SOLIDSETUP + + FINDTOPLEFT( GouraudPolygon ) + + n_dx1 = 0; + n_dx2 = 0; + n_dr1 = 0; + n_dr2 = 0; + n_dg1 = 0; + n_dg2 = 0; + n_db1 = 0; + n_db2 = 0; + + n_y = COORD_Y( m_packet.GouraudPolygon.vertex[ n_rightpoint ].n_coord ); + + for( ;; ) + { + if( n_y == COORD_Y( m_packet.GouraudPolygon.vertex[ n_leftpoint ].n_coord ) ) + { + while( n_y == COORD_Y( m_packet.GouraudPolygon.vertex[ p_n_leftpointlist[ n_leftpoint ] ].n_coord ) ) + { + n_leftpoint = p_n_leftpointlist[ n_leftpoint ]; + if( n_leftpoint == n_rightpoint ) + { + break; + } + } + n_cx1.sw.h = COORD_X( m_packet.GouraudPolygon.vertex[ n_leftpoint ].n_coord ); n_cx1.sw.l = 0; + n_cr1.w.h = BGR_R( m_packet.GouraudPolygon.vertex[ n_leftpoint ].n_bgr ); n_cr1.w.l = 0; + n_cg1.w.h = BGR_G( m_packet.GouraudPolygon.vertex[ n_leftpoint ].n_bgr ); n_cg1.w.l = 0; + n_cb1.w.h = BGR_B( m_packet.GouraudPolygon.vertex[ n_leftpoint ].n_bgr ); n_cb1.w.l = 0; + n_leftpoint = p_n_leftpointlist[ n_leftpoint ]; + n_distance = COORD_Y( m_packet.GouraudPolygon.vertex[ n_leftpoint ].n_coord ) - n_y; + if( n_distance < 1 ) + { + break; + } + n_dx1 = (INT32)( ( COORD_X( m_packet.GouraudPolygon.vertex[ n_leftpoint ].n_coord ) << 16 ) - n_cx1.d ) / n_distance; + n_dr1 = (INT32)( ( BGR_R( m_packet.GouraudPolygon.vertex[ n_leftpoint ].n_bgr ) << 16 ) - n_cr1.d ) / n_distance; + n_dg1 = (INT32)( ( BGR_G( m_packet.GouraudPolygon.vertex[ n_leftpoint ].n_bgr ) << 16 ) - n_cg1.d ) / n_distance; + n_db1 = (INT32)( ( BGR_B( m_packet.GouraudPolygon.vertex[ n_leftpoint ].n_bgr ) << 16 ) - n_cb1.d ) / n_distance; + } + if( n_y == COORD_Y( m_packet.GouraudPolygon.vertex[ n_rightpoint ].n_coord ) ) + { + while( n_y == COORD_Y( m_packet.GouraudPolygon.vertex[ p_n_rightpointlist[ n_rightpoint ] ].n_coord ) ) + { + n_rightpoint = p_n_rightpointlist[ n_rightpoint ]; + if( n_rightpoint == n_leftpoint ) + { + break; + } + } + n_cx2.sw.h = COORD_X( m_packet.GouraudPolygon.vertex[ n_rightpoint ].n_coord ); n_cx2.sw.l = 0; + n_cr2.w.h = BGR_R( m_packet.GouraudPolygon.vertex[ n_rightpoint ].n_bgr ); n_cr2.w.l = 0; + n_cg2.w.h = BGR_G( m_packet.GouraudPolygon.vertex[ n_rightpoint ].n_bgr ); n_cg2.w.l = 0; + n_cb2.w.h = BGR_B( m_packet.GouraudPolygon.vertex[ n_rightpoint ].n_bgr ); n_cb2.w.l = 0; + n_rightpoint = p_n_rightpointlist[ n_rightpoint ]; + n_distance = COORD_Y( m_packet.GouraudPolygon.vertex[ n_rightpoint ].n_coord ) - n_y; + if( n_distance < 1 ) + { + break; + } + n_dx2 = (INT32)( ( COORD_X( m_packet.GouraudPolygon.vertex[ n_rightpoint ].n_coord ) << 16 ) - n_cx2.d ) / n_distance; + n_dr2 = (INT32)( ( BGR_R( m_packet.GouraudPolygon.vertex[ n_rightpoint ].n_bgr ) << 16 ) - n_cr2.d ) / n_distance; + n_dg2 = (INT32)( ( BGR_G( m_packet.GouraudPolygon.vertex[ n_rightpoint ].n_bgr ) << 16 ) - n_cg2.d ) / n_distance; + n_db2 = (INT32)( ( BGR_B( m_packet.GouraudPolygon.vertex[ n_rightpoint ].n_bgr ) << 16 ) - n_cb2.d ) / n_distance; + } + + int drawy = n_y + n_drawoffset_y; + + if( (INT16)n_cx1.sw.h != (INT16)n_cx2.sw.h && drawy >= (INT32)n_drawarea_y1 && drawy <= (INT32)n_drawarea_y2 ) + { + if( (INT16)n_cx1.sw.h < (INT16)n_cx2.sw.h ) + { + n_x = n_cx1.sw.h; + n_distance = (INT16)n_cx2.sw.h - n_x; + + n_r.d = n_cr1.d; + n_g.d = n_cg1.d; + n_b.d = n_cb1.d; + n_dr = (INT32)( n_cr2.d - n_cr1.d ) / n_distance; + n_dg = (INT32)( n_cg2.d - n_cg1.d ) / n_distance; + n_db = (INT32)( n_cb2.d - n_cb1.d ) / n_distance; + } + else + { + n_x = n_cx2.sw.h; + n_distance = (INT16)n_cx1.sw.h - n_x; + + n_r.d = n_cr2.d; + n_g.d = n_cg2.d; + n_b.d = n_cb2.d; + n_dr = (INT32)( n_cr1.d - n_cr2.d ) / n_distance; + n_dg = (INT32)( n_cg1.d - n_cg2.d ) / n_distance; + n_db = (INT32)( n_cb1.d - n_cb2.d ) / n_distance; + } + + int drawx = n_x + n_drawoffset_x; + + if( ( (INT32)n_drawarea_x1 - drawx ) > 0 ) + { + n_r.d += n_dr * ( n_drawarea_x1 - drawx ); + n_g.d += n_dg * ( n_drawarea_x1 - drawx ); + n_b.d += n_db * ( n_drawarea_x1 - drawx ); + n_distance -= ( n_drawarea_x1 - drawx ); + drawx = n_drawarea_x1; + } + + SOLIDFILL( GOURAUDPOLYGONUPDATE ) + } + n_cx1.d += n_dx1; + n_cr1.d += n_dr1; + n_cg1.d += n_dg1; + n_cb1.d += n_db1; + n_cx2.d += n_dx2; + n_cr2.d += n_dr2; + n_cg2.d += n_dg2; + n_cb2.d += n_db2; + n_y++; + } +} + +void psxgpu_device::GouraudTexturedPolygon( int n_points ) +{ + INT16 n_y; + INT16 n_x; + int n_tx; + int n_ty; + + UINT8 n_cmd; + + UINT32 n_clutx; + UINT32 n_cluty; + + UINT16 *p_n_f; + UINT16 *p_n_redb; + UINT16 *p_n_greenb; + UINT16 *p_n_blueb; + UINT16 *p_n_redtrans; + UINT16 *p_n_greentrans; + UINT16 *p_n_bluetrans; + + PAIR n_r; + PAIR n_g; + PAIR n_b; + PAIR n_u; + PAIR n_v; + + PAIR n_cx1; + PAIR n_cx2; + PAIR n_cu1; + PAIR n_cv1; + PAIR n_cu2; + PAIR n_cv2; + PAIR n_cr1; + PAIR n_cg1; + PAIR n_cb1; + PAIR n_cr2; + PAIR n_cg2; + PAIR n_cb2; + INT32 n_dr; + INT32 n_dg; + INT32 n_db; + INT32 n_du; + INT32 n_dv; + INT32 n_dx1; + INT32 n_dx2; + INT32 n_dr1; + INT32 n_dg1; + INT32 n_db1; + INT32 n_dr2; + INT32 n_dg2; + INT32 n_db2; + INT32 n_du1; + INT32 n_dv1; + INT32 n_du2; + INT32 n_dv2; + + INT32 n_distance; + UINT16 n_point; + UINT16 n_rightpoint; + UINT16 n_leftpoint; + const UINT16 *p_n_rightpointlist; + const UINT16 *p_n_leftpointlist; + UINT16 *p_clut; + UINT16 *p_vram; + UINT32 n_bgr; + +#if DEBUG_VIEWER + if( m_debug.n_skip == 4 ) + { + return; + } + for( n_point = 0; n_point < n_points; n_point++ ) + { + DebugMesh( SINT11( COORD_X( m_packet.GouraudTexturedPolygon.vertex[ n_point ].n_coord ) ) + n_drawoffset_x, SINT11( COORD_Y( m_packet.GouraudTexturedPolygon.vertex[ n_point ].n_coord ) ) + n_drawoffset_y ); + } + DebugMeshEnd(); +#endif + + n_cmd = BGR_C( m_packet.GouraudTexturedPolygon.vertex[ 0 ].n_bgr ); + + n_clutx = ( m_packet.GouraudTexturedPolygon.vertex[ 0 ].n_texture.w.h & 0x3f ) << 4; + n_cluty = ( m_packet.GouraudTexturedPolygon.vertex[ 0 ].n_texture.w.h >> 6 ) & 0x3ff; + + n_cx1.d = 0; + n_cr1.d = 0; + n_cg1.d = 0; + n_cb1.d = 0; + n_cu1.d = 0; + n_cv1.d = 0; + n_cx2.d = 0; + n_cr2.d = 0; + n_cg2.d = 0; + n_cb2.d = 0; + n_cu2.d = 0; + n_cv2.d = 0; + + decode_tpage( m_packet.GouraudTexturedPolygon.vertex[ 1 ].n_texture.w.h ); + TEXTURESETUP + + FINDTOPLEFT( GouraudTexturedPolygon ) + + n_dx1 = 0; + n_dx2 = 0; + n_du1 = 0; + n_du2 = 0; + n_dr1 = 0; + n_dr2 = 0; + n_dg1 = 0; + n_dg2 = 0; + n_db1 = 0; + n_db2 = 0; + n_dv1 = 0; + n_dv2 = 0; + + n_y = COORD_Y( m_packet.GouraudTexturedPolygon.vertex[ n_rightpoint ].n_coord ); + + for( ;; ) + { + if( n_y == COORD_Y( m_packet.GouraudTexturedPolygon.vertex[ n_leftpoint ].n_coord ) ) + { + while( n_y == COORD_Y( m_packet.GouraudTexturedPolygon.vertex[ p_n_leftpointlist[ n_leftpoint ] ].n_coord ) ) + { + n_leftpoint = p_n_leftpointlist[ n_leftpoint ]; + if( n_leftpoint == n_rightpoint ) + { + break; + } + } + n_cx1.sw.h = COORD_X( m_packet.GouraudTexturedPolygon.vertex[ n_leftpoint ].n_coord ); n_cx1.sw.l = 0; + switch( n_cmd & 0x01 ) + { + case 0x00: + n_cr1.w.h = BGR_R( m_packet.GouraudTexturedPolygon.vertex[ n_leftpoint ].n_bgr ); n_cr1.w.l = 0; + n_cg1.w.h = BGR_G( m_packet.GouraudTexturedPolygon.vertex[ n_leftpoint ].n_bgr ); n_cg1.w.l = 0; + n_cb1.w.h = BGR_B( m_packet.GouraudTexturedPolygon.vertex[ n_leftpoint ].n_bgr ); n_cb1.w.l = 0; + break; + case 0x01: + n_cr1.w.h = 0x80; n_cr1.w.l = 0; + n_cg1.w.h = 0x80; n_cg1.w.l = 0; + n_cb1.w.h = 0x80; n_cb1.w.l = 0; + break; + } + n_cu1.w.h = TEXTURE_U( m_packet.GouraudTexturedPolygon.vertex[ n_leftpoint ].n_texture ); n_cu1.w.l = 0; + n_cv1.w.h = TEXTURE_V( m_packet.GouraudTexturedPolygon.vertex[ n_leftpoint ].n_texture ); n_cv1.w.l = 0; + n_leftpoint = p_n_leftpointlist[ n_leftpoint ]; + n_distance = COORD_Y( m_packet.GouraudTexturedPolygon.vertex[ n_leftpoint ].n_coord ) - n_y; + if( n_distance < 1 ) + { + break; + } + n_dx1 = (INT32)( ( COORD_X( m_packet.GouraudTexturedPolygon.vertex[ n_leftpoint ].n_coord ) << 16 ) - n_cx1.d ) / n_distance; + switch( n_cmd & 0x01 ) + { + case 0x00: + n_dr1 = (INT32)( ( BGR_R( m_packet.GouraudTexturedPolygon.vertex[ n_leftpoint ].n_bgr ) << 16 ) - n_cr1.d ) / n_distance; + n_dg1 = (INT32)( ( BGR_G( m_packet.GouraudTexturedPolygon.vertex[ n_leftpoint ].n_bgr ) << 16 ) - n_cg1.d ) / n_distance; + n_db1 = (INT32)( ( BGR_B( m_packet.GouraudTexturedPolygon.vertex[ n_leftpoint ].n_bgr ) << 16 ) - n_cb1.d ) / n_distance; + break; + case 0x01: + n_dr1 = 0; + n_dg1 = 0; + n_db1 = 0; + break; + } + n_du1 = (INT32)( ( TEXTURE_U( m_packet.GouraudTexturedPolygon.vertex[ n_leftpoint ].n_texture ) << 16 ) - n_cu1.d ) / n_distance; + n_dv1 = (INT32)( ( TEXTURE_V( m_packet.GouraudTexturedPolygon.vertex[ n_leftpoint ].n_texture ) << 16 ) - n_cv1.d ) / n_distance; + } + if( n_y == COORD_Y( m_packet.GouraudTexturedPolygon.vertex[ n_rightpoint ].n_coord ) ) + { + while( n_y == COORD_Y( m_packet.GouraudTexturedPolygon.vertex[ p_n_rightpointlist[ n_rightpoint ] ].n_coord ) ) + { + n_rightpoint = p_n_rightpointlist[ n_rightpoint ]; + if( n_rightpoint == n_leftpoint ) + { + break; + } + } + n_cx2.sw.h = COORD_X( m_packet.GouraudTexturedPolygon.vertex[ n_rightpoint ].n_coord ); n_cx2.sw.l = 0; + switch( n_cmd & 0x01 ) + { + case 0x00: + n_cr2.w.h = BGR_R( m_packet.GouraudTexturedPolygon.vertex[ n_rightpoint ].n_bgr ); n_cr2.w.l = 0; + n_cg2.w.h = BGR_G( m_packet.GouraudTexturedPolygon.vertex[ n_rightpoint ].n_bgr ); n_cg2.w.l = 0; + n_cb2.w.h = BGR_B( m_packet.GouraudTexturedPolygon.vertex[ n_rightpoint ].n_bgr ); n_cb2.w.l = 0; + break; + case 0x01: + n_cr2.w.h = 0x80; n_cr2.w.l = 0; + n_cg2.w.h = 0x80; n_cg2.w.l = 0; + n_cb2.w.h = 0x80; n_cb2.w.l = 0; + break; + } + n_cu2.w.h = TEXTURE_U( m_packet.GouraudTexturedPolygon.vertex[ n_rightpoint ].n_texture ); n_cu2.w.l = 0; + n_cv2.w.h = TEXTURE_V( m_packet.GouraudTexturedPolygon.vertex[ n_rightpoint ].n_texture ); n_cv2.w.l = 0; + n_rightpoint = p_n_rightpointlist[ n_rightpoint ]; + n_distance = COORD_Y( m_packet.GouraudTexturedPolygon.vertex[ n_rightpoint ].n_coord ) - n_y; + if( n_distance < 1 ) + { + break; + } + n_dx2 = (INT32)( ( COORD_X( m_packet.GouraudTexturedPolygon.vertex[ n_rightpoint ].n_coord ) << 16 ) - n_cx2.d ) / n_distance; + switch( n_cmd & 0x01 ) + { + case 0x00: + n_dr2 = (INT32)( ( BGR_R( m_packet.GouraudTexturedPolygon.vertex[ n_rightpoint ].n_bgr ) << 16 ) - n_cr2.d ) / n_distance; + n_dg2 = (INT32)( ( BGR_G( m_packet.GouraudTexturedPolygon.vertex[ n_rightpoint ].n_bgr ) << 16 ) - n_cg2.d ) / n_distance; + n_db2 = (INT32)( ( BGR_B( m_packet.GouraudTexturedPolygon.vertex[ n_rightpoint ].n_bgr ) << 16 ) - n_cb2.d ) / n_distance; + break; + case 0x01: + n_dr2 = 0; + n_dg2 = 0; + n_db2 = 0; + break; + } + n_du2 = (INT32)( ( TEXTURE_U( m_packet.GouraudTexturedPolygon.vertex[ n_rightpoint ].n_texture ) << 16 ) - n_cu2.d ) / n_distance; + n_dv2 = (INT32)( ( TEXTURE_V( m_packet.GouraudTexturedPolygon.vertex[ n_rightpoint ].n_texture ) << 16 ) - n_cv2.d ) / n_distance; + } + + int drawy = n_y + n_drawoffset_y; + + if( (INT16)n_cx1.sw.h != (INT16)n_cx2.sw.h && drawy >= (INT32)n_drawarea_y1 && drawy <= (INT32)n_drawarea_y2 ) + { + if( (INT16)n_cx1.sw.h < (INT16)n_cx2.sw.h ) + { + n_x = n_cx1.sw.h; + n_distance = (INT16)n_cx2.sw.h - n_x; + + n_r.d = n_cr1.d; + n_g.d = n_cg1.d; + n_b.d = n_cb1.d; + n_u.d = n_cu1.d; + n_v.d = n_cv1.d; + n_dr = (INT32)( n_cr2.d - n_cr1.d ) / n_distance; + n_dg = (INT32)( n_cg2.d - n_cg1.d ) / n_distance; + n_db = (INT32)( n_cb2.d - n_cb1.d ) / n_distance; + n_du = (INT32)( n_cu2.d - n_cu1.d ) / n_distance; + n_dv = (INT32)( n_cv2.d - n_cv1.d ) / n_distance; + } + else + { + n_x = n_cx2.sw.h; + n_distance = (INT16)n_cx1.sw.h - n_x; + + n_r.d = n_cr2.d; + n_g.d = n_cg2.d; + n_b.d = n_cb2.d; + n_u.d = n_cu2.d; + n_v.d = n_cv2.d; + n_dr = (INT32)( n_cr1.d - n_cr2.d ) / n_distance; + n_dg = (INT32)( n_cg1.d - n_cg2.d ) / n_distance; + n_db = (INT32)( n_cb1.d - n_cb2.d ) / n_distance; + n_du = (INT32)( n_cu1.d - n_cu2.d ) / n_distance; + n_dv = (INT32)( n_cv1.d - n_cv2.d ) / n_distance; + } + + int drawx = n_x + n_drawoffset_x; + + if( ( (INT32)n_drawarea_x1 - drawx ) > 0 ) + { + n_r.d += n_dr * ( n_drawarea_x1 - drawx ); + n_g.d += n_dg * ( n_drawarea_x1 - drawx ); + n_b.d += n_db * ( n_drawarea_x1 - drawx ); + n_u.d += n_du * ( n_drawarea_x1 - drawx ); + n_v.d += n_dv * ( n_drawarea_x1 - drawx ); + n_distance -= ( n_drawarea_x1 - drawx ); + drawx = n_drawarea_x1; + } + + TEXTUREFILL( GOURAUDTEXTUREDPOLYGONUPDATE, n_u.w.h, n_v.w.h ); + } + n_cx1.d += n_dx1; + n_cr1.d += n_dr1; + n_cg1.d += n_dg1; + n_cb1.d += n_db1; + n_cu1.d += n_du1; + n_cv1.d += n_dv1; + n_cx2.d += n_dx2; + n_cr2.d += n_dr2; + n_cg2.d += n_dg2; + n_cb2.d += n_db2; + n_cu2.d += n_du2; + n_cv2.d += n_dv2; + n_y++; + } +} + +void psxgpu_device::MonochromeLine( void ) +{ + PAIR n_x; + PAIR n_y; + INT32 n_dx; + INT32 n_dy; + INT32 n_len; + INT32 n_xlen; + INT32 n_ylen; + INT32 n_xstart; + INT32 n_ystart; + INT32 n_xend; + INT32 n_yend; + UINT32 n_r; + UINT32 n_g; + UINT32 n_b; + UINT16 *p_vram; + +#if DEBUG_VIEWER + if( m_debug.n_skip == 5 ) + { + return; + } + DebugMesh( SINT11( COORD_X( m_packet.MonochromeLine.vertex[ 0 ].n_coord ) ) + n_drawoffset_x, SINT11( COORD_Y( m_packet.MonochromeLine.vertex[ 0 ].n_coord ) ) + n_drawoffset_y ); + DebugMesh( SINT11( COORD_X( m_packet.MonochromeLine.vertex[ 1 ].n_coord ) ) + n_drawoffset_x, SINT11( COORD_Y( m_packet.MonochromeLine.vertex[ 1 ].n_coord ) ) + n_drawoffset_y ); + DebugMeshEnd(); +#endif + + n_xstart = SINT11( COORD_X( m_packet.MonochromeLine.vertex[ 0 ].n_coord ) ); + n_xend = SINT11( COORD_X( m_packet.MonochromeLine.vertex[ 1 ].n_coord ) ); + n_ystart = SINT11( COORD_Y( m_packet.MonochromeLine.vertex[ 0 ].n_coord ) ); + n_yend = SINT11( COORD_Y( m_packet.MonochromeLine.vertex[ 1 ].n_coord ) ); + + n_r = BGR_R( m_packet.MonochromeLine.n_bgr ); + n_g = BGR_G( m_packet.MonochromeLine.n_bgr ); + n_b = BGR_B( m_packet.MonochromeLine.n_bgr ); + + if( n_xend > n_xstart ) + { + n_xlen = n_xend - n_xstart; + } + else + { + n_xlen = n_xstart - n_xend; + } + + if( n_yend > n_ystart ) + { + n_ylen = n_yend - n_ystart; + } + else + { + n_ylen = n_ystart - n_yend; + } + + if( n_xlen > n_ylen ) + { + n_len = n_xlen; + } + else + { + n_len = n_ylen; + } + + if( n_len == 0 ) + { + n_len = 1; + } + + n_x.sw.h = n_xstart; n_x.sw.l = 0; + n_y.sw.h = n_ystart; n_y.sw.l = 0; + + n_dx = (INT32)( ( n_xend << 16 ) - n_x.d ) / n_len; + n_dy = (INT32)( ( n_yend << 16 ) - n_y.d ) / n_len; + + while( n_len > 0 ) + { + int drawx = n_x.sw.h + n_drawoffset_x; + int drawy = n_y.sw.h + n_drawoffset_y; + + if( drawx >= (INT32)n_drawarea_x1 && drawy >= (INT32)n_drawarea_y1 && + drawx <= (INT32)n_drawarea_x2 && drawy <= (INT32)n_drawarea_y2 ) + { + p_vram = p_p_vram[ drawy ] + drawx; + WRITE_PIXEL( + p_n_redshade[ MID_LEVEL | n_r ] | + p_n_greenshade[ MID_LEVEL | n_g ] | + p_n_blueshade[ MID_LEVEL | n_b ] ); + } + n_x.d += n_dx; + n_y.d += n_dy; + n_len--; + } +} + +void psxgpu_device::GouraudLine( void ) +{ + PAIR n_x; + PAIR n_y; + INT32 n_dx; + INT32 n_dy; + INT32 n_dr; + INT32 n_dg; + INT32 n_db; + INT32 n_distance; + INT32 n_xlen; + INT32 n_ylen; + INT32 n_xstart; + INT32 n_ystart; + INT32 n_xend; + INT32 n_yend; + PAIR n_r; + PAIR n_g; + PAIR n_b; + PAIR n_cr1; + PAIR n_cg1; + PAIR n_cb1; + PAIR n_cr2; + PAIR n_cg2; + PAIR n_cb2; + UINT16 *p_vram; + +#if DEBUG_VIEWER + if( m_debug.n_skip == 6 ) + { + return; + } + DebugMesh( SINT11( COORD_X( m_packet.GouraudLine.vertex[ 0 ].n_coord ) ) + n_drawoffset_x, SINT11( COORD_Y( m_packet.GouraudLine.vertex[ 0 ].n_coord ) ) + n_drawoffset_y ); + DebugMesh( SINT11( COORD_X( m_packet.GouraudLine.vertex[ 1 ].n_coord ) ) + n_drawoffset_x, SINT11( COORD_Y( m_packet.GouraudLine.vertex[ 1 ].n_coord ) ) + n_drawoffset_y ); + DebugMeshEnd(); +#endif + + n_xstart = SINT11( COORD_X( m_packet.GouraudLine.vertex[ 0 ].n_coord ) ); + n_ystart = SINT11( COORD_Y( m_packet.GouraudLine.vertex[ 0 ].n_coord ) ); + n_cr1.w.h = BGR_R( m_packet.GouraudLine.vertex[ 0 ].n_bgr ); n_cr1.w.l = 0; + n_cg1.w.h = BGR_G( m_packet.GouraudLine.vertex[ 0 ].n_bgr ); n_cg1.w.l = 0; + n_cb1.w.h = BGR_B( m_packet.GouraudLine.vertex[ 0 ].n_bgr ); n_cb1.w.l = 0; + + n_xend = SINT11( COORD_X( m_packet.GouraudLine.vertex[ 1 ].n_coord ) ); + n_yend = SINT11( COORD_Y( m_packet.GouraudLine.vertex[ 1 ].n_coord ) ); + n_cr2.w.h = BGR_R( m_packet.GouraudLine.vertex[ 1 ].n_bgr ); n_cr1.w.l = 0; + n_cg2.w.h = BGR_G( m_packet.GouraudLine.vertex[ 1 ].n_bgr ); n_cg1.w.l = 0; + n_cb2.w.h = BGR_B( m_packet.GouraudLine.vertex[ 1 ].n_bgr ); n_cb1.w.l = 0; + + n_x.sw.h = n_xstart; n_x.sw.l = 0; + n_y.sw.h = n_ystart; n_y.sw.l = 0; + n_r.d = n_cr1.d; + n_g.d = n_cg1.d; + n_b.d = n_cb1.d; + + if( n_xend > n_xstart ) + { + n_xlen = n_xend - n_xstart; + } + else + { + n_xlen = n_xstart - n_xend; + } + + if( n_yend > n_ystart ) + { + n_ylen = n_yend - n_ystart; + } + else + { + n_ylen = n_ystart - n_yend; + } + + if( n_xlen > n_ylen ) + { + n_distance = n_xlen; + } + else + { + n_distance = n_ylen; + } + + if( n_distance == 0 ) + { + n_distance = 1; + } + + n_dx = (INT32)( ( n_xend << 16 ) - n_x.sd ) / n_distance; + n_dy = (INT32)( ( n_yend << 16 ) - n_y.sd ) / n_distance; + n_dr = (INT32)( n_cr2.d - n_cr1.d ) / n_distance; + n_dg = (INT32)( n_cg2.d - n_cg1.d ) / n_distance; + n_db = (INT32)( n_cb2.d - n_cb1.d ) / n_distance; + + while( n_distance > 0 ) + { + int drawx = n_x.sw.h + n_drawoffset_x; + int drawy = n_y.sw.h + n_drawoffset_y; + + if( drawx >= (INT32)n_drawarea_x1 && drawy >= (INT32)n_drawarea_y1 && + drawx <= (INT32)n_drawarea_x2 && drawy <= (INT32)n_drawarea_y2 ) + { + p_vram = p_p_vram[ drawy ] + drawx; + WRITE_PIXEL( + p_n_redshade[ MID_LEVEL | n_r.w.h ] | + p_n_greenshade[ MID_LEVEL | n_g.w.h ] | + p_n_blueshade[ MID_LEVEL | n_b.w.h ] ); + } + n_x.sd += n_dx; + n_y.sd += n_dy; + n_r.d += n_dr; + n_g.d += n_dg; + n_b.d += n_db; + n_distance--; + } +} + +void psxgpu_device::FrameBufferRectangleDraw( void ) +{ + PAIR n_r; + PAIR n_g; + PAIR n_b; + INT32 n_distance; + INT32 n_h; + INT16 n_y; + INT16 n_x; + UINT16 *p_vram; + +#if DEBUG_VIEWER + if( m_debug.n_skip == 7 ) + { + return; + } + DebugMesh( SINT11( COORD_X( m_packet.FlatRectangle.n_coord ) ), SINT11( COORD_Y( m_packet.FlatRectangle.n_coord ) ) ); + DebugMesh( SINT11( COORD_X( m_packet.FlatRectangle.n_coord ) ) + SIZE_W( m_packet.FlatRectangle.n_size ), SINT11( COORD_Y( m_packet.FlatRectangle.n_coord ) ) ); + DebugMesh( SINT11( COORD_X( m_packet.FlatRectangle.n_coord ) ), SINT11( COORD_Y( m_packet.FlatRectangle.n_coord ) ) + SIZE_H( m_packet.FlatRectangle.n_size ) ); + DebugMesh( SINT11( COORD_X( m_packet.FlatRectangle.n_coord ) ) + SIZE_W( m_packet.FlatRectangle.n_size ), SINT11( COORD_Y( m_packet.FlatRectangle.n_coord ) ) + SIZE_H( m_packet.FlatRectangle.n_size ) ); + DebugMeshEnd(); +#endif + + n_r.w.h = BGR_R( m_packet.FlatRectangle.n_bgr ); n_r.w.l = 0; + n_g.w.h = BGR_G( m_packet.FlatRectangle.n_bgr ); n_g.w.l = 0; + n_b.w.h = BGR_B( m_packet.FlatRectangle.n_bgr ); n_b.w.l = 0; + + n_y = COORD_Y( m_packet.FlatRectangle.n_coord ); + n_h = SIZE_H( m_packet.FlatRectangle.n_size ); + + while( n_h > 0 ) + { + n_x = COORD_X( m_packet.FlatRectangle.n_coord ); + + n_distance = SIZE_W( m_packet.FlatRectangle.n_size ); + while( n_distance > 0 ) + { + p_vram = p_p_vram[ n_y & 1023 ] + ( n_x & 1023 ); + WRITE_PIXEL( + p_n_redshade[ MID_LEVEL | n_r.w.h ] | + p_n_greenshade[ MID_LEVEL | n_g.w.h ] | + p_n_blueshade[ MID_LEVEL | n_b.w.h ] ); + n_x++; + n_distance--; + } + n_y++; + n_h--; + } +} + +void psxgpu_device::FlatRectangle( void ) +{ + INT16 n_y; + INT16 n_x; + + UINT8 n_cmd; + + UINT16 *p_n_f; + UINT16 *p_n_redb; + UINT16 *p_n_greenb; + UINT16 *p_n_blueb; + UINT16 *p_n_redtrans; + UINT16 *p_n_greentrans; + UINT16 *p_n_bluetrans; + + PAIR n_r; + PAIR n_g; + PAIR n_b; + + INT32 n_distance; + INT32 n_h; + UINT16 *p_vram; + +#if DEBUG_VIEWER + if( m_debug.n_skip == 8 ) + { + return; + } + DebugMesh( SINT11( COORD_X( m_packet.FlatRectangle.n_coord ) ) + n_drawoffset_x, SINT11( COORD_Y( m_packet.FlatRectangle.n_coord ) ) + n_drawoffset_y ); + DebugMesh( SINT11( COORD_X( m_packet.FlatRectangle.n_coord ) ) + n_drawoffset_x + SIZE_W( m_packet.FlatRectangle.n_size ), SINT11( COORD_Y( m_packet.FlatRectangle.n_coord ) ) + n_drawoffset_y ); + DebugMesh( SINT11( COORD_X( m_packet.FlatRectangle.n_coord ) ) + n_drawoffset_x, SINT11( COORD_Y( m_packet.FlatRectangle.n_coord ) ) + n_drawoffset_y + SIZE_H( m_packet.FlatRectangle.n_size ) ); + DebugMesh( SINT11( COORD_X( m_packet.FlatRectangle.n_coord ) ) + n_drawoffset_x + SIZE_W( m_packet.FlatRectangle.n_size ), SINT11( COORD_Y( m_packet.FlatRectangle.n_coord ) ) + n_drawoffset_y + SIZE_H( m_packet.FlatRectangle.n_size ) ); + DebugMeshEnd(); +#endif + + n_cmd = BGR_C( m_packet.FlatRectangle.n_bgr ); + + SOLIDSETUP + + n_r.w.h = BGR_R( m_packet.FlatRectangle.n_bgr ); n_r.w.l = 0; + n_g.w.h = BGR_G( m_packet.FlatRectangle.n_bgr ); n_g.w.l = 0; + n_b.w.h = BGR_B( m_packet.FlatRectangle.n_bgr ); n_b.w.l = 0; + + n_x = SINT11( COORD_X( m_packet.FlatRectangle.n_coord ) ); + n_y = SINT11( COORD_Y( m_packet.FlatRectangle.n_coord ) ); + n_h = SIZE_H( m_packet.FlatRectangle.n_size ); + + while( n_h > 0 ) + { + n_distance = SIZE_W( m_packet.FlatRectangle.n_size ); + + int drawy = n_y + n_drawoffset_y; + + if( n_distance > 0 && drawy >= (INT32)n_drawarea_y1 && drawy <= (INT32)n_drawarea_y2 ) + { + int drawx = n_x + n_drawoffset_x; + + if( ( (INT32)n_drawarea_x1 - drawx ) > 0 ) + { + n_distance -= ( n_drawarea_x1 - drawx ); + drawx = n_drawarea_x1; + } + + SOLIDFILL( FLATRECTANGEUPDATE ) + } + n_y++; + n_h--; + } +} + +void psxgpu_device::FlatRectangle8x8( void ) +{ + INT16 n_y; + INT16 n_x; + + UINT8 n_cmd; + + UINT16 *p_n_f; + UINT16 *p_n_redb; + UINT16 *p_n_greenb; + UINT16 *p_n_blueb; + UINT16 *p_n_redtrans; + UINT16 *p_n_greentrans; + UINT16 *p_n_bluetrans; + + PAIR n_r; + PAIR n_g; + PAIR n_b; + + INT32 n_distance; + INT32 n_h; + UINT16 *p_vram; + +#if DEBUG_VIEWER + if( m_debug.n_skip == 9 ) + { + return; + } + DebugMesh( SINT11( COORD_X( m_packet.FlatRectangle8x8.n_coord ) ) + n_drawoffset_x, SINT11( COORD_Y( m_packet.FlatRectangle8x8.n_coord ) ) + n_drawoffset_y ); + DebugMesh( SINT11( COORD_X( m_packet.FlatRectangle8x8.n_coord ) ) + n_drawoffset_x + 8, SINT11( COORD_Y( m_packet.FlatRectangle8x8.n_coord ) ) + n_drawoffset_y ); + DebugMesh( SINT11( COORD_X( m_packet.FlatRectangle8x8.n_coord ) ) + n_drawoffset_x, SINT11( COORD_Y( m_packet.FlatRectangle8x8.n_coord ) ) + n_drawoffset_y + 8 ); + DebugMesh( SINT11( COORD_X( m_packet.FlatRectangle8x8.n_coord ) ) + n_drawoffset_x + 8, SINT11( COORD_Y( m_packet.FlatRectangle8x8.n_coord ) ) + n_drawoffset_y + 8 ); + DebugMeshEnd(); +#endif + + n_cmd = BGR_C( m_packet.FlatRectangle8x8.n_bgr ); + + SOLIDSETUP + + n_r.w.h = BGR_R( m_packet.FlatRectangle8x8.n_bgr ); n_r.w.l = 0; + n_g.w.h = BGR_G( m_packet.FlatRectangle8x8.n_bgr ); n_g.w.l = 0; + n_b.w.h = BGR_B( m_packet.FlatRectangle8x8.n_bgr ); n_b.w.l = 0; + + n_x = SINT11( COORD_X( m_packet.FlatRectangle8x8.n_coord ) ); + n_y = SINT11( COORD_Y( m_packet.FlatRectangle8x8.n_coord ) ); + n_h = 8; + + while( n_h > 0 ) + { + n_distance = 8; + + int drawy = n_y + n_drawoffset_y; + + if( n_distance > 0 && drawy >= (INT32)n_drawarea_y1 && drawy <= (INT32)n_drawarea_y2 ) + { + int drawx = n_x + n_drawoffset_x; + + if( ( (INT32)n_drawarea_x1 - drawx ) > 0 ) + { + n_distance -= ( n_drawarea_x1 - drawx ); + drawx = n_drawarea_x1; + } + + SOLIDFILL( FLATRECTANGEUPDATE ) + } + n_y++; + n_h--; + } +} + +void psxgpu_device::FlatRectangle16x16( void ) +{ + INT16 n_y; + INT16 n_x; + + UINT8 n_cmd; + + UINT16 *p_n_f; + UINT16 *p_n_redb; + UINT16 *p_n_greenb; + UINT16 *p_n_blueb; + UINT16 *p_n_redtrans; + UINT16 *p_n_greentrans; + UINT16 *p_n_bluetrans; + + PAIR n_r; + PAIR n_g; + PAIR n_b; + + INT32 n_distance; + INT32 n_h; + UINT16 *p_vram; + +#if DEBUG_VIEWER + if( m_debug.n_skip == 10 ) + { + return; + } + DebugMesh( SINT11( COORD_X( m_packet.FlatRectangle16x16.n_coord ) ) + n_drawoffset_x, SINT11( COORD_Y( m_packet.FlatRectangle16x16.n_coord ) ) + n_drawoffset_y ); + DebugMesh( SINT11( COORD_X( m_packet.FlatRectangle16x16.n_coord ) ) + n_drawoffset_x + 16, SINT11( COORD_Y( m_packet.FlatRectangle16x16.n_coord ) ) + n_drawoffset_y ); + DebugMesh( SINT11( COORD_X( m_packet.FlatRectangle16x16.n_coord ) ) + n_drawoffset_x, SINT11( COORD_Y( m_packet.FlatRectangle16x16.n_coord ) ) + n_drawoffset_y + 16 ); + DebugMesh( SINT11( COORD_X( m_packet.FlatRectangle16x16.n_coord ) ) + n_drawoffset_x + 16, SINT11( COORD_Y( m_packet.FlatRectangle16x16.n_coord ) ) + n_drawoffset_y + 16 ); + DebugMeshEnd(); +#endif + + n_cmd = BGR_C( m_packet.FlatRectangle16x16.n_bgr ); + + SOLIDSETUP + + n_r.w.h = BGR_R( m_packet.FlatRectangle16x16.n_bgr ); n_r.w.l = 0; + n_g.w.h = BGR_G( m_packet.FlatRectangle16x16.n_bgr ); n_g.w.l = 0; + n_b.w.h = BGR_B( m_packet.FlatRectangle16x16.n_bgr ); n_b.w.l = 0; + + n_x = SINT11( COORD_X( m_packet.FlatRectangle16x16.n_coord ) ); + n_y = SINT11( COORD_Y( m_packet.FlatRectangle16x16.n_coord ) ); + n_h = 16; + + while( n_h > 0 ) + { + n_distance = 16; + + int drawy = n_y + n_drawoffset_y; + + if( n_distance > 0 && n_y >= (INT32)n_drawarea_y1 && n_y <= (INT32)n_drawarea_y2 ) + { + int drawx = n_x + n_drawoffset_x; + + if( ( (INT32)n_drawarea_x1 - drawx ) > 0 ) + { + n_distance -= ( n_drawarea_x1 - drawx ); + drawx = n_drawarea_x1; + } + + SOLIDFILL( FLATRECTANGEUPDATE ) + } + n_y++; + n_h--; + } +} + +void psxgpu_device::FlatTexturedRectangle( void ) +{ + INT16 n_y; + INT16 n_x; + int n_tx; + int n_ty; + + UINT8 n_cmd; + + UINT32 n_clutx; + UINT32 n_cluty; + + UINT16 *p_n_f; + UINT16 *p_n_redb; + UINT16 *p_n_greenb; + UINT16 *p_n_blueb; + UINT16 *p_n_redtrans; + UINT16 *p_n_greentrans; + UINT16 *p_n_bluetrans; + + PAIR n_r; + PAIR n_g; + PAIR n_b; + UINT8 n_u; + UINT8 n_v; + int n_du; + int n_dv; + + INT16 n_distance; + UINT32 n_h; + UINT16 *p_vram; + UINT16 *p_clut; + UINT16 n_bgr; + +#if DEBUG_VIEWER + if( m_debug.n_skip == 11 ) + { + return; + } + DebugMesh( SINT11( COORD_X( m_packet.FlatTexturedRectangle.n_coord ) ) + n_drawoffset_x, SINT11( COORD_Y( m_packet.FlatTexturedRectangle.n_coord ) ) + n_drawoffset_y ); + DebugMesh( SINT11( COORD_X( m_packet.FlatTexturedRectangle.n_coord ) ) + n_drawoffset_x + SIZE_W( m_packet.FlatTexturedRectangle.n_size ), SINT11( COORD_Y( m_packet.FlatTexturedRectangle.n_coord ) ) + n_drawoffset_y ); + DebugMesh( SINT11( COORD_X( m_packet.FlatTexturedRectangle.n_coord ) ) + n_drawoffset_x, SINT11( COORD_Y( m_packet.FlatTexturedRectangle.n_coord ) ) + n_drawoffset_y + SIZE_H( m_packet.FlatTexturedRectangle.n_size ) ); + DebugMesh( SINT11( COORD_X( m_packet.FlatTexturedRectangle.n_coord ) ) + n_drawoffset_x + SIZE_W( m_packet.FlatTexturedRectangle.n_size ), SINT11( COORD_Y( m_packet.FlatTexturedRectangle.n_coord ) ) + n_drawoffset_y + SIZE_H( m_packet.FlatTexturedRectangle.n_size ) ); + DebugMeshEnd(); +#endif + + n_cmd = BGR_C( m_packet.FlatTexturedRectangle.n_bgr ); + + n_clutx = ( m_packet.FlatTexturedRectangle.n_texture.w.h & 0x3f ) << 4; + n_cluty = ( m_packet.FlatTexturedRectangle.n_texture.w.h >> 6 ) & 0x3ff; + + n_r.d = 0; + n_g.d = 0; + n_b.d = 0; + + TEXTURESETUP + SPRITESETUP + + switch( n_cmd & 0x01 ) + { + case 0: + n_r.w.h = BGR_R( m_packet.FlatTexturedRectangle.n_bgr ); n_r.w.l = 0; + n_g.w.h = BGR_G( m_packet.FlatTexturedRectangle.n_bgr ); n_g.w.l = 0; + n_b.w.h = BGR_B( m_packet.FlatTexturedRectangle.n_bgr ); n_b.w.l = 0; + break; + case 1: + n_r.w.h = 0x80; n_r.w.l = 0; + n_g.w.h = 0x80; n_g.w.l = 0; + n_b.w.h = 0x80; n_b.w.l = 0; + break; + } + + n_x = SINT11( COORD_X( m_packet.FlatTexturedRectangle.n_coord ) ); + n_y = SINT11( COORD_Y( m_packet.FlatTexturedRectangle.n_coord ) ); + n_v = TEXTURE_V( m_packet.FlatTexturedRectangle.n_texture ); + n_h = SIZE_H( m_packet.FlatTexturedRectangle.n_size ); + + while( n_h > 0 ) + { + n_u = TEXTURE_U( m_packet.FlatTexturedRectangle.n_texture ); + n_distance = SIZE_W( m_packet.FlatTexturedRectangle.n_size ); + + int drawy = n_y + n_drawoffset_y; + + if( n_distance > 0 && drawy >= (INT32)n_drawarea_y1 && drawy <= (INT32)n_drawarea_y2 ) + { + int drawx = n_x + n_drawoffset_x; + + if( ( (INT32)n_drawarea_x1 - drawx ) > 0 ) + { + n_u += ( n_drawarea_x1 - drawx ) * n_du; + n_distance -= ( n_drawarea_x1 - drawx ); + drawx = n_drawarea_x1; + } + + TEXTUREFILL( FLATTEXTUREDRECTANGLEUPDATE, n_u, n_v ); + } + n_v += n_dv; + n_y++; + n_h--; + } +} + +void psxgpu_device::Sprite8x8( void ) +{ + INT16 n_y; + INT16 n_x; + int n_tx; + int n_ty; + + UINT8 n_cmd; + + UINT32 n_clutx; + UINT32 n_cluty; + + UINT16 *p_n_f; + UINT16 *p_n_redb; + UINT16 *p_n_greenb; + UINT16 *p_n_blueb; + UINT16 *p_n_redtrans; + UINT16 *p_n_greentrans; + UINT16 *p_n_bluetrans; + + PAIR n_r; + PAIR n_g; + PAIR n_b; + UINT8 n_u; + UINT8 n_v; + int n_du; + int n_dv; + + INT16 n_distance; + UINT32 n_h; + UINT16 *p_vram; + UINT16 *p_clut; + UINT16 n_bgr; + +#if DEBUG_VIEWER + if( m_debug.n_skip == 12 ) + { + return; + } + DebugMesh( SINT11( COORD_X( m_packet.Sprite8x8.n_coord ) ) + n_drawoffset_x, SINT11( COORD_Y( m_packet.Sprite8x8.n_coord ) ) + n_drawoffset_y ); + DebugMesh( SINT11( COORD_X( m_packet.Sprite8x8.n_coord ) ) + n_drawoffset_x + 7, SINT11( COORD_Y( m_packet.Sprite8x8.n_coord ) ) + n_drawoffset_y ); + DebugMesh( SINT11( COORD_X( m_packet.Sprite8x8.n_coord ) ) + n_drawoffset_x, SINT11( COORD_Y( m_packet.Sprite8x8.n_coord ) ) + n_drawoffset_y + 7 ); + DebugMesh( SINT11( COORD_X( m_packet.Sprite8x8.n_coord ) ) + n_drawoffset_x + 7, SINT11( COORD_Y( m_packet.Sprite8x8.n_coord ) ) + n_drawoffset_y + 7 ); + DebugMeshEnd(); +#endif + + n_cmd = BGR_C( m_packet.Sprite8x8.n_bgr ); + + n_clutx = ( m_packet.Sprite8x8.n_texture.w.h & 0x3f ) << 4; + n_cluty = ( m_packet.Sprite8x8.n_texture.w.h >> 6 ) & 0x3ff; + + n_r.d = 0; + n_g.d = 0; + n_b.d = 0; + + TEXTURESETUP + SPRITESETUP + + switch( n_cmd & 0x01 ) + { + case 0: + n_r.w.h = BGR_R( m_packet.Sprite8x8.n_bgr ); n_r.w.l = 0; + n_g.w.h = BGR_G( m_packet.Sprite8x8.n_bgr ); n_g.w.l = 0; + n_b.w.h = BGR_B( m_packet.Sprite8x8.n_bgr ); n_b.w.l = 0; + break; + case 1: + n_r.w.h = 0x80; n_r.w.l = 0; + n_g.w.h = 0x80; n_g.w.l = 0; + n_b.w.h = 0x80; n_b.w.l = 0; + break; + } + + n_x = SINT11( COORD_X( m_packet.Sprite8x8.n_coord ) ); + n_y = SINT11( COORD_Y( m_packet.Sprite8x8.n_coord ) ); + n_v = TEXTURE_V( m_packet.Sprite8x8.n_texture ); + n_h = 8; + + while( n_h > 0 ) + { + n_u = TEXTURE_U( m_packet.Sprite8x8.n_texture ); + n_distance = 8; + + int drawy = n_y + n_drawoffset_y; + + if( n_distance > 0 && drawy >= (INT32)n_drawarea_y1 && drawy <= (INT32)n_drawarea_y2 ) + { + int drawx = n_x + n_drawoffset_x; + + if( ( (INT32)n_drawarea_x1 - drawx ) > 0 ) + { + n_u += ( n_drawarea_x1 - drawx ) * n_du; + n_distance -= ( n_drawarea_x1 - drawx ); + drawx = n_drawarea_x1; + } + + TEXTUREFILL( FLATTEXTUREDRECTANGLEUPDATE, n_u, n_v ); + } + n_v += n_dv; + n_y++; + n_h--; + } +} + +void psxgpu_device::Sprite16x16( void ) +{ + INT16 n_y; + INT16 n_x; + int n_tx; + int n_ty; + + UINT8 n_cmd; + + UINT32 n_clutx; + UINT32 n_cluty; + + UINT16 *p_n_f; + UINT16 *p_n_redb; + UINT16 *p_n_greenb; + UINT16 *p_n_blueb; + UINT16 *p_n_redtrans; + UINT16 *p_n_greentrans; + UINT16 *p_n_bluetrans; + + PAIR n_r; + PAIR n_g; + PAIR n_b; + UINT8 n_u; + UINT8 n_v; + int n_du; + int n_dv; + + INT16 n_distance; + UINT32 n_h; + UINT16 *p_vram; + UINT16 *p_clut; + UINT16 n_bgr; + +#if DEBUG_VIEWER + if( m_debug.n_skip == 13 ) + { + return; + } + DebugMesh( SINT11( COORD_X( m_packet.Sprite16x16.n_coord ) ) + n_drawoffset_x, SINT11( COORD_Y( m_packet.Sprite16x16.n_coord ) ) + n_drawoffset_y ); + DebugMesh( SINT11( COORD_X( m_packet.Sprite16x16.n_coord ) ) + n_drawoffset_x + 7, SINT11( COORD_Y( m_packet.Sprite16x16.n_coord ) ) + n_drawoffset_y ); + DebugMesh( SINT11( COORD_X( m_packet.Sprite16x16.n_coord ) ) + n_drawoffset_x, SINT11( COORD_Y( m_packet.Sprite16x16.n_coord ) ) + n_drawoffset_y + 7 ); + DebugMesh( SINT11( COORD_X( m_packet.Sprite16x16.n_coord ) ) + n_drawoffset_x + 7, SINT11( COORD_Y( m_packet.Sprite16x16.n_coord ) ) + n_drawoffset_y + 7 ); + DebugMeshEnd(); +#endif + + n_cmd = BGR_C( m_packet.Sprite16x16.n_bgr ); + + n_clutx = ( m_packet.Sprite16x16.n_texture.w.h & 0x3f ) << 4; + n_cluty = ( m_packet.Sprite16x16.n_texture.w.h >> 6 ) & 0x3ff; + + n_r.d = 0; + n_g.d = 0; + n_b.d = 0; + + TEXTURESETUP + SPRITESETUP + + switch( n_cmd & 0x01 ) + { + case 0: + n_r.w.h = BGR_R( m_packet.Sprite16x16.n_bgr ); n_r.w.l = 0; + n_g.w.h = BGR_G( m_packet.Sprite16x16.n_bgr ); n_g.w.l = 0; + n_b.w.h = BGR_B( m_packet.Sprite16x16.n_bgr ); n_b.w.l = 0; + break; + case 1: + n_r.w.h = 0x80; n_r.w.l = 0; + n_g.w.h = 0x80; n_g.w.l = 0; + n_b.w.h = 0x80; n_b.w.l = 0; + break; + } + + n_x = SINT11( COORD_X( m_packet.Sprite16x16.n_coord ) ); + n_y = SINT11( COORD_Y( m_packet.Sprite16x16.n_coord ) ); + n_v = TEXTURE_V( m_packet.Sprite16x16.n_texture ); + n_h = 16; + + while( n_h > 0 ) + { + n_u = TEXTURE_U( m_packet.Sprite16x16.n_texture ); + n_distance = 16; + + int drawy = n_y + n_drawoffset_y; + + if( n_distance > 0 && drawy >= (INT32)n_drawarea_y1 && drawy <= (INT32)n_drawarea_y2 ) + { + int drawx = n_x + n_drawoffset_x; + + if( ( (INT32)n_drawarea_x1 - drawx ) > 0 ) + { + n_u += ( n_drawarea_x1 - drawx ) * n_du; + n_distance -= ( n_drawarea_x1 - drawx ); + drawx = n_drawarea_x1; + } + + TEXTUREFILL( FLATTEXTUREDRECTANGLEUPDATE, n_u, n_v ); + } + n_v += n_dv; + n_y++; + n_h--; + } +} + +void psxgpu_device::Dot( void ) +{ + INT32 n_x; + INT32 n_y; + UINT32 n_r; + UINT32 n_g; + UINT32 n_b; + UINT16 *p_vram; + +#if DEBUG_VIEWER + if( m_debug.n_skip == 14 ) + { + return; + } + DebugMesh( SINT11( COORD_X( m_packet.Dot.vertex.n_coord ) ) + n_drawoffset_x, SINT11( COORD_Y( m_packet.Dot.vertex.n_coord ) ) + n_drawoffset_y ); + DebugMeshEnd(); +#endif + + n_r = BGR_R( m_packet.Dot.n_bgr ); + n_g = BGR_G( m_packet.Dot.n_bgr ); + n_b = BGR_B( m_packet.Dot.n_bgr ); + n_x = SINT11( COORD_X( m_packet.Dot.vertex.n_coord ) ); + n_y = SINT11( COORD_Y( m_packet.Dot.vertex.n_coord ) ); + + int drawx = n_x + n_drawoffset_x; + int drawy = n_y + n_drawoffset_y; + + if( drawx >= (INT32)n_drawarea_x1 && drawy >= (INT32)n_drawarea_y1 && + drawx <= (INT32)n_drawarea_x2 && drawy <= (INT32)n_drawarea_y2 ) + { + p_vram = p_p_vram[ drawy ] + drawx; + WRITE_PIXEL( + p_n_redshade[ MID_LEVEL | n_r ] | + p_n_greenshade[ MID_LEVEL | n_g ] | + p_n_blueshade[ MID_LEVEL | n_b ] ); + } +} + +void psxgpu_device::MoveImage( void ) +{ + INT16 n_w; + INT16 n_h; + INT16 n_srcx; + INT16 n_srcy; + INT16 n_dsty; + INT16 n_dstx; + UINT16 *p_vram; + +#if DEBUG_VIEWER + if( m_debug.n_skip == 15 ) + { + return; + } + DebugMesh( SINT11( COORD_X( m_packet.MoveImage.vertex[ 1 ].n_coord ) ), SINT11( COORD_Y( m_packet.MoveImage.vertex[ 1 ].n_coord ) ) ); + DebugMesh( SINT11( COORD_X( m_packet.MoveImage.vertex[ 1 ].n_coord ) ) + SIZE_W( m_packet.MoveImage.n_size ), SINT11( COORD_Y( m_packet.MoveImage.vertex[ 1 ].n_coord ) ) ); + DebugMesh( SINT11( COORD_X( m_packet.MoveImage.vertex[ 1 ].n_coord ) ), SINT11( COORD_Y( m_packet.MoveImage.vertex[ 1 ].n_coord ) ) + SIZE_H( m_packet.MoveImage.n_size ) ); + DebugMesh( SINT11( COORD_X( m_packet.MoveImage.vertex[ 1 ].n_coord ) ) + SIZE_W( m_packet.MoveImage.n_size ), SINT11( COORD_Y( m_packet.MoveImage.vertex[ 1 ].n_coord ) ) + SIZE_H( m_packet.MoveImage.n_size ) ); + DebugMeshEnd(); +#endif + + n_srcy = COORD_Y( m_packet.MoveImage.vertex[ 0 ].n_coord ); + n_dsty = COORD_Y( m_packet.MoveImage.vertex[ 1 ].n_coord ); + n_h = SIZE_H( m_packet.MoveImage.n_size ); + + while( n_h > 0 ) + { + n_srcx = COORD_X( m_packet.MoveImage.vertex[ 0 ].n_coord ); + n_dstx = COORD_X( m_packet.MoveImage.vertex[ 1 ].n_coord ); + n_w = SIZE_W( m_packet.MoveImage.n_size ); + while( n_w > 0 ) + { + p_vram = p_p_vram[ n_dsty & 1023 ] + ( n_dstx & 1023 ); + WRITE_PIXEL( *( p_p_vram[ n_srcy & 1023 ] + ( n_srcx & 1023 ) ) ); + n_srcx++; + n_dstx++; + n_w--; + } + n_srcy++; + n_dsty++; + n_h--; + } +} + +void psxgpu_device::dma_write( UINT32 *p_n_psxram, UINT32 n_address, INT32 n_size ) +{ + gpu_write( &p_n_psxram[ n_address / 4 ], n_size ); +} + +void psxgpu_device::gpu_write( UINT32 *p_ram, INT32 n_size ) +{ + while( n_size > 0 ) + { + UINT32 data = *( p_ram ); + + verboselog( machine(), 2, "PSX Packet #%u %08x\n", n_gpu_buffer_offset, data ); + m_packet.n_entry[ n_gpu_buffer_offset ] = data; + switch( m_packet.n_entry[ 0 ] >> 24 ) + { + case 0x00: + verboselog( machine(), 1, "not handled: GPU Command 0x00: (%08x)\n", data ); + break; + case 0x01: + verboselog( machine(), 1, "not handled: clear cache\n" ); + break; + case 0x02: + if( n_gpu_buffer_offset < 2 ) + { + n_gpu_buffer_offset++; + } + else + { + verboselog( machine(), 1, "%02x: frame buffer rectangle %u,%u %u,%u\n", m_packet.n_entry[ 0 ] >> 24, + m_packet.n_entry[ 1 ] & 0xffff, m_packet.n_entry[ 1 ] >> 16, m_packet.n_entry[ 2 ] & 0xffff, m_packet.n_entry[ 2 ] >> 16 ); + FrameBufferRectangleDraw(); + n_gpu_buffer_offset = 0; + } + break; + case 0x20: + case 0x21: + case 0x22: + case 0x23: + if( n_gpu_buffer_offset < 3 ) + { + n_gpu_buffer_offset++; + } + else + { + verboselog( machine(), 1, "%02x: monochrome 3 point polygon\n", m_packet.n_entry[ 0 ] >> 24 ); + FlatPolygon( 3 ); + n_gpu_buffer_offset = 0; + } + break; + case 0x24: + case 0x25: + case 0x26: + case 0x27: + if( n_gpu_buffer_offset < 6 ) + { + n_gpu_buffer_offset++; + } + else + { + verboselog( machine(), 1, "%02x: textured 3 point polygon\n", m_packet.n_entry[ 0 ] >> 24 ); + FlatTexturedPolygon( 3 ); + n_gpu_buffer_offset = 0; + } + break; + case 0x28: + case 0x29: + case 0x2a: + case 0x2b: + if( n_gpu_buffer_offset < 4 ) + { + n_gpu_buffer_offset++; + } + else + { + verboselog( machine(), 1, "%02x: monochrome 4 point polygon\n", m_packet.n_entry[ 0 ] >> 24 ); + FlatPolygon( 4 ); + n_gpu_buffer_offset = 0; + } + break; + case 0x2c: + case 0x2d: + case 0x2e: + case 0x2f: + if( n_gpu_buffer_offset < 8 ) + { + n_gpu_buffer_offset++; + } + else + { + verboselog( machine(), 1, "%02x: textured 4 point polygon\n", m_packet.n_entry[ 0 ] >> 24 ); + FlatTexturedPolygon( 4 ); + n_gpu_buffer_offset = 0; + } + break; + case 0x30: + case 0x31: + case 0x32: + case 0x33: + if( n_gpu_buffer_offset < 5 ) + { + n_gpu_buffer_offset++; + } + else + { + verboselog( machine(), 1, "%02x: gouraud 3 point polygon\n", m_packet.n_entry[ 0 ] >> 24 ); + GouraudPolygon( 3 ); + n_gpu_buffer_offset = 0; + } + break; + case 0x34: + case 0x35: + case 0x36: + case 0x37: + if( n_gpu_buffer_offset < 8 ) + { + n_gpu_buffer_offset++; + } + else + { + verboselog( machine(), 1, "%02x: gouraud textured 3 point polygon\n", m_packet.n_entry[ 0 ] >> 24 ); + GouraudTexturedPolygon( 3 ); + n_gpu_buffer_offset = 0; + } + break; + case 0x38: + case 0x39: + case 0x3a: + case 0x3b: + if( n_gpu_buffer_offset < 7 ) + { + n_gpu_buffer_offset++; + } + else + { + verboselog( machine(), 1, "%02x: gouraud 4 point polygon\n", m_packet.n_entry[ 0 ] >> 24 ); + GouraudPolygon( 4 ); + n_gpu_buffer_offset = 0; + } + break; + case 0x3c: + case 0x3d: + case 0x3e: + case 0x3f: + if( n_gpu_buffer_offset < 11 ) + { + n_gpu_buffer_offset++; + } + else + { + verboselog( machine(), 1, "%02x: gouraud textured 4 point polygon\n", m_packet.n_entry[ 0 ] >> 24 ); + GouraudTexturedPolygon( 4 ); + n_gpu_buffer_offset = 0; + } + break; + case 0x40: + case 0x41: + case 0x42: + if( n_gpu_buffer_offset < 2 ) + { + n_gpu_buffer_offset++; + } + else + { + verboselog( machine(), 1, "%02x: monochrome line\n", m_packet.n_entry[ 0 ] >> 24 ); + MonochromeLine(); + n_gpu_buffer_offset = 0; + } + break; + case 0x48: + case 0x4a: + case 0x4c: + case 0x4e: + if( n_gpu_buffer_offset < 3 ) + { + n_gpu_buffer_offset++; + } + else + { + verboselog( machine(), 1, "%02x: monochrome polyline\n", m_packet.n_entry[ 0 ] >> 24 ); + MonochromeLine(); + if( ( m_packet.n_entry[ 3 ] & 0xf000f000 ) != 0x50005000 ) + { + m_packet.n_entry[ 1 ] = m_packet.n_entry[ 2 ]; + m_packet.n_entry[ 2 ] = m_packet.n_entry[ 3 ]; + n_gpu_buffer_offset = 3; + } + else + { + n_gpu_buffer_offset = 0; + } + } + break; + case 0x50: + case 0x51: + case 0x52: + case 0x53: + if( n_gpu_buffer_offset < 3 ) + { + n_gpu_buffer_offset++; + } + else + { + verboselog( machine(), 1, "%02x: gouraud line\n", m_packet.n_entry[ 0 ] >> 24 ); + GouraudLine(); + n_gpu_buffer_offset = 0; + } + break; + case 0x58: + case 0x5a: + case 0x5c: + case 0x5e: + if( n_gpu_buffer_offset < 5 && + ( n_gpu_buffer_offset != 4 || ( m_packet.n_entry[ 4 ] & 0xf000f000 ) != 0x50005000 ) ) + { + n_gpu_buffer_offset++; + } + else + { + verboselog( machine(), 1, "%02x: gouraud polyline\n", m_packet.n_entry[ 0 ] >> 24 ); + GouraudLine(); + if( ( m_packet.n_entry[ 4 ] & 0xf000f000 ) != 0x50005000 ) + { + m_packet.n_entry[ 0 ] = ( m_packet.n_entry[ 0 ] & 0xff000000 ) | ( m_packet.n_entry[ 2 ] & 0x00ffffff ); + m_packet.n_entry[ 1 ] = m_packet.n_entry[ 3 ]; + m_packet.n_entry[ 2 ] = m_packet.n_entry[ 4 ]; + m_packet.n_entry[ 3 ] = m_packet.n_entry[ 5 ]; + n_gpu_buffer_offset = 4; + } + else + { + n_gpu_buffer_offset = 0; + } + } + break; + case 0x60: + case 0x61: + case 0x62: + case 0x63: + if( n_gpu_buffer_offset < 2 ) + { + n_gpu_buffer_offset++; + } + else + { + verboselog( machine(), 1, "%02x: rectangle %d,%d %d,%d\n", + m_packet.n_entry[ 0 ] >> 24, + (INT16)( m_packet.n_entry[ 1 ] & 0xffff ), (INT16)( m_packet.n_entry[ 1 ] >> 16 ), + (INT16)( m_packet.n_entry[ 2 ] & 0xffff ), (INT16)( m_packet.n_entry[ 2 ] >> 16 ) ); + FlatRectangle(); + n_gpu_buffer_offset = 0; + } + break; + case 0x64: + case 0x65: + case 0x66: + case 0x67: + if( n_gpu_buffer_offset < 3 ) + { + n_gpu_buffer_offset++; + } + else + { + verboselog( machine(), 1, "%02x: sprite %d,%d %u,%u %08x, %08x\n", + m_packet.n_entry[ 0 ] >> 24, + (INT16)( m_packet.n_entry[ 1 ] & 0xffff ), (INT16)( m_packet.n_entry[ 1 ] >> 16 ), + m_packet.n_entry[ 3 ] & 0xffff, m_packet.n_entry[ 3 ] >> 16, + m_packet.n_entry[ 0 ], m_packet.n_entry[ 2 ] ); + FlatTexturedRectangle(); + n_gpu_buffer_offset = 0; + } + break; + case 0x68: + case 0x6a: + if( n_gpu_buffer_offset < 1 ) + { + n_gpu_buffer_offset++; + } + else + { + verboselog( machine(), 1, "%02x: dot %d,%d %08x\n", + m_packet.n_entry[ 0 ] >> 24, + (INT16)( m_packet.n_entry[ 1 ] & 0xffff ), (INT16)( m_packet.n_entry[ 1 ] >> 16 ), + m_packet.n_entry[ 0 ] & 0xffffff ); + Dot(); + n_gpu_buffer_offset = 0; + } + break; + case 0x70: + case 0x71: + /* 8*8 rectangle */ + if( n_gpu_buffer_offset < 1 ) + { + n_gpu_buffer_offset++; + } + else + { + verboselog( machine(), 1, "%02x: 16x16 rectangle %08x %08x\n", m_packet.n_entry[ 0 ] >> 24, + m_packet.n_entry[ 0 ], m_packet.n_entry[ 1 ] ); + FlatRectangle8x8(); + n_gpu_buffer_offset = 0; + } + break; + case 0x74: + case 0x75: + case 0x76: + case 0x77: + if( n_gpu_buffer_offset < 2 ) + { + n_gpu_buffer_offset++; + } + else + { + verboselog( machine(), 1, "%02x: 8x8 sprite %08x %08x %08x\n", m_packet.n_entry[ 0 ] >> 24, + m_packet.n_entry[ 0 ], m_packet.n_entry[ 1 ], m_packet.n_entry[ 2 ] ); + Sprite8x8(); + n_gpu_buffer_offset = 0; + } + break; + case 0x78: + case 0x79: + /* 16*16 rectangle */ + if( n_gpu_buffer_offset < 1 ) + { + n_gpu_buffer_offset++; + } + else + { + verboselog( machine(), 1, "%02x: 16x16 rectangle %08x %08x\n", m_packet.n_entry[ 0 ] >> 24, + m_packet.n_entry[ 0 ], m_packet.n_entry[ 1 ] ); + FlatRectangle16x16(); + n_gpu_buffer_offset = 0; + } + break; + case 0x7c: + case 0x7d: + case 0x7e: + case 0x7f: + if( n_gpu_buffer_offset < 2 ) + { + n_gpu_buffer_offset++; + } + else + { + verboselog( machine(), 1, "%02x: 16x16 sprite %08x %08x %08x\n", m_packet.n_entry[ 0 ] >> 24, + m_packet.n_entry[ 0 ], m_packet.n_entry[ 1 ], m_packet.n_entry[ 2 ] ); + Sprite16x16(); + n_gpu_buffer_offset = 0; + } + break; + case 0x80: + if( n_gpu_buffer_offset < 3 ) + { + n_gpu_buffer_offset++; + } + else + { + verboselog( machine(), 1, "move image in frame buffer %08x %08x %08x %08x\n", m_packet.n_entry[ 0 ], m_packet.n_entry[ 1 ], m_packet.n_entry[ 2 ], m_packet.n_entry[ 3 ] ); + MoveImage(); + n_gpu_buffer_offset = 0; + } + break; + case 0xa0: + if( n_gpu_buffer_offset < 3 ) + { + n_gpu_buffer_offset++; + } + else + { + UINT32 n_pixel; + for( n_pixel = 0; n_pixel < 2; n_pixel++ ) + { + UINT16 *p_vram; + + verboselog( machine(), 2, "send image to framebuffer ( pixel %u,%u = %u )\n", + ( n_vramx + m_packet.n_entry[ 1 ] ) & 1023, + ( n_vramy + ( m_packet.n_entry[ 1 ] >> 16 ) ) & 1023, + data & 0xffff ); + + p_vram = p_p_vram[ ( n_vramy + ( m_packet.n_entry[ 1 ] >> 16 ) ) & 1023 ] + ( ( n_vramx + m_packet.n_entry[ 1 ] ) & 1023 ); + WRITE_PIXEL( data & 0xffff ); + n_vramx++; + if( n_vramx >= ( m_packet.n_entry[ 2 ] & 0xffff ) ) + { + n_vramx = 0; + n_vramy++; + if( n_vramy >= ( m_packet.n_entry[ 2 ] >> 16 ) ) + { + verboselog( machine(), 1, "%02x: send image to framebuffer %u,%u %u,%u\n", m_packet.n_entry[ 0 ] >> 24, + m_packet.n_entry[ 1 ] & 0xffff, ( m_packet.n_entry[ 1 ] >> 16 ), + m_packet.n_entry[ 2 ] & 0xffff, ( m_packet.n_entry[ 2 ] >> 16 ) ); + n_gpu_buffer_offset = 0; + n_vramx = 0; + n_vramy = 0; + break; + } + } + data >>= 16; + } + } + break; + case 0xc0: + if( n_gpu_buffer_offset < 2 ) + { + n_gpu_buffer_offset++; + } + else + { + verboselog( machine(), 1, "%02x: copy image from frame buffer\n", m_packet.n_entry[ 0 ] >> 24 ); + n_gpustatus |= ( 1L << 0x1b ); + } + break; + case 0xe1: + verboselog( machine(), 1, "%02x: draw mode %06x\n", m_packet.n_entry[ 0 ] >> 24, + m_packet.n_entry[ 0 ] & 0xffffff ); + decode_tpage( m_packet.n_entry[ 0 ] & 0xffffff ); + break; + case 0xe2: + n_twy = ( ( ( m_packet.n_entry[ 0 ] >> 15 ) & 0x1f ) << 3 ); + n_twx = ( ( ( m_packet.n_entry[ 0 ] >> 10 ) & 0x1f ) << 3 ); + n_twh = 255 - ( ( ( m_packet.n_entry[ 0 ] >> 5 ) & 0x1f ) << 3 ); + n_tww = 255 - ( ( m_packet.n_entry[ 0 ] & 0x1f ) << 3 ); + verboselog( machine(), 1, "%02x: texture window %u,%u %u,%u\n", m_packet.n_entry[ 0 ] >> 24, + n_twx, n_twy, n_tww, n_twh ); + break; + case 0xe3: + n_drawarea_x1 = m_packet.n_entry[ 0 ] & 1023; + if( m_n_gputype == 2 ) + { + n_drawarea_y1 = ( m_packet.n_entry[ 0 ] >> 10 ) & 1023; + } + else + { + n_drawarea_y1 = ( m_packet.n_entry[ 0 ] >> 12 ) & 1023; + } + verboselog( machine(), 1, "%02x: drawing area top left %d,%d\n", m_packet.n_entry[ 0 ] >> 24, + n_drawarea_x1, n_drawarea_y1 ); + break; + case 0xe4: + n_drawarea_x2 = m_packet.n_entry[ 0 ] & 1023; + if( m_n_gputype == 2 ) + { + n_drawarea_y2 = ( m_packet.n_entry[ 0 ] >> 10 ) & 1023; + } + else + { + n_drawarea_y2 = ( m_packet.n_entry[ 0 ] >> 12 ) & 1023; + } + verboselog( machine(), 1, "%02x: drawing area bottom right %d,%d\n", m_packet.n_entry[ 0 ] >> 24, + n_drawarea_x2, n_drawarea_y2 ); + break; + case 0xe5: + n_drawoffset_x = SINT11( m_packet.n_entry[ 0 ] & 2047 ); + if( m_n_gputype == 2 ) + { + n_drawoffset_y = SINT11( ( m_packet.n_entry[ 0 ] >> 11 ) & 2047 ); + } + else + { + n_drawoffset_y = SINT11( ( m_packet.n_entry[ 0 ] >> 12 ) & 2047 ); + } + verboselog( machine(), 1, "%02x: drawing offset %d,%d\n", m_packet.n_entry[ 0 ] >> 24, + n_drawoffset_x, n_drawoffset_y ); + break; + case 0xe6: + n_gpustatus &= ~( 3L << 0xb ); + n_gpustatus |= ( data & 0x03 ) << 0xb; + if( ( m_packet.n_entry[ 0 ] & 3 ) != 0 ) + { + verboselog( machine(), 1, "not handled: mask setting %d\n", m_packet.n_entry[ 0 ] & 3 ); + } + else + { + verboselog( machine(), 1, "mask setting %d\n", m_packet.n_entry[ 0 ] & 3 ); + } + break; + default: +#if defined( MAME_DEBUG ) + popmessage( "unknown GPU packet %08x", m_packet.n_entry[ 0 ] ); +#endif + verboselog( machine(), 0, "unknown GPU packet %08x (%08x)\n", m_packet.n_entry[ 0 ], data ); +#if ( STOP_ON_ERROR ) + n_gpu_buffer_offset = 1; +#endif + break; + } + p_ram++; + n_size--; + } +} + +WRITE32_MEMBER( psxgpu_device::write ) +{ + switch( offset ) + { + case 0x00: + gpu_write( &data, 1 ); + break; + case 0x01: + switch( data >> 24 ) + { + case 0x00: + gpu_reset(); + break; + case 0x01: + verboselog( machine(), 1, "not handled: reset command buffer\n" ); + n_gpu_buffer_offset = 0; + break; + case 0x02: + verboselog( machine(), 1, "not handled: reset irq\n" ); + break; + case 0x03: + n_gpustatus &= ~( 1L << 0x17 ); + n_gpustatus |= ( data & 0x01 ) << 0x17; + break; + case 0x04: + verboselog( machine(), 1, "dma setup %d\n", data & 3 ); + n_gpustatus &= ~( 3L << 0x1d ); + n_gpustatus |= ( data & 0x03 ) << 0x1d; + n_gpustatus &= ~( 1L << 0x19 ); + if( ( data & 3 ) == 1 || ( data & 3 ) == 2 ) + { + n_gpustatus |= ( 1L << 0x19 ); + } + break; + case 0x05: + m_n_displaystartx = data & 1023; + if( m_n_gputype == 2 ) + { + n_displaystarty = ( data >> 10 ) & 1023; + } + else + { + n_displaystarty = ( data >> 12 ) & 1023; + } + verboselog( machine(), 1, "start of display area %d %d\n", m_n_displaystartx, n_displaystarty ); + break; + case 0x06: + n_horiz_disstart = data & 4095; + n_horiz_disend = ( data >> 12 ) & 4095; + verboselog( machine(), 1, "horizontal display range %d %d\n", n_horiz_disstart, n_horiz_disend ); + break; + case 0x07: + n_vert_disstart = data & 1023; + n_vert_disend = ( data >> 10 ) & 2047; + verboselog( machine(), 1, "vertical display range %d %d\n", n_vert_disstart, n_vert_disend ); + break; + case 0x08: + verboselog( machine(), 1, "display mode %02x\n", data & 0xff ); + n_gpustatus &= ~( 127L << 0x10 ); + n_gpustatus |= ( data & 0x3f ) << 0x11; /* width 0 + height + videmode + isrgb24 + isinter */ + n_gpustatus |= ( ( data & 0x40 ) >> 0x06 ) << 0x10; /* width 1 */ + if( m_n_gputype == 1 ) + { + b_reverseflag = ( data >> 7 ) & 1; + } + updatevisiblearea(); + break; + case 0x09: + verboselog( machine(), 1, "not handled: GPU Control 0x09: %08x\n", data ); + break; + case 0x0d: + verboselog( machine(), 1, "reset lightgun coordinates %08x\n", data ); + n_lightgun_x = 0; + n_lightgun_y = 0; + break; + case 0x10: + switch( data & 0xff ) + { + case 0x03: + if( m_n_gputype == 2 ) + { + n_gpuinfo = n_drawarea_x1 | ( n_drawarea_y1 << 10 ); + } + else + { + n_gpuinfo = n_drawarea_x1 | ( n_drawarea_y1 << 12 ); + } + verboselog( machine(), 1, "GPU Info - Draw area top left %08x\n", n_gpuinfo ); + break; + case 0x04: + if( m_n_gputype == 2 ) + { + n_gpuinfo = n_drawarea_x2 | ( n_drawarea_y2 << 10 ); + } + else + { + n_gpuinfo = n_drawarea_x2 | ( n_drawarea_y2 << 12 ); + } + verboselog( machine(), 1, "GPU Info - Draw area bottom right %08x\n", n_gpuinfo ); + break; + case 0x05: + if( m_n_gputype == 2 ) + { + n_gpuinfo = ( n_drawoffset_x & 2047 ) | ( ( n_drawoffset_y & 2047 ) << 11 ); + } + else + { + n_gpuinfo = ( n_drawoffset_x & 2047 ) | ( ( n_drawoffset_y & 2047 ) << 12 ); + } + verboselog( machine(), 1, "GPU Info - Draw offset %08x\n", n_gpuinfo ); + break; + case 0x07: + n_gpuinfo = m_n_gputype; + verboselog( machine(), 1, "GPU Info - GPU Type %08x\n", n_gpuinfo ); + break; + case 0x08: + n_gpuinfo = n_lightgun_x | ( n_lightgun_y << 16 ); + verboselog( machine(), 1, "GPU Info - lightgun coordinates %08x\n", n_gpuinfo ); + break; + default: + verboselog( machine(), 0, "GPU Info - unknown request (%08x)\n", data ); + n_gpuinfo = 0; + break; + } + break; + case 0x20: + verboselog( machine(), 1, "not handled: GPU Control 0x20: %08x\n", data ); + break; + default: +#if defined( MAME_DEBUG ) + popmessage( "unknown GPU command %08x", data ); +#endif + verboselog( machine(), 0, "gpu_w( %08x ) unknown GPU command\n", data ); + break; + } + break; + default: + verboselog( machine(), 0, "gpu_w( %08x, %08x, %08x ) unknown register\n", offset, data, mem_mask ); + break; + } +} + + +void psxgpu_device::dma_read( UINT32 *p_n_psxram, UINT32 n_address, INT32 n_size ) +{ + gpu_read( &p_n_psxram[ n_address / 4 ], n_size ); +} + +void psxgpu_device::gpu_read( UINT32 *p_ram, INT32 n_size ) +{ + while( n_size > 0 ) + { + if( ( n_gpustatus & ( 1L << 0x1b ) ) != 0 ) + { + UINT32 n_pixel; + PAIR data; + + verboselog( machine(), 2, "copy image from frame buffer ( %d, %d )\n", n_vramx, n_vramy ); + data.d = 0; + for( n_pixel = 0; n_pixel < 2; n_pixel++ ) + { + data.w.l = data.w.h; + data.w.h = *( p_p_vram[ ( n_vramy + ( m_packet.n_entry[ 1 ] >> 16 ) ) & 0x3ff ] + ( ( n_vramx + ( m_packet.n_entry[ 1 ] & 0xffff ) ) & 0x3ff ) ); + n_vramx++; + if( n_vramx >= ( m_packet.n_entry[ 2 ] & 0xffff ) ) + { + n_vramx = 0; + n_vramy++; + if( n_vramy >= ( m_packet.n_entry[ 2 ] >> 16 ) ) + { + verboselog( machine(), 1, "copy image from frame buffer end\n" ); + n_gpustatus &= ~( 1L << 0x1b ); + n_gpu_buffer_offset = 0; + n_vramx = 0; + n_vramy = 0; + if( n_pixel == 0 ) + { + data.w.l = data.w.h; + data.w.h = 0; + } + break; + } + } + } + *( p_ram ) = data.d; + } + else + { + verboselog( machine(), 2, "read GPU info (%08x)\n", n_gpuinfo ); + *( p_ram ) = n_gpuinfo; + } + p_ram++; + n_size--; + } +} + +READ32_MEMBER( psxgpu_device::read ) +{ + UINT32 data; + + switch( offset ) + { + case 0x00: + gpu_read( &data, 1 ); + break; + case 0x01: + data = n_gpustatus; + verboselog( machine(), 1, "read GPU status (%08x)\n", data ); + break; + default: + verboselog( machine(), 0, "gpu_r( %08x, %08x ) unknown register\n", offset, mem_mask ); + data = 0; + break; + } + return data; +} + +void psxgpu_device::vblank(screen_device &screen, bool vblank_state) +{ + if( vblank_state ) + { +#if DEBUG_VIEWER + DebugCheckKeys(); +#endif + + n_gpustatus ^= ( 1L << 31 ); + m_vblank_handler(1); + } +} + +void psxgpu_device::gpu_reset( void ) +{ + verboselog( machine(), 1, "reset gpu\n" ); + n_gpu_buffer_offset = 0; + n_gpustatus = 0x14802000; + n_drawarea_x1 = 0; + n_drawarea_y1 = 0; + n_drawarea_x2 = 1023; + n_drawarea_y2 = 1023; + n_drawoffset_x = 0; + n_drawoffset_y = 0; + m_n_displaystartx = 0; + n_displaystarty = 0; + n_horiz_disstart = 0x260; + n_horiz_disend = 0xc60; + n_vert_disstart = 0x010; + n_vert_disend = 0x100; + n_vramx = 0; + n_vramy = 0; + n_twx = 0; + n_twy = 0; + n_twh = 255; + n_tww = 255; + updatevisiblearea(); +} + +void psxgpu_device::lightgun_set( int n_x, int n_y ) +{ + n_lightgun_x = n_x; + n_lightgun_y = n_y; +} + +PALETTE_INIT_MEMBER( psxgpu_device, psx ) +{ + UINT32 n_colour; + + for( n_colour = 0; n_colour < 0x10000; n_colour++ ) + { + palette.set_pen_color( n_colour, pal555(n_colour,0, 5, 10) ); + } +} + +MACHINE_CONFIG_FRAGMENT( psxgpu ) + MCFG_SCREEN_ADD("screen", RASTER) + MCFG_SCREEN_REFRESH_RATE( 60 ) + MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(2500) /* not accurate */) + MCFG_SCREEN_SIZE( 1024, 1024 ) + MCFG_SCREEN_VISIBLE_AREA( 0, 639, 0, 479 ) + MCFG_SCREEN_UPDATE_DEVICE( DEVICE_SELF, psxgpu_device, update_screen ) + ((screen_device *)device)->register_vblank_callback(vblank_state_delegate(FUNC(psxgpu_device::vblank), (psxgpu_device *) owner)); + MCFG_SCREEN_PALETTE("palette") + + MCFG_PALETTE_ADD( "palette", 65536 ) + MCFG_PALETTE_INIT_OWNER(psxgpu_device, psx) +MACHINE_CONFIG_END + +//------------------------------------------------- +// machine_config_additions - device-specific +// machine configurations +//------------------------------------------------- + +machine_config_constructor psxgpu_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( psxgpu ); +} diff --git a/src/devices/video/psx.h b/src/devices/video/psx.h new file mode 100644 index 00000000000..c8cdff69c42 --- /dev/null +++ b/src/devices/video/psx.h @@ -0,0 +1,361 @@ +// license:BSD-3-Clause +// copyright-holders:smf +/* + * PlayStation GPU emulator + * + * Copyright 2003-2014 smf + * + */ + +#pragma once + +#ifndef __PSXGPU_H__ +#define __PSXGPU_H__ + +#include "emu.h" + +#define MCFG_PSX_GPU_VBLANK_HANDLER(_devcb) \ + devcb = &psxgpu_device::set_vblank_handler(*device, DEVCB_##_devcb); + +#define MCFG_PSXGPU_ADD( cputag, tag, type, _vramSize, clock ) \ + MCFG_DEVICE_MODIFY( cputag ) \ + MCFG_PSX_GPU_READ_HANDLER(DEVREAD32(tag, psxgpu_device, read)) \ + MCFG_PSX_GPU_WRITE_HANDLER(DEVWRITE32(tag, psxgpu_device, write)) \ + MCFG_DEVICE_ADD( tag, type, clock ) \ + ((psxgpu_device *) device)->vramSize = _vramSize; \ + MCFG_PSX_GPU_VBLANK_HANDLER(DEVWRITELINE(cputag ":irq", psxirq_device, intin0)) \ + MCFG_PSX_DMA_CHANNEL_READ( cputag, 2, psx_dma_write_delegate( FUNC( psxgpu_device::dma_read ), (psxgpu_device *) device ) ) \ + MCFG_PSX_DMA_CHANNEL_WRITE( cputag, 2, psx_dma_read_delegate( FUNC( psxgpu_device::dma_write ), (psxgpu_device *) device ) ) + +#define MCFG_PSXGPU_REPLACE( cputag, tag, type, _vramSize, clock ) \ + MCFG_DEVICE_MODIFY( cputag ) \ + MCFG_PSX_GPU_READ_HANDLER(DEVREAD32(tag, psxgpu_device, read)) \ + MCFG_PSX_GPU_WRITE_HANDLER(DEVWRITE32(tag, psxgpu_device, write)) \ + MCFG_DEVICE_REPLACE( tag, type, clock ) \ + ((psxgpu_device *) device)->vramSize = _vramSize; \ + MCFG_PSX_GPU_VBLANK_HANDLER(DEVWRITELINE(cputag ":irq", psxirq_device, intin0)) \ + MCFG_PSX_DMA_CHANNEL_READ( cputag, 2, psx_dma_write_delegate( FUNC( psxgpu_device::dma_read ), (psxgpu_device *) device ) ) \ + MCFG_PSX_DMA_CHANNEL_WRITE( cputag, 2, psx_dma_read_delegate( FUNC( psxgpu_device::dma_write ), (psxgpu_device *) device ) ) + +#define MCFG_PSXGPU_VBLANK_CALLBACK( _delegate ) \ + ((screen_device *) config.device_find( device, "screen" ))->register_vblank_callback( _delegate ); + +extern const device_type CXD8514Q; +extern const device_type CXD8538Q; +extern const device_type CXD8561Q; +extern const device_type CXD8561BQ; +extern const device_type CXD8561CQ; +extern const device_type CXD8654Q; + +#define STOP_ON_ERROR ( 0 ) + +#define MAX_LEVEL ( 32 ) +#define MID_LEVEL ( ( MAX_LEVEL / 2 ) << 8 ) +#define MAX_SHADE ( 0x100 ) +#define MID_SHADE ( 0x80 ) + +#define DEBUG_COORDS ( 10 ) + +struct psx_gpu_debug +{ + bitmap_ind16 *mesh; + int b_clear; + int b_mesh; + int n_skip; + int b_texture; + int n_interleave; + int n_coord; + int n_coordx[ DEBUG_COORDS ]; + int n_coordy[ DEBUG_COORDS ]; +}; + +struct FLATVERTEX +{ + PAIR n_coord; +}; + +struct GOURAUDVERTEX +{ + PAIR n_bgr; + PAIR n_coord; +}; + +struct FLATTEXTUREDVERTEX +{ + PAIR n_coord; + PAIR n_texture; +}; + +struct GOURAUDTEXTUREDVERTEX +{ + PAIR n_bgr; + PAIR n_coord; + PAIR n_texture; +}; + +union PACKET +{ + UINT32 n_entry[ 16 ]; + + struct + { + PAIR n_cmd; + struct FLATVERTEX vertex[ 2 ]; + PAIR n_size; + } MoveImage; + + struct + { + PAIR n_bgr; + PAIR n_coord; + PAIR n_size; + } FlatRectangle; + + struct + { + PAIR n_bgr; + PAIR n_coord; + } FlatRectangle8x8; + + struct + { + PAIR n_bgr; + PAIR n_coord; + } FlatRectangle16x16; + + struct + { + PAIR n_bgr; + PAIR n_coord; + PAIR n_texture; + } Sprite8x8; + + struct + { + PAIR n_bgr; + PAIR n_coord; + PAIR n_texture; + } Sprite16x16; + + struct + { + PAIR n_bgr; + PAIR n_coord; + PAIR n_texture; + PAIR n_size; + } FlatTexturedRectangle; + + struct + { + PAIR n_bgr; + struct FLATVERTEX vertex[ 4 ]; + } FlatPolygon; + + struct + { + struct GOURAUDVERTEX vertex[ 4 ]; + } GouraudPolygon; + + struct + { + PAIR n_bgr; + struct FLATVERTEX vertex[ 2 ]; + } MonochromeLine; + + struct + { + struct GOURAUDVERTEX vertex[ 2 ]; + } GouraudLine; + + struct + { + PAIR n_bgr; + struct FLATTEXTUREDVERTEX vertex[ 4 ]; + } FlatTexturedPolygon; + + struct + { + struct GOURAUDTEXTUREDVERTEX vertex[ 4 ]; + } GouraudTexturedPolygon; + + struct + { + PAIR n_bgr; + struct FLATVERTEX vertex; + } Dot; +}; + +class psxgpu_device : public device_t +{ +public: + // construction/destruction + psxgpu_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + virtual machine_config_constructor device_mconfig_additions() const; + + // static configuration helpers + template static devcb_base &set_vblank_handler(device_t &device, _Object object) { return downcast(device).m_vblank_handler.set_callback(object); } + + UINT32 update_screen(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); + DECLARE_WRITE32_MEMBER( write ); + DECLARE_READ32_MEMBER( read ); + void dma_read( UINT32 *ram, UINT32 n_address, INT32 n_size ); + void dma_write( UINT32 *ram, UINT32 n_address, INT32 n_size ); + void lightgun_set( int, int ); + int vramSize; + void vblank(screen_device &screen, bool vblank_state); + DECLARE_PALETTE_INIT( psx ); + +protected: + virtual void device_start(); + virtual void device_reset(); + +private: + void updatevisiblearea(); + void decode_tpage( UINT32 tpage ); + void FlatPolygon( int n_points ); + void FlatTexturedPolygon( int n_points ); + void GouraudPolygon( int n_points ); + void GouraudTexturedPolygon( int n_points ); + void MonochromeLine( void ); + void GouraudLine( void ); + void FrameBufferRectangleDraw( void ); + void FlatRectangle( void ); + void FlatRectangle8x8( void ); + void FlatRectangle16x16( void ); + void FlatTexturedRectangle( void ); + void Sprite8x8( void ); + void Sprite16x16( void ); + void Dot( void ); + void MoveImage( void ); + void psx_gpu_init( int n_gputype ); + void gpu_reset(); + void gpu_read( UINT32 *p_ram, INT32 n_size ); + void gpu_write( UINT32 *p_ram, INT32 n_size ); + + INT32 m_n_tx; + INT32 m_n_ty; + INT32 n_abr; + INT32 n_tp; + INT32 n_ix; + INT32 n_iy; + INT32 n_ti; + + UINT16 *p_vram; + UINT32 n_vramx; + UINT32 n_vramy; + UINT32 n_twy; + UINT32 n_twx; + UINT32 n_twh; + UINT32 n_tww; + UINT32 n_drawarea_x1; + UINT32 n_drawarea_y1; + UINT32 n_drawarea_x2; + UINT32 n_drawarea_y2; + UINT32 n_horiz_disstart; + UINT32 n_horiz_disend; + UINT32 n_vert_disstart; + UINT32 n_vert_disend; + UINT32 b_reverseflag; + INT32 n_drawoffset_x; + INT32 n_drawoffset_y; + UINT32 m_n_displaystartx; + UINT32 n_displaystarty; + int m_n_gputype; + UINT32 n_gpustatus; + UINT32 n_gpuinfo; + UINT32 n_gpu_buffer_offset; + UINT32 n_lightgun_x; + UINT32 n_lightgun_y; + UINT32 n_screenwidth; + UINT32 n_screenheight; + + PACKET m_packet; + + UINT16 *p_p_vram[ 1024 ]; + + UINT16 p_n_redshade[ MAX_LEVEL * MAX_SHADE ]; + UINT16 p_n_greenshade[ MAX_LEVEL * MAX_SHADE ]; + UINT16 p_n_blueshade[ MAX_LEVEL * MAX_SHADE ]; + UINT16 p_n_redlevel[ 0x10000 ]; + UINT16 p_n_greenlevel[ 0x10000 ]; + UINT16 p_n_bluelevel[ 0x10000 ]; + + UINT16 p_n_f025[ MAX_LEVEL * MAX_SHADE ]; + UINT16 p_n_f05[ MAX_LEVEL * MAX_SHADE ]; + UINT16 p_n_f1[ MAX_LEVEL * MAX_SHADE ]; + UINT16 p_n_redb05[ 0x10000 ]; + UINT16 p_n_greenb05[ 0x10000 ]; + UINT16 p_n_blueb05[ 0x10000 ]; + UINT16 p_n_redb1[ 0x10000 ]; + UINT16 p_n_greenb1[ 0x10000 ]; + UINT16 p_n_blueb1[ 0x10000 ]; + UINT16 p_n_redaddtrans[ MAX_LEVEL * MAX_LEVEL ]; + UINT16 p_n_greenaddtrans[ MAX_LEVEL * MAX_LEVEL ]; + UINT16 p_n_blueaddtrans[ MAX_LEVEL * MAX_LEVEL ]; + UINT16 p_n_redsubtrans[ MAX_LEVEL * MAX_LEVEL ]; + UINT16 p_n_greensubtrans[ MAX_LEVEL * MAX_LEVEL ]; + UINT16 p_n_bluesubtrans[ MAX_LEVEL * MAX_LEVEL ]; + + UINT16 p_n_g0r0[ 0x10000 ]; + UINT16 p_n_b0[ 0x10000 ]; + UINT16 p_n_r1[ 0x10000 ]; + UINT16 p_n_b1g1[ 0x10000 ]; + + devcb_write_line m_vblank_handler; + +#if defined(DEBUG_VIEWER) && DEBUG_VIEWER + required_device m_screen; + void DebugMeshInit( void ); + void DebugMesh( int n_coordx, int n_coordy ); + void DebugMeshEnd( void ); + void DebugCheckKeys( void ); + int DebugMeshDisplay( bitmap_ind16 &bitmap, const rectangle &cliprect ); + int DebugTextureDisplay( bitmap_ind16 &bitmap ); + + psx_gpu_debug m_debug; +#endif +}; + +class cxd8514q_device : public psxgpu_device +{ +public: + // construction/destruction + cxd8514q_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class cxd8538q_device : public psxgpu_device +{ +public: + // construction/destruction + cxd8538q_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class cxd8561q_device : public psxgpu_device +{ +public: + // construction/destruction + cxd8561q_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class cxd8561bq_device : public psxgpu_device +{ +public: + // construction/destruction + cxd8561bq_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class cxd8561cq_device : public psxgpu_device +{ +public: + // construction/destruction + cxd8561cq_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class cxd8654q_device : public psxgpu_device +{ +public: + // construction/destruction + cxd8654q_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +#endif diff --git a/src/devices/video/ramdac.c b/src/devices/video/ramdac.c new file mode 100644 index 00000000000..f9794e60081 --- /dev/null +++ b/src/devices/video/ramdac.c @@ -0,0 +1,204 @@ +// license:BSD-3-Clause +// copyright-holders:Angelo Salese +/*************************************************************************** + + Generic Palette RAMDAC device + + Written by Angelo Salese + + TODO: + - masking register, almost likely it controls rollback on incrementing + r/w palette access; + - needs information about different models and what exactly they does + +***************************************************************************/ + +#include "emu.h" +#include "video/ramdac.h" + +// default address map +static ADDRESS_MAP_START( ramdac_palram, AS_0, 8, ramdac_device ) + AM_RANGE(0x000, 0x0ff) AM_RAM // R bank + AM_RANGE(0x100, 0x1ff) AM_RAM // G bank + AM_RANGE(0x200, 0x2ff) AM_RAM // B bank + AM_RANGE(0x300, 0x3ff) AM_NOP +ADDRESS_MAP_END + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +// device type definition +const device_type RAMDAC = &device_creator; + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// ramdac_device - constructor +//------------------------------------------------- + +ramdac_device::ramdac_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, RAMDAC, "RAMDAC", tag, owner, clock, "ramdac", __FILE__), + device_memory_interface(mconfig, *this), + m_space_config("videoram", ENDIANNESS_LITTLE, 8, 10, 0, NULL, *ADDRESS_MAP_NAME(ramdac_palram)), + m_palette(*this), + m_split_read_reg(0) +{ +} + +//------------------------------------------------- +// static_set_palette_tag: Set the tag of the +// palette device +//------------------------------------------------- + +void ramdac_device::static_set_palette_tag(device_t &device, const char *tag) +{ + downcast(device).m_palette.set_tag(tag); +} + +//------------------------------------------------- +// memory_space_config - return a description of +// any address spaces owned by this device +//------------------------------------------------- + +const address_space_config *ramdac_device::memory_space_config(address_spacenum spacenum) const +{ + return (spacenum == AS_0) ? &m_space_config : NULL; +} + +//------------------------------------------------- +// readbyte - read a byte at the given address +//------------------------------------------------- + +inline UINT8 ramdac_device::readbyte(offs_t address) +{ + return space().read_byte(address); +} + + +//------------------------------------------------- +// writebyte - write a byte at the given address +//------------------------------------------------- + +inline void ramdac_device::writebyte(offs_t address, UINT8 data) +{ + space().write_byte(address, data); +} + +//------------------------------------------------- +// device_validity_check - perform validity checks +// on this device +//------------------------------------------------- + +void ramdac_device::device_validity_check(validity_checker &valid) const +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void ramdac_device::device_start() +{ + m_palram = auto_alloc_array_clear(machine(), UINT8, 1 << 10); + +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void ramdac_device::device_reset() +{ + m_pal_index[0] = 0; + m_int_index[0] = 0; + m_pal_index[1] = 0; + m_int_index[1] = 0; + m_pal_mask = 0xff; +} + + +//************************************************************************** +// READ/WRITE HANDLERS +// [0] = W register, [1] = R register +//************************************************************************** + +inline void ramdac_device::reg_increment(UINT8 inc_type) +{ + m_int_index[inc_type]++; + if(m_int_index[inc_type] == 3) + { + m_int_index[inc_type] = 0; + m_pal_index[inc_type]++; + } +} + +READ8_MEMBER( ramdac_device::index_r ) +{ + return m_pal_index[0]; +} + +WRITE8_MEMBER( ramdac_device::index_w ) +{ + m_pal_index[0] = data; + m_int_index[0] = 0; +} + +WRITE8_MEMBER( ramdac_device::index_r_w ) +{ + m_pal_index[1] = data; + m_int_index[1] = 0; +} + +READ8_MEMBER( ramdac_device::pal_r ) +{ + UINT8 res; + res = readbyte(m_pal_index[m_split_read_reg] | (m_int_index[m_split_read_reg] << 8)); + reg_increment(m_split_read_reg); + return res; +} + +WRITE8_MEMBER( ramdac_device::pal_w ) +{ + writebyte(m_pal_index[0] | (m_int_index[0] << 8),data); + reg_increment(0); +} + +WRITE8_MEMBER( ramdac_device::mask_w ) +{ + m_pal_mask = data; +} + + +//************************************************************************** +// Generic bank read/write handlers +//************************************************************************** + +READ8_MEMBER( ramdac_device::ramdac_pal_r ) +{ + return m_palram[offset]; +} + +WRITE8_MEMBER( ramdac_device::ramdac_rgb666_w ) +{ + UINT16 pal_offs; + + m_palram[offset] = data & 0x3f; + pal_offs = (offset & 0xff); + + m_palette->set_pen_color(offset&0xff,pal6bit(m_palram[pal_offs|0x000]),pal6bit(m_palram[pal_offs|0x100]),pal6bit(m_palram[pal_offs|0x200])); +} + +WRITE8_MEMBER( ramdac_device::ramdac_rgb888_w ) +{ + UINT16 pal_offs; + + m_palram[offset] = data; + pal_offs = (offset & 0xff); + + m_palette->set_pen_color(offset&0xff,m_palram[pal_offs|0x000],m_palram[pal_offs|0x100],m_palram[pal_offs|0x200]); +} diff --git a/src/devices/video/ramdac.h b/src/devices/video/ramdac.h new file mode 100644 index 00000000000..0cbf29e9057 --- /dev/null +++ b/src/devices/video/ramdac.h @@ -0,0 +1,87 @@ +// license:BSD-3-Clause +// copyright-holders:Angelo Salese +/*************************************************************************** + + Generic Palette RAMDAC device + +***************************************************************************/ + +#pragma once + +#ifndef __ramdacDEV_H__ +#define __ramdacDEV_H__ + +#include "emu.h" + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_RAMDAC_ADD(_tag, _map, _palette_tag) \ + MCFG_DEVICE_ADD(_tag, RAMDAC, 0) \ + MCFG_DEVICE_ADDRESS_MAP(AS_0, _map) \ + ramdac_device::static_set_palette_tag(*device, "^" _palette_tag); + +#define MCFG_RAMDAC_SPLIT_READ(_split) \ + ramdac_device::set_split_read(*device, _split); + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> ramdac_device + +class ramdac_device : public device_t, + public device_memory_interface +{ +public: + // construction/destruction + ramdac_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // static configuration + static void static_set_palette_tag(device_t &device, const char *tag); + static void set_split_read(device_t &device, int split) { downcast(device).m_split_read_reg = split; } + + // I/O operations + DECLARE_READ8_MEMBER( index_r ); + DECLARE_READ8_MEMBER( pal_r ); + DECLARE_WRITE8_MEMBER( index_w ); + DECLARE_WRITE8_MEMBER( index_r_w ); + DECLARE_WRITE8_MEMBER( pal_w ); + DECLARE_WRITE8_MEMBER( mask_w ); + + DECLARE_READ8_MEMBER( ramdac_pal_r ); + DECLARE_WRITE8_MEMBER( ramdac_rgb666_w ); + DECLARE_WRITE8_MEMBER( ramdac_rgb888_w ); + + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const; + +protected: + // device-level overrides + virtual void device_validity_check(validity_checker &valid) const; + virtual void device_start(); + virtual void device_reset(); + inline UINT8 readbyte(offs_t address); + inline void writebyte(offs_t address, UINT8 data); + inline void reg_increment(UINT8 inc_type); + +private: + UINT8 m_pal_index[2]; + UINT8 m_pal_mask; + UINT8 m_int_index[2]; + UINT8 *m_palram; + + const address_space_config m_space_config; + required_device m_palette; + + UINT8 m_split_read_reg; // read register index is separated, seen in rltennis +}; + + +// device type definition +extern const device_type RAMDAC; + + +#endif diff --git a/src/devices/video/resnet.c b/src/devices/video/resnet.c new file mode 100644 index 00000000000..0245aba6161 --- /dev/null +++ b/src/devices/video/resnet.c @@ -0,0 +1,719 @@ +// license:BSD-3-Clause +// copyright-holders:Couriersud +/***************************************************************************** + + resnet.c + + Compute weights for resistors networks. + +****************************************************************************** + + Function can evaluate from one to three networks at a time. + + The output weights can either be scaled with automatically calculated scaler + or scaled with a 'scaler' provided on entry. + + On entry + -------- + + 'minval','maxval' specify the range of output signals (sum of weights). + 'scaler' if negative, function will calculate proper scaler, + otherwise it will use the one provided here. + 'count_x' is the number of resistors in this network + 'resistances_x' is the pointer to a table containing the resistances + 'weights_x' is the pointer to a table to be filled with the weights + (it can contain negative values if 'minval' is below zero). + 'pulldown_x' is the resistance of a pulldown resistor (0 means there's no pulldown resistor) + 'pullup_x' is the resistance of a pullup resistor (0 means there's no pullup resistor) + + + Return value + ------------ + + The value of the scaler that was used for fitting the output within the expected range. + Note that if you provide your own scaler on entry it will be returned here. + + + All resistances are expected in Ohms. + + + Hint + ---- + + If there is no need to calculate all three networks at a time, just specify '0' + for the 'count_x' for unused network(s). + +*****************************************************************************/ + + +#include "emu.h" +#include "resnet.h" + +#define VERBOSE 0 + + +double compute_resistor_weights( + int minval, int maxval, double scaler, + int count_1, const int * resistances_1, double * weights_1, int pulldown_1, int pullup_1, + int count_2, const int * resistances_2, double * weights_2, int pulldown_2, int pullup_2, + int count_3, const int * resistances_3, double * weights_3, int pulldown_3, int pullup_3 ) +{ + int networks_no; + + int rescount[MAX_NETS]; /* number of resistors in each of the nets */ + double r[MAX_NETS][MAX_RES_PER_NET]; /* resistances */ + double w[MAX_NETS][MAX_RES_PER_NET]; /* calulated weights */ + double ws[MAX_NETS][MAX_RES_PER_NET]; /* calulated, scaled weights */ + int r_pd[MAX_NETS]; /* pulldown resistances */ + int r_pu[MAX_NETS]; /* pullup resistances */ + + double max_out[MAX_NETS]; + double * out[MAX_NETS]; + + int i,j,n; + double scale; + double max; + + /* parse input parameters */ + + networks_no = 0; + for (n = 0; n < MAX_NETS; n++) + { + int count, pd, pu; + const int * resistances; + double * weights; + + switch(n){ + case 0: + count = count_1; + resistances = resistances_1; + weights = weights_1; + pd = pulldown_1; + pu = pullup_1; + break; + case 1: + count = count_2; + resistances = resistances_2; + weights = weights_2; + pd = pulldown_2; + pu = pullup_2; + break; + case 2: + default: + count = count_3; + resistances = resistances_3; + weights = weights_3; + pd = pulldown_3; + pu = pullup_3; + break; + } + + /* parameters validity check */ + if (count > MAX_RES_PER_NET) + fatalerror("compute_resistor_weights(): too many resistors in net #%i. The maximum allowed is %i, the number requested was: %i\n",n, MAX_RES_PER_NET, count); + + + if (count > 0) + { + rescount[networks_no] = count; + for (i=0; i < count; i++) + { + r[networks_no][i] = 1.0 * resistances[i]; + } + out[networks_no] = weights; + r_pd[networks_no] = pd; + r_pu[networks_no] = pu; + networks_no++; + } + } + if (networks_no < 1) + fatalerror("compute_resistor_weights(): no input data\n"); + + /* calculate outputs for all given networks */ + for( i = 0; i < networks_no; i++ ) + { + double R0, R1, Vout, dst; + + /* of n resistors */ + for(n = 0; n < rescount[i]; n++) + { + R0 = ( r_pd[i] == 0 ) ? 1.0/1e12 : 1.0/r_pd[i]; + R1 = ( r_pu[i] == 0 ) ? 1.0/1e12 : 1.0/r_pu[i]; + + for( j = 0; j < rescount[i]; j++ ) + { + if( j==n ) /* only one resistance in the network connected to Vcc */ + { + if (r[i][j] != 0.0) + R1 += 1.0/r[i][j]; + } + else + if (r[i][j] != 0.0) + R0 += 1.0/r[i][j]; + } + + /* now determine the voltage */ + R0 = 1.0/R0; + R1 = 1.0/R1; + Vout = (maxval - minval) * R0 / (R1 + R0) + minval; + + /* and convert it to a destination value */ + dst = (Vout < minval) ? minval : (Vout > maxval) ? maxval : Vout; + + w[i][n] = dst; + } + } + + /* calculate maximum outputs for all given networks */ + j = 0; + max = 0.0; + for( i = 0; i < networks_no; i++ ) + { + double sum = 0.0; + + /* of n resistors */ + for( n = 0; n < rescount[i]; n++ ) + sum += w[i][n]; /* maximum output, ie when each resistance is connected to Vcc */ + + max_out[i] = sum; + if (max < sum) + { + max = sum; + j = i; + } + } + + + if (scaler < 0.0) /* use autoscale ? */ + /* calculate the output scaler according to the network with the greatest output */ + scale = ((double)maxval) / max_out[j]; + else /* use scaler provided on entry */ + scale = scaler; + + /* calculate scaled output and fill the output table(s)*/ + for(i = 0; i < networks_no;i++) + { + for (n = 0; n < rescount[i]; n++) + { + ws[i][n] = w[i][n]*scale; /* scale the result */ + (out[i])[n] = ws[i][n]; /* fill the output table */ + } + } + +/* debug code */ +if (VERBOSE) +{ + logerror("compute_resistor_weights(): scaler = %15.10f\n",scale); + logerror("min val :%i max val:%i Total number of networks :%i\n", minval, maxval, networks_no ); + + for(i = 0; i < networks_no;i++) + { + double sum = 0.0; + + logerror(" Network no.%i=> resistances: %i", i, rescount[i] ); + if (r_pu[i] != 0) + logerror(", pullup resistor: %i Ohms",r_pu[i]); + if (r_pd[i] != 0) + logerror(", pulldown resistor: %i Ohms",r_pd[i]); + logerror("\n maximum output of this network:%10.5f (scaled to %15.10f)\n", max_out[i], max_out[i]*scale ); + for (n = 0; n < rescount[i]; n++) + { + logerror(" res %2i:%9.1f Ohms weight=%10.5f (scaled = %15.10f)\n", n, r[i][n], w[i][n], ws[i][n] ); + sum += ws[i][n]; + } + logerror(" sum of scaled weights = %15.10f\n", sum ); + } +} +/* debug end */ + + return (scale); + +} + + +double compute_resistor_net_outputs( + int minval, int maxval, double scaler, + int count_1, const int * resistances_1, double * outputs_1, int pulldown_1, int pullup_1, + int count_2, const int * resistances_2, double * outputs_2, int pulldown_2, int pullup_2, + int count_3, const int * resistances_3, double * outputs_3, int pulldown_3, int pullup_3 ) +{ + int networks_no; + + int rescount[MAX_NETS]; /* number of resistors in each of the nets */ + double r[MAX_NETS][MAX_RES_PER_NET]; /* resistances */ + int r_pd[MAX_NETS]; /* pulldown resistances */ + int r_pu[MAX_NETS]; /* pullup resistances */ + + double max_out[MAX_NETS]; + double min_out[MAX_NETS]; + double * out[MAX_NETS]; + + int i,j,n; + double scale; + double min; + double max; + + /* parse input parameters */ + + std::vector o((1< os((1< MAX_RES_PER_NET) + fatalerror("compute_resistor_net_outputs(): too many resistors in net #%i. The maximum allowed is %i, the number requested was: %i\n",n, MAX_RES_PER_NET, count); + + if (count > 0) + { + rescount[networks_no] = count; + for (i=0; i < count; i++) + { + r[networks_no][i] = 1.0 * resistances[i]; + } + out[networks_no] = weights; + r_pd[networks_no] = pd; + r_pu[networks_no] = pu; + networks_no++; + } + } + + if (networks_no<1) + fatalerror("compute_resistor_net_outputs(): no input data\n"); + + /* calculate outputs for all given networks */ + for( i = 0; i < networks_no; i++ ) + { + double R0, R1, Vout, dst; + + /* of n resistors, generating 1< maxval) ? maxval : Vout; + + o[i*(1< o[i*(1< val) + { + min = val; + } + val = max_out[i]; /* maximum output of this network */ + if (max < val) + { + max = val; + } + } + + + if (scaler < 0.0) /* use autoscale ? */ + /* calculate the output scaler according to the network with the smallest output */ + scale = ((double)maxval) / (max-min); + else /* use scaler provided on entry */ + scale = scaler; + + /* calculate scaled output and fill the output table(s) */ + for(i = 0; i < networks_no; i++) + { + for (n = 0; n < (1< resistances: %i", i, rescount[i] ); + if (r_pu[i] != 0) + logerror(", pullup resistor: %i Ohms",r_pu[i]); + if (r_pd[i] != 0) + logerror(", pulldown resistor: %i Ohms",r_pd[i]); + logerror("\n maximum output of this network:%10.5f", max_out[i] ); + logerror("\n minimum output of this network:%10.5f\n", min_out[i] ); + for (n = 0; n < rescount[i]; n++) + { + logerror(" res %2i:%9.1f Ohms\n", n, r[i][n]); + } + for (n = 0; n < (1<> i) & 1); + if (di.rgb[channel].R[i] != 0.0 && !level) + { + // There is no difference in the calculation of the "low" input + // (transistor conducting to ground) between TTL output and + // open collector output. This is documented explicitly in the + // code below (no difference if / else. + if (OpenCol) + { + rTotal += 1.0 / di.rgb[channel].R[i]; + v += vOL / di.rgb[channel].R[i]; + } + else + { + rTotal += 1.0 / di.rgb[channel].R[i]; + v += vOL / di.rgb[channel].R[i]; + } + } + } + + /* Mix in rbias and rgnd */ + if ( di.rgb[channel].rBias != 0.0 ) + { + rTotal += 1.0 / di.rgb[channel].rBias; + v += vBias / di.rgb[channel].rBias; + } + if (rGnd != 0.0) + rTotal += 1.0 / rGnd; + + /* if the resulting voltage after application of all low inputs is + * greater than vOH, treat high inputs as open collector/high impedance + * There will be now current into/from the TTL gate + */ + + if ( (di.options & RES_NET_VIN_MASK)==RES_NET_VIN_TTL_OUT) + { + if (v / rTotal > vOH) + OpenCol = 1; + } + + /* Second pass - high inputs */ + + for (i=0; i> i) & 1); + if (di.rgb[channel].R[i] != 0.0 && level) + { + if (OpenCol) + { + rTotal += 0; + v += 0; + } + else + { + rTotal += 1.0 / (di.rgb[channel].R[i] + ttlHRes); + v += vOH / (di.rgb[channel].R[i] + ttlHRes); + } + } + } + + rTotal = 1.0 / rTotal; + v *= rTotal; + v = MAX(minout, v - cut); + + switch (di.options & RES_NET_MONITOR_MASK) + { + case RES_NET_MONITOR_INVERT: + v = vcc - v; + break; + case RES_NET_MONITOR_SANYO_EZV20: + v = vcc - v; + v = MAX(0, v-0.7); + v = MIN(v, vcc - 2 * 0.7); + v = v / (vcc-1.4); + v = v * vcc; + break; + case RES_NET_MONITOR_ELECTROHOME_G07: + /* Nothing */ + break; + } + + return (int) (v * 255 / vcc + 0.4); +} + +void compute_res_net_all(std::vector &rgb, const UINT8 *prom, const res_net_decode_info &rdi, const res_net_info &di) +{ + UINT8 r,g,b; + int i,j,k; + + rgb.resize(rdi.end - rdi.start + 1); + for (i=rdi.start; i<=rdi.end; i++) + { + UINT8 t[3] = {0,0,0}; + int s; + for (j=0;j0) + t[k] = t[k] | ( (prom[i+rdi.offset[3*j+k]]>>s) & rdi.mask[3*j+k]); + else + t[k] = t[k] | ( (prom[i+rdi.offset[3*j+k]]<<(0-s)) & rdi.mask[3*j+k]); + } + r = compute_res_net(t[0], RES_NET_CHAN_RED, di); + g = compute_res_net(t[1], RES_NET_CHAN_GREEN, di); + b = compute_res_net(t[2], RES_NET_CHAN_BLUE, di); + rgb[i-rdi.start] = rgb_t(r,g,b); + } +} diff --git a/src/devices/video/resnet.h b/src/devices/video/resnet.h new file mode 100644 index 00000000000..1b1c933cf8f --- /dev/null +++ b/src/devices/video/resnet.h @@ -0,0 +1,199 @@ +// license:BSD-3-Clause +// copyright-holders:Couriersud +/***************************************************************************** + + resnet.h + + Compute weights for resistors networks. + +*****************************************************************************/ + +#pragma once + +#ifndef _RESNET_H_ +#define _RESNET_H_ + +/********************************************************************** + * Rbias + * Vbias >-ZZZ-. .-----------------------------------------> Out0 + * | | Vcc + * R0 | | | + * In0 >-ZZZ-+----+ Vcc Z + * | | | Z + * R1 | | / Z + * In1 >-ZZZ-+ +----+----ZZZ--| NPN +------------> Out1 + * : | > < + * : | +----+----| PNP + * R8 | | Z | \ + * In8 >-ZZZ-+ | Z | | + * | | Z | Gnd + * Z | | '-------------------> Out2 + * Z Rgnd | Gnd + * Z | |-----------------------| + * | `---| max(vmin,min(sig-vcut)|--------> Out3 + * Gnd |-----------------------| + * + *********************************************************************/ + +/* Amplifier stage per channel but may be specified globally as default */ + +#define RES_NET_AMP_USE_GLOBAL 0x0000 +#define RES_NET_AMP_NONE 0x0001 //Out0 +#define RES_NET_AMP_DARLINGTON 0x0002 //Out1 +#define RES_NET_AMP_EMITTER 0x0003 //Out2 +#define RES_NET_AMP_CUSTOM 0x0004 //Out3 +#define RES_NET_AMP_MASK 0x0007 + +/* VCC prebuilds - Global */ + +#define RES_NET_VCC_5V 0x0000 +#define RES_NET_VCC_CUSTOM 0x0008 +#define RES_NET_VCC_MASK 0x0008 + +/* VBias prebuils - per channel but may be specified globally as default */ + +#define RES_NET_VBIAS_USE_GLOBAL 0x0000 +#define RES_NET_VBIAS_5V 0x0010 +#define RES_NET_VBIAS_TTL 0x0020 +#define RES_NET_VBIAS_CUSTOM 0x0030 +#define RES_NET_VBIAS_MASK 0x0030 + +/* Input Voltage levels - Global */ + +#define RES_NET_VIN_OPEN_COL 0x0000 +#define RES_NET_VIN_VCC 0x0100 +#define RES_NET_VIN_TTL_OUT 0x0200 +#define RES_NET_VIN_CUSTOM 0x0300 +#define RES_NET_VIN_MASK 0x0300 + +/* Monitor options */ + +// Just invert the signal +#define RES_NET_MONITOR_INVERT 0x1000 +// SANYO_EZV20 / Nintendo with inverter circuit +#define RES_NET_MONITOR_SANYO_EZV20 0x2000 +// Electrohome G07 Series +// 5.6k input impedance +#define RES_NET_MONITOR_ELECTROHOME_G07 0x3000 + +#define RES_NET_MONITOR_MASK 0x3000 + +/* General defines */ + +#define RES_NET_CHAN_RED 0x00 +#define RES_NET_CHAN_GREEN 0x01 +#define RES_NET_CHAN_BLUE 0x02 + +/* Some aliases */ + +#define RES_NET_VIN_MB7051 RES_NET_VIN_TTL_OUT +#define RES_NET_VIN_MB7052 RES_NET_VIN_TTL_OUT +#define RES_NET_VIN_MB7053 RES_NET_VIN_TTL_OUT +#define RES_NET_VIN_28S42 RES_NET_VIN_TTL_OUT + +/* Structures */ + +struct res_net_channel_info { + // per channel options + UINT32 options; + // Pullup resistor value in Ohms + double rBias; + // Pulldown resistor value in Ohms + double rGnd; + // Number of inputs connected to resistors + int num; + // Resistor values + // - Least significant bit first + double R[8]; + // Minimum output voltage + // - Applicable if output is routed through a complimentary + // - darlington circuit + // - typical value ~ 0.9V + double minout; + // Cutoff output voltage + // - Applicable if output is routed through 1:1 transistor amplifier + // - Typical value ~ 0.7V + double cut; + // Voltage at the pullup resistor + // - Typical voltage ~5V + double vBias; +}; + +struct res_net_info { + // global options + UINT32 options; + // The three color channels + res_net_channel_info rgb[3]; + // Supply Voltage + // - Typical value 5V + double vcc; + // High Level output voltage + // - TTL : 3.40V + // - CMOS: 4.95V (@5v vcc) + double vOL; + // Low Level output voltage + // - TTL : 0.35V + // - CMOS: 0.05V (@5v vcc) + double vOH; + // Open Collector flag + UINT8 OpenCol; +}; + +#define RES_NET_MAX_COMP 3 + +struct res_net_decode_info { + int numcomp; + int start; + int end; + UINT16 offset[3 * RES_NET_MAX_COMP]; + INT16 shift[3 * RES_NET_MAX_COMP]; + UINT16 mask[3 * RES_NET_MAX_COMP]; +}; + +/* return a single value for one channel */ + +int compute_res_net(int inputs, int channel, const res_net_info &di); + +/* compute all values */ + +void compute_res_net_all(std::vector &rgb, const UINT8 *prom, const res_net_decode_info &rdi, const res_net_info &di); + + +/* legacy interface */ + +double compute_resistor_weights( + int minval, int maxval, double scaler, + int count_1, const int * resistances_1, double * weights_1, int pulldown_1, int pullup_1, + int count_2, const int * resistances_2, double * weights_2, int pulldown_2, int pullup_2, + int count_3, const int * resistances_3, double * weights_3, int pulldown_3, int pullup_3 ); + +#define combine_8_weights(tab,w0,w1,w2,w3,w4,w5,w6,w7) ((int)(((tab)[0]*(w0) + (tab)[1]*(w1) + (tab)[2]*(w2) + (tab)[3]*(w3) + (tab)[4]*(w4) + (tab)[5]*(w5) + (tab)[6]*(w6) + (tab)[7]*(w7)) + 0.5)) +#define combine_7_weights(tab,w0,w1,w2,w3,w4,w5,w6) ((int)(((tab)[0]*(w0) + (tab)[1]*(w1) + (tab)[2]*(w2) + (tab)[3]*(w3) + (tab)[4]*(w4) + (tab)[5]*(w5) + (tab)[6]*(w6)) + 0.5)) +#define combine_6_weights(tab,w0,w1,w2,w3,w4,w5) ((int)(((tab)[0]*(w0) + (tab)[1]*(w1) + (tab)[2]*(w2) + (tab)[3]*(w3) + (tab)[4]*(w4) + (tab)[5]*(w5)) + 0.5)) +#define combine_5_weights(tab,w0,w1,w2,w3,w4) ((int)(((tab)[0]*(w0) + (tab)[1]*(w1) + (tab)[2]*(w2) + (tab)[3]*(w3) + (tab)[4]*(w4)) + 0.5)) +#define combine_4_weights(tab,w0,w1,w2,w3) ((int)(((tab)[0]*(w0) + (tab)[1]*(w1) + (tab)[2]*(w2) + (tab)[3]*(w3)) + 0.5)) +#define combine_3_weights(tab,w0,w1,w2) ((int)(((tab)[0]*(w0) + (tab)[1]*(w1) + (tab)[2]*(w2)) + 0.5)) +#define combine_2_weights(tab,w0,w1) ((int)(((tab)[0]*(w0) + (tab)[1]*(w1)) + 0.5)) +#define combine_1_weights(tab,w0) ((int)(((tab)[0]*(w0) + 0.5))) + + + +/* this should be moved to one of the core files */ + +#define MAX_NETS 3 +#define MAX_RES_PER_NET 18 + + + + +/* for the open collector outputs PROMs */ + +double compute_resistor_net_outputs( + int minval, int maxval, double scaler, + int count_1, const int * resistances_1, double * outputs_1, int pulldown_1, int pullup_1, + int count_2, const int * resistances_2, double * outputs_2, int pulldown_2, int pullup_2, + int count_3, const int * resistances_3, double * outputs_3, int pulldown_3, int pullup_3 ); + + + +#endif /*_RESNET_H_*/ diff --git a/src/devices/video/rgbgen.c b/src/devices/video/rgbgen.c new file mode 100644 index 00000000000..4e7e6042569 --- /dev/null +++ b/src/devices/video/rgbgen.c @@ -0,0 +1,136 @@ +// license:BSD-3-Clause +// copyright-holders:Vas Crabb, Ryan Holtz +/*************************************************************************** + + rgbgen.c + + General RGB utilities. + +***************************************************************************/ + +#if !(defined(__ALTIVEC__) || ((!defined(MAME_DEBUG) || defined(__OPTIMIZE__)) && (defined(__SSE2__) || defined(_MSC_VER)) && defined(PTR64))) + +#include "emu.h" +#include "rgbgen.h" + +/*************************************************************************** + HIGHER LEVEL OPERATIONS +***************************************************************************/ + +/*------------------------------------------------- + rgbaint_blend - blend two colors by the given + scale factor +-------------------------------------------------*/ + +void rgbaint_t::blend(const rgbaint_t& color2, UINT8 color1scale) +{ + INT32 scale1 = (INT32)color1scale; + INT32 scale2 = 256 - scale1; + + m_a = (m_a * scale1 + color2.m_a * scale2) >> 8; + m_r = (m_r * scale1 + color2.m_r * scale2) >> 8; + m_g = (m_g * scale1 + color2.m_g * scale2) >> 8; + m_b = (m_b * scale1 + color2.m_b * scale2) >> 8; + m_a |= (m_a & 0x00800000) ? 0xff000000 : 0; + m_r |= (m_r & 0x00800000) ? 0xff000000 : 0; + m_g |= (m_g & 0x00800000) ? 0xff000000 : 0; + m_b |= (m_b & 0x00800000) ? 0xff000000 : 0; +} + + +/*------------------------------------------------- + rgbaint_scale_and_clamp - scale the given + color by an 8.8 scale factor, immediate or + per channel, and clamp to byte values +-------------------------------------------------*/ + +void rgbaint_t::scale_imm_and_clamp(INT32 scale) +{ + m_a = (m_a * scale) >> 8; + m_r = (m_r * scale) >> 8; + m_g = (m_g * scale) >> 8; + m_b = (m_b * scale) >> 8; + m_a |= (m_a & 0x00800000) ? 0xff000000 : 0; + m_r |= (m_r & 0x00800000) ? 0xff000000 : 0; + m_g |= (m_g & 0x00800000) ? 0xff000000 : 0; + m_b |= (m_b & 0x00800000) ? 0xff000000 : 0; + if ((UINT32)m_a > 255) { m_a = (m_a < 0) ? 0 : 255; } + if ((UINT32)m_r > 255) { m_r = (m_r < 0) ? 0 : 255; } + if ((UINT32)m_g > 255) { m_g = (m_g < 0) ? 0 : 255; } + if ((UINT32)m_b > 255) { m_b = (m_b < 0) ? 0 : 255; } +} + +void rgbaint_t::scale_and_clamp(const rgbaint_t& scale) +{ + m_a = (m_a * scale.m_a) >> 8; + m_r = (m_r * scale.m_r) >> 8; + m_g = (m_g * scale.m_g) >> 8; + m_b = (m_b * scale.m_b) >> 8; + m_a |= (m_a & 0x00800000) ? 0xff000000 : 0; + m_r |= (m_r & 0x00800000) ? 0xff000000 : 0; + m_g |= (m_g & 0x00800000) ? 0xff000000 : 0; + m_b |= (m_b & 0x00800000) ? 0xff000000 : 0; + if ((UINT32)m_a > 255) { m_a = (m_a < 0) ? 0 : 255; } + if ((UINT32)m_r > 255) { m_r = (m_r < 0) ? 0 : 255; } + if ((UINT32)m_g > 255) { m_g = (m_g < 0) ? 0 : 255; } + if ((UINT32)m_b > 255) { m_b = (m_b < 0) ? 0 : 255; } +} + + +void rgbaint_t::scale_imm_add_and_clamp(INT32 scale, const rgbaint_t& other) +{ + m_a = (m_a * scale) >> 8; + m_r = (m_r * scale) >> 8; + m_g = (m_g * scale) >> 8; + m_b = (m_b * scale) >> 8; + m_a |= (m_a & 0x00800000) ? 0xff000000 : 0; + m_r |= (m_r & 0x00800000) ? 0xff000000 : 0; + m_g |= (m_g & 0x00800000) ? 0xff000000 : 0; + m_b |= (m_b & 0x00800000) ? 0xff000000 : 0; + m_a += other.m_a; + m_r += other.m_r; + m_g += other.m_g; + m_b += other.m_b; + if ((UINT32)m_a > 255) { m_a = (m_a < 0) ? 0 : 255; } + if ((UINT32)m_r > 255) { m_r = (m_r < 0) ? 0 : 255; } + if ((UINT32)m_g > 255) { m_g = (m_g < 0) ? 0 : 255; } + if ((UINT32)m_b > 255) { m_b = (m_b < 0) ? 0 : 255; } +} + +void rgbaint_t::scale_add_and_clamp(const rgbaint_t& scale, const rgbaint_t& other) +{ + m_a = (m_a * scale.m_a) >> 8; + m_r = (m_r * scale.m_r) >> 8; + m_g = (m_g * scale.m_g) >> 8; + m_b = (m_b * scale.m_b) >> 8; + m_a |= (m_a & 0x00800000) ? 0xff000000 : 0; + m_r |= (m_r & 0x00800000) ? 0xff000000 : 0; + m_g |= (m_g & 0x00800000) ? 0xff000000 : 0; + m_b |= (m_b & 0x00800000) ? 0xff000000 : 0; + m_a += other.m_a; + m_r += other.m_r; + m_g += other.m_g; + m_b += other.m_b; + if ((UINT32)m_a > 255) { m_a = (m_a < 0) ? 0 : 255; } + if ((UINT32)m_r > 255) { m_r = (m_r < 0) ? 0 : 255; } + if ((UINT32)m_g > 255) { m_g = (m_g < 0) ? 0 : 255; } + if ((UINT32)m_b > 255) { m_b = (m_b < 0) ? 0 : 255; } +} + +void rgbaint_t::scale2_add_and_clamp(const rgbaint_t& scale, const rgbaint_t& other, const rgbaint_t& scale2) +{ + m_a = (m_a * scale.m_a + other.m_a * scale2.m_a) >> 8; + m_r = (m_r * scale.m_r + other.m_r * scale2.m_r) >> 8; + m_g = (m_g * scale.m_g + other.m_g * scale2.m_g) >> 8; + m_b = (m_b * scale.m_b + other.m_b * scale2.m_b) >> 8; + m_a |= (m_a & 0x00800000) ? 0xff000000 : 0; + m_r |= (m_r & 0x00800000) ? 0xff000000 : 0; + m_g |= (m_g & 0x00800000) ? 0xff000000 : 0; + m_b |= (m_b & 0x00800000) ? 0xff000000 : 0; + if ((UINT32)m_a > 255) { m_a = (m_a < 0) ? 0 : 255; } + if ((UINT32)m_r > 255) { m_r = (m_r < 0) ? 0 : 255; } + if ((UINT32)m_g > 255) { m_g = (m_g < 0) ? 0 : 255; } + if ((UINT32)m_b > 255) { m_b = (m_b < 0) ? 0 : 255; } +} + +#endif // !defined(__ALTIVEC__) diff --git a/src/devices/video/rgbgen.h b/src/devices/video/rgbgen.h new file mode 100644 index 00000000000..dae5a2984d3 --- /dev/null +++ b/src/devices/video/rgbgen.h @@ -0,0 +1,507 @@ +// license:BSD-3-Clause +// copyright-holders:Vas Crabb, Ryan Holtz +/*************************************************************************** + + rgbgen.h + + General RGB utilities. + +***************************************************************************/ + +#ifndef __RGBGEN__ +#define __RGBGEN__ + + +/*************************************************************************** + TYPE DEFINITIONS +***************************************************************************/ + +class rgbaint_t +{ +public: + inline rgbaint_t() { } + inline rgbaint_t(UINT32 rgba) { set(rgba); } + inline rgbaint_t(INT32 a, INT32 r, INT32 g, INT32 b) { set(a, r, g, b); } + inline rgbaint_t(rgb_t& rgba) { set(rgba); } + + inline void set(rgbaint_t& other) { set(other.m_a, other.m_r, other.m_g, other.m_b); } + inline void set(UINT32 rgba) { set((rgba >> 24) & 0xff, (rgba >> 16) & 0xff, (rgba >> 8) & 0xff, rgba & 0xff); } + inline void set(INT32 a, INT32 r, INT32 g, INT32 b) + { + m_a = a; + m_r = r; + m_g = g; + m_b = b; + } + inline void set(rgb_t& rgba) { set(rgba.a(), rgba.r(), rgba.g(), rgba.b()); } + + inline rgb_t to_rgba() + { + return rgb_t(m_a, m_r, m_g, m_b); + } + + inline rgb_t to_rgba_clamp() + { + UINT8 a = (m_a < 0) ? 0 : (m_a > 255) ? 255 : m_a; + UINT8 r = (m_r < 0) ? 0 : (m_r > 255) ? 255 : m_r; + UINT8 g = (m_g < 0) ? 0 : (m_g > 255) ? 255 : m_g; + UINT8 b = (m_b < 0) ? 0 : (m_b > 255) ? 255 : m_b; + return rgb_t(a, r, g, b); + } + + inline void add(const rgbaint_t& color) + { + add_imm_rgba(color.m_a, color.m_r, color.m_g, color.m_b); + } + + inline void add_imm(const INT32 imm) + { + add_imm_rgba(imm, imm, imm, imm); + } + + inline void add_imm_rgba(const INT32 a, const INT32 r, const INT32 g, const INT32 b) + { + m_a += a; + m_r += r; + m_g += g; + m_b += b; + } + + inline void sub(const rgbaint_t& color) + { + sub_imm_rgba(color.m_a, color.m_r, color.m_g, color.m_b); + } + + inline void sub_imm(const INT32 imm) + { + sub_imm_rgba(imm, imm, imm, imm); + } + + inline void sub_imm_rgba(const INT32 a, const INT32 r, const INT32 g, const INT32 b) + { + m_a -= a; + m_r -= r; + m_g -= g; + m_b -= b; + } + + inline void subr(rgbaint_t& color) + { + subr_imm_rgba(color.m_a, color.m_r, color.m_g, color.m_b); + } + + inline void subr_imm(const INT32 imm) + { + subr_imm_rgba(imm, imm, imm, imm); + } + + inline void subr_imm_rgba(const INT32 a, const INT32 r, const INT32 g, const INT32 b) + { + m_a = a - m_a; + m_r = r - m_r; + m_g = g - m_g; + m_b = b - m_b; + } + + inline void set_a(const INT32 value) + { + m_a = value; + } + + inline void set_r(const INT32 value) + { + m_r = value; + } + + inline void set_g(const INT32 value) + { + m_g = value; + } + + inline void set_b(const INT32 value) + { + m_b = value; + } + + inline UINT8 get_a() const + { + return m_a; + } + + inline UINT8 get_r() const + { + return m_r; + } + + inline UINT8 get_g() const + { + return m_g; + } + + inline UINT8 get_b() const + { + return m_b; + } + + inline INT32 get_a32() const + { + return m_a; + } + + inline INT32 get_r32() const + { + return m_r; + } + + inline INT32 get_g32() const + { + return m_g; + } + + inline INT32 get_b32() const + { + return m_b; + } + + inline void mul(rgbaint_t& color) + { + mul_imm_rgba(color.m_a, color.m_r, color.m_g, color.m_b); + } + + inline void mul_imm(const INT32 imm) + { + mul_imm_rgba(imm, imm, imm, imm); + } + + inline void mul_imm_rgba(const INT32 a, const INT32 r, const INT32 g, const INT32 b) + { + m_a *= a; + m_r *= r; + m_g *= g; + m_b *= b; + } + + inline void shl(const rgbaint_t& shift) + { + m_a <<= shift.m_a; + m_r <<= shift.m_r; + m_g <<= shift.m_g; + m_b <<= shift.m_b; + } + + inline void shl_imm(const UINT8 shift) + { + if (shift == 0) + return; + + m_a <<= shift; + m_r <<= shift; + m_g <<= shift; + m_b <<= shift; + } + + inline void shr(const rgbaint_t& shift) + { + m_a >>= shift.m_a; + m_r >>= shift.m_r; + m_g >>= shift.m_g; + m_b >>= shift.m_b; + } + + inline void shr_imm(const UINT8 shift) + { + if (shift == 0) + return; + + m_a >>= shift; + m_r >>= shift; + m_g >>= shift; + m_b >>= shift; + } + + inline void sra(const rgbaint_t& shift) + { + m_a >>= shift.m_a; + if (m_a & (1 << (31 - shift.m_a))) + m_a |= ~0 << (32 - shift.m_a); + + m_r >>= shift.m_r; + if (m_r & (1 << (31 - shift.m_r))) + m_r |= ~0 << (32 - shift.m_r); + + m_g >>= shift.m_g; + if (m_g & (1 << (31 - shift.m_g))) + m_g |= ~0 << (32 - shift.m_g); + + m_b >>= shift.m_b; + if (m_b & (1 << (31 - shift.m_b))) + m_b |= ~0 << (32 - shift.m_b); + } + + inline void sra_imm(const UINT8 shift) + { + const UINT32 high_bit = 1 << (31 - shift); + const UINT32 high_mask = ~0 << (32 - shift); + + m_a >>= shift; + if (m_a & high_bit) + m_a |= high_mask; + + m_r >>= shift; + if (m_r & high_bit) + m_r |= high_mask; + + m_g >>= shift; + if (m_g & high_bit) + m_g |= high_mask; + + m_b >>= shift; + if (m_b & high_bit) + m_b |= high_mask; + } + + inline void or_reg(const rgbaint_t& color) + { + or_imm_rgba(color.m_a, color.m_r, color.m_g, color.m_b); + } + + inline void or_imm(const INT32 imm) + { + or_imm_rgba(imm, imm, imm, imm); + } + + inline void or_imm_rgba(const INT32 a, const INT32 r, const INT32 g, const INT32 b) + { + m_a |= a; + m_r |= r; + m_g |= g; + m_b |= b; + } + + inline void and_reg(const rgbaint_t& color) + { + and_imm_rgba(color.m_a, color.m_r, color.m_g, color.m_b); + } + + inline void andnot_reg(const rgbaint_t& color) + { + and_imm_rgba(~color.m_a, ~color.m_r, ~color.m_g, ~color.m_b); + } + + inline void and_imm(const INT32 imm) + { + and_imm_rgba(imm, imm, imm, imm); + } + + inline void and_imm_rgba(const INT32 a, const INT32 r, const INT32 g, const INT32 b) + { + m_a &= a; + m_r &= r; + m_g &= g; + m_b &= b; + } + + inline void xor_reg(const rgbaint_t& color) + { + xor_imm_rgba(color.m_a, color.m_r, color.m_g, color.m_b); + } + + inline void xor_imm(const INT32 imm) + { + xor_imm_rgba(imm, imm, imm, imm); + } + + inline void xor_imm_rgba(const INT32 a, const INT32 r, const INT32 g, const INT32 b) + { + m_a ^= a; + m_r ^= r; + m_g ^= g; + m_b ^= b; + } + + inline void clamp_and_clear(const UINT32 sign) + { + if (m_a & sign) + m_a = 0; + + if (m_r & sign) + m_r = 0; + + if (m_g & sign) + m_g = 0; + + if (m_b & sign) + m_b = 0; + + m_a = (m_a < 0) ? 0 : (m_a > 255) ? 255 : m_a; + m_r = (m_r < 0) ? 0 : (m_r > 255) ? 255 : m_r; + m_g = (m_g < 0) ? 0 : (m_g > 255) ? 255 : m_g; + m_b = (m_b < 0) ? 0 : (m_b > 255) ? 255 : m_b; + } + + inline void clamp_to_uint8() + { + m_a = (m_a < 0) ? 0 : (m_a > 255) ? 255 : m_a; + m_r = (m_r < 0) ? 0 : (m_r > 255) ? 255 : m_r; + m_g = (m_g < 0) ? 0 : (m_g > 255) ? 255 : m_g; + m_b = (m_b < 0) ? 0 : (m_b > 255) ? 255 : m_b; + } + + inline void sign_extend(const UINT32 compare, const UINT32 sign) + { + if ((m_a & compare) == compare) + m_a |= sign; + + if ((m_r & compare) == compare) + m_r |= sign; + + if ((m_g & compare) == compare) + m_g |= sign; + + if ((m_b & compare) == compare) + m_b |= sign; + } + + inline void min(const INT32 value) + { + m_a = (m_a > value) ? value : m_a; + m_r = (m_r > value) ? value : m_r; + m_g = (m_g > value) ? value : m_g; + m_b = (m_b > value) ? value : m_b; + } + + void blend(const rgbaint_t& other, UINT8 factor); + + void scale_and_clamp(const rgbaint_t& scale); + void scale_imm_and_clamp(const INT32 scale); + void scale2_add_and_clamp(const rgbaint_t& scale, const rgbaint_t& other, const rgbaint_t& scale2); + void scale_add_and_clamp(const rgbaint_t& scale, const rgbaint_t& other); + void scale_imm_add_and_clamp(const INT32 scale, const rgbaint_t& other); + + inline void cmpeq(const rgbaint_t& value) + { + m_a = (m_a == value.m_a) ? 0xffffffff : 0; + m_r = (m_r == value.m_r) ? 0xffffffff : 0; + m_g = (m_g == value.m_g) ? 0xffffffff : 0; + m_b = (m_b == value.m_b) ? 0xffffffff : 0; + } + + inline void cmpeq_imm(const INT32 value) + { + m_a = (m_a == value) ? 0xffffffff : 0; + m_r = (m_r == value) ? 0xffffffff : 0; + m_g = (m_g == value) ? 0xffffffff : 0; + m_b = (m_b == value) ? 0xffffffff : 0; + } + + inline void cmpgt(const rgbaint_t& value) + { + m_a = (m_a > value.m_a) ? 0xffffffff : 0; + m_r = (m_r > value.m_r) ? 0xffffffff : 0; + m_g = (m_g > value.m_g) ? 0xffffffff : 0; + m_b = (m_b > value.m_b) ? 0xffffffff : 0; + } + + inline void cmpgt_imm(const INT32 value) + { + m_a = (m_a > value) ? 0xffffffff : 0; + m_r = (m_r > value) ? 0xffffffff : 0; + m_g = (m_g > value) ? 0xffffffff : 0; + m_b = (m_b > value) ? 0xffffffff : 0; + } + + inline void cmplt(const rgbaint_t& value) + { + m_a = (m_a < value.m_a) ? 0xffffffff : 0; + m_r = (m_r < value.m_r) ? 0xffffffff : 0; + m_g = (m_g < value.m_g) ? 0xffffffff : 0; + m_b = (m_b < value.m_b) ? 0xffffffff : 0; + } + + inline void cmplt_imm(const INT32 value) + { + m_a = (m_a < value) ? 0xffffffff : 0; + m_r = (m_r < value) ? 0xffffffff : 0; + m_g = (m_g < value) ? 0xffffffff : 0; + m_b = (m_b < value) ? 0xffffffff : 0; + } + + inline void merge_alpha(rgbaint_t& alpha) + { + m_a = alpha.m_a; + } + + inline rgbaint_t operator=(const rgbaint_t& other) + { + m_a = other.m_a; + m_r = other.m_r; + m_g = other.m_g; + m_b = other.m_b; + return *this; + } + + inline rgbaint_t& operator+=(const rgbaint_t& other) + { + m_a += other.m_a; + m_r += other.m_r; + m_g += other.m_g; + m_b += other.m_b; + return *this; + } + + inline rgbaint_t& operator+=(const INT32 other) + { + m_a += other; + m_r += other; + m_g += other; + m_b += other; + return *this; + } + + static UINT32 bilinear_filter(UINT32 rgb00, UINT32 rgb01, UINT32 rgb10, UINT32 rgb11, UINT8 u, UINT8 v) + { + UINT32 rb0 = (rgb00 & 0x00ff00ff) + ((((rgb01 & 0x00ff00ff) - (rgb00 & 0x00ff00ff)) * u) >> 8); + UINT32 rb1 = (rgb10 & 0x00ff00ff) + ((((rgb11 & 0x00ff00ff) - (rgb10 & 0x00ff00ff)) * u) >> 8); + + rgb00 >>= 8; + rgb01 >>= 8; + rgb10 >>= 8; + rgb11 >>= 8; + + UINT32 ag0 = (rgb00 & 0x00ff00ff) + ((((rgb01 & 0x00ff00ff) - (rgb00 & 0x00ff00ff)) * u) >> 8); + UINT32 ag1 = (rgb10 & 0x00ff00ff) + ((((rgb11 & 0x00ff00ff) - (rgb10 & 0x00ff00ff)) * u) >> 8); + + rb0 = (rb0 & 0x00ff00ff) + ((((rb1 & 0x00ff00ff) - (rb0 & 0x00ff00ff)) * v) >> 8); + ag0 = (ag0 & 0x00ff00ff) + ((((ag1 & 0x00ff00ff) - (ag0 & 0x00ff00ff)) * v) >> 8); + + return ((ag0 << 8) & 0xff00ff00) | (rb0 & 0x00ff00ff); + } + + inline void bilinear_filter_rgbaint(UINT32 rgb00, UINT32 rgb01, UINT32 rgb10, UINT32 rgb11, UINT8 u, UINT8 v) + { + UINT32 rb0 = (rgb00 & 0x00ff00ff) + ((((rgb01 & 0x00ff00ff) - (rgb00 & 0x00ff00ff)) * u) >> 8); + UINT32 rb1 = (rgb10 & 0x00ff00ff) + ((((rgb11 & 0x00ff00ff) - (rgb10 & 0x00ff00ff)) * u) >> 8); + + rgb00 >>= 8; + rgb01 >>= 8; + rgb10 >>= 8; + rgb11 >>= 8; + + UINT32 ag0 = (rgb00 & 0x00ff00ff) + ((((rgb01 & 0x00ff00ff) - (rgb00 & 0x00ff00ff)) * u) >> 8); + UINT32 ag1 = (rgb10 & 0x00ff00ff) + ((((rgb11 & 0x00ff00ff) - (rgb10 & 0x00ff00ff)) * u) >> 8); + + rb0 = (rb0 & 0x00ff00ff) + ((((rb1 & 0x00ff00ff) - (rb0 & 0x00ff00ff)) * v) >> 8); + ag0 = (ag0 & 0x00ff00ff) + ((((ag1 & 0x00ff00ff) - (ag0 & 0x00ff00ff)) * v) >> 8); + + UINT32 result = ((ag0 << 8) & 0xff00ff00) | (rb0 & 0x00ff00ff); + this->set(result); + } + +protected: + INT32 m_a; + INT32 m_r; + INT32 m_g; + INT32 m_b; +}; + +#endif /* __RGBGEN__ */ diff --git a/src/devices/video/rgbsse.c b/src/devices/video/rgbsse.c new file mode 100644 index 00000000000..ed20479fd9e --- /dev/null +++ b/src/devices/video/rgbsse.c @@ -0,0 +1,194 @@ +// license:BSD-3-Clause +// copyright-holders:Vas Crabb, Ryan Holtz +/*************************************************************************** + + rgbsse.c + + SSE optimized RGB utilities. + + WARNING: This code assumes SSE2 or greater capability. + +***************************************************************************/ + +#if (!defined(MAME_DEBUG) || defined(__OPTIMIZE__)) && (defined(__SSE2__) || defined(_MSC_VER)) && defined(PTR64) + +#include "emu.h" +#include +#include "rgbsse.h" + +/*************************************************************************** + TABLES +***************************************************************************/ + +const struct rgbaint_t::_statics rgbaint_t::statics = +{ + { 0 }, + { 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x0000, 0x0000 }, + { 0xffff, 0xffff, 0xffff, 0xffff, 0x0000, 0x0000, 0xffff, 0xffff }, + { 0xffff, 0xffff, 0x0000, 0x0000, 0xffff, 0xffff, 0xffff, 0xffff }, + { 0x0000, 0x0000, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff }, + { + { 0, 256, 0, 256, 0, 256, 0, 256 }, { 1, 255, 1, 255, 1, 255, 1, 255 }, + { 2, 254, 2, 254, 2, 254, 2, 254 }, { 3, 253, 3, 253, 3, 253, 3, 253 }, + { 4, 252, 4, 252, 4, 252, 4, 252 }, { 5, 251, 5, 251, 5, 251, 5, 251 }, + { 6, 250, 6, 250, 6, 250, 6, 250 }, { 7, 249, 7, 249, 7, 249, 7, 249 }, + { 8, 248, 8, 248, 8, 248, 8, 248 }, { 9, 247, 9, 247, 9, 247, 9, 247 }, + { 10, 246, 10, 246, 10, 246, 10, 246 }, { 11, 245, 11, 245, 11, 245, 11, 245 }, + { 12, 244, 12, 244, 12, 244, 12, 244 }, { 13, 243, 13, 243, 13, 243, 13, 243 }, + { 14, 242, 14, 242, 14, 242, 14, 242 }, { 15, 241, 15, 241, 15, 241, 15, 241 }, + { 16, 240, 16, 240, 16, 240, 16, 240 }, { 17, 239, 17, 239, 17, 239, 17, 239 }, + { 18, 238, 18, 238, 18, 238, 18, 238 }, { 19, 237, 19, 237, 19, 237, 19, 237 }, + { 20, 236, 20, 236, 20, 236, 20, 236 }, { 21, 235, 21, 235, 21, 235, 21, 235 }, + { 22, 234, 22, 234, 22, 234, 22, 234 }, { 23, 233, 23, 233, 23, 233, 23, 233 }, + { 24, 232, 24, 232, 24, 232, 24, 232 }, { 25, 231, 25, 231, 25, 231, 25, 231 }, + { 26, 230, 26, 230, 26, 230, 26, 230 }, { 27, 229, 27, 229, 27, 229, 27, 229 }, + { 28, 228, 28, 228, 28, 228, 28, 228 }, { 29, 227, 29, 227, 29, 227, 29, 227 }, + { 30, 226, 30, 226, 30, 226, 30, 226 }, { 31, 225, 31, 225, 31, 225, 31, 225 }, + { 32, 224, 32, 224, 32, 224, 32, 224 }, { 33, 223, 33, 223, 33, 223, 33, 223 }, + { 34, 222, 34, 222, 34, 222, 34, 222 }, { 35, 221, 35, 221, 35, 221, 35, 221 }, + { 36, 220, 36, 220, 36, 220, 36, 220 }, { 37, 219, 37, 219, 37, 219, 37, 219 }, + { 38, 218, 38, 218, 38, 218, 38, 218 }, { 39, 217, 39, 217, 39, 217, 39, 217 }, + { 40, 216, 40, 216, 40, 216, 40, 216 }, { 41, 215, 41, 215, 41, 215, 41, 215 }, + { 42, 214, 42, 214, 42, 214, 42, 214 }, { 43, 213, 43, 213, 43, 213, 43, 213 }, + { 44, 212, 44, 212, 44, 212, 44, 212 }, { 45, 211, 45, 211, 45, 211, 45, 211 }, + { 46, 210, 46, 210, 46, 210, 46, 210 }, { 47, 209, 47, 209, 47, 209, 47, 209 }, + { 48, 208, 48, 208, 48, 208, 48, 208 }, { 49, 207, 49, 207, 49, 207, 49, 207 }, + { 50, 206, 50, 206, 50, 206, 50, 206 }, { 51, 205, 51, 205, 51, 205, 51, 205 }, + { 52, 204, 52, 204, 52, 204, 52, 204 }, { 53, 203, 53, 203, 53, 203, 53, 203 }, + { 54, 202, 54, 202, 54, 202, 54, 202 }, { 55, 201, 55, 201, 55, 201, 55, 201 }, + { 56, 200, 56, 200, 56, 200, 56, 200 }, { 57, 199, 57, 199, 57, 199, 57, 199 }, + { 58, 198, 58, 198, 58, 198, 58, 198 }, { 59, 197, 59, 197, 59, 197, 59, 197 }, + { 60, 196, 60, 196, 60, 196, 60, 196 }, { 61, 195, 61, 195, 61, 195, 61, 195 }, + { 62, 194, 62, 194, 62, 194, 62, 194 }, { 63, 193, 63, 193, 63, 193, 63, 193 }, + { 64, 192, 64, 192, 64, 192, 64, 192 }, { 65, 191, 65, 191, 65, 191, 65, 191 }, + { 66, 190, 66, 190, 66, 190, 66, 190 }, { 67, 189, 67, 189, 67, 189, 67, 189 }, + { 68, 188, 68, 188, 68, 188, 68, 188 }, { 69, 187, 69, 187, 69, 187, 69, 187 }, + { 70, 186, 70, 186, 70, 186, 70, 186 }, { 71, 185, 71, 185, 71, 185, 71, 185 }, + { 72, 184, 72, 184, 72, 184, 72, 184 }, { 73, 183, 73, 183, 73, 183, 73, 183 }, + { 74, 182, 74, 182, 74, 182, 74, 182 }, { 75, 181, 75, 181, 75, 181, 75, 181 }, + { 76, 180, 76, 180, 76, 180, 76, 180 }, { 77, 179, 77, 179, 77, 179, 77, 179 }, + { 78, 178, 78, 178, 78, 178, 78, 178 }, { 79, 177, 79, 177, 79, 177, 79, 177 }, + { 80, 176, 80, 176, 80, 176, 80, 176 }, { 81, 175, 81, 175, 81, 175, 81, 175 }, + { 82, 174, 82, 174, 82, 174, 82, 174 }, { 83, 173, 83, 173, 83, 173, 83, 173 }, + { 84, 172, 84, 172, 84, 172, 84, 172 }, { 85, 171, 85, 171, 85, 171, 85, 171 }, + { 86, 170, 86, 170, 86, 170, 86, 170 }, { 87, 169, 87, 169, 87, 169, 87, 169 }, + { 88, 168, 88, 168, 88, 168, 88, 168 }, { 89, 167, 89, 167, 89, 167, 89, 167 }, + { 90, 166, 90, 166, 90, 166, 90, 166 }, { 91, 165, 91, 165, 91, 165, 91, 165 }, + { 92, 164, 92, 164, 92, 164, 92, 164 }, { 93, 163, 93, 163, 93, 163, 93, 163 }, + { 94, 162, 94, 162, 94, 162, 94, 162 }, { 95, 161, 95, 161, 95, 161, 95, 161 }, + { 96, 160, 96, 160, 96, 160, 96, 160 }, { 97, 159, 97, 159, 97, 159, 97, 159 }, + { 98, 158, 98, 158, 98, 158, 98, 158 }, { 99, 157, 99, 157, 99, 157, 99, 157 }, + { 100, 156, 100, 156, 100, 156, 100, 156 }, { 101, 155, 101, 155, 101, 155, 101, 155 }, + { 102, 154, 102, 154, 102, 154, 102, 154 }, { 103, 153, 103, 153, 103, 153, 103, 153 }, + { 104, 152, 104, 152, 104, 152, 104, 152 }, { 105, 151, 105, 151, 105, 151, 105, 151 }, + { 106, 150, 106, 150, 106, 150, 106, 150 }, { 107, 149, 107, 149, 107, 149, 107, 149 }, + { 108, 148, 108, 148, 108, 148, 108, 148 }, { 109, 147, 109, 147, 109, 147, 109, 147 }, + { 110, 146, 110, 146, 110, 146, 110, 146 }, { 111, 145, 111, 145, 111, 145, 111, 145 }, + { 112, 144, 112, 144, 112, 144, 112, 144 }, { 113, 143, 113, 143, 113, 143, 113, 143 }, + { 114, 142, 114, 142, 114, 142, 114, 142 }, { 115, 141, 115, 141, 115, 141, 115, 141 }, + { 116, 140, 116, 140, 116, 140, 116, 140 }, { 117, 139, 117, 139, 117, 139, 117, 139 }, + { 118, 138, 118, 138, 118, 138, 118, 138 }, { 119, 137, 119, 137, 119, 137, 119, 137 }, + { 120, 136, 120, 136, 120, 136, 120, 136 }, { 121, 135, 121, 135, 121, 135, 121, 135 }, + { 122, 134, 122, 134, 122, 134, 122, 134 }, { 123, 133, 123, 133, 123, 133, 123, 133 }, + { 124, 132, 124, 132, 124, 132, 124, 132 }, { 125, 131, 125, 131, 125, 131, 125, 131 }, + { 126, 130, 126, 130, 126, 130, 126, 130 }, { 127, 129, 127, 129, 127, 129, 127, 129 }, + { 128, 128, 128, 128, 128, 128, 128, 128 }, { 129, 127, 129, 127, 129, 127, 129, 127 }, + { 130, 126, 130, 126, 130, 126, 130, 126 }, { 131, 125, 131, 125, 131, 125, 131, 125 }, + { 132, 124, 132, 124, 132, 124, 132, 124 }, { 133, 123, 133, 123, 133, 123, 133, 123 }, + { 134, 122, 134, 122, 134, 122, 134, 122 }, { 135, 121, 135, 121, 135, 121, 135, 121 }, + { 136, 120, 136, 120, 136, 120, 136, 120 }, { 137, 119, 137, 119, 137, 119, 137, 119 }, + { 138, 118, 138, 118, 138, 118, 138, 118 }, { 139, 117, 139, 117, 139, 117, 139, 117 }, + { 140, 116, 140, 116, 140, 116, 140, 116 }, { 141, 115, 141, 115, 141, 115, 141, 115 }, + { 142, 114, 142, 114, 142, 114, 142, 114 }, { 143, 113, 143, 113, 143, 113, 143, 113 }, + { 144, 112, 144, 112, 144, 112, 144, 112 }, { 145, 111, 145, 111, 145, 111, 145, 111 }, + { 146, 110, 146, 110, 146, 110, 146, 110 }, { 147, 109, 147, 109, 147, 109, 147, 109 }, + { 148, 108, 148, 108, 148, 108, 148, 108 }, { 149, 107, 149, 107, 149, 107, 149, 107 }, + { 150, 106, 150, 106, 150, 106, 150, 106 }, { 151, 105, 151, 105, 151, 105, 151, 105 }, + { 152, 104, 152, 104, 152, 104, 152, 104 }, { 153, 103, 153, 103, 153, 103, 153, 103 }, + { 154, 102, 154, 102, 154, 102, 154, 102 }, { 155, 101, 155, 101, 155, 101, 155, 101 }, + { 156, 100, 156, 100, 156, 100, 156, 100 }, { 157, 99, 157, 99, 157, 99, 157, 99 }, + { 158, 98, 158, 98, 158, 98, 158, 98 }, { 159, 97, 159, 97, 159, 97, 159, 97 }, + { 160, 96, 160, 96, 160, 96, 160, 96 }, { 161, 95, 161, 95, 161, 95, 161, 95 }, + { 162, 94, 162, 94, 162, 94, 162, 94 }, { 163, 93, 163, 93, 163, 93, 163, 93 }, + { 164, 92, 164, 92, 164, 92, 164, 92 }, { 165, 91, 165, 91, 165, 91, 165, 91 }, + { 166, 90, 166, 90, 166, 90, 166, 90 }, { 167, 89, 167, 89, 167, 89, 167, 89 }, + { 168, 88, 168, 88, 168, 88, 168, 88 }, { 169, 87, 169, 87, 169, 87, 169, 87 }, + { 170, 86, 170, 86, 170, 86, 170, 86 }, { 171, 85, 171, 85, 171, 85, 171, 85 }, + { 172, 84, 172, 84, 172, 84, 172, 84 }, { 173, 83, 173, 83, 173, 83, 173, 83 }, + { 174, 82, 174, 82, 174, 82, 174, 82 }, { 175, 81, 175, 81, 175, 81, 175, 81 }, + { 176, 80, 176, 80, 176, 80, 176, 80 }, { 177, 79, 177, 79, 177, 79, 177, 79 }, + { 178, 78, 178, 78, 178, 78, 178, 78 }, { 179, 77, 179, 77, 179, 77, 179, 77 }, + { 180, 76, 180, 76, 180, 76, 180, 76 }, { 181, 75, 181, 75, 181, 75, 181, 75 }, + { 182, 74, 182, 74, 182, 74, 182, 74 }, { 183, 73, 183, 73, 183, 73, 183, 73 }, + { 184, 72, 184, 72, 184, 72, 184, 72 }, { 185, 71, 185, 71, 185, 71, 185, 71 }, + { 186, 70, 186, 70, 186, 70, 186, 70 }, { 187, 69, 187, 69, 187, 69, 187, 69 }, + { 188, 68, 188, 68, 188, 68, 188, 68 }, { 189, 67, 189, 67, 189, 67, 189, 67 }, + { 190, 66, 190, 66, 190, 66, 190, 66 }, { 191, 65, 191, 65, 191, 65, 191, 65 }, + { 192, 64, 192, 64, 192, 64, 192, 64 }, { 193, 63, 193, 63, 193, 63, 193, 63 }, + { 194, 62, 194, 62, 194, 62, 194, 62 }, { 195, 61, 195, 61, 195, 61, 195, 61 }, + { 196, 60, 196, 60, 196, 60, 196, 60 }, { 197, 59, 197, 59, 197, 59, 197, 59 }, + { 198, 58, 198, 58, 198, 58, 198, 58 }, { 199, 57, 199, 57, 199, 57, 199, 57 }, + { 200, 56, 200, 56, 200, 56, 200, 56 }, { 201, 55, 201, 55, 201, 55, 201, 55 }, + { 202, 54, 202, 54, 202, 54, 202, 54 }, { 203, 53, 203, 53, 203, 53, 203, 53 }, + { 204, 52, 204, 52, 204, 52, 204, 52 }, { 205, 51, 205, 51, 205, 51, 205, 51 }, + { 206, 50, 206, 50, 206, 50, 206, 50 }, { 207, 49, 207, 49, 207, 49, 207, 49 }, + { 208, 48, 208, 48, 208, 48, 208, 48 }, { 209, 47, 209, 47, 209, 47, 209, 47 }, + { 210, 46, 210, 46, 210, 46, 210, 46 }, { 211, 45, 211, 45, 211, 45, 211, 45 }, + { 212, 44, 212, 44, 212, 44, 212, 44 }, { 213, 43, 213, 43, 213, 43, 213, 43 }, + { 214, 42, 214, 42, 214, 42, 214, 42 }, { 215, 41, 215, 41, 215, 41, 215, 41 }, + { 216, 40, 216, 40, 216, 40, 216, 40 }, { 217, 39, 217, 39, 217, 39, 217, 39 }, + { 218, 38, 218, 38, 218, 38, 218, 38 }, { 219, 37, 219, 37, 219, 37, 219, 37 }, + { 220, 36, 220, 36, 220, 36, 220, 36 }, { 221, 35, 221, 35, 221, 35, 221, 35 }, + { 222, 34, 222, 34, 222, 34, 222, 34 }, { 223, 33, 223, 33, 223, 33, 223, 33 }, + { 224, 32, 224, 32, 224, 32, 224, 32 }, { 225, 31, 225, 31, 225, 31, 225, 31 }, + { 226, 30, 226, 30, 226, 30, 226, 30 }, { 227, 29, 227, 29, 227, 29, 227, 29 }, + { 228, 28, 228, 28, 228, 28, 228, 28 }, { 229, 27, 229, 27, 229, 27, 229, 27 }, + { 230, 26, 230, 26, 230, 26, 230, 26 }, { 231, 25, 231, 25, 231, 25, 231, 25 }, + { 232, 24, 232, 24, 232, 24, 232, 24 }, { 233, 23, 233, 23, 233, 23, 233, 23 }, + { 234, 22, 234, 22, 234, 22, 234, 22 }, { 235, 21, 235, 21, 235, 21, 235, 21 }, + { 236, 20, 236, 20, 236, 20, 236, 20 }, { 237, 19, 237, 19, 237, 19, 237, 19 }, + { 238, 18, 238, 18, 238, 18, 238, 18 }, { 239, 17, 239, 17, 239, 17, 239, 17 }, + { 240, 16, 240, 16, 240, 16, 240, 16 }, { 241, 15, 241, 15, 241, 15, 241, 15 }, + { 242, 14, 242, 14, 242, 14, 242, 14 }, { 243, 13, 243, 13, 243, 13, 243, 13 }, + { 244, 12, 244, 12, 244, 12, 244, 12 }, { 245, 11, 245, 11, 245, 11, 245, 11 }, + { 246, 10, 246, 10, 246, 10, 246, 10 }, { 247, 9, 247, 9, 247, 9, 247, 9 }, + { 248, 8, 248, 8, 248, 8, 248, 8 }, { 249, 7, 249, 7, 249, 7, 249, 7 }, + { 250, 6, 250, 6, 250, 6, 250, 6 }, { 251, 5, 251, 5, 251, 5, 251, 5 }, + { 252, 4, 252, 4, 252, 4, 252, 4 }, { 253, 3, 253, 3, 253, 3, 253, 3 }, + { 254, 2, 254, 2, 254, 2, 254, 2 }, { 255, 1, 255, 1, 255, 1, 255, 1 } + } +}; + + +/*************************************************************************** + HIGHER LEVEL OPERATIONS +***************************************************************************/ + +void rgbaint_t::blend(const rgbaint_t& other, UINT8 factor) +{ + __m128i scale1 = _mm_set1_epi32(factor); + __m128i scale2 = _mm_sub_epi32(_mm_set1_epi32(0x100), scale1); + + rgbaint_t scaled_other(other); + scaled_other.mul(scale2); + + mul(scale1); + add(scaled_other); + sra_imm(8); +} + +void rgbaint_t::scale_and_clamp(const rgbaint_t& scale) +{ + mul(scale); + sra_imm(8); + clamp_to_uint8(); +} + +void rgbaint_t::scale_imm_and_clamp(const INT32 scale) +{ + mul_imm(scale); + sra_imm(8); + clamp_to_uint8(); +} + +#endif // defined(__SSE2__) || defined(_MSC_VER) diff --git a/src/devices/video/rgbsse.h b/src/devices/video/rgbsse.h new file mode 100644 index 00000000000..0b729fabe46 --- /dev/null +++ b/src/devices/video/rgbsse.h @@ -0,0 +1,534 @@ +// license:BSD-3-Clause +// copyright-holders:Vas Crabb, Ryan Holtz +/*************************************************************************** + + rgbsse.h + + SSE optimized RGB utilities. + + WARNING: This code assumes SSE2 or greater capability. + +***************************************************************************/ + +#ifndef __RGBSSE__ +#define __RGBSSE__ + +#include + +/*************************************************************************** + TYPE DEFINITIONS +***************************************************************************/ + +class rgbaint_t +{ +public: + inline rgbaint_t() { } + inline rgbaint_t(UINT32 rgba) { set(rgba); } + inline rgbaint_t(INT32 a, INT32 r, INT32 g, INT32 b) { set(a, r, g, b); } + inline rgbaint_t(rgb_t& rgb) { set(rgb); } + inline rgbaint_t(__m128i rgba) { m_value = rgba; } + + inline void set(rgbaint_t& other) { m_value = other.m_value; } + inline void set(UINT32 rgba) { m_value = _mm_and_si128(_mm_set1_epi32(0xff), _mm_set_epi32(rgba >> 24, rgba >> 16, rgba >> 8, rgba)); } + inline void set(INT32 a, INT32 r, INT32 g, INT32 b) { m_value = _mm_set_epi32(a, r, g, b); } + inline void set(rgb_t& rgb) { m_value = _mm_unpacklo_epi16(_mm_unpacklo_epi8(_mm_cvtsi32_si128(rgb), _mm_setzero_si128()), _mm_setzero_si128()); } + + inline rgb_t to_rgba() + { + return _mm_cvtsi128_si32(_mm_packus_epi16(_mm_packs_epi32(m_value, _mm_setzero_si128()), _mm_setzero_si128())); + } + + inline rgb_t to_rgba_clamp() + { + return _mm_cvtsi128_si32(_mm_packus_epi16(_mm_packs_epi32(m_value, _mm_setzero_si128()), _mm_setzero_si128())); + } + + inline void add(const rgbaint_t& color2) + { + m_value = _mm_add_epi32(m_value, color2.m_value); + } + + inline void add_imm(const INT32 imm) + { + m_value = _mm_add_epi32(m_value, _mm_set1_epi32(imm)); + } + + inline void add_imm_rgba(const INT32 a, const INT32 r, const INT32 g, const INT32 b) + { + m_value = _mm_add_epi32(m_value, _mm_set_epi32(a, r, g, b)); + } + + inline void sub(const rgbaint_t& color2) + { + m_value = _mm_sub_epi32(m_value, color2.m_value); + } + + inline void sub_imm(const INT32 imm) + { + m_value = _mm_sub_epi32(m_value, _mm_set1_epi32(imm)); + } + + inline void sub_imm_rgba(const INT32 a, const INT32 r, const INT32 g, const INT32 b) + { + m_value = _mm_sub_epi32(m_value, _mm_set_epi32(a, r, g, b)); + } + + inline void subr(rgbaint_t& color2) + { + m_value = _mm_sub_epi32(color2.m_value, m_value); + } + + inline void subr_imm(const INT32 imm) + { + m_value = _mm_sub_epi32(_mm_set1_epi32(imm), m_value); + } + + inline void subr_imm_rgba(const INT32 a, const INT32 r, const INT32 g, const INT32 b) + { + m_value = _mm_sub_epi32(_mm_set_epi32(a, r, g, b), m_value); + } + + inline void set_a(const INT32 value) + { + m_value = _mm_or_si128(_mm_and_si128(m_value, alpha_mask()), _mm_set_epi32(value, 0, 0, 0)); + } + + inline void set_r(const INT32 value) + { + m_value = _mm_or_si128(_mm_and_si128(m_value, red_mask()), _mm_set_epi32(0, value, 0, 0)); + } + + inline void set_g(const INT32 value) + { + m_value = _mm_or_si128(_mm_and_si128(m_value, green_mask()), _mm_set_epi32(0, 0, value, 0)); + } + + inline void set_b(const INT32 value) + { + m_value = _mm_or_si128(_mm_and_si128(m_value, blue_mask()), _mm_set_epi32(0, 0, 0, value)); + } + + inline UINT8 get_a() const + { + return _mm_extract_epi16(m_value, 6); + } + + inline UINT8 get_r() const + { + return _mm_extract_epi16(m_value, 4); + } + + inline UINT8 get_g() const + { + return _mm_extract_epi16(m_value, 2); + } + + inline UINT8 get_b() const + { + return _mm_extract_epi16(m_value, 0); + } + + inline INT32 get_a32() const + { + return (_mm_extract_epi16(m_value, 7) << 16) | _mm_extract_epi16(m_value, 6); + } + + inline INT32 get_r32() const + { + return (_mm_extract_epi16(m_value, 5) << 16) | _mm_extract_epi16(m_value, 4); + } + + inline INT32 get_g32() const + { + return (_mm_extract_epi16(m_value, 3) << 16) | _mm_extract_epi16(m_value, 2); + } + + inline INT32 get_b32() const + { + return (_mm_extract_epi16(m_value, 1) << 16) | _mm_extract_epi16(m_value, 0); + } + + inline void mul(const rgbaint_t& color) + { + __m128i tmp1 = _mm_mul_epu32(m_value, color.m_value); + __m128i tmp2 = _mm_mul_epu32(_mm_srli_si128(m_value, 4), _mm_srli_si128(color.m_value, 4)); + m_value = _mm_unpacklo_epi32(_mm_shuffle_epi32(tmp1, _MM_SHUFFLE(0, 0, 2, 0)), _mm_shuffle_epi32(tmp2, _MM_SHUFFLE(0, 0, 2, 0))); + } + + inline void mul_imm(const INT32 imm) + { + __m128i immv = _mm_set1_epi32(imm); + __m128i tmp1 = _mm_mul_epu32(m_value, immv); + __m128i tmp2 = _mm_mul_epu32(_mm_srli_si128(m_value, 4), _mm_srli_si128(immv, 4)); + m_value = _mm_unpacklo_epi32(_mm_shuffle_epi32(tmp1, _MM_SHUFFLE(0, 0, 2, 0)), _mm_shuffle_epi32(tmp2, _MM_SHUFFLE(0, 0, 2, 0))); + } + + inline void mul_imm_rgba(const INT32 a, const INT32 r, const INT32 g, const INT32 b) + { + __m128i immv = _mm_set_epi32(a, r, g, b); + __m128i tmp1 = _mm_mul_epu32(m_value, immv); + __m128i tmp2 = _mm_mul_epu32(_mm_srli_si128(m_value, 4), _mm_srli_si128(immv, 4)); + m_value = _mm_unpacklo_epi32(_mm_shuffle_epi32(tmp1, _MM_SHUFFLE(0, 0, 2, 0)), _mm_shuffle_epi32(tmp2, _MM_SHUFFLE(0, 0, 2, 0))); + } + + inline void shl(const rgbaint_t& shift) + { + rgbaint_t areg(*this); + rgbaint_t rreg(*this); + rgbaint_t greg(*this); + rgbaint_t breg(*this); + rgbaint_t ashift(0, 0, 0, shift.get_a32()); + rgbaint_t rshift(0, 0, 0, shift.get_r32()); + rgbaint_t gshift(0, 0, 0, shift.get_g32()); + rgbaint_t bshift(0, 0, 0, shift.get_b32()); + areg.m_value = _mm_sll_epi32(areg.m_value, ashift.m_value); + rreg.m_value = _mm_sll_epi32(rreg.m_value, rshift.m_value); + greg.m_value = _mm_sll_epi32(greg.m_value, gshift.m_value); + breg.m_value = _mm_sll_epi32(breg.m_value, bshift.m_value); + set(areg.get_a32(), rreg.get_r32(), greg.get_g32(), breg.get_b32()); + } + + inline void shl_imm(const UINT8 shift) + { + m_value = _mm_slli_epi32(m_value, shift); + } + + inline void shr(const rgbaint_t& shift) + { + rgbaint_t areg(*this); + rgbaint_t rreg(*this); + rgbaint_t greg(*this); + rgbaint_t breg(*this); + rgbaint_t ashift(0, 0, 0, shift.get_a32()); + rgbaint_t rshift(0, 0, 0, shift.get_r32()); + rgbaint_t gshift(0, 0, 0, shift.get_g32()); + rgbaint_t bshift(0, 0, 0, shift.get_b32()); + areg.m_value = _mm_srl_epi32(areg.m_value, ashift.m_value); + rreg.m_value = _mm_srl_epi32(rreg.m_value, rshift.m_value); + greg.m_value = _mm_srl_epi32(greg.m_value, gshift.m_value); + breg.m_value = _mm_srl_epi32(breg.m_value, bshift.m_value); + set(areg.get_a32(), rreg.get_r32(), greg.get_g32(), breg.get_b32()); + } + + inline void shr_imm(const UINT8 shift) + { + m_value = _mm_srli_epi32(m_value, shift); + } + + inline void sra(const rgbaint_t& shift) + { + rgbaint_t areg(*this); + rgbaint_t rreg(*this); + rgbaint_t greg(*this); + rgbaint_t breg(*this); + rgbaint_t ashift(0, 0, 0, shift.get_a32()); + rgbaint_t rshift(0, 0, 0, shift.get_r32()); + rgbaint_t gshift(0, 0, 0, shift.get_g32()); + rgbaint_t bshift(0, 0, 0, shift.get_b32()); + areg.m_value = _mm_sra_epi32(areg.m_value, ashift.m_value); + rreg.m_value = _mm_sra_epi32(rreg.m_value, rshift.m_value); + greg.m_value = _mm_sra_epi32(greg.m_value, gshift.m_value); + breg.m_value = _mm_sra_epi32(breg.m_value, bshift.m_value); + set(areg.get_a32(), rreg.get_r32(), greg.get_g32(), breg.get_b32()); + } + + inline void sra_imm(const UINT8 shift) + { + m_value = _mm_srai_epi32(m_value, shift); + } + + inline void or_reg(const rgbaint_t& color2) + { + m_value = _mm_or_si128(m_value, color2.m_value); + } + + inline void or_imm(const INT32 value) + { + m_value = _mm_or_si128(m_value, _mm_set1_epi32(value)); + } + + inline void or_imm_rgba(const INT32 a, const INT32 r, const INT32 g, const INT32 b) + { + m_value = _mm_or_si128(m_value, _mm_set_epi32(a, r, g, b)); + } + + inline void and_reg(const rgbaint_t& color) + { + m_value = _mm_and_si128(m_value, color.m_value); + } + + inline void andnot_reg(const rgbaint_t& color) + { + m_value = _mm_andnot_si128(color.m_value, m_value); + } + + inline void and_imm(const INT32 value) + { + m_value = _mm_and_si128(m_value, _mm_set1_epi32(value)); + } + + inline void and_imm_rgba(const INT32 a, const INT32 r, const INT32 g, const INT32 b) + { + m_value = _mm_and_si128(m_value, _mm_set_epi32(a, r, g, b)); + } + + inline void xor_reg(const rgbaint_t& color2) + { + m_value = _mm_xor_si128(m_value, color2.m_value); + } + + inline void xor_imm(const INT32 value) + { + m_value = _mm_xor_si128(m_value, _mm_set1_epi32(value)); + } + + inline void xor_imm_rgba(const INT32 a, const INT32 r, const INT32 g, const INT32 b) + { + m_value = _mm_xor_si128(m_value, _mm_set_epi32(a, r, g, b)); + } + + inline void clamp_and_clear(const UINT32 sign) + { + __m128i vsign = _mm_set1_epi32(sign); + m_value = _mm_and_si128(m_value, _mm_cmpeq_epi32(_mm_and_si128(m_value, vsign), _mm_setzero_si128())); + vsign = _mm_srai_epi32(vsign, 1); + vsign = _mm_xor_si128(vsign, _mm_set1_epi32(0xffffffff)); + __m128i mask = _mm_cmpgt_epi32(m_value, vsign); + m_value = _mm_or_si128(_mm_and_si128(vsign, mask), _mm_and_si128(m_value, _mm_xor_si128(mask, _mm_set1_epi32(0xffffffff)))); + } + + inline void clamp_to_uint8() + { + m_value = _mm_packs_epi32(m_value, _mm_setzero_si128()); + m_value = _mm_packus_epi16(m_value, _mm_setzero_si128()); + m_value = _mm_unpacklo_epi8(m_value, _mm_setzero_si128()); + m_value = _mm_unpacklo_epi16(m_value, _mm_setzero_si128()); + } + + inline void sign_extend(const UINT32 compare, const UINT32 sign) + { + __m128i compare_vec = _mm_set1_epi32(compare); + __m128i compare_mask = _mm_cmpeq_epi32(_mm_and_si128(m_value, compare_vec), compare_vec); + __m128i compared = _mm_and_si128(_mm_set1_epi32(sign), compare_mask); + m_value = _mm_or_si128(m_value, compared); + } + + inline void min(const INT32 value) + { + __m128i val = _mm_set1_epi32(value); + __m128i is_greater_than = _mm_cmpgt_epi32(m_value, val); + + __m128i val_to_set = _mm_and_si128(val, is_greater_than); + __m128i keep_mask = _mm_xor_si128(is_greater_than, _mm_set1_epi32(0xffffffff)); + + m_value = _mm_and_si128(m_value, keep_mask); + m_value = _mm_or_si128(val_to_set, m_value); + } + + inline void max(const INT32 value) + { + __m128i val = _mm_set1_epi32(value); + __m128i is_less_than = _mm_cmplt_epi32(m_value, val); + + __m128i val_to_set = _mm_and_si128(val, is_less_than); + __m128i keep_mask = _mm_xor_si128(is_less_than, _mm_set1_epi32(0xffffffff)); + + m_value = _mm_and_si128(m_value, keep_mask); + m_value = _mm_or_si128(val_to_set, m_value); + } + + void blend(const rgbaint_t& other, UINT8 factor); + + void scale_and_clamp(const rgbaint_t& scale); + void scale_imm_and_clamp(const INT32 scale); + + inline void scale_imm_add_and_clamp(const INT32 scale, const rgbaint_t& other) + { + mul_imm(scale); + sra_imm(8); + add(other); + clamp_to_uint8(); + } + + inline void scale_add_and_clamp(const rgbaint_t& scale, const rgbaint_t& other) + { + mul(scale); + sra_imm(8); + add(other); + clamp_to_uint8(); + } + + inline void scale2_add_and_clamp(const rgbaint_t& scale, const rgbaint_t& other, const rgbaint_t& scale2) + { + rgbaint_t color2(other); + color2.mul(scale2); + + mul(scale); + add(color2); + sra_imm(8); + clamp_to_uint8(); + } + + inline void cmpeq(const rgbaint_t& value) + { + m_value = _mm_cmpeq_epi32(m_value, value.m_value); + } + + inline void cmpeq_imm(const INT32 value) + { + m_value = _mm_cmpeq_epi32(m_value, _mm_set1_epi32(value)); + } + + inline void cmpeq_imm_rgba(const INT32 a, const INT32 r, const INT32 g, const INT32 b) + { + m_value = _mm_cmpeq_epi32(m_value, _mm_set_epi32(a, r, g, b)); + } + + inline void cmpgt(const rgbaint_t& value) + { + m_value = _mm_cmpgt_epi32(m_value, value.m_value); + } + + inline void cmpgt_imm(const INT32 value) + { + m_value = _mm_cmpgt_epi32(m_value, _mm_set1_epi32(value)); + } + + inline void cmpgt_imm_rgba(const INT32 a, const INT32 r, const INT32 g, const INT32 b) + { + m_value = _mm_cmpgt_epi32(m_value, _mm_set_epi32(a, r, g, b)); + } + + inline void cmplt(const rgbaint_t& value) + { + m_value = _mm_cmplt_epi32(m_value, value.m_value); + } + + inline void cmplt_imm(const INT32 value) + { + m_value = _mm_cmplt_epi32(m_value, _mm_set1_epi32(value)); + } + + inline void cmplt_imm_rgba(const INT32 a, const INT32 r, const INT32 g, const INT32 b) + { + m_value = _mm_cmplt_epi32(m_value, _mm_set_epi32(a, r, g, b)); + } + + inline rgbaint_t operator=(const rgbaint_t& other) + { + m_value = other.m_value; + return *this; + } + + inline rgbaint_t& operator+=(const rgbaint_t& other) + { + m_value = _mm_add_epi32(m_value, other.m_value); + return *this; + } + + inline rgbaint_t& operator+=(const INT32 other) + { + m_value = _mm_add_epi32(m_value, _mm_set1_epi32(other)); + return *this; + } + + inline rgbaint_t& operator-=(const rgbaint_t& other) + { + m_value = _mm_sub_epi32(m_value, other.m_value); + return *this; + } + + inline rgbaint_t& operator*=(const rgbaint_t& other) + { + m_value = _mm_unpacklo_epi32(_mm_shuffle_epi32(_mm_mul_epu32(m_value, other.m_value), _MM_SHUFFLE(0, 0, 2, 0)), _mm_shuffle_epi32(_mm_mul_epu32(_mm_srli_si128(m_value, 4), _mm_srli_si128(other.m_value, 4)), _MM_SHUFFLE(0, 0, 2, 0))); + return *this; + } + + inline rgbaint_t& operator*=(const INT32 other) + { + const __m128i immv = _mm_set1_epi32(other); + m_value = _mm_unpacklo_epi32(_mm_shuffle_epi32(_mm_mul_epu32(m_value, immv), _MM_SHUFFLE(0, 0, 2, 0)), _mm_shuffle_epi32(_mm_mul_epu32(_mm_srli_si128(m_value, 4), _mm_srli_si128(immv, 4)), _MM_SHUFFLE(0, 0, 2, 0))); + return *this; + } + + inline rgbaint_t& operator>>=(const INT32 shift) + { + m_value = _mm_srai_epi32(m_value, shift); + return *this; + } + + inline void merge_alpha(const rgbaint_t& alpha) + { + m_value = _mm_insert_epi16(m_value, _mm_extract_epi16(alpha.m_value, 7), 7); + m_value = _mm_insert_epi16(m_value, _mm_extract_epi16(alpha.m_value, 6), 6); + } + + static UINT32 bilinear_filter(UINT32 rgb00, UINT32 rgb01, UINT32 rgb10, UINT32 rgb11, UINT8 u, UINT8 v) + { + __m128i color00 = _mm_cvtsi32_si128(rgb00); + __m128i color01 = _mm_cvtsi32_si128(rgb01); + __m128i color10 = _mm_cvtsi32_si128(rgb10); + __m128i color11 = _mm_cvtsi32_si128(rgb11); + + /* interleave color01 and color00 at the byte level */ + color01 = _mm_unpacklo_epi8(color01, color00); + color11 = _mm_unpacklo_epi8(color11, color10); + color01 = _mm_unpacklo_epi8(color01, _mm_setzero_si128()); + color11 = _mm_unpacklo_epi8(color11, _mm_setzero_si128()); + color01 = _mm_madd_epi16(color01, scale_factor(u)); + color11 = _mm_madd_epi16(color11, scale_factor(u)); + color01 = _mm_slli_epi32(color01, 15); + color11 = _mm_srli_epi32(color11, 1); + color01 = _mm_max_epi16(color01, color11); + color01 = _mm_madd_epi16(color01, scale_factor(v)); + color01 = _mm_srli_epi32(color01, 15); + color01 = _mm_packs_epi32(color01, _mm_setzero_si128()); + color01 = _mm_packus_epi16(color01, _mm_setzero_si128()); + return _mm_cvtsi128_si32(color01); + } + + inline void bilinear_filter_rgbaint(UINT32 rgb00, UINT32 rgb01, UINT32 rgb10, UINT32 rgb11, UINT8 u, UINT8 v) + { + __m128i color00 = _mm_cvtsi32_si128(rgb00); + __m128i color01 = _mm_cvtsi32_si128(rgb01); + __m128i color10 = _mm_cvtsi32_si128(rgb10); + __m128i color11 = _mm_cvtsi32_si128(rgb11); + + /* interleave color01 and color00 at the byte level */ + color01 = _mm_unpacklo_epi8(color01, color00); + color11 = _mm_unpacklo_epi8(color11, color10); + color01 = _mm_unpacklo_epi8(color01, _mm_setzero_si128()); + color11 = _mm_unpacklo_epi8(color11, _mm_setzero_si128()); + color01 = _mm_madd_epi16(color01, scale_factor(u)); + color11 = _mm_madd_epi16(color11, scale_factor(u)); + color01 = _mm_slli_epi32(color01, 15); + color11 = _mm_srli_epi32(color11, 1); + color01 = _mm_max_epi16(color01, color11); + color01 = _mm_madd_epi16(color01, scale_factor(v)); + m_value = _mm_srli_epi32(color01, 15); + } + +protected: + struct _statics + { + __m128 dummy_for_alignment; + UINT16 alpha_mask[8]; + UINT16 red_mask[8]; + UINT16 green_mask[8]; + UINT16 blue_mask[8]; + INT16 scale_table[256][8]; + }; + + static inline __m128i alpha_mask() { return *(__m128i *)&statics.alpha_mask[0]; } + static inline __m128i red_mask() { return *(__m128i *)&statics.red_mask[0]; } + static inline __m128i green_mask() { return *(__m128i *)&statics.green_mask[0]; } + static inline __m128i blue_mask() { return *(__m128i *)&statics.blue_mask[0]; } + static inline __m128i scale_factor(UINT8 index) { return *(__m128i *)&statics.scale_table[index][0]; } + + __m128i m_value; + + static const _statics statics; + +}; + +#endif /* __RGBSSE__ */ diff --git a/src/devices/video/rgbutil.h b/src/devices/video/rgbutil.h new file mode 100644 index 00000000000..15def4da2c0 --- /dev/null +++ b/src/devices/video/rgbutil.h @@ -0,0 +1,24 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + rgbutil.h + + Utility definitions for RGB manipulation. Allows RGB handling to be + performed in an abstracted fashion and optimized with SIMD. + +***************************************************************************/ + +#ifndef __RGBUTIL__ +#define __RGBUTIL__ + +/* use SSE on 64-bit implementations, where it can be assumed */ +#if (!defined(MAME_DEBUG) || defined(__OPTIMIZE__)) && (defined(__SSE2__) || defined(_MSC_VER)) && defined(PTR64) +#include "rgbsse.h" +#elif defined(__ALTIVEC__) +#include "rgbvmx.h" +#else +#include "rgbgen.h" +#endif + +#endif /* __RGBUTIL__ */ diff --git a/src/devices/video/rgbvmx.c b/src/devices/video/rgbvmx.c new file mode 100644 index 00000000000..a35572368a7 --- /dev/null +++ b/src/devices/video/rgbvmx.c @@ -0,0 +1,220 @@ +// license:BSD-3-Clause +// copyright-holders:Vas Crabb, Ryan Holtz +/*************************************************************************** + + rgbsse.c + + VMX/Altivec optimised RGB utilities. + +***************************************************************************/ + +#if defined(__ALTIVEC__) + +#include "emu.h" +#include "rgbutil.h" + +/*************************************************************************** + TABLES +***************************************************************************/ + +const rgbaint_t::VECU8 rgbaint_t::alpha_perm = { 16, 17, 18, 19, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }; +const rgbaint_t::VECU8 rgbaint_t::red_perm = { 0, 1, 2, 3, 16, 17, 18, 19, 8, 9, 10, 11, 12, 13, 14, 15 }; +const rgbaint_t::VECU8 rgbaint_t::green_perm = { 0, 1, 2, 3, 4, 5, 6, 7, 16, 17, 18, 19, 12, 13, 14, 15 }; +const rgbaint_t::VECU8 rgbaint_t::blue_perm = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 16, 17, 18, 19 }; +const rgbaint_t::VECS16 rgbaint_t::scale_table[256] = { + { 0, 256, 0, 256, 0, 256, 0, 256 }, { 1, 255, 1, 255, 1, 255, 1, 255 }, + { 2, 254, 2, 254, 2, 254, 2, 254 }, { 3, 253, 3, 253, 3, 253, 3, 253 }, + { 4, 252, 4, 252, 4, 252, 4, 252 }, { 5, 251, 5, 251, 5, 251, 5, 251 }, + { 6, 250, 6, 250, 6, 250, 6, 250 }, { 7, 249, 7, 249, 7, 249, 7, 249 }, + { 8, 248, 8, 248, 8, 248, 8, 248 }, { 9, 247, 9, 247, 9, 247, 9, 247 }, + { 10, 246, 10, 246, 10, 246, 10, 246 }, { 11, 245, 11, 245, 11, 245, 11, 245 }, + { 12, 244, 12, 244, 12, 244, 12, 244 }, { 13, 243, 13, 243, 13, 243, 13, 243 }, + { 14, 242, 14, 242, 14, 242, 14, 242 }, { 15, 241, 15, 241, 15, 241, 15, 241 }, + { 16, 240, 16, 240, 16, 240, 16, 240 }, { 17, 239, 17, 239, 17, 239, 17, 239 }, + { 18, 238, 18, 238, 18, 238, 18, 238 }, { 19, 237, 19, 237, 19, 237, 19, 237 }, + { 20, 236, 20, 236, 20, 236, 20, 236 }, { 21, 235, 21, 235, 21, 235, 21, 235 }, + { 22, 234, 22, 234, 22, 234, 22, 234 }, { 23, 233, 23, 233, 23, 233, 23, 233 }, + { 24, 232, 24, 232, 24, 232, 24, 232 }, { 25, 231, 25, 231, 25, 231, 25, 231 }, + { 26, 230, 26, 230, 26, 230, 26, 230 }, { 27, 229, 27, 229, 27, 229, 27, 229 }, + { 28, 228, 28, 228, 28, 228, 28, 228 }, { 29, 227, 29, 227, 29, 227, 29, 227 }, + { 30, 226, 30, 226, 30, 226, 30, 226 }, { 31, 225, 31, 225, 31, 225, 31, 225 }, + { 32, 224, 32, 224, 32, 224, 32, 224 }, { 33, 223, 33, 223, 33, 223, 33, 223 }, + { 34, 222, 34, 222, 34, 222, 34, 222 }, { 35, 221, 35, 221, 35, 221, 35, 221 }, + { 36, 220, 36, 220, 36, 220, 36, 220 }, { 37, 219, 37, 219, 37, 219, 37, 219 }, + { 38, 218, 38, 218, 38, 218, 38, 218 }, { 39, 217, 39, 217, 39, 217, 39, 217 }, + { 40, 216, 40, 216, 40, 216, 40, 216 }, { 41, 215, 41, 215, 41, 215, 41, 215 }, + { 42, 214, 42, 214, 42, 214, 42, 214 }, { 43, 213, 43, 213, 43, 213, 43, 213 }, + { 44, 212, 44, 212, 44, 212, 44, 212 }, { 45, 211, 45, 211, 45, 211, 45, 211 }, + { 46, 210, 46, 210, 46, 210, 46, 210 }, { 47, 209, 47, 209, 47, 209, 47, 209 }, + { 48, 208, 48, 208, 48, 208, 48, 208 }, { 49, 207, 49, 207, 49, 207, 49, 207 }, + { 50, 206, 50, 206, 50, 206, 50, 206 }, { 51, 205, 51, 205, 51, 205, 51, 205 }, + { 52, 204, 52, 204, 52, 204, 52, 204 }, { 53, 203, 53, 203, 53, 203, 53, 203 }, + { 54, 202, 54, 202, 54, 202, 54, 202 }, { 55, 201, 55, 201, 55, 201, 55, 201 }, + { 56, 200, 56, 200, 56, 200, 56, 200 }, { 57, 199, 57, 199, 57, 199, 57, 199 }, + { 58, 198, 58, 198, 58, 198, 58, 198 }, { 59, 197, 59, 197, 59, 197, 59, 197 }, + { 60, 196, 60, 196, 60, 196, 60, 196 }, { 61, 195, 61, 195, 61, 195, 61, 195 }, + { 62, 194, 62, 194, 62, 194, 62, 194 }, { 63, 193, 63, 193, 63, 193, 63, 193 }, + { 64, 192, 64, 192, 64, 192, 64, 192 }, { 65, 191, 65, 191, 65, 191, 65, 191 }, + { 66, 190, 66, 190, 66, 190, 66, 190 }, { 67, 189, 67, 189, 67, 189, 67, 189 }, + { 68, 188, 68, 188, 68, 188, 68, 188 }, { 69, 187, 69, 187, 69, 187, 69, 187 }, + { 70, 186, 70, 186, 70, 186, 70, 186 }, { 71, 185, 71, 185, 71, 185, 71, 185 }, + { 72, 184, 72, 184, 72, 184, 72, 184 }, { 73, 183, 73, 183, 73, 183, 73, 183 }, + { 74, 182, 74, 182, 74, 182, 74, 182 }, { 75, 181, 75, 181, 75, 181, 75, 181 }, + { 76, 180, 76, 180, 76, 180, 76, 180 }, { 77, 179, 77, 179, 77, 179, 77, 179 }, + { 78, 178, 78, 178, 78, 178, 78, 178 }, { 79, 177, 79, 177, 79, 177, 79, 177 }, + { 80, 176, 80, 176, 80, 176, 80, 176 }, { 81, 175, 81, 175, 81, 175, 81, 175 }, + { 82, 174, 82, 174, 82, 174, 82, 174 }, { 83, 173, 83, 173, 83, 173, 83, 173 }, + { 84, 172, 84, 172, 84, 172, 84, 172 }, { 85, 171, 85, 171, 85, 171, 85, 171 }, + { 86, 170, 86, 170, 86, 170, 86, 170 }, { 87, 169, 87, 169, 87, 169, 87, 169 }, + { 88, 168, 88, 168, 88, 168, 88, 168 }, { 89, 167, 89, 167, 89, 167, 89, 167 }, + { 90, 166, 90, 166, 90, 166, 90, 166 }, { 91, 165, 91, 165, 91, 165, 91, 165 }, + { 92, 164, 92, 164, 92, 164, 92, 164 }, { 93, 163, 93, 163, 93, 163, 93, 163 }, + { 94, 162, 94, 162, 94, 162, 94, 162 }, { 95, 161, 95, 161, 95, 161, 95, 161 }, + { 96, 160, 96, 160, 96, 160, 96, 160 }, { 97, 159, 97, 159, 97, 159, 97, 159 }, + { 98, 158, 98, 158, 98, 158, 98, 158 }, { 99, 157, 99, 157, 99, 157, 99, 157 }, + { 100, 156, 100, 156, 100, 156, 100, 156 }, { 101, 155, 101, 155, 101, 155, 101, 155 }, + { 102, 154, 102, 154, 102, 154, 102, 154 }, { 103, 153, 103, 153, 103, 153, 103, 153 }, + { 104, 152, 104, 152, 104, 152, 104, 152 }, { 105, 151, 105, 151, 105, 151, 105, 151 }, + { 106, 150, 106, 150, 106, 150, 106, 150 }, { 107, 149, 107, 149, 107, 149, 107, 149 }, + { 108, 148, 108, 148, 108, 148, 108, 148 }, { 109, 147, 109, 147, 109, 147, 109, 147 }, + { 110, 146, 110, 146, 110, 146, 110, 146 }, { 111, 145, 111, 145, 111, 145, 111, 145 }, + { 112, 144, 112, 144, 112, 144, 112, 144 }, { 113, 143, 113, 143, 113, 143, 113, 143 }, + { 114, 142, 114, 142, 114, 142, 114, 142 }, { 115, 141, 115, 141, 115, 141, 115, 141 }, + { 116, 140, 116, 140, 116, 140, 116, 140 }, { 117, 139, 117, 139, 117, 139, 117, 139 }, + { 118, 138, 118, 138, 118, 138, 118, 138 }, { 119, 137, 119, 137, 119, 137, 119, 137 }, + { 120, 136, 120, 136, 120, 136, 120, 136 }, { 121, 135, 121, 135, 121, 135, 121, 135 }, + { 122, 134, 122, 134, 122, 134, 122, 134 }, { 123, 133, 123, 133, 123, 133, 123, 133 }, + { 124, 132, 124, 132, 124, 132, 124, 132 }, { 125, 131, 125, 131, 125, 131, 125, 131 }, + { 126, 130, 126, 130, 126, 130, 126, 130 }, { 127, 129, 127, 129, 127, 129, 127, 129 }, + { 128, 128, 128, 128, 128, 128, 128, 128 }, { 129, 127, 129, 127, 129, 127, 129, 127 }, + { 130, 126, 130, 126, 130, 126, 130, 126 }, { 131, 125, 131, 125, 131, 125, 131, 125 }, + { 132, 124, 132, 124, 132, 124, 132, 124 }, { 133, 123, 133, 123, 133, 123, 133, 123 }, + { 134, 122, 134, 122, 134, 122, 134, 122 }, { 135, 121, 135, 121, 135, 121, 135, 121 }, + { 136, 120, 136, 120, 136, 120, 136, 120 }, { 137, 119, 137, 119, 137, 119, 137, 119 }, + { 138, 118, 138, 118, 138, 118, 138, 118 }, { 139, 117, 139, 117, 139, 117, 139, 117 }, + { 140, 116, 140, 116, 140, 116, 140, 116 }, { 141, 115, 141, 115, 141, 115, 141, 115 }, + { 142, 114, 142, 114, 142, 114, 142, 114 }, { 143, 113, 143, 113, 143, 113, 143, 113 }, + { 144, 112, 144, 112, 144, 112, 144, 112 }, { 145, 111, 145, 111, 145, 111, 145, 111 }, + { 146, 110, 146, 110, 146, 110, 146, 110 }, { 147, 109, 147, 109, 147, 109, 147, 109 }, + { 148, 108, 148, 108, 148, 108, 148, 108 }, { 149, 107, 149, 107, 149, 107, 149, 107 }, + { 150, 106, 150, 106, 150, 106, 150, 106 }, { 151, 105, 151, 105, 151, 105, 151, 105 }, + { 152, 104, 152, 104, 152, 104, 152, 104 }, { 153, 103, 153, 103, 153, 103, 153, 103 }, + { 154, 102, 154, 102, 154, 102, 154, 102 }, { 155, 101, 155, 101, 155, 101, 155, 101 }, + { 156, 100, 156, 100, 156, 100, 156, 100 }, { 157, 99, 157, 99, 157, 99, 157, 99 }, + { 158, 98, 158, 98, 158, 98, 158, 98 }, { 159, 97, 159, 97, 159, 97, 159, 97 }, + { 160, 96, 160, 96, 160, 96, 160, 96 }, { 161, 95, 161, 95, 161, 95, 161, 95 }, + { 162, 94, 162, 94, 162, 94, 162, 94 }, { 163, 93, 163, 93, 163, 93, 163, 93 }, + { 164, 92, 164, 92, 164, 92, 164, 92 }, { 165, 91, 165, 91, 165, 91, 165, 91 }, + { 166, 90, 166, 90, 166, 90, 166, 90 }, { 167, 89, 167, 89, 167, 89, 167, 89 }, + { 168, 88, 168, 88, 168, 88, 168, 88 }, { 169, 87, 169, 87, 169, 87, 169, 87 }, + { 170, 86, 170, 86, 170, 86, 170, 86 }, { 171, 85, 171, 85, 171, 85, 171, 85 }, + { 172, 84, 172, 84, 172, 84, 172, 84 }, { 173, 83, 173, 83, 173, 83, 173, 83 }, + { 174, 82, 174, 82, 174, 82, 174, 82 }, { 175, 81, 175, 81, 175, 81, 175, 81 }, + { 176, 80, 176, 80, 176, 80, 176, 80 }, { 177, 79, 177, 79, 177, 79, 177, 79 }, + { 178, 78, 178, 78, 178, 78, 178, 78 }, { 179, 77, 179, 77, 179, 77, 179, 77 }, + { 180, 76, 180, 76, 180, 76, 180, 76 }, { 181, 75, 181, 75, 181, 75, 181, 75 }, + { 182, 74, 182, 74, 182, 74, 182, 74 }, { 183, 73, 183, 73, 183, 73, 183, 73 }, + { 184, 72, 184, 72, 184, 72, 184, 72 }, { 185, 71, 185, 71, 185, 71, 185, 71 }, + { 186, 70, 186, 70, 186, 70, 186, 70 }, { 187, 69, 187, 69, 187, 69, 187, 69 }, + { 188, 68, 188, 68, 188, 68, 188, 68 }, { 189, 67, 189, 67, 189, 67, 189, 67 }, + { 190, 66, 190, 66, 190, 66, 190, 66 }, { 191, 65, 191, 65, 191, 65, 191, 65 }, + { 192, 64, 192, 64, 192, 64, 192, 64 }, { 193, 63, 193, 63, 193, 63, 193, 63 }, + { 194, 62, 194, 62, 194, 62, 194, 62 }, { 195, 61, 195, 61, 195, 61, 195, 61 }, + { 196, 60, 196, 60, 196, 60, 196, 60 }, { 197, 59, 197, 59, 197, 59, 197, 59 }, + { 198, 58, 198, 58, 198, 58, 198, 58 }, { 199, 57, 199, 57, 199, 57, 199, 57 }, + { 200, 56, 200, 56, 200, 56, 200, 56 }, { 201, 55, 201, 55, 201, 55, 201, 55 }, + { 202, 54, 202, 54, 202, 54, 202, 54 }, { 203, 53, 203, 53, 203, 53, 203, 53 }, + { 204, 52, 204, 52, 204, 52, 204, 52 }, { 205, 51, 205, 51, 205, 51, 205, 51 }, + { 206, 50, 206, 50, 206, 50, 206, 50 }, { 207, 49, 207, 49, 207, 49, 207, 49 }, + { 208, 48, 208, 48, 208, 48, 208, 48 }, { 209, 47, 209, 47, 209, 47, 209, 47 }, + { 210, 46, 210, 46, 210, 46, 210, 46 }, { 211, 45, 211, 45, 211, 45, 211, 45 }, + { 212, 44, 212, 44, 212, 44, 212, 44 }, { 213, 43, 213, 43, 213, 43, 213, 43 }, + { 214, 42, 214, 42, 214, 42, 214, 42 }, { 215, 41, 215, 41, 215, 41, 215, 41 }, + { 216, 40, 216, 40, 216, 40, 216, 40 }, { 217, 39, 217, 39, 217, 39, 217, 39 }, + { 218, 38, 218, 38, 218, 38, 218, 38 }, { 219, 37, 219, 37, 219, 37, 219, 37 }, + { 220, 36, 220, 36, 220, 36, 220, 36 }, { 221, 35, 221, 35, 221, 35, 221, 35 }, + { 222, 34, 222, 34, 222, 34, 222, 34 }, { 223, 33, 223, 33, 223, 33, 223, 33 }, + { 224, 32, 224, 32, 224, 32, 224, 32 }, { 225, 31, 225, 31, 225, 31, 225, 31 }, + { 226, 30, 226, 30, 226, 30, 226, 30 }, { 227, 29, 227, 29, 227, 29, 227, 29 }, + { 228, 28, 228, 28, 228, 28, 228, 28 }, { 229, 27, 229, 27, 229, 27, 229, 27 }, + { 230, 26, 230, 26, 230, 26, 230, 26 }, { 231, 25, 231, 25, 231, 25, 231, 25 }, + { 232, 24, 232, 24, 232, 24, 232, 24 }, { 233, 23, 233, 23, 233, 23, 233, 23 }, + { 234, 22, 234, 22, 234, 22, 234, 22 }, { 235, 21, 235, 21, 235, 21, 235, 21 }, + { 236, 20, 236, 20, 236, 20, 236, 20 }, { 237, 19, 237, 19, 237, 19, 237, 19 }, + { 238, 18, 238, 18, 238, 18, 238, 18 }, { 239, 17, 239, 17, 239, 17, 239, 17 }, + { 240, 16, 240, 16, 240, 16, 240, 16 }, { 241, 15, 241, 15, 241, 15, 241, 15 }, + { 242, 14, 242, 14, 242, 14, 242, 14 }, { 243, 13, 243, 13, 243, 13, 243, 13 }, + { 244, 12, 244, 12, 244, 12, 244, 12 }, { 245, 11, 245, 11, 245, 11, 245, 11 }, + { 246, 10, 246, 10, 246, 10, 246, 10 }, { 247, 9, 247, 9, 247, 9, 247, 9 }, + { 248, 8, 248, 8, 248, 8, 248, 8 }, { 249, 7, 249, 7, 249, 7, 249, 7 }, + { 250, 6, 250, 6, 250, 6, 250, 6 }, { 251, 5, 251, 5, 251, 5, 251, 5 }, + { 252, 4, 252, 4, 252, 4, 252, 4 }, { 253, 3, 253, 3, 253, 3, 253, 3 }, + { 254, 2, 254, 2, 254, 2, 254, 2 }, { 255, 1, 255, 1, 255, 1, 255, 1 } +}; + + +/*************************************************************************** + HIGHER LEVEL OPERATIONS +***************************************************************************/ + +void rgbaint_t::blend(const rgbaint_t& other, UINT8 factor) +{ + const VECU32 shift = vec_splat_u32(-16); + const VECS32 scale1 = { factor, factor, factor, factor }; + const VECS32 scale2 = { 0x100 - factor, 0x100 - factor, 0x100 - factor, 0x100 - factor, }; + + VECU32 temp = vec_msum((VECU16)m_value, (VECU16)vec_rl(scale1, shift), vec_splat_u32(0)); + temp = vec_msum((VECU16)other.m_value, (VECU16)vec_rl(scale2, shift), temp); + + m_value = vec_msum((VECU16)m_value, (VECU16)scale1, vec_mulo((VECU16)other.m_value, (VECU16)scale2)); + m_value = vec_add(vec_sl(temp, shift), (VECU32)m_value); + sra_imm(8); +} + +void rgbaint_t::scale_and_clamp(const rgbaint_t& scale) +{ + mul(scale); + sra_imm(8); + max(0); + min(255); +} + +void rgbaint_t::scale_imm_and_clamp(const INT32 scale) +{ + mul_imm(scale); + sra_imm(8); + max(0); + min(255); +} + +void rgbaint_t::scale2_add_and_clamp(const rgbaint_t& scale, const rgbaint_t& other, const rgbaint_t& scale2) +{ + rgbaint_t color2(other); + color2.mul(scale2); + + mul(scale); + add(color2); + sra_imm(8); + max(0); + min(255); +} + +void rgbaint_t::scale_imm_add_and_clamp(const INT32 scale, const rgbaint_t& other) +{ + mul_imm(scale); + sra_imm(8); + add(other); + max(0); + min(255); +} + +void rgbaint_t::scale_add_and_clamp(const rgbaint_t& scale, const rgbaint_t& other) +{ + mul(scale); + sra_imm(8); + add(other); + max(0); + min(255); +} + +#endif // defined(__ALTIVEC__) diff --git a/src/devices/video/rgbvmx.h b/src/devices/video/rgbvmx.h new file mode 100644 index 00000000000..10c235eaa5a --- /dev/null +++ b/src/devices/video/rgbvmx.h @@ -0,0 +1,509 @@ +// license:BSD-3-Clause +// copyright-holders:Vas Crabb, Ryan Holtz +/*************************************************************************** + + rgbvmx.h + + VMX/Altivec optimised RGB utilities. + +***************************************************************************/ + +#ifndef __RGBVMX__ +#define __RGBVMX__ + +#include + +/*************************************************************************** + TYPE DEFINITIONS +***************************************************************************/ + +class rgbaint_t +{ +public: + inline rgbaint_t() { } + inline rgbaint_t(UINT32 rgba) { set(rgba); } + inline rgbaint_t(INT32 a, INT32 r, INT32 g, INT32 b) { set(a, r, g, b); } + inline rgbaint_t(rgb_t& rgb) { set(rgb); } + + inline void set(rgbaint_t& other) { m_value = other.m_value; } + + inline void set(UINT32 rgba) + { + const VECU32 zero = { 0, 0, 0, 0 }; + const VECS8 temp = vec_perm(vec_lde(0, &rgba), zero, vec_lvsl(0, &rgba)); + m_value = vec_mergeh((VECS16)zero, (VECS16)vec_mergeh((VECS8)zero, temp)); + } + + inline void set(INT32 a, INT32 r, INT32 g, INT32 b) + { + VECS32 result = { a, r, g, b }; + m_value = result; + } + + inline void set(rgb_t& rgb) + { + const VECU32 zero = { 0, 0, 0, 0 }; + const VECS8 temp = vec_perm(vec_lde(0, rgb.ptr()), zero, vec_lvsl(0, rgb.ptr())); + m_value = vec_mergeh((VECS16)zero, (VECS16)vec_mergeh((VECS8)zero, temp)); + } + + inline rgb_t to_rgba() + { + VECU32 temp = vec_pack(m_value, m_value); + temp = vec_pack((VECU16)temp, (VECU16)temp); + UINT32 result; + vec_ste(temp, 0, &result); + return result; + } + + inline rgb_t to_rgba_clamp() + { + VECU32 temp = vec_packs(m_value, m_value); + temp = vec_packsu((VECU16)temp, (VECU16)temp); + UINT32 result; + vec_ste(temp, 0, &result); + return result; + } + + inline void add(const rgbaint_t& color2) + { + m_value = vec_add(m_value, color2.m_value); + } + + inline void add_imm(const INT32 imm) + { + const VECS32 temp = { imm, imm, imm, imm }; + m_value = vec_add(m_value, temp); + } + + inline void add_imm_rgba(const INT32 a, const INT32 r, const INT32 g, const INT32 b) + { + const VECS32 temp = { a, r, g, b }; + m_value = vec_add(m_value, temp); + } + + inline void sub(const rgbaint_t& color2) + { + m_value = vec_sub(m_value, color2.m_value); + } + + inline void sub_imm(const INT32 imm) + { + const VECS32 temp = { imm, imm, imm, imm }; + m_value = vec_sub(m_value, temp); + } + + inline void sub_imm_rgba(const INT32 a, const INT32 r, const INT32 g, const INT32 b) + { + const VECS32 temp = { a, r, g, b }; + m_value = vec_sub(m_value, temp); + } + + inline void subr(rgbaint_t& color2) + { + m_value = vec_sub(color2.m_value, m_value); + } + + inline void subr_imm(const INT32 imm) + { + const VECS32 temp = { imm, imm, imm, imm }; + m_value = vec_sub(temp, m_value); + } + + inline void subr_imm_rgba(const INT32 a, const INT32 r, const INT32 g, const INT32 b) + { + const VECS32 temp = { a, r, g, b }; + m_value = vec_sub(temp, m_value); + } + + inline void set_a(const INT32 value) + { + const VECS32 temp = { value, value, value, value }; + m_value = vec_perm(m_value, temp, alpha_perm); + } + + inline void set_r(const INT32 value) + { + const VECS32 temp = { value, value, value, value }; + m_value = vec_perm(m_value, temp, red_perm); + } + + inline void set_g(const INT32 value) + { + const VECS32 temp = { value, value, value, value }; + m_value = vec_perm(m_value, temp, green_perm); + } + + inline void set_b(const INT32 value) + { + const VECS32 temp = { value, value, value, value }; + m_value = vec_perm(m_value, temp, blue_perm); + } + + inline UINT8 get_a() const + { + UINT8 result; + vec_ste(vec_splat((VECU8)m_value, 3), 0, &result); + return result; + } + + inline UINT8 get_r() const + { + UINT8 result; + vec_ste(vec_splat((VECU8)m_value, 7), 0, &result); + return result; + } + + inline UINT8 get_g() const + { + UINT8 result; + vec_ste(vec_splat((VECU8)m_value, 11), 0, &result); + return result; + } + + inline UINT8 get_b() const + { + UINT8 result; + vec_ste(vec_splat((VECU8)m_value, 15), 0, &result); + return result; + } + + inline INT32 get_a32() const + { + INT32 result; + vec_ste(vec_splat(m_value, 0), 0, &result); + return result; + } + + inline INT32 get_r32() const + { + INT32 result; + vec_ste(vec_splat(m_value, 1), 0, &result); + return result; + } + + inline INT32 get_g32() const + { + INT32 result; + vec_ste(vec_splat(m_value, 2), 0, &result); + return result; + } + + inline INT32 get_b32() const + { + INT32 result; + vec_ste(vec_splat(m_value, 3), 0, &result); + return result; + } + + inline void mul(const rgbaint_t& color) + { + const VECU32 shift = vec_splat_u32(-16); + const VECU32 temp = vec_msum((VECU16)m_value, (VECU16)vec_rl(color.m_value, shift), vec_splat_u32(0)); + m_value = vec_add(vec_sl(temp, shift), vec_mulo((VECU16)m_value, (VECU16)color.m_value)); + } + + inline void mul_imm(const INT32 imm) + { + const VECU32 value = { imm, imm, imm, imm }; + const VECU32 shift = vec_splat_u32(-16); + const VECU32 temp = vec_msum((VECU16)m_value, (VECU16)vec_rl(value, shift), vec_splat_u32(0)); + m_value = vec_add(vec_sl(temp, shift), vec_mulo((VECU16)m_value, (VECU16)value)); + } + + inline void mul_imm_rgba(const INT32 a, const INT32 r, const INT32 g, const INT32 b) + { + const VECU32 value = { a, r, g, b }; + const VECU32 shift = vec_splat_u32(-16); + const VECU32 temp = vec_msum((VECU16)m_value, (VECU16)vec_rl(value, shift), vec_splat_u32(0)); + m_value = vec_add(vec_sl(temp, shift), vec_mulo((VECU16)m_value, (VECU16)value)); + } + + inline void shl(const rgbaint_t& shift) + { + const VECU32 limit = { 32, 32, 32, 32 }; + const VECU32 temp = vec_splat(shift.m_value, 3); + m_value = vec_and(vec_sl(m_value, temp), vec_cmpgt(limit, temp)); + } + + inline void shl_imm(const UINT8 shift) + { + const VECU32 temp = { shift, shift, shift, shift }; + m_value = vec_sl(m_value, temp); + } + + inline void shr(const rgbaint_t& shift) + { + const VECU32 limit = { 32, 32, 32, 32 }; + const VECU32 temp = vec_splat(shift.m_value, 3); + m_value = vec_and(vec_sr(m_value, temp), vec_cmpgt(limit, temp)); + } + + inline void shr_imm(const UINT8 shift) + { + const VECU32 temp = { shift, shift, shift, shift }; + m_value = vec_sr(m_value, temp); + } + + inline void sra(const rgbaint_t& shift) + { + const VECU32 limit = { 31, 31, 31, 31 }; + m_value = vec_sra(m_value, vec_min((VECU32)vec_splat(shift.m_value, 3), limit)); + } + + inline void sra_imm(const UINT8 shift) + { + const VECU32 temp = { shift, shift, shift, shift }; + m_value = vec_sra(m_value, temp); + } + + inline void or_reg(const rgbaint_t& color2) + { + m_value = vec_or(m_value, color2.m_value); + } + + inline void or_imm(const INT32 value) + { + const VECS32 temp = { value, value, value, value }; + m_value = vec_or(m_value, temp); + } + + inline void or_imm_rgba(const INT32 a, const INT32 r, const INT32 g, const INT32 b) + { + const VECS32 temp = { a, r, g, b }; + m_value = vec_or(m_value, temp); + } + + inline void and_reg(const rgbaint_t& color) + { + m_value = vec_and(m_value, color.m_value); + } + + inline void and_imm(const INT32 value) + { + const VECS32 temp = { value, value, value, value }; + m_value = vec_and(m_value, temp); + } + + inline void and_imm_rgba(const INT32 a, const INT32 r, const INT32 g, const INT32 b) + { + const VECS32 temp = { a, r, g, b }; + m_value = vec_and(m_value, temp); + } + + inline void xor_reg(const rgbaint_t& color2) + { + m_value = vec_xor(m_value, color2.m_value); + } + + inline void xor_imm(const INT32 value) + { + const VECS32 temp = { value, value, value, value }; + m_value = vec_xor(m_value, temp); + } + + inline void xor_imm_rgba(const INT32 a, const INT32 r, const INT32 g, const INT32 b) + { + const VECS32 temp = { a, r, g, b }; + m_value = vec_xor(m_value, temp); + } + + inline void clamp_and_clear(const UINT32 sign) + { + const VECS32 vzero = { 0, 0, 0, 0 }; + VECS32 vsign = { sign, sign, sign, sign }; + m_value = vec_and(m_value, vec_cmpeq(vec_and(m_value, vsign), vzero)); + vsign = vec_nor(vec_sra(vsign, vec_splat_u32(1)), vzero); + const VECS32 mask = vec_cmpgt(m_value, vsign); + m_value = vec_or(vec_and(vsign, mask), vec_and(m_value, vec_nor(mask, vzero))); + } + + inline void sign_extend(const UINT32 compare, const UINT32 sign) + { + const VECS32 compare_vec = { compare, compare, compare, compare }; + const VECS32 compare_mask = vec_cmpeq(vec_and(m_value, compare_vec), compare_vec); + const VECS32 sign_vec = { sign, sign, sign, sign }; + m_value = vec_or(m_value, vec_and(sign_vec, compare_mask)); + } + + inline void min(const INT32 value) + { + const VECS32 temp = { value, value, value, value }; + m_value = vec_min(m_value, temp); + } + + inline void max(const INT32 value) + { + const VECS32 temp = { value, value, value, value }; + m_value = vec_max(m_value, temp); + } + + void blend(const rgbaint_t& other, UINT8 factor); + + void scale_and_clamp(const rgbaint_t& scale); + void scale_imm_and_clamp(const INT32 scale); + void scale2_add_and_clamp(const rgbaint_t& scale, const rgbaint_t& other, const rgbaint_t& scale2); + void scale_add_and_clamp(const rgbaint_t& scale, const rgbaint_t& other); + void scale_imm_add_and_clamp(const INT32 scale, const rgbaint_t& other); + + inline void cmpeq(const rgbaint_t& value) + { + m_value = vec_cmpeq(m_value, value.m_value); + } + + inline void cmpeq_imm(const INT32 value) + { + const VECS32 temp = { value, value, value, value }; + m_value = vec_cmpeq(m_value, temp); + } + + inline void cmpeq_imm_rgba(const INT32 a, const INT32 r, const INT32 g, const INT32 b) + { + const VECS32 temp = { a, r, g, b }; + m_value = vec_cmpeq(m_value, temp); + } + + inline void cmpgt(const rgbaint_t& value) + { + m_value = vec_cmpgt(m_value, value.m_value); + } + + inline void cmpgt_imm(const INT32 value) + { + const VECS32 temp = { value, value, value, value }; + m_value = vec_cmpgt(m_value, temp); + } + + inline void cmpgt_imm_rgba(const INT32 a, const INT32 r, const INT32 g, const INT32 b) + { + const VECS32 temp = { a, r, g, b }; + m_value = vec_cmpgt(m_value, temp); + } + + inline void cmplt(const rgbaint_t& value) + { + m_value = vec_cmplt(m_value, value.m_value); + } + + inline void cmplt_imm(const INT32 value) + { + const VECS32 temp = { value, value, value, value }; + m_value = vec_cmplt(m_value, temp); + } + + inline void cmplt_imm_rgba(const INT32 a, const INT32 r, const INT32 g, const INT32 b) + { + const VECS32 temp = { a, r, g, b }; + m_value = vec_cmplt(m_value, temp); + } + + inline rgbaint_t operator=(const rgbaint_t& other) + { + m_value = other.m_value; + return *this; + } + + inline rgbaint_t& operator+=(const rgbaint_t& other) + { + m_value = vec_add(m_value, other.m_value); + return *this; + } + + inline rgbaint_t& operator+=(const INT32 other) + { + const VECS32 temp = { other, other, other, other }; + m_value = vec_add(m_value, temp); + return *this; + } + + inline rgbaint_t& operator-=(const rgbaint_t& other) + { + m_value = vec_sub(m_value, other.m_value); + return *this; + } + + inline rgbaint_t& operator*=(const rgbaint_t& other) + { + const VECU32 shift = vec_splat_u32(-16); + const VECU32 temp = vec_msum((VECU16)m_value, (VECU16)vec_rl(other.m_value, shift), vec_splat_u32(0)); + m_value = vec_add(vec_sl(temp, shift), vec_mulo((VECU16)m_value, (VECU16)other.m_value)); + return *this; + } + + inline rgbaint_t& operator*=(const INT32 other) + { + const VECS32 value = { other, other, other, other }; + const VECU32 shift = vec_splat_u32(-16); + const VECU32 temp = vec_msum((VECU16)m_value, (VECU16)vec_rl(value, shift), vec_splat_u32(0)); + m_value = vec_add(vec_sl(temp, shift), vec_mulo((VECU16)m_value, (VECU16)value)); + return *this; + } + + inline rgbaint_t& operator>>=(const INT32 shift) + { + const VECU32 temp = { shift, shift, shift, shift }; + m_value = vec_sra(m_value, temp); + return *this; + } + + inline void merge_alpha(const rgbaint_t& alpha) + { + m_value = vec_perm(m_value, alpha.m_value, alpha_perm); + } + + static UINT32 bilinear_filter(UINT32 rgb00, UINT32 rgb01, UINT32 rgb10, UINT32 rgb11, UINT8 u, UINT8 v) + { + const VECS32 zero = vec_splat_s32(0); + + VECS32 color00 = vec_perm((VECS32)vec_lde(0, &rgb00), zero, vec_lvsl(0, &rgb00)); + VECS32 color01 = vec_perm((VECS32)vec_lde(0, &rgb01), zero, vec_lvsl(0, &rgb01)); + VECS32 color10 = vec_perm((VECS32)vec_lde(0, &rgb10), zero, vec_lvsl(0, &rgb10)); + VECS32 color11 = vec_perm((VECS32)vec_lde(0, &rgb11), zero, vec_lvsl(0, &rgb11)); + + /* interleave color01 and color00 at the byte level */ + color01 = vec_mergeh((VECU8)color01, (VECU8)color00); + color11 = vec_mergeh((VECU8)color11, (VECU8)color10); + color01 = vec_mergeh((VECU8)zero, (VECU8)color01); + color11 = vec_mergeh((VECU8)zero, (VECU8)color11); + color01 = vec_msum((VECS16)color01, scale_table[u], zero); + color11 = vec_msum((VECS16)color11, scale_table[u], zero); + color01 = vec_sl(color01, vec_splat_u32(15)); + color11 = vec_sr(color11, vec_splat_u32(1)); + color01 = vec_max((VECS16)color01, (VECS16)color11); + color01 = vec_msum((VECS16)color01, scale_table[v], zero); + color01 = vec_sr(color01, vec_splat_u32(15)); + color01 = vec_packs(color01, color01); + color01 = vec_packsu((VECS16)color01, (VECS16)color01); + + UINT32 result; + vec_ste((VECU32)color01, 0, &result); + return result; + } + +protected: + typedef __vector signed char VECS8; + typedef __vector unsigned char VECU8; + typedef __vector signed short VECS16; + typedef __vector unsigned short VECU16; + typedef __vector signed int VECS32; + typedef __vector unsigned int VECU32; + + VECS32 m_value; + + static const VECU8 alpha_perm; + static const VECU8 red_perm; + static const VECU8 green_perm; + static const VECU8 blue_perm; + static const VECS16 scale_table[256]; +}; + + + +// altivec.h somehow redefines "bool" in a bad way on PowerPC Mac OS X. really. +#ifdef OSX_PPC +#undef vector +#undef pixel +#undef bool +#endif + +#endif /* __RGBVMX__ */ diff --git a/src/devices/video/saa5050.c b/src/devices/video/saa5050.c new file mode 100644 index 00000000000..2440d0bc357 --- /dev/null +++ b/src/devices/video/saa5050.c @@ -0,0 +1,525 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Mullard SAA5050 Teletext Character Generator emulation + + http://www.bighole.nl/pub/mirror/homepage.ntlworld.com/kryten_droid/teletext/spec/teletext_spec_1974.htm + +**********************************************************************/ + +/* + + TODO: + + - character rounding + - remote controller input + - boxing + +*/ + +#include "saa5050.h" + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type SAA5050 = &device_creator; +const device_type SAA5051 = &device_creator; +const device_type SAA5052 = &device_creator; +const device_type SAA5053 = &device_creator; +const device_type SAA5054 = &device_creator; +const device_type SAA5055 = &device_creator; +const device_type SAA5056 = &device_creator; +const device_type SAA5057 = &device_creator; + + +//------------------------------------------------- +// ROM( saa5050 ) +//------------------------------------------------- + +ROM_START( saa5050 ) + ROM_REGION( 0xa00, "chargen", 0 ) + ROM_LOAD( "saa5050", 0x0140, 0x08c0, BAD_DUMP CRC(78c17e3e) SHA1(4e1c59dc484505de1dc0b1ba7e5f70a54b0d4ccc) ) +ROM_END + + +//------------------------------------------------- +// ROM( saa5051 ) +//------------------------------------------------- + +ROM_START( saa5051 ) + ROM_REGION( 0xa00, "chargen", 0 ) + ROM_LOAD( "saa5051", 0x0140, 0x08c0, NO_DUMP ) +ROM_END + + +//------------------------------------------------- +// ROM( saa5052 ) +//------------------------------------------------- + +ROM_START( saa5052 ) + ROM_REGION( 0xa00, "chargen", 0 ) + ROM_LOAD( "saa5052", 0x0140, 0x08c0, BAD_DUMP CRC(cda3bf79) SHA1(cf5ea94459c09001d422dadc212bc970b4b4aa20) ) +ROM_END + + +//------------------------------------------------- +// ROM( saa5053 ) +//------------------------------------------------- + +ROM_START( saa5053 ) + ROM_REGION( 0xa00, "chargen", 0 ) + ROM_LOAD( "saa5053", 0x0140, 0x08c0, NO_DUMP ) +ROM_END + + +//------------------------------------------------- +// ROM( saa5054 ) +//------------------------------------------------- + +ROM_START( saa5054 ) + ROM_REGION( 0xa00, "chargen", 0 ) + ROM_LOAD( "saa5054", 0x0140, 0x08c0, NO_DUMP ) +ROM_END + + +//------------------------------------------------- +// ROM( saa5055 ) +//------------------------------------------------- + +ROM_START( saa5055 ) + ROM_REGION( 0xa00, "chargen", 0 ) + ROM_LOAD( "saa5055", 0x0140, 0x08c0, NO_DUMP ) +ROM_END + + +//------------------------------------------------- +// ROM( saa5056 ) +//------------------------------------------------- + +ROM_START( saa5056 ) + ROM_REGION( 0xa00, "chargen", 0 ) + ROM_LOAD( "saa5056", 0x0140, 0x08c0, NO_DUMP ) +ROM_END + + +//------------------------------------------------- +// ROM( saa5057 ) +//------------------------------------------------- + +ROM_START( saa5057 ) + ROM_REGION( 0xa00, "chargen", 0 ) + ROM_LOAD( "saa5057", 0x0140, 0x08c0, NO_DUMP ) +ROM_END + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *saa5050_device::device_rom_region() const +{ + return ROM_NAME( saa5050 ); +} + +const rom_entry *saa5051_device::device_rom_region() const +{ + return ROM_NAME( saa5051 ); +} + +const rom_entry *saa5052_device::device_rom_region() const +{ + return ROM_NAME( saa5052 ); +} + +const rom_entry *saa5053_device::device_rom_region() const +{ + return ROM_NAME( saa5053 ); +} + +const rom_entry *saa5054_device::device_rom_region() const +{ + return ROM_NAME( saa5054 ); +} + +const rom_entry *saa5055_device::device_rom_region() const +{ + return ROM_NAME( saa5055 ); +} + +const rom_entry *saa5056_device::device_rom_region() const +{ + return ROM_NAME( saa5056 ); +} + +const rom_entry *saa5057_device::device_rom_region() const +{ + return ROM_NAME( saa5057 ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// saa5050_device - constructor +//------------------------------------------------- + +saa5050_device::saa5050_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source), + m_char_rom(*this, "chargen"), + m_read_d(*this), + m_frame_count(0), + m_cols(0), + m_rows(0), + m_size(0) +{ +} + +saa5050_device::saa5050_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, SAA5050, "SAA5050 Video", tag, owner, clock, "saa5050", __FILE__), + m_char_rom(*this, "chargen"), + m_read_d(*this), + m_frame_count(0), + m_cols(0), + m_rows(0), + m_size(0) +{ +} + +saa5051_device::saa5051_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : saa5050_device(mconfig, SAA5051, "SAA5051", tag, owner, clock, "saa5051", __FILE__) { } + +saa5052_device::saa5052_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : saa5050_device(mconfig, SAA5052, "SAA5052", tag, owner, clock, "saa5052", __FILE__) { } + +saa5053_device::saa5053_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : saa5050_device(mconfig, SAA5053, "SAA5053", tag, owner, clock, "saa5053", __FILE__) { } + +saa5054_device::saa5054_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : saa5050_device(mconfig, SAA5054, "SAA5054", tag, owner, clock, "saa5054", __FILE__) { } + +saa5055_device::saa5055_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : saa5050_device(mconfig, SAA5055, "SAA5055", tag, owner, clock, "saa5055", __FILE__) { } + +saa5056_device::saa5056_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : saa5050_device(mconfig, SAA5056, "SAA5056", tag, owner, clock, "saa5056", __FILE__) { } + +saa5057_device::saa5057_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : saa5050_device(mconfig, SAA5057, "SAA5057", tag, owner, clock, "saa5057", __FILE__) { } + + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void saa5050_device::device_start() +{ + // resolve callbacks + m_read_d.resolve_safe(0); + + // register for state saving + save_item(NAME(m_code)); + save_item(NAME(m_last_code)); + save_item(NAME(m_char_data)); + save_item(NAME(m_bit)); + save_item(NAME(m_color)); + save_item(NAME(m_ra)); + save_item(NAME(m_bg)); + save_item(NAME(m_fg)); + save_item(NAME(m_graphics)); + save_item(NAME(m_separated)); + save_item(NAME(m_conceal)); + save_item(NAME(m_flash)); + save_item(NAME(m_boxed)); + save_item(NAME(m_double_height)); + save_item(NAME(m_double_height_top_row)); + save_item(NAME(m_double_height_bottom_row)); + save_item(NAME(m_hold)); + save_item(NAME(m_frame_count)); +} + + +//------------------------------------------------- +// device_start - device-specific reset +//------------------------------------------------- + +void saa5050_device::device_reset() +{ + m_ra = 0; + m_double_height_top_row = false; + m_double_height_bottom_row = false; +} + + +//------------------------------------------------- +// process_control_character - +//------------------------------------------------- + +void saa5050_device::process_control_character(UINT8 data) +{ + switch (data) + { + case ALPHA_RED: + case ALPHA_GREEN: + case ALPHA_YELLOW: + case ALPHA_BLUE: + case ALPHA_MAGENTA: + case ALPHA_CYAN: + case ALPHA_WHITE: + m_graphics = false; + m_conceal = false; + m_fg = data & 0x07; + break; + + case FLASH: + m_flash = true; + break; + + case STEADY: + m_flash = false; + break; + + case END_BOX: + case START_BOX: + // TODO + break; + + case NORMAL_HEIGHT: + m_double_height = 0; + break; + + case DOUBLE_HEIGHT: + if (!m_double_height_bottom_row) + { + m_double_height_top_row = true; + } + + m_double_height = 1; + break; + + case GRAPHICS_RED: + case GRAPHICS_GREEN: + case GRAPHICS_YELLOW: + case GRAPHICS_BLUE: + case GRAPHICS_MAGENTA: + case GRAPHICS_CYAN: + case GRAPHICS_WHITE: + m_graphics = true; + m_conceal = false; + m_fg = data & 0x07; + break; + + case CONCEAL_DISPLAY: + m_conceal = true; + break; + + case CONTIGUOUS_GFX: + m_separated = false; + break; + + case SEPARATED_GFX: + m_separated = true; + break; + + case BLACK_BACKGROUND: + m_bg = 0; + break; + + case NEW_BACKGROUND: + m_bg = m_fg; + break; + + case HOLD_GRAPHICS: + m_hold = true; + break; + + case RELEASE_GRAPHICS: + m_hold = false; + break; + } +} + + +//------------------------------------------------- +// get_character_data - +//------------------------------------------------- + +void saa5050_device::get_character_data(UINT8 data) +{ + if (m_graphics && (data & 0x20)) + { + data += (data & 0x40) ? 64 : 96; + if (m_separated) data += 64; + } + + if ((data < 0x20) && m_hold) data = m_last_code; + if (m_conceal) data = 0x20; + if (m_flash && (m_frame_count > 38)) data = 0x20; + if (m_double_height_bottom_row && !m_double_height) data = 0x20; + m_last_code = data; + + offs_t ra = m_ra >> 1; + if (m_double_height) ra >>= 1; + if (m_double_height && m_double_height_bottom_row) ra += 5; + + m_char_data = m_char_rom[(data * 10) + ra]; +} + + +//------------------------------------------------- +// dew_w - data entry window +//------------------------------------------------- + +WRITE_LINE_MEMBER( saa5050_device::dew_w ) +{ + if (state) + { + m_ra = 19; + m_double_height_top_row = false; + + m_frame_count++; + if (m_frame_count > 50) m_frame_count = 0; + } +} + + +//------------------------------------------------- +// lose_w - load output shift register enable +//------------------------------------------------- + +WRITE_LINE_MEMBER( saa5050_device::lose_w ) +{ + if (state) + { + m_ra++; + m_ra %= 20; + + m_fg = 7; + m_bg = 0; + m_graphics = false; + m_separated = false; + m_conceal = false; + m_flash = false; + m_boxed = false; + m_hold = false; + m_double_height = 0; + m_bit = 5; + m_last_code = 0x20; + + if (!m_ra) + { + m_double_height_bottom_row = m_double_height_top_row; + m_double_height_top_row = false; + } + } +} + + +//------------------------------------------------- +// write - character data write +//------------------------------------------------- + +void saa5050_device::write(UINT8 data) +{ + m_code = data & 0x7f; +} + + +//------------------------------------------------- +// f1_w - character clock +//------------------------------------------------- + +WRITE_LINE_MEMBER( saa5050_device::f1_w ) +{ + if (state) + { + process_control_character(m_code); + get_character_data(m_code); + } +} + + +//------------------------------------------------- +// tr6_w - pixel clock +//------------------------------------------------- + +WRITE_LINE_MEMBER( saa5050_device::tr6_w ) +{ + if (state) + { + m_color = BIT(m_char_data, m_bit) ? m_fg : m_bg; + + m_bit--; + if (m_bit < 0) m_bit = 5; + } +} + + +//------------------------------------------------- +// get_rgb - get output color +//------------------------------------------------- + +int saa5050_device::get_rgb() +{ + return m_color; +} + + +//------------------------------------------------- +// screen_update - +//------------------------------------------------- + +UINT32 saa5050_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + dew_w(1); + dew_w(0); + + for (int y = 0; y < m_rows * 20; y++) + { + int sy = y / 20; + int x = 0; + + lose_w(1); + lose_w(0); + + int ssy = m_double_height_bottom_row ? sy - 1 : sy; + offs_t video_ram_addr = ssy * m_size; + + for (int sx = 0; sx < m_cols; sx++) + { + UINT8 code = m_read_d(video_ram_addr++); + + write(code & 0x7f); + + f1_w(1); + f1_w(0); + + for (int bit = 0; bit < 6; bit++) + { + tr6_w(1); + tr6_w(0); + + int color = get_rgb(); + + if (BIT(code, 7)) color ^= 0x07; + + int r = BIT(color, 0) * 0xff; + int g = BIT(color, 1) * 0xff; + int b = BIT(color, 2) * 0xff; + + rgb_t rgb = rgb_t(r, g, b); + + bitmap.pix32(y, x++) = rgb; + bitmap.pix32(y, x++) = rgb; + } + } + } + + return 0; +} diff --git a/src/devices/video/saa5050.h b/src/devices/video/saa5050.h new file mode 100644 index 00000000000..0155da83e4e --- /dev/null +++ b/src/devices/video/saa5050.h @@ -0,0 +1,257 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Mullard SAA5050 Teletext Character Generator emulation + +********************************************************************** + _____ _____ + Vss 1 |* \_/ | 28 DE + _SI 2 | | 27 PO + _DATA 3 | | 26 LOSE + D1 4 | SAA5050 | 25 BLAN + D2 5 | SAA5051 | 24 R + D3 6 | SAA5052 | 23 G + D4 7 | SAA5053 | 22 B + D5 8 | SAA5054 | 21 Y + D6 9 | SAA5055 | 20 F1 + D7 10 | SAA5056 | 19 TR6 + DLIM 11 | SAA5057 | 18 Vdd + _GLR 12 | | 17 N/C + DEW 13 | | 16 _TLC + CRS 14 |_____________| 15 _BCS + +**********************************************************************/ + +#pragma once + +#ifndef __SAA5050__ +#define __SAA5050__ + +#include "emu.h" + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_SAA5050_D_CALLBACK(_read) \ + devcb = &saa5050_device::set_d_rd_callback(*device, DEVCB_##_read); + + +#define MCFG_SAA5050_SCREEN_SIZE(_cols, _rows, _size) \ + saa5050_device::static_set_screen_size(*device, _cols, _rows, _size); + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> saa5050_device + +class saa5050_device : public device_t +{ +public: + // construction/destruction + saa5050_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + saa5050_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + static void static_set_screen_size(device_t &device, int cols, int rows, int size) { downcast(device).m_cols = cols; downcast(device).m_rows = rows; downcast(device).m_size = size; } + + template static devcb_base &set_d_rd_callback(device_t &device, _Object object) { return downcast(device).m_read_d.set_callback(object); } + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + + DECLARE_WRITE_LINE_MEMBER( dew_w ); + DECLARE_WRITE_LINE_MEMBER( lose_w ); + void write(UINT8 data); + DECLARE_WRITE_LINE_MEMBER( f1_w ); + DECLARE_WRITE_LINE_MEMBER( tr6_w ); + int get_rgb(); + + // NOTE: the following are provided for convenience only, SAA5050 is not a display controller + // this emulates the common setup where bit 7 of data inverts the display, and the + // bottom half of a double height row gets the same character data as the top half + UINT32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + +private: + enum + { + NUL = 0, + ALPHA_RED, + ALPHA_GREEN, + ALPHA_YELLOW, + ALPHA_BLUE, + ALPHA_MAGENTA, + ALPHA_CYAN, + ALPHA_WHITE, + FLASH, + STEADY, + END_BOX, + START_BOX, + NORMAL_HEIGHT, + DOUBLE_HEIGHT, + S0, + S1, + DLE, + GRAPHICS_RED, + GRAPHICS_GREEN, + GRAPHICS_YELLOW, + GRAPHICS_BLUE, + GRAPHICS_MAGENTA, + GRAPHICS_CYAN, + GRAPHICS_WHITE, + CONCEAL_DISPLAY, + CONTIGUOUS_GFX, + SEPARATED_GFX, + ESC, + BLACK_BACKGROUND, + NEW_BACKGROUND, + HOLD_GRAPHICS, + RELEASE_GRAPHICS + }; + + void process_control_character(UINT8 data); + void get_character_data(UINT8 data); + + required_region_ptr m_char_rom; + + devcb_read8 m_read_d; + + UINT8 m_code; + UINT8 m_last_code; + UINT8 m_char_data; + int m_bit; + rgb_t m_color; + int m_ra; + int m_bg; + int m_fg; + bool m_graphics; + bool m_separated; + bool m_conceal; + bool m_flash; + bool m_boxed; + int m_double_height; + bool m_double_height_top_row; + bool m_double_height_bottom_row; + bool m_hold; + int m_frame_count; + + int m_cols; + int m_rows; + int m_size; +}; + + +// ======================> saa5051_device + +class saa5051_device : public saa5050_device +{ +public: + // construction/destruction + saa5051_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; +}; + + +// ======================> saa5052_device + +class saa5052_device : public saa5050_device +{ +public: + // construction/destruction + saa5052_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; +}; + + +// ======================> saa5053_device + +class saa5053_device : public saa5050_device +{ +public: + // construction/destruction + saa5053_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; +}; + + +// ======================> saa5054_device + +class saa5054_device : public saa5050_device +{ +public: + // construction/destruction + saa5054_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; +}; + + +// ======================> saa5055_device + +class saa5055_device : public saa5050_device +{ +public: + // construction/destruction + saa5055_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; +}; + + +// ======================> saa5056_device + +class saa5056_device : public saa5050_device +{ +public: + // construction/destruction + saa5056_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; +}; + + +// ======================> saa5057_device + +class saa5057_device : public saa5050_device +{ +public: + // construction/destruction + saa5057_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; +}; + + +// device type definition +extern const device_type SAA5050; // English +extern const device_type SAA5051; // German +extern const device_type SAA5052; // Swedish/Finnish +extern const device_type SAA5053; // Italian +extern const device_type SAA5054; // Belgian +extern const device_type SAA5055; // U.S. ASCII +extern const device_type SAA5056; // Hebrew +extern const device_type SAA5057; // Cyrillic + + + +#endif diff --git a/src/devices/video/scn2674.c b/src/devices/video/scn2674.c new file mode 100644 index 00000000000..e1998367762 --- /dev/null +++ b/src/devices/video/scn2674.c @@ -0,0 +1,766 @@ +// license:BSD-3-Clause +// copyright-holders:Carl +/* + SCN2674 - Advanced Video Display Controller (AVDC) (Video Chip) +*/ + +#include "scn2674.h" + +#define S674VERBOSE 0 +#define LOG2674(x) do { if (S674VERBOSE) logerror x; } while (0) + +const device_type SCN2674_VIDEO = &device_creator; + + +// default address map +static ADDRESS_MAP_START( scn2674_vram, AS_0, 8, scn2674_device ) + AM_RANGE(0x0000, 0xffff) AM_NOP +ADDRESS_MAP_END + +scn2674_device::scn2674_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, SCN2674_VIDEO, "Signetics SCN2674 AVDC", tag, owner, clock, "scn2674_device", __FILE__), + device_video_interface(mconfig, *this), + device_memory_interface(mconfig, *this), + m_irq_cb(*this), + m_space_config("videoram", ENDIANNESS_LITTLE, 8, 16, 0, NULL, *ADDRESS_MAP_NAME(scn2674_vram)) +{ +} + +void scn2674_device::device_start() +{ + // resolve callbacks + m_display_cb.bind_relative_to(*owner()); + m_irq_cb.resolve_safe(); + m_scanline_timer = timer_alloc(TIMER_SCANLINE); + m_screen->register_screen_bitmap(m_bitmap); + + save_item(NAME(m_address)); + save_item(NAME(m_linecounter)); + save_item(NAME(m_screen2_l)); + save_item(NAME(m_screen2_h)); + save_item(NAME(m_cursor_l)); + save_item(NAME(m_cursor_h)); +} + +void scn2674_device::device_reset() +{ + m_IR_pointer= 0; + m_screen1_l= 0; + m_screen1_h= 0; + m_cursor_l= 0; + m_cursor_h= 0; + m_screen2_l= 0; + m_screen2_h= 0; + m_irq_register= 0; + m_status_register= 0; + m_irq_mask= 0; + m_gfx_enabled= 0; + m_display_enabled= 0; + m_display_enabled_field= 0; + m_display_enabled_scanline= 0; + m_cursor_enabled= 0; + m_IR0_double_ht_wd= 0; + m_IR0_scanline_per_char_row= 0; + m_IR0_sync_select= 0; + m_IR0_buffer_mode_select= 0; + m_IR1_interlace_enable= 0; + m_IR1_equalizing_constant= 0; + m_IR2_row_table= 0; + m_IR2_horz_sync_width= 0; + m_IR2_horz_back_porch= 0; + m_IR3_vert_front_porch= 0; + m_IR3_vert_back_porch= 0; + m_IR4_rows_per_screen= 0; + m_IR4_character_blink_rate_divisor= 0; + m_IR5_character_per_row= 0; + m_IR6_cursor_first_scanline= 0; + m_IR6_cursor_last_scanline= 0; + m_IR7_cursor_underline_position= 0; + m_IR7_cursor_rate_divisor= 0; + m_IR7_cursor_blink= 0; + m_IR7_vsync_width= 0; + m_IR8_display_buffer_first_address_LSB= 0; + m_IR9_display_buffer_first_address_MSB= 0; + m_IR9_display_buffer_last_address= 0; + m_IR10_display_pointer_address_lower= 0; + m_IR11_display_pointer_address_upper= 0; + m_IR11_reset_scanline_counter_on_scrollup= 0; + m_IR11_reset_scanline_counter_on_scrolldown= 0; + m_IR12_scroll_start= 0; + m_IR12_split_register_1= 0; + m_IR13_scroll_end= 0; + m_IR13_split_register_2= 0; + m_IR14_scroll_lines= 0; + m_IR14_double_1= 0; + m_IR14_double_2= 0; + m_spl1= 0; + m_spl2= 0; + m_dbl1= 0; + m_buffer= 0; + m_linecounter= 0; + m_irq_state= 0; + m_IR_pointer = 0; + m_address = 0; + m_start1change = 0; + m_hpixels_per_column = m_text_hpixels_per_column; +} + +// 15 Initialization Registers (8-bit each) +void scn2674_device::write_init_regs(UINT8 data) +{ + LOG2674(("scn2674_write_init_regs %02x %02x\n",m_IR_pointer,data)); + + switch ( m_IR_pointer) /* display some debug info, set mame specific variables */ + { + case 0: + m_IR0_double_ht_wd = (data & 0x80)>>7; + m_IR0_scanline_per_char_row = ((data & 0x78)>>3) + 1; + m_IR0_sync_select = (data&0x04)>>2; + m_IR0_buffer_mode_select = (data&0x03); + + LOG2674(("IR0 - Double Ht Wd %02x\n",m_IR0_double_ht_wd));//affects IR14 as well + LOG2674(("IR0 - Scanlines per Character Row %02x\n",m_IR0_scanline_per_char_row));//value+1 = scanlines + LOG2674(("IR0 - Sync Select %02x\n",m_IR0_sync_select));//1 = csync + LOG2674(("IR0 - Buffer Mode Select %02x\n",m_IR0_buffer_mode_select)); //0 independent 1 transparent 2 shared 3 row + break; + + case 1: + m_IR1_interlace_enable = (data&0x80)>>7; + m_IR1_equalizing_constant = (data&0x7f)+1; + + LOG2674(("IR1 - Interlace Enable %02x\n",m_IR1_interlace_enable)); + LOG2674(("IR1 - Equalizing Constant %02i CCLKs\n",m_IR1_equalizing_constant)); + break; + + case 2: + m_IR2_row_table = (data&0x80)>>7; + m_IR2_horz_sync_width = (((data&0x78)>>3)*2) + 2; + m_IR2_horz_back_porch = ((data&0x07)*4) - 1; + + LOG2674(("IR2 - Row Table %02x\n",m_IR2_row_table)); + LOG2674(("IR2 - Horizontal Sync Width %02i CCLKs\n",m_IR2_horz_sync_width)); + LOG2674(("IR2 - Horizontal Back Porch %02i CCLKs\n",m_IR2_horz_back_porch)); + break; + + case 3: + m_IR3_vert_front_porch = (((data&0xe0)>>5) * 4)+4 ; + m_IR3_vert_back_porch = ((data&0x1f) * 2) + 4; + + LOG2674(("IR3 - Vertical Front Porch %02i Lines\n",m_IR3_vert_front_porch)); + LOG2674(("IR3 - Vertical Back Porch %02i Lines\n",m_IR3_vert_back_porch)); + break; + + case 4: + m_IR4_rows_per_screen = (data&0x7f) + 1; + m_IR4_character_blink_rate_divisor = ((data & 0x80)>>7 ? 128:64); + + LOG2674(("IR4 - Rows Per Screen %02i\n",m_IR4_rows_per_screen)); + LOG2674(("IR4 - Character Blink Rate = 1/%02i\n",m_IR4_character_blink_rate_divisor)); + break; + + case 5: + /* IR5 - Active Characters Per Row + cccc cccc + c = Characters Per Row */ + m_IR5_character_per_row = data + 1; + LOG2674(("IR5 - Active Characters Per Row %02i\n",m_IR5_character_per_row)); + break; + + case 6: + m_IR6_cursor_last_scanline = (data & 0x0f); + m_IR6_cursor_first_scanline = (data & 0xf0)>>4; + LOG2674(("IR6 - First Line of Cursor %02x\n",m_IR6_cursor_first_scanline)); + LOG2674(("IR6 - Last Line of Cursor %02x\n",m_IR6_cursor_last_scanline)); + break; + + case 7: + { + const UINT8 vsync_table[4] = {3,1,5,7}; + m_IR7_cursor_underline_position = (data & 0x0f); + m_IR7_cursor_rate_divisor = ((data & 0x10)>>4 ? 64:32); + m_IR7_cursor_blink = (data & 0x20)>>5; + + m_IR7_vsync_width = vsync_table[(data & 0xC0)>>6]; + + LOG2674(("IR7 - Underline Position %02x\n",m_IR7_cursor_underline_position)); + LOG2674(("IR7 - Cursor rate 1/%02i\n",m_IR7_cursor_rate_divisor)); + LOG2674(("IR7 - Cursor blink %02x\n",m_IR7_cursor_blink)); + LOG2674(("IR7 - Vsync Width %02i Lines\n",m_IR7_vsync_width)); + break; + } + + case 8: + m_IR8_display_buffer_first_address_LSB = data; + LOG2674(("IR8 - Display Buffer First Address LSB %02x\n",m_IR8_display_buffer_first_address_LSB)); + break; + + case 9: + m_IR9_display_buffer_first_address_MSB = data & 0x0f; + m_IR9_display_buffer_last_address = (data & 0xf0)>>4; + LOG2674(("IR9 - Display Buffer First Address MSB %02x\n",m_IR9_display_buffer_first_address_MSB)); + LOG2674(("IR9 - Display Buffer Last Address %02x\n",m_IR9_display_buffer_last_address)); + break; + + case 10: + m_IR10_display_pointer_address_lower = data; + LOG2674(("IR10 - Display Pointer Address Lower %02x\n",m_IR10_display_pointer_address_lower)); + break; + + case 11: + m_IR11_display_pointer_address_upper= data&0x3f; + m_IR11_reset_scanline_counter_on_scrollup= (data&0x40 >> 6); + m_IR11_reset_scanline_counter_on_scrolldown= (data&0x80 >> 7); + + LOG2674(("IR11 - Display Pointer Address Lower %02x\n",m_IR11_display_pointer_address_upper)); + LOG2674(("IR11 - Reset Scanline Counter on Scroll Up %02x\n",m_IR11_reset_scanline_counter_on_scrollup)); + LOG2674(("IR11 - Reset Scanline Counter on Scroll Down %02x\n",m_IR11_reset_scanline_counter_on_scrolldown)); + break; + + case 12: + m_IR12_scroll_start = (data & 0x80)>>7; + m_IR12_split_register_1 = (data & 0x7f); + LOG2674(("IR12 - Scroll Start %02x\n",m_IR12_scroll_start)); + LOG2674(("IR12 - Split Register 1 %02x\n",m_IR12_split_register_1)); + break; + + case 13: + m_IR13_scroll_end = (data & 0x80)>>7; + m_IR13_split_register_2 = (data & 0x7f); + LOG2674(("IR13 - Scroll End %02x\n",m_IR13_scroll_end)); + LOG2674(("IR13 - Split Register 2 %02x\n",m_IR13_split_register_2)); + break; + + case 14: + m_IR14_scroll_lines = (data & 0x0f); + if (!m_IR0_double_ht_wd) + { + m_IR14_double_2 = (data & 0x30)>>4; + LOG2674(("IR14 - Double 2 %02x\n",m_IR14_double_2)); + } + //0 normal, 1, double width, 2, double width and double tops 3, double width and double bottoms + //1 affects SSR1, 2 affects SSR2 + //If Double Height enabled in IR0, Screen start 1 upper (bits 7 and 6)replace Double 1, and Double 2 is unused + m_IR14_double_1 = (data & 0xc0)>>6; + LOG2674(("IR14 - Double 1 %02x\n",m_IR14_double_1)); + + LOG2674(("IR14 - Scroll Lines %02i\n",m_IR14_scroll_lines)); + break; + + case 15: /* not valid! */ + break; + + } + recompute_parameters(); + + m_IR_pointer++; + if (m_IR_pointer>14)m_IR_pointer=14; +} + +void scn2674_device::write_command(UINT8 data) +{ + UINT8 operand; + int i; + + + if (data==0x00) + { + /* master reset, configures registers */ + LOG2674(("master reset\n")); + m_IR_pointer=0; + m_irq_register = 0x00; + m_status_register = 0x20;//RDFLG activated + m_linecounter =0; + m_irq_mask = 0x00; + m_gfx_enabled = 0; + m_display_enabled = 0; + m_cursor_enabled = 0; + m_IR2_row_table = 0; + } + + if ((data&0xf0)==0x10) + { + /* set IR pointer */ + operand = data & 0x0f; + LOG2674(("set IR pointer %02x\n",operand)); + + m_IR_pointer=operand; + + } + + /* ANY COMBINATION OF THESE ARE POSSIBLE */ + + if ((data&0xe3)==0x22) + { + /* Disable GFX */ + LOG2674(("disable GFX %02x\n",data)); + m_gfx_enabled = 0; + recompute_parameters(); + } + + if ((data&0xe3)==0x23) + { + /* Enable GFX */ + LOG2674(("enable GFX %02x\n",data)); + m_gfx_enabled = 1; + recompute_parameters(); + } + + if ((data&0xe9)==0x28) + { + /* Display off */ + operand = data & 0x04; + + m_display_enabled = 0; + + if (operand) + LOG2674(("display OFF - float DADD bus %02x\n",data)); + else + LOG2674(("display OFF - no float DADD bus %02x\n",data)); + } + + if ((data&0xe9)==0x29) + { + /* Display on */ + operand = data & 0x04; + + if (operand) + { + m_display_enabled_field = 1; + LOG2674(("display ON - next field %02x\n",data)); + } + else + { + m_display_enabled_scanline = 1; + LOG2674(("display ON - next scanline %02x\n",data)); + } + recompute_parameters(); // start the scanline timer + } + + if ((data&0xf1)==0x30) + { + /* Cursor Off */ + LOG2674(("cursor off %02x\n",data)); + m_cursor_enabled = 0; + } + + if ((data&0xf1)==0x31) + { + /* Cursor On */ + LOG2674(("cursor on %02x\n",data)); + m_cursor_enabled = 1; + } + + /* END */ + + if ((data&0xe0)==0x40) + { + /* Reset Interrupt / Status bit */ + operand = data & 0x1f; + LOG2674(("reset interrupt / status bit %02x\n",operand)); + + m_irq_register &= ~(data & 0x1f); + m_status_register &= ~(data & 0x1f); + + LOG2674(("IRQ Status after reset\n")); + LOG2674(("Split 2 IRQ: %d Active\n",(m_irq_register>>0)&1)); + LOG2674(("Ready IRQ: %d Active\n",(m_irq_register>>1)&1)); + LOG2674(("Split 1 IRQ: %d Active\n",(m_irq_register>>2)&1)); + LOG2674(("Line Zero IRQ: %d Active\n",(m_irq_register>>3)&1)); + LOG2674(("V-Blank IRQ: %d Active\n",(m_irq_register>>4)&1)); + + m_irq_state = 0; + + for (i = 0; i < 5; i++) + { + if ((m_irq_register>>i&1)&(m_irq_mask>>i&1)) + { + m_irq_state = 1; + } + } + m_irq_cb(m_irq_register ? 1 : 0); + + } + if ((data&0xe0)==0x80) + { + /* Disable Interrupt mask*/ + operand = data & 0x1f; + m_irq_mask &= ~(operand); + LOG2674(("IRQ Mask after disable %x\n",operand)); + LOG2674(("Split 2 IRQ: %d Unmasked\n",(m_irq_mask>>0)&1)); + LOG2674(("Ready IRQ: %d Unmasked\n",(m_irq_mask>>1)&1)); + LOG2674(("Split 1 IRQ: %d Unmasked\n",(m_irq_mask>>2)&1)); + LOG2674(("Line Zero IRQ: %d Unmasked\n",(m_irq_mask>>3)&1)); + LOG2674(("V-Blank IRQ: %d Unmasked\n",(m_irq_mask>>4)&1)); + + } + + if ((data&0xe0)==0x60) + { + /* Enable Interrupt mask*/ + operand = data & 0x1f; + m_irq_mask |= (data & 0x1f); + + LOG2674(("IRQ Mask after enable %x\n",operand)); + LOG2674(("Split 2 IRQ: %d Unmasked\n",(m_irq_mask>>0)&1)); + LOG2674(("Ready IRQ: %d Unmasked\n",(m_irq_mask>>1)&1)); + LOG2674(("Split 1 IRQ: %d Unmasked\n",(m_irq_mask>>2)&1)); + LOG2674(("Line Zero IRQ: %d Unmasked\n",(m_irq_mask>>3)&1)); + LOG2674(("V-Blank IRQ: %d Unmasked\n",(m_irq_mask>>4)&1)); + + } + + /* Delayed Commands */ + /* These set 0x20 in status register when done */ + // These use the pointer address according to the datasheet but the pcx expects the screen start 2 address instead + switch(data) + { + case 0xa4: + /* read at pointer address */ + m_buffer = space().read_byte(m_screen2_l | (m_screen2_h << 8)); + LOG2674(("DELAYED read at pointer address %02x\n",data)); + break; + + case 0xa2: + /* write at pointer address */ + space().write_byte(m_screen2_l | (m_screen2_h << 8), m_buffer); + LOG2674(("DELAYED write at pointer address %02x\n",data)); + break; + + case 0xa9: + /* increment cursor address */ + if(!(++m_cursor_l)) + m_cursor_h++; + LOG2674(("DELAYED increase cursor address %02x\n",data)); + break; + + case 0xac: + /* read at cursor address */ + m_buffer = space().read_byte(m_cursor_l | (m_cursor_h << 8)); + LOG2674(("DELAYED read at cursor address %02x\n",data)); + break; + + case 0xaa: + /* write at cursor address */ + space().write_byte(m_cursor_l | (m_cursor_h << 8), m_buffer); + LOG2674(("DELAYED write at cursor address %02x\n",data)); + break; + + case 0xad: + /* read at cursor address + increment */ + m_buffer = space().read_byte(m_cursor_l | (m_cursor_h << 8)); + if(!(++m_cursor_l)) + m_cursor_h++; + LOG2674(("DELAYED read at cursor address+increment %02x\n",data)); + break; + + case 0xab: + /* write at cursor address + increment */ + space().write_byte(m_cursor_l | (m_cursor_h << 8), m_buffer); + if(!(++m_cursor_l)) + m_cursor_h++; + LOG2674(("DELAYED write at cursor address+increment %02x\n",data)); + break; + + case 0xbb: + /* write from cursor address to pointer address TODO: transfer only during blank*/ + for(i = m_cursor_l | (m_cursor_h << 8); i != (m_screen2_l | (m_screen2_h << 8)); i = ((i + 1) & 0xffff)) + space().write_byte(i, m_buffer); + space().write_byte(i, m_buffer); // get the last + m_cursor_l = m_screen2_l; + m_cursor_h = m_screen2_h; + LOG2674(("DELAYED write from cursor address to pointer address %02x\n",data)); + break; + + case 0xbd: + /* read from cursor address to pointer address */ + LOG2674(("DELAYED read from cursor address to pointer address %02x\n",data)); + break; + } +} + + +READ8_MEMBER( scn2674_device::read ) +{ + /* + Offset: Purpose + 0 Interrupt Register + 1 Status Register + 2 Screen Start 1 Lower Register + 3 Screen Start 1 Upper Register + 4 Cursor Address Lower Register + 5 Cursor Address Upper Register + 6 Screen Start 2 Lower Register + 7 Screen Start 2 Upper Register + */ + + switch (offset) + { + /* Status / Irq Register + + --RV ZSRs + + 6+7 -- = ALWAYS 0 + 5 R = RDFLG (Status Register Only) + 4 V = Vblank + 3 Z = Line Zero + 2 S = Split 1 + 1 R = Ready + 0 s = Split 2 + */ + + case 0: + LOG2674(("Read Irq Register %02x %06x\n",m_irq_register,space.device().safe_pc())); + return m_irq_register; + + case 1: + LOG2674(("Read Status Register %02X %06x\n",m_status_register,space.device().safe_pc())); + return m_status_register; + + case 2: LOG2674(("Read Screen1_l Register %06x\n",space.device().safe_pc()));return m_screen1_l; + case 3: LOG2674(("Read Screen1_h Register %06x\n",space.device().safe_pc()));return m_screen1_h & 0x3f; + case 4: LOG2674(("Read Cursor_l Register %06x\n",space.device().safe_pc()));return m_cursor_l; + case 5: LOG2674(("Read Cursor_h Register %06x\n",space.device().safe_pc()));return m_cursor_h; + case 6: LOG2674(("Read Screen2_l Register %06x\n",space.device().safe_pc()));return m_screen2_l; + case 7: LOG2674(("Read Screen2_h Register %06x\n",space.device().safe_pc()));return m_screen2_h; + } + + return 0xff; +} + + +WRITE8_MEMBER( scn2674_device::write ) +{ + /* + Offset: Purpose + 0 Initialization Registers + 1 Command Register + 2 Screen Start 1 Lower Register + 3 Screen Start 1 Upper Register + 4 Cursor Address Lower Register + 5 Cursor Address Upper Register + 6 Screen Start 2 Lower Register + 7 Screen Start 2 Upper Register + */ + + switch (offset) + { + case 0: + write_init_regs(data); + break; + + case 1: + write_command(data); + break; + + case 2: + m_screen1_l = data; + if(!m_screen->vblank()) + m_start1change = (m_linecounter / m_IR0_scanline_per_char_row) + 1; + break; + case 3: + m_screen1_h = data; + m_dbl1=(data & 0xc0)>>6; + if (m_IR0_double_ht_wd) + { + m_IR14_double_1 = m_dbl1; + m_screen1_h &= 0x3f; + LOG2674(("IR14 - Double 1 overridden %02x\n",m_IR14_double_1)); + } + if(!m_screen->vblank()) + m_start1change = (m_linecounter / m_IR0_scanline_per_char_row) + 1; + break; + + case 4: m_cursor_l = data; break; + case 5: m_cursor_h = (data & 0x3f); break; + case 6: m_screen2_l = data; break; + case 7: + m_screen2_h = (data&0x3f); + m_spl1 = (data & 0x40); + m_spl2 = (data & 0x80); + break; + } +} + +void scn2674_device::recompute_parameters() +{ + m_hpixels_per_column = m_gfx_enabled ? m_gfx_hpixels_per_column : m_text_hpixels_per_column; + int horiz_pix_total = ((m_IR1_equalizing_constant + (m_IR2_horz_sync_width << 1)) << 1) * m_hpixels_per_column; + int vert_pix_total = m_IR4_rows_per_screen * m_IR0_scanline_per_char_row + m_IR3_vert_front_porch + m_IR3_vert_back_porch + m_IR7_vsync_width; + attoseconds_t refresh = m_screen->frame_period().attoseconds(); + int max_visible_x = (m_IR5_character_per_row * m_hpixels_per_column) - 1; + int max_visible_y = (m_IR4_rows_per_screen * m_IR0_scanline_per_char_row) - 1; + + if(!horiz_pix_total || !vert_pix_total) + { + m_scanline_timer->adjust(attotime::never); + return; + } + + LOG2674(("width %u height %u max_x %u max_y %u refresh %f\n", horiz_pix_total, vert_pix_total, max_visible_x, max_visible_y, 1 / ATTOSECONDS_TO_DOUBLE(refresh))); + + rectangle visarea; + visarea.set(0, max_visible_x, 0, max_visible_y); + m_screen->configure(horiz_pix_total, vert_pix_total, visarea, refresh); + + m_scanline_timer->adjust(m_screen->time_until_pos(0, 0), 0, m_screen->scan_period()); +} + +void scn2674_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch(id) + { + case TIMER_SCANLINE: + { + int dw = m_IR0_double_ht_wd ? m_IR14_double_1 : 0; // double width + if(((m_display_enabled_scanline) || (m_display_enabled_field && !m_IR1_interlace_enable)) && (!m_display_enabled)) + { + m_display_enabled = 1; + m_display_enabled_scanline = 0; + m_display_enabled_field = 0; + } + else + m_linecounter++; + + if(m_linecounter >= m_screen->height()) + { + m_linecounter = 0; + m_address = (m_screen1_h << 8) | m_screen1_l; + } + + if(m_linecounter == (m_IR4_rows_per_screen * m_IR0_scanline_per_char_row)) + { + m_status_register |= 0x10; + if(m_irq_mask & 0x10) + { + LOG2674(("vblank irq\n")); + m_irq_state = 1; + m_irq_register |= 0x10; + m_irq_cb(1); + } + } + + if(m_linecounter >= (m_IR4_rows_per_screen * m_IR0_scanline_per_char_row)) + break; + + int charrow = m_linecounter % m_IR0_scanline_per_char_row; + int tilerow = charrow; + + // should be triggered at the start of each ROW (line zero for that row) + if(!charrow) + { + m_status_register |= 0x08; + if (m_irq_mask & 0x08) + { + LOG2674(("SCN2674 Line Zero\n")); + m_irq_state = 1; + m_irq_register |= 0x08; + m_irq_cb(1); + } + } + + if((m_linecounter == (m_IR12_split_register_1 * m_IR0_scanline_per_char_row)) && m_linecounter) /* Split Screen 1 */ + { + m_status_register |= 0x04; + if(m_irq_mask & 0x04) + { + LOG2674(("SCN2674 Split Screen 1 irq\n")); + m_irq_state = 1; + m_irq_register |= 0x04; + m_irq_cb(1); + } + if(m_spl1) + m_address = (m_screen2_h << 8) | m_screen2_l; + if(!m_IR0_double_ht_wd) + dw = m_IR14_double_1; + } + + if((m_linecounter == (m_IR13_split_register_2 * m_IR0_scanline_per_char_row)) && m_linecounter) /* Split Screen 2 */ + { + m_status_register |= 0x01; + if(m_irq_mask & 0x01) + { + LOG2674(("SCN2674 Split Screen 2 irq\n")); + m_irq_state = 1; + m_irq_register |= 0x01; + m_irq_cb(1); + } + if(m_spl2) + m_address = (m_screen2_h << 8) | m_screen2_l; + if(!m_IR0_double_ht_wd) + dw = m_IR14_double_2; + } + + if(!m_display_enabled) + break; + + if(m_IR2_row_table) + { + if(m_IR0_double_ht_wd) + dw = m_screen1_h >> 6; + if(!charrow) + { + UINT16 addr = (m_screen2_h << 8) | m_screen2_l; + UINT16 line = space().read_word(addr); + m_screen1_h = (line >> 8); + m_screen1_l = line & 0xff; + if(m_IR0_double_ht_wd) + { + dw = line >> 14; + line &= ~0xc000; + } + m_address = line; + addr += 2; + m_screen2_h = (addr >> 8) & 0x3f; + m_screen2_l = addr & 0xff; + } + } + else if(m_start1change && (m_start1change == (m_linecounter / m_IR0_scanline_per_char_row))) + { + m_address = (m_screen1_h << 8) | m_screen1_l; + m_start1change = 0; + } + + if(dw == 2) + tilerow >>= 1; + else if(dw == 3) + tilerow = (charrow + m_IR0_scanline_per_char_row) >> 1; + + UINT16 address = m_address; + + for(int i = 0; i < m_IR5_character_per_row; i++) + { + bool cursor_on = ((address & 0x3fff) == ((m_cursor_h << 8) | m_cursor_l)); + + if (!m_display_cb.isnull()) + m_display_cb(m_bitmap, + i * m_hpixels_per_column, + m_linecounter, + tilerow, + space().read_byte(address), + address, + (charrow >= m_IR6_cursor_first_scanline) && (charrow <= m_IR6_cursor_last_scanline) && cursor_on, + dw != 0, + m_gfx_enabled != 0, + charrow == m_IR7_cursor_underline_position, + m_IR7_cursor_blink && (m_screen->frame_number() & (m_IR7_cursor_rate_divisor ? 0x40 : 0x20))); + address = (address + 1) & 0xffff; + + if(address > ((m_IR9_display_buffer_last_address << 10) | 0x3ff)) + address = (m_IR9_display_buffer_first_address_MSB << 8) | m_IR8_display_buffer_first_address_LSB; + } + + if(m_gfx_enabled || (charrow == (m_IR0_scanline_per_char_row - 1))) + m_address = address; + } + } +} + +UINT32 scn2674_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + if (!m_display_enabled) + m_bitmap.fill(rgb_t::black); + else + copybitmap(bitmap, m_bitmap, 0, 0, 0, 0, cliprect); + + return 0; +} diff --git a/src/devices/video/scn2674.h b/src/devices/video/scn2674.h new file mode 100644 index 00000000000..b30c65c4039 --- /dev/null +++ b/src/devices/video/scn2674.h @@ -0,0 +1,133 @@ +// license:BSD-3-Clause +// copyright-holders:Carl +#ifndef SCN2674_H +#define SCN2674_H + +#include "emu.h" + +#define MCFG_SCN2674_VIDEO_ADD(_tag, _clock, _irq) \ + MCFG_DEVICE_ADD(_tag, SCN2674_VIDEO, _clock) \ + devcb = &scn2674_device::set_irq_callback(*device, DEVCB_##_irq); + +#define MCFG_SCN2674_TEXT_CHARACTER_WIDTH(_value) \ + scn2674_device::static_set_character_width(*device, _value); + +#define MCFG_SCN2674_GFX_CHARACTER_WIDTH(_value) \ + scn2674_device::static_set_gfx_character_width(*device, _value); + +#define MCFG_SCN2674_DRAW_CHARACTER_CALLBACK_OWNER(_class, _method) \ + scn2674_device::static_set_display_callback(*device, scn2674_device::draw_character_delegate(&_class::_method, #_class "::" #_method, downcast<_class *>(owner))); + +#define SCN2674_DRAW_CHARACTER_MEMBER(_name) void _name(bitmap_rgb32 &bitmap, int x, int y, UINT8 linecount, UINT8 charcode, UINT16 address, UINT8 cursor, UINT8 dw, UINT8 lg, UINT8 ul, UINT8 blink) + +class scn2674_device : public device_t, + public device_video_interface, + public device_memory_interface +{ +public: + scn2674_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + typedef device_delegate draw_character_delegate; + + // static configuration + template static devcb_base &set_irq_callback(device_t &device, _Object object) { return downcast(device).m_irq_cb.set_callback(object); } + static void static_set_character_width(device_t &device, int value) { downcast(device).m_text_hpixels_per_column = value; } + static void static_set_gfx_character_width(device_t &device, int value) { downcast(device).m_gfx_hpixels_per_column = value; } + static void static_set_display_callback(device_t &device, draw_character_delegate callback) { downcast(device).m_display_cb = callback; } + + DECLARE_READ8_MEMBER( read ); + DECLARE_WRITE8_MEMBER( write ); + DECLARE_READ8_MEMBER( buffer_r ) { return m_buffer; } + DECLARE_WRITE8_MEMBER( buffer_w ) { m_buffer = data; } + + UINT32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const { return (spacenum == AS_0) ? &m_space_config : NULL; } + +protected: + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + +private: + bitmap_rgb32 m_bitmap; + devcb_write_line m_irq_cb; + + UINT8 m_IR_pointer; + UINT8 m_screen1_l; + UINT8 m_screen1_h; + UINT8 m_cursor_l; + UINT8 m_cursor_h; + UINT8 m_screen2_l; + UINT8 m_screen2_h; + UINT8 m_irq_register; + UINT8 m_status_register; + UINT8 m_irq_mask; + UINT8 m_gfx_enabled; + UINT8 m_display_enabled; + UINT8 m_display_enabled_field; + UINT8 m_display_enabled_scanline; + UINT8 m_cursor_enabled; + UINT8 m_hpixels_per_column; + UINT8 m_text_hpixels_per_column; + UINT8 m_gfx_hpixels_per_column; + UINT8 m_IR0_double_ht_wd; + UINT8 m_IR0_scanline_per_char_row; + UINT8 m_IR0_sync_select; + UINT8 m_IR0_buffer_mode_select; + UINT8 m_IR1_interlace_enable; + UINT8 m_IR1_equalizing_constant; + UINT8 m_IR2_row_table; + UINT8 m_IR2_horz_sync_width; + UINT8 m_IR2_horz_back_porch; + UINT8 m_IR3_vert_front_porch; + UINT8 m_IR3_vert_back_porch; + UINT8 m_IR4_rows_per_screen; + UINT8 m_IR4_character_blink_rate_divisor; + UINT8 m_IR5_character_per_row; + UINT8 m_IR6_cursor_first_scanline; + UINT8 m_IR6_cursor_last_scanline; + UINT8 m_IR7_cursor_underline_position; + UINT8 m_IR7_cursor_rate_divisor; + UINT8 m_IR7_cursor_blink; + UINT8 m_IR7_vsync_width; + UINT8 m_IR8_display_buffer_first_address_LSB; + UINT8 m_IR9_display_buffer_first_address_MSB; + UINT8 m_IR9_display_buffer_last_address; + UINT8 m_IR10_display_pointer_address_lower; + UINT8 m_IR11_display_pointer_address_upper; + UINT8 m_IR11_reset_scanline_counter_on_scrollup; + UINT8 m_IR11_reset_scanline_counter_on_scrolldown; + UINT8 m_IR12_scroll_start; + UINT8 m_IR12_split_register_1; + UINT8 m_IR13_scroll_end; + UINT8 m_IR13_split_register_2; + UINT8 m_IR14_scroll_lines; + UINT8 m_IR14_double_1; + UINT8 m_IR14_double_2; + UINT8 m_spl1; + UINT8 m_spl2; + UINT8 m_dbl1; + UINT8 m_buffer; + int m_linecounter; + UINT16 m_address; + int m_start1change; + + UINT8 m_irq_state; + + void write_init_regs(UINT8 data); + void write_command(UINT8 data); + void recompute_parameters(); + + draw_character_delegate m_display_cb; + emu_timer *m_scanline_timer; + const address_space_config m_space_config; + enum + { + TIMER_SCANLINE + }; +}; + + +extern const device_type SCN2674_VIDEO; + +#endif diff --git a/src/devices/video/sed1200.c b/src/devices/video/sed1200.c new file mode 100644 index 00000000000..029ab01c236 --- /dev/null +++ b/src/devices/video/sed1200.c @@ -0,0 +1,192 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +/*************************************************************************** + + SED1200 + + A LCD controller. + + The D/F variants have a packaging difference (QFP80 vs. bare chip). + + The A/B variants have an internal CGROM difference (jis + vs. european characters) + +***************************************************************************/ + +#include "emu.h" +#include "sed1200.h" + +const device_type SED1200D0A = &device_creator; +const device_type SED1200F0A = &device_creator; +const device_type SED1200D0B = &device_creator; +const device_type SED1200F0B = &device_creator; + +ROM_START( sed1200x0a ) + ROM_REGION( 0x800, "cgrom", 0 ) + ROM_LOAD( "sed1200-a.bin", 0x000, 0x800, CRC(e8c28054) SHA1(086406eb74e9ed97b309d2a4bdedc567626e9a98)) +ROM_END + +ROM_START( sed1200x0b ) + ROM_REGION( 0x800, "cgrom", 0 ) + ROM_LOAD( "sed1200-b.bin", 0x000, 0x800, CRC(d0741f51) SHA1(c8c856f1357286a2c8c806af81724a828345357e)) +ROM_END + +sed1200_device::sed1200_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : + device_t(mconfig, type, name, tag, owner, clock, shortname, source) +{ +} + +sed1200d0a_device::sed1200d0a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + sed1200_device(mconfig, SED1200D0A, "sed1200d-0a", tag, owner, clock, "sed1200", __FILE__) +{ +} + +sed1200f0a_device::sed1200f0a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + sed1200_device(mconfig, SED1200F0A, "sed1200f-0a", tag, owner, clock, "sed1200", __FILE__) +{ +} + +sed1200d0b_device::sed1200d0b_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + sed1200_device(mconfig, SED1200D0B, "sed1200d-0b", tag, owner, clock, "sed1200", __FILE__) +{ +} + +sed1200f0b_device::sed1200f0b_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + sed1200_device(mconfig, SED1200F0B, "sed1200f-0b", tag, owner, clock, "sed1200", __FILE__) +{ +} + +const rom_entry *sed1200d0a_device::device_rom_region() const +{ + return ROM_NAME(sed1200x0a); +} + +const rom_entry *sed1200f0a_device::device_rom_region() const +{ + return ROM_NAME(sed1200x0a); +} + +const rom_entry *sed1200d0b_device::device_rom_region() const +{ + return ROM_NAME(sed1200x0b); +} + +const rom_entry *sed1200f0b_device::device_rom_region() const +{ + return ROM_NAME(sed1200x0b); +} + +void sed1200_device::device_start() +{ + memset(cgram, 0, sizeof(cgram)); + memset(ddram, 0, sizeof(ddram)); + if(memregion("cgrom")) + cgrom = memregion("cgrom")->base(); + else + cgrom = NULL; + + soft_reset(); +} + +void sed1200_device::soft_reset() +{ + cursor_direction = false; + cursor_blinking = false; + cursor_full = false; + cursor_on = false; + display_on = false; + cursor_address = 0x00; + cgram_address = 0x00; +} + +void sed1200_device::control_w(UINT8 data) +{ + switch(data) { + case 0x04: case 0x05: + cursor_direction = data & 0x01; + break; + case 0x06: case 0x07: + cursor_step(); + break; + case 0x08: case 0x09: + cursor_full = data & 0x01; + break; + case 0x0a: case 0x0b: + cursor_blinking = data & 0x01; + break; + case 0x0c: case 0x0d: + display_on = data & 0x01; + break; + case 0x0e: case 0x0f: + cursor_on = data & 0x01; + break; + case 0x10: + soft_reset(); + break; + case 0x12: case 0x13: + break; // Number of lines selection + default: + if((data & 0xf0) == 0x20) + cgram_address = (data & 3)*8; + else if((data & 0xe0) == 0x40) { + cgram[cgram_address++] = data; + if(cgram_address == 4*8) + cgram_address = 0; + } else if(data & 0x80) { + cursor_address = data & 0x40 ? 10 : 0; + cursor_address += (data & 0x3f) >= 10 ? 9 : data & 0x3f; + } + break; + } +} + +UINT8 sed1200_device::control_r() +{ + return 0x00; +} + +void sed1200_device::data_w(UINT8 data) +{ + ddram[cursor_address] = data; + cursor_step(); +} + +void sed1200_device::cursor_step() +{ + if(cursor_direction) { + if(cursor_address == 0 || cursor_address == 10) + cursor_address += 9; + else + cursor_address --; + } else { + if(cursor_address == 9 || cursor_address == 19) + cursor_address -= 9; + else + cursor_address ++; + } +} + +const UINT8 *sed1200_device::render() +{ + memset(render_buf, 0, 20*8); + if(!display_on) + return render_buf; + + for(int i=0; i<20; i++) { + UINT8 c = ddram[i]; + if(c < 4) + memcpy(render_buf + 8*i, cgram + 8*c, 8); + else if(cgrom) + memcpy(render_buf + 8*i, cgrom + 8*c, 8); + } + + if(cursor_on && (!cursor_blinking || (machine().time().as_ticks(2) & 1))) { + if(cursor_full) + for(int i=0; i<8; i++) + render_buf[cursor_address*8+i] ^= 0x1f; + else + render_buf[cursor_address*8+7] ^= 0x1f; + } + + return render_buf; +} diff --git a/src/devices/video/sed1200.h b/src/devices/video/sed1200.h new file mode 100644 index 00000000000..7429215c245 --- /dev/null +++ b/src/devices/video/sed1200.h @@ -0,0 +1,92 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +/*************************************************************************** + + SED1200 + + A LCD controller. + + The D/F variants are a packaging difference (QFP80 vs. bare chip). + The A/B variants are an internal CGROM difference (jis + vs. european characters) + +***************************************************************************/ + +#ifndef __SED1200_H__ +#define __SED1200_H__ + +#define MCFG_SED1200D0A_ADD( _tag ) \ + MCFG_DEVICE_ADD( _tag, SED1200D0A, 0 ) + +#define MCFG_SED1200F0A_ADD( _tag ) \ + MCFG_DEVICE_ADD( _tag, SED1200F0A, 0 ) + +#define MCFG_SED1200D0B_ADD( _tag ) \ + MCFG_DEVICE_ADD( _tag, SED1200D0B, 0 ) + +#define MCFG_SED1200F0B_ADD( _tag ) \ + MCFG_DEVICE_ADD( _tag, SED1200F0B, 0 ) + +class sed1200_device : public device_t { +public: + sed1200_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + void control_w(UINT8 data); + UINT8 control_r(); + void data_w(UINT8 data); + + const UINT8 *render(); + +protected: + virtual void device_start(); + +private: + UINT8 cgram[4*8]; + UINT8 ddram[10*2]; + UINT8 render_buf[20*8]; + bool cursor_direction, cursor_blinking, cursor_full, cursor_on, display_on; + UINT8 cursor_address, cgram_address; + const UINT8 *cgrom; + + void soft_reset(); + void cursor_step(); +}; + +class sed1200d0a_device : public sed1200_device { +public: + sed1200d0a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual const rom_entry *device_rom_region() const; +}; + +class sed1200f0a_device : public sed1200_device { +public: + sed1200f0a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual const rom_entry *device_rom_region() const; +}; + +class sed1200d0b_device : public sed1200_device { +public: + sed1200d0b_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual const rom_entry *device_rom_region() const; +}; + +class sed1200f0b_device : public sed1200_device { +public: + sed1200f0b_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + virtual const rom_entry *device_rom_region() const; +}; + +extern const device_type SED1200D0A; +extern const device_type SED1200F0A; +extern const device_type SED1200D0B; +extern const device_type SED1200F0B; + +#endif diff --git a/src/devices/video/sed1330.c b/src/devices/video/sed1330.c new file mode 100644 index 00000000000..2ced64a8170 --- /dev/null +++ b/src/devices/video/sed1330.c @@ -0,0 +1,688 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Seiko-Epson SED1330 LCD Controller emulation + +**********************************************************************/ + +#include "emu.h" +#include "sed1330.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define LOG 0 + + +#define INSTRUCTION_SYSTEM_SET 0x40 +#define INSTRUCTION_SLEEP_IN 0x53 // unimplemented +#define INSTRUCTION_DISP_ON 0x59 +#define INSTRUCTION_DISP_OFF 0x58 +#define INSTRUCTION_SCROLL 0x44 +#define INSTRUCTION_CSRFORM 0x5d +#define INSTRUCTION_CGRAM_ADR 0x5c +#define INSTRUCTION_CSRDIR_RIGHT 0x4c +#define INSTRUCTION_CSRDIR_LEFT 0x4d +#define INSTRUCTION_CSRDIR_UP 0x4e +#define INSTRUCTION_CSRDIR_DOWN 0x4f +#define INSTRUCTION_HDOT_SCR 0x5a +#define INSTRUCTION_OVLAY 0x5b +#define INSTRUCTION_CSRW 0x46 +#define INSTRUCTION_CSRR 0x47 // unimplemented +#define INSTRUCTION_MWRITE 0x42 +#define INSTRUCTION_MREAD 0x43 // unimplemented + + +#define CSRDIR_RIGHT 0x00 +#define CSRDIR_LEFT 0x01 +#define CSRDIR_UP 0x02 +#define CSRDIR_DOWN 0x03 + + +#define MX_OR 0x00 +#define MX_XOR 0x01 // unimplemented +#define MX_AND 0x02 // unimplemented +#define MX_PRIORITY_OR 0x03 // unimplemented + + +#define FC_OFF 0x00 +#define FC_SOLID 0x01 // unimplemented +#define FC_FLASH_32 0x02 // unimplemented +#define FC_FLASH_64 0x03 // unimplemented + + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +// device type definition +const device_type SED1330 = &device_creator; + + +// default address map +static ADDRESS_MAP_START( sed1330, AS_0, 8, sed1330_device ) + AM_RANGE(0x0000, 0xffff) AM_RAM +ADDRESS_MAP_END + + +// internal character generator ROM +ROM_START( sed1330 ) + ROM_REGION( 0x5c0, "gfx1", 0 ) // internal chargen ROM + ROM_LOAD( "sed1330.bin", 0x000, 0x5c0, NO_DUMP ) +ROM_END + + + +//************************************************************************** +// INLINE HELPERS +//************************************************************************** + +//------------------------------------------------- +// readbyte - read a byte at the given address +//------------------------------------------------- + +inline UINT8 sed1330_device::readbyte(offs_t address) +{ + return space().read_byte(address); +} + + +//------------------------------------------------- +// writebyte - write a byte at the given address +//------------------------------------------------- + +inline void sed1330_device::writebyte(offs_t address, UINT8 data) +{ + space().write_byte(address, data); +} + + +//------------------------------------------------- +// increment_csr - increment cursor address +//------------------------------------------------- + +inline void sed1330_device::increment_csr() +{ + switch (m_cd) + { + case CSRDIR_RIGHT: + m_csr++; + break; + + case CSRDIR_LEFT: + m_csr--; + break; + + case CSRDIR_UP: + m_csr -= m_ap; + break; + + case CSRDIR_DOWN: + m_csr += m_ap; + break; + } +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// sed1330_device - constructor +//------------------------------------------------- + +sed1330_device::sed1330_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, SED1330, "SED1330", tag, owner, clock, "sed1330", __FILE__), + device_memory_interface(mconfig, *this), + device_video_interface(mconfig, *this), + m_bf(0), + m_space_config("videoram", ENDIANNESS_LITTLE, 8, 16, 0, NULL, *ADDRESS_MAP_NAME(sed1330)) +{ +} + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *sed1330_device::device_rom_region() const +{ + return ROM_NAME( sed1330 ); +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void sed1330_device::device_start() +{ + // register for state saving + save_item(NAME(m_bf)); + save_item(NAME(m_ir)); + save_item(NAME(m_dor)); + save_item(NAME(m_pbc)); + save_item(NAME(m_d)); + save_item(NAME(m_sleep)); + save_item(NAME(m_sag)); + save_item(NAME(m_m0)); + save_item(NAME(m_m1)); + save_item(NAME(m_m2)); + save_item(NAME(m_ws)); + save_item(NAME(m_iv)); + save_item(NAME(m_wf)); + save_item(NAME(m_fx)); + save_item(NAME(m_fy)); + save_item(NAME(m_cr)); + save_item(NAME(m_tcr)); + save_item(NAME(m_lf)); + save_item(NAME(m_ap)); + save_item(NAME(m_sad1)); + save_item(NAME(m_sad2)); + save_item(NAME(m_sad3)); + save_item(NAME(m_sad4)); + save_item(NAME(m_sl1)); + save_item(NAME(m_sl2)); + save_item(NAME(m_hdotscr)); + save_item(NAME(m_csr)); + save_item(NAME(m_cd)); + save_item(NAME(m_crx)); + save_item(NAME(m_cry)); + save_item(NAME(m_cm)); + save_item(NAME(m_fc)); + save_item(NAME(m_fp)); + save_item(NAME(m_mx)); + save_item(NAME(m_dm)); + save_item(NAME(m_ov)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void sed1330_device::device_reset() +{ +} + + +//------------------------------------------------- +// memory_space_config - return a description of +// any address spaces owned by this device +//------------------------------------------------- + +const address_space_config *sed1330_device::memory_space_config(address_spacenum spacenum) const +{ + return (spacenum == AS_0) ? &m_space_config : NULL; +} + + +//------------------------------------------------- +// status_r - +//------------------------------------------------- + +READ8_MEMBER( sed1330_device::status_r ) +{ + if (LOG) logerror("SED1330 '%s' Status Read: %s\n", tag(), m_bf ? "busy" : "ready"); + + return m_bf << 6; +} + + +//------------------------------------------------- +// command_w - +//------------------------------------------------- + +WRITE8_MEMBER( sed1330_device::command_w ) +{ + m_ir = data; + m_pbc = 0; + + switch (m_ir) + { +#if 0 + case INSTRUCTION_SLEEP_IN: + break; +#endif + case INSTRUCTION_CSRDIR_RIGHT: + case INSTRUCTION_CSRDIR_LEFT: + case INSTRUCTION_CSRDIR_UP: + case INSTRUCTION_CSRDIR_DOWN: + m_cd = data & 0x03; + + if (LOG) + { + switch (m_cd) + { + case CSRDIR_RIGHT: logerror("SED1330 '%s' Cursor Direction: Right\n", tag()); break; + case CSRDIR_LEFT: logerror("SED1330 '%s' Cursor Direction: Left\n", tag()); break; + case CSRDIR_UP: logerror("SED1330 '%s' Cursor Direction: Up\n", tag()); break; + case CSRDIR_DOWN: logerror("SED1330 '%s' Cursor Direction: Down\n", tag()); break; + } + } + break; + } +} + + +//------------------------------------------------- +// data_r - +//------------------------------------------------- + +READ8_MEMBER( sed1330_device::data_r ) +{ + UINT8 data = readbyte(m_csr); + + if (LOG) logerror("SED1330 '%s' Memory Read %02x from %04x\n", tag(), data, m_csr); + + increment_csr(); + + return data; +} + + +//------------------------------------------------- +// data_w - +//------------------------------------------------- + +WRITE8_MEMBER( sed1330_device::data_w ) +{ + switch (m_ir) + { + case INSTRUCTION_SYSTEM_SET: + switch (m_pbc) + { + case 0: + m_m0 = BIT(data, 0); + m_m1 = BIT(data, 1); + m_m2 = BIT(data, 2); + m_ws = BIT(data, 3); + m_iv = BIT(data, 5); + + if (LOG) + { + logerror("SED1330 '%s' %s CG ROM\n", tag(), BIT(data, 0) ? "External" : "Internal"); + logerror("SED1330 '%s' D6 Correction: %s\n", tag(), BIT(data, 1) ? "enabled" : "disabled"); + logerror("SED1330 '%s' Character Height: %u\n", tag(), BIT(data, 2) ? 16 : 8); + logerror("SED1330 '%s' %s Panel Drive\n", tag(), BIT(data, 3) ? "Dual" : "Single"); + logerror("SED1330 '%s' Screen Top-Line Correction: %s\n", tag(), BIT(data, 5) ? "disabled" : "enabled"); + } + break; + + case 1: + m_fx = (data & 0x07) + 1; + m_wf = BIT(data, 7); + + if (LOG) + { + logerror("SED1330 '%s' Horizontal Character Size: %u\n", tag(), m_fx); + logerror("SED1330 '%s' %s AC Drive\n", tag(), BIT(data, 7) ? "2-frame" : "16-line"); + } + break; + + case 2: + m_fy = (data & 0x0f) + 1; + if (LOG) logerror("SED1330 '%s' Vertical Character Size: %u\n", tag(), m_fy); + break; + + case 3: + m_cr = data + 1; + if (LOG) logerror("SED1330 '%s' Visible Characters Per Line: %u\n", tag(), m_cr); + break; + + case 4: + m_tcr = data + 1; + if (LOG) logerror("SED1330 '%s' Total Characters Per Line: %u\n", tag(), m_tcr); + break; + + case 5: + m_lf = data + 1; + if (LOG) logerror("SED1330 '%s' Frame Height: %u\n", tag(), m_lf); + break; + + case 6: + m_ap = (m_ap & 0xff00) | data; + break; + + case 7: + m_ap = (data << 8) | (m_ap & 0xff); + if (LOG) logerror("SED1330 '%s' Virtual Screen Width: %u\n", tag(), m_ap); + break; + + default: + logerror("SED1330 '%s' Invalid parameter byte %02x\n", tag(), data); + } + break; + + case INSTRUCTION_DISP_ON: + case INSTRUCTION_DISP_OFF: + m_d = BIT(data, 0); + m_fc = data & 0x03; + m_fp = data >> 2; + if (LOG) + { + logerror("SED1330 '%s' Display: %s\n", tag(), BIT(data, 0) ? "enabled" : "disabled"); + + switch (m_fc) + { + case FC_OFF: logerror("SED1330 '%s' Cursor: disabled\n", tag()); break; + case FC_SOLID: logerror("SED1330 '%s' Cursor: solid\n", tag()); break; + case FC_FLASH_32: logerror("SED1330 '%s' Cursor: fFR/32\n", tag()); break; + case FC_FLASH_64: logerror("SED1330 '%s' Cursor: fFR/64\n", tag()); break; + } + + switch (m_fp & 0x03) + { + case FC_OFF: logerror("SED1330 '%s' Display Page 1: disabled\n", tag()); break; + case FC_SOLID: logerror("SED1330 '%s' Display Page 1: enabled\n", tag()); break; + case FC_FLASH_32: logerror("SED1330 '%s' Display Page 1: flash fFR/32\n", tag()); break; + case FC_FLASH_64: logerror("SED1330 '%s' Display Page 1: flash fFR/64\n", tag()); break; + } + + switch ((m_fp >> 2) & 0x03) + { + case FC_OFF: logerror("SED1330 '%s' Display Page 2/4: disabled\n", tag()); break; + case FC_SOLID: logerror("SED1330 '%s' Display Page 2/4: enabled\n", tag()); break; + case FC_FLASH_32: logerror("SED1330 '%s' Display Page 2/4: flash fFR/32\n", tag()); break; + case FC_FLASH_64: logerror("SED1330 '%s' Display Page 2/4: flash fFR/64\n", tag()); break; + } + + switch ((m_fp >> 4) & 0x03) + { + case FC_OFF: logerror("SED1330 '%s' Display Page 3: disabled\n", tag()); break; + case FC_SOLID: logerror("SED1330 '%s' Display Page 3: enabled\n", tag()); break; + case FC_FLASH_32: logerror("SED1330 '%s' Display Page 3: flash fFR/32\n", tag()); break; + case FC_FLASH_64: logerror("SED1330 '%s' Display Page 3: flash fFR/64\n", tag()); break; + } + } + break; + + case INSTRUCTION_SCROLL: + switch (m_pbc) + { + case 0: + m_sad1 = (m_sad1 & 0xff00) | data; + break; + + case 1: + m_sad1 = (data << 8) | (m_sad1 & 0xff); + if (LOG) logerror("SED1330 '%s' Display Page 1 Start Address: %04x\n", tag(), m_sad1); + break; + + case 2: + m_sl1 = data + 1; + if (LOG) logerror("SED1330 '%s' Display Block 1 Screen Lines: %u\n", tag(), m_sl1); + break; + + case 3: + m_sad2 = (m_sad2 & 0xff00) | data; + break; + + case 4: + m_sad2 = (data << 8) | (m_sad2 & 0xff); + if (LOG) logerror("SED1330 '%s' Display Page 2 Start Address: %04x\n", tag(), m_sad2); + break; + + case 5: + m_sl2 = data + 1; + if (LOG) logerror("SED1330 '%s' Display Block 2 Screen Lines: %u\n", tag(), m_sl2); + break; + + case 6: + m_sad3 = (m_sad3 & 0xff00) | data; + break; + + case 7: + m_sad3 = (data << 8) | (m_sad3 & 0xff); + if (LOG) logerror("SED1330 '%s' Display Page 3 Start Address: %04x\n", tag(), m_sad3); + break; + + case 8: + m_sad4 = (m_sad4 & 0xff00) | data; + break; + + case 9: + m_sad4 = (data << 8) | (m_sad4 & 0xff); + if (LOG) logerror("SED1330 '%s' Display Page 4 Start Address: %04x\n", tag(), m_sad4); + break; + + default: + logerror("SED1330 '%s' Invalid parameter byte %02x\n", tag(), data); + } + break; + + case INSTRUCTION_CSRFORM: + switch (m_pbc) + { + case 0: + m_crx = (data & 0x0f) + 1; + if (LOG) logerror("SED1330 '%s' Horizontal Cursor Size: %u\n", tag(), m_crx); + break; + + case 1: + m_cry = (data & 0x0f) + 1; + m_cm = BIT(data, 7); + if (LOG) + { + logerror("SED1330 '%s' Vertical Cursor Location: %u\n", tag(), m_cry); + logerror("SED1330 '%s' Cursor Shape: %s\n", tag(), BIT(data, 7) ? "Block" : "Underscore"); + } + break; + + default: + logerror("SED1330 '%s' Invalid parameter byte %02x\n", tag(), data); + } + break; + + case INSTRUCTION_CGRAM_ADR: + switch (m_pbc) + { + case 0: + m_sag = (m_sag & 0xff00) | data; + break; + + case 1: + m_sag = (data << 8) | (m_sag & 0xff); + if (LOG) logerror("SED1330 '%s' Character Generator RAM Start Address: %04x\n", tag(), m_sag); + break; + + default: + logerror("SED1330 '%s' Invalid parameter byte %02x\n", tag(), data); + } + break; + + case INSTRUCTION_HDOT_SCR: + m_hdotscr = data & 0x07; + if (LOG) logerror("SED1330 '%s' Horizontal Dot Scroll: %u\n", tag(), m_hdotscr); + break; + + case INSTRUCTION_OVLAY: + m_mx = data & 0x03; + m_dm = (data >> 2) & 0x03; + m_ov = BIT(data, 4); + + if (LOG) + { + switch (m_mx) + { + case MX_OR: logerror("SED1330 '%s' Display Composition Method: OR\n", tag()); break; + case MX_XOR: logerror("SED1330 '%s' Display Composition Method: Exclusive-OR\n", tag()); break; + case MX_AND: logerror("SED1330 '%s' Display Composition Method: AND\n", tag()); break; + case MX_PRIORITY_OR: logerror("SED1330 '%s' Display Composition Method: Priority-OR\n", tag()); break; + } + + logerror("SED1330 '%s' Display Page 1 Mode: %s\n", tag(), BIT(data, 2) ? "Graphics" : "Text"); + logerror("SED1330 '%s' Display Page 3 Mode: %s\n", tag(), BIT(data, 3) ? "Graphics" : "Text"); + logerror("SED1330 '%s' Display Composition Layers: %u\n", tag(), BIT(data, 4) ? 3 : 2); + } + break; + + case INSTRUCTION_CSRW: + switch (m_pbc) + { + case 0: + m_csr = (m_csr & 0xff00) | data; + break; + + case 1: + m_csr = (data << 8) | (m_csr & 0xff); + if (LOG) logerror("SED1330 '%s' Cursor Address %04x\n", tag(), m_csr); + break; + + default: + logerror("SED1330 '%s' Invalid parameter byte %02x\n", tag(), data); + } + break; +#if 0 + case INSTRUCTION_CSRR: + break; +#endif + case INSTRUCTION_MWRITE: + if (LOG) logerror("SED1330 '%s' Memory Write %02x to %04x (row %u col %u line %u)\n", tag(), data, m_csr, m_csr/80/8, m_csr%80, m_csr/80); + + writebyte(m_csr, data); + + increment_csr(); + break; +#if 0 + case INSTRUCTION_MREAD: + break; +#endif + default: + logerror("SED1330 '%s' Unsupported instruction %02x\n", tag(), m_ir); + } + + m_pbc++; +} + + +//------------------------------------------------- +// draw_text_scanline - +//------------------------------------------------- + +void sed1330_device::draw_text_scanline(bitmap_ind16 &bitmap, const rectangle &cliprect, int y, UINT16 va) +{ + int sx, x; + + for (sx = 0; sx < m_cr; sx++) + { + if ((va + sx) == m_csr) + { + if (m_fc == FC_OFF) continue; + + if (m_cm) + { + // block cursor + if (y % m_fy < m_cry) + { + for (x = 0; x < m_crx; x++) + { + bitmap.pix16(y, (sx * m_fx) + x) = 1; + } + } + } + else + { + // underscore cursor + if (y % m_fy == m_cry) + { + for (x = 0; x < m_crx; x++) + { + bitmap.pix16(y, (sx * m_fx) + x) = 1; + } + } + } + } + } +} + + +//------------------------------------------------- +// draw_graphics_scanline - +//------------------------------------------------- + +void sed1330_device::draw_graphics_scanline(bitmap_ind16 &bitmap, const rectangle &cliprect, int y, UINT16 va) +{ + int sx, x; + + for (sx = 0; sx < m_cr; sx++) + { + UINT8 data = readbyte(va++); + + for (x = 0; x < m_fx; x++) + { + bitmap.pix16(y, (sx * m_fx) + x) = BIT(data, 7); + data <<= 1; + } + } +} + + +//------------------------------------------------- +// update_graphics - +//------------------------------------------------- + +void sed1330_device::update_graphics(bitmap_ind16 &bitmap, const rectangle &cliprect) +{ +} + + +//------------------------------------------------- +// update_text - +//------------------------------------------------- + +void sed1330_device::update_text(bitmap_ind16 &bitmap, const rectangle &cliprect) +{ + int y; + + if (m_ws) + { + for (y = 0; y < m_sl1; y++) + { + UINT16 sad1 = m_sad1 + ((y / m_fy) * m_ap); + UINT16 sad2 = m_sad2 + (y * m_ap); + UINT16 sad3 = m_sad3 + ((y / m_fy) * m_ap); + UINT16 sad4 = m_sad4 + (y * m_ap); + + // draw graphics display page 2 scanline + draw_graphics_scanline(bitmap, cliprect, y, sad2); + + // draw text display page 1 scanline + draw_text_scanline(bitmap, cliprect, y, sad1); + + // draw graphics display page 4 scanline + draw_graphics_scanline(bitmap, cliprect, y + m_sl1, sad4); + + // draw text display page 3 scanline + draw_text_scanline(bitmap, cliprect, y + m_sl1, sad3); + } + } +} + + +//------------------------------------------------- +// screen_update - +//------------------------------------------------- + +UINT32 sed1330_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) +{ + if (m_d) + { + if (m_dm) + { + update_graphics(bitmap, cliprect); + } + else + { + update_text(bitmap, cliprect); + } + } + return 0; +} diff --git a/src/devices/video/sed1330.h b/src/devices/video/sed1330.h new file mode 100644 index 00000000000..a78c71ef3a3 --- /dev/null +++ b/src/devices/video/sed1330.h @@ -0,0 +1,126 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + Seiko-Epson SED1330 LCD Controller emulation + +**********************************************************************/ + +#pragma once + +#ifndef __SED1330__ +#define __SED1330__ + +#include "emu.h" + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_SED1330_ADD(_tag, _clock, _screen_tag, _map) \ + MCFG_DEVICE_ADD(_tag, SED1330, _clock) \ + MCFG_DEVICE_ADDRESS_MAP(AS_0, _map) \ + MCFG_VIDEO_SET_SCREEN(_screen_tag) + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> sed1330_device + +class sed1330_device : public device_t, + public device_memory_interface, + public device_video_interface +{ +public: + // construction/destruction + sed1330_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual const rom_entry *device_rom_region() const; + + DECLARE_READ8_MEMBER( status_r ); + DECLARE_WRITE8_MEMBER( command_w ); + + DECLARE_READ8_MEMBER( data_r ); + DECLARE_WRITE8_MEMBER( data_w ); + + UINT32 screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const; + + inline UINT8 readbyte(offs_t address); + inline void writebyte(offs_t address, UINT8 m_data); + inline void increment_csr(); + + void draw_text_scanline(bitmap_ind16 &bitmap, const rectangle &cliprect, int y, UINT16 va); + void draw_graphics_scanline(bitmap_ind16 &bitmap, const rectangle &cliprect, int y, UINT16 va); + void update_graphics(bitmap_ind16 &bitmap, const rectangle &cliprect); + void update_text(bitmap_ind16 &bitmap, const rectangle &cliprect); + +private: + int m_bf; // busy flag + + UINT8 m_ir; // instruction register + UINT8 m_dor; // data output register + int m_pbc; // parameter byte counter + + int m_d; // display enabled + int m_sleep; // sleep mode + + UINT16 m_sag; // character generator RAM start address + int m_m0; // character generator ROM (0=internal, 1=external) + int m_m1; // character generator RAM D6 correction (0=no, 1=yes) + int m_m2; // height of character bitmaps (0=8, 1=16 pixels) + int m_ws; // LCD drive method (0=single, 1=dual panel) + int m_iv; // screen origin compensation for inverse display (0=yes, 1=no) + int m_wf; // AC frame drive waveform period (0=16-line, 1=2-frame) + + int m_fx; // character width in pixels + int m_fy; // character height in pixels + int m_cr; // visible line width in characters + int m_tcr; // total line width in characters (including horizontal blanking) + int m_lf; // frame height in lines + UINT16 m_ap; // virtual screen line width in characters + + UINT16 m_sad1; // display page 1 start address + UINT16 m_sad2; // display page 2 start address + UINT16 m_sad3; // display page 3 start address + UINT16 m_sad4; // display page 4 start address + int m_sl1; // display block 1 height in lines + int m_sl2; // display block 2 height in lines + int m_hdotscr; // horizontal dot scroll in pixels + int m_fp; // display page flash control + + UINT16 m_csr; // cursor address register + int m_cd; // cursor increment direction + int m_crx; // cursor width + int m_cry; // cursor height or location + int m_cm; // cursor shape (0=underscore, 1=block) + int m_fc; // cursor flash control + + int m_mx; // screen layer composition method + int m_dm; // display mode for pages 1, 3 + int m_ov; // graphics mode layer composition + + // address space configurations + const address_space_config m_space_config; +}; + + +// device type definition +extern const device_type SED1330; + + + +#endif diff --git a/src/devices/video/sed1520.c b/src/devices/video/sed1520.c new file mode 100644 index 00000000000..ba5c68145cd --- /dev/null +++ b/src/devices/video/sed1520.c @@ -0,0 +1,164 @@ +// license:BSD-3-Clause +// copyright-holders:Sandro Ronco +/*************************************************************************** + + SED1520 LCD controller + + TODO: + - busy flag + +***************************************************************************/ + +#include "emu.h" +#include "video/sed1520.h" + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type SED1520 = &device_creator; + + +//************************************************************************** +// live device +//************************************************************************** + +//------------------------------------------------- +// sed1520_device - constructor +//------------------------------------------------- + +sed1520_device::sed1520_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, SED1520, "SED1520", tag, owner, clock, "sed1520", __FILE__), + m_screen_update_func(NULL) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void sed1520_device::device_start() +{ + // state saving + save_item(NAME(m_lcd_on)); + save_item(NAME(m_busy)); + save_item(NAME(m_page)); + save_item(NAME(m_column)); + save_item(NAME(m_old_column)); + save_item(NAME(m_start_line)); + save_item(NAME(m_adc)); + save_item(NAME(m_static_drive)); + save_item(NAME(m_modify_write)); + save_item(NAME(m_vram)); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void sed1520_device::device_reset() +{ + m_lcd_on = 0; + m_busy = 0; + m_page = 3; + m_column = 0; + m_old_column = 0; + m_start_line = 0; + m_adc = 1; + m_static_drive = 0; + m_modify_write = false; + memset(m_vram, 0x00, sizeof(m_vram)); +} + + +//************************************************************************** +// device interface +//************************************************************************** + +UINT32 sed1520_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) +{ + if (m_lcd_on) + { + if (m_screen_update_func) + m_screen_update_func(*this, bitmap, cliprect, m_vram, m_start_line, m_adc); + } + else if (m_static_drive) + return UPDATE_HAS_NOT_CHANGED; + else + bitmap.fill(0, cliprect); + + return 0; +} + +READ8_MEMBER(sed1520_device::read) +{ + if (offset & 0x01) + return data_read(space, 0); + else + return status_read(space, 0); +} + +WRITE8_MEMBER(sed1520_device::write) +{ + if (offset & 0x01) + data_write(space, 0, data); + else + control_write(space, 0, data); +} + +WRITE8_MEMBER(sed1520_device::control_write) +{ + if((data & 0xfe) == 0xae) // display on/off + m_lcd_on = data & 0x01; + else if((data & 0xe0) == 0xc0) // set start line + m_start_line = data & 0x1f; + else if((data & 0xfc) == 0xb8) // set page address + m_page = data & 0x03; + else if((data & 0x80) == 0x00) // set column address + m_column = data % 80; + else if((data & 0xfe) == 0xa0) // select ADC + m_adc = data & 0x01; + else if((data & 0xfe) == 0xa4) // static drive on/off + m_static_drive = data & 0x01; + else if((data & 0xfe) == 0xa8) // select duty + ; + else if(data == 0xe0) // read-modify-write on + { + m_modify_write = true; + m_old_column = m_column; + } + else if(data == 0xee) // read-modify-write off + { + m_modify_write = false; + m_column = m_old_column; + } + else if(data == 0xe2) // reset + { + m_start_line = m_column = 0; + m_page = 3; + } + else + logerror("%s: invalid SED1520 command: %x\n", tag(), data); +} + +READ8_MEMBER(sed1520_device::status_read) +{ + UINT8 data = (m_busy << 7) | (m_adc << 6) | (m_lcd_on << 5); + return data; +} + +WRITE8_MEMBER(sed1520_device::data_write) +{ + m_vram[(m_page * 80 + m_column) % sizeof(m_vram)] = data; + m_column = (m_column + 1) % 80; +} + +READ8_MEMBER(sed1520_device::data_read) +{ + UINT8 data = m_vram[(m_page * 80 + m_column) % sizeof(m_vram)]; + if (!m_modify_write) + m_column = (m_column + 1) % 80; + return data; +} diff --git a/src/devices/video/sed1520.h b/src/devices/video/sed1520.h new file mode 100644 index 00000000000..ebcc640314e --- /dev/null +++ b/src/devices/video/sed1520.h @@ -0,0 +1,72 @@ +// license:BSD-3-Clause +// copyright-holders:Sandro Ronco +/*************************************************************************** + + SED1520 LCD controller + +***************************************************************************/ + +#pragma once + +#ifndef __SED1520_H__ +#define __SED1520_H__ + + +#define MCFG_SED1520_ADD( _tag, _cb ) \ + MCFG_DEVICE_ADD( _tag, SED1520, 0 ) \ + sed1520_device::static_set_screen_update_cb(*device, _cb); + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +typedef UINT32 (*sed1520_screen_update_func)(device_t &device, bitmap_ind16 &bitmap, const rectangle &cliprect, UINT8 *vram, int start_line, int adc); +#define SED1520_UPDATE_CB(name) UINT32 name(device_t &device, bitmap_ind16 &bitmap, const rectangle &cliprect, UINT8 *vram, int start_line, int adc) + + +// ======================> sed1520_device + +class sed1520_device : public device_t +{ +public: + // construction/destruction + sed1520_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // static configuration helpers + static void static_set_screen_update_cb(device_t &device, sed1520_screen_update_func _cb) { downcast(device).m_screen_update_func = _cb; } + + // device interface + virtual DECLARE_WRITE8_MEMBER(write); + virtual DECLARE_READ8_MEMBER(read); + virtual DECLARE_WRITE8_MEMBER(control_write); + virtual DECLARE_READ8_MEMBER(status_read); + virtual DECLARE_WRITE8_MEMBER(data_write); + virtual DECLARE_READ8_MEMBER(data_read); + UINT32 screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + +private: + // internal state + UINT8 m_lcd_on; + UINT8 m_busy; + UINT8 m_page; + UINT8 m_column; + UINT8 m_old_column; + UINT8 m_start_line; + UINT8 m_adc; + UINT8 m_static_drive; + bool m_modify_write; + sed1520_screen_update_func m_screen_update_func; + + UINT8 m_vram[0x140]; +}; + + +// device type definition +extern const device_type SED1520; + +#endif diff --git a/src/devices/video/snes_ppu.c b/src/devices/video/snes_ppu.c new file mode 100644 index 00000000000..93529ad307e --- /dev/null +++ b/src/devices/video/snes_ppu.c @@ -0,0 +1,2949 @@ +// license:BSD-3-Clause +// copyright-holders:Anthony Kruize, Fabio Priuli +/*************************************************************************** + + snes.c + + Video file to handle emulation of the Nintendo Super NES. + + Anthony Kruize + Based on the original code by Lee Hammerton (aka Savoury Snax) + + Some notes on the snes video hardware: + + Object Attribute Memory(OAM) is made up of 128 blocks of 32 bits, followed + by 128 blocks of 2 bits. The format for each block is: + -First Block---------------------------------------------------------------- + | x pos | y pos |char no.| v flip | h flip |priority|palette |char no msb| + +--------+--------+--------+--------+--------+--------+--------+-----------+ + | 8 bits | 8 bits | 8 bits | 1 bit | 1 bit | 2 bits | 3 bits | 1 bit | + -Second Block--------------------------------------------------------------- + | size | x pos msb | + +-------+-----------+ + | 1 bit | 1 bit | + --------------------- + + Video RAM contains information for character data and screen maps. + Screen maps are made up of 32 x 32 blocks of 16 bits each. + The format for each block is: + ---------------------------------------------- + | v flip | x flip |priority|palette |char no.| + +--------+--------+--------+--------+--------+ + | 1 bit | 1 bit | 1 bit | 3 bits |10 bits | + ---------------------------------------------- + Mode 7 is stored differently. Character data and screen map are interleaved. + There are two formats: + -Normal----------------- -EXTBG----------------------------- + | char data | char no. | | priority | char data | char no. | + +-----------+----------+ +----------+-----------+----------+ + | 8 bits | 8 bits | | 1 bit | 7 bits | 8 bits | + ------------------------ ----------------------------------- + + The screen layers are drawn with the following priorities (updated info courtesy of byuu): + + | | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | + ------------------------------------------------------------------------------------------------------------- + | Mode 0 | BG4B | BG3B | OAM0 | BG4A | BG3A | OAM1 | BG2B | BG1B | OAM2 | BG2A | BG1A | OAM3 | + ------------------------------------------------------------------------------------------------------------- + | Mode 1 (*)| BG3B | OAM0 | OAM1 | BG2B | BG1B | OAM2 | BG2A | BG1A | OAM3 | BG3A | | | + ------------------------------------------------------------------------------------------------------------- + | Mode 1 (!)| BG3B | OAM0 | BG3A | OAM1 | BG2B | BG1B | OAM2 | BG2A | BG1A | OAM3 | | | + ------------------------------------------------------------------------------------------------------------- + | Mode 2 | BG2B | OAM0 | BG1B | OAM1 | BG2A | OAM2 | BG1A | OAM3 | | | | | + ------------------------------------------------------------------------------------------------------------- + | Mode 3 | BG2B | OAM0 | BG1B | OAM1 | BG2A | OAM2 | BG1A | OAM3 | | | | | + ------------------------------------------------------------------------------------------------------------- + | Mode 4 | BG2B | OAM0 | BG1B | OAM1 | BG2A | OAM2 | BG1A | OAM3 | | | | | + ------------------------------------------------------------------------------------------------------------- + | Mode 5 | BG2B | OAM0 | BG1B | OAM1 | BG2A | OAM2 | BG1A | OAM3 | | | | | + ------------------------------------------------------------------------------------------------------------- + | Mode 6 | OAM0 | BG1B | OAM1 | OAM2 | BG1A | OAM3 | | | | | | | + ------------------------------------------------------------------------------------------------------------- + | Mode 7 (+)| OAM0 | BG1n | OAM1 | OAM2 | OAM3 | | | | | | | | + ------------------------------------------------------------------------------------------------------------- + | Mode 7 (-)| BG2B | OAM0 | BG1n | OAM1 | BG2A | OAM2 | OAM3 | | | | | | + ------------------------------------------------------------------------------------------------------------- + + Where: + - Mode 1 (*) is Mode 1 with bg3_pty = 1 + - Mode 1 (!) is Mode 1 with bg3_pty = 0 + - Mode 7 (+) is base Mode 7 + - Mode 7 (-) is Mode 7 EXTBG + +***************************************************************************/ + +#include "emu.h" +#include "video/snes_ppu.h" + +#define SNES_MAINSCREEN 0 +#define SNES_SUBSCREEN 1 +#define SNES_CLIP_NEVER 0 +#define SNES_CLIP_IN 1 +#define SNES_CLIP_OUT 2 +#define SNES_CLIP_ALWAYS 3 + +#define SNES_VRAM_SIZE 0x20000 /* 128kb of video ram */ +#define SNES_CGRAM_SIZE 0x202 /* 256 16-bit colours + 1 tacked on 16-bit colour for fixed colour */ +#define SNES_OAM_SIZE 0x440 /* 1088 bytes of Object Attribute Memory */ +#define FIXED_COLOUR 256 /* Position in cgram for fixed colour */ + + +/* Definitions for PPU Memory-Mapped registers */ +#define INIDISP 0x2100 +#define OBSEL 0x2101 +#define OAMADDL 0x2102 +#define OAMADDH 0x2103 +#define OAMDATA 0x2104 +#define BGMODE 0x2105 /* abcdefff = abcd: bg4-1 tile size | e: BG3 high priority | f: mode */ +#define MOSAIC 0x2106 /* xxxxabcd = x: pixel size | abcd: affects bg 1-4 */ +#define BG1SC 0x2107 +#define BG2SC 0x2108 +#define BG3SC 0x2109 +#define BG4SC 0x210A +#define BG12NBA 0x210B +#define BG34NBA 0x210C +#define BG1HOFS 0x210D +#define BG1VOFS 0x210E +#define BG2HOFS 0x210F +#define BG2VOFS 0x2110 +#define BG3HOFS 0x2111 +#define BG3VOFS 0x2112 +#define BG4HOFS 0x2113 +#define BG4VOFS 0x2114 +#define VMAIN 0x2115 /* i---ffrr = i: Increment timing | f: Full graphic | r: increment rate */ +#define VMADDL 0x2116 /* aaaaaaaa = a: LSB of vram address */ +#define VMADDH 0x2117 /* aaaaaaaa = a: MSB of vram address */ +#define VMDATAL 0x2118 /* dddddddd = d: data to be written */ +#define VMDATAH 0x2119 /* dddddddd = d: data to be written */ +#define M7SEL 0x211A /* ab----yx = a: screen over | y: vertical flip | x: horizontal flip */ +#define M7A 0x211B /* aaaaaaaa = a: COSINE rotate angle / X expansion */ +#define M7B 0x211C /* aaaaaaaa = a: SINE rotate angle / X expansion */ +#define M7C 0x211D /* aaaaaaaa = a: SINE rotate angle / Y expansion */ +#define M7D 0x211E /* aaaaaaaa = a: COSINE rotate angle / Y expansion */ +#define M7X 0x211F +#define M7Y 0x2120 +#define CGADD 0x2121 +#define CGDATA 0x2122 +#define W12SEL 0x2123 +#define W34SEL 0x2124 +#define WOBJSEL 0x2125 +#define WH0 0x2126 /* pppppppp = p: Left position of window 1 */ +#define WH1 0x2127 /* pppppppp = p: Right position of window 1 */ +#define WH2 0x2128 /* pppppppp = p: Left position of window 2 */ +#define WH3 0x2129 /* pppppppp = p: Right position of window 2 */ +#define WBGLOG 0x212A /* aabbccdd = a: BG4 params | b: BG3 params | c: BG2 params | d: BG1 params */ +#define WOBJLOG 0x212B /* ----ccoo = c: Colour window params | o: Object window params */ +#define TM 0x212C +#define TS 0x212D +#define TMW 0x212E +#define TSW 0x212F +#define CGWSEL 0x2130 +#define CGADSUB 0x2131 +#define COLDATA 0x2132 +#define SETINI 0x2133 +#define MPYL 0x2134 +#define MPYM 0x2135 +#define MPYH 0x2136 +#define SLHV 0x2137 +#define ROAMDATA 0x2138 +#define RVMDATAL 0x2139 +#define RVMDATAH 0x213A +#define RCGDATA 0x213B +#define OPHCT 0x213C +#define OPVCT 0x213D +#define STAT77 0x213E +#define STAT78 0x213F + + +#if SNES_LAYER_DEBUG +/* red green blue purple yellow cyan grey white */ +static const UINT16 dbg_mode_colours[8] = { 0x1f, 0x3e0, 0x7c00, 0x7c1f, 0x3ff, 0x7fe0, 0x4210, 0x7fff }; +#endif /* SNES_LAYER_DEBUG */ + +static const UINT16 table_obj_offset[8][8] = +{ + { (0*32), (0*32)+32, (0*32)+64, (0*32)+96, (0*32)+128, (0*32)+160, (0*32)+192, (0*32)+224 }, + { (16*32), (16*32)+32, (16*32)+64, (16*32)+96, (16*32)+128, (16*32)+160, (16*32)+192, (16*32)+224 }, + { (32*32), (32*32)+32, (32*32)+64, (32*32)+96, (32*32)+128, (32*32)+160, (32*32)+192, (32*32)+224 }, + { (48*32), (48*32)+32, (48*32)+64, (48*32)+96, (48*32)+128, (48*32)+160, (48*32)+192, (48*32)+224 }, + { (64*32), (64*32)+32, (64*32)+64, (64*32)+96, (64*32)+128, (64*32)+160, (64*32)+192, (64*32)+224 }, + { (80*32), (80*32)+32, (80*32)+64, (80*32)+96, (80*32)+128, (80*32)+160, (80*32)+192, (80*32)+224 }, + { (96*32), (96*32)+32, (96*32)+64, (96*32)+96, (96*32)+128, (96*32)+160, (96*32)+192, (96*32)+224 }, + { (112*32), (112*32)+32, (112*32)+64, (112*32)+96, (112*32)+128, (112*32)+160, (112*32)+192, (112*32)+224 } +}; + + +enum +{ + SNES_COLOR_DEPTH_2BPP = 0, + SNES_COLOR_DEPTH_4BPP, + SNES_COLOR_DEPTH_8BPP +}; + + +#define PPU_REG(a) m_regs[a - 0x2100] + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type SNES_PPU = &device_creator; + + +//************************************************************************** +// live device +//************************************************************************** + +//------------------------------------------------- +// snes_ppu_device - constructor +//------------------------------------------------- + +snes_ppu_device::snes_ppu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, SNES_PPU, "SNES PPU", tag, owner, clock, "snes_ppu", __FILE__), + device_video_interface(mconfig, *this), + m_openbus_cb(*this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void snes_ppu_device::device_start() +{ + m_openbus_cb.resolve_safe(0); + + m_vram = auto_alloc_array(machine(), UINT8, SNES_VRAM_SIZE); + m_cgram = auto_alloc_array(machine(), UINT16, SNES_CGRAM_SIZE/2); + m_oam_ram = auto_alloc_array(machine(), UINT16, SNES_OAM_SIZE/2); + + for (int i = 0; i < 2; i++) + { + save_item(NAME(m_scanlines[i].enable), i); + save_item(NAME(m_scanlines[i].clip), i); + save_item(NAME(m_scanlines[i].buffer), i); + save_item(NAME(m_scanlines[i].priority), i); + save_item(NAME(m_scanlines[i].layer), i); + save_item(NAME(m_scanlines[i].blend_exception), i); + } + + for (int i = 0; i < 6; i++) + { + save_item(NAME(m_layer[i].window1_enabled), i); + save_item(NAME(m_layer[i].window1_invert), i); + save_item(NAME(m_layer[i].window2_enabled), i); + save_item(NAME(m_layer[i].window2_invert), i); + save_item(NAME(m_layer[i].wlog_mask), i); + save_item(NAME(m_layer[i].color_math), i); + save_item(NAME(m_layer[i].charmap), i); + save_item(NAME(m_layer[i].tilemap), i); + save_item(NAME(m_layer[i].tilemap_size), i); + save_item(NAME(m_layer[i].tile_size), i); + save_item(NAME(m_layer[i].mosaic_enabled), i); + save_item(NAME(m_layer[i].main_window_enabled), i); + save_item(NAME(m_layer[i].sub_window_enabled), i); + save_item(NAME(m_layer[i].main_bg_enabled), i); + save_item(NAME(m_layer[i].sub_bg_enabled), i); + save_item(NAME(m_layer[i].hoffs), i); + save_item(NAME(m_layer[i].voffs), i); + + save_item(NAME(m_clipmasks[i]), i); + } + + save_item(NAME(m_oam.address_low)); + save_item(NAME(m_oam.address_high)); + save_item(NAME(m_oam.saved_address_low)); + save_item(NAME(m_oam.saved_address_high)); + save_item(NAME(m_oam.address)); + save_item(NAME(m_oam.priority_rotation)); + save_item(NAME(m_oam.next_charmap)); + save_item(NAME(m_oam.next_size)); + save_item(NAME(m_oam.size)); + save_item(NAME(m_oam.next_name_select)); + save_item(NAME(m_oam.name_select)); + save_item(NAME(m_oam.first_sprite)); + save_item(NAME(m_oam.flip)); + save_item(NAME(m_oam.write_latch)); + + save_item(NAME(m_beam.latch_horz)); + save_item(NAME(m_beam.latch_vert)); + save_item(NAME(m_beam.current_vert)); + save_item(NAME(m_beam.last_visible_line)); + save_item(NAME(m_beam.interlace_count)); + + save_item(NAME(m_mode7.repeat)); + save_item(NAME(m_mode7.hflip)); + save_item(NAME(m_mode7.vflip)); + save_item(NAME(m_mode7.matrix_a)); + save_item(NAME(m_mode7.matrix_b)); + save_item(NAME(m_mode7.matrix_c)); + save_item(NAME(m_mode7.matrix_d)); + save_item(NAME(m_mode7.origin_x)); + save_item(NAME(m_mode7.origin_y)); + save_item(NAME(m_mode7.hor_offset)); + save_item(NAME(m_mode7.ver_offset)); + save_item(NAME(m_mode7.extbg)); + + for (int i = 0; i < ARRAY_LENGTH(m_oam_spritelist); i++) + { + save_item(NAME(m_oam_spritelist[i].tile), i); + save_item(NAME(m_oam_spritelist[i].x), i); + save_item(NAME(m_oam_spritelist[i].y), i); + save_item(NAME(m_oam_spritelist[i].size), i); + save_item(NAME(m_oam_spritelist[i].vflip), i); + save_item(NAME(m_oam_spritelist[i].hflip), i); + save_item(NAME(m_oam_spritelist[i].priority_bits), i); + save_item(NAME(m_oam_spritelist[i].pal), i); + save_item(NAME(m_oam_spritelist[i].height), i); + save_item(NAME(m_oam_spritelist[i].width), i); + } + + for (int i = 0; i < ARRAY_LENGTH(m_oam_tilelist); i++) + { + save_item(NAME(m_oam_tilelist[i].x), i); + save_item(NAME(m_oam_tilelist[i].priority), i); + save_item(NAME(m_oam_tilelist[i].pal), i); + save_item(NAME(m_oam_tilelist[i].tileaddr), i); + save_item(NAME(m_oam_tilelist[i].hflip), i); + } + + save_item(NAME(m_mosaic_size)); + save_item(NAME(m_clip_to_black)); + save_item(NAME(m_prevent_color_math)); + save_item(NAME(m_sub_add_mode)); + save_item(NAME(m_bg3_priority_bit)); + save_item(NAME(m_direct_color)); + save_item(NAME(m_ppu_last_scroll)); + save_item(NAME(m_mode7_last_scroll)); + + save_item(NAME(m_ppu1_open_bus)); + save_item(NAME(m_ppu2_open_bus)); + save_item(NAME(m_ppu1_version)); + save_item(NAME(m_ppu2_version)); + save_item(NAME(m_window1_left)); + save_item(NAME(m_window1_right)); + save_item(NAME(m_window2_left)); + save_item(NAME(m_window2_right)); + + save_item(NAME(m_update_windows)); + save_item(NAME(m_update_offsets)); + save_item(NAME(m_update_oam_list)); + save_item(NAME(m_mode)); + save_item(NAME(m_interlace)); + save_item(NAME(m_obj_interlace)); + save_item(NAME(m_screen_brightness)); + save_item(NAME(m_screen_disabled)); + save_item(NAME(m_pseudo_hires)); + save_item(NAME(m_color_modes)); + save_item(NAME(m_stat77)); + save_item(NAME(m_stat78)); + + save_item(NAME(m_htmult)); + save_item(NAME(m_cgram_address)); + save_item(NAME(m_read_ophct)); + save_item(NAME(m_read_opvct)); + save_item(NAME(m_vram_fgr_high)); + save_item(NAME(m_vram_fgr_increment)); + save_item(NAME(m_vram_fgr_count)); + save_item(NAME(m_vram_fgr_mask)); + save_item(NAME(m_vram_fgr_shift)); + save_item(NAME(m_vram_read_buffer)); + save_item(NAME(m_vmadd)); + + save_item(NAME(m_regs)); + + save_pointer(NAME(m_vram), SNES_VRAM_SIZE); + save_pointer(NAME(m_cgram), SNES_CGRAM_SIZE/2); + save_pointer(NAME(m_oam_ram), SNES_OAM_SIZE/2); +} + +void snes_ppu_device::device_reset() +{ +#if SNES_LAYER_DEBUG + memset(&m_debug_options, 0, sizeof(m_debug_options)); +#endif + + /* Inititialize registers/variables */ + m_update_windows = 1; + m_beam.latch_vert = 0; + m_beam.latch_horz = 0; + m_beam.current_vert = 0; + m_beam.last_visible_line = 225; /* TODO: PAL setting */ + m_mode = 0; + m_ppu1_version = 1; // 5C77 chip version number, read by STAT77, only '1' is known + m_ppu2_version = 3; // 5C78 chip version number, read by STAT78, only '2' & '3' encountered so far. + + m_cgram_address = 0; + m_read_ophct = 0; + m_read_opvct = 0; + + m_vmadd = 0; + + PPU_REG(VMAIN) = 0x80; + // what about other regs? + + /* Inititialize mosaic table */ + for (int j = 0; j < 16; j++) + { + for (int i = 0; i < 4096; i++) + m_mosaic_table[j][i] = (i / (j + 1)) * (j + 1); + } + + /* Init VRAM */ + memset(m_vram, 0, SNES_VRAM_SIZE); + + /* Init Palette RAM */ + memset((UINT8 *)m_cgram, 0, SNES_CGRAM_SIZE); + + /* Init oam RAM */ + memset((UINT8 *)m_oam_ram, 0xff, SNES_OAM_SIZE); + + m_stat78 = 0; + + // other initializations to 0 + memset(m_regs, 0, sizeof(m_regs)); + memset(m_oam_itemlist, 0, sizeof(m_oam_itemlist)); + memset(&m_oam, 0, sizeof(m_oam)); + memset(&m_mode7, 0, sizeof(m_mode7)); + + for (int i = 0; i < 2; i++) + { + m_scanlines[i].enable = 0; + m_scanlines[i].clip = 0; + memset(m_scanlines[i].buffer, 0, SNES_SCR_WIDTH); + memset(m_scanlines[i].priority, 0, SNES_SCR_WIDTH); + memset(m_scanlines[i].layer, 0, SNES_SCR_WIDTH); + memset(m_scanlines[i].blend_exception, 0, SNES_SCR_WIDTH); + } + + for (int i = 0; i < 6; i++) + { + m_layer[i].window1_enabled = 0; + m_layer[i].window1_invert = 0; + m_layer[i].window2_enabled = 0; + m_layer[i].window2_invert = 0; + m_layer[i].wlog_mask = 0; + m_layer[i].color_math = 0; + m_layer[i].charmap = 0; + m_layer[i].tilemap = 0; + m_layer[i].tilemap_size = 0; + m_layer[i].tile_size = 0; + m_layer[i].mosaic_enabled = 0; + m_layer[i].main_window_enabled = 0; + m_layer[i].sub_window_enabled = 0; + m_layer[i].main_bg_enabled = 0; + m_layer[i].sub_bg_enabled = 0; + m_layer[i].hoffs = 0; + m_layer[i].voffs = 0; + + memset(m_clipmasks[i], 0, SNES_SCR_WIDTH); + } + + for (int i = 0; i < ARRAY_LENGTH(m_oam_spritelist); i++) + { + m_oam_spritelist[i].tile = 0; + m_oam_spritelist[i].x = 0; + m_oam_spritelist[i].y = 0; + m_oam_spritelist[i].size = 0; + m_oam_spritelist[i].vflip = 0; + m_oam_spritelist[i].hflip = 0; + m_oam_spritelist[i].priority_bits = 0; + m_oam_spritelist[i].pal = 0; + m_oam_spritelist[i].height = 0; + m_oam_spritelist[i].width = 0; + } + + for (int i = 0; i < ARRAY_LENGTH(m_oam_tilelist); i++) + { + m_oam_tilelist[i].x = 0; + m_oam_tilelist[i].priority = 0; + m_oam_tilelist[i].pal = 0; + m_oam_tilelist[i].tileaddr = 0; + m_oam_tilelist[i].hflip = 0; + } +} + +/***************************************** + * get_bgcolor() + * + * Get the proper color (direct or from cgram) + *****************************************/ + +inline UINT16 snes_ppu_device::get_bgcolor( UINT8 direct_colors, UINT16 palette, UINT8 color ) +{ + UINT16 c = 0; + + if (direct_colors) + { + /* format is 0 | BBb00 | GGGg0 | RRRr0, HW confirms that the data is zero padded. */ + c = ((color & 0x07) << 2) | ((color & 0x38) << 4) | ((color & 0xc0) << 7); + c |= ((palette & 0x04) >> 1) | ((palette & 0x08) << 3) | ((palette & 0x10) << 8); + } + else + c = m_cgram[(palette + color) % FIXED_COLOUR]; + + return c; +} + +/***************************************** + * set_scanline_pixel() + * + * Store pixel color, priority, layer and + * color math exception (for OAM) in the + * proper scanline + *****************************************/ + +inline void snes_ppu_device::set_scanline_pixel( int screen, INT16 x, UINT16 color, UINT8 priority, UINT8 layer, int blend ) +{ + m_scanlines[screen].buffer[x] = color; + m_scanlines[screen].priority[x] = priority; + m_scanlines[screen].layer[x] = layer; + m_scanlines[screen].blend_exception[x] = blend; +} + +/************************************************************************************************* + * SNES tiles + * + * The way vram is accessed to draw tiles is basically the same for both BG and OAM tiles. Main + * differences are bit planes (variable for BG and fixed for OAM) and a few details of the scanline + * output (since OAM has neither mosaic, nor hires, nor direct colors). + * Hence, we use a common function to take data from VRAM and then we call specific routines for + * OAM vs BG vs Hi-Res BG tiles. + *************************************************************************************************/ + +/***************************************** + * draw_bgtile_lores() + * draw_bgtile_hires() + * draw_oamtile_() + * + * Check if a pixel is clipped or not, and + * copy it to the scanline buffer when + * appropriate. The actual way to perform + * such operations depends on the source + * (BG or OAM) and on the resolution (hires + * or lores) + *****************************************/ + +inline void snes_ppu_device::draw_bgtile_lores( UINT8 layer, INT16 ii, UINT8 colour, UINT16 pal, UINT8 direct_colors, UINT8 priority ) +{ + int screen; + UINT16 c; + + for (screen = SNES_MAINSCREEN; screen <= SNES_SUBSCREEN; screen++) + { + if (ii >= 0 && ii < SNES_SCR_WIDTH && m_scanlines[screen].enable) + { + if (m_scanlines[screen].priority[ii] <= priority) + { + UINT8 clr = colour; + UINT8 clipmask = m_clipmasks[layer][ii]; + +#if SNES_LAYER_DEBUG + if (m_debug_options.windows_disabled) + clipmask = 0xff; +#endif /* SNES_LAYER_DEBUG */ + + /* Clip to windows */ + if (m_scanlines[screen].clip) + clr &= clipmask; + + /* Only draw if we have a colour (0 == transparent) */ + if (clr) + { + c = get_bgcolor(direct_colors, pal, clr); + set_scanline_pixel(screen, ii, c, priority, layer, 0); + } + } + } + } +} + +inline void snes_ppu_device::draw_bgtile_hires( UINT8 layer, INT16 ii, UINT8 colour, UINT16 pal, UINT8 direct_colors, UINT8 priority ) +{ + int screen; + UINT16 c; + + for (screen = SNES_MAINSCREEN; screen <= SNES_SUBSCREEN; screen++) + { + // odd pixels to main screen, even pixels to sub screen + if (ii >= 0 && ii < (SNES_SCR_WIDTH << 1) && ((ii & 1) ^ screen) && m_scanlines[screen].enable) + { + if (m_scanlines[screen].priority[ii >> 1] <= priority) + { + UINT8 clr = colour; + UINT8 clipmask = m_clipmasks[layer][ii >> 1]; + +#if SNES_LAYER_DEBUG + if (m_debug_options.windows_disabled) + clipmask = 0xff; +#endif /* SNES_LAYER_DEBUG */ + + /* Clip to windows */ + if (m_scanlines[screen].clip) + clr &= clipmask; + + /* Only draw if we have a colour (0 == transparent) */ + if (clr) + { + c = get_bgcolor(direct_colors, pal, clr); + set_scanline_pixel(screen, ii >> 1, c, priority, layer, 0); + } + } + } + } +} + +inline void snes_ppu_device::draw_oamtile( INT16 ii, UINT8 colour, UINT16 pal, UINT8 priority ) +{ + int screen; + int blend; + UINT16 c; + INT16 pos = ii & 0x1ff; + + for (screen = SNES_MAINSCREEN; screen <= SNES_SUBSCREEN; screen++) + { + if (pos >= 0 && pos < SNES_SCR_WIDTH && m_scanlines[screen].enable) + { + UINT8 clr = colour; + UINT8 clipmask = m_clipmasks[SNES_OAM][pos]; + +#if SNES_LAYER_DEBUG + if (m_debug_options.windows_disabled) + clipmask = 0xff; +#endif /* SNES_LAYER_DEBUG */ + + /* Clip to windows */ + if (m_scanlines[screen].clip) + clr &= clipmask; + + /* Only draw if we have a colour (0 == transparent) */ + if (clr) + { + c = m_cgram[(pal + clr) % FIXED_COLOUR]; + blend = (pal + clr < 192) ? 1 : 0; + set_scanline_pixel(screen, pos, c, priority, SNES_OAM, blend); + } + } + } +} + +/***************************************** + * draw_tile() + * + * Draw 8 pixels from the expected tile + * by reading the color planes from vram + * and by calling the appropriate routine + * (depending on layer and resolution) + *****************************************/ + +inline void snes_ppu_device::draw_tile( UINT8 planes, UINT8 layer, UINT32 tileaddr, INT16 x, UINT8 priority, UINT8 flip, UINT8 direct_colors, UINT16 pal, UINT8 hires ) +{ + UINT8 plane[8]; + INT16 ii, jj; + int x_mos; + + for (ii = 0; ii < planes / 2; ii++) + { + plane[2 * ii + 0] = m_vram[(tileaddr + 16 * ii + 0) % SNES_VRAM_SIZE]; + plane[2 * ii + 1] = m_vram[(tileaddr + 16 * ii + 1) % SNES_VRAM_SIZE]; + } + + for (ii = x; ii < (x + 8); ii++) + { + UINT8 colour = 0; + UINT8 mosaic = m_layer[layer].mosaic_enabled; + +#if SNES_LAYER_DEBUG + if (m_debug_options.mosaic_disabled) + mosaic = 0; +#endif /* SNES_LAYER_DEBUG */ + + if (flip) + { + for (jj = 0; jj < planes; jj++) + colour |= BIT(plane[jj], ii - x) ? (1 << jj) : 0; + } + else + { + for (jj = 0; jj < planes; jj++) + colour |= BIT(plane[jj], 7 - (ii - x)) ? (1 << jj) : 0; + } + + if (layer == SNES_OAM) + draw_oamtile(ii, colour, pal, priority); + else if (!hires) + { + if (mosaic) + { + for (x_mos = 0; x_mos < (m_mosaic_size + 1); x_mos++) + draw_bgtile_lores(layer, ii + x_mos, colour, pal, direct_colors, priority); + ii += x_mos - 1; + } + else + draw_bgtile_lores(layer, ii, colour, pal, direct_colors, priority); + } + else /* hires */ + { + if (mosaic) + { + for (x_mos = 0; x_mos < (m_mosaic_size + 1); x_mos++) + draw_bgtile_hires(layer, ii + x_mos, colour, pal, direct_colors, priority); + ii += x_mos - 1; + } + else + draw_bgtile_hires(layer, ii, colour, pal, direct_colors, priority); + } + } +} + +/************************************************************************************************* + * SNES BG layers + * + * BG drawing theory of each scanline is quite easy: depending on the graphics Mode (0-7), there + * are up to 4 background layers. Pixels for each BG layer can have two different priorities. + * Depending on the line and on the BGHOFS and BGVOFS PPU registers, we first determine the tile + * address in m_vram (by determining x,y coord and tile size and by calling get_tmap_addr). + * Then, we load the correspondent data and we determine the tile properties: which priority to + * use, which palette etc. Finally, for each pixel of the tile appearing on screen, we check if + * the tile priority is higher than the BG/OAM already stored in that pixel for that line. If so + * we store the pixel in the buffer, otherwise we discard it. + * + * Of course, depending on the graphics Mode, it might be easier or harder to determine the proper + * tile address in vram (Mode 7 uses different registers, Mode 2, 4 and 6 uses OPT effect, etc.), + * but in general it works as described. + *************************************************************************************************/ + +/********************************************* + * get_tmap_addr() + * + * Find the address in VRAM of the tile (x,y) + *********************************************/ + +inline UINT32 snes_ppu_device::get_tmap_addr( UINT8 layer, UINT8 tile_size, UINT32 base, UINT32 x, UINT32 y ) +{ + UINT32 res = base; + x >>= (3 + tile_size); + y >>= (3 + tile_size); + + res += (m_layer[layer].tilemap_size & 2) ? ((y & 0x20) << ((m_layer[layer].tilemap_size & 1) ? 7 : 6)) : 0; + /* Scroll vertically */ + res += (y & 0x1f) << 6; + /* Offset horizontally */ + res += (m_layer[layer].tilemap_size & 1) ? ((x & 0x20) << 6) : 0; + /* Scroll horizontally */ + res += (x & 0x1f) << 1; + + return res; +} + +/********************************************* + * update_line() + * + * Update an entire line of tiles. + *********************************************/ + +inline void snes_ppu_device::update_line( UINT16 curline, UINT8 layer, UINT8 priority_b, UINT8 priority_a, UINT8 color_depth, UINT8 hires, UINT8 offset_per_tile, UINT8 direct_colors ) +{ + UINT32 tmap, tile, xoff, yoff, charaddr, addr; + UINT16 ii = 0, vflip, hflip, pal, pal_direct, tilemap; + UINT8 xscroll, priority; + INT8 yscroll; + int tile_incr = 0; + UINT16 opt_bit = (layer == SNES_BG1) ? 13 : (layer == SNES_BG2) ? 14 : 0; + UINT8 tile_size; + /* variables depending on color_depth */ + UINT8 color_planes = 2 << color_depth; + /* below we cheat to simplify the code: 8BPP should have 0 pal offset, not 0x100 (but we take care of this by later using pal % FIXED_COLOUR) */ + UINT8 color_shift = 2 << color_depth; + +#if SNES_LAYER_DEBUG + if (m_debug_options.bg_disabled[layer]) + return; +#endif /* SNES_LAYER_DEBUG */ + + m_scanlines[SNES_MAINSCREEN].enable = m_layer[layer].main_bg_enabled; + m_scanlines[SNES_SUBSCREEN].enable = m_layer[layer].sub_bg_enabled; + m_scanlines[SNES_MAINSCREEN].clip = m_layer[layer].main_window_enabled; + m_scanlines[SNES_SUBSCREEN].clip = m_layer[layer].sub_window_enabled; + + if (!m_scanlines[SNES_MAINSCREEN].enable && !m_scanlines[SNES_SUBSCREEN].enable) + return; + + /* Handle Mosaic effects */ + if (m_layer[layer].mosaic_enabled) + curline -= (curline % (m_mosaic_size + 1)); + + if ((m_interlace == 2) && !hires && !m_pseudo_hires) + curline /= 2; + + /* Find the size of the tiles (8x8 or 16x16) */ + tile_size = m_layer[layer].tile_size; + + /* Find scroll info */ + xoff = m_layer[layer].hoffs; + yoff = m_layer[layer].voffs; + + xscroll = xoff & ((1 << (3 + tile_size)) - 1); + + /* Jump to base map address */ + tmap = m_layer[layer].tilemap << 9; + charaddr = m_layer[layer].charmap << 13; + + while (ii < 256 + (8 << tile_size)) + { + // determine the horizontal position (Bishojo Janshi Suchi Pai & Desert Figther have tile_size & hires == 1) + UINT32 xpos = xoff + (ii << (tile_size * hires)); + UINT32 ypos = yoff + curline; + + if (offset_per_tile != SNES_OPT_NONE) + { + int opt_x = ii + (xoff & 7); + UINT32 haddr = 0, vaddr = 0; + UINT16 hval = 0, vval = 0; + + if (opt_x >= 8) + { + switch (offset_per_tile) + { + case SNES_OPT_MODE2: + case SNES_OPT_MODE6: + haddr = get_tmap_addr(SNES_BG3, m_layer[SNES_BG3].tile_size, m_layer[SNES_BG3].tilemap << 9, (opt_x - 8) + ((m_layer[SNES_BG3].hoffs & 0x3ff) & ~7), (m_layer[SNES_BG3].voffs & 0x3ff)); + vaddr = get_tmap_addr(SNES_BG3, m_layer[SNES_BG3].tile_size, m_layer[SNES_BG3].tilemap << 9, (opt_x - 8) + ((m_layer[SNES_BG3].hoffs & 0x3ff) & ~7), (m_layer[SNES_BG3].voffs & 0x3ff) + 8); + hval = m_vram[haddr % SNES_VRAM_SIZE] | (m_vram[(haddr + 1) % SNES_VRAM_SIZE] << 8); + vval = m_vram[vaddr % SNES_VRAM_SIZE] | (m_vram[(vaddr + 1) % SNES_VRAM_SIZE] << 8); + if (BIT(hval, opt_bit)) + xpos = opt_x + (hval & ~7); + if (BIT(vval, opt_bit)) + ypos = curline + vval; + break; + case SNES_OPT_MODE4: + haddr = get_tmap_addr(SNES_BG3, m_layer[SNES_BG3].tile_size, m_layer[SNES_BG3].tilemap << 9, (opt_x - 8) + ((m_layer[SNES_BG3].hoffs & 0x3ff) & ~7), (m_layer[SNES_BG3].voffs & 0x3ff)); + hval = m_vram[haddr % SNES_VRAM_SIZE] | (m_vram[(haddr + 1) % SNES_VRAM_SIZE] << 8); + if (BIT(hval, opt_bit)) + { + if (!BIT(hval, 15)) + xpos = opt_x + (hval & ~7); + else + ypos = curline + hval; + } + break; + } + } + } + + addr = get_tmap_addr(layer, tile_size, tmap, xpos, ypos); + + /* + Tilemap format + vhopppcc cccccccc + + v/h = Vertical/Horizontal flip this tile. + o = Tile priority. + ppp = Tile palette. The number of entries in the palette depends on the Mode and the BG. + cccccccccc = Tile number. + */ + tilemap = m_vram[addr % SNES_VRAM_SIZE] | (m_vram[(addr + 1) % SNES_VRAM_SIZE] << 8); + vflip = BIT(tilemap, 15); + hflip = BIT(tilemap, 14); + priority = BIT(tilemap, 13) ? priority_a : priority_b; + pal_direct = ((tilemap & 0x1c00) >> 8); + tile = tilemap & 0x03ff; + + pal = ((pal_direct >> 2) << color_shift); + + /* Mode 0 palettes are layer specific */ + if (m_mode == 0) + { + pal += (layer << 5); + } + +#if SNES_LAYER_DEBUG + /* if we want to draw only one of the priorities of this layer */ + if (((m_debug_options.select_pri[layer] & 0x01) && (priority == priority_a)) || + ((m_debug_options.select_pri[layer] & 0x02) && (priority == priority_b))) + { + if (!hires && tile_size) + ii += 16; + else + ii += 8; + continue; + } +#endif /* SNES_LAYER_DEBUG */ + + /* figure out which line to draw */ + yscroll = ypos & ((8 << tile_size) - 1); + + if (tile_size) + if (BIT(yscroll, 3) != vflip) + tile += 16; + + if (yscroll > 7) + yscroll &= 7; + + if (vflip) + yscroll = 7 - yscroll; + + yscroll <<= 1; + + /* if we have to draw 16 pixels, set tile_incr and adjust tile for horizontal flip */ + if (tile_size || hires) + { + if (hflip) + { + tile += 1; + tile_incr = -1; // next 8 pixels from previous tile (because of hflip) + } + else + tile_incr = 1; // next 8 pixels from next tile + } + + if (hires) + { + /* draw 16 pixels (the routine will automatically send half of them to the mainscreen scanline and half to the subscreen one) */ + draw_tile(color_planes, layer, charaddr + (((tile + 0) & 0x3ff) * 8 * color_planes) + yscroll, (ii - xscroll) * 2, priority, hflip, direct_colors, direct_colors ? pal_direct : pal, hires); + draw_tile(color_planes, layer, charaddr + (((tile + tile_incr) & 0x3ff) * 8 * color_planes) + yscroll, (ii - xscroll) * 2 + 8, priority, hflip, direct_colors, direct_colors ? pal_direct : pal, hires); + ii += 8; + } + else + { + draw_tile(color_planes, layer, charaddr + ((tile & 0x3ff) * 8 * color_planes) + yscroll, ii - xscroll, priority, hflip, direct_colors, direct_colors ? pal_direct : pal, hires); + ii += 8; + + if (tile_size) + { + draw_tile(color_planes, layer, charaddr + (((tile + tile_incr) & 0x3ff) * 8 * color_planes) + yscroll, ii - xscroll, priority, hflip, direct_colors, direct_colors ? pal_direct : pal, hires); + ii += 8; + } + } + } +} + + +/********************************************* + * update_line_mode7() + * + * Update an entire line of mode7 tiles. + *********************************************/ + +#define MODE7_CLIP(x) (((x) & 0x2000) ? ((x) | ~0x03ff) : ((x) & 0x03ff)) + +void snes_ppu_device::update_line_mode7( UINT16 curline, UINT8 layer, UINT8 priority_b, UINT8 priority_a ) +{ + UINT32 tiled; + INT16 ma, mb, mc, md; + INT32 xc, yc, tx, ty, sx, sy, hs, vs, xpos, xdir, x0, y0; + UINT8 priority = priority_b; + UINT8 colour = 0; + UINT16 *mosaic_x, *mosaic_y; + UINT16 c; + int screen; + +#if SNES_LAYER_DEBUG + if (m_debug_options.bg_disabled[layer]) + return; +#endif /* SNES_LAYER_DEBUG */ + + m_scanlines[SNES_MAINSCREEN].enable = m_layer[layer].main_bg_enabled; + m_scanlines[SNES_SUBSCREEN].enable = m_layer[layer].sub_bg_enabled; + m_scanlines[SNES_MAINSCREEN].clip = m_layer[layer].main_window_enabled; + m_scanlines[SNES_SUBSCREEN].clip = m_layer[layer].sub_window_enabled; + + if (!m_scanlines[SNES_MAINSCREEN].enable && !m_scanlines[SNES_SUBSCREEN].enable) + return; + + ma = m_mode7.matrix_a; + mb = m_mode7.matrix_b; + mc = m_mode7.matrix_c; + md = m_mode7.matrix_d; + xc = m_mode7.origin_x; + yc = m_mode7.origin_y; + hs = m_mode7.hor_offset; + vs = m_mode7.ver_offset; + + /* Sign extend */ + xc <<= 19; + xc >>= 19; + yc <<= 19; + yc >>= 19; + hs <<= 19; + hs >>= 19; + vs <<= 19; + vs >>= 19; + + /* Vertical flip */ + if (m_mode7.vflip) + sy = 255 - curline; + else + sy = curline; + + /* Horizontal flip */ + if (m_mode7.hflip) + { + xpos = 255; + xdir = -1; + } + else + { + xpos = 0; + xdir = 1; + } + + /* MOSAIC - to be verified */ + if (layer == SNES_BG2) // BG2 use two different bits for horizontal and vertical mosaic + { + mosaic_x = m_mosaic_table[m_layer[SNES_BG2].mosaic_enabled ? m_mosaic_size : 0]; + mosaic_y = m_mosaic_table[m_layer[SNES_BG1].mosaic_enabled ? m_mosaic_size : 0]; + } + else // BG1 works as usual + { + mosaic_x = m_mosaic_table[m_layer[SNES_BG1].mosaic_enabled ? m_mosaic_size : 0]; + mosaic_y = m_mosaic_table[m_layer[SNES_BG1].mosaic_enabled ? m_mosaic_size : 0]; + } + +#if SNES_LAYER_DEBUG + if (m_debug_options.mosaic_disabled) + { + mosaic_x = m_mosaic_table[0]; + mosaic_y = m_mosaic_table[0]; + } +#endif /* SNES_LAYER_DEBUG */ + + /* Let's do some mode7 drawing huh? */ + /* These can be computed only once, since they do not depend on sx */ + x0 = ((ma * MODE7_CLIP(hs - xc)) & ~0x3f) + ((mb * mosaic_y[sy]) & ~0x3f) + ((mb * MODE7_CLIP(vs - yc)) & ~0x3f) + (xc << 8); + y0 = ((mc * MODE7_CLIP(hs - xc)) & ~0x3f) + ((md * mosaic_y[sy]) & ~0x3f) + ((md * MODE7_CLIP(vs - yc)) & ~0x3f) + (yc << 8); + + for (sx = 0; sx < 256; sx++, xpos += xdir) + { + tx = (x0 + (ma * mosaic_x[sx])) >> 8; + ty = (y0 + (mc * mosaic_x[sx])) >> 8; + + switch (m_mode7.repeat) + { + case 0x00: /* Repeat if outside screen area */ + case 0x01: /* Repeat if outside screen area */ + tx &= 0x3ff; + ty &= 0x3ff; + tiled = m_vram[((((tx >> 3) & 0x7f) + (((ty >> 3) & 0x7f) * 128)) * 2) % SNES_VRAM_SIZE] << 7; + colour = m_vram[(tiled + ((tx & 0x07) * 2) + ((ty & 0x07) * 16) + 1) % SNES_VRAM_SIZE]; + break; + case 0x02: /* Single colour backdrop screen if outside screen area */ + if ((tx >= 0) && (tx < 1024) && (ty >= 0) && (ty < 1024)) + { + tiled = m_vram[((((tx >> 3) & 0x7f) + (((ty >> 3) & 0x7f) * 128)) * 2) % SNES_VRAM_SIZE] << 7; + colour = m_vram[(tiled + ((tx & 0x07) * 2) + ((ty & 0x07) * 16) + 1) % SNES_VRAM_SIZE]; + } + else + colour = 0; + break; + case 0x03: /* Character 0x00 repeat if outside screen area */ + if ((tx >= 0) && (tx < 1024) && (ty >= 0) && (ty < 1024)) + tiled = m_vram[((((tx >> 3) & 0x7f) + (((ty >> 3) & 0x7f) * 128)) * 2) % SNES_VRAM_SIZE] << 7; + else + tiled = 0; + + colour = m_vram[(tiled + ((tx & 0x07) * 2) + ((ty & 0x07) * 16) + 1) % SNES_VRAM_SIZE]; + break; + } + + /* The last bit is for priority in EXTBG mode (used only for BG2) */ + if (layer == SNES_BG2) + { + priority = ((colour & 0x80) >> 7) ? priority_a : priority_b; + colour &= 0x7f; + +#if SNES_LAYER_DEBUG + /* if we want to draw only one of the priorities of this layer */ + if (((m_debug_options.select_pri[layer] & 0x01) && (priority == priority_a)) || + ((m_debug_options.select_pri[layer] & 0x02) && (priority == priority_b))) + continue; +#endif /* SNES_LAYER_DEBUG */ + } + + for (screen = SNES_MAINSCREEN; screen <= SNES_SUBSCREEN; screen++) + { + if (m_scanlines[screen].enable) + { + UINT8 clr = colour; + UINT8 clipmask = m_clipmasks[layer][xpos]; + +#if SNES_LAYER_DEBUG + if (m_debug_options.windows_disabled) + clipmask = 0xff; +#endif /* SNES_LAYER_DEBUG */ + + /* Clip to windows */ + if (m_scanlines[screen].clip) + clr &= clipmask; + + /* Draw pixel if appropriate */ + if (m_scanlines[screen].priority[xpos] <= priority && clr > 0) + { + /* Direct select, but only outside EXTBG! */ + // Direct color format is: 0 | BB000 | GGG00 | RRR00, HW confirms that the data is zero padded. + // In other words, like normal direct color, with pal = 0 + c = get_bgcolor(m_direct_color && layer == SNES_BG1, 0, clr); + set_scanline_pixel(screen, xpos, c, priority, layer, 0); + } + } + } + } +} + +/************************************************************************************************* + * SNES Sprites + * + * 1. First of all: sprites are drawn one line in advance. We emulate this by caching the + * starting vram address, the sprite size and the "name select" at each line, and by using + * them the next line to output the proper sprites - see update_obsel. + * + * 2. Each line can select its sprites among 128 available ones in oam_ram, hence we start + * by creating a list of the available objects (each one with its x,y coordinate, its size, + * its tile address, etc.) - see oam_list_build. + * + * 3. Next, we start finding out which sprites will appear in the line: starting from + * FirstSprite, we count 32 OBJs which intersect our line and we store their indexes in the + * oam_itemlist array (if more than 32 sprites intersect our line, we set the Range Over + * flag); then, selecting among these sprites, we count 34 8x8 tiles which are visible + * in our line (i.e. whose x coord is between -size and 256) and we store the corresponding + * coordinates/priorities/palettes/etc. in the oam_tilelist array (if more than 34 tiles would + * appear on screen, we set the Time Over flag). + * Notice that when we populate oam_tilelist, we proceed from oam_itemlist[31] (or from the last + * item which intersects the scanline), towards oam_itemlist[0], i.e. the higher tiles (say + * oam_tilelist[34], or the last tile which appear on screen) will contain FirstSprite object, + * or the sprites with closer index to FirstSprite which get displayed. This will play an + * important role for sprite priority - see update_objects_rto. + * + * 4. All the above happens at the beginning of each VIDEO_UPDATE. When we finally draw the + * scanline, we pass through the oam_tilelist and we store the displayed pixels in our scanline + * buffer. Notice that, for each pixel of a SNES sprite, only the priority of the topmost sprite + * is tested against the priority of the BG pixel (because FirstSprite is on top of FirstSprite+1, + * which is on top of FirstSprite+2, etc., and therefore other sprites are already covered by the + * topmost one). To emulate this, we draw each tile over the previous ones no matter what + * priorities are (differently from what we did with BGs): in the end, we will have in each pixel z + * its topmost sprite and scanline.priority[z] will be the topmost sprite priority as expected. + * Of course, sprite drawing must happen before BG drawing, so that afterwords BG pixels properly + * test their priority with the one of the correct sprite - see update_objects. + *************************************************************************************************/ + + +/********************************************* + * update_obsel() + * + * Update sprite settings for next line. + *********************************************/ + +void snes_ppu_device::update_obsel( void ) +{ + m_layer[SNES_OAM].charmap = m_oam.next_charmap; + m_oam.name_select = m_oam.next_name_select; + + if (m_oam.size != m_oam.next_size) + { + m_oam.size = m_oam.next_size; + m_update_oam_list = 1; + } +} + +/********************************************* + * oam_list_build() + * + * Build a list of the available obj in OAM ram. + *********************************************/ + +void snes_ppu_device::oam_list_build( void ) +{ + UINT8 *oamram = (UINT8 *)m_oam_ram; + INT16 oam = 0x1ff; + UINT16 oam_extra = oam + 0x20; + UINT16 extra = 0; + int ii; + + m_update_oam_list = 0; // eventually, we can optimize the code by only calling this function when there is a change in size + + for (ii = 127; ii >= 0; ii--) + { + if (((ii + 1) % 4) == 0) + extra = oamram[oam_extra--]; + + m_oam_spritelist[ii].vflip = (oamram[oam] & 0x80) >> 7; + m_oam_spritelist[ii].hflip = (oamram[oam] & 0x40) >> 6; + m_oam_spritelist[ii].priority_bits = (oamram[oam] & 0x30) >> 4; + m_oam_spritelist[ii].pal = 128 + ((oamram[oam] & 0x0e) << 3); + m_oam_spritelist[ii].tile = (oamram[oam--] & 0x1) << 8; + m_oam_spritelist[ii].tile |= oamram[oam--]; + m_oam_spritelist[ii].y = oamram[oam--] + 1; + m_oam_spritelist[ii].x = oamram[oam--]; + m_oam_spritelist[ii].size = (extra & 0x80) >> 7; + extra <<= 1; + m_oam_spritelist[ii].x |= ((extra & 0x80) << 1); + extra <<= 1; + + m_oam_spritelist[ii].y *= m_obj_interlace; + m_oam_spritelist[ii].y &= 0x1ff; + + m_oam_spritelist[ii].x &= 0x1ff; + + /* Determine object size */ + switch (m_oam.size) + { + case 0: /* 8x8 or 16x16 */ + m_oam_spritelist[ii].width = m_oam_spritelist[ii].size ? 2 : 1; + m_oam_spritelist[ii].height = m_oam_spritelist[ii].size ? 2 : 1; + break; + case 1: /* 8x8 or 32x32 */ + m_oam_spritelist[ii].width = m_oam_spritelist[ii].size ? 4 : 1; + m_oam_spritelist[ii].height = m_oam_spritelist[ii].size ? 4 : 1; + break; + case 2: /* 8x8 or 64x64 */ + m_oam_spritelist[ii].width = m_oam_spritelist[ii].size ? 8 : 1; + m_oam_spritelist[ii].height = m_oam_spritelist[ii].size ? 8 : 1; + break; + case 3: /* 16x16 or 32x32 */ + m_oam_spritelist[ii].width = m_oam_spritelist[ii].size ? 4 : 2; + m_oam_spritelist[ii].height = m_oam_spritelist[ii].size ? 4 : 2; + break; + case 4: /* 16x16 or 64x64 */ + m_oam_spritelist[ii].width = m_oam_spritelist[ii].size ? 8 : 2; + m_oam_spritelist[ii].height = m_oam_spritelist[ii].size ? 8 : 2; + break; + case 5: /* 32x32 or 64x64 */ + m_oam_spritelist[ii].width = m_oam_spritelist[ii].size ? 8 : 4; + m_oam_spritelist[ii].height = m_oam_spritelist[ii].size ? 8 : 4; + break; + case 6: /* undocumented: 16x32 or 32x64 */ + m_oam_spritelist[ii].width = m_oam_spritelist[ii].size ? 4 : 2; + m_oam_spritelist[ii].height = m_oam_spritelist[ii].size ? 8 : 4; + if (m_obj_interlace && !m_oam_spritelist[ii].size) + m_oam_spritelist[ii].height = 2; + break; + case 7: /* undocumented: 16x32 or 32x32 */ + m_oam_spritelist[ii].width = m_oam_spritelist[ii].size ? 4 : 2; + m_oam_spritelist[ii].height = m_oam_spritelist[ii].size ? 4 : 4; + if (m_obj_interlace && !m_oam_spritelist[ii].size) + m_oam_spritelist[ii].height = 2; + break; + default: + /* we should never enter here... */ + logerror("Object size unsupported: %d\n", m_oam.size); + break; + } + } +} + +/********************************************* + * is_sprite_on_scanline() + * + * Check if a given sprites intersect current + * scanline + *********************************************/ + +int snes_ppu_device::is_sprite_on_scanline( UINT16 curline, UINT8 sprite ) +{ + //if sprite is entirely offscreen and doesn't wrap around to the left side of the screen, + //then it is not counted. this *should* be 256, and not 255, even though dot 256 is offscreen. + int spr_height = (m_oam_spritelist[sprite].height << 3); + + if (m_oam_spritelist[sprite].x > 256 && (m_oam_spritelist[sprite].x + (m_oam_spritelist[sprite].width << 3) - 1) < 512) + return 0; + + if (curline >= m_oam_spritelist[sprite].y && curline < (m_oam_spritelist[sprite].y + spr_height)) + return 1; + + if ((m_oam_spritelist[sprite].y + spr_height) >= 256 && curline < ((m_oam_spritelist[sprite].y + spr_height) & 255)) + return 1; + + return 0; +} + +/********************************************* + * update_objects_rto() + * + * Determine which OBJs will be drawn on this + * scanline. + *********************************************/ + +void snes_ppu_device::update_objects_rto( UINT16 curline ) +{ + int ii, jj, active_sprite; + UINT8 range_over, time_over; + INT8 xs, ys; + UINT8 line; + UINT8 height, width, vflip, hflip, priority, pal; + UINT16 tile; + INT16 x, y; + UINT32 name_sel = 0; + + oam_list_build(); + + /* initialize counters */ + range_over = 0; + time_over = 0; + + /* setup the proper line */ + curline /= m_interlace; + curline *= m_obj_interlace; + + /* reset the list of first 32 objects which intersect current scanline */ + memset(m_oam_itemlist, 0xff, 32); + + /* populate the list of 32 objects */ + for (ii = 0; ii < 128; ii++) + { + active_sprite = (ii + m_oam.first_sprite) & 0x7f; + + if (!is_sprite_on_scanline(curline, active_sprite)) + continue; + + if (range_over++ >= 32) + break; + + m_oam_itemlist[range_over - 1] = active_sprite; + } + + /* reset the list of first 34 tiles to be drawn */ + for (ii = 0; ii < 34; ii++) + m_oam_tilelist[ii].tileaddr = 0xffff; + + /* populate the list of 34 tiles */ + for (ii = 31; ii >= 0; ii--) + { + if (m_oam_itemlist[ii] == 0xff) + continue; + + active_sprite = m_oam_itemlist[ii]; + + tile = m_oam_spritelist[active_sprite].tile; + x = m_oam_spritelist[active_sprite].x; + y = m_oam_spritelist[active_sprite].y; + height = m_oam_spritelist[active_sprite].height; + width = m_oam_spritelist[active_sprite].width; + vflip = m_oam_spritelist[active_sprite].vflip; + hflip = m_oam_spritelist[active_sprite].hflip; + priority = m_oam_spritelist[active_sprite].priority_bits; + pal = m_oam_spritelist[active_sprite].pal; + + /* Adjust y, if past maximum position (for sprites which overlap between top & bottom) */ + if (y >= (0x100 - 16) * m_interlace) + y -= (0x100) * m_interlace; + + if (curline >= y && curline < (y + (height << 3))) + { + /* Only objects using tiles over 255 use name select */ + name_sel = (tile < 256) ? 0 : m_oam.name_select; + + ys = (curline - y) >> 3; + line = (curline - y) % 8; + if (vflip) + { + ys = height - ys - 1; + line = 7 - line; + } + line <<= 1; + tile <<= 5; + + for (jj = 0; jj < width; jj++) + { + INT16 xx = (x + (jj << 3)) & 0x1ff; + + if (x != 256 && xx >= 256 && (xx + 7) < 512) + continue; + + if (time_over++ >= 34) + break; + + xs = (hflip) ? (width - 1 - jj) : jj; + m_oam_tilelist[time_over - 1].tileaddr = name_sel + tile + table_obj_offset[ys][xs] + line; + m_oam_tilelist[time_over - 1].hflip = hflip; + m_oam_tilelist[time_over - 1].x = xx; + m_oam_tilelist[time_over - 1].pal = pal; + m_oam_tilelist[time_over - 1].priority = priority; + } + } + } + + /* set Range Over flag if necessary */ + if (range_over > 32) + m_stat77 |= 0x40; + + /* set Time Over flag if necessary */ + if (time_over > 34) + m_stat77 |= 0x80; +} + +/********************************************* + * update_objects() + * + * Update an entire line of sprites. + *********************************************/ + +void snes_ppu_device::update_objects( UINT8 priority_oam0, UINT8 priority_oam1, UINT8 priority_oam2, UINT8 priority_oam3 ) +{ + UINT8 pri, priority[4]; + UINT32 charaddr; + int ii; + +#if SNES_LAYER_DEBUG + if (m_debug_options.bg_disabled[SNES_OAM]) + return; +#endif /* SNES_LAYER_DEBUG */ + + m_scanlines[SNES_MAINSCREEN].enable = m_layer[SNES_OAM].main_bg_enabled; + m_scanlines[SNES_SUBSCREEN].enable = m_layer[SNES_OAM].sub_bg_enabled; + m_scanlines[SNES_MAINSCREEN].clip = m_layer[SNES_OAM].main_window_enabled; + m_scanlines[SNES_SUBSCREEN].clip = m_layer[SNES_OAM].sub_window_enabled; + + if (!m_scanlines[SNES_MAINSCREEN].enable && !m_scanlines[SNES_SUBSCREEN].enable) + return; + + charaddr = m_layer[SNES_OAM].charmap << 13; + + priority[0] = priority_oam0; + priority[1] = priority_oam1; + priority[2] = priority_oam2; + priority[3] = priority_oam3; + + /* finally draw the tiles from the tilelist */ + for (ii = 0; ii < 34; ii++) + { + int tile = ii; +#if SNES_LAYER_DEBUG + if (m_debug_options.sprite_reversed) + tile = 33 - ii; +#endif /* SNES_LAYER_DEBUG */ + + if (m_oam_tilelist[tile].tileaddr == 0xffff) + continue; + + pri = priority[m_oam_tilelist[tile].priority]; + +#if SNES_LAYER_DEBUG + if (m_debug_options.select_pri[SNES_OAM]) + { + int oam_draw = m_debug_options.select_pri[SNES_OAM] - 1; + if (oam_draw != m_oam_tilelist[tile].priority) + continue; + } +#endif /* SNES_LAYER_DEBUG */ + + /* OAM tiles have fixed planes (4), no direct color and no hires, but otherwise work the same as BG ones */ + draw_tile(4, SNES_OAM, charaddr + m_oam_tilelist[tile].tileaddr, m_oam_tilelist[tile].x, pri, m_oam_tilelist[tile].hflip, 0, m_oam_tilelist[tile].pal, 0); + } +} + + +/********************************************* + * snes_update_mode_X() + * + * Update Mode X line. + *********************************************/ + +void snes_ppu_device::update_mode_0( UINT16 curline ) +{ +#if SNES_LAYER_DEBUG + if (m_debug_options.mode_disabled[0]) + return; +#endif /* SNES_LAYER_DEBUG */ + + update_objects(3, 6, 9, 12); + update_line(curline, SNES_BG1, 8, 11, SNES_COLOR_DEPTH_2BPP, 0, SNES_OPT_NONE, 0); + update_line(curline, SNES_BG2, 7, 10, SNES_COLOR_DEPTH_2BPP, 0, SNES_OPT_NONE, 0); + update_line(curline, SNES_BG3, 2, 5, SNES_COLOR_DEPTH_2BPP, 0, SNES_OPT_NONE, 0); + update_line(curline, SNES_BG4, 1, 4, SNES_COLOR_DEPTH_2BPP, 0, SNES_OPT_NONE, 0); +} + +void snes_ppu_device::update_mode_1( UINT16 curline ) +{ +#if SNES_LAYER_DEBUG + if (m_debug_options.mode_disabled[1]) + return; +#endif /* SNES_LAYER_DEBUG */ + + if (!m_bg3_priority_bit) + { + update_objects(2, 4, 7, 10); + update_line(curline, SNES_BG1, 6, 9, SNES_COLOR_DEPTH_4BPP, 0, SNES_OPT_NONE, 0); + update_line(curline, SNES_BG2, 5, 8, SNES_COLOR_DEPTH_4BPP, 0, SNES_OPT_NONE, 0); + update_line(curline, SNES_BG3, 1, 3, SNES_COLOR_DEPTH_2BPP, 0, SNES_OPT_NONE, 0); + } + else + { + update_objects(2, 3, 6, 9); + update_line(curline, SNES_BG1, 5, 8, SNES_COLOR_DEPTH_4BPP, 0, SNES_OPT_NONE, 0); + update_line(curline, SNES_BG2, 4, 7, SNES_COLOR_DEPTH_4BPP, 0, SNES_OPT_NONE, 0); + update_line(curline, SNES_BG3, 1, 10, SNES_COLOR_DEPTH_2BPP, 0, SNES_OPT_NONE, 0); + } +} + +void snes_ppu_device::update_mode_2( UINT16 curline ) +{ +#if SNES_LAYER_DEBUG + if (m_debug_options.mode_disabled[2]) + return; +#endif /* SNES_LAYER_DEBUG */ + + update_objects(2, 4, 6, 8); + update_line(curline, SNES_BG1, 3, 7, SNES_COLOR_DEPTH_4BPP, 0, SNES_OPT_MODE2, 0); + update_line(curline, SNES_BG2, 1, 5, SNES_COLOR_DEPTH_4BPP, 0, SNES_OPT_MODE2, 0); +} + +void snes_ppu_device::update_mode_3( UINT16 curline ) +{ +#if SNES_LAYER_DEBUG + if (m_debug_options.mode_disabled[3]) + return; +#endif /* SNES_LAYER_DEBUG */ + + update_objects(2, 4, 6, 8); + update_line(curline, SNES_BG1, 3, 7, SNES_COLOR_DEPTH_8BPP, 0, SNES_OPT_NONE, m_direct_color); + update_line(curline, SNES_BG2, 1, 5, SNES_COLOR_DEPTH_4BPP, 0, SNES_OPT_NONE, 0); +} + +void snes_ppu_device::update_mode_4( UINT16 curline ) +{ +#if SNES_LAYER_DEBUG + if (m_debug_options.mode_disabled[4]) + return; +#endif /* SNES_LAYER_DEBUG */ + + update_objects(2, 4, 6, 8); + update_line(curline, SNES_BG1, 3, 7, SNES_COLOR_DEPTH_8BPP, 0, SNES_OPT_MODE4, m_direct_color); + update_line(curline, SNES_BG2, 1, 5, SNES_COLOR_DEPTH_2BPP, 0, SNES_OPT_MODE4, 0); +} + +void snes_ppu_device::update_mode_5( UINT16 curline ) +{ +#if SNES_LAYER_DEBUG + if (m_debug_options.mode_disabled[5]) + return; +#endif /* SNES_LAYER_DEBUG */ + + update_objects(2, 4, 6, 8); + update_line(curline, SNES_BG1, 3, 7, SNES_COLOR_DEPTH_4BPP, 1, SNES_OPT_NONE, 0); + update_line(curline, SNES_BG2, 1, 5, SNES_COLOR_DEPTH_2BPP, 1, SNES_OPT_NONE, 0); +} + +void snes_ppu_device::update_mode_6( UINT16 curline ) +{ +#if SNES_LAYER_DEBUG + if (m_debug_options.mode_disabled[6]) + return; +#endif /* SNES_LAYER_DEBUG */ + + update_objects(1, 3, 4, 6); + update_line(curline, SNES_BG1, 2, 5, SNES_COLOR_DEPTH_4BPP, 1, SNES_OPT_MODE6, 0); +} + +void snes_ppu_device::update_mode_7( UINT16 curline ) +{ +#if SNES_LAYER_DEBUG + if (m_debug_options.mode_disabled[7]) + return; +#endif /* SNES_LAYER_DEBUG */ + + if (!m_mode7.extbg) + { + update_objects(1, 3, 4, 5); + update_line_mode7(curline, SNES_BG1, 2, 2); + } + else + { + update_objects(2, 4, 6, 7); + update_line_mode7(curline, SNES_BG1, 3, 3); + update_line_mode7(curline, SNES_BG2, 1, 5); + } +} + +/********************************************* + * snes_draw_screens() + * + * Draw the whole screen (Mode 0 -> 7). + *********************************************/ + +void snes_ppu_device::draw_screens( UINT16 curline ) +{ + switch (m_mode) + { + case 0: update_mode_0(curline); break; /* Mode 0 */ + case 1: update_mode_1(curline); break; /* Mode 1 */ + case 2: update_mode_2(curline); break; /* Mode 2 - Supports offset per tile */ + case 3: update_mode_3(curline); break; /* Mode 3 - Supports direct colour */ + case 4: update_mode_4(curline); break; /* Mode 4 - Supports offset per tile and direct colour */ + case 5: update_mode_5(curline); break; /* Mode 5 - Supports hires */ + case 6: update_mode_6(curline); break; /* Mode 6 - Supports offset per tile and hires */ + case 7: update_mode_7(curline); break; /* Mode 7 - Supports direct colour */ + } +} + +/********************************************* + * update_windowmasks() + * + * An example of how windows work: + * Win1: ...#####...... + * Win2: ......#####... + * IN OUT + * OR: ...########... ###........### + * AND: ......##...... ######..###### + * XOR: ...###..###... ###...##...### + * XNOR: ###...##...### ...###..###... + *********************************************/ + +void snes_ppu_device::update_windowmasks( void ) +{ + UINT16 ii, jj; + INT8 w1, w2; + + m_update_windows = 0; /* reset the flag */ + + for (ii = 0; ii < SNES_SCR_WIDTH; ii++) + { + /* update bg 1, 2, 3, 4, obj & color windows */ + /* jj = layer */ + for (jj = 0; jj < 6; jj++) + { + m_clipmasks[jj][ii] = 0xff; /* let's start from un-masked */ + w1 = w2 = -1; + + if (m_layer[jj].window1_enabled) + { + /* Default to mask area inside */ + if ((ii < m_window1_left) || (ii > m_window1_right)) + w1 = 0; + else + w1 = 1; + + /* If mask area is outside then swap */ + if (m_layer[jj].window1_invert) + w1 = !w1; + } + + if (m_layer[jj].window2_enabled) + { + if ((ii < m_window2_left) || (ii > m_window2_right)) + w2 = 0; + else + w2 = 1; + if (m_layer[jj].window2_invert) + w2 = !w2; + } + + /* mask if the appropriate expression is true */ + if (w1 >= 0 && w2 >= 0) + { + switch (m_layer[jj].wlog_mask) + { + case 0x00: /* OR */ + m_clipmasks[jj][ii] = (w1 | w2) ? 0x00 : 0xff; + break; + case 0x01: /* AND */ + m_clipmasks[jj][ii] = (w1 & w2) ? 0x00 : 0xff; + break; + case 0x02: /* XOR */ + m_clipmasks[jj][ii] = (w1 ^ w2) ? 0x00 : 0xff; + break; + case 0x03: /* XNOR */ + m_clipmasks[jj][ii] = !(w1 ^ w2) ? 0x00 : 0xff; + break; + } + } + else if (w1 >= 0) + m_clipmasks[jj][ii] = w1 ? 0x00 : 0xff; + else if (w2 >= 0) + m_clipmasks[jj][ii] = w2 ? 0x00 : 0xff; + } + } +} + +/********************************************* + * update_offsets() + * + * Update the offsets with the latest changes. + * This is currently unused, but it could + * possibly be handy for some minor optimization + *********************************************/ + +void snes_ppu_device::update_offsets( void ) +{ + int ii; + for (ii = 0; ii < 4; ii++) + { + } + m_update_offsets = 0; +} + +/***************************************** + * draw_blend() + * + * Routine for additive/subtractive blending + * between the main and sub screens, i.e. + * color math. + *****************************************/ + +inline void snes_ppu_device::draw_blend( UINT16 offset, UINT16 *colour, UINT8 prevent_color_math, UINT8 black_pen_clip, int switch_screens ) +{ +#if SNES_LAYER_DEBUG + if (m_debug_options.colormath_disabled) + return; +#endif /* SNES_LAYER_DEBUG */ + + /* when color math is applied to subscreen pixels, the blending depends on the blending used by the previous mainscreen + pixel, except for subscreen pixel 0 which has no previous mainscreen pixel, see comments in refresh_scanline */ + if (switch_screens && offset > 0) + offset -= 1; + + if ((black_pen_clip == SNES_CLIP_ALWAYS) || + (black_pen_clip == SNES_CLIP_IN && m_clipmasks[SNES_COLOR][offset]) || + (black_pen_clip == SNES_CLIP_OUT && !m_clipmasks[SNES_COLOR][offset])) + *colour = 0; //clip to black before color math + + if (prevent_color_math == SNES_CLIP_ALWAYS) // blending mode 3 == always OFF + return; + + if ((prevent_color_math == SNES_CLIP_NEVER) || + (prevent_color_math == SNES_CLIP_IN && !m_clipmasks[SNES_COLOR][offset]) || + (prevent_color_math == SNES_CLIP_OUT && m_clipmasks[SNES_COLOR][offset])) + { + UINT16 r, g, b; + struct SNES_SCANLINE *subscreen; + int clip_max = 0; // if add then clip to 0x1f, if sub then clip to 0 + +#if SNES_LAYER_DEBUG + /* Toggle drawing of SNES_SUBSCREEN or SNES_MAINSCREEN */ + if (m_debug_options.draw_subscreen) + { + subscreen = switch_screens ? &m_scanlines[SNES_SUBSCREEN] : &m_scanlines[SNES_MAINSCREEN]; + } + else +#endif /* SNES_LAYER_DEBUG */ + { + subscreen = switch_screens ? &m_scanlines[SNES_MAINSCREEN] : &m_scanlines[SNES_SUBSCREEN]; + } + + if (m_sub_add_mode) /* SNES_SUBSCREEN*/ + { + if (!BIT(m_color_modes, 7)) + { + /* 0x00 add */ + r = (*colour & 0x1f) + (subscreen->buffer[offset] & 0x1f); + g = ((*colour & 0x3e0) >> 5) + ((subscreen->buffer[offset] & 0x3e0) >> 5); + b = ((*colour & 0x7c00) >> 10) + ((subscreen->buffer[offset] & 0x7c00) >> 10); + clip_max = 1; + } + else + { + /* 0x80 sub */ + r = (*colour & 0x1f) - (subscreen->buffer[offset] & 0x1f); + g = ((*colour & 0x3e0) >> 5) - ((subscreen->buffer[offset] & 0x3e0) >> 5); + b = ((*colour & 0x7c00) >> 10) - ((subscreen->buffer[offset] & 0x7c00) >> 10); + if (r > 0x1f) r = 0; + if (g > 0x1f) g = 0; + if (b > 0x1f) b = 0; + } + /* only halve if the color is not the back colour */ + if (BIT(m_color_modes, 6) && (subscreen->buffer[offset] != m_cgram[FIXED_COLOUR])) + { + r >>= 1; + g >>= 1; + b >>= 1; + } + } + else /* Fixed colour */ + { + if (!BIT(m_color_modes, 7)) + { + /* 0x00 add */ + r = (*colour & 0x1f) + (m_cgram[FIXED_COLOUR] & 0x1f); + g = ((*colour & 0x3e0) >> 5) + ((m_cgram[FIXED_COLOUR] & 0x3e0) >> 5); + b = ((*colour & 0x7c00) >> 10) + ((m_cgram[FIXED_COLOUR] & 0x7c00) >> 10); + clip_max = 1; + } + else + { + /* 0x80: sub */ + r = (*colour & 0x1f) - (m_cgram[FIXED_COLOUR] & 0x1f); + g = ((*colour & 0x3e0) >> 5) - ((m_cgram[FIXED_COLOUR] & 0x3e0) >> 5); + b = ((*colour & 0x7c00) >> 10) - ((m_cgram[FIXED_COLOUR] & 0x7c00) >> 10); + if (r > 0x1f) r = 0; + if (g > 0x1f) g = 0; + if (b > 0x1f) b = 0; + } + /* halve if necessary */ + if (BIT(m_color_modes, 6)) + { + r >>= 1; + g >>= 1; + b >>= 1; + } + } + + /* according to anomie's docs, after addition has been performed, division by 2 happens *before* clipping to max, hence we clip now */ + if (clip_max) + { + if (r > 0x1f) r = 0x1f; + if (g > 0x1f) g = 0x1f; + if (b > 0x1f) b = 0x1f; + } + + *colour = ((r & 0x1f) | ((g & 0x1f) << 5) | ((b & 0x1f) << 10)); + } +} + +/********************************************* + * refresh_scanline() + * + * Redraw the current line. + *********************************************/ +/********************************************* + * Notice that in hires and pseudo hires modes, + * i.e. when 512 different pixels are present + * in a scanline, a crt TV monitor would end + * up blending adjacent pixels. To mimic this, + * we add a small (optional) hack which enters + * only in the very last stage of the scanline + * drawing and which simulates the TV by + * replacing the exact pixel color with an + * average of the current and next pixel colors. + * Credits (and thanks) to Blargg and Byuu for + * the optimized averaging algorithm. + *********************************************/ + +void snes_ppu_device::refresh_scanline( bitmap_rgb32 &bitmap, UINT16 curline ) +{ + UINT16 ii; + int x; + int fade; + struct SNES_SCANLINE *scanline1, *scanline2; + UINT16 c; + UINT16 prev_colour = 0; + int blurring = machine().root_device().ioport("OPTIONS")->read_safe(0) & 0x01; + + g_profiler.start(PROFILER_VIDEO); + + if (m_screen_disabled) /* screen is forced blank */ + for (x = 0; x < SNES_SCR_WIDTH * 2; x++) + bitmap.pix32(curline, x) = rgb_t::black; + else + { + /* Update clip window masks if necessary */ + if (m_update_windows) + update_windowmasks(); + /* Update the offsets if necessary */ + if (m_update_offsets) + update_offsets(); + + /* Clear priority */ + memset(m_scanlines[SNES_MAINSCREEN].priority, 0, SNES_SCR_WIDTH); + memset(m_scanlines[SNES_SUBSCREEN].priority, 0, SNES_SCR_WIDTH); + + /* Clear layers */ + memset(m_scanlines[SNES_MAINSCREEN].layer, SNES_COLOR, SNES_SCR_WIDTH); + memset(m_scanlines[SNES_SUBSCREEN].layer, SNES_COLOR, SNES_SCR_WIDTH); + + /* Clear blend_exception (only used for OAM) */ + memset(m_scanlines[SNES_MAINSCREEN].blend_exception, 0, SNES_SCR_WIDTH); + memset(m_scanlines[SNES_SUBSCREEN].blend_exception, 0, SNES_SCR_WIDTH); + + /* Draw back colour */ + for (ii = 0; ii < SNES_SCR_WIDTH; ii++) + { + if (m_mode == 5 || m_mode == 6 || m_pseudo_hires) + m_scanlines[SNES_SUBSCREEN].buffer[ii] = m_cgram[0]; + else + m_scanlines[SNES_SUBSCREEN].buffer[ii] = m_cgram[FIXED_COLOUR]; + + m_scanlines[SNES_MAINSCREEN].buffer[ii] = m_cgram[0]; + } + + /* Prepare OAM for this scanline */ + update_objects_rto(curline); + + /* Draw scanline */ + draw_screens(curline); + + update_obsel(); + +#if SNES_LAYER_DEBUG + if (dbg_video(curline)) + { + g_profiler.stop(); + return; + } + + /* Toggle drawing of SNES_SUBSCREEN or SNES_MAINSCREEN */ + if (m_debug_options.draw_subscreen) + { + scanline1 = &m_scanlines[SNES_SUBSCREEN]; + scanline2 = &m_scanlines[SNES_MAINSCREEN]; + } + else +#endif /* SNES_LAYER_DEBUG */ + { + scanline1 = &m_scanlines[SNES_MAINSCREEN]; + scanline2 = &m_scanlines[SNES_SUBSCREEN]; + } + + /* Draw the scanline to screen */ + + fade = m_screen_brightness; + + for (x = 0; x < SNES_SCR_WIDTH; x++) + { + int r, g, b, hires; + UINT16 tmp_col[2]; + hires = (m_mode != 5 && m_mode != 6 && !m_pseudo_hires) ? 0 : 1; + + /* in hires, the first pixel (of 512) is subscreen pixel, then the first mainscreen pixel follows, and so on... */ + if (!hires) + { + c = scanline1->buffer[x]; + + /* perform color math if the layer wants it (except if it's an object > 192) */ + if (!scanline1->blend_exception[x] && m_layer[scanline1->layer[x]].color_math) + draw_blend(x, &c, m_prevent_color_math, m_clip_to_black, 0); + + r = ((c & 0x1f) * fade) >> 4; + g = (((c & 0x3e0) >> 5) * fade) >> 4; + b = (((c & 0x7c00) >> 10) * fade) >> 4; + + bitmap.pix32(curline, x * 2 + 0) = rgb_t(pal5bit(r), pal5bit(g), pal5bit(b)); + bitmap.pix32(curline, x * 2 + 1) = rgb_t(pal5bit(r), pal5bit(g), pal5bit(b)); + } + else + { + /* prepare the pixel from main screen */ + c = scanline1->buffer[x]; + + /* perform color math if the layer wants it (except if it's an object > 192) */ + if (!scanline1->blend_exception[x] && m_layer[scanline1->layer[x]].color_math) + draw_blend(x, &c, m_prevent_color_math, m_clip_to_black, 0); + + tmp_col[1] = c; + + /* prepare the pixel from sub screen */ + c = scanline2->buffer[x]; + + /* in hires/pseudo-hires, subscreen pixels are blended as well: for each subscreen pixel, color math + is applied if it had been applied to the previous mainscreen pixel. What happens at subscreen pixel 0 + (which has no previous mainscreen pixel) is undocumented. Until more info are discovered, we (arbitrarily) + apply to it the same color math as the *next* mainscreen pixel (i.e. mainscreen pixel 0), which seems as good as + any other choice */ + if (x == 0 && !scanline1->blend_exception[0] && m_layer[scanline1->layer[0]].color_math) + draw_blend(0, &c, m_prevent_color_math, m_clip_to_black, 1); + else if (x > 0 && !scanline1->blend_exception[x - 1] && m_layer[scanline1->layer[x - 1]].color_math) + draw_blend(x, &c, m_prevent_color_math, m_clip_to_black, 1); + + tmp_col[0] = c; + + /* average the first pixel if required, or draw it directly*/ + if (blurring) + c = (prev_colour + tmp_col[0] - ((prev_colour ^ tmp_col[0]) & 0x0421)) >> 1; // Hack code to mimic TV pixel blurring + else + c = tmp_col[0]; + + r = ((c & 0x1f) * fade) >> 4; + g = (((c & 0x3e0) >> 5) * fade) >> 4; + b = (((c & 0x7c00) >> 10) * fade) >> 4; + + bitmap.pix32(curline, x * 2 + 0) = rgb_t(pal5bit(r), pal5bit(g), pal5bit(b)); + prev_colour = tmp_col[0]; + + /* average the second pixel if required, or draw it directly*/ + if (blurring) + c = (prev_colour + tmp_col[1] - ((prev_colour ^ tmp_col[1]) & 0x0421)) >> 1; // Hack code to mimic TV pixel blurring + else + c = tmp_col[1]; + + r = ((c & 0x1f) * fade) >> 4; + g = (((c & 0x3e0) >> 5) * fade) >> 4; + b = (((c & 0x7c00) >> 10) * fade) >> 4; + + bitmap.pix32(curline, x * 2 + 1) = rgb_t(pal5bit(r), pal5bit(g), pal5bit(b)); + prev_colour = tmp_col[1]; + } + } + } + + g_profiler.stop(); +} + + +/* CPU <-> PPU comms */ + +// full graphic variables +static const UINT16 vram_fgr_inctab[4] = { 1, 32, 128, 128 }; +static const UINT16 vram_fgr_inccnts[4] = { 0, 32, 64, 128 }; +static const UINT16 vram_fgr_shiftab[4] = { 0, 5, 6, 7 }; + +// utility function - latches the H/V counters. Used by IRQ, writes to WRIO, etc. +void snes_ppu_device::set_latch_hv(INT16 x, INT16 y) +{ + m_beam.latch_vert = y; + m_beam.latch_horz = x; + m_stat78 |= 0x40; // indicate we latched + +// printf("latched @ H %d V %d\n", m_beam.latch_horz, m_beam.latch_vert); +} + +void snes_ppu_device::dynamic_res_change() +{ + rectangle visarea = m_screen->visible_area(); + attoseconds_t refresh; + + visarea.min_x = visarea.min_y = 0; + visarea.max_y = m_beam.last_visible_line * m_interlace - 1; + visarea.max_x = (SNES_SCR_WIDTH * 2) - 1; + + // fixme: should compensate for SNES_DBG_VIDEO + if (m_mode == 5 || m_mode == 6 || m_pseudo_hires) + m_htmult = 2; + else + m_htmult = 1; + + /* FIXME: does the timing changes when the gfx mode is equal to 5 or 6? */ + if ((m_stat78 & 0x10) == SNES_NTSC) + { + refresh = HZ_TO_ATTOSECONDS(DOTCLK_NTSC) * SNES_HTOTAL * SNES_VTOTAL_NTSC; + m_screen->configure(SNES_HTOTAL * 2, SNES_VTOTAL_NTSC * m_interlace, visarea, refresh); + } + else + { + refresh = HZ_TO_ATTOSECONDS(DOTCLK_PAL) * SNES_HTOTAL * SNES_VTOTAL_PAL; + m_screen->configure(SNES_HTOTAL * 2, SNES_VTOTAL_PAL * m_interlace, visarea, refresh); + } +} + +/************************************************* + + SNES VRAM accesses: + + VRAM accesses during active display are invalid. + Unlike OAM and CGRAM, they will not be written + anywhere at all. Thanks to byuu's researches, + the ranges where writes are invalid have been + validated on hardware, as has the edge case where + the S-CPU open bus can be written if the write + occurs during the very last clock cycle of + vblank. + Our implementation could be not 100% accurate + when interlace is active. +*************************************************/ + +inline UINT32 snes_ppu_device::get_vram_address() +{ + UINT32 addr = m_vmadd; + + if (m_vram_fgr_count) + { + UINT32 rem = addr & m_vram_fgr_mask; + UINT32 faddr = (addr & ~m_vram_fgr_mask) + (rem >> m_vram_fgr_shift) + ((rem & (m_vram_fgr_count - 1)) << 3); + return faddr << 1; + } + + return addr << 1; +} + +READ8_MEMBER( snes_ppu_device::vram_read ) +{ + UINT8 res = 0; + offset &= 0xffff; // only 64KB are present on SNES + + if (m_screen_disabled) + res = m_vram[offset]; + else + { + UINT16 v = m_screen->vpos(); + UINT16 h = m_screen->hpos(); + UINT16 ls = (((m_stat78 & 0x10) == SNES_NTSC ? 525 : 625) >> 1) - 1; + + if (m_interlace == 2) + ls++; + + if (v == ls && h == 1362) + res = 0; + else if (v < m_beam.last_visible_line - 1) + res = 0; + else if (v == m_beam.last_visible_line - 1) + { + if (h == 1362) + res = m_vram[offset]; + else + { + //printf("%d %d VRAM read, CHECK!\n",h,v); + res = 0; + } + } + else + res = m_vram[offset]; + } + return res; +} + +WRITE8_MEMBER( snes_ppu_device::vram_write ) +{ + offset &= 0xffff; // only 64KB are present on SNES, Robocop 3 relies on this + + if (m_screen_disabled) + m_vram[offset] = data; + else + { + UINT16 v = m_screen->vpos(); + UINT16 h = m_screen->hpos(); + if (v == 0) + { + if (h <= 4) + m_vram[offset] = data; + else if (h == 6) + m_vram[offset] = m_openbus_cb(space, 0); + else + { + //printf("%d %d VRAM write, CHECK!\n",h,v); + //no write + } + } + else if (v < m_beam.last_visible_line) + { + //printf("%d %d VRAM write, CHECK!\n",h,v); + //no write + } + else if (v == m_beam.last_visible_line) + { + if (h <= 4) + { + //printf("%d %d VRAM write, CHECK!\n",h,v); + //no write + } + else + m_vram[offset] = data; + } + else + m_vram[offset] = data; + } +} + +/************************************************* + + SNES OAM accesses: + + OAM accesses during active display are allowed. + The actual address varies during rendering, as the + PPU reads in data itself for processing. + Unfortunately, no one has been able (yet) to + determine how this works. The only known game to + actually access OAM during active display is + Uniracers and it expects accesses to map to + offset 0x0218. Hence, following byuu's choice + we rerouted OAM accesses during active display + to 0x0218 (0x010c in our snes_oam). + This is a hack, but it is more accurate than + writing to the 'expected' address set by + $2102,$2103. + + Notice that, since PPU_REG(OAMDATA) is never + read/written directly, we use it as an index + to choose the high/low byte of the snes_oam word. +*************************************************/ + +READ8_MEMBER( snes_ppu_device::oam_read ) +{ + offset &= 0x1ff; + + if (offset & 0x100) + offset &= 0x10f; + + if (!m_screen_disabled) + { + UINT16 v = m_screen->vpos(); + + if (v < m_beam.last_visible_line) + offset = 0x010c; + } + + return (m_oam_ram[offset] >> (PPU_REG(OAMDATA) << 3)) & 0xff; +} + +WRITE8_MEMBER( snes_ppu_device::oam_write ) +{ + offset &= 0x1ff; + + if (offset & 0x100) + offset &= 0x10f; + + if (!m_screen_disabled) + { + UINT16 v = m_screen->vpos(); + + if (v < m_beam.last_visible_line) + offset = 0x010c; + } + + if (!(PPU_REG(OAMDATA))) + m_oam_ram[offset] = (m_oam_ram[offset] & 0xff00) | (data << 0); + else + m_oam_ram[offset] = (m_oam_ram[offset] & 0x00ff) | (data << 8); +} + +/************************************************* + + SNES CGRAM accesses: + + CGRAM writes during hblank are valid. During + active display, the actual address the data + is written to varies, as the PPU itself changes + the address. Like OAM, it is not known the exact + algorithm used, but no commercial software seems + to attempt this. While byuu, in his emu, maps + those accesses to 0x01ff, because it is more + accurate to invalidate the 'expected' address + than not, MESS has issues if we don't write to + the expected address (see e.g. Tokimeki Memorial). + This is because writes should work during hblank + (so that the game can produce color fading), but + ends up not working with the conditions below. + Hence, for the moment, we only document the + solution adopted by BSNES without enabling it. +*************************************************/ + +READ8_MEMBER( snes_ppu_device::cgram_read ) +{ + UINT8 res = 0; + offset &= 0x1ff; + +#if 0 + if (!m_screen_disabled) + { + UINT16 v = m_screen->vpos(); + UINT16 h = m_screen->hpos(); + + if (v < m_beam.last_visible_line && h >= 128 && h < 1096) + offset = 0x1ff; + } +#endif + + res = ((UINT8 *)m_cgram)[offset]; + + // CGRAM palette data format is 15-bits (0,bbbbb,ggggg,rrrrr). + // Highest bit is simply ignored. + if (offset & 0x01) + res &= 0x7f; + + return res; +} + +WRITE8_MEMBER( snes_ppu_device::cgram_write ) +{ + offset &= 0x1ff; + +#if 0 + // FIXME: this currently breaks some games (e.g. Tokimeki Memorial), + // even if it's expected to be more accurate than allowing for + // writes to the cgram address + if (!m_screen_disabled) + { + UINT16 v = m_screen->vpos(); + UINT16 h = m_screen->hpos(); + + if (v < m_beam.last_visible_line && h >= 128 && h < 1096) + offset = 0x1ff; + } +#endif + + // CGRAM palette data format is 15-bits (0,bbbbb,ggggg,rrrrr). + // Highest bit is simply ignored. + if (offset & 0x01) + data &= 0x7f; + + ((UINT8 *)m_cgram)[offset] = data; +} + +UINT8 snes_ppu_device::read(address_space &space, UINT32 offset, UINT8 wrio_bit7) +{ + UINT8 value; + + switch (offset) + { + case OAMDATA: /* 21xy for x=0,1,2 and y=4,5,6,8,9,a returns PPU1 open bus*/ + case BGMODE: + case MOSAIC: + case BG2SC: + case BG3SC: + case BG4SC: + case BG4VOFS: + case VMAIN: + case VMADDL: + case VMDATAL: + case VMDATAH: + case M7SEL: + case W34SEL: + case WOBJSEL: + case WH0: + case WH2: + case WH3: + case WBGLOG: + return m_ppu1_open_bus; + + case MPYL: /* Multiplication result (low) */ + { + /* Perform 16bit * 8bit multiply */ + UINT32 c = (INT16)m_mode7.matrix_a * (INT8)(m_mode7.matrix_b >> 8); + m_ppu1_open_bus = c & 0xff; + return m_ppu1_open_bus; + } + case MPYM: /* Multiplication result (mid) */ + { + /* Perform 16bit * 8bit multiply */ + UINT32 c = (INT16)m_mode7.matrix_a * (INT8)(m_mode7.matrix_b >> 8); + m_ppu1_open_bus = (c >> 8) & 0xff; + return m_ppu1_open_bus; + } + case MPYH: /* Multiplication result (high) */ + { + /* Perform 16bit * 8bit multiply */ + UINT32 c = (INT16)m_mode7.matrix_a * (INT8)(m_mode7.matrix_b >> 8); + m_ppu1_open_bus = (c >> 16) & 0xff; + return m_ppu1_open_bus; + } + case SLHV: /* Software latch for H/V counter */ + set_latch_hv(m_screen->hpos() / m_htmult, m_screen->vpos()); + return m_openbus_cb(space, 0); /* Return value is meaningless */ + + case ROAMDATA: /* Read data from OAM (DR) */ + m_ppu1_open_bus = oam_read(space, m_oam.address); + PPU_REG(OAMDATA) = (PPU_REG(OAMDATA) + 1) % 2; + if (!PPU_REG(OAMDATA)) + { + m_oam.address++; + m_oam.address &= 0x1ff; + m_oam.first_sprite = m_oam.priority_rotation ? (m_oam.address >> 1) & 127 : 0; + } + return m_ppu1_open_bus; + case RVMDATAL: /* Read data from VRAM (low) */ + { + UINT32 addr = get_vram_address(); + m_ppu1_open_bus = m_vram_read_buffer & 0xff; + + if (!m_vram_fgr_high) + { + m_vram_read_buffer = vram_read(space, addr); + m_vram_read_buffer |= (vram_read(space, addr + 1) << 8); + + m_vmadd = (m_vmadd + m_vram_fgr_increment) & 0xffff; + } + + return m_ppu1_open_bus; + } + case RVMDATAH: /* Read data from VRAM (high) */ + { + UINT32 addr = get_vram_address(); + m_ppu1_open_bus = (m_vram_read_buffer >> 8) & 0xff; + + if (m_vram_fgr_high) + { + m_vram_read_buffer = vram_read(space, addr); + m_vram_read_buffer |= (vram_read(space, addr + 1) << 8); + + m_vmadd = (m_vmadd + m_vram_fgr_increment) & 0xffff; + } + + return m_ppu1_open_bus; + } + case RCGDATA: /* Read data from CGRAM */ + if (!(m_cgram_address & 0x01)) + m_ppu2_open_bus = cgram_read(space, m_cgram_address); + else + { + m_ppu2_open_bus &= 0x80; + m_ppu2_open_bus |= cgram_read(space, m_cgram_address) & 0x7f; + } + + m_cgram_address = (m_cgram_address + 1) % (SNES_CGRAM_SIZE - 2); + return m_ppu2_open_bus; + case OPHCT: /* Horizontal counter data by ext/soft latch */ + if (m_read_ophct) + { + m_ppu2_open_bus &= 0xfe; + m_ppu2_open_bus |= (m_beam.latch_horz >> 8) & 0x01; + } + else + { + m_ppu2_open_bus = m_beam.latch_horz & 0xff; + } + m_read_ophct ^= 1; + return m_ppu2_open_bus; + case OPVCT: /* Vertical counter data by ext/soft latch */ + if (m_read_opvct) + { + m_ppu2_open_bus &= 0xfe; + m_ppu2_open_bus |= (m_beam.latch_vert >> 8) & 0x01; + } + else + { + m_ppu2_open_bus = m_beam.latch_vert & 0xff; + } + m_read_opvct ^= 1; + return m_ppu2_open_bus; + case STAT77: /* PPU status flag and version number */ + value = m_stat77 & 0xc0; // 0x80 & 0x40 are Time Over / Range Over Sprite flags, set by the video code + // 0x20 - Master/slave mode select. Little is known about this bit. We always seem to read back 0 here. + value |= (m_ppu1_open_bus & 0x10); + value |= (m_ppu1_version & 0x0f); + m_stat77 = value; // not sure if this is needed... + m_ppu1_open_bus = value; + return m_ppu1_open_bus; + case STAT78: /* PPU status flag and version number */ + m_read_ophct = 0; + m_read_opvct = 0; + if (wrio_bit7) + m_stat78 &= ~0x40; //clear ext latch if bit 7 of WRIO is set + m_stat78 = (m_stat78 & ~0x2f) | (m_ppu2_open_bus & 0x20) | (m_ppu2_version & 0x0f); + m_ppu2_open_bus = m_stat78; + return m_ppu2_open_bus; + } + + /* note: remaining registers (Namely TM in Super Kick Boxing) returns MDR open bus, not PPU Open Bus! */ + return m_openbus_cb(space, 0); +} + + +void snes_ppu_device::write(address_space &space, UINT32 offset, UINT8 data) +{ + switch (offset) + { + case INIDISP: /* Initial settings for screen */ + if ((m_screen_disabled & 0x80) && (!(data & 0x80))) //a 1->0 force blank transition causes a reset OAM address + { + space.write_byte(OAMADDL, m_oam.saved_address_low); + space.write_byte(OAMADDH, m_oam.saved_address_high); + m_oam.first_sprite = m_oam.priority_rotation ? (m_oam.address >> 1) & 127 : 0; + } + m_screen_disabled = data & 0x80; + m_screen_brightness = (data & 0x0f) + 1; + break; + case OBSEL: /* Object size and data area designation */ + m_oam.next_charmap = (data & 0x03) << 1; + m_oam.next_name_select = (((data & 0x18) >> 3) * 0x1000) << 1; + m_oam.next_size = (data & 0xe0) >> 5; + break; + case OAMADDL: /* Address for accessing OAM (low) */ + m_oam.saved_address_low = data; + m_oam.address = (m_oam.address & 0xff00) + data; + m_oam.first_sprite = m_oam.priority_rotation ? (m_oam.address >> 1) & 127 : 0; + PPU_REG(OAMDATA) = 0; + break; + case OAMADDH: /* Address for accessing OAM (high) */ + m_oam.saved_address_high = data; + m_oam.address = (m_oam.address & 0x00ff) | ((data & 0x01) << 8); + m_oam.priority_rotation = BIT(data, 7); + m_oam.first_sprite = m_oam.priority_rotation ? (m_oam.address >> 1) & 127 : 0; + PPU_REG(OAMDATA) = 0; + break; + case OAMDATA: /* Data for OAM write (DW) */ + if (m_oam.address >= 0x100) + oam_write(space, m_oam.address, data); + else + { + if (!PPU_REG(OAMDATA)) + m_oam.write_latch = data; + else + { + // in this case, we not only write data to the upper byte of the word, + // but also m_oam.write_latch to the lower byte (recall that + // PPU_REG(OAMDATA) is used to select high/low byte) + oam_write(space, m_oam.address, data); + PPU_REG(OAMDATA) = 0; + oam_write(space, m_oam.address, m_oam.write_latch); + PPU_REG(OAMDATA) = 1; + } + } + PPU_REG(OAMDATA) = (PPU_REG(OAMDATA) + 1) % 2; + if (!PPU_REG(OAMDATA)) + { + m_oam.address++; + m_oam.address &= 0x1ff; + m_oam.first_sprite = m_oam.priority_rotation ? (m_oam.address >> 1) & 127 : 0; + } + return; + case BGMODE: /* BG mode and character size settings */ + m_mode = data & 0x07; + dynamic_res_change(); + m_bg3_priority_bit = BIT(data, 3); + m_layer[SNES_BG1].tile_size = BIT(data, 4); + m_layer[SNES_BG2].tile_size = BIT(data, 5); + m_layer[SNES_BG3].tile_size = BIT(data, 6); + m_layer[SNES_BG4].tile_size = BIT(data, 7); + m_update_offsets = 1; + break; + case MOSAIC: /* Size and screen designation for mosaic */ + m_mosaic_size = (data & 0xf0) >> 4; + m_layer[SNES_BG1].mosaic_enabled = BIT(data, 0); + m_layer[SNES_BG2].mosaic_enabled = BIT(data, 1); + m_layer[SNES_BG3].mosaic_enabled = BIT(data, 2); + m_layer[SNES_BG4].mosaic_enabled = BIT(data, 3); + break; + case BG1SC: /* Address for storing SC data BG1 SC size designation */ + case BG2SC: /* Address for storing SC data BG2 SC size designation */ + case BG3SC: /* Address for storing SC data BG3 SC size designation */ + case BG4SC: /* Address for storing SC data BG4 SC size designation */ + m_layer[offset - BG1SC].tilemap = data & 0xfc; + m_layer[offset - BG1SC].tilemap_size = data & 0x3; + break; + case BG12NBA: /* Address for BG 1 and 2 character data */ + m_layer[SNES_BG1].charmap = (data & 0x0f); + m_layer[SNES_BG2].charmap = (data & 0xf0) >> 4; + break; + case BG34NBA: /* Address for BG 3 and 4 character data */ + m_layer[SNES_BG3].charmap = (data & 0x0f); + m_layer[SNES_BG4].charmap = (data & 0xf0) >> 4; + break; + + // Anomie says "H Current = (Byte<<8) | (Prev&~7) | ((Current>>8)&7); V Current = (Current<<8) | Prev;" and Prev is shared by all scrolls but in Mode 7! + case BG1HOFS: /* BG1 - horizontal scroll (DW) */ + /* In Mode 0->6 we use ppu_last_scroll as Prev */ + m_layer[SNES_BG1].hoffs = (data << 8) | (m_ppu_last_scroll & ~7) | ((m_layer[SNES_BG1].hoffs >> 8) & 7); + m_ppu_last_scroll = data; + /* In Mode 7 we use mode7_last_scroll as Prev */ + m_mode7.hor_offset = (data << 8) | (m_mode7_last_scroll & ~7) | ((m_mode7.hor_offset >> 8) & 7); + m_mode7_last_scroll = data; + m_update_offsets = 1; + return; + case BG1VOFS: /* BG1 - vertical scroll (DW) */ + /* In Mode 0->6 we use ppu_last_scroll as Prev */ + m_layer[SNES_BG1].voffs = (data << 8) | m_ppu_last_scroll; + m_ppu_last_scroll = data; + /* In Mode 7 we use mode7_last_scroll as Prev */ + m_mode7.ver_offset = (data << 8) | m_mode7_last_scroll; + m_mode7_last_scroll = data; + m_update_offsets = 1; + return; + case BG2HOFS: /* BG2 - horizontal scroll (DW) */ + m_layer[SNES_BG2].hoffs = (data << 8) | (m_ppu_last_scroll & ~7) | ((m_layer[SNES_BG2].hoffs >> 8) & 7); + m_ppu_last_scroll = data; + m_update_offsets = 1; + return; + case BG2VOFS: /* BG2 - vertical scroll (DW) */ + m_layer[SNES_BG2].voffs = (data << 8) | (m_ppu_last_scroll); + m_ppu_last_scroll = data; + m_update_offsets = 1; + return; + case BG3HOFS: /* BG3 - horizontal scroll (DW) */ + m_layer[SNES_BG3].hoffs = (data << 8) | (m_ppu_last_scroll & ~7) | ((m_layer[SNES_BG3].hoffs >> 8) & 7); + m_ppu_last_scroll = data; + m_update_offsets = 1; + return; + case BG3VOFS: /* BG3 - vertical scroll (DW) */ + m_layer[SNES_BG3].voffs = (data << 8) | (m_ppu_last_scroll); + m_ppu_last_scroll = data; + m_update_offsets = 1; + return; + case BG4HOFS: /* BG4 - horizontal scroll (DW) */ + m_layer[SNES_BG4].hoffs = (data << 8) | (m_ppu_last_scroll & ~7) | ((m_layer[SNES_BG4].hoffs >> 8) & 7); + m_ppu_last_scroll = data; + m_update_offsets = 1; + return; + case BG4VOFS: /* BG4 - vertical scroll (DW) */ + m_layer[SNES_BG4].voffs = (data << 8) | (m_ppu_last_scroll); + m_ppu_last_scroll = data; + m_update_offsets = 1; + return; + case VMAIN: /* VRAM address increment value designation */ + m_vram_fgr_high = (data & 0x80); + m_vram_fgr_increment = vram_fgr_inctab[data & 3]; + + if (data & 0xc) + { + int md = (data & 0xc) >> 2; + + m_vram_fgr_count = vram_fgr_inccnts[md]; // 0x20, 0x40, 0x80 + m_vram_fgr_mask = (m_vram_fgr_count * 8) - 1; // 0xff, 0x1ff, 0x2ff + m_vram_fgr_shift = vram_fgr_shiftab[md]; // 5, 6, 7 + } + else + { + m_vram_fgr_count = 0; + } +// printf("VMAIN: high %x inc %x count %x mask %x shift %x\n", m_vram_fgr_high, m_vram_fgr_increment, m_vram_fgr_count, m_vram_fgr_mask, m_vram_fgr_shift); + break; + case VMADDL: /* Address for VRAM read/write (low) */ + { + UINT32 addr; + m_vmadd = (m_vmadd & 0xff00) | (data << 0); + addr = get_vram_address(); + m_vram_read_buffer = vram_read(space, addr); + m_vram_read_buffer |= (vram_read(space, addr + 1) << 8); + } + break; + case VMADDH: /* Address for VRAM read/write (high) */ + { + UINT32 addr; + m_vmadd = (m_vmadd & 0x00ff) | (data << 8); + addr = get_vram_address(); + m_vram_read_buffer = vram_read(space, addr); + m_vram_read_buffer |= (vram_read(space, addr + 1) << 8); + } + break; + case VMDATAL: /* 2118: Data for VRAM write (low) */ + { + UINT32 addr = get_vram_address(); + vram_write(space, addr, data); + + if (!m_vram_fgr_high) + m_vmadd = (m_vmadd + m_vram_fgr_increment) & 0xffff; + } + return; + case VMDATAH: /* 2119: Data for VRAM write (high) */ + { + UINT32 addr = get_vram_address(); + vram_write(space, addr + 1, data); + + if (m_vram_fgr_high) + m_vmadd = (m_vmadd + m_vram_fgr_increment) & 0xffff; + } + return; + case M7SEL: /* Mode 7 initial settings */ + m_mode7.repeat = (data >> 6) & 3; + m_mode7.vflip = BIT(data, 1); + m_mode7.hflip = BIT(data, 0); + break; + /* As per Anomie's doc: Reg = (Current<<8) | Prev; and there is only one Prev, shared by these matrix regs and Mode 7 scroll regs */ + case M7A: /* Mode 7 COS angle/x expansion (DW) */ + m_mode7.matrix_a = m_mode7_last_scroll + (data << 8); + m_mode7_last_scroll = data; + break; + case M7B: /* Mode 7 SIN angle/ x expansion (DW) */ + m_mode7.matrix_b = m_mode7_last_scroll + (data << 8); + m_mode7_last_scroll = data; + break; + case M7C: /* Mode 7 SIN angle/y expansion (DW) */ + m_mode7.matrix_c = m_mode7_last_scroll + (data << 8); + m_mode7_last_scroll = data; + break; + case M7D: /* Mode 7 COS angle/y expansion (DW) */ + m_mode7.matrix_d = m_mode7_last_scroll + (data << 8); + m_mode7_last_scroll = data; + break; + case M7X: /* Mode 7 x center position (DW) */ + m_mode7.origin_x = m_mode7_last_scroll + (data << 8); + m_mode7_last_scroll = data; + break; + case M7Y: /* Mode 7 y center position (DW) */ + m_mode7.origin_y = m_mode7_last_scroll + (data << 8); + m_mode7_last_scroll = data; + break; + case CGADD: /* Initial address for colour RAM writing */ + /* CGRAM is 16-bit, but when reading/writing we treat it as 8-bit, so we need to double the address */ + m_cgram_address = data << 1; + break; + case CGDATA: /* Data for colour RAM */ + cgram_write(space, m_cgram_address, data); + m_cgram_address = (m_cgram_address + 1) % (SNES_CGRAM_SIZE - 2); + break; + case W12SEL: /* Window mask settings for BG1-2 */ + if (data != PPU_REG(W12SEL)) + { + m_layer[SNES_BG1].window1_invert = BIT(data, 0); + m_layer[SNES_BG1].window1_enabled = BIT(data, 1); + m_layer[SNES_BG1].window2_invert = BIT(data, 2); + m_layer[SNES_BG1].window2_enabled = BIT(data, 3); + m_layer[SNES_BG2].window1_invert = BIT(data, 4); + m_layer[SNES_BG2].window1_enabled = BIT(data, 5); + m_layer[SNES_BG2].window2_invert = BIT(data, 6); + m_layer[SNES_BG2].window2_enabled = BIT(data, 7); + m_update_windows = 1; + } + break; + case W34SEL: /* Window mask settings for BG3-4 */ + if (data != PPU_REG(W34SEL)) + { + m_layer[SNES_BG3].window1_invert = BIT(data, 0); + m_layer[SNES_BG3].window1_enabled = BIT(data, 1); + m_layer[SNES_BG3].window2_invert = BIT(data, 2); + m_layer[SNES_BG3].window2_enabled = BIT(data, 3); + m_layer[SNES_BG4].window1_invert = BIT(data, 4); + m_layer[SNES_BG4].window1_enabled = BIT(data, 5); + m_layer[SNES_BG4].window2_invert = BIT(data, 6); + m_layer[SNES_BG4].window2_enabled = BIT(data, 7); + m_update_windows = 1; + } + break; + case WOBJSEL: /* Window mask settings for objects */ + if (data != PPU_REG(WOBJSEL)) + { + m_layer[SNES_OAM].window1_invert = BIT(data, 0); + m_layer[SNES_OAM].window1_enabled = BIT(data, 1); + m_layer[SNES_OAM].window2_invert = BIT(data, 2); + m_layer[SNES_OAM].window2_enabled = BIT(data, 3); + m_layer[SNES_COLOR].window1_invert = BIT(data, 4); + m_layer[SNES_COLOR].window1_enabled = BIT(data, 5); + m_layer[SNES_COLOR].window2_invert = BIT(data, 6); + m_layer[SNES_COLOR].window2_enabled = BIT(data, 7); + m_update_windows = 1; + } + break; + case WH0: /* Window 1 left position */ + if (data != PPU_REG(WH0)) + { + m_window1_left = data; + m_update_windows = 1; + } + break; + case WH1: /* Window 1 right position */ + if (data != PPU_REG(WH1)) + { + m_window1_right = data; + m_update_windows = 1; + } + break; + case WH2: /* Window 2 left position */ + if (data != PPU_REG(WH2)) + { + m_window2_left = data; + m_update_windows = 1; + } + break; + case WH3: /* Window 2 right position */ + if (data != PPU_REG(WH3)) + { + m_window2_right = data; + m_update_windows = 1; + } + break; + case WBGLOG: /* Window mask logic for BG's */ + if (data != PPU_REG(WBGLOG)) + { + m_layer[SNES_BG1].wlog_mask = data & 0x03; + m_layer[SNES_BG2].wlog_mask = (data & 0x0c) >> 2; + m_layer[SNES_BG3].wlog_mask = (data & 0x30) >> 4; + m_layer[SNES_BG4].wlog_mask = (data & 0xc0) >> 6; + m_update_windows = 1; + } + break; + case WOBJLOG: /* Window mask logic for objects */ + if (data != PPU_REG(WOBJLOG)) + { + m_layer[SNES_OAM].wlog_mask = data & 0x03; + m_layer[SNES_COLOR].wlog_mask = (data & 0x0c) >> 2; + m_update_windows = 1; + } + break; + case TM: /* Main screen designation */ + m_layer[SNES_BG1].main_bg_enabled = BIT(data, 0); + m_layer[SNES_BG2].main_bg_enabled = BIT(data, 1); + m_layer[SNES_BG3].main_bg_enabled = BIT(data, 2); + m_layer[SNES_BG4].main_bg_enabled = BIT(data, 3); + m_layer[SNES_OAM].main_bg_enabled = BIT(data, 4); + break; + case TS: /* Subscreen designation */ + m_layer[SNES_BG1].sub_bg_enabled = BIT(data, 0); + m_layer[SNES_BG2].sub_bg_enabled = BIT(data, 1); + m_layer[SNES_BG3].sub_bg_enabled = BIT(data, 2); + m_layer[SNES_BG4].sub_bg_enabled = BIT(data, 3); + m_layer[SNES_OAM].sub_bg_enabled = BIT(data, 4); + break; + case TMW: /* Window mask for main screen designation */ + m_layer[SNES_BG1].main_window_enabled = BIT(data, 0); + m_layer[SNES_BG2].main_window_enabled = BIT(data, 1); + m_layer[SNES_BG3].main_window_enabled = BIT(data, 2); + m_layer[SNES_BG4].main_window_enabled = BIT(data, 3); + m_layer[SNES_OAM].main_window_enabled = BIT(data, 4); + break; + case TSW: /* Window mask for subscreen designation */ + m_layer[SNES_BG1].sub_window_enabled = BIT(data, 0); + m_layer[SNES_BG2].sub_window_enabled = BIT(data, 1); + m_layer[SNES_BG3].sub_window_enabled = BIT(data, 2); + m_layer[SNES_BG4].sub_window_enabled = BIT(data, 3); + m_layer[SNES_OAM].sub_window_enabled = BIT(data, 4); + break; + case CGWSEL: /* Initial settings for Fixed colour addition or screen addition */ + m_clip_to_black = (data >> 6) & 0x03; + m_prevent_color_math = (data >> 4) & 0x03; + m_sub_add_mode = BIT(data, 1); + m_direct_color = BIT(data, 0); +#ifdef SNES_DBG_REG_W + if ((data & 0x2) != (PPU_REG(CGWSEL) & 0x2)) + osd_printf_debug("Add/Sub Layer: %s\n", ((data & 0x2) >> 1) ? "Subscreen" : "Fixed colour"); +#endif + break; + case CGADSUB: /* Addition/Subtraction designation for each screen */ + m_color_modes = data & 0xc0; + m_layer[SNES_BG1].color_math = BIT(data, 0); + m_layer[SNES_BG2].color_math = BIT(data, 1); + m_layer[SNES_BG3].color_math = BIT(data, 2); + m_layer[SNES_BG4].color_math = BIT(data, 3); + m_layer[SNES_OAM].color_math = BIT(data, 4); + m_layer[SNES_COLOR].color_math = BIT(data, 5); + break; + case COLDATA: /* Fixed colour data for fixed colour addition/subtraction */ + { + /* Store it in the extra space we made in the CGRAM. It doesn't really go there, but it's as good a place as any. */ + UINT8 r, g, b; + + /* Get existing value. */ + r = m_cgram[FIXED_COLOUR] & 0x1f; + g = (m_cgram[FIXED_COLOUR] & 0x3e0) >> 5; + b = (m_cgram[FIXED_COLOUR] & 0x7c00) >> 10; + /* Set new value */ + if (data & 0x20) + r = data & 0x1f; + if (data & 0x40) + g = data & 0x1f; + if (data & 0x80) + b = data & 0x1f; + m_cgram[FIXED_COLOUR] = (r | (g << 5) | (b << 10)); + } break; + case SETINI: /* Screen mode/video select */ + m_interlace = (data & 0x01) ? 2 : 1; + m_obj_interlace = (data & 0x02) ? 2 : 1; + m_beam.last_visible_line = (data & 0x04) ? 240 : 225; + m_pseudo_hires = BIT(data, 3); + m_mode7.extbg = BIT(data, 6); + dynamic_res_change(); +#ifdef SNES_DBG_REG_W + if ((data & 0x8) != (PPU_REG(SETINI) & 0x8)) + osd_printf_debug("Pseudo 512 mode: %s\n", (data & 0x8) ? "on" : "off"); +#endif + break; + } + + PPU_REG(offset) = data; +} + +/***** Debug Functions *****/ + +#if SNES_LAYER_DEBUG + +#define DEBUG_TOGGLE(bit, debug_settings, MSG1, MSG2) \ + if (BIT(toggles, bit) && !debug_settings) \ + { \ + debug_settings = 1; \ + popmessage MSG1; \ + } \ + else if (!BIT(toggles, bit) && debug_settings) \ + { \ + debug_settings = 0; \ + popmessage MSG2; \ + } + +UINT8 snes_ppu_device::dbg_video( UINT16 curline ) +{ + int i; + UINT8 toggles = machine().root_device().ioport("DEBUG1")->read_safe(0); + m_debug_options.select_pri[SNES_BG1] = (toggles & 0x03); + m_debug_options.select_pri[SNES_BG2] = (toggles & 0x0c) >> 2; + m_debug_options.select_pri[SNES_BG3] = (toggles & 0x30) >> 4; + m_debug_options.select_pri[SNES_BG4] = (toggles & 0xc0) >> 6; + + toggles = machine().root_device().ioport("DEBUG2")->read_safe(0); + for (i = 0; i < 4; i++) + DEBUG_TOGGLE(i, m_debug_options.bg_disabled[i], ("Debug: Disabled BG%d.\n", i + 1), ("Debug: Enabled BG%d.\n", i + 1)) + DEBUG_TOGGLE(4, m_debug_options.bg_disabled[SNES_OAM], ("Debug: Disabled OAM.\n"), ("Debug: Enabled OAM.\n")) + DEBUG_TOGGLE(5, m_debug_options.draw_subscreen, ("Debug: Switched screens.\n"), ("Debug: Switched screens.\n")) + DEBUG_TOGGLE(6, m_debug_options.colormath_disabled, ("Debug: Disabled Color Math.\n"), ("Debug: Enabled Color Math.\n")) + DEBUG_TOGGLE(7, m_debug_options.windows_disabled, ("Debug: Disabled Window Masks.\n"), ("Debug: Enabled Window Masks.\n")) + + toggles = machine().root_device().ioport("DEBUG4")->read_safe(0); + for (i = 0; i < 8; i++) + DEBUG_TOGGLE(i, m_debug_options.mode_disabled[i], ("Debug: Disabled Mode %d drawing.\n", i), ("Debug: Enabled Mode %d drawing.\n", i)) + + toggles = machine().root_device().ioport("DEBUG3")->read_safe(0); + DEBUG_TOGGLE(2, m_debug_options.mosaic_disabled, ("Debug: Disabled Mosaic.\n"), ("Debug: Enabled Mosaic.\n")) + m_debug_options.sprite_reversed = BIT(toggles, 7); + m_debug_options.select_pri[SNES_OAM] = (toggles & 0x70) >> 4; + +#ifdef MAME_DEBUG + /* Once per frame, log video properties */ + if (curline == 1) + { + static const char WINLOGIC[4] = { '|', '&', '^', '!' }; + + logerror("%s", m_debug_options.windows_disabled?" ":"W"); + logerror("%s1 %s%s%s%s%s%c%s%s%d%s %d %4X %4X", + m_debug_options.bg_disabled[0]?" ":"*", + (PPU_REG(TM) & 0x1)?"M":" ", + (PPU_REG(TS) & 0x1)?"S":" ", + (PPU_REG(CGADSUB) & 0x1)?"B":" ", + (PPU_REG(TMW) & 0x1)?"m":" ", + (PPU_REG(TSW) & 0x1)?"s":" ", + WINLOGIC[(PPU_REG(WBGLOG) & 0x3)], + (PPU_REG(W12SEL) & 0x2)?((PPU_REG(W12SEL) & 0x1)?"o":"i"):" ", + (PPU_REG(W12SEL) & 0x8)?((PPU_REG(W12SEL) & 0x4)?"o":"i"):" ", + m_layer[SNES_BG1].tile_size + 1, + (PPU_REG(MOSAIC) & 0x1)?"m":" ", + PPU_REG(BG1SC) & 0x3, + (PPU_REG(BG1SC) & 0xfc) << 9, + m_layer[SNES_BG1].charmap << 13); + logerror("%s2 %s%s%s%s%s%c%s%s%d%s %d %4X %4X", + m_debug_options.bg_disabled[1]?" ":"*", + (PPU_REG(TM) & 0x2)?"M":" ", + (PPU_REG(TS) & 0x2)?"S":" ", + (PPU_REG(CGADSUB) & 0x2)?"B":" ", + (PPU_REG(TMW) & 0x2)?"m":" ", + (PPU_REG(TSW) & 0x2)?"s":" ", + WINLOGIC[(PPU_REG(WBGLOG) & 0xc) >> 2], + (PPU_REG(W12SEL) & 0x20)?((PPU_REG(W12SEL) & 0x10)?"o":"i"):" ", + (PPU_REG(W12SEL) & 0x80)?((PPU_REG(W12SEL) & 0x40)?"o":"i"):" ", + m_layer[SNES_BG2].tile_size + 1, + (PPU_REG(MOSAIC) & 0x2)?"m":" ", + PPU_REG(BG2SC) & 0x3, + (PPU_REG(BG2SC) & 0xfc) << 9, + m_layer[SNES_BG2].charmap << 13); + logerror("%s3 %s%s%s%s%s%c%s%s%d%s%s%d %4X %4X", + m_debug_options.bg_disabled[2]?" ":"*", + (PPU_REG(TM) & 0x4)?"M":" ", + (PPU_REG(TS) & 0x4)?"S":" ", + (PPU_REG(CGADSUB) & 0x4)?"B":" ", + (PPU_REG(TMW) & 0x4)?"m":" ", + (PPU_REG(TSW) & 0x4)?"s":" ", + WINLOGIC[(PPU_REG(WBGLOG) & 0x30)>>4], + (PPU_REG(W34SEL) & 0x2)?((PPU_REG(W34SEL) & 0x1)?"o":"i"):" ", + (PPU_REG(W34SEL) & 0x8)?((PPU_REG(W34SEL) & 0x4)?"o":"i"):" ", + m_layer[SNES_BG3].tile_size + 1, + (PPU_REG(MOSAIC) & 0x4)?"m":" ", + (PPU_REG(BGMODE) & 0x8)?"P":" ", + PPU_REG(BG3SC) & 0x3, + (PPU_REG(BG3SC) & 0xfc) << 9, + m_layer[SNES_BG3].charmap << 13); + logerror("%s4 %s%s%s%s%s%c%s%s%d%s %d %4X %4X", + m_debug_options.bg_disabled[3]?" ":"*", + (PPU_REG(TM) & 0x8)?"M":" ", + (PPU_REG(TS) & 0x8)?"S":" ", + (PPU_REG(CGADSUB) & 0x8)?"B":" ", + (PPU_REG(TMW) & 0x8)?"m":" ", + (PPU_REG(TSW) & 0x8)?"s":" ", + WINLOGIC[(PPU_REG(WBGLOG) & 0xc0)>>6], + (PPU_REG(W34SEL) & 0x20)?((PPU_REG(W34SEL) & 0x10)?"o":"i"):" ", + (PPU_REG(W34SEL) & 0x80)?((PPU_REG(W34SEL) & 0x40)?"o":"i"):" ", + m_layer[SNES_BG4].tile_size + 1, + (PPU_REG(MOSAIC) & 0x8)?"m":" ", + PPU_REG(BG4SC) & 0x3, + (PPU_REG(BG4SC) & 0xfc) << 9, + m_layer[SNES_BG4].charmap << 13 ); + logerror("%sO %s%s%s%s%s%c%s%s %4X", + m_debug_options.bg_disabled[4]?" ":"*", + (PPU_REG(TM) & 0x10)?"M":" ", + (PPU_REG(TS) & 0x10)?"S":" ", + (PPU_REG(CGADSUB) & 0x10)?"B":" ", + (PPU_REG(TMW) & 0x10)?"m":" ", + (PPU_REG(TSW) & 0x10)?"s":" ", + WINLOGIC[(PPU_REG(WOBJLOG) & 0x3)], + (PPU_REG(WOBJSEL) & 0x2)?((PPU_REG(WOBJSEL) & 0x1)?"o":"i"):" ", + (PPU_REG(WOBJSEL) & 0x8)?((PPU_REG(WOBJSEL) & 0x4)?"o":"i"):" ", + m_layer[SNES_OAM].charmap << 13 ); + logerror("%sB %s %c%s%s", + m_debug_options.colormath_disabled?" ":"*", + (PPU_REG(CGADSUB) & 0x20)?"B":" ", + WINLOGIC[(PPU_REG(WOBJLOG) & 0xc)>>2], + (PPU_REG(WOBJSEL) & 0x20)?((PPU_REG(WOBJSEL) & 0x10)?"o":"i"):" ", + (PPU_REG(WOBJSEL) & 0x80)?((PPU_REG(WOBJSEL) & 0x40)?"o":"i"):" " ); + logerror("Flags: %s%s%s %s %2d", (PPU_REG(CGWSEL) & 0x2)?"S":"F", (PPU_REG(CGADSUB) & 0x80)?"-":"+", (PPU_REG(CGADSUB) & 0x40)?" 50%":"100%",(PPU_REG(CGWSEL) & 0x1)?"D":"P", (PPU_REG(MOSAIC) & 0xf0) >> 4 ); + logerror("SetINI: %s %s %s %s %s %s", (PPU_REG(SETINI) & 0x1)?" I":"NI", (PPU_REG(SETINI) & 0x2)?"P":"R", (PPU_REG(SETINI) & 0x4)?"240":"225",(PPU_REG(SETINI) & 0x8)?"512":"256",(PPU_REG(SETINI) & 0x40)?"E":"N",(PPU_REG(SETINI) & 0x80)?"ES":"NS" ); + logerror("Mode7: A %5d B %5d", m_mode7.matrix_a, m_mode7.matrix_b ); + logerror(" %s%s%s C %5d D %5d", (PPU_REG(M7SEL) & 0xc0)?((PPU_REG(M7SEL) & 0x40)?"0":"C"):"R", (PPU_REG(M7SEL) & 0x1)?"H":" ", (PPU_REG(M7SEL) & 0x2)?"V":" ", m_mode7.matrix_c, m_mode7.matrix_d ); + logerror(" X %5d Y %5d", m_mode7.origin_x, m_mode7.origin_y ); + } +#endif + + return 0; +} +#endif /* SNES_LAYER_DEBUG */ diff --git a/src/devices/video/snes_ppu.h b/src/devices/video/snes_ppu.h new file mode 100644 index 00000000000..806865a0729 --- /dev/null +++ b/src/devices/video/snes_ppu.h @@ -0,0 +1,295 @@ +// license:BSD-3-Clause +// copyright-holders:Anthony Kruize, Fabio Priuli +/*************************************************************************** + + SNES PPU + +***************************************************************************/ + +#pragma once + +#ifndef __SNES_PPU_H__ +#define __SNES_PPU_H__ + + +#define MCLK_NTSC (21477272) /* verified */ +#define MCLK_PAL (21218370) /* verified */ + +#define DOTCLK_NTSC (MCLK_NTSC/4) +#define DOTCLK_PAL (MCLK_PAL/4) + +#define SNES_SCR_WIDTH 256 /* 32 characters 8 pixels wide */ +#define SNES_SCR_HEIGHT_NTSC 225 /* Can be 224 or 240 height */ +#define SNES_SCR_HEIGHT_PAL 240 /* ??? */ +#define SNES_VTOTAL_NTSC 262 /* Maximum number of lines for NTSC systems */ +#define SNES_VTOTAL_PAL 312 /* Maximum number of lines for PAL systems */ +#define SNES_HTOTAL 341 /* Maximum number pixels per line (incl. hblank) */ + +#define SNES_NTSC 0x00 +#define SNES_PAL 0x10 + + +#define SNES_LAYER_DEBUG 0 + + +/* offset-per-tile modes */ +enum +{ + SNES_OPT_NONE = 0, + SNES_OPT_MODE2, + SNES_OPT_MODE4, + SNES_OPT_MODE6 +}; + +/* layers */ +enum +{ + SNES_BG1 = 0, + SNES_BG2, + SNES_BG3, + SNES_BG4, + SNES_OAM, + SNES_COLOR +}; + + +struct SNES_SCANLINE +{ + int enable, clip; + + UINT16 buffer[SNES_SCR_WIDTH]; + UINT8 priority[SNES_SCR_WIDTH]; + UINT8 layer[SNES_SCR_WIDTH]; + UINT8 blend_exception[SNES_SCR_WIDTH]; +}; + +// ======================> snes_ppu_device + +class snes_ppu_device : public device_t, + public device_video_interface +{ +public: + // construction/destruction + snes_ppu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // inline configuration helpers + template static devcb_base &static_set_open_bus_callback(device_t &device, _Object object) { return downcast(device).m_openbus_cb.set_callback(object); } + + UINT8 m_regs[0x40]; + + SNES_SCANLINE m_scanlines[2]; + + struct + { + /* clipmasks */ + UINT8 window1_enabled, window1_invert; + UINT8 window2_enabled, window2_invert; + UINT8 wlog_mask; + /* color math enabled */ + UINT8 color_math; + + UINT8 charmap; + UINT8 tilemap; + UINT8 tilemap_size; + + UINT8 tile_size; + UINT8 mosaic_enabled; // actually used only for layers 0->3! + + UINT8 main_window_enabled; + UINT8 sub_window_enabled; + UINT8 main_bg_enabled; + UINT8 sub_bg_enabled; + + UINT16 hoffs; + UINT16 voffs; + } m_layer[6]; // this is for the BG1 - BG2 - BG3 - BG4 - OBJ - color layers + + struct + { + UINT8 address_low; + UINT8 address_high; + UINT8 saved_address_low; + UINT8 saved_address_high; + UINT16 address; + UINT16 priority_rotation; + UINT8 next_charmap; + UINT8 next_size; + UINT8 size; + UINT32 next_name_select; + UINT32 name_select; + UINT8 first_sprite; + UINT8 flip; + UINT16 write_latch; + } m_oam; + + struct + { + UINT16 latch_horz; + UINT16 latch_vert; + UINT16 current_vert; + UINT8 last_visible_line; + UINT8 interlace_count; + } m_beam; + + struct + { + UINT8 repeat; + UINT8 hflip; + UINT8 vflip; + INT16 matrix_a; + INT16 matrix_b; + INT16 matrix_c; + INT16 matrix_d; + INT16 origin_x; + INT16 origin_y; + UINT16 hor_offset; + UINT16 ver_offset; + UINT8 extbg; + } m_mode7; + + struct OAM + { + UINT16 tile; + INT16 x, y; + UINT8 size, vflip, hflip, priority_bits, pal; + int height, width; + }; + + struct OAM m_oam_spritelist[SNES_SCR_WIDTH / 2]; + + UINT8 m_oam_itemlist[32]; + + struct TILELIST { + INT16 x; + UINT16 priority, pal, tileaddr; + int hflip; + }; + + struct TILELIST m_oam_tilelist[34]; + +#if SNES_LAYER_DEBUG + struct DEBUGOPTS + { + UINT8 bg_disabled[5]; + UINT8 mode_disabled[8]; + UINT8 draw_subscreen; + UINT8 windows_disabled; + UINT8 mosaic_disabled; + UINT8 colormath_disabled; + UINT8 sprite_reversed; + UINT8 select_pri[5]; + }; + struct DEBUGOPTS m_debug_options; +#endif + + UINT8 m_mosaic_size; + UINT8 m_clip_to_black; + UINT8 m_prevent_color_math; + UINT8 m_sub_add_mode; + UINT8 m_bg3_priority_bit; + UINT8 m_direct_color; + UINT8 m_ppu_last_scroll; /* as per Anomie's doc and Theme Park, all scroll regs shares (but mode 7 ones) the same + 'previous' scroll value */ + UINT8 m_mode7_last_scroll; /* as per Anomie's doc mode 7 scroll regs use a different value, shared with mode 7 matrix! */ + + UINT8 m_ppu1_open_bus, m_ppu2_open_bus; + UINT8 m_ppu1_version, m_ppu2_version; + UINT8 m_window1_left, m_window1_right, m_window2_left, m_window2_right; + + UINT16 m_mosaic_table[16][4096]; + UINT8 m_clipmasks[6][SNES_SCR_WIDTH]; + UINT8 m_update_windows; + UINT8 m_update_offsets; + UINT8 m_update_oam_list; + UINT8 m_mode; + UINT8 m_interlace; //doubles the visible resolution + UINT8 m_obj_interlace; + UINT8 m_screen_brightness; + UINT8 m_screen_disabled; + UINT8 m_pseudo_hires; + UINT8 m_color_modes; + UINT8 m_stat77; + UINT8 m_stat78; + + UINT16 m_htmult; /* in 512 wide, we run HTOTAL double and halve it on latching */ + UINT16 m_cgram_address; /* CGRAM address */ + UINT8 m_read_ophct; + UINT8 m_read_opvct; + UINT16 m_vram_fgr_high; + UINT16 m_vram_fgr_increment; + UINT16 m_vram_fgr_count; + UINT16 m_vram_fgr_mask; + UINT16 m_vram_fgr_shift; + UINT16 m_vram_read_buffer; + UINT16 m_vmadd; + + inline UINT16 get_bgcolor(UINT8 direct_colors, UINT16 palette, UINT8 color); + inline void set_scanline_pixel(int screen, INT16 x, UINT16 color, UINT8 priority, UINT8 layer, int blend); + inline void draw_bgtile_lores(UINT8 layer, INT16 ii, UINT8 colour, UINT16 pal, UINT8 direct_colors, UINT8 priority); + inline void draw_bgtile_hires(UINT8 layer, INT16 ii, UINT8 colour, UINT16 pal, UINT8 direct_colors, UINT8 priority); + inline void draw_oamtile(INT16 ii, UINT8 colour, UINT16 pal, UINT8 priority); + inline void draw_tile(UINT8 planes, UINT8 layer, UINT32 tileaddr, INT16 x, UINT8 priority, UINT8 flip, UINT8 direct_colors, UINT16 pal, UINT8 hires); + inline UINT32 get_tmap_addr(UINT8 layer, UINT8 tile_size, UINT32 base, UINT32 x, UINT32 y); + inline void update_line(UINT16 curline, UINT8 layer, UINT8 priority_b, UINT8 priority_a, UINT8 color_depth, UINT8 hires, UINT8 offset_per_tile, UINT8 direct_colors); + void update_line_mode7(UINT16 curline, UINT8 layer, UINT8 priority_b, UINT8 priority_a); + void update_obsel(void); + void oam_list_build(void); + int is_sprite_on_scanline(UINT16 curline, UINT8 sprite); + void update_objects_rto(UINT16 curline); + void update_objects(UINT8 priority_oam0, UINT8 priority_oam1, UINT8 priority_oam2, UINT8 priority_oam3); + void update_mode_0(UINT16 curline); + void update_mode_1(UINT16 curline); + void update_mode_2(UINT16 curline); + void update_mode_3(UINT16 curline); + void update_mode_4(UINT16 curline); + void update_mode_5(UINT16 curline); + void update_mode_6(UINT16 curline); + void update_mode_7(UINT16 curline); + void draw_screens(UINT16 curline); + void update_windowmasks(void); + void update_offsets(void); + inline void draw_blend(UINT16 offset, UINT16 *colour, UINT8 prevent_color_math, UINT8 black_pen_clip, int switch_screens); + void refresh_scanline(bitmap_rgb32 &bitmap, UINT16 curline); + + inline INT16 current_x() { return m_screen->hpos() / m_htmult; } + inline INT16 current_y() { return m_screen->vpos(); } + void set_latch_hv(INT16 x, INT16 y); + void dynamic_res_change(); + inline UINT32 get_vram_address(); + UINT8 dbg_video(UINT16 curline); + + UINT8 read(address_space &space, UINT32 offset, UINT8 wrio_bit7); + void write(address_space &space, UINT32 offset, UINT8 data); + + DECLARE_READ8_MEMBER( oam_read ); + DECLARE_WRITE8_MEMBER( oam_write ); + DECLARE_READ8_MEMBER( cgram_read ); + DECLARE_WRITE8_MEMBER( cgram_write ); + DECLARE_READ8_MEMBER( vram_read ); + DECLARE_WRITE8_MEMBER( vram_write ); + UINT16 *m_oam_ram; /* Object Attribute Memory */ + UINT16 *m_cgram; /* Palette RAM */ + UINT8 *m_vram; /* Video RAM (TODO: Should be 16-bit, but it's easier this way) */ + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + +private: + devcb_read16 m_openbus_cb; +}; + + +// device type definition +extern const device_type SNES_PPU; + + +/*************************************************************************** + INTERFACE CONFIGURATION MACROS + ***************************************************************************/ + +#define MCFG_SNES_PPU_OPENBUS_CB(_read) \ + devcb = &snes_ppu_device::static_set_open_bus_callback(*device, DEVCB_##_read); + +#endif diff --git a/src/devices/video/stvvdp1.c b/src/devices/video/stvvdp1.c new file mode 100644 index 00000000000..126089d40b5 --- /dev/null +++ b/src/devices/video/stvvdp1.c @@ -0,0 +1,2160 @@ +// license:LGPL-2.1+ +// copyright-holders:David Haywood, Angelo Salese, Olivier Galibert, Mariusz Wojcieszek, R. Belmont +/* + +STV - VDP1 + +the vdp1 draws to the FRAMEBUFFER which is mapped in memory + +Framebuffer todo: +- finish manual erase +- add proper framebuffer erase +- 8 bpp support - now we always draw as 16 bpp, but this is not a problem since + VDP2 interprets framebuffer as 8 bpp in these cases + +*/ + + +#include "emu.h" +#include "includes/stv.h" + +#define VDP1_LOG 0 + + +enum { FRAC_SHIFT = 16 }; + +struct spoint { + INT32 x, y; + INT32 u, v; +}; + +struct shaded_point +{ + INT32 x,y; + INT32 r,g,b; +}; + +#define RGB_R(_color) (_color & 0x1f) +#define RGB_G(_color) ((_color >> 5) & 0x1f) +#define RGB_B(_color) ((_color >> 10) & 0x1f) + +#define SWAP_INT32(_a,_b) \ + { \ + INT32 t; \ + t = _a; \ + _a = _b; \ + _b = t; \ + } + +#define SWAP_INT32PTR(_p1, _p2) \ + { \ + INT32 *p; \ + p = _p1; \ + _p1 = _p2; \ + _p2 = p; \ + } + +/*TV Mode Selection Register */ +/* + xxxx xxxx xxxx ---- | UNUSED + ---- ---- ---- x--- | VBlank Erase/Write (VBE) + ---- ---- ---- -xxx | TV Mode (TVM) + TV-Mode: + This sets the Frame Buffer size,the rotation of the Frame Buffer & the bit width. + bit 2 HDTV disable(0)/enable(1) + bit 1 non-rotation/rotation(1) + bit 0 16(0)/8(1) bits per pixel + Size of the Frame Buffer: + 7 invalid + 6 invalid + 5 invalid + 4 512x256 + 3 512x512 + 2 512x256 + 1 1024x256 + 0 512x256 +*/ + +/*Frame Buffer Change Mode Register*/ +/* + xxxx xxxx xxx- ---- | UNUSED + ---- ---- ---x ---- | Even/Odd Coordinate Select Bit (EOS) + ---- ---- ---- x--- | Double Interlace Mode (DIE) + ---- ---- ---- -x-- | Double Interlace Draw Line (DIL) + ---- ---- ---- --x- | Frame Buffer Change Trigger (FCM) + ---- ---- ---- ---x | Frame Buffer Change Mode (FCT) +*/ +#define STV_VDP1_FBCR ((m_vdp1_regs[0x002/2] >> 0)&0xffff) +#define STV_VDP1_EOS ((STV_VDP1_FBCR & 0x0010) >> 4) +#define STV_VDP1_DIE ((STV_VDP1_FBCR & 0x0008) >> 3) +#define STV_VDP1_DIL ((STV_VDP1_FBCR & 0x0004) >> 2) +#define STV_VDP1_FCM ((STV_VDP1_FBCR & 0x0002) >> 1) +#define STV_VDP1_FCT ((STV_VDP1_FBCR & 0x0001) >> 0) + +/*Plot Trigger Register*/ +/* + xxxx xxxx xxxx xx-- | UNUSED + ---- ---- ---- --xx | Plot Trigger Mode (PTM) + + Plot Trigger Mode: + 3 Invalid + 2 Automatic draw + 1 VDP1 draw by request + 0 VDP1 Idle (no access) +*/ +#define STV_VDP1_PTMR ((m_vdp1_regs[0x004/2])&0xffff) +#define STV_VDP1_PTM ((STV_VDP1_PTMR & 0x0003) >> 0) +#define PTM_0 m_vdp1_regs[0x004/2]&=~0x0001 + +/* + Erase/Write Data Register + 16 bpp = data + 8 bpp = erase/write data for even/odd X coordinates +*/ +#define STV_VDP1_EWDR ((m_vdp1_regs[0x006/2])&0xffff) + +/*Erase/Write Upper-Left register*/ +/* + x--- ---- ---- ---- | UNUSED + -xxx xxx- ---- ---- | X1 register + ---- ---x xxxx xxxx | Y1 register + +*/ +#define STV_VDP1_EWLR ((m_vdp1_regs[0x008/2])&0xffff) +#define STV_VDP1_EWLR_X1 ((STV_VDP1_EWLR & 0x7e00) >> 9) +#define STV_VDP1_EWLR_Y1 ((STV_VDP1_EWLR & 0x01ff) >> 0) +/*Erase/Write Lower-Right register*/ +/* + xxxx xxx- ---- ---- | X3 register + ---- ---x xxxx xxxx | Y3 register + +*/ +#define STV_VDP1_EWRR ((m_vdp1_regs[0x00a/2])&0xffff) +#define STV_VDP1_EWRR_X3 ((STV_VDP1_EWRR & 0xfe00) >> 9) +#define STV_VDP1_EWRR_Y3 ((STV_VDP1_EWRR & 0x01ff) >> 0) +/*Transfer End Status Register*/ +/* + xxxx xxxx xxxx xx-- | UNUSED + ---- ---- ---- --x- | CEF + ---- ---- ---- ---x | BEF + +*/ +#define STV_VDP1_EDSR ((m_vdp1_regs[0x010/2])&0xffff) +#define STV_VDP1_CEF (STV_VDP1_EDSR & 2) +#define STV_VDP1_BEF (STV_VDP1_EDSR & 1) +/**/ + + + +READ16_MEMBER( saturn_state::saturn_vdp1_regs_r ) +{ + //logerror ("cpu %s (PC=%08X) VDP1: Read from Registers, Offset %04x\n", space.device().tag(), space.device().safe_pc(), offset); + + switch(offset) + { + case 0x02/2: + return 0; + case 0x10/2: + break; + case 0x12/2: return m_vdp1.lopr; + case 0x14/2: return m_vdp1.copr; + /* MODR register, read register for the other VDP1 regs + (Shienryu SS version abuses of this during intro) */ + case 0x16/2: + UINT16 modr; + + modr = 0x1000; //vdp1 VER + modr |= (STV_VDP1_PTM >> 1) << 8; // PTM1 + modr |= STV_VDP1_EOS << 7; // EOS + modr |= STV_VDP1_DIE << 6; // DIE + modr |= STV_VDP1_DIL << 5; // DIL + modr |= STV_VDP1_FCM << 4; //FCM + modr |= STV_VDP1_VBE << 3; //VBE + modr |= STV_VDP1_TVM & 7; //TVM + + return modr; + default: + if(!space.debugger_access()) + printf ("cpu %s (PC=%08X) VDP1: Read from Registers, Offset %04x\n", space.device().tag(), space.device().safe_pc(), offset*2); + break; + } + + return m_vdp1_regs[offset]; //TODO: write-only regs should return open bus or zero +} + +/* TODO: TVM & 1 is just a kludgy work-around, the VDP1 actually needs to be rewritten from scratch. */ +/* Daisenryaku Strong Style (daisenss) uses it */ +void saturn_state::stv_clear_framebuffer( int which_framebuffer ) +{ + int start_x, end_x, start_y, end_y; + + start_x = STV_VDP1_EWLR_X1 * ((STV_VDP1_TVM & 1) ? 16 : 8); + start_y = STV_VDP1_EWLR_Y1 * (m_vdp1.framebuffer_double_interlace+1); + end_x = STV_VDP1_EWRR_X3 * ((STV_VDP1_TVM & 1) ? 16 : 8); + end_y = (STV_VDP1_EWRR_Y3+1) * (m_vdp1.framebuffer_double_interlace+1); +// popmessage("%d %d %d %d %d",STV_VDP1_EWLR_X1,STV_VDP1_EWLR_Y1,STV_VDP1_EWRR_X3,STV_VDP1_EWRR_Y3,m_vdp1.framebuffer_double_interlace); + + if(STV_VDP1_TVM & 1) + { + for(int y=start_y;y 0xdf) && ((offset * 4) < 0x140)) +// { +// logerror("cpu %s (PC=%08X): VRAM dword write to %08X = %08X & %08X\n", space.device().tag(), space.device().safe_pc(), offset*4, data, mem_mask); +// } + + data = m_vdp1_vram[offset]; + /* put in gfx region for easy decoding */ + vdp1[offset*4+0] = (data & 0xff000000) >> 24; + vdp1[offset*4+1] = (data & 0x00ff0000) >> 16; + vdp1[offset*4+2] = (data & 0x0000ff00) >> 8; + vdp1[offset*4+3] = (data & 0x000000ff) >> 0; +} + +WRITE32_MEMBER ( saturn_state::saturn_vdp1_framebuffer0_w ) +{ + //popmessage ("STV VDP1 Framebuffer 0 WRITE offset %08x data %08x",offset, data); + if ( STV_VDP1_TVM & 1 ) + { + /* 8-bit mode */ + //printf("VDP1 8-bit mode %08x %02x\n",offset,data); + if ( ACCESSING_BITS_24_31 ) + { + m_vdp1.framebuffer[m_vdp1.framebuffer_current_draw][offset*2] &= 0x00ff; + m_vdp1.framebuffer[m_vdp1.framebuffer_current_draw][offset*2] |= data & 0xff00; + } + if ( ACCESSING_BITS_16_23 ) + { + m_vdp1.framebuffer[m_vdp1.framebuffer_current_draw][offset*2] &= 0xff00; + m_vdp1.framebuffer[m_vdp1.framebuffer_current_draw][offset*2] |= data & 0x00ff; + } + if ( ACCESSING_BITS_8_15 ) + { + m_vdp1.framebuffer[m_vdp1.framebuffer_current_draw][offset*2+1] &= 0x00ff; + m_vdp1.framebuffer[m_vdp1.framebuffer_current_draw][offset*2+1] |= data & 0xff00; + } + if ( ACCESSING_BITS_0_7 ) + { + m_vdp1.framebuffer[m_vdp1.framebuffer_current_draw][offset*2+1] &= 0xff00; + m_vdp1.framebuffer[m_vdp1.framebuffer_current_draw][offset*2+1] |= data & 0x00ff; + } + } + else + { + /* 16-bit mode */ + if ( ACCESSING_BITS_16_31 ) + { + m_vdp1.framebuffer[m_vdp1.framebuffer_current_draw][offset*2] = (data >> 16) & 0xffff; + } + if ( ACCESSING_BITS_0_15 ) + { + m_vdp1.framebuffer[m_vdp1.framebuffer_current_draw][offset*2+1] = data & 0xffff; + } + } +} + +READ32_MEMBER ( saturn_state::saturn_vdp1_framebuffer0_r ) +{ + UINT32 result = 0; + //popmessage ("STV VDP1 Framebuffer 0 READ offset %08x",offset); + if ( STV_VDP1_TVM & 1 ) + { + /* 8-bit mode */ + //printf("VDP1 8-bit mode %08x\n",offset); + if ( ACCESSING_BITS_24_31 ) + result |= ((m_vdp1.framebuffer[m_vdp1.framebuffer_current_draw][offset*2] & 0xff00) << 16); + if ( ACCESSING_BITS_16_23 ) + result |= ((m_vdp1.framebuffer[m_vdp1.framebuffer_current_draw][offset*2] & 0x00ff) << 16); + if ( ACCESSING_BITS_8_15 ) + result |= ((m_vdp1.framebuffer[m_vdp1.framebuffer_current_draw][offset*2+1] & 0xff00)); + if ( ACCESSING_BITS_0_7 ) + result |= ((m_vdp1.framebuffer[m_vdp1.framebuffer_current_draw][offset*2+1] & 0x00ff)); + } + else + { + /* 16-bit mode */ + if ( ACCESSING_BITS_16_31 ) + { + result |= (m_vdp1.framebuffer[m_vdp1.framebuffer_current_draw][offset*2] << 16); + } + if ( ACCESSING_BITS_0_15 ) + { + result |= (m_vdp1.framebuffer[m_vdp1.framebuffer_current_draw][offset*2+1]); + } + + } + + return result; +} + +#ifdef UNUSED_FUNCTION +WRITE32_MEMBER ( saturn_state::saturn_vdp1_framebuffer1_w ) +{ + //popmessage ("STV VDP1 Framebuffer 1 WRITE offset %08x data %08x",offset, data); +} + +READ32_MEMBER ( saturn_state::saturn_vdp1_framebuffer1_r ) +{ + //popmessage ("STV VDP1 Framebuffer 1 READ offset %08x",offset); + return 0xffff; +} +#endif + + +/* + +there is a command every 0x20 bytes +the first word is the control word +the rest are data used by it + +--- +00 CMDCTRL + e--- ---- ---- ---- | end bit (15) + -jjj ---- ---- ---- | jump select bits (12-14) + ---- zzzz ---- ---- | zoom point / hotspot (8-11) + ---- ---- 00-- ---- | UNUSED + ---- ---- --dd ---- | character read direction (4,5) + ---- ---- ---- cccc | command bits (0-3) + +02 CMDLINK + llll llll llll ll-- | link + ---- ---- ---- --00 | UNUSED + +04 CMDPMOD + m--- ---- ---- ---- | MON (looks at MSB and apply shadows etc.) + -00- ---- ---- ---- | UNUSED + ---h ---- ---- ---- | HSS (High Speed Shrink) + ---- p--- ---- ---- | PCLIP (Pre Clipping Disable) + ---- -c-- ---- ---- | CLIP (Clipping Mode Bit) + ---- --m- ---- ---- | CMOD (User Clipping Enable Bit) + ---- ---M ---- ---- | MESH (Mesh Enable Bit) + ---- ---- e--- ---- | ECD (End Code Disable) + ---- ---- -S-- ---- | SPD (Transparent Pixel Disable) + ---- ---- --cc c--- | Colour Mode + ---- ---- ---- -CCC | Colour Calculation bits + +06 CMDCOLR + mmmm mmmm mmmm mmmm | Colour Bank, Colour Lookup /8 + +08 CMDSRCA (Character Address) + aaaa aaaa aaaa aa-- | Character Address + ---- ---- ---- --00 | UNUSED + +0a CMDSIZE (Character Size) + 00-- ---- ---- ---- | UNUSED + --xx xxxx ---- ---- | Character Size (X) + ---- ---- yyyy yyyy | Character Size (Y) + +0c CMDXA (used for normal sprite) + eeee ee-- ---- ---- | extension bits + ---- --xx xxxx xxxx | x position + +0e CMDYA (used for normal sprite) + eeee ee-- ---- ---- | extension bits + ---- --yy yyyy yyyy | y position + +10 CMDXB +12 CMDYB +14 CMDXC +16 CMDYC +18 CMDXD +1a CMDYD +1c CMDGRDA (Gouraud Shading Table) +1e UNUSED +--- + + +*/ + +void saturn_state::stv_clear_gouraud_shading(void) +{ + memset( &stv_gouraud_shading, 0, sizeof( stv_gouraud_shading ) ); +} + +UINT8 saturn_state::stv_read_gouraud_table( void ) +{ + int gaddr; + + if ( (stv2_current_sprite.CMDPMOD & 0x7) == 4 ) + { + gaddr = stv2_current_sprite.CMDGRDA * 8; + stv_gouraud_shading.GA = (m_vdp1_vram[gaddr/4] >> 16) & 0xffff; + stv_gouraud_shading.GB = (m_vdp1_vram[gaddr/4] >> 0) & 0xffff; + stv_gouraud_shading.GC = (m_vdp1_vram[gaddr/4 + 1] >> 16) & 0xffff; + stv_gouraud_shading.GD = (m_vdp1_vram[gaddr/4 + 1] >> 0) & 0xffff; + return 1; + } + else + { + return 0; + } +} + +INLINE INT32 _shading( INT32 color, INT32 correction ) +{ + correction = (correction >> 16) & 0x1f; + color += (correction - 16); + + if ( color < 0 ) color = 0; + if ( color > 0x1f ) color = 0x1f; + + return color; +} + +UINT16 saturn_state::stv_vdp1_apply_gouraud_shading( int x, int y, UINT16 pix ) +{ + INT32 r,g,b, msb; + + msb = pix & 0x8000; + +#ifdef MAME_DEBUG + if ( (stv_vdp1_shading_data->scanline[y].x[0] >> 16) != x ) + { + logerror( "ERROR in computing x coordinates (line %d, x = %x, %d, xc = %x, %d)\n", y, x, x, stv_vdp1_shading_data->scanline[y].x[0], stv_vdp1_shading_data->scanline[y].x[0] >> 16 ); + }; +#endif + + b = RGB_B(pix); + g = RGB_G(pix); + r = RGB_R(pix); + + b = _shading( b, stv_vdp1_shading_data->scanline[y].b[0] ); + g = _shading( g, stv_vdp1_shading_data->scanline[y].g[0] ); + r = _shading( r, stv_vdp1_shading_data->scanline[y].r[0] ); + + stv_vdp1_shading_data->scanline[y].b[0] += stv_vdp1_shading_data->scanline[y].db; + stv_vdp1_shading_data->scanline[y].g[0] += stv_vdp1_shading_data->scanline[y].dg; + stv_vdp1_shading_data->scanline[y].r[0] += stv_vdp1_shading_data->scanline[y].dr; + + stv_vdp1_shading_data->scanline[y].x[0] += 1 << FRAC_SHIFT; + + return msb | b << 10 | g << 5 | r; +} + +void saturn_state::stv_vdp1_setup_shading_for_line(INT32 y, INT32 x1, INT32 x2, + INT32 r1, INT32 g1, INT32 b1, + INT32 r2, INT32 g2, INT32 b2) +{ + int xx1 = x1>>FRAC_SHIFT; + int xx2 = x2>>FRAC_SHIFT; + + + if ( xx1 > xx2 ) + { + SWAP_INT32(xx1, xx2); + SWAP_INT32(r1, r2); + SWAP_INT32(g1, g2); + SWAP_INT32(b1, b2); + } + + if ( (y >= 0) && (y < 512) ) + { + INT32 dx; + INT32 gbd, ggd, grd; + + dx = xx2 - xx1; + + if ( dx == 0 ) + { + gbd = ggd = grd = 0; + } + else + { + gbd = abs(b2 - b1) / dx; + if (b2 < b1) gbd = -gbd; + ggd = abs(g2 - g1) / dx; + if (g2 < g1) ggd = -ggd; + grd = abs(r2 - r1) / dx; + if (r2 < r1) grd = -grd; + } + + stv_vdp1_shading_data->scanline[y].x[0] = x1; + stv_vdp1_shading_data->scanline[y].x[1] = x2; + + stv_vdp1_shading_data->scanline[y].b[0] = b1; + stv_vdp1_shading_data->scanline[y].g[0] = g1; + stv_vdp1_shading_data->scanline[y].r[0] = r1; + stv_vdp1_shading_data->scanline[y].b[1] = b2; + stv_vdp1_shading_data->scanline[y].g[1] = g2; + stv_vdp1_shading_data->scanline[y].r[1] = r2; + + stv_vdp1_shading_data->scanline[y].db = gbd; + stv_vdp1_shading_data->scanline[y].dg = ggd; + stv_vdp1_shading_data->scanline[y].dr = grd; + + } +} + +void saturn_state::stv_vdp1_setup_shading_for_slope( + INT32 x1, INT32 x2, INT32 sl1, INT32 sl2, INT32 *nx1, INT32 *nx2, + INT32 r1, INT32 r2, INT32 slr1, INT32 slr2, INT32 *nr1, INT32 *nr2, + INT32 g1, INT32 g2, INT32 slg1, INT32 slg2, INT32 *ng1, INT32 *ng2, + INT32 b1, INT32 b2, INT32 slb1, INT32 slb2, INT32 *nb1, INT32 *nb2, + INT32 _y1, INT32 y2) +{ + if(x1 > x2 || (x1==x2 && sl1 > sl2)) { + SWAP_INT32(x1,x2); + SWAP_INT32(sl1,sl2); + SWAP_INT32PTR(nx1, nx2); + SWAP_INT32(r1,r2); + SWAP_INT32(slr1, slr2); + SWAP_INT32PTR(nr1, nr2); + SWAP_INT32(g1, g2); + SWAP_INT32(slg1, slg2); + SWAP_INT32PTR(ng1, ng2); + SWAP_INT32(b1, b2); + SWAP_INT32(slb1, slb2); + SWAP_INT32PTR(nb1, nb2); + } + + while(_y1 < y2) + { + stv_vdp1_setup_shading_for_line(_y1, x1, x2, r1, g1, b1, r2, g2, b2); + x1 += sl1; + r1 += slr1; + g1 += slg1; + b1 += slb1; + + x2 += sl2; + r2 += slr2; + g2 += slg2; + b2 += slb2; + _y1++; + } + *nx1 = x1; + *nr1 = r1; + *ng1 = g1; + *nb1 = b1; + + *nx2 = x2; + *nr2 = r2; + *nb2 = b2; + *ng2 = g2; +} + +void saturn_state::stv_vdp1_setup_shading(const struct spoint* q, const rectangle &cliprect) +{ + INT32 x1, x2, delta, cury, limy; + INT32 r1, g1, b1, r2, g2, b2; + INT32 sl1, slg1, slb1, slr1; + INT32 sl2, slg2, slb2, slr2; + int pmin, pmax, i, ps1, ps2; + struct shaded_point p[8]; + UINT16 gd[4]; + + if ( stv_read_gouraud_table() == 0 ) return; + + gd[0] = stv_gouraud_shading.GA; + gd[1] = stv_gouraud_shading.GB; + gd[2] = stv_gouraud_shading.GC; + gd[3] = stv_gouraud_shading.GD; + + for(i=0; i<4; i++) { + p[i].x = p[i+4].x = q[i].x << FRAC_SHIFT; + p[i].y = p[i+4].y = q[i].y; + p[i].r = p[i+4].r = RGB_R(gd[i]) << FRAC_SHIFT; + p[i].g = p[i+4].g = RGB_G(gd[i]) << FRAC_SHIFT; + p[i].b = p[i+4].b = RGB_B(gd[i]) << FRAC_SHIFT; + } + + pmin = pmax = 0; + for(i=1; i<4; i++) { + if(p[i].y < p[pmin].y) + pmin = i; + if(p[i].y > p[pmax].y) + pmax = i; + } + + cury = p[pmin].y; + limy = p[pmax].y; + + stv_vdp1_shading_data->sy = cury; + stv_vdp1_shading_data->ey = limy; + + if(cury == limy) { + x1 = x2 = p[0].x; + ps1 = ps2 = 0; + for(i=1; i<4; i++) { + if(p[i].x < x1) { + x1 = p[i].x; + ps1 = i; + } + if(p[i].x > x2) { + x2 = p[i].x; + ps2 = i; + } + } + stv_vdp1_setup_shading_for_line(cury, x1, x2, p[ps1].r, p[ps1].g, p[ps1].b, p[ps2].r, p[ps2].g, p[ps2].b); + goto finish; + } + + ps1 = pmin+4; + ps2 = pmin; + + goto startup; + + for(;;) { + if(p[ps1-1].y == p[ps2+1].y) { + stv_vdp1_setup_shading_for_slope( + x1, x2, sl1, sl2, &x1, &x2, + r1, r2, slr1, slr2, &r1, &r2, + g1, g2, slg1, slg2, &g1, &g2, + b1, b2, slb1, slb2, &b1, &b2, + cury, p[ps1-1].y); + cury = p[ps1-1].y; + if(cury >= limy) + break; + ps1--; + ps2++; + + startup: + while(p[ps1-1].y == cury) + ps1--; + while(p[ps2+1].y == cury) + ps2++; + x1 = p[ps1].x; + r1 = p[ps1].r; + g1 = p[ps1].g; + b1 = p[ps1].b; + x2 = p[ps2].x; + r2 = p[ps2].r; + g2 = p[ps2].g; + b2 = p[ps2].b; + + delta = cury-p[ps1-1].y; + sl1 = (x1-p[ps1-1].x)/delta; + slr1 = (r1-p[ps1-1].r)/delta; + slg1 = (g1-p[ps1-1].g)/delta; + slb1 = (b1-p[ps1-1].b)/delta; + + delta = cury-p[ps2+1].y; + sl2 = (x2-p[ps2+1].x)/delta; + slr2 = (r2-p[ps2+1].r)/delta; + slg2 = (g2-p[ps2+1].g)/delta; + slb2 = (b2-p[ps2+1].b)/delta; + } else if(p[ps1-1].y < p[ps2+1].y) { + stv_vdp1_setup_shading_for_slope( + x1, x2, sl1, sl2, &x1, &x2, + r1, r2, slr1, slr2, &r1, &r2, + g1, g2, slg1, slg2, &g1, &g2, + b1, b2, slb1, slb2, &b1, &b2, + cury, p[ps1-1].y); + cury = p[ps1-1].y; + if(cury >= limy) + break; + ps1--; + while(p[ps1-1].y == cury) + ps1--; + x1 = p[ps1].x; + r1 = p[ps1].r; + g1 = p[ps1].g; + b1 = p[ps1].b; + + delta = cury-p[ps1-1].y; + sl1 = (x1-p[ps1-1].x)/delta; + slr1 = (r1-p[ps1-1].r)/delta; + slg1 = (g1-p[ps1-1].g)/delta; + slb1 = (b1-p[ps1-1].b)/delta; + } else { + stv_vdp1_setup_shading_for_slope( + x1, x2, sl1, sl2, &x1, &x2, + r1, r2, slr1, slr2, &r1, &r2, + g1, g2, slg1, slg2, &g1, &g2, + b1, b2, slb1, slb2, &b1, &b2, + cury, p[ps2+1].y); + cury = p[ps2+1].y; + if(cury >= limy) + break; + ps2++; + while(p[ps2+1].y == cury) + ps2++; + x2 = p[ps2].x; + r2 = p[ps2].r; + g2 = p[ps2].g; + b2 = p[ps2].b; + + delta = cury-p[ps2+1].y; + sl2 = (x2-p[ps2+1].x)/delta; + slr2 = (r2-p[ps2+1].r)/delta; + slg2 = (g2-p[ps2+1].g)/delta; + slb2 = (b2-p[ps2+1].b)/delta; + } + } + if(cury == limy) + stv_vdp1_setup_shading_for_line(cury, x1, x2, r1, g1, b1, r2, g2, b2 ); + +finish: + + if ( stv_vdp1_shading_data->sy < 0 ) stv_vdp1_shading_data->sy = 0; + if ( stv_vdp1_shading_data->sy >= 512 ) return; + if ( stv_vdp1_shading_data->ey < 0 ) return; + if ( stv_vdp1_shading_data->ey >= 512 ) stv_vdp1_shading_data->ey = 511; + + for ( cury = stv_vdp1_shading_data->sy; cury <= stv_vdp1_shading_data->ey; cury++ ) + { + while( (stv_vdp1_shading_data->scanline[cury].x[0] >> 16) < cliprect.min_x ) + { + stv_vdp1_shading_data->scanline[cury].x[0] += (1 << FRAC_SHIFT); + stv_vdp1_shading_data->scanline[cury].b[0] += stv_vdp1_shading_data->scanline[cury].db; + stv_vdp1_shading_data->scanline[cury].g[0] += stv_vdp1_shading_data->scanline[cury].dg; + stv_vdp1_shading_data->scanline[cury].r[0] += stv_vdp1_shading_data->scanline[cury].dr; + } + } + +} + +/* note that if we're drawing +to the framebuffer we CAN'T frameskip the vdp1 drawing as the hardware can READ the framebuffer +and if we skip the drawing the content could be incorrect when it reads it, although i have no idea +why they would want to */ + + + +void saturn_state::drawpixel_poly(int x, int y, int patterndata, int offsetcnt) +{ + /* Capcom Collection Dai 4 uses a dummy polygon to clear VDP1 framebuffer that goes over our current max size ... */ + if(x >= 1024 || y >= 512) + return; + + m_vdp1.framebuffer_draw_lines[y][x] = stv2_current_sprite.CMDCOLR; +} + +void saturn_state::drawpixel_8bpp_trans(int x, int y, int patterndata, int offsetcnt) +{ + UINT16 pix; + + pix = m_vdp1.gfx_decode[patterndata+offsetcnt]; + if ( pix & 0xff ) + { + m_vdp1.framebuffer_draw_lines[y][x] = pix | m_sprite_colorbank; + } +} + +void saturn_state::drawpixel_4bpp_notrans(int x, int y, int patterndata, int offsetcnt) +{ + UINT16 pix; + + pix = m_vdp1.gfx_decode[patterndata+offsetcnt/2]; + pix = offsetcnt&1 ? (pix & 0x0f) : ((pix & 0xf0)>>4); + m_vdp1.framebuffer_draw_lines[y][x] = pix | m_sprite_colorbank; +} + +void saturn_state::drawpixel_4bpp_trans(int x, int y, int patterndata, int offsetcnt) +{ + UINT16 pix; + + pix = m_vdp1.gfx_decode[patterndata+offsetcnt/2]; + pix = offsetcnt&1 ? (pix & 0x0f) : ((pix & 0xf0)>>4); + if ( pix ) + m_vdp1.framebuffer_draw_lines[y][x] = pix | m_sprite_colorbank; +} + +void saturn_state::drawpixel_generic(int x, int y, int patterndata, int offsetcnt) +{ + int pix,mode,transmask, spd = stv2_current_sprite.CMDPMOD & 0x40; + int mesh = stv2_current_sprite.CMDPMOD & 0x100; + int pix2; + + if ( mesh && !((x ^ y) & 1) ) + { + return; + } + + if ( stv2_current_sprite.ispoly ) + { + pix = stv2_current_sprite.CMDCOLR&0xffff; + + transmask = 0xffff; + if ( pix & 0x8000 ) + { + mode = 5; + } + else + { + mode = 1; + } + } + else + { + switch (stv2_current_sprite.CMDPMOD&0x0038) + { + case 0x0000: // mode 0 16 colour bank mode (4bits) (hanagumi blocks) + // most of the shienryu sprites use this mode + pix = m_vdp1.gfx_decode[(patterndata+offsetcnt/2) & 0xfffff]; + pix = offsetcnt&1 ? (pix & 0x0f) : ((pix & 0xf0)>>4); + pix = pix+((stv2_current_sprite.CMDCOLR&0xfff0)); + mode = 0; + transmask = 0xf; + break; + case 0x0008: // mode 1 16 colour lookup table mode (4bits) + // shienryu explosisons (and some enemies) use this mode + pix2 = m_vdp1.gfx_decode[(patterndata+offsetcnt/2) & 0xfffff]; + pix2 = offsetcnt&1 ? (pix2 & 0x0f) : ((pix2 & 0xf0)>>4); + pix = pix2&1 ? + ((((m_vdp1_vram[(((stv2_current_sprite.CMDCOLR&0xffff)*8)>>2)+((pix2&0xfffe)/2)])) & 0x0000ffff) >> 0): + ((((m_vdp1_vram[(((stv2_current_sprite.CMDCOLR&0xffff)*8)>>2)+((pix2&0xfffe)/2)])) & 0xffff0000) >> 16); + + mode = 5; + transmask = 0xffff; + + if ( !spd ) + { + if ( (pix2 & 0xf) == 0 ) + { + return; + } + else + { + spd = 1; + } + } + break; + case 0x0010: // mode 2 64 colour bank mode (8bits) (character select portraits on hanagumi) + pix = m_vdp1.gfx_decode[(patterndata+offsetcnt) & 0xfffff]; + mode = 2; + pix = pix+(stv2_current_sprite.CMDCOLR&0xffc0); + transmask = 0x3f; + break; + case 0x0018: // mode 3 128 colour bank mode (8bits) (little characters on hanagumi use this mode) + pix = m_vdp1.gfx_decode[(patterndata+offsetcnt) & 0xfffff]; + pix = pix+(stv2_current_sprite.CMDCOLR&0xff80); + transmask = 0x7f; + mode = 3; + break; + case 0x0020: // mode 4 256 colour bank mode (8bits) (hanagumi title) + pix = m_vdp1.gfx_decode[(patterndata+offsetcnt) & 0xfffff]; + pix = pix+(stv2_current_sprite.CMDCOLR&0xff00); + transmask = 0xff; + mode = 4; + break; + case 0x0028: // mode 5 32,768 colour RGB mode (16bits) + pix = m_vdp1.gfx_decode[(patterndata+offsetcnt*2+1) & 0xfffff] | (m_vdp1.gfx_decode[(patterndata+offsetcnt*2) & 0xfffff]<<8) ; + mode = 5; + transmask = -1; /* TODO: check me */ + break; + default: // other settings illegal + pix = machine().rand(); + mode = 0; + transmask = 0xff; + popmessage("Illegal Sprite Mode, contact MAMEdev"); + } + + + // preliminary end code disable support + if ( ((stv2_current_sprite.CMDPMOD & 0x80) == 0) && + ((pix & transmask) == transmask) ) + { + return; + } + } + + /* MSBON */ + pix |= stv2_current_sprite.CMDPMOD & 0x8000; + if ( mode != 5 ) + { + if ( (pix & transmask) || spd ) + { + m_vdp1.framebuffer_draw_lines[y][x] = pix; + } + } + else + { + if ( (pix & transmask) || spd ) + { + switch( stv2_current_sprite.CMDPMOD & 0x7 ) + { + case 0: /* replace */ + m_vdp1.framebuffer_draw_lines[y][x] = pix; + break; + case 1: /* shadow */ + if ( m_vdp1.framebuffer_draw_lines[y][x] & 0x8000 ) + { + m_vdp1.framebuffer_draw_lines[y][x] = ((m_vdp1.framebuffer_draw_lines[y][x] & ~0x8421) >> 1) | 0x8000; + } + break; + case 2: /* half luminance */ + m_vdp1.framebuffer_draw_lines[y][x] = ((pix & ~0x8421) >> 1) | 0x8000; + break; + case 3: /* half transparent */ + if ( m_vdp1.framebuffer_draw_lines[y][x] & 0x8000 ) + { + m_vdp1.framebuffer_draw_lines[y][x] = alpha_blend_r16( m_vdp1.framebuffer_draw_lines[y][x], pix, 0x80 ) | 0x8000; + } + else + { + m_vdp1.framebuffer_draw_lines[y][x] = pix; + } + break; + case 4: /* Gouraud shading */ + m_vdp1.framebuffer_draw_lines[y][x] = stv_vdp1_apply_gouraud_shading( x, y, pix ); + break; + default: + m_vdp1.framebuffer_draw_lines[y][x] = pix; + break; + } + } + } +} + + +void saturn_state::stv_vdp1_set_drawpixel( void ) +{ + int sprite_type = stv2_current_sprite.CMDCTRL & 0x000f; + int sprite_mode = stv2_current_sprite.CMDPMOD&0x0038; + int spd = stv2_current_sprite.CMDPMOD & 0x40; + int mesh = stv2_current_sprite.CMDPMOD & 0x100; + int ecd = stv2_current_sprite.CMDPMOD & 0x80; + + if ( mesh || !ecd || ((stv2_current_sprite.CMDPMOD & 0x7) != 0) ) + { + drawpixel = &saturn_state::drawpixel_generic; + return; + } + + if (sprite_type == 4 && ((stv2_current_sprite.CMDPMOD & 0x7) == 0)) + { + drawpixel = &saturn_state::drawpixel_poly; + } + else if ( (sprite_mode == 0x20) && !spd ) + { + m_sprite_colorbank = (stv2_current_sprite.CMDCOLR&0xff00); + drawpixel = &saturn_state::drawpixel_8bpp_trans; + } + else if ((sprite_mode == 0x00) && spd) + { + m_sprite_colorbank = (stv2_current_sprite.CMDCOLR&0xfff0); + drawpixel = &saturn_state::drawpixel_4bpp_notrans; + } + else if (sprite_mode == 0x00 && !spd ) + { + m_sprite_colorbank = (stv2_current_sprite.CMDCOLR&0xfff0); + drawpixel = &saturn_state::drawpixel_4bpp_trans; + } + else + { + drawpixel = &saturn_state::drawpixel_generic; + } +} + + +void saturn_state::vdp1_fill_slope(const rectangle &cliprect, int patterndata, int xsize, + INT32 x1, INT32 x2, INT32 sl1, INT32 sl2, INT32 *nx1, INT32 *nx2, + INT32 u1, INT32 u2, INT32 slu1, INT32 slu2, INT32 *nu1, INT32 *nu2, + INT32 v1, INT32 v2, INT32 slv1, INT32 slv2, INT32 *nv1, INT32 *nv2, + INT32 _y1, INT32 y2) +{ + if(_y1 > cliprect.max_y) + return; + + if(y2 <= cliprect.min_y) { + int delta = y2-_y1; + *nx1 = x1+delta*sl1; + *nu1 = u1+delta*slu1; + *nv1 = v1+delta*slv1; + *nx2 = x2+delta*sl2; + *nu2 = u2+delta*slu2; + *nv2 = v2+delta*slv2; + return; + } + + if(y2 > cliprect.max_y) + y2 = cliprect.max_y+1; + + if(_y1 < cliprect.min_y) { + int delta = cliprect.min_y - _y1; + x1 += delta*sl1; + u1 += delta*slu1; + v1 += delta*slv1; + x2 += delta*sl2; + u2 += delta*slu2; + v2 += delta*slv2; + _y1 = cliprect.min_y; + } + + if(x1 > x2 || (x1==x2 && sl1 > sl2)) { + INT32 t, *tp; + t = x1; + x1 = x2; + x2 = t; + t = sl1; + sl1 = sl2; + sl2 = t; + tp = nx1; + nx1 = nx2; + nx2 = tp; + + t = u1; + u1 = u2; + u2 = t; + t = slu1; + slu1 = slu2; + slu2 = t; + tp = nu1; + nu1 = nu2; + nu2 = tp; + + t = v1; + v1 = v2; + v2 = t; + t = slv1; + slv1 = slv2; + slv2 = t; + tp = nv1; + nv1 = nv2; + nv2 = tp; + } + + while(_y1 < y2) { + if(_y1 >= cliprect.min_y) { + INT32 slux = 0, slvx = 0; + int xx1 = x1>>FRAC_SHIFT; + int xx2 = x2>>FRAC_SHIFT; + INT32 u = u1; + INT32 v = v1; + if(xx1 != xx2) { + int delta = xx2-xx1; + slux = (u2-u1)/delta; + slvx = (v2-v1)/delta; + } + if(xx1 <= cliprect.max_x || xx2 >= cliprect.min_x) { + if(xx1 < cliprect.min_x) { + int delta = cliprect.min_x-xx1; + u += slux*delta; + v += slvx*delta; + xx1 = cliprect.min_x; + } + if(xx2 > cliprect.max_x) + xx2 = cliprect.max_x; + + while(xx1 <= xx2) { + (this->*drawpixel)(xx1,_y1, patterndata, (v>>FRAC_SHIFT)*xsize+(u>>FRAC_SHIFT)); + xx1++; + u += slux; + v += slvx; + } + } + } + + x1 += sl1; + u1 += slu1; + v1 += slv1; + x2 += sl2; + u2 += slu2; + v2 += slv2; + _y1++; + } + *nx1 = x1; + *nu1 = u1; + *nv1 = v1; + *nx2 = x2; + *nu2 = u2; + *nv2 = v2; +} + +void saturn_state::vdp1_fill_line(const rectangle &cliprect, int patterndata, int xsize, INT32 y, + INT32 x1, INT32 x2, INT32 u1, INT32 u2, INT32 v1, INT32 v2) +{ + int xx1 = x1>>FRAC_SHIFT; + int xx2 = x2>>FRAC_SHIFT; + + if(y > cliprect.max_y || y < cliprect.min_y) + return; + + if(xx1 <= cliprect.max_x || xx2 >= cliprect.min_x) { + INT32 slux = 0, slvx = 0; + INT32 u = u1; + INT32 v = v1; + if(xx1 != xx2) { + int delta = xx2-xx1; + slux = (u2-u1)/delta; + slvx = (v2-v1)/delta; + } + if(xx1 < cliprect.min_x) { + int delta = cliprect.min_x-xx1; + u += slux*delta; + v += slvx*delta; + xx1 = cliprect.min_x; + } + if(xx2 > cliprect.max_x) + xx2 = cliprect.max_x; + + while(xx1 <= xx2) { + (this->*drawpixel)(xx1,y,patterndata,(v>>FRAC_SHIFT)*xsize+(u>>FRAC_SHIFT)); + xx1++; + u += slux; + v += slvx; + } + } +} + +void saturn_state::vdp1_fill_quad(const rectangle &cliprect, int patterndata, int xsize, const struct spoint *q) +{ + INT32 sl1, sl2, slu1, slu2, slv1, slv2, cury, limy, x1, x2, u1, u2, v1, v2, delta; + int pmin, pmax, i, ps1, ps2; + struct spoint p[8]; + + for(i=0; i<4; i++) { + p[i].x = p[i+4].x = q[i].x << FRAC_SHIFT; + p[i].y = p[i+4].y = q[i].y; + p[i].u = p[i+4].u = q[i].u << FRAC_SHIFT; + p[i].v = p[i+4].v = q[i].v << FRAC_SHIFT; + } + + pmin = pmax = 0; + for(i=1; i<4; i++) { + if(p[i].y < p[pmin].y) + pmin = i; + if(p[i].y > p[pmax].y) + pmax = i; + } + + cury = p[pmin].y; + limy = p[pmax].y; + + if(cury == limy) { + x1 = x2 = p[0].x; + u1 = u2 = p[0].u; + v1 = v2 = p[0].v; + for(i=1; i<4; i++) { + if(p[i].x < x1) { + x1 = p[i].x; + u1 = p[i].u; + v1 = p[i].v; + } + if(p[i].x > x2) { + x2 = p[i].x; + u2 = p[i].u; + v2 = p[i].v; + } + } + vdp1_fill_line(cliprect, patterndata, xsize, cury, x1, x2, u1, u2, v1, v2); + return; + } + + if(cury > cliprect.max_y) + return; + if(limy <= cliprect.min_y) + return; + + if(limy > cliprect.max_y) + limy = cliprect.max_y; + + ps1 = pmin+4; + ps2 = pmin; + + goto startup; + + for(;;) { + if(p[ps1-1].y == p[ps2+1].y) { + vdp1_fill_slope(cliprect, patterndata, xsize, + x1, x2, sl1, sl2, &x1, &x2, + u1, u2, slu1, slu2, &u1, &u2, + v1, v2, slv1, slv2, &v1, &v2, + cury, p[ps1-1].y); + cury = p[ps1-1].y; + if(cury >= limy) + break; + ps1--; + ps2++; + + startup: + while(p[ps1-1].y == cury) + ps1--; + while(p[ps2+1].y == cury) + ps2++; + x1 = p[ps1].x; + u1 = p[ps1].u; + v1 = p[ps1].v; + x2 = p[ps2].x; + u2 = p[ps2].u; + v2 = p[ps2].v; + + delta = cury-p[ps1-1].y; + sl1 = (x1-p[ps1-1].x)/delta; + slu1 = (u1-p[ps1-1].u)/delta; + slv1 = (v1-p[ps1-1].v)/delta; + + delta = cury-p[ps2+1].y; + sl2 = (x2-p[ps2+1].x)/delta; + slu2 = (u2-p[ps2+1].u)/delta; + slv2 = (v2-p[ps2+1].v)/delta; + } else if(p[ps1-1].y < p[ps2+1].y) { + vdp1_fill_slope(cliprect, patterndata, xsize, + x1, x2, sl1, sl2, &x1, &x2, + u1, u2, slu1, slu2, &u1, &u2, + v1, v2, slv1, slv2, &v1, &v2, + cury, p[ps1-1].y); + cury = p[ps1-1].y; + if(cury >= limy) + break; + ps1--; + while(p[ps1-1].y == cury) + ps1--; + x1 = p[ps1].x; + u1 = p[ps1].u; + v1 = p[ps1].v; + + delta = cury-p[ps1-1].y; + sl1 = (x1-p[ps1-1].x)/delta; + slu1 = (u1-p[ps1-1].u)/delta; + slv1 = (v1-p[ps1-1].v)/delta; + } else { + vdp1_fill_slope(cliprect, patterndata, xsize, + x1, x2, sl1, sl2, &x1, &x2, + u1, u2, slu1, slu2, &u1, &u2, + v1, v2, slv1, slv2, &v1, &v2, + cury, p[ps2+1].y); + cury = p[ps2+1].y; + if(cury >= limy) + break; + ps2++; + while(p[ps2+1].y == cury) + ps2++; + x2 = p[ps2].x; + u2 = p[ps2].u; + v2 = p[ps2].v; + + delta = cury-p[ps2+1].y; + sl2 = (x2-p[ps2+1].x)/delta; + slu2 = (u2-p[ps2+1].u)/delta; + slv2 = (v2-p[ps2+1].v)/delta; + } + } + if(cury == limy) + vdp1_fill_line(cliprect, patterndata, xsize, cury, x1, x2, u1, u2, v1, v2); +} + +int saturn_state::x2s(int v) +{ + return (INT32)(INT16)v + m_vdp1.local_x; +} + +int saturn_state::y2s(int v) +{ + return (INT32)(INT16)v + m_vdp1.local_y; +} + +void saturn_state::stv_vdp1_draw_line(const rectangle &cliprect) +{ + struct spoint q[4]; + + q[0].x = x2s(stv2_current_sprite.CMDXA); + q[0].y = y2s(stv2_current_sprite.CMDYA); + q[1].x = x2s(stv2_current_sprite.CMDXB); + q[1].y = y2s(stv2_current_sprite.CMDYB); + q[2].x = x2s(stv2_current_sprite.CMDXA); + q[2].y = y2s(stv2_current_sprite.CMDYA); + q[3].x = x2s(stv2_current_sprite.CMDXB); + q[3].y = y2s(stv2_current_sprite.CMDYB); + + q[0].u = q[3].u = q[1].u = q[2].u = 0; + q[0].v = q[1].v = q[2].v = q[3].v = 0; + + vdp1_fill_quad(cliprect, 0, 1, q); +} + +void saturn_state::stv_vdp1_draw_poly_line(const rectangle &cliprect) +{ + struct spoint q[4]; + + q[0].x = x2s(stv2_current_sprite.CMDXA); + q[0].y = y2s(stv2_current_sprite.CMDYA); + q[1].x = x2s(stv2_current_sprite.CMDXB); + q[1].y = y2s(stv2_current_sprite.CMDYB); + q[2].x = x2s(stv2_current_sprite.CMDXA); + q[2].y = y2s(stv2_current_sprite.CMDYA); + q[3].x = x2s(stv2_current_sprite.CMDXB); + q[3].y = y2s(stv2_current_sprite.CMDYB); + + q[0].u = q[3].u = q[1].u = q[2].u = 0; + q[0].v = q[1].v = q[2].v = q[3].v = 0; + + vdp1_fill_quad(cliprect, 0, 1, q); + + q[0].x = x2s(stv2_current_sprite.CMDXB); + q[0].y = y2s(stv2_current_sprite.CMDYB); + q[1].x = x2s(stv2_current_sprite.CMDXC); + q[1].y = y2s(stv2_current_sprite.CMDYC); + q[2].x = x2s(stv2_current_sprite.CMDXB); + q[2].y = y2s(stv2_current_sprite.CMDYB); + q[3].x = x2s(stv2_current_sprite.CMDXC); + q[3].y = y2s(stv2_current_sprite.CMDYC); + + q[0].u = q[3].u = q[1].u = q[2].u = 0; + q[0].v = q[1].v = q[2].v = q[3].v = 0; + + vdp1_fill_quad(cliprect, 0, 1, q); + + q[0].x = x2s(stv2_current_sprite.CMDXC); + q[0].y = y2s(stv2_current_sprite.CMDYC); + q[1].x = x2s(stv2_current_sprite.CMDXD); + q[1].y = y2s(stv2_current_sprite.CMDYD); + q[2].x = x2s(stv2_current_sprite.CMDXC); + q[2].y = y2s(stv2_current_sprite.CMDYC); + q[3].x = x2s(stv2_current_sprite.CMDXD); + q[3].y = y2s(stv2_current_sprite.CMDYD); + + q[0].u = q[3].u = q[1].u = q[2].u = 0; + q[0].v = q[1].v = q[2].v = q[3].v = 0; + + vdp1_fill_quad(cliprect, 0, 1, q); + + q[0].x = x2s(stv2_current_sprite.CMDXD); + q[0].y = y2s(stv2_current_sprite.CMDYD); + q[1].x = x2s(stv2_current_sprite.CMDXA); + q[1].y = y2s(stv2_current_sprite.CMDYA); + q[2].x = x2s(stv2_current_sprite.CMDXD); + q[2].y = y2s(stv2_current_sprite.CMDYD); + q[3].x = x2s(stv2_current_sprite.CMDXA); + q[3].y = y2s(stv2_current_sprite.CMDYA); + + q[0].u = q[3].u = q[1].u = q[2].u = 0; + q[0].v = q[1].v = q[2].v = q[3].v = 0; + + stv_vdp1_setup_shading(q, cliprect); + vdp1_fill_quad(cliprect, 0, 1, q); + +} + +void saturn_state::stv_vdp1_draw_distorted_sprite(const rectangle &cliprect) +{ + struct spoint q[4]; + + int xsize, ysize; + int direction; + int patterndata; + + direction = (stv2_current_sprite.CMDCTRL & 0x0030)>>4; + + if ( stv2_current_sprite.ispoly ) + { + xsize = ysize = 1; + patterndata = 0; + } + else + { + xsize = (stv2_current_sprite.CMDSIZE & 0x3f00) >> 8; + xsize = xsize * 8; + if (xsize == 0) return; /* setting prohibited */ + + ysize = (stv2_current_sprite.CMDSIZE & 0x00ff); + if (ysize == 0) return; /* setting prohibited */ + + patterndata = (stv2_current_sprite.CMDSRCA) & 0xffff; + patterndata = patterndata * 0x8; + + } + + + q[0].x = x2s(stv2_current_sprite.CMDXA); + q[0].y = y2s(stv2_current_sprite.CMDYA); + q[1].x = x2s(stv2_current_sprite.CMDXB); + q[1].y = y2s(stv2_current_sprite.CMDYB); + q[2].x = x2s(stv2_current_sprite.CMDXC); + q[2].y = y2s(stv2_current_sprite.CMDYC); + q[3].x = x2s(stv2_current_sprite.CMDXD); + q[3].y = y2s(stv2_current_sprite.CMDYD); + + if(direction & 1) { // xflip + q[0].u = q[3].u = xsize-1; + q[1].u = q[2].u = 0; + } else { + q[0].u = q[3].u = 0; + q[1].u = q[2].u = xsize-1; + } + if(direction & 2) { // yflip + q[0].v = q[1].v = ysize-1; + q[2].v = q[3].v = 0; + } else { + q[0].v = q[1].v = 0; + q[2].v = q[3].v = ysize-1; + } + + stv_vdp1_setup_shading(q, cliprect); + vdp1_fill_quad(cliprect, patterndata, xsize, q); +} + +void saturn_state::stv_vdp1_draw_scaled_sprite(const rectangle &cliprect) +{ + struct spoint q[4]; + + int xsize, ysize; + int direction; + int patterndata; + int zoompoint; + int x,y; + int x2,y2; + int screen_width,screen_height,screen_height_negative = 0; + + direction = (stv2_current_sprite.CMDCTRL & 0x0030)>>4; + + xsize = (stv2_current_sprite.CMDSIZE & 0x3f00) >> 8; + xsize = xsize * 8; + + ysize = (stv2_current_sprite.CMDSIZE & 0x00ff); + + patterndata = (stv2_current_sprite.CMDSRCA) & 0xffff; + patterndata = patterndata * 0x8; + + zoompoint = (stv2_current_sprite.CMDCTRL & 0x0f00)>>8; + + x = stv2_current_sprite.CMDXA; + y = stv2_current_sprite.CMDYA; + + screen_width = (INT16)stv2_current_sprite.CMDXB; + if ( (screen_width < 0) && zoompoint) + { + screen_width = -screen_width; + direction |= 1; + } + + screen_height = (INT16)stv2_current_sprite.CMDYB; + if ( (screen_height < 0) && zoompoint ) + { + screen_height_negative = 1; + screen_height = -screen_height; + direction |= 2; + } + + x2 = stv2_current_sprite.CMDXC; // second co-ordinate set x + y2 = stv2_current_sprite.CMDYC; // second co-ordinate set y + + switch (zoompoint) + { + case 0x0: // specified co-ordinates + break; + case 0x5: // up left + break; + case 0x6: // up center + x -= screen_width/2 ; + break; + case 0x7: // up right + x -= screen_width; + break; + + case 0x9: // center left + y -= screen_height/2 ; + break; + case 0xa: // center center + y -= screen_height/2 ; + x -= screen_width/2 ; + + break; + + case 0xb: // center right + y -= screen_height/2 ; + x -= screen_width; + break; + + case 0xd: // center left + y -= screen_height; + break; + + case 0xe: // center center + y -= screen_height; + x -= screen_width/2 ; + break; + + case 0xf: // center right + y -= screen_height; + x -= screen_width; + break; + + default: // illegal + break; + + } + + /* 0----1 + | | + | | + 3----2 */ + + if (zoompoint) + { + q[0].x = x2s(x); + q[0].y = y2s(y); + q[1].x = x2s(x)+screen_width; + q[1].y = y2s(y); + q[2].x = x2s(x)+screen_width; + q[2].y = y2s(y)+screen_height; + q[3].x = x2s(x); + q[3].y = y2s(y)+screen_height; + + if ( screen_height_negative ) + { + q[0].y += screen_height; + q[1].y += screen_height; + q[2].y += screen_height; + q[3].y += screen_height; + } + } + else + { + q[0].x = x2s(x); + q[0].y = y2s(y); + q[1].x = x2s(x2); + q[1].y = y2s(y); + q[2].x = x2s(x2); + q[2].y = y2s(y2); + q[3].x = x2s(x); + q[3].y = y2s(y2); + } + + + if(direction & 1) { // xflip + q[0].u = q[3].u = xsize-1; + q[1].u = q[2].u = 0; + } else { + q[0].u = q[3].u = 0; + q[1].u = q[2].u = xsize-1; + } + if(direction & 2) { // yflip + q[0].v = q[1].v = ysize-1; + q[2].v = q[3].v = 0; + } else { + q[0].v = q[1].v = 0; + q[2].v = q[3].v = ysize-1; + } + + stv_vdp1_setup_shading(q, cliprect); + vdp1_fill_quad(cliprect, patterndata, xsize, q); +} + + + + +void saturn_state::stv_vdp1_draw_normal_sprite(const rectangle &cliprect, int sprite_type) +{ + //UINT16 *destline; + //saturn_state *state = machine.driver_data(); + int y, ysize, drawypos; + int x, xsize, drawxpos; + int direction; + int patterndata; + UINT8 shading; + int su, u, dux, duy; + int maxdrawypos, maxdrawxpos; + + x = x2s(stv2_current_sprite.CMDXA); + y = y2s(stv2_current_sprite.CMDYA); + + direction = (stv2_current_sprite.CMDCTRL & 0x0030)>>4; + + xsize = (stv2_current_sprite.CMDSIZE & 0x3f00) >> 8; + xsize = xsize * 8; + + ysize = (stv2_current_sprite.CMDSIZE & 0x00ff); + + patterndata = (stv2_current_sprite.CMDSRCA) & 0xffff; + patterndata = patterndata * 0x8; + + if (VDP1_LOG) logerror ("Drawing Normal Sprite x %04x y %04x xsize %04x ysize %04x patterndata %06x\n",x,y,xsize,ysize,patterndata); + + if ( x > cliprect.max_x ) return; + if ( y > cliprect.max_y ) return; + + shading = stv_read_gouraud_table(); + if ( shading ) + { + struct spoint q[4]; + q[0].x = x; q[0].y = y; + q[1].x = x + xsize; q[1].y = y; + q[2].x = x + xsize; q[2].y = y + ysize; + q[3].x = x; q[3].y = y + ysize; + + stv_vdp1_setup_shading( q, cliprect ); + } + + u = 0; + dux = 1; + duy = xsize; + if ( direction & 0x1 ) //xflip + { + dux = -1; + u = xsize - 1; + } + if ( direction & 0x2 ) //yflip + { + duy = -xsize; + u += xsize*(ysize-1); + } + if ( y < cliprect.min_y ) //clip y + { + u += xsize*(cliprect.min_y - y); + ysize -= (cliprect.min_y - y); + y = cliprect.min_y; + } + if ( x < cliprect.min_x ) //clip x + { + u += dux*(cliprect.min_x - x); + xsize -= (cliprect.min_x - x); + x = cliprect.min_x; + } + maxdrawypos = MIN(y+ysize-1,cliprect.max_y); + maxdrawxpos = MIN(x+xsize-1,cliprect.max_x); + for (drawypos = y; drawypos <= maxdrawypos; drawypos++ ) + { + //destline = m_vdp1.framebuffer_draw_lines[drawypos]; + su = u; + for (drawxpos = x; drawxpos <= maxdrawxpos; drawxpos++ ) + { + (this->*drawpixel)( drawxpos, drawypos, patterndata, u ); + u += dux; + } + u = su + duy; + } +} + +TIMER_CALLBACK_MEMBER(saturn_state::vdp1_draw_end ) +{ + /* set CEF to 1*/ + CEF_1; + + if(!(m_scu.ism & IRQ_VDP1_END)) + { + m_maincpu->set_input_line_and_vector(0x2, HOLD_LINE, 0x4d); + scu_do_transfer(6); + } + else + m_scu.ist |= (IRQ_VDP1_END); +} + + +void saturn_state::stv_vdp1_process_list( void ) +{ + int position; + int spritecount; + int vdp1_nest; + rectangle *cliprect; + + spritecount = 0; + position = 0; + + if (VDP1_LOG) logerror ("Sprite List Process START\n"); + + vdp1_nest = -1; + + stv_clear_gouraud_shading(); + + /*Set CEF bit to 0*/ + CEF_0; + + while (spritecount<10000) // if its drawn this many sprites something is probably wrong or sega were crazy ;-) + { + int draw_this_sprite; + + draw_this_sprite = 1; + + // if (position >= ((0x80000/0x20)/4)) // safety check + // { + // if (VDP1_LOG) logerror ("Sprite List Position Too High!\n"); + // position = 0; + // } + + spritecount++; + + stv2_current_sprite.CMDCTRL = (m_vdp1_vram[position * (0x20/4)+0] & 0xffff0000) >> 16; + + if (stv2_current_sprite.CMDCTRL == 0x8000) + { + if (VDP1_LOG) logerror ("List Terminator (0x8000) Encountered, Sprite List Process END\n"); + goto end; // end of list + } + + stv2_current_sprite.CMDLINK = (m_vdp1_vram[position * (0x20/4)+0] & 0x0000ffff) >> 0; + stv2_current_sprite.CMDPMOD = (m_vdp1_vram[position * (0x20/4)+1] & 0xffff0000) >> 16; + stv2_current_sprite.CMDCOLR = (m_vdp1_vram[position * (0x20/4)+1] & 0x0000ffff) >> 0; + stv2_current_sprite.CMDSRCA = (m_vdp1_vram[position * (0x20/4)+2] & 0xffff0000) >> 16; + stv2_current_sprite.CMDSIZE = (m_vdp1_vram[position * (0x20/4)+2] & 0x0000ffff) >> 0; + stv2_current_sprite.CMDXA = (m_vdp1_vram[position * (0x20/4)+3] & 0xffff0000) >> 16; + stv2_current_sprite.CMDYA = (m_vdp1_vram[position * (0x20/4)+3] & 0x0000ffff) >> 0; + stv2_current_sprite.CMDXB = (m_vdp1_vram[position * (0x20/4)+4] & 0xffff0000) >> 16; + stv2_current_sprite.CMDYB = (m_vdp1_vram[position * (0x20/4)+4] & 0x0000ffff) >> 0; + stv2_current_sprite.CMDXC = (m_vdp1_vram[position * (0x20/4)+5] & 0xffff0000) >> 16; + stv2_current_sprite.CMDYC = (m_vdp1_vram[position * (0x20/4)+5] & 0x0000ffff) >> 0; + stv2_current_sprite.CMDXD = (m_vdp1_vram[position * (0x20/4)+6] & 0xffff0000) >> 16; + stv2_current_sprite.CMDYD = (m_vdp1_vram[position * (0x20/4)+6] & 0x0000ffff) >> 0; + stv2_current_sprite.CMDGRDA = (m_vdp1_vram[position * (0x20/4)+7] & 0xffff0000) >> 16; +// stv2_current_sprite.UNUSED = (m_vdp1_vram[position * (0x20/4)+7] & 0x0000ffff) >> 0; + + /* proecess jump / skip commands, set position for next sprite */ + switch (stv2_current_sprite.CMDCTRL & 0x7000) + { + case 0x0000: // jump next + if (VDP1_LOG) logerror ("Sprite List Process + Next (Normal)\n"); + position++; + break; + case 0x1000: // jump assign + if (VDP1_LOG) logerror ("Sprite List Process + Jump Old %06x New %06x\n", position, (stv2_current_sprite.CMDLINK>>2)); + position= (stv2_current_sprite.CMDLINK>>2); + break; + case 0x2000: // jump call + if (vdp1_nest == -1) + { + if (VDP1_LOG) logerror ("Sprite List Process + Call Old %06x New %06x\n",position, (stv2_current_sprite.CMDLINK>>2)); + vdp1_nest = position+1; + position = (stv2_current_sprite.CMDLINK>>2); + } + else + { + if (VDP1_LOG) logerror ("Sprite List Nested Call, ignoring\n"); + position++; + } + break; + case 0x3000: + if (vdp1_nest != -1) + { + if (VDP1_LOG) logerror ("Sprite List Process + Return\n"); + position = vdp1_nest; + vdp1_nest = -1; + } + else + { + if (VDP1_LOG) logerror ("Attempted return from no subroutine, aborting\n"); + position++; + goto end; // end of list + } + break; + case 0x4000: + draw_this_sprite = 0; + position++; + break; + case 0x5000: + if (VDP1_LOG) logerror ("Sprite List Skip + Jump Old %06x New %06x\n", position, (stv2_current_sprite.CMDLINK>>2)); + draw_this_sprite = 0; + position= (stv2_current_sprite.CMDLINK>>2); + + break; + case 0x6000: + draw_this_sprite = 0; + if (vdp1_nest == -1) + { + if (VDP1_LOG) logerror ("Sprite List Skip + Call To Subroutine Old %06x New %06x\n",position, (stv2_current_sprite.CMDLINK>>2)); + + vdp1_nest = position+1; + position = (stv2_current_sprite.CMDLINK>>2); + } + else + { + if (VDP1_LOG) logerror ("Sprite List Nested Call, ignoring\n"); + position++; + } + break; + case 0x7000: + draw_this_sprite = 0; + if (vdp1_nest != -1) + { + if (VDP1_LOG) logerror ("Sprite List Skip + Return from Subroutine\n"); + + position = vdp1_nest; + vdp1_nest = -1; + } + else + { + if (VDP1_LOG) logerror ("Attempted return from no subroutine, aborting\n"); + position++; + goto end; // end of list + } + break; + } + + /* continue to draw this sprite only if the command wasn't to skip it */ + if (draw_this_sprite ==1) + { + if ( stv2_current_sprite.CMDPMOD & 0x0400 ) + { + //if(stv2_current_sprite.CMDPMOD & 0x0200) /* TODO: Bio Hazard inventory screen uses outside cliprect */ + // cliprect = &m_vdp1.system_cliprect; + //else + cliprect = &m_vdp1.user_cliprect; + } + else + { + cliprect = &m_vdp1.system_cliprect; + } + + stv_vdp1_set_drawpixel(); + + switch (stv2_current_sprite.CMDCTRL & 0x000f) + { + case 0x0000: + if (VDP1_LOG) logerror ("Sprite List Normal Sprite (%d %d)\n",stv2_current_sprite.CMDXA,stv2_current_sprite.CMDYA); + stv2_current_sprite.ispoly = 0; + stv_vdp1_draw_normal_sprite(*cliprect, 0); + break; + + case 0x0001: + if (VDP1_LOG) logerror ("Sprite List Scaled Sprite (%d %d)\n",stv2_current_sprite.CMDXA,stv2_current_sprite.CMDYA); + stv2_current_sprite.ispoly = 0; + stv_vdp1_draw_scaled_sprite(*cliprect); + break; + + case 0x0002: + case 0x0003: // used by Hardcore 4x4 + if (VDP1_LOG) logerror ("Sprite List Distorted Sprite\n"); + if (VDP1_LOG) logerror ("(A: %d %d)\n",stv2_current_sprite.CMDXA,stv2_current_sprite.CMDYA); + if (VDP1_LOG) logerror ("(B: %d %d)\n",stv2_current_sprite.CMDXB,stv2_current_sprite.CMDYB); + if (VDP1_LOG) logerror ("(C: %d %d)\n",stv2_current_sprite.CMDXC,stv2_current_sprite.CMDYC); + if (VDP1_LOG) logerror ("(D: %d %d)\n",stv2_current_sprite.CMDXD,stv2_current_sprite.CMDYD); + if (VDP1_LOG) logerror ("CMDPMOD = %04x\n",stv2_current_sprite.CMDPMOD); + + stv2_current_sprite.ispoly = 0; + stv_vdp1_draw_distorted_sprite(*cliprect); + break; + + case 0x0004: + if (VDP1_LOG) logerror ("Sprite List Polygon\n"); + stv2_current_sprite.ispoly = 1; + stv_vdp1_draw_distorted_sprite(*cliprect); + break; + + case 0x0005: +// case 0x0007: // mirror? Baroque uses it, crashes for whatever reason + if (VDP1_LOG) logerror ("Sprite List Polyline\n"); + stv2_current_sprite.ispoly = 1; + stv_vdp1_draw_poly_line(*cliprect); + break; + + case 0x0006: + if (VDP1_LOG) logerror ("Sprite List Line\n"); + stv2_current_sprite.ispoly = 1; + stv_vdp1_draw_line(*cliprect); + break; + + case 0x0008: +// case 0x000b: // mirror? Bug 2 + if (VDP1_LOG) logerror ("Sprite List Set Command for User Clipping (%d,%d),(%d,%d)\n", stv2_current_sprite.CMDXA, stv2_current_sprite.CMDYA, stv2_current_sprite.CMDXC, stv2_current_sprite.CMDYC); + m_vdp1.user_cliprect.set(stv2_current_sprite.CMDXA, stv2_current_sprite.CMDXC, stv2_current_sprite.CMDYA, stv2_current_sprite.CMDYC); + break; + + case 0x0009: + if (VDP1_LOG) logerror ("Sprite List Set Command for System Clipping (0,0),(%d,%d)\n", stv2_current_sprite.CMDXC, stv2_current_sprite.CMDYC); + m_vdp1.system_cliprect.set(0, stv2_current_sprite.CMDXC, 0, stv2_current_sprite.CMDYC); + break; + + case 0x000a: + if (VDP1_LOG) logerror ("Sprite List Local Co-Ordinate Set (%d %d)\n",(INT16)stv2_current_sprite.CMDXA,(INT16)stv2_current_sprite.CMDYA); + m_vdp1.local_x = (INT16)stv2_current_sprite.CMDXA; + m_vdp1.local_y = (INT16)stv2_current_sprite.CMDYA; + break; + + default: + popmessage ("VDP1: Sprite List Illegal %02x, contact MAMEdev",stv2_current_sprite.CMDCTRL & 0xf); + m_vdp1.lopr = (position * 0x20) >> 3; + m_vdp1.copr = (position * 0x20) >> 3; + return; + } + } + + } + + + end: + m_vdp1.copr = (position * 0x20) >> 3; + + /* TODO: what's the exact formula? Guess it should be a mix between number of pixels written and actual command data fetched. */ + machine().scheduler().timer_set(m_maincpu->cycles_to_attotime(spritecount*16), timer_expired_delegate(FUNC(saturn_state::vdp1_draw_end),this)); + + if (VDP1_LOG) logerror ("End of list processing!\n"); +} + +void saturn_state::video_update_vdp1( void ) +{ + int framebuffer_changed = 0; + +// int enable; +// if (machine.input().code_pressed (KEYCODE_R)) VDP1_LOG = 1; +// if (machine.input().code_pressed (KEYCODE_T)) VDP1_LOG = 0; + +// if (machine.input().code_pressed (KEYCODE_Y)) VDP1_LOG = 0; +// { +// FILE *fp; +// +// fp=fopen("vdp1_ram.dmp", "w+b"); +// if (fp) +// { +// fwrite(stv_vdp1, 0x00100000, 1, fp); +// fclose(fp); +// } +// } + if (VDP1_LOG) logerror("video_update_vdp1 called\n"); + if (VDP1_LOG) logerror( "FBCR = %0x, accessed = %d\n", STV_VDP1_FBCR, m_vdp1.fbcr_accessed ); + + if(STV_VDP1_CEF) + BEF_1; + else + BEF_0; + + if ( m_vdp1.framebuffer_clear_on_next_frame ) + { + if ( ((STV_VDP1_FBCR & 0x3) == 3) && + m_vdp1.fbcr_accessed ) + { + stv_clear_framebuffer(m_vdp1.framebuffer_current_display); + m_vdp1.framebuffer_clear_on_next_frame = 0; + } + } + + switch( STV_VDP1_FBCR & 0x3 ) + { + case 0: /* Automatic mode */ + stv_vdp1_change_framebuffers(); + stv_clear_framebuffer(m_vdp1.framebuffer_current_draw); + framebuffer_changed = 1; + break; + case 1: /* Setting prohibited */ + break; + case 2: /* Manual mode - erase */ + if ( m_vdp1.fbcr_accessed ) + { + m_vdp1.framebuffer_clear_on_next_frame = 1; + } + break; + case 3: /* Manual mode - change */ + if ( m_vdp1.fbcr_accessed ) + { + stv_vdp1_change_framebuffers(); + if ( STV_VDP1_VBE ) + { + stv_clear_framebuffer(m_vdp1.framebuffer_current_draw); + } + /* TODO: Slam n Jam 96 & Cross Romance doesn't like this, investigate. */ + framebuffer_changed = 1; + } + // framebuffer_changed = 1; + break; + } + m_vdp1.fbcr_accessed = 0; + + if (VDP1_LOG) logerror( "PTM = %0x, TVM = %x\n", STV_VDP1_PTM, STV_VDP1_TVM ); + /*Set CEF bit to 0*/ + //CEF_0; + switch(STV_VDP1_PTM & 3) + { + case 0:/*Idle Mode*/ + /*Set CEF bit to 0*/ + CEF_0; + break; + case 1:/*Draw by request*/ + /*Set CEF bit to 0*/ + CEF_0; + break; + case 2:/*Automatic Draw*/ + if ( framebuffer_changed || VDP1_LOG ) + { + /*set CEF to 1*/ + stv_vdp1_process_list(); + } + break; + case 3: /**/ + logerror("Warning: Invalid PTM mode set for VDP1!\n"); + break; + } + //popmessage("%04x %04x",STV_VDP1_EWRR_X3,STV_VDP1_EWRR_Y3); +} + +void saturn_state::stv_vdp1_state_save_postload( void ) +{ + UINT8 *vdp1 = m_vdp1.gfx_decode; + int offset; + UINT32 data; + + m_vdp1.framebuffer_mode = -1; + m_vdp1.framebuffer_double_interlace = -1; + + stv_set_framebuffer_config(); + + for (offset = 0; offset < 0x80000/4; offset++ ) + { + data = m_vdp1_vram[offset]; + /* put in gfx region for easy decoding */ + vdp1[offset*4+0] = (data & 0xff000000) >> 24; + vdp1[offset*4+1] = (data & 0x00ff0000) >> 16; + vdp1[offset*4+2] = (data & 0x0000ff00) >> 8; + vdp1[offset*4+3] = (data & 0x000000ff) >> 0; + } +} + +int saturn_state::stv_vdp1_start ( void ) +{ + m_vdp1_regs = auto_alloc_array_clear(machine(), UINT16, 0x020/2 ); + m_vdp1_vram = auto_alloc_array_clear(machine(), UINT32, 0x100000/4 ); + m_vdp1.gfx_decode = auto_alloc_array(machine(), UINT8, 0x100000 ); + + stv_vdp1_shading_data = auto_alloc(machine(), struct stv_vdp1_poly_scanline_data); + + m_vdp1.framebuffer[0] = auto_alloc_array(machine(), UINT16, 1024 * 256 * 2 ); /* *2 is for double interlace */ + m_vdp1.framebuffer[1] = auto_alloc_array(machine(), UINT16, 1024 * 256 * 2 ); + + m_vdp1.framebuffer_display_lines = auto_alloc_array(machine(), UINT16 *, 512); + m_vdp1.framebuffer_draw_lines = auto_alloc_array(machine(), UINT16 *, 512); + + m_vdp1.framebuffer_width = m_vdp1.framebuffer_height = 0; + m_vdp1.framebuffer_mode = -1; + m_vdp1.framebuffer_double_interlace = -1; + m_vdp1.fbcr_accessed = 0; + m_vdp1.framebuffer_current_display = 0; + m_vdp1.framebuffer_current_draw = 1; + stv_clear_framebuffer(m_vdp1.framebuffer_current_draw); + m_vdp1.framebuffer_clear_on_next_frame = 0; + + m_vdp1.system_cliprect.set(0, 0, 0, 0); + /* Kidou Senshi Z Gundam - Zenpen Zeta no Kodou loves to use the user cliprect vars in an undefined state ... */ + m_vdp1.user_cliprect.set(0, 512, 0, 256); + + // save state + save_pointer(NAME(m_vdp1_regs), 0x020/2); + save_pointer(NAME(m_vdp1_vram), 0x100000/4); + save_item(NAME(m_vdp1.fbcr_accessed)); + save_item(NAME(m_vdp1.framebuffer_current_display)); + save_item(NAME(m_vdp1.framebuffer_current_draw)); + save_item(NAME(m_vdp1.framebuffer_clear_on_next_frame)); + save_item(NAME(m_vdp1.local_x)); + save_item(NAME(m_vdp1.local_y)); + machine().save().register_postload(save_prepost_delegate(FUNC(saturn_state::stv_vdp1_state_save_postload), this)); + return 0; +} diff --git a/src/devices/video/stvvdp2.c b/src/devices/video/stvvdp2.c new file mode 100644 index 00000000000..e2fbcf7f58d --- /dev/null +++ b/src/devices/video/stvvdp2.c @@ -0,0 +1,6968 @@ +// license:LGPL-2.1+ +// copyright-holders:David Haywood, Angelo Salese, Olivier Galibert, Mariusz Wojcieszek, R. Belmont +/* Sega Saturn VDP2 */ + +#define DEBUG_MODE 0 +#define TEST_FUNCTIONS 0 +#define POPMESSAGE_DEBUG 0 + +/* + +the dirty marking stuff and tile decoding will probably be removed in the end anyway as we'll need custom +rendering code since mame's drawgfx / tilesytem don't offer everything st-v needs + +this system seems far too complex to use Mame's tilemap system + +4 'scroll' planes (scroll screens) + +the scroll planes have slightly different capabilities + +NBG0 +NBG1 +NBG2 +NBG3 + +2 'rotate' planes + +RBG0 +RBG1 + +-- other crap +EXBG (external) + +----------------------------------------------------------------------------------------------------------- + +Video emulation TODO: +-all games: + \-priorities (check myfairld,thunt) + \-complete windows effects + \-mosaic effect + \-ODD bit/H/V Counter not yet emulated properly + \-Reduction enable bits + \-Check if there are any remaining video registers that are yet to be macroized & added to the rumble. +-batmanfr: + \-If you reset the game after the character selection screen,when you get again to it there's garbage + floating behind Batman. +-elandore: + \-(BTANB) priorities at the VS. screen apparently is wrong,but it's like this on the Saturn version too. +-hanagumi: + \-ending screens have corrupt graphics. (*untested*) +-kiwames: + \-incorrect color emulation for the alpha blended flames on the title screen,it's caused by a schizoid + linescroll emulation quirk. + \-the VDP1 sprites refresh is too slow,causing the "Draw by request" mode to + flicker.Moved back to default ATM. +-pblbeach: + \-Sprites are offset, because it doesn't clear vdp1 local coordinates set by bios, + I guess that they are cleared when some vdp1 register is written (kludged for now) +-prikura: + \-Attract mode presentation has corrupted graphics in various places,probably caused by incomplete + framebuffer data delete. +-seabass: + \-Player sprite is corrupt/missing during movements,caused by incomplete framebuffer switching. + +Notes of Interest & Unclear features: + +-the test mode / bios is drawn with layer NBG3; +-hanagumi puts a 'RED' dragon logo in tileram (base 0x64000, 4bpp, 8x8 tiles) but +its not displayed because its priority value is 0.Left-over? + +-scrolling is screen display wise,meaning that a scrolling value is masked with the +screen resolution size values; + +-H-Blank bit is INDIPENDENT of the V-Blank bit...trying to fix enable/disable it during V-Blank period + causes wrong gameplay speed in Golden Axe:The Duel. + +-Bitmaps uses transparency pens,examples are: +\-elandore's energy bars; +\-mausuke's foreground(the one used on the playfield) +\-shanhigw's tile-based sprites; +The transparency pen table is like this: + +|------------------|---------------------| +| Character count | Transparency code | +|------------------|---------------------| +| 16 colors |=0x0 (4 bits) | +| 256 colors |=0x00 (8 bits) | +| 2048 colors |=0x000 (11 bits) | +| 32,768 colors |MSB=0 (bit 15) | +| 16,770,000 colors|MSB=0 (bit 31) | +|------------------|---------------------| +In other words,the first three types uses the offset and not the color allocated. + +-double density interlace setting (LSMD == 3) apparently does a lot of fancy stuff in the graphics sizes. + +-Debug key list(only if you enable the debug mode on top of this file): + \-T: NBG3 layer toggle + \-Y: NBG2 layer toggle + \-U: NBG1 layer toggle + \-I: NBG0 layer toggle + \-O: SPRITE toggle + \-K: RBG0 layer toggle + \-W Decodes the graphics for F4 menu. + \-M Stores VDP1 ram contents from a file. + \-N Stores VDP1 ram contents into a file. +*/ + +#include "emu.h" +#include "includes/stv.h" + +enum +{ + STV_TRANSPARENCY_NONE, + STV_TRANSPARENCY_PEN, + STV_TRANSPARENCY_ADD_BLEND, + STV_TRANSPARENCY_ALPHA +}; + +#if DEBUG_MODE +#define LOG_VDP2 1 +#define LOG_ROZ 0 +#else +#define LOG_VDP2 0 +#define LOG_ROZ 0 +#endif + +/* + +-------------------------------------------------|-----------------------------|------------------------------ +| Function | Normal Scroll Screen | Rotation Scroll Screen | +| |-----------------------------|-----------------------------|------------------------------ +| | NBG0 | NBG1 | NBG2 | NBG3 | RBG0 | RBG1 | +-------------------------------------------------|-----------------------------|------------------------------ +| Character Colour | 16 colours | 16 colours | 16 colours | 16 colours | 16 colours | 16 colours | +| Count | 256 " " | 256 " " | 256 " " | 256 " " | 256 " " | 256 " " | +| | 2048 " " | 2048 " " | | | 2048 " " | 2048 " " | +| | 32768 " " | 32768 " " | | | 32768 " " | 32768 " " | +| | 16770000 " " | | | | 16770000 " " | 16770000 " " | +-------------------------------------------------|-----------------------------|------------------------------ +| Character Size | 1x1 Cells , 2x2 Cells | +-------------------------------------------------|-----------------------------|------------------------------ +| Pattern Name | 1 word , 2 words | +| Data Size | | +-------------------------------------------------|-----------------------------|------------------------------ +| Plane Size | 1 H x 1 V 1 Pages ; 2 H x 1 V 1 Pages ; 2 H x 2 V Pages | +-------------------------------------------------|-----------------------------|------------------------------ +| Plane Count | 4 | 16 | +-------------------------------------------------|-----------------------------|------------------------------ +| Bitmap Possible | Yes | No | Yes | No | +-------------------------------------------------|-----------------------------|------------------------------ +| Bitmap Size | 512 x 256 | N/A | 512x256 | N/A | +| | 512 x 512 | | 512x512 | | +| | 1024 x 256 | | | | +| | 1024 x 512 | | | | +-------------------------------------------------|-----------------------------|------------------------------ +| Scale | 0.25 x - 256 x | None | Any ? | +-------------------------------------------------|-----------------------------|------------------------------ +| Rotation | No | Yes | +-------------------------------------------------|-----------------------------|-----------------------------| +| Linescroll | Yes | No | +-------------------------------------------------|-----------------------------|------------------------------ +| Column Scroll | Yes | No | +-------------------------------------------------|-----------------------------|------------------------------ +| Mosaic | Yes | Horizontal Only | +-------------------------------------------------|-----------------------------|------------------------------ + +*/ + +/* 180000 - r/w - TVMD - TV Screen Mode + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | DISP | -- | -- | -- | -- | -- | -- | BDCLMD | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | LSMD1 | LSMD0 | VRESO1 | VRESO0 | -- | HRESO2 | HRESO1 | HRESO0 | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_TVMD (m_vdp2_regs[0x000/2]) + + #define STV_VDP2_DISP ((STV_VDP2_TVMD & 0x8000) >> 15) + #define STV_VDP2_BDCLMD ((STV_VDP2_TVMD & 0x0100) >> 8) + #define STV_VDP2_LSMD ((STV_VDP2_TVMD & 0x00c0) >> 6) + #define STV_VDP2_VRES ((STV_VDP2_TVMD & 0x0030) >> 4) + #define STV_VDP2_HRES ((STV_VDP2_TVMD & 0x0007) >> 0) + +/* 180002 - r/w - EXTEN - External Signal Enable Register + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | -- | EXLTEN | EXSYEN | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | -- | DASEL | EXBGEN | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_EXTEN (m_vdp2_regs[0x002/2]) + + #define STV_VDP2_EXLTEN ((STV_VDP2_EXTEN & 0x0200) >> 9) + +/* 180004 - r/o - TVSTAT - Screen Status + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | -- | EXLTFG | EXSYFG | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | VBLANK | HBLANK | ODD | EVEN | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + +/* 180006 - r/w - VRSIZE - VRAM Size + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | VRAMSZ | -- | -- | -- | -- | -- | -- | -- | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | VER3 | VER2 | VER1 | VER0 | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_VRSIZE (m_vdp2_regs[0x006/2]) + + #define STV_VDP2_VRAMSZ ((STV_VDP2_VRSIZE & 0x8000) >> 15) + +/* 180008 - r/o - HCNT - H-Counter + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | -- | HCT9 | HCT8 | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | HCT7 | HCT6 | HCT5 | HCT4 | HCT3 | HCT2 | HCT1 | HCT0 | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_HCNT (m_vdp2_regs[0x008/2]) + +/* 18000A - r/o - VCNT - V-Counter + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | -- | VCT9 | VCT8 | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | VCT7 | VCT6 | VCT5 | VCT4 | VCT3 | VCT2 | VCT1 | VCT0 | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_VCNT (m_vdp2_regs[0x00a/2]) + +/* 18000C - RESERVED + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | -- | -- | -- | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | -- | -- | -- | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + +/* 18000E - r/w - RAMCTL - RAM Control + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | CRKTE | -- | CRMD1 | CRMD0 | -- | -- | VRBMD | VRAMD | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | RDBSB11 | RDBSB10 | RDBSB01 | RDBSB00 | RDBSA11 | RDBSA10 | RDBSA01 | RDBSA00 | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_RAMCTL (m_vdp2_regs[0x00e/2]) + + #define STV_VDP2_CRKTE ((STV_VDP2_RAMCTL & 0x8000) >> 15) + #define STV_VDP2_CRMD ((STV_VDP2_RAMCTL & 0x3000) >> 12) + #define STV_VDP2_RDBSB1 ((STV_VDP2_RAMCTL & 0x00c0) >> 6) + #define STV_VDP2_RDBSB0 ((STV_VDP2_RAMCTL & 0x0030) >> 4) + #define STV_VDP2_RDBSA1 ((STV_VDP2_RAMCTL & 0x000c) >> 2) + #define STV_VDP2_RDBSA0 ((STV_VDP2_RAMCTL & 0x0003) >> 0) + + +/* 180010 - r/w - -CYCA0L - VRAM CYCLE PATTERN (BANK A0) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | VCP0A03 | VCP0A02 | VCP0A01 | VCP0A00 | VCP1A03 | VCP1A02 | VCP1A01 | VCP1A00 | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | VCP2A03 | VCP2A02 | VCP2A01 | VCP2A00 | VCP3A03 | VCP3A02 | VCP3A01 | VCP3A00 | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_CYCA0L (m_vdp2_regs[0x010/2]) + +/* 180012 - r/w - -CYCA0U - VRAM CYCLE PATTERN (BANK A0) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | VCP4A03 | VCP4A02 | VCP4A01 | VCP4A00 | VCP5A03 | VCP5A02 | VCP5A01 | VCP5A00 | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | VCP6A03 | VCP6A02 | VCP6A01 | VCP6A00 | VCP7A03 | VCP7A02 | VCP7A01 | VCP7A00 | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_CYCA0U (m_vdp2_regs[0x012/2]) + +/* 180014 - r/w - -CYCA1L - VRAM CYCLE PATTERN (BANK A1) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | VCP0A13 | VCP0A12 | VCP0A11 | VCP0A10 | VCP1A13 | VCP1A12 | VCP1A11 | VCP1A10 | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | VCP2A13 | VCP2A12 | VCP2A11 | VCP2A10 | VCP3A13 | VCP3A12 | VCP3A11 | VCP3A10 | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_CYCA1L (m_vdp2_regs[0x014/2]) + +/* 180016 - r/w - -CYCA1U - VRAM CYCLE PATTERN (BANK A1) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | VCP4A13 | VCP4A12 | VCP4A11 | VCP4A10 | VCP5A13 | VCP5A12 | VCP5A11 | VCP5A10 | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | VCP6A13 | VCP6A12 | VCP6A11 | VCP6A10 | VCP7A13 | VCP7A12 | VCP7A11 | VCP7A10 | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_CYCA1U (m_vdp2_regs[0x016/2]) + +/* 180018 - r/w - -CYCB0L - VRAM CYCLE PATTERN (BANK B0) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | VCP0B03 | VCP0B02 | VCP0B01 | VCP0B00 | VCP1B03 | VCP1B02 | VCP1B01 | VCP1B00 | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | VCP2B03 | VCP2B02 | VCP2B01 | VCP2B00 | VCP3B03 | VCP3B02 | VCP3B01 | VCP3B00 | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_CYCA2L (m_vdp2_regs[0x018/2]) + +/* 18001A - r/w - -CYCB0U - VRAM CYCLE PATTERN (BANK B0) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | VCP4B03 | VCP4B02 | VCP4B01 | VCP4B00 | VCP5B03 | VCP5B02 | VCP5B01 | VCP5B00 | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | VCP6B03 | VCP6B02 | VCP6B01 | VCP6B00 | VCP7B03 | VCP7B02 | VCP7B01 | VCP7B00 | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_CYCA2U (m_vdp2_regs[0x01a/2]) + +/* 18001C - r/w - -CYCB1L - VRAM CYCLE PATTERN (BANK B1) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | VCP0B13 | VCP0B12 | VCP0B11 | VCP0B10 | VCP1B13 | VCP1B12 | VCP1B11 | VCP1B10 | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | VCP2B13 | VCP2B12 | VCP2B11 | VCP2B10 | VCP3B13 | VCP3B12 | VCP3B11 | VCP3B10 | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_CYCA3L (m_vdp2_regs[0x01c/2]) + +/* 18001E - r/w - -CYCB1U - VRAM CYCLE PATTERN (BANK B1) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | VCP4B13 | VCP4B12 | VCP4B11 | VCP4B10 | VCP5B13 | VCP5B12 | VCP5B11 | VCP5B10 | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | VCP6B13 | VCP6B12 | VCP6B11 | VCP6B10 | VCP7B13 | VCP7B12 | VCP7B11 | VCP7B10 | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_CYCA3U (m_vdp2_regs[0x01e/2]) + +/* 180020 - r/w - BGON - SCREEN DISPLAY ENABLE + + this register allows each tilemap to be enabled or disabled and also which layers are solid + + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | R0TPON | N3TPON | N2TPON | N1TPON | N0TPON | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | R1ON | R0ON | N3ON | N2ON | N1ON | N0ON | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_BGON (m_vdp2_regs[0x020/2]) + + // NxOn - Layer Enable Register + #define STV_VDP2_xxON ((STV_VDP2_BGON & 0x001f) >> 0) /* to see if anything is enabled */ + + #define STV_VDP2_N0ON ((STV_VDP2_BGON & 0x0001) >> 0) /* N0On = NBG0 Enable */ + #define STV_VDP2_N1ON ((STV_VDP2_BGON & 0x0002) >> 1) /* N1On = NBG1 Enable */ + #define STV_VDP2_N2ON ((STV_VDP2_BGON & 0x0004) >> 2) /* N2On = NBG2 Enable */ + #define STV_VDP2_N3ON ((STV_VDP2_BGON & 0x0008) >> 3) /* N3On = NBG3 Enable */ + #define STV_VDP2_R0ON ((STV_VDP2_BGON & 0x0010) >> 4) /* R0On = RBG0 Enable */ + #define STV_VDP2_R1ON ((STV_VDP2_BGON & 0x0020) >> 5) /* R1On = RBG1 Enable */ + + // NxTPON - Transparency Pen Enable Registers + #define STV_VDP2_N0TPON ((STV_VDP2_BGON & 0x0100) >> 8) /* N0TPON = NBG0 Draw Transparent Pen (as solid) /or/ RBG1 Draw Transparent Pen */ + #define STV_VDP2_N1TPON ((STV_VDP2_BGON & 0x0200) >> 9) /* N1TPON = NBG1 Draw Transparent Pen (as solid) /or/ EXBG Draw Transparent Pen */ + #define STV_VDP2_N2TPON ((STV_VDP2_BGON & 0x0400) >> 10)/* N2TPON = NBG2 Draw Transparent Pen (as solid) */ + #define STV_VDP2_N3TPON ((STV_VDP2_BGON & 0x0800) >> 11)/* N3TPON = NBG3 Draw Transparent Pen (as solid) */ + #define STV_VDP2_R0TPON ((STV_VDP2_BGON & 0x1000) >> 12)/* R0TPON = RBG0 Draw Transparent Pen (as solid) */ + +/* +180022 - MZCTL - Mosaic Control +bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | -- | -- | -- | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | -- | -- | -- | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_MZCTL (m_vdp2_regs[0x022/2]) + + #define STV_VDP2_MZSZV ((STV_VDP2_MZCTL & 0xf000) >> 12) + #define STV_VDP2_MZSZH ((STV_VDP2_MZCTL & 0x0f00) >> 8) + #define STV_VDP2_R0MZE ((STV_VDP2_MZCTL & 0x0010) >> 4) + #define STV_VDP2_N3MZE ((STV_VDP2_MZCTL & 0x0008) >> 3) + #define STV_VDP2_N2MZE ((STV_VDP2_MZCTL & 0x0004) >> 2) + #define STV_VDP2_N1MZE ((STV_VDP2_MZCTL & 0x0002) >> 1) + #define STV_VDP2_N0MZE ((STV_VDP2_MZCTL & 0x0001) >> 0) + +/*180024 - Special Function Code Select + +*/ + + #define STV_VDP2_SFSEL (m_vdp2_regs[0x024/2]) + +/*180026 - Special Function Code + +*/ + + #define STV_VDP2_SFCODE (m_vdp2_regs[0x026/2]) + + +/* +180028 - CHCTLA - Character Control (NBG0, NBG1) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | N1CHCN1 | N1CHCN0 | N1BMSZ1 | N1BMSZ0 | N1BMEN | N1CHSZ | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | N0CHCN2 | N0CHCN1 | N0CHCN0 | N0BMSZ1 | N0BMSZ0 | N0BMEN | N0CHSZ | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_CHCTLA (m_vdp2_regs[0x028/2]) + +/* -------------------------- NBG0 Character Control Registers -------------------------- */ + +/* N0CHCNx NBG0 (or RGB1) Colour Depth + 000 - 16 Colours + 001 - 256 Colours + 010 - 2048 Colours + 011 - 32768 Colours (RGB5) + 100 - 16770000 Colours (RGB8) + 101 - invalid + 110 - invalid + 111 - invalid */ + #define STV_VDP2_N0CHCN ((STV_VDP2_CHCTLA & 0x0070) >> 4) + +/* N0BMSZx - NBG0 Bitmap Size *guessed* + 00 - 512 x 256 + 01 - 512 x 512 + 10 - 1024 x 256 + 11 - 1024 x 512 */ + #define STV_VDP2_N0BMSZ ((STV_VDP2_CHCTLA & 0x000c) >> 2) + +/* N0BMEN - NBG0 Bitmap Enable + 0 - use cell mode + 1 - use bitmap mode */ + #define STV_VDP2_N0BMEN ((STV_VDP2_CHCTLA & 0x0002) >> 1) + +/* N0CHSZ - NBG0 Character (Tile) Size + 0 - 1 cell x 1 cell (8x8) + 1 - 2 cells x 2 cells (16x16) */ + #define STV_VDP2_N0CHSZ ((STV_VDP2_CHCTLA & 0x0001) >> 0) + +/* -------------------------- NBG1 Character Control Registers -------------------------- */ + +/* N1CHCNx - NBG1 (or EXB1) Colour Depth + 00 - 16 Colours + 01 - 256 Colours + 10 - 2048 Colours + 11 - 32768 Colours (RGB5) */ + #define STV_VDP2_N1CHCN ((STV_VDP2_CHCTLA & 0x3000) >> 12) + +/* N1BMSZx - NBG1 Bitmap Size *guessed* + 00 - 512 x 256 + 01 - 512 x 512 + 10 - 1024 x 256 + 11 - 1024 x 512 */ + #define STV_VDP2_N1BMSZ ((STV_VDP2_CHCTLA & 0x0c00) >> 10) + +/* N1BMEN - NBG1 Bitmap Enable + 0 - use cell mode + 1 - use bitmap mode */ + #define STV_VDP2_N1BMEN ((STV_VDP2_CHCTLA & 0x0200) >> 9) + +/* N1CHSZ - NBG1 Character (Tile) Size + 0 - 1 cell x 1 cell (8x8) + 1 - 2 cells x 2 cells (16x16) */ + #define STV_VDP2_N1CHSZ ((STV_VDP2_CHCTLA & 0x0100) >> 8) + +/* +18002A - CHCTLB - Character Control (NBG2, NBG1, RBG0) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | R0CHCN2 | R0CHCN1 | R0CHCN0 | -- | R0BMSZ | R0BMEN | R0CHSZ | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | N3CHCN | N3CHSZ | -- | -- | N2CHCN | N2CHSZ | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_CHCTLB (m_vdp2_regs[0x02a/2]) + +/* -------------------------- RBG0 Character Control Registers -------------------------- */ + + +/* R0CHCNx RBG0 Colour Depth + 000 - 16 Colours + 001 - 256 Colours + 010 - 2048 Colours + 011 - 32768 Colours (RGB5) + 100 - 16770000 Colours (RGB8) + 101 - invalid + 110 - invalid + 111 - invalid */ + #define STV_VDP2_R0CHCN ((STV_VDP2_CHCTLB & 0x7000) >> 12) + +/* R0BMSZx - RBG0 Bitmap Size *guessed* + 00 - 512 x 256 + 01 - 512 x 512 */ + #define STV_VDP2_R0BMSZ ((STV_VDP2_CHCTLB & 0x0400) >> 10) + +/* R0BMEN - RBG0 Bitmap Enable + 0 - use cell mode + 1 - use bitmap mode */ + #define STV_VDP2_R0BMEN ((STV_VDP2_CHCTLB & 0x0200) >> 9) + +/* R0CHSZ - RBG0 Character (Tile) Size + 0 - 1 cell x 1 cell (8x8) + 1 - 2 cells x 2 cells (16x16) */ + #define STV_VDP2_R0CHSZ ((STV_VDP2_CHCTLB & 0x0100) >> 8) + + #define STV_VDP2_N3CHCN ((STV_VDP2_CHCTLB & 0x0020) >> 5) + #define STV_VDP2_N3CHSZ ((STV_VDP2_CHCTLB & 0x0010) >> 4) + #define STV_VDP2_N2CHCN ((STV_VDP2_CHCTLB & 0x0002) >> 1) + #define STV_VDP2_N2CHSZ ((STV_VDP2_CHCTLB & 0x0001) >> 0) + + +/* +18002C - BMPNA - Bitmap Palette Number (NBG0, NBG1) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | -- | -- | -- | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | -- | -- | -- | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_BMPNA (m_vdp2_regs[0x02c/2]) + + #define STV_VDP2_N1BMP ((STV_VDP2_BMPNA & 0x0700) >> 8) + #define STV_VDP2_N0BMP ((STV_VDP2_BMPNA & 0x0007) >> 0) + +/* 18002E - Bitmap Palette Number (RBG0) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | -- | -- | -- | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | -- | -- | -- | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_BMPNB (m_vdp2_regs[0x02e/2]) + + #define STV_VDP2_R0BMP ((STV_VDP2_BMPNB & 0x0007) >> 0) + +/* 180030 - PNCN0 - Pattern Name Control (NBG0) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | N0PNB | N0CNSM | -- | -- | -- | -- | N0SPR | N0SCC | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | N0SPLT6 | N0SPLT5 | N0SPLT4 | N0SPCN4 | N0SPCN3 | N0SPCN2 | N0SPCN1 | N0SPCN0 | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_PNCN0 (m_vdp2_regs[0x030/2]) + +/* Pattern Data Size + 0 = 2 bytes + 1 = 1 byte */ + #define STV_VDP2_N0PNB ((STV_VDP2_PNCN0 & 0x8000) >> 15) + +/* Character Number Supplement (in 1 byte mode) + 0 = Character Number = 10bits + 2bits for flip + 1 = Character Number = 12 bits, no flip */ + #define STV_VDP2_N0CNSM ((STV_VDP2_PNCN0 & 0x4000) >> 14) + +/* NBG0 Special Priority Register (in 1 byte mode) */ + #define STV_VDP2_N0SPR ((STV_VDP2_PNCN0 & 0x0200) >> 9) + +/* NBG0 Special Colour Control Register (in 1 byte mode) */ + #define STV_VDP2_N0SCC ((STV_VDP2_PNCN0 & 0x0100) >> 8) + +/* Supplementary Palette Bits (in 1 byte mode) */ + #define STV_VDP2_N0SPLT ((STV_VDP2_PNCN0 & 0x00e0) >> 5) + +/* Supplementary Character Bits (in 1 byte mode) */ + #define STV_VDP2_N0SPCN ((STV_VDP2_PNCN0 & 0x001f) >> 0) + +/* 180032 - Pattern Name Control (NBG1) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | -- | -- | -- | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | -- | -- | -- | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_PNCN1 (m_vdp2_regs[0x032/2]) + +/* Pattern Data Size + 0 = 2 bytes + 1 = 1 byte */ + #define STV_VDP2_N1PNB ((STV_VDP2_PNCN1 & 0x8000) >> 15) + +/* Character Number Supplement (in 1 byte mode) + 0 = Character Number = 10bits + 2bits for flip + 1 = Character Number = 12 bits, no flip */ + #define STV_VDP2_N1CNSM ((STV_VDP2_PNCN1 & 0x4000) >> 14) + +/* NBG0 Special Priority Register (in 1 byte mode) */ + #define STV_VDP2_N1SPR ((STV_VDP2_PNCN1 & 0x0200) >> 9) + +/* NBG0 Special Colour Control Register (in 1 byte mode) */ + #define STV_VDP2_N1SCC ((STV_VDP2_PNCN1 & 0x0100) >> 8) + +/* Supplementary Palette Bits (in 1 byte mode) */ + #define STV_VDP2_N1SPLT ((STV_VDP2_PNCN1 & 0x00e0) >> 5) + +/* Supplementary Character Bits (in 1 byte mode) */ + #define STV_VDP2_N1SPCN ((STV_VDP2_PNCN1 & 0x001f) >> 0) + + +/* 180034 - Pattern Name Control (NBG2) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | -- | -- | -- | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | -- | -- | -- | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_PNCN2 (m_vdp2_regs[0x034/2]) + +/* Pattern Data Size + 0 = 2 bytes + 1 = 1 byte */ + #define STV_VDP2_N2PNB ((STV_VDP2_PNCN2 & 0x8000) >> 15) + +/* Character Number Supplement (in 1 byte mode) + 0 = Character Number = 10bits + 2bits for flip + 1 = Character Number = 12 bits, no flip */ + #define STV_VDP2_N2CNSM ((STV_VDP2_PNCN2 & 0x4000) >> 14) + +/* NBG0 Special Priority Register (in 1 byte mode) */ + #define STV_VDP2_N2SPR ((STV_VDP2_PNCN2 & 0x0200) >> 9) + +/* NBG0 Special Colour Control Register (in 1 byte mode) */ + #define STV_VDP2_N2SCC ((STV_VDP2_PNCN2 & 0x0100) >> 8) + +/* Supplementary Palette Bits (in 1 byte mode) */ + #define STV_VDP2_N2SPLT ((STV_VDP2_PNCN2 & 0x00e0) >> 5) + +/* Supplementary Character Bits (in 1 byte mode) */ + #define STV_VDP2_N2SPCN ((STV_VDP2_PNCN2 & 0x001f) >> 0) + + +/* 180036 - Pattern Name Control (NBG3) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | N3PNB | N3CNSM | -- | -- | -- | -- | N3SPR | N3SCC | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | N3SPLT6 | N3SPLT5 | N3SPLT4 | N3SPCN4 | N3SPCN3 | N3SPCN2 | N3SPCN1 | N3SPCN0 | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_PNCN3 (m_vdp2_regs[0x036/2]) + +/* Pattern Data Size + 0 = 2 bytes + 1 = 1 byte */ + #define STV_VDP2_N3PNB ((STV_VDP2_PNCN3 & 0x8000) >> 15) + +/* Character Number Supplement (in 1 byte mode) + 0 = Character Number = 10bits + 2bits for flip + 1 = Character Number = 12 bits, no flip */ + #define STV_VDP2_N3CNSM ((STV_VDP2_PNCN3 & 0x4000) >> 14) + +/* NBG0 Special Priority Register (in 1 byte mode) */ + #define STV_VDP2_N3SPR ((STV_VDP2_PNCN3 & 0x0200) >> 9) + +/* NBG0 Special Colour Control Register (in 1 byte mode) */ + #define STV_VDP2_N3SCC ((STV_VDP2_PNCN3 & 0x0100) >> 8) + +/* Supplementary Palette Bits (in 1 byte mode) */ + #define STV_VDP2_N3SPLT ((STV_VDP2_PNCN3 & 0x00e0) >> 5) + +/* Supplementary Character Bits (in 1 byte mode) */ + #define STV_VDP2_N3SPCN ((STV_VDP2_PNCN3 & 0x001f) >> 0) + + +/* 180038 - Pattern Name Control (RBG0) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | -- | -- | -- | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | -- | -- | -- | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_PNCR (m_vdp2_regs[0x038/2]) + +/* Pattern Data Size + 0 = 2 bytes + 1 = 1 byte */ + #define STV_VDP2_R0PNB ((STV_VDP2_PNCR & 0x8000) >> 15) + +/* Character Number Supplement (in 1 byte mode) + 0 = Character Number = 10bits + 2bits for flip + 1 = Character Number = 12 bits, no flip */ + #define STV_VDP2_R0CNSM ((STV_VDP2_PNCR & 0x4000) >> 14) + +/* NBG0 Special Priority Register (in 1 byte mode) */ + #define STV_VDP2_R0SPR ((STV_VDP2_PNCR & 0x0200) >> 9) + +/* NBG0 Special Colour Control Register (in 1 byte mode) */ + #define STV_VDP2_R0SCC ((STV_VDP2_PNCR & 0x0100) >> 8) + +/* Supplementary Palette Bits (in 1 byte mode) */ + #define STV_VDP2_R0SPLT ((STV_VDP2_PNCR & 0x00e0) >> 5) + +/* Supplementary Character Bits (in 1 byte mode) */ + #define STV_VDP2_R0SPCN ((STV_VDP2_PNCR & 0x001f) >> 0) + +/* 18003A - PLSZ - Plane Size + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | -- | -- | -- | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | N3PLSZ1 | N3PLSZ0 | -- | -- | N1PLSZ1 | N1PLSZ0 | N0PLSZ1 | N0PLSZ0 | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_PLSZ (m_vdp2_regs[0x03a/2]) + + /* NBG0 Plane Size + 00 1H Page x 1V Page + 01 2H Pages x 1V Page + 10 invalid + 11 2H Pages x 2V Pages */ + #define STV_VDP2_RBOVR ((STV_VDP2_PLSZ & 0xc000) >> 14) + #define STV_VDP2_RBPLSZ ((STV_VDP2_PLSZ & 0x3000) >> 12) + #define STV_VDP2_RAOVR ((STV_VDP2_PLSZ & 0x0c00) >> 10) + #define STV_VDP2_RAPLSZ ((STV_VDP2_PLSZ & 0x0300) >> 8) + #define STV_VDP2_N3PLSZ ((STV_VDP2_PLSZ & 0x00c0) >> 6) + #define STV_VDP2_N2PLSZ ((STV_VDP2_PLSZ & 0x0030) >> 4) + #define STV_VDP2_N1PLSZ ((STV_VDP2_PLSZ & 0x000c) >> 2) + #define STV_VDP2_N0PLSZ ((STV_VDP2_PLSZ & 0x0003) >> 0) + +/* 18003C - MPOFN - Map Offset (NBG0, NBG1, NBG2, NBG3) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | N3MP8 | N3MP7 | N3MP6 | -- | N2MP8 | N2MP7 | N2MP6 | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | N1MP8 | N1MP7 | N1MP6 | -- | N0MP8 | N0MP7 | N0MP6 | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_MPOFN_ (m_vdp2_regs[0x03c/2]) + + /* Higher 3 bits of the map offset for each layer */ + #define STV_VDP2_N3MP_ ((STV_VDP2_MPOFN_ & 0x3000) >> 12) + #define STV_VDP2_N2MP_ ((STV_VDP2_MPOFN_ & 0x0300) >> 8) + #define STV_VDP2_N1MP_ ((STV_VDP2_MPOFN_ & 0x0030) >> 4) + #define STV_VDP2_N0MP_ ((STV_VDP2_MPOFN_ & 0x0003) >> 0) + + + + +/* 18003E - Map Offset (Rotation Parameter A,B) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | -- | -- | -- | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | -- | -- | -- | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_MPOFR_ (m_vdp2_regs[0x03e/2]) + + #define STV_VDP2_RBMP_ ((STV_VDP2_MPOFR_ & 0x0030) >> 4) + #define STV_VDP2_RAMP_ ((STV_VDP2_MPOFR_ & 0x0003) >> 0) + +/* 180040 - MPABN0 - Map (NBG0, Plane A,B) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | N0MPB5 | N0MPB4 | N0MPB3 | N0MPB2 | N0MPB1 | N0MPB0 | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | N0MPA5 | N0MPA4 | N0MPA3 | N0MPA2 | N0MPA1 | N0MPA0 | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_MPABN0 (m_vdp2_regs[0x040/2]) + + /* N0MPB5 = lower 6 bits of Map Address of Plane B of Tilemap NBG0 */ + #define STV_VDP2_N0MPB ((STV_VDP2_MPABN0 & 0x3f00) >> 8) + + /* N0MPA5 = lower 6 bits of Map Address of Plane A of Tilemap NBG0 */ + #define STV_VDP2_N0MPA ((STV_VDP2_MPABN0 & 0x003f) >> 0) + + +/* 180042 - MPCDN0 - (NBG0, Plane C,D) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | N0MPD5 | N0MPD4 | N0MPD3 | N0MPD2 | N0MPD1 | N0MPD0 | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | N0MPC5 | N0MPC4 | N0MPC3 | N0MPC2 | N0MPC1 | N0MPC0 | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_MPCDN0 (m_vdp2_regs[0x042/2]) + + /* N0MPB5 = lower 6 bits of Map Address of Plane D of Tilemap NBG0 */ + #define STV_VDP2_N0MPD ((STV_VDP2_MPCDN0 & 0x3f00) >> 8) + + /* N0MPA5 = lower 6 bits of Map Address of Plane C of Tilemap NBG0 */ + #define STV_VDP2_N0MPC ((STV_VDP2_MPCDN0 & 0x003f) >> 0) + + +/* 180044 - Map (NBG1, Plane A,B) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | -- | -- | -- | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | -- | -- | -- | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_MPABN1 (m_vdp2_regs[0x044/2]) + + /* N0MPB5 = lower 6 bits of Map Address of Plane B of Tilemap NBG1 */ + #define STV_VDP2_N1MPB ((STV_VDP2_MPABN1 & 0x3f00) >> 8) + + /* N0MPA5 = lower 6 bits of Map Address of Plane A of Tilemap NBG1 */ + #define STV_VDP2_N1MPA ((STV_VDP2_MPABN1 & 0x003f) >> 0) + +/* 180046 - Map (NBG1, Plane C,D) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | -- | -- | -- | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | -- | -- | -- | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_MPCDN1 (m_vdp2_regs[0x046/2]) + + /* N0MPB5 = lower 6 bits of Map Address of Plane D of Tilemap NBG0 */ + #define STV_VDP2_N1MPD ((STV_VDP2_MPCDN1 & 0x3f00) >> 8) + + /* N0MPA5 = lower 6 bits of Map Address of Plane C of Tilemap NBG0 */ + #define STV_VDP2_N1MPC ((STV_VDP2_MPCDN1 & 0x003f) >> 0) + + +/* 180048 - Map (NBG2, Plane A,B) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | -- | -- | -- | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | -- | -- | -- | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_MPABN2 (m_vdp2_regs[0x048/2]) + + /* N0MPB5 = lower 6 bits of Map Address of Plane B of Tilemap NBG2 */ + #define STV_VDP2_N2MPB ((STV_VDP2_MPABN2 & 0x3f00) >> 8) + + /* N0MPA5 = lower 6 bits of Map Address of Plane A of Tilemap NBG2 */ + #define STV_VDP2_N2MPA ((STV_VDP2_MPABN2 & 0x003f) >> 0) + +/* 18004a - Map (NBG2, Plane C,D) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | -- | -- | -- | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | -- | -- | -- | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_MPCDN2 (m_vdp2_regs[0x04a/2]) + + /* N0MPB5 = lower 6 bits of Map Address of Plane D of Tilemap NBG2 */ + #define STV_VDP2_N2MPD ((STV_VDP2_MPCDN2 & 0x3f00) >> 8) + + /* N0MPA5 = lower 6 bits of Map Address of Plane C of Tilemap NBG2 */ + #define STV_VDP2_N2MPC ((STV_VDP2_MPCDN2 & 0x003f) >> 0) + +/* 18004c - Map (NBG3, Plane A,B) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | -- | -- | -- | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | -- | -- | -- | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_MPABN3 (m_vdp2_regs[0x04c/2]) + + /* N0MPB5 = lower 6 bits of Map Address of Plane B of Tilemap NBG1 */ + #define STV_VDP2_N3MPB ((STV_VDP2_MPABN3 & 0x3f00) >> 8) + + /* N0MPA5 = lower 6 bits of Map Address of Plane A of Tilemap NBG1 */ + #define STV_VDP2_N3MPA ((STV_VDP2_MPABN3 & 0x003f) >> 0) + + +/* 18004e - Map (NBG3, Plane C,D) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | -- | -- | -- | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | -- | -- | -- | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_MPCDN3 (m_vdp2_regs[0x04e/2]) + + /* N0MPB5 = lower 6 bits of Map Address of Plane B of Tilemap NBG0 */ + #define STV_VDP2_N3MPD ((STV_VDP2_MPCDN3 & 0x3f00) >> 8) + + /* N0MPA5 = lower 6 bits of Map Address of Plane A of Tilemap NBG0 */ + #define STV_VDP2_N3MPC ((STV_VDP2_MPCDN3 & 0x003f) >> 0) + +/* 180050 - Map (Rotation Parameter A, Plane A,B) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | -- | -- | -- | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | -- | -- | -- | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_MPABRA (m_vdp2_regs[0x050/2]) + + /* R0MPB5 = lower 6 bits of Map Address of Plane B of Tilemap RBG0 */ + #define STV_VDP2_RAMPB ((STV_VDP2_MPABRA & 0x3f00) >> 8) + + /* R0MPA5 = lower 6 bits of Map Address of Plane A of Tilemap RBG0 */ + #define STV_VDP2_RAMPA ((STV_VDP2_MPABRA & 0x003f) >> 0) + + + +/* 180052 - Map (Rotation Parameter A, Plane C,D) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | -- | -- | -- | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | -- | -- | -- | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + #define STV_VDP2_MPCDRA (m_vdp2_regs[0x052/2]) + + /* R0MPB5 = lower 6 bits of Map Address of Plane D of Tilemap RBG0 */ + #define STV_VDP2_RAMPD ((STV_VDP2_MPCDRA & 0x3f00) >> 8) + + /* R0MPA5 = lower 6 bits of Map Address of Plane C of Tilemap RBG0 */ + #define STV_VDP2_RAMPC ((STV_VDP2_MPCDRA & 0x003f) >> 0) + +/* 180054 - Map (Rotation Parameter A, Plane E,F) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | -- | -- | -- | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | -- | -- | -- | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + #define STV_VDP2_MPEFRA (m_vdp2_regs[0x054/2]) + + /* R0MPB5 = lower 6 bits of Map Address of Plane F of Tilemap RBG0 */ + #define STV_VDP2_RAMPF ((STV_VDP2_MPEFRA & 0x3f00) >> 8) + + /* R0MPA5 = lower 6 bits of Map Address of Plane E of Tilemap RBG0 */ + #define STV_VDP2_RAMPE ((STV_VDP2_MPEFRA & 0x003f) >> 0) + +/* 180056 - Map (Rotation Parameter A, Plane G,H) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | -- | -- | -- | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | -- | -- | -- | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + #define STV_VDP2_MPGHRA (m_vdp2_regs[0x056/2]) + + /* R0MPB5 = lower 6 bits of Map Address of Plane H of Tilemap RBG0 */ + #define STV_VDP2_RAMPH ((STV_VDP2_MPGHRA & 0x3f00) >> 8) + + /* R0MPA5 = lower 6 bits of Map Address of Plane G of Tilemap RBG0 */ + #define STV_VDP2_RAMPG ((STV_VDP2_MPGHRA & 0x003f) >> 0) + +/* 180058 - Map (Rotation Parameter A, Plane I,J) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | -- | -- | -- | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | -- | -- | -- | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + #define STV_VDP2_MPIJRA (m_vdp2_regs[0x058/2]) + + /* R0MPB5 = lower 6 bits of Map Address of Plane J of Tilemap RBG0 */ + #define STV_VDP2_RAMPJ ((STV_VDP2_MPIJRA & 0x3f00) >> 8) + + /* R0MPA5 = lower 6 bits of Map Address of Plane I of Tilemap RBG0 */ + #define STV_VDP2_RAMPI ((STV_VDP2_MPIJRA & 0x003f) >> 0) + +/* 18005a - Map (Rotation Parameter A, Plane K,L) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | -- | -- | -- | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | -- | -- | -- | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + #define STV_VDP2_MPKLRA (m_vdp2_regs[0x05a/2]) + + /* R0MPB5 = lower 6 bits of Map Address of Plane L of Tilemap RBG0 */ + #define STV_VDP2_RAMPL ((STV_VDP2_MPKLRA & 0x3f00) >> 8) + + /* R0MPA5 = lower 6 bits of Map Address of Plane K of Tilemap RBG0 */ + #define STV_VDP2_RAMPK ((STV_VDP2_MPKLRA & 0x003f) >> 0) + +/* 18005c - Map (Rotation Parameter A, Plane M,N) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | -- | -- | -- | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | -- | -- | -- | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + #define STV_VDP2_MPMNRA (m_vdp2_regs[0x05c/2]) + + /* R0MPB5 = lower 6 bits of Map Address of Plane N of Tilemap RBG0 */ + #define STV_VDP2_RAMPN ((STV_VDP2_MPMNRA & 0x3f00) >> 8) + + /* R0MPA5 = lower 6 bits of Map Address of Plane M of Tilemap RBG0 */ + #define STV_VDP2_RAMPM ((STV_VDP2_MPMNRA & 0x003f) >> 0) + +/* 18005e - Map (Rotation Parameter A, Plane O,P) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | -- | -- | -- | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | -- | -- | -- | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + #define STV_VDP2_MPOPRA (m_vdp2_regs[0x05e/2]) + + /* R0MPB5 = lower 6 bits of Map Address of Plane P of Tilemap RBG0 */ + #define STV_VDP2_RAMPP ((STV_VDP2_MPOPRA & 0x3f00) >> 8) + + /* R0MPA5 = lower 6 bits of Map Address of Plane O of Tilemap RBG0 */ + #define STV_VDP2_RAMPO ((STV_VDP2_MPOPRA & 0x003f) >> 0) + +/* 180060 - Map (Rotation Parameter B, Plane A,B) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | -- | -- | -- | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | -- | -- | -- | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_MPABRB (m_vdp2_regs[0x060/2]) + + /* R0MPB5 = lower 6 bits of Map Address of Plane B of Tilemap RBG0 */ + #define STV_VDP2_RBMPB ((STV_VDP2_MPABRB & 0x3f00) >> 8) + + /* R0MPA5 = lower 6 bits of Map Address of Plane A of Tilemap RBG0 */ + #define STV_VDP2_RBMPA ((STV_VDP2_MPABRB & 0x003f) >> 0) + + +/* 180062 - Map (Rotation Parameter B, Plane C,D) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | -- | -- | -- | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | -- | -- | -- | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_MPCDRB (m_vdp2_regs[0x062/2]) + + /* R0MPD5 = lower 6 bits of Map Address of Plane D of Tilemap RBG0 */ + #define STV_VDP2_RBMPD ((STV_VDP2_MPCDRB & 0x3f00) >> 8) + + /* R0MPc5 = lower 6 bits of Map Address of Plane C of Tilemap RBG0 */ + #define STV_VDP2_RBMPC ((STV_VDP2_MPCDRB & 0x003f) >> 0) + +/* 180064 - Map (Rotation Parameter B, Plane E,F) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | -- | -- | -- | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | -- | -- | -- | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_MPEFRB (m_vdp2_regs[0x064/2]) + + /* R0MPF5 = lower 6 bits of Map Address of Plane F of Tilemap RBG0 */ + #define STV_VDP2_RBMPF ((STV_VDP2_MPEFRB & 0x3f00) >> 8) + + /* R0MPE5 = lower 6 bits of Map Address of Plane E of Tilemap RBG0 */ + #define STV_VDP2_RBMPE ((STV_VDP2_MPEFRB & 0x003f) >> 0) + +/* 180066 - Map (Rotation Parameter B, Plane G,H) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | -- | -- | -- | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | -- | -- | -- | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_MPGHRB (m_vdp2_regs[0x066/2]) + + /* R0MPH5 = lower 6 bits of Map Address of Plane H of Tilemap RBG0 */ + #define STV_VDP2_RBMPH ((STV_VDP2_MPGHRB & 0x3f00) >> 8) + + /* R0MPG5 = lower 6 bits of Map Address of Plane G of Tilemap RBG0 */ + #define STV_VDP2_RBMPG ((STV_VDP2_MPGHRB & 0x003f) >> 0) + +/* 180068 - Map (Rotation Parameter B, Plane I,J) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | -- | -- | -- | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | -- | -- | -- | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_MPIJRB (m_vdp2_regs[0x068/2]) + + /* R0MPJ5 = lower 6 bits of Map Address of Plane J of Tilemap RBG0 */ + #define STV_VDP2_RBMPJ ((STV_VDP2_MPIJRB & 0x3f00) >> 8) + + /* R0MPI5 = lower 6 bits of Map Address of Plane E of Tilemap RBG0 */ + #define STV_VDP2_RBMPI ((STV_VDP2_MPIJRB & 0x003f) >> 0) + +/* 18006a - Map (Rotation Parameter B, Plane K,L) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | -- | -- | -- | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | -- | -- | -- | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_MPKLRB (m_vdp2_regs[0x06a/2]) + + /* R0MPL5 = lower 6 bits of Map Address of Plane L of Tilemap RBG0 */ + #define STV_VDP2_RBMPL ((STV_VDP2_MPKLRB & 0x3f00) >> 8) + + /* R0MPK5 = lower 6 bits of Map Address of Plane K of Tilemap RBG0 */ + #define STV_VDP2_RBMPK ((STV_VDP2_MPKLRB & 0x003f) >> 0) + +/* 18006c - Map (Rotation Parameter B, Plane M,N) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | -- | -- | -- | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | -- | -- | -- | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_MPMNRB (m_vdp2_regs[0x06c/2]) + + /* R0MPN5 = lower 6 bits of Map Address of Plane N of Tilemap RBG0 */ + #define STV_VDP2_RBMPN ((STV_VDP2_MPMNRB & 0x3f00) >> 8) + + /* R0MPM5 = lower 6 bits of Map Address of Plane M of Tilemap RBG0 */ + #define STV_VDP2_RBMPM ((STV_VDP2_MPMNRB & 0x003f) >> 0) + +/* 18006e - Map (Rotation Parameter B, Plane O,P) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | -- | -- | -- | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | -- | -- | -- | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_MPOPRB (m_vdp2_regs[0x06e/2]) + + /* R0MPP5 = lower 6 bits of Map Address of Plane P of Tilemap RBG0 */ + #define STV_VDP2_RBMPP ((STV_VDP2_MPOPRB & 0x3f00) >> 8) + + /* R0MPO5 = lower 6 bits of Map Address of Plane O of Tilemap RBG0 */ + #define STV_VDP2_RBMPO ((STV_VDP2_MPOPRB & 0x003f) >> 0) + +/* 180070 - SCXIN0 - Screen Scroll (NBG0, Horizontal Integer Part) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | -- | -- | -- | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | -- | -- | -- | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_SCXIN0 (m_vdp2_regs[0x070/2]) + + +/* 180072 - Screen Scroll (NBG0, Horizontal Fractional Part) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | -- | -- | -- | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | -- | -- | -- | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_SCXDN0 (m_vdp2_regs[0x072/2]) + +/* 180074 - SCYIN0 - Screen Scroll (NBG0, Vertical Integer Part) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | -- | -- | -- | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | -- | -- | -- | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + #define STV_VDP2_SCYIN0 (m_vdp2_regs[0x074/2]) + + +/* 180076 - Screen Scroll (NBG0, Vertical Fractional Part) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | -- | -- | -- | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | -- | -- | -- | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_SCYDN0 (m_vdp2_regs[0x076/2]) + +/* 180078 - Coordinate Inc (NBG0, Horizontal Integer Part) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | -- | -- | -- | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | -- | -- | -- | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_ZMXIN0 (m_vdp2_regs[0x078/2]) + + #define STV_VDP2_N0ZMXI ((STV_VDP2_ZMXIN0 & 0x0007) >> 0) + +/* 18007a - Coordinate Inc (NBG0, Horizontal Fractional Part) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | -- | -- | -- | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | -- | -- | -- | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_ZMXDN0 (m_vdp2_regs[0x07a/2]) + + #define STV_VDP2_N0ZMXD ((STV_VDP2_ZMXDN0 >> 8)& 0xff) + #define STV_VDP2_ZMXN0 (((STV_VDP2_N0ZMXI<<16) | (STV_VDP2_N0ZMXD<<8)) & 0x0007ff00) + + +/* 18007c - Coordinate Inc (NBG0, Vertical Integer Part) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | -- | -- | -- | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | -- | -- | -- | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_ZMYIN0 (m_vdp2_regs[0x07c/2]) + + #define STV_VDP2_N0ZMYI ((STV_VDP2_ZMYIN0 & 0x0007) >> 0) + +/* 18007e - Coordinate Inc (NBG0, Vertical Fractional Part) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | -- | -- | -- | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | -- | -- | -- | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_ZMYDN0 (m_vdp2_regs[0x07e/2]) + + #define STV_VDP2_N0ZMYD ((STV_VDP2_ZMYDN0 >> 8)& 0xff) + #define STV_VDP2_ZMYN0 (((STV_VDP2_N0ZMYI<<16) | (STV_VDP2_N0ZMYD<<8)) & 0x0007ff00) + +/* 180080 - SCXIN1 - Screen Scroll (NBG1, Horizontal Integer Part) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | -- | -- | -- | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | -- | -- | -- | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_SCXIN1 (m_vdp2_regs[0x080/2]) + +/* 180082 - Screen Scroll (NBG1, Horizontal Fractional Part) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | -- | -- | -- | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | -- | -- | -- | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_SCXDN1 (m_vdp2_regs[0x082/2]) + +/* 180084 - SCYIN1 - Screen Scroll (NBG1, Vertical Integer Part) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | -- | -- | -- | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | -- | -- | -- | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_SCYIN1 (m_vdp2_regs[0x084/2]) + +/* 180086 - Screen Scroll (NBG1, Vertical Fractional Part) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | -- | -- | -- | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | -- | -- | -- | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_SCYDN1 (m_vdp2_regs[0x086/2]) + +/* 180088 - Coordinate Inc (NBG1, Horizontal Integer Part) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | -- | -- | -- | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | -- | -- | -- | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_ZMXIN1 (m_vdp2_regs[0x088/2]) + + #define STV_VDP2_N1ZMXI ((STV_VDP2_ZMXIN1 & 0x0007) >> 0) + +/* 18008a - Coordinate Inc (NBG1, Horizontal Fractional Part) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | -- | -- | -- | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | -- | -- | -- | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_ZMXDN1 (m_vdp2_regs[0x08a/2]) + + #define STV_VDP2_N1ZMXD ((STV_VDP2_ZMXDN1 >> 8)& 0xff) + #define STV_VDP2_ZMXN1 (((STV_VDP2_N1ZMXI<<16) | (STV_VDP2_N1ZMXD<<8)) & 0x0007ff00) + +/* 18008c - Coordinate Inc (NBG1, Vertical Integer Part) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | -- | -- | -- | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | -- | -- | -- | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_ZMYIN1 (m_vdp2_regs[0x08c/2]) + + #define STV_VDP2_N1ZMYI ((STV_VDP2_ZMYIN1 & 0x0007) >> 0) + +/* 18008e - Coordinate Inc (NBG1, Vertical Fractional Part) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | -- | -- | -- | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | -- | -- | -- | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_ZMYDN1 (m_vdp2_regs[0x08e/2]) + + #define STV_VDP2_N1ZMYD ((STV_VDP2_ZMYDN1 >> 8)& 0xff) + #define STV_VDP2_ZMYN1 (((STV_VDP2_N1ZMYI<<16) | (STV_VDP2_N1ZMYD<<8)) & 0x007ff00) + +/* 180090 - SCXN2 - Screen Scroll (NBG2, Horizontal) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | -- | -- | -- | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | -- | -- | -- | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_SCXN2 (m_vdp2_regs[0x090/2]) + +/* 180092 - SCYN2 - Screen Scroll (NBG2, Vertical) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | -- | -- | -- | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | -- | -- | -- | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_SCYN2 (m_vdp2_regs[0x092/2]) + +/* 180094 - SCXN3 - Screen Scroll (NBG3, Horizontal) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | -- | -- | -- | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | -- | -- | -- | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_SCXN3 (m_vdp2_regs[0x094/2]) + +/* 180096 - SCYN3 - Screen Scroll (NBG3, Vertical) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | -- | -- | -- | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | -- | -- | -- | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_SCYN3 (m_vdp2_regs[0x096/2]) + +/* 180098 - Reduction Enable + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | -- | N1ZMQT | N1ZMHF | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | -- | N0ZMQT | N0ZMHF | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_ZMCTL (m_vdp2_regs[0x098/2]) + + #define STV_VDP2_N1ZMQT ((STV_VDP2_ZMCTL & 0x0200) >> 9) + #define STV_VDP2_N1ZMHF ((STV_VDP2_ZMCTL & 0x0100) >> 8) + #define STV_VDP2_N0ZMQT ((STV_VDP2_ZMCTL & 0x0002) >> 1) + #define STV_VDP2_N0ZMHF ((STV_VDP2_ZMCTL & 0x0001) >> 0) + +/* 18009a - Line and Vertical Cell Scroll Control (NBG0, NBG1) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | -- | -- | -- | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | -- | -- | -- | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_SCRCTL (m_vdp2_regs[0x09a/2]) + + #define STV_VDP2_N1LSS ((STV_VDP2_SCRCTL & 0x3000) >> 12) + #define STV_VDP2_N1LZMX ((STV_VDP2_SCRCTL & 0x0800) >> 11) + #define STV_VDP2_N1LSCY ((STV_VDP2_SCRCTL & 0x0400) >> 10) + #define STV_VDP2_N1LSCX ((STV_VDP2_SCRCTL & 0x0200) >> 9) + #define STV_VDP2_N1VCSC ((STV_VDP2_SCRCTL & 0x0100) >> 8) + #define STV_VDP2_N0LSS ((STV_VDP2_SCRCTL & 0x0030) >> 4) + #define STV_VDP2_N0LZMX ((STV_VDP2_SCRCTL & 0x0008) >> 3) + #define STV_VDP2_N0LSCY ((STV_VDP2_SCRCTL & 0x0004) >> 2) + #define STV_VDP2_N0LSCX ((STV_VDP2_SCRCTL & 0x0002) >> 1) + #define STV_VDP2_N0VCSC ((STV_VDP2_SCRCTL & 0x0001) >> 0) + +/* 18009c - Vertical Cell Table Address (NBG0, NBG1) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | -- | -- | -- | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | -- | -- | -- | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_VCSTAU (m_vdp2_regs[0x09c/2] & 7) + + +/* 18009e - Vertical Cell Table Address (NBG0, NBG1) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | -- | -- | -- | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | -- | -- | -- | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_VCSTAL (m_vdp2_regs[0x09e/2]) + + +/* 1800a0 - LSTA0U - Line Scroll Table Address (NBG0) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | -- | -- | -- | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | -- | -- | -- | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + /*bit 2 unused when VRAM = 4 Mbits*/ + #define STV_VDP2_LSTA0U (m_vdp2_regs[0x0a0/2] & 7) + +/* 1800a2 - LSTA0L - Line Scroll Table Address (NBG0) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | -- | -- | -- | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | -- | -- | -- | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_LSTA0L (m_vdp2_regs[0x0a2/2]) + +/* 1800a4 - LSTA1U - Line Scroll Table Address (NBG1) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | -- | -- | -- | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | -- | -- | -- | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + /*bit 2 unused when VRAM = 4 Mbits*/ + #define STV_VDP2_LSTA1U (m_vdp2_regs[0x0a4/2] & 7) + +/* 1800a6 - LSTA1L - Line Scroll Table Address (NBG1) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | -- | -- | -- | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | -- | -- | -- | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_LSTA1L (m_vdp2_regs[0x0a6/2]) + +/* 1800a8 - LCTAU - Line Colour Screen Table Address + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | -- | -- | -- | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | -- | -- | -- | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_LCTAU (m_vdp2_regs[0x0a8/2]) + #define STV_VDP2_LCCLMD ((STV_VDP2_LCTAU & 0x8000) >> 15) + +/* 1800aa - LCTAL - Line Colour Screen Table Address + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | -- | -- | -- | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | -- | -- | -- | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + #define STV_VDP2_LCTAL (m_vdp2_regs[0x0aa/2]) + + #define STV_VDP2_LCTA (((STV_VDP2_LCTAU & 0x0007) << 16) | (STV_VDP2_LCTAL & 0xffff)) + +/* 1800ac - Back Screen Table Address + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | BKCLMD | -- | -- | -- | -- | -- | -- | -- | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | BKTA18 | BKTA17 | BKTA16 | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_BKTAU (m_vdp2_regs[0x0ac/2]) + + #define STV_VDP2_BKCLMD ((STV_VDP2_BKTAU & 0x8000) >> 15) + + +/* 1800ae - Back Screen Table Address + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | BKTA15 | BKTA14 | BKTA13 | BKTA12 | BKTA11 | BKTA10 | BKTA9 | BKTA8 | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | BKTA7 | BKTA7 | BKTA6 | BKTA5 | BKTA4 | BKTA3 | BKTA2 | BKTA0 | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_BKTAL (m_vdp2_regs[0x0ae/2]) + + #define STV_VDP2_BKTA (((STV_VDP2_BKTAU & 0x0007) << 16) | (STV_VDP2_BKTAL & 0xffff)) + +/* 1800b0 - RPMD - Rotation Parameter Mode + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | -- | -- | -- | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | -- | -- | -- | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_RPMD ((m_vdp2_regs[0x0b0/2]) & 0x0003) + +/* 1800b2 - RPRCTL - Rotation Parameter Read Control + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | RBKASTRE | RBYSTRE | RBXSTRE | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | RAKASTRE | RAYSTRE | RBXSTRE | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_RPRCTL (m_vdp2_regs[0x0b2/2]) + #define STV_VDP2_RBKASTRE ((STV_VDP2_RPRCTL & 0x0400) >> 10) + #define STV_VDP2_RBYSTRE ((STV_VDP2_RPRCTL & 0x0200) >> 9) + #define STV_VDP2_RBXSTRE ((STV_VDP2_RPRCTL & 0x0100) >> 8) + #define STV_VDP2_RAKASTRE ((STV_VDP2_RPRCTL & 0x0004) >> 2) + #define STV_VDP2_RAYSTRE ((STV_VDP2_RPRCTL & 0x0002) >> 1) + #define STV_VDP2_RAXSTRE ((STV_VDP2_RPRCTL & 0x0001) >> 0) + +/* 1800b4 - KTCTL - Coefficient Table Control + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | RBKLCE | RBKMD1 | RBKMD0 | RBKDBS | RBKTE | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | RAKLCE | RAKMD1 | RAKMD0 | RAKDBS | RAKTE | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_KTCTL (m_vdp2_regs[0x0b4/2]) + #define STV_VDP2_RBKLCE ((STV_VDP2_KTCTL & 0x1000) >> 12) + #define STV_VDP2_RBKMD ((STV_VDP2_KTCTL & 0x0c00) >> 10) + #define STV_VDP2_RBKDBS ((STV_VDP2_KTCTL & 0x0200) >> 9) + #define STV_VDP2_RBKTE ((STV_VDP2_KTCTL & 0x0100) >> 8) + #define STV_VDP2_RAKLCE ((STV_VDP2_KTCTL & 0x0010) >> 4) + #define STV_VDP2_RAKMD ((STV_VDP2_KTCTL & 0x000c) >> 2) + #define STV_VDP2_RAKDBS ((STV_VDP2_KTCTL & 0x0002) >> 1) + #define STV_VDP2_RAKTE ((STV_VDP2_KTCTL & 0x0001) >> 0) + +/* 1800b6 - KTAOF - Coefficient Table Address Offset (Rotation Parameter A,B) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | RBKTAOS2 | RBKTAOS1 | RBKTAOS0 | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | RAKTAOS2 | RAKTAOS1 | RAKTAOS0 | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_KTAOF (m_vdp2_regs[0x0b6/2]) + #define STV_VDP2_RBKTAOS ((STV_VDP2_KTAOF & 0x0700) >> 8) + #define STV_VDP2_RAKTAOS ((STV_VDP2_KTAOF & 0x0007) >> 0) + +/* 1800b8 - OVPNRA - Screen Over Pattern Name (Rotation Parameter A) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | -- | -- | -- | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | -- | -- | -- | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_OVPNRA (m_vdp2_regs[0x0b8/2]) + +/* 1800ba - Screen Over Pattern Name (Rotation Parameter B) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | -- | -- | -- | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | -- | -- | -- | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_OVPNRB (m_vdp2_regs[0x0ba/2]) + +/* 1800bc - RPTAU - Rotation Parameter Table Address (Rotation Parameter A,B) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | -- | -- | -- | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | RPTA18 | RPTA17 | RPTA16 | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + #define STV_VDP2_RPTAU (m_vdp2_regs[0x0bc/2] & 7) + +/* 1800be - RPTAL - Rotation Parameter Table Address (Rotation Parameter A,B) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | RPTA15 | RPTA14 | RPTA13 | RPTA12 | RPTA11 | RPTA10 | RPTA9 | RPTA8 | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | RPTA7 | RPTA6 | RPTA5 | RPTA4 | RPTA3 | RPTA2 | RPTA1 | -- | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_RPTAL (m_vdp2_regs[0x0be/2] & 0x0000ffff) + +/* 1800c0 - Window Position (W0, Horizontal Start Point) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | -- | -- | -- | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | -- | -- | -- | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_WPSX0 (m_vdp2_regs[0x0c0/2]) + + #define STV_VDP2_W0SX ((STV_VDP2_WPSX0 & 0x03ff) >> 0) + +/* 1800c2 - Window Position (W0, Vertical Start Point) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | -- | -- | -- | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | -- | -- | -- | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_WPSY0 (m_vdp2_regs[0x0c2/2]) + + #define STV_VDP2_W0SY ((STV_VDP2_WPSY0 & 0x03ff) >> 0) + +/* 1800c4 - Window Position (W0, Horizontal End Point) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | -- | -- | -- | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | -- | -- | -- | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_WPEX0 (m_vdp2_regs[0x0c4/2]) + + #define STV_VDP2_W0EX ((STV_VDP2_WPEX0 & 0x03ff) >> 0) + +/* 1800c6 - Window Position (W0, Vertical End Point) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | -- | -- | -- | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | -- | -- | -- | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_WPEY0 (m_vdp2_regs[0x0c6/2]) + + #define STV_VDP2_W0EY ((STV_VDP2_WPEY0 & 0x03ff) >> 0) + +/* 1800c8 - Window Position (W1, Horizontal Start Point) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | -- | -- | -- | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | -- | -- | -- | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_WPSX1 (m_vdp2_regs[0x0c8/2]) + + #define STV_VDP2_W1SX ((STV_VDP2_WPSX1 & 0x03ff) >> 0) + +/* 1800ca - Window Position (W1, Vertical Start Point) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | -- | -- | -- | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | -- | -- | -- | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_WPSY1 (m_vdp2_regs[0x0ca/2]) + + #define STV_VDP2_W1SY ((STV_VDP2_WPSY1 & 0x03ff) >> 0) + +/* 1800cc - Window Position (W1, Horizontal End Point) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | -- | -- | -- | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | -- | -- | -- | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_WPEX1 (m_vdp2_regs[0x0cc/2]) + + #define STV_VDP2_W1EX ((STV_VDP2_WPEX1 & 0x03ff) >> 0) + +/* 1800ce - Window Position (W1, Vertical End Point) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | -- | -- | -- | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | -- | -- | -- | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_WPEY1 (m_vdp2_regs[0x0ce/2]) + + #define STV_VDP2_W1EY ((STV_VDP2_WPEY1 & 0x03ff) >> 0) + +/* 1800d0 - Window Control (NBG0, NBG1) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | -- | -- | -- | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | -- | -- | -- | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_WCTLA (m_vdp2_regs[0x0d0/2]) + #define STV_VDP2_N1LOG ((STV_VDP2_WCTLA & 0x8000) >> 15) + #define STV_VDP2_N1SWE ((STV_VDP2_WCTLA & 0x2000) >> 13) + #define STV_VDP2_N1SWA ((STV_VDP2_WCTLA & 0x1000) >> 12) + #define STV_VDP2_N1W1E ((STV_VDP2_WCTLA & 0x0800) >> 11) + #define STV_VDP2_N1W1A ((STV_VDP2_WCTLA & 0x0400) >> 10) + #define STV_VDP2_N1W0E ((STV_VDP2_WCTLA & 0x0200) >> 9) + #define STV_VDP2_N1W0A ((STV_VDP2_WCTLA & 0x0100) >> 8) + #define STV_VDP2_N0LOG ((STV_VDP2_WCTLA & 0x0080) >> 7) + #define STV_VDP2_N0SWE ((STV_VDP2_WCTLA & 0x0020) >> 5) + #define STV_VDP2_N0SWA ((STV_VDP2_WCTLA & 0x0010) >> 4) + #define STV_VDP2_N0W1E ((STV_VDP2_WCTLA & 0x0008) >> 3) + #define STV_VDP2_N0W1A ((STV_VDP2_WCTLA & 0x0004) >> 2) + #define STV_VDP2_N0W0E ((STV_VDP2_WCTLA & 0x0002) >> 1) + #define STV_VDP2_N0W0A ((STV_VDP2_WCTLA & 0x0001) >> 0) + +/* 1800d2 - Window Control (NBG2, NBG3) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | -- | -- | -- | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | -- | -- | -- | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_WCTLB (m_vdp2_regs[0x0d2/2]) + #define STV_VDP2_N3LOG ((STV_VDP2_WCTLB & 0x8000) >> 15) + #define STV_VDP2_N3SWE ((STV_VDP2_WCTLB & 0x2000) >> 13) + #define STV_VDP2_N3SWA ((STV_VDP2_WCTLB & 0x1000) >> 12) + #define STV_VDP2_N3W1E ((STV_VDP2_WCTLB & 0x0800) >> 11) + #define STV_VDP2_N3W1A ((STV_VDP2_WCTLB & 0x0400) >> 10) + #define STV_VDP2_N3W0E ((STV_VDP2_WCTLB & 0x0200) >> 9) + #define STV_VDP2_N3W0A ((STV_VDP2_WCTLB & 0x0100) >> 8) + #define STV_VDP2_N2LOG ((STV_VDP2_WCTLB & 0x0080) >> 7) + #define STV_VDP2_N2SWE ((STV_VDP2_WCTLB & 0x0020) >> 5) + #define STV_VDP2_N2SWA ((STV_VDP2_WCTLB & 0x0010) >> 4) + #define STV_VDP2_N2W1E ((STV_VDP2_WCTLB & 0x0008) >> 3) + #define STV_VDP2_N2W1A ((STV_VDP2_WCTLB & 0x0004) >> 2) + #define STV_VDP2_N2W0E ((STV_VDP2_WCTLB & 0x0002) >> 1) + #define STV_VDP2_N2W0A ((STV_VDP2_WCTLB & 0x0001) >> 0) + +/* 1800d4 - Window Control (RBG0, Sprite) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | -- | -- | -- | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | -- | -- | -- | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_WCTLC (m_vdp2_regs[0x0d4/2]) + #define STV_VDP2_SPLOG ((STV_VDP2_WCTLC & 0x8000) >> 15) + #define STV_VDP2_SPSWE ((STV_VDP2_WCTLC & 0x2000) >> 13) + #define STV_VDP2_SPSWA ((STV_VDP2_WCTLC & 0x1000) >> 12) + #define STV_VDP2_SPW1E ((STV_VDP2_WCTLC & 0x0800) >> 11) + #define STV_VDP2_SPW1A ((STV_VDP2_WCTLC & 0x0400) >> 10) + #define STV_VDP2_SPW0E ((STV_VDP2_WCTLC & 0x0200) >> 9) + #define STV_VDP2_SPW0A ((STV_VDP2_WCTLC & 0x0100) >> 8) + #define STV_VDP2_R0LOG ((STV_VDP2_WCTLC & 0x0080) >> 7) + #define STV_VDP2_R0SWE ((STV_VDP2_WCTLC & 0x0020) >> 5) + #define STV_VDP2_R0SWA ((STV_VDP2_WCTLC & 0x0010) >> 4) + #define STV_VDP2_R0W1E ((STV_VDP2_WCTLC & 0x0008) >> 3) + #define STV_VDP2_R0W1A ((STV_VDP2_WCTLC & 0x0004) >> 2) + #define STV_VDP2_R0W0E ((STV_VDP2_WCTLC & 0x0002) >> 1) + #define STV_VDP2_R0W0A ((STV_VDP2_WCTLC & 0x0001) >> 0) + +/* 1800d6 - Window Control (Parameter Window, Colour Calc. Window) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | -- | -- | -- | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | -- | -- | -- | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_WCTLD (m_vdp2_regs[0x0d6/2]) + #define STV_VDP2_CCLOG ((STV_VDP2_WCTLD & 0x8000) >> 15) + #define STV_VDP2_CCSWE ((STV_VDP2_WCTLD & 0x2000) >> 13) + #define STV_VDP2_CCSWA ((STV_VDP2_WCTLD & 0x1000) >> 12) + #define STV_VDP2_CCW1E ((STV_VDP2_WCTLD & 0x0800) >> 11) + #define STV_VDP2_CCW1A ((STV_VDP2_WCTLD & 0x0400) >> 10) + #define STV_VDP2_CCW0E ((STV_VDP2_WCTLD & 0x0200) >> 9) + #define STV_VDP2_CCW0A ((STV_VDP2_WCTLD & 0x0100) >> 8) + #define STV_VDP2_RPLOG ((STV_VDP2_WCTLD & 0x0080) >> 7) + #define STV_VDP2_RPW1E ((STV_VDP2_WCTLD & 0x0008) >> 3) + #define STV_VDP2_RPW1A ((STV_VDP2_WCTLD & 0x0004) >> 2) + #define STV_VDP2_RPW0E ((STV_VDP2_WCTLD & 0x0002) >> 1) + #define STV_VDP2_RPW0A ((STV_VDP2_WCTLD & 0x0001) >> 0) + +/* 1800d8 - Line Window Table Address (W0) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | -- | -- | -- | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | -- | -- | -- | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_LWTA0U (m_vdp2_regs[0x0d8/2]) + + #define STV_VDP2_W0LWE ((STV_VDP2_LWTA0U & 0x8000) >> 15) + +/* 1800da - Line Window Table Address (W0) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | -- | -- | -- | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | -- | -- | -- | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_LWTA0L (m_vdp2_regs[0x0da/2]) + + /* bit 19 isn't used when VRAM = 4 Mbit */ + #define STV_VDP2_W0LWTA (((STV_VDP2_LWTA0U & 0x0007) << 16) | (STV_VDP2_LWTA0L & 0xfffe)) + + +/* 1800dc - Line Window Table Address (W1) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | -- | -- | -- | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | -- | -- | -- | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_LWTA1U (m_vdp2_regs[0x0dc/2]) + + #define STV_VDP2_W1LWE ((STV_VDP2_LWTA1U & 0x8000) >> 15) + + +/* 1800de - Line Window Table Address (W1) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | -- | -- | -- | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | -- | -- | -- | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_LWTA1L (m_vdp2_regs[0x0de/2]) + + /* bit 19 isn't used when VRAM = 4 Mbit */ + #define STV_VDP2_W1LWTA (((STV_VDP2_LWTA1U & 0x0007) << 16) | (STV_VDP2_LWTA1L & 0xfffe)) + + +/* 1800e0 - Sprite Control + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | SPCCCS1 | SPCCCS0 | -- | SPCCN2 | SPCCN1 | SPCCN0 | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | SPCLMD | SPWINEN | SPTYPE3 | SPTYPE2 | SPTYPE1 | SPTYPE0 | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_SPCTL (m_vdp2_regs[0xe0/2]) + #define STV_VDP2_SPCCCS ((STV_VDP2_SPCTL & 0x3000) >> 12) + #define STV_VDP2_SPCCN ((STV_VDP2_SPCTL & 0x700) >> 8) + #define STV_VDP2_SPCLMD ((STV_VDP2_SPCTL & 0x20) >> 5) + #define STV_VDP2_SPWINEN ((STV_VDP2_SPCTL & 0x10) >> 4) + #define STV_VDP2_SPTYPE (STV_VDP2_SPCTL & 0xf) + +/* 1800e2 - Shadow Control + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | -- | -- | -- | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | -- | -- | -- | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_SDCTL (m_vdp2_regs[0x0e2/2]) + +/* 1800e4 - CRAOFA - Colour Ram Address Offset (NBG0 - NBG3) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | N0CAOS2 | N3CAOS1 | N3CAOS0 | -- | N2CAOS2 | N2CAOS1 | N2CAOS0 | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | N1CAOS2 | N1CAOS1 | N1CAOS0 | -- | N0CAOS2 | N0CAOS1 | N0CAOS0 | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_CRAOFA (m_vdp2_regs[0x0e4/2]) + + /* NxCAOS = */ + #define STV_VDP2_N0CAOS ((STV_VDP2_CRAOFA & 0x0007) >> 0) + #define STV_VDP2_N1CAOS ((STV_VDP2_CRAOFA & 0x0070) >> 4) + #define STV_VDP2_N2CAOS ((STV_VDP2_CRAOFA & 0x0700) >> 8) + #define STV_VDP2_N3CAOS ((STV_VDP2_CRAOFA & 0x7000) >> 12) + + +/* 1800e6 - Colour Ram Address Offset (RBG0, SPRITE) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | -- | -- | -- | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | -- | -- | -- | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + #define STV_VDP2_CRAOFB (m_vdp2_regs[0x0e6/2]) + #define STV_VDP2_R0CAOS ((STV_VDP2_CRAOFB & 0x0007) >> 0) + #define STV_VDP2_SPCAOS ((STV_VDP2_CRAOFB & 0x0070) >> 4) + +/* 1800e8 - LNCLEN - Line Colour Screen Enable + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | -- | -- | -- | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | SPLCEN | R0LCEN | N3LCEN | N2LCEN | N1LCEN | N0LCEN | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_LNCLEN (m_vdp2_regs[0x0e8/2]) + #define STV_VDP2_SPLCEN ((STV_VDP2_LNCLEN & 0x0020) >> 5) + #define STV_VDP2_R0LCEN ((STV_VDP2_LNCLEN & 0x0010) >> 4) + #define STV_VDP2_N3LCEN ((STV_VDP2_LNCLEN & 0x0008) >> 3) + #define STV_VDP2_N2LCEN ((STV_VDP2_LNCLEN & 0x0004) >> 2) + #define STV_VDP2_N1LCEN ((STV_VDP2_LNCLEN & 0x0002) >> 1) + #define STV_VDP2_N0LCEN ((STV_VDP2_LNCLEN & 0x0001) >> 0) + +/* 1800ea - Special Priority Mode + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | -- | -- | -- | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | -- | -- | -- | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_SFPRMD (m_vdp2_regs[0x0ea/2]) + + +/* 1800ec - Colour Calculation Control + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | BOKEN | BOKN2 | BOKN1 | BOKN0 | -- | EXCCEN | CCRTMD | CCMD | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | SPCCEN | LCCCEN | R0CCEN | N3CCEN | N2CCEN | N1CCEN | N0CCEN | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_CCCR (m_vdp2_regs[0x0ec/2]) + #define STV_VDP2_CCMD ((STV_VDP2_CCCR & 0x100) >> 8) + #define STV_VDP2_SPCCEN ((STV_VDP2_CCCR & 0x40) >> 6) + #define STV_VDP2_LCCCEN ((STV_VDP2_CCCR & 0x20) >> 5) + #define STV_VDP2_R0CCEN ((STV_VDP2_CCCR & 0x10) >> 4) + #define STV_VDP2_N3CCEN ((STV_VDP2_CCCR & 0x8) >> 3) + #define STV_VDP2_N2CCEN ((STV_VDP2_CCCR & 0x4) >> 2) + #define STV_VDP2_N1CCEN ((STV_VDP2_CCCR & 0x2) >> 1) + #define STV_VDP2_N0CCEN ((STV_VDP2_CCCR & 0x1) >> 0) + + +/* 1800ee - Special Colour Calculation Mode + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | -- | -- | -- | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | -- | -- | -- | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_SFCCMD (m_vdp2_regs[0x0ee/2]) + +/* 1800f0 - Priority Number (Sprite 0,1) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | S1PRIN2 | S1PRIN1 | S1PRIN0 | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | S0PRIN2 | S0PRIN1 | S0PRIN0 | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_PRISA (m_vdp2_regs[0x0f0/2]) + #define STV_VDP2_S1PRIN ((STV_VDP2_PRISA & 0x0700) >> 8) + #define STV_VDP2_S0PRIN ((STV_VDP2_PRISA & 0x0007) >> 0) + +/* 1800f2 - Priority Number (Sprite 2,3) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | S3PRIN2 | S3PRIN1 | S3PRIN0 | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | S2PRIN2 | S2PRIN1 | S2PRIN0 | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_PRISB (m_vdp2_regs[0x0f2/2]) + #define STV_VDP2_S3PRIN ((STV_VDP2_PRISB & 0x0700) >> 8) + #define STV_VDP2_S2PRIN ((STV_VDP2_PRISB & 0x0007) >> 0) + +/* 1800f4 - Priority Number (Sprite 4,5) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | S5PRIN2 | S5PRIN1 | S5PRIN0 | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | S4PRIN2 | S4PRIN1 | S4PRIN0 | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_PRISC (m_vdp2_regs[0x0f4/2]) + #define STV_VDP2_S5PRIN ((STV_VDP2_PRISC & 0x0700) >> 8) + #define STV_VDP2_S4PRIN ((STV_VDP2_PRISC & 0x0007) >> 0) + +/* 1800f6 - Priority Number (Sprite 6,7) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | S7PRIN2 | S7PRIN1 | S7PRIN0 | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | S6PRIN2 | S6PRIN1 | S6PRIN0 | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_PRISD (m_vdp2_regs[0x0f6/2]) + #define STV_VDP2_S7PRIN ((STV_VDP2_PRISD & 0x0700) >> 8) + #define STV_VDP2_S6PRIN ((STV_VDP2_PRISD & 0x0007) >> 0) + + +/* 1800f8 - PRINA - Priority Number (NBG 0,1) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | -- | -- | -- | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | -- | -- | -- | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_PRINA (m_vdp2_regs[0x0f8/2]) + + #define STV_VDP2_N1PRIN ((STV_VDP2_PRINA & 0x0700) >> 8) + #define STV_VDP2_N0PRIN ((STV_VDP2_PRINA & 0x0007) >> 0) + +/* 1800fa - PRINB - Priority Number (NBG 2,3) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | -- | -- | -- | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | -- | -- | -- | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_PRINB (m_vdp2_regs[0x0fa/2]) + + #define STV_VDP2_N3PRIN ((STV_VDP2_PRINB & 0x0700) >> 8) + #define STV_VDP2_N2PRIN ((STV_VDP2_PRINB & 0x0007) >> 0) + +/* 1800fc - Priority Number (RBG0) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | -- | -- | -- | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | -- | -- | -- | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + #define STV_VDP2_PRIR (m_vdp2_regs[0x0fc/2]) + + #define STV_VDP2_R0PRIN ((STV_VDP2_PRIR & 0x0007) >> 0) + +/* 1800fe - Reserved + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | -- | -- | -- | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | -- | -- | -- | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + +/* 180100 - Colour Calculation Ratio (Sprite 0,1) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | S1CCRT4 | S1CCRT3 | S1CCRT2 | S1CCRT1 | S1CCRT0 | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | S0CCRT4 | S0CCRT3 | S0CCRT2 | S0CCRT1 | S0CCRT0 | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_CCRSA (m_vdp2_regs[0x100/2]) + #define STV_VDP2_S1CCRT ((STV_VDP2_CCRSA & 0x1f00) >> 8) + #define STV_VDP2_S0CCRT ((STV_VDP2_CCRSA & 0x001f) >> 0) + +/* 180102 - Colour Calculation Ratio (Sprite 2,3) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | S3CCRT4 | S3CCRT3 | S3CCRT2 | S3CCRT1 | S3CCRT0 | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | S2CCRT4 | S2CCRT3 | S2CCRT2 | S2CCRT1 | S2CCRT0 | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_CCRSB (m_vdp2_regs[0x102/2]) + #define STV_VDP2_S3CCRT ((STV_VDP2_CCRSB & 0x1f00) >> 8) + #define STV_VDP2_S2CCRT ((STV_VDP2_CCRSB & 0x001f) >> 0) + +/* 180104 - Colour Calculation Ratio (Sprite 4,5) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | S5CCRT4 | S5CCRT3 | S5CCRT2 | S5CCRT1 | S5CCRT0 | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | S4CCRT4 | S4CCRT3 | S4CCRT2 | S4CCRT1 | S4CCRT0 | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_CCRSC (m_vdp2_regs[0x104/2]) + #define STV_VDP2_S5CCRT ((STV_VDP2_CCRSC & 0x1f00) >> 8) + #define STV_VDP2_S4CCRT ((STV_VDP2_CCRSC & 0x001f) >> 0) + +/* 180106 - Colour Calculation Ratio (Sprite 6,7) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | S7CCRT4 | S7CCRT3 | S7CCRT2 | S7CCRT1 | S7CCRT0 | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | S6CCRT4 | S6CCRT3 | S6CCRT2 | S6CCRT1 | S6CCRT0 | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_CCRSD (m_vdp2_regs[0x106/2]) + #define STV_VDP2_S7CCRT ((STV_VDP2_CCRSD & 0x1f00) >> 8) + #define STV_VDP2_S6CCRT ((STV_VDP2_CCRSD & 0x001f) >> 0) + +/* 180108 - Colour Calculation Ratio (NBG 0,1) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | N1CCRT4 | N1CCRT3 | N1CCRT2 | N1CCRT1 | N1CCRT0 | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | N0CCRT4 | N0CCRT3 | N0CCRT2 | N0CCRT1 | N0CCRT0 | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_CCRNA (m_vdp2_regs[0x108/2]) + #define STV_VDP2_N1CCRT ((STV_VDP2_CCRNA & 0x1f00) >> 8) + #define STV_VDP2_N0CCRT (STV_VDP2_CCRNA & 0x1f) + +/* 18010a - Colour Calculation Ratio (NBG 2,3) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | N3CCRT4 | N3CCRT3 | N3CCRT2 | N3CCRT1 | N3CCRT0 | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | N2CCRT4 | N2CCRT3 | N2CCRT2 | N2CCRT1 | N2CCRT0 | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_CCRNB (m_vdp2_regs[0x10a/2]) + #define STV_VDP2_N3CCRT ((STV_VDP2_CCRNB & 0x1f00) >> 8) + #define STV_VDP2_N2CCRT (STV_VDP2_CCRNB & 0x1f) + +/* 18010c - Colour Calculation Ratio (RBG 0) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | -- | -- | -- | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | -- | -- | -- | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_CCRR (m_vdp2_regs[0x10c/2]) + #define STV_VDP2_R0CCRT (STV_VDP2_CCRR & 0x1f) + +/* 18010e - Colour Calculation Ratio (Line Colour Screen, Back Colour Screen) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | -- | -- | -- | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | -- | -- | -- | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_CCRLB (m_vdp2_regs[0x10e/2]) + + +/* 180110 - Colour Offset Enable + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | -- | -- | -- | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | -- | -- | -- | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_CLOFEN (m_vdp2_regs[0x110/2]) + #define STV_VDP2_N0COEN ((STV_VDP2_CLOFEN & 0x01) >> 0) + #define STV_VDP2_N1COEN ((STV_VDP2_CLOFEN & 0x02) >> 1) + #define STV_VDP2_N2COEN ((STV_VDP2_CLOFEN & 0x04) >> 2) + #define STV_VDP2_N3COEN ((STV_VDP2_CLOFEN & 0x08) >> 3) + #define STV_VDP2_R0COEN ((STV_VDP2_CLOFEN & 0x10) >> 4) + #define STV_VDP2_BKCOEN ((STV_VDP2_CLOFEN & 0x20) >> 5) + #define STV_VDP2_SPCOEN ((STV_VDP2_CLOFEN & 0x40) >> 6) + +/* 180112 - Colour Offset Select + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | -- | -- | -- | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | -- | -- | -- | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_CLOFSL (m_vdp2_regs[0x112/2]) + #define STV_VDP2_N0COSL ((STV_VDP2_CLOFSL & 0x01) >> 0) + #define STV_VDP2_N1COSL ((STV_VDP2_CLOFSL & 0x02) >> 1) + #define STV_VDP2_N2COSL ((STV_VDP2_CLOFSL & 0x04) >> 2) + #define STV_VDP2_N3COSL ((STV_VDP2_CLOFSL & 0x08) >> 3) + #define STV_VDP2_R0COSL ((STV_VDP2_CLOFSL & 0x10) >> 4) + #define STV_VDP2_BKCOSL ((STV_VDP2_CLOFSL & 0x20) >> 5) + #define STV_VDP2_SPCOSL ((STV_VDP2_CLOFSL & 0x40) >> 6) + +/* 180114 - Colour Offset A (Red) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | -- | -- | -- | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | -- | -- | -- | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_COAR (m_vdp2_regs[0x114/2]) + +/* 180116 - Colour Offset A (Green) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | -- | -- | -- | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | -- | -- | -- | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + #define STV_VDP2_COAG (m_vdp2_regs[0x116/2]) + +/* 180118 - Colour Offset A (Blue) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | -- | -- | -- | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | -- | -- | -- | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + + #define STV_VDP2_COAB (m_vdp2_regs[0x118/2]) + +/* 18011a - Colour Offset B (Red) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | -- | -- | -- | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | -- | -- | -- | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + #define STV_VDP2_COBR (m_vdp2_regs[0x11a/2]) + +/* 18011c - Colour Offset B (Green) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | -- | -- | -- | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | -- | -- | -- | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + #define STV_VDP2_COBG (m_vdp2_regs[0x11c/2]) + +/* 18011e - Colour Offset B (Blue) + bit-> /----15----|----14----|----13----|----12----|----11----|----10----|----09----|----08----\ + | -- | -- | -- | -- | -- | -- | -- | -- | + |----07----|----06----|----05----|----04----|----03----|----02----|----01----|----00----| + | -- | -- | -- | -- | -- | -- | -- | -- | + \----------|----------|----------|----------|----------|----------|----------|---------*/ + #define STV_VDP2_COBB (m_vdp2_regs[0x11e/2]) + + +#define STV_VDP2_RBG_ROTATION_PARAMETER_A 1 +#define STV_VDP2_RBG_ROTATION_PARAMETER_B 2 + + +#define mul_fixed32( a, b ) mul_32x32_shift( a, b, 16 ) + +void saturn_state::stv_vdp2_fill_rotation_parameter_table( UINT8 rot_parameter ) +{ + UINT32 address = 0; + + address = (((STV_VDP2_RPTAU << 16) | STV_VDP2_RPTAL) << 1); + if ( rot_parameter == 1 ) + { + address &= ~0x00000080; + } + else if ( rot_parameter == 2 ) + { + address |= 0x00000080; + } + + stv_current_rotation_parameter_table.xst = (m_vdp2_vram[address/4] & 0x1fffffc0) | ((m_vdp2_vram[address/4] & 0x10000000) ? 0xe0000000 : 0x00000000 ); + stv_current_rotation_parameter_table.yst = (m_vdp2_vram[address/4 + 1] & 0x1fffffc0) | ((m_vdp2_vram[address/4 + 1] & 0x10000000) ? 0xe0000000 : 0x00000000 ); + stv_current_rotation_parameter_table.zst = (m_vdp2_vram[address/4 + 2] & 0x1fffffc0) | ((m_vdp2_vram[address/4 + 2] & 0x10000000) ? 0xe0000000 : 0x00000000 ); + stv_current_rotation_parameter_table.dxst = (m_vdp2_vram[address/4 + 3] & 0x0007ffc0) | ((m_vdp2_vram[address/4 + 3] & 0x00040000) ? 0xfff80000 : 0x00000000 ); + stv_current_rotation_parameter_table.dyst = (m_vdp2_vram[address/4 + 4] & 0x0007ffc0) | ((m_vdp2_vram[address/4 + 4] & 0x00040000) ? 0xfff80000 : 0x00000000 ); + stv_current_rotation_parameter_table.dx = (m_vdp2_vram[address/4 + 5] & 0x0007ffc0) | ((m_vdp2_vram[address/4 + 5] & 0x00040000) ? 0xfff80000 : 0x00000000 ); + stv_current_rotation_parameter_table.dy = (m_vdp2_vram[address/4 + 6] & 0x0007ffc0) | ((m_vdp2_vram[address/4 + 6] & 0x00040000) ? 0xfff80000 : 0x00000000 ); + stv_current_rotation_parameter_table.A = (m_vdp2_vram[address/4 + 7] & 0x000fffc0) | ((m_vdp2_vram[address/4 + 7] & 0x00080000) ? 0xfff00000 : 0x00000000 ); + stv_current_rotation_parameter_table.B = (m_vdp2_vram[address/4 + 8] & 0x000fffc0) | ((m_vdp2_vram[address/4 + 8] & 0x00080000) ? 0xfff00000 : 0x00000000 ); + stv_current_rotation_parameter_table.C = (m_vdp2_vram[address/4 + 9] & 0x000fffc0) | ((m_vdp2_vram[address/4 + 9] & 0x00080000) ? 0xfff00000 : 0x00000000 ); + stv_current_rotation_parameter_table.D = (m_vdp2_vram[address/4 + 10] & 0x000fffc0) | ((m_vdp2_vram[address/4 + 10] & 0x00080000) ? 0xfff00000 : 0x00000000 ); + stv_current_rotation_parameter_table.E = (m_vdp2_vram[address/4 + 11] & 0x000fffc0) | ((m_vdp2_vram[address/4 + 11] & 0x00080000) ? 0xfff00000 : 0x00000000 ); + stv_current_rotation_parameter_table.F = (m_vdp2_vram[address/4 + 12] & 0x000fffc0) | ((m_vdp2_vram[address/4 + 12] & 0x00080000) ? 0xfff00000 : 0x00000000 ); + stv_current_rotation_parameter_table.px = (m_vdp2_vram[address/4 + 13] & 0x3fff0000) | ((m_vdp2_vram[address/4 + 13] & 0x30000000) ? 0xc0000000 : 0x00000000 ); + stv_current_rotation_parameter_table.py = (m_vdp2_vram[address/4 + 13] & 0x00003fff) << 16; + if ( stv_current_rotation_parameter_table.py & 0x20000000 ) stv_current_rotation_parameter_table.py |= 0xc0000000; + stv_current_rotation_parameter_table.pz = (m_vdp2_vram[address/4 + 14] & 0x3fff0000) | ((m_vdp2_vram[address/4 + 14] & 0x20000000) ? 0xc0000000 : 0x00000000 ); + stv_current_rotation_parameter_table.cx = (m_vdp2_vram[address/4 + 15] & 0x3fff0000) | ((m_vdp2_vram[address/4 + 15] & 0x20000000) ? 0xc0000000 : 0x00000000 ); + stv_current_rotation_parameter_table.cy = (m_vdp2_vram[address/4 + 15] & 0x00003fff) << 16; + if ( stv_current_rotation_parameter_table.cy & 0x20000000 ) stv_current_rotation_parameter_table.cy |= 0xc0000000; + stv_current_rotation_parameter_table.cz = (m_vdp2_vram[address/4 + 16] & 0x3fff0000) | ((m_vdp2_vram[address/4 + 16] & 0x20000000) ? 0xc0000000 : 0x00000000 ); + stv_current_rotation_parameter_table.mx = (m_vdp2_vram[address/4 + 17] & 0x3fffffc0) | ((m_vdp2_vram[address/4 + 17] & 0x20000000) ? 0xc0000000 : 0x00000000 ); + stv_current_rotation_parameter_table.my = (m_vdp2_vram[address/4 + 18] & 0x3fffffc0) | ((m_vdp2_vram[address/4 + 18] & 0x20000000) ? 0xc0000000 : 0x00000000 ); + stv_current_rotation_parameter_table.kx = (m_vdp2_vram[address/4 + 19] & 0x00ffffff) | ((m_vdp2_vram[address/4 + 19] & 0x00800000) ? 0xff000000 : 0x00000000 ); + stv_current_rotation_parameter_table.ky = (m_vdp2_vram[address/4 + 20] & 0x00ffffff) | ((m_vdp2_vram[address/4 + 20] & 0x00800000) ? 0xff000000 : 0x00000000 ); + stv_current_rotation_parameter_table.kast = (m_vdp2_vram[address/4 + 21] & 0xffffffc0); + stv_current_rotation_parameter_table.dkast= (m_vdp2_vram[address/4 + 22] & 0x03ffffc0) | ((m_vdp2_vram[address/4 + 22] & 0x02000000) ? 0xfc000000 : 0x00000000 ); + stv_current_rotation_parameter_table.dkax = (m_vdp2_vram[address/4 + 23] & 0x03ffffc0) | ((m_vdp2_vram[address/4 + 23] & 0x02000000) ? 0xfc000000 : 0x00000000 ); + +#define RP stv_current_rotation_parameter_table + + if(LOG_ROZ == 1) logerror( "Rotation parameter table (%d)\n", rot_parameter ); + if(LOG_ROZ == 1) logerror( "xst = %x, yst = %x, zst = %x\n", RP.xst, RP.yst, RP.zst ); + if(LOG_ROZ == 1) logerror( "dxst = %x, dyst = %x\n", RP.dxst, RP.dyst ); + if(LOG_ROZ == 1) logerror( "dx = %x, dy = %x\n", RP.dx, RP.dy ); + if(LOG_ROZ == 1) logerror( "A = %x, B = %x, C = %x, D = %x, E = %x, F = %x\n", RP.A, RP.B, RP.C, RP.D, RP.E, RP.F ); + if(LOG_ROZ == 1) logerror( "px = %x, py = %x, pz = %x\n", RP.px, RP.py, RP.pz ); + if(LOG_ROZ == 1) logerror( "cx = %x, cy = %x, cz = %x\n", RP.cx, RP.cy, RP.cz ); + if(LOG_ROZ == 1) logerror( "mx = %x, my = %x\n", RP.mx, RP.my ); + if(LOG_ROZ == 1) logerror( "kx = %x, ky = %x\n", RP.kx, RP.ky ); + if(LOG_ROZ == 1) logerror( "kast = %x, dkast = %x, dkax = %x\n", RP.kast, RP.dkast, RP.dkax ); + + /*Attempt to show on screen the rotation table*/ + #if 0 + if(LOG_ROZ == 2) + { + if(machine().input().code_pressed_once(JOYCODE_Y_UP_SWITCH)) + m_vdpdebug_roz++; + + if(machine().input().code_pressed_once(JOYCODE_Y_DOWN_SWITCH)) + m_vdpdebug_roz--; + + if(m_vdpdebug_roz > 10) + m_vdpdebug_roz = 10; + + switch(m_vdpdebug_roz) + { + case 0: popmessage( "Rotation parameter Table (%d)", rot_parameter ); break; + case 1: popmessage( "xst = %x, yst = %x, zst = %x", RP.xst, RP.yst, RP.zst ); break; + case 2: popmessage( "dxst = %x, dyst = %x", RP.dxst, RP.dyst ); break; + case 3: popmessage( "dx = %x, dy = %x", RP.dx, RP.dy ); break; + case 4: popmessage( "A = %x, B = %x, C = %x, D = %x, E = %x, F = %x", RP.A, RP.B, RP.C, RP.D, RP.E, RP.F ); break; + case 5: popmessage( "px = %x, py = %x, pz = %x", RP.px, RP.py, RP.pz ); break; + case 6: popmessage( "cx = %x, cy = %x, cz = %x", RP.cx, RP.cy, RP.cz ); break; + case 7: popmessage( "mx = %x, my = %x", RP.mx, RP.my ); break; + case 8: popmessage( "kx = %x, ky = %x", RP.kx, RP.ky ); break; + case 9: popmessage( "kast = %x, dkast = %x, dkax = %x", RP.kast, RP.dkast, RP.dkax ); break; + case 10: break; + } + } + #endif +} + +/* check if RGB layer has rotation applied */ +UINT8 saturn_state::stv_vdp2_is_rotation_applied(void) +{ +#define _FIXED_1 (0x00010000) +#define _FIXED_0 (0x00000000) + + if ( RP.A == _FIXED_1 && + RP.B == _FIXED_0 && + RP.C == _FIXED_0 && + RP.D == _FIXED_0 && + RP.E == _FIXED_1 && + RP.F == _FIXED_0 && + RP.dxst == _FIXED_0 && + RP.dyst == _FIXED_1 && + RP.dx == _FIXED_1 && + RP.dy == _FIXED_0 && + RP.kx == _FIXED_1 && + RP.ky == _FIXED_1 ) + { + return 0; + } + else + { + return 1; + } +} + +UINT8 saturn_state::stv_vdp2_are_map_registers_equal(void) +{ + int i; + + for ( i = 1; i < stv2_current_tilemap.map_count; i++ ) + { + if ( stv2_current_tilemap.map_offset[i] != stv2_current_tilemap.map_offset[0] ) + { + return 0; + } + } + return 1; +} + +void saturn_state::stv_vdp2_check_fade_control_for_layer( void ) +{ + if ( stv2_current_tilemap.fade_control & 1 ) + { + if ( stv2_current_tilemap.fade_control & 2 ) + { + if ((STV_VDP2_COBR & 0x1ff) == 0 && + (STV_VDP2_COBG & 0x1ff) == 0 && + (STV_VDP2_COBB & 0x1ff) == 0 ) + { + stv2_current_tilemap.fade_control = 0; + } + } + else + { + if ((STV_VDP2_COAR & 0x1ff) == 0 && + (STV_VDP2_COAG & 0x1ff) == 0 && + (STV_VDP2_COAB & 0x1ff) == 0 ) + { + stv2_current_tilemap.fade_control = 0; + } + } + } +} + +#define STV_VDP2_CP_NBG0_PNMDR 0x0 +#define STV_VDP2_CP_NBG1_PNMDR 0x1 +#define STV_VDP2_CP_NBG2_PNMDR 0x2 +#define STV_VDP2_CP_NBG3_PNMDR 0x3 +#define STV_VDP2_CP_NBG0_CPDR 0x4 +#define STV_VDP2_CP_NBG1_CPDR 0x5 +#define STV_VDP2_CP_NBG2_CPDR 0x6 +#define STV_VDP2_CP_NBG3_CPDR 0x7 + +UINT8 saturn_state::stv_vdp2_check_vram_cycle_pattern_registers( UINT8 access_command_pnmdr, UINT8 access_command_cpdr, UINT8 bitmap_enable ) +{ + int i; + UINT8 access_command_ok = 0; + UINT16 cp_regs[8]; + cp_regs[0] = STV_VDP2_CYCA0L; + cp_regs[1] = STV_VDP2_CYCA0U; + cp_regs[2] = STV_VDP2_CYCA1L; + cp_regs[3] = STV_VDP2_CYCA1U; + cp_regs[4] = STV_VDP2_CYCA2L; + cp_regs[5] = STV_VDP2_CYCA2U; + cp_regs[6] = STV_VDP2_CYCA3L; + cp_regs[7] = STV_VDP2_CYCA3U; + + if ( bitmap_enable ) access_command_ok = 1; + + for ( i = 0; i < 8; i++ ) + { + if ( ((cp_regs[i] >> 12) & 0xf) == access_command_pnmdr ) + { + access_command_ok |= 1; + } + if ( ((cp_regs[i] >> 12) & 0xf) == access_command_cpdr ) + { + access_command_ok |= 2; + } + if ( ((cp_regs[i] >> 8) & 0xf) == access_command_pnmdr ) + { + access_command_ok |= 1; + } + if ( ((cp_regs[i] >> 8) & 0xf) == access_command_cpdr ) + { + access_command_ok |= 2; + } + if ( ((cp_regs[i] >> 4) & 0xf) == access_command_pnmdr ) + { + access_command_ok |= 1; + } + if ( ((cp_regs[i] >> 4) & 0xf) == access_command_cpdr ) + { + access_command_ok |= 2; + } + if ( ((cp_regs[i] >> 0) & 0xf) == access_command_pnmdr ) + { + access_command_ok |= 1; + } + if ( ((cp_regs[i] >> 0) & 0xf) == access_command_cpdr ) + { + access_command_ok |= 2; + } + } + return access_command_ok == 3 ? 1 : 0; +} + +INLINE UINT32 stv_add_blend(UINT32 a, UINT32 b) +{ + rgb_t rb = (a & 0xff00ff) + (b & 0xff00ff); + rgb_t g = (a & 0x00ff00) + (b & 0x00ff00); + return rgb_t((rb & 0x1000000) ? 0xff : rb.r(), + (g & 0x0010000) ? 0xff : g.g(), + (rb & 0x0000100) ? 0xff : rb.b() + ); +} + + +void saturn_state::stv_vdp2_compute_color_offset( int *r, int *g, int *b, int cor ) +{ + if ( cor == 0 ) + { + *r = (STV_VDP2_COAR & 0x100) ? (*r - (0x100 - (STV_VDP2_COAR & 0xff))) : ((STV_VDP2_COAR & 0xff) + *r); + *g = (STV_VDP2_COAG & 0x100) ? (*g - (0x100 - (STV_VDP2_COAG & 0xff))) : ((STV_VDP2_COAG & 0xff) + *g); + *b = (STV_VDP2_COAB & 0x100) ? (*b - (0x100 - (STV_VDP2_COAB & 0xff))) : ((STV_VDP2_COAB & 0xff) + *b); + } + else + { + *r = (STV_VDP2_COBR & 0x100) ? (*r - (0xff - (STV_VDP2_COBR & 0xff))) : ((STV_VDP2_COBR & 0xff) + *r); + *g = (STV_VDP2_COBG & 0x100) ? (*g - (0xff - (STV_VDP2_COBG & 0xff))) : ((STV_VDP2_COBG & 0xff) + *g); + *b = (STV_VDP2_COBB & 0x100) ? (*b - (0xff - (STV_VDP2_COBB & 0xff))) : ((STV_VDP2_COBB & 0xff) + *b); + } + if(*r < 0) { *r = 0; } + if(*r > 0xff) { *r = 0xff; } + if(*g < 0) { *g = 0; } + if(*g > 0xff) { *g = 0xff; } + if(*b < 0) { *b = 0; } + if(*b > 0xff) { *b = 0xff; } +} + +void saturn_state::stv_vdp2_compute_color_offset_UINT32(rgb_t *rgb, int cor) +{ + int _r = rgb->r(); + int _g = rgb->g(); + int _b = rgb->b(); + if ( cor == 0 ) + { + _r = (STV_VDP2_COAR & 0x100) ? (_r - (0x100 - (STV_VDP2_COAR & 0xff))) : ((STV_VDP2_COAR & 0xff) + _r); + _g = (STV_VDP2_COAG & 0x100) ? (_g - (0x100 - (STV_VDP2_COAG & 0xff))) : ((STV_VDP2_COAG & 0xff) + _g); + _b = (STV_VDP2_COAB & 0x100) ? (_b - (0x100 - (STV_VDP2_COAB & 0xff))) : ((STV_VDP2_COAB & 0xff) + _b); + } + else + { + _r = (STV_VDP2_COBR & 0x100) ? (_r - (0xff - (STV_VDP2_COBR & 0xff))) : ((STV_VDP2_COBR & 0xff) + _r); + _g = (STV_VDP2_COBG & 0x100) ? (_g - (0xff - (STV_VDP2_COBG & 0xff))) : ((STV_VDP2_COBG & 0xff) + _g); + _b = (STV_VDP2_COBB & 0x100) ? (_b - (0xff - (STV_VDP2_COBB & 0xff))) : ((STV_VDP2_COBB & 0xff) + _b); + } + if(_r < 0) { _r = 0; } + if(_r > 0xff) { _r = 0xff; } + if(_g < 0) { _g = 0; } + if(_g > 0xff) { _g = 0xff; } + if(_b < 0) { _b = 0; } + if(_b > 0xff) { _b = 0xff; } + + *rgb = rgb_t(_r, _g, _b); +} + +void saturn_state::stv_vdp2_drawgfxzoom( + bitmap_rgb32 &dest_bmp,const rectangle &clip,gfx_element *gfx, + UINT32 code,UINT32 color,int flipx,int flipy,int sx,int sy, + int transparency,int transparent_color,int scalex, int scaley, + int sprite_screen_width, int sprite_screen_height, int alpha) +{ + rectangle myclip; + + if (!scalex || !scaley) return; + + if (gfx->has_pen_usage() && transparency == STV_TRANSPARENCY_PEN) + { + int transmask = 0; + + transmask = 1 << (transparent_color & 0xff); + + if ((gfx->pen_usage(code) & ~transmask) == 0) + /* character is totally transparent, no need to draw */ + return; + else if ((gfx->pen_usage(code) & transmask) == 0) + /* character is totally opaque, can disable transparency */ + transparency = STV_TRANSPARENCY_NONE; + } + + /* + scalex and scaley are 16.16 fixed point numbers + 1<<15 : shrink to 50% + 1<<16 : uniform scale + 1<<17 : double to 200% + */ + + + /* KW 991012 -- Added code to force clip to bitmap boundary */ + myclip = clip; + myclip &= dest_bmp.cliprect(); + + if( gfx ) + { + const pen_t *pal = &m_palette->pen(gfx->colorbase() + gfx->granularity() * (color % gfx->colors())); + const UINT8 *source_base = gfx->get_data(code % gfx->elements()); + + //int sprite_screen_height = (scaley*gfx->height()+0x8000)>>16; + //int sprite_screen_width = (scalex*gfx->width()+0x8000)>>16; + + if (sprite_screen_width && sprite_screen_height) + { + /* compute sprite increment per screen pixel */ + //int dx = (gfx->width()<<16)/sprite_screen_width; + //int dy = (gfx->height()<<16)/sprite_screen_height; + int dx = stv2_current_tilemap.incx; + int dy = stv2_current_tilemap.incy; + + int ex = sx+sprite_screen_width; + int ey = sy+sprite_screen_height; + + int x_index_base; + int y_index; + + if( flipx ) + { + x_index_base = (sprite_screen_width-1)*dx; + dx = -dx; + } + else + { + x_index_base = 0; + } + + if( flipy ) + { + y_index = (sprite_screen_height-1)*dy; + dy = -dy; + } + else + { + y_index = 0; + } + + if( sx < myclip.min_x) + { /* clip left */ + int pixels = myclip.min_x-sx; + sx += pixels; + x_index_base += pixels*dx; + } + if( sy < myclip.min_y ) + { /* clip top */ + int pixels = myclip.min_y-sy; + sy += pixels; + y_index += pixels*dy; + } + /* NS 980211 - fixed incorrect clipping */ + if( ex > myclip.max_x+1 ) + { /* clip right */ + int pixels = ex-myclip.max_x-1; + ex -= pixels; + } + if( ey > myclip.max_y+1 ) + { /* clip bottom */ + int pixels = ey-myclip.max_y-1; + ey -= pixels; + } + + if( ex>sx ) + { /* skip if inner loop doesn't draw anything */ + int y; + + /* case 0: STV_TRANSPARENCY_NONE */ + if (transparency == STV_TRANSPARENCY_NONE) + { + for( y=sy; y>16) * gfx->rowbytes(); + UINT32 *dest = &dest_bmp.pix32(y); + + int x, x_index = x_index_base; + for( x=sx; x>16]]; + x_index += dx; + } + + y_index += dy; + } + } /* case 1: STV_TRANSPARENCY_PEN */ + else if (transparency == STV_TRANSPARENCY_PEN) + { + for( y=sy; y>16) * gfx->rowbytes(); + UINT32 *dest = &dest_bmp.pix32(y); + + int x, x_index = x_index_base; + for( x=sx; x>16]; + if( c != transparent_color ) dest[x] = pal[c]; + } + x_index += dx; + } + + y_index += dy; + } + } /* case 6: STV_TRANSPARENCY_ALPHA */ + else if (transparency == STV_TRANSPARENCY_ALPHA) + { + for( y=sy; y>16) * gfx->rowbytes(); + UINT32 *dest = &dest_bmp.pix32(y); + + int x, x_index = x_index_base; + for( x=sx; x>16]; + if( c != transparent_color ) dest[x] = alpha_blend_r32(dest[x], pal[c], alpha); + } + x_index += dx; + } + + y_index += dy; + } + } /* case : STV_TRANSPARENCY_ADD_BLEND */ + else if (transparency == STV_TRANSPARENCY_ADD_BLEND ) + { + for( y=sy; y>16) * gfx->rowbytes(); + UINT32 *dest = &dest_bmp.pix32(y); + + int x, x_index = x_index_base; + for( x=sx; x>16]; + if( c != transparent_color ) dest[x] = stv_add_blend(dest[x],pal[c]); + } + x_index += dx; + } + + y_index += dy; + } + } + } + } + } +} + +void saturn_state::stv_vdp2_drawgfxzoom_rgb555( + bitmap_rgb32 &dest_bmp,const rectangle &clip, + UINT32 code,UINT32 color,int flipx,int flipy,int sx,int sy, + int transparency,int transparent_color,int scalex, int scaley, + int sprite_screen_width, int sprite_screen_height, int alpha) +{ + rectangle myclip; + UINT8* gfxdata; + + gfxdata = m_vdp2.gfx_decode + code * 0x20; + + if(stv2_current_tilemap.window_control.enabled[0] || + stv2_current_tilemap.window_control.enabled[1]) + popmessage("Window Enabled for RGB555 Zoom"); + + if (!scalex || !scaley) return; + + #if 0 + if (gfx->has_pen_usage() && transparency == STV_TRANSPARENCY_PEN) + { + int transmask = 0; + + transmask = 1 << (transparent_color & 0xff); + + if ((gfx->pen_usage(code) & ~transmask) == 0) + /* character is totally transparent, no need to draw */ + return; + else if ((gfx->pen_usage(code) & transmask) == 0) + /* character is totally opaque, can disable transparency */ + transparency = STV_TRANSPARENCY_NONE; + } + #endif + + /* + scalex and scaley are 16.16 fixed point numbers + 1<<15 : shrink to 50% + 1<<16 : uniform scale + 1<<17 : double to 200% + */ + + + /* KW 991012 -- Added code to force clip to bitmap boundary */ + myclip = clip; + myclip &= dest_bmp.cliprect(); + +// if( gfx ) + { +// const UINT8 *source_base = gfx->get_data(code % gfx->elements()); + + //int sprite_screen_height = (scaley*gfx->height()+0x8000)>>16; + //int sprite_screen_width = (scalex*gfx->width()+0x8000)>>16; + + if (sprite_screen_width && sprite_screen_height) + { + /* compute sprite increment per screen pixel */ + //int dx = (gfx->width()<<16)/sprite_screen_width; + //int dy = (gfx->height()<<16)/sprite_screen_height; + int dx = stv2_current_tilemap.incx; + int dy = stv2_current_tilemap.incy; + + int ex = sx+sprite_screen_width; + int ey = sy+sprite_screen_height; + + int x_index_base; + int y_index; + + if( flipx ) + { + x_index_base = (sprite_screen_width-1)*dx; + dx = -dx; + } + else + { + x_index_base = 0; + } + + if( flipy ) + { + y_index = (sprite_screen_height-1)*dy; + dy = -dy; + } + else + { + y_index = 0; + } + + if( sx < myclip.min_x) + { /* clip left */ + int pixels = myclip.min_x-sx; + sx += pixels; + x_index_base += pixels*dx; + } + if( sy < myclip.min_y ) + { /* clip top */ + int pixels = myclip.min_y-sy; + sy += pixels; + y_index += pixels*dy; + } + /* NS 980211 - fixed incorrect clipping */ + if( ex > myclip.max_x+1 ) + { /* clip right */ + int pixels = ex-myclip.max_x-1; + ex -= pixels; + } + if( ey > myclip.max_y+1 ) + { /* clip bottom */ + int pixels = ey-myclip.max_y-1; + ey -= pixels; + } + + if( ex>sx ) + { /* skip if inner loop doesn't draw anything */ + int y; + + /* case 0: STV_TRANSPARENCY_NONE */ + if (transparency == STV_TRANSPARENCY_NONE) + { + for( y=sy; y>16)*16; + UINT32 *dest = &dest_bmp.pix32(y); + int r,g,b,data; + + int x, x_index = x_index_base; + for( x=sx; x>16)*2] << 8) | source[(x_index>>16)*2+1]; + b = pal5bit((data & 0x7c00) >> 10); + g = pal5bit((data & 0x03e0) >> 5); + r = pal5bit( data & 0x001f); + if(stv2_current_tilemap.fade_control & 1) + stv_vdp2_compute_color_offset(&r,&g,&b,stv2_current_tilemap.fade_control & 2); + + dest[x] = rgb_t(r, g, b); + x_index += dx; + } + + y_index += dy; + } + } + + /* case 1: STV_TRANSPARENCY_PEN */ + if (transparency == STV_TRANSPARENCY_PEN) + { + for( y=sy; y>16)*16; + UINT32 *dest = &dest_bmp.pix32(y); + int r,g,b,data; + + int x, x_index = x_index_base; + for( x=sx; x>16)*2] << 8) | source[(x_index>>16)*2+1]; + b = pal5bit((data & 0x7c00) >> 10); + g = pal5bit((data & 0x03e0) >> 5); + r = pal5bit( data & 0x001f); + if(stv2_current_tilemap.fade_control & 1) + stv_vdp2_compute_color_offset(&r,&g,&b,stv2_current_tilemap.fade_control & 2); + + if( data ) dest[x] = rgb_t(r, g, b); + x_index += dx; + } + + y_index += dy; + } + } + + /* case 6: STV_TRANSPARENCY_ALPHA */ + if (transparency == STV_TRANSPARENCY_ALPHA) + { + for( y=sy; y>16)*16; + UINT32 *dest = &dest_bmp.pix32(y); + int r,g,b,data; + + int x, x_index = x_index_base; + for( x=sx; x>16)*2] << 8) | source[(x_index>>16)*2+1]; + b = pal5bit((data & 0x7c00) >> 10); + g = pal5bit((data & 0x03e0) >> 5); + r = pal5bit( data & 0x001f); + if(stv2_current_tilemap.fade_control & 1) + stv_vdp2_compute_color_offset(&r,&g,&b,stv2_current_tilemap.fade_control & 2); + + if( data ) dest[x] = alpha_blend_r32(dest[x], rgb_t(r, g, b), alpha); + x_index += dx; + } + + y_index += dy; + } + } + + /* case : STV_TRANSPARENCY_ADD_BLEND */ + if (transparency == STV_TRANSPARENCY_ADD_BLEND ) + { + for( y=sy; y>16)*16; + UINT32 *dest = &dest_bmp.pix32(y); + int r,g,b,data; + + int x, x_index = x_index_base; + for( x=sx; x>16]<<0)|(source[(x_index*2+1)>>16]<<8); + b = pal5bit((data & 0x7c00) >> 10); + g = pal5bit((data & 0x03e0) >> 5); + r = pal5bit( data & 0x001f); + if(stv2_current_tilemap.fade_control & 1) + stv_vdp2_compute_color_offset(&r,&g,&b,stv2_current_tilemap.fade_control & 2); + + if( data ) dest[x] = stv_add_blend(dest[x], rgb_t(r, g, b)); + x_index += dx; + } + + y_index += dy; + } + } + + } + } + } + +} + + +void saturn_state::stv_vdp2_drawgfx_rgb555( bitmap_rgb32 &dest_bmp, const rectangle &clip, UINT32 code, int flipx, int flipy, int sx, int sy, int transparency, int alpha) +{ + rectangle myclip; + UINT8* gfxdata; + int sprite_screen_width, sprite_screen_height; + + gfxdata = m_vdp2.gfx_decode + code * 0x20; + sprite_screen_width = sprite_screen_height = 8; + + if(stv2_current_tilemap.window_control.enabled[0] || + stv2_current_tilemap.window_control.enabled[1]) + popmessage("Window Enabled for RGB555 tiles"); + + /* KW 991012 -- Added code to force clip to bitmap boundary */ + myclip = clip; + myclip &= dest_bmp.cliprect(); + + { + int dx = stv2_current_tilemap.incx; + int dy = stv2_current_tilemap.incy; + + int ex = sx+sprite_screen_width; + int ey = sy+sprite_screen_height; + + int x_index_base; + int y_index; + + if( flipx ) + { + x_index_base = (sprite_screen_width-1)*dx; + dx = -dx; + } + else + { + x_index_base = 0; + } + + if( flipy ) + { + y_index = (sprite_screen_height-1)*dy; + dy = -dy; + } + else + { + y_index = 0; + } + + if( sx < myclip.min_x) + { /* clip left */ + int pixels = myclip.min_x-sx; + sx += pixels; + x_index_base += pixels*dx; + } + if( sy < myclip.min_y ) + { /* clip top */ + int pixels = myclip.min_y-sy; + sy += pixels; + y_index += pixels*dy; + } + /* NS 980211 - fixed incorrect clipping */ + if( ex > myclip.max_x+1 ) + { /* clip right */ + int pixels = ex-myclip.max_x-1; + ex -= pixels; + } + if( ey > myclip.max_y+1 ) + { /* clip bottom */ + int pixels = ey-myclip.max_y-1; + ey -= pixels; + } + + if( ex>sx ) + { /* skip if inner loop doesn't draw anything */ + int y; + + for( y=sy; y>16)*16; + UINT32 *dest = &dest_bmp.pix32(y); + UINT16 data; + + int x, x_index = x_index_base; + for( x=sx; x>16)*2] << 8) | source[(x_index>>16)*2+1]; + if ((data & 0x8000) || (transparency == STV_TRANSPARENCY_NONE)) + { + b = pal5bit((data & 0x7c00) >> 10); + g = pal5bit((data & 0x03e0) >> 5); + r = pal5bit( data & 0x001f); + if(stv2_current_tilemap.fade_control & 1) + stv_vdp2_compute_color_offset(&r,&g,&b,stv2_current_tilemap.fade_control & 2); + + if ( transparency == STV_TRANSPARENCY_ALPHA ) + dest[x] = alpha_blend_r32( dest[x], rgb_t(r, g, b), alpha ); + else + dest[x] = rgb_t(r, g, b); + } + x_index += dx; + } + + y_index += dy; + } + + } + + } + +} + + +void saturn_state::stv_vdp2_drawgfx_rgb888( bitmap_rgb32 &dest_bmp, const rectangle &clip, UINT32 code, int flipx, int flipy, + int sx, int sy, int transparency, int alpha) +{ + rectangle myclip; + UINT8* gfxdata; + int sprite_screen_width, sprite_screen_height; + + gfxdata = m_vdp2.gfx_decode + code * 0x20; + sprite_screen_width = sprite_screen_height = 8; + + if(stv2_current_tilemap.window_control.enabled[0] || + stv2_current_tilemap.window_control.enabled[1]) + popmessage("Window Enabled for RGB888 tiles"); + + /* KW 991012 -- Added code to force clip to bitmap boundary */ + myclip = clip; + myclip &= dest_bmp.cliprect(); + { + int dx = stv2_current_tilemap.incx; + int dy = stv2_current_tilemap.incy; + + int ex = sx+sprite_screen_width; + int ey = sy+sprite_screen_height; + + int x_index_base; + int y_index; + + if( flipx ) + { + x_index_base = (sprite_screen_width-1)*dx; + dx = -dx; + } + else + { + x_index_base = 0; + } + + if( flipy ) + { + y_index = (sprite_screen_height-1)*dy; + dy = -dy; + } + else + { + y_index = 0; + } + + if( sx < myclip.min_x) + { /* clip left */ + int pixels = myclip.min_x-sx; + sx += pixels; + x_index_base += pixels*dx; + } + if( sy < myclip.min_y ) + { /* clip top */ + int pixels = myclip.min_y-sy; + sy += pixels; + y_index += pixels*dy; + } + /* NS 980211 - fixed incorrect clipping */ + if( ex > myclip.max_x+1 ) + { /* clip right */ + int pixels = ex-myclip.max_x-1; + ex -= pixels; + } + if( ey > myclip.max_y+1 ) + { /* clip bottom */ + int pixels = ey-myclip.max_y-1; + ey -= pixels; + } + + if( ex>sx ) + { /* skip if inner loop doesn't draw anything */ + int y; + + for( y=sy; y>16)*32; + UINT32 *dest = &dest_bmp.pix32(y); + UINT32 data; + + int x, x_index = x_index_base; + + for( x=sx; x>16)*4+0] << 24) | (source[(x_index>>16)*4+1] << 16) | (source[(x_index>>16)*4+2] << 8) | (source[(x_index>>16)*4+3] << 0); + if ((data & 0x80000000) || (transparency == STV_TRANSPARENCY_NONE)) + { + b = (data & 0xff0000) >> 16; + g = (data & 0x00ff00) >> 8; + r = (data & 0x0000ff); + + if(stv2_current_tilemap.fade_control & 1) + stv_vdp2_compute_color_offset(&r,&g,&b,stv2_current_tilemap.fade_control & 2); + + if ( transparency == STV_TRANSPARENCY_ALPHA ) + dest[x] = alpha_blend_r32( dest[x], rgb_t(r, g, b), alpha ); + else + dest[x] = rgb_t(r, g, b); + } + x_index += dx; + } + + y_index += dy; + } + + } + + } +} + +void saturn_state::stv_vdp2_drawgfx_alpha(bitmap_rgb32 &dest_bmp,const rectangle &clip,gfx_element *gfx, + UINT32 code,UINT32 color, int flipx,int flipy,int offsx,int offsy, + int transparent_color, int alpha) +{ + const pen_t *pal = &m_palette->pen(gfx->colorbase() + gfx->granularity() * (color % gfx->colors())); + const UINT8 *source_base = gfx->get_data(code % gfx->elements()); + int x_index_base, y_index, sx, sy, ex, ey; + int xinc, yinc; + + xinc = flipx ? -1 : 1; + yinc = flipy ? -1 : 1; + + x_index_base = flipx ? gfx->width()-1 : 0; + y_index = flipy ? gfx->height()-1 : 0; + + /* start coordinates */ + sx = offsx; + sy = offsy; + + /* end coordinates */ + ex = sx + gfx->width(); + ey = sy + gfx->height(); + + /* clip left */ + if (sx < clip.min_x) + { + int pixels = clip.min_x-sx; + sx += pixels; + x_index_base += xinc*pixels; + } + + /* clip top */ + if (sy < clip.min_y) + { int pixels = clip.min_y-sy; + sy += pixels; + y_index += yinc*pixels; + } + + /* clip right */ + if (ex > clip.max_x+1) + { + ex = clip.max_x+1; + } + /* clip bottom */ + if (ey > clip.max_y+1) + { + ey = clip.max_y+1; + } + + /* skip if inner loop doesn't draw anything */ + if (ex > sx) + { + int x, y; + + { + for (y = sy; y < ey; y++) + { + const UINT8 *source = source_base + y_index*gfx->rowbytes(); + UINT32 *dest = &dest_bmp.pix32(y); + int x_index = x_index_base; + for (x = sx; x < ex; x++) + { + if(stv_vdp2_window_process(x,y)) + { + int c = (source[x_index]); + if (c != transparent_color) + dest[x] = alpha_blend_r32( dest[x], pal[c], alpha );; + } + + x_index += xinc; + } + y_index += yinc; + } + } + } +} + +void saturn_state::stv_vdp2_drawgfx_transpen(bitmap_rgb32 &dest_bmp,const rectangle &clip,gfx_element *gfx, + UINT32 code,UINT32 color, int flipx,int flipy,int offsx,int offsy, + int transparent_color) +{ + const pen_t *pal = &m_palette->pen(gfx->colorbase() + gfx->granularity() * (color % gfx->colors())); + const UINT8 *source_base = gfx->get_data(code % gfx->elements()); + int x_index_base, y_index, sx, sy, ex, ey; + int xinc, yinc; + + xinc = flipx ? -1 : 1; + yinc = flipy ? -1 : 1; + + x_index_base = flipx ? gfx->width()-1 : 0; + y_index = flipy ? gfx->height()-1 : 0; + + /* start coordinates */ + sx = offsx; + sy = offsy; + + /* end coordinates */ + ex = sx + gfx->width(); + ey = sy + gfx->height(); + + /* clip left */ + if (sx < clip.min_x) + { + int pixels = clip.min_x-sx; + sx += pixels; + x_index_base += xinc*pixels; + } + + /* clip top */ + if (sy < clip.min_y) + { int pixels = clip.min_y-sy; + sy += pixels; + y_index += yinc*pixels; + } + + /* clip right */ + if (ex > clip.max_x+1) + { + ex = clip.max_x+1; + } + /* clip bottom */ + if (ey > clip.max_y+1) + { + ey = clip.max_y+1; + } + + /* skip if inner loop doesn't draw anything */ + if (ex > sx) + { + int x, y; + + { + for (y = sy; y < ey; y++) + { + const UINT8 *source = source_base + y_index*gfx->rowbytes(); + UINT32 *dest = &dest_bmp.pix32(y); + int x_index = x_index_base; + for (x = sx; x < ex; x++) + { + if(stv_vdp2_window_process(x,y)) + { + int c = (source[x_index]); + if (c != transparent_color) + dest[x] = pal[c]; + } + + x_index += xinc; + } + y_index += yinc; + } + } + } +} + +void saturn_state::draw_4bpp_bitmap(bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + int xsize, ysize, xsize_mask, ysize_mask; + int xsrc,ysrc,xdst,ydst; + int src_offs; + UINT8* vram = m_vdp2.gfx_decode; + UINT32 map_offset = stv2_current_tilemap.bitmap_map * 0x20000; + int scrollx = stv2_current_tilemap.scrollx; + int scrolly = stv2_current_tilemap.scrolly; + UINT16 dot_data; + UINT16 pal_bank; + + xsize = (stv2_current_tilemap.bitmap_size & 2) ? 1024 : 512; + ysize = (stv2_current_tilemap.bitmap_size & 1) ? 512 : 256; + + xsize_mask = (stv2_current_tilemap.linescroll_enable) ? 1024 : xsize; + ysize_mask = (stv2_current_tilemap.vertical_linescroll_enable) ? 512 : ysize; + + pal_bank = stv2_current_tilemap.bitmap_palette_number; + pal_bank+= stv2_current_tilemap.colour_ram_address_offset; + pal_bank&= 7; + pal_bank<<=8; + if(stv2_current_tilemap.fade_control & 1) + pal_bank += ((stv2_current_tilemap.fade_control & 2) ? (2*2048) : (2048)); + + for(ydst=cliprect.min_y;ydst<=cliprect.max_y;ydst++) + { + for(xdst=cliprect.min_x;xdst<=cliprect.max_x;xdst++) + { + if(!stv_vdp2_window_process(xdst,ydst)) + continue; + + xsrc = (xdst + scrollx) & (xsize_mask-1); + ysrc = (ydst + scrolly) & (ysize_mask-1); + src_offs = (xsrc + (ysrc*xsize)); + src_offs/= 2; + src_offs += map_offset; + src_offs &= 0x7ffff; + + dot_data = vram[src_offs] >> ((xsrc & 1) ? 0 : 4); + dot_data&= 0xf; + + if ((dot_data != 0) || (stv2_current_tilemap.transparency == STV_TRANSPARENCY_NONE)) + { + dot_data += pal_bank; + + if ( stv2_current_tilemap.colour_calculation_enabled == 0 ) + bitmap.pix32(ydst, xdst) = m_palette->pen(dot_data); + else + bitmap.pix32(ydst, xdst) = alpha_blend_r32(bitmap.pix32(ydst, xdst), m_palette->pen(dot_data), stv2_current_tilemap.alpha); + } + } + } +} + + +void saturn_state::draw_8bpp_bitmap(bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + int xsize, ysize, xsize_mask, ysize_mask; + int xsrc,ysrc,xdst,ydst; + int src_offs; + UINT8* vram = m_vdp2.gfx_decode; + UINT32 map_offset = stv2_current_tilemap.bitmap_map * 0x20000; + int scrollx = stv2_current_tilemap.scrollx; + int scrolly = stv2_current_tilemap.scrolly; + UINT16 dot_data; + UINT16 pal_bank; + int xf, yf; + + xsize = (stv2_current_tilemap.bitmap_size & 2) ? 1024 : 512; + ysize = (stv2_current_tilemap.bitmap_size & 1) ? 512 : 256; + + xsize_mask = (stv2_current_tilemap.linescroll_enable) ? 1024 : xsize; + ysize_mask = (stv2_current_tilemap.vertical_linescroll_enable) ? 512 : ysize; + + pal_bank = stv2_current_tilemap.bitmap_palette_number; + pal_bank+= stv2_current_tilemap.colour_ram_address_offset; + pal_bank&= 7; + pal_bank<<=8; + if(stv2_current_tilemap.fade_control & 1) + pal_bank += ((stv2_current_tilemap.fade_control & 2) ? (2*2048) : (2048)); + + for(ydst=cliprect.min_y;ydst<=cliprect.max_y;ydst++) + { + for(xdst=cliprect.min_x;xdst<=cliprect.max_x;xdst++) + { + if(!stv_vdp2_window_process(xdst,ydst)) + continue; + + xf = stv2_current_tilemap.incx * xdst; + xf>>=16; + yf = stv2_current_tilemap.incy * ydst; + yf>>=16; + + xsrc = (xf + scrollx) & (xsize_mask-1); + ysrc = (yf + scrolly) & (ysize_mask-1); + src_offs = (xsrc + (ysrc*xsize)); + src_offs += map_offset; + src_offs &= 0x7ffff; + + dot_data = vram[src_offs]; + + if ((dot_data != 0) || (stv2_current_tilemap.transparency == STV_TRANSPARENCY_NONE)) + { + dot_data += pal_bank; + + if ( stv2_current_tilemap.colour_calculation_enabled == 0 ) + bitmap.pix32(ydst, xdst) = m_palette->pen(dot_data); + else + bitmap.pix32(ydst, xdst) = alpha_blend_r32(bitmap.pix32(ydst, xdst), m_palette->pen(dot_data), stv2_current_tilemap.alpha); + } + } + } +} + +void saturn_state::draw_11bpp_bitmap(bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + int xsize, ysize, xsize_mask, ysize_mask; + int xsrc,ysrc,xdst,ydst; + int src_offs; + UINT8* vram = m_vdp2.gfx_decode; + UINT32 map_offset = stv2_current_tilemap.bitmap_map * 0x20000; + int scrollx = stv2_current_tilemap.scrollx; + int scrolly = stv2_current_tilemap.scrolly; + UINT16 dot_data; + UINT16 pal_bank; + int xf, yf; + + xsize = (stv2_current_tilemap.bitmap_size & 2) ? 1024 : 512; + ysize = (stv2_current_tilemap.bitmap_size & 1) ? 512 : 256; + + xsize_mask = (stv2_current_tilemap.linescroll_enable) ? 1024 : xsize; + ysize_mask = (stv2_current_tilemap.vertical_linescroll_enable) ? 512 : ysize; + + pal_bank = 0; + if(stv2_current_tilemap.fade_control & 1) + pal_bank = ((stv2_current_tilemap.fade_control & 2) ? (2*2048) : (2048)); + + for(ydst=cliprect.min_y;ydst<=cliprect.max_y;ydst++) + { + for(xdst=cliprect.min_x;xdst<=cliprect.max_x;xdst++) + { + if(!stv_vdp2_window_process(xdst,ydst)) + continue; + + xf = stv2_current_tilemap.incx * xdst; + xf>>=16; + yf = stv2_current_tilemap.incy * ydst; + yf>>=16; + + xsrc = (xf + scrollx) & (xsize_mask-1); + ysrc = (yf + scrolly) & (ysize_mask-1); + src_offs = (xsrc + (ysrc*xsize)); + src_offs *= 2; + src_offs += map_offset; + src_offs &= 0x7ffff; + + dot_data = ((vram[src_offs]<<8)|(vram[src_offs+1]<<0)) & 0x7ff; + + if ((dot_data != 0) || (stv2_current_tilemap.transparency == STV_TRANSPARENCY_NONE)) + { + dot_data += pal_bank; + + if ( stv2_current_tilemap.colour_calculation_enabled == 0 ) + bitmap.pix32(ydst, xdst) = m_palette->pen(dot_data); + else + bitmap.pix32(ydst, xdst) = alpha_blend_r32(bitmap.pix32(ydst, xdst), m_palette->pen(dot_data), stv2_current_tilemap.alpha); + } + } + } +} + + +void saturn_state::draw_rgb15_bitmap(bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + int xsize, ysize, xsize_mask, ysize_mask; + int xsrc,ysrc,xdst,ydst; + int src_offs; + UINT8* vram = m_vdp2.gfx_decode; + UINT32 map_offset = stv2_current_tilemap.bitmap_map * 0x20000; + int scrollx = stv2_current_tilemap.scrollx; + int scrolly = stv2_current_tilemap.scrolly; + int r,g,b; + UINT16 dot_data; + int xf, yf; + + xsize = (stv2_current_tilemap.bitmap_size & 2) ? 1024 : 512; + ysize = (stv2_current_tilemap.bitmap_size & 1) ? 512 : 256; + + xsize_mask = (stv2_current_tilemap.linescroll_enable) ? 1024 : xsize; + ysize_mask = (stv2_current_tilemap.vertical_linescroll_enable) ? 512 : ysize; + + for(ydst=cliprect.min_y;ydst<=cliprect.max_y;ydst++) + { + for(xdst=cliprect.min_x;xdst<=cliprect.max_x;xdst++) + { + if(!stv_vdp2_window_process(xdst,ydst)) + continue; + + xf = stv2_current_tilemap.incx * xdst; + xf>>=16; + yf = stv2_current_tilemap.incy * ydst; + yf>>=16; + + xsrc = (xf + scrollx) & (xsize_mask-1); + ysrc = (yf + scrolly) & (ysize_mask-1); + src_offs = (xsrc + (ysrc*xsize)); + src_offs *= 2; + src_offs += map_offset; + src_offs &= 0x7ffff; + + dot_data =(vram[src_offs]<<8)|(vram[src_offs+1]<<0); + + if ((dot_data & 0x8000) || (stv2_current_tilemap.transparency == STV_TRANSPARENCY_NONE)) + { + b = pal5bit((dot_data & 0x7c00) >> 10); + g = pal5bit((dot_data & 0x03e0) >> 5); + r = pal5bit((dot_data & 0x001f) >> 0); + + if(stv2_current_tilemap.fade_control & 1) + stv_vdp2_compute_color_offset(&r,&g,&b,stv2_current_tilemap.fade_control & 2); + + if ( stv2_current_tilemap.colour_calculation_enabled == 0 ) + bitmap.pix32(ydst, xdst) = rgb_t(r, g, b); + else + bitmap.pix32(ydst, xdst) = alpha_blend_r32( bitmap.pix32(ydst, xdst), rgb_t(r, g, b), stv2_current_tilemap.alpha ); + } + } + } +} + +void saturn_state::draw_rgb32_bitmap(bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + int xsize, ysize, xsize_mask, ysize_mask; + int xsrc,ysrc,xdst,ydst; + int src_offs; + UINT8* vram = m_vdp2.gfx_decode; + UINT32 map_offset = stv2_current_tilemap.bitmap_map * 0x20000; + int scrollx = stv2_current_tilemap.scrollx; + int scrolly = stv2_current_tilemap.scrolly; + int r,g,b; + UINT32 dot_data; + int xf, yf; + + xsize = (stv2_current_tilemap.bitmap_size & 2) ? 1024 : 512; + ysize = (stv2_current_tilemap.bitmap_size & 1) ? 512 : 256; + + xsize_mask = (stv2_current_tilemap.linescroll_enable) ? 1024 : xsize; + ysize_mask = (stv2_current_tilemap.vertical_linescroll_enable) ? 512 : ysize; + + for(ydst=cliprect.min_y;ydst<=cliprect.max_y;ydst++) + { + for(xdst=cliprect.min_x;xdst<=cliprect.max_x;xdst++) + { + if(!stv_vdp2_window_process(xdst,ydst)) + continue; + + xf = stv2_current_tilemap.incx * xdst; + xf>>=16; + yf = stv2_current_tilemap.incy * ydst; + yf>>=16; + + xsrc = (xf + scrollx) & (xsize_mask-1); + ysrc = (yf + scrolly) & (ysize_mask-1); + src_offs = (xsrc + (ysrc*xsize)); + src_offs *= 4; + src_offs += map_offset; + src_offs &= 0x7ffff; + + dot_data = (vram[src_offs+0]<<24)|(vram[src_offs+1]<<16)|(vram[src_offs+2]<<8)|(vram[src_offs+3]<<0); + + if ((dot_data & 0x80000000) || (stv2_current_tilemap.transparency == STV_TRANSPARENCY_NONE)) + { + b = ((dot_data & 0x00ff0000) >> 16); + g = ((dot_data & 0x0000ff00) >> 8); + r = ((dot_data & 0x000000ff) >> 0); + + if(stv2_current_tilemap.fade_control & 1) + stv_vdp2_compute_color_offset(&r,&g,&b,stv2_current_tilemap.fade_control & 2); + + if ( stv2_current_tilemap.colour_calculation_enabled == 0 ) + bitmap.pix32(ydst, xdst) = rgb_t(r, g, b); + else + bitmap.pix32(ydst, xdst) = alpha_blend_r32( bitmap.pix32(ydst, xdst), rgb_t(r, g, b), stv2_current_tilemap.alpha ); + } + } + } +} + + +void saturn_state::stv_vdp2_draw_basic_bitmap(bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + if (!stv2_current_tilemap.enabled) return; + + /* new bitmap code, supposed to rewrite the old one. Not supposed to be clean, but EFFICIENT! */ + if(stv2_current_tilemap.incx == 0x10000 && stv2_current_tilemap.incy == 0x10000) + { + switch(stv2_current_tilemap.colour_depth) + { + case 0: draw_4bpp_bitmap(bitmap,cliprect); return; + case 1: draw_8bpp_bitmap(bitmap,cliprect); return; + case 2: draw_11bpp_bitmap(bitmap, cliprect); return; + case 3: draw_rgb15_bitmap(bitmap,cliprect); return; + case 4: draw_rgb32_bitmap(bitmap,cliprect); return; + } + + /* intentional fall-through*/ + popmessage("%d %s %s %s",stv2_current_tilemap.colour_depth, + stv2_current_tilemap.transparency == STV_TRANSPARENCY_NONE ? "no trans" : "trans", + stv2_current_tilemap.colour_calculation_enabled ? "cc" : "no cc", + (stv2_current_tilemap.incx == 0x10000 && stv2_current_tilemap.incy == 0x10000) ? "no zoom" : "zoom"); + } + else + { + switch(stv2_current_tilemap.colour_depth) + { + // case 0: draw_4bpp_bitmap(bitmap,cliprect); return; + case 1: draw_8bpp_bitmap(bitmap,cliprect); return; + // case 2: draw_11bpp_bitmap(bitmap, cliprect); return; + case 3: draw_rgb15_bitmap(bitmap,cliprect); return; + case 4: draw_rgb32_bitmap(bitmap,cliprect); return; + } + + /* intentional fall-through*/ + popmessage("%d %s %s %s",stv2_current_tilemap.colour_depth, + stv2_current_tilemap.transparency == STV_TRANSPARENCY_NONE ? "no trans" : "trans", + stv2_current_tilemap.colour_calculation_enabled ? "cc" : "no cc", + (stv2_current_tilemap.incx == 0x10000 && stv2_current_tilemap.incy == 0x10000) ? "no zoom" : "zoom"); + } +} + + /*--------------------------------------------------------------------------- + | Plane Size | Pattern Name Data Size | Character Size | Map Bits / Address | + ----------------------------------------------------------------------------| + | | | 1 H x 1 V | bits 6-0 * 0x02000 | + | | 1 word |-------------------------------------| + | | | 2 H x 2 V | bits 8-0 * 0x00800 | + | 1 H x 1 V ---------------------------------------------------------------| + | | | 1 H x 1 V | bits 5-0 * 0x04000 | + | | 2 words |-------------------------------------| + | | | 2 H x 2 V | bits 7-0 * 0x01000 | + ----------------------------------------------------------------------------- + | | | 1 H x 1 V | bits 6-1 * 0x04000 | + | | 1 word |-------------------------------------| + | | | 2 H x 2 V | bits 8-1 * 0x01000 | + | 2 H x 1 V ---------------------------------------------------------------| + | | | 1 H x 1 V | bits 5-1 * 0x08000 | + | | 2 words |-------------------------------------| + | | | 2 H x 2 V | bits 7-1 * 0x02000 | + ----------------------------------------------------------------------------- + | | | 1 H x 1 V | bits 6-2 * 0x08000 | + | | 1 word |-------------------------------------| + | | | 2 H x 2 V | bits 8-2 * 0x02000 | + | 2 H x 2 V ---------------------------------------------------------------| + | | | 1 H x 1 V | bits 5-2 * 0x10000 | + | | 2 words |-------------------------------------| + | | | 2 H x 2 V | bits 7-2 * 0x04000 | + --the-highest-bit-is-ignored-if-vram-is-only-4mbits------------------------*/ + + +/* +4.2 Sega's Cell / Character Pattern / Page / Plane / Map system, aka a rather annoying thing that makes optimizations hard + (this is only for the normal tilemaps at the moment, i haven't even thought about the ROZ ones) + +Tiles: + +Cells are 8x8 gfx stored in video ram, they can be of various colour depths + +Character Patterns can be 8x8 or 16x16 (1 hcell x 1 vcell or 2 hcell x 2 vcell) + (a 16x16 character pattern is 4 8x8 cells put together) + +A page is made up of 64x64 cells, thats 64x64 character patterns in 8x8 mode or 32x32 character patterns in 16x16 mode. + 64 * 8 = 512 (0x200) + 32 * 16 = 512 (0x200) +A page is _always_ 512 (0x200) pixels in each direction + +in 1 word mode a 32*16 x 32*16 page is 0x0800 bytes +in 1 word mode a 64*8 x 64*8 page is 0x2000 bytes +in 2 word mode a 32*16 x 32*16 page is 0x1000 bytes +in 2 word mode a 64*8 x 64*8 page is 0x4000 bytes + +either 1, 2 or 4 pages make each plane depending on the plane size register (per tilemap) + therefore each plane is either + 64 * 8 * 1 x 64 * 8 * 1 (512 x 512) + 64 * 8 * 2 x 64 * 8 * 1 (1024 x 512) + 64 * 8 * 2 x 64 * 8 * 2 (1024 x 1024) + + 32 * 16 * 1 x 32 * 16 * 1 (512 x 512) + 32 * 16 * 2 x 32 * 16 * 1 (1024 x 512) + 32 * 16 * 2 x 32 * 16 * 2 (1024 x 1024) + +map is always enabled? + map is a 2x2 arrangement of planes, all 4 of the planes can be the same. + +*/ + +void saturn_state::stv_vdp2_get_map_page( int x, int y, int *_map, int *_page ) +{ + int page = 0; + int map = 0; + + if ( stv2_current_tilemap.map_count == 4 ) + { + if ( stv2_current_tilemap.tile_size == 0 ) + { + if ( stv2_current_tilemap.plane_size & 1 ) + { + page = ((x >> 6) & 1); + map = (x >> 7) & 1; + } + else + { + map = (x >> 6) & 1; + } + + if ( stv2_current_tilemap.plane_size & 2 ) + { + page |= ((y >> (6-1)) & 2); + map |= ((y >> (7-1)) & 2); + } + else + { + map |= ((y >> (6-1)) & 2); + } + } + else + { + if ( stv2_current_tilemap.plane_size & 1 ) + { + page = ((x >> 5) & 1); + map = (x >> 6) & 1; + } + else + { + map = (x >> 5) & 1; + } + + if ( stv2_current_tilemap.plane_size & 2 ) + { + page |= ((y >> (5 - 1)) & 2); + map |= ((y >> (6-1)) & 2); + } + else + { + map |= ((y >> (5-1)) & 2); + } + } + } + else //16 + { + if ( stv2_current_tilemap.tile_size == 0 ) + { + if ( stv2_current_tilemap.plane_size & 1 ) + { + page = ((x >> 6) & 1); + map = (x >> 7) & 3; + } + else + { + map = (x >> 6) & 3; + } + + if ( stv2_current_tilemap.plane_size & 2 ) + { + page |= ((y >> (6-1)) & 2); + map |= ((y >> (7-2)) & 12); + } + else + { + map |= ((y >> (6-2)) & 12); + } + } + else + { + if ( stv2_current_tilemap.plane_size & 1 ) + { + page = ((x >> 5) & 1); + map = (x >> 6) & 3; + } + else + { + map = (x >> 5) & 3; + } + + if ( stv2_current_tilemap.plane_size & 2 ) + { + page |= ((y >> (5 - 1)) & 2); + map |= ((y >> (6-2)) & 12); + } + else + { + map |= ((y >> (5-2)) & 12); + } + } + } + *_page = page; + *_map = map; +} + +void saturn_state::stv_vdp2_draw_basic_tilemap(bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + /* hopefully this is easier to follow than it is efficient .. */ + + /* I call character patterns tiles .. even if they represent up to 4 tiles */ + + /* Page variables */ + int pgtiles_x, pgpixels_x; + int pgtiles_y, pgpixels_y; + int pgsize_bytes, pgsize_dwords; + + /* Plane Variables */ + int pltiles_x, plpixels_x; + int pltiles_y, plpixels_y; + int plsize_bytes/*, plsize_dwords*/; + + /* Map Variables */ + int mptiles_x, mppixels_x; + int mptiles_y, mppixels_y; + int mpsize_bytes, mpsize_dwords; + + /* work Variables */ + int i, x, y; + int base[16]; + + int scalex,scaley; + int tilesizex, tilesizey; + int drawypos, drawxpos; + + int tilecodemin = 0x10000000, tilecodemax = 0; + + if ( stv2_current_tilemap.incx == 0 || stv2_current_tilemap.incy == 0 ) return; + + if ( stv2_current_tilemap.colour_calculation_enabled == 1 ) + { + if ( STV_VDP2_CCMD ) + { + stv2_current_tilemap.transparency = STV_TRANSPARENCY_ADD_BLEND; + } + else + { + stv2_current_tilemap.transparency = STV_TRANSPARENCY_ALPHA; + } + } + + scalex = (INT32)((INT64)S64(0x100000000) / (INT64)stv2_current_tilemap.incx); + scaley = (INT32)((INT64)S64(0x100000000) / (INT64)stv2_current_tilemap.incy); + tilesizex = scalex * 8; + tilesizey = scaley * 8; + drawypos = drawxpos = 0; + + /* Calculate the Number of tiles for x / y directions of each page (actually these will be the same */ + /* (2-stv2_current_tilemap.tile_size) << 5) */ + pgtiles_x = ((2-stv2_current_tilemap.tile_size) << 5); // 64 (8x8 mode) or 32 (16x16 mode) + pgtiles_y = ((2-stv2_current_tilemap.tile_size) << 5); // 64 (8x8 mode) or 32 (16x16 mode) + + /* Calculate the Page Size in BYTES */ + /* 64 * 64 * (1 * 2) = 0x2000 bytes + 32 * 32 * (1 * 2) = 0x0800 bytes + 64 * 64 * (2 * 2) = 0x4000 bytes + 32 * 32 * (2 * 2) = 0x1000 bytes */ + + pgsize_bytes = (pgtiles_x * pgtiles_y) * ((2-stv2_current_tilemap.pattern_data_size)*2); + + /*--------------------------------------------------------------------------- + | Plane Size | Pattern Name Data Size | Character Size | Map Bits / Address | + ----------------------------------------------------------------------------| + | | | 1 H x 1 V | bits 6-0 * 0x02000 | + | | 1 word |-------------------------------------| + | | | 2 H x 2 V | bits 8-0 * 0x00800 | + | 1 H x 1 V ---------------------------------------------------------------| + | | | 1 H x 1 V | bits 5-0 * 0x04000 | + | | 2 words |-------------------------------------| + | | | 2 H x 2 V | bits 7-0 * 0x01000 | + ---------------------------------------------------------------------------*/ + + + /* Page Dimensions are always 0x200 pixes (512x512) */ + pgpixels_x = 0x200; + pgpixels_y = 0x200; + + /* Work out the Plane Size in tiles and Plane Dimensions (pixels) */ + switch (stv2_current_tilemap.plane_size & 3) + { + case 0: // 1 page * 1 page + pltiles_x = pgtiles_x; + plpixels_x = pgpixels_x; + pltiles_y = pgtiles_y; + plpixels_y = pgpixels_y; + break; + + case 1: // 2 pages * 1 page + pltiles_x = pgtiles_x * 2; + plpixels_x = pgpixels_x * 2; + pltiles_y = pgtiles_y; + plpixels_y = pgpixels_y; + break; + + case 3: // 2 pages * 2 pages + pltiles_x = pgtiles_x * 2; + plpixels_x = pgpixels_x * 2; + pltiles_y = pgtiles_y * 2; + plpixels_y = pgpixels_y * 2; + break; + + default: + // illegal + pltiles_x = pgtiles_x; + plpixels_x = pgpixels_x; + pltiles_y = pgtiles_y * 2; + plpixels_y = pgpixels_y * 2; + break; + } + + /* Plane Size in BYTES */ + /* still the same as before + (64 * 1) * (64 * 1) * (1 * 2) = 0x02000 bytes + (32 * 1) * (32 * 1) * (1 * 2) = 0x00800 bytes + (64 * 1) * (64 * 1) * (2 * 2) = 0x04000 bytes + (32 * 1) * (32 * 1) * (2 * 2) = 0x01000 bytes + changed + (64 * 2) * (64 * 1) * (1 * 2) = 0x04000 bytes + (32 * 2) * (32 * 1) * (1 * 2) = 0x01000 bytes + (64 * 2) * (64 * 1) * (2 * 2) = 0x08000 bytes + (32 * 2) * (32 * 1) * (2 * 2) = 0x02000 bytes + changed + (64 * 2) * (64 * 1) * (1 * 2) = 0x08000 bytes + (32 * 2) * (32 * 1) * (1 * 2) = 0x02000 bytes + (64 * 2) * (64 * 1) * (2 * 2) = 0x10000 bytes + (32 * 2) * (32 * 1) * (2 * 2) = 0x04000 bytes + */ + + plsize_bytes = (pltiles_x * pltiles_y) * ((2-stv2_current_tilemap.pattern_data_size)*2); + + /*--------------------------------------------------------------------------- + | Plane Size | Pattern Name Data Size | Character Size | Map Bits / Address | + ----------------------------------------------------------------------------- + | 1 H x 1 V see above, nothing has changed | + ----------------------------------------------------------------------------- + | | | 1 H x 1 V | bits 6-1 * 0x04000 | + | | 1 word |-------------------------------------| + | | | 2 H x 2 V | bits 8-1 * 0x01000 | + | 2 H x 1 V ---------------------------------------------------------------| + | | | 1 H x 1 V | bits 5-1 * 0x08000 | + | | 2 words |-------------------------------------| + | | | 2 H x 2 V | bits 7-1 * 0x02000 | + ----------------------------------------------------------------------------- + | | | 1 H x 1 V | bits 6-2 * 0x08000 | + | | 1 word |-------------------------------------| + | | | 2 H x 2 V | bits 8-2 * 0x02000 | + | 2 H x 2 V ---------------------------------------------------------------| + | | | 1 H x 1 V | bits 5-2 * 0x10000 | + | | 2 words |-------------------------------------| + | | | 2 H x 2 V | bits 7-2 * 0x04000 | + --the-highest-bit-is-ignored-if-vram-is-only-4mbits------------------------*/ + + + /* Work out the Map Sizes in tiles, Map Dimensions */ + /* maps are always enabled? */ + if ( stv2_current_tilemap.map_count == 4 ) + { + mptiles_x = pltiles_x * 2; + mptiles_y = pltiles_y * 2; + mppixels_x = plpixels_x * 2; + mppixels_y = plpixels_y * 2; + } + else + { + mptiles_x = pltiles_x * 4; + mptiles_y = pltiles_y * 4; + mppixels_x = plpixels_x * 4; + mppixels_y = plpixels_y * 4; + } + + /* Map Size in BYTES */ + mpsize_bytes = (mptiles_x * mptiles_y) * ((2-stv2_current_tilemap.pattern_data_size)*2); + + + /*----------------------------------------------------------------------------------------------------------- + | | | 1 H x 1 V | bits 6-1 (upper mask 0x07f) (0x1ff >> 2) * 0x04000 | + | | 1 word |---------------------------------------------------------------------| + | | | 2 H x 2 V | bits 8-1 (upper mask 0x1ff) (0x1ff >> 0) * 0x01000 | + | 2 H x 1 V -----------------------------------------------------------------------------------------------| + | | | 1 H x 1 V | bits 5-1 (upper mask 0x03f) (0x1ff >> 3) * 0x08000 | + | | 2 words |---------------------------------------------------------------------| + | | | 2 H x 2 V | bits 7-1 (upper mask 0x0ff) (0x1ff >> 1) * 0x02000 | + ------------------------------------------------------------------------------------------------------------- + lower mask = ~stv2_current_tilemap.plane_size + -----------------------------------------------------------------------------------------------------------*/ + + /* Precalculate bases from MAP registers */ + for (i = 0; i < stv2_current_tilemap.map_count; i++) + { + static const int shifttable[4] = {0,1,2,2}; + + int uppermask, uppermaskshift; + + uppermaskshift = (1-stv2_current_tilemap.pattern_data_size) | ((1-stv2_current_tilemap.tile_size)<<1); + uppermask = 0x1ff >> uppermaskshift; + + base[i] = ((stv2_current_tilemap.map_offset[i] & uppermask) >> shifttable[stv2_current_tilemap.plane_size]) * plsize_bytes; + + base[i] &= 0x7ffff; /* shienryu needs this for the text layer, is there a problem elsewhere or is it just right without the ram cart */ + + base[i] = base[i] / 4; // convert bytes to DWORDS + } + + /* other bits */ + //stv2_current_tilemap.trans_enabled = stv2_current_tilemap.trans_enabled ? STV_TRANSPARENCY_NONE : STV_TRANSPARENCY_PEN; + stv2_current_tilemap.scrollx &= mppixels_x-1; + stv2_current_tilemap.scrolly &= mppixels_y-1; + + pgsize_dwords = pgsize_bytes /4; + //plsize_dwords = plsize_bytes /4; + mpsize_dwords = mpsize_bytes /4; + +// if (stv2_current_tilemap.layer_name==3) popmessage ("well this is a bit %08x", stv2_current_tilemap.map_offset[0]); +// if (stv2_current_tilemap.layer_name==3) popmessage ("well this is a bit %08x %08x %08x %08x", stv2_current_tilemap.plane_size, pgtiles_x, pltiles_x, mptiles_x); + + if (!stv2_current_tilemap.enabled) return; // stop right now if its disabled ... + + /* most things we need (or don't need) to work out are now worked out */ + + for (y = 0; y> 16) < cliprect.min_y ) + { + drawypos += drawyposinc; + y++; + } + mptiles_y += y; + } + else + { + drawypos += tilesizey*(stv2_current_tilemap.tile_size ? 2 : 1); + } + if ((drawypos >> 16) > cliprect.max_y) break; + + ypageoffs = y & (pgtiles_y-1); + + for (x = 0; x> 16) < cliprect.min_x ) + { + drawxpos += drawxposinc; + x++; + } + mptiles_x += x; + } + else + { + drawxpos+=tilesizex*(stv2_current_tilemap.tile_size ? 2 : 1); + } + if ( (drawxpos >> 16) > cliprect.max_x ) break; + + xpageoffs = x & (pgtiles_x-1); + + stv_vdp2_get_map_page(x,y,&map,&page); + + newbase = base[map] + page * pgsize_dwords; + offs = (ypageoffs * pgtiles_x) + xpageoffs; + +/* GET THE TILE INFO ... */ + /* 1 word per tile mode with supplement bits */ + if (stv2_current_tilemap.pattern_data_size ==1) + { + data = m_vdp2_vram[newbase + offs/2]; + data = (offs&1) ? (data & 0x0000ffff) : ((data & 0xffff0000) >> 16); + + /* Supplement Mode 12 bits, no flip */ + if (stv2_current_tilemap.character_number_supplement == 1) + { +/* no flip */ flipyx = 0; +/* 8x8 */ if (stv2_current_tilemap.tile_size==0) tilecode = (data & 0x0fff) + ( (stv2_current_tilemap.supplementary_character_bits&0x1c) << 10); +/* 16x16 */ else tilecode = ((data & 0x0fff) << 2) + (stv2_current_tilemap.supplementary_character_bits&0x03) + ((stv2_current_tilemap.supplementary_character_bits&0x10) << 10); + } + /* Supplement Mode 10 bits, with flip */ + else + { +/* flip bits */ flipyx = (data & 0x0c00) >> 10; +/* 8x8 */ if (stv2_current_tilemap.tile_size==0) tilecode = (data & 0x03ff) + ( (stv2_current_tilemap.supplementary_character_bits) << 10); +/* 16x16 */ else tilecode = ((data & 0x03ff) <<2) + (stv2_current_tilemap.supplementary_character_bits&0x03) + ((stv2_current_tilemap.supplementary_character_bits&0x1c) << 10); + } + +/*>16cols*/ if (stv2_current_tilemap.colour_depth != 0) pal = ((data & 0x7000)>>8); +/*16 cols*/ else pal = ((data & 0xf000)>>12) +( (stv2_current_tilemap.supplementary_palette_bits) << 4); + + } + /* 2 words per tile, no supplement bits */ + else + { + data = m_vdp2_vram[newbase + offs]; + tilecode = (data & 0x00007fff); + pal = (data & 0x007f0000)>>16; + // specialc = (data & 0x10000000)>>28; + flipyx = (data & 0xc0000000)>>30; + } +/* WE'VE GOT THE TILE INFO ... */ + + if ( tilecode < tilecodemin ) tilecodemin = tilecode; + if ( tilecode > tilecodemax ) tilecodemax = tilecode; + +/* DECODE ANY TILES WE NEED TO DECODE */ + + pal += stv2_current_tilemap.colour_ram_address_offset<< 4; // bios uses this .. + + /*Enable fading bit*/ + if(stv2_current_tilemap.fade_control & 1) + { + /*Select fading bit*/ + pal += ((stv2_current_tilemap.fade_control & 2) ? (0x100) : (0x80)); + } + + if (stv2_current_tilemap.colour_depth == 1) + { + gfx = 2; + pal = pal >>4; + tilecode &=0x7fff; + if (tilecode == 0x7fff) tilecode--; /* prevents crash but unsure what should happen; wrapping? */ + tilecodespacing = 2; + } + else if (stv2_current_tilemap.colour_depth == 0) + { + gfx = 0; + tilecode &=0x7fff; + tilecodespacing = 1; + } +/* TILES ARE NOW DECODED */ + + if(!STV_VDP2_VRAMSZ) + tilecode &= 0x3fff; + +/* DRAW! */ + if(stv2_current_tilemap.incx != 0x10000 || + stv2_current_tilemap.incy != 0x10000 || + stv2_current_tilemap.transparency == STV_TRANSPARENCY_ADD_BLEND ) + { +#define SCR_TILESIZE_X (((drawxpos + tilesizex) >> 16) - (drawxpos >> 16)) +#define SCR_TILESIZE_X1(startx) (((drawxpos + (startx) + tilesizex) >> 16) - ((drawxpos + (startx))>>16)) +#define SCR_TILESIZE_Y (((drawypos + tilesizey) >> 16) - (drawypos >> 16)) +#define SCR_TILESIZE_Y1(starty) (((drawypos + (starty) + tilesizey) >> 16) - ((drawypos + (starty))>>16)) + if (stv2_current_tilemap.tile_size==1) + { + if ( stv2_current_tilemap.colour_depth == 4 ) + { + popmessage("Unsupported tilemap gfx zoom color depth = 4, tile size = 1, contact MAMEdev"); + } + else if ( stv2_current_tilemap.colour_depth == 3 ) + { + /* RGB555 */ + stv_vdp2_drawgfxzoom_rgb555(bitmap,cliprect,tilecode+(0+(flipyx&1)+(flipyx&2))*tilecodespacing,pal,flipyx&1,flipyx&2,drawxpos >> 16, drawypos >> 16,stv2_current_tilemap.transparency,0,scalex,scaley,SCR_TILESIZE_X, SCR_TILESIZE_Y,stv2_current_tilemap.alpha); + stv_vdp2_drawgfxzoom_rgb555(bitmap,cliprect,tilecode+(1-(flipyx&1)+(flipyx&2))*tilecodespacing,pal,flipyx&1,flipyx&2,(drawxpos+tilesizex) >> 16,drawypos >> 16,stv2_current_tilemap.transparency,0,scalex,scaley,SCR_TILESIZE_X1(tilesizex), SCR_TILESIZE_Y,stv2_current_tilemap.alpha); + stv_vdp2_drawgfxzoom_rgb555(bitmap,cliprect,tilecode+(2+(flipyx&1)-(flipyx&2))*tilecodespacing,pal,flipyx&1,flipyx&2,drawxpos >> 16,(drawypos+tilesizey) >> 16,stv2_current_tilemap.transparency,0,scalex,scaley,SCR_TILESIZE_X, SCR_TILESIZE_Y1(tilesizey),stv2_current_tilemap.alpha); + stv_vdp2_drawgfxzoom_rgb555(bitmap,cliprect,tilecode+(3-(flipyx&1)-(flipyx&2))*tilecodespacing,pal,flipyx&1,flipyx&2,(drawxpos+tilesizex)>> 16,(drawypos+tilesizey) >> 16,stv2_current_tilemap.transparency,0,scalex,scaley,SCR_TILESIZE_X1(tilesizex), SCR_TILESIZE_Y1(tilesizey),stv2_current_tilemap.alpha); + } + else + { + /* normal */ + stv_vdp2_drawgfxzoom(bitmap,cliprect,m_gfxdecode->gfx(gfx),tilecode+(0+(flipyx&1)+(flipyx&2))*tilecodespacing,pal,flipyx&1,flipyx&2,drawxpos >> 16, drawypos >> 16,stv2_current_tilemap.transparency,0,scalex,scaley,SCR_TILESIZE_X, SCR_TILESIZE_Y,stv2_current_tilemap.alpha); + stv_vdp2_drawgfxzoom(bitmap,cliprect,m_gfxdecode->gfx(gfx),tilecode+(1-(flipyx&1)+(flipyx&2))*tilecodespacing,pal,flipyx&1,flipyx&2,(drawxpos+tilesizex) >> 16,drawypos >> 16,stv2_current_tilemap.transparency,0,scalex,scaley,SCR_TILESIZE_X1(tilesizex), SCR_TILESIZE_Y,stv2_current_tilemap.alpha); + stv_vdp2_drawgfxzoom(bitmap,cliprect,m_gfxdecode->gfx(gfx),tilecode+(2+(flipyx&1)-(flipyx&2))*tilecodespacing,pal,flipyx&1,flipyx&2,drawxpos >> 16,(drawypos+tilesizey) >> 16,stv2_current_tilemap.transparency,0,scalex,scaley,SCR_TILESIZE_X, SCR_TILESIZE_Y1(tilesizey),stv2_current_tilemap.alpha); + stv_vdp2_drawgfxzoom(bitmap,cliprect,m_gfxdecode->gfx(gfx),tilecode+(3-(flipyx&1)-(flipyx&2))*tilecodespacing,pal,flipyx&1,flipyx&2,(drawxpos+tilesizex)>> 16,(drawypos+tilesizey) >> 16,stv2_current_tilemap.transparency,0,scalex,scaley,SCR_TILESIZE_X1(tilesizex), SCR_TILESIZE_Y1(tilesizey),stv2_current_tilemap.alpha); + } + } + else + { + if ( stv2_current_tilemap.colour_depth == 4 ) + popmessage("Unsupported tilemap gfx zoom color depth = 4, tile size = 0, contact MAMEdev"); + else if ( stv2_current_tilemap.colour_depth == 3) + { + stv_vdp2_drawgfxzoom_rgb555(bitmap,cliprect,tilecode,pal,flipyx&1,flipyx&2, drawxpos >> 16, drawypos >> 16,stv2_current_tilemap.transparency,0,scalex,scaley,SCR_TILESIZE_X,SCR_TILESIZE_Y,stv2_current_tilemap.alpha); + } + else + stv_vdp2_drawgfxzoom(bitmap,cliprect,m_gfxdecode->gfx(gfx),tilecode,pal,flipyx&1,flipyx&2, drawxpos >> 16, drawypos >> 16,stv2_current_tilemap.transparency,0,scalex,scaley,SCR_TILESIZE_X,SCR_TILESIZE_Y,stv2_current_tilemap.alpha); + } + } + else + { + int olddrawxpos, olddrawypos; + olddrawxpos = drawxpos; drawxpos >>= 16; + olddrawypos = drawypos; drawypos >>= 16; + if (stv2_current_tilemap.tile_size==1) + { + if ( stv2_current_tilemap.colour_depth == 4 ) + { + /* normal */ + stv_vdp2_drawgfx_rgb888(bitmap,cliprect,tilecode+(0+(flipyx&1)+(flipyx&2))*4,flipyx&1,flipyx&2,drawxpos, drawypos,stv2_current_tilemap.transparency,stv2_current_tilemap.alpha); + stv_vdp2_drawgfx_rgb888(bitmap,cliprect,tilecode+(1-(flipyx&1)+(flipyx&2))*4,flipyx&1,flipyx&2,drawxpos+8,drawypos,stv2_current_tilemap.transparency,stv2_current_tilemap.alpha); + stv_vdp2_drawgfx_rgb888(bitmap,cliprect,tilecode+(2+(flipyx&1)-(flipyx&2))*4,flipyx&1,flipyx&2,drawxpos,drawypos+8,stv2_current_tilemap.transparency,stv2_current_tilemap.alpha); + stv_vdp2_drawgfx_rgb888(bitmap,cliprect,tilecode+(3-(flipyx&1)-(flipyx&2))*4,flipyx&1,flipyx&2,drawxpos+8,drawypos+8,stv2_current_tilemap.transparency,stv2_current_tilemap.alpha); + } + else if ( stv2_current_tilemap.colour_depth == 3 ) + { + /* normal */ + stv_vdp2_drawgfx_rgb555(bitmap,cliprect,tilecode+(0+(flipyx&1)+(flipyx&2))*4,flipyx&1,flipyx&2,drawxpos, drawypos,stv2_current_tilemap.transparency,stv2_current_tilemap.alpha); + stv_vdp2_drawgfx_rgb555(bitmap,cliprect,tilecode+(1-(flipyx&1)+(flipyx&2))*4,flipyx&1,flipyx&2,drawxpos+8,drawypos,stv2_current_tilemap.transparency,stv2_current_tilemap.alpha); + stv_vdp2_drawgfx_rgb555(bitmap,cliprect,tilecode+(2+(flipyx&1)-(flipyx&2))*4,flipyx&1,flipyx&2,drawxpos,drawypos+8,stv2_current_tilemap.transparency,stv2_current_tilemap.alpha); + stv_vdp2_drawgfx_rgb555(bitmap,cliprect,tilecode+(3-(flipyx&1)-(flipyx&2))*4,flipyx&1,flipyx&2,drawxpos+8,drawypos+8,stv2_current_tilemap.transparency,stv2_current_tilemap.alpha); + } + else if (stv2_current_tilemap.transparency == STV_TRANSPARENCY_ALPHA) + { + /* alpha */ + stv_vdp2_drawgfx_alpha(bitmap,cliprect,m_gfxdecode->gfx(gfx),tilecode+(0+(flipyx&1)+(flipyx&2))*tilecodespacing,pal,flipyx&1,flipyx&2,drawxpos, drawypos,0,stv2_current_tilemap.alpha); + stv_vdp2_drawgfx_alpha(bitmap,cliprect,m_gfxdecode->gfx(gfx),tilecode+(1-(flipyx&1)+(flipyx&2))*tilecodespacing,pal,flipyx&1,flipyx&2,drawxpos+8,drawypos,0,stv2_current_tilemap.alpha); + stv_vdp2_drawgfx_alpha(bitmap,cliprect,m_gfxdecode->gfx(gfx),tilecode+(2+(flipyx&1)-(flipyx&2))*tilecodespacing,pal,flipyx&1,flipyx&2,drawxpos,drawypos+8,0,stv2_current_tilemap.alpha); + stv_vdp2_drawgfx_alpha(bitmap,cliprect,m_gfxdecode->gfx(gfx),tilecode+(3-(flipyx&1)-(flipyx&2))*tilecodespacing,pal,flipyx&1,flipyx&2,drawxpos+8,drawypos+8,0,stv2_current_tilemap.alpha); + } + else + { + /* normal */ + stv_vdp2_drawgfx_transpen(bitmap,cliprect,m_gfxdecode->gfx(gfx),tilecode+(0+(flipyx&1)+(flipyx&2))*tilecodespacing,pal,flipyx&1,flipyx&2,drawxpos, drawypos,(stv2_current_tilemap.transparency==STV_TRANSPARENCY_PEN)?0:-1); + stv_vdp2_drawgfx_transpen(bitmap,cliprect,m_gfxdecode->gfx(gfx),tilecode+(1-(flipyx&1)+(flipyx&2))*tilecodespacing,pal,flipyx&1,flipyx&2,drawxpos+8,drawypos,(stv2_current_tilemap.transparency==STV_TRANSPARENCY_PEN)?0:-1); + stv_vdp2_drawgfx_transpen(bitmap,cliprect,m_gfxdecode->gfx(gfx),tilecode+(2+(flipyx&1)-(flipyx&2))*tilecodespacing,pal,flipyx&1,flipyx&2,drawxpos,drawypos+8,(stv2_current_tilemap.transparency==STV_TRANSPARENCY_PEN)?0:-1); + stv_vdp2_drawgfx_transpen(bitmap,cliprect,m_gfxdecode->gfx(gfx),tilecode+(3-(flipyx&1)-(flipyx&2))*tilecodespacing,pal,flipyx&1,flipyx&2,drawxpos+8,drawypos+8,(stv2_current_tilemap.transparency==STV_TRANSPARENCY_PEN)?0:-1); + } + } + else + { + if ( stv2_current_tilemap.colour_depth == 4) + { + stv_vdp2_drawgfx_rgb888(bitmap,cliprect,tilecode,flipyx&1,flipyx&2,drawxpos,drawypos,stv2_current_tilemap.transparency,stv2_current_tilemap.alpha); + } + else if ( stv2_current_tilemap.colour_depth == 3) + { + stv_vdp2_drawgfx_rgb555(bitmap,cliprect,tilecode,flipyx&1,flipyx&2,drawxpos,drawypos,stv2_current_tilemap.transparency,stv2_current_tilemap.alpha); + } + else + { + if (stv2_current_tilemap.transparency == STV_TRANSPARENCY_ALPHA) + stv_vdp2_drawgfx_alpha(bitmap,cliprect,m_gfxdecode->gfx(gfx),tilecode,pal,flipyx&1,flipyx&2, drawxpos, drawypos,0,stv2_current_tilemap.alpha); + else + stv_vdp2_drawgfx_transpen(bitmap,cliprect,m_gfxdecode->gfx(gfx),tilecode,pal,flipyx&1,flipyx&2, drawxpos, drawypos,(stv2_current_tilemap.transparency==STV_TRANSPARENCY_PEN)?0:-1); + } + } + drawxpos = olddrawxpos; + drawypos = olddrawypos; + } +/* DRAWN?! */ + + } + } + if ( stv2_current_tilemap.layer_name & 0x80 ) + { + static const int shifttable[4] = {0,1,2,2}; + int uppermask, uppermaskshift; + int mapsize; + uppermaskshift = (1-stv2_current_tilemap.pattern_data_size) | ((1-stv2_current_tilemap.tile_size)<<1); + uppermask = 0x1ff >> uppermaskshift; + + if ( LOG_VDP2 ) + { + logerror( "Layer RBG%d, size %d x %d\n", stv2_current_tilemap.layer_name & 0x7f, cliprect.max_x + 1, cliprect.max_y + 1 ); + logerror( "Tiles: min %08X, max %08X\n", tilecodemin, tilecodemax ); + logerror( "MAP size in dwords %08X\n", mpsize_dwords ); + for (i = 0; i < stv2_current_tilemap.map_count; i++) + { + logerror( "Map register %d: base %08X\n", stv2_current_tilemap.map_offset[i], base[i] ); + } + } + + // store map information + stv_vdp2_layer_data_placement.map_offset_min = 0x7fffffff; + stv_vdp2_layer_data_placement.map_offset_max = 0x00000000; + for (i = 0; i < stv2_current_tilemap.map_count; i++) + { + if ( base[i] < stv_vdp2_layer_data_placement.map_offset_min ) + stv_vdp2_layer_data_placement.map_offset_min = base[i]; + if ( base[i] > stv_vdp2_layer_data_placement.map_offset_max ) + stv_vdp2_layer_data_placement.map_offset_max = base[i]; + } + + + mapsize = ((1 & uppermask) >> shifttable[stv2_current_tilemap.plane_size]) * plsize_bytes - + ((0 & uppermask) >> shifttable[stv2_current_tilemap.plane_size]) * plsize_bytes; + mapsize /= 4; + + stv_vdp2_layer_data_placement.map_offset_max += mapsize; + + stv_vdp2_layer_data_placement.tile_offset_min = tilecodemin * 0x20 / 4; + stv_vdp2_layer_data_placement.tile_offset_max = (tilecodemax + 1) * 0x20 / 4; + } + +} + +#define STV_VDP2_READ_VERTICAL_LINESCROLL( _val, _address ) \ + { \ + _val = m_vdp2_vram[ _address ]; \ + _val &= 0x07ffff00; \ + if ( _val & 0x04000000 ) _val |= 0xf8000000; \ + } + + +void saturn_state::stv_vdp2_check_tilemap_with_linescroll(bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + rectangle mycliprect; + int cur_line = cliprect.min_y; + int address; + int active_functions = 0; + INT32 scroll_values[3], prev_scroll_values[3]; + int i; + int scroll_values_equal; + int lines; + INT16 main_scrollx, main_scrolly; +// INT32 incx; + int linescroll_enable, vertical_linescroll_enable, linezoom_enable; + int vertical_linescroll_index = -1; + + // read original scroll values + main_scrollx = stv2_current_tilemap.scrollx; + main_scrolly = stv2_current_tilemap.scrolly; +// incx = stv2_current_tilemap.incx; + + // prepare linescroll flags + linescroll_enable = stv2_current_tilemap.linescroll_enable; +// stv2_current_tilemap.linescroll_enable = 0; + vertical_linescroll_enable = stv2_current_tilemap.vertical_linescroll_enable; +// stv2_current_tilemap.vertical_linescroll_enable = 0; + linezoom_enable = stv2_current_tilemap.linezoom_enable; +// stv2_current_tilemap.linezoom_enable = 0; + + // prepare working clipping rectangle + memcpy( &mycliprect, &cliprect, sizeof(rectangle) ); + + // calculate the number of active functions + if ( linescroll_enable ) active_functions++; + if ( vertical_linescroll_enable ) + { + vertical_linescroll_index = active_functions; + active_functions++; + } + if ( linezoom_enable ) active_functions++; + + // address of data table + address = stv2_current_tilemap.linescroll_table_address + active_functions*4*cliprect.min_y; + + // get the first scroll values + for ( i = 0; i < active_functions; i++ ) + { + if ( i == vertical_linescroll_index ) + { + STV_VDP2_READ_VERTICAL_LINESCROLL( prev_scroll_values[i], (address / 4) + i ); + prev_scroll_values[i] -= (cur_line * stv2_current_tilemap.incy); + } + else + { + prev_scroll_values[i] = m_vdp2_vram[ (address / 4) + i ]; + } + } + + while( cur_line <= cliprect.max_y ) + { + lines = 0; + do + { + // update address + address += active_functions*4; + + // update lines count + lines += stv2_current_tilemap.linescroll_interval; + + // get scroll values + for ( i = 0; i < active_functions; i++ ) + { + if ( i == vertical_linescroll_index ) + { + STV_VDP2_READ_VERTICAL_LINESCROLL( scroll_values[i], (address/4) + i ); + scroll_values[i] -= (cur_line + lines) * stv2_current_tilemap.incy; + } + else + { + scroll_values[i] = m_vdp2_vram[ (address / 4) + i ]; + } + } + + // compare scroll values + scroll_values_equal = 1; + for ( i = 0; i < active_functions; i++ ) + { + scroll_values_equal &= (scroll_values[i] == prev_scroll_values[i]); + } + } while( scroll_values_equal && ((cur_line + lines) <= cliprect.max_y) ); + + // determined how many lines can be drawn + // prepare clipping rectangle + mycliprect.min_y = cur_line; + mycliprect.max_y = cur_line + lines - 1; + + // prepare scroll values + i = 0; + // linescroll + if ( linescroll_enable ) + { + prev_scroll_values[i] &= 0x07ffff00; + if ( prev_scroll_values[i] & 0x04000000 ) prev_scroll_values[i] |= 0xf8000000; + stv2_current_tilemap.scrollx = main_scrollx + (prev_scroll_values[i] >> 16); + i++; + } + // vertical line scroll + if ( vertical_linescroll_enable ) + { + stv2_current_tilemap.scrolly = main_scrolly + (prev_scroll_values[i] >> 16); + i++; + } + + // linezooom + if ( linezoom_enable ) + { + prev_scroll_values[i] &= 0x0007ff00; + if ( prev_scroll_values[i] & 0x00040000 ) prev_scroll_values[i] |= 0xfff80000; + stv2_current_tilemap.incx = prev_scroll_values[i]; + i++; + } + +// if ( LOG_VDP2 ) logerror( "Linescroll: y < %d, %d >, scrollx = %d, scrolly = %d, incx = %f\n", mycliprect.min_y, mycliprect.max_y, stv2_current_tilemap.scrollx, stv2_current_tilemap.scrolly, (float)stv2_current_tilemap.incx/65536.0 ); + // render current tilemap portion + if (stv2_current_tilemap.bitmap_enable) // this layer is a bitmap + { + stv_vdp2_draw_basic_bitmap(bitmap, mycliprect); + } + else + { + //stv_vdp2_apply_window_on_layer(mycliprect); + stv_vdp2_draw_basic_tilemap(bitmap, mycliprect); + } + + // update parameters for next iteration + memcpy( prev_scroll_values, scroll_values, sizeof(scroll_values)); + cur_line += lines; + } +} + +void saturn_state::stv_vdp2_draw_line(bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + int x,y; + UINT8* gfxdata = m_vdp2.gfx_decode; + UINT32 base_offs,base_mask; + UINT32 pix; + UINT8 interlace; + + interlace = (STV_VDP2_LSMD == 3)+1; + + { + base_mask = STV_VDP2_VRAMSZ ? 0x7ffff : 0x3ffff; + + for(y=cliprect.min_y;y<=cliprect.max_y;y++) + { + base_offs = (STV_VDP2_LCTA & base_mask) << 1; + + if(STV_VDP2_LCCLMD) + base_offs += (y / interlace) << 1; + + for(x=cliprect.min_x;x<=cliprect.max_x;x++) + { + UINT16 pen; + + pen = (gfxdata[base_offs+0]<<8)|gfxdata[base_offs+1]; + pix = bitmap.pix32(y, x); + + bitmap.pix32(y, x) = stv_add_blend(m_palette->pen(pen & 0x7ff),pix); + } + } + } +} + +void saturn_state::stv_vdp2_draw_mosaic(bitmap_rgb32 &bitmap, const rectangle &cliprect, UINT8 is_roz) +{ + int x,y,xi,yi; + UINT8 h_size,v_size; + UINT32 pix; + + h_size = STV_VDP2_MZSZH+1; + v_size = STV_VDP2_MZSZV+1; + + if(is_roz) + v_size = 1; + + if(h_size == 1 && v_size == 1) + return; // don't bother + + if(STV_VDP2_LSMD == 3) + v_size <<= 1; + + for(y=cliprect.min_y;y<=cliprect.max_y;y+=v_size) + { + for(x=cliprect.min_x;x<=cliprect.max_x;x+=h_size) + { + pix = bitmap.pix32(y, x); + + for(yi=0;yi color calculation window */ + /* Ide Yousuke Meijin No Shin Jissen Mahjong 0x0303 */ + /* Decathlete 0x088 */ + /* Sexy Parodius 0x2300 */ +// if(STV_VDP2_WCTLD & 0x2000) +// popmessage("Special window enabled %04x, contact MAMEdev",STV_VDP2_WCTLD); + + /* Shining Force III, After Burner 2 (doesn't make a proper use tho?) */ + /* Layer Section */ + //if(STV_VDP2_W0LWE || STV_VDP2_W1LWE) + // popmessage("Line Window %s %08x enabled, contact MAMEdev",STV_VDP2_W0LWE ? "0" : "1",STV_VDP2_W0LWTA); + + /* Akumajou Dracula, bits 2-4 */ + /* Arcana Strikes bit 5 */ + /* Choh Makai Mura 0x0055 */ + /* Sega Rally 0x0155 */ + /* Find Love 0x4400 */ + /* Dragon Ball Z 0x3800 - 0x2c00 */ + /* Assault Suit Leynos 2 0x0200*/ + /* Bug! 0x8800 */ + /* Wonder 3 0x0018 */ + if(STV_VDP2_SFPRMD & ~0xff7f) + popmessage("Special Priority Mode enabled %04x, contact MAMEdev",STV_VDP2_SFPRMD); + } +} + + +void saturn_state::stv_vdp2_copy_roz_bitmap(bitmap_rgb32 &bitmap, + bitmap_rgb32 &roz_bitmap, + const rectangle &cliprect, + int iRP, + int planesizex, + int planesizey, + int planerenderedsizex, + int planerenderedsizey) +{ + INT32 xsp, ysp, xp, yp, dx, dy, x, y, xs, ys, dxs, dys; + INT32 vcnt, hcnt; + INT32 kx, ky; + INT8 use_coeff_table, coeff_table_mode, coeff_table_size, coeff_table_shift; + INT8 screen_over_process; + UINT8 vcnt_shift, hcnt_shift; + UINT8 coeff_msb; + UINT32 *coeff_table_base, coeff_table_offset; + INT32 coeff_table_val; + UINT32 address; + UINT32 *line; + rgb_t pix; + //UINT32 coeff_line_color_screen_data; + INT32 clipxmask = 0, clipymask = 0; + + + vcnt_shift = ((STV_VDP2_LSMD & 3) == 3); + hcnt_shift = ((STV_VDP2_HRES & 2) == 2); + + planesizex--; + planesizey--; + planerenderedsizex--; + planerenderedsizey--; + + kx = RP.kx; + ky = RP.ky; + + use_coeff_table = coeff_table_mode = coeff_table_size = coeff_table_shift = 0; + coeff_table_offset = 0; + coeff_table_val = 0; + coeff_table_base = NULL; + + if ( LOG_ROZ == 1 ) logerror( "Rendering RBG with parameter %s\n", iRP == 1 ? "A" : "B" ); + if ( LOG_ROZ == 1 ) logerror( "RPMD (parameter mode) = %x\n", STV_VDP2_RPMD ); + if ( LOG_ROZ == 1 ) logerror( "RPRCTL (parameter read control) = %04x\n", STV_VDP2_RPRCTL ); + if ( LOG_ROZ == 1 ) logerror( "KTCTL (coefficient table control) = %04x\n", STV_VDP2_KTCTL ); + if ( LOG_ROZ == 1 ) logerror( "KTAOF (coefficient table address offset) = %04x\n", STV_VDP2_KTAOF ); + if ( LOG_ROZ == 1 ) logerror( "RAOVR (screen-over process) = %x\n", STV_VDP2_RAOVR ); + if ( iRP == 1 ) + { + use_coeff_table = STV_VDP2_RAKTE; + if ( use_coeff_table == 1 ) + { + coeff_table_mode = STV_VDP2_RAKMD; + coeff_table_size = STV_VDP2_RAKDBS; + coeff_table_offset = STV_VDP2_RAKTAOS; + } + screen_over_process = STV_VDP2_RAOVR; + } + else + { + use_coeff_table = STV_VDP2_RBKTE; + if ( use_coeff_table == 1 ) + { + coeff_table_mode = STV_VDP2_RBKMD; + coeff_table_size = STV_VDP2_RBKDBS; + coeff_table_offset = STV_VDP2_RBKTAOS; + } + screen_over_process = STV_VDP2_RBOVR; + } + if ( use_coeff_table ) + { + if ( STV_VDP2_CRKTE == 0 ) + { + coeff_table_base = m_vdp2_vram; + } + else + { + coeff_table_base = m_vdp2_cram; + } + if ( coeff_table_size == 0 ) + { + coeff_table_offset = (coeff_table_offset & 0x0003) * 0x40000; + coeff_table_shift = 2; + } + else + { + coeff_table_offset = (coeff_table_offset & 0x0007) * 0x20000; + coeff_table_shift = 1; + } + } + + if ( stv2_current_tilemap.colour_calculation_enabled == 1 ) + { + if ( STV_VDP2_CCMD ) + { + stv2_current_tilemap.transparency = STV_TRANSPARENCY_ADD_BLEND; + } + else + { + stv2_current_tilemap.transparency = STV_TRANSPARENCY_ALPHA; + } + } + + /* clipping */ + switch( screen_over_process ) + { + case 0: + /* repeated */ + clipxmask = clipymask = 0; + break; + case 1: + /* screen over pattern, not supported */ + clipxmask = clipymask = 0; + break; + case 2: + /* outside display area, scroll screen is transparent */ + clipxmask = ~planesizex; + clipymask = ~planesizey; + break; + case 3: + /* display area is 512x512, outside is transparent */ + clipxmask = ~511; + clipymask = ~511; + break; + } + + //dx = (RP.A * RP.dx) + (RP.B * RP.dy); + //dy = (RP.D * RP.dx) + (RP.E * RP.dy); + dx = mul_fixed32( RP.A, RP.dx ) + mul_fixed32( RP.B, RP.dy ); + dy = mul_fixed32( RP.D, RP.dx ) + mul_fixed32( RP.E, RP.dy ); + + //xp = RP.A * ( RP.px - RP.cx ) + RP.B * ( RP.py - RP.cy ) + RP.C * ( RP.pz - RP.cz ) + RP.cx + RP.mx; + //yp = RP.D * ( RP.px - RP.cx ) + RP.E * ( RP.py - RP.cy ) + RP.F * ( RP.pz - RP.cz ) + RP.cy + RP.my; + xp = mul_fixed32( RP.A, RP.px - RP.cx ) + mul_fixed32( RP.B, RP.py - RP.cy ) + mul_fixed32( RP.C, RP.pz - RP.cz ) + RP.cx + RP.mx; + yp = mul_fixed32( RP.D, RP.px - RP.cx ) + mul_fixed32( RP.E, RP.py - RP.cy ) + mul_fixed32( RP.F, RP.pz - RP.cz ) + RP.cy + RP.my; + + for (vcnt = cliprect.min_y; vcnt <= cliprect.max_y; vcnt++ ) + { + /*xsp = RP.A * ( ( RP.xst + RP.dxst * (vcnt << 16) ) - RP.px ) + + RP.B * ( ( RP.yst + RP.dyst * (vcnt << 16) ) - RP.py ) + + RP.C * ( RP.zst - RP.pz); + ysp = RP.D * ( ( RP.xst + RP.dxst * (vcnt << 16) ) - RP.px ) + + RP.E * ( ( RP.yst + RP.dyst * (vcnt << 16) ) - RP.py ) + + RP.F * ( RP.zst - RP.pz );*/ + xsp = mul_fixed32( RP.A, RP.xst + mul_fixed32( RP.dxst, vcnt << (16 - vcnt_shift)) - RP.px ) + + mul_fixed32( RP.B, RP.yst + mul_fixed32( RP.dyst, vcnt << (16 - vcnt_shift)) - RP.py ) + + mul_fixed32( RP.C, RP.zst - RP.pz ); + ysp = mul_fixed32( RP.D, RP.xst + mul_fixed32( RP.dxst, vcnt << (16 - vcnt_shift)) - RP.px ) + + mul_fixed32( RP.E, RP.yst + mul_fixed32( RP.dyst, vcnt << (16 - vcnt_shift)) - RP.py ) + + mul_fixed32( RP.F, RP.zst - RP.pz ); + //xp = RP.A * ( RP.px - RP.cx ) + RP.B * ( RP.py - RP.cy ) + RP.C * ( RP.pz - RP.cz ) + RP.cx + RP.mx; + //yp = RP.D * ( RP.px - RP.cx ) + RP.E * ( RP.py - RP.cy ) + RP.F * ( RP.pz - RP.cz ) + RP.cy + RP.my; + //dx = (RP.A * RP.dx) + (RP.B * RP.dy); + //dy = (RP.D * RP.dx) + (RP.E * RP.dy); + + line = &bitmap.pix32(vcnt); + + if ( !use_coeff_table || RP.dkax == 0 ) + { + if ( use_coeff_table ) + { + switch( coeff_table_size ) + { + case 0: + address = coeff_table_offset + ((RP.kast + RP.dkast*(vcnt>>vcnt_shift)) >> 16) * 4; + coeff_table_val = coeff_table_base[ address / 4 ]; + //coeff_line_color_screen_data = (coeff_table_val & 0x7f000000) >> 24; + coeff_msb = (coeff_table_val & 0x80000000) > 0; + if ( coeff_table_val & 0x00800000 ) + { + coeff_table_val |= 0xff000000; + } + else + { + coeff_table_val &= 0x007fffff; + } + break; + case 1: + address = coeff_table_offset + ((RP.kast + RP.dkast*(vcnt>>vcnt_shift)) >> 16) * 2; + coeff_table_val = coeff_table_base[ address / 4 ]; + if ( (address & 2) == 0 ) + { + coeff_table_val >>= 16; + } + coeff_table_val &= 0xffff; + //coeff_line_color_screen_data = 0; + coeff_msb = (coeff_table_val & 0x8000) > 0; + if ( coeff_table_val & 0x4000 ) + { + coeff_table_val |= 0xffff8000; + } + else + { + coeff_table_val &= 0x3fff; + } + coeff_table_val <<= 6; /* to form 16.16 fixed point val */ + break; + default: + coeff_msb = 1; + break; + } + if ( coeff_msb ) continue; + + switch( coeff_table_mode ) + { + case 0: + kx = ky = coeff_table_val; + break; + case 1: + kx = coeff_table_val; + break; + case 2: + ky = coeff_table_val; + break; + case 3: + xp = coeff_table_val; + break; + } + } + + //x = RP.kx * ( xsp + dx * (hcnt << 16)) + xp; + //y = RP.ky * ( ysp + dy * (hcnt << 16)) + yp; + xs = mul_fixed32( kx, xsp ) + xp; + ys = mul_fixed32( ky, ysp ) + yp; + dxs = mul_fixed32( kx, mul_fixed32( dx, 1 << (16-hcnt_shift))); + dys = mul_fixed32( ky, mul_fixed32( dy, 1 << (16-hcnt_shift))); + + for (hcnt = cliprect.min_x; hcnt <= cliprect.max_x; xs+=dxs, ys+=dys, hcnt++ ) + { + x = xs >> 16; + y = ys >> 16; + + if ( x & clipxmask || y & clipymask ) continue; + pix = roz_bitmap.pix32(y & planerenderedsizey, x & planerenderedsizex); + switch( stv2_current_tilemap.transparency ) + { + case STV_TRANSPARENCY_PEN: + if (pix & 0xffffff) + { + if(stv2_current_tilemap.fade_control & 1) + stv_vdp2_compute_color_offset_UINT32(&pix,stv2_current_tilemap.fade_control & 2); + + line[hcnt] = pix; + } + break; + case STV_TRANSPARENCY_NONE: + if(stv2_current_tilemap.fade_control & 1) + stv_vdp2_compute_color_offset_UINT32(&pix,stv2_current_tilemap.fade_control & 2); + + line[hcnt] = pix; + break; + case STV_TRANSPARENCY_ALPHA: + if (pix & 0xffffff) + { + if(stv2_current_tilemap.fade_control & 1) + stv_vdp2_compute_color_offset_UINT32(&pix,stv2_current_tilemap.fade_control & 2); + + line[hcnt] = alpha_blend_r32( line[hcnt], pix, stv2_current_tilemap.alpha ); + } + break; + case STV_TRANSPARENCY_ADD_BLEND: + if (pix & 0xffffff) + { + if(stv2_current_tilemap.fade_control & 1) + stv_vdp2_compute_color_offset_UINT32(&pix,stv2_current_tilemap.fade_control & 2); + + line[hcnt] = stv_add_blend( line[hcnt], pix ); + } + break; + } + + } + } + else + { + for (hcnt = cliprect.min_x; hcnt <= cliprect.max_x; hcnt++ ) + { + switch( coeff_table_size ) + { + case 0: + address = coeff_table_offset + ((RP.kast + RP.dkast*(vcnt>>vcnt_shift) + RP.dkax*hcnt) >> 16) * 4; + coeff_table_val = coeff_table_base[ address / 4 ]; + //coeff_line_color_screen_data = (coeff_table_val & 0x7f000000) >> 24; + coeff_msb = (coeff_table_val & 0x80000000) > 0; + if ( coeff_table_val & 0x00800000 ) + { + coeff_table_val |= 0xff000000; + } + else + { + coeff_table_val &= 0x007fffff; + } + break; + case 1: + address = coeff_table_offset + ((RP.kast + RP.dkast*(vcnt>>vcnt_shift) + RP.dkax*hcnt) >> 16) * 2; + coeff_table_val = coeff_table_base[ address / 4 ]; + if ( (address & 2) == 0 ) + { + coeff_table_val >>= 16; + } + coeff_table_val &= 0xffff; + //coeff_line_color_screen_data = 0; + coeff_msb = (coeff_table_val & 0x8000) > 0; + if ( coeff_table_val & 0x4000 ) + { + coeff_table_val |= 0xffff8000; + } + else + { + coeff_table_val &= 0x3fff; + } + coeff_table_val <<= 6; /* to form 16.16 fixed point val */ + break; + default: + coeff_msb = 1; + break; + } + if ( coeff_msb ) continue; + switch( coeff_table_mode ) + { + case 0: + kx = ky = coeff_table_val; + break; + case 1: + kx = coeff_table_val; + break; + case 2: + ky = coeff_table_val; + break; + case 3: + xp = coeff_table_val; + break; + } + + //x = RP.kx * ( xsp + dx * (hcnt << 16)) + xp; + //y = RP.ky * ( ysp + dy * (hcnt << 16)) + yp; + x = mul_fixed32( kx, xsp + mul_fixed32( dx, (hcnt>>hcnt_shift) << 16 ) ) + xp; + y = mul_fixed32( ky, ysp + mul_fixed32( dy, (hcnt>>hcnt_shift) << 16 ) ) + yp; + + x >>= 16; + y >>= 16; + + if ( x & clipxmask || y & clipymask ) continue; + + pix = roz_bitmap.pix32(y & planerenderedsizey, x & planerenderedsizex); + switch( stv2_current_tilemap.transparency ) + { + case STV_TRANSPARENCY_PEN: + if (pix & 0xffffff) + { + if(stv2_current_tilemap.fade_control & 1) + stv_vdp2_compute_color_offset_UINT32(&pix,stv2_current_tilemap.fade_control & 2); + + line[hcnt] = pix; + } + break; + case STV_TRANSPARENCY_NONE: + if(stv2_current_tilemap.fade_control & 1) + stv_vdp2_compute_color_offset_UINT32(&pix,stv2_current_tilemap.fade_control & 2); + + line[hcnt] = pix; + break; + case STV_TRANSPARENCY_ALPHA: + if (pix & 0xffffff) + { + if(stv2_current_tilemap.fade_control & 1) + stv_vdp2_compute_color_offset_UINT32(&pix,stv2_current_tilemap.fade_control & 2); + + line[hcnt] = alpha_blend_r32( line[hcnt], pix, stv2_current_tilemap.alpha ); + } + break; + case STV_TRANSPARENCY_ADD_BLEND: + if (pix & 0xffffff) + { + if(stv2_current_tilemap.fade_control & 1) + stv_vdp2_compute_color_offset_UINT32(&pix,stv2_current_tilemap.fade_control & 2); + + line[hcnt] = stv_add_blend( line[hcnt], pix ); + } + break; + } + } + } + } +} + +void saturn_state::stv_vdp2_draw_NBG0(bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + UINT32 base_mask; + + base_mask = STV_VDP2_VRAMSZ ? 0x7ffff : 0x3ffff; + + /* + Colours : 16, 256, 2048, 32768, 16770000 + Char Size : 1x1 cells, 2x2 cells + Pattern Data Size : 1 word, 2 words + Plane Layouts : 1 x 1, 2 x 1, 2 x 2 + Planes : 4 + Bitmap : Possible + Bitmap Sizes : 512 x 256, 512 x 512, 1024 x 256, 1024 x 512 + Scale : 0.25 x - 256 x + Rotation : No + Linescroll : Yes + Column Scroll : Yes + Mosaic : Yes + */ + + stv2_current_tilemap.enabled = STV_VDP2_N0ON | STV_VDP2_R1ON; + +// if (!stv2_current_tilemap.enabled) return; // stop right now if its disabled ... + + //stv2_current_tilemap.trans_enabled = STV_VDP2_N0TPON; + if ( STV_VDP2_N0CCEN ) + { + stv2_current_tilemap.colour_calculation_enabled = 1; + stv2_current_tilemap.alpha = ((UINT16)(0x1f-STV_VDP2_N0CCRT)*0xff)/0x1f; + } + else + { + stv2_current_tilemap.colour_calculation_enabled = 0; + } + if ( STV_VDP2_N0TPON == 0 ) + { + stv2_current_tilemap.transparency = STV_TRANSPARENCY_PEN; + } + else + { + stv2_current_tilemap.transparency = STV_TRANSPARENCY_NONE; + } + stv2_current_tilemap.colour_depth = STV_VDP2_N0CHCN; + stv2_current_tilemap.tile_size = STV_VDP2_N0CHSZ; + stv2_current_tilemap.bitmap_enable = STV_VDP2_N0BMEN; + stv2_current_tilemap.bitmap_size = STV_VDP2_N0BMSZ; + stv2_current_tilemap.bitmap_palette_number = STV_VDP2_N0BMP; + stv2_current_tilemap.bitmap_map = STV_VDP2_N0MP_; + stv2_current_tilemap.map_offset[0] = STV_VDP2_N0MPA | (STV_VDP2_N0MP_ << 6); + stv2_current_tilemap.map_offset[1] = STV_VDP2_N0MPB | (STV_VDP2_N0MP_ << 6); + stv2_current_tilemap.map_offset[2] = STV_VDP2_N0MPC | (STV_VDP2_N0MP_ << 6); + stv2_current_tilemap.map_offset[3] = STV_VDP2_N0MPD | (STV_VDP2_N0MP_ << 6); + stv2_current_tilemap.map_count = 4; + + stv2_current_tilemap.pattern_data_size = STV_VDP2_N0PNB; + stv2_current_tilemap.character_number_supplement = STV_VDP2_N0CNSM; + stv2_current_tilemap.special_priority_register = STV_VDP2_N0SPR; + stv2_current_tilemap.special_colour_control_register = STV_VDP2_PNCN0; + stv2_current_tilemap.supplementary_palette_bits = STV_VDP2_N0SPLT; + stv2_current_tilemap.supplementary_character_bits = STV_VDP2_N0SPCN; + + stv2_current_tilemap.scrollx = STV_VDP2_SCXIN0; + stv2_current_tilemap.scrolly = STV_VDP2_SCYIN0; + stv2_current_tilemap.incx = STV_VDP2_ZMXN0; + stv2_current_tilemap.incy = STV_VDP2_ZMYN0; + + stv2_current_tilemap.linescroll_enable = STV_VDP2_N0LSCX; + stv2_current_tilemap.linescroll_interval = (((STV_VDP2_LSMD & 3) == 2) ? (2) : (1)) << (STV_VDP2_N0LSS); + stv2_current_tilemap.linescroll_table_address = (((STV_VDP2_LSTA0U << 16) | STV_VDP2_LSTA0L) & base_mask) * 2; + stv2_current_tilemap.vertical_linescroll_enable = STV_VDP2_N0LSCY; + stv2_current_tilemap.linezoom_enable = STV_VDP2_N0LZMX; + + stv2_current_tilemap.plane_size = (STV_VDP2_R1ON) ? STV_VDP2_RBPLSZ : STV_VDP2_N0PLSZ; + stv2_current_tilemap.colour_ram_address_offset = STV_VDP2_N0CAOS; + stv2_current_tilemap.fade_control = (STV_VDP2_N0COEN * 1) | (STV_VDP2_N0COSL * 2); + stv_vdp2_check_fade_control_for_layer(); + stv2_current_tilemap.window_control.logic = STV_VDP2_N0LOG; + stv2_current_tilemap.window_control.enabled[0] = STV_VDP2_N0W0E; + stv2_current_tilemap.window_control.enabled[1] = STV_VDP2_N0W1E; +// stv2_current_tilemap.window_control.? = STV_VDP2_N0SWE; + stv2_current_tilemap.window_control.area[0] = STV_VDP2_N0W0A; + stv2_current_tilemap.window_control.area[1] = STV_VDP2_N0W1A; +// stv2_current_tilemap.window_control.? = STV_VDP2_N0SWA; + + stv2_current_tilemap.line_screen_enabled = STV_VDP2_N0LCEN; + stv2_current_tilemap.mosaic_screen_enabled = STV_VDP2_N0MZE; + + stv2_current_tilemap.layer_name=(STV_VDP2_R1ON) ? 0x81 : 0; + + if ( stv2_current_tilemap.enabled && (!(STV_VDP2_R1ON))) /* TODO: check cycle pattern for RBG1 */ + { + stv2_current_tilemap.enabled = stv_vdp2_check_vram_cycle_pattern_registers( STV_VDP2_CP_NBG0_PNMDR, STV_VDP2_CP_NBG0_CPDR, stv2_current_tilemap.bitmap_enable ); + } + + if(STV_VDP2_R1ON) + stv_vdp2_draw_rotation_screen(bitmap, cliprect, 2 ); + else + stv_vdp2_check_tilemap(bitmap, cliprect); +} + +void saturn_state::stv_vdp2_draw_NBG1(bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + UINT32 base_mask; + + base_mask = STV_VDP2_VRAMSZ ? 0x7ffff : 0x3ffff; + + /* + Colours : 16, 256, 2048, 32768 + Char Size : 1x1 cells, 2x2 cells + Pattern Data Size : 1 word, 2 words + Plane Layouts : 1 x 1, 2 x 1, 2 x 2 + Planes : 4 + Bitmap : Possible + Bitmap Sizes : 512 x 256, 512 x 512, 1024 x 256, 1024 x 512 + Scale : 0.25 x - 256 x + Rotation : No + Linescroll : Yes + Column Scroll : Yes + Mosaic : Yes + */ + stv2_current_tilemap.enabled = STV_VDP2_N1ON; + +// if (!stv2_current_tilemap.enabled) return; // stop right now if its disabled ... + + //stv2_current_tilemap.trans_enabled = STV_VDP2_N1TPON; + if ( STV_VDP2_N1CCEN ) + { + stv2_current_tilemap.colour_calculation_enabled = 1; + stv2_current_tilemap.alpha = ((UINT16)(0x1f-STV_VDP2_N1CCRT)*0xff)/0x1f; + } + else + { + stv2_current_tilemap.colour_calculation_enabled = 0; + } + if ( STV_VDP2_N1TPON == 0 ) + { + stv2_current_tilemap.transparency = STV_TRANSPARENCY_PEN; + } + else + { + stv2_current_tilemap.transparency = STV_TRANSPARENCY_NONE; + } + stv2_current_tilemap.colour_depth = STV_VDP2_N1CHCN; + stv2_current_tilemap.tile_size = STV_VDP2_N1CHSZ; + stv2_current_tilemap.bitmap_enable = STV_VDP2_N1BMEN; + stv2_current_tilemap.bitmap_size = STV_VDP2_N1BMSZ; + stv2_current_tilemap.bitmap_palette_number = STV_VDP2_N1BMP; + stv2_current_tilemap.bitmap_map = STV_VDP2_N1MP_; + stv2_current_tilemap.map_offset[0] = STV_VDP2_N1MPA | (STV_VDP2_N1MP_ << 6); + stv2_current_tilemap.map_offset[1] = STV_VDP2_N1MPB | (STV_VDP2_N1MP_ << 6); + stv2_current_tilemap.map_offset[2] = STV_VDP2_N1MPC | (STV_VDP2_N1MP_ << 6); + stv2_current_tilemap.map_offset[3] = STV_VDP2_N1MPD | (STV_VDP2_N1MP_ << 6); + stv2_current_tilemap.map_count = 4; + + stv2_current_tilemap.pattern_data_size = STV_VDP2_N1PNB; + stv2_current_tilemap.character_number_supplement = STV_VDP2_N1CNSM; + stv2_current_tilemap.special_priority_register = STV_VDP2_N1SPR; + stv2_current_tilemap.special_colour_control_register = STV_VDP2_PNCN1; + stv2_current_tilemap.supplementary_palette_bits = STV_VDP2_N1SPLT; + stv2_current_tilemap.supplementary_character_bits = STV_VDP2_N1SPCN; + + stv2_current_tilemap.scrollx = STV_VDP2_SCXIN1; + stv2_current_tilemap.scrolly = STV_VDP2_SCYIN1; + stv2_current_tilemap.incx = STV_VDP2_ZMXN1; + stv2_current_tilemap.incy = STV_VDP2_ZMYN1; + + stv2_current_tilemap.linescroll_enable = STV_VDP2_N1LSCX; + stv2_current_tilemap.linescroll_interval = (((STV_VDP2_LSMD & 3) == 2) ? (2) : (1)) << (STV_VDP2_N1LSS); + stv2_current_tilemap.linescroll_table_address = (((STV_VDP2_LSTA1U << 16) | STV_VDP2_LSTA1L) & base_mask) * 2; + stv2_current_tilemap.vertical_linescroll_enable = STV_VDP2_N1LSCY; + stv2_current_tilemap.linezoom_enable = STV_VDP2_N1LZMX; + + stv2_current_tilemap.plane_size = STV_VDP2_N1PLSZ; + stv2_current_tilemap.colour_ram_address_offset = STV_VDP2_N1CAOS; + stv2_current_tilemap.fade_control = (STV_VDP2_N1COEN * 1) | (STV_VDP2_N1COSL * 2); + stv_vdp2_check_fade_control_for_layer(); + stv2_current_tilemap.window_control.logic = STV_VDP2_N1LOG; + stv2_current_tilemap.window_control.enabled[0] = STV_VDP2_N1W0E; + stv2_current_tilemap.window_control.enabled[1] = STV_VDP2_N1W1E; +// stv2_current_tilemap.window_control.? = STV_VDP2_N1SWE; + stv2_current_tilemap.window_control.area[0] = STV_VDP2_N1W0A; + stv2_current_tilemap.window_control.area[1] = STV_VDP2_N1W1A; +// stv2_current_tilemap.window_control.? = STV_VDP2_N1SWA; + + stv2_current_tilemap.line_screen_enabled = STV_VDP2_N1LCEN; + stv2_current_tilemap.mosaic_screen_enabled = STV_VDP2_N1MZE; + + stv2_current_tilemap.layer_name=1; + + if ( stv2_current_tilemap.enabled ) + { + stv2_current_tilemap.enabled = stv_vdp2_check_vram_cycle_pattern_registers( STV_VDP2_CP_NBG1_PNMDR, STV_VDP2_CP_NBG1_CPDR, stv2_current_tilemap.bitmap_enable ); + } + + stv_vdp2_check_tilemap(bitmap, cliprect); +} + +void saturn_state::stv_vdp2_draw_NBG2(bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + /* + NBG2 is the first of the 2 more basic tilemaps, it has exactly the same capabilities as NBG3 + + Colours : 16, 256 + Char Size : 1x1 cells, 2x2 cells + Pattern Data Size : 1 word, 2 words + Plane Layouts : 1 x 1, 2 x 1, 2 x 2 + Planes : 4 + Bitmap : No + Bitmap Sizes : N/A + Scale : No + Rotation : No + Linescroll : No + Column Scroll : No + Mosaic : Yes + */ + + stv2_current_tilemap.enabled = STV_VDP2_N2ON; + + /* these modes for N0 disable this layer */ + if (STV_VDP2_N0CHCN == 0x03) stv2_current_tilemap.enabled = 0; + if (STV_VDP2_N0CHCN == 0x04) stv2_current_tilemap.enabled = 0; + +// if (!stv2_current_tilemap.enabled) return; // stop right now if its disabled ... + + //stv2_current_tilemap.trans_enabled = STV_VDP2_N2TPON; + if ( STV_VDP2_N2CCEN ) + { + stv2_current_tilemap.colour_calculation_enabled = 1; + stv2_current_tilemap.alpha = ((UINT16)(0x1f-STV_VDP2_N2CCRT)*0xff)/0x1f; + } + else + { + stv2_current_tilemap.colour_calculation_enabled = 0; + } + if ( STV_VDP2_N2TPON == 0 ) + { + stv2_current_tilemap.transparency = STV_TRANSPARENCY_PEN; + } + else + { + stv2_current_tilemap.transparency = STV_TRANSPARENCY_NONE; + } + stv2_current_tilemap.colour_depth = STV_VDP2_N2CHCN; + stv2_current_tilemap.tile_size = STV_VDP2_N2CHSZ; + /* this layer can't be a bitmap,so ignore these registers*/ + stv2_current_tilemap.bitmap_enable = 0; + stv2_current_tilemap.bitmap_size = 0; + stv2_current_tilemap.bitmap_palette_number = 0; + stv2_current_tilemap.bitmap_map = 0; + stv2_current_tilemap.map_offset[0] = STV_VDP2_N2MPA | (STV_VDP2_N2MP_ << 6); + stv2_current_tilemap.map_offset[1] = STV_VDP2_N2MPB | (STV_VDP2_N2MP_ << 6); + stv2_current_tilemap.map_offset[2] = STV_VDP2_N2MPC | (STV_VDP2_N2MP_ << 6); + stv2_current_tilemap.map_offset[3] = STV_VDP2_N2MPD | (STV_VDP2_N2MP_ << 6); + stv2_current_tilemap.map_count = 4; + + stv2_current_tilemap.pattern_data_size = STV_VDP2_N2PNB; + stv2_current_tilemap.character_number_supplement = STV_VDP2_N2CNSM; + stv2_current_tilemap.special_priority_register = STV_VDP2_N2SPR; + stv2_current_tilemap.special_colour_control_register = STV_VDP2_PNCN2; + stv2_current_tilemap.supplementary_palette_bits = STV_VDP2_N2SPLT; + stv2_current_tilemap.supplementary_character_bits = STV_VDP2_N2SPCN; + + stv2_current_tilemap.scrollx = STV_VDP2_SCXN2; + stv2_current_tilemap.scrolly = STV_VDP2_SCYN2; + /*This layer can't be scaled*/ + stv2_current_tilemap.incx = 0x10000; + stv2_current_tilemap.incy = 0x10000; + + stv2_current_tilemap.linescroll_enable = 0; + stv2_current_tilemap.linescroll_interval = 0; + stv2_current_tilemap.linescroll_table_address = 0; + stv2_current_tilemap.vertical_linescroll_enable = 0; + stv2_current_tilemap.linezoom_enable = 0; + + stv2_current_tilemap.colour_ram_address_offset = STV_VDP2_N2CAOS; + stv2_current_tilemap.fade_control = (STV_VDP2_N2COEN * 1) | (STV_VDP2_N2COSL * 2); + stv_vdp2_check_fade_control_for_layer(); + stv2_current_tilemap.window_control.logic = STV_VDP2_N2LOG; + stv2_current_tilemap.window_control.enabled[0] = STV_VDP2_N2W0E; + stv2_current_tilemap.window_control.enabled[1] = STV_VDP2_N2W1E; +// stv2_current_tilemap.window_control.? = STV_VDP2_N2SWE; + stv2_current_tilemap.window_control.area[0] = STV_VDP2_N2W0A; + stv2_current_tilemap.window_control.area[1] = STV_VDP2_N2W1A; +// stv2_current_tilemap.window_control.? = STV_VDP2_N2SWA; + + stv2_current_tilemap.line_screen_enabled = STV_VDP2_N2LCEN; + stv2_current_tilemap.mosaic_screen_enabled = STV_VDP2_N2MZE; + + stv2_current_tilemap.layer_name=2; + + stv2_current_tilemap.plane_size = STV_VDP2_N2PLSZ; + + if ( stv2_current_tilemap.enabled ) + { + stv2_current_tilemap.enabled = stv_vdp2_check_vram_cycle_pattern_registers( STV_VDP2_CP_NBG2_PNMDR, STV_VDP2_CP_NBG2_CPDR, stv2_current_tilemap.bitmap_enable ); + } + + stv_vdp2_check_tilemap(bitmap, cliprect); +} + +void saturn_state::stv_vdp2_draw_NBG3(bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + /* + NBG3 is the second of the 2 more basic tilemaps, it has exactly the same capabilities as NBG2 + + Colours : 16, 256 + Char Size : 1x1 cells, 2x2 cells + Pattern Data Size : 1 word, 2 words + Plane Layouts : 1 x 1, 2 x 1, 2 x 2 + Planes : 4 + Bitmap : No + Bitmap Sizes : N/A + Scale : No + Rotation : No + Linescroll : No + Column Scroll : No + Mosaic : Yes + */ + + stv2_current_tilemap.enabled = STV_VDP2_N3ON; + +// if (!stv2_current_tilemap.enabled) return; // stop right now if its disabled ... + + /* these modes for N1 disable this layer */ + if (STV_VDP2_N1CHCN == 0x03) stv2_current_tilemap.enabled = 0; + if (STV_VDP2_N1CHCN == 0x04) stv2_current_tilemap.enabled = 0; + + //stv2_current_tilemap.trans_enabled = STV_VDP2_N3TPON; + if ( STV_VDP2_N3CCEN ) + { + stv2_current_tilemap.colour_calculation_enabled = 1; + stv2_current_tilemap.alpha = ((UINT16)(0x1f-STV_VDP2_N3CCRT)*0xff)/0x1f; + } + else + { + stv2_current_tilemap.colour_calculation_enabled = 0; + } + if ( STV_VDP2_N3TPON == 0 ) + { + stv2_current_tilemap.transparency = STV_TRANSPARENCY_PEN; + } + else + { + stv2_current_tilemap.transparency = STV_TRANSPARENCY_NONE; + } + stv2_current_tilemap.colour_depth = STV_VDP2_N3CHCN; + stv2_current_tilemap.tile_size = STV_VDP2_N3CHSZ; + /* this layer can't be a bitmap,so ignore these registers*/ + stv2_current_tilemap.bitmap_enable = 0; + stv2_current_tilemap.bitmap_size = 0; + stv2_current_tilemap.bitmap_palette_number = 0; + stv2_current_tilemap.bitmap_map = 0; + stv2_current_tilemap.map_offset[0] = STV_VDP2_N3MPA | (STV_VDP2_N3MP_ << 6); + stv2_current_tilemap.map_offset[1] = STV_VDP2_N3MPB | (STV_VDP2_N3MP_ << 6); + stv2_current_tilemap.map_offset[2] = STV_VDP2_N3MPC | (STV_VDP2_N3MP_ << 6); + stv2_current_tilemap.map_offset[3] = STV_VDP2_N3MPD | (STV_VDP2_N3MP_ << 6); + stv2_current_tilemap.map_count = 4; + + stv2_current_tilemap.pattern_data_size = STV_VDP2_N3PNB; + stv2_current_tilemap.character_number_supplement = STV_VDP2_N3CNSM; + stv2_current_tilemap.special_priority_register = STV_VDP2_N3SPR; + stv2_current_tilemap.special_colour_control_register = STV_VDP2_N3SCC; + stv2_current_tilemap.supplementary_palette_bits = STV_VDP2_N3SPLT; + stv2_current_tilemap.supplementary_character_bits = STV_VDP2_N3SPCN; + + stv2_current_tilemap.scrollx = STV_VDP2_SCXN3; + stv2_current_tilemap.scrolly = STV_VDP2_SCYN3; + /*This layer can't be scaled*/ + stv2_current_tilemap.incx = 0x10000; + stv2_current_tilemap.incy = 0x10000; + + stv2_current_tilemap.linescroll_enable = 0; + stv2_current_tilemap.linescroll_interval = 0; + stv2_current_tilemap.linescroll_table_address = 0; + stv2_current_tilemap.vertical_linescroll_enable = 0; + stv2_current_tilemap.linezoom_enable = 0; + + stv2_current_tilemap.colour_ram_address_offset = STV_VDP2_N3CAOS; + stv2_current_tilemap.fade_control = (STV_VDP2_N3COEN * 1) | (STV_VDP2_N3COSL * 2); + stv_vdp2_check_fade_control_for_layer(); + stv2_current_tilemap.window_control.logic = STV_VDP2_N3LOG; + stv2_current_tilemap.window_control.enabled[0] = STV_VDP2_N3W0E; + stv2_current_tilemap.window_control.enabled[1] = STV_VDP2_N3W1E; +// stv2_current_tilemap.window_control.? = STV_VDP2_N3SWE; + stv2_current_tilemap.window_control.area[0] = STV_VDP2_N3W0A; + stv2_current_tilemap.window_control.area[1] = STV_VDP2_N3W1A; +// stv2_current_tilemap.window_control.? = STV_VDP2_N3SWA; + + stv2_current_tilemap.line_screen_enabled = STV_VDP2_N3LCEN; + stv2_current_tilemap.mosaic_screen_enabled = STV_VDP2_N3MZE; + + stv2_current_tilemap.layer_name=3; + + stv2_current_tilemap.plane_size = STV_VDP2_N3PLSZ; + + if ( stv2_current_tilemap.enabled ) + { + stv2_current_tilemap.enabled = stv_vdp2_check_vram_cycle_pattern_registers( STV_VDP2_CP_NBG3_PNMDR, STV_VDP2_CP_NBG3_CPDR, stv2_current_tilemap.bitmap_enable ); + } + + stv_vdp2_check_tilemap(bitmap, cliprect); +} + + +void saturn_state::stv_vdp2_draw_rotation_screen(bitmap_rgb32 &bitmap, const rectangle &cliprect, int iRP) +{ + rectangle roz_clip_rect, mycliprect; + int planesizex = 0, planesizey = 0; + int planerenderedsizex, planerenderedsizey; + UINT8 colour_calculation_enabled; + UINT8 fade_control; + + if ( iRP == 1) + { + stv2_current_tilemap.bitmap_map = STV_VDP2_RAMP_; + stv2_current_tilemap.map_offset[0] = STV_VDP2_RAMPA | (STV_VDP2_RAMP_ << 6); + stv2_current_tilemap.map_offset[1] = STV_VDP2_RAMPB | (STV_VDP2_RAMP_ << 6); + stv2_current_tilemap.map_offset[2] = STV_VDP2_RAMPC | (STV_VDP2_RAMP_ << 6); + stv2_current_tilemap.map_offset[3] = STV_VDP2_RAMPD | (STV_VDP2_RAMP_ << 6); + stv2_current_tilemap.map_offset[4] = STV_VDP2_RAMPE | (STV_VDP2_RAMP_ << 6); + stv2_current_tilemap.map_offset[5] = STV_VDP2_RAMPF | (STV_VDP2_RAMP_ << 6); + stv2_current_tilemap.map_offset[6] = STV_VDP2_RAMPG | (STV_VDP2_RAMP_ << 6); + stv2_current_tilemap.map_offset[7] = STV_VDP2_RAMPH | (STV_VDP2_RAMP_ << 6); + stv2_current_tilemap.map_offset[8] = STV_VDP2_RAMPI | (STV_VDP2_RAMP_ << 6); + stv2_current_tilemap.map_offset[9] = STV_VDP2_RAMPJ | (STV_VDP2_RAMP_ << 6); + stv2_current_tilemap.map_offset[10] = STV_VDP2_RAMPK | (STV_VDP2_RAMP_ << 6); + stv2_current_tilemap.map_offset[11] = STV_VDP2_RAMPL | (STV_VDP2_RAMP_ << 6); + stv2_current_tilemap.map_offset[12] = STV_VDP2_RAMPM | (STV_VDP2_RAMP_ << 6); + stv2_current_tilemap.map_offset[13] = STV_VDP2_RAMPN | (STV_VDP2_RAMP_ << 6); + stv2_current_tilemap.map_offset[14] = STV_VDP2_RAMPO | (STV_VDP2_RAMP_ << 6); + stv2_current_tilemap.map_offset[15] = STV_VDP2_RAMPP | (STV_VDP2_RAMP_ << 6); + stv2_current_tilemap.map_count = 16; + } + else + { + stv2_current_tilemap.bitmap_map = STV_VDP2_RBMP_; + stv2_current_tilemap.map_offset[0] = STV_VDP2_RBMPA | (STV_VDP2_RBMP_ << 6); + stv2_current_tilemap.map_offset[1] = STV_VDP2_RBMPB | (STV_VDP2_RBMP_ << 6); + stv2_current_tilemap.map_offset[2] = STV_VDP2_RBMPC | (STV_VDP2_RBMP_ << 6); + stv2_current_tilemap.map_offset[3] = STV_VDP2_RBMPD | (STV_VDP2_RBMP_ << 6); + stv2_current_tilemap.map_offset[4] = STV_VDP2_RBMPE | (STV_VDP2_RBMP_ << 6); + stv2_current_tilemap.map_offset[5] = STV_VDP2_RBMPF | (STV_VDP2_RBMP_ << 6); + stv2_current_tilemap.map_offset[6] = STV_VDP2_RBMPG | (STV_VDP2_RBMP_ << 6); + stv2_current_tilemap.map_offset[7] = STV_VDP2_RBMPH | (STV_VDP2_RBMP_ << 6); + stv2_current_tilemap.map_offset[8] = STV_VDP2_RBMPI | (STV_VDP2_RBMP_ << 6); + stv2_current_tilemap.map_offset[9] = STV_VDP2_RBMPJ | (STV_VDP2_RBMP_ << 6); + stv2_current_tilemap.map_offset[10] = STV_VDP2_RBMPK | (STV_VDP2_RBMP_ << 6); + stv2_current_tilemap.map_offset[11] = STV_VDP2_RBMPL | (STV_VDP2_RBMP_ << 6); + stv2_current_tilemap.map_offset[12] = STV_VDP2_RBMPM | (STV_VDP2_RBMP_ << 6); + stv2_current_tilemap.map_offset[13] = STV_VDP2_RBMPN | (STV_VDP2_RBMP_ << 6); + stv2_current_tilemap.map_offset[14] = STV_VDP2_RBMPO | (STV_VDP2_RBMP_ << 6); + stv2_current_tilemap.map_offset[15] = STV_VDP2_RBMPP | (STV_VDP2_RBMP_ << 6); + stv2_current_tilemap.map_count = 16; + } + + stv_vdp2_fill_rotation_parameter_table(iRP); + + if ( iRP == 1 ) + { + stv2_current_tilemap.plane_size = STV_VDP2_RAPLSZ; + } + else + { + stv2_current_tilemap.plane_size = STV_VDP2_RBPLSZ; + } + + if (stv2_current_tilemap.bitmap_enable) + { + switch (stv2_current_tilemap.bitmap_size) + { + case 0: planesizex=512; planesizey=256; break; + case 1: planesizex=512; planesizey=512; break; + case 2: planesizex=1024; planesizey=256; break; + case 3: planesizex=1024; planesizey=512; break; + } + } + else + { + switch( stv2_current_tilemap.plane_size ) + { + case 0: + planesizex = planesizey = 2048; + break; + case 1: + planesizex = 4096; + planesizey = 2048; + break; + case 2: + planesizex = 0; + planesizey = 0; + break; + case 3: + planesizex = planesizey = 4096; + break; + } + } + + if ( stv_vdp2_is_rotation_applied() == 0 ) + { + stv2_current_tilemap.scrollx = stv_current_rotation_parameter_table.mx >> 16; + stv2_current_tilemap.scrolly = stv_current_rotation_parameter_table.my >> 16; + + stv_vdp2_check_tilemap(bitmap,cliprect); + } + else + { + if ( !m_vdp2.roz_bitmap[iRP-1].valid() ) + m_vdp2.roz_bitmap[iRP-1].allocate(4096, 4096); + + roz_clip_rect.min_x = roz_clip_rect.min_y = 0; + if ( (iRP == 1 && STV_VDP2_RAOVR == 3) || + (iRP == 2 && STV_VDP2_RBOVR == 3) ) + { + roz_clip_rect.max_x = roz_clip_rect.max_y = 511; + planerenderedsizex = planerenderedsizey = 512; + } + else if (stv_vdp2_are_map_registers_equal() && + !stv2_current_tilemap.bitmap_enable) + { + roz_clip_rect.max_x = (planesizex / 4) - 1; + roz_clip_rect.max_y = (planesizey / 4) - 1; + planerenderedsizex = planesizex / 4; + planerenderedsizey = planesizey / 4; + } + else + { + roz_clip_rect.max_x = planesizex - 1; + roz_clip_rect.max_y = planesizey - 1; + planerenderedsizex = planesizex; + planerenderedsizey = planesizey; + } + + + colour_calculation_enabled = stv2_current_tilemap.colour_calculation_enabled; + stv2_current_tilemap.colour_calculation_enabled = 0; +// window_control = stv2_current_tilemap.window_control; +// stv2_current_tilemap.window_control = 0; + fade_control = stv2_current_tilemap.fade_control; + stv2_current_tilemap.fade_control = 0; + g_profiler.start(PROFILER_USER1); + if ( LOG_VDP2 ) logerror( "Checking for cached RBG bitmap, cache_dirty = %d, memcmp() = %d\n", stv_rbg_cache_data.is_cache_dirty, memcmp(&stv_rbg_cache_data.layer_data[iRP-1],&stv2_current_tilemap,sizeof(stv2_current_tilemap))); + if ( (stv_rbg_cache_data.is_cache_dirty & iRP) || + memcmp(&stv_rbg_cache_data.layer_data[iRP-1],&stv2_current_tilemap,sizeof(stv2_current_tilemap)) != 0 ) + { + m_vdp2.roz_bitmap[iRP-1].fill(m_palette->black_pen(), roz_clip_rect ); + stv_vdp2_check_tilemap(m_vdp2.roz_bitmap[iRP-1], roz_clip_rect); + // prepare cache data + stv_rbg_cache_data.watch_vdp2_vram_writes |= iRP; + stv_rbg_cache_data.is_cache_dirty &= ~iRP; + memcpy(&stv_rbg_cache_data.layer_data[iRP-1], &stv2_current_tilemap, sizeof(stv2_current_tilemap)); + stv_rbg_cache_data.map_offset_min[iRP-1] = stv_vdp2_layer_data_placement.map_offset_min; + stv_rbg_cache_data.map_offset_max[iRP-1] = stv_vdp2_layer_data_placement.map_offset_max; + stv_rbg_cache_data.tile_offset_min[iRP-1] = stv_vdp2_layer_data_placement.tile_offset_min; + stv_rbg_cache_data.tile_offset_max[iRP-1] = stv_vdp2_layer_data_placement.tile_offset_max; + if ( LOG_VDP2 ) logerror( "Cache watch: map = %06X - %06X, tile = %06X - %06X\n", stv_rbg_cache_data.map_offset_min[iRP-1], + stv_rbg_cache_data.map_offset_max[iRP-1], stv_rbg_cache_data.tile_offset_min[iRP-1], stv_rbg_cache_data.tile_offset_max[iRP-1] ); + } + + g_profiler.stop(); + + stv2_current_tilemap.colour_calculation_enabled = colour_calculation_enabled; + if ( colour_calculation_enabled ) + { + stv2_current_tilemap.transparency = STV_TRANSPARENCY_ALPHA; + } + + mycliprect = cliprect; + + /* TODO: remove me. */ + if ( stv2_current_tilemap.window_control.enabled[0] || stv2_current_tilemap.window_control.enabled[1] ) + { + //popmessage("Window control for RBG"); + stv_vdp2_apply_window_on_layer(mycliprect); + stv2_current_tilemap.window_control.enabled[0] = 0; + stv2_current_tilemap.window_control.enabled[1] = 0; + } + + stv2_current_tilemap.fade_control = fade_control; + + g_profiler.start(PROFILER_USER2); + stv_vdp2_copy_roz_bitmap(bitmap, m_vdp2.roz_bitmap[iRP-1], mycliprect, iRP, planesizex, planesizey, planerenderedsizex, planerenderedsizey ); + g_profiler.stop(); + } + +} + +void saturn_state::stv_vdp2_draw_RBG0(bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + /* + Colours : 16, 256, 2048, 32768, 16770000 + Char Size : 1x1 cells, 2x2 cells + Pattern Data Size : 1 word, 2 words + Plane Layouts : 1 x 1, 2 x 1, 2 x 2 + Planes : 4 + Bitmap : Possible + Bitmap Sizes : 512 x 256, 512 x 512, 1024 x 256, 1024 x 512 + Scale : 0.25 x - 256 x + Rotation : Yes + Linescroll : Yes + Column Scroll : Yes + Mosaic : Yes + */ + + stv2_current_tilemap.enabled = STV_VDP2_R0ON; + +// if (!stv2_current_tilemap.enabled) return; // stop right now if its disabled ... + + //stv2_current_tilemap.trans_enabled = STV_VDP2_R0TPON; + if ( STV_VDP2_R0CCEN ) + { + stv2_current_tilemap.colour_calculation_enabled = 1; + stv2_current_tilemap.alpha = ((UINT16)(0x1f-STV_VDP2_R0CCRT)*0xff)/0x1f; + } + else + { + stv2_current_tilemap.colour_calculation_enabled = 0; + } + if ( STV_VDP2_R0TPON == 0 ) + { + stv2_current_tilemap.transparency = STV_TRANSPARENCY_PEN; + } + else + { + stv2_current_tilemap.transparency = STV_TRANSPARENCY_NONE; + } + stv2_current_tilemap.colour_depth = STV_VDP2_R0CHCN; + stv2_current_tilemap.tile_size = STV_VDP2_R0CHSZ; + stv2_current_tilemap.bitmap_enable = STV_VDP2_R0BMEN; + stv2_current_tilemap.bitmap_size = STV_VDP2_R0BMSZ; + stv2_current_tilemap.bitmap_palette_number = STV_VDP2_R0BMP; + + stv2_current_tilemap.pattern_data_size = STV_VDP2_R0PNB; + stv2_current_tilemap.character_number_supplement = STV_VDP2_R0CNSM; + stv2_current_tilemap.special_priority_register = STV_VDP2_R0SPR; + stv2_current_tilemap.special_colour_control_register = STV_VDP2_R0SCC; + stv2_current_tilemap.supplementary_palette_bits = STV_VDP2_R0SPLT; + stv2_current_tilemap.supplementary_character_bits = STV_VDP2_R0SPCN; + + stv2_current_tilemap.colour_ram_address_offset = STV_VDP2_R0CAOS; + stv2_current_tilemap.fade_control = (STV_VDP2_R0COEN * 1) | (STV_VDP2_R0COSL * 2); + stv_vdp2_check_fade_control_for_layer(); + stv2_current_tilemap.window_control.logic = STV_VDP2_R0LOG; + stv2_current_tilemap.window_control.enabled[0] = STV_VDP2_R0W0E; + stv2_current_tilemap.window_control.enabled[1] = STV_VDP2_R0W1E; +// stv2_current_tilemap.window_control.? = STV_VDP2_R0SWE; + stv2_current_tilemap.window_control.area[0] = STV_VDP2_R0W0A; + stv2_current_tilemap.window_control.area[1] = STV_VDP2_R0W1A; +// stv2_current_tilemap.window_control.? = STV_VDP2_R0SWA; + + stv2_current_tilemap.scrollx = 0; + stv2_current_tilemap.scrolly = 0; + stv2_current_tilemap.incx = 0x10000; + stv2_current_tilemap.incy = 0x10000; + + stv2_current_tilemap.linescroll_enable = 0; + stv2_current_tilemap.linescroll_interval = 0; + stv2_current_tilemap.linescroll_table_address = 0; + stv2_current_tilemap.vertical_linescroll_enable = 0; + stv2_current_tilemap.linezoom_enable = 0; + + stv2_current_tilemap.line_screen_enabled = STV_VDP2_R0LCEN; + stv2_current_tilemap.mosaic_screen_enabled = STV_VDP2_R0MZE; + + /*Use 0x80 as a normal/rotate switch*/ + stv2_current_tilemap.layer_name=0x80; + + if ( !stv2_current_tilemap.enabled ) return; + + switch(STV_VDP2_RPMD) + { + case 0://Rotation Parameter A + stv_vdp2_draw_rotation_screen(bitmap, cliprect, 1 ); + break; + case 1://Rotation Parameter B + //case 2: + stv_vdp2_draw_rotation_screen(bitmap, cliprect, 2 ); + break; + case 2://Rotation Parameter A & B CKTE + stv_vdp2_draw_rotation_screen(bitmap, cliprect, 2 ); + stv_vdp2_draw_rotation_screen(bitmap, cliprect, 1 ); + break; + case 3://Rotation Parameter A & B Window (wrong) + stv_vdp2_draw_rotation_screen(bitmap, cliprect, 1 ); + break; + } + +} + +void saturn_state::stv_vdp2_draw_back(bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + int x,y; + UINT8* gfxdata = m_vdp2.gfx_decode; + UINT32 base_offs,base_mask; + UINT8 interlace; + + interlace = (STV_VDP2_LSMD == 3)+1; + +// popmessage("Back screen %08x %08x %08x",STV_VDP2_BDCLMD,STV_VDP2_BKCLMD,STV_VDP2_BKTA); + + /* draw black if BDCLMD and DISP are cleared */ + if(!(STV_VDP2_BDCLMD) && !(STV_VDP2_DISP)) + bitmap.fill(m_palette->black_pen(), cliprect); + else + { + base_mask = STV_VDP2_VRAMSZ ? 0x7ffff : 0x3ffff; + + for(y=cliprect.min_y;y<=cliprect.max_y;y++) + { + base_offs = ((STV_VDP2_BKTA ) & base_mask) << 1; + if(STV_VDP2_BKCLMD) + base_offs += ((y / interlace) << 1); + + for(x=cliprect.min_x;x<=cliprect.max_x;x++) + { + int r,g,b; + UINT16 dot; + + dot = (gfxdata[base_offs+0]<<8)|gfxdata[base_offs+1]; + b = pal5bit((dot & 0x7c00) >> 10); + g = pal5bit((dot & 0x03e0) >> 5); + r = pal5bit( dot & 0x001f); + if(STV_VDP2_BKCOEN) + stv_vdp2_compute_color_offset( &r, &g, &b, STV_VDP2_BKCOSL ); + + bitmap.pix32(y, x) = rgb_t(r, g, b); + } + } + } +} + +READ32_MEMBER ( saturn_state::saturn_vdp2_vram_r ) +{ + return m_vdp2_vram[offset]; +} + +WRITE32_MEMBER ( saturn_state::saturn_vdp2_vram_w ) +{ + UINT8* gfxdata = m_vdp2.gfx_decode; + + COMBINE_DATA(&m_vdp2_vram[offset]); + + data = m_vdp2_vram[offset]; + /* put in gfx region for easy decoding */ + gfxdata[offset*4+0] = (data & 0xff000000) >> 24; + gfxdata[offset*4+1] = (data & 0x00ff0000) >> 16; + gfxdata[offset*4+2] = (data & 0x0000ff00) >> 8; + gfxdata[offset*4+3] = (data & 0x000000ff) >> 0; + + m_gfxdecode->gfx(0)->mark_dirty(offset/8); + m_gfxdecode->gfx(1)->mark_dirty(offset/8); + m_gfxdecode->gfx(2)->mark_dirty(offset/8); + m_gfxdecode->gfx(3)->mark_dirty(offset/8); + + /* 8-bit tiles overlap, so this affects the previous one as well */ + if (offset/8 != 0) + { + m_gfxdecode->gfx(2)->mark_dirty(offset/8 - 1); + m_gfxdecode->gfx(3)->mark_dirty(offset/8 - 1); + } + + if ( stv_rbg_cache_data.watch_vdp2_vram_writes ) + { + if ( stv_rbg_cache_data.watch_vdp2_vram_writes & STV_VDP2_RBG_ROTATION_PARAMETER_A ) + { + if ( (offset >= stv_rbg_cache_data.map_offset_min[0] && + offset < stv_rbg_cache_data.map_offset_max[0]) || + (offset >= stv_rbg_cache_data.tile_offset_min[0] && + offset < stv_rbg_cache_data.tile_offset_max[0]) ) + { + if ( LOG_VDP2 ) logerror( "RBG Cache: dirtying for RP = 1, write at offset = %06X\n", offset ); + stv_rbg_cache_data.is_cache_dirty |= STV_VDP2_RBG_ROTATION_PARAMETER_A; + stv_rbg_cache_data.watch_vdp2_vram_writes &= ~STV_VDP2_RBG_ROTATION_PARAMETER_A; + } + } + if ( stv_rbg_cache_data.watch_vdp2_vram_writes & STV_VDP2_RBG_ROTATION_PARAMETER_B ) + { + if ( (offset >= stv_rbg_cache_data.map_offset_min[1] && + offset < stv_rbg_cache_data.map_offset_max[1]) || + (offset >= stv_rbg_cache_data.tile_offset_min[1] && + offset < stv_rbg_cache_data.tile_offset_max[1]) ) + { + if ( LOG_VDP2 ) logerror( "RBG Cache: dirtying for RP = 2, write at offset = %06X\n", offset ); + stv_rbg_cache_data.is_cache_dirty |= STV_VDP2_RBG_ROTATION_PARAMETER_B; + stv_rbg_cache_data.watch_vdp2_vram_writes &= ~STV_VDP2_RBG_ROTATION_PARAMETER_B; + } + } + } +} + +READ16_MEMBER ( saturn_state::saturn_vdp2_regs_r ) +{ + switch(offset) + { + case 0x002/2: + { + /* latch h/v signals through HV latch*/ + if(!STV_VDP2_EXLTEN) + { + if(!space.debugger_access()) + { + m_vdp2.h_count = get_hcounter(); + m_vdp2.v_count = get_vcounter(); + /* latch flag */ + m_vdp2.exltfg |= 1; + } + } + + break; + } + case 0x004/2: + { + /*Screen Status Register*/ + /*VBLANK HBLANK ODD PAL */ + m_vdp2_regs[offset] = (m_vdp2.exltfg<<9) | + (m_vdp2.exsyfg<<8) | + (get_vblank() << 3) | + (get_hblank() << 2) | + (get_odd_bit() << 1) | + (m_vdp2.pal << 0); + + /* vblank bit is always 1 if DISP bit is disabled */ + if(!STV_VDP2_DISP) + m_vdp2_regs[offset] |= 1 << 3; + + /* HV latches clears if this register is read */ + if(!space.debugger_access()) + { + m_vdp2.exltfg &= ~1; + m_vdp2.exsyfg &= ~1; + } + break; + } + case 0x006/2: + { + m_vdp2_regs[offset] = (STV_VDP2_VRAMSZ << 15) | + ((0 << 0) & 0xf); // VDP2 version + + /* Games basically r/w the entire VDP2 register area when this is tripped. (example: Silhouette Mirage) + Disable log for the time being. */ + //if(!space.debugger_access()) + // printf("Warning: VDP2 version read\n"); + break; + } + + /* HCNT */ + case 0x008/2: + { + m_vdp2_regs[offset] = (m_vdp2.h_count); + break; + } + + /* VCNT */ + case 0x00a/2: + { + m_vdp2_regs[offset] = (m_vdp2.v_count); + break; + } + + default: + //if(!space.debugger_access()) + // printf("VDP2: read from register %08x %08x\n",offset*4,mem_mask); + break; + } + + return m_vdp2_regs[offset]; +} + +READ32_MEMBER ( saturn_state::saturn_vdp2_cram_r ) +{ + offset &= (0xfff) >> (2); + return m_vdp2_cram[offset]; +} + + + + +WRITE32_MEMBER ( saturn_state::saturn_vdp2_cram_w ) +{ + int r,g,b; + UINT8 cmode0; + + cmode0 = (STV_VDP2_CRMD & 3) == 0; + + offset &= (0xfff) >> (2); + COMBINE_DATA(&m_vdp2_cram[offset]); + + switch( STV_VDP2_CRMD ) + { + /*Mode 2/3*/ + case 2: + case 3: + { + //offset &= (0xfff) >> 2; + + b = ((m_vdp2_cram[offset] & 0x00ff0000) >> 16); + g = ((m_vdp2_cram[offset] & 0x0000ff00) >> 8); + r = ((m_vdp2_cram[offset] & 0x000000ff) >> 0); + m_palette->set_pen_color(offset,rgb_t(r,g,b)); + m_palette->set_pen_color(offset^0x400,rgb_t(r,g,b)); + } + break; + /*Mode 0*/ + case 0: + case 1: + { + offset &= (0xfff) >> (cmode0+2); + + b = ((m_vdp2_cram[offset] & 0x00007c00) >> 10); + g = ((m_vdp2_cram[offset] & 0x000003e0) >> 5); + r = ((m_vdp2_cram[offset] & 0x0000001f) >> 0); + m_palette->set_pen_color((offset*2)+1,pal5bit(r),pal5bit(g),pal5bit(b)); + if(cmode0) + m_palette->set_pen_color(((offset*2)+1)^0x400,pal5bit(r),pal5bit(g),pal5bit(b)); + + b = ((m_vdp2_cram[offset] & 0x7c000000) >> 26); + g = ((m_vdp2_cram[offset] & 0x03e00000) >> 21); + r = ((m_vdp2_cram[offset] & 0x001f0000) >> 16); + m_palette->set_pen_color(offset*2,pal5bit(r),pal5bit(g),pal5bit(b)); + if(cmode0) + m_palette->set_pen_color((offset*2)^0x400,pal5bit(r),pal5bit(g),pal5bit(b)); + } + break; + } +} + +void saturn_state::refresh_palette_data( void ) +{ + int r,g,b; + int c_i; + UINT8 bank; + + switch( STV_VDP2_CRMD ) + { + case 2: + case 3: + { + for(c_i=0;c_i<0x400;c_i++) + { + b = ((m_vdp2_cram[c_i] & 0x00ff0000) >> 16); + g = ((m_vdp2_cram[c_i] & 0x0000ff00) >> 8); + r = ((m_vdp2_cram[c_i] & 0x000000ff) >> 0); + m_palette->set_pen_color(c_i,rgb_t(r,g,b)); + m_palette->set_pen_color(c_i+0x400,rgb_t(r,g,b)); + } + } + break; + case 0: + { + for(bank=0;bank<2;bank++) + { + for(c_i=0;c_i<0x400;c_i++) + { + b = ((m_vdp2_cram[c_i] & 0x00007c00) >> 10); + g = ((m_vdp2_cram[c_i] & 0x000003e0) >> 5); + r = ((m_vdp2_cram[c_i] & 0x0000001f) >> 0); + m_palette->set_pen_color((c_i*2)+1+bank*0x400,pal5bit(r),pal5bit(g),pal5bit(b)); + b = ((m_vdp2_cram[c_i] & 0x7c000000) >> 26); + g = ((m_vdp2_cram[c_i] & 0x03e00000) >> 21); + r = ((m_vdp2_cram[c_i] & 0x001f0000) >> 16); + m_palette->set_pen_color(c_i*2+bank*0x400,pal5bit(r),pal5bit(g),pal5bit(b)); + } + } + } + break; + case 1: + { + for(c_i=0;c_i<0x800;c_i++) + { + b = ((m_vdp2_cram[c_i] & 0x00007c00) >> 10); + g = ((m_vdp2_cram[c_i] & 0x000003e0) >> 5); + r = ((m_vdp2_cram[c_i] & 0x0000001f) >> 0); + m_palette->set_pen_color((c_i*2)+1,pal5bit(r),pal5bit(g),pal5bit(b)); + b = ((m_vdp2_cram[c_i] & 0x7c000000) >> 26); + g = ((m_vdp2_cram[c_i] & 0x03e00000) >> 21); + r = ((m_vdp2_cram[c_i] & 0x001f0000) >> 16); + m_palette->set_pen_color(c_i*2,pal5bit(r),pal5bit(g),pal5bit(b)); + } + } + break; + } +} + +WRITE16_MEMBER ( saturn_state::saturn_vdp2_regs_w ) +{ + COMBINE_DATA(&m_vdp2_regs[offset]); + + if(m_vdp2.old_crmd != STV_VDP2_CRMD) + { + m_vdp2.old_crmd = STV_VDP2_CRMD; + refresh_palette_data(); + } + if(m_vdp2.old_tvmd != STV_VDP2_TVMD) + { + m_vdp2.old_tvmd = STV_VDP2_TVMD; + stv_vdp2_dynamic_res_change(); + } + + if(STV_VDP2_VRAMSZ) + printf("VDP2 sets up 8 Mbit VRAM!\n"); +} + +int saturn_state::get_hblank_duration( void ) +{ + int res; + + res = (STV_VDP2_HRES & 1) ? 455 : 427; + + /* double pump horizontal max res */ + if(STV_VDP2_HRES & 2) + res<<=1; + + return res; +} + +/*some vblank lines measurements (according to Charles MacDonald)*/ +/* TODO: interlace mode "eats" one line, should be 262.5 */ +int saturn_state::get_vblank_duration( void ) +{ + int res; + + res = (m_vdp2.pal) ? 313 : 263; + + /* compensate for interlacing */ + if((STV_VDP2_LSMD & 3) == 3) + res<<=1; + + if(STV_VDP2_HRES & 4) + res = (STV_VDP2_HRES & 1) ? 561 : 525; //Hi-Vision / 31kHz Monitor + + return res; +} + +int saturn_state::get_pixel_clock( void ) +{ + int res,divider; + + res = m_vdp2.dotsel ? MASTER_CLOCK_352 : MASTER_CLOCK_320; + /* TODO: divider is ALWAYS 8, this thing is just to over-compensate for MAME framework faults ... */ + divider = 8; + + if(STV_VDP2_HRES & 2) + divider>>=1; + + if((STV_VDP2_LSMD & 3) == 3) + divider>>=1; + + if(STV_VDP2_HRES & 4) //TODO + divider>>=1; + + return res/divider; +} + +/* TODO: hblank position and hblank firing doesn't really match HW behaviour. */ +UINT8 saturn_state::get_hblank( void ) +{ + const rectangle &visarea = machine().first_screen()->visible_area(); + int cur_h = machine().first_screen()->hpos(); + + if (cur_h > visarea.max_x) //TODO + return 1; + + return 0; +} + +UINT8 saturn_state::get_vblank( void ) +{ + int cur_v,vblank; + cur_v = machine().first_screen()->vpos(); + + vblank = get_vblank_start_position() * get_ystep_count(); + + if (cur_v >= vblank) + return 1; + + return 0; +} + +UINT8 saturn_state::get_odd_bit( void ) +{ + if(STV_VDP2_HRES & 4) //exclusive monitor mode makes this bit to be always 1 + return 1; + + if(STV_VDP2_LSMD == 0) // same for non-interlace mode + return 1; + + return machine().first_screen()->frame_number() & 1; +} + +int saturn_state::get_vblank_start_position( void ) +{ + /* TODO: test says that second setting happens at 241, might need further investigation ... */ + const int d_vres[4] = { 224, 240, 256, 256 }; + int vres_mask; + int vblank_line; + + vres_mask = (m_vdp2.pal << 1)|1; //PAL uses mask 3, NTSC uses mask 1 + vblank_line = d_vres[STV_VDP2_VRES & vres_mask]; + + return vblank_line; +} + +int saturn_state::get_ystep_count( void ) +{ + int max_y = machine().first_screen()->height(); + int y_step; + + y_step = 2; + + if((max_y == 263 && m_vdp2.pal == 0) || (max_y == 313 && m_vdp2.pal == 1)) + y_step = 1; + + return y_step; +} + +/* TODO: these needs to be checked via HW tests! */ +int saturn_state::get_hcounter( void ) +{ + int hcount; + + hcount = machine().first_screen()->hpos(); + + switch(STV_VDP2_HRES & 6) + { + /* Normal */ + case 0: + hcount &= 0x1ff; + hcount <<= 1; + break; + /* Hi-Res */ + case 2: + hcount &= 0x3ff; + break; + /* Exclusive Normal*/ + case 4: + hcount &= 0x1ff; + break; + /* Exclusive Hi-Res */ + case 6: + hcount >>= 1; + hcount &= 0x1ff; + break; + } + + return hcount; +} + +int saturn_state::get_vcounter( void ) +{ + int vcount; + + vcount = machine().first_screen()->vpos(); + + /* Exclusive Monitor */ + if(STV_VDP2_HRES & 4) + return vcount & 0x3ff; + + /* Double Density Interlace */ + if((STV_VDP2_LSMD & 3) == 3) + return (vcount & ~1) | (machine().first_screen()->frame_number() & 1); + + /* docs says << 1, but according to HW tests it's a typo. */ + assert((vcount & 0x1ff) < ARRAY_LENGTH(true_vcount)); + return (true_vcount[vcount & 0x1ff][STV_VDP2_VRES]); // Non-interlace +} + +void saturn_state::stv_vdp2_state_save_postload( void ) +{ + UINT8 *gfxdata = m_vdp2.gfx_decode; + int offset; + UINT32 data; + + for ( offset = 0; offset < 0x100000/4; offset++ ) + { + data = m_vdp2_vram[offset]; + /* put in gfx region for easy decoding */ + gfxdata[offset*4+0] = (data & 0xff000000) >> 24; + gfxdata[offset*4+1] = (data & 0x00ff0000) >> 16; + gfxdata[offset*4+2] = (data & 0x0000ff00) >> 8; + gfxdata[offset*4+3] = (data & 0x000000ff) >> 0; + + m_gfxdecode->gfx(0)->mark_dirty(offset/8); + m_gfxdecode->gfx(1)->mark_dirty(offset/8); + m_gfxdecode->gfx(2)->mark_dirty(offset/8); + m_gfxdecode->gfx(3)->mark_dirty(offset/8); + + /* 8-bit tiles overlap, so this affects the previous one as well */ + if (offset/8 != 0) + { + m_gfxdecode->gfx(2)->mark_dirty(offset/8 - 1); + m_gfxdecode->gfx(3)->mark_dirty(offset/8 - 1); + } + + } + + memset( &stv_rbg_cache_data, 0, sizeof(stv_rbg_cache_data)); + stv_rbg_cache_data.is_cache_dirty = 3; + memset( &stv_vdp2_layer_data_placement, 0, sizeof(stv_vdp2_layer_data_placement)); + + refresh_palette_data(); +} + +void saturn_state::stv_vdp2_exit ( void ) +{ + m_vdp2.roz_bitmap[0].reset(); + m_vdp2.roz_bitmap[1].reset(); +} + +int saturn_state::stv_vdp2_start ( void ) +{ + machine().add_notifier(MACHINE_NOTIFY_EXIT, machine_notify_delegate(FUNC(saturn_state::stv_vdp2_exit), this)); + + m_vdp2_regs = auto_alloc_array_clear(machine(), UINT16, 0x040000/2 ); + m_vdp2_vram = auto_alloc_array_clear(machine(), UINT32, 0x100000/4 ); + m_vdp2_cram = auto_alloc_array_clear(machine(), UINT32, 0x080000/4 ); + m_vdp2.gfx_decode = auto_alloc_array(machine(), UINT8, 0x100000 ); + +// m_gfxdecode->gfx(0)->granularity()=4; +// m_gfxdecode->gfx(1)->granularity()=4; + + memset( &stv_rbg_cache_data, 0, sizeof(stv_rbg_cache_data)); + stv_rbg_cache_data.is_cache_dirty = 3; + memset( &stv_vdp2_layer_data_placement, 0, sizeof(stv_vdp2_layer_data_placement)); + + save_pointer(NAME(m_vdp2_regs), 0x040000/2); + save_pointer(NAME(m_vdp2_vram), 0x100000/4); + save_pointer(NAME(m_vdp2_cram), 0x080000/4); + machine().save().register_postload(save_prepost_delegate(FUNC(saturn_state::stv_vdp2_state_save_postload), this)); + + return 0; +} + +/* maybe we should move this to video/stv.c */ +VIDEO_START_MEMBER(saturn_state,stv_vdp2) +{ + int i; + machine().first_screen()->register_screen_bitmap(m_tmpbitmap); + stv_vdp2_start(); + stv_vdp1_start(); + m_vdpdebug_roz = 0; + m_gfxdecode->gfx(0)->set_source(m_vdp2.gfx_decode); + m_gfxdecode->gfx(1)->set_source(m_vdp2.gfx_decode); + m_gfxdecode->gfx(2)->set_source(m_vdp2.gfx_decode); + m_gfxdecode->gfx(3)->set_source(m_vdp2.gfx_decode); + + /* calc V counter offsets */ + /* 224 mode */ + for(i=0;i<263;i++) + { + true_vcount[i][0] = i; + if(i>0xec) + true_vcount[i][0]+=0xf9; + } + + for(i=0;i<263;i++) + { + true_vcount[i][1] = i; + if(i>0xf5) + true_vcount[i][1]+=0xf9; + } + + /* 256 mode, todo */ + for(i=0;i<263;i++) + { + true_vcount[i][2] = i; + true_vcount[i][3] = i; + } +} + +void saturn_state::stv_vdp2_dynamic_res_change( void ) +{ + const int d_vres[4] = { 224, 240, 256, 256 }; + const int d_hres[4] = { 320, 352, 640, 704 }; + int horz_res,vert_res; + int vres_mask; + + vres_mask = (m_vdp2.pal << 1)|1; //PAL uses mask 3, NTSC uses mask 1 + vert_res = d_vres[STV_VDP2_VRES & vres_mask]; + + if((STV_VDP2_VRES & 3) == 3) + popmessage("Illegal VRES MODE, contact MAMEdev"); + + /*Double-density interlace mode,doubles the vertical res*/ + if((STV_VDP2_LSMD & 3) == 3) { vert_res*=2; } + + horz_res = d_hres[STV_VDP2_HRES & 3]; + /*Exclusive modes,they sets the Vertical Resolution without considering the + VRES register.*/ + if(STV_VDP2_HRES & 4) + vert_res = 480; + + { + int vblank_period,hblank_period; + attoseconds_t refresh; + rectangle visarea(0, horz_res-1, 0, vert_res-1); + + vblank_period = get_vblank_duration(); + hblank_period = get_hblank_duration(); + refresh = HZ_TO_ATTOSECONDS(get_pixel_clock()) * (hblank_period) * vblank_period; + //printf("%d %d %d %d\n",horz_res,vert_res,horz_res+hblank_period,vblank_period); + + machine().first_screen()->configure(hblank_period, vblank_period, visarea, refresh ); + } +// machine().first_screen()->set_visible_area(0*8, horz_res-1,0*8, vert_res-1); +} + +/*This is for calculating the rgb brightness*/ +/*TODO: Optimize this...*/ +void saturn_state::stv_vdp2_fade_effects( void ) +{ + /* + Note:We have to use temporary storages because palette_get_color must use + variables setted with unsigned int8 + */ + INT16 t_r,t_g,t_b; + UINT8 r,g,b; + rgb_t color; + int i; + //popmessage("%04x %04x",STV_VDP2_CLOFEN,STV_VDP2_CLOFSL); + for(i=0;i<2048;i++) + { + /*Fade A*/ + color = m_palette->pen_color(i); + t_r = (STV_VDP2_COAR & 0x100) ? (color.r() - (0x100 - (STV_VDP2_COAR & 0xff))) : ((STV_VDP2_COAR & 0xff) + color.r()); + t_g = (STV_VDP2_COAG & 0x100) ? (color.g() - (0x100 - (STV_VDP2_COAG & 0xff))) : ((STV_VDP2_COAG & 0xff) + color.g()); + t_b = (STV_VDP2_COAB & 0x100) ? (color.b() - (0x100 - (STV_VDP2_COAB & 0xff))) : ((STV_VDP2_COAB & 0xff) + color.b()); + if(t_r < 0) { t_r = 0; } + if(t_r > 0xff) { t_r = 0xff; } + if(t_g < 0) { t_g = 0; } + if(t_g > 0xff) { t_g = 0xff; } + if(t_b < 0) { t_b = 0; } + if(t_b > 0xff) { t_b = 0xff; } + r = t_r; + g = t_g; + b = t_b; + m_palette->set_pen_color(i+(2048*1),rgb_t(r,g,b)); + + /*Fade B*/ + color = m_palette->pen_color(i); + t_r = (STV_VDP2_COBR & 0x100) ? (color.r() - (0xff - (STV_VDP2_COBR & 0xff))) : ((STV_VDP2_COBR & 0xff) + color.r()); + t_g = (STV_VDP2_COBG & 0x100) ? (color.g() - (0xff - (STV_VDP2_COBG & 0xff))) : ((STV_VDP2_COBG & 0xff) + color.g()); + t_b = (STV_VDP2_COBB & 0x100) ? (color.b() - (0xff - (STV_VDP2_COBB & 0xff))) : ((STV_VDP2_COBB & 0xff) + color.b()); + if(t_r < 0) { t_r = 0; } + if(t_r > 0xff) { t_r = 0xff; } + if(t_g < 0) { t_g = 0; } + if(t_g > 0xff) { t_g = 0xff; } + if(t_b < 0) { t_b = 0; } + if(t_b > 0xff) { t_b = 0xff; } + r = t_r; + g = t_g; + b = t_b; + m_palette->set_pen_color(i+(2048*2),rgb_t(r,g,b)); + } + //popmessage("%04x %04x %04x %04x %04x %04x",STV_VDP2_COAR,STV_VDP2_COAG,STV_VDP2_COAB,STV_VDP2_COBR,STV_VDP2_COBG,STV_VDP2_COBB); +} + +void saturn_state::stv_vdp2_get_window0_coordinates(int *s_x, int *e_x, int *s_y, int *e_y) +{ + /*W0*/ + switch(STV_VDP2_LSMD & 3) + { + case 0: + case 1: + case 2: + *s_y = ((STV_VDP2_W0SY & 0x3ff) >> 0); + *e_y = ((STV_VDP2_W0EY & 0x3ff) >> 0); + break; + case 3: + *s_y = ((STV_VDP2_W0SY & 0x7ff) >> 0); + *e_y = ((STV_VDP2_W0EY & 0x7ff) >> 0); + break; + } + switch(STV_VDP2_HRES & 6) + { + /*Normal*/ + case 0: + *s_x = ((STV_VDP2_W0SX & 0x3fe) >> 1); + *e_x = ((STV_VDP2_W0EX & 0x3fe) >> 1); + break; + /*Hi-Res*/ + case 2: + *s_x = ((STV_VDP2_W0SX & 0x3ff) >> 0); + *e_x = ((STV_VDP2_W0EX & 0x3ff) >> 0); + break; + /*Exclusive Normal*/ + case 4: + *s_x = ((STV_VDP2_W0SX & 0x1ff) >> 0); + *e_x = ((STV_VDP2_W0EX & 0x1ff) >> 0); + *s_y = ((STV_VDP2_W0SY & 0x3ff) >> 0); + *e_y = ((STV_VDP2_W0EY & 0x3ff) >> 0); + break; + /*Exclusive Hi-Res*/ + case 6: + *s_x = ((STV_VDP2_W0SX & 0x1ff) << 1); + *e_x = ((STV_VDP2_W0EX & 0x1ff) << 1); + *s_y = ((STV_VDP2_W0SY & 0x3ff) >> 0); + *e_y = ((STV_VDP2_W0EY & 0x3ff) >> 0); + break; + } +} + +void saturn_state::stv_vdp2_get_window1_coordinates(int *s_x, int *e_x, int *s_y, int *e_y) +{ + /*W1*/ + switch(STV_VDP2_LSMD & 3) + { + case 0: + case 1: + case 2: + *s_y = ((STV_VDP2_W1SY & 0x3ff) >> 0); + *e_y = ((STV_VDP2_W1EY & 0x3ff) >> 0); + break; + case 3: + *s_y = ((STV_VDP2_W1SY & 0x7ff) >> 0); + *e_y = ((STV_VDP2_W1EY & 0x7ff) >> 0); + break; + } + switch(STV_VDP2_HRES & 6) + { + /*Normal*/ + case 0: + *s_x = ((STV_VDP2_W1SX & 0x3fe) >> 1); + *e_x = ((STV_VDP2_W1EX & 0x3fe) >> 1); + break; + /*Hi-Res*/ + case 2: + *s_x = ((STV_VDP2_W1SX & 0x3ff) >> 0); + *e_x = ((STV_VDP2_W1EX & 0x3ff) >> 0); + break; + /*Exclusive Normal*/ + case 4: + *s_x = ((STV_VDP2_W1SX & 0x1ff) >> 0); + *e_x = ((STV_VDP2_W1EX & 0x1ff) >> 0); + *s_y = ((STV_VDP2_W1SY & 0x3ff) >> 0); + *e_y = ((STV_VDP2_W1EY & 0x3ff) >> 0); + break; + /*Exclusive Hi-Res*/ + case 6: + *s_x = ((STV_VDP2_W1SX & 0x1ff) << 1); + *e_x = ((STV_VDP2_W1EX & 0x1ff) << 1); + *s_y = ((STV_VDP2_W1SY & 0x3ff) >> 0); + *e_y = ((STV_VDP2_W1EY & 0x3ff) >> 0); + break; + } + +} + +int saturn_state::get_window_pixel(int s_x,int e_x,int s_y,int e_y,int x, int y,UINT8 win_num) +{ + int res; + + res = 1; + if(stv2_current_tilemap.window_control.enabled[win_num]) + { + if(stv2_current_tilemap.window_control.area[win_num]) + res = (y >= s_y && y <= e_y && x >= s_x && x <= e_x); + else + res = (y >= s_y && y <= e_y && x >= s_x && x <= e_x) ^ 1; + } + + return res; +} + +inline int saturn_state::stv_vdp2_window_process(int x,int y) +{ + int s_x=0,e_x=0,s_y=0,e_y=0; + int w0_pix, w1_pix; + + if (stv2_current_tilemap.window_control.enabled[0] == 0 && + stv2_current_tilemap.window_control.enabled[1] == 0) + return 1; + + stv_vdp2_get_window0_coordinates(&s_x, &e_x, &s_y, &e_y); + w0_pix = get_window_pixel(s_x,e_x,s_y,e_y,x,y,0); + + stv_vdp2_get_window1_coordinates(&s_x, &e_x, &s_y, &e_y); + w1_pix = get_window_pixel(s_x,e_x,s_y,e_y,x,y,1); + + return stv2_current_tilemap.window_control.logic & 1 ? (w0_pix | w1_pix) : (w0_pix & w1_pix); +} + +/* TODO: remove this crap. */ +int saturn_state::stv_vdp2_apply_window_on_layer(rectangle &cliprect) +{ + int s_x=0,e_x=0,s_y=0,e_y=0; + + if ( stv2_current_tilemap.window_control.enabled[0] && (!stv2_current_tilemap.window_control.area[0])) + { + /* w0, transparent outside supported */ + stv_vdp2_get_window0_coordinates(&s_x, &e_x, &s_y, &e_y); + + if ( s_x > cliprect.min_x ) cliprect.min_x = s_x; + if ( e_x < cliprect.max_x ) cliprect.max_x = e_x; + if ( s_y > cliprect.min_y ) cliprect.min_y = s_y; + if ( e_y < cliprect.max_y ) cliprect.max_y = e_y; + + return 1; + } + else if ( stv2_current_tilemap.window_control.enabled[1] && (!stv2_current_tilemap.window_control.area[1]) ) + { + /* w1, transparent outside supported */ + stv_vdp2_get_window1_coordinates(&s_x, &e_x, &s_y, &e_y); + + if ( s_x > cliprect.min_x ) cliprect.min_x = s_x; + if ( e_x < cliprect.max_x ) cliprect.max_x = e_x; + if ( s_y > cliprect.min_y ) cliprect.min_y = s_y; + if ( e_y < cliprect.max_y ) cliprect.max_y = e_y; + + return 1; + } + else + { + return 0; + } +} + +void saturn_state::draw_sprites(bitmap_rgb32 &bitmap, const rectangle &cliprect, UINT8 pri) +{ + int x,y,r,g,b; + int i; + UINT16 pix; + UINT16 *framebuffer_line; + UINT32 *bitmap_line, *bitmap_line2 = NULL; + UINT8 interlace_framebuffer; + UINT8 double_x; + static const UINT16 sprite_colormask_table[] = { + 0x07ff, 0x07ff, 0x07ff, 0x07ff, 0x03ff, 0x07ff, 0x03ff, 0x01ff, + 0x007f, 0x003f, 0x003f, 0x003f, 0x00ff, 0x00ff, 0x00ff, 0x00ff + }; + static const UINT16 priority_shift_table[] = { 14, 13, 14, 13, 13, 12, 12, 12, 7, 7, 6, 0, 7, 7, 6, 0 }; + static const UINT16 priority_mask_table[] = { 3, 7, 1, 3, 3, 7, 7, 7, 1, 1, 3, 0, 1, 1, 3, 0 }; + static const UINT16 ccrr_shift_table[] = { 11, 11, 11, 11, 10, 11, 10, 9, 0, 6, 0, 6, 0, 6, 0, 6 }; + static const UINT16 ccrr_mask_table[] = { 7, 3, 7, 3, 7, 1, 3, 7, 0, 1, 0, 3, 0, 1, 0, 3 }; + static const UINT16 shadow_mask_table[] = { 0, 0, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0, 0, 0, 0, 0, 0, 0, 0 }; + UINT16 alpha_enabled; + + int sprite_type; + int sprite_colormask; + int color_offset_pal; + int sprite_shadow; + UINT16 sprite_priority_shift, sprite_priority_mask, sprite_ccrr_shift, sprite_ccrr_mask; + UINT8 priority; + UINT8 ccr = 0; + UINT8 sprite_priorities[8]; + UINT8 sprite_ccr[8]; + int sprite_color_mode = STV_VDP2_SPCLMD; + + if ( (stv_sprite_priorities_usage_valid == 1) && (stv_sprite_priorities_used[pri] == 0) ) + return; + + sprite_priorities[0] = STV_VDP2_S0PRIN; + sprite_priorities[1] = STV_VDP2_S1PRIN; + sprite_priorities[2] = STV_VDP2_S2PRIN; + sprite_priorities[3] = STV_VDP2_S3PRIN; + sprite_priorities[4] = STV_VDP2_S4PRIN; + sprite_priorities[5] = STV_VDP2_S5PRIN; + sprite_priorities[6] = STV_VDP2_S6PRIN; + sprite_priorities[7] = STV_VDP2_S7PRIN; + + sprite_ccr[0] = STV_VDP2_S0CCRT; + sprite_ccr[1] = STV_VDP2_S1CCRT; + sprite_ccr[2] = STV_VDP2_S2CCRT; + sprite_ccr[3] = STV_VDP2_S3CCRT; + sprite_ccr[4] = STV_VDP2_S4CCRT; + sprite_ccr[5] = STV_VDP2_S5CCRT; + sprite_ccr[6] = STV_VDP2_S6CCRT; + sprite_ccr[7] = STV_VDP2_S7CCRT; + + sprite_type = STV_VDP2_SPTYPE; + sprite_colormask = sprite_colormask_table[sprite_type]; + sprite_priority_shift = priority_shift_table[sprite_type]; + sprite_priority_mask = priority_mask_table[sprite_type]; + sprite_ccrr_shift = ccrr_shift_table[sprite_type]; + sprite_ccrr_mask = ccrr_mask_table[sprite_type]; + sprite_shadow = shadow_mask_table[sprite_type]; + + for ( i = 0; i < (sprite_priority_mask+1); i++ ) if ( sprite_priorities[i] == pri ) break; + if ( i == (sprite_priority_mask+1) ) return; + + /* color offset (RGB brightness) */ + color_offset_pal = 0; + if ( STV_VDP2_SPCOEN ) + { + if ( STV_VDP2_SPCOSL == 0 ) + { color_offset_pal = 2048; } + else + { color_offset_pal = 2048*2; } + } + + /* color calculation (alpha blending)*/ + if ( STV_VDP2_SPCCEN ) + { + alpha_enabled = 0; + switch( STV_VDP2_SPCCCS ) + { + case 0x0: if ( pri <= STV_VDP2_SPCCN ) alpha_enabled = 1; break; + case 0x1: if ( pri == STV_VDP2_SPCCN ) alpha_enabled = 1; break; + case 0x2: if ( pri >= STV_VDP2_SPCCN ) alpha_enabled = 1; break; + case 0x3: alpha_enabled = 2; sprite_shadow = 0; break; + } + } + else + { + alpha_enabled = 0; + } + + /* framebuffer interlace */ + if ( (STV_VDP2_LSMD == 3) && m_vdp1.framebuffer_double_interlace == 0 ) + interlace_framebuffer = 1; + else + interlace_framebuffer = 0; + + /*Guess:Some games needs that the horizontal sprite size to be doubled + (TODO: understand the proper settings,it might not work like this)*/ + if(STV_VDP1_TVM == 0 && STV_VDP2_HRES & 2) // astrass & findlove + double_x = 1; + else + double_x = 0; + + /* window control */ + stv2_current_tilemap.window_control.logic = STV_VDP2_SPLOG; + stv2_current_tilemap.window_control.enabled[0] = STV_VDP2_SPW0E; + stv2_current_tilemap.window_control.enabled[1] = STV_VDP2_SPW1E; +// stv2_current_tilemap.window_control.? = STV_VDP2_SPSWE; + stv2_current_tilemap.window_control.area[0] = STV_VDP2_SPW0A; + stv2_current_tilemap.window_control.area[1] = STV_VDP2_SPW1A; +// stv2_current_tilemap.window_control.? = STV_VDP2_SPSWA; + +// stv_vdp2_apply_window_on_layer(mycliprect); + + if (interlace_framebuffer == 0 && double_x == 0 ) + { + if ( alpha_enabled == 0 ) + { + for ( y = cliprect.min_y; y <= cliprect.max_y; y++ ) + { + if ( stv_sprite_priorities_usage_valid ) + if (stv_sprite_priorities_in_fb_line[y][pri] == 0) + continue; + + framebuffer_line = m_vdp1.framebuffer_display_lines[y]; + bitmap_line = &bitmap.pix32(y); + + for ( x = cliprect.min_x; x <= cliprect.max_x; x++ ) + { + if(!stv_vdp2_window_process(x,y)) + continue; + + pix = framebuffer_line[x]; + if ( (pix & 0x8000) && sprite_color_mode) + { + if ( sprite_priorities[0] != pri ) + { + stv_sprite_priorities_used[sprite_priorities[0]] = 1; + stv_sprite_priorities_in_fb_line[y][sprite_priorities[0]] = 1; + continue; + }; + + if(STV_VDP2_SPWINEN && pix == 0x8000) /* Pukunpa */ + continue; + + b = pal5bit((pix & 0x7c00) >> 10); + g = pal5bit((pix & 0x03e0) >> 5); + r = pal5bit( pix & 0x001f); + if ( color_offset_pal ) + { + stv_vdp2_compute_color_offset( &r, &g, &b, STV_VDP2_SPCOSL ); + } + + bitmap_line[x] = rgb_t(r, g, b); + } + else + { + priority = sprite_priorities[(pix >> sprite_priority_shift) & sprite_priority_mask]; + if ( priority != pri ) + { + stv_sprite_priorities_used[priority] = 1; + stv_sprite_priorities_in_fb_line[y][priority] = 1; + continue; + }; + + { + pix &= sprite_colormask; + if ( pix == (sprite_colormask - 1) ) + { + /*shadow - in reality, we should check from what layer pixel beneath comes...*/ + if ( STV_VDP2_SDCTL & 0x3f ) + { + rgb_t p = bitmap_line[x]; + bitmap_line[x] = rgb_t(p.r() >> 1, p.g() >> 1, p.b() >> 1); + } + /* note that when shadows are disabled, "shadow" palette entries are not drawn */ + } + else if ( pix ) + { + pix += (STV_VDP2_SPCAOS << 8); + pix &= 0x7ff; + pix += color_offset_pal; + bitmap_line[x] = m_palette->pen( pix ); + } + } + + /* TODO: I don't think this one makes much logic ... (1) */ + if ( pix & sprite_shadow ) + { + if ( pix & ~sprite_shadow ) + { + rgb_t p = bitmap_line[x]; + bitmap_line[x] = rgb_t(p.r() >> 1, p.g() >> 1, p.b() >> 1); + } + } + } + } + } + } + else //alpha_enabled == 1 + { + for ( y = cliprect.min_y; y <= cliprect.max_y; y++ ) + { + if ( stv_sprite_priorities_usage_valid ) + if (stv_sprite_priorities_in_fb_line[y][pri] == 0) + continue; + + framebuffer_line = m_vdp1.framebuffer_display_lines[y]; + bitmap_line = &bitmap.pix32(y); + + for ( x = cliprect.min_x; x <= cliprect.max_x; x++ ) + { + if(!stv_vdp2_window_process(x,y)) + continue; + + pix = framebuffer_line[x]; + if ( (pix & 0x8000) && sprite_color_mode) + { + if ( sprite_priorities[0] != pri ) + { + stv_sprite_priorities_used[sprite_priorities[0]] = 1; + stv_sprite_priorities_in_fb_line[y][sprite_priorities[0]] = 1; + continue; + }; + + b = pal5bit((pix & 0x7c00) >> 10); + g = pal5bit((pix & 0x03e0) >> 5); + r = pal5bit( pix & 0x001f); + if ( color_offset_pal ) + { + stv_vdp2_compute_color_offset( &r, &g, &b, STV_VDP2_SPCOSL ); + } + ccr = sprite_ccr[0]; + if ( STV_VDP2_CCMD ) + { + bitmap_line[x] = stv_add_blend( bitmap_line[x], rgb_t(r, g, b)); + } + else + { + bitmap_line[x] = alpha_blend_r32( bitmap_line[x], rgb_t(r, g ,b), ((UINT16)(0x1f-ccr)*0xff)/0x1f); + } + } + else + { + priority = sprite_priorities[(pix >> sprite_priority_shift) & sprite_priority_mask]; + if ( priority != pri ) + { + stv_sprite_priorities_used[priority] = 1; + stv_sprite_priorities_in_fb_line[y][priority] = 1; + continue; + }; + + ccr = sprite_ccr[ (pix >> sprite_ccrr_shift) & sprite_ccrr_mask ]; + if ( alpha_enabled == 2 ) + { + if ( ( pix & 0x8000 ) == 0 ) + { + ccr = 0; + } + } + + + { + pix &= sprite_colormask; + if ( pix == (sprite_colormask - 1) ) + { + /*shadow - in reality, we should check from what layer pixel beneath comes...*/ + if ( STV_VDP2_SDCTL & 0x3f ) + { + rgb_t p = bitmap_line[x]; + bitmap_line[x] = rgb_t(p.r() >> 1, p.g() >> 1, p.b() >> 1); + } + /* note that when shadows are disabled, "shadow" palette entries are not drawn */ + } else if ( pix ) + { + pix += (STV_VDP2_SPCAOS << 8); + pix &= 0x7ff; + pix += color_offset_pal; + if ( ccr > 0 ) + { + if ( STV_VDP2_CCMD ) + { + bitmap_line[x] = stv_add_blend( bitmap_line[x], m_palette->pen(pix) ); + } + else + { + bitmap_line[x] = alpha_blend_r32( bitmap_line[x], m_palette->pen(pix), ((UINT16)(0x1f-ccr)*0xff)/0x1f ); + } + } + else + bitmap_line[x] = m_palette->pen(pix); + } + } + + /* TODO: (1) */ + if ( pix & sprite_shadow ) + { + if ( pix & ~sprite_shadow ) + { + rgb_t p = bitmap_line[x]; + bitmap_line[x] = rgb_t(p.r() >> 1, p.g() >> 1, p.b() >> 1); + } + } + } + } + } + } + } + else + { + for ( y = cliprect.min_y; y <= cliprect.max_y / (interlace_framebuffer+1); y++ ) + { + if ( stv_sprite_priorities_usage_valid ) + if (stv_sprite_priorities_in_fb_line[y][pri] == 0) + continue; + + framebuffer_line = m_vdp1.framebuffer_display_lines[y]; + if ( interlace_framebuffer == 0 ) + { + bitmap_line = &bitmap.pix32(y); + } + else + { + bitmap_line = &bitmap.pix32(2*y); + bitmap_line2 = &bitmap.pix32(2*y + 1); + } + + for ( x = cliprect.min_x; x <= cliprect.max_x /(double_x+1) ; x++ ) + { + if(!stv_vdp2_window_process(x,y)) + continue; + + pix = framebuffer_line[x]; + if ( (pix & 0x8000) && sprite_color_mode) + { + if ( sprite_priorities[0] != pri ) + { + stv_sprite_priorities_used[sprite_priorities[0]] = 1; + stv_sprite_priorities_in_fb_line[y][sprite_priorities[0]] = 1; + continue; + }; + + b = pal5bit((pix & 0x7c00) >> 10); + g = pal5bit((pix & 0x03e0) >> 5); + r = pal5bit( pix & 0x001f); + if ( color_offset_pal ) + { + stv_vdp2_compute_color_offset( &r, &g, &b, STV_VDP2_SPCOSL ); + } + if ( alpha_enabled == 0 ) + { + if(double_x) + { + bitmap_line[x*2] = rgb_t(r, g, b); + if ( interlace_framebuffer == 1 ) bitmap_line2[x*2] = rgb_t(r, g, b); + bitmap_line[x*2+1] = rgb_t(r, g, b); + if ( interlace_framebuffer == 1 ) bitmap_line2[x*2+1] = rgb_t(r, g, b); + } + else + { + bitmap_line[x] = rgb_t(r, g, b); + if ( interlace_framebuffer == 1 ) bitmap_line2[x] = rgb_t(r, g, b); + } + } + else // alpha_blend == 1 + { + ccr = sprite_ccr[0]; + + if ( STV_VDP2_CCMD ) + { + if(double_x) + { + bitmap_line[x*2] = stv_add_blend( bitmap_line[x*2], rgb_t(r, g, b) ); + if ( interlace_framebuffer == 1 ) bitmap_line2[x*2] = stv_add_blend( bitmap_line2[x*2], rgb_t(r, g, b) ); + bitmap_line[x*2+1] = stv_add_blend( bitmap_line[x*2+1], rgb_t(r, g, b) ); + if ( interlace_framebuffer == 1 ) bitmap_line2[x*2+1] = stv_add_blend( bitmap_line2[x*2+1], rgb_t(r, g, b) ); + } + else + { + bitmap_line[x] = stv_add_blend( bitmap_line[x], rgb_t(r, g, b) ); + if ( interlace_framebuffer == 1 ) bitmap_line2[x] = stv_add_blend( bitmap_line2[x], rgb_t(r, g, b) ); + } + } + else + { + if(double_x) + { + bitmap_line[x*2] = alpha_blend_r32( bitmap_line[x*2], rgb_t(r, g, b), ((UINT16)(0x1f-ccr)*0xff)/0x1f ); + if ( interlace_framebuffer == 1 ) bitmap_line2[x*2] = alpha_blend_r32( bitmap_line2[x*2], rgb_t(r, g, b), ((UINT16)(0x1f-ccr)*0xff)/0x1f ); + bitmap_line[x*2+1] = alpha_blend_r32( bitmap_line[x*2+1], rgb_t(r, g, b), ((UINT16)(0x1f-ccr)*0xff)/0x1f ); + if ( interlace_framebuffer == 1 ) bitmap_line2[x*2+1] = alpha_blend_r32( bitmap_line2[x*2+1], rgb_t(r, g, b), ((UINT16)(0x1f-ccr)*0xff)/0x1f); + } + else + { + bitmap_line[x] = alpha_blend_r32( bitmap_line[x], rgb_t(r, g, b), ((UINT16)(0x1f-ccr)*0xff)/0x1f); + if ( interlace_framebuffer == 1 ) bitmap_line2[x] = alpha_blend_r32( bitmap_line2[x], rgb_t(r, g, b), ((UINT16)(0x1f-ccr)*0xff)/0x1f); + } + } + } + } + else + { + priority = sprite_priorities[(pix >> sprite_priority_shift) & sprite_priority_mask]; + if ( priority != pri ) + { + stv_sprite_priorities_used[priority] = 1; + stv_sprite_priorities_in_fb_line[y][priority] = 1; + continue; + }; + + if ( alpha_enabled ) + ccr = sprite_ccr[ (pix >> sprite_ccrr_shift) & sprite_ccrr_mask ]; + + if ( alpha_enabled == 2 ) + { + if ( ( pix & 0x8000 ) == 0 ) + { + ccr = 0; + } + } + + { + pix &= sprite_colormask; + if ( pix == (sprite_colormask - 1) ) + { + /*shadow - in reality, we should check from what layer pixel beneath comes...*/ + if ( STV_VDP2_SDCTL & 0x3f ) + { + rgb_t p = bitmap_line[x]; + if(double_x) + { + p = bitmap_line[x*2]; + bitmap_line[x*2] = rgb_t(p.r() >> 1, p.g() >> 1, p.b() >> 1); + p = bitmap_line[x*2+1]; + bitmap_line[x*2+1] = rgb_t(p.r() >> 1, p.g() >> 1, p.b() >> 1); + } + else + bitmap_line[x] = rgb_t(p.r() >> 1, p.g() >> 1, p.b() >> 1); + } + /* note that when shadows are disabled, "shadow" palette entries are not drawn */ + } else if ( pix ) + { + pix += (STV_VDP2_SPCAOS << 8); + pix &= 0x7ff; + pix += color_offset_pal; + if ( alpha_enabled == 0 ) + { + if(double_x) + { + bitmap_line[x*2] = m_palette->pen( pix ); + if ( interlace_framebuffer == 1 ) bitmap_line2[x*2] = m_palette->pen( pix ); + bitmap_line[x*2+1] = m_palette->pen( pix ); + if ( interlace_framebuffer == 1 ) bitmap_line2[x*2+1] = m_palette->pen( pix ); + } + else + { + bitmap_line[x] = m_palette->pen( pix ); + if ( interlace_framebuffer == 1 ) bitmap_line2[x] = m_palette->pen( pix ); + } + } + else // alpha_blend == 1 + { + if ( STV_VDP2_CCMD ) + { + if(double_x) + { + bitmap_line[x*2] = stv_add_blend( bitmap_line[x*2], m_palette->pen(pix) ); + if ( interlace_framebuffer == 1 ) bitmap_line2[x*2] = stv_add_blend( bitmap_line2[x], m_palette->pen(pix) ); + bitmap_line[x*2+1] = stv_add_blend( bitmap_line[x*2+1], m_palette->pen(pix) ); + if ( interlace_framebuffer == 1 ) bitmap_line2[x*2+1] = stv_add_blend( bitmap_line2[x], m_palette->pen(pix) ); + } + else + { + bitmap_line[x] = stv_add_blend( bitmap_line[x], m_palette->pen(pix) ); + if ( interlace_framebuffer == 1 ) bitmap_line2[x] = stv_add_blend( bitmap_line2[x], m_palette->pen(pix) ); + } + } + else + { + if(double_x) + { + bitmap_line[x*2] = alpha_blend_r32( bitmap_line[x*2], m_palette->pen(pix), ((UINT16)(0x1f-ccr)*0xff)/0x1f ); + if ( interlace_framebuffer == 1 ) bitmap_line2[x*2] = alpha_blend_r32( bitmap_line2[x], m_palette->pen(pix), ((UINT16)(0x1f-ccr)*0xff)/0x1f ); + bitmap_line[x*2+1] = alpha_blend_r32( bitmap_line[x*2+1], m_palette->pen(pix), ((UINT16)(0x1f-ccr)*0xff)/0x1f ); + if ( interlace_framebuffer == 1 ) bitmap_line2[x*2+1] = alpha_blend_r32( bitmap_line2[x], m_palette->pen(pix), ((UINT16)(0x1f-ccr)*0xff)/0x1f ); + } + else + { + bitmap_line[x] = alpha_blend_r32( bitmap_line[x], m_palette->pen(pix), ((UINT16)(0x1f-ccr)*0xff)/0x1f ); + if ( interlace_framebuffer == 1 ) bitmap_line2[x] = alpha_blend_r32( bitmap_line2[x], m_palette->pen(pix), ((UINT16)(0x1f-ccr)*0xff)/0x1f ); + } + } + } + } + } + + /* TODO: (1) */ + if ( pix & sprite_shadow ) + { + if ( pix & ~sprite_shadow ) + { + rgb_t p = bitmap_line[x]; + if(double_x) + { + p = bitmap_line[x*2]; + bitmap_line[x*2] = rgb_t(p.r() >> 1, p.g() >> 1, p.b() >> 1); + p = bitmap_line[x*2+1]; + bitmap_line[x*2+1] = rgb_t(p.r() >> 1, p.g() >> 1, p.b() >> 1); + } + else + bitmap_line[x] = rgb_t(p.r() >> 1, p.g() >> 1, p.b() >> 1); + } + } + } + } + } + } + + stv_sprite_priorities_usage_valid = 1; +} + +UINT32 saturn_state::screen_update_stv_vdp2(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + stv_vdp2_fade_effects(); + + stv_vdp2_draw_back(m_tmpbitmap,cliprect); + + if(STV_VDP2_DISP) + { + UINT8 pri; + + stv_sprite_priorities_usage_valid = 0; + memset(stv_sprite_priorities_used, 0, sizeof(stv_sprite_priorities_used)); + memset(stv_sprite_priorities_in_fb_line, 0, sizeof(stv_sprite_priorities_in_fb_line)); + + /*If a plane has a priority value of zero it isn't shown at all.*/ + for(pri=1;pri<8;pri++) + { + if(pri==STV_VDP2_N3PRIN) { stv_vdp2_draw_NBG3(m_tmpbitmap,cliprect); } + if(pri==STV_VDP2_N2PRIN) { stv_vdp2_draw_NBG2(m_tmpbitmap,cliprect); } + if(pri==STV_VDP2_N1PRIN) { stv_vdp2_draw_NBG1(m_tmpbitmap,cliprect); } + if(pri==STV_VDP2_N0PRIN) { stv_vdp2_draw_NBG0(m_tmpbitmap,cliprect); } + if(pri==STV_VDP2_R0PRIN) { stv_vdp2_draw_RBG0(m_tmpbitmap,cliprect); } + { draw_sprites(m_tmpbitmap,cliprect,pri); } + } + } + + copybitmap(bitmap, m_tmpbitmap, 0, 0, 0, 0, cliprect); + + #if 0 + /* Do NOT remove me, used to test video code performance. */ + if(machine().input().code_pressed(KEYCODE_Q)) + { + popmessage("Halt CPUs"); + m_maincpu->set_input_line(INPUT_LINE_HALT, ASSERT_LINE); + m_slave->set_input_line(INPUT_LINE_HALT, ASSERT_LINE); + m_audiocpu->set_input_line(INPUT_LINE_HALT, ASSERT_LINE); + } + #endif + return 0; +} diff --git a/src/devices/video/t6a04.c b/src/devices/video/t6a04.c new file mode 100644 index 00000000000..89bf9cf716a --- /dev/null +++ b/src/devices/video/t6a04.c @@ -0,0 +1,242 @@ +// license:BSD-3-Clause +// copyright-holders:Sandro Ronco +/*************************************************************************** + + Toshiba T6A04 LCD controller + + TODO: + - busy flag + - contrast + - slave mode + +***************************************************************************/ + +#include "emu.h" +#include "video/t6a04.h" + +// devices +const device_type T6A04 = &device_creator; + +//------------------------------------------------- +// device_validity_check - perform validity checks +// on this device +//------------------------------------------------- + +void t6a04_device::device_validity_check(validity_checker &valid) const +{ + if (m_height == 0 || m_width == 0) + osd_printf_error("Configured with invalid parameter\n"); +} + +//************************************************************************** +// live device +//************************************************************************** + +//------------------------------------------------- +// t6a04_device - constructor +//------------------------------------------------- + +t6a04_device::t6a04_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, T6A04, "T6A04", tag, owner, clock, "t6a04", __FILE__), + m_height(0), + m_width(0) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void t6a04_device::device_start() +{ + save_item(NAME(m_busy_flag)); + save_item(NAME(m_display_on)); + save_item(NAME(m_contrast)); + save_item(NAME(m_xpos)); + save_item(NAME(m_ypos)); + save_item(NAME(m_zpos)); + save_item(NAME(m_active_counter)); + save_item(NAME(m_direction)); + save_item(NAME(m_word_len)); + save_item(NAME(m_opa1)); + save_item(NAME(m_opa2)); + save_item(NAME(m_output_reg)); + save_item(NAME(m_lcd_ram)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void t6a04_device::device_reset() +{ + //values taken from the datasheet + memset(m_lcd_ram, 0x00, sizeof(m_lcd_ram)); + m_busy_flag = 0; + m_display_on = 0; + m_contrast = 0; + m_xpos = 0; + m_ypos = 0; + m_zpos = 0; + m_direction = 1; + m_active_counter = 1; + m_word_len = 1; //8bit mode + m_opa1 = 0; + m_opa2 = 0; + m_output_reg = 0; +} + + +//************************************************************************** +// device interface +//************************************************************************** + +UINT32 t6a04_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) +{ + UINT8 ypages = m_width>>3; + UINT8 last_line = m_zpos + m_height; + + if (m_display_on) + { + for (int y=0; y=0; b--) + { + bitmap.pix16(x&0x3f, y*8+b) = data & 1; + data>>=1; + } + } + } + else + { + bitmap.fill(0, cliprect); + } + + return 0; +} + +WRITE8_MEMBER(t6a04_device::control_write) +{ + if ((data & 0xc0) == 0xc0) // SCE (set contrast) + { + m_contrast = data&0x3f; + } + else if ((data & 0xc0) == 0x80) // SXE (set x address) + { + m_xpos = data&0x3f; + } + else if ((data & 0xc0) == 0x40) // SZE (set z address) + { + m_zpos = data&0x3f; + } + else if ((data & 0xe0) == 0x20) // SYE (set y address) + { + m_ypos = data&0x1f; + } + else if ((data & 0xf8) == 0x18) // CHE (test mode) + { + //??? + } + else if ((data & 0xf8) == 0x10) // OPA1 (op-amp control 1) + { + m_opa1 = data & 3; + } + else if ((data & 0xf8) == 0x08) // OPA2 (op-amp control 2) + { + m_opa2 = data & 3; + } + else if ((data & 0xfc) == 0x04) // UDE (up/down mode) + { + m_active_counter = (data & 0x02) >> 1; + m_direction = (data & 0x01) ? +1 : -1; + } + else if ((data & 0xfe) == 0x02) // DPE (display on/off) + { + m_display_on = data & 1; + } + else if ((data & 0xfe) == 0x00) // 86E (word length) + { + m_word_len = data & 1; + } +} + +READ8_MEMBER(t6a04_device::control_read) +{ + /* + status read + x--- ---- busy + -x-- ---- 8/6 mode + --x- ---- display on/off + ---x ---- reset state + ---- xx-- unused (always 0) + ---- --x- x/y counter + ---- ---x up/down mode + */ + + return (m_busy_flag<<7) | (m_word_len<<6) | (m_display_on<<5) | (m_active_counter<<1) | (m_direction == 1 ? 1 : 0); +} + +WRITE8_MEMBER(t6a04_device::data_write) +{ + if (m_word_len) + { + //8bit mode + m_lcd_ram[m_xpos*15 + m_ypos] = data; + } + else + { + //6bit mode + data = data<<0x02; + UINT8 start_bit = m_ypos * 6; + UINT8 pos_bit = start_bit & 0x07; + UINT8 *ti82_video = &m_lcd_ram[(m_xpos*15)+(start_bit>>3)]; + + ti82_video[0] = (ti82_video[0] & ~(0xFC>>pos_bit)) | (data>>pos_bit); + if(pos_bit>0x02) + ti82_video[1] = (ti82_video[1] & ~(0xFC<<(8-pos_bit))) | (data<<(8-pos_bit)); + } + + if (m_active_counter) + m_ypos = (m_ypos + m_direction) & 0x1f; + else + m_xpos = (m_xpos + m_direction) & 0x3f; + +} + +READ8_MEMBER(t6a04_device::data_read) +{ + UINT8 data = m_output_reg; + UINT8 output_reg; + + if (m_word_len) + { + //8bit mode + output_reg = m_lcd_ram[m_xpos*15 + m_ypos]; + } + else + { + //6bit mode + UINT8 start_bit = m_ypos * 6; + UINT8 pos_bit = start_bit & 7; + UINT8 *ti82_video = &m_lcd_ram[(m_xpos*15)+(start_bit>>3)]; + + output_reg = ((((*ti82_video)<<8)+ti82_video[1])>>(10-pos_bit)); + } + + if (!space.debugger_access()) + { + m_output_reg = output_reg; + + if (m_active_counter) + m_ypos = (m_ypos + m_direction) & 0x1f; + else + m_xpos = (m_xpos + m_direction) & 0x3f; + } + + return data; +} diff --git a/src/devices/video/t6a04.h b/src/devices/video/t6a04.h new file mode 100644 index 00000000000..2fe5b68bd33 --- /dev/null +++ b/src/devices/video/t6a04.h @@ -0,0 +1,72 @@ +// license:BSD-3-Clause +// copyright-holders:Sandro Ronco +/*************************************************************************** + + Toshiba T6A04 LCD controller + +***************************************************************************/ + +#pragma once + +#ifndef __T6A04_H__ +#define __T6A04_H__ + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> t6a04_device + +class t6a04_device : public device_t +{ +public: + // construction/destruction + t6a04_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + static void set_size(device_t &device, int w, int h) + { + t6a04_device &dev = downcast(device); + dev.m_width = w; + dev.m_height = h; + } + + // device interface + DECLARE_WRITE8_MEMBER(control_write); + DECLARE_READ8_MEMBER(control_read); + DECLARE_WRITE8_MEMBER(data_write); + DECLARE_READ8_MEMBER(data_read); + + UINT32 screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_validity_check(validity_checker &valid) const; + +private: + UINT8 m_busy_flag; + UINT8 m_lcd_ram[960]; //7680 bit (64*120) + UINT8 m_display_on; + UINT8 m_contrast; + UINT8 m_xpos; + UINT8 m_ypos; + UINT8 m_zpos; + INT8 m_direction; + UINT8 m_active_counter; + UINT8 m_word_len; + UINT8 m_opa1; + UINT8 m_opa2; + UINT8 m_output_reg; + + UINT8 m_height; // number of lines + UINT8 m_width; // pixels for line +}; + +// device type definition +extern const device_type T6A04; + +#define MCFG_T6A04_SIZE(_width, _height) \ + t6a04_device::set_size(*device, _width, _height); + +#endif diff --git a/src/devices/video/tea1002.c b/src/devices/video/tea1002.c new file mode 100644 index 00000000000..ba518e6a6ac --- /dev/null +++ b/src/devices/video/tea1002.c @@ -0,0 +1,85 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best +/*************************************************************************** + + TEA1002 + + PAL colour encoder and video summer + +***************************************************************************/ + +#include "tea1002.h" + + +//************************************************************************** +// CONSTANTS +//************************************************************************** + +const float tea1002_device::m_luminance[] = +{ + 0, 22.5, 44, 66.5, 8.5, 31, 52.5, 100, // INV = 0 + 75, 52.5, 31, 8.5, 66.5, 44, 22.5, 0 // INV = 1 +}; + +const int tea1002_device::m_phase[] = +{ + 0, 103, 241, 167, 347, 61, 283, 0, // INV = 0 + 0, 283, 61, 347, 167, 241, 103, 0 // INV = 1 +}; + +const int tea1002_device::m_amplitute[] = +{ + 0, 48, 44, 33, 33, 44, 48, 0, // INV = 0 + 0, 24, 22, 17, 17, 22, 24, 0 // INV = 1 +}; + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type TEA1002 = &device_creator; + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// paula_device - constructor +//------------------------------------------------- + +tea1002_device::tea1002_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, TEA1002, "TEA1002 PAL colour encoder", tag, owner, clock, "tea1002", __FILE__) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void tea1002_device::device_start() +{ +} + + +//************************************************************************** +// IMPLEMENTATION +//************************************************************************** + +// this could be done in device_start() and cached, but it's only +// accessed once at PALETTE_INIT anyway +rgb_t tea1002_device::color(int index) +{ + // calculate yuv + double y = m_luminance[index] / 100; + double u = cos((m_phase[index] + m_tint) * M_PI / 180) * m_amplitute[index] / 100; + double v = sin((m_phase[index] + m_tint) * M_PI / 180) * m_amplitute[index] / 100; + + // and convert to rgb + double r = y + v * 1.14; + double g = y - u * 0.395 - v * 0.581; + double b = y + u * 2.032; + + return rgb_t(rgb_t::clamp(r * 255), rgb_t::clamp(g * 255), rgb_t::clamp(b * 255)); +} diff --git a/src/devices/video/tea1002.h b/src/devices/video/tea1002.h new file mode 100644 index 00000000000..ee01a2178b2 --- /dev/null +++ b/src/devices/video/tea1002.h @@ -0,0 +1,66 @@ +// license:GPL-2.0+ +// copyright-holders:Dirk Best +/*************************************************************************** + + TEA1002 + + PAL colour encoder and video summer + + _____ _____ + INV 1 |* \_/ | 18 CBLNK + R 2 | | 17 3,54 MHz + G 3 | | 16 GND + B 4 | | 15 CBF + _CSYNC 5 | TEA1002 | 14 8,86 MHz + lum. delay line 6 | | 13 8,86 MHz + lum. delay line 7 | | 12 PAL switch + comp. video to mod. 8 | | 11 chroma band limiting + d.c. adj. / colour bar 9 |_____________| 10 Vp + +***************************************************************************/ + +#pragma once + +#ifndef __TEA1002_H__ +#define __TEA1002_H__ + +#include "emu.h" + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_TEA1002_ADD(_tag, _clock) \ + MCFG_DEVICE_ADD(_tag, TEA1002, _clock) + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> tea1002_device + +class tea1002_device : public device_t +{ +public: + // construction/destruction + tea1002_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + rgb_t color(int index); + +protected: + // device_t overrides + virtual void device_start(); + +private: + static const int m_tint = -6; // what is this based on? + static const float m_luminance[16]; + static const int m_phase[16]; + static const int m_amplitute[16]; +}; + +// device type definition +extern const device_type TEA1002; + +#endif // __TEA1002_H__ diff --git a/src/devices/video/tlc34076.c b/src/devices/video/tlc34076.c new file mode 100644 index 00000000000..b695ce08ed7 --- /dev/null +++ b/src/devices/video/tlc34076.c @@ -0,0 +1,263 @@ +// license:BSD-3-Clause +// copyright-holders:Philip Bennett +/*************************************************************************** + + tlc34076.c + + Basic implementation of the TLC34076 palette chip and similar + compatible chips. + +***************************************************************************/ + +#include "emu.h" +#include "tlc34076.h" + + +//************************************************************************** +// MACROS +//************************************************************************** + +#define PALETTE_WRITE_ADDR 0x00 +#define PALETTE_DATA 0x01 +#define PIXEL_READ_MASK 0x02 +#define PALETTE_READ_ADDR 0x03 +#define GENERAL_CONTROL 0x08 +#define INPUT_CLOCK_SEL 0x09 +#define OUTPUT_CLOCK_SEL 0x0a +#define MUX_CONTROL 0x0b +#define PALETTE_PAGE 0x0c +#define TEST_REGISTER 0x0e +#define RESET_STATE 0x0f + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +// device type definition +const device_type TLC34076 = &device_creator; + + +//------------------------------------------------- +// tlc34076_device - constructor +//------------------------------------------------- +tlc34076_device::tlc34076_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, TLC34076, "TLC34076 VIP", tag, owner, clock, "tlc34076", __FILE__), + m_dacbits(6) +{ +} + + +//------------------------------------------------- +// static_set_bits - set DAC resolution +//------------------------------------------------- +void tlc34076_device::static_set_bits(device_t &device, tlc34076_bits bits) +{ + tlc34076_device &tlc = downcast(device); + tlc.m_dacbits = bits; +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- +void tlc34076_device::device_start() +{ + save_item(NAME(m_local_paletteram)); + save_item(NAME(m_regs)); + save_item(NAME(m_pens)); + + save_item(NAME(m_writeindex)); + save_item(NAME(m_readindex)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void tlc34076_device::device_reset() +{ + m_regs[PIXEL_READ_MASK] = 0xff; + m_regs[GENERAL_CONTROL] = 0x03; + m_regs[INPUT_CLOCK_SEL] = 0x00; + m_regs[OUTPUT_CLOCK_SEL] = 0x3f; + m_regs[MUX_CONTROL] = 0x2d; + m_regs[PALETTE_PAGE] = 0x00; + m_regs[TEST_REGISTER] = 0x00; + m_regs[RESET_STATE] = 0x00; +} + + +//************************************************************************** +// PUBLIC INTERFACE +//************************************************************************** + +//------------------------------------------------- +// get_pens - retrieve current palette +//------------------------------------------------- + +const rgb_t *tlc34076_device::get_pens() +{ + offs_t i; + + for (i = 0; i < 0x100; i++) + { + int r, g, b; + + if ((i & m_regs[PIXEL_READ_MASK]) == i) + { + r = m_local_paletteram[3 * i + 0]; + g = m_local_paletteram[3 * i + 1]; + b = m_local_paletteram[3 * i + 2]; + + if (m_dacbits == 6) + { + r = pal6bit(r); + g = pal6bit(g); + b = pal6bit(b); + } + } + else + { + r = 0; + g = 0; + b = 0; + } + + m_pens[i] = rgb_t(r, g, b); + } + + return m_pens; +} + + +//------------------------------------------------- +// read - read access +//------------------------------------------------- + +READ8_MEMBER( tlc34076_device::read ) +{ + UINT8 result; + + /* keep in range */ + offset &= 0x0f; + result = m_regs[offset]; + + /* switch off the offset */ + switch (offset) + { + case PALETTE_DATA: + if (m_readindex == 0) + { + m_palettedata[0] = m_local_paletteram[3 * m_regs[PALETTE_READ_ADDR] + 0]; + m_palettedata[1] = m_local_paletteram[3 * m_regs[PALETTE_READ_ADDR] + 1]; + m_palettedata[2] = m_local_paletteram[3 * m_regs[PALETTE_READ_ADDR] + 2]; + } + result = m_palettedata[m_readindex++]; + if (m_readindex == 3) + { + m_readindex = 0; + m_regs[PALETTE_READ_ADDR]++; + } + break; + } + + return result; +} + + +//------------------------------------------------- +// write - write access +//------------------------------------------------- + +WRITE8_MEMBER( tlc34076_device::write ) +{ +// UINT8 oldval; + + /* keep in range */ + offset &= 0x0f; +// oldval = m_regs[offset]; + m_regs[offset] = data; + + /* switch off the offset */ + switch (offset) + { + case PALETTE_WRITE_ADDR: + m_writeindex = 0; + break; + + case PALETTE_DATA: + m_palettedata[m_writeindex++] = data; + if (m_writeindex == 3) + { + m_local_paletteram[3 * m_regs[PALETTE_WRITE_ADDR] + 0] = m_palettedata[0]; + m_local_paletteram[3 * m_regs[PALETTE_WRITE_ADDR] + 1] = m_palettedata[1]; + m_local_paletteram[3 * m_regs[PALETTE_WRITE_ADDR] + 2] = m_palettedata[2]; + m_writeindex = 0; + m_regs[PALETTE_WRITE_ADDR]++; + } + break; + + case PALETTE_READ_ADDR: + m_readindex = 0; + break; + + case GENERAL_CONTROL: + /* + 7 6 5 4 3 2 1 0 + X X X X X X X 0 HSYNCOUT is active-low + X X X X X X X 1 HSYNCOUT is active-high (default) + X X X X X X 0 X VSYNCOUT is active-low + X X X X X X 1 X VSYNCOUT is active-high (default) + X X X X X 0 X X Disable split shift register transfer (default) + X X X X 0 1 X X Enable split shift register transfer + X X X X 0 X X X Disable special nibble mode (default) + X X X X 1 0 X X Enable special nibble mode + X X X 0 X X X X 0-IRE pedestal (default) + X X X 1 X X X X 7.5-IRE pedestal + X X 0 X X X X X Disable sync (default) + X X 1 X X X X X Enable sync + X 0 X X X X X X Little-endian mode (default) + X 1 X X X X X X Big-endian mode + 0 X X X X X X X MUXOUT is low (default) + 1 X X X X X X X MUXOUT is high + */ + break; + + case INPUT_CLOCK_SEL: + /* + 3 2 1 0 + 0 0 0 0 Select CLK0 as clock source? + 0 0 0 1 Select CLK1 as clock source + 0 0 1 0 Select CLK2 as clock source + 0 0 1 1 Select CLK3 as TTL clock source + 0 1 0 0 Select CLK3 as TTL clock source + 1 0 0 0 Select CLK3 and CLK3 as ECL clock sources + */ + break; + + case OUTPUT_CLOCK_SEL: + /* + 0 0 0 X X X VCLK frequency = DOTCLK frequency + 0 0 1 X X X VCLK frequency = DOTCLK frequency/2 + 0 1 0 X X X VCLK frequency = DOTCLK frequency/4 + 0 1 1 X X X VCLK frequency = DOTCLK frequency/8 + 1 0 0 X X X VCLK frequency = DOTCLK frequency/16 + 1 0 1 X X X VCLK frequency = DOTCLK frequency/32 + 1 1 X X X X VCLK output held at logic high level (default condition) + X X X 0 0 0 SCLK frequency = DOTCLK frequency + X X X 0 0 1 SCLK frequency = DOTCLK frequency/2 + X X X 0 1 0 SCLK frequency = DOTCLK frequency/4 + X X X 0 1 1 SCLK frequency = DOTCLK frequency/8 + X X X 1 0 0 SCLK frequency = DOTCLK frequency/16 + X X X 1 0 1 SCLK frequency = DOTCLK frequency/32 + X X X 1 1 X SCLK output held at logic level low (default condition) + */ + break; + + case RESET_STATE: + device_reset(); + break; + } +} diff --git a/src/devices/video/tlc34076.h b/src/devices/video/tlc34076.h new file mode 100644 index 00000000000..08c8d666fee --- /dev/null +++ b/src/devices/video/tlc34076.h @@ -0,0 +1,76 @@ +// license:BSD-3-Clause +// copyright-holders:Philip Bennett +/*************************************************************************** + + tlc34076.h + + Basic implementation of the TLC34076 palette chip and similar + compatible chips. + +***************************************************************************/ + +#pragma once + +#ifndef __TLC34076_H__ +#define __TLC34076_H__ + + +/*************************************************************************** + CONSTANTS +***************************************************************************/ + +enum tlc34076_bits +{ + TLC34076_6_BIT = 6, + TLC34076_8_BIT = 8 +}; + + +/*************************************************************************** + TYPE DEFINITIONS +***************************************************************************/ + +class tlc34076_device : public device_t +{ +public: + // construction/destruction + tlc34076_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // static configuration helpers + static void static_set_bits(device_t &device, tlc34076_bits bits); + + // public interface + const rgb_t *get_pens(); + DECLARE_READ8_MEMBER(read); + DECLARE_WRITE8_MEMBER(write); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + +private: + // internal state + UINT8 m_local_paletteram[0x300]; + UINT8 m_regs[0x10]; + UINT8 m_palettedata[3]; + UINT8 m_writeindex; + UINT8 m_readindex; + UINT8 m_dacbits; + rgb_t m_pens[0x100]; +}; + + +/*************************************************************************** + DEVICE CONFIGURATION MACROS +***************************************************************************/ + +#define MCFG_TLC34076_ADD(_tag, _bits) \ + MCFG_DEVICE_ADD(_tag, TLC34076, 0) \ + tlc34076_device::static_set_bits(*device, _bits); + + +extern const device_type TLC34076; + + +#endif /* __TLC34076_H__ */ diff --git a/src/devices/video/tms34061.c b/src/devices/video/tms34061.c new file mode 100644 index 00000000000..02720cda66a --- /dev/null +++ b/src/devices/video/tms34061.c @@ -0,0 +1,557 @@ +// license:BSD-3-Clause +// copyright-holders:Zsolt Vasvari, Aaron Giles +/**************************************************************************** + * * + * Functions to emulate the TMS34061 video controller * + * * + * Created by Zsolt Vasvari on 5/26/1998. * + * Updated by Aaron Giles on 11/21/2000. * + * * + * This is far from complete. See the TMS34061 User's Guide available on * + * www.spies.com/arcade * + * * + ****************************************************************************/ + +#include "emu.h" +#include "tms34061.h" + + +#define VERBOSE (0) + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// tms34061_device - constructor +//------------------------------------------------- + +const device_type TMS34061 = &device_creator; + +tms34061_device::tms34061_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, TMS34061, "TMS34061 VSC", tag, owner, clock, "tms34061", __FILE__), + device_video_interface(mconfig, *this), + m_rowshift(0), + m_vramsize(0), + m_interrupt_cb(*this), + m_xmask(0), + m_yshift(0), + m_vrammask(0), + m_vram(NULL), + m_latchram(NULL), + m_latchdata(0), + m_shiftreg(NULL), + m_timer(NULL) +{ + memset(m_regs, 0, sizeof(m_regs)); + memset(&m_display, 0, sizeof(m_display)); +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void tms34061_device::device_start() +{ + /* resolve callbak */ + m_interrupt_cb.resolve(); + + /* reset the data */ + m_vrammask = m_vramsize - 1; + + /* allocate memory for VRAM */ + m_vram = auto_alloc_array_clear(machine(), UINT8, m_vramsize + 256 * 2); + + /* allocate memory for latch RAM */ + m_latchram = auto_alloc_array_clear(machine(), UINT8, m_vramsize + 256 * 2); + + /* add some buffer space for VRAM and latch RAM */ + m_vram += 256; + m_latchram += 256; + + /* point the shift register to the base of VRAM for now */ + m_shiftreg = m_vram; + + /* initialize registers to their default values from the manual */ + m_regs[TMS34061_HORENDSYNC] = 0x0010; + m_regs[TMS34061_HORENDBLNK] = 0x0020; + m_regs[TMS34061_HORSTARTBLNK] = 0x01f0; + m_regs[TMS34061_HORTOTAL] = 0x0200; + m_regs[TMS34061_VERENDSYNC] = 0x0004; + m_regs[TMS34061_VERENDBLNK] = 0x0010; + m_regs[TMS34061_VERSTARTBLNK] = 0x00f0; + m_regs[TMS34061_VERTOTAL] = 0x0100; + m_regs[TMS34061_DISPUPDATE] = 0x0000; + m_regs[TMS34061_DISPSTART] = 0x0000; + m_regs[TMS34061_VERINT] = 0x0000; + m_regs[TMS34061_CONTROL1] = 0x7000; + m_regs[TMS34061_CONTROL2] = 0x0600; + m_regs[TMS34061_STATUS] = 0x0000; + m_regs[TMS34061_XYOFFSET] = 0x0010; + m_regs[TMS34061_XYADDRESS] = 0x0000; + m_regs[TMS34061_DISPADDRESS] = 0x0000; + m_regs[TMS34061_VERCOUNTER] = 0x0000; + + /* start vertical interrupt timer */ + m_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(tms34061_device::interrupt), this)); + + save_item(NAME(m_regs)); + save_item(NAME(m_xmask)); + save_item(NAME(m_yshift)); + save_pointer(NAME(m_vram), m_vramsize); + save_pointer(NAME(m_latchram), m_vramsize); + save_item(NAME(m_latchdata)); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void tms34061_device::device_reset() +{ +} + +/************************************* + * + * Global variables + * + *************************************/ + +static const char *const regnames[] = +{ + "HORENDSYNC", "HORENDBLNK", "HORSTARTBLNK", "HORTOTAL", + "VERENDSYNC", "VERENDBLNK", "VERSTARTBLNK", "VERTOTAL", + "DISPUPDATE", "DISPSTART", "VERINT", "CONTROL1", + "CONTROL2", "STATUS", "XYOFFSET", "XYADDRESS", + "DISPADDRESS", "VERCOUNTER" +}; + + +/************************************* + * + * Interrupt handling + * + *************************************/ + +void tms34061_device::update_interrupts() +{ + /* if we have a callback, process it */ + if (!m_interrupt_cb.isnull()) + { + /* if the status bit is set, and ints are enabled, turn it on */ + if ((m_regs[TMS34061_STATUS] & 0x0001) && (m_regs[TMS34061_CONTROL1] & 0x0400)) + m_interrupt_cb(ASSERT_LINE); + else + m_interrupt_cb(CLEAR_LINE); + } +} + + +TIMER_CALLBACK_MEMBER( tms34061_device::interrupt ) +{ + /* set timer for next frame */ + m_timer->adjust(m_screen->frame_period()); + + /* set the interrupt bit in the status reg */ + m_regs[TMS34061_STATUS] |= 1; + + /* update the interrupt state */ + update_interrupts(); +} + + + +/************************************* + * + * Register writes + * + *************************************/ + +void tms34061_device::register_w(address_space &space, offs_t offset, UINT8 data) +{ + int scanline; + int regnum = offset >> 2; + + /* certain registers affect the display directly */ + if ((regnum >= TMS34061_HORENDSYNC && regnum <= TMS34061_DISPSTART) || + (regnum == TMS34061_CONTROL2)) + m_screen->update_partial(m_screen->vpos()); + + /* store the hi/lo half */ + if (regnum < ARRAY_LENGTH(m_regs)) + { + if (offset & 0x02) + m_regs[regnum] = (m_regs[regnum] & 0x00ff) | (data << 8); + else + m_regs[regnum] = (m_regs[regnum] & 0xff00) | data; + } + + /* log it */ + if (VERBOSE) logerror("%s:tms34061 %s = %04x\n", space.machine().describe_context(), regnames[regnum], m_regs[regnum]); + + /* update the state of things */ + switch (regnum) + { + /* vertical interrupt: adjust the timer */ + case TMS34061_VERINT: + scanline = m_regs[TMS34061_VERINT] - m_regs[TMS34061_VERENDBLNK]; + + if (scanline < 0) + scanline += m_regs[TMS34061_VERTOTAL]; + + m_timer->adjust(m_screen->time_until_pos(scanline, m_regs[TMS34061_HORSTARTBLNK])); + break; + + /* XY offset: set the X and Y masks */ + case TMS34061_XYOFFSET: + switch (m_regs[TMS34061_XYOFFSET] & 0x00ff) + { + case 0x01: m_yshift = 2; break; + case 0x02: m_yshift = 3; break; + case 0x04: m_yshift = 4; break; + case 0x08: m_yshift = 5; break; + case 0x10: m_yshift = 6; break; + case 0x20: m_yshift = 7; break; + case 0x40: m_yshift = 8; break; + case 0x80: m_yshift = 9; break; + default: logerror("Invalid value for XYOFFSET = %04x\n", m_regs[TMS34061_XYOFFSET]); break; + } + m_xmask = (1 << m_yshift) - 1; + break; + + /* CONTROL1: they could have turned interrupts on */ + case TMS34061_CONTROL1: + update_interrupts(); + break; + + /* other supported registers */ + case TMS34061_XYADDRESS: + break; + } +} + + + +/************************************* + * + * Register reads + * + *************************************/ + +UINT8 tms34061_device::register_r(address_space &space, offs_t offset) +{ + int regnum = offset >> 2; + UINT16 result; + + /* extract the correct portion of the register */ + if (regnum < ARRAY_LENGTH(m_regs)) + result = m_regs[regnum]; + else + result = 0xffff; + + /* special cases: */ + switch (regnum) + { + /* status register: a read here clears it */ + case TMS34061_STATUS: + m_regs[TMS34061_STATUS] = 0; + update_interrupts(); + break; + + /* vertical count register: return the current scanline */ + case TMS34061_VERCOUNTER: + result = (m_screen->vpos()+ m_regs[TMS34061_VERENDBLNK]) % m_regs[TMS34061_VERTOTAL]; + break; + } + + /* log it */ + if (VERBOSE) logerror("%s:tms34061 %s read = %04X\n", space.machine().describe_context(), regnames[regnum], result); + return (offset & 0x02) ? (result >> 8) : result; +} + + + +/************************************* + * + * XY addressing + * + *************************************/ + +void tms34061_device::adjust_xyaddress(int offset) +{ + /* note that carries are allowed if the Y coordinate isn't being modified */ + switch (offset & 0x1e) + { + case 0x00: /* no change */ + break; + + case 0x02: /* X + 1 */ + m_regs[TMS34061_XYADDRESS]++; + break; + + case 0x04: /* X - 1 */ + m_regs[TMS34061_XYADDRESS]--; + break; + + case 0x06: /* X = 0 */ + m_regs[TMS34061_XYADDRESS] &= ~m_xmask; + break; + + case 0x08: /* Y + 1 */ + m_regs[TMS34061_XYADDRESS] += 1 << m_yshift; + break; + + case 0x0a: /* X + 1, Y + 1 */ + m_regs[TMS34061_XYADDRESS] = (m_regs[TMS34061_XYADDRESS] & ~m_xmask) | + ((m_regs[TMS34061_XYADDRESS] + 1) & m_xmask); + m_regs[TMS34061_XYADDRESS] += 1 << m_yshift; + break; + + case 0x0c: /* X - 1, Y + 1 */ + m_regs[TMS34061_XYADDRESS] = (m_regs[TMS34061_XYADDRESS] & ~m_xmask) | + ((m_regs[TMS34061_XYADDRESS] - 1) & m_xmask); + m_regs[TMS34061_XYADDRESS] += 1 << m_yshift; + break; + + case 0x0e: /* X = 0, Y + 1 */ + m_regs[TMS34061_XYADDRESS] &= ~m_xmask; + m_regs[TMS34061_XYADDRESS] += 1 << m_yshift; + break; + + case 0x10: /* Y - 1 */ + m_regs[TMS34061_XYADDRESS] -= 1 << m_yshift; + break; + + case 0x12: /* X + 1, Y - 1 */ + m_regs[TMS34061_XYADDRESS] = (m_regs[TMS34061_XYADDRESS] & ~m_xmask) | + ((m_regs[TMS34061_XYADDRESS] + 1) & m_xmask); + m_regs[TMS34061_XYADDRESS] -= 1 << m_yshift; + break; + + case 0x14: /* X - 1, Y - 1 */ + m_regs[TMS34061_XYADDRESS] = (m_regs[TMS34061_XYADDRESS] & ~m_xmask) | + ((m_regs[TMS34061_XYADDRESS] - 1) & m_xmask); + m_regs[TMS34061_XYADDRESS] -= 1 << m_yshift; + break; + + case 0x16: /* X = 0, Y - 1 */ + m_regs[TMS34061_XYADDRESS] &= ~m_xmask; + m_regs[TMS34061_XYADDRESS] -= 1 << m_yshift; + break; + + case 0x18: /* Y = 0 */ + m_regs[TMS34061_XYADDRESS] &= m_xmask; + break; + + case 0x1a: /* X + 1, Y = 0 */ + m_regs[TMS34061_XYADDRESS]++; + m_regs[TMS34061_XYADDRESS] &= m_xmask; + break; + + case 0x1c: /* X - 1, Y = 0 */ + m_regs[TMS34061_XYADDRESS]--; + m_regs[TMS34061_XYADDRESS] &= m_xmask; + break; + + case 0x1e: /* X = 0, Y = 0 */ + m_regs[TMS34061_XYADDRESS] = 0; + break; + } +} + + +void tms34061_device::xypixel_w(address_space &space, int offset, UINT8 data) +{ + /* determine the offset, then adjust it */ + offs_t pixeloffs = m_regs[TMS34061_XYADDRESS]; + if (offset) + adjust_xyaddress(offset); + + /* adjust for the upper bits */ + pixeloffs |= (m_regs[TMS34061_XYOFFSET] & 0x0f00) << 8; + + /* mask to the VRAM size */ + pixeloffs &= m_vrammask; + if (VERBOSE) logerror("%s:tms34061 xy (%04x) = %02x/%02x\n", space.machine().describe_context(), pixeloffs, data, m_latchdata); + + /* set the pixel data */ + m_vram[pixeloffs] = data; + m_latchram[pixeloffs] = m_latchdata; +} + + +UINT8 tms34061_device::xypixel_r(address_space &space, int offset) +{ + /* determine the offset, then adjust it */ + offs_t pixeloffs = m_regs[TMS34061_XYADDRESS]; + if (offset) + adjust_xyaddress(offset); + + /* adjust for the upper bits */ + pixeloffs |= (m_regs[TMS34061_XYOFFSET] & 0x0f00) << 8; + + /* mask to the VRAM size */ + pixeloffs &= m_vrammask; + + /* return the result */ + return m_vram[pixeloffs]; +} + + + +/************************************* + * + * Core writes + * + *************************************/ + +void tms34061_device::write(address_space &space, int col, int row, int func, UINT8 data) +{ + offs_t offs; + + /* the function code determines what to do */ + switch (func) + { + /* both 0 and 2 map to register access */ + case 0: + case 2: + register_w(space, col, data); + break; + + /* function 1 maps to XY access; col is the address adjustment */ + case 1: + xypixel_w(space, col, data); + break; + + /* function 3 maps to direct access */ + case 3: + offs = ((row << m_rowshift) | col) & m_vrammask; + if (m_regs[TMS34061_CONTROL2] & 0x0040) + offs |= (m_regs[TMS34061_CONTROL2] & 3) << 16; + if (VERBOSE) logerror("%s:tms34061 direct (%04x) = %02x/%02x\n", space.machine().describe_context(), offs, data, m_latchdata); + if (m_vram[offs] != data || m_latchram[offs] != m_latchdata) + { + m_vram[offs] = data; + m_latchram[offs] = m_latchdata; + } + break; + + /* function 4 performs a shift reg transfer to VRAM */ + case 4: + offs = col << m_rowshift; + if (m_regs[TMS34061_CONTROL2] & 0x0040) + offs |= (m_regs[TMS34061_CONTROL2] & 3) << 16; + offs &= m_vrammask; + if (VERBOSE) logerror("%s:tms34061 shiftreg write (%04x)\n", space.machine().describe_context(), offs); + + memcpy(&m_vram[offs], m_shiftreg, (size_t)1 << m_rowshift); + memset(&m_latchram[offs], m_latchdata, (size_t)1 << m_rowshift); + break; + + /* function 5 performs a shift reg transfer from VRAM */ + case 5: + offs = col << m_rowshift; + if (m_regs[TMS34061_CONTROL2] & 0x0040) + offs |= (m_regs[TMS34061_CONTROL2] & 3) << 16; + offs &= m_vrammask; + if (VERBOSE) logerror("%s:tms34061 shiftreg read (%04x)\n", space.machine().describe_context(), offs); + + m_shiftreg = &m_vram[offs]; + break; + + /* log anything else */ + default: + logerror("%s:Unsupported TMS34061 function %d\n", space.machine().describe_context(), func); + break; + } +} + + +UINT8 tms34061_device::read(address_space &space, int col, int row, int func) +{ + int result = 0; + offs_t offs; + + /* the function code determines what to do */ + switch (func) + { + /* both 0 and 2 map to register access */ + case 0: + case 2: + result = register_r(space, col); + break; + + /* function 1 maps to XY access; col is the address adjustment */ + case 1: + result = xypixel_r(space, col); + break; + + /* funtion 3 maps to direct access */ + case 3: + offs = ((row << m_rowshift) | col) & m_vrammask; + result = m_vram[offs]; + break; + + /* function 4 performs a shift reg transfer to VRAM */ + case 4: + offs = col << m_rowshift; + if (m_regs[TMS34061_CONTROL2] & 0x0040) + offs |= (m_regs[TMS34061_CONTROL2] & 3) << 16; + offs &= m_vrammask; + + memcpy(&m_vram[offs], m_shiftreg, (size_t)1 << m_rowshift); + memset(&m_latchram[offs], m_latchdata, (size_t)1 << m_rowshift); + break; + + /* function 5 performs a shift reg transfer from VRAM */ + case 5: + offs = col << m_rowshift; + if (m_regs[TMS34061_CONTROL2] & 0x0040) + offs |= (m_regs[TMS34061_CONTROL2] & 3) << 16; + offs &= m_vrammask; + + m_shiftreg = &m_vram[offs]; + break; + + /* log anything else */ + default: + logerror("%s:Unsupported TMS34061 function %d\n", space.machine().describe_context(), + func); + break; + } + + return result; +} + + + +/************************************* + * + * Misc functions + * + *************************************/ + +READ8_MEMBER( tms34061_device::latch_r ) +{ + return m_latchdata; +} + + +WRITE8_MEMBER( tms34061_device::latch_w ) +{ + if (VERBOSE) logerror("tms34061_latch = %02X\n", data); + m_latchdata = data; +} + + +void tms34061_device::get_display_state() +{ + m_display.blanked = (~m_regs[TMS34061_CONTROL2] >> 13) & 1; + m_display.vram = m_vram; + m_display.latchram = m_latchram; + m_display.regs = m_regs; + + /* compute the display start */ + m_display.dispstart = (m_regs[TMS34061_DISPSTART] << (m_rowshift - 2)) & m_vrammask; +} diff --git a/src/devices/video/tms34061.h b/src/devices/video/tms34061.h new file mode 100644 index 00000000000..fa8d6a98601 --- /dev/null +++ b/src/devices/video/tms34061.h @@ -0,0 +1,122 @@ +// license:BSD-3-Clause +// copyright-holders:Zsolt Vasvari, Aaron Giles +/**************************************************************************** + * * + * Function prototypes and constants used by the TMS34061 emulator * + * * + * Created by Zsolt Vasvari on 5/26/1998. * + * Updated by Aaron Giles on 11/21/2000. * + * * + ****************************************************************************/ + + +#ifndef __TMS34061_H__ +#define __TMS34061_H__ + + +#define MCFG_TMS34061_ROWSHIFT(_shift) \ + tms34061_device::set_rowshift(*device, _shift); + +#define MCFG_TMS34061_VRAM_SIZE(_size) \ + tms34061_device::set_vram_size(*device, _size); + +#define MCFG_TMS34061_INTERRUPT_CB(_devcb) \ + devcb = &tms34061_device::set_interrupt_callback(*device, DEVCB_##_devcb); + + +/* register constants */ +enum +{ + TMS34061_HORENDSYNC = 0, + TMS34061_HORENDBLNK, + TMS34061_HORSTARTBLNK, + TMS34061_HORTOTAL, + TMS34061_VERENDSYNC, + TMS34061_VERENDBLNK, + TMS34061_VERSTARTBLNK, + TMS34061_VERTOTAL, + TMS34061_DISPUPDATE, + TMS34061_DISPSTART, + TMS34061_VERINT, + TMS34061_CONTROL1, + TMS34061_CONTROL2, + TMS34061_STATUS, + TMS34061_XYOFFSET, + TMS34061_XYADDRESS, + TMS34061_DISPADDRESS, + TMS34061_VERCOUNTER, + TMS34061_REGCOUNT +}; + +/* display state structure */ +struct tms34061_display +{ + UINT8 blanked; /* true if blanked */ + UINT8 *vram; /* base of VRAM */ + UINT8 *latchram; /* base of latch RAM */ + UINT16 *regs; /* pointer to array of registers */ + offs_t dispstart; /* display start */ +}; + + + + +// ======================> tms34061_device + +class tms34061_device : public device_t, + public device_video_interface +{ +public: + // construction/destruction + tms34061_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + static void set_rowshift(device_t &device, UINT8 rowshift) { downcast(device).m_rowshift = rowshift; } + static void set_vram_size(device_t &device, UINT32 vramsize) { downcast(device).m_vramsize = vramsize; } + template static devcb_base &set_interrupt_callback(device_t &device, _Object object) { return downcast(device).m_interrupt_cb.set_callback(object); } + + /* reads/writes to the 34061 */ + UINT8 read(address_space &space, int col, int row, int func); + void write(address_space &space, int col, int row, int func, UINT8 data); + + /* latch settings */ + DECLARE_READ8_MEMBER( latch_r ); + DECLARE_WRITE8_MEMBER( latch_w ); + + /* video update handling */ + void get_display_state(); + + struct tms34061_display m_display; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + +private: + UINT8 m_rowshift; /* VRAM address is (row << rowshift) | col */ + UINT32 m_vramsize; /* size of video RAM */ + devcb_write_line m_interrupt_cb; /* interrupt gen callback */ + + UINT16 m_regs[TMS34061_REGCOUNT]; + UINT16 m_xmask; + UINT8 m_yshift; + UINT32 m_vrammask; + UINT8 * m_vram; + UINT8 * m_latchram; + UINT8 m_latchdata; + UINT8 * m_shiftreg; + emu_timer * m_timer; + + void update_interrupts(void); + TIMER_CALLBACK_MEMBER( interrupt ); + void register_w(address_space &space, offs_t offset, UINT8 data); + UINT8 register_r(address_space &space, offs_t offset); + void adjust_xyaddress(int offset); + void xypixel_w(address_space &space, int offset, UINT8 data); + UINT8 xypixel_r(address_space &space, int offset); +}; + +// device type definition +extern const device_type TMS34061; + +#endif diff --git a/src/devices/video/tms3556.c b/src/devices/video/tms3556.c new file mode 100644 index 00000000000..9d073bdbe0d --- /dev/null +++ b/src/devices/video/tms3556.c @@ -0,0 +1,658 @@ +// license:BSD-3-Clause +// copyright-holders:Raphael Nabet +/* + tms3556 emulation + + TODO: + * implement remaining flags in control registers + * test the whole thing + * find the bloody tms3556 manual. I mean the register and VRAM interfaces + are mostly guesswork full of hacks, and I'd like to compare it with + documentation. + + Raphael Nabet, 2004 +*/ + +#include "emu.h" +#include "tms3556.h" + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define LOG 0 + + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +// devices +const device_type TMS3556 = &device_creator; + + +// default address map +static ADDRESS_MAP_START( tms3556, AS_0, 8, tms3556_device ) + AM_RANGE(0x0000, 0xffff) AM_RAM +ADDRESS_MAP_END + +//------------------------------------------------- +// memory_space_config - return a description of +// any address spaces owned by this device +//------------------------------------------------- + +const address_space_config *tms3556_device::memory_space_config(address_spacenum spacenum) const +{ + return (spacenum == AS_0) ? &m_space_config : NULL; +} + + +//************************************************************************** +// INLINE HELPERS +//************************************************************************** + +//------------------------------------------------- +// readbyte - read a byte at the given address +//------------------------------------------------- + +inline UINT8 tms3556_device::readbyte(offs_t address) +{ + return space().read_byte(address&0xFFFF); +} + + +//------------------------------------------------- +// writebyte - write a byte at the given address +//------------------------------------------------- + +inline void tms3556_device::writebyte(offs_t address, UINT8 data) +{ + space().write_byte(address&0xFFFF, data); +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// tms3556_device - constructor +//------------------------------------------------- + +tms3556_device::tms3556_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, TMS3556, "Texas Instruments VDP TMS3556", tag, owner, clock, "tms3556", __FILE__), + device_memory_interface(mconfig, *this), + m_space_config("videoram", ENDIANNESS_LITTLE, 8, 17, 0, NULL, *ADDRESS_MAP_NAME(tms3556)), + m_reg_access_phase(0), + m_row_col_written(0), + m_bamp_written(0), + m_colrow(0), + m_vdp_acmpxy_mode(dma_write), + m_vdp_acmpxy(0), + m_vdp_acmp(0), + m_init_read(0), + m_scanline(0), + m_blink(0), + m_blink_count(0), + m_bg_color(0) +{ + for (int i = 0; i < 8; i++) + { + m_control_regs[i] = 0; + m_address_regs[i] = 0xFFFF; + } +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void tms3556_device::device_start() +{ + // register for state saving + save_item(NAME(m_control_regs)); + save_item(NAME(m_address_regs)); + save_item(NAME(m_reg_access_phase)); + save_item(NAME(m_row_col_written)); + save_item(NAME(m_bamp_written)); + save_item(NAME(m_colrow)); +// save_item(NAME(m_vdp_acmpxy_mode)); // FIXME : mame cannot save enum + save_item(NAME(m_vdp_acmpxy)); + save_item(NAME(m_vdp_acmp)); + save_item(NAME(m_scanline)); + save_item(NAME(m_blink)); + save_item(NAME(m_blink_count)); + save_item(NAME(m_bg_color)); + save_item(NAME(m_name_offset)); + save_item(NAME(m_cg_flag)); + save_item(NAME(m_char_line_counter)); + save_item(NAME(m_dbl_h_phase)); + + machine().first_screen()->register_screen_bitmap(m_bitmap); +} + + +/*static const char *const tms3556_mode_names[] = { "DISPLAY OFF", "TEXT", "GRAPHIC", "MIXED" };*/ + + +UINT32 tms3556_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) +{ + copybitmap(bitmap, m_bitmap, 0, 0, 0, 0, cliprect); + return 0; +} + + +//------------------------------------------------- +// vram_r - VRAM read +//------------------------------------------------- + +READ8_MEMBER( tms3556_device::vram_r ) +{ + UINT8 ret; + if (m_bamp_written) { + m_bamp_written=false; + m_vdp_acmpxy_mode=dma_write; + if (m_init_read) + m_vdp_acmp=VDP_BAMP; + else + m_vdp_acmp=(VDP_BAMP-1)&0xFFFF; + } + + if (m_row_col_written) { + m_row_col_written=0; + m_vdp_acmpxy_mode=dma_read; + if (m_init_read) + m_vdp_acmpxy=m_colrow; + else + m_vdp_acmpxy=(m_colrow-1)&0xFFFF; + } + + m_init_read=false; + if (m_vdp_acmpxy_mode==dma_read) { + ret=readbyte(m_vdp_acmpxy); + m_vdp_acmpxy++; + if (m_vdp_acmpxy==VDP_BAMTF) m_vdp_acmpxy=VDP_BAMP; + } else { + ret=readbyte(m_vdp_acmp); + m_vdp_acmp++; + if (m_vdp_acmp==VDP_BAMTF) m_vdp_acmp=VDP_BAMP; + } + return ret; +} + +//------------------------------------------------- +// vram_w - VRAM write +//------------------------------------------------- + +WRITE8_MEMBER( tms3556_device::vram_w ) +{ + if (m_bamp_written) { + m_bamp_written=false; + m_vdp_acmpxy_mode=dma_read; + m_vdp_acmp=VDP_BAMP; + } + + if (m_row_col_written) { + m_row_col_written=0; + m_vdp_acmpxy_mode=dma_write; + m_vdp_acmpxy=m_colrow; + } + + if (m_vdp_acmpxy_mode==dma_write) { + writebyte(m_vdp_acmpxy,data); + m_vdp_acmpxy++; + if (m_vdp_acmpxy==VDP_BAMTF) m_vdp_acmpxy=VDP_BAMP; + } else { + writebyte(m_vdp_acmp,data); + m_vdp_acmp++; + if (m_vdp_acmp==VDP_BAMTF) m_vdp_acmp=VDP_BAMP; + } + +} + + +//------------------------------------------------- +// reg_r - read from register port +//------------------------------------------------- + +READ8_MEMBER( tms3556_device::reg_r ) +{ + if (LOG) logerror("TMS3556 Reg Read: %06x\n", offset); + + int reply = 0; // FIXME : will send internal status (VBL, HBL...) + m_reg_access_phase=0; + return reply; +} + +//------------------------------------------------- +// reg_w - write to register port +//------------------------------------------------- + +WRITE8_MEMBER( tms3556_device::reg_w ) +{ + static int reg2=0; // FIXME : this static makes that only one TMS3556 will be present in one system... + static int reg=0; + + if (LOG) logerror("TMS3556 Reg Write: %06x = %02x\n", offset, data); + + switch (m_reg_access_phase) { + case 0: + reg=data&0x0F; + reg2=(data&0xF0)>>4; + if (reg!=0) + m_reg_access_phase=1; + return; + + case 1: + if (reg<8) { + m_control_regs[reg]=data; + // leve un flag si le dernier registre ecrit est row ou col + if ((reg==2) || (reg==1)) { + m_colrow=(m_control_regs[2]<<8)|m_control_regs[1]; + m_row_col_written=true; + } + + if (reg2==0) { + m_reg_access_phase=0; + return; + } + else { + m_reg_access_phase=1; + reg=reg2; + reg2=0; + return; + } + } else { + m_address_regs[reg-8]=(m_control_regs[2]<<8)|m_control_regs[1]; + // cas speciaux de decalage pour les generateurs + if ((reg>=0xB) && (reg<=0xE)) { + m_address_regs[reg-8]+=2; + m_address_regs[reg-8]&=0xFFFF; + } else { + m_address_regs[reg-8]+=1; + m_address_regs[reg-8]&=0xFFFF; + } + if (reg==9) { + m_row_col_written=false; + m_bamp_written=true; + m_reg_access_phase=0; + return; + } else { + m_row_col_written=0; + m_bamp_written=false; + m_reg_access_phase=2;//??? + return; + } + logerror("VDP16[%d] = x%x",reg,m_address_regs[reg-8]); + if (reg2==0) { + m_reg_access_phase=0; + return; + } + else { + m_reg_access_phase=1; + reg=reg2; + reg2=0; + return; + } + } + case 2: + m_reg_access_phase=0; + return; + } +} + +//-------------------------------------------------------------------------- +// initptr_r - set VDP in read mode (not exacly on the VDP but on the TAL) +//-------------------------------------------------------------------------- + +READ8_MEMBER( tms3556_device::initptr_r ) +{ + m_init_read=true; + return 0xff; +} + + +//------------------------------------------------- +// redraw code +//------------------------------------------------- + + +//------------------------------------------------- +// draw_line_empty - draw an empty line (used for +// top and bottom borders, and screen off mode) +//------------------------------------------------- + +void tms3556_device::draw_line_empty(UINT16 *ln) +{ + int i; + + for (i = 0; i < TMS3556_TOTAL_WIDTH; i++) +#if TMS3556_DOUBLE_WIDTH + *ln++ = m_bg_color; +#endif + *ln++ = m_bg_color; +} + + +//------------------------------------------------- +// draw_line_text_common - draw a line of text +// (called by draw_line_text and draw_line_mixed) +//------------------------------------------------- + +void tms3556_device::draw_line_text_common(UINT16 *ln) +{ + int pattern, x, xx, i, name_offset; + UINT16 fg, bg; + offs_t nametbl_base; + offs_t patterntbl_base[4]; + int name_hi, name_lo; + int pattern_ix; + int alphanumeric_mode, dbl_w, dbl_h, dbl_w_phase = 0; + + nametbl_base = m_address_regs[2]; + for (i = 0; i < 4; i++) + patterntbl_base[i] = m_address_regs[i + 3]; + + for (xx = 0; xx < TMS3556_LEFT_BORDER; xx++) +#if TMS3556_DOUBLE_WIDTH + *ln++ = m_bg_color; +#endif + *ln++ = m_bg_color; + + name_offset = m_name_offset; + + for (x = 0; x < 40; x++) + { + name_hi = readbyte(nametbl_base + name_offset); + name_lo = readbyte(nametbl_base + name_offset + 1); + pattern_ix = ((name_hi >> 2) & 2) | ((name_hi >> 4) & 1); + alphanumeric_mode = (pattern_ix < 2) || ((pattern_ix == 3) && !(m_control_regs[7] & 0x08)); + fg = (name_hi >> 5) & 0x7; + if (alphanumeric_mode) + { + if (name_hi & 4) + { /* inverted color */ + bg = fg; + fg = m_bg_color; + } + else + bg = m_bg_color; + dbl_w = name_hi & 0x2; + dbl_h = name_hi & 0x1; + } + else + { + bg = name_hi & 0x7; + dbl_w = 0; + dbl_h = 0; + } + if ((name_lo & 0x80) && m_blink) + fg = bg; /* blink off time */ + if (! dbl_h) + { /* single height */ + pattern = readbyte(patterntbl_base[pattern_ix] + (name_lo & 0x7f) + 128 * m_char_line_counter); + if (m_char_line_counter == 0) + m_dbl_h_phase[x] = 0; + } + else + { /* double height */ + if (! m_dbl_h_phase[x]) + /* first phase: pattern from upper half */ + pattern = readbyte(patterntbl_base[pattern_ix] + (name_lo & 0x7f) + 128 * (5 + (m_char_line_counter >> 1))); + else + /* second phase: pattern from lower half */ + pattern = readbyte(patterntbl_base[pattern_ix] + (name_lo & 0x7f) + 128 * (m_char_line_counter >> 1)); + if (m_char_line_counter == 0) + m_dbl_h_phase[x] = !m_dbl_h_phase[x]; + } + if (!dbl_w) + { /* single width */ + for (xx = 0; xx < 8; xx++) + { + UINT16 color = (pattern & 0x80) ? fg : bg; +#if TMS3556_DOUBLE_WIDTH + *ln++ = color; +#endif + *ln++ = color; + pattern <<= 1; + } + dbl_w_phase = 0; + } + else + { /* double width */ + if (dbl_w_phase) + /* second phase: display right half */ + pattern <<= 4; + for (xx = 0; xx < 4; xx++) + { + UINT16 color = (pattern & 0x80) ? fg : bg; +#if TMS3556_DOUBLE_WIDTH + *ln++ = color; *ln++ = color; +#endif + *ln++ = color; *ln++ = color; + pattern <<= 1; + } + dbl_w_phase = !dbl_w_phase; + } + name_offset += 2; + } + + for (xx = 0; xx < TMS3556_RIGHT_BORDER; xx++) +#if TMS3556_DOUBLE_WIDTH + *ln++ = m_bg_color; +#endif + *ln++ = m_bg_color; + + if (m_char_line_counter == 0) + m_name_offset = name_offset; +} + + +//------------------------------------------------- +// draw_line_bitmap_common - draw a line of bitmap +// (called by draw_line_bitmap and draw_line_mixed) +//------------------------------------------------- + +void tms3556_device::draw_line_bitmap_common(UINT16 *ln) +{ + int x, xx; + offs_t nametbl_base; + int name_b, name_g, name_r; + + nametbl_base = m_address_regs[2]; + + for (xx = 0; xx < TMS3556_LEFT_BORDER; xx++) +#if TMS3556_DOUBLE_WIDTH + *ln++ = m_bg_color; +#endif + *ln++ = m_bg_color; + + for (x = 0; x < 40; x++) + { + name_b = readbyte(nametbl_base + m_name_offset); + name_g = readbyte(nametbl_base + m_name_offset + 1); + name_r = readbyte(nametbl_base + m_name_offset + 2); + for (xx = 0; xx < 8; xx++) + { + UINT16 color = ((name_b >> 5) & 0x4) | ((name_g >> 6) & 0x2) | ((name_r >> 7) & 0x1); +#if TMS3556_DOUBLE_WIDTH + *ln++ = color; +#endif + *ln++ = color; + name_b <<= 1; + name_g <<= 1; + name_r <<= 1; + } + m_name_offset += 3; + } + + for (xx = 0; xx < TMS3556_RIGHT_BORDER; xx++) +#if TMS3556_DOUBLE_WIDTH + *ln++ = m_bg_color; +#endif + *ln++ = m_bg_color; +} + + +//------------------------------------------------- +// draw_line_text - draw a line in text mode +//------------------------------------------------- + +void tms3556_device::draw_line_text(UINT16 *ln) +{ + if (m_char_line_counter == 0) + m_char_line_counter = 10; + m_char_line_counter--; + draw_line_text_common(ln); +} + + +//------------------------------------------------- +// draw_line_bitmap - draw a line in bitmap mode +//------------------------------------------------- + +void tms3556_device::draw_line_bitmap(UINT16 *ln) +{ + draw_line_bitmap_common(ln); + m_bg_color = (readbyte(m_address_regs[2] + m_name_offset) >> 5) & 0x7; + m_name_offset += 2; +} + + +//------------------------------------------------- +// draw_line_mixed - draw a line in mixed mode +//------------------------------------------------- + +void tms3556_device::draw_line_mixed(UINT16 *ln) +{ + if (m_cg_flag) + { /* bitmap line */ + draw_line_bitmap_common(ln); + m_bg_color = (readbyte(m_address_regs[2] + m_name_offset) >> 5) & 0x7; + m_cg_flag = (readbyte(m_address_regs[2] + m_name_offset) >> 4) & 0x1; + m_name_offset += 2; + } + else + { /* text line */ + if (m_char_line_counter == 0) + m_char_line_counter = 10; + m_char_line_counter--; + draw_line_text_common(ln); + if (m_char_line_counter == 0) + { + m_bg_color = (readbyte(m_address_regs[2] + m_name_offset) >> 5) & 0x7; + m_cg_flag = (readbyte(m_address_regs[2] + m_name_offset) >> 4) & 0x1; + m_name_offset += 2; + } + } +} + + +//------------------------------------------------- +// draw_line - draw a line. If non-interlaced mode, +// duplicate the line. +//------------------------------------------------- + +void tms3556_device::draw_line(bitmap_ind16 &bmp, int line) +{ + int double_lines = 0; + UINT16 *ln, *ln2 = NULL; + +// if (m_control_regs[4] & 0x??) +// { // interlaced mode +// ln = &bmp->pix16(line, m_field); +// } +// else + { /* non-interlaced mode */ + ln = &bmp.pix16(line); + ln2 = &bmp.pix16(line, 1); + double_lines = 1; + } + + if ((line < TMS3556_TOP_BORDER) || (line >= (TMS3556_TOP_BORDER + 250))) + { + /* draw top and bottom borders */ + draw_line_empty(ln); + m_cg_flag=0; // FIXME : forme text mode for 1st line in mixed + } + else + { + /* draw useful area */ + switch (m_control_regs[6] >> 6) + { + case TMS3556_MODE_OFF: + draw_line_empty(ln); + break; + case TMS3556_MODE_TEXT: + draw_line_text(ln); + break; + case TMS3556_MODE_BITMAP: + draw_line_bitmap(ln); + break; + case TMS3556_MODE_MIXED: + draw_line_mixed(ln); + break; + } + } + + if (double_lines) + { + // TODO: this overlaps in exeltel - use memmove for now + //memcpy(ln2, ln, TMS3556_TOTAL_WIDTH * (TMS3556_DOUBLE_WIDTH ? 2 : 1)); + memmove(ln2, ln, TMS3556_TOTAL_WIDTH * (TMS3556_DOUBLE_WIDTH ? 2 : 1)); + } +} + + +//------------------------------------------------- +// interrupt_start_vblank - Do vblank-time tasks +//------------------------------------------------- + +void tms3556_device::interrupt_start_vblank(void) +{ + /* at every frame, vdp switches fields */ + //m_field = !m_field; + + /* color blinking */ + if (m_blink_count) + m_blink_count--; + if (!m_blink_count) + { + m_blink = !m_blink; + m_blink_count = 60; /*no idea what the real value is*/ + } + /* reset background color */ + m_bg_color = (m_control_regs[7] >> 5) & 0x7; + /* reset name offset */ + m_name_offset = 0; + /* reset character line counter */ + m_char_line_counter = 0; + /* reset c/g flag */ + m_cg_flag = 0; + /* reset double height phase flags */ + memset(m_dbl_h_phase, 0, sizeof(m_dbl_h_phase)); +} + + +//------------------------------------------------- +// interrupt - scanline handler +//------------------------------------------------- + +void tms3556_device::interrupt(running_machine &machine) +{ + /* check for start of vblank */ + if (m_scanline == 310) /*no idea what the real value is*/ + interrupt_start_vblank(); + + /* render the current line */ + if ((m_scanline >= 0) && (m_scanline < TMS3556_TOTAL_HEIGHT)) + { + //if (!video_skip_this_frame()) + draw_line(m_bitmap, m_scanline); + } + + if (++m_scanline == 313) + m_scanline = 0; +} diff --git a/src/devices/video/tms3556.h b/src/devices/video/tms3556.h new file mode 100644 index 00000000000..a331b8333e3 --- /dev/null +++ b/src/devices/video/tms3556.h @@ -0,0 +1,139 @@ +// license:BSD-3-Clause +// copyright-holders:Raphael Nabet +/*************************************************************************** + + Texas Instruments TMS3556 Video Display Processor + + ***************************************************************************/ + + +#pragma once + +#ifndef __TMS3556_H__ +#define __TMS3556_H__ + +///************************************************************************* +// MACROS / CONSTANTS +///************************************************************************* + +#define TMS3556_TOP_BORDER 1 +#define TMS3556_BOTTOM_BORDER 1 +#define TMS3556_LEFT_BORDER 8 +#define TMS3556_RIGHT_BORDER 8 +#define TMS3556_TOTAL_WIDTH (320 + TMS3556_LEFT_BORDER + TMS3556_RIGHT_BORDER) +#define TMS3556_TOTAL_HEIGHT (250 + TMS3556_TOP_BORDER + TMS3556_BOTTOM_BORDER) + +/* if DOUBLE_WIDTH set, the horizontal resolution is doubled */ +#define TMS3556_DOUBLE_WIDTH 0 + +#define TMS3556_MODE_OFF 0 +#define TMS3556_MODE_TEXT 1 +#define TMS3556_MODE_BITMAP 2 +#define TMS3556_MODE_MIXED 3 + +#define VDP_POINTER m_control_regs[0] +#define VDP_COL m_control_regs[1] +#define VDP_ROW m_control_regs[2] +#define VDP_STAT m_control_regs[3] +#define VDP_CM1 m_control_regs[4] +#define VDP_CM2 m_control_regs[5] +#define VDP_CM3 m_control_regs[6] +#define VDP_CM4 m_control_regs[7] +#define VDP_BAMT m_address_regs[0] +#define VDP_BAMP m_address_regs[1] +#define VDP_BAPA m_address_regs[2] +#define VDP_BAGC0 m_address_regs[3] +#define VDP_BAGC1 m_address_regs[4] +#define VDP_BAGC2 m_address_regs[5] +#define VDP_BAGC3 m_address_regs[6] +#define VDP_BAMTF m_address_regs[7] + +///************************************************************************* +// INTERFACE CONFIGURATION MACROS +///************************************************************************* + +#define MCFG_TMS3556_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, TMS3556, 0) + +///************************************************************************* +// TYPE DEFINITIONS +///************************************************************************* + +typedef enum { dma_read, dma_write } dma_mode_tt; + + +// ======================> tms3556_device + +class tms3556_device : public device_t, + public device_memory_interface +{ +public: + // construction/destruction + tms3556_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + DECLARE_READ8_MEMBER( vram_r ); + DECLARE_WRITE8_MEMBER( vram_w ); + DECLARE_READ8_MEMBER( reg_r ); + DECLARE_WRITE8_MEMBER( reg_w ); + DECLARE_READ8_MEMBER( initptr_r ); + + void interrupt(running_machine &machine); + + UINT32 screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); + +protected: + // device-level overrides + virtual void device_start(); + + // device_config_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const; + + // address space configurations + const address_space_config m_space_config; + + inline UINT8 readbyte(offs_t address); + inline void writebyte(offs_t address, UINT8 data); + + void draw_line_empty(UINT16 *ln); + void draw_line_text_common(UINT16 *ln); + void draw_line_bitmap_common(UINT16 *ln); + void draw_line_text(UINT16 *ln); + void draw_line_bitmap(UINT16 *ln); + void draw_line_mixed(UINT16 *ln); + void draw_line(bitmap_ind16 &bmp, int line); + void interrupt_start_vblank(void); + +private: + // registers + UINT8 m_control_regs[8]; + UINT16 m_address_regs[8]; + + // register interface + int m_reg_access_phase; + + int m_row_col_written; + int m_bamp_written; + int m_colrow; + dma_mode_tt m_vdp_acmpxy_mode; + UINT16 m_vdp_acmpxy; + UINT16 m_vdp_acmp; + int m_init_read; + + int m_scanline; // scanline counter + int m_blink, m_blink_count; // blinking + int m_bg_color; // background color for current line + int m_name_offset; // current offset in name table + int m_cg_flag; // c/g flag (mixed mode only) + int m_char_line_counter; // character line counter (decrements from 10, 0 when we have reached + // last line of character row) + int m_dbl_h_phase[40]; // double height phase flags (one per horizontal character position) + + bitmap_ind16 m_bitmap; +}; + + +// device type definition +extern const device_type TMS3556; + + +#endif diff --git a/src/devices/video/tms9927.c b/src/devices/video/tms9927.c new file mode 100644 index 00000000000..85c6a178243 --- /dev/null +++ b/src/devices/video/tms9927.c @@ -0,0 +1,326 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/********************************************************************** + + TI TMS9927 and compatible CRT controller emulation + +**********************************************************************/ + +#include "emu.h" +#include "video/tms9927.h" + + +static const UINT8 chars_per_row_value[8] = { 20, 32, 40, 64, 72, 80, 96, 132 }; +static const UINT8 skew_bits_value[4] = { 0, 1, 2, 2 }; + + +#define HCOUNT (m_reg[0] + 1) +#define INTERLACED ((m_reg[1] >> 7) & 0x01) +#define HSYNC_WIDTH ((m_reg[1] >> 4) & 0x0f) +#define HSYNC_DELAY ((m_reg[1] >> 0) & 0x07) +#define SCANS_PER_DATA_ROW (((m_reg[2] >> 3) & 0x0f) + 1) +#define CHARS_PER_DATA_ROW (chars_per_row_value[(m_reg[2] >> 0) & 0x07]) +#define SKEW_BITS (skew_bits_value[(m_reg[3] >> 6) & 0x03]) +#define DATA_ROWS_PER_FRAME (((m_reg[3] >> 0) & 0x3f) + 1) +#define SCAN_LINES_PER_FRAME ((m_reg[4] * 2) + 256) +#define VERTICAL_DATA_START (m_reg[5]) +#define LAST_DISP_DATA_ROW (m_reg[6] & 0x3f) +#define CURSOR_CHAR_ADDRESS (m_reg[7]) +#define CURSOR_ROW_ADDRESS (m_reg[8] & 0x3f) + + +const device_type TMS9927 = &device_creator; +const device_type CRT5027 = &device_creator; +const device_type CRT5037 = &device_creator; +const device_type CRT5057 = &device_creator; + +tms9927_device::tms9927_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, TMS9927, "TMS9927 VTC", tag, owner, clock, "tms9927", __FILE__), + device_video_interface(mconfig, *this), + m_write_vsyn(*this), + m_hpixels_per_column(0), + m_selfload_region(NULL), + m_reset(0) +{ + memset(m_reg, 0x00, sizeof(m_reg)); +} + +tms9927_device::tms9927_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_video_interface(mconfig, *this), + m_write_vsyn(*this), + m_hpixels_per_column(0), + m_selfload_region(NULL), + m_reset(0) +{ + memset(m_reg, 0x00, sizeof(m_reg)); +} + +crt5027_device::crt5027_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : tms9927_device(mconfig, CRT5027, "CRT5027", tag, owner, clock, "crt5027", __FILE__) +{ +} + +crt5037_device::crt5037_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : tms9927_device(mconfig, CRT5037, "CRT5037", tag, owner, clock, "crt5037", __FILE__) +{ +} + +crt5057_device::crt5057_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : tms9927_device(mconfig, CRT5057, "CRT5057", tag, owner, clock, "crt5057", __FILE__) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void tms9927_device::device_start() +{ + assert(clock() > 0); + assert(m_hpixels_per_column > 0); + + /* copy the initial parameters */ + m_clock = clock(); + + /* get the self-load PROM */ + if (m_selfload_region != NULL) + { + m_selfload = machine().root_device().memregion(m_selfload_region)->base(); + assert(m_selfload != NULL); + } + + // resolve callbacks + m_write_vsyn.resolve_safe(); + + // allocate timers + m_vsync_timer = timer_alloc(TIMER_VSYNC); + + /* register for state saving */ + machine().save().register_postload(save_prepost_delegate(FUNC(tms9927_device::state_postload), this)); + + save_item(NAME(m_reg)); + save_item(NAME(m_start_datarow)); + save_item(NAME(m_reset)); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void tms9927_device::device_reset() +{ +} + +//------------------------------------------------- +// device_stop - device-specific stop +//------------------------------------------------- + +void tms9927_device::device_stop() +{ + osd_printf_debug("TMS9937: Final params: (%d, %d, %d, %d, %d, %d, %d)\n", + m_clock, + m_total_hpix, + 0, m_visible_hpix, + m_total_vpix, + 0, m_visible_vpix); +} + + + +//------------------------------------------------- +// device_timer - handle timer events +//------------------------------------------------- + +void tms9927_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch (id) + { + case TIMER_VSYNC: + m_vsyn = !m_vsyn; + + m_write_vsyn(m_vsyn); + + if (m_vsyn) + { + m_vsync_timer->adjust(m_screen->time_until_pos(3)); + } + else + { + m_vsync_timer->adjust(m_screen->time_until_pos(0)); + } + break; + } +} + +void tms9927_device::state_postload() +{ + recompute_parameters(TRUE); +} + + +void tms9927_device::generic_access(address_space &space, offs_t offset) +{ + switch (offset) + { + case 0x07: /* Processor Self Load */ + case 0x0f: /* Non-processor self-load */ + if (m_selfload != NULL) + { + for (int cur = 0; cur < 7; cur++) + write(space, cur, m_selfload[cur]); + for (int cur = 0; cur < 1; cur++) + write(space, cur + 0xc, m_selfload[cur + 7]); + } + else + popmessage("tms9927: self-load initiated with no PROM!"); + + /* processor self-load waits with reset enabled; + non-processor just goes ahead */ + m_reset = (offset == 0x07); + break; + + case 0x0a: /* Reset */ + if (!m_reset) + { + m_screen->update_now(); + m_reset = TRUE; + } + break; + + case 0x0b: /* Up scroll */ +osd_printf_debug("Up scroll\n"); + m_screen->update_now(); + m_start_datarow = (m_start_datarow + 1) % DATA_ROWS_PER_FRAME; + break; + + case 0x0e: /* Start timing chain */ + if (m_reset) + { + m_screen->update_now(); + m_reset = FALSE; + recompute_parameters(FALSE); + } + break; + } +} + + +WRITE8_MEMBER( tms9927_device::write ) +{ + switch (offset) + { + case 0x00: /* HORIZONTAL CHARACTER COUNT */ + case 0x01: /* INTERLACED / HSYNC WIDTH / HSYNC DELAY */ + case 0x02: /* SCANS PER DATA ROW / CHARACTERS PER DATA ROW */ + case 0x03: /* SKEW BITS / DATA ROWS PER FRAME */ + case 0x04: /* SCAN LINES / FRAME */ + case 0x05: /* VERTICAL DATA START */ + case 0x06: /* LAST DISPLAYED DATA ROW */ + m_reg[offset] = data; + recompute_parameters(FALSE); + break; + + case 0x0c: /* LOAD CURSOR CHARACTER ADDRESS */ + case 0x0d: /* LOAD CURSOR ROW ADDRESS */ +osd_printf_debug("Cursor address changed\n"); + m_reg[offset - 0x0c + 7] = data; + recompute_parameters(FALSE); + break; + + default: + generic_access(space, offset); + break; + } +} + + +READ8_MEMBER( tms9927_device::read ) +{ + switch (offset) + { + case 0x08: /* READ CURSOR CHARACTER ADDRESS */ + case 0x09: /* READ CURSOR ROW ADDRESS */ + return m_reg[offset - 0x08 + 7]; + + default: + generic_access(space, offset); + break; + } + return 0xff; +} + + +int tms9927_device::screen_reset() +{ + return m_reset; +} + + +int tms9927_device::upscroll_offset() +{ + return m_start_datarow; +} + + +int tms9927_device::cursor_bounds(rectangle &bounds) +{ + int cursorx = CURSOR_CHAR_ADDRESS; + int cursory = CURSOR_ROW_ADDRESS; + + bounds.min_x = cursorx * m_hpixels_per_column; + bounds.max_x = bounds.min_x + m_hpixels_per_column - 1; + bounds.min_y = cursory * SCANS_PER_DATA_ROW; + bounds.max_y = bounds.min_y + SCANS_PER_DATA_ROW - 1; + + return (cursorx < HCOUNT && cursory <= LAST_DISP_DATA_ROW); +} + + +void tms9927_device::recompute_parameters(int postload) +{ + UINT16 offset_hpix, offset_vpix; + attoseconds_t refresh; + rectangle visarea; + + if (m_reset) + return; + + /* compute the screen sizes */ + m_total_hpix = HCOUNT * m_hpixels_per_column; + m_total_vpix = SCAN_LINES_PER_FRAME; + + /* determine the visible area, avoid division by 0 */ + m_visible_hpix = CHARS_PER_DATA_ROW * m_hpixels_per_column; + m_visible_vpix = (LAST_DISP_DATA_ROW + 1) * SCANS_PER_DATA_ROW; + + /* determine the horizontal/vertical offsets */ + offset_hpix = HSYNC_DELAY * m_hpixels_per_column; + offset_vpix = VERTICAL_DATA_START; + + osd_printf_debug("TMS9937: Total = %dx%d, Visible = %dx%d, Offset=%dx%d, Skew=%d\n", m_total_hpix, m_total_vpix, m_visible_hpix, m_visible_vpix, offset_hpix, offset_vpix, SKEW_BITS); + + /* see if it all makes sense */ + m_valid_config = TRUE; + if (m_visible_hpix > m_total_hpix || m_visible_vpix > m_total_vpix) + { + m_valid_config = FALSE; + logerror("tms9927: invalid visible size (%dx%d) versus total size (%dx%d)\n", m_visible_hpix, m_visible_vpix, m_total_hpix, m_total_vpix); + } + + /* update */ + if (!m_valid_config) + return; + + /* create a visible area */ + /* fix me: how do the offsets fit in here? */ + visarea.set(0, m_visible_hpix - 1, 0, m_visible_vpix - 1); + + refresh = HZ_TO_ATTOSECONDS(m_clock) * m_total_hpix * m_total_vpix; + + m_screen->configure(m_total_hpix, m_total_vpix, visarea, refresh); + + m_vsyn = 0; + m_vsync_timer->adjust(m_screen->time_until_pos(0, 0)); +} diff --git a/src/devices/video/tms9927.h b/src/devices/video/tms9927.h new file mode 100644 index 00000000000..adadf8945cb --- /dev/null +++ b/src/devices/video/tms9927.h @@ -0,0 +1,110 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/********************************************************************** + + TI TMS9927 and compatible CRT controller emulation + +**********************************************************************/ + +#ifndef __TMS9927__ +#define __TMS9927__ + + +#define MCFG_TMS9927_VSYN_CALLBACK(_write) \ + devcb = &tms9927_device::set_vsyn_wr_callback(*device, DEVCB_##_write); + +#define MCFG_TMS9927_CHAR_WIDTH(_pixels) \ + tms9927_device::set_char_width(*device, _pixels); + +#define MCFG_TMS9927_REGION(_tag) \ + tms9927_device::set_region_tag(*device, _tag); + + +class tms9927_device : public device_t, + public device_video_interface +{ +public: + tms9927_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + tms9927_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + ~tms9927_device() {} + + template static devcb_base &set_vsyn_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_vsyn.set_callback(object); } + + static void set_char_width(device_t &device, int pixels) { downcast(device).m_hpixels_per_column = pixels; } + static void set_region_tag(device_t &device, const char *tag) { downcast(device).m_selfload_region = tag; } + + DECLARE_WRITE8_MEMBER(write); + DECLARE_READ8_MEMBER(read); + + int screen_reset(); + int upscroll_offset(); + int cursor_bounds(rectangle &bounds); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_stop(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + +private: + enum + { + TIMER_VSYNC + }; + + void state_postload(); + void recompute_parameters(int postload); + void generic_access(address_space &space, offs_t offset); + + devcb_write_line m_write_vsyn; + int m_hpixels_per_column; /* number of pixels per video memory address */ + const char *m_selfload_region; /* name of the region with self-load data */ + + // internal state + const UINT8 *m_selfload; + + /* live state */ + UINT32 m_clock; + UINT8 m_reg[9]; + UINT8 m_start_datarow; + UINT8 m_reset; + + /* derived state; no need to save */ + UINT8 m_valid_config; + UINT16 m_total_hpix, m_total_vpix; + UINT16 m_visible_hpix, m_visible_vpix; + + int m_vsyn; + + emu_timer *m_vsync_timer; +}; + +extern const device_type TMS9927; + +class crt5027_device : public tms9927_device +{ +public: + crt5027_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +extern const device_type CRT5027; + +class crt5037_device : public tms9927_device +{ +public: + crt5037_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +extern const device_type CRT5037; + +class crt5057_device : public tms9927_device +{ +public: + crt5057_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +extern const device_type CRT5057; + + +#endif diff --git a/src/devices/video/tms9928a.c b/src/devices/video/tms9928a.c new file mode 100644 index 00000000000..8e8b672f8e4 --- /dev/null +++ b/src/devices/video/tms9928a.c @@ -0,0 +1,731 @@ +// license:BSD-3-Clause +// copyright-holders:Sean Young, Nathan Woods, Aaron Giles, Wilbert Pol, hap +/* +** File: tms9928a.c -- software implementation of the Texas Instruments +** TMS9918(A), TMS9928(A) and TMS9929(A), used by the Coleco, MSX and +** TI99/4(A). +** +** All undocumented features as described in the following file +** should be emulated. +** +** http://bifi.msxnet.org/msxnet/tech/tms9918a.txt +** +** By Sean Young 1999 (sean@msxnet.org). +** Based on code by Mike Balfour. +** Improved over the years by MESS and MAME teams. +** +** Todo: +** - External VDP input and sync (pin 34/35 on 9918A) +** - Updates during mid-scanline, probably only used in some MSX1 demos +** - Colours are incorrect. [fixed by R Nabet ?] +** - Sprites 8-31 are ghosted/cloned in mode 3 when using less than +** three pattern tables. Exact behaviour is not known. +** - Address scrambling when setting TMS99xxA to 4K (not on TMS91xx) +*/ + +#include "emu.h" +#include "tms9928a.h" + + +const device_type TMS9928A = &device_creator; +const device_type TMS9918 = &device_creator; +const device_type TMS9918A = &device_creator; +const device_type TMS9118 = &device_creator; +const device_type TMS9128 = &device_creator; +const device_type TMS9929 = &device_creator; +const device_type TMS9929A = &device_creator; +const device_type TMS9129 = &device_creator; + +// ======= Debugging ========= + +// Log register accesses +#define TRACE_REG 0 + +// Log mode settings +#define TRACE_MODE 0 + +// =========================== + +/* + The TMS9928 has an own address space. +*/ +static ADDRESS_MAP_START(memmap, AS_DATA, 8, tms9928a_device) + ADDRESS_MAP_GLOBAL_MASK(0x3fff) + AM_RANGE(0x0000, 0x3fff) AM_RAM +ADDRESS_MAP_END + +tms9928a_device::tms9928a_device( const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, bool is_50hz, bool is_reva, bool is_99, const char *shortname, const char *source) + : device_t( mconfig, type, name, tag, owner, clock, shortname, source), + device_memory_interface(mconfig, *this), + device_video_interface(mconfig, *this), + m_out_int_line_cb(*this), + m_space_config("vram",ENDIANNESS_BIG, 8, 14, 0, NULL, *ADDRESS_MAP_NAME(memmap)) +{ + m_50hz = is_50hz; + m_reva = is_reva; + m_99 = is_99; +// static_set_addrmap(*this, AS_DATA, ADDRESS_MAP_NAME(memmap)); +} + + +tms9928a_device::tms9928a_device( const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock ) + : device_t( mconfig, TMS9928A, "TMS9928A VDP", tag, owner, clock, "tms9928a", __FILE__), + device_memory_interface(mconfig, *this), + device_video_interface(mconfig, *this), + m_vram_size(0), + m_out_int_line_cb(*this), + m_space_config("vram",ENDIANNESS_BIG, 8, 14, 0, NULL, *ADDRESS_MAP_NAME(memmap)) +{ + m_50hz = false; + m_reva = true; + m_99 = true; +// static_set_addrmap(*this, AS_DATA, ADDRESS_MAP_NAME(memmap)); +} + +tms9129_device::tms9129_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : tms9928a_device( mconfig, TMS9129, "TMS9129", tag, owner, clock, true, true, false, "tms9129", __FILE__) +{ } + +tms9918_device::tms9918_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : tms9928a_device( mconfig, TMS9918, "TMS9918", tag, owner, clock, false, false, true, "tms9918", __FILE__) +{ } + +tms9918a_device::tms9918a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : tms9928a_device( mconfig, TMS9918A, "TMS9918A", tag, owner, clock, false, true, true, "tms9918a", __FILE__) +{ } + +tms9118_device::tms9118_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : tms9928a_device( mconfig, TMS9118, "TMS9118 VDP", tag, owner, clock, false, true, false, "tms9118", __FILE__) +{ } + +tms9128_device::tms9128_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : tms9928a_device( mconfig, TMS9128, "TMS9128 VDP", tag, owner, clock, false, true, false, "tms9128", __FILE__) +{ } + +tms9929_device::tms9929_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : tms9928a_device( mconfig, TMS9929, "TMS9929", tag, owner, clock, true, false, true, "tms9929", __FILE__) +{ } + +tms9929a_device::tms9929a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : tms9928a_device( mconfig, TMS9929A, "TMS9929A", tag, owner, clock, true, true, true, "tms9929a", __FILE__) +{ } + + +READ8_MEMBER( tms9928a_device::vram_read ) +{ + // prevent debugger from changing the address base + if (space.debugger_access()) return 0; + + UINT8 data = m_ReadAhead; + + m_ReadAhead = m_vram_space->read_byte(m_Addr); + m_Addr = (m_Addr + 1) & (m_vram_size - 1); + m_latch = 0; + + return data; +} + + +WRITE8_MEMBER( tms9928a_device::vram_write ) +{ + // prevent debugger from changing the address base + if (space.debugger_access()) return; + + m_vram_space->write_byte(m_Addr, data); + m_Addr = (m_Addr + 1) & (m_vram_size - 1); + m_ReadAhead = data; + m_latch = 0; +} + + +READ8_MEMBER( tms9928a_device::register_read ) +{ + // prevent debugger from changing the internal state + if (space.debugger_access()) return 0; + + UINT8 data = m_StatusReg; + + m_StatusReg = m_FifthSprite; + check_interrupt(); + m_latch = 0; + + return data; +} + + +void tms9928a_device::check_interrupt() +{ + // trigger if vblank and interrupt-enable bits are set + UINT8 b = (m_StatusReg & 0x80 && m_Regs[1] & 0x20) ? 1 : 0; + + if (b != m_INT) + { + m_INT = b; + if ( !m_out_int_line_cb.isnull() ) + m_out_int_line_cb( m_INT ); + } +} + + +void tms9928a_device::update_backdrop() +{ + // update backdrop colour to transparent if EXTVID bit is set + if ((m_Regs[7] & 15) == 0) + m_palette[0] = rgb_t(m_Regs[0] & 1 ? 0 : 255,0,0,0); +} + + +void tms9928a_device::update_table_masks() +{ + m_colourmask = ( (m_Regs[3] & 0x7f) << 3 ) | 7; + + // on 91xx family, the colour table mask doesn't affect the pattern table mask + m_patternmask = ( (m_Regs[4] & 3) << 8 ) | ( m_99 ? (m_colourmask & 0xff) : 0xff ); +} + + +void tms9928a_device::change_register(UINT8 reg, UINT8 val) +{ + static const UINT8 Mask[8] = + { 0x03, 0xfb, 0x0f, 0xff, 0x07, 0x7f, 0x07, 0xff }; + static const char *const modes[] = + { + "Mode 0 (GRAPHIC 1)", "Mode 1 (TEXT 1)", "Mode 2 (GRAPHIC 2)", + "Mode 1+2 (TEXT 1 variation)", "Mode 3 (MULTICOLOR)", + "Mode 1+3 (BOGUS)", "Mode 2+3 (MULTICOLOR variation)", + "Mode 1+2+3 (BOGUS)" + }; + + UINT8 prev = m_Regs[reg]; + val &= Mask[reg]; + m_Regs[reg] = val; + + if (TRACE_REG) logerror("TMS9928A('%s'): Reg %d = %02xh\n", tag(), reg, (int)val); + + switch (reg) + { + case 0: + /* re-calculate masks and pattern generator & colour */ + if (val & 2) + { + m_colour = ((m_Regs[3] & 0x80) * 64) & (m_vram_size - 1); + m_pattern = ((m_Regs[4] & 4) * 2048) & (m_vram_size - 1); + update_table_masks(); + } + else + { + m_colour = (m_Regs[3] * 64) & (m_vram_size - 1); + m_pattern = (m_Regs[4] * 2048) & (m_vram_size - 1); + } + m_mode = ( (m_reva ? (m_Regs[0] & 2) : 0) | ((m_Regs[1] & 0x10)>>4) | ((m_Regs[1] & 8)>>1)); + if ((val ^ prev) & 1) + update_backdrop(); + if (TRACE_MODE) logerror("TMS9928A('%s'): %s\n", tag(), modes[m_mode]); + break; + case 1: + check_interrupt(); + m_mode = ( (m_reva ? (m_Regs[0] & 2) : 0) | ((m_Regs[1] & 0x10)>>4) | ((m_Regs[1] & 8)>>1)); + if (TRACE_MODE) logerror("TMS9928A('%s'): %s\n", tag(), modes[m_mode]); + break; + case 2: + m_nametbl = (val * 1024) & (m_vram_size - 1); + break; + case 3: + if (m_Regs[0] & 2) + { + m_colour = ((val & 0x80) * 64) & (m_vram_size - 1); + update_table_masks(); + } + else + { + m_colour = (val * 64) & (m_vram_size - 1); + } + break; + case 4: + if (m_Regs[0] & 2) + { + m_pattern = ((val & 4) * 2048) & (m_vram_size - 1); + update_table_masks(); + } + else + { + m_pattern = (val * 2048) & (m_vram_size - 1); + } + break; + case 5: + m_spriteattribute = (val * 128) & (m_vram_size - 1); + break; + case 6: + m_spritepattern = (val * 2048) & (m_vram_size - 1); + break; + case 7: + if ((val ^ prev) & 15) + update_backdrop(); + break; + } +} + + +WRITE8_MEMBER( tms9928a_device::register_write ) +{ + // prevent debugger from changing the internal state + if (space.debugger_access()) return; + + if (m_latch) + { + /* set high part of read/write address */ + m_Addr = ((data << 8) | (m_Addr & 0xff)) & (m_vram_size - 1); + + if (data & 0x80) + { + /* register write */ + change_register (data & 7, m_Addr & 0xff); + } + else + { + if ( !(data & 0x40) ) + { + /* read ahead */ + vram_read(space, 0); + } + } + m_latch = 0; + } + else + { + /* set low part of read/write address */ + m_Addr = ((m_Addr & 0xff00) | data) & (m_vram_size - 1); + m_latch = 1; + } +} + + +void tms9928a_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + int raw_vpos = m_screen->vpos(); + int vpos = raw_vpos * m_vertical_size / m_screen->height(); + UINT16 BackColour = m_Regs[7] & 15; + UINT32 *p = &m_tmpbmp.pix32(vpos); + + int y = vpos - m_top_border; + + if ( y < 0 || y >= 192 || ! (m_Regs[1] & 0x40) ) + { + /* Draw backdrop colour */ + for ( int i = 0; i < TMS9928A_TOTAL_HORZ; i++ ) + p[i] = m_palette[BackColour]; + + /* vblank is set at the last cycle of the first inactive line */ + if ( y == 193 ) + { + m_StatusReg |= 0x80; + check_interrupt(); + } + } + else + { + /* Draw regular line */ + + /* Left border */ + for ( int i = 0; i < TMS9928A_HORZ_DISPLAY_START; i++ ) + p[i] = m_palette[BackColour]; + + /* Active display */ + + switch( m_mode ) + { + case 0: /* MODE 0 */ + // if (vpos==100 ) popmessage("TMS9928A MODE 0"); + { + UINT16 addr = m_nametbl + ( ( y & 0xF8 ) << 2 ); + + for ( int x = TMS9928A_HORZ_DISPLAY_START; x < TMS9928A_HORZ_DISPLAY_START + 256; x+= 8, addr++ ) + { + UINT8 charcode = m_vram_space->read_byte( addr ); + UINT8 pattern = m_vram_space->read_byte( m_pattern + ( charcode << 3 ) + ( y & 7 ) ); + UINT8 colour = m_vram_space->read_byte( m_colour + ( charcode >> 3 ) ); + rgb_t fg = m_palette[(colour >> 4) ? (colour >> 4) : BackColour]; + rgb_t bg = m_palette[(colour & 15) ? (colour & 15) : BackColour]; + + for ( int i = 0; i < 8; pattern <<= 1, i++ ) + p[x+i] = ( pattern & 0x80 ) ? fg : bg; + } + } + break; + + case 1: /* MODE 1 */ + //if (vpos==100 ) popmessage("TMS9928A MODE 1"); + { + UINT16 addr = m_nametbl + ( ( y >> 3 ) * 40 ); + rgb_t fg = m_palette[(m_Regs[7] >> 4) ? (m_Regs[7] >> 4) : BackColour]; + rgb_t bg = m_palette[BackColour]; + + /* Extra 6 pixels left border */ + for ( int x = TMS9928A_HORZ_DISPLAY_START; x < TMS9928A_HORZ_DISPLAY_START + 6; x++ ) + p[x] = bg; + + for ( int x = TMS9928A_HORZ_DISPLAY_START + 6; x < TMS9928A_HORZ_DISPLAY_START + 246; x+= 6, addr++ ) + { + UINT16 charcode = m_vram_space->read_byte( addr ); + UINT8 pattern = m_vram_space->read_byte( m_pattern + ( charcode << 3 ) + ( y & 7 ) ); + + for ( int i = 0; i < 6; pattern <<= 1, i++ ) + p[x+i] = ( pattern & 0x80 ) ? fg : bg; + } + + /* Extra 10 pixels right border */ + for ( int x = TMS9928A_HORZ_DISPLAY_START + 246; x < TMS9928A_HORZ_DISPLAY_START + 256; x++ ) + p[x] = bg; + } + break; + + case 2: /* MODE 2 */ + //if (vpos==100 ) popmessage("TMS9928A MODE 2"); + { + UINT16 addr = m_nametbl + ( ( y >> 3 ) * 32 ); + + for ( int x = TMS9928A_HORZ_DISPLAY_START; x < TMS9928A_HORZ_DISPLAY_START + 256; x+= 8, addr++ ) + { + UINT16 charcode = m_vram_space->read_byte( addr ) + ( ( y >> 6 ) << 8 ); + UINT8 pattern = m_vram_space->read_byte( m_pattern + ( ( charcode & m_patternmask ) << 3 ) + ( y & 7 ) ); + UINT8 colour = m_vram_space->read_byte( m_colour + ( ( charcode & m_colourmask ) << 3 ) + ( y & 7 ) ); + rgb_t fg = m_palette[(colour >> 4) ? (colour >> 4) : BackColour]; + rgb_t bg = m_palette[(colour & 15) ? (colour & 15) : BackColour]; + + for ( int i = 0; i < 8; pattern <<= 1, i++ ) + p[x+i] = ( pattern & 0x80 ) ? fg : bg; + } + } + break; + + case 3: /* MODE 1+2 */ + //if (vpos==100) popmessage("TMS9928A MODE1+2"); + { + UINT16 addr = m_nametbl + ( ( y >> 3 ) * 40 ); + rgb_t fg = m_palette[(m_Regs[7] >> 4) ? (m_Regs[7] >> 4) : BackColour]; + rgb_t bg = m_palette[BackColour]; + + /* Extra 6 pixels left border */ + for ( int x = TMS9928A_HORZ_DISPLAY_START; x < TMS9928A_HORZ_DISPLAY_START + 6; x++ ) + p[x] = bg; + + for ( int x = TMS9928A_HORZ_DISPLAY_START + 6; x < TMS9928A_HORZ_DISPLAY_START + 246; x+= 6, addr++ ) + { + UINT16 charcode = ( m_vram_space->read_byte( addr ) + ( ( y >> 6 ) << 8 ) ) & m_patternmask; + UINT8 pattern = m_vram_space->read_byte( m_pattern + ( charcode << 3 ) + ( y & 7 ) ); + + for ( int i = 0; i < 6; pattern <<= 1, i++ ) + p[x+i] = ( pattern & 0x80 ) ? fg : bg; + } + + /* Extra 10 pixels right border */ + for ( int x = TMS9928A_HORZ_DISPLAY_START + 246; x < TMS9928A_HORZ_DISPLAY_START + 256; x++ ) + p[x] = bg; + } + break; + + case 4: /* MODE 3 */ + //if (vpos==100 ) popmessage("TMS9928A MODE 3"); + { + UINT16 addr = m_nametbl + ( ( y >> 3 ) * 32 ); + + for ( int x = TMS9928A_HORZ_DISPLAY_START; x < TMS9928A_HORZ_DISPLAY_START + 256; x+= 8, addr++ ) + { + UINT8 charcode = m_vram_space->read_byte( addr ); + UINT8 colour = m_vram_space->read_byte( m_pattern + ( charcode << 3 ) + ( ( y >> 2 ) & 7 ) ); + rgb_t fg = m_palette[(colour >> 4) ? (colour >> 4) : BackColour]; + rgb_t bg = m_palette[(colour & 15) ? (colour & 15) : BackColour]; + + p[x+0] = p[x+1] = p[x+2] = p[x+3] = fg; + p[x+4] = p[x+5] = p[x+6] = p[x+7] = bg; + } + } + break; + + case 5: case 7: /* MODE bogus */ + //if (vpos==100 ) popmessage("TMS9928A MODE bogus"); + { + rgb_t fg = m_palette[(m_Regs[7] >> 4) ? (m_Regs[7] >> 4) : BackColour]; + rgb_t bg = m_palette[BackColour]; + + /* Extra 6 pixels left border */ + for ( int x = TMS9928A_HORZ_DISPLAY_START; x < TMS9928A_HORZ_DISPLAY_START + 6; x++ ) + p[x] = bg; + + for ( int x = TMS9928A_HORZ_DISPLAY_START + 6; x < TMS9928A_HORZ_DISPLAY_START + 246; x+= 6 ) + { + p[x+0] = p[x+1] = p[x+2] = p[x+3] = fg; + p[x+4] = p[x+5] = bg; + } + + /* Extra 10 pixels right border */ + for ( int x = TMS9928A_HORZ_DISPLAY_START + 246; x < TMS9928A_HORZ_DISPLAY_START + 256; x++ ) + p[x] = bg; + } + break; + + case 6: /* MODE 2+3 */ + //if (vpos==100 ) popmessage("TMS9928A MODE 2+3"); + { + UINT16 addr = m_nametbl + ( ( y >> 3 ) * 32 ); + + for ( int x = TMS9928A_HORZ_DISPLAY_START; x < TMS9928A_HORZ_DISPLAY_START + 256; x+= 8, addr++ ) + { + UINT8 charcode = m_vram_space->read_byte( addr ); + UINT8 colour = m_vram_space->read_byte( m_pattern + ( ( ( charcode + ( ( y >> 2 ) & 7 ) + ( ( y >> 6 ) << 8 ) ) & m_patternmask ) << 3 ) ); + rgb_t fg = m_palette[(colour >> 4) ? (colour >> 4) : BackColour]; + rgb_t bg = m_palette[(colour & 15) ? (colour & 15) : BackColour]; + + p[x+0] = p[x+1] = p[x+2] = p[x+3] = fg; + p[x+4] = p[x+5] = p[x+6] = p[x+7] = bg; + } + } + break; + } + + /* Draw sprites */ + if ( ( m_Regs[1] & 0x50 ) != 0x40 ) + { + /* sprites are disabled */ + m_FifthSprite = 31; + } + else + { + UINT8 sprite_size = ( m_Regs[1] & 0x02 ) ? 16 : 8; + UINT8 sprite_mag = m_Regs[1] & 0x01; + UINT8 sprite_height = sprite_size * ( sprite_mag + 1 ); + UINT8 spr_drawn[32+256+32] = { 0 }; + UINT8 num_sprites = 0; + bool fifth_encountered = false; + + for ( UINT16 sprattr = 0; sprattr < 128; sprattr += 4 ) + { + int spr_y = m_vram_space->read_byte( m_spriteattribute + sprattr + 0 ); + + m_FifthSprite = sprattr / 4; + + /* Stop processing sprites */ + if ( spr_y == 208 ) + break; + + if ( spr_y > 0xE0 ) + spr_y -= 256; + + /* vert pos 255 is displayed on the first line of the screen */ + spr_y++; + + /* is sprite enabled on this line? */ + if ( spr_y <= y && y < spr_y + sprite_height ) + { + int spr_x = m_vram_space->read_byte( m_spriteattribute + sprattr + 1 ); + UINT8 sprcode = m_vram_space->read_byte( m_spriteattribute + sprattr + 2 ); + UINT8 sprcol = m_vram_space->read_byte( m_spriteattribute + sprattr + 3 ); + UINT16 pataddr = m_spritepattern + ( ( sprite_size == 16 ) ? sprcode & ~0x03 : sprcode ) * 8; + + num_sprites++; + + /* Fifth sprite encountered? */ + if ( num_sprites == 5 ) + { + fifth_encountered = true; + break; + } + + if ( sprite_mag ) + pataddr += ( ( ( y - spr_y ) & 0x1F ) >> 1 ); + else + pataddr += ( ( y - spr_y ) & 0x0F ); + + UINT8 pattern = m_vram_space->read_byte( pataddr ); + + if ( sprcol & 0x80 ) + spr_x -= 32; + + sprcol &= 0x0f; + + for ( int s = 0; s < sprite_size; s += 8 ) + { + for ( int i = 0; i < 8; pattern <<= 1, i++ ) + { + int colission_index = spr_x + ( sprite_mag ? i * 2 : i ) + 32; + + for ( int z = 0; z <= sprite_mag; colission_index++, z++ ) + { + /* Check if pixel should be drawn */ + if ( pattern & 0x80 ) + { + if ( colission_index >= 32 && colission_index < 32 + 256 ) + { + /* Check for colission */ + if ( spr_drawn[ colission_index ] ) + m_StatusReg |= 0x20; + spr_drawn[ colission_index ] |= 0x01; + + if ( sprcol ) + { + /* Has another sprite already drawn here? */ + if ( ! ( spr_drawn[ colission_index ] & 0x02 ) ) + { + spr_drawn[ colission_index ] |= 0x02; + p[ TMS9928A_HORZ_DISPLAY_START + colission_index - 32 ] = m_palette[sprcol]; + } + } + } + } + } + } + + pattern = m_vram_space->read_byte( pataddr + 16 ); + spr_x += sprite_mag ? 16 : 8; + } + } + } + + /* Update sprite overflow bits */ + if (~m_StatusReg & 0x40) + { + m_StatusReg = (m_StatusReg & 0xe0) | m_FifthSprite; + if (fifth_encountered && ~m_StatusReg & 0x80) + m_StatusReg |= 0x40; + } + } + + /* Right border */ + for ( int i = TMS9928A_HORZ_DISPLAY_START + 256; i < TMS9928A_TOTAL_HORZ; i++ ) + p[i] = m_palette[BackColour]; + } + + /* Schedule next callback */ + m_line_timer->adjust( m_screen->time_until_pos( ( raw_vpos + 1 ) % m_screen->height() , TMS9928A_HORZ_DISPLAY_START ) ); +} + + +UINT32 tms9928a_device::screen_update( screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect ) +{ + copybitmap( bitmap, m_tmpbmp, 0, 0, 0, 0, cliprect ); + return 0; +} + +void tms9928a_device::set_palette() +{ + /* + New palette (R. Nabet). + + First 3 columns from TI datasheet (in volts). + Next 3 columns based on formula : + Y = .299*R + .587*G + .114*B (NTSC) + (the coefficients are likely to be slightly different with PAL, but who cares ?) + I assumed the "zero" for R-Y and B-Y was 0.47V. + Last 3 coeffs are the 8-bit values. + + Color Y R-Y B-Y R G B R G B + 0 Transparent + 1 Black 0.00 0.47 0.47 0.00 0.00 0.00 0 0 0 + 2 Medium green 0.53 0.07 0.20 0.13 0.79 0.26 33 200 66 + 3 Light green 0.67 0.17 0.27 0.37 0.86 0.47 94 220 120 + 4 Dark blue 0.40 0.40 1.00 0.33 0.33 0.93 84 85 237 + 5 Light blue 0.53 0.43 0.93 0.49 0.46 0.99 125 118 252 + 6 Dark red 0.47 0.83 0.30 0.83 0.32 0.30 212 82 77 + 7 Cyan 0.73 0.00 0.70 0.26 0.92 0.96 66 235 245 + 8 Medium red 0.53 0.93 0.27 0.99 0.33 0.33 252 85 84 + 9 Light red 0.67 0.93 0.27 1.13(!) 0.47 0.47 255 121 120 + A Dark yellow 0.73 0.57 0.07 0.83 0.76 0.33 212 193 84 + B Light yellow 0.80 0.57 0.17 0.90 0.81 0.50 230 206 128 + C Dark green 0.47 0.13 0.23 0.13 0.69 0.23 33 176 59 + D Magenta 0.53 0.73 0.67 0.79 0.36 0.73 201 91 186 + E Gray 0.80 0.47 0.47 0.80 0.80 0.80 204 204 204 + F White 1.00 0.47 0.47 1.00 1.00 1.00 255 255 255 + */ + static const rgb_t tms9928a_palette[TMS9928A_PALETTE_SIZE] = + { + rgb_t::black, + rgb_t::black, + rgb_t(33, 200, 66), + rgb_t(94, 220, 120), + rgb_t(84, 85, 237), + rgb_t(125, 118, 252), + rgb_t(212, 82, 77), + rgb_t(66, 235, 245), + rgb_t(252, 85, 84), + rgb_t(255, 121, 120), + rgb_t(212, 193, 84), + rgb_t(230, 206, 128), + rgb_t(33, 176, 59), + rgb_t(201, 91, 186), + rgb_t(204, 204, 204), + rgb_t::white + }; + + /* copy default palette into working palette */ + for (int i = 0; i < TMS9928A_PALETTE_SIZE; i++) + { + m_palette[i] = tms9928a_palette[i]; + } +} + +void tms9928a_device::device_start() +{ + m_top_border = m_50hz ? TMS9928A_VERT_DISPLAY_START_PAL : TMS9928A_VERT_DISPLAY_START_NTSC; + m_vertical_size = m_50hz ? TMS9928A_TOTAL_VERT_PAL : TMS9928A_TOTAL_VERT_NTSC; + + m_out_int_line_cb.resolve(); + + // Video RAM is allocated as an own address space + m_vram_space = &space(AS_DATA); + + /* back bitmap */ + m_tmpbmp.allocate(TMS9928A_TOTAL_HORZ, TMS9928A_TOTAL_VERT_PAL); + + m_line_timer = timer_alloc(TIMER_LINE); + + set_palette(); + + save_item(NAME(m_Regs[0])); + save_item(NAME(m_Regs[1])); + save_item(NAME(m_Regs[2])); + save_item(NAME(m_Regs[3])); + save_item(NAME(m_Regs[4])); + save_item(NAME(m_Regs[5])); + save_item(NAME(m_Regs[6])); + save_item(NAME(m_Regs[7])); + save_item(NAME(m_StatusReg)); + save_item(NAME(m_FifthSprite)); + save_item(NAME(m_ReadAhead)); + save_item(NAME(m_latch)); + save_item(NAME(m_Addr)); + save_item(NAME(m_INT)); +// save_pointer(NAME(m_vMem), m_vram_size); + save_item(NAME(m_colour)); + save_item(NAME(m_colourmask)); + save_item(NAME(m_pattern)); + save_item(NAME(m_patternmask)); + save_item(NAME(m_nametbl)); + save_item(NAME(m_spriteattribute)); + save_item(NAME(m_spritepattern)); + save_item(NAME(m_mode)); + save_item(NAME(m_palette)); +} + + +void tms9928a_device::device_reset() +{ + for ( int i = 0; i < 8; i++ ) + m_Regs[i] = 0; + + m_StatusReg = 0; + m_FifthSprite = 31; + m_nametbl = 0; + m_pattern = 0; + m_colour = 0; + m_spritepattern = 0; + m_spriteattribute = 0; + m_colourmask = 0x3fff; + m_patternmask = 0x3fff; + m_Addr = 0; + m_ReadAhead = 0; + m_INT = 0; + m_latch = 0; + m_mode = 0; + + m_line_timer->adjust( m_screen->time_until_pos( 0, TMS9928A_HORZ_DISPLAY_START ) ); +} diff --git a/src/devices/video/tms9928a.h b/src/devices/video/tms9928a.h new file mode 100644 index 00000000000..b87807782d1 --- /dev/null +++ b/src/devices/video/tms9928a.h @@ -0,0 +1,207 @@ +// license:BSD-3-Clause +// copyright-holders:Sean Young, Nathan Woods, Aaron Giles, Wilbert Pol, hap +/* +** File: tms9928a.h -- software implementation of the TMS9928A VDP. +** +** By Sean Young 1999 (sean@msxnet.org). +*/ + +/* + + Model Video Hz + + TMS9918 NTSC 60 + TMS9929? YPbPr? 50 (not sure. 50Hz non-A model, used in Creativision? or was it a 3rd party clone chip?) + + TMS9918A NTSC 60 + TMS9928A YPbPr 60 + TMS9929A YPbPr 50 + + TMS9118 NTSC 60 + TMS9128 YPbPr 60 + TMS9129 YPbPr 50 + +*/ + +#ifndef __TMS9928A_H__ +#define __TMS9928A_H__ + +#include "emu.h" + + +#define TMS9928A_PALETTE_SIZE 16 + + +/* Some defines used in defining the screens */ +#define TMS9928A_TOTAL_HORZ 342 +#define TMS9928A_TOTAL_VERT_NTSC 262 +#define TMS9928A_TOTAL_VERT_PAL 313 + +#define TMS9928A_HORZ_DISPLAY_START (2 + 14 + 8 + 13) +#define TMS9928A_VERT_DISPLAY_START_PAL (13 + 51) +#define TMS9928A_VERT_DISPLAY_START_NTSC (13 + 27) + +// MCFG_DEVICE_ADD(_tag, _variant, XTAL_10_738635MHz / 2 ) + +#define MCFG_TMS9928A_VRAM_SIZE(_size) \ + tms9928a_device::set_vram_size(*device, _size); + +#define MCFG_TMS9928A_OUT_INT_LINE_CB(_devcb) \ + devcb = &tms9928a_device::set_out_int_line_callback(*device, DEVCB_##_devcb); + +#define MCFG_TMS9928A_SET_SCREEN MCFG_VIDEO_SET_SCREEN + + +#define MCFG_TMS9928A_SCREEN_ADD_NTSC(_screen_tag) \ + MCFG_VIDEO_SET_SCREEN(_screen_tag) \ + MCFG_SCREEN_ADD( _screen_tag, RASTER ) \ + MCFG_SCREEN_RAW_PARAMS( XTAL_10_738635MHz / 2, TMS9928A_TOTAL_HORZ, TMS9928A_HORZ_DISPLAY_START-12, TMS9928A_HORZ_DISPLAY_START + 256 + 12, \ + TMS9928A_TOTAL_VERT_NTSC, TMS9928A_VERT_DISPLAY_START_NTSC - 12, TMS9928A_VERT_DISPLAY_START_NTSC + 192 + 12 ) + + +#define MCFG_TMS9928A_SCREEN_ADD_PAL(_screen_tag) \ + MCFG_VIDEO_SET_SCREEN(_screen_tag) \ + MCFG_SCREEN_ADD(_screen_tag, RASTER ) \ + MCFG_SCREEN_RAW_PARAMS( XTAL_10_738635MHz / 2, TMS9928A_TOTAL_HORZ, TMS9928A_HORZ_DISPLAY_START-12, TMS9928A_HORZ_DISPLAY_START + 256 + 12, \ + TMS9928A_TOTAL_VERT_PAL, TMS9928A_VERT_DISPLAY_START_PAL - 12, TMS9928A_VERT_DISPLAY_START_PAL + 192 + 12 ) + + +extern const device_type TMS9918; +extern const device_type TMS9918A; +extern const device_type TMS9118; +extern const device_type TMS9928A; +extern const device_type TMS9128; +extern const device_type TMS9929; +extern const device_type TMS9929A; +extern const device_type TMS9129; + + +class tms9928a_device : public device_t, + public device_memory_interface, + public device_video_interface +{ +public: + // construction/destruction + tms9928a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + tms9928a_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, bool is_50hz, bool is_reva, bool is_99, const char *shortname, const char *source); + + static void set_vram_size(device_t &device, int vram_size) { downcast(device).m_vram_size = vram_size; } + template static devcb_base &set_out_int_line_callback(device_t &device, _Object object) { return downcast(device).m_out_int_line_cb.set_callback(object); } + + DECLARE_READ8_MEMBER( vram_read ); + DECLARE_WRITE8_MEMBER( vram_write ); + DECLARE_READ8_MEMBER( register_read ); + DECLARE_WRITE8_MEMBER( register_write ); + + /* update the screen */ + UINT32 screen_update( screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect ); + bitmap_rgb32 &get_bitmap() { return m_tmpbmp; } + + /* RESET pin */ + void reset_line(int state) { if (state==ASSERT_LINE) device_reset(); } + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_DATA) const { return (spacenum == AS_DATA) ? &m_space_config : NULL; } + +private: + void change_register(UINT8 reg, UINT8 val); + void check_interrupt(); + void update_backdrop(); + void update_table_masks(); + void set_palette(); + + static const device_timer_id TIMER_LINE = 0; + + int m_vram_size; /* 4K, 8K, or 16K. This should be replaced by fetching data from an address space? */ + devcb_write_line m_out_int_line_cb; /* Callback is called whenever the state of the INT output changes */ + + /* TMS9928A internal settings */ + UINT8 m_ReadAhead; + UINT8 m_Regs[8]; + UINT8 m_StatusReg; + UINT8 m_FifthSprite; + UINT8 m_latch; + UINT8 m_INT; + UINT16 m_Addr; + UINT16 m_colour; + UINT16 m_pattern; + UINT16 m_nametbl; + UINT16 m_spriteattribute; + UINT16 m_spritepattern; + int m_colourmask; + int m_patternmask; + bool m_50hz; + bool m_reva; + bool m_99; + rgb_t m_palette[16]; + + /* memory */ + const address_space_config m_space_config; + address_space* m_vram_space; + + bitmap_rgb32 m_tmpbmp; + emu_timer *m_line_timer; + UINT8 m_mode; + + /* emulation settings */ + int m_top_border; + int m_vertical_size; +}; + + +class tms9918_device : public tms9928a_device +{ +public: + tms9918_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +class tms9918a_device : public tms9928a_device +{ +public: + tms9918a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +class tms9118_device : public tms9928a_device +{ +public: + tms9118_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +class tms9128_device : public tms9928a_device +{ +public: + tms9128_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +class tms9929_device : public tms9928a_device +{ +public: + tms9929_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +class tms9929a_device : public tms9928a_device +{ +public: + tms9929a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +class tms9129_device : public tms9928a_device +{ +public: + tms9129_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +#endif diff --git a/src/devices/video/upd3301.c b/src/devices/video/upd3301.c new file mode 100644 index 00000000000..8370f52c85c --- /dev/null +++ b/src/devices/video/upd3301.c @@ -0,0 +1,635 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + NEC uPD3301 Programmable CRT Controller emulation + +**********************************************************************/ + +/* + + TODO: + + - attributes + - N interrupt + - light pen + - reset counters + - proper DMA timing (now the whole screen is transferred at the end of the frame, + accurate timing requires CCLK timer which kills performance) + +*/ + +#include "upd3301.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define LOG 0 + + +#define COMMAND_MASK 0xe0 +#define COMMAND_RESET 0x00 +#define COMMAND_START_DISPLAY 0x20 +#define COMMAND_SET_INTERRUPT_MASK 0x40 +#define COMMAND_READ_LIGHT_PEN 0x60 // not supported +#define COMMAND_LOAD_CURSOR_POSITION 0x80 +#define COMMAND_RESET_INTERRUPT 0xa0 +#define COMMAND_RESET_COUNTERS 0xc0 // not supported + + +#define STATUS_VE 0x10 +#define STATUS_U 0x08 // not supported +#define STATUS_N 0x04 // not supported +#define STATUS_E 0x02 +#define STATUS_LP 0x01 // not supported + + +enum +{ + MODE_NONE, + MODE_RESET, + MODE_READ_LIGHT_PEN, + MODE_LOAD_CURSOR_POSITION, + MODE_RESET_COUNTERS +}; + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type UPD3301 = &device_creator; + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// upd3301_device - constructor +//------------------------------------------------- + +upd3301_device::upd3301_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, UPD3301, "UPD3301", tag, owner, clock, "upd3301", __FILE__), + device_video_interface(mconfig, *this), + m_write_int(*this), + m_write_drq(*this), + m_write_hrtc(*this), + m_write_vrtc(*this), + m_width(0), + m_status(0), + m_param_count(0), + m_data_fifo_pos(0), + m_attr_fifo_pos(0), + m_input_fifo(0), + m_me(0), + m_h(80), + m_l(20), + m_r(10), + m_v(6), + m_z(32), + m_attr_blink(0), + m_attr_frame(0), + m_cm(0), + m_cx(0), + m_cy(0), + m_cursor_blink(0), + m_cursor_frame(0) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void upd3301_device::device_start() +{ + // resolve callbacks + m_display_cb.bind_relative_to(*owner()); + m_write_drq.resolve_safe(); + m_write_int.resolve_safe(); + m_write_hrtc.resolve_safe(); + m_write_vrtc.resolve_safe(); + + // allocate timers + m_hrtc_timer = timer_alloc(TIMER_HRTC); + m_vrtc_timer = timer_alloc(TIMER_VRTC); + m_drq_timer = timer_alloc(TIMER_DRQ); + + // state saving + save_item(NAME(m_y)); + save_item(NAME(m_hrtc)); + save_item(NAME(m_vrtc)); + save_item(NAME(m_mode)); + save_item(NAME(m_status)); + save_item(NAME(m_param_count)); + save_item(NAME(m_data_fifo_pos)); + save_item(NAME(m_attr_fifo_pos)); + save_item(NAME(m_input_fifo)); + save_item(NAME(m_mn)); + save_item(NAME(m_me)); + save_item(NAME(m_dma_mode)); + save_item(NAME(m_h)); + save_item(NAME(m_b)); + save_item(NAME(m_l)); + save_item(NAME(m_s)); + save_item(NAME(m_c)); + save_item(NAME(m_r)); + save_item(NAME(m_v)); + save_item(NAME(m_z)); + save_item(NAME(m_at1)); + save_item(NAME(m_at0)); + save_item(NAME(m_sc)); + save_item(NAME(m_attr)); + save_item(NAME(m_attr_blink)); + save_item(NAME(m_attr_frame)); + save_item(NAME(m_cm)); + save_item(NAME(m_cx)); + save_item(NAME(m_cy)); + save_item(NAME(m_cursor_blink)); + save_item(NAME(m_cursor_frame)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void upd3301_device::device_reset() +{ + set_interrupt(0); + set_drq(0); + + recompute_parameters(); +} + + +//------------------------------------------------- +// device_clock_changed - handle clock change +//------------------------------------------------- + +void upd3301_device::device_clock_changed() +{ + recompute_parameters(); +} + + +//------------------------------------------------- +// device_timer - handle timer events +//------------------------------------------------- + +void upd3301_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch (id) + { + case TIMER_HRTC: + if (LOG) logerror("UPD3301 '%s' HRTC: %u\n", tag(), param); + + m_write_hrtc(param); + m_hrtc = param; + + update_hrtc_timer(param); + break; + + case TIMER_VRTC: + if (LOG) logerror("UPD3301 '%s' VRTC: %u\n", tag(), param); + + m_write_vrtc(param); + m_vrtc = param; + + if (param && !m_me) + { + m_status |= STATUS_E; + set_interrupt(1); + } + + update_vrtc_timer(param); + break; + + case TIMER_DRQ: + break; + } +} + + +//------------------------------------------------- +// read - +//------------------------------------------------- + +READ8_MEMBER( upd3301_device::read ) +{ + UINT8 data = 0; + + switch (offset & 0x01) + { + case 0: // data + break; + + case 1: // status + data = m_status; + m_status &= ~(STATUS_LP | STATUS_E |STATUS_N | STATUS_U); + break; + } + + return data; +} + + +//------------------------------------------------- +// write - +//------------------------------------------------- + +WRITE8_MEMBER( upd3301_device::write ) +{ + switch (offset & 0x01) + { + case 0: // data + switch (m_mode) + { + case MODE_RESET: + switch (m_param_count) + { + case 0: + m_dma_mode = BIT(data, 7); + m_h = (data & 0x7f) + 2; + if (LOG) logerror("UPD3301 '%s' DMA Mode: %s\n", tag(), m_dma_mode ? "character" : "burst"); + if (LOG) logerror("UPD3301 '%s' H: %u\n", tag(), m_h); + break; + + case 1: + m_b = ((data >> 6) + 1) * 16; + m_l = (data & 0x3f) + 1; + if (LOG) logerror("UPD3301 '%s' B: %u\n", tag(), m_b); + if (LOG) logerror("UPD3301 '%s' L: %u\n", tag(), m_l); + break; + + case 2: + m_s = BIT(data, 7); + m_c = (data >> 4) & 0x03; + m_r = (data & 0x1f) + 1; + if (LOG) logerror("UPD3301 '%s' S: %u\n", tag(), m_s); + if (LOG) logerror("UPD3301 '%s' C: %u\n", tag(), m_c); + if (LOG) logerror("UPD3301 '%s' R: %u\n", tag(), m_r); + break; + + case 3: + m_v = (data >> 5) + 1; + m_z = (data & 0x1f) + 2; + if (LOG) logerror("UPD3301 '%s' V: %u\n", tag(), m_v); + if (LOG) logerror("UPD3301 '%s' Z: %u\n", tag(), m_z); + recompute_parameters(); + break; + + case 4: + m_at1 = BIT(data, 7); + m_at0 = BIT(data, 6); + m_sc = BIT(data, 5); + m_attr = (data & 0x1f) + 1; + if (LOG) logerror("UPD3301 '%s' AT1: %u\n", tag(), m_at1); + if (LOG) logerror("UPD3301 '%s' AT0: %u\n", tag(), m_at0); + if (LOG) logerror("UPD3301 '%s' SC: %u\n", tag(), m_sc); + if (LOG) logerror("UPD3301 '%s' ATTR: %u\n", tag(), m_attr); + + m_mode = MODE_NONE; + break; + } + + m_param_count++; + break; + + case MODE_LOAD_CURSOR_POSITION: + switch (m_param_count) + { + case 0: + m_cx = data & 0x7f; + if (LOG) logerror("UPD3301 '%s' CX: %u\n", tag(), m_cx); + break; + + case 1: + m_cy = data & 0x3f; + if (LOG) logerror("UPD3301 '%s' CY: %u\n", tag(), m_cy); + + m_mode = MODE_NONE; + break; + } + + m_param_count++; + break; + + default: + if (LOG) logerror("UPD3301 '%s' Invalid Parameter Byte %02x!\n", tag(), data); + } + break; + + case 1: // command + m_mode = MODE_NONE; + m_param_count = 0; + + switch (data & 0xe0) + { + case COMMAND_RESET: + if (LOG) logerror("UPD3301 '%s' Reset\n", tag()); + m_mode = MODE_RESET; + set_display(0); + set_interrupt(0); + break; + + case COMMAND_START_DISPLAY: + if (LOG) logerror("UPD3301 '%s' Start Display\n", tag()); + set_display(1); + reset_counters(); + break; + + case COMMAND_SET_INTERRUPT_MASK: + if (LOG) logerror("UPD3301 '%s' Set Interrupt Mask\n", tag()); + m_me = BIT(data, 0); + m_mn = BIT(data, 1); + if (LOG) logerror("UPD3301 '%s' ME: %u\n", tag(), m_me); + if (LOG) logerror("UPD3301 '%s' MN: %u\n", tag(), m_mn); + break; + + case COMMAND_READ_LIGHT_PEN: + if (LOG) logerror("UPD3301 '%s' Read Light Pen\n", tag()); + m_mode = MODE_READ_LIGHT_PEN; + break; + + case COMMAND_LOAD_CURSOR_POSITION: + if (LOG) logerror("UPD3301 '%s' Load Cursor Position\n", tag()); + m_mode = MODE_LOAD_CURSOR_POSITION; + m_cm = BIT(data, 0); + if (LOG) logerror("UPD3301 '%s' CM: %u\n", tag(), m_cm); + break; + + case COMMAND_RESET_INTERRUPT: + if (LOG) logerror("UPD3301 '%s' Reset Interrupt\n", tag()); + set_interrupt(0); + break; + + case COMMAND_RESET_COUNTERS: + if (LOG) logerror("UPD3301 '%s' Reset Counters\n", tag()); + m_mode = MODE_RESET_COUNTERS; + reset_counters(); + break; + } + break; + } +} + + +//------------------------------------------------- +// dack_w - +//------------------------------------------------- + +WRITE8_MEMBER( upd3301_device::dack_w ) +{ + if (m_y >= (m_l * m_r)) + { + return; + } + + if (m_data_fifo_pos < m_h) + { + m_data_fifo[m_data_fifo_pos][m_input_fifo] = data; + m_data_fifo_pos++; + } + else + { + m_attr_fifo[m_attr_fifo_pos][m_input_fifo] = data; + m_attr_fifo_pos++; + } + + if ((m_data_fifo_pos == m_h) && (m_attr_fifo_pos == (m_attr << 1))) + { + m_input_fifo = !m_input_fifo; + + m_data_fifo_pos = 0; + m_attr_fifo_pos = 0; + + draw_scanline(); + + if (m_y == (m_l * m_r)) + { + // end DMA transfer + set_drq(0); + } + } +} + + +//------------------------------------------------- +// lpen_w - +//------------------------------------------------- + +WRITE_LINE_MEMBER( upd3301_device::lpen_w ) +{ +} + + +//------------------------------------------------- +// hrtc_r - +//------------------------------------------------- + +READ_LINE_MEMBER( upd3301_device::hrtc_r ) +{ + return m_hrtc; +} + + +//------------------------------------------------- +// vrtc_r - +//------------------------------------------------- + +READ_LINE_MEMBER( upd3301_device::vrtc_r ) +{ + return m_vrtc; +} + + +//------------------------------------------------- +// draw_scanline - +//------------------------------------------------- + +void upd3301_device::draw_scanline() +{ + for (int lc = 0; lc < m_r; lc++) + { + for (int sx = 0; sx < m_h; sx++) + { + int y = m_y + lc; + UINT8 cc = m_data_fifo[sx][!m_input_fifo]; + int hlgt = 0; // TODO + int rvv = 0; // TODO + int vsp = 0; // TODO + int sl0 = 0; // TODO + int sl12 = 0; // TODO + int csr = m_cm && m_cursor_blink && ((y / m_r) == m_cy) && (sx == m_cx); + int gpa = 0; // TODO + + m_display_cb(*m_bitmap, y, sx, cc, lc, hlgt, rvv, vsp, sl0, sl12, csr, gpa); + } + } + + m_y += m_r; +} + + +//------------------------------------------------- +// update_screen - +//------------------------------------------------- + +UINT32 upd3301_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + if (m_status & STATUS_VE) + { + m_y = 0; + m_bitmap = &bitmap; + m_data_fifo_pos = 0; + m_attr_fifo_pos = 0; + + m_cursor_frame++; + + if (m_cursor_frame == m_b) + { + m_cursor_frame = 0; + m_cursor_blink = !m_cursor_blink; + } + + m_attr_frame++; + + if (m_attr_frame == (m_b << 1)) + { + m_attr_frame = 0; + m_attr_blink = !m_attr_blink; + } + + // start DMA transfer + set_drq(1); + } + else + { + bitmap.fill(rgb_t(0x00,0x00,0x00), cliprect); + } + return 0; +} + + +//------------------------------------------------- +// set_interrupt - +//------------------------------------------------- + +void upd3301_device::set_interrupt(int state) +{ + if (LOG) logerror("UPD3301 '%s' Interrupt: %u\n", tag(), state); + + m_write_int(state); + + if (!state) + { + m_status &= ~(STATUS_N | STATUS_E); + } +} + + +//------------------------------------------------- +// set_drq - +//------------------------------------------------- + +void upd3301_device::set_drq(int state) +{ + if (LOG) logerror("UPD3301 '%s' DRQ: %u\n", tag(), state); + + m_write_drq(state); +} + + +//------------------------------------------------- +// set_display - +//------------------------------------------------- + +void upd3301_device::set_display(int state) +{ + if (state) + { + m_status |= STATUS_VE; + } + else + { + m_status &= ~STATUS_VE; + } +} + + +//------------------------------------------------- +// reset_counters - +//------------------------------------------------- + +void upd3301_device::reset_counters() +{ + set_interrupt(0); + set_drq(0); +} + + +//------------------------------------------------- +// update_hrtc_timer - +//------------------------------------------------- + +void upd3301_device::update_hrtc_timer(int state) +{ + int y = m_screen->vpos(); + + int next_x = state ? m_h : 0; + int next_y = state ? y : ((y + 1) % ((m_l + m_v) * m_width)); + + attotime duration = m_screen->time_until_pos(next_y, next_x); + + m_hrtc_timer->adjust(duration, !state); +} + + +//------------------------------------------------- +// update_vrtc_timer - +//------------------------------------------------- + +void upd3301_device::update_vrtc_timer(int state) +{ + int next_y = state ? (m_l * m_r) : 0; + + attotime duration = m_screen->time_until_pos(next_y, 0); + + m_vrtc_timer->adjust(duration, !state); +} + + +//------------------------------------------------- +// recompute_parameters - +//------------------------------------------------- + +void upd3301_device::recompute_parameters() +{ + int horiz_pix_total = (m_h + m_z) * m_width; + int vert_pix_total = (m_l + m_v) * m_r; + + attoseconds_t refresh = HZ_TO_ATTOSECONDS(clock()) * horiz_pix_total * vert_pix_total; + + rectangle visarea; + + visarea.set(0, (m_h * m_width) - 1, 0, (m_l * m_r) - 1); + + if (LOG) + { + if (LOG) logerror("UPD3301 '%s' Screen: %u x %u @ %f Hz\n", tag(), horiz_pix_total, vert_pix_total, 1 / ATTOSECONDS_TO_DOUBLE(refresh)); + if (LOG) logerror("UPD3301 '%s' Visible Area: (%u, %u) - (%u, %u)\n", tag(), visarea.min_x, visarea.min_y, visarea.max_x, visarea.max_y); + } + + m_screen->configure(horiz_pix_total, vert_pix_total, visarea, refresh); + + update_hrtc_timer(0); + update_vrtc_timer(0); +} diff --git a/src/devices/video/upd3301.h b/src/devices/video/upd3301.h new file mode 100644 index 00000000000..cef42e08627 --- /dev/null +++ b/src/devices/video/upd3301.h @@ -0,0 +1,194 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + NEC uPD3301 Programmable CRT Controller emulation + +********************************************************************** + _____ _____ + VRTC 1 |* \_/ | 40 Vcc + RVV 2 | | 39 SL0 + CSR 3 | | 38 LC0 + LPEN 4 | | 37 LC1 + INT 5 | | 36 LC2 + DRQ 6 | | 35 LC3 + _DACK 7 | | 34 VSP + A0 8 | | 33 SL12 + _RD 9 | | 32 GPA + _WR 10 | uPD3301 | 31 HLGT + _CS 11 | | 30 CC7 + DB0 12 | | 29 CC6 + DB1 13 | | 28 CC5 + DB2 14 | | 27 CC4 + DB3 15 | | 26 CC3 + DB4 16 | | 25 CC2 + DB5 17 | | 24 CC1 + DB6 18 | | 23 CC0 + DB7 19 | | 22 CCLK + GND 20 |_____________| 21 HRTC + +**********************************************************************/ + +#pragma once + +#ifndef __UPD3301__ +#define __UPD3301__ + +#include "emu.h" + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define UPD3301_DRAW_CHARACTER_MEMBER(_name) void _name(bitmap_rgb32 &bitmap, int y, int sx, UINT8 cc, UINT8 lc, int hlgt, int rvv, int vsp, int sl0, int sl12, int csr, int gpa) + + +#define MCFG_UPD3301_CHARACTER_WIDTH(_value) \ + upd3301_device::static_set_character_width(*device, _value); + +#define MCFG_UPD3301_DRAW_CHARACTER_CALLBACK_OWNER(_class, _method) \ + upd3301_device::static_set_display_callback(*device, upd3301_draw_character_delegate(&_class::_method, #_class "::" #_method, downcast<_class *>(owner))); + +#define MCFG_UPD3301_DRQ_CALLBACK(_write) \ + devcb = &upd3301_device::set_drq_wr_callback(*device, DEVCB_##_write); + +#define MCFG_UPD3301_INT_CALLBACK(_write) \ + devcb = &upd3301_device::set_int_wr_callback(*device, DEVCB_##_write); + +#define MCFG_UPD3301_HRTC_CALLBACK(_write) \ + devcb = &upd3301_device::set_hrtc_wr_callback(*device, DEVCB_##_write); + +#define MCFG_UPD3301_VRTC_CALLBACK(_write) \ + devcb = &upd3301_device::set_vrtc_wr_callback(*device, DEVCB_##_write); + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +typedef device_delegate upd3301_draw_character_delegate; + + +// ======================> upd3301_device + +class upd3301_device : public device_t, + public device_video_interface +{ +public: + // construction/destruction + upd3301_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + static void static_set_character_width(device_t &device, int value) { downcast(device).m_width = value; } + static void static_set_display_callback(device_t &device, upd3301_draw_character_delegate callback) { downcast(device).m_display_cb = callback; } + + template static devcb_base &set_drq_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_drq.set_callback(object); } + template static devcb_base &set_int_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_int.set_callback(object); } + template static devcb_base &set_hrtc_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_hrtc.set_callback(object); } + template static devcb_base &set_vrtc_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_vrtc.set_callback(object); } + + DECLARE_READ8_MEMBER( read ); + DECLARE_WRITE8_MEMBER( write ); + DECLARE_WRITE8_MEMBER( dack_w ); + DECLARE_WRITE_LINE_MEMBER( lpen_w ); + DECLARE_READ_LINE_MEMBER( hrtc_r ); + DECLARE_READ_LINE_MEMBER( vrtc_r ); + + UINT32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_clock_changed(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + +private: + enum + { + TIMER_HRTC, + TIMER_VRTC, + TIMER_DRQ + }; + + void set_interrupt(int state); + void set_drq(int state); + void set_display(int state); + void reset_counters(); + void update_hrtc_timer(int state); + void update_vrtc_timer(int state); + void recompute_parameters(); + + void draw_scanline(); + + devcb_write_line m_write_int; + devcb_write_line m_write_drq; + devcb_write_line m_write_hrtc; + devcb_write_line m_write_vrtc; + + upd3301_draw_character_delegate m_display_cb; + int m_width; + + // screen drawing + bitmap_rgb32 *m_bitmap; // bitmap + int m_y; // current scanline + int m_hrtc; // horizontal retrace + int m_vrtc; // vertical retrace + + // live state + int m_mode; // command mode + UINT8 m_status; // status register + int m_param_count; // parameter count + + // FIFOs + UINT8 m_data_fifo[80][2]; // row data FIFO + UINT8 m_attr_fifo[40][2]; // attribute FIFO + int m_data_fifo_pos; // row data FIFO position + int m_attr_fifo_pos; // attribute FIFO position + int m_input_fifo; // which FIFO is in input mode + + // interrupts + int m_mn; // disable special character interrupt + int m_me; // disable end of screen interrupt + int m_dma_mode; // DMA mode + + // screen geometry + int m_h; // characters per line + int m_b; // cursor blink time + int m_l; // lines per screen + int m_s; // display every other line + int m_c; // cursor mode + int m_r; // lines per character + int m_v; // vertical blanking height + int m_z; // horizontal blanking width + + // attributes + int m_at1; // + int m_at0; // + int m_sc; // + int m_attr; // attributes per row + int m_attr_blink; // attribute blink + int m_attr_frame; // attribute blink frame counter + + // cursor + int m_cm; // cursor visible + int m_cx; // cursor column + int m_cy; // cursor row + int m_cursor_blink; // cursor blink + int m_cursor_frame; // cursor blink frame counter + + // timers + emu_timer *m_hrtc_timer; + emu_timer *m_vrtc_timer; + emu_timer *m_drq_timer; +}; + + +// device type definition +extern const device_type UPD3301; + + + +#endif diff --git a/src/devices/video/upd7220.c b/src/devices/video/upd7220.c new file mode 100644 index 00000000000..05f64cc2878 --- /dev/null +++ b/src/devices/video/upd7220.c @@ -0,0 +1,1683 @@ +// license:BSD-3-Clause +// copyright-holders:Angelo Salese, Miodrag Milanovic, Carl +/********************************************************************** + + Intel 82720 Graphics Display Controller emulation + +**********************************************************************/ + +/* + + TODO: + + - implement FIFO as ring buffer + - commands + - DMAR + - DMAW + - incomplete / unimplemented FIGD / GCHRD draw modes + - FIGD character + - slanted character + - read-modify-write cycle + - read data + - modify data + - write data + - QX-10 diagnostic test has positioning bugs with the bitmap display test; + - QX-10 diagnostic test misses the zooming factor (external pin); + - compis2 SAD address for bitmap is 0x20000 for whatever reason (presumably missing banking); + - A5105 has a FIFO bug with the RDAT, should be a lot larger when it scrolls up. + The problem is that DMA-ing with RDAT/WDAT shouldn't be instant; + + - honor visible area + - wide mode (32-bit access) + - light pen + - dad and mask are the same, in figd dad is shifted every step and when msb or lsb are 1 ead is advanced in x dir + +*/ + +#include "emu.h" +#include "upd7220.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define VERBOSE 0 +#define LOG(x) do { if (VERBOSE) logerror x; } while (0) + + +// todo typedef +enum +{ + COMMAND_INVALID = -1, + COMMAND_RESET, + COMMAND_SYNC, + COMMAND_VSYNC, + COMMAND_CCHAR, + COMMAND_START, + COMMAND_BCTRL, + COMMAND_ZOOM, + COMMAND_CURS, + COMMAND_PRAM, + COMMAND_PITCH, + COMMAND_WDAT, + COMMAND_MASK, + COMMAND_FIGS, + COMMAND_FIGD, + COMMAND_GCHRD, + COMMAND_RDAT, + COMMAND_CURD, + COMMAND_LPRD, + COMMAND_DMAR, + COMMAND_DMAW, + COMMAND_5A +}; + +enum +{ + FIFO_READ = 0, + FIFO_WRITE +}; + +enum +{ + FIFO_EMPTY = -1, + FIFO_PARAMETER, + FIFO_COMMAND +}; + +#define UPD7220_COMMAND_RESET 0x00 +#define UPD7220_COMMAND_SYNC 0x0e // & 0xfe +#define UPD7220_COMMAND_VSYNC 0x6e // & 0xfe +#define UPD7220_COMMAND_CCHAR 0x4b +#define UPD7220_COMMAND_START 0x6b +#define UPD7220_COMMAND_BCTRL 0x0c // & 0xfe +#define UPD7220_COMMAND_ZOOM 0x46 +#define UPD7220_COMMAND_CURS 0x49 +#define UPD7220_COMMAND_PRAM 0x70 // & 0xf0 +#define UPD7220_COMMAND_PITCH 0x47 +#define UPD7220_COMMAND_WDAT 0x20 // & 0xe4 +#define UPD7220_COMMAND_MASK 0x4a +#define UPD7220_COMMAND_FIGS 0x4c +#define UPD7220_COMMAND_FIGD 0x6c +#define UPD7220_COMMAND_GCHRD 0x68 +#define UPD7220_COMMAND_RDAT 0xa0 // & 0xe4 +#define UPD7220_COMMAND_CURD 0xe0 +#define UPD7220_COMMAND_LPRD 0xc0 +#define UPD7220_COMMAND_DMAR 0xa4 // & 0xe4 +#define UPD7220_COMMAND_DMAW 0x24 // & 0xe4 +#define UPD7220_COMMAND_5A 0x5a + +#define UPD7220_SR_DATA_READY 0x01 +#define UPD7220_SR_FIFO_FULL 0x02 +#define UPD7220_SR_FIFO_EMPTY 0x04 +#define UPD7220_SR_DRAWING_IN_PROGRESS 0x08 +#define UPD7220_SR_DMA_EXECUTE 0x10 +#define UPD7220_SR_VSYNC_ACTIVE 0x20 +#define UPD7220_SR_HBLANK_ACTIVE 0x40 +#define UPD7220_SR_LIGHT_PEN_DETECT 0x80 + +#define UPD7220_MODE_REFRESH_RAM 0x04 +#define UPD7220_MODE_DRAW_ON_RETRACE 0x10 +#define UPD7220_MODE_DISPLAY_MASK 0x22 +#define UPD7220_MODE_DISPLAY_MIXED 0x00 +#define UPD7220_MODE_DISPLAY_GRAPHICS 0x02 +#define UPD7220_MODE_DISPLAY_CHARACTER 0x20 +#define UPD7220_MODE_DISPLAY_INVALID 0x22 +#define UPD7220_MODE_INTERLACE_MASK 0x09 +#define UPD7220_MODE_INTERLACE_NONE 0x00 +#define UPD7220_MODE_INTERLACE_INVALID 0x01 +#define UPD7220_MODE_INTERLACE_REPEAT 0x08 +#define UPD7220_MODE_INTERLACE_ON 0x09 + + +static const int x_dir[8] = { 0, 1, 1, 1, 0,-1,-1,-1}; +static const int y_dir[8] = { 1, 1, 0,-1,-1,-1, 0, 1}; + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +// devices +const device_type UPD7220 = &device_creator; + + +// default address map +static ADDRESS_MAP_START( upd7220_vram, AS_0, 16, upd7220_device ) + AM_RANGE(0x00000, 0x3ffff) AM_RAM +ADDRESS_MAP_END + + +// internal 128x14 control ROM +// hand-dumped as little-endian from a die shot +ROM_START( upd7220 ) + ROM_REGION( 0x100, "upd7220", 0 ) + ROM_LOAD( "upd7220.bin", 0x000, 0x100, CRC(3c92b218) SHA1(e154b3106a80c9c98d9f2ee18efcd7f4b4aa7d49) ) +ROM_END + + +//------------------------------------------------- +// memory_space_config - return a description of +// any address spaces owned by this device +//------------------------------------------------- + +const address_space_config *upd7220_device::memory_space_config(address_spacenum spacenum) const +{ + return (spacenum == AS_0) ? &m_space_config : NULL; +} + + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const rom_entry *upd7220_device::device_rom_region() const +{ + return ROM_NAME( upd7220 ); +} + + + +//************************************************************************** +// INLINE HELPERS +//************************************************************************** + +//------------------------------------------------- +// readbyte - read a byte at the given address +//------------------------------------------------- + +inline UINT8 upd7220_device::readbyte(offs_t address) +{ + return space().read_byte(address); +} + + +//------------------------------------------------- +// writebyte - write a byte at the given address +//------------------------------------------------- + +inline void upd7220_device::writebyte(offs_t address, UINT8 data) +{ + space().write_byte(address, data); +} + +inline UINT16 upd7220_device::readword(offs_t address) +{ + return space().read_word(address); +} + + +inline void upd7220_device::writeword(offs_t address, UINT16 data) +{ + space().write_word(address, data); +} + +//------------------------------------------------- +// fifo_clear - +//------------------------------------------------- + +inline void upd7220_device::fifo_clear() +{ + for (int i = 0; i < 16; i++) + { + m_fifo[i] = 0; + m_fifo_flag[i] = FIFO_EMPTY; + } + + m_fifo_ptr = -1; + + m_sr &= ~UPD7220_SR_DATA_READY; + m_sr |= UPD7220_SR_FIFO_EMPTY; + m_sr &= ~UPD7220_SR_FIFO_FULL; +} + + +//------------------------------------------------- +// fifo_param_count - +//------------------------------------------------- + +inline int upd7220_device::fifo_param_count() +{ + int i; + + for (i = 0; i < 16; i++) + { + if (m_fifo_flag[i] != FIFO_PARAMETER) break; + } + + return i; +} + + +//------------------------------------------------- +// fifo_set_direction - +//------------------------------------------------- + +inline void upd7220_device::fifo_set_direction(int dir) +{ + if (m_fifo_dir != dir) + { + fifo_clear(); + } + + m_fifo_dir = dir; +} + + +//------------------------------------------------- +// queue - +//------------------------------------------------- + +inline void upd7220_device::queue(UINT8 data, int flag) +{ + if (m_fifo_ptr < 15) + { + m_fifo_ptr++; + + m_fifo[m_fifo_ptr] = data; + m_fifo_flag[m_fifo_ptr] = flag; + + if (m_fifo_ptr == 16) + { + m_sr |= UPD7220_SR_FIFO_FULL; + } + + m_sr &= ~UPD7220_SR_FIFO_EMPTY; + } + else + { + // TODO what happen? somebody set us up the bomb + logerror("FIFO?\n"); + } +} + + +//------------------------------------------------- +// dequeue - +//------------------------------------------------- + +inline void upd7220_device::dequeue(UINT8 *data, int *flag) +{ + *data = m_fifo[0]; + *flag = m_fifo_flag[0]; + + if (m_fifo_ptr > -1) + { + for (int i = 0; i < 15; i++) + { + m_fifo[i] = m_fifo[i + 1]; + m_fifo_flag[i] = m_fifo_flag[i + 1]; + } + + m_fifo[15] = 0; + m_fifo_flag[15] = 0; + + m_fifo_ptr--; + + if (m_fifo_ptr == -1) + { + m_sr &= ~UPD7220_SR_DATA_READY; + m_sr |= UPD7220_SR_FIFO_EMPTY; + } + } +} + + +//------------------------------------------------- +// update_vsync_timer - +//------------------------------------------------- + +inline void upd7220_device::update_vsync_timer(int state) +{ + int next_y = state ? m_vs : 0; + + attotime duration = m_screen->time_until_pos(next_y, 0); + + m_vsync_timer->adjust(duration, !state); +} + + +//------------------------------------------------- +// update_hsync_timer - +//------------------------------------------------- + +inline void upd7220_device::update_hsync_timer(int state) +{ + int y = m_screen->vpos(); + + int next_x = state ? m_hs : 0; + int next_y = state ? y : ((y + 1) % m_al); + + attotime duration = m_screen->time_until_pos(next_y, next_x); + + m_hsync_timer->adjust(duration, !state); +} + + +//------------------------------------------------- +// update_blank_timer - +//------------------------------------------------- + +inline void upd7220_device::update_blank_timer(int state) +{ + int y = m_screen->vpos(); + + int next_x = state ? (m_hs + m_hbp) : (m_hs + m_hbp + (m_aw << 3)); + int next_y = state ? ((y + 1) % (m_vs + m_vbp + m_al + m_vfp - 1)) : y; + + attotime duration = m_screen->time_until_pos(next_y, next_x); + + m_hsync_timer->adjust(duration, !state); +} + + +//------------------------------------------------- +// recompute_parameters - +//------------------------------------------------- + +inline void upd7220_device::recompute_parameters() +{ + int horiz_mult = 16, vert_mult = 1; + /* TODO: assume that the pitch also controls number of horizontal pixels in a single cell */ + // horiz_mult = 4 if both mixed and interlace? + if((m_mode & UPD7220_MODE_DISPLAY_MASK) == UPD7220_MODE_DISPLAY_MIXED) + horiz_mult = 8; + else if((m_mode & UPD7220_MODE_INTERLACE_MASK) == UPD7220_MODE_INTERLACE_ON) + { + // in interlaced mode every line contains both fields + horiz_mult = 8; + vert_mult = 2; + } + + int horiz_pix_total = (m_hs + m_hbp + m_hfp + m_aw) * horiz_mult; + int vert_pix_total = (m_vs + m_vbp + m_al + m_vfp) * vert_mult; + + //printf("%d %d %d %d\n",m_hs,m_hbp,m_aw,m_hfp); + //printf("%d %d\n",m_aw * 8,m_pitch * 8); + + if (horiz_pix_total == 0 || vert_pix_total == 0) //bail out if screen params aren't valid + return; + + attoseconds_t refresh = HZ_TO_ATTOSECONDS(clock() * 8) * horiz_pix_total * vert_pix_total; + + rectangle visarea; + + visarea.min_x = 0; //(m_hs + m_hbp) * 8; + visarea.min_y = m_vbp; //m_vs + m_vbp; + visarea.max_x = m_aw * horiz_mult - 1;//horiz_pix_total - (m_hfp * 8) - 1; + visarea.max_y = m_al * vert_mult + m_vbp - 1;//vert_pix_total - m_vfp - 1; + + LOG(("uPD7220 '%s' Screen: %u x %u @ %f Hz\n", tag(), horiz_pix_total, vert_pix_total, 1 / ATTOSECONDS_TO_DOUBLE(refresh))); + LOG(("Visible Area: (%u, %u) - (%u, %u)\n", visarea.min_x, visarea.min_y, visarea.max_x, visarea.max_y)); + LOG(("%d %d %d %d %d\n",m_hs,m_hbp,m_aw,m_hfp,m_pitch)); + LOG(("%d %d %d %d\n",m_vs,m_vbp,m_al,m_vfp)); + + if (m_m) + { + m_screen->configure(horiz_pix_total, vert_pix_total, visarea, refresh); + + update_hsync_timer(0); + update_vsync_timer(0); + } + else + { + m_hsync_timer->enable(0); + m_vsync_timer->enable(0); + } + + update_blank_timer(0); +} + + +//------------------------------------------------- +// reset_figs_param - +//------------------------------------------------- + +inline void upd7220_device::reset_figs_param() +{ + m_figs.m_dc = 0x0000; + m_figs.m_d = 0x0008; + m_figs.m_d1 = 0x0008; + m_figs.m_d2 = 0x0000; + m_figs.m_dm = 0x0000; + m_figs.m_gd = 0; +} + + +//------------------------------------------------- +// read_vram - +//------------------------------------------------- + +inline void upd7220_device::read_vram(UINT8 type, UINT8 mod) +{ + if (type == 1) + { + LOG (("uPD7220 invalid type 1 RDAT parameter\n")); + return; + } + + if (mod) + LOG (("uPD7220 RDAT used with mod = %02x?\n",mod)); + + while (m_figs.m_dc && m_fifo_ptr < (type ? 15 : 14)) + { + switch(type) + { + case 0: + queue(readbyte(m_ead*2), 0); + queue(readbyte(m_ead*2+1), 0); + break; + case 2: + queue(readbyte(m_ead*2), 0); + break; + case 3: + queue(readbyte(m_ead*2+1), 0); + break; + } + + m_figs.m_dc--; + m_ead += x_dir[m_figs.m_dir] + (y_dir[m_figs.m_dir] * m_pitch); + m_ead &= 0x3ffff; + } + + if (m_figs.m_dc == 0) + reset_figs_param(); +} + + +//------------------------------------------------- +// write_vram - +//------------------------------------------------- + +inline void upd7220_device::write_vram(UINT8 type, UINT8 mod) +{ + UINT16 result; + + if (type == 1) + { + logerror("uPD7220 invalid type 1 WDAT parameter\n"); + return; + } + + result = 0; + + result = m_pr[1] | (m_pr[2] << 8); + + switch(type) + { + case 0: + result &= m_mask; + break; + case 2: + result &= (m_mask & 0xff); + break; + case 3: + result <<= 8; + result &= (m_mask & 0xff00); + break; + } + + //if(result) + { + //printf("%04x %02x %02x %04x %02x %02x\n",readbyte(m_ead),m_pr[1],m_pr[2],m_mask,type,mod); + //printf("%04x %02x %02x\n",m_ead,m_figs.m_dir,m_pitch); + //printf("%04x %04x %02x %04x\n",m_ead,result,mod,m_figs.m_dc); + } + + for(int i = 0; i < m_figs.m_dc + 1; i++) + { + switch(mod & 3) + { + case 0x00: //replace + if(type == 0) + writeword(m_ead*2+0, result); + if(type == 2) + writebyte(m_ead*2+0, result & 0xff); + if(type == 3) + writebyte(m_ead*2+1, result >> 8); + break; + case 0x01: //complement + if(type == 0) + writeword(m_ead*2+0, readword(m_ead*2+0) ^ result); + if(type == 2) + writebyte(m_ead*2+0, readbyte(m_ead*2+0) ^ (result & 0xff)); + if(type == 3) + writebyte(m_ead*2+1, readbyte(m_ead*2+1) ^ (result >> 8)); + break; + case 0x02: //reset to zero + if(type == 0) + writeword(m_ead*2+0, readword(m_ead*2+0) & ~result); + if(type == 2) + writebyte(m_ead*2+0, readbyte(m_ead*2+0) & ~(result & 0xff)); + if(type == 3) + writebyte(m_ead*2+1, readbyte(m_ead*2+1) & ~(result >> 8)); + break; + case 0x03: //set to one + if(type == 0) + writeword(m_ead*2+0, readword(m_ead*2+0) | result); + if(type == 2) + writebyte(m_ead*2+0, readbyte(m_ead*2+0) | (result & 0xff)); + if(type == 3) + writebyte(m_ead*2+1, readbyte(m_ead*2+1) | (result >> 8)); + break; + } + + m_ead += x_dir[m_figs.m_dir] + (y_dir[m_figs.m_dir] * m_pitch); + m_ead &= 0x3ffff; + } +} + + +//------------------------------------------------- +// get_text_partition - +//------------------------------------------------- + +inline void upd7220_device::get_text_partition(int index, UINT32 *sad, UINT16 *len, int *im, int *wd) +{ + *sad = ((m_ra[(index * 4) + 1] & 0x1f) << 8) | m_ra[(index * 4) + 0]; + *len = ((m_ra[(index * 4) + 3] & 0x3f) << 4) | (m_ra[(index * 4) + 2] >> 4); + *im = BIT(m_ra[(index * 4) + 3], 6); + *wd = BIT(m_ra[(index * 4) + 3], 7); +} + + +//------------------------------------------------- +// get_graphics_partition - +//------------------------------------------------- + +inline void upd7220_device::get_graphics_partition(int index, UINT32 *sad, UINT16 *len, int *im, int *wd) +{ + *sad = ((m_ra[(index * 4) + 2] & 0x03) << 16) | (m_ra[(index * 4) + 1] << 8) | m_ra[(index * 4) + 0]; + *len = ((m_ra[(index * 4) + 3] & 0x3f) << 4) | (m_ra[(index * 4) + 2] >> 4); + *im = BIT(m_ra[(index * 4) + 3], 6); + *wd = BIT(m_ra[(index * 4) + 3], 7); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// upd7220_device - constructor +//------------------------------------------------- + +upd7220_device::upd7220_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + device_t(mconfig, UPD7220, "uPD7220", tag, owner, clock, "upd7220", __FILE__), + device_memory_interface(mconfig, *this), + device_video_interface(mconfig, *this), + m_write_drq(*this), + m_write_hsync(*this), + m_write_vsync(*this), + m_write_blank(*this), + m_mask(0), + m_pitch(0), + m_ead(0), + m_dad(0), + m_lad(0), + m_ra_addr(0), + m_sr(UPD7220_SR_FIFO_EMPTY), + m_cr(0), + m_param_ptr(0), + m_fifo_ptr(-1), + m_fifo_dir(0), + m_mode(0), + m_de(0), + m_m(0), + m_aw(0), + m_al(0), + m_vs(0), + m_vfp(0), + m_vbp(0), + m_hs(0), + m_hfp(0), + m_hbp(0), + m_dc(0), + m_sc(0), + m_br(0), + m_ctop(0), + m_cbot(0), + m_lr(0), + m_disp(0), + m_gchr(0), + m_bitmap_mod(0), + m_space_config("videoram", ENDIANNESS_LITTLE, 16, 18, 0, NULL, *ADDRESS_MAP_NAME(upd7220_vram)) +{ + for (int i = 0; i < 16; i++) + { + m_fifo[i] = 0; + m_fifo_flag[i] = FIFO_EMPTY; + + m_ra[i] = 0; + } + + for (int i = 0; i < 17; i++) + { + m_pr[i] = 0; + } + + memset(&m_figs, 0x00, sizeof(m_figs)); +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void upd7220_device::device_start() +{ + // resolve callbacks + m_display_cb.bind_relative_to(*owner()); + m_draw_text_cb.bind_relative_to(*owner()); + + m_write_drq.resolve_safe(); + m_write_hsync.resolve_safe(); + m_write_vsync.resolve_safe(); + m_write_blank.resolve_safe(); + + // allocate timers + m_vsync_timer = timer_alloc(TIMER_VSYNC); + m_hsync_timer = timer_alloc(TIMER_HSYNC); + m_blank_timer = timer_alloc(TIMER_BLANK); + + // register for state saving + save_item(NAME(m_ra)); + save_item(NAME(m_sr)); + save_item(NAME(m_mode)); + save_item(NAME(m_de)); + save_item(NAME(m_aw)); + save_item(NAME(m_al)); + save_item(NAME(m_vs)); + save_item(NAME(m_vfp)); + save_item(NAME(m_vbp)); + save_item(NAME(m_hs)); + save_item(NAME(m_hfp)); + save_item(NAME(m_hbp)); + save_item(NAME(m_m)); + save_item(NAME(m_dc)); + save_item(NAME(m_sc)); + save_item(NAME(m_br)); + save_item(NAME(m_lr)); + save_item(NAME(m_ctop)); + save_item(NAME(m_cbot)); + save_item(NAME(m_ead)); + save_item(NAME(m_dad)); + save_item(NAME(m_lad)); + save_item(NAME(m_disp)); + save_item(NAME(m_gchr)); + save_item(NAME(m_mask)); + save_item(NAME(m_pitch)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void upd7220_device::device_reset() +{ + m_write_drq(CLEAR_LINE); +} + + +//------------------------------------------------- +// device_timer - handler timer events +//------------------------------------------------- + +void upd7220_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch (id) + { + case TIMER_HSYNC: + if (param) + { + m_sr |= UPD7220_SR_HBLANK_ACTIVE; + } + else + { + m_sr &= ~UPD7220_SR_HBLANK_ACTIVE; + } + + m_write_hsync(param); + + update_hsync_timer(param); + break; + + case TIMER_VSYNC: + if (param) + { + m_sr |= UPD7220_SR_VSYNC_ACTIVE; + } + else + { + m_sr &= ~UPD7220_SR_VSYNC_ACTIVE; + } + + m_write_vsync(param); + + update_vsync_timer(param); + break; + + case TIMER_BLANK: + if (param) + { + m_sr |= UPD7220_SR_HBLANK_ACTIVE; + } + else + { + m_sr &= ~UPD7220_SR_HBLANK_ACTIVE; + } + + m_write_blank(param); + + update_blank_timer(param); + break; + } +} + + +//------------------------------------------------- +// draw_pixel - +//------------------------------------------------- + +void upd7220_device::draw_pixel(int x, int y, int xi, UINT16 tile_data) +{ + UINT32 addr = ((y * (m_pitch << (m_figs.m_gd ? 0 : 1))) + (x >> 3)) & 0x3ffff; + UINT16 data = readword(addr); + UINT16 new_pixel = (tile_data & (1 << (xi & 0xf))) ? (1 << (x & 0xf)) : 0; + + switch(m_bitmap_mod) + { + case 0: //replace + writeword(addr, (data & ~(1 << (x & 0xf))) | new_pixel); + break; + case 1: //complement + writeword(addr, data ^ new_pixel); + break; + case 2: //reset + writeword(addr, data & ~new_pixel); + break; + case 3: //set + writeword(addr, data | new_pixel); + break; + } +} + + +//------------------------------------------------- +// draw_line - +//------------------------------------------------- + +void upd7220_device::draw_line(int x, int y) +{ + int xi, yi; + int d = (m_figs.m_d & 0x2000) ? (INT16)(m_figs.m_d | 0xe000) : m_figs.m_d; + int d2 = (m_figs.m_d2 & 0x2000) ? (INT16)(m_figs.m_d2 | 0xe000) : m_figs.m_d2; + UINT16 pattern = (m_ra[8]) | (m_ra[9]<<8); + const int dot_dir[4] = {1, -1, -1, 1}; + + LOG(("uPD7220 line check: %d %d %02x %08x %d %d %d\n",x,y,m_figs.m_dir,m_ead,m_figs.m_d1,m_figs.m_dc,m_bitmap_mod)); + + for(yi = xi = 0; yi <= m_figs.m_dc; yi++) + { + switch(m_figs.m_dir & 3) + { + case 1: + case 2: + draw_pixel(yi * dot_dir[((m_figs.m_dir >> 1) + 3) & 3] + x, xi * dot_dir[m_figs.m_dir >> 1] + y, yi, pattern); + break; + default: + draw_pixel(xi * dot_dir[((m_figs.m_dir >> 1) + 3) & 3] + x, yi * dot_dir[m_figs.m_dir >> 1] + y, yi, pattern); + break; + } + if(d > 0) + { + xi++; + d += d2; + } + else + d += m_figs.m_d1; + } + + switch(m_figs.m_dir & 3) + { + case 1: + case 2: + x += yi * dot_dir[((m_figs.m_dir >> 1) + 3) & 3]; + y += xi * dot_dir[m_figs.m_dir >> 1]; + break; + default: + x += xi * dot_dir[((m_figs.m_dir >> 1) + 3) & 3]; + y += yi * dot_dir[m_figs.m_dir >> 1]; + break; + } + + m_ead = (x >> 4) + (y * (m_pitch >> m_figs.m_gd)); + m_dad = x & 0x0f; +} + +//------------------------------------------------- +// draw_arc - +//------------------------------------------------- + +void upd7220_device::draw_arc(int x, int y) +{ + int xi = m_figs.m_d + 1, yi = 0, err = -m_figs.m_d; + int x0, y0; + UINT16 pattern = (m_ra[8]) | (m_ra[9]<<8); + const int dot_dir[4] = {1, -1, -1, 1}; + + switch(m_figs.m_dir & 3) + { + case 1: + case 2: + x0 = x; + y0 = y + xi * dot_dir[m_figs.m_dir >> 1]; + break; + default: + x0 = x + xi * dot_dir[((m_figs.m_dir >> 1) + 3) & 3]; + y0 = y; + break; + } + + LOG(("uPD7220 arc check: %d %d %02x %08x %d %d %d\n",x,y,m_figs.m_dir,m_ead,m_figs.m_dm,m_figs.m_dc,m_figs.m_d)); + + for(int i = 0; i <= m_figs.m_dc; i++) + { + if(i >= m_figs.m_dm) + { + switch(m_figs.m_dir & 3) + { + case 1: + case 2: + draw_pixel(yi * dot_dir[((m_figs.m_dir >> 1) + 3) & 3] + x0, xi * dot_dir[m_figs.m_dir >> 1] + y0, i, pattern); + break; + default: + draw_pixel(xi * dot_dir[m_figs.m_dir >> 1] + x0, yi * dot_dir[((m_figs.m_dir >> 1) + 3) & 3] + y0, i, pattern); + break; + } + } + yi++; + if(err < 0) + err += (yi + 1) << 1; + else + { + xi--; + err += (yi - xi + 1) << 1; + } + } + switch(m_figs.m_dir & 3) + { + case 1: + case 2: + x += (m_figs.m_dc + 1) * dot_dir[((m_figs.m_dir >> 1) + 3) & 3]; + break; + default: + y += (m_figs.m_dc + 1) * dot_dir[m_figs.m_dir >> 1]; + break; + } + + m_ead = (x >> 4) + (y * (m_pitch >> m_figs.m_gd)); + m_dad = x & 0x0f; +} + +//------------------------------------------------- +// draw_rectangle - +//------------------------------------------------- + +void upd7220_device::draw_rectangle(int x, int y) +{ + int i; + const int rect_x_dir[8] = { 0, 1, 0,-1, 1, 1,-1,-1 }; + const int rect_y_dir[8] = { 1, 0,-1, 0, 1,-1,-1, 1 }; + UINT8 rect_type,rect_dir; + UINT16 pattern = (m_ra[8]) | (m_ra[9]<<8); + + LOG(("uPD7220 rectangle check: %d %d %02x %08x\n",x,y,m_figs.m_dir,m_ead)); + + rect_type = (m_figs.m_dir & 1) << 2; + rect_dir = rect_type | (((m_figs.m_dir >> 1) + 0) & 3); + + for(i = 0;i < m_figs.m_d;i++) + { + draw_pixel(x,y,i,pattern); + x+=rect_x_dir[rect_dir]; + y+=rect_y_dir[rect_dir]; + } + + rect_dir = rect_type | (((m_figs.m_dir >> 1) + 1) & 3); + + for(i = 0;i < m_figs.m_d2;i++) + { + draw_pixel(x,y,i,pattern); + x+=rect_x_dir[rect_dir]; + y+=rect_y_dir[rect_dir]; + } + + rect_dir = rect_type | (((m_figs.m_dir >> 1) + 2) & 3); + + for(i = 0;i < m_figs.m_d;i++) + { + draw_pixel(x,y,i,pattern); + x+=rect_x_dir[rect_dir]; + y+=rect_y_dir[rect_dir]; + } + + rect_dir = rect_type | (((m_figs.m_dir >> 1) + 3) & 3); + + for(i = 0;i < m_figs.m_d2;i++) + { + draw_pixel(x,y,i,pattern); + x+=rect_x_dir[rect_dir]; + y+=rect_y_dir[rect_dir]; + } + + m_ead = (x >> 4) + (y * (m_pitch >> m_figs.m_gd)); + m_dad = x & 0x0f; + +} + + +//------------------------------------------------- +// draw_char - +//------------------------------------------------- + +void upd7220_device::draw_char(int x, int y) +{ + int isize,psize; + UINT16 tile_data = 0; + + LOG(("uPD7220 char check: %d %d %02x %08x %d %d %02x\n",x,y,m_figs.m_dir,m_ead,m_figs.m_d,m_figs.m_dc,m_figs.m_figure_type)); + + isize = m_figs.m_d & 0x3ff; + /* Guess: D has presumably upper bits for ysize, QX-10 relies on this (TODO: check this on any real HW) */ + psize = ((m_figs.m_d & 0x400) + m_figs.m_dc) + 1; + + for(int pi = 0; pi < psize; pi++) + { + tile_data = (m_ra[((psize-1-pi) & 7) | 8] << 8) | m_ra[((psize-1-pi) & 7) | 8]; + for(int pz = 0; pz <= m_gchr; pz++) + { + for(int ii = 0, curpixel = 0; ii < isize; ii++) + { + for(int iz = 0; iz <= m_gchr; iz++) + { + draw_pixel(x + (curpixel * x_dir[m_figs.m_dir]), y + (curpixel * y_dir[m_figs.m_dir]), ii, tile_data); + curpixel++; + } + } + if(m_figs.m_figure_type == 2) + { + x += x_dir[(m_figs.m_dir + 2) & 7]; + y += y_dir[(m_figs.m_dir + 2) & 7]; + } + else + { + x += x_dir[(m_figs.m_dir + 1) & 7]; + y += y_dir[(m_figs.m_dir + 1) & 7]; + } + } + } + + m_ead = (x >> 4) + (y * (m_pitch >> m_figs.m_gd)); + m_dad = (x & 0xf); +} + + +//------------------------------------------------- +// translate_command - +//------------------------------------------------- + +int upd7220_device::translate_command(UINT8 data) +{ + int command = COMMAND_INVALID; + + switch (data) + { + case UPD7220_COMMAND_RESET: command = COMMAND_RESET; break; + case UPD7220_COMMAND_CCHAR: command = COMMAND_CCHAR; break; + case UPD7220_COMMAND_START: command = COMMAND_START; break; + case UPD7220_COMMAND_ZOOM: command = COMMAND_ZOOM; break; + case UPD7220_COMMAND_CURS: command = COMMAND_CURS; break; + case UPD7220_COMMAND_PITCH: command = COMMAND_PITCH; break; + case UPD7220_COMMAND_MASK: command = COMMAND_MASK; break; + case UPD7220_COMMAND_FIGS: command = COMMAND_FIGS; break; + case UPD7220_COMMAND_FIGD: command = COMMAND_FIGD; break; + case UPD7220_COMMAND_GCHRD: command = COMMAND_GCHRD; break; + case UPD7220_COMMAND_CURD: command = COMMAND_CURD; break; + case UPD7220_COMMAND_LPRD: command = COMMAND_LPRD; break; + case UPD7220_COMMAND_5A: command = COMMAND_5A; break; + default: + switch (data & 0xfe) + { + case UPD7220_COMMAND_SYNC: command = COMMAND_SYNC; break; + case UPD7220_COMMAND_VSYNC: command = COMMAND_VSYNC; break; + case UPD7220_COMMAND_BCTRL: command = COMMAND_BCTRL; break; + default: + switch (data & 0xf0) + { + case UPD7220_COMMAND_PRAM: command = COMMAND_PRAM; break; + default: + switch (data & 0xe4) + { + case UPD7220_COMMAND_WDAT: command = COMMAND_WDAT; break; + case UPD7220_COMMAND_RDAT: command = COMMAND_RDAT; break; + case UPD7220_COMMAND_DMAR: command = COMMAND_DMAR; break; + case UPD7220_COMMAND_DMAW: command = COMMAND_DMAW; break; + } + } + } + } + + return command; +} + + +//------------------------------------------------- +// process_fifo - +//------------------------------------------------- + +void upd7220_device::process_fifo() +{ + UINT8 data; + int flag; + UINT16 eff_pitch = m_pitch >> m_figs.m_gd; + + dequeue(&data, &flag); + + if (flag == FIFO_COMMAND) + { + m_cr = data; + m_param_ptr = 1; + } + else + { + m_pr[m_param_ptr] = data; + m_param_ptr++; + } + + switch (translate_command(m_cr)) + { + case COMMAND_INVALID: + logerror("uPD7220 '%s' Invalid Command Byte %02x\n", tag(), m_cr); + break; + + case COMMAND_5A: + if (m_param_ptr == 4) + logerror("uPD7220 '%s' Undocumented Command 0x5A Executed %02x %02x %02x\n", tag(),m_pr[1],m_pr[2],m_pr[3] ); + break; + + case COMMAND_RESET: /* reset */ + switch (m_param_ptr) + { + case 0: + LOG(("uPD7220 '%s' RESET\n", tag())); + + m_de = 0; + m_ra[0] = m_ra[1] = m_ra[2] = 0; + m_ra[3] = 0x19; + m_ead = 0; + m_dad = 0; + m_mask = 0; + break; + + case 9: + m_mode = m_pr[1]; + m_aw = m_pr[2] + 2; + m_hs = (m_pr[3] & 0x1f) + 1; + m_vs = ((m_pr[4] & 0x03) << 3) | (m_pr[3] >> 5); + m_hfp = (m_pr[4] >> 2) + 1; + m_hbp = (m_pr[5] & 0x3f) + 1; + m_vfp = m_pr[6] & 0x3f; + m_al = ((m_pr[8] & 0x03) << 8) | m_pr[7]; + m_vbp = m_pr[8] >> 2; + + m_pitch = m_aw; + + LOG(("uPD7220 '%s' Mode: %02x\n", tag(), m_mode)); + LOG(("uPD7220 '%s' AW: %u\n", tag(), m_aw)); + LOG(("uPD7220 '%s' HS: %u\n", tag(), m_hs)); + LOG(("uPD7220 '%s' VS: %u\n", tag(), m_vs)); + LOG(("uPD7220 '%s' HFP: %u\n", tag(), m_hfp)); + LOG(("uPD7220 '%s' HBP: %u\n", tag(), m_hbp)); + LOG(("uPD7220 '%s' VFP: %u\n", tag(), m_vfp)); + LOG(("uPD7220 '%s' AL: %u\n", tag(), m_al)); + LOG(("uPD7220 '%s' VBP: %u\n", tag(), m_vbp)); + LOG(("uPD7220 '%s' PITCH: %u\n", tag(), m_pitch)); + + recompute_parameters(); + break; + } + break; + + case COMMAND_SYNC: /* sync format specify */ + if (m_param_ptr == 9) + { + m_mode = m_pr[1]; + m_aw = m_pr[2] + 2; + m_hs = (m_pr[3] & 0x1f) + 1; + m_vs = ((m_pr[4] & 0x03) << 3) | (m_pr[3] >> 5); + m_hfp = (m_pr[4] >> 2) + 1; + m_hbp = (m_pr[5] & 0x3f) + 1; + m_vfp = m_pr[6] & 0x3f; + m_al = ((m_pr[8] & 0x03) << 8) | m_pr[7]; + m_vbp = m_pr[8] >> 2; + + m_pitch = m_aw; + + LOG(("uPD7220 '%s' Mode: %02x\n", tag(), m_mode)); + LOG(("uPD7220 '%s' AW: %u\n", tag(), m_aw)); + LOG(("uPD7220 '%s' HS: %u\n", tag(), m_hs)); + LOG(("uPD7220 '%s' VS: %u\n", tag(), m_vs)); + LOG(("uPD7220 '%s' HFP: %u\n", tag(), m_hfp)); + LOG(("uPD7220 '%s' HBP: %u\n", tag(), m_hbp)); + LOG(("uPD7220 '%s' VFP: %u\n", tag(), m_vfp)); + LOG(("uPD7220 '%s' AL: %u\n", tag(), m_al)); + LOG(("uPD7220 '%s' VBP: %u\n", tag(), m_vbp)); + LOG(("uPD7220 '%s' PITCH: %u\n", tag(), m_pitch)); + + recompute_parameters(); + } + break; + + case COMMAND_VSYNC: /* vertical sync mode */ + m_m = m_cr & 0x01; + + LOG(("uPD7220 '%s' M: %u\n", tag(), m_m)); + + recompute_parameters(); + break; + + case COMMAND_CCHAR: /* cursor & character characteristics */ + if(m_param_ptr == 2) + { + m_lr = (m_pr[1] & 0x1f) + 1; + m_dc = BIT(m_pr[1], 7); + + LOG(("uPD7220 '%s' LR: %u\n", tag(), m_lr)); + LOG(("uPD7220 '%s' DC: %u\n", tag(), m_dc)); + } + + if(m_param_ptr == 3) + { + m_ctop = m_pr[2] & 0x1f; + m_sc = BIT(m_pr[2], 5); + m_br = (m_pr[2] >> 6); /* guess, assume that blink rate clears upper bits (if any) */ + + LOG(("uPD7220 '%s' CTOP: %u\n", tag(), m_ctop)); + LOG(("uPD7220 '%s' SC: %u\n", tag(), m_sc)); + } + + if(m_param_ptr == 4) + { + m_br = ((m_pr[3] & 0x07) << 2) | (m_pr[2] >> 6); + m_cbot = m_pr[3] >> 3; + + LOG(("uPD7220 '%s' BR: %u\n", tag(), m_br)); + LOG(("uPD7220 '%s' CBOT: %u\n", tag(), m_cbot)); + } + break; + + case COMMAND_START: /* start display & end idle mode */ + m_de = 1; + + //LOG(("uPD7220 '%s' DE: 1\n", tag())); + break; + + case COMMAND_BCTRL: /* display blanking control */ + m_de = m_cr & 0x01; + + //LOG(("uPD7220 '%s' DE: %u\n", tag(), m_de)); + break; + + case COMMAND_ZOOM: /* zoom factors specify */ + if (flag == FIFO_PARAMETER) + { + m_gchr = m_pr[1] & 0x0f; + m_disp = m_pr[1] >> 4; + + LOG(("uPD7220 '%s' GCHR: %01x\n", tag(), m_gchr)); + LOG(("uPD7220 '%s' DISP: %01x\n", tag(), m_disp)); + } + break; + + case COMMAND_CURS: /* cursor position specify */ + if (m_param_ptr >= 3) + { + UINT8 upper_addr = (m_param_ptr == 3) ? 0 : (m_pr[3] & 0x03); + + m_ead = (upper_addr << 16) | (m_pr[2] << 8) | m_pr[1]; + + LOG(("uPD7220 '%s' EAD: %06x\n", tag(), m_ead)); + + if(m_param_ptr == 4) + { + m_dad = m_pr[3] >> 4; + LOG(("uPD7220 '%s' DAD: %01x\n", tag(), m_dad)); + } + } + break; + + case COMMAND_PRAM: /* parameter RAM load */ + if (flag == FIFO_COMMAND) + { + m_ra_addr = m_cr & 0x0f; + } + else + { + if (m_ra_addr < 16) + { + LOG(("uPD7220 '%s' RA%u: %02x\n", tag(), m_ra_addr, data)); + + m_ra[m_ra_addr] = data; + m_ra_addr++; + } + + m_param_ptr = 0; + } + break; + + case COMMAND_PITCH: /* pitch specification */ + if (flag == FIFO_PARAMETER) + { + m_pitch = data; + + LOG(("uPD7220 '%s' PITCH: %u\n", tag(), m_pitch)); + } + break; + + case COMMAND_WDAT: /* write data into display memory */ + m_bitmap_mod = m_cr & 3; + + if (m_param_ptr == 3 || (m_param_ptr == 2 && m_cr & 0x10)) + { + LOG(("%02x = %02x %02x (%c) %06x %04x\n",m_cr,m_pr[2],m_pr[1],m_pr[1]?m_pr[1]:' ',m_ead,m_figs.m_dc)); + fifo_set_direction(FIFO_WRITE); + + write_vram((m_cr & 0x18) >> 3,m_cr & 3); + reset_figs_param(); + m_param_ptr = 1; + } + break; + + case COMMAND_MASK: /* mask register load */ + if (m_param_ptr == 3) + { + m_mask = (m_pr[2] << 8) | m_pr[1]; + + LOG(("uPD7220 '%s' MASK: %04x\n", tag(), m_mask)); + } + break; + + case COMMAND_FIGS: /* figure drawing parameters specify */ + if (m_param_ptr == 2) + { + m_figs.m_dir = m_pr[1] & 0x7; + m_figs.m_figure_type = (m_pr[1] & 0xf8) >> 3; + + //if(m_figs.m_dir != 2) + // printf("DIR %02x\n",m_pr[1]); + } + + // the Decision Mate V during start-up test upload only 2 params before execute the + // RDAT command, so I assume this is the expected behaviour, but this needs to be verified. + if (m_param_ptr == 3) + m_figs.m_dc = (m_pr[2]) | (m_figs.m_dc & 0x3f00); + + if (m_param_ptr == 4) + { + m_figs.m_dc = (m_pr[2]) | ((m_pr[3] & 0x3f) << 8); + m_figs.m_gd = (m_pr[3] & 0x40) && ((m_mode & UPD7220_MODE_DISPLAY_MASK) == UPD7220_MODE_DISPLAY_MIXED); + } + + if (m_param_ptr == 6) + m_figs.m_d = (m_pr[4]) | ((m_pr[5] & 0x3f) << 8); + + if (m_param_ptr == 8) + m_figs.m_d2 = (m_pr[6]) | ((m_pr[7] & 0x3f) << 8); + + if (m_param_ptr == 10) + m_figs.m_d1 = (m_pr[8]) | ((m_pr[9] & 0x3f) << 8); + + if (m_param_ptr == 12) + m_figs.m_dm = (m_pr[10]) | ((m_pr[11] & 0x3f) << 8); + + break; + + case COMMAND_FIGD: /* figure draw start */ + if(m_figs.m_figure_type == 0) + draw_pixel(((m_ead % eff_pitch) << 4) | (m_dad & 0xf),(m_ead / eff_pitch),m_dad,(m_ra[8]) | (m_ra[9]<<8)); + else if(m_figs.m_figure_type == 1) + draw_line(((m_ead % eff_pitch) << 4) | (m_dad & 0xf),(m_ead / eff_pitch)); + else if(m_figs.m_figure_type == 4) + draw_arc(((m_ead % eff_pitch) << 4) | (m_dad & 0xf),(m_ead / eff_pitch)); + else if(m_figs.m_figure_type == 8) + draw_rectangle(((m_ead % eff_pitch) << 4) | (m_dad & 0xf),(m_ead / eff_pitch)); + else + logerror("uPD7220 '%s' Unimplemented command FIGD %02x\n", tag(),m_figs.m_figure_type); + + reset_figs_param(); + m_sr |= UPD7220_SR_DRAWING_IN_PROGRESS; + break; + + case COMMAND_GCHRD: /* graphics character draw and area filling start */ + if((m_figs.m_figure_type & 0xf) == 2) + draw_char(((m_ead % eff_pitch) << 4) | (m_dad & 0xf),(m_ead / eff_pitch)); + else + logerror("uPD7220 '%s' Unimplemented command GCHRD %02x\n", tag(),m_figs.m_figure_type); + + reset_figs_param(); + m_sr |= UPD7220_SR_DRAWING_IN_PROGRESS; + break; + + case COMMAND_RDAT: /* read data from display memory */ + fifo_set_direction(FIFO_READ); + + read_vram((m_cr & 0x18) >> 3,m_cr & 3); + + m_sr |= UPD7220_SR_DATA_READY; + break; + + case COMMAND_CURD: /* cursor address read */ + { + UINT16 dad = 1 << m_dad; + fifo_set_direction(FIFO_READ); + + queue(m_ead & 0xff, 0); + queue((m_ead >> 8) & 0xff, 0); + queue(m_ead >> 16, 0); + queue(dad & 0xff, 0); + queue(dad >> 8, 0); + + m_sr |= UPD7220_SR_DATA_READY; + break; + } + + case COMMAND_LPRD: /* light pen address read */ + fifo_set_direction(FIFO_READ); + + queue(m_lad & 0xff, 0); + queue((m_lad >> 8) & 0xff, 0); + queue(m_lad >> 16, 0); + + m_sr |= UPD7220_SR_DATA_READY; + m_sr &= ~UPD7220_SR_LIGHT_PEN_DETECT; + break; + + case COMMAND_DMAR: /* DMA read request */ + logerror("uPD7220 '%s' Unimplemented command DMAR\n", tag()); + break; + + case COMMAND_DMAW: /* DMA write request */ + logerror("uPD7220 '%s' Unimplemented command DMAW\n", tag()); + break; + } +} + + +//------------------------------------------------- +// continue command +//------------------------------------------------- + +void upd7220_device::continue_command() +{ + // continue RDAT command when data to read are larger than the FIFO (a5105 and dmv text scrolling) + if (m_figs.m_dc && translate_command(m_cr) == COMMAND_RDAT) + { + read_vram((m_cr & 0x18) >> 3, m_cr & 3); + m_sr |= UPD7220_SR_DATA_READY; + } +} + + +//------------------------------------------------- +// read - +//------------------------------------------------- + +READ8_MEMBER( upd7220_device::read ) +{ + UINT8 data; + + if (offset & 1) + { + /* FIFO read */ + int flag; + fifo_set_direction(FIFO_READ); + dequeue(&data, &flag); + + continue_command(); + } + else + { + /* status register */ + data = m_sr; + + /* TODO: timing of these */ + m_sr &= ~UPD7220_SR_DRAWING_IN_PROGRESS; + m_sr &= ~UPD7220_SR_DMA_EXECUTE; + } + + return data; +} + + +//------------------------------------------------- +// write - +//------------------------------------------------- + +WRITE8_MEMBER( upd7220_device::write ) +{ + if (offset & 1) + { + /* command into FIFO */ + fifo_set_direction(FIFO_WRITE); + queue(data, 1); + } + else + { + /* parameter into FIFO */ +// fifo_set_direction(FIFO_WRITE); + queue(data, 0); + } + + process_fifo(); +} + + +//------------------------------------------------- +// dack_r - +//------------------------------------------------- + +READ8_MEMBER( upd7220_device::dack_r ) +{ + return 0; +} + + +//------------------------------------------------- +// dack_w - +//------------------------------------------------- + +WRITE8_MEMBER( upd7220_device::dack_w ) +{ +} + + +//------------------------------------------------- +// ext_sync_w - +//------------------------------------------------- + +WRITE_LINE_MEMBER( upd7220_device::ext_sync_w ) +{ + //LOG(("uPD7220 '%s' External Synchronization: %u\n", tag(), state)); + + if (state) + { + m_sr |= UPD7220_SR_VSYNC_ACTIVE; + } + else + { + m_sr &= ~UPD7220_SR_VSYNC_ACTIVE; + } +} + + +//------------------------------------------------- +// ext_sync_w - +//------------------------------------------------- + +WRITE_LINE_MEMBER( upd7220_device::lpen_w ) +{ + /* only if 2 rising edges on the lpen input occur at the same + point during successive video fields are the pulses accepted */ + + /* + + 1. compute the address of the location on the CRT + 2. compare with LAD + 3. if not equal move address to LAD + 4. if equal set LPEN DETECT flag to 1 + + */ +} + + +//------------------------------------------------- +// update_text - +//------------------------------------------------- + +void upd7220_device::update_text(bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + UINT32 addr, sad; + UINT16 len; + int im, wd; + int y, sy = 0; + + for (int area = 0; area < 4; area++) + { + get_text_partition(area, &sad, &len, &im, &wd); + + for (y = sy; y < sy + len; y++) + { + addr = sad + (y * m_pitch); + + if (!m_draw_text_cb.isnull()) + m_draw_text_cb(bitmap, addr, (y * m_lr) + m_vbp, wd, m_pitch, m_lr, m_dc, m_ead); + } + + sy = y + 1; + } +} + + +//------------------------------------------------- +// draw_graphics_line - +//------------------------------------------------- + +void upd7220_device::draw_graphics_line(bitmap_rgb32 &bitmap, UINT32 addr, int y, int wd, int pitch) +{ + int sx, al = bitmap.cliprect().height(); + + for (sx = 0; sx < pitch; sx++) + { + if((sx << 4) < m_aw * 16 && y < al) + m_display_cb(bitmap, y, sx << 4, addr); + + addr+= (wd + 1) * 2; + } +} + + +//------------------------------------------------- +// update_graphics - +//------------------------------------------------- + +void upd7220_device::update_graphics(bitmap_rgb32 &bitmap, const rectangle &cliprect, int force_bitmap) +{ + UINT32 addr, sad; + UINT16 len; + int im, wd, area; + int y = 0, tsy = 0, bsy = 0; + bool mixed = ((m_mode & UPD7220_MODE_DISPLAY_MASK) == UPD7220_MODE_DISPLAY_MIXED); + UINT8 interlace = ((m_mode & UPD7220_MODE_INTERLACE_MASK) == UPD7220_MODE_INTERLACE_ON) ? 0 : 1; + + for (area = 0; area < 4; area++) + { + get_graphics_partition(area, &sad, &len, &im, &wd); + + if (im || force_bitmap) + { + //get_graphics_partition(area, &sad, &len, &im, &wd); + + if(area >= 3) // TODO: most likely to be correct, Quarth (PC-98xx) definitely draws with area 2. We might see an area 3 someday ... + break; + + if(!interlace) + len <<= 1; + + for (y = 0; y < len; y++) + { + /* TODO: again correct? + Quarth (PC-98xx) doesn't seem to use pitch here and it definitely wants bsy to be /2 to make scrolling to work. + Xevious (PC-98xx) wants the pitch to be fixed at 80, and wants bsy to be /1 + Dragon Buster (PC-98xx) contradicts with Xevious with regards of the pitch tho ... */ + addr = ((sad << 1) & 0x3ffff) + (y * (m_pitch << (im ? 0 : 1))); + + if (!m_display_cb.isnull()) + draw_graphics_line(bitmap, addr, y + ((bsy + m_vbp) / (mixed ? 1 : m_lr)), wd, (m_pitch << interlace)); + } + } + else + { + get_text_partition(area, &sad, &len, &im, &wd); + + if(m_lr) + { + for (y = 0; y < len; y+=m_lr) + { + addr = (sad & 0x3ffff) + ((y / m_lr) * m_pitch); + + if (!m_draw_text_cb.isnull()) + m_draw_text_cb(bitmap, addr, y + tsy + m_vbp, wd, m_pitch, m_lr, m_dc, m_ead); + } + } + } + + if (m_lr) + tsy += y; + bsy += y; + } +} + + +//------------------------------------------------- +// update_screen - +//------------------------------------------------- + +UINT32 upd7220_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + if (m_de) + { + switch (m_mode & UPD7220_MODE_DISPLAY_MASK) + { + case UPD7220_MODE_DISPLAY_MIXED: + update_graphics(bitmap, cliprect, 0); + break; + + case UPD7220_MODE_DISPLAY_GRAPHICS: + update_graphics(bitmap, cliprect, 1); + break; + + case UPD7220_MODE_DISPLAY_CHARACTER: + update_text(bitmap, cliprect); + break; + + case UPD7220_MODE_DISPLAY_INVALID: + LOG(("uPD7220 '%s' Invalid Display Mode!\n", tag())); + } + } + return 0; +} diff --git a/src/devices/video/upd7220.h b/src/devices/video/upd7220.h new file mode 100644 index 00000000000..4a8be071cac --- /dev/null +++ b/src/devices/video/upd7220.h @@ -0,0 +1,234 @@ +// license:BSD-3-Clause +// copyright-holders:Angelo Salese, Miodrag Milanovic, Carl +/********************************************************************** + + NEC uPD7220 Graphics Display Controller emulation + +********************************************************************** + _____ _____ + 2xWCLK 1 |* \_/ | 40 Vcc + _DBIN 2 | | 39 A17 + HSYNC 3 | | 38 A16 + V/EXT SYNC 4 | | 37 AD15 + BLANK 5 | | 36 AD14 + ALE 6 | | 35 AD13 + DRQ 7 | | 34 AD12 + _DACK 8 | | 33 AD11 + _RD 9 | | 32 AD10 + _WR 10 | uPD7220 | 31 AD9 + A0 11 | 82720 | 30 AD8 + DB0 12 | | 29 AD7 + DB1 13 | | 28 AD6 + DB2 14 | | 27 AD5 + DB3 15 | | 26 AD4 + DB4 16 | | 25 AD3 + DB5 17 | | 24 AD2 + DB6 18 | | 23 AD1 + DB7 19 | | 22 AD0 + GND 20 |_____________| 21 LPEN + +**********************************************************************/ + +#pragma once + +#ifndef __UPD7220__ +#define __UPD7220__ + +#include "emu.h" + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define UPD7220_DISPLAY_PIXELS_MEMBER(_name) void _name(bitmap_rgb32 &bitmap, int y, int x, UINT32 address) +#define UPD7220_DRAW_TEXT_LINE_MEMBER(_name) void _name(bitmap_rgb32 &bitmap, UINT32 addr, int y, int wd, int pitch, int lr, int cursor_on, int cursor_addr) + + +#define MCFG_UPD7220_DISPLAY_PIXELS_CALLBACK_OWNER(_class, _method) \ + upd7220_device::static_set_display_pixels_callback(*device, upd7220_display_pixels_delegate(&_class::_method, #_class "::" #_method, downcast<_class *>(owner))); + +#define MCFG_UPD7220_DRAW_TEXT_CALLBACK_OWNER(_class, _method) \ + upd7220_device::static_set_draw_text_callback(*device, upd7220_draw_text_delegate(&_class::_method, #_class "::" #_method, downcast<_class *>(owner))); + +#define MCFG_UPD7220_DRQ_CALLBACK(_write) \ + devcb = &upd7220_device::set_drq_wr_callback(*device, DEVCB_##_write); + +#define MCFG_UPD7220_HSYNC_CALLBACK(_write) \ + devcb = &upd7220_device::set_hsync_wr_callback(*device, DEVCB_##_write); + +#define MCFG_UPD7220_VSYNC_CALLBACK(_write) \ + devcb = &upd7220_device::set_vsync_wr_callback(*device, DEVCB_##_write); + +#define MCFG_UPD7220_BLANK_CALLBACK(_write) \ + devcb = &upd7220_device::set_blank_wr_callback(*device, DEVCB_##_write); + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +typedef device_delegate upd7220_display_pixels_delegate; +typedef device_delegate upd7220_draw_text_delegate; + + +// ======================> upd7220_device + +class upd7220_device : public device_t, + public device_memory_interface, + public device_video_interface +{ +public: + // construction/destruction + upd7220_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + static void static_set_display_pixels_callback(device_t &device, upd7220_display_pixels_delegate callback) { downcast(device).m_display_cb = callback; } + static void static_set_draw_text_callback(device_t &device, upd7220_draw_text_delegate callback) { downcast(device).m_draw_text_cb = callback; } + + template static devcb_base &set_drq_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_drq.set_callback(object); } + template static devcb_base &set_hsync_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_hsync.set_callback(object); } + template static devcb_base &set_vsync_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_vsync.set_callback(object); } + template static devcb_base &set_blank_wr_callback(device_t &device, _Object object) { return downcast(device).m_write_blank.set_callback(object); } + + DECLARE_READ8_MEMBER( read ); + DECLARE_WRITE8_MEMBER( write ); + + DECLARE_READ8_MEMBER( dack_r ); + DECLARE_WRITE8_MEMBER( dack_w ); + + DECLARE_WRITE_LINE_MEMBER( ext_sync_w ); + DECLARE_WRITE_LINE_MEMBER( lpen_w ); + + DECLARE_WRITE8_MEMBER( bank_w ); + DECLARE_READ8_MEMBER( vram_r ); + DECLARE_WRITE8_MEMBER( vram_w ); + + UINT32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); + virtual const rom_entry *device_rom_region() const; + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const; + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + +private: + enum + { + TIMER_VSYNC, + TIMER_HSYNC, + TIMER_BLANK + }; + + inline UINT8 readbyte(offs_t address); + inline void writebyte(offs_t address, UINT8 data); + inline UINT16 readword(offs_t address); + inline void writeword(offs_t address, UINT16 data); + inline void fifo_clear(); + inline int fifo_param_count(); + inline void fifo_set_direction(int dir); + inline void queue(UINT8 data, int flag); + inline void dequeue(UINT8 *data, int *flag); + inline void update_vsync_timer(int state); + inline void update_hsync_timer(int state); + inline void update_blank_timer(int state); + inline void recompute_parameters(); + inline void reset_figs_param(); + inline void read_vram(UINT8 type, UINT8 mod); + inline void write_vram(UINT8 type, UINT8 mod); + inline void get_text_partition(int index, UINT32 *sad, UINT16 *len, int *im, int *wd); + inline void get_graphics_partition(int index, UINT32 *sad, UINT16 *len, int *im, int *wd); + + void draw_pixel(int x, int y, int xi, UINT16 tile_data); + void draw_line(int x, int y); + void draw_rectangle(int x, int y); + void draw_arc(int x, int y); + void draw_char(int x, int y); + int translate_command(UINT8 data); + void process_fifo(); + void continue_command(); + void update_text(bitmap_rgb32 &bitmap, const rectangle &cliprect); + void draw_graphics_line(bitmap_rgb32 &bitmap, UINT32 addr, int y, int wd, int pitch); + void update_graphics(bitmap_rgb32 &bitmap, const rectangle &cliprect, int force_bitmap); + + upd7220_display_pixels_delegate m_display_cb; + upd7220_draw_text_delegate m_draw_text_cb; + + devcb_write_line m_write_drq; + devcb_write_line m_write_hsync; + devcb_write_line m_write_vsync; + devcb_write_line m_write_blank; + + UINT16 m_mask; // mask register + UINT8 m_pitch; // number of word addresses in display memory in the horizontal direction + UINT32 m_ead; // execute word address + UINT16 m_dad; // dot address within the word + UINT32 m_lad; // light pen address + + UINT8 m_ra[16]; // parameter RAM + int m_ra_addr; // parameter RAM address + + UINT8 m_sr; // status register + UINT8 m_cr; // command register + UINT8 m_pr[17]; // parameter byte register + int m_param_ptr; // parameter pointer + + UINT8 m_fifo[16]; // FIFO data queue + int m_fifo_flag[16]; // FIFO flag queue + int m_fifo_ptr; // FIFO pointer + int m_fifo_dir; // FIFO direction + + UINT8 m_mode; // mode of operation + + int m_de; // display enabled + int m_m; // 0 = accept external vertical sync (slave mode) / 1 = generate & output vertical sync (master mode) + int m_aw; // active display words per line - 2 (must be even number with bit 0 = 0) + int m_al; // active display lines per video field + int m_vs; // vertical sync width - 1 + int m_vfp; // vertical front porch width - 1 + int m_vbp; // vertical back porch width - 1 + int m_hs; // horizontal sync width - 1 + int m_hfp; // horizontal front porch width - 1 + int m_hbp; // horizontal back porch width - 1 + + int m_dc; // display cursor + int m_sc; // 0 = blinking cursor / 1 = steady cursor + int m_br; // blink rate + int m_ctop; // cursor top line number in the row + int m_cbot; // cursor bottom line number in the row (CBOT < LR) + int m_lr; // lines per character row - 1 + + int m_disp; // display zoom factor + int m_gchr; // zoom factor for graphics character writing and area filling + + UINT8 m_bitmap_mod; + + struct { + UINT8 m_dir; // figs param 0: drawing direction + UINT8 m_figure_type; // figs param 1: figure type + UINT16 m_dc; // figs param 2: + UINT8 m_gd; // mixed mode only + UINT16 m_d; // figs param 3: + UINT16 m_d1; // figs param 4: + UINT16 m_d2; // figs param 5: + UINT16 m_dm; // figs param 6: + } m_figs; + + // timers + emu_timer *m_vsync_timer; // vertical sync timer + emu_timer *m_hsync_timer; // horizontal sync timer + emu_timer *m_blank_timer; // CRT blanking timer + + const address_space_config m_space_config; +}; + + +// device type definition +extern const device_type UPD7220; + + + +#endif diff --git a/src/devices/video/upd7227.c b/src/devices/video/upd7227.c new file mode 100644 index 00000000000..037dd037610 --- /dev/null +++ b/src/devices/video/upd7227.c @@ -0,0 +1,162 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + uPD7227 Intelligent Dot-Matrix LCD Controller/Driver emulation + +**********************************************************************/ + +#include "emu.h" +#include "upd7227.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define LOG 0 + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type UPD7227 = &device_creator; + + +static ADDRESS_MAP_START( upd7227_map, AS_PROGRAM, 8, upd7227_device ) + AM_RANGE(0x00, 0x27) AM_RAM + AM_RANGE(0x40, 0x67) AM_RAM +ADDRESS_MAP_END + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// upd7227_device - constructor +//------------------------------------------------- + +upd7227_device::upd7227_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, UPD7227, "uPD7227", tag, owner, clock, "upd7227", __FILE__), + device_memory_interface(mconfig, *this), + m_space_config("videoram", ENDIANNESS_BIG, 8, 7, 0, *ADDRESS_MAP_NAME(upd7227_map)), + m_cs(1), + m_cd(1), + m_sck(1), + m_si(1), + m_so(1) +{ +} + + +//------------------------------------------------- +// static_set_offsets - configuration helper +//------------------------------------------------- + +void upd7227_device::static_set_offsets(device_t &device, int sx, int sy) +{ + upd7227_device &upd7227 = downcast(device); + + upd7227.m_sx = sx; + upd7227.m_sy = sy; +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void upd7227_device::device_start() +{ + // state saving + save_item(NAME(m_cs)); + save_item(NAME(m_cd)); + save_item(NAME(m_sck)); + save_item(NAME(m_si)); + save_item(NAME(m_so)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void upd7227_device::device_reset() +{ +} + + +//------------------------------------------------- +// memory_space_config - return a description of +// any address spaces owned by this device +//------------------------------------------------- + +const address_space_config *upd7227_device::memory_space_config(address_spacenum spacenum) const +{ + return (spacenum == 0) ? &m_space_config : NULL; +} + + +//------------------------------------------------- +// update_screen - update screen +//------------------------------------------------- + +UINT32 upd7227_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) +{ + return 0; +} + + +//------------------------------------------------- +// cs_w - chip select +//------------------------------------------------- + +WRITE_LINE_MEMBER( upd7227_device::cs_w ) +{ + m_cs = state; +} + + +//------------------------------------------------- +// cd_w - command/data select +//------------------------------------------------- + +WRITE_LINE_MEMBER( upd7227_device::cd_w ) +{ + m_cd = state; +} + + +//------------------------------------------------- +// sck_w - serial clock +//------------------------------------------------- + +WRITE_LINE_MEMBER( upd7227_device::sck_w ) +{ + m_sck = state; +} + + +//------------------------------------------------- +// si_w - serial input +//------------------------------------------------- + +WRITE_LINE_MEMBER( upd7227_device::si_w ) +{ + m_si = state; +} + + +//------------------------------------------------- +// so_r - serial output/busy +//------------------------------------------------- + +READ_LINE_MEMBER( upd7227_device::so_r ) +{ + return m_so; +} diff --git a/src/devices/video/upd7227.h b/src/devices/video/upd7227.h new file mode 100644 index 00000000000..19d04224d1c --- /dev/null +++ b/src/devices/video/upd7227.h @@ -0,0 +1,95 @@ +// license:BSD-3-Clause +// copyright-holders:Curt Coder +/********************************************************************** + + uPD7227 Intelligent Dot-Matrix LCD Controller/Driver emulation + +**********************************************************************/ + +#pragma once + +#ifndef __UPD7227__ +#define __UPD7227__ + +#include "emu.h" + + + +///************************************************************************* +// INTERFACE CONFIGURATION MACROS +///************************************************************************* + +#define MCFG_UPD7227_ADD(_tag, _sx, _sy) \ + MCFG_DEVICE_ADD(_tag, UPD7227, 0) \ + upd7227_device::static_set_offsets(*device, _sx, _sy); + + + +///************************************************************************* +// TYPE DEFINITIONS +///************************************************************************* + +// ======================> upd7227_device + +class upd7227_device : public device_t, + public device_memory_interface +{ +public: + // construction/destruction + upd7227_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // inline configuration helpers + static void static_set_offsets(device_t &device, int sx, int sy); + + DECLARE_WRITE_LINE_MEMBER( cs_w ); + DECLARE_WRITE_LINE_MEMBER( cd_w ); + DECLARE_WRITE_LINE_MEMBER( sck_w ); + DECLARE_WRITE_LINE_MEMBER( si_w ); + DECLARE_READ_LINE_MEMBER( so_r ); + + UINT32 screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const; + + address_space_config m_space_config; + +private: + enum + { + CMD_SMM = 0x18, + CMD_SFF = 0x10, + CMD_LDPI = 0x80, + CMD_SWM = 0x64, + CMD_SRM = 0x60, + CMD_SANDM = 0x6c, + CMD_SORM = 0x68, + CMD_SCM = 0x72, + CMD_BSET = 0x40, + CMD_BRESET = 0x20, + CMD_DISP_ON = 0x09, + CMD_DISP_OFF = 0x08 + }; + + int m_sx; + int m_sy; + + int m_cs; + int m_cd; + int m_sck; + int m_si; + int m_so; +}; + + +// device type definition +extern const device_type UPD7227; + + + +#endif diff --git a/src/devices/video/v9938.c b/src/devices/video/v9938.c new file mode 100644 index 00000000000..3192593e76a --- /dev/null +++ b/src/devices/video/v9938.c @@ -0,0 +1,3012 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles, Nathan Woods + +/*************************************************************************** + +v9938 / v9958 emulation + +***************************************************************************/ + +/* +todo: + +- sprite collision +- vdp engine -- make run at correct speed +- vr/hr/fh flags: double-check all of that +- make vdp engine work in exp. ram +*/ + +#include "emu.h" +#include "v9938.h" + +#define VERBOSE 0 +#define LOG(x) do { if (VERBOSE) logerror x; } while (0) + +enum +{ + V9938_MODE_TEXT1 = 0, + V9938_MODE_MULTI, + V9938_MODE_GRAPHIC1, + V9938_MODE_GRAPHIC2, + V9938_MODE_GRAPHIC3, + V9938_MODE_GRAPHIC4, + V9938_MODE_GRAPHIC5, + V9938_MODE_GRAPHIC6, + V9938_MODE_GRAPHIC7, + V9938_MODE_TEXT2, + V9938_MODE_UNKNOWN +}; + +#define MODEL_V9938 (0) +#define MODEL_V9958 (1) + +#define EXPMEM_OFFSET 0x20000 + +#define LONG_WIDTH (512 + 32) + +static const char *const v9938_modes[] = { + "TEXT 1", "MULTICOLOR", "GRAPHIC 1", "GRAPHIC 2", "GRAPHIC 3", + "GRAPHIC 4", "GRAPHIC 5", "GRAPHIC 6", "GRAPHIC 7", "TEXT 2", + "UNKNOWN" +}; + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +/* +Similar to the TMS9928, the V9938 has an own address space. It can handle +at most 192 KiB RAM (128 KiB base, 64 KiB expansion). +*/ +static ADDRESS_MAP_START(memmap, AS_DATA, 8, v99x8_device) +ADDRESS_MAP_GLOBAL_MASK(0x3ffff) +AM_RANGE(0x00000, 0x2ffff) AM_RAM +ADDRESS_MAP_END + + +// devices +const device_type V9938 = &device_creator; +const device_type V9958 = &device_creator; + +v99x8_device::v99x8_device(const machine_config &mconfig, device_type type, const char *name, const char *shortname, const char *tag, device_t *owner, UINT32 clock) +: device_t(mconfig, type, name, tag, owner, clock, shortname, __FILE__), + device_memory_interface(mconfig, *this), + device_video_interface(mconfig, *this), + m_space_config("vram", ENDIANNESS_BIG, 8, 18), + m_model(0), + m_offset_x(0), + m_offset_y(0), + m_visible_y(0), + m_mode(0), + m_pal_write_first(0), + m_cmd_write_first(0), + m_pal_write(0), + m_cmd_write(0), + m_read_ahead(0), + m_v9958_sp_mode(0), + m_address_latch(0), + m_vram_size(0), + m_int_state(0), + m_int_callback(*this), + m_scanline(0), + m_blink(0), + m_blink_count(0), + m_mx_delta(0), + m_my_delta(0), + m_button_state(0), + m_vdp_ops_count(0), + m_vdp_engine(NULL), + m_palette(*this, "palette") +{ + static_set_addrmap(*this, AS_DATA, ADDRESS_MAP_NAME(memmap)); +} + +v9938_device::v9938_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) +: v99x8_device(mconfig, V9938, "V9938 VDP", "v9938", tag, owner, clock) +{ + m_model = MODEL_V9938; +} + +v9958_device::v9958_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) +: v99x8_device(mconfig, V9938, "V9958 VDP", "v9958", tag, owner, clock) +{ + m_model = MODEL_V9958; +} + + +int v99x8_device::interrupt () +{ + int scanline, max, pal, scanline_start; + + update_command (); + + pal = m_cont_reg[9] & 2; + if (pal) scanline_start = 53; else scanline_start = 22; + + // set flags + if (m_scanline == (m_offset_y + scanline_start) ) + { + m_stat_reg[2] &= ~0x40; + } + else if (m_scanline == (m_offset_y + m_visible_y + scanline_start) ) + { + m_stat_reg[2] |= 0x40; + m_stat_reg[0] |= 0x80; + } + + max = (pal) ? 255 : (m_cont_reg[9] & 0x80) ? 234 : 244; + scanline = (m_scanline - scanline_start - m_offset_y); + if ( (scanline >= 0) && (scanline <= max) && + ( ( (scanline + m_cont_reg[23]) & 255) == m_cont_reg[19]) ) + { + m_stat_reg[1] |= 1; + LOG(("V9938: scanline interrupt (%d)\n", scanline)); + } + else + if ( !(m_cont_reg[0] & 0x10) ) m_stat_reg[1] &= 0xfe; + + check_int (); + + // check for start of vblank + if ((pal && (m_scanline == 310)) || + (!pal && (m_scanline == 259))) + interrupt_start_vblank (); + + // render the current line + if ((m_scanline >= scanline_start) && (m_scanline < (212 + 28 + scanline_start))) + { + scanline = (m_scanline - scanline_start) & 255; + + refresh_line (scanline); + } + + max = (m_cont_reg[9] & 2) ? 313 : 262; + if (++m_scanline >= max) + m_scanline = 0; + + return m_int_state; +} + +/* + Not really right... won't work with sprites in graphics 7 + and with palette updated mid-screen +*/ +int v99x8_device::get_transpen() +{ + if (m_mode == V9938_MODE_GRAPHIC7) + { + return m_pal_ind256[0]; + } + else + { + return m_pal_ind16[0]; + } +} + +/* + Driver-specific function: update the vdp mouse state +*/ +void v99x8_device::update_mouse_state(int mx_delta, int my_delta, int button_state) +{ + // save button state + m_button_state = (button_state << 6) & 0xc0; + + if ((m_cont_reg[8] & 0xc0) == 0x80) + { // vdp will process mouse deltas only if it is in mouse mode + m_mx_delta += mx_delta; + m_my_delta += my_delta; + } +} + + + +/*************************************************************************** + +Palette functions + +***************************************************************************/ + +/* +About the colour burst registers: + +The color burst registers will only have effect on the composite video output from +the V9938. but the output is only NTSC (Never The Same Color ,so the +effects are already present) . this system is not used in europe +the european machines use a separate PAL (Phase Alternating Line) encoder +or no encoder at all , only RGB output. + +Erik de Boer. + +-- +Right now they're not emulated. For completeness sake they should -- with +a dip-switch to turn them off. I really don't know how they work though. :( +*/ + +/* +In screen 8, the colors are encoded as: + +7 6 5 4 3 2 1 0 ++--+--+--+--+--+--+--+--+ +|g2|g1|g0|r2|r1|r0|b2|b1| ++--+--+--+--+--+--+--+--+ + +b0 is set if b2 and b1 are set (remember, color bus is 3 bits) + +*/ + +PALETTE_INIT_MEMBER(v9938_device, v9938) +{ + int i; + + // create the full 512 colour palette + for (i=0;i<512;i++) + palette.set_pen_color(i, pal3bit(i >> 6), pal3bit(i >> 3), pal3bit(i >> 0)); +} + +/* + +The v9958 can display up to 19286 colours. For this we need a larger palette. + +The colours are encoded in 17 bits; however there are just 19268 different colours. +Here we calculate the palette and a 2^17 reference table to the palette, +which is: s_pal_indYJK. It's 256K in size, but I can't think of a faster way +to emulate this. Also it keeps the palette a reasonable size. :) + +*/ + +UINT16 v99x8_device::s_pal_indYJK[0x20000]; + +PALETTE_INIT_MEMBER(v9958_device, v9958) +{ + int r,g,b,y,j,k,i,k0,j0,n; + UINT8 pal[19268*3]; + + // init v9938 512-color palette + for (i=0;i<512;i++) + palette.set_pen_color(i, pal3bit(i >> 6), pal3bit(i >> 3), pal3bit(i >> 0)); + + + if(palette.entries() != 19780) + fatalerror("V9958: not enough palette, must be 19780"); + + // set up YJK table + LOG(("Building YJK table for V9958 screens, may take a while ... \n")); + i = 0; + for (y=0;y<32;y++) for (k=0;k<64;k++) for (j=0;j<64;j++) + { + // calculate the color + if (k >= 32) k0 = (k - 64); else k0 = k; + if (j >= 32) j0 = (j - 64); else j0 = j; + r = y + j0; + b = (y * 5 - 2 * j0 - k0) / 4; + g = y + k0; + if (r < 0) r = 0; else if (r > 31) r = 31; + if (g < 0) g = 0; else if (g > 31) g = 31; + if (b < 0) b = 0; else if (b > 31) b = 31; + + //r = (r << 3) | (r >> 2); + //b = (b << 3) | (b >> 2); + //g = (g << 3) | (g >> 2); + // have we seen this one before? + n = 0; + while (n < i) + { + if (pal[n*3+0] == r && pal[n*3+1] == g && pal[n*3+2] == b) + { + v99x8_device::s_pal_indYJK[y | j << 5 | k << (5 + 6)] = n + 512; + break; + } + n++; + } + + if (i == n) + { + // so we haven't; add it + pal[i*3+0] = r; + pal[i*3+1] = g; + pal[i*3+2] = b; + palette.set_pen_color(i+512, rgb_t(pal5bit(r), pal5bit(g), pal5bit(b))); + v99x8_device::s_pal_indYJK[y | j << 5 | k << (5 + 6)] = i + 512; + i++; + } + } + + if (i != 19268) + LOG( ("Table creation failed - %d colours out of 19286 created\n", i)); +} + +UINT32 v99x8_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) +{ + copybitmap(bitmap, m_bitmap, 0, 0, 0, 0, cliprect); + return 0; +} + +READ8_MEMBER( v99x8_device::read ) +{ + switch (offset & 3) + { + case 0: return vram_r(); + case 1: return status_r(); + } + return 0xff; +} + +WRITE8_MEMBER( v99x8_device::write ) +{ + switch (offset & 3) + { + case 0: vram_w(data); break; + case 1: command_w(data); break; + case 2: palette_w(data); break; + case 3: register_w(data); break; + } +} + +UINT8 v99x8_device::vram_r() +{ + UINT8 ret; + int address; + + address = ((int)m_cont_reg[14] << 14) | m_address_latch; + + m_cmd_write_first = 0; + + ret = m_read_ahead; + + if (m_cont_reg[45] & 0x40) // Expansion memory + { + if ( (m_mode == V9938_MODE_GRAPHIC6) || (m_mode == V9938_MODE_GRAPHIC7) ) + address >>= 1; // correct? + // Expansion memory only offers 64 K + if (m_vram_size > 0x20000 && ((address & 0x10000)==0)) + m_read_ahead = m_vram_space->read_byte(address + EXPMEM_OFFSET); + else + m_read_ahead = 0xff; + } + else + { + m_read_ahead = vram_read(address); + } + + m_address_latch = (m_address_latch + 1) & 0x3fff; + if ((!m_address_latch) && (m_cont_reg[0] & 0x0c) ) // correct ??? + { + m_cont_reg[14] = (m_cont_reg[14] + 1) & 7; + } + + return ret; +} + +UINT8 v99x8_device::status_r() +{ + int reg; + UINT8 ret; + + m_cmd_write_first = 0; + + reg = m_cont_reg[15] & 0x0f; + if (reg > 9) + return 0xff; + + switch (reg) + { + case 0: + ret = m_stat_reg[0]; + m_stat_reg[0] &= 0x1f; + break; + case 1: + ret = m_stat_reg[1]; + m_stat_reg[1] &= 0xfe; + if ((m_cont_reg[8] & 0xc0) == 0x80) + // mouse mode: add button state + ret |= m_button_state & 0xc0; + break; + case 2: + /*update_command ();*/ + /* + WTF is this? Whatever this was intended to do, it is nonsensical. + Might as well pick a random number.... + This was an attempt to emulate H-Blank flag ;) + n = cycles_currently_ran (); + if ( (n < 28) || (n > 199) ) vdp.statReg[2] |= 0x20; + else vdp.statReg[2] &= ~0x20; + */ + if (machine().rand() & 1) m_stat_reg[2] |= 0x20; + else m_stat_reg[2] &= ~0x20; + ret = m_stat_reg[2]; + break; + case 3: + if ((m_cont_reg[8] & 0xc0) == 0x80) + { // mouse mode: return x mouse delta + ret = m_mx_delta; + m_mx_delta = 0; + } + else + ret = m_stat_reg[3]; + break; + case 5: + if ((m_cont_reg[8] & 0xc0) == 0x80) + { // mouse mode: return y mouse delta + ret = m_my_delta; + m_my_delta = 0; + } + else + ret = m_stat_reg[5]; + break; + case 7: + ret = m_stat_reg[7]; + m_stat_reg[7] = m_cont_reg[44] = vdp_to_cpu () ; + break; + default: + ret = m_stat_reg[reg]; + break; + } + + LOG(("V9938: Read %02x from S#%d\n", ret, reg)); + check_int (); + + return ret; +} + +void v99x8_device::palette_w(UINT8 data) +{ + int indexp; + + if (m_pal_write_first) + { + // store in register + indexp = m_cont_reg[0x10] & 15; + m_pal_reg[indexp*2] = m_pal_write & 0x77; + m_pal_reg[indexp*2+1] = data & 0x07; + // update palette + m_pal_ind16[indexp] = (((int)m_pal_write << 2) & 0x01c0) | + (((int)data << 3) & 0x0038) | + ((int)m_pal_write & 0x0007); + + m_cont_reg[0x10] = (m_cont_reg[0x10] + 1) & 15; + m_pal_write_first = 0; + } + else + { + m_pal_write = data; + m_pal_write_first = 1; + } +} + +void v99x8_device::vram_w(UINT8 data) +{ + int address; + + /*update_command ();*/ + + m_cmd_write_first = 0; + + address = ((int)m_cont_reg[14] << 14) | m_address_latch; + + if (m_cont_reg[45] & 0x40) + { + if ( (m_mode == V9938_MODE_GRAPHIC6) || (m_mode == V9938_MODE_GRAPHIC7) ) + address >>= 1; // correct? + if (m_vram_size > 0x20000 && ((address & 0x10000)==0)) + m_vram_space->write_byte(EXPMEM_OFFSET + address, data); + } + else + { + vram_write(address, data); + } + + m_address_latch = (m_address_latch + 1) & 0x3fff; + if ((!m_address_latch) && (m_cont_reg[0] & 0x0c) ) // correct ??? + { + m_cont_reg[14] = (m_cont_reg[14] + 1) & 7; + } +} + +void v99x8_device::command_w(UINT8 data) +{ + if (m_cmd_write_first) + { + if (data & 0x80) + { + if (!(data & 0x40)) + register_write (data & 0x3f, m_cmd_write); + } + else + { + m_address_latch = + (((UINT16)data << 8) | m_cmd_write) & 0x3fff; + if ( !(data & 0x40) ) vram_r (); // read ahead! + } + + m_cmd_write_first = 0; + } + else + { + m_cmd_write = data; + m_cmd_write_first = 1; + } +} + +void v99x8_device::register_w(UINT8 data) +{ + int reg; + + reg = m_cont_reg[17] & 0x3f; + if (reg != 17) + register_write(reg, data); // true ? + + if (!(m_cont_reg[17] & 0x80)) + m_cont_reg[17] = (m_cont_reg[17] + 1) & 0x3f; +} + +void v99x8_device::static_set_vram_size(device_t &device, UINT32 vram_size) +{ + downcast(device).m_vram_size = vram_size; +} + +/*************************************************************************** + + Init/stop/reset/Interrupt functions + +***************************************************************************/ + +void v99x8_device::device_start() +{ + m_int_callback.resolve_safe(); + m_vdp_ops_count = 1; + m_vdp_engine = NULL; + + m_screen->register_screen_bitmap(m_bitmap); + + // Video RAM is allocated as an own address space + m_vram_space = &space(AS_DATA); + + // allocate VRAM + assert(m_vram_size > 0); + + if (m_vram_size < 0x20000) + { + // set unavailable RAM to 0xff + for (int addr = m_vram_size; addr < 0x30000; addr++) m_vram_space->write_byte(addr, 0xff); + } + + save_item(NAME(m_offset_x)); + save_item(NAME(m_offset_y)); + save_item(NAME(m_visible_y)); + save_item(NAME(m_mode)); + save_item(NAME(m_pal_write_first)); + save_item(NAME(m_cmd_write_first)); + save_item(NAME(m_pal_write)); + save_item(NAME(m_cmd_write)); + save_item(NAME(m_pal_reg)); + save_item(NAME(m_stat_reg)); + save_item(NAME(m_cont_reg)); + save_item(NAME(m_read_ahead)); + // save_item(NAME(m_vram)); + // if ( m_vram_exp != NULL ) + // save_pointer(NAME(m_vram_exp), 0x10000); + save_item(NAME(m_int_state)); + save_item(NAME(m_scanline)); + save_item(NAME(m_blink)); + save_item(NAME(m_blink_count)); + save_item(NAME(m_mx_delta)); + save_item(NAME(m_my_delta)); + save_item(NAME(m_button_state)); + save_item(NAME(m_pal_ind16)); + save_item(NAME(m_pal_ind256)); + save_item(NAME(m_mmc.SX)); + save_item(NAME(m_mmc.SY)); + save_item(NAME(m_mmc.DX)); + save_item(NAME(m_mmc.DY)); + save_item(NAME(m_mmc.TX)); + save_item(NAME(m_mmc.TY)); + save_item(NAME(m_mmc.NX)); + save_item(NAME(m_mmc.NY)); + save_item(NAME(m_mmc.MX)); + save_item(NAME(m_mmc.ASX)); + save_item(NAME(m_mmc.ADX)); + save_item(NAME(m_mmc.ANX)); + save_item(NAME(m_mmc.CL)); + save_item(NAME(m_mmc.LO)); + save_item(NAME(m_mmc.CM)); + save_item(NAME(m_mmc.MXS)); + save_item(NAME(m_mmc.MXD)); + save_item(NAME(m_vdp_ops_count)); +} + +void v99x8_device::device_reset() +{ + int i; + + // offset reset + m_offset_x = 8; + m_offset_y = 8 + 16; + m_visible_y = 192; + // register reset + reset_palette (); // palette registers + for (i=0;i<10;i++) m_stat_reg[i] = 0; + m_stat_reg[2] = 0x0c; + if (m_model == MODEL_V9958) m_stat_reg[1] |= 4; + for (i=0;i<48;i++) m_cont_reg[i] = 0; + m_cmd_write_first = m_pal_write_first = 0; + m_int_state = 0; + m_read_ahead = 0; m_address_latch = 0; // ??? + m_scanline = 0; + // MZ: The status registers 4 and 6 hold the high bits of the sprite + // collision location. The unused bits are set to 1. + // SR3: x x x x x x x x + // SR4: 1 1 1 1 1 1 1 x + // SR5: y y y y y y y y + // SR6: 1 1 1 1 1 1 y y + // Note that status register 4 is used in detection algorithms to tell + // apart the tms9929 from the v99x8. + + // TODO: SR3-S6 do not yet store the information about the sprite collision + m_stat_reg[4] = 0xfe; + m_stat_reg[6] = 0xfc; +} + + +void v99x8_device::reset_palette () +{ + // taken from V9938 Technical Data book, page 148. it's in G-R-B format + static const UINT8 pal16[16*3] = { + 0, 0, 0, // 0: black/transparent + 0, 0, 0, // 1: black + 6, 1, 1, // 2: medium green + 7, 3, 3, // 3: light green + 1, 1, 7, // 4: dark blue + 3, 2, 7, // 5: light blue + 1, 5, 1, // 6: dark red + 6, 2, 7, // 7: cyan + 1, 7, 1, // 8: medium red + 3, 7, 3, // 9: light red + 6, 6, 1, // 10: dark yellow + 6, 6, 4, // 11: light yellow + 4, 1, 1, // 12: dark green + 2, 6, 5, // 13: magenta + 5, 5, 5, // 14: gray + 7, 7, 7 // 15: white + }; + int i, red, ind; + + for (i=0;i<16;i++) + { + // set the palette registers + m_pal_reg[i*2+0] = pal16[i*3+1] << 4 | pal16[i*3+2]; + m_pal_reg[i*2+1] = pal16[i*3]; + // set the reference table + m_pal_ind16[i] = pal16[i*3+1] << 6 | pal16[i*3] << 3 | pal16[i*3+2]; + } + + // set internal palette GRAPHIC 7 + for (i=0;i<256;i++) + { + ind = (i << 4) & 0x01c0; + ind |= (i >> 2) & 0x0038; + red = (i << 1) & 6; if (red == 6) red++; + ind |= red; + + m_pal_ind256[i] = ind; + } +} + +/*************************************************************************** + +Memory functions + +***************************************************************************/ + +void v99x8_device::vram_write(int offset, int data) +{ + int newoffset; + + if ( (m_mode == V9938_MODE_GRAPHIC6) || (m_mode == V9938_MODE_GRAPHIC7) ) + { + newoffset = ((offset & 1) << 16) | (offset >> 1); + if (newoffset < m_vram_size) + m_vram_space->write_byte(newoffset, data); + } + else + { + if (offset < m_vram_size) + m_vram_space->write_byte(offset, data); + } +} + +int v99x8_device::vram_read(int offset) +{ + if ( (m_mode == V9938_MODE_GRAPHIC6) || (m_mode == V9938_MODE_GRAPHIC7) ) + return m_vram_space->read_byte(((offset & 1) << 16) | (offset >> 1)); + else + return m_vram_space->read_byte(offset); +} + +void v99x8_device::check_int() +{ + UINT8 n; + + n = ( (m_cont_reg[1] & 0x20) && (m_stat_reg[0] & 0x80) /*&& m_vblank_int*/) || + ( (m_stat_reg[1] & 0x01) && (m_cont_reg[0] & 0x10) ); + + #if 0 + if(n && m_vblank_int) + { + m_vblank_int = 0; + } + #endif + + if (n != m_int_state) + { + m_int_state = n; + LOG(("V9938: IRQ line %s\n", n ? "up" : "down")); + } + + /* + ** Somehow the IRQ request is going down without cpu_irq_line () being + ** called; because of this Mr. Ghost, Xevious and SD Snatcher don't + ** run. As a patch it's called every scanline + */ + m_int_callback(n); +} + +/*************************************************************************** + + Register functions + +***************************************************************************/ + +void v99x8_device::register_write (int reg, int data) +{ + static UINT8 const reg_mask[] = + { + 0x7e, 0x7b, 0x7f, 0xff, 0x3f, 0xff, 0x3f, 0xff, + 0xfb, 0xbf, 0x07, 0x03, 0xff, 0xff, 0x07, 0x0f, + 0x0f, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x7f, 0x3f, 0x07 + }; + + if (reg <= 27) + { + data &= reg_mask[reg]; + if (m_cont_reg[reg] == data) + return; + } + + if (reg > 46) + { + LOG(("V9938: Attempted to write to non-existant R#%d\n", reg)); + return; + } + + /*update_command ();*/ + + switch (reg) { + // registers that affect interrupt and display mode + case 0: + case 1: + m_cont_reg[reg] = data; + set_mode(); + check_int(); + LOG(("v9938: mode = %s\n", v9938_modes[m_mode])); + break; + + case 18: + case 9: + m_cont_reg[reg] = data; + // recalc offset + m_offset_x = (( (~m_cont_reg[18] - 8) & 0x0f) + 1); + m_offset_y = ((~(m_cont_reg[18]>>4) - 8) & 0x0f) + 7; + if (m_cont_reg[9] & 0x80) + { + m_visible_y = 212; + } + else + { + m_visible_y = 192; + m_offset_y += 10; + } + break; + + case 15: + m_pal_write_first = 0; + break; + + // color burst registers aren't emulated + case 20: + case 21: + case 22: + LOG(("v9938: Write %02xh to R#%d; color burst not emulated\n", data, reg)); + break; + case 25: + case 26: + case 27: + if (m_model != MODEL_V9958) + { + LOG(("v9938: Attempting to write %02xh to V9958 R#%d\n", data, reg)); + data = 0; + } + else + { + if(reg == 25) + m_v9958_sp_mode = data & 0x18; + } + break; + + case 44: + cpu_to_vdp (data); + break; + + case 46: + command_unit_w (data); + break; + } + + if (reg != 15) + LOG(("v9938: Write %02x to R#%d\n", data, reg)); + + m_cont_reg[reg] = data; +} + +/*************************************************************************** + +Refresh / render function + +***************************************************************************/ + +inline bool v99x8_device::v9938_second_field() +{ + return !(((m_cont_reg[9] & 0x04) && !(m_stat_reg[2] & 2)) || m_blink); +} + + +void v99x8_device::default_border(const pen_t *pens, UINT16 *ln) +{ + UINT16 pen; + int i; + + pen = pens[m_pal_ind16[(m_cont_reg[7]&0x0f)]]; + i = LONG_WIDTH; + while (i--) *ln++ = pen; +} + +void v99x8_device::graphic7_border(const pen_t *pens, UINT16 *ln) +{ + UINT16 pen; + int i; + + pen = pens[m_pal_ind256[m_cont_reg[7]]]; + i = LONG_WIDTH; + while (i--) *ln++ = pen; +} + +void v99x8_device::graphic5_border(const pen_t *pens, UINT16 *ln) +{ + int i; + UINT16 pen0; + UINT16 pen1; + + pen1 = pens[m_pal_ind16[(m_cont_reg[7]&0x03)]]; + pen0 = pens[m_pal_ind16[((m_cont_reg[7]>>2)&0x03)]]; + i = LONG_WIDTH / 2; + while (i--) { *ln++ = pen0; *ln++ = pen1; } +} + +void v99x8_device::mode_text1(const pen_t *pens, UINT16 *ln, int line) +{ + int pattern, x, xx, name, xxx; + UINT16 fg, bg, pen; + int nametbl_addr, patterntbl_addr; + + patterntbl_addr = m_cont_reg[4] << 11; + nametbl_addr = m_cont_reg[2] << 10; + + fg = pens[m_pal_ind16[m_cont_reg[7] >> 4]]; + bg = pens[m_pal_ind16[m_cont_reg[7] & 15]]; + + name = (line/8)*40; + + pen = pens[m_pal_ind16[(m_cont_reg[7]&0x0f)]]; + + xxx = (m_offset_x + 8) * 2; + while (xxx--) *ln++ = pen; + + for (x=0;x<40;x++) + { + pattern = m_vram_space->read_byte(patterntbl_addr + (m_vram_space->read_byte(nametbl_addr + name) * 8) + + ((line + m_cont_reg[23]) & 7)); + for (xx=0;xx<6;xx++) + { + *ln++ = (pattern & 0x80) ? fg : bg; + *ln++ = (pattern & 0x80) ? fg : bg; + pattern <<= 1; + } + /* width height 212, characters start repeating at the bottom */ + name = (name + 1) & 0x3ff; + } + + xxx = ((16 - m_offset_x) + 8) * 2; + while (xxx--) *ln++ = pen; +} + +void v99x8_device::mode_text2(const pen_t *pens, UINT16 *ln, int line) +{ + int pattern, x, charcode, name, xxx, patternmask, colourmask; + UINT16 fg, bg, fg0, bg0, pen; + int nametbl_addr, patterntbl_addr, colourtbl_addr; + + patterntbl_addr = m_cont_reg[4] << 11; + colourtbl_addr = ((m_cont_reg[3] & 0xf8) << 6) + (m_cont_reg[10] << 14); + #if 0 + colourmask = ((m_cont_reg[3] & 7) << 5) | 0x1f; /* cause a bug in Forth+ v1.0 on Geneve */ + #else + colourmask = ((m_cont_reg[3] & 7) << 6) | 0x3f; /* verify! */ + #endif + nametbl_addr = ((m_cont_reg[2] & 0xfc) << 10); + patternmask = ((m_cont_reg[2] & 3) << 10) | 0x3ff; /* seems correct */ + + fg = pens[m_pal_ind16[m_cont_reg[7] >> 4]]; + bg = pens[m_pal_ind16[m_cont_reg[7] & 15]]; + fg0 = pens[m_pal_ind16[m_cont_reg[12] >> 4]]; + bg0 = pens[m_pal_ind16[m_cont_reg[12] & 15]]; + + name = (line/8)*80; + + xxx = (m_offset_x + 8) * 2; + pen = pens[m_pal_ind16[(m_cont_reg[7]&0x0f)]]; + while (xxx--) *ln++ = pen; + + for (x=0;x<80;x++) + { + charcode = m_vram_space->read_byte(nametbl_addr + (name&patternmask)); + if (m_blink) + { + pattern = m_vram_space->read_byte(colourtbl_addr + ((name/8)&colourmask)); + if (pattern & (0x80 >> (name & 7) ) ) + { + pattern = m_vram_space->read_byte(patterntbl_addr + ((charcode * 8) + + ((line + m_cont_reg[23]) & 7))); + + *ln++ = (pattern & 0x80) ? fg0 : bg0; + *ln++ = (pattern & 0x40) ? fg0 : bg0; + *ln++ = (pattern & 0x20) ? fg0 : bg0; + *ln++ = (pattern & 0x10) ? fg0 : bg0; + *ln++ = (pattern & 0x08) ? fg0 : bg0; + *ln++ = (pattern & 0x04) ? fg0 : bg0; + + name++; + continue; + } + } + + pattern = m_vram_space->read_byte(patterntbl_addr + ((charcode * 8) + + ((line + m_cont_reg[23]) & 7))); + + *ln++ = (pattern & 0x80) ? fg : bg; + *ln++ = (pattern & 0x40) ? fg : bg; + *ln++ = (pattern & 0x20) ? fg : bg; + *ln++ = (pattern & 0x10) ? fg : bg; + *ln++ = (pattern & 0x08) ? fg : bg; + *ln++ = (pattern & 0x04) ? fg : bg; + + name++; + } + + xxx = (16 - m_offset_x + 8) * 2; + while (xxx--) *ln++ = pen; +} + +void v99x8_device::mode_multi(const pen_t *pens, UINT16 *ln, int line) +{ + int nametbl_addr, patterntbl_addr, colour; + int name, line2, x, xx; + UINT16 pen, pen_bg; + + nametbl_addr = (m_cont_reg[2] << 10); + patterntbl_addr = (m_cont_reg[4] << 11); + + line2 = (line - m_cont_reg[23]) & 255; + name = (line2/8)*32; + + pen_bg = pens[m_pal_ind16[(m_cont_reg[7]&0x0f)]]; + xx = m_offset_x * 2; + while (xx--) *ln++ = pen_bg; + + for (x=0;x<32;x++) + { + colour = m_vram_space->read_byte(patterntbl_addr + (m_vram_space->read_byte(nametbl_addr + name) * 8) + ((line2/4)&7)); + pen = pens[m_pal_ind16[colour>>4]]; + /* eight pixels */ + *ln++ = pen; + *ln++ = pen; + *ln++ = pen; + *ln++ = pen; + *ln++ = pen; + *ln++ = pen; + *ln++ = pen; + *ln++ = pen; + pen = pens[m_pal_ind16[colour&15]]; + /* eight pixels */ + *ln++ = pen; + *ln++ = pen; + *ln++ = pen; + *ln++ = pen; + *ln++ = pen; + *ln++ = pen; + *ln++ = pen; + *ln++ = pen; + name++; + } + + xx = (16 - m_offset_x) * 2; + while (xx--) *ln++ = pen_bg; +} + +void v99x8_device::mode_graphic1(const pen_t *pens, UINT16 *ln, int line) +{ + UINT16 fg, bg, pen; + int nametbl_addr, patterntbl_addr, colourtbl_addr; + int pattern, x, xx, line2, name, charcode, colour, xxx; + + nametbl_addr = (m_cont_reg[2] << 10); + colourtbl_addr = (m_cont_reg[3] << 6) + (m_cont_reg[10] << 14); + patterntbl_addr = (m_cont_reg[4] << 11); + + line2 = (line - m_cont_reg[23]) & 255; + + name = (line2/8)*32; + + pen = pens[m_pal_ind16[(m_cont_reg[7]&0x0f)]]; + xxx = m_offset_x * 2; + while (xxx--) *ln++ = pen; + + for (x=0;x<32;x++) + { + charcode = m_vram_space->read_byte(nametbl_addr + name); + colour = m_vram_space->read_byte(colourtbl_addr + charcode/8); + fg = pens[m_pal_ind16[colour>>4]]; + bg = pens[m_pal_ind16[colour&15]]; + pattern = m_vram_space->read_byte(patterntbl_addr + (charcode * 8 + (line2 & 7))); + + for (xx=0;xx<8;xx++) + { + *ln++ = (pattern & 0x80) ? fg : bg; + *ln++ = (pattern & 0x80) ? fg : bg; + pattern <<= 1; + } + name++; + } + + xx = (16 - m_offset_x) * 2; + while (xx--) *ln++ = pen; +} + +void v99x8_device::mode_graphic23(const pen_t *pens, UINT16 *ln, int line) +{ + UINT16 fg, bg, pen; + int nametbl_addr, patterntbl_addr, colourtbl_addr; + int pattern, x, xx, line2, name, charcode, + colour, colourmask, patternmask, xxx; + + colourmask = ((m_cont_reg[3] & 0x7f) * 8) | 7; + patternmask = ((m_cont_reg[4] & 0x03) * 256) | 0xff; + + nametbl_addr = (m_cont_reg[2] << 10); + colourtbl_addr = ((m_cont_reg[3] & 0x80) << 6) + (m_cont_reg[10] << 14); + patterntbl_addr = ((m_cont_reg[4] & 0x3c) << 11); + + line2 = (line + m_cont_reg[23]) & 255; + name = (line2/8)*32; + + pen = pens[m_pal_ind16[(m_cont_reg[7]&0x0f)]]; + xxx = m_offset_x * 2; + while (xxx--) *ln++ = pen; + + for (x=0;x<32;x++) + { + charcode = m_vram_space->read_byte(nametbl_addr + name) + (line2&0xc0)*4; + colour = m_vram_space->read_byte(colourtbl_addr + ((charcode&colourmask)*8+(line2&7))); + pattern = m_vram_space->read_byte(patterntbl_addr + ((charcode&patternmask)*8+(line2&7))); + fg = pens[m_pal_ind16[colour>>4]]; + bg = pens[m_pal_ind16[colour&15]]; + for (xx=0;xx<8;xx++) + { + *ln++ = (pattern & 0x80) ? fg : bg; + *ln++ = (pattern & 0x80) ? fg : bg; + pattern <<= 1; + } + name++; + } + + xx = (16 - m_offset_x) * 2; + while (xx--) *ln++ = pen; +} + +void v99x8_device::mode_graphic4(const pen_t *pens, UINT16 *ln, int line) +{ + int nametbl_addr, colour; + int line2, linemask, x, xx; + UINT16 pen, pen_bg; + + linemask = ((m_cont_reg[2] & 0x1f) << 3) | 7; + + line2 = ((line + m_cont_reg[23]) & linemask) & 255; + + nametbl_addr = ((m_cont_reg[2] & 0x40) << 10) + line2 * 128; + if ( (m_cont_reg[2] & 0x20) && v9938_second_field() ) + nametbl_addr += 0x8000; + + pen_bg = pens[m_pal_ind16[(m_cont_reg[7]&0x0f)]]; + xx = m_offset_x * 2; + while (xx--) *ln++ = pen_bg; + + for (x=0;x<128;x++) + { + colour = m_vram_space->read_byte(nametbl_addr++); + pen = pens[m_pal_ind16[colour>>4]]; + *ln++ = pen; + *ln++ = pen; + pen = pens[m_pal_ind16[colour&15]]; + *ln++ = pen; + *ln++ = pen; + } + + xx = (16 - m_offset_x) * 2; + while (xx--) *ln++ = pen_bg; +} + +void v99x8_device::mode_graphic5(const pen_t *pens, UINT16 *ln, int line) +{ + int nametbl_addr, colour; + int line2, linemask, x, xx; + UINT16 pen_bg0[4]; + UINT16 pen_bg1[4]; + + linemask = ((m_cont_reg[2] & 0x1f) << 3) | 7; + + line2 = ((line + m_cont_reg[23]) & linemask) & 255; + + nametbl_addr = ((m_cont_reg[2] & 0x40) << 10) + line2 * 128; + if ( (m_cont_reg[2] & 0x20) && v9938_second_field() ) + nametbl_addr += 0x8000; + + pen_bg1[0] = pens[m_pal_ind16[(m_cont_reg[7]&0x03)]]; + pen_bg0[0] = pens[m_pal_ind16[((m_cont_reg[7]>>2)&0x03)]]; + + xx = m_offset_x; + while (xx--) { *ln++ = pen_bg0[0]; *ln++ = pen_bg1[0]; } + + x = (m_cont_reg[8] & 0x20) ? 0 : 1; + + for (;x<4;x++) + { + pen_bg0[x] = pens[m_pal_ind16[x]]; + pen_bg1[x] = pens[m_pal_ind16[x]]; + } + + for (x=0;x<128;x++) + { + colour = m_vram_space->read_byte(nametbl_addr++); + + *ln++ = pen_bg0[colour>>6]; + *ln++ = pen_bg1[(colour>>4)&3]; + *ln++ = pen_bg0[(colour>>2)&3]; + *ln++ = pen_bg1[(colour&3)]; + } + + pen_bg1[0] = pens[m_pal_ind16[(m_cont_reg[7]&0x03)]]; + pen_bg0[0] = pens[m_pal_ind16[((m_cont_reg[7]>>2)&0x03)]]; + xx = 16 - m_offset_x; + while (xx--) { *ln++ = pen_bg0[0]; *ln++ = pen_bg1[0]; } +} + +void v99x8_device::mode_graphic6(const pen_t *pens, UINT16 *ln, int line) +{ + UINT8 colour; + int line2, linemask, x, xx, nametbl_addr; + UINT16 pen_bg, fg0; + UINT16 fg1; + + linemask = ((m_cont_reg[2] & 0x1f) << 3) | 7; + + line2 = ((line + m_cont_reg[23]) & linemask) & 255; + + nametbl_addr = line2 << 8 ; + if ( (m_cont_reg[2] & 0x20) && v9938_second_field() ) + nametbl_addr += 0x10000; + + pen_bg = pens[m_pal_ind16[(m_cont_reg[7]&0x0f)]]; + xx = m_offset_x * 2; + while (xx--) *ln++ = pen_bg; + + if (m_cont_reg[2] & 0x40) + { + for (x=0;x<32;x++) + { + nametbl_addr++; + colour = m_vram_space->read_byte(((nametbl_addr&1) << 16) | (nametbl_addr>>1)); + fg0 = pens[m_pal_ind16[colour>>4]]; + fg1 = pens[m_pal_ind16[colour&15]]; + *ln++ = fg0; *ln++ = fg1; *ln++ = fg0; *ln++ = fg1; + *ln++ = fg0; *ln++ = fg1; *ln++ = fg0; *ln++ = fg1; + *ln++ = fg0; *ln++ = fg1; *ln++ = fg0; *ln++ = fg1; + *ln++ = fg0; *ln++ = fg1; *ln++ = fg0; *ln++ = fg1; + nametbl_addr += 7; + } + } + else + { + for (x=0;x<256;x++) + { + colour = m_vram_space->read_byte(((nametbl_addr&1) << 16) | (nametbl_addr>>1)); + *ln++ = pens[m_pal_ind16[colour>>4]]; + *ln++ = pens[m_pal_ind16[colour&15]]; + nametbl_addr++; + } + } + + xx = (16 - m_offset_x) * 2; + while (xx--) *ln++ = pen_bg; +} + +void v99x8_device::mode_graphic7(const pen_t *pens, UINT16 *ln, int line) +{ + UINT8 colour; + int line2, linemask, x, xx, nametbl_addr; + UINT16 pen, pen_bg; + + linemask = ((m_cont_reg[2] & 0x1f) << 3) | 7; + + line2 = ((line + m_cont_reg[23]) & linemask) & 255; + + nametbl_addr = line2 << 8; + if ( (m_cont_reg[2] & 0x20) && v9938_second_field() ) + nametbl_addr += 0x10000; + + pen_bg = pens[m_pal_ind256[m_cont_reg[7]]]; + xx = m_offset_x * 2; + while (xx--) *ln++ = pen_bg; + + if ((m_v9958_sp_mode & 0x18) == 0x08) // v9958 screen 12, puzzle star title screen + { + for (x=0;x<64;x++) + { + int colour[4]; + int ind; + + colour[0] = m_vram_space->read_byte(((nametbl_addr&1) << 16) | (nametbl_addr>>1)); + nametbl_addr++; + colour[1] = m_vram_space->read_byte(((nametbl_addr&1) << 16) | (nametbl_addr>>1)); + nametbl_addr++; + colour[2] = m_vram_space->read_byte(((nametbl_addr&1) << 16) | (nametbl_addr>>1)); + nametbl_addr++; + colour[3] = m_vram_space->read_byte(((nametbl_addr&1) << 16) | (nametbl_addr>>1)); + + ind = (colour[0] & 7) << 11 | (colour[1] & 7) << 14 | + (colour[2] & 7) << 5 | (colour[3] & 7) << 8; + + *ln++ = s_pal_indYJK[ind | ((colour[0] >> 3) & 31)]; + *ln++ = s_pal_indYJK[ind | ((colour[0] >> 3) & 31)]; + + *ln++ = s_pal_indYJK[ind | ((colour[1] >> 3) & 31)]; + *ln++ = s_pal_indYJK[ind | ((colour[1] >> 3) & 31)]; + + *ln++ = s_pal_indYJK[ind | ((colour[2] >> 3) & 31)]; + *ln++ = s_pal_indYJK[ind | ((colour[2] >> 3) & 31)]; + + *ln++ = s_pal_indYJK[ind | ((colour[3] >> 3) & 31)]; + *ln++ = s_pal_indYJK[ind | ((colour[3] >> 3) & 31)]; + + nametbl_addr++; + } + } + else if ((m_v9958_sp_mode & 0x18) == 0x18) // v9958 screen 10/11, puzzle star & sexy boom gameplay + { + for (x=0;x<64;x++) + { + int colour[4]; + int ind; + + colour[0] = m_vram_space->read_byte(((nametbl_addr&1) << 16) | (nametbl_addr>>1)); + nametbl_addr++; + colour[1] = m_vram_space->read_byte(((nametbl_addr&1) << 16) | (nametbl_addr>>1)); + nametbl_addr++; + colour[2] = m_vram_space->read_byte(((nametbl_addr&1) << 16) | (nametbl_addr>>1)); + nametbl_addr++; + colour[3] = m_vram_space->read_byte(((nametbl_addr&1) << 16) | (nametbl_addr>>1)); + + ind = (colour[0] & 7) << 11 | (colour[1] & 7) << 14 | + (colour[2] & 7) << 5 | (colour[3] & 7) << 8; + + *ln++ = colour[0] & 8 ? m_pal_ind16[colour[0] >> 4] : s_pal_indYJK[ind | ((colour[0] >> 3) & 30)]; + *ln++ = colour[0] & 8 ? m_pal_ind16[colour[0] >> 4] : s_pal_indYJK[ind | ((colour[0] >> 3) & 30)]; + + *ln++ = colour[1] & 8 ? m_pal_ind16[colour[1] >> 4] : s_pal_indYJK[ind | ((colour[1] >> 3) & 30)]; + *ln++ = colour[1] & 8 ? m_pal_ind16[colour[1] >> 4] : s_pal_indYJK[ind | ((colour[1] >> 3) & 30)]; + + *ln++ = colour[2] & 8 ? m_pal_ind16[colour[2] >> 4] : s_pal_indYJK[ind | ((colour[2] >> 3) & 30)]; + *ln++ = colour[2] & 8 ? m_pal_ind16[colour[2] >> 4] : s_pal_indYJK[ind | ((colour[2] >> 3) & 30)]; + + *ln++ = colour[3] & 8 ? m_pal_ind16[colour[3] >> 4] : s_pal_indYJK[ind | ((colour[3] >> 3) & 30)]; + *ln++ = colour[3] & 8 ? m_pal_ind16[colour[3] >> 4] : s_pal_indYJK[ind | ((colour[3] >> 3) & 30)]; + + nametbl_addr++; + } + } + else if (m_cont_reg[2] & 0x40) + { + for (x=0;x<32;x++) + { + nametbl_addr++; + colour = m_vram_space->read_byte(((nametbl_addr&1) << 16) | (nametbl_addr>>1)); + pen = pens[m_pal_ind256[colour]]; + *ln++ = pen; *ln++ = pen; + *ln++ = pen; *ln++ = pen; + *ln++ = pen; *ln++ = pen; + *ln++ = pen; *ln++ = pen; + *ln++ = pen; *ln++ = pen; + *ln++ = pen; *ln++ = pen; + *ln++ = pen; *ln++ = pen; + *ln++ = pen; *ln++ = pen; + nametbl_addr++; + } + } + else + { + for (x=0;x<256;x++) + { + colour = m_vram_space->read_byte(((nametbl_addr&1) << 16) | (nametbl_addr>>1)); + pen = pens[m_pal_ind256[colour]]; + *ln++ = pen; + *ln++ = pen; + nametbl_addr++; + } + } + + xx = (16 - m_offset_x) * 2; + while (xx--) *ln++ = pen_bg; +} + +void v99x8_device::mode_unknown(const pen_t *pens, UINT16 *ln, int line) +{ + UINT16 fg, bg; + int x; + + fg = pens[m_pal_ind16[m_cont_reg[7] >> 4]]; + bg = pens[m_pal_ind16[m_cont_reg[7] & 15]]; + + x = m_offset_x * 2; + while (x--) *ln++ = bg; + + x = 512; + while (x--) *ln++ = fg; + + x = (16 - m_offset_x) * 2; + while (x--) *ln++ = bg; +} + +void v99x8_device::default_draw_sprite(const pen_t *pens, UINT16 *ln, UINT8 *col) +{ + int i; + ln += m_offset_x * 2; + + for (i=0;i<256;i++) + { + if (col[i] & 0x80) + { + *ln++ = pens[m_pal_ind16[col[i]&0x0f]]; + *ln++ = pens[m_pal_ind16[col[i]&0x0f]]; + } + else + { + ln += 2; + } + } +} + +void v99x8_device::graphic5_draw_sprite(const pen_t *pens, UINT16 *ln, UINT8 *col) +{ + int i; + ln += m_offset_x * 2; + + for (i=0;i<256;i++) + { + if (col[i] & 0x80) + { + *ln++ = pens[m_pal_ind16[(col[i]>>2)&0x03]]; + *ln++ = pens[m_pal_ind16[col[i]&0x03]]; + } + else + { + ln += 2; + } + } +} + + +void v99x8_device::graphic7_draw_sprite(const pen_t *pens, UINT16 *ln, UINT8 *col) +{ + static const UINT16 g7_ind16[16] = { + 0, 2, 192, 194, 48, 50, 240, 242, + 482, 7, 448, 455, 56, 63, 504, 511 }; + int i; + + ln += m_offset_x * 2; + + for (i=0;i<256;i++) + { + if (col[i] & 0x80) + { + *ln++ = pens[g7_ind16[col[i]&0x0f]]; + *ln++ = pens[g7_ind16[col[i]&0x0f]]; + } + else + { + ln += 2; + } + } +} + + +void v99x8_device::sprite_mode1 (int line, UINT8 *col) +{ + int attrtbl_addr, patterntbl_addr, pattern_addr; + int x, y, p, height, c, p2, i, n, pattern; + + memset(col, 0, 256); + + // are sprites disabled? + if (m_cont_reg[8] & 0x02) return; + + attrtbl_addr = (m_cont_reg[5] << 7) + (m_cont_reg[11] << 15); + patterntbl_addr = (m_cont_reg[6] << 11); + + // 16x16 or 8x8 sprites + height = (m_cont_reg[1] & 2) ? 16 : 8; + // magnified sprites (zoomed) + if (m_cont_reg[1] & 1) height *= 2; + + p2 = p = 0; + while (1) + { + y = m_vram_space->read_byte(attrtbl_addr); + if (y == 208) break; + y = (y - m_cont_reg[23]) & 255; + if (y > 208) + y = -(~y&255); + else + y++; + + // if sprite in range, has to be drawn + if ( (line >= y) && (line < (y + height) ) ) + { + if (p2 == 4) + { + // max maximum sprites per line! + if ( !(m_stat_reg[0] & 0x40) ) + m_stat_reg[0] = (m_stat_reg[0] & 0xa0) | 0x40 | p; + + break; + } + // get x + x = m_vram_space->read_byte(attrtbl_addr + 1); + if (m_vram_space->read_byte(attrtbl_addr + 3) & 0x80) x -= 32; + + // get pattern + pattern = m_vram_space->read_byte(attrtbl_addr + 2); + if (m_cont_reg[1] & 2) + pattern &= 0xfc; + n = line - y; + pattern_addr = patterntbl_addr + pattern * 8 + ((m_cont_reg[1] & 1) ? n/2 : n); + pattern = (m_vram_space->read_byte(pattern_addr) << 8) | m_vram_space->read_byte(pattern_addr+16); + + // get colour + c = m_vram_space->read_byte(attrtbl_addr + 3) & 0x0f; + + // draw left part + n = 0; + while (1) + { + if (n == 0) pattern = m_vram_space->read_byte(pattern_addr); + else if ( (n == 1) && (m_cont_reg[1] & 2) ) pattern = m_vram_space->read_byte(pattern_addr + 16); + else break; + + n++; + + for (i=0;i<8;i++) + { + if (pattern & 0x80) + { + if ( (x >= 0) && (x < 256) ) + { + if (col[x] & 0x40) + { + // we have a collision! + if (p2 < 4) + m_stat_reg[0] |= 0x20; + } + if ( !(col[x] & 0x80) ) + { + if (c || (m_cont_reg[8] & 0x20) ) + col[x] |= 0xc0 | c; + else + col[x] |= 0x40; + } + + // if zoomed, draw another pixel + if (m_cont_reg[1] & 1) + { + if (col[x+1] & 0x40) + { + // we have a collision! + if (p2 < 4) + m_stat_reg[0] |= 0x20; + } + if ( !(col[x+1] & 0x80) ) + { + if (c || (m_cont_reg[8] & 0x20) ) + col[x+1] |= 0xc0 | c; + else + col[x+1] |= 0x80; + } + } + } + } + if (m_cont_reg[1] & 1) x += 2; else x++; + pattern <<= 1; + } + } + + p2++; + } + + if (p >= 31) break; + p++; + attrtbl_addr += 4; + } + + if ( !(m_stat_reg[0] & 0x40) ) + m_stat_reg[0] = (m_stat_reg[0] & 0xa0) | p; +} + +void v99x8_device::sprite_mode2 (int line, UINT8 *col) +{ + int attrtbl_addr, patterntbl_addr, pattern_addr, colourtbl_addr; + int x, i, y, p, height, c, p2, n, pattern, colourmask, first_cc_seen; + + memset(col, 0, 256); + + // are sprites disabled? + if (m_cont_reg[8] & 0x02) return; + + attrtbl_addr = ( (m_cont_reg[5] & 0xfc) << 7) + (m_cont_reg[11] << 15); + colourtbl_addr = ( (m_cont_reg[5] & 0xf8) << 7) + (m_cont_reg[11] << 15); + patterntbl_addr = (m_cont_reg[6] << 11); + colourmask = ( (m_cont_reg[5] & 3) << 3) | 0x7; // check this! + + // 16x16 or 8x8 sprites + height = (m_cont_reg[1] & 2) ? 16 : 8; + // magnified sprites (zoomed) + if (m_cont_reg[1] & 1) height *= 2; + + p2 = p = first_cc_seen = 0; + while (1) + { + y = vram_read(attrtbl_addr); + if (y == 216) break; + y = (y - m_cont_reg[23]) & 255; + if (y > 216) + y = -(~y&255); + else + y++; + + // if sprite in range, has to be drawn + if ( (line >= y) && (line < (y + height) ) ) + { + if (p2 == 8) + { + // max maximum sprites per line! + if ( !(m_stat_reg[0] & 0x40) ) + m_stat_reg[0] = (m_stat_reg[0] & 0xa0) | 0x40 | p; + + break; + } + + n = line - y; if (m_cont_reg[1] & 1) n /= 2; + // get colour + c = vram_read(colourtbl_addr + (((p&colourmask)*16) + n)); + + // don't draw all sprite with CC set before any sprites + // with CC = 0 are seen on this line + if (c & 0x40) + { + if (!first_cc_seen) + goto skip_first_cc_set; + } + else + first_cc_seen = 1; + + // get pattern + pattern = vram_read(attrtbl_addr + 2); + if (m_cont_reg[1] & 2) + pattern &= 0xfc; + pattern_addr = patterntbl_addr + pattern * 8 + n; + pattern = (vram_read(pattern_addr) << 8) | vram_read(pattern_addr + 16); + + // get x + x = vram_read(attrtbl_addr + 1); + if (c & 0x80) x -= 32; + + n = (m_cont_reg[1] & 2) ? 16 : 8; + while (n--) + { + for (i=0;i<=(m_cont_reg[1] & 1);i++) + { + if ( (x >= 0) && (x < 256) ) + { + if ( (pattern & 0x8000) && !(col[x] & 0x10) ) + { + if ( (c & 15) || (m_cont_reg[8] & 0x20) ) + { + if ( !(c & 0x40) ) + { + if (col[x] & 0x20) col[x] |= 0x10; + else + col[x] |= 0x20 | (c & 15); + } + else + col[x] |= c & 15; + + col[x] |= 0x80; + } + } + else + { + if ( !(c & 0x40) && (col[x] & 0x20) ) + col[x] |= 0x10; + } + + if ( !(c & 0x60) && (pattern & 0x8000) ) + { + if (col[x] & 0x40) + { + // sprite collision! + if (p2 < 8) + m_stat_reg[0] |= 0x20; + } + else + col[x] |= 0x40; + } + + x++; + } + } + + pattern <<= 1; + } + + skip_first_cc_set: + p2++; + } + + if (p >= 31) break; + p++; + attrtbl_addr += 4; + } + + if ( !(m_stat_reg[0] & 0x40) ) + m_stat_reg[0] = (m_stat_reg[0] & 0xa0) | p; +} + + +const v99x8_device::v99x8_mode v99x8_device::s_modes[] = { + { 0x02, + &v99x8_device::mode_text1, + &v99x8_device::default_border, + NULL, + NULL + }, + { 0x01, + &v99x8_device::mode_multi, + &v99x8_device::default_border, + &v99x8_device::sprite_mode1, + &v99x8_device::default_draw_sprite + }, + { 0x00, + &v99x8_device::mode_graphic1, + &v99x8_device::default_border, + &v99x8_device::sprite_mode1, + &v99x8_device::default_draw_sprite + }, + { 0x04, + &v99x8_device::mode_graphic23, + &v99x8_device::default_border, + &v99x8_device::sprite_mode1, + &v99x8_device::default_draw_sprite + }, + { 0x08, + &v99x8_device::mode_graphic23, + &v99x8_device::default_border, + &v99x8_device::sprite_mode2, + &v99x8_device::default_draw_sprite + }, + { 0x0c, + &v99x8_device::mode_graphic4, + &v99x8_device::default_border, + &v99x8_device::sprite_mode2, + &v99x8_device::default_draw_sprite + }, + { 0x10, + &v99x8_device::mode_graphic5, + &v99x8_device::graphic5_border, + &v99x8_device::sprite_mode2, + &v99x8_device::graphic5_draw_sprite + }, + { 0x14, + &v99x8_device::mode_graphic6, + &v99x8_device::default_border, + &v99x8_device::sprite_mode2, + &v99x8_device::default_draw_sprite + }, + { 0x1c, + &v99x8_device::mode_graphic7, + &v99x8_device::graphic7_border, + &v99x8_device::sprite_mode2, + &v99x8_device::graphic7_draw_sprite + }, + { 0x0a, + &v99x8_device::mode_text2, + &v99x8_device::default_border, + NULL, + NULL + }, + { 0xff, + &v99x8_device::mode_unknown, + &v99x8_device::default_border, + NULL, + NULL + } +}; + +void v99x8_device::set_mode() +{ + int n,i; + + n = (((m_cont_reg[0] & 0x0e) << 1) | ((m_cont_reg[1] & 0x18) >> 3)); + for (i=0;;i++) + { + if ( (s_modes[i].m == n) || (s_modes[i].m == 0xff) ) break; + } + m_mode = i; +} + +void v99x8_device::refresh_16(int line) +{ + const pen_t *pens = m_palette->pens(); + bool double_lines = false; + UINT8 col[256]; + UINT16 *ln, *ln2 = NULL; + + if (m_cont_reg[9] & 0x08) + { + ln = &m_bitmap.pix16(line*2+((m_stat_reg[2]>>1)&1)); + } + else + { + ln = &m_bitmap.pix16(line*2); + ln2 = &m_bitmap.pix16(line*2+1); + double_lines = true; + } + + if ( !(m_cont_reg[1] & 0x40) || (m_stat_reg[2] & 0x40) ) + { + (this->*s_modes[m_mode].border_16) (pens, ln); + } + else + { + int i = (line - m_offset_y) & 255; + (this->*s_modes[m_mode].visible_16) (pens, ln, i); + if (s_modes[m_mode].sprites) + { + (this->*s_modes[m_mode].sprites) (i, col); + (this->*s_modes[m_mode].draw_sprite_16) (pens, ln, col); + } + } + + if (double_lines) + memcpy (ln2, ln, (512 + 32) * 2); +} + +void v99x8_device::refresh_line(int line) +{ + int ind16, ind256; + + ind16 = m_pal_ind16[0]; + ind256 = m_pal_ind256[0]; + + if ( !(m_cont_reg[8] & 0x20) && (m_mode != V9938_MODE_GRAPHIC5) ) + { + m_pal_ind16[0] = m_pal_ind16[(m_cont_reg[7] & 0x0f)]; + m_pal_ind256[0] = m_pal_ind256[m_cont_reg[7]]; + } + + refresh_16 (line); + + if ( !(m_cont_reg[8] & 0x20) && (m_mode != V9938_MODE_GRAPHIC5) ) + { + m_pal_ind16[0] = ind16; + m_pal_ind256[0] = ind256; + } +} + +/* + +From: awulms@inter.nl.net (Alex Wulms) +*** About the HR/VR topic: this is how it works according to me: + +*** HR: +HR is very straightforward: +-HR=1 during 'display time' +-HR=0 during 'horizontal border, horizontal retrace' +I have put 'display time' and 'horizontal border, horizontal retrace' between +quotes because HR does not only flip between 0 and 1 during the display of +the 192/212 display lines, but also during the vertical border and during the +vertical retrace. + +*** VR: +VR is a little bit tricky +-VR always gets set to 0 when the VDP starts with display line 0 +-VR gets set to 1 when the VDP reaches display line (192 if LN=0) or (212 if +LN=1) +-The VDP displays contents of VRAM as long as VR=0 + +As a consequence of this behaviour, it is possible to program the famous +overscan trick, where VRAM contents is shown in the borders: +Generate an interrupt at line 230 (or so) and on this interrupt: set LN=1 +Generate an interrupt at line 200 (or so) and on this interrupt: set LN=0 +Repeat the above two steps + +*** The top/bottom border contents during overscan: +On screen 0: +1) The VDP keeps increasing the name table address pointer during bottom +border, vertical retrace and top border +2) The VDP resets the name table address pointer when the first display line +is reached + +On the other screens: +1) The VDP keeps increasing the name table address pointer during the bottom +border +2) The VDP resets the name table address pointer such that the top border +contents connects up with the first display line. E.g., when the top border +is 26 lines high, the VDP will take: +'logical' vram line +TOPB000 256-26 +... +TOPB025 256-01 +DISPL000 000 +... +DISPL211 211 +BOTB000 212 +... +BOTB024 236 + + + +*** About the horizontal interrupt + +All relevant definitions on a row: +-FH: Bit 0 of status register 1 +-IE1: Bit 4 of mode register 0 +-IL: Line number in mode register 19 +-DL: The line that the VDP is going to display (corrected for vertical scroll) +-IRQ: Interrupt request line of VDP to Z80 + +At the *start* of every new line (display, bottom border, part of vertical +display), the VDP does: +-FH = (FH && IE1) || (IL==DL) + +After reading of status register 1 by the CPU, the VDP does: +-FH = 0 + +Furthermore, the following is true all the time: +-IRQ = FH && IE1 + +The resulting behaviour: +When IE1=0: +-FH will be set as soon as display of line IL starts +-FH will be reset as soon as status register 1 is read +-FH will be reset as soon as the next display line is reached + +When IE=1: +-FH and IRQ will be set as soon as display line IL is reached +-FH and IRQ will be reset as soon as status register 1 is read + +Another subtile result: +If, while FH and IRQ are set, IE1 gets reset, the next happens: +-IRQ is reset immediately (since IRQ is always FH && IE1) +-FH will be reset as soon as display of the next line starts (unless the next +line is line IL) + + +*** About the vertical interrupt: +Another relevant definition: +-FV: Bit 7 of status register 0 +-IE0: Bit 5 of mode register 1 + +I only know for sure the behaviour when IE0=1: +-FV and IRQ will be set as soon as VR changes from 0 to 1 +-FV and IRQ will be reset as soon as status register 0 is read + +A consequence is that NO vertical interrupts will be generated during the +overscan trick, described in the VR section above. + +I do not know the behaviour of FV when IE0=0. That is the part that I still +have to test. +*/ + +void v99x8_device::interrupt_start_vblank() +{ + #if 0 + if (machine.input().code_pressed (KEYCODE_D) ) + { + for (i=0;i<24;i++) osd_printf_debug ("R#%d = %02x\n", i, m_cont_reg[i]); + } + #endif + + // at every frame, vdp switches fields + m_stat_reg[2] = (m_stat_reg[2] & 0xfd) | (~m_stat_reg[2] & 2); + + // color blinking + if (!(m_cont_reg[13] & 0xf0)) + m_blink = 0; + else if (!(m_cont_reg[13] & 0x0f)) + m_blink = 1; + else + { + // both on and off counter are non-zero: timed blinking + if (m_blink_count) + m_blink_count--; + if (!m_blink_count) + { + m_blink = !m_blink; + if (m_blink) + m_blink_count = (m_cont_reg[13] >> 4) * 10; + else + m_blink_count = (m_cont_reg[13] & 0x0f) * 10; + } + } +} + +/*************************************************************************** + +Command unit + +***************************************************************************/ + +/*************************************************************/ +/** Completely rewritten by Alex Wulms: **/ +/** - VDP Command execution 'in parallel' with CPU **/ +/** - Corrected behaviour of VDP commands **/ +/** - Made it easier to implement correct S7/8 mapping **/ +/** by concentrating VRAM access in one single place **/ +/** - Made use of the 'in parallel' VDP command exec **/ +/** and correct timing. You must call the function **/ +/** LoopVDP() from LoopZ80 in MSX.c. You must call it **/ +/** exactly 256 times per screen refresh. **/ +/** Started on : 11-11-1999 **/ +/** Beta release 1 on: 9-12-1999 **/ +/** Beta release 2 on: 20-01-2000 **/ +/** - Corrected behaviour of VRM <-> Z80 transfer **/ +/** - Improved performance of the code **/ +/** Public release 1.0: 20-04-2000 **/ +/*************************************************************/ + +#define VDP_VRMP5(MX, X, Y) ((!MX) ? (((Y&1023)<<7) + ((X&255)>>1)) : (EXPMEM_OFFSET + ((Y&511)<<7) + ((X&255)>>1))) +#define VDP_VRMP6(MX, X, Y) ((!MX) ? (((Y&1023)<<7) + ((X&511)>>2)) : (EXPMEM_OFFSET + ((Y&511)<<7) + ((X&511)>>2))) +//#define VDP_VRMP7(MX, X, Y) ((!MX) ? (((Y&511)<<8) + ((X&511)>>1)) : (EXPMEM_OFFSET + ((Y&255)<<8) + ((X&511)>>1))) +#define VDP_VRMP7(MX, X, Y) ((!MX) ? (((X&2)<<15) + ((Y&511)<<7) + ((X&511)>>2)) : (EXPMEM_OFFSET + ((Y&511)<<7) + ((X&511)>>2))/*(EXPMEM_OFFSET + ((Y&255)<<8) + ((X&511)>>1))*/) +//#define VDP_VRMP8(MX, X, Y) ((!MX) ? (((Y&511)<<8) + (X&255)) : (EXPMEM_OFFSET + ((Y&255)<<8) + (X&255))) +#define VDP_VRMP8(MX, X, Y) ((!MX) ? (((X&1)<<16) + ((Y&511)<<7) + ((X>>1)&127)) : (EXPMEM_OFFSET + ((Y&511)<<7) + ((X>>1)&127))/*(EXPMEM_OFFSET + ((Y&255)<<8) + (X&255))*/) + +#define VDP_VRMP(M, MX, X, Y) VDPVRMP(M, MX, X, Y) +#define VDP_POINT(M, MX, X, Y) VDPpoint(M, MX, X, Y) +#define VDP_PSET(M, MX, X, Y, C, O) VDPpset(M, MX, X, Y, C, O) + +#define CM_ABRT 0x0 +#define CM_POINT 0x4 +#define CM_PSET 0x5 +#define CM_SRCH 0x6 +#define CM_LINE 0x7 +#define CM_LMMV 0x8 +#define CM_LMMM 0x9 +#define CM_LMCM 0xA +#define CM_LMMC 0xB +#define CM_HMMV 0xC +#define CM_HMMM 0xD +#define CM_YMMM 0xE +#define CM_HMMC 0xF + +/************************************************************* +Many VDP commands are executed in some kind of loop but +essentially, there are only a few basic loop structures +that are re-used. We define the loop structures that are +re-used here so that they have to be entered only once +*************************************************************/ +#define pre_loop \ +while ((cnt-=delta) > 0) { + #define post_loop \ +} + +// Loop over DX, DY +#define post__x_y(MX) \ +if (!--ANX || ((ADX+=TX)&MX)) { \ + if (!(--NY&1023) || (DY+=TY)==-1) \ + break; \ + else { \ + ADX=DX; \ + ANX=NX; \ + } \ +} \ +post_loop + +// Loop over DX, SY, DY +#define post__xyy(MX) \ +if ((ADX+=TX)&MX) { \ + if (!(--NY&1023) || (SY+=TY)==-1 || (DY+=TY)==-1) \ + break; \ + else \ + ADX=DX; \ +} \ +post_loop + +// Loop over SX, DX, SY, DY +#define post_xxyy(MX) \ +if (!--ANX || ((ASX+=TX)&MX) || ((ADX+=TX)&MX)) { \ + if (!(--NY&1023) || (SY+=TY)==-1 || (DY+=TY)==-1) \ + break; \ + else { \ + ASX=SX; \ + ADX=DX; \ + ANX=NX; \ + } \ +} \ +post_loop + +/*************************************************************/ +/** Variables visible only in this module **/ +/*************************************************************/ +static const UINT8 Mask[4] = { 0x0F,0x03,0x0F,0xFF }; +static const int PPB[4] = { 2,4,2,1 }; +static const int PPL[4] = { 256,512,512,256 }; + +// SprOn SprOn SprOf SprOf +// ScrOf ScrOn ScrOf ScrOn +static const int srch_timing[8]={ + 818, 1025, 818, 830, // ntsc + 696, 854, 696, 684 // pal +}; +static const int line_timing[8]={ + 1063, 1259, 1063, 1161, + 904, 1026, 904, 953 +}; +static const int hmmv_timing[8]={ + 439, 549, 439, 531, + 366, 439, 366, 427 +}; +static const int lmmv_timing[8]={ + 873, 1135, 873, 1056, + 732, 909, 732, 854 +}; +static const int ymmm_timing[8]={ + 586, 952, 586, 610, + 488, 720, 488, 500 +}; +static const int hmmm_timing[8]={ + 818, 1111, 818, 854, + 684, 879, 684, 708 +}; +static const int lmmm_timing[8]={ + 1160, 1599, 1160, 1172, + 964, 1257, 964, 977 +}; + +/** VDPVRMP() **********************************************/ +/** Calculate addr of a pixel in vram **/ +/*************************************************************/ +inline int v99x8_device::VDPVRMP(UINT8 M,int MX,int X,int Y) +{ + switch(M) + { + case 0: return VDP_VRMP5(MX,X,Y); + case 1: return VDP_VRMP6(MX,X,Y); + case 2: return VDP_VRMP7(MX,X,Y); + case 3: return VDP_VRMP8(MX,X,Y); + } + + return 0; +} + +/** VDPpoint5() ***********************************************/ +/** Get a pixel on screen 5 **/ +/*************************************************************/ +inline UINT8 v99x8_device::VDPpoint5(int MXS, int SX, int SY) +{ + return (m_vram_space->read_byte(VDP_VRMP5(MXS, SX, SY)) >> + (((~SX)&1)<<2) + )&15; +} + +/** VDPpoint6() ***********************************************/ +/** Get a pixel on screen 6 **/ +/*************************************************************/ +inline UINT8 v99x8_device::VDPpoint6(int MXS, int SX, int SY) +{ + return (m_vram_space->read_byte(VDP_VRMP6(MXS, SX, SY)) >> + (((~SX)&3)<<1) + )&3; +} + +/** VDPpoint7() ***********************************************/ +/** Get a pixel on screen 7 **/ +/*************************************************************/ +inline UINT8 v99x8_device::VDPpoint7(int MXS, int SX, int SY) +{ + return (m_vram_space->read_byte(VDP_VRMP7(MXS, SX, SY)) >> + (((~SX)&1)<<2) + )&15; +} + +/** VDPpoint8() ***********************************************/ +/** Get a pixel on screen 8 **/ +/*************************************************************/ +inline UINT8 v99x8_device::VDPpoint8(int MXS, int SX, int SY) +{ + return m_vram_space->read_byte(VDP_VRMP8(MXS, SX, SY)); +} + +/** VDPpoint() ************************************************/ +/** Get a pixel on a screen **/ +/*************************************************************/ +inline UINT8 v99x8_device::VDPpoint(UINT8 SM, int MXS, int SX, int SY) +{ + switch(SM) + { + case 0: return VDPpoint5(MXS,SX,SY); + case 1: return VDPpoint6(MXS,SX,SY); + case 2: return VDPpoint7(MXS,SX,SY); + case 3: return VDPpoint8(MXS,SX,SY); + } + + return(0); +} + +/** VDPpsetlowlevel() ****************************************/ +/** Low level function to set a pixel on a screen **/ +/** Make it inline to make it fast **/ +/*************************************************************/ +inline void v99x8_device::VDPpsetlowlevel(int addr, UINT8 CL, UINT8 M, UINT8 OP) +{ + // If this turns out to be too slow, get a pointer to the address space + // and work directly on it. + UINT8 val = m_vram_space->read_byte(addr); + switch (OP) + { + case 0: val = (val & M) | CL; break; + case 1: val = val & (CL | M); break; + case 2: val |= CL; break; + case 3: val ^= CL; break; + case 4: val = (val & M) | ~(CL | M); break; + case 8: if (CL) val = (val & M) | CL; break; + case 9: if (CL) val = val & (CL | M); break; + case 10: if (CL) val |= CL; break; + case 11: if (CL) val ^= CL; break; + case 12: if (CL) val = (val & M) | ~(CL|M); break; + default: + LOG(("v9938: invalid operation %d in pset\n", OP)); + } + + m_vram_space->write_byte(addr, val); +} + +/** VDPpset5() ***********************************************/ +/** Set a pixel on screen 5 **/ +/*************************************************************/ +inline void v99x8_device::VDPpset5(int MXD, int DX, int DY, UINT8 CL, UINT8 OP) +{ + UINT8 SH = ((~DX)&1)<<2; + VDPpsetlowlevel(VDP_VRMP5(MXD, DX, DY), CL << SH, ~(15<>6)&1)|(m_cont_reg[8]&2)|((m_cont_reg[9]<<1)&4)]); +} + +/** SrchEgine()** ********************************************/ +/** Search a dot **/ +/*************************************************************/ +void v99x8_device::srch_engine() +{ + int SX=m_mmc.SX; + int SY=m_mmc.SY; + int TX=m_mmc.TX; + int ANX=m_mmc.ANX; + UINT8 CL=m_mmc.CL; + int MXD = m_mmc.MXD; + int cnt; + int delta; + + delta = get_vdp_timing_value(srch_timing); + cnt = m_vdp_ops_count; + + #define post_srch(MX) \ + { m_stat_reg[2]|=0x10; /* Border detected */ break; } \ + if ((SX+=TX) & MX) { m_stat_reg[2] &= 0xEF; /* Border not detected */ break; } + switch (m_mode) { + default: + case V9938_MODE_GRAPHIC4: pre_loop if ((VDPpoint5(MXD, SX, SY)==CL) ^ANX) post_srch(256) post_loop + break; + case V9938_MODE_GRAPHIC5: pre_loop if ((VDPpoint6(MXD, SX, SY)==CL) ^ANX) post_srch(512) post_loop + break; + case V9938_MODE_GRAPHIC6: pre_loop if ((VDPpoint7(MXD, SX, SY)==CL) ^ANX) post_srch(512) post_loop + break; + case V9938_MODE_GRAPHIC7: pre_loop if ((VDPpoint8(MXD, SX, SY)==CL) ^ANX) post_srch(256) post_loop + break; + } + + if ((m_vdp_ops_count=cnt)>0) { + // Command execution done + m_stat_reg[2] &= 0xFE; + m_vdp_engine = 0; + // Update SX in VDP registers + m_stat_reg[8] = SX & 0xFF; + m_stat_reg[9] = (SX>>8) | 0xFE; + } + else { + m_mmc.SX=SX; + } +} + +/** LineEgine()** ********************************************/ +/** Draw a line **/ +/*************************************************************/ +void v99x8_device::line_engine() +{ + int DX=m_mmc.DX; + int DY=m_mmc.DY; + int TX=m_mmc.TX; + int TY=m_mmc.TY; + int NX=m_mmc.NX; + int NY=m_mmc.NY; + int ASX=m_mmc.ASX; + int ADX=m_mmc.ADX; + UINT8 CL=m_mmc.CL; + UINT8 LO=m_mmc.LO; + int MXD = m_mmc.MXD; + int cnt; + int delta; + + delta = get_vdp_timing_value(line_timing); + cnt = m_vdp_ops_count; + + #define post_linexmaj(MX) \ + DX+=TX; \ + if ((ASX-=NY)<0) { \ + ASX+=NX; \ + DY+=TY; \ + } \ + ASX&=1023; /* Mask to 10 bits range */\ + if (ADX++==NX || (DX&MX)) \ + break; \ + post_loop + + #define post_lineymaj(MX) \ + DY+=TY; \ + if ((ASX-=NY)<0) { \ + ASX+=NX; \ + DX+=TX; \ + } \ + ASX&=1023; /* Mask to 10 bits range */\ + if (ADX++==NX || (DX&MX)) \ + break; \ + post_loop + + if ((m_cont_reg[45]&0x01)==0) + // X-Axis is major direction + switch (m_mode) { + default: + case V9938_MODE_GRAPHIC4: pre_loop VDPpset5(MXD, DX, DY, CL, LO); post_linexmaj(256) + break; + case V9938_MODE_GRAPHIC5: pre_loop VDPpset6(MXD, DX, DY, CL, LO); post_linexmaj(512) + break; + case V9938_MODE_GRAPHIC6: pre_loop VDPpset7(MXD, DX, DY, CL, LO); post_linexmaj(512) + break; + case V9938_MODE_GRAPHIC7: pre_loop VDPpset8(MXD, DX, DY, CL, LO); post_linexmaj(256) + break; + } + else + // Y-Axis is major direction + switch (m_mode) { + default: + case V9938_MODE_GRAPHIC4: pre_loop VDPpset5(MXD, DX, DY, CL, LO); post_lineymaj(256) + break; + case V9938_MODE_GRAPHIC5: pre_loop VDPpset6(MXD, DX, DY, CL, LO); post_lineymaj(512) + break; + case V9938_MODE_GRAPHIC6: pre_loop VDPpset7(MXD, DX, DY, CL, LO); post_lineymaj(512) + break; + case V9938_MODE_GRAPHIC7: pre_loop VDPpset8(MXD, DX, DY, CL, LO); post_lineymaj(256) + break; + } + + if ((m_vdp_ops_count=cnt)>0) { + // Command execution done + m_stat_reg[2]&=0xFE; + m_vdp_engine=0; + m_cont_reg[38]=DY & 0xFF; + m_cont_reg[39]=(DY>>8) & 0x03; + } + else { + m_mmc.DX=DX; + m_mmc.DY=DY; + m_mmc.ASX=ASX; + m_mmc.ADX=ADX; + } +} + +/** lmmv_engine() *********************************************/ +/** VDP -> Vram **/ +/*************************************************************/ +void v99x8_device::lmmv_engine() +{ + int DX=m_mmc.DX; + int DY=m_mmc.DY; + int TX=m_mmc.TX; + int TY=m_mmc.TY; + int NX=m_mmc.NX; + int NY=m_mmc.NY; + int ADX=m_mmc.ADX; + int ANX=m_mmc.ANX; + UINT8 CL=m_mmc.CL; + UINT8 LO=m_mmc.LO; + int MXD = m_mmc.MXD; + int cnt; + int delta; + + delta = get_vdp_timing_value(lmmv_timing); + cnt = m_vdp_ops_count; + + switch (m_mode) { + default: + case V9938_MODE_GRAPHIC4: pre_loop VDPpset5(MXD, ADX, DY, CL, LO); post__x_y(256) + break; + case V9938_MODE_GRAPHIC5: pre_loop VDPpset6(MXD, ADX, DY, CL, LO); post__x_y(512) + break; + case V9938_MODE_GRAPHIC6: pre_loop VDPpset7(MXD, ADX, DY, CL, LO); post__x_y(512) + break; + case V9938_MODE_GRAPHIC7: pre_loop VDPpset8(MXD, ADX, DY, CL, LO); post__x_y(256) + break; + } + + if ((m_vdp_ops_count=cnt)>0) { + // Command execution done + m_stat_reg[2]&=0xFE; + m_vdp_engine=0; + if (!NY) + DY+=TY; + m_cont_reg[38]=DY & 0xFF; + m_cont_reg[39]=(DY>>8) & 0x03; + m_cont_reg[42]=NY & 0xFF; + m_cont_reg[43]=(NY>>8) & 0x03; + } + else { + m_mmc.DY=DY; + m_mmc.NY=NY; + m_mmc.ANX=ANX; + m_mmc.ADX=ADX; + } +} + +/** lmmm_engine() *********************************************/ +/** Vram -> Vram **/ +/*************************************************************/ +void v99x8_device::lmmm_engine() +{ + int SX=m_mmc.SX; + int SY=m_mmc.SY; + int DX=m_mmc.DX; + int DY=m_mmc.DY; + int TX=m_mmc.TX; + int TY=m_mmc.TY; + int NX=m_mmc.NX; + int NY=m_mmc.NY; + int ASX=m_mmc.ASX; + int ADX=m_mmc.ADX; + int ANX=m_mmc.ANX; + UINT8 LO=m_mmc.LO; + int MXS = m_mmc.MXS; + int MXD = m_mmc.MXD; + int cnt; + int delta; + + delta = get_vdp_timing_value(lmmm_timing); + cnt = m_vdp_ops_count; + + switch (m_mode) { + default: + case V9938_MODE_GRAPHIC4: pre_loop VDPpset5(MXD, ADX, DY, VDPpoint5(MXS, ASX, SY), LO); post_xxyy(256) + break; + case V9938_MODE_GRAPHIC5: pre_loop VDPpset6(MXD, ADX, DY, VDPpoint6(MXS, ASX, SY), LO); post_xxyy(512) + break; + case V9938_MODE_GRAPHIC6: pre_loop VDPpset7(MXD, ADX, DY, VDPpoint7(MXS, ASX, SY), LO); post_xxyy(512) + break; + case V9938_MODE_GRAPHIC7: pre_loop VDPpset8(MXD, ADX, DY, VDPpoint8(MXS, ASX, SY), LO); post_xxyy(256) + break; + } + + if ((m_vdp_ops_count=cnt)>0) { + // Command execution done + m_stat_reg[2]&=0xFE; + m_vdp_engine=0; + if (!NY) { + SY+=TY; + DY+=TY; + } + else + if (SY==-1) + DY+=TY; + m_cont_reg[42]=NY & 0xFF; + m_cont_reg[43]=(NY>>8) & 0x03; + m_cont_reg[34]=SY & 0xFF; + m_cont_reg[35]=(SY>>8) & 0x03; + m_cont_reg[38]=DY & 0xFF; + m_cont_reg[39]=(DY>>8) & 0x03; + } + else { + m_mmc.SY=SY; + m_mmc.DY=DY; + m_mmc.NY=NY; + m_mmc.ANX=ANX; + m_mmc.ASX=ASX; + m_mmc.ADX=ADX; + } +} + +/** lmcm_engine() *********************************************/ +/** Vram -> CPU **/ +/*************************************************************/ +void v99x8_device::lmcm_engine() +{ + if ((m_stat_reg[2]&0x80)!=0x80) { + m_stat_reg[7]=m_cont_reg[44]=VDP_POINT(((m_mode >= 5) && (m_mode <= 8)) ? (m_mode-5) : 0, m_mmc.MXS, m_mmc.ASX, m_mmc.SY); + m_vdp_ops_count-=get_vdp_timing_value(lmmv_timing); + m_stat_reg[2]|=0x80; + + if (!--m_mmc.ANX || ((m_mmc.ASX+=m_mmc.TX)&m_mmc.MX)) { + if (!(--m_mmc.NY & 1023) || (m_mmc.SY+=m_mmc.TY)==-1) { + m_stat_reg[2]&=0xFE; + m_vdp_engine=0; + if (!m_mmc.NY) + m_mmc.DY+=m_mmc.TY; + m_cont_reg[42]=m_mmc.NY & 0xFF; + m_cont_reg[43]=(m_mmc.NY>>8) & 0x03; + m_cont_reg[34]=m_mmc.SY & 0xFF; + m_cont_reg[35]=(m_mmc.SY>>8) & 0x03; + } + else { + m_mmc.ASX=m_mmc.SX; + m_mmc.ANX=m_mmc.NX; + } + } + } +} + +/** lmmc_engine() *********************************************/ +/** CPU -> Vram **/ +/*************************************************************/ +void v99x8_device::lmmc_engine() +{ + if ((m_stat_reg[2]&0x80)!=0x80) { + UINT8 SM=((m_mode >= 5) && (m_mode <= 8)) ? (m_mode-5) : 0; + + m_stat_reg[7]=m_cont_reg[44]&=Mask[SM]; + VDP_PSET(SM, m_mmc.MXD, m_mmc.ADX, m_mmc.DY, m_cont_reg[44], m_mmc.LO); + m_vdp_ops_count-=get_vdp_timing_value(lmmv_timing); + m_stat_reg[2]|=0x80; + + if (!--m_mmc.ANX || ((m_mmc.ADX+=m_mmc.TX)&m_mmc.MX)) { + if (!(--m_mmc.NY&1023) || (m_mmc.DY+=m_mmc.TY)==-1) { + m_stat_reg[2]&=0xFE; + m_vdp_engine=0; + if (!m_mmc.NY) + m_mmc.DY+=m_mmc.TY; + m_cont_reg[42]=m_mmc.NY & 0xFF; + m_cont_reg[43]=(m_mmc.NY>>8) & 0x03; + m_cont_reg[38]=m_mmc.DY & 0xFF; + m_cont_reg[39]=(m_mmc.DY>>8) & 0x03; + } + else { + m_mmc.ADX=m_mmc.DX; + m_mmc.ANX=m_mmc.NX; + } + } + } +} + +/** hmmv_engine() *********************************************/ +/** VDP --> Vram **/ +/*************************************************************/ +void v99x8_device::hmmv_engine() +{ + int DX=m_mmc.DX; + int DY=m_mmc.DY; + int TX=m_mmc.TX; + int TY=m_mmc.TY; + int NX=m_mmc.NX; + int NY=m_mmc.NY; + int ADX=m_mmc.ADX; + int ANX=m_mmc.ANX; + UINT8 CL=m_mmc.CL; + int MXD = m_mmc.MXD; + int cnt; + int delta; + + delta = get_vdp_timing_value(hmmv_timing); + cnt = m_vdp_ops_count; + + switch (m_mode) { + default: + case V9938_MODE_GRAPHIC4: pre_loop m_vram_space->write_byte(VDP_VRMP5(MXD, ADX, DY), CL); post__x_y(256) + break; + case V9938_MODE_GRAPHIC5: pre_loop m_vram_space->write_byte(VDP_VRMP6(MXD, ADX, DY), CL); post__x_y(512) + break; + case V9938_MODE_GRAPHIC6: pre_loop m_vram_space->write_byte(VDP_VRMP7(MXD, ADX, DY), CL); post__x_y(512) + break; + case V9938_MODE_GRAPHIC7: pre_loop m_vram_space->write_byte(VDP_VRMP8(MXD, ADX, DY), CL); post__x_y(256) + break; + } + + if ((m_vdp_ops_count=cnt)>0) { + // Command execution done + m_stat_reg[2]&=0xFE; + m_vdp_engine=0; + if (!NY) + DY+=TY; + m_cont_reg[42]=NY & 0xFF; + m_cont_reg[43]=(NY>>8) & 0x03; + m_cont_reg[38]=DY & 0xFF; + m_cont_reg[39]=(DY>>8) & 0x03; + } + else { + m_mmc.DY=DY; + m_mmc.NY=NY; + m_mmc.ANX=ANX; + m_mmc.ADX=ADX; + } +} + +/** hmmm_engine() *********************************************/ +/** Vram -> Vram **/ +/*************************************************************/ +void v99x8_device::hmmm_engine() +{ + int SX=m_mmc.SX; + int SY=m_mmc.SY; + int DX=m_mmc.DX; + int DY=m_mmc.DY; + int TX=m_mmc.TX; + int TY=m_mmc.TY; + int NX=m_mmc.NX; + int NY=m_mmc.NY; + int ASX=m_mmc.ASX; + int ADX=m_mmc.ADX; + int ANX=m_mmc.ANX; + int MXS = m_mmc.MXS; + int MXD = m_mmc.MXD; + int cnt; + int delta; + + delta = get_vdp_timing_value(hmmm_timing); + cnt = m_vdp_ops_count; + + switch (m_mode) { + default: + case V9938_MODE_GRAPHIC4: pre_loop m_vram_space->write_byte(VDP_VRMP5(MXD, ADX, DY), m_vram_space->read_byte(VDP_VRMP5(MXS, ASX, SY))); post_xxyy(256) + break; + case V9938_MODE_GRAPHIC5: pre_loop m_vram_space->write_byte(VDP_VRMP6(MXD, ADX, DY), m_vram_space->read_byte(VDP_VRMP6(MXS, ASX, SY))); post_xxyy(512) + break; + case V9938_MODE_GRAPHIC6: pre_loop m_vram_space->write_byte(VDP_VRMP7(MXD, ADX, DY), m_vram_space->read_byte(VDP_VRMP7(MXS, ASX, SY))); post_xxyy(512) + break; + case V9938_MODE_GRAPHIC7: pre_loop m_vram_space->write_byte(VDP_VRMP8(MXD, ADX, DY), m_vram_space->read_byte(VDP_VRMP8(MXS, ASX, SY))); post_xxyy(256) + break; + } + + if ((m_vdp_ops_count=cnt)>0) { + // Command execution done + m_stat_reg[2]&=0xFE; + m_vdp_engine=0; + if (!NY) { + SY+=TY; + DY+=TY; + } + else + if (SY==-1) + DY+=TY; + m_cont_reg[42]=NY & 0xFF; + m_cont_reg[43]=(NY>>8) & 0x03; + m_cont_reg[34]=SY & 0xFF; + m_cont_reg[35]=(SY>>8) & 0x03; + m_cont_reg[38]=DY & 0xFF; + m_cont_reg[39]=(DY>>8) & 0x03; + } + else { + m_mmc.SY=SY; + m_mmc.DY=DY; + m_mmc.NY=NY; + m_mmc.ANX=ANX; + m_mmc.ASX=ASX; + m_mmc.ADX=ADX; + } +} + +/** ymmm_engine() *********************************************/ +/** Vram -> Vram **/ +/*************************************************************/ + +void v99x8_device::ymmm_engine() +{ + int SY=m_mmc.SY; + int DX=m_mmc.DX; + int DY=m_mmc.DY; + int TX=m_mmc.TX; + int TY=m_mmc.TY; + int NY=m_mmc.NY; + int ADX=m_mmc.ADX; + int MXD = m_mmc.MXD; + int cnt; + int delta; + + delta = get_vdp_timing_value(ymmm_timing); + cnt = m_vdp_ops_count; + + switch (m_mode) { + default: + case V9938_MODE_GRAPHIC4: pre_loop m_vram_space->write_byte(VDP_VRMP5(MXD, ADX, DY), m_vram_space->read_byte(VDP_VRMP5(MXD, ADX, SY))); post__xyy(256) + break; + case V9938_MODE_GRAPHIC5: pre_loop m_vram_space->write_byte(VDP_VRMP6(MXD, ADX, DY), m_vram_space->read_byte(VDP_VRMP6(MXD, ADX, SY))); post__xyy(512) + break; + case V9938_MODE_GRAPHIC6: pre_loop m_vram_space->write_byte(VDP_VRMP7(MXD, ADX, DY), m_vram_space->read_byte(VDP_VRMP7(MXD, ADX, SY))); post__xyy(512) + break; + case V9938_MODE_GRAPHIC7: pre_loop m_vram_space->write_byte(VDP_VRMP8(MXD, ADX, DY), m_vram_space->read_byte(VDP_VRMP8(MXD, ADX, SY))); post__xyy(256) + break; + } + + if ((m_vdp_ops_count=cnt)>0) { + // Command execution done + m_stat_reg[2]&=0xFE; + m_vdp_engine=0; + if (!NY) { + SY+=TY; + DY+=TY; + } + else + if (SY==-1) + DY+=TY; + m_cont_reg[42]=NY & 0xFF; + m_cont_reg[43]=(NY>>8) & 0x03; + m_cont_reg[34]=SY & 0xFF; + m_cont_reg[35]=(SY>>8) & 0x03; + m_cont_reg[38]=DY & 0xFF; + m_cont_reg[39]=(DY>>8) & 0x03; + } + else { + m_mmc.SY=SY; + m_mmc.DY=DY; + m_mmc.NY=NY; + m_mmc.ADX=ADX; + } +} + +/** hmmc_engine() *********************************************/ +/** CPU -> Vram **/ +/*************************************************************/ +void v99x8_device::hmmc_engine() +{ + if ((m_stat_reg[2]&0x80)!=0x80) { + m_vram_space->write_byte(VDP_VRMP(((m_mode >= 5) && (m_mode <= 8)) ? (m_mode-5) : 0, m_mmc.MXD, m_mmc.ADX, m_mmc.DY), m_cont_reg[44]); + m_vdp_ops_count -= get_vdp_timing_value(hmmv_timing); + m_stat_reg[2]|=0x80; + + if (!--m_mmc.ANX || ((m_mmc.ADX+=m_mmc.TX)&m_mmc.MX)) { + if (!(--m_mmc.NY&1023) || (m_mmc.DY+=m_mmc.TY)==-1) { + m_stat_reg[2]&=0xFE; + m_vdp_engine=0; + if (!m_mmc.NY) + m_mmc.DY+=m_mmc.TY; + m_cont_reg[42]=m_mmc.NY & 0xFF; + m_cont_reg[43]=(m_mmc.NY>>8) & 0x03; + m_cont_reg[38]=m_mmc.DY & 0xFF; + m_cont_reg[39]=(m_mmc.DY>>8) & 0x03; + } + else { + m_mmc.ADX=m_mmc.DX; + m_mmc.ANX=m_mmc.NX; + } + } + } +} + +/** VDPWrite() ***********************************************/ +/** Use this function to transfer pixel(s) from CPU to m_ **/ +/*************************************************************/ +void v99x8_device::cpu_to_vdp(UINT8 V) +{ + m_stat_reg[2]&=0x7F; + m_stat_reg[7]=m_cont_reg[44]=V; + if(m_vdp_engine&&(m_vdp_ops_count>0)) (this->*m_vdp_engine)(); +} + +/** VDPRead() ************************************************/ +/** Use this function to transfer pixel(s) from VDP to CPU. **/ +/*************************************************************/ +UINT8 v99x8_device::vdp_to_cpu() +{ + m_stat_reg[2]&=0x7F; + if(m_vdp_engine&&(m_vdp_ops_count>0)) (this->*m_vdp_engine)(); + return(m_cont_reg[44]); +} + +/** report_vdp_command() ***************************************/ +/** Report VDP Command to be executed **/ +/*************************************************************/ +void v99x8_device::report_vdp_command(UINT8 Op) +{ + static const char *const Ops[16] = + { + "SET ","AND ","OR ","XOR ","NOT ","NOP ","NOP ","NOP ", + "TSET","TAND","TOR ","TXOR","TNOT","NOP ","NOP ","NOP " + }; + static const char *const Commands[16] = + { + " ABRT"," ????"," ????"," ????","POINT"," PSET"," SRCH"," LINE", + " LMMV"," LMMM"," LMCM"," LMMC"," HMMV"," HMMM"," YMMM"," HMMC" + }; + + UINT8 CL, CM, LO; + int SX,SY, DX,DY, NX,NY; + + // Fetch arguments + CL = m_cont_reg[44]; + SX = (m_cont_reg[32]+((int)m_cont_reg[33]<<8)) & 511; + SY = (m_cont_reg[34]+((int)m_cont_reg[35]<<8)) & 1023; + DX = (m_cont_reg[36]+((int)m_cont_reg[37]<<8)) & 511; + DY = (m_cont_reg[38]+((int)m_cont_reg[39]<<8)) & 1023; + NX = (m_cont_reg[40]+((int)m_cont_reg[41]<<8)) & 1023; + NY = (m_cont_reg[42]+((int)m_cont_reg[43]<<8)) & 1023; + CM = Op>>4; + LO = Op&0x0F; + + LOG(("V9938: Opcode %02Xh %s-%s (%d,%d)->(%d,%d),%d [%d,%d]%s\n", + Op, Commands[CM], Ops[LO], + SX,SY, DX,DY, CL, m_cont_reg[45]&0x04? -NX:NX, + m_cont_reg[45]&0x08? -NY:NY, + m_cont_reg[45]&0x70? " on ExtVRAM":"" + )); +} + +/** VDPDraw() ************************************************/ +/** Perform a given V9938 operation Op. **/ +/*************************************************************/ +UINT8 v99x8_device::command_unit_w(UINT8 Op) +{ + int SM; + + // V9938 ops only work in SCREENs 5-8 + if (m_mode<5) + return(0); + + SM = m_mode-5; // Screen mode index 0..3 + + m_mmc.CM = Op>>4; + if ((m_mmc.CM & 0x0C) != 0x0C && m_mmc.CM != 0) + // Dot operation: use only relevant bits of color + m_stat_reg[7]=(m_cont_reg[44]&=Mask[SM]); + + // if(Verbose&0x02) + report_vdp_command(Op); + + switch(Op>>4) { + case CM_ABRT: + m_stat_reg[2]&=0xFE; + m_vdp_engine=0; + return 1; + case CM_POINT: + m_stat_reg[2]&=0xFE; + m_vdp_engine=0; + m_stat_reg[7]=m_cont_reg[44]= + VDP_POINT(SM, (m_cont_reg[45] & 0x10) != 0, + m_cont_reg[32]+((int)m_cont_reg[33]<<8), + m_cont_reg[34]+((int)m_cont_reg[35]<<8)); + return 1; + case CM_PSET: + m_stat_reg[2]&=0xFE; + m_vdp_engine=0; + VDP_PSET(SM, (m_cont_reg[45] & 0x20) != 0, + m_cont_reg[36]+((int)m_cont_reg[37]<<8), + m_cont_reg[38]+((int)m_cont_reg[39]<<8), + m_cont_reg[44], + Op&0x0F); + return 1; + case CM_SRCH: + m_vdp_engine=&v99x8_device::srch_engine; + break; + case CM_LINE: + m_vdp_engine=&v99x8_device::line_engine; + break; + case CM_LMMV: + m_vdp_engine=&v99x8_device::lmmv_engine; + break; + case CM_LMMM: + m_vdp_engine=&v99x8_device::lmmm_engine; + break; + case CM_LMCM: + m_vdp_engine=&v99x8_device::lmcm_engine; + break; + case CM_LMMC: + m_vdp_engine=&v99x8_device::lmmc_engine; + break; + case CM_HMMV: + m_vdp_engine=&v99x8_device::hmmv_engine; + break; + case CM_HMMM: + m_vdp_engine=&v99x8_device::hmmm_engine; + break; + case CM_YMMM: + m_vdp_engine=&v99x8_device::ymmm_engine; + break; + case CM_HMMC: + m_vdp_engine=&v99x8_device::hmmc_engine; + break; + default: + LOG(("V9938: Unrecognized opcode %02Xh\n",Op)); + return(0); + } + + // Fetch unconditional arguments + m_mmc.SX = (m_cont_reg[32]+((int)m_cont_reg[33]<<8)) & 511; + m_mmc.SY = (m_cont_reg[34]+((int)m_cont_reg[35]<<8)) & 1023; + m_mmc.DX = (m_cont_reg[36]+((int)m_cont_reg[37]<<8)) & 511; + m_mmc.DY = (m_cont_reg[38]+((int)m_cont_reg[39]<<8)) & 1023; + m_mmc.NY = (m_cont_reg[42]+((int)m_cont_reg[43]<<8)) & 1023; + m_mmc.TY = m_cont_reg[45]&0x08? -1:1; + m_mmc.MX = PPL[SM]; + m_mmc.CL = m_cont_reg[44]; + m_mmc.LO = Op&0x0F; + m_mmc.MXS = (m_cont_reg[45] & 0x10) != 0; + m_mmc.MXD = (m_cont_reg[45] & 0x20) != 0; + + // Argument depends on UINT8 or dot operation + if ((m_mmc.CM & 0x0C) == 0x0C) { + m_mmc.TX = m_cont_reg[45]&0x04? -PPB[SM]:PPB[SM]; + m_mmc.NX = ((m_cont_reg[40]+((int)m_cont_reg[41]<<8)) & 1023)/PPB[SM]; + } + else { + m_mmc.TX = m_cont_reg[45]&0x04? -1:1; + m_mmc.NX = (m_cont_reg[40]+((int)m_cont_reg[41]<<8)) & 1023; + } + + // X loop variables are treated specially for LINE command + if (m_mmc.CM == CM_LINE) { + m_mmc.ASX=((m_mmc.NX-1)>>1); + m_mmc.ADX=0; + } + else { + m_mmc.ASX = m_mmc.SX; + m_mmc.ADX = m_mmc.DX; + } + + // NX loop variable is treated specially for SRCH command + if (m_mmc.CM == CM_SRCH) + m_mmc.ANX=(m_cont_reg[45]&0x02)!=0; // Do we look for "==" or "!="? + else + m_mmc.ANX = m_mmc.NX; + + // Command execution started + m_stat_reg[2]|=0x01; + + // Start execution if we still have time slices + if(m_vdp_engine&&(m_vdp_ops_count>0)) (this->*m_vdp_engine)(); + + // Operation successfully initiated + return(1); +} + +/** LoopVDP() ************************************************ +Run X steps of active VDP command +*************************************************************/ +void v99x8_device::update_command() +{ + if(m_vdp_ops_count<=0) + { + m_vdp_ops_count+=13662; + if(m_vdp_engine&&(m_vdp_ops_count>0)) (this->*m_vdp_engine)(); + } + else + { + m_vdp_ops_count=13662; + if(m_vdp_engine) (this->*m_vdp_engine)(); + } +} + +static MACHINE_CONFIG_FRAGMENT( v9938 ) + MCFG_PALETTE_ADD("palette", 512) + MCFG_PALETTE_INIT_OWNER(v9938_device, v9938) +MACHINE_CONFIG_END + +//------------------------------------------------- +// machine_config_additions - return a pointer to +// the device's machine fragment +//------------------------------------------------- + +machine_config_constructor v9938_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( v9938 ); +} + +static MACHINE_CONFIG_FRAGMENT( v9958 ) + MCFG_PALETTE_ADD("palette", 19780) + MCFG_PALETTE_INIT_OWNER(v9958_device, v9958) +MACHINE_CONFIG_END + +//------------------------------------------------- +// machine_config_additions - return a pointer to +// the device's machine fragment +//------------------------------------------------- + +machine_config_constructor v9958_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( v9958 ); +} diff --git a/src/devices/video/v9938.h b/src/devices/video/v9938.h new file mode 100644 index 00000000000..4430c2ba4d5 --- /dev/null +++ b/src/devices/video/v9938.h @@ -0,0 +1,250 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles, Nathan Woods +/*************************************************************************** + + v9938 / v9958 emulation + +***************************************************************************/ + +#pragma once + +#ifndef __V9938_H__ +#define __V9938_H__ + + + +//************************************************************************** +// DEVICE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_V9938_ADD(_tag, _screen, _vramsize, _clock) \ + MCFG_DEVICE_ADD(_tag, V9938, _clock) \ + MCFG_VIDEO_SET_SCREEN(_screen) \ + v9938_device::static_set_vram_size(*device, _vramsize); +#define MCFG_V9958_ADD(_tag, _screen, _vramsize, _clock) \ + MCFG_DEVICE_ADD(_tag, V9958, _clock) \ + MCFG_VIDEO_SET_SCREEN(_screen) \ + v9938_device::static_set_vram_size(*device, _vramsize); + +#define MCFG_V99X8_INTERRUPT_CALLBACK(_irq) \ + downcast(device)->set_interrupt_callback(DEVCB_##_irq); + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +// device type definition +extern const device_type V9938; +extern const device_type V9958; + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> v99x8_device + +class v99x8_device : public device_t, + public device_memory_interface, + public device_video_interface +{ +protected: + // construction/destruction + v99x8_device(const machine_config &mconfig, device_type type, const char *name, const char *shortname, const char *tag, device_t *owner, UINT32 clock); + +public: + template void set_interrupt_callback(_irq irq) { + m_int_callback.set_callback(irq); + } + int interrupt (); + int get_transpen(); + bitmap_ind16 &get_bitmap() { return m_bitmap; } + void update_mouse_state(int mx_delta, int my_delta, int button_state); + + UINT32 screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); + + DECLARE_READ8_MEMBER( read ); + DECLARE_WRITE8_MEMBER( write ); + + UINT8 vram_r(); + UINT8 status_r(); + void palette_w(UINT8 data); + void vram_w(UINT8 data); + void command_w(UINT8 data); + void register_w(UINT8 data); + + static void static_set_vram_size(device_t &device, UINT32 vram_size); + + /* RESET pin */ + void reset_line(int state) { if (state==ASSERT_LINE) device_reset(); } + +protected: + const address_space_config m_space_config; + address_space* m_vram_space; + + int m_model; + + // device overrides + virtual void device_start(); + virtual void device_reset(); + + // device_memory_interface overrides + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_DATA) const { return (spacenum == AS_DATA) ? &m_space_config : NULL; } + +private: + // internal helpers + void reset_palette(); + void vram_write(int offset, int data); + int vram_read(int offset); + void check_int(); + void register_write(int reg, int data); + + void default_border(const pen_t *pens, UINT16 *ln); + void graphic7_border(const pen_t *pens, UINT16 *ln); + void graphic5_border(const pen_t *pens, UINT16 *ln); + void mode_text1(const pen_t *pens, UINT16 *ln, int line); + void mode_text2(const pen_t *pens, UINT16 *ln, int line); + void mode_multi(const pen_t *pens, UINT16 *ln, int line); + void mode_graphic1(const pen_t *pens, UINT16 *ln, int line); + void mode_graphic23(const pen_t *pens, UINT16 *ln, int line); + void mode_graphic4(const pen_t *pens, UINT16 *ln, int line); + void mode_graphic5(const pen_t *pens, UINT16 *ln, int line); + void mode_graphic6(const pen_t *pens, UINT16 *ln, int line); + void mode_graphic7(const pen_t *pens, UINT16 *ln, int line); +// template void mode_yae(const pen_t *pens, _PixelType *ln, int line); +// template void mode_yjk(const pen_t *pens, _PixelType *ln, int line); + void mode_unknown(const pen_t *pens, UINT16 *ln, int line); + void default_draw_sprite(const pen_t *pens, UINT16 *ln, UINT8 *col); + void graphic5_draw_sprite(const pen_t *pens, UINT16 *ln, UINT8 *col); + void graphic7_draw_sprite(const pen_t *pens, UINT16 *ln, UINT8 *col); + + void sprite_mode1(int line, UINT8 *col); + void sprite_mode2(int line, UINT8 *col); + void set_mode(); + void refresh_16(int line); + void refresh_line(int line); + + void interrupt_start_vblank(); + + int VDPVRMP(UINT8 M, int MX, int X, int Y); + + UINT8 VDPpoint5(int MXS, int SX, int SY); + UINT8 VDPpoint6(int MXS, int SX, int SY); + UINT8 VDPpoint7(int MXS, int SX, int SY); + UINT8 VDPpoint8(int MXS, int SX, int SY); + + UINT8 VDPpoint(UINT8 SM, int MXS, int SX, int SY); + + void VDPpsetlowlevel(int addr, UINT8 CL, UINT8 M, UINT8 OP); + + void VDPpset5(int MXD, int DX, int DY, UINT8 CL, UINT8 OP); + void VDPpset6(int MXD, int DX, int DY, UINT8 CL, UINT8 OP); + void VDPpset7(int MXD, int DX, int DY, UINT8 CL, UINT8 OP); + void VDPpset8(int MXD, int DX, int DY, UINT8 CL, UINT8 OP); + + void VDPpset(UINT8 SM, int MXD, int DX, int DY, UINT8 CL, UINT8 OP); + + int get_vdp_timing_value(const int *); + + void srch_engine(); + void line_engine(); + void lmmv_engine(); + void lmmm_engine(); + void lmcm_engine(); + void lmmc_engine(); + void hmmv_engine(); + void hmmm_engine(); + void ymmm_engine(); + void hmmc_engine(); + + inline bool v9938_second_field(); + + void cpu_to_vdp(UINT8 V); + UINT8 vdp_to_cpu(); + void report_vdp_command(UINT8 Op); + UINT8 command_unit_w(UINT8 Op); + void update_command(); + + // general + int m_offset_x, m_offset_y, m_visible_y, m_mode; + // palette + int m_pal_write_first, m_cmd_write_first; + UINT8 m_pal_write, m_cmd_write; + UINT8 m_pal_reg[32], m_stat_reg[10], m_cont_reg[48], m_read_ahead; + UINT8 m_v9958_sp_mode; + + // memory + UINT16 m_address_latch; + int m_vram_size; + + // interrupt + UINT8 m_int_state; + devcb_write_line m_int_callback; + int m_scanline; + // blinking + int m_blink, m_blink_count; + // mouse + UINT8 m_mx_delta, m_my_delta; + // mouse & lightpen + UINT8 m_button_state; + // palette + UINT16 m_pal_ind16[16]; + UINT16 m_pal_ind256[256]; + // render bitmap + bitmap_ind16 m_bitmap; + // Command unit + struct { + int SX,SY; + int DX,DY; + int TX,TY; + int NX,NY; + int MX; + int ASX,ADX,ANX; + UINT8 CL; + UINT8 LO; + UINT8 CM; + UINT8 MXS, MXD; + } m_mmc; + int m_vdp_ops_count; + void (v99x8_device::*m_vdp_engine)(); + + struct v99x8_mode + { + UINT8 m; + void (v99x8_device::*visible_16)(const pen_t *, UINT16*, int); + void (v99x8_device::*border_16)(const pen_t *, UINT16*); + void (v99x8_device::*sprites)(int, UINT8*); + void (v99x8_device::*draw_sprite_16)(const pen_t *, UINT16*, UINT8*); + } ; + static const v99x8_mode s_modes[]; + required_device m_palette; +protected: + static UINT16 s_pal_indYJK[0x20000]; +}; + + +class v9938_device : public v99x8_device +{ +public: + v9938_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + DECLARE_PALETTE_INIT(v9938); +protected: + virtual machine_config_constructor device_mconfig_additions() const; +}; + +class v9958_device : public v99x8_device +{ +public: + v9958_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + DECLARE_PALETTE_INIT(v9958); + +protected: + virtual machine_config_constructor device_mconfig_additions() const; +}; + + +#endif diff --git a/src/devices/video/vector.c b/src/devices/video/vector.c new file mode 100644 index 00000000000..5e88ad286d9 --- /dev/null +++ b/src/devices/video/vector.c @@ -0,0 +1,307 @@ +// license:BSD-3-Clause +// copyright-holders:Brad Oliver,Aaron Giles,Bernd Wiebelt,Allard van der Bas +/****************************************************************************** + * + * vector.c + * + * anti-alias code by Andrew Caldwell + * (still more to add) + * + * 040227 Fixed miny clip scaling which was breaking in mhavoc. AREK + * 010903 added support for direct RGB modes MLR + * 980611 use translucent vectors. Thanks to Peter Hirschberg + * and Neil Bradley for the inspiration. BW + * 980307 added cleverer dirty handling. BW, ASG + * fixed antialias table .ac + * 980221 rewrote anti-alias line draw routine + * added inline assembly multiply fuction for 8086 based machines + * beam diameter added to draw routine + * beam diameter is accurate in anti-alias line draw (Tcosin) + * flicker added .ac + * 980203 moved LBO's routines for drawing into a buffer of vertices + * from avgdvg.c to this location. Scaling is now initialized + * by calling vector_init(...). BW + * 980202 moved out of msdos.c ASG + * 980124 added anti-alias line draw routine + * modified avgdvg.c and sega.c to support new line draw routine + * added two new tables Tinten and Tmerge (for 256 color support) + * added find_color routine to build above tables .ac + * + **************************************************************************** */ + +#include "emu.h" +#include "emuopts.h" +#include "rendutil.h" +#include "vector.h" + + + +#define VECTOR_WIDTH_DENOM 512 + + +#define MAX_POINTS 10000 + +#define VECTOR_TEAM \ + "-* Vector Heads *-\n" \ + "Brad Oliver\n" \ + "Aaron Giles\n" \ + "Bernd Wiebelt\n" \ + "Allard van der Bas\n" \ + "Al Kossow (VECSIM)\n" \ + "Hedley Rainnie (VECSIM)\n" \ + "Eric Smith (VECSIM)\n" \ + "Neil Bradley (technical advice)\n" \ + "Andrew Caldwell (anti-aliasing)\n" \ + "- *** -\n" + +#if 0 + +#define TEXTURE_LENGTH_BUCKETS 32 +#define TEXTURE_INTENSITY_BUCKETS 4 +#define TEXTURE_WIDTH 16 + +#define MAX_INTENSITY 2 +#define VECTOR_BLEED (0.25f) +#define VECTOR_INT_SCALE (255.0f * 1.5f) + + +struct vector_texture +{ + render_texture * texture; + bitmap_argb32 * bitmap; +}; + +static vector_texture *vectortex[TEXTURE_INTENSITY_BUCKETS][TEXTURE_LENGTH_BUCKETS]; + + +static render_texture *get_vector_texture(float dx, float dy, float intensity) +{ + float length = sqrt(dx * dx + dy * dy); + int lbucket = length * (float)TEXTURE_LENGTH_BUCKETS; + int ibucket = (intensity / (float)MAX_INTENSITY) * (float)TEXTURE_INTENSITY_BUCKETS; + vector_texture *tex; + int height, x, y; + float totalint; + + if (lbucket > TEXTURE_LENGTH_BUCKETS) + lbucket = TEXTURE_LENGTH_BUCKETS; + if (ibucket > TEXTURE_INTENSITY_BUCKETS) + ibucket = TEXTURE_INTENSITY_BUCKETS; + + tex = &vectortex[ibucket][lbucket]; + if (tex->texture != NULL) + return tex->texture; + + height = lbucket * VECTOR_WIDTH_DENOM / TEXTURE_LENGTH_BUCKETS; + tex->bitmap = global_alloc(bitmap_argb32(TEXTURE_WIDTH, height)); + tex->bitmap.fill(rgb_t(0xff,0xff,0xff,0xff)); + + totalint = 1.0f; + for (x = TEXTURE_WIDTH / 2 - 1; x >= 0; x--) + { + int intensity = (int)(totalint * (1.0f - VECTOR_BLEED) * VECTOR_INT_SCALE); + intensity = MIN(255, intensity); + totalint -= (float)intensity * (1.0f / VECTOR_INT_SCALE); + + for (y = 0; y < height; y++) + { + UINT32 *pix; + + pix = (UINT32 *)bitmap.base + y * bitmap.rowpixels + x; + *pix = rgb_t((*pix.a() * intensity) >> 8,0xff,0xff,0xff); + + pix = (UINT32 *)bitmap.base + y * bitmap.rowpixels + (TEXTURE_WIDTH - 1 - x); + *pix = rgb_t((*pix.a() * intensity) >> 8,0xff,0xff,0xff); + } + } + + tex->texture = render_texture_create(); + return tex->texture; +} + +#endif + +#define VCLEAN 0 +#define VDIRTY 1 +#define VCLIP 2 + +// device type definition +const device_type VECTOR = &device_creator; + +vector_device::vector_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_video_interface(mconfig, *this) +{ +} + +vector_device::vector_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, VECTOR, "VECTOR", tag, owner, clock, "vector_device", __FILE__), + device_video_interface(mconfig, *this) +{ +} + +float vector_device::m_flicker_correction = 0.0f; +float vector_device::m_beam_width = 0.0f; +int vector_device::m_flicker; +int vector_device::m_vector_index; + +void vector_device::device_start() +{ + m_beam_width = machine().options().beam(); + + /* Grab the settings for this session */ + set_flicker(machine().options().flicker()); + + m_vector_index = 0; + + /* allocate memory for tables */ + m_vector_list = auto_alloc_array_clear(machine(), point, MAX_POINTS); +} + +void vector_device::set_flicker(float _flicker) +{ + m_flicker_correction = _flicker; + m_flicker = (int)(m_flicker_correction * 2.55f); +} + +float vector_device::get_flicker() +{ + return m_flicker_correction; +} + +void vector_device::set_beam(float _beam) +{ + m_beam_width = _beam; +} + +float vector_device::get_beam() +{ + return m_beam_width; +} + + +/* + * Adds a line end point to the vertices list. The vector processor emulation + * needs to call this. + */ +void vector_device::add_point (int x, int y, rgb_t color, int intensity) +{ + point *newpoint; + + if (intensity > 0xff) + intensity = 0xff; + + if (m_flicker && (intensity > 0)) + { + intensity += (intensity * (0x80-(machine().rand()&0xff)) * m_flicker)>>16; + if (intensity < 0) + intensity = 0; + if (intensity > 0xff) + intensity = 0xff; + } + newpoint = &m_vector_list[m_vector_index]; + newpoint->x = x; + newpoint->y = y; + newpoint->col = color; + newpoint->intensity = intensity; + newpoint->status = VDIRTY; /* mark identical lines as clean later */ + + m_vector_index++; + if (m_vector_index >= MAX_POINTS) + { + m_vector_index--; + logerror("*** Warning! Vector list overflow!\n"); + } +} + +/* + * Add new clipping info to the list + */ +void vector_device::add_clip (int x1, int yy1, int x2, int y2) +{ + point *newpoint; + + newpoint = &m_vector_list[m_vector_index]; + newpoint->x = x1; + newpoint->y = yy1; + newpoint->arg1 = x2; + newpoint->arg2 = y2; + newpoint->status = VCLIP; + + m_vector_index++; + if (m_vector_index >= MAX_POINTS) + { + m_vector_index--; + logerror("*** Warning! Vector list overflow!\n"); + } +} + + +/* + * The vector CPU creates a new display list. We save the old display list, + * but only once per refresh. + */ +void vector_device::clear_list (void) +{ + m_vector_index = 0; +} + + +UINT32 vector_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + UINT32 flags = PRIMFLAG_ANTIALIAS(screen.machine().options().antialias() ? 1 : 0) | PRIMFLAG_BLENDMODE(BLENDMODE_ADD) | PRIMFLAG_VECTOR(1); + const rectangle &visarea = screen.visible_area(); + float xscale = 1.0f / (65536 * visarea.width()); + float yscale = 1.0f / (65536 * visarea.height()); + float xoffs = (float)visarea.min_x; + float yoffs = (float)visarea.min_y; + point *curpoint; + render_bounds clip; + int lastx = 0, lasty = 0; + int i; + + curpoint = m_vector_list; + + screen.container().empty(); + screen.container().add_rect(0.0f, 0.0f, 1.0f, 1.0f, rgb_t(0xff,0x00,0x00,0x00), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_VECTORBUF(1)); + + clip.x0 = clip.y0 = 0.0f; + clip.x1 = clip.y1 = 1.0f; + + for (i = 0; i < m_vector_index; i++) + { + render_bounds coords; + + if (curpoint->status == VCLIP) + { + coords.x0 = ((float)curpoint->x - xoffs) * xscale; + coords.y0 = ((float)curpoint->y - yoffs) * yscale; + coords.x1 = ((float)curpoint->arg1 - xoffs) * xscale; + coords.y1 = ((float)curpoint->arg2 - yoffs) * yscale; + + clip.x0 = (coords.x0 > 0.0f) ? coords.x0 : 0.0f; + clip.y0 = (coords.y0 > 0.0f) ? coords.y0 : 0.0f; + clip.x1 = (coords.x1 < 1.0f) ? coords.x1 : 1.0f; + clip.y1 = (coords.y1 < 1.0f) ? coords.y1 : 1.0f; + } + else + { + coords.x0 = ((float)lastx - xoffs) * xscale; + coords.y0 = ((float)lasty - yoffs) * yscale; + coords.x1 = ((float)curpoint->x - xoffs) * xscale; + coords.y1 = ((float)curpoint->y - yoffs) * yscale; + + if (curpoint->intensity != 0) + if (!render_clip_line(&coords, &clip)) + screen.container().add_line(coords.x0, coords.y0, coords.x1, coords.y1, + m_beam_width * (1.0f / (float)VECTOR_WIDTH_DENOM), + (curpoint->intensity << 24) | (curpoint->col & 0xffffff), + flags); + + lastx = curpoint->x; + lasty = curpoint->y; + } + curpoint++; + } + return 0; +} diff --git a/src/devices/video/vector.h b/src/devices/video/vector.h new file mode 100644 index 00000000000..2e922d4a922 --- /dev/null +++ b/src/devices/video/vector.h @@ -0,0 +1,73 @@ +// license:BSD-3-Clause +// copyright-holders:Brad Oliver,Aaron Giles,Bernd Wiebelt,Allard van der Bas +#ifndef __VECTOR__ +#define __VECTOR__ + +#define VECTOR_COLOR111(c) \ + rgb_t(pal1bit((c) >> 2), pal1bit((c) >> 1), pal1bit((c) >> 0)) + +#define VECTOR_COLOR222(c) \ + rgb_t(pal2bit((c) >> 4), pal2bit((c) >> 2), pal2bit((c) >> 0)) + +#define VECTOR_COLOR444(c) \ + rgb_t(pal4bit((c) >> 8), pal4bit((c) >> 4), pal4bit((c) >> 0)) + + +/* The vertices are buffered here */ +struct point +{ + point(): + x(0), + y(0), + col(0), + intensity(0), + arg1(0), + arg2(0), + status(0) {} + + int x; int y; + rgb_t col; + int intensity; + int arg1; int arg2; /* start/end in pixel array or clipping info */ + int status; /* for dirty and clipping handling */ +}; + +class vector_device : public device_t, + public device_video_interface +{ +public: + // construction/destruction + vector_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + vector_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + UINT32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); + void clear_list(); + + void add_point(int x, int y, rgb_t color, int intensity); + void add_clip(int minx, int miny, int maxx, int maxy); + + void set_flicker(float m_flicker_correction); + float get_flicker(); + + void set_beam(float _beam); + float get_beam(); + + // device-level overrides + virtual void device_start(); + +private: + static int m_flicker; /* beam flicker value */ + static float m_flicker_correction; + static float m_beam_width; + point *m_vector_list; + static int m_vector_index; +}; + + +// device type definition +extern const device_type VECTOR; + +#define MCFG_VECTOR_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, VECTOR, 0) + +#endif diff --git a/src/devices/video/vic4567.c b/src/devices/video/vic4567.c new file mode 100644 index 00000000000..ca98279365b --- /dev/null +++ b/src/devices/video/vic4567.c @@ -0,0 +1,2055 @@ +// license:BSD-3-Clause +// copyright-holders:Peter Trauner +/*************************************************************************** + + Video Interface Chip (4567) + + original emulation by PeT (mess@utanet.at) + + 2010-02: converted to be a device and split from vic II + + TODO: + - plenty of cleanups + - emulate variants of the vic chip + - update vic III to use the new vic6567.c code for the vic II comaptibility + +***************************************************************************/ + +#include "emu.h" +#include "video/vic4567.h" + +/***************************************************************************** + CONSTANTS +*****************************************************************************/ + +#define VERBOSE_LEVEL 0 +#define DBG_LOG(N,M,A) \ + do { \ + if(VERBOSE_LEVEL >= N) \ + { \ + if( M ) \ + logerror("%11.6f: %-24s", machine().time().as_double(), (char*) M ); \ + logerror A; \ + } \ + } while (0) + +#define VREFRESHINLINES 28 + +#define VIC2_YPOS 50 +#define RASTERLINE_2_C64(a) (a) +#define C64_2_RASTERLINE(a) (a) +#define XPOS (VIC2_STARTVISIBLECOLUMNS + (VIC2_VISIBLECOLUMNS - VIC2_HSIZE) / 2) +#define YPOS (VIC2_STARTVISIBLELINES /* + (VIC2_VISIBLELINES - VIC2_VSIZE) / 2 */) +#define FIRSTLINE 10 /* 36 ((VIC2_VISIBLELINES - VIC2_VSIZE)/2) */ +#define FIRSTCOLUMN 50 + +/* 2008-05 FP: lightpen code needs to read input port from c64.c and cbmb.c */ + +#define LIGHTPEN_BUTTON (m_lightpen_button_cb(0)) +#define LIGHTPEN_X_VALUE (m_lightpen_x_cb(0)) +#define LIGHTPEN_Y_VALUE (m_lightpen_y_cb(0)) + +/* lightpen delivers values from internal counters; they do not start with the visual area or frame area */ +#define VIC2_MAME_XPOS 0 +#define VIC2_MAME_YPOS 0 +#define VIC6567_X_BEGIN 38 +#define VIC6567_Y_BEGIN -6 /* first 6 lines after retrace not for lightpen! */ +#define VIC6569_X_BEGIN 38 +#define VIC6569_Y_BEGIN -6 +#define VIC2_X_BEGIN ((m_type == VIC4567_PAL) ? VIC6569_X_BEGIN : VIC6567_X_BEGIN) +#define VIC2_Y_BEGIN ((m_type == VIC4567_PAL) ? VIC6569_Y_BEGIN : VIC6567_Y_BEGIN) +#define VIC2_X_VALUE ((LIGHTPEN_X_VALUE + VIC2_X_BEGIN + VIC2_MAME_XPOS) / 2) +#define VIC2_Y_VALUE ((LIGHTPEN_Y_VALUE + VIC2_Y_BEGIN + VIC2_MAME_YPOS)) + +#define VIC2E_K0_LEVEL (m_reg[0x2f] & 0x01) +#define VIC2E_K1_LEVEL (m_reg[0x2f] & 0x02) +#define VIC2E_K2_LEVEL (m_reg[0x2f] & 0x04) + +/*#define VIC3_P5_LEVEL (m_reg[0x30] & 0x20) */ +#define VIC3_BITPLANES (m_reg[0x31] & 0x10) +#define VIC3_80COLUMNS (m_reg[0x31] & 0x80) +#define VIC3_LINES ((m_reg[0x31] & 0x19) == 0x19 ? 400 : 200) +#define VIC3_BITPLANES_WIDTH (m_reg[0x31] & 0x80 ? 640 : 320) + +/*#define VIC2E_TEST (vic2[0x30] & 2) */ +#define DOUBLE_CLOCK (m_reg[0x30] & 0x01) + +/* sprites 0 .. 7 */ +#define SPRITEON(nr) (m_reg[0x15] & (1 << nr)) +#define SPRITE_Y_EXPAND(nr) (m_reg[0x17] & (1 << nr)) +#define SPRITE_Y_SIZE(nr) (SPRITE_Y_EXPAND(nr) ? 2 * 21 : 21) +#define SPRITE_X_EXPAND(nr) (m_reg[0x1d] & (1 << nr)) +#define SPRITE_X_SIZE(nr) (SPRITE_X_EXPAND(nr) ? 2 * 24 : 24) +#define SPRITE_X_POS(nr) ((m_reg[(nr) * 2] | (m_reg[0x10] & (1 <<(nr)) ? 0x100 : 0)) - 24 + XPOS) +#define SPRITE_X_POS2(nr) (m_reg[(nr) * 2] | (m_reg[0x10] & (1 <<(nr)) ? 0x100 : 0)) +#define SPRITE_Y_POS(nr) (m_reg[1+2*(nr)] - 50 + YPOS) +#define SPRITE_Y_POS2(nr) (m_reg[1 + 2 *(nr)]) +#define SPRITE_MULTICOLOR(nr) (m_reg[0x1c] & (1 << nr)) +#define SPRITE_PRIORITY(nr) (m_reg[0x1b] & (1 << nr)) +#define SPRITE_MULTICOLOR1 (m_reg[0x25] & 0x0f) +#define SPRITE_MULTICOLOR2 (m_reg[0x26] & 0x0f) +#define SPRITE_COLOR(nr) (m_reg[0x27+nr] & 0x0f) +#define SPRITE_ADDR(nr) (m_videoaddr | 0x3f8 | nr) +#define SPRITE_BG_COLLISION(nr) (m_reg[0x1f] & (1 << nr)) +#define SPRITE_COLLISION(nr) (m_reg[0x1e] & (1 << nr)) +#define SPRITE_SET_BG_COLLISION(nr) (m_reg[0x1f] |= (1 << nr)) +#define SPRITE_SET_COLLISION(nr) (m_reg[0x1e] |= (1 << nr)) +#define SPRITE_COLL (m_reg[0x1e]) +#define SPRITE_BG_COLL (m_reg[0x1f]) + +#define GFXMODE ((m_reg[0x11] & 0x60) | (m_reg[0x16] & 0x10)) >> 4 +#define SCREENON (m_reg[0x11] & 0x10) +#define VERTICALPOS (m_reg[0x11] & 0x07) +#define HORIZONTALPOS (m_reg[0x16] & 0x07) +#define ECMON (m_reg[0x11] & 0x40) +#define HIRESON (m_reg[0x11] & 0x20) +#define MULTICOLORON (m_reg[0x16] & 0x10) +#define LINES25 (m_reg[0x11] & 0x08) /* else 24 Lines */ +#define LINES (LINES25 ? 25 : 24) +#define YSIZE (LINES * 8) +#define COLUMNS40 (m_reg[0x16] & 0x08) /* else 38 Columns */ +#define COLUMNS (COLUMNS40 ? 40 : 38) +#define XSIZE (COLUMNS * 8) + +#define VIDEOADDR ((m_reg[0x18] & 0xf0) << (10 - 4)) +#define CHARGENADDR ((m_reg[0x18] & 0x0e) << 10) +#define BITMAPADDR ((data & 0x08) << 10) + +#define RASTERLINE (((m_reg[0x11] & 0x80) << 1) | m_reg[0x12]) + +#define FRAMECOLOR (m_reg[0x20] & 0x0f) +#define BACKGROUNDCOLOR (m_reg[0x21] & 0x0f) +#define MULTICOLOR1 (m_reg[0x22] & 0x0f) +#define MULTICOLOR2 (m_reg[0x23] & 0x0f) +#define FOREGROUNDCOLOR (m_reg[0x24] & 0x0f) + + +#define VIC2_LINES (m_type == VIC4567_PAL ? VIC6569_LINES : VIC6567_LINES) +#define VIC2_VISIBLELINES (m_type == VIC4567_PAL ? VIC6569_VISIBLELINES : VIC6567_VISIBLELINES) +#define VIC2_VISIBLECOLUMNS (m_type == VIC4567_PAL ? VIC6569_VISIBLECOLUMNS : VIC6567_VISIBLECOLUMNS) +#define VIC2_STARTVISIBLELINES ((VIC2_LINES - VIC2_VISIBLELINES)/2) +#define VIC2_FIRSTRASTERLINE (m_type == VIC4567_PAL ? VIC6569_FIRSTRASTERLINE : VIC6567_FIRSTRASTERLINE) +#define VIC2_COLUMNS (m_type == VIC4567_PAL ? VIC6569_COLUMNS : VIC6567_COLUMNS) +#define VIC2_STARTVISIBLECOLUMNS ((VIC2_COLUMNS - VIC2_VISIBLECOLUMNS)/2) + +#define VIC3_BITPLANES_MASK (m_reg[0x32]) +/* bit 0, 4 not used !?*/ +/* I think hinibbles contains the banknumbers for interlaced modes */ +/* if hinibble set then x&1==0 should be in bank1 (0x10000), x&1==1 in bank 0 */ +#define VIC3_BITPLANE_ADDR_HELPER(x) ((m_reg[0x33 + x] & 0x0f) << 12) +#define VIC3_BITPLANE_ADDR(x) (x & 1 ? VIC3_BITPLANE_ADDR_HELPER(x) + 0x10000 : VIC3_BITPLANE_ADDR_HELPER(x) ) +#define VIC3_BITPLANE_IADDR_HELPER(x) ((m_reg[0x33 + x] & 0xf0) << 8) +#define VIC3_BITPLANE_IADDR(x) (x & 1 ? VIC3_BITPLANE_IADDR_HELPER(x) + 0x10000 : VIC3_BITPLANE_IADDR_HELPER(x)) + + +const device_type VIC3 = &device_creator; + +vic3_device::vic3_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, VIC3, "4567 VIC III", tag, owner, clock, "vic3", __FILE__), + device_video_interface(mconfig, *this), + m_type(VIC4567_NTSC), + m_cpu(*this), + m_dma_read_cb(*this), + m_dma_read_color_cb(*this), + m_interrupt_cb(*this), + m_port_changed_cb(*this), + m_lightpen_button_cb(*this), + m_lightpen_x_cb(*this), + m_lightpen_y_cb(*this), + m_c64_mem_r_cb(*this), + m_palette(*this, "palette") +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void vic3_device::device_start() +{ + int width, height; + + width = m_screen->width(); + height = m_screen->height(); + + m_bitmap = auto_bitmap_ind16_alloc(machine(), width, height); + + m_dma_read_cb.resolve_safe(0); + m_dma_read_color_cb.resolve_safe(0); + m_interrupt_cb.resolve_safe(); + + m_port_changed_cb.resolve(); + + m_c64_mem_r_cb.resolve_safe(0); + + m_lightpen_button_cb.resolve_safe(0); + m_lightpen_x_cb.resolve_safe(0); + m_lightpen_y_cb.resolve_safe(0); + + m_screenptr[0] = auto_alloc_array(machine(), UINT8, 216 * 656 / 8); + + for (int i = 1; i < 216; i++) + m_screenptr[i] = m_screenptr[i - 1] + 656 / 8; + + for (int i = 0; i < 256; i++) + { + m_foreground[i] = 0; + if ((i & 3) > 1) + m_foreground[i] |= 0x3; + if ((i & 0xc) > 0x4) + m_foreground[i] |= 0xc; + if ((i & 0x30) > 0x10) + m_foreground[i] |= 0x30; + if ((i & 0xc0) > 0x40) + m_foreground[i] |= 0xc0; + } + + for (int i = 0; i < 256; i++) + { + m_expandx[i] = 0; + if (i & 1) + m_expandx[i] |= 3; + if (i & 2) + m_expandx[i] |= 0xc; + if (i & 4) + m_expandx[i] |= 0x30; + if (i & 8) + m_expandx[i] |= 0xc0; + if (i & 0x10) + m_expandx[i] |= 0x300; + if (i & 0x20) + m_expandx[i] |= 0xc00; + if (i & 0x40) + m_expandx[i] |= 0x3000; + if (i & 0x80) + m_expandx[i] |= 0xc000; + } + + for (int i = 0; i < 256; i++) + { + m_expandx_multi[i] = 0; + if (i & 1) + m_expandx_multi[i] |= 5; + if (i & 2) + m_expandx_multi[i] |= 0xa; + if (i & 4) + m_expandx_multi[i] |= 0x50; + if (i & 8) + m_expandx_multi[i] |= 0xa0; + if (i & 0x10) + m_expandx_multi[i] |= 0x500; + if (i & 0x20) + m_expandx_multi[i] |= 0xa00; + if (i & 0x40) + m_expandx_multi[i] |= 0x5000; + if (i & 0x80) + m_expandx_multi[i] |= 0xa000; + } + + save_item(NAME(m_reg)); + + save_item(NAME(m_on)); + + //save_item(NAME(m_bitmap)); + + save_item(NAME(m_lines)); + + save_item(NAME(m_chargenaddr)); + save_item(NAME(m_videoaddr)); + save_item(NAME(m_bitmapaddr)); + + save_item(NAME(m_x_begin)); + save_item(NAME(m_x_end)); + save_item(NAME(m_y_begin)); + save_item(NAME(m_y_end)); + + save_item(NAME(m_c64_bitmap)); + save_item(NAME(m_bitmapmulti)); + save_item(NAME(m_mono)); + save_item(NAME(m_multi)); + save_item(NAME(m_ecmcolor)); + save_item(NAME(m_colors)); + save_item(NAME(m_spritemulti)); + + save_item(NAME(m_lastline)); + save_item(NAME(m_rasterline)); + save_item(NAME(m_interlace)); + + save_item(NAME(m_columns)); + save_item(NAME(m_rows)); + + save_item(NAME(m_shift)); + save_item(NAME(m_foreground)); + save_item(NAME(m_multi_collision)); + + save_item(NAME(m_palette_red)); + save_item(NAME(m_palette_green)); + save_item(NAME(m_palette_blue)); + save_item(NAME(m_palette_dirty)); + + for (int i = 0; i < 8; i++) + { + save_item(NAME(m_sprites[i].x), i); + save_item(NAME(m_sprites[i].y), i); + save_item(NAME(m_sprites[i].repeat), i); + save_item(NAME(m_sprites[i].line), i); + save_item(NAME(m_sprites[i].paintedline), i); + save_item(NAME(m_sprites[i].bitmap[0]), i); + save_item(NAME(m_sprites[i].bitmap[1]), i); + save_item(NAME(m_sprites[i].bitmap[2]), i); + save_item(NAME(m_sprites[i].bitmap[3]), i); + save_item(NAME(m_sprites[i].bitmap[4]), i); + save_item(NAME(m_sprites[i].bitmap[5]), i); + save_item(NAME(m_sprites[i].bitmap[6]), i); + save_item(NAME(m_sprites[i].bitmap[7]), i); + } +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void vic3_device::device_reset() +{ + memset(m_reg, 0, ARRAY_LENGTH(m_reg)); + + m_on = 1; + + m_interlace = 0; + m_columns = 640; + m_rows = 200; + m_lines = VIC2_LINES; + + memset(&m_sprites, 0, sizeof(m_sprites)); + + m_chargenaddr = 0; + m_videoaddr = 0; + m_bitmapaddr = 0; + + m_x_begin = 0; + m_x_end = 0; + m_y_begin = 0; + m_y_end = 0; + + for (int i = 0; i < 2; i++) + { + m_c64_bitmap[i] = 0; + m_mono[i] = 0; + m_ecmcolor[i] = 0; + } + + for (int i = 0; i < 4; i++) + { + m_bitmapmulti[i] = 0; + m_multi[i] = 0; + m_colors[i] = 0; + m_spritemulti[i] = 0; + } + + m_lastline = 0; + m_rasterline = 0; + + memset(m_shift, 0, ARRAY_LENGTH(m_shift)); + memset(m_multi_collision, 0, ARRAY_LENGTH(m_multi_collision)); + memset(m_palette_red, 0, ARRAY_LENGTH(m_palette_red)); + memset(m_palette_green, 0, ARRAY_LENGTH(m_palette_green)); + memset(m_palette_blue, 0, ARRAY_LENGTH(m_palette_blue)); + + m_palette_dirty = 0; +} + + +/***************************************************************************** + IMPLEMENTATION +*****************************************************************************/ + +inline int vic3_device::getforeground( int y, int x ) +{ + return ((m_screenptr[y][x >> 3] << 8) | (m_screenptr[y][(x >> 3) + 1])) >> (8 - (x & 7)); +} + +inline int vic3_device::getforeground16( int y, int x ) +{ + return ((m_screenptr[y][x >> 3] << 16) | (m_screenptr[y][(x >> 3) + 1] << 8) | (m_screenptr[y][(x >> 3) + 2])) >> (8 - (x & 7)); +} + +void vic3_device::set_interrupt( int mask ) +{ + if (((m_reg[0x19] ^ mask) & m_reg[0x1a] & 0xf)) + { + if (!(m_reg[0x19] & 0x80)) + { + //DBG_LOG(2, "vic2", ("irq start %.2x\n", mask)); + m_reg[0x19] |= 0x80; + m_interrupt_cb(1); + } + } + m_reg[0x19] |= mask; +} + +void vic3_device::clear_interrupt( int mask ) +{ + m_reg[0x19] &= ~mask; + if ((m_reg[0x19] & 0x80) && !(m_reg[0x19] & m_reg[0x1a] & 0xf)) + { + //DBG_LOG(2, "vic2", ("irq end %.2x\n", mask)); + m_reg[0x19] &= ~0x80; + m_interrupt_cb(0); + } +} + +TIMER_CALLBACK_MEMBER( vic3_device::timer_timeout ) +{ + int which = param; + //DBG_LOG(3, "vic3 ", ("timer %d timeout\n", which)); + switch (which) + { + case 1: /* light pen */ + /* and diode must recognize light */ + if (1) + { + m_reg[0x13] = VIC2_X_VALUE; + m_reg[0x14] = VIC2_Y_VALUE; + } + set_interrupt(8); + break; + } +} + +void vic3_device::draw_character( int ybegin, int yend, int ch, int yoff, int xoff, UINT16 *color, int start_x, int end_x ) +{ + int code; + + for (int y = ybegin; y <= yend; y++) + { + code = m_dma_read_cb(m_chargenaddr + ch * 8 + y); + m_screenptr[y + yoff][xoff >> 3] = code; + if ((xoff + 0 > start_x) && (xoff + 0 < end_x)) m_bitmap->pix16(y + yoff + FIRSTLINE, xoff + 0) = color[code >> 7]; + if ((xoff + 1 > start_x) && (xoff + 0 < end_x)) m_bitmap->pix16(y + yoff + FIRSTLINE, xoff + 1) = color[(code >> 6) & 1]; + if ((xoff + 2 > start_x) && (xoff + 0 < end_x)) m_bitmap->pix16(y + yoff + FIRSTLINE, xoff + 2) = color[(code >> 5) & 1]; + if ((xoff + 3 > start_x) && (xoff + 0 < end_x)) m_bitmap->pix16(y + yoff + FIRSTLINE, xoff + 3) = color[(code >> 4) & 1]; + if ((xoff + 4 > start_x) && (xoff + 0 < end_x)) m_bitmap->pix16(y + yoff + FIRSTLINE, xoff + 4) = color[(code >> 3) & 1]; + if ((xoff + 5 > start_x) && (xoff + 0 < end_x)) m_bitmap->pix16(y + yoff + FIRSTLINE, xoff + 5) = color[(code >> 2) & 1]; + if ((xoff + 6 > start_x) && (xoff + 0 < end_x)) m_bitmap->pix16(y + yoff + FIRSTLINE, xoff + 6) = color[(code >> 1) & 1]; + if ((xoff + 7 > start_x) && (xoff + 0 < end_x)) m_bitmap->pix16(y + yoff + FIRSTLINE, xoff + 7) = color[code & 1]; + } +} + +void vic3_device::draw_character_multi( int ybegin, int yend, int ch, int yoff, int xoff, int start_x, int end_x ) +{ + int code; + + for (int y = ybegin; y <= yend; y++) + { + code = m_dma_read_cb(m_chargenaddr + ch * 8 + y); + m_screenptr[y + yoff][xoff >> 3] = m_foreground[code]; + if ((xoff + 0 > start_x) && (xoff + 0 < end_x)) m_bitmap->pix16(y + yoff + FIRSTLINE, xoff + 0) = m_multi[code >> 6]; + if ((xoff + 1 > start_x) && (xoff + 1 < end_x)) m_bitmap->pix16(y + yoff + FIRSTLINE, xoff + 1) = m_multi[code >> 6]; + if ((xoff + 2 > start_x) && (xoff + 2 < end_x)) m_bitmap->pix16(y + yoff + FIRSTLINE, xoff + 2) = m_multi[(code >> 4) & 3]; + if ((xoff + 3 > start_x) && (xoff + 3 < end_x)) m_bitmap->pix16(y + yoff + FIRSTLINE, xoff + 3) = m_multi[(code >> 4) & 3]; + if ((xoff + 4 > start_x) && (xoff + 4 < end_x)) m_bitmap->pix16(y + yoff + FIRSTLINE, xoff + 4) = m_multi[(code >> 2) & 3]; + if ((xoff + 5 > start_x) && (xoff + 5 < end_x)) m_bitmap->pix16(y + yoff + FIRSTLINE, xoff + 5) = m_multi[(code >> 2) & 3]; + if ((xoff + 6 > start_x) && (xoff + 6 < end_x)) m_bitmap->pix16(y + yoff + FIRSTLINE, xoff + 6) = m_multi[code & 3]; + if ((xoff + 7 > start_x) && (xoff + 7 < end_x)) m_bitmap->pix16(y + yoff + FIRSTLINE, xoff + 7) = m_multi[code & 3]; + } +} + +void vic3_device::draw_bitmap( int ybegin, int yend, int ch, int yoff, int xoff, int start_x, int end_x ) +{ + int code; + + for (int y = ybegin; y <= yend; y++) + { + code = m_dma_read_cb((m_chargenaddr & 0x2000) + ch * 8 + y); + m_screenptr[y + yoff][xoff >> 3] = code; + if ((xoff + 0 > start_x) && (xoff + 0 < end_x)) m_bitmap->pix16(y + yoff + FIRSTLINE, xoff + 0) = m_c64_bitmap[code >> 7]; + if ((xoff + 1 > start_x) && (xoff + 1 < end_x)) m_bitmap->pix16(y + yoff + FIRSTLINE, xoff + 1) = m_c64_bitmap[(code >> 6) & 1]; + if ((xoff + 2 > start_x) && (xoff + 2 < end_x)) m_bitmap->pix16(y + yoff + FIRSTLINE, xoff + 2) = m_c64_bitmap[(code >> 5) & 1]; + if ((xoff + 3 > start_x) && (xoff + 3 < end_x)) m_bitmap->pix16(y + yoff + FIRSTLINE, xoff + 3) = m_c64_bitmap[(code >> 4) & 1]; + if ((xoff + 4 > start_x) && (xoff + 4 < end_x)) m_bitmap->pix16(y + yoff + FIRSTLINE, xoff + 4) = m_c64_bitmap[(code >> 3) & 1]; + if ((xoff + 5 > start_x) && (xoff + 5 < end_x)) m_bitmap->pix16(y + yoff + FIRSTLINE, xoff + 5) = m_c64_bitmap[(code >> 2) & 1]; + if ((xoff + 6 > start_x) && (xoff + 6 < end_x)) m_bitmap->pix16(y + yoff + FIRSTLINE, xoff + 6) = m_c64_bitmap[(code >> 1) & 1]; + if ((xoff + 7 > start_x) && (xoff + 7 < end_x)) m_bitmap->pix16(y + yoff + FIRSTLINE, xoff + 7) = m_c64_bitmap[code & 1]; + } +} + +void vic3_device::draw_bitmap_multi( int ybegin, int yend, int ch, int yoff, int xoff, int start_x, int end_x ) +{ + int code; + + for (int y = ybegin; y <= yend; y++) + { + code = m_dma_read_cb((m_chargenaddr & 0x2000) + ch * 8 + y); + m_screenptr[y + yoff][xoff >> 3] = m_foreground[code]; + if ((xoff + 0 > start_x) && (xoff + 0 < end_x)) m_bitmap->pix16(y + yoff + FIRSTLINE, xoff + 0) = m_bitmapmulti[code >> 6]; + if ((xoff + 1 > start_x) && (xoff + 1 < end_x)) m_bitmap->pix16(y + yoff + FIRSTLINE, xoff + 1) = m_bitmapmulti[code >> 6]; + if ((xoff + 2 > start_x) && (xoff + 2 < end_x)) m_bitmap->pix16(y + yoff + FIRSTLINE, xoff + 2) = m_bitmapmulti[(code >> 4) & 3]; + if ((xoff + 3 > start_x) && (xoff + 3 < end_x)) m_bitmap->pix16(y + yoff + FIRSTLINE, xoff + 3) = m_bitmapmulti[(code >> 4) & 3]; + if ((xoff + 4 > start_x) && (xoff + 4 < end_x)) m_bitmap->pix16(y + yoff + FIRSTLINE, xoff + 4) = m_bitmapmulti[(code >> 2) & 3]; + if ((xoff + 5 > start_x) && (xoff + 5 < end_x)) m_bitmap->pix16(y + yoff + FIRSTLINE, xoff + 5) = m_bitmapmulti[(code >> 2) & 3]; + if ((xoff + 6 > start_x) && (xoff + 6 < end_x)) m_bitmap->pix16(y + yoff + FIRSTLINE, xoff + 6) = m_bitmapmulti[code & 3]; + if ((xoff + 7 > start_x) && (xoff + 7 < end_x)) m_bitmap->pix16(y + yoff + FIRSTLINE, xoff + 7) = m_bitmapmulti[code & 3]; + } +} + +void vic3_device::draw_sprite_code( int y, int xbegin, int code, int color, int start_x, int end_x ) +{ + register int mask, x; + + if ((y < YPOS) || (y >= (VIC2_STARTVISIBLELINES + VIC2_VISIBLELINES)) || (xbegin <= 1) || (xbegin >= (VIC2_STARTVISIBLECOLUMNS + VIC2_VISIBLECOLUMNS))) + return; + + for (x = 0, mask = 0x80; x < 8; x++, mask >>= 1) + { + if (code & mask) + { + if ((xbegin + x > start_x) && (xbegin + x < end_x)) + m_bitmap->pix16(y + FIRSTLINE, xbegin + x) = color; + } + } +} + +void vic3_device::draw_sprite_code_multi( int y, int xbegin, int code, int prior, int start_x, int end_x ) +{ + register int x, mask, shift; + + if ((y < YPOS) || (y >= (VIC2_STARTVISIBLELINES + VIC2_VISIBLELINES)) || (xbegin <= 1) || (xbegin >= (VIC2_STARTVISIBLECOLUMNS + VIC2_VISIBLECOLUMNS))) + return; + + for (x = 0, mask = 0xc0, shift = 6; x < 8; x += 2, mask >>= 2, shift -= 2) + { + if (code & mask) + { + switch ((prior & mask) >> shift) + { + case 1: + if ((xbegin + x + 1 > start_x) && (xbegin + x + 1 < end_x)) + m_bitmap->pix16(y + FIRSTLINE, xbegin + x + 1) = m_spritemulti[(code >> shift) & 3]; + break; + case 2: + if ((xbegin + x > start_x) && (xbegin + x < end_x)) + m_bitmap->pix16(y + FIRSTLINE, xbegin + x) = m_spritemulti[(code >> shift) & 3]; + break; + case 3: + if ((xbegin + x > start_x) && (xbegin + x < end_x)) + m_bitmap->pix16(y + FIRSTLINE, xbegin + x) = m_spritemulti[(code >> shift) & 3]; + if ((xbegin + x + 1> start_x) && (xbegin + x + 1< end_x)) + m_bitmap->pix16(y + FIRSTLINE, xbegin + x + 1) = m_spritemulti[(code >> shift) & 3]; + break; + } + } + } +} + +void vic3_device::sprite_collision( int nr, int y, int x, int mask ) +{ + int value, xdiff; + + for (int i = 7; i > nr; i--) + { + if (!SPRITEON(i) || !m_sprites[i].paintedline[y] || (SPRITE_COLLISION(i) && SPRITE_COLLISION(nr))) + continue; + + if ((x + 7 < SPRITE_X_POS(i)) || (x >= SPRITE_X_POS(i) + SPRITE_X_SIZE(i))) + continue; + + xdiff = x - SPRITE_X_POS(i); + + if ((x & 7) == (SPRITE_X_POS(i) & 7)) + value = m_sprites[i].bitmap[y][xdiff >> 3]; + else if (xdiff < 0) + value = m_sprites[i].bitmap[y][0] >> (-xdiff); + else { + UINT8 *vp = m_sprites[i].bitmap[y]+(xdiff >> 3); + value = ((vp[1] | (*vp << 8)) >> (8 - (xdiff & 7) )) & 0xff; + } + + if (value & mask) + { + SPRITE_SET_COLLISION(i); + SPRITE_SET_COLLISION(nr); + set_interrupt(4); + } + } +} + +void vic3_device::draw_sprite( int nr, int yoff, int ybegin, int yend, int start_x, int end_x ) +{ + int y, i, addr, xbegin, color, prior, collision; + int value, value3 = 0; + + xbegin = SPRITE_X_POS(nr); + addr = m_dma_read_cb(SPRITE_ADDR(nr)) << 6; + color = SPRITE_COLOR(nr); + prior = SPRITE_PRIORITY(nr); + collision = SPRITE_BG_COLLISION(nr); + + if (SPRITE_X_EXPAND(nr)) + { + for (y = ybegin; y <= yend; y++) + { + m_sprites[nr].paintedline[y] = 1; + for (i = 0; i < 3; i++) + { + value = m_expandx[m_dma_read_cb(addr + m_sprites[nr].line * 3 + i)]; + m_sprites[nr].bitmap[y][i * 2] = value >> 8; + m_sprites[nr].bitmap[y][i * 2 + 1] = value & 0xff; + sprite_collision(nr, y, xbegin + i * 16, value >> 8); + sprite_collision(nr, y, xbegin + i * 16 + 8, value & 0xff); + if (prior || !collision) + value3 = getforeground16(yoff + y, xbegin + i * 16 - 7); + if (!collision && (value & value3)) + { + collision = 1; + SPRITE_SET_BG_COLLISION(nr); + set_interrupt(2); + } + if (prior) + value &= ~value3; + draw_sprite_code(yoff + y, xbegin + i * 16, value >> 8, color, start_x, end_x); + draw_sprite_code(yoff + y, xbegin + i * 16 + 8, value & 0xff, color, start_x, end_x); + } + m_sprites[nr].bitmap[y][i * 2]=0; //easier sprite collision detection + if (SPRITE_Y_EXPAND(nr)) + { + if (m_sprites[nr].repeat) + { + m_sprites[nr].line++; + m_sprites[nr].repeat = 0; + } + else + m_sprites[nr].repeat = 1; + } + else + { + m_sprites[nr].line++; + } + } + } + else + { + for (y = ybegin; y <= yend; y++) + { + m_sprites[nr].paintedline[y] = 1; + for (i = 0; i < 3; i++) + { + value = m_dma_read_cb(addr + m_sprites[nr].line * 3 + i); + m_sprites[nr].bitmap[y][i] = value; + sprite_collision(nr, y, xbegin + i * 8, value); + if (prior || !collision) + value3 = getforeground(yoff + y, xbegin + i * 8 - 7); + if (!collision && (value & value3)) + { + collision = 1; + SPRITE_SET_BG_COLLISION(nr); + set_interrupt(2); + } + if (prior) + value &= ~value3; + draw_sprite_code(yoff + y, xbegin + i * 8, value, color, start_x, end_x); + } + m_sprites[nr].bitmap[y][i]=0; //easier sprite collision detection + if (SPRITE_Y_EXPAND(nr)) + { + if (m_sprites[nr].repeat) + { + m_sprites[nr].line++; + m_sprites[nr].repeat = 0; + } + else + m_sprites[nr].repeat = 1; + } + else + { + m_sprites[nr].line++; + } + } + } +} + +void vic3_device::draw_sprite_multi( int nr, int yoff, int ybegin, int yend, int start_x, int end_x ) +{ + int y, i, prior, addr, xbegin, collision; + int value, value2, value3 = 0, bg/*, color[2]*/; + + xbegin = SPRITE_X_POS(nr); + addr = m_dma_read_cb(SPRITE_ADDR(nr)) << 6; + m_spritemulti[2] = SPRITE_COLOR(nr); + prior = SPRITE_PRIORITY(nr); + collision = SPRITE_BG_COLLISION(nr); + //color[0] = 0; + //color[1] = 1; + + if (SPRITE_X_EXPAND(nr)) + { + for (y = ybegin; y <= yend; y++) + { + m_sprites[nr].paintedline[y] = 1; + for (i = 0; i < 3; i++) + { + value = m_expandx_multi[bg = m_dma_read_cb(addr + m_sprites[nr].line * 3 + i)]; + value2 = m_expandx[m_multi_collision[bg]]; + m_sprites[nr].bitmap[y][i * 2] = value2 >> 8; + m_sprites[nr].bitmap[y][i * 2 + 1] = value2 & 0xff; + sprite_collision(nr, y, xbegin + i * 16, value2 >> 8); + sprite_collision(nr, y, xbegin + i * 16 + 8, value2 & 0xff); + if (prior || !collision) + { + value3 = getforeground16(yoff + y, xbegin + i * 16 - 7); + } + if (!collision && (value2 & value3)) + { + collision = 1; + SPRITE_SET_BG_COLLISION(nr); + set_interrupt(2); + } + if (prior) + { + draw_sprite_code_multi(yoff + y, xbegin + i * 16, value >> 8, (value3 >> 8) ^ 0xff, start_x, end_x); + draw_sprite_code_multi(yoff + y, xbegin + i * 16 + 8, value & 0xff, (value3 & 0xff) ^ 0xff, start_x, end_x); + } + else + { + draw_sprite_code_multi(yoff + y, xbegin + i * 16, value >> 8, 0xff, start_x, end_x); + draw_sprite_code_multi(yoff + y, xbegin + i * 16 + 8, value & 0xff, 0xff, start_x, end_x); + } + } + m_sprites[nr].bitmap[y][i * 2]=0; //easier sprite collision detection + if (SPRITE_Y_EXPAND(nr)) + { + if (m_sprites[nr].repeat) + { + m_sprites[nr].line++; + m_sprites[nr].repeat = 0; + } + else + m_sprites[nr].repeat = 1; + } + else + { + m_sprites[nr].line++; + } + } + } + else + { + for (y = ybegin; y <= yend; y++) + { + m_sprites[nr].paintedline[y] = 1; + for (i = 0; i < 3; i++) + { + value = m_dma_read_cb(addr + m_sprites[nr].line * 3 + i); + m_sprites[nr].bitmap[y][i] = value2 = m_multi_collision[value]; + sprite_collision(nr, y, xbegin + i * 8, value2); + if (prior || !collision) + { + value3 = getforeground(yoff + y, xbegin + i * 8 - 7); + } + if (!collision && (value2 & value3)) + { + collision = 1; + SPRITE_SET_BG_COLLISION(nr); + set_interrupt(2); + } + if (prior) + { + draw_sprite_code_multi(yoff + y, xbegin + i * 8, value, value3 ^ 0xff, start_x, end_x); + } + else + { + draw_sprite_code_multi(yoff + y, xbegin + i * 8, value, 0xff, start_x, end_x); + } + } + m_sprites[nr].bitmap[y][i] = 0; //easier sprite collision detection + if (SPRITE_Y_EXPAND(nr)) + { + if (m_sprites[nr].repeat) + { + m_sprites[nr].line++; + m_sprites[nr].repeat = 0; + } + else + m_sprites[nr].repeat = 1; + } + else + { + m_sprites[nr].line++; + } + } + } +} + +#ifndef memset16 +static void *memset16(void *dest, int value, size_t size) +{ + register int i; + + for (i = 0; i < size; i++) + ((short *) dest)[i] = value; + return dest; +} +#endif + +void vic3_device::drawlines( int first, int last, int start_x, int end_x ) +{ + int line, vline, end; + int attr, ch, ecm; + int syend; + int offs, yoff, xoff, ybegin, yend, xbegin, xend; + int x_end2; + int i, j; + + if (first == last) + return; + m_lastline = last; + + /* top part of display not rastered */ + first -= VIC2_YPOS - YPOS; + last -= VIC2_YPOS - YPOS; + if ((first >= last) || (last <= 0)) + { + for (i = 0; i < 8; i++) + m_sprites[i].repeat = m_sprites[i].line = 0; + return; + } + if (first < 0) + first = 0; + + if (!SCREENON) + { + for (line = first; (line < last) && (line < m_bitmap->height()); line++) + { + memset16(&m_bitmap->pix16(line + FIRSTLINE), 0, m_bitmap->width()); + } + return; + } + if (COLUMNS40) + xbegin = XPOS, xend = xbegin + 640; + else + xbegin = XPOS + 7, xend = xbegin + 624; + + if (last < m_y_begin) + end = last; + else + end = m_y_begin + YPOS; + + for (line = first; line < end; line++) + { + memset16(&m_bitmap->pix16(line + FIRSTLINE), FRAMECOLOR, m_bitmap->width()); + } + + if (LINES25) + { + vline = line - m_y_begin - YPOS; + } + else + { + vline = line - m_y_begin - YPOS + 8 - VERTICALPOS; + } + if (last < m_y_end + YPOS) + end = last; + else + end = m_y_end + YPOS; + x_end2 = m_x_end * 2; + for (; line < end; vline = (vline + 8) & ~7, line = line + 1 + yend - ybegin) + { + offs = (vline >> 3) * 80; + ybegin = vline & 7; + yoff = line - ybegin; + yend = (yoff + 7 < end) ? 7 : (end - yoff - 1); + /* rendering 39 characters */ + /* left and right borders are overwritten later */ + m_shift[line] = HORIZONTALPOS; + + for (xoff = m_x_begin + XPOS; xoff < x_end2 + XPOS; xoff += 8, offs++) + { + ch = m_dma_read_cb(m_videoaddr + offs); + attr = m_dma_read_color_cb(m_videoaddr + offs); + if (HIRESON) + { + m_bitmapmulti[1] = m_c64_bitmap[1] = ch >> 4; + m_bitmapmulti[2] = m_c64_bitmap[0] = ch & 0xf; + if (MULTICOLORON) + { + m_bitmapmulti[3] = attr; + draw_bitmap_multi(ybegin, yend, offs, yoff, xoff, start_x, end_x); + } + else + { + draw_bitmap(ybegin, yend, offs, yoff, xoff, start_x, end_x); + } + } + else if (ECMON) + { + ecm = ch >> 6; + m_ecmcolor[0] = m_colors[ecm]; + m_ecmcolor[1] = attr; + draw_character(ybegin, yend, ch & ~0xC0, yoff, xoff, m_ecmcolor, start_x, end_x); + } + else if (MULTICOLORON && (attr & 8)) + { + m_multi[3] = attr & 7; + draw_character_multi(ybegin, yend, ch, yoff, xoff, start_x, end_x); + } + else + { + m_mono[1] = attr; + draw_character(ybegin, yend, ch, yoff, xoff, m_mono, start_x, end_x); + } + } + /* sprite priority, sprite overwrites lowerprior pixels */ + for (i = 7; i >= 0; i--) + { + if (m_sprites[i].line || m_sprites[i].repeat) + { + syend = yend; + if (SPRITE_Y_EXPAND(i)) + { + if ((21 - m_sprites[i].line) * 2 - m_sprites[i].repeat < yend - ybegin + 1) + syend = ybegin + (21 - m_sprites[i].line) * 2 - m_sprites[i].repeat - 1; + } + else + { + if (m_sprites[i].line + yend - ybegin + 1 > 20) + syend = ybegin + 20 - m_sprites[i].line; + } + if (yoff + syend > YPOS + 200) + syend = YPOS + 200 - yoff - 1; + if (SPRITE_MULTICOLOR(i)) + draw_sprite_multi(i, yoff, ybegin, syend, start_x, end_x); + else + draw_sprite(i, yoff, ybegin, syend, start_x, end_x); + if ((syend != yend) || (m_sprites[i].line > 20)) + { + m_sprites[i].line = m_sprites[i].repeat = 0; + for (j = syend; j <= yend; j++) + m_sprites[i].paintedline[j] = 0; + } + } + // sprite wrap y at the top of the screen + else if (SPRITEON(i) && (yoff == 1 + yend - ybegin) && (SPRITE_Y_POS(i) < 1 + yend - ybegin)) + { + int wrapped = 1 + yend - ybegin - SPRITE_Y_POS(i); + syend = yend; + + if (SPRITE_Y_EXPAND(i)) + { + if (wrapped & 1) m_sprites[i].repeat = 1; + wrapped >>= 1; + syend = 21 * 2 - 1 - wrapped * 2; + if (syend > (yend - ybegin)) syend = yend - ybegin; + } + else + { + syend = 21 - 1 - wrapped; + if (syend > (yend - ybegin)) syend = yend - ybegin; + } + + m_sprites[i].line = wrapped; + + if (SPRITE_MULTICOLOR(i)) + draw_sprite_multi(i, yoff, 0 , syend, start_x, end_x); + else + draw_sprite(i, yoff, 0 , syend, start_x, end_x); + + if ((syend != yend) || (m_sprites[i].line > 20)) + { + for (j = syend; j <= yend; j++) + m_sprites[i].paintedline[j] = 0; + m_sprites[i].line = m_sprites[i].repeat = 0; + } + } + else if (SPRITEON(i) && (yoff + ybegin <= SPRITE_Y_POS(i)) + && (yoff + yend >= SPRITE_Y_POS(i))) + { + syend = yend; + if (SPRITE_Y_EXPAND(i)) + { + if (21 * 2 < yend - ybegin + 1) + syend = ybegin + 21 * 2 - 1; + } + else + { + if (yend - ybegin + 1 > 21) + syend = ybegin + 21 - 1; + } + if (yoff + syend >= YPOS + 200) + syend = YPOS + 200 - yoff - 1; + for (j = 0; j < SPRITE_Y_POS(i) - yoff; j++) + m_sprites[i].paintedline[j] = 0; + if (SPRITE_MULTICOLOR(i)) + draw_sprite_multi(i, yoff, SPRITE_Y_POS(i) - yoff, syend, start_x, end_x); + else + draw_sprite(i, yoff, SPRITE_Y_POS(i) - yoff, syend, start_x, end_x); + if ((syend != yend) || (m_sprites[i].line > 20)) + { + for (j = syend; j <= yend; j++) + m_sprites[i].paintedline[j] = 0; + m_sprites[i].line = m_sprites[i].repeat = 0; + } + } + else + { + memset (m_sprites[i].paintedline, 0, sizeof (m_sprites[i].paintedline)); + } + } + + for (i = ybegin; i <= yend; i++) + { + m_bitmap->plot_box(0, yoff + ybegin + FIRSTLINE, xbegin, yend - ybegin + 1, FRAMECOLOR); + m_bitmap->plot_box(xend, yoff + ybegin + FIRSTLINE, m_bitmap->width() - xend, yend - ybegin + 1, FRAMECOLOR); + } + } + if (last < m_bitmap->height()) + end = last; + else + end = m_bitmap->height(); + + for (; line < end; line++) + { + memset16(&m_bitmap->pix16(line + FIRSTLINE), FRAMECOLOR, m_bitmap->width()); + } +} + +void vic3_device::vic2_drawlines( int first, int last, int start_x, int end_x ) +{ + int line, vline, end; + int attr, ch, ecm; + int syend; + int offs, yoff, xoff, ybegin, yend, xbegin, xend; + int i; + + if (VIC3_BITPLANES) + return ; + + /* temporary allowing vic3 displaying 80 columns */ + if (m_reg[0x31] & 0x80) + { + drawlines(first, first + 1, start_x, end_x); + return; + } + + /* otherwise, draw VIC II output (currently using the old code, not the new one from vic6567.c) */ + + /* top part of display not rastered */ + first -= VIC2_YPOS - YPOS; + + xbegin = VIC2_STARTVISIBLECOLUMNS; + xend = xbegin + VIC2_VISIBLECOLUMNS; + if (!SCREENON) + { + xbegin = VIC2_STARTVISIBLECOLUMNS; + xend = xbegin + VIC2_VISIBLECOLUMNS; + if ((start_x <= xbegin) && (end_x >= xend)) + m_bitmap->plot_box(xbegin, first + FIRSTLINE, xend - xbegin, 1, FRAMECOLOR); + if ((start_x > xbegin) && (end_x >= xend)) + m_bitmap->plot_box(start_x - VIC2_STARTVISIBLECOLUMNS, first + FIRSTLINE, xend - start_x, 1, FRAMECOLOR); + if ((start_x <= xbegin) && (end_x < xend)) + m_bitmap->plot_box(xbegin, first + FIRSTLINE, end_x - xbegin , 1, FRAMECOLOR); + if ((start_x > xbegin) && (end_x < xend)) + m_bitmap->plot_box(start_x - VIC2_STARTVISIBLECOLUMNS, first + FIRSTLINE, end_x - start_x, 1, FRAMECOLOR); + return; + } + + if (COLUMNS40) + { + xbegin = XPOS; + xend = xbegin + 320; + } + else + { + xbegin = XPOS + 7; + xend = xbegin + 304; + } + + if (first + 1 < m_y_begin) + end = first + 1; + else + end = m_y_begin + YPOS; + + line = first; + // top border + if (line < end) + { + if ((start_x <= xbegin) && (end_x >= xend)) + m_bitmap->plot_box(xbegin, first + FIRSTLINE, xend - xbegin, 1, FRAMECOLOR); + if ((start_x > xbegin) && (end_x >= xend)) + m_bitmap->plot_box(start_x - VIC2_STARTVISIBLECOLUMNS, first + FIRSTLINE, xend - start_x, 1, FRAMECOLOR); + if ((start_x <= xbegin) && (end_x < xend)) + m_bitmap->plot_box(xbegin, first + FIRSTLINE, end_x - xbegin , 1, FRAMECOLOR); + if ((start_x > xbegin) && (end_x < xend)) + m_bitmap->plot_box(start_x - VIC2_STARTVISIBLECOLUMNS, first + FIRSTLINE, end_x - start_x, 1, FRAMECOLOR); + line = end; + } + + vline = line - YPOS + 3 - VERTICALPOS; + + if (first + 1 < m_y_end + YPOS) + end = first + 1; + else + end = m_y_end + YPOS; + + if (line < end) + { + offs = (vline >> 3) * 40; + ybegin = vline & 7; + yoff = line - ybegin; + yend = (yoff + 7 < end) ? 7 : (end - yoff - 1); + + /* rendering 39 characters */ + /* left and right borders are overwritten later */ + + m_shift[line] = HORIZONTALPOS; + for (xoff = m_x_begin + XPOS; xoff < m_x_end + XPOS; xoff += 8, offs++) + { + ch = m_dma_read_cb(m_videoaddr + offs); +#if 0 + attr = m_dma_read_color_cb(m_videoaddr + offs); +#else + /* temporary until vic3 finished */ + attr = m_dma_read_color_cb((m_videoaddr + offs)&0x3ff)&0x0f; +#endif + if (HIRESON) + { + m_bitmapmulti[1] = m_c64_bitmap[1] = ch >> 4; + m_bitmapmulti[2] = m_c64_bitmap[0] = ch & 0xf; + if (MULTICOLORON) + { + m_bitmapmulti[3] = attr; + draw_bitmap_multi(ybegin, yend, offs, yoff, xoff, start_x, end_x); + } + else + { + draw_bitmap(ybegin, yend, offs, yoff, xoff, start_x, end_x); + } + } + else if (ECMON) + { + ecm = ch >> 6; + m_ecmcolor[0] = m_colors[ecm]; + m_ecmcolor[1] = attr; + draw_character(ybegin, yend, ch & ~0xC0, yoff, xoff, m_ecmcolor, start_x, end_x); + } + else if (MULTICOLORON && (attr & 8)) + { + m_multi[3] = attr & 7; + draw_character_multi(ybegin, yend, ch, yoff, xoff, start_x, end_x); + } + else + { + m_mono[1] = attr; + draw_character(ybegin, yend, ch, yoff, xoff, m_mono, start_x, end_x); + } + } + + /* sprite priority, sprite overwrites lowerprior pixels */ + for (i = 7; i >= 0; i--) + { + if (SPRITEON (i) && + (yoff + ybegin >= SPRITE_Y_POS (i)) && + (yoff + ybegin - SPRITE_Y_POS (i) < (SPRITE_Y_EXPAND (i)? 21 * 2 : 21 )) && + (SPRITE_Y_POS (i) < 0)) + { + int wrapped = - SPRITE_Y_POS (i) + 6; + + syend = yend; + + if (SPRITE_Y_EXPAND (i)) + { + if (wrapped & 1) m_sprites[i].repeat = 1; + wrapped >>= 1; + syend = 21 * 2 - 1 - wrapped * 2; + if (syend > (yend - ybegin)) syend = yend - ybegin; + } + else + { + syend = 21 - 1 - wrapped; + if (syend > (yend - ybegin)) syend = yend - ybegin; + } + + m_sprites[i].line = wrapped; + + if (SPRITE_MULTICOLOR (i)) + draw_sprite_multi(i, 0, 0 , syend, start_x, end_x); + else + draw_sprite(i, 0, 0 , syend, start_x, end_x); + } + else if (SPRITEON (i) && + (yoff + ybegin >= SPRITE_Y_POS (i)) && + (yoff + ybegin - SPRITE_Y_POS (i) < (SPRITE_Y_EXPAND (i)? 21 * 2 : 21 )) && + (SPRITE_Y_POS (i) >= 0)) + { + int wrapped = yoff + ybegin - SPRITE_Y_POS (i); + + syend = yend; + + if (SPRITE_Y_EXPAND (i)) + { + if (wrapped & 1) m_sprites[i].repeat = 1; + wrapped >>= 1; + syend = 21 * 2 - 1 - wrapped * 2; + if (syend > (yend - ybegin)) syend = yend - ybegin; + } + else + { + syend = 21 - 1 - wrapped; + if (syend > (yend - ybegin)) syend = yend - ybegin; + } + + m_sprites[i].line = wrapped; + + if (SPRITE_MULTICOLOR (i)) + draw_sprite_multi(i, yoff + ybegin, 0, 0, start_x, end_x); + else + draw_sprite(i, yoff + ybegin, 0, 0, start_x, end_x); + } + else + { + memset(m_sprites[i].paintedline, 0, sizeof (m_sprites[i].paintedline)); + } + } + line += 1 + yend - ybegin; + } + + // left border + if ((start_x <= VIC2_STARTVISIBLECOLUMNS) && (end_x >= xbegin)) + m_bitmap->plot_box(VIC2_STARTVISIBLECOLUMNS, first + FIRSTLINE, xbegin - VIC2_STARTVISIBLECOLUMNS, 1, FRAMECOLOR); + else if ((start_x > VIC2_STARTVISIBLECOLUMNS) && (end_x >= xbegin)) + m_bitmap->plot_box(start_x, first + FIRSTLINE, xbegin - start_x, 1, FRAMECOLOR); + else if ((start_x <= VIC2_STARTVISIBLECOLUMNS) && (end_x < xbegin)) + m_bitmap->plot_box(VIC2_STARTVISIBLECOLUMNS, first + FIRSTLINE, end_x, 1, FRAMECOLOR); + else if ((start_x > VIC2_STARTVISIBLECOLUMNS) && (end_x < xbegin)) + m_bitmap->plot_box(start_x, first + FIRSTLINE, end_x - start_x, 1, FRAMECOLOR); + + // right border + if ((start_x <= xend) && (end_x >= VIC2_STARTVISIBLECOLUMNS + VIC2_VISIBLECOLUMNS)) + m_bitmap->plot_box(xend, first + FIRSTLINE, VIC2_STARTVISIBLECOLUMNS + VIC2_VISIBLECOLUMNS - xend, 1, FRAMECOLOR); + else if ((start_x > xend) && (end_x >= VIC2_STARTVISIBLECOLUMNS + VIC2_VISIBLECOLUMNS)) + m_bitmap->plot_box(start_x, first + FIRSTLINE, VIC2_STARTVISIBLECOLUMNS + VIC2_VISIBLECOLUMNS - start_x, 1, FRAMECOLOR); + else if ((start_x <= xend) && (end_x < VIC2_STARTVISIBLECOLUMNS + VIC2_VISIBLECOLUMNS)) + m_bitmap->plot_box(xend, first + FIRSTLINE, end_x - xend, 1, FRAMECOLOR); + else if ((start_x > VIC2_STARTVISIBLECOLUMNS) && (end_x < xbegin)) + m_bitmap->plot_box(start_x, first + FIRSTLINE, end_x - start_x, 1, FRAMECOLOR); + + if (first + 1 < m_bitmap->height()) + end = first + 1; + else + end = m_bitmap->height(); + + // bottom border + if (line < end) + { + if ((start_x <= xbegin) && (end_x >= xend)) + m_bitmap->plot_box(xbegin, first + FIRSTLINE, xend - xbegin, 1, FRAMECOLOR); + if ((start_x > xbegin) && (end_x >= xend)) + m_bitmap->plot_box(start_x - VIC2_STARTVISIBLECOLUMNS, first + FIRSTLINE, xend - start_x, 1, FRAMECOLOR); + if ((start_x <= xbegin) && (end_x < xend)) + m_bitmap->plot_box(xbegin, first + FIRSTLINE, end_x - xbegin , 1, FRAMECOLOR); + if ((start_x > xbegin) && (end_x < xend)) + m_bitmap->plot_box(start_x - VIC2_STARTVISIBLECOLUMNS, first + FIRSTLINE, end_x - start_x, 1, FRAMECOLOR); + line = end; + } +} + +/***************************************************************************** + I/O HANDLERS +*****************************************************************************/ + +WRITE8_MEMBER( vic3_device::palette_w ) +{ + if (offset < 0x100) + m_palette_red[offset] = data; + else if (offset < 0x200) + m_palette_green[offset & 0xff] = data; + else + m_palette_blue[offset & 0xff] = data; + + m_palette_dirty = 1; +} + + +WRITE8_MEMBER( vic3_device::port_w ) +{ + DBG_LOG(2, "vic write", ("%.2x:%.2x\n", offset, data)); + offset &= 0x7f; + + /* offsets 0x00 -> 0x2e coincide with VICII */ + switch (offset) + { + case 0x01: + case 0x03: + case 0x05: + case 0x07: + case 0x09: + case 0x0b: + case 0x0d: + case 0x0f: + /* sprite y positions */ + if (m_reg[offset] != data) + { + m_reg[offset] = data; + m_sprites[offset / 2].y = SPRITE_Y_POS(offset / 2); + } + break; + + case 0x00: + case 0x02: + case 0x04: + case 0x06: + case 0x08: + case 0x0a: + case 0x0c: + case 0x0e: + /* sprite x positions */ + if (m_reg[offset] != data) + { + m_reg[offset] = data; + m_sprites[offset / 2].x = SPRITE_X_POS(offset / 2); + } + break; + + case 0x10: /* sprite x positions */ + if (m_reg[offset] != data) + { + m_reg[offset] = data; + m_sprites[0].x = SPRITE_X_POS(0); + m_sprites[1].x = SPRITE_X_POS(1); + m_sprites[2].x = SPRITE_X_POS(2); + m_sprites[3].x = SPRITE_X_POS(3); + m_sprites[4].x = SPRITE_X_POS(4); + m_sprites[5].x = SPRITE_X_POS(5); + m_sprites[6].x = SPRITE_X_POS(6); + m_sprites[7].x = SPRITE_X_POS(7); + } + break; + + case 0x17: /* sprite y size */ + if (m_reg[offset] != data) + { + m_reg[offset] = data; + } + break; + + case 0x1d: /* sprite x size */ + if (m_reg[offset] != data) + { + m_reg[offset] = data; + } + break; + + case 0x1b: /* sprite background priority */ + if (m_reg[offset] != data) + { + m_reg[offset] = data; + } + break; + + case 0x1c: /* sprite multicolor mode select */ + if (m_reg[offset] != data) + { + m_reg[offset] = data; + } + break; + + case 0x27: + case 0x28: + case 0x29: + case 0x2a: + case 0x2b: + case 0x2c: + case 0x2d: + case 0x2e: + /* sprite colors */ + if (m_reg[offset] != data) + { + m_reg[offset] = data; + } + break; + + case 0x25: /* sprite multicolor */ + if (m_reg[offset] != data) + { + m_reg[offset] = data; + m_spritemulti[1] = SPRITE_MULTICOLOR1; + } + break; + + case 0x26: /* sprite multicolor */ + if (m_reg[offset] != data) + { + m_reg[offset] = data; + m_spritemulti[3] = SPRITE_MULTICOLOR2; + } + break; + + case 0x19: + clear_interrupt(data & 0x0f); + break; + + case 0x1a: /* irq mask */ + m_reg[offset] = data; + set_interrupt(0); // beamrider needs this + break; + + case 0x11: + if (m_reg[offset] != data) + { + m_reg[offset] = data; + if (LINES25) + { + m_y_begin = 0; + m_y_end = m_y_begin + 200; + } + else + { + m_y_begin = 4; + m_y_end = m_y_begin + 192; + } + } + break; + + case 0x12: + if (data != m_reg[offset]) + { + m_reg[offset] = data; + } + break; + + case 0x16: + if (m_reg[offset] != data) + { + m_reg[offset] = data; + m_x_begin = HORIZONTALPOS; + m_x_end = m_x_begin + 320; + } + break; + + case 0x18: + if (m_reg[offset] != data) + { + m_reg[offset] = data; + m_videoaddr = VIDEOADDR; + m_chargenaddr = CHARGENADDR; + m_bitmapaddr = BITMAPADDR; + } + break; + + case 0x21: /* background color */ + if (m_reg[offset] != data) + { + m_reg[offset] = data; + m_mono[0] = m_bitmapmulti[0] = m_multi[0] = m_colors[0] = BACKGROUNDCOLOR; + } + break; + + case 0x22: /* background color 1 */ + if (m_reg[offset] != data) + { + m_reg[offset] = data; + m_multi[1] = m_colors[1] = MULTICOLOR1; + } + break; + + case 0x23: /* background color 2 */ + if (m_reg[offset] != data) + { + m_reg[offset] = data; + m_multi[2] = m_colors[2] = MULTICOLOR2; + } + break; + + case 0x24: /* background color 3 */ + if (m_reg[offset] != data) + { + m_reg[offset] = data; + m_colors[3] = FOREGROUNDCOLOR; + } + break; + + case 0x20: /* framecolor */ + if (m_reg[offset] != data) + { + m_reg[offset] = data; + } + break; + + case 0x2f: + DBG_LOG(2, "vic write", ("%.2x:%.2x\n", offset, data)); + m_reg[offset] = data; + break; + case 0x30: + m_reg[offset] = data; + if (!m_port_changed_cb.isnull()) + { + DBG_LOG(2, "vic write", ("%.2x:%.2x\n", offset, data)); + m_reg[offset] = data; + m_port_changed_cb((offs_t)0,data); + } + break; + case 0x31: + m_reg[offset] = data; + if (data & 0x40) + m_cpu->set_clock_scale(1.0); + else + m_cpu->set_clock_scale(1.0/3.5); + break; + 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: + m_reg[offset] = data; + DBG_LOG(2, "vic write", ("%.2x:%.2x\n", offset, data)); + break; + case 0x40: + case 0x41: + case 0x42: + case 0x43: + case 0x44: + case 0x45: + case 0x46: + case 0x47: + DBG_LOG(2, "vic plane write", ("%.2x:%.2x\n", offset, data)); + break; + default: + m_reg[offset] = data; + break; + } +} + +READ8_MEMBER( vic3_device::port_r ) +{ + int val = 0; + offset &= 0x7f; + + /* offsets 0x00 -> 0x2e coincide with VICII */ + switch (offset) + { + case 0x11: + val = (m_reg[offset] & ~0x80) | ((m_rasterline & 0x100) >> 1); + break; + + case 0x12: + val = m_rasterline & 0xff; + break; + + case 0x16: + val = m_reg[offset] | 0xc0; + break; + + case 0x18: + val = m_reg[offset] | 0x01; + break; + + case 0x19: /* interrupt flag register */ + /* vic2_clear_interrupt(0xf); */ + val = m_reg[offset] | 0x70; + break; + + case 0x1a: + val = m_reg[offset] | 0xf0; + break; + + case 0x1e: /* sprite to sprite collision detect */ + val = m_reg[offset]; + m_reg[offset] = 0; + clear_interrupt(4); + break; + + case 0x1f: /* sprite to background collision detect */ + val = m_reg[offset]; + m_reg[offset] = 0; + clear_interrupt(2); + break; + + case 0x20: + case 0x21: + case 0x22: + case 0x23: + case 0x24: + val = m_reg[offset]; + break; + + case 0x00: + case 0x01: + case 0x02: + case 0x03: + case 0x04: + case 0x05: + case 0x06: + case 0x07: + case 0x08: + case 0x09: + case 0x0a: + case 0x0b: + case 0x0c: + case 0x0d: + case 0x0e: + case 0x0f: + case 0x10: + case 0x17: + case 0x1b: + case 0x1c: + case 0x1d: + case 0x25: + case 0x26: + case 0x27: + case 0x28: + case 0x29: + case 0x2a: + case 0x2b: + case 0x2c: + case 0x2d: + case 0x2e: + val = m_reg[offset]; + break; + + case 0x2f: + case 0x30: + val = m_reg[offset]; + DBG_LOG(2, "vic read", ("%.2x:%.2x\n", offset, val)); + break; + 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: /* not used */ + val = m_reg[offset]; + DBG_LOG(2, "vic read", ("%.2x:%.2x\n", offset, val)); + break; + case 0x40: + case 0x41: + case 0x42: + case 0x43: + case 0x44: + case 0x45: + case 0x46: + case 0x47: + DBG_LOG(2, "vic3 plane read", ("%.2x:%.2x\n", offset, val)); + break; + default: + val = m_reg[offset]; + } + return val; +} + + +#define VIC3_MASK(M) \ + if (M) \ + { \ + if (M & 0x01) \ + colors[0] = m_c64_mem_r_cb(VIC3_ADDR(0) + offset); \ + if (M & 0x02) \ + colors[1] = m_c64_mem_r_cb(VIC3_ADDR(1) + offset) << 1; \ + if (M & 0x04) \ + colors[2] = m_c64_mem_r_cb(VIC3_ADDR(2) + offset) << 2; \ + if (M & 0x08) \ + colors[3] = m_c64_mem_r_cb(VIC3_ADDR(3) + offset) << 3; \ + if (M & 0x10) \ + colors[4] = m_c64_mem_r_cb(VIC3_ADDR(4) + offset) << 4; \ + if (M & 0x20) \ + colors[5] = m_c64_mem_r_cb(VIC3_ADDR(5) + offset) << 5; \ + if (M & 0x40) \ + colors[6] = m_c64_mem_r_cb(VIC3_ADDR(6) + offset) << 6; \ + if (M & 0x80) \ + colors[7] = m_c64_mem_r_cb(VIC3_ADDR(7) + offset) << 7; \ + for (i = 7; i >= 0; i--) \ + { \ + p = 0; \ + if (M & 0x01) \ + { \ + p = colors[0] & 0x01; \ + colors[0] >>= 1; \ + } \ + if (M & 0x02) \ + { \ + p |= colors[1] & 0x02; \ + colors[1] >>= 1; \ + } \ + if (M & 0x04) \ + { \ + p |= colors[2] & 0x04; \ + colors[2] >>= 1; \ + } \ + if (M & 0x08) \ + { \ + p |= colors[3] & 0x08; \ + colors[3] >>= 1; \ + } \ + if (M & 0x10) \ + { \ + p |= colors[4] & 0x10; \ + colors[4] >>= 1; \ + } \ + if (M & 0x20) \ + { \ + p |= colors[5] & 0x20; \ + colors[5] >>= 1; \ + } \ + if (M & 0x40) \ + { \ + p |= colors[6] & 0x40; \ + colors[6] >>= 1; \ + } \ + if (M & 0x80) \ + { \ + p |= colors[7] & 0x80; \ + colors[7] >>= 1; \ + } \ + m_bitmap->pix16(YPOS + y, XPOS + x + i) = p; \ + } \ + } + +#define VIC3_ADDR(a) VIC3_BITPLANE_IADDR(a) +void vic3_device::interlace_draw_block( int x, int y, int offset ) +{ + int colors[8] = {0}; + int i, p; + + switch (VIC3_BITPLANES_MASK) + { + case 0x05: + VIC3_MASK(0x05) + break; + case 0x07: + VIC3_MASK(0x07) + break; + case 0x0f: + VIC3_MASK(0x0f) + break; + case 0x1f: + VIC3_MASK(0x1f) + break; + case 0x7f: + VIC3_MASK(0x7f) + break; + case 0xff: + VIC3_MASK(0xff) + break; + default: + if (VIC3_BITPLANES_MASK & 0x01) + colors[0] = m_c64_mem_r_cb(VIC3_BITPLANE_IADDR(0) + offset); + + if (VIC3_BITPLANES_MASK & 0x02) + colors[1] = m_c64_mem_r_cb(VIC3_BITPLANE_IADDR(1) + offset) << 1; + + if (VIC3_BITPLANES_MASK & 0x04) + colors[2] = m_c64_mem_r_cb(VIC3_BITPLANE_IADDR(2) + offset) << 2; + + if (VIC3_BITPLANES_MASK & 0x08) + colors[3] = m_c64_mem_r_cb(VIC3_BITPLANE_IADDR(3) + offset) << 3; + + if (VIC3_BITPLANES_MASK & 0x10) + colors[4] = m_c64_mem_r_cb(VIC3_BITPLANE_IADDR(4) + offset) << 4; + + if (VIC3_BITPLANES_MASK & 0x20) + colors[5] = m_c64_mem_r_cb(VIC3_BITPLANE_IADDR(5) + offset) << 5; + + if (VIC3_BITPLANES_MASK & 0x40) + colors[6] = m_c64_mem_r_cb(VIC3_BITPLANE_IADDR(6) + offset) << 6; + + if (VIC3_BITPLANES_MASK & 0x80) + colors[7] = m_c64_mem_r_cb(VIC3_BITPLANE_IADDR(7) + offset) << 7; + + for (i = 7; i >= 0; i--) + { + m_bitmap->pix16(YPOS + y, XPOS + x + i) = + (colors[0] & 0x01) | (colors[1] & 0x02) + | (colors[2] & 0x04) | (colors[3] & 0x08) + | (colors[4] & 0x10) | (colors[5] & 0x20) + | (colors[6] & 0x40) | (colors[7] & 0x80); + colors[0] >>= 1; + colors[1] >>= 1; + colors[2] >>= 1; + colors[3] >>= 1; + colors[4] >>= 1; + colors[5] >>= 1; + colors[6] >>= 1; + colors[7] >>= 1; + } + } +} + +#undef VIC3_ADDR +#define VIC3_ADDR(a) VIC3_BITPLANE_ADDR(a) +void vic3_device::draw_block( int x, int y, int offset ) +{ + int colors[8] = {0}; + int i, p; + + switch (VIC3_BITPLANES_MASK) + { + case 5: + VIC3_MASK(0x05) + break; + case 7: + VIC3_MASK(0x07) + break; + case 0xf: + VIC3_MASK(0x0f) + break; + case 0x1f: + VIC3_MASK(0x1f) + break; + case 0x7f: + VIC3_MASK(0x7f) + break; + case 0xff: + VIC3_MASK(0xff) + break; + default: + if (VIC3_BITPLANES_MASK & 0x01) + colors[0] = m_c64_mem_r_cb(VIC3_BITPLANE_ADDR(0) + offset); + + if (VIC3_BITPLANES_MASK & 0x02) + colors[1] = m_c64_mem_r_cb(VIC3_BITPLANE_ADDR(1) + offset) << 1; + + if (VIC3_BITPLANES_MASK & 0x04) + colors[2] = m_c64_mem_r_cb(VIC3_BITPLANE_ADDR(2) + offset) << 2; + + if (VIC3_BITPLANES_MASK & 0x08) + colors[3] = m_c64_mem_r_cb(VIC3_BITPLANE_ADDR(3) + offset) << 3; + + if (VIC3_BITPLANES_MASK & 0x10) + colors[4] = m_c64_mem_r_cb(VIC3_BITPLANE_ADDR(4) + offset) << 4; + + if (VIC3_BITPLANES_MASK & 0x20) + colors[5] = m_c64_mem_r_cb(VIC3_BITPLANE_ADDR(5) + offset) << 5; + + if (VIC3_BITPLANES_MASK & 0x40) + colors[6] = m_c64_mem_r_cb(VIC3_BITPLANE_ADDR(6) + offset) << 6; + + if (VIC3_BITPLANES_MASK & 0x80) + colors[7] = m_c64_mem_r_cb(VIC3_BITPLANE_ADDR(7) + offset) << 7; + + for (i = 7; i >= 0; i--) + { + m_bitmap->pix16(YPOS + y, XPOS + x + i) = + (colors[0] & 0x01) | (colors[1] & 0x02) + | (colors[2] & 0x04) | (colors[3] & 0x08) + | (colors[4] & 0x10) | (colors[5] & 0x20) + | (colors[6] & 0x40) | (colors[7] & 0x80); + colors[0] >>= 1; + colors[1] >>= 1; + colors[2] >>= 1; + colors[3] >>= 1; + colors[4] >>= 1; + colors[5] >>= 1; + colors[6] >>= 1; + colors[7] >>= 1; + } + } +} + + +void vic3_device::draw_bitplanes() +{ + int x, y, y1s, offset; + rectangle vis; + const rectangle &visarea = m_screen->visible_area(); + + if (VIC3_LINES == 400) + { /* interlaced! */ + for (y1s = 0, offset = 0; y1s < 400; y1s += 16) + { + for (x = 0; x < VIC3_BITPLANES_WIDTH; x += 8) + { + for (y = y1s; y < y1s + 16; y += 2, offset++) + { + if (m_interlace) + draw_block(x, y, offset); + else + interlace_draw_block(x, y + 1, offset); + } + } + } + m_interlace ^= 1; + } + else + { + for (y1s = 0, offset = 0; y1s < 200; y1s += 8) + { + for (x = 0; x < VIC3_BITPLANES_WIDTH; x += 8) + { + for (y = y1s; y < y1s + 8; y++, offset++) + { + draw_block(x, y, offset); + } + } + } + } + + if (XPOS > 0) + { + vis.set(0, XPOS - 1, 0, visarea.max_y); + m_bitmap->fill(FRAMECOLOR, vis); + } + + if (XPOS + VIC3_BITPLANES_WIDTH < visarea.max_x) + { + vis.set(XPOS + VIC3_BITPLANES_WIDTH, visarea.max_x, 0, visarea.max_y); + m_bitmap->fill(FRAMECOLOR, vis); + } + + if (YPOS > 0) + { + vis.set(0, visarea.max_x, 0, YPOS - 1); + m_bitmap->fill(FRAMECOLOR, vis); + } + + if (YPOS + VIC3_LINES < visarea.max_y) + { + vis.set(0, visarea.max_x, YPOS + VIC3_LINES, visarea.max_y); + m_bitmap->fill(FRAMECOLOR, vis); + } +} + +void vic3_device::raster_interrupt_gen() +{ + int new_columns, new_rows; + int i; + + m_rasterline++; + if (m_rasterline >= m_lines) + { + m_rasterline = 0; + if (m_palette_dirty) + for (i = 0; i < 256; i++) + m_palette->set_pen_color(i, m_palette_red[i] << 4, m_palette_green[i] << 4, m_palette_blue[i] << 4); + + if (m_palette_dirty) + { + m_spritemulti[1] = SPRITE_MULTICOLOR1; + m_spritemulti[3] = SPRITE_MULTICOLOR2; + m_mono[0] = m_bitmapmulti[0] = m_multi[0] = m_colors[0] = BACKGROUNDCOLOR; + m_multi[1] = m_colors[1] = MULTICOLOR1; + m_multi[2] = m_colors[2] = MULTICOLOR2; + m_colors[3] = FOREGROUNDCOLOR; + m_palette_dirty = 0; + } + + new_rows = 200; + + if (VIC3_BITPLANES) + { + new_columns = VIC3_BITPLANES_WIDTH; + if (new_columns < 320) + new_columns = 320; /*sprites resolution about 320x200 */ + new_rows = VIC3_LINES; + } + else if (VIC3_80COLUMNS) + { + new_columns = 640; + } + else + { + new_columns = 320; + } + if ((new_columns != m_columns) || (new_rows != m_rows)) + { + m_rows = new_rows; + m_columns = new_columns; + if (m_type == VIC4567_PAL) + m_screen->set_visible_area( + VIC2_STARTVISIBLECOLUMNS + 32, + VIC2_STARTVISIBLECOLUMNS + 32 + m_columns + 16 - 1, + VIC2_STARTVISIBLELINES + 34, + VIC2_STARTVISIBLELINES + 34 + m_rows + 16 - 1); + else + m_screen->set_visible_area( + VIC2_STARTVISIBLECOLUMNS + 34, + VIC2_STARTVISIBLECOLUMNS + 34 + m_columns + 16 - 1, + VIC2_STARTVISIBLELINES + 10, + VIC2_STARTVISIBLELINES + 10 + m_rows + 16 - 1); + } + if (VIC3_BITPLANES) + { + draw_bitplanes(); + } + else + { + if (m_type == VIC4567_PAL) + { + if (m_on) + vic2_drawlines(m_lastline, m_lines, VIC2_STARTVISIBLECOLUMNS + 32, VIC2_STARTVISIBLECOLUMNS + 32 + m_columns + 16 - 1); + } + else + { + if (m_on) + vic2_drawlines(m_lastline, m_lines, VIC2_STARTVISIBLECOLUMNS + 34, VIC2_STARTVISIBLECOLUMNS + 34 + m_columns + 16 - 1); + } + } + + for (i = 0; i < 8; i++) + m_sprites[i].repeat = m_sprites[i].line = 0; + + m_lastline = 0; + + if (LIGHTPEN_BUTTON) + { + /* lightpen timer start */ + machine().scheduler().timer_set(attotime(0, 0), timer_expired_delegate(FUNC(vic3_device::timer_timeout),this), 1); + } + + } + + if (m_rasterline == C64_2_RASTERLINE(RASTERLINE)) + { + set_interrupt(1); + } + + if (m_on) + if ((m_rasterline >= VIC2_FIRSTRASTERLINE) && (m_rasterline < (VIC2_FIRSTRASTERLINE + VIC2_VISIBLELINES))) + { + if (m_type == VIC4567_PAL) + { + if (m_on) + vic2_drawlines(m_rasterline - 1, m_rasterline, VIC2_STARTVISIBLECOLUMNS + 32, VIC2_STARTVISIBLECOLUMNS + 32 + m_columns + 16 - 1); + } + else + { + if (m_on) + vic2_drawlines(m_rasterline - 1, m_rasterline, VIC2_STARTVISIBLECOLUMNS + 34, VIC2_STARTVISIBLECOLUMNS + 34 + m_columns + 16 - 1); + } + } +} + +UINT32 vic3_device::video_update( bitmap_ind16 &bitmap, const rectangle &cliprect ) +{ + copybitmap(bitmap, *m_bitmap, 0, 0, 0, 0, cliprect); + return 0; +} + + +static MACHINE_CONFIG_FRAGMENT( vic3 ) + MCFG_PALETTE_ADD_INIT_BLACK("palette", 0x100) +MACHINE_CONFIG_END + +//------------------------------------------------- +// machine_config_additions - return a pointer to +// the device's machine fragment +//------------------------------------------------- + +machine_config_constructor vic3_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( vic3 ); +} diff --git a/src/devices/video/vic4567.h b/src/devices/video/vic4567.h new file mode 100644 index 00000000000..41d385397fa --- /dev/null +++ b/src/devices/video/vic4567.h @@ -0,0 +1,273 @@ +// license:BSD-3-Clause +// copyright-holders:Peter Trauner +/***************************************************************************** + * + * video/vic4567.h + * + ****************************************************************************/ + +#ifndef __VIC4567_H__ +#define __VIC4567_H__ + + +/*************************************************************************** + TYPE DEFINITIONS +***************************************************************************/ + +enum vic3_type +{ + VIC4567_NTSC, + VIC4567_PAL +}; + +#define SPRITE_BASE_X_SIZE 24 +#define SPRITE_BASE_Y_SIZE 21 + +struct vic3_sprite +{ + int x, y; + + int repeat; /* expand, line once drawn */ + int line; /* 0 not painting, else painting */ + + /* buffer for currently painted line */ + int paintedline[8]; + UINT8 bitmap[8][SPRITE_BASE_X_SIZE * 2 / 8 + 1 /*for simplier sprite collision detection*/]; +}; + + +/*************************************************************************** + CONSTANTS +***************************************************************************/ + +#define VIC6567_CLOCK (1022700 /* = 8181600 / 8) */ ) +#define VIC6569_CLOCK ( 985248 /* = 7881984 / 8) */ ) + +#define VIC6567_CYCLESPERLINE 65 +#define VIC6569_CYCLESPERLINE 63 + +#define VIC6567_LINES 263 +#define VIC6569_LINES 312 + +#define VIC6567_VRETRACERATE (59.8245100906698 /* = 1022700 / (65 * 263) */ ) +#define VIC6569_VRETRACERATE (50.1245421245421 /* = 985248 / (63 * 312) */ ) + +#define VIC6567_HRETRACERATE (VIC6567_CLOCK / VIC6567_CYCLESPERLINE) +#define VIC6569_HRETRACERATE (VIC6569_CLOCK / VIC6569_CYCLESPERLINE) + +#define VIC2_HSIZE 320 +#define VIC2_VSIZE 200 + +#define VIC6567_VISIBLELINES 235 +#define VIC6569_VISIBLELINES 284 + +#define VIC6567_FIRST_DMA_LINE 0x30 +#define VIC6569_FIRST_DMA_LINE 0x30 + +#define VIC6567_LAST_DMA_LINE 0xf7 +#define VIC6569_LAST_DMA_LINE 0xf7 + +#define VIC6567_FIRST_DISP_LINE 0x29 +#define VIC6569_FIRST_DISP_LINE 0x10 + +#define VIC6567_LAST_DISP_LINE (VIC6567_FIRST_DISP_LINE + VIC6567_VISIBLELINES - 1) +#define VIC6569_LAST_DISP_LINE (VIC6569_FIRST_DISP_LINE + VIC6569_VISIBLELINES - 1) + +#define VIC6567_RASTER_2_EMU(a) ((a >= VIC6567_FIRST_DISP_LINE) ? (a - VIC6567_FIRST_DISP_LINE) : (a + 222)) +#define VIC6569_RASTER_2_EMU(a) (a - VIC6569_FIRST_DISP_LINE) + +#define VIC6567_FIRSTCOLUMN 50 +#define VIC6569_FIRSTCOLUMN 50 + +#define VIC6567_VISIBLECOLUMNS 418 +#define VIC6569_VISIBLECOLUMNS 403 + +#define VIC6567_X_2_EMU(a) (a) +#define VIC6569_X_2_EMU(a) (a) + +#define VIC6567_STARTVISIBLELINES ((VIC6567_LINES - VIC6567_VISIBLELINES)/2) +#define VIC6569_STARTVISIBLELINES 16 /* ((VIC6569_LINES - VIC6569_VISIBLELINES)/2) */ + +#define VIC6567_FIRSTRASTERLINE 34 +#define VIC6569_FIRSTRASTERLINE 0 + +#define VIC6567_COLUMNS 512 +#define VIC6569_COLUMNS 504 + + +#define VIC6567_STARTVISIBLECOLUMNS ((VIC6567_COLUMNS - VIC6567_VISIBLECOLUMNS)/2) +#define VIC6569_STARTVISIBLECOLUMNS ((VIC6569_COLUMNS - VIC6569_VISIBLECOLUMNS)/2) + +#define VIC6567_FIRSTRASTERCOLUMNS 412 +#define VIC6569_FIRSTRASTERCOLUMNS 404 + +#define VIC6569_FIRST_X 0x194 +#define VIC6567_FIRST_X 0x19c + +#define VIC6569_FIRST_VISIBLE_X 0x1e0 +#define VIC6567_FIRST_VISIBLE_X 0x1e8 + +#define VIC6569_MAX_X 0x1f7 +#define VIC6567_MAX_X 0x1ff + +#define VIC6569_LAST_VISIBLE_X 0x17c +#define VIC6567_LAST_VISIBLE_X 0x184 + +#define VIC6569_LAST_X 0x193 +#define VIC6567_LAST_X 0x19b + +/*************************************************************************** + DEVICE CONFIGURATION MACROS +***************************************************************************/ + +class vic3_device : public device_t, + public device_video_interface +{ +public: + vic3_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + ~vic3_device() {} + + static void static_set_cpu_tag(device_t &device, const char *tag) { downcast(device).m_cpu.set_tag(tag); } + static void set_vic3_type(device_t &device, vic3_type type) { downcast(device).m_type = type; } + template static devcb_base &set_dma_read_callback(device_t &device, _Object object) { return downcast(device).m_dma_read_cb.set_callback(object); } + template static devcb_base &set_dma_read_color_callback(device_t &device, _Object object) { return downcast(device).m_dma_read_color_cb.set_callback(object); } + template static devcb_base &set_interrupt_callback(device_t &device, _Object object) { return downcast(device).m_interrupt_cb.set_callback(object); } + template static devcb_base &set_port_changed_callback(device_t &device, _Object object) { return downcast(device).m_port_changed_cb.set_callback(object); } + template static devcb_base &set_lightpen_button_callback(device_t &device, _Object object) { return downcast(device).m_lightpen_button_cb.set_callback(object); } + template static devcb_base &set_lightpen_x_callback(device_t &device, _Object object) { return downcast(device).m_lightpen_x_cb.set_callback(object); } + template static devcb_base &set_lightpen_y_callback(device_t &device, _Object object) { return downcast(device).m_lightpen_y_cb.set_callback(object); } + template static devcb_base &set_c64_mem_r_callback(device_t &device, _Object object) { return downcast(device).m_c64_mem_r_cb.set_callback(object); } + + DECLARE_WRITE8_MEMBER(port_w); + DECLARE_WRITE8_MEMBER(palette_w); + DECLARE_READ8_MEMBER(port_r); + + void raster_interrupt_gen(); + UINT32 video_update(bitmap_ind16 &bitmap, const rectangle &cliprect); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual machine_config_constructor device_mconfig_additions() const; +private: + // internal state + + inline int getforeground(int y, int x); + inline int getforeground16(int y, int x); + void set_interrupt(int mask); + void clear_interrupt(int mask); + void draw_character(int ybegin, int yend, int ch, int yoff, int xoff, UINT16 *color, int start_x, int end_x); + void draw_character_multi(int ybegin, int yend, int ch, int yoff, int xoff, int start_x, int end_x); + void draw_bitmap(int ybegin, int yend, int ch, int yoff, int xoff, int start_x, int end_x); + void draw_bitmap_multi(int ybegin, int yend, int ch, int yoff, int xoff, int start_x, int end_x); + void draw_sprite_code(int y, int xbegin, int code, int color, int start_x, int end_x); + void draw_sprite_code_multi(int y, int xbegin, int code, int prior, int start_x, int end_x); + void sprite_collision(int nr, int y, int x, int mask); + void draw_sprite(int nr, int yoff, int ybegin, int yend, int start_x, int end_x); + void draw_sprite_multi(int nr, int yoff, int ybegin, int yend, int start_x, int end_x); + void drawlines(int first, int last, int start_x, int end_x); + void vic2_drawlines(int first, int last, int start_x, int end_x); + void interlace_draw_block(int x, int y, int offset); + void draw_block(int x, int y, int offset); + void draw_bitplanes(); + + TIMER_CALLBACK_MEMBER(timer_timeout); + + vic3_type m_type; + + required_device m_cpu; + + UINT8 m_reg[0x80]; + int m_on; /* rastering of the screen */ + + int m_lines; + + UINT16 m_chargenaddr, m_videoaddr, m_bitmapaddr; + + bitmap_ind16 *m_bitmap; + int m_x_begin, m_x_end; + int m_y_begin, m_y_end; + + UINT16 m_c64_bitmap[2], m_bitmapmulti[4], m_mono[2], m_multi[4], m_ecmcolor[2], m_colors[4], m_spritemulti[4]; + + int m_lastline, m_rasterline; + + int m_interlace; + int m_columns, m_rows; + + /* background/foreground for sprite collision */ + UINT8 *m_screenptr[216], m_shift[216]; + + /* convert multicolor byte to background/foreground for sprite collision */ + UINT8 m_foreground[256]; + UINT16 m_expandx[256]; + UINT16 m_expandx_multi[256]; + + /* converts sprite multicolor info to info for background collision checking */ + UINT8 m_multi_collision[256]; + + vic3_sprite m_sprites[8]; + + /* DMA */ + devcb_read8 m_dma_read_cb; + devcb_read8 m_dma_read_color_cb; + + /* IRQ */ + devcb_write_line m_interrupt_cb; + + /* Port Changed */ + devcb_write8 m_port_changed_cb; + + /* lightpen */ + devcb_read8 m_lightpen_button_cb; + devcb_read8 m_lightpen_x_cb; + devcb_read8 m_lightpen_y_cb; + + /* C64 memory access */ + devcb_read8 m_c64_mem_r_cb; + + /* palette - vic3 specific items (the ones above are used for VIC II as well) */ + UINT8 m_palette_red[0x100]; + UINT8 m_palette_green[0x100]; + UINT8 m_palette_blue[0x100]; + int m_palette_dirty; + + required_device m_palette; +}; + +extern const device_type VIC3; + + +#define MCFG_VIC3_CPU(_tag) \ + vic3_device::static_set_cpu_tag(*device, "^" _tag); + +#define MCFG_VIC3_TYPE(_type) \ + vic3_device::set_vic3_type(*device, _type); + +#define MCFG_VIC3_DMA_READ_CB(_devcb) \ + devcb = &vic3_device::set_dma_read_callback(*device, DEVCB_##_devcb); + +#define MCFG_VIC3_DMA_READ_COLOR_CB(_devcb) \ + devcb = &vic3_device::set_dma_read_color_callback(*device, DEVCB_##_devcb); + +#define MCFG_VIC3_INTERRUPT_CB(_devcb) \ + devcb = &vic3_device::set_interrupt_callback(*device, DEVCB_##_devcb); + +#define MCFG_VIC3_PORT_CHANGED_CB(_devcb) \ + devcb = &vic3_device::set_port_changed_callback(*device, DEVCB_##_devcb); + +#define MCFG_VIC3_LIGHTPEN_BUTTON_CB(_devcb) \ + devcb = &vic3_device::set_lightpen_button_callback(*device, DEVCB_##_devcb); + +#define MCFG_VIC3_LIGHTPEN_X_CB(_devcb) \ + devcb = &vic3_device::set_lightpen_x_callback(*device, DEVCB_##_devcb); + +#define MCFG_VIC3_LIGHTPEN_Y_CB(_devcb) \ + devcb = &vic3_device::set_lightpen_y_callback(*device, DEVCB_##_devcb); + +#define MCFG_VIC3_C64_MEM_R_CB(_devcb) \ + devcb = &vic3_device::set_c64_mem_r_callback(*device, DEVCB_##_devcb); + + +#endif /* __VIC4567_H__ */ diff --git a/src/devices/video/vooddefs.h b/src/devices/video/vooddefs.h new file mode 100644 index 00000000000..f98aece2110 --- /dev/null +++ b/src/devices/video/vooddefs.h @@ -0,0 +1,5099 @@ + // license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + vooddefs.h + + 3dfx Voodoo Graphics SST-1/2 emulator. + +***************************************************************************/ + + +/************************************* + * + * Misc. constants + * + *************************************/ + +/* enumeration describing reasons we might be stalled */ +enum +{ + NOT_STALLED = 0, + STALLED_UNTIL_FIFO_LWM, + STALLED_UNTIL_FIFO_EMPTY +}; + +// Use old macro style or newer SSE2 optimized functions +#define USE_OLD_RASTER 0 + +// Use old table lookup versus straight double divide +#define USE_FAST_RECIP 0 + +/* maximum number of TMUs */ +#define MAX_TMU 2 + +/* accumulate operations less than this number of clocks */ +#define ACCUMULATE_THRESHOLD 0 + +/* number of clocks to set up a triangle (just a guess) */ +#define TRIANGLE_SETUP_CLOCKS 100 + +/* maximum number of rasterizers */ +#define MAX_RASTERIZERS 1024 + +/* size of the rasterizer hash table */ +#define RASTER_HASH_SIZE 97 + +/* flags for LFB writes */ +#define LFB_RGB_PRESENT 1 +#define LFB_ALPHA_PRESENT 2 +#define LFB_DEPTH_PRESENT 4 +#define LFB_DEPTH_PRESENT_MSW 8 + +/* flags for the register access array */ +#define REGISTER_READ 0x01 /* reads are allowed */ +#define REGISTER_WRITE 0x02 /* writes are allowed */ +#define REGISTER_PIPELINED 0x04 /* writes are pipelined */ +#define REGISTER_FIFO 0x08 /* writes go to FIFO */ +#define REGISTER_WRITETHRU 0x10 /* writes are valid even for CMDFIFO */ + +/* shorter combinations to make the table smaller */ +#define REG_R (REGISTER_READ) +#define REG_W (REGISTER_WRITE) +#define REG_WT (REGISTER_WRITE | REGISTER_WRITETHRU) +#define REG_RW (REGISTER_READ | REGISTER_WRITE) +#define REG_RWT (REGISTER_READ | REGISTER_WRITE | REGISTER_WRITETHRU) +#define REG_RP (REGISTER_READ | REGISTER_PIPELINED) +#define REG_WP (REGISTER_WRITE | REGISTER_PIPELINED) +#define REG_RWP (REGISTER_READ | REGISTER_WRITE | REGISTER_PIPELINED) +#define REG_RWPT (REGISTER_READ | REGISTER_WRITE | REGISTER_PIPELINED | REGISTER_WRITETHRU) +#define REG_RF (REGISTER_READ | REGISTER_FIFO) +#define REG_WF (REGISTER_WRITE | REGISTER_FIFO) +#define REG_RWF (REGISTER_READ | REGISTER_WRITE | REGISTER_FIFO) +#define REG_RPF (REGISTER_READ | REGISTER_PIPELINED | REGISTER_FIFO) +#define REG_WPF (REGISTER_WRITE | REGISTER_PIPELINED | REGISTER_FIFO) +#define REG_RWPF (REGISTER_READ | REGISTER_WRITE | REGISTER_PIPELINED | REGISTER_FIFO) + +/* lookup bits is the log2 of the size of the reciprocal/log table */ +#define RECIPLOG_LOOKUP_BITS 9 + +/* input precision is how many fraction bits the input value has; this is a 64-bit number */ +#define RECIPLOG_INPUT_PREC 32 + +/* lookup precision is how many fraction bits each table entry contains */ +#define RECIPLOG_LOOKUP_PREC 22 + +/* output precision is how many fraction bits the result should have */ +#define RECIP_OUTPUT_PREC 15 +#define LOG_OUTPUT_PREC 8 + + + +/************************************* + * + * Register constants + * + *************************************/ + +/* Codes to the right: + R = readable + W = writeable + P = pipelined + F = goes to FIFO +*/ + +/* 0x000 */ +#define status (0x000/4) /* R P */ +#define intrCtrl (0x004/4) /* RW P -- Voodoo2/Banshee only */ +#define vertexAx (0x008/4) /* W PF */ +#define vertexAy (0x00c/4) /* W PF */ +#define vertexBx (0x010/4) /* W PF */ +#define vertexBy (0x014/4) /* W PF */ +#define vertexCx (0x018/4) /* W PF */ +#define vertexCy (0x01c/4) /* W PF */ +#define startR (0x020/4) /* W PF */ +#define startG (0x024/4) /* W PF */ +#define startB (0x028/4) /* W PF */ +#define startZ (0x02c/4) /* W PF */ +#define startA (0x030/4) /* W PF */ +#define startS (0x034/4) /* W PF */ +#define startT (0x038/4) /* W PF */ +#define startW (0x03c/4) /* W PF */ + +/* 0x040 */ +#define dRdX (0x040/4) /* W PF */ +#define dGdX (0x044/4) /* W PF */ +#define dBdX (0x048/4) /* W PF */ +#define dZdX (0x04c/4) /* W PF */ +#define dAdX (0x050/4) /* W PF */ +#define dSdX (0x054/4) /* W PF */ +#define dTdX (0x058/4) /* W PF */ +#define dWdX (0x05c/4) /* W PF */ +#define dRdY (0x060/4) /* W PF */ +#define dGdY (0x064/4) /* W PF */ +#define dBdY (0x068/4) /* W PF */ +#define dZdY (0x06c/4) /* W PF */ +#define dAdY (0x070/4) /* W PF */ +#define dSdY (0x074/4) /* W PF */ +#define dTdY (0x078/4) /* W PF */ +#define dWdY (0x07c/4) /* W PF */ + +/* 0x080 */ +#define triangleCMD (0x080/4) /* W PF */ +#define fvertexAx (0x088/4) /* W PF */ +#define fvertexAy (0x08c/4) /* W PF */ +#define fvertexBx (0x090/4) /* W PF */ +#define fvertexBy (0x094/4) /* W PF */ +#define fvertexCx (0x098/4) /* W PF */ +#define fvertexCy (0x09c/4) /* W PF */ +#define fstartR (0x0a0/4) /* W PF */ +#define fstartG (0x0a4/4) /* W PF */ +#define fstartB (0x0a8/4) /* W PF */ +#define fstartZ (0x0ac/4) /* W PF */ +#define fstartA (0x0b0/4) /* W PF */ +#define fstartS (0x0b4/4) /* W PF */ +#define fstartT (0x0b8/4) /* W PF */ +#define fstartW (0x0bc/4) /* W PF */ + +/* 0x0c0 */ +#define fdRdX (0x0c0/4) /* W PF */ +#define fdGdX (0x0c4/4) /* W PF */ +#define fdBdX (0x0c8/4) /* W PF */ +#define fdZdX (0x0cc/4) /* W PF */ +#define fdAdX (0x0d0/4) /* W PF */ +#define fdSdX (0x0d4/4) /* W PF */ +#define fdTdX (0x0d8/4) /* W PF */ +#define fdWdX (0x0dc/4) /* W PF */ +#define fdRdY (0x0e0/4) /* W PF */ +#define fdGdY (0x0e4/4) /* W PF */ +#define fdBdY (0x0e8/4) /* W PF */ +#define fdZdY (0x0ec/4) /* W PF */ +#define fdAdY (0x0f0/4) /* W PF */ +#define fdSdY (0x0f4/4) /* W PF */ +#define fdTdY (0x0f8/4) /* W PF */ +#define fdWdY (0x0fc/4) /* W PF */ + +/* 0x100 */ +#define ftriangleCMD (0x100/4) /* W PF */ +#define fbzColorPath (0x104/4) /* RW PF */ +#define fogMode (0x108/4) /* RW PF */ +#define alphaMode (0x10c/4) /* RW PF */ +#define fbzMode (0x110/4) /* RW F */ +#define lfbMode (0x114/4) /* RW F */ +#define clipLeftRight (0x118/4) /* RW F */ +#define clipLowYHighY (0x11c/4) /* RW F */ +#define nopCMD (0x120/4) /* W F */ +#define fastfillCMD (0x124/4) /* W F */ +#define swapbufferCMD (0x128/4) /* W F */ +#define fogColor (0x12c/4) /* W F */ +#define zaColor (0x130/4) /* W F */ +#define chromaKey (0x134/4) /* W F */ +#define chromaRange (0x138/4) /* W F -- Voodoo2/Banshee only */ +#define userIntrCMD (0x13c/4) /* W F -- Voodoo2/Banshee only */ + +/* 0x140 */ +#define stipple (0x140/4) /* RW F */ +#define color0 (0x144/4) /* RW F */ +#define color1 (0x148/4) /* RW F */ +#define fbiPixelsIn (0x14c/4) /* R */ +#define fbiChromaFail (0x150/4) /* R */ +#define fbiZfuncFail (0x154/4) /* R */ +#define fbiAfuncFail (0x158/4) /* R */ +#define fbiPixelsOut (0x15c/4) /* R */ +#define fogTable (0x160/4) /* W F */ + +/* 0x1c0 */ +#define cmdFifoBaseAddr (0x1e0/4) /* RW -- Voodoo2 only */ +#define cmdFifoBump (0x1e4/4) /* RW -- Voodoo2 only */ +#define cmdFifoRdPtr (0x1e8/4) /* RW -- Voodoo2 only */ +#define cmdFifoAMin (0x1ec/4) /* RW -- Voodoo2 only */ +#define colBufferAddr (0x1ec/4) /* RW -- Banshee only */ +#define cmdFifoAMax (0x1f0/4) /* RW -- Voodoo2 only */ +#define colBufferStride (0x1f0/4) /* RW -- Banshee only */ +#define cmdFifoDepth (0x1f4/4) /* RW -- Voodoo2 only */ +#define auxBufferAddr (0x1f4/4) /* RW -- Banshee only */ +#define cmdFifoHoles (0x1f8/4) /* RW -- Voodoo2 only */ +#define auxBufferStride (0x1f8/4) /* RW -- Banshee only */ + +/* 0x200 */ +#define fbiInit4 (0x200/4) /* RW -- Voodoo/Voodoo2 only */ +#define clipLeftRight1 (0x200/4) /* RW -- Banshee only */ +#define vRetrace (0x204/4) /* R -- Voodoo/Voodoo2 only */ +#define clipTopBottom1 (0x204/4) /* RW -- Banshee only */ +#define backPorch (0x208/4) /* RW -- Voodoo/Voodoo2 only */ +#define videoDimensions (0x20c/4) /* RW -- Voodoo/Voodoo2 only */ +#define fbiInit0 (0x210/4) /* RW -- Voodoo/Voodoo2 only */ +#define fbiInit1 (0x214/4) /* RW -- Voodoo/Voodoo2 only */ +#define fbiInit2 (0x218/4) /* RW -- Voodoo/Voodoo2 only */ +#define fbiInit3 (0x21c/4) /* RW -- Voodoo/Voodoo2 only */ +#define hSync (0x220/4) /* W -- Voodoo/Voodoo2 only */ +#define vSync (0x224/4) /* W -- Voodoo/Voodoo2 only */ +#define clutData (0x228/4) /* W F -- Voodoo/Voodoo2 only */ +#define dacData (0x22c/4) /* W -- Voodoo/Voodoo2 only */ +#define maxRgbDelta (0x230/4) /* W -- Voodoo/Voodoo2 only */ +#define hBorder (0x234/4) /* W -- Voodoo2 only */ +#define vBorder (0x238/4) /* W -- Voodoo2 only */ +#define borderColor (0x23c/4) /* W -- Voodoo2 only */ + +/* 0x240 */ +#define hvRetrace (0x240/4) /* R -- Voodoo2 only */ +#define fbiInit5 (0x244/4) /* RW -- Voodoo2 only */ +#define fbiInit6 (0x248/4) /* RW -- Voodoo2 only */ +#define fbiInit7 (0x24c/4) /* RW -- Voodoo2 only */ +#define swapPending (0x24c/4) /* W -- Banshee only */ +#define leftOverlayBuf (0x250/4) /* W -- Banshee only */ +#define rightOverlayBuf (0x254/4) /* W -- Banshee only */ +#define fbiSwapHistory (0x258/4) /* R -- Voodoo2/Banshee only */ +#define fbiTrianglesOut (0x25c/4) /* R -- Voodoo2/Banshee only */ +#define sSetupMode (0x260/4) /* W PF -- Voodoo2/Banshee only */ +#define sVx (0x264/4) /* W PF -- Voodoo2/Banshee only */ +#define sVy (0x268/4) /* W PF -- Voodoo2/Banshee only */ +#define sARGB (0x26c/4) /* W PF -- Voodoo2/Banshee only */ +#define sRed (0x270/4) /* W PF -- Voodoo2/Banshee only */ +#define sGreen (0x274/4) /* W PF -- Voodoo2/Banshee only */ +#define sBlue (0x278/4) /* W PF -- Voodoo2/Banshee only */ +#define sAlpha (0x27c/4) /* W PF -- Voodoo2/Banshee only */ + +/* 0x280 */ +#define sVz (0x280/4) /* W PF -- Voodoo2/Banshee only */ +#define sWb (0x284/4) /* W PF -- Voodoo2/Banshee only */ +#define sWtmu0 (0x288/4) /* W PF -- Voodoo2/Banshee only */ +#define sS_W0 (0x28c/4) /* W PF -- Voodoo2/Banshee only */ +#define sT_W0 (0x290/4) /* W PF -- Voodoo2/Banshee only */ +#define sWtmu1 (0x294/4) /* W PF -- Voodoo2/Banshee only */ +#define sS_Wtmu1 (0x298/4) /* W PF -- Voodoo2/Banshee only */ +#define sT_Wtmu1 (0x29c/4) /* W PF -- Voodoo2/Banshee only */ +#define sDrawTriCMD (0x2a0/4) /* W PF -- Voodoo2/Banshee only */ +#define sBeginTriCMD (0x2a4/4) /* W PF -- Voodoo2/Banshee only */ + +/* 0x2c0 */ +#define bltSrcBaseAddr (0x2c0/4) /* RW PF -- Voodoo2 only */ +#define bltDstBaseAddr (0x2c4/4) /* RW PF -- Voodoo2 only */ +#define bltXYStrides (0x2c8/4) /* RW PF -- Voodoo2 only */ +#define bltSrcChromaRange (0x2cc/4) /* RW PF -- Voodoo2 only */ +#define bltDstChromaRange (0x2d0/4) /* RW PF -- Voodoo2 only */ +#define bltClipX (0x2d4/4) /* RW PF -- Voodoo2 only */ +#define bltClipY (0x2d8/4) /* RW PF -- Voodoo2 only */ +#define bltSrcXY (0x2e0/4) /* RW PF -- Voodoo2 only */ +#define bltDstXY (0x2e4/4) /* RW PF -- Voodoo2 only */ +#define bltSize (0x2e8/4) /* RW PF -- Voodoo2 only */ +#define bltRop (0x2ec/4) /* RW PF -- Voodoo2 only */ +#define bltColor (0x2f0/4) /* RW PF -- Voodoo2 only */ +#define bltCommand (0x2f8/4) /* RW PF -- Voodoo2 only */ +#define bltData (0x2fc/4) /* W PF -- Voodoo2 only */ + +/* 0x300 */ +#define textureMode (0x300/4) /* W PF */ +#define tLOD (0x304/4) /* W PF */ +#define tDetail (0x308/4) /* W PF */ +#define texBaseAddr (0x30c/4) /* W PF */ +#define texBaseAddr_1 (0x310/4) /* W PF */ +#define texBaseAddr_2 (0x314/4) /* W PF */ +#define texBaseAddr_3_8 (0x318/4) /* W PF */ +#define trexInit0 (0x31c/4) /* W F -- Voodoo/Voodoo2 only */ +#define trexInit1 (0x320/4) /* W F */ +#define nccTable (0x324/4) /* W F */ + + + +// 2D registers +#define banshee2D_clip0Min (0x008/4) +#define banshee2D_clip0Max (0x00c/4) +#define banshee2D_dstBaseAddr (0x010/4) +#define banshee2D_dstFormat (0x014/4) +#define banshee2D_srcColorkeyMin (0x018/4) +#define banshee2D_srcColorkeyMax (0x01c/4) +#define banshee2D_dstColorkeyMin (0x020/4) +#define banshee2D_dstColorkeyMax (0x024/4) +#define banshee2D_bresError0 (0x028/4) +#define banshee2D_bresError1 (0x02c/4) +#define banshee2D_rop (0x030/4) +#define banshee2D_srcBaseAddr (0x034/4) +#define banshee2D_commandExtra (0x038/4) +#define banshee2D_lineStipple (0x03c/4) +#define banshee2D_lineStyle (0x040/4) +#define banshee2D_pattern0Alias (0x044/4) +#define banshee2D_pattern1Alias (0x048/4) +#define banshee2D_clip1Min (0x04c/4) +#define banshee2D_clip1Max (0x050/4) +#define banshee2D_srcFormat (0x054/4) +#define banshee2D_srcSize (0x058/4) +#define banshee2D_srcXY (0x05c/4) +#define banshee2D_colorBack (0x060/4) +#define banshee2D_colorFore (0x064/4) +#define banshee2D_dstSize (0x068/4) +#define banshee2D_dstXY (0x06c/4) +#define banshee2D_command (0x070/4) + + +/************************************* + * + * Alias map of the first 64 + * registers when remapped + * + *************************************/ + +static const UINT8 register_alias_map[0x40] = +{ + status, 0x004/4, vertexAx, vertexAy, + vertexBx, vertexBy, vertexCx, vertexCy, + startR, dRdX, dRdY, startG, + dGdX, dGdY, startB, dBdX, + dBdY, startZ, dZdX, dZdY, + startA, dAdX, dAdY, startS, + dSdX, dSdY, startT, dTdX, + dTdY, startW, dWdX, dWdY, + + triangleCMD,0x084/4, fvertexAx, fvertexAy, + fvertexBx, fvertexBy, fvertexCx, fvertexCy, + fstartR, fdRdX, fdRdY, fstartG, + fdGdX, fdGdY, fstartB, fdBdX, + fdBdY, fstartZ, fdZdX, fdZdY, + fstartA, fdAdX, fdAdY, fstartS, + fdSdX, fdSdY, fstartT, fdTdX, + fdTdY, fstartW, fdWdX, fdWdY +}; + + + +/************************************* + * + * Table of per-register access rights + * + *************************************/ + +static const UINT8 voodoo_register_access[0x100] = +{ + /* 0x000 */ + REG_RP, 0, REG_WPF, REG_WPF, + REG_WPF, REG_WPF, REG_WPF, REG_WPF, + REG_WPF, REG_WPF, REG_WPF, REG_WPF, + REG_WPF, REG_WPF, REG_WPF, REG_WPF, + + /* 0x040 */ + REG_WPF, REG_WPF, REG_WPF, REG_WPF, + REG_WPF, REG_WPF, REG_WPF, REG_WPF, + REG_WPF, REG_WPF, REG_WPF, REG_WPF, + REG_WPF, REG_WPF, REG_WPF, REG_WPF, + + /* 0x080 */ + REG_WPF, 0, REG_WPF, REG_WPF, + REG_WPF, REG_WPF, REG_WPF, REG_WPF, + REG_WPF, REG_WPF, REG_WPF, REG_WPF, + REG_WPF, REG_WPF, REG_WPF, REG_WPF, + + /* 0x0c0 */ + REG_WPF, REG_WPF, REG_WPF, REG_WPF, + REG_WPF, REG_WPF, REG_WPF, REG_WPF, + REG_WPF, REG_WPF, REG_WPF, REG_WPF, + REG_WPF, REG_WPF, REG_WPF, REG_WPF, + + /* 0x100 */ + REG_WPF, REG_RWPF, REG_RWPF, REG_RWPF, + REG_RWF, REG_RWF, REG_RWF, REG_RWF, + REG_WF, REG_WF, REG_WF, REG_WF, + REG_WF, REG_WF, 0, 0, + + /* 0x140 */ + REG_RWF, REG_RWF, REG_RWF, REG_R, + REG_R, REG_R, REG_R, REG_R, + REG_WF, REG_WF, REG_WF, REG_WF, + REG_WF, REG_WF, REG_WF, REG_WF, + + /* 0x180 */ + REG_WF, REG_WF, REG_WF, REG_WF, + REG_WF, REG_WF, REG_WF, REG_WF, + REG_WF, REG_WF, REG_WF, REG_WF, + REG_WF, REG_WF, REG_WF, REG_WF, + + /* 0x1c0 */ + REG_WF, REG_WF, REG_WF, REG_WF, + REG_WF, REG_WF, REG_WF, REG_WF, + 0, 0, 0, 0, + 0, 0, 0, 0, + + /* 0x200 */ + REG_RW, REG_R, REG_RW, REG_RW, + REG_RW, REG_RW, REG_RW, REG_RW, + REG_W, REG_W, REG_W, REG_W, + REG_W, 0, 0, 0, + + /* 0x240 */ + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + + /* 0x280 */ + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + + /* 0x2c0 */ + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + + /* 0x300 */ + REG_WPF, REG_WPF, REG_WPF, REG_WPF, + REG_WPF, REG_WPF, REG_WPF, REG_WF, + REG_WF, REG_WF, REG_WF, REG_WF, + REG_WF, REG_WF, REG_WF, REG_WF, + + /* 0x340 */ + REG_WF, REG_WF, REG_WF, REG_WF, + REG_WF, REG_WF, REG_WF, REG_WF, + REG_WF, REG_WF, REG_WF, REG_WF, + REG_WF, REG_WF, REG_WF, REG_WF, + + /* 0x380 */ + REG_WF +}; + + +static const UINT8 voodoo2_register_access[0x100] = +{ + /* 0x000 */ + REG_RP, REG_RWPT, REG_WPF, REG_WPF, + REG_WPF, REG_WPF, REG_WPF, REG_WPF, + REG_WPF, REG_WPF, REG_WPF, REG_WPF, + REG_WPF, REG_WPF, REG_WPF, REG_WPF, + + /* 0x040 */ + REG_WPF, REG_WPF, REG_WPF, REG_WPF, + REG_WPF, REG_WPF, REG_WPF, REG_WPF, + REG_WPF, REG_WPF, REG_WPF, REG_WPF, + REG_WPF, REG_WPF, REG_WPF, REG_WPF, + + /* 0x080 */ + REG_WPF, REG_WPF, REG_WPF, REG_WPF, + REG_WPF, REG_WPF, REG_WPF, REG_WPF, + REG_WPF, REG_WPF, REG_WPF, REG_WPF, + REG_WPF, REG_WPF, REG_WPF, REG_WPF, + + /* 0x0c0 */ + REG_WPF, REG_WPF, REG_WPF, REG_WPF, + REG_WPF, REG_WPF, REG_WPF, REG_WPF, + REG_WPF, REG_WPF, REG_WPF, REG_WPF, + REG_WPF, REG_WPF, REG_WPF, REG_WPF, + + /* 0x100 */ + REG_WPF, REG_RWPF, REG_RWPF, REG_RWPF, + REG_RWF, REG_RWF, REG_RWF, REG_RWF, + REG_WF, REG_WF, REG_WF, REG_WF, + REG_WF, REG_WF, REG_WF, REG_WF, + + /* 0x140 */ + REG_RWF, REG_RWF, REG_RWF, REG_R, + REG_R, REG_R, REG_R, REG_R, + REG_WF, REG_WF, REG_WF, REG_WF, + REG_WF, REG_WF, REG_WF, REG_WF, + + /* 0x180 */ + REG_WF, REG_WF, REG_WF, REG_WF, + REG_WF, REG_WF, REG_WF, REG_WF, + REG_WF, REG_WF, REG_WF, REG_WF, + REG_WF, REG_WF, REG_WF, REG_WF, + + /* 0x1c0 */ + REG_WF, REG_WF, REG_WF, REG_WF, + REG_WF, REG_WF, REG_WF, REG_WF, + REG_RWT, REG_RWT, REG_RWT, REG_RWT, + REG_RWT, REG_RWT, REG_RWT, REG_RW, + + /* 0x200 */ + REG_RWT, REG_R, REG_RWT, REG_RWT, + REG_RWT, REG_RWT, REG_RWT, REG_RWT, + REG_WT, REG_WT, REG_WF, REG_WT, + REG_WT, REG_WT, REG_WT, REG_WT, + + /* 0x240 */ + REG_R, REG_RWT, REG_RWT, REG_RWT, + 0, 0, REG_R, REG_R, + REG_WPF, REG_WPF, REG_WPF, REG_WPF, + REG_WPF, REG_WPF, REG_WPF, REG_WPF, + + /* 0x280 */ + REG_WPF, REG_WPF, REG_WPF, REG_WPF, + REG_WPF, REG_WPF, REG_WPF, REG_WPF, + REG_WPF, REG_WPF, 0, 0, + 0, 0, 0, 0, + + /* 0x2c0 */ + REG_RWPF, REG_RWPF, REG_RWPF, REG_RWPF, + REG_RWPF, REG_RWPF, REG_RWPF, REG_RWPF, + REG_RWPF, REG_RWPF, REG_RWPF, REG_RWPF, + REG_RWPF, REG_RWPF, REG_RWPF, REG_WPF, + + /* 0x300 */ + REG_WPF, REG_WPF, REG_WPF, REG_WPF, + REG_WPF, REG_WPF, REG_WPF, REG_WF, + REG_WF, REG_WF, REG_WF, REG_WF, + REG_WF, REG_WF, REG_WF, REG_WF, + + /* 0x340 */ + REG_WF, REG_WF, REG_WF, REG_WF, + REG_WF, REG_WF, REG_WF, REG_WF, + REG_WF, REG_WF, REG_WF, REG_WF, + REG_WF, REG_WF, REG_WF, REG_WF, + + /* 0x380 */ + REG_WF +}; + + +static const UINT8 banshee_register_access[0x100] = +{ + /* 0x000 */ + REG_RP, REG_RWPT, REG_WPF, REG_WPF, + REG_WPF, REG_WPF, REG_WPF, REG_WPF, + REG_WPF, REG_WPF, REG_WPF, REG_WPF, + REG_WPF, REG_WPF, REG_WPF, REG_WPF, + + /* 0x040 */ + REG_WPF, REG_WPF, REG_WPF, REG_WPF, + REG_WPF, REG_WPF, REG_WPF, REG_WPF, + REG_WPF, REG_WPF, REG_WPF, REG_WPF, + REG_WPF, REG_WPF, REG_WPF, REG_WPF, + + /* 0x080 */ + REG_WPF, REG_WPF, REG_WPF, REG_WPF, + REG_WPF, REG_WPF, REG_WPF, REG_WPF, + REG_WPF, REG_WPF, REG_WPF, REG_WPF, + REG_WPF, REG_WPF, REG_WPF, REG_WPF, + + /* 0x0c0 */ + REG_WPF, REG_WPF, REG_WPF, REG_WPF, + REG_WPF, REG_WPF, REG_WPF, REG_WPF, + REG_WPF, REG_WPF, REG_WPF, REG_WPF, + REG_WPF, REG_WPF, REG_WPF, REG_WPF, + + /* 0x100 */ + REG_WPF, REG_RWPF, REG_RWPF, REG_RWPF, + REG_RWF, REG_RWF, REG_RWF, REG_RWF, + REG_WF, REG_WF, REG_WF, REG_WF, + REG_WF, REG_WF, REG_WF, REG_WF, + + /* 0x140 */ + REG_RWF, REG_RWF, REG_RWF, REG_R, + REG_R, REG_R, REG_R, REG_R, + REG_WF, REG_WF, REG_WF, REG_WF, + REG_WF, REG_WF, REG_WF, REG_WF, + + /* 0x180 */ + REG_WF, REG_WF, REG_WF, REG_WF, + REG_WF, REG_WF, REG_WF, REG_WF, + REG_WF, REG_WF, REG_WF, REG_WF, + REG_WF, REG_WF, REG_WF, REG_WF, + + /* 0x1c0 */ + REG_WF, REG_WF, REG_WF, REG_WF, + REG_WF, REG_WF, REG_WF, REG_WF, + 0, 0, 0, REG_RWF, + REG_RWF, REG_RWF, REG_RWF, 0, + + /* 0x200 */ + REG_RWF, REG_RWF, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + + /* 0x240 */ + 0, 0, 0, REG_WT, + REG_RWF, REG_RWF, REG_WPF, REG_WPF, + REG_WPF, REG_WPF, REG_R, REG_R, + REG_WPF, REG_WPF, REG_WPF, REG_WPF, + + /* 0x280 */ + REG_WPF, REG_WPF, REG_WPF, REG_WPF, + REG_WPF, REG_WPF, REG_WPF, REG_WPF, + REG_WPF, REG_WPF, 0, 0, + 0, 0, 0, 0, + + /* 0x2c0 */ + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + + /* 0x300 */ + REG_WPF, REG_WPF, REG_WPF, REG_WPF, + REG_WPF, REG_WPF, REG_WPF, 0, + REG_WF, REG_WF, REG_WF, REG_WF, + REG_WF, REG_WF, REG_WF, REG_WF, + + /* 0x340 */ + REG_WF, REG_WF, REG_WF, REG_WF, + REG_WF, REG_WF, REG_WF, REG_WF, + REG_WF, REG_WF, REG_WF, REG_WF, + REG_WF, REG_WF, REG_WF, REG_WF, + + /* 0x380 */ + REG_WF +}; + + + +/************************************* + * + * Register string table for debug + * + *************************************/ + +static const char *const voodoo_reg_name[] = +{ + /* 0x000 */ + "status", "{intrCtrl}", "vertexAx", "vertexAy", + "vertexBx", "vertexBy", "vertexCx", "vertexCy", + "startR", "startG", "startB", "startZ", + "startA", "startS", "startT", "startW", + /* 0x040 */ + "dRdX", "dGdX", "dBdX", "dZdX", + "dAdX", "dSdX", "dTdX", "dWdX", + "dRdY", "dGdY", "dBdY", "dZdY", + "dAdY", "dSdY", "dTdY", "dWdY", + /* 0x080 */ + "triangleCMD", "reserved084", "fvertexAx", "fvertexAy", + "fvertexBx", "fvertexBy", "fvertexCx", "fvertexCy", + "fstartR", "fstartG", "fstartB", "fstartZ", + "fstartA", "fstartS", "fstartT", "fstartW", + /* 0x0c0 */ + "fdRdX", "fdGdX", "fdBdX", "fdZdX", + "fdAdX", "fdSdX", "fdTdX", "fdWdX", + "fdRdY", "fdGdY", "fdBdY", "fdZdY", + "fdAdY", "fdSdY", "fdTdY", "fdWdY", + /* 0x100 */ + "ftriangleCMD", "fbzColorPath", "fogMode", "alphaMode", + "fbzMode", "lfbMode", "clipLeftRight","clipLowYHighY", + "nopCMD", "fastfillCMD", "swapbufferCMD","fogColor", + "zaColor", "chromaKey", "{chromaRange}","{userIntrCMD}", + /* 0x140 */ + "stipple", "color0", "color1", "fbiPixelsIn", + "fbiChromaFail","fbiZfuncFail", "fbiAfuncFail", "fbiPixelsOut", + "fogTable160", "fogTable164", "fogTable168", "fogTable16c", + "fogTable170", "fogTable174", "fogTable178", "fogTable17c", + /* 0x180 */ + "fogTable180", "fogTable184", "fogTable188", "fogTable18c", + "fogTable190", "fogTable194", "fogTable198", "fogTable19c", + "fogTable1a0", "fogTable1a4", "fogTable1a8", "fogTable1ac", + "fogTable1b0", "fogTable1b4", "fogTable1b8", "fogTable1bc", + /* 0x1c0 */ + "fogTable1c0", "fogTable1c4", "fogTable1c8", "fogTable1cc", + "fogTable1d0", "fogTable1d4", "fogTable1d8", "fogTable1dc", + "{cmdFifoBaseAddr}","{cmdFifoBump}","{cmdFifoRdPtr}","{cmdFifoAMin}", + "{cmdFifoAMax}","{cmdFifoDepth}","{cmdFifoHoles}","reserved1fc", + /* 0x200 */ + "fbiInit4", "vRetrace", "backPorch", "videoDimensions", + "fbiInit0", "fbiInit1", "fbiInit2", "fbiInit3", + "hSync", "vSync", "clutData", "dacData", + "maxRgbDelta", "{hBorder}", "{vBorder}", "{borderColor}", + /* 0x240 */ + "{hvRetrace}", "{fbiInit5}", "{fbiInit6}", "{fbiInit7}", + "reserved250", "reserved254", "{fbiSwapHistory}","{fbiTrianglesOut}", + "{sSetupMode}", "{sVx}", "{sVy}", "{sARGB}", + "{sRed}", "{sGreen}", "{sBlue}", "{sAlpha}", + /* 0x280 */ + "{sVz}", "{sWb}", "{sWtmu0}", "{sS/Wtmu0}", + "{sT/Wtmu0}", "{sWtmu1}", "{sS/Wtmu1}", "{sT/Wtmu1}", + "{sDrawTriCMD}","{sBeginTriCMD}","reserved2a8", "reserved2ac", + "reserved2b0", "reserved2b4", "reserved2b8", "reserved2bc", + /* 0x2c0 */ + "{bltSrcBaseAddr}","{bltDstBaseAddr}","{bltXYStrides}","{bltSrcChromaRange}", + "{bltDstChromaRange}","{bltClipX}","{bltClipY}","reserved2dc", + "{bltSrcXY}", "{bltDstXY}", "{bltSize}", "{bltRop}", + "{bltColor}", "reserved2f4", "{bltCommand}", "{bltData}", + /* 0x300 */ + "textureMode", "tLOD", "tDetail", "texBaseAddr", + "texBaseAddr_1","texBaseAddr_2","texBaseAddr_3_8","trexInit0", + "trexInit1", "nccTable0.0", "nccTable0.1", "nccTable0.2", + "nccTable0.3", "nccTable0.4", "nccTable0.5", "nccTable0.6", + /* 0x340 */ + "nccTable0.7", "nccTable0.8", "nccTable0.9", "nccTable0.A", + "nccTable0.B", "nccTable1.0", "nccTable1.1", "nccTable1.2", + "nccTable1.3", "nccTable1.4", "nccTable1.5", "nccTable1.6", + "nccTable1.7", "nccTable1.8", "nccTable1.9", "nccTable1.A", + /* 0x380 */ + "nccTable1.B" +}; + + +static const char *const banshee_reg_name[] = +{ + /* 0x000 */ + "status", "intrCtrl", "vertexAx", "vertexAy", + "vertexBx", "vertexBy", "vertexCx", "vertexCy", + "startR", "startG", "startB", "startZ", + "startA", "startS", "startT", "startW", + /* 0x040 */ + "dRdX", "dGdX", "dBdX", "dZdX", + "dAdX", "dSdX", "dTdX", "dWdX", + "dRdY", "dGdY", "dBdY", "dZdY", + "dAdY", "dSdY", "dTdY", "dWdY", + /* 0x080 */ + "triangleCMD", "reserved084", "fvertexAx", "fvertexAy", + "fvertexBx", "fvertexBy", "fvertexCx", "fvertexCy", + "fstartR", "fstartG", "fstartB", "fstartZ", + "fstartA", "fstartS", "fstartT", "fstartW", + /* 0x0c0 */ + "fdRdX", "fdGdX", "fdBdX", "fdZdX", + "fdAdX", "fdSdX", "fdTdX", "fdWdX", + "fdRdY", "fdGdY", "fdBdY", "fdZdY", + "fdAdY", "fdSdY", "fdTdY", "fdWdY", + /* 0x100 */ + "ftriangleCMD", "fbzColorPath", "fogMode", "alphaMode", + "fbzMode", "lfbMode", "clipLeftRight","clipLowYHighY", + "nopCMD", "fastfillCMD", "swapbufferCMD","fogColor", + "zaColor", "chromaKey", "chromaRange", "userIntrCMD", + /* 0x140 */ + "stipple", "color0", "color1", "fbiPixelsIn", + "fbiChromaFail","fbiZfuncFail", "fbiAfuncFail", "fbiPixelsOut", + "fogTable160", "fogTable164", "fogTable168", "fogTable16c", + "fogTable170", "fogTable174", "fogTable178", "fogTable17c", + /* 0x180 */ + "fogTable180", "fogTable184", "fogTable188", "fogTable18c", + "fogTable190", "fogTable194", "fogTable198", "fogTable19c", + "fogTable1a0", "fogTable1a4", "fogTable1a8", "fogTable1ac", + "fogTable1b0", "fogTable1b4", "fogTable1b8", "fogTable1bc", + /* 0x1c0 */ + "fogTable1c0", "fogTable1c4", "fogTable1c8", "fogTable1cc", + "fogTable1d0", "fogTable1d4", "fogTable1d8", "fogTable1dc", + "reserved1e0", "reserved1e4", "reserved1e8", "colBufferAddr", + "colBufferStride","auxBufferAddr","auxBufferStride","reserved1fc", + /* 0x200 */ + "clipLeftRight1","clipTopBottom1","reserved208","reserved20c", + "reserved210", "reserved214", "reserved218", "reserved21c", + "reserved220", "reserved224", "reserved228", "reserved22c", + "reserved230", "reserved234", "reserved238", "reserved23c", + /* 0x240 */ + "reserved240", "reserved244", "reserved248", "swapPending", + "leftOverlayBuf","rightOverlayBuf","fbiSwapHistory","fbiTrianglesOut", + "sSetupMode", "sVx", "sVy", "sARGB", + "sRed", "sGreen", "sBlue", "sAlpha", + /* 0x280 */ + "sVz", "sWb", "sWtmu0", "sS/Wtmu0", + "sT/Wtmu0", "sWtmu1", "sS/Wtmu1", "sT/Wtmu1", + "sDrawTriCMD", "sBeginTriCMD", "reserved2a8", "reserved2ac", + "reserved2b0", "reserved2b4", "reserved2b8", "reserved2bc", + /* 0x2c0 */ + "reserved2c0", "reserved2c4", "reserved2c8", "reserved2cc", + "reserved2d0", "reserved2d4", "reserved2d8", "reserved2dc", + "reserved2e0", "reserved2e4", "reserved2e8", "reserved2ec", + "reserved2f0", "reserved2f4", "reserved2f8", "reserved2fc", + /* 0x300 */ + "textureMode", "tLOD", "tDetail", "texBaseAddr", + "texBaseAddr_1","texBaseAddr_2","texBaseAddr_3_8","reserved31c", + "trexInit1", "nccTable0.0", "nccTable0.1", "nccTable0.2", + "nccTable0.3", "nccTable0.4", "nccTable0.5", "nccTable0.6", + /* 0x340 */ + "nccTable0.7", "nccTable0.8", "nccTable0.9", "nccTable0.A", + "nccTable0.B", "nccTable1.0", "nccTable1.1", "nccTable1.2", + "nccTable1.3", "nccTable1.4", "nccTable1.5", "nccTable1.6", + "nccTable1.7", "nccTable1.8", "nccTable1.9", "nccTable1.A", + /* 0x380 */ + "nccTable1.B" +}; + + + +/************************************* + * + * Voodoo Banshee I/O space registers + * + *************************************/ + +/* 0x000 */ +#define io_status (0x000/4) /* */ +#define io_pciInit0 (0x004/4) /* */ +#define io_sipMonitor (0x008/4) /* */ +#define io_lfbMemoryConfig (0x00c/4) /* */ +#define io_miscInit0 (0x010/4) /* */ +#define io_miscInit1 (0x014/4) /* */ +#define io_dramInit0 (0x018/4) /* */ +#define io_dramInit1 (0x01c/4) /* */ +#define io_agpInit (0x020/4) /* */ +#define io_tmuGbeInit (0x024/4) /* */ +#define io_vgaInit0 (0x028/4) /* */ +#define io_vgaInit1 (0x02c/4) /* */ +#define io_dramCommand (0x030/4) /* */ +#define io_dramData (0x034/4) /* */ + +/* 0x040 */ +#define io_pllCtrl0 (0x040/4) /* */ +#define io_pllCtrl1 (0x044/4) /* */ +#define io_pllCtrl2 (0x048/4) /* */ +#define io_dacMode (0x04c/4) /* */ +#define io_dacAddr (0x050/4) /* */ +#define io_dacData (0x054/4) /* */ +#define io_rgbMaxDelta (0x058/4) /* */ +#define io_vidProcCfg (0x05c/4) /* */ +#define io_hwCurPatAddr (0x060/4) /* */ +#define io_hwCurLoc (0x064/4) /* */ +#define io_hwCurC0 (0x068/4) /* */ +#define io_hwCurC1 (0x06c/4) /* */ +#define io_vidInFormat (0x070/4) /* */ +#define io_vidInStatus (0x074/4) /* */ +#define io_vidSerialParallelPort (0x078/4) /* */ +#define io_vidInXDecimDeltas (0x07c/4) /* */ + +/* 0x080 */ +#define io_vidInDecimInitErrs (0x080/4) /* */ +#define io_vidInYDecimDeltas (0x084/4) /* */ +#define io_vidPixelBufThold (0x088/4) /* */ +#define io_vidChromaMin (0x08c/4) /* */ +#define io_vidChromaMax (0x090/4) /* */ +#define io_vidCurrentLine (0x094/4) /* */ +#define io_vidScreenSize (0x098/4) /* */ +#define io_vidOverlayStartCoords (0x09c/4) /* */ +#define io_vidOverlayEndScreenCoord (0x0a0/4) /* */ +#define io_vidOverlayDudx (0x0a4/4) /* */ +#define io_vidOverlayDudxOffsetSrcWidth (0x0a8/4) /* */ +#define io_vidOverlayDvdy (0x0ac/4) /* */ +#define io_vgab0 (0x0b0/4) /* */ +#define io_vgab4 (0x0b4/4) /* */ +#define io_vgab8 (0x0b8/4) /* */ +#define io_vgabc (0x0bc/4) /* */ + +/* 0x0c0 */ +#define io_vgac0 (0x0c0/4) /* */ +#define io_vgac4 (0x0c4/4) /* */ +#define io_vgac8 (0x0c8/4) /* */ +#define io_vgacc (0x0cc/4) /* */ +#define io_vgad0 (0x0d0/4) /* */ +#define io_vgad4 (0x0d4/4) /* */ +#define io_vgad8 (0x0d8/4) /* */ +#define io_vgadc (0x0dc/4) /* */ +#define io_vidOverlayDvdyOffset (0x0e0/4) /* */ +#define io_vidDesktopStartAddr (0x0e4/4) /* */ +#define io_vidDesktopOverlayStride (0x0e8/4) /* */ +#define io_vidInAddr0 (0x0ec/4) /* */ +#define io_vidInAddr1 (0x0f0/4) /* */ +#define io_vidInAddr2 (0x0f4/4) /* */ +#define io_vidInStride (0x0f8/4) /* */ +#define io_vidCurrOverlayStartAddr (0x0fc/4) /* */ + + + +/************************************* + * + * Register string table for debug + * + *************************************/ + +static const char *const banshee_io_reg_name[] = +{ + /* 0x000 */ + "status", "pciInit0", "sipMonitor", "lfbMemoryConfig", + "miscInit0", "miscInit1", "dramInit0", "dramInit1", + "agpInit", "tmuGbeInit", "vgaInit0", "vgaInit1", + "dramCommand", "dramData", "reserved38", "reserved3c", + + /* 0x040 */ + "pllCtrl0", "pllCtrl1", "pllCtrl2", "dacMode", + "dacAddr", "dacData", "rgbMaxDelta", "vidProcCfg", + "hwCurPatAddr", "hwCurLoc", "hwCurC0", "hwCurC1", + "vidInFormat", "vidInStatus", "vidSerialParallelPort","vidInXDecimDeltas", + + /* 0x080 */ + "vidInDecimInitErrs","vidInYDecimDeltas","vidPixelBufThold","vidChromaMin", + "vidChromaMax", "vidCurrentLine","vidScreenSize","vidOverlayStartCoords", + "vidOverlayEndScreenCoord","vidOverlayDudx","vidOverlayDudxOffsetSrcWidth","vidOverlayDvdy", + "vga[b0]", "vga[b4]", "vga[b8]", "vga[bc]", + + /* 0x0c0 */ + "vga[c0]", "vga[c4]", "vga[c8]", "vga[cc]", + "vga[d0]", "vga[d4]", "vga[d8]", "vga[dc]", + "vidOverlayDvdyOffset","vidDesktopStartAddr","vidDesktopOverlayStride","vidInAddr0", + "vidInAddr1", "vidInAddr2", "vidInStride", "vidCurrOverlayStartAddr" +}; + + + +/************************************* + * + * Voodoo Banshee AGP space registers + * + *************************************/ + +/* 0x000 */ +#define agpReqSize (0x000/4) /* */ +#define agpHostAddressLow (0x004/4) /* */ +#define agpHostAddressHigh (0x008/4) /* */ +#define agpGraphicsAddress (0x00c/4) /* */ +#define agpGraphicsStride (0x010/4) /* */ +#define agpMoveCMD (0x014/4) /* */ +#define cmdBaseAddr0 (0x020/4) /* */ +#define cmdBaseSize0 (0x024/4) /* */ +#define cmdBump0 (0x028/4) /* */ +#define cmdRdPtrL0 (0x02c/4) /* */ +#define cmdRdPtrH0 (0x030/4) /* */ +#define cmdAMin0 (0x034/4) /* */ +#define cmdAMax0 (0x03c/4) /* */ + +/* 0x040 */ +#define cmdFifoDepth0 (0x044/4) /* */ +#define cmdHoleCnt0 (0x048/4) /* */ +#define cmdBaseAddr1 (0x050/4) /* */ +#define cmdBaseSize1 (0x054/4) /* */ +#define cmdBump1 (0x058/4) /* */ +#define cmdRdPtrL1 (0x05c/4) /* */ +#define cmdRdPtrH1 (0x060/4) /* */ +#define cmdAMin1 (0x064/4) /* */ +#define cmdAMax1 (0x06c/4) /* */ +#define cmdFifoDepth1 (0x074/4) /* */ +#define cmdHoleCnt1 (0x078/4) /* */ + +/* 0x080 */ +#define cmdFifoThresh (0x080/4) /* */ +#define cmdHoleInt (0x084/4) /* */ + +/* 0x100 */ +#define yuvBaseAddress (0x100/4) /* */ +#define yuvStride (0x104/4) /* */ +#define crc1 (0x120/4) /* */ +#define crc2 (0x130/4) /* */ + + + +/************************************* + * + * Register string table for debug + * + *************************************/ + +static const char *const banshee_agp_reg_name[] = +{ + /* 0x000 */ + "agpReqSize", "agpHostAddressLow","agpHostAddressHigh","agpGraphicsAddress", + "agpGraphicsStride","agpMoveCMD","reserved18", "reserved1c", + "cmdBaseAddr0", "cmdBaseSize0", "cmdBump0", "cmdRdPtrL0", + "cmdRdPtrH0", "cmdAMin0", "reserved38", "cmdAMax0", + + /* 0x040 */ + "reserved40", "cmdFifoDepth0","cmdHoleCnt0", "reserved4c", + "cmdBaseAddr1", "cmdBaseSize1", "cmdBump1", "cmdRdPtrL1", + "cmdRdPtrH1", "cmdAMin1", "reserved68", "cmdAMax1", + "reserved70", "cmdFifoDepth1","cmdHoleCnt1", "reserved7c", + + /* 0x080 */ + "cmdFifoThresh","cmdHoleInt", "reserved88", "reserved8c", + "reserved90", "reserved94", "reserved98", "reserved9c", + "reserveda0", "reserveda4", "reserveda8", "reservedac", + "reservedb0", "reservedb4", "reservedb8", "reservedbc", + + /* 0x0c0 */ + "reservedc0", "reservedc4", "reservedc8", "reservedcc", + "reservedd0", "reservedd4", "reservedd8", "reserveddc", + "reservede0", "reservede4", "reservede8", "reservedec", + "reservedf0", "reservedf4", "reservedf8", "reservedfc", + + /* 0x100 */ + "yuvBaseAddress","yuvStride", "reserved108", "reserved10c", + "reserved110", "reserved114", "reserved118", "reserved11c", + "crc1", "reserved124", "reserved128", "reserved12c", + "crc2", "reserved134", "reserved138", "reserved13c" +}; + + + +/************************************* + * + * Dithering tables + * + *************************************/ + +static const UINT8 dither_matrix_4x4[16] = +{ + 0, 8, 2, 10, + 12, 4, 14, 6, + 3, 11, 1, 9, + 15, 7, 13, 5 +}; + +static const UINT8 dither_matrix_2x2[16] = +{ + 2, 10, 2, 10, + 14, 6, 14, 6, + 2, 10, 2, 10, + 14, 6, 14, 6 +}; + + + +/************************************* + * + * Macros for extracting pixels + * + *************************************/ + +#define EXTRACT_565_TO_888(val, a, b, c) \ + (a) = (((val) >> 8) & 0xf8) | (((val) >> 13) & 0x07); \ + (b) = (((val) >> 3) & 0xfc) | (((val) >> 9) & 0x03); \ + (c) = (((val) << 3) & 0xf8) | (((val) >> 2) & 0x07); +#define EXTRACT_x555_TO_888(val, a, b, c) \ + (a) = (((val) >> 7) & 0xf8) | (((val) >> 12) & 0x07); \ + (b) = (((val) >> 2) & 0xf8) | (((val) >> 7) & 0x07); \ + (c) = (((val) << 3) & 0xf8) | (((val) >> 2) & 0x07); +#define EXTRACT_555x_TO_888(val, a, b, c) \ + (a) = (((val) >> 8) & 0xf8) | (((val) >> 13) & 0x07); \ + (b) = (((val) >> 3) & 0xf8) | (((val) >> 8) & 0x07); \ + (c) = (((val) << 2) & 0xf8) | (((val) >> 3) & 0x07); +#define EXTRACT_1555_TO_8888(val, a, b, c, d) \ + (a) = ((INT16)(val) >> 15) & 0xff; \ + EXTRACT_x555_TO_888(val, b, c, d) +#define EXTRACT_5551_TO_8888(val, a, b, c, d) \ + EXTRACT_555x_TO_888(val, a, b, c) \ + (d) = ((val) & 0x0001) ? 0xff : 0x00; +#define EXTRACT_x888_TO_888(val, a, b, c) \ + (a) = ((val) >> 16) & 0xff; \ + (b) = ((val) >> 8) & 0xff; \ + (c) = ((val) >> 0) & 0xff; +#define EXTRACT_888x_TO_888(val, a, b, c) \ + (a) = ((val) >> 24) & 0xff; \ + (b) = ((val) >> 16) & 0xff; \ + (c) = ((val) >> 8) & 0xff; +#define EXTRACT_8888_TO_8888(val, a, b, c, d) \ + (a) = ((val) >> 24) & 0xff; \ + (b) = ((val) >> 16) & 0xff; \ + (c) = ((val) >> 8) & 0xff; \ + (d) = ((val) >> 0) & 0xff; +#define EXTRACT_4444_TO_8888(val, a, b, c, d) \ + (a) = (((val) >> 8) & 0xf0) | (((val) >> 12) & 0x0f); \ + (b) = (((val) >> 4) & 0xf0) | (((val) >> 8) & 0x0f); \ + (c) = (((val) >> 0) & 0xf0) | (((val) >> 4) & 0x0f); \ + (d) = (((val) << 4) & 0xf0) | (((val) >> 0) & 0x0f); +#define EXTRACT_332_TO_888(val, a, b, c) \ + (a) = (((val) >> 0) & 0xe0) | (((val) >> 3) & 0x1c) | (((val) >> 6) & 0x03); \ + (b) = (((val) << 3) & 0xe0) | (((val) >> 0) & 0x1c) | (((val) >> 3) & 0x03); \ + (c) = (((val) << 6) & 0xc0) | (((val) << 4) & 0x30) | (((val) << 2) & 0x0c) | (((val) << 0) & 0x03); + + +/************************************* + * + * Misc. macros + * + *************************************/ + +/* macro for clamping a value between minimum and maximum values */ +#define CLAMP(val,min,max) do { if ((val) < (min)) { (val) = (min); } else if ((val) > (max)) { (val) = (max); } } while (0) + +/* macro to compute the base 2 log for LOD calculations */ +#define LOGB2(x) (log((double)(x)) / log(2.0)) + + + +/************************************* + * + * Macros for extracting bitfields + * + *************************************/ + +#define INITEN_ENABLE_HW_INIT(val) (((val) >> 0) & 1) +#define INITEN_ENABLE_PCI_FIFO(val) (((val) >> 1) & 1) +#define INITEN_REMAP_INIT_TO_DAC(val) (((val) >> 2) & 1) +#define INITEN_ENABLE_SNOOP0(val) (((val) >> 4) & 1) +#define INITEN_SNOOP0_MEMORY_MATCH(val) (((val) >> 5) & 1) +#define INITEN_SNOOP0_READWRITE_MATCH(val) (((val) >> 6) & 1) +#define INITEN_ENABLE_SNOOP1(val) (((val) >> 7) & 1) +#define INITEN_SNOOP1_MEMORY_MATCH(val) (((val) >> 8) & 1) +#define INITEN_SNOOP1_READWRITE_MATCH(val) (((val) >> 9) & 1) +#define INITEN_SLI_BUS_OWNER(val) (((val) >> 10) & 1) +#define INITEN_SLI_ODD_EVEN(val) (((val) >> 11) & 1) +#define INITEN_SECONDARY_REV_ID(val) (((val) >> 12) & 0xf) /* voodoo 2 only */ +#define INITEN_MFCTR_FAB_ID(val) (((val) >> 16) & 0xf) /* voodoo 2 only */ +#define INITEN_ENABLE_PCI_INTERRUPT(val) (((val) >> 20) & 1) /* voodoo 2 only */ +#define INITEN_PCI_INTERRUPT_TIMEOUT(val) (((val) >> 21) & 1) /* voodoo 2 only */ +#define INITEN_ENABLE_NAND_TREE_TEST(val) (((val) >> 22) & 1) /* voodoo 2 only */ +#define INITEN_ENABLE_SLI_ADDRESS_SNOOP(val) (((val) >> 23) & 1) /* voodoo 2 only */ +#define INITEN_SLI_SNOOP_ADDRESS(val) (((val) >> 24) & 0xff) /* voodoo 2 only */ + +#define FBZCP_CC_RGBSELECT(val) (((val) >> 0) & 3) +#define FBZCP_CC_ASELECT(val) (((val) >> 2) & 3) +#define FBZCP_CC_LOCALSELECT(val) (((val) >> 4) & 1) +#define FBZCP_CCA_LOCALSELECT(val) (((val) >> 5) & 3) +#define FBZCP_CC_LOCALSELECT_OVERRIDE(val) (((val) >> 7) & 1) +#define FBZCP_CC_ZERO_OTHER(val) (((val) >> 8) & 1) +#define FBZCP_CC_SUB_CLOCAL(val) (((val) >> 9) & 1) +#define FBZCP_CC_MSELECT(val) (((val) >> 10) & 7) +#define FBZCP_CC_REVERSE_BLEND(val) (((val) >> 13) & 1) +#define FBZCP_CC_ADD_ACLOCAL(val) (((val) >> 14) & 3) +#define FBZCP_CC_INVERT_OUTPUT(val) (((val) >> 16) & 1) +#define FBZCP_CCA_ZERO_OTHER(val) (((val) >> 17) & 1) +#define FBZCP_CCA_SUB_CLOCAL(val) (((val) >> 18) & 1) +#define FBZCP_CCA_MSELECT(val) (((val) >> 19) & 7) +#define FBZCP_CCA_REVERSE_BLEND(val) (((val) >> 22) & 1) +#define FBZCP_CCA_ADD_ACLOCAL(val) (((val) >> 23) & 3) +#define FBZCP_CCA_INVERT_OUTPUT(val) (((val) >> 25) & 1) +#define FBZCP_CCA_SUBPIXEL_ADJUST(val) (((val) >> 26) & 1) +#define FBZCP_TEXTURE_ENABLE(val) (((val) >> 27) & 1) +#define FBZCP_RGBZW_CLAMP(val) (((val) >> 28) & 1) /* voodoo 2 only */ +#define FBZCP_ANTI_ALIAS(val) (((val) >> 29) & 1) /* voodoo 2 only */ + +#define ALPHAMODE_ALPHATEST(val) (((val) >> 0) & 1) +#define ALPHAMODE_ALPHAFUNCTION(val) (((val) >> 1) & 7) +#define ALPHAMODE_ALPHABLEND(val) (((val) >> 4) & 1) +#define ALPHAMODE_ANTIALIAS(val) (((val) >> 5) & 1) +#define ALPHAMODE_SRCRGBBLEND(val) (((val) >> 8) & 15) +#define ALPHAMODE_DSTRGBBLEND(val) (((val) >> 12) & 15) +#define ALPHAMODE_SRCALPHABLEND(val) (((val) >> 16) & 15) +#define ALPHAMODE_DSTALPHABLEND(val) (((val) >> 20) & 15) +#define ALPHAMODE_ALPHAREF(val) (((val) >> 24) & 0xff) + +#define FOGMODE_ENABLE_FOG(val) (((val) >> 0) & 1) +#define FOGMODE_FOG_ADD(val) (((val) >> 1) & 1) +#define FOGMODE_FOG_MULT(val) (((val) >> 2) & 1) +#define FOGMODE_FOG_ZALPHA(val) (((val) >> 3) & 3) +#define FOGMODE_FOG_CONSTANT(val) (((val) >> 5) & 1) +#define FOGMODE_FOG_DITHER(val) (((val) >> 6) & 1) /* voodoo 2 only */ +#define FOGMODE_FOG_ZONES(val) (((val) >> 7) & 1) /* voodoo 2 only */ + +#define FBZMODE_ENABLE_CLIPPING(val) (((val) >> 0) & 1) +#define FBZMODE_ENABLE_CHROMAKEY(val) (((val) >> 1) & 1) +#define FBZMODE_ENABLE_STIPPLE(val) (((val) >> 2) & 1) +#define FBZMODE_WBUFFER_SELECT(val) (((val) >> 3) & 1) +#define FBZMODE_ENABLE_DEPTHBUF(val) (((val) >> 4) & 1) +#define FBZMODE_DEPTH_FUNCTION(val) (((val) >> 5) & 7) +#define FBZMODE_ENABLE_DITHERING(val) (((val) >> 8) & 1) +#define FBZMODE_RGB_BUFFER_MASK(val) (((val) >> 9) & 1) +#define FBZMODE_AUX_BUFFER_MASK(val) (((val) >> 10) & 1) +#define FBZMODE_DITHER_TYPE(val) (((val) >> 11) & 1) +#define FBZMODE_STIPPLE_PATTERN(val) (((val) >> 12) & 1) +#define FBZMODE_ENABLE_ALPHA_MASK(val) (((val) >> 13) & 1) +#define FBZMODE_DRAW_BUFFER(val) (((val) >> 14) & 3) +#define FBZMODE_ENABLE_DEPTH_BIAS(val) (((val) >> 16) & 1) +#define FBZMODE_Y_ORIGIN(val) (((val) >> 17) & 1) +#define FBZMODE_ENABLE_ALPHA_PLANES(val) (((val) >> 18) & 1) +#define FBZMODE_ALPHA_DITHER_SUBTRACT(val) (((val) >> 19) & 1) +#define FBZMODE_DEPTH_SOURCE_COMPARE(val) (((val) >> 20) & 1) +#define FBZMODE_DEPTH_FLOAT_SELECT(val) (((val) >> 21) & 1) /* voodoo 2 only */ + +#define LFBMODE_WRITE_FORMAT(val) (((val) >> 0) & 0xf) +#define LFBMODE_WRITE_BUFFER_SELECT(val) (((val) >> 4) & 3) +#define LFBMODE_READ_BUFFER_SELECT(val) (((val) >> 6) & 3) +#define LFBMODE_ENABLE_PIXEL_PIPELINE(val) (((val) >> 8) & 1) +#define LFBMODE_RGBA_LANES(val) (((val) >> 9) & 3) +#define LFBMODE_WORD_SWAP_WRITES(val) (((val) >> 11) & 1) +#define LFBMODE_BYTE_SWIZZLE_WRITES(val) (((val) >> 12) & 1) +#define LFBMODE_Y_ORIGIN(val) (((val) >> 13) & 1) +#define LFBMODE_WRITE_W_SELECT(val) (((val) >> 14) & 1) +#define LFBMODE_WORD_SWAP_READS(val) (((val) >> 15) & 1) +#define LFBMODE_BYTE_SWIZZLE_READS(val) (((val) >> 16) & 1) + +#define CHROMARANGE_BLUE_EXCLUSIVE(val) (((val) >> 24) & 1) +#define CHROMARANGE_GREEN_EXCLUSIVE(val) (((val) >> 25) & 1) +#define CHROMARANGE_RED_EXCLUSIVE(val) (((val) >> 26) & 1) +#define CHROMARANGE_UNION_MODE(val) (((val) >> 27) & 1) +#define CHROMARANGE_ENABLE(val) (((val) >> 28) & 1) + +#define FBIINIT0_VGA_PASSTHRU(val) (((val) >> 0) & 1) +#define FBIINIT0_GRAPHICS_RESET(val) (((val) >> 1) & 1) +#define FBIINIT0_FIFO_RESET(val) (((val) >> 2) & 1) +#define FBIINIT0_SWIZZLE_REG_WRITES(val) (((val) >> 3) & 1) +#define FBIINIT0_STALL_PCIE_FOR_HWM(val) (((val) >> 4) & 1) +#define FBIINIT0_PCI_FIFO_LWM(val) (((val) >> 6) & 0x1f) +#define FBIINIT0_LFB_TO_MEMORY_FIFO(val) (((val) >> 11) & 1) +#define FBIINIT0_TEXMEM_TO_MEMORY_FIFO(val) (((val) >> 12) & 1) +#define FBIINIT0_ENABLE_MEMORY_FIFO(val) (((val) >> 13) & 1) +#define FBIINIT0_MEMORY_FIFO_HWM(val) (((val) >> 14) & 0x7ff) +#define FBIINIT0_MEMORY_FIFO_BURST(val) (((val) >> 25) & 0x3f) + +#define FBIINIT1_PCI_DEV_FUNCTION(val) (((val) >> 0) & 1) +#define FBIINIT1_PCI_WRITE_WAIT_STATES(val) (((val) >> 1) & 1) +#define FBIINIT1_MULTI_SST1(val) (((val) >> 2) & 1) /* not on voodoo 2 */ +#define FBIINIT1_ENABLE_LFB(val) (((val) >> 3) & 1) +#define FBIINIT1_X_VIDEO_TILES(val) (((val) >> 4) & 0xf) +#define FBIINIT1_VIDEO_TIMING_RESET(val) (((val) >> 8) & 1) +#define FBIINIT1_SOFTWARE_OVERRIDE(val) (((val) >> 9) & 1) +#define FBIINIT1_SOFTWARE_HSYNC(val) (((val) >> 10) & 1) +#define FBIINIT1_SOFTWARE_VSYNC(val) (((val) >> 11) & 1) +#define FBIINIT1_SOFTWARE_BLANK(val) (((val) >> 12) & 1) +#define FBIINIT1_DRIVE_VIDEO_TIMING(val) (((val) >> 13) & 1) +#define FBIINIT1_DRIVE_VIDEO_BLANK(val) (((val) >> 14) & 1) +#define FBIINIT1_DRIVE_VIDEO_SYNC(val) (((val) >> 15) & 1) +#define FBIINIT1_DRIVE_VIDEO_DCLK(val) (((val) >> 16) & 1) +#define FBIINIT1_VIDEO_TIMING_VCLK(val) (((val) >> 17) & 1) +#define FBIINIT1_VIDEO_CLK_2X_DELAY(val) (((val) >> 18) & 3) +#define FBIINIT1_VIDEO_TIMING_SOURCE(val) (((val) >> 20) & 3) +#define FBIINIT1_ENABLE_24BPP_OUTPUT(val) (((val) >> 22) & 1) +#define FBIINIT1_ENABLE_SLI(val) (((val) >> 23) & 1) +#define FBIINIT1_X_VIDEO_TILES_BIT5(val) (((val) >> 24) & 1) /* voodoo 2 only */ +#define FBIINIT1_ENABLE_EDGE_FILTER(val) (((val) >> 25) & 1) +#define FBIINIT1_INVERT_VID_CLK_2X(val) (((val) >> 26) & 1) +#define FBIINIT1_VID_CLK_2X_SEL_DELAY(val) (((val) >> 27) & 3) +#define FBIINIT1_VID_CLK_DELAY(val) (((val) >> 29) & 3) +#define FBIINIT1_DISABLE_FAST_READAHEAD(val) (((val) >> 31) & 1) + +#define FBIINIT2_DISABLE_DITHER_SUB(val) (((val) >> 0) & 1) +#define FBIINIT2_DRAM_BANKING(val) (((val) >> 1) & 1) +#define FBIINIT2_ENABLE_TRIPLE_BUF(val) (((val) >> 4) & 1) +#define FBIINIT2_ENABLE_FAST_RAS_READ(val) (((val) >> 5) & 1) +#define FBIINIT2_ENABLE_GEN_DRAM_OE(val) (((val) >> 6) & 1) +#define FBIINIT2_ENABLE_FAST_READWRITE(val) (((val) >> 7) & 1) +#define FBIINIT2_ENABLE_PASSTHRU_DITHER(val) (((val) >> 8) & 1) +#define FBIINIT2_SWAP_BUFFER_ALGORITHM(val) (((val) >> 9) & 3) +#define FBIINIT2_VIDEO_BUFFER_OFFSET(val) (((val) >> 11) & 0x1ff) +#define FBIINIT2_ENABLE_DRAM_BANKING(val) (((val) >> 20) & 1) +#define FBIINIT2_ENABLE_DRAM_READ_FIFO(val) (((val) >> 21) & 1) +#define FBIINIT2_ENABLE_DRAM_REFRESH(val) (((val) >> 22) & 1) +#define FBIINIT2_REFRESH_LOAD_VALUE(val) (((val) >> 23) & 0x1ff) + +#define FBIINIT3_TRI_REGISTER_REMAP(val) (((val) >> 0) & 1) +#define FBIINIT3_VIDEO_FIFO_THRESH(val) (((val) >> 1) & 0x1f) +#define FBIINIT3_DISABLE_TMUS(val) (((val) >> 6) & 1) +#define FBIINIT3_FBI_MEMORY_TYPE(val) (((val) >> 8) & 7) +#define FBIINIT3_VGA_PASS_RESET_VAL(val) (((val) >> 11) & 1) +#define FBIINIT3_HARDCODE_PCI_BASE(val) (((val) >> 12) & 1) +#define FBIINIT3_FBI2TREX_DELAY(val) (((val) >> 13) & 0xf) +#define FBIINIT3_TREX2FBI_DELAY(val) (((val) >> 17) & 0x1f) +#define FBIINIT3_YORIGIN_SUBTRACT(val) (((val) >> 22) & 0x3ff) + +#define FBIINIT4_PCI_READ_WAITS(val) (((val) >> 0) & 1) +#define FBIINIT4_ENABLE_LFB_READAHEAD(val) (((val) >> 1) & 1) +#define FBIINIT4_MEMORY_FIFO_LWM(val) (((val) >> 2) & 0x3f) +#define FBIINIT4_MEMORY_FIFO_START_ROW(val) (((val) >> 8) & 0x3ff) +#define FBIINIT4_MEMORY_FIFO_STOP_ROW(val) (((val) >> 18) & 0x3ff) +#define FBIINIT4_VIDEO_CLOCKING_DELAY(val) (((val) >> 29) & 7) /* voodoo 2 only */ + +#define FBIINIT5_DISABLE_PCI_STOP(val) (((val) >> 0) & 1) /* voodoo 2 only */ +#define FBIINIT5_PCI_SLAVE_SPEED(val) (((val) >> 1) & 1) /* voodoo 2 only */ +#define FBIINIT5_DAC_DATA_OUTPUT_WIDTH(val) (((val) >> 2) & 1) /* voodoo 2 only */ +#define FBIINIT5_DAC_DATA_17_OUTPUT(val) (((val) >> 3) & 1) /* voodoo 2 only */ +#define FBIINIT5_DAC_DATA_18_OUTPUT(val) (((val) >> 4) & 1) /* voodoo 2 only */ +#define FBIINIT5_GENERIC_STRAPPING(val) (((val) >> 5) & 0xf) /* voodoo 2 only */ +#define FBIINIT5_BUFFER_ALLOCATION(val) (((val) >> 9) & 3) /* voodoo 2 only */ +#define FBIINIT5_DRIVE_VID_CLK_SLAVE(val) (((val) >> 11) & 1) /* voodoo 2 only */ +#define FBIINIT5_DRIVE_DAC_DATA_16(val) (((val) >> 12) & 1) /* voodoo 2 only */ +#define FBIINIT5_VCLK_INPUT_SELECT(val) (((val) >> 13) & 1) /* voodoo 2 only */ +#define FBIINIT5_MULTI_CVG_DETECT(val) (((val) >> 14) & 1) /* voodoo 2 only */ +#define FBIINIT5_SYNC_RETRACE_READS(val) (((val) >> 15) & 1) /* voodoo 2 only */ +#define FBIINIT5_ENABLE_RHBORDER_COLOR(val) (((val) >> 16) & 1) /* voodoo 2 only */ +#define FBIINIT5_ENABLE_LHBORDER_COLOR(val) (((val) >> 17) & 1) /* voodoo 2 only */ +#define FBIINIT5_ENABLE_BVBORDER_COLOR(val) (((val) >> 18) & 1) /* voodoo 2 only */ +#define FBIINIT5_ENABLE_TVBORDER_COLOR(val) (((val) >> 19) & 1) /* voodoo 2 only */ +#define FBIINIT5_DOUBLE_HORIZ(val) (((val) >> 20) & 1) /* voodoo 2 only */ +#define FBIINIT5_DOUBLE_VERT(val) (((val) >> 21) & 1) /* voodoo 2 only */ +#define FBIINIT5_ENABLE_16BIT_GAMMA(val) (((val) >> 22) & 1) /* voodoo 2 only */ +#define FBIINIT5_INVERT_DAC_HSYNC(val) (((val) >> 23) & 1) /* voodoo 2 only */ +#define FBIINIT5_INVERT_DAC_VSYNC(val) (((val) >> 24) & 1) /* voodoo 2 only */ +#define FBIINIT5_ENABLE_24BIT_DACDATA(val) (((val) >> 25) & 1) /* voodoo 2 only */ +#define FBIINIT5_ENABLE_INTERLACING(val) (((val) >> 26) & 1) /* voodoo 2 only */ +#define FBIINIT5_DAC_DATA_18_CONTROL(val) (((val) >> 27) & 1) /* voodoo 2 only */ +#define FBIINIT5_RASTERIZER_UNIT_MODE(val) (((val) >> 30) & 3) /* voodoo 2 only */ + +#define FBIINIT6_WINDOW_ACTIVE_COUNTER(val) (((val) >> 0) & 7) /* voodoo 2 only */ +#define FBIINIT6_WINDOW_DRAG_COUNTER(val) (((val) >> 3) & 0x1f) /* voodoo 2 only */ +#define FBIINIT6_SLI_SYNC_MASTER(val) (((val) >> 8) & 1) /* voodoo 2 only */ +#define FBIINIT6_DAC_DATA_22_OUTPUT(val) (((val) >> 9) & 3) /* voodoo 2 only */ +#define FBIINIT6_DAC_DATA_23_OUTPUT(val) (((val) >> 11) & 3) /* voodoo 2 only */ +#define FBIINIT6_SLI_SYNCIN_OUTPUT(val) (((val) >> 13) & 3) /* voodoo 2 only */ +#define FBIINIT6_SLI_SYNCOUT_OUTPUT(val) (((val) >> 15) & 3) /* voodoo 2 only */ +#define FBIINIT6_DAC_RD_OUTPUT(val) (((val) >> 17) & 3) /* voodoo 2 only */ +#define FBIINIT6_DAC_WR_OUTPUT(val) (((val) >> 19) & 3) /* voodoo 2 only */ +#define FBIINIT6_PCI_FIFO_LWM_RDY(val) (((val) >> 21) & 0x7f) /* voodoo 2 only */ +#define FBIINIT6_VGA_PASS_N_OUTPUT(val) (((val) >> 28) & 3) /* voodoo 2 only */ +#define FBIINIT6_X_VIDEO_TILES_BIT0(val) (((val) >> 30) & 1) /* voodoo 2 only */ + +#define FBIINIT7_GENERIC_STRAPPING(val) (((val) >> 0) & 0xff) /* voodoo 2 only */ +#define FBIINIT7_CMDFIFO_ENABLE(val) (((val) >> 8) & 1) /* voodoo 2 only */ +#define FBIINIT7_CMDFIFO_MEMORY_STORE(val) (((val) >> 9) & 1) /* voodoo 2 only */ +#define FBIINIT7_DISABLE_CMDFIFO_HOLES(val) (((val) >> 10) & 1) /* voodoo 2 only */ +#define FBIINIT7_CMDFIFO_READ_THRESH(val) (((val) >> 11) & 0x1f) /* voodoo 2 only */ +#define FBIINIT7_SYNC_CMDFIFO_WRITES(val) (((val) >> 16) & 1) /* voodoo 2 only */ +#define FBIINIT7_SYNC_CMDFIFO_READS(val) (((val) >> 17) & 1) /* voodoo 2 only */ +#define FBIINIT7_RESET_PCI_PACKER(val) (((val) >> 18) & 1) /* voodoo 2 only */ +#define FBIINIT7_ENABLE_CHROMA_STUFF(val) (((val) >> 19) & 1) /* voodoo 2 only */ +#define FBIINIT7_CMDFIFO_PCI_TIMEOUT(val) (((val) >> 20) & 0x7f) /* voodoo 2 only */ +#define FBIINIT7_ENABLE_TEXTURE_BURST(val) (((val) >> 27) & 1) /* voodoo 2 only */ + +#define TEXMODE_ENABLE_PERSPECTIVE(val) (((val) >> 0) & 1) +#define TEXMODE_MINIFICATION_FILTER(val) (((val) >> 1) & 1) +#define TEXMODE_MAGNIFICATION_FILTER(val) (((val) >> 2) & 1) +#define TEXMODE_CLAMP_NEG_W(val) (((val) >> 3) & 1) +#define TEXMODE_ENABLE_LOD_DITHER(val) (((val) >> 4) & 1) +#define TEXMODE_NCC_TABLE_SELECT(val) (((val) >> 5) & 1) +#define TEXMODE_CLAMP_S(val) (((val) >> 6) & 1) +#define TEXMODE_CLAMP_T(val) (((val) >> 7) & 1) +#define TEXMODE_FORMAT(val) (((val) >> 8) & 0xf) +#define TEXMODE_TC_ZERO_OTHER(val) (((val) >> 12) & 1) +#define TEXMODE_TC_SUB_CLOCAL(val) (((val) >> 13) & 1) +#define TEXMODE_TC_MSELECT(val) (((val) >> 14) & 7) +#define TEXMODE_TC_REVERSE_BLEND(val) (((val) >> 17) & 1) +#define TEXMODE_TC_ADD_ACLOCAL(val) (((val) >> 18) & 3) +#define TEXMODE_TC_INVERT_OUTPUT(val) (((val) >> 20) & 1) +#define TEXMODE_TCA_ZERO_OTHER(val) (((val) >> 21) & 1) +#define TEXMODE_TCA_SUB_CLOCAL(val) (((val) >> 22) & 1) +#define TEXMODE_TCA_MSELECT(val) (((val) >> 23) & 7) +#define TEXMODE_TCA_REVERSE_BLEND(val) (((val) >> 26) & 1) +#define TEXMODE_TCA_ADD_ACLOCAL(val) (((val) >> 27) & 3) +#define TEXMODE_TCA_INVERT_OUTPUT(val) (((val) >> 29) & 1) +#define TEXMODE_TRILINEAR(val) (((val) >> 30) & 1) +#define TEXMODE_SEQ_8_DOWNLD(val) (((val) >> 31) & 1) + +#define TEXLOD_LODMIN(val) (((val) >> 0) & 0x3f) +#define TEXLOD_LODMAX(val) (((val) >> 6) & 0x3f) +#define TEXLOD_LODBIAS(val) (((val) >> 12) & 0x3f) +#define TEXLOD_LOD_ODD(val) (((val) >> 18) & 1) +#define TEXLOD_LOD_TSPLIT(val) (((val) >> 19) & 1) +#define TEXLOD_LOD_S_IS_WIDER(val) (((val) >> 20) & 1) +#define TEXLOD_LOD_ASPECT(val) (((val) >> 21) & 3) +#define TEXLOD_LOD_ZEROFRAC(val) (((val) >> 23) & 1) +#define TEXLOD_TMULTIBASEADDR(val) (((val) >> 24) & 1) +#define TEXLOD_TDATA_SWIZZLE(val) (((val) >> 25) & 1) +#define TEXLOD_TDATA_SWAP(val) (((val) >> 26) & 1) +#define TEXLOD_TDIRECT_WRITE(val) (((val) >> 27) & 1) /* Voodoo 2 only */ + +#define TEXDETAIL_DETAIL_MAX(val) (((val) >> 0) & 0xff) +#define TEXDETAIL_DETAIL_BIAS(val) (((val) >> 8) & 0x3f) +#define TEXDETAIL_DETAIL_SCALE(val) (((val) >> 14) & 7) +#define TEXDETAIL_RGB_MIN_FILTER(val) (((val) >> 17) & 1) /* Voodoo 2 only */ +#define TEXDETAIL_RGB_MAG_FILTER(val) (((val) >> 18) & 1) /* Voodoo 2 only */ +#define TEXDETAIL_ALPHA_MIN_FILTER(val) (((val) >> 19) & 1) /* Voodoo 2 only */ +#define TEXDETAIL_ALPHA_MAG_FILTER(val) (((val) >> 20) & 1) /* Voodoo 2 only */ +#define TEXDETAIL_SEPARATE_RGBA_FILTER(val) (((val) >> 21) & 1) /* Voodoo 2 only */ + +#define TREXINIT_SEND_TMU_CONFIG(val) (((val) >> 18) & 1) + + +/************************************* + * + * Core types + * + *************************************/ + +struct voodoo_state; +struct poly_extra_data; + + +struct rgba +{ +#ifdef LSB_FIRST + UINT8 b, g, r, a; +#else + UINT8 a, r, g, b; +#endif +}; + + +union voodoo_reg +{ + INT32 i; + UINT32 u; + float f; + rgba rgb; +}; + + +typedef voodoo_reg rgb_union; + + +struct voodoo_stats +{ + UINT8 lastkey; /* last key state */ + UINT8 display; /* display stats? */ + INT32 swaps; /* total swaps */ + INT32 stalls; /* total stalls */ + INT32 total_triangles; /* total triangles */ + INT32 total_pixels_in; /* total pixels in */ + INT32 total_pixels_out; /* total pixels out */ + INT32 total_chroma_fail; /* total chroma fail */ + INT32 total_zfunc_fail; /* total z func fail */ + INT32 total_afunc_fail; /* total a func fail */ + INT32 total_clipped; /* total clipped */ + INT32 total_stippled; /* total stippled */ + INT32 lfb_writes; /* LFB writes */ + INT32 lfb_reads; /* LFB reads */ + INT32 reg_writes; /* register writes */ + INT32 reg_reads; /* register reads */ + INT32 tex_writes; /* texture writes */ + INT32 texture_mode[16]; /* 16 different texture modes */ + UINT8 render_override; /* render override */ + char buffer[1024]; /* string */ +}; + + +/* note that this structure is an even 64 bytes long */ +struct stats_block +{ + INT32 pixels_in; /* pixels in statistic */ + INT32 pixels_out; /* pixels out statistic */ + INT32 chroma_fail; /* chroma test fail statistic */ + INT32 zfunc_fail; /* z function test fail statistic */ + INT32 afunc_fail; /* alpha function test fail statistic */ + INT32 clip_fail; /* clipping fail statistic */ + INT32 stipple_count; /* stipple statistic */ + INT32 filler[64/4 - 7]; /* pad this structure to 64 bytes */ +}; + + +struct fifo_state +{ + UINT32 * base; /* base of the FIFO */ + INT32 size; /* size of the FIFO */ + INT32 in; /* input pointer */ + INT32 out; /* output pointer */ +}; + + +struct cmdfifo_info +{ + UINT8 enable; /* enabled? */ + UINT8 count_holes; /* count holes? */ + UINT32 base; /* base address in framebuffer RAM */ + UINT32 end; /* end address in framebuffer RAM */ + UINT32 rdptr; /* current read pointer */ + UINT32 amin; /* minimum address */ + UINT32 amax; /* maximum address */ + UINT32 depth; /* current depth */ + UINT32 holes; /* number of holes */ +}; + + +struct pci_state +{ + fifo_state fifo; /* PCI FIFO */ + UINT32 init_enable; /* initEnable value */ + UINT8 stall_state; /* state of the system if we're stalled */ + UINT8 op_pending; /* true if an operation is pending */ + attotime op_end_time; /* time when the pending operation ends */ + emu_timer * continue_timer; /* timer to use to continue processing */ + UINT32 fifo_mem[64*2]; /* memory backing the PCI FIFO */ +}; + + +struct ncc_table +{ + UINT8 dirty; /* is the texel lookup dirty? */ + voodoo_reg * reg; /* pointer to our registers */ + INT32 ir[4], ig[4], ib[4]; /* I values for R,G,B */ + INT32 qr[4], qg[4], qb[4]; /* Q values for R,G,B */ + INT32 y[16]; /* Y values */ + rgb_t * palette; /* pointer to associated RGB palette */ + rgb_t * palettea; /* pointer to associated ARGB palette */ + rgb_t texel[256]; /* texel lookup */ +}; + + +struct tmu_state +{ + UINT8 * ram; /* pointer to our RAM */ + UINT32 mask; /* mask to apply to pointers */ + voodoo_reg * reg; /* pointer to our register base */ + UINT32 regdirty; /* true if the LOD/mode/base registers have changed */ + + UINT32 texaddr_mask; /* mask for texture address */ + UINT8 texaddr_shift; /* shift for texture address */ + + INT64 starts, startt; /* starting S,T (14.18) */ + INT64 startw; /* starting W (2.30) */ + INT64 dsdx, dtdx; /* delta S,T per X */ + INT64 dwdx; /* delta W per X */ + INT64 dsdy, dtdy; /* delta S,T per Y */ + INT64 dwdy; /* delta W per Y */ + + INT32 lodmin, lodmax; /* min, max LOD values */ + INT32 lodbias; /* LOD bias */ + UINT32 lodmask; /* mask of available LODs */ + UINT32 lodoffset[9]; /* offset of texture base for each LOD */ + INT32 detailmax; /* detail clamp */ + INT32 detailbias; /* detail bias */ + UINT8 detailscale; /* detail scale */ + + UINT32 wmask; /* mask for the current texture width */ + UINT32 hmask; /* mask for the current texture height */ + + UINT32 bilinear_mask; /* mask for bilinear resolution (0xf0 for V1, 0xff for V2) */ + + ncc_table ncc[2]; /* two NCC tables */ + + rgb_t * lookup; /* currently selected lookup */ + rgb_t * texel[16]; /* texel lookups for each format */ + + rgb_t palette[256]; /* palette lookup table */ + rgb_t palettea[256]; /* palette+alpha lookup table */ +}; + + +struct tmu_shared_state +{ + rgb_t rgb332[256]; /* RGB 3-3-2 lookup table */ + rgb_t alpha8[256]; /* alpha 8-bit lookup table */ + rgb_t int8[256]; /* intensity 8-bit lookup table */ + rgb_t ai44[256]; /* alpha, intensity 4-4 lookup table */ + + rgb_t rgb565[65536]; /* RGB 5-6-5 lookup table */ + rgb_t argb1555[65536]; /* ARGB 1-5-5-5 lookup table */ + rgb_t argb4444[65536]; /* ARGB 4-4-4-4 lookup table */ +}; + + +struct setup_vertex +{ + float x, y; /* X, Y coordinates */ + float a, r, g, b; /* A, R, G, B values */ + float z, wb; /* Z and broadcast W values */ + float w0, s0, t0; /* W, S, T for TMU 0 */ + float w1, s1, t1; /* W, S, T for TMU 1 */ +}; + + +struct fbi_state +{ + UINT8 * ram; /* pointer to frame buffer RAM */ + UINT32 mask; /* mask to apply to pointers */ + UINT32 rgboffs[3]; /* word offset to 3 RGB buffers */ + UINT32 auxoffs; /* word offset to 1 aux buffer */ + + UINT8 frontbuf; /* front buffer index */ + UINT8 backbuf; /* back buffer index */ + UINT8 swaps_pending; /* number of pending swaps */ + UINT8 video_changed; /* did the frontbuffer video change? */ + + UINT32 yorigin; /* Y origin subtract value */ + UINT32 lfb_base; /* base of LFB in memory */ + UINT8 lfb_stride; /* stride of LFB accesses in bits */ + + UINT32 width; /* width of current frame buffer */ + UINT32 height; /* height of current frame buffer */ + UINT32 xoffs; /* horizontal offset (back porch) */ + UINT32 yoffs; /* vertical offset (back porch) */ + UINT32 vsyncscan; /* vertical sync scanline */ + UINT32 rowpixels; /* pixels per row */ + UINT32 tile_width; /* width of video tiles */ + UINT32 tile_height; /* height of video tiles */ + UINT32 x_tiles; /* number of tiles in the X direction */ + + emu_timer * vblank_timer; /* VBLANK timer */ + UINT8 vblank; /* VBLANK state */ + UINT8 vblank_count; /* number of VBLANKs since last swap */ + UINT8 vblank_swap_pending; /* a swap is pending, waiting for a vblank */ + UINT8 vblank_swap; /* swap when we hit this count */ + UINT8 vblank_dont_swap; /* don't actually swap when we hit this point */ + + /* triangle setup info */ + UINT8 cheating_allowed; /* allow cheating? */ + INT32 sign; /* triangle sign */ + INT16 ax, ay; /* vertex A x,y (12.4) */ + INT16 bx, by; /* vertex B x,y (12.4) */ + INT16 cx, cy; /* vertex C x,y (12.4) */ + INT32 startr, startg, startb, starta; /* starting R,G,B,A (12.12) */ + INT32 startz; /* starting Z (20.12) */ + INT64 startw; /* starting W (16.32) */ + INT32 drdx, dgdx, dbdx, dadx; /* delta R,G,B,A per X */ + INT32 dzdx; /* delta Z per X */ + INT64 dwdx; /* delta W per X */ + INT32 drdy, dgdy, dbdy, dady; /* delta R,G,B,A per Y */ + INT32 dzdy; /* delta Z per Y */ + INT64 dwdy; /* delta W per Y */ + + stats_block lfb_stats; /* LFB-access statistics */ + + UINT8 sverts; /* number of vertices ready */ + setup_vertex svert[3]; /* 3 setup vertices */ + + fifo_state fifo; /* framebuffer memory fifo */ + cmdfifo_info cmdfifo[2]; /* command FIFOs */ + + UINT8 fogblend[64]; /* 64-entry fog table */ + UINT8 fogdelta[64]; /* 64-entry fog table */ + UINT8 fogdelta_mask; /* mask for for delta (0xff for V1, 0xfc for V2) */ + + rgb_t pen[65536]; /* mapping from pixels to pens */ + rgb_t clut[512]; /* clut gamma data */ + UINT8 clut_dirty; /* do we need to recompute? */ +}; + + +struct dac_state +{ + UINT8 reg[8]; /* 8 registers */ + UINT8 read_result; /* pending read result */ +}; + + +struct raster_info +{ + raster_info * next; /* pointer to next entry with the same hash */ + poly_draw_scanline_func callback; /* callback pointer */ + UINT8 is_generic; /* TRUE if this is one of the generic rasterizers */ + UINT8 display; /* display index */ + UINT32 hits; /* how many hits (pixels) we've used this for */ + UINT32 polys; /* how many polys we've used this for */ + UINT32 eff_color_path; /* effective fbzColorPath value */ + UINT32 eff_alpha_mode; /* effective alphaMode value */ + UINT32 eff_fog_mode; /* effective fogMode value */ + UINT32 eff_fbz_mode; /* effective fbzMode value */ + UINT32 eff_tex_mode_0; /* effective textureMode value for TMU #0 */ + UINT32 eff_tex_mode_1; /* effective textureMode value for TMU #1 */ + UINT32 hash; +}; + + +struct poly_extra_data +{ + voodoo_state * state; /* pointer back to the voodoo state */ + raster_info * info; /* pointer to rasterizer information */ + + INT16 ax, ay; /* vertex A x,y (12.4) */ + INT32 startr, startg, startb, starta; /* starting R,G,B,A (12.12) */ + INT32 startz; /* starting Z (20.12) */ + INT64 startw; /* starting W (16.32) */ + INT32 drdx, dgdx, dbdx, dadx; /* delta R,G,B,A per X */ + INT32 dzdx; /* delta Z per X */ + INT64 dwdx; /* delta W per X */ + INT32 drdy, dgdy, dbdy, dady; /* delta R,G,B,A per Y */ + INT32 dzdy; /* delta Z per Y */ + INT64 dwdy; /* delta W per Y */ + + INT64 starts0, startt0; /* starting S,T (14.18) */ + INT64 startw0; /* starting W (2.30) */ + INT64 ds0dx, dt0dx; /* delta S,T per X */ + INT64 dw0dx; /* delta W per X */ + INT64 ds0dy, dt0dy; /* delta S,T per Y */ + INT64 dw0dy; /* delta W per Y */ + INT32 lodbase0; /* used during rasterization */ + + INT64 starts1, startt1; /* starting S,T (14.18) */ + INT64 startw1; /* starting W (2.30) */ + INT64 ds1dx, dt1dx; /* delta S,T per X */ + INT64 dw1dx; /* delta W per X */ + INT64 ds1dy, dt1dy; /* delta S,T per Y */ + INT64 dw1dy; /* delta W per Y */ + INT32 lodbase1; /* used during rasterization */ + + UINT16 dither[16]; /* dither matrix, for fastfill */ +}; + + +struct banshee_info +{ + UINT32 io[0x40]; /* I/O registers */ + UINT32 agp[0x80]; /* AGP registers */ + UINT8 vga[0x20]; /* VGA registers */ + UINT8 crtc[0x27]; /* VGA CRTC registers */ + UINT8 seq[0x05]; /* VGA sequencer registers */ + UINT8 gc[0x05]; /* VGA graphics controller registers */ + UINT8 att[0x15]; /* VGA attribute registers */ + UINT8 attff; /* VGA attribute flip-flop */ + + UINT32 blt_regs[0x20]; /* 2D Blitter registers */ + UINT32 blt_dst_base; + UINT32 blt_dst_x; + UINT32 blt_dst_y; + UINT32 blt_dst_width; + UINT32 blt_dst_height; + UINT32 blt_dst_stride; + UINT32 blt_dst_bpp; + UINT32 blt_cmd; + UINT32 blt_src_base; + UINT32 blt_src_x; + UINT32 blt_src_y; + UINT32 blt_src_width; + UINT32 blt_src_height; + UINT32 blt_src_stride; + UINT32 blt_src_bpp; +}; + + +struct voodoo_state +{ + UINT8 index; /* index of board */ + voodoo_device *device; /* pointer to our containing device */ + screen_device *screen; /* the screen we are acting on */ + device_t *cpu; /* the CPU we interact with */ + UINT8 type; /* type of system */ + UINT8 chipmask; /* mask for which chips are available */ + UINT32 freq; /* operating frequency */ + attoseconds_t attoseconds_per_cycle; /* attoseconds per cycle */ + UINT32 extra_cycles; /* extra cycles not yet accounted for */ + int trigger; /* trigger used for stalling */ + + voodoo_reg reg[0x400]; /* raw registers */ + const UINT8 * regaccess; /* register access array */ + const char *const * regnames; /* register names array */ + UINT8 alt_regmap; /* enable alternate register map? */ + + pci_state pci; /* PCI state */ + dac_state dac; /* DAC state */ + + fbi_state fbi; /* FBI states */ + tmu_state tmu[MAX_TMU]; /* TMU states */ + tmu_shared_state tmushare; /* TMU shared state */ + banshee_info banshee; /* Banshee state */ + + legacy_poly_manager * poly; /* polygon manager */ + stats_block * thread_stats; /* per-thread statistics */ + + voodoo_stats stats; /* internal statistics */ + + offs_t last_status_pc; /* PC of last status description (for logging) */ + UINT32 last_status_value; /* value of last status read (for logging) */ + + int next_rasterizer; /* next rasterizer index */ + raster_info rasterizer[MAX_RASTERIZERS]; /* array of rasterizers */ + raster_info * raster_hash[RASTER_HASH_SIZE]; /* hash table of rasterizers */ + + bool send_config; + UINT32 tmu_config; +}; + + + +/************************************* + * + * Inline FIFO management + * + *************************************/ + +INLINE void fifo_reset(fifo_state *f) +{ + f->in = f->out = 0; +} + + +INLINE void fifo_add(fifo_state *f, UINT32 data) +{ + INT32 next_in; + + /* compute the value of 'in' after we add this item */ + next_in = f->in + 1; + if (next_in >= f->size) + next_in = 0; + + /* as long as it's not equal to the output pointer, we can do it */ + if (next_in != f->out) + { + f->base[f->in] = data; + f->in = next_in; + } +} + + +INLINE UINT32 fifo_remove(fifo_state *f) +{ + UINT32 data = 0xffffffff; + + /* as long as we have data, we can do it */ + if (f->out != f->in) + { + INT32 next_out; + + /* fetch the data */ + data = f->base[f->out]; + + /* advance the output pointer */ + next_out = f->out + 1; + if (next_out >= f->size) + next_out = 0; + f->out = next_out; + } + return data; +} + + +INLINE UINT32 fifo_peek(fifo_state *f) +{ + return f->base[f->out]; +} + + +INLINE int fifo_empty(fifo_state *f) +{ + return (f->in == f->out); +} + + +INLINE int fifo_full(fifo_state *f) +{ + return (f->in + 1 == f->out || (f->in == f->size - 1 && f->out == 0)); +} + + +INLINE INT32 fifo_items(fifo_state *f) +{ + INT32 items = f->in - f->out; + if (items < 0) + items += f->size; + return items; +} + + +INLINE INT32 fifo_space(fifo_state *f) +{ + INT32 items = f->in - f->out; + if (items < 0) + items += f->size; + return f->size - 1 - items; +} + + + +/************************************* + * + * Computes a fast 16.16 reciprocal + * of a 16.32 value; used for + * computing 1/w in the rasterizer. + * + * Since it is trivial to also + * compute log2(1/w) = -log2(w) at + * the same time, we do that as well + * to 16.8 precision for LOD + * calculations. + * + * On a Pentium M, this routine is + * 20% faster than a 64-bit integer + * divide and also produces the log + * for free. + * + *************************************/ + +INLINE INT32 fast_reciplog(INT64 value, INT32 *log2) +{ + extern UINT32 voodoo_reciplog[]; + UINT32 temp, recip, rlog; + UINT32 interp; + UINT32 *table; + int neg = FALSE; + int lz, exp = 0; + + /* always work with unsigned numbers */ + if (value < 0) + { + value = -value; + neg = TRUE; + } + + /* if we've spilled out of 32 bits, push it down under 32 */ + if (value & U64(0xffff00000000)) + { + temp = (UINT32)(value >> 16); + exp -= 16; + } + else + temp = (UINT32)value; + + /* if the resulting value is 0, the reciprocal is infinite */ + if (UNEXPECTED(temp == 0)) + { + *log2 = 1000 << LOG_OUTPUT_PREC; + return neg ? 0x80000000 : 0x7fffffff; + } + + /* determine how many leading zeros in the value and shift it up high */ + lz = count_leading_zeros(temp); + temp <<= lz; + exp += lz; + + /* compute a pointer to the table entries we want */ + /* math is a bit funny here because we shift one less than we need to in order */ + /* to account for the fact that there are two UINT32's per table entry */ + table = &voodoo_reciplog[(temp >> (31 - RECIPLOG_LOOKUP_BITS - 1)) & ((2 << RECIPLOG_LOOKUP_BITS) - 2)]; + + /* compute the interpolation value */ + interp = (temp >> (31 - RECIPLOG_LOOKUP_BITS - 8)) & 0xff; + + /* do a linear interpolatation between the two nearest table values */ + /* for both the log and the reciprocal */ + rlog = (table[1] * (0x100 - interp) + table[3] * interp) >> 8; + recip = (table[0] * (0x100 - interp) + table[2] * interp) >> 8; + + /* the log result is the fractional part of the log; round it to the output precision */ + rlog = (rlog + (1 << (RECIPLOG_LOOKUP_PREC - LOG_OUTPUT_PREC - 1))) >> (RECIPLOG_LOOKUP_PREC - LOG_OUTPUT_PREC); + + /* the exponent is the non-fractional part of the log; normally, we would subtract it from rlog */ + /* but since we want the log(1/value) = -log(value), we subtract rlog from the exponent */ + *log2 = ((exp - (31 - RECIPLOG_INPUT_PREC)) << LOG_OUTPUT_PREC) - rlog; + + /* adjust the exponent to account for all the reciprocal-related parameters to arrive at a final shift amount */ + exp += (RECIP_OUTPUT_PREC - RECIPLOG_LOOKUP_PREC) - (31 - RECIPLOG_INPUT_PREC); + + /* shift by the exponent */ + if (exp < 0) + recip >>= -exp; + else + recip <<= exp; + + /* on the way out, apply the original sign to the reciprocal */ + return neg ? -recip : recip; +} + + + +/************************************* + * + * Float-to-int conversions + * + *************************************/ + +INLINE INT32 float_to_int32(UINT32 data, int fixedbits) +{ + int exponent = ((data >> 23) & 0xff) - 127 - 23 + fixedbits; + INT32 result = (data & 0x7fffff) | 0x800000; + if (exponent < 0) + { + if (exponent > -32) + result >>= -exponent; + else + result = 0; + } + else + { + if (exponent < 32) + result <<= exponent; + else + result = 0x7fffffff; + } + if (data & 0x80000000) + result = -result; + return result; +} + + +INLINE INT64 float_to_int64(UINT32 data, int fixedbits) +{ + int exponent = ((data >> 23) & 0xff) - 127 - 23 + fixedbits; + INT64 result = (data & 0x7fffff) | 0x800000; + if (exponent < 0) + { + if (exponent > -64) + result >>= -exponent; + else + result = 0; + } + else + { + if (exponent < 64) + result <<= exponent; + else + result = U64(0x7fffffffffffffff); + } + if (data & 0x80000000) + result = -result; + return result; +} + + + +/************************************* + * + * Rasterizer inlines + * + *************************************/ + +INLINE UINT32 normalize_color_path(UINT32 eff_color_path) +{ + /* ignore the subpixel adjust and texture enable flags */ + eff_color_path &= ~((1 << 26) | (1 << 27)); + + return eff_color_path; +} + + +INLINE UINT32 normalize_alpha_mode(UINT32 eff_alpha_mode) +{ + /* always ignore alpha ref value */ + eff_alpha_mode &= ~(0xff << 24); + + /* if not doing alpha testing, ignore the alpha function and ref value */ + if (!ALPHAMODE_ALPHATEST(eff_alpha_mode)) + eff_alpha_mode &= ~(7 << 1); + + /* if not doing alpha blending, ignore the source and dest blending factors */ + if (!ALPHAMODE_ALPHABLEND(eff_alpha_mode)) + eff_alpha_mode &= ~((15 << 8) | (15 << 12) | (15 << 16) | (15 << 20)); + + return eff_alpha_mode; +} + + +INLINE UINT32 normalize_fog_mode(UINT32 eff_fog_mode) +{ + /* if not doing fogging, ignore all the other fog bits */ + if (!FOGMODE_ENABLE_FOG(eff_fog_mode)) + eff_fog_mode = 0; + + return eff_fog_mode; +} + + +INLINE UINT32 normalize_fbz_mode(UINT32 eff_fbz_mode) +{ + /* ignore the draw buffer */ + eff_fbz_mode &= ~(3 << 14); + + return eff_fbz_mode; +} + + +INLINE UINT32 normalize_tex_mode(UINT32 eff_tex_mode) +{ + /* ignore the NCC table and seq_8_downld flags */ + eff_tex_mode &= ~((1 << 5) | (1 << 31)); + + /* classify texture formats into 3 format categories */ + if (TEXMODE_FORMAT(eff_tex_mode) < 8) + eff_tex_mode = (eff_tex_mode & ~(0xf << 8)) | (0 << 8); + else if (TEXMODE_FORMAT(eff_tex_mode) >= 10 && TEXMODE_FORMAT(eff_tex_mode) <= 12) + eff_tex_mode = (eff_tex_mode & ~(0xf << 8)) | (10 << 8); + else + eff_tex_mode = (eff_tex_mode & ~(0xf << 8)) | (8 << 8); + + return eff_tex_mode; +} + + +INLINE UINT32 compute_raster_hash(const raster_info *info) +{ + UINT32 hash; + + /* make a hash */ + hash = info->eff_color_path; + hash = (hash << 1) | (hash >> 31); + hash ^= info->eff_fbz_mode; + hash = (hash << 1) | (hash >> 31); + hash ^= info->eff_alpha_mode; + hash = (hash << 1) | (hash >> 31); + hash ^= info->eff_fog_mode; + hash = (hash << 1) | (hash >> 31); + hash ^= info->eff_tex_mode_0; + hash = (hash << 1) | (hash >> 31); + hash ^= info->eff_tex_mode_1; + + return hash % RASTER_HASH_SIZE; +} + + + +/************************************* + * + * Dithering macros + * + *************************************/ + +/* note that these equations and the dither matrixes have + been confirmed to be exact matches to the real hardware */ +#define DITHER_RB(val,dith) ((((val) << 1) - ((val) >> 4) + ((val) >> 7) + (dith)) >> 1) +#define DITHER_G(val,dith) ((((val) << 2) - ((val) >> 4) + ((val) >> 6) + (dith)) >> 2) + +#define DECLARE_DITHER_POINTERS \ + const UINT8 *dither_lookup = NULL; \ + const UINT8 *dither4 = NULL; \ + const UINT8 *dither = NULL +#define DECLARE_DITHER_POINTERS_NO_DITHER_VAR \ + const UINT8 *dither_lookup = NULL; +#define COMPUTE_DITHER_POINTERS(FBZMODE, YY) \ +do \ +{ \ + /* compute the dithering pointers */ \ + if (FBZMODE_ENABLE_DITHERING(FBZMODE)) \ + { \ + dither4 = &dither_matrix_4x4[((YY) & 3) * 4]; \ + if (FBZMODE_DITHER_TYPE(FBZMODE) == 0) \ + { \ + dither = dither4; \ + dither_lookup = &dither4_lookup[(YY & 3) << 11]; \ + } \ + else \ + { \ + dither = &dither_matrix_2x2[((YY) & 3) * 4]; \ + dither_lookup = &dither2_lookup[(YY & 3) << 11]; \ + } \ + } \ +} \ +while (0) + +#define COMPUTE_DITHER_POINTERS_NO_DITHER_VAR(FBZMODE, YY) \ +do \ +{ \ + /* compute the dithering pointers */ \ + if (FBZMODE_ENABLE_DITHERING(FBZMODE)) \ + { \ + if (FBZMODE_DITHER_TYPE(FBZMODE) == 0) \ + { \ + dither_lookup = &dither4_lookup[(YY & 3) << 11]; \ + } \ + else \ + { \ + dither_lookup = &dither2_lookup[(YY & 3) << 11]; \ + } \ + } \ +} \ +while (0) + +#define APPLY_DITHER(FBZMODE, XX, DITHER_LOOKUP, RR, GG, BB) \ +do \ +{ \ + /* apply dithering */ \ + if (FBZMODE_ENABLE_DITHERING(FBZMODE)) \ + { \ + /* look up the dither value from the appropriate matrix */ \ + const UINT8 *dith = &DITHER_LOOKUP[((XX) & 3) << 1]; \ + \ + /* apply dithering to R,G,B */ \ + (RR) = dith[((RR) << 3) + 0]; \ + (GG) = dith[((GG) << 3) + 1]; \ + (BB) = dith[((BB) << 3) + 0]; \ + } \ + else \ + { \ + (RR) >>= 3; \ + (GG) >>= 2; \ + (BB) >>= 3; \ + } \ +} \ +while (0) + + + +/************************************* + * + * Clamping macros + * + *************************************/ + +#define CLAMPED_ARGB(ITERR, ITERG, ITERB, ITERA, FBZCP, RESULT) \ +do \ +{ \ + r = (INT32)(ITERR) >> 12; \ + g = (INT32)(ITERG) >> 12; \ + b = (INT32)(ITERB) >> 12; \ + a = (INT32)(ITERA) >> 12; \ + \ + if (FBZCP_RGBZW_CLAMP(FBZCP) == 0) \ + { \ + r &= 0xfff; \ + RESULT.rgb.r = r; \ + if (r == 0xfff) \ + RESULT.rgb.r = 0; \ + else if (r == 0x100) \ + RESULT.rgb.r = 0xff; \ + \ + g &= 0xfff; \ + RESULT.rgb.g = g; \ + if (g == 0xfff) \ + RESULT.rgb.g = 0; \ + else if (g == 0x100) \ + RESULT.rgb.g = 0xff; \ + \ + b &= 0xfff; \ + RESULT.rgb.b = b; \ + if (b == 0xfff) \ + RESULT.rgb.b = 0; \ + else if (b == 0x100) \ + RESULT.rgb.b = 0xff; \ + \ + a &= 0xfff; \ + RESULT.rgb.a = a; \ + if (a == 0xfff) \ + RESULT.rgb.a = 0; \ + else if (a == 0x100) \ + RESULT.rgb.a = 0xff; \ + } \ + else \ + { \ + RESULT.rgb.r = (r < 0) ? 0 : (r > 0xff) ? 0xff : r; \ + RESULT.rgb.g = (g < 0) ? 0 : (g > 0xff) ? 0xff : g; \ + RESULT.rgb.b = (b < 0) ? 0 : (b > 0xff) ? 0xff : b; \ + RESULT.rgb.a = (a < 0) ? 0 : (a > 0xff) ? 0xff : a; \ + } \ +} \ +while (0) + +INLINE rgbaint_t ATTR_FORCE_INLINE clampARGB(const rgbaint_t &iterargb, UINT32 FBZCP) +{ + rgbaint_t result(iterargb); + //rgbaint_t colorint((INT32) (itera>>12), (INT32) (iterr>>12), (INT32) (iterg>>12), (INT32) (iterb>>12)); + result.shr_imm(12); + + if (FBZCP_RGBZW_CLAMP(FBZCP) == 0) + { + //r &= 0xfff; + result.and_imm(0xfff); + //if (r == 0xfff) + rgbaint_t temp(result); + temp.cmpeq_imm(0xfff); + // result.rgb.r = 0; + result.andnot_reg(temp); + //else if (r == 0x100) + temp.set(result); + temp.cmpeq_imm(0x100); + // Shift by 1 so that INT32 result is not negative + temp.shr_imm(1); + // result.rgb.r = 0xff; + result.or_reg(temp); + } + else + { + //return colorint.to_rgba_clamp(); + } + result.clamp_to_uint8(); + return result; +} + +#define CLAMPED_Z(ITERZ, FBZCP, RESULT) \ +do \ +{ \ + (RESULT) = (INT32)(ITERZ) >> 12; \ + if (FBZCP_RGBZW_CLAMP(FBZCP) == 0) \ + { \ + (RESULT) &= 0xfffff; \ + if ((RESULT) == 0xfffff) \ + (RESULT) = 0; \ + else if ((RESULT) == 0x10000) \ + (RESULT) = 0xffff; \ + else \ + (RESULT) &= 0xffff; \ + } \ + else \ + { \ + CLAMP((RESULT), 0, 0xffff); \ + } \ +} \ +while (0) + + +#define CLAMPED_W(ITERW, FBZCP, RESULT) \ +do \ +{ \ + (RESULT) = (INT16)((ITERW) >> 32); \ + if (FBZCP_RGBZW_CLAMP(FBZCP) == 0) \ + { \ + (RESULT) &= 0xffff; \ + if ((RESULT) == 0xffff) \ + (RESULT) = 0; \ + else if ((RESULT) == 0x100) \ + (RESULT) = 0xff; \ + (RESULT) &= 0xff; \ + } \ + else \ + { \ + CLAMP((RESULT), 0, 0xff); \ + } \ +} \ +while (0) + + + +/************************************* + * + * Chroma keying macro + * + *************************************/ + +#define APPLY_CHROMAKEY(VV, STATS, FBZMODE, COLOR) \ +do \ +{ \ + if (FBZMODE_ENABLE_CHROMAKEY(FBZMODE)) \ + { \ + /* non-range version */ \ + if (!CHROMARANGE_ENABLE((VV)->reg[chromaRange].u)) \ + { \ + if (((COLOR.u ^ (VV)->reg[chromaKey].u) & 0xffffff) == 0) \ + { \ + (STATS)->chroma_fail++; \ + goto skipdrawdepth; \ + } \ + } \ + \ + /* tricky range version */ \ + else \ + { \ + INT32 low, high, test; \ + int results = 0; \ + \ + /* check blue */ \ + low = (VV)->reg[chromaKey].rgb.b; \ + high = (VV)->reg[chromaRange].rgb.b; \ + test = COLOR.rgb.b; \ + results = (test >= low && test <= high); \ + results ^= CHROMARANGE_BLUE_EXCLUSIVE((VV)->reg[chromaRange].u); \ + results <<= 1; \ + \ + /* check green */ \ + low = (VV)->reg[chromaKey].rgb.g; \ + high = (VV)->reg[chromaRange].rgb.g; \ + test = COLOR.rgb.g; \ + results |= (test >= low && test <= high); \ + results ^= CHROMARANGE_GREEN_EXCLUSIVE((VV)->reg[chromaRange].u); \ + results <<= 1; \ + \ + /* check red */ \ + low = (VV)->reg[chromaKey].rgb.r; \ + high = (VV)->reg[chromaRange].rgb.r; \ + test = COLOR.rgb.r; \ + results |= (test >= low && test <= high); \ + results ^= CHROMARANGE_RED_EXCLUSIVE((VV)->reg[chromaRange].u); \ + \ + /* final result */ \ + if (CHROMARANGE_UNION_MODE((VV)->reg[chromaRange].u)) \ + { \ + if (results != 0) \ + { \ + (STATS)->chroma_fail++; \ + goto skipdrawdepth; \ + } \ + } \ + else \ + { \ + if (results == 7) \ + { \ + (STATS)->chroma_fail++; \ + goto skipdrawdepth; \ + } \ + } \ + } \ + } \ +} \ +while (0) + +INLINE bool ATTR_FORCE_INLINE chromaKeyTest(voodoo_state *v, stats_block *stats, UINT32 fbzModeReg, rgbaint_t rgbaIntColor) +{ + if (FBZMODE_ENABLE_CHROMAKEY(fbzModeReg)) + { + rgb_union color; + color.u = (rgbaIntColor.get_a()<<24) | (rgbaIntColor.get_r()<<16) | (rgbaIntColor.get_g()<<8) | rgbaIntColor.get_b(); + /* non-range version */ + if (!CHROMARANGE_ENABLE(v->reg[chromaRange].u)) + { + if (((color.u ^ v->reg[chromaKey].u) & 0xffffff) == 0) + { + stats->chroma_fail++; + return false; + } + } + + /* tricky range version */ + else + { + INT32 low, high, test; + int results = 0; + + /* check blue */ + low = v->reg[chromaKey].rgb.b; + high = v->reg[chromaRange].rgb.b; + test = color.rgb.b; + results = (test >= low && test <= high); + results ^= CHROMARANGE_BLUE_EXCLUSIVE(v->reg[chromaRange].u); + results <<= 1; + + /* check green */ + low = v->reg[chromaKey].rgb.g; + high = v->reg[chromaRange].rgb.g; + test = color.rgb.g; + results |= (test >= low && test <= high); + results ^= CHROMARANGE_GREEN_EXCLUSIVE(v->reg[chromaRange].u); + results <<= 1; + + /* check red */ + low = v->reg[chromaKey].rgb.r; + high = v->reg[chromaRange].rgb.r; + test = color.rgb.r; + results |= (test >= low && test <= high); + results ^= CHROMARANGE_RED_EXCLUSIVE(v->reg[chromaRange].u); + + /* final result */ + if (CHROMARANGE_UNION_MODE(v->reg[chromaRange].u)) + { + if (results != 0) + { + stats->chroma_fail++; + return false; + } + } + else + { + if (results == 7) + { + stats->chroma_fail++; + return false; + } + } + } + } + return true; +} + + + +/************************************* + * + * Alpha masking macro + * + *************************************/ + +#define APPLY_ALPHAMASK(VV, STATS, FBZMODE, AA) \ +do \ +{ \ + if (FBZMODE_ENABLE_ALPHA_MASK(FBZMODE)) \ + { \ + if (((AA) & 1) == 0) \ + { \ + (STATS)->afunc_fail++; \ + goto skipdrawdepth; \ + } \ + } \ +} \ +while (0) + +INLINE bool alphaMaskTest(stats_block *stats, UINT32 fbzModeReg, UINT8 alpha) +{ + if (FBZMODE_ENABLE_ALPHA_MASK(fbzModeReg)) + { + if ((alpha & 1) == 0) + { + stats->afunc_fail++; + return false; + } + } + return true; +} + +/************************************* + * + * Alpha testing macro + * + *************************************/ + +#define APPLY_ALPHATEST(VV, STATS, ALPHAMODE, AA) \ +do \ +{ \ + if (ALPHAMODE_ALPHATEST(ALPHAMODE)) \ + { \ + UINT8 alpharef = (VV)->reg[alphaMode].rgb.a; \ + switch (ALPHAMODE_ALPHAFUNCTION(ALPHAMODE)) \ + { \ + case 0: /* alphaOP = never */ \ + (STATS)->afunc_fail++; \ + goto skipdrawdepth; \ + \ + case 1: /* alphaOP = less than */ \ + if ((AA) >= alpharef) \ + { \ + (STATS)->afunc_fail++; \ + goto skipdrawdepth; \ + } \ + break; \ + \ + case 2: /* alphaOP = equal */ \ + if ((AA) != alpharef) \ + { \ + (STATS)->afunc_fail++; \ + goto skipdrawdepth; \ + } \ + break; \ + \ + case 3: /* alphaOP = less than or equal */ \ + if ((AA) > alpharef) \ + { \ + (STATS)->afunc_fail++; \ + goto skipdrawdepth; \ + } \ + break; \ + \ + case 4: /* alphaOP = greater than */ \ + if ((AA) <= alpharef) \ + { \ + (STATS)->afunc_fail++; \ + goto skipdrawdepth; \ + } \ + break; \ + \ + case 5: /* alphaOP = not equal */ \ + if ((AA) == alpharef) \ + { \ + (STATS)->afunc_fail++; \ + goto skipdrawdepth; \ + } \ + break; \ + \ + case 6: /* alphaOP = greater than or equal */ \ + if ((AA) < alpharef) \ + { \ + (STATS)->afunc_fail++; \ + goto skipdrawdepth; \ + } \ + break; \ + \ + case 7: /* alphaOP = always */ \ + break; \ + } \ + } \ +} \ +while (0) + +INLINE bool ATTR_FORCE_INLINE alphaTest(voodoo_state *v, stats_block *stats, UINT32 alphaModeReg, UINT8 alpha) +{ + if (ALPHAMODE_ALPHATEST(alphaModeReg)) + { + UINT8 alpharef = v->reg[alphaMode].rgb.a; + switch (ALPHAMODE_ALPHAFUNCTION(alphaModeReg)) + { + case 0: /* alphaOP = never */ + stats->afunc_fail++; + return false; + + case 1: /* alphaOP = less than */ + if (alpha >= alpharef) + { + stats->afunc_fail++; + return false; + } + break; + + case 2: /* alphaOP = equal */ + if (alpha != alpharef) + { + stats->afunc_fail++; + return false; + } + break; + + case 3: /* alphaOP = less than or equal */ + if (alpha > alpharef) + { + stats->afunc_fail++; + return false; + } + break; + + case 4: /* alphaOP = greater than */ + if (alpha <= alpharef) + { + stats->afunc_fail++; + return false; + } + break; + + case 5: /* alphaOP = not equal */ + if (alpha == alpharef) + { + stats->afunc_fail++; + return false; + } + break; + + case 6: /* alphaOP = greater than or equal */ + if (alpha < alpharef) + { + stats->afunc_fail++; + return false; + } + break; + + case 7: /* alphaOP = always */ + break; + } + } + return true; +} + + +/************************************* + * + * Alpha blending macro + * + *************************************/ + +#define APPLY_ALPHA_BLEND(FBZMODE, ALPHAMODE, XX, DITHER, RR, GG, BB, AA) \ +do \ +{ \ + if (ALPHAMODE_ALPHABLEND(ALPHAMODE)) \ + { \ + int dpix = dest[XX]; \ + int dr, dg, db; \ + EXTRACT_565_TO_888(dpix, dr, dg, db); \ + int da = FBZMODE_ENABLE_ALPHA_PLANES(FBZMODE) ? depth[XX] : 0xff; \ + int sr = (RR); \ + int sg = (GG); \ + int sb = (BB); \ + int sa = (AA); \ + int ta; \ + \ + /* apply dither subtraction */ \ + if (FBZMODE_ALPHA_DITHER_SUBTRACT(FBZMODE)) \ + { \ + /* look up the dither value from the appropriate matrix */ \ + int dith = DITHER[(XX) & 3]; \ + \ + /* subtract the dither value */ \ + dr = ((dr << 1) + 15 - dith) >> 1; \ + dg = ((dg << 2) + 15 - dith) >> 2; \ + db = ((db << 1) + 15 - dith) >> 1; \ + } \ + \ + /* compute source portion */ \ + switch (ALPHAMODE_SRCRGBBLEND(ALPHAMODE)) \ + { \ + default: /* reserved */ \ + case 0: /* AZERO */ \ + (RR) = (GG) = (BB) = 0; \ + break; \ + \ + case 1: /* ASRC_ALPHA */ \ + (RR) = (sr * (sa + 1)) >> 8; \ + (GG) = (sg * (sa + 1)) >> 8; \ + (BB) = (sb * (sa + 1)) >> 8; \ + break; \ + \ + case 2: /* A_COLOR */ \ + (RR) = (sr * (dr + 1)) >> 8; \ + (GG) = (sg * (dg + 1)) >> 8; \ + (BB) = (sb * (db + 1)) >> 8; \ + break; \ + \ + case 3: /* ADST_ALPHA */ \ + (RR) = (sr * (da + 1)) >> 8; \ + (GG) = (sg * (da + 1)) >> 8; \ + (BB) = (sb * (da + 1)) >> 8; \ + break; \ + \ + case 4: /* AONE */ \ + break; \ + \ + case 5: /* AOMSRC_ALPHA */ \ + (RR) = (sr * (0x100 - sa)) >> 8; \ + (GG) = (sg * (0x100 - sa)) >> 8; \ + (BB) = (sb * (0x100 - sa)) >> 8; \ + break; \ + \ + case 6: /* AOM_COLOR */ \ + (RR) = (sr * (0x100 - dr)) >> 8; \ + (GG) = (sg * (0x100 - dg)) >> 8; \ + (BB) = (sb * (0x100 - db)) >> 8; \ + break; \ + \ + case 7: /* AOMDST_ALPHA */ \ + (RR) = (sr * (0x100 - da)) >> 8; \ + (GG) = (sg * (0x100 - da)) >> 8; \ + (BB) = (sb * (0x100 - da)) >> 8; \ + break; \ + \ + case 15: /* ASATURATE */ \ + ta = (sa < (0x100 - da)) ? sa : (0x100 - da); \ + (RR) = (sr * (ta + 1)) >> 8; \ + (GG) = (sg * (ta + 1)) >> 8; \ + (BB) = (sb * (ta + 1)) >> 8; \ + break; \ + } \ + \ + /* add in dest portion */ \ + switch (ALPHAMODE_DSTRGBBLEND(ALPHAMODE)) \ + { \ + default: /* reserved */ \ + case 0: /* AZERO */ \ + break; \ + \ + case 1: /* ASRC_ALPHA */ \ + (RR) += (dr * (sa + 1)) >> 8; \ + (GG) += (dg * (sa + 1)) >> 8; \ + (BB) += (db * (sa + 1)) >> 8; \ + break; \ + \ + case 2: /* A_COLOR */ \ + (RR) += (dr * (sr + 1)) >> 8; \ + (GG) += (dg * (sg + 1)) >> 8; \ + (BB) += (db * (sb + 1)) >> 8; \ + break; \ + \ + case 3: /* ADST_ALPHA */ \ + (RR) += (dr * (da + 1)) >> 8; \ + (GG) += (dg * (da + 1)) >> 8; \ + (BB) += (db * (da + 1)) >> 8; \ + break; \ + \ + case 4: /* AONE */ \ + (RR) += dr; \ + (GG) += dg; \ + (BB) += db; \ + break; \ + \ + case 5: /* AOMSRC_ALPHA */ \ + (RR) += (dr * (0x100 - sa)) >> 8; \ + (GG) += (dg * (0x100 - sa)) >> 8; \ + (BB) += (db * (0x100 - sa)) >> 8; \ + break; \ + \ + case 6: /* AOM_COLOR */ \ + (RR) += (dr * (0x100 - sr)) >> 8; \ + (GG) += (dg * (0x100 - sg)) >> 8; \ + (BB) += (db * (0x100 - sb)) >> 8; \ + break; \ + \ + case 7: /* AOMDST_ALPHA */ \ + (RR) += (dr * (0x100 - da)) >> 8; \ + (GG) += (dg * (0x100 - da)) >> 8; \ + (BB) += (db * (0x100 - da)) >> 8; \ + break; \ + \ + case 15: /* A_COLORBEFOREFOG */ \ + (RR) += (dr * (prefogr + 1)) >> 8; \ + (GG) += (dg * (prefogg + 1)) >> 8; \ + (BB) += (db * (prefogb + 1)) >> 8; \ + break; \ + } \ + \ + /* blend the source alpha */ \ + (AA) = 0; \ + if (ALPHAMODE_SRCALPHABLEND(ALPHAMODE) == 4) \ + (AA) = sa; \ + \ + /* blend the dest alpha */ \ + if (ALPHAMODE_DSTALPHABLEND(ALPHAMODE) == 4) \ + (AA) += da; \ + \ + /* clamp */ \ + CLAMP((RR), 0x00, 0xff); \ + CLAMP((GG), 0x00, 0xff); \ + CLAMP((BB), 0x00, 0xff); \ + CLAMP((AA), 0x00, 0xff); \ + } \ +} \ +while (0) + +INLINE void ATTR_FORCE_INLINE alphaBlend(UINT32 FBZMODE, UINT32 ALPHAMODE, INT32 x, const UINT8 *dither, int dpix, UINT16 *depth, rgbaint_t &preFog, rgbaint_t &srcColor) +{ + if (ALPHAMODE_ALPHABLEND(ALPHAMODE)) + { + //int dpix = dest[XX]; + int dr, dg, db; + EXTRACT_565_TO_888(dpix, dr, dg, db); + int da = FBZMODE_ENABLE_ALPHA_PLANES(FBZMODE) ? depth[x] : 0xff; + //int sr = (RR); + //int sg = (GG); + //int sb = (BB); + //int sa = (AA); + int sa = srcColor.get_a(); + int ta; + int srcAlphaScale, destAlphaScale; + rgbaint_t srcScale, destScale; + + /* apply dither subtraction */ + if (FBZMODE_ALPHA_DITHER_SUBTRACT(FBZMODE)) + { + /* look up the dither value from the appropriate matrix */ + //int dith = DITHER[(XX) & 3]; + + /* subtract the dither value */ + dr += (15 - dither[x&3]) >> 1; + dg += (15 - dither[x&3]) >> 2; + db += (15 - dither[x&3]) >> 1; + } + + /* blend the source alpha */ + srcAlphaScale = 0; + if (ALPHAMODE_SRCALPHABLEND(ALPHAMODE) == 4) + srcAlphaScale = 256; + //(AA) = sa; + + /* compute source portion */ + switch (ALPHAMODE_SRCRGBBLEND(ALPHAMODE)) + { + default: /* reserved */ + case 0: /* AZERO */ + srcScale.set(srcAlphaScale, 0, 0, 0); + //(RR) = (GG) = (BB) = 0; + break; + + case 1: /* ASRC_ALPHA */ + srcScale.set(srcAlphaScale-1, sa, sa, sa); + srcScale.add_imm(1); + //(RR) = (sr * (sa + 1)) >> 8; + //(GG) = (sg * (sa + 1)) >> 8; + //(BB) = (sb * (sa + 1)) >> 8; + break; + + case 2: /* A_COLOR */ + srcScale.set(srcAlphaScale-1, dr, dg, db); + srcScale.add_imm(1); + //(RR) = (sr * (dr + 1)) >> 8; + //(GG) = (sg * (dg + 1)) >> 8; + //(BB) = (sb * (db + 1)) >> 8; + break; + + case 3: /* ADST_ALPHA */ + ta = da + 1; + srcScale.set(srcAlphaScale, ta, ta, ta); + //(RR) = (sr * (da + 1)) >> 8; + //(GG) = (sg * (da + 1)) >> 8; + //(BB) = (sb * (da + 1)) >> 8; + break; + + case 4: /* AONE */ + srcScale.set(srcAlphaScale, 256, 256, 256); + break; + + case 5: /* AOMSRC_ALPHA */ + ta = (0x100 - sa); + srcScale.set(srcAlphaScale, ta, ta, ta); + //(RR) = (sr * (0x100 - sa)) >> 8; + //(GG) = (sg * (0x100 - sa)) >> 8; + //(BB) = (sb * (0x100 - sa)) >> 8; + break; + + case 6: /* AOM_COLOR */ + srcScale.set(srcAlphaScale, (0x100 - dr), (0x100 - dg), (0x100 - db)); + //(RR) = (sr * (0x100 - dr)) >> 8; + //(GG) = (sg * (0x100 - dg)) >> 8; + //(BB) = (sb * (0x100 - db)) >> 8; + break; + + case 7: /* AOMDST_ALPHA */ + ta = (0x100 - da); + srcScale.set(srcAlphaScale, ta, ta, ta); + //(RR) = (sr * (0x100 - da)) >> 8; + //(GG) = (sg * (0x100 - da)) >> 8; + //(BB) = (sb * (0x100 - da)) >> 8; + break; + + case 15: /* ASATURATE */ + ta = (sa < (0x100 - da)) ? sa : (0x100 - da); + ta++; + srcScale.set(srcAlphaScale, ta, ta, ta); + //(RR) = (sr * (ta + 1)) >> 8; + //(GG) = (sg * (ta + 1)) >> 8; + //(BB) = (sb * (ta + 1)) >> 8; + break; + } + + /* blend the dest alpha */ + destAlphaScale = 0; + if (ALPHAMODE_DSTALPHABLEND(ALPHAMODE) == 4) + destAlphaScale = 256; + //(AA) += da; + + /* add in dest portion */ + switch (ALPHAMODE_DSTRGBBLEND(ALPHAMODE)) + { + default: /* reserved */ + case 0: /* AZERO */ + destScale.set(destAlphaScale, 0, 0, 0); + break; + + case 1: /* ASRC_ALPHA */ + destScale.set(destAlphaScale-1, sa, sa, sa); + destScale.add_imm(1); + //(RR) += (dr * (sa + 1)) >> 8; + //(GG) += (dg * (sa + 1)) >> 8; + //(BB) += (db * (sa + 1)) >> 8; + break; + + case 2: /* A_COLOR */ + destScale.set(srcColor); + destScale.add_imm(1); + destScale.set_a(destAlphaScale); + //(RR) += (dr * (sr + 1)) >> 8; + //(GG) += (dg * (sg + 1)) >> 8; + //(BB) += (db * (sb + 1)) >> 8; + break; + + case 3: /* ADST_ALPHA */ + ta = da + 1; + destScale.set(destAlphaScale, ta, ta, ta); + //(RR) += (dr * (da + 1)) >> 8; + //(GG) += (dg * (da + 1)) >> 8; + //(BB) += (db * (da + 1)) >> 8; + break; + + case 4: /* AONE */ + destScale.set(destAlphaScale, 256, 256, 256); + //(RR) += dr; + //(GG) += dg; + //(BB) += db; + break; + + case 5: /* AOMSRC_ALPHA */ + ta = (0x100 - sa); + destScale.set(destAlphaScale, ta, ta, ta); + //(RR) += (dr * (0x100 - sa)) >> 8; + //(GG) += (dg * (0x100 - sa)) >> 8; + //(BB) += (db * (0x100 - sa)) >> 8; + break; + + case 6: /* AOM_COLOR */ + destScale.set(0x100, 0x100, 0x100, 0x100); + destScale.sub(srcColor); + destScale.set_a(destAlphaScale); + //destScale.set(destAlphaScale, (0x100 - color.rgb.r), (0x100 - color.rgb.g), (0x100 - color.rgb.b)); + //(RR) += (dr * (0x100 - sr)) >> 8; + //(GG) += (dg * (0x100 - sg)) >> 8; + //(BB) += (db * (0x100 - sb)) >> 8; + break; + + case 7: /* AOMDST_ALPHA */ + ta = (0x100 - da); + destScale.set(destAlphaScale, ta, ta, ta); + //(RR) += (dr * (0x100 - da)) >> 8; + //(GG) += (dg * (0x100 - da)) >> 8; + //(BB) += (db * (0x100 - da)) >> 8; + break; + + case 15: /* A_COLORBEFOREFOG */ + destScale.set(preFog); + destScale.add_imm(1); + destScale.set_a(destAlphaScale); + //destScale.set((rgb_t) (((destAlphaScale-1)<<24) | (preFog.u & 0x00ffffff))); + //destScale.add_imm(1); + //(RR) += (dr * (prefogr + 1)) >> 8; + //(GG) += (dg * (prefogg + 1)) >> 8; + //(BB) += (db * (prefogb + 1)) >> 8; + break; + } + // Main blend + rgbaint_t destColor(da, dr, dg, db); + + srcColor.scale2_add_and_clamp(srcScale, destColor, destScale); + /* clamp */ + //CLAMP((RR), 0x00, 0xff); + //CLAMP((GG), 0x00, 0xff); + //CLAMP((BB), 0x00, 0xff); + //CLAMP((AA), 0x00, 0xff); + } +} + + +/************************************* + * + * Fogging macro + * + *************************************/ + +#define APPLY_FOGGING(VV, FOGMODE, FBZCP, XX, DITHER4, RR, GG, BB, ITERZ, ITERW, ITERAXXX) \ +do \ +{ \ + if (FOGMODE_ENABLE_FOG(FOGMODE)) \ + { \ + rgb_union fogcolor = (VV)->reg[fogColor]; \ + INT32 fr, fg, fb; \ + \ + /* constant fog bypasses everything else */ \ + if (FOGMODE_FOG_CONSTANT(FOGMODE)) \ + { \ + fr = fogcolor.rgb.r; \ + fg = fogcolor.rgb.g; \ + fb = fogcolor.rgb.b; \ + } \ + \ + /* non-constant fog comes from several sources */ \ + else \ + { \ + INT32 fogblend = 0; \ + \ + /* if fog_add is zero, we start with the fog color */ \ + if (FOGMODE_FOG_ADD(FOGMODE) == 0) \ + { \ + fr = fogcolor.rgb.r; \ + fg = fogcolor.rgb.g; \ + fb = fogcolor.rgb.b; \ + } \ + else \ + fr = fg = fb = 0; \ + \ + /* if fog_mult is zero, we subtract the incoming color */ \ + if (FOGMODE_FOG_MULT(FOGMODE) == 0) \ + { \ + fr -= (RR); \ + fg -= (GG); \ + fb -= (BB); \ + } \ + \ + /* fog blending mode */ \ + switch (FOGMODE_FOG_ZALPHA(FOGMODE)) \ + { \ + case 0: /* fog table */ \ + { \ + INT32 delta = (VV)->fbi.fogdelta[fogdepth >> 10]; \ + INT32 deltaval; \ + \ + /* perform the multiply against lower 8 bits of wfloat */ \ + deltaval = (delta & (VV)->fbi.fogdelta_mask) * \ + ((fogdepth >> 2) & 0xff); \ + \ + /* fog zones allow for negating this value */ \ + if (FOGMODE_FOG_ZONES(FOGMODE) && (delta & 2)) \ + deltaval = -deltaval; \ + deltaval >>= 6; \ + \ + /* apply dither */ \ + if (FOGMODE_FOG_DITHER(FOGMODE)) \ + deltaval += DITHER4[(XX) & 3]; \ + deltaval >>= 4; \ + \ + /* add to the blending factor */ \ + fogblend = (VV)->fbi.fogblend[fogdepth >> 10] + deltaval; \ + break; \ + } \ + \ + case 1: /* iterated A */ \ + fogblend = ITERAXXX.rgb.a; \ + break; \ + \ + case 2: /* iterated Z */ \ + CLAMPED_Z((ITERZ), FBZCP, fogblend); \ + fogblend >>= 8; \ + break; \ + \ + case 3: /* iterated W - Voodoo 2 only */ \ + CLAMPED_W((ITERW), FBZCP, fogblend); \ + break; \ + } \ + \ + /* perform the blend */ \ + fogblend++; \ + fr = (fr * fogblend) >> 8; \ + fg = (fg * fogblend) >> 8; \ + fb = (fb * fogblend) >> 8; \ + } \ + \ + /* if fog_mult is 0, we add this to the original color */ \ + if (FOGMODE_FOG_MULT(FOGMODE) == 0) \ + { \ + (RR) += fr; \ + (GG) += fg; \ + (BB) += fb; \ + } \ + \ + /* otherwise this just becomes the new color */ \ + else \ + { \ + (RR) = fr; \ + (GG) = fg; \ + (BB) = fb; \ + } \ + \ + /* clamp */ \ + CLAMP((RR), 0x00, 0xff); \ + CLAMP((GG), 0x00, 0xff); \ + CLAMP((BB), 0x00, 0xff); \ + } \ +} \ +while (0) + +INLINE void ATTR_FORCE_INLINE applyFogging(voodoo_state *v, UINT32 fogModeReg, UINT32 fbzCpReg, INT32 x, const UINT8 *dither4, INT32 fogDepth, + rgbaint_t &color, INT32 iterz, INT64 iterw, UINT8 itera) +{ + if (FOGMODE_ENABLE_FOG(fogModeReg)) + { + UINT32 color_alpha = color.get_a(); + + /* constant fog bypasses everything else */ + rgbaint_t fogColorLocal(v->reg[fogColor].u); + + if (FOGMODE_FOG_CONSTANT(fogModeReg)) + { + /* if fog_mult is 0, we add this to the original color */ + if (FOGMODE_FOG_MULT(fogModeReg) == 0) + { + fogColorLocal.add(color); + fogColorLocal.clamp_to_uint8(); + //color += fog; + } + + /* otherwise this just becomes the new color */ + else + { + //color = fogColorLocal; + //color = fog; + } + } + /* non-constant fog comes from several sources */ + else + { + INT32 fogblend = 0; + + /* if fog_add is zero, we start with the fog color */ + if (FOGMODE_FOG_ADD(fogModeReg)) + fogColorLocal.set(0, 0, 0, 0); + //fr = fg = fb = 0; + + /* if fog_mult is zero, we subtract the incoming color */ + if (!FOGMODE_FOG_MULT(fogModeReg)) + { + fogColorLocal.sub(color); + //fog.rgb -= color.rgb; + //fr -= (RR); + //fg -= (GG); + //fb -= (BB); + } + + /* fog blending mode */ + switch (FOGMODE_FOG_ZALPHA(fogModeReg)) + { + case 0: /* fog table */ + { + INT32 delta = v->fbi.fogdelta[fogDepth >> 10]; + INT32 deltaval; + + /* perform the multiply against lower 8 bits of wfloat */ + deltaval = (delta & v->fbi.fogdelta_mask) * + ((fogDepth >> 2) & 0xff); + + /* fog zones allow for negating this value */ + if (FOGMODE_FOG_ZONES(fogModeReg) && (delta & 2)) + deltaval = -deltaval; + deltaval >>= 6; + + /* apply dither */ + if (FOGMODE_FOG_DITHER(fogModeReg)) + deltaval += dither4[x&3]; + deltaval >>= 4; + + /* add to the blending factor */ + fogblend = v->fbi.fogblend[fogDepth >> 10] + deltaval; + break; + } + + case 1: /* iterated A */ + fogblend = itera; + break; + + case 2: /* iterated Z */ + CLAMPED_Z(iterz, fbzCpReg, fogblend); + fogblend >>= 8; + break; + + case 3: /* iterated W - Voodoo 2 only */ + CLAMPED_W(iterw, fbzCpReg, fogblend); + break; + } + + /* perform the blend */ + fogblend++; + + //fr = (fr * fogblend) >> 8; + //fg = (fg * fogblend) >> 8; + //fb = (fb * fogblend) >> 8; + /* if fog_mult is 0, we add this to the original color */ + if (FOGMODE_FOG_MULT(fogModeReg) == 0) + { + fogColorLocal.scale_imm_add_and_clamp(fogblend, color); + //color += fog; + //(RR) += fr; + //(GG) += fg; + //(BB) += fb; + } + + /* otherwise this just becomes the new color */ + else + { + fogColorLocal.scale_imm_and_clamp(fogblend); + //color = fog; + //(RR) = fr; + //(GG) = fg; + //(BB) = fb; + } + } + + + /* clamp */ + //CLAMP((RR), 0x00, 0xff); + //CLAMP((GG), 0x00, 0xff); + //CLAMP((BB), 0x00, 0xff); + fogColorLocal.set_a(color_alpha); + color.set(fogColorLocal); + } +} + + +/************************************* + * + * Texture pipeline macro + * + *************************************/ + +#define TEXTURE_PIPELINE(TT, XX, DITHER4, TEXMODE, COTHER, LOOKUP, LODBASE, ITERS, ITERT, ITERW, RESULT) \ +do \ +{ \ + INT32 blendr, blendg, blendb, blenda; \ + INT32 tr, tg, tb, ta; \ + INT32 s, t, lod, ilod; \ + INT32 smax, tmax; \ + UINT32 texbase; \ + rgb_union c_local; \ + \ + /* determine the S/T/LOD values for this texture */ \ + if (TEXMODE_ENABLE_PERSPECTIVE(TEXMODE)) \ + { \ + if (USE_FAST_RECIP) { \ + const INT32 oow = fast_reciplog((ITERW), &lod); \ + s = ((INT64)oow * (ITERS)) >> 29; \ + t = ((INT64)oow * (ITERT)) >> 29; \ + } else { \ + multi_reciplog(ITERS, ITERT, ITERW, lod, s, t); \ + } \ + lod += (LODBASE); \ + } \ + else \ + { \ + s = (ITERS) >> 14; \ + t = (ITERT) >> 14; \ + lod = (LODBASE); \ + } \ + \ + /* clamp W */ \ + if (TEXMODE_CLAMP_NEG_W(TEXMODE) && (ITERW) < 0) \ + s = t = 0; \ + \ + /* clamp the LOD */ \ + lod += (TT)->lodbias; \ + if (TEXMODE_ENABLE_LOD_DITHER(TEXMODE)) \ + lod += DITHER4[(XX) & 3] << 4; \ + if (lod < (TT)->lodmin) \ + lod = (TT)->lodmin; \ + if (lod > (TT)->lodmax) \ + lod = (TT)->lodmax; \ + \ + /* now the LOD is in range; if we don't own this LOD, take the next one */ \ + ilod = lod >> 8; \ + if (!(((TT)->lodmask >> ilod) & 1)) \ + ilod++; \ + \ + /* fetch the texture base */ \ + texbase = (TT)->lodoffset[ilod]; \ + \ + /* compute the maximum s and t values at this LOD */ \ + smax = (TT)->wmask >> ilod; \ + tmax = (TT)->hmask >> ilod; \ + \ + /* determine whether we are point-sampled or bilinear */ \ + if ((lod == (TT)->lodmin && !TEXMODE_MAGNIFICATION_FILTER(TEXMODE)) || \ + (lod != (TT)->lodmin && !TEXMODE_MINIFICATION_FILTER(TEXMODE))) \ + { \ + /* point sampled */ \ + \ + UINT32 texel0; \ + \ + /* adjust S/T for the LOD and strip off the fractions */ \ + s >>= ilod + 18; \ + t >>= ilod + 18; \ + \ + /* clamp/wrap S/T if necessary */ \ + if (TEXMODE_CLAMP_S(TEXMODE)) \ + CLAMP(s, 0, smax); \ + if (TEXMODE_CLAMP_T(TEXMODE)) \ + CLAMP(t, 0, tmax); \ + s &= smax; \ + t &= tmax; \ + t *= smax + 1; \ + \ + /* fetch texel data */ \ + if (TEXMODE_FORMAT(TEXMODE) < 8) \ + { \ + texel0 = *(UINT8 *)&(TT)->ram[(texbase + t + s) & (TT)->mask]; \ + c_local.u = (LOOKUP)[texel0]; \ + } \ + else \ + { \ + texel0 = *(UINT16 *)&(TT)->ram[(texbase + 2*(t + s)) & (TT)->mask]; \ + if (TEXMODE_FORMAT(TEXMODE) >= 10 && TEXMODE_FORMAT(TEXMODE) <= 12) \ + c_local.u = (LOOKUP)[texel0]; \ + else \ + c_local.u = ((LOOKUP)[texel0 & 0xff] & 0xffffff) | \ + ((texel0 & 0xff00) << 16); \ + } \ + } \ + else \ + { \ + /* bilinear filtered */ \ + \ + UINT32 texel0, texel1, texel2, texel3; \ + UINT32 sfrac, tfrac; \ + INT32 s1, t1; \ + \ + /* adjust S/T for the LOD and strip off all but the low 8 bits of */ \ + /* the fraction */ \ + s >>= ilod + 10; \ + t >>= ilod + 10; \ + \ + /* also subtract 1/2 texel so that (0.5,0.5) = a full (0,0) texel */ \ + s -= 0x80; \ + t -= 0x80; \ + \ + /* extract the fractions */ \ + sfrac = s & (TT)->bilinear_mask; \ + tfrac = t & (TT)->bilinear_mask; \ + \ + /* now toss the rest */ \ + s >>= 8; \ + t >>= 8; \ + s1 = s + 1; \ + t1 = t + 1; \ + \ + /* clamp/wrap S/T if necessary */ \ + if (TEXMODE_CLAMP_S(TEXMODE)) \ + { \ + CLAMP(s, 0, smax); \ + CLAMP(s1, 0, smax); \ + } \ + if (TEXMODE_CLAMP_T(TEXMODE)) \ + { \ + CLAMP(t, 0, tmax); \ + CLAMP(t1, 0, tmax); \ + } \ + s &= smax; \ + s1 &= smax; \ + t &= tmax; \ + t1 &= tmax; \ + t *= smax + 1; \ + t1 *= smax + 1; \ + \ + /* fetch texel data */ \ + if (TEXMODE_FORMAT(TEXMODE) < 8) \ + { \ + texel0 = *(UINT8 *)&(TT)->ram[(texbase + t + s) & (TT)->mask]; \ + texel1 = *(UINT8 *)&(TT)->ram[(texbase + t + s1) & (TT)->mask]; \ + texel2 = *(UINT8 *)&(TT)->ram[(texbase + t1 + s) & (TT)->mask]; \ + texel3 = *(UINT8 *)&(TT)->ram[(texbase + t1 + s1) & (TT)->mask]; \ + texel0 = (LOOKUP)[texel0]; \ + texel1 = (LOOKUP)[texel1]; \ + texel2 = (LOOKUP)[texel2]; \ + texel3 = (LOOKUP)[texel3]; \ + } \ + else \ + { \ + texel0 = *(UINT16 *)&(TT)->ram[(texbase + 2*(t + s)) & (TT)->mask]; \ + texel1 = *(UINT16 *)&(TT)->ram[(texbase + 2*(t + s1)) & (TT)->mask];\ + texel2 = *(UINT16 *)&(TT)->ram[(texbase + 2*(t1 + s)) & (TT)->mask];\ + texel3 = *(UINT16 *)&(TT)->ram[(texbase + 2*(t1 + s1)) & (TT)->mask];\ + if (TEXMODE_FORMAT(TEXMODE) >= 10 && TEXMODE_FORMAT(TEXMODE) <= 12) \ + { \ + texel0 = (LOOKUP)[texel0]; \ + texel1 = (LOOKUP)[texel1]; \ + texel2 = (LOOKUP)[texel2]; \ + texel3 = (LOOKUP)[texel3]; \ + } \ + else \ + { \ + texel0 = ((LOOKUP)[texel0 & 0xff] & 0xffffff) | \ + ((texel0 & 0xff00) << 16); \ + texel1 = ((LOOKUP)[texel1 & 0xff] & 0xffffff) | \ + ((texel1 & 0xff00) << 16); \ + texel2 = ((LOOKUP)[texel2 & 0xff] & 0xffffff) | \ + ((texel2 & 0xff00) << 16); \ + texel3 = ((LOOKUP)[texel3 & 0xff] & 0xffffff) | \ + ((texel3 & 0xff00) << 16); \ + } \ + } \ + \ + /* weigh in each texel */ \ + c_local.u = rgbaint_t::bilinear_filter(texel0, texel1, texel2, texel3, sfrac, tfrac); \ + } \ + \ + /* select zero/other for RGB */ \ + if (!TEXMODE_TC_ZERO_OTHER(TEXMODE)) \ + { \ + tr = COTHER.rgb.r; \ + tg = COTHER.rgb.g; \ + tb = COTHER.rgb.b; \ + } \ + else \ + tr = tg = tb = 0; \ + \ + /* select zero/other for alpha */ \ + if (!TEXMODE_TCA_ZERO_OTHER(TEXMODE)) \ + ta = COTHER.rgb.a; \ + else \ + ta = 0; \ + \ + /* potentially subtract c_local */ \ + if (TEXMODE_TC_SUB_CLOCAL(TEXMODE)) \ + { \ + tr -= c_local.rgb.r; \ + tg -= c_local.rgb.g; \ + tb -= c_local.rgb.b; \ + } \ + if (TEXMODE_TCA_SUB_CLOCAL(TEXMODE)) \ + ta -= c_local.rgb.a; \ + \ + /* blend RGB */ \ + switch (TEXMODE_TC_MSELECT(TEXMODE)) \ + { \ + default: /* reserved */ \ + case 0: /* zero */ \ + blendr = blendg = blendb = 0; \ + break; \ + \ + case 1: /* c_local */ \ + blendr = c_local.rgb.r; \ + blendg = c_local.rgb.g; \ + blendb = c_local.rgb.b; \ + break; \ + \ + case 2: /* a_other */ \ + blendr = blendg = blendb = COTHER.rgb.a; \ + break; \ + \ + case 3: /* a_local */ \ + blendr = blendg = blendb = c_local.rgb.a; \ + break; \ + \ + case 4: /* LOD (detail factor) */ \ + if ((TT)->detailbias <= lod) \ + blendr = blendg = blendb = 0; \ + else \ + { \ + blendr = ((((TT)->detailbias - lod) << (TT)->detailscale) >> 8);\ + if (blendr > (TT)->detailmax) \ + blendr = (TT)->detailmax; \ + blendg = blendb = blendr; \ + } \ + break; \ + \ + case 5: /* LOD fraction */ \ + blendr = blendg = blendb = lod & 0xff; \ + break; \ + } \ + \ + /* blend alpha */ \ + switch (TEXMODE_TCA_MSELECT(TEXMODE)) \ + { \ + default: /* reserved */ \ + case 0: /* zero */ \ + blenda = 0; \ + break; \ + \ + case 1: /* c_local */ \ + blenda = c_local.rgb.a; \ + break; \ + \ + case 2: /* a_other */ \ + blenda = COTHER.rgb.a; \ + break; \ + \ + case 3: /* a_local */ \ + blenda = c_local.rgb.a; \ + break; \ + \ + case 4: /* LOD (detail factor) */ \ + if ((TT)->detailbias <= lod) \ + blenda = 0; \ + else \ + { \ + blenda = ((((TT)->detailbias - lod) << (TT)->detailscale) >> 8);\ + if (blenda > (TT)->detailmax) \ + blenda = (TT)->detailmax; \ + } \ + break; \ + \ + case 5: /* LOD fraction */ \ + blenda = lod & 0xff; \ + break; \ + } \ + \ + /* reverse the RGB blend */ \ + if (!TEXMODE_TC_REVERSE_BLEND(TEXMODE)) \ + { \ + blendr ^= 0xff; \ + blendg ^= 0xff; \ + blendb ^= 0xff; \ + } \ + \ + /* reverse the alpha blend */ \ + if (!TEXMODE_TCA_REVERSE_BLEND(TEXMODE)) \ + blenda ^= 0xff; \ + \ + /* do the blend */ \ + tr = (tr * (blendr + 1)) >> 8; \ + tg = (tg * (blendg + 1)) >> 8; \ + tb = (tb * (blendb + 1)) >> 8; \ + ta = (ta * (blenda + 1)) >> 8; \ + \ + /* add clocal or alocal to RGB */ \ + switch (TEXMODE_TC_ADD_ACLOCAL(TEXMODE)) \ + { \ + case 3: /* reserved */ \ + case 0: /* nothing */ \ + break; \ + \ + case 1: /* add c_local */ \ + tr += c_local.rgb.r; \ + tg += c_local.rgb.g; \ + tb += c_local.rgb.b; \ + break; \ + \ + case 2: /* add_alocal */ \ + tr += c_local.rgb.a; \ + tg += c_local.rgb.a; \ + tb += c_local.rgb.a; \ + break; \ + } \ + \ + /* add clocal or alocal to alpha */ \ + if (TEXMODE_TCA_ADD_ACLOCAL(TEXMODE)) \ + ta += c_local.rgb.a; \ + \ + /* clamp */ \ + RESULT.rgb.r = (tr < 0) ? 0 : (tr > 0xff) ? 0xff : tr; \ + RESULT.rgb.g = (tg < 0) ? 0 : (tg > 0xff) ? 0xff : tg; \ + RESULT.rgb.b = (tb < 0) ? 0 : (tb > 0xff) ? 0xff : tb; \ + RESULT.rgb.a = (ta < 0) ? 0 : (ta > 0xff) ? 0xff : ta; \ + \ + /* invert */ \ + if (TEXMODE_TC_INVERT_OUTPUT(TEXMODE)) \ + RESULT.u ^= 0x00ffffff; \ + if (TEXMODE_TCA_INVERT_OUTPUT(TEXMODE)) \ + RESULT.rgb.a ^= 0xff; \ +} \ +while (0) + + + +/************************************* + * + * Pixel pipeline macros + * + *************************************/ + +#define PIXEL_PIPELINE_BEGIN(VV, STATS, XX, YY, FBZCOLORPATH, FBZMODE, ITERZ, ITERW) \ +do \ +{ \ + INT32 depthval, wfloat, fogdepth, biasdepth; \ + INT32 r, g, b, a; \ + \ + (STATS)->pixels_in++; \ + \ + /* apply clipping */ \ + /* note that for perf reasons, we assume the caller has done clipping */ \ + \ + /* handle stippling */ \ + if (FBZMODE_ENABLE_STIPPLE(FBZMODE)) \ + { \ + /* rotate mode */ \ + if (FBZMODE_STIPPLE_PATTERN(FBZMODE) == 0) \ + { \ + (VV)->reg[stipple].u = ((VV)->reg[stipple].u << 1) | ((VV)->reg[stipple].u >> 31);\ + if (((VV)->reg[stipple].u & 0x80000000) == 0) \ + { \ + (VV)->stats.total_stippled++; \ + goto skipdrawdepth; \ + } \ + } \ + \ + /* pattern mode */ \ + else \ + { \ + int stipple_index = (((YY) & 3) << 3) | (~(XX) & 7); \ + if ((((VV)->reg[stipple].u >> stipple_index) & 1) == 0) \ + { \ + (VV)->stats.total_stippled++; \ + goto skipdrawdepth; \ + } \ + } \ + } \ + \ + /* compute "floating point" W value (used for depth and fog) */ \ + if ((ITERW) & U64(0xffff00000000)) \ + wfloat = 0x0000; \ + else \ + { \ + UINT32 temp = (UINT32)(ITERW); \ + if (!(temp & 0xffff0000)) \ + wfloat = 0xffff; \ + else \ + { \ + int exp = count_leading_zeros(temp); \ + wfloat = ((exp << 12) | ((~temp >> (19 - exp)) & 0xfff)) + 1; \ + } \ + } \ + fogdepth = wfloat; \ + /* add the bias for fog selection*/ \ + if (FBZMODE_ENABLE_DEPTH_BIAS(FBZMODE)) \ + { \ + fogdepth += (INT16)(VV)->reg[zaColor].u; \ + CLAMP(fogdepth, 0, 0xffff); \ + } \ + \ + /* compute depth value (W or Z) for this pixel */ \ + if (FBZMODE_WBUFFER_SELECT(FBZMODE) == 0) \ + { \ + CLAMPED_Z(ITERZ, FBZCOLORPATH, depthval); \ + } \ + else if (FBZMODE_DEPTH_FLOAT_SELECT(FBZMODE) == 0) \ + depthval = wfloat; \ + else \ + { \ + if ((ITERZ) & 0xf0000000) \ + depthval = 0x0000; \ + else \ + { \ + UINT32 temp = (ITERZ << 4); \ + if (!(temp & 0xffff0000)) \ + depthval = 0xffff; \ + else \ + { \ + int exp = count_leading_zeros(temp); \ + depthval = ((exp << 12) | ((~temp >> (19 - exp)) & 0xfff)) + 1; \ + } \ + } \ + } \ + /* add the bias */ \ + biasdepth = depthval; \ + if (FBZMODE_ENABLE_DEPTH_BIAS(FBZMODE)) \ + { \ + biasdepth += (INT16)(VV)->reg[zaColor].u; \ + CLAMP(biasdepth, 0, 0xffff); \ + } + + +#define DEPTH_TEST(VV, STATS, XX, FBZMODE) \ +do \ +{ \ + /* handle depth buffer testing */ \ + if (FBZMODE_ENABLE_DEPTHBUF(FBZMODE)) \ + { \ + INT32 depthsource; \ + \ + /* the source depth is either the iterated W/Z+bias or a */ \ + /* constant value */ \ + if (FBZMODE_DEPTH_SOURCE_COMPARE(FBZMODE) == 0) \ + depthsource = biasdepth; \ + else \ + depthsource = (UINT16)(VV)->reg[zaColor].u; \ + \ + /* test against the depth buffer */ \ + switch (FBZMODE_DEPTH_FUNCTION(FBZMODE)) \ + { \ + case 0: /* depthOP = never */ \ + (STATS)->zfunc_fail++; \ + goto skipdrawdepth; \ + \ + case 1: /* depthOP = less than */ \ + if (depthsource >= depth[XX]) \ + { \ + (STATS)->zfunc_fail++; \ + goto skipdrawdepth; \ + } \ + break; \ + \ + case 2: /* depthOP = equal */ \ + if (depthsource != depth[XX]) \ + { \ + (STATS)->zfunc_fail++; \ + goto skipdrawdepth; \ + } \ + break; \ + \ + case 3: /* depthOP = less than or equal */ \ + if (depthsource > depth[XX]) \ + { \ + (STATS)->zfunc_fail++; \ + goto skipdrawdepth; \ + } \ + break; \ + \ + case 4: /* depthOP = greater than */ \ + if (depthsource <= depth[XX]) \ + { \ + (STATS)->zfunc_fail++; \ + goto skipdrawdepth; \ + } \ + break; \ + \ + case 5: /* depthOP = not equal */ \ + if (depthsource == depth[XX]) \ + { \ + (STATS)->zfunc_fail++; \ + goto skipdrawdepth; \ + } \ + break; \ + \ + case 6: /* depthOP = greater than or equal */ \ + if (depthsource < depth[XX]) \ + { \ + (STATS)->zfunc_fail++; \ + goto skipdrawdepth; \ + } \ + break; \ + \ + case 7: /* depthOP = always */ \ + break; \ + } \ + } \ +} \ +while (0) + +INLINE bool ATTR_FORCE_INLINE depthTest(UINT16 zaColorReg, stats_block *stats, INT32 destDepth, UINT32 fbzModeReg, INT32 biasdepth) +{ + /* handle depth buffer testing */ + if (FBZMODE_ENABLE_DEPTHBUF(fbzModeReg)) + { + INT32 depthsource; + + /* the source depth is either the iterated W/Z+bias or a */ + /* constant value */ + if (FBZMODE_DEPTH_SOURCE_COMPARE(fbzModeReg) == 0) + depthsource = biasdepth; + else + depthsource = zaColorReg; + + /* test against the depth buffer */ + switch (FBZMODE_DEPTH_FUNCTION(fbzModeReg)) + { + case 0: /* depthOP = never */ + stats->zfunc_fail++; + return false; + + case 1: /* depthOP = less than */ + if (depthsource >= destDepth) + { + stats->zfunc_fail++; + return false; + } + break; + + case 2: /* depthOP = equal */ + if (depthsource != destDepth) + { + stats->zfunc_fail++; + return false; + } + break; + + case 3: /* depthOP = less than or equal */ + if (depthsource > destDepth) + { + stats->zfunc_fail++; + return false; + } + break; + + case 4: /* depthOP = greater than */ + if (depthsource <= destDepth) + { + stats->zfunc_fail++; + return false; + } + break; + + case 5: /* depthOP = not equal */ + if (depthsource == destDepth) + { + stats->zfunc_fail++; + return false; + } + break; + + case 6: /* depthOP = greater than or equal */ + if (depthsource < destDepth) + { + stats->zfunc_fail++; + return false; + } + break; + + case 7: /* depthOP = always */ + break; + } + } + return true; +} + +#if USE_OLD_RASTER == 1 +#define PIXEL_PIPELINE_END(VV, STATS, DITHER, DITHER4, DITHER_LOOKUP, XX, dest, depth, FBZMODE, FBZCOLORPATH, ALPHAMODE, FOGMODE, ITERZ, ITERW, ITERAXXX) \ + \ + /* perform fogging */ \ + INT32 prefogr, prefogg, prefogb; \ + prefogr = r; \ + prefogg = g; \ + prefogb = b; \ + APPLY_FOGGING(VV, FOGMODE, FBZCOLORPATH, XX, DITHER4, r, g, b, \ + ITERZ, ITERW, ITERAXXX); \ + \ + /* perform alpha blending */ \ + APPLY_ALPHA_BLEND(FBZMODE, ALPHAMODE, XX, DITHER, r, g, b, a); \ + /* modify the pixel for debugging purposes */ \ + MODIFY_PIXEL(VV); \ + \ + /* write to framebuffer */ \ + if (FBZMODE_RGB_BUFFER_MASK(FBZMODE)) \ + { \ + /* apply dithering */ \ + APPLY_DITHER(FBZMODE, XX, DITHER_LOOKUP, r, g, b); \ + dest[XX] = (r << 11) | (g << 5) | b; \ + } \ + \ + /* write to aux buffer */ \ + if (depth && FBZMODE_AUX_BUFFER_MASK(FBZMODE)) \ + { \ + if (FBZMODE_ENABLE_ALPHA_PLANES(FBZMODE) == 0) \ + depth[XX] = biasdepth; \ + else \ + depth[XX] = a; \ + } \ + \ + /* track pixel writes to the frame buffer regardless of mask */ \ + (STATS)->pixels_out++; \ + \ +skipdrawdepth: \ + ; \ +} \ +while (0) +#else +#define PIXEL_PIPELINE_END(VV, STATS, DITHER, DITHER4, DITHER_LOOKUP, XX, dest, depth, FBZMODE, FBZCOLORPATH, ALPHAMODE, FOGMODE, ITERZ, ITERW, ITERAXXX) \ + \ + /* perform fogging */ \ + preFog.set(color); \ + applyFogging(VV, FOGMODE, FBZCOLORPATH, XX, DITHER4, fogdepth, color, ITERZ, ITERW, ITERAXXX.get_a()); \ + /* perform alpha blending */ \ + alphaBlend(FBZMODE, ALPHAMODE, XX, DITHER, dest[XX], depth, preFog, color); \ + a = color.get_a(); r = color.get_r(); g = color.get_g(); b = color.get_b(); \ + /* modify the pixel for debugging purposes */ \ + MODIFY_PIXEL(VV); \ + \ + /* write to framebuffer */ \ + if (FBZMODE_RGB_BUFFER_MASK(FBZMODE)) \ + { \ + /* apply dithering */ \ + APPLY_DITHER(FBZMODE, XX, DITHER_LOOKUP, r, g, b); \ + dest[XX] = (r << 11) | (g << 5) | b; \ + } \ + \ + /* write to aux buffer */ \ + if (depth && FBZMODE_AUX_BUFFER_MASK(FBZMODE)) \ + { \ + if (FBZMODE_ENABLE_ALPHA_PLANES(FBZMODE) == 0) \ + depth[XX] = biasdepth; \ + else \ + depth[XX] = a; \ + } \ + \ + /* track pixel writes to the frame buffer regardless of mask */ \ + (STATS)->pixels_out++; \ + \ +skipdrawdepth: \ + ; \ +} \ +while (0) +#endif + + +/************************************* + * + * Colorpath pipeline macro + * + *************************************/ + +/* + + c_other_is_used: + + if (FBZMODE_ENABLE_CHROMAKEY(FBZMODE) || + FBZCP_CC_ZERO_OTHER(FBZCOLORPATH) == 0) + + c_local_is_used: + + if (FBZCP_CC_SUB_CLOCAL(FBZCOLORPATH) || + FBZCP_CC_MSELECT(FBZCOLORPATH) == 1 || + FBZCP_CC_ADD_ACLOCAL(FBZCOLORPATH) == 1) + + NEEDS_ITER_RGB: + + if ((c_other_is_used && FBZCP_CC_RGBSELECT(FBZCOLORPATH) == 0) || + (c_local_is_used && (FBZCP_CC_LOCALSELECT_OVERRIDE(FBZCOLORPATH) != 0 || FBZCP_CC_LOCALSELECT(FBZCOLORPATH) == 0)) + + NEEDS_ITER_A: + + if ((a_other_is_used && FBZCP_CC_ASELECT(FBZCOLORPATH) == 0) || + (a_local_is_used && FBZCP_CCA_LOCALSELECT(FBZCOLORPATH) == 0)) + + NEEDS_ITER_Z: + + if (FBZMODE_WBUFFER_SELECT(FBZMODE) == 0 || + FBZMODE_DEPTH_FLOAT_SELECT(FBZMODE) != 0 || + FBZCP_CCA_LOCALSELECT(FBZCOLORPATH) == 2) + + +*/ + +/* + Expects the following declarations to be outside of this scope: + + INT32 r, g, b, a; +*/ +#define COLORPATH_PIPELINE(VV, STATS, FBZCOLORPATH, FBZMODE, ALPHAMODE, TEXELARGB, ITERZ, ITERW, ITERARGB) \ +do \ +{ \ + INT32 blendr, blendg, blendb, blenda; \ + rgb_union c_other; \ + rgb_union c_local; \ + \ + /* compute c_other */ \ + switch (FBZCP_CC_RGBSELECT(FBZCOLORPATH)) \ + { \ + case 0: /* iterated RGB */ \ + c_other.u = ITERARGB.u; \ + break; \ + \ + case 1: /* texture RGB */ \ + c_other.u = TEXELARGB.u; \ + break; \ + \ + case 2: /* color1 RGB */ \ + c_other.u = (VV)->reg[color1].u; \ + break; \ + \ + default: /* reserved - voodoo3 framebufferRGB */ \ + c_other.u = 0; \ + break; \ + } \ + \ + /* handle chroma key */ \ + APPLY_CHROMAKEY(VV, STATS, FBZMODE, c_other); \ + \ + /* compute a_other */ \ + switch (FBZCP_CC_ASELECT(FBZCOLORPATH)) \ + { \ + case 0: /* iterated alpha */ \ + c_other.rgb.a = ITERARGB.rgb.a; \ + break; \ + \ + case 1: /* texture alpha */ \ + c_other.rgb.a = TEXELARGB.rgb.a; \ + break; \ + \ + case 2: /* color1 alpha */ \ + c_other.rgb.a = (VV)->reg[color1].rgb.a; \ + break; \ + \ + default: /* reserved */ \ + c_other.rgb.a = 0; \ + break; \ + } \ + \ + /* handle alpha mask */ \ + APPLY_ALPHAMASK(VV, STATS, FBZMODE, c_other.rgb.a); \ + \ + /* compute c_local */ \ + if (FBZCP_CC_LOCALSELECT_OVERRIDE(FBZCOLORPATH) == 0) \ + { \ + if (FBZCP_CC_LOCALSELECT(FBZCOLORPATH) == 0) /* iterated RGB */ \ + c_local.u = ITERARGB.u; \ + else /* color0 RGB */ \ + c_local.u = (VV)->reg[color0].u; \ + } \ + else \ + { \ + if (!(TEXELARGB.rgb.a & 0x80)) /* iterated RGB */ \ + c_local.u = ITERARGB.u; \ + else /* color0 RGB */ \ + c_local.u = (VV)->reg[color0].u; \ + } \ + \ + /* compute a_local */ \ + switch (FBZCP_CCA_LOCALSELECT(FBZCOLORPATH)) \ + { \ + default: \ + case 0: /* iterated alpha */ \ + c_local.rgb.a = ITERARGB.rgb.a; \ + break; \ + \ + case 1: /* color0 alpha */ \ + c_local.rgb.a = (VV)->reg[color0].rgb.a; \ + break; \ + \ + case 2: /* clamped iterated Z[27:20] */ \ + { \ + int temp; \ + CLAMPED_Z(ITERZ, FBZCOLORPATH, temp); \ + c_local.rgb.a = (UINT8)temp; \ + break; \ + } \ + \ + case 3: /* clamped iterated W[39:32] */ \ + { \ + int temp; \ + CLAMPED_W(ITERW, FBZCOLORPATH, temp); /* Voodoo 2 only */ \ + c_local.rgb.a = (UINT8)temp; \ + break; \ + } \ + } \ + \ + /* select zero or a_other */ \ + if (!FBZCP_CCA_ZERO_OTHER(FBZCOLORPATH)) \ + a = c_other.rgb.a; \ + else \ + a = 0; \ + \ + /* subtract a_local */ \ + if (FBZCP_CCA_SUB_CLOCAL(FBZCOLORPATH)) \ + a -= c_local.rgb.a; \ + \ + /* blend alpha */ \ + switch (FBZCP_CCA_MSELECT(FBZCOLORPATH)) \ + { \ + default: /* reserved */ \ + case 0: /* 0 */ \ + blenda = 0; \ + break; \ + \ + case 1: /* a_local */ \ + blenda = c_local.rgb.a; \ + break; \ + \ + case 2: /* a_other */ \ + blenda = c_other.rgb.a; \ + break; \ + \ + case 3: /* a_local */ \ + blenda = c_local.rgb.a; \ + break; \ + \ + case 4: /* texture alpha */ \ + blenda = TEXELARGB.rgb.a; \ + break; \ + } \ + \ + /* reverse the alpha blend */ \ + if (!FBZCP_CCA_REVERSE_BLEND(FBZCOLORPATH)) \ + blenda ^= 0xff; \ + \ + /* do the blend */ \ + a = (a * (blenda + 1)) >> 8; \ + \ + /* add clocal or alocal to alpha */ \ + if (FBZCP_CCA_ADD_ACLOCAL(FBZCOLORPATH)) \ + a += c_local.rgb.a; \ + \ + /* clamp */ \ + CLAMP(a, 0x00, 0xff); \ + \ + /* invert */ \ + if (FBZCP_CCA_INVERT_OUTPUT(FBZCOLORPATH)) \ + a ^= 0xff; \ + \ + /* handle alpha test */ \ + APPLY_ALPHATEST(VV, STATS, ALPHAMODE, a); \ + \ + \ + /* select zero or c_other */ \ + if (FBZCP_CC_ZERO_OTHER(FBZCOLORPATH) == 0) \ + { \ + r = c_other.rgb.r; \ + g = c_other.rgb.g; \ + b = c_other.rgb.b; \ + } \ + else \ + r = g = b = 0; \ + \ + /* subtract c_local */ \ + if (FBZCP_CC_SUB_CLOCAL(FBZCOLORPATH)) \ + { \ + r -= c_local.rgb.r; \ + g -= c_local.rgb.g; \ + b -= c_local.rgb.b; \ + } \ + \ + /* blend RGB */ \ + switch (FBZCP_CC_MSELECT(FBZCOLORPATH)) \ + { \ + default: /* reserved */ \ + case 0: /* 0 */ \ + blendr = blendg = blendb = 0; \ + break; \ + \ + case 1: /* c_local */ \ + blendr = c_local.rgb.r; \ + blendg = c_local.rgb.g; \ + blendb = c_local.rgb.b; \ + break; \ + \ + case 2: /* a_other */ \ + blendr = blendg = blendb = c_other.rgb.a; \ + break; \ + \ + case 3: /* a_local */ \ + blendr = blendg = blendb = c_local.rgb.a; \ + break; \ + \ + case 4: /* texture alpha */ \ + blendr = blendg = blendb = TEXELARGB.rgb.a; \ + break; \ + \ + case 5: /* texture RGB (Voodoo 2 only) */ \ + blendr = TEXELARGB.rgb.r; \ + blendg = TEXELARGB.rgb.g; \ + blendb = TEXELARGB.rgb.b; \ + break; \ + } \ + \ + /* reverse the RGB blend */ \ + if (!FBZCP_CC_REVERSE_BLEND(FBZCOLORPATH)) \ + { \ + blendr ^= 0xff; \ + blendg ^= 0xff; \ + blendb ^= 0xff; \ + } \ + \ + /* do the blend */ \ + r = (r * (blendr + 1)) >> 8; \ + g = (g * (blendg + 1)) >> 8; \ + b = (b * (blendb + 1)) >> 8; \ + \ + /* add clocal or alocal to RGB */ \ + switch (FBZCP_CC_ADD_ACLOCAL(FBZCOLORPATH)) \ + { \ + case 3: /* reserved */ \ + case 0: /* nothing */ \ + break; \ + \ + case 1: /* add c_local */ \ + r += c_local.rgb.r; \ + g += c_local.rgb.g; \ + b += c_local.rgb.b; \ + break; \ + \ + case 2: /* add_alocal */ \ + r += c_local.rgb.a; \ + g += c_local.rgb.a; \ + b += c_local.rgb.a; \ + break; \ + } \ + \ + /* clamp */ \ + CLAMP(r, 0x00, 0xff); \ + CLAMP(g, 0x00, 0xff); \ + CLAMP(b, 0x00, 0xff); \ + \ + /* invert */ \ + if (FBZCP_CC_INVERT_OUTPUT(FBZCOLORPATH)) \ + { \ + r ^= 0xff; \ + g ^= 0xff; \ + b ^= 0xff; \ + } \ +} \ +while (0) + +INLINE bool ATTR_FORCE_INLINE combineColor(voodoo_state *VV, stats_block *STATS, UINT32 FBZCOLORPATH, UINT32 FBZMODE, UINT32 ALPHAMODE, + rgbaint_t TEXELARGB, INT32 ITERZ, INT64 ITERW, rgbaint_t &srcColor) +{ + rgbaint_t c_other; + rgbaint_t c_local; + + /* compute c_other */ + switch (FBZCP_CC_RGBSELECT(FBZCOLORPATH)) + { + case 0: /* iterated RGB */ + c_other.set(srcColor); + break; + + case 1: /* texture RGB */ + c_other.set(TEXELARGB); + break; + + case 2: /* color1 RGB */ + c_other.set((VV)->reg[color1].u); + break; + + default: /* reserved - voodoo3 framebufferRGB */ + c_other.set(0); + break; + } + + /* handle chroma key */ + if (!chromaKeyTest(VV, STATS, FBZMODE, c_other)) + return false; + //APPLY_CHROMAKEY(VV, STATS, FBZMODE, c_other); + + /* compute a_other */ + switch (FBZCP_CC_ASELECT(FBZCOLORPATH)) + { + case 0: /* iterated alpha */ + c_other.merge_alpha(srcColor); + break; + + case 1: /* texture alpha */ + c_other.merge_alpha(TEXELARGB); + break; + + case 2: /* color1 alpha */ + c_other.set_a((VV)->reg[color1].rgb.a); + break; + + default: /* reserved */ + c_other.set_a(0); + break; + } + + /* handle alpha mask */ + if (!alphaMaskTest(STATS, FBZMODE, c_other.get_a())) + return false; + //APPLY_ALPHAMASK(VV, STATS, FBZMODE, c_other.rgb.a); + + + /* compute c_local */ + if (FBZCP_CC_LOCALSELECT_OVERRIDE(FBZCOLORPATH) == 0) + { + if (FBZCP_CC_LOCALSELECT(FBZCOLORPATH) == 0) /* iterated RGB */ + c_local.set(srcColor); + else /* color0 RGB */ + c_local.set((VV)->reg[color0].u); + } + else + { + if (!(TEXELARGB.get_a() & 0x80)) /* iterated RGB */ + c_local.set(srcColor); + else /* color0 RGB */ + c_local.set((VV)->reg[color0].u); + } + + /* compute a_local */ + switch (FBZCP_CCA_LOCALSELECT(FBZCOLORPATH)) + { + default: + case 0: /* iterated alpha */ + c_local.merge_alpha(srcColor); + break; + + case 1: /* color0 alpha */ + c_local.set_a((VV)->reg[color0].rgb.a); + break; + + case 2: /* clamped iterated Z[27:20] */ + { + int temp; + CLAMPED_Z(ITERZ, FBZCOLORPATH, temp); + c_local.set_a((UINT8) temp); + break; + } + + case 3: /* clamped iterated W[39:32] */ + { + int temp; + CLAMPED_W(ITERW, FBZCOLORPATH, temp); /* Voodoo 2 only */ + c_local.set_a((UINT8) temp); + break; + } + } + + UINT8 a_other = c_other.get_a(); + UINT8 a_local = c_local.get_a(); + UINT8 tmp; + rgbaint_t add_val(c_local); + + /* select zero or c_other */ + if (FBZCP_CC_ZERO_OTHER(FBZCOLORPATH)) + c_other.and_imm_rgba(-1, 0, 0, 0); + //r = g = b = 0; + + /* select zero or a_other */ + if (FBZCP_CCA_ZERO_OTHER(FBZCOLORPATH)) + c_other.set_a(0); + + /* subtract a/c_local */ + if (FBZCP_CC_SUB_CLOCAL(FBZCOLORPATH) || (FBZCP_CCA_SUB_CLOCAL(FBZCOLORPATH))) + { + rgbaint_t sub_val = c_local; + + if (!FBZCP_CC_SUB_CLOCAL(FBZCOLORPATH)) + sub_val.set(a_local, 0, 0, 0); + + if (!FBZCP_CCA_SUB_CLOCAL(FBZCOLORPATH)) + sub_val.set_a(0); + + c_other.sub(sub_val); + } + + /* blend RGB */ + switch (FBZCP_CC_MSELECT(FBZCOLORPATH)) + { + default: /* reserved */ + case 0: /* 0 */ + c_local.and_imm_rgba(-1, 0, 0, 0); + break; + + case 1: /* c_local */ + break; + + case 2: /* a_other */ + c_local.set(a_local, a_other, a_other, a_other); + break; + + case 3: /* a_local */ + c_local.set(a_local, a_local, a_local, a_local); + break; + + case 4: /* texture alpha */ + tmp = TEXELARGB.get_a(); + c_local.set(a_local, tmp, tmp, tmp); + break; + + case 5: /* texture RGB (Voodoo 2 only) */ + c_local.set(TEXELARGB); + break; + } + + /* blend alpha */ + switch (FBZCP_CCA_MSELECT(FBZCOLORPATH)) + { + default: /* reserved */ + case 0: /* 0 */ + c_local.set_a(0); + break; + + case 1: /* a_local */ + case 3: /* a_local */ + c_local.set_a(a_local); + break; + + case 2: /* a_other */ + c_local.set_a(a_other); + break; + + case 4: /* texture alpha */ + c_local.merge_alpha(TEXELARGB); + break; + } + + /* reverse the RGB blend */ + if (!FBZCP_CC_REVERSE_BLEND(FBZCOLORPATH)) + c_local.xor_imm_rgba(0, 0xff, 0xff, 0xff); + + /* reverse the alpha blend */ + if (!FBZCP_CCA_REVERSE_BLEND(FBZCOLORPATH)) + c_local.xor_imm_rgba(0xff, 0, 0, 0); + + /* do the blend */ + //color.rgb.a = (color.rgb.a * (blenda + 1)) >> 8; + //color.rgb.r = (color.rgb.r * (blendr + 1)) >> 8; + //color.rgb.g = (color.rgb.g * (blendg + 1)) >> 8; + //color.rgb.b = (color.rgb.b * (blendb + 1)) >> 8; + + /* add clocal or alocal to RGB */ + switch (FBZCP_CC_ADD_ACLOCAL(FBZCOLORPATH)) + { + case 3: /* reserved */ + case 0: /* nothing */ + add_val.set(a_local, 0, 0, 0); + break; + + case 1: /* add c_local */ + break; + + case 2: /* add_alocal */ + add_val.set(a_local, a_local, a_local, a_local); + break; + } + + /* add clocal or alocal to alpha */ + if (!FBZCP_CCA_ADD_ACLOCAL(FBZCOLORPATH)) + add_val.set_a(0); + //color.rgb.a += c_local.rgb.a; + + /* clamp */ + //CLAMP(color.rgb.a, 0x00, 0xff); + //CLAMP(color.rgb.r, 0x00, 0xff); + //CLAMP(color.rgb.g, 0x00, 0xff); + //CLAMP(color.rgb.b, 0x00, 0xff); + c_local.add_imm(1); + c_other.scale_add_and_clamp(c_local, add_val); + srcColor.set(c_other); + + /* invert */ + if (FBZCP_CCA_INVERT_OUTPUT(FBZCOLORPATH)) + srcColor.xor_imm_rgba(0xff, 0, 0, 0); + /* invert */ + if (FBZCP_CC_INVERT_OUTPUT(FBZCOLORPATH)) + srcColor.xor_imm_rgba(0, 0xff, 0xff, 0xff); + + + /* handle alpha test */ + if (!alphaTest(VV, STATS, ALPHAMODE, srcColor.get_a())) + return false; + //APPLY_ALPHATEST(VV, STATS, ALPHAMODE, color.rgb.a); + + return true; +} + + + +/************************************* + * + * Rasterizer generator macro + * + *************************************/ +#if USE_OLD_RASTER == 1 +#define RASTERIZER(name, TMUS, FBZCOLORPATH, FBZMODE, ALPHAMODE, FOGMODE, TEXMODE0, TEXMODE1) \ + \ +static void raster_##name(void *destbase, INT32 y, const poly_extent *extent, const void *extradata, int threadid) \ +{ \ + const poly_extra_data *extra = (const poly_extra_data *)extradata; \ + voodoo_state *v = extra->state; \ + stats_block *stats = &v->thread_stats[threadid]; \ + DECLARE_DITHER_POINTERS; \ + INT32 startx = extent->startx; \ + INT32 stopx = extent->stopx; \ + INT32 iterr, iterg, iterb, itera; \ + INT32 iterz; \ + INT64 iterw, iterw0 = 0, iterw1 = 0; \ + INT64 iters0 = 0, iters1 = 0; \ + INT64 itert0 = 0, itert1 = 0; \ + UINT16 *depth; \ + UINT16 *dest; \ + INT32 dx, dy; \ + INT32 scry; \ + INT32 x; \ + \ + /* determine the screen Y */ \ + scry = y; \ + if (FBZMODE_Y_ORIGIN(FBZMODE)) \ + scry = (v->fbi.yorigin - y) & 0x3ff; \ + \ + /* compute dithering */ \ + COMPUTE_DITHER_POINTERS(FBZMODE, y); \ + \ + /* apply clipping */ \ + if (FBZMODE_ENABLE_CLIPPING(FBZMODE)) \ + { \ + INT32 tempclip; \ + \ + /* Y clipping buys us the whole scanline */ \ + if (scry < ((v->reg[clipLowYHighY].u >> 16) & 0x3ff) || \ + scry >= (v->reg[clipLowYHighY].u & 0x3ff)) \ + { \ + stats->pixels_in += stopx - startx; \ + stats->clip_fail += stopx - startx; \ + return; \ + } \ + \ + /* X clipping */ \ + tempclip = (v->reg[clipLeftRight].u >> 16) & 0x3ff; \ + if (startx < tempclip) \ + { \ + stats->pixels_in += tempclip - startx; \ + v->stats.total_clipped += tempclip - startx; \ + startx = tempclip; \ + } \ + tempclip = v->reg[clipLeftRight].u & 0x3ff; \ + if (stopx >= tempclip) \ + { \ + stats->pixels_in += stopx - tempclip; \ + v->stats.total_clipped += stopx - tempclip; \ + stopx = tempclip - 1; \ + } \ + } \ + \ + /* get pointers to the target buffer and depth buffer */ \ + dest = (UINT16 *)destbase + scry * v->fbi.rowpixels; \ + depth = (v->fbi.auxoffs != ~0) ? ((UINT16 *)(v->fbi.ram + v->fbi.auxoffs) + scry * v->fbi.rowpixels) : NULL; \ + \ + /* compute the starting parameters */ \ + dx = startx - (extra->ax >> 4); \ + dy = y - (extra->ay >> 4); \ + iterr = extra->startr + dy * extra->drdy + dx * extra->drdx; \ + iterg = extra->startg + dy * extra->dgdy + dx * extra->dgdx; \ + iterb = extra->startb + dy * extra->dbdy + dx * extra->dbdx; \ + itera = extra->starta + dy * extra->dady + dx * extra->dadx; \ + iterz = extra->startz + dy * extra->dzdy + dx * extra->dzdx; \ + iterw = extra->startw + dy * extra->dwdy + dx * extra->dwdx; \ + if (TMUS >= 1) \ + { \ + iterw0 = extra->startw0 + dy * extra->dw0dy + dx * extra->dw0dx; \ + iters0 = extra->starts0 + dy * extra->ds0dy + dx * extra->ds0dx; \ + itert0 = extra->startt0 + dy * extra->dt0dy + dx * extra->dt0dx; \ + } \ + if (TMUS >= 2) \ + { \ + iterw1 = extra->startw1 + dy * extra->dw1dy + dx * extra->dw1dx; \ + iters1 = extra->starts1 + dy * extra->ds1dy + dx * extra->ds1dx; \ + itert1 = extra->startt1 + dy * extra->dt1dy + dx * extra->dt1dx; \ + } \ + extra->info->hits++; \ + /* loop in X */ \ + for (x = startx; x < stopx; x++) \ + { \ + rgb_union iterargb; \ + rgb_union texel = { 0 }; \ + \ + /* pixel pipeline part 1 handles depth setup and stippling */ \ + PIXEL_PIPELINE_BEGIN(v, stats, x, y, FBZCOLORPATH, FBZMODE, iterz, iterw); \ + DEPTH_TEST(v, stats, x, FBZMODE); \ + \ + /* run the texture pipeline on TMU1 to produce a value in texel */ \ + /* note that they set LOD min to 8 to "disable" a TMU */ \ + if (TMUS >= 2 && v->tmu[1].lodmin < (8 << 8)) \ + TEXTURE_PIPELINE(&v->tmu[1], x, dither4, TEXMODE1, texel, \ + v->tmu[1].lookup, extra->lodbase1, \ + iters1, itert1, iterw1, texel); \ + \ + /* run the texture pipeline on TMU0 to produce a final */ \ + /* result in texel */ \ + /* note that they set LOD min to 8 to "disable" a TMU */ \ + if (TMUS >= 1 && v->tmu[0].lodmin < (8 << 8)) \ + { \ + if (!v->send_config) \ + TEXTURE_PIPELINE(&v->tmu[0], x, dither4, TEXMODE0, texel, \ + v->tmu[0].lookup, extra->lodbase0, \ + iters0, itert0, iterw0, texel); \ + else \ + texel.u = v->tmu_config; \ + } \ + /* colorpath pipeline selects source colors and does blending */ \ + CLAMPED_ARGB(iterr, iterg, iterb, itera, FBZCOLORPATH, iterargb); \ + COLORPATH_PIPELINE(v, stats, FBZCOLORPATH, FBZMODE, ALPHAMODE, texel, \ + iterz, iterw, iterargb); \ + \ + /* pixel pipeline part 2 handles fog, alpha, and final output */ \ + PIXEL_PIPELINE_END(v, stats, dither, dither4, dither_lookup, x, dest, depth, \ + FBZMODE, FBZCOLORPATH, ALPHAMODE, FOGMODE, \ + iterz, iterw, iterargb); \ + \ + /* update the iterated parameters */ \ + iterr += extra->drdx; \ + iterg += extra->dgdx; \ + iterb += extra->dbdx; \ + itera += extra->dadx; \ + iterz += extra->dzdx; \ + iterw += extra->dwdx; \ + if (TMUS >= 1) \ + { \ + iterw0 += extra->dw0dx; \ + iters0 += extra->ds0dx; \ + itert0 += extra->dt0dx; \ + } \ + if (TMUS >= 2) \ + { \ + iterw1 += extra->dw1dx; \ + iters1 += extra->ds1dx; \ + itert1 += extra->dt1dx; \ + } \ + } \ +} +#else +// New rasterizer implementation +#define RASTERIZER(name, TMUS, FBZCOLORPATH, FBZMODE, ALPHAMODE, FOGMODE, TEXMODE0, TEXMODE1) \ + \ +static void raster_##name(void *destbase, INT32 y, const poly_extent *extent, const void *extradata, int threadid) \ +{ \ + const poly_extra_data *extra = (const poly_extra_data *)extradata; \ + voodoo_state *v = extra->state; \ + stats_block *stats = &v->thread_stats[threadid]; \ + DECLARE_DITHER_POINTERS; \ + INT32 startx = extent->startx; \ + INT32 stopx = extent->stopx; \ + rgbaint_t iterargb, iterargbDelta; \ + INT32 iterz; \ + INT64 iterw, iterw0 = 0, iterw1 = 0; \ + INT64 iters0 = 0, iters1 = 0; \ + INT64 itert0 = 0, itert1 = 0; \ + UINT16 *depth; \ + UINT16 *dest; \ + INT32 dx, dy; \ + INT32 scry; \ + INT32 x; \ + \ + /* determine the screen Y */ \ + scry = y; \ + if (FBZMODE_Y_ORIGIN(FBZMODE)) \ + scry = (v->fbi.yorigin - y) & 0x3ff; \ + \ + /* compute dithering */ \ + COMPUTE_DITHER_POINTERS(FBZMODE, y); \ + \ + /* apply clipping */ \ + if (FBZMODE_ENABLE_CLIPPING(FBZMODE)) \ + { \ + INT32 tempclip; \ + \ + /* Y clipping buys us the whole scanline */ \ + if (scry < ((v->reg[clipLowYHighY].u >> 16) & 0x3ff) || \ + scry >= (v->reg[clipLowYHighY].u & 0x3ff)) \ + { \ + stats->pixels_in += stopx - startx; \ + stats->clip_fail += stopx - startx; \ + return; \ + } \ + \ + /* X clipping */ \ + tempclip = (v->reg[clipLeftRight].u >> 16) & 0x3ff; \ + if (startx < tempclip) \ + { \ + stats->pixels_in += tempclip - startx; \ + v->stats.total_clipped += tempclip - startx; \ + startx = tempclip; \ + } \ + tempclip = v->reg[clipLeftRight].u & 0x3ff; \ + if (stopx >= tempclip) \ + { \ + stats->pixels_in += stopx - tempclip; \ + v->stats.total_clipped += stopx - tempclip; \ + stopx = tempclip - 1; \ + } \ + } \ + \ + /* get pointers to the target buffer and depth buffer */ \ + dest = (UINT16 *)destbase + scry * v->fbi.rowpixels; \ + depth = (v->fbi.auxoffs != ~0) ? ((UINT16 *)(v->fbi.ram + v->fbi.auxoffs) + scry * v->fbi.rowpixels) : NULL; \ + \ + /* compute the starting parameters */ \ + dx = startx - (extra->ax >> 4); \ + dy = y - (extra->ay >> 4); \ + INT32 iterr = extra->startr + dy * extra->drdy + dx * extra->drdx; \ + INT32 iterg = extra->startg + dy * extra->dgdy + dx * extra->dgdx; \ + INT32 iterb = extra->startb + dy * extra->dbdy + dx * extra->dbdx; \ + INT32 itera = extra->starta + dy * extra->dady + dx * extra->dadx; \ + iterargb.set(itera, iterr, iterg, iterb); \ + iterargbDelta.set(extra->dadx, extra->drdx, extra->dgdx, extra->dbdx); \ + iterz = extra->startz + dy * extra->dzdy + dx * extra->dzdx; \ + iterw = extra->startw + dy * extra->dwdy + dx * extra->dwdx; \ + if (TMUS >= 1) \ + { \ + iterw0 = extra->startw0 + dy * extra->dw0dy + dx * extra->dw0dx; \ + iters0 = extra->starts0 + dy * extra->ds0dy + dx * extra->ds0dx; \ + itert0 = extra->startt0 + dy * extra->dt0dy + dx * extra->dt0dx; \ + } \ + if (TMUS >= 2) \ + { \ + iterw1 = extra->startw1 + dy * extra->dw1dy + dx * extra->dw1dx; \ + iters1 = extra->starts1 + dy * extra->ds1dy + dx * extra->ds1dx; \ + itert1 = extra->startt1 + dy * extra->dt1dy + dx * extra->dt1dx; \ + } \ + extra->info->hits++; \ + /* loop in X */ \ + for (x = startx; x < stopx; x++) \ + { \ + rgbaint_t texel(0); \ + rgbaint_t color, preFog; \ + \ + /* pixel pipeline part 1 handles depth setup and stippling */ \ + PIXEL_PIPELINE_BEGIN(v, stats, x, y, FBZCOLORPATH, FBZMODE, iterz, iterw); \ + /* depth testing */ \ + if (!depthTest((UINT16) v->reg[zaColor].u, stats, depth[x], FBZMODE, biasdepth)) \ + goto skipdrawdepth; \ + \ + /* run the texture pipeline on TMU1 to produce a value in texel */ \ + /* note that they set LOD min to 8 to "disable" a TMU */ \ + if (TMUS >= 2 && v->tmu[1].lodmin < (8 << 8)) { \ + INT32 tmp; \ + const rgbaint_t texelZero(0); \ + texel = genTexture(&v->tmu[1], x, dither4, TEXMODE1, v->tmu[1].lookup, extra->lodbase1, \ + iters1, itert1, iterw1, tmp); \ + texel = combineTexture(&v->tmu[1], TEXMODE1, texel, texelZero, tmp); \ + } \ + /* run the texture pipeline on TMU0 to produce a final */ \ + /* result in texel */ \ + /* note that they set LOD min to 8 to "disable" a TMU */ \ + if (TMUS >= 1 && v->tmu[0].lodmin < (8 << 8)) \ + { \ + if (!v->send_config) \ + { \ + INT32 lod0; \ + rgbaint_t texelT0; \ + texelT0 = genTexture(&v->tmu[0], x, dither4, TEXMODE0, v->tmu[0].lookup, extra->lodbase0, \ + iters0, itert0, iterw0, lod0); \ + texel = combineTexture(&v->tmu[0], TEXMODE0, texelT0, texel, lod0); \ + } \ + else \ + { \ + texel.set(v->tmu_config); \ + } \ + } \ + \ + /* colorpath pipeline selects source colors and does blending */ \ + color = clampARGB(iterargb, FBZCOLORPATH); \ + if (!combineColor(v, stats, FBZCOLORPATH, FBZMODE, ALPHAMODE, texel, iterz, iterw, color)) \ + goto skipdrawdepth; \ + \ + /* pixel pipeline part 2 handles fog, alpha, and final output */ \ + PIXEL_PIPELINE_END(v, stats, dither, dither4, dither_lookup, x, dest, depth, \ + FBZMODE, FBZCOLORPATH, ALPHAMODE, FOGMODE, \ + iterz, iterw, iterargb); \ + \ + /* update the iterated parameters */ \ + iterargb += iterargbDelta; \ + iterz += extra->dzdx; \ + iterw += extra->dwdx; \ + if (TMUS >= 1) \ + { \ + iterw0 += extra->dw0dx; \ + iters0 += extra->ds0dx; \ + itert0 += extra->dt0dx; \ + } \ + if (TMUS >= 2) \ + { \ + iterw1 += extra->dw1dx; \ + iters1 += extra->ds1dx; \ + itert1 += extra->dt1dx; \ + } \ + } \ +} +#endif +// ****************************************************************************************************************************** +// Computes a log2 of a 16.32 value to 2 fractional bits of precision. +// The return value is coded as a 24.8 value. +// The maximum error using a 4 bit lookup from the mantissa is 0.0875, which is less than 1/2 lsb (0.125) for 2 bits of fraction. +// ****************************************************************************************************************************** +INLINE INT32 ATTR_FORCE_INLINE new_log2(double &value) +{ + static const INT32 new_log2_table[16] = {0, 22, 44, 63, 82, 100, 118, 134, 150, 165, 179, 193, 207, 220, 232, 244}; + UINT64 ival = *((UINT64 *)&value); + // We zero the result if negative so don't worry about the sign bit + INT32 exp = (ival>>52); + exp -= 1023+32; + exp <<= 8; + UINT32 addr = (UINT64)(ival>>48) & 0xf; + exp += new_log2_table[addr]; + // Return 0 if negative + return (ival & ((UINT64)1<<63)) ? 0 : exp; +} + +// Computes A/C and B/C and returns log2 of 1/C +// A, B and C are 16.32 values. The results are 24.8. +INLINE void ATTR_FORCE_INLINE multi_reciplog(INT64 valueA, INT64 valueB, INT64 valueC, INT32 &log, INT32 &resA, INT32 &resB) +{ + double recip = double(1ULL<<(47-39))/valueC; + double resAD = valueA * recip; + double resBD = valueB * recip; + log = new_log2(recip); + log += 56<<8; + resA = resAD; + resB = resBD; +} + + +INLINE rgbaint_t ATTR_FORCE_INLINE genTexture(tmu_state *TT, INT32 x, const UINT8 *dither4, const UINT32 TEXMODE, rgb_t *LOOKUP, INT32 LODBASE, INT64 ITERS, INT64 ITERT, INT64 ITERW, INT32 &lod) +{ + rgbaint_t result; + INT32 s, t, ilod; + + /* determine the S/T/LOD values for this texture */ + lod = (LODBASE); + if (TEXMODE_ENABLE_PERSPECTIVE(TEXMODE)) + { + INT32 wLog; + if (USE_FAST_RECIP) { + const INT32 oow = fast_reciplog((ITERW), &wLog); + s = ((INT64)oow * (ITERS)) >> (29+10); + t = ((INT64)oow * (ITERT)) >> (29+10); + } else { + multi_reciplog(ITERS, ITERT, ITERW, wLog, s, t); + } + lod += wLog; + } + else + { + s = (ITERS) >> (14+10); + t = (ITERT) >> (14+10); + } + + /* clamp W */ + if (TEXMODE_CLAMP_NEG_W(TEXMODE) && (ITERW) < 0) + { + s = t = 0; + } + + /* clamp the LOD */ + lod += (TT)->lodbias; + if (TEXMODE_ENABLE_LOD_DITHER(TEXMODE)) + lod += dither4[x&3] << 4; + if (lod < (TT)->lodmin) + lod = (TT)->lodmin; + else if (lod > (TT)->lodmax) + lod = (TT)->lodmax; + + /* now the LOD is in range; if we don't own this LOD, take the next one */ + ilod = lod >> 8; + if (!(((TT)->lodmask >> ilod) & 1)) + ilod++; + + /* fetch the texture base */ + UINT32 texbase = (TT)->lodoffset[ilod]; + + /* compute the maximum s and t values at this LOD */ + INT32 smax = (TT)->wmask >> ilod; + INT32 tmax = (TT)->hmask >> ilod; + + /* determine whether we are point-sampled or bilinear */ + if ((lod == (TT)->lodmin && !TEXMODE_MAGNIFICATION_FILTER(TEXMODE)) || + (lod != (TT)->lodmin && !TEXMODE_MINIFICATION_FILTER(TEXMODE))) + { + /* point sampled */ + + UINT32 texel0; + + /* adjust S/T for the LOD and strip off the fractions */ + s >>= ilod + (18-10); + t >>= ilod + (18-10); + + /* clamp/wrap S/T if necessary */ + if (TEXMODE_CLAMP_S(TEXMODE)) + CLAMP(s, 0, smax); + if (TEXMODE_CLAMP_T(TEXMODE)) + CLAMP(t, 0, tmax); + s &= smax; + t &= tmax; + t *= smax + 1; + + /* fetch texel data */ + if (TEXMODE_FORMAT(TEXMODE) < 8) + { + texel0 = *(UINT8 *)&(TT)->ram[(texbase + t + s) & (TT)->mask]; + result.set((LOOKUP)[texel0]); + } + else + { + texel0 = *(UINT16 *)&(TT)->ram[(texbase + 2*(t + s)) & (TT)->mask]; + if (TEXMODE_FORMAT(TEXMODE) >= 10 && TEXMODE_FORMAT(TEXMODE) <= 12) + result.set((LOOKUP)[texel0]); + else + result.set(((LOOKUP)[texel0 & 0xff] & 0xffffff) | ((texel0 & 0xff00) << 16)); + } + } + else + { + /* bilinear filtered */ + + UINT32 texel0, texel1, texel2, texel3; + UINT32 sfrac, tfrac; + INT32 s1, t1; + + /* adjust S/T for the LOD and strip off all but the low 8 bits of */ + /* the fraction */ + s >>= ilod; // + (10-10); + t >>= ilod; // + (10-10); + + /* also subtract 1/2 texel so that (0.5,0.5) = a full (0,0) texel */ + s -= 0x80; + t -= 0x80; + + /* extract the fractions */ + sfrac = s & (TT)->bilinear_mask; + tfrac = t & (TT)->bilinear_mask; + + /* now toss the rest */ + s >>= 8; + t >>= 8; + s1 = s + 1; + t1 = t + 1; + + /* clamp/wrap S/T if necessary */ + if (TEXMODE_CLAMP_S(TEXMODE)) + { + if (s < 0) { + s = 0; + s1 = 0; + } else if (s >= smax) { + s = smax; + s1 = smax; + } + //CLAMP(s, 0, smax); + //CLAMP(s1, 0, smax); + } else { + s &= smax; + s1 &= smax; + } + + if (TEXMODE_CLAMP_T(TEXMODE)) + { + if (t < 0) { + t = 0; + t1 = 0; + } else if (t >= tmax) { + t = tmax; + t1 = tmax; + } + //CLAMP(t, 0, tmax); + //CLAMP(t1, 0, tmax); + } else { + t &= tmax; + t1 &= tmax; + } + t *= smax + 1; + t1 *= smax + 1; + + /* fetch texel data */ + if (TEXMODE_FORMAT(TEXMODE) < 8) + { + texel0 = *(UINT8 *)&(TT)->ram[(texbase + t + s)]; + texel1 = *(UINT8 *)&(TT)->ram[(texbase + t + s1)]; + texel2 = *(UINT8 *)&(TT)->ram[(texbase + t1 + s)]; + texel3 = *(UINT8 *)&(TT)->ram[(texbase + t1 + s1)]; + texel0 = (LOOKUP)[texel0]; + texel1 = (LOOKUP)[texel1]; + texel2 = (LOOKUP)[texel2]; + texel3 = (LOOKUP)[texel3]; + } + else + { + texel0 = *(UINT16 *)&(TT)->ram[(texbase + 2*(t + s))]; + texel1 = *(UINT16 *)&(TT)->ram[(texbase + 2*(t + s1))]; + texel2 = *(UINT16 *)&(TT)->ram[(texbase + 2*(t1 + s))]; + texel3 = *(UINT16 *)&(TT)->ram[(texbase + 2*(t1 + s1))]; + if (TEXMODE_FORMAT(TEXMODE) >= 10 && TEXMODE_FORMAT(TEXMODE) <= 12) + { + texel0 = (LOOKUP)[texel0]; + texel1 = (LOOKUP)[texel1]; + texel2 = (LOOKUP)[texel2]; + texel3 = (LOOKUP)[texel3]; + } + else + { + texel0 = ((LOOKUP)[texel0 & 0xff] & 0xffffff) | ((texel0 & 0xff00) << 16); + texel1 = ((LOOKUP)[texel1 & 0xff] & 0xffffff) | ((texel1 & 0xff00) << 16); + texel2 = ((LOOKUP)[texel2 & 0xff] & 0xffffff) | ((texel2 & 0xff00) << 16); + texel3 = ((LOOKUP)[texel3 & 0xff] & 0xffffff) | ((texel3 & 0xff00) << 16); + } + } + + /* weigh in each texel */ + + result.bilinear_filter_rgbaint(texel0, texel1, texel2, texel3, sfrac, tfrac); + } + return result; +} + +INLINE rgbaint_t ATTR_FORCE_INLINE combineTexture(tmu_state *TT, const UINT32 TEXMODE, rgbaint_t c_local, rgbaint_t c_other, INT32 lod) +{ + INT32 a_other = c_other.get_a(); + INT32 a_local = c_local.get_a(); + rgbaint_t add_val = c_local; + UINT8 tmp; + + /* select zero/other for RGB */ + if (TEXMODE_TC_ZERO_OTHER(TEXMODE)) + c_other.and_imm_rgba(-1, 0, 0, 0); + + /* select zero/other for alpha */ + if (TEXMODE_TCA_ZERO_OTHER(TEXMODE)) + c_other.set_a(0); + + if (TEXMODE_TC_SUB_CLOCAL(TEXMODE) || TEXMODE_TCA_SUB_CLOCAL(TEXMODE)) + { + rgbaint_t sub_val = c_local; + + /* potentially subtract c_local */ + if (!TEXMODE_TC_SUB_CLOCAL(TEXMODE)) + sub_val.and_imm_rgba(-1, 0, 0, 0); + + if (!TEXMODE_TCA_SUB_CLOCAL(TEXMODE)) + sub_val.set_a(0); + + c_other.sub(sub_val); + } + + /* blend RGB */ + switch (TEXMODE_TC_MSELECT(TEXMODE)) + { + default: /* reserved */ + case 0: /* zero */ + c_local.and_imm_rgba(-1, 0, 0, 0); + break; + + case 1: /* c_local */ + break; + + case 2: /* a_other */ + c_local.set(a_local, a_other, a_other, a_other); + break; + + case 3: /* a_local */ + c_local.set(a_local, a_local, a_local, a_local); + break; + + case 4: /* LOD (detail factor) */ + if ((TT)->detailbias <= lod) + c_local.and_imm_rgba(-1, 0, 0, 0); + else + { + tmp = ((((TT)->detailbias - lod) << (TT)->detailscale) >> 8); + if (tmp > (TT)->detailmax) + tmp = (TT)->detailmax; + c_local.set(a_local, tmp, tmp, tmp); + } + break; + + case 5: /* LOD fraction */ + tmp = lod & 0xff; + c_local.set(a_local, tmp, tmp, tmp); + break; + } + + /* blend alpha */ + switch (TEXMODE_TCA_MSELECT(TEXMODE)) + { + default: /* reserved */ + case 0: /* zero */ + c_local.set_a(0); + break; + + case 1: /* c_local */ + break; + + case 2: /* a_other */ + c_local.set_a(a_other); + break; + + case 3: /* a_local */ + break; + + case 4: /* LOD (detail factor) */ + if ((TT)->detailbias <= lod) + c_local.set_a(0); + else + { + tmp = ((((TT)->detailbias - lod) << (TT)->detailscale) >> 8); + if (tmp > (TT)->detailmax) + tmp = (TT)->detailmax; + c_local.set_a(tmp); + } + break; + + case 5: /* LOD fraction */ + c_local.set_a(lod & 0xff); + break; + } + + /* reverse the RGB blend */ + if (!TEXMODE_TC_REVERSE_BLEND(TEXMODE)) + { + c_local.xor_imm_rgba(0, 0xff, 0xff, 0xff); + } + + /* reverse the alpha blend */ + if (!TEXMODE_TCA_REVERSE_BLEND(TEXMODE)) + c_local.xor_imm_rgba(0xff, 0, 0, 0); + + /* do the blend */ + //tr = (tr * (blendr + 1)) >> 8; + //tg = (tg * (blendg + 1)) >> 8; + //tb = (tb * (blendb + 1)) >> 8; + //ta = (ta * (blenda + 1)) >> 8; + + /* add clocal or alocal to RGB */ + switch (TEXMODE_TC_ADD_ACLOCAL(TEXMODE)) + { + case 3: /* reserved */ + case 0: /* nothing */ + add_val.set(a_local, 0, 0, 0); + break; + + case 1: /* add c_local */ + break; + + case 2: /* add_alocal */ + add_val.set(a_local, a_local , a_local , a_local); + //tr += c_local.rgb.a; + //tg += c_local.rgb.a; + //tb += c_local.rgb.a; + break; + } + + /* add clocal or alocal to alpha */ + if (!TEXMODE_TCA_ADD_ACLOCAL(TEXMODE)) + add_val.set_a(0); + //ta += c_local.rgb.a; + + /* clamp */ + //result.rgb.r = (tr < 0) ? 0 : (tr > 0xff) ? 0xff : tr; + //result.rgb.g = (tg < 0) ? 0 : (tg > 0xff) ? 0xff : tg; + //result.rgb.b = (tb < 0) ? 0 : (tb > 0xff) ? 0xff : tb; + //result.rgb.a = (ta < 0) ? 0 : (ta > 0xff) ? 0xff : ta; + c_local.add_imm(1); + c_other.scale_add_and_clamp(c_local, add_val); + rgbaint_t result(c_other); + /* invert */ + if (TEXMODE_TC_INVERT_OUTPUT(TEXMODE)) + result.xor_imm_rgba(0, 0xff, 0xff, 0xff); + if (TEXMODE_TCA_INVERT_OUTPUT(TEXMODE)) + result.xor_imm_rgba(0xff, 0, 0, 0); + return result; +} diff --git a/src/devices/video/voodoo.c b/src/devices/video/voodoo.c new file mode 100644 index 00000000000..1874fccad29 --- /dev/null +++ b/src/devices/video/voodoo.c @@ -0,0 +1,6537 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + voodoo.c + + 3dfx Voodoo Graphics SST-1/2 emulator. + +**************************************************************************** + +//fix me -- blitz2k dies when starting a game with heavy fog (in DRC) + +**************************************************************************** + + 3dfx Voodoo Graphics SST-1/2 emulator + + emulator by Aaron Giles + + -------------------------- + + Specs: + + Voodoo 1 (SST1): + 2,4MB frame buffer RAM + 1,2,4MB texture RAM + 50MHz clock frequency + clears @ 2 pixels/clock (RGB and depth simultaneously) + renders @ 1 pixel/clock + 64 entry PCI FIFO + memory FIFO up to 65536 entries + + Voodoo 2: + 2,4MB frame buffer RAM + 2,4,8,16MB texture RAM + 90MHz clock frquency + clears @ 2 pixels/clock (RGB and depth simultaneously) + renders @ 1 pixel/clock + ultrafast clears @ 16 pixels/clock + 128 entry PCI FIFO + memory FIFO up to 65536 entries + + Voodoo Banshee (h3): + Integrated VGA support + 2,4,8MB frame buffer RAM + 90MHz clock frquency + clears @ 2 pixels/clock (RGB and depth simultaneously) + renders @ 1 pixel/clock + ultrafast clears @ 32 pixels/clock + + Voodoo 3 ("Avenger"/h4): + Integrated VGA support + 4,8,16MB frame buffer RAM + 143MHz clock frquency + clears @ 2 pixels/clock (RGB and depth simultaneously) + renders @ 1 pixel/clock + ultrafast clears @ 32 pixels/clock + + -------------------------- + + still to be implemented: + * trilinear textures + + things to verify: + * floating Z buffer + + +iterated RGBA = 12.12 [24 bits] +iterated Z = 20.12 [32 bits] +iterated W = 18.32 [48 bits] + +>mamepm blitz +Stall PCI for HWM: 1 +PCI FIFO Empty Entries LWM: D +LFB -> FIFO: 1 +Texture -> FIFO: 1 +Memory FIFO: 1 +Memory FIFO HWM: 2000 +Memory FIFO Write Burst HWM: 36 +Memory FIFO LWM for PCI: 5 +Memory FIFO row start: 120 +Memory FIFO row rollover: 3FF +Video dither subtract: 0 +DRAM banking: 1 +Triple buffer: 0 +Video buffer offset: 60 +DRAM banking: 1 + +>mamepm wg3dh +Stall PCI for HWM: 1 +PCI FIFO Empty Entries LWM: D +LFB -> FIFO: 1 +Texture -> FIFO: 1 +Memory FIFO: 1 +Memory FIFO HWM: 2000 +Memory FIFO Write Burst HWM: 36 +Memory FIFO LWM for PCI: 5 +Memory FIFO row start: C0 +Memory FIFO row rollover: 3FF +Video dither subtract: 0 +DRAM banking: 1 +Triple buffer: 0 +Video buffer offset: 40 +DRAM banking: 1 + + +As a point of reference, the 3D engine uses the following algorithm to calculate the linear memory address as a +function of the video buffer offset (fbiInit2 bits(19:11)), the number of 32x32 tiles in the X dimension (fbiInit1 +bits(7:4) and bit(24)), X, and Y: + + tilesInX[4:0] = {fbiInit1[24], fbiInit1[7:4], fbiInit6[30]} + rowBase = fbiInit2[19:11] + rowStart = ((Y>>5) * tilesInX) >> 1 + + if (!(tilesInX & 1)) + { + rowOffset = (X>>6); + row[9:0] = rowStart + rowOffset (for color buffer 0) + row[9:0] = rowBase + rowStart + rowOffset (for color buffer 1) + row[9:0] = (rowBase<<1) + rowStart + rowOffset (for depth/alpha buffer when double color buffering[fbiInit5[10:9]=0]) + row[9:0] = (rowBase<<1) + rowStart + rowOffset (for color buffer 2 when triple color buffering[fbiInit5[10:9]=1 or 2]) + row[9:0] = (rowBase<<1) + rowBase + rowStart + rowOffset (for depth/alpha buffer when triple color buffering[fbiInit5[10:9]=2]) + column[8:0] = ((Y % 32) <<4) + ((X % 32)>>1) + ramSelect[1] = ((X&0x20) ? 1 : 0) (for color buffers) + ramSelect[1] = ((X&0x20) ? 0 : 1) (for depth/alpha buffers) + } + else + { + rowOffset = (!(Y&0x20)) ? (X>>6) : ((X>31) ? (((X-32)>>6)+1) : 0) + row[9:0] = rowStart + rowOffset (for color buffer 0) + row[9:0] = rowBase + rowStart + rowOffset (for color buffer 1) + row[9:0] = (rowBase<<1) + rowStart + rowOffset (for depth/alpha buffer when double color buffering[fbiInit5[10:9]=0]) + row[9:0] = (rowBase<<1) + rowStart + rowOffset (for color buffer 2 when triple color buffering[fbiInit5[10:9]=1 or 2]) + row[9:0] = (rowBase<<1) + rowBase + rowStart + rowOffset (for depth/alpha buffer when triple color buffering[fbiInit5[10:9]=2]) + column[8:0] = ((Y % 32) <<4) + ((X % 32)>>1) + ramSelect[1] = (((X&0x20)^(Y&0x20)) ? 1 : 0) (for color buffers) + ramSelect[1] = (((X&0x20)^(Y&0x20)) ? 0 : 1) (for depth/alpha buffers) + } + ramSelect[0] = X % 2 + pixelMemoryAddress[21:0] = (row[9:0]<<12) + (column[8:0]<<3) + (ramSelect[1:0]<<1) + bankSelect = pixelMemoryAddress[21] + +**************************************************************************/ + +#ifndef EXPAND_RASTERIZERS +#define EXPAND_RASTERIZERS + +#include "emu.h" +#include "video/polylgcy.h" +#include "video/rgbutil.h" +#include "voodoo.h" +#include "vooddefs.h" + + +/************************************* + * + * Debugging + * + *************************************/ + +#define DEBUG_DEPTH (0) +#define DEBUG_LOD (0) + +#define LOG_VBLANK_SWAP (0) +#define LOG_FIFO (0) +#define LOG_FIFO_VERBOSE (0) +#define LOG_REGISTERS (0) +#define LOG_WAITS (0) +#define LOG_LFB (0) +#define LOG_TEXTURE_RAM (0) +#define LOG_RASTERIZERS (0) +#define LOG_CMDFIFO (0) +#define LOG_CMDFIFO_VERBOSE (0) +#define LOG_BANSHEE_2D (0) + +#define MODIFY_PIXEL(VV) + +// Need to turn off cycle eating when debugging MIPS drc +// otherwise timer interrupts won't match nodrc debug mode. +#define EAT_CYCLES (1) + + +/************************************* + * + * Statics + * + *************************************/ + +static const rectangle global_cliprect(-4096, 4095, -4096, 4095); + +/* fast dither lookup */ +static UINT8 dither4_lookup[256*16*2]; +static UINT8 dither2_lookup[256*16*2]; + +/* fast reciprocal+log2 lookup */ +UINT32 voodoo_reciplog[(2 << RECIPLOG_LOOKUP_BITS) + 2]; + + + +/************************************* + * + * Prototypes + * + *************************************/ + +static void init_fbi(voodoo_state *v, fbi_state *f, void *memory, int fbmem); +static void init_tmu_shared(tmu_shared_state *s); +static void init_tmu(voodoo_state *v, tmu_state *t, voodoo_reg *reg, void *memory, int tmem); +static void soft_reset(voodoo_state *v); +static void recompute_video_memory(voodoo_state *v); +static void check_stalled_cpu(voodoo_state *v, attotime current_time); +static void flush_fifos(voodoo_state *v, attotime current_time); +static TIMER_CALLBACK( stall_cpu_callback ); +static void stall_cpu(voodoo_state *v, int state, attotime current_time); +static TIMER_CALLBACK( vblank_callback ); +static INT32 register_w(voodoo_state *v, offs_t offset, UINT32 data); +static INT32 lfb_direct_w(voodoo_state *v, offs_t offset, UINT32 data, UINT32 mem_mask); +static INT32 lfb_w(voodoo_state *v, offs_t offset, UINT32 data, UINT32 mem_mask); +static INT32 texture_w(voodoo_state *v, offs_t offset, UINT32 data); +static INT32 banshee_2d_w(voodoo_state *v, offs_t offset, UINT32 data); + +/* command handlers */ +static INT32 fastfill(voodoo_state *v); +static INT32 swapbuffer(voodoo_state *v, UINT32 data); +static INT32 triangle(voodoo_state *v); +static INT32 begin_triangle(voodoo_state *v); +static INT32 draw_triangle(voodoo_state *v); + +/* triangle helpers */ +static INT32 setup_and_draw_triangle(voodoo_state *v); +static INT32 triangle_create_work_item(voodoo_state *v, UINT16 *drawbuf, int texcount); + +/* rasterizer management */ +static raster_info *add_rasterizer(voodoo_state *v, const raster_info *cinfo); +static raster_info *find_rasterizer(voodoo_state *v, int texcount); +static void dump_rasterizer_stats(voodoo_state *v); + +/* generic rasterizers */ +static void raster_fastfill(void *dest, INT32 scanline, const poly_extent *extent, const void *extradata, int threadid); +static void raster_generic_0tmu(void *dest, INT32 scanline, const poly_extent *extent, const void *extradata, int threadid); +static void raster_generic_1tmu(void *dest, INT32 scanline, const poly_extent *extent, const void *extradata, int threadid); +static void raster_generic_2tmu(void *dest, INT32 scanline, const poly_extent *extent, const void *extradata, int threadid); + + + +/************************************* + * + * Specific rasterizers + * + *************************************/ + +#define RASTERIZER_ENTRY(fbzcp, alpha, fog, fbz, tex0, tex1) \ + RASTERIZER(fbzcp##_##alpha##_##fog##_##fbz##_##tex0##_##tex1, (((tex0) == 0xffffffff) ? 0 : ((tex1) == 0xffffffff) ? 1 : 2), fbzcp, fbz, alpha, fog, tex0, tex1) + +#include "voodoo.c" + +#undef RASTERIZER_ENTRY + + + +/************************************* + * + * Rasterizer table + * + *************************************/ + +#define RASTERIZER_ENTRY(fbzcp, alpha, fog, fbz, tex0, tex1) \ + { NULL, raster_##fbzcp##_##alpha##_##fog##_##fbz##_##tex0##_##tex1, FALSE, 0, 0, 0, fbzcp, alpha, fog, fbz, tex0, tex1 }, + +static const raster_info predef_raster_table[] = +{ +#include "voodoo.c" + { 0 } +}; + +#undef RASTERIZER_ENTRY + + + +/*************************************************************************** + INLINE FUNCTIONS +***************************************************************************/ + +/*------------------------------------------------- + get_safe_token - makes sure that the passed + in device is, in fact, a voodoo device +-------------------------------------------------*/ + +INLINE voodoo_state *get_safe_token(device_t *device) +{ + assert(device != NULL); + assert((device->type() == VOODOO_1) || (device->type() == VOODOO_2) || (device->type() == VOODOO_BANSHEE) || (device->type() == VOODOO_3)); + + return (voodoo_state *)downcast(device)->token(); +} + + + +/************************************* + * + * Video update + * + *************************************/ + +int voodoo_update(device_t *device, bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + voodoo_state *v = get_safe_token(device); + int changed = v->fbi.video_changed; + int drawbuf = v->fbi.frontbuf; + int statskey; + int x, y; + + /* reset the video changed flag */ + v->fbi.video_changed = FALSE; + + /* if we are blank, just fill with black */ + if (v->type <= TYPE_VOODOO_2 && FBIINIT1_SOFTWARE_BLANK(v->reg[fbiInit1].u)) + { + bitmap.fill(0, cliprect); + return changed; + } + + /* if the CLUT is dirty, recompute the pens array */ + if (v->fbi.clut_dirty) + { + UINT8 rtable[32], gtable[64], btable[32]; + + /* Voodoo/Voodoo-2 have an internal 33-entry CLUT */ + if (v->type <= TYPE_VOODOO_2) + { + /* kludge: some of the Midway games write 0 to the last entry when they obviously mean FF */ + if ((v->fbi.clut[32] & 0xffffff) == 0 && (v->fbi.clut[31] & 0xffffff) != 0) + v->fbi.clut[32] = 0x20ffffff; + + /* compute the R/G/B pens first */ + for (x = 0; x < 32; x++) + { + /* treat X as a 5-bit value, scale up to 8 bits, and linear interpolate for red/blue */ + y = (x << 3) | (x >> 2); + rtable[x] = (v->fbi.clut[y >> 3].r() * (8 - (y & 7)) + v->fbi.clut[(y >> 3) + 1].r() * (y & 7)) >> 3; + btable[x] = (v->fbi.clut[y >> 3].b() * (8 - (y & 7)) + v->fbi.clut[(y >> 3) + 1].b() * (y & 7)) >> 3; + + /* treat X as a 6-bit value with LSB=0, scale up to 8 bits, and linear interpolate */ + y = (x * 2) + 0; + y = (y << 2) | (y >> 4); + gtable[x*2+0] = (v->fbi.clut[y >> 3].g() * (8 - (y & 7)) + v->fbi.clut[(y >> 3) + 1].g() * (y & 7)) >> 3; + + /* treat X as a 6-bit value with LSB=1, scale up to 8 bits, and linear interpolate */ + y = (x * 2) + 1; + y = (y << 2) | (y >> 4); + gtable[x*2+1] = (v->fbi.clut[y >> 3].g() * (8 - (y & 7)) + v->fbi.clut[(y >> 3) + 1].g() * (y & 7)) >> 3; + } + } + + /* Banshee and later have a 512-entry CLUT that can be bypassed */ + else + { + int which = (v->banshee.io[io_vidProcCfg] >> 13) & 1; + int bypass = (v->banshee.io[io_vidProcCfg] >> 11) & 1; + + /* compute R/G/B pens first */ + for (x = 0; x < 32; x++) + { + /* treat X as a 5-bit value, scale up to 8 bits */ + y = (x << 3) | (x >> 2); + rtable[x] = bypass ? y : v->fbi.clut[which * 256 + y].r(); + btable[x] = bypass ? y : v->fbi.clut[which * 256 + y].b(); + + /* treat X as a 6-bit value with LSB=0, scale up to 8 bits */ + y = (x * 2) + 0; + y = (y << 2) | (y >> 4); + gtable[x*2+0] = bypass ? y : v->fbi.clut[which * 256 + y].g(); + + /* treat X as a 6-bit value with LSB=1, scale up to 8 bits, and linear interpolate */ + y = (x * 2) + 1; + y = (y << 2) | (y >> 4); + gtable[x*2+1] = bypass ? y : v->fbi.clut[which * 256 + y].g(); + } + } + + /* now compute the actual pens array */ + for (x = 0; x < 65536; x++) + { + int r = rtable[(x >> 11) & 0x1f]; + int g = gtable[(x >> 5) & 0x3f]; + int b = btable[x & 0x1f]; + v->fbi.pen[x] = rgb_t(r, g, b); + } + + /* no longer dirty */ + v->fbi.clut_dirty = FALSE; + changed = TRUE; + } + + /* debugging! */ + if (device->machine().input().code_pressed(KEYCODE_L)) + drawbuf = v->fbi.backbuf; + + /* copy from the current front buffer */ + for (y = cliprect.min_y; y <= cliprect.max_y; y++) + if (y >= v->fbi.yoffs) + { + UINT16 *src = (UINT16 *)(v->fbi.ram + v->fbi.rgboffs[drawbuf]) + (y - v->fbi.yoffs) * v->fbi.rowpixels - v->fbi.xoffs; + UINT32 *dst = &bitmap.pix32(y); + for (x = cliprect.min_x; x <= cliprect.max_x; x++) + dst[x] = v->fbi.pen[src[x]]; + } + + /* update stats display */ + statskey = (device->machine().input().code_pressed(KEYCODE_BACKSLASH) != 0); + if (statskey && statskey != v->stats.lastkey) + v->stats.display = !v->stats.display; + v->stats.lastkey = statskey; + + /* display stats */ + if (v->stats.display) + popmessage(v->stats.buffer, 0, 0); + + /* update render override */ + v->stats.render_override = device->machine().input().code_pressed(KEYCODE_ENTER); + if (DEBUG_DEPTH && v->stats.render_override) + { + for (y = cliprect.min_y; y <= cliprect.max_y; y++) + { + UINT16 *src = (UINT16 *)(v->fbi.ram + v->fbi.auxoffs) + (y - v->fbi.yoffs) * v->fbi.rowpixels - v->fbi.xoffs; + UINT32 *dst = &bitmap.pix32(y); + for (x = cliprect.min_x; x <= cliprect.max_x; x++) + dst[x] = ((src[x] << 8) & 0xff0000) | ((src[x] >> 0) & 0xff00) | ((src[x] >> 8) & 0xff); + } + } + return changed; +} + + + +/************************************* + * + * Chip reset + * + *************************************/ + +int voodoo_get_type(device_t *device) +{ + voodoo_state *v = get_safe_token(device); + return v->type; +} + + +int voodoo_is_stalled(device_t *device) +{ + voodoo_state *v = get_safe_token(device); + return (v->pci.stall_state != NOT_STALLED); +} + + +void voodoo_set_init_enable(device_t *device, UINT32 newval) +{ + voodoo_state *v = get_safe_token(device); + v->pci.init_enable = newval; + if (LOG_REGISTERS) + logerror("VOODOO.%d.REG:initEnable write = %08X\n", v->index, newval); +} + + + +/************************************* + * + * Common initialization + * + *************************************/ + +static void init_fbi(voodoo_state *v, fbi_state *f, void *memory, int fbmem) +{ + int pen; + + /* allocate frame buffer RAM and set pointers */ + f->ram = (UINT8 *)memory; + f->mask = fbmem - 1; + f->rgboffs[0] = f->rgboffs[1] = f->rgboffs[2] = 0; + f->auxoffs = ~0; + + /* default to 0x0 */ + f->frontbuf = 0; + f->backbuf = 1; + f->width = 512; + f->height = 384; + + /* init the pens */ + f->clut_dirty = TRUE; + if (v->type <= TYPE_VOODOO_2) + { + for (pen = 0; pen < 32; pen++) + v->fbi.clut[pen] = rgb_t(pen, pal5bit(pen), pal5bit(pen), pal5bit(pen)); + v->fbi.clut[32] = rgb_t(32,0xff,0xff,0xff); + } + else + { + for (pen = 0; pen < 512; pen++) + v->fbi.clut[pen] = rgb_t(pen,pen,pen); + } + + /* allocate a VBLANK timer */ + f->vblank_timer = v->device->machine().scheduler().timer_alloc(FUNC(vblank_callback), v); + f->vblank = FALSE; + + /* initialize the memory FIFO */ + f->fifo.base = NULL; + f->fifo.size = f->fifo.in = f->fifo.out = 0; + + /* set the fog delta mask */ + f->fogdelta_mask = (v->type < TYPE_VOODOO_2) ? 0xff : 0xfc; +} + + +static void init_tmu_shared(tmu_shared_state *s) +{ + int val; + + /* build static 8-bit texel tables */ + for (val = 0; val < 256; val++) + { + int r, g, b, a; + + /* 8-bit RGB (3-3-2) */ + EXTRACT_332_TO_888(val, r, g, b); + s->rgb332[val] = rgb_t(0xff, r, g, b); + + /* 8-bit alpha */ + s->alpha8[val] = rgb_t(val, val, val, val); + + /* 8-bit intensity */ + s->int8[val] = rgb_t(0xff, val, val, val); + + /* 8-bit alpha, intensity */ + a = ((val >> 0) & 0xf0) | ((val >> 4) & 0x0f); + r = ((val << 4) & 0xf0) | ((val << 0) & 0x0f); + s->ai44[val] = rgb_t(a, r, r, r); + } + + /* build static 16-bit texel tables */ + for (val = 0; val < 65536; val++) + { + int r, g, b, a; + + /* table 10 = 16-bit RGB (5-6-5) */ + EXTRACT_565_TO_888(val, r, g, b); + s->rgb565[val] = rgb_t(0xff, r, g, b); + + /* table 11 = 16 ARGB (1-5-5-5) */ + EXTRACT_1555_TO_8888(val, a, r, g, b); + s->argb1555[val] = rgb_t(a, r, g, b); + + /* table 12 = 16-bit ARGB (4-4-4-4) */ + EXTRACT_4444_TO_8888(val, a, r, g, b); + s->argb4444[val] = rgb_t(a, r, g, b); + } +} + + +static void init_tmu(voodoo_state *v, tmu_state *t, voodoo_reg *reg, void *memory, int tmem) +{ + /* allocate texture RAM */ + t->ram = (UINT8 *)memory; + t->mask = tmem - 1; + t->reg = reg; + t->regdirty = TRUE; + t->bilinear_mask = (v->type >= TYPE_VOODOO_2) ? 0xff : 0xf0; + + /* mark the NCC tables dirty and configure their registers */ + t->ncc[0].dirty = t->ncc[1].dirty = TRUE; + t->ncc[0].reg = &t->reg[nccTable+0]; + t->ncc[1].reg = &t->reg[nccTable+12]; + + /* create pointers to all the tables */ + t->texel[0] = v->tmushare.rgb332; + t->texel[1] = t->ncc[0].texel; + t->texel[2] = v->tmushare.alpha8; + t->texel[3] = v->tmushare.int8; + t->texel[4] = v->tmushare.ai44; + t->texel[5] = t->palette; + t->texel[6] = (v->type >= TYPE_VOODOO_2) ? t->palettea : NULL; + t->texel[7] = NULL; + t->texel[8] = v->tmushare.rgb332; + t->texel[9] = t->ncc[0].texel; + t->texel[10] = v->tmushare.rgb565; + t->texel[11] = v->tmushare.argb1555; + t->texel[12] = v->tmushare.argb4444; + t->texel[13] = v->tmushare.int8; + t->texel[14] = t->palette; + t->texel[15] = NULL; + t->lookup = t->texel[0]; + + /* attach the palette to NCC table 0 */ + t->ncc[0].palette = t->palette; + if (v->type >= TYPE_VOODOO_2) + t->ncc[0].palettea = t->palettea; + + /* set up texture address calculations */ + if (v->type <= TYPE_VOODOO_2) + { + t->texaddr_mask = 0x0fffff; + t->texaddr_shift = 3; + } + else + { + t->texaddr_mask = 0xfffff0; + t->texaddr_shift = 0; + } +} + + +static void voodoo_postload(voodoo_state *v) +{ + int index, subindex; + + v->fbi.clut_dirty = TRUE; + for (index = 0; index < ARRAY_LENGTH(v->tmu); index++) + { + v->tmu[index].regdirty = TRUE; + for (subindex = 0; subindex < ARRAY_LENGTH(v->tmu[index].ncc); subindex++) + v->tmu[index].ncc[subindex].dirty = TRUE; + } + + /* recompute video memory to get the FBI FIFO base recomputed */ + if (v->type <= TYPE_VOODOO_2) + recompute_video_memory(v); +} + + +static void init_save_state(device_t *device) +{ + voodoo_state *v = get_safe_token(device); + int index, subindex; + + device->machine().save().register_postload(save_prepost_delegate(FUNC(voodoo_postload), v)); + + /* register states: core */ + device->save_item(NAME(v->extra_cycles)); + device->save_pointer(NAME(&v->reg[0].u), ARRAY_LENGTH(v->reg)); + device->save_item(NAME(v->alt_regmap)); + + /* register states: pci */ + device->save_item(NAME(v->pci.fifo.in)); + device->save_item(NAME(v->pci.fifo.out)); + device->save_item(NAME(v->pci.init_enable)); + device->save_item(NAME(v->pci.stall_state)); + device->save_item(NAME(v->pci.op_pending)); + device->save_item(NAME(v->pci.op_end_time)); + device->save_item(NAME(v->pci.fifo_mem)); + + /* register states: dac */ + device->save_item(NAME(v->dac.reg)); + device->save_item(NAME(v->dac.read_result)); + + /* register states: fbi */ + device->save_pointer(NAME(v->fbi.ram), v->fbi.mask + 1); + device->save_item(NAME(v->fbi.rgboffs)); + device->save_item(NAME(v->fbi.auxoffs)); + device->save_item(NAME(v->fbi.frontbuf)); + device->save_item(NAME(v->fbi.backbuf)); + device->save_item(NAME(v->fbi.swaps_pending)); + device->save_item(NAME(v->fbi.video_changed)); + device->save_item(NAME(v->fbi.yorigin)); + device->save_item(NAME(v->fbi.lfb_base)); + device->save_item(NAME(v->fbi.lfb_stride)); + device->save_item(NAME(v->fbi.width)); + device->save_item(NAME(v->fbi.height)); + device->save_item(NAME(v->fbi.xoffs)); + device->save_item(NAME(v->fbi.yoffs)); + device->save_item(NAME(v->fbi.vsyncscan)); + device->save_item(NAME(v->fbi.rowpixels)); + device->save_item(NAME(v->fbi.vblank)); + device->save_item(NAME(v->fbi.vblank_count)); + device->save_item(NAME(v->fbi.vblank_swap_pending)); + device->save_item(NAME(v->fbi.vblank_swap)); + device->save_item(NAME(v->fbi.vblank_dont_swap)); + device->save_item(NAME(v->fbi.cheating_allowed)); + device->save_item(NAME(v->fbi.sign)); + device->save_item(NAME(v->fbi.ax)); + device->save_item(NAME(v->fbi.ay)); + device->save_item(NAME(v->fbi.bx)); + device->save_item(NAME(v->fbi.by)); + device->save_item(NAME(v->fbi.cx)); + device->save_item(NAME(v->fbi.cy)); + device->save_item(NAME(v->fbi.startr)); + device->save_item(NAME(v->fbi.startg)); + device->save_item(NAME(v->fbi.startb)); + device->save_item(NAME(v->fbi.starta)); + device->save_item(NAME(v->fbi.startz)); + device->save_item(NAME(v->fbi.startw)); + device->save_item(NAME(v->fbi.drdx)); + device->save_item(NAME(v->fbi.dgdx)); + device->save_item(NAME(v->fbi.dbdx)); + device->save_item(NAME(v->fbi.dadx)); + device->save_item(NAME(v->fbi.dzdx)); + device->save_item(NAME(v->fbi.dwdx)); + device->save_item(NAME(v->fbi.drdy)); + device->save_item(NAME(v->fbi.dgdy)); + device->save_item(NAME(v->fbi.dbdy)); + device->save_item(NAME(v->fbi.dady)); + device->save_item(NAME(v->fbi.dzdy)); + device->save_item(NAME(v->fbi.dwdy)); + device->save_item(NAME(v->fbi.lfb_stats.pixels_in)); + device->save_item(NAME(v->fbi.lfb_stats.pixels_out)); + device->save_item(NAME(v->fbi.lfb_stats.chroma_fail)); + device->save_item(NAME(v->fbi.lfb_stats.zfunc_fail)); + device->save_item(NAME(v->fbi.lfb_stats.afunc_fail)); + device->save_item(NAME(v->fbi.lfb_stats.clip_fail)); + device->save_item(NAME(v->fbi.lfb_stats.stipple_count)); + device->save_item(NAME(v->fbi.sverts)); + for (index = 0; index < ARRAY_LENGTH(v->fbi.svert); index++) + { + device->save_item(NAME(v->fbi.svert[index].x), index); + device->save_item(NAME(v->fbi.svert[index].y), index); + device->save_item(NAME(v->fbi.svert[index].a), index); + device->save_item(NAME(v->fbi.svert[index].r), index); + device->save_item(NAME(v->fbi.svert[index].g), index); + device->save_item(NAME(v->fbi.svert[index].b), index); + device->save_item(NAME(v->fbi.svert[index].z), index); + device->save_item(NAME(v->fbi.svert[index].wb), index); + device->save_item(NAME(v->fbi.svert[index].w0), index); + device->save_item(NAME(v->fbi.svert[index].s0), index); + device->save_item(NAME(v->fbi.svert[index].t0), index); + device->save_item(NAME(v->fbi.svert[index].w1), index); + device->save_item(NAME(v->fbi.svert[index].s1), index); + device->save_item(NAME(v->fbi.svert[index].t1), index); + } + device->save_item(NAME(v->fbi.fifo.size)); + device->save_item(NAME(v->fbi.fifo.in)); + device->save_item(NAME(v->fbi.fifo.out)); + for (index = 0; index < ARRAY_LENGTH(v->fbi.cmdfifo); index++) + { + device->save_item(NAME(v->fbi.cmdfifo[index].enable), index); + device->save_item(NAME(v->fbi.cmdfifo[index].count_holes), index); + device->save_item(NAME(v->fbi.cmdfifo[index].base), index); + device->save_item(NAME(v->fbi.cmdfifo[index].end), index); + device->save_item(NAME(v->fbi.cmdfifo[index].rdptr), index); + device->save_item(NAME(v->fbi.cmdfifo[index].amin), index); + device->save_item(NAME(v->fbi.cmdfifo[index].amax), index); + device->save_item(NAME(v->fbi.cmdfifo[index].depth), index); + device->save_item(NAME(v->fbi.cmdfifo[index].holes), index); + } + device->save_item(NAME(v->fbi.fogblend)); + device->save_item(NAME(v->fbi.fogdelta)); + device->save_item(NAME(v->fbi.clut)); + + /* register states: tmu */ + for (index = 0; index < ARRAY_LENGTH(v->tmu); index++) + { + tmu_state *tmu = &v->tmu[index]; + if (tmu->ram == NULL) + continue; + if (tmu->ram != v->fbi.ram) + device->save_pointer(NAME(tmu->ram), tmu->mask + 1, index); + device->save_item(NAME(tmu->starts), index); + device->save_item(NAME(tmu->startt), index); + device->save_item(NAME(tmu->startw), index); + device->save_item(NAME(tmu->dsdx), index); + device->save_item(NAME(tmu->dtdx), index); + device->save_item(NAME(tmu->dwdx), index); + device->save_item(NAME(tmu->dsdy), index); + device->save_item(NAME(tmu->dtdy), index); + device->save_item(NAME(tmu->dwdy), index); + for (subindex = 0; subindex < ARRAY_LENGTH(tmu->ncc); subindex++) + { + device->save_item(NAME(tmu->ncc[subindex].ir), index * ARRAY_LENGTH(tmu->ncc) + subindex); + device->save_item(NAME(tmu->ncc[subindex].ig), index * ARRAY_LENGTH(tmu->ncc) + subindex); + device->save_item(NAME(tmu->ncc[subindex].ib), index * ARRAY_LENGTH(tmu->ncc) + subindex); + device->save_item(NAME(tmu->ncc[subindex].qr), index * ARRAY_LENGTH(tmu->ncc) + subindex); + device->save_item(NAME(tmu->ncc[subindex].qg), index * ARRAY_LENGTH(tmu->ncc) + subindex); + device->save_item(NAME(tmu->ncc[subindex].qb), index * ARRAY_LENGTH(tmu->ncc) + subindex); + device->save_item(NAME(tmu->ncc[subindex].y), index * ARRAY_LENGTH(tmu->ncc) + subindex); + } + } + + /* register states: banshee */ + if (v->type >= TYPE_VOODOO_BANSHEE) + { + device->save_item(NAME(v->banshee.io)); + device->save_item(NAME(v->banshee.agp)); + device->save_item(NAME(v->banshee.vga)); + device->save_item(NAME(v->banshee.crtc)); + device->save_item(NAME(v->banshee.seq)); + device->save_item(NAME(v->banshee.gc)); + device->save_item(NAME(v->banshee.att)); + device->save_item(NAME(v->banshee.attff)); + } +} + + + +/************************************* + * + * Statistics management + * + *************************************/ + +static void accumulate_statistics(voodoo_state *v, const stats_block *stats) +{ + /* apply internal voodoo statistics */ + v->reg[fbiPixelsIn].u += stats->pixels_in; + v->reg[fbiPixelsOut].u += stats->pixels_out; + v->reg[fbiChromaFail].u += stats->chroma_fail; + v->reg[fbiZfuncFail].u += stats->zfunc_fail; + v->reg[fbiAfuncFail].u += stats->afunc_fail; + + /* apply emulation statistics */ + v->stats.total_pixels_in += stats->pixels_in; + v->stats.total_pixels_out += stats->pixels_out; + v->stats.total_chroma_fail += stats->chroma_fail; + v->stats.total_zfunc_fail += stats->zfunc_fail; + v->stats.total_afunc_fail += stats->afunc_fail; + v->stats.total_clipped += stats->clip_fail; + v->stats.total_stippled += stats->stipple_count; +} + + +static void update_statistics(voodoo_state *v, int accumulate) +{ + int threadnum; + + /* accumulate/reset statistics from all units */ + for (threadnum = 0; threadnum < WORK_MAX_THREADS; threadnum++) + { + if (accumulate) + accumulate_statistics(v, &v->thread_stats[threadnum]); + memset(&v->thread_stats[threadnum], 0, sizeof(v->thread_stats[threadnum])); + } + + /* accumulate/reset statistics from the LFB */ + if (accumulate) + accumulate_statistics(v, &v->fbi.lfb_stats); + memset(&v->fbi.lfb_stats, 0, sizeof(v->fbi.lfb_stats)); +} + + + +/************************************* + * + * VBLANK management + * + *************************************/ + +static void swap_buffers(voodoo_state *v) +{ + int count; + + if (LOG_VBLANK_SWAP) logerror("--- swap_buffers @ %d\n", v->screen->vpos()); + + /* force a partial update */ + v->screen->update_partial(v->screen->vpos()); + v->fbi.video_changed = TRUE; + + /* keep a history of swap intervals */ + count = v->fbi.vblank_count; + if (count > 15) + count = 15; + v->reg[fbiSwapHistory].u = (v->reg[fbiSwapHistory].u << 4) | count; + + /* rotate the buffers */ + if (v->type <= TYPE_VOODOO_2) + { + if (v->type < TYPE_VOODOO_2 || !v->fbi.vblank_dont_swap) + { + if (v->fbi.rgboffs[2] == ~0) + { + v->fbi.frontbuf = 1 - v->fbi.frontbuf; + v->fbi.backbuf = 1 - v->fbi.frontbuf; + } + else + { + v->fbi.frontbuf = (v->fbi.frontbuf + 1) % 3; + v->fbi.backbuf = (v->fbi.frontbuf + 1) % 3; + } + } + } + else + v->fbi.rgboffs[0] = v->reg[leftOverlayBuf].u & v->fbi.mask & ~0x0f; + + /* decrement the pending count and reset our state */ + if (v->fbi.swaps_pending) + v->fbi.swaps_pending--; + v->fbi.vblank_count = 0; + v->fbi.vblank_swap_pending = FALSE; + + /* reset the last_op_time to now and start processing the next command */ + if (v->pci.op_pending) + { + v->pci.op_end_time = v->device->machine().time(); + flush_fifos(v, v->pci.op_end_time); + } + + /* we may be able to unstall now */ + if (v->pci.stall_state != NOT_STALLED) + check_stalled_cpu(v, v->device->machine().time()); + + /* periodically log rasterizer info */ + v->stats.swaps++; + if (LOG_RASTERIZERS && v->stats.swaps % 1000 == 0) + dump_rasterizer_stats(v); + + /* update the statistics (debug) */ + if (v->stats.display) + { + const rectangle &visible_area = v->screen->visible_area(); + int screen_area = visible_area.width() * visible_area.height(); + char *statsptr = v->stats.buffer; + int pixelcount; + int i; + + update_statistics(v, TRUE); + pixelcount = v->stats.total_pixels_out; + + statsptr += sprintf(statsptr, "Swap:%6d\n", v->stats.swaps); + statsptr += sprintf(statsptr, "Hist:%08X\n", v->reg[fbiSwapHistory].u); + statsptr += sprintf(statsptr, "Stal:%6d\n", v->stats.stalls); + statsptr += sprintf(statsptr, "Rend:%6d%%\n", pixelcount * 100 / screen_area); + statsptr += sprintf(statsptr, "Poly:%6d\n", v->stats.total_triangles); + statsptr += sprintf(statsptr, "PxIn:%6d\n", v->stats.total_pixels_in); + statsptr += sprintf(statsptr, "POut:%6d\n", v->stats.total_pixels_out); + statsptr += sprintf(statsptr, "Clip:%6d\n", v->stats.total_clipped); + statsptr += sprintf(statsptr, "Stip:%6d\n", v->stats.total_stippled); + statsptr += sprintf(statsptr, "Chro:%6d\n", v->stats.total_chroma_fail); + statsptr += sprintf(statsptr, "ZFun:%6d\n", v->stats.total_zfunc_fail); + statsptr += sprintf(statsptr, "AFun:%6d\n", v->stats.total_afunc_fail); + statsptr += sprintf(statsptr, "RegW:%6d\n", v->stats.reg_writes); + statsptr += sprintf(statsptr, "RegR:%6d\n", v->stats.reg_reads); + statsptr += sprintf(statsptr, "LFBW:%6d\n", v->stats.lfb_writes); + statsptr += sprintf(statsptr, "LFBR:%6d\n", v->stats.lfb_reads); + statsptr += sprintf(statsptr, "TexW:%6d\n", v->stats.tex_writes); + statsptr += sprintf(statsptr, "TexM:"); + for (i = 0; i < 16; i++) + if (v->stats.texture_mode[i]) + *statsptr++ = "0123456789ABCDEF"[i]; + *statsptr = 0; + } + + /* update statistics */ + v->stats.stalls = 0; + v->stats.total_triangles = 0; + v->stats.total_pixels_in = 0; + v->stats.total_pixels_out = 0; + v->stats.total_chroma_fail = 0; + v->stats.total_zfunc_fail = 0; + v->stats.total_afunc_fail = 0; + v->stats.total_clipped = 0; + v->stats.total_stippled = 0; + v->stats.reg_writes = 0; + v->stats.reg_reads = 0; + v->stats.lfb_writes = 0; + v->stats.lfb_reads = 0; + v->stats.tex_writes = 0; + memset(v->stats.texture_mode, 0, sizeof(v->stats.texture_mode)); +} + + +static void adjust_vblank_timer(voodoo_state *v) +{ + attotime vblank_period = v->screen->time_until_pos(v->fbi.vsyncscan); + + /* if zero, adjust to next frame, otherwise we may get stuck in an infinite loop */ + if (vblank_period == attotime::zero) + vblank_period = v->screen->frame_period(); + v->fbi.vblank_timer->adjust(vblank_period); +} + + +static TIMER_CALLBACK( vblank_off_callback ) +{ + voodoo_state *v = (voodoo_state *)ptr; + + if (LOG_VBLANK_SWAP) logerror("--- vblank end\n"); + + /* set internal state and call the client */ + v->fbi.vblank = FALSE; + + // TODO: Vblank IRQ enable is VOODOO3 only? + if (v->type >= TYPE_VOODOO_3) + { + if (v->reg[intrCtrl].u & 0x8) // call IRQ handler if VSYNC interrupt (falling) is enabled + { + v->reg[intrCtrl].u |= 0x200; // VSYNC int (falling) active + + if (!v->device->m_vblank.isnull()) + v->device->m_vblank(FALSE); + + } + } + else + { + if (!v->device->m_vblank.isnull()) + v->device->m_vblank(FALSE); + } + + /* go to the end of the next frame */ + adjust_vblank_timer(v); +} + + +static TIMER_CALLBACK( vblank_callback ) +{ + voodoo_state *v = (voodoo_state *)ptr; + + if (LOG_VBLANK_SWAP) logerror("--- vblank start\n"); + + /* flush the pipes */ + if (v->pci.op_pending) + { + if (LOG_VBLANK_SWAP) logerror("---- vblank flush begin\n"); + flush_fifos(v, machine.time()); + if (LOG_VBLANK_SWAP) logerror("---- vblank flush end\n"); + } + + /* increment the count */ + v->fbi.vblank_count++; + if (v->fbi.vblank_count > 250) + v->fbi.vblank_count = 250; + if (LOG_VBLANK_SWAP) logerror("---- vblank count = %d", v->fbi.vblank_count); + if (v->fbi.vblank_swap_pending) + if (LOG_VBLANK_SWAP) logerror(" (target=%d)", v->fbi.vblank_swap); + if (LOG_VBLANK_SWAP) logerror("\n"); + + /* if we're past the swap count, do the swap */ + if (v->fbi.vblank_swap_pending && v->fbi.vblank_count >= v->fbi.vblank_swap) + swap_buffers(v); + + /* set a timer for the next off state */ + machine.scheduler().timer_set(v->screen->time_until_pos(0), FUNC(vblank_off_callback), 0, v); + + /* set internal state and call the client */ + v->fbi.vblank = TRUE; + + // TODO: Vblank IRQ enable is VOODOO3 only? + if (v->type >= TYPE_VOODOO_3) + { + if (v->reg[intrCtrl].u & 0x4) // call IRQ handler if VSYNC interrupt (rising) is enabled + { + v->reg[intrCtrl].u |= 0x100; // VSYNC int (rising) active + + if (!v->device->m_vblank.isnull()) + v->device->m_vblank(TRUE); + } + } + else + { + if (!v->device->m_vblank.isnull()) + v->device->m_vblank(TRUE); + } +} + + + +/************************************* + * + * Chip reset + * + *************************************/ + +static void reset_counters(voodoo_state *v) +{ + update_statistics(v, FALSE); + v->reg[fbiPixelsIn].u = 0; + v->reg[fbiChromaFail].u = 0; + v->reg[fbiZfuncFail].u = 0; + v->reg[fbiAfuncFail].u = 0; + v->reg[fbiPixelsOut].u = 0; +} + + +static void soft_reset(voodoo_state *v) +{ + reset_counters(v); + v->reg[fbiTrianglesOut].u = 0; + fifo_reset(&v->fbi.fifo); + fifo_reset(&v->pci.fifo); +} + + + +/************************************* + * + * Recompute video memory layout + * + *************************************/ + +static void recompute_video_memory(voodoo_state *v) +{ + UINT32 buffer_pages = FBIINIT2_VIDEO_BUFFER_OFFSET(v->reg[fbiInit2].u); + UINT32 fifo_start_page = FBIINIT4_MEMORY_FIFO_START_ROW(v->reg[fbiInit4].u); + UINT32 fifo_last_page = FBIINIT4_MEMORY_FIFO_STOP_ROW(v->reg[fbiInit4].u); + UINT32 memory_config; + int buf; + + /* memory config is determined differently between V1 and V2 */ + memory_config = FBIINIT2_ENABLE_TRIPLE_BUF(v->reg[fbiInit2].u); + if (v->type == TYPE_VOODOO_2 && memory_config == 0) + memory_config = FBIINIT5_BUFFER_ALLOCATION(v->reg[fbiInit5].u); + + /* tiles are 64x16/32; x_tiles specifies how many half-tiles */ + v->fbi.tile_width = (v->type == TYPE_VOODOO_1) ? 64 : 32; + v->fbi.tile_height = (v->type == TYPE_VOODOO_1) ? 16 : 32; + v->fbi.x_tiles = FBIINIT1_X_VIDEO_TILES(v->reg[fbiInit1].u); + if (v->type == TYPE_VOODOO_2) + { + v->fbi.x_tiles = (v->fbi.x_tiles << 1) | + (FBIINIT1_X_VIDEO_TILES_BIT5(v->reg[fbiInit1].u) << 5) | + (FBIINIT6_X_VIDEO_TILES_BIT0(v->reg[fbiInit6].u)); + } + v->fbi.rowpixels = v->fbi.tile_width * v->fbi.x_tiles; + +// logerror("VOODOO.%d.VIDMEM: buffer_pages=%X fifo=%X-%X tiles=%X rowpix=%d\n", v->index, buffer_pages, fifo_start_page, fifo_last_page, v->fbi.x_tiles, v->fbi.rowpixels); + + /* first RGB buffer always starts at 0 */ + v->fbi.rgboffs[0] = 0; + + /* second RGB buffer starts immediately afterwards */ + v->fbi.rgboffs[1] = buffer_pages * 0x1000; + + /* remaining buffers are based on the config */ + switch (memory_config) + { + case 3: /* reserved */ + logerror("VOODOO.%d.ERROR:Unexpected memory configuration in recompute_video_memory!\n", v->index); + + case 0: /* 2 color buffers, 1 aux buffer */ + v->fbi.rgboffs[2] = ~0; + v->fbi.auxoffs = 2 * buffer_pages * 0x1000; + break; + + case 1: /* 3 color buffers, 0 aux buffers */ + v->fbi.rgboffs[2] = 2 * buffer_pages * 0x1000; + v->fbi.auxoffs = ~0; + break; + + case 2: /* 3 color buffers, 1 aux buffers */ + v->fbi.rgboffs[2] = 2 * buffer_pages * 0x1000; + v->fbi.auxoffs = 3 * buffer_pages * 0x1000; + break; + } + + /* clamp the RGB buffers to video memory */ + for (buf = 0; buf < 3; buf++) + if (v->fbi.rgboffs[buf] != ~0 && v->fbi.rgboffs[buf] > v->fbi.mask) + v->fbi.rgboffs[buf] = v->fbi.mask; + + /* clamp the aux buffer to video memory */ + if (v->fbi.auxoffs != ~0 && v->fbi.auxoffs > v->fbi.mask) + v->fbi.auxoffs = v->fbi.mask; + +/* osd_printf_debug("rgb[0] = %08X rgb[1] = %08X rgb[2] = %08X aux = %08X\n", + v->fbi.rgboffs[0], v->fbi.rgboffs[1], v->fbi.rgboffs[2], v->fbi.auxoffs);*/ + + /* compute the memory FIFO location and size */ + if (fifo_last_page > v->fbi.mask / 0x1000) + fifo_last_page = v->fbi.mask / 0x1000; + + /* is it valid and enabled? */ + if (fifo_start_page <= fifo_last_page && FBIINIT0_ENABLE_MEMORY_FIFO(v->reg[fbiInit0].u)) + { + v->fbi.fifo.base = (UINT32 *)(v->fbi.ram + fifo_start_page * 0x1000); + v->fbi.fifo.size = (fifo_last_page + 1 - fifo_start_page) * 0x1000 / 4; + if (v->fbi.fifo.size > 65536*2) + v->fbi.fifo.size = 65536*2; + } + + /* if not, disable the FIFO */ + else + { + v->fbi.fifo.base = NULL; + v->fbi.fifo.size = 0; + } + + /* reset the FIFO */ + fifo_reset(&v->fbi.fifo); + + /* reset our front/back buffers if they are out of range */ + if (v->fbi.rgboffs[2] == ~0) + { + if (v->fbi.frontbuf == 2) + v->fbi.frontbuf = 0; + if (v->fbi.backbuf == 2) + v->fbi.backbuf = 0; + } +} + + + +/************************************* + * + * NCC table management + * + *************************************/ + +static void ncc_table_write(ncc_table *n, offs_t regnum, UINT32 data) +{ + /* I/Q entries reference the plaette if the high bit is set */ + if (regnum >= 4 && (data & 0x80000000) && n->palette) + { + int index = ((data >> 23) & 0xfe) | (regnum & 1); + + /* set the ARGB for this palette index */ + n->palette[index] = 0xff000000 | data; + + /* if we have an ARGB palette as well, compute its value */ + if (n->palettea) + { + int a = ((data >> 16) & 0xfc) | ((data >> 22) & 0x03); + int r = ((data >> 10) & 0xfc) | ((data >> 16) & 0x03); + int g = ((data >> 4) & 0xfc) | ((data >> 10) & 0x03); + int b = ((data << 2) & 0xfc) | ((data >> 4) & 0x03); + n->palettea[index] = rgb_t(a, r, g, b); + } + + /* this doesn't dirty the table or go to the registers, so bail */ + return; + } + + /* if the register matches, don't update */ + if (data == n->reg[regnum].u) + return; + n->reg[regnum].u = data; + + /* first four entries are packed Y values */ + if (regnum < 4) + { + regnum *= 4; + n->y[regnum+0] = (data >> 0) & 0xff; + n->y[regnum+1] = (data >> 8) & 0xff; + n->y[regnum+2] = (data >> 16) & 0xff; + n->y[regnum+3] = (data >> 24) & 0xff; + } + + /* the second four entries are the I RGB values */ + else if (regnum < 8) + { + regnum &= 3; + n->ir[regnum] = (INT32)(data << 5) >> 23; + n->ig[regnum] = (INT32)(data << 14) >> 23; + n->ib[regnum] = (INT32)(data << 23) >> 23; + } + + /* the final four entries are the Q RGB values */ + else + { + regnum &= 3; + n->qr[regnum] = (INT32)(data << 5) >> 23; + n->qg[regnum] = (INT32)(data << 14) >> 23; + n->qb[regnum] = (INT32)(data << 23) >> 23; + } + + /* mark the table dirty */ + n->dirty = TRUE; +} + + +static void ncc_table_update(ncc_table *n) +{ + int r, g, b, i; + + /* generte all 256 possibilities */ + for (i = 0; i < 256; i++) + { + int vi = (i >> 2) & 0x03; + int vq = (i >> 0) & 0x03; + + /* start with the intensity */ + r = g = b = n->y[(i >> 4) & 0x0f]; + + /* add the coloring */ + r += n->ir[vi] + n->qr[vq]; + g += n->ig[vi] + n->qg[vq]; + b += n->ib[vi] + n->qb[vq]; + + /* clamp */ + CLAMP(r, 0, 255); + CLAMP(g, 0, 255); + CLAMP(b, 0, 255); + + /* fill in the table */ + n->texel[i] = rgb_t(0xff, r, g, b); + } + + /* no longer dirty */ + n->dirty = FALSE; +} + + + +/************************************* + * + * Faux DAC implementation + * + *************************************/ + +static void dacdata_w(dac_state *d, UINT8 regnum, UINT8 data) +{ + d->reg[regnum] = data; +} + + +static void dacdata_r(dac_state *d, UINT8 regnum) +{ + UINT8 result = 0xff; + + /* switch off the DAC register requested */ + switch (regnum) + { + case 5: + /* this is just to make startup happy */ + switch (d->reg[7]) + { + case 0x01: result = 0x55; break; + case 0x07: result = 0x71; break; + case 0x0b: result = 0x79; break; + } + break; + + default: + result = d->reg[regnum]; + break; + } + + /* remember the read result; it is fetched elsewhere */ + d->read_result = result; +} + + + +/************************************* + * + * Texuture parameter computation + * + *************************************/ + +static void recompute_texture_params(tmu_state *t) +{ + int bppscale; + UINT32 base; + int lod; + + /* extract LOD parameters */ + t->lodmin = TEXLOD_LODMIN(t->reg[tLOD].u) << 6; + t->lodmax = TEXLOD_LODMAX(t->reg[tLOD].u) << 6; + t->lodbias = (INT8)(TEXLOD_LODBIAS(t->reg[tLOD].u) << 2) << 4; + + /* determine which LODs are present */ + t->lodmask = 0x1ff; + if (TEXLOD_LOD_TSPLIT(t->reg[tLOD].u)) + { + if (!TEXLOD_LOD_ODD(t->reg[tLOD].u)) + t->lodmask = 0x155; + else + t->lodmask = 0x0aa; + } + + /* determine base texture width/height */ + t->wmask = t->hmask = 0xff; + if (TEXLOD_LOD_S_IS_WIDER(t->reg[tLOD].u)) + t->hmask >>= TEXLOD_LOD_ASPECT(t->reg[tLOD].u); + else + t->wmask >>= TEXLOD_LOD_ASPECT(t->reg[tLOD].u); + + /* determine the bpp of the texture */ + bppscale = TEXMODE_FORMAT(t->reg[textureMode].u) >> 3; + + /* start with the base of LOD 0 */ + if (t->texaddr_shift == 0 && (t->reg[texBaseAddr].u & 1)) + osd_printf_debug("Tiled texture\n"); + base = (t->reg[texBaseAddr].u & t->texaddr_mask) << t->texaddr_shift; + t->lodoffset[0] = base & t->mask; + + /* LODs 1-3 are different depending on whether we are in multitex mode */ + /* Several Voodoo 2 games leave the upper bits of TLOD == 0xff, meaning we think */ + /* they want multitex mode when they really don't -- disable for now */ + // Enable for Voodoo 3 or Viper breaks - VL. + if (TEXLOD_TMULTIBASEADDR(t->reg[tLOD].u)) + { + base = (t->reg[texBaseAddr_1].u & t->texaddr_mask) << t->texaddr_shift; + t->lodoffset[1] = base & t->mask; + base = (t->reg[texBaseAddr_2].u & t->texaddr_mask) << t->texaddr_shift; + t->lodoffset[2] = base & t->mask; + base = (t->reg[texBaseAddr_3_8].u & t->texaddr_mask) << t->texaddr_shift; + t->lodoffset[3] = base & t->mask; + } + else + { + if (t->lodmask & (1 << 0)) + base += (((t->wmask >> 0) + 1) * ((t->hmask >> 0) + 1)) << bppscale; + t->lodoffset[1] = base & t->mask; + if (t->lodmask & (1 << 1)) + base += (((t->wmask >> 1) + 1) * ((t->hmask >> 1) + 1)) << bppscale; + t->lodoffset[2] = base & t->mask; + if (t->lodmask & (1 << 2)) + base += (((t->wmask >> 2) + 1) * ((t->hmask >> 2) + 1)) << bppscale; + t->lodoffset[3] = base & t->mask; + } + + /* remaining LODs make sense */ + for (lod = 4; lod <= 8; lod++) + { + if (t->lodmask & (1 << (lod - 1))) + { + UINT32 size = ((t->wmask >> (lod - 1)) + 1) * ((t->hmask >> (lod - 1)) + 1); + if (size < 4) size = 4; + base += size << bppscale; + } + t->lodoffset[lod] = base & t->mask; + } + + /* set the NCC lookup appropriately */ + t->texel[1] = t->texel[9] = t->ncc[TEXMODE_NCC_TABLE_SELECT(t->reg[textureMode].u)].texel; + + /* pick the lookup table */ + t->lookup = t->texel[TEXMODE_FORMAT(t->reg[textureMode].u)]; + + /* compute the detail parameters */ + t->detailmax = TEXDETAIL_DETAIL_MAX(t->reg[tDetail].u); + t->detailbias = (INT8)(TEXDETAIL_DETAIL_BIAS(t->reg[tDetail].u) << 2) << 6; + t->detailscale = TEXDETAIL_DETAIL_SCALE(t->reg[tDetail].u); + + /* no longer dirty */ + t->regdirty = FALSE; + + /* check for separate RGBA filtering */ + if (TEXDETAIL_SEPARATE_RGBA_FILTER(t->reg[tDetail].u)) + fatalerror("Separate RGBA filters!\n"); +} + + +INLINE INT32 prepare_tmu(tmu_state *t) +{ + INT64 texdx, texdy; + INT32 lodbase; + + /* if the texture parameters are dirty, update them */ + if (t->regdirty) + { + recompute_texture_params(t); + + /* ensure that the NCC tables are up to date */ + if ((TEXMODE_FORMAT(t->reg[textureMode].u) & 7) == 1) + { + ncc_table *n = &t->ncc[TEXMODE_NCC_TABLE_SELECT(t->reg[textureMode].u)]; + t->texel[1] = t->texel[9] = n->texel; + if (n->dirty) + ncc_table_update(n); + } + } + + /* compute (ds^2 + dt^2) in both X and Y as 28.36 numbers */ + texdx = (INT64)(t->dsdx >> 14) * (INT64)(t->dsdx >> 14) + (INT64)(t->dtdx >> 14) * (INT64)(t->dtdx >> 14); + texdy = (INT64)(t->dsdy >> 14) * (INT64)(t->dsdy >> 14) + (INT64)(t->dtdy >> 14) * (INT64)(t->dtdy >> 14); + + /* pick whichever is larger and shift off some high bits -> 28.20 */ + if (texdx < texdy) + texdx = texdy; + texdx >>= 16; + + /* use our fast reciprocal/log on this value; it expects input as a */ + /* 16.32 number, and returns the log of the reciprocal, so we have to */ + /* adjust the result: negative to get the log of the original value */ + /* plus 12 to account for the extra exponent, and divided by 2 to */ + /* get the log of the square root of texdx */ + #if USE_FAST_RECIP == 1 + (void)fast_reciplog(texdx, &lodbase); + return (-lodbase + (12 << 8)) / 2; + #else + double tmpTex = texdx; + lodbase = new_log2(tmpTex); + return (lodbase + (12 << 8)) / 2; + #endif +} + + + +/************************************* + * + * Command FIFO depth computation + * + *************************************/ + +static int cmdfifo_compute_expected_depth(voodoo_state *v, cmdfifo_info *f) +{ + UINT32 *fifobase = (UINT32 *)v->fbi.ram; + UINT32 readptr = f->rdptr; + UINT32 command = fifobase[readptr / 4]; + int i, count = 0; + + /* low 3 bits specify the packet type */ + switch (command & 7) + { + /* + Packet type 0: 1 or 2 words + + Word Bits + 0 31:29 = reserved + 0 28:6 = Address [24:2] + 0 5:3 = Function (0 = NOP, 1 = JSR, 2 = RET, 3 = JMP LOCAL, 4 = JMP AGP) + 0 2:0 = Packet type (0) + 1 31:11 = reserved (JMP AGP only) + 1 10:0 = Address [35:25] + */ + case 0: + if (((command >> 3) & 7) == 4) + return 2; + return 1; + + /* + Packet type 1: 1 + N words + + Word Bits + 0 31:16 = Number of words + 0 15 = Increment? + 0 14:3 = Register base + 0 2:0 = Packet type (1) + 1 31:0 = Data word + */ + case 1: + return 1 + (command >> 16); + + /* + Packet type 2: 1 + N words + + Word Bits + 0 31:3 = 2D Register mask + 0 2:0 = Packet type (2) + 1 31:0 = Data word + */ + case 2: + for (i = 3; i <= 31; i++) + if (command & (1 << i)) count++; + return 1 + count; + + /* + Packet type 3: 1 + N words + + Word Bits + 0 31:29 = Number of dummy entries following the data + 0 28 = Packed color data? + 0 25 = Disable ping pong sign correction (0=normal, 1=disable) + 0 24 = Culling sign (0=positive, 1=negative) + 0 23 = Enable culling (0=disable, 1=enable) + 0 22 = Strip mode (0=strip, 1=fan) + 0 17 = Setup S1 and T1 + 0 16 = Setup W1 + 0 15 = Setup S0 and T0 + 0 14 = Setup W0 + 0 13 = Setup Wb + 0 12 = Setup Z + 0 11 = Setup Alpha + 0 10 = Setup RGB + 0 9:6 = Number of vertices + 0 5:3 = Command (0=Independent tris, 1=Start new strip, 2=Continue strip) + 0 2:0 = Packet type (3) + 1 31:0 = Data word + */ + case 3: + count = 2; /* X/Y */ + if (command & (1 << 28)) + { + if (command & (3 << 10)) count++; /* ARGB */ + } + else + { + if (command & (1 << 10)) count += 3; /* RGB */ + if (command & (1 << 11)) count++; /* A */ + } + if (command & (1 << 12)) count++; /* Z */ + if (command & (1 << 13)) count++; /* Wb */ + if (command & (1 << 14)) count++; /* W0 */ + if (command & (1 << 15)) count += 2; /* S0/T0 */ + if (command & (1 << 16)) count++; /* W1 */ + if (command & (1 << 17)) count += 2; /* S1/T1 */ + count *= (command >> 6) & 15; /* numverts */ + return 1 + count + (command >> 29); + + /* + Packet type 4: 1 + N words + + Word Bits + 0 31:29 = Number of dummy entries following the data + 0 28:15 = General register mask + 0 14:3 = Register base + 0 2:0 = Packet type (4) + 1 31:0 = Data word + */ + case 4: + for (i = 15; i <= 28; i++) + if (command & (1 << i)) count++; + return 1 + count + (command >> 29); + + /* + Packet type 5: 2 + N words + + Word Bits + 0 31:30 = Space (0,1=reserved, 2=LFB, 3=texture) + 0 29:26 = Byte disable W2 + 0 25:22 = Byte disable WN + 0 21:3 = Num words + 0 2:0 = Packet type (5) + 1 31:30 = Reserved + 1 29:0 = Base address [24:0] + 2 31:0 = Data word + */ + case 5: + return 2 + ((command >> 3) & 0x7ffff); + + default: + osd_printf_debug("UNKNOWN PACKET TYPE %d\n", command & 7); + return 1; + } +} + + + +/************************************* + * + * Command FIFO execution + * + *************************************/ + +static UINT32 cmdfifo_execute(voodoo_state *v, cmdfifo_info *f) +{ + UINT32 *fifobase = (UINT32 *)v->fbi.ram; + UINT32 readptr = f->rdptr; + UINT32 *src = &fifobase[readptr / 4]; + UINT32 command = *src++; + int count, inc, code, i; + setup_vertex svert = {0}; + offs_t target; + int cycles = 0; + + switch (command & 7) + { + /* + Packet type 0: 1 or 2 words + + Word Bits + 0 31:29 = reserved + 0 28:6 = Address [24:2] + 0 5:3 = Function (0 = NOP, 1 = JSR, 2 = RET, 3 = JMP LOCAL, 4 = JMP AGP) + 0 2:0 = Packet type (0) + 1 31:11 = reserved (JMP AGP only) + 1 10:0 = Address [35:25] + */ + case 0: + + /* extract parameters */ + target = (command >> 4) & 0x1fffffc; + + /* switch off of the specific command */ + switch ((command >> 3) & 7) + { + case 0: /* NOP */ + if (LOG_CMDFIFO) logerror(" NOP\n"); + break; + + case 1: /* JSR */ + if (LOG_CMDFIFO) logerror(" JSR $%06X\n", target); + osd_printf_debug("JSR in CMDFIFO!\n"); + src = &fifobase[target / 4]; + break; + + case 2: /* RET */ + if (LOG_CMDFIFO) logerror(" RET $%06X\n", target); + fatalerror("RET in CMDFIFO!\n"); + + case 3: /* JMP LOCAL FRAME BUFFER */ + if (LOG_CMDFIFO) logerror(" JMP LOCAL FRAMEBUF $%06X\n", target); + src = &fifobase[target / 4]; + break; + + case 4: /* JMP AGP */ + if (LOG_CMDFIFO) logerror(" JMP AGP $%06X\n", target); + fatalerror("JMP AGP in CMDFIFO!\n"); + src = &fifobase[target / 4]; + break; + + default: + osd_printf_debug("INVALID JUMP COMMAND!\n"); + fatalerror(" INVALID JUMP COMMAND\n"); + } + break; + + /* + Packet type 1: 1 + N words + + Word Bits + 0 31:16 = Number of words + 0 15 = Increment? + 0 14:3 = Register base + 0 2:0 = Packet type (1) + 1 31:0 = Data word + */ + case 1: + + /* extract parameters */ + count = command >> 16; + inc = (command >> 15) & 1; + target = (command >> 3) & 0xfff; + + if (LOG_CMDFIFO) logerror(" PACKET TYPE 1: count=%d inc=%d reg=%04X\n", count, inc, target); + + if (v->type >= TYPE_VOODOO_BANSHEE && (target & 0x800)) + { + // Banshee/Voodoo3 2D register writes + + /* loop over all registers and write them one at a time */ + for (i = 0; i < count; i++, target += inc) + { + cycles += banshee_2d_w(v, target & 0xff, *src); + //logerror(" 2d reg: %03x = %08X\n", target & 0x7ff, *src); + src++; + } + } + else + { + /* loop over all registers and write them one at a time */ + for (i = 0; i < count; i++, target += inc) + cycles += register_w(v, target, *src++); + } + break; + + /* + Packet type 2: 1 + N words + + Word Bits + 0 31:3 = 2D Register mask + 0 2:0 = Packet type (2) + 1 31:0 = Data word + */ + case 2: + if (LOG_CMDFIFO) logerror(" PACKET TYPE 2: mask=%X\n", (command >> 3) & 0x1ffffff); + + /* loop over all registers and write them one at a time */ + for (i = 3; i <= 31; i++) + if (command & (1 << i)) + cycles += register_w(v, banshee2D_clip0Min + (i - 3), *src++); + break; + + /* + Packet type 3: 1 + N words + + Word Bits + 0 31:29 = Number of dummy entries following the data + 0 28 = Packed color data? + 0 25 = Disable ping pong sign correction (0=normal, 1=disable) + 0 24 = Culling sign (0=positive, 1=negative) + 0 23 = Enable culling (0=disable, 1=enable) + 0 22 = Strip mode (0=strip, 1=fan) + 0 17 = Setup S1 and T1 + 0 16 = Setup W1 + 0 15 = Setup S0 and T0 + 0 14 = Setup W0 + 0 13 = Setup Wb + 0 12 = Setup Z + 0 11 = Setup Alpha + 0 10 = Setup RGB + 0 9:6 = Number of vertices + 0 5:3 = Command (0=Independent tris, 1=Start new strip, 2=Continue strip) + 0 2:0 = Packet type (3) + 1 31:0 = Data word + */ + case 3: + + /* extract parameters */ + count = (command >> 6) & 15; + code = (command >> 3) & 7; + + if (LOG_CMDFIFO) logerror(" PACKET TYPE 3: count=%d code=%d mask=%03X smode=%02X pc=%d\n", count, code, (command >> 10) & 0xfff, (command >> 22) & 0x3f, (command >> 28) & 1); + + /* copy relevant bits into the setup mode register */ + v->reg[sSetupMode].u = ((command >> 10) & 0xff) | ((command >> 6) & 0xf0000); + + /* loop over triangles */ + for (i = 0; i < count; i++) + { + /* always extract X/Y */ + svert.x = *(float *)src++; + svert.y = *(float *)src++; + + /* load ARGB values if packed */ + if (command & (1 << 28)) + { + if (command & (3 << 10)) + { + rgb_t argb = *src++; + if (command & (1 << 10)) + { + svert.r = argb.r(); + svert.g = argb.g(); + svert.b = argb.b(); + } + if (command & (1 << 11)) + svert.a = argb.a(); + } + } + + /* load ARGB values if not packed */ + else + { + if (command & (1 << 10)) + { + svert.r = *(float *)src++; + svert.g = *(float *)src++; + svert.b = *(float *)src++; + } + if (command & (1 << 11)) + svert.a = *(float *)src++; + } + + /* load Z and Wb values */ + if (command & (1 << 12)) + svert.z = *(float *)src++; + if (command & (1 << 13)) + svert.wb = *(float *)src++; + + /* load W0, S0, T0 values */ + if (command & (1 << 14)) + svert.w0 = *(float *)src++; + if (command & (1 << 15)) + { + svert.s0 = *(float *)src++; + svert.t0 = *(float *)src++; + } + + /* load W1, S1, T1 values */ + if (command & (1 << 16)) + svert.w1 = *(float *)src++; + if (command & (1 << 17)) + { + svert.s1 = *(float *)src++; + svert.t1 = *(float *)src++; + } + + /* if we're starting a new strip, or if this is the first of a set of verts */ + /* for a series of individual triangles, initialize all the verts */ + if ((code == 1 && i == 0) || (code == 0 && i % 3 == 0)) + { + v->fbi.sverts = 1; + v->fbi.svert[0] = v->fbi.svert[1] = v->fbi.svert[2] = svert; + } + + /* otherwise, add this to the list */ + else + { + /* for strip mode, shuffle vertex 1 down to 0 */ + if (!(command & (1 << 22))) + v->fbi.svert[0] = v->fbi.svert[1]; + + /* copy 2 down to 1 and add our new one regardless */ + v->fbi.svert[1] = v->fbi.svert[2]; + v->fbi.svert[2] = svert; + + /* if we have enough, draw */ + if (++v->fbi.sverts >= 3) + cycles += setup_and_draw_triangle(v); + } + } + + /* account for the extra dummy words */ + src += command >> 29; + break; + + /* + Packet type 4: 1 + N words + + Word Bits + 0 31:29 = Number of dummy entries following the data + 0 28:15 = General register mask + 0 14:3 = Register base + 0 2:0 = Packet type (4) + 1 31:0 = Data word + */ + case 4: + + /* extract parameters */ + target = (command >> 3) & 0xfff; + + if (LOG_CMDFIFO) logerror(" PACKET TYPE 4: mask=%X reg=%04X pad=%d\n", (command >> 15) & 0x3fff, target, command >> 29); + + if (v->type >= TYPE_VOODOO_BANSHEE && (target & 0x800)) + { + // Banshee/Voodoo3 2D register writes + + /* loop over all registers and write them one at a time */ + target &= 0xff; + for (i = 15; i <= 28; i++) + { + if (command & (1 << i)) + { + cycles += banshee_2d_w(v, target + (i - 15), *src); + //logerror(" 2d reg: %03x = %08X\n", target & 0x7ff, *src); + src++; + } + } + } + else + { + /* loop over all registers and write them one at a time */ + for (i = 15; i <= 28; i++) + if (command & (1 << i)) + cycles += register_w(v, target + (i - 15), *src++); + } + + /* account for the extra dummy words */ + src += command >> 29; + break; + + /* + Packet type 5: 2 + N words + + Word Bits + 0 31:30 = Space (0,1=reserved, 2=LFB, 3=texture) + 0 29:26 = Byte disable W2 + 0 25:22 = Byte disable WN + 0 21:3 = Num words + 0 2:0 = Packet type (5) + 1 31:30 = Reserved + 1 29:0 = Base address [24:0] + 2 31:0 = Data word + */ + case 5: + + /* extract parameters */ + count = (command >> 3) & 0x7ffff; + target = *src++ / 4; + + /* handle LFB writes */ + switch (command >> 30) + { + case 0: // Linear FB + { + if (LOG_CMDFIFO) logerror(" PACKET TYPE 5: FB count=%d dest=%08X bd2=%X bdN=%X\n", count, target, (command >> 26) & 15, (command >> 22) & 15); + + UINT32 addr = target * 4; + for (i=0; i < count; i++) + { + UINT32 data = *src++; + + v->fbi.ram[BYTE_XOR_LE(addr + 0)] = (UINT8)(data); + v->fbi.ram[BYTE_XOR_LE(addr + 1)] = (UINT8)(data >> 8); + v->fbi.ram[BYTE_XOR_LE(addr + 2)] = (UINT8)(data >> 16); + v->fbi.ram[BYTE_XOR_LE(addr + 3)] = (UINT8)(data >> 24); + + addr += 4; + } + break; + } + case 2: // 3D LFB + { + if (LOG_CMDFIFO) logerror(" PACKET TYPE 5: 3D LFB count=%d dest=%08X bd2=%X bdN=%X\n", count, target, (command >> 26) & 15, (command >> 22) & 15); + + /* loop over words */ + for (i = 0; i < count; i++) + cycles += lfb_w(v, target++, *src++, 0xffffffff); + + break; + } + + case 1: // Planar YUV + { + // TODO + + /* just update the pointers for now */ + for (i = 0; i < count; i++) + { + target++; + src++; + } + + break; + } + + case 3: // Texture Port + { + if (LOG_CMDFIFO) logerror(" PACKET TYPE 5: textureRAM count=%d dest=%08X bd2=%X bdN=%X\n", count, target, (command >> 26) & 15, (command >> 22) & 15); + + /* loop over words */ + for (i = 0; i < count; i++) + cycles += texture_w(v, target++, *src++); + + break; + } + } + + break; + + default: + fprintf(stderr, "PACKET TYPE %d\n", command & 7); + break; + } + + /* by default just update the read pointer past all the data we consumed */ + f->rdptr = 4 * (src - fifobase); + return cycles; +} + + + +/************************************* + * + * Handle execution if we're ready + * + *************************************/ + +static INT32 cmdfifo_execute_if_ready(voodoo_state *v, cmdfifo_info *f) +{ + int needed_depth; + int cycles; + + /* all CMDFIFO commands need at least one word */ + if (f->depth == 0) + return -1; + + /* see if we have enough for the current command */ + needed_depth = cmdfifo_compute_expected_depth(v, f); + if (f->depth < needed_depth) + return -1; + + /* execute */ + cycles = cmdfifo_execute(v, f); + f->depth -= needed_depth; + return cycles; +} + + + +/************************************* + * + * Handle writes to the CMD FIFO + * + *************************************/ + +static void cmdfifo_w(voodoo_state *v, cmdfifo_info *f, offs_t offset, UINT32 data) +{ + UINT32 addr = f->base + offset * 4; + UINT32 *fifobase = (UINT32 *)v->fbi.ram; + + if (LOG_CMDFIFO_VERBOSE) logerror("CMDFIFO_w(%04X) = %08X\n", offset, data); + + /* write the data */ + if (addr < f->end) + fifobase[addr / 4] = data; + + /* count holes? */ + if (f->count_holes) + { + /* in-order, no holes */ + if (f->holes == 0 && addr == f->amin + 4) + { + f->amin = f->amax = addr; + f->depth++; + } + + /* out-of-order, below the minimum */ + else if (addr < f->amin) + { + if (f->holes != 0) + logerror("Unexpected CMDFIFO: AMin=%08X AMax=%08X Holes=%d WroteTo:%08X\n", + f->amin, f->amax, f->holes, addr); + //f->amin = f->amax = addr; + f->holes += (addr - f->base) / 4; + f->amin = f->base; + f->amax = addr; + + f->depth++; + } + + /* out-of-order, but within the min-max range */ + else if (addr < f->amax) + { + f->holes--; + if (f->holes == 0) + { + f->depth += (f->amax - f->amin) / 4; + f->amin = f->amax; + } + } + + /* out-of-order, bumping max */ + else + { + f->holes += (addr - f->amax) / 4 - 1; + f->amax = addr; + } + } + + /* execute if we can */ + if (!v->pci.op_pending) + { + INT32 cycles = cmdfifo_execute_if_ready(v, f); + if (cycles > 0) + { + v->pci.op_pending = TRUE; + v->pci.op_end_time = v->device->machine().time() + attotime(0, (attoseconds_t)cycles * v->attoseconds_per_cycle); + + if (LOG_FIFO_VERBOSE) logerror("VOODOO.%d.FIFO:direct write start at %d.%08X%08X end at %d.%08X%08X\n", v->index, + v->device->machine().time().seconds(), (UINT32)(v->device->machine().time().attoseconds() >> 32), (UINT32)v->device->machine().time().attoseconds(), + v->pci.op_end_time.seconds(), (UINT32)(v->pci.op_end_time.attoseconds() >> 32), (UINT32)v->pci.op_end_time.attoseconds()); + } + } +} + + + +/************************************* + * + * Stall the active cpu until we are + * ready + * + *************************************/ + +static TIMER_CALLBACK( stall_cpu_callback ) +{ + check_stalled_cpu((voodoo_state *)ptr, machine.time()); +} + + +static void check_stalled_cpu(voodoo_state *v, attotime current_time) +{ + int resume = FALSE; + + /* flush anything we can */ + if (v->pci.op_pending) + flush_fifos(v, current_time); + + /* if we're just stalled until the LWM is passed, see if we're ok now */ + if (v->pci.stall_state == STALLED_UNTIL_FIFO_LWM) + { + /* if there's room in the memory FIFO now, we can proceed */ + if (FBIINIT0_ENABLE_MEMORY_FIFO(v->reg[fbiInit0].u)) + { + if (fifo_items(&v->fbi.fifo) < 2 * 32 * FBIINIT0_MEMORY_FIFO_HWM(v->reg[fbiInit0].u)) + resume = TRUE; + } + else if (fifo_space(&v->pci.fifo) > 2 * FBIINIT0_PCI_FIFO_LWM(v->reg[fbiInit0].u)) + resume = TRUE; + } + + /* if we're stalled until the FIFOs are empty, check now */ + else if (v->pci.stall_state == STALLED_UNTIL_FIFO_EMPTY) + { + if (FBIINIT0_ENABLE_MEMORY_FIFO(v->reg[fbiInit0].u)) + { + if (fifo_empty(&v->fbi.fifo) && fifo_empty(&v->pci.fifo)) + resume = TRUE; + } + else if (fifo_empty(&v->pci.fifo)) + resume = TRUE; + } + + /* resume if necessary */ + if (resume || !v->pci.op_pending) + { + if (LOG_FIFO) logerror("VOODOO.%d.FIFO:Stall condition cleared; resuming\n", v->index); + v->pci.stall_state = NOT_STALLED; + + /* either call the callback, or trigger the trigger */ + if (!v->device->m_stall.isnull()) + v->device->m_stall(FALSE); + else + v->device->machine().scheduler().trigger(v->trigger); + } + + /* if not, set a timer for the next one */ + else + { + v->pci.continue_timer->adjust(v->pci.op_end_time - current_time); + } +} + + +static void stall_cpu(voodoo_state *v, int state, attotime current_time) +{ + /* sanity check */ + if (!v->pci.op_pending) fatalerror("FIFOs not empty, no op pending!\n"); + + /* set the state and update statistics */ + v->pci.stall_state = state; + v->stats.stalls++; + + /* either call the callback, or spin the CPU */ + if (!v->device->m_stall.isnull()) + v->device->m_stall(TRUE); + else + v->cpu->execute().spin_until_trigger(v->trigger); + + /* set a timer to clear the stall */ + v->pci.continue_timer->adjust(v->pci.op_end_time - current_time); +} + + + +/************************************* + * + * Voodoo register writes + * + *************************************/ + +static INT32 register_w(voodoo_state *v, offs_t offset, UINT32 data) +{ + UINT32 origdata = data; + INT32 cycles = 0; + INT64 data64; + UINT8 regnum; + UINT8 chips; + + /* statistics */ + v->stats.reg_writes++; + + /* determine which chips we are addressing */ + chips = (offset >> 8) & 0xf; + if (chips == 0) + chips = 0xf; + chips &= v->chipmask; + + /* the first 64 registers can be aliased differently */ + if ((offset & 0x800c0) == 0x80000 && v->alt_regmap) + regnum = register_alias_map[offset & 0x3f]; + else + regnum = offset & 0xff; + + /* first make sure this register is readable */ + if (!(v->regaccess[regnum] & REGISTER_WRITE)) + { + logerror("VOODOO.%d.ERROR:Invalid attempt to write %s\n", v->index, v->regnames[regnum]); + return 0; + } + + /* switch off the register */ + switch (regnum) + { + /* Vertex data is 12.4 formatted fixed point */ + case fvertexAx: + data = float_to_int32(data, 4); + case vertexAx: + if (chips & 1) v->fbi.ax = (INT16)data; + break; + + case fvertexAy: + data = float_to_int32(data, 4); + case vertexAy: + if (chips & 1) v->fbi.ay = (INT16)data; + break; + + case fvertexBx: + data = float_to_int32(data, 4); + case vertexBx: + if (chips & 1) v->fbi.bx = (INT16)data; + break; + + case fvertexBy: + data = float_to_int32(data, 4); + case vertexBy: + if (chips & 1) v->fbi.by = (INT16)data; + break; + + case fvertexCx: + data = float_to_int32(data, 4); + case vertexCx: + if (chips & 1) v->fbi.cx = (INT16)data; + break; + + case fvertexCy: + data = float_to_int32(data, 4); + case vertexCy: + if (chips & 1) v->fbi.cy = (INT16)data; + break; + + /* RGB data is 12.12 formatted fixed point */ + case fstartR: + data = float_to_int32(data, 12); + case startR: + if (chips & 1) v->fbi.startr = (INT32)(data << 8) >> 8; + break; + + case fstartG: + data = float_to_int32(data, 12); + case startG: + if (chips & 1) v->fbi.startg = (INT32)(data << 8) >> 8; + break; + + case fstartB: + data = float_to_int32(data, 12); + case startB: + if (chips & 1) v->fbi.startb = (INT32)(data << 8) >> 8; + break; + + case fstartA: + data = float_to_int32(data, 12); + case startA: + if (chips & 1) v->fbi.starta = (INT32)(data << 8) >> 8; + break; + + case fdRdX: + data = float_to_int32(data, 12); + case dRdX: + if (chips & 1) v->fbi.drdx = (INT32)(data << 8) >> 8; + break; + + case fdGdX: + data = float_to_int32(data, 12); + case dGdX: + if (chips & 1) v->fbi.dgdx = (INT32)(data << 8) >> 8; + break; + + case fdBdX: + data = float_to_int32(data, 12); + case dBdX: + if (chips & 1) v->fbi.dbdx = (INT32)(data << 8) >> 8; + break; + + case fdAdX: + data = float_to_int32(data, 12); + case dAdX: + if (chips & 1) v->fbi.dadx = (INT32)(data << 8) >> 8; + break; + + case fdRdY: + data = float_to_int32(data, 12); + case dRdY: + if (chips & 1) v->fbi.drdy = (INT32)(data << 8) >> 8; + break; + + case fdGdY: + data = float_to_int32(data, 12); + case dGdY: + if (chips & 1) v->fbi.dgdy = (INT32)(data << 8) >> 8; + break; + + case fdBdY: + data = float_to_int32(data, 12); + case dBdY: + if (chips & 1) v->fbi.dbdy = (INT32)(data << 8) >> 8; + break; + + case fdAdY: + data = float_to_int32(data, 12); + case dAdY: + if (chips & 1) v->fbi.dady = (INT32)(data << 8) >> 8; + break; + + /* Z data is 20.12 formatted fixed point */ + case fstartZ: + data = float_to_int32(data, 12); + case startZ: + if (chips & 1) v->fbi.startz = (INT32)data; + break; + + case fdZdX: + data = float_to_int32(data, 12); + case dZdX: + if (chips & 1) v->fbi.dzdx = (INT32)data; + break; + + case fdZdY: + data = float_to_int32(data, 12); + case dZdY: + if (chips & 1) v->fbi.dzdy = (INT32)data; + break; + + /* S,T data is 14.18 formatted fixed point, converted to 16.32 internally */ + case fstartS: + data64 = float_to_int64(data, 32); + if (chips & 2) v->tmu[0].starts = data64; + if (chips & 4) v->tmu[1].starts = data64; + break; + case startS: + if (chips & 2) v->tmu[0].starts = (INT64)(INT32)data << 14; + if (chips & 4) v->tmu[1].starts = (INT64)(INT32)data << 14; + break; + + case fstartT: + data64 = float_to_int64(data, 32); + if (chips & 2) v->tmu[0].startt = data64; + if (chips & 4) v->tmu[1].startt = data64; + break; + case startT: + if (chips & 2) v->tmu[0].startt = (INT64)(INT32)data << 14; + if (chips & 4) v->tmu[1].startt = (INT64)(INT32)data << 14; + break; + + case fdSdX: + data64 = float_to_int64(data, 32); + if (chips & 2) v->tmu[0].dsdx = data64; + if (chips & 4) v->tmu[1].dsdx = data64; + break; + case dSdX: + if (chips & 2) v->tmu[0].dsdx = (INT64)(INT32)data << 14; + if (chips & 4) v->tmu[1].dsdx = (INT64)(INT32)data << 14; + break; + + case fdTdX: + data64 = float_to_int64(data, 32); + if (chips & 2) v->tmu[0].dtdx = data64; + if (chips & 4) v->tmu[1].dtdx = data64; + break; + case dTdX: + if (chips & 2) v->tmu[0].dtdx = (INT64)(INT32)data << 14; + if (chips & 4) v->tmu[1].dtdx = (INT64)(INT32)data << 14; + break; + + case fdSdY: + data64 = float_to_int64(data, 32); + if (chips & 2) v->tmu[0].dsdy = data64; + if (chips & 4) v->tmu[1].dsdy = data64; + break; + case dSdY: + if (chips & 2) v->tmu[0].dsdy = (INT64)(INT32)data << 14; + if (chips & 4) v->tmu[1].dsdy = (INT64)(INT32)data << 14; + break; + + case fdTdY: + data64 = float_to_int64(data, 32); + if (chips & 2) v->tmu[0].dtdy = data64; + if (chips & 4) v->tmu[1].dtdy = data64; + break; + case dTdY: + if (chips & 2) v->tmu[0].dtdy = (INT64)(INT32)data << 14; + if (chips & 4) v->tmu[1].dtdy = (INT64)(INT32)data << 14; + break; + + /* W data is 2.30 formatted fixed point, converted to 16.32 internally */ + case fstartW: + data64 = float_to_int64(data, 32); + if (chips & 1) v->fbi.startw = data64; + if (chips & 2) v->tmu[0].startw = data64; + if (chips & 4) v->tmu[1].startw = data64; + break; + case startW: + if (chips & 1) v->fbi.startw = (INT64)(INT32)data << 2; + if (chips & 2) v->tmu[0].startw = (INT64)(INT32)data << 2; + if (chips & 4) v->tmu[1].startw = (INT64)(INT32)data << 2; + break; + + case fdWdX: + data64 = float_to_int64(data, 32); + if (chips & 1) v->fbi.dwdx = data64; + if (chips & 2) v->tmu[0].dwdx = data64; + if (chips & 4) v->tmu[1].dwdx = data64; + break; + case dWdX: + if (chips & 1) v->fbi.dwdx = (INT64)(INT32)data << 2; + if (chips & 2) v->tmu[0].dwdx = (INT64)(INT32)data << 2; + if (chips & 4) v->tmu[1].dwdx = (INT64)(INT32)data << 2; + break; + + case fdWdY: + data64 = float_to_int64(data, 32); + if (chips & 1) v->fbi.dwdy = data64; + if (chips & 2) v->tmu[0].dwdy = data64; + if (chips & 4) v->tmu[1].dwdy = data64; + break; + case dWdY: + if (chips & 1) v->fbi.dwdy = (INT64)(INT32)data << 2; + if (chips & 2) v->tmu[0].dwdy = (INT64)(INT32)data << 2; + if (chips & 4) v->tmu[1].dwdy = (INT64)(INT32)data << 2; + break; + + /* setup bits */ + case sARGB: + if (chips & 1) + { + rgb_t rgbdata(data); + v->reg[sAlpha].f = rgbdata.a(); + v->reg[sRed].f = rgbdata.r(); + v->reg[sGreen].f = rgbdata.g(); + v->reg[sBlue].f = rgbdata.b(); + } + break; + + /* mask off invalid bits for different cards */ + case fbzColorPath: + poly_wait(v->poly, v->regnames[regnum]); + if (v->type < TYPE_VOODOO_2) + data &= 0x0fffffff; + if (chips & 1) v->reg[fbzColorPath].u = data; + break; + + case fbzMode: + poly_wait(v->poly, v->regnames[regnum]); + if (v->type < TYPE_VOODOO_2) + data &= 0x001fffff; + if (chips & 1) v->reg[fbzMode].u = data; + break; + + case fogMode: + poly_wait(v->poly, v->regnames[regnum]); + if (v->type < TYPE_VOODOO_2) + data &= 0x0000003f; + if (chips & 1) v->reg[fogMode].u = data; + break; + + /* triangle drawing */ + case triangleCMD: + v->fbi.cheating_allowed = (v->fbi.ax != 0 || v->fbi.ay != 0 || v->fbi.bx > 50 || v->fbi.by != 0 || v->fbi.cx != 0 || v->fbi.cy > 50); + v->fbi.sign = data; + cycles = triangle(v); + break; + + case ftriangleCMD: + v->fbi.cheating_allowed = TRUE; + v->fbi.sign = data; + cycles = triangle(v); + break; + + case sBeginTriCMD: + cycles = begin_triangle(v); + break; + + case sDrawTriCMD: + cycles = draw_triangle(v); + break; + + /* other commands */ + case nopCMD: + poly_wait(v->poly, v->regnames[regnum]); + if (data & 1) + reset_counters(v); + if (data & 2) + v->reg[fbiTrianglesOut].u = 0; + break; + + case fastfillCMD: + cycles = fastfill(v); + break; + + case swapbufferCMD: + poly_wait(v->poly, v->regnames[regnum]); + cycles = swapbuffer(v, data); + break; + + case userIntrCMD: + poly_wait(v->poly, v->regnames[regnum]); + //fatalerror("userIntrCMD\n"); + + v->reg[intrCtrl].u |= 0x1800; + v->reg[intrCtrl].u &= ~0x80000000; + + // TODO: rename vblank_client for less confusion? + if (!v->device->m_vblank.isnull()) + v->device->m_vblank(TRUE); + break; + + /* gamma table access -- Voodoo/Voodoo2 only */ + case clutData: + if (v->type <= TYPE_VOODOO_2 && (chips & 1)) + { + poly_wait(v->poly, v->regnames[regnum]); + if (!FBIINIT1_VIDEO_TIMING_RESET(v->reg[fbiInit1].u)) + { + int index = data >> 24; + if (index <= 32) + { + v->fbi.clut[index] = data; + v->fbi.clut_dirty = TRUE; + } + } + else + logerror("clutData ignored because video timing reset = 1\n"); + } + break; + + /* external DAC access -- Voodoo/Voodoo2 only */ + case dacData: + if (v->type <= TYPE_VOODOO_2 && (chips & 1)) + { + poly_wait(v->poly, v->regnames[regnum]); + if (!(data & 0x800)) + dacdata_w(&v->dac, (data >> 8) & 7, data & 0xff); + else + dacdata_r(&v->dac, (data >> 8) & 7); + } + break; + + /* vertical sync rate -- Voodoo/Voodoo2 only */ + case hSync: + case vSync: + case backPorch: + case videoDimensions: + if (v->type <= TYPE_VOODOO_2 && (chips & 1)) + { + poly_wait(v->poly, v->regnames[regnum]); + v->reg[regnum].u = data; + if (v->reg[hSync].u != 0 && v->reg[vSync].u != 0 && v->reg[videoDimensions].u != 0) + { + int hvis, vvis, htotal, vtotal, hbp, vbp; + attoseconds_t refresh = v->screen->frame_period().attoseconds(); + attoseconds_t stdperiod, medperiod, vgaperiod; + attoseconds_t stddiff, meddiff, vgadiff; + rectangle visarea; + + if (v->type == TYPE_VOODOO_2) + { + htotal = ((v->reg[hSync].u >> 16) & 0x7ff) + 1 + (v->reg[hSync].u & 0x1ff) + 1; + vtotal = ((v->reg[vSync].u >> 16) & 0x1fff) + (v->reg[vSync].u & 0x1fff); + hvis = v->reg[videoDimensions].u & 0x7ff; + vvis = (v->reg[videoDimensions].u >> 16) & 0x7ff; + hbp = (v->reg[backPorch].u & 0x1ff) + 2; + vbp = (v->reg[backPorch].u >> 16) & 0x1ff; + } + else + { + htotal = ((v->reg[hSync].u >> 16) & 0x3ff) + 1 + (v->reg[hSync].u & 0xff) + 1; + vtotal = ((v->reg[vSync].u >> 16) & 0xfff) + (v->reg[vSync].u & 0xfff); + hvis = v->reg[videoDimensions].u & 0x3ff; + vvis = (v->reg[videoDimensions].u >> 16) & 0x3ff; + hbp = (v->reg[backPorch].u & 0xff) + 2; + vbp = (v->reg[backPorch].u >> 16) & 0xff; + } + + /* create a new visarea */ + visarea.set(hbp, hbp + hvis - 1, vbp, vbp + vvis - 1); + + /* keep within bounds */ + visarea.max_x = MIN(visarea.max_x, htotal - 1); + visarea.max_y = MIN(visarea.max_y, vtotal - 1); + + /* compute the new period for standard res, medium res, and VGA res */ + stdperiod = HZ_TO_ATTOSECONDS(15750) * vtotal; + medperiod = HZ_TO_ATTOSECONDS(25000) * vtotal; + vgaperiod = HZ_TO_ATTOSECONDS(31500) * vtotal; + + /* compute a diff against the current refresh period */ + stddiff = stdperiod - refresh; + if (stddiff < 0) stddiff = -stddiff; + meddiff = medperiod - refresh; + if (meddiff < 0) meddiff = -meddiff; + vgadiff = vgaperiod - refresh; + if (vgadiff < 0) vgadiff = -vgadiff; + + osd_printf_debug("hSync=%08X vSync=%08X backPorch=%08X videoDimensions=%08X\n", + v->reg[hSync].u, v->reg[vSync].u, v->reg[backPorch].u, v->reg[videoDimensions].u); + osd_printf_debug("Horiz: %d-%d (%d total) Vert: %d-%d (%d total) -- ", visarea.min_x, visarea.max_x, htotal, visarea.min_y, visarea.max_y, vtotal); + + /* configure the screen based on which one matches the closest */ + if (stddiff < meddiff && stddiff < vgadiff) + { + v->screen->configure(htotal, vtotal, visarea, stdperiod); + osd_printf_debug("Standard resolution, %f Hz\n", ATTOSECONDS_TO_HZ(stdperiod)); + } + else if (meddiff < vgadiff) + { + v->screen->configure(htotal, vtotal, visarea, medperiod); + osd_printf_debug("Medium resolution, %f Hz\n", ATTOSECONDS_TO_HZ(medperiod)); + } + else + { + v->screen->configure(htotal, vtotal, visarea, vgaperiod); + osd_printf_debug("VGA resolution, %f Hz\n", ATTOSECONDS_TO_HZ(vgaperiod)); + } + + /* configure the new framebuffer info */ + v->fbi.width = hvis; + v->fbi.height = vvis; + v->fbi.xoffs = hbp; + v->fbi.yoffs = vbp; + v->fbi.vsyncscan = (v->reg[vSync].u >> 16) & 0xfff; + + /* recompute the time of VBLANK */ + adjust_vblank_timer(v); + + /* if changing dimensions, update video memory layout */ + if (regnum == videoDimensions) + recompute_video_memory(v); + } + } + break; + + /* fbiInit0 can only be written if initEnable says we can -- Voodoo/Voodoo2 only */ + case fbiInit0: + poly_wait(v->poly, v->regnames[regnum]); + if (v->type <= TYPE_VOODOO_2 && (chips & 1) && INITEN_ENABLE_HW_INIT(v->pci.init_enable)) + { + v->reg[fbiInit0].u = data; + if (FBIINIT0_GRAPHICS_RESET(data)) + soft_reset(v); + if (FBIINIT0_FIFO_RESET(data)) + fifo_reset(&v->pci.fifo); + recompute_video_memory(v); + } + break; + + /* fbiInit5-7 are Voodoo 2-only; ignore them on anything else */ + case fbiInit5: + case fbiInit6: + if (v->type < TYPE_VOODOO_2) + break; + /* else fall through... */ + + /* fbiInitX can only be written if initEnable says we can -- Voodoo/Voodoo2 only */ + /* most of these affect memory layout, so always recompute that when done */ + case fbiInit1: + case fbiInit2: + case fbiInit4: + poly_wait(v->poly, v->regnames[regnum]); + if (v->type <= TYPE_VOODOO_2 && (chips & 1) && INITEN_ENABLE_HW_INIT(v->pci.init_enable)) + { + v->reg[regnum].u = data; + recompute_video_memory(v); + v->fbi.video_changed = TRUE; + } + break; + + case fbiInit3: + poly_wait(v->poly, v->regnames[regnum]); + if (v->type <= TYPE_VOODOO_2 && (chips & 1) && INITEN_ENABLE_HW_INIT(v->pci.init_enable)) + { + v->reg[regnum].u = data; + v->alt_regmap = FBIINIT3_TRI_REGISTER_REMAP(data); + v->fbi.yorigin = FBIINIT3_YORIGIN_SUBTRACT(v->reg[fbiInit3].u); + recompute_video_memory(v); + } + break; + + case fbiInit7: +/* case swapPending: -- Banshee */ + if (v->type == TYPE_VOODOO_2 && (chips & 1) && INITEN_ENABLE_HW_INIT(v->pci.init_enable)) + { + poly_wait(v->poly, v->regnames[regnum]); + v->reg[regnum].u = data; + v->fbi.cmdfifo[0].enable = FBIINIT7_CMDFIFO_ENABLE(data); + v->fbi.cmdfifo[0].count_holes = !FBIINIT7_DISABLE_CMDFIFO_HOLES(data); + } + else if (v->type >= TYPE_VOODOO_BANSHEE) + v->fbi.swaps_pending++; + break; + + /* cmdFifo -- Voodoo2 only */ + case cmdFifoBaseAddr: + if (v->type == TYPE_VOODOO_2 && (chips & 1)) + { + poly_wait(v->poly, v->regnames[regnum]); + v->reg[regnum].u = data; + v->fbi.cmdfifo[0].base = (data & 0x3ff) << 12; + v->fbi.cmdfifo[0].end = (((data >> 16) & 0x3ff) + 1) << 12; + } + break; + + case cmdFifoBump: + if (v->type == TYPE_VOODOO_2 && (chips & 1)) + fatalerror("cmdFifoBump\n"); + break; + + case cmdFifoRdPtr: + if (v->type == TYPE_VOODOO_2 && (chips & 1)) + v->fbi.cmdfifo[0].rdptr = data; + break; + + case cmdFifoAMin: +/* case colBufferAddr: -- Banshee */ + if (v->type == TYPE_VOODOO_2 && (chips & 1)) + v->fbi.cmdfifo[0].amin = data; + else if (v->type >= TYPE_VOODOO_BANSHEE && (chips & 1)) + v->fbi.rgboffs[1] = data & v->fbi.mask & ~0x0f; + break; + + case cmdFifoAMax: +/* case colBufferStride: -- Banshee */ + if (v->type == TYPE_VOODOO_2 && (chips & 1)) + v->fbi.cmdfifo[0].amax = data; + else if (v->type >= TYPE_VOODOO_BANSHEE && (chips & 1)) + { + if (data & 0x8000) + v->fbi.rowpixels = (data & 0x7f) << 6; + else + v->fbi.rowpixels = (data & 0x3fff) >> 1; + } + break; + + case cmdFifoDepth: +/* case auxBufferAddr: -- Banshee */ + if (v->type == TYPE_VOODOO_2 && (chips & 1)) + v->fbi.cmdfifo[0].depth = data; + else if (v->type >= TYPE_VOODOO_BANSHEE && (chips & 1)) + v->fbi.auxoffs = data & v->fbi.mask & ~0x0f; + break; + + case cmdFifoHoles: +/* case auxBufferStride: -- Banshee */ + if (v->type == TYPE_VOODOO_2 && (chips & 1)) + v->fbi.cmdfifo[0].holes = data; + else if (v->type >= TYPE_VOODOO_BANSHEE && (chips & 1)) + { + int rowpixels; + + if (data & 0x8000) + rowpixels = (data & 0x7f) << 6; + else + rowpixels = (data & 0x3fff) >> 1; + if (v->fbi.rowpixels != rowpixels) + fatalerror("aux buffer stride differs from color buffer stride\n"); + } + break; + + /* nccTable entries are processed and expanded immediately */ + case nccTable+0: + case nccTable+1: + case nccTable+2: + case nccTable+3: + case nccTable+4: + case nccTable+5: + case nccTable+6: + case nccTable+7: + case nccTable+8: + case nccTable+9: + case nccTable+10: + case nccTable+11: + poly_wait(v->poly, v->regnames[regnum]); + if (chips & 2) ncc_table_write(&v->tmu[0].ncc[0], regnum - nccTable, data); + if (chips & 4) ncc_table_write(&v->tmu[1].ncc[0], regnum - nccTable, data); + break; + + case nccTable+12: + case nccTable+13: + case nccTable+14: + case nccTable+15: + case nccTable+16: + case nccTable+17: + case nccTable+18: + case nccTable+19: + case nccTable+20: + case nccTable+21: + case nccTable+22: + case nccTable+23: + poly_wait(v->poly, v->regnames[regnum]); + if (chips & 2) ncc_table_write(&v->tmu[0].ncc[1], regnum - (nccTable+12), data); + if (chips & 4) ncc_table_write(&v->tmu[1].ncc[1], regnum - (nccTable+12), data); + break; + + /* fogTable entries are processed and expanded immediately */ + case fogTable+0: + case fogTable+1: + case fogTable+2: + case fogTable+3: + case fogTable+4: + case fogTable+5: + case fogTable+6: + case fogTable+7: + case fogTable+8: + case fogTable+9: + case fogTable+10: + case fogTable+11: + case fogTable+12: + case fogTable+13: + case fogTable+14: + case fogTable+15: + case fogTable+16: + case fogTable+17: + case fogTable+18: + case fogTable+19: + case fogTable+20: + case fogTable+21: + case fogTable+22: + case fogTable+23: + case fogTable+24: + case fogTable+25: + case fogTable+26: + case fogTable+27: + case fogTable+28: + case fogTable+29: + case fogTable+30: + case fogTable+31: + poly_wait(v->poly, v->regnames[regnum]); + if (chips & 1) + { + int base = 2 * (regnum - fogTable); + v->fbi.fogdelta[base + 0] = (data >> 0) & 0xff; + v->fbi.fogblend[base + 0] = (data >> 8) & 0xff; + v->fbi.fogdelta[base + 1] = (data >> 16) & 0xff; + v->fbi.fogblend[base + 1] = (data >> 24) & 0xff; + } + break; + + /* texture modifications cause us to recompute everything */ + case textureMode: + case tLOD: + case tDetail: + case texBaseAddr: + case texBaseAddr_1: + case texBaseAddr_2: + case texBaseAddr_3_8: + poly_wait(v->poly, v->regnames[regnum]); + if (chips & 2) + { + v->tmu[0].reg[regnum].u = data; + v->tmu[0].regdirty = TRUE; + } + if (chips & 4) + { + v->tmu[1].reg[regnum].u = data; + v->tmu[1].regdirty = TRUE; + } + break; + + case trexInit1: + /* send tmu config data to the frame buffer */ + v->send_config = (TREXINIT_SEND_TMU_CONFIG(data) > 0); + goto default_case; + + /* these registers are referenced in the renderer; we must wait for pending work before changing */ + case chromaRange: + case chromaKey: + case alphaMode: + case fogColor: + case stipple: + case zaColor: + case color1: + case color0: + case clipLowYHighY: + case clipLeftRight: + poly_wait(v->poly, v->regnames[regnum]); + /* fall through to default implementation */ + + /* by default, just feed the data to the chips */ + default: +default_case: + if (chips & 1) v->reg[0x000 + regnum].u = data; + if (chips & 2) v->reg[0x100 + regnum].u = data; + if (chips & 4) v->reg[0x200 + regnum].u = data; + if (chips & 8) v->reg[0x300 + regnum].u = data; + break; + } + + if (LOG_REGISTERS) + { + if (regnum < fvertexAx || regnum > fdWdY) + logerror("VOODOO.%d.REG:%s(%d) write = %08X\n", v->index, (regnum < 0x384/4) ? v->regnames[regnum] : "oob", chips, origdata); + else + logerror("VOODOO.%d.REG:%s(%d) write = %f\n", v->index, (regnum < 0x384/4) ? v->regnames[regnum] : "oob", chips, (double) u2f(origdata)); + } + + return cycles; +} + + + +/************************************* + * + * Voodoo LFB writes + * + *************************************/ +static INT32 lfb_direct_w(voodoo_state *v, offs_t offset, UINT32 data, UINT32 mem_mask) +{ + UINT16 *dest; + UINT32 destmax; + int x, y; + UINT32 bufoffs; + + /* statistics */ + v->stats.lfb_writes++; + + /* byte swizzling */ + if (LFBMODE_BYTE_SWIZZLE_WRITES(v->reg[lfbMode].u)) + { + data = FLIPENDIAN_INT32(data); + mem_mask = FLIPENDIAN_INT32(mem_mask); + } + + /* word swapping */ + if (LFBMODE_WORD_SWAP_WRITES(v->reg[lfbMode].u)) + { + data = (data << 16) | (data >> 16); + mem_mask = (mem_mask << 16) | (mem_mask >> 16); + } + + // TODO: This direct write is not verified. + // For direct lfb access just write the data + /* compute X,Y */ + offset <<= 1; + x = offset & ((1 << v->fbi.lfb_stride) - 1); + y = (offset >> v->fbi.lfb_stride); + dest = (UINT16 *)(v->fbi.ram + v->fbi.lfb_base*4); + destmax = (v->fbi.mask + 1 - v->fbi.lfb_base*4) / 2; + bufoffs = y * v->fbi.rowpixels + x; + if (bufoffs >= destmax) { + logerror("lfb_direct_w: Buffer offset out of bounds x=%i y=%i offset=%08X bufoffs=%08X data=%08X\n", x, y, offset, (UINT32) bufoffs, data); + return 0; + } + if (ACCESSING_BITS_0_15) + dest[bufoffs + 0] = data&0xffff; + if (ACCESSING_BITS_16_31) + dest[bufoffs + 1] = data>>16; + if (LOG_LFB) logerror("VOODOO.%d.LFB:write direct (%d,%d) = %08X & %08X\n", v->index, x, y, data, mem_mask); + return 0; +} + +static INT32 lfb_w(voodoo_state *v, offs_t offset, UINT32 data, UINT32 mem_mask) +{ + UINT16 *dest, *depth; + UINT32 destmax, depthmax; + int sr[2], sg[2], sb[2], sa[2], sw[2]; + int x, y, scry, mask; + int pix, destbuf; + + /* statistics */ + v->stats.lfb_writes++; + + /* byte swizzling */ + if (LFBMODE_BYTE_SWIZZLE_WRITES(v->reg[lfbMode].u)) + { + data = FLIPENDIAN_INT32(data); + mem_mask = FLIPENDIAN_INT32(mem_mask); + } + + /* word swapping */ + if (LFBMODE_WORD_SWAP_WRITES(v->reg[lfbMode].u)) + { + data = (data << 16) | (data >> 16); + mem_mask = (mem_mask << 16) | (mem_mask >> 16); + } + + /* extract default depth and alpha values */ + sw[0] = sw[1] = v->reg[zaColor].u & 0xffff; + sa[0] = sa[1] = v->reg[zaColor].u >> 24; + + /* first extract A,R,G,B from the data */ + switch (LFBMODE_WRITE_FORMAT(v->reg[lfbMode].u) + 16 * LFBMODE_RGBA_LANES(v->reg[lfbMode].u)) + { + case 16*0 + 0: /* ARGB, 16-bit RGB 5-6-5 */ + case 16*2 + 0: /* RGBA, 16-bit RGB 5-6-5 */ + EXTRACT_565_TO_888(data, sr[0], sg[0], sb[0]); + EXTRACT_565_TO_888(data >> 16, sr[1], sg[1], sb[1]); + mask = LFB_RGB_PRESENT | (LFB_RGB_PRESENT << 4); + offset <<= 1; + break; + case 16*1 + 0: /* ABGR, 16-bit RGB 5-6-5 */ + case 16*3 + 0: /* BGRA, 16-bit RGB 5-6-5 */ + EXTRACT_565_TO_888(data, sb[0], sg[0], sr[0]); + EXTRACT_565_TO_888(data >> 16, sb[1], sg[1], sr[1]); + mask = LFB_RGB_PRESENT | (LFB_RGB_PRESENT << 4); + offset <<= 1; + break; + + case 16*0 + 1: /* ARGB, 16-bit RGB x-5-5-5 */ + EXTRACT_x555_TO_888(data, sr[0], sg[0], sb[0]); + EXTRACT_x555_TO_888(data >> 16, sr[1], sg[1], sb[1]); + mask = LFB_RGB_PRESENT | (LFB_RGB_PRESENT << 4); + offset <<= 1; + break; + case 16*1 + 1: /* ABGR, 16-bit RGB x-5-5-5 */ + EXTRACT_x555_TO_888(data, sb[0], sg[0], sr[0]); + EXTRACT_x555_TO_888(data >> 16, sb[1], sg[1], sr[1]); + mask = LFB_RGB_PRESENT | (LFB_RGB_PRESENT << 4); + offset <<= 1; + break; + case 16*2 + 1: /* RGBA, 16-bit RGB x-5-5-5 */ + EXTRACT_555x_TO_888(data, sr[0], sg[0], sb[0]); + EXTRACT_555x_TO_888(data >> 16, sr[1], sg[1], sb[1]); + mask = LFB_RGB_PRESENT | (LFB_RGB_PRESENT << 4); + offset <<= 1; + break; + case 16*3 + 1: /* BGRA, 16-bit RGB x-5-5-5 */ + EXTRACT_555x_TO_888(data, sb[0], sg[0], sr[0]); + EXTRACT_555x_TO_888(data >> 16, sb[1], sg[1], sr[1]); + mask = LFB_RGB_PRESENT | (LFB_RGB_PRESENT << 4); + offset <<= 1; + break; + + case 16*0 + 2: /* ARGB, 16-bit ARGB 1-5-5-5 */ + EXTRACT_1555_TO_8888(data, sa[0], sr[0], sg[0], sb[0]); + EXTRACT_1555_TO_8888(data >> 16, sa[1], sr[1], sg[1], sb[1]); + mask = LFB_RGB_PRESENT | LFB_ALPHA_PRESENT | ((LFB_RGB_PRESENT | LFB_ALPHA_PRESENT) << 4); + offset <<= 1; + break; + case 16*1 + 2: /* ABGR, 16-bit ARGB 1-5-5-5 */ + EXTRACT_1555_TO_8888(data, sa[0], sb[0], sg[0], sr[0]); + EXTRACT_1555_TO_8888(data >> 16, sa[1], sb[1], sg[1], sr[1]); + mask = LFB_RGB_PRESENT | LFB_ALPHA_PRESENT | ((LFB_RGB_PRESENT | LFB_ALPHA_PRESENT) << 4); + offset <<= 1; + break; + case 16*2 + 2: /* RGBA, 16-bit ARGB 1-5-5-5 */ + EXTRACT_5551_TO_8888(data, sr[0], sg[0], sb[0], sa[0]); + EXTRACT_5551_TO_8888(data >> 16, sr[1], sg[1], sb[1], sa[1]); + mask = LFB_RGB_PRESENT | LFB_ALPHA_PRESENT | ((LFB_RGB_PRESENT | LFB_ALPHA_PRESENT) << 4); + offset <<= 1; + break; + case 16*3 + 2: /* BGRA, 16-bit ARGB 1-5-5-5 */ + EXTRACT_5551_TO_8888(data, sb[0], sg[0], sr[0], sa[0]); + EXTRACT_5551_TO_8888(data >> 16, sb[1], sg[1], sr[1], sa[1]); + mask = LFB_RGB_PRESENT | LFB_ALPHA_PRESENT | ((LFB_RGB_PRESENT | LFB_ALPHA_PRESENT) << 4); + offset <<= 1; + break; + + case 16*0 + 4: /* ARGB, 32-bit RGB x-8-8-8 */ + EXTRACT_x888_TO_888(data, sr[0], sg[0], sb[0]); + mask = LFB_RGB_PRESENT; + break; + case 16*1 + 4: /* ABGR, 32-bit RGB x-8-8-8 */ + EXTRACT_x888_TO_888(data, sb[0], sg[0], sr[0]); + mask = LFB_RGB_PRESENT; + break; + case 16*2 + 4: /* RGBA, 32-bit RGB x-8-8-8 */ + EXTRACT_888x_TO_888(data, sr[0], sg[0], sb[0]); + mask = LFB_RGB_PRESENT; + break; + case 16*3 + 4: /* BGRA, 32-bit RGB x-8-8-8 */ + EXTRACT_888x_TO_888(data, sb[0], sg[0], sr[0]); + mask = LFB_RGB_PRESENT; + break; + + case 16*0 + 5: /* ARGB, 32-bit ARGB 8-8-8-8 */ + EXTRACT_8888_TO_8888(data, sa[0], sr[0], sg[0], sb[0]); + mask = LFB_RGB_PRESENT | LFB_ALPHA_PRESENT; + break; + case 16*1 + 5: /* ABGR, 32-bit ARGB 8-8-8-8 */ + EXTRACT_8888_TO_8888(data, sa[0], sb[0], sg[0], sr[0]); + mask = LFB_RGB_PRESENT | LFB_ALPHA_PRESENT; + break; + case 16*2 + 5: /* RGBA, 32-bit ARGB 8-8-8-8 */ + EXTRACT_8888_TO_8888(data, sr[0], sg[0], sb[0], sa[0]); + mask = LFB_RGB_PRESENT | LFB_ALPHA_PRESENT; + break; + case 16*3 + 5: /* BGRA, 32-bit ARGB 8-8-8-8 */ + EXTRACT_8888_TO_8888(data, sb[0], sg[0], sr[0], sa[0]); + mask = LFB_RGB_PRESENT | LFB_ALPHA_PRESENT; + break; + + case 16*0 + 12: /* ARGB, 32-bit depth+RGB 5-6-5 */ + case 16*2 + 12: /* RGBA, 32-bit depth+RGB 5-6-5 */ + sw[0] = data >> 16; + EXTRACT_565_TO_888(data, sr[0], sg[0], sb[0]); + mask = LFB_RGB_PRESENT | LFB_DEPTH_PRESENT_MSW; + break; + case 16*1 + 12: /* ABGR, 32-bit depth+RGB 5-6-5 */ + case 16*3 + 12: /* BGRA, 32-bit depth+RGB 5-6-5 */ + sw[0] = data >> 16; + EXTRACT_565_TO_888(data, sb[0], sg[0], sr[0]); + mask = LFB_RGB_PRESENT | LFB_DEPTH_PRESENT_MSW; + break; + + case 16*0 + 13: /* ARGB, 32-bit depth+RGB x-5-5-5 */ + sw[0] = data >> 16; + EXTRACT_x555_TO_888(data, sr[0], sg[0], sb[0]); + mask = LFB_RGB_PRESENT | LFB_DEPTH_PRESENT_MSW; + break; + case 16*1 + 13: /* ABGR, 32-bit depth+RGB x-5-5-5 */ + sw[0] = data >> 16; + EXTRACT_x555_TO_888(data, sb[0], sg[0], sr[0]); + mask = LFB_RGB_PRESENT | LFB_DEPTH_PRESENT_MSW; + break; + case 16*2 + 13: /* RGBA, 32-bit depth+RGB x-5-5-5 */ + sw[0] = data >> 16; + EXTRACT_555x_TO_888(data, sr[0], sg[0], sb[0]); + mask = LFB_RGB_PRESENT | LFB_DEPTH_PRESENT_MSW; + break; + case 16*3 + 13: /* BGRA, 32-bit depth+RGB x-5-5-5 */ + sw[0] = data >> 16; + EXTRACT_555x_TO_888(data, sb[0], sg[0], sr[0]); + mask = LFB_RGB_PRESENT | LFB_DEPTH_PRESENT_MSW; + break; + + case 16*0 + 14: /* ARGB, 32-bit depth+ARGB 1-5-5-5 */ + sw[0] = data >> 16; + EXTRACT_1555_TO_8888(data, sa[0], sr[0], sg[0], sb[0]); + mask = LFB_RGB_PRESENT | LFB_ALPHA_PRESENT | LFB_DEPTH_PRESENT_MSW; + break; + case 16*1 + 14: /* ABGR, 32-bit depth+ARGB 1-5-5-5 */ + sw[0] = data >> 16; + EXTRACT_1555_TO_8888(data, sa[0], sb[0], sg[0], sr[0]); + mask = LFB_RGB_PRESENT | LFB_ALPHA_PRESENT | LFB_DEPTH_PRESENT_MSW; + break; + case 16*2 + 14: /* RGBA, 32-bit depth+ARGB 1-5-5-5 */ + sw[0] = data >> 16; + EXTRACT_5551_TO_8888(data, sr[0], sg[0], sb[0], sa[0]); + mask = LFB_RGB_PRESENT | LFB_ALPHA_PRESENT | LFB_DEPTH_PRESENT_MSW; + break; + case 16*3 + 14: /* BGRA, 32-bit depth+ARGB 1-5-5-5 */ + sw[0] = data >> 16; + EXTRACT_5551_TO_8888(data, sb[0], sg[0], sr[0], sa[0]); + mask = LFB_RGB_PRESENT | LFB_ALPHA_PRESENT | LFB_DEPTH_PRESENT_MSW; + break; + + case 16*0 + 15: /* ARGB, 16-bit depth */ + case 16*1 + 15: /* ARGB, 16-bit depth */ + case 16*2 + 15: /* ARGB, 16-bit depth */ + case 16*3 + 15: /* ARGB, 16-bit depth */ + sw[0] = data & 0xffff; + sw[1] = data >> 16; + mask = LFB_DEPTH_PRESENT | (LFB_DEPTH_PRESENT << 4); + offset <<= 1; + break; + + default: /* reserved */ + logerror("lfb_w: Unknown format\n"); + return 0; + } + + /* compute X,Y */ + x = offset & ((1 << v->fbi.lfb_stride) - 1); + y = (offset >> v->fbi.lfb_stride) & 0x3ff; + + /* adjust the mask based on which half of the data is written */ + if (!ACCESSING_BITS_0_15) + mask &= ~(0x0f - LFB_DEPTH_PRESENT_MSW); + if (!ACCESSING_BITS_16_31) + mask &= ~(0xf0 + LFB_DEPTH_PRESENT_MSW); + + /* select the target buffer */ + destbuf = (v->type >= TYPE_VOODOO_BANSHEE) ? 1 : LFBMODE_WRITE_BUFFER_SELECT(v->reg[lfbMode].u); + switch (destbuf) + { + case 0: /* front buffer */ + dest = (UINT16 *)(v->fbi.ram + v->fbi.rgboffs[v->fbi.frontbuf]); + destmax = (v->fbi.mask + 1 - v->fbi.rgboffs[v->fbi.frontbuf]) / 2; + v->fbi.video_changed = TRUE; + break; + + case 1: /* back buffer */ + dest = (UINT16 *)(v->fbi.ram + v->fbi.rgboffs[v->fbi.backbuf]); + destmax = (v->fbi.mask + 1 - v->fbi.rgboffs[v->fbi.backbuf]) / 2; + break; + + default: /* reserved */ + return 0; + } + depth = (UINT16 *)(v->fbi.ram + v->fbi.auxoffs); + depthmax = (v->fbi.mask + 1 - v->fbi.auxoffs) / 2; + + /* simple case: no pipeline */ + if (!LFBMODE_ENABLE_PIXEL_PIPELINE(v->reg[lfbMode].u)) + { + DECLARE_DITHER_POINTERS_NO_DITHER_VAR; + UINT32 bufoffs; + + if (LOG_LFB) logerror("VOODOO.%d.LFB:write raw mode %X (%d,%d) = %08X & %08X\n", v->index, LFBMODE_WRITE_FORMAT(v->reg[lfbMode].u), x, y, data, mem_mask); + + /* determine the screen Y */ + scry = y; + if (LFBMODE_Y_ORIGIN(v->reg[lfbMode].u)) + scry = (v->fbi.yorigin - y) & 0x3ff; + + /* advance pointers to the proper row */ + bufoffs = scry * v->fbi.rowpixels + x; + + /* compute dithering */ + COMPUTE_DITHER_POINTERS_NO_DITHER_VAR(v->reg[fbzMode].u, y); + + /* wait for any outstanding work to finish */ + poly_wait(v->poly, "LFB Write"); + + /* loop over up to two pixels */ + for (pix = 0; mask; pix++) + { + /* make sure we care about this pixel */ + if (mask & 0x0f) + { + /* write to the RGB buffer */ + if ((mask & LFB_RGB_PRESENT) && bufoffs < destmax) + { + /* apply dithering and write to the screen */ + APPLY_DITHER(v->reg[fbzMode].u, x, dither_lookup, sr[pix], sg[pix], sb[pix]); + dest[bufoffs] = (sr[pix] << 11) | (sg[pix] << 5) | sb[pix]; + } + + /* make sure we have an aux buffer to write to */ + if (depth && bufoffs < depthmax) + { + /* write to the alpha buffer */ + if ((mask & LFB_ALPHA_PRESENT) && FBZMODE_ENABLE_ALPHA_PLANES(v->reg[fbzMode].u)) + depth[bufoffs] = sa[pix]; + + /* write to the depth buffer */ + if ((mask & (LFB_DEPTH_PRESENT | LFB_DEPTH_PRESENT_MSW)) && !FBZMODE_ENABLE_ALPHA_PLANES(v->reg[fbzMode].u)) + depth[bufoffs] = sw[pix]; + } + + /* track pixel writes to the frame buffer regardless of mask */ + v->reg[fbiPixelsOut].u++; + } + + /* advance our pointers */ + bufoffs++; + x++; + mask >>= 4; + } + } + + /* tricky case: run the full pixel pipeline on the pixel */ + else + { + DECLARE_DITHER_POINTERS; + + if (LOG_LFB) logerror("VOODOO.%d.LFB:write pipelined mode %X (%d,%d) = %08X & %08X\n", v->index, LFBMODE_WRITE_FORMAT(v->reg[lfbMode].u), x, y, data, mem_mask); + + /* determine the screen Y */ + scry = y; + if (FBZMODE_Y_ORIGIN(v->reg[fbzMode].u)) + scry = (v->fbi.yorigin - y) & 0x3ff; + + /* advance pointers to the proper row */ + dest += scry * v->fbi.rowpixels; + if (depth) + depth += scry * v->fbi.rowpixels; + + /* compute dithering */ + COMPUTE_DITHER_POINTERS(v->reg[fbzMode].u, y); + + /* loop over up to two pixels */ + for (pix = 0; mask; pix++) + { + /* make sure we care about this pixel */ + if (mask & 0x0f) + { + stats_block *stats = &v->fbi.lfb_stats; + INT64 iterw; + if (LFBMODE_WRITE_W_SELECT(v->reg[lfbMode].u)) { + iterw = (UINT32) v->reg[zaColor].u << 16; + } else { + // The most significant fractional bits of 16.32 W are set to z + iterw = (UINT32) sw[pix] << 16; + } + INT32 iterz = sw[pix] << 12; + + /* apply clipping */ + if (FBZMODE_ENABLE_CLIPPING(v->reg[fbzMode].u)) + { + if (x < ((v->reg[clipLeftRight].u >> 16) & 0x3ff) || + x >= (v->reg[clipLeftRight].u & 0x3ff) || + scry < ((v->reg[clipLowYHighY].u >> 16) & 0x3ff) || + scry >= (v->reg[clipLowYHighY].u & 0x3ff)) + { + stats->pixels_in++; + stats->clip_fail++; + goto nextpixel; + } + } + #if USE_OLD_RASTER == 1 + rgb_union color; + rgb_union iterargb = { 0 }; + #else + rgbaint_t color, preFog; + rgbaint_t iterargb(0); + #endif + + /* pixel pipeline part 1 handles depth testing and stippling */ + //PIXEL_PIPELINE_BEGIN(v, stats, x, y, v->reg[fbzColorPath].u, v->reg[fbzMode].u, iterz, iterw); +// Start PIXEL_PIPE_BEGIN copy + //#define PIXEL_PIPELINE_BEGIN(VV, STATS, XX, YY, FBZCOLORPATH, FBZMODE, ITERZ, ITERW) + INT32 fogdepth, biasdepth; + INT32 r, g, b, a; + + (stats)->pixels_in++; + + /* apply clipping */ + /* note that for perf reasons, we assume the caller has done clipping */ + + /* handle stippling */ + if (FBZMODE_ENABLE_STIPPLE(v->reg[fbzMode].u)) + { + /* rotate mode */ + if (FBZMODE_STIPPLE_PATTERN(v->reg[fbzMode].u) == 0) + { + v->reg[stipple].u = (v->reg[stipple].u << 1) | (v->reg[stipple].u >> 31); + if ((v->reg[stipple].u & 0x80000000) == 0) + { + v->stats.total_stippled++; + goto skipdrawdepth; + } + } + + /* pattern mode */ + else + { + int stipple_index = ((y & 3) << 3) | (~x & 7); + if (((v->reg[stipple].u >> stipple_index) & 1) == 0) + { + v->stats.total_stippled++; + goto nextpixel; + } + } + } +// End PIXEL_PIPELINE_BEGIN COPY + + // Depth testing value for lfb pipeline writes is directly from write data, no biasing is used + fogdepth = biasdepth = (UINT32) sw[pix]; + + #if USE_OLD_RASTER == 1 + /* Perform depth testing */ + DEPTH_TEST(v, stats, x, v->reg[fbzMode].u); + + /* use the RGBA we stashed above */ + color.rgb.r = r = sr[pix]; + color.rgb.g = g = sg[pix]; + color.rgb.b = b = sb[pix]; + color.rgb.a = a = sa[pix]; + + /* apply chroma key, alpha mask, and alpha testing */ + APPLY_CHROMAKEY(v, stats, v->reg[fbzMode].u, color); + APPLY_ALPHAMASK(v, stats, v->reg[fbzMode].u, color.rgb.a); + APPLY_ALPHATEST(v, stats, v->reg[alphaMode].u, color.rgb.a); + #else + /* Perform depth testing */ + if (!depthTest((UINT16) v->reg[zaColor].u, stats, depth[x], v->reg[fbzMode].u, biasdepth)) + goto nextpixel; + + /* use the RGBA we stashed above */ + color.set(sa[pix], sr[pix], sg[pix], sb[pix]); + + /* handle chroma key */ + if (!chromaKeyTest(v, stats, v->reg[fbzMode].u, color)) + goto nextpixel; + /* handle alpha mask */ + if (!alphaMaskTest(stats, v->reg[fbzMode].u, color.get_a())) + goto nextpixel; + /* handle alpha test */ + if (!alphaTest(v, stats, v->reg[alphaMode].u, color.get_a())) + goto nextpixel; + #endif + + /* wait for any outstanding work to finish */ + poly_wait(v->poly, "LFB Write"); + + /* pixel pipeline part 2 handles color combine, fog, alpha, and final output */ + PIXEL_PIPELINE_END(v, stats, dither, dither4, dither_lookup, x, dest, depth, + v->reg[fbzMode].u, v->reg[fbzColorPath].u, v->reg[alphaMode].u, v->reg[fogMode].u, + iterz, iterw, iterargb); +nextpixel: + /* advance our pointers */ + x++; + mask >>= 4; + } + } + + return 0; +} + + + +/************************************* + * + * Voodoo texture RAM writes + * + *************************************/ + +static INT32 texture_w(voodoo_state *v, offs_t offset, UINT32 data) +{ + int tmunum = (offset >> 19) & 0x03; + tmu_state *t; + + /* statistics */ + v->stats.tex_writes++; + + /* point to the right TMU */ + if (!(v->chipmask & (2 << tmunum))) + return 0; + t = &v->tmu[tmunum]; + + if (TEXLOD_TDIRECT_WRITE(t->reg[tLOD].u)) + fatalerror("Texture direct write!\n"); + + /* wait for any outstanding work to finish */ + poly_wait(v->poly, "Texture write"); + + /* update texture info if dirty */ + if (t->regdirty) + recompute_texture_params(t); + + /* swizzle the data */ + if (TEXLOD_TDATA_SWIZZLE(t->reg[tLOD].u)) + data = FLIPENDIAN_INT32(data); + if (TEXLOD_TDATA_SWAP(t->reg[tLOD].u)) + data = (data >> 16) | (data << 16); + + /* 8-bit texture case */ + if (TEXMODE_FORMAT(t->reg[textureMode].u) < 8) + { + int lod, tt, ts; + UINT32 tbaseaddr; + UINT8 *dest; + + /* extract info */ + if (v->type <= TYPE_VOODOO_2) + { + lod = (offset >> 15) & 0x0f; + tt = (offset >> 7) & 0xff; + + /* old code has a bit about how this is broken in gauntleg unless we always look at TMU0 */ + if (TEXMODE_SEQ_8_DOWNLD(v->tmu[0].reg/*t->reg*/[textureMode].u)) + ts = (offset << 2) & 0xfc; + else + ts = (offset << 1) & 0xfc; + + /* validate parameters */ + if (lod > 8) + return 0; + + /* compute the base address */ + tbaseaddr = t->lodoffset[lod]; + tbaseaddr += tt * ((t->wmask >> lod) + 1) + ts; + + if (LOG_TEXTURE_RAM) logerror("Texture 8-bit w: lod=%d s=%d t=%d data=%08X\n", lod, ts, tt, data); + } + else + { + tbaseaddr = t->lodoffset[0] + offset*4; + + if (LOG_TEXTURE_RAM) logerror("Texture 8-bit w: offset=%X data=%08X\n", offset*4, data); + } + + /* write the four bytes in little-endian order */ + dest = t->ram; + tbaseaddr &= t->mask; + dest[BYTE4_XOR_LE(tbaseaddr + 0)] = (data >> 0) & 0xff; + dest[BYTE4_XOR_LE(tbaseaddr + 1)] = (data >> 8) & 0xff; + dest[BYTE4_XOR_LE(tbaseaddr + 2)] = (data >> 16) & 0xff; + dest[BYTE4_XOR_LE(tbaseaddr + 3)] = (data >> 24) & 0xff; + } + + /* 16-bit texture case */ + else + { + int lod, tt, ts; + UINT32 tbaseaddr; + UINT16 *dest; + + /* extract info */ + if (v->type <= TYPE_VOODOO_2) + { + lod = (offset >> 15) & 0x0f; + tt = (offset >> 7) & 0xff; + ts = (offset << 1) & 0xfe; + + /* validate parameters */ + if (lod > 8) + return 0; + + /* compute the base address */ + tbaseaddr = t->lodoffset[lod]; + tbaseaddr += 2 * (tt * ((t->wmask >> lod) + 1) + ts); + + if (LOG_TEXTURE_RAM) logerror("Texture 16-bit w: lod=%d s=%d t=%d data=%08X\n", lod, ts, tt, data); + } + else + { + tbaseaddr = t->lodoffset[0] + offset*4; + + if (LOG_TEXTURE_RAM) logerror("Texture 16-bit w: offset=%X data=%08X\n", offset*4, data); + } + + /* write the two words in little-endian order */ + dest = (UINT16 *)t->ram; + tbaseaddr &= t->mask; + tbaseaddr >>= 1; + dest[BYTE_XOR_LE(tbaseaddr + 0)] = (data >> 0) & 0xffff; + dest[BYTE_XOR_LE(tbaseaddr + 1)] = (data >> 16) & 0xffff; + } + + return 0; +} + + + +/************************************* + * + * Flush data from the FIFOs + * + *************************************/ + +static void flush_fifos(voodoo_state *v, attotime current_time) +{ + static UINT8 in_flush; + + /* check for recursive calls */ + if (in_flush) + return; + in_flush = TRUE; + + if (!v->pci.op_pending) fatalerror("flush_fifos called with no pending operation\n"); + + if (LOG_FIFO_VERBOSE) logerror("VOODOO.%d.FIFO:flush_fifos start -- pending=%d.%08X%08X cur=%d.%08X%08X\n", v->index, + v->pci.op_end_time.seconds(), (UINT32)(v->pci.op_end_time.attoseconds() >> 32), (UINT32)v->pci.op_end_time.attoseconds(), + current_time.seconds(), (UINT32)(current_time.attoseconds() >> 32), (UINT32)current_time.attoseconds()); + + /* loop while we still have cycles to burn */ + while (v->pci.op_end_time <= current_time) + { + INT32 extra_cycles = 0; + INT32 cycles; + + /* loop over 0-cycle stuff; this constitutes the bulk of our writes */ + do + { + fifo_state *fifo; + UINT32 address; + UINT32 data; + + /* we might be in CMDFIFO mode */ + if (v->fbi.cmdfifo[0].enable) + { + /* if we don't have anything to execute, we're done for now */ + cycles = cmdfifo_execute_if_ready(v, &v->fbi.cmdfifo[0]); + if (cycles == -1) + { + v->pci.op_pending = FALSE; + in_flush = FALSE; + if (LOG_FIFO_VERBOSE) logerror("VOODOO.%d.FIFO:flush_fifos end -- CMDFIFO empty\n", v->index); + return; + } + } + else if (v->fbi.cmdfifo[1].enable) + { + /* if we don't have anything to execute, we're done for now */ + cycles = cmdfifo_execute_if_ready(v, &v->fbi.cmdfifo[1]); + if (cycles == -1) + { + v->pci.op_pending = FALSE; + in_flush = FALSE; + if (LOG_FIFO_VERBOSE) logerror("VOODOO.%d.FIFO:flush_fifos end -- CMDFIFO empty\n", v->index); + return; + } + } + + /* else we are in standard PCI/memory FIFO mode */ + else + { + /* choose which FIFO to read from */ + if (!fifo_empty(&v->fbi.fifo)) + fifo = &v->fbi.fifo; + else if (!fifo_empty(&v->pci.fifo)) + fifo = &v->pci.fifo; + else + { + v->pci.op_pending = FALSE; + in_flush = FALSE; + if (LOG_FIFO_VERBOSE) logerror("VOODOO.%d.FIFO:flush_fifos end -- FIFOs empty\n", v->index); + return; + } + + /* extract address and data */ + address = fifo_remove(fifo); + data = fifo_remove(fifo); + + /* target the appropriate location */ + if ((address & (0xc00000/4)) == 0) + cycles = register_w(v, address, data); + else if (address & (0x800000/4)) + cycles = texture_w(v, address, data); + else + { + UINT32 mem_mask = 0xffffffff; + + /* compute mem_mask */ + if (address & 0x80000000) + mem_mask &= 0x0000ffff; + if (address & 0x40000000) + mem_mask &= 0xffff0000; + address &= 0xffffff; + + cycles = lfb_w(v, address, data, mem_mask); + } + } + + /* accumulate smaller operations */ + if (cycles < ACCUMULATE_THRESHOLD) + { + extra_cycles += cycles; + cycles = 0; + } + } + while (cycles == 0); + + /* account for extra cycles */ + cycles += extra_cycles; + + /* account for those cycles */ + v->pci.op_end_time += attotime(0, (attoseconds_t)cycles * v->attoseconds_per_cycle); + + if (LOG_FIFO_VERBOSE) logerror("VOODOO.%d.FIFO:update -- pending=%d.%08X%08X cur=%d.%08X%08X\n", v->index, + v->pci.op_end_time.seconds(), (UINT32)(v->pci.op_end_time.attoseconds() >> 32), (UINT32)v->pci.op_end_time.attoseconds(), + current_time.seconds(), (UINT32)(current_time.attoseconds() >> 32), (UINT32)current_time.attoseconds()); + } + + if (LOG_FIFO_VERBOSE) logerror("VOODOO.%d.FIFO:flush_fifos end -- pending command complete at %d.%08X%08X\n", v->index, + v->pci.op_end_time.seconds(), (UINT32)(v->pci.op_end_time.attoseconds() >> 32), (UINT32)v->pci.op_end_time.attoseconds()); + + in_flush = FALSE; +} + + + +/************************************* + * + * Handle a write to the Voodoo + * memory space + * + *************************************/ + +WRITE32_MEMBER( voodoo_device::voodoo_w ) +{ + voodoo_state *v = get_safe_token(this); + int stall = FALSE; + + g_profiler.start(PROFILER_USER1); + + /* should not be getting accesses while stalled */ + if (v->pci.stall_state != NOT_STALLED) + logerror("voodoo_w while stalled!\n"); + + /* if we have something pending, flush the FIFOs up to the current time */ + if (v->pci.op_pending) + flush_fifos(v, machine().time()); + + /* special handling for registers */ + if ((offset & 0xc00000/4) == 0) + { + UINT8 access; + + /* some special stuff for Voodoo 2 */ + if (v->type >= TYPE_VOODOO_2) + { + /* we might be in CMDFIFO mode */ + if (FBIINIT7_CMDFIFO_ENABLE(v->reg[fbiInit7].u)) + { + /* if bit 21 is set, we're writing to the FIFO */ + if (offset & 0x200000/4) + { + /* check for byte swizzling (bit 18) */ + if (offset & 0x40000/4) + data = FLIPENDIAN_INT32(data); + cmdfifo_w(v, &v->fbi.cmdfifo[0], offset & 0xffff, data); + g_profiler.stop(); + return; + } + + /* we're a register access; but only certain ones are allowed */ + access = v->regaccess[offset & 0xff]; + if (!(access & REGISTER_WRITETHRU)) + { + /* track swap buffers regardless */ + if ((offset & 0xff) == swapbufferCMD) + v->fbi.swaps_pending++; + + logerror("Ignoring write to %s in CMDFIFO mode\n", v->regnames[offset & 0xff]); + g_profiler.stop(); + return; + } + } + + /* if not, we might be byte swizzled (bit 20) */ + else if (offset & 0x100000/4) + data = FLIPENDIAN_INT32(data); + } + + /* check the access behavior; note that the table works even if the */ + /* alternate mapping is used */ + access = v->regaccess[offset & 0xff]; + + /* ignore if writes aren't allowed */ + if (!(access & REGISTER_WRITE)) + { + g_profiler.stop(); + return; + } + + /* if this is a non-FIFO command, let it go to the FIFO, but stall until it completes */ + if (!(access & REGISTER_FIFO)) + stall = TRUE; + + /* track swap buffers */ + if ((offset & 0xff) == swapbufferCMD) + v->fbi.swaps_pending++; + } + + /* if we don't have anything pending, or if FIFOs are disabled, just execute */ + if (!v->pci.op_pending || !INITEN_ENABLE_PCI_FIFO(v->pci.init_enable)) + { + int cycles; + + /* target the appropriate location */ + if ((offset & (0xc00000/4)) == 0) + cycles = register_w(v, offset, data); + else if (offset & (0x800000/4)) + cycles = texture_w(v, offset, data); + else + cycles = lfb_w(v, offset, data, mem_mask); + + /* if we ended up with cycles, mark the operation pending */ + if (cycles) + { + v->pci.op_pending = TRUE; + v->pci.op_end_time = machine().time() + attotime(0, (attoseconds_t)cycles * v->attoseconds_per_cycle); + + if (LOG_FIFO_VERBOSE) logerror("VOODOO.%d.FIFO:direct write start at %d.%08X%08X end at %d.%08X%08X\n", v->index, + machine().time().seconds(), (UINT32)(machine().time().attoseconds() >> 32), (UINT32)machine().time().attoseconds(), + v->pci.op_end_time.seconds(), (UINT32)(v->pci.op_end_time.attoseconds() >> 32), (UINT32)v->pci.op_end_time.attoseconds()); + } + g_profiler.stop(); + return; + } + + /* modify the offset based on the mem_mask */ + if (mem_mask != 0xffffffff) + { + if (!ACCESSING_BITS_16_31) + offset |= 0x80000000; + if (!ACCESSING_BITS_0_15) + offset |= 0x40000000; + } + + /* if there's room in the PCI FIFO, add there */ + if (LOG_FIFO_VERBOSE) logerror("VOODOO.%d.FIFO:voodoo_w adding to PCI FIFO @ %08X=%08X\n", v->index, offset, data); + if (!fifo_full(&v->pci.fifo)) + { + fifo_add(&v->pci.fifo, offset); + fifo_add(&v->pci.fifo, data); + } + else + fatalerror("PCI FIFO full\n"); + + /* handle flushing to the memory FIFO */ + if (FBIINIT0_ENABLE_MEMORY_FIFO(v->reg[fbiInit0].u) && + fifo_space(&v->pci.fifo) <= 2 * FBIINIT4_MEMORY_FIFO_LWM(v->reg[fbiInit4].u)) + { + UINT8 valid[4]; + + /* determine which types of data can go to the memory FIFO */ + valid[0] = TRUE; + valid[1] = FBIINIT0_LFB_TO_MEMORY_FIFO(v->reg[fbiInit0].u); + valid[2] = valid[3] = FBIINIT0_TEXMEM_TO_MEMORY_FIFO(v->reg[fbiInit0].u); + + /* flush everything we can */ + if (LOG_FIFO_VERBOSE) logerror("VOODOO.%d.FIFO:voodoo_w moving PCI FIFO to memory FIFO\n", v->index); + while (!fifo_empty(&v->pci.fifo) && valid[(fifo_peek(&v->pci.fifo) >> 22) & 3]) + { + fifo_add(&v->fbi.fifo, fifo_remove(&v->pci.fifo)); + fifo_add(&v->fbi.fifo, fifo_remove(&v->pci.fifo)); + } + + /* if we're above the HWM as a result, stall */ + if (FBIINIT0_STALL_PCIE_FOR_HWM(v->reg[fbiInit0].u) && + fifo_items(&v->fbi.fifo) >= 2 * 32 * FBIINIT0_MEMORY_FIFO_HWM(v->reg[fbiInit0].u)) + { + if (LOG_FIFO) logerror("VOODOO.%d.FIFO:voodoo_w hit memory FIFO HWM -- stalling\n", v->index); + stall_cpu(v, STALLED_UNTIL_FIFO_LWM, machine().time()); + } + } + + /* if we're at the LWM for the PCI FIFO, stall */ + if (FBIINIT0_STALL_PCIE_FOR_HWM(v->reg[fbiInit0].u) && + fifo_space(&v->pci.fifo) <= 2 * FBIINIT0_PCI_FIFO_LWM(v->reg[fbiInit0].u)) + { + if (LOG_FIFO) logerror("VOODOO.%d.FIFO:voodoo_w hit PCI FIFO free LWM -- stalling\n", v->index); + stall_cpu(v, STALLED_UNTIL_FIFO_LWM, machine().time()); + } + + /* if we weren't ready, and this is a non-FIFO access, stall until the FIFOs are clear */ + if (stall) + { + if (LOG_FIFO_VERBOSE) logerror("VOODOO.%d.FIFO:voodoo_w wrote non-FIFO register -- stalling until clear\n", v->index); + stall_cpu(v, STALLED_UNTIL_FIFO_EMPTY, machine().time()); + } + + g_profiler.stop(); +} + + + +/************************************* + * + * Handle a register read + * + *************************************/ + +static UINT32 register_r(voodoo_state *v, offs_t offset) +{ + int regnum = offset & 0xff; + UINT32 result; + + /* statistics */ + v->stats.reg_reads++; + + /* first make sure this register is readable */ + if (!(v->regaccess[regnum] & REGISTER_READ)) + { + logerror("VOODOO.%d.ERROR:Invalid attempt to read %s\n", v->index, regnum < 225 ? v->regnames[regnum] : "unknown register"); + return 0xffffffff; + } + + /* default result is the FBI register value */ + result = v->reg[regnum].u; + + /* some registers are dynamic; compute them */ + switch (regnum) + { + case status: + + /* start with a blank slate */ + result = 0; + + /* bits 5:0 are the PCI FIFO free space */ + if (fifo_empty(&v->pci.fifo)) + result |= 0x3f << 0; + else + { + int temp = fifo_space(&v->pci.fifo)/2; + if (temp > 0x3f) + temp = 0x3f; + result |= temp << 0; + } + + /* bit 6 is the vertical retrace */ + result |= v->fbi.vblank << 6; + + /* bit 7 is FBI graphics engine busy */ + if (v->pci.op_pending) + result |= 1 << 7; + + /* bit 8 is TREX busy */ + if (v->pci.op_pending) + result |= 1 << 8; + + /* bit 9 is overall busy */ + if (v->pci.op_pending) + result |= 1 << 9; + + /* Banshee is different starting here */ + if (v->type < TYPE_VOODOO_BANSHEE) + { + /* bits 11:10 specifies which buffer is visible */ + result |= v->fbi.frontbuf << 10; + + /* bits 27:12 indicate memory FIFO freespace */ + if (!FBIINIT0_ENABLE_MEMORY_FIFO(v->reg[fbiInit0].u) || fifo_empty(&v->fbi.fifo)) + result |= 0xffff << 12; + else + { + int temp = fifo_space(&v->fbi.fifo)/2; + if (temp > 0xffff) + temp = 0xffff; + result |= temp << 12; + } + } + else + { + /* bit 10 is 2D busy */ + + /* bit 11 is cmd FIFO 0 busy */ + if (v->fbi.cmdfifo[0].enable && v->fbi.cmdfifo[0].depth > 0) + result |= 1 << 11; + + /* bit 12 is cmd FIFO 1 busy */ + if (v->fbi.cmdfifo[1].enable && v->fbi.cmdfifo[1].depth > 0) + result |= 1 << 12; + } + + /* bits 30:28 are the number of pending swaps */ + if (v->fbi.swaps_pending > 7) + result |= 7 << 28; + else + result |= v->fbi.swaps_pending << 28; + + /* bit 31 is not used */ + + /* eat some cycles since people like polling here */ + if (EAT_CYCLES) v->cpu->execute().eat_cycles(1000); + break; + + /* bit 2 of the initEnable register maps this to dacRead */ + case fbiInit2: + if (INITEN_REMAP_INIT_TO_DAC(v->pci.init_enable)) + result = v->dac.read_result; + break; + + /* return the current scanline for now */ + case vRetrace: + + /* eat some cycles since people like polling here */ + if (EAT_CYCLES) v->cpu->execute().eat_cycles(10); + result = v->screen->vpos(); + break; + + /* reserved area in the TMU read by the Vegas startup sequence */ + case hvRetrace: + result = 0x200 << 16; /* should be between 0x7b and 0x267 */ + result |= 0x80; /* should be between 0x17 and 0x103 */ + break; + + /* cmdFifo -- Voodoo2 only */ + case cmdFifoRdPtr: + result = v->fbi.cmdfifo[0].rdptr; + + /* eat some cycles since people like polling here */ + if (EAT_CYCLES) v->cpu->execute().eat_cycles(1000); + break; + + case cmdFifoAMin: + result = v->fbi.cmdfifo[0].amin; + break; + + case cmdFifoAMax: + result = v->fbi.cmdfifo[0].amax; + break; + + case cmdFifoDepth: + result = v->fbi.cmdfifo[0].depth; + break; + + case cmdFifoHoles: + result = v->fbi.cmdfifo[0].holes; + break; + + /* all counters are 24-bit only */ + case fbiPixelsIn: + case fbiChromaFail: + case fbiZfuncFail: + case fbiAfuncFail: + case fbiPixelsOut: + update_statistics(v, TRUE); + case fbiTrianglesOut: + result = v->reg[regnum].u & 0xffffff; + break; + } + + if (LOG_REGISTERS) + { + int logit = TRUE; + + /* don't log multiple identical status reads from the same address */ + if (regnum == status) + { + offs_t pc = v->cpu->safe_pc(); + if (pc == v->last_status_pc && result == v->last_status_value) + logit = FALSE; + v->last_status_pc = pc; + v->last_status_value = result; + } + if (regnum == cmdFifoRdPtr) + logit = FALSE; + + if (logit) + logerror("VOODOO.%d.REG:%s read = %08X\n", v->index, v->regnames[regnum], result); + } + + return result; +} + + + +/************************************* + * + * Handle an LFB read + * + *************************************/ + +static UINT32 lfb_r(voodoo_state *v, offs_t offset, bool lfb_3d) +{ + UINT16 *buffer; + UINT32 bufmax; + UINT32 bufoffs; + UINT32 data; + int x, y, scry, destbuf; + + /* statistics */ + v->stats.lfb_reads++; + + /* compute X,Y */ + offset <<= 1; + x = offset & ((1 << v->fbi.lfb_stride) - 1); + y = (offset >> v->fbi.lfb_stride); + + /* select the target buffer */ + if (lfb_3d) { + y &= 0x3ff; + destbuf = (v->type >= TYPE_VOODOO_BANSHEE) ? 1 : LFBMODE_READ_BUFFER_SELECT(v->reg[lfbMode].u); + switch (destbuf) + { + case 0: /* front buffer */ + buffer = (UINT16 *)(v->fbi.ram + v->fbi.rgboffs[v->fbi.frontbuf]); + bufmax = (v->fbi.mask + 1 - v->fbi.rgboffs[v->fbi.frontbuf]) / 2; + break; + + case 1: /* back buffer */ + buffer = (UINT16 *)(v->fbi.ram + v->fbi.rgboffs[v->fbi.backbuf]); + bufmax = (v->fbi.mask + 1 - v->fbi.rgboffs[v->fbi.backbuf]) / 2; + break; + + case 2: /* aux buffer */ + if (v->fbi.auxoffs == ~0) + return 0xffffffff; + buffer = (UINT16 *)(v->fbi.ram + v->fbi.auxoffs); + bufmax = (v->fbi.mask + 1 - v->fbi.auxoffs) / 2; + break; + + default: /* reserved */ + return 0xffffffff; + } + + /* determine the screen Y */ + scry = y; + if (LFBMODE_Y_ORIGIN(v->reg[lfbMode].u)) + scry = (v->fbi.yorigin - y) & 0x3ff; + } else { + // Direct lfb access + buffer = (UINT16 *)(v->fbi.ram + v->fbi.lfb_base*4); + bufmax = (v->fbi.mask + 1 - v->fbi.lfb_base*4) / 2; + scry = y; + } + + /* advance pointers to the proper row */ + bufoffs = scry * v->fbi.rowpixels + x; + if (bufoffs >= bufmax) { + logerror("LFB_R: Buffer offset out of bounds x=%i y=%i lfb_3d=%i offset=%08X bufoffs=%08X\n", x, y, lfb_3d, offset, (UINT32) bufoffs); + return 0xffffffff; + } + + /* wait for any outstanding work to finish */ + poly_wait(v->poly, "LFB read"); + + /* compute the data */ + data = buffer[bufoffs + 0] | (buffer[bufoffs + 1] << 16); + + /* word swapping */ + if (LFBMODE_WORD_SWAP_READS(v->reg[lfbMode].u)) + data = (data << 16) | (data >> 16); + + /* byte swizzling */ + if (LFBMODE_BYTE_SWIZZLE_READS(v->reg[lfbMode].u)) + data = FLIPENDIAN_INT32(data); + + if (LOG_LFB) logerror("VOODOO.%d.LFB:read (%d,%d) = %08X\n", v->index, x, y, data); + return data; +} + + + +/************************************* + * + * Handle a read from the Voodoo + * memory space + * + *************************************/ + +READ32_MEMBER( voodoo_device::voodoo_r ) +{ + voodoo_state *v = get_safe_token(this); + + /* if we have something pending, flush the FIFOs up to the current time */ + if (v->pci.op_pending) + flush_fifos(v, machine().time()); + + /* target the appropriate location */ + if (!(offset & (0xc00000/4))) + return register_r(v, offset); + else if (!(offset & (0x800000/4))) + return lfb_r(v, offset, true); + + return 0xffffffff; +} + + + +/************************************* + * + * Handle a read from the Banshee + * I/O space + * + *************************************/ + +READ32_MEMBER( voodoo_banshee_device::banshee_agp_r ) +{ + voodoo_state *v = get_safe_token(this); + UINT32 result; + + offset &= 0x1ff/4; + + /* switch off the offset */ + switch (offset) + { + case cmdRdPtrL0: + result = v->fbi.cmdfifo[0].rdptr; + break; + + case cmdAMin0: + result = v->fbi.cmdfifo[0].amin; + break; + + case cmdAMax0: + result = v->fbi.cmdfifo[0].amax; + break; + + case cmdFifoDepth0: + result = v->fbi.cmdfifo[0].depth; + break; + + case cmdHoleCnt0: + result = v->fbi.cmdfifo[0].holes; + break; + + case cmdRdPtrL1: + result = v->fbi.cmdfifo[1].rdptr; + break; + + case cmdAMin1: + result = v->fbi.cmdfifo[1].amin; + break; + + case cmdAMax1: + result = v->fbi.cmdfifo[1].amax; + break; + + case cmdFifoDepth1: + result = v->fbi.cmdfifo[1].depth; + break; + + case cmdHoleCnt1: + result = v->fbi.cmdfifo[1].holes; + break; + + default: + result = v->banshee.agp[offset]; + break; + } + + if (LOG_REGISTERS) + logerror("%s:banshee_r(AGP:%s)\n", v->device->machine().describe_context(), banshee_agp_reg_name[offset]); + return result; +} + + +READ32_MEMBER( voodoo_banshee_device::banshee_r ) +{ + voodoo_state *v = get_safe_token(this); + UINT32 result = 0xffffffff; + + /* if we have something pending, flush the FIFOs up to the current time */ + if (v->pci.op_pending) + flush_fifos(v, machine().time()); + + if (offset < 0x80000/4) + result = banshee_io_r(space, offset, mem_mask); + else if (offset < 0x100000/4) + result = banshee_agp_r(space, offset, mem_mask); + else if (offset < 0x200000/4) + logerror("%s:banshee_r(2D:%X)\n", machine().describe_context(), (offset*4) & 0xfffff); + else if (offset < 0x600000/4) + result = register_r(v, offset & 0x1fffff/4); + else if (offset < 0x800000/4) + logerror("%s:banshee_r(TEX0:%X)\n", machine().describe_context(), (offset*4) & 0x1fffff); + else if (offset < 0xa00000/4) + logerror("%s:banshee_r(TEX1:%X)\n", machine().describe_context(), (offset*4) & 0x1fffff); + else if (offset < 0xc00000/4) + logerror("%s:banshee_r(FLASH Bios ROM:%X)\n", machine().describe_context(), (offset*4) & 0x3fffff); + else if (offset < 0x1000000/4) + logerror("%s:banshee_r(YUV:%X)\n", machine().describe_context(), (offset*4) & 0x3fffff); + else if (offset < 0x2000000/4) + { + result = lfb_r(v, offset & 0xffffff/4, true); + } else { + logerror("%s:banshee_r(%X) Access out of bounds\n", machine().describe_context(), offset*4); + } + return result; +} + + +READ32_MEMBER( voodoo_banshee_device::banshee_fb_r ) +{ + voodoo_state *v = get_safe_token(this); + UINT32 result = 0xffffffff; + + /* if we have something pending, flush the FIFOs up to the current time */ + if (v->pci.op_pending) + flush_fifos(v, machine().time()); + + if (offset < v->fbi.lfb_base) + { +#if LOG_LFB + logerror("%s:banshee_fb_r(%X)\n", machine().describe_context(), offset*4); +#endif + if (offset*4 <= v->fbi.mask) + result = ((UINT32 *)v->fbi.ram)[offset]; + else + logerror("%s:banshee_fb_r(%X) Access out of bounds\n", machine().describe_context(), offset*4); + } + else { + if (LOG_LFB) + logerror("%s:banshee_fb_r(%X) to lfb_r: %08X lfb_base=%08X\n", machine().describe_context(), offset*4, offset - v->fbi.lfb_base, v->fbi.lfb_base); + result = lfb_r(v, offset - v->fbi.lfb_base, false); + } + return result; +} + + +READ8_MEMBER( voodoo_banshee_device::banshee_vga_r ) +{ + voodoo_state *v = get_safe_token(this); + UINT8 result = 0xff; + + offset &= 0x1f; + + /* switch off the offset */ + switch (offset + 0x3c0) + { + /* attribute access */ + case 0x3c0: + if (v->banshee.vga[0x3c1 & 0x1f] < ARRAY_LENGTH(v->banshee.att)) + result = v->banshee.att[v->banshee.vga[0x3c1 & 0x1f]]; + if (LOG_REGISTERS) + logerror("%s:banshee_att_r(%X)\n", machine().describe_context(), v->banshee.vga[0x3c1 & 0x1f]); + break; + + /* Input status 0 */ + case 0x3c2: + /* + bit 7 = Interrupt Status. When its value is ?1?, denotes that an interrupt is pending. + bit 6:5 = Feature Connector. These 2 bits are readable bits from the feature connector. + bit 4 = Sense. This bit reflects the state of the DAC monitor sense logic. + bit 3:0 = Reserved. Read back as 0. + */ + result = 0x00; + if (LOG_REGISTERS) + logerror("%s:banshee_vga_r(%X)\n", machine().describe_context(), 0x300+offset); + break; + + /* Sequencer access */ + case 0x3c5: + if (v->banshee.vga[0x3c4 & 0x1f] < ARRAY_LENGTH(v->banshee.seq)) + result = v->banshee.seq[v->banshee.vga[0x3c4 & 0x1f]]; + if (LOG_REGISTERS) + logerror("%s:banshee_seq_r(%X)\n", machine().describe_context(), v->banshee.vga[0x3c4 & 0x1f]); + break; + + /* Feature control */ + case 0x3ca: + result = v->banshee.vga[0x3da & 0x1f]; + v->banshee.attff = 0; + if (LOG_REGISTERS) + logerror("%s:banshee_vga_r(%X)\n", machine().describe_context(), 0x300+offset); + break; + + /* Miscellaneous output */ + case 0x3cc: + result = v->banshee.vga[0x3c2 & 0x1f]; + if (LOG_REGISTERS) + logerror("%s:banshee_vga_r(%X)\n", machine().describe_context(), 0x300+offset); + break; + + /* Graphics controller access */ + case 0x3cf: + if (v->banshee.vga[0x3ce & 0x1f] < ARRAY_LENGTH(v->banshee.gc)) + result = v->banshee.gc[v->banshee.vga[0x3ce & 0x1f]]; + if (LOG_REGISTERS) + logerror("%s:banshee_gc_r(%X)\n", machine().describe_context(), v->banshee.vga[0x3ce & 0x1f]); + break; + + /* CRTC access */ + case 0x3d5: + if (v->banshee.vga[0x3d4 & 0x1f] < ARRAY_LENGTH(v->banshee.crtc)) + result = v->banshee.crtc[v->banshee.vga[0x3d4 & 0x1f]]; + if (LOG_REGISTERS) + logerror("%s:banshee_crtc_r(%X)\n", machine().describe_context(), v->banshee.vga[0x3d4 & 0x1f]); + break; + + /* Input status 1 */ + case 0x3da: + /* + bit 7:6 = Reserved. These bits read back 0. + bit 5:4 = Display Status. These 2 bits reflect 2 of the 8 pixel data outputs from the Attribute + controller, as determined by the Attribute controller index 0x12 bits 4 and 5. + bit 3 = Vertical sync Status. A ?1? indicates vertical retrace is in progress. + bit 2:1 = Reserved. These bits read back 0x2. + bit 0 = Display Disable. When this bit is 1, either horizontal or vertical display end has occurred, + otherwise video data is being displayed. + */ + result = 0x04; + if (LOG_REGISTERS) + logerror("%s:banshee_vga_r(%X)\n", machine().describe_context(), 0x300+offset); + break; + + default: + result = v->banshee.vga[offset]; + if (LOG_REGISTERS) + logerror("%s:banshee_vga_r(%X)\n", machine().describe_context(), 0x300+offset); + break; + } + return result; +} + + +READ32_MEMBER( voodoo_banshee_device::banshee_io_r ) +{ + voodoo_state *v = get_safe_token(this); + UINT32 result; + + offset &= 0xff/4; + + /* switch off the offset */ + switch (offset) + { + case io_status: + result = register_r(v, 0); + break; + + case io_dacData: + result = v->fbi.clut[v->banshee.io[io_dacAddr] & 0x1ff] = v->banshee.io[offset]; + if (LOG_REGISTERS) + logerror("%s:banshee_dac_r(%X)\n", machine().describe_context(), v->banshee.io[io_dacAddr] & 0x1ff); + break; + + case io_vgab0: case io_vgab4: case io_vgab8: case io_vgabc: + case io_vgac0: case io_vgac4: case io_vgac8: case io_vgacc: + case io_vgad0: case io_vgad4: case io_vgad8: case io_vgadc: + result = 0; + if (ACCESSING_BITS_0_7) + result |= banshee_vga_r(space, offset*4+0, mem_mask >> 0) << 0; + if (ACCESSING_BITS_8_15) + result |= banshee_vga_r(space, offset*4+1, mem_mask >> 8) << 8; + if (ACCESSING_BITS_16_23) + result |= banshee_vga_r(space, offset*4+2, mem_mask >> 16) << 16; + if (ACCESSING_BITS_24_31) + result |= banshee_vga_r(space, offset*4+3, mem_mask >> 24) << 24; + break; + + default: + result = v->banshee.io[offset]; + if (LOG_REGISTERS) + logerror("%s:banshee_io_r(%s)\n", machine().describe_context(), banshee_io_reg_name[offset]); + break; + } + + return result; +} + + +READ32_MEMBER( voodoo_banshee_device::banshee_rom_r ) +{ + logerror("%s:banshee_rom_r(%X)\n", machine().describe_context(), offset*4); + return 0xffffffff; +} + +static void blit_2d(voodoo_state *v, UINT32 data) +{ + switch (v->banshee.blt_cmd) + { + case 0: // NOP - wait for idle + { + break; + } + + case 1: // Screen-to-screen blit + { + // TODO +#if LOG_BANSHEE_2D + logerror(" blit_2d:screen_to_screen: src X %d, src Y %d\n", data & 0xfff, (data >> 16) & 0xfff); +#endif + break; + } + + case 2: // Screen-to-screen stretch blit + { + fatalerror(" blit_2d:screen_to_screen_stretch: src X %d, src Y %d\n", data & 0xfff, (data >> 16) & 0xfff); + } + + case 3: // Host-to-screen blit + { + UINT32 addr = v->banshee.blt_dst_base; + + addr += (v->banshee.blt_dst_y * v->banshee.blt_dst_stride) + (v->banshee.blt_dst_x * v->banshee.blt_dst_bpp); + +#if LOG_BANSHEE_2D + logerror(" blit_2d:host_to_screen: %08x -> %08x, %d, %d\n", data, addr, v->banshee.blt_dst_x, v->banshee.blt_dst_y); +#endif + + switch (v->banshee.blt_dst_bpp) + { + case 1: + v->fbi.ram[addr+0] = data & 0xff; + v->fbi.ram[addr+1] = (data >> 8) & 0xff; + v->fbi.ram[addr+2] = (data >> 16) & 0xff; + v->fbi.ram[addr+3] = (data >> 24) & 0xff; + v->banshee.blt_dst_x += 4; + break; + case 2: + v->fbi.ram[addr+1] = data & 0xff; + v->fbi.ram[addr+0] = (data >> 8) & 0xff; + v->fbi.ram[addr+3] = (data >> 16) & 0xff; + v->fbi.ram[addr+2] = (data >> 24) & 0xff; + v->banshee.blt_dst_x += 2; + break; + case 3: + v->banshee.blt_dst_x += 1; + break; + case 4: + v->fbi.ram[addr+3] = data & 0xff; + v->fbi.ram[addr+2] = (data >> 8) & 0xff; + v->fbi.ram[addr+1] = (data >> 16) & 0xff; + v->fbi.ram[addr+0] = (data >> 24) & 0xff; + v->banshee.blt_dst_x += 1; + break; + } + + if (v->banshee.blt_dst_x >= v->banshee.blt_dst_width) + { + v->banshee.blt_dst_x = 0; + v->banshee.blt_dst_y++; + } + break; + } + + case 5: // Rectangle fill + { + fatalerror("blit_2d:rectangle_fill: src X %d, src Y %d\n", data & 0xfff, (data >> 16) & 0xfff); + } + + case 6: // Line + { + fatalerror("blit_2d:line: end X %d, end Y %d\n", data & 0xfff, (data >> 16) & 0xfff); + } + + case 7: // Polyline + { + fatalerror("blit_2d:polyline: end X %d, end Y %d\n", data & 0xfff, (data >> 16) & 0xfff); + } + + case 8: // Polygon fill + { + fatalerror("blit_2d:polygon_fill\n"); + } + + default: + { + fatalerror("blit_2d: unknown command %d\n", v->banshee.blt_cmd); + } + } +} + +static INT32 banshee_2d_w(voodoo_state *v, offs_t offset, UINT32 data) +{ + switch (offset) + { + case banshee2D_command: +#if LOG_BANSHEE_2D + logerror(" 2D:command: cmd %d, ROP0 %02X\n", data & 0xf, data >> 24); +#endif + + v->banshee.blt_src_x = v->banshee.blt_regs[banshee2D_srcXY] & 0xfff; + v->banshee.blt_src_y = (v->banshee.blt_regs[banshee2D_srcXY] >> 16) & 0xfff; + v->banshee.blt_src_base = v->banshee.blt_regs[banshee2D_srcBaseAddr] & 0xffffff; + v->banshee.blt_src_stride = v->banshee.blt_regs[banshee2D_srcFormat] & 0x3fff; + v->banshee.blt_src_width = v->banshee.blt_regs[banshee2D_srcSize] & 0xfff; + v->banshee.blt_src_height = (v->banshee.blt_regs[banshee2D_srcSize] >> 16) & 0xfff; + + switch ((v->banshee.blt_regs[banshee2D_srcFormat] >> 16) & 0xf) + { + case 1: v->banshee.blt_src_bpp = 1; break; + case 3: v->banshee.blt_src_bpp = 2; break; + case 4: v->banshee.blt_src_bpp = 3; break; + case 5: v->banshee.blt_src_bpp = 4; break; + case 8: v->banshee.blt_src_bpp = 2; break; + case 9: v->banshee.blt_src_bpp = 2; break; + default: v->banshee.blt_src_bpp = 1; break; + } + + v->banshee.blt_dst_x = v->banshee.blt_regs[banshee2D_dstXY] & 0xfff; + v->banshee.blt_dst_y = (v->banshee.blt_regs[banshee2D_dstXY] >> 16) & 0xfff; + v->banshee.blt_dst_base = v->banshee.blt_regs[banshee2D_dstBaseAddr] & 0xffffff; + v->banshee.blt_dst_stride = v->banshee.blt_regs[banshee2D_dstFormat] & 0x3fff; + v->banshee.blt_dst_width = v->banshee.blt_regs[banshee2D_dstSize] & 0xfff; + v->banshee.blt_dst_height = (v->banshee.blt_regs[banshee2D_dstSize] >> 16) & 0xfff; + + switch ((v->banshee.blt_regs[banshee2D_dstFormat] >> 16) & 0x7) + { + case 1: v->banshee.blt_dst_bpp = 1; break; + case 3: v->banshee.blt_dst_bpp = 2; break; + case 4: v->banshee.blt_dst_bpp = 3; break; + case 5: v->banshee.blt_dst_bpp = 4; break; + default: v->banshee.blt_dst_bpp = 1; break; + } + + v->banshee.blt_cmd = data & 0xf; + break; + + case banshee2D_colorBack: +#if LOG_BANSHEE_2D + logerror(" 2D:colorBack: %08X\n", data); +#endif + v->banshee.blt_regs[banshee2D_colorBack] = data; + break; + + case banshee2D_colorFore: +#if LOG_BANSHEE_2D + logerror(" 2D:colorFore: %08X\n", data); +#endif + v->banshee.blt_regs[banshee2D_colorFore] = data; + break; + + case banshee2D_srcBaseAddr: +#if LOG_BANSHEE_2D + logerror(" 2D:srcBaseAddr: %08X, %s\n", data & 0xffffff, data & 0x80000000 ? "tiled" : "non-tiled"); +#endif + v->banshee.blt_regs[banshee2D_srcBaseAddr] = data; + break; + + case banshee2D_dstBaseAddr: +#if LOG_BANSHEE_2D + logerror(" 2D:dstBaseAddr: %08X, %s\n", data & 0xffffff, data & 0x80000000 ? "tiled" : "non-tiled"); +#endif + v->banshee.blt_regs[banshee2D_dstBaseAddr] = data; + break; + + case banshee2D_srcSize: +#if LOG_BANSHEE_2D + logerror(" 2D:srcSize: %d, %d\n", data & 0xfff, (data >> 16) & 0xfff); +#endif + v->banshee.blt_regs[banshee2D_srcSize] = data; + break; + + case banshee2D_dstSize: +#if LOG_BANSHEE_2D + logerror(" 2D:dstSize: %d, %d\n", data & 0xfff, (data >> 16) & 0xfff); +#endif + v->banshee.blt_regs[banshee2D_dstSize] = data; + break; + + case banshee2D_srcXY: +#if LOG_BANSHEE_2D + logerror(" 2D:srcXY: %d, %d\n", data & 0xfff, (data >> 16) & 0xfff); +#endif + v->banshee.blt_regs[banshee2D_srcXY] = data; + break; + + case banshee2D_dstXY: +#if LOG_BANSHEE_2D + logerror(" 2D:dstXY: %d, %d\n", data & 0xfff, (data >> 16) & 0xfff); +#endif + v->banshee.blt_regs[banshee2D_dstXY] = data; + break; + + case banshee2D_srcFormat: +#if LOG_BANSHEE_2D + logerror(" 2D:srcFormat: str %d, fmt %d, packing %d\n", data & 0x3fff, (data >> 16) & 0xf, (data >> 22) & 0x3); +#endif + v->banshee.blt_regs[banshee2D_srcFormat] = data; + break; + + case banshee2D_dstFormat: +#if LOG_BANSHEE_2D + logerror(" 2D:dstFormat: str %d, fmt %d\n", data & 0x3fff, (data >> 16) & 0xf); +#endif + v->banshee.blt_regs[banshee2D_dstFormat] = data; + break; + + case banshee2D_clip0Min: +#if LOG_BANSHEE_2D + logerror(" 2D:clip0Min: %d, %d\n", data & 0xfff, (data >> 16) & 0xfff); +#endif + v->banshee.blt_regs[banshee2D_clip0Min] = data; + break; + + case banshee2D_clip0Max: +#if LOG_BANSHEE_2D + logerror(" 2D:clip0Max: %d, %d\n", data & 0xfff, (data >> 16) & 0xfff); +#endif + v->banshee.blt_regs[banshee2D_clip0Max] = data; + break; + + case banshee2D_clip1Min: +#if LOG_BANSHEE_2D + logerror(" 2D:clip1Min: %d, %d\n", data & 0xfff, (data >> 16) & 0xfff); +#endif + v->banshee.blt_regs[banshee2D_clip1Min] = data; + break; + + case banshee2D_clip1Max: +#if LOG_BANSHEE_2D + logerror(" 2D:clip1Max: %d, %d\n", data & 0xfff, (data >> 16) & 0xfff); +#endif + v->banshee.blt_regs[banshee2D_clip1Max] = data; + break; + + case banshee2D_rop: +#if LOG_BANSHEE_2D + logerror(" 2D:rop: %d, %d, %d\n", data & 0xff, (data >> 8) & 0xff, (data >> 16) & 0xff); +#endif + v->banshee.blt_regs[banshee2D_rop] = data; + break; + + default: + if (offset >= 0x20 && offset < 0x40) + { + blit_2d(v, data); + } + else if (offset >= 0x40 && offset < 0x80) + { + // TODO: colorPattern + } + break; + } + + + return 1; +} + + + + +WRITE32_MEMBER( voodoo_banshee_device::banshee_agp_w ) +{ + voodoo_state *v = get_safe_token(this); + offset &= 0x1ff/4; + + /* switch off the offset */ + switch (offset) + { + case cmdBaseAddr0: + COMBINE_DATA(&v->banshee.agp[offset]); + v->fbi.cmdfifo[0].base = (data & 0xffffff) << 12; + v->fbi.cmdfifo[0].end = v->fbi.cmdfifo[0].base + (((v->banshee.agp[cmdBaseSize0] & 0xff) + 1) << 12); + break; + + case cmdBaseSize0: + COMBINE_DATA(&v->banshee.agp[offset]); + v->fbi.cmdfifo[0].end = v->fbi.cmdfifo[0].base + (((v->banshee.agp[cmdBaseSize0] & 0xff) + 1) << 12); + v->fbi.cmdfifo[0].enable = (data >> 8) & 1; + v->fbi.cmdfifo[0].count_holes = (~data >> 10) & 1; + break; + + case cmdBump0: + fatalerror("cmdBump0\n"); + + case cmdRdPtrL0: + v->fbi.cmdfifo[0].rdptr = data; + break; + + case cmdAMin0: + v->fbi.cmdfifo[0].amin = data; + break; + + case cmdAMax0: + v->fbi.cmdfifo[0].amax = data; + break; + + case cmdFifoDepth0: + v->fbi.cmdfifo[0].depth = data; + break; + + case cmdHoleCnt0: + v->fbi.cmdfifo[0].holes = data; + break; + + case cmdBaseAddr1: + COMBINE_DATA(&v->banshee.agp[offset]); + v->fbi.cmdfifo[1].base = (data & 0xffffff) << 12; + v->fbi.cmdfifo[1].end = v->fbi.cmdfifo[1].base + (((v->banshee.agp[cmdBaseSize1] & 0xff) + 1) << 12); + break; + + case cmdBaseSize1: + COMBINE_DATA(&v->banshee.agp[offset]); + v->fbi.cmdfifo[1].end = v->fbi.cmdfifo[1].base + (((v->banshee.agp[cmdBaseSize1] & 0xff) + 1) << 12); + v->fbi.cmdfifo[1].enable = (data >> 8) & 1; + v->fbi.cmdfifo[1].count_holes = (~data >> 10) & 1; + break; + + case cmdBump1: + fatalerror("cmdBump1\n"); + + case cmdRdPtrL1: + v->fbi.cmdfifo[1].rdptr = data; + break; + + case cmdAMin1: + v->fbi.cmdfifo[1].amin = data; + break; + + case cmdAMax1: + v->fbi.cmdfifo[1].amax = data; + break; + + case cmdFifoDepth1: + v->fbi.cmdfifo[1].depth = data; + break; + + case cmdHoleCnt1: + v->fbi.cmdfifo[1].holes = data; + break; + + default: + COMBINE_DATA(&v->banshee.agp[offset]); + break; + } + + if (LOG_REGISTERS) + logerror("%s:banshee_w(AGP:%s) = %08X & %08X\n", machine().describe_context(), banshee_agp_reg_name[offset], data, mem_mask); +} + + +WRITE32_MEMBER( voodoo_banshee_device::banshee_w ) +{ + voodoo_state *v = get_safe_token(this); + + /* if we have something pending, flush the FIFOs up to the current time */ + if (v->pci.op_pending) + flush_fifos(v, machine().time()); + + if (offset < 0x80000/4) + banshee_io_w(space, offset, data, mem_mask); + else if (offset < 0x100000/4) + banshee_agp_w(space, offset, data, mem_mask); + else if (offset < 0x200000/4) + logerror("%s:banshee_w(2D:%X) = %08X & %08X\n", machine().describe_context(), (offset*4) & 0xfffff, data, mem_mask); + else if (offset < 0x600000/4) + register_w(v, offset & 0x1fffff/4, data); + else if (offset < 0x800000/4) + logerror("%s:banshee_w(TEX0:%X) = %08X & %08X\n", machine().describe_context(), (offset*4) & 0x1fffff, data, mem_mask); + else if (offset < 0xa00000/4) + logerror("%s:banshee_w(TEX1:%X) = %08X & %08X\n", machine().describe_context(), (offset*4) & 0x1fffff, data, mem_mask); + else if (offset < 0xc00000/4) + logerror("%s:banshee_r(FLASH Bios ROM:%X)\n", machine().describe_context(), (offset*4) & 0x3fffff); + else if (offset < 0x1000000/4) + logerror("%s:banshee_w(YUV:%X) = %08X & %08X\n", machine().describe_context(), (offset*4) & 0x3fffff, data, mem_mask); + else if (offset < 0x2000000/4) + { + lfb_w(v, offset & 0xffffff/4, data, mem_mask); + } else { + logerror("%s:banshee_w Address out of range %08X = %08X & %08X\n", machine().describe_context(), (offset*4), data, mem_mask); + } +} + + +WRITE32_MEMBER( voodoo_banshee_device::banshee_fb_w ) +{ + voodoo_state *v = get_safe_token(this); + UINT32 addr = offset*4; + + /* if we have something pending, flush the FIFOs up to the current time */ + if (v->pci.op_pending) + flush_fifos(v, machine().time()); + + if (offset < v->fbi.lfb_base) + { + if (v->fbi.cmdfifo[0].enable && addr >= v->fbi.cmdfifo[0].base && addr < v->fbi.cmdfifo[0].end) + cmdfifo_w(v, &v->fbi.cmdfifo[0], (addr - v->fbi.cmdfifo[0].base) / 4, data); + else if (v->fbi.cmdfifo[1].enable && addr >= v->fbi.cmdfifo[1].base && addr < v->fbi.cmdfifo[1].end) + cmdfifo_w(v, &v->fbi.cmdfifo[1], (addr - v->fbi.cmdfifo[1].base) / 4, data); + else + { + if (offset*4 <= v->fbi.mask) + COMBINE_DATA(&((UINT32 *)v->fbi.ram)[offset]); + else + logerror("%s:banshee_fb_w Out of bounds (%X) = %08X & %08X\n", machine().describe_context(), offset*4, data, mem_mask); +#if LOG_LFB + logerror("%s:banshee_fb_w(%X) = %08X & %08X\n", machine().describe_context(), offset*4, data, mem_mask); +#endif + } + } + else + lfb_direct_w(v, offset - v->fbi.lfb_base, data, mem_mask); +} + + +WRITE8_MEMBER( voodoo_banshee_device::banshee_vga_w ) +{ + voodoo_state *v = get_safe_token(this); + offset &= 0x1f; + + /* switch off the offset */ + switch (offset + 0x3c0) + { + /* attribute access */ + case 0x3c0: + case 0x3c1: + if (v->banshee.attff == 0) + { + v->banshee.vga[0x3c1 & 0x1f] = data; + if (LOG_REGISTERS) + logerror("%s:banshee_vga_w(%X) = %02X\n", machine().describe_context(), 0x3c0+offset, data); + } + else + { + if (v->banshee.vga[0x3c1 & 0x1f] < ARRAY_LENGTH(v->banshee.att)) + v->banshee.att[v->banshee.vga[0x3c1 & 0x1f]] = data; + if (LOG_REGISTERS) + logerror("%s:banshee_att_w(%X) = %02X\n", machine().describe_context(), v->banshee.vga[0x3c1 & 0x1f], data); + } + v->banshee.attff ^= 1; + break; + + /* Sequencer access */ + case 0x3c5: + if (v->banshee.vga[0x3c4 & 0x1f] < ARRAY_LENGTH(v->banshee.seq)) + v->banshee.seq[v->banshee.vga[0x3c4 & 0x1f]] = data; + if (LOG_REGISTERS) + logerror("%s:banshee_seq_w(%X) = %02X\n", machine().describe_context(), v->banshee.vga[0x3c4 & 0x1f], data); + break; + + /* Graphics controller access */ + case 0x3cf: + if (v->banshee.vga[0x3ce & 0x1f] < ARRAY_LENGTH(v->banshee.gc)) + v->banshee.gc[v->banshee.vga[0x3ce & 0x1f]] = data; + if (LOG_REGISTERS) + logerror("%s:banshee_gc_w(%X) = %02X\n", machine().describe_context(), v->banshee.vga[0x3ce & 0x1f], data); + break; + + /* CRTC access */ + case 0x3d5: + if (v->banshee.vga[0x3d4 & 0x1f] < ARRAY_LENGTH(v->banshee.crtc)) + v->banshee.crtc[v->banshee.vga[0x3d4 & 0x1f]] = data; + if (LOG_REGISTERS) + logerror("%s:banshee_crtc_w(%X) = %02X\n", machine().describe_context(), v->banshee.vga[0x3d4 & 0x1f], data); + break; + + default: + v->banshee.vga[offset] = data; + if (LOG_REGISTERS) + logerror("%s:banshee_vga_w(%X) = %02X\n", machine().describe_context(), 0x3c0+offset, data); + break; + } +} + + +WRITE32_MEMBER( voodoo_banshee_device::banshee_io_w ) +{ + voodoo_state *v = get_safe_token(this); + UINT32 old; + + offset &= 0xff/4; + old = v->banshee.io[offset]; + + /* switch off the offset */ + switch (offset) + { + case io_vidProcCfg: + COMBINE_DATA(&v->banshee.io[offset]); + if ((v->banshee.io[offset] ^ old) & 0x2800) + v->fbi.clut_dirty = TRUE; + if (LOG_REGISTERS) + logerror("%s:banshee_io_w(%s) = %08X & %08X\n", machine().describe_context(), banshee_io_reg_name[offset], data, mem_mask); + break; + + case io_dacData: + COMBINE_DATA(&v->banshee.io[offset]); + if (v->banshee.io[offset] != v->fbi.clut[v->banshee.io[io_dacAddr] & 0x1ff]) + { + v->fbi.clut[v->banshee.io[io_dacAddr] & 0x1ff] = v->banshee.io[offset]; + v->fbi.clut_dirty = TRUE; + } + if (LOG_REGISTERS) + logerror("%s:banshee_dac_w(%X) = %08X & %08X\n", machine().describe_context(), v->banshee.io[io_dacAddr] & 0x1ff, data, mem_mask); + break; + + case io_miscInit0: + COMBINE_DATA(&v->banshee.io[offset]); + v->fbi.yorigin = (data >> 18) & 0xfff; + if (LOG_REGISTERS) + logerror("%s:banshee_io_w(%s) = %08X & %08X\n", machine().describe_context(), banshee_io_reg_name[offset], data, mem_mask); + break; + + case io_vidScreenSize: + if (data & 0xfff) + v->fbi.width = data & 0xfff; + if (data & 0xfff000) + v->fbi.height = (data >> 12) & 0xfff; + /* fall through */ + case io_vidOverlayDudx: + case io_vidOverlayDvdy: + { + /* warning: this is a hack for now! We should really compute the screen size */ + /* from the CRTC registers */ + COMBINE_DATA(&v->banshee.io[offset]); + + int width = v->fbi.width; + int height = v->fbi.height; + + if (v->banshee.io[io_vidOverlayDudx] != 0) + width = (v->fbi.width * v->banshee.io[io_vidOverlayDudx]) / 1048576; + if (v->banshee.io[io_vidOverlayDvdy] != 0) + height = (v->fbi.height * v->banshee.io[io_vidOverlayDvdy]) / 1048576; + + v->screen->set_visible_area(0, width - 1, 0, height - 1); + + adjust_vblank_timer(v); + if (LOG_REGISTERS) + logerror("%s:banshee_io_w(%s) = %08X & %08X\n", machine().describe_context(), banshee_io_reg_name[offset], data, mem_mask); + break; + } + + case io_lfbMemoryConfig: + v->fbi.lfb_base = (data & 0x1fff) << (12-2); + v->fbi.lfb_stride = ((data >> 13) & 7) + 9; + if (LOG_REGISTERS) + logerror("%s:banshee_io_w(%s) = %08X & %08X\n", machine().describe_context(), banshee_io_reg_name[offset], data, mem_mask); + break; + + case io_vgab0: case io_vgab4: case io_vgab8: case io_vgabc: + case io_vgac0: case io_vgac4: case io_vgac8: case io_vgacc: + case io_vgad0: case io_vgad4: case io_vgad8: case io_vgadc: + if (ACCESSING_BITS_0_7) + banshee_vga_w(space, offset*4+0, data >> 0, mem_mask >> 0); + if (ACCESSING_BITS_8_15) + banshee_vga_w(space, offset*4+1, data >> 8, mem_mask >> 8); + if (ACCESSING_BITS_16_23) + banshee_vga_w(space, offset*4+2, data >> 16, mem_mask >> 16); + if (ACCESSING_BITS_24_31) + banshee_vga_w(space, offset*4+3, data >> 24, mem_mask >> 24); + break; + + default: + COMBINE_DATA(&v->banshee.io[offset]); + if (LOG_REGISTERS) + logerror("%s:banshee_io_w(%s) = %08X & %08X\n", machine().describe_context(), banshee_io_reg_name[offset], data, mem_mask); + break; + } +} + + + +/*************************************************************************** + DEVICE INTERFACE +***************************************************************************/ + +/*------------------------------------------------- + device start callback +-------------------------------------------------*/ + +void voodoo_device::common_start_voodoo(UINT8 type) +{ + voodoo_state *v = get_safe_token(this); + const raster_info *info; + void *fbmem, *tmumem[2]; + UINT32 tmumem0, tmumem1; + int val; + + /* validate configuration */ + assert(m_screen != NULL); + assert(m_cputag != NULL); + assert(m_fbmem > 0); + + /* store a pointer back to the device */ + v->device = this; + v->type = type; + + /* copy config data */ + v->freq = clock(); + v->device->m_vblank.resolve(); + v->device->m_stall.resolve(); + + /* create a multiprocessor work queue */ + v->poly = poly_alloc(machine(), 64, sizeof(poly_extra_data), 0); + v->thread_stats = auto_alloc_array(machine(), stats_block, WORK_MAX_THREADS); + + /* create a table of precomputed 1/n and log2(n) values */ + /* n ranges from 1.0000 to 2.0000 */ + for (val = 0; val <= (1 << RECIPLOG_LOOKUP_BITS); val++) + { + UINT32 value = (1 << RECIPLOG_LOOKUP_BITS) + val; + voodoo_reciplog[val*2 + 0] = (1 << (RECIPLOG_LOOKUP_PREC + RECIPLOG_LOOKUP_BITS)) / value; + voodoo_reciplog[val*2 + 1] = (UINT32)(LOGB2((double)value / (double)(1 << RECIPLOG_LOOKUP_BITS)) * (double)(1 << RECIPLOG_LOOKUP_PREC)); + } + + /* create dithering tables */ + for (val = 0; val < 256*16*2; val++) + { + int g = (val >> 0) & 1; + int x = (val >> 1) & 3; + int color = (val >> 3) & 0xff; + int y = (val >> 11) & 3; + + if (!g) + { + dither4_lookup[val] = DITHER_RB(color, dither_matrix_4x4[y * 4 + x]) >> 3; + dither2_lookup[val] = DITHER_RB(color, dither_matrix_2x2[y * 4 + x]) >> 3; + } + else + { + dither4_lookup[val] = DITHER_G(color, dither_matrix_4x4[y * 4 + x]) >> 2; + dither2_lookup[val] = DITHER_G(color, dither_matrix_2x2[y * 4 + x]) >> 2; + } + } + + v->tmu_config = 0x11; // revision 1 + + /* configure type-specific values */ + switch (v->type) + { + case TYPE_VOODOO_1: + v->regaccess = voodoo_register_access; + v->regnames = voodoo_reg_name; + v->alt_regmap = 0; + v->fbi.lfb_stride = 10; + break; + + case TYPE_VOODOO_2: + v->regaccess = voodoo2_register_access; + v->regnames = voodoo_reg_name; + v->alt_regmap = 0; + v->fbi.lfb_stride = 10; + v->tmu_config |= 0x800; + break; + + case TYPE_VOODOO_BANSHEE: + v->regaccess = banshee_register_access; + v->regnames = banshee_reg_name; + v->alt_regmap = 1; + v->fbi.lfb_stride = 11; + break; + + case TYPE_VOODOO_3: + v->regaccess = banshee_register_access; + v->regnames = banshee_reg_name; + v->alt_regmap = 1; + v->fbi.lfb_stride = 11; + break; + + default: + fatalerror("Unsupported voodoo card in voodoo_start!\n"); + } + + /* set the type, and initialize the chip mask */ + device_iterator iter(machine().root_device()); + v->index = 0; + for (device_t *scan = iter.first(); scan != NULL; scan = iter.next()) + if (scan->type() == this->type()) + { + if (scan == this) + break; + v->index++; + } + v->screen = downcast(machine().device(m_screen)); + assert_always(v->screen != NULL, "Unable to find screen attached to voodoo"); + v->cpu = machine().device(m_cputag); + assert_always(v->cpu != NULL, "Unable to find CPU attached to voodoo"); + + if (m_tmumem1 != 0) + v->tmu_config |= 0xc0; // two TMUs + + v->chipmask = 0x01; + v->attoseconds_per_cycle = ATTOSECONDS_PER_SECOND / v->freq; + v->trigger = 51324 + v->index; + + /* build the rasterizer table */ + for (info = predef_raster_table; info->callback; info++) + add_rasterizer(v, info); + + /* set up the PCI FIFO */ + v->pci.fifo.base = v->pci.fifo_mem; + v->pci.fifo.size = 64*2; + v->pci.fifo.in = v->pci.fifo.out = 0; + v->pci.stall_state = NOT_STALLED; + v->pci.continue_timer = machine().scheduler().timer_alloc(FUNC(stall_cpu_callback), v); + + /* allocate memory */ + tmumem0 = m_tmumem0; + tmumem1 = m_tmumem1; + if (v->type <= TYPE_VOODOO_2) + { + /* separate FB/TMU memory */ + fbmem = auto_alloc_array(machine(), UINT8, m_fbmem << 20); + tmumem[0] = auto_alloc_array(machine(), UINT8, m_tmumem0 << 20); + tmumem[1] = (m_tmumem1 != 0) ? auto_alloc_array(machine(), UINT8, m_tmumem1 << 20) : NULL; + } + else + { + /* shared memory */ + tmumem[0] = tmumem[1] = fbmem = auto_alloc_array(machine(), UINT8, m_fbmem << 20); + tmumem0 = m_fbmem; + if (v->type == TYPE_VOODOO_3) + tmumem1 = m_fbmem; + } + + /* set up frame buffer */ + init_fbi(v, &v->fbi, fbmem, m_fbmem << 20); + + /* build shared TMU tables */ + init_tmu_shared(&v->tmushare); + + /* set up the TMUs */ + init_tmu(v, &v->tmu[0], &v->reg[0x100], tmumem[0], tmumem0 << 20); + v->chipmask |= 0x02; + if (tmumem1 != 0) + { + init_tmu(v, &v->tmu[1], &v->reg[0x200], tmumem[1], tmumem1 << 20); + v->chipmask |= 0x04; + v->tmu_config |= 0x40; + } + + /* initialize some registers */ + memset(v->reg, 0, sizeof(v->reg)); + v->pci.init_enable = 0; + v->reg[fbiInit0].u = (1 << 4) | (0x10 << 6); + v->reg[fbiInit1].u = (1 << 1) | (1 << 8) | (1 << 12) | (2 << 20); + v->reg[fbiInit2].u = (1 << 6) | (0x100 << 23); + v->reg[fbiInit3].u = (2 << 13) | (0xf << 17); + v->reg[fbiInit4].u = (1 << 0); + + /* initialize banshee registers */ + memset(v->banshee.io, 0, sizeof(v->banshee.io)); + v->banshee.io[io_pciInit0] = 0x01800040; + v->banshee.io[io_sipMonitor] = 0x40000000; + v->banshee.io[io_lfbMemoryConfig] = 0x000a2200; + v->banshee.io[io_dramInit0] = 0x00579d29; + v->banshee.io[io_dramInit0] |= 0x08000000; // Konami Viper expects 16MBit SGRAMs + v->banshee.io[io_dramInit1] = 0x00f02200; + v->banshee.io[io_tmuGbeInit] = 0x00000bfb; + + /* do a soft reset to reset everything else */ + soft_reset(v); + + /* register for save states */ + init_save_state(this); +} + + + +/*************************************************************************** + COMMAND HANDLERS +***************************************************************************/ + +/*------------------------------------------------- + fastfill - execute the 'fastfill' + command +-------------------------------------------------*/ + +static INT32 fastfill(voodoo_state *v) +{ + int sx = (v->reg[clipLeftRight].u >> 16) & 0x3ff; + int ex = (v->reg[clipLeftRight].u >> 0) & 0x3ff; + int sy = (v->reg[clipLowYHighY].u >> 16) & 0x3ff; + int ey = (v->reg[clipLowYHighY].u >> 0) & 0x3ff; + poly_extent extents[64]; + UINT16 dithermatrix[16]; + UINT16 *drawbuf = NULL; + UINT32 pixels = 0; + int extnum, x, y; + + /* if we're not clearing either, take no time */ + if (!FBZMODE_RGB_BUFFER_MASK(v->reg[fbzMode].u) && !FBZMODE_AUX_BUFFER_MASK(v->reg[fbzMode].u)) + return 0; + + /* are we clearing the RGB buffer? */ + if (FBZMODE_RGB_BUFFER_MASK(v->reg[fbzMode].u)) + { + /* determine the draw buffer */ + int destbuf = (v->type >= TYPE_VOODOO_BANSHEE) ? 1 : FBZMODE_DRAW_BUFFER(v->reg[fbzMode].u); + switch (destbuf) + { + case 0: /* front buffer */ + drawbuf = (UINT16 *)(v->fbi.ram + v->fbi.rgboffs[v->fbi.frontbuf]); + break; + + case 1: /* back buffer */ + drawbuf = (UINT16 *)(v->fbi.ram + v->fbi.rgboffs[v->fbi.backbuf]); + break; + + default: /* reserved */ + break; + } + + /* determine the dither pattern */ + for (y = 0; y < 4; y++) + { + DECLARE_DITHER_POINTERS_NO_DITHER_VAR; + COMPUTE_DITHER_POINTERS_NO_DITHER_VAR(v->reg[fbzMode].u, y); + for (x = 0; x < 4; x++) + { + int r = v->reg[color1].rgb.r; + int g = v->reg[color1].rgb.g; + int b = v->reg[color1].rgb.b; + + APPLY_DITHER(v->reg[fbzMode].u, x, dither_lookup, r, g, b); + dithermatrix[y*4 + x] = (r << 11) | (g << 5) | b; + } + } + } + + /* fill in a block of extents */ + extents[0].startx = sx; + extents[0].stopx = ex; + for (extnum = 1; extnum < ARRAY_LENGTH(extents); extnum++) + extents[extnum] = extents[0]; + + /* iterate over blocks of extents */ + for (y = sy; y < ey; y += ARRAY_LENGTH(extents)) + { + poly_extra_data *extra = (poly_extra_data *)poly_get_extra_data(v->poly); + int count = MIN(ey - y, ARRAY_LENGTH(extents)); + + extra->state = v; + memcpy(extra->dither, dithermatrix, sizeof(extra->dither)); + + pixels += poly_render_triangle_custom(v->poly, drawbuf, global_cliprect, raster_fastfill, y, count, extents); + } + + /* 2 pixels per clock */ + return pixels / 2; +} + + +/*------------------------------------------------- + swapbuffer - execute the 'swapbuffer' + command +-------------------------------------------------*/ + +static INT32 swapbuffer(voodoo_state *v, UINT32 data) +{ + /* set the don't swap value for Voodoo 2 */ + v->fbi.vblank_swap_pending = TRUE; + v->fbi.vblank_swap = (data >> 1) & 0xff; + v->fbi.vblank_dont_swap = (data >> 9) & 1; + + /* if we're not syncing to the retrace, process the command immediately */ + if (!(data & 1)) + { + swap_buffers(v); + return 0; + } + + /* determine how many cycles to wait; we deliberately overshoot here because */ + /* the final count gets updated on the VBLANK */ + return (v->fbi.vblank_swap + 1) * v->freq / 30; +} + + +/*------------------------------------------------- + triangle - execute the 'triangle' + command +-------------------------------------------------*/ + +static INT32 triangle(voodoo_state *v) +{ + int texcount = 0; + UINT16 *drawbuf; + int destbuf; + int pixels; + + g_profiler.start(PROFILER_USER2); + + /* determine the number of TMUs involved */ + texcount = 0; + if (!FBIINIT3_DISABLE_TMUS(v->reg[fbiInit3].u) && FBZCP_TEXTURE_ENABLE(v->reg[fbzColorPath].u)) + { + texcount = 1; + if (v->chipmask & 0x04) + texcount = 2; + } + + /* perform subpixel adjustments */ + if (FBZCP_CCA_SUBPIXEL_ADJUST(v->reg[fbzColorPath].u)) + { + INT32 dx = 8 - (v->fbi.ax & 15); + INT32 dy = 8 - (v->fbi.ay & 15); + + /* adjust iterated R,G,B,A and W/Z */ + v->fbi.startr += (dy * v->fbi.drdy + dx * v->fbi.drdx) >> 4; + v->fbi.startg += (dy * v->fbi.dgdy + dx * v->fbi.dgdx) >> 4; + v->fbi.startb += (dy * v->fbi.dbdy + dx * v->fbi.dbdx) >> 4; + v->fbi.starta += (dy * v->fbi.dady + dx * v->fbi.dadx) >> 4; + v->fbi.startw += (dy * v->fbi.dwdy + dx * v->fbi.dwdx) >> 4; + v->fbi.startz += mul_32x32_shift(dy, v->fbi.dzdy, 4) + mul_32x32_shift(dx, v->fbi.dzdx, 4); + + /* adjust iterated W/S/T for TMU 0 */ + if (texcount >= 1) + { + v->tmu[0].startw += (dy * v->tmu[0].dwdy + dx * v->tmu[0].dwdx) >> 4; + v->tmu[0].starts += (dy * v->tmu[0].dsdy + dx * v->tmu[0].dsdx) >> 4; + v->tmu[0].startt += (dy * v->tmu[0].dtdy + dx * v->tmu[0].dtdx) >> 4; + + /* adjust iterated W/S/T for TMU 1 */ + if (texcount >= 2) + { + v->tmu[1].startw += (dy * v->tmu[1].dwdy + dx * v->tmu[1].dwdx) >> 4; + v->tmu[1].starts += (dy * v->tmu[1].dsdy + dx * v->tmu[1].dsdx) >> 4; + v->tmu[1].startt += (dy * v->tmu[1].dtdy + dx * v->tmu[1].dtdx) >> 4; + } + } + } + + /* wait for any outstanding work to finish */ +// poly_wait(v->poly, "triangle"); + + /* determine the draw buffer */ + destbuf = (v->type >= TYPE_VOODOO_BANSHEE) ? 1 : FBZMODE_DRAW_BUFFER(v->reg[fbzMode].u); + switch (destbuf) + { + case 0: /* front buffer */ + drawbuf = (UINT16 *)(v->fbi.ram + v->fbi.rgboffs[v->fbi.frontbuf]); + v->fbi.video_changed = TRUE; + break; + + case 1: /* back buffer */ + drawbuf = (UINT16 *)(v->fbi.ram + v->fbi.rgboffs[v->fbi.backbuf]); + break; + + default: /* reserved */ + return TRIANGLE_SETUP_CLOCKS; + } + + /* find a rasterizer that matches our current state */ + pixels = triangle_create_work_item(v, drawbuf, texcount); + + /* update stats */ + v->reg[fbiTrianglesOut].u++; + + /* update stats */ + v->stats.total_triangles++; + + g_profiler.stop(); + + /* 1 pixel per clock, plus some setup time */ + if (LOG_REGISTERS) logerror("cycles = %d\n", TRIANGLE_SETUP_CLOCKS + pixels); + return TRIANGLE_SETUP_CLOCKS + pixels; +} + + +/*------------------------------------------------- + begin_triangle - execute the 'beginTri' + command +-------------------------------------------------*/ + +static INT32 begin_triangle(voodoo_state *v) +{ + setup_vertex *sv = &v->fbi.svert[2]; + + /* extract all the data from registers */ + sv->x = v->reg[sVx].f; + sv->y = v->reg[sVy].f; + sv->wb = v->reg[sWb].f; + sv->w0 = v->reg[sWtmu0].f; + sv->s0 = v->reg[sS_W0].f; + sv->t0 = v->reg[sT_W0].f; + sv->w1 = v->reg[sWtmu1].f; + sv->s1 = v->reg[sS_Wtmu1].f; + sv->t1 = v->reg[sT_Wtmu1].f; + sv->a = v->reg[sAlpha].f; + sv->r = v->reg[sRed].f; + sv->g = v->reg[sGreen].f; + sv->b = v->reg[sBlue].f; + + /* spread it across all three verts and reset the count */ + v->fbi.svert[0] = v->fbi.svert[1] = v->fbi.svert[2]; + v->fbi.sverts = 1; + + return 0; +} + + +/*------------------------------------------------- + draw_triangle - execute the 'DrawTri' + command +-------------------------------------------------*/ + +static INT32 draw_triangle(voodoo_state *v) +{ + setup_vertex *sv = &v->fbi.svert[2]; + int cycles = 0; + + /* for strip mode, shuffle vertex 1 down to 0 */ + if (!(v->reg[sSetupMode].u & (1 << 16))) + v->fbi.svert[0] = v->fbi.svert[1]; + + /* copy 2 down to 1 regardless */ + v->fbi.svert[1] = v->fbi.svert[2]; + + /* extract all the data from registers */ + sv->x = v->reg[sVx].f; + sv->y = v->reg[sVy].f; + sv->wb = v->reg[sWb].f; + sv->w0 = v->reg[sWtmu0].f; + sv->s0 = v->reg[sS_W0].f; + sv->t0 = v->reg[sT_W0].f; + sv->w1 = v->reg[sWtmu1].f; + sv->s1 = v->reg[sS_Wtmu1].f; + sv->t1 = v->reg[sT_Wtmu1].f; + sv->a = v->reg[sAlpha].f; + sv->r = v->reg[sRed].f; + sv->g = v->reg[sGreen].f; + sv->b = v->reg[sBlue].f; + + /* if we have enough verts, go ahead and draw */ + if (++v->fbi.sverts >= 3) + cycles = setup_and_draw_triangle(v); + + return cycles; +} + + + +/*************************************************************************** + TRIANGLE HELPERS +***************************************************************************/ + +/*------------------------------------------------- + setup_and_draw_triangle - process the setup + parameters and render the triangle +-------------------------------------------------*/ + +static INT32 setup_and_draw_triangle(voodoo_state *v) +{ + float dx1, dy1, dx2, dy2; + float divisor, tdiv; + + /* grab the X/Ys at least */ + v->fbi.ax = (INT16)(v->fbi.svert[0].x * 16.0f); + v->fbi.ay = (INT16)(v->fbi.svert[0].y * 16.0f); + v->fbi.bx = (INT16)(v->fbi.svert[1].x * 16.0f); + v->fbi.by = (INT16)(v->fbi.svert[1].y * 16.0f); + v->fbi.cx = (INT16)(v->fbi.svert[2].x * 16.0f); + v->fbi.cy = (INT16)(v->fbi.svert[2].y * 16.0f); + + /* compute the divisor */ + divisor = 1.0f / ((v->fbi.svert[0].x - v->fbi.svert[1].x) * (v->fbi.svert[0].y - v->fbi.svert[2].y) - + (v->fbi.svert[0].x - v->fbi.svert[2].x) * (v->fbi.svert[0].y - v->fbi.svert[1].y)); + + /* backface culling */ + if (v->reg[sSetupMode].u & 0x20000) + { + int culling_sign = (v->reg[sSetupMode].u >> 18) & 1; + int divisor_sign = (divisor < 0); + + /* if doing strips and ping pong is enabled, apply the ping pong */ + if ((v->reg[sSetupMode].u & 0x90000) == 0x00000) + culling_sign ^= (v->fbi.sverts - 3) & 1; + + /* if our sign matches the culling sign, we're done for */ + if (divisor_sign == culling_sign) + return TRIANGLE_SETUP_CLOCKS; + } + + /* compute the dx/dy values */ + dx1 = v->fbi.svert[0].y - v->fbi.svert[2].y; + dx2 = v->fbi.svert[0].y - v->fbi.svert[1].y; + dy1 = v->fbi.svert[0].x - v->fbi.svert[1].x; + dy2 = v->fbi.svert[0].x - v->fbi.svert[2].x; + + /* set up R,G,B */ + tdiv = divisor * 4096.0f; + if (v->reg[sSetupMode].u & (1 << 0)) + { + v->fbi.startr = (INT32)(v->fbi.svert[0].r * 4096.0f); + v->fbi.drdx = (INT32)(((v->fbi.svert[0].r - v->fbi.svert[1].r) * dx1 - (v->fbi.svert[0].r - v->fbi.svert[2].r) * dx2) * tdiv); + v->fbi.drdy = (INT32)(((v->fbi.svert[0].r - v->fbi.svert[2].r) * dy1 - (v->fbi.svert[0].r - v->fbi.svert[1].r) * dy2) * tdiv); + v->fbi.startg = (INT32)(v->fbi.svert[0].g * 4096.0f); + v->fbi.dgdx = (INT32)(((v->fbi.svert[0].g - v->fbi.svert[1].g) * dx1 - (v->fbi.svert[0].g - v->fbi.svert[2].g) * dx2) * tdiv); + v->fbi.dgdy = (INT32)(((v->fbi.svert[0].g - v->fbi.svert[2].g) * dy1 - (v->fbi.svert[0].g - v->fbi.svert[1].g) * dy2) * tdiv); + v->fbi.startb = (INT32)(v->fbi.svert[0].b * 4096.0f); + v->fbi.dbdx = (INT32)(((v->fbi.svert[0].b - v->fbi.svert[1].b) * dx1 - (v->fbi.svert[0].b - v->fbi.svert[2].b) * dx2) * tdiv); + v->fbi.dbdy = (INT32)(((v->fbi.svert[0].b - v->fbi.svert[2].b) * dy1 - (v->fbi.svert[0].b - v->fbi.svert[1].b) * dy2) * tdiv); + } + + /* set up alpha */ + if (v->reg[sSetupMode].u & (1 << 1)) + { + v->fbi.starta = (INT32)(v->fbi.svert[0].a * 4096.0f); + v->fbi.dadx = (INT32)(((v->fbi.svert[0].a - v->fbi.svert[1].a) * dx1 - (v->fbi.svert[0].a - v->fbi.svert[2].a) * dx2) * tdiv); + v->fbi.dady = (INT32)(((v->fbi.svert[0].a - v->fbi.svert[2].a) * dy1 - (v->fbi.svert[0].a - v->fbi.svert[1].a) * dy2) * tdiv); + } + + /* set up Z */ + if (v->reg[sSetupMode].u & (1 << 2)) + { + v->fbi.startz = (INT32)(v->fbi.svert[0].z * 4096.0f); + v->fbi.dzdx = (INT32)(((v->fbi.svert[0].z - v->fbi.svert[1].z) * dx1 - (v->fbi.svert[0].z - v->fbi.svert[2].z) * dx2) * tdiv); + v->fbi.dzdy = (INT32)(((v->fbi.svert[0].z - v->fbi.svert[2].z) * dy1 - (v->fbi.svert[0].z - v->fbi.svert[1].z) * dy2) * tdiv); + } + + /* set up Wb */ + tdiv = divisor * 65536.0f * 65536.0f; + if (v->reg[sSetupMode].u & (1 << 3)) + { + v->fbi.startw = v->tmu[0].startw = v->tmu[1].startw = (INT64)(v->fbi.svert[0].wb * 65536.0f * 65536.0f); + v->fbi.dwdx = v->tmu[0].dwdx = v->tmu[1].dwdx = ((v->fbi.svert[0].wb - v->fbi.svert[1].wb) * dx1 - (v->fbi.svert[0].wb - v->fbi.svert[2].wb) * dx2) * tdiv; + v->fbi.dwdy = v->tmu[0].dwdy = v->tmu[1].dwdy = ((v->fbi.svert[0].wb - v->fbi.svert[2].wb) * dy1 - (v->fbi.svert[0].wb - v->fbi.svert[1].wb) * dy2) * tdiv; + } + + /* set up W0 */ + if (v->reg[sSetupMode].u & (1 << 4)) + { + v->tmu[0].startw = v->tmu[1].startw = (INT64)(v->fbi.svert[0].w0 * 65536.0f * 65536.0f); + v->tmu[0].dwdx = v->tmu[1].dwdx = ((v->fbi.svert[0].w0 - v->fbi.svert[1].w0) * dx1 - (v->fbi.svert[0].w0 - v->fbi.svert[2].w0) * dx2) * tdiv; + v->tmu[0].dwdy = v->tmu[1].dwdy = ((v->fbi.svert[0].w0 - v->fbi.svert[2].w0) * dy1 - (v->fbi.svert[0].w0 - v->fbi.svert[1].w0) * dy2) * tdiv; + } + + /* set up S0,T0 */ + if (v->reg[sSetupMode].u & (1 << 5)) + { + v->tmu[0].starts = v->tmu[1].starts = (INT64)(v->fbi.svert[0].s0 * 65536.0f * 65536.0f); + v->tmu[0].dsdx = v->tmu[1].dsdx = ((v->fbi.svert[0].s0 - v->fbi.svert[1].s0) * dx1 - (v->fbi.svert[0].s0 - v->fbi.svert[2].s0) * dx2) * tdiv; + v->tmu[0].dsdy = v->tmu[1].dsdy = ((v->fbi.svert[0].s0 - v->fbi.svert[2].s0) * dy1 - (v->fbi.svert[0].s0 - v->fbi.svert[1].s0) * dy2) * tdiv; + v->tmu[0].startt = v->tmu[1].startt = (INT64)(v->fbi.svert[0].t0 * 65536.0f * 65536.0f); + v->tmu[0].dtdx = v->tmu[1].dtdx = ((v->fbi.svert[0].t0 - v->fbi.svert[1].t0) * dx1 - (v->fbi.svert[0].t0 - v->fbi.svert[2].t0) * dx2) * tdiv; + v->tmu[0].dtdy = v->tmu[1].dtdy = ((v->fbi.svert[0].t0 - v->fbi.svert[2].t0) * dy1 - (v->fbi.svert[0].t0 - v->fbi.svert[1].t0) * dy2) * tdiv; + } + + /* set up W1 */ + if (v->reg[sSetupMode].u & (1 << 6)) + { + v->tmu[1].startw = (INT64)(v->fbi.svert[0].w1 * 65536.0f * 65536.0f); + v->tmu[1].dwdx = ((v->fbi.svert[0].w1 - v->fbi.svert[1].w1) * dx1 - (v->fbi.svert[0].w1 - v->fbi.svert[2].w1) * dx2) * tdiv; + v->tmu[1].dwdy = ((v->fbi.svert[0].w1 - v->fbi.svert[2].w1) * dy1 - (v->fbi.svert[0].w1 - v->fbi.svert[1].w1) * dy2) * tdiv; + } + + /* set up S1,T1 */ + if (v->reg[sSetupMode].u & (1 << 7)) + { + v->tmu[1].starts = (INT64)(v->fbi.svert[0].s1 * 65536.0f * 65536.0f); + v->tmu[1].dsdx = ((v->fbi.svert[0].s1 - v->fbi.svert[1].s1) * dx1 - (v->fbi.svert[0].s1 - v->fbi.svert[2].s1) * dx2) * tdiv; + v->tmu[1].dsdy = ((v->fbi.svert[0].s1 - v->fbi.svert[2].s1) * dy1 - (v->fbi.svert[0].s1 - v->fbi.svert[1].s1) * dy2) * tdiv; + v->tmu[1].startt = (INT64)(v->fbi.svert[0].t1 * 65536.0f * 65536.0f); + v->tmu[1].dtdx = ((v->fbi.svert[0].t1 - v->fbi.svert[1].t1) * dx1 - (v->fbi.svert[0].t1 - v->fbi.svert[2].t1) * dx2) * tdiv; + v->tmu[1].dtdy = ((v->fbi.svert[0].t1 - v->fbi.svert[2].t1) * dy1 - (v->fbi.svert[0].t1 - v->fbi.svert[1].t1) * dy2) * tdiv; + } + + /* draw the triangle */ + v->fbi.cheating_allowed = 1; + return triangle(v); +} + + +/*------------------------------------------------- + triangle_create_work_item - finish triangle + setup and create the work item +-------------------------------------------------*/ + +static INT32 triangle_create_work_item(voodoo_state *v, UINT16 *drawbuf, int texcount) +{ + poly_extra_data *extra = (poly_extra_data *)poly_get_extra_data(v->poly); + raster_info *info = find_rasterizer(v, texcount); + poly_vertex vert[3]; + + /* fill in the vertex data */ + vert[0].x = (float)v->fbi.ax * (1.0f / 16.0f); + vert[0].y = (float)v->fbi.ay * (1.0f / 16.0f); + vert[1].x = (float)v->fbi.bx * (1.0f / 16.0f); + vert[1].y = (float)v->fbi.by * (1.0f / 16.0f); + vert[2].x = (float)v->fbi.cx * (1.0f / 16.0f); + vert[2].y = (float)v->fbi.cy * (1.0f / 16.0f); + + /* fill in the extra data */ + extra->state = v; + extra->info = info; + + /* fill in triangle parameters */ + extra->ax = v->fbi.ax; + extra->ay = v->fbi.ay; + extra->startr = v->fbi.startr; + extra->startg = v->fbi.startg; + extra->startb = v->fbi.startb; + extra->starta = v->fbi.starta; + extra->startz = v->fbi.startz; + extra->startw = v->fbi.startw; + extra->drdx = v->fbi.drdx; + extra->dgdx = v->fbi.dgdx; + extra->dbdx = v->fbi.dbdx; + extra->dadx = v->fbi.dadx; + extra->dzdx = v->fbi.dzdx; + extra->dwdx = v->fbi.dwdx; + extra->drdy = v->fbi.drdy; + extra->dgdy = v->fbi.dgdy; + extra->dbdy = v->fbi.dbdy; + extra->dady = v->fbi.dady; + extra->dzdy = v->fbi.dzdy; + extra->dwdy = v->fbi.dwdy; + + /* fill in texture 0 parameters */ + if (texcount > 0) + { + extra->starts0 = v->tmu[0].starts; + extra->startt0 = v->tmu[0].startt; + extra->startw0 = v->tmu[0].startw; + extra->ds0dx = v->tmu[0].dsdx; + extra->dt0dx = v->tmu[0].dtdx; + extra->dw0dx = v->tmu[0].dwdx; + extra->ds0dy = v->tmu[0].dsdy; + extra->dt0dy = v->tmu[0].dtdy; + extra->dw0dy = v->tmu[0].dwdy; + extra->lodbase0 = prepare_tmu(&v->tmu[0]); + v->stats.texture_mode[TEXMODE_FORMAT(v->tmu[0].reg[textureMode].u)]++; + + /* fill in texture 1 parameters */ + if (texcount > 1) + { + extra->starts1 = v->tmu[1].starts; + extra->startt1 = v->tmu[1].startt; + extra->startw1 = v->tmu[1].startw; + extra->ds1dx = v->tmu[1].dsdx; + extra->dt1dx = v->tmu[1].dtdx; + extra->dw1dx = v->tmu[1].dwdx; + extra->ds1dy = v->tmu[1].dsdy; + extra->dt1dy = v->tmu[1].dtdy; + extra->dw1dy = v->tmu[1].dwdy; + extra->lodbase1 = prepare_tmu(&v->tmu[1]); + v->stats.texture_mode[TEXMODE_FORMAT(v->tmu[1].reg[textureMode].u)]++; + } + } + + /* farm the rasterization out to other threads */ + info->polys++; + return poly_render_triangle(v->poly, drawbuf, global_cliprect, info->callback, 0, &vert[0], &vert[1], &vert[2]); +} + + + +/*************************************************************************** + RASTERIZER MANAGEMENT +***************************************************************************/ + +/*------------------------------------------------- + add_rasterizer - add a rasterizer to our + hash table +-------------------------------------------------*/ + +static raster_info *add_rasterizer(voodoo_state *v, const raster_info *cinfo) +{ + raster_info *info = &v->rasterizer[v->next_rasterizer++]; + int hash = compute_raster_hash(cinfo); + + assert_always(v->next_rasterizer <= MAX_RASTERIZERS, "Out of space for new rasterizers!"); + + /* make a copy of the info */ + *info = *cinfo; + + /* fill in the data */ + info->hits = 0; + info->polys = 0; + info->hash = hash; + + /* hook us into the hash table */ + info->next = v->raster_hash[hash]; + v->raster_hash[hash] = info; + + if (LOG_RASTERIZERS) + printf("Adding rasterizer @ %p : cp=%08X am=%08X %08X fbzM=%08X tm0=%08X tm1=%08X (hash=%d)\n", + (void *)info->callback, + info->eff_color_path, info->eff_alpha_mode, info->eff_fog_mode, info->eff_fbz_mode, + info->eff_tex_mode_0, info->eff_tex_mode_1, hash); + + return info; +} + + +/*------------------------------------------------- + find_rasterizer - find a rasterizer that + matches our current parameters and return + it, creating a new one if necessary +-------------------------------------------------*/ + +static raster_info *find_rasterizer(voodoo_state *v, int texcount) +{ + raster_info *info, *prev = NULL; + raster_info curinfo; + int hash; + + /* build an info struct with all the parameters */ + curinfo.eff_color_path = normalize_color_path(v->reg[fbzColorPath].u); + curinfo.eff_alpha_mode = normalize_alpha_mode(v->reg[alphaMode].u); + curinfo.eff_fog_mode = normalize_fog_mode(v->reg[fogMode].u); + curinfo.eff_fbz_mode = normalize_fbz_mode(v->reg[fbzMode].u); + curinfo.eff_tex_mode_0 = (texcount >= 1) ? normalize_tex_mode(v->tmu[0].reg[textureMode].u) : 0xffffffff; + curinfo.eff_tex_mode_1 = (texcount >= 2) ? normalize_tex_mode(v->tmu[1].reg[textureMode].u) : 0xffffffff; + + /* compute the hash */ + hash = compute_raster_hash(&curinfo); + + /* find the appropriate hash entry */ + for (info = v->raster_hash[hash]; info; prev = info, info = info->next) + if (info->eff_color_path == curinfo.eff_color_path && + info->eff_alpha_mode == curinfo.eff_alpha_mode && + info->eff_fog_mode == curinfo.eff_fog_mode && + info->eff_fbz_mode == curinfo.eff_fbz_mode && + info->eff_tex_mode_0 == curinfo.eff_tex_mode_0 && + info->eff_tex_mode_1 == curinfo.eff_tex_mode_1) + { + /* got it, move us to the head of the list */ + if (prev) + { + prev->next = info->next; + info->next = v->raster_hash[hash]; + v->raster_hash[hash] = info; + } + + /* return the result */ + return info; + } + + /* generate a new one using the generic entry */ + curinfo.callback = (texcount == 0) ? raster_generic_0tmu : (texcount == 1) ? raster_generic_1tmu : raster_generic_2tmu; + curinfo.is_generic = TRUE; + curinfo.display = 0; + curinfo.polys = 0; + curinfo.hits = 0; + curinfo.next = 0; + curinfo.hash = hash; + + return add_rasterizer(v, &curinfo); +} + + +/*------------------------------------------------- + dump_rasterizer_stats - dump statistics on + the current rasterizer usage patterns +-------------------------------------------------*/ + +static void dump_rasterizer_stats(voodoo_state *v) +{ + static UINT8 display_index; + raster_info *cur, *best; + int hash; + + printf("----\n"); + display_index++; + + /* loop until we've displayed everything */ + while (1) + { + best = NULL; + + /* find the highest entry */ + for (hash = 0; hash < RASTER_HASH_SIZE; hash++) + for (cur = v->raster_hash[hash]; cur; cur = cur->next) + if (cur->display != display_index && (best == NULL || cur->hits > best->hits)) + best = cur; + + /* if we're done, we're done */ + if (best == NULL || best->hits == 0) + break; + + /* print it */ + printf("RASTERIZER_ENTRY( 0x%08X, 0x%08X, 0x%08X, 0x%08X, 0x%08X, 0x%08X ) /* %c %2d %8d %10d */\n", + best->eff_color_path, + best->eff_alpha_mode, + best->eff_fog_mode, + best->eff_fbz_mode, + best->eff_tex_mode_0, + best->eff_tex_mode_1, + best->is_generic ? '*' : ' ', + best->hash, + best->polys, + best->hits); + + /* reset */ + best->display = display_index; + } +} + +voodoo_device::voodoo_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + m_fbmem(0), + m_tmumem0(0), + m_tmumem1(0), + m_screen(NULL), + m_cputag(NULL), + m_vblank(*this), + m_stall(*this) +{ + m_token = global_alloc_clear(voodoo_state); +} + +voodoo_device::~voodoo_device() +{ + global_free(m_token); +} + +//------------------------------------------------- +// device_config_complete - perform any +// operations now that the configuration is +// complete +//------------------------------------------------- + +void voodoo_device::device_config_complete() +{ +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void voodoo_device::device_reset() +{ + voodoo_state *v = get_safe_token(this); + soft_reset(v); +} + +//------------------------------------------------- +// device_stop - device-specific stop +//------------------------------------------------- + +void voodoo_device::device_stop() +{ + voodoo_state *v = get_safe_token(this); + + /* release the work queue, ensuring all work is finished */ + if (v->poly != NULL) + poly_free(v->poly); +} + + +const device_type VOODOO_1 = &device_creator; + +voodoo_1_device::voodoo_1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : voodoo_device(mconfig, VOODOO_1, "3dfx Voodoo Graphics", tag, owner, clock, "voodoo_1", __FILE__) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void voodoo_1_device::device_start() +{ + common_start_voodoo(TYPE_VOODOO_1); +} + + +const device_type VOODOO_2 = &device_creator; + +voodoo_2_device::voodoo_2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : voodoo_device(mconfig, VOODOO_2, "3dfx Voodoo 2", tag, owner, clock, "voodoo_2", __FILE__) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void voodoo_2_device::device_start() +{ + common_start_voodoo(TYPE_VOODOO_2); +} + + +const device_type VOODOO_BANSHEE = &device_creator; + +voodoo_banshee_device::voodoo_banshee_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : voodoo_device(mconfig, VOODOO_BANSHEE, "3dfx Voodoo Banshee", tag, owner, clock, "voodoo_banshee", __FILE__) +{ +} + +voodoo_banshee_device::voodoo_banshee_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : voodoo_device(mconfig, type, name, tag, owner, clock, shortname, source) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void voodoo_banshee_device::device_start() +{ + common_start_voodoo(TYPE_VOODOO_BANSHEE); +} + + +const device_type VOODOO_3 = &device_creator; + +voodoo_3_device::voodoo_3_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : voodoo_banshee_device(mconfig, VOODOO_3, "3dfx Voodoo 3", tag, owner, clock, "voodoo_3", __FILE__) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void voodoo_3_device::device_start() +{ + common_start_voodoo(TYPE_VOODOO_3); +} + + + +/*************************************************************************** + GENERIC RASTERIZERS +***************************************************************************/ + +/*------------------------------------------------- + raster_fastfill - per-scanline + implementation of the 'fastfill' command +-------------------------------------------------*/ + +static void raster_fastfill(void *destbase, INT32 y, const poly_extent *extent, const void *extradata, int threadid) +{ + const poly_extra_data *extra = (const poly_extra_data *)extradata; + voodoo_state *v = extra->state; + stats_block *stats = &v->thread_stats[threadid]; + INT32 startx = extent->startx; + INT32 stopx = extent->stopx; + int scry, x; + + /* determine the screen Y */ + scry = y; + if (FBZMODE_Y_ORIGIN(v->reg[fbzMode].u)) + scry = (v->fbi.yorigin - y) & 0x3ff; + + /* fill this RGB row */ + if (FBZMODE_RGB_BUFFER_MASK(v->reg[fbzMode].u)) + { + const UINT16 *ditherow = &extra->dither[(y & 3) * 4]; + UINT64 expanded = *(UINT64 *)ditherow; + UINT16 *dest = (UINT16 *)destbase + scry * v->fbi.rowpixels; + + for (x = startx; x < stopx && (x & 3) != 0; x++) + dest[x] = ditherow[x & 3]; + for ( ; x < (stopx & ~3); x += 4) + *(UINT64 *)&dest[x] = expanded; + for ( ; x < stopx; x++) + dest[x] = ditherow[x & 3]; + stats->pixels_out += stopx - startx; + } + + /* fill this dest buffer row */ + if (FBZMODE_AUX_BUFFER_MASK(v->reg[fbzMode].u) && v->fbi.auxoffs != ~0) + { + UINT16 color = v->reg[zaColor].u; + UINT64 expanded = ((UINT64)color << 48) | ((UINT64)color << 32) | (color << 16) | color; + UINT16 *dest = (UINT16 *)(v->fbi.ram + v->fbi.auxoffs) + scry * v->fbi.rowpixels; + + for (x = startx; x < stopx && (x & 3) != 0; x++) + dest[x] = color; + for ( ; x < (stopx & ~3); x += 4) + *(UINT64 *)&dest[x] = expanded; + for ( ; x < stopx; x++) + dest[x] = color; + } +} + + +/*------------------------------------------------- + generic_0tmu - generic rasterizer for 0 TMUs +-------------------------------------------------*/ + +RASTERIZER(generic_0tmu, 0, v->reg[fbzColorPath].u, v->reg[fbzMode].u, v->reg[alphaMode].u, + v->reg[fogMode].u, 0, 0) + + +/*------------------------------------------------- + generic_1tmu - generic rasterizer for 1 TMU +-------------------------------------------------*/ + +RASTERIZER(generic_1tmu, 1, v->reg[fbzColorPath].u, v->reg[fbzMode].u, v->reg[alphaMode].u, + v->reg[fogMode].u, v->tmu[0].reg[textureMode].u, 0) + + +/*------------------------------------------------- + generic_2tmu - generic rasterizer for 2 TMUs +-------------------------------------------------*/ + +RASTERIZER(generic_2tmu, 2, v->reg[fbzColorPath].u, v->reg[fbzMode].u, v->reg[alphaMode].u, + v->reg[fogMode].u, v->tmu[0].reg[textureMode].u, v->tmu[1].reg[textureMode].u) + + +#else + + + +/*************************************************************************** + GAME-SPECIFIC RASTERIZERS +***************************************************************************/ + +/* blitz ------> fbzColorPath alphaMode fogMode, fbzMode, texMode0, texMode1 */ +RASTERIZER_ENTRY( 0x00000035, 0x00000000, 0x00000000, 0x000B0739, 0x0C261A0F, 0xFFFFFFFF ) /* 284269 914846168 */ +RASTERIZER_ENTRY( 0x00002C35, 0x00515110, 0x00000000, 0x000B07F9, 0x0C261A0F, 0xFFFFFFFF ) /* 485421 440309121 */ +RASTERIZER_ENTRY( 0x00582C35, 0x00515110, 0x00000000, 0x000B0739, 0x0C261ACF, 0xFFFFFFFF ) /* 31606 230753709 */ +RASTERIZER_ENTRY( 0x00582C35, 0x00515110, 0x00000000, 0x000B0739, 0x0C261A0F, 0xFFFFFFFF ) /* 76742 211701679 */ +RASTERIZER_ENTRY( 0x01420039, 0x00000000, 0x00000000, 0x000B073B, 0x0C261ACF, 0xFFFFFFFF ) /* 6188 152109056 */ +RASTERIZER_ENTRY( 0x01420039, 0x00000000, 0x00000000, 0x000B07F9, 0x0C261ACF, 0xFFFFFFFF ) /* 1100 108134400 */ +RASTERIZER_ENTRY( 0x00002C35, 0x00515119, 0x00000000, 0x000B0739, 0x0C261A0F, 0xFFFFFFFF ) /* 6229525 106197740 */ +RASTERIZER_ENTRY( 0x00002C35, 0x00515119, 0x00000000, 0x000B0799, 0x0C261A0F, 0xFFFFFFFF ) /* 905641 75886220 */ +RASTERIZER_ENTRY( 0x00002C35, 0x00515119, 0x00000000, 0x000B07F9, 0x0C261A0F, 0xFFFFFFFF ) /* 205236 53317253 */ +RASTERIZER_ENTRY( 0x01422439, 0x00000000, 0x00000000, 0x000B073B, 0x0C2610C9, 0xFFFFFFFF ) /* 817356 48881349 */ +RASTERIZER_ENTRY( 0x00000035, 0x00000000, 0x00000000, 0x000B07F9, 0x0C261A0F, 0xFFFFFFFF ) /* 37979 41687251 */ +RASTERIZER_ENTRY( 0x00002C35, 0x00515110, 0x00000000, 0x000B0739, 0x0C261A0F, 0xFFFFFFFF ) /* 26014 41183295 */ +RASTERIZER_ENTRY( 0x01420039, 0x00000000, 0x00000000, 0x000B07F9, 0x0C261A0F, 0xFFFFFFFF ) /* 2512 37911104 */ +RASTERIZER_ENTRY( 0x00006136, 0x00515119, 0x00000000, 0x000B07F9, 0x0C261A0F, 0xFFFFFFFF ) /* 28834 15527654 */ +RASTERIZER_ENTRY( 0x00582435, 0x00515110, 0x00000000, 0x000B0739, 0x0C261ACF, 0xFFFFFFFF ) /* 9878 4979429 */ +RASTERIZER_ENTRY( 0x00002C35, 0x00515119, 0x00000000, 0x000B0739, 0x0C261ACF, 0xFFFFFFFF ) /* 199952 4622064 */ +RASTERIZER_ENTRY( 0x00582C35, 0x00515110, 0x00000000, 0x000B0739, 0x0C261AC9, 0xFFFFFFFF ) /* 8672 3676949 */ +RASTERIZER_ENTRY( 0x00582C35, 0x00515010, 0x00000000, 0x000B0739, 0x0C2610CF, 0xFFFFFFFF ) /* 616 2743972 */ +RASTERIZER_ENTRY( 0x01422C39, 0x00045110, 0x00000000, 0x000B0739, 0x0C261A0F, 0xFFFFFFFF ) /* 81380 2494832 */ +//RASTERIZER_ENTRY( 0x00582435, 0x00515110, 0x00000000, 0x000B0739, 0x0C261AC9, 0xFFFFFFFF ) /* 7670 2235587 */ +//RASTERIZER_ENTRY( 0x00592136, 0x00515110, 0x00000000, 0x000B073B, 0x0C261A0F, 0xFFFFFFFF ) /* 210 1639140 */ +//RASTERIZER_ENTRY( 0x00582C35, 0x00515110, 0x00000000, 0x000B073B, 0x0C261A0F, 0xFFFFFFFF ) /* 108 1154736 */ +//RASTERIZER_ENTRY( 0x00002C35, 0x00515110, 0x00000000, 0x000B07F9, 0x0C26180F, 0xFFFFFFFF ) /* 2152 1150842 */ +//RASTERIZER_ENTRY( 0x00592136, 0x00515110, 0x00000000, 0x000B073B, 0x0C261ACF, 0xFFFFFFFF ) /* 152 880560 */ +//RASTERIZER_ENTRY( 0x00008035, 0x00515119, 0x00000000, 0x000B0739, 0x0C261A0F, 0xFFFFFFFF ) /* 90848 805730 */ +//RASTERIZER_ENTRY( 0x00002C35, 0x00515119, 0x00000000, 0x000B07F9, 0x0C261AC9, 0xFFFFFFFF ) /* 2024 571406 */ +//RASTERIZER_ENTRY( 0x00012136, 0x00515110, 0x00000000, 0x000B07F9, 0x0C261A0F, 0xFFFFFFFF ) /* 1792 494592 */ +//RASTERIZER_ENTRY( 0x00000002, 0x00000000, 0x00000000, 0x00000300, 0xFFFFFFFF, 0xFFFFFFFF ) /* 256 161280 */ + +/* blitz99 ----> fbzColorPath alphaMode fogMode, fbzMode, texMode0, texMode1 */ +RASTERIZER_ENTRY( 0x00000035, 0x00000009, 0x00000000, 0x000B0739, 0x0C261A0F, 0xFFFFFFFF ) /* * 6297478 149465839 */ +RASTERIZER_ENTRY( 0x00000035, 0x00000009, 0x00000000, 0x000B0739, 0x0C261ACF, 0xFFFFFFFF ) /* * 210693 6285480 */ +RASTERIZER_ENTRY( 0x01422C39, 0x00045110, 0x00000000, 0x000B073B, 0x0C2610C9, 0xFFFFFFFF ) /* * 20180 2718710 */ +RASTERIZER_ENTRY( 0x00582C35, 0x00515110, 0x00000000, 0x000B073B, 0x0C261ACF, 0xFFFFFFFF ) /* * 360 2425416 */ +RASTERIZER_ENTRY( 0x00002C35, 0x00000009, 0x00000000, 0x000B0739, 0x0C261A0F, 0xFFFFFFFF ) /* * 67059 1480978 */ +RASTERIZER_ENTRY( 0x00008035, 0x00000009, 0x00000000, 0x000B0739, 0x0C261A0F, 0xFFFFFFFF ) /* * 24811 400666 */ +RASTERIZER_ENTRY( 0x01420039, 0x00000000, 0x00000000, 0x000B073B, 0x0C2610C9, 0xFFFFFFFF ) /* * 10304 324468 */ +RASTERIZER_ENTRY( 0x00002C35, 0x00515110, 0x00000000, 0x000B0739, 0x0C261ACF, 0xFFFFFFFF ) /* * 1024 112665 */ + +/* blitz2k ----> fbzColorPath alphaMode fogMode, fbzMode, texMode0, texMode1 */ +RASTERIZER_ENTRY( 0x01420039, 0x00000000, 0x00000000, 0x000B0739, 0x0C261ACF, 0xFFFFFFFF ) /* * 3880 95344128 */ +RASTERIZER_ENTRY( 0x00582C35, 0x00514110, 0x00000000, 0x000B0739, 0x0C261ACF, 0xFFFFFFFF ) /* * 148 1785480 */ +RASTERIZER_ENTRY( 0x01420039, 0x00000000, 0x00000000, 0x000B073B, 0x0C2610CF, 0xFFFFFFFF ) /* * 9976 314244 */ + +/* carnevil ---> fbzColorPath alphaMode fogMode, fbzMode, texMode0, texMode1 */ +RASTERIZER_ENTRY( 0x00002435, 0x00045119, 0x00000000, 0x00030279, 0x0C261A0F, 0xFFFFFFFF ) /* * 492 84128082 */ +RASTERIZER_ENTRY( 0x00002425, 0x00045119, 0x00000000, 0x00030679, 0x0C261A0F, 0xFFFFFFFF ) /* * 1988398 36166780 */ +RASTERIZER_ENTRY( 0x00486116, 0x00045119, 0x00000000, 0x00030279, 0x0C26180F, 0xFFFFFFFF ) /* * 34424 28788847 */ +RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000000, 0x00030679, 0x0C261A0F, 0xFFFFFFFF ) /* * 514 26316800 */ +RASTERIZER_ENTRY( 0x00480015, 0x00045119, 0x00000000, 0x000306F9, 0x0C261AC9, 0xFFFFFFFF ) /* * 7346 18805760 */ +RASTERIZER_ENTRY( 0x00002435, 0x00045119, 0x00000000, 0x000302F9, 0x0C26180F, 0xFFFFFFFF ) /* * 130764 18678972 */ +RASTERIZER_ENTRY( 0x00482415, 0x00045119, 0x00000000, 0x000306F9, 0x0C2618C9, 0xFFFFFFFF ) /* * 7244 12179040 */ +RASTERIZER_ENTRY( 0x00482415, 0x00045119, 0x00000000, 0x000306F9, 0x0C26180F, 0xFFFFFFFF ) /* * 84520 12059721 */ +RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000000, 0x000306F9, 0x0C261AC9, 0xFFFFFFFF ) /* * 21926 11226112 */ +RASTERIZER_ENTRY( 0x00482415, 0x00045119, 0x00000000, 0x00030679, 0x0C2618C9, 0xFFFFFFFF ) /* * 92115 8926536 */ +RASTERIZER_ENTRY( 0x00482415, 0x00045119, 0x00000000, 0x00030279, 0x0C261A0F, 0xFFFFFFFF ) /* * 1730 7629334 */ +RASTERIZER_ENTRY( 0x00002435, 0x00045119, 0x00000000, 0x000B0779, 0x0C26180F, 0xFFFFFFFF ) /* * 37408 5545956 */ +RASTERIZER_ENTRY( 0x00002435, 0x00045119, 0x00000000, 0x00030679, 0x0C26180F, 0xFFFFFFFF ) /* * 26528 4225026 */ +RASTERIZER_ENTRY( 0x00002435, 0x00045119, 0x00000000, 0x000306F9, 0x0C26180F, 0xFFFFFFFF ) /* * 35764 3230884 */ +RASTERIZER_ENTRY( 0x01422409, 0x00045119, 0x00000000, 0x00030679, 0x0C261A0F, 0xFFFFFFFF ) /* * 96020 1226438 */ +RASTERIZER_ENTRY( 0x00482415, 0x00045119, 0x00000000, 0x00030279, 0x0C2618C9, 0xFFFFFFFF ) /* * 1020 574649 */ +RASTERIZER_ENTRY( 0x00482415, 0x00045119, 0x00000000, 0x00030679, 0x0C261A0F, 0xFFFFFFFF ) /* * 360 370008 */ +RASTERIZER_ENTRY( 0x00480015, 0x00045119, 0x00000000, 0x000306F9, 0x0C261A0F, 0xFFFFFFFF ) /* * 576 334404 */ + +/* calspeed ---> fbzColorPath alphaMode fogMode, fbzMode, texMode0, texMode1 */ +RASTERIZER_ENTRY( 0x00002815, 0x00045119, 0x00000001, 0x000B07F9, 0x0C26100F, 0xFFFFFFFF ) /* * 99120 1731923836 */ +RASTERIZER_ENTRY( 0x01022819, 0x00000009, 0x00000001, 0x000B0739, 0x0C26100F, 0xFFFFFFFF ) /* * 9955804 1526119944 */ +RASTERIZER_ENTRY( 0x00002815, 0x00045119, 0x00000001, 0x000B0739, 0x0C26180F, 0xFFFFFFFF ) /* * 1898207 1124776864 */ +RASTERIZER_ENTRY( 0x01022819, 0x00000009, 0x00000001, 0x000B073B, 0x0C26100F, 0xFFFFFFFF ) /* * 3487467 1101663125 */ +RASTERIZER_ENTRY( 0x01022C19, 0x00000009, 0x00000001, 0x000B0739, 0x0C26100F, 0xFFFFFFFF ) /* * 1079277 609256033 */ +RASTERIZER_ENTRY( 0x00002815, 0x00045119, 0x00000001, 0x000A0723, 0x0C261ACF, 0xFFFFFFFF ) /* * 11880 583925760 */ +RASTERIZER_ENTRY( 0x00602819, 0x00045119, 0x00000001, 0x000B07F9, 0x0C26180F, 0xFFFFFFFF ) /* * 63644 582469888 */ +RASTERIZER_ENTRY( 0x01022819, 0x00000009, 0x00000001, 0x000B07F9, 0x0C261A0F, 0xFFFFFFFF ) /* * 22688 556797972 */ +RASTERIZER_ENTRY( 0x00002815, 0x00045119, 0x00000001, 0x000B07F9, 0x0C26180F, 0xFFFFFFFF ) /* * 1360254 417068457 */ +RASTERIZER_ENTRY( 0x00002815, 0x00045119, 0x00000001, 0x000B0739, 0x0C26100F, 0xFFFFFFFF ) /* * 3427489 405421272 */ +RASTERIZER_ENTRY( 0x00002C15, 0x00045119, 0x00000001, 0x000B0739, 0x0C26180F, 0xFFFFFFFF ) /* * 286809 238944049 */ +RASTERIZER_ENTRY( 0x00002815, 0x00045119, 0x00000001, 0x000A0321, 0x0C26180F, 0xFFFFFFFF ) /* * 28160 231084818 */ +RASTERIZER_ENTRY( 0x01022819, 0x00000009, 0x00000001, 0x000B07FB, 0x0C26100F, 0xFFFFFFFF ) /* * 183564 201014424 */ +RASTERIZER_ENTRY( 0x00480015, 0x00045119, 0x00000001, 0x000B0339, 0x0C26100F, 0xFFFFFFFF ) /* * 15275 168207109 */ +RASTERIZER_ENTRY( 0x01022819, 0x00000009, 0x00000001, 0x000B07F9, 0x0C26100F, 0xFFFFFFFF ) /* * 2856 134400000 */ +RASTERIZER_ENTRY( 0x00002815, 0x00045119, 0x00000001, 0x000B0339, 0x0C26180F, 0xFFFFFFFF ) /* * 98551 110417974 */ +RASTERIZER_ENTRY( 0x01022819, 0x00000009, 0x00000001, 0x000B07F9, 0x0C2610CF, 0xFFFFFFFF ) /* * 47040 107360728 */ +RASTERIZER_ENTRY( 0x00480015, 0x00045119, 0x00000001, 0x000B0339, 0x0C26180F, 0xFFFFFFFF ) /* * 13128 86876789 */ +RASTERIZER_ENTRY( 0x01022C19, 0x00000009, 0x00000001, 0x000B073B, 0x0C26100F, 0xFFFFFFFF ) /* * 257515 76329054 */ +RASTERIZER_ENTRY( 0x00002815, 0x00045119, 0x00000001, 0x000B07F9, 0x0C261A0F, 0xFFFFFFFF ) /* * 3934 64958208 */ +//RASTERIZER_ENTRY( 0x00002C15, 0x00045119, 0x00000001, 0x000B07F9, 0x0C26180F, 0xFFFFFFFF ) /* * 77400 63786236 */ +//RASTERIZER_ENTRY( 0x01022C19, 0x00000009, 0x00000001, 0x000B07F9, 0x0C261A0F, 0xFFFFFFFF ) /* * 12500 63151200 */ +//RASTERIZER_ENTRY( 0x0102001A, 0x00045119, 0x00000001, 0x000A0321, 0xFFFFFFFF, 0xFFFFFFFF ) /* * 8764 57629312 */ +//RASTERIZER_ENTRY( 0x00002C15, 0x00045119, 0x00000001, 0x000A0321, 0x0C26180F, 0xFFFFFFFF ) /* * 3257 32708448 */ +//RASTERIZER_ENTRY( 0x00002815, 0x00045119, 0x00000001, 0x000A07E3, 0x0C2610CF, 0xFFFFFFFF ) /* * 28364 31195605 */ +//RASTERIZER_ENTRY( 0x00002C15, 0x00045119, 0x00000001, 0x000B0739, 0x0C26100F, 0xFFFFFFFF ) /* * 409001 30699647 */ +//RASTERIZER_ENTRY( 0x00482C35, 0x00045119, 0x00000001, 0x000A0321, 0x0C26100F, 0xFFFFFFFF ) /* * 17669 11214172 */ +//RASTERIZER_ENTRY( 0x00002C15, 0x00045119, 0x00000001, 0x000B0339, 0x0C26180F, 0xFFFFFFFF ) /* * 5844 6064373 */ +//RASTERIZER_ENTRY( 0x00002C15, 0x00045119, 0x00000001, 0x000B07FB, 0x0C26100F, 0xFFFFFFFF ) /* * 626 4651080 */ +//RASTERIZER_ENTRY( 0x00482C35, 0x00045119, 0x00000001, 0x000A0321, 0x0C26180F, 0xFFFFFFFF ) /* * 5887 2945500 */ +//RASTERIZER_ENTRY( 0x00480015, 0x00045119, 0x00000001, 0x000B0339, 0x0C261A0F, 0xFFFFFFFF ) /* * 1090 2945093 */ +//RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x00000001, 0x000B07F9, 0x0C26180F, 0xFFFFFFFF ) /* * 228 1723908 */ +//RASTERIZER_ENTRY( 0x00002C15, 0x00045119, 0x00000001, 0x000A0321, 0x0C261A0F, 0xFFFFFFFF ) /* * 112 1433600 */ +//RASTERIZER_ENTRY( 0x00002815, 0x00045119, 0x00000001, 0x000B0739, 0x0C261A0F, 0xFFFFFFFF ) /* * 3091 1165805 */ +//RASTERIZER_ENTRY( 0x01022C19, 0x00000009, 0x00000001, 0x000B07FB, 0x0C26100F, 0xFFFFFFFF ) /* * 620 791202 */ + +/* hyprdriv ---> fbzColorPath alphaMode fogMode, fbzMode, texMode0, texMode1 */ +RASTERIZER_ENTRY( 0x01420039, 0x00000000, 0x00000001, 0x000B0739, 0x0C261ACF, 0xFFFFFFFF ) /* * 60860 498565120 */ +RASTERIZER_ENTRY( 0x01420039, 0x00000000, 0x00000001, 0x000B07F9, 0x0C261A0F, 0xFFFFFFFF ) /* * 28688 235012096 */ +RASTERIZER_ENTRY( 0x01420039, 0x00000000, 0x00000001, 0x000B07F9, 0x0C261ACF, 0xFFFFFFFF ) /* * 11844 156499968 */ +RASTERIZER_ENTRY( 0x00580035, 0x00045119, 0x00000001, 0x00030279, 0x0C261A0F, 0xFFFFFFFF ) /* * 175990 146518715 */ +RASTERIZER_ENTRY( 0x00582C35, 0x00515110, 0x00000001, 0x000B0739, 0x0C261ACF, 0xFFFFFFFF ) /* * 2336 114819072 */ +RASTERIZER_ENTRY( 0x00580035, 0x00000000, 0x00000001, 0x000B073B, 0x0C261A1F, 0xFFFFFFFF ) /* * 363325 100404294 */ +RASTERIZER_ENTRY( 0x00582C35, 0x00045110, 0x00000001, 0x000B073B, 0x0C261A0F, 0xFFFFFFFF ) /* * 40918 96318738 */ +RASTERIZER_ENTRY( 0x01420039, 0x00000000, 0x00000001, 0x000B0739, 0x0C26101F, 0xFFFFFFFF ) /* * 54815 94990269 */ +RASTERIZER_ENTRY( 0x01420039, 0x00000000, 0x00000001, 0x000B0739, 0x0C261A1F, 0xFFFFFFFF ) /* * 123032 91652828 */ +RASTERIZER_ENTRY( 0x01422429, 0x00000000, 0x00000001, 0x000B0739, 0x0C261A1F, 0xFFFFFFFF ) /* * 82767 86431997 */ +RASTERIZER_ENTRY( 0x01422429, 0x00000000, 0x00000001, 0x000B0739, 0x0C26101F, 0xFFFFFFFF ) /* * 9874 78101834 */ +RASTERIZER_ENTRY( 0x01422429, 0x00000000, 0x00000001, 0x000B073B, 0x0C261A1F, 0xFFFFFFFF ) /* * 102146 72570879 */ +RASTERIZER_ENTRY( 0x01420039, 0x00000000, 0x00000001, 0x000B073B, 0x0C26100F, 0xFFFFFFFF ) /* * 657804 67229658 */ +RASTERIZER_ENTRY( 0x00580035, 0x00045110, 0x00000001, 0x000B03F9, 0x0C261A0F, 0xFFFFFFFF ) /* * 10428 63173865 */ +RASTERIZER_ENTRY( 0x01422429, 0x00000000, 0x00000001, 0x000B073B, 0x0C261A0F, 0xFFFFFFFF ) /* * 230145 57902926 */ +RASTERIZER_ENTRY( 0x01422C19, 0x00000000, 0x00000001, 0x000B073B, 0x0C261A0F, 0xFFFFFFFF ) /* * 769654 53992486 */ +RASTERIZER_ENTRY( 0x01422C19, 0x00000000, 0x00000001, 0x000B0739, 0x0C26101F, 0xFFFFFFFF ) /* * 85365 51865697 */ +RASTERIZER_ENTRY( 0x00582435, 0x00515110, 0x00000001, 0x000B0739, 0x0C261AC9, 0xFFFFFFFF ) /* * 454674 46165536 */ +RASTERIZER_ENTRY( 0x00580035, 0x00000000, 0x00000001, 0x000B073B, 0x0C26101F, 0xFFFFFFFF ) /* * 101889 33337987 */ +RASTERIZER_ENTRY( 0x00580035, 0x00000000, 0x00000001, 0x000B0739, 0x0C26101F, 0xFFFFFFFF ) /* * 255952 29810993 */ +//RASTERIZER_ENTRY( 0x00582425, 0x00000000, 0x00000001, 0x000B073B, 0x0C261A1F, 0xFFFFFFFF ) /* * 106190 25430383 */ +//RASTERIZER_ENTRY( 0x01420039, 0x00000000, 0x00000001, 0x000B073B, 0x0C261A1F, 0xFFFFFFFF ) /* * 595001 23268601 */ +//RASTERIZER_ENTRY( 0x0142612A, 0x00000000, 0x00000001, 0x000B0739, 0xFFFFFFFF, 0xFFFFFFFF ) /* * 946410 22589110 */ +//RASTERIZER_ENTRY( 0x01420039, 0x00000000, 0x00000001, 0x000B073B, 0x0C261A0F, 0xFFFFFFFF ) /* * 330036 21323230 */ +//RASTERIZER_ENTRY( 0x01422C19, 0x00000000, 0x00000001, 0x000B0739, 0x0C261A1F, 0xFFFFFFFF ) /* * 40089 13470498 */ +//RASTERIZER_ENTRY( 0x01422C19, 0x00000000, 0x00000000, 0x000B073B, 0x0C261A0F, 0xFFFFFFFF ) /* * 90906 12850855 */ +//RASTERIZER_ENTRY( 0x00582C35, 0x00515110, 0x00000001, 0x000B0739, 0x0C261A0F, 0xFFFFFFFF ) /* * 9492 12115280 */ +//RASTERIZER_ENTRY( 0x01420039, 0x00000000, 0x00000001, 0x000B073B, 0x0C26101F, 0xFFFFFFFF ) /* * 453515 12013961 */ +//RASTERIZER_ENTRY( 0x01422C19, 0x00000000, 0x00000001, 0x000B073B, 0x0C261A1F, 0xFFFFFFFF ) /* * 33829 8384312 */ +//RASTERIZER_ENTRY( 0x00580035, 0x00000000, 0x00000001, 0x000B073B, 0x0C26100F, 0xFFFFFFFF ) /* * 83986 7841206 */ +//RASTERIZER_ENTRY( 0x00580035, 0x00045110, 0x00000001, 0x000B0339, 0x0C261A0F, 0xFFFFFFFF ) /* * 42515 7242660 */ +//RASTERIZER_ENTRY( 0x00582425, 0x00000000, 0x00000001, 0x000B0739, 0x0C26100F, 0xFFFFFFFF ) /* * 706 6158684 */ +//RASTERIZER_ENTRY( 0x00582425, 0x00000000, 0x00000001, 0x000B0739, 0x0C26101F, 0xFFFFFFFF ) /* * 62051 5819485 */ +//RASTERIZER_ENTRY( 0x0142612A, 0x00000000, 0x00000000, 0x000B0739, 0xFFFFFFFF, 0xFFFFFFFF ) /* * 135139 5063467 */ +//RASTERIZER_ENTRY( 0x01422429, 0x00000000, 0x00000001, 0x000B073B, 0x0C26100F, 0xFFFFFFFF ) /* * 10359 5135837 */ +//RASTERIZER_ENTRY( 0x01420039, 0x00000000, 0x00000001, 0x000B0739, 0x0C26100F, 0xFFFFFFFF ) /* * 170159 4449246 */ +//RASTERIZER_ENTRY( 0x00582425, 0x00000000, 0x00000001, 0x000B073B, 0x0C26101F, 0xFFFFFFFF ) /* * 19037 4371219 */ +//RASTERIZER_ENTRY( 0x01422429, 0x00000000, 0x00000001, 0x000B073B, 0x0C26101F, 0xFFFFFFFF ) /* * 8963 4352501 */ +//RASTERIZER_ENTRY( 0x01422C39, 0x00045110, 0x00000001, 0x000B073B, 0x0C261A0F, 0xFFFFFFFF ) /* * 47712 4159994 */ +//RASTERIZER_ENTRY( 0x01422C19, 0x00000000, 0x00000000, 0x000B073B, 0x0C261ACF, 0xFFFFFFFF ) /* * 47525 4151435 */ +//RASTERIZER_ENTRY( 0x01422C19, 0x00000000, 0x00000001, 0x000B0739, 0x0C261A0F, 0xFFFFFFFF ) /* * 34980 3794066 */ +//RASTERIZER_ENTRY( 0x0142613A, 0x00045110, 0x00000000, 0x000B0739, 0xFFFFFFFF, 0xFFFFFFFF ) /* * 6540 2358068 */ +//RASTERIZER_ENTRY( 0x0142611A, 0x00045110, 0x00000000, 0x000B0739, 0xFFFFFFFF, 0xFFFFFFFF ) /* * 703308 2096781 */ +//RASTERIZER_ENTRY( 0x00580035, 0x00045110, 0x00000001, 0x000B0339, 0x0C261A1F, 0xFFFFFFFF ) /* * 3963 2079440 */ +//RASTERIZER_ENTRY( 0x01422439, 0x00000000, 0x00000001, 0x000B073B, 0x0C261AC9, 0xFFFFFFFF ) /* * 22866 2008397 */ +//RASTERIZER_ENTRY( 0x01420039, 0x00000000, 0x00000001, 0x000B0739, 0x0C261A0F, 0xFFFFFFFF ) /* * 69705 1673671 */ +//RASTERIZER_ENTRY( 0x01422C19, 0x00000000, 0x00000001, 0x000B073B, 0x0C26100F, 0xFFFFFFFF ) /* * 13366 1575120 */ +//RASTERIZER_ENTRY( 0x0142613A, 0x00000000, 0x00000000, 0x000B0739, 0xFFFFFFFF, 0xFFFFFFFF ) /* * 50625 1408211 */ +//RASTERIZER_ENTRY( 0x0142613A, 0x00045110, 0x00000001, 0x000B0739, 0xFFFFFFFF, 0xFFFFFFFF ) /* * 1244348 1244346 */ +//RASTERIZER_ENTRY( 0x00582425, 0x00000000, 0x00000001, 0x000B073B, 0x0C26100F, 0xFFFFFFFF ) /* * 13791 1222735 */ +//RASTERIZER_ENTRY( 0x00580035, 0x00000000, 0x00000001, 0x000B073B, 0x0C261A0F, 0xFFFFFFFF ) /* * 33064 943590 */ +//RASTERIZER_ENTRY( 0x0142610A, 0x00045110, 0x00000001, 0x000B0739, 0xFFFFFFFF, 0xFFFFFFFF ) /* * 2041 926507 */ +//RASTERIZER_ENTRY( 0x00480019, 0x00045110, 0x00000001, 0x000B073B, 0x0C261A0F, 0xFFFFFFFF ) /* * 2722 453924 */ +//RASTERIZER_ENTRY( 0x00580035, 0x00000000, 0x00000001, 0x000B0739, 0x0C26100F, 0xFFFFFFFF ) /* * 68232 306869 */ +//RASTERIZER_ENTRY( 0x0142611A, 0x00045110, 0x00000001, 0x000B0379, 0xFFFFFFFF, 0xFFFFFFFF ) /* * 7164 269002 */ + +/* mace -------> fbzColorPath alphaMode fogMode, fbzMode, texMode0, texMode1 */ +RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x0824100F, 0xFFFFFFFF ) /* * 7204150 1340201579 */ +RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000000, 0x000B0779, 0x08241ADF, 0xFFFFFFFF ) /* * 15332 1181663232 */ +RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000000, 0x000B0779, 0x082418DF, 0xFFFFFFFF ) /* * 104456 652582379 */ +RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x0824180F, 0xFFFFFFFF ) /* * 488613 368880164 */ +RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x082418CF, 0xFFFFFFFF ) /* * 352924 312417405 */ +RASTERIZER_ENTRY( 0x00480035, 0x00045119, 0x00000000, 0x000B0779, 0x082418DF, 0xFFFFFFFF ) /* * 15024 291762384 */ +RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x082410CF, 0xFFFFFFFF ) /* * 711824 279246170 */ +RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x0824100F, 0xFFFFFFFF ) /* * 735574 171881981 */ +RASTERIZER_ENTRY( 0x00602401, 0x00045119, 0x00000000, 0x000B0779, 0x082418DF, 0xFFFFFFFF ) /* * 943006 154374023 */ +RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x082410CF, 0xFFFFFFFF ) /* * 103877 101077498 */ +RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x0824108F, 0xFFFFFFFF ) /* * 710125 87547221 */ +RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x08241ACF, 0xFFFFFFFF ) /* * 9834 79774966 */ +RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000000, 0x000B0379, 0x082418DF, 0xFFFFFFFF ) /* * 17644 70187036 */ +RASTERIZER_ENTRY( 0x00480035, 0x00045119, 0x00000000, 0x000B0379, 0x082418DF, 0xFFFFFFFF ) /* * 11324 56633925 */ +RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B0379, 0x0824180F, 0xFFFFFFFF ) /* * 96743 40820171 */ +RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B0739, 0x082418CF, 0xFFFFFFFF ) /* * 166053 29100794 */ +RASTERIZER_ENTRY( 0x00482435, 0x00045117, 0x00000000, 0x000B0339, 0x082418CF, 0xFFFFFFFF ) /* * 166053 29100697 */ +RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000001, 0x000B0379, 0x0824188F, 0xFFFFFFFF ) /* * 6723 29076516 */ +RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x0824188F, 0xFFFFFFFF ) /* * 53297 23928976 */ +RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x0824180F, 0xFFFFFFFF ) /* * 10309 19001776 */ +//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0379, 0x0824180F, 0xFFFFFFFF ) /* * 22105 17473157 */ +//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0379, 0x0824188F, 0xFFFFFFFF ) /* * 11304 17236698 */ +//RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000000, 0x000B0779, 0x082410DF, 0xFFFFFFFF ) /* * 1664 17180883 */ +//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x08241A0F, 0xFFFFFFFF ) /* * 148606 12274278 */ +//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x082418CF, 0xFFFFFFFF ) /* * 80692 9248007 */ +//RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000001, 0x000B0739, 0x082418CF, 0xFFFFFFFF ) /* * 37819 8080994 */ +//RASTERIZER_ENTRY( 0x00482435, 0x00045117, 0x00000001, 0x000B0339, 0x082418CF, 0xFFFFFFFF ) /* * 37819 8080969 */ +//RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000001, 0x000B0379, 0x082418DF, 0xFFFFFFFF ) /* * 536 7930305 */ +//RASTERIZER_ENTRY( 0x00482435, 0x00045117, 0x00000000, 0x000B0339, 0x082418CF, 0xFFFFFFFF ) /* * 27601 7905364 */ +//RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B0739, 0x082418CF, 0xFFFFFFFF ) /* * 27601 7905364 */ +//RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B0739, 0x082418CF, 0xFFFFFFFF ) /* * 36314 7667917 */ +//RASTERIZER_ENTRY( 0x00482435, 0x00045117, 0x00000000, 0x000B0339, 0x082418CF, 0xFFFFFFFF ) /* * 36314 7667917 */ +//RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B0739, 0x082418CF, 0xFFFFFFFF ) /* * 31109 6020110 */ +//RASTERIZER_ENTRY( 0x00482435, 0x00045117, 0x00000000, 0x000B0339, 0x082418CF, 0xFFFFFFFF ) /* * 31109 6020110 */ +//RASTERIZER_ENTRY( 0x00482435, 0x00045117, 0x00000000, 0x000B0339, 0x082418CF, 0xFFFFFFFF ) /* * 42689 5959231 */ +//RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B0739, 0x082418CF, 0xFFFFFFFF ) /* * 42689 5959231 */ +//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x0824188F, 0xFFFFFFFF ) /* * 11965 5118044 */ +//RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000001, 0x000B0379, 0x0824180F, 0xFFFFFFFF ) /* * 11923 4662909 */ +//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0379, 0x082410CF, 0xFFFFFFFF ) /* * 4422 4624260 */ +//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0379, 0x0824100F, 0xFFFFFFFF ) /* * 3853 3596375 */ +//RASTERIZER_ENTRY( 0x00480035, 0x00045119, 0x00000001, 0x000B0379, 0x082418DF, 0xFFFFFFFF ) /* * 400 3555759 */ +//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000001, 0x000B0379, 0x0824180F, 0xFFFFFFFF ) /* * 3755 3453084 */ +//RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000001, 0x000B0779, 0x082418DF, 0xFFFFFFFF ) /* * 4170 2425016 */ +//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x0824184F, 0xFFFFFFFF ) /* * 322 2220073 */ +//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0379, 0x082418CF, 0xFFFFFFFF ) /* * 4008 1201335 */ +//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x0824108F, 0xFFFFFFFF ) /* * 13704 883585 */ + +/* sfrush -----> fbzColorPath alphaMode fogMode, fbzMode, texMode0, texMode1 */ +RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x00000000, 0x0824101F ) /* * 590139 246714190 */ +RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x0824101F, 0x0824101F ) /* * 397774 153418144 */ +RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x00000000, 0x082410DF ) /* * 22732 146975666 */ +RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x00000000, 0x0824101F ) /* * 306398 130393278 */ +RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x0824101F, 0x0824101F ) /* * 437743 117403881 */ +RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x0824181F, 0x0824101F ) /* * 66608 109289500 */ +RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x00000000, 0x082410DF ) /* * 19101 92573085 */ +RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x00000000, 0x0824181F ) /* * 258287 78618228 */ +RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x0824181F, 0x0824101F ) /* * 61814 68788856 */ +RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000001, 0x000B0779, 0x082410DF, 0x0824181F ) /* * 149792 61464124 */ +RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x0824181F, 0x0824181F ) /* * 109988 55083276 */ +RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000000, 0x000B0779, 0x08241ADF, 0x00000000 ) /* * 478 46989312 */ +RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000000, 0x000B0779, 0x08241ADF, 0x0824181F ) /* * 468 46006272 */ +RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x00000000, 0x0824181F ) /* * 125204 39023396 */ +RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000000, 0x000B0779, 0x08241ADF, 0x082410DB ) /* * 394 38731776 */ +RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000000, 0x000B0779, 0x082410DF, 0x082410DB ) /* * 12890 36333568 */ +RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B0379, 0x0824101F, 0x0824101F ) /* * 147995 31086325 */ +RASTERIZER_ENTRY( 0x00480035, 0x00045119, 0x00000000, 0x000B077B, 0x00000000, 0x082410DB ) /* * 3576 29294592 */ +RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x0824181F, 0x0824181F ) /* * 76059 29282981 */ +RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000001, 0x000B0779, 0x082418DF, 0x0824101F ) /* * 12632 29173808 */ +//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x00000000, 0x082418DF ) /* * 14040 24318118 */ +//RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000001, 0x000B0379, 0x0824101F, 0x0824101F ) /* * 56586 17643207 */ +//RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000001, 0x000B0779, 0x082418DF, 0x0824181F ) /* * 9130 17277440 */ +//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x082418DF, 0x0824101F ) /* * 66302 17049921 */ +//RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000001, 0x000B0779, 0x082410DF, 0x0824101F ) /* * 64380 16463672 */ +//RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000000, 0x000B0779, 0x082410DF, 0x0824181F ) /* * 152 14942208 */ +//RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000000, 0x000B0779, 0x082418DF, 0x0824101F ) /* * 8748 13810176 */ +//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x082708DF, 0x0824101F ) /* * 216634 10628656 */ +//RASTERIZER_ENTRY( 0x00480035, 0x00045119, 0x00000001, 0x000B077B, 0x00000000, 0x082410DB ) /* * 1282 10502144 */ +//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x082418DF, 0x0824101F ) /* * 74636 9758030 */ +//RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000000, 0x000B0779, 0x082418DF, 0x082410DB ) /* * 58652 9353671 */ +//RASTERIZER_ENTRY( 0x00480035, 0x00045119, 0x00000000, 0x000B0779, 0x082418DF, 0x082410DB ) /* * 5242 8038747 */ +//RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000000, 0x000B077B, 0x082410DB, 0x082410DB ) /* * 11048 7538060 */ +//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x0824101F, 0x0824181F ) /* * 121630 6906591 */ +//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x00000000, 0x082418DF ) /* * 19553 6864245 */ +//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x082418DF, 0x082418DF ) /* * 1287 6648834 */ +//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x082708DF, 0x0824101F ) /* * 197766 6617876 */ +//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x082700DF, 0x0824101F ) /* * 75470 6231739 */ +//RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000001, 0x000B0779, 0x08241ADF, 0x0824101F ) /* * 180 5898240 */ +//RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000001, 0x000B0779, 0x082410DF, 0x082410DB ) /* * 7692 5743360 */ +//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x082418DF, 0x0824181F ) /* * 20128 4980591 */ +//RASTERIZER_ENTRY( 0x00480035, 0x00045119, 0x00000001, 0x000B0779, 0x082418DF, 0x0824181F ) /* * 1144 4685824 */ +//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x082700DF, 0x0824101F ) /* * 72299 4466336 */ +//RASTERIZER_ENTRY( 0x00480035, 0x00045119, 0x00000000, 0x000B0779, 0x082410DF, 0x082410DB ) /* * 3750 4018176 */ +//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x082410DF, 0x082410DF ) /* * 7533 3692141 */ +//RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000001, 0x000B077B, 0x082410DB, 0x0824101F ) /* * 9484 3610674 */ +//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x0824101F, 0x0824181F ) /* * 128660 3216280 */ +//RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000001, 0x000B0779, 0x082418DF, 0x082410DB ) /* * 22214 3172813 */ +//RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000001, 0x000B077B, 0x082410DB, 0x0824181F ) /* * 5094 3099098 */ +//RASTERIZER_ENTRY( 0x00480035, 0x00045119, 0x00000001, 0x000B0779, 0x082418DF, 0x0824101F ) /* * 1954 2850924 */ +//RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000000, 0x000B0779, 0x082418DF, 0x0824181F ) /* * 1542 2434304 */ +//RASTERIZER_ENTRY( 0x00480035, 0x00045119, 0x00000000, 0x000B0779, 0x082418DF, 0x00000000 ) /* * 478 1957888 */ +//RASTERIZER_ENTRY( 0x00480035, 0x00045119, 0x00000000, 0x000B0779, 0x082418DF, 0x0824181F ) /* * 468 1916928 */ +//RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000000, 0x000B077B, 0x082410DB, 0x0824101F ) /* * 11664 1729188 */ +//RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000001, 0x000B077B, 0x082410DB, 0x082410DB ) /* * 1282 1640960 */ +//RASTERIZER_ENTRY( 0x00480035, 0x00045119, 0x00000001, 0x000B077B, 0x082410DB, 0x0824101F ) /* * 388 1589248 */ +//RASTERIZER_ENTRY( 0x00480035, 0x00045119, 0x00000001, 0x000B0779, 0x082410DF, 0x082410DB ) /* * 1282 1312768 */ +//RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000000, 0x000B077B, 0x082410DB, 0x0824181F ) /* * 3928 1046582 */ + +/* vaportrx ---> fbzColorPath alphaMode fogMode, fbzMode, texMode0, texMode1 */ +RASTERIZER_ENTRY( 0x00482405, 0x00000000, 0x00000000, 0x000B0739, 0x0C26100F, 0xFFFFFFFF ) /* * 2226138 592165102 */ +RASTERIZER_ENTRY( 0x00482435, 0x00000000, 0x00000000, 0x000B0739, 0x0C261A0F, 0xFFFFFFFF ) /* * 53533 281405105 */ +RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B07F9, 0x0C261ACF, 0xFFFFFFFF ) /* * 314131 219103141 */ +RASTERIZER_ENTRY( 0x00482405, 0x00045119, 0x00000000, 0x000B0339, 0x0C261A0F, 0xFFFFFFFF ) /* * 216329 95014510 */ +RASTERIZER_ENTRY( 0x00482405, 0x00000009, 0x00000000, 0x000B0739, 0x0C26100F, 0xFFFFFFFF ) /* * 317128 92010096 */ +RASTERIZER_ENTRY( 0x0142613A, 0x00045119, 0x00000000, 0x000B07F9, 0xFFFFFFFF, 0xFFFFFFFF ) /* * 13728 88595930 */ +RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B0339, 0x0C261ACF, 0xFFFFFFFF ) /* * 649448 81449105 */ +RASTERIZER_ENTRY( 0x00482435, 0x00000000, 0x00000000, 0x000B0739, 0x0C26100F, 0xFFFFFFFF ) /* * 444231 60067944 */ +RASTERIZER_ENTRY( 0x00482405, 0x00045119, 0x00000000, 0x000B0339, 0x0C26184F, 0xFFFFFFFF ) /* * 36057 58970468 */ +RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B0339, 0x0C26100F, 0xFFFFFFFF ) /* * 53147 48856709 */ +RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B07F9, 0x0C2610C9, 0xFFFFFFFF ) /* * 447654 47171792 */ +RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B0339, 0x0C261A0F, 0xFFFFFFFF ) /* * 207392 38933691 */ +RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B0739, 0x0C2610CF, 0xFFFFFFFF ) /* * 2015632 33364173 */ +RASTERIZER_ENTRY( 0x00482405, 0x00045119, 0x00000000, 0x000B0339, 0x0C26100F, 0xFFFFFFFF ) /* * 196361 30395218 */ +RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B0339, 0x0C2610CF, 0xFFFFFFFF ) /* * 110898 28973006 */ +RASTERIZER_ENTRY( 0x00482435, 0x00000009, 0x00000000, 0x000B0739, 0x0C26100F, 0xFFFFFFFF ) /* * 135107 16301589 */ +RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B0339, 0x0C261A8F, 0xFFFFFFFF ) /* * 22375 15797748 */ +RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B0339, 0x0C26184F, 0xFFFFFFFF ) /* * 141539 7513140 */ +RASTERIZER_ENTRY( 0x0142613A, 0x00045119, 0x00000000, 0x000B0739, 0xFFFFFFFF, 0xFFFFFFFF ) /* * 621403 5369705 */ +RASTERIZER_ENTRY( 0x00482435, 0x00045110, 0x00000000, 0x000B0739, 0x0C261A0F, 0xFFFFFFFF ) /* * 30443 4070277 */ +//RASTERIZER_ENTRY( 0x00482405, 0x00045110, 0x00000000, 0x000B0739, 0x0C261A0F, 0xFFFFFFFF ) /* * 22121 3129894 */ +//RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B0739, 0x0C26100F, 0xFFFFFFFF ) /* * 9187 1864599 */ +//RASTERIZER_ENTRY( 0x00482405, 0x00044110, 0x00000000, 0x000B0739, 0x0C2610CF, 0xFFFFFFFF ) /* * 10390 1694950 */ +//RASTERIZER_ENTRY( 0x0142610A, 0x00000009, 0x00000000, 0x000B0739, 0xFFFFFFFF, 0xFFFFFFFF ) /* * 25366 1624563 */ +//RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B0739, 0x0C261A0F, 0xFFFFFFFF ) /* * 69033 1607970 */ +//RASTERIZER_ENTRY( 0x0142610A, 0x00000000, 0x00000000, 0x000B0739, 0xFFFFFFFF, 0xFFFFFFFF ) /* * 36316 1084818 */ +//RASTERIZER_ENTRY( 0x00482405, 0x00045119, 0x00000000, 0x000B0339, 0x0C2610CF, 0xFFFFFFFF ) /* * 1813 816763 */ +//RASTERIZER_ENTRY( 0x0142613A, 0x00045119, 0x00000000, 0x000B0339, 0xFFFFFFFF, 0xFFFFFFFF ) /* * 6602 767221 */ +//RASTERIZER_ENTRY( 0x00482435, 0x00045110, 0x00000000, 0x000B0739, 0x0C26100F, 0xFFFFFFFF ) /* * 2547 646048 */ +//RASTERIZER_ENTRY( 0x00482405, 0x00045119, 0x00000000, 0x000B0339, 0x0C261A8F, 0xFFFFFFFF ) /* * 2394 501590 */ +//RASTERIZER_ENTRY( 0x0142613A, 0x00000009, 0x00000000, 0x000B0739, 0xFFFFFFFF, 0xFFFFFFFF ) /* * 14078 440086 */ +//RASTERIZER_ENTRY( 0x0142610A, 0x00045119, 0x00000000, 0x000B0339, 0xFFFFFFFF, 0xFFFFFFFF ) /* * 9877 429160 */ +//RASTERIZER_ENTRY( 0x00482405, 0x00045119, 0x00000000, 0x000B0339, 0x0C261ACF, 0xFFFFFFFF ) /* * 3222 366052 */ +//RASTERIZER_ENTRY( 0x00482435, 0x00000009, 0x00000000, 0x000B0739, 0x0C2610CF, 0xFFFFFFFF ) /* * 5942 285657 */ +//RASTERIZER_ENTRY( 0x00482405, 0x00044119, 0x00000000, 0x000B0339, 0x0C2610CF, 0xFFFFFFFF ) /* * 2328 239688 */ +//RASTERIZER_ENTRY( 0x00482405, 0x00045119, 0x00000000, 0x000B0739, 0x0C26100F, 0xFFFFFFFF ) /* * 1129 208448 */ + +/* wg3dh ------> fbzColorPath alphaMode fogMode, fbzMode, texMode0, texMode1 */ +RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000000, 0x000B0779, 0x0824181F, 0xFFFFFFFF ) /* * 127676 116109477 */ +RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000000, 0x000B0779, 0x0824189F, 0xFFFFFFFF ) /* * 96310 112016758 */ +RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000000, 0x000B0779, 0x0824109F, 0xFFFFFFFF ) /* * 1412831 108682642 */ +RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000000, 0x000B0779, 0x0824101F, 0xFFFFFFFF ) /* * 1612798 45952714 */ +RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000000, 0x000B0779, 0x08241AD9, 0xFFFFFFFF ) /* * 5960 6103040 */ +RASTERIZER_ENTRY( 0x00002435, 0x00045119, 0x00000000, 0x000B0779, 0x082418DF, 0xFFFFFFFF ) /* * 56512 4856542 */ +RASTERIZER_ENTRY( 0x00480035, 0x00045119, 0x00000000, 0x000B0779, 0x0824109F, 0xFFFFFFFF ) /* * 8480 2045940 */ +RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000000, 0x000B0379, 0x0824181F, 0xFFFFFFFF ) /* * 2779 1994317 */ +RASTERIZER_ENTRY( 0x00000035, 0x00045119, 0x00000000, 0x000B0779, 0x0824105F, 0xFFFFFFFF ) /* * 154691 1922774 */ +RASTERIZER_ENTRY( 0x00002435, 0x00045119, 0x00000000, 0x000B0779, 0x082410DF, 0xFFFFFFFF ) /* * 18114 776139 */ + +/* gauntleg ---> fbzColorPath alphaMode fogMode, fbzMode, texMode0, texMode1 */ +RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x00000000, 0x000B0779, 0x00000000, 0x0C24100F ) /* * 157050 668626339 */ +RASTERIZER_ENTRY( 0x00600039, 0x00045119, 0x00000000, 0x000B0779, 0x0C22400F, 0x0C241ACF ) /* * 1079126 580272490 */ +RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B0779, 0x0C241A4F, 0x0C24100F ) /* * 49686 232178144 */ +RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B0779, 0x0C24104F, 0x0C24100F ) /* * 1048560 206304396 */ +RASTERIZER_ENTRY( 0x00600039, 0x00045119, 0x00000000, 0x000B0779, 0x0C2240CF, 0x0C241ACF ) /* * 59176 182444375 */ +RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B0779, 0x00000000, 0x0C241A4F ) /* * 66342 179689728 */ +RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x00000000, 0x000B0779, 0x0C24180F, 0x0C24180F ) /* * 72264 109413344 */ +RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x00000000, 0x000B0779, 0x0C24100F, 0x0C24100F ) /* * 281243 75399210 */ +RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B0779, 0x00000000, 0x0C24104F ) /* * 126384 68412120 */ +RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x0C241A0F, 0x0C24100F ) /* * 26864 43754988 */ +RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B0779, 0x00000000, 0x0C241ACF ) /* * 30510 32759936 */ +RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x00000000, 0x000B0779, 0x0C24180F, 0x0C24100F ) /* * 44783 31884168 */ +RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x00000000, 0x000B0779, 0x00000000, 0x0C24180F ) /* * 34946 31359362 */ +RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x00000000, 0x0C241ACF ) /* * 8006 28367999 */ +RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x00000000, 0x000B0379, 0x0C24180F, 0x0C24180F ) /* * 15430 27908213 */ +RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x00000000, 0x0C241A0F ) /* * 29306 25166802 */ +RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x00000000, 0x000B0779, 0x0C24180F, 0x0C241ACF ) /* * 27737 24517949 */ +RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x0C241ACF, 0x0C24100F ) /* * 6783 21292092 */ +RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x00000000, 0x000B0379, 0x00000000, 0x0C24180F ) /* * 9591 17815763 */ +RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x00000000, 0x000B0779, 0x0C24100F, 0x0C24180F ) /* * 343966 13864759 */ +//RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B0779, 0x0C241ACF, 0x0C24100F ) /* * 11842 12126208 */ +//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x0C241A8F, 0x0C24100F ) /* * 6648 9788508 */ +//RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B0779, 0x00000000, 0x0C2418CF ) /* * 8444 8646656 */ +//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0379, 0x0C24180F, 0x0C24100F ) /* * 9677 8365606 */ +//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x0C24100F, 0x0C24100F ) /* * 844920 8289326 */ +//RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B0779, 0x00000000, 0x0C24184F ) /* * 3108 8010176 */ +//RASTERIZER_ENTRY( 0x00600039, 0x00045119, 0x00000000, 0x000B03F9, 0x00000000, 0x0C24180F ) /* * 1435 6209238 */ +//RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x00000000, 0x000B0379, 0x0C24180F, 0x0C24100F ) /* * 5754 5617499 */ +//RASTERIZER_ENTRY( 0x00600039, 0x00045119, 0x00000000, 0x000B0379, 0x0C24180F, 0x0C24180F ) /* * 1608 5557253 */ +//RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x00000000, 0x000B0779, 0x0C24100F, 0x0C241ACF ) /* * 105127 5133321 */ +//RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x00000000, 0x000B0379, 0x0C24180F, 0x0C241ACF ) /* * 3460 4689138 */ +//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x0C24180F, 0x0C24100F ) /* * 7025 4629550 */ +//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x00000000, 0x0C24180F ) /* * 7164 4407683 */ +//RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x00000000, 0x000B0779, 0x00000000, 0x0C24188F ) /* * 1922 3924179 */ +//RASTERIZER_ENTRY( 0x00600039, 0x00045119, 0x00000000, 0x000B0779, 0x00000000, 0x0C24180F ) /* * 4116 3733777 */ +//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x00000000, 0x0C241A8F ) /* * 2626 3732809 */ +//RASTERIZER_ENTRY( 0x00600039, 0x00045119, 0x00000000, 0x000B03F9, 0x0C24180F, 0x0C24180F ) /* * 778 3202973 */ +//RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x00000000, 0x000B0779, 0x0C24184F, 0x0C24100F ) /* * 1525 2997446 */ +//RASTERIZER_ENTRY( 0x00600039, 0x00045119, 0x00000000, 0x000B03F9, 0x0C24180F, 0x0C241A0F ) /* * 645 2975266 */ +//RASTERIZER_ENTRY( 0x00600039, 0x00044119, 0x00000000, 0x000B0379, 0x00000000, 0x0C241A0F ) /* * 5212 2491361 */ +//RASTERIZER_ENTRY( 0x00600039, 0x00045119, 0x00000000, 0x000B0379, 0x00000000, 0x0C24180F ) /* * 825 1996513 */ +//RASTERIZER_ENTRY( 0x00600039, 0x00045119, 0x00000000, 0x000B0379, 0x0C24180F, 0x0C241A0F ) /* * 466 1967163 */ +//RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x00000000, 0x000B0779, 0x0580000F, 0x0C24180F ) /* * 77400 1883434 */ +//RASTERIZER_ENTRY( 0x00600039, 0x00045119, 0x00000000, 0x000B0379, 0x0C24180F, 0x0C24100F ) /* * 472 1698177 */ +//RASTERIZER_ENTRY( 0x00600039, 0x00045119, 0x00000000, 0x000B0779, 0x0C24180F, 0x0C24180F ) /* * 2476 1678760 */ +//RASTERIZER_ENTRY( 0x00600C09, 0x00045119, 0x00000000, 0x000B0379, 0x00000000, 0x0C24180F ) /* * 4054 1541748 */ +//RASTERIZER_ENTRY( 0x00600039, 0x00044119, 0x00000000, 0x000B0379, 0x0C241A0F, 0x0C24180F ) /* * 3132 1509438 */ +//RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x00000000, 0x000B0779, 0x0580080F, 0x0C24180F ) /* * 8582 1324196 */ +//RASTERIZER_ENTRY( 0x00602C19, 0x00044119, 0x00000000, 0x000B0379, 0x00000000, 0x0C24100F ) /* * 1436 1239704 */ +//RASTERIZER_ENTRY( 0x00600039, 0x00045119, 0x00000000, 0x000B03F9, 0x0C24180F, 0x0C24100F ) /* * 253 1220316 */ +//RASTERIZER_ENTRY( 0x00600039, 0x00045119, 0x00000000, 0x000B0779, 0x0C22480F, 0x0C241ACF ) /* * 2433 1014668 */ + +/* gauntdl ----> fbzColorPath alphaMode fogMode, fbzMode, texMode0, texMode1 */ +RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x000000C1, 0x000B0779, 0x00000009, 0x0C241ACF ) /* * 30860 1128173568 */ +RASTERIZER_ENTRY( 0x0060743A, 0x00045119, 0x000000C1, 0x000B0779, 0x0C22400F, 0x0C241ACF ) /* * 2631692 1117011118 */ +RASTERIZER_ENTRY( 0x0060743A, 0x00045110, 0x000000C1, 0x000B0779, 0x0C22400F, 0x0C241ACF ) /* * 2429239 826969012 */ +RASTERIZER_ENTRY( 0x0060743A, 0x00045119, 0x000000C1, 0x000B0779, 0x0C22480F, 0x0C241ACF ) /* * 454056 468285142 */ +RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x000000C1, 0x000B0779, 0x00000009, 0x0C2418CF ) /* * 257586 355634672 */ +RASTERIZER_ENTRY( 0x00602439, 0x00045119, 0x000000C1, 0x000B0379, 0x00000009, 0x0C24180F ) /* * 10898 134362122 */ +RASTERIZER_ENTRY( 0x00602439, 0x00045119, 0x000000C1, 0x000B0779, 0x00000009, 0x0C241A0F ) /* * 32195 126327049 */ +RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x000000C1, 0x000B0779, 0x0C2410CF, 0x0C24100F ) /* * 855240 123899880 */ +RASTERIZER_ENTRY( 0x00602439, 0x00045110, 0x000000C1, 0x000B0379, 0x00000009, 0x0C24180F ) /* * 1718 120629204 */ +RASTERIZER_ENTRY( 0x0060743A, 0x00045119, 0x000000C1, 0x000B0779, 0x0C22488F, 0x0C241ACF ) /* * 186839 120281357 */ +RASTERIZER_ENTRY( 0x0060743A, 0x00045119, 0x000000C1, 0x000B0379, 0x0C22480F, 0x0C241ACF ) /* * 14102 115428820 */ +RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x000000C1, 0x000B0779, 0x00000009, 0x0C2410CF ) /* * 88530 98271949 */ +RASTERIZER_ENTRY( 0x0060743A, 0x00045110, 0x000000C1, 0x000B0379, 0x0C22480F, 0x0C241ACF ) /* * 12994 68053222 */ +RASTERIZER_ENTRY( 0x00602439, 0x00044110, 0x00000000, 0x000B0379, 0x00000009, 0x0C24100F ) /* * 68273 67454880 */ +RASTERIZER_ENTRY( 0x00602439, 0x00045119, 0x000000C1, 0x000B0779, 0x00000009, 0x0C24180F ) /* * 100026 62271618 */ +RASTERIZER_ENTRY( 0x0060743A, 0x00045110, 0x000000C1, 0x000B0779, 0x0C22480F, 0x0C241ACF ) /* * 153285 44411342 */ +RASTERIZER_ENTRY( 0x00602439, 0x00045119, 0x000000C1, 0x000B0779, 0x00000009, 0x0C24100F ) /* * 157545 40702131 */ +RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x000000C1, 0x000B0779, 0x0C241ACF, 0x0C24100F ) /* * 7800 31948800 */ +RASTERIZER_ENTRY( 0x0060743A, 0x00045110, 0x000000C1, 0x000B0779, 0x0C22408F, 0x0C241ACF ) /* * 47623 20321183 */ +RASTERIZER_ENTRY( 0x00602439, 0x00044119, 0x00000000, 0x000B0379, 0x00000009, 0x0C24188F ) /* * 21570 19324892 */ +//RASTERIZER_ENTRY( 0x00482435, 0x00045110, 0x000000C1, 0x000B0779, 0x0C241ACF, 0x0C24100F ) /* * 3698 15147008 */ +//RASTERIZER_ENTRY( 0x0060743A, 0x00045119, 0x000000C1, 0x000B0779, 0x0C22408F, 0x0C241ACF ) /* * 19765 12383722 */ +//RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x000000C1, 0x000B0779, 0x0C24100F, 0x0C241ACF ) /* * 662274 10563855 */ +//RASTERIZER_ENTRY( 0x00602439, 0x00045110, 0x000000C1, 0x000B0779, 0x0C24180F, 0x0C241ACF ) /* * 27909 10462997 */ +//RASTERIZER_ENTRY( 0x00602439, 0x00045110, 0x000000C1, 0x000B0779, 0x00000009, 0x0C24180F ) /* * 78671 10286957 */ +//RASTERIZER_ENTRY( 0x00602439, 0x00045110, 0x000000C1, 0x000B0779, 0x00000009, 0x0C24188F ) /* * 52038 9928244 */ +//RASTERIZER_ENTRY( 0x0060743A, 0x00045119, 0x000000C1, 0x000B0779, 0x0C224A0F, 0x0C241ACF ) /* * 27469 9239782 */ +//RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x000000C1, 0x000B0779, 0x00000009, 0x0C24100F ) /* * 757116 8072783 */ +//RASTERIZER_ENTRY( 0x0060743A, 0x00045110, 0x000000C1, 0x000B0779, 0x0C22488F, 0x0C241ACF ) /* * 18018 7035833 */ +//RASTERIZER_ENTRY( 0x00602439, 0x00044119, 0x00000000, 0x000B0379, 0x00000009, 0x0C241A0F ) /* * 50339 5976564 */ +//RASTERIZER_ENTRY( 0x00603430, 0x00040219, 0x00000000, 0x000B0379, 0x00000009, 0x0C2410CE ) /* * 29385 5466384 */ +//RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x000000C1, 0x000B0779, 0x0C24100F, 0x0C24180F ) /* * 423347 5355017 */ +//RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x000000C1, 0x000B0779, 0x0C24180F, 0x0C241ACF ) /* * 162620 4709092 */ +//RASTERIZER_ENTRY( 0x00602C19, 0x00045110, 0x000000C1, 0x000B0779, 0x00000009, 0x0C24100F ) /* * 463705 4642480 */ +//RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x000000C1, 0x000B0779, 0x0C24180F, 0x0C24180F ) /* * 280337 4425529 */ +//RASTERIZER_ENTRY( 0x00602C19, 0x00045110, 0x000000C1, 0x000B0779, 0x0C24180F, 0x0C24180F ) /* * 212646 3432265 */ +//RASTERIZER_ENTRY( 0x00482435, 0x00045119, 0x000000C1, 0x000B0779, 0x0C2418CF, 0x0C24100F ) /* * 5788 2963456 */ +//RASTERIZER_ENTRY( 0x00602C19, 0x00045110, 0x000000C1, 0x000B0779, 0x0C24180F, 0x0C24100F ) /* * 460800 2609198 */ +//RASTERIZER_ENTRY( 0x00602439, 0x00045119, 0x000000C1, 0x000B0779, 0x0C24100F, 0x0C24180F ) /* * 251108 2392362 */ +//RASTERIZER_ENTRY( 0x00602C19, 0x00045110, 0x000000C1, 0x000B0779, 0x0C24100F, 0x0C24100F ) /* * 297219 2352862 */ +//RASTERIZER_ENTRY( 0x00602439, 0x00045119, 0x000000C1, 0x000B0779, 0x0584180F, 0x0C2410CF ) /* * 9913 2097069 */ +//RASTERIZER_ENTRY( 0x00602C19, 0x00045110, 0x000000C1, 0x000B0779, 0x0C24180F, 0x0C241ACF ) /* * 142722 2091569 */ +//RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x000000C1, 0x000B0379, 0x0C24180F, 0x0C241ACF ) /* * 8820 2053325 */ +//RASTERIZER_ENTRY( 0x00602439, 0x00045119, 0x000000C1, 0x000B0779, 0x00000009, 0x0C24188F ) /* * 10346 2033427 */ +//RASTERIZER_ENTRY( 0x00602439, 0x00045119, 0x000000C1, 0x000B0779, 0x0C24188F, 0x0C241ACF ) /* * 2136 2017241 */ +//RASTERIZER_ENTRY( 0x00602439, 0x00044119, 0x00000000, 0x000B0379, 0x00000009, 0x0C24100F ) /* * 1505 1928490 */ +//RASTERIZER_ENTRY( 0x00602C19, 0x00045110, 0x000000C1, 0x000B0779, 0x0C24100F, 0x0C241ACF ) /* * 176734 1842440 */ +//RASTERIZER_ENTRY( 0x00602C19, 0x00045110, 0x000000C1, 0x000B0779, 0x0C24100F, 0x0C24180F ) /* * 262577 1799080 */ +//RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x000000C1, 0x000B0779, 0x00000009, 0x0C24180F ) /* * 83179 1534171 */ +//RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x000000C1, 0x000B0779, 0x00000009, 0x0C24188F ) /* * 3863 1527077 */ +//RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x000000C1, 0x000B0379, 0x0C24180F, 0x0C24180F ) /* * 8021 1472661 */ +//RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x000000C1, 0x000B0779, 0x0C241A0F, 0x0C241ACF ) /* * 85416 1342195 */ +//RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x000000C1, 0x000B0779, 0x0C24180F, 0x0C24100F ) /* * 261360 1335048 */ +//RASTERIZER_ENTRY( 0x00602C19, 0x00000009, 0x000000C1, 0x000B0779, 0x0C2418CF, 0x0C24100F ) /* * 74811 1320900 */ +//RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x000000C1, 0x000B0779, 0x0C24100F, 0x0C24100F ) /* * 239331 1268661 */ +//RASTERIZER_ENTRY( 0x00602439, 0x00045119, 0x000000C1, 0x000B0779, 0x0C24100F, 0x0C241ACF ) /* * 107769 1244175 */ +//RASTERIZER_ENTRY( 0x00602C19, 0x00045110, 0x000000C1, 0x000B0379, 0x0C24180F, 0x0C241ACF ) /* * 3706 1216182 */ +//RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x000000C1, 0x000B0779, 0x0C24100F, 0x0C24188F ) /* * 49608 1206129 */ +//RASTERIZER_ENTRY( 0x00602C19, 0x00000009, 0x000000C1, 0x000B0779, 0x0C2418CF, 0x0C241ACF ) /* * 42440 1204109 */ +//RASTERIZER_ENTRY( 0x00482435, 0x00045110, 0x000000C1, 0x000B0779, 0x0C2410CF, 0x0C24100F ) /* * 29584 1168568 */ +//RASTERIZER_ENTRY( 0x00602439, 0x00045119, 0x000000C1, 0x000B0779, 0x0C24180F, 0x0C241ACF ) /* * 17729 1152869 */ +//RASTERIZER_ENTRY( 0x00602C19, 0x00045110, 0x000000C1, 0x000B0379, 0x0C24180F, 0x0C24100F ) /* * 4052 1108726 */ +//RASTERIZER_ENTRY( 0x00602C19, 0x00045119, 0x000000C1, 0x000B0779, 0x0C2418CF, 0x0C24100F ) /* * 7082 1079348 */ +//RASTERIZER_ENTRY( 0x00602439, 0x00044119, 0x00000000, 0x000B0379, 0x00000009, 0x0C24180F ) /* * 7761 1023855 */ + +/* gradius4 ----> fbzColorPath alphaMode fogMode, fbzMode, texMode0, texMode1 */ +//RASTERIZER_ENTRY( 0x02420002, 0x00000009, 0x00000000, 0x00030F7B, 0x08241AC7, 0xFFFFFFFF ) /* intro */ +//RASTERIZER_ENTRY( 0x01420021, 0x00005119, 0x00000000, 0x00030F7B, 0x14261AC7, 0xFFFFFFFF ) /* intro */ +//RASTERIZER_ENTRY( 0x00000005, 0x00005119, 0x00000000, 0x00030F7B, 0x14261A87, 0xFFFFFFFF ) /* in-game */ + +/* nbapbp ------> fbzColorPath alphaMode fogMode, fbzMode, texMode0, texMode1 */ +//RASTERIZER_ENTRY( 0x00424219, 0x00000000, 0x00000001, 0x00030B7B, 0x08241AC7, 0xFFFFFFFF ) /* intro */ +//RASTERIZER_ENTRY( 0x00002809, 0x00004110, 0x00000001, 0x00030FFB, 0x08241AC7, 0xFFFFFFFF ) /* in-game */ +//RASTERIZER_ENTRY( 0x00424219, 0x00000000, 0x00000001, 0x00030F7B, 0x08241AC7, 0xFFFFFFFF ) /* in-game */ +//RASTERIZER_ENTRY( 0x0200421A, 0x00001510, 0x00000001, 0x00030F7B, 0x08241AC7, 0xFFFFFFFF ) /* in-game */ +/* gtfore06 ----> fbzColorPath alphaMode fogMode, fbzMode, texMode0, texMode1 hash */ +RASTERIZER_ENTRY( 0x00482405, 0x00045119, 0x000000C1, 0x00010F79, 0x0C261ACD, 0x0C261ACD ) /* 18 1064626 69362127 */ +RASTERIZER_ENTRY( 0x00002425, 0x00045119, 0x000000C1, 0x00010F79, 0x0C224A0D, 0x0C261ACD ) /* 47 3272483 31242799 */ +RASTERIZER_ENTRY( 0x00482405, 0x00045119, 0x000000C1, 0x00010F79, 0x00000ACD, 0x0C261ACD ) /* 9 221917 12348555 */ +RASTERIZER_ENTRY( 0x00002425, 0x00045110, 0x000000C1, 0x00010FF9, 0x00000ACD, 0x0C261ACD ) /* 26 57291 9357989 */ +RASTERIZER_ENTRY( 0x00002429, 0x00000000, 0x000000C1, 0x00010FF9, 0x00000A09, 0x0C261A0F ) /* 12 97156 8530607 */ +RASTERIZER_ENTRY( 0x00482405, 0x00045119, 0x000000C1, 0x00010F79, 0x000000C4, 0x0C261ACD ) /* 55 110144 5265532 */ +RASTERIZER_ENTRY( 0x00002425, 0x00045110, 0x000000C1, 0x00010FF9, 0x000000C4, 0x0C261ACD ) /* 61 16644 1079382 */ +RASTERIZER_ENTRY( 0x00002425, 0x00045119, 0x000000C1, 0x00010FF9, 0x000000C4, 0x0C261ACD ) /* 5 8332 1065229 */ +RASTERIZER_ENTRY( 0x00002425, 0x00045119, 0x000000C1, 0x00010F79, 0x0C224A0D, 0x0C261A0D ) /* 45 8148 505013 */ +RASTERIZER_ENTRY( 0x00002425, 0x00045119, 0x00000000, 0x00010F79, 0x0C224A0D, 0x0C261A0D ) /* 84 45233 248267 */ +RASTERIZER_ENTRY( 0x00482405, 0x00045119, 0x000000C1, 0x00010F79, 0x0C261ACD, 0x0C2610C4 ) /* 90 10235 193036 */ +RASTERIZER_ENTRY( 0x00482405, 0x00045119, 0x000000C1, 0x00010FF9, 0x0C261ACD, 0x0C261ACD ) /* * 29 3777 83777 */ +RASTERIZER_ENTRY( 0x00482405, 0x00045119, 0x00000000, 0x00010FF9, 0x0C261ACD, 0x042210C0 ) /* 2 24952 66761 */ +RASTERIZER_ENTRY( 0x00002429, 0x00000000, 0x00000000, 0x00010FF9, 0x00000A09, 0x0C261A0F ) /* 24 661 50222 */ +RASTERIZER_ENTRY( 0x00482405, 0x00045119, 0x00000000, 0x00010FF9, 0x0C261ACD, 0x04221AC9 ) /* 92 12504 43720 */ +RASTERIZER_ENTRY( 0x00482405, 0x00045119, 0x000000C1, 0x00010FF9, 0x0C261ACD, 0x0C2610C4 ) /* 79 2160 43650 */ +RASTERIZER_ENTRY( 0x00482405, 0x00045119, 0x00000000, 0x00010FF9, 0x000000C4, 0x04221AC9 ) /* 19 2796 30377 */ +RASTERIZER_ENTRY( 0x00002425, 0x00045119, 0x000000C1, 0x00010FF9, 0x00000ACD, 0x0C261ACD ) /* 67 1962 14755 */ +RASTERIZER_ENTRY( 0x00482405, 0x00045119, 0x000000C1, 0x00010FF9, 0x000000C4, 0x0C261ACD ) /* * 66 74 3951 */ +RASTERIZER_ENTRY( 0x00482405, 0x00045119, 0x00000000, 0x00010FF9, 0x00000ACD, 0x04221AC9 ) /* 70 374 3691 */ +RASTERIZER_ENTRY( 0x00482405, 0x00045119, 0x000000C1, 0x00010FF9, 0x00000ACD, 0x0C261ACD ) /* * 20 350 7928 */ +/* virtpool ----> fbzColorPath alphaMode fogMode, fbzMode, texMode0, texMode1 hash */ +RASTERIZER_ENTRY( 0x00002421, 0x00000000, 0x00000000, 0x000B0739, 0x0C261A0F, 0x042210C0 ) /* * 78 2182388 74854175 */ +RASTERIZER_ENTRY( 0x00002421, 0x00000000, 0x00000000, 0x000B07F9, 0x0C261A0F, 0x042210C0 ) /* * 46 114830 6776826 */ +RASTERIZER_ENTRY( 0x00482405, 0x00045110, 0x00000000, 0x000B0739, 0x0C261A0F, 0x042210C0 ) /* * 58 1273673 4513463 */ +RASTERIZER_ENTRY( 0x00482405, 0x00045110, 0x00000000, 0x000B0739, 0x0C261A09, 0x042210C0 ) /* * 46 634995 2275612 */ +RASTERIZER_ENTRY( 0x00002421, 0x00000000, 0x00000000, 0x000B073B, 0x0C261A0F, 0x042210C0 ) /* * 46 26651 1883507 */ +RASTERIZER_ENTRY( 0x00482405, 0x00045110, 0x00000000, 0x000B073B, 0x0C261A0F, 0x042210C0 ) /* * 26 220644 751241 */ +//RASTERIZER_ENTRY( 0x00002421, 0x00445110, 0x00000000, 0x000B073B, 0x0C261A09, 0x042210C0 ) /* * 79 14846 3499120 */ +//RASTERIZER_ENTRY( 0x00002421, 0x00000000, 0x00000000, 0x000B0739, 0x0C261A09, 0x042210C0 ) /* * 66 26665 1583363 */ +//RASTERIZER_ENTRY( 0x00002421, 0x00000000, 0x00000000, 0x000B073B, 0x0C26100F, 0x042210C0 ) /* * 78 33096 957935 */ +//RASTERIZER_ENTRY( 0x00002425, 0x00445110, 0x00000000, 0x000B07F9, 0x0C261A0F, 0x042210C0 ) /* * 38 12494 678029 */ +//RASTERIZER_ENTRY( 0x00800000, 0x00000000, 0x00000000, 0x00000200, 0x00000000, 0x00000000 ) /* * 28 25348 316181 */ +//RASTERIZER_ENTRY( 0x00002421, 0x00000000, 0x00000000, 0x000B0739, 0x0C26100F, 0x042210C0 ) /* * 13 11344 267903 */ +//RASTERIZER_ENTRY( 0x00002421, 0x00000000, 0x00000000, 0x000B073B, 0x0C261A09, 0x042210C0 ) /* * 34 1548 112168 */ +//RASTERIZER_ENTRY( 0x00002421, 0x00000000, 0x00000000, 0x000B07FB, 0x0C26100F, 0x042210C0 ) /* * 35 664 25222 */ +//RASTERIZER_ENTRY( 0x00000002, 0x00000000, 0x00000000, 0x00000300, 0xFFFFFFFF, 0xFFFFFFFF ) /* * 33 512 18393 */ +//RASTERIZER_ENTRY( 0x00002421, 0x00000000, 0x00000000, 0x000B07FB, 0x0C261A0F, 0x042210C0 ) /* * 14 216 16842 */ +//RASTERIZER_ENTRY( 0x00000001, 0x00000000, 0x00000000, 0x00000300, 0x00000800, 0x00000800 ) /* * 87 2 72 */ +//RASTERIZER_ENTRY( 0x00000001, 0x00000000, 0x00000000, 0x00000200, 0x08241A00, 0x08241A00 ) /* * 92 2 8 */ +//RASTERIZER_ENTRY( 0x00000001, 0x00000000, 0x00000000, 0x00000200, 0x00000000, 0x08241A00 ) /* * 93 2 8 */ + +#endif diff --git a/src/devices/video/voodoo.h b/src/devices/video/voodoo.h new file mode 100644 index 00000000000..dcd03d38876 --- /dev/null +++ b/src/devices/video/voodoo.h @@ -0,0 +1,168 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + voodoo.h + + 3dfx Voodoo Graphics SST-1/2 emulator. + +***************************************************************************/ + +#ifndef __VOODOO_H__ +#define __VOODOO_H__ + +#pragma once + + + +/*************************************************************************** + CONSTANTS +***************************************************************************/ +/* enumeration specifying which model of Voodoo we are emulating */ +enum +{ + TYPE_VOODOO_1, + TYPE_VOODOO_2, + TYPE_VOODOO_BANSHEE, + TYPE_VOODOO_3 +}; + +#define STD_VOODOO_1_CLOCK 50000000 +#define STD_VOODOO_2_CLOCK 90000000 +#define STD_VOODOO_BANSHEE_CLOCK 90000000 +#define STD_VOODOO_3_CLOCK 132000000 + + + +/*************************************************************************** + DEVICE CONFIGURATION MACROS +***************************************************************************/ + +#define MCFG_VOODOO_FBMEM(_value) \ + voodoo_device::static_set_fbmem(*device, _value); + +#define MCFG_VOODOO_TMUMEM(_value1, _value2) \ + voodoo_device::static_set_tmumem(*device, _value1, _value2); + +#define MCFG_VOODOO_SCREEN_TAG(_tag) \ + voodoo_device::static_set_screen_tag(*device, _tag); + +#define MCFG_VOODOO_CPU_TAG(_tag) \ + voodoo_device::static_set_cpu_tag(*device, _tag); + +#define MCFG_VOODOO_VBLANK_CB(_devcb) \ + devcb = &voodoo_device::static_set_vblank_callback(*device, DEVCB_##_devcb); + +#define MCFG_VOODOO_STALL_CB(_devcb) \ + devcb = &voodoo_device::static_set_stall_callback(*device, DEVCB_##_devcb); + + +/*************************************************************************** + FUNCTION PROTOTYPES +***************************************************************************/ + +int voodoo_update(device_t *device, bitmap_rgb32 &bitmap, const rectangle &cliprect); +int voodoo_get_type(device_t *device); +int voodoo_is_stalled(device_t *device); +void voodoo_set_init_enable(device_t *device, UINT32 newval); + +/* ----- device interface ----- */ + +class voodoo_device : public device_t +{ +public: + voodoo_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + ~voodoo_device(); + + + static void static_set_fbmem(device_t &device, int value) { downcast(device).m_fbmem = value; } + static void static_set_tmumem(device_t &device, int value1, int value2) { downcast(device).m_tmumem0 = value1; downcast(device).m_tmumem1 = value2; } + static void static_set_screen_tag(device_t &device, const char *tag) { downcast(device).m_screen = tag; } + static void static_set_cpu_tag(device_t &device, const char *tag) { downcast(device).m_cputag = tag; } + template static devcb_base &static_set_vblank_callback(device_t &device, _Object object) { return downcast(device).m_vblank.set_callback(object); } + template static devcb_base &static_set_stall_callback(device_t &device, _Object object) { return downcast(device).m_stall.set_callback(object); } + + DECLARE_READ32_MEMBER( voodoo_r ); + DECLARE_WRITE32_MEMBER( voodoo_w ); + + // access to legacy token + struct voodoo_state *token() const { assert(m_token != NULL); return m_token; } + void common_start_voodoo(UINT8 type); + + UINT8 m_fbmem; + UINT8 m_tmumem0; + UINT8 m_tmumem1; + const char * m_screen; + const char * m_cputag; + devcb_write_line m_vblank; + devcb_write_line m_stall; + +protected: + // device-level overrides + virtual void device_config_complete(); + virtual void device_stop(); + virtual void device_reset(); +private: + // internal state + struct voodoo_state *m_token; +}; + +class voodoo_1_device : public voodoo_device +{ +public: + voodoo_1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +protected: + // device-level overrides + virtual void device_start(); +}; + +extern const device_type VOODOO_1; + +class voodoo_2_device : public voodoo_device +{ +public: + voodoo_2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +protected: + // device-level overrides + virtual void device_start(); +}; + +extern const device_type VOODOO_2; + +class voodoo_banshee_device : public voodoo_device +{ +public: + voodoo_banshee_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + voodoo_banshee_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + DECLARE_READ32_MEMBER( banshee_r ); + DECLARE_WRITE32_MEMBER( banshee_w ); + DECLARE_READ32_MEMBER( banshee_fb_r ); + DECLARE_WRITE32_MEMBER( banshee_fb_w ); + DECLARE_READ32_MEMBER( banshee_io_r ); + DECLARE_WRITE32_MEMBER( banshee_io_w ); + DECLARE_READ32_MEMBER( banshee_rom_r ); + +protected: + // device-level overrides + virtual void device_start(); + DECLARE_READ32_MEMBER( banshee_agp_r ); + DECLARE_WRITE32_MEMBER( banshee_agp_w ); + DECLARE_READ8_MEMBER( banshee_vga_r ); + DECLARE_WRITE8_MEMBER( banshee_vga_w ); +}; + +extern const device_type VOODOO_BANSHEE; + +class voodoo_3_device : public voodoo_banshee_device +{ +public: + voodoo_3_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +protected: + // device-level overrides + virtual void device_start(); +}; + +extern const device_type VOODOO_3; + +#endif diff --git a/src/devices/video/voodoo_pci.c b/src/devices/video/voodoo_pci.c new file mode 100644 index 00000000000..7570a007efb --- /dev/null +++ b/src/devices/video/voodoo_pci.c @@ -0,0 +1,180 @@ +// license:BSD-3-Clause +// copyright-holders:Ted Green +#include "voodoo_pci.h" + +int voodoo_pci_device::m_type = 0; + +static MACHINE_CONFIG_FRAGMENT( voodoo_1_pci ) + MCFG_DEVICE_ADD("voodoo", VOODOO_1, STD_VOODOO_1_CLOCK) + MCFG_VOODOO_FBMEM(4) + MCFG_VOODOO_TMUMEM(1, 0) + MCFG_VOODOO_SCREEN_TAG("screen") +MACHINE_CONFIG_END + +static MACHINE_CONFIG_FRAGMENT( voodoo_2_pci ) + MCFG_DEVICE_ADD("voodoo", VOODOO_2, STD_VOODOO_2_CLOCK) + MCFG_VOODOO_FBMEM(4) + MCFG_VOODOO_TMUMEM(1, 0) + MCFG_VOODOO_SCREEN_TAG("screen") +MACHINE_CONFIG_END + +static MACHINE_CONFIG_FRAGMENT( voodoo_banshee_pci ) + MCFG_DEVICE_ADD("voodoo", VOODOO_BANSHEE, STD_VOODOO_BANSHEE_CLOCK) + MCFG_VOODOO_FBMEM(16) + MCFG_VOODOO_SCREEN_TAG("screen") +MACHINE_CONFIG_END + +static MACHINE_CONFIG_FRAGMENT( voodoo_3_pci ) + MCFG_DEVICE_ADD("voodoo", VOODOO_3, STD_VOODOO_3_CLOCK) + MCFG_VOODOO_FBMEM(16) + MCFG_VOODOO_SCREEN_TAG("screen") +MACHINE_CONFIG_END + +machine_config_constructor voodoo_pci_device::device_mconfig_additions() const +{ + switch (m_type) { + case TYPE_VOODOO_1: + return MACHINE_CONFIG_NAME( voodoo_1_pci ); + break; + case TYPE_VOODOO_2: + return MACHINE_CONFIG_NAME( voodoo_2_pci ); + break; + case TYPE_VOODOO_BANSHEE: + return MACHINE_CONFIG_NAME( voodoo_banshee_pci ); + break; + //case TYPE_VOODOO_3 + default: + return MACHINE_CONFIG_NAME( voodoo_3_pci ); + break; + } +} + +const device_type VOODOO_PCI = &device_creator; + +DEVICE_ADDRESS_MAP_START(config_map, 32, voodoo_pci_device) + AM_RANGE(0x40, 0x4f) AM_READWRITE (pcictrl_r, pcictrl_w) + AM_INHERIT_FROM(pci_device::config_map) +ADDRESS_MAP_END + +DEVICE_ADDRESS_MAP_START(voodoo_reg_map, 32, voodoo_pci_device) + AM_RANGE(0x0, 0x00ffffff) AM_DEVREADWRITE("voodoo", voodoo_device, voodoo_r, voodoo_w) +ADDRESS_MAP_END + + +DEVICE_ADDRESS_MAP_START(banshee_reg_map, 32, voodoo_pci_device) + AM_RANGE(0x0, 0x01ffffff) AM_DEVREADWRITE("voodoo", voodoo_banshee_device, banshee_r, banshee_w) +ADDRESS_MAP_END +DEVICE_ADDRESS_MAP_START(lfb_map, 32, voodoo_pci_device) + AM_RANGE(0x0, 0x01ffffff) AM_DEVREADWRITE("voodoo", voodoo_banshee_device, banshee_fb_r, banshee_fb_w) +ADDRESS_MAP_END +DEVICE_ADDRESS_MAP_START(io_map, 32, voodoo_pci_device) + AM_RANGE(0x000, 0x0ff) AM_DEVREADWRITE("voodoo", voodoo_banshee_device, banshee_io_r, banshee_io_w) +ADDRESS_MAP_END + +voodoo_pci_device::voodoo_pci_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : pci_device(mconfig, VOODOO_PCI, "Voodoo PCI", tag, owner, clock, "voodoo_pci", __FILE__), + m_voodoo(*this, "voodoo"), m_fbmem(2), m_tmumem0(0), m_tmumem1(0) +{ +} + +void voodoo_pci_device::set_cpu_tag(const char *_cpu_tag) +{ + m_cpu_tag = _cpu_tag; +} + +void voodoo_pci_device::device_start() +{ + voodoo_device::static_set_cpu_tag(m_voodoo, m_cpu_tag); + voodoo_device::static_set_fbmem(m_voodoo, m_fbmem); + voodoo_device::static_set_tmumem(m_voodoo, m_tmumem0, m_tmumem1); + switch (m_type) { + //void set_ids(UINT32 main_id, UINT8 revision, UINT32 pclass, UINT32 subsystem_id); + case TYPE_VOODOO_1: + set_ids(0x121a0001, 0x02, 0x000000, 0x000000); + break; + case TYPE_VOODOO_2: + set_ids(0x121a0002, 0x02, 0x040000, 0x000000); + break; + case TYPE_VOODOO_BANSHEE: + set_ids(0x121a0003, 0x02, 0x000003, 0x000000); + break; + //case TYPE_VOODOO_3 + default: + set_ids(0x121a0005, 0x02, 0x000003, 0x000000); + break; + } + pci_device::device_start(); + if (m_type<=TYPE_VOODOO_2) { + add_map(16*1024*1024, M_MEM | M_PREF, FUNC(voodoo_pci_device::voodoo_reg_map)); + } else { + add_map(32*1024*1024, M_MEM, FUNC(voodoo_pci_device::banshee_reg_map)); + add_map(32*1024*1024, M_MEM, FUNC(voodoo_pci_device::lfb_map)); + add_map(256, M_IO, FUNC(voodoo_pci_device::io_map)); + } +} + +void voodoo_pci_device::device_reset() +{ + memset(m_pcictrl_reg, 0, sizeof(m_pcictrl_reg)); + pci_device::device_reset(); +} + +void voodoo_pci_device::map_extra(UINT64 memory_window_start, UINT64 memory_window_end, UINT64 memory_offset, address_space *memory_space, + UINT64 io_window_start, UINT64 io_window_end, UINT64 io_offset, address_space *io_space) +{ + logerror("%s: map_extra\n", this->tag()); + // Really awkward way of getting vga address space mapped + // Should really be dependent on voodoo VGAINIT0 bit 8 and IO base + 0xc3 bit 0 + if (1) { + // io map is on bank_infos[2] + bank_info &bi = bank_infos[2]; + if(bi.adr==-1) + return; + if(UINT32(bi.adr) == UINT32(~(bi.size - 1))) + return; + + UINT64 start; + address_space *space; + if(bi.flags & M_IO) { + space = io_space; + start = bi.adr + io_offset; + } else { + space = memory_space; + start = bi.adr + memory_offset; + } + // The mapping needs to only check high address bits + start = (start & 0xFFFF0000) + 0x300; + UINT64 end = (start & 0xFFFF0000) + 0x3ef; + space->install_device_delegate(start, end, *this, bi.map); + logerror("%s: map %s at %0*x-%0*x\n", this->tag(), bi.map.name(), bi.flags & M_IO ? 4 : 8, UINT32(start), bi.flags & M_IO ? 4 : 8, UINT32(end)); + } + +} + +UINT32 voodoo_pci_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + return voodoo_update(m_voodoo, bitmap, cliprect) ? 0 : UPDATE_HAS_NOT_CHANGED; +} + +// PCI bus control +READ32_MEMBER (voodoo_pci_device::pcictrl_r) +{ + UINT32 result = m_pcictrl_reg[offset]; + if (1) + logerror("%06X:voodoo_pci_device pcictrl_r from offset %02X = %08X & %08X\n", space.device().safe_pc(), offset*4, result, mem_mask); + return result; +} +WRITE32_MEMBER (voodoo_pci_device::pcictrl_w) +{ + COMBINE_DATA(&m_pcictrl_reg[offset]); + switch (offset) { + case 0x0/4: // The address map starts at 0x40 + // HW initEnable + voodoo_set_init_enable(m_voodoo, data); + logerror("%06X:voodoo_pci_device pcictrl_w to offset %02X = %08X & %08X\n", space.device().safe_pc(), offset*4, data, mem_mask); + break; + default: + logerror("%06X:voodoo_pci_device pcictrl_w to offset %02X = %08X & %08X\n", space.device().safe_pc(), offset*4, data, mem_mask); + break; + } +} diff --git a/src/devices/video/voodoo_pci.h b/src/devices/video/voodoo_pci.h new file mode 100644 index 00000000000..a1fe30bd7db --- /dev/null +++ b/src/devices/video/voodoo_pci.h @@ -0,0 +1,59 @@ +// license:BSD-3-Clause +// copyright-holders:Ted Green +// 3dfx Voodoo Graphics SST-1/2 emulator. + +#ifndef VOODOO_PCI_H +#define VOODOO_PCI_H + +#include "machine/pci.h" +#include "voodoo.h" + +#define MCFG_VOODOO_PCI_ADD(_tag, _type, _cpu_tag) \ + voodoo_pci_device::set_type(_type); \ + MCFG_PCI_DEVICE_ADD(_tag, VOODOO_PCI, 0, 0, 0, 0) \ + downcast(device)->set_cpu_tag(_cpu_tag); + +#define MCFG_VOODOO_PCI_FBMEM(_value) \ + downcast(device)->set_fbmem(_value); + +#define MCFG_VOODOO_PCI_TMUMEM(_value1, _value2) \ + downcast(device)->set_tmumem(_value1, _value2); + +class voodoo_pci_device : public pci_device { +public: + voodoo_pci_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual void map_extra(UINT64 memory_window_start, UINT64 memory_window_end, UINT64 memory_offset, address_space *memory_space, + UINT64 io_window_start, UINT64 io_window_end, UINT64 io_offset, address_space *io_space); + // optional information overrides + virtual machine_config_constructor device_mconfig_additions() const; + UINT32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); + virtual DECLARE_ADDRESS_MAP(config_map, 32); + + void set_cpu_tag(const char *tag); + static void set_type(const int type) {m_type = type;} + void set_fbmem(const int fbmem) {m_fbmem = fbmem;} + void set_tmumem(const int tmumem0, const int tmumem1) {m_tmumem0 = tmumem0; m_tmumem1 = tmumem1;} + + DECLARE_READ32_MEMBER( pcictrl_r); + DECLARE_WRITE32_MEMBER( pcictrl_w); + +protected: + virtual void device_start(); + virtual void device_reset(); + +private: + required_device m_voodoo; + static int m_type; + int m_fbmem, m_tmumem0, m_tmumem1; + const char *m_cpu_tag; + + UINT32 m_pcictrl_reg[0x10]; + DECLARE_ADDRESS_MAP(voodoo_reg_map, 32); + DECLARE_ADDRESS_MAP(banshee_reg_map, 32); + DECLARE_ADDRESS_MAP(lfb_map, 32); + DECLARE_ADDRESS_MAP(io_map, 32); +}; + +extern const device_type VOODOO_PCI; + +#endif -- cgit v1.2.3